Creating release candidate final from release_600 branch

git-svn-id: https://llvm.org/svn/llvm-project/polly/tags/RELEASE_600@326561 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/final/.arcconfig b/final/.arcconfig
new file mode 100644
index 0000000..27acbf4
--- /dev/null
+++ b/final/.arcconfig
@@ -0,0 +1,9 @@
+{
+  "repository.callsign" : "PLO",
+  "conduit_uri" : "https://reviews.llvm.org/",
+  "history.immutable" : true,
+  "load" : [
+    "utils/arcanist/LitTestEngine"
+  ],
+  "unit.engine" : "LitTestEngine"
+}
diff --git a/final/.arclint b/final/.arclint
new file mode 100644
index 0000000..07bca35
--- /dev/null
+++ b/final/.arclint
@@ -0,0 +1,25 @@
+{
+  "linters": {
+    "format": {
+      "include": "(include/polly/.+\\.h$|lib/.+\\.cpp$)",
+      "exclude": "(lib/External/JSON/.*)",
+      "type": "script-and-regex",
+      "script-and-regex.script": "sh -c './utils/check_format.sh \"$0\" 2> /dev/null || true'",
+      "script-and-regex.regex": "/^(OK:(?P<ignore>.+)|Error:) (?P<message>.+)$/m"
+    },
+    "chmod": {
+      "type": "chmod"
+    },
+    "filename": {
+      "exclude": "(www/experiments/.+|.*\\.jscop.*)",
+      "type": "filename"
+    },
+    "merge-conflict": {
+      "type": "merge-conflict"
+    },
+    "spelling": {
+      "exclude": "(configure|autoconf/.*)",
+      "type": "spelling"
+    }
+  }
+}
diff --git a/final/.gitattributes b/final/.gitattributes
new file mode 100644
index 0000000..7105fff
--- /dev/null
+++ b/final/.gitattributes
@@ -0,0 +1,4 @@
+# Auto detect text files and perform LF normalization
+* text eol=lf
+*.png -text
+*.pdf -text
diff --git a/final/.gitignore b/final/.gitignore
new file mode 100644
index 0000000..60b5030
--- /dev/null
+++ b/final/.gitignore
@@ -0,0 +1,3 @@
+test/lit.site.cfg
+lib/External/isl/doc/manual.pdf
+00*
diff --git a/final/CMakeLists.txt b/final/CMakeLists.txt
new file mode 100644
index 0000000..9ddc0f7
--- /dev/null
+++ b/final/CMakeLists.txt
@@ -0,0 +1,222 @@
+# Check if this is a in tree build.
+if (NOT DEFINED LLVM_MAIN_SRC_DIR)
+  project(Polly)
+  cmake_minimum_required(VERSION 3.4.3)
+
+  # Where is LLVM installed?
+  find_package(LLVM CONFIG REQUIRED)
+  set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${LLVM_CMAKE_DIR})
+  include(HandleLLVMOptions)
+  include(AddLLVM)
+
+  # Add the llvm header path.
+  include_directories(${LLVM_INCLUDE_DIRS})
+
+  # Sources available, too?
+  if (LLVM_BUILD_MAIN_SRC_DIR)
+    set(LLVM_SOURCE_ROOT ${LLVM_BUILD_MAIN_SRC_DIR} CACHE PATH
+      "Path to LLVM source tree")
+  else()
+    execute_process(COMMAND "${LLVM_TOOLS_BINARY_DIR}/llvm-config" --src-root
+      OUTPUT_VARIABLE MAIN_SRC_DIR
+      OUTPUT_STRIP_TRAILING_WHITESPACE)
+    set(LLVM_SOURCE_ROOT ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
+  endif()
+
+  # Enable unit tests if available.
+  set(POLLY_GTEST_AVAIL 0)
+  set(UNITTEST_DIR ${LLVM_SOURCE_ROOT}/utils/unittest)
+  if(EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h)
+    # The build tree already exports the gtest target, which we can reuse
+    if (TARGET gtest)
+      # LLVM Doesn't export gtest's include directorys, so do that here
+      set_target_properties(gtest
+        PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
+        "${UNITTEST_DIR}/googletest/include;${UNITTEST_DIR}/googlemock/include"
+        )
+      set(POLLY_GTEST_AVAIL 1)
+    else()
+      add_library(gtest
+        ${UNITTEST_DIR}/googletest/src/gtest-all.cc
+        ${UNITTEST_DIR}/googlemock/src/gmock-all.cc
+        )
+      target_include_directories(gtest
+        PUBLIC
+        "${UNITTEST_DIR}/googletest/include"
+        "${UNITTEST_DIR}/googlemock/include"
+
+        PRIVATE
+        "${UNITTEST_DIR}/googletest"
+        "${UNITTEST_DIR}/googlemock"
+        )
+      target_link_libraries(gtest -lpthread)
+
+      add_library(gtest_main ${UNITTEST_DIR}/UnitTestMain/TestMain.cpp)
+      target_link_libraries(gtest_main gtest)
+
+      set(POLLY_GTEST_AVAIL 1)
+    endif()
+  endif()
+
+  # Make sure the isl c files are built as fPIC
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+
+  # Set directory for polly-isl-test.
+  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
+else ()
+  set(LLVM_SOURCE_ROOT "${LLVM_MAIN_SRC_DIR}")
+  set(POLLY_GTEST_AVAIL 1)
+endif ()
+
+set(POLLY_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(POLLY_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+
+# Add path for custom modules
+set(CMAKE_MODULE_PATH
+  ${CMAKE_MODULE_PATH}
+  "${CMAKE_CURRENT_SOURCE_DIR}/cmake"
+  )
+
+include("polly_macros")
+
+# Add appropriate flags for GCC
+if (CMAKE_COMPILER_IS_GNUCXX)
+  # FIXME: Turn off exceptions, RTTI:
+  # -fno-exceptions -fno-rtti
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings -fno-exceptions -fno-rtti")
+elseif (MSVC)
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHs-c-")
+  add_definitions("-D_HAS_EXCEPTIONS=0")
+else ()
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
+endif ()
+
+# Add path for custom modules
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${POLLY_SOURCE_DIR}/cmake")
+
+SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+
+option(POLLY_ENABLE_GPGPU_CODEGEN "Enable GPGPU code generation feature" OFF)
+if (POLLY_ENABLE_GPGPU_CODEGEN)
+  # Do not require CUDA/OpenCL, as GPU code generation test cases can be run
+  # without a CUDA/OpenCL library.
+  FIND_PACKAGE(CUDA)
+  FIND_PACKAGE(OpenCL)
+  set(GPU_CODEGEN TRUE)
+else(POLLY_ENABLE_GPGPU_CODEGEN)
+  set(GPU_CODEGEN FALSE)
+endif(POLLY_ENABLE_GPGPU_CODEGEN)
+
+
+# Support GPGPU code generation if the library is available.
+if (CUDA_FOUND)
+  add_definitions(-DHAS_LIBCUDART)
+  INCLUDE_DIRECTORIES( ${CUDA_INCLUDE_DIRS} )
+endif(CUDA_FOUND)
+if (OpenCL_FOUND)
+  add_definitions(-DHAS_LIBOPENCL)
+  INCLUDE_DIRECTORIES( ${OpenCL_INCLUDE_DIR} )
+endif(OpenCL_FOUND)
+
+option(POLLY_BUNDLED_ISL "Use the bundled version of libisl included in Polly" ON)
+if (NOT POLLY_BUNDLED_ISL)
+  find_package(ISL MODULE REQUIRED)
+  message(STATUS "Using external libisl ${ISL_VERSION} in: ${ISL_PREFIX}")
+  set(ISL_TARGET ISL)
+else()
+  set(ISL_INCLUDE_DIRS
+    ${CMAKE_CURRENT_BINARY_DIR}/lib/External/isl/include
+    ${CMAKE_CURRENT_SOURCE_DIR}/lib/External/isl/include
+  )
+  set(ISL_TARGET PollyISL)
+endif()
+
+option(POLLY_BUNDLED_JSONCPP "Use the bundled version of jsoncpp included in Polly" ON)
+if (POLLY_BUNDLED_JSONCPP)
+  set(JSONCPP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/lib/External/JSON/include")
+  set(JSONCPP_LIBRARIES)
+  set(POLLY_JSON_FILES
+    External/JSON/json_reader.cpp
+    External/JSON/json_value.cpp
+    External/JSON/json_writer.cpp
+  )
+else ()
+  find_package(Jsoncpp REQUIRED)
+  set(POLLY_JSON_FILES)
+endif ()
+
+include_directories(
+  BEFORE
+  ${CMAKE_CURRENT_SOURCE_DIR}/include
+  ${ISL_INCLUDE_DIRS}
+  ${JSONCPP_INCLUDE_DIRS}
+  ${CMAKE_CURRENT_SOURCE_DIR}/lib/External/pet/include
+  ${CMAKE_CURRENT_SOURCE_DIR}/lib/External
+  ${CMAKE_CURRENT_BINARY_DIR}/include
+  )
+
+if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+  install(DIRECTORY include/
+    DESTINATION include
+    FILES_MATCHING
+    PATTERN "*.h"
+    PATTERN ".svn" EXCLUDE
+    )
+
+  install(DIRECTORY ${POLLY_BINARY_DIR}/include/
+    DESTINATION include
+    FILES_MATCHING
+    PATTERN "*.h"
+    PATTERN "CMakeFiles" EXCLUDE
+    PATTERN ".svn" EXCLUDE
+    )
+endif()
+
+add_definitions( -D_GNU_SOURCE )
+
+add_subdirectory(docs)
+add_subdirectory(lib)
+add_subdirectory(test)
+if (POLLY_GTEST_AVAIL)
+  add_subdirectory(unittests)
+endif ()
+add_subdirectory(tools)
+add_subdirectory(cmake)
+# TODO: docs.
+
+
+configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/include/polly/Config/config.h.cmake
+                ${POLLY_BINARY_DIR}/include/polly/Config/config.h )
+
+# Add target to check formatting of polly files
+file( GLOB_RECURSE files *.h lib/*.cpp lib/*.c tools/*.cpp tools/*.c tools/*.h unittests/*.cpp)
+file( GLOB_RECURSE external lib/External/*.h lib/External/*.c lib/External/*.cpp isl_config.h)
+list( REMOVE_ITEM files ${external})
+
+set(check_format_depends)
+set(update_format_depends)
+set(i 0)
+foreach (file IN LISTS files)
+  add_custom_command(OUTPUT polly-check-format${i}
+    COMMAND clang-format -sort-includes -style=llvm ${file} | diff -u ${file} -
+    VERBATIM
+    COMMENT "Checking format of ${file}..."
+  )
+  list(APPEND check_format_depends "polly-check-format${i}")
+
+  add_custom_command(OUTPUT polly-update-format${i}
+    COMMAND clang-format -sort-includes -i -style=llvm ${file}
+    VERBATIM
+    COMMENT "Updating format of ${file}..."
+  )
+  list(APPEND update_format_depends "polly-update-format${i}")
+
+  math(EXPR i ${i}+1)
+endforeach ()
+
+add_custom_target(polly-check-format DEPENDS ${check_format_depends})
+set_target_properties(polly-check-format PROPERTIES FOLDER "Polly")
+
+add_custom_target(polly-update-format DEPENDS ${update_format_depends})
+set_target_properties(polly-update-format PROPERTIES FOLDER "Polly")
+
diff --git a/final/CREDITS.txt b/final/CREDITS.txt
new file mode 100644
index 0000000..98fb9cd
--- /dev/null
+++ b/final/CREDITS.txt
@@ -0,0 +1,42 @@
+This file is a partial list of people who have contributed to Polly.
+If you have contributed a patch or made some other contribution to
+Polly, please submit a patch to this file to add yourself, and it will be
+done!
+
+The list is sorted by surname and formatted to allow easy grepping and
+beautification by scripts.  The fields are: name (N), email (E), web-address
+(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
+(S).
+
+N: Raghesh Aloor
+E: raghesh.a@gmail.com
+D: OpenMP code generation
+D: Google Summer of Code student 2011
+
+N: Tobias Grosser
+E: tobias@grosser.es
+W: http://www.grosser.es
+D: Co-founder, design of the overall architecture
+
+N: Yabin Hu
+E: yabin.hwu@gmail.com
+D: GPGPU code generation
+D: Google Summer of Code student 2012, 2014
+
+N: Andreas Simbuerger
+E: simbuerg@fim.uni-passau.de
+W: http://www.infosun.fim.uni-passau.de/cl/staff/simbuerger/
+D: Profiling infrastructure
+
+N: Hongbin Zheng
+E: etherzhhb@gmail.com
+D: Co-founder
+D: scop detection, automake/cmake infrastructure, scopinfo, scoppasses, ...
+D: Google Summer of Code student 2010
+
+N: Johannes Doerfert
+E: doerfert@cs.uni-saarland.de
+E: jdoerfert@codeaurora.org
+W: http://www.cdl.uni-saarland.de/people/doerfert/
+P: http://www.cdl.uni-saarland.de/people/doerfert/JohannesDoerfert.asc
+D: reductions, general infrastructure
diff --git a/final/LICENSE.txt b/final/LICENSE.txt
new file mode 100644
index 0000000..5019e51
--- /dev/null
+++ b/final/LICENSE.txt
@@ -0,0 +1,61 @@
+==============================================================================
+Polly Release License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2009-2016 Polly Team
+All rights reserved.
+
+Developed by:
+
+    Polly Team
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimers.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimers in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the names of the Polly Team, copyright holders, nor the names of
+      its contributors may be used to endorse or promote products derived from
+      this Software without specific prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+Copyrights and Licenses for Third Party Software Distributed with LLVM:
+==============================================================================
+The Polly software contains code written by third parties.   Such software will
+have its own individual LICENSE.TXT file in the directory in which it appears.
+This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License
+applies to all code in the Polly Distribution, and nothing in any of the other
+licenses gives permission to use the names of the Polly Team or promote products
+derived from this Software.
+
+The following pieces of software have additional or alternate copyrights,
+licenses, and/or restrictions:
+
+Program             Directory
+-------             ---------
+jsoncpp             lib/External/JSON
+
+
+
diff --git a/final/README b/final/README
new file mode 100644
index 0000000..09a4a54
--- /dev/null
+++ b/final/README
@@ -0,0 +1,12 @@
+Polly - Polyhedral optimizations for LLVM
+-----------------------------------------
+http://polly.llvm.org/
+
+Polly uses a mathematical representation, the polyhedral model, to represent and
+transform loops and other control flow structures. Using an abstract
+representation it is possible to reason about transformations in a more general
+way and to use highly optimized linear programming libraries to figure out the
+optimal loop structure. These transformations can be used to do constant
+propagation through arrays, remove dead loop iterations, optimize loops for
+cache locality, optimize arrays, apply advanced automatic parallelization, drive
+vectorization, or they can be used to do software pipelining.
diff --git a/final/cmake/CMakeLists.txt b/final/cmake/CMakeLists.txt
new file mode 100644
index 0000000..969292c
--- /dev/null
+++ b/final/cmake/CMakeLists.txt
@@ -0,0 +1,133 @@
+# Keep this in sync with llvm/cmake/CMakeLists.txt!
+
+set(LLVM_INSTALL_PACKAGE_DIR "lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm")
+set(POLLY_INSTALL_PACKAGE_DIR "lib${LLVM_LIBDIR_SUFFIX}/cmake/polly")
+if (CMAKE_CONFIGURATION_TYPES)
+  set(POLLY_EXPORTS_FILE_NAME "PollyExports-$<LOWER_CASE:$<CONFIG>>.cmake")
+else()
+  # avoid conflicts in the build-tree when changing configuration
+  set(POLLY_EXPORTS_FILE_NAME "PollyExports-all.cmake")
+endif()
+
+set(POLLY_CONFIG_EXPORTED_TARGETS Polly ${ISL_TARGET})
+if (NOT MSVC)
+  # LLVMPolly is a dummy target on Win
+  list(APPEND POLLY_CONFIG_EXPORTED_TARGETS LLVMPolly)
+endif()
+if (POLLY_ENABLE_GPGPU_CODEGEN)
+  list(APPEND POLLY_CONFIG_EXPORTED_TARGETS PollyPPCG)
+endif()
+
+# Get the target type for every exported target
+foreach(tgt IN LISTS POLLY_CONFIG_EXPORTED_TARGETS)
+  get_target_property(tgt_type ${tgt} TYPE)
+  string(REPLACE "_LIBRARY" "" tgt_type ${tgt_type})
+  set(POLLY_CONFIG_TARGET_${tgt}_TYPE ${tgt_type})
+endforeach()
+
+set(llvm_cmake_builddir "${LLVM_BINARY_DIR}/${LLVM_INSTALL_PACKAGE_DIR}")
+set(POLLY_CONFIG_LLVM_CMAKE_DIR "${llvm_cmake_builddir}")
+
+# generate the import code for bundled/undbundled libisl versions
+if (NOT POLLY_BUNDLED_ISL)
+  get_property(incl TARGET ISL PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
+  get_property(lib TARGET ISL PROPERTY INTERFACE_LINK_LIBRARIES)
+  get_property(opt TARGET ISL PROPERTY INTERFACE_COMPILE_OPTIONS)
+  set(ISL_CONFIG_CODE "
+add_library(ISL INTERFACE IMPORTED)
+set_property(TARGET ISL APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${incl})
+set_property(TARGET ISL APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${lib})
+set_property(TARGET ISL APPEND PROPERTY INTERFACE_COMPILE_OPTIONS ${opt})")
+else()
+  set(ISL_CONFIG_CODE "
+if (NOT TARGET PollyISL)
+  add_library(PollyISL ${POLLY_CONFIG_TARGET_PollyISL_TYPE} IMPORTED)
+endif()")
+endif()
+
+# Generate PollyConfig.cmake for the build tree.
+set(POLLY_CONFIG_CMAKE_DIR "${CMAKE_BINARY_DIR}/${POLLY_INSTALL_PACKAGE_DIR}")
+set(POLLY_CONFIG_INCLUDE_DIRS
+  ${POLLY_SOURCE_DIR}/include
+  ${ISL_INCLUDE_DIRS}
+  ${POLLY_BINARY_DIR}/include
+  )
+set(POLLY_CONFIG_LIBRARY_DIRS "${POLLY_BINARY_DIR}/lib")
+
+# set locations for imported targets
+foreach(tgt IN LISTS POLLY_CONFIG_EXPORTED_TARGETS)
+  get_target_property(tgt_type ${tgt} TYPE)
+  if (NOT tgt_type STREQUAL "INTERFACE_LIBRARY")
+    set(POLLY_EXPORTS
+      "set_target_properties(${tgt} PROPERTIES
+              IMPORTED_LOCATION_$<UPPER_CASE:$<CONFIG>> $<TARGET_FILE:${tgt}>)
+${POLLY_EXPORTS}")
+  endif()
+endforeach(tgt)
+
+# PollyConfig holds the target definitions and general settings, PollyExports
+# the imported locations
+configure_file(
+  ${CMAKE_CURRENT_SOURCE_DIR}/PollyConfig.cmake.in
+  ${POLLY_CONFIG_CMAKE_DIR}/PollyConfig.cmake
+  @ONLY)
+
+file(GENERATE
+  OUTPUT ${POLLY_CONFIG_CMAKE_DIR}/${POLLY_EXPORTS_FILE_NAME}
+  CONTENT "${POLLY_EXPORTS}")
+
+
+# Generate PollyConfig.cmake for the install tree.
+unset(POLLY_EXPORTS)
+set(POLLY_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
+set(POLLY_CONFIG_LLVM_CMAKE_DIR "${LLVM_BINARY_DIR}/${LLVM_INSTALL_PACKAGE_DIR}")
+set(POLLY_CONFIG_CMAKE_DIR "${POLLY_INSTALL_PREFIX}/${POLLY_INSTALL_PACKAGE_DIR}")
+set(POLLY_CONFIG_LIBRARY_DIRS "${POLLY_INSTALL_PREFIX}/lib${LLVM_LIBDIR_SUFFIX}")
+if (POLLY_BUNDLED_ISL)
+  set(POLLY_CONFIG_INCLUDE_DIRS
+    "${POLLY_INSTALL_PREFIX}/include"
+    "${POLLY_INSTALL_PREFIX}/include/polly"
+    )
+else()
+  set(POLLY_CONFIG_INCLUDE_DIRS
+    "${POLLY_INSTALL_PREFIX}/include"
+    ${ISL_INCLUDE_DIRS}
+    )
+endif()
+
+# set locations for imported targets. The path is constructed to be relative to
+# the config file
+foreach(tgt IN LISTS POLLY_CONFIG_EXPORTED_TARGETS)
+  get_target_property(tgt_type ${tgt} TYPE)
+  if (tgt_type STREQUAL "EXECUTABLE")
+    set(tgt_prefix "bin/")
+  else()
+    set(tgt_prefix "lib/")
+  endif()
+
+  set(tgt_path "${CMAKE_INSTALL_PREFIX}/${tgt_prefix}$<TARGET_FILE_NAME:${tgt}>")
+  file(RELATIVE_PATH tgt_path ${POLLY_CONFIG_CMAKE_DIR} ${tgt_path})
+
+  if (NOT tgt_type STREQUAL "INTERFACE_LIBRARY")
+    set(POLLY_EXPORTS
+"set_target_properties(${tgt} PROPERTIES
+        IMPORTED_LOCATION$<$<NOT:$<CONFIG:>>:_<UPPER_CASE:$<CONFIG>> \${CMAKE_CURRENT_LIST_DIR}/${tgt_path})
+${POLLY_EXPORTS}")
+  endif()
+endforeach(tgt)
+
+configure_file(
+  ${CMAKE_CURRENT_SOURCE_DIR}/PollyConfig.cmake.in
+  ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/PollyConfig.cmake
+  @ONLY)
+file(GENERATE OUTPUT
+  ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${POLLY_EXPORTS_FILE_NAME}
+  CONTENT "${POLLY_EXPORTS}")
+
+if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+  install(
+    FILES
+    "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/PollyConfig.cmake"
+    "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${POLLY_EXPORTS_FILE_NAME}"
+    DESTINATION "${POLLY_INSTALL_PACKAGE_DIR}")
+endif ()
diff --git a/final/cmake/FindISL.cmake b/final/cmake/FindISL.cmake
new file mode 100644
index 0000000..613e86d
--- /dev/null
+++ b/final/cmake/FindISL.cmake
@@ -0,0 +1,24 @@
+find_package(PkgConfig REQUIRED)
+pkg_search_module(ISL isl)
+if (NOT ISL_FOUND EQUAL 1)
+  message(FATAL_ERROR "No libisl found on this system. Consider setting PKG_CONFIG_PATH.")
+endif()
+
+add_library(ISL INTERFACE IMPORTED)
+foreach (incl IN LISTS ISL_INCLUDE_DIRS)
+  set_property(TARGET ISL APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${incl})
+endforeach()
+
+foreach (libname IN LISTS ISL_LIBRARIES)
+  if (ISL_LIBRARY_DIRS)
+    foreach (dir IN LISTS ISL_LIBRARY_DIRS)
+      list(APPEND hints  ${dir})
+    endforeach()
+  endif()
+  find_library(lib NAMES ${libname} HINTS ${hints} NO_DEFAULT_PATH)
+  set_property(TARGET ISL APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${lib})
+endforeach()
+
+foreach (opt IN LISTS ISL_CFLAGS ISL_CFLAGS_OTHER)
+  set_property(TARGET ISL APPEND PROPERTY INTERFACE_COMPILE_OPTIONS ${opt})
+endforeach()
diff --git a/final/cmake/FindJsoncpp.cmake b/final/cmake/FindJsoncpp.cmake
new file mode 100644
index 0000000..cee44d1
--- /dev/null
+++ b/final/cmake/FindJsoncpp.cmake
@@ -0,0 +1,57 @@
+find_package(PkgConfig QUIET)
+if (PkgConfig_FOUND)
+  pkg_search_module(JSONCPP jsoncpp QUIET)
+
+  # Get the libraries full paths, to be consistent with find_library().
+  set(fulllibs)
+  foreach (libname IN LISTS JSONCPP_LIBRARIES)
+    find_library(jsoncpp_lib${libname} NAMES ${libname}
+      HINTS ${JSONCPP_LIBDIR} ${JSONCPP_LIBRARY_DIRS}
+    )
+    if (jsoncpp_lib${libname})
+      list(APPEND fulllibs ${jsoncpp_lib${libname}})
+    else ()
+      list(APPEND fulllibs ${libname})
+    endif ()
+  endforeach ()
+  set(JSONCPP_LIBRARIES ${fulllibs})
+
+  set(JSONCPP_DEFINITIONS ${JSONCPP_CFLAGS})
+else ()
+  set(JSONCPP_DEFINITIONS)
+
+  find_path(JSONCPP_INCLUDE_DIR json/json.h
+    PATHS ENV JSONCPP_INCLUDE ENV JSONCPP_DIR
+    PATH_SUFFIXES jsoncpp
+    NO_DEFAULT_PATH
+  )
+  find_path(JSONCPP_INCLUDE_DIR json/json.h
+    PATH_SUFFIXES jsoncpp
+  )
+  mark_as_advanced(JSONCPP_INCLUDE_DIR)
+  set(JSONCPP_INCLUDE_DIRS "${JSONCPP_INCLUDE_DIR}")
+
+  find_library(JSONCPP_LIBRARY NAMES jsoncpp
+    HINTS ENV JSONCPP_LIB ENV JSONCPP_DIR
+    NO_DEFAULT_PATH
+  )
+  find_library(JSONCPP_LIBRARY NAMES jsoncpp)
+  mark_as_advanced(JSONCPP_LIBRARY)
+  set(JSON_LIBRARIES ${JSON_LIBRARY})
+endif ()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Jsoncpp DEFAULT_MSG JSONCPP_INCLUDE_DIRS JSONCPP_LIBRARIES JSONCPP_DEFINITIONS)
+
+if (Jsoncpp_FOUND)
+  add_library(jsoncpp INTERFACE IMPORTED)
+  foreach (incl IN LISTS JSONCPP_INCLUDE_DIRS)
+    set_property(TARGET jsoncpp APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${incl})
+  endforeach ()
+  foreach (libname IN LISTS JSONCPP_LIBRARIES)
+    set_property(TARGET jsoncpp APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${libname})
+  endforeach ()
+  foreach (opt IN LISTS JSONCPP_DEFINITIONS)
+    set_property(TARGET jsoncpp APPEND PROPERTY INTERFACE_COMPILE_OPTIONS ${opt})
+  endforeach ()
+endif ()
diff --git a/final/cmake/PollyConfig.cmake.in b/final/cmake/PollyConfig.cmake.in
new file mode 100644
index 0000000..1329071
--- /dev/null
+++ b/final/cmake/PollyConfig.cmake.in
@@ -0,0 +1,43 @@
+# This file allows users to call find_package(Polly) and pick up our targets.
+
+find_package(LLVM REQUIRED CONFIG
+             HINTS "@POLLY_CONFIG_LLVM_CMAKE_DIR@")
+
+set(Polly_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR})
+set(Polly_BUNDLED_ISL @POLLY_BUNDLED_ISL@)
+set(Polly_BUNDLED_JSONCPP @POLLY_BUNDLED_JSONCPP@)
+set(Polly_ENABLE_GPGPU_CODEGEN @POLLY_ENABLE_GPGPU_CODEGEN@)
+
+set(Polly_DEFINITIONS ${LLVM_DEFINITIONS})
+set(Polly_INCLUDE_DIRS @POLLY_CONFIG_INCLUDE_DIRS@ ${LLVM_INCLUDE_DIRS})
+set(Polly_LIBRARY_DIRS @POLLY_CONFIG_LIBRARY_DIRS@)
+set(Polly_EXPORTED_TARGETS @POLLY_CONFIG_EXPORTED_TARGETS@)
+set(Polly_LIBRARIES ${LLVM_LIBRARIES} ${Polly_EXPORTED_TARGETS})
+
+# Imported Targets:
+@ISL_CONFIG_CODE@
+
+if (Polly_ENABLE_GPGPU_CODEGEN AND NOT TARGET PollyPPCG)
+  add_library(PollyPPCG @POLLY_CONFIG_TARGET_PollyPPCG_TYPE@ IMPORTED)
+  set_property(TARGET PollyPPCG PROPERTY INTERFACE_LINK_LIBRARIES @ISL_TARGET@)
+endif()
+
+if (NOT TARGET Polly)
+  add_library(Polly @POLLY_CONFIG_TARGET_Polly_TYPE@ IMPORTED)
+  set_property(TARGET Polly PROPERTY INTERFACE_LINK_LIBRARIES @ISL_TARGET@)
+  if (Polly_ENABLE_GPGPU_CODEGEN)
+    set_property(TARGET Polly APPEND PROPERTY INTERFACE_LINK_LIBRARIES PollyPPCG)
+  endif()
+  set_property(TARGET Polly APPEND PROPERTY INTERFACE_LINK_LIBRARIES @JSONCPP_LIBRARIES@)
+endif()
+
+if (NOT TARGET LLVMPolly)
+  add_library(LLVMPolly @POLLY_CONFIG_TARGET_LLVMPolly_TYPE@ IMPORTED)
+  set_property(TARGET LLVMPolly PROPERTY INTERFACE_LINK_LIBRARIES Polly)
+endif()
+
+# Exported locations:
+file(GLOB CONFIG_FILES "${Polly_CMAKE_DIR}/PollyExports-*.cmake")
+foreach(f ${CONFIG_FILES})
+  include(${f})
+endforeach()
diff --git a/final/cmake/polly_macros.cmake b/final/cmake/polly_macros.cmake
new file mode 100644
index 0000000..32bed50
--- /dev/null
+++ b/final/cmake/polly_macros.cmake
@@ -0,0 +1,88 @@
+
+include(CMakeParseArguments)
+
+macro(add_polly_library name)
+  cmake_parse_arguments(ARG "" "" "" ${ARGN})
+  set(srcs ${ARG_UNPARSED_ARGUMENTS})
+  if(MSVC_IDE OR XCODE)
+    file( GLOB_RECURSE headers *.h *.td *.def)
+    set(srcs ${srcs} ${headers})
+    string( REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR})
+    list( GET split_path -1 dir)
+    file( GLOB_RECURSE headers
+      ../../include/polly${dir}/*.h)
+    set(srcs ${srcs} ${headers})
+  endif(MSVC_IDE OR XCODE)
+  if (MODULE)
+    set(libkind MODULE)
+  elseif (SHARED_LIBRARY)
+    set(libkind SHARED)
+  else()
+    set(libkind)
+  endif()
+  add_library( ${name} ${libkind} ${srcs} )
+  set_target_properties(${name} PROPERTIES FOLDER "Polly")
+
+  if( LLVM_COMMON_DEPENDS )
+    add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} )
+  endif( LLVM_COMMON_DEPENDS )
+  if( LLVM_USED_LIBS )
+    foreach(lib ${LLVM_USED_LIBS})
+      target_link_libraries( ${name} ${lib} )
+    endforeach(lib)
+  endif( LLVM_USED_LIBS )
+
+  if(POLLY_LINK_LIBS)
+    foreach(lib ${POLLY_LINK_LIBS})
+      target_link_libraries(${name} ${lib})
+    endforeach(lib)
+  endif(POLLY_LINK_LIBS)
+
+  if( LLVM_LINK_COMPONENTS )
+    llvm_config(${name} ${LLVM_LINK_COMPONENTS})
+  endif( LLVM_LINK_COMPONENTS )
+  if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ${name} STREQUAL "LLVMPolly")
+    install(TARGETS ${name}
+      EXPORT LLVMExports
+      LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+      ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX})
+  endif()
+  set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS ${name})
+endmacro(add_polly_library)
+
+macro(add_polly_loadable_module name)
+  set(srcs ${ARGN})
+  # klduge: pass different values for MODULE with multiple targets in same dir
+  # this allows building shared-lib and module in same dir
+  # there must be a cleaner way to achieve this....
+  if (MODULE)
+  else()
+    set(GLOBAL_NOT_MODULE TRUE)
+  endif()
+  set(MODULE TRUE)
+  add_polly_library(${name} ${srcs})
+  set_target_properties(${name} PROPERTIES FOLDER "Polly")
+  if (GLOBAL_NOT_MODULE)
+    unset (MODULE)
+  endif()
+  if (APPLE)
+    # Darwin-specific linker flags for loadable modules.
+    set_target_properties(${name} PROPERTIES
+      LINK_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress")
+  endif()
+endmacro(add_polly_loadable_module)
+
+# Use C99-compatible compile mode for all C source files of a target.
+function(target_enable_c99 _target)
+  if(CMAKE_VERSION VERSION_GREATER "3.1")
+    set_target_properties("${_target}" PROPERTIES C_STANDARD 99)
+  elseif(CMAKE_COMPILER_IS_GNUCC)
+    get_target_property(_sources "${_target}" SOURCES)
+    foreach(_file IN LISTS _sources)
+      get_source_file_property(_lang "${_file}" LANGUAGE)
+      if(_lang STREQUAL "C")
+        set_source_files_properties(${_file} COMPILE_FLAGS "-std=gnu99")
+      endif()
+    endforeach()
+  endif()
+endfunction()
diff --git a/final/docs/Architecture.rst b/final/docs/Architecture.rst
new file mode 100644
index 0000000..f2ae2b1
--- /dev/null
+++ b/final/docs/Architecture.rst
@@ -0,0 +1,93 @@
+================
+The Architecture
+================
+
+Polly is a loop optimizer for LLVM. Starting from LLVM-IR it detects and
+extracts interesting loop kernels. For each kernel a mathematical model is
+derived which precisely describes the individual computations and memory
+accesses in the kernels. Within Polly a variety of analysis and code
+transformations are performed on this mathematical model. After all
+optimizations have been derived and applied, optimized LLVM-IR is regenerated
+and inserted into the LLVM-IR module.
+
+.. image:: images/architecture.png
+    :align: center
+
+Polly in the LLVM pass pipeline
+-------------------------------
+
+The standard LLVM pass pipeline as it is used in -O1/-O2/-O3 mode of clang/opt
+consists of a sequence of passes that can be grouped in different conceptual
+phases. The first phase, we call it here **Canonicalization**, is a scalar
+canonicalization phase that contains passes like -mem2reg, -instcombine,
+-cfgsimplify, or early loop unrolling. It has the goal of removing and
+simplifying the given IR as much as possible focusing mostly on scalar
+optimizations. The second phase consists of three conceptual groups that  are
+executed in the so-called **Inliner cycle**, This is again a set of **Scalar
+Simplification** passes, a set of **Simple Loop Optimizations**, and the
+**Inliner** itself. Even though these passes make up the majority of the LLVM
+pass pipeline, the primary goal of these passes is still canonicalization
+without loosing semantic information that complicates later analysis. As part of
+the inliner cycle, the LLVM inliner step-by-step tries to inline functions, runs
+canonicalization passes to exploit newly exposed simplification opportunities,
+and then tries to inline the further simplified functions. Some simple loop
+optimizations are executed as part of the inliner cycle. Even though they
+perform some optimizations, their primary goal is still the simplification of
+the program code. Loop invariant code motion is one such optimization that
+besides being beneficial for program performance also allows us to move
+computation out of loops and in the best case enables us to eliminate certain
+loops completely.  Only after the inliner cycle has been finished, a last
+**Target Specialization** phase is run, where IR complexity is deliberately
+increased to take advantage of target specific features that maximize the
+execution performance on the device we target. One of the principal
+optimizations in this phase is vectorization, but also target specific loop
+unrolling, or some loop transformations (e.g., distribution) that expose more
+vectorization opportunities.
+
+.. image:: images/LLVM-Passes-only.png
+    :align: center
+
+Polly can conceptually be run at three different positions in the pass pipeline.
+As an early optimizer before the standard LLVM pass pipeline, as a later
+optimizer as part of the target specialization sequence, and theoretically also
+with the loop optimizations in the inliner cycle. We only discuss the first two
+options, as running Polly in the inline loop, is likely to disturb the inliner
+and is consequently not a good idea.
+
+.. image:: images/LLVM-Passes-all.png
+    :align: center
+
+Running Polly early before the standard pass pipeline has the benefit that the
+LLVM-IR processed by Polly is still very close to the original input code.
+Hence, it is less likely that transformations applied by LLVM change the IR in
+ways not easily understandable for the programmer. As a result, user feedback is
+likely better and it is less likely that kernels that in C seem a perfect fit
+for Polly have been transformed such that Polly can not handle them any
+more. On the other hand, codes that require inlining to be optimized won't
+benefit if Polly is scheduled at this position. The additional set of
+canonicalization passes required will result in a small, but general compile
+time increase and some random run-time performance changes due to slightly
+different IR being passed through the optimizers. To force Polly to run early in
+the pass pipleline use the option *-polly-position=early* (default today).
+
+.. image:: images/LLVM-Passes-early.png
+    :align: center
+
+Running Polly right before the vectorizer has the benefit that the full inlining
+cycle has been run and as a result even heavily templated C++ code could
+theoretically benefit from Polly (more work is necessary to make Polly here
+really effective). As the IR that is passed to Polly has already been
+canonicalized, there is also no need to run additional canonicalization passes.
+General compile time is almost not affected by Polly, as detection of loop
+kernels is generally very fast and the actual optimization and cleanup passes
+are only run on functions which contain loop kernels that are worth optimizing.
+However, due to the many optimizations that LLVM runs before Polly the IR that
+reaches Polly often has additional scalar dependences that make Polly a lot less
+efficient. To force Polly to run before the vectorizer in the pass pipleline use
+the option *-polly-position=before-vectorizer*. This position is not yet the
+default for Polly, but work is on its way to be effective even in presence of
+scalar dependences. After this work has been completed, Polly will likely use
+this position by default.
+
+.. image:: images/LLVM-Passes-late.png
+    :align: center
diff --git a/final/docs/CMakeLists.txt b/final/docs/CMakeLists.txt
new file mode 100644
index 0000000..a1ef5ce
--- /dev/null
+++ b/final/docs/CMakeLists.txt
@@ -0,0 +1,103 @@
+if (DOXYGEN_FOUND)
+if (LLVM_ENABLE_DOXYGEN)
+  set(abs_srcdir ${CMAKE_CURRENT_SOURCE_DIR})
+  set(abs_builddir ${CMAKE_CURRENT_BINARY_DIR})
+
+  if (HAVE_DOT)
+    set(DOT ${LLVM_PATH_DOT})
+  endif()
+
+  if (LLVM_DOXYGEN_EXTERNAL_SEARCH)
+    set(enable_searchengine "YES")
+    set(searchengine_url "${LLVM_DOXYGEN_SEARCHENGINE_URL}")
+    set(enable_server_based_search "YES")
+    set(enable_external_search "YES")
+    set(extra_search_mappings "${LLVM_DOXYGEN_SEARCH_MAPPINGS}")
+  else()
+    set(enable_searchengine "NO")
+    set(searchengine_url "")
+    set(enable_server_based_search "NO")
+    set(enable_external_search "NO")
+    set(extra_search_mappings "")
+  endif()
+
+  # If asked, configure doxygen for the creation of a Qt Compressed Help file.
+  if (LLVM_ENABLE_DOXYGEN_QT_HELP)
+    set(POLLY_DOXYGEN_QCH_FILENAME "org.llvm.polly.qch" CACHE STRING
+      "Filename of the Qt Compressed help file")
+    set(POLLY_DOXYGEN_QHP_NAMESPACE "org.llvm.polly" CACHE STRING
+      "Namespace under which the intermediate Qt Help Project file lives")
+    set(POLLY_DOXYGEN_QHP_CUST_FILTER_NAME "Clang ${POLLY_VERSION}" CACHE STRING
+      "See http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-filters")
+    set(POLLY_DOXYGEN_QHP_CUST_FILTER_ATTRS "Clang,${POLLY_VERSION}" CACHE STRING
+      "See http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes")
+    set(polly_doxygen_generate_qhp "YES")
+    set(polly_doxygen_qch_filename "${POLLY_DOXYGEN_QCH_FILENAME}")
+    set(polly_doxygen_qhp_namespace "${POLLY_DOXYGEN_QHP_NAMESPACE}")
+    set(polly_doxygen_qhelpgenerator_path "${LLVM_DOXYGEN_QHELPGENERATOR_PATH}")
+    set(polly_doxygen_qhp_cust_filter_name "${POLLY_DOXYGEN_QHP_CUST_FILTER_NAME}")
+    set(polly_doxygen_qhp_cust_filter_attrs "${POLLY_DOXYGEN_QHP_CUST_FILTER_ATTRS}")
+  else()
+    set(polly_doxygen_generate_qhp "NO")
+    set(polly_doxygen_qch_filename "")
+    set(polly_doxygen_qhp_namespace "")
+    set(polly_doxygen_qhelpgenerator_path "")
+    set(polly_doxygen_qhp_cust_filter_name "")
+    set(polly_doxygen_qhp_cust_filter_attrs "")
+  endif()
+
+  option(LLVM_DOXYGEN_SVG
+    "Use svg instead of png files for doxygen graphs." OFF)
+  if (LLVM_DOXYGEN_SVG)
+    set(DOT_IMAGE_FORMAT "svg")
+  else()
+    set(DOT_IMAGE_FORMAT "png")
+  endif()
+
+  configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxygen.cfg.in
+    ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg @ONLY)
+
+  set(abs_top_srcdir)
+  set(abs_top_builddir)
+  set(DOT)
+  set(enable_searchengine)
+  set(searchengine_url)
+  set(enable_server_based_search)
+  set(enable_external_search)
+  set(extra_search_mappings)
+  set(polly_doxygen_generate_qhp)
+  set(polly_doxygen_qch_filename)
+  set(polly_doxygen_qhp_namespace)
+  set(polly_doxygen_qhelpgenerator_path)
+  set(polly_doxygen_qhp_cust_filter_name)
+  set(polly_doxygen_qhp_cust_filter_attrs)
+  set(DOT_IMAGE_FORMAT)
+
+  add_custom_target(doxygen-polly
+    COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg
+    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+    COMMENT "Generating polly doxygen documentation." VERBATIM)
+
+  if (LLVM_BUILD_DOCS)
+    add_dependencies(doxygen doxygen-polly)
+  endif()
+
+  if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+    install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doxygen/html
+      DESTINATION docs/html)
+  endif()
+endif()
+endif()
+
+if (LLVM_ENABLE_SPHINX)
+  include(AddSphinxTarget)
+  if (SPHINX_FOUND)
+    if (${SPHINX_OUTPUT_HTML})
+      add_sphinx_target(html polly)
+    endif()
+    if (${SPHINX_OUTPUT_MAN})
+      add_sphinx_target(man polly)
+    endif()
+  endif()
+endif()
+
diff --git a/final/docs/HowToManuallyUseTheIndividualPiecesOfPolly.rst b/final/docs/HowToManuallyUseTheIndividualPiecesOfPolly.rst
new file mode 100644
index 0000000..1822923
--- /dev/null
+++ b/final/docs/HowToManuallyUseTheIndividualPiecesOfPolly.rst
@@ -0,0 +1,475 @@
+==================================================
+How to manually use the Individual pieces of Polly
+==================================================
+
+Execute the individual Polly passes manually
+============================================
+
+.. sectionauthor:: Singapuram Sanjay Srivallabh
+
+This example presents the individual passes that are involved when optimizing
+code with Polly. We show how to execute them individually and explain for
+each which analysis is performed or what transformation is applied. In this
+example the polyhedral transformation is user-provided to show how much
+performance improvement can be expected by an optimal automatic optimizer.
+
+1. **Create LLVM-IR from the C code**
+-------------------------------------
+        Polly works on LLVM-IR. Hence it is necessary to translate the source
+        files into LLVM-IR. If more than one file should be optimized the
+        files can be combined into a single file with llvm-link.
+
+        .. code-block:: console
+
+                clang -S -emit-llvm matmul.c -o matmul.s
+
+
+2. **Prepare the LLVM-IR for Polly**
+------------------------------------
+
+        Polly is only able to work with code that matches a canonical form.
+        To translate the LLVM-IR into this form we use a set of
+        canonicalication passes. They are scheduled by using
+        '-polly-canonicalize'.
+
+        .. code-block:: console
+
+                opt -S -polly-canonicalize matmul.s > matmul.preopt.ll
+
+3. **Show the SCoPs detected by Polly (optional)**
+--------------------------------------------------
+
+        To understand if Polly was able to detect SCoPs, we print the structure
+        of the detected SCoPs. In our example two SCoPs are detected. One in
+        'init_array' the other in 'main'.
+
+        .. code-block:: console
+
+                $ opt -polly-ast -analyze -q matmul.preopt.ll -polly-process-unprofitable
+
+        .. code-block:: guess
+
+                :: isl ast :: init_array :: %for.cond1.preheader---%for.end19
+
+                if (1)
+
+                    for (int c0 = 0; c0 <= 1535; c0 += 1)
+                      for (int c1 = 0; c1 <= 1535; c1 += 1)
+                        Stmt_for_body3(c0, c1);
+
+                else
+                    {  /* original code */ }
+
+                :: isl ast :: main :: %for.cond1.preheader---%for.end30
+
+                if (1)
+
+                    for (int c0 = 0; c0 <= 1535; c0 += 1)
+                      for (int c1 = 0; c1 <= 1535; c1 += 1) {
+                        Stmt_for_body3(c0, c1);
+                        for (int c2 = 0; c2 <= 1535; c2 += 1)
+                          Stmt_for_body8(c0, c1, c2);
+                      }
+
+                else
+                    {  /* original code */ }
+
+4. **Highlight the detected SCoPs in the CFGs of the program (requires graphviz/dotty)**
+----------------------------------------------------------------------------------------
+
+        Polly can use graphviz to graphically show a CFG in which the detected
+        SCoPs are highlighted. It can also create '.dot' files that can be
+        translated by the 'dot' utility into various graphic formats.
+
+
+        .. code-block:: console
+
+                $ opt -view-scops -disable-output matmul.preopt.ll
+                $ opt -view-scops-only -disable-output matmul.preopt.ll
+
+        The output for the different functions:
+
+        - view-scops : main_, init_array_, print_array_
+        - view-scops-only : main-scopsonly_, init_array-scopsonly_, print_array-scopsonly_
+
+.. _main:  http://polly.llvm.org/experiments/matmul/scops.main.dot.png
+.. _init_array: http://polly.llvm.org/experiments/matmul/scops.init_array.dot.png
+.. _print_array: http://polly.llvm.org/experiments/matmul/scops.print_array.dot.png
+.. _main-scopsonly: http://polly.llvm.org/experiments/matmul/scopsonly.main.dot.png
+.. _init_array-scopsonly: http://polly.llvm.org/experiments/matmul/scopsonly.init_array.dot.png
+.. _print_array-scopsonly: http://polly.llvm.org/experiments/matmul/scopsonly.print_array.dot.png
+
+5. **View the polyhedral representation of the SCoPs**
+------------------------------------------------------
+
+        .. code-block:: console
+
+                $ opt -polly-scops -analyze matmul.preopt.ll -polly-process-unprofitable
+
+        .. code-block:: guess
+
+                [...]Printing analysis 'Polly - Create polyhedral description of Scops' for region: 'for.cond1.preheader => for.end19' in function 'init_array':
+                    Function: init_array
+                    Region: %for.cond1.preheader---%for.end19
+                    Max Loop Depth:  2
+                        Invariant Accesses: {
+                        }
+                        Context:
+                        {  :  }
+                        Assumed Context:
+                        {  :  }
+                        Invalid Context:
+                        {  : 1 = 0 }
+                        Arrays {
+                            float MemRef_A[*][1536]; // Element size 4
+                            float MemRef_B[*][1536]; // Element size 4
+                        }
+                        Arrays (Bounds as pw_affs) {
+                            float MemRef_A[*][ { [] -> [(1536)] } ]; // Element size 4
+                            float MemRef_B[*][ { [] -> [(1536)] } ]; // Element size 4
+                        }
+                        Alias Groups (0):
+                            n/a
+                        Statements {
+    	                    Stmt_for_body3
+                                Domain :=
+                                    { Stmt_for_body3[i0, i1] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 };
+                                Schedule :=
+                                    { Stmt_for_body3[i0, i1] -> [i0, i1] };
+                                MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+                                    { Stmt_for_body3[i0, i1] -> MemRef_A[i0, i1] };
+                                MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+                                    { Stmt_for_body3[i0, i1] -> MemRef_B[i0, i1] };
+                        }
+                [...]Printing analysis 'Polly - Create polyhedral description of Scops' for region: 'for.cond1.preheader => for.end30' in function 'main':
+                    Function: main
+                    Region: %for.cond1.preheader---%for.end30
+                    Max Loop Depth:  3
+                    Invariant Accesses: {
+                    }
+                    Context:
+                    {  :  }
+                    Assumed Context:
+                    {  :  }
+                    Invalid Context:
+                    {  : 1 = 0 }
+                    Arrays {
+                        float MemRef_C[*][1536]; // Element size 4
+                        float MemRef_A[*][1536]; // Element size 4
+                        float MemRef_B[*][1536]; // Element size 4
+                    }
+                    Arrays (Bounds as pw_affs) {
+                        float MemRef_C[*][ { [] -> [(1536)] } ]; // Element size 4
+                        float MemRef_A[*][ { [] -> [(1536)] } ]; // Element size 4
+                        float MemRef_B[*][ { [] -> [(1536)] } ]; // Element size 4
+                    }
+                    Alias Groups (0):
+                        n/a
+                    Statements {
+                    	Stmt_for_body3
+                            Domain :=
+                                { Stmt_for_body3[i0, i1] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 };
+                            Schedule :=
+                                { Stmt_for_body3[i0, i1] -> [i0, i1, 0, 0] };
+                            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+                                { Stmt_for_body3[i0, i1] -> MemRef_C[i0, i1] };
+                    	Stmt_for_body8
+                            Domain :=
+                                { Stmt_for_body8[i0, i1, i2] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 and 0 <= i2 <= 1535 };
+                            Schedule :=
+                                { Stmt_for_body8[i0, i1, i2] -> [i0, i1, 1, i2] };
+                            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+                                { Stmt_for_body8[i0, i1, i2] -> MemRef_C[i0, i1] };
+                            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+                                { Stmt_for_body8[i0, i1, i2] -> MemRef_A[i0, i2] };
+                            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+                                { Stmt_for_body8[i0, i1, i2] -> MemRef_B[i2, i1] };
+                            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+                                { Stmt_for_body8[i0, i1, i2] -> MemRef_C[i0, i1] };
+                    }
+
+
+6. **Show the dependences for the SCoPs**
+-----------------------------------------
+
+        .. code-block:: console
+
+	        $ opt -polly-dependences -analyze matmul.preopt.ll -polly-process-unprofitable
+
+        .. code-block:: guess
+
+        	[...]Printing analysis 'Polly - Calculate dependences' for region: 'for.cond1.preheader => for.end19' in function 'init_array':
+        		RAW dependences:
+        			{  }
+        		WAR dependences:
+        			{  }
+        		WAW dependences:
+        			{  }
+        		Reduction dependences:
+        			n/a
+        		Transitive closure of reduction dependences:
+        			{  }
+        	[...]Printing analysis 'Polly - Calculate dependences' for region: 'for.cond1.preheader => for.end30' in function 'main':
+        		RAW dependences:
+        			{ Stmt_for_body3[i0, i1] -> Stmt_for_body8[i0, i1, 0] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535; Stmt_for_body8[i0, i1, i2] -> Stmt_for_body8[i0, i1, 1 + i2] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 and 0 <= i2 <= 1534 }
+        		WAR dependences:
+        			{  }
+        		WAW dependences:
+        			{ Stmt_for_body3[i0, i1] -> Stmt_for_body8[i0, i1, 0] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535; Stmt_for_body8[i0, i1, i2] -> Stmt_for_body8[i0, i1, 1 + i2] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 and 0 <= i2 <= 1534 }
+        		Reduction dependences:
+        			n/a
+        		Transitive closure of reduction dependences:
+        			{  }
+
+7. **Export jscop files**
+-------------------------
+
+        .. code-block:: console
+
+        	$ opt -polly-export-jscop matmul.preopt.ll -polly-process-unprofitable
+
+        .. code-block:: guess
+
+	        [...]Writing JScop '%for.cond1.preheader---%for.end19' in function 'init_array' to './init_array___%for.cond1.preheader---%for.end19.jscop'.
+
+	        Writing JScop '%for.cond1.preheader---%for.end30' in function 'main' to './main___%for.cond1.preheader---%for.end30.jscop'.
+
+
+
+8. **Import the changed jscop files and print the updated SCoP structure (optional)**
+-------------------------------------------------------------------------------------
+
+	Polly can reimport jscop files, in which the schedules of the statements
+        are changed. These changed schedules are used to descripe
+        transformations. It is possible to import different jscop files by
+        providing the postfix of the jscop file that is imported.
+
+	We apply three different transformations on the SCoP in the main
+        function. The jscop files describing these transformations are
+        hand written (and available in docs/experiments/matmul).
+
+	**No Polly**
+
+	As a baseline we do not call any Polly code generation, but only apply the normal -O3 optimizations.
+
+	.. code-block:: console
+
+		$ opt matmul.preopt.ll -polly-import-jscop -polly-ast -analyze -polly-process-unprofitable
+
+	.. code-block:: c
+
+		[...]
+		:: isl ast :: main :: %for.cond1.preheader---%for.end30
+		
+		if (1)
+		
+		    for (int c0 = 0; c0 <= 1535; c0 += 1)
+		      for (int c1 = 0; c1 <= 1535; c1 += 1) {
+		        Stmt_for_body3(c0, c1);
+		        for (int c3 = 0; c3 <= 1535; c3 += 1)
+		          Stmt_for_body8(c0, c1, c3);
+		      }
+		
+		else
+		    {  /* original code */ }
+		[...]
+
+	**Loop Interchange (and Fission to allow the interchange)**
+
+	We split the loops and can now apply an interchange of the loop dimensions that enumerate Stmt_for_body8.
+
+	.. Although I feel (and have created a .jscop) we can avoid splitting the loops.
+
+	.. code-block:: console
+
+		$ opt matmul.preopt.ll -polly-import-jscop -polly-import-jscop-postfix=interchanged -polly-ast -analyze -polly-process-unprofitable
+
+	.. code-block:: c
+
+		[...]
+		:: isl ast :: main :: %for.cond1.preheader---%for.end30
+
+		if (1)
+
+		    {
+		      for (int c1 = 0; c1 <= 1535; c1 += 1)
+		        for (int c2 = 0; c2 <= 1535; c2 += 1)
+		          Stmt_for_body3(c1, c2);
+		      for (int c1 = 0; c1 <= 1535; c1 += 1)
+		        for (int c2 = 0; c2 <= 1535; c2 += 1)
+		          for (int c3 = 0; c3 <= 1535; c3 += 1)
+		            Stmt_for_body8(c1, c3, c2);
+		    }
+
+		else
+		    {  /* original code */ }
+		[...]
+
+	**Interchange + Tiling**
+
+	In addition to the interchange we now tile the second loop nest.
+
+	.. code-block:: console
+
+		$ opt matmul.preopt.ll -polly-import-jscop -polly-import-jscop-postfix=interchanged+tiled -polly-ast -analyze -polly-process-unprofitable
+
+	.. code-block:: c
+
+		[...]
+		:: isl ast :: main :: %for.cond1.preheader---%for.end30
+
+		if (1)
+
+		    {
+		      for (int c1 = 0; c1 <= 1535; c1 += 1)
+		        for (int c2 = 0; c2 <= 1535; c2 += 1)
+		          Stmt_for_body3(c1, c2);
+		      for (int c1 = 0; c1 <= 1535; c1 += 64)
+		        for (int c2 = 0; c2 <= 1535; c2 += 64)
+		          for (int c3 = 0; c3 <= 1535; c3 += 64)
+		            for (int c4 = c1; c4 <= c1 + 63; c4 += 1)
+		              for (int c5 = c3; c5 <= c3 + 63; c5 += 1)
+		                for (int c6 = c2; c6 <= c2 + 63; c6 += 1)
+		                  Stmt_for_body8(c4, c6, c5);
+		    }
+
+		else
+		    {  /* original code */ }
+		[...]
+
+
+	**Interchange + Tiling + Strip-mining to prepare vectorization**
+
+	To later allow vectorization we create a so called trivially
+        parallelizable loop. It is innermost, parallel and has only four
+        iterations. It can be replaced by 4-element SIMD instructions.
+
+	.. code-block:: console
+
+		$ opt matmul.preopt.ll -polly-import-jscop -polly-import-jscop-postfix=interchanged+tiled -polly-ast -analyze -polly-process-unprofitable
+
+	.. code-block:: c
+
+		[...]
+		:: isl ast :: main :: %for.cond1.preheader---%for.end30
+
+		if (1)
+
+		    {
+		      for (int c1 = 0; c1 <= 1535; c1 += 1)
+		        for (int c2 = 0; c2 <= 1535; c2 += 1)
+		          Stmt_for_body3(c1, c2);
+		      for (int c1 = 0; c1 <= 1535; c1 += 64)
+		        for (int c2 = 0; c2 <= 1535; c2 += 64)
+		          for (int c3 = 0; c3 <= 1535; c3 += 64)
+		            for (int c4 = c1; c4 <= c1 + 63; c4 += 1)
+		              for (int c5 = c3; c5 <= c3 + 63; c5 += 1)
+		                for (int c6 = c2; c6 <= c2 + 63; c6 += 4)
+		                  for (int c7 = c6; c7 <= c6 + 3; c7 += 1)
+		                    Stmt_for_body8(c4, c7, c5);
+		    }
+
+		else
+		    {  /* original code */ }
+		[...]
+
+9. **Codegenerate the SCoPs**
+-----------------------------
+
+	This generates new code for the SCoPs detected by polly. If
+        -polly-import-jscop is present, transformations specified in the
+        imported jscop files will be applied.
+
+
+	.. code-block:: console
+
+		$ opt matmul.preopt.ll | opt -O3 > matmul.normalopt.ll
+		
+	.. code-block:: console
+
+		$ opt matmul.preopt.ll -polly-import-jscop -polly-import-jscop-postfix=interchanged -polly-codegen -polly-process-unprofitable | opt -O3 > matmul.polly.interchanged.ll
+
+	.. code-block:: guess
+
+		Reading JScop '%for.cond1.preheader---%for.end19' in function 'init_array' from './init_array___%for.cond1.preheader---%for.end19.jscop.interchanged'.
+		File could not be read: No such file or directory
+		Reading JScop '%for.cond1.preheader---%for.end30' in function 'main' from './main___%for.cond1.preheader---%for.end30.jscop.interchanged'.
+
+	.. code-block:: console
+
+		$ opt matmul.preopt.ll -polly-import-jscop -polly-import-jscop-postfix=interchanged+tiled -polly-codegen -polly-process-unprofitable | opt -O3 > matmul.polly.interchanged+tiled.ll
+		
+	.. code-block:: guess
+
+		Reading JScop '%for.cond1.preheader---%for.end19' in function 'init_array' from './init_array___%for.cond1.preheader---%for.end19.jscop.interchanged+tiled'.
+		File could not be read: No such file or directory
+		Reading JScop '%for.cond1.preheader---%for.end30' in function 'main' from './main___%for.cond1.preheader---%for.end30.jscop.interchanged+tiled'.
+
+	.. code-block:: console
+
+		$ opt matmul.preopt.ll -polly-import-jscop -polly-import-jscop-postfix=interchanged+tiled+vector -polly-codegen -polly-vectorizer=polly -polly-process-unprofitable | opt -O3 > matmul.polly.interchanged+tiled+vector.ll
+
+	.. code-block:: guess
+
+		Reading JScop '%for.cond1.preheader---%for.end19' in function 'init_array' from './init_array___%for.cond1.preheader---%for.end19.jscop.interchanged+tiled+vector'.
+		File could not be read: No such file or directory
+		Reading JScop '%for.cond1.preheader---%for.end30' in function 'main' from './main___%for.cond1.preheader---%for.end30.jscop.interchanged+tiled+vector'.
+
+	.. code-block:: console
+
+		$ opt matmul.preopt.ll -polly-import-jscop -polly-import-jscop-postfix=interchanged+tiled+vector -polly-codegen -polly-vectorizer=polly -polly-parallel -polly-process-unprofitable | opt -O3 > matmul.polly.interchanged+tiled+openmp.ll
+
+	.. code-block:: guess
+
+		Reading JScop '%for.cond1.preheader---%for.end19' in function 'init_array' from './init_array___%for.cond1.preheader---%for.end19.jscop.interchanged+tiled+vector'.
+		File could not be read: No such file or directory
+		Reading JScop '%for.cond1.preheader---%for.end30' in function 'main' from './main___%for.cond1.preheader---%for.end30.jscop.interchanged+tiled+vector'.
+
+
+10. **Create the executables**
+------------------------------
+
+        .. code-block:: console
+
+	        $ llc matmul.normalopt.ll -o matmul.normalopt.s && gcc matmul.normalopt.s -o matmul.normalopt.exe
+	        $ llc matmul.polly.interchanged.ll -o matmul.polly.interchanged.s && gcc matmul.polly.interchanged.s -o matmul.polly.interchanged.exe
+	        $ llc matmul.polly.interchanged+tiled.ll -o matmul.polly.interchanged+tiled.s && gcc matmul.polly.interchanged+tiled.s -o matmul.polly.interchanged+tiled.exe
+	        $ llc matmul.polly.interchanged+tiled+vector.ll -o matmul.polly.interchanged+tiled+vector.s && gcc matmul.polly.interchanged+tiled+vector.s -o matmul.polly.interchanged+tiled+vector.exe
+        	$ llc matmul.polly.interchanged+tiled+vector+openmp.ll -o matmul.polly.interchanged+tiled+vector+openmp.s && gcc -fopenmp matmul.polly.interchanged+tiled+vector+openmp.s -o matmul.polly.interchanged+tiled+vector+openmp.exe
+
+11. **Compare the runtime of the executables**
+----------------------------------------------
+
+	By comparing the runtimes of the different code snippets we see that a
+        simple loop interchange gives here the largest performance boost.
+        However in this case, adding vectorization and using OpenMP degrades
+        the performance.
+
+        .. code-block:: console
+
+	        $ time ./matmul.normalopt.exe
+
+	        real	0m11.295s
+        	user	0m11.288s
+        	sys	0m0.004s
+        	$ time ./matmul.polly.interchanged.exe
+
+        	real	0m0.988s
+	        user	0m0.980s
+	        sys	0m0.008s
+	        $ time ./matmul.polly.interchanged+tiled.exe
+
+	        real	0m0.830s
+	        user	0m0.816s
+	        sys	0m0.012s
+	        $ time ./matmul.polly.interchanged+tiled+vector.exe
+
+        	real	0m5.430s
+        	user	0m5.424s
+        	sys	0m0.004s
+        	$ time ./matmul.polly.interchanged+tiled+vector+openmp.exe
+
+        	real	0m3.184s
+        	user	0m11.972s
+        	sys	0m0.036s
+
diff --git a/final/docs/Performance.rst b/final/docs/Performance.rst
new file mode 100644
index 0000000..51716e0
--- /dev/null
+++ b/final/docs/Performance.rst
@@ -0,0 +1,57 @@
+.. include:: <isonum.txt>
+==================================================
+Performance
+==================================================
+
+High-Performance Generalized Matrix Multiplication
+--------------------------------------------------
+
+Polly automatically detects and optimizes generalized matrix multiplication,
+the computation C |larr| α ⊗ C ⊕ β ⊗ A ⊗ B, where A, B, and C are three appropriately sized matrices,
+⊕ and ⊗ operations are originating from the corresponding matrix semiring, and α and β are
+constants, and beta is not equal to zero. It allows to obtain the highly optimized form structured
+similar to the expert implementation of GEMM that can be found in GotoBLAS and its successors. The
+performance evaluation of GEMM is shown in the following figure.
+
+
+    .. image:: images/GEMM_double.png
+       :align: center
+
+
+
+Compile Time Impact of Polly
+----------------------------
+
+Clang+LLVM+Polly are compiled using Clang on a Intel(R) Core(TM) i7-7700 based system. The experiment
+is repeated twice: with and without Polly enabled in order to measure its compile time impact.
+
+The following versions are used:
+
+
+- Polly (git hash 0db98a4837b6f233063307bb9184374175401922)
+- Clang (git hash 3e1d04a92b51ed36163995c96c31a0e4bbb1561d)
+- LLVM  git hash 0265ec7ebad69a47f5c899d95295b5eb41aba68e)
+
+`ninja <https://ninja-build.org/>`_ is used as the build system.
+
+For both cases the whole compilation was performed five times. The compile times in seconds are shown in the following table.
+
++----------------------------+
+|       Compile Time         |
++--------------+-------------+
+|Polly Disabled|Polly Enabled|
++==============+=============+
+|964           |977          |
++--------------+-------------+
+|964           |980          |
++--------------+-------------+
+|967           |981          |
++--------------+-------------+
+|967           |981          |
++--------------+-------------+
+|968           |982          |
++--------------+-------------+
+
+
+The median compile time without Polly enabled is 967 seconds and with Polly enabled it is 981 seconds. The overhead is 1.4%.
+
diff --git a/final/docs/ReleaseNotes.rst b/final/docs/ReleaseNotes.rst
new file mode 100644
index 0000000..1055e05
--- /dev/null
+++ b/final/docs/ReleaseNotes.rst
@@ -0,0 +1,3 @@
+=================
+Release Notes 6.0
+=================
diff --git a/final/docs/TipsAndTricks.rst b/final/docs/TipsAndTricks.rst
new file mode 100644
index 0000000..d399da8
--- /dev/null
+++ b/final/docs/TipsAndTricks.rst
@@ -0,0 +1,56 @@
+==================================================
+Tips and Tricks on using and contributing to Polly
+==================================================
+
+Commiting to polly trunk
+------------------------
+    - `General reference to git-svn workflow <https://stackoverflow.com/questions/190431/is-git-svn-dcommit-after-merging-in-git-dangerous>`_
+
+
+Using bugpoint to track down errors in large files
+--------------------------------------------------
+
+    If you know the ``opt`` invocation and have a large ``.ll`` file that causes
+    an error, ``bugpoint`` allows one to reduce the size of test cases.
+
+    The general calling pattern is:
+
+    - ``$ bugpoint <file.ll> <pass that causes the crash> -opt-args <opt option flags>``
+
+    An example invocation is:
+
+    - ``$ bugpoint crash.ll -polly-codegen -opt-args  -polly-canonicalize -polly-process-unprofitable``
+
+    For more documentation on bugpoint, `Visit the LLVM manual <http://llvm.org/docs/Bugpoint.html>`_
+
+
+Understanding which pass makes a particular change
+--------------------------------------------------
+
+    If you know that something like `opt -O3 -polly` makes a change, but you wish to
+    isolate which pass makes a change, the steps are as follows:
+
+    - ``$ bugpoint -O3 file.ll -opt-args -polly``  will allow bugpoint to track down the pass which causes the crash.
+
+    To do this manually:
+
+    - ``$ opt -O3 -polly -debug-pass=Arguments`` to get all passes that are run by default. ``-debug-pass=Arguments`` will list all passes that have run.
+    - Bisect down to the pass that changes it.
+
+
+Debugging regressions introduced at some unknown earlier point
+--------------------------------------------------------------
+
+In case of a regression in performance or correctness (e.g., an earlier version
+of Polly behaved as expected and a later version does not), bisecting over the
+version history is the standard approach to identify the commit that introduced
+the regression.
+
+LLVM has a single repository that contains all projects. It can be cloned at:
+`<https://github.com/llvm-project/llvm-project-20170507>`_. How to bisect on a
+git repository is explained here
+`<https://www.metaltoad.com/blog/beginners-guide-git-bisect-process-elimination>`_.
+The bisect process can also be automated as explained here:
+`<https://www.metaltoad.com/blog/mechanizing-git-bisect-bug-hunting-lazy>`_.
+An LLVM specific run script is available here:
+`<https://gist.github.com/dcci/891cd98d80b1b95352a407d80914f7cf>`_.
diff --git a/final/docs/UsingPollyWithClang.rst b/final/docs/UsingPollyWithClang.rst
new file mode 100644
index 0000000..ade5b41
--- /dev/null
+++ b/final/docs/UsingPollyWithClang.rst
@@ -0,0 +1,132 @@
+======================
+Using Polly with Clang
+======================
+
+This documentation discusses how Polly can be used in Clang to automatically
+optimize C/C++ code during compilation.
+
+
+.. warning::
+
+  Warning: clang/LLVM/Polly need to be in sync (compiled from the same SVN
+  revision).
+
+Make Polly available from Clang
+===============================
+
+Polly is available through clang, opt, and bugpoint, if Polly was checked out
+into tools/polly before compilation. No further configuration is needed.
+
+Optimizing with Polly
+=====================
+
+Optimizing with Polly is as easy as adding -O3 -mllvm -polly to your compiler
+flags (Polly is only available at -O3).
+
+.. code-block:: console
+
+  clang -O3 -mllvm -polly file.c
+
+Automatic OpenMP code generation
+================================
+
+To automatically detect parallel loops and generate OpenMP code for them you
+also need to add -mllvm -polly-parallel -lgomp to your CFLAGS.
+
+.. code-block:: console
+
+  clang -O3 -mllvm -polly -mllvm -polly-parallel -lgomp file.c
+
+Automatic Vector code generation
+================================
+
+Automatic vector code generation can be enabled by adding -mllvm
+-polly-vectorizer=stripmine to your CFLAGS.
+
+.. code-block:: console
+
+  clang -O3 -mllvm -polly -mllvm -polly-vectorizer=stripmine file.c
+
+Extract a preoptimized LLVM-IR file
+===================================
+
+Often it is useful to derive from a C-file the LLVM-IR code that is actually
+optimized by Polly. Normally the LLVM-IR is automatically generated from the C
+code by first lowering C to LLVM-IR (clang) and by subsequently applying a set
+of preparing transformations on the LLVM-IR. To get the LLVM-IR after the
+preparing transformations have been applied run Polly with '-O0'.
+
+.. code-block:: console
+
+  clang -O0 -mllvm -polly -S -emit-llvm file.c
+
+Further options
+===============
+Polly supports further options that are mainly useful for the development or the
+analysis of Polly. The relevant options can be added to clang by appending
+-mllvm -option-name to the CFLAGS or the clang command line.
+
+Limit Polly to a single function
+--------------------------------
+
+To limit the execution of Polly to a single function, use the option
+-polly-only-func=functionname.
+
+Disable LLVM-IR generation
+--------------------------
+
+Polly normally regenerates LLVM-IR from the Polyhedral representation. To only
+see the effects of the preparing transformation, but to disable Polly code
+generation add the option polly-no-codegen.
+
+Graphical view of the SCoPs
+---------------------------
+Polly can use graphviz to show the SCoPs it detects in a program. The relevant
+options are -polly-show, -polly-show-only, -polly-dot and -polly-dot-only. The
+'show' options automatically run dotty or another graphviz viewer to show the
+scops graphically. The 'dot' options store for each function a dot file that
+highlights the detected SCoPs. If 'only' is appended at the end of the option,
+the basic blocks are shown without the statements the contain.
+
+Change/Disable the Optimizer
+----------------------------
+
+Polly uses by default the isl scheduling optimizer. The isl optimizer optimizes
+for data-locality and parallelism using the Pluto algorithm.
+To disable the optimizer entirely use the option -polly-optimizer=none.
+
+Disable tiling in the optimizer
+-------------------------------
+
+By default both optimizers perform tiling, if possible. In case this is not
+wanted the option -polly-tiling=false can be used to disable it. (This option
+disables tiling for both optimizers).
+
+Import / Export
+---------------
+
+The flags -polly-import and -polly-export allow the export and reimport of the
+polyhedral representation. By exporting, modifying and reimporting the
+polyhedral representation externally calculated transformations can be
+applied. This enables external optimizers or the manual optimization of
+specific SCoPs.
+
+Viewing Polly Diagnostics with opt-viewer
+-----------------------------------------
+
+The flag -fsave-optimization-record will generate .opt.yaml files when compiling
+your program. These yaml files contain information about each emitted remark.
+Ensure that you have Python 2.7 with PyYaml and Pygments Python Packages.
+To run opt-viewer:
+
+.. code-block:: console
+
+   llvm/tools/opt-viewer/opt-viewer.py -source-dir /path/to/program/src/ \
+      /path/to/program/src/foo.opt.yaml \
+      /path/to/program/src/bar.opt.yaml \
+      -o ./output
+
+Include all yaml files (use \*.opt.yaml when specifying which yaml files to view)
+to view all diagnostics from your program in opt-viewer. Compile with `PGO
+<https://clang.llvm.org/docs/UsersManual.html#profiling-with-instrumentation>`_ to view
+Hotness information in opt-viewer. Resulting html files can be viewed in an internet browser.
diff --git a/final/docs/conf.py b/final/docs/conf.py
new file mode 100644
index 0000000..c403233
--- /dev/null
+++ b/final/docs/conf.py
@@ -0,0 +1,240 @@
+# -*- coding: utf-8 -*-
+#
+# Polly documentation build configuration file, created by
+# sphinx-quickstart on Sun Dec  9 20:01:55 2012.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+from datetime import date
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Polly'
+copyright = u'2010-%d, The Polly Team' % date.today().year
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '6.0-devel'
+# The full version, including alpha/beta/rc tags.
+release = '6.0-devel'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build', 'analyzer']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'friendly'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+try:
+    import sphinx_rtd_theme
+    html_theme = "sphinx_rtd_theme"
+    html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
+except ImportError:
+    html_theme = 'haiku'
+
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Pollydoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'Polly.tex', u'Polly Documentation',
+   u'The Polly Team', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('index', 'Polly', u'Polly Documentation',
+   u'The Polly Team', 'Polly', 'One line description of project.',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
diff --git a/final/docs/doxygen.cfg.in b/final/docs/doxygen.cfg.in
new file mode 100644
index 0000000..36786aa
--- /dev/null
+++ b/final/docs/doxygen.cfg.in
@@ -0,0 +1,2306 @@
+# Doxyfile 1.8.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = Polly
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = @PACKAGE_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = @abs_builddir@/doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        = ../..
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 2
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 2
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = NO
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = NO
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = @abs_srcdir@/../include \
+                         @abs_srcdir@/../lib \
+                         @abs_srcdir@/doxygen.intro
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = *.py
+EXCLUDE_PATTERNS      += *.sh
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           = @abs_srcdir@/../examples
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = YES
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             = @abs_srcdir@/img
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 4
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          = polly::
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = @polly_doxygen_generate_qhp@
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               = @polly_doxygen_qch_filename@
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = @polly_doxygen_qhp_namespace@
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   = @polly_doxygen_qhp_cust_filter_name@
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  = @polly_doxygen_qhp_cust_filter_attrs@
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           = @polly_doxygen_qhelpgenerator_path@
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = @enable_searchengine@
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavours of web server based searching depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools. See
+# the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = @enable_server_based_search@
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = @enable_external_search@
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       = @searchengine_url@
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     = polly
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  = @extra_search_mappings@
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           = ../include
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all refrences to function-like macros that are alone on a line, have an
+# all uppercase name, and do not end with a semicolon. Such function macros are
+# typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have an unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = YES
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = YES
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = @DOT_IMAGE_FORMAT@
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               = @DOT@
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/final/docs/experiments/matmul/init_array___%for.cond1.preheader---%for.end19.jscop b/final/docs/experiments/matmul/init_array___%for.cond1.preheader---%for.end19.jscop
new file mode 100644
index 0000000..7f1db3e
--- /dev/null
+++ b/final/docs/experiments/matmul/init_array___%for.cond1.preheader---%for.end19.jscop
@@ -0,0 +1,33 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.cond1.preheader---%for.end19",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_A[i0, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_B[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body3[i0, i1] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "{ Stmt_for_body3[i0, i1] -> [i0, i1] }"
+      }
+   ]
+}
diff --git a/final/docs/experiments/matmul/main___%for.cond1.preheader---%for.end30.jscop b/final/docs/experiments/matmul/main___%for.cond1.preheader---%for.end30.jscop
new file mode 100644
index 0000000..ac1a908
--- /dev/null
+++ b/final/docs/experiments/matmul/main___%for.cond1.preheader---%for.end30.jscop
@@ -0,0 +1,57 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.cond1.preheader---%for.end30",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body3[i0, i1] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "{ Stmt_for_body3[i0, i1] -> [i0, i1, 0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_A[i0, i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_B[i2, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body8[i0, i1, i2] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 and 0 <= i2 <= 1535 }",
+         "name" : "Stmt_for_body8",
+         "schedule" : "{ Stmt_for_body8[i0, i1, i2] -> [i0, i1, 1, i2] }"
+      }
+   ]
+}
diff --git a/final/docs/experiments/matmul/main___%for.cond1.preheader---%for.end30.jscop.interchanged b/final/docs/experiments/matmul/main___%for.cond1.preheader---%for.end30.jscop.interchanged
new file mode 100644
index 0000000..7e3d212
--- /dev/null
+++ b/final/docs/experiments/matmul/main___%for.cond1.preheader---%for.end30.jscop.interchanged
@@ -0,0 +1,57 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.cond1.preheader---%for.end30",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body3[i0, i1] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "{ Stmt_for_body3[i0, i1] -> [0, i0, i1, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_A[i0, i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_B[i2, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body8[i0, i1, i2] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 and 0 <= i2 <= 1535 }",
+         "name" : "Stmt_for_body8",
+         "schedule" : "{ Stmt_for_body8[i0, i1, i2] -> [1, i0, i2, i1] }"
+      }
+   ]
+}
diff --git a/final/docs/experiments/matmul/main___%for.cond1.preheader---%for.end30.jscop.interchanged+tiled b/final/docs/experiments/matmul/main___%for.cond1.preheader---%for.end30.jscop.interchanged+tiled
new file mode 100644
index 0000000..b7c33b9
--- /dev/null
+++ b/final/docs/experiments/matmul/main___%for.cond1.preheader---%for.end30.jscop.interchanged+tiled
@@ -0,0 +1,57 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.cond1.preheader---%for.end30",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body3[i0, i1] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "{ Stmt_for_body3[i0, i1] -> [0, i0, i1, 0, 0, 0, 0 ] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_A[i0, i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_B[i2, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body8[i0, i1, i2] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 and 0 <= i2 <= 1535 }",
+         "name" : "Stmt_for_body8",
+         "schedule" : "{ Stmt_for_body8[i0, i1, i2] -> [1, o0, o1, o2, i0, i2, i1]: o0 <= i0 < o0 + 64 and o1 <= i1 < o1 + 64 and o2 <= i2 < o2 + 64 and o0 % 64 = 0 and o1 % 64 = 0 and o2 % 64 = 0 }"
+      }
+   ]
+}
diff --git a/final/docs/experiments/matmul/main___%for.cond1.preheader---%for.end30.jscop.interchanged+tiled+vector b/final/docs/experiments/matmul/main___%for.cond1.preheader---%for.end30.jscop.interchanged+tiled+vector
new file mode 100644
index 0000000..0f588aa
--- /dev/null
+++ b/final/docs/experiments/matmul/main___%for.cond1.preheader---%for.end30.jscop.interchanged+tiled+vector
@@ -0,0 +1,57 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "1536" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.cond1.preheader---%for.end30",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body3[i0, i1] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "{ Stmt_for_body3[i0, i1] -> [0, i0, i1, 0, 0, 0, 0, 0 ] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_A[i0, i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_B[i2, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body8[i0, i1, i2] : 0 <= i0 <= 1535 and 0 <= i1 <= 1535 and 0 <= i2 <= 1535 }",
+         "name" : "Stmt_for_body8",
+         "schedule" : "{ Stmt_for_body8[i0, i1, i2] -> [1, o0, o1, o2, i0, i2, oo1, i1]: o0 <= i0 < o0 + 64 and o1 <= oo1 < o1 + 64 and o2 <= i2 < o2 + 64 and oo1 <= i1 < oo1 + 4 and o0 % 64 = 0 and o1 % 64 = 0 and o2 % 64 = 0 and oo1 % 4 = 0 }"
+      }
+   ]
+}
diff --git a/final/docs/images/GEMM_double.png b/final/docs/images/GEMM_double.png
new file mode 100644
index 0000000..dfdf17e
--- /dev/null
+++ b/final/docs/images/GEMM_double.png
Binary files differ
diff --git a/final/docs/images/LLVM-Passes-all.pdf b/final/docs/images/LLVM-Passes-all.pdf
new file mode 100644
index 0000000..e2c6cf6
--- /dev/null
+++ b/final/docs/images/LLVM-Passes-all.pdf
Binary files differ
diff --git a/final/docs/images/LLVM-Passes-all.png b/final/docs/images/LLVM-Passes-all.png
new file mode 100644
index 0000000..0df6f76
--- /dev/null
+++ b/final/docs/images/LLVM-Passes-all.png
Binary files differ
diff --git a/final/docs/images/LLVM-Passes-early.pdf b/final/docs/images/LLVM-Passes-early.pdf
new file mode 100644
index 0000000..4d959a1
--- /dev/null
+++ b/final/docs/images/LLVM-Passes-early.pdf
Binary files differ
diff --git a/final/docs/images/LLVM-Passes-early.png b/final/docs/images/LLVM-Passes-early.png
new file mode 100644
index 0000000..5499152
--- /dev/null
+++ b/final/docs/images/LLVM-Passes-early.png
Binary files differ
diff --git a/final/docs/images/LLVM-Passes-late.pdf b/final/docs/images/LLVM-Passes-late.pdf
new file mode 100644
index 0000000..f326659
--- /dev/null
+++ b/final/docs/images/LLVM-Passes-late.pdf
Binary files differ
diff --git a/final/docs/images/LLVM-Passes-late.png b/final/docs/images/LLVM-Passes-late.png
new file mode 100644
index 0000000..f70895f
--- /dev/null
+++ b/final/docs/images/LLVM-Passes-late.png
Binary files differ
diff --git a/final/docs/images/LLVM-Passes-only.pdf b/final/docs/images/LLVM-Passes-only.pdf
new file mode 100644
index 0000000..146909e
--- /dev/null
+++ b/final/docs/images/LLVM-Passes-only.pdf
Binary files differ
diff --git a/final/docs/images/LLVM-Passes-only.png b/final/docs/images/LLVM-Passes-only.png
new file mode 100644
index 0000000..24b56bf
--- /dev/null
+++ b/final/docs/images/LLVM-Passes-only.png
Binary files differ
diff --git a/final/docs/images/LLVM-Passes.xml b/final/docs/images/LLVM-Passes.xml
new file mode 100644
index 0000000..9c18531
--- /dev/null
+++ b/final/docs/images/LLVM-Passes.xml
@@ -0,0 +1 @@
+<mxfile type="device" userAgent="Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0" version="5.2.8.3" editor="www.draw.io"><diagram>7Vtdd+I2EP01PKYHLCDZxwSSNOdkT3NCu20fBQhQ11iuLEKyv35H8sgfIMCJjUib8AB4NOhjpDtzNRItMlg+30oaL76KKQtbQXv63CLDVhB0SL8DH1rykkou2l9SwVzyKSrlghH/wVDYRumKT1lSUlRChIrHZeFERBGbqJKMSinWZbWZCMutxnRuW8wFowkNt6V/8qla4CiCfi7/lfH5wrbc6eP4xnTyfS7FKsL2WgGZmVdavKS2LjNQcg1GlEJANfrb8nnAQm1Ia6PUGjc7SrNOShZhR/b/gHTTXzzRcIUDTQWJerEjN31n+gedFrlaL7hio5hOdOka5hpkC7UMsXhKk0Wmqx8eqFJMRkYStLsgjUPKozMhaaQtfjWXdMqhuwMRCglqkYi0eMbD0IrAZDc3171rAnLsL5OK2bW1PWgjwhHfMrFkSr6ACv4AbdLGlUh6+LzO57VnZYvCnAZtFFJcS/Os6tzE8AWt7La4bbxgYDaFlYaPQqqFmIuIhte59Gqykk+ZVfP5aJdtz565+qvw/W+t8ktPP0XQS12kf2Ee8rJ/mFIviDe6UgJEeSfuhYAJNjWm3dZ93W92GJpYSbM8tHERqlTOGWqZJbc9OZKFVPGncu21LH3h2dLn787U3myNbZfcSD+EXlzNBHS5OAn9f1fau5mCs8QY4xIUOv34OS+Eb3P9eX//7autaSyt9O7RyqBfaQNpwbbq1hJIFjTWXyOh9HwfcGdp/4baiOi3wF2llmnUBwVk2wddOFxQpwkX1MHI9EFcEIa4Ii5M0PYAC1d0fSUsui5YZOvcCgYUwiYHtsJ/wAhEVMBHplMZM2fQ7le2DB7ZHL7Bk0vhLkogZC/HHKL1TqXBze2IL+OQz7R5HUr1yIZFJGMw4NqQ7PR7ZUx2tzHZsTgtgtICtRYmfQer02ISLV3EZMcwTx+8wPbHl6lhtAVbm7JT2zrfa7zN1uanl9LEwkwhFjxSSaHmBy3IAdb/shH0+hubkwP6HQRkPs9pD/JZz4ZSzTv7puJ7CaJZJd5XAjF+xwPqsG1HKNwKUPViowk4OiYZcwXt32K9JveGPleULAcyrOtRKAq0cWe8Q7U/omTN1WRxUHHIQlapPimMMbXsOEH0BWZLrBuIor1NZuuKoq7ddSNR9PxDRVHMPRXxbGDmAc7Y9PGZrU7BUVjqbSSSk2b47f+PvhJLTU8BPEfasGngGXRVAp6HSGqz0qfYVNq2j4+9uygEfOjVXh1s9QEx1sOqj4euXf+WPVq7FfFgg1URD8hK680R+scPEojSvdvGHsNX7tE2fnxq+Xs6PIhFMZvwrWRLMS68mm82A93KtQSuWgqU8xucoQmZDfAQj+WJkny82q88un+oVvNh8zkD/HFMWmkO3xEBPz8lD0hB/3kQUH26vtiM/ilOAoKPdRLgOgrwRtv8HQY8QLJAD6FwKACE6vNA4LXQtETQ3hM493geQPBE9URJ6g1omsTlkbHpSE56uylQITmJoDo2gXOB822AHU1EPITsItyF2s3IQOcumol9GnCdZxUyyKLyJYxBZ2J2OYAkvEz2NDaAO2G3DPaTe5lfffhLUG9g+9gunwYS6w0Oob+RwEx8n1F5ALgjW+ktXekvX/mfzplk5HNfyHPlTBrJIR4/eY8EFFe9LvEf1LyteTuX7+N40weFcHmYuvT+TSfdGW4QR12ci10n3Zv6PYwhu/SzHPAb9Tf6U/sknRzjdNeZBziLNQ+D94QbFkGGjMoSMXt1sgbcpZYXN/tKiu9sz4VkFMHOaq67MIFVCS6fXGnnqzdcl1iw5NOpgZXLiQvQnumcDxkuQA+2LJWuTzdx0wnA6Fo+RTefpY2aTo2T46fGrSuynqnklgpuyhYe+V6u69qFtyCAQfVDXfDvb+TUXDf8nUm1Rm74d097v8x/3E3vEJ3oNp9t/HPv/rl3z/C/Ed8qZ+6a2btjUv0UZGjMZkKysyc8YyvtQz+J0eHLazYoWJ5sb6AWFg6xXLomMYLH/H9+KefO/zlJrn8C</diagram></mxfile>
\ No newline at end of file
diff --git a/final/docs/images/architecture.png b/final/docs/images/architecture.png
new file mode 100644
index 0000000..c540e72
--- /dev/null
+++ b/final/docs/images/architecture.png
Binary files differ
diff --git a/final/docs/index.rst b/final/docs/index.rst
new file mode 100644
index 0000000..333c8eb
--- /dev/null
+++ b/final/docs/index.rst
@@ -0,0 +1,37 @@
+.. Polly documentation master file
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+.. title:: Welcome to Polly's documentation!
+
+.. toctree::
+   :maxdepth: 1
+
+Upcoming Release
+================
+
+.. toctree::
+   :maxdepth: 2
+
+   ReleaseNotes
+
+Using Polly
+===========
+
+.. toctree::
+   :maxdepth: 2
+
+   Architecture
+   UsingPollyWithClang
+   HowToManuallyUseTheIndividualPiecesOfPolly
+   TipsAndTricks
+   Performance
+
+* `A list of Polly passes <http://polly.llvm.org/documentation/passes.html>`_
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
+
diff --git a/final/include/polly/Canonicalization.h b/final/include/polly/Canonicalization.h
new file mode 100644
index 0000000..1d0fc96
--- /dev/null
+++ b/final/include/polly/Canonicalization.h
@@ -0,0 +1,27 @@
+//===--- Canonicalization.h - Set of canonicalization passes ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_CANONICALIZATION_H
+#define POLLY_CANONICALIZATION_H
+
+#include "llvm/IR/LegacyPassManager.h"
+
+namespace polly {
+
+/// Schedule a set of canonicalization passes to prepare for Polly.
+///
+/// The set of optimization passes was partially taken/copied from the
+/// set of default optimization passes in LLVM. It is used to bring the code
+/// into a canonical form that simplifies the analysis and optimization passes
+/// of Polly. The set of optimization passes scheduled here is probably not yet
+/// optimal. TODO: Optimize the set of canonicalization passes.
+void registerCanonicalicationPasses(llvm::legacy::PassManagerBase &PM);
+} // namespace polly
+
+#endif
diff --git a/final/include/polly/CodeGen/BlockGenerators.h b/final/include/polly/CodeGen/BlockGenerators.h
new file mode 100644
index 0000000..35f23c4
--- /dev/null
+++ b/final/include/polly/CodeGen/BlockGenerators.h
@@ -0,0 +1,967 @@
+//===-BlockGenerators.h - Helper to generate code for statements-*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the BlockGenerator and VectorBlockGenerator classes, which
+// generate sequential code and vectorized code for a polyhedral statement,
+// respectively.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_BLOCK_GENERATORS_H
+#define POLLY_BLOCK_GENERATORS_H
+
+#include "polly/CodeGen/IRBuilder.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "isl/map.h"
+
+struct isl_ast_build;
+struct isl_id_to_ast_expr;
+
+namespace llvm {
+class Pass;
+class Region;
+class ScalarEvolution;
+} // namespace llvm
+
+namespace polly {
+using namespace llvm;
+class ScopStmt;
+class MemoryAccess;
+class ScopArrayInfo;
+class IslExprBuilder;
+
+/// Generate a new basic block for a polyhedral statement.
+class BlockGenerator {
+public:
+  typedef llvm::SmallVector<ValueMapT, 8> VectorValueMapT;
+
+  /// Map types to resolve scalar dependences.
+  ///
+  ///@{
+  using AllocaMapTy = DenseMap<const ScopArrayInfo *, AssertingVH<AllocaInst>>;
+
+  /// Simple vector of instructions to store escape users.
+  using EscapeUserVectorTy = SmallVector<Instruction *, 4>;
+
+  /// Map type to resolve escaping users for scalar instructions.
+  ///
+  /// @see The EscapeMap member.
+  using EscapeUsersAllocaMapTy =
+      MapVector<Instruction *,
+                std::pair<AssertingVH<Value>, EscapeUserVectorTy>>;
+
+  ///@}
+
+  /// Create a generator for basic blocks.
+  ///
+  /// @param Builder     The LLVM-IR Builder used to generate the statement. The
+  ///                    code is generated at the location, the Builder points
+  ///                    to.
+  /// @param LI          The loop info for the current function
+  /// @param SE          The scalar evolution info for the current function
+  /// @param DT          The dominator tree of this function.
+  /// @param ScalarMap   Map from scalars to their demoted location.
+  /// @param EscapeMap   Map from scalars to their escape users and locations.
+  /// @param GlobalMap   A mapping from llvm::Values used in the original scop
+  ///                    region to a new set of llvm::Values. Each reference to
+  ///                    an original value appearing in this mapping is replaced
+  ///                    with the new value it is mapped to.
+  /// @param ExprBuilder An expression builder to generate new access functions.
+  /// @param StartBlock  The first basic block after the RTC.
+  BlockGenerator(PollyIRBuilder &Builder, LoopInfo &LI, ScalarEvolution &SE,
+                 DominatorTree &DT, AllocaMapTy &ScalarMap,
+                 EscapeUsersAllocaMapTy &EscapeMap, ValueMapT &GlobalMap,
+                 IslExprBuilder *ExprBuilder, BasicBlock *StartBlock);
+
+  /// Copy the basic block.
+  ///
+  /// This copies the entire basic block and updates references to old values
+  /// with references to new values, as defined by GlobalMap.
+  ///
+  /// @param Stmt        The block statement to code generate.
+  /// @param LTS         A map from old loops to new induction variables as
+  ///                    SCEVs.
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  void copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
+                isl_id_to_ast_expr *NewAccesses);
+
+  /// Remove a ScopArrayInfo's allocation from the ScalarMap.
+  ///
+  /// This function allows to remove values from the ScalarMap. This is useful
+  /// if the corresponding alloca instruction will be deleted (or moved into
+  /// another module), as without removing these values the underlying
+  /// AssertingVH will trigger due to us still keeping reference to this
+  /// scalar.
+  ///
+  /// @param Array The array for which the alloca was generated.
+  void freeScalarAlloc(ScopArrayInfo *Array) { ScalarMap.erase(Array); }
+
+  /// Return the alloca for @p Access.
+  ///
+  /// If no alloca was mapped for @p Access a new one is created.
+  ///
+  /// @param Access    The memory access for which to generate the alloca.
+  ///
+  /// @returns The alloca for @p Access or a replacement value taken from
+  ///          GlobalMap.
+  Value *getOrCreateAlloca(const MemoryAccess &Access);
+
+  /// Return the alloca for @p Array.
+  ///
+  /// If no alloca was mapped for @p Array a new one is created.
+  ///
+  /// @param Array The array for which to generate the alloca.
+  ///
+  /// @returns The alloca for @p Array or a replacement value taken from
+  ///          GlobalMap.
+  Value *getOrCreateAlloca(const ScopArrayInfo *Array);
+
+  /// Finalize the code generation for the SCoP @p S.
+  ///
+  /// This will initialize and finalize the scalar variables we demoted during
+  /// the code generation.
+  ///
+  /// @see createScalarInitialization(Scop &)
+  /// @see createScalarFinalization(Region &)
+  void finalizeSCoP(Scop &S);
+
+  /// An empty destructor
+  virtual ~BlockGenerator() {}
+
+  BlockGenerator(const BlockGenerator &) = default;
+
+protected:
+  PollyIRBuilder &Builder;
+  LoopInfo &LI;
+  ScalarEvolution &SE;
+  IslExprBuilder *ExprBuilder;
+
+  /// The dominator tree of this function.
+  DominatorTree &DT;
+
+  /// The entry block of the current function.
+  BasicBlock *EntryBB;
+
+  /// Map to resolve scalar dependences for PHI operands and scalars.
+  ///
+  /// When translating code that contains scalar dependences as they result from
+  /// inter-block scalar dependences (including the use of data carrying PHI
+  /// nodes), we do not directly regenerate in-register SSA code, but instead
+  /// allocate some stack memory through which these scalar values are passed.
+  /// Only a later pass of -mem2reg will then (re)introduce in-register
+  /// computations.
+  ///
+  /// To keep track of the memory location(s) used to store the data computed by
+  /// a given SSA instruction, we use the map 'ScalarMap'. ScalarMap maps a
+  /// given ScopArrayInfo to the junk of stack allocated memory, that is
+  /// used for code generation.
+  ///
+  /// Up to two different ScopArrayInfo objects are associated with each
+  /// llvm::Value:
+  ///
+  /// MemoryType::Value objects are used for normal scalar dependences that go
+  /// from a scalar definition to its use. Such dependences are lowered by
+  /// directly writing the value an instruction computes into the corresponding
+  /// chunk of memory and reading it back from this chunk of memory right before
+  /// every use of this original scalar value. The memory allocations for
+  /// MemoryType::Value objects end with '.s2a'.
+  ///
+  /// MemoryType::PHI (and MemoryType::ExitPHI) objects are used to model PHI
+  /// nodes. For each PHI nodes we introduce, besides the Array of type
+  /// MemoryType::Value, a second chunk of memory into which we write at the end
+  /// of each basic block preceding the PHI instruction the value passed
+  /// through this basic block. At the place where the PHI node is executed, we
+  /// replace the PHI node with a load from the corresponding MemoryType::PHI
+  /// memory location. The memory allocations for MemoryType::PHI end with
+  /// '.phiops'.
+  ///
+  /// Example:
+  ///
+  ///                              Input C Code
+  ///                              ============
+  ///
+  ///                 S1:      x1 = ...
+  ///                          for (i=0...N) {
+  ///                 S2:           x2 = phi(x1, add)
+  ///                 S3:           add = x2 + 42;
+  ///                          }
+  ///                 S4:      print(x1)
+  ///                          print(x2)
+  ///                          print(add)
+  ///
+  ///
+  ///        Unmodified IR                         IR After expansion
+  ///        =============                         ==================
+  ///
+  /// S1:   x1 = ...                     S1:    x1 = ...
+  ///                                           x1.s2a = s1
+  ///                                           x2.phiops = s1
+  ///        |                                    |
+  ///        |   <--<--<--<--<                    |   <--<--<--<--<
+  ///        | /              \                   | /              \     .
+  ///        V V               \                  V V               \    .
+  /// S2:  x2 = phi (x1, add)   |        S2:    x2 = x2.phiops       |
+  ///                           |               x2.s2a = x2          |
+  ///                           |                                    |
+  /// S3:  add = x2 + 42        |        S3:    add = x2 + 42        |
+  ///                           |               add.s2a = add        |
+  ///                           |               x2.phiops = add      |
+  ///        | \               /                  | \               /
+  ///        |  \             /                   |  \             /
+  ///        |   >-->-->-->-->                    |   >-->-->-->-->
+  ///        V                                    V
+  ///
+  ///                                    S4:    x1 = x1.s2a
+  /// S4:  ... = x1                             ... = x1
+  ///                                           x2 = x2.s2a
+  ///      ... = x2                             ... = x2
+  ///                                           add = add.s2a
+  ///      ... = add                            ... = add
+  ///
+  ///      ScalarMap = { x1:Value -> x1.s2a, x2:Value -> x2.s2a,
+  ///                    add:Value -> add.s2a, x2:PHI -> x2.phiops }
+  ///
+  ///  ??? Why does a PHI-node require two memory chunks ???
+  ///
+  ///  One may wonder why a PHI node requires two memory chunks and not just
+  ///  all data is stored in a single location. The following example tries
+  ///  to store all data in .s2a and drops the .phiops location:
+  ///
+  ///      S1:    x1 = ...
+  ///             x1.s2a = s1
+  ///             x2.s2a = s1             // use .s2a instead of .phiops
+  ///               |
+  ///               |   <--<--<--<--<
+  ///               | /              \    .
+  ///               V V               \   .
+  ///      S2:    x2 = x2.s2a          |  // value is same as above, but read
+  ///                                  |  // from .s2a
+  ///                                  |
+  ///             x2.s2a = x2          |  // store into .s2a as normal
+  ///                                  |
+  ///      S3:    add = x2 + 42        |
+  ///             add.s2a = add        |
+  ///             x2.s2a = add         |  // use s2a instead of .phiops
+  ///               | \               /   // !!! This is wrong, as x2.s2a now
+  ///               |   >-->-->-->-->     // contains add instead of x2.
+  ///               V
+  ///
+  ///      S4:    x1 = x1.s2a
+  ///             ... = x1
+  ///             x2 = x2.s2a             // !!! We now read 'add' instead of
+  ///             ... = x2                // 'x2'
+  ///             add = add.s2a
+  ///             ... = add
+  ///
+  ///  As visible in the example, the SSA value of the PHI node may still be
+  ///  needed _after_ the basic block, which could conceptually branch to the
+  ///  PHI node, has been run and has overwritten the PHI's old value. Hence, a
+  ///  single memory location is not enough to code-generate a PHI node.
+  ///
+  /// Memory locations used for the special PHI node modeling.
+  AllocaMapTy &ScalarMap;
+
+  /// Map from instructions to their escape users as well as the alloca.
+  EscapeUsersAllocaMapTy &EscapeMap;
+
+  /// A map from llvm::Values referenced in the old code to a new set of
+  ///        llvm::Values, which is used to replace these old values during
+  ///        code generation.
+  ValueMapT &GlobalMap;
+
+  /// The first basic block after the RTC.
+  BasicBlock *StartBlock;
+
+  /// Split @p BB to create a new one we can use to clone @p BB in.
+  BasicBlock *splitBB(BasicBlock *BB);
+
+  /// Copy the given basic block.
+  ///
+  /// @param Stmt      The statement to code generate.
+  /// @param BB        The basic block to code generate.
+  /// @param BBMap     A mapping from old values to their new values in this
+  /// block.
+  /// @param LTS         A map from old loops to new induction variables as
+  ///                    SCEVs.
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  ///
+  /// @returns The copy of the basic block.
+  BasicBlock *copyBB(ScopStmt &Stmt, BasicBlock *BB, ValueMapT &BBMap,
+                     LoopToScevMapT &LTS, isl_id_to_ast_expr *NewAccesses);
+
+  /// Copy the given basic block.
+  ///
+  /// @param Stmt      The statement to code generate.
+  /// @param BB        The basic block to code generate.
+  /// @param BBCopy    The new basic block to generate code in.
+  /// @param BBMap     A mapping from old values to their new values in this
+  /// block.
+  /// @param LTS         A map from old loops to new induction variables as
+  ///                    SCEVs.
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  void copyBB(ScopStmt &Stmt, BasicBlock *BB, BasicBlock *BBCopy,
+              ValueMapT &BBMap, LoopToScevMapT &LTS,
+              isl_id_to_ast_expr *NewAccesses);
+
+  /// Generate reload of scalars demoted to memory and needed by @p Stmt.
+  ///
+  /// @param Stmt  The statement we generate code for.
+  /// @param LTS   A mapping from loops virtual canonical induction
+  ///              variable to their new values.
+  /// @param BBMap A mapping from old values to their new values in this block.
+  /// @param NewAccesses A map from memory access ids to new ast expressions.
+  void generateScalarLoads(ScopStmt &Stmt, LoopToScevMapT &LTS,
+                           ValueMapT &BBMap,
+                           __isl_keep isl_id_to_ast_expr *NewAccesses);
+
+  /// Generate instructions that compute whether one instance of @p Set is
+  /// executed.
+  ///
+  /// @param Stmt      The statement we generate code for.
+  /// @param Subdomain A set in the space of @p Stmt's domain. Elements not in
+  ///                  @p Stmt's domain are ignored.
+  ///
+  /// @return An expression of type i1, generated into the current builder
+  ///         position, that evaluates to 1 if the executed instance is part of
+  ///         @p Set.
+  Value *buildContainsCondition(ScopStmt &Stmt, const isl::set &Subdomain);
+
+  /// Generate code that executes in a subset of @p Stmt's domain.
+  ///
+  /// @param Stmt        The statement we generate code for.
+  /// @param Subdomain   The condition for some code to be executed.
+  /// @param Subject     A name for the code that is executed
+  ///                    conditionally. Used to name new basic blocks and
+  ///                    instructions.
+  /// @param GenThenFunc Callback which generates the code to be executed
+  ///                    when the current executed instance is in @p Set. The
+  ///                    IRBuilder's position is moved to within the block that
+  ///                    executes conditionally for this callback.
+  void generateConditionalExecution(ScopStmt &Stmt, const isl::set &Subdomain,
+                                    StringRef Subject,
+                                    const std::function<void()> &GenThenFunc);
+
+  /// Generate the scalar stores for the given statement.
+  ///
+  /// After the statement @p Stmt was copied all inner-SCoP scalar dependences
+  /// starting in @p Stmt (hence all scalar write accesses in @p Stmt) need to
+  /// be demoted to memory.
+  ///
+  /// @param Stmt  The statement we generate code for.
+  /// @param LTS   A mapping from loops virtual canonical induction
+  ///              variable to their new values
+  ///              (for values recalculated in the new ScoP, but not
+  ///               within this basic block)
+  /// @param BBMap A mapping from old values to their new values in this block.
+  /// @param NewAccesses A map from memory access ids to new ast expressions.
+  virtual void generateScalarStores(ScopStmt &Stmt, LoopToScevMapT &LTS,
+                                    ValueMapT &BBMap,
+                                    __isl_keep isl_id_to_ast_expr *NewAccesses);
+
+  /// Handle users of @p Array outside the SCoP.
+  ///
+  /// @param S         The current SCoP.
+  /// @param Inst      The ScopArrayInfo to handle.
+  void handleOutsideUsers(const Scop &S, ScopArrayInfo *Array);
+
+  /// Find scalar statements that have outside users.
+  ///
+  /// We register these scalar values to later update subsequent scalar uses of
+  /// these values to either use the newly computed value from within the scop
+  /// (if the scop was executed) or the unchanged original code (if the run-time
+  /// check failed).
+  ///
+  /// @param S The scop for which to find the outside users.
+  void findOutsideUsers(Scop &S);
+
+  /// Initialize the memory of demoted scalars.
+  ///
+  /// @param S The scop for which to generate the scalar initializers.
+  void createScalarInitialization(Scop &S);
+
+  /// Create exit PHI node merges for PHI nodes with more than two edges
+  ///        from inside the scop.
+  ///
+  /// For scops which have a PHI node in the exit block that has more than two
+  /// incoming edges from inside the scop region, we require some special
+  /// handling to understand which of the possible values will be passed to the
+  /// PHI node from inside the optimized version of the scop. To do so ScopInfo
+  /// models the possible incoming values as write accesses of the ScopStmts.
+  ///
+  /// This function creates corresponding code to reload the computed outgoing
+  /// value from the stack slot it has been stored into and to pass it on to the
+  /// PHI node in the original exit block.
+  ///
+  /// @param S The scop for which to generate the exiting PHI nodes.
+  void createExitPHINodeMerges(Scop &S);
+
+  /// Promote the values of demoted scalars after the SCoP.
+  ///
+  /// If a scalar value was used outside the SCoP we need to promote the value
+  /// stored in the memory cell allocated for that scalar and combine it with
+  /// the original value in the non-optimized SCoP.
+  void createScalarFinalization(Scop &S);
+
+  /// Try to synthesize a new value
+  ///
+  /// Given an old value, we try to synthesize it in a new context from its
+  /// original SCEV expression. We start from the original SCEV expression,
+  /// then replace outdated parameter and loop references, and finally
+  /// expand it to code that computes this updated expression.
+  ///
+  /// @param Stmt      The statement to code generate
+  /// @param Old       The old Value
+  /// @param BBMap     A mapping from old values to their new values
+  ///                  (for values recalculated within this basic block)
+  /// @param LTS       A mapping from loops virtual canonical induction
+  ///                  variable to their new values
+  ///                  (for values recalculated in the new ScoP, but not
+  ///                   within this basic block)
+  /// @param L         The loop that surrounded the instruction that referenced
+  ///                  this value in the original code. This loop is used to
+  ///                  evaluate the scalar evolution at the right scope.
+  ///
+  /// @returns  o A newly synthesized value.
+  ///           o NULL, if synthesizing the value failed.
+  Value *trySynthesizeNewValue(ScopStmt &Stmt, Value *Old, ValueMapT &BBMap,
+                               LoopToScevMapT &LTS, Loop *L) const;
+
+  /// Get the new version of a value.
+  ///
+  /// Given an old value, we first check if a new version of this value is
+  /// available in the BBMap or GlobalMap. In case it is not and the value can
+  /// be recomputed using SCEV, we do so. If we can not recompute a value
+  /// using SCEV, but we understand that the value is constant within the scop,
+  /// we return the old value.  If the value can still not be derived, this
+  /// function will assert.
+  ///
+  /// @param Stmt      The statement to code generate.
+  /// @param Old       The old Value.
+  /// @param BBMap     A mapping from old values to their new values
+  ///                  (for values recalculated within this basic block).
+  /// @param LTS       A mapping from loops virtual canonical induction
+  ///                  variable to their new values
+  ///                  (for values recalculated in the new ScoP, but not
+  ///                   within this basic block).
+  /// @param L         The loop that surrounded the instruction that referenced
+  ///                  this value in the original code. This loop is used to
+  ///                  evaluate the scalar evolution at the right scope.
+  ///
+  /// @returns  o The old value, if it is still valid.
+  ///           o The new value, if available.
+  ///           o NULL, if no value is found.
+  Value *getNewValue(ScopStmt &Stmt, Value *Old, ValueMapT &BBMap,
+                     LoopToScevMapT &LTS, Loop *L) const;
+
+  void copyInstScalar(ScopStmt &Stmt, Instruction *Inst, ValueMapT &BBMap,
+                      LoopToScevMapT &LTS);
+
+  /// Get the innermost loop that surrounds the statement @p Stmt.
+  Loop *getLoopForStmt(const ScopStmt &Stmt) const;
+
+  /// Generate the operand address
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  Value *generateLocationAccessed(ScopStmt &Stmt, MemAccInst Inst,
+                                  ValueMapT &BBMap, LoopToScevMapT &LTS,
+                                  isl_id_to_ast_expr *NewAccesses);
+
+  /// Generate the operand address.
+  ///
+  /// @param Stmt         The statement to generate code for.
+  /// @param L            The innermost loop that surrounds the statement.
+  /// @param Pointer      If the access expression is not changed (ie. not found
+  ///                     in @p LTS), use this Pointer from the original code
+  ///                     instead.
+  /// @param BBMap        A mapping from old values to their new values.
+  /// @param LTS          A mapping from loops virtual canonical induction
+  ///                     variable to their new values.
+  /// @param NewAccesses  Ahead-of-time generated access expressions.
+  /// @param Id           Identifier of the MemoryAccess to generate.
+  /// @param ExpectedType The type the returned value should have.
+  ///
+  /// @return The generated address.
+  Value *generateLocationAccessed(ScopStmt &Stmt, Loop *L, Value *Pointer,
+                                  ValueMapT &BBMap, LoopToScevMapT &LTS,
+                                  isl_id_to_ast_expr *NewAccesses,
+                                  __isl_take isl_id *Id, Type *ExpectedType);
+
+  /// Generate the pointer value that is accesses by @p Access.
+  ///
+  /// For write accesses, generate the target address. For read accesses,
+  /// generate the source address.
+  /// The access can be either an array access or a scalar access. In the first
+  /// case, the returned address will point to an element into that array. In
+  /// the scalar case, an alloca is used.
+  /// If a new AccessRelation is set for the MemoryAccess, the new relation will
+  /// be used.
+  ///
+  /// @param Access      The access to generate a pointer for.
+  /// @param L           The innermost loop that surrounds the statement.
+  /// @param LTS         A mapping from loops virtual canonical induction
+  ///                    variable to their new values.
+  /// @param BBMap       A mapping from old values to their new values.
+  /// @param NewAccesses A map from memory access ids to new ast expressions.
+  ///
+  /// @return The generated address.
+  Value *getImplicitAddress(MemoryAccess &Access, Loop *L, LoopToScevMapT &LTS,
+                            ValueMapT &BBMap,
+                            __isl_keep isl_id_to_ast_expr *NewAccesses);
+
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  Value *generateArrayLoad(ScopStmt &Stmt, LoadInst *load, ValueMapT &BBMap,
+                           LoopToScevMapT &LTS,
+                           isl_id_to_ast_expr *NewAccesses);
+
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  void generateArrayStore(ScopStmt &Stmt, StoreInst *store, ValueMapT &BBMap,
+                          LoopToScevMapT &LTS, isl_id_to_ast_expr *NewAccesses);
+
+  /// Copy a single PHI instruction.
+  ///
+  /// The implementation in the BlockGenerator is trivial, however it allows
+  /// subclasses to handle PHIs different.
+  virtual void copyPHIInstruction(ScopStmt &, PHINode *, ValueMapT &,
+                                  LoopToScevMapT &) {}
+
+  /// Copy a single Instruction.
+  ///
+  /// This copies a single Instruction and updates references to old values
+  /// with references to new values, as defined by GlobalMap and BBMap.
+  ///
+  /// @param Stmt        The statement to code generate.
+  /// @param Inst        The instruction to copy.
+  /// @param BBMap       A mapping from old values to their new values
+  ///                    (for values recalculated within this basic block).
+  /// @param GlobalMap   A mapping from old values to their new values
+  ///                    (for values recalculated in the new ScoP, but not
+  ///                    within this basic block).
+  /// @param LTS         A mapping from loops virtual canonical induction
+  ///                    variable to their new values
+  ///                    (for values recalculated in the new ScoP, but not
+  ///                     within this basic block).
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  void copyInstruction(ScopStmt &Stmt, Instruction *Inst, ValueMapT &BBMap,
+                       LoopToScevMapT &LTS, isl_id_to_ast_expr *NewAccesses);
+
+  /// Helper to determine if @p Inst can be synthesized in @p Stmt.
+  ///
+  /// @returns false, iff @p Inst can be synthesized in @p Stmt.
+  bool canSyntheziseInStmt(ScopStmt &Stmt, Instruction *Inst);
+
+  /// Remove dead instructions generated for BB
+  ///
+  /// @param BB The basic block code for which code has been generated.
+  /// @param BBMap A local map from old to new instructions.
+  void removeDeadInstructions(BasicBlock *BB, ValueMapT &BBMap);
+
+  /// Invalidate the scalar evolution expressions for a scop.
+  ///
+  /// This function invalidates the scalar evolution results for all
+  /// instructions that are part of a given scop, and the loops
+  /// surrounding the users of merge blocks. This is necessary to ensure that
+  /// later scops do not obtain scalar evolution expressions that reference
+  /// values that earlier dominated the later scop, but have been moved in the
+  /// conditional part of an earlier scop and consequently do not any more
+  /// dominate the later scop.
+  ///
+  /// @param S The scop to invalidate.
+  void invalidateScalarEvolution(Scop &S);
+};
+
+/// Generate a new vector basic block for a polyhedral statement.
+///
+/// The only public function exposed is generate().
+class VectorBlockGenerator : BlockGenerator {
+public:
+  /// Generate a new vector basic block for a ScoPStmt.
+  ///
+  /// This code generation is similar to the normal, scalar code generation,
+  /// except that each instruction is code generated for several vector lanes
+  /// at a time. If possible instructions are issued as actual vector
+  /// instructions, but e.g. for address calculation instructions we currently
+  /// generate scalar instructions for each vector lane.
+  ///
+  /// @param BlockGen    A block generator object used as parent.
+  /// @param Stmt        The statement to code generate.
+  /// @param VLTS        A mapping from loops virtual canonical induction
+  ///                    variable to their new values
+  ///                    (for values recalculated in the new ScoP, but not
+  ///                     within this basic block), one for each lane.
+  /// @param Schedule    A map from the statement to a schedule where the
+  ///                    innermost dimension is the dimension of the innermost
+  ///                    loop containing the statement.
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  static void generate(BlockGenerator &BlockGen, ScopStmt &Stmt,
+                       std::vector<LoopToScevMapT> &VLTS,
+                       __isl_keep isl_map *Schedule,
+                       __isl_keep isl_id_to_ast_expr *NewAccesses) {
+    VectorBlockGenerator Generator(BlockGen, VLTS, Schedule);
+    Generator.copyStmt(Stmt, NewAccesses);
+  }
+
+private:
+  // This is a vector of loop->scev maps.  The first map is used for the first
+  // vector lane, ...
+  // Each map, contains information about Instructions in the old ScoP, which
+  // are recalculated in the new SCoP. When copying the basic block, we replace
+  // all references to the old instructions with their recalculated values.
+  //
+  // For example, when the code generator produces this AST:
+  //
+  //   for (int c1 = 0; c1 <= 1023; c1 += 1)
+  //     for (int c2 = 0; c2 <= 1023; c2 += VF)
+  //       for (int lane = 0; lane <= VF; lane += 1)
+  //         Stmt(c2 + lane + 3, c1);
+  //
+  // VLTS[lane] contains a map:
+  //   "outer loop in the old loop nest" -> SCEV("c2 + lane + 3"),
+  //   "inner loop in the old loop nest" -> SCEV("c1").
+  std::vector<LoopToScevMapT> &VLTS;
+
+  // A map from the statement to a schedule where the innermost dimension is the
+  // dimension of the innermost loop containing the statement.
+  isl_map *Schedule;
+
+  VectorBlockGenerator(BlockGenerator &BlockGen,
+                       std::vector<LoopToScevMapT> &VLTS,
+                       __isl_keep isl_map *Schedule);
+
+  int getVectorWidth();
+
+  Value *getVectorValue(ScopStmt &Stmt, Value *Old, ValueMapT &VectorMap,
+                        VectorValueMapT &ScalarMaps, Loop *L);
+
+  Type *getVectorPtrTy(const Value *V, int Width);
+
+  /// Load a vector from a set of adjacent scalars
+  ///
+  /// In case a set of scalars is known to be next to each other in memory,
+  /// create a vector load that loads those scalars
+  ///
+  /// %vector_ptr= bitcast double* %p to <4 x double>*
+  /// %vec_full = load <4 x double>* %vector_ptr
+  ///
+  /// @param Stmt           The statement to code generate.
+  /// @param NegativeStride This is used to indicate a -1 stride. In such
+  ///                       a case we load the end of a base address and
+  ///                       shuffle the accesses in reverse order into the
+  ///                       vector. By default we would do only positive
+  ///                       strides.
+  ///
+  /// @param NewAccesses    A map from memory access ids to new ast
+  ///                       expressions, which may contain new access
+  ///                       expressions for certain memory accesses.
+  Value *generateStrideOneLoad(ScopStmt &Stmt, LoadInst *Load,
+                               VectorValueMapT &ScalarMaps,
+                               __isl_keep isl_id_to_ast_expr *NewAccesses,
+                               bool NegativeStride);
+
+  /// Load a vector initialized from a single scalar in memory
+  ///
+  /// In case all elements of a vector are initialized to the same
+  /// scalar value, this value is loaded and shuffled into all elements
+  /// of the vector.
+  ///
+  /// %splat_one = load <1 x double>* %p
+  /// %splat = shufflevector <1 x double> %splat_one, <1 x
+  ///       double> %splat_one, <4 x i32> zeroinitializer
+  ///
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  Value *generateStrideZeroLoad(ScopStmt &Stmt, LoadInst *Load,
+                                ValueMapT &BBMap,
+                                __isl_keep isl_id_to_ast_expr *NewAccesses);
+
+  /// Load a vector from scalars distributed in memory
+  ///
+  /// In case some scalars a distributed randomly in memory. Create a vector
+  /// by loading each scalar and by inserting one after the other into the
+  /// vector.
+  ///
+  /// %scalar_1= load double* %p_1
+  /// %vec_1 = insertelement <2 x double> undef, double %scalar_1, i32 0
+  /// %scalar 2 = load double* %p_2
+  /// %vec_2 = insertelement <2 x double> %vec_1, double %scalar_1, i32 1
+  ///
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  Value *generateUnknownStrideLoad(ScopStmt &Stmt, LoadInst *Load,
+                                   VectorValueMapT &ScalarMaps,
+                                   __isl_keep isl_id_to_ast_expr *NewAccesses);
+
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  void generateLoad(ScopStmt &Stmt, LoadInst *Load, ValueMapT &VectorMap,
+                    VectorValueMapT &ScalarMaps,
+                    __isl_keep isl_id_to_ast_expr *NewAccesses);
+
+  void copyUnaryInst(ScopStmt &Stmt, UnaryInstruction *Inst,
+                     ValueMapT &VectorMap, VectorValueMapT &ScalarMaps);
+
+  void copyBinaryInst(ScopStmt &Stmt, BinaryOperator *Inst,
+                      ValueMapT &VectorMap, VectorValueMapT &ScalarMaps);
+
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  void copyStore(ScopStmt &Stmt, StoreInst *Store, ValueMapT &VectorMap,
+                 VectorValueMapT &ScalarMaps,
+                 __isl_keep isl_id_to_ast_expr *NewAccesses);
+
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  void copyInstScalarized(ScopStmt &Stmt, Instruction *Inst,
+                          ValueMapT &VectorMap, VectorValueMapT &ScalarMaps,
+                          __isl_keep isl_id_to_ast_expr *NewAccesses);
+
+  bool extractScalarValues(const Instruction *Inst, ValueMapT &VectorMap,
+                           VectorValueMapT &ScalarMaps);
+
+  bool hasVectorOperands(const Instruction *Inst, ValueMapT &VectorMap);
+
+  /// Generate vector loads for scalars.
+  ///
+  /// @param Stmt           The scop statement for which to generate the loads.
+  /// @param VectorBlockMap A map that will be updated to relate the original
+  ///                       values with the newly generated vector loads.
+  void generateScalarVectorLoads(ScopStmt &Stmt, ValueMapT &VectorBlockMap);
+
+  /// Verify absence of scalar stores.
+  ///
+  /// @param Stmt The scop statement to check for scalar stores.
+  void verifyNoScalarStores(ScopStmt &Stmt);
+
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  void copyInstruction(ScopStmt &Stmt, Instruction *Inst, ValueMapT &VectorMap,
+                       VectorValueMapT &ScalarMaps,
+                       __isl_keep isl_id_to_ast_expr *NewAccesses);
+
+  /// @param NewAccesses A map from memory access ids to new ast expressions,
+  ///                    which may contain new access expressions for certain
+  ///                    memory accesses.
+  void copyStmt(ScopStmt &Stmt, __isl_keep isl_id_to_ast_expr *NewAccesses);
+};
+
+/// Generator for new versions of polyhedral region statements.
+class RegionGenerator : public BlockGenerator {
+public:
+  /// Create a generator for regions.
+  ///
+  /// @param BlockGen A generator for basic blocks.
+  RegionGenerator(BlockGenerator &BlockGen) : BlockGenerator(BlockGen) {}
+
+  virtual ~RegionGenerator() {}
+
+  /// Copy the region statement @p Stmt.
+  ///
+  /// This copies the entire region represented by @p Stmt and updates
+  /// references to old values with references to new values, as defined by
+  /// GlobalMap.
+  ///
+  /// @param Stmt      The statement to code generate.
+  /// @param LTS       A map from old loops to new induction variables as SCEVs.
+  void copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
+                __isl_keep isl_id_to_ast_expr *IdToAstExp);
+
+private:
+  /// A map from old to the first new block in the region, that was created to
+  /// model the old basic block.
+  DenseMap<BasicBlock *, BasicBlock *> StartBlockMap;
+
+  /// A map from old to the last new block in the region, that was created to
+  /// model the old basic block.
+  DenseMap<BasicBlock *, BasicBlock *> EndBlockMap;
+
+  /// The "BBMaps" for the whole region (one for each block). In case a basic
+  /// block is code generated to multiple basic blocks (e.g., for partial
+  /// writes), the StartBasic is used as index for the RegionMap.
+  DenseMap<BasicBlock *, ValueMapT> RegionMaps;
+
+  /// Mapping to remember PHI nodes that still need incoming values.
+  using PHINodePairTy = std::pair<PHINode *, PHINode *>;
+  DenseMap<BasicBlock *, SmallVector<PHINodePairTy, 4>> IncompletePHINodeMap;
+
+  /// Repair the dominance tree after we created a copy block for @p BB.
+  ///
+  /// @returns The immediate dominator in the DT for @p BBCopy if in the region.
+  BasicBlock *repairDominance(BasicBlock *BB, BasicBlock *BBCopy);
+
+  /// Add the new operand from the copy of @p IncomingBB to @p PHICopy.
+  ///
+  /// PHI nodes, which may have (multiple) edges that enter from outside the
+  /// non-affine subregion and even from outside the scop, are code generated as
+  /// follows:
+  ///
+  /// # Original
+  ///
+  ///   Region: %A-> %exit
+  ///   NonAffine Stmt: %nonaffB -> %D (includes %nonaffB, %nonaffC)
+  ///
+  ///     pre:
+  ///       %val = add i64 1, 1
+  ///
+  ///     A:
+  ///      br label %nonaff
+  ///
+  ///     nonaffB:
+  ///       %phi = phi i64 [%val, %A], [%valC, %nonAffC], [%valD, %D]
+  ///       %cmp = <nonaff>
+  ///       br i1 %cmp, label %C, label %nonaffC
+  ///
+  ///     nonaffC:
+  ///       %valC = add i64 1, 1
+  ///       br i1 undef, label %D, label %nonaffB
+  ///
+  ///     D:
+  ///       %valD = ...
+  ///       %exit_cond = <loopexit>
+  ///       br i1 %exit_cond, label %nonaffB, label %exit
+  ///
+  ///     exit:
+  ///       ...
+  ///
+  ///  - %start and %C enter from outside the non-affine region.
+  ///  - %nonaffC enters from within the non-affine region.
+  ///
+  ///  # New
+  ///
+  ///    polly.A:
+  ///       store i64 %val, i64* %phi.phiops
+  ///       br label %polly.nonaffA.entry
+  ///
+  ///    polly.nonaffB.entry:
+  ///       %phi.phiops.reload = load i64, i64* %phi.phiops
+  ///       br label %nonaffB
+  ///
+  ///    polly.nonaffB:
+  ///       %polly.phi = [%phi.phiops.reload, %nonaffB.entry],
+  ///                    [%p.valC, %polly.nonaffC]
+  ///
+  ///    polly.nonaffC:
+  ///       %p.valC = add i64 1, 1
+  ///       br i1 undef, label %polly.D, label %polly.nonaffB
+  ///
+  ///    polly.D:
+  ///        %p.valD = ...
+  ///        store i64 %p.valD, i64* %phi.phiops
+  ///        %p.exit_cond = <loopexit>
+  ///        br i1 %p.exit_cond, label %polly.nonaffB, label %exit
+  ///
+  /// Values that enter the PHI from outside the non-affine region are stored
+  /// into the stack slot %phi.phiops by statements %polly.A and %polly.D and
+  /// reloaded in %polly.nonaffB.entry, a basic block generated before the
+  /// actual non-affine region.
+  ///
+  /// When generating the PHI node of the non-affine region in %polly.nonaffB,
+  /// incoming edges from outside the region are combined into a single branch
+  /// from %polly.nonaffB.entry which has as incoming value the value reloaded
+  /// from the %phi.phiops stack slot. Incoming edges from within the region
+  /// refer to the copied instructions (%p.valC) and basic blocks
+  /// (%polly.nonaffC) of the non-affine region.
+  ///
+  /// @param Stmt       The statement to code generate.
+  /// @param PHI        The original PHI we copy.
+  /// @param PHICopy    The copy of @p PHI.
+  /// @param IncomingBB An incoming block of @p PHI.
+  /// @param LTS        A map from old loops to new induction variables as
+  /// SCEVs.
+  void addOperandToPHI(ScopStmt &Stmt, PHINode *PHI, PHINode *PHICopy,
+                       BasicBlock *IncomingBB, LoopToScevMapT &LTS);
+
+  /// Create a PHI that combines the incoming values from all incoming blocks
+  /// that are in the subregion.
+  ///
+  /// PHIs in the subregion's exit block can have incoming edges from within and
+  /// outside the subregion. This function combines the incoming values from
+  /// within the subregion to appear as if there is only one incoming edge from
+  /// the subregion (an additional exit block is created by RegionGenerator).
+  /// This is to avoid that a value is written to the .phiops location without
+  /// leaving the subregion because the exiting block as an edge back into the
+  /// subregion.
+  ///
+  /// @param MA    The WRITE of MemoryKind::PHI/MemoryKind::ExitPHI for a PHI in
+  ///              the subregion's exit block.
+  /// @param LTS   Virtual induction variable mapping.
+  /// @param BBMap A mapping from old values to their new values in this block.
+  /// @param L     Loop surrounding this region statement.
+  ///
+  /// @returns The constructed PHI node.
+  PHINode *buildExitPHI(MemoryAccess *MA, LoopToScevMapT &LTS, ValueMapT &BBMap,
+                        Loop *L);
+
+  /// @param Return the new value of a scalar write, creating a PHINode if
+  ///        necessary.
+  ///
+  /// @param MA    A scalar WRITE MemoryAccess.
+  /// @param LTS   Virtual induction variable mapping.
+  /// @param BBMap A mapping from old values to their new values in this block.
+  ///
+  /// @returns The effective value of @p MA's written value when leaving the
+  ///          subregion.
+  /// @see buildExitPHI
+  Value *getExitScalar(MemoryAccess *MA, LoopToScevMapT &LTS, ValueMapT &BBMap);
+
+  /// Generate the scalar stores for the given statement.
+  ///
+  /// After the statement @p Stmt was copied all inner-SCoP scalar dependences
+  /// starting in @p Stmt (hence all scalar write accesses in @p Stmt) need to
+  /// be demoted to memory.
+  ///
+  /// @param Stmt  The statement we generate code for.
+  /// @param LTS   A mapping from loops virtual canonical induction variable to
+  ///              their new values (for values recalculated in the new ScoP,
+  ///              but not within this basic block)
+  /// @param BBMap A mapping from old values to their new values in this block.
+  /// @param LTS   A mapping from loops virtual canonical induction variable to
+  /// their new values.
+  virtual void
+  generateScalarStores(ScopStmt &Stmt, LoopToScevMapT &LTS, ValueMapT &BBMAp,
+                       __isl_keep isl_id_to_ast_expr *NewAccesses) override;
+
+  /// Copy a single PHI instruction.
+  ///
+  /// This copies a single PHI instruction and updates references to old values
+  /// with references to new values, as defined by GlobalMap and BBMap.
+  ///
+  /// @param Stmt      The statement to code generate.
+  /// @param PHI       The PHI instruction to copy.
+  /// @param BBMap     A mapping from old values to their new values
+  ///                  (for values recalculated within this basic block).
+  /// @param LTS       A map from old loops to new induction variables as SCEVs.
+  virtual void copyPHIInstruction(ScopStmt &Stmt, PHINode *Inst,
+                                  ValueMapT &BBMap,
+                                  LoopToScevMapT &LTS) override;
+};
+} // namespace polly
+#endif
diff --git a/final/include/polly/CodeGen/CodeGeneration.h b/final/include/polly/CodeGen/CodeGeneration.h
new file mode 100644
index 0000000..1dc224e
--- /dev/null
+++ b/final/include/polly/CodeGen/CodeGeneration.h
@@ -0,0 +1,50 @@
+//===- polly/CodeGeneration.h - The Polly code generator --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_CODEGENERATION_H
+#define POLLY_CODEGENERATION_H
+
+#include "IRBuilder.h"
+#include "polly/Config/config.h"
+#include "polly/ScopPass.h"
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class BasicBlock;
+
+} // namespace llvm
+
+namespace polly {
+
+class Scop;
+
+enum VectorizerChoice {
+  VECTORIZER_NONE,
+  VECTORIZER_STRIPMINE,
+  VECTORIZER_POLLY,
+};
+extern VectorizerChoice PollyVectorizerChoice;
+
+/// Mark a basic block unreachable.
+///
+/// Marks the basic block @p Block unreachable by equipping it with an
+/// UnreachableInst.
+void markBlockUnreachable(BasicBlock &Block, PollyIRBuilder &Builder);
+
+struct CodeGenerationPass : public PassInfoMixin<CodeGenerationPass> {
+  PreservedAnalyses run(Scop &S, ScopAnalysisManager &SAM,
+                        ScopStandardAnalysisResults &AR, SPMUpdater &U);
+};
+
+extern bool PerfMonitoring;
+
+} // namespace polly
+
+#endif // POLLY_CODEGENERATION_H
diff --git a/final/include/polly/CodeGen/CodegenCleanup.h b/final/include/polly/CodeGen/CodegenCleanup.h
new file mode 100644
index 0000000..a1fd680
--- /dev/null
+++ b/final/include/polly/CodeGen/CodegenCleanup.h
@@ -0,0 +1,17 @@
+#ifndef POLLY_CODEGENCLEANUP_H
+#define POLLY_CODEGENCLEANUP_H
+
+namespace llvm {
+class FunctionPass;
+class PassRegistry;
+} // namespace llvm
+
+namespace polly {
+llvm::FunctionPass *createCodegenCleanupPass();
+} // namespace polly
+
+namespace llvm {
+void initializeCodegenCleanupPass(llvm::PassRegistry &);
+} // namespace llvm
+
+#endif
diff --git a/final/include/polly/CodeGen/IRBuilder.h b/final/include/polly/CodeGen/IRBuilder.h
new file mode 100644
index 0000000..dcfc348
--- /dev/null
+++ b/final/include/polly/CodeGen/IRBuilder.h
@@ -0,0 +1,169 @@
+//===- Codegen/IRBuilder.h - The IR builder used by Polly -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The Polly IRBuilder file contains Polly specific extensions for the IRBuilder
+// that are used e.g. to emit the llvm.loop.parallel metadata.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_CODEGEN_IRBUILDER_H
+#define POLLY_CODEGEN_IRBUILDER_H
+
+#include "llvm/ADT/MapVector.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/ValueMap.h"
+
+namespace llvm {
+class ScalarEvolution;
+} // namespace llvm
+
+namespace polly {
+class Scop;
+
+/// Helper class to annotate newly generated SCoPs with metadata.
+///
+/// The annotations are twofold:
+///   1) Loops are stored in a stack-like structure in the order they are
+///      constructed and the LoopID metadata node is added to the backedge.
+///      Contained memory instructions and loop headers are annotated according
+///      to all parallel surrounding loops.
+///   2) The new SCoP is assumed alias free (either due to the result of
+///      AliasAnalysis queries or runtime alias checks). We annotate therefore
+///      all memory instruction with alias scopes to indicate that fact to
+///      later optimizations.
+///      These alias scopes live in a new alias domain only used in this SCoP.
+///      Each base pointer has its own alias scope and is annotated to not
+///      alias with any access to different base pointers.
+class ScopAnnotator {
+public:
+  ScopAnnotator();
+
+  /// Build all alias scopes for the given SCoP.
+  void buildAliasScopes(Scop &S);
+
+  /// Add a new loop @p L which is parallel if @p IsParallel is true.
+  void pushLoop(llvm::Loop *L, bool IsParallel);
+
+  /// Remove the last added loop.
+  void popLoop(bool isParallel);
+
+  /// Annotate the new instruction @p I for all parallel loops.
+  void annotate(llvm::Instruction *I);
+
+  /// Annotate the loop latch @p B wrt. @p L.
+  void annotateLoopLatch(llvm::BranchInst *B, llvm::Loop *L, bool IsParallel,
+                         bool IsLoopVectorizerDisabled) const;
+
+  /// Add alternative alias based pointers
+  ///
+  /// When annotating instructions with alias scope metadata, the right metadata
+  /// is identified through the base pointer of the memory access. In some cases
+  /// (e.g. OpenMP code generation), the base pointer of the memory accesses is
+  /// not the original base pointer, but was changed when passing the original
+  /// base pointer over a function boundary. This function allows to provide a
+  /// map that maps from these new base pointers to the original base pointers
+  /// to allow the ScopAnnotator to still find the right alias scop annotations.
+  ///
+  /// @param NewMap A map from new base pointers to original base pointers.
+  void addAlternativeAliasBases(
+      llvm::DenseMap<llvm::AssertingVH<llvm::Value>,
+                     llvm::AssertingVH<llvm::Value>> &NewMap) {
+    AlternativeAliasBases.insert(NewMap.begin(), NewMap.end());
+  }
+
+  /// Delete the set of alternative alias bases
+  void resetAlternativeAliasBases() { AlternativeAliasBases.clear(); }
+
+  /// Add inter iteration alias-free base pointer @p BasePtr.
+  void addInterIterationAliasFreeBasePtr(llvm::Value *BasePtr);
+
+private:
+  /// Annotate with the second level alias metadata
+  ///
+  /// Annotate the instruction @p I with the second level alias metadata
+  /// to distinguish the individual non-aliasing accesses that have inter
+  /// iteration alias-free base pointers.
+  ///
+  /// @param I The instruction to be annotated.
+  /// @param BasePtr The base pointer of @p I.
+  void annotateSecondLevel(llvm::Instruction *I, llvm::Value *BasePtr);
+
+  /// The ScalarEvolution analysis we use to find base pointers.
+  llvm::ScalarEvolution *SE;
+
+  /// All loops currently under construction.
+  llvm::SmallVector<llvm::Loop *, 8> ActiveLoops;
+
+  /// Metadata pointing to parallel loops currently under construction.
+  llvm::SmallVector<llvm::MDNode *, 8> ParallelLoops;
+
+  /// The alias scope domain for the current SCoP.
+  llvm::MDNode *AliasScopeDomain;
+
+  /// A map from base pointers to its alias scope.
+  llvm::MapVector<llvm::AssertingVH<llvm::Value>, llvm::MDNode *> AliasScopeMap;
+
+  /// A map from base pointers to an alias scope list of other pointers.
+  llvm::DenseMap<llvm::AssertingVH<llvm::Value>, llvm::MDNode *>
+      OtherAliasScopeListMap;
+
+  /// A map from pointers to second level alias scopes.
+  llvm::DenseMap<const llvm::SCEV *, llvm::MDNode *> SecondLevelAliasScopeMap;
+
+  /// A map from pointers to second level alias scope list of other pointers.
+  llvm::DenseMap<const llvm::SCEV *, llvm::MDNode *>
+      SecondLevelOtherAliasScopeListMap;
+
+  /// Inter iteration alias-free base pointers.
+  llvm::SmallPtrSet<llvm::Value *, 4> InterIterationAliasFreeBasePtrs;
+
+  llvm::DenseMap<llvm::AssertingVH<llvm::Value>, llvm::AssertingVH<llvm::Value>>
+      AlternativeAliasBases;
+};
+
+/// Add Polly specifics when running IRBuilder.
+///
+/// This is used to add additional items such as e.g. the llvm.loop.parallel
+/// metadata.
+class IRInserter : protected llvm::IRBuilderDefaultInserter {
+public:
+  IRInserter() = default;
+  IRInserter(class ScopAnnotator &A) : Annotator(&A) {}
+
+protected:
+  void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name,
+                    llvm::BasicBlock *BB,
+                    llvm::BasicBlock::iterator InsertPt) const {
+    llvm::IRBuilderDefaultInserter::InsertHelper(I, Name, BB, InsertPt);
+    if (Annotator)
+      Annotator->annotate(I);
+  }
+
+private:
+  class ScopAnnotator *Annotator = nullptr;
+};
+
+// TODO: We should not name instructions in NDEBUG builds.
+//
+// We currently always name instructions, as the polly test suite currently
+// matches for certain names.
+typedef llvm::IRBuilder<llvm::ConstantFolder, IRInserter> PollyIRBuilder;
+
+/// Return an IR builder pointed before the @p BB terminator.
+static inline PollyIRBuilder createPollyIRBuilder(llvm::BasicBlock *BB,
+                                                  ScopAnnotator &LA) {
+  PollyIRBuilder Builder(BB->getContext(), llvm::ConstantFolder(),
+                         polly::IRInserter(LA));
+  Builder.SetInsertPoint(BB->getTerminator());
+  return Builder;
+}
+} // namespace polly
+#endif
diff --git a/final/include/polly/CodeGen/IslAst.h b/final/include/polly/CodeGen/IslAst.h
new file mode 100644
index 0000000..c1d3305
--- /dev/null
+++ b/final/include/polly/CodeGen/IslAst.h
@@ -0,0 +1,236 @@
+//===- IslAst.h - Interface to the isl code generator -----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The isl code generator interface takes a Scop and generates a isl_ast. This
+// ist_ast can either be returned directly or it can be pretty printed to
+// stdout.
+//
+// A typical isl_ast output looks like this:
+//
+// for (c2 = max(0, ceild(n + m, 2); c2 <= min(511, floord(5 * n, 3)); c2++) {
+//   bb2(c2);
+// }
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_ISLAST_H
+#define POLLY_ISLAST_H
+
+#include "polly/Config/config.h"
+#include "polly/ScopPass.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/IR/PassManager.h"
+#include "isl/ast.h"
+#include "isl/ctx.h"
+#include <memory>
+
+namespace llvm {
+
+class PassRegistry;
+class raw_ostream;
+
+void initializeIslAstInfoWrapperPassPass(PassRegistry &);
+
+} // namespace llvm
+
+struct isl_ast_build;
+struct isl_ast_expr;
+struct isl_ast_node;
+struct isl_pw_aff;
+struct isl_pw_multi_aff;
+struct isl_union_map;
+
+namespace polly {
+
+struct Dependences;
+class MemoryAccess;
+class Scop;
+
+class IslAst {
+public:
+  IslAst(const IslAst &) = delete;
+  IslAst &operator=(const IslAst &) = delete;
+  IslAst(IslAst &&);
+  IslAst &operator=(IslAst &&) = delete;
+  ~IslAst();
+
+  static IslAst create(Scop &Scop, const Dependences &D);
+
+  /// Print a source code representation of the program.
+  void pprint(raw_ostream &OS);
+
+  __isl_give isl_ast_node *getAst();
+
+  const std::shared_ptr<isl_ctx> getSharedIslCtx() const { return Ctx; }
+
+  /// Get the run-time conditions for the Scop.
+  __isl_give isl_ast_expr *getRunCondition();
+
+  /// Build run-time condition for scop.
+  ///
+  /// @param S     The scop to build the condition for.
+  /// @param Build The isl_build object to use to build the condition.
+  ///
+  /// @returns An ast expression that describes the necessary run-time check.
+  static isl_ast_expr *buildRunCondition(Scop &S,
+                                         __isl_keep isl_ast_build *Build);
+
+private:
+  Scop &S;
+  isl_ast_node *Root = nullptr;
+  isl_ast_expr *RunCondition = nullptr;
+  std::shared_ptr<isl_ctx> Ctx;
+
+  IslAst(Scop &Scop);
+
+  void init(const Dependences &D);
+};
+
+class IslAstInfo {
+public:
+  using MemoryAccessSet = SmallPtrSet<MemoryAccess *, 4>;
+
+  /// Payload information used to annotate an AST node.
+  struct IslAstUserPayload {
+    /// Construct and initialize the payload.
+    IslAstUserPayload() = default;
+
+    /// Cleanup all isl structs on destruction.
+    ~IslAstUserPayload();
+
+    /// Flag to mark innermost loops.
+    bool IsInnermost = false;
+
+    /// Flag to mark innermost parallel loops.
+    bool IsInnermostParallel = false;
+
+    /// Flag to mark outermost parallel loops.
+    bool IsOutermostParallel = false;
+
+    /// Flag to mark parallel loops which break reductions.
+    bool IsReductionParallel = false;
+
+    /// The minimal dependence distance for non parallel loops.
+    isl_pw_aff *MinimalDependenceDistance = nullptr;
+
+    /// The build environment at the time this node was constructed.
+    isl_ast_build *Build = nullptr;
+
+    /// Set of accesses which break reduction dependences.
+    MemoryAccessSet BrokenReductions;
+  };
+
+private:
+  Scop &S;
+  IslAst Ast;
+
+public:
+  IslAstInfo(Scop &S, const Dependences &D) : S(S), Ast(IslAst::create(S, D)) {}
+
+  /// Return the isl AST computed by this IslAstInfo.
+  IslAst &getIslAst() { return Ast; }
+
+  /// Return a copy of the AST root node.
+  __isl_give isl_ast_node *getAst();
+
+  /// Get the run condition.
+  ///
+  /// Only if the run condition evaluates at run-time to a non-zero value, the
+  /// assumptions that have been taken hold. If the run condition evaluates to
+  /// zero/false some assumptions do not hold and the original code needs to
+  /// be executed.
+  __isl_give isl_ast_expr *getRunCondition();
+
+  void print(raw_ostream &O);
+
+  /// @name Extract information attached to an isl ast (for) node.
+  ///
+  ///{
+  /// Get the complete payload attached to @p Node.
+  static IslAstUserPayload *getNodePayload(__isl_keep isl_ast_node *Node);
+
+  /// Is this loop an innermost loop?
+  static bool isInnermost(__isl_keep isl_ast_node *Node);
+
+  /// Is this loop a parallel loop?
+  static bool isParallel(__isl_keep isl_ast_node *Node);
+
+  /// Is this loop an outermost parallel loop?
+  static bool isOutermostParallel(__isl_keep isl_ast_node *Node);
+
+  /// Is this loop an innermost parallel loop?
+  static bool isInnermostParallel(__isl_keep isl_ast_node *Node);
+
+  /// Is this loop a reduction parallel loop?
+  static bool isReductionParallel(__isl_keep isl_ast_node *Node);
+
+  /// Will the loop be run as thread parallel?
+  static bool isExecutedInParallel(__isl_keep isl_ast_node *Node);
+
+  /// Get the nodes schedule or a nullptr if not available.
+  static __isl_give isl_union_map *getSchedule(__isl_keep isl_ast_node *Node);
+
+  /// Get minimal dependence distance or nullptr if not available.
+  static __isl_give isl_pw_aff *
+  getMinimalDependenceDistance(__isl_keep isl_ast_node *Node);
+
+  /// Get the nodes broken reductions or a nullptr if not available.
+  static MemoryAccessSet *getBrokenReductions(__isl_keep isl_ast_node *Node);
+
+  /// Get the nodes build context or a nullptr if not available.
+  static __isl_give isl_ast_build *getBuild(__isl_keep isl_ast_node *Node);
+
+  ///}
+};
+
+struct IslAstAnalysis : public AnalysisInfoMixin<IslAstAnalysis> {
+  static AnalysisKey Key;
+
+  using Result = IslAstInfo;
+
+  IslAstInfo run(Scop &S, ScopAnalysisManager &SAM,
+                 ScopStandardAnalysisResults &SAR);
+};
+
+class IslAstInfoWrapperPass : public ScopPass {
+  std::unique_ptr<IslAstInfo> Ast;
+
+public:
+  static char ID;
+
+  IslAstInfoWrapperPass() : ScopPass(ID) {}
+
+  IslAstInfo &getAI() { return *Ast; }
+  const IslAstInfo &getAI() const { return *Ast; }
+
+  /// Build the AST for the given SCoP @p S.
+  bool runOnScop(Scop &S) override;
+
+  /// Register all analyses and transformation required.
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+  /// Release the internal memory.
+  void releaseMemory() override;
+
+  /// Print a source code representation of the program.
+  void printScop(raw_ostream &OS, Scop &S) const override;
+};
+
+struct IslAstPrinterPass : public PassInfoMixin<IslAstPrinterPass> {
+  IslAstPrinterPass(raw_ostream &OS) : OS(OS) {}
+
+  PreservedAnalyses run(Scop &S, ScopAnalysisManager &SAM,
+                        ScopStandardAnalysisResults &, SPMUpdater &U);
+
+  raw_ostream &OS;
+};
+
+} // namespace polly
+
+#endif // POLLY_ISLAST_H
diff --git a/final/include/polly/CodeGen/IslExprBuilder.h b/final/include/polly/CodeGen/IslExprBuilder.h
new file mode 100644
index 0000000..c036463
--- /dev/null
+++ b/final/include/polly/CodeGen/IslExprBuilder.h
@@ -0,0 +1,278 @@
+//===-IslExprBuilder.h - Helper to generate code for isl AST expressions --===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_ISL_EXPR_BUILDER_H
+#define POLLY_ISL_EXPR_BUILDER_H
+
+#include "polly/CodeGen/IRBuilder.h"
+#include "polly/Support/ScopHelper.h"
+
+#include "llvm/ADT/MapVector.h"
+#include "isl/ast.h"
+#include "isl/isl-noexceptions.h"
+
+namespace llvm {
+class DataLayout;
+class ScalarEvolution;
+} // namespace llvm
+
+struct isl_id;
+
+namespace llvm {
+// Provide PointerLikeTypeTraits for isl_id.
+template <> struct PointerLikeTypeTraits<isl_id *> {
+
+public:
+  static inline const void *getAsVoidPointer(isl_id *P) { return (void *)P; }
+  static inline const Region *getFromVoidPointer(void *P) {
+    return (Region *)P;
+  }
+  enum { NumLowBitsAvailable = 0 };
+};
+} // namespace llvm
+
+namespace polly {
+class ScopArrayInfo;
+
+/// LLVM-IR generator for isl_ast_expr[essions]
+///
+/// This generator generates LLVM-IR that performs the computation described by
+/// an isl_ast_expr[ession].
+///
+/// Example:
+///
+///   An isl_ast_expr[ession] can look like this:
+///
+///     (N + M) + 10
+///
+///   The IslExprBuilder could create the following LLVM-IR:
+///
+///     %tmp1 = add nsw i64 %N
+///     %tmp2 = add nsw i64 %tmp1, %M
+///     %tmp3 = add nsw i64 %tmp2, 10
+///
+/// The implementation of this class is mostly a mapping from isl_ast_expr
+/// constructs to the corresponding LLVM-IR constructs.
+///
+/// The following decisions may need some explanation:
+///
+/// 1) Which data-type to choose
+///
+/// isl_ast_expr[essions] are untyped expressions that assume arbitrary
+/// precision integer computations. LLVM-IR instead has fixed size integers.
+/// When lowering to LLVM-IR we need to chose both the size of the data type and
+/// the sign of the operations we use.
+///
+/// At the moment, we hardcode i64 bit signed computations. Our experience has
+/// shown that 64 bit are generally large enough for the loop bounds that appear
+/// in the wild. Signed computations are needed, as loop bounds may become
+/// negative.
+///
+/// It is possible to track overflows that occurred in the generated IR. See the
+/// description of @see OverflowState for more information.
+///
+/// FIXME: Hardcoding sizes can cause issues:
+///
+///   -  On embedded systems and especially for high-level-synthesis 64 bit
+///      computations are very costly.
+///
+///   The right approach is to compute the minimal necessary bitwidth and
+///   signedness for each subexpression during in the isl AST generation and
+///   to use this information in our IslAstGenerator. Preliminary patches are
+///   available, but have not been committed yet.
+///
+class IslExprBuilder {
+public:
+  /// A map from isl_ids to llvm::Values.
+  typedef llvm::MapVector<isl_id *, llvm::AssertingVH<llvm::Value>> IDToValueTy;
+
+  typedef llvm::MapVector<isl_id *, const ScopArrayInfo *> IDToScopArrayInfoTy;
+
+  /// A map from isl_ids to ScopArrayInfo objects.
+  ///
+  /// This map is used to obtain ScopArrayInfo objects for isl_ids which do not
+  /// carry a ScopArrayInfo object in their user pointer. This is useful if the
+  /// construction of ScopArrayInfo objects happens only after references (e.g.
+  /// in an AST) to an isl_id are generated and the user pointer of the isl_id
+  /// can not be changed any more.
+  ///
+  /// This is useful for external users who just use the IslExprBuilder for
+  /// code generation.
+  IDToScopArrayInfoTy *IDToSAI = nullptr;
+
+  /// Set the isl_id to ScopArrayInfo map.
+  ///
+  /// @param NewIDToSAI The new isl_id to ScopArrayInfo map to use.
+  void setIDToSAI(IDToScopArrayInfoTy *NewIDToSAI) { IDToSAI = NewIDToSAI; }
+
+  /// Construct an IslExprBuilder.
+  ///
+  /// @param Builder     The IRBuilder used to construct the
+  ///                    isl_ast_expr[ession]. The insert location of this
+  ///                    IRBuilder defines WHERE the  corresponding LLVM-IR
+  ///                    is generated.
+  /// @param IDToValue   The isl_ast_expr[ession] may reference parameters or
+  ///                    variables (identified by an isl_id). The IDTOValue map
+  ///                    specifies the LLVM-IR Values that correspond to these
+  ///                    parameters and variables.
+  /// @param GlobalMap   A mapping from llvm::Values used in the original scop
+  ///                    region to a new set of llvm::Values.
+  /// @param DL          DataLayout for the current Module.
+  /// @param SE          ScalarEvolution analysis for the current function.
+  /// @param DT          DominatorTree analysis for the current function.
+  /// @param LI          LoopInfo analysis for the current function.
+  /// @param StartBlock The first basic block after the RTC.
+  IslExprBuilder(Scop &S, PollyIRBuilder &Builder, IDToValueTy &IDToValue,
+                 ValueMapT &GlobalMap, const llvm::DataLayout &DL,
+                 llvm::ScalarEvolution &SE, llvm::DominatorTree &DT,
+                 llvm::LoopInfo &LI, llvm::BasicBlock *StartBlock);
+
+  /// Create LLVM-IR for an isl_ast_expr[ession].
+  ///
+  /// @param Expr The ast expression for which we generate LLVM-IR.
+  ///
+  /// @return The llvm::Value* containing the result of the computation.
+  llvm::Value *create(__isl_take isl_ast_expr *Expr);
+
+  /// Return the largest of two types.
+  ///
+  /// @param T1 The first type.
+  /// @param T2 The second type.
+  ///
+  /// @return The largest of the two types.
+  llvm::Type *getWidestType(llvm::Type *T1, llvm::Type *T2);
+
+  /// Return the type with which this expression should be computed.
+  ///
+  /// The type needs to be large enough to hold all possible input and all
+  /// possible output values.
+  ///
+  /// @param Expr The expression for which to find the type.
+  /// @return The type with which the expression should be computed.
+  llvm::IntegerType *getType(__isl_keep isl_ast_expr *Expr);
+
+  /// Change if runtime overflows are tracked or not.
+  ///
+  /// @param Enable Flag to enable/disable the tracking.
+  ///
+  /// Note that this will reset the tracking state and that tracking is only
+  /// allowed if the last tracked expression dominates the current insert point.
+  void setTrackOverflow(bool Enable);
+
+  /// Return the current overflow status or nullptr if it is not tracked.
+  ///
+  /// @return A nullptr if tracking is disabled or otherwise an i1 that has the
+  ///         value of "0" if and only if no overflow happened since tracking
+  ///         was enabled.
+  llvm::Value *getOverflowState() const;
+
+  /// Create LLVM-IR that computes the memory location of an access expression.
+  ///
+  /// For a given isl_ast_expr[ession] of type isl_ast_op_access this function
+  /// creates IR that computes the address the access expression refers to.
+  ///
+  /// @param Expr The ast expression of type isl_ast_op_access
+  ///             for which we generate LLVM-IR.
+  ///
+  /// @return The llvm::Value* containing the result of the computation.
+  llvm::Value *createAccessAddress(__isl_take isl_ast_expr *Expr);
+
+  /// Check if an @p Expr contains integer constants larger than 64 bit.
+  ///
+  /// @param Expr The expression to check.
+  ///
+  /// @return True if the ast expression is larger than 64 bit.
+  bool hasLargeInts(isl::ast_expr Expr);
+
+private:
+  Scop &S;
+
+  /// Flag that will be set if an overflow occurred at runtime.
+  ///
+  /// Note that this flag is by default a nullptr and if it is a nullptr
+  /// we will not record overflows but simply perform the computations.
+  /// The intended usage is as follows:
+  ///   - If overflows in [an] expression[s] should be tracked, call
+  ///     the setTrackOverflow(true) function.
+  ///   - Use create(...) for all expressions that should be checked.
+  ///   - Call getOverflowState() to get the value representing the current
+  ///     state of the overflow flag.
+  ///   - To stop tracking call setTrackOverflow(false).
+  llvm::Value *OverflowState;
+
+  PollyIRBuilder &Builder;
+  IDToValueTy &IDToValue;
+  ValueMapT &GlobalMap;
+
+  const llvm::DataLayout &DL;
+  llvm::ScalarEvolution &SE;
+  llvm::DominatorTree &DT;
+  llvm::LoopInfo &LI;
+  llvm::BasicBlock *StartBlock;
+
+  llvm::Value *createOp(__isl_take isl_ast_expr *Expr);
+  llvm::Value *createOpUnary(__isl_take isl_ast_expr *Expr);
+  llvm::Value *createOpAccess(__isl_take isl_ast_expr *Expr);
+  llvm::Value *createOpBin(__isl_take isl_ast_expr *Expr);
+  llvm::Value *createOpNAry(__isl_take isl_ast_expr *Expr);
+  llvm::Value *createOpSelect(__isl_take isl_ast_expr *Expr);
+  llvm::Value *createOpICmp(__isl_take isl_ast_expr *Expr);
+  llvm::Value *createOpBoolean(__isl_take isl_ast_expr *Expr);
+  llvm::Value *createOpBooleanConditional(__isl_take isl_ast_expr *Expr);
+  llvm::Value *createId(__isl_take isl_ast_expr *Expr);
+  llvm::Value *createInt(__isl_take isl_ast_expr *Expr);
+  llvm::Value *createOpAddressOf(__isl_take isl_ast_expr *Expr);
+
+  /// Create a binary operation @p Opc and track overflows if requested.
+  ///
+  /// @param OpC  The binary operation that should be performed [Add/Sub/Mul].
+  /// @param LHS  The left operand.
+  /// @param RHS  The right operand.
+  /// @param Name The (base) name of the new IR operations.
+  ///
+  /// @return A value that represents the result of the binary operation.
+  llvm::Value *createBinOp(llvm::BinaryOperator::BinaryOps Opc,
+                           llvm::Value *LHS, llvm::Value *RHS,
+                           const llvm::Twine &Name);
+
+  /// Create an addition and track overflows if requested.
+  ///
+  /// @param LHS  The left operand.
+  /// @param RHS  The right operand.
+  /// @param Name The (base) name of the new IR operations.
+  ///
+  /// @return A value that represents the result of the addition.
+  llvm::Value *createAdd(llvm::Value *LHS, llvm::Value *RHS,
+                         const llvm::Twine &Name = "");
+
+  /// Create a subtraction and track overflows if requested.
+  ///
+  /// @param LHS  The left operand.
+  /// @param RHS  The right operand.
+  /// @param Name The (base) name of the new IR operations.
+  ///
+  /// @return A value that represents the result of the subtraction.
+  llvm::Value *createSub(llvm::Value *LHS, llvm::Value *RHS,
+                         const llvm::Twine &Name = "");
+
+  /// Create a multiplication and track overflows if requested.
+  ///
+  /// @param LHS  The left operand.
+  /// @param RHS  The right operand.
+  /// @param Name The (base) name of the new IR operations.
+  ///
+  /// @return A value that represents the result of the multiplication.
+  llvm::Value *createMul(llvm::Value *LHS, llvm::Value *RHS,
+                         const llvm::Twine &Name = "");
+};
+} // namespace polly
+
+#endif
diff --git a/final/include/polly/CodeGen/IslNodeBuilder.h b/final/include/polly/CodeGen/IslNodeBuilder.h
new file mode 100644
index 0000000..cae93ee
--- /dev/null
+++ b/final/include/polly/CodeGen/IslNodeBuilder.h
@@ -0,0 +1,464 @@
+//=- IslNodeBuilder.cpp - Translate an isl AST into a LLVM-IR AST -*- C++ -*-=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the IslNodeBuilder, a class to translate an isl AST into
+// a LLVM-IR AST.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_ISLNODEBUILDER_H
+#define POLLY_ISLNODEBUILDER_H
+
+#include "polly/CodeGen/BlockGenerators.h"
+#include "polly/CodeGen/IslExprBuilder.h"
+#include "polly/ScopDetectionDiagnostic.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/InstrTypes.h"
+#include "isl/ctx.h"
+#include "isl/isl-noexceptions.h"
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace polly;
+
+namespace llvm {
+
+class BasicBlock;
+class DataLayout;
+class DominatorTree;
+class Function;
+class Instruction;
+class Loop;
+class LoopInfo;
+class ScalarEvolution;
+class SCEV;
+class Type;
+class Value;
+
+} // namespace llvm
+
+namespace polly {
+
+struct InvariantEquivClassTy;
+class MemoryAccess;
+class Scop;
+class ScopStmt;
+
+} // namespace polly
+
+struct isl_ast_node;
+struct isl_ast_build;
+struct isl_union_map;
+
+struct SubtreeReferences {
+  LoopInfo &LI;
+  ScalarEvolution &SE;
+  Scop &S;
+  ValueMapT &GlobalMap;
+  SetVector<Value *> &Values;
+  SetVector<const SCEV *> &SCEVs;
+  BlockGenerator &BlockGen;
+  // In case an (optional) parameter space location is provided, parameter space
+  // information is collected as well.
+  isl::space *ParamSpace;
+};
+
+/// Extract the out-of-scop values and SCEVs referenced from a ScopStmt.
+///
+/// This includes the SCEVUnknowns referenced by the SCEVs used in the
+/// statement and the base pointers of the memory accesses. For scalar
+/// statements we force the generation of alloca memory locations and list
+/// these locations in the set of out-of-scop values as well.
+///
+/// We also collect an isl::space that includes all parameter dimensions
+/// used in the statement's memory accesses, in case the ParamSpace pointer
+/// is non-null.
+///
+/// @param Stmt             The statement for which to extract the information.
+/// @param UserPtr          A void pointer that can be casted to a
+///                         SubtreeReferences structure.
+/// @param CreateScalarRefs Should the result include allocas of scalar
+///                         references?
+isl_stat addReferencesFromStmt(const ScopStmt *Stmt, void *UserPtr,
+                               bool CreateScalarRefs = true);
+
+class IslNodeBuilder {
+public:
+  IslNodeBuilder(PollyIRBuilder &Builder, ScopAnnotator &Annotator,
+                 const DataLayout &DL, LoopInfo &LI, ScalarEvolution &SE,
+                 DominatorTree &DT, Scop &S, BasicBlock *StartBlock)
+      : S(S), Builder(Builder), Annotator(Annotator),
+        ExprBuilder(S, Builder, IDToValue, ValueMap, DL, SE, DT, LI,
+                    StartBlock),
+        BlockGen(Builder, LI, SE, DT, ScalarMap, EscapeMap, ValueMap,
+                 &ExprBuilder, StartBlock),
+        RegionGen(BlockGen), DL(DL), LI(LI), SE(SE), DT(DT),
+        StartBlock(StartBlock) {}
+
+  virtual ~IslNodeBuilder() = default;
+
+  void addParameters(__isl_take isl_set *Context);
+
+  /// Create Values which hold the sizes of the outermost dimension of all
+  /// Fortran arrays in the current scop.
+  ///
+  /// @returns False, if a problem occurred and a Fortran array was not
+  /// materialized. True otherwise.
+  bool materializeFortranArrayOutermostDimension();
+
+  /// Generate code that evaluates @p Condition at run-time.
+  ///
+  /// This function is typically called to generate the LLVM-IR for the
+  /// run-time condition of the scop, that verifies that all the optimistic
+  /// assumptions we have taken during scop modeling and transformation
+  /// hold at run-time.
+  ///
+  /// @param Condition The condition to evaluate
+  ///
+  /// @result An llvm::Value that is true if the condition holds and false
+  ///         otherwise.
+  Value *createRTC(isl_ast_expr *Condition);
+
+  void create(__isl_take isl_ast_node *Node);
+
+  /// Allocate memory for all new arrays created by Polly.
+  void allocateNewArrays(BBPair StartExitBlocks);
+
+  /// Preload all memory loads that are invariant.
+  bool preloadInvariantLoads();
+
+  /// Finalize code generation.
+  ///
+  /// @see BlockGenerator::finalizeSCoP(Scop &S)
+  virtual void finalize() { BlockGen.finalizeSCoP(S); }
+
+  IslExprBuilder &getExprBuilder() { return ExprBuilder; }
+
+  /// Get the associated block generator.
+  ///
+  /// @return A reference to the associated block generator.
+  BlockGenerator &getBlockGenerator() { return BlockGen; }
+
+  /// Return the parallel subfunctions that have been created.
+  const ArrayRef<Function *> getParallelSubfunctions() const {
+    return ParallelSubfunctions;
+  }
+
+protected:
+  Scop &S;
+  PollyIRBuilder &Builder;
+  ScopAnnotator &Annotator;
+
+  IslExprBuilder ExprBuilder;
+
+  /// Maps used by the block and region generator to demote scalars.
+  ///
+  ///@{
+
+  /// See BlockGenerator::ScalarMap.
+  BlockGenerator::AllocaMapTy ScalarMap;
+
+  /// See BlockGenerator::EscapeMap.
+  BlockGenerator::EscapeUsersAllocaMapTy EscapeMap;
+
+  ///@}
+
+  /// The generator used to copy a basic block.
+  BlockGenerator BlockGen;
+
+  /// The generator used to copy a non-affine region.
+  RegionGenerator RegionGen;
+
+  const DataLayout &DL;
+  LoopInfo &LI;
+  ScalarEvolution &SE;
+  DominatorTree &DT;
+  BasicBlock *StartBlock;
+
+  /// The current iteration of out-of-scop loops
+  ///
+  /// This map provides for a given loop a llvm::Value that contains the current
+  /// loop iteration.
+  LoopToScevMapT OutsideLoopIterations;
+
+  // This maps an isl_id* to the Value* it has in the generated program. For now
+  // on, the only isl_ids that are stored here are the newly calculated loop
+  // ivs.
+  IslExprBuilder::IDToValueTy IDToValue;
+
+  /// A collection of all parallel subfunctions that have been created.
+  SmallVector<Function *, 8> ParallelSubfunctions;
+
+  /// Generate code for a given SCEV*
+  ///
+  /// This function generates code for a given SCEV expression. It generated
+  /// code is emitted at the end of the basic block our Builder currently
+  /// points to and the resulting value is returned.
+  ///
+  /// @param Expr The expression to code generate.
+  Value *generateSCEV(const SCEV *Expr);
+
+  /// A set of Value -> Value remappings to apply when generating new code.
+  ///
+  /// When generating new code for a ScopStmt this map is used to map certain
+  /// llvm::Values to new llvm::Values.
+  ValueMapT ValueMap;
+
+  /// Materialize code for @p Id if it was not done before.
+  ///
+  /// @returns False, iff a problem occurred and the value was not materialized.
+  bool materializeValue(__isl_take isl_id *Id);
+
+  /// Materialize parameters of @p Set.
+  ///
+  /// @returns False, iff a problem occurred and the value was not materialized.
+  bool materializeParameters(__isl_take isl_set *Set);
+
+  /// Materialize all parameters in the current scop.
+  ///
+  /// @returns False, iff a problem occurred and the value was not materialized.
+  bool materializeParameters();
+
+  // Extract the upper bound of this loop
+  //
+  // The isl code generation can generate arbitrary expressions to check if the
+  // upper bound of a loop is reached, but it provides an option to enforce
+  // 'atomic' upper bounds. An 'atomic upper bound is always of the form
+  // iv <= expr, where expr is an (arbitrary) expression not containing iv.
+  //
+  // This function extracts 'atomic' upper bounds. Polly, in general, requires
+  // atomic upper bounds for the following reasons:
+  //
+  // 1. An atomic upper bound is loop invariant
+  //
+  //    It must not be calculated at each loop iteration and can often even be
+  //    hoisted out further by the loop invariant code motion.
+  //
+  // 2. OpenMP needs a loop invariant upper bound to calculate the number
+  //    of loop iterations.
+  //
+  // 3. With the existing code, upper bounds have been easier to implement.
+  __isl_give isl_ast_expr *getUpperBound(__isl_keep isl_ast_node *For,
+                                         CmpInst::Predicate &Predicate);
+
+  /// Return non-negative number of iterations in case of the following form
+  /// of a loop and -1 otherwise.
+  ///
+  /// for (i = 0; i <= NumIter; i++) {
+  ///   loop body;
+  /// }
+  ///
+  /// NumIter is a non-negative integer value. Condition can have
+  /// isl_ast_op_lt type.
+  int getNumberOfIterations(__isl_keep isl_ast_node *For);
+
+  /// Compute the values and loops referenced in this subtree.
+  ///
+  /// This function looks at all ScopStmts scheduled below the provided For node
+  /// and finds the llvm::Value[s] and llvm::Loops[s] which are referenced but
+  /// not locally defined.
+  ///
+  /// Values that can be synthesized or that are available as globals are
+  /// considered locally defined.
+  ///
+  /// Loops that contain the scop or that are part of the scop are considered
+  /// locally defined. Loops that are before the scop, but do not contain the
+  /// scop itself are considered not locally defined.
+  ///
+  /// @param For    The node defining the subtree.
+  /// @param Values A vector that will be filled with the Values referenced in
+  ///               this subtree.
+  /// @param Loops  A vector that will be filled with the Loops referenced in
+  ///               this subtree.
+  void getReferencesInSubtree(__isl_keep isl_ast_node *For,
+                              SetVector<Value *> &Values,
+                              SetVector<const Loop *> &Loops);
+
+  /// Change the llvm::Value(s) used for code generation.
+  ///
+  /// When generating code certain values (e.g., references to induction
+  /// variables or array base pointers) in the original code may be replaced by
+  /// new values. This function allows to (partially) update the set of values
+  /// used. A typical use case for this function is the case when we continue
+  /// code generation in a subfunction/kernel function and need to explicitly
+  /// pass down certain values.
+  ///
+  /// @param NewValues A map that maps certain llvm::Values to new llvm::Values.
+  void updateValues(ValueMapT &NewValues);
+
+  /// Return the most up-to-date version of the llvm::Value for code generation.
+  /// @param Original The Value to check for an up to date version.
+  /// @returns A remapped `Value` from ValueMap, or `Original` if no mapping
+  ///          exists.
+  /// @see IslNodeBuilder::updateValues
+  /// @see IslNodeBuilder::ValueMap
+  Value *getLatestValue(Value *Original) const;
+
+  /// Generate code for a marker now.
+  ///
+  /// For mark nodes with an unknown name, we just forward the code generation
+  /// to its child. This is currently the only behavior implemented, as there is
+  /// currently not special handling for marker nodes implemented.
+  ///
+  /// @param Mark The node we generate code for.
+  virtual void createMark(__isl_take isl_ast_node *Marker);
+
+  virtual void createFor(__isl_take isl_ast_node *For);
+
+  /// Set to remember materialized invariant loads.
+  ///
+  /// An invariant load is identified by its pointer (the SCEV) and its type.
+  SmallSet<std::pair<const SCEV *, Type *>, 16> PreloadedPtrs;
+
+  /// Preload the memory access at @p AccessRange with @p Build.
+  ///
+  /// @returns The preloaded value casted to type @p Ty
+  Value *preloadUnconditionally(__isl_take isl_set *AccessRange,
+                                isl_ast_build *Build, Instruction *AccInst);
+
+  /// Preload the memory load access @p MA.
+  ///
+  /// If @p MA is not always executed it will be conditionally loaded and
+  /// merged with undef from the same type. Hence, if @p MA is executed only
+  /// under condition C then the preload code will look like this:
+  ///
+  /// MA_preload = undef;
+  /// if (C)
+  ///   MA_preload = load MA;
+  /// use MA_preload
+  Value *preloadInvariantLoad(const MemoryAccess &MA,
+                              __isl_take isl_set *Domain);
+
+  /// Preload the invariant access equivalence class @p IAClass
+  ///
+  /// This function will preload the representing load from @p IAClass and
+  /// map all members of @p IAClass to that preloaded value, potentially casted
+  /// to the required type.
+  ///
+  /// @returns False, iff a problem occurred and the load was not preloaded.
+  bool preloadInvariantEquivClass(InvariantEquivClassTy &IAClass);
+
+  void createForVector(__isl_take isl_ast_node *For, int VectorWidth);
+  void createForSequential(__isl_take isl_ast_node *For, bool MarkParallel);
+
+  /// Create LLVM-IR that executes a for node thread parallel.
+  ///
+  /// @param For The FOR isl_ast_node for which code is generated.
+  void createForParallel(__isl_take isl_ast_node *For);
+
+  /// Create new access functions for modified memory accesses.
+  ///
+  /// In case the access function of one of the memory references in the Stmt
+  /// has been modified, we generate a new isl_ast_expr that reflects the
+  /// newly modified access function and return a map that maps from the
+  /// individual memory references in the statement (identified by their id)
+  /// to these newly generated ast expressions.
+  ///
+  /// @param Stmt  The statement for which to (possibly) generate new access
+  ///              functions.
+  /// @param Node  The ast node corresponding to the statement for us to extract
+  ///              the local schedule from.
+  /// @return A new hash table that contains remappings from memory ids to new
+  ///         access expressions.
+  __isl_give isl_id_to_ast_expr *
+  createNewAccesses(ScopStmt *Stmt, __isl_keep isl_ast_node *Node);
+
+  /// Generate LLVM-IR that computes the values of the original induction
+  /// variables in function of the newly generated loop induction variables.
+  ///
+  /// Example:
+  ///
+  ///   // Original
+  ///   for i
+  ///     for j
+  ///       S(i)
+  ///
+  ///   Schedule: [i,j] -> [i+j, j]
+  ///
+  ///   // New
+  ///   for c0
+  ///     for c1
+  ///       S(c0 - c1, c1)
+  ///
+  /// Assuming the original code consists of two loops which are
+  /// transformed according to a schedule [i,j] -> [c0=i+j,c1=j]. The resulting
+  /// ast models the original statement as a call expression where each argument
+  /// is an expression that computes the old induction variables from the new
+  /// ones, ordered such that the first argument computes the value of induction
+  /// variable that was outermost in the original code.
+  ///
+  /// @param Expr The call expression that represents the statement.
+  /// @param Stmt The statement that is called.
+  /// @param LTS  The loop to SCEV map in which the mapping from the original
+  ///             loop to a SCEV representing the new loop iv is added. This
+  ///             mapping does not require an explicit induction variable.
+  ///             Instead, we think in terms of an implicit induction variable
+  ///             that counts the number of times a loop is executed. For each
+  ///             original loop this count, expressed in function of the new
+  ///             induction variables, is added to the LTS map.
+  void createSubstitutions(__isl_take isl_ast_expr *Expr, ScopStmt *Stmt,
+                           LoopToScevMapT &LTS);
+  void createSubstitutionsVector(__isl_take isl_ast_expr *Expr, ScopStmt *Stmt,
+                                 std::vector<LoopToScevMapT> &VLTS,
+                                 std::vector<Value *> &IVS,
+                                 __isl_take isl_id *IteratorID);
+  virtual void createIf(__isl_take isl_ast_node *If);
+  void createUserVector(__isl_take isl_ast_node *User,
+                        std::vector<Value *> &IVS,
+                        __isl_take isl_id *IteratorID,
+                        __isl_take isl_union_map *Schedule);
+  virtual void createUser(__isl_take isl_ast_node *User);
+  virtual void createBlock(__isl_take isl_ast_node *Block);
+
+  /// Get the schedule for a given AST node.
+  ///
+  /// This information is used to reason about parallelism of loops or the
+  /// locality of memory accesses under a given schedule.
+  ///
+  /// @param Node The node we want to obtain the schedule for.
+  /// @return Return an isl_union_map that maps from the statements executed
+  ///         below this ast node to the scheduling vectors used to enumerate
+  ///         them.
+  ///
+  virtual __isl_give isl_union_map *
+  getScheduleForAstNode(__isl_take isl_ast_node *Node);
+
+private:
+  /// Create code for a copy statement.
+  ///
+  /// A copy statement is expected to have one read memory access and one write
+  /// memory access (in this very order). Data is loaded from the location
+  /// described by the read memory access and written to the location described
+  /// by the write memory access. @p NewAccesses contains for each access
+  /// the isl ast expression that describes the location accessed.
+  ///
+  /// @param Stmt The copy statement that contains the accesses.
+  /// @param NewAccesses The hash table that contains remappings from memory
+  ///                    ids to new access expressions.
+  void generateCopyStmt(ScopStmt *Stmt,
+                        __isl_keep isl_id_to_ast_expr *NewAccesses);
+
+  /// Materialize a canonical loop induction variable for `L`, which is a loop
+  /// that is *not* present in the Scop.
+  ///
+  /// Note that this is materialized at the point where the `Builder` is
+  /// currently pointing.
+  /// We also populate the `OutsideLoopIterations` map with `L`s SCEV to keep
+  /// track of the induction variable.
+  /// See [Code generation of induction variables of loops outside Scops]
+  Value *materializeNonScopLoopInductionVariable(const Loop *L);
+};
+
+#endif // POLLY_ISLNODEBUILDER_H
diff --git a/final/include/polly/CodeGen/LoopGenerators.h b/final/include/polly/CodeGen/LoopGenerators.h
new file mode 100644
index 0000000..fe13299
--- /dev/null
+++ b/final/include/polly/CodeGen/LoopGenerators.h
@@ -0,0 +1,220 @@
+//===- LoopGenerators.h - IR helper to create loops -------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains functions to create scalar and OpenMP parallel loops
+// as LLVM-IR.
+//
+//===----------------------------------------------------------------------===//
+#ifndef POLLY_LOOP_GENERATORS_H
+#define POLLY_LOOP_GENERATORS_H
+
+#include "polly/CodeGen/IRBuilder.h"
+#include "polly/Support/ScopHelper.h"
+
+#include "llvm/ADT/SetVector.h"
+#include "llvm/IR/ValueMap.h"
+
+namespace llvm {
+class Value;
+class Pass;
+class BasicBlock;
+} // namespace llvm
+
+namespace polly {
+using namespace llvm;
+
+/// Create a scalar do/for-style loop.
+///
+/// @param LowerBound         The starting value of the induction variable.
+/// @param UpperBound         The upper bound of the induction variable.
+/// @param Stride             The value by which the induction variable
+///                           is incremented.
+///
+/// @param Builder            The builder used to create the loop.
+/// @param P                  A pointer to the pass that uses this function.
+///                           It is used to update analysis information.
+/// @param LI                 The loop info for the current function
+/// @param DT                 The dominator tree we need to update
+/// @param ExitBlock          The block the loop will exit to.
+/// @param Predicate          The predicate used to generate the upper loop
+///                           bound.
+/// @param Annotator          This function can (optionally) take
+///                           a ScopAnnotator which
+///                           annotates loops and alias information in the SCoP.
+/// @param Parallel           If this loop should be marked parallel in
+///                           the Annotator.
+/// @param UseGuard           Create a guard in front of the header to check if
+///                           the loop is executed at least once, otherwise just
+///                           assume it.
+/// @param LoopVectDisabled   If the Loop vectorizer should be disabled for this
+///                           loop.
+///
+/// @return Value*    The newly created induction variable for this loop.
+Value *createLoop(Value *LowerBound, Value *UpperBound, Value *Stride,
+                  PollyIRBuilder &Builder, LoopInfo &LI, DominatorTree &DT,
+                  BasicBlock *&ExitBlock, ICmpInst::Predicate Predicate,
+                  ScopAnnotator *Annotator = NULL, bool Parallel = false,
+                  bool UseGuard = true, bool LoopVectDisabled = false);
+
+/// The ParallelLoopGenerator allows to create parallelized loops
+///
+/// To parallelize a loop, we perform the following steps:
+///   o  Generate a subfunction which will hold the loop body.
+///   o  Create a struct to hold all outer values needed in the loop body.
+///   o  Create calls to a runtime library to achieve the actual parallelism.
+///      These calls will spawn and join threads, define how the work (here the
+///      iterations) are distributed between them and make sure each has access
+///      to the struct holding all needed values.
+///
+/// At the moment we support only one parallel runtime, OpenMP.
+///
+/// If we parallelize the outer loop of the following loop nest,
+///
+///   S0;
+///   for (int i = 0; i < N; i++)
+///     for (int j = 0; j < M; j++)
+///       S1(i, j);
+///   S2;
+///
+/// we will generate the following code (with different runtime function names):
+///
+///   S0;
+///   auto *values = storeValuesIntoStruct();
+///   // Execute subfunction with multiple threads
+///   spawn_threads(subfunction, values);
+///   join_threads();
+///   S2;
+///
+///  // This function is executed in parallel by different threads
+///   void subfunction(values) {
+///     while (auto *WorkItem = getWorkItem()) {
+///       int LB = WorkItem.begin();
+///       int UB = WorkItem.end();
+///       for (int i = LB; i < UB; i++)
+///         for (int j = 0; j < M; j++)
+///           S1(i, j);
+///     }
+///     cleanup_thread();
+///   }
+class ParallelLoopGenerator {
+public:
+  /// Create a parallel loop generator for the current function.
+  ParallelLoopGenerator(PollyIRBuilder &Builder, LoopInfo &LI,
+                        DominatorTree &DT, const DataLayout &DL)
+      : Builder(Builder), LI(LI), DT(DT),
+        LongType(
+            Type::getIntNTy(Builder.getContext(), DL.getPointerSizeInBits())),
+        M(Builder.GetInsertBlock()->getParent()->getParent()) {}
+
+  /// Create a parallel loop.
+  ///
+  /// This function is the main function to automatically generate a parallel
+  /// loop with all its components.
+  ///
+  /// @param LB        The lower bound for the loop we parallelize.
+  /// @param UB        The upper bound for the loop we parallelize.
+  /// @param Stride    The stride of the loop we parallelize.
+  /// @param Values    A set of LLVM-IR Values that should be available in
+  ///                  the new loop body.
+  /// @param VMap      A map to allow outside access to the new versions of
+  ///                  the values in @p Values.
+  /// @param LoopBody  A pointer to an iterator that is set to point to the
+  ///                  body of the created loop. It should be used to insert
+  ///                  instructions that form the actual loop body.
+  ///
+  /// @return The newly created induction variable for this loop.
+  Value *createParallelLoop(Value *LB, Value *UB, Value *Stride,
+                            SetVector<Value *> &Values, ValueMapT &VMap,
+                            BasicBlock::iterator *LoopBody);
+
+private:
+  /// The IR builder we use to create instructions.
+  PollyIRBuilder &Builder;
+
+  /// The loop info of the current function we need to update.
+  LoopInfo &LI;
+
+  /// The dominance tree of the current function we need to update.
+  DominatorTree &DT;
+
+  /// The type of a "long" on this hardware used for backend calls.
+  Type *LongType;
+
+  /// The current module
+  Module *M;
+
+public:
+  /// The functions below can be used if one does not want to generate a
+  /// specific OpenMP parallel loop, but generate individual parts of it
+  /// (e.g., the subfunction definition).
+
+  /// Create a runtime library call to spawn the worker threads.
+  ///
+  /// @param SubFn      The subfunction which holds the loop body.
+  /// @param SubFnParam The parameter for the subfunction (basically the struct
+  ///                   filled with the outside values).
+  /// @param LB         The lower bound for the loop we parallelize.
+  /// @param UB         The upper bound for the loop we parallelize.
+  /// @param Stride     The stride of the loop we parallelize.
+  void createCallSpawnThreads(Value *SubFn, Value *SubFnParam, Value *LB,
+                              Value *UB, Value *Stride);
+
+  /// Create a runtime library call to join the worker threads.
+  void createCallJoinThreads();
+
+  /// Create a runtime library call to get the next work item.
+  ///
+  /// @param LBPtr A pointer value to store the work item begin in.
+  /// @param UBPtr A pointer value to store the work item end in.
+  ///
+  /// @returns A true value if the work item is not empty.
+  Value *createCallGetWorkItem(Value *LBPtr, Value *UBPtr);
+
+  /// Create a runtime library call to allow cleanup of the thread.
+  ///
+  /// @note This function is called right before the thread will exit the
+  ///       subfunction and only if the runtime system depends on it.
+  void createCallCleanupThread();
+
+  /// Create a struct for all @p Values and store them in there.
+  ///
+  /// @param Values The values which should be stored in the struct.
+  ///
+  /// @return The created struct.
+  AllocaInst *storeValuesIntoStruct(SetVector<Value *> &Values);
+
+  /// Extract all values from the @p Struct and construct the mapping.
+  ///
+  /// @param Values The values which were stored in the struct.
+  /// @param Struct The struct holding all the values in @p Values.
+  /// @param VMap   A map to associate every element of @p Values with the
+  ///               new llvm value loaded from the @p Struct.
+  void extractValuesFromStruct(SetVector<Value *> Values, Type *Ty,
+                               Value *Struct, ValueMapT &VMap);
+
+  /// Create the definition of the parallel subfunction.
+  Function *createSubFnDefinition();
+
+  /// Create the parallel subfunction.
+  ///
+  /// @param Stride The induction variable increment.
+  /// @param Struct A struct holding all values in @p Values.
+  /// @param Values A set of LLVM-IR Values that should be available in
+  ///               the new loop body.
+  /// @param VMap   A map to allow outside access to the new versions of
+  ///               the values in @p Values.
+  /// @param SubFn  The newly created subfunction is returned here.
+  ///
+  /// @return The newly created induction variable.
+  Value *createSubFn(Value *Stride, AllocaInst *Struct,
+                     SetVector<Value *> UsedValues, ValueMapT &VMap,
+                     Function **SubFn);
+};
+} // end namespace polly
+#endif
diff --git a/final/include/polly/CodeGen/PPCGCodeGeneration.h b/final/include/polly/CodeGen/PPCGCodeGeneration.h
new file mode 100644
index 0000000..9a9a143
--- /dev/null
+++ b/final/include/polly/CodeGen/PPCGCodeGeneration.h
@@ -0,0 +1,28 @@
+//===--- polly/PPCGCodeGeneration.h - Polly Accelerator Code Generation. --===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Take a scop created by ScopInfo and map it to GPU code using the ppcg
+// GPU mapping strategy.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_PPCGCODEGENERATION_H
+#define POLLY_PPCGCODEGENERATION_H
+
+/// The GPU Architecture to target.
+enum GPUArch { NVPTX64, SPIR32, SPIR64 };
+
+/// The GPU Runtime implementation to use.
+enum GPURuntime { CUDA, OpenCL };
+
+namespace polly {
+extern bool PollyManagedMemory;
+}
+
+#endif // POLLY_PPCGCODEGENERATION_H
diff --git a/final/include/polly/CodeGen/PerfMonitor.h b/final/include/polly/CodeGen/PerfMonitor.h
new file mode 100644
index 0000000..e6245cd
--- /dev/null
+++ b/final/include/polly/CodeGen/PerfMonitor.h
@@ -0,0 +1,155 @@
+//===--- PerfMonitor.h --- Monitor time spent in scops --------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef PERF_MONITOR_H
+#define PERF_MONITOR_H
+
+#include "polly/CodeGen/IRBuilder.h"
+
+namespace llvm {
+class Function;
+class Module;
+class Value;
+class Instruction;
+} // namespace llvm
+
+namespace polly {
+
+class PerfMonitor {
+public:
+  /// Create a new performance monitor.
+  ///
+  /// @param S The scop for which to generate fine-grained performance
+  ///          monitoring information.
+  /// @param M The module for which to generate the performance monitor.
+  PerfMonitor(const Scop &S, llvm::Module *M);
+
+  /// Initialize the performance monitor.
+  ///
+  /// Ensure that all global variables, functions, and callbacks needed to
+  /// manage the performance monitor are initialized and registered.
+  void initialize();
+
+  /// Mark the beginning of a timing region.
+  ///
+  /// @param InsertBefore The instruction before which the timing region starts.
+  void insertRegionStart(llvm::Instruction *InsertBefore);
+
+  /// Mark the end of a timing region.
+  ///
+  /// @param InsertBefore The instruction before which the timing region starts.
+  void insertRegionEnd(llvm::Instruction *InsertBefore);
+
+private:
+  llvm::Module *M;
+  PollyIRBuilder Builder;
+
+  // The scop to profile against.
+  const Scop &S;
+
+  /// Indicates if performance profiling is supported on this architecture.
+  bool Supported;
+
+  /// The cycle counter at the beginning of the program execution.
+  llvm::Value *CyclesTotalStartPtr;
+
+  /// The total number of cycles spent in the current scop S.
+  llvm::Value *CyclesInCurrentScopPtr;
+
+  /// The total number of times the current scop S is executed.
+  llvm::Value *TripCountForCurrentScopPtr;
+
+  /// The total number of cycles spent within scops.
+  llvm::Value *CyclesInScopsPtr;
+
+  /// The value of the cycle counter at the beginning of the last scop.
+  llvm::Value *CyclesInScopStartPtr;
+
+  /// A memory location which serves as argument of the RDTSCP function.
+  ///
+  /// The value written to this location is currently not used.
+  llvm::Value *RDTSCPWriteLocation;
+
+  /// A global variable, that keeps track if the performance monitor
+  /// initialization has already been run.
+  llvm::Value *AlreadyInitializedPtr;
+
+  llvm::Function *insertInitFunction(llvm::Function *FinalReporting);
+
+  /// Add Function @p to list of global constructors
+  ///
+  /// If no global constructors are available in this current module, insert
+  /// a new list of global constructors containing @p Fn as only global
+  /// constructor. Otherwise, append @p Fn to the list of global constructors.
+  ///
+  /// All functions listed as global constructors are executed before the
+  /// main() function is called.
+  ///
+  /// @param Fn Function to add to global constructors
+  void addToGlobalConstructors(llvm::Function *Fn);
+
+  /// Add global variables to module.
+  ///
+  /// Insert a set of global variables that are used to track performance,
+  /// into the module (or obtain references to them if they already exist).
+  void addGlobalVariables();
+
+  /// Add per-scop tracking to module.
+  ///
+  /// Insert the global variable which is used to track the number of cycles
+  /// this scop runs.
+  void addScopCounter();
+
+  /// Get a reference to the intrinsic "i64 @llvm.x86.rdtscp(i8*)".
+  ///
+  /// The rdtscp function returns the current value of the processor's
+  /// time-stamp counter as well as the current CPU identifier. On modern x86
+  /// systems, the returned value is independent of the dynamic clock frequency
+  /// and consistent across multiple cores. It can consequently be used to get
+  /// accurate and low-overhead timing information. Even though the counter is
+  /// wrapping, it can be reliably used even for measuring longer time
+  /// intervals, as on a 1 GHz processor the counter only wraps every 545 years.
+  ///
+  /// The RDTSCP instruction is "pseudo" serializing:
+  ///
+  /// "“The RDTSCP instruction waits until all previous instructions have been
+  /// executed before reading the counter. However, subsequent instructions may
+  /// begin execution before the read operation is performed.”
+  ///
+  /// To ensure that no later instructions are scheduled before the RDTSCP
+  /// instruction it is often recommended to schedule a cpuid call after the
+  /// RDTSCP instruction. We do not do this yet, trading some imprecision in
+  /// our timing for a reduced overhead in our timing.
+  ///
+  /// @returns A reference to the declaration of @llvm.x86.rdtscp.
+  llvm::Function *getRDTSCP();
+
+  /// Get a reference to "int atexit(void (*function)(void))" function.
+  ///
+  /// This function allows to register function pointers that must be executed
+  /// when the program is terminated.
+  ///
+  /// @returns A reference to @atexit().
+  llvm::Function *getAtExit();
+
+  /// Create function "__polly_perf_final_reporting".
+  ///
+  /// This function finalizes the performance measurements and prints the
+  /// results to stdout. It is expected to be registered with 'atexit()'.
+  llvm::Function *insertFinalReporting();
+
+  /// Append Scop reporting data to "__polly_perf_final_reporting".
+  ///
+  /// This function appends the current scop (S)'s information to the final
+  /// printing function.
+  void AppendScopReporting();
+};
+} // namespace polly
+
+#endif
diff --git a/final/include/polly/CodeGen/RuntimeDebugBuilder.h b/final/include/polly/CodeGen/RuntimeDebugBuilder.h
new file mode 100644
index 0000000..3a4e60d
--- /dev/null
+++ b/final/include/polly/CodeGen/RuntimeDebugBuilder.h
@@ -0,0 +1,154 @@
+//===--- RuntimeDebugBuilder.h --- Helper to insert prints into LLVM-IR ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef RUNTIME_DEBUG_BUILDER_H
+#define RUNTIME_DEBUG_BUILDER_H
+
+#include "polly/CodeGen/IRBuilder.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <vector>
+
+namespace llvm {
+class Value;
+class Function;
+} // namespace llvm
+
+namespace polly {
+
+/// Insert function calls that print certain LLVM values at run time.
+///
+/// This class inserts libc function calls to print certain LLVM values at
+/// run time.
+struct RuntimeDebugBuilder {
+
+  /// Print a set of LLVM-IR Values or StringRefs via printf
+  ///
+  ///  This function emits a call to printf that will print the given arguments.
+  ///  It is useful for debugging CPU programs. All arguments given in this list
+  ///  will be automatically concatenated and the resulting string will be
+  ///  printed atomically. We also support ArrayRef arguments, which can be used
+  ///  to provide of id values.
+  ///
+  ///  @param Builder The builder used to emit the printer calls.
+  ///  @param Args    The list of values to print.
+  template <typename... Args>
+  static void createCPUPrinter(PollyIRBuilder &Builder, Args... args) {
+    std::vector<llvm::Value *> Vector;
+    createPrinter(Builder, /* CPU */ false, Vector, args...);
+  }
+
+  /// Print a set of LLVM-IR Values or StringRefs on an NVIDIA GPU.
+  ///
+  ///  This function emits a call to vprintf that will print the given
+  ///  arguments from within a kernel thread. It is useful for debugging
+  ///  CUDA program kernels. All arguments given in this list will be
+  ///  automatically concatenated and the resulting string will be printed
+  ///  atomically. We also support ArrayRef arguments, which can be used to
+  ///  provide for example a list of thread-id values.
+  ///
+  ///  @param Builder The builder used to emit the printer calls.
+  ///  @param Args    The list of values to print.
+  template <typename... Args>
+  static void createGPUPrinter(PollyIRBuilder &Builder, Args... args) {
+    std::vector<llvm::Value *> Vector;
+    createPrinter(Builder, /* GPU */ true, Vector, args...);
+  }
+
+private:
+  /// Handle Values.
+  template <typename... Args>
+  static void createPrinter(PollyIRBuilder &Builder, bool UseGPU,
+                            std::vector<llvm::Value *> &Values,
+                            llvm::Value *Value, Args... args) {
+    Values.push_back(Value);
+    createPrinter(Builder, UseGPU, Values, args...);
+  }
+
+  /// Handle StringRefs.
+  template <typename... Args>
+  static void createPrinter(PollyIRBuilder &Builder, bool UseGPU,
+                            std::vector<llvm::Value *> &Values,
+                            llvm::StringRef String, Args... args) {
+    Values.push_back(Builder.CreateGlobalStringPtr(String, "", 4));
+    createPrinter(Builder, UseGPU, Values, args...);
+  }
+
+  /// Handle ArrayRefs.
+  template <typename... Args>
+  static void createPrinter(PollyIRBuilder &Builder, bool UseGPU,
+                            std::vector<llvm::Value *> &Values,
+                            llvm::ArrayRef<llvm::Value *> Array, Args... args) {
+    if (Array.size() >= 2)
+      createPrinter(Builder, Values, Array[0], " ",
+                    llvm::ArrayRef<llvm::Value *>(&Array[1], Array.size() - 1),
+                    args...);
+    else if (Array.size() == 1)
+      createPrinter(Builder, UseGPU, Values, Array[0], args...);
+    else
+      createPrinter(Builder, UseGPU, Values, args...);
+  }
+
+  /// Print a list of Values.
+  static void createPrinter(PollyIRBuilder &Builder, bool UseGPU,
+                            llvm::ArrayRef<llvm::Value *> Values);
+
+  /// Print a list of Values on a GPU.
+  static void createGPUPrinterT(PollyIRBuilder &Builder,
+                                llvm::ArrayRef<llvm::Value *> Values);
+
+  /// Print a list of Values on a CPU.
+  static void createCPUPrinterT(PollyIRBuilder &Builder,
+                                llvm::ArrayRef<llvm::Value *> Values);
+
+  /// Get a reference to the 'printf' function.
+  ///
+  /// If the current module does not yet contain a reference to printf, we
+  /// insert a reference to it. Otherwise the existing reference is returned.
+  static llvm::Function *getPrintF(PollyIRBuilder &Builder);
+
+  /// Call printf
+  ///
+  /// @param Builder The builder used to insert the code.
+  /// @param Format  The format string.
+  /// @param Values  The set of values to print.
+  static void createPrintF(PollyIRBuilder &Builder, std::string Format,
+                           llvm::ArrayRef<llvm::Value *> Values);
+
+  /// Get (and possibly insert) a vprintf declaration into the module.
+  static llvm::Function *getVPrintF(PollyIRBuilder &Builder);
+
+  /// Call fflush
+  ///
+  /// @parma Builder The builder used to insert the code.
+  static void createFlush(PollyIRBuilder &Builder);
+
+  /// Get (and possibly insert) a NVIDIA address space cast call.
+  static llvm::Function *getAddressSpaceCast(PollyIRBuilder &Builder,
+                                             unsigned Src, unsigned Dst,
+                                             unsigned SrcBits = 8,
+                                             unsigned DstBits = 8);
+
+  /// Get identifiers that describe the currently executed GPU thread.
+  ///
+  /// The result will be a vector that if passed to the GPU printer will result
+  /// into a string (initialized to values corresponding to the printing
+  /// thread):
+  ///
+  ///   "> block-id: bidx bid1y bidz | thread-id: tidx tidy tidz "
+  static std::vector<llvm::Value *>
+  getGPUThreadIdentifiers(PollyIRBuilder &Builder);
+};
+} // namespace polly
+
+extern bool PollyDebugPrinting;
+
+#endif
diff --git a/final/include/polly/CodeGen/Utils.h b/final/include/polly/CodeGen/Utils.h
new file mode 100644
index 0000000..9bce03d
--- /dev/null
+++ b/final/include/polly/CodeGen/Utils.h
@@ -0,0 +1,74 @@
+//===- Utils.h - Utility functions for code generation ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains utility functions for the code generation.
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_CODEGEN_UTILS_H
+#define POLLY_CODEGEN_UTILS_H
+
+#include <utility>
+
+namespace llvm {
+class Pass;
+class Value;
+class BasicBlock;
+class DominatorTree;
+class RegionInfo;
+class LoopInfo;
+class BranchInst;
+} // namespace llvm
+
+namespace polly {
+
+class Scop;
+
+using BBPair = std::pair<llvm::BasicBlock *, llvm::BasicBlock *>;
+/// Execute a Scop conditionally wrt @p RTC.
+///
+/// In the CFG the optimized code of the Scop is generated next to the
+/// original code. Both the new and the original version of the code remain
+/// in the CFG. A branch statement decides which version is executed based on
+/// the runtime value of @p RTC.
+///
+/// Before transformation:
+///
+///                        bb0
+///                         |
+///                     orig_scop
+///                         |
+///                        bb1
+///
+/// After transformation:
+///                        bb0
+///                         |
+///                  polly.splitBlock
+///                     /       \.
+///                     |     startBlock
+///                     |        |
+///               orig_scop   new_scop
+///                     \      /
+///                      \    /
+///                        bb1 (joinBlock)
+///
+/// @param S   The Scop to execute conditionally.
+/// @param P   A reference to the pass calling this function.
+/// @param RTC The runtime condition checked before executing the new SCoP.
+///
+/// @return  An std::pair:
+///              - The first element is a BBPair of (StartBlock, EndBlock).
+///              - The second element is the BranchInst which conditionally
+///                branches to the SCoP based on the RTC.
+///
+std::pair<BBPair, llvm::BranchInst *>
+executeScopConditionally(Scop &S, llvm::Value *RTC, llvm::DominatorTree &DT,
+                         llvm::RegionInfo &RI, llvm::LoopInfo &LI);
+
+} // namespace polly
+#endif
diff --git a/final/include/polly/CodePreparation.h b/final/include/polly/CodePreparation.h
new file mode 100644
index 0000000..326465f
--- /dev/null
+++ b/final/include/polly/CodePreparation.h
@@ -0,0 +1,26 @@
+//===- polly/ScopPreparation.h - Code preparation pass ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Prepare the Function for polyhedral codegeneration.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_CODEPREPARATION_H
+#define POLLY_CODEPREPARATION_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace polly {
+struct CodePreparationPass : public llvm::PassInfoMixin<CodePreparationPass> {
+  llvm::PreservedAnalyses run(llvm::Function &F,
+                              llvm::FunctionAnalysisManager &FAM);
+};
+} // namespace polly
+
+#endif /* POLLY_CODEPREPARATION_H */
diff --git a/final/include/polly/Config/config.h.cmake b/final/include/polly/Config/config.h.cmake
new file mode 100644
index 0000000..728eedd
--- /dev/null
+++ b/final/include/polly/Config/config.h.cmake
@@ -0,0 +1,19 @@
+//===- polly/Config.h ------------ Configuration of Polly -------*- C++ -*-===//
+//
+//                      The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Configuration of Polly.
+//
+//===----------------------------------------------------------------------===//
+#ifndef POLLY_CONFIG_H
+#define POLLY_CONFIG_H
+
+#cmakedefine CUDA_FOUND
+#cmakedefine GPU_CODEGEN
+
+#endif
diff --git a/final/include/polly/DeLICM.h b/final/include/polly/DeLICM.h
new file mode 100644
index 0000000..8aeefb6
--- /dev/null
+++ b/final/include/polly/DeLICM.h
@@ -0,0 +1,48 @@
+//===------ DeLICM.h --------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Undo the effect of Loop Invariant Code Motion (LICM) and
+// GVN Partial Redundancy Elimination (PRE) on SCoP-level.
+//
+// Namely, remove register/scalar dependencies by mapping them back to array
+// elements.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_DELICM_H
+#define POLLY_DELICM_H
+
+#include "polly/Support/GICHelper.h"
+
+namespace llvm {
+class PassRegistry;
+class Pass;
+} // namespace llvm
+
+namespace polly {
+/// Create a new DeLICM pass instance.
+llvm::Pass *createDeLICMPass();
+
+/// Determine whether two lifetimes are conflicting.
+///
+/// Used by unittesting.
+bool isConflicting(isl::union_set ExistingOccupied,
+                   isl::union_set ExistingUnused, isl::union_map ExistingKnown,
+                   isl::union_map ExistingWrites,
+                   isl::union_set ProposedOccupied,
+                   isl::union_set ProposedUnused, isl::union_map ProposedKnown,
+                   isl::union_map ProposedWrites,
+                   llvm::raw_ostream *OS = nullptr, unsigned Indent = 0);
+} // namespace polly
+
+namespace llvm {
+void initializeDeLICMPass(llvm::PassRegistry &);
+} // namespace llvm
+
+#endif /* POLLY_DELICM_H */
diff --git a/final/include/polly/DependenceInfo.h b/final/include/polly/DependenceInfo.h
new file mode 100644
index 0000000..89c3205
--- /dev/null
+++ b/final/include/polly/DependenceInfo.h
@@ -0,0 +1,322 @@
+//===--- polly/DependenceInfo.h - Polyhedral dependency analysis *- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Calculate the data dependency relations for a Scop using ISL.
+//
+// The integer set library (ISL) from Sven has an integrated dependency analysis
+// to calculate data dependences. This pass takes advantage of this and
+// calculates those dependences of a Scop.
+//
+// The dependences in this pass are exact in terms that for a specific read
+// statement instance only the last write statement instance is returned. In
+// case of may-writes, a set of possible write instances is returned. This
+// analysis will never produce redundant dependences.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_DEPENDENCE_INFO_H
+#define POLLY_DEPENDENCE_INFO_H
+
+#include "polly/ScopPass.h"
+#include "isl/ctx.h"
+
+struct isl_pw_aff;
+struct isl_union_map;
+struct isl_union_set;
+struct isl_map;
+struct isl_set;
+struct clast_for;
+
+using namespace llvm;
+
+namespace polly {
+
+class Scop;
+class ScopStmt;
+class MemoryAccess;
+
+/// The accumulated dependence information for a SCoP.
+///
+/// The Dependences struct holds all dependence information we collect and
+/// compute for one SCoP. It also offers an interface that allows users to
+/// query only specific parts.
+struct Dependences {
+  // Granularities of the current dependence analysis
+  enum AnalysisLevel {
+    AL_Statement = 0,
+    // Distinguish accessed memory references in the same statement
+    AL_Reference,
+    // Distinguish memory access instances in the same statement
+    AL_Access,
+
+    NumAnalysisLevels
+  };
+
+  /// Map type for reduction dependences.
+  using ReductionDependencesMapTy = DenseMap<MemoryAccess *, isl_map *>;
+
+  /// Map type to associate statements with schedules.
+  using StatementToIslMapTy = DenseMap<ScopStmt *, isl_map *>;
+
+  /// The type of the dependences.
+  ///
+  /// Reduction dependences are separated from RAW/WAW/WAR dependences because
+  /// we can ignore them during the scheduling. That's because the order
+  /// in which the reduction statements are executed does not matter. However,
+  /// if they are executed in parallel we need to take additional measures
+  /// (e.g, privatization) to ensure a correct result. The (reverse) transitive
+  /// closure of the reduction dependences are used to check for parallel
+  /// executed reduction statements during code generation. These dependences
+  /// connect all instances of a reduction with each other, they are therefore
+  /// cyclic and possibly "reversed".
+  enum Type {
+    // Write after read
+    TYPE_WAR = 1 << 0,
+
+    // Read after write
+    TYPE_RAW = 1 << 1,
+
+    // Write after write
+    TYPE_WAW = 1 << 2,
+
+    // Reduction dependences
+    TYPE_RED = 1 << 3,
+
+    // Transitive closure of the reduction dependences (& the reverse)
+    TYPE_TC_RED = 1 << 4,
+  };
+
+  const std::shared_ptr<isl_ctx> &getSharedIslCtx() const { return IslCtx; }
+
+  /// Get the dependences of type @p Kinds.
+  ///
+  /// @param Kinds This integer defines the different kinds of dependences
+  ///              that will be returned. To return more than one kind, the
+  ///              different kinds are 'ored' together.
+  __isl_give isl_union_map *getDependences(int Kinds) const;
+
+  /// Report if valid dependences are available.
+  bool hasValidDependences() const;
+
+  /// Return the reduction dependences caused by @p MA.
+  ///
+  /// @return The reduction dependences caused by @p MA or nullptr if none.
+  __isl_give isl_map *getReductionDependences(MemoryAccess *MA) const;
+
+  /// Return all reduction dependences.
+  const ReductionDependencesMapTy &getReductionDependences() const {
+    return ReductionDependences;
+  }
+
+  /// Check if a partial schedule is parallel wrt to @p Deps.
+  ///
+  /// @param Schedule       The subset of the schedule space that we want to
+  ///                       check.
+  /// @param Deps           The dependences @p Schedule needs to respect.
+  /// @param MinDistancePtr If not nullptr, the minimal dependence distance will
+  ///                       be returned at the address of that pointer
+  ///
+  /// @return Returns true, if executing parallel the outermost dimension of
+  ///         @p Schedule is valid according to the dependences @p Deps.
+  bool isParallel(__isl_keep isl_union_map *Schedule,
+                  __isl_take isl_union_map *Deps,
+                  __isl_give isl_pw_aff **MinDistancePtr = nullptr) const;
+
+  /// Check if a new schedule is valid.
+  ///
+  /// @param S             The current SCoP.
+  /// @param NewSchedules  The new schedules
+  ///
+  /// @return True if the new schedule is valid, false if it reverses
+  ///         dependences.
+  bool isValidSchedule(Scop &S, StatementToIslMapTy *NewSchedules) const;
+
+  /// Print the stored dependence information.
+  void print(llvm::raw_ostream &OS) const;
+
+  /// Dump the dependence information stored to the dbgs stream.
+  void dump() const;
+
+  /// Return the granularity of this dependence analysis.
+  AnalysisLevel getDependenceLevel() { return Level; }
+
+  /// Allow the DependenceInfo access to private members and methods.
+  ///
+  /// To restrict access to the internal state, only the DependenceInfo class
+  /// is able to call or modify a Dependences struct.
+  friend struct DependenceAnalysis;
+  friend struct DependenceInfoPrinterPass;
+  friend class DependenceInfo;
+  friend class DependenceInfoWrapperPass;
+
+  /// Destructor that will free internal objects.
+  ~Dependences() { releaseMemory(); }
+
+private:
+  /// Create an empty dependences struct.
+  explicit Dependences(const std::shared_ptr<isl_ctx> &IslCtx,
+                       AnalysisLevel Level)
+      : RAW(nullptr), WAR(nullptr), WAW(nullptr), RED(nullptr), TC_RED(nullptr),
+        IslCtx(IslCtx), Level(Level) {}
+
+  /// Calculate and add at the privatization dependences.
+  void addPrivatizationDependences();
+
+  /// Calculate the dependences for a certain SCoP @p S.
+  void calculateDependences(Scop &S);
+
+  /// Set the reduction dependences for @p MA to @p Deps.
+  void setReductionDependences(MemoryAccess *MA, __isl_take isl_map *Deps);
+
+  /// Free the objects associated with this Dependences struct.
+  ///
+  /// The Dependences struct will again be "empty" afterwards.
+  void releaseMemory();
+
+  /// The different basic kinds of dependences we calculate.
+  isl_union_map *RAW;
+  isl_union_map *WAR;
+  isl_union_map *WAW;
+
+  /// The special reduction dependences.
+  isl_union_map *RED;
+
+  /// The (reverse) transitive closure of reduction dependences.
+  isl_union_map *TC_RED;
+
+  /// Mapping from memory accesses to their reduction dependences.
+  ReductionDependencesMapTy ReductionDependences;
+
+  /// Isl context from the SCoP.
+  std::shared_ptr<isl_ctx> IslCtx;
+
+  /// Granularity of this dependence analysis.
+  const AnalysisLevel Level;
+};
+
+struct DependenceAnalysis : public AnalysisInfoMixin<DependenceAnalysis> {
+  static AnalysisKey Key;
+  struct Result {
+    Scop &S;
+    std::unique_ptr<Dependences> D[Dependences::NumAnalysisLevels];
+
+    /// Return the dependence information for the current SCoP.
+    ///
+    /// @param Level The granularity of dependence analysis result.
+    ///
+    /// @return The dependence analysis result
+    ///
+    const Dependences &getDependences(Dependences::AnalysisLevel Level);
+
+    /// Recompute dependences from schedule and memory accesses.
+    const Dependences &recomputeDependences(Dependences::AnalysisLevel Level);
+  };
+  Result run(Scop &S, ScopAnalysisManager &SAM,
+             ScopStandardAnalysisResults &SAR);
+};
+
+struct DependenceInfoPrinterPass
+    : public PassInfoMixin<DependenceInfoPrinterPass> {
+  DependenceInfoPrinterPass(raw_ostream &OS) : OS(OS) {}
+
+  PreservedAnalyses run(Scop &S, ScopAnalysisManager &,
+                        ScopStandardAnalysisResults &, SPMUpdater &);
+
+  raw_ostream &OS;
+};
+
+class DependenceInfo : public ScopPass {
+public:
+  static char ID;
+
+  /// Construct a new DependenceInfo pass.
+  DependenceInfo() : ScopPass(ID) {}
+
+  /// Return the dependence information for the current SCoP.
+  ///
+  /// @param Level The granularity of dependence analysis result.
+  ///
+  /// @return The dependence analysis result
+  ///
+  const Dependences &getDependences(Dependences::AnalysisLevel Level);
+
+  /// Recompute dependences from schedule and memory accesses.
+  const Dependences &recomputeDependences(Dependences::AnalysisLevel Level);
+
+  /// Compute the dependence information for the SCoP @p S.
+  bool runOnScop(Scop &S) override;
+
+  /// Print the dependences for the given SCoP to @p OS.
+  void printScop(raw_ostream &OS, Scop &) const override;
+
+  /// Release the internal memory.
+  void releaseMemory() override {
+    for (auto &d : D)
+      d.reset();
+  }
+
+  /// Register all analyses and transformation required.
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  Scop *S;
+
+  /// Dependences struct for the current SCoP.
+  std::unique_ptr<Dependences> D[Dependences::NumAnalysisLevels];
+};
+
+/// Construct a new DependenceInfoWrapper pass.
+class DependenceInfoWrapperPass : public FunctionPass {
+public:
+  static char ID;
+
+  /// Construct a new DependenceInfoWrapper pass.
+  DependenceInfoWrapperPass() : FunctionPass(ID) {}
+
+  /// Return the dependence information for the given SCoP.
+  ///
+  /// @param S     SCoP object.
+  /// @param Level The granularity of dependence analysis result.
+  ///
+  /// @return The dependence analysis result
+  ///
+  const Dependences &getDependences(Scop *S, Dependences::AnalysisLevel Level);
+
+  /// Recompute dependences from schedule and memory accesses.
+  const Dependences &recomputeDependences(Scop *S,
+                                          Dependences::AnalysisLevel Level);
+
+  /// Compute the dependence information on-the-fly for the function.
+  bool runOnFunction(Function &F) override;
+
+  /// Print the dependences for the current function to @p OS.
+  void print(raw_ostream &OS, const Module *M = nullptr) const override;
+
+  /// Release the internal memory.
+  void releaseMemory() override { ScopToDepsMap.clear(); }
+
+  /// Register all analyses and transformation required.
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  using ScopToDepsMapTy = DenseMap<Scop *, std::unique_ptr<Dependences>>;
+
+  /// Scop to Dependence map for the current function.
+  ScopToDepsMapTy ScopToDepsMap;
+};
+
+} // namespace polly
+
+namespace llvm {
+class PassRegistry;
+void initializeDependenceInfoPass(llvm::PassRegistry &);
+void initializeDependenceInfoWrapperPassPass(llvm::PassRegistry &);
+} // namespace llvm
+
+#endif
diff --git a/final/include/polly/FlattenAlgo.h b/final/include/polly/FlattenAlgo.h
new file mode 100644
index 0000000..f5bc757
--- /dev/null
+++ b/final/include/polly/FlattenAlgo.h
@@ -0,0 +1,38 @@
+//===------ FlattenAlgo.h --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Main algorithm of the FlattenSchedulePass. This is a separate file to avoid
+// the unittest for this requiring linking against LLVM.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_FLATTENALGO_H
+#define POLLY_FLATTENALGO_H
+
+#include "polly/Support/GICHelper.h"
+
+namespace polly {
+/// Recursively flatten a schedule.
+///
+/// Reduce the number of scatter dimensions as much as possible without changing
+/// the relative order of instances in a schedule. Ideally, this results in a
+/// single scatter dimension, but it may not always be possible to combine
+/// dimensions, eg. if a dimension is unbounded. In worst case, the original
+/// schedule is returned.
+///
+/// Schedules with fewer dimensions may be easier to understand for humans, but
+/// it should make no difference to the computer.
+///
+/// @param Schedule The input schedule.
+///
+/// @return The flattened schedule.
+isl::union_map flattenSchedule(isl::union_map Schedule);
+} // namespace polly
+
+#endif /* POLLY_FLATTENALGO_H */
diff --git a/final/include/polly/FlattenSchedule.h b/final/include/polly/FlattenSchedule.h
new file mode 100644
index 0000000..0e30473
--- /dev/null
+++ b/final/include/polly/FlattenSchedule.h
@@ -0,0 +1,32 @@
+//===------ FlattenSchedule.h ----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Try to reduce the number of scatter dimension. Useful to make isl_union_map
+// schedules more understandable. This is only intended for debugging and
+// unittests, not for optimizations themselves.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_FLATTENSCHEDULE_H
+#define POLLY_FLATTENSCHEDULE_H
+
+namespace llvm {
+class PassRegistry;
+class Pass;
+} // namespace llvm
+
+namespace polly {
+llvm::Pass *createFlattenSchedulePass();
+} // namespace polly
+
+namespace llvm {
+void initializeFlattenSchedulePass(llvm::PassRegistry &);
+} // namespace llvm
+
+#endif /* POLLY_FLATTENSCHEDULE_H */
diff --git a/final/include/polly/ForwardOpTree.h b/final/include/polly/ForwardOpTree.h
new file mode 100644
index 0000000..b0c16ca
--- /dev/null
+++ b/final/include/polly/ForwardOpTree.h
@@ -0,0 +1,33 @@
+//===- ForwardOpTree.h ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Move instructions between statements.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_FORWARDOPTREE_H
+#define POLLY_FORWARDOPTREE_H
+
+namespace llvm {
+
+class PassRegistry;
+
+void initializeForwardOpTreePass(PassRegistry &);
+
+} // namespace llvm
+
+namespace polly {
+
+class ScopPass;
+
+ScopPass *createForwardOpTreePass();
+
+} // namespace polly
+
+#endif // POLLY_FORWARDOPTREE_H
diff --git a/final/include/polly/JSONExporter.h b/final/include/polly/JSONExporter.h
new file mode 100644
index 0000000..8252dd4
--- /dev/null
+++ b/final/include/polly/JSONExporter.h
@@ -0,0 +1,32 @@
+//===- polly/JSONExporter.h - Import/Export to/from jscop files.-*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_JSONEXPORTER_H
+#define POLLY_JSONEXPORTER_H
+
+#include "polly/ScopPass.h"
+#include "llvm/IR/PassManager.h"
+
+namespace polly {
+/// This pass exports a scop to a jscop file. The filename is generated from the
+/// concatenation of the function and scop name.
+struct JSONExportPass : public llvm::PassInfoMixin<JSONExportPass> {
+  llvm::PreservedAnalyses run(Scop &, ScopAnalysisManager &,
+                              ScopStandardAnalysisResults &, SPMUpdater &);
+};
+
+/// This pass imports a scop from a jscop file. The filename is deduced from the
+/// concatenation of the function and scop name.
+struct JSONImportPass : public llvm::PassInfoMixin<JSONExportPass> {
+  llvm::PreservedAnalyses run(Scop &, ScopAnalysisManager &,
+                              ScopStandardAnalysisResults &, SPMUpdater &);
+};
+} // namespace polly
+
+#endif /* POLLY_JSONEXPORTER_H */
diff --git a/final/include/polly/LinkAllPasses.h b/final/include/polly/LinkAllPasses.h
new file mode 100644
index 0000000..56a7330
--- /dev/null
+++ b/final/include/polly/LinkAllPasses.h
@@ -0,0 +1,130 @@
+//===- polly/LinkAllPasses.h ----------- Reference All Passes ---*- C++ -*-===//
+//
+//                      The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header file pulls in all transformation and analysis passes for tools
+// like opt and bugpoint that need this functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_LINKALLPASSES_H
+#define POLLY_LINKALLPASSES_H
+
+#include "polly/CodeGen/PPCGCodeGeneration.h"
+#include "polly/Config/config.h"
+#include "polly/PruneUnprofitable.h"
+#include "polly/Simplify.h"
+#include "polly/Support/DumpModulePass.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstdlib>
+
+namespace llvm {
+class Pass;
+class PassInfo;
+class PassRegistry;
+class RegionPass;
+} // namespace llvm
+
+namespace polly {
+llvm::Pass *createCodePreparationPass();
+llvm::Pass *createScopInlinerPass();
+llvm::Pass *createDeadCodeElimPass();
+llvm::Pass *createDependenceInfoPass();
+llvm::Pass *createDependenceInfoWrapperPassPass();
+llvm::Pass *createDOTOnlyPrinterPass();
+llvm::Pass *createDOTOnlyViewerPass();
+llvm::Pass *createDOTPrinterPass();
+llvm::Pass *createDOTViewerPass();
+llvm::Pass *createJSONExporterPass();
+llvm::Pass *createJSONImporterPass();
+llvm::Pass *createPollyCanonicalizePass();
+llvm::Pass *createPolyhedralInfoPass();
+llvm::Pass *createScopDetectionWrapperPassPass();
+llvm::Pass *createScopInfoRegionPassPass();
+llvm::Pass *createScopInfoWrapperPassPass();
+llvm::Pass *createRewriteByrefParamsPass();
+llvm::Pass *createIslAstInfoWrapperPassPass();
+llvm::Pass *createCodeGenerationPass();
+#ifdef GPU_CODEGEN
+llvm::Pass *createPPCGCodeGenerationPass(GPUArch Arch = GPUArch::NVPTX64,
+                                         GPURuntime Runtime = GPURuntime::CUDA);
+
+llvm::Pass *
+createManagedMemoryRewritePassPass(GPUArch Arch = GPUArch::NVPTX64,
+                                   GPURuntime Runtime = GPURuntime::CUDA);
+#endif
+llvm::Pass *createIslScheduleOptimizerPass();
+llvm::Pass *createFlattenSchedulePass();
+llvm::Pass *createDeLICMPass();
+llvm::Pass *createMaximalStaticExpansionPass();
+
+extern char &CodePreparationID;
+} // namespace polly
+
+namespace {
+struct PollyForcePassLinking {
+  PollyForcePassLinking() {
+    // We must reference the passes in such a way that compilers will not
+    // delete it all as dead code, even with whole program optimization,
+    // yet is effectively a NO-OP. As the compiler isn't smart enough
+    // to know that getenv() never returns -1, this will do the job.
+    if (std::getenv("bar") != (char *)-1)
+      return;
+
+    polly::createCodePreparationPass();
+    polly::createDeadCodeElimPass();
+    polly::createDependenceInfoPass();
+    polly::createDOTOnlyPrinterPass();
+    polly::createDOTOnlyViewerPass();
+    polly::createDOTPrinterPass();
+    polly::createDOTViewerPass();
+    polly::createJSONExporterPass();
+    polly::createJSONImporterPass();
+    polly::createScopDetectionWrapperPassPass();
+    polly::createScopInfoRegionPassPass();
+    polly::createPollyCanonicalizePass();
+    polly::createPolyhedralInfoPass();
+    polly::createIslAstInfoWrapperPassPass();
+    polly::createCodeGenerationPass();
+#ifdef GPU_CODEGEN
+    polly::createPPCGCodeGenerationPass();
+    polly::createManagedMemoryRewritePassPass();
+#endif
+    polly::createIslScheduleOptimizerPass();
+    polly::createMaximalStaticExpansionPass();
+    polly::createFlattenSchedulePass();
+    polly::createDeLICMPass();
+    polly::createDumpModulePass("", true);
+    polly::createSimplifyPass();
+    polly::createPruneUnprofitablePass();
+  }
+} PollyForcePassLinking; // Force link by creating a global definition.
+} // namespace
+
+namespace llvm {
+class PassRegistry;
+void initializeCodePreparationPass(llvm::PassRegistry &);
+void initializeScopInlinerPass(llvm::PassRegistry &);
+void initializeDeadCodeElimPass(llvm::PassRegistry &);
+void initializeJSONExporterPass(llvm::PassRegistry &);
+void initializeJSONImporterPass(llvm::PassRegistry &);
+void initializeIslAstInfoWrapperPassPass(llvm::PassRegistry &);
+void initializeCodeGenerationPass(llvm::PassRegistry &);
+void initializeRewriteByrefParamsPass(llvm::PassRegistry &);
+#ifdef GPU_CODEGEN
+void initializePPCGCodeGenerationPass(llvm::PassRegistry &);
+void initializeManagedMemoryRewritePassPass(llvm::PassRegistry &);
+#endif
+void initializeIslScheduleOptimizerPass(llvm::PassRegistry &);
+void initializeMaximalStaticExpanderPass(llvm::PassRegistry &);
+void initializePollyCanonicalizePass(llvm::PassRegistry &);
+void initializeFlattenSchedulePass(llvm::PassRegistry &);
+void initializeDeLICMPass(llvm::PassRegistry &);
+} // namespace llvm
+
+#endif
diff --git a/final/include/polly/Options.h b/final/include/polly/Options.h
new file mode 100644
index 0000000..62e0960
--- /dev/null
+++ b/final/include/polly/Options.h
@@ -0,0 +1,20 @@
+//===--------------- polly/Options.h - The Polly option category *- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Introduce an option category for Polly.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_OPTIONS_H
+#define POLLY_OPTIONS_H
+
+#include "llvm/Support/CommandLine.h"
+
+extern llvm::cl::OptionCategory PollyCategory;
+#endif
diff --git a/final/include/polly/PolyhedralInfo.h b/final/include/polly/PolyhedralInfo.h
new file mode 100644
index 0000000..54d5de9
--- /dev/null
+++ b/final/include/polly/PolyhedralInfo.h
@@ -0,0 +1,102 @@
+//===- polly/PolyhedralInfo.h - PolyhedralInfo class definition -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file contains the declaration of the PolyhedralInfo class, which will
+/// provide an interface to expose polyhedral analysis information of Polly.
+///
+/// This is work in progress. We will add more API's as and when deemed
+/// required.
+//===----------------------------------------------------------------------===///
+
+#ifndef POLLY_POLYHEDRAL_INFO_H
+#define POLLY_POLYHEDRAL_INFO_H
+
+#include "llvm/Pass.h"
+#include "isl/ctx.h"
+#include "isl/union_map.h"
+
+namespace llvm {
+class Loop;
+} // namespace llvm
+
+namespace polly {
+
+class Scop;
+class ScopInfo;
+class DependenceInfoWrapperPass;
+
+class PolyhedralInfo : public llvm::FunctionPass {
+public:
+  static char ID; // Pass identification, replacement for typeid
+
+  /// Construct a new PolyhedralInfo pass.
+  PolyhedralInfo() : FunctionPass(ID) {}
+  ~PolyhedralInfo() {}
+
+  /// Check if a given loop is parallel.
+  ///
+  /// @param L The loop.
+  ///
+  /// @return  Returns true, if loop is parallel false otherwise.
+  bool isParallel(llvm::Loop *L) const;
+
+  /// Return the SCoP containing the @p L loop.
+  ///
+  /// @param L The loop.
+  ///
+  /// @return  Returns the SCoP containing the given loop.
+  ///          Returns null if the loop is not contained in any SCoP.
+  const Scop *getScopContainingLoop(llvm::Loop *L) const;
+
+  /// Computes the partial schedule for the given @p L loop.
+  ///
+  /// @param S The SCoP containing the given loop
+  /// @param L The loop.
+  ///
+  /// @return  Returns the partial schedule for the given loop
+  __isl_give isl_union_map *getScheduleForLoop(const Scop *S,
+                                               llvm::Loop *L) const;
+
+  /// Get the SCoP and dependence analysis information for @p F.
+  bool runOnFunction(llvm::Function &F) override;
+
+  /// Release the internal memory.
+  void releaseMemory() override {}
+
+  /// Print to @p OS if each dimension of a loop nest is parallel or not.
+  void print(llvm::raw_ostream &OS,
+             const llvm::Module *M = nullptr) const override;
+
+  /// Register all analyses and transformation required.
+  void getAnalysisUsage(llvm::AnalysisUsage &AU) const override;
+
+private:
+  /// Check if a given loop is parallel or vectorizable.
+  ///
+  /// @param L             The loop.
+  /// @param MinDepDistPtr If not nullptr, the minimal dependence distance will
+  ///                      be returned at the address of that pointer
+  ///
+  /// @return  Returns true if loop is parallel or vectorizable, false
+  ///          otherwise.
+  bool checkParallel(llvm::Loop *L,
+                     __isl_give isl_pw_aff **MinDepDistPtr = nullptr) const;
+
+  ScopInfo *SI;
+  DependenceInfoWrapperPass *DI;
+};
+
+} // end namespace polly
+
+namespace llvm {
+class PassRegistry;
+void initializePolyhedralInfoPass(llvm::PassRegistry &);
+} // namespace llvm
+
+#endif
diff --git a/final/include/polly/PruneUnprofitable.h b/final/include/polly/PruneUnprofitable.h
new file mode 100644
index 0000000..e75220f
--- /dev/null
+++ b/final/include/polly/PruneUnprofitable.h
@@ -0,0 +1,32 @@
+//===- PruneUnprofitable.h --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Mark a SCoP as unfeasible if not deemed profitable to optimize.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_PRUNEUNPROFITABLE_H
+#define POLLY_PRUNEUNPROFITABLE_H
+
+namespace llvm {
+
+class Pass;
+class PassRegistry;
+
+void initializePruneUnprofitablePass(PassRegistry &);
+
+} // namespace llvm
+
+namespace polly {
+
+llvm::Pass *createPruneUnprofitablePass();
+
+} // namespace polly
+
+#endif // POLLY_PRUNEUNPROFITABLE_H
diff --git a/final/include/polly/RegisterPasses.h b/final/include/polly/RegisterPasses.h
new file mode 100644
index 0000000..dc2aa25
--- /dev/null
+++ b/final/include/polly/RegisterPasses.h
@@ -0,0 +1,29 @@
+//===------ polly/RegisterPasses.h - Register the Polly passes *- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Functions to register the Polly passes in a LLVM pass manager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_REGISTER_PASSES_H
+#define POLLY_REGISTER_PASSES_H
+
+#include "llvm/IR/LegacyPassManager.h"
+
+namespace llvm {
+namespace legacy {
+class PassManagerBase;
+} // namespace legacy
+} // namespace llvm
+
+namespace polly {
+void initializePollyPasses(llvm::PassRegistry &Registry);
+void registerPollyPasses(llvm::legacy::PassManagerBase &PM);
+} // namespace polly
+#endif
diff --git a/final/include/polly/ScheduleOptimizer.h b/final/include/polly/ScheduleOptimizer.h
new file mode 100644
index 0000000..079acf1
--- /dev/null
+++ b/final/include/polly/ScheduleOptimizer.h
@@ -0,0 +1,356 @@
+//===- polly/ScheduleOptimizer.h - The Schedule Optimizer -------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_SCHEDULEOPTIMIZER_H
+#define POLLY_SCHEDULEOPTIMIZER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "isl/isl-noexceptions.h"
+
+namespace llvm {
+
+class TargetTransformInfo;
+
+} // namespace llvm
+
+struct isl_schedule_node;
+
+/// Parameters of the micro kernel.
+///
+/// Parameters, which determine sizes of rank-1 (i.e., outer product) update
+/// used in the optimized matrix multiplication.
+struct MicroKernelParamsTy {
+  int Mr;
+  int Nr;
+};
+
+/// Parameters of the macro kernel.
+///
+/// Parameters, which determine sizes of blocks of partitioned matrices
+/// used in the optimized matrix multiplication.
+struct MacroKernelParamsTy {
+  int Mc;
+  int Nc;
+  int Kc;
+};
+
+namespace polly {
+
+struct Dependences;
+class MemoryAccess;
+class Scop;
+
+/// Additional parameters of the schedule optimizer.
+///
+/// Target Transform Info and the SCoP dependencies used by the schedule
+/// optimizer.
+struct OptimizerAdditionalInfoTy {
+  const llvm::TargetTransformInfo *TTI;
+  const Dependences *D;
+};
+
+/// Parameters of the matrix multiplication operands.
+///
+/// Parameters, which describe access relations that represent operands of the
+/// matrix multiplication.
+struct MatMulInfoTy {
+  MemoryAccess *A = nullptr;
+  MemoryAccess *B = nullptr;
+  MemoryAccess *ReadFromC = nullptr;
+  MemoryAccess *WriteToC = nullptr;
+  int i = -1;
+  int j = -1;
+  int k = -1;
+};
+
+extern bool DisablePollyTiling;
+
+} // namespace polly
+
+class ScheduleTreeOptimizer {
+public:
+  /// Apply schedule tree transformations.
+  ///
+  /// This function takes an (possibly already optimized) schedule tree and
+  /// applies a set of additional optimizations on the schedule tree. The
+  /// transformations applied include:
+  ///
+  ///   - Tiling
+  ///   - Prevectorization
+  ///
+  /// @param Schedule The schedule object the transformations will be applied
+  ///                 to.
+  /// @param OAI      Target Transform Info and the SCoP dependencies.
+  /// @returns        The transformed schedule.
+  static isl::schedule
+  optimizeSchedule(isl::schedule Schedule,
+                   const polly::OptimizerAdditionalInfoTy *OAI = nullptr);
+
+  /// Apply schedule tree transformations.
+  ///
+  /// This function takes a node in an (possibly already optimized) schedule
+  /// tree and applies a set of additional optimizations on this schedule tree
+  /// node and its descendants. The transformations applied include:
+  ///
+  ///   - Tiling
+  ///   - Prevectorization
+  ///
+  /// @param Node The schedule object post-transformations will be applied to.
+  /// @param OAI  Target Transform Info and the SCoP dependencies.
+  /// @returns    The transformed schedule.
+  static isl::schedule_node
+  optimizeScheduleNode(isl::schedule_node Node,
+                       const polly::OptimizerAdditionalInfoTy *OAI = nullptr);
+
+  /// Decide if the @p NewSchedule is profitable for @p S.
+  ///
+  /// @param S           The SCoP we optimize.
+  /// @param NewSchedule The new schedule we computed.
+  ///
+  /// @return True, if we believe @p NewSchedule is an improvement for @p S.
+  static bool isProfitableSchedule(polly::Scop &S, isl::schedule NewSchedule);
+
+  /// Isolate a set of partial tile prefixes.
+  ///
+  /// This set should ensure that it contains only partial tile prefixes that
+  /// have exactly VectorWidth iterations.
+  ///
+  /// @param Node A schedule node band, which is a parent of a band node,
+  ///             that contains a vector loop.
+  /// @return Modified isl_schedule_node.
+  static isl::schedule_node isolateFullPartialTiles(isl::schedule_node Node,
+                                                    int VectorWidth);
+
+private:
+  /// Tile a schedule node.
+  ///
+  /// @param Node            The node to tile.
+  /// @param Identifier      An name that identifies this kind of tiling and
+  ///                        that is used to mark the tiled loops in the
+  ///                        generated AST.
+  /// @param TileSizes       A vector of tile sizes that should be used for
+  ///                        tiling.
+  /// @param DefaultTileSize A default tile size that is used for dimensions
+  ///                        that are not covered by the TileSizes vector.
+  static isl::schedule_node tileNode(isl::schedule_node Node,
+                                     const char *Identifier,
+                                     llvm::ArrayRef<int> TileSizes,
+                                     int DefaultTileSize);
+
+  /// Tile a schedule node and unroll point loops.
+  ///
+  /// @param Node            The node to register tile.
+  /// @param TileSizes       A vector of tile sizes that should be used for
+  ///                        tiling.
+  /// @param DefaultTileSize A default tile size that is used for dimensions
+  static isl::schedule_node applyRegisterTiling(isl::schedule_node Node,
+                                                llvm::ArrayRef<int> TileSizes,
+                                                int DefaultTileSize);
+
+  /// Apply the BLIS matmul optimization pattern.
+  ///
+  /// Make the loops containing the matrix multiplication be the innermost
+  /// loops and apply the BLIS matmul optimization pattern. BLIS implements
+  /// gemm as three nested loops around a macro-kernel, plus two packing
+  /// routines. The macro-kernel is implemented in terms of two additional
+  /// loops around a micro-kernel. The micro-kernel is a loop around a rank-1
+  /// (i.e., outer product) update.
+  ///
+  /// For a detailed description please see [1].
+  ///
+  /// The order of the loops defines the data reused in the BLIS implementation
+  /// of gemm ([1]). In particular, elements of the matrix B, the second
+  /// operand of matrix multiplication, are reused between iterations of the
+  /// innermost loop. To keep the reused data in cache, only elements of matrix
+  /// A, the first operand of matrix multiplication, should be evicted during
+  /// an iteration of the innermost loop. To provide such a cache replacement
+  /// policy, elements of the matrix A can, in particular, be loaded first and,
+  /// consequently, be least-recently-used.
+  ///
+  /// In our case matrices are stored in row-major order instead of
+  /// column-major order used in the BLIS implementation ([1]). It affects only
+  /// on the form of the BLIS micro kernel and the computation of its
+  /// parameters. In particular, reused elements of the matrix B are
+  /// successively multiplied by specific elements of the matrix A.
+  ///
+  /// Refs.:
+  /// [1] - Analytical Modeling is Enough for High Performance BLIS
+  /// Tze Meng Low, Francisco D Igual, Tyler M Smith, Enrique S Quintana-Orti
+  /// Technical Report, 2014
+  /// http://www.cs.utexas.edu/users/flame/pubs/TOMS-BLIS-Analytical.pdf
+  ///
+  /// @see ScheduleTreeOptimizer::createMicroKernel
+  /// @see ScheduleTreeOptimizer::createMacroKernel
+  /// @see getMicroKernelParams
+  /// @see getMacroKernelParams
+  ///
+  /// TODO: Implement the packing transformation.
+  ///
+  /// @param Node The node that contains a band to be optimized. The node
+  ///             is required to successfully pass
+  ///             ScheduleTreeOptimizer::isMatrMultPattern.
+  /// @param TTI  Target Transform Info.
+  /// @param MMI  Parameters of the matrix multiplication operands.
+  /// @returns    The transformed schedule.
+  static isl::schedule_node
+  optimizeMatMulPattern(isl::schedule_node Node,
+                        const llvm::TargetTransformInfo *TTI,
+                        polly::MatMulInfoTy &MMI);
+
+  /// Check if this node is a band node we want to tile.
+  ///
+  /// We look for innermost band nodes where individual dimensions are marked as
+  /// permutable.
+  ///
+  /// @param Node The node to check.
+  static bool isTileableBandNode(isl::schedule_node Node);
+
+  /// Pre-vectorizes one scheduling dimension of a schedule band.
+  ///
+  /// prevectSchedBand splits out the dimension DimToVectorize, tiles it and
+  /// sinks the resulting point loop.
+  ///
+  /// Example (DimToVectorize=0, VectorWidth=4):
+  ///
+  /// | Before transformation:
+  /// |
+  /// | A[i,j] -> [i,j]
+  /// |
+  /// | for (i = 0; i < 128; i++)
+  /// |    for (j = 0; j < 128; j++)
+  /// |      A(i,j);
+  ///
+  /// | After transformation:
+  /// |
+  /// | for (it = 0; it < 32; it+=1)
+  /// |    for (j = 0; j < 128; j++)
+  /// |      for (ip = 0; ip <= 3; ip++)
+  /// |        A(4 * it + ip,j);
+  ///
+  /// The goal of this transformation is to create a trivially vectorizable
+  /// loop.  This means a parallel loop at the innermost level that has a
+  /// constant number of iterations corresponding to the target vector width.
+  ///
+  /// This transformation creates a loop at the innermost level. The loop has
+  /// a constant number of iterations, if the number of loop iterations at
+  /// DimToVectorize can be divided by VectorWidth. The default VectorWidth is
+  /// currently constant and not yet target specific. This function does not
+  /// reason about parallelism.
+  static isl::schedule_node prevectSchedBand(isl::schedule_node Node,
+                                             unsigned DimToVectorize,
+                                             int VectorWidth);
+
+  /// Apply additional optimizations on the bands in the schedule tree.
+  ///
+  /// We are looking for an innermost band node and apply the following
+  /// transformations:
+  ///
+  ///  - Tile the band
+  ///      - if the band is tileable
+  ///      - if the band has more than one loop dimension
+  ///
+  ///  - Prevectorize the schedule of the band (or the point loop in case of
+  ///    tiling).
+  ///      - if vectorization is enabled
+  ///
+  /// @param Node The schedule node to (possibly) optimize.
+  /// @param User A pointer to forward some use information
+  ///        (currently unused).
+  static isl_schedule_node *optimizeBand(isl_schedule_node *Node, void *User);
+
+  /// Apply additional optimizations on the bands in the schedule tree.
+  ///
+  /// We apply the following
+  /// transformations:
+  ///
+  ///  - Tile the band
+  ///  - Prevectorize the schedule of the band (or the point loop in case of
+  ///    tiling).
+  ///      - if vectorization is enabled
+  ///
+  /// @param Node The schedule node to (possibly) optimize.
+  /// @param User A pointer to forward some use information
+  ///        (currently unused).
+  static isl::schedule_node standardBandOpts(isl::schedule_node Node,
+                                             void *User);
+
+  /// Check if this node contains a partial schedule that could
+  ///        probably be optimized with analytical modeling.
+  ///
+  /// isMatrMultPattern tries to determine whether the following conditions
+  /// are true:
+  /// 1. the partial schedule contains only one statement.
+  /// 2. there are exactly three input dimensions.
+  /// 3. all memory accesses of the statement will have stride 0 or 1, if we
+  ///    interchange loops (switch the variable used in the inner loop to
+  ///    the outer loop).
+  /// 4. all memory accesses of the statement except from the last one, are
+  ///    read memory access and the last one is write memory access.
+  /// 5. all subscripts of the last memory access of the statement don't
+  ///    contain the variable used in the inner loop.
+  /// If this is the case, we could try to use an approach that is similar to
+  /// the one used to get close-to-peak performance of matrix multiplications.
+  ///
+  /// @param Node The node to check.
+  /// @param D    The SCoP dependencies.
+  /// @param MMI  Parameters of the matrix multiplication operands.
+  static bool isMatrMultPattern(isl::schedule_node Node,
+                                const polly::Dependences *D,
+                                polly::MatMulInfoTy &MMI);
+
+  /// Create the BLIS macro-kernel.
+  ///
+  /// We create the BLIS macro-kernel by applying a combination of tiling
+  /// of dimensions of the band node and interchanging of two innermost
+  /// modified dimensions. The values of of MacroKernelParams's fields are used
+  /// as tile sizes.
+  ///
+  /// @param Node The schedule node to be modified.
+  /// @param MacroKernelParams Parameters of the macro kernel
+  ///                          to be used as tile sizes.
+  static isl::schedule_node
+  createMacroKernel(isl::schedule_node Node,
+                    MacroKernelParamsTy MacroKernelParams);
+
+  /// Create the BLIS macro-kernel.
+  ///
+  /// We create the BLIS macro-kernel by applying a combination of tiling
+  /// of dimensions of the band node and interchanging of two innermost
+  /// modified dimensions. The values passed in MicroKernelParam are used
+  /// as tile sizes.
+  ///
+  /// @param Node The schedule node to be modified.
+  /// @param MicroKernelParams Parameters of the micro kernel
+  ///                          to be used as tile sizes.
+  /// @see MicroKernelParamsTy
+  static isl::schedule_node
+  createMicroKernel(isl::schedule_node Node,
+                    MicroKernelParamsTy MicroKernelParams);
+};
+
+/// Build the desired set of partial tile prefixes.
+///
+/// We build a set of partial tile prefixes, which are prefixes of the vector
+/// loop that have exactly VectorWidth iterations.
+///
+/// 1. Drop all constraints involving the dimension that represents the
+///    vector loop.
+/// 2. Constrain the last dimension to get a set, which has exactly VectorWidth
+///    iterations.
+/// 3. Subtract loop domain from it, project out the vector loop dimension and
+///    get a set that contains prefixes, which do not have exactly VectorWidth
+///    iterations.
+/// 4. Project out the vector loop dimension of the set that was build on the
+///    first step and subtract the set built on the previous step to get the
+///    desired set of prefixes.
+///
+/// @param ScheduleRange A range of a map, which describes a prefix schedule
+///                      relation.
+isl::set getPartialTilePrefixes(isl::set ScheduleRange, int VectorWidth);
+#endif // POLLY_SCHEDULEOPTIMIZER_H
diff --git a/final/include/polly/ScopBuilder.h b/final/include/polly/ScopBuilder.h
new file mode 100644
index 0000000..e1e351c
--- /dev/null
+++ b/final/include/polly/ScopBuilder.h
@@ -0,0 +1,410 @@
+//===- polly/ScopBuilder.h --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Create a polyhedral description for a static control flow region.
+//
+// The pass creates a polyhedral description of the Scops detected by the SCoP
+// detection derived from their LLVM-IR code.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_SCOPBUILDER_H
+#define POLLY_SCOPBUILDER_H
+
+#include "polly/ScopInfo.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+namespace llvm {
+
+class AssumptionCache;
+class BasicBlock;
+class DataLayout;
+class DominatorTree;
+class Instruction;
+class LoopInfo;
+class PassRegistry;
+class PHINode;
+class Region;
+class ScalarEvolution;
+class SCEV;
+class Type;
+class Value;
+
+void initializeScopInfoRegionPassPass(PassRegistry &);
+void initializeScopInfoWrapperPassPass(PassRegistry &);
+
+} // end namespace llvm
+
+namespace polly {
+
+class ScopDetection;
+
+/// Command line switch whether to model read-only accesses.
+extern bool ModelReadOnlyScalars;
+
+/// Build the Polly IR (Scop and ScopStmt) on a Region.
+class ScopBuilder {
+  /// The AliasAnalysis to build AliasSetTracker.
+  AliasAnalysis &AA;
+
+  /// Target data for element size computing.
+  const DataLayout &DL;
+
+  /// DominatorTree to reason about guaranteed execution.
+  DominatorTree &DT;
+
+  /// LoopInfo for information about loops.
+  LoopInfo &LI;
+
+  /// Valid Regions for Scop
+  ScopDetection &SD;
+
+  /// The ScalarEvolution to help building Scop.
+  ScalarEvolution &SE;
+
+  /// Set of instructions that might read any memory location.
+  SmallVector<std::pair<ScopStmt *, Instruction *>, 16> GlobalReads;
+
+  /// Set of all accessed array base pointers.
+  SmallSetVector<Value *, 16> ArrayBasePointers;
+
+  // The Scop
+  std::unique_ptr<Scop> scop;
+
+  // Methods for pattern matching against Fortran code generated by dragonegg.
+  // @{
+
+  /// Try to match for the descriptor of a Fortran array whose allocation
+  /// is not visible. That is, we can see the load/store into the memory, but
+  /// we don't actually know where the memory is allocated. If ALLOCATE had been
+  /// called on the Fortran array, then we will see the lowered malloc() call.
+  /// If not, this is dubbed as an "invisible allocation".
+  ///
+  /// "<descriptor>" is the descriptor of the Fortran array.
+  ///
+  /// Pattern match for "@descriptor":
+  ///  1. %mem = load double*, double** bitcast (%"struct.array1_real(kind=8)"*
+  ///    <descriptor> to double**), align 32
+  ///
+  ///  2. [%slot = getelementptr inbounds i8, i8* %mem, i64 <index>]
+  ///  2 is optional because if you are writing to the 0th index, you don't
+  ///     need a GEP.
+  ///
+  ///  3.1 store/load <memtype> <val>, <memtype>* %slot
+  ///  3.2 store/load <memtype> <val>, <memtype>* %mem
+  ///
+  /// @see polly::MemoryAccess, polly::ScopArrayInfo
+  ///
+  /// @note assumes -polly-canonicalize has been run.
+  ///
+  /// @param Inst The LoadInst/StoreInst that accesses the memory.
+  ///
+  /// @returns Reference to <descriptor> on success, nullptr on failure.
+  Value *findFADAllocationInvisible(MemAccInst Inst);
+
+  /// Try to match for the descriptor of a Fortran array whose allocation
+  /// call is visible. When we have a Fortran array, we try to look for a
+  /// Fortran array where we can see the lowered ALLOCATE call. ALLOCATE
+  /// is materialized as a malloc(...) which we pattern match for.
+  ///
+  /// Pattern match for "%untypedmem":
+  ///  1. %untypedmem = i8* @malloc(...)
+  ///
+  ///  2. %typedmem = bitcast i8* %untypedmem to <memtype>
+  ///
+  ///  3. [%slot = getelementptr inbounds i8, i8* %typedmem, i64 <index>]
+  ///  3 is optional because if you are writing to the 0th index, you don't
+  ///     need a GEP.
+  ///
+  ///  4.1 store/load <memtype> <val>, <memtype>* %slot, align 8
+  ///  4.2 store/load <memtype> <val>, <memtype>* %mem, align 8
+  ///
+  /// @see polly::MemoryAccess, polly::ScopArrayInfo
+  ///
+  /// @note assumes -polly-canonicalize has been run.
+  ///
+  /// @param Inst The LoadInst/StoreInst that accesses the memory.
+  ///
+  /// @returns Reference to %untypedmem on success, nullptr on failure.
+  Value *findFADAllocationVisible(MemAccInst Inst);
+
+  // @}
+
+  // Build the SCoP for Region @p R.
+  void buildScop(Region &R, AssumptionCache &AC,
+                 OptimizationRemarkEmitter &ORE);
+
+  /// Try to build a multi-dimensional fixed sized MemoryAccess from the
+  /// Load/Store instruction.
+  ///
+  /// @param Inst       The Load/Store instruction that access the memory
+  /// @param Stmt       The parent statement of the instruction
+  ///
+  /// @returns True if the access could be built, False otherwise.
+  bool buildAccessMultiDimFixed(MemAccInst Inst, ScopStmt *Stmt);
+
+  /// Try to build a multi-dimensional parametric sized MemoryAccess.
+  ///        from the Load/Store instruction.
+  ///
+  /// @param Inst       The Load/Store instruction that access the memory
+  /// @param Stmt       The parent statement of the instruction
+  ///
+  /// @returns True if the access could be built, False otherwise.
+  bool buildAccessMultiDimParam(MemAccInst Inst, ScopStmt *Stmt);
+
+  /// Try to build a MemoryAccess for a memory intrinsic.
+  ///
+  /// @param Inst       The instruction that access the memory
+  /// @param Stmt       The parent statement of the instruction
+  ///
+  /// @returns True if the access could be built, False otherwise.
+  bool buildAccessMemIntrinsic(MemAccInst Inst, ScopStmt *Stmt);
+
+  /// Try to build a MemoryAccess for a call instruction.
+  ///
+  /// @param Inst       The call instruction that access the memory
+  /// @param Stmt       The parent statement of the instruction
+  ///
+  /// @returns True if the access could be built, False otherwise.
+  bool buildAccessCallInst(MemAccInst Inst, ScopStmt *Stmt);
+
+  /// Build a single-dimensional parametric sized MemoryAccess
+  ///        from the Load/Store instruction.
+  ///
+  /// @param Inst       The Load/Store instruction that access the memory
+  /// @param Stmt       The parent statement of the instruction
+  void buildAccessSingleDim(MemAccInst Inst, ScopStmt *Stmt);
+
+  /// Build an instance of MemoryAccess from the Load/Store instruction.
+  ///
+  /// @param Inst       The Load/Store instruction that access the memory
+  /// @param Stmt       The parent statement of the instruction
+  void buildMemoryAccess(MemAccInst Inst, ScopStmt *Stmt);
+
+  /// Analyze and extract the cross-BB scalar dependences (or, dataflow
+  /// dependencies) of an instruction.
+  ///
+  /// @param UserStmt The statement @p Inst resides in.
+  /// @param Inst     The instruction to be analyzed.
+  void buildScalarDependences(ScopStmt *UserStmt, Instruction *Inst);
+
+  /// Build the escaping dependences for @p Inst.
+  ///
+  /// Search for uses of the llvm::Value defined by @p Inst that are not
+  /// within the SCoP. If there is such use, add a SCALAR WRITE such that
+  /// it is available after the SCoP as escaping value.
+  ///
+  /// @param Inst The instruction to be analyzed.
+  void buildEscapingDependences(Instruction *Inst);
+
+  /// Create MemoryAccesses for the given PHI node in the given region.
+  ///
+  /// @param PHIStmt            The statement @p PHI resides in.
+  /// @param PHI                The PHI node to be handled
+  /// @param NonAffineSubRegion The non affine sub-region @p PHI is in.
+  /// @param IsExitBlock        Flag to indicate that @p PHI is in the exit BB.
+  void buildPHIAccesses(ScopStmt *PHIStmt, PHINode *PHI,
+                        Region *NonAffineSubRegion, bool IsExitBlock = false);
+
+  /// Build the access functions for the subregion @p SR.
+  void buildAccessFunctions();
+
+  /// Should an instruction be modeled in a ScopStmt.
+  ///
+  /// @param Inst The instruction to check.
+  /// @param L    The loop in which context the instruction is looked at.
+  ///
+  /// @returns True if the instruction should be modeled.
+  bool shouldModelInst(Instruction *Inst, Loop *L);
+
+  /// Create one or more ScopStmts for @p BB.
+  ///
+  /// Consecutive instructions are associated to the same statement until a
+  /// separator is found.
+  void buildSequentialBlockStmts(BasicBlock *BB, bool SplitOnStore = false);
+
+  /// Create one or more ScopStmts for @p BB using equivalence classes.
+  ///
+  /// Instructions of a basic block that belong to the same equivalence class
+  /// are added to the same statement.
+  void buildEqivClassBlockStmts(BasicBlock *BB);
+
+  /// Create ScopStmt for all BBs and non-affine subregions of @p SR.
+  ///
+  /// @param SR A subregion of @p R.
+  ///
+  /// Some of the statements might be optimized away later when they do not
+  /// access any memory and thus have no effect.
+  void buildStmts(Region &SR);
+
+  /// Build the access functions for the statement @p Stmt in or represented by
+  /// @p BB.
+  ///
+  /// @param Stmt               Statement to add MemoryAccesses to.
+  /// @param BB                 A basic block in @p R.
+  /// @param NonAffineSubRegion The non affine sub-region @p BB is in.
+  void buildAccessFunctions(ScopStmt *Stmt, BasicBlock &BB,
+                            Region *NonAffineSubRegion = nullptr);
+
+  /// Create a new MemoryAccess object and add it to #AccFuncMap.
+  ///
+  /// @param Stmt        The statement where the access takes place.
+  /// @param Inst        The instruction doing the access. It is not necessarily
+  ///                    inside @p BB.
+  /// @param AccType     The kind of access.
+  /// @param BaseAddress The accessed array's base address.
+  /// @param ElemType    The type of the accessed array elements.
+  /// @param Affine      Whether all subscripts are affine expressions.
+  /// @param AccessValue Value read or written.
+  /// @param Subscripts  Access subscripts per dimension.
+  /// @param Sizes       The array dimension's sizes.
+  /// @param Kind        The kind of memory accessed.
+  ///
+  /// @return The created MemoryAccess, or nullptr if the access is not within
+  ///         the SCoP.
+  MemoryAccess *addMemoryAccess(ScopStmt *Stmt, Instruction *Inst,
+                                MemoryAccess::AccessType AccType,
+                                Value *BaseAddress, Type *ElemType, bool Affine,
+                                Value *AccessValue,
+                                ArrayRef<const SCEV *> Subscripts,
+                                ArrayRef<const SCEV *> Sizes, MemoryKind Kind);
+
+  /// Create a MemoryAccess that represents either a LoadInst or
+  /// StoreInst.
+  ///
+  /// @param Stmt        The statement to add the MemoryAccess to.
+  /// @param MemAccInst  The LoadInst or StoreInst.
+  /// @param AccType     The kind of access.
+  /// @param BaseAddress The accessed array's base address.
+  /// @param ElemType    The type of the accessed array elements.
+  /// @param IsAffine    Whether all subscripts are affine expressions.
+  /// @param Subscripts  Access subscripts per dimension.
+  /// @param Sizes       The array dimension's sizes.
+  /// @param AccessValue Value read or written.
+  ///
+  /// @see MemoryKind
+  void addArrayAccess(ScopStmt *Stmt, MemAccInst MemAccInst,
+                      MemoryAccess::AccessType AccType, Value *BaseAddress,
+                      Type *ElemType, bool IsAffine,
+                      ArrayRef<const SCEV *> Subscripts,
+                      ArrayRef<const SCEV *> Sizes, Value *AccessValue);
+
+  /// Create a MemoryAccess for writing an llvm::Instruction.
+  ///
+  /// The access will be created at the position of @p Inst.
+  ///
+  /// @param Inst The instruction to be written.
+  ///
+  /// @see ensureValueRead()
+  /// @see MemoryKind
+  void ensureValueWrite(Instruction *Inst);
+
+  /// Ensure an llvm::Value is available in the BB's statement, creating a
+  /// MemoryAccess for reloading it if necessary.
+  ///
+  /// @param V        The value expected to be loaded.
+  /// @param UserStmt Where to reload the value.
+  ///
+  /// @see ensureValueStore()
+  /// @see MemoryKind
+  void ensureValueRead(Value *V, ScopStmt *UserStmt);
+
+  /// Create a write MemoryAccess for the incoming block of a phi node.
+  ///
+  /// Each of the incoming blocks write their incoming value to be picked in the
+  /// phi's block.
+  ///
+  /// @param PHI           PHINode under consideration.
+  /// @param IncomingStmt  The statement to add the MemoryAccess to.
+  /// @param IncomingBlock Some predecessor block.
+  /// @param IncomingValue @p PHI's value when coming from @p IncomingBlock.
+  /// @param IsExitBlock   When true, uses the .s2a alloca instead of the
+  ///                      .phiops one. Required for values escaping through a
+  ///                      PHINode in the SCoP region's exit block.
+  /// @see addPHIReadAccess()
+  /// @see MemoryKind
+  void ensurePHIWrite(PHINode *PHI, ScopStmt *IncomintStmt,
+                      BasicBlock *IncomingBlock, Value *IncomingValue,
+                      bool IsExitBlock);
+
+  /// Create a MemoryAccess for reading the value of a phi.
+  ///
+  /// The modeling assumes that all incoming blocks write their incoming value
+  /// to the same location. Thus, this access will read the incoming block's
+  /// value as instructed by this @p PHI.
+  ///
+  /// @param PHIStmt Statement @p PHI resides in.
+  /// @param PHI     PHINode under consideration; the READ access will be added
+  ///                here.
+  ///
+  /// @see ensurePHIWrite()
+  /// @see MemoryKind
+  void addPHIReadAccess(ScopStmt *PHIStmt, PHINode *PHI);
+
+  /// Build the domain of @p Stmt.
+  void buildDomain(ScopStmt &Stmt);
+
+  /// Fill NestLoops with loops surrounding @p Stmt.
+  void collectSurroundingLoops(ScopStmt &Stmt);
+
+  /// Check for reductions in @p Stmt.
+  ///
+  /// Iterate over all store memory accesses and check for valid binary
+  /// reduction like chains. For all candidates we check if they have the same
+  /// base address and there are no other accesses which overlap with them. The
+  /// base address check rules out impossible reductions candidates early. The
+  /// overlap check, together with the "only one user" check in
+  /// collectCandidateReductionLoads, guarantees that none of the intermediate
+  /// results will escape during execution of the loop nest. We basically check
+  /// here that no other memory access can access the same memory as the
+  /// potential reduction.
+  void checkForReductions(ScopStmt &Stmt);
+
+  /// Collect loads which might form a reduction chain with @p StoreMA.
+  ///
+  /// Check if the stored value for @p StoreMA is a binary operator with one or
+  /// two loads as operands. If the binary operand is commutative & associative,
+  /// used only once (by @p StoreMA) and its load operands are also used only
+  /// once, we have found a possible reduction chain. It starts at an operand
+  /// load and includes the binary operator and @p StoreMA.
+  ///
+  /// Note: We allow only one use to ensure the load and binary operator cannot
+  ///       escape this block or into any other store except @p StoreMA.
+  void collectCandidateReductionLoads(MemoryAccess *StoreMA,
+                                      SmallVectorImpl<MemoryAccess *> &Loads);
+
+  /// Build the access relation of all memory accesses of @p Stmt.
+  void buildAccessRelations(ScopStmt &Stmt);
+
+public:
+  explicit ScopBuilder(Region *R, AssumptionCache &AC, AliasAnalysis &AA,
+                       const DataLayout &DL, DominatorTree &DT, LoopInfo &LI,
+                       ScopDetection &SD, ScalarEvolution &SE,
+                       OptimizationRemarkEmitter &ORE);
+  ScopBuilder(const ScopBuilder &) = delete;
+  ScopBuilder &operator=(const ScopBuilder &) = delete;
+  ~ScopBuilder() = default;
+
+  /// Try to build the Polly IR of static control part on the current
+  /// SESE-Region.
+  ///
+  /// @return Give up the ownership of the scop object or static control part
+  ///         for the region
+  std::unique_ptr<Scop> getScop() { return std::move(scop); }
+};
+
+} // end namespace polly
+
+#endif // POLLY_SCOPBUILDER_H
diff --git a/final/include/polly/ScopDetection.h b/final/include/polly/ScopDetection.h
new file mode 100644
index 0000000..7e61c06
--- /dev/null
+++ b/final/include/polly/ScopDetection.h
@@ -0,0 +1,676 @@
+//===- ScopDetection.h - Detect Scops ---------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Detect the maximal Scops of a function.
+//
+// A static control part (Scop) is a subgraph of the control flow graph (CFG)
+// that only has statically known control flow and can therefore be described
+// within the polyhedral model.
+//
+// Every Scop fulfills these restrictions:
+//
+// * It is a single entry single exit region
+//
+// * Only affine linear bounds in the loops
+//
+// Every natural loop in a Scop must have a number of loop iterations that can
+// be described as an affine linear function in surrounding loop iterators or
+// parameters. (A parameter is a scalar that does not change its value during
+// execution of the Scop).
+//
+// * Only comparisons of affine linear expressions in conditions
+//
+// * All loops and conditions perfectly nested
+//
+// The control flow needs to be structured such that it could be written using
+// just 'for' and 'if' statements, without the need for any 'goto', 'break' or
+// 'continue'.
+//
+// * Side effect free functions call
+//
+// Only function calls and intrinsics that do not have side effects are allowed
+// (readnone).
+//
+// The Scop detection finds the largest Scops by checking if the largest
+// region is a Scop. If this is not the case, its canonical subregions are
+// checked until a region is a Scop. It is now tried to extend this Scop by
+// creating a larger non canonical region.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_SCOPDETECTION_H
+#define POLLY_SCOPDETECTION_H
+
+#include "polly/ScopDetectionDiagnostic.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/AliasSetTracker.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/Pass.h"
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+
+namespace llvm {
+
+class BasicBlock;
+class BranchInst;
+class CallInst;
+class DebugLoc;
+class DominatorTree;
+class Function;
+class Instruction;
+class IntrinsicInst;
+class Loop;
+class LoopInfo;
+class OptimizationRemarkEmitter;
+class PassRegistry;
+class raw_ostream;
+class ScalarEvolution;
+class SCEV;
+class SCEVUnknown;
+class SwitchInst;
+class Value;
+
+void initializeScopDetectionWrapperPassPass(PassRegistry &);
+
+} // namespace llvm
+
+namespace polly {
+
+using ParamSetType = std::set<const SCEV *>;
+
+// Description of the shape of an array.
+struct ArrayShape {
+  // Base pointer identifying all accesses to this array.
+  const SCEVUnknown *BasePointer;
+
+  // Sizes of each delinearized dimension.
+  SmallVector<const SCEV *, 4> DelinearizedSizes;
+
+  ArrayShape(const SCEVUnknown *B) : BasePointer(B) {}
+};
+
+struct MemAcc {
+  const Instruction *Insn;
+
+  // A pointer to the shape description of the array.
+  std::shared_ptr<ArrayShape> Shape;
+
+  // Subscripts computed by delinearization.
+  SmallVector<const SCEV *, 4> DelinearizedSubscripts;
+
+  MemAcc(const Instruction *I, std::shared_ptr<ArrayShape> S)
+      : Insn(I), Shape(S) {}
+};
+
+using MapInsnToMemAcc = std::map<const Instruction *, MemAcc>;
+using PairInstSCEV = std::pair<const Instruction *, const SCEV *>;
+using AFs = std::vector<PairInstSCEV>;
+using BaseToAFs = std::map<const SCEVUnknown *, AFs>;
+using BaseToElSize = std::map<const SCEVUnknown *, const SCEV *>;
+
+extern bool PollyTrackFailures;
+extern bool PollyDelinearize;
+extern bool PollyUseRuntimeAliasChecks;
+extern bool PollyProcessUnprofitable;
+extern bool PollyInvariantLoadHoisting;
+extern bool PollyAllowUnsignedOperations;
+extern bool PollyAllowFullFunction;
+
+/// A function attribute which will cause Polly to skip the function
+extern StringRef PollySkipFnAttr;
+
+//===----------------------------------------------------------------------===//
+/// Pass to detect the maximal static control parts (Scops) of a
+/// function.
+class ScopDetection {
+public:
+  using RegionSet = SetVector<const Region *>;
+
+  // Remember the valid regions
+  RegionSet ValidRegions;
+
+  /// Context variables for SCoP detection.
+  struct DetectionContext {
+    Region &CurRegion;   // The region to check.
+    AliasSetTracker AST; // The AliasSetTracker to hold the alias information.
+    bool Verifying;      // If we are in the verification phase?
+
+    /// Container to remember rejection reasons for this region.
+    RejectLog Log;
+
+    /// Map a base pointer to all access functions accessing it.
+    ///
+    /// This map is indexed by the base pointer. Each element of the map
+    /// is a list of memory accesses that reference this base pointer.
+    BaseToAFs Accesses;
+
+    /// The set of base pointers with non-affine accesses.
+    ///
+    /// This set contains all base pointers and the locations where they are
+    /// used for memory accesses that can not be detected as affine accesses.
+    SetVector<std::pair<const SCEVUnknown *, Loop *>> NonAffineAccesses;
+    BaseToElSize ElementSize;
+
+    /// The region has at least one load instruction.
+    bool hasLoads = false;
+
+    /// The region has at least one store instruction.
+    bool hasStores = false;
+
+    /// Flag to indicate the region has at least one unknown access.
+    bool HasUnknownAccess = false;
+
+    /// The set of non-affine subregions in the region we analyze.
+    RegionSet NonAffineSubRegionSet;
+
+    /// The set of loops contained in non-affine regions.
+    BoxedLoopsSetTy BoxedLoopsSet;
+
+    /// Loads that need to be invariant during execution.
+    InvariantLoadsSetTy RequiredILS;
+
+    /// Map to memory access description for the corresponding LLVM
+    ///        instructions.
+    MapInsnToMemAcc InsnToMemAcc;
+
+    /// Initialize a DetectionContext from scratch.
+    DetectionContext(Region &R, AliasAnalysis &AA, bool Verify)
+        : CurRegion(R), AST(AA), Verifying(Verify), Log(&R) {}
+
+    /// Initialize a DetectionContext with the data from @p DC.
+    DetectionContext(const DetectionContext &&DC)
+        : CurRegion(DC.CurRegion), AST(DC.AST.getAliasAnalysis()),
+          Verifying(DC.Verifying), Log(std::move(DC.Log)),
+          Accesses(std::move(DC.Accesses)),
+          NonAffineAccesses(std::move(DC.NonAffineAccesses)),
+          ElementSize(std::move(DC.ElementSize)), hasLoads(DC.hasLoads),
+          hasStores(DC.hasStores), HasUnknownAccess(DC.HasUnknownAccess),
+          NonAffineSubRegionSet(std::move(DC.NonAffineSubRegionSet)),
+          BoxedLoopsSet(std::move(DC.BoxedLoopsSet)),
+          RequiredILS(std::move(DC.RequiredILS)) {
+      AST.add(DC.AST);
+    }
+  };
+
+  /// Helper data structure to collect statistics about loop counts.
+  struct LoopStats {
+    int NumLoops;
+    int MaxDepth;
+  };
+
+private:
+  //===--------------------------------------------------------------------===//
+
+  /// Analyses used
+  //@{
+  const DominatorTree &DT;
+  ScalarEvolution &SE;
+  LoopInfo &LI;
+  RegionInfo &RI;
+  AliasAnalysis &AA;
+  //@}
+
+  /// Map to remember detection contexts for all regions.
+  using DetectionContextMapTy = DenseMap<BBPair, DetectionContext>;
+  mutable DetectionContextMapTy DetectionContextMap;
+
+  /// Remove cached results for @p R.
+  void removeCachedResults(const Region &R);
+
+  /// Remove cached results for the children of @p R recursively.
+  void removeCachedResultsRecursively(const Region &R);
+
+  /// Check if @p S0 and @p S1 do contain multiple possibly aliasing pointers.
+  ///
+  /// @param S0    A expression to check.
+  /// @param S1    Another expression to check or nullptr.
+  /// @param Scope The loop/scope the expressions are checked in.
+  ///
+  /// @returns True, if multiple possibly aliasing pointers are used in @p S0
+  ///          (and @p S1 if given).
+  bool involvesMultiplePtrs(const SCEV *S0, const SCEV *S1, Loop *Scope) const;
+
+  /// Add the region @p AR as over approximated sub-region in @p Context.
+  ///
+  /// @param AR      The non-affine subregion.
+  /// @param Context The current detection context.
+  ///
+  /// @returns True if the subregion can be over approximated, false otherwise.
+  bool addOverApproximatedRegion(Region *AR, DetectionContext &Context) const;
+
+  /// Find for a given base pointer terms that hint towards dimension
+  ///        sizes of a multi-dimensional array.
+  ///
+  /// @param Context      The current detection context.
+  /// @param BasePointer  A base pointer indicating the virtual array we are
+  ///                     interested in.
+  SmallVector<const SCEV *, 4>
+  getDelinearizationTerms(DetectionContext &Context,
+                          const SCEVUnknown *BasePointer) const;
+
+  /// Check if the dimension size of a delinearized array is valid.
+  ///
+  /// @param Context     The current detection context.
+  /// @param Sizes       The sizes of the different array dimensions.
+  /// @param BasePointer The base pointer we are interested in.
+  /// @param Scope       The location where @p BasePointer is being used.
+  /// @returns True if one or more array sizes could be derived - meaning: we
+  ///          see this array as multi-dimensional.
+  bool hasValidArraySizes(DetectionContext &Context,
+                          SmallVectorImpl<const SCEV *> &Sizes,
+                          const SCEVUnknown *BasePointer, Loop *Scope) const;
+
+  /// Derive access functions for a given base pointer.
+  ///
+  /// @param Context     The current detection context.
+  /// @param Sizes       The sizes of the different array dimensions.
+  /// @param BasePointer The base pointer of all the array for which to compute
+  ///                    access functions.
+  /// @param Shape       The shape that describes the derived array sizes and
+  ///                    which should be filled with newly computed access
+  ///                    functions.
+  /// @returns True if a set of affine access functions could be derived.
+  bool computeAccessFunctions(DetectionContext &Context,
+                              const SCEVUnknown *BasePointer,
+                              std::shared_ptr<ArrayShape> Shape) const;
+
+  /// Check if all accesses to a given BasePointer are affine.
+  ///
+  /// @param Context     The current detection context.
+  /// @param BasePointer the base pointer we are interested in.
+  /// @param Scope       The location where @p BasePointer is being used.
+  /// @param True if consistent (multi-dimensional) array accesses could be
+  ///        derived for this array.
+  bool hasBaseAffineAccesses(DetectionContext &Context,
+                             const SCEVUnknown *BasePointer, Loop *Scope) const;
+
+  // Delinearize all non affine memory accesses and return false when there
+  // exists a non affine memory access that cannot be delinearized. Return true
+  // when all array accesses are affine after delinearization.
+  bool hasAffineMemoryAccesses(DetectionContext &Context) const;
+
+  // Try to expand the region R. If R can be expanded return the expanded
+  // region, NULL otherwise.
+  Region *expandRegion(Region &R);
+
+  /// Find the Scops in this region tree.
+  ///
+  /// @param The region tree to scan for scops.
+  void findScops(Region &R);
+
+  /// Check if all basic block in the region are valid.
+  ///
+  /// @param Context The context of scop detection.
+  ///
+  /// @return True if all blocks in R are valid, false otherwise.
+  bool allBlocksValid(DetectionContext &Context) const;
+
+  /// Check if a region has sufficient compute instructions.
+  ///
+  /// This function checks if a region has a non-trivial number of instructions
+  /// in each loop. This can be used as an indicator whether a loop is worth
+  /// optimizing.
+  ///
+  /// @param Context  The context of scop detection.
+  /// @param NumLoops The number of loops in the region.
+  ///
+  /// @return True if region is has sufficient compute instructions,
+  ///         false otherwise.
+  bool hasSufficientCompute(DetectionContext &Context,
+                            int NumAffineLoops) const;
+
+  /// Check if the unique affine loop might be amendable to distribution.
+  ///
+  /// This function checks if the number of non-trivial blocks in the unique
+  /// affine loop in Context.CurRegion is at least two, thus if the loop might
+  /// be amendable to distribution.
+  ///
+  /// @param Context  The context of scop detection.
+  ///
+  /// @return True only if the affine loop might be amendable to distributable.
+  bool hasPossiblyDistributableLoop(DetectionContext &Context) const;
+
+  /// Check if a region is profitable to optimize.
+  ///
+  /// Regions that are unlikely to expose interesting optimization opportunities
+  /// are called 'unprofitable' and may be skipped during scop detection.
+  ///
+  /// @param Context The context of scop detection.
+  ///
+  /// @return True if region is profitable to optimize, false otherwise.
+  bool isProfitableRegion(DetectionContext &Context) const;
+
+  /// Check if a region is a Scop.
+  ///
+  /// @param Context The context of scop detection.
+  ///
+  /// @return True if R is a Scop, false otherwise.
+  bool isValidRegion(DetectionContext &Context) const;
+
+  /// Check if an intrinsic call can be part of a Scop.
+  ///
+  /// @param II      The intrinsic call instruction to check.
+  /// @param Context The current detection context.
+  ///
+  /// @return True if the call instruction is valid, false otherwise.
+  bool isValidIntrinsicInst(IntrinsicInst &II, DetectionContext &Context) const;
+
+  /// Check if a call instruction can be part of a Scop.
+  ///
+  /// @param CI      The call instruction to check.
+  /// @param Context The current detection context.
+  ///
+  /// @return True if the call instruction is valid, false otherwise.
+  bool isValidCallInst(CallInst &CI, DetectionContext &Context) const;
+
+  /// Check if the given loads could be invariant and can be hoisted.
+  ///
+  /// If true is returned the loads are added to the required invariant loads
+  /// contained in the @p Context.
+  ///
+  /// @param RequiredILS The loads to check.
+  /// @param Context     The current detection context.
+  ///
+  /// @return True if all loads can be assumed invariant.
+  bool onlyValidRequiredInvariantLoads(InvariantLoadsSetTy &RequiredILS,
+                                       DetectionContext &Context) const;
+
+  /// Check if a value is invariant in the region Reg.
+  ///
+  /// @param Val Value to check for invariance.
+  /// @param Reg The region to consider for the invariance of Val.
+  /// @param Ctx The current detection context.
+  ///
+  /// @return True if the value represented by Val is invariant in the region
+  ///         identified by Reg.
+  bool isInvariant(Value &Val, const Region &Reg, DetectionContext &Ctx) const;
+
+  /// Check if the memory access caused by @p Inst is valid.
+  ///
+  /// @param Inst    The access instruction.
+  /// @param AF      The access function.
+  /// @param BP      The access base pointer.
+  /// @param Context The current detection context.
+  bool isValidAccess(Instruction *Inst, const SCEV *AF, const SCEVUnknown *BP,
+                     DetectionContext &Context) const;
+
+  /// Check if a memory access can be part of a Scop.
+  ///
+  /// @param Inst The instruction accessing the memory.
+  /// @param Context The context of scop detection.
+  ///
+  /// @return True if the memory access is valid, false otherwise.
+  bool isValidMemoryAccess(MemAccInst Inst, DetectionContext &Context) const;
+
+  /// Check if an instruction has any non trivial scalar dependencies as part of
+  /// a Scop.
+  ///
+  /// @param Inst The instruction to check.
+  /// @param RefRegion The region in respect to which we check the access
+  ///                  function.
+  ///
+  /// @return True if the instruction has scalar dependences, false otherwise.
+  bool hasScalarDependency(Instruction &Inst, Region &RefRegion) const;
+
+  /// Check if an instruction can be part of a Scop.
+  ///
+  /// @param Inst The instruction to check.
+  /// @param Context The context of scop detection.
+  ///
+  /// @return True if the instruction is valid, false otherwise.
+  bool isValidInstruction(Instruction &Inst, DetectionContext &Context) const;
+
+  /// Check if the switch @p SI with condition @p Condition is valid.
+  ///
+  /// @param BB           The block to check.
+  /// @param SI           The switch to check.
+  /// @param Condition    The switch condition.
+  /// @param IsLoopBranch Flag to indicate the branch is a loop exit/latch.
+  /// @param Context      The context of scop detection.
+  ///
+  /// @return True if the branch @p BI is valid.
+  bool isValidSwitch(BasicBlock &BB, SwitchInst *SI, Value *Condition,
+                     bool IsLoopBranch, DetectionContext &Context) const;
+
+  /// Check if the branch @p BI with condition @p Condition is valid.
+  ///
+  /// @param BB           The block to check.
+  /// @param BI           The branch to check.
+  /// @param Condition    The branch condition.
+  /// @param IsLoopBranch Flag to indicate the branch is a loop exit/latch.
+  /// @param Context      The context of scop detection.
+  ///
+  /// @return True if the branch @p BI is valid.
+  bool isValidBranch(BasicBlock &BB, BranchInst *BI, Value *Condition,
+                     bool IsLoopBranch, DetectionContext &Context) const;
+
+  /// Check if the SCEV @p S is affine in the current @p Context.
+  ///
+  /// This will also use a heuristic to decide if we want to require loads to be
+  /// invariant to make the expression affine or if we want to treat is as
+  /// non-affine.
+  ///
+  /// @param S           The expression to be checked.
+  /// @param Scope       The loop nest in which @p S is used.
+  /// @param Context     The context of scop detection.
+  bool isAffine(const SCEV *S, Loop *Scope, DetectionContext &Context) const;
+
+  /// Check if the control flow in a basic block is valid.
+  ///
+  /// This function checks if a certain basic block is terminated by a
+  /// Terminator instruction we can handle or, if this is not the case,
+  /// registers this basic block as the start of a non-affine region.
+  ///
+  /// This function optionally allows unreachable statements.
+  ///
+  /// @param BB               The BB to check the control flow.
+  /// @param IsLoopBranch     Flag to indicate the branch is a loop exit/latch.
+  //  @param AllowUnreachable Allow unreachable statements.
+  /// @param Context          The context of scop detection.
+  ///
+  /// @return True if the BB contains only valid control flow.
+  bool isValidCFG(BasicBlock &BB, bool IsLoopBranch, bool AllowUnreachable,
+                  DetectionContext &Context) const;
+
+  /// Is a loop valid with respect to a given region.
+  ///
+  /// @param L The loop to check.
+  /// @param Context The context of scop detection.
+  ///
+  /// @return True if the loop is valid in the region.
+  bool isValidLoop(Loop *L, DetectionContext &Context) const;
+
+  /// Count the number of loops and the maximal loop depth in @p L.
+  ///
+  /// @param L The loop to check.
+  /// @param SE The scalar evolution analysis.
+  /// @param MinProfitableTrips The minimum number of trip counts from which
+  ///                           a loop is assumed to be profitable and
+  ///                           consequently is counted.
+  /// returns A tuple of number of loops and their maximal depth.
+  static ScopDetection::LoopStats
+  countBeneficialSubLoops(Loop *L, ScalarEvolution &SE,
+                          unsigned MinProfitableTrips);
+
+  /// Check if the function @p F is marked as invalid.
+  ///
+  /// @note An OpenMP subfunction will be marked as invalid.
+  bool isValidFunction(Function &F);
+
+  /// Can ISL compute the trip count of a loop.
+  ///
+  /// @param L The loop to check.
+  /// @param Context The context of scop detection.
+  ///
+  /// @return True if ISL can compute the trip count of the loop.
+  bool canUseISLTripCount(Loop *L, DetectionContext &Context) const;
+
+  /// Print the locations of all detected scops.
+  void printLocations(Function &F);
+
+  /// Check if a region is reducible or not.
+  ///
+  /// @param Region The region to check.
+  /// @param DbgLoc Parameter to save the location of instruction that
+  ///               causes irregular control flow if the region is irreducible.
+  ///
+  /// @return True if R is reducible, false otherwise.
+  bool isReducibleRegion(Region &R, DebugLoc &DbgLoc) const;
+
+  /// Track diagnostics for invalid scops.
+  ///
+  /// @param Context The context of scop detection.
+  /// @param Assert Throw an assert in verify mode or not.
+  /// @param Args Argument list that gets passed to the constructor of RR.
+  template <class RR, typename... Args>
+  inline bool invalid(DetectionContext &Context, bool Assert,
+                      Args &&... Arguments) const;
+
+public:
+  ScopDetection(Function &F, const DominatorTree &DT, ScalarEvolution &SE,
+                LoopInfo &LI, RegionInfo &RI, AliasAnalysis &AA,
+                OptimizationRemarkEmitter &ORE);
+
+  /// Get the RegionInfo stored in this pass.
+  ///
+  /// This was added to give the DOT printer easy access to this information.
+  RegionInfo *getRI() const { return &RI; }
+
+  /// Get the LoopInfo stored in this pass.
+  LoopInfo *getLI() const { return &LI; }
+
+  /// Is the region is the maximum region of a Scop?
+  ///
+  /// @param R The Region to test if it is maximum.
+  /// @param Verify Rerun the scop detection to verify SCoP was not invalidated
+  ///               meanwhile.
+  ///
+  /// @return Return true if R is the maximum Region in a Scop, false otherwise.
+  bool isMaxRegionInScop(const Region &R, bool Verify = true) const;
+
+  /// Return the detection context for @p R, nullptr if @p R was invalid.
+  DetectionContext *getDetectionContext(const Region *R) const;
+
+  /// Return the set of rejection causes for @p R.
+  const RejectLog *lookupRejectionLog(const Region *R) const;
+
+  /// Return true if @p SubR is a non-affine subregion in @p ScopR.
+  bool isNonAffineSubRegion(const Region *SubR, const Region *ScopR) const;
+
+  /// Get a message why a region is invalid
+  ///
+  /// @param R The region for which we get the error message
+  ///
+  /// @return The error or "" if no error appeared.
+  std::string regionIsInvalidBecause(const Region *R) const;
+
+  /// @name Maximum Region In Scops Iterators
+  ///
+  /// These iterators iterator over all maximum region in Scops of this
+  /// function.
+  //@{
+  using iterator = RegionSet::iterator;
+  using const_iterator = RegionSet::const_iterator;
+
+  iterator begin() { return ValidRegions.begin(); }
+  iterator end() { return ValidRegions.end(); }
+
+  const_iterator begin() const { return ValidRegions.begin(); }
+  const_iterator end() const { return ValidRegions.end(); }
+  //@}
+
+  /// Emit rejection remarks for all rejected regions.
+  ///
+  /// @param F The function to emit remarks for.
+  void emitMissedRemarks(const Function &F);
+
+  /// Mark the function as invalid so we will not extract any scop from
+  ///        the function.
+  ///
+  /// @param F The function to mark as invalid.
+  static void markFunctionAsInvalid(Function *F);
+
+  /// Verify if all valid Regions in this Function are still valid
+  /// after some transformations.
+  void verifyAnalysis() const;
+
+  /// Verify if R is still a valid part of Scop after some transformations.
+  ///
+  /// @param R The Region to verify.
+  void verifyRegion(const Region &R) const;
+
+  /// Count the number of loops and the maximal loop depth in @p R.
+  ///
+  /// @param R The region to check
+  /// @param SE The scalar evolution analysis.
+  /// @param MinProfitableTrips The minimum number of trip counts from which
+  ///                           a loop is assumed to be profitable and
+  ///                           consequently is counted.
+  /// returns A tuple of number of loops and their maximal depth.
+  static ScopDetection::LoopStats
+  countBeneficialLoops(Region *R, ScalarEvolution &SE, LoopInfo &LI,
+                       unsigned MinProfitableTrips);
+
+private:
+  /// OptimizationRemarkEmitter object used to emit diagnostic remarks
+  OptimizationRemarkEmitter &ORE;
+};
+
+struct ScopAnalysis : public AnalysisInfoMixin<ScopAnalysis> {
+  static AnalysisKey Key;
+
+  using Result = ScopDetection;
+
+  ScopAnalysis();
+
+  Result run(Function &F, FunctionAnalysisManager &FAM);
+};
+
+struct ScopAnalysisPrinterPass : public PassInfoMixin<ScopAnalysisPrinterPass> {
+  ScopAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {}
+
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+
+  raw_ostream &OS;
+};
+
+struct ScopDetectionWrapperPass : public FunctionPass {
+  static char ID;
+  std::unique_ptr<ScopDetection> Result;
+
+  ScopDetectionWrapperPass();
+
+  /// @name FunctionPass interface
+  //@{
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+  void releaseMemory() override;
+  bool runOnFunction(Function &F) override;
+  void print(raw_ostream &OS, const Module *) const override;
+  //@}
+
+  ScopDetection &getSD() { return *Result; }
+  const ScopDetection &getSD() const { return *Result; }
+};
+
+} // namespace polly
+
+#endif // POLLY_SCOPDETECTION_H
diff --git a/final/include/polly/ScopDetectionDiagnostic.h b/final/include/polly/ScopDetectionDiagnostic.h
new file mode 100644
index 0000000..d5fa238
--- /dev/null
+++ b/final/include/polly/ScopDetectionDiagnostic.h
@@ -0,0 +1,836 @@
+//===- ScopDetectionDiagnostic.h - Diagnostic for ScopDetection -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Small set of diagnostic helper classes to encapsulate any errors occurred
+// during the detection of Scops.
+//
+// The ScopDetection defines a set of error classes (via Statistic variables)
+// that groups a number of individual errors into a group, e.g. non-affinity
+// related errors.
+// On error we generate an object that carries enough additional information
+// to diagnose the error and generate a helpful error message.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_SCOPDETECTIONDIAGNOSTIC_H
+#define POLLY_SCOPDETECTIONDIAGNOSTIC_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/Instruction.h"
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+
+namespace llvm {
+
+class AliasSet;
+class BasicBlock;
+class OptimizationRemarkEmitter;
+class raw_ostream;
+class Region;
+class SCEV;
+class Value;
+
+} // namespace llvm
+
+namespace polly {
+
+/// Type to hold region delimiters (entry & exit block).
+using BBPair = std::pair<BasicBlock *, BasicBlock *>;
+
+/// Return the region delimiters (entry & exit block) of @p R.
+BBPair getBBPairForRegion(const Region *R);
+
+/// Set the begin and end source location for the region limited by @p P.
+void getDebugLocations(const BBPair &P, DebugLoc &Begin, DebugLoc &End);
+
+class RejectLog;
+
+/// Emit optimization remarks about the rejected regions to the user.
+///
+/// This emits the content of the reject log as optimization remarks.
+/// Remember to at least track failures (-polly-detect-track-failures).
+/// @param P The region delimiters (entry & exit) we emit remarks for.
+/// @param Log The error log containing all messages being emitted as remark.
+void emitRejectionRemarks(const BBPair &P, const RejectLog &Log,
+                          OptimizationRemarkEmitter &ORE);
+
+// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
+enum class RejectReasonKind {
+  // CFG Category
+  CFG,
+  InvalidTerminator,
+  IrreducibleRegion,
+  UnreachableInExit,
+  LastCFG,
+
+  // Non-Affinity
+  AffFunc,
+  UndefCond,
+  InvalidCond,
+  UndefOperand,
+  NonAffBranch,
+  NoBasePtr,
+  UndefBasePtr,
+  VariantBasePtr,
+  NonAffineAccess,
+  DifferentElementSize,
+  LastAffFunc,
+
+  LoopBound,
+  LoopHasNoExit,
+  LoopOnlySomeLatches,
+
+  FuncCall,
+  NonSimpleMemoryAccess,
+
+  Alias,
+
+  // Other
+  Other,
+  IntToPtr,
+  Alloca,
+  UnknownInst,
+  Entry,
+  Unprofitable,
+  LastOther
+};
+
+//===----------------------------------------------------------------------===//
+/// Base class of all reject reasons found during Scop detection.
+///
+/// Subclasses of RejectReason should provide means to capture enough
+/// diagnostic information to help clients figure out what and where something
+/// went wrong in the Scop detection.
+class RejectReason {
+private:
+  const RejectReasonKind Kind;
+
+protected:
+  static const DebugLoc Unknown;
+
+public:
+  RejectReason(RejectReasonKind K);
+
+  virtual ~RejectReason() = default;
+
+  RejectReasonKind getKind() const { return Kind; }
+
+  /// Generate the remark name to identify this remark.
+  ///
+  /// @return A short string that identifies the error.
+  virtual std::string getRemarkName() const = 0;
+
+  /// Get the Basic Block containing this remark.
+  ///
+  /// @return The Basic Block containing this remark.
+  virtual const Value *getRemarkBB() const = 0;
+
+  /// Generate a reasonable diagnostic message describing this error.
+  ///
+  /// @return A debug message representing this error.
+  virtual std::string getMessage() const = 0;
+
+  /// Generate a message for the end-user describing this error.
+  ///
+  /// The message provided has to be suitable for the end-user. So it should
+  /// not reference any LLVM internal data structures or terminology.
+  /// Ideally, the message helps the end-user to increase the size of the
+  /// regions amenable to Polly.
+  ///
+  /// @return A short message representing this error.
+  virtual std::string getEndUserMessage() const { return "Unspecified error."; }
+
+  /// Get the source location of this error.
+  ///
+  /// @return The debug location for this error.
+  virtual const DebugLoc &getDebugLoc() const;
+};
+
+using RejectReasonPtr = std::shared_ptr<RejectReason>;
+
+/// Stores all errors that occurred during the detection.
+class RejectLog {
+  Region *R;
+  SmallVector<RejectReasonPtr, 1> ErrorReports;
+
+public:
+  explicit RejectLog(Region *R) : R(R) {}
+
+  using iterator = SmallVector<RejectReasonPtr, 1>::const_iterator;
+
+  iterator begin() const { return ErrorReports.begin(); }
+  iterator end() const { return ErrorReports.end(); }
+  size_t size() const { return ErrorReports.size(); }
+
+  /// Returns true, if we store at least one error.
+  ///
+  /// @return true, if we store at least one error.
+  bool hasErrors() const { return size() > 0; }
+
+  void print(raw_ostream &OS, int level = 0) const;
+
+  const Region *region() const { return R; }
+  void report(RejectReasonPtr Reject) { ErrorReports.push_back(Reject); }
+};
+
+//===----------------------------------------------------------------------===//
+/// Base class for CFG related reject reasons.
+///
+/// Scop candidates that violate structural restrictions can be grouped under
+/// this reject reason class.
+class ReportCFG : public RejectReason {
+public:
+  ReportCFG(const RejectReasonKind K);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures bad terminator within a Scop candidate.
+class ReportInvalidTerminator : public ReportCFG {
+  BasicBlock *BB;
+
+public:
+  ReportInvalidTerminator(BasicBlock *BB)
+      : ReportCFG(RejectReasonKind::InvalidTerminator), BB(BB) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures irreducible regions in CFG.
+class ReportIrreducibleRegion : public ReportCFG {
+  Region *R;
+  DebugLoc DbgLoc;
+
+public:
+  ReportIrreducibleRegion(Region *R, DebugLoc DbgLoc)
+      : ReportCFG(RejectReasonKind::IrreducibleRegion), R(R), DbgLoc(DbgLoc) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  std::string getEndUserMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures regions with an unreachable in the exit block.
+class ReportUnreachableInExit : public ReportCFG {
+  BasicBlock *BB;
+  DebugLoc DbgLoc;
+
+public:
+  ReportUnreachableInExit(BasicBlock *BB, DebugLoc DbgLoc)
+      : ReportCFG(RejectReasonKind::UnreachableInExit), BB(BB), DbgLoc(DbgLoc) {
+  }
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  std::string getEndUserMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Base class for non-affine reject reasons.
+///
+/// Scop candidates that violate restrictions to affinity are reported under
+/// this class.
+class ReportAffFunc : public RejectReason {
+protected:
+  // The instruction that caused non-affinity to occur.
+  const Instruction *Inst;
+
+public:
+  ReportAffFunc(const RejectReasonKind K, const Instruction *Inst);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  const DebugLoc &getDebugLoc() const override { return Inst->getDebugLoc(); }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures a condition that is based on an 'undef' value.
+class ReportUndefCond : public ReportAffFunc {
+  // The BasicBlock we found the broken condition in.
+  BasicBlock *BB;
+
+public:
+  ReportUndefCond(const Instruction *Inst, BasicBlock *BB)
+      : ReportAffFunc(RejectReasonKind::UndefCond, Inst), BB(BB) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures an invalid condition
+///
+/// Conditions have to be either constants or icmp instructions.
+class ReportInvalidCond : public ReportAffFunc {
+  // The BasicBlock we found the broken condition in.
+  BasicBlock *BB;
+
+public:
+  ReportInvalidCond(const Instruction *Inst, BasicBlock *BB)
+      : ReportAffFunc(RejectReasonKind::InvalidCond, Inst), BB(BB) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures an undefined operand.
+class ReportUndefOperand : public ReportAffFunc {
+  // The BasicBlock we found the undefined operand in.
+  BasicBlock *BB;
+
+public:
+  ReportUndefOperand(BasicBlock *BB, const Instruction *Inst)
+      : ReportAffFunc(RejectReasonKind::UndefOperand, Inst), BB(BB) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures a non-affine branch.
+class ReportNonAffBranch : public ReportAffFunc {
+  // The BasicBlock we found the non-affine branch in.
+  BasicBlock *BB;
+
+  /// LHS & RHS of the failed condition.
+  //@{
+  const SCEV *LHS;
+  const SCEV *RHS;
+  //@}
+
+public:
+  ReportNonAffBranch(BasicBlock *BB, const SCEV *LHS, const SCEV *RHS,
+                     const Instruction *Inst)
+      : ReportAffFunc(RejectReasonKind::NonAffBranch, Inst), BB(BB), LHS(LHS),
+        RHS(RHS) {}
+
+  const SCEV *lhs() { return LHS; }
+  const SCEV *rhs() { return RHS; }
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures a missing base pointer.
+class ReportNoBasePtr : public ReportAffFunc {
+public:
+  ReportNoBasePtr(const Instruction *Inst)
+      : ReportAffFunc(RejectReasonKind::NoBasePtr, Inst) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures an undefined base pointer.
+class ReportUndefBasePtr : public ReportAffFunc {
+public:
+  ReportUndefBasePtr(const Instruction *Inst)
+      : ReportAffFunc(RejectReasonKind::UndefBasePtr, Inst) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures a base pointer that is not invariant in the region.
+class ReportVariantBasePtr : public ReportAffFunc {
+  // The variant base pointer.
+  Value *BaseValue;
+
+public:
+  ReportVariantBasePtr(Value *BaseValue, const Instruction *Inst)
+      : ReportAffFunc(RejectReasonKind::VariantBasePtr, Inst),
+        BaseValue(BaseValue) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures a non-affine access function.
+class ReportNonAffineAccess : public ReportAffFunc {
+  // The non-affine access function.
+  const SCEV *AccessFunction;
+
+  // The base pointer of the memory access.
+  const Value *BaseValue;
+
+public:
+  ReportNonAffineAccess(const SCEV *AccessFunction, const Instruction *Inst,
+                        const Value *V)
+      : ReportAffFunc(RejectReasonKind::NonAffineAccess, Inst),
+        AccessFunction(AccessFunction), BaseValue(V) {}
+
+  const SCEV *get() { return AccessFunction; }
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Report array accesses with differing element size.
+class ReportDifferentArrayElementSize : public ReportAffFunc {
+  // The base pointer of the memory access.
+  const Value *BaseValue;
+
+public:
+  ReportDifferentArrayElementSize(const Instruction *Inst, const Value *V)
+      : ReportAffFunc(RejectReasonKind::DifferentElementSize, Inst),
+        BaseValue(V) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures errors with non affine loop bounds.
+class ReportLoopBound : public RejectReason {
+  // The offending loop.
+  Loop *L;
+
+  // The non-affine loop bound.
+  const SCEV *LoopCount;
+
+  // A copy of the offending loop's debug location.
+  const DebugLoc Loc;
+
+public:
+  ReportLoopBound(Loop *L, const SCEV *LoopCount);
+
+  const SCEV *loopCount() { return LoopCount; }
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures errors when loop has no exit.
+class ReportLoopHasNoExit : public RejectReason {
+  /// The loop that has no exit.
+  Loop *L;
+
+  const DebugLoc Loc;
+
+public:
+  ReportLoopHasNoExit(Loop *L)
+      : RejectReason(RejectReasonKind::LoopHasNoExit), L(L),
+        Loc(L->getStartLoc()) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures errors when not all loop latches are part of the scop.
+class ReportLoopOnlySomeLatches : public RejectReason {
+  /// The loop for which not all loop latches are part of the scop.
+  Loop *L;
+
+  const DebugLoc Loc;
+
+public:
+  ReportLoopOnlySomeLatches(Loop *L)
+      : RejectReason(RejectReasonKind::LoopOnlySomeLatches), L(L),
+        Loc(L->getStartLoc()) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures errors with non-side-effect-known function calls.
+class ReportFuncCall : public RejectReason {
+  // The offending call instruction.
+  Instruction *Inst;
+
+public:
+  ReportFuncCall(Instruction *Inst);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures errors with aliasing.
+class ReportAlias : public RejectReason {
+public:
+  using PointerSnapshotTy = std::vector<const Value *>;
+
+private:
+  /// Format an invalid alias set.
+  ///
+  //  @param Prefix A prefix string to put before the list of aliasing pointers.
+  //  @param Suffix A suffix string to put after the list of aliasing pointers.
+  std::string formatInvalidAlias(std::string Prefix = "",
+                                 std::string Suffix = "") const;
+
+  Instruction *Inst;
+
+  // A snapshot of the llvm values that took part in the aliasing error.
+  mutable PointerSnapshotTy Pointers;
+
+public:
+  ReportAlias(Instruction *Inst, AliasSet &AS);
+
+  const PointerSnapshotTy &getPointers() const { return Pointers; }
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Base class for otherwise ungrouped reject reasons.
+class ReportOther : public RejectReason {
+public:
+  ReportOther(const RejectReasonKind K);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures errors with bad IntToPtr instructions.
+class ReportIntToPtr : public ReportOther {
+  // The offending base value.
+  Instruction *BaseValue;
+
+public:
+  ReportIntToPtr(Instruction *BaseValue);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures errors with alloca instructions.
+class ReportAlloca : public ReportOther {
+  Instruction *Inst;
+
+public:
+  ReportAlloca(Instruction *Inst);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures errors with unknown instructions.
+class ReportUnknownInst : public ReportOther {
+  Instruction *Inst;
+
+public:
+  ReportUnknownInst(Instruction *Inst);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures errors with regions containing the function entry block.
+class ReportEntry : public ReportOther {
+  BasicBlock *BB;
+
+public:
+  ReportEntry(BasicBlock *BB);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  std::string getEndUserMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Report regions that seem not profitable to be optimized.
+class ReportUnprofitable : public ReportOther {
+  Region *R;
+
+public:
+  ReportUnprofitable(Region *R);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  std::string getEndUserMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// Captures errors with non-simple memory accesses.
+class ReportNonSimpleMemoryAccess : public ReportOther {
+  // The offending call instruction.
+  Instruction *Inst;
+
+public:
+  ReportNonSimpleMemoryAccess(Instruction *Inst);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  std::string getRemarkName() const override;
+  const Value *getRemarkBB() const override;
+  std::string getMessage() const override;
+  const DebugLoc &getDebugLoc() const override;
+  std::string getEndUserMessage() const override;
+  //@}
+};
+
+} // namespace polly
+
+#endif // POLLY_SCOPDETECTIONDIAGNOSTIC_H
diff --git a/final/include/polly/ScopInfo.h b/final/include/polly/ScopInfo.h
new file mode 100644
index 0000000..248e5f9
--- /dev/null
+++ b/final/include/polly/ScopInfo.h
@@ -0,0 +1,3203 @@
+//===- polly/ScopInfo.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Store the polyhedral model representation of a static control flow region,
+// also called SCoP (Static Control Part).
+//
+// This representation is shared among several tools in the polyhedral
+// community, which are e.g. CLooG, Pluto, Loopo, Graphite.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_SCOPINFO_H
+#define POLLY_SCOPINFO_H
+
+#include "polly/ScopDetection.h"
+#include "polly/Support/SCEVAffinator.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Analysis/RegionPass.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/ValueHandle.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Casting.h"
+#include "isl/isl-noexceptions.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <forward_list>
+#include <functional>
+#include <list>
+#include <map>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+
+namespace llvm {
+
+class AssumptionCache;
+class BasicBlock;
+class DataLayout;
+class DominatorTree;
+class Function;
+class Loop;
+class LoopInfo;
+class OptimizationRemarkEmitter;
+class PassRegistry;
+class raw_ostream;
+class ScalarEvolution;
+class SCEV;
+class Type;
+class Value;
+
+void initializeScopInfoRegionPassPass(PassRegistry &);
+void initializeScopInfoWrapperPassPass(PassRegistry &);
+
+} // end namespace llvm
+
+struct isl_map;
+struct isl_pw_multi_aff;
+struct isl_schedule;
+struct isl_set;
+struct isl_union_map;
+
+namespace polly {
+
+class MemoryAccess;
+class Scop;
+class ScopStmt;
+
+//===---------------------------------------------------------------------===//
+
+extern bool UseInstructionNames;
+
+/// Enumeration of assumptions Polly can take.
+enum AssumptionKind {
+  ALIASING,
+  INBOUNDS,
+  WRAPPING,
+  UNSIGNED,
+  PROFITABLE,
+  ERRORBLOCK,
+  COMPLEXITY,
+  INFINITELOOP,
+  INVARIANTLOAD,
+  DELINEARIZATION,
+};
+
+/// Enum to distinguish between assumptions and restrictions.
+enum AssumptionSign { AS_ASSUMPTION, AS_RESTRICTION };
+
+/// The different memory kinds used in Polly.
+///
+/// We distinguish between arrays and various scalar memory objects. We use
+/// the term ``array'' to describe memory objects that consist of a set of
+/// individual data elements arranged in a multi-dimensional grid. A scalar
+/// memory object describes an individual data element and is used to model
+/// the definition and uses of llvm::Values.
+///
+/// The polyhedral model does traditionally not reason about SSA values. To
+/// reason about llvm::Values we model them "as if" they were zero-dimensional
+/// memory objects, even though they were not actually allocated in (main)
+/// memory.  Memory for such objects is only alloca[ed] at CodeGeneration
+/// time. To relate the memory slots used during code generation with the
+/// llvm::Values they belong to the new names for these corresponding stack
+/// slots are derived by appending suffixes (currently ".s2a" and ".phiops")
+/// to the name of the original llvm::Value. To describe how def/uses are
+/// modeled exactly we use these suffixes here as well.
+///
+/// There are currently four different kinds of memory objects:
+enum class MemoryKind {
+  /// MemoryKind::Array: Models a one or multi-dimensional array
+  ///
+  /// A memory object that can be described by a multi-dimensional array.
+  /// Memory objects of this type are used to model actual multi-dimensional
+  /// arrays as they exist in LLVM-IR, but they are also used to describe
+  /// other objects:
+  ///   - A single data element allocated on the stack using 'alloca' is
+  ///     modeled as a one-dimensional, single-element array.
+  ///   - A single data element allocated as a global variable is modeled as
+  ///     one-dimensional, single-element array.
+  ///   - Certain multi-dimensional arrays with variable size, which in
+  ///     LLVM-IR are commonly expressed as a single-dimensional access with a
+  ///     complicated access function, are modeled as multi-dimensional
+  ///     memory objects (grep for "delinearization").
+  Array,
+
+  /// MemoryKind::Value: Models an llvm::Value
+  ///
+  /// Memory objects of type MemoryKind::Value are used to model the data flow
+  /// induced by llvm::Values. For each llvm::Value that is used across
+  /// BasicBlocks, one ScopArrayInfo object is created. A single memory WRITE
+  /// stores the llvm::Value at its definition into the memory object and at
+  /// each use of the llvm::Value (ignoring trivial intra-block uses) a
+  /// corresponding READ is added. For instance, the use/def chain of a
+  /// llvm::Value %V depicted below
+  ///              ______________________
+  ///              |DefBB:              |
+  ///              |  %V = float op ... |
+  ///              ----------------------
+  ///               |                  |
+  /// _________________               _________________
+  /// |UseBB1:        |               |UseBB2:        |
+  /// |  use float %V |               |  use float %V |
+  /// -----------------               -----------------
+  ///
+  /// is modeled as if the following memory accesses occurred:
+  ///
+  ///                        __________________________
+  ///                        |entry:                  |
+  ///                        |  %V.s2a = alloca float |
+  ///                        --------------------------
+  ///                                     |
+  ///                    ___________________________________
+  ///                    |DefBB:                           |
+  ///                    |  store %float %V, float* %V.s2a |
+  ///                    -----------------------------------
+  ///                           |                   |
+  /// ____________________________________ ___________________________________
+  /// |UseBB1:                           | |UseBB2:                          |
+  /// |  %V.reload1 = load float* %V.s2a | |  %V.reload2 = load float* %V.s2a|
+  /// |  use float %V.reload1            | |  use float %V.reload2           |
+  /// ------------------------------------ -----------------------------------
+  ///
+  Value,
+
+  /// MemoryKind::PHI: Models PHI nodes within the SCoP
+  ///
+  /// Besides the MemoryKind::Value memory object used to model the normal
+  /// llvm::Value dependences described above, PHI nodes require an additional
+  /// memory object of type MemoryKind::PHI to describe the forwarding of values
+  /// to
+  /// the PHI node.
+  ///
+  /// As an example, a PHIInst instructions
+  ///
+  /// %PHI = phi float [ %Val1, %IncomingBlock1 ], [ %Val2, %IncomingBlock2 ]
+  ///
+  /// is modeled as if the accesses occurred this way:
+  ///
+  ///                    _______________________________
+  ///                    |entry:                       |
+  ///                    |  %PHI.phiops = alloca float |
+  ///                    -------------------------------
+  ///                           |              |
+  /// __________________________________  __________________________________
+  /// |IncomingBlock1:                 |  |IncomingBlock2:                 |
+  /// |  ...                           |  |  ...                           |
+  /// |  store float %Val1 %PHI.phiops |  |  store float %Val2 %PHI.phiops |
+  /// |  br label % JoinBlock          |  |  br label %JoinBlock           |
+  /// ----------------------------------  ----------------------------------
+  ///                             \            /
+  ///                              \          /
+  ///               _________________________________________
+  ///               |JoinBlock:                             |
+  ///               |  %PHI = load float, float* PHI.phiops |
+  ///               -----------------------------------------
+  ///
+  /// Note that there can also be a scalar write access for %PHI if used in a
+  /// different BasicBlock, i.e. there can be a memory object %PHI.phiops as
+  /// well as a memory object %PHI.s2a.
+  PHI,
+
+  /// MemoryKind::ExitPHI: Models PHI nodes in the SCoP's exit block
+  ///
+  /// For PHI nodes in the Scop's exit block a special memory object kind is
+  /// used. The modeling used is identical to MemoryKind::PHI, with the
+  /// exception
+  /// that there are no READs from these memory objects. The PHINode's
+  /// llvm::Value is treated as a value escaping the SCoP. WRITE accesses
+  /// write directly to the escaping value's ".s2a" alloca.
+  ExitPHI
+};
+
+/// Maps from a loop to the affine function expressing its backedge taken count.
+/// The backedge taken count already enough to express iteration domain as we
+/// only allow loops with canonical induction variable.
+/// A canonical induction variable is:
+/// an integer recurrence that starts at 0 and increments by one each time
+/// through the loop.
+using LoopBoundMapType = std::map<const Loop *, const SCEV *>;
+
+using AccFuncVector = std::vector<std::unique_ptr<MemoryAccess>>;
+
+/// A class to store information about arrays in the SCoP.
+///
+/// Objects are accessible via the ScoP, MemoryAccess or the id associated with
+/// the MemoryAccess access function.
+///
+class ScopArrayInfo {
+public:
+  /// Construct a ScopArrayInfo object.
+  ///
+  /// @param BasePtr        The array base pointer.
+  /// @param ElementType    The type of the elements stored in the array.
+  /// @param IslCtx         The isl context used to create the base pointer id.
+  /// @param DimensionSizes A vector containing the size of each dimension.
+  /// @param Kind           The kind of the array object.
+  /// @param DL             The data layout of the module.
+  /// @param S              The scop this array object belongs to.
+  /// @param BaseName       The optional name of this memory reference.
+  ScopArrayInfo(Value *BasePtr, Type *ElementType, isl::ctx IslCtx,
+                ArrayRef<const SCEV *> DimensionSizes, MemoryKind Kind,
+                const DataLayout &DL, Scop *S, const char *BaseName = nullptr);
+
+  /// Destructor to free the isl id of the base pointer.
+  ~ScopArrayInfo();
+
+  ///  Update the element type of the ScopArrayInfo object.
+  ///
+  ///  Memory accesses referencing this ScopArrayInfo object may use
+  ///  different element sizes. This function ensures the canonical element type
+  ///  stored is small enough to model accesses to the current element type as
+  ///  well as to @p NewElementType.
+  ///
+  ///  @param NewElementType An element type that is used to access this array.
+  void updateElementType(Type *NewElementType);
+
+  ///  Update the sizes of the ScopArrayInfo object.
+  ///
+  ///  A ScopArrayInfo object may be created without all outer dimensions being
+  ///  available. This function is called when new memory accesses are added for
+  ///  this ScopArrayInfo object. It verifies that sizes are compatible and adds
+  ///  additional outer array dimensions, if needed.
+  ///
+  ///  @param Sizes       A vector of array sizes where the rightmost array
+  ///                     sizes need to match the innermost array sizes already
+  ///                     defined in SAI.
+  ///  @param CheckConsistency Update sizes, even if new sizes are inconsistent
+  ///                          with old sizes
+  bool updateSizes(ArrayRef<const SCEV *> Sizes, bool CheckConsistency = true);
+
+  /// Make the ScopArrayInfo model a Fortran array.
+  /// It receives the Fortran array descriptor and stores this.
+  /// It also adds a piecewise expression for the outermost dimension
+  /// since this information is available for Fortran arrays at runtime.
+  void applyAndSetFAD(Value *FAD);
+
+  /// Get the FortranArrayDescriptor corresponding to this array if it exists,
+  /// nullptr otherwise.
+  Value *getFortranArrayDescriptor() const { return this->FAD; }
+
+  /// Set the base pointer to @p BP.
+  void setBasePtr(Value *BP) { BasePtr = BP; }
+
+  /// Return the base pointer.
+  Value *getBasePtr() const { return BasePtr; }
+
+  // Set IsOnHeap to the value in parameter.
+  void setIsOnHeap(bool value) { IsOnHeap = value; }
+
+  /// For indirect accesses return the origin SAI of the BP, else null.
+  const ScopArrayInfo *getBasePtrOriginSAI() const { return BasePtrOriginSAI; }
+
+  /// The set of derived indirect SAIs for this origin SAI.
+  const SmallSetVector<ScopArrayInfo *, 2> &getDerivedSAIs() const {
+    return DerivedSAIs;
+  }
+
+  /// Return the number of dimensions.
+  unsigned getNumberOfDimensions() const {
+    if (Kind == MemoryKind::PHI || Kind == MemoryKind::ExitPHI ||
+        Kind == MemoryKind::Value)
+      return 0;
+    return DimensionSizes.size();
+  }
+
+  /// Return the size of dimension @p dim as SCEV*.
+  //
+  //  Scalars do not have array dimensions and the first dimension of
+  //  a (possibly multi-dimensional) array also does not carry any size
+  //  information, in case the array is not newly created.
+  const SCEV *getDimensionSize(unsigned Dim) const {
+    assert(Dim < getNumberOfDimensions() && "Invalid dimension");
+    return DimensionSizes[Dim];
+  }
+
+  /// Return the size of dimension @p dim as isl::pw_aff.
+  //
+  //  Scalars do not have array dimensions and the first dimension of
+  //  a (possibly multi-dimensional) array also does not carry any size
+  //  information, in case the array is not newly created.
+  isl::pw_aff getDimensionSizePw(unsigned Dim) const {
+    assert(Dim < getNumberOfDimensions() && "Invalid dimension");
+    return DimensionSizesPw[Dim];
+  }
+
+  /// Get the canonical element type of this array.
+  ///
+  /// @returns The canonical element type of this array.
+  Type *getElementType() const { return ElementType; }
+
+  /// Get element size in bytes.
+  int getElemSizeInBytes() const;
+
+  /// Get the name of this memory reference.
+  std::string getName() const;
+
+  /// Return the isl id for the base pointer.
+  isl::id getBasePtrId() const;
+
+  /// Return what kind of memory this represents.
+  MemoryKind getKind() const { return Kind; }
+
+  /// Is this array info modeling an llvm::Value?
+  bool isValueKind() const { return Kind == MemoryKind::Value; }
+
+  /// Is this array info modeling special PHI node memory?
+  ///
+  /// During code generation of PHI nodes, there is a need for two kinds of
+  /// virtual storage. The normal one as it is used for all scalar dependences,
+  /// where the result of the PHI node is stored and later loaded from as well
+  /// as a second one where the incoming values of the PHI nodes are stored
+  /// into and reloaded when the PHI is executed. As both memories use the
+  /// original PHI node as virtual base pointer, we have this additional
+  /// attribute to distinguish the PHI node specific array modeling from the
+  /// normal scalar array modeling.
+  bool isPHIKind() const { return Kind == MemoryKind::PHI; }
+
+  /// Is this array info modeling an MemoryKind::ExitPHI?
+  bool isExitPHIKind() const { return Kind == MemoryKind::ExitPHI; }
+
+  /// Is this array info modeling an array?
+  bool isArrayKind() const { return Kind == MemoryKind::Array; }
+
+  /// Is this array allocated on heap
+  ///
+  /// This property is only relevant if the array is allocated by Polly instead
+  /// of pre-existing. If false, it is allocated using alloca instead malloca.
+  bool isOnHeap() const { return IsOnHeap; }
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  /// Dump a readable representation to stderr.
+  void dump() const;
+#endif
+
+  /// Print a readable representation to @p OS.
+  ///
+  /// @param SizeAsPwAff Print the size as isl::pw_aff
+  void print(raw_ostream &OS, bool SizeAsPwAff = false) const;
+
+  /// Access the ScopArrayInfo associated with an access function.
+  static const ScopArrayInfo *getFromAccessFunction(isl::pw_multi_aff PMA);
+
+  /// Access the ScopArrayInfo associated with an isl Id.
+  static const ScopArrayInfo *getFromId(isl::id Id);
+
+  /// Get the space of this array access.
+  isl::space getSpace() const;
+
+  /// If the array is read only
+  bool isReadOnly();
+
+  /// Verify that @p Array is compatible to this ScopArrayInfo.
+  ///
+  /// Two arrays are compatible if their dimensionality, the sizes of their
+  /// dimensions, and their element sizes match.
+  ///
+  /// @param Array The array to compare against.
+  ///
+  /// @returns True, if the arrays are compatible, False otherwise.
+  bool isCompatibleWith(const ScopArrayInfo *Array) const;
+
+private:
+  void addDerivedSAI(ScopArrayInfo *DerivedSAI) {
+    DerivedSAIs.insert(DerivedSAI);
+  }
+
+  /// For indirect accesses this is the SAI of the BP origin.
+  const ScopArrayInfo *BasePtrOriginSAI;
+
+  /// For origin SAIs the set of derived indirect SAIs.
+  SmallSetVector<ScopArrayInfo *, 2> DerivedSAIs;
+
+  /// The base pointer.
+  AssertingVH<Value> BasePtr;
+
+  /// The canonical element type of this array.
+  ///
+  /// The canonical element type describes the minimal accessible element in
+  /// this array. Not all elements accessed, need to be of the very same type,
+  /// but the allocation size of the type of the elements loaded/stored from/to
+  /// this array needs to be a multiple of the allocation size of the canonical
+  /// type.
+  Type *ElementType;
+
+  /// The isl id for the base pointer.
+  isl::id Id;
+
+  /// True if the newly allocated array is on heap.
+  bool IsOnHeap = false;
+
+  /// The sizes of each dimension as SCEV*.
+  SmallVector<const SCEV *, 4> DimensionSizes;
+
+  /// The sizes of each dimension as isl::pw_aff.
+  SmallVector<isl::pw_aff, 4> DimensionSizesPw;
+
+  /// The type of this scop array info object.
+  ///
+  /// We distinguish between SCALAR, PHI and ARRAY objects.
+  MemoryKind Kind;
+
+  /// The data layout of the module.
+  const DataLayout &DL;
+
+  /// The scop this SAI object belongs to.
+  Scop &S;
+
+  /// If this array models a Fortran array, then this points
+  /// to the Fortran array descriptor.
+  Value *FAD = nullptr;
+};
+
+/// Represent memory accesses in statements.
+class MemoryAccess {
+  friend class Scop;
+  friend class ScopStmt;
+  friend class ScopBuilder;
+
+public:
+  /// The access type of a memory access
+  ///
+  /// There are three kind of access types:
+  ///
+  /// * A read access
+  ///
+  /// A certain set of memory locations are read and may be used for internal
+  /// calculations.
+  ///
+  /// * A must-write access
+  ///
+  /// A certain set of memory locations is definitely written. The old value is
+  /// replaced by a newly calculated value. The old value is not read or used at
+  /// all.
+  ///
+  /// * A may-write access
+  ///
+  /// A certain set of memory locations may be written. The memory location may
+  /// contain a new value if there is actually a write or the old value may
+  /// remain, if no write happens.
+  enum AccessType {
+    READ = 0x1,
+    MUST_WRITE = 0x2,
+    MAY_WRITE = 0x3,
+  };
+
+  /// Reduction access type
+  ///
+  /// Commutative and associative binary operations suitable for reductions
+  enum ReductionType {
+    RT_NONE, ///< Indicate no reduction at all
+    RT_ADD,  ///< Addition
+    RT_MUL,  ///< Multiplication
+    RT_BOR,  ///< Bitwise Or
+    RT_BXOR, ///< Bitwise XOr
+    RT_BAND, ///< Bitwise And
+  };
+
+private:
+  /// A unique identifier for this memory access.
+  ///
+  /// The identifier is unique between all memory accesses belonging to the same
+  /// scop statement.
+  isl::id Id;
+
+  /// What is modeled by this MemoryAccess.
+  /// @see MemoryKind
+  MemoryKind Kind;
+
+  /// Whether it a reading or writing access, and if writing, whether it
+  /// is conditional (MAY_WRITE).
+  enum AccessType AccType;
+
+  /// Reduction type for reduction like accesses, RT_NONE otherwise
+  ///
+  /// An access is reduction like if it is part of a load-store chain in which
+  /// both access the same memory location (use the same LLVM-IR value
+  /// as pointer reference). Furthermore, between the load and the store there
+  /// is exactly one binary operator which is known to be associative and
+  /// commutative.
+  ///
+  /// TODO:
+  ///
+  /// We can later lift the constraint that the same LLVM-IR value defines the
+  /// memory location to handle scops such as the following:
+  ///
+  ///    for i
+  ///      for j
+  ///        sum[i+j] = sum[i] + 3;
+  ///
+  /// Here not all iterations access the same memory location, but iterations
+  /// for which j = 0 holds do. After lifting the equality check in ScopBuilder,
+  /// subsequent transformations do not only need check if a statement is
+  /// reduction like, but they also need to verify that that the reduction
+  /// property is only exploited for statement instances that load from and
+  /// store to the same data location. Doing so at dependence analysis time
+  /// could allow us to handle the above example.
+  ReductionType RedType = RT_NONE;
+
+  /// Parent ScopStmt of this access.
+  ScopStmt *Statement;
+
+  /// The domain under which this access is not modeled precisely.
+  ///
+  /// The invalid domain for an access describes all parameter combinations
+  /// under which the statement looks to be executed but is in fact not because
+  /// some assumption/restriction makes the access invalid.
+  isl::set InvalidDomain;
+
+  // Properties describing the accessed array.
+  // TODO: It might be possible to move them to ScopArrayInfo.
+  // @{
+
+  /// The base address (e.g., A for A[i+j]).
+  ///
+  /// The #BaseAddr of a memory access of kind MemoryKind::Array is the base
+  /// pointer of the memory access.
+  /// The #BaseAddr of a memory access of kind MemoryKind::PHI or
+  /// MemoryKind::ExitPHI is the PHI node itself.
+  /// The #BaseAddr of a memory access of kind MemoryKind::Value is the
+  /// instruction defining the value.
+  AssertingVH<Value> BaseAddr;
+
+  /// Type a single array element wrt. this access.
+  Type *ElementType;
+
+  /// Size of each dimension of the accessed array.
+  SmallVector<const SCEV *, 4> Sizes;
+  // @}
+
+  // Properties describing the accessed element.
+  // @{
+
+  /// The access instruction of this memory access.
+  ///
+  /// For memory accesses of kind MemoryKind::Array the access instruction is
+  /// the Load or Store instruction performing the access.
+  ///
+  /// For memory accesses of kind MemoryKind::PHI or MemoryKind::ExitPHI the
+  /// access instruction of a load access is the PHI instruction. The access
+  /// instruction of a PHI-store is the incoming's block's terminator
+  /// instruction.
+  ///
+  /// For memory accesses of kind MemoryKind::Value the access instruction of a
+  /// load access is nullptr because generally there can be multiple
+  /// instructions in the statement using the same llvm::Value. The access
+  /// instruction of a write access is the instruction that defines the
+  /// llvm::Value.
+  Instruction *AccessInstruction = nullptr;
+
+  /// Incoming block and value of a PHINode.
+  SmallVector<std::pair<BasicBlock *, Value *>, 4> Incoming;
+
+  /// The value associated with this memory access.
+  ///
+  ///  - For array memory accesses (MemoryKind::Array) it is the loaded result
+  ///    or the stored value. If the access instruction is a memory intrinsic it
+  ///    the access value is also the memory intrinsic.
+  ///  - For accesses of kind MemoryKind::Value it is the access instruction
+  ///    itself.
+  ///  - For accesses of kind MemoryKind::PHI or MemoryKind::ExitPHI it is the
+  ///    PHI node itself (for both, READ and WRITE accesses).
+  ///
+  AssertingVH<Value> AccessValue;
+
+  /// Are all the subscripts affine expression?
+  bool IsAffine = true;
+
+  /// Subscript expression for each dimension.
+  SmallVector<const SCEV *, 4> Subscripts;
+
+  /// Relation from statement instances to the accessed array elements.
+  ///
+  /// In the common case this relation is a function that maps a set of loop
+  /// indices to the memory address from which a value is loaded/stored:
+  ///
+  ///      for i
+  ///        for j
+  ///    S:     A[i + 3 j] = ...
+  ///
+  ///    => { S[i,j] -> A[i + 3j] }
+  ///
+  /// In case the exact access function is not known, the access relation may
+  /// also be a one to all mapping { S[i,j] -> A[o] } describing that any
+  /// element accessible through A might be accessed.
+  ///
+  /// In case of an access to a larger element belonging to an array that also
+  /// contains smaller elements, the access relation models the larger access
+  /// with multiple smaller accesses of the size of the minimal array element
+  /// type:
+  ///
+  ///      short *A;
+  ///
+  ///      for i
+  ///    S:     A[i] = *((double*)&A[4 * i]);
+  ///
+  ///    => { S[i] -> A[i]; S[i] -> A[o] : 4i <= o <= 4i + 3 }
+  isl::map AccessRelation;
+
+  /// Updated access relation read from JSCOP file.
+  isl::map NewAccessRelation;
+
+  /// Fortran arrays whose sizes are not statically known are stored in terms
+  /// of a descriptor struct. This maintains a raw pointer to the memory,
+  /// along with auxiliary fields with information such as dimensions.
+  /// We hold a reference to the descriptor corresponding to a MemoryAccess
+  /// into a Fortran array. FAD for "Fortran Array Descriptor"
+  AssertingVH<Value> FAD;
+  // @}
+
+  isl::basic_map createBasicAccessMap(ScopStmt *Statement);
+
+  void assumeNoOutOfBound();
+
+  /// Compute bounds on an over approximated  access relation.
+  ///
+  /// @param ElementSize The size of one element accessed.
+  void computeBoundsOnAccessRelation(unsigned ElementSize);
+
+  /// Get the original access function as read from IR.
+  isl::map getOriginalAccessRelation() const;
+
+  /// Return the space in which the access relation lives in.
+  isl::space getOriginalAccessRelationSpace() const;
+
+  /// Get the new access function imported or set by a pass
+  isl::map getNewAccessRelation() const;
+
+  /// Fold the memory access to consider parametric offsets
+  ///
+  /// To recover memory accesses with array size parameters in the subscript
+  /// expression we post-process the delinearization results.
+  ///
+  /// We would normally recover from an access A[exp0(i) * N + exp1(i)] into an
+  /// array A[][N] the 2D access A[exp0(i)][exp1(i)]. However, another valid
+  /// delinearization is A[exp0(i) - 1][exp1(i) + N] which - depending on the
+  /// range of exp1(i) - may be preferable. Specifically, for cases where we
+  /// know exp1(i) is negative, we want to choose the latter expression.
+  ///
+  /// As we commonly do not have any information about the range of exp1(i),
+  /// we do not choose one of the two options, but instead create a piecewise
+  /// access function that adds the (-1, N) offsets as soon as exp1(i) becomes
+  /// negative. For a 2D array such an access function is created by applying
+  /// the piecewise map:
+  ///
+  /// [i,j] -> [i, j] :      j >= 0
+  /// [i,j] -> [i-1, j+N] :  j <  0
+  ///
+  /// We can generalize this mapping to arbitrary dimensions by applying this
+  /// piecewise mapping pairwise from the rightmost to the leftmost access
+  /// dimension. It would also be possible to cover a wider range by introducing
+  /// more cases and adding multiple of Ns to these cases. However, this has
+  /// not yet been necessary.
+  /// The introduction of different cases necessarily complicates the memory
+  /// access function, but cases that can be statically proven to not happen
+  /// will be eliminated later on.
+  void foldAccessRelation();
+
+  /// Create the access relation for the underlying memory intrinsic.
+  void buildMemIntrinsicAccessRelation();
+
+  /// Assemble the access relation from all available information.
+  ///
+  /// In particular, used the information passes in the constructor and the
+  /// parent ScopStmt set by setStatment().
+  ///
+  /// @param SAI Info object for the accessed array.
+  void buildAccessRelation(const ScopArrayInfo *SAI);
+
+  /// Carry index overflows of dimensions with constant size to the next higher
+  /// dimension.
+  ///
+  /// For dimensions that have constant size, modulo the index by the size and
+  /// add up the carry (floored division) to the next higher dimension. This is
+  /// how overflow is defined in row-major order.
+  /// It happens e.g. when ScalarEvolution computes the offset to the base
+  /// pointer and would algebraically sum up all lower dimensions' indices of
+  /// constant size.
+  ///
+  /// Example:
+  ///   float (*A)[4];
+  ///   A[1][6] -> A[2][2]
+  void wrapConstantDimensions();
+
+public:
+  /// Create a new MemoryAccess.
+  ///
+  /// @param Stmt       The parent statement.
+  /// @param AccessInst The instruction doing the access.
+  /// @param BaseAddr   The accessed array's address.
+  /// @param ElemType   The type of the accessed array elements.
+  /// @param AccType    Whether read or write access.
+  /// @param IsAffine   Whether the subscripts are affine expressions.
+  /// @param Kind       The kind of memory accessed.
+  /// @param Subscripts Subscript expressions
+  /// @param Sizes      Dimension lengths of the accessed array.
+  MemoryAccess(ScopStmt *Stmt, Instruction *AccessInst, AccessType AccType,
+               Value *BaseAddress, Type *ElemType, bool Affine,
+               ArrayRef<const SCEV *> Subscripts, ArrayRef<const SCEV *> Sizes,
+               Value *AccessValue, MemoryKind Kind);
+
+  /// Create a new MemoryAccess that corresponds to @p AccRel.
+  ///
+  /// Along with @p Stmt and @p AccType it uses information about dimension
+  /// lengths of the accessed array, the type of the accessed array elements,
+  /// the name of the accessed array that is derived from the object accessible
+  /// via @p AccRel.
+  ///
+  /// @param Stmt       The parent statement.
+  /// @param AccType    Whether read or write access.
+  /// @param AccRel     The access relation that describes the memory access.
+  MemoryAccess(ScopStmt *Stmt, AccessType AccType, isl::map AccRel);
+
+  MemoryAccess(const MemoryAccess &) = delete;
+  MemoryAccess &operator=(const MemoryAccess &) = delete;
+  ~MemoryAccess();
+
+  /// Add a new incoming block/value pairs for this PHI/ExitPHI access.
+  ///
+  /// @param IncomingBlock The PHI's incoming block.
+  /// @param IncomingValue The value when reaching the PHI from the @p
+  ///                      IncomingBlock.
+  void addIncoming(BasicBlock *IncomingBlock, Value *IncomingValue) {
+    assert(!isRead());
+    assert(isAnyPHIKind());
+    Incoming.emplace_back(std::make_pair(IncomingBlock, IncomingValue));
+  }
+
+  /// Return the list of possible PHI/ExitPHI values.
+  ///
+  /// After code generation moves some PHIs around during region simplification,
+  /// we cannot reliably locate the original PHI node and its incoming values
+  /// anymore. For this reason we remember these explicitly for all PHI-kind
+  /// accesses.
+  ArrayRef<std::pair<BasicBlock *, Value *>> getIncoming() const {
+    assert(isAnyPHIKind());
+    return Incoming;
+  }
+
+  /// Get the type of a memory access.
+  enum AccessType getType() { return AccType; }
+
+  /// Is this a reduction like access?
+  bool isReductionLike() const { return RedType != RT_NONE; }
+
+  /// Is this a read memory access?
+  bool isRead() const { return AccType == MemoryAccess::READ; }
+
+  /// Is this a must-write memory access?
+  bool isMustWrite() const { return AccType == MemoryAccess::MUST_WRITE; }
+
+  /// Is this a may-write memory access?
+  bool isMayWrite() const { return AccType == MemoryAccess::MAY_WRITE; }
+
+  /// Is this a write memory access?
+  bool isWrite() const { return isMustWrite() || isMayWrite(); }
+
+  /// Is this a memory intrinsic access (memcpy, memset, memmove)?
+  bool isMemoryIntrinsic() const {
+    return isa<MemIntrinsic>(getAccessInstruction());
+  }
+
+  /// Check if a new access relation was imported or set by a pass.
+  bool hasNewAccessRelation() const { return !NewAccessRelation.is_null(); }
+
+  /// Return the newest access relation of this access.
+  ///
+  /// There are two possibilities:
+  ///   1) The original access relation read from the LLVM-IR.
+  ///   2) A new access relation imported from a json file or set by another
+  ///      pass (e.g., for privatization).
+  ///
+  /// As 2) is by construction "newer" than 1) we return the new access
+  /// relation if present.
+  ///
+  isl::map getLatestAccessRelation() const {
+    return hasNewAccessRelation() ? getNewAccessRelation()
+                                  : getOriginalAccessRelation();
+  }
+
+  /// Old name of getLatestAccessRelation().
+  isl::map getAccessRelation() const { return getLatestAccessRelation(); }
+
+  /// Get an isl map describing the memory address accessed.
+  ///
+  /// In most cases the memory address accessed is well described by the access
+  /// relation obtained with getAccessRelation. However, in case of arrays
+  /// accessed with types of different size the access relation maps one access
+  /// to multiple smaller address locations. This method returns an isl map that
+  /// relates each dynamic statement instance to the unique memory location
+  /// that is loaded from / stored to.
+  ///
+  /// For an access relation { S[i] -> A[o] : 4i <= o <= 4i + 3 } this method
+  /// will return the address function { S[i] -> A[4i] }.
+  ///
+  /// @returns The address function for this memory access.
+  isl::map getAddressFunction() const;
+
+  /// Return the access relation after the schedule was applied.
+  isl::pw_multi_aff
+  applyScheduleToAccessRelation(isl::union_map Schedule) const;
+
+  /// Get an isl string representing the access function read from IR.
+  std::string getOriginalAccessRelationStr() const;
+
+  /// Get an isl string representing a new access function, if available.
+  std::string getNewAccessRelationStr() const;
+
+  /// Get an isl string representing the latest access relation.
+  std::string getAccessRelationStr() const;
+
+  /// Get the original base address of this access (e.g. A for A[i+j]) when
+  /// detected.
+  ///
+  /// This address may differ from the base address referenced by the original
+  /// ScopArrayInfo to which this array belongs, as this memory access may
+  /// have been canonicalized to a ScopArrayInfo which has a different but
+  /// identically-valued base pointer in case invariant load hoisting is
+  /// enabled.
+  Value *getOriginalBaseAddr() const { return BaseAddr; }
+
+  /// Get the detection-time base array isl::id for this access.
+  isl::id getOriginalArrayId() const;
+
+  /// Get the base array isl::id for this access, modifiable through
+  /// setNewAccessRelation().
+  isl::id getLatestArrayId() const;
+
+  /// Old name of getOriginalArrayId().
+  isl::id getArrayId() const { return getOriginalArrayId(); }
+
+  /// Get the detection-time ScopArrayInfo object for the base address.
+  const ScopArrayInfo *getOriginalScopArrayInfo() const;
+
+  /// Get the ScopArrayInfo object for the base address, or the one set
+  /// by setNewAccessRelation().
+  const ScopArrayInfo *getLatestScopArrayInfo() const;
+
+  /// Legacy name of getOriginalScopArrayInfo().
+  const ScopArrayInfo *getScopArrayInfo() const {
+    return getOriginalScopArrayInfo();
+  }
+
+  /// Return a string representation of the access's reduction type.
+  const std::string getReductionOperatorStr() const;
+
+  /// Return a string representation of the reduction type @p RT.
+  static const std::string getReductionOperatorStr(ReductionType RT);
+
+  /// Return the element type of the accessed array wrt. this access.
+  Type *getElementType() const { return ElementType; }
+
+  /// Return the access value of this memory access.
+  Value *getAccessValue() const { return AccessValue; }
+
+  /// Return llvm::Value that is stored by this access, if available.
+  ///
+  /// PHI nodes may not have a unique value available that is stored, as in
+  /// case of region statements one out of possibly several llvm::Values
+  /// might be stored. In this case nullptr is returned.
+  Value *tryGetValueStored() {
+    assert(isWrite() && "Only write statement store values");
+    if (isAnyPHIKind()) {
+      if (Incoming.size() == 1)
+        return Incoming[0].second;
+      return nullptr;
+    }
+    return AccessValue;
+  }
+
+  /// Return the access instruction of this memory access.
+  Instruction *getAccessInstruction() const { return AccessInstruction; }
+
+  /// Return the number of access function subscript.
+  unsigned getNumSubscripts() const { return Subscripts.size(); }
+
+  /// Return the access function subscript in the dimension @p Dim.
+  const SCEV *getSubscript(unsigned Dim) const { return Subscripts[Dim]; }
+
+  /// Compute the isl representation for the SCEV @p E wrt. this access.
+  ///
+  /// Note that this function will also adjust the invalid context accordingly.
+  isl::pw_aff getPwAff(const SCEV *E);
+
+  /// Get the invalid domain for this access.
+  isl::set getInvalidDomain() const { return InvalidDomain; }
+
+  /// Get the invalid context for this access.
+  isl::set getInvalidContext() const { return getInvalidDomain().params(); }
+
+  /// Get the stride of this memory access in the specified Schedule. Schedule
+  /// is a map from the statement to a schedule where the innermost dimension is
+  /// the dimension of the innermost loop containing the statement.
+  isl::set getStride(isl::map Schedule) const;
+
+  /// Get the FortranArrayDescriptor corresponding to this memory access if
+  /// it exists, and nullptr otherwise.
+  Value *getFortranArrayDescriptor() const { return this->FAD; }
+
+  /// Is the stride of the access equal to a certain width? Schedule is a map
+  /// from the statement to a schedule where the innermost dimension is the
+  /// dimension of the innermost loop containing the statement.
+  bool isStrideX(isl::map Schedule, int StrideWidth) const;
+
+  /// Is consecutive memory accessed for a given statement instance set?
+  /// Schedule is a map from the statement to a schedule where the innermost
+  /// dimension is the dimension of the innermost loop containing the
+  /// statement.
+  bool isStrideOne(isl::map Schedule) const;
+
+  /// Is always the same memory accessed for a given statement instance set?
+  /// Schedule is a map from the statement to a schedule where the innermost
+  /// dimension is the dimension of the innermost loop containing the
+  /// statement.
+  bool isStrideZero(isl::map Schedule) const;
+
+  /// Return the kind when this access was first detected.
+  MemoryKind getOriginalKind() const {
+    assert(!getOriginalScopArrayInfo() /* not yet initialized */ ||
+           getOriginalScopArrayInfo()->getKind() == Kind);
+    return Kind;
+  }
+
+  /// Return the kind considering a potential setNewAccessRelation.
+  MemoryKind getLatestKind() const {
+    return getLatestScopArrayInfo()->getKind();
+  }
+
+  /// Whether this is an access of an explicit load or store in the IR.
+  bool isOriginalArrayKind() const {
+    return getOriginalKind() == MemoryKind::Array;
+  }
+
+  /// Whether storage memory is either an custom .s2a/.phiops alloca
+  /// (false) or an existing pointer into an array (true).
+  bool isLatestArrayKind() const {
+    return getLatestKind() == MemoryKind::Array;
+  }
+
+  /// Old name of isOriginalArrayKind.
+  bool isArrayKind() const { return isOriginalArrayKind(); }
+
+  /// Whether this access is an array to a scalar memory object, without
+  /// considering changes by setNewAccessRelation.
+  ///
+  /// Scalar accesses are accesses to MemoryKind::Value, MemoryKind::PHI or
+  /// MemoryKind::ExitPHI.
+  bool isOriginalScalarKind() const {
+    return getOriginalKind() != MemoryKind::Array;
+  }
+
+  /// Whether this access is an array to a scalar memory object, also
+  /// considering changes by setNewAccessRelation.
+  bool isLatestScalarKind() const {
+    return getLatestKind() != MemoryKind::Array;
+  }
+
+  /// Old name of isOriginalScalarKind.
+  bool isScalarKind() const { return isOriginalScalarKind(); }
+
+  /// Was this MemoryAccess detected as a scalar dependences?
+  bool isOriginalValueKind() const {
+    return getOriginalKind() == MemoryKind::Value;
+  }
+
+  /// Is this MemoryAccess currently modeling scalar dependences?
+  bool isLatestValueKind() const {
+    return getLatestKind() == MemoryKind::Value;
+  }
+
+  /// Old name of isOriginalValueKind().
+  bool isValueKind() const { return isOriginalValueKind(); }
+
+  /// Was this MemoryAccess detected as a special PHI node access?
+  bool isOriginalPHIKind() const {
+    return getOriginalKind() == MemoryKind::PHI;
+  }
+
+  /// Is this MemoryAccess modeling special PHI node accesses, also
+  /// considering a potential change by setNewAccessRelation?
+  bool isLatestPHIKind() const { return getLatestKind() == MemoryKind::PHI; }
+
+  /// Old name of isOriginalPHIKind.
+  bool isPHIKind() const { return isOriginalPHIKind(); }
+
+  /// Was this MemoryAccess detected as the accesses of a PHI node in the
+  /// SCoP's exit block?
+  bool isOriginalExitPHIKind() const {
+    return getOriginalKind() == MemoryKind::ExitPHI;
+  }
+
+  /// Is this MemoryAccess modeling the accesses of a PHI node in the
+  /// SCoP's exit block? Can be changed to an array access using
+  /// setNewAccessRelation().
+  bool isLatestExitPHIKind() const {
+    return getLatestKind() == MemoryKind::ExitPHI;
+  }
+
+  /// Old name of isOriginalExitPHIKind().
+  bool isExitPHIKind() const { return isOriginalExitPHIKind(); }
+
+  /// Was this access detected as one of the two PHI types?
+  bool isOriginalAnyPHIKind() const {
+    return isOriginalPHIKind() || isOriginalExitPHIKind();
+  }
+
+  /// Does this access originate from one of the two PHI types? Can be
+  /// changed to an array access using setNewAccessRelation().
+  bool isLatestAnyPHIKind() const {
+    return isLatestPHIKind() || isLatestExitPHIKind();
+  }
+
+  /// Old name of isOriginalAnyPHIKind().
+  bool isAnyPHIKind() const { return isOriginalAnyPHIKind(); }
+
+  /// Get the statement that contains this memory access.
+  ScopStmt *getStatement() const { return Statement; }
+
+  /// Get the reduction type of this access
+  ReductionType getReductionType() const { return RedType; }
+
+  /// Set the array descriptor corresponding to the Array on which the
+  /// memory access is performed.
+  void setFortranArrayDescriptor(Value *FAD);
+
+  /// Update the original access relation.
+  ///
+  /// We need to update the original access relation during scop construction,
+  /// when unifying the memory accesses that access the same scop array info
+  /// object. After the scop has been constructed, the original access relation
+  /// should not be changed any more. Instead setNewAccessRelation should
+  /// be called.
+  void setAccessRelation(isl::map AccessRelation);
+
+  /// Set the updated access relation read from JSCOP file.
+  void setNewAccessRelation(isl::map NewAccessRelation);
+
+  /// Return whether the MemoryyAccess is a partial access. That is, the access
+  /// is not executed in some instances of the parent statement's domain.
+  bool isLatestPartialAccess() const;
+
+  /// Mark this a reduction like access
+  void markAsReductionLike(ReductionType RT) { RedType = RT; }
+
+  /// Align the parameters in the access relation to the scop context
+  void realignParams();
+
+  /// Update the dimensionality of the memory access.
+  ///
+  /// During scop construction some memory accesses may not be constructed with
+  /// their full dimensionality, but outer dimensions may have been omitted if
+  /// they took the value 'zero'. By updating the dimensionality of the
+  /// statement we add additional zero-valued dimensions to match the
+  /// dimensionality of the ScopArrayInfo object that belongs to this memory
+  /// access.
+  void updateDimensionality();
+
+  /// Get identifier for the memory access.
+  ///
+  /// This identifier is unique for all accesses that belong to the same scop
+  /// statement.
+  isl::id getId() const;
+
+  /// Print the MemoryAccess.
+  ///
+  /// @param OS The output stream the MemoryAccess is printed to.
+  void print(raw_ostream &OS) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  /// Print the MemoryAccess to stderr.
+  void dump() const;
+#endif
+
+  /// Is the memory access affine?
+  bool isAffine() const { return IsAffine; }
+};
+
+raw_ostream &operator<<(raw_ostream &OS, MemoryAccess::ReductionType RT);
+
+/// Ordered list type to hold accesses.
+using MemoryAccessList = std::forward_list<MemoryAccess *>;
+
+/// Helper structure for invariant memory accesses.
+struct InvariantAccess {
+  /// The memory access that is (partially) invariant.
+  MemoryAccess *MA;
+
+  /// The context under which the access is not invariant.
+  isl::set NonHoistableCtx;
+};
+
+/// Ordered container type to hold invariant accesses.
+using InvariantAccessesTy = SmallVector<InvariantAccess, 8>;
+
+/// Type for equivalent invariant accesses and their domain context.
+struct InvariantEquivClassTy {
+  /// The pointer that identifies this equivalence class
+  const SCEV *IdentifyingPointer;
+
+  /// Memory accesses now treated invariant
+  ///
+  /// These memory accesses access the pointer location that identifies
+  /// this equivalence class. They are treated as invariant and hoisted during
+  /// code generation.
+  MemoryAccessList InvariantAccesses;
+
+  /// The execution context under which the memory location is accessed
+  ///
+  /// It is the union of the execution domains of the memory accesses in the
+  /// InvariantAccesses list.
+  isl::set ExecutionContext;
+
+  /// The type of the invariant access
+  ///
+  /// It is used to differentiate between differently typed invariant loads from
+  /// the same location.
+  Type *AccessType;
+};
+
+/// Type for invariant accesses equivalence classes.
+using InvariantEquivClassesTy = SmallVector<InvariantEquivClassTy, 8>;
+
+/// Statement of the Scop
+///
+/// A Scop statement represents an instruction in the Scop.
+///
+/// It is further described by its iteration domain, its schedule and its data
+/// accesses.
+/// At the moment every statement represents a single basic block of LLVM-IR.
+class ScopStmt {
+  friend class ScopBuilder;
+
+public:
+  /// Create the ScopStmt from a BasicBlock.
+  ScopStmt(Scop &parent, BasicBlock &bb, Loop *SurroundingLoop,
+           std::vector<Instruction *> Instructions, int Count);
+
+  /// Create an overapproximating ScopStmt for the region @p R.
+  ///
+  /// @param EntryBlockInstructions The list of instructions that belong to the
+  ///                               entry block of the region statement.
+  ///                               Instructions are only tracked for entry
+  ///                               blocks for now. We currently do not allow
+  ///                               to modify the instructions of blocks later
+  ///                               in the region statement.
+  ScopStmt(Scop &parent, Region &R, Loop *SurroundingLoop,
+           std::vector<Instruction *> EntryBlockInstructions);
+
+  /// Create a copy statement.
+  ///
+  /// @param Stmt       The parent statement.
+  /// @param SourceRel  The source location.
+  /// @param TargetRel  The target location.
+  /// @param Domain     The original domain under which the copy statement would
+  ///                   be executed.
+  ScopStmt(Scop &parent, isl::map SourceRel, isl::map TargetRel,
+           isl::set Domain);
+
+  ScopStmt(const ScopStmt &) = delete;
+  const ScopStmt &operator=(const ScopStmt &) = delete;
+  ~ScopStmt();
+
+private:
+  /// Polyhedral description
+  //@{
+
+  /// The Scop containing this ScopStmt.
+  Scop &Parent;
+
+  /// The domain under which this statement is not modeled precisely.
+  ///
+  /// The invalid domain for a statement describes all parameter combinations
+  /// under which the statement looks to be executed but is in fact not because
+  /// some assumption/restriction makes the statement/scop invalid.
+  isl::set InvalidDomain;
+
+  /// The iteration domain describes the set of iterations for which this
+  /// statement is executed.
+  ///
+  /// Example:
+  ///     for (i = 0; i < 100 + b; ++i)
+  ///       for (j = 0; j < i; ++j)
+  ///         S(i,j);
+  ///
+  /// 'S' is executed for different values of i and j. A vector of all
+  /// induction variables around S (i, j) is called iteration vector.
+  /// The domain describes the set of possible iteration vectors.
+  ///
+  /// In this case it is:
+  ///
+  ///     Domain: 0 <= i <= 100 + b
+  ///             0 <= j <= i
+  ///
+  /// A pair of statement and iteration vector (S, (5,3)) is called statement
+  /// instance.
+  isl::set Domain;
+
+  /// The memory accesses of this statement.
+  ///
+  /// The only side effects of a statement are its memory accesses.
+  using MemoryAccessVec = SmallVector<MemoryAccess *, 8>;
+  MemoryAccessVec MemAccs;
+
+  /// Mapping from instructions to (scalar) memory accesses.
+  DenseMap<const Instruction *, MemoryAccessList> InstructionToAccess;
+
+  /// The set of values defined elsewhere required in this ScopStmt and
+  ///        their MemoryKind::Value READ MemoryAccesses.
+  DenseMap<Value *, MemoryAccess *> ValueReads;
+
+  /// The set of values defined in this ScopStmt that are required
+  ///        elsewhere, mapped to their MemoryKind::Value WRITE MemoryAccesses.
+  DenseMap<Instruction *, MemoryAccess *> ValueWrites;
+
+  /// Map from PHI nodes to its incoming value when coming from this
+  ///        statement.
+  ///
+  /// Non-affine subregions can have multiple exiting blocks that are incoming
+  /// blocks of the PHI nodes. This map ensures that there is only one write
+  /// operation for the complete subregion. A PHI selecting the relevant value
+  /// will be inserted.
+  DenseMap<PHINode *, MemoryAccess *> PHIWrites;
+
+  /// Map from PHI nodes to its read access in this statement.
+  DenseMap<PHINode *, MemoryAccess *> PHIReads;
+
+  //@}
+
+  /// A SCoP statement represents either a basic block (affine/precise case) or
+  /// a whole region (non-affine case).
+  ///
+  /// Only one of the following two members will therefore be set and indicate
+  /// which kind of statement this is.
+  ///
+  ///{
+
+  /// The BasicBlock represented by this statement (in the affine case).
+  BasicBlock *BB = nullptr;
+
+  /// The region represented by this statement (in the non-affine case).
+  Region *R = nullptr;
+
+  ///}
+
+  /// The isl AST build for the new generated AST.
+  isl::ast_build Build;
+
+  SmallVector<Loop *, 4> NestLoops;
+
+  std::string BaseName;
+
+  /// The closest loop that contains this statement.
+  Loop *SurroundingLoop;
+
+  /// Vector for Instructions in this statement.
+  std::vector<Instruction *> Instructions;
+
+  /// Remove @p MA from dictionaries pointing to them.
+  void removeAccessData(MemoryAccess *MA);
+
+public:
+  /// Get an isl_ctx pointer.
+  isl::ctx getIslCtx() const;
+
+  /// Get the iteration domain of this ScopStmt.
+  ///
+  /// @return The iteration domain of this ScopStmt.
+  isl::set getDomain() const;
+
+  /// Get the space of the iteration domain
+  ///
+  /// @return The space of the iteration domain
+  isl::space getDomainSpace() const;
+
+  /// Get the id of the iteration domain space
+  ///
+  /// @return The id of the iteration domain space
+  isl::id getDomainId() const;
+
+  /// Get an isl string representing this domain.
+  std::string getDomainStr() const;
+
+  /// Get the schedule function of this ScopStmt.
+  ///
+  /// @return The schedule function of this ScopStmt, if it does not contain
+  /// extension nodes, and nullptr, otherwise.
+  isl::map getSchedule() const;
+
+  /// Get an isl string representing this schedule.
+  ///
+  /// @return An isl string representing this schedule, if it does not contain
+  /// extension nodes, and an empty string, otherwise.
+  std::string getScheduleStr() const;
+
+  /// Get the invalid domain for this statement.
+  isl::set getInvalidDomain() const { return InvalidDomain; }
+
+  /// Get the invalid context for this statement.
+  isl::set getInvalidContext() const { return getInvalidDomain().params(); }
+
+  /// Set the invalid context for this statement to @p ID.
+  void setInvalidDomain(isl::set ID);
+
+  /// Get the BasicBlock represented by this ScopStmt (if any).
+  ///
+  /// @return The BasicBlock represented by this ScopStmt, or null if the
+  ///         statement represents a region.
+  BasicBlock *getBasicBlock() const { return BB; }
+
+  /// Return true if this statement represents a single basic block.
+  bool isBlockStmt() const { return BB != nullptr; }
+
+  /// Return true if this is a copy statement.
+  bool isCopyStmt() const { return BB == nullptr && R == nullptr; }
+
+  /// Get the region represented by this ScopStmt (if any).
+  ///
+  /// @return The region represented by this ScopStmt, or null if the statement
+  ///         represents a basic block.
+  Region *getRegion() const { return R; }
+
+  /// Return true if this statement represents a whole region.
+  bool isRegionStmt() const { return R != nullptr; }
+
+  /// Return a BasicBlock from this statement.
+  ///
+  /// For block statements, it returns the BasicBlock itself. For subregion
+  /// statements, return its entry block.
+  BasicBlock *getEntryBlock() const;
+
+  /// Return whether @p L is boxed within this statement.
+  bool contains(const Loop *L) const {
+    // Block statements never contain loops.
+    if (isBlockStmt())
+      return false;
+
+    return getRegion()->contains(L);
+  }
+
+  /// Return whether this statement represents @p BB.
+  bool represents(BasicBlock *BB) const {
+    if (isCopyStmt())
+      return false;
+    if (isBlockStmt())
+      return BB == getBasicBlock();
+    return getRegion()->contains(BB);
+  }
+
+  /// Return whether this statement contains @p Inst.
+  bool contains(Instruction *Inst) const {
+    if (!Inst)
+      return false;
+    if (isBlockStmt())
+      return std::find(Instructions.begin(), Instructions.end(), Inst) !=
+             Instructions.end();
+    return represents(Inst->getParent());
+  }
+
+  /// Return the closest innermost loop that contains this statement, but is not
+  /// contained in it.
+  ///
+  /// For block statement, this is just the loop that contains the block. Region
+  /// statements can contain boxed loops, so getting the loop of one of the
+  /// region's BBs might return such an inner loop. For instance, the region's
+  /// entry could be a header of a loop, but the region might extend to BBs
+  /// after the loop exit. Similarly, the region might only contain parts of the
+  /// loop body and still include the loop header.
+  ///
+  /// Most of the time the surrounding loop is the top element of #NestLoops,
+  /// except when it is empty. In that case it return the loop that the whole
+  /// SCoP is contained in. That can be nullptr if there is no such loop.
+  Loop *getSurroundingLoop() const {
+    assert(!isCopyStmt() &&
+           "No surrounding loop for artificially created statements");
+    return SurroundingLoop;
+  }
+
+  /// Return true if this statement does not contain any accesses.
+  bool isEmpty() const { return MemAccs.empty(); }
+
+  /// Find all array accesses for @p Inst.
+  ///
+  /// @param Inst The instruction accessing an array.
+  ///
+  /// @return A list of array accesses (MemoryKind::Array) accessed by @p Inst.
+  ///         If there is no such access, it returns nullptr.
+  const MemoryAccessList *
+  lookupArrayAccessesFor(const Instruction *Inst) const {
+    auto It = InstructionToAccess.find(Inst);
+    if (It == InstructionToAccess.end())
+      return nullptr;
+    if (It->second.empty())
+      return nullptr;
+    return &It->second;
+  }
+
+  /// Return the only array access for @p Inst, if existing.
+  ///
+  /// @param Inst The instruction for which to look up the access.
+  /// @returns The unique array memory access related to Inst or nullptr if
+  ///          no array access exists
+  MemoryAccess *getArrayAccessOrNULLFor(const Instruction *Inst) const {
+    auto It = InstructionToAccess.find(Inst);
+    if (It == InstructionToAccess.end())
+      return nullptr;
+
+    MemoryAccess *ArrayAccess = nullptr;
+
+    for (auto Access : It->getSecond()) {
+      if (!Access->isArrayKind())
+        continue;
+
+      assert(!ArrayAccess && "More then one array access for instruction");
+
+      ArrayAccess = Access;
+    }
+
+    return ArrayAccess;
+  }
+
+  /// Return the only array access for @p Inst.
+  ///
+  /// @param Inst The instruction for which to look up the access.
+  /// @returns The unique array memory access related to Inst.
+  MemoryAccess &getArrayAccessFor(const Instruction *Inst) const {
+    MemoryAccess *ArrayAccess = getArrayAccessOrNULLFor(Inst);
+
+    assert(ArrayAccess && "No array access found for instruction!");
+    return *ArrayAccess;
+  }
+
+  /// Return the MemoryAccess that writes the value of an instruction
+  ///        defined in this statement, or nullptr if not existing, respectively
+  ///        not yet added.
+  MemoryAccess *lookupValueWriteOf(Instruction *Inst) const {
+    assert((isRegionStmt() && R->contains(Inst)) ||
+           (!isRegionStmt() && Inst->getParent() == BB));
+    return ValueWrites.lookup(Inst);
+  }
+
+  /// Return the MemoryAccess that reloads a value, or nullptr if not
+  ///        existing, respectively not yet added.
+  MemoryAccess *lookupValueReadOf(Value *Inst) const {
+    return ValueReads.lookup(Inst);
+  }
+
+  /// Return the MemoryAccess that loads a PHINode value, or nullptr if not
+  /// existing, respectively not yet added.
+  MemoryAccess *lookupPHIReadOf(PHINode *PHI) const {
+    return PHIReads.lookup(PHI);
+  }
+
+  /// Return the PHI write MemoryAccess for the incoming values from any
+  ///        basic block in this ScopStmt, or nullptr if not existing,
+  ///        respectively not yet added.
+  MemoryAccess *lookupPHIWriteOf(PHINode *PHI) const {
+    assert(isBlockStmt() || R->getExit() == PHI->getParent());
+    return PHIWrites.lookup(PHI);
+  }
+
+  /// Return the input access of the value, or null if no such MemoryAccess
+  /// exists.
+  ///
+  /// The input access is the MemoryAccess that makes an inter-statement value
+  /// available in this statement by reading it at the start of this statement.
+  /// This can be a MemoryKind::Value if defined in another statement or a
+  /// MemoryKind::PHI if the value is a PHINode in this statement.
+  MemoryAccess *lookupInputAccessOf(Value *Val) const {
+    if (isa<PHINode>(Val))
+      if (auto InputMA = lookupPHIReadOf(cast<PHINode>(Val))) {
+        assert(!lookupValueReadOf(Val) && "input accesses must be unique; a "
+                                          "statement cannot read a .s2a and "
+                                          ".phiops simultaneously");
+        return InputMA;
+      }
+
+    if (auto *InputMA = lookupValueReadOf(Val))
+      return InputMA;
+
+    return nullptr;
+  }
+
+  /// Add @p Access to this statement's list of accesses.
+  ///
+  /// @param Access  The access to add.
+  /// @param Prepend If true, will add @p Access before all other instructions
+  ///                (instead of appending it).
+  void addAccess(MemoryAccess *Access, bool Preprend = false);
+
+  /// Remove a MemoryAccess from this statement.
+  ///
+  /// Note that scalar accesses that are caused by MA will
+  /// be eliminated too.
+  void removeMemoryAccess(MemoryAccess *MA);
+
+  /// Remove @p MA from this statement.
+  ///
+  /// In contrast to removeMemoryAccess(), no other access will be eliminated.
+  void removeSingleMemoryAccess(MemoryAccess *MA);
+
+  using iterator = MemoryAccessVec::iterator;
+  using const_iterator = MemoryAccessVec::const_iterator;
+
+  iterator begin() { return MemAccs.begin(); }
+  iterator end() { return MemAccs.end(); }
+  const_iterator begin() const { return MemAccs.begin(); }
+  const_iterator end() const { return MemAccs.end(); }
+  size_t size() const { return MemAccs.size(); }
+
+  unsigned getNumIterators() const;
+
+  Scop *getParent() { return &Parent; }
+  const Scop *getParent() const { return &Parent; }
+
+  const std::vector<Instruction *> &getInstructions() const {
+    return Instructions;
+  }
+
+  /// Set the list of instructions for this statement. It replaces the current
+  /// list.
+  void setInstructions(ArrayRef<Instruction *> Range) {
+    Instructions.assign(Range.begin(), Range.end());
+  }
+
+  std::vector<Instruction *>::const_iterator insts_begin() const {
+    return Instructions.begin();
+  }
+
+  std::vector<Instruction *>::const_iterator insts_end() const {
+    return Instructions.end();
+  }
+
+  /// The range of instructions in this statement.
+  iterator_range<std::vector<Instruction *>::const_iterator> insts() const {
+    return {insts_begin(), insts_end()};
+  }
+
+  /// Insert an instruction before all other instructions in this statement.
+  void prependInstruction(Instruction *Inst) {
+    Instructions.insert(Instructions.begin(), Inst);
+  }
+
+  const char *getBaseName() const;
+
+  /// Set the isl AST build.
+  void setAstBuild(isl::ast_build B) { Build = B; }
+
+  /// Get the isl AST build.
+  isl::ast_build getAstBuild() const { return Build; }
+
+  /// Restrict the domain of the statement.
+  ///
+  /// @param NewDomain The new statement domain.
+  void restrictDomain(isl::set NewDomain);
+
+  /// Get the loop for a dimension.
+  ///
+  /// @param Dimension The dimension of the induction variable
+  /// @return The loop at a certain dimension.
+  Loop *getLoopForDimension(unsigned Dimension) const;
+
+  /// Align the parameters in the statement to the scop context
+  void realignParams();
+
+  /// Print the ScopStmt.
+  ///
+  /// @param OS                The output stream the ScopStmt is printed to.
+  /// @param PrintInstructions Whether to print the statement's instructions as
+  ///                          well.
+  void print(raw_ostream &OS, bool PrintInstructions) const;
+
+  /// Print the instructions in ScopStmt.
+  ///
+  void printInstructions(raw_ostream &OS) const;
+
+  /// Check whether there is a value read access for @p V in this statement, and
+  /// if not, create one.
+  ///
+  /// This allows to add MemoryAccesses after the initial creation of the Scop
+  /// by ScopBuilder.
+  ///
+  /// @return The already existing or newly created MemoryKind::Value READ
+  /// MemoryAccess.
+  ///
+  /// @see ScopBuilder::ensureValueRead(Value*,ScopStmt*)
+  MemoryAccess *ensureValueRead(Value *V);
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  /// Print the ScopStmt to stderr.
+  void dump() const;
+#endif
+};
+
+/// Print ScopStmt S to raw_ostream OS.
+raw_ostream &operator<<(raw_ostream &OS, const ScopStmt &S);
+
+/// Static Control Part
+///
+/// A Scop is the polyhedral representation of a control flow region detected
+/// by the Scop detection. It is generated by translating the LLVM-IR and
+/// abstracting its effects.
+///
+/// A Scop consists of a set of:
+///
+///   * A set of statements executed in the Scop.
+///
+///   * A set of global parameters
+///   Those parameters are scalar integer values, which are constant during
+///   execution.
+///
+///   * A context
+///   This context contains information about the values the parameters
+///   can take and relations between different parameters.
+class Scop {
+public:
+  /// Type to represent a pair of minimal/maximal access to an array.
+  using MinMaxAccessTy = std::pair<isl::pw_multi_aff, isl::pw_multi_aff>;
+
+  /// Vector of minimal/maximal accesses to different arrays.
+  using MinMaxVectorTy = SmallVector<MinMaxAccessTy, 4>;
+
+  /// Pair of minimal/maximal access vectors representing
+  /// read write and read only accesses
+  using MinMaxVectorPairTy = std::pair<MinMaxVectorTy, MinMaxVectorTy>;
+
+  /// Vector of pair of minimal/maximal access vectors representing
+  /// non read only and read only accesses for each alias group.
+  using MinMaxVectorPairVectorTy = SmallVector<MinMaxVectorPairTy, 4>;
+
+private:
+  friend class ScopBuilder;
+
+  /// Isl context.
+  ///
+  /// We need a shared_ptr with reference counter to delete the context when all
+  /// isl objects are deleted. We will distribute the shared_ptr to all objects
+  /// that use the context to create isl objects, and increase the reference
+  /// counter. By doing this, we guarantee that the context is deleted when we
+  /// delete the last object that creates isl objects with the context. This
+  /// declaration needs to be the first in class to gracefully destroy all isl
+  /// objects before the context.
+  std::shared_ptr<isl_ctx> IslCtx;
+
+  ScalarEvolution *SE;
+  DominatorTree *DT;
+
+  /// The underlying Region.
+  Region &R;
+
+  /// The name of the SCoP (identical to the regions name)
+  std::string name;
+
+  /// The ID to be assigned to the next Scop in a function
+  static int NextScopID;
+
+  /// The name of the function currently under consideration
+  static std::string CurrentFunc;
+
+  // Access functions of the SCoP.
+  //
+  // This owns all the MemoryAccess objects of the Scop created in this pass.
+  AccFuncVector AccessFunctions;
+
+  /// Flag to indicate that the scheduler actually optimized the SCoP.
+  bool IsOptimized = false;
+
+  /// True if the underlying region has a single exiting block.
+  bool HasSingleExitEdge;
+
+  /// Flag to remember if the SCoP contained an error block or not.
+  bool HasErrorBlock = false;
+
+  /// Max loop depth.
+  unsigned MaxLoopDepth = 0;
+
+  /// Number of copy statements.
+  unsigned CopyStmtsNum = 0;
+
+  /// Flag to indicate if the Scop is to be skipped.
+  bool SkipScop = false;
+
+  using StmtSet = std::list<ScopStmt>;
+
+  /// The statements in this Scop.
+  StmtSet Stmts;
+
+  /// Parameters of this Scop
+  ParameterSetTy Parameters;
+
+  /// Mapping from parameters to their ids.
+  DenseMap<const SCEV *, isl::id> ParameterIds;
+
+  /// The context of the SCoP created during SCoP detection.
+  ScopDetection::DetectionContext &DC;
+
+  /// OptimizationRemarkEmitter object for displaying diagnostic remarks
+  OptimizationRemarkEmitter &ORE;
+
+  /// A map from basic blocks to vector of SCoP statements. Currently this
+  /// vector comprises only of a single statement.
+  DenseMap<BasicBlock *, std::vector<ScopStmt *>> StmtMap;
+
+  /// A map from instructions to SCoP statements.
+  DenseMap<Instruction *, ScopStmt *> InstStmtMap;
+
+  /// A map from basic blocks to their domains.
+  DenseMap<BasicBlock *, isl::set> DomainMap;
+
+  /// Constraints on parameters.
+  isl::set Context = nullptr;
+
+  /// The affinator used to translate SCEVs to isl expressions.
+  SCEVAffinator Affinator;
+
+  using ArrayInfoMapTy =
+      std::map<std::pair<AssertingVH<const Value>, MemoryKind>,
+               std::unique_ptr<ScopArrayInfo>>;
+
+  using ArrayNameMapTy = StringMap<std::unique_ptr<ScopArrayInfo>>;
+
+  using ArrayInfoSetTy = SetVector<ScopArrayInfo *>;
+
+  /// A map to remember ScopArrayInfo objects for all base pointers.
+  ///
+  /// As PHI nodes may have two array info objects associated, we add a flag
+  /// that distinguishes between the PHI node specific ArrayInfo object
+  /// and the normal one.
+  ArrayInfoMapTy ScopArrayInfoMap;
+
+  /// A map to remember ScopArrayInfo objects for all names of memory
+  ///        references.
+  ArrayNameMapTy ScopArrayNameMap;
+
+  /// A set to remember ScopArrayInfo objects.
+  /// @see Scop::ScopArrayInfoMap
+  ArrayInfoSetTy ScopArrayInfoSet;
+
+  /// The assumptions under which this scop was built.
+  ///
+  /// When constructing a scop sometimes the exact representation of a statement
+  /// or condition would be very complex, but there is a common case which is a
+  /// lot simpler, but which is only valid under certain assumptions. The
+  /// assumed context records the assumptions taken during the construction of
+  /// this scop and that need to be code generated as a run-time test.
+  isl::set AssumedContext;
+
+  /// The restrictions under which this SCoP was built.
+  ///
+  /// The invalid context is similar to the assumed context as it contains
+  /// constraints over the parameters. However, while we need the constraints
+  /// in the assumed context to be "true" the constraints in the invalid context
+  /// need to be "false". Otherwise they behave the same.
+  isl::set InvalidContext;
+
+  /// Helper struct to remember assumptions.
+  struct Assumption {
+    /// The kind of the assumption (e.g., WRAPPING).
+    AssumptionKind Kind;
+
+    /// Flag to distinguish assumptions and restrictions.
+    AssumptionSign Sign;
+
+    /// The valid/invalid context if this is an assumption/restriction.
+    isl::set Set;
+
+    /// The location that caused this assumption.
+    DebugLoc Loc;
+
+    /// An optional block whose domain can simplify the assumption.
+    BasicBlock *BB;
+  };
+
+  /// Collection to hold taken assumptions.
+  ///
+  /// There are two reasons why we want to record assumptions first before we
+  /// add them to the assumed/invalid context:
+  ///   1) If the SCoP is not profitable or otherwise invalid without the
+  ///      assumed/invalid context we do not have to compute it.
+  ///   2) Information about the context are gathered rather late in the SCoP
+  ///      construction (basically after we know all parameters), thus the user
+  ///      might see overly complicated assumptions to be taken while they will
+  ///      only be simplified later on.
+  SmallVector<Assumption, 8> RecordedAssumptions;
+
+  /// The schedule of the SCoP
+  ///
+  /// The schedule of the SCoP describes the execution order of the statements
+  /// in the scop by assigning each statement instance a possibly
+  /// multi-dimensional execution time. The schedule is stored as a tree of
+  /// schedule nodes.
+  ///
+  /// The most common nodes in a schedule tree are so-called band nodes. Band
+  /// nodes map statement instances into a multi dimensional schedule space.
+  /// This space can be seen as a multi-dimensional clock.
+  ///
+  /// Example:
+  ///
+  /// <S,(5,4)>  may be mapped to (5,4) by this schedule:
+  ///
+  /// s0 = i (Year of execution)
+  /// s1 = j (Day of execution)
+  ///
+  /// or to (9, 20) by this schedule:
+  ///
+  /// s0 = i + j (Year of execution)
+  /// s1 = 20 (Day of execution)
+  ///
+  /// The order statement instances are executed is defined by the
+  /// schedule vectors they are mapped to. A statement instance
+  /// <A, (i, j, ..)> is executed before a statement instance <B, (i', ..)>, if
+  /// the schedule vector of A is lexicographic smaller than the schedule
+  /// vector of B.
+  ///
+  /// Besides band nodes, schedule trees contain additional nodes that specify
+  /// a textual ordering between two subtrees or filter nodes that filter the
+  /// set of statement instances that will be scheduled in a subtree. There
+  /// are also several other nodes. A full description of the different nodes
+  /// in a schedule tree is given in the isl manual.
+  isl::schedule Schedule = nullptr;
+
+  /// The set of minimal/maximal accesses for each alias group.
+  ///
+  /// When building runtime alias checks we look at all memory instructions and
+  /// build so called alias groups. Each group contains a set of accesses to
+  /// different base arrays which might alias with each other. However, between
+  /// alias groups there is no aliasing possible.
+  ///
+  /// In a program with int and float pointers annotated with tbaa information
+  /// we would probably generate two alias groups, one for the int pointers and
+  /// one for the float pointers.
+  ///
+  /// During code generation we will create a runtime alias check for each alias
+  /// group to ensure the SCoP is executed in an alias free environment.
+  MinMaxVectorPairVectorTy MinMaxAliasGroups;
+
+  /// Mapping from invariant loads to the representing invariant load of
+  ///        their equivalence class.
+  ValueToValueMap InvEquivClassVMap;
+
+  /// List of invariant accesses.
+  InvariantEquivClassesTy InvariantEquivClasses;
+
+  /// The smallest array index not yet assigned.
+  long ArrayIdx = 0;
+
+  /// The smallest statement index not yet assigned.
+  long StmtIdx = 0;
+
+  /// A number that uniquely represents a Scop within its function
+  const int ID;
+
+  /// Map of values to the MemoryAccess that writes its definition.
+  ///
+  /// There must be at most one definition per llvm::Instruction in a SCoP.
+  DenseMap<Value *, MemoryAccess *> ValueDefAccs;
+
+  /// Map of values to the MemoryAccess that reads a PHI.
+  DenseMap<PHINode *, MemoryAccess *> PHIReadAccs;
+
+  /// List of all uses (i.e. read MemoryAccesses) for a MemoryKind::Value
+  /// scalar.
+  DenseMap<const ScopArrayInfo *, SmallVector<MemoryAccess *, 4>> ValueUseAccs;
+
+  /// List of all incoming values (write MemoryAccess) of a MemoryKind::PHI or
+  /// MemoryKind::ExitPHI scalar.
+  DenseMap<const ScopArrayInfo *, SmallVector<MemoryAccess *, 4>>
+      PHIIncomingAccs;
+
+  /// Return the ID for a new Scop within a function
+  static int getNextID(std::string ParentFunc);
+
+  /// Scop constructor; invoked from ScopBuilder::buildScop.
+  Scop(Region &R, ScalarEvolution &SE, LoopInfo &LI, DominatorTree &DT,
+       ScopDetection::DetectionContext &DC, OptimizationRemarkEmitter &ORE);
+
+  //@}
+
+  /// Initialize this ScopBuilder.
+  void init(AliasAnalysis &AA, AssumptionCache &AC, DominatorTree &DT,
+            LoopInfo &LI);
+
+  /// Propagate domains that are known due to graph properties.
+  ///
+  /// As a CFG is mostly structured we use the graph properties to propagate
+  /// domains without the need to compute all path conditions. In particular, if
+  /// a block A dominates a block B and B post-dominates A we know that the
+  /// domain of B is a superset of the domain of A. As we do not have
+  /// post-dominator information available here we use the less precise region
+  /// information. Given a region R, we know that the exit is always executed if
+  /// the entry was executed, thus the domain of the exit is a superset of the
+  /// domain of the entry. In case the exit can only be reached from within the
+  /// region the domains are in fact equal. This function will use this property
+  /// to avoid the generation of condition constraints that determine when a
+  /// branch is taken. If @p BB is a region entry block we will propagate its
+  /// domain to the region exit block. Additionally, we put the region exit
+  /// block in the @p FinishedExitBlocks set so we can later skip edges from
+  /// within the region to that block.
+  ///
+  /// @param BB                 The block for which the domain is currently
+  ///                           propagated.
+  /// @param BBLoop             The innermost affine loop surrounding @p BB.
+  /// @param FinishedExitBlocks Set of region exits the domain was set for.
+  /// @param LI                 The LoopInfo for the current function.
+  /// @param InvalidDomainMap   BB to InvalidDomain map for the BB of current
+  ///                           region.
+  void propagateDomainConstraintsToRegionExit(
+      BasicBlock *BB, Loop *BBLoop,
+      SmallPtrSetImpl<BasicBlock *> &FinishedExitBlocks, LoopInfo &LI,
+      DenseMap<BasicBlock *, isl::set> &InvalidDomainMap);
+
+  /// Compute the union of predecessor domains for @p BB.
+  ///
+  /// To compute the union of all domains of predecessors of @p BB this
+  /// function applies similar reasoning on the CFG structure as described for
+  ///   @see propagateDomainConstraintsToRegionExit
+  ///
+  /// @param BB     The block for which the predecessor domains are collected.
+  /// @param Domain The domain under which BB is executed.
+  /// @param DT     The DominatorTree for the current function.
+  /// @param LI     The LoopInfo for the current function.
+  ///
+  /// @returns The domain under which @p BB is executed.
+  isl::set getPredecessorDomainConstraints(BasicBlock *BB, isl::set Domain,
+                                           DominatorTree &DT, LoopInfo &LI);
+
+  /// Add loop carried constraints to the header block of the loop @p L.
+  ///
+  /// @param L                The loop to process.
+  /// @param LI               The LoopInfo for the current function.
+  /// @param InvalidDomainMap BB to InvalidDomain map for the BB of current
+  ///                         region.
+  ///
+  /// @returns True if there was no problem and false otherwise.
+  bool addLoopBoundsToHeaderDomain(
+      Loop *L, LoopInfo &LI,
+      DenseMap<BasicBlock *, isl::set> &InvalidDomainMap);
+
+  /// Compute the branching constraints for each basic block in @p R.
+  ///
+  /// @param R                The region we currently build branching conditions
+  ///                         for.
+  /// @param DT               The DominatorTree for the current function.
+  /// @param LI               The LoopInfo for the current function.
+  /// @param InvalidDomainMap BB to InvalidDomain map for the BB of current
+  ///                         region.
+  ///
+  /// @returns True if there was no problem and false otherwise.
+  bool buildDomainsWithBranchConstraints(
+      Region *R, DominatorTree &DT, LoopInfo &LI,
+      DenseMap<BasicBlock *, isl::set> &InvalidDomainMap);
+
+  /// Propagate the domain constraints through the region @p R.
+  ///
+  /// @param R                The region we currently build branching conditions
+  /// for.
+  /// @param DT               The DominatorTree for the current function.
+  /// @param LI               The LoopInfo for the current function.
+  /// @param InvalidDomainMap BB to InvalidDomain map for the BB of current
+  ///                         region.
+  ///
+  /// @returns True if there was no problem and false otherwise.
+  bool propagateDomainConstraints(
+      Region *R, DominatorTree &DT, LoopInfo &LI,
+      DenseMap<BasicBlock *, isl::set> &InvalidDomainMap);
+
+  /// Propagate invalid domains of statements through @p R.
+  ///
+  /// This method will propagate invalid statement domains through @p R and at
+  /// the same time add error block domains to them. Additionally, the domains
+  /// of error statements and those only reachable via error statements will be
+  /// replaced by an empty set. Later those will be removed completely.
+  ///
+  /// @param R                The currently traversed region.
+  /// @param DT               The DominatorTree for the current function.
+  /// @param LI               The LoopInfo for the current function.
+  /// @param InvalidDomainMap BB to InvalidDomain map for the BB of current
+  ///                         region.
+  //
+  /// @returns True if there was no problem and false otherwise.
+  bool propagateInvalidStmtDomains(
+      Region *R, DominatorTree &DT, LoopInfo &LI,
+      DenseMap<BasicBlock *, isl::set> &InvalidDomainMap);
+
+  /// Compute the domain for each basic block in @p R.
+  ///
+  /// @param R                The region we currently traverse.
+  /// @param DT               The DominatorTree for the current function.
+  /// @param LI               The LoopInfo for the current function.
+  /// @param InvalidDomainMap BB to InvalidDomain map for the BB of current
+  ///                         region.
+  ///
+  /// @returns True if there was no problem and false otherwise.
+  bool buildDomains(Region *R, DominatorTree &DT, LoopInfo &LI,
+                    DenseMap<BasicBlock *, isl::set> &InvalidDomainMap);
+
+  /// Add parameter constraints to @p C that imply a non-empty domain.
+  isl::set addNonEmptyDomainConstraints(isl::set C) const;
+
+  /// Return the access for the base ptr of @p MA if any.
+  MemoryAccess *lookupBasePtrAccess(MemoryAccess *MA);
+
+  /// Check if the base ptr of @p MA is in the SCoP but not hoistable.
+  bool hasNonHoistableBasePtrInScop(MemoryAccess *MA, isl::union_map Writes);
+
+  /// Create equivalence classes for required invariant accesses.
+  ///
+  /// These classes will consolidate multiple required invariant loads from the
+  /// same address in order to keep the number of dimensions in the SCoP
+  /// description small. For each such class equivalence class only one
+  /// representing element, hence one required invariant load, will be chosen
+  /// and modeled as parameter. The method
+  /// Scop::getRepresentingInvariantLoadSCEV() will replace each element from an
+  /// equivalence class with the representing element that is modeled. As a
+  /// consequence Scop::getIdForParam() will only return an id for the
+  /// representing element of each equivalence class, thus for each required
+  /// invariant location.
+  void buildInvariantEquivalenceClasses();
+
+  /// Return the context under which the access cannot be hoisted.
+  ///
+  /// @param Access The access to check.
+  /// @param Writes The set of all memory writes in the scop.
+  ///
+  /// @return Return the context under which the access cannot be hoisted or a
+  ///         nullptr if it cannot be hoisted at all.
+  isl::set getNonHoistableCtx(MemoryAccess *Access, isl::union_map Writes);
+
+  /// Verify that all required invariant loads have been hoisted.
+  ///
+  /// Invariant load hoisting is not guaranteed to hoist all loads that were
+  /// assumed to be scop invariant during scop detection. This function checks
+  /// for cases where the hoisting failed, but where it would have been
+  /// necessary for our scop modeling to be correct. In case of insufficient
+  /// hoisting the scop is marked as invalid.
+  ///
+  /// In the example below Bound[1] is required to be invariant:
+  ///
+  /// for (int i = 1; i < Bound[0]; i++)
+  ///   for (int j = 1; j < Bound[1]; j++)
+  ///     ...
+  void verifyInvariantLoads();
+
+  /// Hoist invariant memory loads and check for required ones.
+  ///
+  /// We first identify "common" invariant loads, thus loads that are invariant
+  /// and can be hoisted. Then we check if all required invariant loads have
+  /// been identified as (common) invariant. A load is a required invariant load
+  /// if it was assumed to be invariant during SCoP detection, e.g., to assume
+  /// loop bounds to be affine or runtime alias checks to be placeable. In case
+  /// a required invariant load was not identified as (common) invariant we will
+  /// drop this SCoP. An example for both "common" as well as required invariant
+  /// loads is given below:
+  ///
+  /// for (int i = 1; i < *LB[0]; i++)
+  ///   for (int j = 1; j < *LB[1]; j++)
+  ///     A[i][j] += A[0][0] + (*V);
+  ///
+  /// Common inv. loads: V, A[0][0], LB[0], LB[1]
+  /// Required inv. loads: LB[0], LB[1], (V, if it may alias with A or LB)
+  void hoistInvariantLoads();
+
+  /// Canonicalize arrays with base pointers from the same equivalence class.
+  ///
+  /// Some context: in our normal model we assume that each base pointer is
+  /// related to a single specific memory region, where memory regions
+  /// associated with different base pointers are disjoint. Consequently we do
+  /// not need to compute additional data dependences that model possible
+  /// overlaps of these memory regions. To verify our assumption we compute
+  /// alias checks that verify that modeled arrays indeed do not overlap. In
+  /// case an overlap is detected the runtime check fails and we fall back to
+  /// the original code.
+  ///
+  /// In case of arrays where the base pointers are know to be identical,
+  /// because they are dynamically loaded by accesses that are in the same
+  /// invariant load equivalence class, such run-time alias check would always
+  /// be false.
+  ///
+  /// This function makes sure that we do not generate consistently failing
+  /// run-time checks for code that contains distinct arrays with known
+  /// equivalent base pointers. It identifies for each invariant load
+  /// equivalence class a single canonical array and canonicalizes all memory
+  /// accesses that reference arrays that have base pointers that are known to
+  /// be equal to the base pointer of such a canonical array to this canonical
+  /// array.
+  ///
+  /// We currently do not canonicalize arrays for which certain memory accesses
+  /// have been hoisted as loop invariant.
+  void canonicalizeDynamicBasePtrs();
+
+  /// Check if @p MA can always be hoisted without execution context.
+  bool canAlwaysBeHoisted(MemoryAccess *MA, bool StmtInvalidCtxIsEmpty,
+                          bool MAInvalidCtxIsEmpty,
+                          bool NonHoistableCtxIsEmpty);
+
+  /// Add invariant loads listed in @p InvMAs with the domain of @p Stmt.
+  void addInvariantLoads(ScopStmt &Stmt, InvariantAccessesTy &InvMAs);
+
+  /// Create an id for @p Param and store it in the ParameterIds map.
+  void createParameterId(const SCEV *Param);
+
+  /// Build the Context of the Scop.
+  void buildContext();
+
+  /// Add user provided parameter constraints to context (source code).
+  void addUserAssumptions(AssumptionCache &AC, DominatorTree &DT, LoopInfo &LI,
+                          DenseMap<BasicBlock *, isl::set> &InvalidDomainMap);
+
+  /// Add user provided parameter constraints to context (command line).
+  void addUserContext();
+
+  /// Add the bounds of the parameters to the context.
+  void addParameterBounds();
+
+  /// Simplify the assumed and invalid context.
+  void simplifyContexts();
+
+  /// Get the representing SCEV for @p S if applicable, otherwise @p S.
+  ///
+  /// Invariant loads of the same location are put in an equivalence class and
+  /// only one of them is chosen as a representing element that will be
+  /// modeled as a parameter. The others have to be normalized, i.e.,
+  /// replaced by the representing element of their equivalence class, in order
+  /// to get the correct parameter value, e.g., in the SCEVAffinator.
+  ///
+  /// @param S The SCEV to normalize.
+  ///
+  /// @return The representing SCEV for invariant loads or @p S if none.
+  const SCEV *getRepresentingInvariantLoadSCEV(const SCEV *S) const;
+
+  /// Create a new SCoP statement for @p BB.
+  ///
+  /// A new statement for @p BB will be created and added to the statement
+  /// vector
+  /// and map.
+  ///
+  /// @param BB              The basic block we build the statement for.
+  /// @param SurroundingLoop The loop the created statement is contained in.
+  /// @param Instructions    The instructions in the statement.
+  /// @param Count           The index of the created statement in @p BB.
+  void addScopStmt(BasicBlock *BB, Loop *SurroundingLoop,
+                   std::vector<Instruction *> Instructions, int Count);
+
+  /// Create a new SCoP statement for @p R.
+  ///
+  /// A new statement for @p R will be created and added to the statement vector
+  /// and map.
+  ///
+  /// @param R                      The region we build the statement for.
+  /// @param SurroundingLoop        The loop the created statement is contained
+  ///                               in.
+  /// @param EntryBlockInstructions The (interesting) instructions in the
+  ///                               entry block of the region statement.
+  void addScopStmt(Region *R, Loop *SurroundingLoop,
+                   std::vector<Instruction *> EntryBlockInstructions);
+
+  /// Update access dimensionalities.
+  ///
+  /// When detecting memory accesses different accesses to the same array may
+  /// have built with different dimensionality, as outer zero-values dimensions
+  /// may not have been recognized as separate dimensions. This function goes
+  /// again over all memory accesses and updates their dimensionality to match
+  /// the dimensionality of the underlying ScopArrayInfo object.
+  void updateAccessDimensionality();
+
+  /// Fold size constants to the right.
+  ///
+  /// In case all memory accesses in a given dimension are multiplied with a
+  /// common constant, we can remove this constant from the individual access
+  /// functions and move it to the size of the memory access. We do this as this
+  /// increases the size of the innermost dimension, consequently widens the
+  /// valid range the array subscript in this dimension can evaluate to, and
+  /// as a result increases the likelihood that our delinearization is
+  /// correct.
+  ///
+  /// Example:
+  ///
+  ///    A[][n]
+  ///    S[i,j] -> A[2i][2j+1]
+  ///    S[i,j] -> A[2i][2j]
+  ///
+  ///    =>
+  ///
+  ///    A[][2n]
+  ///    S[i,j] -> A[i][2j+1]
+  ///    S[i,j] -> A[i][2j]
+  ///
+  /// Constants in outer dimensions can arise when the elements of a parametric
+  /// multi-dimensional array are not elementary data types, but e.g.,
+  /// structures.
+  void foldSizeConstantsToRight();
+
+  /// Fold memory accesses to handle parametric offset.
+  ///
+  /// As a post-processing step, we 'fold' memory accesses to parametric
+  /// offsets in the access functions. @see MemoryAccess::foldAccess for
+  /// details.
+  void foldAccessRelations();
+
+  /// Assume that all memory accesses are within bounds.
+  ///
+  /// After we have built a model of all memory accesses, we need to assume
+  /// that the model we built matches reality -- aka. all modeled memory
+  /// accesses always remain within bounds. We do this as last step, after
+  /// all memory accesses have been modeled and canonicalized.
+  void assumeNoOutOfBounds();
+
+  /// Remove statements from the list of scop statements.
+  ///
+  /// @param ShouldDelete A function that returns true if the statement passed
+  ///                     to it should be deleted.
+  void removeStmts(std::function<bool(ScopStmt &)> ShouldDelete);
+
+  /// Removes @p Stmt from the StmtMap.
+  void removeFromStmtMap(ScopStmt &Stmt);
+
+  /// Removes all statements where the entry block of the statement does not
+  /// have a corresponding domain in the domain map.
+  void removeStmtNotInDomainMap();
+
+  /// Mark arrays that have memory accesses with FortranArrayDescriptor.
+  void markFortranArrays();
+
+  /// Finalize all access relations.
+  ///
+  /// When building up access relations, temporary access relations that
+  /// correctly represent each individual access are constructed. However, these
+  /// access relations can be inconsistent or non-optimal when looking at the
+  /// set of accesses as a whole. This function finalizes the memory accesses
+  /// and constructs a globally consistent state.
+  void finalizeAccesses();
+
+  /// Construct the schedule of this SCoP.
+  ///
+  /// @param LI The LoopInfo for the current function.
+  void buildSchedule(LoopInfo &LI);
+
+  /// A loop stack element to keep track of per-loop information during
+  ///        schedule construction.
+  using LoopStackElementTy = struct LoopStackElement {
+    // The loop for which we keep information.
+    Loop *L;
+
+    // The (possibly incomplete) schedule for this loop.
+    isl::schedule Schedule;
+
+    // The number of basic blocks in the current loop, for which a schedule has
+    // already been constructed.
+    unsigned NumBlocksProcessed;
+
+    LoopStackElement(Loop *L, isl::schedule S, unsigned NumBlocksProcessed)
+        : L(L), Schedule(S), NumBlocksProcessed(NumBlocksProcessed) {}
+  };
+
+  /// The loop stack used for schedule construction.
+  ///
+  /// The loop stack keeps track of schedule information for a set of nested
+  /// loops as well as an (optional) 'nullptr' loop that models the outermost
+  /// schedule dimension. The loops in a loop stack always have a parent-child
+  /// relation where the loop at position n is the parent of the loop at
+  /// position n + 1.
+  using LoopStackTy = SmallVector<LoopStackElementTy, 4>;
+
+  /// Construct schedule information for a given Region and add the
+  ///        derived information to @p LoopStack.
+  ///
+  /// Given a Region we derive schedule information for all RegionNodes
+  /// contained in this region ensuring that the assigned execution times
+  /// correctly model the existing control flow relations.
+  ///
+  /// @param R              The region which to process.
+  /// @param LoopStack      A stack of loops that are currently under
+  ///                       construction.
+  /// @param LI The LoopInfo for the current function.
+  void buildSchedule(Region *R, LoopStackTy &LoopStack, LoopInfo &LI);
+
+  /// Build Schedule for the region node @p RN and add the derived
+  ///        information to @p LoopStack.
+  ///
+  /// In case @p RN is a BasicBlock or a non-affine Region, we construct the
+  /// schedule for this @p RN and also finalize loop schedules in case the
+  /// current @p RN completes the loop.
+  ///
+  /// In case @p RN is a not-non-affine Region, we delegate the construction to
+  /// buildSchedule(Region *R, ...).
+  ///
+  /// @param RN             The RegionNode region traversed.
+  /// @param LoopStack      A stack of loops that are currently under
+  ///                       construction.
+  /// @param LI The LoopInfo for the current function.
+  void buildSchedule(RegionNode *RN, LoopStackTy &LoopStack, LoopInfo &LI);
+
+  /// Collect all memory access relations of a given type.
+  ///
+  /// @param Predicate A predicate function that returns true if an access is
+  ///                  of a given type.
+  ///
+  /// @returns The set of memory accesses in the scop that match the predicate.
+  isl::union_map
+  getAccessesOfType(std::function<bool(MemoryAccess &)> Predicate);
+
+  /// @name Helper functions for printing the Scop.
+  ///
+  //@{
+  void printContext(raw_ostream &OS) const;
+  void printArrayInfo(raw_ostream &OS) const;
+  void printStatements(raw_ostream &OS, bool PrintInstructions) const;
+  void printAliasAssumptions(raw_ostream &OS) const;
+  //@}
+
+public:
+  Scop(const Scop &) = delete;
+  Scop &operator=(const Scop &) = delete;
+  ~Scop();
+
+  /// Get the count of copy statements added to this Scop.
+  ///
+  /// @return The count of copy statements added to this Scop.
+  unsigned getCopyStmtsNum() { return CopyStmtsNum; }
+
+  /// Create a new copy statement.
+  ///
+  /// A new statement will be created and added to the statement vector.
+  ///
+  /// @param Stmt       The parent statement.
+  /// @param SourceRel  The source location.
+  /// @param TargetRel  The target location.
+  /// @param Domain     The original domain under which the copy statement would
+  ///                   be executed.
+  ScopStmt *addScopStmt(isl::map SourceRel, isl::map TargetRel,
+                        isl::set Domain);
+
+  /// Add the access function to all MemoryAccess objects of the Scop
+  ///        created in this pass.
+  void addAccessFunction(MemoryAccess *Access) {
+    AccessFunctions.emplace_back(Access);
+
+    // Register value definitions.
+    if (Access->isWrite() && Access->isOriginalValueKind()) {
+      assert(!ValueDefAccs.count(Access->getAccessValue()) &&
+             "there can be just one definition per value");
+      ValueDefAccs[Access->getAccessValue()] = Access;
+    } else if (Access->isRead() && Access->isOriginalPHIKind()) {
+      PHINode *PHI = cast<PHINode>(Access->getAccessInstruction());
+      assert(!PHIReadAccs.count(PHI) &&
+             "there can be just one PHI read per PHINode");
+      PHIReadAccs[PHI] = Access;
+    }
+  }
+
+  /// Add metadata for @p Access.
+  void addAccessData(MemoryAccess *Access);
+
+  /// Remove the metadata stored for @p Access.
+  void removeAccessData(MemoryAccess *Access);
+
+  /// Return the scalar evolution.
+  ScalarEvolution *getSE() const;
+
+  /// Return the dominator tree.
+  DominatorTree *getDT() const { return DT; }
+
+  /// Return the LoopInfo used for this Scop.
+  LoopInfo *getLI() const { return Affinator.getLI(); }
+
+  /// Get the count of parameters used in this Scop.
+  ///
+  /// @return The count of parameters used in this Scop.
+  size_t getNumParams() const { return Parameters.size(); }
+
+  /// Take a list of parameters and add the new ones to the scop.
+  void addParams(const ParameterSetTy &NewParameters);
+
+  /// Return an iterator range containing the scop parameters.
+  iterator_range<ParameterSetTy::iterator> parameters() const {
+    return make_range(Parameters.begin(), Parameters.end());
+  }
+
+  /// Return whether this scop is empty, i.e. contains no statements that
+  /// could be executed.
+  bool isEmpty() const { return Stmts.empty(); }
+
+  const StringRef getName() const { return name; }
+
+  using array_iterator = ArrayInfoSetTy::iterator;
+  using const_array_iterator = ArrayInfoSetTy::const_iterator;
+  using array_range = iterator_range<ArrayInfoSetTy::iterator>;
+  using const_array_range = iterator_range<ArrayInfoSetTy::const_iterator>;
+
+  inline array_iterator array_begin() { return ScopArrayInfoSet.begin(); }
+
+  inline array_iterator array_end() { return ScopArrayInfoSet.end(); }
+
+  inline const_array_iterator array_begin() const {
+    return ScopArrayInfoSet.begin();
+  }
+
+  inline const_array_iterator array_end() const {
+    return ScopArrayInfoSet.end();
+  }
+
+  inline array_range arrays() {
+    return array_range(array_begin(), array_end());
+  }
+
+  inline const_array_range arrays() const {
+    return const_array_range(array_begin(), array_end());
+  }
+
+  /// Return the isl_id that represents a certain parameter.
+  ///
+  /// @param Parameter A SCEV that was recognized as a Parameter.
+  ///
+  /// @return The corresponding isl_id or NULL otherwise.
+  isl::id getIdForParam(const SCEV *Parameter) const;
+
+  /// Get the maximum region of this static control part.
+  ///
+  /// @return The maximum region of this static control part.
+  inline const Region &getRegion() const { return R; }
+  inline Region &getRegion() { return R; }
+
+  /// Return the function this SCoP is in.
+  Function &getFunction() const { return *R.getEntry()->getParent(); }
+
+  /// Check if @p L is contained in the SCoP.
+  bool contains(const Loop *L) const { return R.contains(L); }
+
+  /// Check if @p BB is contained in the SCoP.
+  bool contains(const BasicBlock *BB) const { return R.contains(BB); }
+
+  /// Check if @p I is contained in the SCoP.
+  bool contains(const Instruction *I) const { return R.contains(I); }
+
+  /// Return the unique exit block of the SCoP.
+  BasicBlock *getExit() const { return R.getExit(); }
+
+  /// Return the unique exiting block of the SCoP if any.
+  BasicBlock *getExitingBlock() const { return R.getExitingBlock(); }
+
+  /// Return the unique entry block of the SCoP.
+  BasicBlock *getEntry() const { return R.getEntry(); }
+
+  /// Return the unique entering block of the SCoP if any.
+  BasicBlock *getEnteringBlock() const { return R.getEnteringBlock(); }
+
+  /// Return true if @p BB is the exit block of the SCoP.
+  bool isExit(BasicBlock *BB) const { return getExit() == BB; }
+
+  /// Return a range of all basic blocks in the SCoP.
+  Region::block_range blocks() const { return R.blocks(); }
+
+  /// Return true if and only if @p BB dominates the SCoP.
+  bool isDominatedBy(const DominatorTree &DT, BasicBlock *BB) const;
+
+  /// Get the maximum depth of the loop.
+  ///
+  /// @return The maximum depth of the loop.
+  inline unsigned getMaxLoopDepth() const { return MaxLoopDepth; }
+
+  /// Return the invariant equivalence class for @p Val if any.
+  InvariantEquivClassTy *lookupInvariantEquivClass(Value *Val);
+
+  /// Return the set of invariant accesses.
+  InvariantEquivClassesTy &getInvariantAccesses() {
+    return InvariantEquivClasses;
+  }
+
+  /// Check if the scop has any invariant access.
+  bool hasInvariantAccesses() { return !InvariantEquivClasses.empty(); }
+
+  /// Mark the SCoP as optimized by the scheduler.
+  void markAsOptimized() { IsOptimized = true; }
+
+  /// Check if the SCoP has been optimized by the scheduler.
+  bool isOptimized() const { return IsOptimized; }
+
+  /// Mark the SCoP to be skipped by ScopPass passes.
+  void markAsToBeSkipped() { SkipScop = true; }
+
+  /// Check if the SCoP is to be skipped by ScopPass passes.
+  bool isToBeSkipped() const { return SkipScop; }
+
+  /// Return the ID of the Scop
+  int getID() const { return ID; }
+
+  /// Get the name of the entry and exit blocks of this Scop.
+  ///
+  /// These along with the function name can uniquely identify a Scop.
+  ///
+  /// @return std::pair whose first element is the entry name & second element
+  ///         is the exit name.
+  std::pair<std::string, std::string> getEntryExitStr() const;
+
+  /// Get the name of this Scop.
+  std::string getNameStr() const;
+
+  /// Get the constraint on parameter of this Scop.
+  ///
+  /// @return The constraint on parameter of this Scop.
+  isl::set getContext() const;
+
+  /// Return space of isl context parameters.
+  ///
+  /// Returns the set of context parameters that are currently constrained. In
+  /// case the full set of parameters is needed, see @getFullParamSpace.
+  isl::space getParamSpace() const;
+
+  /// Return the full space of parameters.
+  ///
+  /// getParamSpace will only return the parameters of the context that are
+  /// actually constrained, whereas getFullParamSpace will return all
+  //  parameters. This is useful in cases, where we need to ensure all
+  //  parameters are available, as certain isl functions will abort if this is
+  //  not the case.
+  isl::space getFullParamSpace() const;
+
+  /// Get the assumed context for this Scop.
+  ///
+  /// @return The assumed context of this Scop.
+  isl::set getAssumedContext() const;
+
+  /// Return true if the optimized SCoP can be executed.
+  ///
+  /// In addition to the runtime check context this will also utilize the domain
+  /// constraints to decide it the optimized version can actually be executed.
+  ///
+  /// @returns True if the optimized SCoP can be executed.
+  bool hasFeasibleRuntimeContext() const;
+
+  /// Check if the assumption in @p Set is trivial or not.
+  ///
+  /// @param Set  The relations between parameters that are assumed to hold.
+  /// @param Sign Enum to indicate if the assumptions in @p Set are positive
+  ///             (needed/assumptions) or negative (invalid/restrictions).
+  ///
+  /// @returns True if the assumption @p Set is not trivial.
+  bool isEffectiveAssumption(isl::set Set, AssumptionSign Sign);
+
+  /// Track and report an assumption.
+  ///
+  /// Use 'clang -Rpass-analysis=polly-scops' or 'opt
+  /// -pass-remarks-analysis=polly-scops' to output the assumptions.
+  ///
+  /// @param Kind The assumption kind describing the underlying cause.
+  /// @param Set  The relations between parameters that are assumed to hold.
+  /// @param Loc  The location in the source that caused this assumption.
+  /// @param Sign Enum to indicate if the assumptions in @p Set are positive
+  ///             (needed/assumptions) or negative (invalid/restrictions).
+  /// @param BB   The block in which this assumption was taken. Used to
+  ///             calculate hotness when emitting remark.
+  ///
+  /// @returns True if the assumption is not trivial.
+  bool trackAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
+                       AssumptionSign Sign, BasicBlock *BB);
+
+  /// Add assumptions to assumed context.
+  ///
+  /// The assumptions added will be assumed to hold during the execution of the
+  /// scop. However, as they are generally not statically provable, at code
+  /// generation time run-time checks will be generated that ensure the
+  /// assumptions hold.
+  ///
+  /// WARNING: We currently exploit in simplifyAssumedContext the knowledge
+  ///          that assumptions do not change the set of statement instances
+  ///          executed.
+  ///
+  /// @param Kind The assumption kind describing the underlying cause.
+  /// @param Set  The relations between parameters that are assumed to hold.
+  /// @param Loc  The location in the source that caused this assumption.
+  /// @param Sign Enum to indicate if the assumptions in @p Set are positive
+  ///             (needed/assumptions) or negative (invalid/restrictions).
+  /// @param BB   The block in which this assumption was taken. Used to
+  ///             calculate hotness when emitting remark.
+  void addAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
+                     AssumptionSign Sign, BasicBlock *BB);
+
+  /// Record an assumption for later addition to the assumed context.
+  ///
+  /// This function will add the assumption to the RecordedAssumptions. This
+  /// collection will be added (@see addAssumption) to the assumed context once
+  /// all paramaters are known and the context is fully built.
+  ///
+  /// @param Kind The assumption kind describing the underlying cause.
+  /// @param Set  The relations between parameters that are assumed to hold.
+  /// @param Loc  The location in the source that caused this assumption.
+  /// @param Sign Enum to indicate if the assumptions in @p Set are positive
+  ///             (needed/assumptions) or negative (invalid/restrictions).
+  /// @param BB   The block in which this assumption was taken. If it is
+  ///             set, the domain of that block will be used to simplify the
+  ///             actual assumption in @p Set once it is added. This is useful
+  ///             if the assumption was created prior to the domain.
+  void recordAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
+                        AssumptionSign Sign, BasicBlock *BB = nullptr);
+
+  /// Add all recorded assumptions to the assumed context.
+  void addRecordedAssumptions();
+
+  /// Mark the scop as invalid.
+  ///
+  /// This method adds an assumption to the scop that is always invalid. As a
+  /// result, the scop will not be optimized later on. This function is commonly
+  /// called when a condition makes it impossible (or too compile time
+  /// expensive) to process this scop any further.
+  ///
+  /// @param Kind The assumption kind describing the underlying cause.
+  /// @param Loc  The location in the source that triggered .
+  /// @param BB   The BasicBlock where it was triggered.
+  void invalidate(AssumptionKind Kind, DebugLoc Loc, BasicBlock *BB = nullptr);
+
+  /// Get the invalid context for this Scop.
+  ///
+  /// @return The invalid context of this Scop.
+  isl::set getInvalidContext() const;
+
+  /// Return true if and only if the InvalidContext is trivial (=empty).
+  bool hasTrivialInvalidContext() const { return InvalidContext.is_empty(); }
+
+  /// A vector of memory accesses that belong to an alias group.
+  using AliasGroupTy = SmallVector<MemoryAccess *, 4>;
+
+  /// A vector of alias groups.
+  using AliasGroupVectorTy = SmallVector<Scop::AliasGroupTy, 4>;
+
+  /// Build the alias checks for this SCoP.
+  bool buildAliasChecks(AliasAnalysis &AA);
+
+  /// Build all alias groups for this SCoP.
+  ///
+  /// @returns True if __no__ error occurred, false otherwise.
+  bool buildAliasGroups(AliasAnalysis &AA);
+
+  /// Build alias groups for all memory accesses in the Scop.
+  ///
+  /// Using the alias analysis and an alias set tracker we build alias sets
+  /// for all memory accesses inside the Scop. For each alias set we then map
+  /// the aliasing pointers back to the memory accesses we know, thus obtain
+  /// groups of memory accesses which might alias. We also collect the set of
+  /// arrays through which memory is written.
+  ///
+  /// @param AA A reference to the alias analysis.
+  ///
+  /// @returns A pair consistent of a vector of alias groups and a set of arrays
+  ///          through which memory is written.
+  std::tuple<AliasGroupVectorTy, DenseSet<const ScopArrayInfo *>>
+  buildAliasGroupsForAccesses(AliasAnalysis &AA);
+
+  ///  Split alias groups by iteration domains.
+  ///
+  ///  We split each group based on the domains of the minimal/maximal accesses.
+  ///  That means two minimal/maximal accesses are only in a group if their
+  ///  access domains intersect. Otherwise, they are in different groups.
+  ///
+  ///  @param AliasGroups The alias groups to split
+  void splitAliasGroupsByDomain(AliasGroupVectorTy &AliasGroups);
+
+  /// Build a given alias group and its access data.
+  ///
+  /// @param AliasGroup     The alias group to build.
+  /// @param HasWriteAccess A set of arrays through which memory is not only
+  ///                       read, but also written.
+  ///
+  /// @returns True if __no__ error occurred, false otherwise.
+  bool buildAliasGroup(Scop::AliasGroupTy &AliasGroup,
+                       DenseSet<const ScopArrayInfo *> HasWriteAccess);
+
+  /// Return all alias groups for this SCoP.
+  const MinMaxVectorPairVectorTy &getAliasGroups() const {
+    return MinMaxAliasGroups;
+  }
+
+  /// Get an isl string representing the context.
+  std::string getContextStr() const;
+
+  /// Get an isl string representing the assumed context.
+  std::string getAssumedContextStr() const;
+
+  /// Get an isl string representing the invalid context.
+  std::string getInvalidContextStr() const;
+
+  /// Return the list of ScopStmts that represent the given @p BB.
+  ArrayRef<ScopStmt *> getStmtListFor(BasicBlock *BB) const;
+
+  /// Return the last statement representing @p BB.
+  ///
+  /// Of the sequence of statements that represent a @p BB, this is the last one
+  /// to be executed. It is typically used to determine which instruction to add
+  /// a MemoryKind::PHI WRITE to. For this purpose, it is not strictly required
+  /// to be executed last, only that the incoming value is available in it.
+  ScopStmt *getLastStmtFor(BasicBlock *BB) const;
+
+  /// Return the ScopStmts that represents the Region @p R, or nullptr if
+  ///        it is not represented by any statement in this Scop.
+  ArrayRef<ScopStmt *> getStmtListFor(Region *R) const;
+
+  /// Return the ScopStmts that represents @p RN; can return nullptr if
+  ///        the RegionNode is not within the SCoP or has been removed due to
+  ///        simplifications.
+  ArrayRef<ScopStmt *> getStmtListFor(RegionNode *RN) const;
+
+  /// Return the ScopStmt an instruction belongs to, or nullptr if it
+  ///        does not belong to any statement in this Scop.
+  ScopStmt *getStmtFor(Instruction *Inst) const {
+    return InstStmtMap.lookup(Inst);
+  }
+
+  /// Return the number of statements in the SCoP.
+  size_t getSize() const { return Stmts.size(); }
+
+  /// @name Statements Iterators
+  ///
+  /// These iterators iterate over all statements of this Scop.
+  //@{
+  using iterator = StmtSet::iterator;
+  using const_iterator = StmtSet::const_iterator;
+
+  iterator begin() { return Stmts.begin(); }
+  iterator end() { return Stmts.end(); }
+  const_iterator begin() const { return Stmts.begin(); }
+  const_iterator end() const { return Stmts.end(); }
+
+  using reverse_iterator = StmtSet::reverse_iterator;
+  using const_reverse_iterator = StmtSet::const_reverse_iterator;
+
+  reverse_iterator rbegin() { return Stmts.rbegin(); }
+  reverse_iterator rend() { return Stmts.rend(); }
+  const_reverse_iterator rbegin() const { return Stmts.rbegin(); }
+  const_reverse_iterator rend() const { return Stmts.rend(); }
+  //@}
+
+  /// Return the set of required invariant loads.
+  const InvariantLoadsSetTy &getRequiredInvariantLoads() const {
+    return DC.RequiredILS;
+  }
+
+  /// Add @p LI to the set of required invariant loads.
+  void addRequiredInvariantLoad(LoadInst *LI) { DC.RequiredILS.insert(LI); }
+
+  /// Return true if and only if @p LI is a required invariant load.
+  bool isRequiredInvariantLoad(LoadInst *LI) const {
+    return getRequiredInvariantLoads().count(LI);
+  }
+
+  /// Return the set of boxed (thus overapproximated) loops.
+  const BoxedLoopsSetTy &getBoxedLoops() const { return DC.BoxedLoopsSet; }
+
+  /// Return true if and only if @p R is a non-affine subregion.
+  bool isNonAffineSubRegion(const Region *R) {
+    return DC.NonAffineSubRegionSet.count(R);
+  }
+
+  const MapInsnToMemAcc &getInsnToMemAccMap() const { return DC.InsnToMemAcc; }
+
+  /// Return the (possibly new) ScopArrayInfo object for @p Access.
+  ///
+  /// @param ElementType The type of the elements stored in this array.
+  /// @param Kind        The kind of the array info object.
+  /// @param BaseName    The optional name of this memory reference.
+  ScopArrayInfo *getOrCreateScopArrayInfo(Value *BasePtr, Type *ElementType,
+                                          ArrayRef<const SCEV *> Sizes,
+                                          MemoryKind Kind,
+                                          const char *BaseName = nullptr);
+
+  /// Create an array and return the corresponding ScopArrayInfo object.
+  ///
+  /// @param ElementType The type of the elements stored in this array.
+  /// @param BaseName    The name of this memory reference.
+  /// @param Sizes       The sizes of dimensions.
+  ScopArrayInfo *createScopArrayInfo(Type *ElementType,
+                                     const std::string &BaseName,
+                                     const std::vector<unsigned> &Sizes);
+
+  /// Return the cached ScopArrayInfo object for @p BasePtr.
+  ///
+  /// @param BasePtr   The base pointer the object has been stored for.
+  /// @param Kind      The kind of array info object.
+  ///
+  /// @returns The ScopArrayInfo pointer or NULL if no such pointer is
+  ///          available.
+  const ScopArrayInfo *getScopArrayInfoOrNull(Value *BasePtr, MemoryKind Kind);
+
+  /// Return the cached ScopArrayInfo object for @p BasePtr.
+  ///
+  /// @param BasePtr   The base pointer the object has been stored for.
+  /// @param Kind      The kind of array info object.
+  ///
+  /// @returns The ScopArrayInfo pointer (may assert if no such pointer is
+  ///          available).
+  const ScopArrayInfo *getScopArrayInfo(Value *BasePtr, MemoryKind Kind);
+
+  /// Invalidate ScopArrayInfo object for base address.
+  ///
+  /// @param BasePtr The base pointer of the ScopArrayInfo object to invalidate.
+  /// @param Kind    The Kind of the ScopArrayInfo object.
+  void invalidateScopArrayInfo(Value *BasePtr, MemoryKind Kind) {
+    auto It = ScopArrayInfoMap.find(std::make_pair(BasePtr, Kind));
+    if (It == ScopArrayInfoMap.end())
+      return;
+    ScopArrayInfoSet.remove(It->second.get());
+    ScopArrayInfoMap.erase(It);
+  }
+
+  void setContext(isl::set NewContext);
+
+  /// Align the parameters in the statement to the scop context
+  void realignParams();
+
+  /// Return true if this SCoP can be profitably optimized.
+  ///
+  /// @param ScalarsAreUnprofitable Never consider statements with scalar writes
+  ///                               as profitably optimizable.
+  ///
+  /// @return Whether this SCoP can be profitably optimized.
+  bool isProfitable(bool ScalarsAreUnprofitable) const;
+
+  /// Return true if the SCoP contained at least one error block.
+  bool hasErrorBlock() const { return HasErrorBlock; }
+
+  /// Return true if the underlying region has a single exiting block.
+  bool hasSingleExitEdge() const { return HasSingleExitEdge; }
+
+  /// Print the static control part.
+  ///
+  /// @param OS The output stream the static control part is printed to.
+  /// @param PrintInstructions Whether to print the statement's instructions as
+  ///                          well.
+  void print(raw_ostream &OS, bool PrintInstructions) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  /// Print the ScopStmt to stderr.
+  void dump() const;
+#endif
+
+  /// Get the isl context of this static control part.
+  ///
+  /// @return The isl context of this static control part.
+  isl::ctx getIslCtx() const;
+
+  /// Directly return the shared_ptr of the context.
+  const std::shared_ptr<isl_ctx> &getSharedIslCtx() const { return IslCtx; }
+
+  /// Compute the isl representation for the SCEV @p E
+  ///
+  /// @param E  The SCEV that should be translated.
+  /// @param BB An (optional) basic block in which the isl_pw_aff is computed.
+  ///           SCEVs known to not reference any loops in the SCoP can be
+  ///           passed without a @p BB.
+  /// @param NonNegative Flag to indicate the @p E has to be non-negative.
+  ///
+  /// Note that this function will always return a valid isl_pw_aff. However, if
+  /// the translation of @p E was deemed to complex the SCoP is invalidated and
+  /// a dummy value of appropriate dimension is returned. This allows to bail
+  /// for complex cases without "error handling code" needed on the users side.
+  PWACtx getPwAff(const SCEV *E, BasicBlock *BB = nullptr,
+                  bool NonNegative = false);
+
+  /// Compute the isl representation for the SCEV @p E
+  ///
+  /// This function is like @see Scop::getPwAff() but strips away the invalid
+  /// domain part associated with the piecewise affine function.
+  isl::pw_aff getPwAffOnly(const SCEV *E, BasicBlock *BB = nullptr);
+
+  /// Return the domain of @p Stmt.
+  ///
+  /// @param Stmt The statement for which the conditions should be returned.
+  isl::set getDomainConditions(const ScopStmt *Stmt) const;
+
+  /// Return the domain of @p BB.
+  ///
+  /// @param BB The block for which the conditions should be returned.
+  isl::set getDomainConditions(BasicBlock *BB) const;
+
+  /// Get a union set containing the iteration domains of all statements.
+  isl::union_set getDomains() const;
+
+  /// Get a union map of all may-writes performed in the SCoP.
+  isl::union_map getMayWrites();
+
+  /// Get a union map of all must-writes performed in the SCoP.
+  isl::union_map getMustWrites();
+
+  /// Get a union map of all writes performed in the SCoP.
+  isl::union_map getWrites();
+
+  /// Get a union map of all reads performed in the SCoP.
+  isl::union_map getReads();
+
+  /// Get a union map of all memory accesses performed in the SCoP.
+  isl::union_map getAccesses();
+
+  /// Get a union map of all memory accesses performed in the SCoP.
+  ///
+  /// @param Array The array to which the accesses should belong.
+  isl::union_map getAccesses(ScopArrayInfo *Array);
+
+  /// Get the schedule of all the statements in the SCoP.
+  ///
+  /// @return The schedule of all the statements in the SCoP, if the schedule of
+  /// the Scop does not contain extension nodes, and nullptr, otherwise.
+  isl::union_map getSchedule() const;
+
+  /// Get a schedule tree describing the schedule of all statements.
+  isl::schedule getScheduleTree() const;
+
+  /// Update the current schedule
+  ///
+  /// NewSchedule The new schedule (given as a flat union-map).
+  void setSchedule(isl::union_map NewSchedule);
+
+  /// Update the current schedule
+  ///
+  /// NewSchedule The new schedule (given as schedule tree).
+  void setScheduleTree(isl::schedule NewSchedule);
+
+  /// Intersects the domains of all statements in the SCoP.
+  ///
+  /// @return true if a change was made
+  bool restrictDomains(isl::union_set Domain);
+
+  /// Get the depth of a loop relative to the outermost loop in the Scop.
+  ///
+  /// This will return
+  ///    0 if @p L is an outermost loop in the SCoP
+  ///   >0 for other loops in the SCoP
+  ///   -1 if @p L is nullptr or there is no outermost loop in the SCoP
+  int getRelativeLoopDepth(const Loop *L) const;
+
+  /// Find the ScopArrayInfo associated with an isl Id
+  ///        that has name @p Name.
+  ScopArrayInfo *getArrayInfoByName(const std::string BaseName);
+
+  /// Check whether @p Schedule contains extension nodes.
+  ///
+  /// @return true if @p Schedule contains extension nodes.
+  static bool containsExtensionNode(isl::schedule Schedule);
+
+  /// Simplify the SCoP representation.
+  ///
+  /// @param AfterHoisting Whether it is called after invariant load hoisting.
+  ///                      When true, also removes statements without
+  ///                      side-effects.
+  void simplifySCoP(bool AfterHoisting);
+
+  /// Get the next free array index.
+  ///
+  /// This function returns a unique index which can be used to identify an
+  /// array.
+  long getNextArrayIdx() { return ArrayIdx++; }
+
+  /// Get the next free statement index.
+  ///
+  /// This function returns a unique index which can be used to identify a
+  /// statement.
+  long getNextStmtIdx() { return StmtIdx++; }
+
+  /// Return the MemoryAccess that writes an llvm::Value, represented by a
+  /// ScopArrayInfo.
+  ///
+  /// There can be at most one such MemoryAccess per llvm::Value in the SCoP.
+  /// Zero is possible for read-only values.
+  MemoryAccess *getValueDef(const ScopArrayInfo *SAI) const;
+
+  /// Return all MemoryAccesses that us an llvm::Value, represented by a
+  /// ScopArrayInfo.
+  ArrayRef<MemoryAccess *> getValueUses(const ScopArrayInfo *SAI) const;
+
+  /// Return the MemoryAccess that represents an llvm::PHINode.
+  ///
+  /// ExitPHIs's PHINode is not within the SCoPs. This function returns nullptr
+  /// for them.
+  MemoryAccess *getPHIRead(const ScopArrayInfo *SAI) const;
+
+  /// Return all MemoryAccesses for all incoming statements of a PHINode,
+  /// represented by a ScopArrayInfo.
+  ArrayRef<MemoryAccess *> getPHIIncomings(const ScopArrayInfo *SAI) const;
+
+  /// Return whether @p Inst has a use outside of this SCoP.
+  bool isEscaping(Instruction *Inst);
+
+  struct ScopStatistics {
+    int NumAffineLoops = 0;
+    int NumBoxedLoops = 0;
+
+    int NumValueWrites = 0;
+    int NumValueWritesInLoops = 0;
+    int NumPHIWrites = 0;
+    int NumPHIWritesInLoops = 0;
+    int NumSingletonWrites = 0;
+    int NumSingletonWritesInLoops = 0;
+  };
+
+  /// Collect statistic about this SCoP.
+  ///
+  /// These are most commonly used for LLVM's static counters (Statistic.h) in
+  /// various places. If statistics are disabled, only zeros are returned to
+  /// avoid the overhead.
+  ScopStatistics getStatistics() const;
+};
+
+/// Print Scop scop to raw_ostream OS.
+raw_ostream &operator<<(raw_ostream &OS, const Scop &scop);
+
+/// The legacy pass manager's analysis pass to compute scop information
+///        for a region.
+class ScopInfoRegionPass : public RegionPass {
+  /// The Scop pointer which is used to construct a Scop.
+  std::unique_ptr<Scop> S;
+
+public:
+  static char ID; // Pass identification, replacement for typeid
+
+  ScopInfoRegionPass() : RegionPass(ID) {}
+  ~ScopInfoRegionPass() override = default;
+
+  /// Build Scop object, the Polly IR of static control
+  ///        part for the current SESE-Region.
+  ///
+  /// @return If the current region is a valid for a static control part,
+  ///         return the Polly IR representing this static control part,
+  ///         return null otherwise.
+  Scop *getScop() { return S.get(); }
+  const Scop *getScop() const { return S.get(); }
+
+  /// Calculate the polyhedral scop information for a given Region.
+  bool runOnRegion(Region *R, RGPassManager &RGM) override;
+
+  void releaseMemory() override { S.reset(); }
+
+  void print(raw_ostream &O, const Module *M = nullptr) const override;
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+};
+
+class ScopInfo {
+public:
+  using RegionToScopMapTy = MapVector<Region *, std::unique_ptr<Scop>>;
+  using reverse_iterator = RegionToScopMapTy::reverse_iterator;
+  using const_reverse_iterator = RegionToScopMapTy::const_reverse_iterator;
+  using iterator = RegionToScopMapTy::iterator;
+  using const_iterator = RegionToScopMapTy::const_iterator;
+
+private:
+  /// A map of Region to its Scop object containing
+  ///        Polly IR of static control part.
+  RegionToScopMapTy RegionToScopMap;
+  const DataLayout &DL;
+  ScopDetection &SD;
+  ScalarEvolution &SE;
+  LoopInfo &LI;
+  AliasAnalysis &AA;
+  DominatorTree &DT;
+  AssumptionCache &AC;
+  OptimizationRemarkEmitter &ORE;
+
+public:
+  ScopInfo(const DataLayout &DL, ScopDetection &SD, ScalarEvolution &SE,
+           LoopInfo &LI, AliasAnalysis &AA, DominatorTree &DT,
+           AssumptionCache &AC, OptimizationRemarkEmitter &ORE);
+
+  /// Get the Scop object for the given Region.
+  ///
+  /// @return If the given region is the maximal region within a scop, return
+  ///         the scop object. If the given region is a subregion, return a
+  ///         nullptr. Top level region containing the entry block of a function
+  ///         is not considered in the scop creation.
+  Scop *getScop(Region *R) const {
+    auto MapIt = RegionToScopMap.find(R);
+    if (MapIt != RegionToScopMap.end())
+      return MapIt->second.get();
+    return nullptr;
+  }
+
+  /// Recompute the Scop-Information for a function.
+  ///
+  /// This invalidates any iterators.
+  void recompute();
+
+  /// Handle invalidation explicitly
+  bool invalidate(Function &F, const PreservedAnalyses &PA,
+                  FunctionAnalysisManager::Invalidator &Inv);
+
+  iterator begin() { return RegionToScopMap.begin(); }
+  iterator end() { return RegionToScopMap.end(); }
+  const_iterator begin() const { return RegionToScopMap.begin(); }
+  const_iterator end() const { return RegionToScopMap.end(); }
+  reverse_iterator rbegin() { return RegionToScopMap.rbegin(); }
+  reverse_iterator rend() { return RegionToScopMap.rend(); }
+  const_reverse_iterator rbegin() const { return RegionToScopMap.rbegin(); }
+  const_reverse_iterator rend() const { return RegionToScopMap.rend(); }
+  bool empty() const { return RegionToScopMap.empty(); }
+};
+
+struct ScopInfoAnalysis : public AnalysisInfoMixin<ScopInfoAnalysis> {
+  static AnalysisKey Key;
+
+  using Result = ScopInfo;
+
+  Result run(Function &, FunctionAnalysisManager &);
+};
+
+struct ScopInfoPrinterPass : public PassInfoMixin<ScopInfoPrinterPass> {
+  ScopInfoPrinterPass(raw_ostream &OS) : Stream(OS) {}
+
+  PreservedAnalyses run(Function &, FunctionAnalysisManager &);
+
+  raw_ostream &Stream;
+};
+
+//===----------------------------------------------------------------------===//
+/// The legacy pass manager's analysis pass to compute scop information
+///        for the whole function.
+///
+/// This pass will maintain a map of the maximal region within a scop to its
+/// scop object for all the feasible scops present in a function.
+/// This pass is an alternative to the ScopInfoRegionPass in order to avoid a
+/// region pass manager.
+class ScopInfoWrapperPass : public FunctionPass {
+  std::unique_ptr<ScopInfo> Result;
+
+public:
+  ScopInfoWrapperPass() : FunctionPass(ID) {}
+  ~ScopInfoWrapperPass() override = default;
+
+  static char ID; // Pass identification, replacement for typeid
+
+  ScopInfo *getSI() { return Result.get(); }
+  const ScopInfo *getSI() const { return Result.get(); }
+
+  /// Calculate all the polyhedral scops for a given function.
+  bool runOnFunction(Function &F) override;
+
+  void releaseMemory() override { Result.reset(); }
+
+  void print(raw_ostream &O, const Module *M = nullptr) const override;
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+};
+
+} // end namespace polly
+
+#endif // POLLY_SCOPINFO_H
diff --git a/final/include/polly/ScopPass.h b/final/include/polly/ScopPass.h
new file mode 100644
index 0000000..5182a1b
--- /dev/null
+++ b/final/include/polly/ScopPass.h
@@ -0,0 +1,274 @@
+//===--------- ScopPass.h - Pass for Static Control Parts --------*-C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ScopPass class.  ScopPasses are just RegionPasses,
+// except they operate on Polly IR (Scop and ScopStmt) built by ScopInfo Pass.
+// Because they operate on Polly IR, not the LLVM IR, ScopPasses are not allowed
+// to modify the LLVM IR. Due to this limitation, the ScopPass class takes
+// care of declaring that no LLVM passes are invalidated.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_SCOP_PASS_H
+#define POLLY_SCOP_PASS_H
+
+#include "polly/ScopInfo.h"
+#include "llvm/ADT/PriorityWorklist.h"
+#include "llvm/Analysis/RegionPass.h"
+#include "llvm/IR/PassManager.h"
+
+using namespace llvm;
+
+namespace polly {
+class Scop;
+class SPMUpdater;
+struct ScopStandardAnalysisResults;
+
+using ScopAnalysisManager =
+    AnalysisManager<Scop, ScopStandardAnalysisResults &>;
+using ScopAnalysisManagerFunctionProxy =
+    InnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
+using FunctionAnalysisManagerScopProxy =
+    OuterAnalysisManagerProxy<FunctionAnalysisManager, Scop,
+                              ScopStandardAnalysisResults &>;
+} // namespace polly
+
+namespace llvm {
+using polly::Scop;
+using polly::ScopAnalysisManager;
+using polly::ScopAnalysisManagerFunctionProxy;
+using polly::ScopInfo;
+using polly::ScopStandardAnalysisResults;
+using polly::SPMUpdater;
+
+template <>
+class InnerAnalysisManagerProxy<ScopAnalysisManager, Function>::Result {
+public:
+  explicit Result(ScopAnalysisManager &InnerAM, ScopInfo &SI)
+      : InnerAM(&InnerAM), SI(&SI) {}
+  Result(Result &&R) : InnerAM(std::move(R.InnerAM)), SI(R.SI) {
+    R.InnerAM = nullptr;
+  }
+  Result &operator=(Result &&RHS) {
+    InnerAM = RHS.InnerAM;
+    SI = RHS.SI;
+    RHS.InnerAM = nullptr;
+    return *this;
+  }
+  ~Result() {
+    if (!InnerAM)
+      return;
+    InnerAM->clear();
+  }
+
+  ScopAnalysisManager &getManager() { return *InnerAM; }
+
+  bool invalidate(Function &F, const PreservedAnalyses &PA,
+                  FunctionAnalysisManager::Invalidator &Inv);
+
+private:
+  ScopAnalysisManager *InnerAM;
+  ScopInfo *SI;
+};
+
+// A partial specialization of the require analysis template pass to handle
+// extra parameters
+template <typename AnalysisT>
+struct RequireAnalysisPass<AnalysisT, Scop, ScopAnalysisManager,
+                           ScopStandardAnalysisResults &, SPMUpdater &>
+    : PassInfoMixin<
+          RequireAnalysisPass<AnalysisT, Scop, ScopAnalysisManager,
+                              ScopStandardAnalysisResults &, SPMUpdater &>> {
+  PreservedAnalyses run(Scop &L, ScopAnalysisManager &AM,
+                        ScopStandardAnalysisResults &AR, SPMUpdater &) {
+    (void)AM.template getResult<AnalysisT>(L, AR);
+    return PreservedAnalyses::all();
+  }
+};
+
+template <>
+InnerAnalysisManagerProxy<ScopAnalysisManager, Function>::Result
+InnerAnalysisManagerProxy<ScopAnalysisManager, Function>::run(
+    Function &F, FunctionAnalysisManager &FAM);
+
+template <>
+PreservedAnalyses
+PassManager<Scop, ScopAnalysisManager, ScopStandardAnalysisResults &,
+            SPMUpdater &>::run(Scop &InitialS, ScopAnalysisManager &AM,
+                               ScopStandardAnalysisResults &, SPMUpdater &);
+extern template class PassManager<Scop, ScopAnalysisManager,
+                                  ScopStandardAnalysisResults &, SPMUpdater &>;
+extern template class InnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
+extern template class OuterAnalysisManagerProxy<FunctionAnalysisManager, Scop,
+                                                ScopStandardAnalysisResults &>;
+} // namespace llvm
+
+namespace polly {
+
+template <typename AnalysisManagerT, typename IRUnitT, typename... ExtraArgTs>
+class OwningInnerAnalysisManagerProxy
+    : public InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT> {
+public:
+  OwningInnerAnalysisManagerProxy()
+      : InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT>(InnerAM) {}
+  using Result = typename InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT,
+                                                    ExtraArgTs...>::Result;
+  Result run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
+             ExtraArgTs...) {
+    return Result(InnerAM);
+  }
+
+  AnalysisManagerT &getManager() { return InnerAM; }
+
+private:
+  AnalysisManagerT InnerAM;
+};
+
+template <>
+OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>::Result
+OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>::run(
+    Function &F, FunctionAnalysisManager &FAM);
+extern template class OwningInnerAnalysisManagerProxy<ScopAnalysisManager,
+                                                      Function>;
+
+using OwningScopAnalysisManagerFunctionProxy =
+    OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
+using ScopPassManager =
+    PassManager<Scop, ScopAnalysisManager, ScopStandardAnalysisResults &,
+                SPMUpdater &>;
+
+/// ScopPass - This class adapts the RegionPass interface to allow convenient
+/// creation of passes that operate on the Polly IR. Instead of overriding
+/// runOnRegion, subclasses override runOnScop.
+class ScopPass : public RegionPass {
+  Scop *S;
+
+protected:
+  explicit ScopPass(char &ID) : RegionPass(ID), S(0) {}
+
+  /// runOnScop - This method must be overloaded to perform the
+  /// desired Polyhedral transformation or analysis.
+  ///
+  virtual bool runOnScop(Scop &S) = 0;
+
+  /// Print method for SCoPs.
+  virtual void printScop(raw_ostream &OS, Scop &S) const {}
+
+  /// getAnalysisUsage - Subclasses that override getAnalysisUsage
+  /// must call this.
+  ///
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  bool runOnRegion(Region *R, RGPassManager &RGM) override;
+  void print(raw_ostream &OS, const Module *) const override;
+};
+
+struct ScopStandardAnalysisResults {
+  DominatorTree &DT;
+  ScopInfo &SI;
+  ScalarEvolution &SE;
+  LoopInfo &LI;
+  RegionInfo &RI;
+};
+
+class SPMUpdater {
+public:
+  SPMUpdater(SmallPriorityWorklist<Region *, 4> &Worklist,
+             ScopAnalysisManager &SAM)
+      : InvalidateCurrentScop(false), Worklist(Worklist), SAM(SAM) {}
+
+  bool invalidateCurrentScop() const { return InvalidateCurrentScop; }
+
+  void invalidateScop(Scop &S) {
+    if (&S == CurrentScop)
+      InvalidateCurrentScop = true;
+
+    Worklist.erase(&S.getRegion());
+    SAM.clear(S, S.getName());
+  }
+
+private:
+  Scop *CurrentScop;
+  bool InvalidateCurrentScop;
+  SmallPriorityWorklist<Region *, 4> &Worklist;
+  ScopAnalysisManager &SAM;
+  template <typename ScopPassT> friend class FunctionToScopPassAdaptor;
+};
+
+template <typename ScopPassT>
+class FunctionToScopPassAdaptor
+    : public PassInfoMixin<FunctionToScopPassAdaptor<ScopPassT>> {
+public:
+  explicit FunctionToScopPassAdaptor(ScopPassT Pass) : Pass(std::move(Pass)) {}
+
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
+    PreservedAnalyses PA = PreservedAnalyses::all();
+    auto &SD = AM.getResult<ScopAnalysis>(F);
+    auto &SI = AM.getResult<ScopInfoAnalysis>(F);
+    if (SI.empty())
+      return PA;
+
+    SmallPriorityWorklist<Region *, 4> Worklist;
+    for (auto &S : SI)
+      if (S.second)
+        Worklist.insert(S.first);
+
+    ScopStandardAnalysisResults AR = {AM.getResult<DominatorTreeAnalysis>(F),
+                                      AM.getResult<ScopInfoAnalysis>(F),
+                                      AM.getResult<ScalarEvolutionAnalysis>(F),
+                                      AM.getResult<LoopAnalysis>(F),
+                                      AM.getResult<RegionInfoAnalysis>(F)};
+
+    ScopAnalysisManager &SAM =
+        AM.getResult<ScopAnalysisManagerFunctionProxy>(F).getManager();
+
+    SPMUpdater Updater{Worklist, SAM};
+
+    while (!Worklist.empty()) {
+      Region *R = Worklist.pop_back_val();
+      if (!SD.isMaxRegionInScop(*R))
+        continue;
+      Scop *scop = SI.getScop(R);
+      if (!scop)
+        continue;
+      Updater.CurrentScop = scop;
+      Updater.InvalidateCurrentScop = false;
+      PreservedAnalyses PassPA = Pass.run(*scop, SAM, AR, Updater);
+
+      SAM.invalidate(*scop, PassPA);
+      PA.intersect(std::move(PassPA));
+      if (Updater.invalidateCurrentScop())
+        SI.recompute();
+    };
+
+    PA.preserveSet<AllAnalysesOn<Scop>>();
+    PA.preserve<ScopAnalysisManagerFunctionProxy>();
+    PA.preserve<DominatorTreeAnalysis>();
+    PA.preserve<ScopAnalysis>();
+    PA.preserve<ScopInfoAnalysis>();
+    PA.preserve<ScalarEvolutionAnalysis>();
+    PA.preserve<LoopAnalysis>();
+    PA.preserve<RegionInfoAnalysis>();
+    return PA;
+  }
+
+private:
+  ScopPassT Pass;
+}; // namespace polly
+
+template <typename ScopPassT>
+FunctionToScopPassAdaptor<ScopPassT>
+createFunctionToScopPassAdaptor(ScopPassT Pass) {
+  return FunctionToScopPassAdaptor<ScopPassT>(std::move(Pass));
+}
+
+} // namespace polly
+
+#endif
diff --git a/final/include/polly/Simplify.h b/final/include/polly/Simplify.h
new file mode 100644
index 0000000..20c0517
--- /dev/null
+++ b/final/include/polly/Simplify.h
@@ -0,0 +1,60 @@
+//===------ Simplify.h ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Simplify a SCoP by removing unnecessary statements and accesses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_TRANSFORM_SIMPLIFY_H
+#define POLLY_TRANSFORM_SIMPLIFY_H
+
+#include "llvm/ADT/SmallVector.h"
+
+namespace llvm {
+class PassRegistry;
+class Pass;
+} // namespace llvm
+
+namespace polly {
+
+class MemoryAccess;
+class ScopStmt;
+
+/// Return a vector that contains MemoryAccesses in the order in
+/// which they are executed.
+///
+/// The order is:
+/// - Implicit reads (BlockGenerator::generateScalarLoads)
+/// - Explicit reads and writes (BlockGenerator::generateArrayLoad,
+///   BlockGenerator::generateArrayStore)
+///   - In block statements, the accesses are in order in which their
+///     instructions are executed.
+///   - In region statements, that order of execution is not predictable at
+///     compile-time.
+/// - Implicit writes (BlockGenerator::generateScalarStores)
+///   The order in which implicit writes are executed relative to each other is
+///   undefined.
+llvm::SmallVector<MemoryAccess *, 32> getAccessesInOrder(ScopStmt &Stmt);
+
+/// Create a Simplify pass
+///
+/// @param CallNo Disambiguates this instance for when there are multiple
+///               instances of this pass in the pass manager. It is used only to
+///               keep the statistics apart and has no influence on the
+///               simplification itself.
+///
+/// @return The Simplify pass.
+llvm::Pass *createSimplifyPass(int CallNo = 0);
+} // namespace polly
+
+namespace llvm {
+void initializeSimplifyPass(llvm::PassRegistry &);
+} // namespace llvm
+
+#endif /* POLLY_TRANSFORM_SIMPLIFY_H */
diff --git a/final/include/polly/Support/DumpModulePass.h b/final/include/polly/Support/DumpModulePass.h
new file mode 100644
index 0000000..9b16051
--- /dev/null
+++ b/final/include/polly/Support/DumpModulePass.h
@@ -0,0 +1,40 @@
+//===------ DumpModulePass.h ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Write a module to a file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_SUPPORT_DUMPMODULEPASS_H
+#define POLLY_SUPPORT_DUMPMODULEPASS_H
+
+namespace llvm {
+class StringRef;
+class ModulePass;
+} // namespace llvm
+
+namespace polly {
+/// Create a pass that prints the module into a file.
+///
+/// The meaning of @p Filename depends on @p IsSuffix. If IsSuffix==false, then
+/// the module is written to the @p Filename. If it is true, the filename is
+/// generated from the module's name, @p Filename with an '.ll' extension.
+///
+/// The intent of IsSuffix is to avoid the file being overwritten when
+/// processing multiple modules and/or with multiple dump passes in the
+/// pipeline.
+llvm::ModulePass *createDumpModulePass(llvm::StringRef Filename, bool IsSuffix);
+} // namespace polly
+
+namespace llvm {
+class PassRegistry;
+void initializeDumpModulePass(llvm::PassRegistry &);
+} // namespace llvm
+
+#endif /* POLLY_SUPPORT_DUMPMODULEPASS_H */
diff --git a/final/include/polly/Support/GICHelper.h b/final/include/polly/Support/GICHelper.h
new file mode 100644
index 0000000..3c0fe40
--- /dev/null
+++ b/final/include/polly/Support/GICHelper.h
@@ -0,0 +1,436 @@
+//===- Support/GICHelper.h -- Helper functions for ISL --------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper functions for isl objects.
+//
+//===----------------------------------------------------------------------===//
+//
+#ifndef POLLY_SUPPORT_GIC_HELPER_H
+#define POLLY_SUPPORT_GIC_HELPER_H
+
+#include "llvm/ADT/APInt.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/Support/raw_ostream.h"
+#include "isl/aff.h"
+#include "isl/ctx.h"
+#include "isl/isl-noexceptions.h"
+#include "isl/map.h"
+#include "isl/options.h"
+#include "isl/set.h"
+#include "isl/union_map.h"
+#include "isl/union_set.h"
+#include <functional>
+#include <string>
+
+struct isl_schedule;
+struct isl_multi_aff;
+
+namespace llvm {
+class Value;
+} // namespace llvm
+
+namespace polly {
+
+/// Translate an llvm::APInt to an isl_val.
+///
+/// Translate the bitsequence without sign information as provided by APInt into
+/// a signed isl_val type. Depending on the value of @p IsSigned @p Int is
+/// interpreted as unsigned value or as signed value in two's complement
+/// representation.
+///
+/// Input IsSigned                 Output
+///
+///     0        0           ->    0
+///     1        0           ->    1
+///    00        0           ->    0
+///    01        0           ->    1
+///    10        0           ->    2
+///    11        0           ->    3
+///
+///     0        1           ->    0
+///     1        1           ->   -1
+///    00        1           ->    0
+///    01        1           ->    1
+///    10        1           ->   -2
+///    11        1           ->   -1
+///
+/// @param Ctx      The isl_ctx to create the isl_val in.
+/// @param Int      The integer value to translate.
+/// @param IsSigned If the APInt should be interpreted as signed or unsigned
+///                 value.
+///
+/// @return The isl_val corresponding to @p Int.
+__isl_give isl_val *isl_valFromAPInt(isl_ctx *Ctx, const llvm::APInt Int,
+                                     bool IsSigned);
+
+/// Translate an llvm::APInt to an isl::val.
+///
+/// Translate the bitsequence without sign information as provided by APInt into
+/// a signed isl::val type. Depending on the value of @p IsSigned @p Int is
+/// interpreted as unsigned value or as signed value in two's complement
+/// representation.
+///
+/// Input IsSigned                 Output
+///
+///     0        0           ->    0
+///     1        0           ->    1
+///    00        0           ->    0
+///    01        0           ->    1
+///    10        0           ->    2
+///    11        0           ->    3
+///
+///     0        1           ->    0
+///     1        1           ->   -1
+///    00        1           ->    0
+///    01        1           ->    1
+///    10        1           ->   -2
+///    11        1           ->   -1
+///
+/// @param Ctx      The isl_ctx to create the isl::val in.
+/// @param Int      The integer value to translate.
+/// @param IsSigned If the APInt should be interpreted as signed or unsigned
+///                 value.
+///
+/// @return The isl::val corresponding to @p Int.
+inline isl::val valFromAPInt(isl_ctx *Ctx, const llvm::APInt Int,
+                             bool IsSigned) {
+  return isl::manage(isl_valFromAPInt(Ctx, Int, IsSigned));
+}
+
+/// Translate isl_val to llvm::APInt.
+///
+/// This function can only be called on isl_val values which are integers.
+/// Calling this function with a non-integral rational, NaN or infinity value
+/// is not allowed.
+///
+/// As the input isl_val may be negative, the APInt that this function returns
+/// must always be interpreted as signed two's complement value. The bitwidth of
+/// the generated APInt is always the minimal bitwidth necessary to model the
+/// provided integer when interpreting the bit pattern as signed value.
+///
+/// Some example conversions are:
+///
+///   Input      Bits    Signed  Bitwidth
+///       0 ->      0         0         1
+///      -1 ->      1        -1         1
+///       1 ->     01         1         2
+///      -2 ->     10        -2         2
+///       2 ->    010         2         3
+///      -3 ->    101        -3         3
+///       3 ->    011         3         3
+///      -4 ->    100        -4         3
+///       4 ->   0100         4         4
+///
+/// @param Val The isl val to translate.
+///
+/// @return The APInt value corresponding to @p Val.
+llvm::APInt APIntFromVal(__isl_take isl_val *Val);
+
+/// Translate isl::val to llvm::APInt.
+///
+/// This function can only be called on isl::val values which are integers.
+/// Calling this function with a non-integral rational, NaN or infinity value
+/// is not allowed.
+///
+/// As the input isl::val may be negative, the APInt that this function returns
+/// must always be interpreted as signed two's complement value. The bitwidth of
+/// the generated APInt is always the minimal bitwidth necessary to model the
+/// provided integer when interpreting the bit pattern as signed value.
+///
+/// Some example conversions are:
+///
+///   Input      Bits    Signed  Bitwidth
+///       0 ->      0         0         1
+///      -1 ->      1        -1         1
+///       1 ->     01         1         2
+///      -2 ->     10        -2         2
+///       2 ->    010         2         3
+///      -3 ->    101        -3         3
+///       3 ->    011         3         3
+///      -4 ->    100        -4         3
+///       4 ->   0100         4         4
+///
+/// @param Val The isl val to translate.
+///
+/// @return The APInt value corresponding to @p Val.
+inline llvm::APInt APIntFromVal(isl::val V) {
+  return APIntFromVal(V.release());
+}
+
+/// Get c++ string from Isl objects.
+//@{
+std::string stringFromIslObj(__isl_keep isl_map *map);
+std::string stringFromIslObj(__isl_keep isl_union_map *umap);
+std::string stringFromIslObj(__isl_keep isl_set *set);
+std::string stringFromIslObj(__isl_keep isl_union_set *uset);
+std::string stringFromIslObj(__isl_keep isl_schedule *schedule);
+std::string stringFromIslObj(__isl_keep isl_multi_aff *maff);
+std::string stringFromIslObj(__isl_keep isl_pw_multi_aff *pma);
+std::string stringFromIslObj(__isl_keep isl_multi_pw_aff *mpa);
+std::string stringFromIslObj(__isl_keep isl_union_pw_multi_aff *upma);
+std::string stringFromIslObj(__isl_keep isl_aff *aff);
+std::string stringFromIslObj(__isl_keep isl_pw_aff *pwaff);
+std::string stringFromIslObj(__isl_keep isl_space *space);
+//@}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     __isl_keep isl_union_map *Map) {
+  OS << polly::stringFromIslObj(Map);
+  return OS;
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     __isl_keep isl_map *Map) {
+  OS << polly::stringFromIslObj(Map);
+  return OS;
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     __isl_keep isl_set *Set) {
+  OS << polly::stringFromIslObj(Set);
+  return OS;
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     __isl_keep isl_pw_aff *Map) {
+  OS << polly::stringFromIslObj(Map);
+  return OS;
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     __isl_keep isl_pw_multi_aff *PMA) {
+  OS << polly::stringFromIslObj(PMA);
+  return OS;
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     __isl_keep isl_multi_aff *MA) {
+  OS << polly::stringFromIslObj(MA);
+  return OS;
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     __isl_keep isl_union_pw_multi_aff *UPMA) {
+  OS << polly::stringFromIslObj(UPMA);
+  return OS;
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     __isl_keep isl_schedule *Schedule) {
+  OS << polly::stringFromIslObj(Schedule);
+  return OS;
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     __isl_keep isl_space *Space) {
+  OS << polly::stringFromIslObj(Space);
+  return OS;
+}
+
+/// Combine Prefix, Val (or Number) and Suffix to an isl-compatible name.
+///
+/// In case @p UseInstructionNames is set, this function returns:
+///
+/// @p Prefix + "_" + @p Val->getName() + @p Suffix
+///
+/// otherwise
+///
+/// @p Prefix + to_string(Number) + @p Suffix
+///
+/// We ignore the value names by default, as they may change between release
+/// and debug mode and can consequently not be used when aiming for reproducible
+/// builds. However, for debugging named statements are often helpful, hence
+/// we allow their optional use.
+std::string getIslCompatibleName(const std::string &Prefix,
+                                 const llvm::Value *Val, long Number,
+                                 const std::string &Suffix,
+                                 bool UseInstructionNames);
+
+/// Combine Prefix, Name (or Number) and Suffix to an isl-compatible name.
+///
+/// In case @p UseInstructionNames is set, this function returns:
+///
+/// @p Prefix + "_" + Name + @p Suffix
+///
+/// otherwise
+///
+/// @p Prefix + to_string(Number) + @p Suffix
+///
+/// We ignore @p Name by default, as they may change between release
+/// and debug mode and can consequently not be used when aiming for reproducible
+/// builds. However, for debugging named statements are often helpful, hence
+/// we allow their optional use.
+std::string getIslCompatibleName(const std::string &Prefix,
+                                 const std::string &Middle, long Number,
+                                 const std::string &Suffix,
+                                 bool UseInstructionNames);
+
+std::string getIslCompatibleName(const std::string &Prefix,
+                                 const std::string &Middle,
+                                 const std::string &Suffix);
+
+// Make isl::give available in polly namespace. We do this as there was
+// previously a function polly::give() which did the very same thing and we
+// did not want yet to introduce the isl:: prefix to each call of give.
+using isl::give;
+
+inline llvm::DiagnosticInfoOptimizationBase &
+operator<<(llvm::DiagnosticInfoOptimizationBase &OS,
+           const isl::union_map &Obj) {
+  OS << Obj.to_str();
+  return OS;
+}
+
+/// Scope guard for code that allows arbitrary isl function to return an error
+/// if the max-operations quota exceeds.
+///
+/// This allows to opt-in code sections that have known long executions times.
+/// code not in a hot path can continue to assume that no unexpected error
+/// occurs.
+///
+/// This is typically used inside a nested IslMaxOperationsGuard scope. The
+/// IslMaxOperationsGuard defines the number of allowed base operations for some
+/// code, IslQuotaScope defines where it is allowed to return an error result.
+class IslQuotaScope {
+  isl_ctx *IslCtx;
+  int OldOnError;
+
+public:
+  IslQuotaScope() : IslCtx(nullptr) {}
+  IslQuotaScope(const IslQuotaScope &) = delete;
+  IslQuotaScope(IslQuotaScope &&Other)
+      : IslCtx(Other.IslCtx), OldOnError(Other.OldOnError) {
+    Other.IslCtx = nullptr;
+  }
+  const IslQuotaScope &operator=(IslQuotaScope &&Other) {
+    std::swap(this->IslCtx, Other.IslCtx);
+    std::swap(this->OldOnError, Other.OldOnError);
+    return *this;
+  }
+
+  /// Enter a quota-aware scope.
+  ///
+  /// Should not be used directly. Use IslMaxOperationsGuard::enter() instead.
+  explicit IslQuotaScope(isl_ctx *IslCtx, unsigned long LocalMaxOps)
+      : IslCtx(IslCtx) {
+    assert(IslCtx);
+    assert(isl_ctx_get_max_operations(IslCtx) == 0 && "Incorrect nesting");
+    if (LocalMaxOps == 0) {
+      this->IslCtx = nullptr;
+      return;
+    }
+
+    OldOnError = isl_options_get_on_error(IslCtx);
+    isl_options_set_on_error(IslCtx, ISL_ON_ERROR_CONTINUE);
+    isl_ctx_reset_error(IslCtx);
+    isl_ctx_set_max_operations(IslCtx, LocalMaxOps);
+  }
+
+  ~IslQuotaScope() {
+    if (!IslCtx)
+      return;
+
+    assert(isl_ctx_get_max_operations(IslCtx) > 0 && "Incorrect nesting");
+    assert(isl_options_get_on_error(IslCtx) == ISL_ON_ERROR_CONTINUE &&
+           "Incorrect nesting");
+    isl_ctx_set_max_operations(IslCtx, 0);
+    isl_options_set_on_error(IslCtx, OldOnError);
+  }
+
+  /// Return whether the current quota has exceeded.
+  bool hasQuotaExceeded() const {
+    if (!IslCtx)
+      return false;
+
+    return isl_ctx_last_error(IslCtx) == isl_error_quota;
+  }
+};
+
+/// Scoped limit of ISL operations.
+///
+/// Limits the number of ISL operations during the lifetime of this object. The
+/// idea is to use this as an RAII guard for the scope where the code is aware
+/// that ISL can return errors even when all input is valid. After leaving the
+/// scope, it will return to the error setting as it was before. That also means
+/// that the error setting should not be changed while in that scope.
+///
+/// Such scopes are not allowed to be nested because the previous operations
+/// counter cannot be reset to the previous state, or one that adds the
+/// operations while being in the nested scope. Use therefore is only allowed
+/// while currently a no operations-limit is active.
+class IslMaxOperationsGuard {
+private:
+  /// The ISL context to set the operations limit.
+  ///
+  /// If set to nullptr, there is no need for any action at the end of the
+  /// scope.
+  isl_ctx *IslCtx;
+
+  /// Maximum number of operations for the scope.
+  unsigned long LocalMaxOps;
+
+  /// When AutoEnter is enabled, holds the IslQuotaScope object.
+  IslQuotaScope TopLevelScope;
+
+public:
+  /// Enter a max operations scope.
+  ///
+  /// @param IslCtx      The ISL context to set the operations limit for.
+  /// @param LocalMaxOps Maximum number of operations allowed in the
+  ///                    scope. If set to zero, no operations limit is enforced.
+  /// @param AutoEnter   If true, automatically enters an IslQuotaScope such
+  ///                    that isl operations may return quota errors
+  ///                    immediately. If false, only starts the operations
+  ///                    counter, but isl does not return quota errors before
+  ///                    calling enter().
+  IslMaxOperationsGuard(isl_ctx *IslCtx, unsigned long LocalMaxOps,
+                        bool AutoEnter = true)
+      : IslCtx(IslCtx), LocalMaxOps(LocalMaxOps) {
+    assert(IslCtx);
+    assert(isl_ctx_get_max_operations(IslCtx) == 0 &&
+           "Nested max operations not supported");
+
+    // Users of this guard may check whether the last error was isl_error_quota.
+    // Reset the last error such that a previous out-of-quota error is not
+    // mistaken to have occurred in the in this quota, even if the max number of
+    // operations is set to infinite (LocalMaxOps == 0).
+    isl_ctx_reset_error(IslCtx);
+
+    if (LocalMaxOps == 0) {
+      // No limit on operations; also disable restoring on_error/max_operations.
+      this->IslCtx = nullptr;
+      return;
+    }
+
+    isl_ctx_reset_operations(IslCtx);
+    TopLevelScope = enter(AutoEnter);
+  }
+
+  /// Enter a scope that can handle out-of-quota errors.
+  ///
+  /// @param AllowReturnNull Whether the scoped code can handle out-of-quota
+  ///                        errors. If false, returns a dummy scope object that
+  ///                        does nothing.
+  IslQuotaScope enter(bool AllowReturnNull = true) {
+    return AllowReturnNull && IslCtx ? IslQuotaScope(IslCtx, LocalMaxOps)
+                                     : IslQuotaScope();
+  }
+
+  /// Return whether the current quota has exceeded.
+  bool hasQuotaExceeded() const {
+    if (!IslCtx)
+      return false;
+
+    return isl_ctx_last_error(IslCtx) == isl_error_quota;
+  }
+};
+
+} // end namespace polly
+
+#endif
diff --git a/final/include/polly/Support/ISLOStream.h b/final/include/polly/Support/ISLOStream.h
new file mode 100644
index 0000000..fd9c941
--- /dev/null
+++ b/final/include/polly/Support/ISLOStream.h
@@ -0,0 +1,48 @@
+//===------ IslOstream.h ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// raw_ostream printers for isl C++ objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/raw_ostream.h"
+#include "isl/isl-noexceptions.h"
+namespace polly {
+
+#define ADD_OSTREAM_PRINTER(name)                                              \
+  inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,                  \
+                                       const name &Obj) {                      \
+    OS << Obj.to_str();                                                        \
+    return OS;                                                                 \
+  }
+
+ADD_OSTREAM_PRINTER(isl::aff)
+ADD_OSTREAM_PRINTER(isl::ast_expr)
+ADD_OSTREAM_PRINTER(isl::ast_node)
+ADD_OSTREAM_PRINTER(isl::basic_map)
+ADD_OSTREAM_PRINTER(isl::basic_set)
+ADD_OSTREAM_PRINTER(isl::map)
+ADD_OSTREAM_PRINTER(isl::set)
+ADD_OSTREAM_PRINTER(isl::id)
+ADD_OSTREAM_PRINTER(isl::multi_aff)
+ADD_OSTREAM_PRINTER(isl::multi_pw_aff)
+ADD_OSTREAM_PRINTER(isl::multi_union_pw_aff)
+ADD_OSTREAM_PRINTER(isl::point)
+ADD_OSTREAM_PRINTER(isl::pw_aff)
+ADD_OSTREAM_PRINTER(isl::pw_multi_aff)
+ADD_OSTREAM_PRINTER(isl::schedule)
+ADD_OSTREAM_PRINTER(isl::schedule_node)
+ADD_OSTREAM_PRINTER(isl::space)
+ADD_OSTREAM_PRINTER(isl::union_access_info)
+ADD_OSTREAM_PRINTER(isl::union_flow)
+ADD_OSTREAM_PRINTER(isl::union_set)
+ADD_OSTREAM_PRINTER(isl::union_map)
+ADD_OSTREAM_PRINTER(isl::union_pw_aff)
+ADD_OSTREAM_PRINTER(isl::union_pw_multi_aff)
+} // namespace polly
diff --git a/final/include/polly/Support/ISLTools.h b/final/include/polly/Support/ISLTools.h
new file mode 100644
index 0000000..0dfb530
--- /dev/null
+++ b/final/include/polly/Support/ISLTools.h
@@ -0,0 +1,528 @@
+//===------ ISLTools.h ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tools, utilities, helpers and extensions useful in conjunction with the
+// Integer Set Library (isl).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_ISLTOOLS_H
+#define POLLY_ISLTOOLS_H
+
+#include "polly/Support/GICHelper.h"
+
+namespace polly {
+
+/// Return the range elements that are lexicographically smaller.
+///
+/// @param Map    { Space[] -> Scatter[] }
+/// @param Strict True for strictly lexicographically smaller elements (exclude
+///               same timepoints from the result).
+///
+/// @return { Space[] -> Scatter[] }
+///         A map to all timepoints that happen before the timepoints the input
+///         mapped to.
+isl::map beforeScatter(isl::map Map, bool Strict);
+
+/// Piecewise beforeScatter(isl::map,bool).
+isl::union_map beforeScatter(isl::union_map UMap, bool Strict);
+
+/// Return the range elements that are lexicographically larger.
+///
+/// @param Map    { Space[] -> Scatter[] }
+/// @param Strict True for strictly lexicographically larger elements (exclude
+///               same timepoints from the result).
+///
+/// @return { Space[] -> Scatter[] }
+///         A map to all timepoints that happen after the timepoints the input
+///         map originally mapped to.
+isl::map afterScatter(isl::map Map, bool Strict);
+
+/// Piecewise afterScatter(isl::map,bool).
+isl::union_map afterScatter(const isl::union_map &UMap, bool Strict);
+
+/// Construct a range of timepoints between two timepoints.
+///
+/// Example:
+/// From := { A[] -> [0]; B[] -> [0] }
+/// To   := {             B[] -> [10]; C[] -> [20] }
+///
+/// Result:
+/// { B[] -> [i] : 0 < i < 10 }
+///
+/// Note that A[] and C[] are not in the result because they do not have a start
+/// or end timepoint. If a start (or end) timepoint is not unique, the first
+/// (respectively last) is chosen.
+///
+/// @param From     { Space[] -> Scatter[] }
+///                 Map to start timepoints.
+/// @param To       { Space[] -> Scatter[] }
+///                 Map to end timepoints.
+/// @param InclFrom Whether to include the start timepoints in the result. In
+///                 the example, this would add { B[] -> [0] }
+/// @param InclTo   Whether to include the end timepoints in the result. In this
+///                 example, this would add { B[] -> [10] }
+///
+/// @return { Space[] -> Scatter[] }
+///         A map for each domain element of timepoints between two extreme
+///         points, or nullptr if @p From or @p To is nullptr, or the isl max
+///         operations is exceeded.
+isl::map betweenScatter(isl::map From, isl::map To, bool InclFrom, bool InclTo);
+
+/// Piecewise betweenScatter(isl::map,isl::map,bool,bool).
+isl::union_map betweenScatter(isl::union_map From, isl::union_map To,
+                              bool InclFrom, bool InclTo);
+
+/// If by construction a union map is known to contain only a single map, return
+/// it.
+///
+/// This function combines isl_map_from_union_map() and
+/// isl_union_map_extract_map(). isl_map_from_union_map() fails if the map is
+/// empty because it does not know which space it would be in.
+/// isl_union_map_extract_map() on the other hand does not check whether there
+/// is (at most) one isl_map in the union, i.e. how it has been constructed is
+/// probably wrong.
+isl::map singleton(isl::union_map UMap, isl::space ExpectedSpace);
+
+/// If by construction an isl_union_set is known to contain only a single
+/// isl_set, return it.
+///
+/// This function combines isl_set_from_union_set() and
+/// isl_union_set_extract_set(). isl_map_from_union_set() fails if the set is
+/// empty because it does not know which space it would be in.
+/// isl_union_set_extract_set() on the other hand does not check whether there
+/// is (at most) one isl_set in the union, i.e. how it has been constructed is
+/// probably wrong.
+isl::set singleton(isl::union_set USet, isl::space ExpectedSpace);
+
+/// Determine how many dimensions the scatter space of @p Schedule has.
+///
+/// The schedule must not be empty and have equal number of dimensions of any
+/// subspace it contains.
+///
+/// The implementation currently returns the maximum number of dimensions it
+/// encounters, if different, and 0 if none is encountered. However, most other
+/// code will most likely fail if one of these happen.
+unsigned getNumScatterDims(const isl::union_map &Schedule);
+
+/// Return the scatter space of a @p Schedule.
+///
+/// This is basically the range space of the schedule map, but harder to
+/// determine because it is an isl_union_map.
+isl::space getScatterSpace(const isl::union_map &Schedule);
+
+/// Construct an identity map for the given domain values.
+///
+/// There is no type resembling isl_union_space, hence we have to pass an
+/// isl_union_set as the map's domain and range space.
+///
+/// @param USet           { Space[] }
+///                       The returned map's domain and range.
+/// @param RestrictDomain If true, the returned map only maps elements contained
+///                       in @p USet and no other. If false, it returns an
+///                       overapproximation with the identity maps of any space
+///                       in @p USet, not just the elements in it.
+///
+/// @return { Space[] -> Space[] }
+///         A map that maps each value of @p USet to itself.
+isl::union_map makeIdentityMap(const isl::union_set &USet, bool RestrictDomain);
+
+/// Reverse the nested map tuple in @p Map's domain.
+///
+/// @param Map { [Space1[] -> Space2[]] -> Space3[] }
+///
+/// @return { [Space2[] -> Space1[]] -> Space3[] }
+isl::map reverseDomain(isl::map Map);
+
+/// Piecewise reverseDomain(isl::map).
+isl::union_map reverseDomain(const isl::union_map &UMap);
+
+/// Add a constant to one dimension of a set.
+///
+/// @param Map    The set to shift a dimension in.
+/// @param Pos    The dimension to shift. If negative, the dimensions are
+///               counted from the end instead from the beginning. E.g. -1 is
+///               the last dimension in the tuple.
+/// @param Amount The offset to add to the specified dimension.
+///
+/// @return The modified set.
+isl::set shiftDim(isl::set Set, int Pos, int Amount);
+
+/// Piecewise shiftDim(isl::set,int,int).
+isl::union_set shiftDim(isl::union_set USet, int Pos, int Amount);
+
+/// Add a constant to one dimension of a map.
+///
+/// @param Map    The map to shift a dimension in.
+/// @param Type   A tuple of @p Map which contains the dimension to shift.
+/// @param Pos    The dimension to shift. If negative, the dimensions are
+/// counted from the end instead from the beginning. Eg. -1 is the last
+/// dimension in the tuple.
+/// @param Amount The offset to add to the specified dimension.
+///
+/// @return The modified map.
+isl::map shiftDim(isl::map Map, isl::dim Dim, int Pos, int Amount);
+
+/// Add a constant to one dimension of a each map in a union map.
+///
+/// @param UMap   The maps to shift a dimension in.
+/// @param Type   The tuple which contains the dimension to shift.
+/// @param Pos    The dimension to shift. If negative, the dimensions are
+///               counted from the ends of each map of union instead from their
+///               beginning. E.g. -1 is the last dimension of any map.
+/// @param Amount The offset to add to the specified dimension.
+///
+/// @return The union of all modified maps.
+isl::union_map shiftDim(isl::union_map UMap, isl::dim Dim, int Pos, int Amount);
+
+/// Simplify a set inplace.
+void simplify(isl::set &Set);
+
+/// Simplify a union set inplace.
+void simplify(isl::union_set &USet);
+
+/// Simplify a map inplace.
+void simplify(isl::map &Map);
+
+/// Simplify a union map inplace.
+void simplify(isl::union_map &UMap);
+
+/// Compute the reaching definition statement or the next overwrite for each
+/// definition of an array element.
+///
+/// The reaching definition of an array element at a specific timepoint is the
+/// statement instance that has written the current element's content.
+/// Alternatively, this function determines for each timepoint and element which
+/// write is going to overwrite an element at a future timepoint. This can be
+/// seen as "reaching definition in reverse" where definitions are found in the
+/// past.
+///
+/// For example:
+///
+/// Schedule := { Write[] -> [0]; Overwrite[] -> [10] }
+/// Defs := { Write[] -> A[5]; Overwrite[] -> A[5] }
+///
+/// If index 5 of array A is written at timepoint 0 and 10, the resulting
+/// reaching definitions are:
+///
+/// { [A[5] -> [i]] -> Write[] : 0 < i < 10;
+///   [A[5] -> [i]] -> Overwrite[] : 10 < i }
+///
+/// Between timepoint 0 (Write[]) and timepoint 10 (Overwrite[]), the
+/// content of A[5] is written by statement instance Write[] and after
+/// timepoint 10 by Overwrite[]. Values not defined in the map have no known
+/// definition. This includes the statement instance timepoints themselves,
+/// because reads at those timepoints could either read the old or the new
+/// value, defined only by the statement itself. But this can be changed by @p
+/// InclPrevDef and @p InclNextDef. InclPrevDef=false and InclNextDef=true
+/// returns a zone. Unless @p InclPrevDef and @p InclNextDef are both true,
+/// there is only one unique definition per element and timepoint.
+///
+/// @param Schedule    { DomainWrite[] -> Scatter[] }
+///                    Schedule of (at least) all array writes. Instances not in
+///                    @p Writes are ignored.
+/// @param Writes      { DomainWrite[] -> Element[] }
+///                    Elements written to by the statement instances.
+/// @param Reverse     If true, look for definitions in the future. That is,
+///                    find the write that is overwrites the current value.
+/// @param InclPrevDef Include the definition's timepoint to the set of
+///                    well-defined elements (any load at that timepoint happen
+///                    at the writes). In the example, enabling this option adds
+///                    {[A[5] -> [0]] -> Write[]; [A[5] -> [10]] -> Overwrite[]}
+///                    to the result.
+/// @param InclNextDef Whether to assume that at the timepoint where an element
+///                    is overwritten, it still contains the old value (any load
+///                    at that timepoint would happen before the overwrite). In
+///                    this example, enabling this adds
+///                    { [A[] -> [10]] -> Write[] } to the result.
+///
+/// @return { [Element[] -> Scatter[]] -> DomainWrite[] }
+///         The reaching definitions or future overwrite as described above, or
+///         nullptr if either @p Schedule or @p Writes is nullptr, or the isl
+///         max operations count has exceeded.
+isl::union_map computeReachingWrite(isl::union_map Schedule,
+                                    isl::union_map Writes, bool Reverse,
+                                    bool InclPrevDef, bool InclNextDef);
+
+/// Compute the timepoints where the contents of an array element are not used.
+///
+/// An element is unused at a timepoint when the element is overwritten in
+/// the future, but it is not read in between. Another way to express this: the
+/// time from when the element is written, to the most recent read before it, or
+/// infinitely into the past if there is no read before. Such unused elements
+/// can be overwritten by any value without changing the scop's semantics. An
+/// example:
+///
+/// Schedule := { Read[] -> [0]; Write[] -> [10]; Def[] -> [20] }
+/// Writes := { Write[] -> A[5]; Def[] -> A[6] }
+/// Reads := { Read[] -> A[5] }
+///
+/// The result is:
+///
+/// { A[5] -> [i] : 0 < i < 10;
+///   A[6] -> [i] : i < 20 }
+///
+/// That is, A[5] is unused between timepoint 0 (the read) and timepoint 10 (the
+/// write). A[6] is unused before timepoint 20, but might be used after the
+/// scop's execution (A[5] and any other A[i] as well). Use InclLastRead=false
+/// and InclWrite=true to interpret the result as zone.
+///
+/// @param Schedule          { Domain[] -> Scatter[] }
+///                          The schedule of (at least) all statement instances
+///                          occurring in @p Writes or @p Reads. All other
+///                          instances are ignored.
+/// @param Writes            { DomainWrite[] -> Element[] }
+///                          Elements written to by the statement instances.
+/// @param Reads             { DomainRead[] -> Element[] }
+///                          Elements read from by the statement instances.
+/// @param ReadEltInSameInst Whether a load reads the value from a write
+///                          that is scheduled at the same timepoint (Writes
+///                          happen before reads). Otherwise, loads use the
+///                          value of an element that it had before the
+///                          timepoint (Reads before writes). For example:
+///                          { Read[] -> [0]; Write[] -> [0] }
+///                          With ReadEltInSameInst=false it is assumed that the
+///                          read happens before the write, such that the
+///                          element is never unused, or just at timepoint 0,
+///                          depending on InclLastRead/InclWrite.
+///                          With ReadEltInSameInst=false it assumes that the
+///                          value just written is used. Anything before
+///                          timepoint 0 is considered unused.
+/// @param InclLastRead      Whether a timepoint where an element is last read
+///                          counts as unused (the read happens at the beginning
+///                          of its timepoint, and nothing (else) can use it
+///                          during the timepoint). In the example, this option
+///                          adds { A[5] -> [0] } to the result.
+/// @param InclWrite         Whether the timepoint where an element is written
+///                          itself counts as unused (the write happens at the
+///                          end of its timepoint; no (other) operations uses
+///                          the element during the timepoint). In this example,
+///                          this adds
+///                          { A[5] -> [10]; A[6] -> [20] } to the result.
+///
+/// @return { Element[] -> Scatter[] }
+///         The unused timepoints as defined above, or nullptr if either @p
+///         Schedule, @p Writes are @p Reads is nullptr, or the ISL max
+///         operations count is exceeded.
+isl::union_map computeArrayUnused(isl::union_map Schedule,
+                                  isl::union_map Writes, isl::union_map Reads,
+                                  bool ReadEltInSameInst, bool InclLastRead,
+                                  bool InclWrite);
+
+/// Convert a zone (range between timepoints) to timepoints.
+///
+/// A zone represents the time between (integer) timepoints, but not the
+/// timepoints themselves. This function can be used to determine whether a
+/// timepoint lies within a zone.
+///
+/// For instance, the range (1,3), representing the time between 1 and 3, is
+/// represented by the zone
+///
+/// { [i] : 1 < i <= 3 }
+///
+/// The set of timepoints that lie completely within this range is
+///
+/// { [i] : 1 < i < 3 }
+///
+/// A typical use-case is the range in which a value written by a store is
+/// available until it is overwritten by another value. If the write is at
+/// timepoint 1 and its value is overwritten by another value at timepoint 3,
+/// the value is available between those timepoints: timepoint 2 in this
+/// example.
+///
+///
+/// When InclStart is true, the range is interpreted left-inclusive, i.e. adds
+/// the timepoint 1 to the result:
+///
+/// { [i] : 1 <= i < 3 }
+///
+/// In the use-case mentioned above that means that the value written at
+/// timepoint 1 is already available in timepoint 1 (write takes place before
+/// any read of it even if executed at the same timepoint)
+///
+/// When InclEnd is true, the range is interpreted right-inclusive, i.e. adds
+/// the timepoint 3 to the result:
+///
+/// { [i] : 1 < i <= 3 }
+///
+/// In the use-case mentioned above that means that although the value is
+/// overwritten in timepoint 3, the old value is still available at timepoint 3
+/// (write takes place after any read even if executed at the same timepoint)
+///
+/// @param Zone      { Zone[] }
+/// @param InclStart Include timepoints adjacent to the beginning of a zone.
+/// @param InclEnd   Include timepoints adjacent to the ending of a zone.
+///
+/// @return { Scatter[] }
+isl::union_set convertZoneToTimepoints(isl::union_set Zone, bool InclStart,
+                                       bool InclEnd);
+
+/// Like convertZoneToTimepoints(isl::union_set,InclStart,InclEnd), but convert
+/// either the domain or the range of a map.
+isl::union_map convertZoneToTimepoints(isl::union_map Zone, isl::dim Dim,
+                                       bool InclStart, bool InclEnd);
+
+/// Overload of convertZoneToTimepoints(isl::map,InclStart,InclEnd) to process
+/// only a single map.
+isl::map convertZoneToTimepoints(isl::map Zone, isl::dim Dim, bool InclStart,
+                                 bool InclEnd);
+
+/// Distribute the domain to the tuples of a wrapped range map.
+///
+/// @param Map { Domain[] -> [Range1[] -> Range2[]] }
+///
+/// @return { [Domain[] -> Range1[]] -> [Domain[] -> Range2[]] }
+isl::map distributeDomain(isl::map Map);
+
+/// Apply distributeDomain(isl::map) to each map in the union.
+isl::union_map distributeDomain(isl::union_map UMap);
+
+/// Prepend a space to the tuples of a map.
+///
+/// @param UMap   { Domain[] -> Range[] }
+/// @param Factor { Factor[] }
+///
+/// @return { [Factor[] -> Domain[]] -> [Factor[] -> Range[]] }
+isl::union_map liftDomains(isl::union_map UMap, isl::union_set Factor);
+
+/// Apply a map to the 'middle' of another relation.
+///
+/// @param UMap { [DomainDomain[] -> DomainRange[]] -> Range[] }
+/// @param Func { DomainRange[] -> NewDomainRange[] }
+///
+/// @return { [DomainDomain[] -> NewDomainRange[]] -> Range[] }
+isl::union_map applyDomainRange(isl::union_map UMap, isl::union_map Func);
+
+/// Intersect the range of @p Map with @p Range.
+///
+/// Since @p Map is an isl::map, the result will be a single space, even though
+/// @p Range is an isl::union_set. This is the only difference to
+/// isl::map::intersect_range and isl::union_map::interset_range.
+///
+/// @param Map   { Domain[] -> Range[] }
+/// @param Range { Range[] }
+///
+/// @return { Domain[] -> Range[] }
+isl::map intersectRange(isl::map Map, isl::union_set Range);
+
+/// If @p PwAff maps to a constant, return said constant. If @p Max/@p Min, it
+/// can also be a piecewise constant and it would return the minimum/maximum
+/// value. Otherwise, return NaN.
+isl::val getConstant(isl::pw_aff PwAff, bool Max, bool Min);
+
+/// Dump a description of the argument to llvm::errs().
+///
+/// In contrast to isl's dump function, there are a few differences:
+/// - Each polyhedron (pieces) is written on its own line.
+/// - Spaces are sorted by structure. E.g. maps with same domain space are
+///   grouped. Isl sorts them according to the space's hash function.
+/// - Pieces of the same space are sorted using their lower bound.
+/// - A more compact to_str representation is used instead of Isl's dump
+///   functions that try to show the internal representation.
+///
+/// The goal is to get a better understandable representation that is also
+/// useful to compare two sets. As all dump() functions, its intended use is to
+/// be called in a debugger only.
+///
+/// isl_map_dump example:
+/// [p_0, p_1, p_2] -> { Stmt0[i0] -> [o0, o1] : (o0 = i0 and o1 = 0 and i0 > 0
+/// and i0 <= 5 - p_2) or (i0 = 0 and o0 = 0 and o1 = 0); Stmt3[i0] -> [o0, o1]
+/// : (o0 = i0 and o1 = 3 and i0 > 0 and i0 <= 5 - p_2) or (i0 = 0 and o0 = 0
+/// and o1 = 3); Stmt2[i0] -> [o0, o1] : (o0 = i0 and o1 = 1 and i0 >= 3 + p_0 -
+/// p_1 and i0 > 0 and i0 <= 5 - p_2) or (o0 = i0 and o1 = 1 and i0 > 0 and i0
+/// <= 5 - p_2 and i0 < p_0 - p_1) or (i0 = 0 and o0 = 0 and o1 = 1 and p_1 >= 3
+/// + p_0) or (i0 = 0 and o0 = 0 and o1 = 1 and p_1 < p_0) or (p_0 = 0 and i0 =
+/// 2 - p_1 and o0 = 2 - p_1 and o1 = 1 and p_2 <= 3 + p_1 and p_1 <= 1) or (p_1
+/// = 1 + p_0 and i0 = 0 and o0 = 0 and o1 = 1) or (p_0 = 0 and p_1 = 2 and i0 =
+/// 0 and o0 = 0 and o1 = 1) or (p_0 = -1 and p_1 = -1 and i0 = 0 and o0 = 0 and
+/// o1 = 1); Stmt1[i0] -> [o0, o1] : (p_0 = -1 and i0 = 1 - p_1 and o0 = 1 - p_1
+/// and o1 = 2 and p_2 <= 4 + p_1 and p_1 <= 0) or (p_0 = 0 and i0 = -p_1 and o0
+/// = -p_1 and o1 = 2 and p_2 <= 5 + p_1 and p_1 < 0) or (p_0 = -1 and p_1 = 1
+/// and i0 = 0 and o0 = 0 and o1 = 2) or (p_0 = 0 and p_1 = 0 and i0 = 0 and o0
+/// = 0 and o1 = 2) }
+///
+/// dumpPw example (same set):
+/// [p_0, p_1, p_2] -> {
+///   Stmt0[0] -> [0, 0];
+///   Stmt0[i0] -> [i0, 0] : 0 < i0 <= 5 - p_2;
+///   Stmt1[0] -> [0, 2] : p_1 = 1 and p_0 = -1;
+///   Stmt1[0] -> [0, 2] : p_1 = 0 and p_0 = 0;
+///   Stmt1[1 - p_1] -> [1 - p_1, 2] : p_0 = -1 and p_1 <= 0 and p_2 <= 4 + p_1;
+///   Stmt1[-p_1] -> [-p_1, 2] : p_0 = 0 and p_1 < 0 and p_2 <= 5 + p_1;
+///   Stmt2[0] -> [0, 1] : p_1 >= 3 + p_0;
+///   Stmt2[0] -> [0, 1] : p_1 < p_0;
+///   Stmt2[0] -> [0, 1] : p_1 = 1 + p_0;
+///   Stmt2[0] -> [0, 1] : p_1 = 2 and p_0 = 0;
+///   Stmt2[0] -> [0, 1] : p_1 = -1 and p_0 = -1;
+///   Stmt2[i0] -> [i0, 1] : i0 >= 3 + p_0 - p_1 and 0 < i0 <= 5 - p_2;
+///   Stmt2[i0] -> [i0, 1] : 0 < i0 <= 5 - p_2 and i0 < p_0 - p_1;
+///   Stmt2[2 - p_1] -> [2 - p_1, 1] : p_0 = 0 and p_1 <= 1 and p_2 <= 3 + p_1;
+///   Stmt3[0] -> [0, 3];
+///   Stmt3[i0] -> [i0, 3] : 0 < i0 <= 5 - p_2
+/// }
+/// @{
+void dumpPw(const isl::set &Set);
+void dumpPw(const isl::map &Map);
+void dumpPw(const isl::union_set &USet);
+void dumpPw(const isl::union_map &UMap);
+void dumpPw(__isl_keep isl_set *Set);
+void dumpPw(__isl_keep isl_map *Map);
+void dumpPw(__isl_keep isl_union_set *USet);
+void dumpPw(__isl_keep isl_union_map *UMap);
+/// @}
+
+/// Dump all points of the argument to llvm::errs().
+///
+/// Before being printed by dumpPw(), the argument's pieces are expanded to
+/// contain only single points. If a dimension is unbounded, it keeps its
+/// representation.
+///
+/// This is useful for debugging reduced cases where parameters are set to
+/// constants to keep the example simple. Such sets can still contain
+/// existential dimensions which makes the polyhedral hard to compare.
+///
+/// Example:
+///   { [MemRef_A[i0] -> [i1]] : (exists (e0 = floor((1 + i1)/3): i0 = 1 and 3e0
+///   <= i1 and 3e0 >= -1 + i1 and i1 >= 15 and i1 <= 25)) or (exists (e0 =
+///   floor((i1)/3): i0 = 0 and 3e0 < i1 and 3e0 >= -2 + i1 and i1 > 0 and i1 <=
+///   11)) }
+///
+/// dumpExpanded:
+/// {
+///   [MemRef_A[0] ->[1]];
+///   [MemRef_A[0] ->[2]];
+///   [MemRef_A[0] ->[4]];
+///   [MemRef_A[0] ->[5]];
+///   [MemRef_A[0] ->[7]];
+///   [MemRef_A[0] ->[8]];
+///   [MemRef_A[0] ->[10]];
+///   [MemRef_A[0] ->[11]];
+///   [MemRef_A[1] ->[15]];
+///   [MemRef_A[1] ->[16]];
+///   [MemRef_A[1] ->[18]];
+///   [MemRef_A[1] ->[19]];
+///   [MemRef_A[1] ->[21]];
+///   [MemRef_A[1] ->[22]];
+///   [MemRef_A[1] ->[24]];
+///   [MemRef_A[1] ->[25]]
+/// }
+/// @{
+void dumpExpanded(const isl::set &Set);
+void dumpExpanded(const isl::map &Map);
+void dumpExpanded(const isl::union_set &USet);
+void dumpExpanded(const isl::union_map &UMap);
+void dumpExpanded(__isl_keep isl_set *Set);
+void dumpExpanded(__isl_keep isl_map *Map);
+void dumpExpanded(__isl_keep isl_union_set *USet);
+void dumpExpanded(__isl_keep isl_union_map *UMap);
+/// @}
+
+} // namespace polly
+
+#endif /* POLLY_ISLTOOLS_H */
diff --git a/final/include/polly/Support/LinkGPURuntime.h b/final/include/polly/Support/LinkGPURuntime.h
new file mode 100644
index 0000000..85a6189
--- /dev/null
+++ b/final/include/polly/Support/LinkGPURuntime.h
@@ -0,0 +1,43 @@
+//===- Support/LinkGPURuntime.h -- Headerfile to help force-link GPURuntime  =//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header helps pull in libGPURuntime.so
+//
+//===----------------------------------------------------------------------===//
+#ifndef POLLY_LINK_GPURUNTIME
+#define POLLY_LINK_GPURUNTIME
+
+extern "C" {
+#include "GPURuntime/GPUJIT.h"
+}
+
+namespace polly {
+struct ForceGPURuntimeLinking {
+  ForceGPURuntimeLinking() {
+    if (std::getenv("bar") != (char *)-1)
+      return;
+    // We must reference GPURuntime in such a way that compilers will not
+    // delete it all as dead code, even with whole program optimization,
+    // yet is effectively a NO-OP. As the compiler isn't smart enough
+    // to know that getenv() never returns -1, this will do the job.
+    polly_initContextCL();
+    polly_initContextCUDA();
+    polly_getKernel(nullptr, nullptr);
+    polly_freeKernel(nullptr);
+    polly_copyFromHostToDevice(nullptr, nullptr, 0);
+    polly_copyFromDeviceToHost(nullptr, nullptr, 0);
+    polly_synchronizeDevice();
+    polly_launchKernel(nullptr, 0, 0, 0, 0, 0, nullptr);
+    polly_freeDeviceMemory(nullptr);
+    polly_freeContext(nullptr);
+    polly_synchronizeDevice();
+  }
+} structure;
+} // namespace polly
+#endif
diff --git a/final/include/polly/Support/SCEVAffinator.h b/final/include/polly/Support/SCEVAffinator.h
new file mode 100644
index 0000000..e4fb715
--- /dev/null
+++ b/final/include/polly/Support/SCEVAffinator.h
@@ -0,0 +1,126 @@
+//===------ polly/SCEVAffinator.h - Create isl expressions from SCEVs -----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Create a polyhedral description for a SCEV value.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_SCEV_AFFINATOR_H
+#define POLLY_SCEV_AFFINATOR_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+
+#include "isl/isl-noexceptions.h"
+
+namespace llvm {
+class Region;
+class BasicBlock;
+class DataLayout;
+class ScalarEvolution;
+} // namespace llvm
+
+namespace polly {
+class Scop;
+class ScopStmt;
+
+/// The result type of the SCEVAffinator.
+///
+/// The first element of the pair is the isl representation of the SCEV, the
+/// second is the domain under which it is __invalid__.
+typedef std::pair<isl::pw_aff, isl::set> PWACtx;
+
+/// Translate a SCEV to an isl::pw_aff and the domain on which it is invalid.
+struct SCEVAffinator : public llvm::SCEVVisitor<SCEVAffinator, PWACtx> {
+public:
+  SCEVAffinator(Scop *S, llvm::LoopInfo &LI);
+
+  /// Translate a SCEV to an isl::pw_aff.
+  ///
+  /// @param E  he expression that is translated.
+  /// @param BB The block in which @p E is executed.
+  ///
+  /// @returns The isl representation of the SCEV @p E in @p Domain.
+  PWACtx getPwAff(const llvm::SCEV *E, llvm::BasicBlock *BB = nullptr);
+
+  /// Take the assumption that @p PWAC is non-negative.
+  void takeNonNegativeAssumption(PWACtx &PWAC);
+
+  /// Interpret the PWA in @p PWAC as an unsigned value.
+  void interpretAsUnsigned(PWACtx &PWAC, unsigned Width);
+
+  /// Check an <nsw> AddRec for the loop @p L is cached.
+  bool hasNSWAddRecForLoop(llvm::Loop *L) const;
+
+  /// Return the LoopInfo used by thi object.
+  llvm::LoopInfo *getLI() const { return &LI; }
+
+private:
+  /// Key to identify cached expressions.
+  using CacheKey = std::pair<const llvm::SCEV *, llvm::BasicBlock *>;
+
+  /// Map to remembered cached expressions.
+  llvm::DenseMap<CacheKey, PWACtx> CachedExpressions;
+
+  Scop *S;
+  isl::ctx Ctx;
+  unsigned NumIterators;
+  llvm::ScalarEvolution &SE;
+  llvm::LoopInfo &LI;
+  llvm::BasicBlock *BB;
+
+  /// Target data for element size computing.
+  const llvm::DataLayout &TD;
+
+  /// Return the loop for the current block if any.
+  llvm::Loop *getScope();
+
+  /// Return a PWACtx for @p PWA that is always valid.
+  PWACtx getPWACtxFromPWA(isl::pw_aff PWA);
+
+  /// Compute the non-wrapping version of @p PWA for type @p ExprType.
+  ///
+  /// @param PWA  The piece-wise affine function that might wrap.
+  /// @param Type The type of the SCEV that was translated to @p PWA.
+  ///
+  /// @returns The expr @p PWA modulo the size constraints of @p ExprType.
+  isl::pw_aff addModuloSemantic(isl::pw_aff PWA, llvm::Type *ExprType) const;
+
+  /// If @p Expr might cause an integer wrap record an assumption.
+  ///
+  /// @param Expr The SCEV expression that might wrap.
+  /// @param PWAC The isl representation of @p Expr with the invalid domain.
+  ///
+  /// @returns The isl representation @p PWAC with a possibly adjusted domain.
+  PWACtx checkForWrapping(const llvm::SCEV *Expr, PWACtx PWAC) const;
+
+  /// Whether to track the value of this expression precisely, rather than
+  /// assuming it won't wrap.
+  bool computeModuloForExpr(const llvm::SCEV *Expr);
+
+  PWACtx visit(const llvm::SCEV *E);
+  PWACtx visitConstant(const llvm::SCEVConstant *E);
+  PWACtx visitTruncateExpr(const llvm::SCEVTruncateExpr *E);
+  PWACtx visitZeroExtendExpr(const llvm::SCEVZeroExtendExpr *E);
+  PWACtx visitSignExtendExpr(const llvm::SCEVSignExtendExpr *E);
+  PWACtx visitAddExpr(const llvm::SCEVAddExpr *E);
+  PWACtx visitMulExpr(const llvm::SCEVMulExpr *E);
+  PWACtx visitUDivExpr(const llvm::SCEVUDivExpr *E);
+  PWACtx visitAddRecExpr(const llvm::SCEVAddRecExpr *E);
+  PWACtx visitSMaxExpr(const llvm::SCEVSMaxExpr *E);
+  PWACtx visitUMaxExpr(const llvm::SCEVUMaxExpr *E);
+  PWACtx visitUnknown(const llvm::SCEVUnknown *E);
+  PWACtx visitSDivInstruction(llvm::Instruction *SDiv);
+  PWACtx visitSRemInstruction(llvm::Instruction *SRem);
+
+  friend struct llvm::SCEVVisitor<SCEVAffinator, PWACtx>;
+};
+} // namespace polly
+
+#endif
diff --git a/final/include/polly/Support/SCEVValidator.h b/final/include/polly/Support/SCEVValidator.h
new file mode 100644
index 0000000..c8a6293
--- /dev/null
+++ b/final/include/polly/Support/SCEVValidator.h
@@ -0,0 +1,119 @@
+//===--- SCEVValidator.h - Detect Scops -------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Checks if a SCEV expression represents a valid affine expression.
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_SCEV_VALIDATOR_H
+#define POLLY_SCEV_VALIDATOR_H
+
+#include "polly/Support/ScopHelper.h"
+#include "llvm/ADT/SetVector.h"
+
+namespace llvm {
+class Region;
+class SCEV;
+class SCEVConstant;
+class ScalarEvolution;
+class Value;
+class Loop;
+class LoadInst;
+class CallInst;
+} // namespace llvm
+
+namespace polly {
+
+/// Check if a call is side-effect free and has only constant arguments.
+///
+/// Such calls can be re-generated easily, so we do not need to model them
+/// as scalar dependences.
+///
+/// @param Call The call to check.
+bool isConstCall(llvm::CallInst *Call);
+
+/// Check if some parameters in the affine expression might hide induction
+/// variables. If this is the case, we will try to delinearize the accesses
+/// taking into account this information to possibly obtain a memory access
+/// with more structure. Currently we assume that each parameter that
+/// comes from a function call might depend on a (virtual) induction variable.
+/// This covers calls to 'get_global_id' and 'get_local_id' as they commonly
+/// arise in OpenCL code, while not catching any false-positives in our current
+/// tests.
+bool hasIVParams(const llvm::SCEV *Expr);
+
+/// Find the loops referenced from a SCEV expression.
+///
+/// @param Expr The SCEV expression to scan for loops.
+/// @param Loops A vector into which the found loops are inserted.
+void findLoops(const llvm::SCEV *Expr,
+               llvm::SetVector<const llvm::Loop *> &Loops);
+
+/// Find the values referenced by SCEVUnknowns in a given SCEV
+/// expression.
+///
+/// @param Expr   The SCEV expression to scan for SCEVUnknowns.
+/// @param SE     The ScalarEvolution analysis for this function.
+/// @param Values A vector into which the found values are inserted.
+void findValues(const llvm::SCEV *Expr, llvm::ScalarEvolution &SE,
+                llvm::SetVector<llvm::Value *> &Values);
+
+/// Returns true when the SCEV contains references to instructions within the
+/// region.
+///
+/// @param Expr The SCEV to analyze.
+/// @param R The region in which we look for dependences.
+/// @param Scope Location where the value is needed.
+/// @param AllowLoops Whether loop recurrences outside the loop that are in the
+///                   region count as dependence.
+bool hasScalarDepsInsideRegion(const llvm::SCEV *Expr, const llvm::Region *R,
+                               llvm::Loop *Scope, bool AllowLoops,
+                               const InvariantLoadsSetTy &ILS);
+bool isAffineExpr(const llvm::Region *R, llvm::Loop *Scope,
+                  const llvm::SCEV *Expression, llvm::ScalarEvolution &SE,
+                  InvariantLoadsSetTy *ILS = nullptr);
+
+/// Check if @p V describes an affine constraint in @p R.
+bool isAffineConstraint(llvm::Value *V, const llvm::Region *R,
+                        llvm::Loop *Scope, llvm::ScalarEvolution &SE,
+                        ParameterSetTy &Params, bool OrExpr = false);
+
+ParameterSetTy getParamsInAffineExpr(const llvm::Region *R, llvm::Loop *Scope,
+                                     const llvm::SCEV *Expression,
+                                     llvm::ScalarEvolution &SE);
+
+/// Extract the constant factors from the multiplication @p M.
+///
+/// @param M  A potential SCEV multiplication.
+/// @param SE The ScalarEvolution analysis to create new SCEVs.
+///
+/// @returns The constant factor in @p M and the rest of @p M.
+std::pair<const llvm::SCEVConstant *, const llvm::SCEV *>
+extractConstantFactor(const llvm::SCEV *M, llvm::ScalarEvolution &SE);
+
+/// Try to look through PHI nodes, where some incoming edges come from error
+/// blocks.
+///
+/// In case a PHI node follows an error block we can assume that the incoming
+/// value can only come from the node that is not an error block. As a result,
+/// conditions that seemed non-affine before are now in fact affine.
+const llvm::SCEV *tryForwardThroughPHI(const llvm::SCEV *Expr, llvm::Region &R,
+                                       llvm::ScalarEvolution &SE,
+                                       llvm::LoopInfo &LI,
+                                       const llvm::DominatorTree &DT);
+
+/// Return a unique non-error block incoming value for @p PHI if available.
+///
+/// @param R The region to run our code on.
+/// @param LI The loopinfo tree
+/// @param DT The dominator tree
+llvm::Value *getUniqueNonErrorValue(llvm::PHINode *PHI, llvm::Region *R,
+                                    llvm::LoopInfo &LI,
+                                    const llvm::DominatorTree &DT);
+} // namespace polly
+
+#endif
diff --git a/final/include/polly/Support/ScopHelper.h b/final/include/polly/Support/ScopHelper.h
new file mode 100644
index 0000000..ccbdbf6
--- /dev/null
+++ b/final/include/polly/Support/ScopHelper.h
@@ -0,0 +1,459 @@
+//===------ Support/ScopHelper.h -- Some Helper Functions for Scop. -------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Small functions that help with LLVM-IR.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_SUPPORT_IRHELPER_H
+#define POLLY_SUPPORT_IRHELPER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/ValueHandle.h"
+#include <tuple>
+#include <vector>
+
+namespace llvm {
+class LoopInfo;
+class Loop;
+class ScalarEvolution;
+class SCEV;
+class Region;
+class Pass;
+class DominatorTree;
+class RegionInfo;
+class GetElementPtrInst;
+} // namespace llvm
+
+namespace polly {
+class Scop;
+
+/// Type to remap values.
+using ValueMapT = llvm::DenseMap<llvm::AssertingVH<llvm::Value>,
+                                 llvm::AssertingVH<llvm::Value>>;
+
+/// Type for a set of invariant loads.
+using InvariantLoadsSetTy = llvm::SetVector<llvm::AssertingVH<llvm::LoadInst>>;
+
+/// Set type for parameters.
+using ParameterSetTy = llvm::SetVector<const llvm::SCEV *>;
+
+/// Set of loops (used to remember loops in non-affine subregions).
+using BoxedLoopsSetTy = llvm::SetVector<const llvm::Loop *>;
+
+/// Utility proxy to wrap the common members of LoadInst and StoreInst.
+///
+/// This works like the LLVM utility class CallSite, ie. it forwards all calls
+/// to either a LoadInst, StoreInst, MemIntrinsic or MemTransferInst.
+/// It is similar to LLVM's utility classes IntrinsicInst, MemIntrinsic,
+/// MemTransferInst, etc. in that it offers a common interface, but does not act
+/// as a fake base class.
+/// It is similar to StringRef and ArrayRef in that it holds a pointer to the
+/// referenced object and should be passed by-value as it is small enough.
+///
+/// This proxy can either represent a LoadInst instance, a StoreInst instance,
+/// a MemIntrinsic instance (memset, memmove, memcpy), a CallInst instance or a
+/// nullptr (only creatable using the default constructor); never an Instruction
+/// that is neither of the above mentioned. When representing a nullptr, only
+/// the following methods are defined:
+/// isNull(), isInstruction(), isLoad(), isStore(), ..., isMemTransferInst(),
+/// operator bool(), operator!()
+///
+/// The functions isa, cast, cast_or_null, dyn_cast are modeled te resemble
+/// those from llvm/Support/Casting.h. Partial template function specialization
+/// is currently not supported in C++ such that those cannot be used directly.
+/// (llvm::isa could, but then llvm:cast etc. would not have the expected
+/// behavior)
+class MemAccInst {
+private:
+  llvm::Instruction *I;
+
+public:
+  MemAccInst() : I(nullptr) {}
+  MemAccInst(const MemAccInst &Inst) : I(Inst.I) {}
+  /* implicit */ MemAccInst(llvm::LoadInst &LI) : I(&LI) {}
+  /* implicit */ MemAccInst(llvm::LoadInst *LI) : I(LI) {}
+  /* implicit */ MemAccInst(llvm::StoreInst &SI) : I(&SI) {}
+  /* implicit */ MemAccInst(llvm::StoreInst *SI) : I(SI) {}
+  /* implicit */ MemAccInst(llvm::MemIntrinsic *MI) : I(MI) {}
+  /* implicit */ MemAccInst(llvm::CallInst *CI) : I(CI) {}
+  explicit MemAccInst(llvm::Instruction &I) : I(&I) { assert(isa(I)); }
+  explicit MemAccInst(llvm::Instruction *I) : I(I) { assert(isa(I)); }
+
+  static bool isa(const llvm::Value &V) {
+    return llvm::isa<llvm::LoadInst>(V) || llvm::isa<llvm::StoreInst>(V) ||
+           llvm::isa<llvm::CallInst>(V) || llvm::isa<llvm::MemIntrinsic>(V);
+  }
+  static bool isa(const llvm::Value *V) {
+    return llvm::isa<llvm::LoadInst>(V) || llvm::isa<llvm::StoreInst>(V) ||
+           llvm::isa<llvm::CallInst>(V) || llvm::isa<llvm::MemIntrinsic>(V);
+  }
+  static MemAccInst cast(llvm::Value &V) {
+    return MemAccInst(llvm::cast<llvm::Instruction>(V));
+  }
+  static MemAccInst cast(llvm::Value *V) {
+    return MemAccInst(llvm::cast<llvm::Instruction>(V));
+  }
+  static MemAccInst cast_or_null(llvm::Value &V) {
+    return MemAccInst(llvm::cast<llvm::Instruction>(V));
+  }
+  static MemAccInst cast_or_null(llvm::Value *V) {
+    if (!V)
+      return MemAccInst();
+    return MemAccInst(llvm::cast<llvm::Instruction>(V));
+  }
+  static MemAccInst dyn_cast(llvm::Value &V) {
+    if (isa(V))
+      return MemAccInst(llvm::cast<llvm::Instruction>(V));
+    return MemAccInst();
+  }
+  static MemAccInst dyn_cast(llvm::Value *V) {
+    assert(V);
+    if (isa(V))
+      return MemAccInst(llvm::cast<llvm::Instruction>(V));
+    return MemAccInst();
+  }
+
+  MemAccInst &operator=(const MemAccInst &Inst) {
+    I = Inst.I;
+    return *this;
+  }
+  MemAccInst &operator=(llvm::LoadInst &LI) {
+    I = &LI;
+    return *this;
+  }
+  MemAccInst &operator=(llvm::LoadInst *LI) {
+    I = LI;
+    return *this;
+  }
+  MemAccInst &operator=(llvm::StoreInst &SI) {
+    I = &SI;
+    return *this;
+  }
+  MemAccInst &operator=(llvm::StoreInst *SI) {
+    I = SI;
+    return *this;
+  }
+  MemAccInst &operator=(llvm::MemIntrinsic &MI) {
+    I = &MI;
+    return *this;
+  }
+  MemAccInst &operator=(llvm::MemIntrinsic *MI) {
+    I = MI;
+    return *this;
+  }
+  MemAccInst &operator=(llvm::CallInst &CI) {
+    I = &CI;
+    return *this;
+  }
+  MemAccInst &operator=(llvm::CallInst *CI) {
+    I = CI;
+    return *this;
+  }
+
+  llvm::Instruction *get() const {
+    assert(I && "Unexpected nullptr!");
+    return I;
+  }
+  operator llvm::Instruction *() const { return asInstruction(); }
+  llvm::Instruction *operator->() const { return get(); }
+
+  explicit operator bool() const { return isInstruction(); }
+  bool operator!() const { return isNull(); }
+
+  llvm::Value *getValueOperand() const {
+    if (isLoad())
+      return asLoad();
+    if (isStore())
+      return asStore()->getValueOperand();
+    if (isMemIntrinsic())
+      return nullptr;
+    if (isCallInst())
+      return nullptr;
+    llvm_unreachable("Operation not supported on nullptr");
+  }
+  llvm::Value *getPointerOperand() const {
+    if (isLoad())
+      return asLoad()->getPointerOperand();
+    if (isStore())
+      return asStore()->getPointerOperand();
+    if (isMemIntrinsic())
+      return asMemIntrinsic()->getRawDest();
+    if (isCallInst())
+      return nullptr;
+    llvm_unreachable("Operation not supported on nullptr");
+  }
+
+  unsigned getAlignment() const {
+    if (isLoad())
+      return asLoad()->getAlignment();
+    if (isStore())
+      return asStore()->getAlignment();
+    if (isMemIntrinsic())
+      return asMemIntrinsic()->getAlignment();
+    if (isCallInst())
+      return 0;
+    llvm_unreachable("Operation not supported on nullptr");
+  }
+  bool isVolatile() const {
+    if (isLoad())
+      return asLoad()->isVolatile();
+    if (isStore())
+      return asStore()->isVolatile();
+    if (isMemIntrinsic())
+      return asMemIntrinsic()->isVolatile();
+    if (isCallInst())
+      return false;
+    llvm_unreachable("Operation not supported on nullptr");
+  }
+  bool isSimple() const {
+    if (isLoad())
+      return asLoad()->isSimple();
+    if (isStore())
+      return asStore()->isSimple();
+    if (isMemIntrinsic())
+      return !asMemIntrinsic()->isVolatile();
+    if (isCallInst())
+      return true;
+    llvm_unreachable("Operation not supported on nullptr");
+  }
+  llvm::AtomicOrdering getOrdering() const {
+    if (isLoad())
+      return asLoad()->getOrdering();
+    if (isStore())
+      return asStore()->getOrdering();
+    if (isMemIntrinsic())
+      return llvm::AtomicOrdering::NotAtomic;
+    if (isCallInst())
+      return llvm::AtomicOrdering::NotAtomic;
+    llvm_unreachable("Operation not supported on nullptr");
+  }
+  bool isUnordered() const {
+    if (isLoad())
+      return asLoad()->isUnordered();
+    if (isStore())
+      return asStore()->isUnordered();
+    // Copied from the Load/Store implementation of isUnordered:
+    if (isMemIntrinsic())
+      return !asMemIntrinsic()->isVolatile();
+    if (isCallInst())
+      return true;
+    llvm_unreachable("Operation not supported on nullptr");
+  }
+
+  bool isNull() const { return !I; }
+  bool isInstruction() const { return I; }
+
+  llvm::Instruction *asInstruction() const { return I; }
+
+private:
+  bool isLoad() const { return I && llvm::isa<llvm::LoadInst>(I); }
+  bool isStore() const { return I && llvm::isa<llvm::StoreInst>(I); }
+  bool isCallInst() const { return I && llvm::isa<llvm::CallInst>(I); }
+  bool isMemIntrinsic() const { return I && llvm::isa<llvm::MemIntrinsic>(I); }
+  bool isMemSetInst() const { return I && llvm::isa<llvm::MemSetInst>(I); }
+  bool isMemTransferInst() const {
+    return I && llvm::isa<llvm::MemTransferInst>(I);
+  }
+
+  llvm::LoadInst *asLoad() const { return llvm::cast<llvm::LoadInst>(I); }
+  llvm::StoreInst *asStore() const { return llvm::cast<llvm::StoreInst>(I); }
+  llvm::CallInst *asCallInst() const { return llvm::cast<llvm::CallInst>(I); }
+  llvm::MemIntrinsic *asMemIntrinsic() const {
+    return llvm::cast<llvm::MemIntrinsic>(I);
+  }
+  llvm::MemSetInst *asMemSetInst() const {
+    return llvm::cast<llvm::MemSetInst>(I);
+  }
+  llvm::MemTransferInst *asMemTransferInst() const {
+    return llvm::cast<llvm::MemTransferInst>(I);
+  }
+};
+} // namespace polly
+
+namespace llvm {
+/// Specialize simplify_type for MemAccInst to enable dyn_cast and cast
+///        from a MemAccInst object.
+template <> struct simplify_type<polly::MemAccInst> {
+  typedef Instruction *SimpleType;
+  static SimpleType getSimplifiedValue(polly::MemAccInst &I) {
+    return I.asInstruction();
+  }
+};
+} // namespace llvm
+
+namespace polly {
+
+/// Simplify the region to have a single unconditional entry edge and a
+/// single exit edge.
+///
+/// Although this function allows DT and RI to be null, regions only work
+/// properly if the DominatorTree (for Region::contains) and RegionInfo are kept
+/// up-to-date.
+///
+/// @param R  The region to be simplified
+/// @param DT DominatorTree to be updated.
+/// @param LI LoopInfo to be updated.
+/// @param RI RegionInfo to be updated.
+void simplifyRegion(llvm::Region *R, llvm::DominatorTree *DT,
+                    llvm::LoopInfo *LI, llvm::RegionInfo *RI);
+
+/// Split the entry block of a function to store the newly inserted
+///        allocations outside of all Scops.
+///
+/// @param EntryBlock The entry block of the current function.
+/// @param P          The pass that currently running.
+///
+void splitEntryBlockForAlloca(llvm::BasicBlock *EntryBlock, llvm::Pass *P);
+
+/// Split the entry block of a function to store the newly inserted
+///        allocations outside of all Scops.
+///
+/// @param DT DominatorTree to be updated.
+/// @param LI LoopInfo to be updated.
+/// @param RI RegionInfo to be updated.
+void splitEntryBlockForAlloca(llvm::BasicBlock *EntryBlock,
+                              llvm::DominatorTree *DT, llvm::LoopInfo *LI,
+                              llvm::RegionInfo *RI);
+
+/// Wrapper for SCEVExpander extended to all Polly features.
+///
+/// This wrapper will internally call the SCEVExpander but also makes sure that
+/// all additional features not represented in SCEV (e.g., SDiv/SRem are not
+/// black boxes but can be part of the function) will be expanded correctly.
+///
+/// The parameters are the same as for the creation of a SCEVExpander as well
+/// as the call to SCEVExpander::expandCodeFor:
+///
+/// @param S     The current Scop.
+/// @param SE    The Scalar Evolution pass.
+/// @param DL    The module data layout.
+/// @param Name  The suffix added to the new instruction names.
+/// @param E     The expression for which code is actually generated.
+/// @param Ty    The type of the resulting code.
+/// @param IP    The insertion point for the new code.
+/// @param VMap  A remapping of values used in @p E.
+/// @param RTCBB The last block of the RTC. Used to insert loop-invariant
+///              instructions in rare cases.
+llvm::Value *expandCodeFor(Scop &S, llvm::ScalarEvolution &SE,
+                           const llvm::DataLayout &DL, const char *Name,
+                           const llvm::SCEV *E, llvm::Type *Ty,
+                           llvm::Instruction *IP, ValueMapT *VMap,
+                           llvm::BasicBlock *RTCBB);
+
+/// Check if the block is a error block.
+///
+/// A error block is currently any block that fulfills at least one of
+/// the following conditions:
+///
+///  - It is terminated by an unreachable instruction
+///  - It contains a call to a non-pure function that is not immediately
+///    dominated by a loop header and that does not dominate the region exit.
+///    This is a heuristic to pick only error blocks that are conditionally
+///    executed and can be assumed to be not executed at all without the domains
+///    being available.
+///
+/// @param BB The block to check.
+/// @param R  The analyzed region.
+/// @param LI The loop info analysis.
+/// @param DT The dominator tree of the function.
+///
+/// @return True if the block is a error block, false otherwise.
+bool isErrorBlock(llvm::BasicBlock &BB, const llvm::Region &R,
+                  llvm::LoopInfo &LI, const llvm::DominatorTree &DT);
+
+/// Return the condition for the terminator @p TI.
+///
+/// For unconditional branches the "i1 true" condition will be returned.
+///
+/// @param TI The terminator to get the condition from.
+///
+/// @return The condition of @p TI and nullptr if none could be extracted.
+llvm::Value *getConditionFromTerminator(llvm::TerminatorInst *TI);
+
+/// Check if @p LInst can be hoisted in @p R.
+///
+/// @param LInst The load to check.
+/// @param R     The analyzed region.
+/// @param LI    The loop info.
+/// @param SE    The scalar evolution analysis.
+/// @param DT    The dominator tree of the function.
+///
+/// @return True if @p LInst can be hoisted in @p R.
+bool isHoistableLoad(llvm::LoadInst *LInst, llvm::Region &R, llvm::LoopInfo &LI,
+                     llvm::ScalarEvolution &SE, const llvm::DominatorTree &DT);
+
+/// Return true iff @p V is an intrinsic that we ignore during code
+///        generation.
+bool isIgnoredIntrinsic(const llvm::Value *V);
+
+/// Check whether a value an be synthesized by the code generator.
+///
+/// Some value will be recalculated only from information that is code generated
+/// from the polyhedral representation. For such instructions we do not need to
+/// ensure that their operands are available during code generation.
+///
+/// @param V The value to check.
+/// @param S The current SCoP.
+/// @param SE The scalar evolution database.
+/// @param Scope Location where the value would by synthesized.
+/// @return If the instruction I can be regenerated from its
+///         scalar evolution representation, return true,
+///         otherwise return false.
+bool canSynthesize(const llvm::Value *V, const Scop &S,
+                   llvm::ScalarEvolution *SE, llvm::Loop *Scope);
+
+/// Return the block in which a value is used.
+///
+/// For normal instructions, this is the instruction's parent block. For PHI
+/// nodes, this is the incoming block of that use, because this is where the
+/// operand must be defined (i.e. its definition dominates this block).
+/// Non-instructions do not use operands at a specific point such that in this
+/// case this function returns nullptr.
+llvm::BasicBlock *getUseBlock(const llvm::Use &U);
+
+/// Derive the individual index expressions from a GEP instruction.
+///
+/// This function optimistically assumes the GEP references into a fixed size
+/// array. If this is actually true, this function returns a list of array
+/// subscript expressions as SCEV as well as a list of integers describing
+/// the size of the individual array dimensions. Both lists have either equal
+/// length or the size list is one element shorter in case there is no known
+/// size available for the outermost array dimension.
+///
+/// @param GEP The GetElementPtr instruction to analyze.
+///
+/// @return A tuple with the subscript expressions and the dimension sizes.
+std::tuple<std::vector<const llvm::SCEV *>, std::vector<int>>
+getIndexExpressionsFromGEP(llvm::GetElementPtrInst *GEP,
+                           llvm::ScalarEvolution &SE);
+
+// If the loop is nonaffine/boxed, return the first non-boxed surrounding loop
+// for Polly. If the loop is affine, return the loop itself.
+//
+// @param L             Pointer to the Loop object to analyze.
+// @param LI            Reference to the LoopInfo.
+// @param BoxedLoops    Set of Boxed Loops we get from the SCoP.
+llvm::Loop *getFirstNonBoxedLoopFor(llvm::Loop *L, llvm::LoopInfo &LI,
+                                    const BoxedLoopsSetTy &BoxedLoops);
+
+// If the Basic Block belongs to a loop that is nonaffine/boxed, return the
+// first non-boxed surrounding loop for Polly. If the loop is affine, return
+// the loop itself.
+//
+// @param BB            Pointer to the Basic Block to analyze.
+// @param LI            Reference to the LoopInfo.
+// @param BoxedLoops    Set of Boxed Loops we get from the SCoP.
+llvm::Loop *getFirstNonBoxedLoopFor(llvm::BasicBlock *BB, llvm::LoopInfo &LI,
+                                    const BoxedLoopsSetTy &BoxedLoops);
+} // namespace polly
+#endif
diff --git a/final/include/polly/Support/ScopLocation.h b/final/include/polly/Support/ScopLocation.h
new file mode 100644
index 0000000..50d0011
--- /dev/null
+++ b/final/include/polly/Support/ScopLocation.h
@@ -0,0 +1,35 @@
+//=== ScopLocation.h -- Debug location helper for ScopDetection -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper function for extracting region debug information.
+//
+//===----------------------------------------------------------------------===//
+//
+#ifndef POLLY_SCOP_LOCATION_H
+#define POLLY_SCOP_LOCATION_H
+
+#include <string>
+
+namespace llvm {
+class Region;
+} // namespace llvm
+
+namespace polly {
+
+/// Get the location of a region from the debug info.
+///
+/// @param R The region to get debug info for.
+/// @param LineBegin The first line in the region.
+/// @param LineEnd The last line in the region.
+/// @param FileName The filename where the region was defined.
+void getDebugLocation(const llvm::Region *R, unsigned &LineBegin,
+                      unsigned &LineEnd, std::string &FileName);
+} // namespace polly
+
+#endif // POLLY_SCOP_LOCATION_H
diff --git a/final/include/polly/Support/VirtualInstruction.h b/final/include/polly/Support/VirtualInstruction.h
new file mode 100644
index 0000000..bf7ebe4
--- /dev/null
+++ b/final/include/polly/Support/VirtualInstruction.h
@@ -0,0 +1,343 @@
+//===------ VirtualInstruction.cpp ------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tools for determining which instructions are within a statement and the
+// nature of their operands.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_SUPPORT_VIRTUALINSTRUCTION_H
+#define POLLY_SUPPORT_VIRTUALINSTRUCTION_H
+
+#include "polly/ScopInfo.h"
+
+namespace polly {
+
+/// Determine the nature of a value's use within a statement.
+///
+/// These are not always representable by llvm::Use. For instance, scalar write
+/// MemoryAccesses do use a value, but are not associated with an instruction's
+/// argument.
+///
+/// Despite its name it is not tied to virtual instructions (although it works
+/// fine with them), but to promote consistent handling of values used in
+/// statements.
+class VirtualUse {
+public:
+  /// The different types of uses. Handling usually differentiates a lot between
+  /// these; one can use a switch to handle each case (and get warned by the
+  /// compiler if one is not handled).
+  enum UseKind {
+    // An llvm::Constant.
+    Constant,
+
+    // An llvm::BasicBlock.
+    Block,
+
+    // A value that can be generated using ScopExpander.
+    Synthesizable,
+
+    // A load that always reads the same value throughout the SCoP (address and
+    // the value located there a SCoP-invariant) and has been hoisted in front
+    // of the SCoP.
+    Hoisted,
+
+    // Definition before the SCoP and not synthesizable. Can be an instruction
+    // outside the SCoP, a function argument or a global value. Whether there is
+    // a scalar MemoryAccess in this statement for reading it depends on the
+    // -polly-analyze-read-only-scalars switch.
+    ReadOnly,
+
+    // A definition within the same statement. No MemoryAccess between
+    // definition and use are necessary.
+    Intra,
+
+    // Definition in another statement. There is a scalar MemoryAccess that
+    // makes it available in this statement.
+    Inter
+  };
+
+private:
+  /// The statement where a value is used.
+  ScopStmt *User;
+
+  /// The value that is used.
+  Value *Val;
+
+  /// The type of value use.
+  UseKind Kind;
+
+  /// The value represented as llvm::SCEV expression.
+  const SCEV *ScevExpr;
+
+  /// If this is an inter-statement (or read-only) use, contains the
+  /// MemoryAccess that makes the value available in this statement. In case of
+  /// intra-statement uses, can contain a MemoryKind::Array access. In all other
+  /// cases, it is a nullptr.
+  MemoryAccess *InputMA;
+
+  VirtualUse(ScopStmt *User, Value *Val, UseKind Kind, const SCEV *ScevExpr,
+             MemoryAccess *InputMA)
+      : User(User), Val(Val), Kind(Kind), ScevExpr(ScevExpr), InputMA(InputMA) {
+  }
+
+public:
+  /// Get a VirtualUse for an llvm::Use.
+  ///
+  /// @param S       The Scop object.
+  /// @param U       The llvm::Use the get information for.
+  /// @param LI      The LoopInfo analysis. Needed to determine whether the
+  ///                value is synthesizable.
+  /// @param Virtual Whether to ignore existing MemoryAcccess.
+  ///
+  /// @return The VirtualUse representing the same use as @p U.
+  static VirtualUse create(Scop *S, const Use &U, LoopInfo *LI, bool Virtual);
+
+  /// Get a VirtualUse for any kind of use of a value within a statement.
+  ///
+  /// @param S         The Scop object.
+  /// @param UserStmt  The statement in which @p Val is used. Can be nullptr, in
+  ///                  which case it assumed that the statement has been
+  ///                  removed, which is only possible if no instruction in it
+  ///                  had side-effects or computes a value used by another
+  ///                  statement.
+  /// @param UserScope Loop scope in which the value is used. Needed to
+  ///                  determine whether the value is synthesizable.
+  /// @param Val       The value being used.
+  /// @param Virtual   Whether to use (and prioritize over instruction location)
+  ///                  information about MemoryAccesses.
+  ///
+  /// @return A VirtualUse object that gives information about @p Val's use in
+  ///         @p UserStmt.
+  static VirtualUse create(Scop *S, ScopStmt *UserStmt, Loop *UserScope,
+                           Value *Val, bool Virtual);
+
+  static VirtualUse create(ScopStmt *UserStmt, Loop *UserScope, Value *Val,
+                           bool Virtual) {
+    return create(UserStmt->getParent(), UserStmt, UserScope, Val, Virtual);
+  }
+
+  bool isConstant() const { return Kind == Constant; }
+  bool isBlock() const { return Kind == Block; }
+  bool isSynthesizable() const { return Kind == Synthesizable; }
+  bool isHoisted() const { return Kind == Hoisted; }
+  bool isReadOnly() const { return Kind == ReadOnly; }
+  bool isIntra() const { return Kind == Intra; }
+  bool isInter() const { return Kind == Inter; }
+
+  /// Return user statement.
+  ScopStmt *getUser() const { return User; }
+
+  /// Return the used value.
+  llvm::Value *getValue() const { return Val; }
+
+  /// Return the type of use.
+  UseKind getKind() const { return Kind; }
+
+  /// Return the ScalarEvolution representation of @p Val.
+  const SCEV *getScevExpr() const { return ScevExpr; }
+
+  /// Return the MemoryAccess that makes the value available in this statement,
+  /// if any.
+  MemoryAccess *getMemoryAccess() const { return InputMA; }
+
+  /// Print a description of this object.
+  ///
+  /// @param OS           Stream to print to.
+  /// @param Reproducible If true, ensures that the output is stable between
+  ///                     runs and is suitable to check in regression tests.
+  ///                     This excludes printing e.g. pointer values. If false,
+  ///                     the output should not be used for regression tests,
+  ///                     but may contain more information useful in debugger
+  ///                     sessions.
+  void print(raw_ostream &OS, bool Reproducible = true) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dump() const;
+#endif
+};
+
+/// An iterator for virtual operands.
+class VirtualOperandIterator
+    : public std::iterator<std::forward_iterator_tag, VirtualUse> {
+  friend class VirtualInstruction;
+  friend class VirtualUse;
+
+  using super = std::iterator<std::forward_iterator_tag, VirtualUse>;
+  using Self = VirtualOperandIterator;
+
+  ScopStmt *User;
+  User::op_iterator U;
+
+  VirtualOperandIterator(ScopStmt *User, User::op_iterator U)
+      : User(User), U(U) {}
+
+public:
+  using pointer = typename super::pointer;
+  using reference = typename super::reference;
+
+  inline bool operator==(const Self &that) const {
+    assert(this->User == that.User);
+    return this->U == that.U;
+  }
+
+  inline bool operator!=(const Self &that) const {
+    assert(this->User == that.User);
+    return this->U != that.U;
+  }
+
+  VirtualUse operator*() const {
+    return VirtualUse::create(User, User->getSurroundingLoop(), U->get(), true);
+  }
+
+  Use *operator->() const { return U; }
+
+  Self &operator++() {
+    U++;
+    return *this;
+  }
+
+  Self operator++(int) {
+    Self tmp = *this;
+    ++*this;
+    return tmp;
+  }
+};
+
+/// This class represents a "virtual instruction", an instruction in a ScopStmt,
+/// effectively a ScopStmt/Instruction-pair.
+///
+/// An instructions can be moved between statements (e.g. to avoid a scalar
+/// dependency) and even can be contained in multiple statements (for instance,
+/// to recompute a value instead of transferring it), hence 'virtual'. This
+/// class is required to represent such instructions that are not in their
+/// 'physical' location anymore.
+///
+/// A statement can currently not contain the same instructions multiple times
+/// (that is, from different loop iterations). Therefore, a
+/// ScopStmt/Instruction-pair uniquely identifies a virtual instructions.
+/// ScopStmt::getInstruction() can contain the same instruction multiple times,
+/// but they necessarily compute the same value.
+class VirtualInstruction {
+  friend class VirtualOperandIterator;
+  friend struct llvm::DenseMapInfo<VirtualInstruction>;
+
+private:
+  /// The statement this virtual instruction is in.
+  ScopStmt *Stmt = nullptr;
+
+  /// The instruction of a statement.
+  Instruction *Inst = nullptr;
+
+public:
+  VirtualInstruction() {}
+
+  /// Create a new virtual instruction of an instruction @p Inst in @p Stmt.
+  VirtualInstruction(ScopStmt *Stmt, Instruction *Inst)
+      : Stmt(Stmt), Inst(Inst) {
+    assert(Stmt && Inst);
+  }
+
+  VirtualOperandIterator operand_begin() const {
+    return VirtualOperandIterator(Stmt, Inst->op_begin());
+  }
+
+  VirtualOperandIterator operand_end() const {
+    return VirtualOperandIterator(Stmt, Inst->op_end());
+  }
+
+  /// Returns a list of virtual operands.
+  ///
+  /// Virtual operands, like virtual instructions, need to encode the ScopStmt
+  /// they are in.
+  llvm::iterator_range<VirtualOperandIterator> operands() const {
+    return {operand_begin(), operand_end()};
+  }
+
+  /// Return the SCoP everything is contained in.
+  Scop *getScop() const { return Stmt->getParent(); }
+
+  /// Return the ScopStmt this virtual instruction is in.
+  ScopStmt *getStmt() const { return Stmt; }
+
+  /// Return the instruction in the statement.
+  Instruction *getInstruction() const { return Inst; }
+
+  /// Print a description of this object.
+  ///
+  /// @param OS           Stream to print to.
+  /// @param Reproducible If true, ensures that the output is stable between
+  ///                     runs and is suitable for checks in regression tests.
+  ///                     This excludes printing e.g., pointer values. If false,
+  ///                     the output should not be used for regression tests,
+  ///                     but may contain more information useful in debugger
+  ///                     sessions.
+  void print(raw_ostream &OS, bool Reproducible = true) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dump() const;
+#endif
+};
+
+static inline bool operator==(VirtualInstruction LHS, VirtualInstruction RHS) {
+  return LHS.getStmt() == RHS.getStmt() &&
+         LHS.getInstruction() == RHS.getInstruction();
+}
+
+/// Find all reachable instructions and accesses.
+///
+/// @param S              The SCoP to find everything reachable in.
+/// @param LI             LoopInfo required for analysis.
+/// @param UsedInsts[out] Receives all reachable instructions.
+/// @param UsedAccs[out]  Receives all reachable accesses.
+/// @param OnlyLocal      If non-nullptr, activates local mode: The SCoP is
+///                       assumed to consist only of this statement and is
+///                       conservatively correct. Does not require walking the
+///                       whole SCoP.
+void markReachable(Scop *S, LoopInfo *LI,
+                   DenseSet<VirtualInstruction> &UsedInsts,
+                   DenseSet<MemoryAccess *> &UsedAccs,
+                   ScopStmt *OnlyLocal = nullptr);
+
+} // namespace polly
+
+namespace llvm {
+/// Support VirtualInstructions in llvm::DenseMaps.
+template <> struct DenseMapInfo<polly::VirtualInstruction> {
+public:
+  static bool isEqual(polly::VirtualInstruction LHS,
+                      polly::VirtualInstruction RHS) {
+    return DenseMapInfo<polly::ScopStmt *>::isEqual(LHS.getStmt(),
+                                                    RHS.getStmt()) &&
+           DenseMapInfo<Instruction *>::isEqual(LHS.getInstruction(),
+                                                RHS.getInstruction());
+  }
+
+  static polly::VirtualInstruction getTombstoneKey() {
+    polly::VirtualInstruction TombstoneKey;
+    TombstoneKey.Stmt = DenseMapInfo<polly::ScopStmt *>::getTombstoneKey();
+    TombstoneKey.Inst = DenseMapInfo<Instruction *>::getTombstoneKey();
+    return TombstoneKey;
+  }
+
+  static polly::VirtualInstruction getEmptyKey() {
+    polly::VirtualInstruction EmptyKey;
+    EmptyKey.Stmt = DenseMapInfo<polly::ScopStmt *>::getEmptyKey();
+    EmptyKey.Inst = DenseMapInfo<Instruction *>::getEmptyKey();
+    return EmptyKey;
+  }
+
+  static unsigned getHashValue(polly::VirtualInstruction Val) {
+    return DenseMapInfo<std::pair<polly::ScopStmt *, Instruction *>>::
+        getHashValue(std::make_pair(Val.getStmt(), Val.getInstruction()));
+  }
+};
+} // namespace llvm
+
+#endif /* POLLY_SUPPORT_VIRTUALINSTRUCTION_H */
diff --git a/final/include/polly/ZoneAlgo.h b/final/include/polly/ZoneAlgo.h
new file mode 100644
index 0000000..43a9da9
--- /dev/null
+++ b/final/include/polly/ZoneAlgo.h
@@ -0,0 +1,386 @@
+//===------ ZoneAlgo.h ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Derive information about array elements between statements ("Zones").
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_ZONEALGO_H
+#define POLLY_ZONEALGO_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "isl/isl-noexceptions.h"
+#include <memory>
+
+namespace llvm {
+class Value;
+class LoopInfo;
+class Loop;
+class PHINode;
+class raw_ostream;
+} // namespace llvm
+
+namespace polly {
+class Scop;
+class ScopStmt;
+class MemoryAccess;
+class ScopArrayInfo;
+
+/// Return only the mappings that map to known values.
+///
+/// @param UMap { [] -> ValInst[] }
+///
+/// @return { [] -> ValInst[] }
+isl::union_map filterKnownValInst(const isl::union_map &UMap);
+
+/// Base class for algorithms based on zones, like DeLICM.
+class ZoneAlgorithm {
+protected:
+  /// The name of the pass this is used from. Used for optimization remarks.
+  const char *PassName;
+
+  /// Hold a reference to the isl_ctx to avoid it being freed before we released
+  /// all of the isl objects.
+  ///
+  /// This must be declared before any other member that holds an isl object.
+  /// This guarantees that the shared_ptr and its isl_ctx is destructed last,
+  /// after all other members free'd the isl objects they were holding.
+  std::shared_ptr<isl_ctx> IslCtx;
+
+  /// Cached reaching definitions for each ScopStmt.
+  ///
+  /// Use getScalarReachingDefinition() to get its contents.
+  llvm::DenseMap<ScopStmt *, isl::map> ScalarReachDefZone;
+
+  /// The analyzed Scop.
+  Scop *S;
+
+  /// LoopInfo analysis used to determine whether values are synthesizable.
+  llvm::LoopInfo *LI;
+
+  /// Parameter space that does not need realignment.
+  isl::space ParamSpace;
+
+  /// Space the schedule maps to.
+  isl::space ScatterSpace;
+
+  /// Cached version of the schedule and domains.
+  isl::union_map Schedule;
+
+  /// Combined access relations of all MemoryKind::Array READ accesses.
+  /// { DomainRead[] -> Element[] }
+  isl::union_map AllReads;
+
+  /// The loaded values (llvm::LoadInst) of all reads.
+  /// { [Element[] -> DomainRead[]] -> ValInst[] }
+  isl::union_map AllReadValInst;
+
+  /// Combined access relations of all MemoryKind::Array, MAY_WRITE accesses.
+  /// { DomainMayWrite[] -> Element[] }
+  isl::union_map AllMayWrites;
+
+  /// Combined access relations of all MemoryKind::Array, MUST_WRITE accesses.
+  /// { DomainMustWrite[] -> Element[] }
+  isl::union_map AllMustWrites;
+
+  /// Combined access relations of all MK_Array write accesses (union of
+  /// AllMayWrites and AllMustWrites).
+  /// { DomainWrite[] -> Element[] }
+  isl::union_map AllWrites;
+
+  /// The value instances written to array elements of all write accesses.
+  /// { [Element[] -> DomainWrite[]] -> ValInst[] }
+  isl::union_map AllWriteValInst;
+
+  /// All reaching definitions for  MemoryKind::Array writes.
+  /// { [Element[] -> Zone[]] -> DomainWrite[] }
+  isl::union_map WriteReachDefZone;
+
+  /// Map llvm::Values to an isl identifier.
+  /// Used with -polly-use-llvm-names=false as an alternative method to get
+  /// unique ids that do not depend on pointer values.
+  llvm::DenseMap<llvm::Value *, isl::id> ValueIds;
+
+  /// Set of array elements that can be reliably used for zone analysis.
+  /// { Element[] }
+  isl::union_set CompatibleElts;
+
+  /// List of PHIs that may transitively refer to themselves.
+  ///
+  /// Computing them would require a polyhedral transitive closure operation,
+  /// for which isl may only return an approximation. For correctness, we always
+  /// require an exact result. Hence, we exclude such PHIs.
+  llvm::SmallPtrSet<llvm::PHINode *, 4> RecursivePHIs;
+
+  /// PHIs that have been computed.
+  ///
+  /// Computed PHIs are replaced by their incoming values using #NormalizeMap.
+  llvm::DenseSet<llvm::PHINode *> ComputedPHIs;
+
+  /// For computed PHIs, contains the ValInst they stand for.
+  ///
+  /// To show an example, assume the following PHINode:
+  ///
+  ///   Stmt:
+  ///     %phi = phi double [%val1, %bb1], [%val2, %bb2]
+  ///
+  /// It's ValInst is:
+  ///
+  ///   { [Stmt[i] -> phi[]] }
+  ///
+  /// The value %phi will be either %val1 or %val2, depending on whether in
+  /// iteration i %bb1 or %bb2 has been executed before. In SCoPs, this can be
+  /// determined at compile-time, and the result stored in #NormalizeMap. For
+  /// the previous example, it could be:
+  ///
+  ///   { [Stmt[i] -> phi[]] -> [Stmt[0] -> val1[]];
+  ///     [Stmt[i] -> phi[]] -> [Stmt[i] -> val2[]] : i > 0 }
+  ///
+  /// Only ValInsts in #ComputedPHIs are present in this map. Other values are
+  /// assumed to represent themselves. This is to avoid adding lots of identity
+  /// entries to this map.
+  ///
+  /// { PHIValInst[] -> IncomingValInst[] }
+  isl::union_map NormalizeMap;
+
+  /// Cache for computePerPHI(const ScopArrayInfo *)
+  llvm::SmallDenseMap<llvm::PHINode *, isl::union_map> PerPHIMaps;
+
+  /// Prepare the object before computing the zones of @p S.
+  ///
+  /// @param PassName Name of the pass using this analysis.
+  /// @param S        The SCoP to process.
+  /// @param LI       LoopInfo analysis used to determine synthesizable values.
+  ZoneAlgorithm(const char *PassName, Scop *S, llvm::LoopInfo *LI);
+
+private:
+  /// Find the array elements that violate the zone analysis assumptions.
+  ///
+  /// What violates our assumptions:
+  /// - A load after a write of the same location; we assume that all reads
+  ///   occur before the writes.
+  /// - Two writes to the same location; we cannot model the order in which
+  ///   these occur.
+  ///
+  /// Scalar reads implicitly always occur before other accesses therefore never
+  /// violate the first condition. There is also at most one write to a scalar,
+  /// satisfying the second condition.
+  ///
+  /// @param Stmt                  The statement to be analyzed.
+  /// @param[out] IncompatibleElts Receives the elements that are not
+  ///                              zone-analysis compatible.
+  /// @param[out]                  AllElts receives all encountered elements.
+  void collectIncompatibleElts(ScopStmt *Stmt, isl::union_set &IncompatibleElts,
+                               isl::union_set &AllElts);
+
+  void addArrayReadAccess(MemoryAccess *MA);
+
+  /// Return the ValInst write by a (must-)write access. Returns the 'unknown'
+  /// ValInst if there is no single ValInst[] the array element written to will
+  /// have.
+  ///
+  /// @return { ValInst[] }
+  isl::union_map getWrittenValue(MemoryAccess *MA, isl::map AccRel);
+
+  void addArrayWriteAccess(MemoryAccess *MA);
+
+protected:
+  isl::union_set makeEmptyUnionSet() const;
+
+  isl::union_map makeEmptyUnionMap() const;
+
+  /// For each 'execution' of a PHINode, get the incoming block that was
+  /// executed before.
+  ///
+  /// For each PHI instance we can directly determine which was the incoming
+  /// block, and hence derive which value the PHI has.
+  ///
+  /// @param SAI The ScopArrayInfo representing the PHI's storage.
+  ///
+  /// @return { DomainPHIRead[] -> DomainPHIWrite[] }
+  isl::union_map computePerPHI(const polly::ScopArrayInfo *SAI);
+
+  /// Find the array elements that can be used for zone analysis.
+  void collectCompatibleElts();
+
+  /// Get the schedule for @p Stmt.
+  ///
+  /// The domain of the result is as narrow as possible.
+  isl::map getScatterFor(ScopStmt *Stmt) const;
+
+  /// Get the schedule of @p MA's parent statement.
+  isl::map getScatterFor(MemoryAccess *MA) const;
+
+  /// Get the schedule for the statement instances of @p Domain.
+  isl::union_map getScatterFor(isl::union_set Domain) const;
+
+  /// Get the schedule for the statement instances of @p Domain.
+  isl::map getScatterFor(isl::set Domain) const;
+
+  /// Get the domain of @p Stmt.
+  isl::set getDomainFor(ScopStmt *Stmt) const;
+
+  /// Get the domain @p MA's parent statement.
+  isl::set getDomainFor(MemoryAccess *MA) const;
+
+  /// Get the access relation of @p MA.
+  ///
+  /// The domain of the result is as narrow as possible.
+  isl::map getAccessRelationFor(MemoryAccess *MA) const;
+
+  /// Get the reaching definition of a scalar defined in @p Stmt.
+  ///
+  /// Note that this does not depend on the llvm::Instruction, only on the
+  /// statement it is defined in. Therefore the same computation can be reused.
+  ///
+  /// @param Stmt The statement in which a scalar is defined.
+  ///
+  /// @return { Scatter[] -> DomainDef[] }
+  isl::map getScalarReachingDefinition(ScopStmt *Stmt);
+
+  /// Get the reaching definition of a scalar defined in @p DefDomain.
+  ///
+  /// @param DomainDef { DomainDef[] }
+  ///              The write statements to get the reaching definition for.
+  ///
+  /// @return { Scatter[] -> DomainDef[] }
+  isl::map getScalarReachingDefinition(isl::set DomainDef);
+
+  /// Create a statement-to-unknown value mapping.
+  ///
+  /// @param Stmt The statement whose instances are mapped to unknown.
+  ///
+  /// @return { Domain[] -> ValInst[] }
+  isl::map makeUnknownForDomain(ScopStmt *Stmt) const;
+
+  /// Create an isl_id that represents @p V.
+  isl::id makeValueId(llvm::Value *V);
+
+  /// Create the space for an llvm::Value that is available everywhere.
+  isl::space makeValueSpace(llvm::Value *V);
+
+  /// Create a set with the llvm::Value @p V which is available everywhere.
+  isl::set makeValueSet(llvm::Value *V);
+
+  /// Create a mapping from a statement instance to the instance of an
+  /// llvm::Value that can be used in there.
+  ///
+  /// Although LLVM IR uses single static assignment, llvm::Values can have
+  /// different contents in loops, when they get redefined in the last
+  /// iteration. This function tries to get the statement instance of the
+  /// previous definition, relative to a user.
+  ///
+  /// Example:
+  /// for (int i = 0; i < N; i += 1) {
+  /// DEF:
+  ///    int v = A[i];
+  /// USE:
+  ///    use(v);
+  ///  }
+  ///
+  /// The value instance used by statement instance USE[i] is DEF[i]. Hence,
+  /// makeValInst returns:
+  ///
+  /// { USE[i] -> [DEF[i] -> v[]] : 0 <= i < N }
+  ///
+  /// @param Val       The value to get the instance of.
+  /// @param UserStmt  The statement that uses @p Val. Can be nullptr.
+  /// @param Scope     Loop the using instruction resides in.
+  /// @param IsCertain Pass true if the definition of @p Val is a
+  ///                  MUST_WRITE or false if the write is conditional.
+  ///
+  /// @return { DomainUse[] -> ValInst[] }
+  isl::map makeValInst(llvm::Value *Val, ScopStmt *UserStmt, llvm::Loop *Scope,
+                       bool IsCertain = true);
+
+  /// Create and normalize a ValInst.
+  ///
+  /// @see makeValInst
+  /// @see normalizeValInst
+  /// @see #NormalizedPHI
+  isl::union_map makeNormalizedValInst(llvm::Value *Val, ScopStmt *UserStmt,
+                                       llvm::Loop *Scope,
+                                       bool IsCertain = true);
+
+  /// Return whether @p MA can be used for transformations (e.g. OpTree load
+  /// forwarding, DeLICM mapping).
+  bool isCompatibleAccess(MemoryAccess *MA);
+
+  /// Compute the different zones.
+  void computeCommon();
+
+  ///  Compute the normalization map that replaces PHIs by their incoming
+  ///  values.
+  ///
+  /// @see #NormalizeMap
+  void computeNormalizedPHIs();
+
+  /// Print the current state of all MemoryAccesses to @p.
+  void printAccesses(llvm::raw_ostream &OS, int Indent = 0) const;
+
+  /// Is @p MA a PHI READ access that can be normalized?
+  ///
+  /// @see #NormalizeMap
+  bool isNormalizable(MemoryAccess *MA);
+
+  /// @{
+  /// Determine whether the argument does not map to any computed PHI. Those
+  /// should have been replaced by their incoming values.
+  ///
+  /// @see #NormalizedPHI
+  bool isNormalized(isl::map Map);
+  bool isNormalized(isl::union_map Map);
+  /// @}
+
+public:
+  /// Return the SCoP this object is analyzing.
+  Scop *getScop() const { return S; }
+
+  /// A reaching definition zone is known to have the definition's written value
+  /// if the definition is a MUST_WRITE.
+  ///
+  /// @return { [Element[] -> Zone[]] -> ValInst[] }
+  isl::union_map computeKnownFromMustWrites() const;
+
+  /// A reaching definition zone is known to be the same value as any load that
+  /// reads from that array element in that period.
+  ///
+  /// @return { [Element[] -> Zone[]] -> ValInst[] }
+  isl::union_map computeKnownFromLoad() const;
+
+  /// Compute which value an array element stores at every instant.
+  ///
+  /// @param FromWrite Use stores as source of information.
+  /// @param FromRead  Use loads as source of information.
+  ///
+  /// @return { [Element[] -> Zone[]] -> ValInst[] }
+  isl::union_map computeKnown(bool FromWrite, bool FromRead) const;
+};
+
+/// Create a domain-to-unknown value mapping.
+///
+/// Value instances that do not represent a specific value are represented by an
+/// unnamed tuple of 0 dimensions. Its meaning depends on the context. It can
+/// either mean a specific but unknown value which cannot be represented by
+/// other means. It conflicts with itself because those two unknown ValInsts may
+/// have different concrete values at runtime.
+///
+/// The other meaning is an arbitrary or wildcard value that can be chosen
+/// freely, like LLVM's undef. If matched with an unknown ValInst, there is no
+/// conflict.
+///
+/// @param Domain { Domain[] }
+///
+/// @return { Domain[] -> ValInst[] }
+isl::union_map makeUnknownForDomain(isl::union_set Domain);
+} // namespace polly
+
+#endif /* POLLY_ZONEALGO_H */
diff --git a/final/lib/Analysis/DependenceInfo.cpp b/final/lib/Analysis/DependenceInfo.cpp
new file mode 100644
index 0000000..1b09e4f
--- /dev/null
+++ b/final/lib/Analysis/DependenceInfo.cpp
@@ -0,0 +1,1062 @@
+//===- DependenceInfo.cpp - Calculate dependency information for a Scop. --===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Calculate the data dependency relations for a Scop using ISL.
+//
+// The integer set library (ISL) from Sven, has a integrated dependency analysis
+// to calculate data dependences. This pass takes advantage of this and
+// calculate those dependences a Scop.
+//
+// The dependences in this pass are exact in terms that for a specific read
+// statement instance only the last write statement instance is returned. In
+// case of may writes a set of possible write instances is returned. This
+// analysis will never produce redundant dependences.
+//
+//===----------------------------------------------------------------------===//
+//
+#include "polly/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/GICHelper.h"
+#include "llvm/Support/Debug.h"
+#include <isl/aff.h>
+#include <isl/ctx.h>
+#include <isl/flow.h>
+#include <isl/map.h>
+#include <isl/options.h>
+#include <isl/schedule.h>
+#include <isl/set.h>
+#include <isl/union_map.h>
+#include <isl/union_set.h>
+
+using namespace polly;
+using namespace llvm;
+
+#define DEBUG_TYPE "polly-dependence"
+
+static cl::opt<int> OptComputeOut(
+    "polly-dependences-computeout",
+    cl::desc("Bound the dependence analysis by a maximal amount of "
+             "computational steps (0 means no bound)"),
+    cl::Hidden, cl::init(500000), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> LegalityCheckDisabled(
+    "disable-polly-legality", cl::desc("Disable polly legality check"),
+    cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    UseReductions("polly-dependences-use-reductions",
+                  cl::desc("Exploit reductions in dependence analysis"),
+                  cl::Hidden, cl::init(true), cl::ZeroOrMore,
+                  cl::cat(PollyCategory));
+
+enum AnalysisType { VALUE_BASED_ANALYSIS, MEMORY_BASED_ANALYSIS };
+
+static cl::opt<enum AnalysisType> OptAnalysisType(
+    "polly-dependences-analysis-type",
+    cl::desc("The kind of dependence analysis to use"),
+    cl::values(clEnumValN(VALUE_BASED_ANALYSIS, "value-based",
+                          "Exact dependences without transitive dependences"),
+               clEnumValN(MEMORY_BASED_ANALYSIS, "memory-based",
+                          "Overapproximation of dependences")),
+    cl::Hidden, cl::init(VALUE_BASED_ANALYSIS), cl::ZeroOrMore,
+    cl::cat(PollyCategory));
+
+static cl::opt<Dependences::AnalysisLevel> OptAnalysisLevel(
+    "polly-dependences-analysis-level",
+    cl::desc("The level of dependence analysis"),
+    cl::values(clEnumValN(Dependences::AL_Statement, "statement-wise",
+                          "Statement-level analysis"),
+               clEnumValN(Dependences::AL_Reference, "reference-wise",
+                          "Memory reference level analysis that distinguish"
+                          " accessed references in the same statement"),
+               clEnumValN(Dependences::AL_Access, "access-wise",
+                          "Memory reference level analysis that distinguish"
+                          " access instructions in the same statement")),
+    cl::Hidden, cl::init(Dependences::AL_Statement), cl::ZeroOrMore,
+    cl::cat(PollyCategory));
+
+//===----------------------------------------------------------------------===//
+
+/// Tag the @p Relation domain with @p TagId
+static __isl_give isl_map *tag(__isl_take isl_map *Relation,
+                               __isl_take isl_id *TagId) {
+  isl_space *Space = isl_map_get_space(Relation);
+  Space = isl_space_drop_dims(Space, isl_dim_out, 0,
+                              isl_map_dim(Relation, isl_dim_out));
+  Space = isl_space_set_tuple_id(Space, isl_dim_out, TagId);
+  isl_multi_aff *Tag = isl_multi_aff_domain_map(Space);
+  Relation = isl_map_preimage_domain_multi_aff(Relation, Tag);
+  return Relation;
+}
+
+/// Tag the @p Relation domain with either MA->getArrayId() or
+///        MA->getId() based on @p TagLevel
+static __isl_give isl_map *tag(__isl_take isl_map *Relation, MemoryAccess *MA,
+                               Dependences::AnalysisLevel TagLevel) {
+  if (TagLevel == Dependences::AL_Reference)
+    return tag(Relation, MA->getArrayId().release());
+
+  if (TagLevel == Dependences::AL_Access)
+    return tag(Relation, MA->getId().release());
+
+  // No need to tag at the statement level.
+  return Relation;
+}
+
+/// Collect information about the SCoP @p S.
+static void collectInfo(Scop &S, isl_union_map *&Read,
+                        isl_union_map *&MustWrite, isl_union_map *&MayWrite,
+                        isl_union_map *&ReductionTagMap,
+                        isl_union_set *&TaggedStmtDomain,
+                        Dependences::AnalysisLevel Level) {
+  isl_space *Space = S.getParamSpace().release();
+  Read = isl_union_map_empty(isl_space_copy(Space));
+  MustWrite = isl_union_map_empty(isl_space_copy(Space));
+  MayWrite = isl_union_map_empty(isl_space_copy(Space));
+  ReductionTagMap = isl_union_map_empty(isl_space_copy(Space));
+  isl_union_map *StmtSchedule = isl_union_map_empty(Space);
+
+  SmallPtrSet<const ScopArrayInfo *, 8> ReductionArrays;
+  if (UseReductions)
+    for (ScopStmt &Stmt : S)
+      for (MemoryAccess *MA : Stmt)
+        if (MA->isReductionLike())
+          ReductionArrays.insert(MA->getScopArrayInfo());
+
+  for (ScopStmt &Stmt : S) {
+    for (MemoryAccess *MA : Stmt) {
+      isl_set *domcp = Stmt.getDomain().release();
+      isl_map *accdom = MA->getAccessRelation().release();
+
+      accdom = isl_map_intersect_domain(accdom, domcp);
+
+      if (ReductionArrays.count(MA->getScopArrayInfo())) {
+        // Wrap the access domain and adjust the schedule accordingly.
+        //
+        // An access domain like
+        //   Stmt[i0, i1] -> MemAcc_A[i0 + i1]
+        // will be transformed into
+        //   [Stmt[i0, i1] -> MemAcc_A[i0 + i1]] -> MemAcc_A[i0 + i1]
+        //
+        // We collect all the access domains in the ReductionTagMap.
+        // This is used in Dependences::calculateDependences to create
+        // a tagged Schedule tree.
+
+        ReductionTagMap =
+            isl_union_map_add_map(ReductionTagMap, isl_map_copy(accdom));
+        accdom = isl_map_range_map(accdom);
+      } else {
+        accdom = tag(accdom, MA, Level);
+        if (Level > Dependences::AL_Statement) {
+          isl_map *StmtScheduleMap = Stmt.getSchedule().release();
+          assert(StmtScheduleMap &&
+                 "Schedules that contain extension nodes require special "
+                 "handling.");
+          isl_map *Schedule = tag(StmtScheduleMap, MA, Level);
+          StmtSchedule = isl_union_map_add_map(StmtSchedule, Schedule);
+        }
+      }
+
+      if (MA->isRead())
+        Read = isl_union_map_add_map(Read, accdom);
+      else if (MA->isMayWrite())
+        MayWrite = isl_union_map_add_map(MayWrite, accdom);
+      else
+        MustWrite = isl_union_map_add_map(MustWrite, accdom);
+    }
+
+    if (!ReductionArrays.empty() && Level == Dependences::AL_Statement)
+      StmtSchedule =
+          isl_union_map_add_map(StmtSchedule, Stmt.getSchedule().release());
+  }
+
+  StmtSchedule = isl_union_map_intersect_params(
+      StmtSchedule, S.getAssumedContext().release());
+  TaggedStmtDomain = isl_union_map_domain(StmtSchedule);
+
+  ReductionTagMap = isl_union_map_coalesce(ReductionTagMap);
+  Read = isl_union_map_coalesce(Read);
+  MustWrite = isl_union_map_coalesce(MustWrite);
+  MayWrite = isl_union_map_coalesce(MayWrite);
+}
+
+/// Fix all dimension of @p Zero to 0 and add it to @p user
+static isl_stat fixSetToZero(__isl_take isl_set *Zero, void *user) {
+  isl_union_set **User = (isl_union_set **)user;
+  for (unsigned i = 0; i < isl_set_dim(Zero, isl_dim_set); i++)
+    Zero = isl_set_fix_si(Zero, isl_dim_set, i, 0);
+  *User = isl_union_set_add_set(*User, Zero);
+  return isl_stat_ok;
+}
+
+/// Compute the privatization dependences for a given dependency @p Map
+///
+/// Privatization dependences are widened original dependences which originate
+/// or end in a reduction access. To compute them we apply the transitive close
+/// of the reduction dependences (which maps each iteration of a reduction
+/// statement to all following ones) on the RAW/WAR/WAW dependences. The
+/// dependences which start or end at a reduction statement will be extended to
+/// depend on all following reduction statement iterations as well.
+/// Note: "Following" here means according to the reduction dependences.
+///
+/// For the input:
+///
+///  S0:   *sum = 0;
+///        for (int i = 0; i < 1024; i++)
+///  S1:     *sum += i;
+///  S2:   *sum = *sum * 3;
+///
+/// we have the following dependences before we add privatization dependences:
+///
+///   RAW:
+///     { S0[] -> S1[0]; S1[1023] -> S2[] }
+///   WAR:
+///     {  }
+///   WAW:
+///     { S0[] -> S1[0]; S1[1024] -> S2[] }
+///   RED:
+///     { S1[i0] -> S1[1 + i0] : i0 >= 0 and i0 <= 1022 }
+///
+/// and afterwards:
+///
+///   RAW:
+///     { S0[] -> S1[i0] : i0 >= 0 and i0 <= 1023;
+///       S1[i0] -> S2[] : i0 >= 0 and i0 <= 1023}
+///   WAR:
+///     {  }
+///   WAW:
+///     { S0[] -> S1[i0] : i0 >= 0 and i0 <= 1023;
+///       S1[i0] -> S2[] : i0 >= 0 and i0 <= 1023}
+///   RED:
+///     { S1[i0] -> S1[1 + i0] : i0 >= 0 and i0 <= 1022 }
+///
+/// Note: This function also computes the (reverse) transitive closure of the
+///       reduction dependences.
+void Dependences::addPrivatizationDependences() {
+  isl_union_map *PrivRAW, *PrivWAW, *PrivWAR;
+
+  // The transitive closure might be over approximated, thus could lead to
+  // dependency cycles in the privatization dependences. To make sure this
+  // will not happen we remove all negative dependences after we computed
+  // the transitive closure.
+  TC_RED = isl_union_map_transitive_closure(isl_union_map_copy(RED), nullptr);
+
+  // FIXME: Apply the current schedule instead of assuming the identity schedule
+  //        here. The current approach is only valid as long as we compute the
+  //        dependences only with the initial (identity schedule). Any other
+  //        schedule could change "the direction of the backward dependences" we
+  //        want to eliminate here.
+  isl_union_set *UDeltas = isl_union_map_deltas(isl_union_map_copy(TC_RED));
+  isl_union_set *Universe = isl_union_set_universe(isl_union_set_copy(UDeltas));
+  isl_union_set *Zero = isl_union_set_empty(isl_union_set_get_space(Universe));
+  isl_union_set_foreach_set(Universe, fixSetToZero, &Zero);
+  isl_union_map *NonPositive = isl_union_set_lex_le_union_set(UDeltas, Zero);
+
+  TC_RED = isl_union_map_subtract(TC_RED, NonPositive);
+
+  TC_RED = isl_union_map_union(
+      TC_RED, isl_union_map_reverse(isl_union_map_copy(TC_RED)));
+  TC_RED = isl_union_map_coalesce(TC_RED);
+
+  isl_union_map **Maps[] = {&RAW, &WAW, &WAR};
+  isl_union_map **PrivMaps[] = {&PrivRAW, &PrivWAW, &PrivWAR};
+  for (unsigned u = 0; u < 3; u++) {
+    isl_union_map **Map = Maps[u], **PrivMap = PrivMaps[u];
+
+    *PrivMap = isl_union_map_apply_range(isl_union_map_copy(*Map),
+                                         isl_union_map_copy(TC_RED));
+    *PrivMap = isl_union_map_union(
+        *PrivMap, isl_union_map_apply_range(isl_union_map_copy(TC_RED),
+                                            isl_union_map_copy(*Map)));
+
+    *Map = isl_union_map_union(*Map, *PrivMap);
+  }
+
+  isl_union_set_free(Universe);
+}
+
+static __isl_give isl_union_flow *buildFlow(__isl_keep isl_union_map *Snk,
+                                            __isl_keep isl_union_map *Src,
+                                            __isl_keep isl_union_map *MaySrc,
+                                            __isl_keep isl_schedule *Schedule) {
+  isl_union_access_info *AI;
+
+  AI = isl_union_access_info_from_sink(isl_union_map_copy(Snk));
+  if (MaySrc)
+    AI = isl_union_access_info_set_may_source(AI, isl_union_map_copy(MaySrc));
+  if (Src)
+    AI = isl_union_access_info_set_must_source(AI, isl_union_map_copy(Src));
+  AI = isl_union_access_info_set_schedule(AI, isl_schedule_copy(Schedule));
+  auto Flow = isl_union_access_info_compute_flow(AI);
+  DEBUG(if (!Flow) dbgs() << "last error: "
+                          << isl_ctx_last_error(isl_schedule_get_ctx(Schedule))
+                          << '\n';);
+  return Flow;
+}
+
+/// Compute exact WAR dependences
+/// We need exact WAR dependences. That is, if there are
+/// dependences of the form:
+/// must-W2 (sink) <- must-W1 (sink) <- R (source)
+/// We wish to generate *ONLY*:
+/// { R -> W1 },
+/// NOT:
+/// { R -> W2, R -> W1 }
+///
+/// However, in the case of may-writes, we do *not* wish to allow
+/// may-writes to block must-writes. This makes sense, since perhaps the
+/// may-write will not happen. In that case, the exact dependence will
+/// be the (read -> must-write).
+/// Example:
+/// must-W2 (sink) <- may-W1 (sink) <- R (source)
+/// We wish to generate:
+/// { R-> W1, R -> W2 }
+///
+/// We use the fact that may dependences are not allowed to flow
+/// through a must source. That way, reads will be stopped by intermediate
+/// must-writes.
+/// However, may-sources may not interfere with one another. Hence, reads
+/// will not block each other from generating dependences.
+///
+/// Write (Sink) <- MustWrite (Must-Source) <- Read (MaySource) is
+/// present, then the dependence
+///    { Write <- Read }
+/// is not tracked.
+///
+/// We would like to specify the Must-Write as kills, source as Read
+/// and sink as Write.
+/// ISL does not have the functionality currently to support "kills".
+/// Use the Must-Source as a way to specify "kills".
+/// The drawback is that we will have both
+///   { Write <- MustWrite, Write <- Read }
+///
+/// We need to filter this to track only { Write <- Read }.
+///
+/// Filtering { Write <- Read } from WAROverestimated:
+/// --------------------------------------------------
+/// isl_union_flow_get_full_may_dependence gives us dependences of the form
+///   WAROverestimated = { Read+MustWrite -> [Write -> MemoryAccess]}
+///
+///  We need to intersect the domain with Read to get only
+///  Read dependences.
+///    Read = { Read -> MemoryAccess }
+///
+///
+/// 1. Construct:
+///   WARMemAccesses = { Read+Write -> [Read+Write -> MemoryAccess] }
+/// This takes a Read+Write from WAROverestimated and maps it to the
+/// corresponding wrapped memory access from WAROverestimated.
+///
+/// 2. Apply WARMemAcesses to the domain of WAR Overestimated to give:
+///   WAR = { [Read+Write -> MemoryAccess] -> [Write -> MemoryAccess] }
+///
+/// WAR is in a state where we can intersect with Read, since they
+/// have the same structure.
+///
+/// 3. Intersect this with a wrapped Read. Read is wrapped
+/// to ensure the domains look the same.
+///   WAR = WAR \intersect (wrapped Read)
+///   WAR = { [Read -> MemoryAccesss] -> [Write -> MemoryAccess] }
+///
+///  4. Project out the memory access in the domain to get
+///  WAR = { Read -> Write }
+static isl_union_map *buildWAR(isl_union_map *Write, isl_union_map *MustWrite,
+                               isl_union_map *Read, isl_schedule *Schedule) {
+  isl_union_flow *Flow = buildFlow(Write, MustWrite, Read, Schedule);
+  auto *WAROverestimated = isl_union_flow_get_full_may_dependence(Flow);
+
+  // 1. Constructing WARMemAccesses
+  // WarMemAccesses = { Read+Write -> [Write -> MemAccess] }
+  // Range factor of range product
+  //     { Read+Write -> MemAcesss }
+  // Domain projection
+  //     { [Read+Write -> MemAccess] -> Read+Write }
+  // Reverse
+  //     { Read+Write -> [Read+Write -> MemAccess] }
+  auto WARMemAccesses = isl_union_map_copy(WAROverestimated);
+  WARMemAccesses = isl_union_map_range_factor_range(WAROverestimated);
+  WARMemAccesses = isl_union_map_domain_map(WARMemAccesses);
+  WARMemAccesses = isl_union_map_reverse(WARMemAccesses);
+
+  // 2. Apply to get domain tagged with memory accesses
+  isl_union_map *WAR =
+      isl_union_map_apply_domain(WAROverestimated, WARMemAccesses);
+
+  // 3. Intersect with Read to extract only reads
+  auto ReadWrapped = isl_union_map_wrap(isl_union_map_copy(Read));
+  WAR = isl_union_map_intersect_domain(WAR, ReadWrapped);
+
+  // 4. Project out memory accesses to get usual style dependences
+  WAR = isl_union_map_range_factor_domain(WAR);
+  WAR = isl_union_map_domain_factor_domain(WAR);
+
+  isl_union_flow_free(Flow);
+  return WAR;
+}
+
+void Dependences::calculateDependences(Scop &S) {
+  isl_union_map *Read, *MustWrite, *MayWrite, *ReductionTagMap;
+  isl_schedule *Schedule;
+  isl_union_set *TaggedStmtDomain;
+
+  DEBUG(dbgs() << "Scop: \n" << S << "\n");
+
+  collectInfo(S, Read, MustWrite, MayWrite, ReductionTagMap, TaggedStmtDomain,
+              Level);
+
+  bool HasReductions = !isl_union_map_is_empty(ReductionTagMap);
+
+  DEBUG(dbgs() << "Read: " << Read << '\n';
+        dbgs() << "MustWrite: " << MustWrite << '\n';
+        dbgs() << "MayWrite: " << MayWrite << '\n';
+        dbgs() << "ReductionTagMap: " << ReductionTagMap << '\n';
+        dbgs() << "TaggedStmtDomain: " << TaggedStmtDomain << '\n';);
+
+  Schedule = S.getScheduleTree().release();
+
+  if (!HasReductions) {
+    isl_union_map_free(ReductionTagMap);
+    // Tag the schedule tree if we want fine-grain dependence info
+    if (Level > AL_Statement) {
+      auto TaggedMap =
+          isl_union_set_unwrap(isl_union_set_copy(TaggedStmtDomain));
+      auto Tags = isl_union_map_domain_map_union_pw_multi_aff(TaggedMap);
+      Schedule = isl_schedule_pullback_union_pw_multi_aff(Schedule, Tags);
+    }
+  } else {
+    isl_union_map *IdentityMap;
+    isl_union_pw_multi_aff *ReductionTags, *IdentityTags, *Tags;
+
+    // Extract Reduction tags from the combined access domains in the given
+    // SCoP. The result is a map that maps each tagged element in the domain to
+    // the memory location it accesses. ReductionTags = {[Stmt[i] ->
+    // Array[f(i)]] -> Stmt[i] }
+    ReductionTags =
+        isl_union_map_domain_map_union_pw_multi_aff(ReductionTagMap);
+
+    // Compute an identity map from each statement in domain to itself.
+    // IdentityTags = { [Stmt[i] -> Stmt[i] }
+    IdentityMap = isl_union_set_identity(isl_union_set_copy(TaggedStmtDomain));
+    IdentityTags = isl_union_pw_multi_aff_from_union_map(IdentityMap);
+
+    Tags = isl_union_pw_multi_aff_union_add(ReductionTags, IdentityTags);
+
+    // By pulling back Tags from Schedule, we have a schedule tree that can
+    // be used to compute normal dependences, as well as 'tagged' reduction
+    // dependences.
+    Schedule = isl_schedule_pullback_union_pw_multi_aff(Schedule, Tags);
+  }
+
+  DEBUG(dbgs() << "Read: " << Read << "\n";
+        dbgs() << "MustWrite: " << MustWrite << "\n";
+        dbgs() << "MayWrite: " << MayWrite << "\n";
+        dbgs() << "Schedule: " << Schedule << "\n");
+
+  isl_union_map *StrictWAW = nullptr;
+  {
+    IslMaxOperationsGuard MaxOpGuard(IslCtx.get(), OptComputeOut);
+
+    RAW = WAW = WAR = RED = nullptr;
+    isl_union_map *Write = isl_union_map_union(isl_union_map_copy(MustWrite),
+                                               isl_union_map_copy(MayWrite));
+
+    // We are interested in detecting reductions that do not have intermediate
+    // computations that are captured by other statements.
+    //
+    // Example:
+    // void f(int *A, int *B) {
+    //     for(int i = 0; i <= 100; i++) {
+    //
+    //            *-WAR (S0[i] -> S0[i + 1] 0 <= i <= 100)------------*
+    //            |                                                   |
+    //            *-WAW (S0[i] -> S0[i + 1] 0 <= i <= 100)------------*
+    //            |                                                   |
+    //            v                                                   |
+    //     S0:    *A += i; >------------------*-----------------------*
+    //                                        |
+    //         if (i >= 98) {          WAR (S0[i] -> S1[i]) 98 <= i <= 100
+    //                                        |
+    //     S1:        *B = *A; <--------------*
+    //         }
+    //     }
+    // }
+    //
+    // S0[0 <= i <= 100] has a reduction. However, the values in
+    // S0[98 <= i <= 100] is captured in S1[98 <= i <= 100].
+    // Since we allow free reordering on our reduction dependences, we need to
+    // remove all instances of a reduction statement that have data dependences
+    // originating from them.
+    // In the case of the example, we need to remove S0[98 <= i <= 100] from
+    // our reduction dependences.
+    //
+    // When we build up the WAW dependences that are used to detect reductions,
+    // we consider only **Writes that have no intermediate Reads**.
+    //
+    // `isl_union_flow_get_must_dependence` gives us dependences of the form:
+    // (sink <- must_source).
+    //
+    // It *will not give* dependences of the form:
+    // 1. (sink <- ... <- may_source <- ... <- must_source)
+    // 2. (sink <- ... <- must_source <- ... <- must_source)
+    //
+    // For a detailed reference on ISL's flow analysis, see:
+    // "Presburger Formulas and Polyhedral Compilation" - Approximate Dataflow
+    //  Analysis.
+    //
+    // Since we set "Write" as a must-source, "Read" as a may-source, and ask
+    // for must dependences, we get all Writes to Writes that **do not flow
+    // through a Read**.
+    //
+    // ScopInfo::checkForReductions makes sure that if something captures
+    // the reduction variable in the same basic block, then it is rejected
+    // before it is even handed here. This makes sure that there is exactly
+    // one read and one write to a reduction variable in a Statement.
+    // Example:
+    //     void f(int *sum, int A[N], int B[N]) {
+    //       for (int i = 0; i < N; i++) {
+    //         *sum += A[i]; < the store and the load is not tagged as a
+    //         B[i] = *sum;  < reduction-like access due to the overlap.
+    //       }
+    //     }
+
+    isl_union_flow *Flow = buildFlow(Write, Write, Read, Schedule);
+    StrictWAW = isl_union_flow_get_must_dependence(Flow);
+    isl_union_flow_free(Flow);
+
+    if (OptAnalysisType == VALUE_BASED_ANALYSIS) {
+      Flow = buildFlow(Read, MustWrite, MayWrite, Schedule);
+      RAW = isl_union_flow_get_may_dependence(Flow);
+      isl_union_flow_free(Flow);
+
+      Flow = buildFlow(Write, MustWrite, MayWrite, Schedule);
+      WAW = isl_union_flow_get_may_dependence(Flow);
+      isl_union_flow_free(Flow);
+
+      WAR = buildWAR(Write, MustWrite, Read, Schedule);
+      isl_union_map_free(Write);
+      isl_schedule_free(Schedule);
+    } else {
+      isl_union_flow *Flow;
+
+      Flow = buildFlow(Read, nullptr, Write, Schedule);
+      RAW = isl_union_flow_get_may_dependence(Flow);
+      isl_union_flow_free(Flow);
+
+      Flow = buildFlow(Write, nullptr, Read, Schedule);
+      WAR = isl_union_flow_get_may_dependence(Flow);
+      isl_union_flow_free(Flow);
+
+      Flow = buildFlow(Write, nullptr, Write, Schedule);
+      WAW = isl_union_flow_get_may_dependence(Flow);
+      isl_union_flow_free(Flow);
+
+      isl_union_map_free(Write);
+      isl_schedule_free(Schedule);
+    }
+
+    isl_union_map_free(MustWrite);
+    isl_union_map_free(MayWrite);
+    isl_union_map_free(Read);
+
+    RAW = isl_union_map_coalesce(RAW);
+    WAW = isl_union_map_coalesce(WAW);
+    WAR = isl_union_map_coalesce(WAR);
+
+    // End of max_operations scope.
+  }
+
+  if (isl_ctx_last_error(IslCtx.get()) == isl_error_quota) {
+    isl_union_map_free(RAW);
+    isl_union_map_free(WAW);
+    isl_union_map_free(WAR);
+    isl_union_map_free(StrictWAW);
+    RAW = WAW = WAR = StrictWAW = nullptr;
+    isl_ctx_reset_error(IslCtx.get());
+  }
+
+  // Drop out early, as the remaining computations are only needed for
+  // reduction dependences or dependences that are finer than statement
+  // level dependences.
+  if (!HasReductions && Level == AL_Statement) {
+    RED = isl_union_map_empty(isl_union_map_get_space(RAW));
+    TC_RED = isl_union_map_empty(isl_union_set_get_space(TaggedStmtDomain));
+    isl_union_set_free(TaggedStmtDomain);
+    isl_union_map_free(StrictWAW);
+    return;
+  }
+
+  isl_union_map *STMT_RAW, *STMT_WAW, *STMT_WAR;
+  STMT_RAW = isl_union_map_intersect_domain(
+      isl_union_map_copy(RAW), isl_union_set_copy(TaggedStmtDomain));
+  STMT_WAW = isl_union_map_intersect_domain(
+      isl_union_map_copy(WAW), isl_union_set_copy(TaggedStmtDomain));
+  STMT_WAR =
+      isl_union_map_intersect_domain(isl_union_map_copy(WAR), TaggedStmtDomain);
+  DEBUG({
+    dbgs() << "Wrapped Dependences:\n";
+    dump();
+    dbgs() << "\n";
+  });
+
+  // To handle reduction dependences we proceed as follows:
+  // 1) Aggregate all possible reduction dependences, namely all self
+  //    dependences on reduction like statements.
+  // 2) Intersect them with the actual RAW & WAW dependences to the get the
+  //    actual reduction dependences. This will ensure the load/store memory
+  //    addresses were __identical__ in the two iterations of the statement.
+  // 3) Relax the original RAW, WAW and WAR dependences by subtracting the
+  //    actual reduction dependences. Binary reductions (sum += A[i]) cause
+  //    the same, RAW, WAW and WAR dependences.
+  // 4) Add the privatization dependences which are widened versions of
+  //    already present dependences. They model the effect of manual
+  //    privatization at the outermost possible place (namely after the last
+  //    write and before the first access to a reduction location).
+
+  // Step 1)
+  RED = isl_union_map_empty(isl_union_map_get_space(RAW));
+  for (ScopStmt &Stmt : S) {
+    for (MemoryAccess *MA : Stmt) {
+      if (!MA->isReductionLike())
+        continue;
+      isl_set *AccDomW = isl_map_wrap(MA->getAccessRelation().release());
+      isl_map *Identity =
+          isl_map_from_domain_and_range(isl_set_copy(AccDomW), AccDomW);
+      RED = isl_union_map_add_map(RED, Identity);
+    }
+  }
+
+  // Step 2)
+  RED = isl_union_map_intersect(RED, isl_union_map_copy(RAW));
+  RED = isl_union_map_intersect(RED, StrictWAW);
+
+  if (!isl_union_map_is_empty(RED)) {
+
+    // Step 3)
+    RAW = isl_union_map_subtract(RAW, isl_union_map_copy(RED));
+    WAW = isl_union_map_subtract(WAW, isl_union_map_copy(RED));
+    WAR = isl_union_map_subtract(WAR, isl_union_map_copy(RED));
+
+    // Step 4)
+    addPrivatizationDependences();
+  }
+
+  DEBUG({
+    dbgs() << "Final Wrapped Dependences:\n";
+    dump();
+    dbgs() << "\n";
+  });
+
+  // RED_SIN is used to collect all reduction dependences again after we
+  // split them according to the causing memory accesses. The current assumption
+  // is that our method of splitting will not have any leftovers. In the end
+  // we validate this assumption until we have more confidence in this method.
+  isl_union_map *RED_SIN = isl_union_map_empty(isl_union_map_get_space(RAW));
+
+  // For each reduction like memory access, check if there are reduction
+  // dependences with the access relation of the memory access as a domain
+  // (wrapped space!). If so these dependences are caused by this memory access.
+  // We then move this portion of reduction dependences back to the statement ->
+  // statement space and add a mapping from the memory access to these
+  // dependences.
+  for (ScopStmt &Stmt : S) {
+    for (MemoryAccess *MA : Stmt) {
+      if (!MA->isReductionLike())
+        continue;
+
+      isl_set *AccDomW = isl_map_wrap(MA->getAccessRelation().release());
+      isl_union_map *AccRedDepU = isl_union_map_intersect_domain(
+          isl_union_map_copy(TC_RED), isl_union_set_from_set(AccDomW));
+      if (isl_union_map_is_empty(AccRedDepU)) {
+        isl_union_map_free(AccRedDepU);
+        continue;
+      }
+
+      isl_map *AccRedDep = isl_map_from_union_map(AccRedDepU);
+      RED_SIN = isl_union_map_add_map(RED_SIN, isl_map_copy(AccRedDep));
+      AccRedDep = isl_map_zip(AccRedDep);
+      AccRedDep = isl_set_unwrap(isl_map_domain(AccRedDep));
+      setReductionDependences(MA, AccRedDep);
+    }
+  }
+
+  assert(isl_union_map_is_equal(RED_SIN, TC_RED) &&
+         "Intersecting the reduction dependence domain with the wrapped access "
+         "relation is not enough, we need to loosen the access relation also");
+  isl_union_map_free(RED_SIN);
+
+  RAW = isl_union_map_zip(RAW);
+  WAW = isl_union_map_zip(WAW);
+  WAR = isl_union_map_zip(WAR);
+  RED = isl_union_map_zip(RED);
+  TC_RED = isl_union_map_zip(TC_RED);
+
+  DEBUG({
+    dbgs() << "Zipped Dependences:\n";
+    dump();
+    dbgs() << "\n";
+  });
+
+  RAW = isl_union_set_unwrap(isl_union_map_domain(RAW));
+  WAW = isl_union_set_unwrap(isl_union_map_domain(WAW));
+  WAR = isl_union_set_unwrap(isl_union_map_domain(WAR));
+  RED = isl_union_set_unwrap(isl_union_map_domain(RED));
+  TC_RED = isl_union_set_unwrap(isl_union_map_domain(TC_RED));
+
+  DEBUG({
+    dbgs() << "Unwrapped Dependences:\n";
+    dump();
+    dbgs() << "\n";
+  });
+
+  RAW = isl_union_map_union(RAW, STMT_RAW);
+  WAW = isl_union_map_union(WAW, STMT_WAW);
+  WAR = isl_union_map_union(WAR, STMT_WAR);
+
+  RAW = isl_union_map_coalesce(RAW);
+  WAW = isl_union_map_coalesce(WAW);
+  WAR = isl_union_map_coalesce(WAR);
+  RED = isl_union_map_coalesce(RED);
+  TC_RED = isl_union_map_coalesce(TC_RED);
+
+  DEBUG(dump());
+}
+
+bool Dependences::isValidSchedule(Scop &S,
+                                  StatementToIslMapTy *NewSchedule) const {
+  if (LegalityCheckDisabled)
+    return true;
+
+  isl_union_map *Dependences = getDependences(TYPE_RAW | TYPE_WAW | TYPE_WAR);
+  isl_space *Space = S.getParamSpace().release();
+  isl_union_map *Schedule = isl_union_map_empty(Space);
+
+  isl_space *ScheduleSpace = nullptr;
+
+  for (ScopStmt &Stmt : S) {
+    isl_map *StmtScat;
+
+    if (NewSchedule->find(&Stmt) == NewSchedule->end())
+      StmtScat = Stmt.getSchedule().release();
+    else
+      StmtScat = isl_map_copy((*NewSchedule)[&Stmt]);
+    assert(StmtScat &&
+           "Schedules that contain extension nodes require special handling.");
+
+    if (!ScheduleSpace)
+      ScheduleSpace = isl_space_range(isl_map_get_space(StmtScat));
+
+    Schedule = isl_union_map_add_map(Schedule, StmtScat);
+  }
+
+  Dependences =
+      isl_union_map_apply_domain(Dependences, isl_union_map_copy(Schedule));
+  Dependences = isl_union_map_apply_range(Dependences, Schedule);
+
+  isl_set *Zero = isl_set_universe(isl_space_copy(ScheduleSpace));
+  for (unsigned i = 0; i < isl_set_dim(Zero, isl_dim_set); i++)
+    Zero = isl_set_fix_si(Zero, isl_dim_set, i, 0);
+
+  isl_union_set *UDeltas = isl_union_map_deltas(Dependences);
+  isl_set *Deltas = isl_union_set_extract_set(UDeltas, ScheduleSpace);
+  isl_union_set_free(UDeltas);
+
+  isl_map *NonPositive = isl_set_lex_le_set(Deltas, Zero);
+  bool IsValid = isl_map_is_empty(NonPositive);
+  isl_map_free(NonPositive);
+
+  return IsValid;
+}
+
+// Check if the current scheduling dimension is parallel.
+//
+// We check for parallelism by verifying that the loop does not carry any
+// dependences.
+//
+// Parallelism test: if the distance is zero in all outer dimensions, then it
+// has to be zero in the current dimension as well.
+//
+// Implementation: first, translate dependences into time space, then force
+// outer dimensions to be equal. If the distance is zero in the current
+// dimension, then the loop is parallel. The distance is zero in the current
+// dimension if it is a subset of a map with equal values for the current
+// dimension.
+bool Dependences::isParallel(isl_union_map *Schedule, isl_union_map *Deps,
+                             isl_pw_aff **MinDistancePtr) const {
+  isl_set *Deltas, *Distance;
+  isl_map *ScheduleDeps;
+  unsigned Dimension;
+  bool IsParallel;
+
+  Deps = isl_union_map_apply_range(Deps, isl_union_map_copy(Schedule));
+  Deps = isl_union_map_apply_domain(Deps, isl_union_map_copy(Schedule));
+
+  if (isl_union_map_is_empty(Deps)) {
+    isl_union_map_free(Deps);
+    return true;
+  }
+
+  ScheduleDeps = isl_map_from_union_map(Deps);
+  Dimension = isl_map_dim(ScheduleDeps, isl_dim_out) - 1;
+
+  for (unsigned i = 0; i < Dimension; i++)
+    ScheduleDeps = isl_map_equate(ScheduleDeps, isl_dim_out, i, isl_dim_in, i);
+
+  Deltas = isl_map_deltas(ScheduleDeps);
+  Distance = isl_set_universe(isl_set_get_space(Deltas));
+
+  // [0, ..., 0, +] - All zeros and last dimension larger than zero
+  for (unsigned i = 0; i < Dimension; i++)
+    Distance = isl_set_fix_si(Distance, isl_dim_set, i, 0);
+
+  Distance = isl_set_lower_bound_si(Distance, isl_dim_set, Dimension, 1);
+  Distance = isl_set_intersect(Distance, Deltas);
+
+  IsParallel = isl_set_is_empty(Distance);
+  if (IsParallel || !MinDistancePtr) {
+    isl_set_free(Distance);
+    return IsParallel;
+  }
+
+  Distance = isl_set_project_out(Distance, isl_dim_set, 0, Dimension);
+  Distance = isl_set_coalesce(Distance);
+
+  // This last step will compute a expression for the minimal value in the
+  // distance polyhedron Distance with regards to the first (outer most)
+  // dimension.
+  *MinDistancePtr = isl_pw_aff_coalesce(isl_set_dim_min(Distance, 0));
+
+  return false;
+}
+
+static void printDependencyMap(raw_ostream &OS, __isl_keep isl_union_map *DM) {
+  if (DM)
+    OS << DM << "\n";
+  else
+    OS << "n/a\n";
+}
+
+void Dependences::print(raw_ostream &OS) const {
+  OS << "\tRAW dependences:\n\t\t";
+  printDependencyMap(OS, RAW);
+  OS << "\tWAR dependences:\n\t\t";
+  printDependencyMap(OS, WAR);
+  OS << "\tWAW dependences:\n\t\t";
+  printDependencyMap(OS, WAW);
+  OS << "\tReduction dependences:\n\t\t";
+  printDependencyMap(OS, RED);
+  OS << "\tTransitive closure of reduction dependences:\n\t\t";
+  printDependencyMap(OS, TC_RED);
+}
+
+void Dependences::dump() const { print(dbgs()); }
+
+void Dependences::releaseMemory() {
+  isl_union_map_free(RAW);
+  isl_union_map_free(WAR);
+  isl_union_map_free(WAW);
+  isl_union_map_free(RED);
+  isl_union_map_free(TC_RED);
+
+  RED = RAW = WAR = WAW = TC_RED = nullptr;
+
+  for (auto &ReductionDeps : ReductionDependences)
+    isl_map_free(ReductionDeps.second);
+  ReductionDependences.clear();
+}
+
+__isl_give isl_union_map *Dependences::getDependences(int Kinds) const {
+  assert(hasValidDependences() && "No valid dependences available");
+  isl_space *Space = isl_union_map_get_space(RAW);
+  isl_union_map *Deps = isl_union_map_empty(Space);
+
+  if (Kinds & TYPE_RAW)
+    Deps = isl_union_map_union(Deps, isl_union_map_copy(RAW));
+
+  if (Kinds & TYPE_WAR)
+    Deps = isl_union_map_union(Deps, isl_union_map_copy(WAR));
+
+  if (Kinds & TYPE_WAW)
+    Deps = isl_union_map_union(Deps, isl_union_map_copy(WAW));
+
+  if (Kinds & TYPE_RED)
+    Deps = isl_union_map_union(Deps, isl_union_map_copy(RED));
+
+  if (Kinds & TYPE_TC_RED)
+    Deps = isl_union_map_union(Deps, isl_union_map_copy(TC_RED));
+
+  Deps = isl_union_map_coalesce(Deps);
+  Deps = isl_union_map_detect_equalities(Deps);
+  return Deps;
+}
+
+bool Dependences::hasValidDependences() const {
+  return (RAW != nullptr) && (WAR != nullptr) && (WAW != nullptr);
+}
+
+__isl_give isl_map *
+Dependences::getReductionDependences(MemoryAccess *MA) const {
+  return isl_map_copy(ReductionDependences.lookup(MA));
+}
+
+void Dependences::setReductionDependences(MemoryAccess *MA, isl_map *D) {
+  assert(ReductionDependences.count(MA) == 0 &&
+         "Reduction dependences set twice!");
+  ReductionDependences[MA] = D;
+}
+
+const Dependences &
+DependenceAnalysis::Result::getDependences(Dependences::AnalysisLevel Level) {
+  if (Dependences *d = D[Level].get())
+    return *d;
+
+  return recomputeDependences(Level);
+}
+
+const Dependences &DependenceAnalysis::Result::recomputeDependences(
+    Dependences::AnalysisLevel Level) {
+  D[Level].reset(new Dependences(S.getSharedIslCtx(), Level));
+  D[Level]->calculateDependences(S);
+  return *D[Level];
+}
+
+DependenceAnalysis::Result
+DependenceAnalysis::run(Scop &S, ScopAnalysisManager &SAM,
+                        ScopStandardAnalysisResults &SAR) {
+  return {S, {}};
+}
+
+AnalysisKey DependenceAnalysis::Key;
+
+PreservedAnalyses
+DependenceInfoPrinterPass::run(Scop &S, ScopAnalysisManager &SAM,
+                               ScopStandardAnalysisResults &SAR,
+                               SPMUpdater &U) {
+  auto &DI = SAM.getResult<DependenceAnalysis>(S, SAR);
+
+  if (auto d = DI.D[OptAnalysisLevel].get()) {
+    d->print(OS);
+    return PreservedAnalyses::all();
+  }
+
+  // Otherwise create the dependences on-the-fly and print them
+  Dependences D(S.getSharedIslCtx(), OptAnalysisLevel);
+  D.calculateDependences(S);
+  D.print(OS);
+
+  return PreservedAnalyses::all();
+}
+
+const Dependences &
+DependenceInfo::getDependences(Dependences::AnalysisLevel Level) {
+  if (Dependences *d = D[Level].get())
+    return *d;
+
+  return recomputeDependences(Level);
+}
+
+const Dependences &
+DependenceInfo::recomputeDependences(Dependences::AnalysisLevel Level) {
+  D[Level].reset(new Dependences(S->getSharedIslCtx(), Level));
+  D[Level]->calculateDependences(*S);
+  return *D[Level];
+}
+
+bool DependenceInfo::runOnScop(Scop &ScopVar) {
+  S = &ScopVar;
+  return false;
+}
+
+/// Print the dependences for the given SCoP to @p OS.
+
+void polly::DependenceInfo::printScop(raw_ostream &OS, Scop &S) const {
+  if (auto d = D[OptAnalysisLevel].get()) {
+    d->print(OS);
+    return;
+  }
+
+  // Otherwise create the dependences on-the-fly and print it
+  Dependences D(S.getSharedIslCtx(), OptAnalysisLevel);
+  D.calculateDependences(S);
+  D.print(OS);
+}
+
+void DependenceInfo::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequiredTransitive<ScopInfoRegionPass>();
+  AU.setPreservesAll();
+}
+
+char DependenceInfo::ID = 0;
+
+Pass *polly::createDependenceInfoPass() { return new DependenceInfo(); }
+
+INITIALIZE_PASS_BEGIN(DependenceInfo, "polly-dependences",
+                      "Polly - Calculate dependences", false, false);
+INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass);
+INITIALIZE_PASS_END(DependenceInfo, "polly-dependences",
+                    "Polly - Calculate dependences", false, false)
+
+//===----------------------------------------------------------------------===//
+const Dependences &
+DependenceInfoWrapperPass::getDependences(Scop *S,
+                                          Dependences::AnalysisLevel Level) {
+  auto It = ScopToDepsMap.find(S);
+  if (It != ScopToDepsMap.end())
+    if (It->second) {
+      if (It->second->getDependenceLevel() == Level)
+        return *It->second.get();
+    }
+  return recomputeDependences(S, Level);
+}
+
+const Dependences &DependenceInfoWrapperPass::recomputeDependences(
+    Scop *S, Dependences::AnalysisLevel Level) {
+  std::unique_ptr<Dependences> D(new Dependences(S->getSharedIslCtx(), Level));
+  D->calculateDependences(*S);
+  auto Inserted = ScopToDepsMap.insert(std::make_pair(S, std::move(D)));
+  return *Inserted.first->second;
+}
+
+bool DependenceInfoWrapperPass::runOnFunction(Function &F) {
+  auto &SI = *getAnalysis<ScopInfoWrapperPass>().getSI();
+  for (auto &It : SI) {
+    assert(It.second && "Invalid SCoP object!");
+    recomputeDependences(It.second.get(), Dependences::AL_Access);
+  }
+  return false;
+}
+
+void DependenceInfoWrapperPass::print(raw_ostream &OS, const Module *M) const {
+  for (auto &It : ScopToDepsMap) {
+    assert((It.first && It.second) && "Invalid Scop or Dependence object!\n");
+    It.second->print(OS);
+  }
+}
+
+void DependenceInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequiredTransitive<ScopInfoWrapperPass>();
+  AU.setPreservesAll();
+}
+
+char DependenceInfoWrapperPass::ID = 0;
+
+Pass *polly::createDependenceInfoWrapperPassPass() {
+  return new DependenceInfoWrapperPass();
+}
+
+INITIALIZE_PASS_BEGIN(
+    DependenceInfoWrapperPass, "polly-function-dependences",
+    "Polly - Calculate dependences for all the SCoPs of a function", false,
+    false)
+INITIALIZE_PASS_DEPENDENCY(ScopInfoWrapperPass);
+INITIALIZE_PASS_END(
+    DependenceInfoWrapperPass, "polly-function-dependences",
+    "Polly - Calculate dependences for all the SCoPs of a function", false,
+    false)
diff --git a/final/lib/Analysis/PolyhedralInfo.cpp b/final/lib/Analysis/PolyhedralInfo.cpp
new file mode 100644
index 0000000..b159c15
--- /dev/null
+++ b/final/lib/Analysis/PolyhedralInfo.cpp
@@ -0,0 +1,163 @@
+//===--------- PolyhedralInfo.cpp  - Create Scops from LLVM IR-------------===//
+///
+///                     The LLVM Compiler Infrastructure
+///
+/// This file is distributed under the University of Illinois Open Source
+/// License. See LICENSE.TXT for details.
+///
+//===----------------------------------------------------------------------===//
+///
+/// An interface to the Polyhedral analysis engine(Polly) of LLVM.
+///
+/// This pass provides an interface to the polyhedral analysis performed by
+/// Polly.
+///
+/// This interface provides basic interface like isParallel, isVectorizable
+/// that can be used in LLVM transformation passes.
+///
+/// Work in progress, this file is subject to change.
+//===----------------------------------------------------------------------===//
+
+#include "polly/PolyhedralInfo.h"
+#include "polly/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/GICHelper.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Support/Debug.h"
+#include <isl/map.h>
+#include <isl/union_map.h>
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polyhedral-info"
+
+static cl::opt<bool> CheckParallel("polly-check-parallel",
+                                   cl::desc("Check for parallel loops"),
+                                   cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                                   cl::cat(PollyCategory));
+
+static cl::opt<bool> CheckVectorizable("polly-check-vectorizable",
+                                       cl::desc("Check for vectorizable loops"),
+                                       cl::Hidden, cl::init(false),
+                                       cl::ZeroOrMore, cl::cat(PollyCategory));
+
+void PolyhedralInfo::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequiredTransitive<DependenceInfoWrapperPass>();
+  AU.addRequired<LoopInfoWrapperPass>();
+  AU.addRequiredTransitive<ScopInfoWrapperPass>();
+  AU.setPreservesAll();
+}
+
+bool PolyhedralInfo::runOnFunction(Function &F) {
+  DI = &getAnalysis<DependenceInfoWrapperPass>();
+  SI = getAnalysis<ScopInfoWrapperPass>().getSI();
+  return false;
+}
+
+void PolyhedralInfo::print(raw_ostream &OS, const Module *) const {
+  auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+  for (auto *TopLevelLoop : LI) {
+    for (auto *L : depth_first(TopLevelLoop)) {
+      OS.indent(2) << L->getHeader()->getName() << ":\t";
+      if (CheckParallel && isParallel(L))
+        OS << "Loop is parallel.\n";
+      else if (CheckParallel)
+        OS << "Loop is not parallel.\n";
+    }
+  }
+}
+
+bool PolyhedralInfo::checkParallel(Loop *L, isl_pw_aff **MinDepDistPtr) const {
+  bool IsParallel;
+  const Scop *S = getScopContainingLoop(L);
+  if (!S)
+    return false;
+  const Dependences &D =
+      DI->getDependences(const_cast<Scop *>(S), Dependences::AL_Access);
+  if (!D.hasValidDependences())
+    return false;
+  DEBUG(dbgs() << "Loop :\t" << L->getHeader()->getName() << ":\n");
+
+  isl_union_map *Deps =
+      D.getDependences(Dependences::TYPE_RAW | Dependences::TYPE_WAW |
+                       Dependences::TYPE_WAR | Dependences::TYPE_RED);
+  DEBUG(dbgs() << "Dependences :\t" << stringFromIslObj(Deps) << "\n");
+
+  isl_union_map *Schedule = getScheduleForLoop(S, L);
+  DEBUG(dbgs() << "Schedule: \t" << stringFromIslObj(Schedule) << "\n");
+
+  IsParallel = D.isParallel(Schedule, Deps, MinDepDistPtr);
+  isl_union_map_free(Schedule);
+  return IsParallel;
+}
+
+bool PolyhedralInfo::isParallel(Loop *L) const { return checkParallel(L); }
+
+const Scop *PolyhedralInfo::getScopContainingLoop(Loop *L) const {
+  assert((SI) && "ScopInfoWrapperPass is required by PolyhedralInfo pass!\n");
+  for (auto &It : *SI) {
+    Region *R = It.first;
+    if (R->contains(L))
+      return It.second.get();
+  }
+  return nullptr;
+}
+
+//  Given a Loop and the containing SCoP, we compute the partial schedule
+//  by taking union of individual schedules of each ScopStmt within the loop
+//  and projecting out the inner dimensions from the range of the schedule.
+//   for (i = 0; i < n; i++)
+//      for (j = 0; j < n; j++)
+//        A[j] = 1;  //Stmt
+//
+//  The original schedule will be
+//    Stmt[i0, i1] -> [i0, i1]
+//  The schedule for the outer loop will be
+//    Stmt[i0, i1] -> [i0]
+//  The schedule for the inner loop will be
+//    Stmt[i0, i1] -> [i0, i1]
+__isl_give isl_union_map *PolyhedralInfo::getScheduleForLoop(const Scop *S,
+                                                             Loop *L) const {
+  isl_union_map *Schedule = isl_union_map_empty(S->getParamSpace().release());
+  int CurrDim = S->getRelativeLoopDepth(L);
+  DEBUG(dbgs() << "Relative loop depth:\t" << CurrDim << "\n");
+  assert(CurrDim >= 0 && "Loop in region should have at least depth one");
+
+  for (auto &SS : *S) {
+    if (L->contains(SS.getSurroundingLoop())) {
+
+      unsigned int MaxDim = SS.getNumIterators();
+      DEBUG(dbgs() << "Maximum depth of Stmt:\t" << MaxDim << "\n");
+      isl_map *ScheduleMap = SS.getSchedule().release();
+      assert(
+          ScheduleMap &&
+          "Schedules that contain extension nodes require special handling.");
+
+      ScheduleMap = isl_map_project_out(ScheduleMap, isl_dim_out, CurrDim + 1,
+                                        MaxDim - CurrDim - 1);
+      ScheduleMap = isl_map_set_tuple_id(ScheduleMap, isl_dim_in,
+                                         SS.getDomainId().release());
+      Schedule =
+          isl_union_map_union(Schedule, isl_union_map_from_map(ScheduleMap));
+    }
+  }
+  Schedule = isl_union_map_coalesce(Schedule);
+  return Schedule;
+}
+
+char PolyhedralInfo::ID = 0;
+
+Pass *polly::createPolyhedralInfoPass() { return new PolyhedralInfo(); }
+
+INITIALIZE_PASS_BEGIN(PolyhedralInfo, "polyhedral-info",
+                      "Polly - Interface to polyhedral analysis engine", false,
+                      false);
+INITIALIZE_PASS_DEPENDENCY(DependenceInfoWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(ScopInfoWrapperPass);
+INITIALIZE_PASS_END(PolyhedralInfo, "polyhedral-info",
+                    "Polly - Interface to polyhedral analysis engine", false,
+                    false)
diff --git a/final/lib/Analysis/PruneUnprofitable.cpp b/final/lib/Analysis/PruneUnprofitable.cpp
new file mode 100644
index 0000000..9dcaa73
--- /dev/null
+++ b/final/lib/Analysis/PruneUnprofitable.cpp
@@ -0,0 +1,105 @@
+//===- PruneUnprofitable.cpp ----------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Mark a SCoP as unfeasible if not deemed profitable to optimize.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/PruneUnprofitable.h"
+#include "polly/ScopDetection.h"
+#include "polly/ScopInfo.h"
+#include "polly/ScopPass.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-prune-unprofitable"
+
+namespace {
+
+STATISTIC(ScopsProcessed,
+          "Number of SCoPs considered for unprofitability pruning");
+STATISTIC(ScopsPruned, "Number of pruned SCoPs because it they cannot be "
+                       "optimized in a significant way");
+STATISTIC(ScopsSurvived, "Number of SCoPs after pruning");
+
+STATISTIC(NumPrunedLoops, "Number of pruned loops");
+STATISTIC(NumPrunedBoxedLoops, "Number of pruned boxed loops");
+STATISTIC(NumPrunedAffineLoops, "Number of pruned affine loops");
+
+STATISTIC(NumLoopsInScop, "Number of loops in scops after pruning");
+STATISTIC(NumBoxedLoops, "Number of boxed loops in SCoPs after pruning");
+STATISTIC(NumAffineLoops, "Number of affine loops in SCoPs after pruning");
+
+class PruneUnprofitable : public ScopPass {
+private:
+  void updateStatistics(Scop &S, bool Pruned) {
+    auto ScopStats = S.getStatistics();
+    if (Pruned) {
+      ScopsPruned++;
+      NumPrunedLoops += ScopStats.NumAffineLoops + ScopStats.NumBoxedLoops;
+      NumPrunedBoxedLoops += ScopStats.NumBoxedLoops;
+      NumPrunedAffineLoops += ScopStats.NumAffineLoops;
+    } else {
+      ScopsSurvived++;
+      NumLoopsInScop += ScopStats.NumAffineLoops + ScopStats.NumBoxedLoops;
+      NumBoxedLoops += ScopStats.NumBoxedLoops;
+      NumAffineLoops += ScopStats.NumAffineLoops;
+    }
+  }
+
+public:
+  static char ID;
+
+  explicit PruneUnprofitable() : ScopPass(ID) {}
+  PruneUnprofitable(const PruneUnprofitable &) = delete;
+  PruneUnprofitable &operator=(const PruneUnprofitable &) = delete;
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.addRequired<ScopInfoRegionPass>();
+    AU.setPreservesAll();
+  }
+
+  bool runOnScop(Scop &S) override {
+    if (PollyProcessUnprofitable) {
+      DEBUG(dbgs() << "NOTE: -polly-process-unprofitable active, won't prune "
+                      "anything\n");
+      return false;
+    }
+
+    ScopsProcessed++;
+
+    if (!S.isProfitable(true)) {
+      DEBUG(dbgs() << "SCoP pruned because it probably cannot be optimized in "
+                      "a significant way\n");
+      S.invalidate(PROFITABLE, DebugLoc());
+      updateStatistics(S, true);
+    } else {
+      updateStatistics(S, false);
+    }
+
+    return false;
+  }
+};
+
+} // namespace
+
+char PruneUnprofitable::ID;
+
+Pass *polly::createPruneUnprofitablePass() { return new PruneUnprofitable(); }
+
+INITIALIZE_PASS_BEGIN(PruneUnprofitable, "polly-prune-unprofitable",
+                      "Polly - Prune unprofitable SCoPs", false, false)
+INITIALIZE_PASS_END(PruneUnprofitable, "polly-prune-unprofitable",
+                    "Polly - Prune unprofitable SCoPs", false, false)
diff --git a/final/lib/Analysis/ScopBuilder.cpp b/final/lib/Analysis/ScopBuilder.cpp
new file mode 100644
index 0000000..3c7f67b
--- /dev/null
+++ b/final/lib/Analysis/ScopBuilder.cpp
@@ -0,0 +1,1574 @@
+//===- ScopBuilder.cpp ----------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Create a polyhedral description for a static control flow region.
+//
+// The pass creates a polyhedral description of the Scops detected by the SCoP
+// detection derived from their LLVM-IR code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/ScopBuilder.h"
+#include "polly/Options.h"
+#include "polly/ScopDetection.h"
+#include "polly/ScopDetectionDiagnostic.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/SCEVValidator.h"
+#include "polly/Support/ScopHelper.h"
+#include "polly/Support/VirtualInstruction.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/EquivalenceClasses.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/RegionIterator.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Use.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <string>
+#include <tuple>
+#include <vector>
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-scops"
+
+STATISTIC(ScopFound, "Number of valid Scops");
+STATISTIC(RichScopFound, "Number of Scops containing a loop");
+STATISTIC(InfeasibleScops,
+          "Number of SCoPs with statically infeasible context.");
+
+bool polly::ModelReadOnlyScalars;
+
+static cl::opt<bool, true> XModelReadOnlyScalars(
+    "polly-analyze-read-only-scalars",
+    cl::desc("Model read-only scalar values in the scop description"),
+    cl::location(ModelReadOnlyScalars), cl::Hidden, cl::ZeroOrMore,
+    cl::init(true), cl::cat(PollyCategory));
+
+static cl::opt<bool> UnprofitableScalarAccs(
+    "polly-unprofitable-scalar-accs",
+    cl::desc("Count statements with scalar accesses as not optimizable"),
+    cl::Hidden, cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<bool> DetectFortranArrays(
+    "polly-detect-fortran-arrays",
+    cl::desc("Detect Fortran arrays and use this for code generation"),
+    cl::Hidden, cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<bool> DetectReductions("polly-detect-reductions",
+                                      cl::desc("Detect and exploit reductions"),
+                                      cl::Hidden, cl::ZeroOrMore,
+                                      cl::init(true), cl::cat(PollyCategory));
+
+// Multiplicative reductions can be disabled separately as these kind of
+// operations can overflow easily. Additive reductions and bit operations
+// are in contrast pretty stable.
+static cl::opt<bool> DisableMultiplicativeReductions(
+    "polly-disable-multiplicative-reductions",
+    cl::desc("Disable multiplicative reductions"), cl::Hidden, cl::ZeroOrMore,
+    cl::init(false), cl::cat(PollyCategory));
+
+enum class GranularityChoice { BasicBlocks, ScalarIndependence, Stores };
+
+static cl::opt<GranularityChoice> StmtGranularity(
+    "polly-stmt-granularity",
+    cl::desc(
+        "Algorithm to use for splitting basic blocks into multiple statements"),
+    cl::values(clEnumValN(GranularityChoice::BasicBlocks, "bb",
+                          "One statement per basic block"),
+               clEnumValN(GranularityChoice::ScalarIndependence, "scalar-indep",
+                          "Scalar independence heuristic"),
+               clEnumValN(GranularityChoice::Stores, "store",
+                          "Store-level granularity")),
+    cl::init(GranularityChoice::BasicBlocks), cl::cat(PollyCategory));
+
+void ScopBuilder::buildPHIAccesses(ScopStmt *PHIStmt, PHINode *PHI,
+                                   Region *NonAffineSubRegion,
+                                   bool IsExitBlock) {
+  // PHI nodes that are in the exit block of the region, hence if IsExitBlock is
+  // true, are not modeled as ordinary PHI nodes as they are not part of the
+  // region. However, we model the operands in the predecessor blocks that are
+  // part of the region as regular scalar accesses.
+
+  // If we can synthesize a PHI we can skip it, however only if it is in
+  // the region. If it is not it can only be in the exit block of the region.
+  // In this case we model the operands but not the PHI itself.
+  auto *Scope = LI.getLoopFor(PHI->getParent());
+  if (!IsExitBlock && canSynthesize(PHI, *scop, &SE, Scope))
+    return;
+
+  // PHI nodes are modeled as if they had been demoted prior to the SCoP
+  // detection. Hence, the PHI is a load of a new memory location in which the
+  // incoming value was written at the end of the incoming basic block.
+  bool OnlyNonAffineSubRegionOperands = true;
+  for (unsigned u = 0; u < PHI->getNumIncomingValues(); u++) {
+    Value *Op = PHI->getIncomingValue(u);
+    BasicBlock *OpBB = PHI->getIncomingBlock(u);
+    ScopStmt *OpStmt = scop->getLastStmtFor(OpBB);
+
+    // Do not build PHI dependences inside a non-affine subregion, but make
+    // sure that the necessary scalar values are still made available.
+    if (NonAffineSubRegion && NonAffineSubRegion->contains(OpBB)) {
+      auto *OpInst = dyn_cast<Instruction>(Op);
+      if (!OpInst || !NonAffineSubRegion->contains(OpInst))
+        ensureValueRead(Op, OpStmt);
+      continue;
+    }
+
+    OnlyNonAffineSubRegionOperands = false;
+    ensurePHIWrite(PHI, OpStmt, OpBB, Op, IsExitBlock);
+  }
+
+  if (!OnlyNonAffineSubRegionOperands && !IsExitBlock) {
+    addPHIReadAccess(PHIStmt, PHI);
+  }
+}
+
+void ScopBuilder::buildScalarDependences(ScopStmt *UserStmt,
+                                         Instruction *Inst) {
+  assert(!isa<PHINode>(Inst));
+
+  // Pull-in required operands.
+  for (Use &Op : Inst->operands())
+    ensureValueRead(Op.get(), UserStmt);
+}
+
+void ScopBuilder::buildEscapingDependences(Instruction *Inst) {
+  // Check for uses of this instruction outside the scop. Because we do not
+  // iterate over such instructions and therefore did not "ensure" the existence
+  // of a write, we must determine such use here.
+  if (scop->isEscaping(Inst))
+    ensureValueWrite(Inst);
+}
+
+/// Check that a value is a Fortran Array descriptor.
+///
+/// We check if V has the following structure:
+/// %"struct.array1_real(kind=8)" = type { i8*, i<zz>, i<zz>,
+///                                   [<num> x %struct.descriptor_dimension] }
+///
+///
+/// %struct.descriptor_dimension = type { i<zz>, i<zz>, i<zz> }
+///
+/// 1. V's type name starts with "struct.array"
+/// 2. V's type has layout as shown.
+/// 3. Final member of V's type has name "struct.descriptor_dimension",
+/// 4. "struct.descriptor_dimension" has layout as shown.
+/// 5. Consistent use of i<zz> where <zz> is some fixed integer number.
+///
+/// We are interested in such types since this is the code that dragonegg
+/// generates for Fortran array descriptors.
+///
+/// @param V the Value to be checked.
+///
+/// @returns True if V is a Fortran array descriptor, False otherwise.
+bool isFortranArrayDescriptor(Value *V) {
+  PointerType *PTy = dyn_cast<PointerType>(V->getType());
+
+  if (!PTy)
+    return false;
+
+  Type *Ty = PTy->getElementType();
+  assert(Ty && "Ty expected to be initialized");
+  auto *StructArrTy = dyn_cast<StructType>(Ty);
+
+  if (!(StructArrTy && StructArrTy->hasName()))
+    return false;
+
+  if (!StructArrTy->getName().startswith("struct.array"))
+    return false;
+
+  if (StructArrTy->getNumElements() != 4)
+    return false;
+
+  const ArrayRef<Type *> ArrMemberTys = StructArrTy->elements();
+
+  // i8* match
+  if (ArrMemberTys[0] != Type::getInt8PtrTy(V->getContext()))
+    return false;
+
+  // Get a reference to the int type and check that all the members
+  // share the same int type
+  Type *IntTy = ArrMemberTys[1];
+  if (ArrMemberTys[2] != IntTy)
+    return false;
+
+  // type: [<num> x %struct.descriptor_dimension]
+  ArrayType *DescriptorDimArrayTy = dyn_cast<ArrayType>(ArrMemberTys[3]);
+  if (!DescriptorDimArrayTy)
+    return false;
+
+  // type: %struct.descriptor_dimension := type { ixx, ixx, ixx }
+  StructType *DescriptorDimTy =
+      dyn_cast<StructType>(DescriptorDimArrayTy->getElementType());
+
+  if (!(DescriptorDimTy && DescriptorDimTy->hasName()))
+    return false;
+
+  if (DescriptorDimTy->getName() != "struct.descriptor_dimension")
+    return false;
+
+  if (DescriptorDimTy->getNumElements() != 3)
+    return false;
+
+  for (auto MemberTy : DescriptorDimTy->elements()) {
+    if (MemberTy != IntTy)
+      return false;
+  }
+
+  return true;
+}
+
+Value *ScopBuilder::findFADAllocationVisible(MemAccInst Inst) {
+  // match: 4.1 & 4.2 store/load
+  if (!isa<LoadInst>(Inst) && !isa<StoreInst>(Inst))
+    return nullptr;
+
+  // match: 4
+  if (Inst.getAlignment() != 8)
+    return nullptr;
+
+  Value *Address = Inst.getPointerOperand();
+
+  const BitCastInst *Bitcast = nullptr;
+  // [match: 3]
+  if (auto *Slot = dyn_cast<GetElementPtrInst>(Address)) {
+    Value *TypedMem = Slot->getPointerOperand();
+    // match: 2
+    Bitcast = dyn_cast<BitCastInst>(TypedMem);
+  } else {
+    // match: 2
+    Bitcast = dyn_cast<BitCastInst>(Address);
+  }
+
+  if (!Bitcast)
+    return nullptr;
+
+  auto *MallocMem = Bitcast->getOperand(0);
+
+  // match: 1
+  auto *MallocCall = dyn_cast<CallInst>(MallocMem);
+  if (!MallocCall)
+    return nullptr;
+
+  Function *MallocFn = MallocCall->getCalledFunction();
+  if (!(MallocFn && MallocFn->hasName() && MallocFn->getName() == "malloc"))
+    return nullptr;
+
+  // Find all uses the malloc'd memory.
+  // We are looking for a "store" into a struct with the type being the Fortran
+  // descriptor type
+  for (auto user : MallocMem->users()) {
+    /// match: 5
+    auto *MallocStore = dyn_cast<StoreInst>(user);
+    if (!MallocStore)
+      continue;
+
+    auto *DescriptorGEP =
+        dyn_cast<GEPOperator>(MallocStore->getPointerOperand());
+    if (!DescriptorGEP)
+      continue;
+
+    // match: 5
+    auto DescriptorType =
+        dyn_cast<StructType>(DescriptorGEP->getSourceElementType());
+    if (!(DescriptorType && DescriptorType->hasName()))
+      continue;
+
+    Value *Descriptor = dyn_cast<Value>(DescriptorGEP->getPointerOperand());
+
+    if (!Descriptor)
+      continue;
+
+    if (!isFortranArrayDescriptor(Descriptor))
+      continue;
+
+    return Descriptor;
+  }
+
+  return nullptr;
+}
+
+Value *ScopBuilder::findFADAllocationInvisible(MemAccInst Inst) {
+  // match: 3
+  if (!isa<LoadInst>(Inst) && !isa<StoreInst>(Inst))
+    return nullptr;
+
+  Value *Slot = Inst.getPointerOperand();
+
+  LoadInst *MemLoad = nullptr;
+  // [match: 2]
+  if (auto *SlotGEP = dyn_cast<GetElementPtrInst>(Slot)) {
+    // match: 1
+    MemLoad = dyn_cast<LoadInst>(SlotGEP->getPointerOperand());
+  } else {
+    // match: 1
+    MemLoad = dyn_cast<LoadInst>(Slot);
+  }
+
+  if (!MemLoad)
+    return nullptr;
+
+  auto *BitcastOperator =
+      dyn_cast<BitCastOperator>(MemLoad->getPointerOperand());
+  if (!BitcastOperator)
+    return nullptr;
+
+  Value *Descriptor = dyn_cast<Value>(BitcastOperator->getOperand(0));
+  if (!Descriptor)
+    return nullptr;
+
+  if (!isFortranArrayDescriptor(Descriptor))
+    return nullptr;
+
+  return Descriptor;
+}
+
+bool ScopBuilder::buildAccessMultiDimFixed(MemAccInst Inst, ScopStmt *Stmt) {
+  Value *Val = Inst.getValueOperand();
+  Type *ElementType = Val->getType();
+  Value *Address = Inst.getPointerOperand();
+  const SCEV *AccessFunction =
+      SE.getSCEVAtScope(Address, LI.getLoopFor(Inst->getParent()));
+  const SCEVUnknown *BasePointer =
+      dyn_cast<SCEVUnknown>(SE.getPointerBase(AccessFunction));
+  enum MemoryAccess::AccessType AccType =
+      isa<LoadInst>(Inst) ? MemoryAccess::READ : MemoryAccess::MUST_WRITE;
+
+  if (auto *BitCast = dyn_cast<BitCastInst>(Address)) {
+    auto *Src = BitCast->getOperand(0);
+    auto *SrcTy = Src->getType();
+    auto *DstTy = BitCast->getType();
+    // Do not try to delinearize non-sized (opaque) pointers.
+    if ((SrcTy->isPointerTy() && !SrcTy->getPointerElementType()->isSized()) ||
+        (DstTy->isPointerTy() && !DstTy->getPointerElementType()->isSized())) {
+      return false;
+    }
+    if (SrcTy->isPointerTy() && DstTy->isPointerTy() &&
+        DL.getTypeAllocSize(SrcTy->getPointerElementType()) ==
+            DL.getTypeAllocSize(DstTy->getPointerElementType()))
+      Address = Src;
+  }
+
+  auto *GEP = dyn_cast<GetElementPtrInst>(Address);
+  if (!GEP)
+    return false;
+
+  std::vector<const SCEV *> Subscripts;
+  std::vector<int> Sizes;
+  std::tie(Subscripts, Sizes) = getIndexExpressionsFromGEP(GEP, SE);
+  auto *BasePtr = GEP->getOperand(0);
+
+  if (auto *BasePtrCast = dyn_cast<BitCastInst>(BasePtr))
+    BasePtr = BasePtrCast->getOperand(0);
+
+  // Check for identical base pointers to ensure that we do not miss index
+  // offsets that have been added before this GEP is applied.
+  if (BasePtr != BasePointer->getValue())
+    return false;
+
+  std::vector<const SCEV *> SizesSCEV;
+
+  const InvariantLoadsSetTy &ScopRIL = scop->getRequiredInvariantLoads();
+
+  Loop *SurroundingLoop = Stmt->getSurroundingLoop();
+  for (auto *Subscript : Subscripts) {
+    InvariantLoadsSetTy AccessILS;
+    if (!isAffineExpr(&scop->getRegion(), SurroundingLoop, Subscript, SE,
+                      &AccessILS))
+      return false;
+
+    for (LoadInst *LInst : AccessILS)
+      if (!ScopRIL.count(LInst))
+        return false;
+  }
+
+  if (Sizes.empty())
+    return false;
+
+  SizesSCEV.push_back(nullptr);
+
+  for (auto V : Sizes)
+    SizesSCEV.push_back(SE.getSCEV(
+        ConstantInt::get(IntegerType::getInt64Ty(BasePtr->getContext()), V)));
+
+  addArrayAccess(Stmt, Inst, AccType, BasePointer->getValue(), ElementType,
+                 true, Subscripts, SizesSCEV, Val);
+  return true;
+}
+
+bool ScopBuilder::buildAccessMultiDimParam(MemAccInst Inst, ScopStmt *Stmt) {
+  if (!PollyDelinearize)
+    return false;
+
+  Value *Address = Inst.getPointerOperand();
+  Value *Val = Inst.getValueOperand();
+  Type *ElementType = Val->getType();
+  unsigned ElementSize = DL.getTypeAllocSize(ElementType);
+  enum MemoryAccess::AccessType AccType =
+      isa<LoadInst>(Inst) ? MemoryAccess::READ : MemoryAccess::MUST_WRITE;
+
+  const SCEV *AccessFunction =
+      SE.getSCEVAtScope(Address, LI.getLoopFor(Inst->getParent()));
+  const SCEVUnknown *BasePointer =
+      dyn_cast<SCEVUnknown>(SE.getPointerBase(AccessFunction));
+
+  assert(BasePointer && "Could not find base pointer");
+
+  auto &InsnToMemAcc = scop->getInsnToMemAccMap();
+  auto AccItr = InsnToMemAcc.find(Inst);
+  if (AccItr == InsnToMemAcc.end())
+    return false;
+
+  std::vector<const SCEV *> Sizes = {nullptr};
+
+  Sizes.insert(Sizes.end(), AccItr->second.Shape->DelinearizedSizes.begin(),
+               AccItr->second.Shape->DelinearizedSizes.end());
+
+  // In case only the element size is contained in the 'Sizes' array, the
+  // access does not access a real multi-dimensional array. Hence, we allow
+  // the normal single-dimensional access construction to handle this.
+  if (Sizes.size() == 1)
+    return false;
+
+  // Remove the element size. This information is already provided by the
+  // ElementSize parameter. In case the element size of this access and the
+  // element size used for delinearization differs the delinearization is
+  // incorrect. Hence, we invalidate the scop.
+  //
+  // TODO: Handle delinearization with differing element sizes.
+  auto DelinearizedSize =
+      cast<SCEVConstant>(Sizes.back())->getAPInt().getSExtValue();
+  Sizes.pop_back();
+  if (ElementSize != DelinearizedSize)
+    scop->invalidate(DELINEARIZATION, Inst->getDebugLoc(), Inst->getParent());
+
+  addArrayAccess(Stmt, Inst, AccType, BasePointer->getValue(), ElementType,
+                 true, AccItr->second.DelinearizedSubscripts, Sizes, Val);
+  return true;
+}
+
+bool ScopBuilder::buildAccessMemIntrinsic(MemAccInst Inst, ScopStmt *Stmt) {
+  auto *MemIntr = dyn_cast_or_null<MemIntrinsic>(Inst);
+
+  if (MemIntr == nullptr)
+    return false;
+
+  auto *L = LI.getLoopFor(Inst->getParent());
+  auto *LengthVal = SE.getSCEVAtScope(MemIntr->getLength(), L);
+  assert(LengthVal);
+
+  // Check if the length val is actually affine or if we overapproximate it
+  InvariantLoadsSetTy AccessILS;
+  const InvariantLoadsSetTy &ScopRIL = scop->getRequiredInvariantLoads();
+
+  Loop *SurroundingLoop = Stmt->getSurroundingLoop();
+  bool LengthIsAffine = isAffineExpr(&scop->getRegion(), SurroundingLoop,
+                                     LengthVal, SE, &AccessILS);
+  for (LoadInst *LInst : AccessILS)
+    if (!ScopRIL.count(LInst))
+      LengthIsAffine = false;
+  if (!LengthIsAffine)
+    LengthVal = nullptr;
+
+  auto *DestPtrVal = MemIntr->getDest();
+  assert(DestPtrVal);
+
+  auto *DestAccFunc = SE.getSCEVAtScope(DestPtrVal, L);
+  assert(DestAccFunc);
+  // Ignore accesses to "NULL".
+  // TODO: We could use this to optimize the region further, e.g., intersect
+  //       the context with
+  //          isl_set_complement(isl_set_params(getDomain()))
+  //       as we know it would be undefined to execute this instruction anyway.
+  if (DestAccFunc->isZero())
+    return true;
+
+  auto *DestPtrSCEV = dyn_cast<SCEVUnknown>(SE.getPointerBase(DestAccFunc));
+  assert(DestPtrSCEV);
+  DestAccFunc = SE.getMinusSCEV(DestAccFunc, DestPtrSCEV);
+  addArrayAccess(Stmt, Inst, MemoryAccess::MUST_WRITE, DestPtrSCEV->getValue(),
+                 IntegerType::getInt8Ty(DestPtrVal->getContext()),
+                 LengthIsAffine, {DestAccFunc, LengthVal}, {nullptr},
+                 Inst.getValueOperand());
+
+  auto *MemTrans = dyn_cast<MemTransferInst>(MemIntr);
+  if (!MemTrans)
+    return true;
+
+  auto *SrcPtrVal = MemTrans->getSource();
+  assert(SrcPtrVal);
+
+  auto *SrcAccFunc = SE.getSCEVAtScope(SrcPtrVal, L);
+  assert(SrcAccFunc);
+  // Ignore accesses to "NULL".
+  // TODO: See above TODO
+  if (SrcAccFunc->isZero())
+    return true;
+
+  auto *SrcPtrSCEV = dyn_cast<SCEVUnknown>(SE.getPointerBase(SrcAccFunc));
+  assert(SrcPtrSCEV);
+  SrcAccFunc = SE.getMinusSCEV(SrcAccFunc, SrcPtrSCEV);
+  addArrayAccess(Stmt, Inst, MemoryAccess::READ, SrcPtrSCEV->getValue(),
+                 IntegerType::getInt8Ty(SrcPtrVal->getContext()),
+                 LengthIsAffine, {SrcAccFunc, LengthVal}, {nullptr},
+                 Inst.getValueOperand());
+
+  return true;
+}
+
+bool ScopBuilder::buildAccessCallInst(MemAccInst Inst, ScopStmt *Stmt) {
+  auto *CI = dyn_cast_or_null<CallInst>(Inst);
+
+  if (CI == nullptr)
+    return false;
+
+  if (CI->doesNotAccessMemory() || isIgnoredIntrinsic(CI))
+    return true;
+
+  bool ReadOnly = false;
+  auto *AF = SE.getConstant(IntegerType::getInt64Ty(CI->getContext()), 0);
+  auto *CalledFunction = CI->getCalledFunction();
+  switch (AA.getModRefBehavior(CalledFunction)) {
+  case FMRB_UnknownModRefBehavior:
+    llvm_unreachable("Unknown mod ref behaviour cannot be represented.");
+  case FMRB_DoesNotAccessMemory:
+    return true;
+  case FMRB_DoesNotReadMemory:
+  case FMRB_OnlyAccessesInaccessibleMem:
+  case FMRB_OnlyAccessesInaccessibleOrArgMem:
+    return false;
+  case FMRB_OnlyReadsMemory:
+    GlobalReads.emplace_back(Stmt, CI);
+    return true;
+  case FMRB_OnlyReadsArgumentPointees:
+    ReadOnly = true;
+  // Fall through
+  case FMRB_OnlyAccessesArgumentPointees: {
+    auto AccType = ReadOnly ? MemoryAccess::READ : MemoryAccess::MAY_WRITE;
+    Loop *L = LI.getLoopFor(Inst->getParent());
+    for (const auto &Arg : CI->arg_operands()) {
+      if (!Arg->getType()->isPointerTy())
+        continue;
+
+      auto *ArgSCEV = SE.getSCEVAtScope(Arg, L);
+      if (ArgSCEV->isZero())
+        continue;
+
+      auto *ArgBasePtr = cast<SCEVUnknown>(SE.getPointerBase(ArgSCEV));
+      addArrayAccess(Stmt, Inst, AccType, ArgBasePtr->getValue(),
+                     ArgBasePtr->getType(), false, {AF}, {nullptr}, CI);
+    }
+    return true;
+  }
+  }
+
+  return true;
+}
+
+void ScopBuilder::buildAccessSingleDim(MemAccInst Inst, ScopStmt *Stmt) {
+  Value *Address = Inst.getPointerOperand();
+  Value *Val = Inst.getValueOperand();
+  Type *ElementType = Val->getType();
+  enum MemoryAccess::AccessType AccType =
+      isa<LoadInst>(Inst) ? MemoryAccess::READ : MemoryAccess::MUST_WRITE;
+
+  const SCEV *AccessFunction =
+      SE.getSCEVAtScope(Address, LI.getLoopFor(Inst->getParent()));
+  const SCEVUnknown *BasePointer =
+      dyn_cast<SCEVUnknown>(SE.getPointerBase(AccessFunction));
+
+  assert(BasePointer && "Could not find base pointer");
+  AccessFunction = SE.getMinusSCEV(AccessFunction, BasePointer);
+
+  // Check if the access depends on a loop contained in a non-affine subregion.
+  bool isVariantInNonAffineLoop = false;
+  SetVector<const Loop *> Loops;
+  findLoops(AccessFunction, Loops);
+  for (const Loop *L : Loops)
+    if (Stmt->contains(L)) {
+      isVariantInNonAffineLoop = true;
+      break;
+    }
+
+  InvariantLoadsSetTy AccessILS;
+
+  Loop *SurroundingLoop = Stmt->getSurroundingLoop();
+  bool IsAffine = !isVariantInNonAffineLoop &&
+                  isAffineExpr(&scop->getRegion(), SurroundingLoop,
+                               AccessFunction, SE, &AccessILS);
+
+  const InvariantLoadsSetTy &ScopRIL = scop->getRequiredInvariantLoads();
+  for (LoadInst *LInst : AccessILS)
+    if (!ScopRIL.count(LInst))
+      IsAffine = false;
+
+  if (!IsAffine && AccType == MemoryAccess::MUST_WRITE)
+    AccType = MemoryAccess::MAY_WRITE;
+
+  addArrayAccess(Stmt, Inst, AccType, BasePointer->getValue(), ElementType,
+                 IsAffine, {AccessFunction}, {nullptr}, Val);
+}
+
+void ScopBuilder::buildMemoryAccess(MemAccInst Inst, ScopStmt *Stmt) {
+  if (buildAccessMemIntrinsic(Inst, Stmt))
+    return;
+
+  if (buildAccessCallInst(Inst, Stmt))
+    return;
+
+  if (buildAccessMultiDimFixed(Inst, Stmt))
+    return;
+
+  if (buildAccessMultiDimParam(Inst, Stmt))
+    return;
+
+  buildAccessSingleDim(Inst, Stmt);
+}
+
+void ScopBuilder::buildAccessFunctions() {
+  for (auto &Stmt : *scop) {
+    if (Stmt.isBlockStmt()) {
+      buildAccessFunctions(&Stmt, *Stmt.getBasicBlock());
+      continue;
+    }
+
+    Region *R = Stmt.getRegion();
+    for (BasicBlock *BB : R->blocks())
+      buildAccessFunctions(&Stmt, *BB, R);
+  }
+
+  // Build write accesses for values that are used after the SCoP.
+  // The instructions defining them might be synthesizable and therefore not
+  // contained in any statement, hence we iterate over the original instructions
+  // to identify all escaping values.
+  for (BasicBlock *BB : scop->getRegion().blocks()) {
+    for (Instruction &Inst : *BB)
+      buildEscapingDependences(&Inst);
+  }
+}
+
+bool ScopBuilder::shouldModelInst(Instruction *Inst, Loop *L) {
+  return !isa<TerminatorInst>(Inst) && !isIgnoredIntrinsic(Inst) &&
+         !canSynthesize(Inst, *scop, &SE, L);
+}
+
+void ScopBuilder::buildSequentialBlockStmts(BasicBlock *BB, bool SplitOnStore) {
+  Loop *SurroundingLoop = LI.getLoopFor(BB);
+
+  int Count = 0;
+  std::vector<Instruction *> Instructions;
+  for (Instruction &Inst : *BB) {
+    if (shouldModelInst(&Inst, SurroundingLoop))
+      Instructions.push_back(&Inst);
+    if (Inst.getMetadata("polly_split_after") ||
+        (SplitOnStore && isa<StoreInst>(Inst))) {
+      scop->addScopStmt(BB, SurroundingLoop, Instructions, Count);
+      Count++;
+      Instructions.clear();
+    }
+  }
+
+  scop->addScopStmt(BB, SurroundingLoop, Instructions, Count);
+}
+
+/// Is @p Inst an ordered instruction?
+///
+/// An unordered instruction is an instruction, such that a sequence of
+/// unordered instructions can be permuted without changing semantics. Any
+/// instruction for which this is not always the case is ordered.
+static bool isOrderedInstruction(Instruction *Inst) {
+  return Inst->mayHaveSideEffects() || Inst->mayReadOrWriteMemory();
+}
+
+/// Join instructions to the same statement if one uses the scalar result of the
+/// other.
+static void joinOperandTree(EquivalenceClasses<Instruction *> &UnionFind,
+                            ArrayRef<Instruction *> ModeledInsts) {
+  for (Instruction *Inst : ModeledInsts) {
+    if (isa<PHINode>(Inst))
+      continue;
+
+    for (Use &Op : Inst->operands()) {
+      Instruction *OpInst = dyn_cast<Instruction>(Op.get());
+      if (!OpInst)
+        continue;
+
+      // Check if OpInst is in the BB and is a modeled instruction.
+      auto OpVal = UnionFind.findValue(OpInst);
+      if (OpVal == UnionFind.end())
+        continue;
+
+      UnionFind.unionSets(Inst, OpInst);
+    }
+  }
+}
+
+/// Join instructions that are used as incoming value in successor PHIs into the
+/// epilogue.
+static void
+joinIncomingPHIValuesIntoEpilogue(EquivalenceClasses<Instruction *> &UnionFind,
+                                  ArrayRef<Instruction *> ModeledInsts,
+                                  BasicBlock *BB) {
+  for (BasicBlock *Succ : successors(BB)) {
+    for (Instruction &SuccInst : *Succ) {
+      PHINode *SuccPHI = dyn_cast<PHINode>(&SuccInst);
+      if (!SuccPHI)
+        break;
+
+      Value *IncomingVal = SuccPHI->getIncomingValueForBlock(BB);
+      Instruction *IncomingInst = dyn_cast<Instruction>(IncomingVal);
+      if (!IncomingInst)
+        continue;
+      if (IncomingInst->getParent() != BB)
+        continue;
+      if (UnionFind.findValue(IncomingInst) == UnionFind.end())
+        continue;
+
+      UnionFind.unionSets(nullptr, IncomingInst);
+    }
+  }
+}
+
+/// Ensure that the order of ordered instructions does not change.
+///
+/// If we encounter an ordered instruction enclosed in instructions belonging to
+/// a different statement (which might as well contain ordered instructions, but
+/// this is not tested here), join them.
+static void
+joinOrderedInstructions(EquivalenceClasses<Instruction *> &UnionFind,
+                        ArrayRef<Instruction *> ModeledInsts) {
+  SetVector<Instruction *> SeenLeaders;
+  for (Instruction *Inst : ModeledInsts) {
+    if (!isOrderedInstruction(Inst))
+      continue;
+
+    Instruction *Leader = UnionFind.getLeaderValue(Inst);
+    bool Inserted = SeenLeaders.insert(Leader);
+    if (Inserted)
+      continue;
+
+    // Merge statements to close holes. Say, we have already seen statements A
+    // and B, in this order. Then we see an instruction of A again and we would
+    // see the pattern "A B A". This function joins all statements until the
+    // only seen occurrence of A.
+    for (Instruction *Prev : reverse(SeenLeaders)) {
+      // Items added to 'SeenLeaders' are leaders, but may have lost their
+      // leadership status when merged into another statement.
+      Instruction *PrevLeader = UnionFind.getLeaderValue(SeenLeaders.back());
+      if (PrevLeader == Leader)
+        break;
+      UnionFind.unionSets(Prev, Leader);
+    }
+  }
+}
+
+/// Also ensure that the epilogue is the last statement relative to all ordered
+/// instructions.
+///
+/// This is basically joinOrderedInstructions() but using the epilogue as
+/// 'ordered instruction'.
+static void joinAllAfterEpilogue(EquivalenceClasses<Instruction *> &UnionFind,
+                                 ArrayRef<Instruction *> ModeledInsts) {
+  bool EpilogueSeen = false;
+  for (Instruction *Inst : ModeledInsts) {
+    auto PHIWritesLeader = UnionFind.findLeader(nullptr);
+    auto InstLeader = UnionFind.findLeader(Inst);
+
+    if (PHIWritesLeader == InstLeader)
+      EpilogueSeen = true;
+
+    if (!isOrderedInstruction(Inst))
+      continue;
+
+    if (EpilogueSeen)
+      UnionFind.unionSets(PHIWritesLeader, InstLeader);
+  }
+}
+
+void ScopBuilder::buildEqivClassBlockStmts(BasicBlock *BB) {
+  Loop *L = LI.getLoopFor(BB);
+
+  // Extracting out modeled instructions saves us from checking
+  // shouldModelInst() repeatedly.
+  SmallVector<Instruction *, 32> ModeledInsts;
+  EquivalenceClasses<Instruction *> UnionFind;
+  for (Instruction &Inst : *BB) {
+    if (!shouldModelInst(&Inst, L))
+      continue;
+    ModeledInsts.push_back(&Inst);
+    UnionFind.insert(&Inst);
+  }
+
+  // 'nullptr' represents the last statement for a basic block. It contains no
+  // instructions, but holds the PHI write accesses for successor basic blocks.
+  // If a PHI has an incoming value defined in this BB, it can also be merged
+  // with other statements.
+  // TODO: We wouldn't need this if we would add PHIWrites into the statement
+  // that defines the incoming value (if in the BB) instead of always the last,
+  // so we could unconditionally always add a last statement.
+  UnionFind.insert(nullptr);
+
+  joinOperandTree(UnionFind, ModeledInsts);
+  joinIncomingPHIValuesIntoEpilogue(UnionFind, ModeledInsts, BB);
+  joinOrderedInstructions(UnionFind, ModeledInsts);
+  joinAllAfterEpilogue(UnionFind, ModeledInsts);
+
+  // The list of instructions for statement (statement represented by the leader
+  // instruction). The order of statements instructions is reversed such that
+  // the epilogue is first. This makes it easier to ensure that the epilogue is
+  // the last statement.
+  MapVector<Instruction *, std::vector<Instruction *>> LeaderToInstList;
+
+  // Ensure that the epilogue is last.
+  LeaderToInstList[nullptr];
+
+  // Collect the instructions of all leaders. UnionFind's member iterator
+  // unfortunately are not in any specific order.
+  for (Instruction &Inst : reverse(*BB)) {
+    auto LeaderIt = UnionFind.findLeader(&Inst);
+    if (LeaderIt == UnionFind.member_end())
+      continue;
+
+    std::vector<Instruction *> &InstList = LeaderToInstList[*LeaderIt];
+    InstList.push_back(&Inst);
+  }
+
+  // Finally build the statements.
+  int Count = 0;
+  for (auto &Instructions : reverse(LeaderToInstList)) {
+    std::vector<Instruction *> &InstList = Instructions.second;
+    std::reverse(InstList.begin(), InstList.end());
+    scop->addScopStmt(BB, L, std::move(InstList), Count);
+    Count += 1;
+  }
+}
+
+void ScopBuilder::buildStmts(Region &SR) {
+  if (scop->isNonAffineSubRegion(&SR)) {
+    std::vector<Instruction *> Instructions;
+    Loop *SurroundingLoop =
+        getFirstNonBoxedLoopFor(SR.getEntry(), LI, scop->getBoxedLoops());
+    for (Instruction &Inst : *SR.getEntry())
+      if (shouldModelInst(&Inst, SurroundingLoop))
+        Instructions.push_back(&Inst);
+    scop->addScopStmt(&SR, SurroundingLoop, Instructions);
+    return;
+  }
+
+  for (auto I = SR.element_begin(), E = SR.element_end(); I != E; ++I)
+    if (I->isSubRegion())
+      buildStmts(*I->getNodeAs<Region>());
+    else {
+      BasicBlock *BB = I->getNodeAs<BasicBlock>();
+      switch (StmtGranularity) {
+      case GranularityChoice::BasicBlocks:
+        buildSequentialBlockStmts(BB);
+        break;
+      case GranularityChoice::ScalarIndependence:
+        buildEqivClassBlockStmts(BB);
+        break;
+      case GranularityChoice::Stores:
+        buildSequentialBlockStmts(BB, true);
+        break;
+      }
+    }
+}
+
+void ScopBuilder::buildAccessFunctions(ScopStmt *Stmt, BasicBlock &BB,
+                                       Region *NonAffineSubRegion) {
+  assert(
+      Stmt &&
+      "The exit BB is the only one that cannot be represented by a statement");
+  assert(Stmt->represents(&BB));
+
+  // We do not build access functions for error blocks, as they may contain
+  // instructions we can not model.
+  if (isErrorBlock(BB, scop->getRegion(), LI, DT))
+    return;
+
+  auto BuildAccessesForInst = [this, Stmt,
+                               NonAffineSubRegion](Instruction *Inst) {
+    PHINode *PHI = dyn_cast<PHINode>(Inst);
+    if (PHI)
+      buildPHIAccesses(Stmt, PHI, NonAffineSubRegion, false);
+
+    if (auto MemInst = MemAccInst::dyn_cast(*Inst)) {
+      assert(Stmt && "Cannot build access function in non-existing statement");
+      buildMemoryAccess(MemInst, Stmt);
+    }
+
+    // PHI nodes have already been modeled above and TerminatorInsts that are
+    // not part of a non-affine subregion are fully modeled and regenerated
+    // from the polyhedral domains. Hence, they do not need to be modeled as
+    // explicit data dependences.
+    if (!PHI)
+      buildScalarDependences(Stmt, Inst);
+  };
+
+  const InvariantLoadsSetTy &RIL = scop->getRequiredInvariantLoads();
+  bool IsEntryBlock = (Stmt->getEntryBlock() == &BB);
+  if (IsEntryBlock) {
+    for (Instruction *Inst : Stmt->getInstructions())
+      BuildAccessesForInst(Inst);
+    if (Stmt->isRegionStmt())
+      BuildAccessesForInst(BB.getTerminator());
+  } else {
+    for (Instruction &Inst : BB) {
+      if (isIgnoredIntrinsic(&Inst))
+        continue;
+
+      // Invariant loads already have been processed.
+      if (isa<LoadInst>(Inst) && RIL.count(cast<LoadInst>(&Inst)))
+        continue;
+
+      BuildAccessesForInst(&Inst);
+    }
+  }
+}
+
+MemoryAccess *ScopBuilder::addMemoryAccess(
+    ScopStmt *Stmt, Instruction *Inst, MemoryAccess::AccessType AccType,
+    Value *BaseAddress, Type *ElementType, bool Affine, Value *AccessValue,
+    ArrayRef<const SCEV *> Subscripts, ArrayRef<const SCEV *> Sizes,
+    MemoryKind Kind) {
+  bool isKnownMustAccess = false;
+
+  // Accesses in single-basic block statements are always executed.
+  if (Stmt->isBlockStmt())
+    isKnownMustAccess = true;
+
+  if (Stmt->isRegionStmt()) {
+    // Accesses that dominate the exit block of a non-affine region are always
+    // executed. In non-affine regions there may exist MemoryKind::Values that
+    // do not dominate the exit. MemoryKind::Values will always dominate the
+    // exit and MemoryKind::PHIs only if there is at most one PHI_WRITE in the
+    // non-affine region.
+    if (Inst && DT.dominates(Inst->getParent(), Stmt->getRegion()->getExit()))
+      isKnownMustAccess = true;
+  }
+
+  // Non-affine PHI writes do not "happen" at a particular instruction, but
+  // after exiting the statement. Therefore they are guaranteed to execute and
+  // overwrite the old value.
+  if (Kind == MemoryKind::PHI || Kind == MemoryKind::ExitPHI)
+    isKnownMustAccess = true;
+
+  if (!isKnownMustAccess && AccType == MemoryAccess::MUST_WRITE)
+    AccType = MemoryAccess::MAY_WRITE;
+
+  auto *Access = new MemoryAccess(Stmt, Inst, AccType, BaseAddress, ElementType,
+                                  Affine, Subscripts, Sizes, AccessValue, Kind);
+
+  scop->addAccessFunction(Access);
+  Stmt->addAccess(Access);
+  return Access;
+}
+
+void ScopBuilder::addArrayAccess(ScopStmt *Stmt, MemAccInst MemAccInst,
+                                 MemoryAccess::AccessType AccType,
+                                 Value *BaseAddress, Type *ElementType,
+                                 bool IsAffine,
+                                 ArrayRef<const SCEV *> Subscripts,
+                                 ArrayRef<const SCEV *> Sizes,
+                                 Value *AccessValue) {
+  ArrayBasePointers.insert(BaseAddress);
+  auto *MemAccess = addMemoryAccess(Stmt, MemAccInst, AccType, BaseAddress,
+                                    ElementType, IsAffine, AccessValue,
+                                    Subscripts, Sizes, MemoryKind::Array);
+
+  if (!DetectFortranArrays)
+    return;
+
+  if (Value *FAD = findFADAllocationInvisible(MemAccInst))
+    MemAccess->setFortranArrayDescriptor(FAD);
+  else if (Value *FAD = findFADAllocationVisible(MemAccInst))
+    MemAccess->setFortranArrayDescriptor(FAD);
+}
+
+void ScopBuilder::ensureValueWrite(Instruction *Inst) {
+  // Find the statement that defines the value of Inst. That statement has to
+  // write the value to make it available to those statements that read it.
+  ScopStmt *Stmt = scop->getStmtFor(Inst);
+
+  // It is possible that the value is synthesizable within a loop (such that it
+  // is not part of any statement), but not after the loop (where you need the
+  // number of loop round-trips to synthesize it). In LCSSA-form a PHI node will
+  // avoid this. In case the IR has no such PHI, use the last statement (where
+  // the value is synthesizable) to write the value.
+  if (!Stmt)
+    Stmt = scop->getLastStmtFor(Inst->getParent());
+
+  // Inst not defined within this SCoP.
+  if (!Stmt)
+    return;
+
+  // Do not process further if the instruction is already written.
+  if (Stmt->lookupValueWriteOf(Inst))
+    return;
+
+  addMemoryAccess(Stmt, Inst, MemoryAccess::MUST_WRITE, Inst, Inst->getType(),
+                  true, Inst, ArrayRef<const SCEV *>(),
+                  ArrayRef<const SCEV *>(), MemoryKind::Value);
+}
+
+void ScopBuilder::ensureValueRead(Value *V, ScopStmt *UserStmt) {
+  // TODO: Make ScopStmt::ensureValueRead(Value*) offer the same functionality
+  // to be able to replace this one. Currently, there is a split responsibility.
+  // In a first step, the MemoryAccess is created, but without the
+  // AccessRelation. In the second step by ScopStmt::buildAccessRelations(), the
+  // AccessRelation is created. At least for scalar accesses, there is no new
+  // information available at ScopStmt::buildAccessRelations(), so we could
+  // create the AccessRelation right away. This is what
+  // ScopStmt::ensureValueRead(Value*) does.
+
+  auto *Scope = UserStmt->getSurroundingLoop();
+  auto VUse = VirtualUse::create(scop.get(), UserStmt, Scope, V, false);
+  switch (VUse.getKind()) {
+  case VirtualUse::Constant:
+  case VirtualUse::Block:
+  case VirtualUse::Synthesizable:
+  case VirtualUse::Hoisted:
+  case VirtualUse::Intra:
+    // Uses of these kinds do not need a MemoryAccess.
+    break;
+
+  case VirtualUse::ReadOnly:
+    // Add MemoryAccess for invariant values only if requested.
+    if (!ModelReadOnlyScalars)
+      break;
+
+    LLVM_FALLTHROUGH;
+  case VirtualUse::Inter:
+
+    // Do not create another MemoryAccess for reloading the value if one already
+    // exists.
+    if (UserStmt->lookupValueReadOf(V))
+      break;
+
+    addMemoryAccess(UserStmt, nullptr, MemoryAccess::READ, V, V->getType(),
+                    true, V, ArrayRef<const SCEV *>(), ArrayRef<const SCEV *>(),
+                    MemoryKind::Value);
+
+    // Inter-statement uses need to write the value in their defining statement.
+    if (VUse.isInter())
+      ensureValueWrite(cast<Instruction>(V));
+    break;
+  }
+}
+
+void ScopBuilder::ensurePHIWrite(PHINode *PHI, ScopStmt *IncomingStmt,
+                                 BasicBlock *IncomingBlock,
+                                 Value *IncomingValue, bool IsExitBlock) {
+  // As the incoming block might turn out to be an error statement ensure we
+  // will create an exit PHI SAI object. It is needed during code generation
+  // and would be created later anyway.
+  if (IsExitBlock)
+    scop->getOrCreateScopArrayInfo(PHI, PHI->getType(), {},
+                                   MemoryKind::ExitPHI);
+
+  // This is possible if PHI is in the SCoP's entry block. The incoming blocks
+  // from outside the SCoP's region have no statement representation.
+  if (!IncomingStmt)
+    return;
+
+  // Take care for the incoming value being available in the incoming block.
+  // This must be done before the check for multiple PHI writes because multiple
+  // exiting edges from subregion each can be the effective written value of the
+  // subregion. As such, all of them must be made available in the subregion
+  // statement.
+  ensureValueRead(IncomingValue, IncomingStmt);
+
+  // Do not add more than one MemoryAccess per PHINode and ScopStmt.
+  if (MemoryAccess *Acc = IncomingStmt->lookupPHIWriteOf(PHI)) {
+    assert(Acc->getAccessInstruction() == PHI);
+    Acc->addIncoming(IncomingBlock, IncomingValue);
+    return;
+  }
+
+  MemoryAccess *Acc = addMemoryAccess(
+      IncomingStmt, PHI, MemoryAccess::MUST_WRITE, PHI, PHI->getType(), true,
+      PHI, ArrayRef<const SCEV *>(), ArrayRef<const SCEV *>(),
+      IsExitBlock ? MemoryKind::ExitPHI : MemoryKind::PHI);
+  assert(Acc);
+  Acc->addIncoming(IncomingBlock, IncomingValue);
+}
+
+void ScopBuilder::addPHIReadAccess(ScopStmt *PHIStmt, PHINode *PHI) {
+  addMemoryAccess(PHIStmt, PHI, MemoryAccess::READ, PHI, PHI->getType(), true,
+                  PHI, ArrayRef<const SCEV *>(), ArrayRef<const SCEV *>(),
+                  MemoryKind::PHI);
+}
+
+void ScopBuilder::buildDomain(ScopStmt &Stmt) {
+  isl::id Id = isl::id::alloc(scop->getIslCtx(), Stmt.getBaseName(), &Stmt);
+
+  Stmt.Domain = scop->getDomainConditions(&Stmt);
+  Stmt.Domain = Stmt.Domain.set_tuple_id(Id);
+}
+
+void ScopBuilder::collectSurroundingLoops(ScopStmt &Stmt) {
+  isl::set Domain = Stmt.getDomain();
+  for (unsigned u = 0, e = Domain.dim(isl::dim::set); u < e; u++) {
+    isl::id DimId = Domain.get_dim_id(isl::dim::set, u);
+    Stmt.NestLoops.push_back(static_cast<Loop *>(DimId.get_user()));
+  }
+}
+
+/// Return the reduction type for a given binary operator.
+static MemoryAccess::ReductionType getReductionType(const BinaryOperator *BinOp,
+                                                    const Instruction *Load) {
+  if (!BinOp)
+    return MemoryAccess::RT_NONE;
+  switch (BinOp->getOpcode()) {
+  case Instruction::FAdd:
+    if (!BinOp->isFast())
+      return MemoryAccess::RT_NONE;
+    // Fall through
+  case Instruction::Add:
+    return MemoryAccess::RT_ADD;
+  case Instruction::Or:
+    return MemoryAccess::RT_BOR;
+  case Instruction::Xor:
+    return MemoryAccess::RT_BXOR;
+  case Instruction::And:
+    return MemoryAccess::RT_BAND;
+  case Instruction::FMul:
+    if (!BinOp->isFast())
+      return MemoryAccess::RT_NONE;
+    // Fall through
+  case Instruction::Mul:
+    if (DisableMultiplicativeReductions)
+      return MemoryAccess::RT_NONE;
+    return MemoryAccess::RT_MUL;
+  default:
+    return MemoryAccess::RT_NONE;
+  }
+}
+
+void ScopBuilder::checkForReductions(ScopStmt &Stmt) {
+  SmallVector<MemoryAccess *, 2> Loads;
+  SmallVector<std::pair<MemoryAccess *, MemoryAccess *>, 4> Candidates;
+
+  // First collect candidate load-store reduction chains by iterating over all
+  // stores and collecting possible reduction loads.
+  for (MemoryAccess *StoreMA : Stmt) {
+    if (StoreMA->isRead())
+      continue;
+
+    Loads.clear();
+    collectCandidateReductionLoads(StoreMA, Loads);
+    for (MemoryAccess *LoadMA : Loads)
+      Candidates.push_back(std::make_pair(LoadMA, StoreMA));
+  }
+
+  // Then check each possible candidate pair.
+  for (const auto &CandidatePair : Candidates) {
+    bool Valid = true;
+    isl::map LoadAccs = CandidatePair.first->getAccessRelation();
+    isl::map StoreAccs = CandidatePair.second->getAccessRelation();
+
+    // Skip those with obviously unequal base addresses.
+    if (!LoadAccs.has_equal_space(StoreAccs)) {
+      continue;
+    }
+
+    // And check if the remaining for overlap with other memory accesses.
+    isl::map AllAccsRel = LoadAccs.unite(StoreAccs);
+    AllAccsRel = AllAccsRel.intersect_domain(Stmt.getDomain());
+    isl::set AllAccs = AllAccsRel.range();
+
+    for (MemoryAccess *MA : Stmt) {
+      if (MA == CandidatePair.first || MA == CandidatePair.second)
+        continue;
+
+      isl::map AccRel =
+          MA->getAccessRelation().intersect_domain(Stmt.getDomain());
+      isl::set Accs = AccRel.range();
+
+      if (AllAccs.has_equal_space(Accs)) {
+        isl::set OverlapAccs = Accs.intersect(AllAccs);
+        Valid = Valid && OverlapAccs.is_empty();
+      }
+    }
+
+    if (!Valid)
+      continue;
+
+    const LoadInst *Load =
+        dyn_cast<const LoadInst>(CandidatePair.first->getAccessInstruction());
+    MemoryAccess::ReductionType RT =
+        getReductionType(dyn_cast<BinaryOperator>(Load->user_back()), Load);
+
+    // If no overlapping access was found we mark the load and store as
+    // reduction like.
+    CandidatePair.first->markAsReductionLike(RT);
+    CandidatePair.second->markAsReductionLike(RT);
+  }
+}
+
+void ScopBuilder::collectCandidateReductionLoads(
+    MemoryAccess *StoreMA, SmallVectorImpl<MemoryAccess *> &Loads) {
+  ScopStmt *Stmt = StoreMA->getStatement();
+
+  auto *Store = dyn_cast<StoreInst>(StoreMA->getAccessInstruction());
+  if (!Store)
+    return;
+
+  // Skip if there is not one binary operator between the load and the store
+  auto *BinOp = dyn_cast<BinaryOperator>(Store->getValueOperand());
+  if (!BinOp)
+    return;
+
+  // Skip if the binary operators has multiple uses
+  if (BinOp->getNumUses() != 1)
+    return;
+
+  // Skip if the opcode of the binary operator is not commutative/associative
+  if (!BinOp->isCommutative() || !BinOp->isAssociative())
+    return;
+
+  // Skip if the binary operator is outside the current SCoP
+  if (BinOp->getParent() != Store->getParent())
+    return;
+
+  // Skip if it is a multiplicative reduction and we disabled them
+  if (DisableMultiplicativeReductions &&
+      (BinOp->getOpcode() == Instruction::Mul ||
+       BinOp->getOpcode() == Instruction::FMul))
+    return;
+
+  // Check the binary operator operands for a candidate load
+  auto *PossibleLoad0 = dyn_cast<LoadInst>(BinOp->getOperand(0));
+  auto *PossibleLoad1 = dyn_cast<LoadInst>(BinOp->getOperand(1));
+  if (!PossibleLoad0 && !PossibleLoad1)
+    return;
+
+  // A load is only a candidate if it cannot escape (thus has only this use)
+  if (PossibleLoad0 && PossibleLoad0->getNumUses() == 1)
+    if (PossibleLoad0->getParent() == Store->getParent())
+      Loads.push_back(&Stmt->getArrayAccessFor(PossibleLoad0));
+  if (PossibleLoad1 && PossibleLoad1->getNumUses() == 1)
+    if (PossibleLoad1->getParent() == Store->getParent())
+      Loads.push_back(&Stmt->getArrayAccessFor(PossibleLoad1));
+}
+
+void ScopBuilder::buildAccessRelations(ScopStmt &Stmt) {
+  for (MemoryAccess *Access : Stmt.MemAccs) {
+    Type *ElementType = Access->getElementType();
+
+    MemoryKind Ty;
+    if (Access->isPHIKind())
+      Ty = MemoryKind::PHI;
+    else if (Access->isExitPHIKind())
+      Ty = MemoryKind::ExitPHI;
+    else if (Access->isValueKind())
+      Ty = MemoryKind::Value;
+    else
+      Ty = MemoryKind::Array;
+
+    auto *SAI = scop->getOrCreateScopArrayInfo(Access->getOriginalBaseAddr(),
+                                               ElementType, Access->Sizes, Ty);
+    Access->buildAccessRelation(SAI);
+    scop->addAccessData(Access);
+  }
+}
+
+#ifndef NDEBUG
+static void verifyUse(Scop *S, Use &Op, LoopInfo &LI) {
+  auto PhysUse = VirtualUse::create(S, Op, &LI, false);
+  auto VirtUse = VirtualUse::create(S, Op, &LI, true);
+  assert(PhysUse.getKind() == VirtUse.getKind());
+}
+
+/// Check the consistency of every statement's MemoryAccesses.
+///
+/// The check is carried out by expecting the "physical" kind of use (derived
+/// from the BasicBlocks instructions resides in) to be same as the "virtual"
+/// kind of use (derived from a statement's MemoryAccess).
+///
+/// The "physical" uses are taken by ensureValueRead to determine whether to
+/// create MemoryAccesses. When done, the kind of scalar access should be the
+/// same no matter which way it was derived.
+///
+/// The MemoryAccesses might be changed by later SCoP-modifying passes and hence
+/// can intentionally influence on the kind of uses (not corresponding to the
+/// "physical" anymore, hence called "virtual"). The CodeGenerator therefore has
+/// to pick up the virtual uses. But here in the code generator, this has not
+/// happened yet, such that virtual and physical uses are equivalent.
+static void verifyUses(Scop *S, LoopInfo &LI, DominatorTree &DT) {
+  for (auto *BB : S->getRegion().blocks()) {
+    for (auto &Inst : *BB) {
+      auto *Stmt = S->getStmtFor(&Inst);
+      if (!Stmt)
+        continue;
+
+      if (isIgnoredIntrinsic(&Inst))
+        continue;
+
+      // Branch conditions are encoded in the statement domains.
+      if (isa<TerminatorInst>(&Inst) && Stmt->isBlockStmt())
+        continue;
+
+      // Verify all uses.
+      for (auto &Op : Inst.operands())
+        verifyUse(S, Op, LI);
+
+      // Stores do not produce values used by other statements.
+      if (isa<StoreInst>(Inst))
+        continue;
+
+      // For every value defined in the block, also check that a use of that
+      // value in the same statement would not be an inter-statement use. It can
+      // still be synthesizable or load-hoisted, but these kind of instructions
+      // are not directly copied in code-generation.
+      auto VirtDef =
+          VirtualUse::create(S, Stmt, Stmt->getSurroundingLoop(), &Inst, true);
+      assert(VirtDef.getKind() == VirtualUse::Synthesizable ||
+             VirtDef.getKind() == VirtualUse::Intra ||
+             VirtDef.getKind() == VirtualUse::Hoisted);
+    }
+  }
+
+  if (S->hasSingleExitEdge())
+    return;
+
+  // PHINodes in the SCoP region's exit block are also uses to be checked.
+  if (!S->getRegion().isTopLevelRegion()) {
+    for (auto &Inst : *S->getRegion().getExit()) {
+      if (!isa<PHINode>(Inst))
+        break;
+
+      for (auto &Op : Inst.operands())
+        verifyUse(S, Op, LI);
+    }
+  }
+}
+#endif
+
+/// Return the block that is the representing block for @p RN.
+static inline BasicBlock *getRegionNodeBasicBlock(RegionNode *RN) {
+  return RN->isSubRegion() ? RN->getNodeAs<Region>()->getEntry()
+                           : RN->getNodeAs<BasicBlock>();
+}
+
+void ScopBuilder::buildScop(Region &R, AssumptionCache &AC,
+                            OptimizationRemarkEmitter &ORE) {
+  scop.reset(new Scop(R, SE, LI, DT, *SD.getDetectionContext(&R), ORE));
+
+  buildStmts(R);
+
+  // Create all invariant load instructions first. These are categorized as
+  // 'synthesizable', therefore are not part of any ScopStmt but need to be
+  // created somewhere.
+  const InvariantLoadsSetTy &RIL = scop->getRequiredInvariantLoads();
+  for (BasicBlock *BB : scop->getRegion().blocks()) {
+    if (isErrorBlock(*BB, scop->getRegion(), LI, DT))
+      continue;
+
+    for (Instruction &Inst : *BB) {
+      LoadInst *Load = dyn_cast<LoadInst>(&Inst);
+      if (!Load)
+        continue;
+
+      if (!RIL.count(Load))
+        continue;
+
+      // Invariant loads require a MemoryAccess to be created in some statement.
+      // It is not important to which statement the MemoryAccess is added
+      // because it will later be removed from the ScopStmt again. We chose the
+      // first statement of the basic block the LoadInst is in.
+      ArrayRef<ScopStmt *> List = scop->getStmtListFor(BB);
+      assert(!List.empty());
+      ScopStmt *RILStmt = List.front();
+      buildMemoryAccess(Load, RILStmt);
+    }
+  }
+  buildAccessFunctions();
+
+  // In case the region does not have an exiting block we will later (during
+  // code generation) split the exit block. This will move potential PHI nodes
+  // from the current exit block into the new region exiting block. Hence, PHI
+  // nodes that are at this point not part of the region will be.
+  // To handle these PHI nodes later we will now model their operands as scalar
+  // accesses. Note that we do not model anything in the exit block if we have
+  // an exiting block in the region, as there will not be any splitting later.
+  if (!R.isTopLevelRegion() && !scop->hasSingleExitEdge()) {
+    for (Instruction &Inst : *R.getExit()) {
+      PHINode *PHI = dyn_cast<PHINode>(&Inst);
+      if (!PHI)
+        break;
+
+      buildPHIAccesses(nullptr, PHI, nullptr, true);
+    }
+  }
+
+  // Create memory accesses for global reads since all arrays are now known.
+  auto *AF = SE.getConstant(IntegerType::getInt64Ty(SE.getContext()), 0);
+  for (auto GlobalReadPair : GlobalReads) {
+    ScopStmt *GlobalReadStmt = GlobalReadPair.first;
+    Instruction *GlobalRead = GlobalReadPair.second;
+    for (auto *BP : ArrayBasePointers)
+      addArrayAccess(GlobalReadStmt, MemAccInst(GlobalRead), MemoryAccess::READ,
+                     BP, BP->getType(), false, {AF}, {nullptr}, GlobalRead);
+  }
+
+  scop->buildInvariantEquivalenceClasses();
+
+  /// A map from basic blocks to their invalid domains.
+  DenseMap<BasicBlock *, isl::set> InvalidDomainMap;
+
+  if (!scop->buildDomains(&R, DT, LI, InvalidDomainMap)) {
+    DEBUG(dbgs() << "Bailing-out because buildDomains encountered problems\n");
+    return;
+  }
+
+  scop->addUserAssumptions(AC, DT, LI, InvalidDomainMap);
+
+  // Initialize the invalid domain.
+  for (ScopStmt &Stmt : scop->Stmts)
+    if (Stmt.isBlockStmt())
+      Stmt.setInvalidDomain(InvalidDomainMap[Stmt.getEntryBlock()]);
+    else
+      Stmt.setInvalidDomain(InvalidDomainMap[getRegionNodeBasicBlock(
+          Stmt.getRegion()->getNode())]);
+
+  // Remove empty statements.
+  // Exit early in case there are no executable statements left in this scop.
+  scop->removeStmtNotInDomainMap();
+  scop->simplifySCoP(false);
+  if (scop->isEmpty()) {
+    DEBUG(dbgs() << "Bailing-out because SCoP is empty\n");
+    return;
+  }
+
+  // The ScopStmts now have enough information to initialize themselves.
+  for (ScopStmt &Stmt : *scop) {
+    buildDomain(Stmt);
+    collectSurroundingLoops(Stmt);
+    buildAccessRelations(Stmt);
+
+    if (DetectReductions)
+      checkForReductions(Stmt);
+  }
+
+  // Check early for a feasible runtime context.
+  if (!scop->hasFeasibleRuntimeContext()) {
+    DEBUG(dbgs() << "Bailing-out because of unfeasible context (early)\n");
+    return;
+  }
+
+  // Check early for profitability. Afterwards it cannot change anymore,
+  // only the runtime context could become infeasible.
+  if (!scop->isProfitable(UnprofitableScalarAccs)) {
+    scop->invalidate(PROFITABLE, DebugLoc());
+    DEBUG(dbgs() << "Bailing-out because SCoP is not considered profitable\n");
+    return;
+  }
+
+  scop->buildSchedule(LI);
+
+  scop->finalizeAccesses();
+
+  scop->realignParams();
+  scop->addUserContext();
+
+  // After the context was fully constructed, thus all our knowledge about
+  // the parameters is in there, we add all recorded assumptions to the
+  // assumed/invalid context.
+  scop->addRecordedAssumptions();
+
+  scop->simplifyContexts();
+  if (!scop->buildAliasChecks(AA)) {
+    DEBUG(dbgs() << "Bailing-out because could not build alias checks\n");
+    return;
+  }
+
+  scop->hoistInvariantLoads();
+  scop->canonicalizeDynamicBasePtrs();
+  scop->verifyInvariantLoads();
+  scop->simplifySCoP(true);
+
+  // Check late for a feasible runtime context because profitability did not
+  // change.
+  if (!scop->hasFeasibleRuntimeContext()) {
+    DEBUG(dbgs() << "Bailing-out because of unfeasible context (late)\n");
+    return;
+  }
+
+#ifndef NDEBUG
+  verifyUses(scop.get(), LI, DT);
+#endif
+}
+
+ScopBuilder::ScopBuilder(Region *R, AssumptionCache &AC, AliasAnalysis &AA,
+                         const DataLayout &DL, DominatorTree &DT, LoopInfo &LI,
+                         ScopDetection &SD, ScalarEvolution &SE,
+                         OptimizationRemarkEmitter &ORE)
+    : AA(AA), DL(DL), DT(DT), LI(LI), SD(SD), SE(SE) {
+  DebugLoc Beg, End;
+  auto P = getBBPairForRegion(R);
+  getDebugLocations(P, Beg, End);
+
+  std::string Msg = "SCoP begins here.";
+  ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "ScopEntry", Beg, P.first)
+           << Msg);
+
+  buildScop(*R, AC, ORE);
+
+  DEBUG(dbgs() << *scop);
+
+  if (!scop->hasFeasibleRuntimeContext()) {
+    InfeasibleScops++;
+    Msg = "SCoP ends here but was dismissed.";
+    DEBUG(dbgs() << "SCoP detected but dismissed\n");
+    scop.reset();
+  } else {
+    Msg = "SCoP ends here.";
+    ++ScopFound;
+    if (scop->getMaxLoopDepth() > 0)
+      ++RichScopFound;
+  }
+
+  if (R->isTopLevelRegion())
+    ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "ScopEnd", End, P.first)
+             << Msg);
+  else
+    ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "ScopEnd", End, P.second)
+             << Msg);
+}
diff --git a/final/lib/Analysis/ScopDetection.cpp b/final/lib/Analysis/ScopDetection.cpp
new file mode 100644
index 0000000..b61ebcb
--- /dev/null
+++ b/final/lib/Analysis/ScopDetection.cpp
@@ -0,0 +1,1903 @@
+//===- ScopDetection.cpp - Detect Scops -----------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Detect the maximal Scops of a function.
+//
+// A static control part (Scop) is a subgraph of the control flow graph (CFG)
+// that only has statically known control flow and can therefore be described
+// within the polyhedral model.
+//
+// Every Scop fulfills these restrictions:
+//
+// * It is a single entry single exit region
+//
+// * Only affine linear bounds in the loops
+//
+// Every natural loop in a Scop must have a number of loop iterations that can
+// be described as an affine linear function in surrounding loop iterators or
+// parameters. (A parameter is a scalar that does not change its value during
+// execution of the Scop).
+//
+// * Only comparisons of affine linear expressions in conditions
+//
+// * All loops and conditions perfectly nested
+//
+// The control flow needs to be structured such that it could be written using
+// just 'for' and 'if' statements, without the need for any 'goto', 'break' or
+// 'continue'.
+//
+// * Side effect free functions call
+//
+// Function calls and intrinsics that do not have side effects (readnone)
+// or memory intrinsics (memset, memcpy, memmove) are allowed.
+//
+// The Scop detection finds the largest Scops by checking if the largest
+// region is a Scop. If this is not the case, its canonical subregions are
+// checked until a region is a Scop. It is now tried to extend this Scop by
+// creating a larger non canonical region.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/ScopDetection.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopDetectionDiagnostic.h"
+#include "polly/Support/SCEVValidator.h"
+#include "polly/Support/ScopHelper.h"
+#include "polly/Support/ScopLocation.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/Loads.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/MemoryLocation.h"
+#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <memory>
+#include <stack>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-detect"
+
+// This option is set to a very high value, as analyzing such loops increases
+// compile time on several cases. For experiments that enable this option,
+// a value of around 40 has been working to avoid run-time regressions with
+// Polly while still exposing interesting optimization opportunities.
+static cl::opt<int> ProfitabilityMinPerLoopInstructions(
+    "polly-detect-profitability-min-per-loop-insts",
+    cl::desc("The minimal number of per-loop instructions before a single loop "
+             "region is considered profitable"),
+    cl::Hidden, cl::ValueRequired, cl::init(100000000), cl::cat(PollyCategory));
+
+bool polly::PollyProcessUnprofitable;
+
+static cl::opt<bool, true> XPollyProcessUnprofitable(
+    "polly-process-unprofitable",
+    cl::desc(
+        "Process scops that are unlikely to benefit from Polly optimizations."),
+    cl::location(PollyProcessUnprofitable), cl::init(false), cl::ZeroOrMore,
+    cl::cat(PollyCategory));
+
+static cl::list<std::string> OnlyFunctions(
+    "polly-only-func",
+    cl::desc("Only run on functions that match a regex. "
+             "Multiple regexes can be comma separated. "
+             "Scop detection will run on all functions that match "
+             "ANY of the regexes provided."),
+    cl::ZeroOrMore, cl::CommaSeparated, cl::cat(PollyCategory));
+
+static cl::list<std::string> IgnoredFunctions(
+    "polly-ignore-func",
+    cl::desc("Ignore functions that match a regex. "
+             "Multiple regexes can be comma separated. "
+             "Scop detection will ignore all functions that match "
+             "ANY of the regexes provided."),
+    cl::ZeroOrMore, cl::CommaSeparated, cl::cat(PollyCategory));
+
+bool polly::PollyAllowFullFunction;
+
+static cl::opt<bool, true>
+    XAllowFullFunction("polly-detect-full-functions",
+                       cl::desc("Allow the detection of full functions"),
+                       cl::location(polly::PollyAllowFullFunction),
+                       cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<std::string> OnlyRegion(
+    "polly-only-region",
+    cl::desc("Only run on certain regions (The provided identifier must "
+             "appear in the name of the region's entry block"),
+    cl::value_desc("identifier"), cl::ValueRequired, cl::init(""),
+    cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    IgnoreAliasing("polly-ignore-aliasing",
+                   cl::desc("Ignore possible aliasing of the array bases"),
+                   cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                   cl::cat(PollyCategory));
+
+bool polly::PollyAllowUnsignedOperations;
+
+static cl::opt<bool, true> XPollyAllowUnsignedOperations(
+    "polly-allow-unsigned-operations",
+    cl::desc("Allow unsigned operations such as comparisons or zero-extends."),
+    cl::location(PollyAllowUnsignedOperations), cl::Hidden, cl::ZeroOrMore,
+    cl::init(true), cl::cat(PollyCategory));
+
+bool polly::PollyUseRuntimeAliasChecks;
+
+static cl::opt<bool, true> XPollyUseRuntimeAliasChecks(
+    "polly-use-runtime-alias-checks",
+    cl::desc("Use runtime alias checks to resolve possible aliasing."),
+    cl::location(PollyUseRuntimeAliasChecks), cl::Hidden, cl::ZeroOrMore,
+    cl::init(true), cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    ReportLevel("polly-report",
+                cl::desc("Print information about the activities of Polly"),
+                cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> AllowDifferentTypes(
+    "polly-allow-differing-element-types",
+    cl::desc("Allow different element types for array accesses"), cl::Hidden,
+    cl::init(true), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    AllowNonAffine("polly-allow-nonaffine",
+                   cl::desc("Allow non affine access functions in arrays"),
+                   cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                   cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    AllowModrefCall("polly-allow-modref-calls",
+                    cl::desc("Allow functions with known modref behavior"),
+                    cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                    cl::cat(PollyCategory));
+
+static cl::opt<bool> AllowNonAffineSubRegions(
+    "polly-allow-nonaffine-branches",
+    cl::desc("Allow non affine conditions for branches"), cl::Hidden,
+    cl::init(true), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    AllowNonAffineSubLoops("polly-allow-nonaffine-loops",
+                           cl::desc("Allow non affine conditions for loops"),
+                           cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                           cl::cat(PollyCategory));
+
+static cl::opt<bool, true>
+    TrackFailures("polly-detect-track-failures",
+                  cl::desc("Track failure strings in detecting scop regions"),
+                  cl::location(PollyTrackFailures), cl::Hidden, cl::ZeroOrMore,
+                  cl::init(true), cl::cat(PollyCategory));
+
+static cl::opt<bool> KeepGoing("polly-detect-keep-going",
+                               cl::desc("Do not fail on the first error."),
+                               cl::Hidden, cl::ZeroOrMore, cl::init(false),
+                               cl::cat(PollyCategory));
+
+static cl::opt<bool, true>
+    PollyDelinearizeX("polly-delinearize",
+                      cl::desc("Delinearize array access functions"),
+                      cl::location(PollyDelinearize), cl::Hidden,
+                      cl::ZeroOrMore, cl::init(true), cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    VerifyScops("polly-detect-verify",
+                cl::desc("Verify the detected SCoPs after each transformation"),
+                cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                cl::cat(PollyCategory));
+
+bool polly::PollyInvariantLoadHoisting;
+
+static cl::opt<bool, true> XPollyInvariantLoadHoisting(
+    "polly-invariant-load-hoisting", cl::desc("Hoist invariant loads."),
+    cl::location(PollyInvariantLoadHoisting), cl::Hidden, cl::ZeroOrMore,
+    cl::init(false), cl::cat(PollyCategory));
+
+/// The minimal trip count under which loops are considered unprofitable.
+static const unsigned MIN_LOOP_TRIP_COUNT = 8;
+
+bool polly::PollyTrackFailures = false;
+bool polly::PollyDelinearize = false;
+StringRef polly::PollySkipFnAttr = "polly.skip.fn";
+
+//===----------------------------------------------------------------------===//
+// Statistics.
+
+STATISTIC(NumScopRegions, "Number of scops");
+STATISTIC(NumLoopsInScop, "Number of loops in scops");
+STATISTIC(NumScopsDepthOne, "Number of scops with maximal loop depth 1");
+STATISTIC(NumScopsDepthTwo, "Number of scops with maximal loop depth 2");
+STATISTIC(NumScopsDepthThree, "Number of scops with maximal loop depth 3");
+STATISTIC(NumScopsDepthFour, "Number of scops with maximal loop depth 4");
+STATISTIC(NumScopsDepthFive, "Number of scops with maximal loop depth 5");
+STATISTIC(NumScopsDepthLarger,
+          "Number of scops with maximal loop depth 6 and larger");
+STATISTIC(NumProfScopRegions, "Number of scops (profitable scops only)");
+STATISTIC(NumLoopsInProfScop,
+          "Number of loops in scops (profitable scops only)");
+STATISTIC(NumLoopsOverall, "Number of total loops");
+STATISTIC(NumProfScopsDepthOne,
+          "Number of scops with maximal loop depth 1 (profitable scops only)");
+STATISTIC(NumProfScopsDepthTwo,
+          "Number of scops with maximal loop depth 2 (profitable scops only)");
+STATISTIC(NumProfScopsDepthThree,
+          "Number of scops with maximal loop depth 3 (profitable scops only)");
+STATISTIC(NumProfScopsDepthFour,
+          "Number of scops with maximal loop depth 4 (profitable scops only)");
+STATISTIC(NumProfScopsDepthFive,
+          "Number of scops with maximal loop depth 5 (profitable scops only)");
+STATISTIC(NumProfScopsDepthLarger,
+          "Number of scops with maximal loop depth 6 and larger "
+          "(profitable scops only)");
+STATISTIC(MaxNumLoopsInScop, "Maximal number of loops in scops");
+STATISTIC(MaxNumLoopsInProfScop,
+          "Maximal number of loops in scops (profitable scops only)");
+
+static void updateLoopCountStatistic(ScopDetection::LoopStats Stats,
+                                     bool OnlyProfitable);
+
+namespace {
+
+class DiagnosticScopFound : public DiagnosticInfo {
+private:
+  static int PluginDiagnosticKind;
+
+  Function &F;
+  std::string FileName;
+  unsigned EntryLine, ExitLine;
+
+public:
+  DiagnosticScopFound(Function &F, std::string FileName, unsigned EntryLine,
+                      unsigned ExitLine)
+      : DiagnosticInfo(PluginDiagnosticKind, DS_Note), F(F), FileName(FileName),
+        EntryLine(EntryLine), ExitLine(ExitLine) {}
+
+  void print(DiagnosticPrinter &DP) const override;
+
+  static bool classof(const DiagnosticInfo *DI) {
+    return DI->getKind() == PluginDiagnosticKind;
+  }
+};
+
+} // namespace
+
+int DiagnosticScopFound::PluginDiagnosticKind =
+    getNextAvailablePluginDiagnosticKind();
+
+void DiagnosticScopFound::print(DiagnosticPrinter &DP) const {
+  DP << "Polly detected an optimizable loop region (scop) in function '" << F
+     << "'\n";
+
+  if (FileName.empty()) {
+    DP << "Scop location is unknown. Compile with debug info "
+          "(-g) to get more precise information. ";
+    return;
+  }
+
+  DP << FileName << ":" << EntryLine << ": Start of scop\n";
+  DP << FileName << ":" << ExitLine << ": End of scop";
+}
+
+/// Check if a string matches any regex in a list of regexes.
+/// @param Str the input string to match against.
+/// @param RegexList a list of strings that are regular expressions.
+static bool doesStringMatchAnyRegex(StringRef Str,
+                                    const cl::list<std::string> &RegexList) {
+  for (auto RegexStr : RegexList) {
+    Regex R(RegexStr);
+
+    std::string Err;
+    if (!R.isValid(Err))
+      report_fatal_error("invalid regex given as input to polly: " + Err, true);
+
+    if (R.match(Str))
+      return true;
+  }
+  return false;
+}
+//===----------------------------------------------------------------------===//
+// ScopDetection.
+
+ScopDetection::ScopDetection(Function &F, const DominatorTree &DT,
+                             ScalarEvolution &SE, LoopInfo &LI, RegionInfo &RI,
+                             AliasAnalysis &AA, OptimizationRemarkEmitter &ORE)
+    : DT(DT), SE(SE), LI(LI), RI(RI), AA(AA), ORE(ORE) {
+  if (!PollyProcessUnprofitable && LI.empty())
+    return;
+
+  Region *TopRegion = RI.getTopLevelRegion();
+
+  if (!OnlyFunctions.empty() &&
+      !doesStringMatchAnyRegex(F.getName(), OnlyFunctions))
+    return;
+
+  if (doesStringMatchAnyRegex(F.getName(), IgnoredFunctions))
+    return;
+
+  if (!isValidFunction(F))
+    return;
+
+  findScops(*TopRegion);
+
+  NumScopRegions += ValidRegions.size();
+
+  // Prune non-profitable regions.
+  for (auto &DIt : DetectionContextMap) {
+    auto &DC = DIt.getSecond();
+    if (DC.Log.hasErrors())
+      continue;
+    if (!ValidRegions.count(&DC.CurRegion))
+      continue;
+    LoopStats Stats = countBeneficialLoops(&DC.CurRegion, SE, LI, 0);
+    updateLoopCountStatistic(Stats, false /* OnlyProfitable */);
+    if (isProfitableRegion(DC)) {
+      updateLoopCountStatistic(Stats, true /* OnlyProfitable */);
+      continue;
+    }
+
+    ValidRegions.remove(&DC.CurRegion);
+  }
+
+  NumProfScopRegions += ValidRegions.size();
+  NumLoopsOverall += countBeneficialLoops(TopRegion, SE, LI, 0).NumLoops;
+
+  // Only makes sense when we tracked errors.
+  if (PollyTrackFailures)
+    emitMissedRemarks(F);
+
+  if (ReportLevel)
+    printLocations(F);
+
+  assert(ValidRegions.size() <= DetectionContextMap.size() &&
+         "Cached more results than valid regions");
+}
+
+template <class RR, typename... Args>
+inline bool ScopDetection::invalid(DetectionContext &Context, bool Assert,
+                                   Args &&... Arguments) const {
+  if (!Context.Verifying) {
+    RejectLog &Log = Context.Log;
+    std::shared_ptr<RR> RejectReason = std::make_shared<RR>(Arguments...);
+
+    if (PollyTrackFailures)
+      Log.report(RejectReason);
+
+    DEBUG(dbgs() << RejectReason->getMessage());
+    DEBUG(dbgs() << "\n");
+  } else {
+    assert(!Assert && "Verification of detected scop failed");
+  }
+
+  return false;
+}
+
+bool ScopDetection::isMaxRegionInScop(const Region &R, bool Verify) const {
+  if (!ValidRegions.count(&R))
+    return false;
+
+  if (Verify) {
+    DetectionContextMap.erase(getBBPairForRegion(&R));
+    const auto &It = DetectionContextMap.insert(std::make_pair(
+        getBBPairForRegion(&R),
+        DetectionContext(const_cast<Region &>(R), AA, false /*verifying*/)));
+    DetectionContext &Context = It.first->second;
+    return isValidRegion(Context);
+  }
+
+  return true;
+}
+
+std::string ScopDetection::regionIsInvalidBecause(const Region *R) const {
+  // Get the first error we found. Even in keep-going mode, this is the first
+  // reason that caused the candidate to be rejected.
+  auto *Log = lookupRejectionLog(R);
+
+  // This can happen when we marked a region invalid, but didn't track
+  // an error for it.
+  if (!Log || !Log->hasErrors())
+    return "";
+
+  RejectReasonPtr RR = *Log->begin();
+  return RR->getMessage();
+}
+
+bool ScopDetection::addOverApproximatedRegion(Region *AR,
+                                              DetectionContext &Context) const {
+  // If we already know about Ar we can exit.
+  if (!Context.NonAffineSubRegionSet.insert(AR))
+    return true;
+
+  // All loops in the region have to be overapproximated too if there
+  // are accesses that depend on the iteration count.
+
+  for (BasicBlock *BB : AR->blocks()) {
+    Loop *L = LI.getLoopFor(BB);
+    if (AR->contains(L))
+      Context.BoxedLoopsSet.insert(L);
+  }
+
+  return (AllowNonAffineSubLoops || Context.BoxedLoopsSet.empty());
+}
+
+bool ScopDetection::onlyValidRequiredInvariantLoads(
+    InvariantLoadsSetTy &RequiredILS, DetectionContext &Context) const {
+  Region &CurRegion = Context.CurRegion;
+  const DataLayout &DL = CurRegion.getEntry()->getModule()->getDataLayout();
+
+  if (!PollyInvariantLoadHoisting && !RequiredILS.empty())
+    return false;
+
+  for (LoadInst *Load : RequiredILS) {
+    // If we already know a load has been accepted as required invariant, we
+    // already run the validation below once and consequently don't need to
+    // run it again. Hence, we return early. For certain test cases (e.g.,
+    // COSMO this avoids us spending 50% of scop-detection time in this
+    // very function (and its children).
+    if (Context.RequiredILS.count(Load))
+      continue;
+
+    if (!isHoistableLoad(Load, CurRegion, LI, SE, DT))
+      return false;
+
+    for (auto NonAffineRegion : Context.NonAffineSubRegionSet) {
+      if (isSafeToLoadUnconditionally(Load->getPointerOperand(),
+                                      Load->getAlignment(), DL))
+        continue;
+
+      if (NonAffineRegion->contains(Load) &&
+          Load->getParent() != NonAffineRegion->getEntry())
+        return false;
+    }
+  }
+
+  Context.RequiredILS.insert(RequiredILS.begin(), RequiredILS.end());
+
+  return true;
+}
+
+bool ScopDetection::involvesMultiplePtrs(const SCEV *S0, const SCEV *S1,
+                                         Loop *Scope) const {
+  SetVector<Value *> Values;
+  findValues(S0, SE, Values);
+  if (S1)
+    findValues(S1, SE, Values);
+
+  SmallPtrSet<Value *, 8> PtrVals;
+  for (auto *V : Values) {
+    if (auto *P2I = dyn_cast<PtrToIntInst>(V))
+      V = P2I->getOperand(0);
+
+    if (!V->getType()->isPointerTy())
+      continue;
+
+    auto *PtrSCEV = SE.getSCEVAtScope(V, Scope);
+    if (isa<SCEVConstant>(PtrSCEV))
+      continue;
+
+    auto *BasePtr = dyn_cast<SCEVUnknown>(SE.getPointerBase(PtrSCEV));
+    if (!BasePtr)
+      return true;
+
+    auto *BasePtrVal = BasePtr->getValue();
+    if (PtrVals.insert(BasePtrVal).second) {
+      for (auto *PtrVal : PtrVals)
+        if (PtrVal != BasePtrVal && !AA.isNoAlias(PtrVal, BasePtrVal))
+          return true;
+    }
+  }
+
+  return false;
+}
+
+bool ScopDetection::isAffine(const SCEV *S, Loop *Scope,
+                             DetectionContext &Context) const {
+  InvariantLoadsSetTy AccessILS;
+  if (!isAffineExpr(&Context.CurRegion, Scope, S, SE, &AccessILS))
+    return false;
+
+  if (!onlyValidRequiredInvariantLoads(AccessILS, Context))
+    return false;
+
+  return true;
+}
+
+bool ScopDetection::isValidSwitch(BasicBlock &BB, SwitchInst *SI,
+                                  Value *Condition, bool IsLoopBranch,
+                                  DetectionContext &Context) const {
+  Loop *L = LI.getLoopFor(&BB);
+  const SCEV *ConditionSCEV = SE.getSCEVAtScope(Condition, L);
+
+  if (IsLoopBranch && L->isLoopLatch(&BB))
+    return false;
+
+  // Check for invalid usage of different pointers in one expression.
+  if (involvesMultiplePtrs(ConditionSCEV, nullptr, L))
+    return false;
+
+  if (isAffine(ConditionSCEV, L, Context))
+    return true;
+
+  if (AllowNonAffineSubRegions &&
+      addOverApproximatedRegion(RI.getRegionFor(&BB), Context))
+    return true;
+
+  return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB,
+                                     ConditionSCEV, ConditionSCEV, SI);
+}
+
+bool ScopDetection::isValidBranch(BasicBlock &BB, BranchInst *BI,
+                                  Value *Condition, bool IsLoopBranch,
+                                  DetectionContext &Context) const {
+  // Constant integer conditions are always affine.
+  if (isa<ConstantInt>(Condition))
+    return true;
+
+  if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(Condition)) {
+    auto Opcode = BinOp->getOpcode();
+    if (Opcode == Instruction::And || Opcode == Instruction::Or) {
+      Value *Op0 = BinOp->getOperand(0);
+      Value *Op1 = BinOp->getOperand(1);
+      return isValidBranch(BB, BI, Op0, IsLoopBranch, Context) &&
+             isValidBranch(BB, BI, Op1, IsLoopBranch, Context);
+    }
+  }
+
+  if (auto PHI = dyn_cast<PHINode>(Condition)) {
+    auto *Unique = dyn_cast_or_null<ConstantInt>(
+        getUniqueNonErrorValue(PHI, &Context.CurRegion, LI, DT));
+    if (Unique && (Unique->isZero() || Unique->isOne()))
+      return true;
+  }
+
+  if (auto Load = dyn_cast<LoadInst>(Condition))
+    if (!IsLoopBranch && Context.CurRegion.contains(Load)) {
+      Context.RequiredILS.insert(Load);
+      return true;
+    }
+
+  // Non constant conditions of branches need to be ICmpInst.
+  if (!isa<ICmpInst>(Condition)) {
+    if (!IsLoopBranch && AllowNonAffineSubRegions &&
+        addOverApproximatedRegion(RI.getRegionFor(&BB), Context))
+      return true;
+    return invalid<ReportInvalidCond>(Context, /*Assert=*/true, BI, &BB);
+  }
+
+  ICmpInst *ICmp = cast<ICmpInst>(Condition);
+
+  // Are both operands of the ICmp affine?
+  if (isa<UndefValue>(ICmp->getOperand(0)) ||
+      isa<UndefValue>(ICmp->getOperand(1)))
+    return invalid<ReportUndefOperand>(Context, /*Assert=*/true, &BB, ICmp);
+
+  Loop *L = LI.getLoopFor(&BB);
+  const SCEV *LHS = SE.getSCEVAtScope(ICmp->getOperand(0), L);
+  const SCEV *RHS = SE.getSCEVAtScope(ICmp->getOperand(1), L);
+
+  LHS = tryForwardThroughPHI(LHS, Context.CurRegion, SE, LI, DT);
+  RHS = tryForwardThroughPHI(RHS, Context.CurRegion, SE, LI, DT);
+
+  // If unsigned operations are not allowed try to approximate the region.
+  if (ICmp->isUnsigned() && !PollyAllowUnsignedOperations)
+    return !IsLoopBranch && AllowNonAffineSubRegions &&
+           addOverApproximatedRegion(RI.getRegionFor(&BB), Context);
+
+  // Check for invalid usage of different pointers in one expression.
+  if (ICmp->isEquality() && involvesMultiplePtrs(LHS, nullptr, L) &&
+      involvesMultiplePtrs(RHS, nullptr, L))
+    return false;
+
+  // Check for invalid usage of different pointers in a relational comparison.
+  if (ICmp->isRelational() && involvesMultiplePtrs(LHS, RHS, L))
+    return false;
+
+  if (isAffine(LHS, L, Context) && isAffine(RHS, L, Context))
+    return true;
+
+  if (!IsLoopBranch && AllowNonAffineSubRegions &&
+      addOverApproximatedRegion(RI.getRegionFor(&BB), Context))
+    return true;
+
+  if (IsLoopBranch)
+    return false;
+
+  return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB, LHS, RHS,
+                                     ICmp);
+}
+
+bool ScopDetection::isValidCFG(BasicBlock &BB, bool IsLoopBranch,
+                               bool AllowUnreachable,
+                               DetectionContext &Context) const {
+  Region &CurRegion = Context.CurRegion;
+
+  TerminatorInst *TI = BB.getTerminator();
+
+  if (AllowUnreachable && isa<UnreachableInst>(TI))
+    return true;
+
+  // Return instructions are only valid if the region is the top level region.
+  if (isa<ReturnInst>(TI) && CurRegion.isTopLevelRegion())
+    return true;
+
+  Value *Condition = getConditionFromTerminator(TI);
+
+  if (!Condition)
+    return invalid<ReportInvalidTerminator>(Context, /*Assert=*/true, &BB);
+
+  // UndefValue is not allowed as condition.
+  if (isa<UndefValue>(Condition))
+    return invalid<ReportUndefCond>(Context, /*Assert=*/true, TI, &BB);
+
+  if (BranchInst *BI = dyn_cast<BranchInst>(TI))
+    return isValidBranch(BB, BI, Condition, IsLoopBranch, Context);
+
+  SwitchInst *SI = dyn_cast<SwitchInst>(TI);
+  assert(SI && "Terminator was neither branch nor switch");
+
+  return isValidSwitch(BB, SI, Condition, IsLoopBranch, Context);
+}
+
+bool ScopDetection::isValidCallInst(CallInst &CI,
+                                    DetectionContext &Context) const {
+  if (CI.doesNotReturn())
+    return false;
+
+  if (CI.doesNotAccessMemory())
+    return true;
+
+  if (auto *II = dyn_cast<IntrinsicInst>(&CI))
+    if (isValidIntrinsicInst(*II, Context))
+      return true;
+
+  Function *CalledFunction = CI.getCalledFunction();
+
+  // Indirect calls are not supported.
+  if (CalledFunction == nullptr)
+    return false;
+
+  if (AllowModrefCall) {
+    switch (AA.getModRefBehavior(CalledFunction)) {
+    case FMRB_UnknownModRefBehavior:
+      return false;
+    case FMRB_DoesNotAccessMemory:
+    case FMRB_OnlyReadsMemory:
+      // Implicitly disable delinearization since we have an unknown
+      // accesses with an unknown access function.
+      Context.HasUnknownAccess = true;
+      Context.AST.add(&CI);
+      return true;
+    case FMRB_OnlyReadsArgumentPointees:
+    case FMRB_OnlyAccessesArgumentPointees:
+      for (const auto &Arg : CI.arg_operands()) {
+        if (!Arg->getType()->isPointerTy())
+          continue;
+
+        // Bail if a pointer argument has a base address not known to
+        // ScalarEvolution. Note that a zero pointer is acceptable.
+        auto *ArgSCEV = SE.getSCEVAtScope(Arg, LI.getLoopFor(CI.getParent()));
+        if (ArgSCEV->isZero())
+          continue;
+
+        auto *BP = dyn_cast<SCEVUnknown>(SE.getPointerBase(ArgSCEV));
+        if (!BP)
+          return false;
+
+        // Implicitly disable delinearization since we have an unknown
+        // accesses with an unknown access function.
+        Context.HasUnknownAccess = true;
+      }
+
+      Context.AST.add(&CI);
+      return true;
+    case FMRB_DoesNotReadMemory:
+    case FMRB_OnlyAccessesInaccessibleMem:
+    case FMRB_OnlyAccessesInaccessibleOrArgMem:
+      return false;
+    }
+  }
+
+  return false;
+}
+
+bool ScopDetection::isValidIntrinsicInst(IntrinsicInst &II,
+                                         DetectionContext &Context) const {
+  if (isIgnoredIntrinsic(&II))
+    return true;
+
+  // The closest loop surrounding the call instruction.
+  Loop *L = LI.getLoopFor(II.getParent());
+
+  // The access function and base pointer for memory intrinsics.
+  const SCEV *AF;
+  const SCEVUnknown *BP;
+
+  switch (II.getIntrinsicID()) {
+  // Memory intrinsics that can be represented are supported.
+  case Intrinsic::memmove:
+  case Intrinsic::memcpy:
+    AF = SE.getSCEVAtScope(cast<MemTransferInst>(II).getSource(), L);
+    if (!AF->isZero()) {
+      BP = dyn_cast<SCEVUnknown>(SE.getPointerBase(AF));
+      // Bail if the source pointer is not valid.
+      if (!isValidAccess(&II, AF, BP, Context))
+        return false;
+    }
+  // Fall through
+  case Intrinsic::memset:
+    AF = SE.getSCEVAtScope(cast<MemIntrinsic>(II).getDest(), L);
+    if (!AF->isZero()) {
+      BP = dyn_cast<SCEVUnknown>(SE.getPointerBase(AF));
+      // Bail if the destination pointer is not valid.
+      if (!isValidAccess(&II, AF, BP, Context))
+        return false;
+    }
+
+    // Bail if the length is not affine.
+    if (!isAffine(SE.getSCEVAtScope(cast<MemIntrinsic>(II).getLength(), L), L,
+                  Context))
+      return false;
+
+    return true;
+  default:
+    break;
+  }
+
+  return false;
+}
+
+bool ScopDetection::isInvariant(Value &Val, const Region &Reg,
+                                DetectionContext &Ctx) const {
+  // A reference to function argument or constant value is invariant.
+  if (isa<Argument>(Val) || isa<Constant>(Val))
+    return true;
+
+  Instruction *I = dyn_cast<Instruction>(&Val);
+  if (!I)
+    return false;
+
+  if (!Reg.contains(I))
+    return true;
+
+  // Loads within the SCoP may read arbitrary values, need to hoist them. If it
+  // is not hoistable, it will be rejected later, but here we assume it is and
+  // that makes the value invariant.
+  if (auto LI = dyn_cast<LoadInst>(I)) {
+    Ctx.RequiredILS.insert(LI);
+    return true;
+  }
+
+  return false;
+}
+
+namespace {
+
+/// Remove smax of smax(0, size) expressions from a SCEV expression and
+/// register the '...' components.
+///
+/// Array access expressions as they are generated by GFortran contain smax(0,
+/// size) expressions that confuse the 'normal' delinearization algorithm.
+/// However, if we extract such expressions before the normal delinearization
+/// takes place they can actually help to identify array size expressions in
+/// Fortran accesses. For the subsequently following delinearization the smax(0,
+/// size) component can be replaced by just 'size'. This is correct as we will
+/// always add and verify the assumption that for all subscript expressions
+/// 'exp' the inequality 0 <= exp < size holds. Hence, we will also verify
+/// that 0 <= size, which means smax(0, size) == size.
+class SCEVRemoveMax : public SCEVRewriteVisitor<SCEVRemoveMax> {
+public:
+  SCEVRemoveMax(ScalarEvolution &SE, std::vector<const SCEV *> *Terms)
+      : SCEVRewriteVisitor(SE), Terms(Terms) {}
+
+  static const SCEV *rewrite(const SCEV *Scev, ScalarEvolution &SE,
+                             std::vector<const SCEV *> *Terms = nullptr) {
+    SCEVRemoveMax Rewriter(SE, Terms);
+    return Rewriter.visit(Scev);
+  }
+
+  const SCEV *visitSMaxExpr(const SCEVSMaxExpr *Expr) {
+    if ((Expr->getNumOperands() == 2) && Expr->getOperand(0)->isZero()) {
+      auto Res = visit(Expr->getOperand(1));
+      if (Terms)
+        (*Terms).push_back(Res);
+      return Res;
+    }
+
+    return Expr;
+  }
+
+private:
+  std::vector<const SCEV *> *Terms;
+};
+
+} // namespace
+
+SmallVector<const SCEV *, 4>
+ScopDetection::getDelinearizationTerms(DetectionContext &Context,
+                                       const SCEVUnknown *BasePointer) const {
+  SmallVector<const SCEV *, 4> Terms;
+  for (const auto &Pair : Context.Accesses[BasePointer]) {
+    std::vector<const SCEV *> MaxTerms;
+    SCEVRemoveMax::rewrite(Pair.second, SE, &MaxTerms);
+    if (!MaxTerms.empty()) {
+      Terms.insert(Terms.begin(), MaxTerms.begin(), MaxTerms.end());
+      continue;
+    }
+    // In case the outermost expression is a plain add, we check if any of its
+    // terms has the form 4 * %inst * %param * %param ..., aka a term that
+    // contains a product between a parameter and an instruction that is
+    // inside the scop. Such instructions, if allowed at all, are instructions
+    // SCEV can not represent, but Polly is still looking through. As a
+    // result, these instructions can depend on induction variables and are
+    // most likely no array sizes. However, terms that are multiplied with
+    // them are likely candidates for array sizes.
+    if (auto *AF = dyn_cast<SCEVAddExpr>(Pair.second)) {
+      for (auto Op : AF->operands()) {
+        if (auto *AF2 = dyn_cast<SCEVAddRecExpr>(Op))
+          SE.collectParametricTerms(AF2, Terms);
+        if (auto *AF2 = dyn_cast<SCEVMulExpr>(Op)) {
+          SmallVector<const SCEV *, 0> Operands;
+
+          for (auto *MulOp : AF2->operands()) {
+            if (auto *Const = dyn_cast<SCEVConstant>(MulOp))
+              Operands.push_back(Const);
+            if (auto *Unknown = dyn_cast<SCEVUnknown>(MulOp)) {
+              if (auto *Inst = dyn_cast<Instruction>(Unknown->getValue())) {
+                if (!Context.CurRegion.contains(Inst))
+                  Operands.push_back(MulOp);
+
+              } else {
+                Operands.push_back(MulOp);
+              }
+            }
+          }
+          if (Operands.size())
+            Terms.push_back(SE.getMulExpr(Operands));
+        }
+      }
+    }
+    if (Terms.empty())
+      SE.collectParametricTerms(Pair.second, Terms);
+  }
+  return Terms;
+}
+
+bool ScopDetection::hasValidArraySizes(DetectionContext &Context,
+                                       SmallVectorImpl<const SCEV *> &Sizes,
+                                       const SCEVUnknown *BasePointer,
+                                       Loop *Scope) const {
+  // If no sizes were found, all sizes are trivially valid. We allow this case
+  // to make it possible to pass known-affine accesses to the delinearization to
+  // try to recover some interesting multi-dimensional accesses, but to still
+  // allow the already known to be affine access in case the delinearization
+  // fails. In such situations, the delinearization will just return a Sizes
+  // array of size zero.
+  if (Sizes.size() == 0)
+    return true;
+
+  Value *BaseValue = BasePointer->getValue();
+  Region &CurRegion = Context.CurRegion;
+  for (const SCEV *DelinearizedSize : Sizes) {
+    if (!isAffine(DelinearizedSize, Scope, Context)) {
+      Sizes.clear();
+      break;
+    }
+    if (auto *Unknown = dyn_cast<SCEVUnknown>(DelinearizedSize)) {
+      auto *V = dyn_cast<Value>(Unknown->getValue());
+      if (auto *Load = dyn_cast<LoadInst>(V)) {
+        if (Context.CurRegion.contains(Load) &&
+            isHoistableLoad(Load, CurRegion, LI, SE, DT))
+          Context.RequiredILS.insert(Load);
+        continue;
+      }
+    }
+    if (hasScalarDepsInsideRegion(DelinearizedSize, &CurRegion, Scope, false,
+                                  Context.RequiredILS))
+      return invalid<ReportNonAffineAccess>(
+          Context, /*Assert=*/true, DelinearizedSize,
+          Context.Accesses[BasePointer].front().first, BaseValue);
+  }
+
+  // No array shape derived.
+  if (Sizes.empty()) {
+    if (AllowNonAffine)
+      return true;
+
+    for (const auto &Pair : Context.Accesses[BasePointer]) {
+      const Instruction *Insn = Pair.first;
+      const SCEV *AF = Pair.second;
+
+      if (!isAffine(AF, Scope, Context)) {
+        invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Insn,
+                                       BaseValue);
+        if (!KeepGoing)
+          return false;
+      }
+    }
+    return false;
+  }
+  return true;
+}
+
+// We first store the resulting memory accesses in TempMemoryAccesses. Only
+// if the access functions for all memory accesses have been successfully
+// delinearized we continue. Otherwise, we either report a failure or, if
+// non-affine accesses are allowed, we drop the information. In case the
+// information is dropped the memory accesses need to be overapproximated
+// when translated to a polyhedral representation.
+bool ScopDetection::computeAccessFunctions(
+    DetectionContext &Context, const SCEVUnknown *BasePointer,
+    std::shared_ptr<ArrayShape> Shape) const {
+  Value *BaseValue = BasePointer->getValue();
+  bool BasePtrHasNonAffine = false;
+  MapInsnToMemAcc TempMemoryAccesses;
+  for (const auto &Pair : Context.Accesses[BasePointer]) {
+    const Instruction *Insn = Pair.first;
+    auto *AF = Pair.second;
+    AF = SCEVRemoveMax::rewrite(AF, SE);
+    bool IsNonAffine = false;
+    TempMemoryAccesses.insert(std::make_pair(Insn, MemAcc(Insn, Shape)));
+    MemAcc *Acc = &TempMemoryAccesses.find(Insn)->second;
+    auto *Scope = LI.getLoopFor(Insn->getParent());
+
+    if (!AF) {
+      if (isAffine(Pair.second, Scope, Context))
+        Acc->DelinearizedSubscripts.push_back(Pair.second);
+      else
+        IsNonAffine = true;
+    } else {
+      if (Shape->DelinearizedSizes.size() == 0) {
+        Acc->DelinearizedSubscripts.push_back(AF);
+      } else {
+        SE.computeAccessFunctions(AF, Acc->DelinearizedSubscripts,
+                                  Shape->DelinearizedSizes);
+        if (Acc->DelinearizedSubscripts.size() == 0)
+          IsNonAffine = true;
+      }
+      for (const SCEV *S : Acc->DelinearizedSubscripts)
+        if (!isAffine(S, Scope, Context))
+          IsNonAffine = true;
+    }
+
+    // (Possibly) report non affine access
+    if (IsNonAffine) {
+      BasePtrHasNonAffine = true;
+      if (!AllowNonAffine)
+        invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, Pair.second,
+                                       Insn, BaseValue);
+      if (!KeepGoing && !AllowNonAffine)
+        return false;
+    }
+  }
+
+  if (!BasePtrHasNonAffine)
+    Context.InsnToMemAcc.insert(TempMemoryAccesses.begin(),
+                                TempMemoryAccesses.end());
+
+  return true;
+}
+
+bool ScopDetection::hasBaseAffineAccesses(DetectionContext &Context,
+                                          const SCEVUnknown *BasePointer,
+                                          Loop *Scope) const {
+  auto Shape = std::shared_ptr<ArrayShape>(new ArrayShape(BasePointer));
+
+  auto Terms = getDelinearizationTerms(Context, BasePointer);
+
+  SE.findArrayDimensions(Terms, Shape->DelinearizedSizes,
+                         Context.ElementSize[BasePointer]);
+
+  if (!hasValidArraySizes(Context, Shape->DelinearizedSizes, BasePointer,
+                          Scope))
+    return false;
+
+  return computeAccessFunctions(Context, BasePointer, Shape);
+}
+
+bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const {
+  // TODO: If we have an unknown access and other non-affine accesses we do
+  //       not try to delinearize them for now.
+  if (Context.HasUnknownAccess && !Context.NonAffineAccesses.empty())
+    return AllowNonAffine;
+
+  for (auto &Pair : Context.NonAffineAccesses) {
+    auto *BasePointer = Pair.first;
+    auto *Scope = Pair.second;
+    if (!hasBaseAffineAccesses(Context, BasePointer, Scope)) {
+      if (KeepGoing)
+        continue;
+      else
+        return false;
+    }
+  }
+  return true;
+}
+
+bool ScopDetection::isValidAccess(Instruction *Inst, const SCEV *AF,
+                                  const SCEVUnknown *BP,
+                                  DetectionContext &Context) const {
+
+  if (!BP)
+    return invalid<ReportNoBasePtr>(Context, /*Assert=*/true, Inst);
+
+  auto *BV = BP->getValue();
+  if (isa<UndefValue>(BV))
+    return invalid<ReportUndefBasePtr>(Context, /*Assert=*/true, Inst);
+
+  // FIXME: Think about allowing IntToPtrInst
+  if (IntToPtrInst *Inst = dyn_cast<IntToPtrInst>(BV))
+    return invalid<ReportIntToPtr>(Context, /*Assert=*/true, Inst);
+
+  // Check that the base address of the access is invariant in the current
+  // region.
+  if (!isInvariant(*BV, Context.CurRegion, Context))
+    return invalid<ReportVariantBasePtr>(Context, /*Assert=*/true, BV, Inst);
+
+  AF = SE.getMinusSCEV(AF, BP);
+
+  const SCEV *Size;
+  if (!isa<MemIntrinsic>(Inst)) {
+    Size = SE.getElementSize(Inst);
+  } else {
+    auto *SizeTy =
+        SE.getEffectiveSCEVType(PointerType::getInt8PtrTy(SE.getContext()));
+    Size = SE.getConstant(SizeTy, 8);
+  }
+
+  if (Context.ElementSize[BP]) {
+    if (!AllowDifferentTypes && Context.ElementSize[BP] != Size)
+      return invalid<ReportDifferentArrayElementSize>(Context, /*Assert=*/true,
+                                                      Inst, BV);
+
+    Context.ElementSize[BP] = SE.getSMinExpr(Size, Context.ElementSize[BP]);
+  } else {
+    Context.ElementSize[BP] = Size;
+  }
+
+  bool IsVariantInNonAffineLoop = false;
+  SetVector<const Loop *> Loops;
+  findLoops(AF, Loops);
+  for (const Loop *L : Loops)
+    if (Context.BoxedLoopsSet.count(L))
+      IsVariantInNonAffineLoop = true;
+
+  auto *Scope = LI.getLoopFor(Inst->getParent());
+  bool IsAffine = !IsVariantInNonAffineLoop && isAffine(AF, Scope, Context);
+  // Do not try to delinearize memory intrinsics and force them to be affine.
+  if (isa<MemIntrinsic>(Inst) && !IsAffine) {
+    return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Inst,
+                                          BV);
+  } else if (PollyDelinearize && !IsVariantInNonAffineLoop) {
+    Context.Accesses[BP].push_back({Inst, AF});
+
+    if (!IsAffine || hasIVParams(AF))
+      Context.NonAffineAccesses.insert(
+          std::make_pair(BP, LI.getLoopFor(Inst->getParent())));
+  } else if (!AllowNonAffine && !IsAffine) {
+    return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Inst,
+                                          BV);
+  }
+
+  if (IgnoreAliasing)
+    return true;
+
+  // Check if the base pointer of the memory access does alias with
+  // any other pointer. This cannot be handled at the moment.
+  AAMDNodes AATags;
+  Inst->getAAMetadata(AATags);
+  AliasSet &AS = Context.AST.getAliasSetForPointer(
+      BP->getValue(), MemoryLocation::UnknownSize, AATags);
+
+  if (!AS.isMustAlias()) {
+    if (PollyUseRuntimeAliasChecks) {
+      bool CanBuildRunTimeCheck = true;
+      // The run-time alias check places code that involves the base pointer at
+      // the beginning of the SCoP. This breaks if the base pointer is defined
+      // inside the scop. Hence, we can only create a run-time check if we are
+      // sure the base pointer is not an instruction defined inside the scop.
+      // However, we can ignore loads that will be hoisted.
+      for (const auto &Ptr : AS) {
+        Instruction *Inst = dyn_cast<Instruction>(Ptr.getValue());
+        if (Inst && Context.CurRegion.contains(Inst)) {
+          auto *Load = dyn_cast<LoadInst>(Inst);
+          if (Load && isHoistableLoad(Load, Context.CurRegion, LI, SE, DT)) {
+            Context.RequiredILS.insert(Load);
+            continue;
+          }
+
+          CanBuildRunTimeCheck = false;
+          break;
+        }
+      }
+
+      if (CanBuildRunTimeCheck)
+        return true;
+    }
+    return invalid<ReportAlias>(Context, /*Assert=*/true, Inst, AS);
+  }
+
+  return true;
+}
+
+bool ScopDetection::isValidMemoryAccess(MemAccInst Inst,
+                                        DetectionContext &Context) const {
+  Value *Ptr = Inst.getPointerOperand();
+  Loop *L = LI.getLoopFor(Inst->getParent());
+  const SCEV *AccessFunction = SE.getSCEVAtScope(Ptr, L);
+  const SCEVUnknown *BasePointer;
+
+  BasePointer = dyn_cast<SCEVUnknown>(SE.getPointerBase(AccessFunction));
+
+  return isValidAccess(Inst, AccessFunction, BasePointer, Context);
+}
+
+bool ScopDetection::isValidInstruction(Instruction &Inst,
+                                       DetectionContext &Context) const {
+  for (auto &Op : Inst.operands()) {
+    auto *OpInst = dyn_cast<Instruction>(&Op);
+
+    if (!OpInst)
+      continue;
+
+    if (isErrorBlock(*OpInst->getParent(), Context.CurRegion, LI, DT)) {
+      auto *PHI = dyn_cast<PHINode>(OpInst);
+      if (PHI) {
+        for (User *U : PHI->users()) {
+          if (!isa<TerminatorInst>(U))
+            return false;
+        }
+      } else {
+        return false;
+      }
+    }
+  }
+
+  if (isa<LandingPadInst>(&Inst) || isa<ResumeInst>(&Inst))
+    return false;
+
+  // We only check the call instruction but not invoke instruction.
+  if (CallInst *CI = dyn_cast<CallInst>(&Inst)) {
+    if (isValidCallInst(*CI, Context))
+      return true;
+
+    return invalid<ReportFuncCall>(Context, /*Assert=*/true, &Inst);
+  }
+
+  if (!Inst.mayReadOrWriteMemory()) {
+    if (!isa<AllocaInst>(Inst))
+      return true;
+
+    return invalid<ReportAlloca>(Context, /*Assert=*/true, &Inst);
+  }
+
+  // Check the access function.
+  if (auto MemInst = MemAccInst::dyn_cast(Inst)) {
+    Context.hasStores |= isa<StoreInst>(MemInst);
+    Context.hasLoads |= isa<LoadInst>(MemInst);
+    if (!MemInst.isSimple())
+      return invalid<ReportNonSimpleMemoryAccess>(Context, /*Assert=*/true,
+                                                  &Inst);
+
+    return isValidMemoryAccess(MemInst, Context);
+  }
+
+  // We do not know this instruction, therefore we assume it is invalid.
+  return invalid<ReportUnknownInst>(Context, /*Assert=*/true, &Inst);
+}
+
+/// Check whether @p L has exiting blocks.
+///
+/// @param L The loop of interest
+///
+/// @return True if the loop has exiting blocks, false otherwise.
+static bool hasExitingBlocks(Loop *L) {
+  SmallVector<BasicBlock *, 4> ExitingBlocks;
+  L->getExitingBlocks(ExitingBlocks);
+  return !ExitingBlocks.empty();
+}
+
+bool ScopDetection::canUseISLTripCount(Loop *L,
+                                       DetectionContext &Context) const {
+  // Ensure the loop has valid exiting blocks as well as latches, otherwise we
+  // need to overapproximate it as a boxed loop.
+  SmallVector<BasicBlock *, 4> LoopControlBlocks;
+  L->getExitingBlocks(LoopControlBlocks);
+  L->getLoopLatches(LoopControlBlocks);
+  for (BasicBlock *ControlBB : LoopControlBlocks) {
+    if (!isValidCFG(*ControlBB, true, false, Context))
+      return false;
+  }
+
+  // We can use ISL to compute the trip count of L.
+  return true;
+}
+
+bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) const {
+  // Loops that contain part but not all of the blocks of a region cannot be
+  // handled by the schedule generation. Such loop constructs can happen
+  // because a region can contain BBs that have no path to the exit block
+  // (Infinite loops, UnreachableInst), but such blocks are never part of a
+  // loop.
+  //
+  // _______________
+  // | Loop Header | <-----------.
+  // ---------------             |
+  //        |                    |
+  // _______________       ______________
+  // | RegionEntry |-----> | RegionExit |----->
+  // ---------------       --------------
+  //        |
+  // _______________
+  // | EndlessLoop | <--.
+  // ---------------    |
+  //       |            |
+  //       \------------/
+  //
+  // In the example above, the loop (LoopHeader,RegionEntry,RegionExit) is
+  // neither entirely contained in the region RegionEntry->RegionExit
+  // (containing RegionEntry,EndlessLoop) nor is the region entirely contained
+  // in the loop.
+  // The block EndlessLoop is contained in the region because Region::contains
+  // tests whether it is not dominated by RegionExit. This is probably to not
+  // having to query the PostdominatorTree. Instead of an endless loop, a dead
+  // end can also be formed by an UnreachableInst. This case is already caught
+  // by isErrorBlock(). We hence only have to reject endless loops here.
+  if (!hasExitingBlocks(L))
+    return invalid<ReportLoopHasNoExit>(Context, /*Assert=*/true, L);
+
+  if (canUseISLTripCount(L, Context))
+    return true;
+
+  if (AllowNonAffineSubLoops && AllowNonAffineSubRegions) {
+    Region *R = RI.getRegionFor(L->getHeader());
+    while (R != &Context.CurRegion && !R->contains(L))
+      R = R->getParent();
+
+    if (addOverApproximatedRegion(R, Context))
+      return true;
+  }
+
+  const SCEV *LoopCount = SE.getBackedgeTakenCount(L);
+  return invalid<ReportLoopBound>(Context, /*Assert=*/true, L, LoopCount);
+}
+
+/// Return the number of loops in @p L (incl. @p L) that have a trip
+///        count that is not known to be less than @MinProfitableTrips.
+ScopDetection::LoopStats
+ScopDetection::countBeneficialSubLoops(Loop *L, ScalarEvolution &SE,
+                                       unsigned MinProfitableTrips) {
+  auto *TripCount = SE.getBackedgeTakenCount(L);
+
+  int NumLoops = 1;
+  int MaxLoopDepth = 1;
+  if (MinProfitableTrips > 0)
+    if (auto *TripCountC = dyn_cast<SCEVConstant>(TripCount))
+      if (TripCountC->getType()->getScalarSizeInBits() <= 64)
+        if (TripCountC->getValue()->getZExtValue() <= MinProfitableTrips)
+          NumLoops -= 1;
+
+  for (auto &SubLoop : *L) {
+    LoopStats Stats = countBeneficialSubLoops(SubLoop, SE, MinProfitableTrips);
+    NumLoops += Stats.NumLoops;
+    MaxLoopDepth = std::max(MaxLoopDepth, Stats.MaxDepth + 1);
+  }
+
+  return {NumLoops, MaxLoopDepth};
+}
+
+ScopDetection::LoopStats
+ScopDetection::countBeneficialLoops(Region *R, ScalarEvolution &SE,
+                                    LoopInfo &LI, unsigned MinProfitableTrips) {
+  int LoopNum = 0;
+  int MaxLoopDepth = 0;
+
+  auto L = LI.getLoopFor(R->getEntry());
+
+  // If L is fully contained in R, move to first loop surrounding R. Otherwise,
+  // L is either nullptr or already surrounding R.
+  if (L && R->contains(L)) {
+    L = R->outermostLoopInRegion(L);
+    L = L->getParentLoop();
+  }
+
+  auto SubLoops =
+      L ? L->getSubLoopsVector() : std::vector<Loop *>(LI.begin(), LI.end());
+
+  for (auto &SubLoop : SubLoops)
+    if (R->contains(SubLoop)) {
+      LoopStats Stats =
+          countBeneficialSubLoops(SubLoop, SE, MinProfitableTrips);
+      LoopNum += Stats.NumLoops;
+      MaxLoopDepth = std::max(MaxLoopDepth, Stats.MaxDepth);
+    }
+
+  return {LoopNum, MaxLoopDepth};
+}
+
+Region *ScopDetection::expandRegion(Region &R) {
+  // Initial no valid region was found (greater than R)
+  std::unique_ptr<Region> LastValidRegion;
+  auto ExpandedRegion = std::unique_ptr<Region>(R.getExpandedRegion());
+
+  DEBUG(dbgs() << "\tExpanding " << R.getNameStr() << "\n");
+
+  while (ExpandedRegion) {
+    const auto &It = DetectionContextMap.insert(std::make_pair(
+        getBBPairForRegion(ExpandedRegion.get()),
+        DetectionContext(*ExpandedRegion, AA, false /*verifying*/)));
+    DetectionContext &Context = It.first->second;
+    DEBUG(dbgs() << "\t\tTrying " << ExpandedRegion->getNameStr() << "\n");
+    // Only expand when we did not collect errors.
+
+    if (!Context.Log.hasErrors()) {
+      // If the exit is valid check all blocks
+      //  - if true, a valid region was found => store it + keep expanding
+      //  - if false, .tbd. => stop  (should this really end the loop?)
+      if (!allBlocksValid(Context) || Context.Log.hasErrors()) {
+        removeCachedResults(*ExpandedRegion);
+        DetectionContextMap.erase(It.first);
+        break;
+      }
+
+      // Store this region, because it is the greatest valid (encountered so
+      // far).
+      if (LastValidRegion) {
+        removeCachedResults(*LastValidRegion);
+        DetectionContextMap.erase(getBBPairForRegion(LastValidRegion.get()));
+      }
+      LastValidRegion = std::move(ExpandedRegion);
+
+      // Create and test the next greater region (if any)
+      ExpandedRegion =
+          std::unique_ptr<Region>(LastValidRegion->getExpandedRegion());
+
+    } else {
+      // Create and test the next greater region (if any)
+      removeCachedResults(*ExpandedRegion);
+      DetectionContextMap.erase(It.first);
+      ExpandedRegion =
+          std::unique_ptr<Region>(ExpandedRegion->getExpandedRegion());
+    }
+  }
+
+  DEBUG({
+    if (LastValidRegion)
+      dbgs() << "\tto " << LastValidRegion->getNameStr() << "\n";
+    else
+      dbgs() << "\tExpanding " << R.getNameStr() << " failed\n";
+  });
+
+  return LastValidRegion.release();
+}
+
+static bool regionWithoutLoops(Region &R, LoopInfo &LI) {
+  for (const BasicBlock *BB : R.blocks())
+    if (R.contains(LI.getLoopFor(BB)))
+      return false;
+
+  return true;
+}
+
+void ScopDetection::removeCachedResultsRecursively(const Region &R) {
+  for (auto &SubRegion : R) {
+    if (ValidRegions.count(SubRegion.get())) {
+      removeCachedResults(*SubRegion.get());
+    } else
+      removeCachedResultsRecursively(*SubRegion);
+  }
+}
+
+void ScopDetection::removeCachedResults(const Region &R) {
+  ValidRegions.remove(&R);
+}
+
+void ScopDetection::findScops(Region &R) {
+  const auto &It = DetectionContextMap.insert(std::make_pair(
+      getBBPairForRegion(&R), DetectionContext(R, AA, false /*verifying*/)));
+  DetectionContext &Context = It.first->second;
+
+  bool RegionIsValid = false;
+  if (!PollyProcessUnprofitable && regionWithoutLoops(R, LI))
+    invalid<ReportUnprofitable>(Context, /*Assert=*/true, &R);
+  else
+    RegionIsValid = isValidRegion(Context);
+
+  bool HasErrors = !RegionIsValid || Context.Log.size() > 0;
+
+  if (HasErrors) {
+    removeCachedResults(R);
+  } else {
+    ValidRegions.insert(&R);
+    return;
+  }
+
+  for (auto &SubRegion : R)
+    findScops(*SubRegion);
+
+  // Try to expand regions.
+  //
+  // As the region tree normally only contains canonical regions, non canonical
+  // regions that form a Scop are not found. Therefore, those non canonical
+  // regions are checked by expanding the canonical ones.
+
+  std::vector<Region *> ToExpand;
+
+  for (auto &SubRegion : R)
+    ToExpand.push_back(SubRegion.get());
+
+  for (Region *CurrentRegion : ToExpand) {
+    // Skip invalid regions. Regions may become invalid, if they are element of
+    // an already expanded region.
+    if (!ValidRegions.count(CurrentRegion))
+      continue;
+
+    // Skip regions that had errors.
+    bool HadErrors = lookupRejectionLog(CurrentRegion)->hasErrors();
+    if (HadErrors)
+      continue;
+
+    Region *ExpandedR = expandRegion(*CurrentRegion);
+
+    if (!ExpandedR)
+      continue;
+
+    R.addSubRegion(ExpandedR, true);
+    ValidRegions.insert(ExpandedR);
+    removeCachedResults(*CurrentRegion);
+    removeCachedResultsRecursively(*ExpandedR);
+  }
+}
+
+bool ScopDetection::allBlocksValid(DetectionContext &Context) const {
+  Region &CurRegion = Context.CurRegion;
+
+  for (const BasicBlock *BB : CurRegion.blocks()) {
+    Loop *L = LI.getLoopFor(BB);
+    if (L && L->getHeader() == BB) {
+      if (CurRegion.contains(L)) {
+        if (!isValidLoop(L, Context) && !KeepGoing)
+          return false;
+      } else {
+        SmallVector<BasicBlock *, 1> Latches;
+        L->getLoopLatches(Latches);
+        for (BasicBlock *Latch : Latches)
+          if (CurRegion.contains(Latch))
+            return invalid<ReportLoopOnlySomeLatches>(Context, /*Assert=*/true,
+                                                      L);
+      }
+    }
+  }
+
+  for (BasicBlock *BB : CurRegion.blocks()) {
+    bool IsErrorBlock = isErrorBlock(*BB, CurRegion, LI, DT);
+
+    // Also check exception blocks (and possibly register them as non-affine
+    // regions). Even though exception blocks are not modeled, we use them
+    // to forward-propagate domain constraints during ScopInfo construction.
+    if (!isValidCFG(*BB, false, IsErrorBlock, Context) && !KeepGoing)
+      return false;
+
+    if (IsErrorBlock)
+      continue;
+
+    for (BasicBlock::iterator I = BB->begin(), E = --BB->end(); I != E; ++I)
+      if (!isValidInstruction(*I, Context) && !KeepGoing)
+        return false;
+  }
+
+  if (!hasAffineMemoryAccesses(Context))
+    return false;
+
+  return true;
+}
+
+bool ScopDetection::hasSufficientCompute(DetectionContext &Context,
+                                         int NumLoops) const {
+  int InstCount = 0;
+
+  if (NumLoops == 0)
+    return false;
+
+  for (auto *BB : Context.CurRegion.blocks())
+    if (Context.CurRegion.contains(LI.getLoopFor(BB)))
+      InstCount += BB->size();
+
+  InstCount = InstCount / NumLoops;
+
+  return InstCount >= ProfitabilityMinPerLoopInstructions;
+}
+
+bool ScopDetection::hasPossiblyDistributableLoop(
+    DetectionContext &Context) const {
+  for (auto *BB : Context.CurRegion.blocks()) {
+    auto *L = LI.getLoopFor(BB);
+    if (!Context.CurRegion.contains(L))
+      continue;
+    if (Context.BoxedLoopsSet.count(L))
+      continue;
+    unsigned StmtsWithStoresInLoops = 0;
+    for (auto *LBB : L->blocks()) {
+      bool MemStore = false;
+      for (auto &I : *LBB)
+        MemStore |= isa<StoreInst>(&I);
+      StmtsWithStoresInLoops += MemStore;
+    }
+    return (StmtsWithStoresInLoops > 1);
+  }
+  return false;
+}
+
+bool ScopDetection::isProfitableRegion(DetectionContext &Context) const {
+  Region &CurRegion = Context.CurRegion;
+
+  if (PollyProcessUnprofitable)
+    return true;
+
+  // We can probably not do a lot on scops that only write or only read
+  // data.
+  if (!Context.hasStores || !Context.hasLoads)
+    return invalid<ReportUnprofitable>(Context, /*Assert=*/true, &CurRegion);
+
+  int NumLoops =
+      countBeneficialLoops(&CurRegion, SE, LI, MIN_LOOP_TRIP_COUNT).NumLoops;
+  int NumAffineLoops = NumLoops - Context.BoxedLoopsSet.size();
+
+  // Scops with at least two loops may allow either loop fusion or tiling and
+  // are consequently interesting to look at.
+  if (NumAffineLoops >= 2)
+    return true;
+
+  // A loop with multiple non-trivial blocks might be amendable to distribution.
+  if (NumAffineLoops == 1 && hasPossiblyDistributableLoop(Context))
+    return true;
+
+  // Scops that contain a loop with a non-trivial amount of computation per
+  // loop-iteration are interesting as we may be able to parallelize such
+  // loops. Individual loops that have only a small amount of computation
+  // per-iteration are performance-wise very fragile as any change to the
+  // loop induction variables may affect performance. To not cause spurious
+  // performance regressions, we do not consider such loops.
+  if (NumAffineLoops == 1 && hasSufficientCompute(Context, NumLoops))
+    return true;
+
+  return invalid<ReportUnprofitable>(Context, /*Assert=*/true, &CurRegion);
+}
+
+bool ScopDetection::isValidRegion(DetectionContext &Context) const {
+  Region &CurRegion = Context.CurRegion;
+
+  DEBUG(dbgs() << "Checking region: " << CurRegion.getNameStr() << "\n\t");
+
+  if (!PollyAllowFullFunction && CurRegion.isTopLevelRegion()) {
+    DEBUG(dbgs() << "Top level region is invalid\n");
+    return false;
+  }
+
+  DebugLoc DbgLoc;
+  if (CurRegion.getExit() &&
+      isa<UnreachableInst>(CurRegion.getExit()->getTerminator())) {
+    DEBUG(dbgs() << "Unreachable in exit\n");
+    return invalid<ReportUnreachableInExit>(Context, /*Assert=*/true,
+                                            CurRegion.getExit(), DbgLoc);
+  }
+
+  if (!CurRegion.getEntry()->getName().count(OnlyRegion)) {
+    DEBUG({
+      dbgs() << "Region entry does not match -polly-region-only";
+      dbgs() << "\n";
+    });
+    return false;
+  }
+
+  // SCoP cannot contain the entry block of the function, because we need
+  // to insert alloca instruction there when translate scalar to array.
+  if (!PollyAllowFullFunction &&
+      CurRegion.getEntry() ==
+          &(CurRegion.getEntry()->getParent()->getEntryBlock()))
+    return invalid<ReportEntry>(Context, /*Assert=*/true, CurRegion.getEntry());
+
+  if (!allBlocksValid(Context))
+    return false;
+
+  if (!isReducibleRegion(CurRegion, DbgLoc))
+    return invalid<ReportIrreducibleRegion>(Context, /*Assert=*/true,
+                                            &CurRegion, DbgLoc);
+
+  DEBUG(dbgs() << "OK\n");
+  return true;
+}
+
+void ScopDetection::markFunctionAsInvalid(Function *F) {
+  F->addFnAttr(PollySkipFnAttr);
+}
+
+bool ScopDetection::isValidFunction(Function &F) {
+  return !F.hasFnAttribute(PollySkipFnAttr);
+}
+
+void ScopDetection::printLocations(Function &F) {
+  for (const Region *R : *this) {
+    unsigned LineEntry, LineExit;
+    std::string FileName;
+
+    getDebugLocation(R, LineEntry, LineExit, FileName);
+    DiagnosticScopFound Diagnostic(F, FileName, LineEntry, LineExit);
+    F.getContext().diagnose(Diagnostic);
+  }
+}
+
+void ScopDetection::emitMissedRemarks(const Function &F) {
+  for (auto &DIt : DetectionContextMap) {
+    auto &DC = DIt.getSecond();
+    if (DC.Log.hasErrors())
+      emitRejectionRemarks(DIt.getFirst(), DC.Log, ORE);
+  }
+}
+
+bool ScopDetection::isReducibleRegion(Region &R, DebugLoc &DbgLoc) const {
+  /// Enum for coloring BBs in Region.
+  ///
+  /// WHITE - Unvisited BB in DFS walk.
+  /// GREY - BBs which are currently on the DFS stack for processing.
+  /// BLACK - Visited and completely processed BB.
+  enum Color { WHITE, GREY, BLACK };
+
+  BasicBlock *REntry = R.getEntry();
+  BasicBlock *RExit = R.getExit();
+  // Map to match the color of a BasicBlock during the DFS walk.
+  DenseMap<const BasicBlock *, Color> BBColorMap;
+  // Stack keeping track of current BB and index of next child to be processed.
+  std::stack<std::pair<BasicBlock *, unsigned>> DFSStack;
+
+  unsigned AdjacentBlockIndex = 0;
+  BasicBlock *CurrBB, *SuccBB;
+  CurrBB = REntry;
+
+  // Initialize the map for all BB with WHITE color.
+  for (auto *BB : R.blocks())
+    BBColorMap[BB] = WHITE;
+
+  // Process the entry block of the Region.
+  BBColorMap[CurrBB] = GREY;
+  DFSStack.push(std::make_pair(CurrBB, 0));
+
+  while (!DFSStack.empty()) {
+    // Get next BB on stack to be processed.
+    CurrBB = DFSStack.top().first;
+    AdjacentBlockIndex = DFSStack.top().second;
+    DFSStack.pop();
+
+    // Loop to iterate over the successors of current BB.
+    const TerminatorInst *TInst = CurrBB->getTerminator();
+    unsigned NSucc = TInst->getNumSuccessors();
+    for (unsigned I = AdjacentBlockIndex; I < NSucc;
+         ++I, ++AdjacentBlockIndex) {
+      SuccBB = TInst->getSuccessor(I);
+
+      // Checks for region exit block and self-loops in BB.
+      if (SuccBB == RExit || SuccBB == CurrBB)
+        continue;
+
+      // WHITE indicates an unvisited BB in DFS walk.
+      if (BBColorMap[SuccBB] == WHITE) {
+        // Push the current BB and the index of the next child to be visited.
+        DFSStack.push(std::make_pair(CurrBB, I + 1));
+        // Push the next BB to be processed.
+        DFSStack.push(std::make_pair(SuccBB, 0));
+        // First time the BB is being processed.
+        BBColorMap[SuccBB] = GREY;
+        break;
+      } else if (BBColorMap[SuccBB] == GREY) {
+        // GREY indicates a loop in the control flow.
+        // If the destination dominates the source, it is a natural loop
+        // else, an irreducible control flow in the region is detected.
+        if (!DT.dominates(SuccBB, CurrBB)) {
+          // Get debug info of instruction which causes irregular control flow.
+          DbgLoc = TInst->getDebugLoc();
+          return false;
+        }
+      }
+    }
+
+    // If all children of current BB have been processed,
+    // then mark that BB as fully processed.
+    if (AdjacentBlockIndex == NSucc)
+      BBColorMap[CurrBB] = BLACK;
+  }
+
+  return true;
+}
+
+static void updateLoopCountStatistic(ScopDetection::LoopStats Stats,
+                                     bool OnlyProfitable) {
+  if (!OnlyProfitable) {
+    NumLoopsInScop += Stats.NumLoops;
+    MaxNumLoopsInScop =
+        std::max(MaxNumLoopsInScop.getValue(), (unsigned)Stats.NumLoops);
+    if (Stats.MaxDepth == 1)
+      NumScopsDepthOne++;
+    else if (Stats.MaxDepth == 2)
+      NumScopsDepthTwo++;
+    else if (Stats.MaxDepth == 3)
+      NumScopsDepthThree++;
+    else if (Stats.MaxDepth == 4)
+      NumScopsDepthFour++;
+    else if (Stats.MaxDepth == 5)
+      NumScopsDepthFive++;
+    else
+      NumScopsDepthLarger++;
+  } else {
+    NumLoopsInProfScop += Stats.NumLoops;
+    MaxNumLoopsInProfScop =
+        std::max(MaxNumLoopsInProfScop.getValue(), (unsigned)Stats.NumLoops);
+    if (Stats.MaxDepth == 1)
+      NumProfScopsDepthOne++;
+    else if (Stats.MaxDepth == 2)
+      NumProfScopsDepthTwo++;
+    else if (Stats.MaxDepth == 3)
+      NumProfScopsDepthThree++;
+    else if (Stats.MaxDepth == 4)
+      NumProfScopsDepthFour++;
+    else if (Stats.MaxDepth == 5)
+      NumProfScopsDepthFive++;
+    else
+      NumProfScopsDepthLarger++;
+  }
+}
+
+ScopDetection::DetectionContext *
+ScopDetection::getDetectionContext(const Region *R) const {
+  auto DCMIt = DetectionContextMap.find(getBBPairForRegion(R));
+  if (DCMIt == DetectionContextMap.end())
+    return nullptr;
+  return &DCMIt->second;
+}
+
+const RejectLog *ScopDetection::lookupRejectionLog(const Region *R) const {
+  const DetectionContext *DC = getDetectionContext(R);
+  return DC ? &DC->Log : nullptr;
+}
+
+void ScopDetection::verifyRegion(const Region &R) const {
+  assert(isMaxRegionInScop(R) && "Expect R is a valid region.");
+
+  DetectionContext Context(const_cast<Region &>(R), AA, true /*verifying*/);
+  isValidRegion(Context);
+}
+
+void ScopDetection::verifyAnalysis() const {
+  if (!VerifyScops)
+    return;
+
+  for (const Region *R : ValidRegions)
+    verifyRegion(*R);
+}
+
+bool ScopDetectionWrapperPass::runOnFunction(Function &F) {
+  auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+  auto &RI = getAnalysis<RegionInfoPass>().getRegionInfo();
+  auto &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
+  auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
+  auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+  auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
+  Result.reset(new ScopDetection(F, DT, SE, LI, RI, AA, ORE));
+  return false;
+}
+
+void ScopDetectionWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequired<LoopInfoWrapperPass>();
+  AU.addRequiredTransitive<ScalarEvolutionWrapperPass>();
+  AU.addRequired<DominatorTreeWrapperPass>();
+  AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
+  // We also need AA and RegionInfo when we are verifying analysis.
+  AU.addRequiredTransitive<AAResultsWrapperPass>();
+  AU.addRequiredTransitive<RegionInfoPass>();
+  AU.setPreservesAll();
+}
+
+void ScopDetectionWrapperPass::print(raw_ostream &OS, const Module *) const {
+  for (const Region *R : Result->ValidRegions)
+    OS << "Valid Region for Scop: " << R->getNameStr() << '\n';
+
+  OS << "\n";
+}
+
+ScopDetectionWrapperPass::ScopDetectionWrapperPass() : FunctionPass(ID) {
+  // Disable runtime alias checks if we ignore aliasing all together.
+  if (IgnoreAliasing)
+    PollyUseRuntimeAliasChecks = false;
+}
+
+ScopAnalysis::ScopAnalysis() {
+  // Disable runtime alias checks if we ignore aliasing all together.
+  if (IgnoreAliasing)
+    PollyUseRuntimeAliasChecks = false;
+}
+
+void ScopDetectionWrapperPass::releaseMemory() { Result.reset(); }
+
+char ScopDetectionWrapperPass::ID;
+
+AnalysisKey ScopAnalysis::Key;
+
+ScopDetection ScopAnalysis::run(Function &F, FunctionAnalysisManager &FAM) {
+  auto &LI = FAM.getResult<LoopAnalysis>(F);
+  auto &RI = FAM.getResult<RegionInfoAnalysis>(F);
+  auto &AA = FAM.getResult<AAManager>(F);
+  auto &SE = FAM.getResult<ScalarEvolutionAnalysis>(F);
+  auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
+  auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
+  return {F, DT, SE, LI, RI, AA, ORE};
+}
+
+PreservedAnalyses ScopAnalysisPrinterPass::run(Function &F,
+                                               FunctionAnalysisManager &FAM) {
+  OS << "Detected Scops in Function " << F.getName() << "\n";
+  auto &SD = FAM.getResult<ScopAnalysis>(F);
+  for (const Region *R : SD.ValidRegions)
+    OS << "Valid Region for Scop: " << R->getNameStr() << '\n';
+
+  OS << "\n";
+  return PreservedAnalyses::all();
+}
+
+Pass *polly::createScopDetectionWrapperPassPass() {
+  return new ScopDetectionWrapperPass();
+}
+
+INITIALIZE_PASS_BEGIN(ScopDetectionWrapperPass, "polly-detect",
+                      "Polly - Detect static control parts (SCoPs)", false,
+                      false);
+INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass);
+INITIALIZE_PASS_END(ScopDetectionWrapperPass, "polly-detect",
+                    "Polly - Detect static control parts (SCoPs)", false, false)
diff --git a/final/lib/Analysis/ScopDetectionDiagnostic.cpp b/final/lib/Analysis/ScopDetectionDiagnostic.cpp
new file mode 100644
index 0000000..7135262
--- /dev/null
+++ b/final/lib/Analysis/ScopDetectionDiagnostic.cpp
@@ -0,0 +1,780 @@
+//===- ScopDetectionDiagnostic.cpp - Error diagnostics --------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Small set of diagnostic helper classes to encapsulate any errors occurred
+// during the detection of Scops.
+//
+// The ScopDetection defines a set of error classes (via Statistic variables)
+// that groups a number of individual errors into a group, e.g. non-affinity
+// related errors.
+// On error we generate an object that carries enough additional information
+// to diagnose the error and generate a helpful error message.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/ScopDetectionDiagnostic.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Analysis/AliasSetTracker.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <string>
+#include <utility>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "polly-detect"
+
+#define SCOP_STAT(NAME, DESC)                                                  \
+  { "polly-detect", "NAME", "Number of rejected regions: " DESC, {0}, false }
+
+Statistic RejectStatistics[] = {
+    SCOP_STAT(CFG, ""),
+    SCOP_STAT(InvalidTerminator, "Unsupported terminator instruction"),
+    SCOP_STAT(UnreachableInExit, "Unreachable in exit block"),
+    SCOP_STAT(IrreducibleRegion, "Irreducible loops"),
+    SCOP_STAT(LastCFG, ""),
+    SCOP_STAT(AffFunc, ""),
+    SCOP_STAT(UndefCond, "Undefined branch condition"),
+    SCOP_STAT(InvalidCond, "Non-integer branch condition"),
+    SCOP_STAT(UndefOperand, "Undefined operands in comparison"),
+    SCOP_STAT(NonAffBranch, "Non-affine branch condition"),
+    SCOP_STAT(NoBasePtr, "No base pointer"),
+    SCOP_STAT(UndefBasePtr, "Undefined base pointer"),
+    SCOP_STAT(VariantBasePtr, "Variant base pointer"),
+    SCOP_STAT(NonAffineAccess, "Non-affine memory accesses"),
+    SCOP_STAT(DifferentElementSize, "Accesses with differing sizes"),
+    SCOP_STAT(LastAffFunc, ""),
+    SCOP_STAT(LoopBound, "Uncomputable loop bounds"),
+    SCOP_STAT(LoopHasNoExit, "Loop without exit"),
+    SCOP_STAT(LoopOnlySomeLatches, "Not all loop latches in scop"),
+    SCOP_STAT(FuncCall, "Function call with side effects"),
+    SCOP_STAT(NonSimpleMemoryAccess,
+              "Compilated access semantics (volatile or atomic)"),
+    SCOP_STAT(Alias, "Base address aliasing"),
+    SCOP_STAT(Other, ""),
+    SCOP_STAT(IntToPtr, "Integer to pointer conversions"),
+    SCOP_STAT(Alloca, "Stack allocations"),
+    SCOP_STAT(UnknownInst, "Unknown Instructions"),
+    SCOP_STAT(Entry, "Contains entry block"),
+    SCOP_STAT(Unprofitable, "Assumed to be unprofitable"),
+    SCOP_STAT(LastOther, ""),
+};
+
+namespace polly {
+
+/// Small string conversion via raw_string_stream.
+template <typename T> std::string operator+(Twine LHS, const T &RHS) {
+  std::string Buf;
+  raw_string_ostream fmt(Buf);
+  fmt << RHS;
+  fmt.flush();
+
+  return LHS.concat(Buf).str();
+}
+
+} // namespace polly
+
+namespace llvm {
+
+// Lexicographic order on (line, col) of our debug locations.
+static bool operator<(const DebugLoc &LHS, const DebugLoc &RHS) {
+  return LHS.getLine() < RHS.getLine() ||
+         (LHS.getLine() == RHS.getLine() && LHS.getCol() < RHS.getCol());
+}
+
+} // namespace llvm
+
+namespace polly {
+
+BBPair getBBPairForRegion(const Region *R) {
+  return std::make_pair(R->getEntry(), R->getExit());
+}
+
+void getDebugLocations(const BBPair &P, DebugLoc &Begin, DebugLoc &End) {
+  SmallPtrSet<BasicBlock *, 32> Seen;
+  SmallVector<BasicBlock *, 32> Todo;
+  Todo.push_back(P.first);
+  while (!Todo.empty()) {
+    auto *BB = Todo.pop_back_val();
+    if (BB == P.second)
+      continue;
+    if (!Seen.insert(BB).second)
+      continue;
+    Todo.append(succ_begin(BB), succ_end(BB));
+    for (const Instruction &Inst : *BB) {
+      DebugLoc DL = Inst.getDebugLoc();
+      if (!DL)
+        continue;
+
+      Begin = Begin ? std::min(Begin, DL) : DL;
+      End = End ? std::max(End, DL) : DL;
+    }
+  }
+}
+
+void emitRejectionRemarks(const BBPair &P, const RejectLog &Log,
+                          OptimizationRemarkEmitter &ORE) {
+  DebugLoc Begin, End;
+  getDebugLocations(P, Begin, End);
+
+  ORE.emit(
+      OptimizationRemarkMissed(DEBUG_TYPE, "RejectionErrors", Begin, P.first)
+      << "The following errors keep this region from being a Scop.");
+
+  for (RejectReasonPtr RR : Log) {
+
+    if (const DebugLoc &Loc = RR->getDebugLoc())
+      ORE.emit(OptimizationRemarkMissed(DEBUG_TYPE, RR->getRemarkName(), Loc,
+                                        RR->getRemarkBB())
+               << RR->getEndUserMessage());
+    else
+      ORE.emit(OptimizationRemarkMissed(DEBUG_TYPE, RR->getRemarkName(), Begin,
+                                        RR->getRemarkBB())
+               << RR->getEndUserMessage());
+  }
+
+  /* Check to see if Region is a top level region, getExit = NULL*/
+  if (P.second)
+    ORE.emit(
+        OptimizationRemarkMissed(DEBUG_TYPE, "InvalidScopEnd", End, P.second)
+        << "Invalid Scop candidate ends here.");
+  else
+    ORE.emit(
+        OptimizationRemarkMissed(DEBUG_TYPE, "InvalidScopEnd", End, P.first)
+        << "Invalid Scop candidate ends here.");
+}
+
+//===----------------------------------------------------------------------===//
+// RejectReason.
+
+RejectReason::RejectReason(RejectReasonKind K) : Kind(K) {
+  RejectStatistics[static_cast<int>(K)]++;
+}
+
+const DebugLoc RejectReason::Unknown = DebugLoc();
+
+const DebugLoc &RejectReason::getDebugLoc() const {
+  // Allocate an empty DebugLoc and return it a reference to it.
+  return Unknown;
+}
+
+// RejectLog.
+void RejectLog::print(raw_ostream &OS, int level) const {
+  int j = 0;
+  for (auto Reason : ErrorReports)
+    OS.indent(level) << "[" << j++ << "] " << Reason->getMessage() << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// ReportCFG.
+
+ReportCFG::ReportCFG(const RejectReasonKind K) : RejectReason(K) {}
+
+bool ReportCFG::classof(const RejectReason *RR) {
+  return RR->getKind() >= RejectReasonKind::CFG &&
+         RR->getKind() <= RejectReasonKind::LastCFG;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportInvalidTerminator.
+
+std::string ReportInvalidTerminator::getRemarkName() const {
+  return "InvalidTerminator";
+}
+
+const Value *ReportInvalidTerminator::getRemarkBB() const { return BB; }
+
+std::string ReportInvalidTerminator::getMessage() const {
+  return ("Invalid instruction terminates BB: " + BB->getName()).str();
+}
+
+const DebugLoc &ReportInvalidTerminator::getDebugLoc() const {
+  return BB->getTerminator()->getDebugLoc();
+}
+
+bool ReportInvalidTerminator::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::InvalidTerminator;
+}
+
+//===----------------------------------------------------------------------===//
+// UnreachableInExit.
+
+std::string ReportUnreachableInExit::getRemarkName() const {
+  return "UnreachableInExit";
+}
+
+const Value *ReportUnreachableInExit::getRemarkBB() const { return BB; }
+
+std::string ReportUnreachableInExit::getMessage() const {
+  std::string BBName = BB->getName();
+  return "Unreachable in exit block" + BBName;
+}
+
+const DebugLoc &ReportUnreachableInExit::getDebugLoc() const { return DbgLoc; }
+
+std::string ReportUnreachableInExit::getEndUserMessage() const {
+  return "Unreachable in exit block.";
+}
+
+bool ReportUnreachableInExit::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::UnreachableInExit;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportIrreducibleRegion.
+
+std::string ReportIrreducibleRegion::getRemarkName() const {
+  return "IrreducibleRegion";
+}
+
+const Value *ReportIrreducibleRegion::getRemarkBB() const {
+  return R->getEntry();
+}
+
+std::string ReportIrreducibleRegion::getMessage() const {
+  return "Irreducible region encountered: " + R->getNameStr();
+}
+
+const DebugLoc &ReportIrreducibleRegion::getDebugLoc() const { return DbgLoc; }
+
+std::string ReportIrreducibleRegion::getEndUserMessage() const {
+  return "Irreducible region encountered in control flow.";
+}
+
+bool ReportIrreducibleRegion::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::IrreducibleRegion;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportAffFunc.
+
+ReportAffFunc::ReportAffFunc(const RejectReasonKind K, const Instruction *Inst)
+    : RejectReason(K), Inst(Inst) {}
+
+bool ReportAffFunc::classof(const RejectReason *RR) {
+  return RR->getKind() >= RejectReasonKind::AffFunc &&
+         RR->getKind() <= RejectReasonKind::LastAffFunc;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportUndefCond.
+
+std::string ReportUndefCond::getRemarkName() const { return "UndefCond"; }
+
+const Value *ReportUndefCond::getRemarkBB() const { return BB; }
+
+std::string ReportUndefCond::getMessage() const {
+  return ("Condition based on 'undef' value in BB: " + BB->getName()).str();
+}
+
+bool ReportUndefCond::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::UndefCond;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportInvalidCond.
+
+std::string ReportInvalidCond::getRemarkName() const { return "InvalidCond"; }
+
+const Value *ReportInvalidCond::getRemarkBB() const { return BB; }
+
+std::string ReportInvalidCond::getMessage() const {
+  return ("Condition in BB '" + BB->getName()).str() +
+         "' neither constant nor an icmp instruction";
+}
+
+bool ReportInvalidCond::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::InvalidCond;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportUndefOperand.
+
+std::string ReportUndefOperand::getRemarkName() const { return "UndefOperand"; }
+
+const Value *ReportUndefOperand::getRemarkBB() const { return BB; }
+
+std::string ReportUndefOperand::getMessage() const {
+  return ("undef operand in branch at BB: " + BB->getName()).str();
+}
+
+bool ReportUndefOperand::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::UndefOperand;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportNonAffBranch.
+
+std::string ReportNonAffBranch::getRemarkName() const { return "NonAffBranch"; }
+
+const Value *ReportNonAffBranch::getRemarkBB() const { return BB; }
+
+std::string ReportNonAffBranch::getMessage() const {
+  return ("Non affine branch in BB '" + BB->getName()).str() +
+         "' with LHS: " + *LHS + " and RHS: " + *RHS;
+}
+
+bool ReportNonAffBranch::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::NonAffBranch;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportNoBasePtr.
+
+std::string ReportNoBasePtr::getRemarkName() const { return "NoBasePtr"; }
+
+const Value *ReportNoBasePtr::getRemarkBB() const { return Inst->getParent(); }
+
+std::string ReportNoBasePtr::getMessage() const { return "No base pointer"; }
+
+bool ReportNoBasePtr::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::NoBasePtr;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportUndefBasePtr.
+
+std::string ReportUndefBasePtr::getRemarkName() const { return "UndefBasePtr"; }
+
+const Value *ReportUndefBasePtr::getRemarkBB() const {
+  return Inst->getParent();
+}
+
+std::string ReportUndefBasePtr::getMessage() const {
+  return "Undefined base pointer";
+}
+
+bool ReportUndefBasePtr::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::UndefBasePtr;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportVariantBasePtr.
+
+std::string ReportVariantBasePtr::getRemarkName() const {
+  return "VariantBasePtr";
+}
+
+const Value *ReportVariantBasePtr::getRemarkBB() const {
+  return Inst->getParent();
+}
+
+std::string ReportVariantBasePtr::getMessage() const {
+  return "Base address not invariant in current region:" + *BaseValue;
+}
+
+std::string ReportVariantBasePtr::getEndUserMessage() const {
+  return "The base address of this array is not invariant inside the loop";
+}
+
+bool ReportVariantBasePtr::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::VariantBasePtr;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportDifferentArrayElementSize
+
+std::string ReportDifferentArrayElementSize::getRemarkName() const {
+  return "DifferentArrayElementSize";
+}
+
+const Value *ReportDifferentArrayElementSize::getRemarkBB() const {
+  return Inst->getParent();
+}
+
+std::string ReportDifferentArrayElementSize::getMessage() const {
+  return "Access to one array through data types of different size";
+}
+
+bool ReportDifferentArrayElementSize::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::DifferentElementSize;
+}
+
+std::string ReportDifferentArrayElementSize::getEndUserMessage() const {
+  StringRef BaseName = BaseValue->getName();
+  std::string Name = BaseName.empty() ? "UNKNOWN" : BaseName;
+  return "The array \"" + Name +
+         "\" is accessed through elements that differ "
+         "in size";
+}
+
+//===----------------------------------------------------------------------===//
+// ReportNonAffineAccess.
+
+std::string ReportNonAffineAccess::getRemarkName() const {
+  return "NonAffineAccess";
+}
+
+const Value *ReportNonAffineAccess::getRemarkBB() const {
+  return Inst->getParent();
+}
+
+std::string ReportNonAffineAccess::getMessage() const {
+  return "Non affine access function: " + *AccessFunction;
+}
+
+bool ReportNonAffineAccess::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::NonAffineAccess;
+}
+
+std::string ReportNonAffineAccess::getEndUserMessage() const {
+  StringRef BaseName = BaseValue->getName();
+  std::string Name = BaseName.empty() ? "UNKNOWN" : BaseName;
+  return "The array subscript of \"" + Name + "\" is not affine";
+}
+
+//===----------------------------------------------------------------------===//
+// ReportLoopBound.
+
+ReportLoopBound::ReportLoopBound(Loop *L, const SCEV *LoopCount)
+    : RejectReason(RejectReasonKind::LoopBound), L(L), LoopCount(LoopCount),
+      Loc(L->getStartLoc()) {}
+
+std::string ReportLoopBound::getRemarkName() const { return "LoopBound"; }
+
+const Value *ReportLoopBound::getRemarkBB() const { return L->getHeader(); }
+
+std::string ReportLoopBound::getMessage() const {
+  return "Non affine loop bound '" + *LoopCount +
+         "' in loop: " + L->getHeader()->getName();
+}
+
+const DebugLoc &ReportLoopBound::getDebugLoc() const { return Loc; }
+
+bool ReportLoopBound::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::LoopBound;
+}
+
+std::string ReportLoopBound::getEndUserMessage() const {
+  return "Failed to derive an affine function from the loop bounds.";
+}
+
+//===----------------------------------------------------------------------===//
+// ReportLoopHasNoExit.
+
+std::string ReportLoopHasNoExit::getRemarkName() const {
+  return "LoopHasNoExit";
+}
+
+const Value *ReportLoopHasNoExit::getRemarkBB() const { return L->getHeader(); }
+
+std::string ReportLoopHasNoExit::getMessage() const {
+  return "Loop " + L->getHeader()->getName() + " has no exit.";
+}
+
+bool ReportLoopHasNoExit::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::LoopHasNoExit;
+}
+
+const DebugLoc &ReportLoopHasNoExit::getDebugLoc() const { return Loc; }
+
+std::string ReportLoopHasNoExit::getEndUserMessage() const {
+  return "Loop cannot be handled because it has no exit.";
+}
+
+//===----------------------------------------------------------------------===//
+// ReportLoopOnlySomeLatches
+
+std::string ReportLoopOnlySomeLatches::getRemarkName() const {
+  return "LoopHasNoExit";
+}
+
+const Value *ReportLoopOnlySomeLatches::getRemarkBB() const {
+  return L->getHeader();
+}
+
+std::string ReportLoopOnlySomeLatches::getMessage() const {
+  return "Not all latches of loop " + L->getHeader()->getName() +
+         " part of scop.";
+}
+
+bool ReportLoopOnlySomeLatches::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::LoopHasNoExit;
+}
+
+const DebugLoc &ReportLoopOnlySomeLatches::getDebugLoc() const { return Loc; }
+
+std::string ReportLoopOnlySomeLatches::getEndUserMessage() const {
+  return "Loop cannot be handled because not all latches are part of loop "
+         "region.";
+}
+
+//===----------------------------------------------------------------------===//
+// ReportFuncCall.
+
+ReportFuncCall::ReportFuncCall(Instruction *Inst)
+    : RejectReason(RejectReasonKind::FuncCall), Inst(Inst) {}
+
+std::string ReportFuncCall::getRemarkName() const { return "FuncCall"; }
+
+const Value *ReportFuncCall::getRemarkBB() const { return Inst->getParent(); }
+
+std::string ReportFuncCall::getMessage() const {
+  return "Call instruction: " + *Inst;
+}
+
+const DebugLoc &ReportFuncCall::getDebugLoc() const {
+  return Inst->getDebugLoc();
+}
+
+std::string ReportFuncCall::getEndUserMessage() const {
+  return "This function call cannot be handled. "
+         "Try to inline it.";
+}
+
+bool ReportFuncCall::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::FuncCall;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportNonSimpleMemoryAccess
+
+ReportNonSimpleMemoryAccess::ReportNonSimpleMemoryAccess(Instruction *Inst)
+    : ReportOther(RejectReasonKind::NonSimpleMemoryAccess), Inst(Inst) {}
+
+std::string ReportNonSimpleMemoryAccess::getRemarkName() const {
+  return "NonSimpleMemoryAccess";
+}
+
+const Value *ReportNonSimpleMemoryAccess::getRemarkBB() const {
+  return Inst->getParent();
+}
+
+std::string ReportNonSimpleMemoryAccess::getMessage() const {
+  return "Non-simple memory access: " + *Inst;
+}
+
+const DebugLoc &ReportNonSimpleMemoryAccess::getDebugLoc() const {
+  return Inst->getDebugLoc();
+}
+
+std::string ReportNonSimpleMemoryAccess::getEndUserMessage() const {
+  return "Volatile memory accesses or memory accesses for atomic types "
+         "are not supported.";
+}
+
+bool ReportNonSimpleMemoryAccess::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::NonSimpleMemoryAccess;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportAlias.
+
+ReportAlias::ReportAlias(Instruction *Inst, AliasSet &AS)
+    : RejectReason(RejectReasonKind::Alias), Inst(Inst) {
+  for (const auto &I : AS)
+    Pointers.push_back(I.getValue());
+}
+
+std::string ReportAlias::formatInvalidAlias(std::string Prefix,
+                                            std::string Suffix) const {
+  std::string Message;
+  raw_string_ostream OS(Message);
+
+  OS << Prefix;
+
+  for (PointerSnapshotTy::const_iterator PI = Pointers.begin(),
+                                         PE = Pointers.end();
+       ;) {
+    const Value *V = *PI;
+    assert(V && "Diagnostic info does not match found LLVM-IR anymore.");
+
+    if (V->getName().empty())
+      OS << "\" <unknown> \"";
+    else
+      OS << "\"" << V->getName() << "\"";
+
+    ++PI;
+
+    if (PI != PE)
+      OS << ", ";
+    else
+      break;
+  }
+
+  OS << Suffix;
+
+  return OS.str();
+}
+
+std::string ReportAlias::getRemarkName() const { return "Alias"; }
+
+const Value *ReportAlias::getRemarkBB() const { return Inst->getParent(); }
+
+std::string ReportAlias::getMessage() const {
+  return formatInvalidAlias("Possible aliasing: ");
+}
+
+std::string ReportAlias::getEndUserMessage() const {
+  return formatInvalidAlias("Accesses to the arrays ",
+                            " may access the same memory.");
+}
+
+const DebugLoc &ReportAlias::getDebugLoc() const { return Inst->getDebugLoc(); }
+
+bool ReportAlias::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::Alias;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportOther.
+
+std::string ReportOther::getRemarkName() const { return "UnknownRejectReason"; }
+
+std::string ReportOther::getMessage() const { return "Unknown reject reason"; }
+
+ReportOther::ReportOther(const RejectReasonKind K) : RejectReason(K) {}
+
+bool ReportOther::classof(const RejectReason *RR) {
+  return RR->getKind() >= RejectReasonKind::Other &&
+         RR->getKind() <= RejectReasonKind::LastOther;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportIntToPtr.
+ReportIntToPtr::ReportIntToPtr(Instruction *BaseValue)
+    : ReportOther(RejectReasonKind::IntToPtr), BaseValue(BaseValue) {}
+
+std::string ReportIntToPtr::getRemarkName() const { return "IntToPtr"; }
+
+const Value *ReportIntToPtr::getRemarkBB() const {
+  return BaseValue->getParent();
+}
+
+std::string ReportIntToPtr::getMessage() const {
+  return "Find bad intToptr prt: " + *BaseValue;
+}
+
+const DebugLoc &ReportIntToPtr::getDebugLoc() const {
+  return BaseValue->getDebugLoc();
+}
+
+bool ReportIntToPtr::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::IntToPtr;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportAlloca.
+
+ReportAlloca::ReportAlloca(Instruction *Inst)
+    : ReportOther(RejectReasonKind::Alloca), Inst(Inst) {}
+
+std::string ReportAlloca::getRemarkName() const { return "Alloca"; }
+
+const Value *ReportAlloca::getRemarkBB() const { return Inst->getParent(); }
+
+std::string ReportAlloca::getMessage() const {
+  return "Alloca instruction: " + *Inst;
+}
+
+const DebugLoc &ReportAlloca::getDebugLoc() const {
+  return Inst->getDebugLoc();
+}
+
+bool ReportAlloca::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::Alloca;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportUnknownInst.
+
+ReportUnknownInst::ReportUnknownInst(Instruction *Inst)
+    : ReportOther(RejectReasonKind::UnknownInst), Inst(Inst) {}
+
+std::string ReportUnknownInst::getRemarkName() const { return "UnknownInst"; }
+
+const Value *ReportUnknownInst::getRemarkBB() const {
+  return Inst->getParent();
+}
+
+std::string ReportUnknownInst::getMessage() const {
+  return "Unknown instruction: " + *Inst;
+}
+
+const DebugLoc &ReportUnknownInst::getDebugLoc() const {
+  return Inst->getDebugLoc();
+}
+
+bool ReportUnknownInst::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::UnknownInst;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportEntry.
+
+ReportEntry::ReportEntry(BasicBlock *BB)
+    : ReportOther(RejectReasonKind::Entry), BB(BB) {}
+
+std::string ReportEntry::getRemarkName() const { return "Entry"; }
+
+const Value *ReportEntry::getRemarkBB() const { return BB; }
+
+std::string ReportEntry::getMessage() const {
+  return "Region containing entry block of function is invalid!";
+}
+
+std::string ReportEntry::getEndUserMessage() const {
+  return "Scop contains function entry (not yet supported).";
+}
+
+const DebugLoc &ReportEntry::getDebugLoc() const {
+  return BB->getTerminator()->getDebugLoc();
+}
+
+bool ReportEntry::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::Entry;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportUnprofitable.
+
+ReportUnprofitable::ReportUnprofitable(Region *R)
+    : ReportOther(RejectReasonKind::Unprofitable), R(R) {}
+
+std::string ReportUnprofitable::getRemarkName() const { return "Unprofitable"; }
+
+const Value *ReportUnprofitable::getRemarkBB() const { return R->getEntry(); }
+
+std::string ReportUnprofitable::getMessage() const {
+  return "Region can not profitably be optimized!";
+}
+
+std::string ReportUnprofitable::getEndUserMessage() const {
+  return "No profitable polyhedral optimization found";
+}
+
+const DebugLoc &ReportUnprofitable::getDebugLoc() const {
+  for (const BasicBlock *BB : R->blocks())
+    for (const Instruction &Inst : *BB)
+      if (const DebugLoc &DL = Inst.getDebugLoc())
+        return DL;
+
+  return R->getEntry()->getTerminator()->getDebugLoc();
+}
+
+bool ReportUnprofitable::classof(const RejectReason *RR) {
+  return RR->getKind() == RejectReasonKind::Unprofitable;
+}
+
+} // namespace polly
diff --git a/final/lib/Analysis/ScopGraphPrinter.cpp b/final/lib/Analysis/ScopGraphPrinter.cpp
new file mode 100644
index 0000000..fd4e65f
--- /dev/null
+++ b/final/lib/Analysis/ScopGraphPrinter.cpp
@@ -0,0 +1,266 @@
+//===- GraphPrinter.cpp - Create a DOT output describing the Scop. --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Create a DOT output describing the Scop.
+//
+// For each function a dot file is created that shows the control flow graph of
+// the function and highlights the detected Scops.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/LinkAllPasses.h"
+#include "polly/ScopDetection.h"
+#include "polly/Support/ScopLocation.h"
+#include "llvm/Analysis/DOTGraphTraitsPass.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/RegionIterator.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace polly;
+using namespace llvm;
+static cl::opt<std::string>
+    ViewFilter("polly-view-only",
+               cl::desc("Only view functions that match this pattern"),
+               cl::Hidden, cl::init(""), cl::ZeroOrMore);
+
+static cl::opt<bool> ViewAll("polly-view-all",
+                             cl::desc("Also show functions without any scops"),
+                             cl::Hidden, cl::init(false), cl::ZeroOrMore);
+
+namespace llvm {
+template <>
+struct GraphTraits<ScopDetection *> : public GraphTraits<RegionInfo *> {
+  static NodeRef getEntryNode(ScopDetection *SD) {
+    return GraphTraits<RegionInfo *>::getEntryNode(SD->getRI());
+  }
+  static nodes_iterator nodes_begin(ScopDetection *SD) {
+    return nodes_iterator::begin(getEntryNode(SD));
+  }
+  static nodes_iterator nodes_end(ScopDetection *SD) {
+    return nodes_iterator::end(getEntryNode(SD));
+  }
+};
+
+template <>
+struct GraphTraits<ScopDetectionWrapperPass *>
+    : public GraphTraits<ScopDetection *> {
+  static NodeRef getEntryNode(ScopDetectionWrapperPass *P) {
+    return GraphTraits<ScopDetection *>::getEntryNode(&P->getSD());
+  }
+  static nodes_iterator nodes_begin(ScopDetectionWrapperPass *P) {
+    return nodes_iterator::begin(getEntryNode(P));
+  }
+  static nodes_iterator nodes_end(ScopDetectionWrapperPass *P) {
+    return nodes_iterator::end(getEntryNode(P));
+  }
+};
+
+template <> struct DOTGraphTraits<RegionNode *> : public DefaultDOTGraphTraits {
+  DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
+
+  std::string getNodeLabel(RegionNode *Node, RegionNode *Graph) {
+    if (!Node->isSubRegion()) {
+      BasicBlock *BB = Node->getNodeAs<BasicBlock>();
+
+      if (isSimple())
+        return DOTGraphTraits<const Function *>::getSimpleNodeLabel(
+            BB, BB->getParent());
+      else
+        return DOTGraphTraits<const Function *>::getCompleteNodeLabel(
+            BB, BB->getParent());
+    }
+
+    return "Not implemented";
+  }
+};
+
+template <>
+struct DOTGraphTraits<ScopDetectionWrapperPass *>
+    : public DOTGraphTraits<RegionNode *> {
+  DOTGraphTraits(bool isSimple = false)
+      : DOTGraphTraits<RegionNode *>(isSimple) {}
+  static std::string getGraphName(ScopDetectionWrapperPass *SD) {
+    return "Scop Graph";
+  }
+
+  std::string getEdgeAttributes(RegionNode *srcNode,
+                                GraphTraits<RegionInfo *>::ChildIteratorType CI,
+                                ScopDetectionWrapperPass *P) {
+    RegionNode *destNode = *CI;
+    auto *SD = &P->getSD();
+
+    if (srcNode->isSubRegion() || destNode->isSubRegion())
+      return "";
+
+    // In case of a backedge, do not use it to define the layout of the nodes.
+    BasicBlock *srcBB = srcNode->getNodeAs<BasicBlock>();
+    BasicBlock *destBB = destNode->getNodeAs<BasicBlock>();
+
+    RegionInfo *RI = SD->getRI();
+    Region *R = RI->getRegionFor(destBB);
+
+    while (R && R->getParent())
+      if (R->getParent()->getEntry() == destBB)
+        R = R->getParent();
+      else
+        break;
+
+    if (R && R->getEntry() == destBB && R->contains(srcBB))
+      return "constraint=false";
+
+    return "";
+  }
+
+  std::string getNodeLabel(RegionNode *Node, ScopDetectionWrapperPass *P) {
+    return DOTGraphTraits<RegionNode *>::getNodeLabel(
+        Node, reinterpret_cast<RegionNode *>(
+                  P->getSD().getRI()->getTopLevelRegion()));
+  }
+
+  static std::string escapeString(std::string String) {
+    std::string Escaped;
+
+    for (const auto &C : String) {
+      if (C == '"')
+        Escaped += '\\';
+
+      Escaped += C;
+    }
+    return Escaped;
+  }
+
+  // Print the cluster of the subregions. This groups the single basic blocks
+  // and adds a different background color for each group.
+  static void printRegionCluster(const ScopDetection *SD, const Region *R,
+                                 raw_ostream &O, unsigned depth = 0) {
+    O.indent(2 * depth) << "subgraph cluster_" << static_cast<const void *>(R)
+                        << " {\n";
+    unsigned LineBegin, LineEnd;
+    std::string FileName;
+
+    getDebugLocation(R, LineBegin, LineEnd, FileName);
+
+    std::string Location;
+    if (LineBegin != (unsigned)-1) {
+      Location = escapeString(FileName + ":" + std::to_string(LineBegin) + "-" +
+                              std::to_string(LineEnd) + "\n");
+    }
+
+    std::string ErrorMessage = SD->regionIsInvalidBecause(R);
+    ErrorMessage = escapeString(ErrorMessage);
+    O.indent(2 * (depth + 1))
+        << "label = \"" << Location << ErrorMessage << "\";\n";
+
+    if (SD->isMaxRegionInScop(*R)) {
+      O.indent(2 * (depth + 1)) << "style = filled;\n";
+
+      // Set color to green.
+      O.indent(2 * (depth + 1)) << "color = 3";
+    } else {
+      O.indent(2 * (depth + 1)) << "style = solid;\n";
+
+      int color = (R->getDepth() * 2 % 12) + 1;
+
+      // We do not want green again.
+      if (color == 3)
+        color = 6;
+
+      O.indent(2 * (depth + 1)) << "color = " << color << "\n";
+    }
+
+    for (const auto &SubRegion : *R)
+      printRegionCluster(SD, SubRegion.get(), O, depth + 1);
+
+    RegionInfo *RI = R->getRegionInfo();
+
+    for (const auto &BB : R->blocks())
+      if (RI->getRegionFor(BB) == R)
+        O.indent(2 * (depth + 1))
+            << "Node"
+            << static_cast<void *>(RI->getTopLevelRegion()->getBBNode(BB))
+            << ";\n";
+
+    O.indent(2 * depth) << "}\n";
+  }
+  static void
+  addCustomGraphFeatures(const ScopDetectionWrapperPass *SD,
+                         GraphWriter<ScopDetectionWrapperPass *> &GW) {
+    raw_ostream &O = GW.getOStream();
+    O << "\tcolorscheme = \"paired12\"\n";
+    printRegionCluster(&SD->getSD(), SD->getSD().getRI()->getTopLevelRegion(),
+                       O, 4);
+  }
+};
+
+} // end namespace llvm
+
+struct ScopViewer
+    : public DOTGraphTraitsViewer<ScopDetectionWrapperPass, false> {
+  static char ID;
+  ScopViewer()
+      : DOTGraphTraitsViewer<ScopDetectionWrapperPass, false>("scops", ID) {}
+  bool processFunction(Function &F, ScopDetectionWrapperPass &SD) override {
+    if (ViewFilter != "" && !F.getName().count(ViewFilter))
+      return false;
+
+    if (ViewAll)
+      return true;
+
+    // Check that at least one scop was detected.
+    return std::distance(SD.getSD().begin(), SD.getSD().end()) > 0;
+  }
+};
+char ScopViewer::ID = 0;
+
+struct ScopOnlyViewer
+    : public DOTGraphTraitsViewer<ScopDetectionWrapperPass, true> {
+  static char ID;
+  ScopOnlyViewer()
+      : DOTGraphTraitsViewer<ScopDetectionWrapperPass, true>("scopsonly", ID) {}
+};
+char ScopOnlyViewer::ID = 0;
+
+struct ScopPrinter
+    : public DOTGraphTraitsPrinter<ScopDetectionWrapperPass, false> {
+  static char ID;
+  ScopPrinter()
+      : DOTGraphTraitsPrinter<ScopDetectionWrapperPass, false>("scops", ID) {}
+};
+char ScopPrinter::ID = 0;
+
+struct ScopOnlyPrinter
+    : public DOTGraphTraitsPrinter<ScopDetectionWrapperPass, true> {
+  static char ID;
+  ScopOnlyPrinter()
+      : DOTGraphTraitsPrinter<ScopDetectionWrapperPass, true>("scopsonly", ID) {
+  }
+};
+char ScopOnlyPrinter::ID = 0;
+
+static RegisterPass<ScopViewer> X("view-scops",
+                                  "Polly - View Scops of function");
+
+static RegisterPass<ScopOnlyViewer>
+    Y("view-scops-only",
+      "Polly - View Scops of function (with no function bodies)");
+
+static RegisterPass<ScopPrinter> M("dot-scops",
+                                   "Polly - Print Scops of function");
+
+static RegisterPass<ScopOnlyPrinter>
+    N("dot-scops-only",
+      "Polly - Print Scops of function (with no function bodies)");
+
+Pass *polly::createDOTViewerPass() { return new ScopViewer(); }
+
+Pass *polly::createDOTOnlyViewerPass() { return new ScopOnlyViewer(); }
+
+Pass *polly::createDOTPrinterPass() { return new ScopPrinter(); }
+
+Pass *polly::createDOTOnlyPrinterPass() { return new ScopOnlyPrinter(); }
diff --git a/final/lib/Analysis/ScopInfo.cpp b/final/lib/Analysis/ScopInfo.cpp
new file mode 100644
index 0000000..d2bc71f
--- /dev/null
+++ b/final/lib/Analysis/ScopInfo.cpp
@@ -0,0 +1,5224 @@
+//===- ScopInfo.cpp -------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Create a polyhedral description for a static control flow region.
+//
+// The pass creates a polyhedral description of the Scops detected by the Scop
+// detection derived from their LLVM-IR code.
+//
+// This representation is shared among several tools in the polyhedral
+// community, which are e.g. Cloog, Pluto, Loopo, Graphite.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/ScopInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopBuilder.h"
+#include "polly/ScopDetection.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/ISLOStream.h"
+#include "polly/Support/SCEVAffinator.h"
+#include "polly/Support/SCEVValidator.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/AliasSetTracker.h"
+#include "llvm/Analysis/AssumptionCache.h"
+#include "llvm/Analysis/Loads.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/RegionIterator.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/Argument.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/ConstantRange.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Use.h"
+#include "llvm/IR/User.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "isl/aff.h"
+#include "isl/constraint.h"
+#include "isl/local_space.h"
+#include "isl/map.h"
+#include "isl/options.h"
+#include "isl/printer.h"
+#include "isl/schedule.h"
+#include "isl/schedule_node.h"
+#include "isl/set.h"
+#include "isl/union_map.h"
+#include "isl/union_set.h"
+#include "isl/val.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <deque>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-scops"
+
+STATISTIC(AssumptionsAliasing, "Number of aliasing assumptions taken.");
+STATISTIC(AssumptionsInbounds, "Number of inbounds assumptions taken.");
+STATISTIC(AssumptionsWrapping, "Number of wrapping assumptions taken.");
+STATISTIC(AssumptionsUnsigned, "Number of unsigned assumptions taken.");
+STATISTIC(AssumptionsComplexity, "Number of too complex SCoPs.");
+STATISTIC(AssumptionsUnprofitable, "Number of unprofitable SCoPs.");
+STATISTIC(AssumptionsErrorBlock, "Number of error block assumptions taken.");
+STATISTIC(AssumptionsInfiniteLoop, "Number of bounded loop assumptions taken.");
+STATISTIC(AssumptionsInvariantLoad,
+          "Number of invariant loads assumptions taken.");
+STATISTIC(AssumptionsDelinearization,
+          "Number of delinearization assumptions taken.");
+
+STATISTIC(NumScops, "Number of feasible SCoPs after ScopInfo");
+STATISTIC(NumLoopsInScop, "Number of loops in scops");
+STATISTIC(NumBoxedLoops, "Number of boxed loops in SCoPs after ScopInfo");
+STATISTIC(NumAffineLoops, "Number of affine loops in SCoPs after ScopInfo");
+
+STATISTIC(NumScopsDepthOne, "Number of scops with maximal loop depth 1");
+STATISTIC(NumScopsDepthTwo, "Number of scops with maximal loop depth 2");
+STATISTIC(NumScopsDepthThree, "Number of scops with maximal loop depth 3");
+STATISTIC(NumScopsDepthFour, "Number of scops with maximal loop depth 4");
+STATISTIC(NumScopsDepthFive, "Number of scops with maximal loop depth 5");
+STATISTIC(NumScopsDepthLarger,
+          "Number of scops with maximal loop depth 6 and larger");
+STATISTIC(MaxNumLoopsInScop, "Maximal number of loops in scops");
+
+STATISTIC(NumValueWrites, "Number of scalar value writes after ScopInfo");
+STATISTIC(
+    NumValueWritesInLoops,
+    "Number of scalar value writes nested in affine loops after ScopInfo");
+STATISTIC(NumPHIWrites, "Number of scalar phi writes after ScopInfo");
+STATISTIC(NumPHIWritesInLoops,
+          "Number of scalar phi writes nested in affine loops after ScopInfo");
+STATISTIC(NumSingletonWrites, "Number of singleton writes after ScopInfo");
+STATISTIC(NumSingletonWritesInLoops,
+          "Number of singleton writes nested in affine loops after ScopInfo");
+
+// The maximal number of basic sets we allow during domain construction to
+// be created. More complex scops will result in very high compile time and
+// are also unlikely to result in good code
+static int const MaxDisjunctsInDomain = 20;
+
+// The number of disjunct in the context after which we stop to add more
+// disjuncts. This parameter is there to avoid exponential growth in the
+// number of disjunct when adding non-convex sets to the context.
+static int const MaxDisjunctsInContext = 4;
+
+// The maximal number of dimensions we allow during invariant load construction.
+// More complex access ranges will result in very high compile time and are also
+// unlikely to result in good code. This value is very high and should only
+// trigger for corner cases (e.g., the "dct_luma" function in h264, SPEC2006).
+static int const MaxDimensionsInAccessRange = 9;
+
+static cl::opt<int>
+    OptComputeOut("polly-analysis-computeout",
+                  cl::desc("Bound the scop analysis by a maximal amount of "
+                           "computational steps (0 means no bound)"),
+                  cl::Hidden, cl::init(800000), cl::ZeroOrMore,
+                  cl::cat(PollyCategory));
+
+static cl::opt<bool> PollyRemarksMinimal(
+    "polly-remarks-minimal",
+    cl::desc("Do not emit remarks about assumptions that are known"),
+    cl::Hidden, cl::ZeroOrMore, cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<int> RunTimeChecksMaxAccessDisjuncts(
+    "polly-rtc-max-array-disjuncts",
+    cl::desc("The maximal number of disjunts allowed in memory accesses to "
+             "to build RTCs."),
+    cl::Hidden, cl::ZeroOrMore, cl::init(8), cl::cat(PollyCategory));
+
+static cl::opt<unsigned> RunTimeChecksMaxParameters(
+    "polly-rtc-max-parameters",
+    cl::desc("The maximal number of parameters allowed in RTCs."), cl::Hidden,
+    cl::ZeroOrMore, cl::init(8), cl::cat(PollyCategory));
+
+static cl::opt<unsigned> RunTimeChecksMaxArraysPerGroup(
+    "polly-rtc-max-arrays-per-group",
+    cl::desc("The maximal number of arrays to compare in each alias group."),
+    cl::Hidden, cl::ZeroOrMore, cl::init(20), cl::cat(PollyCategory));
+
+static cl::opt<std::string> UserContextStr(
+    "polly-context", cl::value_desc("isl parameter set"),
+    cl::desc("Provide additional constraints on the context parameters"),
+    cl::init(""), cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    IslOnErrorAbort("polly-on-isl-error-abort",
+                    cl::desc("Abort if an isl error is encountered"),
+                    cl::init(true), cl::cat(PollyCategory));
+
+static cl::opt<bool> PollyPreciseInbounds(
+    "polly-precise-inbounds",
+    cl::desc("Take more precise inbounds assumptions (do not scale well)"),
+    cl::Hidden, cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    PollyIgnoreInbounds("polly-ignore-inbounds",
+                        cl::desc("Do not take inbounds assumptions at all"),
+                        cl::Hidden, cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<bool> PollyIgnoreParamBounds(
+    "polly-ignore-parameter-bounds",
+    cl::desc(
+        "Do not add parameter bounds and do no gist simplify sets accordingly"),
+    cl::Hidden, cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<bool> PollyAllowDereferenceOfAllFunctionParams(
+    "polly-allow-dereference-of-all-function-parameters",
+    cl::desc(
+        "Treat all parameters to functions that are pointers as dereferencible."
+        " This is useful for invariant load hoisting, since we can generate"
+        " less runtime checks. This is only valid if all pointers to functions"
+        " are always initialized, so that Polly can choose to hoist"
+        " their loads. "),
+    cl::Hidden, cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<bool> PollyPreciseFoldAccesses(
+    "polly-precise-fold-accesses",
+    cl::desc("Fold memory accesses to model more possible delinearizations "
+             "(does not scale well)"),
+    cl::Hidden, cl::init(false), cl::cat(PollyCategory));
+
+bool polly::UseInstructionNames;
+
+static cl::opt<bool, true> XUseInstructionNames(
+    "polly-use-llvm-names",
+    cl::desc("Use LLVM-IR names when deriving statement names"),
+    cl::location(UseInstructionNames), cl::Hidden, cl::init(false),
+    cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> PollyPrintInstructions(
+    "polly-print-instructions", cl::desc("Output instructions per ScopStmt"),
+    cl::Hidden, cl::Optional, cl::init(false), cl::cat(PollyCategory));
+
+//===----------------------------------------------------------------------===//
+
+// Create a sequence of two schedules. Either argument may be null and is
+// interpreted as the empty schedule. Can also return null if both schedules are
+// empty.
+static isl::schedule combineInSequence(isl::schedule Prev, isl::schedule Succ) {
+  if (!Prev)
+    return Succ;
+  if (!Succ)
+    return Prev;
+
+  return Prev.sequence(Succ);
+}
+
+static isl::set addRangeBoundsToSet(isl::set S, const ConstantRange &Range,
+                                    int dim, isl::dim type) {
+  isl::val V;
+  isl::ctx Ctx = S.get_ctx();
+
+  // The upper and lower bound for a parameter value is derived either from
+  // the data type of the parameter or from the - possibly more restrictive -
+  // range metadata.
+  V = valFromAPInt(Ctx.get(), Range.getSignedMin(), true);
+  S = S.lower_bound_val(type, dim, V);
+  V = valFromAPInt(Ctx.get(), Range.getSignedMax(), true);
+  S = S.upper_bound_val(type, dim, V);
+
+  if (Range.isFullSet())
+    return S;
+
+  if (isl_set_n_basic_set(S.get()) > MaxDisjunctsInContext)
+    return S;
+
+  // In case of signed wrapping, we can refine the set of valid values by
+  // excluding the part not covered by the wrapping range.
+  if (Range.isSignWrappedSet()) {
+    V = valFromAPInt(Ctx.get(), Range.getLower(), true);
+    isl::set SLB = S.lower_bound_val(type, dim, V);
+
+    V = valFromAPInt(Ctx.get(), Range.getUpper(), true);
+    V = V.sub_ui(1);
+    isl::set SUB = S.upper_bound_val(type, dim, V);
+    S = SLB.unite(SUB);
+  }
+
+  return S;
+}
+
+static const ScopArrayInfo *identifyBasePtrOriginSAI(Scop *S, Value *BasePtr) {
+  LoadInst *BasePtrLI = dyn_cast<LoadInst>(BasePtr);
+  if (!BasePtrLI)
+    return nullptr;
+
+  if (!S->contains(BasePtrLI))
+    return nullptr;
+
+  ScalarEvolution &SE = *S->getSE();
+
+  auto *OriginBaseSCEV =
+      SE.getPointerBase(SE.getSCEV(BasePtrLI->getPointerOperand()));
+  if (!OriginBaseSCEV)
+    return nullptr;
+
+  auto *OriginBaseSCEVUnknown = dyn_cast<SCEVUnknown>(OriginBaseSCEV);
+  if (!OriginBaseSCEVUnknown)
+    return nullptr;
+
+  return S->getScopArrayInfo(OriginBaseSCEVUnknown->getValue(),
+                             MemoryKind::Array);
+}
+
+ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *ElementType, isl::ctx Ctx,
+                             ArrayRef<const SCEV *> Sizes, MemoryKind Kind,
+                             const DataLayout &DL, Scop *S,
+                             const char *BaseName)
+    : BasePtr(BasePtr), ElementType(ElementType), Kind(Kind), DL(DL), S(*S) {
+  std::string BasePtrName =
+      BaseName ? BaseName
+               : getIslCompatibleName("MemRef", BasePtr, S->getNextArrayIdx(),
+                                      Kind == MemoryKind::PHI ? "__phi" : "",
+                                      UseInstructionNames);
+  Id = isl::id::alloc(Ctx, BasePtrName, this);
+
+  updateSizes(Sizes);
+
+  if (!BasePtr || Kind != MemoryKind::Array) {
+    BasePtrOriginSAI = nullptr;
+    return;
+  }
+
+  BasePtrOriginSAI = identifyBasePtrOriginSAI(S, BasePtr);
+  if (BasePtrOriginSAI)
+    const_cast<ScopArrayInfo *>(BasePtrOriginSAI)->addDerivedSAI(this);
+}
+
+ScopArrayInfo::~ScopArrayInfo() = default;
+
+isl::space ScopArrayInfo::getSpace() const {
+  auto Space = isl::space(Id.get_ctx(), 0, getNumberOfDimensions());
+  Space = Space.set_tuple_id(isl::dim::set, Id);
+  return Space;
+}
+
+bool ScopArrayInfo::isReadOnly() {
+  isl::union_set WriteSet = S.getWrites().range();
+  isl::space Space = getSpace();
+  WriteSet = WriteSet.extract_set(Space);
+
+  return bool(WriteSet.is_empty());
+}
+
+bool ScopArrayInfo::isCompatibleWith(const ScopArrayInfo *Array) const {
+  if (Array->getElementType() != getElementType())
+    return false;
+
+  if (Array->getNumberOfDimensions() != getNumberOfDimensions())
+    return false;
+
+  for (unsigned i = 0; i < getNumberOfDimensions(); i++)
+    if (Array->getDimensionSize(i) != getDimensionSize(i))
+      return false;
+
+  return true;
+}
+
+void ScopArrayInfo::updateElementType(Type *NewElementType) {
+  if (NewElementType == ElementType)
+    return;
+
+  auto OldElementSize = DL.getTypeAllocSizeInBits(ElementType);
+  auto NewElementSize = DL.getTypeAllocSizeInBits(NewElementType);
+
+  if (NewElementSize == OldElementSize || NewElementSize == 0)
+    return;
+
+  if (NewElementSize % OldElementSize == 0 && NewElementSize < OldElementSize) {
+    ElementType = NewElementType;
+  } else {
+    auto GCD = GreatestCommonDivisor64(NewElementSize, OldElementSize);
+    ElementType = IntegerType::get(ElementType->getContext(), GCD);
+  }
+}
+
+/// Make the ScopArrayInfo model a Fortran Array
+void ScopArrayInfo::applyAndSetFAD(Value *FAD) {
+  assert(FAD && "got invalid Fortran array descriptor");
+  if (this->FAD) {
+    assert(this->FAD == FAD &&
+           "receiving different array descriptors for same array");
+    return;
+  }
+
+  assert(DimensionSizesPw.size() > 0 && !DimensionSizesPw[0]);
+  assert(!this->FAD);
+  this->FAD = FAD;
+
+  isl::space Space(S.getIslCtx(), 1, 0);
+
+  std::string param_name = getName();
+  param_name += "_fortranarr_size";
+  isl::id IdPwAff = isl::id::alloc(S.getIslCtx(), param_name, this);
+
+  Space = Space.set_dim_id(isl::dim::param, 0, IdPwAff);
+  isl::pw_aff PwAff =
+      isl::aff::var_on_domain(isl::local_space(Space), isl::dim::param, 0);
+
+  DimensionSizesPw[0] = PwAff;
+}
+
+bool ScopArrayInfo::updateSizes(ArrayRef<const SCEV *> NewSizes,
+                                bool CheckConsistency) {
+  int SharedDims = std::min(NewSizes.size(), DimensionSizes.size());
+  int ExtraDimsNew = NewSizes.size() - SharedDims;
+  int ExtraDimsOld = DimensionSizes.size() - SharedDims;
+
+  if (CheckConsistency) {
+    for (int i = 0; i < SharedDims; i++) {
+      auto *NewSize = NewSizes[i + ExtraDimsNew];
+      auto *KnownSize = DimensionSizes[i + ExtraDimsOld];
+      if (NewSize && KnownSize && NewSize != KnownSize)
+        return false;
+    }
+
+    if (DimensionSizes.size() >= NewSizes.size())
+      return true;
+  }
+
+  DimensionSizes.clear();
+  DimensionSizes.insert(DimensionSizes.begin(), NewSizes.begin(),
+                        NewSizes.end());
+  DimensionSizesPw.clear();
+  for (const SCEV *Expr : DimensionSizes) {
+    if (!Expr) {
+      DimensionSizesPw.push_back(nullptr);
+      continue;
+    }
+    isl::pw_aff Size = S.getPwAffOnly(Expr);
+    DimensionSizesPw.push_back(Size);
+  }
+  return true;
+}
+
+std::string ScopArrayInfo::getName() const { return Id.get_name(); }
+
+int ScopArrayInfo::getElemSizeInBytes() const {
+  return DL.getTypeAllocSize(ElementType);
+}
+
+isl::id ScopArrayInfo::getBasePtrId() const { return Id; }
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void ScopArrayInfo::dump() const { print(errs()); }
+#endif
+
+void ScopArrayInfo::print(raw_ostream &OS, bool SizeAsPwAff) const {
+  OS.indent(8) << *getElementType() << " " << getName();
+  unsigned u = 0;
+  // If this is a Fortran array, then we can print the outermost dimension
+  // as a isl_pw_aff even though there is no SCEV information.
+  bool IsOutermostSizeKnown = SizeAsPwAff && FAD;
+
+  if (!IsOutermostSizeKnown && getNumberOfDimensions() > 0 &&
+      !getDimensionSize(0)) {
+    OS << "[*]";
+    u++;
+  }
+  for (; u < getNumberOfDimensions(); u++) {
+    OS << "[";
+
+    if (SizeAsPwAff) {
+      isl::pw_aff Size = getDimensionSizePw(u);
+      OS << " " << Size << " ";
+    } else {
+      OS << *getDimensionSize(u);
+    }
+
+    OS << "]";
+  }
+
+  OS << ";";
+
+  if (BasePtrOriginSAI)
+    OS << " [BasePtrOrigin: " << BasePtrOriginSAI->getName() << "]";
+
+  OS << " // Element size " << getElemSizeInBytes() << "\n";
+}
+
+const ScopArrayInfo *
+ScopArrayInfo::getFromAccessFunction(isl::pw_multi_aff PMA) {
+  isl::id Id = PMA.get_tuple_id(isl::dim::out);
+  assert(!Id.is_null() && "Output dimension didn't have an ID");
+  return getFromId(Id);
+}
+
+const ScopArrayInfo *ScopArrayInfo::getFromId(isl::id Id) {
+  void *User = Id.get_user();
+  const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
+  return SAI;
+}
+
+void MemoryAccess::wrapConstantDimensions() {
+  auto *SAI = getScopArrayInfo();
+  isl::space ArraySpace = SAI->getSpace();
+  isl::ctx Ctx = ArraySpace.get_ctx();
+  unsigned DimsArray = SAI->getNumberOfDimensions();
+
+  isl::multi_aff DivModAff = isl::multi_aff::identity(
+      ArraySpace.map_from_domain_and_range(ArraySpace));
+  isl::local_space LArraySpace = isl::local_space(ArraySpace);
+
+  // Begin with last dimension, to iteratively carry into higher dimensions.
+  for (int i = DimsArray - 1; i > 0; i--) {
+    auto *DimSize = SAI->getDimensionSize(i);
+    auto *DimSizeCst = dyn_cast<SCEVConstant>(DimSize);
+
+    // This transformation is not applicable to dimensions with dynamic size.
+    if (!DimSizeCst)
+      continue;
+
+    // This transformation is not applicable to dimensions of size zero.
+    if (DimSize->isZero())
+      continue;
+
+    isl::val DimSizeVal =
+        valFromAPInt(Ctx.get(), DimSizeCst->getAPInt(), false);
+    isl::aff Var = isl::aff::var_on_domain(LArraySpace, isl::dim::set, i);
+    isl::aff PrevVar =
+        isl::aff::var_on_domain(LArraySpace, isl::dim::set, i - 1);
+
+    // Compute: index % size
+    // Modulo must apply in the divide of the previous iteration, if any.
+    isl::aff Modulo = Var.mod(DimSizeVal);
+    Modulo = Modulo.pullback(DivModAff);
+
+    // Compute: floor(index / size)
+    isl::aff Divide = Var.div(isl::aff(LArraySpace, DimSizeVal));
+    Divide = Divide.floor();
+    Divide = Divide.add(PrevVar);
+    Divide = Divide.pullback(DivModAff);
+
+    // Apply Modulo and Divide.
+    DivModAff = DivModAff.set_aff(i, Modulo);
+    DivModAff = DivModAff.set_aff(i - 1, Divide);
+  }
+
+  // Apply all modulo/divides on the accesses.
+  isl::map Relation = AccessRelation;
+  Relation = Relation.apply_range(isl::map::from_multi_aff(DivModAff));
+  Relation = Relation.detect_equalities();
+  AccessRelation = Relation;
+}
+
+void MemoryAccess::updateDimensionality() {
+  auto *SAI = getScopArrayInfo();
+  isl::space ArraySpace = SAI->getSpace();
+  isl::space AccessSpace = AccessRelation.get_space().range();
+  isl::ctx Ctx = ArraySpace.get_ctx();
+
+  auto DimsArray = ArraySpace.dim(isl::dim::set);
+  auto DimsAccess = AccessSpace.dim(isl::dim::set);
+  auto DimsMissing = DimsArray - DimsAccess;
+
+  auto *BB = getStatement()->getEntryBlock();
+  auto &DL = BB->getModule()->getDataLayout();
+  unsigned ArrayElemSize = SAI->getElemSizeInBytes();
+  unsigned ElemBytes = DL.getTypeAllocSize(getElementType());
+
+  isl::map Map = isl::map::from_domain_and_range(
+      isl::set::universe(AccessSpace), isl::set::universe(ArraySpace));
+
+  for (unsigned i = 0; i < DimsMissing; i++)
+    Map = Map.fix_si(isl::dim::out, i, 0);
+
+  for (unsigned i = DimsMissing; i < DimsArray; i++)
+    Map = Map.equate(isl::dim::in, i - DimsMissing, isl::dim::out, i);
+
+  AccessRelation = AccessRelation.apply_range(Map);
+
+  // For the non delinearized arrays, divide the access function of the last
+  // subscript by the size of the elements in the array.
+  //
+  // A stride one array access in C expressed as A[i] is expressed in
+  // LLVM-IR as something like A[i * elementsize]. This hides the fact that
+  // two subsequent values of 'i' index two values that are stored next to
+  // each other in memory. By this division we make this characteristic
+  // obvious again. If the base pointer was accessed with offsets not divisible
+  // by the accesses element size, we will have chosen a smaller ArrayElemSize
+  // that divides the offsets of all accesses to this base pointer.
+  if (DimsAccess == 1) {
+    isl::val V = isl::val(Ctx, ArrayElemSize);
+    AccessRelation = AccessRelation.floordiv_val(V);
+  }
+
+  // We currently do this only if we added at least one dimension, which means
+  // some dimension's indices have not been specified, an indicator that some
+  // index values have been added together.
+  // TODO: Investigate general usefulness; Effect on unit tests is to make index
+  // expressions more complicated.
+  if (DimsMissing)
+    wrapConstantDimensions();
+
+  if (!isAffine())
+    computeBoundsOnAccessRelation(ArrayElemSize);
+
+  // Introduce multi-element accesses in case the type loaded by this memory
+  // access is larger than the canonical element type of the array.
+  //
+  // An access ((float *)A)[i] to an array char *A is modeled as
+  // {[i] -> A[o] : 4 i <= o <= 4 i + 3
+  if (ElemBytes > ArrayElemSize) {
+    assert(ElemBytes % ArrayElemSize == 0 &&
+           "Loaded element size should be multiple of canonical element size");
+    isl::map Map = isl::map::from_domain_and_range(
+        isl::set::universe(ArraySpace), isl::set::universe(ArraySpace));
+    for (unsigned i = 0; i < DimsArray - 1; i++)
+      Map = Map.equate(isl::dim::in, i, isl::dim::out, i);
+
+    isl::constraint C;
+    isl::local_space LS;
+
+    LS = isl::local_space(Map.get_space());
+    int Num = ElemBytes / getScopArrayInfo()->getElemSizeInBytes();
+
+    C = isl::constraint::alloc_inequality(LS);
+    C = C.set_constant_val(isl::val(Ctx, Num - 1));
+    C = C.set_coefficient_si(isl::dim::in, DimsArray - 1, 1);
+    C = C.set_coefficient_si(isl::dim::out, DimsArray - 1, -1);
+    Map = Map.add_constraint(C);
+
+    C = isl::constraint::alloc_inequality(LS);
+    C = C.set_coefficient_si(isl::dim::in, DimsArray - 1, -1);
+    C = C.set_coefficient_si(isl::dim::out, DimsArray - 1, 1);
+    C = C.set_constant_val(isl::val(Ctx, 0));
+    Map = Map.add_constraint(C);
+    AccessRelation = AccessRelation.apply_range(Map);
+  }
+}
+
+const std::string
+MemoryAccess::getReductionOperatorStr(MemoryAccess::ReductionType RT) {
+  switch (RT) {
+  case MemoryAccess::RT_NONE:
+    llvm_unreachable("Requested a reduction operator string for a memory "
+                     "access which isn't a reduction");
+  case MemoryAccess::RT_ADD:
+    return "+";
+  case MemoryAccess::RT_MUL:
+    return "*";
+  case MemoryAccess::RT_BOR:
+    return "|";
+  case MemoryAccess::RT_BXOR:
+    return "^";
+  case MemoryAccess::RT_BAND:
+    return "&";
+  }
+  llvm_unreachable("Unknown reduction type");
+}
+
+const ScopArrayInfo *MemoryAccess::getOriginalScopArrayInfo() const {
+  isl::id ArrayId = getArrayId();
+  void *User = ArrayId.get_user();
+  const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
+  return SAI;
+}
+
+const ScopArrayInfo *MemoryAccess::getLatestScopArrayInfo() const {
+  isl::id ArrayId = getLatestArrayId();
+  void *User = ArrayId.get_user();
+  const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
+  return SAI;
+}
+
+isl::id MemoryAccess::getOriginalArrayId() const {
+  return AccessRelation.get_tuple_id(isl::dim::out);
+}
+
+isl::id MemoryAccess::getLatestArrayId() const {
+  if (!hasNewAccessRelation())
+    return getOriginalArrayId();
+  return NewAccessRelation.get_tuple_id(isl::dim::out);
+}
+
+isl::map MemoryAccess::getAddressFunction() const {
+  return getAccessRelation().lexmin();
+}
+
+isl::pw_multi_aff
+MemoryAccess::applyScheduleToAccessRelation(isl::union_map USchedule) const {
+  isl::map Schedule, ScheduledAccRel;
+  isl::union_set UDomain;
+
+  UDomain = getStatement()->getDomain();
+  USchedule = USchedule.intersect_domain(UDomain);
+  Schedule = isl::map::from_union_map(USchedule);
+  ScheduledAccRel = getAddressFunction().apply_domain(Schedule);
+  return isl::pw_multi_aff::from_map(ScheduledAccRel);
+}
+
+isl::map MemoryAccess::getOriginalAccessRelation() const {
+  return AccessRelation;
+}
+
+std::string MemoryAccess::getOriginalAccessRelationStr() const {
+  return AccessRelation.to_str();
+}
+
+isl::space MemoryAccess::getOriginalAccessRelationSpace() const {
+  return AccessRelation.get_space();
+}
+
+isl::map MemoryAccess::getNewAccessRelation() const {
+  return NewAccessRelation;
+}
+
+std::string MemoryAccess::getNewAccessRelationStr() const {
+  return NewAccessRelation.to_str();
+}
+
+std::string MemoryAccess::getAccessRelationStr() const {
+  return getAccessRelation().to_str();
+}
+
+isl::basic_map MemoryAccess::createBasicAccessMap(ScopStmt *Statement) {
+  isl::space Space = isl::space(Statement->getIslCtx(), 0, 1);
+  Space = Space.align_params(Statement->getDomainSpace());
+
+  return isl::basic_map::from_domain_and_range(
+      isl::basic_set::universe(Statement->getDomainSpace()),
+      isl::basic_set::universe(Space));
+}
+
+// Formalize no out-of-bound access assumption
+//
+// When delinearizing array accesses we optimistically assume that the
+// delinearized accesses do not access out of bound locations (the subscript
+// expression of each array evaluates for each statement instance that is
+// executed to a value that is larger than zero and strictly smaller than the
+// size of the corresponding dimension). The only exception is the outermost
+// dimension for which we do not need to assume any upper bound.  At this point
+// we formalize this assumption to ensure that at code generation time the
+// relevant run-time checks can be generated.
+//
+// To find the set of constraints necessary to avoid out of bound accesses, we
+// first build the set of data locations that are not within array bounds. We
+// then apply the reverse access relation to obtain the set of iterations that
+// may contain invalid accesses and reduce this set of iterations to the ones
+// that are actually executed by intersecting them with the domain of the
+// statement. If we now project out all loop dimensions, we obtain a set of
+// parameters that may cause statement instances to be executed that may
+// possibly yield out of bound memory accesses. The complement of these
+// constraints is the set of constraints that needs to be assumed to ensure such
+// statement instances are never executed.
+void MemoryAccess::assumeNoOutOfBound() {
+  if (PollyIgnoreInbounds)
+    return;
+  auto *SAI = getScopArrayInfo();
+  isl::space Space = getOriginalAccessRelationSpace().range();
+  isl::set Outside = isl::set::empty(Space);
+  for (int i = 1, Size = Space.dim(isl::dim::set); i < Size; ++i) {
+    isl::local_space LS(Space);
+    isl::pw_aff Var = isl::pw_aff::var_on_domain(LS, isl::dim::set, i);
+    isl::pw_aff Zero = isl::pw_aff(LS);
+
+    isl::set DimOutside = Var.lt_set(Zero);
+    isl::pw_aff SizeE = SAI->getDimensionSizePw(i);
+    SizeE = SizeE.add_dims(isl::dim::in, Space.dim(isl::dim::set));
+    SizeE = SizeE.set_tuple_id(isl::dim::in, Space.get_tuple_id(isl::dim::set));
+    DimOutside = DimOutside.unite(SizeE.le_set(Var));
+
+    Outside = Outside.unite(DimOutside);
+  }
+
+  Outside = Outside.apply(getAccessRelation().reverse());
+  Outside = Outside.intersect(Statement->getDomain());
+  Outside = Outside.params();
+
+  // Remove divs to avoid the construction of overly complicated assumptions.
+  // Doing so increases the set of parameter combinations that are assumed to
+  // not appear. This is always save, but may make the resulting run-time check
+  // bail out more often than strictly necessary.
+  Outside = Outside.remove_divs();
+  Outside = Outside.complement();
+  const auto &Loc = getAccessInstruction()
+                        ? getAccessInstruction()->getDebugLoc()
+                        : DebugLoc();
+  if (!PollyPreciseInbounds)
+    Outside = Outside.gist_params(Statement->getDomain().params());
+  Statement->getParent()->recordAssumption(INBOUNDS, Outside, Loc,
+                                           AS_ASSUMPTION);
+}
+
+void MemoryAccess::buildMemIntrinsicAccessRelation() {
+  assert(isMemoryIntrinsic());
+  assert(Subscripts.size() == 2 && Sizes.size() == 1);
+
+  isl::pw_aff SubscriptPWA = getPwAff(Subscripts[0]);
+  isl::map SubscriptMap = isl::map::from_pw_aff(SubscriptPWA);
+
+  isl::map LengthMap;
+  if (Subscripts[1] == nullptr) {
+    LengthMap = isl::map::universe(SubscriptMap.get_space());
+  } else {
+    isl::pw_aff LengthPWA = getPwAff(Subscripts[1]);
+    LengthMap = isl::map::from_pw_aff(LengthPWA);
+    isl::space RangeSpace = LengthMap.get_space().range();
+    LengthMap = LengthMap.apply_range(isl::map::lex_gt(RangeSpace));
+  }
+  LengthMap = LengthMap.lower_bound_si(isl::dim::out, 0, 0);
+  LengthMap = LengthMap.align_params(SubscriptMap.get_space());
+  SubscriptMap = SubscriptMap.align_params(LengthMap.get_space());
+  LengthMap = LengthMap.sum(SubscriptMap);
+  AccessRelation =
+      LengthMap.set_tuple_id(isl::dim::in, getStatement()->getDomainId());
+}
+
+void MemoryAccess::computeBoundsOnAccessRelation(unsigned ElementSize) {
+  ScalarEvolution *SE = Statement->getParent()->getSE();
+
+  auto MAI = MemAccInst(getAccessInstruction());
+  if (isa<MemIntrinsic>(MAI))
+    return;
+
+  Value *Ptr = MAI.getPointerOperand();
+  if (!Ptr || !SE->isSCEVable(Ptr->getType()))
+    return;
+
+  auto *PtrSCEV = SE->getSCEV(Ptr);
+  if (isa<SCEVCouldNotCompute>(PtrSCEV))
+    return;
+
+  auto *BasePtrSCEV = SE->getPointerBase(PtrSCEV);
+  if (BasePtrSCEV && !isa<SCEVCouldNotCompute>(BasePtrSCEV))
+    PtrSCEV = SE->getMinusSCEV(PtrSCEV, BasePtrSCEV);
+
+  const ConstantRange &Range = SE->getSignedRange(PtrSCEV);
+  if (Range.isFullSet())
+    return;
+
+  if (Range.isWrappedSet() || Range.isSignWrappedSet())
+    return;
+
+  bool isWrapping = Range.isSignWrappedSet();
+
+  unsigned BW = Range.getBitWidth();
+  const auto One = APInt(BW, 1);
+  const auto LB = isWrapping ? Range.getLower() : Range.getSignedMin();
+  const auto UB = isWrapping ? (Range.getUpper() - One) : Range.getSignedMax();
+
+  auto Min = LB.sdiv(APInt(BW, ElementSize));
+  auto Max = UB.sdiv(APInt(BW, ElementSize)) + One;
+
+  assert(Min.sle(Max) && "Minimum expected to be less or equal than max");
+
+  isl::map Relation = AccessRelation;
+  isl::set AccessRange = Relation.range();
+  AccessRange = addRangeBoundsToSet(AccessRange, ConstantRange(Min, Max), 0,
+                                    isl::dim::set);
+  AccessRelation = Relation.intersect_range(AccessRange);
+}
+
+void MemoryAccess::foldAccessRelation() {
+  if (Sizes.size() < 2 || isa<SCEVConstant>(Sizes[1]))
+    return;
+
+  int Size = Subscripts.size();
+
+  isl::map NewAccessRelation = AccessRelation;
+
+  for (int i = Size - 2; i >= 0; --i) {
+    isl::space Space;
+    isl::map MapOne, MapTwo;
+    isl::pw_aff DimSize = getPwAff(Sizes[i + 1]);
+
+    isl::space SpaceSize = DimSize.get_space();
+    isl::id ParamId =
+        give(isl_space_get_dim_id(SpaceSize.get(), isl_dim_param, 0));
+
+    Space = AccessRelation.get_space();
+    Space = Space.range().map_from_set();
+    Space = Space.align_params(SpaceSize);
+
+    int ParamLocation = Space.find_dim_by_id(isl::dim::param, ParamId);
+
+    MapOne = isl::map::universe(Space);
+    for (int j = 0; j < Size; ++j)
+      MapOne = MapOne.equate(isl::dim::in, j, isl::dim::out, j);
+    MapOne = MapOne.lower_bound_si(isl::dim::in, i + 1, 0);
+
+    MapTwo = isl::map::universe(Space);
+    for (int j = 0; j < Size; ++j)
+      if (j < i || j > i + 1)
+        MapTwo = MapTwo.equate(isl::dim::in, j, isl::dim::out, j);
+
+    isl::local_space LS(Space);
+    isl::constraint C;
+    C = isl::constraint::alloc_equality(LS);
+    C = C.set_constant_si(-1);
+    C = C.set_coefficient_si(isl::dim::in, i, 1);
+    C = C.set_coefficient_si(isl::dim::out, i, -1);
+    MapTwo = MapTwo.add_constraint(C);
+    C = isl::constraint::alloc_equality(LS);
+    C = C.set_coefficient_si(isl::dim::in, i + 1, 1);
+    C = C.set_coefficient_si(isl::dim::out, i + 1, -1);
+    C = C.set_coefficient_si(isl::dim::param, ParamLocation, 1);
+    MapTwo = MapTwo.add_constraint(C);
+    MapTwo = MapTwo.upper_bound_si(isl::dim::in, i + 1, -1);
+
+    MapOne = MapOne.unite(MapTwo);
+    NewAccessRelation = NewAccessRelation.apply_range(MapOne);
+  }
+
+  isl::id BaseAddrId = getScopArrayInfo()->getBasePtrId();
+  isl::space Space = Statement->getDomainSpace();
+  NewAccessRelation = NewAccessRelation.set_tuple_id(
+      isl::dim::in, Space.get_tuple_id(isl::dim::set));
+  NewAccessRelation = NewAccessRelation.set_tuple_id(isl::dim::out, BaseAddrId);
+  NewAccessRelation = NewAccessRelation.gist_domain(Statement->getDomain());
+
+  // Access dimension folding might in certain cases increase the number of
+  // disjuncts in the memory access, which can possibly complicate the generated
+  // run-time checks and can lead to costly compilation.
+  if (!PollyPreciseFoldAccesses &&
+      isl_map_n_basic_map(NewAccessRelation.get()) >
+          isl_map_n_basic_map(AccessRelation.get())) {
+  } else {
+    AccessRelation = NewAccessRelation;
+  }
+}
+
+/// Check if @p Expr is divisible by @p Size.
+static bool isDivisible(const SCEV *Expr, unsigned Size, ScalarEvolution &SE) {
+  assert(Size != 0);
+  if (Size == 1)
+    return true;
+
+  // Only one factor needs to be divisible.
+  if (auto *MulExpr = dyn_cast<SCEVMulExpr>(Expr)) {
+    for (auto *FactorExpr : MulExpr->operands())
+      if (isDivisible(FactorExpr, Size, SE))
+        return true;
+    return false;
+  }
+
+  // For other n-ary expressions (Add, AddRec, Max,...) all operands need
+  // to be divisible.
+  if (auto *NAryExpr = dyn_cast<SCEVNAryExpr>(Expr)) {
+    for (auto *OpExpr : NAryExpr->operands())
+      if (!isDivisible(OpExpr, Size, SE))
+        return false;
+    return true;
+  }
+
+  auto *SizeSCEV = SE.getConstant(Expr->getType(), Size);
+  auto *UDivSCEV = SE.getUDivExpr(Expr, SizeSCEV);
+  auto *MulSCEV = SE.getMulExpr(UDivSCEV, SizeSCEV);
+  return MulSCEV == Expr;
+}
+
+void MemoryAccess::buildAccessRelation(const ScopArrayInfo *SAI) {
+  assert(AccessRelation.is_null() && "AccessRelation already built");
+
+  // Initialize the invalid domain which describes all iterations for which the
+  // access relation is not modeled correctly.
+  isl::set StmtInvalidDomain = getStatement()->getInvalidDomain();
+  InvalidDomain = isl::set::empty(StmtInvalidDomain.get_space());
+
+  isl::ctx Ctx = Id.get_ctx();
+  isl::id BaseAddrId = SAI->getBasePtrId();
+
+  if (getAccessInstruction() && isa<MemIntrinsic>(getAccessInstruction())) {
+    buildMemIntrinsicAccessRelation();
+    AccessRelation = AccessRelation.set_tuple_id(isl::dim::out, BaseAddrId);
+    return;
+  }
+
+  if (!isAffine()) {
+    // We overapproximate non-affine accesses with a possible access to the
+    // whole array. For read accesses it does not make a difference, if an
+    // access must or may happen. However, for write accesses it is important to
+    // differentiate between writes that must happen and writes that may happen.
+    if (AccessRelation.is_null())
+      AccessRelation = createBasicAccessMap(Statement);
+
+    AccessRelation = AccessRelation.set_tuple_id(isl::dim::out, BaseAddrId);
+    return;
+  }
+
+  isl::space Space = isl::space(Ctx, 0, Statement->getNumIterators(), 0);
+  AccessRelation = isl::map::universe(Space);
+
+  for (int i = 0, Size = Subscripts.size(); i < Size; ++i) {
+    isl::pw_aff Affine = getPwAff(Subscripts[i]);
+    isl::map SubscriptMap = isl::map::from_pw_aff(Affine);
+    AccessRelation = AccessRelation.flat_range_product(SubscriptMap);
+  }
+
+  Space = Statement->getDomainSpace();
+  AccessRelation = AccessRelation.set_tuple_id(
+      isl::dim::in, Space.get_tuple_id(isl::dim::set));
+  AccessRelation = AccessRelation.set_tuple_id(isl::dim::out, BaseAddrId);
+
+  AccessRelation = AccessRelation.gist_domain(Statement->getDomain());
+}
+
+MemoryAccess::MemoryAccess(ScopStmt *Stmt, Instruction *AccessInst,
+                           AccessType AccType, Value *BaseAddress,
+                           Type *ElementType, bool Affine,
+                           ArrayRef<const SCEV *> Subscripts,
+                           ArrayRef<const SCEV *> Sizes, Value *AccessValue,
+                           MemoryKind Kind)
+    : Kind(Kind), AccType(AccType), Statement(Stmt), InvalidDomain(nullptr),
+      BaseAddr(BaseAddress), ElementType(ElementType),
+      Sizes(Sizes.begin(), Sizes.end()), AccessInstruction(AccessInst),
+      AccessValue(AccessValue), IsAffine(Affine),
+      Subscripts(Subscripts.begin(), Subscripts.end()), AccessRelation(nullptr),
+      NewAccessRelation(nullptr), FAD(nullptr) {
+  static const std::string TypeStrings[] = {"", "_Read", "_Write", "_MayWrite"};
+  const std::string Access = TypeStrings[AccType] + utostr(Stmt->size());
+
+  std::string IdName = Stmt->getBaseName() + Access;
+  Id = isl::id::alloc(Stmt->getParent()->getIslCtx(), IdName, this);
+}
+
+MemoryAccess::MemoryAccess(ScopStmt *Stmt, AccessType AccType, isl::map AccRel)
+    : Kind(MemoryKind::Array), AccType(AccType), Statement(Stmt),
+      InvalidDomain(nullptr), AccessRelation(nullptr),
+      NewAccessRelation(AccRel), FAD(nullptr) {
+  isl::id ArrayInfoId = NewAccessRelation.get_tuple_id(isl::dim::out);
+  auto *SAI = ScopArrayInfo::getFromId(ArrayInfoId);
+  Sizes.push_back(nullptr);
+  for (unsigned i = 1; i < SAI->getNumberOfDimensions(); i++)
+    Sizes.push_back(SAI->getDimensionSize(i));
+  ElementType = SAI->getElementType();
+  BaseAddr = SAI->getBasePtr();
+  static const std::string TypeStrings[] = {"", "_Read", "_Write", "_MayWrite"};
+  const std::string Access = TypeStrings[AccType] + utostr(Stmt->size());
+
+  std::string IdName = Stmt->getBaseName() + Access;
+  Id = isl::id::alloc(Stmt->getParent()->getIslCtx(), IdName, this);
+}
+
+MemoryAccess::~MemoryAccess() = default;
+
+void MemoryAccess::realignParams() {
+  isl::set Ctx = Statement->getParent()->getContext();
+  InvalidDomain = InvalidDomain.gist_params(Ctx);
+  AccessRelation = AccessRelation.gist_params(Ctx);
+}
+
+const std::string MemoryAccess::getReductionOperatorStr() const {
+  return MemoryAccess::getReductionOperatorStr(getReductionType());
+}
+
+isl::id MemoryAccess::getId() const { return Id; }
+
+raw_ostream &polly::operator<<(raw_ostream &OS,
+                               MemoryAccess::ReductionType RT) {
+  if (RT == MemoryAccess::RT_NONE)
+    OS << "NONE";
+  else
+    OS << MemoryAccess::getReductionOperatorStr(RT);
+  return OS;
+}
+
+void MemoryAccess::setFortranArrayDescriptor(Value *FAD) { this->FAD = FAD; }
+
+void MemoryAccess::print(raw_ostream &OS) const {
+  switch (AccType) {
+  case READ:
+    OS.indent(12) << "ReadAccess :=\t";
+    break;
+  case MUST_WRITE:
+    OS.indent(12) << "MustWriteAccess :=\t";
+    break;
+  case MAY_WRITE:
+    OS.indent(12) << "MayWriteAccess :=\t";
+    break;
+  }
+
+  OS << "[Reduction Type: " << getReductionType() << "] ";
+
+  if (FAD) {
+    OS << "[Fortran array descriptor: " << FAD->getName();
+    OS << "] ";
+  };
+
+  OS << "[Scalar: " << isScalarKind() << "]\n";
+  OS.indent(16) << getOriginalAccessRelationStr() << ";\n";
+  if (hasNewAccessRelation())
+    OS.indent(11) << "new: " << getNewAccessRelationStr() << ";\n";
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void MemoryAccess::dump() const { print(errs()); }
+#endif
+
+isl::pw_aff MemoryAccess::getPwAff(const SCEV *E) {
+  auto *Stmt = getStatement();
+  PWACtx PWAC = Stmt->getParent()->getPwAff(E, Stmt->getEntryBlock());
+  isl::set StmtDom = getStatement()->getDomain();
+  StmtDom = StmtDom.reset_tuple_id();
+  isl::set NewInvalidDom = StmtDom.intersect(PWAC.second);
+  InvalidDomain = InvalidDomain.unite(NewInvalidDom);
+  return PWAC.first;
+}
+
+// Create a map in the size of the provided set domain, that maps from the
+// one element of the provided set domain to another element of the provided
+// set domain.
+// The mapping is limited to all points that are equal in all but the last
+// dimension and for which the last dimension of the input is strict smaller
+// than the last dimension of the output.
+//
+//   getEqualAndLarger(set[i0, i1, ..., iX]):
+//
+//   set[i0, i1, ..., iX] -> set[o0, o1, ..., oX]
+//     : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1), iX < oX
+//
+static isl::map getEqualAndLarger(isl::space SetDomain) {
+  isl::space Space = SetDomain.map_from_set();
+  isl::map Map = isl::map::universe(Space);
+  unsigned lastDimension = Map.dim(isl::dim::in) - 1;
+
+  // Set all but the last dimension to be equal for the input and output
+  //
+  //   input[i0, i1, ..., iX] -> output[o0, o1, ..., oX]
+  //     : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1)
+  for (unsigned i = 0; i < lastDimension; ++i)
+    Map = Map.equate(isl::dim::in, i, isl::dim::out, i);
+
+  // Set the last dimension of the input to be strict smaller than the
+  // last dimension of the output.
+  //
+  //   input[?,?,?,...,iX] -> output[?,?,?,...,oX] : iX < oX
+  Map = Map.order_lt(isl::dim::in, lastDimension, isl::dim::out, lastDimension);
+  return Map;
+}
+
+isl::set MemoryAccess::getStride(isl::map Schedule) const {
+  isl::map AccessRelation = getAccessRelation();
+  isl::space Space = Schedule.get_space().range();
+  isl::map NextScatt = getEqualAndLarger(Space);
+
+  Schedule = Schedule.reverse();
+  NextScatt = NextScatt.lexmin();
+
+  NextScatt = NextScatt.apply_range(Schedule);
+  NextScatt = NextScatt.apply_range(AccessRelation);
+  NextScatt = NextScatt.apply_domain(Schedule);
+  NextScatt = NextScatt.apply_domain(AccessRelation);
+
+  isl::set Deltas = NextScatt.deltas();
+  return Deltas;
+}
+
+bool MemoryAccess::isStrideX(isl::map Schedule, int StrideWidth) const {
+  isl::set Stride, StrideX;
+  bool IsStrideX;
+
+  Stride = getStride(Schedule);
+  StrideX = isl::set::universe(Stride.get_space());
+  for (unsigned i = 0; i < StrideX.dim(isl::dim::set) - 1; i++)
+    StrideX = StrideX.fix_si(isl::dim::set, i, 0);
+  StrideX = StrideX.fix_si(isl::dim::set, StrideX.dim(isl::dim::set) - 1,
+                           StrideWidth);
+  IsStrideX = Stride.is_subset(StrideX);
+
+  return IsStrideX;
+}
+
+bool MemoryAccess::isStrideZero(isl::map Schedule) const {
+  return isStrideX(Schedule, 0);
+}
+
+bool MemoryAccess::isStrideOne(isl::map Schedule) const {
+  return isStrideX(Schedule, 1);
+}
+
+void MemoryAccess::setAccessRelation(isl::map NewAccess) {
+  AccessRelation = NewAccess;
+}
+
+void MemoryAccess::setNewAccessRelation(isl::map NewAccess) {
+  assert(NewAccess);
+
+#ifndef NDEBUG
+  // Check domain space compatibility.
+  isl::space NewSpace = NewAccess.get_space();
+  isl::space NewDomainSpace = NewSpace.domain();
+  isl::space OriginalDomainSpace = getStatement()->getDomainSpace();
+  assert(OriginalDomainSpace.has_equal_tuples(NewDomainSpace));
+
+  // Reads must be executed unconditionally. Writes might be executed in a
+  // subdomain only.
+  if (isRead()) {
+    // Check whether there is an access for every statement instance.
+    isl::set StmtDomain = getStatement()->getDomain();
+    StmtDomain =
+        StmtDomain.intersect_params(getStatement()->getParent()->getContext());
+    isl::set NewDomain = NewAccess.domain();
+    assert(StmtDomain.is_subset(NewDomain) &&
+           "Partial READ accesses not supported");
+  }
+
+  isl::space NewAccessSpace = NewAccess.get_space();
+  assert(NewAccessSpace.has_tuple_id(isl::dim::set) &&
+         "Must specify the array that is accessed");
+  isl::id NewArrayId = NewAccessSpace.get_tuple_id(isl::dim::set);
+  auto *SAI = static_cast<ScopArrayInfo *>(NewArrayId.get_user());
+  assert(SAI && "Must set a ScopArrayInfo");
+
+  if (SAI->isArrayKind() && SAI->getBasePtrOriginSAI()) {
+    InvariantEquivClassTy *EqClass =
+        getStatement()->getParent()->lookupInvariantEquivClass(
+            SAI->getBasePtr());
+    assert(EqClass &&
+           "Access functions to indirect arrays must have an invariant and "
+           "hoisted base pointer");
+  }
+
+  // Check whether access dimensions correspond to number of dimensions of the
+  // accesses array.
+  auto Dims = SAI->getNumberOfDimensions();
+  assert(NewAccessSpace.dim(isl::dim::set) == Dims &&
+         "Access dims must match array dims");
+#endif
+
+  NewAccess = NewAccess.gist_domain(getStatement()->getDomain());
+  NewAccessRelation = NewAccess;
+}
+
+bool MemoryAccess::isLatestPartialAccess() const {
+  isl::set StmtDom = getStatement()->getDomain();
+  isl::set AccDom = getLatestAccessRelation().domain();
+
+  return isl_set_is_subset(StmtDom.keep(), AccDom.keep()) == isl_bool_false;
+}
+
+//===----------------------------------------------------------------------===//
+
+isl::map ScopStmt::getSchedule() const {
+  isl::set Domain = getDomain();
+  if (Domain.is_empty())
+    return isl::map::from_aff(isl::aff(isl::local_space(getDomainSpace())));
+  auto Schedule = getParent()->getSchedule();
+  if (!Schedule)
+    return nullptr;
+  Schedule = Schedule.intersect_domain(isl::union_set(Domain));
+  if (Schedule.is_empty())
+    return isl::map::from_aff(isl::aff(isl::local_space(getDomainSpace())));
+  isl::map M = M.from_union_map(Schedule);
+  M = M.coalesce();
+  M = M.gist_domain(Domain);
+  M = M.coalesce();
+  return M;
+}
+
+void ScopStmt::restrictDomain(isl::set NewDomain) {
+  assert(NewDomain.is_subset(Domain) &&
+         "New domain is not a subset of old domain!");
+  Domain = NewDomain;
+}
+
+void ScopStmt::addAccess(MemoryAccess *Access, bool Prepend) {
+  Instruction *AccessInst = Access->getAccessInstruction();
+
+  if (Access->isArrayKind()) {
+    MemoryAccessList &MAL = InstructionToAccess[AccessInst];
+    MAL.emplace_front(Access);
+  } else if (Access->isValueKind() && Access->isWrite()) {
+    Instruction *AccessVal = cast<Instruction>(Access->getAccessValue());
+    assert(!ValueWrites.lookup(AccessVal));
+
+    ValueWrites[AccessVal] = Access;
+  } else if (Access->isValueKind() && Access->isRead()) {
+    Value *AccessVal = Access->getAccessValue();
+    assert(!ValueReads.lookup(AccessVal));
+
+    ValueReads[AccessVal] = Access;
+  } else if (Access->isAnyPHIKind() && Access->isWrite()) {
+    PHINode *PHI = cast<PHINode>(Access->getAccessValue());
+    assert(!PHIWrites.lookup(PHI));
+
+    PHIWrites[PHI] = Access;
+  } else if (Access->isAnyPHIKind() && Access->isRead()) {
+    PHINode *PHI = cast<PHINode>(Access->getAccessValue());
+    assert(!PHIReads.lookup(PHI));
+
+    PHIReads[PHI] = Access;
+  }
+
+  if (Prepend) {
+    MemAccs.insert(MemAccs.begin(), Access);
+    return;
+  }
+  MemAccs.push_back(Access);
+}
+
+void ScopStmt::realignParams() {
+  for (MemoryAccess *MA : *this)
+    MA->realignParams();
+
+  isl::set Ctx = Parent.getContext();
+  InvalidDomain = InvalidDomain.gist_params(Ctx);
+  Domain = Domain.gist_params(Ctx);
+}
+
+/// Add @p BSet to the set @p User if @p BSet is bounded.
+static isl_stat collectBoundedParts(__isl_take isl_basic_set *BSet,
+                                    void *User) {
+  isl_set **BoundedParts = static_cast<isl_set **>(User);
+  if (isl_basic_set_is_bounded(BSet))
+    *BoundedParts = isl_set_union(*BoundedParts, isl_set_from_basic_set(BSet));
+  else
+    isl_basic_set_free(BSet);
+  return isl_stat_ok;
+}
+
+/// Return the bounded parts of @p S.
+static __isl_give isl_set *collectBoundedParts(__isl_take isl_set *S) {
+  isl_set *BoundedParts = isl_set_empty(isl_set_get_space(S));
+  isl_set_foreach_basic_set(S, collectBoundedParts, &BoundedParts);
+  isl_set_free(S);
+  return BoundedParts;
+}
+
+/// Compute the (un)bounded parts of @p S wrt. to dimension @p Dim.
+///
+/// @returns A separation of @p S into first an unbounded then a bounded subset,
+///          both with regards to the dimension @p Dim.
+static std::pair<__isl_give isl_set *, __isl_give isl_set *>
+partitionSetParts(__isl_take isl_set *S, unsigned Dim) {
+  for (unsigned u = 0, e = isl_set_n_dim(S); u < e; u++)
+    S = isl_set_lower_bound_si(S, isl_dim_set, u, 0);
+
+  unsigned NumDimsS = isl_set_n_dim(S);
+  isl_set *OnlyDimS = isl_set_copy(S);
+
+  // Remove dimensions that are greater than Dim as they are not interesting.
+  assert(NumDimsS >= Dim + 1);
+  OnlyDimS =
+      isl_set_project_out(OnlyDimS, isl_dim_set, Dim + 1, NumDimsS - Dim - 1);
+
+  // Create artificial parametric upper bounds for dimensions smaller than Dim
+  // as we are not interested in them.
+  OnlyDimS = isl_set_insert_dims(OnlyDimS, isl_dim_param, 0, Dim);
+  for (unsigned u = 0; u < Dim; u++) {
+    isl_constraint *C = isl_inequality_alloc(
+        isl_local_space_from_space(isl_set_get_space(OnlyDimS)));
+    C = isl_constraint_set_coefficient_si(C, isl_dim_param, u, 1);
+    C = isl_constraint_set_coefficient_si(C, isl_dim_set, u, -1);
+    OnlyDimS = isl_set_add_constraint(OnlyDimS, C);
+  }
+
+  // Collect all bounded parts of OnlyDimS.
+  isl_set *BoundedParts = collectBoundedParts(OnlyDimS);
+
+  // Create the dimensions greater than Dim again.
+  BoundedParts = isl_set_insert_dims(BoundedParts, isl_dim_set, Dim + 1,
+                                     NumDimsS - Dim - 1);
+
+  // Remove the artificial upper bound parameters again.
+  BoundedParts = isl_set_remove_dims(BoundedParts, isl_dim_param, 0, Dim);
+
+  isl_set *UnboundedParts = isl_set_subtract(S, isl_set_copy(BoundedParts));
+  return std::make_pair(UnboundedParts, BoundedParts);
+}
+
+/// Set the dimension Ids from @p From in @p To.
+static __isl_give isl_set *setDimensionIds(__isl_keep isl_set *From,
+                                           __isl_take isl_set *To) {
+  for (unsigned u = 0, e = isl_set_n_dim(From); u < e; u++) {
+    isl_id *DimId = isl_set_get_dim_id(From, isl_dim_set, u);
+    To = isl_set_set_dim_id(To, isl_dim_set, u, DimId);
+  }
+  return To;
+}
+
+/// Create the conditions under which @p L @p Pred @p R is true.
+static __isl_give isl_set *buildConditionSet(ICmpInst::Predicate Pred,
+                                             __isl_take isl_pw_aff *L,
+                                             __isl_take isl_pw_aff *R) {
+  switch (Pred) {
+  case ICmpInst::ICMP_EQ:
+    return isl_pw_aff_eq_set(L, R);
+  case ICmpInst::ICMP_NE:
+    return isl_pw_aff_ne_set(L, R);
+  case ICmpInst::ICMP_SLT:
+    return isl_pw_aff_lt_set(L, R);
+  case ICmpInst::ICMP_SLE:
+    return isl_pw_aff_le_set(L, R);
+  case ICmpInst::ICMP_SGT:
+    return isl_pw_aff_gt_set(L, R);
+  case ICmpInst::ICMP_SGE:
+    return isl_pw_aff_ge_set(L, R);
+  case ICmpInst::ICMP_ULT:
+    return isl_pw_aff_lt_set(L, R);
+  case ICmpInst::ICMP_UGT:
+    return isl_pw_aff_gt_set(L, R);
+  case ICmpInst::ICMP_ULE:
+    return isl_pw_aff_le_set(L, R);
+  case ICmpInst::ICMP_UGE:
+    return isl_pw_aff_ge_set(L, R);
+  default:
+    llvm_unreachable("Non integer predicate not supported");
+  }
+}
+
+/// Create the conditions under which @p L @p Pred @p R is true.
+///
+/// Helper function that will make sure the dimensions of the result have the
+/// same isl_id's as the @p Domain.
+static __isl_give isl_set *buildConditionSet(ICmpInst::Predicate Pred,
+                                             __isl_take isl_pw_aff *L,
+                                             __isl_take isl_pw_aff *R,
+                                             __isl_keep isl_set *Domain) {
+  isl_set *ConsequenceCondSet = buildConditionSet(Pred, L, R);
+  return setDimensionIds(Domain, ConsequenceCondSet);
+}
+
+/// Compute the isl representation for the SCEV @p E in this BB.
+///
+/// @param S                The Scop in which @p BB resides in.
+/// @param BB               The BB for which isl representation is to be
+/// computed.
+/// @param InvalidDomainMap A map of BB to their invalid domains.
+/// @param E                The SCEV that should be translated.
+/// @param NonNegative      Flag to indicate the @p E has to be non-negative.
+///
+/// Note that this function will also adjust the invalid context accordingly.
+
+__isl_give isl_pw_aff *
+getPwAff(Scop &S, BasicBlock *BB,
+         DenseMap<BasicBlock *, isl::set> &InvalidDomainMap, const SCEV *E,
+         bool NonNegative = false) {
+  PWACtx PWAC = S.getPwAff(E, BB, NonNegative);
+  InvalidDomainMap[BB] = InvalidDomainMap[BB].unite(PWAC.second);
+  return PWAC.first.take();
+}
+
+/// Build the conditions sets for the switch @p SI in the @p Domain.
+///
+/// This will fill @p ConditionSets with the conditions under which control
+/// will be moved from @p SI to its successors. Hence, @p ConditionSets will
+/// have as many elements as @p SI has successors.
+bool buildConditionSets(Scop &S, BasicBlock *BB, SwitchInst *SI, Loop *L,
+                        __isl_keep isl_set *Domain,
+                        DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
+                        SmallVectorImpl<__isl_give isl_set *> &ConditionSets) {
+  Value *Condition = getConditionFromTerminator(SI);
+  assert(Condition && "No condition for switch");
+
+  ScalarEvolution &SE = *S.getSE();
+  isl_pw_aff *LHS, *RHS;
+  LHS = getPwAff(S, BB, InvalidDomainMap, SE.getSCEVAtScope(Condition, L));
+
+  unsigned NumSuccessors = SI->getNumSuccessors();
+  ConditionSets.resize(NumSuccessors);
+  for (auto &Case : SI->cases()) {
+    unsigned Idx = Case.getSuccessorIndex();
+    ConstantInt *CaseValue = Case.getCaseValue();
+
+    RHS = getPwAff(S, BB, InvalidDomainMap, SE.getSCEV(CaseValue));
+    isl_set *CaseConditionSet =
+        buildConditionSet(ICmpInst::ICMP_EQ, isl_pw_aff_copy(LHS), RHS, Domain);
+    ConditionSets[Idx] = isl_set_coalesce(
+        isl_set_intersect(CaseConditionSet, isl_set_copy(Domain)));
+  }
+
+  assert(ConditionSets[0] == nullptr && "Default condition set was set");
+  isl_set *ConditionSetUnion = isl_set_copy(ConditionSets[1]);
+  for (unsigned u = 2; u < NumSuccessors; u++)
+    ConditionSetUnion =
+        isl_set_union(ConditionSetUnion, isl_set_copy(ConditionSets[u]));
+  ConditionSets[0] = setDimensionIds(
+      Domain, isl_set_subtract(isl_set_copy(Domain), ConditionSetUnion));
+
+  isl_pw_aff_free(LHS);
+
+  return true;
+}
+
+/// Build condition sets for unsigned ICmpInst(s).
+/// Special handling is required for unsigned operands to ensure that if
+/// MSB (aka the Sign bit) is set for an operands in an unsigned ICmpInst
+/// it should wrap around.
+///
+/// @param IsStrictUpperBound holds information on the predicate relation
+/// between TestVal and UpperBound, i.e,
+/// TestVal < UpperBound  OR  TestVal <= UpperBound
+__isl_give isl_set *
+buildUnsignedConditionSets(Scop &S, BasicBlock *BB, Value *Condition,
+                           __isl_keep isl_set *Domain, const SCEV *SCEV_TestVal,
+                           const SCEV *SCEV_UpperBound,
+                           DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
+                           bool IsStrictUpperBound) {
+  // Do not take NonNeg assumption on TestVal
+  // as it might have MSB (Sign bit) set.
+  isl_pw_aff *TestVal = getPwAff(S, BB, InvalidDomainMap, SCEV_TestVal, false);
+  // Take NonNeg assumption on UpperBound.
+  isl_pw_aff *UpperBound =
+      getPwAff(S, BB, InvalidDomainMap, SCEV_UpperBound, true);
+
+  // 0 <= TestVal
+  isl_set *First =
+      isl_pw_aff_le_set(isl_pw_aff_zero_on_domain(isl_local_space_from_space(
+                            isl_pw_aff_get_domain_space(TestVal))),
+                        isl_pw_aff_copy(TestVal));
+
+  isl_set *Second;
+  if (IsStrictUpperBound)
+    // TestVal < UpperBound
+    Second = isl_pw_aff_lt_set(TestVal, UpperBound);
+  else
+    // TestVal <= UpperBound
+    Second = isl_pw_aff_le_set(TestVal, UpperBound);
+
+  isl_set *ConsequenceCondSet = isl_set_intersect(First, Second);
+  ConsequenceCondSet = setDimensionIds(Domain, ConsequenceCondSet);
+  return ConsequenceCondSet;
+}
+
+/// Build the conditions sets for the branch condition @p Condition in
+/// the @p Domain.
+///
+/// This will fill @p ConditionSets with the conditions under which control
+/// will be moved from @p TI to its successors. Hence, @p ConditionSets will
+/// have as many elements as @p TI has successors. If @p TI is nullptr the
+/// context under which @p Condition is true/false will be returned as the
+/// new elements of @p ConditionSets.
+bool buildConditionSets(Scop &S, BasicBlock *BB, Value *Condition,
+                        TerminatorInst *TI, Loop *L, __isl_keep isl_set *Domain,
+                        DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
+                        SmallVectorImpl<__isl_give isl_set *> &ConditionSets) {
+  ScalarEvolution &SE = *S.getSE();
+  isl_set *ConsequenceCondSet = nullptr;
+
+  if (auto Load = dyn_cast<LoadInst>(Condition)) {
+    const SCEV *LHSSCEV = SE.getSCEVAtScope(Load, L);
+    const SCEV *RHSSCEV = SE.getZero(LHSSCEV->getType());
+    bool NonNeg = false;
+    isl_pw_aff *LHS = getPwAff(S, BB, InvalidDomainMap, LHSSCEV, NonNeg);
+    isl_pw_aff *RHS = getPwAff(S, BB, InvalidDomainMap, RHSSCEV, NonNeg);
+    ConsequenceCondSet =
+        buildConditionSet(ICmpInst::ICMP_SLE, LHS, RHS, Domain);
+  } else if (auto *PHI = dyn_cast<PHINode>(Condition)) {
+    auto *Unique = dyn_cast<ConstantInt>(
+        getUniqueNonErrorValue(PHI, &S.getRegion(), *S.getLI(), *S.getDT()));
+
+    if (Unique->isZero())
+      ConsequenceCondSet = isl_set_empty(isl_set_get_space(Domain));
+    else
+      ConsequenceCondSet = isl_set_universe(isl_set_get_space(Domain));
+  } else if (auto *CCond = dyn_cast<ConstantInt>(Condition)) {
+    if (CCond->isZero())
+      ConsequenceCondSet = isl_set_empty(isl_set_get_space(Domain));
+    else
+      ConsequenceCondSet = isl_set_universe(isl_set_get_space(Domain));
+  } else if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(Condition)) {
+    auto Opcode = BinOp->getOpcode();
+    assert(Opcode == Instruction::And || Opcode == Instruction::Or);
+
+    bool Valid = buildConditionSets(S, BB, BinOp->getOperand(0), TI, L, Domain,
+                                    InvalidDomainMap, ConditionSets) &&
+                 buildConditionSets(S, BB, BinOp->getOperand(1), TI, L, Domain,
+                                    InvalidDomainMap, ConditionSets);
+    if (!Valid) {
+      while (!ConditionSets.empty())
+        isl_set_free(ConditionSets.pop_back_val());
+      return false;
+    }
+
+    isl_set_free(ConditionSets.pop_back_val());
+    isl_set *ConsCondPart0 = ConditionSets.pop_back_val();
+    isl_set_free(ConditionSets.pop_back_val());
+    isl_set *ConsCondPart1 = ConditionSets.pop_back_val();
+
+    if (Opcode == Instruction::And)
+      ConsequenceCondSet = isl_set_intersect(ConsCondPart0, ConsCondPart1);
+    else
+      ConsequenceCondSet = isl_set_union(ConsCondPart0, ConsCondPart1);
+  } else {
+    auto *ICond = dyn_cast<ICmpInst>(Condition);
+    assert(ICond &&
+           "Condition of exiting branch was neither constant nor ICmp!");
+
+    LoopInfo &LI = *S.getLI();
+    DominatorTree &DT = *S.getDT();
+    Region &R = S.getRegion();
+
+    isl_pw_aff *LHS, *RHS;
+    // For unsigned comparisons we assumed the signed bit of neither operand
+    // to be set. The comparison is equal to a signed comparison under this
+    // assumption.
+    bool NonNeg = ICond->isUnsigned();
+    const SCEV *LeftOperand = SE.getSCEVAtScope(ICond->getOperand(0), L),
+               *RightOperand = SE.getSCEVAtScope(ICond->getOperand(1), L);
+
+    LeftOperand = tryForwardThroughPHI(LeftOperand, R, SE, LI, DT);
+    RightOperand = tryForwardThroughPHI(RightOperand, R, SE, LI, DT);
+
+    switch (ICond->getPredicate()) {
+    case ICmpInst::ICMP_ULT:
+      ConsequenceCondSet =
+          buildUnsignedConditionSets(S, BB, Condition, Domain, LeftOperand,
+                                     RightOperand, InvalidDomainMap, true);
+      break;
+    case ICmpInst::ICMP_ULE:
+      ConsequenceCondSet =
+          buildUnsignedConditionSets(S, BB, Condition, Domain, LeftOperand,
+                                     RightOperand, InvalidDomainMap, false);
+      break;
+    case ICmpInst::ICMP_UGT:
+      ConsequenceCondSet =
+          buildUnsignedConditionSets(S, BB, Condition, Domain, RightOperand,
+                                     LeftOperand, InvalidDomainMap, true);
+      break;
+    case ICmpInst::ICMP_UGE:
+      ConsequenceCondSet =
+          buildUnsignedConditionSets(S, BB, Condition, Domain, RightOperand,
+                                     LeftOperand, InvalidDomainMap, false);
+      break;
+    default:
+      LHS = getPwAff(S, BB, InvalidDomainMap, LeftOperand, NonNeg);
+      RHS = getPwAff(S, BB, InvalidDomainMap, RightOperand, NonNeg);
+      ConsequenceCondSet =
+          buildConditionSet(ICond->getPredicate(), LHS, RHS, Domain);
+      break;
+    }
+  }
+
+  // If no terminator was given we are only looking for parameter constraints
+  // under which @p Condition is true/false.
+  if (!TI)
+    ConsequenceCondSet = isl_set_params(ConsequenceCondSet);
+  assert(ConsequenceCondSet);
+  ConsequenceCondSet = isl_set_coalesce(
+      isl_set_intersect(ConsequenceCondSet, isl_set_copy(Domain)));
+
+  isl_set *AlternativeCondSet = nullptr;
+  bool TooComplex =
+      isl_set_n_basic_set(ConsequenceCondSet) >= MaxDisjunctsInDomain;
+
+  if (!TooComplex) {
+    AlternativeCondSet = isl_set_subtract(isl_set_copy(Domain),
+                                          isl_set_copy(ConsequenceCondSet));
+    TooComplex =
+        isl_set_n_basic_set(AlternativeCondSet) >= MaxDisjunctsInDomain;
+  }
+
+  if (TooComplex) {
+    S.invalidate(COMPLEXITY, TI ? TI->getDebugLoc() : DebugLoc(),
+                 TI ? TI->getParent() : nullptr /* BasicBlock */);
+    isl_set_free(AlternativeCondSet);
+    isl_set_free(ConsequenceCondSet);
+    return false;
+  }
+
+  ConditionSets.push_back(ConsequenceCondSet);
+  ConditionSets.push_back(isl_set_coalesce(AlternativeCondSet));
+
+  return true;
+}
+
+/// Build the conditions sets for the terminator @p TI in the @p Domain.
+///
+/// This will fill @p ConditionSets with the conditions under which control
+/// will be moved from @p TI to its successors. Hence, @p ConditionSets will
+/// have as many elements as @p TI has successors.
+bool buildConditionSets(Scop &S, BasicBlock *BB, TerminatorInst *TI, Loop *L,
+                        __isl_keep isl_set *Domain,
+                        DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
+                        SmallVectorImpl<__isl_give isl_set *> &ConditionSets) {
+  if (SwitchInst *SI = dyn_cast<SwitchInst>(TI))
+    return buildConditionSets(S, BB, SI, L, Domain, InvalidDomainMap,
+                              ConditionSets);
+
+  assert(isa<BranchInst>(TI) && "Terminator was neither branch nor switch.");
+
+  if (TI->getNumSuccessors() == 1) {
+    ConditionSets.push_back(isl_set_copy(Domain));
+    return true;
+  }
+
+  Value *Condition = getConditionFromTerminator(TI);
+  assert(Condition && "No condition for Terminator");
+
+  return buildConditionSets(S, BB, Condition, TI, L, Domain, InvalidDomainMap,
+                            ConditionSets);
+}
+
+ScopStmt::ScopStmt(Scop &parent, Region &R, Loop *SurroundingLoop,
+                   std::vector<Instruction *> EntryBlockInstructions)
+    : Parent(parent), InvalidDomain(nullptr), Domain(nullptr), R(&R),
+      Build(nullptr), SurroundingLoop(SurroundingLoop),
+      Instructions(EntryBlockInstructions) {
+  BaseName = getIslCompatibleName(
+      "Stmt", R.getNameStr(), parent.getNextStmtIdx(), "", UseInstructionNames);
+}
+
+ScopStmt::ScopStmt(Scop &parent, BasicBlock &bb, Loop *SurroundingLoop,
+                   std::vector<Instruction *> Instructions, int Count)
+    : Parent(parent), InvalidDomain(nullptr), Domain(nullptr), BB(&bb),
+      Build(nullptr), SurroundingLoop(SurroundingLoop),
+      Instructions(Instructions) {
+  std::string S = "";
+  if (Count != 0)
+    S += std::to_string(Count);
+  BaseName = getIslCompatibleName("Stmt", &bb, parent.getNextStmtIdx(), S,
+                                  UseInstructionNames);
+}
+
+ScopStmt::ScopStmt(Scop &parent, isl::map SourceRel, isl::map TargetRel,
+                   isl::set NewDomain)
+    : Parent(parent), InvalidDomain(nullptr), Domain(NewDomain),
+      Build(nullptr) {
+  BaseName = getIslCompatibleName("CopyStmt_", "",
+                                  std::to_string(parent.getCopyStmtsNum()));
+  isl::id Id = isl::id::alloc(getIslCtx(), getBaseName(), this);
+  Domain = Domain.set_tuple_id(Id);
+  TargetRel = TargetRel.set_tuple_id(isl::dim::in, Id);
+  auto *Access =
+      new MemoryAccess(this, MemoryAccess::AccessType::MUST_WRITE, TargetRel);
+  parent.addAccessFunction(Access);
+  addAccess(Access);
+  SourceRel = SourceRel.set_tuple_id(isl::dim::in, Id);
+  Access = new MemoryAccess(this, MemoryAccess::AccessType::READ, SourceRel);
+  parent.addAccessFunction(Access);
+  addAccess(Access);
+}
+
+ScopStmt::~ScopStmt() = default;
+
+std::string ScopStmt::getDomainStr() const { return Domain.to_str(); }
+
+std::string ScopStmt::getScheduleStr() const {
+  auto *S = getSchedule().release();
+  if (!S)
+    return {};
+  auto Str = stringFromIslObj(S);
+  isl_map_free(S);
+  return Str;
+}
+
+void ScopStmt::setInvalidDomain(isl::set ID) { InvalidDomain = ID; }
+
+BasicBlock *ScopStmt::getEntryBlock() const {
+  if (isBlockStmt())
+    return getBasicBlock();
+  return getRegion()->getEntry();
+}
+
+unsigned ScopStmt::getNumIterators() const { return NestLoops.size(); }
+
+const char *ScopStmt::getBaseName() const { return BaseName.c_str(); }
+
+Loop *ScopStmt::getLoopForDimension(unsigned Dimension) const {
+  return NestLoops[Dimension];
+}
+
+isl::ctx ScopStmt::getIslCtx() const { return Parent.getIslCtx(); }
+
+isl::set ScopStmt::getDomain() const { return Domain; }
+
+isl::space ScopStmt::getDomainSpace() const { return Domain.get_space(); }
+
+isl::id ScopStmt::getDomainId() const { return Domain.get_tuple_id(); }
+
+void ScopStmt::printInstructions(raw_ostream &OS) const {
+  OS << "Instructions {\n";
+
+  for (Instruction *Inst : Instructions)
+    OS.indent(16) << *Inst << "\n";
+
+  OS.indent(12) << "}\n";
+}
+
+void ScopStmt::print(raw_ostream &OS, bool PrintInstructions) const {
+  OS << "\t" << getBaseName() << "\n";
+  OS.indent(12) << "Domain :=\n";
+
+  if (Domain) {
+    OS.indent(16) << getDomainStr() << ";\n";
+  } else
+    OS.indent(16) << "n/a\n";
+
+  OS.indent(12) << "Schedule :=\n";
+
+  if (Domain) {
+    OS.indent(16) << getScheduleStr() << ";\n";
+  } else
+    OS.indent(16) << "n/a\n";
+
+  for (MemoryAccess *Access : MemAccs)
+    Access->print(OS);
+
+  if (PrintInstructions)
+    printInstructions(OS.indent(12));
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void ScopStmt::dump() const { print(dbgs(), true); }
+#endif
+
+void ScopStmt::removeAccessData(MemoryAccess *MA) {
+  if (MA->isRead() && MA->isOriginalValueKind()) {
+    bool Found = ValueReads.erase(MA->getAccessValue());
+    (void)Found;
+    assert(Found && "Expected access data not found");
+  }
+  if (MA->isWrite() && MA->isOriginalValueKind()) {
+    bool Found = ValueWrites.erase(cast<Instruction>(MA->getAccessValue()));
+    (void)Found;
+    assert(Found && "Expected access data not found");
+  }
+  if (MA->isWrite() && MA->isOriginalAnyPHIKind()) {
+    bool Found = PHIWrites.erase(cast<PHINode>(MA->getAccessInstruction()));
+    (void)Found;
+    assert(Found && "Expected access data not found");
+  }
+  if (MA->isRead() && MA->isOriginalAnyPHIKind()) {
+    bool Found = PHIReads.erase(cast<PHINode>(MA->getAccessInstruction()));
+    (void)Found;
+    assert(Found && "Expected access data not found");
+  }
+}
+
+void ScopStmt::removeMemoryAccess(MemoryAccess *MA) {
+  // Remove the memory accesses from this statement together with all scalar
+  // accesses that were caused by it. MemoryKind::Value READs have no access
+  // instruction, hence would not be removed by this function. However, it is
+  // only used for invariant LoadInst accesses, its arguments are always affine,
+  // hence synthesizable, and therefore there are no MemoryKind::Value READ
+  // accesses to be removed.
+  auto Predicate = [&](MemoryAccess *Acc) {
+    return Acc->getAccessInstruction() == MA->getAccessInstruction();
+  };
+  for (auto *MA : MemAccs) {
+    if (Predicate(MA)) {
+      removeAccessData(MA);
+      Parent.removeAccessData(MA);
+    }
+  }
+  MemAccs.erase(std::remove_if(MemAccs.begin(), MemAccs.end(), Predicate),
+                MemAccs.end());
+  InstructionToAccess.erase(MA->getAccessInstruction());
+}
+
+void ScopStmt::removeSingleMemoryAccess(MemoryAccess *MA) {
+  auto MAIt = std::find(MemAccs.begin(), MemAccs.end(), MA);
+  assert(MAIt != MemAccs.end());
+  MemAccs.erase(MAIt);
+
+  removeAccessData(MA);
+  Parent.removeAccessData(MA);
+
+  auto It = InstructionToAccess.find(MA->getAccessInstruction());
+  if (It != InstructionToAccess.end()) {
+    It->second.remove(MA);
+    if (It->second.empty())
+      InstructionToAccess.erase(MA->getAccessInstruction());
+  }
+}
+
+MemoryAccess *ScopStmt::ensureValueRead(Value *V) {
+  MemoryAccess *Access = lookupInputAccessOf(V);
+  if (Access)
+    return Access;
+
+  ScopArrayInfo *SAI =
+      Parent.getOrCreateScopArrayInfo(V, V->getType(), {}, MemoryKind::Value);
+  Access = new MemoryAccess(this, nullptr, MemoryAccess::READ, V, V->getType(),
+                            true, {}, {}, V, MemoryKind::Value);
+  Parent.addAccessFunction(Access);
+  Access->buildAccessRelation(SAI);
+  addAccess(Access);
+  Parent.addAccessData(Access);
+  return Access;
+}
+
+raw_ostream &polly::operator<<(raw_ostream &OS, const ScopStmt &S) {
+  S.print(OS, PollyPrintInstructions);
+  return OS;
+}
+
+//===----------------------------------------------------------------------===//
+/// Scop class implement
+
+void Scop::setContext(isl::set NewContext) {
+  Context = NewContext.align_params(Context.get_space());
+}
+
+namespace {
+
+/// Remap parameter values but keep AddRecs valid wrt. invariant loads.
+struct SCEVSensitiveParameterRewriter
+    : public SCEVRewriteVisitor<SCEVSensitiveParameterRewriter> {
+  const ValueToValueMap &VMap;
+
+public:
+  SCEVSensitiveParameterRewriter(const ValueToValueMap &VMap,
+                                 ScalarEvolution &SE)
+      : SCEVRewriteVisitor(SE), VMap(VMap) {}
+
+  static const SCEV *rewrite(const SCEV *E, ScalarEvolution &SE,
+                             const ValueToValueMap &VMap) {
+    SCEVSensitiveParameterRewriter SSPR(VMap, SE);
+    return SSPR.visit(E);
+  }
+
+  const SCEV *visitAddRecExpr(const SCEVAddRecExpr *E) {
+    auto *Start = visit(E->getStart());
+    auto *AddRec = SE.getAddRecExpr(SE.getConstant(E->getType(), 0),
+                                    visit(E->getStepRecurrence(SE)),
+                                    E->getLoop(), SCEV::FlagAnyWrap);
+    return SE.getAddExpr(Start, AddRec);
+  }
+
+  const SCEV *visitUnknown(const SCEVUnknown *E) {
+    if (auto *NewValue = VMap.lookup(E->getValue()))
+      return SE.getUnknown(NewValue);
+    return E;
+  }
+};
+
+/// Check whether we should remap a SCEV expression.
+struct SCEVFindInsideScop : public SCEVTraversal<SCEVFindInsideScop> {
+  const ValueToValueMap &VMap;
+  bool FoundInside = false;
+  const Scop *S;
+
+public:
+  SCEVFindInsideScop(const ValueToValueMap &VMap, ScalarEvolution &SE,
+                     const Scop *S)
+      : SCEVTraversal(*this), VMap(VMap), S(S) {}
+
+  static bool hasVariant(const SCEV *E, ScalarEvolution &SE,
+                         const ValueToValueMap &VMap, const Scop *S) {
+    SCEVFindInsideScop SFIS(VMap, SE, S);
+    SFIS.visitAll(E);
+    return SFIS.FoundInside;
+  }
+
+  bool follow(const SCEV *E) {
+    if (auto *AddRec = dyn_cast<SCEVAddRecExpr>(E)) {
+      FoundInside |= S->getRegion().contains(AddRec->getLoop());
+    } else if (auto *Unknown = dyn_cast<SCEVUnknown>(E)) {
+      if (Instruction *I = dyn_cast<Instruction>(Unknown->getValue()))
+        FoundInside |= S->getRegion().contains(I) && !VMap.count(I);
+    }
+    return !FoundInside;
+  }
+
+  bool isDone() { return FoundInside; }
+};
+
+} // end anonymous namespace
+
+const SCEV *Scop::getRepresentingInvariantLoadSCEV(const SCEV *E) const {
+  // Check whether it makes sense to rewrite the SCEV.  (ScalarEvolution
+  // doesn't like addition between an AddRec and an expression that
+  // doesn't have a dominance relationship with it.)
+  if (SCEVFindInsideScop::hasVariant(E, *SE, InvEquivClassVMap, this))
+    return E;
+
+  // Rewrite SCEV.
+  return SCEVSensitiveParameterRewriter::rewrite(E, *SE, InvEquivClassVMap);
+}
+
+// This table of function names is used to translate parameter names in more
+// human-readable names. This makes it easier to interpret Polly analysis
+// results.
+StringMap<std::string> KnownNames = {
+    {"_Z13get_global_idj", "global_id"},
+    {"_Z12get_local_idj", "local_id"},
+    {"_Z15get_global_sizej", "global_size"},
+    {"_Z14get_local_sizej", "local_size"},
+    {"_Z12get_work_dimv", "work_dim"},
+    {"_Z17get_global_offsetj", "global_offset"},
+    {"_Z12get_group_idj", "group_id"},
+    {"_Z14get_num_groupsj", "num_groups"},
+};
+
+static std::string getCallParamName(CallInst *Call) {
+  std::string Result;
+  raw_string_ostream OS(Result);
+  std::string Name = Call->getCalledFunction()->getName();
+
+  auto Iterator = KnownNames.find(Name);
+  if (Iterator != KnownNames.end())
+    Name = "__" + Iterator->getValue();
+  OS << Name;
+  for (auto &Operand : Call->arg_operands()) {
+    ConstantInt *Op = cast<ConstantInt>(&Operand);
+    OS << "_" << Op->getValue();
+  }
+  OS.flush();
+  return Result;
+}
+
+void Scop::createParameterId(const SCEV *Parameter) {
+  assert(Parameters.count(Parameter));
+  assert(!ParameterIds.count(Parameter));
+
+  std::string ParameterName = "p_" + std::to_string(getNumParams() - 1);
+
+  if (const SCEVUnknown *ValueParameter = dyn_cast<SCEVUnknown>(Parameter)) {
+    Value *Val = ValueParameter->getValue();
+    CallInst *Call = dyn_cast<CallInst>(Val);
+
+    if (Call && isConstCall(Call)) {
+      ParameterName = getCallParamName(Call);
+    } else if (UseInstructionNames) {
+      // If this parameter references a specific Value and this value has a name
+      // we use this name as it is likely to be unique and more useful than just
+      // a number.
+      if (Val->hasName())
+        ParameterName = Val->getName();
+      else if (LoadInst *LI = dyn_cast<LoadInst>(Val)) {
+        auto *LoadOrigin = LI->getPointerOperand()->stripInBoundsOffsets();
+        if (LoadOrigin->hasName()) {
+          ParameterName += "_loaded_from_";
+          ParameterName +=
+              LI->getPointerOperand()->stripInBoundsOffsets()->getName();
+        }
+      }
+    }
+
+    ParameterName = getIslCompatibleName("", ParameterName, "");
+  }
+
+  isl::id Id = isl::id::alloc(getIslCtx(), ParameterName,
+                              const_cast<void *>((const void *)Parameter));
+  ParameterIds[Parameter] = Id;
+}
+
+void Scop::addParams(const ParameterSetTy &NewParameters) {
+  for (const SCEV *Parameter : NewParameters) {
+    // Normalize the SCEV to get the representing element for an invariant load.
+    Parameter = extractConstantFactor(Parameter, *SE).second;
+    Parameter = getRepresentingInvariantLoadSCEV(Parameter);
+
+    if (Parameters.insert(Parameter))
+      createParameterId(Parameter);
+  }
+}
+
+isl::id Scop::getIdForParam(const SCEV *Parameter) const {
+  // Normalize the SCEV to get the representing element for an invariant load.
+  Parameter = getRepresentingInvariantLoadSCEV(Parameter);
+  return ParameterIds.lookup(Parameter);
+}
+
+isl::set Scop::addNonEmptyDomainConstraints(isl::set C) const {
+  isl_set *DomainContext = isl_union_set_params(getDomains().release());
+  return isl::manage(isl_set_intersect_params(C.release(), DomainContext));
+}
+
+bool Scop::isDominatedBy(const DominatorTree &DT, BasicBlock *BB) const {
+  return DT.dominates(BB, getEntry());
+}
+
+void Scop::addUserAssumptions(
+    AssumptionCache &AC, DominatorTree &DT, LoopInfo &LI,
+    DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) {
+  for (auto &Assumption : AC.assumptions()) {
+    auto *CI = dyn_cast_or_null<CallInst>(Assumption);
+    if (!CI || CI->getNumArgOperands() != 1)
+      continue;
+
+    bool InScop = contains(CI);
+    if (!InScop && !isDominatedBy(DT, CI->getParent()))
+      continue;
+
+    auto *L = LI.getLoopFor(CI->getParent());
+    auto *Val = CI->getArgOperand(0);
+    ParameterSetTy DetectedParams;
+    if (!isAffineConstraint(Val, &R, L, *SE, DetectedParams)) {
+      ORE.emit(
+          OptimizationRemarkAnalysis(DEBUG_TYPE, "IgnoreUserAssumption", CI)
+          << "Non-affine user assumption ignored.");
+      continue;
+    }
+
+    // Collect all newly introduced parameters.
+    ParameterSetTy NewParams;
+    for (auto *Param : DetectedParams) {
+      Param = extractConstantFactor(Param, *SE).second;
+      Param = getRepresentingInvariantLoadSCEV(Param);
+      if (Parameters.count(Param))
+        continue;
+      NewParams.insert(Param);
+    }
+
+    SmallVector<isl_set *, 2> ConditionSets;
+    auto *TI = InScop ? CI->getParent()->getTerminator() : nullptr;
+    BasicBlock *BB = InScop ? CI->getParent() : getRegion().getEntry();
+    auto *Dom = InScop ? DomainMap[BB].copy() : Context.copy();
+    assert(Dom && "Cannot propagate a nullptr.");
+    bool Valid = buildConditionSets(*this, BB, Val, TI, L, Dom,
+                                    InvalidDomainMap, ConditionSets);
+    isl_set_free(Dom);
+
+    if (!Valid)
+      continue;
+
+    isl_set *AssumptionCtx = nullptr;
+    if (InScop) {
+      AssumptionCtx = isl_set_complement(isl_set_params(ConditionSets[1]));
+      isl_set_free(ConditionSets[0]);
+    } else {
+      AssumptionCtx = isl_set_complement(ConditionSets[1]);
+      AssumptionCtx = isl_set_intersect(AssumptionCtx, ConditionSets[0]);
+    }
+
+    // Project out newly introduced parameters as they are not otherwise useful.
+    if (!NewParams.empty()) {
+      for (unsigned u = 0; u < isl_set_n_param(AssumptionCtx); u++) {
+        auto *Id = isl_set_get_dim_id(AssumptionCtx, isl_dim_param, u);
+        auto *Param = static_cast<const SCEV *>(isl_id_get_user(Id));
+        isl_id_free(Id);
+
+        if (!NewParams.count(Param))
+          continue;
+
+        AssumptionCtx =
+            isl_set_project_out(AssumptionCtx, isl_dim_param, u--, 1);
+      }
+    }
+    ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "UserAssumption", CI)
+             << "Use user assumption: " << stringFromIslObj(AssumptionCtx));
+    Context = Context.intersect(isl::manage(AssumptionCtx));
+  }
+}
+
+void Scop::addUserContext() {
+  if (UserContextStr.empty())
+    return;
+
+  isl_set *UserContext =
+      isl_set_read_from_str(getIslCtx().get(), UserContextStr.c_str());
+  isl_space *Space = getParamSpace().release();
+  if (isl_space_dim(Space, isl_dim_param) !=
+      isl_set_dim(UserContext, isl_dim_param)) {
+    auto SpaceStr = isl_space_to_str(Space);
+    errs() << "Error: the context provided in -polly-context has not the same "
+           << "number of dimensions than the computed context. Due to this "
+           << "mismatch, the -polly-context option is ignored. Please provide "
+           << "the context in the parameter space: " << SpaceStr << ".\n";
+    free(SpaceStr);
+    isl_set_free(UserContext);
+    isl_space_free(Space);
+    return;
+  }
+
+  for (unsigned i = 0; i < isl_space_dim(Space, isl_dim_param); i++) {
+    std::string NameContext = Context.get_dim_name(isl::dim::param, i);
+    std::string NameUserContext =
+        isl_set_get_dim_name(UserContext, isl_dim_param, i);
+
+    if (NameContext != NameUserContext) {
+      auto SpaceStr = isl_space_to_str(Space);
+      errs() << "Error: the name of dimension " << i
+             << " provided in -polly-context "
+             << "is '" << NameUserContext << "', but the name in the computed "
+             << "context is '" << NameContext
+             << "'. Due to this name mismatch, "
+             << "the -polly-context option is ignored. Please provide "
+             << "the context in the parameter space: " << SpaceStr << ".\n";
+      free(SpaceStr);
+      isl_set_free(UserContext);
+      isl_space_free(Space);
+      return;
+    }
+
+    UserContext =
+        isl_set_set_dim_id(UserContext, isl_dim_param, i,
+                           isl_space_get_dim_id(Space, isl_dim_param, i));
+  }
+
+  Context = Context.intersect(isl::manage(UserContext));
+  isl_space_free(Space);
+}
+
+void Scop::buildInvariantEquivalenceClasses() {
+  DenseMap<std::pair<const SCEV *, Type *>, LoadInst *> EquivClasses;
+
+  const InvariantLoadsSetTy &RIL = getRequiredInvariantLoads();
+  for (LoadInst *LInst : RIL) {
+    const SCEV *PointerSCEV = SE->getSCEV(LInst->getPointerOperand());
+
+    Type *Ty = LInst->getType();
+    LoadInst *&ClassRep = EquivClasses[std::make_pair(PointerSCEV, Ty)];
+    if (ClassRep) {
+      InvEquivClassVMap[LInst] = ClassRep;
+      continue;
+    }
+
+    ClassRep = LInst;
+    InvariantEquivClasses.emplace_back(
+        InvariantEquivClassTy{PointerSCEV, MemoryAccessList(), nullptr, Ty});
+  }
+}
+
+void Scop::buildContext() {
+  isl::space Space = isl::space::params_alloc(getIslCtx(), 0);
+  Context = isl::set::universe(Space);
+  InvalidContext = isl::set::empty(Space);
+  AssumedContext = isl::set::universe(Space);
+}
+
+void Scop::addParameterBounds() {
+  unsigned PDim = 0;
+  for (auto *Parameter : Parameters) {
+    ConstantRange SRange = SE->getSignedRange(Parameter);
+    Context = addRangeBoundsToSet(Context, SRange, PDim++, isl::dim::param);
+  }
+}
+
+static std::vector<isl::id> getFortranArrayIds(Scop::array_range Arrays) {
+  std::vector<isl::id> OutermostSizeIds;
+  for (auto Array : Arrays) {
+    // To check if an array is a Fortran array, we check if it has a isl_pw_aff
+    // for its outermost dimension. Fortran arrays will have this since the
+    // outermost dimension size can be picked up from their runtime description.
+    // TODO: actually need to check if it has a FAD, but for now this works.
+    if (Array->getNumberOfDimensions() > 0) {
+      isl::pw_aff PwAff = Array->getDimensionSizePw(0);
+      if (!PwAff)
+        continue;
+
+      isl::id Id =
+          isl::manage(isl_pw_aff_get_dim_id(PwAff.get(), isl_dim_param, 0));
+      assert(!Id.is_null() &&
+             "Invalid Id for PwAff expression in Fortran array");
+      Id.dump();
+      OutermostSizeIds.push_back(Id);
+    }
+  }
+  return OutermostSizeIds;
+}
+
+// The FORTRAN array size parameters are known to be non-negative.
+static isl::set boundFortranArrayParams(isl::set Context,
+                                        Scop::array_range Arrays) {
+  std::vector<isl::id> OutermostSizeIds;
+  OutermostSizeIds = getFortranArrayIds(Arrays);
+
+  for (isl::id Id : OutermostSizeIds) {
+    int dim = Context.find_dim_by_id(isl::dim::param, Id);
+    Context = Context.lower_bound_si(isl::dim::param, dim, 0);
+  }
+
+  return Context;
+}
+
+void Scop::realignParams() {
+  if (PollyIgnoreParamBounds)
+    return;
+
+  // Add all parameters into a common model.
+  isl::space Space = getFullParamSpace();
+
+  // Align the parameters of all data structures to the model.
+  Context = Context.align_params(Space);
+
+  // Bound the size of the fortran array dimensions.
+  Context = boundFortranArrayParams(Context, arrays());
+
+  // As all parameters are known add bounds to them.
+  addParameterBounds();
+
+  for (ScopStmt &Stmt : *this)
+    Stmt.realignParams();
+  // Simplify the schedule according to the context too.
+  Schedule = Schedule.gist_domain_params(getContext());
+}
+
+static isl::set simplifyAssumptionContext(isl::set AssumptionContext,
+                                          const Scop &S) {
+  // If we have modeled all blocks in the SCoP that have side effects we can
+  // simplify the context with the constraints that are needed for anything to
+  // be executed at all. However, if we have error blocks in the SCoP we already
+  // assumed some parameter combinations cannot occur and removed them from the
+  // domains, thus we cannot use the remaining domain to simplify the
+  // assumptions.
+  if (!S.hasErrorBlock()) {
+    auto DomainParameters = S.getDomains().params();
+    AssumptionContext = AssumptionContext.gist_params(DomainParameters);
+  }
+
+  AssumptionContext = AssumptionContext.gist_params(S.getContext());
+  return AssumptionContext;
+}
+
+void Scop::simplifyContexts() {
+  // The parameter constraints of the iteration domains give us a set of
+  // constraints that need to hold for all cases where at least a single
+  // statement iteration is executed in the whole scop. We now simplify the
+  // assumed context under the assumption that such constraints hold and at
+  // least a single statement iteration is executed. For cases where no
+  // statement instances are executed, the assumptions we have taken about
+  // the executed code do not matter and can be changed.
+  //
+  // WARNING: This only holds if the assumptions we have taken do not reduce
+  //          the set of statement instances that are executed. Otherwise we
+  //          may run into a case where the iteration domains suggest that
+  //          for a certain set of parameter constraints no code is executed,
+  //          but in the original program some computation would have been
+  //          performed. In such a case, modifying the run-time conditions and
+  //          possibly influencing the run-time check may cause certain scops
+  //          to not be executed.
+  //
+  // Example:
+  //
+  //   When delinearizing the following code:
+  //
+  //     for (long i = 0; i < 100; i++)
+  //       for (long j = 0; j < m; j++)
+  //         A[i+p][j] = 1.0;
+  //
+  //   we assume that the condition m <= 0 or (m >= 1 and p >= 0) holds as
+  //   otherwise we would access out of bound data. Now, knowing that code is
+  //   only executed for the case m >= 0, it is sufficient to assume p >= 0.
+  AssumedContext = simplifyAssumptionContext(AssumedContext, *this);
+  InvalidContext = InvalidContext.align_params(getParamSpace());
+}
+
+/// Add the minimal/maximal access in @p Set to @p User.
+static isl::stat
+buildMinMaxAccess(isl::set Set, Scop::MinMaxVectorTy &MinMaxAccesses, Scop &S) {
+  isl::pw_multi_aff MinPMA, MaxPMA;
+  isl::pw_aff LastDimAff;
+  isl::aff OneAff;
+  unsigned Pos;
+  isl::ctx Ctx = Set.get_ctx();
+
+  Set = Set.remove_divs();
+
+  if (isl_set_n_basic_set(Set.get()) >= MaxDisjunctsInDomain)
+    return isl::stat::error;
+
+  // Restrict the number of parameters involved in the access as the lexmin/
+  // lexmax computation will take too long if this number is high.
+  //
+  // Experiments with a simple test case using an i7 4800MQ:
+  //
+  //  #Parameters involved | Time (in sec)
+  //            6          |     0.01
+  //            7          |     0.04
+  //            8          |     0.12
+  //            9          |     0.40
+  //           10          |     1.54
+  //           11          |     6.78
+  //           12          |    30.38
+  //
+  if (isl_set_n_param(Set.get()) > RunTimeChecksMaxParameters) {
+    unsigned InvolvedParams = 0;
+    for (unsigned u = 0, e = isl_set_n_param(Set.get()); u < e; u++)
+      if (Set.involves_dims(isl::dim::param, u, 1))
+        InvolvedParams++;
+
+    if (InvolvedParams > RunTimeChecksMaxParameters)
+      return isl::stat::error;
+  }
+
+  if (isl_set_n_basic_set(Set.get()) > RunTimeChecksMaxAccessDisjuncts)
+    return isl::stat::error;
+
+  MinPMA = Set.lexmin_pw_multi_aff();
+  MaxPMA = Set.lexmax_pw_multi_aff();
+
+  if (isl_ctx_last_error(Ctx.get()) == isl_error_quota)
+    return isl::stat::error;
+
+  MinPMA = MinPMA.coalesce();
+  MaxPMA = MaxPMA.coalesce();
+
+  // Adjust the last dimension of the maximal access by one as we want to
+  // enclose the accessed memory region by MinPMA and MaxPMA. The pointer
+  // we test during code generation might now point after the end of the
+  // allocated array but we will never dereference it anyway.
+  assert(MaxPMA.dim(isl::dim::out) && "Assumed at least one output dimension");
+  Pos = MaxPMA.dim(isl::dim::out) - 1;
+  LastDimAff = MaxPMA.get_pw_aff(Pos);
+  OneAff = isl::aff(isl::local_space(LastDimAff.get_domain_space()));
+  OneAff = OneAff.add_constant_si(1);
+  LastDimAff = LastDimAff.add(OneAff);
+  MaxPMA = MaxPMA.set_pw_aff(Pos, LastDimAff);
+
+  MinMaxAccesses.push_back(std::make_pair(MinPMA, MaxPMA));
+
+  return isl::stat::ok;
+}
+
+static __isl_give isl_set *getAccessDomain(MemoryAccess *MA) {
+  isl_set *Domain = MA->getStatement()->getDomain().release();
+  Domain = isl_set_project_out(Domain, isl_dim_set, 0, isl_set_n_dim(Domain));
+  return isl_set_reset_tuple_id(Domain);
+}
+
+/// Wrapper function to calculate minimal/maximal accesses to each array.
+static bool calculateMinMaxAccess(Scop::AliasGroupTy AliasGroup, Scop &S,
+                                  Scop::MinMaxVectorTy &MinMaxAccesses) {
+  MinMaxAccesses.reserve(AliasGroup.size());
+
+  isl::union_set Domains = S.getDomains();
+  isl::union_map Accesses = isl::union_map::empty(S.getParamSpace());
+
+  for (MemoryAccess *MA : AliasGroup)
+    Accesses = Accesses.add_map(give(MA->getAccessRelation().release()));
+
+  Accesses = Accesses.intersect_domain(Domains);
+  isl::union_set Locations = Accesses.range();
+  Locations = Locations.coalesce();
+  Locations = Locations.detect_equalities();
+
+  auto Lambda = [&MinMaxAccesses, &S](isl::set Set) -> isl::stat {
+    return buildMinMaxAccess(Set, MinMaxAccesses, S);
+  };
+  return Locations.foreach_set(Lambda) == isl::stat::ok;
+}
+
+/// Helper to treat non-affine regions and basic blocks the same.
+///
+///{
+
+/// Return the block that is the representing block for @p RN.
+static inline BasicBlock *getRegionNodeBasicBlock(RegionNode *RN) {
+  return RN->isSubRegion() ? RN->getNodeAs<Region>()->getEntry()
+                           : RN->getNodeAs<BasicBlock>();
+}
+
+/// Return the @p idx'th block that is executed after @p RN.
+static inline BasicBlock *
+getRegionNodeSuccessor(RegionNode *RN, TerminatorInst *TI, unsigned idx) {
+  if (RN->isSubRegion()) {
+    assert(idx == 0);
+    return RN->getNodeAs<Region>()->getExit();
+  }
+  return TI->getSuccessor(idx);
+}
+
+/// Return the smallest loop surrounding @p RN.
+static inline Loop *getRegionNodeLoop(RegionNode *RN, LoopInfo &LI) {
+  if (!RN->isSubRegion()) {
+    BasicBlock *BB = RN->getNodeAs<BasicBlock>();
+    Loop *L = LI.getLoopFor(BB);
+
+    // Unreachable statements are not considered to belong to a LLVM loop, as
+    // they are not part of an actual loop in the control flow graph.
+    // Nevertheless, we handle certain unreachable statements that are common
+    // when modeling run-time bounds checks as being part of the loop to be
+    // able to model them and to later eliminate the run-time bounds checks.
+    //
+    // Specifically, for basic blocks that terminate in an unreachable and
+    // where the immediate predecessor is part of a loop, we assume these
+    // basic blocks belong to the loop the predecessor belongs to. This
+    // allows us to model the following code.
+    //
+    // for (i = 0; i < N; i++) {
+    //   if (i > 1024)
+    //     abort();            <- this abort might be translated to an
+    //                            unreachable
+    //
+    //   A[i] = ...
+    // }
+    if (!L && isa<UnreachableInst>(BB->getTerminator()) && BB->getPrevNode())
+      L = LI.getLoopFor(BB->getPrevNode());
+    return L;
+  }
+
+  Region *NonAffineSubRegion = RN->getNodeAs<Region>();
+  Loop *L = LI.getLoopFor(NonAffineSubRegion->getEntry());
+  while (L && NonAffineSubRegion->contains(L))
+    L = L->getParentLoop();
+  return L;
+}
+
+/// Get the number of blocks in @p L.
+///
+/// The number of blocks in a loop are the number of basic blocks actually
+/// belonging to the loop, as well as all single basic blocks that the loop
+/// exits to and which terminate in an unreachable instruction. We do not
+/// allow such basic blocks in the exit of a scop, hence they belong to the
+/// scop and represent run-time conditions which we want to model and
+/// subsequently speculate away.
+///
+/// @see getRegionNodeLoop for additional details.
+unsigned getNumBlocksInLoop(Loop *L) {
+  unsigned NumBlocks = L->getNumBlocks();
+  SmallVector<BasicBlock *, 4> ExitBlocks;
+  L->getExitBlocks(ExitBlocks);
+
+  for (auto ExitBlock : ExitBlocks) {
+    if (isa<UnreachableInst>(ExitBlock->getTerminator()))
+      NumBlocks++;
+  }
+  return NumBlocks;
+}
+
+static inline unsigned getNumBlocksInRegionNode(RegionNode *RN) {
+  if (!RN->isSubRegion())
+    return 1;
+
+  Region *R = RN->getNodeAs<Region>();
+  return std::distance(R->block_begin(), R->block_end());
+}
+
+static bool containsErrorBlock(RegionNode *RN, const Region &R, LoopInfo &LI,
+                               const DominatorTree &DT) {
+  if (!RN->isSubRegion())
+    return isErrorBlock(*RN->getNodeAs<BasicBlock>(), R, LI, DT);
+  for (BasicBlock *BB : RN->getNodeAs<Region>()->blocks())
+    if (isErrorBlock(*BB, R, LI, DT))
+      return true;
+  return false;
+}
+
+///}
+
+static inline __isl_give isl_set *addDomainDimId(__isl_take isl_set *Domain,
+                                                 unsigned Dim, Loop *L) {
+  Domain = isl_set_lower_bound_si(Domain, isl_dim_set, Dim, -1);
+  isl_id *DimId =
+      isl_id_alloc(isl_set_get_ctx(Domain), nullptr, static_cast<void *>(L));
+  return isl_set_set_dim_id(Domain, isl_dim_set, Dim, DimId);
+}
+
+isl::set Scop::getDomainConditions(const ScopStmt *Stmt) const {
+  return getDomainConditions(Stmt->getEntryBlock());
+}
+
+isl::set Scop::getDomainConditions(BasicBlock *BB) const {
+  auto DIt = DomainMap.find(BB);
+  if (DIt != DomainMap.end())
+    return DIt->getSecond();
+
+  auto &RI = *R.getRegionInfo();
+  auto *BBR = RI.getRegionFor(BB);
+  while (BBR->getEntry() == BB)
+    BBR = BBR->getParent();
+  return getDomainConditions(BBR->getEntry());
+}
+
+bool Scop::buildDomains(Region *R, DominatorTree &DT, LoopInfo &LI,
+                        DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) {
+  bool IsOnlyNonAffineRegion = isNonAffineSubRegion(R);
+  auto *EntryBB = R->getEntry();
+  auto *L = IsOnlyNonAffineRegion ? nullptr : LI.getLoopFor(EntryBB);
+  int LD = getRelativeLoopDepth(L);
+  auto *S = isl_set_universe(isl_space_set_alloc(getIslCtx().get(), 0, LD + 1));
+
+  while (LD-- >= 0) {
+    S = addDomainDimId(S, LD + 1, L);
+    L = L->getParentLoop();
+  }
+
+  InvalidDomainMap[EntryBB] = isl::manage(isl_set_empty(isl_set_get_space(S)));
+  DomainMap[EntryBB] = isl::manage(S);
+
+  if (IsOnlyNonAffineRegion)
+    return !containsErrorBlock(R->getNode(), *R, LI, DT);
+
+  if (!buildDomainsWithBranchConstraints(R, DT, LI, InvalidDomainMap))
+    return false;
+
+  if (!propagateDomainConstraints(R, DT, LI, InvalidDomainMap))
+    return false;
+
+  // Error blocks and blocks dominated by them have been assumed to never be
+  // executed. Representing them in the Scop does not add any value. In fact,
+  // it is likely to cause issues during construction of the ScopStmts. The
+  // contents of error blocks have not been verified to be expressible and
+  // will cause problems when building up a ScopStmt for them.
+  // Furthermore, basic blocks dominated by error blocks may reference
+  // instructions in the error block which, if the error block is not modeled,
+  // can themselves not be constructed properly. To this end we will replace
+  // the domains of error blocks and those only reachable via error blocks
+  // with an empty set. Additionally, we will record for each block under which
+  // parameter combination it would be reached via an error block in its
+  // InvalidDomain. This information is needed during load hoisting.
+  if (!propagateInvalidStmtDomains(R, DT, LI, InvalidDomainMap))
+    return false;
+
+  return true;
+}
+
+/// Adjust the dimensions of @p Dom that was constructed for @p OldL
+///        to be compatible to domains constructed for loop @p NewL.
+///
+/// This function assumes @p NewL and @p OldL are equal or there is a CFG
+/// edge from @p OldL to @p NewL.
+static __isl_give isl_set *adjustDomainDimensions(Scop &S,
+                                                  __isl_take isl_set *Dom,
+                                                  Loop *OldL, Loop *NewL) {
+  // If the loops are the same there is nothing to do.
+  if (NewL == OldL)
+    return Dom;
+
+  int OldDepth = S.getRelativeLoopDepth(OldL);
+  int NewDepth = S.getRelativeLoopDepth(NewL);
+  // If both loops are non-affine loops there is nothing to do.
+  if (OldDepth == -1 && NewDepth == -1)
+    return Dom;
+
+  // Distinguish three cases:
+  //   1) The depth is the same but the loops are not.
+  //      => One loop was left one was entered.
+  //   2) The depth increased from OldL to NewL.
+  //      => One loop was entered, none was left.
+  //   3) The depth decreased from OldL to NewL.
+  //      => Loops were left were difference of the depths defines how many.
+  if (OldDepth == NewDepth) {
+    assert(OldL->getParentLoop() == NewL->getParentLoop());
+    Dom = isl_set_project_out(Dom, isl_dim_set, NewDepth, 1);
+    Dom = isl_set_add_dims(Dom, isl_dim_set, 1);
+    Dom = addDomainDimId(Dom, NewDepth, NewL);
+  } else if (OldDepth < NewDepth) {
+    assert(OldDepth + 1 == NewDepth);
+    auto &R = S.getRegion();
+    (void)R;
+    assert(NewL->getParentLoop() == OldL ||
+           ((!OldL || !R.contains(OldL)) && R.contains(NewL)));
+    Dom = isl_set_add_dims(Dom, isl_dim_set, 1);
+    Dom = addDomainDimId(Dom, NewDepth, NewL);
+  } else {
+    assert(OldDepth > NewDepth);
+    int Diff = OldDepth - NewDepth;
+    int NumDim = isl_set_n_dim(Dom);
+    assert(NumDim >= Diff);
+    Dom = isl_set_project_out(Dom, isl_dim_set, NumDim - Diff, Diff);
+  }
+
+  return Dom;
+}
+
+bool Scop::propagateInvalidStmtDomains(
+    Region *R, DominatorTree &DT, LoopInfo &LI,
+    DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) {
+  ReversePostOrderTraversal<Region *> RTraversal(R);
+  for (auto *RN : RTraversal) {
+
+    // Recurse for affine subregions but go on for basic blocks and non-affine
+    // subregions.
+    if (RN->isSubRegion()) {
+      Region *SubRegion = RN->getNodeAs<Region>();
+      if (!isNonAffineSubRegion(SubRegion)) {
+        propagateInvalidStmtDomains(SubRegion, DT, LI, InvalidDomainMap);
+        continue;
+      }
+    }
+
+    bool ContainsErrorBlock = containsErrorBlock(RN, getRegion(), LI, DT);
+    BasicBlock *BB = getRegionNodeBasicBlock(RN);
+    isl::set &Domain = DomainMap[BB];
+    assert(Domain && "Cannot propagate a nullptr");
+
+    isl::set InvalidDomain = InvalidDomainMap[BB];
+
+    bool IsInvalidBlock = ContainsErrorBlock || Domain.is_subset(InvalidDomain);
+
+    if (!IsInvalidBlock) {
+      InvalidDomain = InvalidDomain.intersect(Domain);
+    } else {
+      InvalidDomain = Domain;
+      isl::set DomPar = Domain.params();
+      recordAssumption(ERRORBLOCK, DomPar, BB->getTerminator()->getDebugLoc(),
+                       AS_RESTRICTION);
+      Domain = nullptr;
+    }
+
+    if (InvalidDomain.is_empty()) {
+      InvalidDomainMap[BB] = InvalidDomain;
+      continue;
+    }
+
+    auto *BBLoop = getRegionNodeLoop(RN, LI);
+    auto *TI = BB->getTerminator();
+    unsigned NumSuccs = RN->isSubRegion() ? 1 : TI->getNumSuccessors();
+    for (unsigned u = 0; u < NumSuccs; u++) {
+      auto *SuccBB = getRegionNodeSuccessor(RN, TI, u);
+
+      // Skip successors outside the SCoP.
+      if (!contains(SuccBB))
+        continue;
+
+      // Skip backedges.
+      if (DT.dominates(SuccBB, BB))
+        continue;
+
+      Loop *SuccBBLoop = getFirstNonBoxedLoopFor(SuccBB, LI, getBoxedLoops());
+
+      auto *AdjustedInvalidDomain = adjustDomainDimensions(
+          *this, InvalidDomain.copy(), BBLoop, SuccBBLoop);
+
+      auto *SuccInvalidDomain = InvalidDomainMap[SuccBB].copy();
+      SuccInvalidDomain =
+          isl_set_union(SuccInvalidDomain, AdjustedInvalidDomain);
+      SuccInvalidDomain = isl_set_coalesce(SuccInvalidDomain);
+      unsigned NumConjucts = isl_set_n_basic_set(SuccInvalidDomain);
+
+      InvalidDomainMap[SuccBB] = isl::manage(SuccInvalidDomain);
+
+      // Check if the maximal number of domain disjunctions was reached.
+      // In case this happens we will bail.
+      if (NumConjucts < MaxDisjunctsInDomain)
+        continue;
+
+      InvalidDomainMap.erase(BB);
+      invalidate(COMPLEXITY, TI->getDebugLoc(), TI->getParent());
+      return false;
+    }
+
+    InvalidDomainMap[BB] = InvalidDomain;
+  }
+
+  return true;
+}
+
+void Scop::propagateDomainConstraintsToRegionExit(
+    BasicBlock *BB, Loop *BBLoop,
+    SmallPtrSetImpl<BasicBlock *> &FinishedExitBlocks, LoopInfo &LI,
+    DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) {
+  // Check if the block @p BB is the entry of a region. If so we propagate it's
+  // domain to the exit block of the region. Otherwise we are done.
+  auto *RI = R.getRegionInfo();
+  auto *BBReg = RI ? RI->getRegionFor(BB) : nullptr;
+  auto *ExitBB = BBReg ? BBReg->getExit() : nullptr;
+  if (!BBReg || BBReg->getEntry() != BB || !contains(ExitBB))
+    return;
+
+  // Do not propagate the domain if there is a loop backedge inside the region
+  // that would prevent the exit block from being executed.
+  auto *L = BBLoop;
+  while (L && contains(L)) {
+    SmallVector<BasicBlock *, 4> LatchBBs;
+    BBLoop->getLoopLatches(LatchBBs);
+    for (auto *LatchBB : LatchBBs)
+      if (BB != LatchBB && BBReg->contains(LatchBB))
+        return;
+    L = L->getParentLoop();
+  }
+
+  isl::set Domain = DomainMap[BB];
+  assert(Domain && "Cannot propagate a nullptr");
+
+  Loop *ExitBBLoop = getFirstNonBoxedLoopFor(ExitBB, LI, getBoxedLoops());
+
+  // Since the dimensions of @p BB and @p ExitBB might be different we have to
+  // adjust the domain before we can propagate it.
+  isl::set AdjustedDomain = isl::manage(
+      adjustDomainDimensions(*this, Domain.copy(), BBLoop, ExitBBLoop));
+  isl::set &ExitDomain = DomainMap[ExitBB];
+
+  // If the exit domain is not yet created we set it otherwise we "add" the
+  // current domain.
+  ExitDomain = ExitDomain ? AdjustedDomain.unite(ExitDomain) : AdjustedDomain;
+
+  // Initialize the invalid domain.
+  InvalidDomainMap[ExitBB] = ExitDomain.empty(ExitDomain.get_space());
+
+  FinishedExitBlocks.insert(ExitBB);
+}
+
+bool Scop::buildDomainsWithBranchConstraints(
+    Region *R, DominatorTree &DT, LoopInfo &LI,
+    DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) {
+  // To create the domain for each block in R we iterate over all blocks and
+  // subregions in R and propagate the conditions under which the current region
+  // element is executed. To this end we iterate in reverse post order over R as
+  // it ensures that we first visit all predecessors of a region node (either a
+  // basic block or a subregion) before we visit the region node itself.
+  // Initially, only the domain for the SCoP region entry block is set and from
+  // there we propagate the current domain to all successors, however we add the
+  // condition that the successor is actually executed next.
+  // As we are only interested in non-loop carried constraints here we can
+  // simply skip loop back edges.
+
+  SmallPtrSet<BasicBlock *, 8> FinishedExitBlocks;
+  ReversePostOrderTraversal<Region *> RTraversal(R);
+  for (auto *RN : RTraversal) {
+    // Recurse for affine subregions but go on for basic blocks and non-affine
+    // subregions.
+    if (RN->isSubRegion()) {
+      Region *SubRegion = RN->getNodeAs<Region>();
+      if (!isNonAffineSubRegion(SubRegion)) {
+        if (!buildDomainsWithBranchConstraints(SubRegion, DT, LI,
+                                               InvalidDomainMap))
+          return false;
+        continue;
+      }
+    }
+
+    if (containsErrorBlock(RN, getRegion(), LI, DT))
+      HasErrorBlock = true;
+
+    BasicBlock *BB = getRegionNodeBasicBlock(RN);
+    TerminatorInst *TI = BB->getTerminator();
+
+    if (isa<UnreachableInst>(TI))
+      continue;
+
+    isl::set Domain = DomainMap.lookup(BB);
+    if (!Domain)
+      continue;
+    MaxLoopDepth = std::max(MaxLoopDepth, isl_set_n_dim(Domain.get()));
+
+    auto *BBLoop = getRegionNodeLoop(RN, LI);
+    // Propagate the domain from BB directly to blocks that have a superset
+    // domain, at the moment only region exit nodes of regions that start in BB.
+    propagateDomainConstraintsToRegionExit(BB, BBLoop, FinishedExitBlocks, LI,
+                                           InvalidDomainMap);
+
+    // If all successors of BB have been set a domain through the propagation
+    // above we do not need to build condition sets but can just skip this
+    // block. However, it is important to note that this is a local property
+    // with regards to the region @p R. To this end FinishedExitBlocks is a
+    // local variable.
+    auto IsFinishedRegionExit = [&FinishedExitBlocks](BasicBlock *SuccBB) {
+      return FinishedExitBlocks.count(SuccBB);
+    };
+    if (std::all_of(succ_begin(BB), succ_end(BB), IsFinishedRegionExit))
+      continue;
+
+    // Build the condition sets for the successor nodes of the current region
+    // node. If it is a non-affine subregion we will always execute the single
+    // exit node, hence the single entry node domain is the condition set. For
+    // basic blocks we use the helper function buildConditionSets.
+    SmallVector<isl_set *, 8> ConditionSets;
+    if (RN->isSubRegion())
+      ConditionSets.push_back(Domain.copy());
+    else if (!buildConditionSets(*this, BB, TI, BBLoop, Domain.get(),
+                                 InvalidDomainMap, ConditionSets))
+      return false;
+
+    // Now iterate over the successors and set their initial domain based on
+    // their condition set. We skip back edges here and have to be careful when
+    // we leave a loop not to keep constraints over a dimension that doesn't
+    // exist anymore.
+    assert(RN->isSubRegion() || TI->getNumSuccessors() == ConditionSets.size());
+    for (unsigned u = 0, e = ConditionSets.size(); u < e; u++) {
+      isl::set CondSet = isl::manage(ConditionSets[u]);
+      BasicBlock *SuccBB = getRegionNodeSuccessor(RN, TI, u);
+
+      // Skip blocks outside the region.
+      if (!contains(SuccBB))
+        continue;
+
+      // If we propagate the domain of some block to "SuccBB" we do not have to
+      // adjust the domain.
+      if (FinishedExitBlocks.count(SuccBB))
+        continue;
+
+      // Skip back edges.
+      if (DT.dominates(SuccBB, BB))
+        continue;
+
+      Loop *SuccBBLoop = getFirstNonBoxedLoopFor(SuccBB, LI, getBoxedLoops());
+
+      CondSet = isl::manage(
+          adjustDomainDimensions(*this, CondSet.copy(), BBLoop, SuccBBLoop));
+
+      // Set the domain for the successor or merge it with an existing domain in
+      // case there are multiple paths (without loop back edges) to the
+      // successor block.
+      isl::set &SuccDomain = DomainMap[SuccBB];
+
+      if (SuccDomain) {
+        SuccDomain = SuccDomain.unite(CondSet).coalesce();
+      } else {
+        // Initialize the invalid domain.
+        InvalidDomainMap[SuccBB] = CondSet.empty(CondSet.get_space());
+        SuccDomain = CondSet;
+      }
+
+      SuccDomain = SuccDomain.detect_equalities();
+
+      // Check if the maximal number of domain disjunctions was reached.
+      // In case this happens we will clean up and bail.
+      if (isl_set_n_basic_set(SuccDomain.get()) < MaxDisjunctsInDomain)
+        continue;
+
+      invalidate(COMPLEXITY, DebugLoc());
+      while (++u < ConditionSets.size())
+        isl_set_free(ConditionSets[u]);
+      return false;
+    }
+  }
+
+  return true;
+}
+
+isl::set Scop::getPredecessorDomainConstraints(BasicBlock *BB, isl::set Domain,
+                                               DominatorTree &DT,
+                                               LoopInfo &LI) {
+  // If @p BB is the ScopEntry we are done
+  if (R.getEntry() == BB)
+    return isl::set::universe(Domain.get_space());
+
+  // The region info of this function.
+  auto &RI = *R.getRegionInfo();
+
+  Loop *BBLoop = getFirstNonBoxedLoopFor(BB, LI, getBoxedLoops());
+
+  // A domain to collect all predecessor domains, thus all conditions under
+  // which the block is executed. To this end we start with the empty domain.
+  isl::set PredDom = isl::set::empty(Domain.get_space());
+
+  // Set of regions of which the entry block domain has been propagated to BB.
+  // all predecessors inside any of the regions can be skipped.
+  SmallSet<Region *, 8> PropagatedRegions;
+
+  for (auto *PredBB : predecessors(BB)) {
+    // Skip backedges.
+    if (DT.dominates(BB, PredBB))
+      continue;
+
+    // If the predecessor is in a region we used for propagation we can skip it.
+    auto PredBBInRegion = [PredBB](Region *PR) { return PR->contains(PredBB); };
+    if (std::any_of(PropagatedRegions.begin(), PropagatedRegions.end(),
+                    PredBBInRegion)) {
+      continue;
+    }
+
+    // Check if there is a valid region we can use for propagation, thus look
+    // for a region that contains the predecessor and has @p BB as exit block.
+    auto *PredR = RI.getRegionFor(PredBB);
+    while (PredR->getExit() != BB && !PredR->contains(BB))
+      PredR->getParent();
+
+    // If a valid region for propagation was found use the entry of that region
+    // for propagation, otherwise the PredBB directly.
+    if (PredR->getExit() == BB) {
+      PredBB = PredR->getEntry();
+      PropagatedRegions.insert(PredR);
+    }
+
+    auto *PredBBDom = getDomainConditions(PredBB).release();
+    Loop *PredBBLoop = getFirstNonBoxedLoopFor(PredBB, LI, getBoxedLoops());
+
+    PredBBDom = adjustDomainDimensions(*this, PredBBDom, PredBBLoop, BBLoop);
+
+    PredDom = PredDom.unite(isl::manage(PredBBDom));
+  }
+
+  return PredDom;
+}
+
+bool Scop::propagateDomainConstraints(
+    Region *R, DominatorTree &DT, LoopInfo &LI,
+    DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) {
+  // Iterate over the region R and propagate the domain constrains from the
+  // predecessors to the current node. In contrast to the
+  // buildDomainsWithBranchConstraints function, this one will pull the domain
+  // information from the predecessors instead of pushing it to the successors.
+  // Additionally, we assume the domains to be already present in the domain
+  // map here. However, we iterate again in reverse post order so we know all
+  // predecessors have been visited before a block or non-affine subregion is
+  // visited.
+
+  ReversePostOrderTraversal<Region *> RTraversal(R);
+  for (auto *RN : RTraversal) {
+    // Recurse for affine subregions but go on for basic blocks and non-affine
+    // subregions.
+    if (RN->isSubRegion()) {
+      Region *SubRegion = RN->getNodeAs<Region>();
+      if (!isNonAffineSubRegion(SubRegion)) {
+        if (!propagateDomainConstraints(SubRegion, DT, LI, InvalidDomainMap))
+          return false;
+        continue;
+      }
+    }
+
+    BasicBlock *BB = getRegionNodeBasicBlock(RN);
+    isl::set &Domain = DomainMap[BB];
+    assert(Domain);
+
+    // Under the union of all predecessor conditions we can reach this block.
+    isl::set PredDom = getPredecessorDomainConstraints(BB, Domain, DT, LI);
+    Domain = Domain.intersect(PredDom).coalesce();
+    Domain = Domain.align_params(getParamSpace());
+
+    Loop *BBLoop = getRegionNodeLoop(RN, LI);
+    if (BBLoop && BBLoop->getHeader() == BB && contains(BBLoop))
+      if (!addLoopBoundsToHeaderDomain(BBLoop, LI, InvalidDomainMap))
+        return false;
+  }
+
+  return true;
+}
+
+/// Create a map to map from a given iteration to a subsequent iteration.
+///
+/// This map maps from SetSpace -> SetSpace where the dimensions @p Dim
+/// is incremented by one and all other dimensions are equal, e.g.,
+///             [i0, i1, i2, i3] -> [i0, i1, i2 + 1, i3]
+///
+/// if @p Dim is 2 and @p SetSpace has 4 dimensions.
+static __isl_give isl_map *
+createNextIterationMap(__isl_take isl_space *SetSpace, unsigned Dim) {
+  auto *MapSpace = isl_space_map_from_set(SetSpace);
+  auto *NextIterationMap = isl_map_universe(isl_space_copy(MapSpace));
+  for (unsigned u = 0; u < isl_map_dim(NextIterationMap, isl_dim_in); u++)
+    if (u != Dim)
+      NextIterationMap =
+          isl_map_equate(NextIterationMap, isl_dim_in, u, isl_dim_out, u);
+  auto *C = isl_constraint_alloc_equality(isl_local_space_from_space(MapSpace));
+  C = isl_constraint_set_constant_si(C, 1);
+  C = isl_constraint_set_coefficient_si(C, isl_dim_in, Dim, 1);
+  C = isl_constraint_set_coefficient_si(C, isl_dim_out, Dim, -1);
+  NextIterationMap = isl_map_add_constraint(NextIterationMap, C);
+  return NextIterationMap;
+}
+
+bool Scop::addLoopBoundsToHeaderDomain(
+    Loop *L, LoopInfo &LI, DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) {
+  int LoopDepth = getRelativeLoopDepth(L);
+  assert(LoopDepth >= 0 && "Loop in region should have at least depth one");
+
+  BasicBlock *HeaderBB = L->getHeader();
+  assert(DomainMap.count(HeaderBB));
+  isl::set &HeaderBBDom = DomainMap[HeaderBB];
+
+  isl::map NextIterationMap = isl::manage(
+      createNextIterationMap(HeaderBBDom.get_space().release(), LoopDepth));
+
+  isl::set UnionBackedgeCondition = HeaderBBDom.empty(HeaderBBDom.get_space());
+
+  SmallVector<BasicBlock *, 4> LatchBlocks;
+  L->getLoopLatches(LatchBlocks);
+
+  for (BasicBlock *LatchBB : LatchBlocks) {
+    // If the latch is only reachable via error statements we skip it.
+    isl::set LatchBBDom = DomainMap.lookup(LatchBB);
+    if (!LatchBBDom)
+      continue;
+
+    isl::set BackedgeCondition = nullptr;
+
+    TerminatorInst *TI = LatchBB->getTerminator();
+    BranchInst *BI = dyn_cast<BranchInst>(TI);
+    assert(BI && "Only branch instructions allowed in loop latches");
+
+    if (BI->isUnconditional())
+      BackedgeCondition = LatchBBDom;
+    else {
+      SmallVector<isl_set *, 8> ConditionSets;
+      int idx = BI->getSuccessor(0) != HeaderBB;
+      if (!buildConditionSets(*this, LatchBB, TI, L, LatchBBDom.get(),
+                              InvalidDomainMap, ConditionSets))
+        return false;
+
+      // Free the non back edge condition set as we do not need it.
+      isl_set_free(ConditionSets[1 - idx]);
+
+      BackedgeCondition = isl::manage(ConditionSets[idx]);
+    }
+
+    int LatchLoopDepth = getRelativeLoopDepth(LI.getLoopFor(LatchBB));
+    assert(LatchLoopDepth >= LoopDepth);
+    BackedgeCondition = BackedgeCondition.project_out(
+        isl::dim::set, LoopDepth + 1, LatchLoopDepth - LoopDepth);
+    UnionBackedgeCondition = UnionBackedgeCondition.unite(BackedgeCondition);
+  }
+
+  isl::map ForwardMap = ForwardMap.lex_le(HeaderBBDom.get_space());
+  for (int i = 0; i < LoopDepth; i++)
+    ForwardMap = ForwardMap.equate(isl::dim::in, i, isl::dim::out, i);
+
+  isl::set UnionBackedgeConditionComplement =
+      UnionBackedgeCondition.complement();
+  UnionBackedgeConditionComplement =
+      UnionBackedgeConditionComplement.lower_bound_si(isl::dim::set, LoopDepth,
+                                                      0);
+  UnionBackedgeConditionComplement =
+      UnionBackedgeConditionComplement.apply(ForwardMap);
+  HeaderBBDom = HeaderBBDom.subtract(UnionBackedgeConditionComplement);
+  HeaderBBDom = HeaderBBDom.apply(NextIterationMap);
+
+  auto Parts = partitionSetParts(HeaderBBDom.copy(), LoopDepth);
+  HeaderBBDom = isl::manage(Parts.second);
+
+  // Check if there is a <nsw> tagged AddRec for this loop and if so do not add
+  // the bounded assumptions to the context as they are already implied by the
+  // <nsw> tag.
+  if (Affinator.hasNSWAddRecForLoop(L)) {
+    isl_set_free(Parts.first);
+    return true;
+  }
+
+  isl::set UnboundedCtx = isl::manage(Parts.first).params();
+  recordAssumption(INFINITELOOP, UnboundedCtx,
+                   HeaderBB->getTerminator()->getDebugLoc(), AS_RESTRICTION);
+  return true;
+}
+
+MemoryAccess *Scop::lookupBasePtrAccess(MemoryAccess *MA) {
+  Value *PointerBase = MA->getOriginalBaseAddr();
+
+  auto *PointerBaseInst = dyn_cast<Instruction>(PointerBase);
+  if (!PointerBaseInst)
+    return nullptr;
+
+  auto *BasePtrStmt = getStmtFor(PointerBaseInst);
+  if (!BasePtrStmt)
+    return nullptr;
+
+  return BasePtrStmt->getArrayAccessOrNULLFor(PointerBaseInst);
+}
+
+bool Scop::hasNonHoistableBasePtrInScop(MemoryAccess *MA,
+                                        isl::union_map Writes) {
+  if (auto *BasePtrMA = lookupBasePtrAccess(MA)) {
+    return getNonHoistableCtx(BasePtrMA, Writes).is_null();
+  }
+
+  Value *BaseAddr = MA->getOriginalBaseAddr();
+  if (auto *BasePtrInst = dyn_cast<Instruction>(BaseAddr))
+    if (!isa<LoadInst>(BasePtrInst))
+      return contains(BasePtrInst);
+
+  return false;
+}
+
+bool Scop::buildAliasChecks(AliasAnalysis &AA) {
+  if (!PollyUseRuntimeAliasChecks)
+    return true;
+
+  if (buildAliasGroups(AA)) {
+    // Aliasing assumptions do not go through addAssumption but we still want to
+    // collect statistics so we do it here explicitly.
+    if (MinMaxAliasGroups.size())
+      AssumptionsAliasing++;
+    return true;
+  }
+
+  // If a problem occurs while building the alias groups we need to delete
+  // this SCoP and pretend it wasn't valid in the first place. To this end
+  // we make the assumed context infeasible.
+  invalidate(ALIASING, DebugLoc());
+
+  DEBUG(dbgs() << "\n\nNOTE: Run time checks for " << getNameStr()
+               << " could not be created as the number of parameters involved "
+                  "is too high. The SCoP will be "
+                  "dismissed.\nUse:\n\t--polly-rtc-max-parameters=X\nto adjust "
+                  "the maximal number of parameters but be advised that the "
+                  "compile time might increase exponentially.\n\n");
+  return false;
+}
+
+std::tuple<Scop::AliasGroupVectorTy, DenseSet<const ScopArrayInfo *>>
+Scop::buildAliasGroupsForAccesses(AliasAnalysis &AA) {
+  AliasSetTracker AST(AA);
+
+  DenseMap<Value *, MemoryAccess *> PtrToAcc;
+  DenseSet<const ScopArrayInfo *> HasWriteAccess;
+  for (ScopStmt &Stmt : *this) {
+
+    isl_set *StmtDomain = Stmt.getDomain().release();
+    bool StmtDomainEmpty = isl_set_is_empty(StmtDomain);
+    isl_set_free(StmtDomain);
+
+    // Statements with an empty domain will never be executed.
+    if (StmtDomainEmpty)
+      continue;
+
+    for (MemoryAccess *MA : Stmt) {
+      if (MA->isScalarKind())
+        continue;
+      if (!MA->isRead())
+        HasWriteAccess.insert(MA->getScopArrayInfo());
+      MemAccInst Acc(MA->getAccessInstruction());
+      if (MA->isRead() && isa<MemTransferInst>(Acc))
+        PtrToAcc[cast<MemTransferInst>(Acc)->getRawSource()] = MA;
+      else
+        PtrToAcc[Acc.getPointerOperand()] = MA;
+      AST.add(Acc);
+    }
+  }
+
+  AliasGroupVectorTy AliasGroups;
+  for (AliasSet &AS : AST) {
+    if (AS.isMustAlias() || AS.isForwardingAliasSet())
+      continue;
+    AliasGroupTy AG;
+    for (auto &PR : AS)
+      AG.push_back(PtrToAcc[PR.getValue()]);
+    if (AG.size() < 2)
+      continue;
+    AliasGroups.push_back(std::move(AG));
+  }
+
+  return std::make_tuple(AliasGroups, HasWriteAccess);
+}
+
+void Scop::splitAliasGroupsByDomain(AliasGroupVectorTy &AliasGroups) {
+  for (unsigned u = 0; u < AliasGroups.size(); u++) {
+    AliasGroupTy NewAG;
+    AliasGroupTy &AG = AliasGroups[u];
+    AliasGroupTy::iterator AGI = AG.begin();
+    isl_set *AGDomain = getAccessDomain(*AGI);
+    while (AGI != AG.end()) {
+      MemoryAccess *MA = *AGI;
+      isl_set *MADomain = getAccessDomain(MA);
+      if (isl_set_is_disjoint(AGDomain, MADomain)) {
+        NewAG.push_back(MA);
+        AGI = AG.erase(AGI);
+        isl_set_free(MADomain);
+      } else {
+        AGDomain = isl_set_union(AGDomain, MADomain);
+        AGI++;
+      }
+    }
+    if (NewAG.size() > 1)
+      AliasGroups.push_back(std::move(NewAG));
+    isl_set_free(AGDomain);
+  }
+}
+
+bool Scop::buildAliasGroups(AliasAnalysis &AA) {
+  // To create sound alias checks we perform the following steps:
+  //   o) We partition each group into read only and non read only accesses.
+  //   o) For each group with more than one base pointer we then compute minimal
+  //      and maximal accesses to each array of a group in read only and non
+  //      read only partitions separately.
+  AliasGroupVectorTy AliasGroups;
+  DenseSet<const ScopArrayInfo *> HasWriteAccess;
+
+  std::tie(AliasGroups, HasWriteAccess) = buildAliasGroupsForAccesses(AA);
+
+  splitAliasGroupsByDomain(AliasGroups);
+
+  for (AliasGroupTy &AG : AliasGroups) {
+    if (!hasFeasibleRuntimeContext())
+      return false;
+
+    {
+      IslMaxOperationsGuard MaxOpGuard(getIslCtx().get(), OptComputeOut);
+      bool Valid = buildAliasGroup(AG, HasWriteAccess);
+      if (!Valid)
+        return false;
+    }
+    if (isl_ctx_last_error(getIslCtx().get()) == isl_error_quota) {
+      invalidate(COMPLEXITY, DebugLoc());
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool Scop::buildAliasGroup(Scop::AliasGroupTy &AliasGroup,
+                           DenseSet<const ScopArrayInfo *> HasWriteAccess) {
+  AliasGroupTy ReadOnlyAccesses;
+  AliasGroupTy ReadWriteAccesses;
+  SmallPtrSet<const ScopArrayInfo *, 4> ReadWriteArrays;
+  SmallPtrSet<const ScopArrayInfo *, 4> ReadOnlyArrays;
+
+  if (AliasGroup.size() < 2)
+    return true;
+
+  for (MemoryAccess *Access : AliasGroup) {
+    ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "PossibleAlias",
+                                        Access->getAccessInstruction())
+             << "Possibly aliasing pointer, use restrict keyword.");
+    const ScopArrayInfo *Array = Access->getScopArrayInfo();
+    if (HasWriteAccess.count(Array)) {
+      ReadWriteArrays.insert(Array);
+      ReadWriteAccesses.push_back(Access);
+    } else {
+      ReadOnlyArrays.insert(Array);
+      ReadOnlyAccesses.push_back(Access);
+    }
+  }
+
+  // If there are no read-only pointers, and less than two read-write pointers,
+  // no alias check is needed.
+  if (ReadOnlyAccesses.empty() && ReadWriteArrays.size() <= 1)
+    return true;
+
+  // If there is no read-write pointer, no alias check is needed.
+  if (ReadWriteArrays.empty())
+    return true;
+
+  // For non-affine accesses, no alias check can be generated as we cannot
+  // compute a sufficiently tight lower and upper bound: bail out.
+  for (MemoryAccess *MA : AliasGroup) {
+    if (!MA->isAffine()) {
+      invalidate(ALIASING, MA->getAccessInstruction()->getDebugLoc(),
+                 MA->getAccessInstruction()->getParent());
+      return false;
+    }
+  }
+
+  // Ensure that for all memory accesses for which we generate alias checks,
+  // their base pointers are available.
+  for (MemoryAccess *MA : AliasGroup) {
+    if (MemoryAccess *BasePtrMA = lookupBasePtrAccess(MA))
+      addRequiredInvariantLoad(
+          cast<LoadInst>(BasePtrMA->getAccessInstruction()));
+  }
+
+  MinMaxAliasGroups.emplace_back();
+  MinMaxVectorPairTy &pair = MinMaxAliasGroups.back();
+  MinMaxVectorTy &MinMaxAccessesReadWrite = pair.first;
+  MinMaxVectorTy &MinMaxAccessesReadOnly = pair.second;
+
+  bool Valid;
+
+  Valid =
+      calculateMinMaxAccess(ReadWriteAccesses, *this, MinMaxAccessesReadWrite);
+
+  if (!Valid)
+    return false;
+
+  // Bail out if the number of values we need to compare is too large.
+  // This is important as the number of comparisons grows quadratically with
+  // the number of values we need to compare.
+  if (MinMaxAccessesReadWrite.size() + ReadOnlyArrays.size() >
+      RunTimeChecksMaxArraysPerGroup)
+    return false;
+
+  Valid =
+      calculateMinMaxAccess(ReadOnlyAccesses, *this, MinMaxAccessesReadOnly);
+
+  if (!Valid)
+    return false;
+
+  return true;
+}
+
+/// Get the smallest loop that contains @p S but is not in @p S.
+static Loop *getLoopSurroundingScop(Scop &S, LoopInfo &LI) {
+  // Start with the smallest loop containing the entry and expand that
+  // loop until it contains all blocks in the region. If there is a loop
+  // containing all blocks in the region check if it is itself contained
+  // and if so take the parent loop as it will be the smallest containing
+  // the region but not contained by it.
+  Loop *L = LI.getLoopFor(S.getEntry());
+  while (L) {
+    bool AllContained = true;
+    for (auto *BB : S.blocks())
+      AllContained &= L->contains(BB);
+    if (AllContained)
+      break;
+    L = L->getParentLoop();
+  }
+
+  return L ? (S.contains(L) ? L->getParentLoop() : L) : nullptr;
+}
+
+int Scop::NextScopID = 0;
+
+std::string Scop::CurrentFunc;
+
+int Scop::getNextID(std::string ParentFunc) {
+  if (ParentFunc != CurrentFunc) {
+    CurrentFunc = ParentFunc;
+    NextScopID = 0;
+  }
+  return NextScopID++;
+}
+
+Scop::Scop(Region &R, ScalarEvolution &ScalarEvolution, LoopInfo &LI,
+           DominatorTree &DT, ScopDetection::DetectionContext &DC,
+           OptimizationRemarkEmitter &ORE)
+    : IslCtx(isl_ctx_alloc(), isl_ctx_free), SE(&ScalarEvolution), DT(&DT),
+      R(R), name(R.getNameStr()), HasSingleExitEdge(R.getExitingBlock()),
+      DC(DC), ORE(ORE), Affinator(this, LI),
+      ID(getNextID((*R.getEntry()->getParent()).getName().str())) {
+  if (IslOnErrorAbort)
+    isl_options_set_on_error(getIslCtx().get(), ISL_ON_ERROR_ABORT);
+  buildContext();
+}
+
+Scop::~Scop() = default;
+
+void Scop::foldSizeConstantsToRight() {
+  isl_union_set *Accessed = isl_union_map_range(getAccesses().release());
+
+  for (auto Array : arrays()) {
+    if (Array->getNumberOfDimensions() <= 1)
+      continue;
+
+    isl_space *Space = Array->getSpace().release();
+
+    Space = isl_space_align_params(Space, isl_union_set_get_space(Accessed));
+
+    if (!isl_union_set_contains(Accessed, Space)) {
+      isl_space_free(Space);
+      continue;
+    }
+
+    isl_set *Elements = isl_union_set_extract_set(Accessed, Space);
+
+    isl_map *Transform =
+        isl_map_universe(isl_space_map_from_set(Array->getSpace().release()));
+
+    std::vector<int> Int;
+
+    int Dims = isl_set_dim(Elements, isl_dim_set);
+    for (int i = 0; i < Dims; i++) {
+      isl_set *DimOnly =
+          isl_set_project_out(isl_set_copy(Elements), isl_dim_set, 0, i);
+      DimOnly = isl_set_project_out(DimOnly, isl_dim_set, 1, Dims - i - 1);
+      DimOnly = isl_set_lower_bound_si(DimOnly, isl_dim_set, 0, 0);
+
+      isl_basic_set *DimHull = isl_set_affine_hull(DimOnly);
+
+      if (i == Dims - 1) {
+        Int.push_back(1);
+        Transform = isl_map_equate(Transform, isl_dim_in, i, isl_dim_out, i);
+        isl_basic_set_free(DimHull);
+        continue;
+      }
+
+      if (isl_basic_set_dim(DimHull, isl_dim_div) == 1) {
+        isl_aff *Diff = isl_basic_set_get_div(DimHull, 0);
+        isl_val *Val = isl_aff_get_denominator_val(Diff);
+        isl_aff_free(Diff);
+
+        int ValInt = 1;
+
+        if (isl_val_is_int(Val))
+          ValInt = isl_val_get_num_si(Val);
+        isl_val_free(Val);
+
+        Int.push_back(ValInt);
+
+        isl_constraint *C = isl_constraint_alloc_equality(
+            isl_local_space_from_space(isl_map_get_space(Transform)));
+        C = isl_constraint_set_coefficient_si(C, isl_dim_out, i, ValInt);
+        C = isl_constraint_set_coefficient_si(C, isl_dim_in, i, -1);
+        Transform = isl_map_add_constraint(Transform, C);
+        isl_basic_set_free(DimHull);
+        continue;
+      }
+
+      isl_basic_set *ZeroSet = isl_basic_set_copy(DimHull);
+      ZeroSet = isl_basic_set_fix_si(ZeroSet, isl_dim_set, 0, 0);
+
+      int ValInt = 1;
+      if (isl_basic_set_is_equal(ZeroSet, DimHull)) {
+        ValInt = 0;
+      }
+
+      Int.push_back(ValInt);
+      Transform = isl_map_equate(Transform, isl_dim_in, i, isl_dim_out, i);
+      isl_basic_set_free(DimHull);
+      isl_basic_set_free(ZeroSet);
+    }
+
+    isl_set *MappedElements = isl_map_domain(isl_map_copy(Transform));
+
+    if (!isl_set_is_subset(Elements, MappedElements)) {
+      isl_set_free(Elements);
+      isl_set_free(MappedElements);
+      isl_map_free(Transform);
+      continue;
+    }
+
+    isl_set_free(MappedElements);
+
+    bool CanFold = true;
+
+    if (Int[0] <= 1)
+      CanFold = false;
+
+    unsigned NumDims = Array->getNumberOfDimensions();
+    for (unsigned i = 1; i < NumDims - 1; i++)
+      if (Int[0] != Int[i] && Int[i])
+        CanFold = false;
+
+    if (!CanFold) {
+      isl_set_free(Elements);
+      isl_map_free(Transform);
+      continue;
+    }
+
+    for (auto &Access : AccessFunctions)
+      if (Access->getScopArrayInfo() == Array)
+        Access->setAccessRelation(Access->getAccessRelation().apply_range(
+            isl::manage(isl_map_copy(Transform))));
+
+    isl_map_free(Transform);
+
+    std::vector<const SCEV *> Sizes;
+    for (unsigned i = 0; i < NumDims; i++) {
+      auto Size = Array->getDimensionSize(i);
+
+      if (i == NumDims - 1)
+        Size = SE->getMulExpr(Size, SE->getConstant(Size->getType(), Int[0]));
+      Sizes.push_back(Size);
+    }
+
+    Array->updateSizes(Sizes, false /* CheckConsistency */);
+
+    isl_set_free(Elements);
+  }
+  isl_union_set_free(Accessed);
+}
+
+void Scop::markFortranArrays() {
+  for (ScopStmt &Stmt : Stmts) {
+    for (MemoryAccess *MemAcc : Stmt) {
+      Value *FAD = MemAcc->getFortranArrayDescriptor();
+      if (!FAD)
+        continue;
+
+      // TODO: const_cast-ing to edit
+      ScopArrayInfo *SAI =
+          const_cast<ScopArrayInfo *>(MemAcc->getLatestScopArrayInfo());
+      assert(SAI && "memory access into a Fortran array does not "
+                    "have an associated ScopArrayInfo");
+      SAI->applyAndSetFAD(FAD);
+    }
+  }
+}
+
+void Scop::finalizeAccesses() {
+  updateAccessDimensionality();
+  foldSizeConstantsToRight();
+  foldAccessRelations();
+  assumeNoOutOfBounds();
+  markFortranArrays();
+}
+
+void Scop::updateAccessDimensionality() {
+  // Check all array accesses for each base pointer and find a (virtual) element
+  // size for the base pointer that divides all access functions.
+  for (ScopStmt &Stmt : *this)
+    for (MemoryAccess *Access : Stmt) {
+      if (!Access->isArrayKind())
+        continue;
+      ScopArrayInfo *Array =
+          const_cast<ScopArrayInfo *>(Access->getScopArrayInfo());
+
+      if (Array->getNumberOfDimensions() != 1)
+        continue;
+      unsigned DivisibleSize = Array->getElemSizeInBytes();
+      const SCEV *Subscript = Access->getSubscript(0);
+      while (!isDivisible(Subscript, DivisibleSize, *SE))
+        DivisibleSize /= 2;
+      auto *Ty = IntegerType::get(SE->getContext(), DivisibleSize * 8);
+      Array->updateElementType(Ty);
+    }
+
+  for (auto &Stmt : *this)
+    for (auto &Access : Stmt)
+      Access->updateDimensionality();
+}
+
+void Scop::foldAccessRelations() {
+  for (auto &Stmt : *this)
+    for (auto &Access : Stmt)
+      Access->foldAccessRelation();
+}
+
+void Scop::assumeNoOutOfBounds() {
+  for (auto &Stmt : *this)
+    for (auto &Access : Stmt)
+      Access->assumeNoOutOfBound();
+}
+
+void Scop::removeFromStmtMap(ScopStmt &Stmt) {
+  for (Instruction *Inst : Stmt.getInstructions())
+    InstStmtMap.erase(Inst);
+
+  if (Stmt.isRegionStmt()) {
+    for (BasicBlock *BB : Stmt.getRegion()->blocks()) {
+      StmtMap.erase(BB);
+      // Skip entry basic block, as its instructions are already deleted as
+      // part of the statement's instruction list.
+      if (BB == Stmt.getEntryBlock())
+        continue;
+      for (Instruction &Inst : *BB)
+        InstStmtMap.erase(&Inst);
+    }
+  } else {
+    auto StmtMapIt = StmtMap.find(Stmt.getBasicBlock());
+    if (StmtMapIt != StmtMap.end())
+      StmtMapIt->second.erase(std::remove(StmtMapIt->second.begin(),
+                                          StmtMapIt->second.end(), &Stmt),
+                              StmtMapIt->second.end());
+    for (Instruction *Inst : Stmt.getInstructions())
+      InstStmtMap.erase(Inst);
+  }
+}
+
+void Scop::removeStmts(std::function<bool(ScopStmt &)> ShouldDelete) {
+  for (auto StmtIt = Stmts.begin(), StmtEnd = Stmts.end(); StmtIt != StmtEnd;) {
+    if (!ShouldDelete(*StmtIt)) {
+      StmtIt++;
+      continue;
+    }
+
+    removeFromStmtMap(*StmtIt);
+    StmtIt = Stmts.erase(StmtIt);
+  }
+}
+
+void Scop::removeStmtNotInDomainMap() {
+  auto ShouldDelete = [this](ScopStmt &Stmt) -> bool {
+    return !this->DomainMap.lookup(Stmt.getEntryBlock());
+  };
+  removeStmts(ShouldDelete);
+}
+
+void Scop::simplifySCoP(bool AfterHoisting) {
+  auto ShouldDelete = [AfterHoisting](ScopStmt &Stmt) -> bool {
+    bool RemoveStmt = Stmt.isEmpty();
+
+    // Remove read only statements only after invariant load hoisting.
+    if (!RemoveStmt && AfterHoisting) {
+      bool OnlyRead = true;
+      for (MemoryAccess *MA : Stmt) {
+        if (MA->isRead())
+          continue;
+
+        OnlyRead = false;
+        break;
+      }
+
+      RemoveStmt = OnlyRead;
+    }
+    return RemoveStmt;
+  };
+
+  removeStmts(ShouldDelete);
+}
+
+InvariantEquivClassTy *Scop::lookupInvariantEquivClass(Value *Val) {
+  LoadInst *LInst = dyn_cast<LoadInst>(Val);
+  if (!LInst)
+    return nullptr;
+
+  if (Value *Rep = InvEquivClassVMap.lookup(LInst))
+    LInst = cast<LoadInst>(Rep);
+
+  Type *Ty = LInst->getType();
+  const SCEV *PointerSCEV = SE->getSCEV(LInst->getPointerOperand());
+  for (auto &IAClass : InvariantEquivClasses) {
+    if (PointerSCEV != IAClass.IdentifyingPointer || Ty != IAClass.AccessType)
+      continue;
+
+    auto &MAs = IAClass.InvariantAccesses;
+    for (auto *MA : MAs)
+      if (MA->getAccessInstruction() == Val)
+        return &IAClass;
+  }
+
+  return nullptr;
+}
+
+bool isAParameter(llvm::Value *maybeParam, const Function &F) {
+  for (const llvm::Argument &Arg : F.args())
+    if (&Arg == maybeParam)
+      return true;
+
+  return false;
+}
+
+bool Scop::canAlwaysBeHoisted(MemoryAccess *MA, bool StmtInvalidCtxIsEmpty,
+                              bool MAInvalidCtxIsEmpty,
+                              bool NonHoistableCtxIsEmpty) {
+  LoadInst *LInst = cast<LoadInst>(MA->getAccessInstruction());
+  const DataLayout &DL = LInst->getParent()->getModule()->getDataLayout();
+  if (PollyAllowDereferenceOfAllFunctionParams &&
+      isAParameter(LInst->getPointerOperand(), getFunction()))
+    return true;
+
+  // TODO: We can provide more information for better but more expensive
+  //       results.
+  if (!isDereferenceableAndAlignedPointer(LInst->getPointerOperand(),
+                                          LInst->getAlignment(), DL))
+    return false;
+
+  // If the location might be overwritten we do not hoist it unconditionally.
+  //
+  // TODO: This is probably too conservative.
+  if (!NonHoistableCtxIsEmpty)
+    return false;
+
+  // If a dereferenceable load is in a statement that is modeled precisely we
+  // can hoist it.
+  if (StmtInvalidCtxIsEmpty && MAInvalidCtxIsEmpty)
+    return true;
+
+  // Even if the statement is not modeled precisely we can hoist the load if it
+  // does not involve any parameters that might have been specialized by the
+  // statement domain.
+  for (unsigned u = 0, e = MA->getNumSubscripts(); u < e; u++)
+    if (!isa<SCEVConstant>(MA->getSubscript(u)))
+      return false;
+  return true;
+}
+
+void Scop::addInvariantLoads(ScopStmt &Stmt, InvariantAccessesTy &InvMAs) {
+  if (InvMAs.empty())
+    return;
+
+  isl::set StmtInvalidCtx = Stmt.getInvalidContext();
+  bool StmtInvalidCtxIsEmpty = StmtInvalidCtx.is_empty();
+
+  // Get the context under which the statement is executed but remove the error
+  // context under which this statement is reached.
+  isl::set DomainCtx = Stmt.getDomain().params();
+  DomainCtx = DomainCtx.subtract(StmtInvalidCtx);
+
+  if (isl_set_n_basic_set(DomainCtx.get()) >= MaxDisjunctsInDomain) {
+    auto *AccInst = InvMAs.front().MA->getAccessInstruction();
+    invalidate(COMPLEXITY, AccInst->getDebugLoc(), AccInst->getParent());
+    return;
+  }
+
+  // Project out all parameters that relate to loads in the statement. Otherwise
+  // we could have cyclic dependences on the constraints under which the
+  // hoisted loads are executed and we could not determine an order in which to
+  // pre-load them. This happens because not only lower bounds are part of the
+  // domain but also upper bounds.
+  for (auto &InvMA : InvMAs) {
+    auto *MA = InvMA.MA;
+    Instruction *AccInst = MA->getAccessInstruction();
+    if (SE->isSCEVable(AccInst->getType())) {
+      SetVector<Value *> Values;
+      for (const SCEV *Parameter : Parameters) {
+        Values.clear();
+        findValues(Parameter, *SE, Values);
+        if (!Values.count(AccInst))
+          continue;
+
+        if (isl::id ParamId = getIdForParam(Parameter)) {
+          int Dim = DomainCtx.find_dim_by_id(isl::dim::param, ParamId);
+          if (Dim >= 0)
+            DomainCtx = DomainCtx.eliminate(isl::dim::param, Dim, 1);
+        }
+      }
+    }
+  }
+
+  for (auto &InvMA : InvMAs) {
+    auto *MA = InvMA.MA;
+    isl::set NHCtx = InvMA.NonHoistableCtx;
+
+    // Check for another invariant access that accesses the same location as
+    // MA and if found consolidate them. Otherwise create a new equivalence
+    // class at the end of InvariantEquivClasses.
+    LoadInst *LInst = cast<LoadInst>(MA->getAccessInstruction());
+    Type *Ty = LInst->getType();
+    const SCEV *PointerSCEV = SE->getSCEV(LInst->getPointerOperand());
+
+    isl::set MAInvalidCtx = MA->getInvalidContext();
+    bool NonHoistableCtxIsEmpty = NHCtx.is_empty();
+    bool MAInvalidCtxIsEmpty = MAInvalidCtx.is_empty();
+
+    isl::set MACtx;
+    // Check if we know that this pointer can be speculatively accessed.
+    if (canAlwaysBeHoisted(MA, StmtInvalidCtxIsEmpty, MAInvalidCtxIsEmpty,
+                           NonHoistableCtxIsEmpty)) {
+      MACtx = isl::set::universe(DomainCtx.get_space());
+    } else {
+      MACtx = DomainCtx;
+      MACtx = MACtx.subtract(MAInvalidCtx.unite(NHCtx));
+      MACtx = MACtx.gist_params(getContext());
+    }
+
+    bool Consolidated = false;
+    for (auto &IAClass : InvariantEquivClasses) {
+      if (PointerSCEV != IAClass.IdentifyingPointer || Ty != IAClass.AccessType)
+        continue;
+
+      // If the pointer and the type is equal check if the access function wrt.
+      // to the domain is equal too. It can happen that the domain fixes
+      // parameter values and these can be different for distinct part of the
+      // SCoP. If this happens we cannot consolidate the loads but need to
+      // create a new invariant load equivalence class.
+      auto &MAs = IAClass.InvariantAccesses;
+      if (!MAs.empty()) {
+        auto *LastMA = MAs.front();
+
+        isl::set AR = MA->getAccessRelation().range();
+        isl::set LastAR = LastMA->getAccessRelation().range();
+        bool SameAR = AR.is_equal(LastAR);
+
+        if (!SameAR)
+          continue;
+      }
+
+      // Add MA to the list of accesses that are in this class.
+      MAs.push_front(MA);
+
+      Consolidated = true;
+
+      // Unify the execution context of the class and this statement.
+      isl::set IAClassDomainCtx = IAClass.ExecutionContext;
+      if (IAClassDomainCtx)
+        IAClassDomainCtx = IAClassDomainCtx.unite(MACtx).coalesce();
+      else
+        IAClassDomainCtx = MACtx;
+      IAClass.ExecutionContext = IAClassDomainCtx;
+      break;
+    }
+
+    if (Consolidated)
+      continue;
+
+    // If we did not consolidate MA, thus did not find an equivalence class
+    // for it, we create a new one.
+    InvariantEquivClasses.emplace_back(
+        InvariantEquivClassTy{PointerSCEV, MemoryAccessList{MA}, MACtx, Ty});
+  }
+}
+
+/// Check if an access range is too complex.
+///
+/// An access range is too complex, if it contains either many disjuncts or
+/// very complex expressions. As a simple heuristic, we assume if a set to
+/// be too complex if the sum of existentially quantified dimensions and
+/// set dimensions is larger than a threshold. This reliably detects both
+/// sets with many disjuncts as well as sets with many divisions as they
+/// arise in h264.
+///
+/// @param AccessRange The range to check for complexity.
+///
+/// @returns True if the access range is too complex.
+static bool isAccessRangeTooComplex(isl::set AccessRange) {
+  unsigned NumTotalDims = 0;
+
+  auto CountDimensions = [&NumTotalDims](isl::basic_set BSet) -> isl::stat {
+    NumTotalDims += BSet.dim(isl::dim::div);
+    NumTotalDims += BSet.dim(isl::dim::set);
+    return isl::stat::ok;
+  };
+
+  AccessRange.foreach_basic_set(CountDimensions);
+
+  if (NumTotalDims > MaxDimensionsInAccessRange)
+    return true;
+
+  return false;
+}
+
+isl::set Scop::getNonHoistableCtx(MemoryAccess *Access, isl::union_map Writes) {
+  // TODO: Loads that are not loop carried, hence are in a statement with
+  //       zero iterators, are by construction invariant, though we
+  //       currently "hoist" them anyway. This is necessary because we allow
+  //       them to be treated as parameters (e.g., in conditions) and our code
+  //       generation would otherwise use the old value.
+
+  auto &Stmt = *Access->getStatement();
+  BasicBlock *BB = Stmt.getEntryBlock();
+
+  if (Access->isScalarKind() || Access->isWrite() || !Access->isAffine() ||
+      Access->isMemoryIntrinsic())
+    return nullptr;
+
+  // Skip accesses that have an invariant base pointer which is defined but
+  // not loaded inside the SCoP. This can happened e.g., if a readnone call
+  // returns a pointer that is used as a base address. However, as we want
+  // to hoist indirect pointers, we allow the base pointer to be defined in
+  // the region if it is also a memory access. Each ScopArrayInfo object
+  // that has a base pointer origin has a base pointer that is loaded and
+  // that it is invariant, thus it will be hoisted too. However, if there is
+  // no base pointer origin we check that the base pointer is defined
+  // outside the region.
+  auto *LI = cast<LoadInst>(Access->getAccessInstruction());
+  if (hasNonHoistableBasePtrInScop(Access, Writes))
+    return nullptr;
+
+  isl::map AccessRelation = give(Access->getAccessRelation().release());
+  assert(!AccessRelation.is_empty());
+
+  if (AccessRelation.involves_dims(isl::dim::in, 0, Stmt.getNumIterators()))
+    return nullptr;
+
+  AccessRelation = AccessRelation.intersect_domain(Stmt.getDomain());
+  isl::set SafeToLoad;
+
+  auto &DL = getFunction().getParent()->getDataLayout();
+  if (isSafeToLoadUnconditionally(LI->getPointerOperand(), LI->getAlignment(),
+                                  DL)) {
+    SafeToLoad = isl::set::universe(AccessRelation.get_space().range());
+  } else if (BB != LI->getParent()) {
+    // Skip accesses in non-affine subregions as they might not be executed
+    // under the same condition as the entry of the non-affine subregion.
+    return nullptr;
+  } else {
+    SafeToLoad = AccessRelation.range();
+  }
+
+  if (isAccessRangeTooComplex(AccessRelation.range()))
+    return nullptr;
+
+  isl::union_map Written = Writes.intersect_range(SafeToLoad);
+  isl::set WrittenCtx = Written.params();
+  bool IsWritten = !WrittenCtx.is_empty();
+
+  if (!IsWritten)
+    return WrittenCtx;
+
+  WrittenCtx = WrittenCtx.remove_divs();
+  bool TooComplex =
+      isl_set_n_basic_set(WrittenCtx.get()) >= MaxDisjunctsInDomain;
+  if (TooComplex || !isRequiredInvariantLoad(LI))
+    return nullptr;
+
+  addAssumption(INVARIANTLOAD, WrittenCtx, LI->getDebugLoc(), AS_RESTRICTION,
+                LI->getParent());
+  return WrittenCtx;
+}
+
+void Scop::verifyInvariantLoads() {
+  auto &RIL = getRequiredInvariantLoads();
+  for (LoadInst *LI : RIL) {
+    assert(LI && contains(LI));
+    // If there exists a statement in the scop which has a memory access for
+    // @p LI, then mark this scop as infeasible for optimization.
+    for (ScopStmt &Stmt : Stmts)
+      if (Stmt.getArrayAccessOrNULLFor(LI)) {
+        invalidate(INVARIANTLOAD, LI->getDebugLoc(), LI->getParent());
+        return;
+      }
+  }
+}
+
+void Scop::hoistInvariantLoads() {
+  if (!PollyInvariantLoadHoisting)
+    return;
+
+  isl::union_map Writes = getWrites();
+  for (ScopStmt &Stmt : *this) {
+    InvariantAccessesTy InvariantAccesses;
+
+    for (MemoryAccess *Access : Stmt)
+      if (isl::set NHCtx = getNonHoistableCtx(Access, Writes))
+        InvariantAccesses.push_back({Access, NHCtx});
+
+    // Transfer the memory access from the statement to the SCoP.
+    for (auto InvMA : InvariantAccesses)
+      Stmt.removeMemoryAccess(InvMA.MA);
+    addInvariantLoads(Stmt, InvariantAccesses);
+  }
+}
+
+/// Find the canonical scop array info object for a set of invariant load
+/// hoisted loads. The canonical array is the one that corresponds to the
+/// first load in the list of accesses which is used as base pointer of a
+/// scop array.
+static const ScopArrayInfo *findCanonicalArray(Scop *S,
+                                               MemoryAccessList &Accesses) {
+  for (MemoryAccess *Access : Accesses) {
+    const ScopArrayInfo *CanonicalArray = S->getScopArrayInfoOrNull(
+        Access->getAccessInstruction(), MemoryKind::Array);
+    if (CanonicalArray)
+      return CanonicalArray;
+  }
+  return nullptr;
+}
+
+/// Check if @p Array severs as base array in an invariant load.
+static bool isUsedForIndirectHoistedLoad(Scop *S, const ScopArrayInfo *Array) {
+  for (InvariantEquivClassTy &EqClass2 : S->getInvariantAccesses())
+    for (MemoryAccess *Access2 : EqClass2.InvariantAccesses)
+      if (Access2->getScopArrayInfo() == Array)
+        return true;
+  return false;
+}
+
+/// Replace the base pointer arrays in all memory accesses referencing @p Old,
+/// with a reference to @p New.
+static void replaceBasePtrArrays(Scop *S, const ScopArrayInfo *Old,
+                                 const ScopArrayInfo *New) {
+  for (ScopStmt &Stmt : *S)
+    for (MemoryAccess *Access : Stmt) {
+      if (Access->getLatestScopArrayInfo() != Old)
+        continue;
+
+      isl::id Id = New->getBasePtrId();
+      isl::map Map = Access->getAccessRelation();
+      Map = Map.set_tuple_id(isl::dim::out, Id);
+      Access->setAccessRelation(Map);
+    }
+}
+
+void Scop::canonicalizeDynamicBasePtrs() {
+  for (InvariantEquivClassTy &EqClass : InvariantEquivClasses) {
+    MemoryAccessList &BasePtrAccesses = EqClass.InvariantAccesses;
+
+    const ScopArrayInfo *CanonicalBasePtrSAI =
+        findCanonicalArray(this, BasePtrAccesses);
+
+    if (!CanonicalBasePtrSAI)
+      continue;
+
+    for (MemoryAccess *BasePtrAccess : BasePtrAccesses) {
+      const ScopArrayInfo *BasePtrSAI = getScopArrayInfoOrNull(
+          BasePtrAccess->getAccessInstruction(), MemoryKind::Array);
+      if (!BasePtrSAI || BasePtrSAI == CanonicalBasePtrSAI ||
+          !BasePtrSAI->isCompatibleWith(CanonicalBasePtrSAI))
+        continue;
+
+      // we currently do not canonicalize arrays where some accesses are
+      // hoisted as invariant loads. If we would, we need to update the access
+      // function of the invariant loads as well. However, as this is not a
+      // very common situation, we leave this for now to avoid further
+      // complexity increases.
+      if (isUsedForIndirectHoistedLoad(this, BasePtrSAI))
+        continue;
+
+      replaceBasePtrArrays(this, BasePtrSAI, CanonicalBasePtrSAI);
+    }
+  }
+}
+
+ScopArrayInfo *Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *ElementType,
+                                              ArrayRef<const SCEV *> Sizes,
+                                              MemoryKind Kind,
+                                              const char *BaseName) {
+  assert((BasePtr || BaseName) &&
+         "BasePtr and BaseName can not be nullptr at the same time.");
+  assert(!(BasePtr && BaseName) && "BaseName is redundant.");
+  auto &SAI = BasePtr ? ScopArrayInfoMap[std::make_pair(BasePtr, Kind)]
+                      : ScopArrayNameMap[BaseName];
+  if (!SAI) {
+    auto &DL = getFunction().getParent()->getDataLayout();
+    SAI.reset(new ScopArrayInfo(BasePtr, ElementType, getIslCtx(), Sizes, Kind,
+                                DL, this, BaseName));
+    ScopArrayInfoSet.insert(SAI.get());
+  } else {
+    SAI->updateElementType(ElementType);
+    // In case of mismatching array sizes, we bail out by setting the run-time
+    // context to false.
+    if (!SAI->updateSizes(Sizes))
+      invalidate(DELINEARIZATION, DebugLoc());
+  }
+  return SAI.get();
+}
+
+ScopArrayInfo *Scop::createScopArrayInfo(Type *ElementType,
+                                         const std::string &BaseName,
+                                         const std::vector<unsigned> &Sizes) {
+  auto *DimSizeType = Type::getInt64Ty(getSE()->getContext());
+  std::vector<const SCEV *> SCEVSizes;
+
+  for (auto size : Sizes)
+    if (size)
+      SCEVSizes.push_back(getSE()->getConstant(DimSizeType, size, false));
+    else
+      SCEVSizes.push_back(nullptr);
+
+  auto *SAI = getOrCreateScopArrayInfo(nullptr, ElementType, SCEVSizes,
+                                       MemoryKind::Array, BaseName.c_str());
+  return SAI;
+}
+
+const ScopArrayInfo *Scop::getScopArrayInfoOrNull(Value *BasePtr,
+                                                  MemoryKind Kind) {
+  auto *SAI = ScopArrayInfoMap[std::make_pair(BasePtr, Kind)].get();
+  return SAI;
+}
+
+const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, MemoryKind Kind) {
+  auto *SAI = getScopArrayInfoOrNull(BasePtr, Kind);
+  assert(SAI && "No ScopArrayInfo available for this base pointer");
+  return SAI;
+}
+
+std::string Scop::getContextStr() const { return getContext().to_str(); }
+
+std::string Scop::getAssumedContextStr() const {
+  assert(AssumedContext && "Assumed context not yet built");
+  return AssumedContext.to_str();
+}
+
+std::string Scop::getInvalidContextStr() const {
+  return InvalidContext.to_str();
+}
+
+std::string Scop::getNameStr() const {
+  std::string ExitName, EntryName;
+  std::tie(EntryName, ExitName) = getEntryExitStr();
+  return EntryName + "---" + ExitName;
+}
+
+std::pair<std::string, std::string> Scop::getEntryExitStr() const {
+  std::string ExitName, EntryName;
+  raw_string_ostream ExitStr(ExitName);
+  raw_string_ostream EntryStr(EntryName);
+
+  R.getEntry()->printAsOperand(EntryStr, false);
+  EntryStr.str();
+
+  if (R.getExit()) {
+    R.getExit()->printAsOperand(ExitStr, false);
+    ExitStr.str();
+  } else
+    ExitName = "FunctionExit";
+
+  return std::make_pair(EntryName, ExitName);
+}
+
+isl::set Scop::getContext() const { return Context; }
+isl::space Scop::getParamSpace() const { return getContext().get_space(); }
+
+isl::space Scop::getFullParamSpace() const {
+  std::vector<isl::id> FortranIDs;
+  FortranIDs = getFortranArrayIds(arrays());
+
+  isl::space Space = isl::space::params_alloc(
+      getIslCtx(), ParameterIds.size() + FortranIDs.size());
+
+  unsigned PDim = 0;
+  for (const SCEV *Parameter : Parameters) {
+    isl::id Id = getIdForParam(Parameter);
+    Space = Space.set_dim_id(isl::dim::param, PDim++, Id);
+  }
+
+  for (isl::id Id : FortranIDs)
+    Space = Space.set_dim_id(isl::dim::param, PDim++, Id);
+
+  return Space;
+}
+
+isl::set Scop::getAssumedContext() const {
+  assert(AssumedContext && "Assumed context not yet built");
+  return AssumedContext;
+}
+
+bool Scop::isProfitable(bool ScalarsAreUnprofitable) const {
+  if (PollyProcessUnprofitable)
+    return true;
+
+  if (isEmpty())
+    return false;
+
+  unsigned OptimizableStmtsOrLoops = 0;
+  for (auto &Stmt : *this) {
+    if (Stmt.getNumIterators() == 0)
+      continue;
+
+    bool ContainsArrayAccs = false;
+    bool ContainsScalarAccs = false;
+    for (auto *MA : Stmt) {
+      if (MA->isRead())
+        continue;
+      ContainsArrayAccs |= MA->isLatestArrayKind();
+      ContainsScalarAccs |= MA->isLatestScalarKind();
+    }
+
+    if (!ScalarsAreUnprofitable || (ContainsArrayAccs && !ContainsScalarAccs))
+      OptimizableStmtsOrLoops += Stmt.getNumIterators();
+  }
+
+  return OptimizableStmtsOrLoops > 1;
+}
+
+bool Scop::hasFeasibleRuntimeContext() const {
+  auto PositiveContext = getAssumedContext();
+  auto NegativeContext = getInvalidContext();
+  PositiveContext = addNonEmptyDomainConstraints(PositiveContext);
+  // addNonEmptyDomainConstraints returns null if ScopStmts have a null domain
+  if (!PositiveContext)
+    return false;
+
+  bool IsFeasible = !(PositiveContext.is_empty() ||
+                      PositiveContext.is_subset(NegativeContext));
+  if (!IsFeasible)
+    return false;
+
+  auto DomainContext = getDomains().params();
+  IsFeasible = !DomainContext.is_subset(NegativeContext);
+  IsFeasible &= !Context.is_subset(NegativeContext);
+
+  return IsFeasible;
+}
+
+static std::string toString(AssumptionKind Kind) {
+  switch (Kind) {
+  case ALIASING:
+    return "No-aliasing";
+  case INBOUNDS:
+    return "Inbounds";
+  case WRAPPING:
+    return "No-overflows";
+  case UNSIGNED:
+    return "Signed-unsigned";
+  case COMPLEXITY:
+    return "Low complexity";
+  case PROFITABLE:
+    return "Profitable";
+  case ERRORBLOCK:
+    return "No-error";
+  case INFINITELOOP:
+    return "Finite loop";
+  case INVARIANTLOAD:
+    return "Invariant load";
+  case DELINEARIZATION:
+    return "Delinearization";
+  }
+  llvm_unreachable("Unknown AssumptionKind!");
+}
+
+bool Scop::isEffectiveAssumption(isl::set Set, AssumptionSign Sign) {
+  if (Sign == AS_ASSUMPTION) {
+    if (Context.is_subset(Set))
+      return false;
+
+    if (AssumedContext.is_subset(Set))
+      return false;
+  } else {
+    if (Set.is_disjoint(Context))
+      return false;
+
+    if (Set.is_subset(InvalidContext))
+      return false;
+  }
+  return true;
+}
+
+bool Scop::trackAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
+                           AssumptionSign Sign, BasicBlock *BB) {
+  if (PollyRemarksMinimal && !isEffectiveAssumption(Set, Sign))
+    return false;
+
+  // Do never emit trivial assumptions as they only clutter the output.
+  if (!PollyRemarksMinimal) {
+    isl::set Univ;
+    if (Sign == AS_ASSUMPTION)
+      Univ = isl::set::universe(Set.get_space());
+
+    bool IsTrivial = (Sign == AS_RESTRICTION && Set.is_empty()) ||
+                     (Sign == AS_ASSUMPTION && Univ.is_equal(Set));
+
+    if (IsTrivial)
+      return false;
+  }
+
+  switch (Kind) {
+  case ALIASING:
+    AssumptionsAliasing++;
+    break;
+  case INBOUNDS:
+    AssumptionsInbounds++;
+    break;
+  case WRAPPING:
+    AssumptionsWrapping++;
+    break;
+  case UNSIGNED:
+    AssumptionsUnsigned++;
+    break;
+  case COMPLEXITY:
+    AssumptionsComplexity++;
+    break;
+  case PROFITABLE:
+    AssumptionsUnprofitable++;
+    break;
+  case ERRORBLOCK:
+    AssumptionsErrorBlock++;
+    break;
+  case INFINITELOOP:
+    AssumptionsInfiniteLoop++;
+    break;
+  case INVARIANTLOAD:
+    AssumptionsInvariantLoad++;
+    break;
+  case DELINEARIZATION:
+    AssumptionsDelinearization++;
+    break;
+  }
+
+  auto Suffix = Sign == AS_ASSUMPTION ? " assumption:\t" : " restriction:\t";
+  std::string Msg = toString(Kind) + Suffix + Set.to_str();
+  if (BB)
+    ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AssumpRestrict", Loc, BB)
+             << Msg);
+  else
+    ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AssumpRestrict", Loc,
+                                        R.getEntry())
+             << Msg);
+  return true;
+}
+
+void Scop::addAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
+                         AssumptionSign Sign, BasicBlock *BB) {
+  // Simplify the assumptions/restrictions first.
+  Set = Set.gist_params(getContext());
+
+  if (!trackAssumption(Kind, Set, Loc, Sign, BB))
+    return;
+
+  if (Sign == AS_ASSUMPTION)
+    AssumedContext = AssumedContext.intersect(Set).coalesce();
+  else
+    InvalidContext = InvalidContext.unite(Set).coalesce();
+}
+
+void Scop::recordAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
+                            AssumptionSign Sign, BasicBlock *BB) {
+  assert((Set.is_params() || BB) &&
+         "Assumptions without a basic block must be parameter sets");
+  RecordedAssumptions.push_back({Kind, Sign, Set, Loc, BB});
+}
+
+void Scop::addRecordedAssumptions() {
+  while (!RecordedAssumptions.empty()) {
+    Assumption AS = RecordedAssumptions.pop_back_val();
+
+    if (!AS.BB) {
+      addAssumption(AS.Kind, AS.Set, AS.Loc, AS.Sign, nullptr /* BasicBlock */);
+      continue;
+    }
+
+    // If the domain was deleted the assumptions are void.
+    isl_set *Dom = getDomainConditions(AS.BB).release();
+    if (!Dom)
+      continue;
+
+    // If a basic block was given use its domain to simplify the assumption.
+    // In case of restrictions we know they only have to hold on the domain,
+    // thus we can intersect them with the domain of the block. However, for
+    // assumptions the domain has to imply them, thus:
+    //                     _              _____
+    //   Dom => S   <==>   A v B   <==>   A - B
+    //
+    // To avoid the complement we will register A - B as a restriction not an
+    // assumption.
+    isl_set *S = AS.Set.copy();
+    if (AS.Sign == AS_RESTRICTION)
+      S = isl_set_params(isl_set_intersect(S, Dom));
+    else /* (AS.Sign == AS_ASSUMPTION) */
+      S = isl_set_params(isl_set_subtract(Dom, S));
+
+    addAssumption(AS.Kind, isl::manage(S), AS.Loc, AS_RESTRICTION, AS.BB);
+  }
+}
+
+void Scop::invalidate(AssumptionKind Kind, DebugLoc Loc, BasicBlock *BB) {
+  DEBUG(dbgs() << "Invalidate SCoP because of reason " << Kind << "\n");
+  addAssumption(Kind, isl::set::empty(getParamSpace()), Loc, AS_ASSUMPTION, BB);
+}
+
+isl::set Scop::getInvalidContext() const { return InvalidContext; }
+
+void Scop::printContext(raw_ostream &OS) const {
+  OS << "Context:\n";
+  OS.indent(4) << Context << "\n";
+
+  OS.indent(4) << "Assumed Context:\n";
+  OS.indent(4) << AssumedContext << "\n";
+
+  OS.indent(4) << "Invalid Context:\n";
+  OS.indent(4) << InvalidContext << "\n";
+
+  unsigned Dim = 0;
+  for (const SCEV *Parameter : Parameters)
+    OS.indent(4) << "p" << Dim++ << ": " << *Parameter << "\n";
+}
+
+void Scop::printAliasAssumptions(raw_ostream &OS) const {
+  int noOfGroups = 0;
+  for (const MinMaxVectorPairTy &Pair : MinMaxAliasGroups) {
+    if (Pair.second.size() == 0)
+      noOfGroups += 1;
+    else
+      noOfGroups += Pair.second.size();
+  }
+
+  OS.indent(4) << "Alias Groups (" << noOfGroups << "):\n";
+  if (MinMaxAliasGroups.empty()) {
+    OS.indent(8) << "n/a\n";
+    return;
+  }
+
+  for (const MinMaxVectorPairTy &Pair : MinMaxAliasGroups) {
+
+    // If the group has no read only accesses print the write accesses.
+    if (Pair.second.empty()) {
+      OS.indent(8) << "[[";
+      for (const MinMaxAccessTy &MMANonReadOnly : Pair.first) {
+        OS << " <" << MMANonReadOnly.first << ", " << MMANonReadOnly.second
+           << ">";
+      }
+      OS << " ]]\n";
+    }
+
+    for (const MinMaxAccessTy &MMAReadOnly : Pair.second) {
+      OS.indent(8) << "[[";
+      OS << " <" << MMAReadOnly.first << ", " << MMAReadOnly.second << ">";
+      for (const MinMaxAccessTy &MMANonReadOnly : Pair.first) {
+        OS << " <" << MMANonReadOnly.first << ", " << MMANonReadOnly.second
+           << ">";
+      }
+      OS << " ]]\n";
+    }
+  }
+}
+
+void Scop::printStatements(raw_ostream &OS, bool PrintInstructions) const {
+  OS << "Statements {\n";
+
+  for (const ScopStmt &Stmt : *this) {
+    OS.indent(4);
+    Stmt.print(OS, PrintInstructions);
+  }
+
+  OS.indent(4) << "}\n";
+}
+
+void Scop::printArrayInfo(raw_ostream &OS) const {
+  OS << "Arrays {\n";
+
+  for (auto &Array : arrays())
+    Array->print(OS);
+
+  OS.indent(4) << "}\n";
+
+  OS.indent(4) << "Arrays (Bounds as pw_affs) {\n";
+
+  for (auto &Array : arrays())
+    Array->print(OS, /* SizeAsPwAff */ true);
+
+  OS.indent(4) << "}\n";
+}
+
+void Scop::print(raw_ostream &OS, bool PrintInstructions) const {
+  OS.indent(4) << "Function: " << getFunction().getName() << "\n";
+  OS.indent(4) << "Region: " << getNameStr() << "\n";
+  OS.indent(4) << "Max Loop Depth:  " << getMaxLoopDepth() << "\n";
+  OS.indent(4) << "Invariant Accesses: {\n";
+  for (const auto &IAClass : InvariantEquivClasses) {
+    const auto &MAs = IAClass.InvariantAccesses;
+    if (MAs.empty()) {
+      OS.indent(12) << "Class Pointer: " << *IAClass.IdentifyingPointer << "\n";
+    } else {
+      MAs.front()->print(OS);
+      OS.indent(12) << "Execution Context: " << IAClass.ExecutionContext
+                    << "\n";
+    }
+  }
+  OS.indent(4) << "}\n";
+  printContext(OS.indent(4));
+  printArrayInfo(OS.indent(4));
+  printAliasAssumptions(OS);
+  printStatements(OS.indent(4), PrintInstructions);
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void Scop::dump() const { print(dbgs(), true); }
+#endif
+
+isl::ctx Scop::getIslCtx() const { return IslCtx.get(); }
+
+__isl_give PWACtx Scop::getPwAff(const SCEV *E, BasicBlock *BB,
+                                 bool NonNegative) {
+  // First try to use the SCEVAffinator to generate a piecewise defined
+  // affine function from @p E in the context of @p BB. If that tasks becomes to
+  // complex the affinator might return a nullptr. In such a case we invalidate
+  // the SCoP and return a dummy value. This way we do not need to add error
+  // handling code to all users of this function.
+  auto PWAC = Affinator.getPwAff(E, BB);
+  if (PWAC.first) {
+    // TODO: We could use a heuristic and either use:
+    //         SCEVAffinator::takeNonNegativeAssumption
+    //       or
+    //         SCEVAffinator::interpretAsUnsigned
+    //       to deal with unsigned or "NonNegative" SCEVs.
+    if (NonNegative)
+      Affinator.takeNonNegativeAssumption(PWAC);
+    return PWAC;
+  }
+
+  auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc();
+  invalidate(COMPLEXITY, DL, BB);
+  return Affinator.getPwAff(SE->getZero(E->getType()), BB);
+}
+
+isl::union_set Scop::getDomains() const {
+  isl_space *EmptySpace = isl_space_params_alloc(getIslCtx().get(), 0);
+  isl_union_set *Domain = isl_union_set_empty(EmptySpace);
+
+  for (const ScopStmt &Stmt : *this)
+    Domain = isl_union_set_add_set(Domain, Stmt.getDomain().release());
+
+  return isl::manage(Domain);
+}
+
+isl::pw_aff Scop::getPwAffOnly(const SCEV *E, BasicBlock *BB) {
+  PWACtx PWAC = getPwAff(E, BB);
+  return PWAC.first;
+}
+
+isl::union_map
+Scop::getAccessesOfType(std::function<bool(MemoryAccess &)> Predicate) {
+  isl::union_map Accesses = isl::union_map::empty(getParamSpace());
+
+  for (ScopStmt &Stmt : *this) {
+    for (MemoryAccess *MA : Stmt) {
+      if (!Predicate(*MA))
+        continue;
+
+      isl::set Domain = Stmt.getDomain();
+      isl::map AccessDomain = MA->getAccessRelation();
+      AccessDomain = AccessDomain.intersect_domain(Domain);
+      Accesses = Accesses.add_map(AccessDomain);
+    }
+  }
+
+  return Accesses.coalesce();
+}
+
+isl::union_map Scop::getMustWrites() {
+  return getAccessesOfType([](MemoryAccess &MA) { return MA.isMustWrite(); });
+}
+
+isl::union_map Scop::getMayWrites() {
+  return getAccessesOfType([](MemoryAccess &MA) { return MA.isMayWrite(); });
+}
+
+isl::union_map Scop::getWrites() {
+  return getAccessesOfType([](MemoryAccess &MA) { return MA.isWrite(); });
+}
+
+isl::union_map Scop::getReads() {
+  return getAccessesOfType([](MemoryAccess &MA) { return MA.isRead(); });
+}
+
+isl::union_map Scop::getAccesses() {
+  return getAccessesOfType([](MemoryAccess &MA) { return true; });
+}
+
+isl::union_map Scop::getAccesses(ScopArrayInfo *Array) {
+  return getAccessesOfType(
+      [Array](MemoryAccess &MA) { return MA.getScopArrayInfo() == Array; });
+}
+
+// Check whether @p Node is an extension node.
+//
+// @return true if @p Node is an extension node.
+isl_bool isNotExtNode(__isl_keep isl_schedule_node *Node, void *User) {
+  if (isl_schedule_node_get_type(Node) == isl_schedule_node_extension)
+    return isl_bool_error;
+  else
+    return isl_bool_true;
+}
+
+bool Scop::containsExtensionNode(isl::schedule Schedule) {
+  return isl_schedule_foreach_schedule_node_top_down(
+             Schedule.keep(), isNotExtNode, nullptr) == isl_stat_error;
+}
+
+isl::union_map Scop::getSchedule() const {
+  auto Tree = getScheduleTree();
+  if (containsExtensionNode(Tree))
+    return nullptr;
+
+  return Tree.get_map();
+}
+
+isl::schedule Scop::getScheduleTree() const {
+  return Schedule.intersect_domain(getDomains());
+}
+
+void Scop::setSchedule(isl::union_map NewSchedule) {
+  auto S = isl::schedule::from_domain(getDomains());
+  Schedule = S.insert_partial_schedule(
+      isl::multi_union_pw_aff::from_union_map(NewSchedule));
+}
+
+void Scop::setScheduleTree(isl::schedule NewSchedule) {
+  Schedule = NewSchedule;
+}
+
+bool Scop::restrictDomains(isl::union_set Domain) {
+  bool Changed = false;
+  for (ScopStmt &Stmt : *this) {
+    isl::union_set StmtDomain = isl::union_set(Stmt.getDomain());
+    isl::union_set NewStmtDomain = StmtDomain.intersect(Domain);
+
+    if (StmtDomain.is_subset(NewStmtDomain))
+      continue;
+
+    Changed = true;
+
+    NewStmtDomain = NewStmtDomain.coalesce();
+
+    if (NewStmtDomain.is_empty())
+      Stmt.restrictDomain(isl::set::empty(Stmt.getDomainSpace()));
+    else
+      Stmt.restrictDomain(isl::set(NewStmtDomain));
+  }
+  return Changed;
+}
+
+ScalarEvolution *Scop::getSE() const { return SE; }
+
+// Create an isl_multi_union_aff that defines an identity mapping from the
+// elements of USet to their N-th dimension.
+//
+// # Example:
+//
+//            Domain: { A[i,j]; B[i,j,k] }
+//                 N: 1
+//
+// Resulting Mapping: { {A[i,j] -> [(j)]; B[i,j,k] -> [(j)] }
+//
+// @param USet   A union set describing the elements for which to generate a
+//               mapping.
+// @param N      The dimension to map to.
+// @returns      A mapping from USet to its N-th dimension.
+static isl::multi_union_pw_aff mapToDimension(isl::union_set USet, int N) {
+  assert(N >= 0);
+  assert(USet);
+  assert(!USet.is_empty());
+
+  auto Result = isl::union_pw_multi_aff::empty(USet.get_space());
+
+  auto Lambda = [&Result, N](isl::set S) -> isl::stat {
+    int Dim = S.dim(isl::dim::set);
+    auto PMA = isl::pw_multi_aff::project_out_map(S.get_space(), isl::dim::set,
+                                                  N, Dim - N);
+    if (N > 1)
+      PMA = PMA.drop_dims(isl::dim::out, 0, N - 1);
+
+    Result = Result.add_pw_multi_aff(PMA);
+    return isl::stat::ok;
+  };
+
+  isl::stat Res = USet.foreach_set(Lambda);
+  (void)Res;
+
+  assert(Res == isl::stat::ok);
+
+  return isl::multi_union_pw_aff(isl::union_pw_multi_aff(Result));
+}
+
+void Scop::addScopStmt(BasicBlock *BB, Loop *SurroundingLoop,
+                       std::vector<Instruction *> Instructions, int Count) {
+  assert(BB && "Unexpected nullptr!");
+  Stmts.emplace_back(*this, *BB, SurroundingLoop, Instructions, Count);
+  auto *Stmt = &Stmts.back();
+  StmtMap[BB].push_back(Stmt);
+  for (Instruction *Inst : Instructions) {
+    assert(!InstStmtMap.count(Inst) &&
+           "Unexpected statement corresponding to the instruction.");
+    InstStmtMap[Inst] = Stmt;
+  }
+}
+
+void Scop::addScopStmt(Region *R, Loop *SurroundingLoop,
+                       std::vector<Instruction *> Instructions) {
+  assert(R && "Unexpected nullptr!");
+  Stmts.emplace_back(*this, *R, SurroundingLoop, Instructions);
+  auto *Stmt = &Stmts.back();
+
+  for (Instruction *Inst : Instructions) {
+    assert(!InstStmtMap.count(Inst) &&
+           "Unexpected statement corresponding to the instruction.");
+    InstStmtMap[Inst] = Stmt;
+  }
+
+  for (BasicBlock *BB : R->blocks()) {
+    StmtMap[BB].push_back(Stmt);
+    if (BB == R->getEntry())
+      continue;
+    for (Instruction &Inst : *BB) {
+      assert(!InstStmtMap.count(&Inst) &&
+             "Unexpected statement corresponding to the instruction.");
+      InstStmtMap[&Inst] = Stmt;
+    }
+  }
+}
+
+ScopStmt *Scop::addScopStmt(isl::map SourceRel, isl::map TargetRel,
+                            isl::set Domain) {
+#ifndef NDEBUG
+  isl::set SourceDomain = SourceRel.domain();
+  isl::set TargetDomain = TargetRel.domain();
+  assert(Domain.is_subset(TargetDomain) &&
+         "Target access not defined for complete statement domain");
+  assert(Domain.is_subset(SourceDomain) &&
+         "Source access not defined for complete statement domain");
+#endif
+  Stmts.emplace_back(*this, SourceRel, TargetRel, Domain);
+  CopyStmtsNum++;
+  return &(Stmts.back());
+}
+
+void Scop::buildSchedule(LoopInfo &LI) {
+  Loop *L = getLoopSurroundingScop(*this, LI);
+  LoopStackTy LoopStack({LoopStackElementTy(L, nullptr, 0)});
+  buildSchedule(getRegion().getNode(), LoopStack, LI);
+  assert(LoopStack.size() == 1 && LoopStack.back().L == L);
+  Schedule = LoopStack[0].Schedule;
+}
+
+/// To generate a schedule for the elements in a Region we traverse the Region
+/// in reverse-post-order and add the contained RegionNodes in traversal order
+/// to the schedule of the loop that is currently at the top of the LoopStack.
+/// For loop-free codes, this results in a correct sequential ordering.
+///
+/// Example:
+///           bb1(0)
+///         /     \.
+///      bb2(1)   bb3(2)
+///         \    /  \.
+///          bb4(3)  bb5(4)
+///             \   /
+///              bb6(5)
+///
+/// Including loops requires additional processing. Whenever a loop header is
+/// encountered, the corresponding loop is added to the @p LoopStack. Starting
+/// from an empty schedule, we first process all RegionNodes that are within
+/// this loop and complete the sequential schedule at this loop-level before
+/// processing about any other nodes. To implement this
+/// loop-nodes-first-processing, the reverse post-order traversal is
+/// insufficient. Hence, we additionally check if the traversal yields
+/// sub-regions or blocks that are outside the last loop on the @p LoopStack.
+/// These region-nodes are then queue and only traverse after the all nodes
+/// within the current loop have been processed.
+void Scop::buildSchedule(Region *R, LoopStackTy &LoopStack, LoopInfo &LI) {
+  Loop *OuterScopLoop = getLoopSurroundingScop(*this, LI);
+
+  ReversePostOrderTraversal<Region *> RTraversal(R);
+  std::deque<RegionNode *> WorkList(RTraversal.begin(), RTraversal.end());
+  std::deque<RegionNode *> DelayList;
+  bool LastRNWaiting = false;
+
+  // Iterate over the region @p R in reverse post-order but queue
+  // sub-regions/blocks iff they are not part of the last encountered but not
+  // completely traversed loop. The variable LastRNWaiting is a flag to indicate
+  // that we queued the last sub-region/block from the reverse post-order
+  // iterator. If it is set we have to explore the next sub-region/block from
+  // the iterator (if any) to guarantee progress. If it is not set we first try
+  // the next queued sub-region/blocks.
+  while (!WorkList.empty() || !DelayList.empty()) {
+    RegionNode *RN;
+
+    if ((LastRNWaiting && !WorkList.empty()) || DelayList.empty()) {
+      RN = WorkList.front();
+      WorkList.pop_front();
+      LastRNWaiting = false;
+    } else {
+      RN = DelayList.front();
+      DelayList.pop_front();
+    }
+
+    Loop *L = getRegionNodeLoop(RN, LI);
+    if (!contains(L))
+      L = OuterScopLoop;
+
+    Loop *LastLoop = LoopStack.back().L;
+    if (LastLoop != L) {
+      if (LastLoop && !LastLoop->contains(L)) {
+        LastRNWaiting = true;
+        DelayList.push_back(RN);
+        continue;
+      }
+      LoopStack.push_back({L, nullptr, 0});
+    }
+    buildSchedule(RN, LoopStack, LI);
+  }
+}
+
+void Scop::buildSchedule(RegionNode *RN, LoopStackTy &LoopStack, LoopInfo &LI) {
+  if (RN->isSubRegion()) {
+    auto *LocalRegion = RN->getNodeAs<Region>();
+    if (!isNonAffineSubRegion(LocalRegion)) {
+      buildSchedule(LocalRegion, LoopStack, LI);
+      return;
+    }
+  }
+
+  assert(LoopStack.rbegin() != LoopStack.rend());
+  auto LoopData = LoopStack.rbegin();
+  LoopData->NumBlocksProcessed += getNumBlocksInRegionNode(RN);
+
+  for (auto *Stmt : getStmtListFor(RN)) {
+    isl::union_set UDomain{Stmt->getDomain()};
+    auto StmtSchedule = isl::schedule::from_domain(UDomain);
+    LoopData->Schedule = combineInSequence(LoopData->Schedule, StmtSchedule);
+  }
+
+  // Check if we just processed the last node in this loop. If we did, finalize
+  // the loop by:
+  //
+  //   - adding new schedule dimensions
+  //   - folding the resulting schedule into the parent loop schedule
+  //   - dropping the loop schedule from the LoopStack.
+  //
+  // Then continue to check surrounding loops, which might also have been
+  // completed by this node.
+  size_t Dimension = LoopStack.size();
+  while (LoopData->L &&
+         LoopData->NumBlocksProcessed == getNumBlocksInLoop(LoopData->L)) {
+    isl::schedule Schedule = LoopData->Schedule;
+    auto NumBlocksProcessed = LoopData->NumBlocksProcessed;
+
+    assert(std::next(LoopData) != LoopStack.rend());
+    ++LoopData;
+    --Dimension;
+
+    if (Schedule) {
+      isl::union_set Domain = Schedule.get_domain();
+      isl::multi_union_pw_aff MUPA = mapToDimension(Domain, Dimension);
+      Schedule = Schedule.insert_partial_schedule(MUPA);
+      LoopData->Schedule = combineInSequence(LoopData->Schedule, Schedule);
+    }
+
+    LoopData->NumBlocksProcessed += NumBlocksProcessed;
+  }
+  // Now pop all loops processed up there from the LoopStack
+  LoopStack.erase(LoopStack.begin() + Dimension, LoopStack.end());
+}
+
+ArrayRef<ScopStmt *> Scop::getStmtListFor(BasicBlock *BB) const {
+  auto StmtMapIt = StmtMap.find(BB);
+  if (StmtMapIt == StmtMap.end())
+    return {};
+  return StmtMapIt->second;
+}
+
+ScopStmt *Scop::getLastStmtFor(BasicBlock *BB) const {
+  ArrayRef<ScopStmt *> StmtList = getStmtListFor(BB);
+  if (!StmtList.empty())
+    return StmtList.back();
+  return nullptr;
+}
+
+ArrayRef<ScopStmt *> Scop::getStmtListFor(RegionNode *RN) const {
+  if (RN->isSubRegion())
+    return getStmtListFor(RN->getNodeAs<Region>());
+  return getStmtListFor(RN->getNodeAs<BasicBlock>());
+}
+
+ArrayRef<ScopStmt *> Scop::getStmtListFor(Region *R) const {
+  return getStmtListFor(R->getEntry());
+}
+
+int Scop::getRelativeLoopDepth(const Loop *L) const {
+  if (!L || !R.contains(L))
+    return -1;
+  // outermostLoopInRegion always returns nullptr for top level regions
+  if (R.isTopLevelRegion()) {
+    // LoopInfo's depths start at 1, we start at 0
+    return L->getLoopDepth() - 1;
+  } else {
+    Loop *OuterLoop = R.outermostLoopInRegion(const_cast<Loop *>(L));
+    assert(OuterLoop);
+    return L->getLoopDepth() - OuterLoop->getLoopDepth();
+  }
+}
+
+ScopArrayInfo *Scop::getArrayInfoByName(const std::string BaseName) {
+  for (auto &SAI : arrays()) {
+    if (SAI->getName() == BaseName)
+      return SAI;
+  }
+  return nullptr;
+}
+
+void Scop::addAccessData(MemoryAccess *Access) {
+  const ScopArrayInfo *SAI = Access->getOriginalScopArrayInfo();
+  assert(SAI && "can only use after access relations have been constructed");
+
+  if (Access->isOriginalValueKind() && Access->isRead())
+    ValueUseAccs[SAI].push_back(Access);
+  else if (Access->isOriginalAnyPHIKind() && Access->isWrite())
+    PHIIncomingAccs[SAI].push_back(Access);
+}
+
+void Scop::removeAccessData(MemoryAccess *Access) {
+  if (Access->isOriginalValueKind() && Access->isWrite()) {
+    ValueDefAccs.erase(Access->getAccessValue());
+  } else if (Access->isOriginalValueKind() && Access->isRead()) {
+    auto &Uses = ValueUseAccs[Access->getScopArrayInfo()];
+    std::remove(Uses.begin(), Uses.end(), Access);
+  } else if (Access->isOriginalPHIKind() && Access->isRead()) {
+    PHINode *PHI = cast<PHINode>(Access->getAccessInstruction());
+    PHIReadAccs.erase(PHI);
+  } else if (Access->isOriginalAnyPHIKind() && Access->isWrite()) {
+    auto &Incomings = PHIIncomingAccs[Access->getScopArrayInfo()];
+    std::remove(Incomings.begin(), Incomings.end(), Access);
+  }
+}
+
+MemoryAccess *Scop::getValueDef(const ScopArrayInfo *SAI) const {
+  assert(SAI->isValueKind());
+
+  Instruction *Val = dyn_cast<Instruction>(SAI->getBasePtr());
+  if (!Val)
+    return nullptr;
+
+  return ValueDefAccs.lookup(Val);
+}
+
+ArrayRef<MemoryAccess *> Scop::getValueUses(const ScopArrayInfo *SAI) const {
+  assert(SAI->isValueKind());
+  auto It = ValueUseAccs.find(SAI);
+  if (It == ValueUseAccs.end())
+    return {};
+  return It->second;
+}
+
+MemoryAccess *Scop::getPHIRead(const ScopArrayInfo *SAI) const {
+  assert(SAI->isPHIKind() || SAI->isExitPHIKind());
+
+  if (SAI->isExitPHIKind())
+    return nullptr;
+
+  PHINode *PHI = cast<PHINode>(SAI->getBasePtr());
+  return PHIReadAccs.lookup(PHI);
+}
+
+ArrayRef<MemoryAccess *> Scop::getPHIIncomings(const ScopArrayInfo *SAI) const {
+  assert(SAI->isPHIKind() || SAI->isExitPHIKind());
+  auto It = PHIIncomingAccs.find(SAI);
+  if (It == PHIIncomingAccs.end())
+    return {};
+  return It->second;
+}
+
+bool Scop::isEscaping(Instruction *Inst) {
+  assert(contains(Inst) && "The concept of escaping makes only sense for "
+                           "values defined inside the SCoP");
+
+  for (Use &Use : Inst->uses()) {
+    BasicBlock *UserBB = getUseBlock(Use);
+    if (!contains(UserBB))
+      return true;
+
+    // When the SCoP region exit needs to be simplified, PHIs in the region exit
+    // move to a new basic block such that its incoming blocks are not in the
+    // SCoP anymore.
+    if (hasSingleExitEdge() && isa<PHINode>(Use.getUser()) &&
+        isExit(cast<PHINode>(Use.getUser())->getParent()))
+      return true;
+  }
+  return false;
+}
+
+Scop::ScopStatistics Scop::getStatistics() const {
+  ScopStatistics Result;
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
+  auto LoopStat = ScopDetection::countBeneficialLoops(&R, *SE, *getLI(), 0);
+
+  int NumTotalLoops = LoopStat.NumLoops;
+  Result.NumBoxedLoops = getBoxedLoops().size();
+  Result.NumAffineLoops = NumTotalLoops - Result.NumBoxedLoops;
+
+  for (const ScopStmt &Stmt : *this) {
+    isl::set Domain = Stmt.getDomain().intersect_params(getContext());
+    bool IsInLoop = Stmt.getNumIterators() >= 1;
+    for (MemoryAccess *MA : Stmt) {
+      if (!MA->isWrite())
+        continue;
+
+      if (MA->isLatestValueKind()) {
+        Result.NumValueWrites += 1;
+        if (IsInLoop)
+          Result.NumValueWritesInLoops += 1;
+      }
+
+      if (MA->isLatestAnyPHIKind()) {
+        Result.NumPHIWrites += 1;
+        if (IsInLoop)
+          Result.NumPHIWritesInLoops += 1;
+      }
+
+      isl::set AccSet =
+          MA->getAccessRelation().intersect_domain(Domain).range();
+      if (AccSet.is_singleton()) {
+        Result.NumSingletonWrites += 1;
+        if (IsInLoop)
+          Result.NumSingletonWritesInLoops += 1;
+      }
+    }
+  }
+#endif
+  return Result;
+}
+
+raw_ostream &polly::operator<<(raw_ostream &OS, const Scop &scop) {
+  scop.print(OS, PollyPrintInstructions);
+  return OS;
+}
+
+//===----------------------------------------------------------------------===//
+void ScopInfoRegionPass::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequired<LoopInfoWrapperPass>();
+  AU.addRequired<RegionInfoPass>();
+  AU.addRequired<DominatorTreeWrapperPass>();
+  AU.addRequiredTransitive<ScalarEvolutionWrapperPass>();
+  AU.addRequiredTransitive<ScopDetectionWrapperPass>();
+  AU.addRequired<AAResultsWrapperPass>();
+  AU.addRequired<AssumptionCacheTracker>();
+  AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
+  AU.setPreservesAll();
+}
+
+void updateLoopCountStatistic(ScopDetection::LoopStats Stats,
+                              Scop::ScopStatistics ScopStats) {
+  assert(Stats.NumLoops == ScopStats.NumAffineLoops + ScopStats.NumBoxedLoops);
+
+  NumScops++;
+  NumLoopsInScop += Stats.NumLoops;
+  MaxNumLoopsInScop =
+      std::max(MaxNumLoopsInScop.getValue(), (unsigned)Stats.NumLoops);
+
+  if (Stats.MaxDepth == 1)
+    NumScopsDepthOne++;
+  else if (Stats.MaxDepth == 2)
+    NumScopsDepthTwo++;
+  else if (Stats.MaxDepth == 3)
+    NumScopsDepthThree++;
+  else if (Stats.MaxDepth == 4)
+    NumScopsDepthFour++;
+  else if (Stats.MaxDepth == 5)
+    NumScopsDepthFive++;
+  else
+    NumScopsDepthLarger++;
+
+  NumAffineLoops += ScopStats.NumAffineLoops;
+  NumBoxedLoops += ScopStats.NumBoxedLoops;
+
+  NumValueWrites += ScopStats.NumValueWrites;
+  NumValueWritesInLoops += ScopStats.NumValueWritesInLoops;
+  NumPHIWrites += ScopStats.NumPHIWrites;
+  NumPHIWritesInLoops += ScopStats.NumPHIWritesInLoops;
+  NumSingletonWrites += ScopStats.NumSingletonWrites;
+  NumSingletonWritesInLoops += ScopStats.NumSingletonWritesInLoops;
+}
+
+bool ScopInfoRegionPass::runOnRegion(Region *R, RGPassManager &RGM) {
+  auto &SD = getAnalysis<ScopDetectionWrapperPass>().getSD();
+
+  if (!SD.isMaxRegionInScop(*R))
+    return false;
+
+  Function *F = R->getEntry()->getParent();
+  auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
+  auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+  auto &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
+  auto const &DL = F->getParent()->getDataLayout();
+  auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+  auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(*F);
+  auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
+
+  ScopBuilder SB(R, AC, AA, DL, DT, LI, SD, SE, ORE);
+  S = SB.getScop(); // take ownership of scop object
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
+  if (S) {
+    ScopDetection::LoopStats Stats =
+        ScopDetection::countBeneficialLoops(&S->getRegion(), SE, LI, 0);
+    updateLoopCountStatistic(Stats, S->getStatistics());
+  }
+#endif
+
+  return false;
+}
+
+void ScopInfoRegionPass::print(raw_ostream &OS, const Module *) const {
+  if (S)
+    S->print(OS, PollyPrintInstructions);
+  else
+    OS << "Invalid Scop!\n";
+}
+
+char ScopInfoRegionPass::ID = 0;
+
+Pass *polly::createScopInfoRegionPassPass() { return new ScopInfoRegionPass(); }
+
+INITIALIZE_PASS_BEGIN(ScopInfoRegionPass, "polly-scops",
+                      "Polly - Create polyhedral description of Scops", false,
+                      false);
+INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker);
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
+INITIALIZE_PASS_END(ScopInfoRegionPass, "polly-scops",
+                    "Polly - Create polyhedral description of Scops", false,
+                    false)
+
+//===----------------------------------------------------------------------===//
+ScopInfo::ScopInfo(const DataLayout &DL, ScopDetection &SD, ScalarEvolution &SE,
+                   LoopInfo &LI, AliasAnalysis &AA, DominatorTree &DT,
+                   AssumptionCache &AC, OptimizationRemarkEmitter &ORE)
+    : DL(DL), SD(SD), SE(SE), LI(LI), AA(AA), DT(DT), AC(AC), ORE(ORE) {
+  recompute();
+}
+
+void ScopInfo::recompute() {
+  RegionToScopMap.clear();
+  /// Create polyhedral description of scops for all the valid regions of a
+  /// function.
+  for (auto &It : SD) {
+    Region *R = const_cast<Region *>(It);
+    if (!SD.isMaxRegionInScop(*R))
+      continue;
+
+    ScopBuilder SB(R, AC, AA, DL, DT, LI, SD, SE, ORE);
+    std::unique_ptr<Scop> S = SB.getScop();
+    if (!S)
+      continue;
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
+    ScopDetection::LoopStats Stats =
+        ScopDetection::countBeneficialLoops(&S->getRegion(), SE, LI, 0);
+    updateLoopCountStatistic(Stats, S->getStatistics());
+#endif
+    bool Inserted = RegionToScopMap.insert({R, std::move(S)}).second;
+    assert(Inserted && "Building Scop for the same region twice!");
+    (void)Inserted;
+  }
+}
+
+bool ScopInfo::invalidate(Function &F, const PreservedAnalyses &PA,
+                          FunctionAnalysisManager::Invalidator &Inv) {
+  // Check whether the analysis, all analyses on functions have been preserved
+  // or anything we're holding references to is being invalidated
+  auto PAC = PA.getChecker<ScopInfoAnalysis>();
+  return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>()) ||
+         Inv.invalidate<ScopAnalysis>(F, PA) ||
+         Inv.invalidate<ScalarEvolutionAnalysis>(F, PA) ||
+         Inv.invalidate<LoopAnalysis>(F, PA) ||
+         Inv.invalidate<AAManager>(F, PA) ||
+         Inv.invalidate<DominatorTreeAnalysis>(F, PA) ||
+         Inv.invalidate<AssumptionAnalysis>(F, PA);
+}
+
+AnalysisKey ScopInfoAnalysis::Key;
+
+ScopInfoAnalysis::Result ScopInfoAnalysis::run(Function &F,
+                                               FunctionAnalysisManager &FAM) {
+  auto &SD = FAM.getResult<ScopAnalysis>(F);
+  auto &SE = FAM.getResult<ScalarEvolutionAnalysis>(F);
+  auto &LI = FAM.getResult<LoopAnalysis>(F);
+  auto &AA = FAM.getResult<AAManager>(F);
+  auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
+  auto &AC = FAM.getResult<AssumptionAnalysis>(F);
+  auto &DL = F.getParent()->getDataLayout();
+  auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
+  return {DL, SD, SE, LI, AA, DT, AC, ORE};
+}
+
+PreservedAnalyses ScopInfoPrinterPass::run(Function &F,
+                                           FunctionAnalysisManager &FAM) {
+  auto &SI = FAM.getResult<ScopInfoAnalysis>(F);
+  // Since the legacy PM processes Scops in bottom up, we print them in reverse
+  // order here to keep the output persistent
+  for (auto &It : reverse(SI)) {
+    if (It.second)
+      It.second->print(Stream, PollyPrintInstructions);
+    else
+      Stream << "Invalid Scop!\n";
+  }
+  return PreservedAnalyses::all();
+}
+
+void ScopInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequired<LoopInfoWrapperPass>();
+  AU.addRequired<RegionInfoPass>();
+  AU.addRequired<DominatorTreeWrapperPass>();
+  AU.addRequiredTransitive<ScalarEvolutionWrapperPass>();
+  AU.addRequiredTransitive<ScopDetectionWrapperPass>();
+  AU.addRequired<AAResultsWrapperPass>();
+  AU.addRequired<AssumptionCacheTracker>();
+  AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
+  AU.setPreservesAll();
+}
+
+bool ScopInfoWrapperPass::runOnFunction(Function &F) {
+  auto &SD = getAnalysis<ScopDetectionWrapperPass>().getSD();
+  auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
+  auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+  auto &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
+  auto const &DL = F.getParent()->getDataLayout();
+  auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+  auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
+  auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
+
+  Result.reset(new ScopInfo{DL, SD, SE, LI, AA, DT, AC, ORE});
+  return false;
+}
+
+void ScopInfoWrapperPass::print(raw_ostream &OS, const Module *) const {
+  for (auto &It : *Result) {
+    if (It.second)
+      It.second->print(OS, PollyPrintInstructions);
+    else
+      OS << "Invalid Scop!\n";
+  }
+}
+
+char ScopInfoWrapperPass::ID = 0;
+
+Pass *polly::createScopInfoWrapperPassPass() {
+  return new ScopInfoWrapperPass();
+}
+
+INITIALIZE_PASS_BEGIN(
+    ScopInfoWrapperPass, "polly-function-scops",
+    "Polly - Create polyhedral description of all Scops of a function", false,
+    false);
+INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker);
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
+INITIALIZE_PASS_END(
+    ScopInfoWrapperPass, "polly-function-scops",
+    "Polly - Create polyhedral description of all Scops of a function", false,
+    false)
diff --git a/final/lib/Analysis/ScopPass.cpp b/final/lib/Analysis/ScopPass.cpp
new file mode 100644
index 0000000..b91d66a
--- /dev/null
+++ b/final/lib/Analysis/ScopPass.cpp
@@ -0,0 +1,168 @@
+//===- ScopPass.cpp - The base class of Passes that operate on Polly IR ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the definitions of the ScopPass members.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/ScopPass.h"
+#include "polly/ScopInfo.h"
+
+#include "llvm/Analysis/AssumptionCache.h"
+#include "llvm/Analysis/BasicAliasAnalysis.h"
+#include "llvm/Analysis/GlobalsModRef.h"
+#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+
+using namespace llvm;
+using namespace polly;
+
+bool ScopPass::runOnRegion(Region *R, RGPassManager &RGM) {
+  S = nullptr;
+
+  if (skipRegion(*R))
+    return false;
+
+  if ((S = getAnalysis<ScopInfoRegionPass>().getScop()))
+    return runOnScop(*S);
+
+  return false;
+}
+
+void ScopPass::print(raw_ostream &OS, const Module *M) const {
+  if (S)
+    printScop(OS, *S);
+}
+
+void ScopPass::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequired<ScopInfoRegionPass>();
+
+  AU.addPreserved<AAResultsWrapperPass>();
+  AU.addPreserved<BasicAAWrapperPass>();
+  AU.addPreserved<LoopInfoWrapperPass>();
+  AU.addPreserved<DominatorTreeWrapperPass>();
+  AU.addPreserved<GlobalsAAWrapperPass>();
+  AU.addPreserved<ScopDetectionWrapperPass>();
+  AU.addPreserved<ScalarEvolutionWrapperPass>();
+  AU.addPreserved<SCEVAAWrapperPass>();
+  AU.addPreserved<OptimizationRemarkEmitterWrapperPass>();
+  AU.addPreserved<RegionInfoPass>();
+  AU.addPreserved<ScopInfoRegionPass>();
+  AU.addPreserved<TargetTransformInfoWrapperPass>();
+}
+
+namespace polly {
+template class OwningInnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
+}
+
+namespace llvm {
+
+template class PassManager<Scop, ScopAnalysisManager,
+                           ScopStandardAnalysisResults &, SPMUpdater &>;
+template class InnerAnalysisManagerProxy<ScopAnalysisManager, Function>;
+template class OuterAnalysisManagerProxy<FunctionAnalysisManager, Scop,
+                                         ScopStandardAnalysisResults &>;
+
+template <>
+PreservedAnalyses
+PassManager<Scop, ScopAnalysisManager, ScopStandardAnalysisResults &,
+            SPMUpdater &>::run(Scop &S, ScopAnalysisManager &AM,
+                               ScopStandardAnalysisResults &AR, SPMUpdater &U) {
+  auto PA = PreservedAnalyses::all();
+  for (auto &Pass : Passes) {
+    auto PassPA = Pass->run(S, AM, AR, U);
+
+    AM.invalidate(S, PassPA);
+    PA.intersect(std::move(PassPA));
+  }
+
+  // All analyses for 'this' Scop have been invalidated above.
+  // If ScopPasses affect break other scops they have to propagate this
+  // information through the updater
+  PA.preserveSet<AllAnalysesOn<Scop>>();
+  return PA;
+}
+
+bool ScopAnalysisManagerFunctionProxy::Result::invalidate(
+    Function &F, const PreservedAnalyses &PA,
+    FunctionAnalysisManager::Invalidator &Inv) {
+
+  // First, check whether our ScopInfo is about to be invalidated
+  auto PAC = PA.getChecker<ScopAnalysisManagerFunctionProxy>();
+  if (!(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>()) ||
+      Inv.invalidate<ScopInfoAnalysis>(F, PA) ||
+      Inv.invalidate<ScalarEvolutionAnalysis>(F, PA) ||
+      Inv.invalidate<LoopAnalysis>(F, PA) ||
+      Inv.invalidate<DominatorTreeAnalysis>(F, PA)) {
+
+    // As everything depends on ScopInfo, we must drop all existing results
+    for (auto &S : *SI)
+      if (auto *scop = S.second.get())
+        if (InnerAM)
+          InnerAM->clear(*scop, scop->getName());
+
+    InnerAM = nullptr;
+    return true; // Invalidate the proxy result as well.
+  }
+
+  bool allPreserved = PA.allAnalysesInSetPreserved<AllAnalysesOn<Scop>>();
+
+  // Invalidate all non-preserved analyses
+  // Even if all analyses were preserved, we still need to run deferred
+  // invalidation
+  for (auto &S : *SI) {
+    Optional<PreservedAnalyses> InnerPA;
+    auto *scop = S.second.get();
+    if (!scop)
+      continue;
+
+    if (auto *OuterProxy =
+            InnerAM->getCachedResult<FunctionAnalysisManagerScopProxy>(*scop)) {
+      for (const auto &InvPair : OuterProxy->getOuterInvalidations()) {
+        auto *OuterAnalysisID = InvPair.first;
+        const auto &InnerAnalysisIDs = InvPair.second;
+
+        if (Inv.invalidate(OuterAnalysisID, F, PA)) {
+          if (!InnerPA)
+            InnerPA = PA;
+          for (auto *InnerAnalysisID : InnerAnalysisIDs)
+            InnerPA->abandon(InnerAnalysisID);
+        }
+      }
+
+      if (InnerPA) {
+        InnerAM->invalidate(*scop, *InnerPA);
+        continue;
+      }
+    }
+
+    if (!allPreserved)
+      InnerAM->invalidate(*scop, PA);
+  }
+
+  return false; // This proxy is still valid
+}
+
+template <>
+ScopAnalysisManagerFunctionProxy::Result
+ScopAnalysisManagerFunctionProxy::run(Function &F,
+                                      FunctionAnalysisManager &FAM) {
+  return Result(*InnerAM, FAM.getResult<ScopInfoAnalysis>(F));
+}
+} // namespace llvm
+
+namespace polly {
+template <>
+OwningScopAnalysisManagerFunctionProxy::Result
+OwningScopAnalysisManagerFunctionProxy::run(Function &F,
+                                            FunctionAnalysisManager &FAM) {
+  return Result(InnerAM, FAM.getResult<ScopInfoAnalysis>(F));
+}
+} // namespace polly
diff --git a/final/lib/CMakeLists.txt b/final/lib/CMakeLists.txt
new file mode 100644
index 0000000..cba633a
--- /dev/null
+++ b/final/lib/CMakeLists.txt
@@ -0,0 +1,163 @@
+set(LLVM_NO_RTTI 1)
+
+set(ISL_CODEGEN_FILES
+    CodeGen/IslAst.cpp
+    CodeGen/IslExprBuilder.cpp
+    CodeGen/IslNodeBuilder.cpp
+    CodeGen/CodeGeneration.cpp)
+
+if (GPU_CODEGEN)
+  set (GPGPU_CODEGEN_FILES
+       CodeGen/PPCGCodeGeneration.cpp
+       CodeGen/ManagedMemoryRewrite.cpp
+       )
+endif (GPU_CODEGEN)
+
+# Compile ISL into a separate library.
+add_subdirectory(External)
+
+set(POLLY_HEADER_FILES)
+if (MSVC_IDE OR XCODE)
+  file(GLOB_RECURSE POLLY_HEADER_FILES "${POLLY_SOURCE_DIR}/include/polly/*.h")
+endif ()
+
+# Use an object-library to add the same files to multiple libs without requiring
+# the sources them to be recompiled for each of them.
+add_library(PollyCore OBJECT
+  Analysis/DependenceInfo.cpp
+  Analysis/PolyhedralInfo.cpp
+  Analysis/ScopDetection.cpp
+  Analysis/ScopDetectionDiagnostic.cpp
+  Analysis/ScopInfo.cpp
+  Analysis/ScopBuilder.cpp
+  Analysis/ScopGraphPrinter.cpp
+  Analysis/ScopPass.cpp
+  Analysis/PruneUnprofitable.cpp
+  CodeGen/BlockGenerators.cpp
+  ${ISL_CODEGEN_FILES}
+  CodeGen/LoopGenerators.cpp
+  CodeGen/IRBuilder.cpp
+  CodeGen/Utils.cpp
+  CodeGen/RuntimeDebugBuilder.cpp
+  CodeGen/CodegenCleanup.cpp
+  CodeGen/PerfMonitor.cpp
+  ${GPGPU_CODEGEN_FILES}
+  Exchange/JSONExporter.cpp
+  Support/GICHelper.cpp
+  Support/SCEVAffinator.cpp
+  Support/SCEVValidator.cpp
+  Support/RegisterPasses.cpp
+  Support/ScopHelper.cpp
+  Support/ScopLocation.cpp
+  Support/ISLTools.cpp
+  Support/DumpModulePass.cpp
+  Support/VirtualInstruction.cpp
+  ${POLLY_JSON_FILES}
+  Transform/Canonicalization.cpp
+  Transform/CodePreparation.cpp
+  Transform/DeadCodeElimination.cpp
+  Transform/ScheduleOptimizer.cpp
+  Transform/FlattenSchedule.cpp
+  Transform/FlattenAlgo.cpp
+  Transform/ForwardOpTree.cpp
+  Transform/DeLICM.cpp
+  Transform/ZoneAlgo.cpp
+  Transform/Simplify.cpp
+  Transform/MaximalStaticExpansion.cpp
+  Transform/RewriteByReferenceParameters.cpp
+  Transform/ScopInliner.cpp
+  ${POLLY_HEADER_FILES}
+  )
+set_target_properties(PollyCore PROPERTIES FOLDER "Polly")
+
+# Create the library that can be linked into LLVM's tools and Polly's unittests.
+# It depends on all library it needs, such that with
+# LLVM_POLLY_LINK_INTO_TOOLS=ON, its dependencies like PollyISL are linked as
+# well.
+add_polly_library(Polly $<TARGET_OBJECTS:PollyCore>)
+target_link_libraries(Polly
+  ${ISL_TARGET}
+  ${JSONCPP_LIBRARIES}
+)
+
+# Additional dependencies for Polly-ACC.
+if (GPU_CODEGEN)
+  target_link_libraries(Polly PollyPPCG)
+endif ()
+
+
+# Polly-ACC requires the NVPTX backend to work. Ask LLVM about its libraries.
+set(nvptx_libs)
+if (GPU_CODEGEN)
+  # This call emits an error if they NVPTX backend is not enable.
+  llvm_map_components_to_libnames(nvptx_libs NVPTX)
+endif ()
+
+if (LLVM_LINK_LLVM_DYLIB)
+  # The shlib/dylib contains all the LLVM components
+  # (including NVPTX is enabled) already. Adding them to target_link_libraries
+  # would cause them being twice in the address space
+  # (their LLVM*.a/so and their copies in libLLVM.so)
+  # which results in errors when the two instances try to register the same
+  # command-line switches.
+  target_link_libraries(Polly LLVM)
+else ()
+  target_link_libraries(Polly
+    LLVMSupport
+    LLVMCore
+    LLVMScalarOpts
+    LLVMInstCombine
+    LLVMTransformUtils
+    LLVMAnalysis
+    LLVMipo
+    LLVMMC
+    LLVMPasses
+    LLVMLinker
+    LLVMIRReader
+    ${nvptx_libs}
+    # The libraries below are required for darwin: http://PR26392
+    LLVMBitReader
+    LLVMMCParser
+    LLVMObject
+    LLVMProfileData
+    LLVMTarget
+    LLVMVectorize
+    )
+endif ()
+
+# Create a loadable module Polly.so that can be loaded using
+# LLVM's/clang's "-load" option.
+if (MSVC)
+  # Add dummy target, because loadable modules are not supported on Windows
+  add_custom_target(LLVMPolly)
+  set_target_properties(LLVMPolly PROPERTIES FOLDER "Polly")
+else ()
+  add_polly_loadable_module(LLVMPolly
+    Polly.cpp
+    $<TARGET_OBJECTS:PollyCore>
+  )
+
+  # Only add the dependencies that are not part of LLVM. The latter are assumed
+  # to be already available in the address space the module is loaded into.
+  # Adding them once more would have the effect that both copies try to register
+  # the same command line options, to which LLVM reacts with an error.
+  # If Polly-ACC is enabled, the NVPTX target is also expected to reside in the
+  # hosts. This is not the case for bugpoint. Use LLVM_POLLY_LINK_INTO_TOOLS=ON
+  # instead which will automatically resolve the additional dependencies by
+  # Polly.
+  target_link_libraries(LLVMPolly ${ISL_TARGET} ${JSONCPP_LIBRARIES})
+  if (GPU_CODEGEN)
+    target_link_libraries(LLVMPolly PollyPPCG)
+  endif ()
+
+  set_target_properties(LLVMPolly
+    PROPERTIES
+    LINKER_LANGUAGE CXX
+    PREFIX "")
+endif ()
+
+if (TARGET intrinsics_gen)
+  # Check if we are building as part of an LLVM build
+  add_dependencies(PollyCore intrinsics_gen)
+endif()
+
diff --git a/final/lib/CodeGen/BlockGenerators.cpp b/final/lib/CodeGen/BlockGenerators.cpp
new file mode 100644
index 0000000..29c29ff
--- /dev/null
+++ b/final/lib/CodeGen/BlockGenerators.cpp
@@ -0,0 +1,1674 @@
+//===--- BlockGenerators.cpp - Generate code for statements -----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the BlockGenerator and VectorBlockGenerator classes,
+// which generate sequential code and vectorized code for a polyhedral
+// statement, respectively.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/BlockGenerators.h"
+#include "polly/CodeGen/CodeGeneration.h"
+#include "polly/CodeGen/IslExprBuilder.h"
+#include "polly/CodeGen/RuntimeDebugBuilder.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/SCEVValidator.h"
+#include "polly/Support/ScopHelper.h"
+#include "polly/Support/VirtualInstruction.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Local.h"
+#include "isl/aff.h"
+#include "isl/ast.h"
+#include "isl/ast_build.h"
+#include "isl/set.h"
+#include <deque>
+
+using namespace llvm;
+using namespace polly;
+
+static cl::opt<bool> Aligned("enable-polly-aligned",
+                             cl::desc("Assumed aligned memory accesses."),
+                             cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                             cl::cat(PollyCategory));
+
+bool PollyDebugPrinting;
+static cl::opt<bool, true> DebugPrintingX(
+    "polly-codegen-add-debug-printing",
+    cl::desc("Add printf calls that show the values loaded/stored."),
+    cl::location(PollyDebugPrinting), cl::Hidden, cl::init(false),
+    cl::ZeroOrMore, cl::cat(PollyCategory));
+
+BlockGenerator::BlockGenerator(
+    PollyIRBuilder &B, LoopInfo &LI, ScalarEvolution &SE, DominatorTree &DT,
+    AllocaMapTy &ScalarMap, EscapeUsersAllocaMapTy &EscapeMap,
+    ValueMapT &GlobalMap, IslExprBuilder *ExprBuilder, BasicBlock *StartBlock)
+    : Builder(B), LI(LI), SE(SE), ExprBuilder(ExprBuilder), DT(DT),
+      EntryBB(nullptr), ScalarMap(ScalarMap), EscapeMap(EscapeMap),
+      GlobalMap(GlobalMap), StartBlock(StartBlock) {}
+
+Value *BlockGenerator::trySynthesizeNewValue(ScopStmt &Stmt, Value *Old,
+                                             ValueMapT &BBMap,
+                                             LoopToScevMapT &LTS,
+                                             Loop *L) const {
+  if (!SE.isSCEVable(Old->getType()))
+    return nullptr;
+
+  const SCEV *Scev = SE.getSCEVAtScope(Old, L);
+  if (!Scev)
+    return nullptr;
+
+  if (isa<SCEVCouldNotCompute>(Scev))
+    return nullptr;
+
+  const SCEV *NewScev = SCEVLoopAddRecRewriter::rewrite(Scev, LTS, SE);
+  ValueMapT VTV;
+  VTV.insert(BBMap.begin(), BBMap.end());
+  VTV.insert(GlobalMap.begin(), GlobalMap.end());
+
+  Scop &S = *Stmt.getParent();
+  const DataLayout &DL = S.getFunction().getParent()->getDataLayout();
+  auto IP = Builder.GetInsertPoint();
+
+  assert(IP != Builder.GetInsertBlock()->end() &&
+         "Only instructions can be insert points for SCEVExpander");
+  Value *Expanded =
+      expandCodeFor(S, SE, DL, "polly", NewScev, Old->getType(), &*IP, &VTV,
+                    StartBlock->getSinglePredecessor());
+
+  BBMap[Old] = Expanded;
+  return Expanded;
+}
+
+Value *BlockGenerator::getNewValue(ScopStmt &Stmt, Value *Old, ValueMapT &BBMap,
+                                   LoopToScevMapT &LTS, Loop *L) const {
+
+  auto lookupGlobally = [this](Value *Old) -> Value * {
+    Value *New = GlobalMap.lookup(Old);
+    if (!New)
+      return nullptr;
+
+    // Required by:
+    // * Isl/CodeGen/OpenMP/invariant_base_pointer_preloaded.ll
+    // * Isl/CodeGen/OpenMP/invariant_base_pointer_preloaded_different_bb.ll
+    // * Isl/CodeGen/OpenMP/invariant_base_pointer_preloaded_pass_only_needed.ll
+    // * Isl/CodeGen/OpenMP/invariant_base_pointers_preloaded.ll
+    // * Isl/CodeGen/OpenMP/loop-body-references-outer-values-3.ll
+    // * Isl/CodeGen/OpenMP/single_loop_with_loop_invariant_baseptr.ll
+    // GlobalMap should be a mapping from (value in original SCoP) to (copied
+    // value in generated SCoP), without intermediate mappings, which might
+    // easily require transitiveness as well.
+    if (Value *NewRemapped = GlobalMap.lookup(New))
+      New = NewRemapped;
+
+    // No test case for this code.
+    if (Old->getType()->getScalarSizeInBits() <
+        New->getType()->getScalarSizeInBits())
+      New = Builder.CreateTruncOrBitCast(New, Old->getType());
+
+    return New;
+  };
+
+  Value *New = nullptr;
+  auto VUse = VirtualUse::create(&Stmt, L, Old, true);
+  switch (VUse.getKind()) {
+  case VirtualUse::Block:
+    // BasicBlock are constants, but the BlockGenerator copies them.
+    New = BBMap.lookup(Old);
+    break;
+
+  case VirtualUse::Constant:
+    // Used by:
+    // * Isl/CodeGen/OpenMP/reference-argument-from-non-affine-region.ll
+    // Constants should not be redefined. In this case, the GlobalMap just
+    // contains a mapping to the same constant, which is unnecessary, but
+    // harmless.
+    if ((New = lookupGlobally(Old)))
+      break;
+
+    assert(!BBMap.count(Old));
+    New = Old;
+    break;
+
+  case VirtualUse::ReadOnly:
+    assert(!GlobalMap.count(Old));
+
+    // Required for:
+    // * Isl/CodeGen/MemAccess/create_arrays.ll
+    // * Isl/CodeGen/read-only-scalars.ll
+    // * ScheduleOptimizer/pattern-matching-based-opts_10.ll
+    // For some reason these reload a read-only value. The reloaded value ends
+    // up in BBMap, buts its value should be identical.
+    //
+    // Required for:
+    // * Isl/CodeGen/OpenMP/single_loop_with_param.ll
+    // The parallel subfunctions need to reference the read-only value from the
+    // parent function, this is done by reloading them locally.
+    if ((New = BBMap.lookup(Old)))
+      break;
+
+    New = Old;
+    break;
+
+  case VirtualUse::Synthesizable:
+    // Used by:
+    // * Isl/CodeGen/OpenMP/loop-body-references-outer-values-3.ll
+    // * Isl/CodeGen/OpenMP/recomputed-srem.ll
+    // * Isl/CodeGen/OpenMP/reference-other-bb.ll
+    // * Isl/CodeGen/OpenMP/two-parallel-loops-reference-outer-indvar.ll
+    // For some reason synthesizable values end up in GlobalMap. Their values
+    // are the same as trySynthesizeNewValue would return. The legacy
+    // implementation prioritized GlobalMap, so this is what we do here as well.
+    // Ideally, synthesizable values should not end up in GlobalMap.
+    if ((New = lookupGlobally(Old)))
+      break;
+
+    // Required for:
+    // * Isl/CodeGen/RuntimeDebugBuilder/combine_different_values.ll
+    // * Isl/CodeGen/getNumberOfIterations.ll
+    // * Isl/CodeGen/non_affine_float_compare.ll
+    // * ScheduleOptimizer/pattern-matching-based-opts_10.ll
+    // Ideally, synthesizable values are synthesized by trySynthesizeNewValue,
+    // not precomputed (SCEVExpander has its own caching mechanism).
+    // These tests fail without this, but I think trySynthesizeNewValue would
+    // just re-synthesize the same instructions.
+    if ((New = BBMap.lookup(Old)))
+      break;
+
+    New = trySynthesizeNewValue(Stmt, Old, BBMap, LTS, L);
+    break;
+
+  case VirtualUse::Hoisted:
+    // TODO: Hoisted invariant loads should be found in GlobalMap only, but not
+    // redefined locally (which will be ignored anyway). That is, the following
+    // assertion should apply: assert(!BBMap.count(Old))
+
+    New = lookupGlobally(Old);
+    break;
+
+  case VirtualUse::Intra:
+  case VirtualUse::Inter:
+    assert(!GlobalMap.count(Old) &&
+           "Intra and inter-stmt values are never global");
+    New = BBMap.lookup(Old);
+    break;
+  }
+  assert(New && "Unexpected scalar dependence in region!");
+  return New;
+}
+
+void BlockGenerator::copyInstScalar(ScopStmt &Stmt, Instruction *Inst,
+                                    ValueMapT &BBMap, LoopToScevMapT &LTS) {
+  // We do not generate debug intrinsics as we did not investigate how to
+  // copy them correctly. At the current state, they just crash the code
+  // generation as the meta-data operands are not correctly copied.
+  if (isa<DbgInfoIntrinsic>(Inst))
+    return;
+
+  Instruction *NewInst = Inst->clone();
+
+  // Replace old operands with the new ones.
+  for (Value *OldOperand : Inst->operands()) {
+    Value *NewOperand =
+        getNewValue(Stmt, OldOperand, BBMap, LTS, getLoopForStmt(Stmt));
+
+    if (!NewOperand) {
+      assert(!isa<StoreInst>(NewInst) &&
+             "Store instructions are always needed!");
+      NewInst->deleteValue();
+      return;
+    }
+
+    NewInst->replaceUsesOfWith(OldOperand, NewOperand);
+  }
+
+  Builder.Insert(NewInst);
+  BBMap[Inst] = NewInst;
+
+  // When copying the instruction onto the Module meant for the GPU,
+  // debug metadata attached to an instruction causes all related
+  // metadata to be pulled into the Module. This includes the DICompileUnit,
+  // which will not be listed in llvm.dbg.cu of the Module since the Module
+  // doesn't contain one. This fails the verification of the Module and the
+  // subsequent generation of the ASM string.
+  if (NewInst->getModule() != Inst->getModule())
+    NewInst->setDebugLoc(llvm::DebugLoc());
+
+  if (!NewInst->getType()->isVoidTy())
+    NewInst->setName("p_" + Inst->getName());
+}
+
+Value *
+BlockGenerator::generateLocationAccessed(ScopStmt &Stmt, MemAccInst Inst,
+                                         ValueMapT &BBMap, LoopToScevMapT &LTS,
+                                         isl_id_to_ast_expr *NewAccesses) {
+  const MemoryAccess &MA = Stmt.getArrayAccessFor(Inst);
+  return generateLocationAccessed(
+      Stmt, getLoopForStmt(Stmt),
+      Inst.isNull() ? nullptr : Inst.getPointerOperand(), BBMap, LTS,
+      NewAccesses, MA.getId().release(), MA.getAccessValue()->getType());
+}
+
+Value *BlockGenerator::generateLocationAccessed(
+    ScopStmt &Stmt, Loop *L, Value *Pointer, ValueMapT &BBMap,
+    LoopToScevMapT &LTS, isl_id_to_ast_expr *NewAccesses, __isl_take isl_id *Id,
+    Type *ExpectedType) {
+  isl_ast_expr *AccessExpr = isl_id_to_ast_expr_get(NewAccesses, Id);
+
+  if (AccessExpr) {
+    AccessExpr = isl_ast_expr_address_of(AccessExpr);
+    auto Address = ExprBuilder->create(AccessExpr);
+
+    // Cast the address of this memory access to a pointer type that has the
+    // same element type as the original access, but uses the address space of
+    // the newly generated pointer.
+    auto OldPtrTy = ExpectedType->getPointerTo();
+    auto NewPtrTy = Address->getType();
+    OldPtrTy = PointerType::get(OldPtrTy->getElementType(),
+                                NewPtrTy->getPointerAddressSpace());
+
+    if (OldPtrTy != NewPtrTy)
+      Address = Builder.CreateBitOrPointerCast(Address, OldPtrTy);
+    return Address;
+  }
+  assert(
+      Pointer &&
+      "If expression was not generated, must use the original pointer value");
+  return getNewValue(Stmt, Pointer, BBMap, LTS, L);
+}
+
+Value *
+BlockGenerator::getImplicitAddress(MemoryAccess &Access, Loop *L,
+                                   LoopToScevMapT &LTS, ValueMapT &BBMap,
+                                   __isl_keep isl_id_to_ast_expr *NewAccesses) {
+  if (Access.isLatestArrayKind())
+    return generateLocationAccessed(*Access.getStatement(), L, nullptr, BBMap,
+                                    LTS, NewAccesses, Access.getId().release(),
+                                    Access.getAccessValue()->getType());
+
+  return getOrCreateAlloca(Access);
+}
+
+Loop *BlockGenerator::getLoopForStmt(const ScopStmt &Stmt) const {
+  auto *StmtBB = Stmt.getEntryBlock();
+  return LI.getLoopFor(StmtBB);
+}
+
+Value *BlockGenerator::generateArrayLoad(ScopStmt &Stmt, LoadInst *Load,
+                                         ValueMapT &BBMap, LoopToScevMapT &LTS,
+                                         isl_id_to_ast_expr *NewAccesses) {
+  if (Value *PreloadLoad = GlobalMap.lookup(Load))
+    return PreloadLoad;
+
+  Value *NewPointer =
+      generateLocationAccessed(Stmt, Load, BBMap, LTS, NewAccesses);
+  Value *ScalarLoad = Builder.CreateAlignedLoad(
+      NewPointer, Load->getAlignment(), Load->getName() + "_p_scalar_");
+
+  if (PollyDebugPrinting)
+    RuntimeDebugBuilder::createCPUPrinter(Builder, "Load from ", NewPointer,
+                                          ": ", ScalarLoad, "\n");
+
+  return ScalarLoad;
+}
+
+void BlockGenerator::generateArrayStore(ScopStmt &Stmt, StoreInst *Store,
+                                        ValueMapT &BBMap, LoopToScevMapT &LTS,
+                                        isl_id_to_ast_expr *NewAccesses) {
+  MemoryAccess &MA = Stmt.getArrayAccessFor(Store);
+  isl::set AccDom = MA.getAccessRelation().domain();
+  std::string Subject = MA.getId().get_name();
+
+  generateConditionalExecution(Stmt, AccDom, Subject.c_str(), [&, this]() {
+    Value *NewPointer =
+        generateLocationAccessed(Stmt, Store, BBMap, LTS, NewAccesses);
+    Value *ValueOperand = getNewValue(Stmt, Store->getValueOperand(), BBMap,
+                                      LTS, getLoopForStmt(Stmt));
+
+    if (PollyDebugPrinting)
+      RuntimeDebugBuilder::createCPUPrinter(Builder, "Store to  ", NewPointer,
+                                            ": ", ValueOperand, "\n");
+
+    Builder.CreateAlignedStore(ValueOperand, NewPointer, Store->getAlignment());
+  });
+}
+
+bool BlockGenerator::canSyntheziseInStmt(ScopStmt &Stmt, Instruction *Inst) {
+  Loop *L = getLoopForStmt(Stmt);
+  return (Stmt.isBlockStmt() || !Stmt.getRegion()->contains(L)) &&
+         canSynthesize(Inst, *Stmt.getParent(), &SE, L);
+}
+
+void BlockGenerator::copyInstruction(ScopStmt &Stmt, Instruction *Inst,
+                                     ValueMapT &BBMap, LoopToScevMapT &LTS,
+                                     isl_id_to_ast_expr *NewAccesses) {
+  // Terminator instructions control the control flow. They are explicitly
+  // expressed in the clast and do not need to be copied.
+  if (Inst->isTerminator())
+    return;
+
+  // Synthesizable statements will be generated on-demand.
+  if (canSyntheziseInStmt(Stmt, Inst))
+    return;
+
+  if (auto *Load = dyn_cast<LoadInst>(Inst)) {
+    Value *NewLoad = generateArrayLoad(Stmt, Load, BBMap, LTS, NewAccesses);
+    // Compute NewLoad before its insertion in BBMap to make the insertion
+    // deterministic.
+    BBMap[Load] = NewLoad;
+    return;
+  }
+
+  if (auto *Store = dyn_cast<StoreInst>(Inst)) {
+    // Identified as redundant by -polly-simplify.
+    if (!Stmt.getArrayAccessOrNULLFor(Store))
+      return;
+
+    generateArrayStore(Stmt, Store, BBMap, LTS, NewAccesses);
+    return;
+  }
+
+  if (auto *PHI = dyn_cast<PHINode>(Inst)) {
+    copyPHIInstruction(Stmt, PHI, BBMap, LTS);
+    return;
+  }
+
+  // Skip some special intrinsics for which we do not adjust the semantics to
+  // the new schedule. All others are handled like every other instruction.
+  if (isIgnoredIntrinsic(Inst))
+    return;
+
+  copyInstScalar(Stmt, Inst, BBMap, LTS);
+}
+
+void BlockGenerator::removeDeadInstructions(BasicBlock *BB, ValueMapT &BBMap) {
+  auto NewBB = Builder.GetInsertBlock();
+  for (auto I = NewBB->rbegin(); I != NewBB->rend(); I++) {
+    Instruction *NewInst = &*I;
+
+    if (!isInstructionTriviallyDead(NewInst))
+      continue;
+
+    for (auto Pair : BBMap)
+      if (Pair.second == NewInst) {
+        BBMap.erase(Pair.first);
+      }
+
+    NewInst->eraseFromParent();
+    I = NewBB->rbegin();
+  }
+}
+
+void BlockGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
+                              isl_id_to_ast_expr *NewAccesses) {
+  assert(Stmt.isBlockStmt() &&
+         "Only block statements can be copied by the block generator");
+
+  ValueMapT BBMap;
+
+  BasicBlock *BB = Stmt.getBasicBlock();
+  copyBB(Stmt, BB, BBMap, LTS, NewAccesses);
+  removeDeadInstructions(BB, BBMap);
+}
+
+BasicBlock *BlockGenerator::splitBB(BasicBlock *BB) {
+  BasicBlock *CopyBB = SplitBlock(Builder.GetInsertBlock(),
+                                  &*Builder.GetInsertPoint(), &DT, &LI);
+  CopyBB->setName("polly.stmt." + BB->getName());
+  return CopyBB;
+}
+
+BasicBlock *BlockGenerator::copyBB(ScopStmt &Stmt, BasicBlock *BB,
+                                   ValueMapT &BBMap, LoopToScevMapT &LTS,
+                                   isl_id_to_ast_expr *NewAccesses) {
+  BasicBlock *CopyBB = splitBB(BB);
+  Builder.SetInsertPoint(&CopyBB->front());
+  generateScalarLoads(Stmt, LTS, BBMap, NewAccesses);
+
+  copyBB(Stmt, BB, CopyBB, BBMap, LTS, NewAccesses);
+
+  // After a basic block was copied store all scalars that escape this block in
+  // their alloca.
+  generateScalarStores(Stmt, LTS, BBMap, NewAccesses);
+  return CopyBB;
+}
+
+void BlockGenerator::copyBB(ScopStmt &Stmt, BasicBlock *BB, BasicBlock *CopyBB,
+                            ValueMapT &BBMap, LoopToScevMapT &LTS,
+                            isl_id_to_ast_expr *NewAccesses) {
+  EntryBB = &CopyBB->getParent()->getEntryBlock();
+
+  // Block statements and the entry blocks of region statement are code
+  // generated from instruction lists. This allow us to optimize the
+  // instructions that belong to a certain scop statement. As the code
+  // structure of region statements might be arbitrary complex, optimizing the
+  // instruction list is not yet supported.
+  if (Stmt.isBlockStmt() || (Stmt.isRegionStmt() && Stmt.getEntryBlock() == BB))
+    for (Instruction *Inst : Stmt.getInstructions())
+      copyInstruction(Stmt, Inst, BBMap, LTS, NewAccesses);
+  else
+    for (Instruction &Inst : *BB)
+      copyInstruction(Stmt, &Inst, BBMap, LTS, NewAccesses);
+}
+
+Value *BlockGenerator::getOrCreateAlloca(const MemoryAccess &Access) {
+  assert(!Access.isLatestArrayKind() && "Trying to get alloca for array kind");
+
+  return getOrCreateAlloca(Access.getLatestScopArrayInfo());
+}
+
+Value *BlockGenerator::getOrCreateAlloca(const ScopArrayInfo *Array) {
+  assert(!Array->isArrayKind() && "Trying to get alloca for array kind");
+
+  auto &Addr = ScalarMap[Array];
+
+  if (Addr) {
+    // Allow allocas to be (temporarily) redirected once by adding a new
+    // old-alloca-addr to new-addr mapping to GlobalMap. This functionality
+    // is used for example by the OpenMP code generation where a first use
+    // of a scalar while still in the host code allocates a normal alloca with
+    // getOrCreateAlloca. When the values of this scalar are accessed during
+    // the generation of the parallel subfunction, these values are copied over
+    // to the parallel subfunction and each request for a scalar alloca slot
+    // must be forwarded to the temporary in-subfunction slot. This mapping is
+    // removed when the subfunction has been generated and again normal host
+    // code is generated. Due to the following reasons it is not possible to
+    // perform the GlobalMap lookup right after creating the alloca below, but
+    // instead we need to check GlobalMap at each call to getOrCreateAlloca:
+    //
+    //   1) GlobalMap may be changed multiple times (for each parallel loop),
+    //   2) The temporary mapping is commonly only known after the initial
+    //      alloca has already been generated, and
+    //   3) The original alloca value must be restored after leaving the
+    //      sub-function.
+    if (Value *NewAddr = GlobalMap.lookup(&*Addr))
+      return NewAddr;
+    return Addr;
+  }
+
+  Type *Ty = Array->getElementType();
+  Value *ScalarBase = Array->getBasePtr();
+  std::string NameExt;
+  if (Array->isPHIKind())
+    NameExt = ".phiops";
+  else
+    NameExt = ".s2a";
+
+  const DataLayout &DL = Builder.GetInsertBlock()->getModule()->getDataLayout();
+
+  Addr = new AllocaInst(Ty, DL.getAllocaAddrSpace(),
+                        ScalarBase->getName() + NameExt);
+  EntryBB = &Builder.GetInsertBlock()->getParent()->getEntryBlock();
+  Addr->insertBefore(&*EntryBB->getFirstInsertionPt());
+
+  return Addr;
+}
+
+void BlockGenerator::handleOutsideUsers(const Scop &S, ScopArrayInfo *Array) {
+  Instruction *Inst = cast<Instruction>(Array->getBasePtr());
+
+  // If there are escape users we get the alloca for this instruction and put it
+  // in the EscapeMap for later finalization. Lastly, if the instruction was
+  // copied multiple times we already did this and can exit.
+  if (EscapeMap.count(Inst))
+    return;
+
+  EscapeUserVectorTy EscapeUsers;
+  for (User *U : Inst->users()) {
+
+    // Non-instruction user will never escape.
+    Instruction *UI = dyn_cast<Instruction>(U);
+    if (!UI)
+      continue;
+
+    if (S.contains(UI))
+      continue;
+
+    EscapeUsers.push_back(UI);
+  }
+
+  // Exit if no escape uses were found.
+  if (EscapeUsers.empty())
+    return;
+
+  // Get or create an escape alloca for this instruction.
+  auto *ScalarAddr = getOrCreateAlloca(Array);
+
+  // Remember that this instruction has escape uses and the escape alloca.
+  EscapeMap[Inst] = std::make_pair(ScalarAddr, std::move(EscapeUsers));
+}
+
+void BlockGenerator::generateScalarLoads(
+    ScopStmt &Stmt, LoopToScevMapT &LTS, ValueMapT &BBMap,
+    __isl_keep isl_id_to_ast_expr *NewAccesses) {
+  for (MemoryAccess *MA : Stmt) {
+    if (MA->isOriginalArrayKind() || MA->isWrite())
+      continue;
+
+#ifndef NDEBUG
+    auto *StmtDom = Stmt.getDomain().release();
+    auto *AccDom = isl_map_domain(MA->getAccessRelation().release());
+    assert(isl_set_is_subset(StmtDom, AccDom) &&
+           "Scalar must be loaded in all statement instances");
+    isl_set_free(StmtDom);
+    isl_set_free(AccDom);
+#endif
+
+    auto *Address =
+        getImplicitAddress(*MA, getLoopForStmt(Stmt), LTS, BBMap, NewAccesses);
+    assert((!isa<Instruction>(Address) ||
+            DT.dominates(cast<Instruction>(Address)->getParent(),
+                         Builder.GetInsertBlock())) &&
+           "Domination violation");
+    BBMap[MA->getAccessValue()] =
+        Builder.CreateLoad(Address, Address->getName() + ".reload");
+  }
+}
+
+Value *BlockGenerator::buildContainsCondition(ScopStmt &Stmt,
+                                              const isl::set &Subdomain) {
+  isl::ast_build AstBuild = Stmt.getAstBuild();
+  isl::set Domain = Stmt.getDomain();
+
+  isl::union_map USchedule = AstBuild.get_schedule();
+  USchedule = USchedule.intersect_domain(Domain);
+
+  assert(!USchedule.is_empty());
+  isl::map Schedule = isl::map::from_union_map(USchedule);
+
+  isl::set ScheduledDomain = Schedule.range();
+  isl::set ScheduledSet = Subdomain.apply(Schedule);
+
+  isl::ast_build RestrictedBuild = AstBuild.restrict(ScheduledDomain);
+
+  isl::ast_expr IsInSet = RestrictedBuild.expr_from(ScheduledSet);
+  Value *IsInSetExpr = ExprBuilder->create(IsInSet.copy());
+  IsInSetExpr = Builder.CreateICmpNE(
+      IsInSetExpr, ConstantInt::get(IsInSetExpr->getType(), 0));
+
+  return IsInSetExpr;
+}
+
+void BlockGenerator::generateConditionalExecution(
+    ScopStmt &Stmt, const isl::set &Subdomain, StringRef Subject,
+    const std::function<void()> &GenThenFunc) {
+  isl::set StmtDom = Stmt.getDomain();
+
+  // If the condition is a tautology, don't generate a condition around the
+  // code.
+  bool IsPartialWrite =
+      !StmtDom.intersect_params(Stmt.getParent()->getContext())
+           .is_subset(Subdomain);
+  if (!IsPartialWrite) {
+    GenThenFunc();
+    return;
+  }
+
+  // Generate the condition.
+  Value *Cond = buildContainsCondition(Stmt, Subdomain);
+
+  // Don't call GenThenFunc if it is never executed. An ast index expression
+  // might not be defined in this case.
+  if (auto *Const = dyn_cast<ConstantInt>(Cond))
+    if (Const->isZero())
+      return;
+
+  BasicBlock *HeadBlock = Builder.GetInsertBlock();
+  StringRef BlockName = HeadBlock->getName();
+
+  // Generate the conditional block.
+  SplitBlockAndInsertIfThen(Cond, &*Builder.GetInsertPoint(), false, nullptr,
+                            &DT, &LI);
+  BranchInst *Branch = cast<BranchInst>(HeadBlock->getTerminator());
+  BasicBlock *ThenBlock = Branch->getSuccessor(0);
+  BasicBlock *TailBlock = Branch->getSuccessor(1);
+
+  // Assign descriptive names.
+  if (auto *CondInst = dyn_cast<Instruction>(Cond))
+    CondInst->setName("polly." + Subject + ".cond");
+  ThenBlock->setName(BlockName + "." + Subject + ".partial");
+  TailBlock->setName(BlockName + ".cont");
+
+  // Put the client code into the conditional block and continue in the merge
+  // block afterwards.
+  Builder.SetInsertPoint(ThenBlock, ThenBlock->getFirstInsertionPt());
+  GenThenFunc();
+  Builder.SetInsertPoint(TailBlock, TailBlock->getFirstInsertionPt());
+}
+
+void BlockGenerator::generateScalarStores(
+    ScopStmt &Stmt, LoopToScevMapT &LTS, ValueMapT &BBMap,
+    __isl_keep isl_id_to_ast_expr *NewAccesses) {
+  Loop *L = LI.getLoopFor(Stmt.getBasicBlock());
+
+  assert(Stmt.isBlockStmt() &&
+         "Region statements need to use the generateScalarStores() function in "
+         "the RegionGenerator");
+
+  for (MemoryAccess *MA : Stmt) {
+    if (MA->isOriginalArrayKind() || MA->isRead())
+      continue;
+
+    isl::set AccDom = MA->getAccessRelation().domain();
+    std::string Subject = MA->getId().get_name();
+
+    generateConditionalExecution(
+        Stmt, AccDom, Subject.c_str(), [&, this, MA]() {
+          Value *Val = MA->getAccessValue();
+          if (MA->isAnyPHIKind()) {
+            assert(MA->getIncoming().size() >= 1 &&
+                   "Block statements have exactly one exiting block, or "
+                   "multiple but "
+                   "with same incoming block and value");
+            assert(std::all_of(MA->getIncoming().begin(),
+                               MA->getIncoming().end(),
+                               [&](std::pair<BasicBlock *, Value *> p) -> bool {
+                                 return p.first == Stmt.getBasicBlock();
+                               }) &&
+                   "Incoming block must be statement's block");
+            Val = MA->getIncoming()[0].second;
+          }
+          auto Address = getImplicitAddress(*MA, getLoopForStmt(Stmt), LTS,
+                                            BBMap, NewAccesses);
+
+          Val = getNewValue(Stmt, Val, BBMap, LTS, L);
+          assert((!isa<Instruction>(Val) ||
+                  DT.dominates(cast<Instruction>(Val)->getParent(),
+                               Builder.GetInsertBlock())) &&
+                 "Domination violation");
+          assert((!isa<Instruction>(Address) ||
+                  DT.dominates(cast<Instruction>(Address)->getParent(),
+                               Builder.GetInsertBlock())) &&
+                 "Domination violation");
+
+          // The new Val might have a different type than the old Val due to
+          // ScalarEvolution looking through bitcasts.
+          if (Val->getType() != Address->getType()->getPointerElementType())
+            Address = Builder.CreateBitOrPointerCast(
+                Address, Val->getType()->getPointerTo());
+
+          Builder.CreateStore(Val, Address);
+        });
+  }
+}
+
+void BlockGenerator::createScalarInitialization(Scop &S) {
+  BasicBlock *ExitBB = S.getExit();
+  BasicBlock *PreEntryBB = S.getEnteringBlock();
+
+  Builder.SetInsertPoint(&*StartBlock->begin());
+
+  for (auto &Array : S.arrays()) {
+    if (Array->getNumberOfDimensions() != 0)
+      continue;
+    if (Array->isPHIKind()) {
+      // For PHI nodes, the only values we need to store are the ones that
+      // reach the PHI node from outside the region. In general there should
+      // only be one such incoming edge and this edge should enter through
+      // 'PreEntryBB'.
+      auto PHI = cast<PHINode>(Array->getBasePtr());
+
+      for (auto BI = PHI->block_begin(), BE = PHI->block_end(); BI != BE; BI++)
+        if (!S.contains(*BI) && *BI != PreEntryBB)
+          llvm_unreachable("Incoming edges from outside the scop should always "
+                           "come from PreEntryBB");
+
+      int Idx = PHI->getBasicBlockIndex(PreEntryBB);
+      if (Idx < 0)
+        continue;
+
+      Value *ScalarValue = PHI->getIncomingValue(Idx);
+
+      Builder.CreateStore(ScalarValue, getOrCreateAlloca(Array));
+      continue;
+    }
+
+    auto *Inst = dyn_cast<Instruction>(Array->getBasePtr());
+
+    if (Inst && S.contains(Inst))
+      continue;
+
+    // PHI nodes that are not marked as such in their SAI object are either exit
+    // PHI nodes we model as common scalars but without initialization, or
+    // incoming phi nodes that need to be initialized. Check if the first is the
+    // case for Inst and do not create and initialize memory if so.
+    if (auto *PHI = dyn_cast_or_null<PHINode>(Inst))
+      if (!S.hasSingleExitEdge() && PHI->getBasicBlockIndex(ExitBB) >= 0)
+        continue;
+
+    Builder.CreateStore(Array->getBasePtr(), getOrCreateAlloca(Array));
+  }
+}
+
+void BlockGenerator::createScalarFinalization(Scop &S) {
+  // The exit block of the __unoptimized__ region.
+  BasicBlock *ExitBB = S.getExitingBlock();
+  // The merge block __just after__ the region and the optimized region.
+  BasicBlock *MergeBB = S.getExit();
+
+  // The exit block of the __optimized__ region.
+  BasicBlock *OptExitBB = *(pred_begin(MergeBB));
+  if (OptExitBB == ExitBB)
+    OptExitBB = *(++pred_begin(MergeBB));
+
+  Builder.SetInsertPoint(OptExitBB->getTerminator());
+  for (const auto &EscapeMapping : EscapeMap) {
+    // Extract the escaping instruction and the escaping users as well as the
+    // alloca the instruction was demoted to.
+    Instruction *EscapeInst = EscapeMapping.first;
+    const auto &EscapeMappingValue = EscapeMapping.second;
+    const EscapeUserVectorTy &EscapeUsers = EscapeMappingValue.second;
+    Value *ScalarAddr = EscapeMappingValue.first;
+
+    // Reload the demoted instruction in the optimized version of the SCoP.
+    Value *EscapeInstReload =
+        Builder.CreateLoad(ScalarAddr, EscapeInst->getName() + ".final_reload");
+    EscapeInstReload =
+        Builder.CreateBitOrPointerCast(EscapeInstReload, EscapeInst->getType());
+
+    // Create the merge PHI that merges the optimized and unoptimized version.
+    PHINode *MergePHI = PHINode::Create(EscapeInst->getType(), 2,
+                                        EscapeInst->getName() + ".merge");
+    MergePHI->insertBefore(&*MergeBB->getFirstInsertionPt());
+
+    // Add the respective values to the merge PHI.
+    MergePHI->addIncoming(EscapeInstReload, OptExitBB);
+    MergePHI->addIncoming(EscapeInst, ExitBB);
+
+    // The information of scalar evolution about the escaping instruction needs
+    // to be revoked so the new merged instruction will be used.
+    if (SE.isSCEVable(EscapeInst->getType()))
+      SE.forgetValue(EscapeInst);
+
+    // Replace all uses of the demoted instruction with the merge PHI.
+    for (Instruction *EUser : EscapeUsers)
+      EUser->replaceUsesOfWith(EscapeInst, MergePHI);
+  }
+}
+
+void BlockGenerator::findOutsideUsers(Scop &S) {
+  for (auto &Array : S.arrays()) {
+
+    if (Array->getNumberOfDimensions() != 0)
+      continue;
+
+    if (Array->isPHIKind())
+      continue;
+
+    auto *Inst = dyn_cast<Instruction>(Array->getBasePtr());
+
+    if (!Inst)
+      continue;
+
+    // Scop invariant hoisting moves some of the base pointers out of the scop.
+    // We can ignore these, as the invariant load hoisting already registers the
+    // relevant outside users.
+    if (!S.contains(Inst))
+      continue;
+
+    handleOutsideUsers(S, Array);
+  }
+}
+
+void BlockGenerator::createExitPHINodeMerges(Scop &S) {
+  if (S.hasSingleExitEdge())
+    return;
+
+  auto *ExitBB = S.getExitingBlock();
+  auto *MergeBB = S.getExit();
+  auto *AfterMergeBB = MergeBB->getSingleSuccessor();
+  BasicBlock *OptExitBB = *(pred_begin(MergeBB));
+  if (OptExitBB == ExitBB)
+    OptExitBB = *(++pred_begin(MergeBB));
+
+  Builder.SetInsertPoint(OptExitBB->getTerminator());
+
+  for (auto &SAI : S.arrays()) {
+    auto *Val = SAI->getBasePtr();
+
+    // Only Value-like scalars need a merge PHI. Exit block PHIs receive either
+    // the original PHI's value or the reloaded incoming values from the
+    // generated code. An llvm::Value is merged between the original code's
+    // value or the generated one.
+    if (!SAI->isExitPHIKind())
+      continue;
+
+    PHINode *PHI = dyn_cast<PHINode>(Val);
+    if (!PHI)
+      continue;
+
+    if (PHI->getParent() != AfterMergeBB)
+      continue;
+
+    std::string Name = PHI->getName();
+    Value *ScalarAddr = getOrCreateAlloca(SAI);
+    Value *Reload = Builder.CreateLoad(ScalarAddr, Name + ".ph.final_reload");
+    Reload = Builder.CreateBitOrPointerCast(Reload, PHI->getType());
+    Value *OriginalValue = PHI->getIncomingValueForBlock(MergeBB);
+    assert((!isa<Instruction>(OriginalValue) ||
+            cast<Instruction>(OriginalValue)->getParent() != MergeBB) &&
+           "Original value must no be one we just generated.");
+    auto *MergePHI = PHINode::Create(PHI->getType(), 2, Name + ".ph.merge");
+    MergePHI->insertBefore(&*MergeBB->getFirstInsertionPt());
+    MergePHI->addIncoming(Reload, OptExitBB);
+    MergePHI->addIncoming(OriginalValue, ExitBB);
+    int Idx = PHI->getBasicBlockIndex(MergeBB);
+    PHI->setIncomingValue(Idx, MergePHI);
+  }
+}
+
+void BlockGenerator::invalidateScalarEvolution(Scop &S) {
+  for (auto &Stmt : S)
+    if (Stmt.isCopyStmt())
+      continue;
+    else if (Stmt.isBlockStmt())
+      for (auto &Inst : *Stmt.getBasicBlock())
+        SE.forgetValue(&Inst);
+    else if (Stmt.isRegionStmt())
+      for (auto *BB : Stmt.getRegion()->blocks())
+        for (auto &Inst : *BB)
+          SE.forgetValue(&Inst);
+    else
+      llvm_unreachable("Unexpected statement type found");
+
+  // Invalidate SCEV of loops surrounding the EscapeUsers.
+  for (const auto &EscapeMapping : EscapeMap) {
+    const EscapeUserVectorTy &EscapeUsers = EscapeMapping.second.second;
+    for (Instruction *EUser : EscapeUsers) {
+      if (Loop *L = LI.getLoopFor(EUser->getParent()))
+        while (L) {
+          SE.forgetLoop(L);
+          L = L->getParentLoop();
+        }
+    }
+  }
+}
+
+void BlockGenerator::finalizeSCoP(Scop &S) {
+  findOutsideUsers(S);
+  createScalarInitialization(S);
+  createExitPHINodeMerges(S);
+  createScalarFinalization(S);
+  invalidateScalarEvolution(S);
+}
+
+VectorBlockGenerator::VectorBlockGenerator(BlockGenerator &BlockGen,
+                                           std::vector<LoopToScevMapT> &VLTS,
+                                           isl_map *Schedule)
+    : BlockGenerator(BlockGen), VLTS(VLTS), Schedule(Schedule) {
+  assert(Schedule && "No statement domain provided");
+}
+
+Value *VectorBlockGenerator::getVectorValue(ScopStmt &Stmt, Value *Old,
+                                            ValueMapT &VectorMap,
+                                            VectorValueMapT &ScalarMaps,
+                                            Loop *L) {
+  if (Value *NewValue = VectorMap.lookup(Old))
+    return NewValue;
+
+  int Width = getVectorWidth();
+
+  Value *Vector = UndefValue::get(VectorType::get(Old->getType(), Width));
+
+  for (int Lane = 0; Lane < Width; Lane++)
+    Vector = Builder.CreateInsertElement(
+        Vector, getNewValue(Stmt, Old, ScalarMaps[Lane], VLTS[Lane], L),
+        Builder.getInt32(Lane));
+
+  VectorMap[Old] = Vector;
+
+  return Vector;
+}
+
+Type *VectorBlockGenerator::getVectorPtrTy(const Value *Val, int Width) {
+  PointerType *PointerTy = dyn_cast<PointerType>(Val->getType());
+  assert(PointerTy && "PointerType expected");
+
+  Type *ScalarType = PointerTy->getElementType();
+  VectorType *VectorType = VectorType::get(ScalarType, Width);
+
+  return PointerType::getUnqual(VectorType);
+}
+
+Value *VectorBlockGenerator::generateStrideOneLoad(
+    ScopStmt &Stmt, LoadInst *Load, VectorValueMapT &ScalarMaps,
+    __isl_keep isl_id_to_ast_expr *NewAccesses, bool NegativeStride = false) {
+  unsigned VectorWidth = getVectorWidth();
+  auto *Pointer = Load->getPointerOperand();
+  Type *VectorPtrType = getVectorPtrTy(Pointer, VectorWidth);
+  unsigned Offset = NegativeStride ? VectorWidth - 1 : 0;
+
+  Value *NewPointer = generateLocationAccessed(Stmt, Load, ScalarMaps[Offset],
+                                               VLTS[Offset], NewAccesses);
+  Value *VectorPtr =
+      Builder.CreateBitCast(NewPointer, VectorPtrType, "vector_ptr");
+  LoadInst *VecLoad =
+      Builder.CreateLoad(VectorPtr, Load->getName() + "_p_vec_full");
+  if (!Aligned)
+    VecLoad->setAlignment(8);
+
+  if (NegativeStride) {
+    SmallVector<Constant *, 16> Indices;
+    for (int i = VectorWidth - 1; i >= 0; i--)
+      Indices.push_back(ConstantInt::get(Builder.getInt32Ty(), i));
+    Constant *SV = llvm::ConstantVector::get(Indices);
+    Value *RevVecLoad = Builder.CreateShuffleVector(
+        VecLoad, VecLoad, SV, Load->getName() + "_reverse");
+    return RevVecLoad;
+  }
+
+  return VecLoad;
+}
+
+Value *VectorBlockGenerator::generateStrideZeroLoad(
+    ScopStmt &Stmt, LoadInst *Load, ValueMapT &BBMap,
+    __isl_keep isl_id_to_ast_expr *NewAccesses) {
+  auto *Pointer = Load->getPointerOperand();
+  Type *VectorPtrType = getVectorPtrTy(Pointer, 1);
+  Value *NewPointer =
+      generateLocationAccessed(Stmt, Load, BBMap, VLTS[0], NewAccesses);
+  Value *VectorPtr = Builder.CreateBitCast(NewPointer, VectorPtrType,
+                                           Load->getName() + "_p_vec_p");
+  LoadInst *ScalarLoad =
+      Builder.CreateLoad(VectorPtr, Load->getName() + "_p_splat_one");
+
+  if (!Aligned)
+    ScalarLoad->setAlignment(8);
+
+  Constant *SplatVector = Constant::getNullValue(
+      VectorType::get(Builder.getInt32Ty(), getVectorWidth()));
+
+  Value *VectorLoad = Builder.CreateShuffleVector(
+      ScalarLoad, ScalarLoad, SplatVector, Load->getName() + "_p_splat");
+  return VectorLoad;
+}
+
+Value *VectorBlockGenerator::generateUnknownStrideLoad(
+    ScopStmt &Stmt, LoadInst *Load, VectorValueMapT &ScalarMaps,
+    __isl_keep isl_id_to_ast_expr *NewAccesses) {
+  int VectorWidth = getVectorWidth();
+  auto *Pointer = Load->getPointerOperand();
+  VectorType *VectorType = VectorType::get(
+      dyn_cast<PointerType>(Pointer->getType())->getElementType(), VectorWidth);
+
+  Value *Vector = UndefValue::get(VectorType);
+
+  for (int i = 0; i < VectorWidth; i++) {
+    Value *NewPointer = generateLocationAccessed(Stmt, Load, ScalarMaps[i],
+                                                 VLTS[i], NewAccesses);
+    Value *ScalarLoad =
+        Builder.CreateLoad(NewPointer, Load->getName() + "_p_scalar_");
+    Vector = Builder.CreateInsertElement(
+        Vector, ScalarLoad, Builder.getInt32(i), Load->getName() + "_p_vec_");
+  }
+
+  return Vector;
+}
+
+void VectorBlockGenerator::generateLoad(
+    ScopStmt &Stmt, LoadInst *Load, ValueMapT &VectorMap,
+    VectorValueMapT &ScalarMaps, __isl_keep isl_id_to_ast_expr *NewAccesses) {
+  if (Value *PreloadLoad = GlobalMap.lookup(Load)) {
+    VectorMap[Load] = Builder.CreateVectorSplat(getVectorWidth(), PreloadLoad,
+                                                Load->getName() + "_p");
+    return;
+  }
+
+  if (!VectorType::isValidElementType(Load->getType())) {
+    for (int i = 0; i < getVectorWidth(); i++)
+      ScalarMaps[i][Load] =
+          generateArrayLoad(Stmt, Load, ScalarMaps[i], VLTS[i], NewAccesses);
+    return;
+  }
+
+  const MemoryAccess &Access = Stmt.getArrayAccessFor(Load);
+
+  // Make sure we have scalar values available to access the pointer to
+  // the data location.
+  extractScalarValues(Load, VectorMap, ScalarMaps);
+
+  Value *NewLoad;
+  if (Access.isStrideZero(isl::manage(isl_map_copy(Schedule))))
+    NewLoad = generateStrideZeroLoad(Stmt, Load, ScalarMaps[0], NewAccesses);
+  else if (Access.isStrideOne(isl::manage(isl_map_copy(Schedule))))
+    NewLoad = generateStrideOneLoad(Stmt, Load, ScalarMaps, NewAccesses);
+  else if (Access.isStrideX(isl::manage(isl_map_copy(Schedule)), -1))
+    NewLoad = generateStrideOneLoad(Stmt, Load, ScalarMaps, NewAccesses, true);
+  else
+    NewLoad = generateUnknownStrideLoad(Stmt, Load, ScalarMaps, NewAccesses);
+
+  VectorMap[Load] = NewLoad;
+}
+
+void VectorBlockGenerator::copyUnaryInst(ScopStmt &Stmt, UnaryInstruction *Inst,
+                                         ValueMapT &VectorMap,
+                                         VectorValueMapT &ScalarMaps) {
+  int VectorWidth = getVectorWidth();
+  Value *NewOperand = getVectorValue(Stmt, Inst->getOperand(0), VectorMap,
+                                     ScalarMaps, getLoopForStmt(Stmt));
+
+  assert(isa<CastInst>(Inst) && "Can not generate vector code for instruction");
+
+  const CastInst *Cast = dyn_cast<CastInst>(Inst);
+  VectorType *DestType = VectorType::get(Inst->getType(), VectorWidth);
+  VectorMap[Inst] = Builder.CreateCast(Cast->getOpcode(), NewOperand, DestType);
+}
+
+void VectorBlockGenerator::copyBinaryInst(ScopStmt &Stmt, BinaryOperator *Inst,
+                                          ValueMapT &VectorMap,
+                                          VectorValueMapT &ScalarMaps) {
+  Loop *L = getLoopForStmt(Stmt);
+  Value *OpZero = Inst->getOperand(0);
+  Value *OpOne = Inst->getOperand(1);
+
+  Value *NewOpZero, *NewOpOne;
+  NewOpZero = getVectorValue(Stmt, OpZero, VectorMap, ScalarMaps, L);
+  NewOpOne = getVectorValue(Stmt, OpOne, VectorMap, ScalarMaps, L);
+
+  Value *NewInst = Builder.CreateBinOp(Inst->getOpcode(), NewOpZero, NewOpOne,
+                                       Inst->getName() + "p_vec");
+  VectorMap[Inst] = NewInst;
+}
+
+void VectorBlockGenerator::copyStore(
+    ScopStmt &Stmt, StoreInst *Store, ValueMapT &VectorMap,
+    VectorValueMapT &ScalarMaps, __isl_keep isl_id_to_ast_expr *NewAccesses) {
+  const MemoryAccess &Access = Stmt.getArrayAccessFor(Store);
+
+  auto *Pointer = Store->getPointerOperand();
+  Value *Vector = getVectorValue(Stmt, Store->getValueOperand(), VectorMap,
+                                 ScalarMaps, getLoopForStmt(Stmt));
+
+  // Make sure we have scalar values available to access the pointer to
+  // the data location.
+  extractScalarValues(Store, VectorMap, ScalarMaps);
+
+  if (Access.isStrideOne(isl::manage(isl_map_copy(Schedule)))) {
+    Type *VectorPtrType = getVectorPtrTy(Pointer, getVectorWidth());
+    Value *NewPointer = generateLocationAccessed(Stmt, Store, ScalarMaps[0],
+                                                 VLTS[0], NewAccesses);
+
+    Value *VectorPtr =
+        Builder.CreateBitCast(NewPointer, VectorPtrType, "vector_ptr");
+    StoreInst *Store = Builder.CreateStore(Vector, VectorPtr);
+
+    if (!Aligned)
+      Store->setAlignment(8);
+  } else {
+    for (unsigned i = 0; i < ScalarMaps.size(); i++) {
+      Value *Scalar = Builder.CreateExtractElement(Vector, Builder.getInt32(i));
+      Value *NewPointer = generateLocationAccessed(Stmt, Store, ScalarMaps[i],
+                                                   VLTS[i], NewAccesses);
+      Builder.CreateStore(Scalar, NewPointer);
+    }
+  }
+}
+
+bool VectorBlockGenerator::hasVectorOperands(const Instruction *Inst,
+                                             ValueMapT &VectorMap) {
+  for (Value *Operand : Inst->operands())
+    if (VectorMap.count(Operand))
+      return true;
+  return false;
+}
+
+bool VectorBlockGenerator::extractScalarValues(const Instruction *Inst,
+                                               ValueMapT &VectorMap,
+                                               VectorValueMapT &ScalarMaps) {
+  bool HasVectorOperand = false;
+  int VectorWidth = getVectorWidth();
+
+  for (Value *Operand : Inst->operands()) {
+    ValueMapT::iterator VecOp = VectorMap.find(Operand);
+
+    if (VecOp == VectorMap.end())
+      continue;
+
+    HasVectorOperand = true;
+    Value *NewVector = VecOp->second;
+
+    for (int i = 0; i < VectorWidth; ++i) {
+      ValueMapT &SM = ScalarMaps[i];
+
+      // If there is one scalar extracted, all scalar elements should have
+      // already been extracted by the code here. So no need to check for the
+      // existence of all of them.
+      if (SM.count(Operand))
+        break;
+
+      SM[Operand] =
+          Builder.CreateExtractElement(NewVector, Builder.getInt32(i));
+    }
+  }
+
+  return HasVectorOperand;
+}
+
+void VectorBlockGenerator::copyInstScalarized(
+    ScopStmt &Stmt, Instruction *Inst, ValueMapT &VectorMap,
+    VectorValueMapT &ScalarMaps, __isl_keep isl_id_to_ast_expr *NewAccesses) {
+  bool HasVectorOperand;
+  int VectorWidth = getVectorWidth();
+
+  HasVectorOperand = extractScalarValues(Inst, VectorMap, ScalarMaps);
+
+  for (int VectorLane = 0; VectorLane < getVectorWidth(); VectorLane++)
+    BlockGenerator::copyInstruction(Stmt, Inst, ScalarMaps[VectorLane],
+                                    VLTS[VectorLane], NewAccesses);
+
+  if (!VectorType::isValidElementType(Inst->getType()) || !HasVectorOperand)
+    return;
+
+  // Make the result available as vector value.
+  VectorType *VectorType = VectorType::get(Inst->getType(), VectorWidth);
+  Value *Vector = UndefValue::get(VectorType);
+
+  for (int i = 0; i < VectorWidth; i++)
+    Vector = Builder.CreateInsertElement(Vector, ScalarMaps[i][Inst],
+                                         Builder.getInt32(i));
+
+  VectorMap[Inst] = Vector;
+}
+
+int VectorBlockGenerator::getVectorWidth() { return VLTS.size(); }
+
+void VectorBlockGenerator::copyInstruction(
+    ScopStmt &Stmt, Instruction *Inst, ValueMapT &VectorMap,
+    VectorValueMapT &ScalarMaps, __isl_keep isl_id_to_ast_expr *NewAccesses) {
+  // Terminator instructions control the control flow. They are explicitly
+  // expressed in the clast and do not need to be copied.
+  if (Inst->isTerminator())
+    return;
+
+  if (canSyntheziseInStmt(Stmt, Inst))
+    return;
+
+  if (auto *Load = dyn_cast<LoadInst>(Inst)) {
+    generateLoad(Stmt, Load, VectorMap, ScalarMaps, NewAccesses);
+    return;
+  }
+
+  if (hasVectorOperands(Inst, VectorMap)) {
+    if (auto *Store = dyn_cast<StoreInst>(Inst)) {
+      // Identified as redundant by -polly-simplify.
+      if (!Stmt.getArrayAccessOrNULLFor(Store))
+        return;
+
+      copyStore(Stmt, Store, VectorMap, ScalarMaps, NewAccesses);
+      return;
+    }
+
+    if (auto *Unary = dyn_cast<UnaryInstruction>(Inst)) {
+      copyUnaryInst(Stmt, Unary, VectorMap, ScalarMaps);
+      return;
+    }
+
+    if (auto *Binary = dyn_cast<BinaryOperator>(Inst)) {
+      copyBinaryInst(Stmt, Binary, VectorMap, ScalarMaps);
+      return;
+    }
+
+    // Fallthrough: We generate scalar instructions, if we don't know how to
+    // generate vector code.
+  }
+
+  copyInstScalarized(Stmt, Inst, VectorMap, ScalarMaps, NewAccesses);
+}
+
+void VectorBlockGenerator::generateScalarVectorLoads(
+    ScopStmt &Stmt, ValueMapT &VectorBlockMap) {
+  for (MemoryAccess *MA : Stmt) {
+    if (MA->isArrayKind() || MA->isWrite())
+      continue;
+
+    auto *Address = getOrCreateAlloca(*MA);
+    Type *VectorPtrType = getVectorPtrTy(Address, 1);
+    Value *VectorPtr = Builder.CreateBitCast(Address, VectorPtrType,
+                                             Address->getName() + "_p_vec_p");
+    auto *Val = Builder.CreateLoad(VectorPtr, Address->getName() + ".reload");
+    Constant *SplatVector = Constant::getNullValue(
+        VectorType::get(Builder.getInt32Ty(), getVectorWidth()));
+
+    Value *VectorVal = Builder.CreateShuffleVector(
+        Val, Val, SplatVector, Address->getName() + "_p_splat");
+    VectorBlockMap[MA->getAccessValue()] = VectorVal;
+  }
+}
+
+void VectorBlockGenerator::verifyNoScalarStores(ScopStmt &Stmt) {
+  for (MemoryAccess *MA : Stmt) {
+    if (MA->isArrayKind() || MA->isRead())
+      continue;
+
+    llvm_unreachable("Scalar stores not expected in vector loop");
+  }
+}
+
+void VectorBlockGenerator::copyStmt(
+    ScopStmt &Stmt, __isl_keep isl_id_to_ast_expr *NewAccesses) {
+  assert(Stmt.isBlockStmt() &&
+         "TODO: Only block statements can be copied by the vector block "
+         "generator");
+
+  BasicBlock *BB = Stmt.getBasicBlock();
+  BasicBlock *CopyBB = SplitBlock(Builder.GetInsertBlock(),
+                                  &*Builder.GetInsertPoint(), &DT, &LI);
+  CopyBB->setName("polly.stmt." + BB->getName());
+  Builder.SetInsertPoint(&CopyBB->front());
+
+  // Create two maps that store the mapping from the original instructions of
+  // the old basic block to their copies in the new basic block. Those maps
+  // are basic block local.
+  //
+  // As vector code generation is supported there is one map for scalar values
+  // and one for vector values.
+  //
+  // In case we just do scalar code generation, the vectorMap is not used and
+  // the scalarMap has just one dimension, which contains the mapping.
+  //
+  // In case vector code generation is done, an instruction may either appear
+  // in the vector map once (as it is calculating >vectorwidth< values at a
+  // time. Or (if the values are calculated using scalar operations), it
+  // appears once in every dimension of the scalarMap.
+  VectorValueMapT ScalarBlockMap(getVectorWidth());
+  ValueMapT VectorBlockMap;
+
+  generateScalarVectorLoads(Stmt, VectorBlockMap);
+
+  for (Instruction &Inst : *BB)
+    copyInstruction(Stmt, &Inst, VectorBlockMap, ScalarBlockMap, NewAccesses);
+
+  verifyNoScalarStores(Stmt);
+}
+
+BasicBlock *RegionGenerator::repairDominance(BasicBlock *BB,
+                                             BasicBlock *BBCopy) {
+
+  BasicBlock *BBIDom = DT.getNode(BB)->getIDom()->getBlock();
+  BasicBlock *BBCopyIDom = EndBlockMap.lookup(BBIDom);
+
+  if (BBCopyIDom)
+    DT.changeImmediateDominator(BBCopy, BBCopyIDom);
+
+  return StartBlockMap.lookup(BBIDom);
+}
+
+// This is to determine whether an llvm::Value (defined in @p BB) is usable when
+// leaving a subregion. The straight-forward DT.dominates(BB, R->getExitBlock())
+// does not work in cases where the exit block has edges from outside the
+// region. In that case the llvm::Value would never be usable in in the exit
+// block. The RegionGenerator however creates an new exit block ('ExitBBCopy')
+// for the subregion's exiting edges only. We need to determine whether an
+// llvm::Value is usable in there. We do this by checking whether it dominates
+// all exiting blocks individually.
+static bool isDominatingSubregionExit(const DominatorTree &DT, Region *R,
+                                      BasicBlock *BB) {
+  for (auto ExitingBB : predecessors(R->getExit())) {
+    // Check for non-subregion incoming edges.
+    if (!R->contains(ExitingBB))
+      continue;
+
+    if (!DT.dominates(BB, ExitingBB))
+      return false;
+  }
+
+  return true;
+}
+
+// Find the direct dominator of the subregion's exit block if the subregion was
+// simplified.
+static BasicBlock *findExitDominator(DominatorTree &DT, Region *R) {
+  BasicBlock *Common = nullptr;
+  for (auto ExitingBB : predecessors(R->getExit())) {
+    // Check for non-subregion incoming edges.
+    if (!R->contains(ExitingBB))
+      continue;
+
+    // First exiting edge.
+    if (!Common) {
+      Common = ExitingBB;
+      continue;
+    }
+
+    Common = DT.findNearestCommonDominator(Common, ExitingBB);
+  }
+
+  assert(Common && R->contains(Common));
+  return Common;
+}
+
+void RegionGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT &LTS,
+                               isl_id_to_ast_expr *IdToAstExp) {
+  assert(Stmt.isRegionStmt() &&
+         "Only region statements can be copied by the region generator");
+
+  // Forget all old mappings.
+  StartBlockMap.clear();
+  EndBlockMap.clear();
+  RegionMaps.clear();
+  IncompletePHINodeMap.clear();
+
+  // Collection of all values related to this subregion.
+  ValueMapT ValueMap;
+
+  // The region represented by the statement.
+  Region *R = Stmt.getRegion();
+
+  // Create a dedicated entry for the region where we can reload all demoted
+  // inputs.
+  BasicBlock *EntryBB = R->getEntry();
+  BasicBlock *EntryBBCopy = SplitBlock(Builder.GetInsertBlock(),
+                                       &*Builder.GetInsertPoint(), &DT, &LI);
+  EntryBBCopy->setName("polly.stmt." + EntryBB->getName() + ".entry");
+  Builder.SetInsertPoint(&EntryBBCopy->front());
+
+  ValueMapT &EntryBBMap = RegionMaps[EntryBBCopy];
+  generateScalarLoads(Stmt, LTS, EntryBBMap, IdToAstExp);
+
+  for (auto PI = pred_begin(EntryBB), PE = pred_end(EntryBB); PI != PE; ++PI)
+    if (!R->contains(*PI)) {
+      StartBlockMap[*PI] = EntryBBCopy;
+      EndBlockMap[*PI] = EntryBBCopy;
+    }
+
+  // Iterate over all blocks in the region in a breadth-first search.
+  std::deque<BasicBlock *> Blocks;
+  SmallSetVector<BasicBlock *, 8> SeenBlocks;
+  Blocks.push_back(EntryBB);
+  SeenBlocks.insert(EntryBB);
+
+  while (!Blocks.empty()) {
+    BasicBlock *BB = Blocks.front();
+    Blocks.pop_front();
+
+    // First split the block and update dominance information.
+    BasicBlock *BBCopy = splitBB(BB);
+    BasicBlock *BBCopyIDom = repairDominance(BB, BBCopy);
+
+    // Get the mapping for this block and initialize it with either the scalar
+    // loads from the generated entering block (which dominates all blocks of
+    // this subregion) or the maps of the immediate dominator, if part of the
+    // subregion. The latter necessarily includes the former.
+    ValueMapT *InitBBMap;
+    if (BBCopyIDom) {
+      assert(RegionMaps.count(BBCopyIDom));
+      InitBBMap = &RegionMaps[BBCopyIDom];
+    } else
+      InitBBMap = &EntryBBMap;
+    auto Inserted = RegionMaps.insert(std::make_pair(BBCopy, *InitBBMap));
+    ValueMapT &RegionMap = Inserted.first->second;
+
+    // Copy the block with the BlockGenerator.
+    Builder.SetInsertPoint(&BBCopy->front());
+    copyBB(Stmt, BB, BBCopy, RegionMap, LTS, IdToAstExp);
+
+    // In order to remap PHI nodes we store also basic block mappings.
+    StartBlockMap[BB] = BBCopy;
+    EndBlockMap[BB] = Builder.GetInsertBlock();
+
+    // Add values to incomplete PHI nodes waiting for this block to be copied.
+    for (const PHINodePairTy &PHINodePair : IncompletePHINodeMap[BB])
+      addOperandToPHI(Stmt, PHINodePair.first, PHINodePair.second, BB, LTS);
+    IncompletePHINodeMap[BB].clear();
+
+    // And continue with new successors inside the region.
+    for (auto SI = succ_begin(BB), SE = succ_end(BB); SI != SE; SI++)
+      if (R->contains(*SI) && SeenBlocks.insert(*SI))
+        Blocks.push_back(*SI);
+
+    // Remember value in case it is visible after this subregion.
+    if (isDominatingSubregionExit(DT, R, BB))
+      ValueMap.insert(RegionMap.begin(), RegionMap.end());
+  }
+
+  // Now create a new dedicated region exit block and add it to the region map.
+  BasicBlock *ExitBBCopy = SplitBlock(Builder.GetInsertBlock(),
+                                      &*Builder.GetInsertPoint(), &DT, &LI);
+  ExitBBCopy->setName("polly.stmt." + R->getExit()->getName() + ".exit");
+  StartBlockMap[R->getExit()] = ExitBBCopy;
+  EndBlockMap[R->getExit()] = ExitBBCopy;
+
+  BasicBlock *ExitDomBBCopy = EndBlockMap.lookup(findExitDominator(DT, R));
+  assert(ExitDomBBCopy &&
+         "Common exit dominator must be within region; at least the entry node "
+         "must match");
+  DT.changeImmediateDominator(ExitBBCopy, ExitDomBBCopy);
+
+  // As the block generator doesn't handle control flow we need to add the
+  // region control flow by hand after all blocks have been copied.
+  for (BasicBlock *BB : SeenBlocks) {
+
+    BasicBlock *BBCopyStart = StartBlockMap[BB];
+    BasicBlock *BBCopyEnd = EndBlockMap[BB];
+    TerminatorInst *TI = BB->getTerminator();
+    if (isa<UnreachableInst>(TI)) {
+      while (!BBCopyEnd->empty())
+        BBCopyEnd->begin()->eraseFromParent();
+      new UnreachableInst(BBCopyEnd->getContext(), BBCopyEnd);
+      continue;
+    }
+
+    Instruction *BICopy = BBCopyEnd->getTerminator();
+
+    ValueMapT &RegionMap = RegionMaps[BBCopyStart];
+    RegionMap.insert(StartBlockMap.begin(), StartBlockMap.end());
+
+    Builder.SetInsertPoint(BICopy);
+    copyInstScalar(Stmt, TI, RegionMap, LTS);
+    BICopy->eraseFromParent();
+  }
+
+  // Add counting PHI nodes to all loops in the region that can be used as
+  // replacement for SCEVs referring to the old loop.
+  for (BasicBlock *BB : SeenBlocks) {
+    Loop *L = LI.getLoopFor(BB);
+    if (L == nullptr || L->getHeader() != BB || !R->contains(L))
+      continue;
+
+    BasicBlock *BBCopy = StartBlockMap[BB];
+    Value *NullVal = Builder.getInt32(0);
+    PHINode *LoopPHI =
+        PHINode::Create(Builder.getInt32Ty(), 2, "polly.subregion.iv");
+    Instruction *LoopPHIInc = BinaryOperator::CreateAdd(
+        LoopPHI, Builder.getInt32(1), "polly.subregion.iv.inc");
+    LoopPHI->insertBefore(&BBCopy->front());
+    LoopPHIInc->insertBefore(BBCopy->getTerminator());
+
+    for (auto *PredBB : make_range(pred_begin(BB), pred_end(BB))) {
+      if (!R->contains(PredBB))
+        continue;
+      if (L->contains(PredBB))
+        LoopPHI->addIncoming(LoopPHIInc, EndBlockMap[PredBB]);
+      else
+        LoopPHI->addIncoming(NullVal, EndBlockMap[PredBB]);
+    }
+
+    for (auto *PredBBCopy : make_range(pred_begin(BBCopy), pred_end(BBCopy)))
+      if (LoopPHI->getBasicBlockIndex(PredBBCopy) < 0)
+        LoopPHI->addIncoming(NullVal, PredBBCopy);
+
+    LTS[L] = SE.getUnknown(LoopPHI);
+  }
+
+  // Continue generating code in the exit block.
+  Builder.SetInsertPoint(&*ExitBBCopy->getFirstInsertionPt());
+
+  // Write values visible to other statements.
+  generateScalarStores(Stmt, LTS, ValueMap, IdToAstExp);
+  StartBlockMap.clear();
+  EndBlockMap.clear();
+  RegionMaps.clear();
+  IncompletePHINodeMap.clear();
+}
+
+PHINode *RegionGenerator::buildExitPHI(MemoryAccess *MA, LoopToScevMapT &LTS,
+                                       ValueMapT &BBMap, Loop *L) {
+  ScopStmt *Stmt = MA->getStatement();
+  Region *SubR = Stmt->getRegion();
+  auto Incoming = MA->getIncoming();
+
+  PollyIRBuilder::InsertPointGuard IPGuard(Builder);
+  PHINode *OrigPHI = cast<PHINode>(MA->getAccessInstruction());
+  BasicBlock *NewSubregionExit = Builder.GetInsertBlock();
+
+  // This can happen if the subregion is simplified after the ScopStmts
+  // have been created; simplification happens as part of CodeGeneration.
+  if (OrigPHI->getParent() != SubR->getExit()) {
+    BasicBlock *FormerExit = SubR->getExitingBlock();
+    if (FormerExit)
+      NewSubregionExit = StartBlockMap.lookup(FormerExit);
+  }
+
+  PHINode *NewPHI = PHINode::Create(OrigPHI->getType(), Incoming.size(),
+                                    "polly." + OrigPHI->getName(),
+                                    NewSubregionExit->getFirstNonPHI());
+
+  // Add the incoming values to the PHI.
+  for (auto &Pair : Incoming) {
+    BasicBlock *OrigIncomingBlock = Pair.first;
+    BasicBlock *NewIncomingBlockStart = StartBlockMap.lookup(OrigIncomingBlock);
+    BasicBlock *NewIncomingBlockEnd = EndBlockMap.lookup(OrigIncomingBlock);
+    Builder.SetInsertPoint(NewIncomingBlockEnd->getTerminator());
+    assert(RegionMaps.count(NewIncomingBlockStart));
+    assert(RegionMaps.count(NewIncomingBlockEnd));
+    ValueMapT *LocalBBMap = &RegionMaps[NewIncomingBlockStart];
+
+    Value *OrigIncomingValue = Pair.second;
+    Value *NewIncomingValue =
+        getNewValue(*Stmt, OrigIncomingValue, *LocalBBMap, LTS, L);
+    NewPHI->addIncoming(NewIncomingValue, NewIncomingBlockEnd);
+  }
+
+  return NewPHI;
+}
+
+Value *RegionGenerator::getExitScalar(MemoryAccess *MA, LoopToScevMapT &LTS,
+                                      ValueMapT &BBMap) {
+  ScopStmt *Stmt = MA->getStatement();
+
+  // TODO: Add some test cases that ensure this is really the right choice.
+  Loop *L = LI.getLoopFor(Stmt->getRegion()->getExit());
+
+  if (MA->isAnyPHIKind()) {
+    auto Incoming = MA->getIncoming();
+    assert(!Incoming.empty() &&
+           "PHI WRITEs must have originate from at least one incoming block");
+
+    // If there is only one incoming value, we do not need to create a PHI.
+    if (Incoming.size() == 1) {
+      Value *OldVal = Incoming[0].second;
+      return getNewValue(*Stmt, OldVal, BBMap, LTS, L);
+    }
+
+    return buildExitPHI(MA, LTS, BBMap, L);
+  }
+
+  // MemoryKind::Value accesses leaving the subregion must dominate the exit
+  // block; just pass the copied value.
+  Value *OldVal = MA->getAccessValue();
+  return getNewValue(*Stmt, OldVal, BBMap, LTS, L);
+}
+
+void RegionGenerator::generateScalarStores(
+    ScopStmt &Stmt, LoopToScevMapT &LTS, ValueMapT &BBMap,
+    __isl_keep isl_id_to_ast_expr *NewAccesses) {
+  assert(Stmt.getRegion() &&
+         "Block statements need to use the generateScalarStores() "
+         "function in the BlockGenerator");
+
+  for (MemoryAccess *MA : Stmt) {
+    if (MA->isOriginalArrayKind() || MA->isRead())
+      continue;
+
+    isl::set AccDom = MA->getAccessRelation().domain();
+    std::string Subject = MA->getId().get_name();
+    generateConditionalExecution(
+        Stmt, AccDom, Subject.c_str(), [&, this, MA]() {
+          Value *NewVal = getExitScalar(MA, LTS, BBMap);
+          Value *Address = getImplicitAddress(*MA, getLoopForStmt(Stmt), LTS,
+                                              BBMap, NewAccesses);
+          assert((!isa<Instruction>(NewVal) ||
+                  DT.dominates(cast<Instruction>(NewVal)->getParent(),
+                               Builder.GetInsertBlock())) &&
+                 "Domination violation");
+          assert((!isa<Instruction>(Address) ||
+                  DT.dominates(cast<Instruction>(Address)->getParent(),
+                               Builder.GetInsertBlock())) &&
+                 "Domination violation");
+          Builder.CreateStore(NewVal, Address);
+        });
+  }
+}
+
+void RegionGenerator::addOperandToPHI(ScopStmt &Stmt, PHINode *PHI,
+                                      PHINode *PHICopy, BasicBlock *IncomingBB,
+                                      LoopToScevMapT &LTS) {
+  // If the incoming block was not yet copied mark this PHI as incomplete.
+  // Once the block will be copied the incoming value will be added.
+  BasicBlock *BBCopyStart = StartBlockMap[IncomingBB];
+  BasicBlock *BBCopyEnd = EndBlockMap[IncomingBB];
+  if (!BBCopyStart) {
+    assert(!BBCopyEnd);
+    assert(Stmt.represents(IncomingBB) &&
+           "Bad incoming block for PHI in non-affine region");
+    IncompletePHINodeMap[IncomingBB].push_back(std::make_pair(PHI, PHICopy));
+    return;
+  }
+
+  assert(RegionMaps.count(BBCopyStart) &&
+         "Incoming PHI block did not have a BBMap");
+  ValueMapT &BBCopyMap = RegionMaps[BBCopyStart];
+
+  Value *OpCopy = nullptr;
+
+  if (Stmt.represents(IncomingBB)) {
+    Value *Op = PHI->getIncomingValueForBlock(IncomingBB);
+
+    // If the current insert block is different from the PHIs incoming block
+    // change it, otherwise do not.
+    auto IP = Builder.GetInsertPoint();
+    if (IP->getParent() != BBCopyEnd)
+      Builder.SetInsertPoint(BBCopyEnd->getTerminator());
+    OpCopy = getNewValue(Stmt, Op, BBCopyMap, LTS, getLoopForStmt(Stmt));
+    if (IP->getParent() != BBCopyEnd)
+      Builder.SetInsertPoint(&*IP);
+  } else {
+    // All edges from outside the non-affine region become a single edge
+    // in the new copy of the non-affine region. Make sure to only add the
+    // corresponding edge the first time we encounter a basic block from
+    // outside the non-affine region.
+    if (PHICopy->getBasicBlockIndex(BBCopyEnd) >= 0)
+      return;
+
+    // Get the reloaded value.
+    OpCopy = getNewValue(Stmt, PHI, BBCopyMap, LTS, getLoopForStmt(Stmt));
+  }
+
+  assert(OpCopy && "Incoming PHI value was not copied properly");
+  PHICopy->addIncoming(OpCopy, BBCopyEnd);
+}
+
+void RegionGenerator::copyPHIInstruction(ScopStmt &Stmt, PHINode *PHI,
+                                         ValueMapT &BBMap,
+                                         LoopToScevMapT &LTS) {
+  unsigned NumIncoming = PHI->getNumIncomingValues();
+  PHINode *PHICopy =
+      Builder.CreatePHI(PHI->getType(), NumIncoming, "polly." + PHI->getName());
+  PHICopy->moveBefore(PHICopy->getParent()->getFirstNonPHI());
+  BBMap[PHI] = PHICopy;
+
+  for (BasicBlock *IncomingBB : PHI->blocks())
+    addOperandToPHI(Stmt, PHI, PHICopy, IncomingBB, LTS);
+}
diff --git a/final/lib/CodeGen/CodeGeneration.cpp b/final/lib/CodeGen/CodeGeneration.cpp
new file mode 100644
index 0000000..41a3b2f
--- /dev/null
+++ b/final/lib/CodeGen/CodeGeneration.cpp
@@ -0,0 +1,400 @@
+//===- CodeGeneration.cpp - Code generate the Scops using ISL. ---------======//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The CodeGeneration pass takes a Scop created by ScopInfo and translates it
+// back to LLVM-IR using the ISL code generator.
+//
+// The Scop describes the high level memory behavior of a control flow region.
+// Transformation passes can update the schedule (execution order) of statements
+// in the Scop. ISL is used to generate an abstract syntax tree that reflects
+// the updated execution order. This clast is used to create new LLVM-IR that is
+// computationally equivalent to the original control flow region, but executes
+// its code in the new execution order defined by the changed schedule.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/CodeGeneration.h"
+#include "polly/CodeGen/IRBuilder.h"
+#include "polly/CodeGen/IslAst.h"
+#include "polly/CodeGen/IslNodeBuilder.h"
+#include "polly/CodeGen/PerfMonitor.h"
+#include "polly/CodeGen/Utils.h"
+#include "polly/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopDetectionDiagnostic.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/BasicAliasAnalysis.h"
+#include "llvm/Analysis/GlobalsModRef.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include "isl/ast.h"
+#include <cassert>
+#include <utility>
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-codegen"
+
+static cl::opt<bool> Verify("polly-codegen-verify",
+                            cl::desc("Verify the function generated by Polly"),
+                            cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                            cl::cat(PollyCategory));
+
+bool polly::PerfMonitoring;
+
+static cl::opt<bool, true>
+    XPerfMonitoring("polly-codegen-perf-monitoring",
+                    cl::desc("Add run-time performance monitoring"), cl::Hidden,
+                    cl::location(polly::PerfMonitoring), cl::init(false),
+                    cl::ZeroOrMore, cl::cat(PollyCategory));
+
+STATISTIC(ScopsProcessed, "Number of SCoP processed");
+STATISTIC(CodegenedScops, "Number of successfully generated SCoPs");
+STATISTIC(CodegenedAffineLoops,
+          "Number of original affine loops in SCoPs that have been generated");
+STATISTIC(CodegenedBoxedLoops,
+          "Number of original boxed loops in SCoPs that have been generated");
+
+namespace polly {
+
+/// Mark a basic block unreachable.
+///
+/// Marks the basic block @p Block unreachable by equipping it with an
+/// UnreachableInst.
+void markBlockUnreachable(BasicBlock &Block, PollyIRBuilder &Builder) {
+  auto *OrigTerminator = Block.getTerminator();
+  Builder.SetInsertPoint(OrigTerminator);
+  Builder.CreateUnreachable();
+  OrigTerminator->eraseFromParent();
+}
+
+} // namespace polly
+
+static void verifyGeneratedFunction(Scop &S, Function &F, IslAstInfo &AI) {
+  if (!Verify || !verifyFunction(F, &errs()))
+    return;
+
+  DEBUG({
+    errs() << "== ISL Codegen created an invalid function ==\n\n== The "
+              "SCoP ==\n";
+    errs() << S;
+    errs() << "\n== The isl AST ==\n";
+    AI.print(errs());
+    errs() << "\n== The invalid function ==\n";
+    F.print(errs());
+  });
+
+  llvm_unreachable("Polly generated function could not be verified. Add "
+                   "-polly-codegen-verify=false to disable this assertion.");
+}
+
+// CodeGeneration adds a lot of BBs without updating the RegionInfo
+// We make all created BBs belong to the scop's parent region without any
+// nested structure to keep the RegionInfo verifier happy.
+static void fixRegionInfo(Function &F, Region &ParentRegion, RegionInfo &RI) {
+  for (BasicBlock &BB : F) {
+    if (RI.getRegionFor(&BB))
+      continue;
+
+    RI.setRegionFor(&BB, &ParentRegion);
+  }
+}
+
+/// Remove all lifetime markers (llvm.lifetime.start, llvm.lifetime.end) from
+/// @R.
+///
+/// CodeGeneration does not copy lifetime markers into the optimized SCoP,
+/// which would leave the them only in the original path. This can transform
+/// code such as
+///
+///     llvm.lifetime.start(%p)
+///     llvm.lifetime.end(%p)
+///
+/// into
+///
+///     if (RTC) {
+///       // generated code
+///     } else {
+///       // original code
+///       llvm.lifetime.start(%p)
+///     }
+///     llvm.lifetime.end(%p)
+///
+/// The current StackColoring algorithm cannot handle if some, but not all,
+/// paths from the end marker to the entry block cross the start marker. Same
+/// for start markers that do not always cross the end markers. We avoid any
+/// issues by removing all lifetime markers, even from the original code.
+///
+/// A better solution could be to hoist all llvm.lifetime.start to the split
+/// node and all llvm.lifetime.end to the merge node, which should be
+/// conservatively correct.
+static void removeLifetimeMarkers(Region *R) {
+  for (auto *BB : R->blocks()) {
+    auto InstIt = BB->begin();
+    auto InstEnd = BB->end();
+
+    while (InstIt != InstEnd) {
+      auto NextIt = InstIt;
+      ++NextIt;
+
+      if (auto *IT = dyn_cast<IntrinsicInst>(&*InstIt)) {
+        switch (IT->getIntrinsicID()) {
+        case Intrinsic::lifetime_start:
+        case Intrinsic::lifetime_end:
+          BB->getInstList().erase(InstIt);
+          break;
+        default:
+          break;
+        }
+      }
+
+      InstIt = NextIt;
+    }
+  }
+}
+
+static bool CodeGen(Scop &S, IslAstInfo &AI, LoopInfo &LI, DominatorTree &DT,
+                    ScalarEvolution &SE, RegionInfo &RI) {
+  // Check whether IslAstInfo uses the same isl_ctx. Since -polly-codegen
+  // reports itself to preserve DependenceInfo and IslAstInfo, we might get
+  // those analysis that were computed by a different ScopInfo for a different
+  // Scop structure. When the ScopInfo/Scop object is freed, there is a high
+  // probability that the new ScopInfo/Scop object will be created at the same
+  // heap position with the same address. Comparing whether the Scop or ScopInfo
+  // address is the expected therefore is unreliable.
+  // Instead, we compare the address of the isl_ctx object. Both, DependenceInfo
+  // and IslAstInfo must hold a reference to the isl_ctx object to ensure it is
+  // not freed before the destruction of those analyses which might happen after
+  // the destruction of the Scop/ScopInfo they refer to.  Hence, the isl_ctx
+  // will not be freed and its space not reused as long there is a
+  // DependenceInfo or IslAstInfo around.
+  IslAst &Ast = AI.getIslAst();
+  if (Ast.getSharedIslCtx() != S.getSharedIslCtx()) {
+    DEBUG(dbgs() << "Got an IstAst for a different Scop/isl_ctx\n");
+    return false;
+  }
+
+  // Check if we created an isl_ast root node, otherwise exit.
+  isl_ast_node *AstRoot = Ast.getAst();
+  if (!AstRoot)
+    return false;
+
+  // Collect statistics. Do it before we modify the IR to avoid having it any
+  // influence on the result.
+  auto ScopStats = S.getStatistics();
+  ScopsProcessed++;
+
+  auto &DL = S.getFunction().getParent()->getDataLayout();
+  Region *R = &S.getRegion();
+  assert(!R->isTopLevelRegion() && "Top level regions are not supported");
+
+  ScopAnnotator Annotator;
+
+  simplifyRegion(R, &DT, &LI, &RI);
+  assert(R->isSimple());
+  BasicBlock *EnteringBB = S.getEnteringBlock();
+  assert(EnteringBB);
+  PollyIRBuilder Builder = createPollyIRBuilder(EnteringBB, Annotator);
+
+  // Only build the run-time condition and parameters _after_ having
+  // introduced the conditional branch. This is important as the conditional
+  // branch will guard the original scop from new induction variables that
+  // the SCEVExpander may introduce while code generating the parameters and
+  // which may introduce scalar dependences that prevent us from correctly
+  // code generating this scop.
+  BBPair StartExitBlocks =
+      std::get<0>(executeScopConditionally(S, Builder.getTrue(), DT, RI, LI));
+  BasicBlock *StartBlock = std::get<0>(StartExitBlocks);
+  BasicBlock *ExitBlock = std::get<1>(StartExitBlocks);
+
+  removeLifetimeMarkers(R);
+  auto *SplitBlock = StartBlock->getSinglePredecessor();
+
+  IslNodeBuilder NodeBuilder(Builder, Annotator, DL, LI, SE, DT, S, StartBlock);
+
+  // All arrays must have their base pointers known before
+  // ScopAnnotator::buildAliasScopes.
+  NodeBuilder.allocateNewArrays(StartExitBlocks);
+  Annotator.buildAliasScopes(S);
+
+  if (PerfMonitoring) {
+    PerfMonitor P(S, EnteringBB->getParent()->getParent());
+    P.initialize();
+    P.insertRegionStart(SplitBlock->getTerminator());
+
+    BasicBlock *MergeBlock = ExitBlock->getUniqueSuccessor();
+    P.insertRegionEnd(MergeBlock->getTerminator());
+  }
+
+  // First generate code for the hoisted invariant loads and transitively the
+  // parameters they reference. Afterwards, for the remaining parameters that
+  // might reference the hoisted loads. Finally, build the runtime check
+  // that might reference both hoisted loads as well as parameters.
+  // If the hoisting fails we have to bail and execute the original code.
+  Builder.SetInsertPoint(SplitBlock->getTerminator());
+  if (!NodeBuilder.preloadInvariantLoads()) {
+    // Patch the introduced branch condition to ensure that we always execute
+    // the original SCoP.
+    auto *FalseI1 = Builder.getFalse();
+    auto *SplitBBTerm = Builder.GetInsertBlock()->getTerminator();
+    SplitBBTerm->setOperand(0, FalseI1);
+
+    // Since the other branch is hence ignored we mark it as unreachable and
+    // adjust the dominator tree accordingly.
+    auto *ExitingBlock = StartBlock->getUniqueSuccessor();
+    assert(ExitingBlock);
+    auto *MergeBlock = ExitingBlock->getUniqueSuccessor();
+    assert(MergeBlock);
+    markBlockUnreachable(*StartBlock, Builder);
+    markBlockUnreachable(*ExitingBlock, Builder);
+    auto *ExitingBB = S.getExitingBlock();
+    assert(ExitingBB);
+    DT.changeImmediateDominator(MergeBlock, ExitingBB);
+    DT.eraseNode(ExitingBlock);
+
+    isl_ast_node_free(AstRoot);
+  } else {
+    NodeBuilder.addParameters(S.getContext().release());
+    Value *RTC = NodeBuilder.createRTC(AI.getRunCondition());
+
+    Builder.GetInsertBlock()->getTerminator()->setOperand(0, RTC);
+
+    // Explicitly set the insert point to the end of the block to avoid that a
+    // split at the builder's current
+    // insert position would move the malloc calls to the wrong BasicBlock.
+    // Ideally we would just split the block during allocation of the new
+    // arrays, but this would break the assumption that there are no blocks
+    // between polly.start and polly.exiting (at this point).
+    Builder.SetInsertPoint(StartBlock->getTerminator());
+
+    NodeBuilder.create(AstRoot);
+    NodeBuilder.finalize();
+    fixRegionInfo(*EnteringBB->getParent(), *R->getParent(), RI);
+
+    CodegenedScops++;
+    CodegenedAffineLoops += ScopStats.NumAffineLoops;
+    CodegenedBoxedLoops += ScopStats.NumBoxedLoops;
+  }
+
+  Function *F = EnteringBB->getParent();
+  verifyGeneratedFunction(S, *F, AI);
+  for (auto *SubF : NodeBuilder.getParallelSubfunctions())
+    verifyGeneratedFunction(S, *SubF, AI);
+
+  // Mark the function such that we run additional cleanup passes on this
+  // function (e.g. mem2reg to rediscover phi nodes).
+  F->addFnAttr("polly-optimized");
+  return true;
+}
+
+namespace {
+
+class CodeGeneration : public ScopPass {
+public:
+  static char ID;
+
+  /// The data layout used.
+  const DataLayout *DL;
+
+  /// @name The analysis passes we need to generate code.
+  ///
+  ///{
+  LoopInfo *LI;
+  IslAstInfo *AI;
+  DominatorTree *DT;
+  ScalarEvolution *SE;
+  RegionInfo *RI;
+  ///}
+
+  CodeGeneration() : ScopPass(ID) {}
+
+  /// Generate LLVM-IR for the SCoP @p S.
+  bool runOnScop(Scop &S) override {
+    // Skip SCoPs in case they're already code-generated by PPCGCodeGeneration.
+    if (S.isToBeSkipped())
+      return false;
+
+    AI = &getAnalysis<IslAstInfoWrapperPass>().getAI();
+    LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+    DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+    SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
+    DL = &S.getFunction().getParent()->getDataLayout();
+    RI = &getAnalysis<RegionInfoPass>().getRegionInfo();
+    return CodeGen(S, *AI, *LI, *DT, *SE, *RI);
+  }
+
+  /// Register all analyses and transformation required.
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    ScopPass::getAnalysisUsage(AU);
+
+    AU.addRequired<DominatorTreeWrapperPass>();
+    AU.addRequired<IslAstInfoWrapperPass>();
+    AU.addRequired<RegionInfoPass>();
+    AU.addRequired<ScalarEvolutionWrapperPass>();
+    AU.addRequired<ScopDetectionWrapperPass>();
+    AU.addRequired<ScopInfoRegionPass>();
+    AU.addRequired<LoopInfoWrapperPass>();
+
+    AU.addPreserved<DependenceInfo>();
+    AU.addPreserved<IslAstInfoWrapperPass>();
+
+    // FIXME: We do not yet add regions for the newly generated code to the
+    //        region tree.
+  }
+};
+
+} // namespace
+
+PreservedAnalyses CodeGenerationPass::run(Scop &S, ScopAnalysisManager &SAM,
+                                          ScopStandardAnalysisResults &AR,
+                                          SPMUpdater &U) {
+  auto &AI = SAM.getResult<IslAstAnalysis>(S, AR);
+  if (CodeGen(S, AI, AR.LI, AR.DT, AR.SE, AR.RI)) {
+    U.invalidateScop(S);
+    return PreservedAnalyses::none();
+  }
+
+  return PreservedAnalyses::all();
+}
+
+char CodeGeneration::ID = 1;
+
+Pass *polly::createCodeGenerationPass() { return new CodeGeneration(); }
+
+INITIALIZE_PASS_BEGIN(CodeGeneration, "polly-codegen",
+                      "Polly - Create LLVM-IR from SCoPs", false, false);
+INITIALIZE_PASS_DEPENDENCY(DependenceInfo);
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass);
+INITIALIZE_PASS_END(CodeGeneration, "polly-codegen",
+                    "Polly - Create LLVM-IR from SCoPs", false, false)
diff --git a/final/lib/CodeGen/CodegenCleanup.cpp b/final/lib/CodeGen/CodegenCleanup.cpp
new file mode 100644
index 0000000..f5a5744
--- /dev/null
+++ b/final/lib/CodeGen/CodegenCleanup.cpp
@@ -0,0 +1,139 @@
+//===- CodegenCleanup.cpp -------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/CodegenCleanup.h"
+
+#include "llvm/Analysis/ScopedNoAliasAA.h"
+#include "llvm/Analysis/TypeBasedAliasAnalysis.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/PassInfo.h"
+#include "llvm/PassRegistry.h"
+#include "llvm/PassSupport.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Scalar/GVN.h"
+
+#define DEBUG_TYPE "polly-cleanup"
+
+using namespace llvm;
+using namespace polly;
+
+namespace {
+
+class CodegenCleanup : public FunctionPass {
+private:
+  CodegenCleanup(const CodegenCleanup &) = delete;
+  const CodegenCleanup &operator=(const CodegenCleanup &) = delete;
+
+  llvm::legacy::FunctionPassManager *FPM;
+
+public:
+  static char ID;
+  explicit CodegenCleanup() : FunctionPass(ID), FPM(nullptr) {}
+
+  /// @name FunctionPass interface
+  //@{
+  virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {}
+
+  virtual bool doInitialization(Module &M) override {
+    assert(!FPM);
+
+    FPM = new llvm::legacy::FunctionPassManager(&M);
+
+    // TODO: How to make parent passes discoverable?
+    // TODO: Should be sensitive to compiler options in PassManagerBuilder, to
+    // which we do not have access here.
+    FPM->add(createScopedNoAliasAAWrapperPass());
+    FPM->add(createTypeBasedAAWrapperPass());
+    FPM->add(createAAResultsWrapperPass());
+
+    // TODO: These are non-conditional passes that run between
+    // EP_ModuleOptimizerEarly and EP_VectorizerStart just to ensure we do not
+    // miss any optimization that would have run after Polly with
+    // -polly-position=early. This can probably be reduced to a more compact set
+    // of passes.
+    FPM->add(createCFGSimplificationPass());
+    FPM->add(createSROAPass());
+    FPM->add(createEarlyCSEPass());
+
+    FPM->add(createPromoteMemoryToRegisterPass());
+    FPM->add(createInstructionCombiningPass(true));
+    FPM->add(createCFGSimplificationPass());
+    FPM->add(createSROAPass());
+    FPM->add(createEarlyCSEPass(true));
+    FPM->add(createSpeculativeExecutionIfHasBranchDivergencePass());
+    FPM->add(createJumpThreadingPass());
+    FPM->add(createCorrelatedValuePropagationPass());
+    FPM->add(createCFGSimplificationPass());
+    FPM->add(createInstructionCombiningPass(true));
+    FPM->add(createLibCallsShrinkWrapPass());
+    FPM->add(createTailCallEliminationPass());
+    FPM->add(createCFGSimplificationPass());
+    FPM->add(createReassociatePass());
+    FPM->add(createLoopRotatePass(-1));
+    FPM->add(createGVNPass());
+    FPM->add(createLICMPass());
+    FPM->add(createLoopUnswitchPass());
+    FPM->add(createCFGSimplificationPass());
+    FPM->add(createInstructionCombiningPass(true));
+    FPM->add(createIndVarSimplifyPass());
+    FPM->add(createLoopIdiomPass());
+    FPM->add(createLoopDeletionPass());
+    FPM->add(createCFGSimplificationPass());
+    FPM->add(createSimpleLoopUnrollPass(3));
+    FPM->add(createMergedLoadStoreMotionPass());
+    FPM->add(createGVNPass());
+    FPM->add(createMemCpyOptPass());
+    FPM->add(createSCCPPass());
+    FPM->add(createBitTrackingDCEPass());
+    FPM->add(createInstructionCombiningPass(true));
+    FPM->add(createJumpThreadingPass());
+    FPM->add(createCorrelatedValuePropagationPass());
+    FPM->add(createDeadStoreEliminationPass());
+    FPM->add(createLICMPass());
+    FPM->add(createAggressiveDCEPass());
+    FPM->add(createCFGSimplificationPass());
+    FPM->add(createInstructionCombiningPass(true));
+    FPM->add(createFloat2IntPass());
+
+    return FPM->doInitialization();
+  }
+
+  virtual bool doFinalization(Module &M) override {
+    bool Result = FPM->doFinalization();
+
+    delete FPM;
+    FPM = nullptr;
+
+    return Result;
+  }
+
+  virtual bool runOnFunction(llvm::Function &F) override {
+    if (!F.hasFnAttribute("polly-optimized")) {
+      DEBUG(dbgs() << F.getName()
+                   << ": Skipping cleanup because Polly did not optimize it.");
+      return false;
+    }
+
+    DEBUG(dbgs() << F.getName() << ": Running codegen cleanup...");
+    return FPM->run(F);
+  }
+  //@}
+};
+
+char CodegenCleanup::ID;
+} // namespace
+
+FunctionPass *polly::createCodegenCleanupPass() { return new CodegenCleanup(); }
+
+INITIALIZE_PASS_BEGIN(CodegenCleanup, "polly-cleanup",
+                      "Polly - Cleanup after code generation", false, false)
+INITIALIZE_PASS_END(CodegenCleanup, "polly-cleanup",
+                    "Polly - Cleanup after code generation", false, false)
diff --git a/final/lib/CodeGen/IRBuilder.cpp b/final/lib/CodeGen/IRBuilder.cpp
new file mode 100644
index 0000000..3efa7c8
--- /dev/null
+++ b/final/lib/CodeGen/IRBuilder.cpp
@@ -0,0 +1,256 @@
+//===------ PollyIRBuilder.cpp --------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The Polly IRBuilder file contains Polly specific extensions for the IRBuilder
+// that are used e.g. to emit the llvm.loop.parallel metadata.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/IRBuilder.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+using namespace polly;
+
+static const int MaxArraysInAliasScops = 10;
+
+/// Get a self referencing id metadata node.
+///
+/// The MDNode looks like this (if arg0/arg1 are not null):
+///
+///    '!n = metadata !{metadata !n, arg0, arg1}'
+///
+/// @return The self referencing id metadata node.
+static MDNode *getID(LLVMContext &Ctx, Metadata *arg0 = nullptr,
+                     Metadata *arg1 = nullptr) {
+  MDNode *ID;
+  SmallVector<Metadata *, 3> Args;
+  // Use a temporary node to safely create a unique pointer for the first arg.
+  auto TempNode = MDNode::getTemporary(Ctx, None);
+  // Reserve operand 0 for loop id self reference.
+  Args.push_back(TempNode.get());
+
+  if (arg0)
+    Args.push_back(arg0);
+  if (arg1)
+    Args.push_back(arg1);
+
+  ID = MDNode::get(Ctx, Args);
+  ID->replaceOperandWith(0, ID);
+  return ID;
+}
+
+ScopAnnotator::ScopAnnotator() : SE(nullptr), AliasScopeDomain(nullptr) {}
+
+void ScopAnnotator::buildAliasScopes(Scop &S) {
+  SE = S.getSE();
+
+  LLVMContext &Ctx = SE->getContext();
+  AliasScopeDomain = getID(Ctx, MDString::get(Ctx, "polly.alias.scope.domain"));
+
+  AliasScopeMap.clear();
+  OtherAliasScopeListMap.clear();
+
+  // We are only interested in arrays, but no scalar references. Scalars should
+  // be handled easily by basicaa.
+  SmallVector<ScopArrayInfo *, 10> Arrays;
+  for (ScopArrayInfo *Array : S.arrays())
+    if (Array->isArrayKind())
+      Arrays.push_back(Array);
+
+  // The construction of alias scopes is quadratic in the number of arrays
+  // involved. In case of too many arrays, skip the construction of alias
+  // information to avoid quadratic increases in compile time and code size.
+  if (Arrays.size() > MaxArraysInAliasScops)
+    return;
+
+  std::string AliasScopeStr = "polly.alias.scope.";
+  for (const ScopArrayInfo *Array : Arrays) {
+    assert(Array->getBasePtr() && "Base pointer must be present");
+    AliasScopeMap[Array->getBasePtr()] =
+        getID(Ctx, AliasScopeDomain,
+              MDString::get(Ctx, (AliasScopeStr + Array->getName()).c_str()));
+  }
+
+  for (const ScopArrayInfo *Array : Arrays) {
+    MDNode *AliasScopeList = MDNode::get(Ctx, {});
+    for (const auto &AliasScopePair : AliasScopeMap) {
+      if (Array->getBasePtr() == AliasScopePair.first)
+        continue;
+
+      Metadata *Args = {AliasScopePair.second};
+      AliasScopeList =
+          MDNode::concatenate(AliasScopeList, MDNode::get(Ctx, Args));
+    }
+
+    OtherAliasScopeListMap[Array->getBasePtr()] = AliasScopeList;
+  }
+}
+
+void ScopAnnotator::pushLoop(Loop *L, bool IsParallel) {
+
+  ActiveLoops.push_back(L);
+  if (!IsParallel)
+    return;
+
+  BasicBlock *Header = L->getHeader();
+  MDNode *Id = getID(Header->getContext());
+  assert(Id->getOperand(0) == Id && "Expected Id to be a self-reference");
+  assert(Id->getNumOperands() == 1 && "Unexpected extra operands in Id");
+  MDNode *Ids = ParallelLoops.empty()
+                    ? Id
+                    : MDNode::concatenate(ParallelLoops.back(), Id);
+  ParallelLoops.push_back(Ids);
+}
+
+void ScopAnnotator::popLoop(bool IsParallel) {
+  ActiveLoops.pop_back();
+  if (!IsParallel)
+    return;
+
+  assert(!ParallelLoops.empty() && "Expected a parallel loop to pop");
+  ParallelLoops.pop_back();
+}
+
+void ScopAnnotator::annotateLoopLatch(BranchInst *B, Loop *L, bool IsParallel,
+                                      bool IsLoopVectorizerDisabled) const {
+  MDNode *MData = nullptr;
+
+  if (IsLoopVectorizerDisabled) {
+    SmallVector<Metadata *, 3> Args;
+    LLVMContext &Ctx = SE->getContext();
+    Args.push_back(MDString::get(Ctx, "llvm.loop.vectorize.enable"));
+    auto *FalseValue = ConstantInt::get(Type::getInt1Ty(Ctx), 0);
+    Args.push_back(ValueAsMetadata::get(FalseValue));
+    MData = MDNode::concatenate(MData, getID(Ctx, MDNode::get(Ctx, Args)));
+  }
+
+  if (IsParallel) {
+    assert(!ParallelLoops.empty() && "Expected a parallel loop to annotate");
+    MDNode *Ids = ParallelLoops.back();
+    MDNode *Id = cast<MDNode>(Ids->getOperand(Ids->getNumOperands() - 1));
+    MData = MDNode::concatenate(MData, Id);
+  }
+
+  B->setMetadata("llvm.loop", MData);
+}
+
+/// Get the pointer operand
+///
+/// @param Inst The instruction to be analyzed.
+/// @return the pointer operand in case @p Inst is a memory access
+///         instruction and nullptr otherwise.
+static llvm::Value *getMemAccInstPointerOperand(Instruction *Inst) {
+  auto MemInst = MemAccInst::dyn_cast(Inst);
+  if (!MemInst)
+    return nullptr;
+
+  return MemInst.getPointerOperand();
+}
+
+void ScopAnnotator::annotateSecondLevel(llvm::Instruction *Inst,
+                                        llvm::Value *BasePtr) {
+  auto *PtrSCEV = SE->getSCEV(getMemAccInstPointerOperand(Inst));
+  auto *BasePtrSCEV = SE->getPointerBase(PtrSCEV);
+
+  if (!PtrSCEV)
+    return;
+  auto SecondLevelAliasScope = SecondLevelAliasScopeMap.lookup(PtrSCEV);
+  auto SecondLevelOtherAliasScopeList =
+      SecondLevelOtherAliasScopeListMap.lookup(PtrSCEV);
+  if (!SecondLevelAliasScope) {
+    auto AliasScope = AliasScopeMap.lookup(BasePtr);
+    if (!AliasScope)
+      return;
+    LLVMContext &Ctx = SE->getContext();
+    SecondLevelAliasScope = getID(
+        Ctx, AliasScope, MDString::get(Ctx, "second level alias metadata"));
+    SecondLevelAliasScopeMap[PtrSCEV] = SecondLevelAliasScope;
+    Metadata *Args = {SecondLevelAliasScope};
+    auto SecondLevelBasePtrAliasScopeList =
+        SecondLevelAliasScopeMap.lookup(BasePtrSCEV);
+    SecondLevelAliasScopeMap[BasePtrSCEV] = MDNode::concatenate(
+        SecondLevelBasePtrAliasScopeList, MDNode::get(Ctx, Args));
+    auto OtherAliasScopeList = OtherAliasScopeListMap.lookup(BasePtr);
+    SecondLevelOtherAliasScopeList = MDNode::concatenate(
+        OtherAliasScopeList, SecondLevelBasePtrAliasScopeList);
+    SecondLevelOtherAliasScopeListMap[PtrSCEV] = SecondLevelOtherAliasScopeList;
+  }
+  Inst->setMetadata("alias.scope", SecondLevelAliasScope);
+  Inst->setMetadata("noalias", SecondLevelOtherAliasScopeList);
+}
+
+void ScopAnnotator::annotate(Instruction *Inst) {
+  if (!Inst->mayReadOrWriteMemory())
+    return;
+
+  if (!ParallelLoops.empty())
+    Inst->setMetadata("llvm.mem.parallel_loop_access", ParallelLoops.back());
+
+  // TODO: Use the ScopArrayInfo once available here.
+  if (!AliasScopeDomain)
+    return;
+
+  // Do not apply annotations on memory operations that take more than one
+  // pointer. It would be ambiguous to which pointer the annotation applies.
+  // FIXME: How can we specify annotations for all pointer arguments?
+  if (isa<CallInst>(Inst) && !isa<MemSetInst>(Inst))
+    return;
+
+  auto *Ptr = getMemAccInstPointerOperand(Inst);
+  if (!Ptr)
+    return;
+
+  auto *PtrSCEV = SE->getSCEV(Ptr);
+  auto *BaseSCEV = SE->getPointerBase(PtrSCEV);
+  auto *SU = dyn_cast<SCEVUnknown>(BaseSCEV);
+
+  if (!SU)
+    return;
+
+  auto *BasePtr = SU->getValue();
+
+  if (!BasePtr)
+    return;
+
+  auto AliasScope = AliasScopeMap.lookup(BasePtr);
+
+  if (!AliasScope) {
+    BasePtr = AlternativeAliasBases.lookup(BasePtr);
+    if (!BasePtr)
+      return;
+
+    AliasScope = AliasScopeMap.lookup(BasePtr);
+    if (!AliasScope)
+      return;
+  }
+
+  assert(OtherAliasScopeListMap.count(BasePtr) &&
+         "BasePtr either expected in AliasScopeMap and OtherAlias...Map");
+  auto *OtherAliasScopeList = OtherAliasScopeListMap[BasePtr];
+
+  if (InterIterationAliasFreeBasePtrs.count(BasePtr)) {
+    annotateSecondLevel(Inst, BasePtr);
+    return;
+  }
+
+  Inst->setMetadata("alias.scope", AliasScope);
+  Inst->setMetadata("noalias", OtherAliasScopeList);
+}
+
+void ScopAnnotator::addInterIterationAliasFreeBasePtr(llvm::Value *BasePtr) {
+  if (!BasePtr)
+    return;
+
+  InterIterationAliasFreeBasePtrs.insert(BasePtr);
+}
diff --git a/final/lib/CodeGen/IslAst.cpp b/final/lib/CodeGen/IslAst.cpp
new file mode 100644
index 0000000..dddfbab
--- /dev/null
+++ b/final/lib/CodeGen/IslAst.cpp
@@ -0,0 +1,846 @@
+//===- IslAst.cpp - isl code generator interface --------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The isl code generator interface takes a Scop and generates an isl_ast. This
+// ist_ast can either be returned directly or it can be pretty printed to
+// stdout.
+//
+// A typical isl_ast output looks like this:
+//
+// for (c2 = max(0, ceild(n + m, 2); c2 <= min(511, floord(5 * n, 3)); c2++) {
+//   bb2(c2);
+// }
+//
+// An in-depth discussion of our AST generation approach can be found in:
+//
+// Polyhedral AST generation is more than scanning polyhedra
+// Tobias Grosser, Sven Verdoolaege, Albert Cohen
+// ACM Transactions on Programming Languages and Systems (TOPLAS),
+// 37(4), July 2015
+// http://www.grosser.es/#pub-polyhedral-AST-generation
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/IslAst.h"
+#include "polly/CodeGen/CodeGeneration.h"
+#include "polly/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopDetection.h"
+#include "polly/ScopInfo.h"
+#include "polly/ScopPass.h"
+#include "polly/Support/GICHelper.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "isl/aff.h"
+#include "isl/ast.h"
+#include "isl/ast_build.h"
+#include "isl/id.h"
+#include "isl/isl-noexceptions.h"
+#include "isl/map.h"
+#include "isl/printer.h"
+#include "isl/schedule.h"
+#include "isl/set.h"
+#include "isl/union_map.h"
+#include "isl/val.h"
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <map>
+#include <string>
+#include <utility>
+
+#define DEBUG_TYPE "polly-ast"
+
+using namespace llvm;
+using namespace polly;
+
+using IslAstUserPayload = IslAstInfo::IslAstUserPayload;
+
+static cl::opt<bool>
+    PollyParallel("polly-parallel",
+                  cl::desc("Generate thread parallel code (isl codegen only)"),
+                  cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> PrintAccesses("polly-ast-print-accesses",
+                                   cl::desc("Print memory access functions"),
+                                   cl::init(false), cl::ZeroOrMore,
+                                   cl::cat(PollyCategory));
+
+static cl::opt<bool> PollyParallelForce(
+    "polly-parallel-force",
+    cl::desc(
+        "Force generation of thread parallel code ignoring any cost model"),
+    cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> UseContext("polly-ast-use-context",
+                                cl::desc("Use context"), cl::Hidden,
+                                cl::init(true), cl::ZeroOrMore,
+                                cl::cat(PollyCategory));
+
+static cl::opt<bool> DetectParallel("polly-ast-detect-parallel",
+                                    cl::desc("Detect parallelism"), cl::Hidden,
+                                    cl::init(false), cl::ZeroOrMore,
+                                    cl::cat(PollyCategory));
+
+STATISTIC(ScopsProcessed, "Number of SCoPs processed");
+STATISTIC(ScopsBeneficial, "Number of beneficial SCoPs");
+STATISTIC(BeneficialAffineLoops, "Number of beneficial affine loops");
+STATISTIC(BeneficialBoxedLoops, "Number of beneficial boxed loops");
+
+STATISTIC(NumForLoops, "Number of for-loops");
+STATISTIC(NumParallel, "Number of parallel for-loops");
+STATISTIC(NumInnermostParallel, "Number of innermost parallel for-loops");
+STATISTIC(NumOutermostParallel, "Number of outermost parallel for-loops");
+STATISTIC(NumReductionParallel, "Number of reduction-parallel for-loops");
+STATISTIC(NumExecutedInParallel, "Number of for-loops executed in parallel");
+STATISTIC(NumIfConditions, "Number of if-conditions");
+
+namespace polly {
+
+/// Temporary information used when building the ast.
+struct AstBuildUserInfo {
+  /// Construct and initialize the helper struct for AST creation.
+  AstBuildUserInfo() = default;
+
+  /// The dependence information used for the parallelism check.
+  const Dependences *Deps = nullptr;
+
+  /// Flag to indicate that we are inside a parallel for node.
+  bool InParallelFor = false;
+
+  /// The last iterator id created for the current SCoP.
+  isl_id *LastForNodeId = nullptr;
+};
+
+} // namespace polly
+
+/// Free an IslAstUserPayload object pointed to by @p Ptr.
+static void freeIslAstUserPayload(void *Ptr) {
+  delete ((IslAstInfo::IslAstUserPayload *)Ptr);
+}
+
+IslAstInfo::IslAstUserPayload::~IslAstUserPayload() {
+  isl_ast_build_free(Build);
+  isl_pw_aff_free(MinimalDependenceDistance);
+}
+
+/// Print a string @p str in a single line using @p Printer.
+static isl_printer *printLine(__isl_take isl_printer *Printer,
+                              const std::string &str,
+                              __isl_keep isl_pw_aff *PWA = nullptr) {
+  Printer = isl_printer_start_line(Printer);
+  Printer = isl_printer_print_str(Printer, str.c_str());
+  if (PWA)
+    Printer = isl_printer_print_pw_aff(Printer, PWA);
+  return isl_printer_end_line(Printer);
+}
+
+/// Return all broken reductions as a string of clauses (OpenMP style).
+static const std::string getBrokenReductionsStr(__isl_keep isl_ast_node *Node) {
+  IslAstInfo::MemoryAccessSet *BrokenReductions;
+  std::string str;
+
+  BrokenReductions = IslAstInfo::getBrokenReductions(Node);
+  if (!BrokenReductions || BrokenReductions->empty())
+    return "";
+
+  // Map each type of reduction to a comma separated list of the base addresses.
+  std::map<MemoryAccess::ReductionType, std::string> Clauses;
+  for (MemoryAccess *MA : *BrokenReductions)
+    if (MA->isWrite())
+      Clauses[MA->getReductionType()] +=
+          ", " + MA->getScopArrayInfo()->getName();
+
+  // Now print the reductions sorted by type. Each type will cause a clause
+  // like:  reduction (+ : sum0, sum1, sum2)
+  for (const auto &ReductionClause : Clauses) {
+    str += " reduction (";
+    str += MemoryAccess::getReductionOperatorStr(ReductionClause.first);
+    // Remove the first two symbols (", ") to make the output look pretty.
+    str += " : " + ReductionClause.second.substr(2) + ")";
+  }
+
+  return str;
+}
+
+/// Callback executed for each for node in the ast in order to print it.
+static isl_printer *cbPrintFor(__isl_take isl_printer *Printer,
+                               __isl_take isl_ast_print_options *Options,
+                               __isl_keep isl_ast_node *Node, void *) {
+  isl_pw_aff *DD = IslAstInfo::getMinimalDependenceDistance(Node);
+  const std::string BrokenReductionsStr = getBrokenReductionsStr(Node);
+  const std::string KnownParallelStr = "#pragma known-parallel";
+  const std::string DepDisPragmaStr = "#pragma minimal dependence distance: ";
+  const std::string SimdPragmaStr = "#pragma simd";
+  const std::string OmpPragmaStr = "#pragma omp parallel for";
+
+  if (DD)
+    Printer = printLine(Printer, DepDisPragmaStr, DD);
+
+  if (IslAstInfo::isInnermostParallel(Node))
+    Printer = printLine(Printer, SimdPragmaStr + BrokenReductionsStr);
+
+  if (IslAstInfo::isExecutedInParallel(Node))
+    Printer = printLine(Printer, OmpPragmaStr);
+  else if (IslAstInfo::isOutermostParallel(Node))
+    Printer = printLine(Printer, KnownParallelStr + BrokenReductionsStr);
+
+  isl_pw_aff_free(DD);
+  return isl_ast_node_for_print(Node, Printer, Options);
+}
+
+/// Check if the current scheduling dimension is parallel.
+///
+/// In case the dimension is parallel we also check if any reduction
+/// dependences is broken when we exploit this parallelism. If so,
+/// @p IsReductionParallel will be set to true. The reduction dependences we use
+/// to check are actually the union of the transitive closure of the initial
+/// reduction dependences together with their reversal. Even though these
+/// dependences connect all iterations with each other (thus they are cyclic)
+/// we can perform the parallelism check as we are only interested in a zero
+/// (or non-zero) dependence distance on the dimension in question.
+static bool astScheduleDimIsParallel(__isl_keep isl_ast_build *Build,
+                                     const Dependences *D,
+                                     IslAstUserPayload *NodeInfo) {
+  if (!D->hasValidDependences())
+    return false;
+
+  isl_union_map *Schedule = isl_ast_build_get_schedule(Build);
+  isl_union_map *Deps = D->getDependences(
+      Dependences::TYPE_RAW | Dependences::TYPE_WAW | Dependences::TYPE_WAR);
+
+  if (!D->isParallel(Schedule, Deps, &NodeInfo->MinimalDependenceDistance) &&
+      !isl_union_map_free(Schedule))
+    return false;
+
+  isl_union_map *RedDeps = D->getDependences(Dependences::TYPE_TC_RED);
+  if (!D->isParallel(Schedule, RedDeps))
+    NodeInfo->IsReductionParallel = true;
+
+  if (!NodeInfo->IsReductionParallel && !isl_union_map_free(Schedule))
+    return true;
+
+  // Annotate reduction parallel nodes with the memory accesses which caused the
+  // reduction dependences parallel execution of the node conflicts with.
+  for (const auto &MaRedPair : D->getReductionDependences()) {
+    if (!MaRedPair.second)
+      continue;
+    RedDeps = isl_union_map_from_map(isl_map_copy(MaRedPair.second));
+    if (!D->isParallel(Schedule, RedDeps))
+      NodeInfo->BrokenReductions.insert(MaRedPair.first);
+  }
+
+  isl_union_map_free(Schedule);
+  return true;
+}
+
+// This method is executed before the construction of a for node. It creates
+// an isl_id that is used to annotate the subsequently generated ast for nodes.
+//
+// In this function we also run the following analyses:
+//
+// - Detection of openmp parallel loops
+//
+static __isl_give isl_id *astBuildBeforeFor(__isl_keep isl_ast_build *Build,
+                                            void *User) {
+  AstBuildUserInfo *BuildInfo = (AstBuildUserInfo *)User;
+  IslAstUserPayload *Payload = new IslAstUserPayload();
+  isl_id *Id = isl_id_alloc(isl_ast_build_get_ctx(Build), "", Payload);
+  Id = isl_id_set_free_user(Id, freeIslAstUserPayload);
+  BuildInfo->LastForNodeId = Id;
+
+  // Test for parallelism only if we are not already inside a parallel loop
+  if (!BuildInfo->InParallelFor)
+    BuildInfo->InParallelFor = Payload->IsOutermostParallel =
+        astScheduleDimIsParallel(Build, BuildInfo->Deps, Payload);
+
+  return Id;
+}
+
+// This method is executed after the construction of a for node.
+//
+// It performs the following actions:
+//
+// - Reset the 'InParallelFor' flag, as soon as we leave a for node,
+//   that is marked as openmp parallel.
+//
+static __isl_give isl_ast_node *
+astBuildAfterFor(__isl_take isl_ast_node *Node, __isl_keep isl_ast_build *Build,
+                 void *User) {
+  isl_id *Id = isl_ast_node_get_annotation(Node);
+  assert(Id && "Post order visit assumes annotated for nodes");
+  IslAstUserPayload *Payload = (IslAstUserPayload *)isl_id_get_user(Id);
+  assert(Payload && "Post order visit assumes annotated for nodes");
+
+  AstBuildUserInfo *BuildInfo = (AstBuildUserInfo *)User;
+  assert(!Payload->Build && "Build environment already set");
+  Payload->Build = isl_ast_build_copy(Build);
+  Payload->IsInnermost = (Id == BuildInfo->LastForNodeId);
+
+  // Innermost loops that are surrounded by parallel loops have not yet been
+  // tested for parallelism. Test them here to ensure we check all innermost
+  // loops for parallelism.
+  if (Payload->IsInnermost && BuildInfo->InParallelFor) {
+    if (Payload->IsOutermostParallel) {
+      Payload->IsInnermostParallel = true;
+    } else {
+      if (PollyVectorizerChoice == VECTORIZER_NONE)
+        Payload->IsInnermostParallel =
+            astScheduleDimIsParallel(Build, BuildInfo->Deps, Payload);
+    }
+  }
+  if (Payload->IsOutermostParallel)
+    BuildInfo->InParallelFor = false;
+
+  isl_id_free(Id);
+  return Node;
+}
+
+static isl_stat astBuildBeforeMark(__isl_keep isl_id *MarkId,
+                                   __isl_keep isl_ast_build *Build,
+                                   void *User) {
+  if (!MarkId)
+    return isl_stat_error;
+
+  AstBuildUserInfo *BuildInfo = (AstBuildUserInfo *)User;
+  if (strcmp(isl_id_get_name(MarkId), "SIMD") == 0)
+    BuildInfo->InParallelFor = true;
+
+  return isl_stat_ok;
+}
+
+static __isl_give isl_ast_node *
+astBuildAfterMark(__isl_take isl_ast_node *Node,
+                  __isl_keep isl_ast_build *Build, void *User) {
+  assert(isl_ast_node_get_type(Node) == isl_ast_node_mark);
+  AstBuildUserInfo *BuildInfo = (AstBuildUserInfo *)User;
+  auto *Id = isl_ast_node_mark_get_id(Node);
+  if (strcmp(isl_id_get_name(Id), "SIMD") == 0)
+    BuildInfo->InParallelFor = false;
+  isl_id_free(Id);
+  return Node;
+}
+
+static __isl_give isl_ast_node *AtEachDomain(__isl_take isl_ast_node *Node,
+                                             __isl_keep isl_ast_build *Build,
+                                             void *User) {
+  assert(!isl_ast_node_get_annotation(Node) && "Node already annotated");
+
+  IslAstUserPayload *Payload = new IslAstUserPayload();
+  isl_id *Id = isl_id_alloc(isl_ast_build_get_ctx(Build), "", Payload);
+  Id = isl_id_set_free_user(Id, freeIslAstUserPayload);
+
+  Payload->Build = isl_ast_build_copy(Build);
+
+  return isl_ast_node_set_annotation(Node, Id);
+}
+
+// Build alias check condition given a pair of minimal/maximal access.
+static isl::ast_expr buildCondition(Scop &S, isl::ast_build Build,
+                                    const Scop::MinMaxAccessTy *It0,
+                                    const Scop::MinMaxAccessTy *It1) {
+
+  isl::pw_multi_aff AFirst = It0->first;
+  isl::pw_multi_aff ASecond = It0->second;
+  isl::pw_multi_aff BFirst = It1->first;
+  isl::pw_multi_aff BSecond = It1->second;
+
+  isl::id Left = AFirst.get_tuple_id(isl::dim::set);
+  isl::id Right = BFirst.get_tuple_id(isl::dim::set);
+
+  isl::ast_expr True =
+      isl::ast_expr::from_val(isl::val::int_from_ui(Build.get_ctx(), 1));
+  isl::ast_expr False =
+      isl::ast_expr::from_val(isl::val::int_from_ui(Build.get_ctx(), 0));
+
+  const ScopArrayInfo *BaseLeft =
+      ScopArrayInfo::getFromId(Left)->getBasePtrOriginSAI();
+  const ScopArrayInfo *BaseRight =
+      ScopArrayInfo::getFromId(Right)->getBasePtrOriginSAI();
+  if (BaseLeft && BaseLeft == BaseRight)
+    return True;
+
+  isl::set Params = S.getContext();
+
+  isl::ast_expr NonAliasGroup, MinExpr, MaxExpr;
+
+  // In the following, we first check if any accesses will be empty under
+  // the execution context of the scop and do not code generate them if this
+  // is the case as isl will fail to derive valid AST expressions for such
+  // accesses.
+
+  if (!AFirst.intersect_params(Params).domain().is_empty() &&
+      !BSecond.intersect_params(Params).domain().is_empty()) {
+    MinExpr = Build.access_from(AFirst).address_of();
+    MaxExpr = Build.access_from(BSecond).address_of();
+    NonAliasGroup = MaxExpr.le(MinExpr);
+  }
+
+  if (!BFirst.intersect_params(Params).domain().is_empty() &&
+      !ASecond.intersect_params(Params).domain().is_empty()) {
+    MinExpr = Build.access_from(BFirst).address_of();
+    MaxExpr = Build.access_from(ASecond).address_of();
+
+    isl::ast_expr Result = MaxExpr.le(MinExpr);
+    if (!NonAliasGroup.is_null())
+      NonAliasGroup = isl::manage(
+          isl_ast_expr_or(NonAliasGroup.release(), Result.release()));
+    else
+      NonAliasGroup = Result;
+  }
+
+  if (NonAliasGroup.is_null())
+    NonAliasGroup = True;
+
+  return NonAliasGroup;
+}
+
+__isl_give isl_ast_expr *
+IslAst::buildRunCondition(Scop &S, __isl_keep isl_ast_build *Build) {
+  isl_ast_expr *RunCondition;
+
+  // The conditions that need to be checked at run-time for this scop are
+  // available as an isl_set in the runtime check context from which we can
+  // directly derive a run-time condition.
+  auto *PosCond =
+      isl_ast_build_expr_from_set(Build, S.getAssumedContext().release());
+  if (S.hasTrivialInvalidContext()) {
+    RunCondition = PosCond;
+  } else {
+    auto *ZeroV = isl_val_zero(isl_ast_build_get_ctx(Build));
+    auto *NegCond =
+        isl_ast_build_expr_from_set(Build, S.getInvalidContext().release());
+    auto *NotNegCond = isl_ast_expr_eq(isl_ast_expr_from_val(ZeroV), NegCond);
+    RunCondition = isl_ast_expr_and(PosCond, NotNegCond);
+  }
+
+  // Create the alias checks from the minimal/maximal accesses in each alias
+  // group which consists of read only and non read only (read write) accesses.
+  // This operation is by construction quadratic in the read-write pointers and
+  // linear in the read only pointers in each alias group.
+  for (const Scop::MinMaxVectorPairTy &MinMaxAccessPair : S.getAliasGroups()) {
+    auto &MinMaxReadWrite = MinMaxAccessPair.first;
+    auto &MinMaxReadOnly = MinMaxAccessPair.second;
+    auto RWAccEnd = MinMaxReadWrite.end();
+
+    for (auto RWAccIt0 = MinMaxReadWrite.begin(); RWAccIt0 != RWAccEnd;
+         ++RWAccIt0) {
+      for (auto RWAccIt1 = RWAccIt0 + 1; RWAccIt1 != RWAccEnd; ++RWAccIt1)
+        RunCondition = isl_ast_expr_and(
+            RunCondition,
+            buildCondition(S, isl::manage(isl_ast_build_copy(Build)), RWAccIt0,
+                           RWAccIt1)
+                .release());
+      for (const Scop::MinMaxAccessTy &ROAccIt : MinMaxReadOnly)
+        RunCondition = isl_ast_expr_and(
+            RunCondition,
+            buildCondition(S, isl::manage(isl_ast_build_copy(Build)), RWAccIt0,
+                           &ROAccIt)
+                .release());
+    }
+  }
+
+  return RunCondition;
+}
+
+/// Simple cost analysis for a given SCoP.
+///
+/// TODO: Improve this analysis and extract it to make it usable in other
+///       places too.
+///       In order to improve the cost model we could either keep track of
+///       performed optimizations (e.g., tiling) or compute properties on the
+///       original as well as optimized SCoP (e.g., #stride-one-accesses).
+static bool benefitsFromPolly(Scop &Scop, bool PerformParallelTest) {
+  if (PollyProcessUnprofitable)
+    return true;
+
+  // Check if nothing interesting happened.
+  if (!PerformParallelTest && !Scop.isOptimized() &&
+      Scop.getAliasGroups().empty())
+    return false;
+
+  // The default assumption is that Polly improves the code.
+  return true;
+}
+
+/// Collect statistics for the syntax tree rooted at @p Ast.
+static void walkAstForStatistics(__isl_keep isl_ast_node *Ast) {
+  assert(Ast);
+  isl_ast_node_foreach_descendant_top_down(
+      Ast,
+      [](__isl_keep isl_ast_node *Node, void *User) -> isl_bool {
+        switch (isl_ast_node_get_type(Node)) {
+        case isl_ast_node_for:
+          NumForLoops++;
+          if (IslAstInfo::isParallel(Node))
+            NumParallel++;
+          if (IslAstInfo::isInnermostParallel(Node))
+            NumInnermostParallel++;
+          if (IslAstInfo::isOutermostParallel(Node))
+            NumOutermostParallel++;
+          if (IslAstInfo::isReductionParallel(Node))
+            NumReductionParallel++;
+          if (IslAstInfo::isExecutedInParallel(Node))
+            NumExecutedInParallel++;
+          break;
+
+        case isl_ast_node_if:
+          NumIfConditions++;
+          break;
+
+        default:
+          break;
+        }
+
+        // Continue traversing subtrees.
+        return isl_bool_true;
+      },
+      nullptr);
+}
+
+IslAst::IslAst(Scop &Scop) : S(Scop), Ctx(Scop.getSharedIslCtx()) {}
+
+IslAst::IslAst(IslAst &&O)
+    : S(O.S), Root(O.Root), RunCondition(O.RunCondition), Ctx(O.Ctx) {
+  O.Root = nullptr;
+  O.RunCondition = nullptr;
+}
+
+IslAst::~IslAst() {
+  isl_ast_node_free(Root);
+  isl_ast_expr_free(RunCondition);
+}
+
+void IslAst::init(const Dependences &D) {
+  bool PerformParallelTest = PollyParallel || DetectParallel ||
+                             PollyVectorizerChoice != VECTORIZER_NONE;
+
+  // We can not perform the dependence analysis and, consequently,
+  // the parallel code generation in case the schedule tree contains
+  // extension nodes.
+  auto ScheduleTree = S.getScheduleTree();
+  PerformParallelTest =
+      PerformParallelTest && !S.containsExtensionNode(ScheduleTree);
+
+  // Skip AST and code generation if there was no benefit achieved.
+  if (!benefitsFromPolly(S, PerformParallelTest))
+    return;
+
+  auto ScopStats = S.getStatistics();
+  ScopsBeneficial++;
+  BeneficialAffineLoops += ScopStats.NumAffineLoops;
+  BeneficialBoxedLoops += ScopStats.NumBoxedLoops;
+
+  auto Ctx = S.getIslCtx();
+  isl_options_set_ast_build_atomic_upper_bound(Ctx.get(), true);
+  isl_options_set_ast_build_detect_min_max(Ctx.get(), true);
+  isl_ast_build *Build;
+  AstBuildUserInfo BuildInfo;
+
+  if (UseContext)
+    Build = isl_ast_build_from_context(S.getContext().release());
+  else
+    Build = isl_ast_build_from_context(
+        isl_set_universe(S.getParamSpace().release()));
+
+  Build = isl_ast_build_set_at_each_domain(Build, AtEachDomain, nullptr);
+
+  if (PerformParallelTest) {
+    BuildInfo.Deps = &D;
+    BuildInfo.InParallelFor = false;
+
+    Build = isl_ast_build_set_before_each_for(Build, &astBuildBeforeFor,
+                                              &BuildInfo);
+    Build =
+        isl_ast_build_set_after_each_for(Build, &astBuildAfterFor, &BuildInfo);
+
+    Build = isl_ast_build_set_before_each_mark(Build, &astBuildBeforeMark,
+                                               &BuildInfo);
+
+    Build = isl_ast_build_set_after_each_mark(Build, &astBuildAfterMark,
+                                              &BuildInfo);
+  }
+
+  RunCondition = buildRunCondition(S, Build);
+
+  Root = isl_ast_build_node_from_schedule(Build, S.getScheduleTree().release());
+  walkAstForStatistics(Root);
+
+  isl_ast_build_free(Build);
+}
+
+IslAst IslAst::create(Scop &Scop, const Dependences &D) {
+  IslAst Ast{Scop};
+  Ast.init(D);
+  return Ast;
+}
+
+__isl_give isl_ast_node *IslAst::getAst() { return isl_ast_node_copy(Root); }
+__isl_give isl_ast_expr *IslAst::getRunCondition() {
+  return isl_ast_expr_copy(RunCondition);
+}
+
+__isl_give isl_ast_node *IslAstInfo::getAst() { return Ast.getAst(); }
+__isl_give isl_ast_expr *IslAstInfo::getRunCondition() {
+  return Ast.getRunCondition();
+}
+
+IslAstUserPayload *IslAstInfo::getNodePayload(__isl_keep isl_ast_node *Node) {
+  isl_id *Id = isl_ast_node_get_annotation(Node);
+  if (!Id)
+    return nullptr;
+  IslAstUserPayload *Payload = (IslAstUserPayload *)isl_id_get_user(Id);
+  isl_id_free(Id);
+  return Payload;
+}
+
+bool IslAstInfo::isInnermost(__isl_keep isl_ast_node *Node) {
+  IslAstUserPayload *Payload = getNodePayload(Node);
+  return Payload && Payload->IsInnermost;
+}
+
+bool IslAstInfo::isParallel(__isl_keep isl_ast_node *Node) {
+  return IslAstInfo::isInnermostParallel(Node) ||
+         IslAstInfo::isOutermostParallel(Node);
+}
+
+bool IslAstInfo::isInnermostParallel(__isl_keep isl_ast_node *Node) {
+  IslAstUserPayload *Payload = getNodePayload(Node);
+  return Payload && Payload->IsInnermostParallel;
+}
+
+bool IslAstInfo::isOutermostParallel(__isl_keep isl_ast_node *Node) {
+  IslAstUserPayload *Payload = getNodePayload(Node);
+  return Payload && Payload->IsOutermostParallel;
+}
+
+bool IslAstInfo::isReductionParallel(__isl_keep isl_ast_node *Node) {
+  IslAstUserPayload *Payload = getNodePayload(Node);
+  return Payload && Payload->IsReductionParallel;
+}
+
+bool IslAstInfo::isExecutedInParallel(__isl_keep isl_ast_node *Node) {
+  if (!PollyParallel)
+    return false;
+
+  // Do not parallelize innermost loops.
+  //
+  // Parallelizing innermost loops is often not profitable, especially if
+  // they have a low number of iterations.
+  //
+  // TODO: Decide this based on the number of loop iterations that will be
+  //       executed. This can possibly require run-time checks, which again
+  //       raises the question of both run-time check overhead and code size
+  //       costs.
+  if (!PollyParallelForce && isInnermost(Node))
+    return false;
+
+  return isOutermostParallel(Node) && !isReductionParallel(Node);
+}
+
+__isl_give isl_union_map *
+IslAstInfo::getSchedule(__isl_keep isl_ast_node *Node) {
+  IslAstUserPayload *Payload = getNodePayload(Node);
+  return Payload ? isl_ast_build_get_schedule(Payload->Build) : nullptr;
+}
+
+__isl_give isl_pw_aff *
+IslAstInfo::getMinimalDependenceDistance(__isl_keep isl_ast_node *Node) {
+  IslAstUserPayload *Payload = getNodePayload(Node);
+  return Payload ? isl_pw_aff_copy(Payload->MinimalDependenceDistance)
+                 : nullptr;
+}
+
+IslAstInfo::MemoryAccessSet *
+IslAstInfo::getBrokenReductions(__isl_keep isl_ast_node *Node) {
+  IslAstUserPayload *Payload = getNodePayload(Node);
+  return Payload ? &Payload->BrokenReductions : nullptr;
+}
+
+isl_ast_build *IslAstInfo::getBuild(__isl_keep isl_ast_node *Node) {
+  IslAstUserPayload *Payload = getNodePayload(Node);
+  return Payload ? Payload->Build : nullptr;
+}
+
+IslAstInfo IslAstAnalysis::run(Scop &S, ScopAnalysisManager &SAM,
+                               ScopStandardAnalysisResults &SAR) {
+  return {S, SAM.getResult<DependenceAnalysis>(S, SAR).getDependences(
+                 Dependences::AL_Statement)};
+}
+
+static __isl_give isl_printer *cbPrintUser(__isl_take isl_printer *P,
+                                           __isl_take isl_ast_print_options *O,
+                                           __isl_keep isl_ast_node *Node,
+                                           void *User) {
+  isl::ast_node AstNode = isl::manage(isl_ast_node_copy(Node));
+  isl::ast_expr NodeExpr = AstNode.user_get_expr();
+  isl::ast_expr CallExpr = NodeExpr.get_op_arg(0);
+  isl::id CallExprId = CallExpr.get_id();
+  ScopStmt *AccessStmt = (ScopStmt *)CallExprId.get_user();
+
+  P = isl_printer_start_line(P);
+  P = isl_printer_print_str(P, AccessStmt->getBaseName());
+  P = isl_printer_print_str(P, "(");
+  P = isl_printer_end_line(P);
+  P = isl_printer_indent(P, 2);
+
+  for (MemoryAccess *MemAcc : *AccessStmt) {
+    P = isl_printer_start_line(P);
+
+    if (MemAcc->isRead())
+      P = isl_printer_print_str(P, "/* read  */ &");
+    else
+      P = isl_printer_print_str(P, "/* write */  ");
+
+    isl::ast_build Build =
+        isl::manage(isl_ast_build_copy(IslAstInfo::getBuild(Node)));
+    if (MemAcc->isAffine()) {
+      isl_pw_multi_aff *PwmaPtr =
+          MemAcc->applyScheduleToAccessRelation(Build.get_schedule()).release();
+      isl::pw_multi_aff Pwma = isl::manage(PwmaPtr);
+      isl::ast_expr AccessExpr = Build.access_from(Pwma);
+      P = isl_printer_print_ast_expr(P, AccessExpr.get());
+    } else {
+      P = isl_printer_print_str(
+          P, MemAcc->getLatestScopArrayInfo()->getName().c_str());
+      P = isl_printer_print_str(P, "[*]");
+    }
+    P = isl_printer_end_line(P);
+  }
+
+  P = isl_printer_indent(P, -2);
+  P = isl_printer_start_line(P);
+  P = isl_printer_print_str(P, ");");
+  P = isl_printer_end_line(P);
+
+  isl_ast_print_options_free(O);
+  return P;
+}
+
+void IslAstInfo::print(raw_ostream &OS) {
+  isl_ast_print_options *Options;
+  isl_ast_node *RootNode = Ast.getAst();
+  Function &F = S.getFunction();
+
+  OS << ":: isl ast :: " << F.getName() << " :: " << S.getNameStr() << "\n";
+
+  if (!RootNode) {
+    OS << ":: isl ast generation and code generation was skipped!\n\n";
+    OS << ":: This is either because no useful optimizations could be applied "
+          "(use -polly-process-unprofitable to enforce code generation) or "
+          "because earlier passes such as dependence analysis timed out (use "
+          "-polly-dependences-computeout=0 to set dependence analysis timeout "
+          "to infinity)\n\n";
+    return;
+  }
+
+  isl_ast_expr *RunCondition = Ast.getRunCondition();
+  char *RtCStr, *AstStr;
+
+  Options = isl_ast_print_options_alloc(S.getIslCtx().get());
+
+  if (PrintAccesses)
+    Options =
+        isl_ast_print_options_set_print_user(Options, cbPrintUser, nullptr);
+  Options = isl_ast_print_options_set_print_for(Options, cbPrintFor, nullptr);
+
+  isl_printer *P = isl_printer_to_str(S.getIslCtx().get());
+  P = isl_printer_set_output_format(P, ISL_FORMAT_C);
+  P = isl_printer_print_ast_expr(P, RunCondition);
+  RtCStr = isl_printer_get_str(P);
+  P = isl_printer_flush(P);
+  P = isl_printer_indent(P, 4);
+  P = isl_ast_node_print(RootNode, P, Options);
+  AstStr = isl_printer_get_str(P);
+
+  auto *Schedule = S.getScheduleTree().release();
+
+  DEBUG({
+    dbgs() << S.getContextStr() << "\n";
+    dbgs() << stringFromIslObj(Schedule);
+  });
+  OS << "\nif (" << RtCStr << ")\n\n";
+  OS << AstStr << "\n";
+  OS << "else\n";
+  OS << "    {  /* original code */ }\n\n";
+
+  free(RtCStr);
+  free(AstStr);
+
+  isl_ast_expr_free(RunCondition);
+  isl_schedule_free(Schedule);
+  isl_ast_node_free(RootNode);
+  isl_printer_free(P);
+}
+
+AnalysisKey IslAstAnalysis::Key;
+PreservedAnalyses IslAstPrinterPass::run(Scop &S, ScopAnalysisManager &SAM,
+                                         ScopStandardAnalysisResults &SAR,
+                                         SPMUpdater &U) {
+  auto &Ast = SAM.getResult<IslAstAnalysis>(S, SAR);
+  Ast.print(OS);
+  return PreservedAnalyses::all();
+}
+
+void IslAstInfoWrapperPass::releaseMemory() { Ast.reset(); }
+
+bool IslAstInfoWrapperPass::runOnScop(Scop &Scop) {
+  // Skip SCoPs in case they're already handled by PPCGCodeGeneration.
+  if (Scop.isToBeSkipped())
+    return false;
+
+  ScopsProcessed++;
+
+  const Dependences &D =
+      getAnalysis<DependenceInfo>().getDependences(Dependences::AL_Statement);
+
+  if (D.getSharedIslCtx() != Scop.getSharedIslCtx()) {
+    DEBUG(dbgs() << "Got dependence analysis for different SCoP/isl_ctx\n");
+    Ast.reset();
+    return false;
+  }
+
+  Ast.reset(new IslAstInfo(Scop, D));
+
+  DEBUG(printScop(dbgs(), Scop));
+  return false;
+}
+
+void IslAstInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
+  // Get the Common analysis usage of ScopPasses.
+  ScopPass::getAnalysisUsage(AU);
+  AU.addRequiredTransitive<ScopInfoRegionPass>();
+  AU.addRequired<DependenceInfo>();
+
+  AU.addPreserved<DependenceInfo>();
+}
+
+void IslAstInfoWrapperPass::printScop(raw_ostream &OS, Scop &S) const {
+  if (Ast)
+    Ast->print(OS);
+}
+
+char IslAstInfoWrapperPass::ID = 0;
+
+Pass *polly::createIslAstInfoWrapperPassPass() {
+  return new IslAstInfoWrapperPass();
+}
+
+INITIALIZE_PASS_BEGIN(IslAstInfoWrapperPass, "polly-ast",
+                      "Polly - Generate an AST of the SCoP (isl)", false,
+                      false);
+INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass);
+INITIALIZE_PASS_DEPENDENCY(DependenceInfo);
+INITIALIZE_PASS_END(IslAstInfoWrapperPass, "polly-ast",
+                    "Polly - Generate an AST from the SCoP (isl)", false, false)
diff --git a/final/lib/CodeGen/IslExprBuilder.cpp b/final/lib/CodeGen/IslExprBuilder.cpp
new file mode 100644
index 0000000..0a4dd91
--- /dev/null
+++ b/final/lib/CodeGen/IslExprBuilder.cpp
@@ -0,0 +1,786 @@
+//===------ IslExprBuilder.cpp ----- Code generate isl AST expressions ----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/IslExprBuilder.h"
+#include "polly/CodeGen/RuntimeDebugBuilder.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+
+using namespace llvm;
+using namespace polly;
+
+/// Different overflow tracking modes.
+enum OverflowTrackingChoice {
+  OT_NEVER,   ///< Never tack potential overflows.
+  OT_REQUEST, ///< Track potential overflows if requested.
+  OT_ALWAYS   ///< Always track potential overflows.
+};
+
+static cl::opt<OverflowTrackingChoice> OTMode(
+    "polly-overflow-tracking",
+    cl::desc("Define where potential integer overflows in generated "
+             "expressions should be tracked."),
+    cl::values(clEnumValN(OT_NEVER, "never", "Never track the overflow bit."),
+               clEnumValN(OT_REQUEST, "request",
+                          "Track the overflow bit if requested."),
+               clEnumValN(OT_ALWAYS, "always",
+                          "Always track the overflow bit.")),
+    cl::Hidden, cl::init(OT_REQUEST), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+IslExprBuilder::IslExprBuilder(Scop &S, PollyIRBuilder &Builder,
+                               IDToValueTy &IDToValue, ValueMapT &GlobalMap,
+                               const DataLayout &DL, ScalarEvolution &SE,
+                               DominatorTree &DT, LoopInfo &LI,
+                               BasicBlock *StartBlock)
+    : S(S), Builder(Builder), IDToValue(IDToValue), GlobalMap(GlobalMap),
+      DL(DL), SE(SE), DT(DT), LI(LI), StartBlock(StartBlock) {
+  OverflowState = (OTMode == OT_ALWAYS) ? Builder.getFalse() : nullptr;
+}
+
+void IslExprBuilder::setTrackOverflow(bool Enable) {
+  // If potential overflows are tracked always or never we ignore requests
+  // to change the behavior.
+  if (OTMode != OT_REQUEST)
+    return;
+
+  if (Enable) {
+    // If tracking should be enabled initialize the OverflowState.
+    OverflowState = Builder.getFalse();
+  } else {
+    // If tracking should be disabled just unset the OverflowState.
+    OverflowState = nullptr;
+  }
+}
+
+Value *IslExprBuilder::getOverflowState() const {
+  // If the overflow tracking was requested but it is disabled we avoid the
+  // additional nullptr checks at the call sides but instead provide a
+  // meaningful result.
+  if (OTMode == OT_NEVER)
+    return Builder.getFalse();
+  return OverflowState;
+}
+
+bool IslExprBuilder::hasLargeInts(isl::ast_expr Expr) {
+  enum isl_ast_expr_type Type = isl_ast_expr_get_type(Expr.get());
+
+  if (Type == isl_ast_expr_id)
+    return false;
+
+  if (Type == isl_ast_expr_int) {
+    isl::val Val = Expr.get_val();
+    APInt APValue = APIntFromVal(Val);
+    auto BitWidth = APValue.getBitWidth();
+    return BitWidth >= 64;
+  }
+
+  assert(Type == isl_ast_expr_op && "Expected isl_ast_expr of type operation");
+
+  int NumArgs = isl_ast_expr_get_op_n_arg(Expr.get());
+
+  for (int i = 0; i < NumArgs; i++) {
+    isl::ast_expr Operand = Expr.get_op_arg(i);
+    if (hasLargeInts(Operand))
+      return true;
+  }
+
+  return false;
+}
+
+Value *IslExprBuilder::createBinOp(BinaryOperator::BinaryOps Opc, Value *LHS,
+                                   Value *RHS, const Twine &Name) {
+  // Handle the plain operation (without overflow tracking) first.
+  if (!OverflowState) {
+    switch (Opc) {
+    case Instruction::Add:
+      return Builder.CreateNSWAdd(LHS, RHS, Name);
+    case Instruction::Sub:
+      return Builder.CreateNSWSub(LHS, RHS, Name);
+    case Instruction::Mul:
+      return Builder.CreateNSWMul(LHS, RHS, Name);
+    default:
+      llvm_unreachable("Unknown binary operator!");
+    }
+  }
+
+  Function *F = nullptr;
+  Module *M = Builder.GetInsertBlock()->getModule();
+  switch (Opc) {
+  case Instruction::Add:
+    F = Intrinsic::getDeclaration(M, Intrinsic::sadd_with_overflow,
+                                  {LHS->getType()});
+    break;
+  case Instruction::Sub:
+    F = Intrinsic::getDeclaration(M, Intrinsic::ssub_with_overflow,
+                                  {LHS->getType()});
+    break;
+  case Instruction::Mul:
+    F = Intrinsic::getDeclaration(M, Intrinsic::smul_with_overflow,
+                                  {LHS->getType()});
+    break;
+  default:
+    llvm_unreachable("No overflow intrinsic for binary operator found!");
+  }
+
+  auto *ResultStruct = Builder.CreateCall(F, {LHS, RHS}, Name);
+  assert(ResultStruct->getType()->isStructTy());
+
+  auto *OverflowFlag =
+      Builder.CreateExtractValue(ResultStruct, 1, Name + ".obit");
+
+  // If all overflows are tracked we do not combine the results as this could
+  // cause dominance problems. Instead we will always keep the last overflow
+  // flag as current state.
+  if (OTMode == OT_ALWAYS)
+    OverflowState = OverflowFlag;
+  else
+    OverflowState =
+        Builder.CreateOr(OverflowState, OverflowFlag, "polly.overflow.state");
+
+  return Builder.CreateExtractValue(ResultStruct, 0, Name + ".res");
+}
+
+Value *IslExprBuilder::createAdd(Value *LHS, Value *RHS, const Twine &Name) {
+  return createBinOp(Instruction::Add, LHS, RHS, Name);
+}
+
+Value *IslExprBuilder::createSub(Value *LHS, Value *RHS, const Twine &Name) {
+  return createBinOp(Instruction::Sub, LHS, RHS, Name);
+}
+
+Value *IslExprBuilder::createMul(Value *LHS, Value *RHS, const Twine &Name) {
+  return createBinOp(Instruction::Mul, LHS, RHS, Name);
+}
+
+Type *IslExprBuilder::getWidestType(Type *T1, Type *T2) {
+  assert(isa<IntegerType>(T1) && isa<IntegerType>(T2));
+
+  if (T1->getPrimitiveSizeInBits() < T2->getPrimitiveSizeInBits())
+    return T2;
+  else
+    return T1;
+}
+
+Value *IslExprBuilder::createOpUnary(__isl_take isl_ast_expr *Expr) {
+  assert(isl_ast_expr_get_op_type(Expr) == isl_ast_op_minus &&
+         "Unsupported unary operation");
+
+  Value *V;
+  Type *MaxType = getType(Expr);
+  assert(MaxType->isIntegerTy() &&
+         "Unary expressions can only be created for integer types");
+
+  V = create(isl_ast_expr_get_op_arg(Expr, 0));
+  MaxType = getWidestType(MaxType, V->getType());
+
+  if (MaxType != V->getType())
+    V = Builder.CreateSExt(V, MaxType);
+
+  isl_ast_expr_free(Expr);
+  return createSub(ConstantInt::getNullValue(MaxType), V);
+}
+
+Value *IslExprBuilder::createOpNAry(__isl_take isl_ast_expr *Expr) {
+  assert(isl_ast_expr_get_type(Expr) == isl_ast_expr_op &&
+         "isl ast expression not of type isl_ast_op");
+  assert(isl_ast_expr_get_op_n_arg(Expr) >= 2 &&
+         "We need at least two operands in an n-ary operation");
+
+  CmpInst::Predicate Pred;
+  switch (isl_ast_expr_get_op_type(Expr)) {
+  default:
+    llvm_unreachable("This is not a an n-ary isl ast expression");
+  case isl_ast_op_max:
+    Pred = CmpInst::ICMP_SGT;
+    break;
+  case isl_ast_op_min:
+    Pred = CmpInst::ICMP_SLT;
+    break;
+  }
+
+  Value *V = create(isl_ast_expr_get_op_arg(Expr, 0));
+
+  for (int i = 1; i < isl_ast_expr_get_op_n_arg(Expr); ++i) {
+    Value *OpV = create(isl_ast_expr_get_op_arg(Expr, i));
+    Type *Ty = getWidestType(V->getType(), OpV->getType());
+
+    if (Ty != OpV->getType())
+      OpV = Builder.CreateSExt(OpV, Ty);
+
+    if (Ty != V->getType())
+      V = Builder.CreateSExt(V, Ty);
+
+    Value *Cmp = Builder.CreateICmp(Pred, V, OpV);
+    V = Builder.CreateSelect(Cmp, V, OpV);
+  }
+
+  // TODO: We can truncate the result, if it fits into a smaller type. This can
+  // help in cases where we have larger operands (e.g. i67) but the result is
+  // known to fit into i64. Without the truncation, the larger i67 type may
+  // force all subsequent operations to be performed on a non-native type.
+  isl_ast_expr_free(Expr);
+  return V;
+}
+
+Value *IslExprBuilder::createAccessAddress(isl_ast_expr *Expr) {
+  assert(isl_ast_expr_get_type(Expr) == isl_ast_expr_op &&
+         "isl ast expression not of type isl_ast_op");
+  assert(isl_ast_expr_get_op_type(Expr) == isl_ast_op_access &&
+         "not an access isl ast expression");
+  assert(isl_ast_expr_get_op_n_arg(Expr) >= 1 &&
+         "We need at least two operands to create a member access.");
+
+  Value *Base, *IndexOp, *Access;
+  isl_ast_expr *BaseExpr;
+  isl_id *BaseId;
+
+  BaseExpr = isl_ast_expr_get_op_arg(Expr, 0);
+  BaseId = isl_ast_expr_get_id(BaseExpr);
+  isl_ast_expr_free(BaseExpr);
+
+  const ScopArrayInfo *SAI = nullptr;
+
+  if (PollyDebugPrinting)
+    RuntimeDebugBuilder::createCPUPrinter(Builder, isl_id_get_name(BaseId));
+
+  if (IDToSAI)
+    SAI = (*IDToSAI)[BaseId];
+
+  if (!SAI)
+    SAI = ScopArrayInfo::getFromId(isl::manage(BaseId));
+  else
+    isl_id_free(BaseId);
+
+  assert(SAI && "No ScopArrayInfo found for this isl_id.");
+
+  Base = SAI->getBasePtr();
+
+  if (auto NewBase = GlobalMap.lookup(Base))
+    Base = NewBase;
+
+  assert(Base->getType()->isPointerTy() && "Access base should be a pointer");
+  StringRef BaseName = Base->getName();
+
+  auto PointerTy = PointerType::get(SAI->getElementType(),
+                                    Base->getType()->getPointerAddressSpace());
+  if (Base->getType() != PointerTy) {
+    Base =
+        Builder.CreateBitCast(Base, PointerTy, "polly.access.cast." + BaseName);
+  }
+
+  if (isl_ast_expr_get_op_n_arg(Expr) == 1) {
+    isl_ast_expr_free(Expr);
+    if (PollyDebugPrinting)
+      RuntimeDebugBuilder::createCPUPrinter(Builder, "\n");
+    return Base;
+  }
+
+  IndexOp = nullptr;
+  for (unsigned u = 1, e = isl_ast_expr_get_op_n_arg(Expr); u < e; u++) {
+    Value *NextIndex = create(isl_ast_expr_get_op_arg(Expr, u));
+    assert(NextIndex->getType()->isIntegerTy() &&
+           "Access index should be an integer");
+
+    if (PollyDebugPrinting)
+      RuntimeDebugBuilder::createCPUPrinter(Builder, "[", NextIndex, "]");
+
+    if (!IndexOp) {
+      IndexOp = NextIndex;
+    } else {
+      Type *Ty = getWidestType(NextIndex->getType(), IndexOp->getType());
+
+      if (Ty != NextIndex->getType())
+        NextIndex = Builder.CreateIntCast(NextIndex, Ty, true);
+      if (Ty != IndexOp->getType())
+        IndexOp = Builder.CreateIntCast(IndexOp, Ty, true);
+
+      IndexOp = createAdd(IndexOp, NextIndex, "polly.access.add." + BaseName);
+    }
+
+    // For every but the last dimension multiply the size, for the last
+    // dimension we can exit the loop.
+    if (u + 1 >= e)
+      break;
+
+    const SCEV *DimSCEV = SAI->getDimensionSize(u);
+
+    llvm::ValueToValueMap Map(GlobalMap.begin(), GlobalMap.end());
+    DimSCEV = SCEVParameterRewriter::rewrite(DimSCEV, SE, Map);
+    Value *DimSize =
+        expandCodeFor(S, SE, DL, "polly", DimSCEV, DimSCEV->getType(),
+                      &*Builder.GetInsertPoint(), nullptr,
+                      StartBlock->getSinglePredecessor());
+
+    Type *Ty = getWidestType(DimSize->getType(), IndexOp->getType());
+
+    if (Ty != IndexOp->getType())
+      IndexOp = Builder.CreateSExtOrTrunc(IndexOp, Ty,
+                                          "polly.access.sext." + BaseName);
+    if (Ty != DimSize->getType())
+      DimSize = Builder.CreateSExtOrTrunc(DimSize, Ty,
+                                          "polly.access.sext." + BaseName);
+    IndexOp = createMul(IndexOp, DimSize, "polly.access.mul." + BaseName);
+  }
+
+  Access = Builder.CreateGEP(Base, IndexOp, "polly.access." + BaseName);
+
+  if (PollyDebugPrinting)
+    RuntimeDebugBuilder::createCPUPrinter(Builder, "\n");
+  isl_ast_expr_free(Expr);
+  return Access;
+}
+
+Value *IslExprBuilder::createOpAccess(isl_ast_expr *Expr) {
+  Value *Addr = createAccessAddress(Expr);
+  assert(Addr && "Could not create op access address");
+  return Builder.CreateLoad(Addr, Addr->getName() + ".load");
+}
+
+Value *IslExprBuilder::createOpBin(__isl_take isl_ast_expr *Expr) {
+  Value *LHS, *RHS, *Res;
+  Type *MaxType;
+  isl_ast_op_type OpType;
+
+  assert(isl_ast_expr_get_type(Expr) == isl_ast_expr_op &&
+         "isl ast expression not of type isl_ast_op");
+  assert(isl_ast_expr_get_op_n_arg(Expr) == 2 &&
+         "not a binary isl ast expression");
+
+  OpType = isl_ast_expr_get_op_type(Expr);
+
+  LHS = create(isl_ast_expr_get_op_arg(Expr, 0));
+  RHS = create(isl_ast_expr_get_op_arg(Expr, 1));
+
+  Type *LHSType = LHS->getType();
+  Type *RHSType = RHS->getType();
+
+  MaxType = getWidestType(LHSType, RHSType);
+
+  // Take the result into account when calculating the widest type.
+  //
+  // For operations such as '+' the result may require a type larger than
+  // the type of the individual operands. For other operations such as '/', the
+  // result type cannot be larger than the type of the individual operand. isl
+  // does not calculate correct types for these operations and we consequently
+  // exclude those operations here.
+  switch (OpType) {
+  case isl_ast_op_pdiv_q:
+  case isl_ast_op_pdiv_r:
+  case isl_ast_op_div:
+  case isl_ast_op_fdiv_q:
+  case isl_ast_op_zdiv_r:
+    // Do nothing
+    break;
+  case isl_ast_op_add:
+  case isl_ast_op_sub:
+  case isl_ast_op_mul:
+    MaxType = getWidestType(MaxType, getType(Expr));
+    break;
+  default:
+    llvm_unreachable("This is no binary isl ast expression");
+  }
+
+  if (MaxType != RHS->getType())
+    RHS = Builder.CreateSExt(RHS, MaxType);
+
+  if (MaxType != LHS->getType())
+    LHS = Builder.CreateSExt(LHS, MaxType);
+
+  switch (OpType) {
+  default:
+    llvm_unreachable("This is no binary isl ast expression");
+  case isl_ast_op_add:
+    Res = createAdd(LHS, RHS);
+    break;
+  case isl_ast_op_sub:
+    Res = createSub(LHS, RHS);
+    break;
+  case isl_ast_op_mul:
+    Res = createMul(LHS, RHS);
+    break;
+  case isl_ast_op_div:
+    Res = Builder.CreateSDiv(LHS, RHS, "pexp.div", true);
+    break;
+  case isl_ast_op_pdiv_q: // Dividend is non-negative
+    Res = Builder.CreateUDiv(LHS, RHS, "pexp.p_div_q");
+    break;
+  case isl_ast_op_fdiv_q: { // Round towards -infty
+    if (auto *Const = dyn_cast<ConstantInt>(RHS)) {
+      auto &Val = Const->getValue();
+      if (Val.isPowerOf2() && Val.isNonNegative()) {
+        Res = Builder.CreateAShr(LHS, Val.ceilLogBase2(), "polly.fdiv_q.shr");
+        break;
+      }
+    }
+    // TODO: Review code and check that this calculation does not yield
+    //       incorrect overflow in some edge cases.
+    //
+    // floord(n,d) ((n < 0) ? (n - d + 1) : n) / d
+    Value *One = ConstantInt::get(MaxType, 1);
+    Value *Zero = ConstantInt::get(MaxType, 0);
+    Value *Sum1 = createSub(LHS, RHS, "pexp.fdiv_q.0");
+    Value *Sum2 = createAdd(Sum1, One, "pexp.fdiv_q.1");
+    Value *isNegative = Builder.CreateICmpSLT(LHS, Zero, "pexp.fdiv_q.2");
+    Value *Dividend =
+        Builder.CreateSelect(isNegative, Sum2, LHS, "pexp.fdiv_q.3");
+    Res = Builder.CreateSDiv(Dividend, RHS, "pexp.fdiv_q.4");
+    break;
+  }
+  case isl_ast_op_pdiv_r: // Dividend is non-negative
+    Res = Builder.CreateURem(LHS, RHS, "pexp.pdiv_r");
+    break;
+
+  case isl_ast_op_zdiv_r: // Result only compared against zero
+    Res = Builder.CreateSRem(LHS, RHS, "pexp.zdiv_r");
+    break;
+  }
+
+  // TODO: We can truncate the result, if it fits into a smaller type. This can
+  // help in cases where we have larger operands (e.g. i67) but the result is
+  // known to fit into i64. Without the truncation, the larger i67 type may
+  // force all subsequent operations to be performed on a non-native type.
+  isl_ast_expr_free(Expr);
+  return Res;
+}
+
+Value *IslExprBuilder::createOpSelect(__isl_take isl_ast_expr *Expr) {
+  assert(isl_ast_expr_get_op_type(Expr) == isl_ast_op_select &&
+         "Unsupported unary isl ast expression");
+  Value *LHS, *RHS, *Cond;
+  Type *MaxType = getType(Expr);
+
+  Cond = create(isl_ast_expr_get_op_arg(Expr, 0));
+  if (!Cond->getType()->isIntegerTy(1))
+    Cond = Builder.CreateIsNotNull(Cond);
+
+  LHS = create(isl_ast_expr_get_op_arg(Expr, 1));
+  RHS = create(isl_ast_expr_get_op_arg(Expr, 2));
+
+  MaxType = getWidestType(MaxType, LHS->getType());
+  MaxType = getWidestType(MaxType, RHS->getType());
+
+  if (MaxType != RHS->getType())
+    RHS = Builder.CreateSExt(RHS, MaxType);
+
+  if (MaxType != LHS->getType())
+    LHS = Builder.CreateSExt(LHS, MaxType);
+
+  // TODO: Do we want to truncate the result?
+  isl_ast_expr_free(Expr);
+  return Builder.CreateSelect(Cond, LHS, RHS);
+}
+
+Value *IslExprBuilder::createOpICmp(__isl_take isl_ast_expr *Expr) {
+  assert(isl_ast_expr_get_type(Expr) == isl_ast_expr_op &&
+         "Expected an isl_ast_expr_op expression");
+
+  Value *LHS, *RHS, *Res;
+
+  auto *Op0 = isl_ast_expr_get_op_arg(Expr, 0);
+  auto *Op1 = isl_ast_expr_get_op_arg(Expr, 1);
+  bool HasNonAddressOfOperand =
+      isl_ast_expr_get_type(Op0) != isl_ast_expr_op ||
+      isl_ast_expr_get_type(Op1) != isl_ast_expr_op ||
+      isl_ast_expr_get_op_type(Op0) != isl_ast_op_address_of ||
+      isl_ast_expr_get_op_type(Op1) != isl_ast_op_address_of;
+
+  LHS = create(Op0);
+  RHS = create(Op1);
+
+  auto *LHSTy = LHS->getType();
+  auto *RHSTy = RHS->getType();
+  bool IsPtrType = LHSTy->isPointerTy() || RHSTy->isPointerTy();
+  bool UseUnsignedCmp = IsPtrType && !HasNonAddressOfOperand;
+
+  auto *PtrAsIntTy = Builder.getIntNTy(DL.getPointerSizeInBits());
+  if (LHSTy->isPointerTy())
+    LHS = Builder.CreatePtrToInt(LHS, PtrAsIntTy);
+  if (RHSTy->isPointerTy())
+    RHS = Builder.CreatePtrToInt(RHS, PtrAsIntTy);
+
+  if (LHS->getType() != RHS->getType()) {
+    Type *MaxType = LHS->getType();
+    MaxType = getWidestType(MaxType, RHS->getType());
+
+    if (MaxType != RHS->getType())
+      RHS = Builder.CreateSExt(RHS, MaxType);
+
+    if (MaxType != LHS->getType())
+      LHS = Builder.CreateSExt(LHS, MaxType);
+  }
+
+  isl_ast_op_type OpType = isl_ast_expr_get_op_type(Expr);
+  assert(OpType >= isl_ast_op_eq && OpType <= isl_ast_op_gt &&
+         "Unsupported ICmp isl ast expression");
+  assert(isl_ast_op_eq + 4 == isl_ast_op_gt &&
+         "Isl ast op type interface changed");
+
+  CmpInst::Predicate Predicates[5][2] = {
+      {CmpInst::ICMP_EQ, CmpInst::ICMP_EQ},
+      {CmpInst::ICMP_SLE, CmpInst::ICMP_ULE},
+      {CmpInst::ICMP_SLT, CmpInst::ICMP_ULT},
+      {CmpInst::ICMP_SGE, CmpInst::ICMP_UGE},
+      {CmpInst::ICMP_SGT, CmpInst::ICMP_UGT},
+  };
+
+  Res = Builder.CreateICmp(Predicates[OpType - isl_ast_op_eq][UseUnsignedCmp],
+                           LHS, RHS);
+
+  isl_ast_expr_free(Expr);
+  return Res;
+}
+
+Value *IslExprBuilder::createOpBoolean(__isl_take isl_ast_expr *Expr) {
+  assert(isl_ast_expr_get_type(Expr) == isl_ast_expr_op &&
+         "Expected an isl_ast_expr_op expression");
+
+  Value *LHS, *RHS, *Res;
+  isl_ast_op_type OpType;
+
+  OpType = isl_ast_expr_get_op_type(Expr);
+
+  assert((OpType == isl_ast_op_and || OpType == isl_ast_op_or) &&
+         "Unsupported isl_ast_op_type");
+
+  LHS = create(isl_ast_expr_get_op_arg(Expr, 0));
+  RHS = create(isl_ast_expr_get_op_arg(Expr, 1));
+
+  // Even though the isl pretty printer prints the expressions as 'exp && exp'
+  // or 'exp || exp', we actually code generate the bitwise expressions
+  // 'exp & exp' or 'exp | exp'. This forces the evaluation of both branches,
+  // but it is, due to the use of i1 types, otherwise equivalent. The reason
+  // to go for bitwise operations is, that we assume the reduced control flow
+  // will outweigh the overhead introduced by evaluating unneeded expressions.
+  // The isl code generation currently does not take advantage of the fact that
+  // the expression after an '||' or '&&' is in some cases not evaluated.
+  // Evaluating it anyways does not cause any undefined behaviour.
+  //
+  // TODO: Document in isl itself, that the unconditionally evaluating the
+  // second part of '||' or '&&' expressions is safe.
+  if (!LHS->getType()->isIntegerTy(1))
+    LHS = Builder.CreateIsNotNull(LHS);
+  if (!RHS->getType()->isIntegerTy(1))
+    RHS = Builder.CreateIsNotNull(RHS);
+
+  switch (OpType) {
+  default:
+    llvm_unreachable("Unsupported boolean expression");
+  case isl_ast_op_and:
+    Res = Builder.CreateAnd(LHS, RHS);
+    break;
+  case isl_ast_op_or:
+    Res = Builder.CreateOr(LHS, RHS);
+    break;
+  }
+
+  isl_ast_expr_free(Expr);
+  return Res;
+}
+
+Value *
+IslExprBuilder::createOpBooleanConditional(__isl_take isl_ast_expr *Expr) {
+  assert(isl_ast_expr_get_type(Expr) == isl_ast_expr_op &&
+         "Expected an isl_ast_expr_op expression");
+
+  Value *LHS, *RHS;
+  isl_ast_op_type OpType;
+
+  Function *F = Builder.GetInsertBlock()->getParent();
+  LLVMContext &Context = F->getContext();
+
+  OpType = isl_ast_expr_get_op_type(Expr);
+
+  assert((OpType == isl_ast_op_and_then || OpType == isl_ast_op_or_else) &&
+         "Unsupported isl_ast_op_type");
+
+  auto InsertBB = Builder.GetInsertBlock();
+  auto InsertPoint = Builder.GetInsertPoint();
+  auto NextBB = SplitBlock(InsertBB, &*InsertPoint, &DT, &LI);
+  BasicBlock *CondBB = BasicBlock::Create(Context, "polly.cond", F);
+  LI.changeLoopFor(CondBB, LI.getLoopFor(InsertBB));
+  DT.addNewBlock(CondBB, InsertBB);
+
+  InsertBB->getTerminator()->eraseFromParent();
+  Builder.SetInsertPoint(InsertBB);
+  auto BR = Builder.CreateCondBr(Builder.getTrue(), NextBB, CondBB);
+
+  Builder.SetInsertPoint(CondBB);
+  Builder.CreateBr(NextBB);
+
+  Builder.SetInsertPoint(InsertBB->getTerminator());
+
+  LHS = create(isl_ast_expr_get_op_arg(Expr, 0));
+  if (!LHS->getType()->isIntegerTy(1))
+    LHS = Builder.CreateIsNotNull(LHS);
+  auto LeftBB = Builder.GetInsertBlock();
+
+  if (OpType == isl_ast_op_and || OpType == isl_ast_op_and_then)
+    BR->setCondition(Builder.CreateNeg(LHS));
+  else
+    BR->setCondition(LHS);
+
+  Builder.SetInsertPoint(CondBB->getTerminator());
+  RHS = create(isl_ast_expr_get_op_arg(Expr, 1));
+  if (!RHS->getType()->isIntegerTy(1))
+    RHS = Builder.CreateIsNotNull(RHS);
+  auto RightBB = Builder.GetInsertBlock();
+
+  Builder.SetInsertPoint(NextBB->getTerminator());
+  auto PHI = Builder.CreatePHI(Builder.getInt1Ty(), 2);
+  PHI->addIncoming(OpType == isl_ast_op_and_then ? Builder.getFalse()
+                                                 : Builder.getTrue(),
+                   LeftBB);
+  PHI->addIncoming(RHS, RightBB);
+
+  isl_ast_expr_free(Expr);
+  return PHI;
+}
+
+Value *IslExprBuilder::createOp(__isl_take isl_ast_expr *Expr) {
+  assert(isl_ast_expr_get_type(Expr) == isl_ast_expr_op &&
+         "Expression not of type isl_ast_expr_op");
+  switch (isl_ast_expr_get_op_type(Expr)) {
+  case isl_ast_op_error:
+  case isl_ast_op_cond:
+  case isl_ast_op_call:
+  case isl_ast_op_member:
+    llvm_unreachable("Unsupported isl ast expression");
+  case isl_ast_op_access:
+    return createOpAccess(Expr);
+  case isl_ast_op_max:
+  case isl_ast_op_min:
+    return createOpNAry(Expr);
+  case isl_ast_op_add:
+  case isl_ast_op_sub:
+  case isl_ast_op_mul:
+  case isl_ast_op_div:
+  case isl_ast_op_fdiv_q: // Round towards -infty
+  case isl_ast_op_pdiv_q: // Dividend is non-negative
+  case isl_ast_op_pdiv_r: // Dividend is non-negative
+  case isl_ast_op_zdiv_r: // Result only compared against zero
+    return createOpBin(Expr);
+  case isl_ast_op_minus:
+    return createOpUnary(Expr);
+  case isl_ast_op_select:
+    return createOpSelect(Expr);
+  case isl_ast_op_and:
+  case isl_ast_op_or:
+    return createOpBoolean(Expr);
+  case isl_ast_op_and_then:
+  case isl_ast_op_or_else:
+    return createOpBooleanConditional(Expr);
+  case isl_ast_op_eq:
+  case isl_ast_op_le:
+  case isl_ast_op_lt:
+  case isl_ast_op_ge:
+  case isl_ast_op_gt:
+    return createOpICmp(Expr);
+  case isl_ast_op_address_of:
+    return createOpAddressOf(Expr);
+  }
+
+  llvm_unreachable("Unsupported isl_ast_expr_op kind.");
+}
+
+Value *IslExprBuilder::createOpAddressOf(__isl_take isl_ast_expr *Expr) {
+  assert(isl_ast_expr_get_type(Expr) == isl_ast_expr_op &&
+         "Expected an isl_ast_expr_op expression.");
+  assert(isl_ast_expr_get_op_n_arg(Expr) == 1 && "Address of should be unary.");
+
+  isl_ast_expr *Op = isl_ast_expr_get_op_arg(Expr, 0);
+  assert(isl_ast_expr_get_type(Op) == isl_ast_expr_op &&
+         "Expected address of operator to be an isl_ast_expr_op expression.");
+  assert(isl_ast_expr_get_op_type(Op) == isl_ast_op_access &&
+         "Expected address of operator to be an access expression.");
+
+  Value *V = createAccessAddress(Op);
+
+  isl_ast_expr_free(Expr);
+
+  return V;
+}
+
+Value *IslExprBuilder::createId(__isl_take isl_ast_expr *Expr) {
+  assert(isl_ast_expr_get_type(Expr) == isl_ast_expr_id &&
+         "Expression not of type isl_ast_expr_ident");
+
+  isl_id *Id;
+  Value *V;
+
+  Id = isl_ast_expr_get_id(Expr);
+
+  assert(IDToValue.count(Id) && "Identifier not found");
+
+  V = IDToValue[Id];
+  if (!V)
+    V = UndefValue::get(getType(Expr));
+
+  if (V->getType()->isPointerTy())
+    V = Builder.CreatePtrToInt(V, Builder.getIntNTy(DL.getPointerSizeInBits()));
+
+  assert(V && "Unknown parameter id found");
+
+  isl_id_free(Id);
+  isl_ast_expr_free(Expr);
+
+  return V;
+}
+
+IntegerType *IslExprBuilder::getType(__isl_keep isl_ast_expr *Expr) {
+  // XXX: We assume i64 is large enough. This is often true, but in general
+  //      incorrect. Also, on 32bit architectures, it would be beneficial to
+  //      use a smaller type. We can and should directly derive this information
+  //      during code generation.
+  return IntegerType::get(Builder.getContext(), 64);
+}
+
+Value *IslExprBuilder::createInt(__isl_take isl_ast_expr *Expr) {
+  assert(isl_ast_expr_get_type(Expr) == isl_ast_expr_int &&
+         "Expression not of type isl_ast_expr_int");
+  isl_val *Val;
+  Value *V;
+  APInt APValue;
+  IntegerType *T;
+
+  Val = isl_ast_expr_get_val(Expr);
+  APValue = APIntFromVal(Val);
+
+  auto BitWidth = APValue.getBitWidth();
+  if (BitWidth <= 64)
+    T = getType(Expr);
+  else
+    T = Builder.getIntNTy(BitWidth);
+
+  APValue = APValue.sextOrSelf(T->getBitWidth());
+  V = ConstantInt::get(T, APValue);
+
+  isl_ast_expr_free(Expr);
+  return V;
+}
+
+Value *IslExprBuilder::create(__isl_take isl_ast_expr *Expr) {
+  switch (isl_ast_expr_get_type(Expr)) {
+  case isl_ast_expr_error:
+    llvm_unreachable("Code generation error");
+  case isl_ast_expr_op:
+    return createOp(Expr);
+  case isl_ast_expr_id:
+    return createId(Expr);
+  case isl_ast_expr_int:
+    return createInt(Expr);
+  }
+
+  llvm_unreachable("Unexpected enum value");
+}
diff --git a/final/lib/CodeGen/IslNodeBuilder.cpp b/final/lib/CodeGen/IslNodeBuilder.cpp
new file mode 100644
index 0000000..f89fa5e
--- /dev/null
+++ b/final/lib/CodeGen/IslNodeBuilder.cpp
@@ -0,0 +1,1631 @@
+//===- IslNodeBuilder.cpp - Translate an isl AST into a LLVM-IR AST -------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the IslNodeBuilder, a class to translate an isl AST into
+// a LLVM-IR AST.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/IslNodeBuilder.h"
+#include "polly/CodeGen/BlockGenerators.h"
+#include "polly/CodeGen/CodeGeneration.h"
+#include "polly/CodeGen/IslAst.h"
+#include "polly/CodeGen/IslExprBuilder.h"
+#include "polly/CodeGen/LoopGenerators.h"
+#include "polly/CodeGen/RuntimeDebugBuilder.h"
+#include "polly/Config/config.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/SCEVValidator.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "isl/aff.h"
+#include "isl/aff_type.h"
+#include "isl/ast.h"
+#include "isl/ast_build.h"
+#include "isl/isl-noexceptions.h"
+#include "isl/map.h"
+#include "isl/set.h"
+#include "isl/union_map.h"
+#include "isl/union_set.h"
+#include "isl/val.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-codegen"
+
+STATISTIC(VersionedScops, "Number of SCoPs that required versioning.");
+
+STATISTIC(SequentialLoops, "Number of generated sequential for-loops");
+STATISTIC(ParallelLoops, "Number of generated parallel for-loops");
+STATISTIC(VectorLoops, "Number of generated vector for-loops");
+STATISTIC(IfConditions, "Number of generated if-conditions");
+
+static cl::opt<bool> PollyGenerateRTCPrint(
+    "polly-codegen-emit-rtc-print",
+    cl::desc("Emit code that prints the runtime check result dynamically."),
+    cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+// If this option is set we always use the isl AST generator to regenerate
+// memory accesses. Without this option set we regenerate expressions using the
+// original SCEV expressions and only generate new expressions in case the
+// access relation has been changed and consequently must be regenerated.
+static cl::opt<bool> PollyGenerateExpressions(
+    "polly-codegen-generate-expressions",
+    cl::desc("Generate AST expressions for unmodified and modified accesses"),
+    cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> PollyTargetFirstLevelCacheLineSize(
+    "polly-target-first-level-cache-line-size",
+    cl::desc("The size of the first level cache line size specified in bytes."),
+    cl::Hidden, cl::init(64), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+__isl_give isl_ast_expr *
+IslNodeBuilder::getUpperBound(__isl_keep isl_ast_node *For,
+                              ICmpInst::Predicate &Predicate) {
+  isl_id *UBID, *IteratorID;
+  isl_ast_expr *Cond, *Iterator, *UB, *Arg0;
+  isl_ast_op_type Type;
+
+  Cond = isl_ast_node_for_get_cond(For);
+  Iterator = isl_ast_node_for_get_iterator(For);
+  assert(isl_ast_expr_get_type(Cond) == isl_ast_expr_op &&
+         "conditional expression is not an atomic upper bound");
+
+  Type = isl_ast_expr_get_op_type(Cond);
+
+  switch (Type) {
+  case isl_ast_op_le:
+    Predicate = ICmpInst::ICMP_SLE;
+    break;
+  case isl_ast_op_lt:
+    Predicate = ICmpInst::ICMP_SLT;
+    break;
+  default:
+    llvm_unreachable("Unexpected comparison type in loop condition");
+  }
+
+  Arg0 = isl_ast_expr_get_op_arg(Cond, 0);
+
+  assert(isl_ast_expr_get_type(Arg0) == isl_ast_expr_id &&
+         "conditional expression is not an atomic upper bound");
+
+  UBID = isl_ast_expr_get_id(Arg0);
+
+  assert(isl_ast_expr_get_type(Iterator) == isl_ast_expr_id &&
+         "Could not get the iterator");
+
+  IteratorID = isl_ast_expr_get_id(Iterator);
+
+  assert(UBID == IteratorID &&
+         "conditional expression is not an atomic upper bound");
+
+  UB = isl_ast_expr_get_op_arg(Cond, 1);
+
+  isl_ast_expr_free(Cond);
+  isl_ast_expr_free(Iterator);
+  isl_ast_expr_free(Arg0);
+  isl_id_free(IteratorID);
+  isl_id_free(UBID);
+
+  return UB;
+}
+
+/// Return true if a return value of Predicate is true for the value represented
+/// by passed isl_ast_expr_int.
+static bool checkIslAstExprInt(__isl_take isl_ast_expr *Expr,
+                               isl_bool (*Predicate)(__isl_keep isl_val *)) {
+  if (isl_ast_expr_get_type(Expr) != isl_ast_expr_int) {
+    isl_ast_expr_free(Expr);
+    return false;
+  }
+  auto ExprVal = isl_ast_expr_get_val(Expr);
+  isl_ast_expr_free(Expr);
+  if (Predicate(ExprVal) != isl_bool_true) {
+    isl_val_free(ExprVal);
+    return false;
+  }
+  isl_val_free(ExprVal);
+  return true;
+}
+
+int IslNodeBuilder::getNumberOfIterations(__isl_keep isl_ast_node *For) {
+  assert(isl_ast_node_get_type(For) == isl_ast_node_for);
+  auto Body = isl_ast_node_for_get_body(For);
+
+  // First, check if we can actually handle this code.
+  switch (isl_ast_node_get_type(Body)) {
+  case isl_ast_node_user:
+    break;
+  case isl_ast_node_block: {
+    isl_ast_node_list *List = isl_ast_node_block_get_children(Body);
+    for (int i = 0; i < isl_ast_node_list_n_ast_node(List); ++i) {
+      isl_ast_node *Node = isl_ast_node_list_get_ast_node(List, i);
+      int Type = isl_ast_node_get_type(Node);
+      isl_ast_node_free(Node);
+      if (Type != isl_ast_node_user) {
+        isl_ast_node_list_free(List);
+        isl_ast_node_free(Body);
+        return -1;
+      }
+    }
+    isl_ast_node_list_free(List);
+    break;
+  }
+  default:
+    isl_ast_node_free(Body);
+    return -1;
+  }
+  isl_ast_node_free(Body);
+
+  auto Init = isl_ast_node_for_get_init(For);
+  if (!checkIslAstExprInt(Init, isl_val_is_zero))
+    return -1;
+  auto Inc = isl_ast_node_for_get_inc(For);
+  if (!checkIslAstExprInt(Inc, isl_val_is_one))
+    return -1;
+  CmpInst::Predicate Predicate;
+  auto UB = getUpperBound(For, Predicate);
+  if (isl_ast_expr_get_type(UB) != isl_ast_expr_int) {
+    isl_ast_expr_free(UB);
+    return -1;
+  }
+  auto UpVal = isl_ast_expr_get_val(UB);
+  isl_ast_expr_free(UB);
+  int NumberIterations = isl_val_get_num_si(UpVal);
+  isl_val_free(UpVal);
+  if (NumberIterations < 0)
+    return -1;
+  if (Predicate == CmpInst::ICMP_SLT)
+    return NumberIterations;
+  else
+    return NumberIterations + 1;
+}
+
+/// Extract the values and SCEVs needed to generate code for a block.
+static int findReferencesInBlock(struct SubtreeReferences &References,
+                                 const ScopStmt *Stmt, BasicBlock *BB) {
+  for (Instruction &Inst : *BB) {
+    // Include invariant loads
+    if (isa<LoadInst>(Inst))
+      if (Value *InvariantLoad = References.GlobalMap.lookup(&Inst))
+        References.Values.insert(InvariantLoad);
+
+    for (Value *SrcVal : Inst.operands()) {
+      auto *Scope = References.LI.getLoopFor(BB);
+      if (canSynthesize(SrcVal, References.S, &References.SE, Scope)) {
+        References.SCEVs.insert(References.SE.getSCEVAtScope(SrcVal, Scope));
+        continue;
+      } else if (Value *NewVal = References.GlobalMap.lookup(SrcVal))
+        References.Values.insert(NewVal);
+    }
+  }
+  return 0;
+}
+
+isl_stat addReferencesFromStmt(const ScopStmt *Stmt, void *UserPtr,
+                               bool CreateScalarRefs) {
+  auto &References = *static_cast<struct SubtreeReferences *>(UserPtr);
+
+  if (Stmt->isBlockStmt())
+    findReferencesInBlock(References, Stmt, Stmt->getBasicBlock());
+  else {
+    assert(Stmt->isRegionStmt() &&
+           "Stmt was neither block nor region statement");
+    for (BasicBlock *BB : Stmt->getRegion()->blocks())
+      findReferencesInBlock(References, Stmt, BB);
+  }
+
+  for (auto &Access : *Stmt) {
+    if (References.ParamSpace) {
+      isl::space ParamSpace = Access->getLatestAccessRelation().get_space();
+      (*References.ParamSpace) =
+          References.ParamSpace->align_params(ParamSpace);
+    }
+
+    if (Access->isLatestArrayKind()) {
+      auto *BasePtr = Access->getLatestScopArrayInfo()->getBasePtr();
+      if (Instruction *OpInst = dyn_cast<Instruction>(BasePtr))
+        if (Stmt->getParent()->contains(OpInst))
+          continue;
+
+      References.Values.insert(BasePtr);
+      continue;
+    }
+
+    if (CreateScalarRefs)
+      References.Values.insert(References.BlockGen.getOrCreateAlloca(*Access));
+  }
+
+  return isl_stat_ok;
+}
+
+/// Extract the out-of-scop values and SCEVs referenced from a set describing
+/// a ScopStmt.
+///
+/// This includes the SCEVUnknowns referenced by the SCEVs used in the
+/// statement and the base pointers of the memory accesses. For scalar
+/// statements we force the generation of alloca memory locations and list
+/// these locations in the set of out-of-scop values as well.
+///
+/// @param Set     A set which references the ScopStmt we are interested in.
+/// @param UserPtr A void pointer that can be casted to a SubtreeReferences
+///                structure.
+static isl_stat addReferencesFromStmtSet(__isl_take isl_set *Set,
+                                         void *UserPtr) {
+  isl_id *Id = isl_set_get_tuple_id(Set);
+  auto *Stmt = static_cast<const ScopStmt *>(isl_id_get_user(Id));
+  isl_id_free(Id);
+  isl_set_free(Set);
+  return addReferencesFromStmt(Stmt, UserPtr);
+}
+
+/// Extract the out-of-scop values and SCEVs referenced from a union set
+/// referencing multiple ScopStmts.
+///
+/// This includes the SCEVUnknowns referenced by the SCEVs used in the
+/// statement and the base pointers of the memory accesses. For scalar
+/// statements we force the generation of alloca memory locations and list
+/// these locations in the set of out-of-scop values as well.
+///
+/// @param USet       A union set referencing the ScopStmts we are interested
+///                   in.
+/// @param References The SubtreeReferences data structure through which
+///                   results are returned and further information is
+///                   provided.
+static void
+addReferencesFromStmtUnionSet(isl_union_set *USet,
+                              struct SubtreeReferences &References) {
+  isl_union_set_foreach_set(USet, addReferencesFromStmtSet, &References);
+  isl_union_set_free(USet);
+}
+
+__isl_give isl_union_map *
+IslNodeBuilder::getScheduleForAstNode(__isl_keep isl_ast_node *For) {
+  return IslAstInfo::getSchedule(For);
+}
+
+void IslNodeBuilder::getReferencesInSubtree(__isl_keep isl_ast_node *For,
+                                            SetVector<Value *> &Values,
+                                            SetVector<const Loop *> &Loops) {
+  SetVector<const SCEV *> SCEVs;
+  struct SubtreeReferences References = {
+      LI, SE, S, ValueMap, Values, SCEVs, getBlockGenerator(), nullptr};
+
+  for (const auto &I : IDToValue)
+    Values.insert(I.second);
+
+  // NOTE: this is populated in IslNodeBuilder::addParameters
+  for (const auto &I : OutsideLoopIterations)
+    Values.insert(cast<SCEVUnknown>(I.second)->getValue());
+
+  isl_union_set *Schedule = isl_union_map_domain(getScheduleForAstNode(For));
+  addReferencesFromStmtUnionSet(Schedule, References);
+
+  for (const SCEV *Expr : SCEVs) {
+    findValues(Expr, SE, Values);
+    findLoops(Expr, Loops);
+  }
+
+  Values.remove_if([](const Value *V) { return isa<GlobalValue>(V); });
+
+  /// Note: Code generation of induction variables of loops outside Scops
+  ///
+  /// Remove loops that contain the scop or that are part of the scop, as they
+  /// are considered local. This leaves only loops that are before the scop, but
+  /// do not contain the scop itself.
+  /// We ignore loops perfectly contained in the Scop because these are already
+  /// generated at `IslNodeBuilder::addParameters`. These `Loops` are loops
+  /// whose induction variables are referred to by the Scop, but the Scop is not
+  /// fully contained in these Loops. Since there can be many of these,
+  /// we choose to codegen these on-demand.
+  /// @see IslNodeBuilder::materializeNonScopLoopInductionVariable.
+  Loops.remove_if([this](const Loop *L) {
+    return S.contains(L) || L->contains(S.getEntry());
+  });
+
+  // Contains Values that may need to be replaced with other values
+  // due to replacements from the ValueMap. We should make sure
+  // that we return correctly remapped values.
+  // NOTE: this code path is tested by:
+  //     1.  test/Isl/CodeGen/OpenMP/single_loop_with_loop_invariant_baseptr.ll
+  //     2.  test/Isl/CodeGen/OpenMP/loop-body-references-outer-values-3.ll
+  SetVector<Value *> ReplacedValues;
+  for (Value *V : Values) {
+    ReplacedValues.insert(getLatestValue(V));
+  }
+  Values = ReplacedValues;
+}
+
+void IslNodeBuilder::updateValues(ValueMapT &NewValues) {
+  SmallPtrSet<Value *, 5> Inserted;
+
+  for (const auto &I : IDToValue) {
+    IDToValue[I.first] = NewValues[I.second];
+    Inserted.insert(I.second);
+  }
+
+  for (const auto &I : NewValues) {
+    if (Inserted.count(I.first))
+      continue;
+
+    ValueMap[I.first] = I.second;
+  }
+}
+
+Value *IslNodeBuilder::getLatestValue(Value *Original) const {
+  auto It = ValueMap.find(Original);
+  if (It == ValueMap.end())
+    return Original;
+  return It->second;
+}
+
+void IslNodeBuilder::createUserVector(__isl_take isl_ast_node *User,
+                                      std::vector<Value *> &IVS,
+                                      __isl_take isl_id *IteratorID,
+                                      __isl_take isl_union_map *Schedule) {
+  isl_ast_expr *Expr = isl_ast_node_user_get_expr(User);
+  isl_ast_expr *StmtExpr = isl_ast_expr_get_op_arg(Expr, 0);
+  isl_id *Id = isl_ast_expr_get_id(StmtExpr);
+  isl_ast_expr_free(StmtExpr);
+  ScopStmt *Stmt = (ScopStmt *)isl_id_get_user(Id);
+  std::vector<LoopToScevMapT> VLTS(IVS.size());
+
+  isl_union_set *Domain = isl_union_set_from_set(Stmt->getDomain().release());
+  Schedule = isl_union_map_intersect_domain(Schedule, Domain);
+  isl_map *S = isl_map_from_union_map(Schedule);
+
+  auto *NewAccesses = createNewAccesses(Stmt, User);
+  createSubstitutionsVector(Expr, Stmt, VLTS, IVS, IteratorID);
+  VectorBlockGenerator::generate(BlockGen, *Stmt, VLTS, S, NewAccesses);
+  isl_id_to_ast_expr_free(NewAccesses);
+  isl_map_free(S);
+  isl_id_free(Id);
+  isl_ast_node_free(User);
+}
+
+void IslNodeBuilder::createMark(__isl_take isl_ast_node *Node) {
+  auto *Id = isl_ast_node_mark_get_id(Node);
+  auto Child = isl_ast_node_mark_get_node(Node);
+  isl_ast_node_free(Node);
+  // If a child node of a 'SIMD mark' is a loop that has a single iteration,
+  // it will be optimized away and we should skip it.
+  if (strcmp(isl_id_get_name(Id), "SIMD") == 0 &&
+      isl_ast_node_get_type(Child) == isl_ast_node_for) {
+    bool Vector = PollyVectorizerChoice == VECTORIZER_POLLY;
+    int VectorWidth = getNumberOfIterations(Child);
+    if (Vector && 1 < VectorWidth && VectorWidth <= 16)
+      createForVector(Child, VectorWidth);
+    else
+      createForSequential(Child, true);
+    isl_id_free(Id);
+    return;
+  }
+  if (strcmp(isl_id_get_name(Id), "Inter iteration alias-free") == 0) {
+    auto *BasePtr = static_cast<Value *>(isl_id_get_user(Id));
+    Annotator.addInterIterationAliasFreeBasePtr(BasePtr);
+  }
+  create(Child);
+  isl_id_free(Id);
+}
+
+void IslNodeBuilder::createForVector(__isl_take isl_ast_node *For,
+                                     int VectorWidth) {
+  isl_ast_node *Body = isl_ast_node_for_get_body(For);
+  isl_ast_expr *Init = isl_ast_node_for_get_init(For);
+  isl_ast_expr *Inc = isl_ast_node_for_get_inc(For);
+  isl_ast_expr *Iterator = isl_ast_node_for_get_iterator(For);
+  isl_id *IteratorID = isl_ast_expr_get_id(Iterator);
+
+  Value *ValueLB = ExprBuilder.create(Init);
+  Value *ValueInc = ExprBuilder.create(Inc);
+
+  Type *MaxType = ExprBuilder.getType(Iterator);
+  MaxType = ExprBuilder.getWidestType(MaxType, ValueLB->getType());
+  MaxType = ExprBuilder.getWidestType(MaxType, ValueInc->getType());
+
+  if (MaxType != ValueLB->getType())
+    ValueLB = Builder.CreateSExt(ValueLB, MaxType);
+  if (MaxType != ValueInc->getType())
+    ValueInc = Builder.CreateSExt(ValueInc, MaxType);
+
+  std::vector<Value *> IVS(VectorWidth);
+  IVS[0] = ValueLB;
+
+  for (int i = 1; i < VectorWidth; i++)
+    IVS[i] = Builder.CreateAdd(IVS[i - 1], ValueInc, "p_vector_iv");
+
+  isl_union_map *Schedule = getScheduleForAstNode(For);
+  assert(Schedule && "For statement annotation does not contain its schedule");
+
+  IDToValue[IteratorID] = ValueLB;
+
+  switch (isl_ast_node_get_type(Body)) {
+  case isl_ast_node_user:
+    createUserVector(Body, IVS, isl_id_copy(IteratorID),
+                     isl_union_map_copy(Schedule));
+    break;
+  case isl_ast_node_block: {
+    isl_ast_node_list *List = isl_ast_node_block_get_children(Body);
+
+    for (int i = 0; i < isl_ast_node_list_n_ast_node(List); ++i)
+      createUserVector(isl_ast_node_list_get_ast_node(List, i), IVS,
+                       isl_id_copy(IteratorID), isl_union_map_copy(Schedule));
+
+    isl_ast_node_free(Body);
+    isl_ast_node_list_free(List);
+    break;
+  }
+  default:
+    isl_ast_node_dump(Body);
+    llvm_unreachable("Unhandled isl_ast_node in vectorizer");
+  }
+
+  IDToValue.erase(IDToValue.find(IteratorID));
+  isl_id_free(IteratorID);
+  isl_union_map_free(Schedule);
+
+  isl_ast_node_free(For);
+  isl_ast_expr_free(Iterator);
+
+  VectorLoops++;
+}
+
+/// Restore the initial ordering of dimensions of the band node
+///
+/// In case the band node represents all the dimensions of the iteration
+/// domain, recreate the band node to restore the initial ordering of the
+/// dimensions.
+///
+/// @param Node The band node to be modified.
+/// @return The modified schedule node.
+static bool IsLoopVectorizerDisabled(isl::ast_node Node) {
+  assert(isl_ast_node_get_type(Node.keep()) == isl_ast_node_for);
+  auto Body = Node.for_get_body();
+  if (isl_ast_node_get_type(Body.keep()) != isl_ast_node_mark)
+    return false;
+  auto Id = Body.mark_get_id();
+  if (strcmp(Id.get_name().c_str(), "Loop Vectorizer Disabled") == 0)
+    return true;
+  return false;
+}
+
+void IslNodeBuilder::createForSequential(__isl_take isl_ast_node *For,
+                                         bool MarkParallel) {
+  isl_ast_node *Body;
+  isl_ast_expr *Init, *Inc, *Iterator, *UB;
+  isl_id *IteratorID;
+  Value *ValueLB, *ValueUB, *ValueInc;
+  Type *MaxType;
+  BasicBlock *ExitBlock;
+  Value *IV;
+  CmpInst::Predicate Predicate;
+
+  bool LoopVectorizerDisabled =
+      IsLoopVectorizerDisabled(isl::manage(isl_ast_node_copy(For)));
+
+  Body = isl_ast_node_for_get_body(For);
+
+  // isl_ast_node_for_is_degenerate(For)
+  //
+  // TODO: For degenerated loops we could generate a plain assignment.
+  //       However, for now we just reuse the logic for normal loops, which will
+  //       create a loop with a single iteration.
+
+  Init = isl_ast_node_for_get_init(For);
+  Inc = isl_ast_node_for_get_inc(For);
+  Iterator = isl_ast_node_for_get_iterator(For);
+  IteratorID = isl_ast_expr_get_id(Iterator);
+  UB = getUpperBound(For, Predicate);
+
+  ValueLB = ExprBuilder.create(Init);
+  ValueUB = ExprBuilder.create(UB);
+  ValueInc = ExprBuilder.create(Inc);
+
+  MaxType = ExprBuilder.getType(Iterator);
+  MaxType = ExprBuilder.getWidestType(MaxType, ValueLB->getType());
+  MaxType = ExprBuilder.getWidestType(MaxType, ValueUB->getType());
+  MaxType = ExprBuilder.getWidestType(MaxType, ValueInc->getType());
+
+  if (MaxType != ValueLB->getType())
+    ValueLB = Builder.CreateSExt(ValueLB, MaxType);
+  if (MaxType != ValueUB->getType())
+    ValueUB = Builder.CreateSExt(ValueUB, MaxType);
+  if (MaxType != ValueInc->getType())
+    ValueInc = Builder.CreateSExt(ValueInc, MaxType);
+
+  // If we can show that LB <Predicate> UB holds at least once, we can
+  // omit the GuardBB in front of the loop.
+  bool UseGuardBB =
+      !SE.isKnownPredicate(Predicate, SE.getSCEV(ValueLB), SE.getSCEV(ValueUB));
+  IV = createLoop(ValueLB, ValueUB, ValueInc, Builder, LI, DT, ExitBlock,
+                  Predicate, &Annotator, MarkParallel, UseGuardBB,
+                  LoopVectorizerDisabled);
+  IDToValue[IteratorID] = IV;
+
+  create(Body);
+
+  Annotator.popLoop(MarkParallel);
+
+  IDToValue.erase(IDToValue.find(IteratorID));
+
+  Builder.SetInsertPoint(&ExitBlock->front());
+
+  isl_ast_node_free(For);
+  isl_ast_expr_free(Iterator);
+  isl_id_free(IteratorID);
+
+  SequentialLoops++;
+}
+
+/// Remove the BBs contained in a (sub)function from the dominator tree.
+///
+/// This function removes the basic blocks that are part of a subfunction from
+/// the dominator tree. Specifically, when generating code it may happen that at
+/// some point the code generation continues in a new sub-function (e.g., when
+/// generating OpenMP code). The basic blocks that are created in this
+/// sub-function are then still part of the dominator tree of the original
+/// function, such that the dominator tree reaches over function boundaries.
+/// This is not only incorrect, but also causes crashes. This function now
+/// removes from the dominator tree all basic blocks that are dominated (and
+/// consequently reachable) from the entry block of this (sub)function.
+///
+/// FIXME: A LLVM (function or region) pass should not touch anything outside of
+/// the function/region it runs on. Hence, the pure need for this function shows
+/// that we do not comply to this rule. At the moment, this does not cause any
+/// issues, but we should be aware that such issues may appear. Unfortunately
+/// the current LLVM pass infrastructure does not allow to make Polly a module
+/// or call-graph pass to solve this issue, as such a pass would not have access
+/// to the per-function analyses passes needed by Polly. A future pass manager
+/// infrastructure is supposed to enable such kind of access possibly allowing
+/// us to create a cleaner solution here.
+///
+/// FIXME: Instead of adding the dominance information and then dropping it
+/// later on, we should try to just not add it in the first place. This requires
+/// some careful testing to make sure this does not break in interaction with
+/// the SCEVBuilder and SplitBlock which may rely on the dominator tree or
+/// which may try to update it.
+///
+/// @param F The function which contains the BBs to removed.
+/// @param DT The dominator tree from which to remove the BBs.
+static void removeSubFuncFromDomTree(Function *F, DominatorTree &DT) {
+  DomTreeNode *N = DT.getNode(&F->getEntryBlock());
+  std::vector<BasicBlock *> Nodes;
+
+  // We can only remove an element from the dominator tree, if all its children
+  // have been removed. To ensure this we obtain the list of nodes to remove
+  // using a post-order tree traversal.
+  for (po_iterator<DomTreeNode *> I = po_begin(N), E = po_end(N); I != E; ++I)
+    Nodes.push_back(I->getBlock());
+
+  for (BasicBlock *BB : Nodes)
+    DT.eraseNode(BB);
+}
+
+void IslNodeBuilder::createForParallel(__isl_take isl_ast_node *For) {
+  isl_ast_node *Body;
+  isl_ast_expr *Init, *Inc, *Iterator, *UB;
+  isl_id *IteratorID;
+  Value *ValueLB, *ValueUB, *ValueInc;
+  Type *MaxType;
+  Value *IV;
+  CmpInst::Predicate Predicate;
+
+  // The preamble of parallel code interacts different than normal code with
+  // e.g., scalar initialization. Therefore, we ensure the parallel code is
+  // separated from the last basic block.
+  BasicBlock *ParBB = SplitBlock(Builder.GetInsertBlock(),
+                                 &*Builder.GetInsertPoint(), &DT, &LI);
+  ParBB->setName("polly.parallel.for");
+  Builder.SetInsertPoint(&ParBB->front());
+
+  Body = isl_ast_node_for_get_body(For);
+  Init = isl_ast_node_for_get_init(For);
+  Inc = isl_ast_node_for_get_inc(For);
+  Iterator = isl_ast_node_for_get_iterator(For);
+  IteratorID = isl_ast_expr_get_id(Iterator);
+  UB = getUpperBound(For, Predicate);
+
+  ValueLB = ExprBuilder.create(Init);
+  ValueUB = ExprBuilder.create(UB);
+  ValueInc = ExprBuilder.create(Inc);
+
+  // OpenMP always uses SLE. In case the isl generated AST uses a SLT
+  // expression, we need to adjust the loop bound by one.
+  if (Predicate == CmpInst::ICMP_SLT)
+    ValueUB = Builder.CreateAdd(
+        ValueUB, Builder.CreateSExt(Builder.getTrue(), ValueUB->getType()));
+
+  MaxType = ExprBuilder.getType(Iterator);
+  MaxType = ExprBuilder.getWidestType(MaxType, ValueLB->getType());
+  MaxType = ExprBuilder.getWidestType(MaxType, ValueUB->getType());
+  MaxType = ExprBuilder.getWidestType(MaxType, ValueInc->getType());
+
+  if (MaxType != ValueLB->getType())
+    ValueLB = Builder.CreateSExt(ValueLB, MaxType);
+  if (MaxType != ValueUB->getType())
+    ValueUB = Builder.CreateSExt(ValueUB, MaxType);
+  if (MaxType != ValueInc->getType())
+    ValueInc = Builder.CreateSExt(ValueInc, MaxType);
+
+  BasicBlock::iterator LoopBody;
+
+  SetVector<Value *> SubtreeValues;
+  SetVector<const Loop *> Loops;
+
+  getReferencesInSubtree(For, SubtreeValues, Loops);
+
+  // Create for all loops we depend on values that contain the current loop
+  // iteration. These values are necessary to generate code for SCEVs that
+  // depend on such loops. As a result we need to pass them to the subfunction.
+  // See [Code generation of induction variables of loops outside Scops]
+  for (const Loop *L : Loops) {
+    Value *LoopInductionVar = materializeNonScopLoopInductionVariable(L);
+    SubtreeValues.insert(LoopInductionVar);
+  }
+
+  ValueMapT NewValues;
+  ParallelLoopGenerator ParallelLoopGen(Builder, LI, DT, DL);
+
+  IV = ParallelLoopGen.createParallelLoop(ValueLB, ValueUB, ValueInc,
+                                          SubtreeValues, NewValues, &LoopBody);
+  BasicBlock::iterator AfterLoop = Builder.GetInsertPoint();
+  Builder.SetInsertPoint(&*LoopBody);
+
+  // Remember the parallel subfunction
+  ParallelSubfunctions.push_back(LoopBody->getFunction());
+
+  // Save the current values.
+  auto ValueMapCopy = ValueMap;
+  IslExprBuilder::IDToValueTy IDToValueCopy = IDToValue;
+
+  updateValues(NewValues);
+  IDToValue[IteratorID] = IV;
+
+  ValueMapT NewValuesReverse;
+
+  for (auto P : NewValues)
+    NewValuesReverse[P.second] = P.first;
+
+  Annotator.addAlternativeAliasBases(NewValuesReverse);
+
+  create(Body);
+
+  Annotator.resetAlternativeAliasBases();
+  // Restore the original values.
+  ValueMap = ValueMapCopy;
+  IDToValue = IDToValueCopy;
+
+  Builder.SetInsertPoint(&*AfterLoop);
+  removeSubFuncFromDomTree((*LoopBody).getParent()->getParent(), DT);
+
+  for (const Loop *L : Loops)
+    OutsideLoopIterations.erase(L);
+
+  isl_ast_node_free(For);
+  isl_ast_expr_free(Iterator);
+  isl_id_free(IteratorID);
+
+  ParallelLoops++;
+}
+
+/// Return whether any of @p Node's statements contain partial accesses.
+///
+/// Partial accesses are not supported by Polly's vector code generator.
+static bool hasPartialAccesses(__isl_take isl_ast_node *Node) {
+  return isl_ast_node_foreach_descendant_top_down(
+             Node,
+             [](isl_ast_node *Node, void *User) -> isl_bool {
+               if (isl_ast_node_get_type(Node) != isl_ast_node_user)
+                 return isl_bool_true;
+
+               isl::ast_expr Expr = give(isl_ast_node_user_get_expr(Node));
+               isl::ast_expr StmtExpr =
+                   give(isl_ast_expr_get_op_arg(Expr.keep(), 0));
+               isl::id Id = give(isl_ast_expr_get_id(StmtExpr.keep()));
+
+               ScopStmt *Stmt =
+                   static_cast<ScopStmt *>(isl_id_get_user(Id.keep()));
+               isl::set StmtDom = Stmt->getDomain();
+               for (auto *MA : *Stmt) {
+                 if (MA->isLatestPartialAccess())
+                   return isl_bool_error;
+               }
+               return isl_bool_true;
+             },
+             nullptr) == isl_stat_error;
+}
+
+void IslNodeBuilder::createFor(__isl_take isl_ast_node *For) {
+  bool Vector = PollyVectorizerChoice == VECTORIZER_POLLY;
+
+  if (Vector && IslAstInfo::isInnermostParallel(For) &&
+      !IslAstInfo::isReductionParallel(For)) {
+    int VectorWidth = getNumberOfIterations(For);
+    if (1 < VectorWidth && VectorWidth <= 16 && !hasPartialAccesses(For)) {
+      createForVector(For, VectorWidth);
+      return;
+    }
+  }
+
+  if (IslAstInfo::isExecutedInParallel(For)) {
+    createForParallel(For);
+    return;
+  }
+  bool Parallel =
+      (IslAstInfo::isParallel(For) && !IslAstInfo::isReductionParallel(For));
+  createForSequential(For, Parallel);
+}
+
+void IslNodeBuilder::createIf(__isl_take isl_ast_node *If) {
+  isl_ast_expr *Cond = isl_ast_node_if_get_cond(If);
+
+  Function *F = Builder.GetInsertBlock()->getParent();
+  LLVMContext &Context = F->getContext();
+
+  BasicBlock *CondBB = SplitBlock(Builder.GetInsertBlock(),
+                                  &*Builder.GetInsertPoint(), &DT, &LI);
+  CondBB->setName("polly.cond");
+  BasicBlock *MergeBB = SplitBlock(CondBB, &CondBB->front(), &DT, &LI);
+  MergeBB->setName("polly.merge");
+  BasicBlock *ThenBB = BasicBlock::Create(Context, "polly.then", F);
+  BasicBlock *ElseBB = BasicBlock::Create(Context, "polly.else", F);
+
+  DT.addNewBlock(ThenBB, CondBB);
+  DT.addNewBlock(ElseBB, CondBB);
+  DT.changeImmediateDominator(MergeBB, CondBB);
+
+  Loop *L = LI.getLoopFor(CondBB);
+  if (L) {
+    L->addBasicBlockToLoop(ThenBB, LI);
+    L->addBasicBlockToLoop(ElseBB, LI);
+  }
+
+  CondBB->getTerminator()->eraseFromParent();
+
+  Builder.SetInsertPoint(CondBB);
+  Value *Predicate = ExprBuilder.create(Cond);
+  Builder.CreateCondBr(Predicate, ThenBB, ElseBB);
+  Builder.SetInsertPoint(ThenBB);
+  Builder.CreateBr(MergeBB);
+  Builder.SetInsertPoint(ElseBB);
+  Builder.CreateBr(MergeBB);
+  Builder.SetInsertPoint(&ThenBB->front());
+
+  create(isl_ast_node_if_get_then(If));
+
+  Builder.SetInsertPoint(&ElseBB->front());
+
+  if (isl_ast_node_if_has_else(If))
+    create(isl_ast_node_if_get_else(If));
+
+  Builder.SetInsertPoint(&MergeBB->front());
+
+  isl_ast_node_free(If);
+
+  IfConditions++;
+}
+
+__isl_give isl_id_to_ast_expr *
+IslNodeBuilder::createNewAccesses(ScopStmt *Stmt,
+                                  __isl_keep isl_ast_node *Node) {
+  isl_id_to_ast_expr *NewAccesses =
+      isl_id_to_ast_expr_alloc(Stmt->getParent()->getIslCtx().get(), 0);
+
+  auto *Build = IslAstInfo::getBuild(Node);
+  assert(Build && "Could not obtain isl_ast_build from user node");
+  Stmt->setAstBuild(isl::manage(isl_ast_build_copy(Build)));
+
+  for (auto *MA : *Stmt) {
+    if (!MA->hasNewAccessRelation()) {
+      if (PollyGenerateExpressions) {
+        if (!MA->isAffine())
+          continue;
+        if (MA->getLatestScopArrayInfo()->getBasePtrOriginSAI())
+          continue;
+
+        auto *BasePtr =
+            dyn_cast<Instruction>(MA->getLatestScopArrayInfo()->getBasePtr());
+        if (BasePtr && Stmt->getParent()->getRegion().contains(BasePtr))
+          continue;
+      } else {
+        continue;
+      }
+    }
+    assert(MA->isAffine() &&
+           "Only affine memory accesses can be code generated");
+
+    auto Schedule = isl_ast_build_get_schedule(Build);
+
+#ifndef NDEBUG
+    if (MA->isRead()) {
+      auto Dom = Stmt->getDomain().release();
+      auto SchedDom = isl_set_from_union_set(
+          isl_union_map_domain(isl_union_map_copy(Schedule)));
+      auto AccDom = isl_map_domain(MA->getAccessRelation().release());
+      Dom = isl_set_intersect_params(Dom,
+                                     Stmt->getParent()->getContext().release());
+      SchedDom = isl_set_intersect_params(
+          SchedDom, Stmt->getParent()->getContext().release());
+      assert(isl_set_is_subset(SchedDom, AccDom) &&
+             "Access relation not defined on full schedule domain");
+      assert(isl_set_is_subset(Dom, AccDom) &&
+             "Access relation not defined on full domain");
+      isl_set_free(AccDom);
+      isl_set_free(SchedDom);
+      isl_set_free(Dom);
+    }
+#endif
+
+    auto PWAccRel =
+        MA->applyScheduleToAccessRelation(isl::manage(Schedule)).release();
+
+    // isl cannot generate an index expression for access-nothing accesses.
+    isl::set AccDomain =
+        give(isl_pw_multi_aff_domain(isl_pw_multi_aff_copy(PWAccRel)));
+    isl::set Context = S.getContext();
+    AccDomain = AccDomain.intersect_params(Context);
+    if (isl_set_is_empty(AccDomain.keep()) == isl_bool_true) {
+      isl_pw_multi_aff_free(PWAccRel);
+      continue;
+    }
+
+    auto AccessExpr = isl_ast_build_access_from_pw_multi_aff(Build, PWAccRel);
+    NewAccesses =
+        isl_id_to_ast_expr_set(NewAccesses, MA->getId().release(), AccessExpr);
+  }
+
+  return NewAccesses;
+}
+
+void IslNodeBuilder::createSubstitutions(__isl_take isl_ast_expr *Expr,
+                                         ScopStmt *Stmt, LoopToScevMapT &LTS) {
+  assert(isl_ast_expr_get_type(Expr) == isl_ast_expr_op &&
+         "Expression of type 'op' expected");
+  assert(isl_ast_expr_get_op_type(Expr) == isl_ast_op_call &&
+         "Operation of type 'call' expected");
+  for (int i = 0; i < isl_ast_expr_get_op_n_arg(Expr) - 1; ++i) {
+    isl_ast_expr *SubExpr;
+    Value *V;
+
+    SubExpr = isl_ast_expr_get_op_arg(Expr, i + 1);
+    V = ExprBuilder.create(SubExpr);
+    ScalarEvolution *SE = Stmt->getParent()->getSE();
+    LTS[Stmt->getLoopForDimension(i)] = SE->getUnknown(V);
+  }
+
+  isl_ast_expr_free(Expr);
+}
+
+void IslNodeBuilder::createSubstitutionsVector(
+    __isl_take isl_ast_expr *Expr, ScopStmt *Stmt,
+    std::vector<LoopToScevMapT> &VLTS, std::vector<Value *> &IVS,
+    __isl_take isl_id *IteratorID) {
+  int i = 0;
+
+  Value *OldValue = IDToValue[IteratorID];
+  for (Value *IV : IVS) {
+    IDToValue[IteratorID] = IV;
+    createSubstitutions(isl_ast_expr_copy(Expr), Stmt, VLTS[i]);
+    i++;
+  }
+
+  IDToValue[IteratorID] = OldValue;
+  isl_id_free(IteratorID);
+  isl_ast_expr_free(Expr);
+}
+
+void IslNodeBuilder::generateCopyStmt(
+    ScopStmt *Stmt, __isl_keep isl_id_to_ast_expr *NewAccesses) {
+  assert(Stmt->size() == 2);
+  auto ReadAccess = Stmt->begin();
+  auto WriteAccess = ReadAccess++;
+  assert((*ReadAccess)->isRead() && (*WriteAccess)->isMustWrite());
+  assert((*ReadAccess)->getElementType() == (*WriteAccess)->getElementType() &&
+         "Accesses use the same data type");
+  assert((*ReadAccess)->isArrayKind() && (*WriteAccess)->isArrayKind());
+  auto *AccessExpr =
+      isl_id_to_ast_expr_get(NewAccesses, (*ReadAccess)->getId().release());
+  auto *LoadValue = ExprBuilder.create(AccessExpr);
+  AccessExpr =
+      isl_id_to_ast_expr_get(NewAccesses, (*WriteAccess)->getId().release());
+  auto *StoreAddr = ExprBuilder.createAccessAddress(AccessExpr);
+  Builder.CreateStore(LoadValue, StoreAddr);
+}
+
+Value *IslNodeBuilder::materializeNonScopLoopInductionVariable(const Loop *L) {
+  assert(OutsideLoopIterations.find(L) == OutsideLoopIterations.end() &&
+         "trying to materialize loop induction variable twice");
+  const SCEV *OuterLIV = SE.getAddRecExpr(SE.getUnknown(Builder.getInt64(0)),
+                                          SE.getUnknown(Builder.getInt64(1)), L,
+                                          SCEV::FlagAnyWrap);
+  Value *V = generateSCEV(OuterLIV);
+  OutsideLoopIterations[L] = SE.getUnknown(V);
+  return V;
+}
+
+void IslNodeBuilder::createUser(__isl_take isl_ast_node *User) {
+  LoopToScevMapT LTS;
+  isl_id *Id;
+  ScopStmt *Stmt;
+
+  isl_ast_expr *Expr = isl_ast_node_user_get_expr(User);
+  isl_ast_expr *StmtExpr = isl_ast_expr_get_op_arg(Expr, 0);
+  Id = isl_ast_expr_get_id(StmtExpr);
+  isl_ast_expr_free(StmtExpr);
+
+  LTS.insert(OutsideLoopIterations.begin(), OutsideLoopIterations.end());
+
+  Stmt = (ScopStmt *)isl_id_get_user(Id);
+  auto *NewAccesses = createNewAccesses(Stmt, User);
+  if (Stmt->isCopyStmt()) {
+    generateCopyStmt(Stmt, NewAccesses);
+    isl_ast_expr_free(Expr);
+  } else {
+    createSubstitutions(Expr, Stmt, LTS);
+
+    if (Stmt->isBlockStmt())
+      BlockGen.copyStmt(*Stmt, LTS, NewAccesses);
+    else
+      RegionGen.copyStmt(*Stmt, LTS, NewAccesses);
+  }
+
+  isl_id_to_ast_expr_free(NewAccesses);
+  isl_ast_node_free(User);
+  isl_id_free(Id);
+}
+
+void IslNodeBuilder::createBlock(__isl_take isl_ast_node *Block) {
+  isl_ast_node_list *List = isl_ast_node_block_get_children(Block);
+
+  for (int i = 0; i < isl_ast_node_list_n_ast_node(List); ++i)
+    create(isl_ast_node_list_get_ast_node(List, i));
+
+  isl_ast_node_free(Block);
+  isl_ast_node_list_free(List);
+}
+
+void IslNodeBuilder::create(__isl_take isl_ast_node *Node) {
+  switch (isl_ast_node_get_type(Node)) {
+  case isl_ast_node_error:
+    llvm_unreachable("code generation error");
+  case isl_ast_node_mark:
+    createMark(Node);
+    return;
+  case isl_ast_node_for:
+    createFor(Node);
+    return;
+  case isl_ast_node_if:
+    createIf(Node);
+    return;
+  case isl_ast_node_user:
+    createUser(Node);
+    return;
+  case isl_ast_node_block:
+    createBlock(Node);
+    return;
+  }
+
+  llvm_unreachable("Unknown isl_ast_node type");
+}
+
+bool IslNodeBuilder::materializeValue(isl_id *Id) {
+  // If the Id is already mapped, skip it.
+  if (!IDToValue.count(Id)) {
+    auto *ParamSCEV = (const SCEV *)isl_id_get_user(Id);
+    Value *V = nullptr;
+
+    // Parameters could refer to invariant loads that need to be
+    // preloaded before we can generate code for the parameter. Thus,
+    // check if any value referred to in ParamSCEV is an invariant load
+    // and if so make sure its equivalence class is preloaded.
+    SetVector<Value *> Values;
+    findValues(ParamSCEV, SE, Values);
+    for (auto *Val : Values) {
+      // Check if the value is an instruction in a dead block within the SCoP
+      // and if so do not code generate it.
+      if (auto *Inst = dyn_cast<Instruction>(Val)) {
+        if (S.contains(Inst)) {
+          bool IsDead = true;
+
+          // Check for "undef" loads first, then if there is a statement for
+          // the parent of Inst and lastly if the parent of Inst has an empty
+          // domain. In the first and last case the instruction is dead but if
+          // there is a statement or the domain is not empty Inst is not dead.
+          auto MemInst = MemAccInst::dyn_cast(Inst);
+          auto Address = MemInst ? MemInst.getPointerOperand() : nullptr;
+          if (Address && SE.getUnknown(UndefValue::get(Address->getType())) ==
+                             SE.getPointerBase(SE.getSCEV(Address))) {
+          } else if (S.getStmtFor(Inst)) {
+            IsDead = false;
+          } else {
+            auto *Domain = S.getDomainConditions(Inst->getParent()).release();
+            IsDead = isl_set_is_empty(Domain);
+            isl_set_free(Domain);
+          }
+
+          if (IsDead) {
+            V = UndefValue::get(ParamSCEV->getType());
+            break;
+          }
+        }
+      }
+
+      if (auto *IAClass = S.lookupInvariantEquivClass(Val)) {
+        // Check if this invariant access class is empty, hence if we never
+        // actually added a loads instruction to it. In that case it has no
+        // (meaningful) users and we should not try to code generate it.
+        if (IAClass->InvariantAccesses.empty())
+          V = UndefValue::get(ParamSCEV->getType());
+
+        if (!preloadInvariantEquivClass(*IAClass)) {
+          isl_id_free(Id);
+          return false;
+        }
+      }
+    }
+
+    V = V ? V : generateSCEV(ParamSCEV);
+    IDToValue[Id] = V;
+  }
+
+  isl_id_free(Id);
+  return true;
+}
+
+bool IslNodeBuilder::materializeParameters(isl_set *Set) {
+  for (unsigned i = 0, e = isl_set_dim(Set, isl_dim_param); i < e; ++i) {
+    if (!isl_set_involves_dims(Set, isl_dim_param, i, 1))
+      continue;
+    isl_id *Id = isl_set_get_dim_id(Set, isl_dim_param, i);
+    if (!materializeValue(Id))
+      return false;
+  }
+  return true;
+}
+
+bool IslNodeBuilder::materializeParameters() {
+  for (const SCEV *Param : S.parameters()) {
+    isl_id *Id = S.getIdForParam(Param).release();
+    if (!materializeValue(Id))
+      return false;
+  }
+  return true;
+}
+
+/// Generate the computation of the size of the outermost dimension from the
+/// Fortran array descriptor (in this case, `@g_arr`). The final `%size`
+/// contains the size of the array.
+///
+/// %arrty = type { i8*, i64, i64, [3 x %desc.dimensionty] }
+/// %desc.dimensionty = type { i64, i64, i64 }
+/// @g_arr = global %arrty zeroinitializer, align 32
+/// ...
+/// %0 = load i64, i64* getelementptr inbounds
+///                       (%arrty, %arrty* @g_arr, i64 0, i32 3, i64 0, i32 2)
+/// %1 = load i64, i64* getelementptr inbounds
+///                      (%arrty, %arrty* @g_arr, i64 0, i32 3, i64 0, i32 1)
+/// %2 = sub nsw i64 %0, %1
+/// %size = add nsw i64 %2, 1
+static Value *buildFADOutermostDimensionLoad(Value *GlobalDescriptor,
+                                             PollyIRBuilder &Builder,
+                                             std::string ArrayName) {
+  assert(GlobalDescriptor && "invalid global descriptor given");
+
+  Value *endIdx[4] = {Builder.getInt64(0), Builder.getInt32(3),
+                      Builder.getInt64(0), Builder.getInt32(2)};
+  Value *endPtr = Builder.CreateInBoundsGEP(GlobalDescriptor, endIdx,
+                                            ArrayName + "_end_ptr");
+  Value *end = Builder.CreateLoad(endPtr, ArrayName + "_end");
+
+  Value *beginIdx[4] = {Builder.getInt64(0), Builder.getInt32(3),
+                        Builder.getInt64(0), Builder.getInt32(1)};
+  Value *beginPtr = Builder.CreateInBoundsGEP(GlobalDescriptor, beginIdx,
+                                              ArrayName + "_begin_ptr");
+  Value *begin = Builder.CreateLoad(beginPtr, ArrayName + "_begin");
+
+  Value *size =
+      Builder.CreateNSWSub(end, begin, ArrayName + "_end_begin_delta");
+  Type *endType = dyn_cast<IntegerType>(end->getType());
+  assert(endType && "expected type of end to be integral");
+
+  size = Builder.CreateNSWAdd(end,
+                              ConstantInt::get(endType, 1, /* signed = */ true),
+                              ArrayName + "_size");
+
+  return size;
+}
+
+bool IslNodeBuilder::materializeFortranArrayOutermostDimension() {
+  for (ScopArrayInfo *Array : S.arrays()) {
+    if (Array->getNumberOfDimensions() == 0)
+      continue;
+
+    Value *FAD = Array->getFortranArrayDescriptor();
+    if (!FAD)
+      continue;
+
+    isl_pw_aff *ParametricPwAff = Array->getDimensionSizePw(0).release();
+    assert(ParametricPwAff && "parametric pw_aff corresponding "
+                              "to outermost dimension does not "
+                              "exist");
+
+    isl_id *Id = isl_pw_aff_get_dim_id(ParametricPwAff, isl_dim_param, 0);
+    isl_pw_aff_free(ParametricPwAff);
+
+    assert(Id && "pw_aff is not parametric");
+
+    if (IDToValue.count(Id)) {
+      isl_id_free(Id);
+      continue;
+    }
+
+    Value *FinalValue =
+        buildFADOutermostDimensionLoad(FAD, Builder, Array->getName());
+    assert(FinalValue && "unable to build Fortran array "
+                         "descriptor load of outermost dimension");
+    IDToValue[Id] = FinalValue;
+    isl_id_free(Id);
+  }
+  return true;
+}
+
+Value *IslNodeBuilder::preloadUnconditionally(isl_set *AccessRange,
+                                              isl_ast_build *Build,
+                                              Instruction *AccInst) {
+  isl_pw_multi_aff *PWAccRel = isl_pw_multi_aff_from_set(AccessRange);
+  isl_ast_expr *Access =
+      isl_ast_build_access_from_pw_multi_aff(Build, PWAccRel);
+  auto *Address = isl_ast_expr_address_of(Access);
+  auto *AddressValue = ExprBuilder.create(Address);
+  Value *PreloadVal;
+
+  // Correct the type as the SAI might have a different type than the user
+  // expects, especially if the base pointer is a struct.
+  Type *Ty = AccInst->getType();
+
+  auto *Ptr = AddressValue;
+  auto Name = Ptr->getName();
+  auto AS = Ptr->getType()->getPointerAddressSpace();
+  Ptr = Builder.CreatePointerCast(Ptr, Ty->getPointerTo(AS), Name + ".cast");
+  PreloadVal = Builder.CreateLoad(Ptr, Name + ".load");
+  if (LoadInst *PreloadInst = dyn_cast<LoadInst>(PreloadVal))
+    PreloadInst->setAlignment(dyn_cast<LoadInst>(AccInst)->getAlignment());
+
+  // TODO: This is only a hot fix for SCoP sequences that use the same load
+  //       instruction contained and hoisted by one of the SCoPs.
+  if (SE.isSCEVable(Ty))
+    SE.forgetValue(AccInst);
+
+  return PreloadVal;
+}
+
+Value *IslNodeBuilder::preloadInvariantLoad(const MemoryAccess &MA,
+                                            isl_set *Domain) {
+  isl_set *AccessRange = isl_map_range(MA.getAddressFunction().release());
+  AccessRange = isl_set_gist_params(AccessRange, S.getContext().release());
+
+  if (!materializeParameters(AccessRange)) {
+    isl_set_free(AccessRange);
+    isl_set_free(Domain);
+    return nullptr;
+  }
+
+  auto *Build =
+      isl_ast_build_from_context(isl_set_universe(S.getParamSpace().release()));
+  isl_set *Universe = isl_set_universe(isl_set_get_space(Domain));
+  bool AlwaysExecuted = isl_set_is_equal(Domain, Universe);
+  isl_set_free(Universe);
+
+  Instruction *AccInst = MA.getAccessInstruction();
+  Type *AccInstTy = AccInst->getType();
+
+  Value *PreloadVal = nullptr;
+  if (AlwaysExecuted) {
+    PreloadVal = preloadUnconditionally(AccessRange, Build, AccInst);
+    isl_ast_build_free(Build);
+    isl_set_free(Domain);
+    return PreloadVal;
+  }
+
+  if (!materializeParameters(Domain)) {
+    isl_ast_build_free(Build);
+    isl_set_free(AccessRange);
+    isl_set_free(Domain);
+    return nullptr;
+  }
+
+  isl_ast_expr *DomainCond = isl_ast_build_expr_from_set(Build, Domain);
+  Domain = nullptr;
+
+  ExprBuilder.setTrackOverflow(true);
+  Value *Cond = ExprBuilder.create(DomainCond);
+  Value *OverflowHappened = Builder.CreateNot(ExprBuilder.getOverflowState(),
+                                              "polly.preload.cond.overflown");
+  Cond = Builder.CreateAnd(Cond, OverflowHappened, "polly.preload.cond.result");
+  ExprBuilder.setTrackOverflow(false);
+
+  if (!Cond->getType()->isIntegerTy(1))
+    Cond = Builder.CreateIsNotNull(Cond);
+
+  BasicBlock *CondBB = SplitBlock(Builder.GetInsertBlock(),
+                                  &*Builder.GetInsertPoint(), &DT, &LI);
+  CondBB->setName("polly.preload.cond");
+
+  BasicBlock *MergeBB = SplitBlock(CondBB, &CondBB->front(), &DT, &LI);
+  MergeBB->setName("polly.preload.merge");
+
+  Function *F = Builder.GetInsertBlock()->getParent();
+  LLVMContext &Context = F->getContext();
+  BasicBlock *ExecBB = BasicBlock::Create(Context, "polly.preload.exec", F);
+
+  DT.addNewBlock(ExecBB, CondBB);
+  if (Loop *L = LI.getLoopFor(CondBB))
+    L->addBasicBlockToLoop(ExecBB, LI);
+
+  auto *CondBBTerminator = CondBB->getTerminator();
+  Builder.SetInsertPoint(CondBBTerminator);
+  Builder.CreateCondBr(Cond, ExecBB, MergeBB);
+  CondBBTerminator->eraseFromParent();
+
+  Builder.SetInsertPoint(ExecBB);
+  Builder.CreateBr(MergeBB);
+
+  Builder.SetInsertPoint(ExecBB->getTerminator());
+  Value *PreAccInst = preloadUnconditionally(AccessRange, Build, AccInst);
+  Builder.SetInsertPoint(MergeBB->getTerminator());
+  auto *MergePHI = Builder.CreatePHI(
+      AccInstTy, 2, "polly.preload." + AccInst->getName() + ".merge");
+  PreloadVal = MergePHI;
+
+  if (!PreAccInst) {
+    PreloadVal = nullptr;
+    PreAccInst = UndefValue::get(AccInstTy);
+  }
+
+  MergePHI->addIncoming(PreAccInst, ExecBB);
+  MergePHI->addIncoming(Constant::getNullValue(AccInstTy), CondBB);
+
+  isl_ast_build_free(Build);
+  return PreloadVal;
+}
+
+bool IslNodeBuilder::preloadInvariantEquivClass(
+    InvariantEquivClassTy &IAClass) {
+  // For an equivalence class of invariant loads we pre-load the representing
+  // element with the unified execution context. However, we have to map all
+  // elements of the class to the one preloaded load as they are referenced
+  // during the code generation and therefor need to be mapped.
+  const MemoryAccessList &MAs = IAClass.InvariantAccesses;
+  if (MAs.empty())
+    return true;
+
+  MemoryAccess *MA = MAs.front();
+  assert(MA->isArrayKind() && MA->isRead());
+
+  // If the access function was already mapped, the preload of this equivalence
+  // class was triggered earlier already and doesn't need to be done again.
+  if (ValueMap.count(MA->getAccessInstruction()))
+    return true;
+
+  // Check for recursion which can be caused by additional constraints, e.g.,
+  // non-finite loop constraints. In such a case we have to bail out and insert
+  // a "false" runtime check that will cause the original code to be executed.
+  auto PtrId = std::make_pair(IAClass.IdentifyingPointer, IAClass.AccessType);
+  if (!PreloadedPtrs.insert(PtrId).second)
+    return false;
+
+  // The execution context of the IAClass.
+  isl::set &ExecutionCtx = IAClass.ExecutionContext;
+
+  // If the base pointer of this class is dependent on another one we have to
+  // make sure it was preloaded already.
+  auto *SAI = MA->getScopArrayInfo();
+  if (auto *BaseIAClass = S.lookupInvariantEquivClass(SAI->getBasePtr())) {
+    if (!preloadInvariantEquivClass(*BaseIAClass))
+      return false;
+
+    // After we preloaded the BaseIAClass we adjusted the BaseExecutionCtx and
+    // we need to refine the ExecutionCtx.
+    isl::set BaseExecutionCtx = BaseIAClass->ExecutionContext;
+    ExecutionCtx = ExecutionCtx.intersect(BaseExecutionCtx);
+  }
+
+  // If the size of a dimension is dependent on another class, make sure it is
+  // preloaded.
+  for (unsigned i = 1, e = SAI->getNumberOfDimensions(); i < e; ++i) {
+    const SCEV *Dim = SAI->getDimensionSize(i);
+    SetVector<Value *> Values;
+    findValues(Dim, SE, Values);
+    for (auto *Val : Values) {
+      if (auto *BaseIAClass = S.lookupInvariantEquivClass(Val)) {
+        if (!preloadInvariantEquivClass(*BaseIAClass))
+          return false;
+
+        // After we preloaded the BaseIAClass we adjusted the BaseExecutionCtx
+        // and we need to refine the ExecutionCtx.
+        isl::set BaseExecutionCtx = BaseIAClass->ExecutionContext;
+        ExecutionCtx = ExecutionCtx.intersect(BaseExecutionCtx);
+      }
+    }
+  }
+
+  Instruction *AccInst = MA->getAccessInstruction();
+  Type *AccInstTy = AccInst->getType();
+
+  Value *PreloadVal = preloadInvariantLoad(*MA, ExecutionCtx.copy());
+  if (!PreloadVal)
+    return false;
+
+  for (const MemoryAccess *MA : MAs) {
+    Instruction *MAAccInst = MA->getAccessInstruction();
+    assert(PreloadVal->getType() == MAAccInst->getType());
+    ValueMap[MAAccInst] = PreloadVal;
+  }
+
+  if (SE.isSCEVable(AccInstTy)) {
+    isl_id *ParamId = S.getIdForParam(SE.getSCEV(AccInst)).release();
+    if (ParamId)
+      IDToValue[ParamId] = PreloadVal;
+    isl_id_free(ParamId);
+  }
+
+  BasicBlock *EntryBB = &Builder.GetInsertBlock()->getParent()->getEntryBlock();
+  auto *Alloca = new AllocaInst(AccInstTy, DL.getAllocaAddrSpace(),
+                                AccInst->getName() + ".preload.s2a");
+  Alloca->insertBefore(&*EntryBB->getFirstInsertionPt());
+  Builder.CreateStore(PreloadVal, Alloca);
+  ValueMapT PreloadedPointer;
+  PreloadedPointer[PreloadVal] = AccInst;
+  Annotator.addAlternativeAliasBases(PreloadedPointer);
+
+  for (auto *DerivedSAI : SAI->getDerivedSAIs()) {
+    Value *BasePtr = DerivedSAI->getBasePtr();
+
+    for (const MemoryAccess *MA : MAs) {
+      // As the derived SAI information is quite coarse, any load from the
+      // current SAI could be the base pointer of the derived SAI, however we
+      // should only change the base pointer of the derived SAI if we actually
+      // preloaded it.
+      if (BasePtr == MA->getOriginalBaseAddr()) {
+        assert(BasePtr->getType() == PreloadVal->getType());
+        DerivedSAI->setBasePtr(PreloadVal);
+      }
+
+      // For scalar derived SAIs we remap the alloca used for the derived value.
+      if (BasePtr == MA->getAccessInstruction())
+        ScalarMap[DerivedSAI] = Alloca;
+    }
+  }
+
+  for (const MemoryAccess *MA : MAs) {
+    Instruction *MAAccInst = MA->getAccessInstruction();
+    // Use the escape system to get the correct value to users outside the SCoP.
+    BlockGenerator::EscapeUserVectorTy EscapeUsers;
+    for (auto *U : MAAccInst->users())
+      if (Instruction *UI = dyn_cast<Instruction>(U))
+        if (!S.contains(UI))
+          EscapeUsers.push_back(UI);
+
+    if (EscapeUsers.empty())
+      continue;
+
+    EscapeMap[MA->getAccessInstruction()] =
+        std::make_pair(Alloca, std::move(EscapeUsers));
+  }
+
+  return true;
+}
+
+void IslNodeBuilder::allocateNewArrays(BBPair StartExitBlocks) {
+  for (auto &SAI : S.arrays()) {
+    if (SAI->getBasePtr())
+      continue;
+
+    assert(SAI->getNumberOfDimensions() > 0 && SAI->getDimensionSize(0) &&
+           "The size of the outermost dimension is used to declare newly "
+           "created arrays that require memory allocation.");
+
+    Type *NewArrayType = nullptr;
+
+    // Get the size of the array = size(dim_1)*...*size(dim_n)
+    uint64_t ArraySizeInt = 1;
+    for (int i = SAI->getNumberOfDimensions() - 1; i >= 0; i--) {
+      auto *DimSize = SAI->getDimensionSize(i);
+      unsigned UnsignedDimSize = static_cast<const SCEVConstant *>(DimSize)
+                                     ->getAPInt()
+                                     .getLimitedValue();
+
+      if (!NewArrayType)
+        NewArrayType = SAI->getElementType();
+
+      NewArrayType = ArrayType::get(NewArrayType, UnsignedDimSize);
+      ArraySizeInt *= UnsignedDimSize;
+    }
+
+    if (SAI->isOnHeap()) {
+      LLVMContext &Ctx = NewArrayType->getContext();
+
+      // Get the IntPtrTy from the Datalayout
+      auto IntPtrTy = DL.getIntPtrType(Ctx);
+
+      // Get the size of the element type in bits
+      unsigned Size = SAI->getElemSizeInBytes();
+
+      // Insert the malloc call at polly.start
+      auto InstIt = std::get<0>(StartExitBlocks)->getTerminator();
+      auto *CreatedArray = CallInst::CreateMalloc(
+          &*InstIt, IntPtrTy, SAI->getElementType(),
+          ConstantInt::get(Type::getInt64Ty(Ctx), Size),
+          ConstantInt::get(Type::getInt64Ty(Ctx), ArraySizeInt), nullptr,
+          SAI->getName());
+
+      SAI->setBasePtr(CreatedArray);
+
+      // Insert the free call at polly.exiting
+      CallInst::CreateFree(CreatedArray,
+                           std::get<1>(StartExitBlocks)->getTerminator());
+    } else {
+      auto InstIt = Builder.GetInsertBlock()
+                        ->getParent()
+                        ->getEntryBlock()
+                        .getTerminator();
+
+      auto *CreatedArray = new AllocaInst(NewArrayType, DL.getAllocaAddrSpace(),
+                                          SAI->getName(), &*InstIt);
+      CreatedArray->setAlignment(PollyTargetFirstLevelCacheLineSize);
+      SAI->setBasePtr(CreatedArray);
+    }
+  }
+}
+
+bool IslNodeBuilder::preloadInvariantLoads() {
+  auto &InvariantEquivClasses = S.getInvariantAccesses();
+  if (InvariantEquivClasses.empty())
+    return true;
+
+  BasicBlock *PreLoadBB = SplitBlock(Builder.GetInsertBlock(),
+                                     &*Builder.GetInsertPoint(), &DT, &LI);
+  PreLoadBB->setName("polly.preload.begin");
+  Builder.SetInsertPoint(&PreLoadBB->front());
+
+  for (auto &IAClass : InvariantEquivClasses)
+    if (!preloadInvariantEquivClass(IAClass))
+      return false;
+
+  return true;
+}
+
+void IslNodeBuilder::addParameters(__isl_take isl_set *Context) {
+  // Materialize values for the parameters of the SCoP.
+  materializeParameters();
+
+  // materialize the outermost dimension parameters for a Fortran array.
+  // NOTE: materializeParameters() does not work since it looks through
+  // the SCEVs. We don't have a corresponding SCEV for the array size
+  // parameter
+  materializeFortranArrayOutermostDimension();
+
+  // Generate values for the current loop iteration for all surrounding loops.
+  //
+  // We may also reference loops outside of the scop which do not contain the
+  // scop itself, but as the number of such scops may be arbitrarily large we do
+  // not generate code for them here, but only at the point of code generation
+  // where these values are needed.
+  Loop *L = LI.getLoopFor(S.getEntry());
+
+  while (L != nullptr && S.contains(L))
+    L = L->getParentLoop();
+
+  while (L != nullptr) {
+    materializeNonScopLoopInductionVariable(L);
+    L = L->getParentLoop();
+  }
+
+  isl_set_free(Context);
+}
+
+Value *IslNodeBuilder::generateSCEV(const SCEV *Expr) {
+  /// We pass the insert location of our Builder, as Polly ensures during IR
+  /// generation that there is always a valid CFG into which instructions are
+  /// inserted. As a result, the insertpoint is known to be always followed by a
+  /// terminator instruction. This means the insert point may be specified by a
+  /// terminator instruction, but it can never point to an ->end() iterator
+  /// which does not have a corresponding instruction. Hence, dereferencing
+  /// the insertpoint to obtain an instruction is known to be save.
+  ///
+  /// We also do not need to update the Builder here, as new instructions are
+  /// always inserted _before_ the given InsertLocation. As a result, the
+  /// insert location remains valid.
+  assert(Builder.GetInsertBlock()->end() != Builder.GetInsertPoint() &&
+         "Insert location points after last valid instruction");
+  Instruction *InsertLocation = &*Builder.GetInsertPoint();
+  return expandCodeFor(S, SE, DL, "polly", Expr, Expr->getType(),
+                       InsertLocation, &ValueMap,
+                       StartBlock->getSinglePredecessor());
+}
+
+/// The AST expression we generate to perform the run-time check assumes
+/// computations on integer types of infinite size. As we only use 64-bit
+/// arithmetic we check for overflows, in case of which we set the result
+/// of this run-time check to false to be conservatively correct,
+Value *IslNodeBuilder::createRTC(isl_ast_expr *Condition) {
+  auto ExprBuilder = getExprBuilder();
+
+  // In case the AST expression has integers larger than 64 bit, bail out. The
+  // resulting LLVM-IR will contain operations on types that use more than 64
+  // bits. These are -- in case wrapping intrinsics are used -- translated to
+  // runtime library calls that are not available on all systems (e.g., Android)
+  // and consequently will result in linker errors.
+  if (ExprBuilder.hasLargeInts(isl::manage(isl_ast_expr_copy(Condition)))) {
+    isl_ast_expr_free(Condition);
+    return Builder.getFalse();
+  }
+
+  ExprBuilder.setTrackOverflow(true);
+  Value *RTC = ExprBuilder.create(Condition);
+  if (!RTC->getType()->isIntegerTy(1))
+    RTC = Builder.CreateIsNotNull(RTC);
+  Value *OverflowHappened =
+      Builder.CreateNot(ExprBuilder.getOverflowState(), "polly.rtc.overflown");
+
+  if (PollyGenerateRTCPrint) {
+    auto *F = Builder.GetInsertBlock()->getParent();
+    RuntimeDebugBuilder::createCPUPrinter(
+        Builder,
+        "F: " + F->getName().str() + " R: " + S.getRegion().getNameStr() +
+            "RTC: ",
+        RTC, " Overflow: ", OverflowHappened,
+        "\n"
+        "  (0 failed, -1 succeeded)\n"
+        "  (if one or both are 0 falling back to original code, if both are -1 "
+        "executing Polly code)\n");
+  }
+
+  RTC = Builder.CreateAnd(RTC, OverflowHappened, "polly.rtc.result");
+  ExprBuilder.setTrackOverflow(false);
+
+  if (!isa<ConstantInt>(RTC))
+    VersionedScops++;
+
+  return RTC;
+}
diff --git a/final/lib/CodeGen/LoopGenerators.cpp b/final/lib/CodeGen/LoopGenerators.cpp
new file mode 100644
index 0000000..368a645
--- /dev/null
+++ b/final/lib/CodeGen/LoopGenerators.cpp
@@ -0,0 +1,381 @@
+//===------ LoopGenerators.cpp -  IR helper to create loops ---------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains functions to create scalar and parallel loops as LLVM-IR.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/LoopGenerators.h"
+#include "polly/ScopDetection.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+
+using namespace llvm;
+using namespace polly;
+
+static cl::opt<int>
+    PollyNumThreads("polly-num-threads",
+                    cl::desc("Number of threads to use (0 = auto)"), cl::Hidden,
+                    cl::init(0));
+
+// We generate a loop of either of the following structures:
+//
+//              BeforeBB                      BeforeBB
+//                 |                             |
+//                 v                             v
+//              GuardBB                      PreHeaderBB
+//              /      |                         |   _____
+//     __  PreHeaderBB  |                        v  \/    |
+//    /  \    /         |                     HeaderBB  latch
+// latch  HeaderBB      |                        |\       |
+//    \  /    \         /                        | \------/
+//     <       \       /                         |
+//              \     /                          v
+//              ExitBB                         ExitBB
+//
+// depending on whether or not we know that it is executed at least once. If
+// not, GuardBB checks if the loop is executed at least once. If this is the
+// case we branch to PreHeaderBB and subsequently to the HeaderBB, which
+// contains the loop iv 'polly.indvar', the incremented loop iv
+// 'polly.indvar_next' as well as the condition to check if we execute another
+// iteration of the loop. After the loop has finished, we branch to ExitBB.
+// We expect the type of UB, LB, UB+Stride to be large enough for values that
+// UB may take throughout the execution of the loop, including the computation
+// of indvar + Stride before the final abort.
+Value *polly::createLoop(Value *LB, Value *UB, Value *Stride,
+                         PollyIRBuilder &Builder, LoopInfo &LI,
+                         DominatorTree &DT, BasicBlock *&ExitBB,
+                         ICmpInst::Predicate Predicate,
+                         ScopAnnotator *Annotator, bool Parallel, bool UseGuard,
+                         bool LoopVectDisabled) {
+  Function *F = Builder.GetInsertBlock()->getParent();
+  LLVMContext &Context = F->getContext();
+
+  assert(LB->getType() == UB->getType() && "Types of loop bounds do not match");
+  IntegerType *LoopIVType = dyn_cast<IntegerType>(UB->getType());
+  assert(LoopIVType && "UB is not integer?");
+
+  BasicBlock *BeforeBB = Builder.GetInsertBlock();
+  BasicBlock *GuardBB =
+      UseGuard ? BasicBlock::Create(Context, "polly.loop_if", F) : nullptr;
+  BasicBlock *HeaderBB = BasicBlock::Create(Context, "polly.loop_header", F);
+  BasicBlock *PreHeaderBB =
+      BasicBlock::Create(Context, "polly.loop_preheader", F);
+
+  // Update LoopInfo
+  Loop *OuterLoop = LI.getLoopFor(BeforeBB);
+  Loop *NewLoop = LI.AllocateLoop();
+
+  if (OuterLoop)
+    OuterLoop->addChildLoop(NewLoop);
+  else
+    LI.addTopLevelLoop(NewLoop);
+
+  if (OuterLoop) {
+    if (GuardBB)
+      OuterLoop->addBasicBlockToLoop(GuardBB, LI);
+    OuterLoop->addBasicBlockToLoop(PreHeaderBB, LI);
+  }
+
+  NewLoop->addBasicBlockToLoop(HeaderBB, LI);
+
+  // Notify the annotator (if present) that we have a new loop, but only
+  // after the header block is set.
+  if (Annotator)
+    Annotator->pushLoop(NewLoop, Parallel);
+
+  // ExitBB
+  ExitBB = SplitBlock(BeforeBB, &*Builder.GetInsertPoint(), &DT, &LI);
+  ExitBB->setName("polly.loop_exit");
+
+  // BeforeBB
+  if (GuardBB) {
+    BeforeBB->getTerminator()->setSuccessor(0, GuardBB);
+    DT.addNewBlock(GuardBB, BeforeBB);
+
+    // GuardBB
+    Builder.SetInsertPoint(GuardBB);
+    Value *LoopGuard;
+    LoopGuard = Builder.CreateICmp(Predicate, LB, UB);
+    LoopGuard->setName("polly.loop_guard");
+    Builder.CreateCondBr(LoopGuard, PreHeaderBB, ExitBB);
+    DT.addNewBlock(PreHeaderBB, GuardBB);
+  } else {
+    BeforeBB->getTerminator()->setSuccessor(0, PreHeaderBB);
+    DT.addNewBlock(PreHeaderBB, BeforeBB);
+  }
+
+  // PreHeaderBB
+  Builder.SetInsertPoint(PreHeaderBB);
+  Builder.CreateBr(HeaderBB);
+
+  // HeaderBB
+  DT.addNewBlock(HeaderBB, PreHeaderBB);
+  Builder.SetInsertPoint(HeaderBB);
+  PHINode *IV = Builder.CreatePHI(LoopIVType, 2, "polly.indvar");
+  IV->addIncoming(LB, PreHeaderBB);
+  Stride = Builder.CreateZExtOrBitCast(Stride, LoopIVType);
+  Value *IncrementedIV = Builder.CreateNSWAdd(IV, Stride, "polly.indvar_next");
+  Value *LoopCondition =
+      Builder.CreateICmp(Predicate, IncrementedIV, UB, "polly.loop_cond");
+
+  // Create the loop latch and annotate it as such.
+  BranchInst *B = Builder.CreateCondBr(LoopCondition, HeaderBB, ExitBB);
+  if (Annotator)
+    Annotator->annotateLoopLatch(B, NewLoop, Parallel, LoopVectDisabled);
+
+  IV->addIncoming(IncrementedIV, HeaderBB);
+  if (GuardBB)
+    DT.changeImmediateDominator(ExitBB, GuardBB);
+  else
+    DT.changeImmediateDominator(ExitBB, HeaderBB);
+
+  // The loop body should be added here.
+  Builder.SetInsertPoint(HeaderBB->getFirstNonPHI());
+  return IV;
+}
+
+Value *ParallelLoopGenerator::createParallelLoop(
+    Value *LB, Value *UB, Value *Stride, SetVector<Value *> &UsedValues,
+    ValueMapT &Map, BasicBlock::iterator *LoopBody) {
+  Function *SubFn;
+
+  AllocaInst *Struct = storeValuesIntoStruct(UsedValues);
+  BasicBlock::iterator BeforeLoop = Builder.GetInsertPoint();
+  Value *IV = createSubFn(Stride, Struct, UsedValues, Map, &SubFn);
+  *LoopBody = Builder.GetInsertPoint();
+  Builder.SetInsertPoint(&*BeforeLoop);
+
+  Value *SubFnParam = Builder.CreateBitCast(Struct, Builder.getInt8PtrTy(),
+                                            "polly.par.userContext");
+
+  // Add one as the upper bound provided by OpenMP is a < comparison
+  // whereas the codegenForSequential function creates a <= comparison.
+  UB = Builder.CreateAdd(UB, ConstantInt::get(LongType, 1));
+
+  // Tell the runtime we start a parallel loop
+  createCallSpawnThreads(SubFn, SubFnParam, LB, UB, Stride);
+  Builder.CreateCall(SubFn, SubFnParam);
+  createCallJoinThreads();
+
+  return IV;
+}
+
+void ParallelLoopGenerator::createCallSpawnThreads(Value *SubFn,
+                                                   Value *SubFnParam, Value *LB,
+                                                   Value *UB, Value *Stride) {
+  const std::string Name = "GOMP_parallel_loop_runtime_start";
+
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+
+    Type *Params[] = {PointerType::getUnqual(FunctionType::get(
+                          Builder.getVoidTy(), Builder.getInt8PtrTy(), false)),
+                      Builder.getInt8PtrTy(),
+                      Builder.getInt32Ty(),
+                      LongType,
+                      LongType,
+                      LongType};
+
+    FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  Value *NumberOfThreads = Builder.getInt32(PollyNumThreads);
+  Value *Args[] = {SubFn, SubFnParam, NumberOfThreads, LB, UB, Stride};
+
+  Builder.CreateCall(F, Args);
+}
+
+Value *ParallelLoopGenerator::createCallGetWorkItem(Value *LBPtr,
+                                                    Value *UBPtr) {
+  const std::string Name = "GOMP_loop_runtime_next";
+
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    Type *Params[] = {LongType->getPointerTo(), LongType->getPointerTo()};
+    FunctionType *Ty = FunctionType::get(Builder.getInt8Ty(), Params, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  Value *Args[] = {LBPtr, UBPtr};
+  Value *Return = Builder.CreateCall(F, Args);
+  Return = Builder.CreateICmpNE(
+      Return, Builder.CreateZExt(Builder.getFalse(), Return->getType()));
+  return Return;
+}
+
+void ParallelLoopGenerator::createCallJoinThreads() {
+  const std::string Name = "GOMP_parallel_end";
+
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+
+    FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  Builder.CreateCall(F, {});
+}
+
+void ParallelLoopGenerator::createCallCleanupThread() {
+  const std::string Name = "GOMP_loop_end_nowait";
+
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+
+    FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  Builder.CreateCall(F, {});
+}
+
+Function *ParallelLoopGenerator::createSubFnDefinition() {
+  Function *F = Builder.GetInsertBlock()->getParent();
+  std::vector<Type *> Arguments(1, Builder.getInt8PtrTy());
+  FunctionType *FT = FunctionType::get(Builder.getVoidTy(), Arguments, false);
+  Function *SubFn = Function::Create(FT, Function::InternalLinkage,
+                                     F->getName() + "_polly_subfn", M);
+
+  // Certain backends (e.g., NVPTX) do not support '.'s in function names.
+  // Hence, we ensure that all '.'s are replaced by '_'s.
+  std::string FunctionName = SubFn->getName();
+  std::replace(FunctionName.begin(), FunctionName.end(), '.', '_');
+  SubFn->setName(FunctionName);
+
+  // Do not run any polly pass on the new function.
+  SubFn->addFnAttr(PollySkipFnAttr);
+
+  Function::arg_iterator AI = SubFn->arg_begin();
+  AI->setName("polly.par.userContext");
+
+  return SubFn;
+}
+
+AllocaInst *
+ParallelLoopGenerator::storeValuesIntoStruct(SetVector<Value *> &Values) {
+  SmallVector<Type *, 8> Members;
+
+  for (Value *V : Values)
+    Members.push_back(V->getType());
+
+  const DataLayout &DL = Builder.GetInsertBlock()->getModule()->getDataLayout();
+
+  // We do not want to allocate the alloca inside any loop, thus we allocate it
+  // in the entry block of the function and use annotations to denote the actual
+  // live span (similar to clang).
+  BasicBlock &EntryBB = Builder.GetInsertBlock()->getParent()->getEntryBlock();
+  Instruction *IP = &*EntryBB.getFirstInsertionPt();
+  StructType *Ty = StructType::get(Builder.getContext(), Members);
+  AllocaInst *Struct = new AllocaInst(Ty, DL.getAllocaAddrSpace(), nullptr,
+                                      "polly.par.userContext", IP);
+
+  for (unsigned i = 0; i < Values.size(); i++) {
+    Value *Address = Builder.CreateStructGEP(Ty, Struct, i);
+    Address->setName("polly.subfn.storeaddr." + Values[i]->getName());
+    Builder.CreateStore(Values[i], Address);
+  }
+
+  return Struct;
+}
+
+void ParallelLoopGenerator::extractValuesFromStruct(
+    SetVector<Value *> OldValues, Type *Ty, Value *Struct, ValueMapT &Map) {
+  for (unsigned i = 0; i < OldValues.size(); i++) {
+    Value *Address = Builder.CreateStructGEP(Ty, Struct, i);
+    Value *NewValue = Builder.CreateLoad(Address);
+    NewValue->setName("polly.subfunc.arg." + OldValues[i]->getName());
+    Map[OldValues[i]] = NewValue;
+  }
+}
+
+Value *ParallelLoopGenerator::createSubFn(Value *Stride, AllocaInst *StructData,
+                                          SetVector<Value *> Data,
+                                          ValueMapT &Map, Function **SubFnPtr) {
+  BasicBlock *PrevBB, *HeaderBB, *ExitBB, *CheckNextBB, *PreHeaderBB, *AfterBB;
+  Value *LBPtr, *UBPtr, *UserContext, *Ret1, *HasNextSchedule, *LB, *UB, *IV;
+  Function *SubFn = createSubFnDefinition();
+  LLVMContext &Context = SubFn->getContext();
+
+  // Store the previous basic block.
+  PrevBB = Builder.GetInsertBlock();
+
+  // Create basic blocks.
+  HeaderBB = BasicBlock::Create(Context, "polly.par.setup", SubFn);
+  ExitBB = BasicBlock::Create(Context, "polly.par.exit", SubFn);
+  CheckNextBB = BasicBlock::Create(Context, "polly.par.checkNext", SubFn);
+  PreHeaderBB = BasicBlock::Create(Context, "polly.par.loadIVBounds", SubFn);
+
+  DT.addNewBlock(HeaderBB, PrevBB);
+  DT.addNewBlock(ExitBB, HeaderBB);
+  DT.addNewBlock(CheckNextBB, HeaderBB);
+  DT.addNewBlock(PreHeaderBB, HeaderBB);
+
+  // Fill up basic block HeaderBB.
+  Builder.SetInsertPoint(HeaderBB);
+  LBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.LBPtr");
+  UBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.UBPtr");
+  UserContext = Builder.CreateBitCast(
+      &*SubFn->arg_begin(), StructData->getType(), "polly.par.userContext");
+
+  extractValuesFromStruct(Data, StructData->getAllocatedType(), UserContext,
+                          Map);
+  Builder.CreateBr(CheckNextBB);
+
+  // Add code to check if another set of iterations will be executed.
+  Builder.SetInsertPoint(CheckNextBB);
+  Ret1 = createCallGetWorkItem(LBPtr, UBPtr);
+  HasNextSchedule = Builder.CreateTrunc(Ret1, Builder.getInt1Ty(),
+                                        "polly.par.hasNextScheduleBlock");
+  Builder.CreateCondBr(HasNextSchedule, PreHeaderBB, ExitBB);
+
+  // Add code to load the iv bounds for this set of iterations.
+  Builder.SetInsertPoint(PreHeaderBB);
+  LB = Builder.CreateLoad(LBPtr, "polly.par.LB");
+  UB = Builder.CreateLoad(UBPtr, "polly.par.UB");
+
+  // Subtract one as the upper bound provided by OpenMP is a < comparison
+  // whereas the codegenForSequential function creates a <= comparison.
+  UB = Builder.CreateSub(UB, ConstantInt::get(LongType, 1),
+                         "polly.par.UBAdjusted");
+
+  Builder.CreateBr(CheckNextBB);
+  Builder.SetInsertPoint(&*--Builder.GetInsertPoint());
+  IV = createLoop(LB, UB, Stride, Builder, LI, DT, AfterBB, ICmpInst::ICMP_SLE,
+                  nullptr, true, /* UseGuard */ false);
+
+  BasicBlock::iterator LoopBody = Builder.GetInsertPoint();
+
+  // Add code to terminate this subfunction.
+  Builder.SetInsertPoint(ExitBB);
+  createCallCleanupThread();
+  Builder.CreateRetVoid();
+
+  Builder.SetInsertPoint(&*LoopBody);
+  *SubFnPtr = SubFn;
+
+  return IV;
+}
diff --git a/final/lib/CodeGen/ManagedMemoryRewrite.cpp b/final/lib/CodeGen/ManagedMemoryRewrite.cpp
new file mode 100644
index 0000000..2ebe9e0
--- /dev/null
+++ b/final/lib/CodeGen/ManagedMemoryRewrite.cpp
@@ -0,0 +1,442 @@
+//===---- ManagedMemoryRewrite.cpp - Rewrite global & malloc'd memory -----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Take a module and rewrite:
+// 1. `malloc` -> `polly_mallocManaged`
+// 2. `free` -> `polly_freeManaged`
+// 3. global arrays with initializers -> global arrays that are initialized
+//                                       with a constructor call to
+//                                       `polly_mallocManaged`.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/CodeGeneration.h"
+#include "polly/CodeGen/IslAst.h"
+#include "polly/CodeGen/IslNodeBuilder.h"
+#include "polly/CodeGen/PPCGCodeGeneration.h"
+#include "polly/CodeGen/Utils.h"
+#include "polly/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopDetection.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/SCEVValidator.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/BasicAliasAnalysis.h"
+#include "llvm/Analysis/CaptureTracking.h"
+#include "llvm/Analysis/GlobalsModRef.h"
+#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Linker/Linker.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+
+static cl::opt<bool> RewriteAllocas(
+    "polly-acc-rewrite-allocas",
+    cl::desc(
+        "Ask the managed memory rewriter to also rewrite alloca instructions"),
+    cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> IgnoreLinkageForGlobals(
+    "polly-acc-rewrite-ignore-linkage-for-globals",
+    cl::desc(
+        "By default, we only rewrite globals with internal linkage. This flag "
+        "enables rewriting of globals regardless of linkage"),
+    cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+#define DEBUG_TYPE "polly-acc-rewrite-managed-memory"
+namespace {
+
+static llvm::Function *getOrCreatePollyMallocManaged(Module &M) {
+  const char *Name = "polly_mallocManaged";
+  Function *F = M.getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    PollyIRBuilder Builder(M.getContext());
+    // TODO: How do I get `size_t`? I assume from DataLayout?
+    FunctionType *Ty = FunctionType::get(Builder.getInt8PtrTy(),
+                                         {Builder.getInt64Ty()}, false);
+    F = Function::Create(Ty, Linkage, Name, &M);
+  }
+
+  return F;
+}
+
+static llvm::Function *getOrCreatePollyFreeManaged(Module &M) {
+  const char *Name = "polly_freeManaged";
+  Function *F = M.getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    PollyIRBuilder Builder(M.getContext());
+    // TODO: How do I get `size_t`? I assume from DataLayout?
+    FunctionType *Ty =
+        FunctionType::get(Builder.getVoidTy(), {Builder.getInt8PtrTy()}, false);
+    F = Function::Create(Ty, Linkage, Name, &M);
+  }
+
+  return F;
+}
+
+// Expand a constant expression `Cur`, which is used at instruction `Parent`
+// at index `index`.
+// Since a constant expression can expand to multiple instructions, store all
+// the expands into a set called `Expands`.
+// Note that this goes inorder on the constant expression tree.
+// A * ((B * D) + C)
+// will be processed with first A, then B * D, then B, then D, and then C.
+// Though ConstantExprs are not treated as "trees" but as DAGs, since you can
+// have something like this:
+//    *
+//   /  \
+//   \  /
+//    (D)
+//
+// For the purposes of this expansion, we expand the two occurences of D
+// separately. Therefore, we expand the DAG into the tree:
+//  *
+// / \
+// D  D
+// TODO: We don't _have_to do this, but this is the simplest solution.
+// We can write a solution that keeps track of which constants have been
+// already expanded.
+static void expandConstantExpr(ConstantExpr *Cur, PollyIRBuilder &Builder,
+                               Instruction *Parent, int index,
+                               SmallPtrSet<Instruction *, 4> &Expands) {
+  assert(Cur && "invalid constant expression passed");
+  Instruction *I = Cur->getAsInstruction();
+  assert(I && "unable to convert ConstantExpr to Instruction");
+
+  DEBUG(dbgs() << "Expanding ConstantExpression: (" << *Cur
+               << ") in Instruction: (" << *I << ")\n";);
+
+  // Invalidate `Cur` so that no one after this point uses `Cur`. Rather,
+  // they should mutate `I`.
+  Cur = nullptr;
+
+  Expands.insert(I);
+  Parent->setOperand(index, I);
+
+  // The things that `Parent` uses (its operands) should be created
+  // before `Parent`.
+  Builder.SetInsertPoint(Parent);
+  Builder.Insert(I);
+
+  for (unsigned i = 0; i < I->getNumOperands(); i++) {
+    Value *Op = I->getOperand(i);
+    assert(isa<Constant>(Op) && "constant must have a constant operand");
+
+    if (ConstantExpr *CExprOp = dyn_cast<ConstantExpr>(Op))
+      expandConstantExpr(CExprOp, Builder, I, i, Expands);
+  }
+}
+
+// Edit all uses of `OldVal` to NewVal` in `Inst`. This will rewrite
+// `ConstantExpr`s that are used in the `Inst`.
+// Note that `replaceAllUsesWith` is insufficient for this purpose because it
+// does not rewrite values in `ConstantExpr`s.
+static void rewriteOldValToNew(Instruction *Inst, Value *OldVal, Value *NewVal,
+                               PollyIRBuilder &Builder) {
+
+  // This contains a set of instructions in which OldVal must be replaced.
+  // We start with `Inst`, and we fill it up with the expanded `ConstantExpr`s
+  // from `Inst`s arguments.
+  // We need to go through this process because `replaceAllUsesWith` does not
+  // actually edit `ConstantExpr`s.
+  SmallPtrSet<Instruction *, 4> InstsToVisit = {Inst};
+
+  // Expand all `ConstantExpr`s and place it in `InstsToVisit`.
+  for (unsigned i = 0; i < Inst->getNumOperands(); i++) {
+    Value *Operand = Inst->getOperand(i);
+    if (ConstantExpr *ValueConstExpr = dyn_cast<ConstantExpr>(Operand))
+      expandConstantExpr(ValueConstExpr, Builder, Inst, i, InstsToVisit);
+  }
+
+  // Now visit each instruction and use `replaceUsesOfWith`. We know that
+  // will work because `I` cannot have any `ConstantExpr` within it.
+  for (Instruction *I : InstsToVisit)
+    I->replaceUsesOfWith(OldVal, NewVal);
+}
+
+// Given a value `Current`, return all Instructions that may contain `Current`
+// in an expression.
+// We need this auxiliary function, because if we have a
+// `Constant` that is a user of `V`, we need to recurse into the
+// `Constant`s uses to gather the root instruciton.
+static void getInstructionUsersOfValue(Value *V,
+                                       SmallVector<Instruction *, 4> &Owners) {
+  if (auto *I = dyn_cast<Instruction>(V)) {
+    Owners.push_back(I);
+  } else {
+    // Anything that is a `User` must be a constant or an instruction.
+    auto *C = cast<Constant>(V);
+    for (Use &CUse : C->uses())
+      getInstructionUsersOfValue(CUse.getUser(), Owners);
+  }
+}
+
+static void
+replaceGlobalArray(Module &M, const DataLayout &DL, GlobalVariable &Array,
+                   SmallPtrSet<GlobalVariable *, 4> &ReplacedGlobals) {
+  // We only want arrays.
+  ArrayType *ArrayTy = dyn_cast<ArrayType>(Array.getType()->getElementType());
+  if (!ArrayTy)
+    return;
+  Type *ElemTy = ArrayTy->getElementType();
+  PointerType *ElemPtrTy = ElemTy->getPointerTo();
+
+  // We only wish to replace arrays that are visible in the module they
+  // inhabit. Otherwise, our type edit from [T] to T* would be illegal across
+  // modules.
+  const bool OnlyVisibleInsideModule = Array.hasPrivateLinkage() ||
+                                       Array.hasInternalLinkage() ||
+                                       IgnoreLinkageForGlobals;
+  if (!OnlyVisibleInsideModule) {
+    DEBUG(dbgs() << "Not rewriting (" << Array
+                 << ") to managed memory "
+                    "because it could be visible externally. To force rewrite, "
+                    "use -polly-acc-rewrite-ignore-linkage-for-globals.\n");
+    return;
+  }
+
+  if (!Array.hasInitializer() ||
+      !isa<ConstantAggregateZero>(Array.getInitializer())) {
+    DEBUG(dbgs() << "Not rewriting (" << Array
+                 << ") to managed memory "
+                    "because it has an initializer which is "
+                    "not a zeroinitializer.\n");
+    return;
+  }
+
+  // At this point, we have committed to replacing this array.
+  ReplacedGlobals.insert(&Array);
+
+  std::string NewName = Array.getName();
+  NewName += ".toptr";
+  GlobalVariable *ReplacementToArr =
+      cast<GlobalVariable>(M.getOrInsertGlobal(NewName, ElemPtrTy));
+  ReplacementToArr->setInitializer(ConstantPointerNull::get(ElemPtrTy));
+
+  Function *PollyMallocManaged = getOrCreatePollyMallocManaged(M);
+  std::string FnName = Array.getName();
+  FnName += ".constructor";
+  PollyIRBuilder Builder(M.getContext());
+  FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), false);
+  const GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+  Function *F = Function::Create(Ty, Linkage, FnName, &M);
+  BasicBlock *Start = BasicBlock::Create(M.getContext(), "entry", F);
+  Builder.SetInsertPoint(Start);
+
+  const uint64_t ArraySizeInt = DL.getTypeAllocSize(ArrayTy);
+  Value *ArraySize = Builder.getInt64(ArraySizeInt);
+  ArraySize->setName("array.size");
+
+  Value *AllocatedMemRaw =
+      Builder.CreateCall(PollyMallocManaged, {ArraySize}, "mem.raw");
+  Value *AllocatedMemTyped =
+      Builder.CreatePointerCast(AllocatedMemRaw, ElemPtrTy, "mem.typed");
+  Builder.CreateStore(AllocatedMemTyped, ReplacementToArr);
+  Builder.CreateRetVoid();
+
+  const int Priority = 0;
+  appendToGlobalCtors(M, F, Priority, ReplacementToArr);
+
+  SmallVector<Instruction *, 4> ArrayUserInstructions;
+  // Get all instructions that use array. We need to do this weird thing
+  // because `Constant`s that contain this array neeed to be expanded into
+  // instructions so that we can replace their parameters. `Constant`s cannot
+  // be edited easily, so we choose to convert all `Constant`s to
+  // `Instruction`s and handle all of the uses of `Array` uniformly.
+  for (Use &ArrayUse : Array.uses())
+    getInstructionUsersOfValue(ArrayUse.getUser(), ArrayUserInstructions);
+
+  for (Instruction *UserOfArrayInst : ArrayUserInstructions) {
+
+    Builder.SetInsertPoint(UserOfArrayInst);
+    // <ty>** -> <ty>*
+    Value *ArrPtrLoaded = Builder.CreateLoad(ReplacementToArr, "arrptr.load");
+    // <ty>* -> [ty]*
+    Value *ArrPtrLoadedBitcasted = Builder.CreateBitCast(
+        ArrPtrLoaded, ArrayTy->getPointerTo(), "arrptr.bitcast");
+    rewriteOldValToNew(UserOfArrayInst, &Array, ArrPtrLoadedBitcasted, Builder);
+  }
+}
+
+// We return all `allocas` that may need to be converted to a call to
+// cudaMallocManaged.
+static void getAllocasToBeManaged(Function &F,
+                                  SmallSet<AllocaInst *, 4> &Allocas) {
+  for (BasicBlock &BB : F) {
+    for (Instruction &I : BB) {
+      auto *Alloca = dyn_cast<AllocaInst>(&I);
+      if (!Alloca)
+        continue;
+      DEBUG(dbgs() << "Checking if (" << *Alloca << ") may be captured: ");
+
+      if (PointerMayBeCaptured(Alloca, /* ReturnCaptures */ false,
+                               /* StoreCaptures */ true)) {
+        Allocas.insert(Alloca);
+        DEBUG(dbgs() << "YES (captured).\n");
+      } else {
+        DEBUG(dbgs() << "NO (not captured).\n");
+      }
+    }
+  }
+}
+
+static void rewriteAllocaAsManagedMemory(AllocaInst *Alloca,
+                                         const DataLayout &DL) {
+  DEBUG(dbgs() << "rewriting: (" << *Alloca << ") to managed mem.\n");
+  Module *M = Alloca->getModule();
+  assert(M && "Alloca does not have a module");
+
+  PollyIRBuilder Builder(M->getContext());
+  Builder.SetInsertPoint(Alloca);
+
+  Value *MallocManagedFn = getOrCreatePollyMallocManaged(*Alloca->getModule());
+  const uint64_t Size =
+      DL.getTypeAllocSize(Alloca->getType()->getElementType());
+  Value *SizeVal = Builder.getInt64(Size);
+  Value *RawManagedMem = Builder.CreateCall(MallocManagedFn, {SizeVal});
+  Value *Bitcasted = Builder.CreateBitCast(RawManagedMem, Alloca->getType());
+
+  Function *F = Alloca->getFunction();
+  assert(F && "Alloca has invalid function");
+
+  Bitcasted->takeName(Alloca);
+  Alloca->replaceAllUsesWith(Bitcasted);
+  Alloca->eraseFromParent();
+
+  for (BasicBlock &BB : *F) {
+    ReturnInst *Return = dyn_cast<ReturnInst>(BB.getTerminator());
+    if (!Return)
+      continue;
+    Builder.SetInsertPoint(Return);
+
+    Value *FreeManagedFn = getOrCreatePollyFreeManaged(*M);
+    Builder.CreateCall(FreeManagedFn, {RawManagedMem});
+  }
+}
+
+// Replace all uses of `Old` with `New`, even inside `ConstantExpr`.
+//
+// `replaceAllUsesWith` does replace values in `ConstantExpr`. This function
+// actually does replace it in `ConstantExpr`. The caveat is that if there is
+// a use that is *outside* a function (say, at global declarations), we fail.
+// So, this is meant to be used on values which we know will only be used
+// within functions.
+//
+// This process works by looking through the uses of `Old`. If it finds a
+// `ConstantExpr`, it recursively looks for the owning instruction.
+// Then, it expands all the `ConstantExpr` to instructions and replaces
+// `Old` with `New` in the expanded instructions.
+static void replaceAllUsesAndConstantUses(Value *Old, Value *New,
+                                          PollyIRBuilder &Builder) {
+  SmallVector<Instruction *, 4> UserInstructions;
+  // Get all instructions that use array. We need to do this weird thing
+  // because `Constant`s that contain this array neeed to be expanded into
+  // instructions so that we can replace their parameters. `Constant`s cannot
+  // be edited easily, so we choose to convert all `Constant`s to
+  // `Instruction`s and handle all of the uses of `Array` uniformly.
+  for (Use &ArrayUse : Old->uses())
+    getInstructionUsersOfValue(ArrayUse.getUser(), UserInstructions);
+
+  for (Instruction *I : UserInstructions)
+    rewriteOldValToNew(I, Old, New, Builder);
+}
+
+class ManagedMemoryRewritePass : public ModulePass {
+public:
+  static char ID;
+  GPUArch Architecture;
+  GPURuntime Runtime;
+
+  ManagedMemoryRewritePass() : ModulePass(ID) {}
+  virtual bool runOnModule(Module &M) {
+    const DataLayout &DL = M.getDataLayout();
+
+    Function *Malloc = M.getFunction("malloc");
+
+    if (Malloc) {
+      PollyIRBuilder Builder(M.getContext());
+      Function *PollyMallocManaged = getOrCreatePollyMallocManaged(M);
+      assert(PollyMallocManaged && "unable to create polly_mallocManaged");
+
+      replaceAllUsesAndConstantUses(Malloc, PollyMallocManaged, Builder);
+      Malloc->eraseFromParent();
+    }
+
+    Function *Free = M.getFunction("free");
+
+    if (Free) {
+      PollyIRBuilder Builder(M.getContext());
+      Function *PollyFreeManaged = getOrCreatePollyFreeManaged(M);
+      assert(PollyFreeManaged && "unable to create polly_freeManaged");
+
+      replaceAllUsesAndConstantUses(Free, PollyFreeManaged, Builder);
+      Free->eraseFromParent();
+    }
+
+    SmallPtrSet<GlobalVariable *, 4> GlobalsToErase;
+    for (GlobalVariable &Global : M.globals())
+      replaceGlobalArray(M, DL, Global, GlobalsToErase);
+    for (GlobalVariable *G : GlobalsToErase)
+      G->eraseFromParent();
+
+    // Rewrite allocas to cudaMallocs if we are asked to do so.
+    if (RewriteAllocas) {
+      SmallSet<AllocaInst *, 4> AllocasToBeManaged;
+      for (Function &F : M.functions())
+        getAllocasToBeManaged(F, AllocasToBeManaged);
+
+      for (AllocaInst *Alloca : AllocasToBeManaged)
+        rewriteAllocaAsManagedMemory(Alloca, DL);
+    }
+
+    return true;
+  }
+};
+
+} // namespace
+char ManagedMemoryRewritePass::ID = 42;
+
+Pass *polly::createManagedMemoryRewritePassPass(GPUArch Arch,
+                                                GPURuntime Runtime) {
+  ManagedMemoryRewritePass *pass = new ManagedMemoryRewritePass();
+  pass->Runtime = Runtime;
+  pass->Architecture = Arch;
+  return pass;
+}
+
+INITIALIZE_PASS_BEGIN(
+    ManagedMemoryRewritePass, "polly-acc-rewrite-managed-memory",
+    "Polly - Rewrite all allocations in heap & data section to managed memory",
+    false, false)
+INITIALIZE_PASS_DEPENDENCY(PPCGCodeGeneration);
+INITIALIZE_PASS_DEPENDENCY(DependenceInfo);
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass);
+INITIALIZE_PASS_END(
+    ManagedMemoryRewritePass, "polly-acc-rewrite-managed-memory",
+    "Polly - Rewrite all allocations in heap & data section to managed memory",
+    false, false)
diff --git a/final/lib/CodeGen/PPCGCodeGeneration.cpp b/final/lib/CodeGen/PPCGCodeGeneration.cpp
new file mode 100644
index 0000000..d665214
--- /dev/null
+++ b/final/lib/CodeGen/PPCGCodeGeneration.cpp
@@ -0,0 +1,3631 @@
+//===------ PPCGCodeGeneration.cpp - Polly Accelerator Code Generation. ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Take a scop created by ScopInfo and map it to GPU code using the ppcg
+// GPU mapping strategy.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/PPCGCodeGeneration.h"
+#include "polly/CodeGen/CodeGeneration.h"
+#include "polly/CodeGen/IslAst.h"
+#include "polly/CodeGen/IslNodeBuilder.h"
+#include "polly/CodeGen/PerfMonitor.h"
+#include "polly/CodeGen/Utils.h"
+#include "polly/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopDetection.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/SCEVValidator.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/BasicAliasAnalysis.h"
+#include "llvm/Analysis/GlobalsModRef.h"
+#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Linker/Linker.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+
+#include "isl/union_map.h"
+
+extern "C" {
+#include "ppcg/cuda.h"
+#include "ppcg/gpu.h"
+#include "ppcg/gpu_print.h"
+#include "ppcg/ppcg.h"
+#include "ppcg/schedule.h"
+}
+
+#include "llvm/Support/Debug.h"
+
+using namespace polly;
+using namespace llvm;
+
+#define DEBUG_TYPE "polly-codegen-ppcg"
+
+static cl::opt<bool> DumpSchedule("polly-acc-dump-schedule",
+                                  cl::desc("Dump the computed GPU Schedule"),
+                                  cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                                  cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    DumpCode("polly-acc-dump-code",
+             cl::desc("Dump C code describing the GPU mapping"), cl::Hidden,
+             cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> DumpKernelIR("polly-acc-dump-kernel-ir",
+                                  cl::desc("Dump the kernel LLVM-IR"),
+                                  cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                                  cl::cat(PollyCategory));
+
+static cl::opt<bool> DumpKernelASM("polly-acc-dump-kernel-asm",
+                                   cl::desc("Dump the kernel assembly code"),
+                                   cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                                   cl::cat(PollyCategory));
+
+static cl::opt<bool> FastMath("polly-acc-fastmath",
+                              cl::desc("Allow unsafe math optimizations"),
+                              cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                              cl::cat(PollyCategory));
+static cl::opt<bool> SharedMemory("polly-acc-use-shared",
+                                  cl::desc("Use shared memory"), cl::Hidden,
+                                  cl::init(false), cl::ZeroOrMore,
+                                  cl::cat(PollyCategory));
+static cl::opt<bool> PrivateMemory("polly-acc-use-private",
+                                   cl::desc("Use private memory"), cl::Hidden,
+                                   cl::init(false), cl::ZeroOrMore,
+                                   cl::cat(PollyCategory));
+
+bool polly::PollyManagedMemory;
+static cl::opt<bool, true>
+    XManagedMemory("polly-acc-codegen-managed-memory",
+                   cl::desc("Generate Host kernel code assuming"
+                            " that all memory has been"
+                            " declared as managed memory"),
+                   cl::location(PollyManagedMemory), cl::Hidden,
+                   cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    FailOnVerifyModuleFailure("polly-acc-fail-on-verify-module-failure",
+                              cl::desc("Fail and generate a backtrace if"
+                                       " verifyModule fails on the GPU "
+                                       " kernel module."),
+                              cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                              cl::cat(PollyCategory));
+
+static cl::opt<std::string> CUDALibDevice(
+    "polly-acc-libdevice", cl::desc("Path to CUDA libdevice"), cl::Hidden,
+    cl::init("/usr/local/cuda/nvvm/libdevice/libdevice.compute_20.10.ll"),
+    cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<std::string>
+    CudaVersion("polly-acc-cuda-version",
+                cl::desc("The CUDA version to compile for"), cl::Hidden,
+                cl::init("sm_30"), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int>
+    MinCompute("polly-acc-mincompute",
+               cl::desc("Minimal number of compute statements to run on GPU."),
+               cl::Hidden, cl::init(10 * 512 * 512));
+
+extern bool polly::PerfMonitoring;
+
+/// Return  a unique name for a Scop, which is the scop region with the
+/// function name.
+std::string getUniqueScopName(const Scop *S) {
+  return "Scop Region: " + S->getNameStr() +
+         " | Function: " + std::string(S->getFunction().getName());
+}
+
+/// Used to store information PPCG wants for kills. This information is
+/// used by live range reordering.
+///
+/// @see computeLiveRangeReordering
+/// @see GPUNodeBuilder::createPPCGScop
+/// @see GPUNodeBuilder::createPPCGProg
+struct MustKillsInfo {
+  /// Collection of all kill statements that will be sequenced at the end of
+  /// PPCGScop->schedule.
+  ///
+  /// The nodes in `KillsSchedule` will be merged using `isl_schedule_set`
+  /// which merges schedules in *arbitrary* order.
+  /// (we don't care about the order of the kills anyway).
+  isl::schedule KillsSchedule;
+  /// Map from kill statement instances to scalars that need to be
+  /// killed.
+  ///
+  /// We currently derive kill information for:
+  ///  1. phi nodes. PHI nodes are not alive outside the scop and can
+  ///     consequently all be killed.
+  ///  2. Scalar arrays that are not used outside the Scop. This is
+  ///     checked by `isScalarUsesContainedInScop`.
+  /// [params] -> { [Stmt_phantom[] -> ref_phantom[]] -> scalar_to_kill[] }
+  isl::union_map TaggedMustKills;
+
+  /// Tagged must kills stripped of the tags.
+  /// [params] -> { Stmt_phantom[]  -> scalar_to_kill[] }
+  isl::union_map MustKills;
+
+  MustKillsInfo() : KillsSchedule(nullptr) {}
+};
+
+/// Check if SAI's uses are entirely contained within Scop S.
+/// If a scalar is used only with a Scop, we are free to kill it, as no data
+/// can flow in/out of the value any more.
+/// @see computeMustKillsInfo
+static bool isScalarUsesContainedInScop(const Scop &S,
+                                        const ScopArrayInfo *SAI) {
+  assert(SAI->isValueKind() && "this function only deals with scalars."
+                               " Dealing with arrays required alias analysis");
+
+  const Region &R = S.getRegion();
+  for (User *U : SAI->getBasePtr()->users()) {
+    Instruction *I = dyn_cast<Instruction>(U);
+    assert(I && "invalid user of scop array info");
+    if (!R.contains(I))
+      return false;
+  }
+  return true;
+}
+
+/// Compute must-kills needed to enable live range reordering with PPCG.
+///
+/// @params S The Scop to compute live range reordering information
+/// @returns live range reordering information that can be used to setup
+/// PPCG.
+static MustKillsInfo computeMustKillsInfo(const Scop &S) {
+  const isl::space ParamSpace = S.getParamSpace();
+  MustKillsInfo Info;
+
+  // 1. Collect all ScopArrayInfo that satisfy *any* of the criteria:
+  //      1.1 phi nodes in scop.
+  //      1.2 scalars that are only used within the scop
+  SmallVector<isl::id, 4> KillMemIds;
+  for (ScopArrayInfo *SAI : S.arrays()) {
+    if (SAI->isPHIKind() ||
+        (SAI->isValueKind() && isScalarUsesContainedInScop(S, SAI)))
+      KillMemIds.push_back(isl::manage(SAI->getBasePtrId().release()));
+  }
+
+  Info.TaggedMustKills = isl::union_map::empty(ParamSpace);
+  Info.MustKills = isl::union_map::empty(ParamSpace);
+
+  // Initialising KillsSchedule to `isl_set_empty` creates an empty node in the
+  // schedule:
+  //     - filter: "[control] -> { }"
+  // So, we choose to not create this to keep the output a little nicer,
+  // at the cost of some code complexity.
+  Info.KillsSchedule = nullptr;
+
+  for (isl::id &ToKillId : KillMemIds) {
+    isl::id KillStmtId = isl::id::alloc(
+        S.getIslCtx(),
+        std::string("SKill_phantom_").append(ToKillId.get_name()), nullptr);
+
+    // NOTE: construction of tagged_must_kill:
+    // 2. We need to construct a map:
+    //     [param] -> { [Stmt_phantom[] -> ref_phantom[]] -> scalar_to_kill[] }
+    // To construct this, we use `isl_map_domain_product` on 2 maps`:
+    // 2a. StmtToScalar:
+    //         [param] -> { Stmt_phantom[] -> scalar_to_kill[] }
+    // 2b. PhantomRefToScalar:
+    //         [param] -> { ref_phantom[] -> scalar_to_kill[] }
+    //
+    // Combining these with `isl_map_domain_product` gives us
+    // TaggedMustKill:
+    //     [param] -> { [Stmt[] -> phantom_ref[]] -> scalar_to_kill[] }
+
+    // 2a. [param] -> { Stmt[] -> scalar_to_kill[] }
+    isl::map StmtToScalar = isl::map::universe(ParamSpace);
+    StmtToScalar = StmtToScalar.set_tuple_id(isl::dim::in, isl::id(KillStmtId));
+    StmtToScalar = StmtToScalar.set_tuple_id(isl::dim::out, isl::id(ToKillId));
+
+    isl::id PhantomRefId = isl::id::alloc(
+        S.getIslCtx(), std::string("ref_phantom") + ToKillId.get_name(),
+        nullptr);
+
+    // 2b. [param] -> { phantom_ref[] -> scalar_to_kill[] }
+    isl::map PhantomRefToScalar = isl::map::universe(ParamSpace);
+    PhantomRefToScalar =
+        PhantomRefToScalar.set_tuple_id(isl::dim::in, PhantomRefId);
+    PhantomRefToScalar =
+        PhantomRefToScalar.set_tuple_id(isl::dim::out, ToKillId);
+
+    // 2. [param] -> { [Stmt[] -> phantom_ref[]] -> scalar_to_kill[] }
+    isl::map TaggedMustKill = StmtToScalar.domain_product(PhantomRefToScalar);
+    Info.TaggedMustKills = Info.TaggedMustKills.unite(TaggedMustKill);
+
+    // 2. [param] -> { Stmt[] -> scalar_to_kill[] }
+    Info.MustKills = Info.TaggedMustKills.domain_factor_domain();
+
+    // 3. Create the kill schedule of the form:
+    //     "[param] -> { Stmt_phantom[] }"
+    // Then add this to Info.KillsSchedule.
+    isl::space KillStmtSpace = ParamSpace;
+    KillStmtSpace = KillStmtSpace.set_tuple_id(isl::dim::set, KillStmtId);
+    isl::union_set KillStmtDomain = isl::set::universe(KillStmtSpace);
+
+    isl::schedule KillSchedule = isl::schedule::from_domain(KillStmtDomain);
+    if (Info.KillsSchedule)
+      Info.KillsSchedule = Info.KillsSchedule.set(KillSchedule);
+    else
+      Info.KillsSchedule = KillSchedule;
+  }
+
+  return Info;
+}
+
+/// Create the ast expressions for a ScopStmt.
+///
+/// This function is a callback for to generate the ast expressions for each
+/// of the scheduled ScopStmts.
+static __isl_give isl_id_to_ast_expr *pollyBuildAstExprForStmt(
+    void *StmtT, __isl_take isl_ast_build *Build_C,
+    isl_multi_pw_aff *(*FunctionIndex)(__isl_take isl_multi_pw_aff *MPA,
+                                       isl_id *Id, void *User),
+    void *UserIndex,
+    isl_ast_expr *(*FunctionExpr)(isl_ast_expr *Expr, isl_id *Id, void *User),
+    void *UserExpr) {
+
+  ScopStmt *Stmt = (ScopStmt *)StmtT;
+
+  if (!Stmt || !Build_C)
+    return NULL;
+
+  isl::ast_build Build = isl::manage(isl_ast_build_copy(Build_C));
+  isl::ctx Ctx = Build.get_ctx();
+  isl::id_to_ast_expr RefToExpr = isl::id_to_ast_expr::alloc(Ctx, 0);
+
+  Stmt->setAstBuild(Build);
+
+  for (MemoryAccess *Acc : *Stmt) {
+    isl::map AddrFunc = Acc->getAddressFunction();
+    AddrFunc = AddrFunc.intersect_domain(Stmt->getDomain());
+
+    isl::id RefId = Acc->getId();
+    isl::pw_multi_aff PMA = isl::pw_multi_aff::from_map(AddrFunc);
+
+    isl::multi_pw_aff MPA = isl::multi_pw_aff(PMA);
+    MPA = MPA.coalesce();
+    MPA = isl::manage(FunctionIndex(MPA.release(), RefId.get(), UserIndex));
+
+    isl::ast_expr Access = Build.access_from(MPA);
+    Access = isl::manage(FunctionExpr(Access.release(), RefId.get(), UserExpr));
+    RefToExpr = RefToExpr.set(RefId, Access);
+  }
+
+  return RefToExpr.release();
+}
+
+/// Given a LLVM Type, compute its size in bytes,
+static int computeSizeInBytes(const Type *T) {
+  int bytes = T->getPrimitiveSizeInBits() / 8;
+  if (bytes == 0)
+    bytes = T->getScalarSizeInBits() / 8;
+  return bytes;
+}
+
+/// Generate code for a GPU specific isl AST.
+///
+/// The GPUNodeBuilder augments the general existing IslNodeBuilder, which
+/// generates code for general-purpose AST nodes, with special functionality
+/// for generating GPU specific user nodes.
+///
+/// @see GPUNodeBuilder::createUser
+class GPUNodeBuilder : public IslNodeBuilder {
+public:
+  GPUNodeBuilder(PollyIRBuilder &Builder, ScopAnnotator &Annotator,
+                 const DataLayout &DL, LoopInfo &LI, ScalarEvolution &SE,
+                 DominatorTree &DT, Scop &S, BasicBlock *StartBlock,
+                 gpu_prog *Prog, GPURuntime Runtime, GPUArch Arch)
+      : IslNodeBuilder(Builder, Annotator, DL, LI, SE, DT, S, StartBlock),
+        Prog(Prog), Runtime(Runtime), Arch(Arch) {
+    getExprBuilder().setIDToSAI(&IDToSAI);
+  }
+
+  /// Create after-run-time-check initialization code.
+  void initializeAfterRTH();
+
+  /// Finalize the generated scop.
+  virtual void finalize();
+
+  /// Track if the full build process was successful.
+  ///
+  /// This value is set to false, if throughout the build process an error
+  /// occurred which prevents us from generating valid GPU code.
+  bool BuildSuccessful = true;
+
+  /// The maximal number of loops surrounding a sequential kernel.
+  unsigned DeepestSequential = 0;
+
+  /// The maximal number of loops surrounding a parallel kernel.
+  unsigned DeepestParallel = 0;
+
+  /// Return the name to set for the ptx_kernel.
+  std::string getKernelFuncName(int Kernel_id);
+
+private:
+  /// A vector of array base pointers for which a new ScopArrayInfo was created.
+  ///
+  /// This vector is used to delete the ScopArrayInfo when it is not needed any
+  /// more.
+  std::vector<Value *> LocalArrays;
+
+  /// A map from ScopArrays to their corresponding device allocations.
+  std::map<ScopArrayInfo *, Value *> DeviceAllocations;
+
+  /// The current GPU context.
+  Value *GPUContext;
+
+  /// The set of isl_ids allocated in the kernel
+  std::vector<isl_id *> KernelIds;
+
+  /// A module containing GPU code.
+  ///
+  /// This pointer is only set in case we are currently generating GPU code.
+  std::unique_ptr<Module> GPUModule;
+
+  /// The GPU program we generate code for.
+  gpu_prog *Prog;
+
+  /// The GPU Runtime implementation to use (OpenCL or CUDA).
+  GPURuntime Runtime;
+
+  /// The GPU Architecture to target.
+  GPUArch Arch;
+
+  /// Class to free isl_ids.
+  class IslIdDeleter {
+  public:
+    void operator()(__isl_take isl_id *Id) { isl_id_free(Id); };
+  };
+
+  /// A set containing all isl_ids allocated in a GPU kernel.
+  ///
+  /// By releasing this set all isl_ids will be freed.
+  std::set<std::unique_ptr<isl_id, IslIdDeleter>> KernelIDs;
+
+  IslExprBuilder::IDToScopArrayInfoTy IDToSAI;
+
+  /// Create code for user-defined AST nodes.
+  ///
+  /// These AST nodes can be of type:
+  ///
+  ///   - ScopStmt:      A computational statement (TODO)
+  ///   - Kernel:        A GPU kernel call (TODO)
+  ///   - Data-Transfer: A GPU <-> CPU data-transfer
+  ///   - In-kernel synchronization
+  ///   - In-kernel memory copy statement
+  ///
+  /// @param UserStmt The ast node to generate code for.
+  virtual void createUser(__isl_take isl_ast_node *UserStmt);
+
+  virtual void createFor(__isl_take isl_ast_node *Node);
+
+  enum DataDirection { HOST_TO_DEVICE, DEVICE_TO_HOST };
+
+  /// Create code for a data transfer statement
+  ///
+  /// @param TransferStmt The data transfer statement.
+  /// @param Direction The direction in which to transfer data.
+  void createDataTransfer(__isl_take isl_ast_node *TransferStmt,
+                          enum DataDirection Direction);
+
+  /// Find llvm::Values referenced in GPU kernel.
+  ///
+  /// @param Kernel The kernel to scan for llvm::Values
+  ///
+  /// @returns A tuple, whose:
+  ///          - First element contains the set of values referenced by the
+  ///            kernel
+  ///          - Second element contains the set of functions referenced by the
+  ///             kernel. All functions in the set satisfy
+  ///             `isValidFunctionInKernel`.
+  ///          - Third element contains loops that have induction variables
+  ///            which are used in the kernel, *and* these loops are *neither*
+  ///            in the scop, nor do they immediately surroung the Scop.
+  ///            See [Code generation of induction variables of loops outside
+  ///            Scops]
+  std::tuple<SetVector<Value *>, SetVector<Function *>, SetVector<const Loop *>,
+             isl::space>
+  getReferencesInKernel(ppcg_kernel *Kernel);
+
+  /// Compute the sizes of the execution grid for a given kernel.
+  ///
+  /// @param Kernel The kernel to compute grid sizes for.
+  ///
+  /// @returns A tuple with grid sizes for X and Y dimension
+  std::tuple<Value *, Value *> getGridSizes(ppcg_kernel *Kernel);
+
+  /// Get the managed array pointer for sending host pointers to the device.
+  /// \note
+  /// This is to be used only with managed memory
+  Value *getManagedDeviceArray(gpu_array_info *Array, ScopArrayInfo *ArrayInfo);
+
+  /// Compute the sizes of the thread blocks for a given kernel.
+  ///
+  /// @param Kernel The kernel to compute thread block sizes for.
+  ///
+  /// @returns A tuple with thread block sizes for X, Y, and Z dimensions.
+  std::tuple<Value *, Value *, Value *> getBlockSizes(ppcg_kernel *Kernel);
+
+  /// Store a specific kernel launch parameter in the array of kernel launch
+  /// parameters.
+  ///
+  /// @param Parameters The list of parameters in which to store.
+  /// @param Param      The kernel launch parameter to store.
+  /// @param Index      The index in the parameter list, at which to store the
+  ///                   parameter.
+  void insertStoreParameter(Instruction *Parameters, Instruction *Param,
+                            int Index);
+
+  /// Create kernel launch parameters.
+  ///
+  /// @param Kernel        The kernel to create parameters for.
+  /// @param F             The kernel function that has been created.
+  /// @param SubtreeValues The set of llvm::Values referenced by this kernel.
+  ///
+  /// @returns A stack allocated array with pointers to the parameter
+  ///          values that are passed to the kernel.
+  Value *createLaunchParameters(ppcg_kernel *Kernel, Function *F,
+                                SetVector<Value *> SubtreeValues);
+
+  /// Create declarations for kernel variable.
+  ///
+  /// This includes shared memory declarations.
+  ///
+  /// @param Kernel        The kernel definition to create variables for.
+  /// @param FN            The function into which to generate the variables.
+  void createKernelVariables(ppcg_kernel *Kernel, Function *FN);
+
+  /// Add CUDA annotations to module.
+  ///
+  /// Add a set of CUDA annotations that declares the maximal block dimensions
+  /// that will be used to execute the CUDA kernel. This allows the NVIDIA
+  /// PTX compiler to bound the number of allocated registers to ensure the
+  /// resulting kernel is known to run with up to as many block dimensions
+  /// as specified here.
+  ///
+  /// @param M         The module to add the annotations to.
+  /// @param BlockDimX The size of block dimension X.
+  /// @param BlockDimY The size of block dimension Y.
+  /// @param BlockDimZ The size of block dimension Z.
+  void addCUDAAnnotations(Module *M, Value *BlockDimX, Value *BlockDimY,
+                          Value *BlockDimZ);
+
+  /// Create GPU kernel.
+  ///
+  /// Code generate the kernel described by @p KernelStmt.
+  ///
+  /// @param KernelStmt The ast node to generate kernel code for.
+  void createKernel(__isl_take isl_ast_node *KernelStmt);
+
+  /// Generate code that computes the size of an array.
+  ///
+  /// @param Array The array for which to compute a size.
+  Value *getArraySize(gpu_array_info *Array);
+
+  /// Generate code to compute the minimal offset at which an array is accessed.
+  ///
+  /// The offset of an array is the minimal array location accessed in a scop.
+  ///
+  /// Example:
+  ///
+  ///   for (long i = 0; i < 100; i++)
+  ///     A[i + 42] += ...
+  ///
+  ///   getArrayOffset(A) results in 42.
+  ///
+  /// @param Array The array for which to compute the offset.
+  /// @returns An llvm::Value that contains the offset of the array.
+  Value *getArrayOffset(gpu_array_info *Array);
+
+  /// Prepare the kernel arguments for kernel code generation
+  ///
+  /// @param Kernel The kernel to generate code for.
+  /// @param FN     The function created for the kernel.
+  void prepareKernelArguments(ppcg_kernel *Kernel, Function *FN);
+
+  /// Create kernel function.
+  ///
+  /// Create a kernel function located in a newly created module that can serve
+  /// as target for device code generation. Set the Builder to point to the
+  /// start block of this newly created function.
+  ///
+  /// @param Kernel The kernel to generate code for.
+  /// @param SubtreeValues The set of llvm::Values referenced by this kernel.
+  /// @param SubtreeFunctions The set of llvm::Functions referenced by this
+  ///                         kernel.
+  void createKernelFunction(ppcg_kernel *Kernel,
+                            SetVector<Value *> &SubtreeValues,
+                            SetVector<Function *> &SubtreeFunctions);
+
+  /// Create the declaration of a kernel function.
+  ///
+  /// The kernel function takes as arguments:
+  ///
+  ///   - One i8 pointer for each external array reference used in the kernel.
+  ///   - Host iterators
+  ///   - Parameters
+  ///   - Other LLVM Value references (TODO)
+  ///
+  /// @param Kernel The kernel to generate the function declaration for.
+  /// @param SubtreeValues The set of llvm::Values referenced by this kernel.
+  ///
+  /// @returns The newly declared function.
+  Function *createKernelFunctionDecl(ppcg_kernel *Kernel,
+                                     SetVector<Value *> &SubtreeValues);
+
+  /// Insert intrinsic functions to obtain thread and block ids.
+  ///
+  /// @param The kernel to generate the intrinsic functions for.
+  void insertKernelIntrinsics(ppcg_kernel *Kernel);
+
+  /// Insert function calls to retrieve the SPIR group/local ids.
+  ///
+  /// @param The kernel to generate the function calls for.
+  void insertKernelCallsSPIR(ppcg_kernel *Kernel);
+
+  /// Setup the creation of functions referenced by the GPU kernel.
+  ///
+  /// 1. Create new function declarations in GPUModule which are the same as
+  /// SubtreeFunctions.
+  ///
+  /// 2. Populate IslNodeBuilder::ValueMap with mappings from
+  /// old functions (that come from the original module) to new functions
+  /// (that are created within GPUModule). That way, we generate references
+  /// to the correct function (in GPUModule) in BlockGenerator.
+  ///
+  /// @see IslNodeBuilder::ValueMap
+  /// @see BlockGenerator::GlobalMap
+  /// @see BlockGenerator::getNewValue
+  /// @see GPUNodeBuilder::getReferencesInKernel.
+  ///
+  /// @param SubtreeFunctions The set of llvm::Functions referenced by
+  ///                         this kernel.
+  void setupKernelSubtreeFunctions(SetVector<Function *> SubtreeFunctions);
+
+  /// Create a global-to-shared or shared-to-global copy statement.
+  ///
+  /// @param CopyStmt The copy statement to generate code for
+  void createKernelCopy(ppcg_kernel_stmt *CopyStmt);
+
+  /// Create code for a ScopStmt called in @p Expr.
+  ///
+  /// @param Expr The expression containing the call.
+  /// @param KernelStmt The kernel statement referenced in the call.
+  void createScopStmt(isl_ast_expr *Expr, ppcg_kernel_stmt *KernelStmt);
+
+  /// Create an in-kernel synchronization call.
+  void createKernelSync();
+
+  /// Create a PTX assembly string for the current GPU kernel.
+  ///
+  /// @returns A string containing the corresponding PTX assembly code.
+  std::string createKernelASM();
+
+  /// Remove references from the dominator tree to the kernel function @p F.
+  ///
+  /// @param F The function to remove references to.
+  void clearDominators(Function *F);
+
+  /// Remove references from scalar evolution to the kernel function @p F.
+  ///
+  /// @param F The function to remove references to.
+  void clearScalarEvolution(Function *F);
+
+  /// Remove references from loop info to the kernel function @p F.
+  ///
+  /// @param F The function to remove references to.
+  void clearLoops(Function *F);
+
+  /// Check if the scop requires to be linked with CUDA's libdevice.
+  bool requiresCUDALibDevice();
+
+  /// Link with the NVIDIA libdevice library (if needed and available).
+  void addCUDALibDevice();
+
+  /// Finalize the generation of the kernel function.
+  ///
+  /// Free the LLVM-IR module corresponding to the kernel and -- if requested --
+  /// dump its IR to stderr.
+  ///
+  /// @returns The Assembly string of the kernel.
+  std::string finalizeKernelFunction();
+
+  /// Finalize the generation of the kernel arguments.
+  ///
+  /// This function ensures that not-read-only scalars used in a kernel are
+  /// stored back to the global memory location they are backed with before
+  /// the kernel terminates.
+  ///
+  /// @params Kernel The kernel to finalize kernel arguments for.
+  void finalizeKernelArguments(ppcg_kernel *Kernel);
+
+  /// Create code that allocates memory to store arrays on device.
+  void allocateDeviceArrays();
+
+  /// Create code to prepare the managed device pointers.
+  void prepareManagedDeviceArrays();
+
+  /// Free all allocated device arrays.
+  void freeDeviceArrays();
+
+  /// Create a call to initialize the GPU context.
+  ///
+  /// @returns A pointer to the newly initialized context.
+  Value *createCallInitContext();
+
+  /// Create a call to get the device pointer for a kernel allocation.
+  ///
+  /// @param Allocation The Polly GPU allocation
+  ///
+  /// @returns The device parameter corresponding to this allocation.
+  Value *createCallGetDevicePtr(Value *Allocation);
+
+  /// Create a call to free the GPU context.
+  ///
+  /// @param Context A pointer to an initialized GPU context.
+  void createCallFreeContext(Value *Context);
+
+  /// Create a call to allocate memory on the device.
+  ///
+  /// @param Size The size of memory to allocate
+  ///
+  /// @returns A pointer that identifies this allocation.
+  Value *createCallAllocateMemoryForDevice(Value *Size);
+
+  /// Create a call to free a device array.
+  ///
+  /// @param Array The device array to free.
+  void createCallFreeDeviceMemory(Value *Array);
+
+  /// Create a call to copy data from host to device.
+  ///
+  /// @param HostPtr A pointer to the host data that should be copied.
+  /// @param DevicePtr A device pointer specifying the location to copy to.
+  void createCallCopyFromHostToDevice(Value *HostPtr, Value *DevicePtr,
+                                      Value *Size);
+
+  /// Create a call to copy data from device to host.
+  ///
+  /// @param DevicePtr A pointer to the device data that should be copied.
+  /// @param HostPtr A host pointer specifying the location to copy to.
+  void createCallCopyFromDeviceToHost(Value *DevicePtr, Value *HostPtr,
+                                      Value *Size);
+
+  /// Create a call to synchronize Host & Device.
+  /// \note
+  /// This is to be used only with managed memory.
+  void createCallSynchronizeDevice();
+
+  /// Create a call to get a kernel from an assembly string.
+  ///
+  /// @param Buffer The string describing the kernel.
+  /// @param Entry  The name of the kernel function to call.
+  ///
+  /// @returns A pointer to a kernel object
+  Value *createCallGetKernel(Value *Buffer, Value *Entry);
+
+  /// Create a call to free a GPU kernel.
+  ///
+  /// @param GPUKernel THe kernel to free.
+  void createCallFreeKernel(Value *GPUKernel);
+
+  /// Create a call to launch a GPU kernel.
+  ///
+  /// @param GPUKernel  The kernel to launch.
+  /// @param GridDimX   The size of the first grid dimension.
+  /// @param GridDimY   The size of the second grid dimension.
+  /// @param GridBlockX The size of the first block dimension.
+  /// @param GridBlockY The size of the second block dimension.
+  /// @param GridBlockZ The size of the third block dimension.
+  /// @param Parameters A pointer to an array that contains itself pointers to
+  ///                   the parameter values passed for each kernel argument.
+  void createCallLaunchKernel(Value *GPUKernel, Value *GridDimX,
+                              Value *GridDimY, Value *BlockDimX,
+                              Value *BlockDimY, Value *BlockDimZ,
+                              Value *Parameters);
+};
+
+std::string GPUNodeBuilder::getKernelFuncName(int Kernel_id) {
+  return "FUNC_" + S.getFunction().getName().str() + "_SCOP_" +
+         std::to_string(S.getID()) + "_KERNEL_" + std::to_string(Kernel_id);
+}
+
+void GPUNodeBuilder::initializeAfterRTH() {
+  BasicBlock *NewBB = SplitBlock(Builder.GetInsertBlock(),
+                                 &*Builder.GetInsertPoint(), &DT, &LI);
+  NewBB->setName("polly.acc.initialize");
+  Builder.SetInsertPoint(&NewBB->front());
+
+  GPUContext = createCallInitContext();
+
+  if (!PollyManagedMemory)
+    allocateDeviceArrays();
+  else
+    prepareManagedDeviceArrays();
+}
+
+void GPUNodeBuilder::finalize() {
+  if (!PollyManagedMemory)
+    freeDeviceArrays();
+
+  createCallFreeContext(GPUContext);
+  IslNodeBuilder::finalize();
+}
+
+void GPUNodeBuilder::allocateDeviceArrays() {
+  assert(!PollyManagedMemory &&
+         "Managed memory will directly send host pointers "
+         "to the kernel. There is no need for device arrays");
+  isl_ast_build *Build = isl_ast_build_from_context(S.getContext().release());
+
+  for (int i = 0; i < Prog->n_array; ++i) {
+    gpu_array_info *Array = &Prog->array[i];
+    auto *ScopArray = (ScopArrayInfo *)Array->user;
+    std::string DevArrayName("p_dev_array_");
+    DevArrayName.append(Array->name);
+
+    Value *ArraySize = getArraySize(Array);
+    Value *Offset = getArrayOffset(Array);
+    if (Offset)
+      ArraySize = Builder.CreateSub(
+          ArraySize,
+          Builder.CreateMul(Offset,
+                            Builder.getInt64(ScopArray->getElemSizeInBytes())));
+    const SCEV *SizeSCEV = SE.getSCEV(ArraySize);
+    // It makes no sense to have an array of size 0. The CUDA API will
+    // throw an error anyway if we invoke `cuMallocManaged` with size `0`. We
+    // choose to be defensive and catch this at the compile phase. It is
+    // most likely that we are doing something wrong with size computation.
+    if (SizeSCEV->isZero()) {
+      errs() << getUniqueScopName(&S)
+             << " has computed array size 0: " << *ArraySize
+             << " | for array: " << *(ScopArray->getBasePtr())
+             << ". This is illegal, exiting.\n";
+      report_fatal_error("array size was computed to be 0");
+    }
+
+    Value *DevArray = createCallAllocateMemoryForDevice(ArraySize);
+    DevArray->setName(DevArrayName);
+    DeviceAllocations[ScopArray] = DevArray;
+  }
+
+  isl_ast_build_free(Build);
+}
+
+void GPUNodeBuilder::prepareManagedDeviceArrays() {
+  assert(PollyManagedMemory &&
+         "Device array most only be prepared in managed-memory mode");
+  for (int i = 0; i < Prog->n_array; ++i) {
+    gpu_array_info *Array = &Prog->array[i];
+    ScopArrayInfo *ScopArray = (ScopArrayInfo *)Array->user;
+    Value *HostPtr;
+
+    if (gpu_array_is_scalar(Array))
+      HostPtr = BlockGen.getOrCreateAlloca(ScopArray);
+    else
+      HostPtr = ScopArray->getBasePtr();
+    HostPtr = getLatestValue(HostPtr);
+
+    Value *Offset = getArrayOffset(Array);
+    if (Offset) {
+      HostPtr = Builder.CreatePointerCast(
+          HostPtr, ScopArray->getElementType()->getPointerTo());
+      HostPtr = Builder.CreateGEP(HostPtr, Offset);
+    }
+
+    HostPtr = Builder.CreatePointerCast(HostPtr, Builder.getInt8PtrTy());
+    DeviceAllocations[ScopArray] = HostPtr;
+  }
+}
+
+void GPUNodeBuilder::addCUDAAnnotations(Module *M, Value *BlockDimX,
+                                        Value *BlockDimY, Value *BlockDimZ) {
+  auto AnnotationNode = M->getOrInsertNamedMetadata("nvvm.annotations");
+
+  for (auto &F : *M) {
+    if (F.getCallingConv() != CallingConv::PTX_Kernel)
+      continue;
+
+    Value *V[] = {BlockDimX, BlockDimY, BlockDimZ};
+
+    Metadata *Elements[] = {
+        ValueAsMetadata::get(&F),   MDString::get(M->getContext(), "maxntidx"),
+        ValueAsMetadata::get(V[0]), MDString::get(M->getContext(), "maxntidy"),
+        ValueAsMetadata::get(V[1]), MDString::get(M->getContext(), "maxntidz"),
+        ValueAsMetadata::get(V[2]),
+    };
+    MDNode *Node = MDNode::get(M->getContext(), Elements);
+    AnnotationNode->addOperand(Node);
+  }
+}
+
+void GPUNodeBuilder::freeDeviceArrays() {
+  assert(!PollyManagedMemory && "Managed memory does not use device arrays");
+  for (auto &Array : DeviceAllocations)
+    createCallFreeDeviceMemory(Array.second);
+}
+
+Value *GPUNodeBuilder::createCallGetKernel(Value *Buffer, Value *Entry) {
+  const char *Name = "polly_getKernel";
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    std::vector<Type *> Args;
+    Args.push_back(Builder.getInt8PtrTy());
+    Args.push_back(Builder.getInt8PtrTy());
+    FunctionType *Ty = FunctionType::get(Builder.getInt8PtrTy(), Args, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  return Builder.CreateCall(F, {Buffer, Entry});
+}
+
+Value *GPUNodeBuilder::createCallGetDevicePtr(Value *Allocation) {
+  const char *Name = "polly_getDevicePtr";
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    std::vector<Type *> Args;
+    Args.push_back(Builder.getInt8PtrTy());
+    FunctionType *Ty = FunctionType::get(Builder.getInt8PtrTy(), Args, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  return Builder.CreateCall(F, {Allocation});
+}
+
+void GPUNodeBuilder::createCallLaunchKernel(Value *GPUKernel, Value *GridDimX,
+                                            Value *GridDimY, Value *BlockDimX,
+                                            Value *BlockDimY, Value *BlockDimZ,
+                                            Value *Parameters) {
+  const char *Name = "polly_launchKernel";
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    std::vector<Type *> Args;
+    Args.push_back(Builder.getInt8PtrTy());
+    Args.push_back(Builder.getInt32Ty());
+    Args.push_back(Builder.getInt32Ty());
+    Args.push_back(Builder.getInt32Ty());
+    Args.push_back(Builder.getInt32Ty());
+    Args.push_back(Builder.getInt32Ty());
+    Args.push_back(Builder.getInt8PtrTy());
+    FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Args, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  Builder.CreateCall(F, {GPUKernel, GridDimX, GridDimY, BlockDimX, BlockDimY,
+                         BlockDimZ, Parameters});
+}
+
+void GPUNodeBuilder::createCallFreeKernel(Value *GPUKernel) {
+  const char *Name = "polly_freeKernel";
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    std::vector<Type *> Args;
+    Args.push_back(Builder.getInt8PtrTy());
+    FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Args, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  Builder.CreateCall(F, {GPUKernel});
+}
+
+void GPUNodeBuilder::createCallFreeDeviceMemory(Value *Array) {
+  assert(!PollyManagedMemory &&
+         "Managed memory does not allocate or free memory "
+         "for device");
+  const char *Name = "polly_freeDeviceMemory";
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    std::vector<Type *> Args;
+    Args.push_back(Builder.getInt8PtrTy());
+    FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Args, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  Builder.CreateCall(F, {Array});
+}
+
+Value *GPUNodeBuilder::createCallAllocateMemoryForDevice(Value *Size) {
+  assert(!PollyManagedMemory &&
+         "Managed memory does not allocate or free memory "
+         "for device");
+  const char *Name = "polly_allocateMemoryForDevice";
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    std::vector<Type *> Args;
+    Args.push_back(Builder.getInt64Ty());
+    FunctionType *Ty = FunctionType::get(Builder.getInt8PtrTy(), Args, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  return Builder.CreateCall(F, {Size});
+}
+
+void GPUNodeBuilder::createCallCopyFromHostToDevice(Value *HostData,
+                                                    Value *DeviceData,
+                                                    Value *Size) {
+  assert(!PollyManagedMemory &&
+         "Managed memory does not transfer memory between "
+         "device and host");
+  const char *Name = "polly_copyFromHostToDevice";
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    std::vector<Type *> Args;
+    Args.push_back(Builder.getInt8PtrTy());
+    Args.push_back(Builder.getInt8PtrTy());
+    Args.push_back(Builder.getInt64Ty());
+    FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Args, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  Builder.CreateCall(F, {HostData, DeviceData, Size});
+}
+
+void GPUNodeBuilder::createCallCopyFromDeviceToHost(Value *DeviceData,
+                                                    Value *HostData,
+                                                    Value *Size) {
+  assert(!PollyManagedMemory &&
+         "Managed memory does not transfer memory between "
+         "device and host");
+  const char *Name = "polly_copyFromDeviceToHost";
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    std::vector<Type *> Args;
+    Args.push_back(Builder.getInt8PtrTy());
+    Args.push_back(Builder.getInt8PtrTy());
+    Args.push_back(Builder.getInt64Ty());
+    FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Args, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  Builder.CreateCall(F, {DeviceData, HostData, Size});
+}
+
+void GPUNodeBuilder::createCallSynchronizeDevice() {
+  assert(PollyManagedMemory && "explicit synchronization is only necessary for "
+                               "managed memory");
+  const char *Name = "polly_synchronizeDevice";
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  Builder.CreateCall(F);
+}
+
+Value *GPUNodeBuilder::createCallInitContext() {
+  const char *Name;
+
+  switch (Runtime) {
+  case GPURuntime::CUDA:
+    Name = "polly_initContextCUDA";
+    break;
+  case GPURuntime::OpenCL:
+    Name = "polly_initContextCL";
+    break;
+  }
+
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    std::vector<Type *> Args;
+    FunctionType *Ty = FunctionType::get(Builder.getInt8PtrTy(), Args, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  return Builder.CreateCall(F, {});
+}
+
+void GPUNodeBuilder::createCallFreeContext(Value *Context) {
+  const char *Name = "polly_freeContext";
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  Function *F = M->getFunction(Name);
+
+  // If F is not available, declare it.
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    std::vector<Type *> Args;
+    Args.push_back(Builder.getInt8PtrTy());
+    FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Args, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  Builder.CreateCall(F, {Context});
+}
+
+/// Check if one string is a prefix of another.
+///
+/// @param String The string in which to look for the prefix.
+/// @param Prefix The prefix to look for.
+static bool isPrefix(std::string String, std::string Prefix) {
+  return String.find(Prefix) == 0;
+}
+
+Value *GPUNodeBuilder::getArraySize(gpu_array_info *Array) {
+  isl::ast_build Build = isl::ast_build::from_context(S.getContext());
+  Value *ArraySize = ConstantInt::get(Builder.getInt64Ty(), Array->size);
+
+  if (!gpu_array_is_scalar(Array)) {
+    isl::multi_pw_aff ArrayBound =
+        isl::manage(isl_multi_pw_aff_copy(Array->bound));
+
+    isl::pw_aff OffsetDimZero = ArrayBound.get_pw_aff(0);
+    isl::ast_expr Res = Build.expr_from(OffsetDimZero);
+
+    for (unsigned int i = 1; i < Array->n_index; i++) {
+      isl::pw_aff Bound_I = ArrayBound.get_pw_aff(i);
+      isl::ast_expr Expr = Build.expr_from(Bound_I);
+      Res = Res.mul(Expr);
+    }
+
+    Value *NumElements = ExprBuilder.create(Res.release());
+    if (NumElements->getType() != ArraySize->getType())
+      NumElements = Builder.CreateSExt(NumElements, ArraySize->getType());
+    ArraySize = Builder.CreateMul(ArraySize, NumElements);
+  }
+  return ArraySize;
+}
+
+Value *GPUNodeBuilder::getArrayOffset(gpu_array_info *Array) {
+  if (gpu_array_is_scalar(Array))
+    return nullptr;
+
+  isl::ast_build Build = isl::ast_build::from_context(S.getContext());
+
+  isl::set Min = isl::manage(isl_set_copy(Array->extent)).lexmin();
+
+  isl::set ZeroSet = isl::set::universe(Min.get_space());
+
+  for (long i = 0, n = Min.dim(isl::dim::set); i < n; i++)
+    ZeroSet = ZeroSet.fix_si(isl::dim::set, i, 0);
+
+  if (Min.is_subset(ZeroSet)) {
+    return nullptr;
+  }
+
+  isl::ast_expr Result = isl::ast_expr::from_val(isl::val(Min.get_ctx(), 0));
+
+  for (long i = 0, n = Min.dim(isl::dim::set); i < n; i++) {
+    if (i > 0) {
+      isl::pw_aff Bound_I =
+          isl::manage(isl_multi_pw_aff_get_pw_aff(Array->bound, i - 1));
+      isl::ast_expr BExpr = Build.expr_from(Bound_I);
+      Result = Result.mul(BExpr);
+    }
+    isl::pw_aff DimMin = Min.dim_min(i);
+    isl::ast_expr MExpr = Build.expr_from(DimMin);
+    Result = Result.add(MExpr);
+  }
+
+  return ExprBuilder.create(Result.release());
+}
+
+Value *GPUNodeBuilder::getManagedDeviceArray(gpu_array_info *Array,
+                                             ScopArrayInfo *ArrayInfo) {
+  assert(PollyManagedMemory && "Only used when you wish to get a host "
+                               "pointer for sending data to the kernel, "
+                               "with managed memory");
+  std::map<ScopArrayInfo *, Value *>::iterator it;
+  it = DeviceAllocations.find(ArrayInfo);
+  assert(it != DeviceAllocations.end() &&
+         "Device array expected to be available");
+  return it->second;
+}
+
+void GPUNodeBuilder::createDataTransfer(__isl_take isl_ast_node *TransferStmt,
+                                        enum DataDirection Direction) {
+  assert(!PollyManagedMemory && "Managed memory needs no data transfers");
+  isl_ast_expr *Expr = isl_ast_node_user_get_expr(TransferStmt);
+  isl_ast_expr *Arg = isl_ast_expr_get_op_arg(Expr, 0);
+  isl_id *Id = isl_ast_expr_get_id(Arg);
+  auto Array = (gpu_array_info *)isl_id_get_user(Id);
+  auto ScopArray = (ScopArrayInfo *)(Array->user);
+
+  Value *Size = getArraySize(Array);
+  Value *Offset = getArrayOffset(Array);
+  Value *DevPtr = DeviceAllocations[ScopArray];
+
+  Value *HostPtr;
+
+  if (gpu_array_is_scalar(Array))
+    HostPtr = BlockGen.getOrCreateAlloca(ScopArray);
+  else
+    HostPtr = ScopArray->getBasePtr();
+  HostPtr = getLatestValue(HostPtr);
+
+  if (Offset) {
+    HostPtr = Builder.CreatePointerCast(
+        HostPtr, ScopArray->getElementType()->getPointerTo());
+    HostPtr = Builder.CreateGEP(HostPtr, Offset);
+  }
+
+  HostPtr = Builder.CreatePointerCast(HostPtr, Builder.getInt8PtrTy());
+
+  if (Offset) {
+    Size = Builder.CreateSub(
+        Size, Builder.CreateMul(
+                  Offset, Builder.getInt64(ScopArray->getElemSizeInBytes())));
+  }
+
+  if (Direction == HOST_TO_DEVICE)
+    createCallCopyFromHostToDevice(HostPtr, DevPtr, Size);
+  else
+    createCallCopyFromDeviceToHost(DevPtr, HostPtr, Size);
+
+  isl_id_free(Id);
+  isl_ast_expr_free(Arg);
+  isl_ast_expr_free(Expr);
+  isl_ast_node_free(TransferStmt);
+}
+
+void GPUNodeBuilder::createUser(__isl_take isl_ast_node *UserStmt) {
+  isl_ast_expr *Expr = isl_ast_node_user_get_expr(UserStmt);
+  isl_ast_expr *StmtExpr = isl_ast_expr_get_op_arg(Expr, 0);
+  isl_id *Id = isl_ast_expr_get_id(StmtExpr);
+  isl_id_free(Id);
+  isl_ast_expr_free(StmtExpr);
+
+  const char *Str = isl_id_get_name(Id);
+  if (!strcmp(Str, "kernel")) {
+    createKernel(UserStmt);
+    if (PollyManagedMemory)
+      createCallSynchronizeDevice();
+    isl_ast_expr_free(Expr);
+    return;
+  }
+  if (!strcmp(Str, "init_device")) {
+    initializeAfterRTH();
+    isl_ast_node_free(UserStmt);
+    isl_ast_expr_free(Expr);
+    return;
+  }
+  if (!strcmp(Str, "clear_device")) {
+    finalize();
+    isl_ast_node_free(UserStmt);
+    isl_ast_expr_free(Expr);
+    return;
+  }
+  if (isPrefix(Str, "to_device")) {
+    if (!PollyManagedMemory)
+      createDataTransfer(UserStmt, HOST_TO_DEVICE);
+    else
+      isl_ast_node_free(UserStmt);
+
+    isl_ast_expr_free(Expr);
+    return;
+  }
+
+  if (isPrefix(Str, "from_device")) {
+    if (!PollyManagedMemory) {
+      createDataTransfer(UserStmt, DEVICE_TO_HOST);
+    } else {
+      isl_ast_node_free(UserStmt);
+    }
+    isl_ast_expr_free(Expr);
+    return;
+  }
+
+  isl_id *Anno = isl_ast_node_get_annotation(UserStmt);
+  struct ppcg_kernel_stmt *KernelStmt =
+      (struct ppcg_kernel_stmt *)isl_id_get_user(Anno);
+  isl_id_free(Anno);
+
+  switch (KernelStmt->type) {
+  case ppcg_kernel_domain:
+    createScopStmt(Expr, KernelStmt);
+    isl_ast_node_free(UserStmt);
+    return;
+  case ppcg_kernel_copy:
+    createKernelCopy(KernelStmt);
+    isl_ast_expr_free(Expr);
+    isl_ast_node_free(UserStmt);
+    return;
+  case ppcg_kernel_sync:
+    createKernelSync();
+    isl_ast_expr_free(Expr);
+    isl_ast_node_free(UserStmt);
+    return;
+  }
+
+  isl_ast_expr_free(Expr);
+  isl_ast_node_free(UserStmt);
+}
+
+void GPUNodeBuilder::createFor(__isl_take isl_ast_node *Node) {
+  createForSequential(Node, false);
+}
+
+void GPUNodeBuilder::createKernelCopy(ppcg_kernel_stmt *KernelStmt) {
+  isl_ast_expr *LocalIndex = isl_ast_expr_copy(KernelStmt->u.c.local_index);
+  LocalIndex = isl_ast_expr_address_of(LocalIndex);
+  Value *LocalAddr = ExprBuilder.create(LocalIndex);
+  isl_ast_expr *Index = isl_ast_expr_copy(KernelStmt->u.c.index);
+  Index = isl_ast_expr_address_of(Index);
+  Value *GlobalAddr = ExprBuilder.create(Index);
+
+  if (KernelStmt->u.c.read) {
+    LoadInst *Load = Builder.CreateLoad(GlobalAddr, "shared.read");
+    Builder.CreateStore(Load, LocalAddr);
+  } else {
+    LoadInst *Load = Builder.CreateLoad(LocalAddr, "shared.write");
+    Builder.CreateStore(Load, GlobalAddr);
+  }
+}
+
+void GPUNodeBuilder::createScopStmt(isl_ast_expr *Expr,
+                                    ppcg_kernel_stmt *KernelStmt) {
+  auto Stmt = (ScopStmt *)KernelStmt->u.d.stmt->stmt;
+  isl_id_to_ast_expr *Indexes = KernelStmt->u.d.ref2expr;
+
+  LoopToScevMapT LTS;
+  LTS.insert(OutsideLoopIterations.begin(), OutsideLoopIterations.end());
+
+  createSubstitutions(Expr, Stmt, LTS);
+
+  if (Stmt->isBlockStmt())
+    BlockGen.copyStmt(*Stmt, LTS, Indexes);
+  else
+    RegionGen.copyStmt(*Stmt, LTS, Indexes);
+}
+
+void GPUNodeBuilder::createKernelSync() {
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  const char *SpirName = "__gen_ocl_barrier_global";
+
+  Function *Sync;
+
+  switch (Arch) {
+  case GPUArch::SPIR64:
+  case GPUArch::SPIR32:
+    Sync = M->getFunction(SpirName);
+
+    // If Sync is not available, declare it.
+    if (!Sync) {
+      GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+      std::vector<Type *> Args;
+      FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Args, false);
+      Sync = Function::Create(Ty, Linkage, SpirName, M);
+      Sync->setCallingConv(CallingConv::SPIR_FUNC);
+    }
+    break;
+  case GPUArch::NVPTX64:
+    Sync = Intrinsic::getDeclaration(M, Intrinsic::nvvm_barrier0);
+    break;
+  }
+
+  Builder.CreateCall(Sync, {});
+}
+
+/// Collect llvm::Values referenced from @p Node
+///
+/// This function only applies to isl_ast_nodes that are user_nodes referring
+/// to a ScopStmt. All other node types are ignore.
+///
+/// @param Node The node to collect references for.
+/// @param User A user pointer used as storage for the data that is collected.
+///
+/// @returns isl_bool_true if data could be collected successfully.
+isl_bool collectReferencesInGPUStmt(__isl_keep isl_ast_node *Node, void *User) {
+  if (isl_ast_node_get_type(Node) != isl_ast_node_user)
+    return isl_bool_true;
+
+  isl_ast_expr *Expr = isl_ast_node_user_get_expr(Node);
+  isl_ast_expr *StmtExpr = isl_ast_expr_get_op_arg(Expr, 0);
+  isl_id *Id = isl_ast_expr_get_id(StmtExpr);
+  const char *Str = isl_id_get_name(Id);
+  isl_id_free(Id);
+  isl_ast_expr_free(StmtExpr);
+  isl_ast_expr_free(Expr);
+
+  if (!isPrefix(Str, "Stmt"))
+    return isl_bool_true;
+
+  Id = isl_ast_node_get_annotation(Node);
+  auto *KernelStmt = (ppcg_kernel_stmt *)isl_id_get_user(Id);
+  auto Stmt = (ScopStmt *)KernelStmt->u.d.stmt->stmt;
+  isl_id_free(Id);
+
+  addReferencesFromStmt(Stmt, User, false /* CreateScalarRefs */);
+
+  return isl_bool_true;
+}
+
+/// A list of functions that are available in NVIDIA's libdevice.
+const std::set<std::string> CUDALibDeviceFunctions = {
+    "exp",      "expf",      "expl",      "cos", "cosf", "sqrt", "sqrtf",
+    "copysign", "copysignf", "copysignl", "log", "logf", "powi", "powif"};
+
+// A map from intrinsics to their corresponding libdevice functions.
+const std::map<std::string, std::string> IntrinsicToLibdeviceFunc = {
+    {"llvm.exp.f64", "exp"},
+    {"llvm.exp.f32", "expf"},
+    {"llvm.powi.f64", "powi"},
+    {"llvm.powi.f32", "powif"}};
+
+/// Return the corresponding CUDA libdevice function name for @p F.
+/// Note that this function will try to convert instrinsics in the list
+/// IntrinsicToLibdeviceFunc into libdevice functions.
+/// This is because some intrinsics such as `exp`
+/// are not supported by the NVPTX backend.
+/// If this restriction of the backend is lifted, we should refactor our code
+/// so that we use intrinsics whenever possible.
+///
+/// Return "" if we are not compiling for CUDA.
+std::string getCUDALibDeviceFuntion(Function *F) {
+  const std::string FnName = [&] {
+    auto It = IntrinsicToLibdeviceFunc.find(F->getName());
+    if (It != IntrinsicToLibdeviceFunc.end())
+      return It->second;
+
+    return std::string(F->getName());
+  }();
+
+  if (CUDALibDeviceFunctions.count(FnName))
+    return "__nv_" + FnName;
+
+  return "";
+}
+
+/// Check if F is a function that we can code-generate in a GPU kernel.
+static bool isValidFunctionInKernel(llvm::Function *F, bool AllowLibDevice) {
+  assert(F && "F is an invalid pointer");
+  // We string compare against the name of the function to allow
+  // all variants of the intrinsic "llvm.sqrt.*", "llvm.fabs", and
+  // "llvm.copysign".
+  const StringRef Name = F->getName();
+
+  if (AllowLibDevice && getCUDALibDeviceFuntion(F).length() > 0)
+    return true;
+
+  return F->isIntrinsic() &&
+         (Name.startswith("llvm.sqrt") || Name.startswith("llvm.fabs") ||
+          Name.startswith("llvm.copysign"));
+}
+
+/// Do not take `Function` as a subtree value.
+///
+/// We try to take the reference of all subtree values and pass them along
+/// to the kernel from the host. Taking an address of any function and
+/// trying to pass along is nonsensical. Only allow `Value`s that are not
+/// `Function`s.
+static bool isValidSubtreeValue(llvm::Value *V) { return !isa<Function>(V); }
+
+/// Return `Function`s from `RawSubtreeValues`.
+static SetVector<Function *>
+getFunctionsFromRawSubtreeValues(SetVector<Value *> RawSubtreeValues,
+                                 bool AllowCUDALibDevice) {
+  SetVector<Function *> SubtreeFunctions;
+  for (Value *It : RawSubtreeValues) {
+    Function *F = dyn_cast<Function>(It);
+    if (F) {
+      assert(isValidFunctionInKernel(F, AllowCUDALibDevice) &&
+             "Code should have bailed out by "
+             "this point if an invalid function "
+             "were present in a kernel.");
+      SubtreeFunctions.insert(F);
+    }
+  }
+  return SubtreeFunctions;
+}
+
+std::tuple<SetVector<Value *>, SetVector<Function *>, SetVector<const Loop *>,
+           isl::space>
+GPUNodeBuilder::getReferencesInKernel(ppcg_kernel *Kernel) {
+  SetVector<Value *> SubtreeValues;
+  SetVector<const SCEV *> SCEVs;
+  SetVector<const Loop *> Loops;
+  isl::space ParamSpace = isl::space(S.getIslCtx(), 0, 0).params();
+  SubtreeReferences References = {
+      LI,         SE, S, ValueMap, SubtreeValues, SCEVs, getBlockGenerator(),
+      &ParamSpace};
+
+  for (const auto &I : IDToValue)
+    SubtreeValues.insert(I.second);
+
+  // NOTE: this is populated in IslNodeBuilder::addParameters
+  // See [Code generation of induction variables of loops outside Scops].
+  for (const auto &I : OutsideLoopIterations)
+    SubtreeValues.insert(cast<SCEVUnknown>(I.second)->getValue());
+
+  isl_ast_node_foreach_descendant_top_down(
+      Kernel->tree, collectReferencesInGPUStmt, &References);
+
+  for (const SCEV *Expr : SCEVs) {
+    findValues(Expr, SE, SubtreeValues);
+    findLoops(Expr, Loops);
+  }
+
+  Loops.remove_if([this](const Loop *L) {
+    return S.contains(L) || L->contains(S.getEntry());
+  });
+
+  for (auto &SAI : S.arrays())
+    SubtreeValues.remove(SAI->getBasePtr());
+
+  isl_space *Space = S.getParamSpace().release();
+  for (long i = 0, n = isl_space_dim(Space, isl_dim_param); i < n; i++) {
+    isl_id *Id = isl_space_get_dim_id(Space, isl_dim_param, i);
+    assert(IDToValue.count(Id));
+    Value *Val = IDToValue[Id];
+    SubtreeValues.remove(Val);
+    isl_id_free(Id);
+  }
+  isl_space_free(Space);
+
+  for (long i = 0, n = isl_space_dim(Kernel->space, isl_dim_set); i < n; i++) {
+    isl_id *Id = isl_space_get_dim_id(Kernel->space, isl_dim_set, i);
+    assert(IDToValue.count(Id));
+    Value *Val = IDToValue[Id];
+    SubtreeValues.remove(Val);
+    isl_id_free(Id);
+  }
+
+  // Note: { ValidSubtreeValues, ValidSubtreeFunctions } partitions
+  // SubtreeValues. This is important, because we should not lose any
+  // SubtreeValues in the process of constructing the
+  // "ValidSubtree{Values, Functions} sets. Nor should the set
+  // ValidSubtree{Values, Functions} have any common element.
+  auto ValidSubtreeValuesIt =
+      make_filter_range(SubtreeValues, isValidSubtreeValue);
+  SetVector<Value *> ValidSubtreeValues(ValidSubtreeValuesIt.begin(),
+                                        ValidSubtreeValuesIt.end());
+
+  bool AllowCUDALibDevice = Arch == GPUArch::NVPTX64;
+
+  SetVector<Function *> ValidSubtreeFunctions(
+      getFunctionsFromRawSubtreeValues(SubtreeValues, AllowCUDALibDevice));
+
+  // @see IslNodeBuilder::getReferencesInSubtree
+  SetVector<Value *> ReplacedValues;
+  for (Value *V : ValidSubtreeValues) {
+    auto It = ValueMap.find(V);
+    if (It == ValueMap.end())
+      ReplacedValues.insert(V);
+    else
+      ReplacedValues.insert(It->second);
+  }
+  return std::make_tuple(ReplacedValues, ValidSubtreeFunctions, Loops,
+                         ParamSpace);
+}
+
+void GPUNodeBuilder::clearDominators(Function *F) {
+  DomTreeNode *N = DT.getNode(&F->getEntryBlock());
+  std::vector<BasicBlock *> Nodes;
+  for (po_iterator<DomTreeNode *> I = po_begin(N), E = po_end(N); I != E; ++I)
+    Nodes.push_back(I->getBlock());
+
+  for (BasicBlock *BB : Nodes)
+    DT.eraseNode(BB);
+}
+
+void GPUNodeBuilder::clearScalarEvolution(Function *F) {
+  for (BasicBlock &BB : *F) {
+    Loop *L = LI.getLoopFor(&BB);
+    if (L)
+      SE.forgetLoop(L);
+  }
+}
+
+void GPUNodeBuilder::clearLoops(Function *F) {
+  for (BasicBlock &BB : *F) {
+    Loop *L = LI.getLoopFor(&BB);
+    if (L)
+      SE.forgetLoop(L);
+    LI.removeBlock(&BB);
+  }
+}
+
+std::tuple<Value *, Value *> GPUNodeBuilder::getGridSizes(ppcg_kernel *Kernel) {
+  std::vector<Value *> Sizes;
+  isl::ast_build Context = isl::ast_build::from_context(S.getContext());
+
+  isl::multi_pw_aff GridSizePwAffs =
+      isl::manage(isl_multi_pw_aff_copy(Kernel->grid_size));
+  for (long i = 0; i < Kernel->n_grid; i++) {
+    isl::pw_aff Size = GridSizePwAffs.get_pw_aff(i);
+    isl::ast_expr GridSize = Context.expr_from(Size);
+    Value *Res = ExprBuilder.create(GridSize.release());
+    Res = Builder.CreateTrunc(Res, Builder.getInt32Ty());
+    Sizes.push_back(Res);
+  }
+
+  for (long i = Kernel->n_grid; i < 3; i++)
+    Sizes.push_back(ConstantInt::get(Builder.getInt32Ty(), 1));
+
+  return std::make_tuple(Sizes[0], Sizes[1]);
+}
+
+std::tuple<Value *, Value *, Value *>
+GPUNodeBuilder::getBlockSizes(ppcg_kernel *Kernel) {
+  std::vector<Value *> Sizes;
+
+  for (long i = 0; i < Kernel->n_block; i++) {
+    Value *Res = ConstantInt::get(Builder.getInt32Ty(), Kernel->block_dim[i]);
+    Sizes.push_back(Res);
+  }
+
+  for (long i = Kernel->n_block; i < 3; i++)
+    Sizes.push_back(ConstantInt::get(Builder.getInt32Ty(), 1));
+
+  return std::make_tuple(Sizes[0], Sizes[1], Sizes[2]);
+}
+
+void GPUNodeBuilder::insertStoreParameter(Instruction *Parameters,
+                                          Instruction *Param, int Index) {
+  Value *Slot = Builder.CreateGEP(
+      Parameters, {Builder.getInt64(0), Builder.getInt64(Index)});
+  Value *ParamTyped = Builder.CreatePointerCast(Param, Builder.getInt8PtrTy());
+  Builder.CreateStore(ParamTyped, Slot);
+}
+
+Value *
+GPUNodeBuilder::createLaunchParameters(ppcg_kernel *Kernel, Function *F,
+                                       SetVector<Value *> SubtreeValues) {
+  const int NumArgs = F->arg_size();
+  std::vector<int> ArgSizes(NumArgs);
+
+  // If we are using the OpenCL Runtime, we need to add the kernel argument
+  // sizes to the end of the launch-parameter list, so OpenCL can determine
+  // how big the respective kernel arguments are.
+  // Here we need to reserve adequate space for that.
+  Type *ArrayTy;
+  if (Runtime == GPURuntime::OpenCL)
+    ArrayTy = ArrayType::get(Builder.getInt8PtrTy(), 2 * NumArgs);
+  else
+    ArrayTy = ArrayType::get(Builder.getInt8PtrTy(), NumArgs);
+
+  BasicBlock *EntryBlock =
+      &Builder.GetInsertBlock()->getParent()->getEntryBlock();
+  auto AddressSpace = F->getParent()->getDataLayout().getAllocaAddrSpace();
+  std::string Launch = "polly_launch_" + std::to_string(Kernel->id);
+  Instruction *Parameters = new AllocaInst(
+      ArrayTy, AddressSpace, Launch + "_params", EntryBlock->getTerminator());
+
+  int Index = 0;
+  for (long i = 0; i < Prog->n_array; i++) {
+    if (!ppcg_kernel_requires_array_argument(Kernel, i))
+      continue;
+
+    isl_id *Id = isl_space_get_tuple_id(Prog->array[i].space, isl_dim_set);
+    const ScopArrayInfo *SAI = ScopArrayInfo::getFromId(isl::manage(Id));
+
+    if (Runtime == GPURuntime::OpenCL)
+      ArgSizes[Index] = SAI->getElemSizeInBytes();
+
+    Value *DevArray = nullptr;
+    if (PollyManagedMemory) {
+      DevArray = getManagedDeviceArray(&Prog->array[i],
+                                       const_cast<ScopArrayInfo *>(SAI));
+    } else {
+      DevArray = DeviceAllocations[const_cast<ScopArrayInfo *>(SAI)];
+      DevArray = createCallGetDevicePtr(DevArray);
+    }
+    assert(DevArray != nullptr && "Array to be offloaded to device not "
+                                  "initialized");
+    Value *Offset = getArrayOffset(&Prog->array[i]);
+
+    if (Offset) {
+      DevArray = Builder.CreatePointerCast(
+          DevArray, SAI->getElementType()->getPointerTo());
+      DevArray = Builder.CreateGEP(DevArray, Builder.CreateNeg(Offset));
+      DevArray = Builder.CreatePointerCast(DevArray, Builder.getInt8PtrTy());
+    }
+    Value *Slot = Builder.CreateGEP(
+        Parameters, {Builder.getInt64(0), Builder.getInt64(Index)});
+
+    if (gpu_array_is_read_only_scalar(&Prog->array[i])) {
+      Value *ValPtr = nullptr;
+      if (PollyManagedMemory)
+        ValPtr = DevArray;
+      else
+        ValPtr = BlockGen.getOrCreateAlloca(SAI);
+
+      assert(ValPtr != nullptr && "ValPtr that should point to a valid object"
+                                  " to be stored into Parameters");
+      Value *ValPtrCast =
+          Builder.CreatePointerCast(ValPtr, Builder.getInt8PtrTy());
+      Builder.CreateStore(ValPtrCast, Slot);
+    } else {
+      Instruction *Param =
+          new AllocaInst(Builder.getInt8PtrTy(), AddressSpace,
+                         Launch + "_param_" + std::to_string(Index),
+                         EntryBlock->getTerminator());
+      Builder.CreateStore(DevArray, Param);
+      Value *ParamTyped =
+          Builder.CreatePointerCast(Param, Builder.getInt8PtrTy());
+      Builder.CreateStore(ParamTyped, Slot);
+    }
+    Index++;
+  }
+
+  int NumHostIters = isl_space_dim(Kernel->space, isl_dim_set);
+
+  for (long i = 0; i < NumHostIters; i++) {
+    isl_id *Id = isl_space_get_dim_id(Kernel->space, isl_dim_set, i);
+    Value *Val = IDToValue[Id];
+    isl_id_free(Id);
+
+    if (Runtime == GPURuntime::OpenCL)
+      ArgSizes[Index] = computeSizeInBytes(Val->getType());
+
+    Instruction *Param =
+        new AllocaInst(Val->getType(), AddressSpace,
+                       Launch + "_param_" + std::to_string(Index),
+                       EntryBlock->getTerminator());
+    Builder.CreateStore(Val, Param);
+    insertStoreParameter(Parameters, Param, Index);
+    Index++;
+  }
+
+  int NumVars = isl_space_dim(Kernel->space, isl_dim_param);
+
+  for (long i = 0; i < NumVars; i++) {
+    isl_id *Id = isl_space_get_dim_id(Kernel->space, isl_dim_param, i);
+    Value *Val = IDToValue[Id];
+    if (ValueMap.count(Val))
+      Val = ValueMap[Val];
+    isl_id_free(Id);
+
+    if (Runtime == GPURuntime::OpenCL)
+      ArgSizes[Index] = computeSizeInBytes(Val->getType());
+
+    Instruction *Param =
+        new AllocaInst(Val->getType(), AddressSpace,
+                       Launch + "_param_" + std::to_string(Index),
+                       EntryBlock->getTerminator());
+    Builder.CreateStore(Val, Param);
+    insertStoreParameter(Parameters, Param, Index);
+    Index++;
+  }
+
+  for (auto Val : SubtreeValues) {
+    if (Runtime == GPURuntime::OpenCL)
+      ArgSizes[Index] = computeSizeInBytes(Val->getType());
+
+    Instruction *Param =
+        new AllocaInst(Val->getType(), AddressSpace,
+                       Launch + "_param_" + std::to_string(Index),
+                       EntryBlock->getTerminator());
+    Builder.CreateStore(Val, Param);
+    insertStoreParameter(Parameters, Param, Index);
+    Index++;
+  }
+
+  if (Runtime == GPURuntime::OpenCL) {
+    for (int i = 0; i < NumArgs; i++) {
+      Value *Val = ConstantInt::get(Builder.getInt32Ty(), ArgSizes[i]);
+      Instruction *Param =
+          new AllocaInst(Builder.getInt32Ty(), AddressSpace,
+                         Launch + "_param_size_" + std::to_string(i),
+                         EntryBlock->getTerminator());
+      Builder.CreateStore(Val, Param);
+      insertStoreParameter(Parameters, Param, Index);
+      Index++;
+    }
+  }
+
+  auto Location = EntryBlock->getTerminator();
+  return new BitCastInst(Parameters, Builder.getInt8PtrTy(),
+                         Launch + "_params_i8ptr", Location);
+}
+
+void GPUNodeBuilder::setupKernelSubtreeFunctions(
+    SetVector<Function *> SubtreeFunctions) {
+  for (auto Fn : SubtreeFunctions) {
+    const std::string ClonedFnName = Fn->getName();
+    Function *Clone = GPUModule->getFunction(ClonedFnName);
+    if (!Clone)
+      Clone =
+          Function::Create(Fn->getFunctionType(), GlobalValue::ExternalLinkage,
+                           ClonedFnName, GPUModule.get());
+    assert(Clone && "Expected cloned function to be initialized.");
+    assert(ValueMap.find(Fn) == ValueMap.end() &&
+           "Fn already present in ValueMap");
+    ValueMap[Fn] = Clone;
+  }
+}
+void GPUNodeBuilder::createKernel(__isl_take isl_ast_node *KernelStmt) {
+  isl_id *Id = isl_ast_node_get_annotation(KernelStmt);
+  ppcg_kernel *Kernel = (ppcg_kernel *)isl_id_get_user(Id);
+  isl_id_free(Id);
+  isl_ast_node_free(KernelStmt);
+
+  if (Kernel->n_grid > 1)
+    DeepestParallel =
+        std::max(DeepestParallel, isl_space_dim(Kernel->space, isl_dim_set));
+  else
+    DeepestSequential =
+        std::max(DeepestSequential, isl_space_dim(Kernel->space, isl_dim_set));
+
+  Value *BlockDimX, *BlockDimY, *BlockDimZ;
+  std::tie(BlockDimX, BlockDimY, BlockDimZ) = getBlockSizes(Kernel);
+
+  SetVector<Value *> SubtreeValues;
+  SetVector<Function *> SubtreeFunctions;
+  SetVector<const Loop *> Loops;
+  isl::space ParamSpace;
+  std::tie(SubtreeValues, SubtreeFunctions, Loops, ParamSpace) =
+      getReferencesInKernel(Kernel);
+
+  // Add parameters that appear only in the access function to the kernel
+  // space. This is important to make sure that all isl_ids are passed as
+  // parameters to the kernel, even though we may not have all parameters
+  // in the context to improve compile time.
+  Kernel->space = isl_space_align_params(Kernel->space, ParamSpace.release());
+
+  assert(Kernel->tree && "Device AST of kernel node is empty");
+
+  Instruction &HostInsertPoint = *Builder.GetInsertPoint();
+  IslExprBuilder::IDToValueTy HostIDs = IDToValue;
+  ValueMapT HostValueMap = ValueMap;
+  BlockGenerator::AllocaMapTy HostScalarMap = ScalarMap;
+  ScalarMap.clear();
+  BlockGenerator::EscapeUsersAllocaMapTy HostEscapeMap = EscapeMap;
+  EscapeMap.clear();
+
+  // Create for all loops we depend on values that contain the current loop
+  // iteration. These values are necessary to generate code for SCEVs that
+  // depend on such loops. As a result we need to pass them to the subfunction.
+  for (const Loop *L : Loops) {
+    const SCEV *OuterLIV = SE.getAddRecExpr(SE.getUnknown(Builder.getInt64(0)),
+                                            SE.getUnknown(Builder.getInt64(1)),
+                                            L, SCEV::FlagAnyWrap);
+    Value *V = generateSCEV(OuterLIV);
+    OutsideLoopIterations[L] = SE.getUnknown(V);
+    SubtreeValues.insert(V);
+  }
+
+  createKernelFunction(Kernel, SubtreeValues, SubtreeFunctions);
+  setupKernelSubtreeFunctions(SubtreeFunctions);
+
+  create(isl_ast_node_copy(Kernel->tree));
+
+  finalizeKernelArguments(Kernel);
+  Function *F = Builder.GetInsertBlock()->getParent();
+  if (Arch == GPUArch::NVPTX64)
+    addCUDAAnnotations(F->getParent(), BlockDimX, BlockDimY, BlockDimZ);
+  clearDominators(F);
+  clearScalarEvolution(F);
+  clearLoops(F);
+
+  IDToValue = HostIDs;
+
+  ValueMap = std::move(HostValueMap);
+  ScalarMap = std::move(HostScalarMap);
+  EscapeMap = std::move(HostEscapeMap);
+  IDToSAI.clear();
+  Annotator.resetAlternativeAliasBases();
+  for (auto &BasePtr : LocalArrays)
+    S.invalidateScopArrayInfo(BasePtr, MemoryKind::Array);
+  LocalArrays.clear();
+
+  std::string ASMString = finalizeKernelFunction();
+  Builder.SetInsertPoint(&HostInsertPoint);
+  Value *Parameters = createLaunchParameters(Kernel, F, SubtreeValues);
+
+  std::string Name = getKernelFuncName(Kernel->id);
+  Value *KernelString = Builder.CreateGlobalStringPtr(ASMString, Name);
+  Value *NameString = Builder.CreateGlobalStringPtr(Name, Name + "_name");
+  Value *GPUKernel = createCallGetKernel(KernelString, NameString);
+
+  Value *GridDimX, *GridDimY;
+  std::tie(GridDimX, GridDimY) = getGridSizes(Kernel);
+
+  createCallLaunchKernel(GPUKernel, GridDimX, GridDimY, BlockDimX, BlockDimY,
+                         BlockDimZ, Parameters);
+  createCallFreeKernel(GPUKernel);
+
+  for (auto Id : KernelIds)
+    isl_id_free(Id);
+
+  KernelIds.clear();
+}
+
+/// Compute the DataLayout string for the NVPTX backend.
+///
+/// @param is64Bit Are we looking for a 64 bit architecture?
+static std::string computeNVPTXDataLayout(bool is64Bit) {
+  std::string Ret = "";
+
+  if (!is64Bit) {
+    Ret += "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:"
+           "64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:"
+           "64-v128:128:128-n16:32:64";
+  } else {
+    Ret += "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:"
+           "64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:"
+           "64-v128:128:128-n16:32:64";
+  }
+
+  return Ret;
+}
+
+/// Compute the DataLayout string for a SPIR kernel.
+///
+/// @param is64Bit Are we looking for a 64 bit architecture?
+static std::string computeSPIRDataLayout(bool is64Bit) {
+  std::string Ret = "";
+
+  if (!is64Bit) {
+    Ret += "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:"
+           "64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:"
+           "32-v48:64:64-v64:64:64-v96:128:128-v128:128:128-v192:"
+           "256:256-v256:256:256-v512:512:512-v1024:1024:1024";
+  } else {
+    Ret += "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:"
+           "64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:"
+           "32-v48:64:64-v64:64:64-v96:128:128-v128:128:128-v192:"
+           "256:256-v256:256:256-v512:512:512-v1024:1024:1024";
+  }
+
+  return Ret;
+}
+
+Function *
+GPUNodeBuilder::createKernelFunctionDecl(ppcg_kernel *Kernel,
+                                         SetVector<Value *> &SubtreeValues) {
+  std::vector<Type *> Args;
+  std::string Identifier = getKernelFuncName(Kernel->id);
+
+  std::vector<Metadata *> MemoryType;
+
+  for (long i = 0; i < Prog->n_array; i++) {
+    if (!ppcg_kernel_requires_array_argument(Kernel, i))
+      continue;
+
+    if (gpu_array_is_read_only_scalar(&Prog->array[i])) {
+      isl_id *Id = isl_space_get_tuple_id(Prog->array[i].space, isl_dim_set);
+      const ScopArrayInfo *SAI = ScopArrayInfo::getFromId(isl::manage(Id));
+      Args.push_back(SAI->getElementType());
+      MemoryType.push_back(
+          ConstantAsMetadata::get(ConstantInt::get(Builder.getInt32Ty(), 0)));
+    } else {
+      static const int UseGlobalMemory = 1;
+      Args.push_back(Builder.getInt8PtrTy(UseGlobalMemory));
+      MemoryType.push_back(
+          ConstantAsMetadata::get(ConstantInt::get(Builder.getInt32Ty(), 1)));
+    }
+  }
+
+  int NumHostIters = isl_space_dim(Kernel->space, isl_dim_set);
+
+  for (long i = 0; i < NumHostIters; i++) {
+    Args.push_back(Builder.getInt64Ty());
+    MemoryType.push_back(
+        ConstantAsMetadata::get(ConstantInt::get(Builder.getInt32Ty(), 0)));
+  }
+
+  int NumVars = isl_space_dim(Kernel->space, isl_dim_param);
+
+  for (long i = 0; i < NumVars; i++) {
+    isl_id *Id = isl_space_get_dim_id(Kernel->space, isl_dim_param, i);
+    Value *Val = IDToValue[Id];
+    isl_id_free(Id);
+    Args.push_back(Val->getType());
+    MemoryType.push_back(
+        ConstantAsMetadata::get(ConstantInt::get(Builder.getInt32Ty(), 0)));
+  }
+
+  for (auto *V : SubtreeValues) {
+    Args.push_back(V->getType());
+    MemoryType.push_back(
+        ConstantAsMetadata::get(ConstantInt::get(Builder.getInt32Ty(), 0)));
+  }
+
+  auto *FT = FunctionType::get(Builder.getVoidTy(), Args, false);
+  auto *FN = Function::Create(FT, Function::ExternalLinkage, Identifier,
+                              GPUModule.get());
+
+  std::vector<Metadata *> EmptyStrings;
+
+  for (unsigned int i = 0; i < MemoryType.size(); i++) {
+    EmptyStrings.push_back(MDString::get(FN->getContext(), ""));
+  }
+
+  if (Arch == GPUArch::SPIR32 || Arch == GPUArch::SPIR64) {
+    FN->setMetadata("kernel_arg_addr_space",
+                    MDNode::get(FN->getContext(), MemoryType));
+    FN->setMetadata("kernel_arg_name",
+                    MDNode::get(FN->getContext(), EmptyStrings));
+    FN->setMetadata("kernel_arg_access_qual",
+                    MDNode::get(FN->getContext(), EmptyStrings));
+    FN->setMetadata("kernel_arg_type",
+                    MDNode::get(FN->getContext(), EmptyStrings));
+    FN->setMetadata("kernel_arg_type_qual",
+                    MDNode::get(FN->getContext(), EmptyStrings));
+    FN->setMetadata("kernel_arg_base_type",
+                    MDNode::get(FN->getContext(), EmptyStrings));
+  }
+
+  switch (Arch) {
+  case GPUArch::NVPTX64:
+    FN->setCallingConv(CallingConv::PTX_Kernel);
+    break;
+  case GPUArch::SPIR32:
+  case GPUArch::SPIR64:
+    FN->setCallingConv(CallingConv::SPIR_KERNEL);
+    break;
+  }
+
+  auto Arg = FN->arg_begin();
+  for (long i = 0; i < Kernel->n_array; i++) {
+    if (!ppcg_kernel_requires_array_argument(Kernel, i))
+      continue;
+
+    Arg->setName(Kernel->array[i].array->name);
+
+    isl_id *Id = isl_space_get_tuple_id(Prog->array[i].space, isl_dim_set);
+    const ScopArrayInfo *SAI =
+        ScopArrayInfo::getFromId(isl::manage(isl_id_copy(Id)));
+    Type *EleTy = SAI->getElementType();
+    Value *Val = &*Arg;
+    SmallVector<const SCEV *, 4> Sizes;
+    isl_ast_build *Build =
+        isl_ast_build_from_context(isl_set_copy(Prog->context));
+    Sizes.push_back(nullptr);
+    for (long j = 1, n = Kernel->array[i].array->n_index; j < n; j++) {
+      isl_ast_expr *DimSize = isl_ast_build_expr_from_pw_aff(
+          Build, isl_multi_pw_aff_get_pw_aff(Kernel->array[i].array->bound, j));
+      auto V = ExprBuilder.create(DimSize);
+      Sizes.push_back(SE.getSCEV(V));
+    }
+    const ScopArrayInfo *SAIRep =
+        S.getOrCreateScopArrayInfo(Val, EleTy, Sizes, MemoryKind::Array);
+    LocalArrays.push_back(Val);
+
+    isl_ast_build_free(Build);
+    KernelIds.push_back(Id);
+    IDToSAI[Id] = SAIRep;
+    Arg++;
+  }
+
+  for (long i = 0; i < NumHostIters; i++) {
+    isl_id *Id = isl_space_get_dim_id(Kernel->space, isl_dim_set, i);
+    Arg->setName(isl_id_get_name(Id));
+    IDToValue[Id] = &*Arg;
+    KernelIDs.insert(std::unique_ptr<isl_id, IslIdDeleter>(Id));
+    Arg++;
+  }
+
+  for (long i = 0; i < NumVars; i++) {
+    isl_id *Id = isl_space_get_dim_id(Kernel->space, isl_dim_param, i);
+    Arg->setName(isl_id_get_name(Id));
+    Value *Val = IDToValue[Id];
+    ValueMap[Val] = &*Arg;
+    IDToValue[Id] = &*Arg;
+    KernelIDs.insert(std::unique_ptr<isl_id, IslIdDeleter>(Id));
+    Arg++;
+  }
+
+  for (auto *V : SubtreeValues) {
+    Arg->setName(V->getName());
+    ValueMap[V] = &*Arg;
+    Arg++;
+  }
+
+  return FN;
+}
+
+void GPUNodeBuilder::insertKernelIntrinsics(ppcg_kernel *Kernel) {
+  Intrinsic::ID IntrinsicsBID[2];
+  Intrinsic::ID IntrinsicsTID[3];
+
+  switch (Arch) {
+  case GPUArch::SPIR64:
+  case GPUArch::SPIR32:
+    llvm_unreachable("Cannot generate NVVM intrinsics for SPIR");
+  case GPUArch::NVPTX64:
+    IntrinsicsBID[0] = Intrinsic::nvvm_read_ptx_sreg_ctaid_x;
+    IntrinsicsBID[1] = Intrinsic::nvvm_read_ptx_sreg_ctaid_y;
+
+    IntrinsicsTID[0] = Intrinsic::nvvm_read_ptx_sreg_tid_x;
+    IntrinsicsTID[1] = Intrinsic::nvvm_read_ptx_sreg_tid_y;
+    IntrinsicsTID[2] = Intrinsic::nvvm_read_ptx_sreg_tid_z;
+    break;
+  }
+
+  auto addId = [this](__isl_take isl_id *Id, Intrinsic::ID Intr) mutable {
+    std::string Name = isl_id_get_name(Id);
+    Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+    Function *IntrinsicFn = Intrinsic::getDeclaration(M, Intr);
+    Value *Val = Builder.CreateCall(IntrinsicFn, {});
+    Val = Builder.CreateIntCast(Val, Builder.getInt64Ty(), false, Name);
+    IDToValue[Id] = Val;
+    KernelIDs.insert(std::unique_ptr<isl_id, IslIdDeleter>(Id));
+  };
+
+  for (int i = 0; i < Kernel->n_grid; ++i) {
+    isl_id *Id = isl_id_list_get_id(Kernel->block_ids, i);
+    addId(Id, IntrinsicsBID[i]);
+  }
+
+  for (int i = 0; i < Kernel->n_block; ++i) {
+    isl_id *Id = isl_id_list_get_id(Kernel->thread_ids, i);
+    addId(Id, IntrinsicsTID[i]);
+  }
+}
+
+void GPUNodeBuilder::insertKernelCallsSPIR(ppcg_kernel *Kernel) {
+  const char *GroupName[3] = {"__gen_ocl_get_group_id0",
+                              "__gen_ocl_get_group_id1",
+                              "__gen_ocl_get_group_id2"};
+
+  const char *LocalName[3] = {"__gen_ocl_get_local_id0",
+                              "__gen_ocl_get_local_id1",
+                              "__gen_ocl_get_local_id2"};
+
+  auto createFunc = [this](const char *Name, __isl_take isl_id *Id) mutable {
+    Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+    Function *FN = M->getFunction(Name);
+
+    // If FN is not available, declare it.
+    if (!FN) {
+      GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+      std::vector<Type *> Args;
+      FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), Args, false);
+      FN = Function::Create(Ty, Linkage, Name, M);
+      FN->setCallingConv(CallingConv::SPIR_FUNC);
+    }
+
+    Value *Val = Builder.CreateCall(FN, {});
+    Val = Builder.CreateIntCast(Val, Builder.getInt64Ty(), false, Name);
+    IDToValue[Id] = Val;
+    KernelIDs.insert(std::unique_ptr<isl_id, IslIdDeleter>(Id));
+  };
+
+  for (int i = 0; i < Kernel->n_grid; ++i)
+    createFunc(GroupName[i], isl_id_list_get_id(Kernel->block_ids, i));
+
+  for (int i = 0; i < Kernel->n_block; ++i)
+    createFunc(LocalName[i], isl_id_list_get_id(Kernel->thread_ids, i));
+}
+
+void GPUNodeBuilder::prepareKernelArguments(ppcg_kernel *Kernel, Function *FN) {
+  auto Arg = FN->arg_begin();
+  for (long i = 0; i < Kernel->n_array; i++) {
+    if (!ppcg_kernel_requires_array_argument(Kernel, i))
+      continue;
+
+    isl_id *Id = isl_space_get_tuple_id(Prog->array[i].space, isl_dim_set);
+    const ScopArrayInfo *SAI =
+        ScopArrayInfo::getFromId(isl::manage(isl_id_copy(Id)));
+    isl_id_free(Id);
+
+    if (SAI->getNumberOfDimensions() > 0) {
+      Arg++;
+      continue;
+    }
+
+    Value *Val = &*Arg;
+
+    if (!gpu_array_is_read_only_scalar(&Prog->array[i])) {
+      Type *TypePtr = SAI->getElementType()->getPointerTo();
+      Value *TypedArgPtr = Builder.CreatePointerCast(Val, TypePtr);
+      Val = Builder.CreateLoad(TypedArgPtr);
+    }
+
+    Value *Alloca = BlockGen.getOrCreateAlloca(SAI);
+    Builder.CreateStore(Val, Alloca);
+
+    Arg++;
+  }
+}
+
+void GPUNodeBuilder::finalizeKernelArguments(ppcg_kernel *Kernel) {
+  auto *FN = Builder.GetInsertBlock()->getParent();
+  auto Arg = FN->arg_begin();
+
+  bool StoredScalar = false;
+  for (long i = 0; i < Kernel->n_array; i++) {
+    if (!ppcg_kernel_requires_array_argument(Kernel, i))
+      continue;
+
+    isl_id *Id = isl_space_get_tuple_id(Prog->array[i].space, isl_dim_set);
+    const ScopArrayInfo *SAI =
+        ScopArrayInfo::getFromId(isl::manage(isl_id_copy(Id)));
+    isl_id_free(Id);
+
+    if (SAI->getNumberOfDimensions() > 0) {
+      Arg++;
+      continue;
+    }
+
+    if (gpu_array_is_read_only_scalar(&Prog->array[i])) {
+      Arg++;
+      continue;
+    }
+
+    Value *Alloca = BlockGen.getOrCreateAlloca(SAI);
+    Value *ArgPtr = &*Arg;
+    Type *TypePtr = SAI->getElementType()->getPointerTo();
+    Value *TypedArgPtr = Builder.CreatePointerCast(ArgPtr, TypePtr);
+    Value *Val = Builder.CreateLoad(Alloca);
+    Builder.CreateStore(Val, TypedArgPtr);
+    StoredScalar = true;
+
+    Arg++;
+  }
+
+  if (StoredScalar) {
+    /// In case more than one thread contains scalar stores, the generated
+    /// code might be incorrect, if we only store at the end of the kernel.
+    /// To support this case we need to store these scalars back at each
+    /// memory store or at least before each kernel barrier.
+    if (Kernel->n_block != 0 || Kernel->n_grid != 0) {
+      BuildSuccessful = 0;
+      DEBUG(
+          dbgs() << getUniqueScopName(&S)
+                 << " has a store to a scalar value that"
+                    " would be undefined to run in parallel. Bailing out.\n";);
+    }
+  }
+}
+
+void GPUNodeBuilder::createKernelVariables(ppcg_kernel *Kernel, Function *FN) {
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+
+  for (int i = 0; i < Kernel->n_var; ++i) {
+    struct ppcg_kernel_var &Var = Kernel->var[i];
+    isl_id *Id = isl_space_get_tuple_id(Var.array->space, isl_dim_set);
+    Type *EleTy = ScopArrayInfo::getFromId(isl::manage(Id))->getElementType();
+
+    Type *ArrayTy = EleTy;
+    SmallVector<const SCEV *, 4> Sizes;
+
+    Sizes.push_back(nullptr);
+    for (unsigned int j = 1; j < Var.array->n_index; ++j) {
+      isl_val *Val = isl_vec_get_element_val(Var.size, j);
+      long Bound = isl_val_get_num_si(Val);
+      isl_val_free(Val);
+      Sizes.push_back(S.getSE()->getConstant(Builder.getInt64Ty(), Bound));
+    }
+
+    for (int j = Var.array->n_index - 1; j >= 0; --j) {
+      isl_val *Val = isl_vec_get_element_val(Var.size, j);
+      long Bound = isl_val_get_num_si(Val);
+      isl_val_free(Val);
+      ArrayTy = ArrayType::get(ArrayTy, Bound);
+    }
+
+    const ScopArrayInfo *SAI;
+    Value *Allocation;
+    if (Var.type == ppcg_access_shared) {
+      auto GlobalVar = new GlobalVariable(
+          *M, ArrayTy, false, GlobalValue::InternalLinkage, 0, Var.name,
+          nullptr, GlobalValue::ThreadLocalMode::NotThreadLocal, 3);
+      GlobalVar->setAlignment(EleTy->getPrimitiveSizeInBits() / 8);
+      GlobalVar->setInitializer(Constant::getNullValue(ArrayTy));
+
+      Allocation = GlobalVar;
+    } else if (Var.type == ppcg_access_private) {
+      Allocation = Builder.CreateAlloca(ArrayTy, 0, "private_array");
+    } else {
+      llvm_unreachable("unknown variable type");
+    }
+    SAI =
+        S.getOrCreateScopArrayInfo(Allocation, EleTy, Sizes, MemoryKind::Array);
+    Id = isl_id_alloc(S.getIslCtx().get(), Var.name, nullptr);
+    IDToValue[Id] = Allocation;
+    LocalArrays.push_back(Allocation);
+    KernelIds.push_back(Id);
+    IDToSAI[Id] = SAI;
+  }
+}
+
+void GPUNodeBuilder::createKernelFunction(
+    ppcg_kernel *Kernel, SetVector<Value *> &SubtreeValues,
+    SetVector<Function *> &SubtreeFunctions) {
+  std::string Identifier = getKernelFuncName(Kernel->id);
+  GPUModule.reset(new Module(Identifier, Builder.getContext()));
+
+  switch (Arch) {
+  case GPUArch::NVPTX64:
+    if (Runtime == GPURuntime::CUDA)
+      GPUModule->setTargetTriple(Triple::normalize("nvptx64-nvidia-cuda"));
+    else if (Runtime == GPURuntime::OpenCL)
+      GPUModule->setTargetTriple(Triple::normalize("nvptx64-nvidia-nvcl"));
+    GPUModule->setDataLayout(computeNVPTXDataLayout(true /* is64Bit */));
+    break;
+  case GPUArch::SPIR32:
+    GPUModule->setTargetTriple(Triple::normalize("spir-unknown-unknown"));
+    GPUModule->setDataLayout(computeSPIRDataLayout(false /* is64Bit */));
+    break;
+  case GPUArch::SPIR64:
+    GPUModule->setTargetTriple(Triple::normalize("spir64-unknown-unknown"));
+    GPUModule->setDataLayout(computeSPIRDataLayout(true /* is64Bit */));
+    break;
+  }
+
+  Function *FN = createKernelFunctionDecl(Kernel, SubtreeValues);
+
+  BasicBlock *PrevBlock = Builder.GetInsertBlock();
+  auto EntryBlock = BasicBlock::Create(Builder.getContext(), "entry", FN);
+
+  DT.addNewBlock(EntryBlock, PrevBlock);
+
+  Builder.SetInsertPoint(EntryBlock);
+  Builder.CreateRetVoid();
+  Builder.SetInsertPoint(EntryBlock, EntryBlock->begin());
+
+  ScopDetection::markFunctionAsInvalid(FN);
+
+  prepareKernelArguments(Kernel, FN);
+  createKernelVariables(Kernel, FN);
+
+  switch (Arch) {
+  case GPUArch::NVPTX64:
+    insertKernelIntrinsics(Kernel);
+    break;
+  case GPUArch::SPIR32:
+  case GPUArch::SPIR64:
+    insertKernelCallsSPIR(Kernel);
+    break;
+  }
+}
+
+std::string GPUNodeBuilder::createKernelASM() {
+  llvm::Triple GPUTriple;
+
+  switch (Arch) {
+  case GPUArch::NVPTX64:
+    switch (Runtime) {
+    case GPURuntime::CUDA:
+      GPUTriple = llvm::Triple(Triple::normalize("nvptx64-nvidia-cuda"));
+      break;
+    case GPURuntime::OpenCL:
+      GPUTriple = llvm::Triple(Triple::normalize("nvptx64-nvidia-nvcl"));
+      break;
+    }
+    break;
+  case GPUArch::SPIR64:
+  case GPUArch::SPIR32:
+    std::string SPIRAssembly;
+    raw_string_ostream IROstream(SPIRAssembly);
+    IROstream << *GPUModule;
+    IROstream.flush();
+    return SPIRAssembly;
+  }
+
+  std::string ErrMsg;
+  auto GPUTarget = TargetRegistry::lookupTarget(GPUTriple.getTriple(), ErrMsg);
+
+  if (!GPUTarget) {
+    errs() << ErrMsg << "\n";
+    return "";
+  }
+
+  TargetOptions Options;
+  Options.UnsafeFPMath = FastMath;
+
+  std::string subtarget;
+
+  switch (Arch) {
+  case GPUArch::NVPTX64:
+    subtarget = CudaVersion;
+    break;
+  case GPUArch::SPIR32:
+  case GPUArch::SPIR64:
+    llvm_unreachable("No subtarget for SPIR architecture");
+  }
+
+  std::unique_ptr<TargetMachine> TargetM(GPUTarget->createTargetMachine(
+      GPUTriple.getTriple(), subtarget, "", Options, Optional<Reloc::Model>()));
+
+  SmallString<0> ASMString;
+  raw_svector_ostream ASMStream(ASMString);
+  llvm::legacy::PassManager PM;
+
+  PM.add(createTargetTransformInfoWrapperPass(TargetM->getTargetIRAnalysis()));
+
+  if (TargetM->addPassesToEmitFile(
+          PM, ASMStream, TargetMachine::CGFT_AssemblyFile, true /* verify */)) {
+    errs() << "The target does not support generation of this file type!\n";
+    return "";
+  }
+
+  PM.run(*GPUModule);
+
+  return ASMStream.str();
+}
+
+bool GPUNodeBuilder::requiresCUDALibDevice() {
+  bool RequiresLibDevice = false;
+  for (Function &F : GPUModule->functions()) {
+    if (!F.isDeclaration())
+      continue;
+
+    const std::string CUDALibDeviceFunc = getCUDALibDeviceFuntion(&F);
+    if (CUDALibDeviceFunc.length() != 0) {
+      // We need to handle the case where a module looks like this:
+      // @expf(..)
+      // @llvm.exp.f64(..)
+      // Both of these functions would be renamed to `__nv_expf`.
+      //
+      // So, we must first check for the existence of the libdevice function.
+      // If this exists, we replace our current function with it.
+      //
+      // If it does not exist, we rename the current function to the
+      // libdevice functiono name.
+      if (Function *Replacement = F.getParent()->getFunction(CUDALibDeviceFunc))
+        F.replaceAllUsesWith(Replacement);
+      else
+        F.setName(CUDALibDeviceFunc);
+      RequiresLibDevice = true;
+    }
+  }
+
+  return RequiresLibDevice;
+}
+
+void GPUNodeBuilder::addCUDALibDevice() {
+  if (Arch != GPUArch::NVPTX64)
+    return;
+
+  if (requiresCUDALibDevice()) {
+    SMDiagnostic Error;
+
+    errs() << CUDALibDevice << "\n";
+    auto LibDeviceModule =
+        parseIRFile(CUDALibDevice, Error, GPUModule->getContext());
+
+    if (!LibDeviceModule) {
+      BuildSuccessful = false;
+      report_fatal_error("Could not find or load libdevice. Skipping GPU "
+                         "kernel generation. Please set -polly-acc-libdevice "
+                         "accordingly.\n");
+      return;
+    }
+
+    Linker L(*GPUModule);
+
+    // Set an nvptx64 target triple to avoid linker warnings. The original
+    // triple of the libdevice files are nvptx-unknown-unknown.
+    LibDeviceModule->setTargetTriple(Triple::normalize("nvptx64-nvidia-cuda"));
+    L.linkInModule(std::move(LibDeviceModule), Linker::LinkOnlyNeeded);
+  }
+}
+
+std::string GPUNodeBuilder::finalizeKernelFunction() {
+
+  if (verifyModule(*GPUModule)) {
+    DEBUG(dbgs() << "verifyModule failed on module:\n";
+          GPUModule->print(dbgs(), nullptr); dbgs() << "\n";);
+    DEBUG(dbgs() << "verifyModule Error:\n";
+          verifyModule(*GPUModule, &dbgs()););
+
+    if (FailOnVerifyModuleFailure)
+      llvm_unreachable("VerifyModule failed.");
+
+    BuildSuccessful = false;
+    return "";
+  }
+
+  addCUDALibDevice();
+
+  if (DumpKernelIR)
+    outs() << *GPUModule << "\n";
+
+  if (Arch != GPUArch::SPIR32 && Arch != GPUArch::SPIR64) {
+    // Optimize module.
+    llvm::legacy::PassManager OptPasses;
+    PassManagerBuilder PassBuilder;
+    PassBuilder.OptLevel = 3;
+    PassBuilder.SizeLevel = 0;
+    PassBuilder.populateModulePassManager(OptPasses);
+    OptPasses.run(*GPUModule);
+  }
+
+  std::string Assembly = createKernelASM();
+
+  if (DumpKernelASM)
+    outs() << Assembly << "\n";
+
+  GPUModule.release();
+  KernelIDs.clear();
+
+  return Assembly;
+}
+/// Construct an `isl_pw_aff_list` from a vector of `isl_pw_aff`
+/// @param PwAffs The list of piecewise affine functions to create an
+///               `isl_pw_aff_list` from. We expect an rvalue ref because
+///               all the isl_pw_aff are used up by this function.
+///
+/// @returns  The `isl_pw_aff_list`.
+__isl_give isl_pw_aff_list *
+createPwAffList(isl_ctx *Context,
+                const std::vector<__isl_take isl_pw_aff *> &&PwAffs) {
+  isl_pw_aff_list *List = isl_pw_aff_list_alloc(Context, PwAffs.size());
+
+  for (unsigned i = 0; i < PwAffs.size(); i++) {
+    List = isl_pw_aff_list_insert(List, i, PwAffs[i]);
+  }
+  return List;
+}
+
+/// Align all the `PwAffs` such that they have the same parameter dimensions.
+///
+/// We loop over all `pw_aff` and align all of their spaces together to
+/// create a common space for all the `pw_aff`. This common space is the
+/// `AlignSpace`. We then align all the `pw_aff` to this space. We start
+/// with the given `SeedSpace`.
+/// @param PwAffs    The list of piecewise affine functions we want to align.
+///                  This is an rvalue reference because the entire vector is
+///                  used up by the end of the operation.
+/// @param SeedSpace The space to start the alignment process with.
+/// @returns         A std::pair, whose first element is the aligned space,
+///                  whose second element is the vector of aligned piecewise
+///                  affines.
+static std::pair<__isl_give isl_space *, std::vector<__isl_give isl_pw_aff *>>
+alignPwAffs(const std::vector<__isl_take isl_pw_aff *> &&PwAffs,
+            __isl_take isl_space *SeedSpace) {
+  assert(SeedSpace && "Invalid seed space given.");
+
+  isl_space *AlignSpace = SeedSpace;
+  for (isl_pw_aff *PwAff : PwAffs) {
+    isl_space *PwAffSpace = isl_pw_aff_get_domain_space(PwAff);
+    AlignSpace = isl_space_align_params(AlignSpace, PwAffSpace);
+  }
+  std::vector<isl_pw_aff *> AdjustedPwAffs;
+
+  for (unsigned i = 0; i < PwAffs.size(); i++) {
+    isl_pw_aff *Adjusted = PwAffs[i];
+    assert(Adjusted && "Invalid pw_aff given.");
+    Adjusted = isl_pw_aff_align_params(Adjusted, isl_space_copy(AlignSpace));
+    AdjustedPwAffs.push_back(Adjusted);
+  }
+  return std::make_pair(AlignSpace, AdjustedPwAffs);
+}
+
+namespace {
+class PPCGCodeGeneration : public ScopPass {
+public:
+  static char ID;
+
+  GPURuntime Runtime = GPURuntime::CUDA;
+
+  GPUArch Architecture = GPUArch::NVPTX64;
+
+  /// The scop that is currently processed.
+  Scop *S;
+
+  LoopInfo *LI;
+  DominatorTree *DT;
+  ScalarEvolution *SE;
+  const DataLayout *DL;
+  RegionInfo *RI;
+
+  PPCGCodeGeneration() : ScopPass(ID) {}
+
+  /// Construct compilation options for PPCG.
+  ///
+  /// @returns The compilation options.
+  ppcg_options *createPPCGOptions() {
+    auto DebugOptions =
+        (ppcg_debug_options *)malloc(sizeof(ppcg_debug_options));
+    auto Options = (ppcg_options *)malloc(sizeof(ppcg_options));
+
+    DebugOptions->dump_schedule_constraints = false;
+    DebugOptions->dump_schedule = false;
+    DebugOptions->dump_final_schedule = false;
+    DebugOptions->dump_sizes = false;
+    DebugOptions->verbose = false;
+
+    Options->debug = DebugOptions;
+
+    Options->group_chains = false;
+    Options->reschedule = true;
+    Options->scale_tile_loops = false;
+    Options->wrap = false;
+
+    Options->non_negative_parameters = false;
+    Options->ctx = nullptr;
+    Options->sizes = nullptr;
+
+    Options->tile = true;
+    Options->tile_size = 32;
+
+    Options->isolate_full_tiles = false;
+
+    Options->use_private_memory = PrivateMemory;
+    Options->use_shared_memory = SharedMemory;
+    Options->max_shared_memory = 48 * 1024;
+
+    Options->target = PPCG_TARGET_CUDA;
+    Options->openmp = false;
+    Options->linearize_device_arrays = true;
+    Options->allow_gnu_extensions = false;
+
+    Options->unroll_copy_shared = false;
+    Options->unroll_gpu_tile = false;
+    Options->live_range_reordering = true;
+
+    Options->live_range_reordering = true;
+    Options->hybrid = false;
+    Options->opencl_compiler_options = nullptr;
+    Options->opencl_use_gpu = false;
+    Options->opencl_n_include_file = 0;
+    Options->opencl_include_files = nullptr;
+    Options->opencl_print_kernel_types = false;
+    Options->opencl_embed_kernel_code = false;
+
+    Options->save_schedule_file = nullptr;
+    Options->load_schedule_file = nullptr;
+
+    return Options;
+  }
+
+  /// Get a tagged access relation containing all accesses of type @p AccessTy.
+  ///
+  /// Instead of a normal access of the form:
+  ///
+  ///   Stmt[i,j,k] -> Array[f_0(i,j,k), f_1(i,j,k)]
+  ///
+  /// a tagged access has the form
+  ///
+  ///   [Stmt[i,j,k] -> id[]] -> Array[f_0(i,j,k), f_1(i,j,k)]
+  ///
+  /// where 'id' is an additional space that references the memory access that
+  /// triggered the access.
+  ///
+  /// @param AccessTy The type of the memory accesses to collect.
+  ///
+  /// @return The relation describing all tagged memory accesses.
+  isl_union_map *getTaggedAccesses(enum MemoryAccess::AccessType AccessTy) {
+    isl_union_map *Accesses = isl_union_map_empty(S->getParamSpace().release());
+
+    for (auto &Stmt : *S)
+      for (auto &Acc : Stmt)
+        if (Acc->getType() == AccessTy) {
+          isl_map *Relation = Acc->getAccessRelation().release();
+          Relation =
+              isl_map_intersect_domain(Relation, Stmt.getDomain().release());
+
+          isl_space *Space = isl_map_get_space(Relation);
+          Space = isl_space_range(Space);
+          Space = isl_space_from_range(Space);
+          Space =
+              isl_space_set_tuple_id(Space, isl_dim_in, Acc->getId().release());
+          isl_map *Universe = isl_map_universe(Space);
+          Relation = isl_map_domain_product(Relation, Universe);
+          Accesses = isl_union_map_add_map(Accesses, Relation);
+        }
+
+    return Accesses;
+  }
+
+  /// Get the set of all read accesses, tagged with the access id.
+  ///
+  /// @see getTaggedAccesses
+  isl_union_map *getTaggedReads() {
+    return getTaggedAccesses(MemoryAccess::READ);
+  }
+
+  /// Get the set of all may (and must) accesses, tagged with the access id.
+  ///
+  /// @see getTaggedAccesses
+  isl_union_map *getTaggedMayWrites() {
+    return isl_union_map_union(getTaggedAccesses(MemoryAccess::MAY_WRITE),
+                               getTaggedAccesses(MemoryAccess::MUST_WRITE));
+  }
+
+  /// Get the set of all must accesses, tagged with the access id.
+  ///
+  /// @see getTaggedAccesses
+  isl_union_map *getTaggedMustWrites() {
+    return getTaggedAccesses(MemoryAccess::MUST_WRITE);
+  }
+
+  /// Collect parameter and array names as isl_ids.
+  ///
+  /// To reason about the different parameters and arrays used, ppcg requires
+  /// a list of all isl_ids in use. As PPCG traditionally performs
+  /// source-to-source compilation each of these isl_ids is mapped to the
+  /// expression that represents it. As we do not have a corresponding
+  /// expression in Polly, we just map each id to a 'zero' expression to match
+  /// the data format that ppcg expects.
+  ///
+  /// @returns Retun a map from collected ids to 'zero' ast expressions.
+  __isl_give isl_id_to_ast_expr *getNames() {
+    auto *Names = isl_id_to_ast_expr_alloc(
+        S->getIslCtx().get(),
+        S->getNumParams() + std::distance(S->array_begin(), S->array_end()));
+    auto *Zero = isl_ast_expr_from_val(isl_val_zero(S->getIslCtx().get()));
+
+    for (const SCEV *P : S->parameters()) {
+      isl_id *Id = S->getIdForParam(P).release();
+      Names = isl_id_to_ast_expr_set(Names, Id, isl_ast_expr_copy(Zero));
+    }
+
+    for (auto &Array : S->arrays()) {
+      auto Id = Array->getBasePtrId().release();
+      Names = isl_id_to_ast_expr_set(Names, Id, isl_ast_expr_copy(Zero));
+    }
+
+    isl_ast_expr_free(Zero);
+
+    return Names;
+  }
+
+  /// Create a new PPCG scop from the current scop.
+  ///
+  /// The PPCG scop is initialized with data from the current polly::Scop. From
+  /// this initial data, the data-dependences in the PPCG scop are initialized.
+  /// We do not use Polly's dependence analysis for now, to ensure we match
+  /// the PPCG default behaviour more closely.
+  ///
+  /// @returns A new ppcg scop.
+  ppcg_scop *createPPCGScop() {
+    MustKillsInfo KillsInfo = computeMustKillsInfo(*S);
+
+    auto PPCGScop = (ppcg_scop *)malloc(sizeof(ppcg_scop));
+
+    PPCGScop->options = createPPCGOptions();
+    // enable live range reordering
+    PPCGScop->options->live_range_reordering = 1;
+
+    PPCGScop->start = 0;
+    PPCGScop->end = 0;
+
+    PPCGScop->context = S->getContext().release();
+    PPCGScop->domain = S->getDomains().release();
+    // TODO: investigate this further. PPCG calls collect_call_domains.
+    PPCGScop->call = isl_union_set_from_set(S->getContext().release());
+    PPCGScop->tagged_reads = getTaggedReads();
+    PPCGScop->reads = S->getReads().release();
+    PPCGScop->live_in = nullptr;
+    PPCGScop->tagged_may_writes = getTaggedMayWrites();
+    PPCGScop->may_writes = S->getWrites().release();
+    PPCGScop->tagged_must_writes = getTaggedMustWrites();
+    PPCGScop->must_writes = S->getMustWrites().release();
+    PPCGScop->live_out = nullptr;
+    PPCGScop->tagged_must_kills = KillsInfo.TaggedMustKills.take();
+    PPCGScop->must_kills = KillsInfo.MustKills.take();
+
+    PPCGScop->tagger = nullptr;
+    PPCGScop->independence =
+        isl_union_map_empty(isl_set_get_space(PPCGScop->context));
+    PPCGScop->dep_flow = nullptr;
+    PPCGScop->tagged_dep_flow = nullptr;
+    PPCGScop->dep_false = nullptr;
+    PPCGScop->dep_forced = nullptr;
+    PPCGScop->dep_order = nullptr;
+    PPCGScop->tagged_dep_order = nullptr;
+
+    PPCGScop->schedule = S->getScheduleTree().release();
+    // If we have something non-trivial to kill, add it to the schedule
+    if (KillsInfo.KillsSchedule.get())
+      PPCGScop->schedule = isl_schedule_sequence(
+          PPCGScop->schedule, KillsInfo.KillsSchedule.take());
+
+    PPCGScop->names = getNames();
+    PPCGScop->pet = nullptr;
+
+    compute_tagger(PPCGScop);
+    compute_dependences(PPCGScop);
+    eliminate_dead_code(PPCGScop);
+
+    return PPCGScop;
+  }
+
+  /// Collect the array accesses in a statement.
+  ///
+  /// @param Stmt The statement for which to collect the accesses.
+  ///
+  /// @returns A list of array accesses.
+  gpu_stmt_access *getStmtAccesses(ScopStmt &Stmt) {
+    gpu_stmt_access *Accesses = nullptr;
+
+    for (MemoryAccess *Acc : Stmt) {
+      auto Access =
+          isl_alloc_type(S->getIslCtx().get(), struct gpu_stmt_access);
+      Access->read = Acc->isRead();
+      Access->write = Acc->isWrite();
+      Access->access = Acc->getAccessRelation().release();
+      isl_space *Space = isl_map_get_space(Access->access);
+      Space = isl_space_range(Space);
+      Space = isl_space_from_range(Space);
+      Space = isl_space_set_tuple_id(Space, isl_dim_in, Acc->getId().release());
+      isl_map *Universe = isl_map_universe(Space);
+      Access->tagged_access =
+          isl_map_domain_product(Acc->getAccessRelation().release(), Universe);
+      Access->exact_write = !Acc->isMayWrite();
+      Access->ref_id = Acc->getId().release();
+      Access->next = Accesses;
+      Access->n_index = Acc->getScopArrayInfo()->getNumberOfDimensions();
+      // TODO: Also mark one-element accesses to arrays as fixed-element.
+      Access->fixed_element =
+          Acc->isLatestScalarKind() ? isl_bool_true : isl_bool_false;
+      Accesses = Access;
+    }
+
+    return Accesses;
+  }
+
+  /// Collect the list of GPU statements.
+  ///
+  /// Each statement has an id, a pointer to the underlying data structure,
+  /// as well as a list with all memory accesses.
+  ///
+  /// TODO: Initialize the list of memory accesses.
+  ///
+  /// @returns A linked-list of statements.
+  gpu_stmt *getStatements() {
+    gpu_stmt *Stmts = isl_calloc_array(S->getIslCtx().get(), struct gpu_stmt,
+                                       std::distance(S->begin(), S->end()));
+
+    int i = 0;
+    for (auto &Stmt : *S) {
+      gpu_stmt *GPUStmt = &Stmts[i];
+
+      GPUStmt->id = Stmt.getDomainId().release();
+
+      // We use the pet stmt pointer to keep track of the Polly statements.
+      GPUStmt->stmt = (pet_stmt *)&Stmt;
+      GPUStmt->accesses = getStmtAccesses(Stmt);
+      i++;
+    }
+
+    return Stmts;
+  }
+
+  /// Derive the extent of an array.
+  ///
+  /// The extent of an array is the set of elements that are within the
+  /// accessed array. For the inner dimensions, the extent constraints are
+  /// 0 and the size of the corresponding array dimension. For the first
+  /// (outermost) dimension, the extent constraints are the minimal and maximal
+  /// subscript value for the first dimension.
+  ///
+  /// @param Array The array to derive the extent for.
+  ///
+  /// @returns An isl_set describing the extent of the array.
+  isl::set getExtent(ScopArrayInfo *Array) {
+    unsigned NumDims = Array->getNumberOfDimensions();
+
+    if (Array->getNumberOfDimensions() == 0)
+      return isl::set::universe(Array->getSpace());
+
+    isl::union_map Accesses = S->getAccesses(Array);
+    isl::union_set AccessUSet = Accesses.range();
+    AccessUSet = AccessUSet.coalesce();
+    AccessUSet = AccessUSet.detect_equalities();
+    AccessUSet = AccessUSet.coalesce();
+
+    if (AccessUSet.is_empty())
+      return isl::set::empty(Array->getSpace());
+
+    isl::set AccessSet = AccessUSet.extract_set(Array->getSpace());
+
+    isl::local_space LS = isl::local_space(Array->getSpace());
+
+    isl::pw_aff Val = isl::aff::var_on_domain(LS, isl::dim::set, 0);
+    isl::pw_aff OuterMin = AccessSet.dim_min(0);
+    isl::pw_aff OuterMax = AccessSet.dim_max(0);
+    OuterMin = OuterMin.add_dims(isl::dim::in, Val.dim(isl::dim::in));
+    OuterMax = OuterMax.add_dims(isl::dim::in, Val.dim(isl::dim::in));
+    OuterMin = OuterMin.set_tuple_id(isl::dim::in, Array->getBasePtrId());
+    OuterMax = OuterMax.set_tuple_id(isl::dim::in, Array->getBasePtrId());
+
+    isl::set Extent = isl::set::universe(Array->getSpace());
+
+    Extent = Extent.intersect(OuterMin.le_set(Val));
+    Extent = Extent.intersect(OuterMax.ge_set(Val));
+
+    for (unsigned i = 1; i < NumDims; ++i)
+      Extent = Extent.lower_bound_si(isl::dim::set, i, 0);
+
+    for (unsigned i = 0; i < NumDims; ++i) {
+      isl::pw_aff PwAff = Array->getDimensionSizePw(i);
+
+      // isl_pw_aff can be NULL for zero dimension. Only in the case of a
+      // Fortran array will we have a legitimate dimension.
+      if (PwAff.is_null()) {
+        assert(i == 0 && "invalid dimension isl_pw_aff for nonzero dimension");
+        continue;
+      }
+
+      isl::pw_aff Val = isl::aff::var_on_domain(
+          isl::local_space(Array->getSpace()), isl::dim::set, i);
+      PwAff = PwAff.add_dims(isl::dim::in, Val.dim(isl::dim::in));
+      PwAff = PwAff.set_tuple_id(isl::dim::in, Val.get_tuple_id(isl::dim::in));
+      isl::set Set = PwAff.gt_set(Val);
+      Extent = Set.intersect(Extent);
+    }
+
+    return Extent;
+  }
+
+  /// Derive the bounds of an array.
+  ///
+  /// For the first dimension we derive the bound of the array from the extent
+  /// of this dimension. For inner dimensions we obtain their size directly from
+  /// ScopArrayInfo.
+  ///
+  /// @param PPCGArray The array to compute bounds for.
+  /// @param Array The polly array from which to take the information.
+  void setArrayBounds(gpu_array_info &PPCGArray, ScopArrayInfo *Array) {
+    std::vector<isl_pw_aff *> Bounds;
+
+    if (PPCGArray.n_index > 0) {
+      if (isl_set_is_empty(PPCGArray.extent)) {
+        isl_set *Dom = isl_set_copy(PPCGArray.extent);
+        isl_local_space *LS = isl_local_space_from_space(
+            isl_space_params(isl_set_get_space(Dom)));
+        isl_set_free(Dom);
+        isl_pw_aff *Zero = isl_pw_aff_from_aff(isl_aff_zero_on_domain(LS));
+        Bounds.push_back(Zero);
+      } else {
+        isl_set *Dom = isl_set_copy(PPCGArray.extent);
+        Dom = isl_set_project_out(Dom, isl_dim_set, 1, PPCGArray.n_index - 1);
+        isl_pw_aff *Bound = isl_set_dim_max(isl_set_copy(Dom), 0);
+        isl_set_free(Dom);
+        Dom = isl_pw_aff_domain(isl_pw_aff_copy(Bound));
+        isl_local_space *LS =
+            isl_local_space_from_space(isl_set_get_space(Dom));
+        isl_aff *One = isl_aff_zero_on_domain(LS);
+        One = isl_aff_add_constant_si(One, 1);
+        Bound = isl_pw_aff_add(Bound, isl_pw_aff_alloc(Dom, One));
+        Bound = isl_pw_aff_gist(Bound, S->getContext().release());
+        Bounds.push_back(Bound);
+      }
+    }
+
+    for (unsigned i = 1; i < PPCGArray.n_index; ++i) {
+      isl_pw_aff *Bound = Array->getDimensionSizePw(i).release();
+      auto LS = isl_pw_aff_get_domain_space(Bound);
+      auto Aff = isl_multi_aff_zero(LS);
+
+      // We need types to work out, which is why we perform this weird dance
+      // with `Aff` and `Bound`. Consider this example:
+
+      // LS: [p] -> { [] }
+      // Zero: [p] -> { [] } | Implicitly, is [p] -> { ~ -> [] }.
+      // This `~` is used to denote a "null space" (which is different from
+      // a *zero dimensional* space), which is something that ISL does not
+      // show you when pretty printing.
+
+      // Bound: [p] -> { [] -> [(10p)] } | Here, the [] is a *zero dimensional*
+      // space, not a "null space" which does not exist at all.
+
+      // When we pullback (precompose) `Bound` with `Zero`, we get:
+      // Bound . Zero =
+      //     ([p] -> { [] -> [(10p)] }) . ([p] -> {~ -> [] }) =
+      //     [p] -> { ~ -> [(10p)] } =
+      //     [p] -> [(10p)] (as ISL pretty prints it)
+      // Bound Pullback: [p] -> { [(10p)] }
+
+      // We want this kind of an expression for Bound, without a
+      // zero dimensional input, but with a "null space" input for the types
+      // to work out later on, as far as I (Siddharth Bhat) understand.
+      // I was unable to find a reference to this in the ISL manual.
+      // References: Tobias Grosser.
+
+      Bound = isl_pw_aff_pullback_multi_aff(Bound, Aff);
+      Bounds.push_back(Bound);
+    }
+
+    /// To construct a `isl_multi_pw_aff`, we need all the indivisual `pw_aff`
+    /// to have the same parameter dimensions. So, we need to align them to an
+    /// appropriate space.
+    /// Scop::Context is _not_ an appropriate space, because when we have
+    /// `-polly-ignore-parameter-bounds` enabled, the Scop::Context does not
+    /// contain all parameter dimensions.
+    /// So, use the helper `alignPwAffs` to align all the `isl_pw_aff` together.
+    isl_space *SeedAlignSpace = S->getParamSpace().release();
+    SeedAlignSpace = isl_space_add_dims(SeedAlignSpace, isl_dim_set, 1);
+
+    isl_space *AlignSpace = nullptr;
+    std::vector<isl_pw_aff *> AlignedBounds;
+    std::tie(AlignSpace, AlignedBounds) =
+        alignPwAffs(std::move(Bounds), SeedAlignSpace);
+
+    assert(AlignSpace && "alignPwAffs did not initialise AlignSpace");
+
+    isl_pw_aff_list *BoundsList =
+        createPwAffList(S->getIslCtx().get(), std::move(AlignedBounds));
+
+    isl_space *BoundsSpace = isl_set_get_space(PPCGArray.extent);
+    BoundsSpace = isl_space_align_params(BoundsSpace, AlignSpace);
+
+    assert(BoundsSpace && "Unable to access space of array.");
+    assert(BoundsList && "Unable to access list of bounds.");
+
+    PPCGArray.bound =
+        isl_multi_pw_aff_from_pw_aff_list(BoundsSpace, BoundsList);
+    assert(PPCGArray.bound && "PPCGArray.bound was not constructed correctly.");
+  }
+
+  /// Create the arrays for @p PPCGProg.
+  ///
+  /// @param PPCGProg The program to compute the arrays for.
+  void createArrays(gpu_prog *PPCGProg,
+                    const SmallVector<ScopArrayInfo *, 4> &ValidSAIs) {
+    int i = 0;
+    for (auto &Array : ValidSAIs) {
+      std::string TypeName;
+      raw_string_ostream OS(TypeName);
+
+      OS << *Array->getElementType();
+      TypeName = OS.str();
+
+      gpu_array_info &PPCGArray = PPCGProg->array[i];
+
+      PPCGArray.space = Array->getSpace().release();
+      PPCGArray.type = strdup(TypeName.c_str());
+      PPCGArray.size = DL->getTypeAllocSize(Array->getElementType());
+      PPCGArray.name = strdup(Array->getName().c_str());
+      PPCGArray.extent = nullptr;
+      PPCGArray.n_index = Array->getNumberOfDimensions();
+      PPCGArray.extent = getExtent(Array).release();
+      PPCGArray.n_ref = 0;
+      PPCGArray.refs = nullptr;
+      PPCGArray.accessed = true;
+      PPCGArray.read_only_scalar =
+          Array->isReadOnly() && Array->getNumberOfDimensions() == 0;
+      PPCGArray.has_compound_element = false;
+      PPCGArray.local = false;
+      PPCGArray.declare_local = false;
+      PPCGArray.global = false;
+      PPCGArray.linearize = false;
+      PPCGArray.dep_order = nullptr;
+      PPCGArray.user = Array;
+
+      PPCGArray.bound = nullptr;
+      setArrayBounds(PPCGArray, Array);
+      i++;
+
+      collect_references(PPCGProg, &PPCGArray);
+      PPCGArray.only_fixed_element = only_fixed_element_accessed(&PPCGArray);
+    }
+  }
+
+  /// Create an identity map between the arrays in the scop.
+  ///
+  /// @returns An identity map between the arrays in the scop.
+  isl_union_map *getArrayIdentity() {
+    isl_union_map *Maps = isl_union_map_empty(S->getParamSpace().release());
+
+    for (auto &Array : S->arrays()) {
+      isl_space *Space = Array->getSpace().release();
+      Space = isl_space_map_from_set(Space);
+      isl_map *Identity = isl_map_identity(Space);
+      Maps = isl_union_map_add_map(Maps, Identity);
+    }
+
+    return Maps;
+  }
+
+  /// Create a default-initialized PPCG GPU program.
+  ///
+  /// @returns A new gpu program description.
+  gpu_prog *createPPCGProg(ppcg_scop *PPCGScop) {
+
+    if (!PPCGScop)
+      return nullptr;
+
+    auto PPCGProg = isl_calloc_type(S->getIslCtx().get(), struct gpu_prog);
+
+    PPCGProg->ctx = S->getIslCtx().get();
+    PPCGProg->scop = PPCGScop;
+    PPCGProg->context = isl_set_copy(PPCGScop->context);
+    PPCGProg->read = isl_union_map_copy(PPCGScop->reads);
+    PPCGProg->may_write = isl_union_map_copy(PPCGScop->may_writes);
+    PPCGProg->must_write = isl_union_map_copy(PPCGScop->must_writes);
+    PPCGProg->tagged_must_kill =
+        isl_union_map_copy(PPCGScop->tagged_must_kills);
+    PPCGProg->to_inner = getArrayIdentity();
+    PPCGProg->to_outer = getArrayIdentity();
+    // TODO: verify that this assignment is correct.
+    PPCGProg->any_to_outer = nullptr;
+    PPCGProg->n_stmts = std::distance(S->begin(), S->end());
+    PPCGProg->stmts = getStatements();
+
+    // Only consider arrays that have a non-empty extent.
+    // Otherwise, this will cause us to consider the following kinds of
+    // empty arrays:
+    //     1. Invariant loads that are represented by SAI objects.
+    //     2. Arrays with statically known zero size.
+    auto ValidSAIsRange =
+        make_filter_range(S->arrays(), [this](ScopArrayInfo *SAI) -> bool {
+          return !getExtent(SAI).is_empty();
+        });
+    SmallVector<ScopArrayInfo *, 4> ValidSAIs(ValidSAIsRange.begin(),
+                                              ValidSAIsRange.end());
+
+    PPCGProg->n_array =
+        ValidSAIs.size(); // std::distance(S->array_begin(), S->array_end());
+    PPCGProg->array = isl_calloc_array(
+        S->getIslCtx().get(), struct gpu_array_info, PPCGProg->n_array);
+
+    createArrays(PPCGProg, ValidSAIs);
+
+    PPCGProg->array_order = nullptr;
+    collect_order_dependences(PPCGProg);
+
+    PPCGProg->may_persist = compute_may_persist(PPCGProg);
+    return PPCGProg;
+  }
+
+  struct PrintGPUUserData {
+    struct cuda_info *CudaInfo;
+    struct gpu_prog *PPCGProg;
+    std::vector<ppcg_kernel *> Kernels;
+  };
+
+  /// Print a user statement node in the host code.
+  ///
+  /// We use ppcg's printing facilities to print the actual statement and
+  /// additionally build up a list of all kernels that are encountered in the
+  /// host ast.
+  ///
+  /// @param P The printer to print to
+  /// @param Options The printing options to use
+  /// @param Node The node to print
+  /// @param User A user pointer to carry additional data. This pointer is
+  ///             expected to be of type PrintGPUUserData.
+  ///
+  /// @returns A printer to which the output has been printed.
+  static __isl_give isl_printer *
+  printHostUser(__isl_take isl_printer *P,
+                __isl_take isl_ast_print_options *Options,
+                __isl_take isl_ast_node *Node, void *User) {
+    auto Data = (struct PrintGPUUserData *)User;
+    auto Id = isl_ast_node_get_annotation(Node);
+
+    if (Id) {
+      bool IsUser = !strcmp(isl_id_get_name(Id), "user");
+
+      // If this is a user statement, format it ourselves as ppcg would
+      // otherwise try to call pet functionality that is not available in
+      // Polly.
+      if (IsUser) {
+        P = isl_printer_start_line(P);
+        P = isl_printer_print_ast_node(P, Node);
+        P = isl_printer_end_line(P);
+        isl_id_free(Id);
+        isl_ast_print_options_free(Options);
+        return P;
+      }
+
+      auto Kernel = (struct ppcg_kernel *)isl_id_get_user(Id);
+      isl_id_free(Id);
+      Data->Kernels.push_back(Kernel);
+    }
+
+    return print_host_user(P, Options, Node, User);
+  }
+
+  /// Print C code corresponding to the control flow in @p Kernel.
+  ///
+  /// @param Kernel The kernel to print
+  void printKernel(ppcg_kernel *Kernel) {
+    auto *P = isl_printer_to_str(S->getIslCtx().get());
+    P = isl_printer_set_output_format(P, ISL_FORMAT_C);
+    auto *Options = isl_ast_print_options_alloc(S->getIslCtx().get());
+    P = isl_ast_node_print(Kernel->tree, P, Options);
+    char *String = isl_printer_get_str(P);
+    printf("%s\n", String);
+    free(String);
+    isl_printer_free(P);
+  }
+
+  /// Print C code corresponding to the GPU code described by @p Tree.
+  ///
+  /// @param Tree An AST describing GPU code
+  /// @param PPCGProg The PPCG program from which @Tree has been constructed.
+  void printGPUTree(isl_ast_node *Tree, gpu_prog *PPCGProg) {
+    auto *P = isl_printer_to_str(S->getIslCtx().get());
+    P = isl_printer_set_output_format(P, ISL_FORMAT_C);
+
+    PrintGPUUserData Data;
+    Data.PPCGProg = PPCGProg;
+
+    auto *Options = isl_ast_print_options_alloc(S->getIslCtx().get());
+    Options =
+        isl_ast_print_options_set_print_user(Options, printHostUser, &Data);
+    P = isl_ast_node_print(Tree, P, Options);
+    char *String = isl_printer_get_str(P);
+    printf("# host\n");
+    printf("%s\n", String);
+    free(String);
+    isl_printer_free(P);
+
+    for (auto Kernel : Data.Kernels) {
+      printf("# kernel%d\n", Kernel->id);
+      printKernel(Kernel);
+    }
+  }
+
+  // Generate a GPU program using PPCG.
+  //
+  // GPU mapping consists of multiple steps:
+  //
+  //  1) Compute new schedule for the program.
+  //  2) Map schedule to GPU (TODO)
+  //  3) Generate code for new schedule (TODO)
+  //
+  // We do not use here the Polly ScheduleOptimizer, as the schedule optimizer
+  // is mostly CPU specific. Instead, we use PPCG's GPU code generation
+  // strategy directly from this pass.
+  gpu_gen *generateGPU(ppcg_scop *PPCGScop, gpu_prog *PPCGProg) {
+
+    auto PPCGGen = isl_calloc_type(S->getIslCtx().get(), struct gpu_gen);
+
+    PPCGGen->ctx = S->getIslCtx().get();
+    PPCGGen->options = PPCGScop->options;
+    PPCGGen->print = nullptr;
+    PPCGGen->print_user = nullptr;
+    PPCGGen->build_ast_expr = &pollyBuildAstExprForStmt;
+    PPCGGen->prog = PPCGProg;
+    PPCGGen->tree = nullptr;
+    PPCGGen->types.n = 0;
+    PPCGGen->types.name = nullptr;
+    PPCGGen->sizes = nullptr;
+    PPCGGen->used_sizes = nullptr;
+    PPCGGen->kernel_id = 0;
+
+    // Set scheduling strategy to same strategy PPCG is using.
+    isl_options_set_schedule_outer_coincidence(PPCGGen->ctx, true);
+    isl_options_set_schedule_maximize_band_depth(PPCGGen->ctx, true);
+    isl_options_set_schedule_whole_component(PPCGGen->ctx, false);
+
+    isl_schedule *Schedule = get_schedule(PPCGGen);
+
+    int has_permutable = has_any_permutable_node(Schedule);
+
+    Schedule =
+        isl_schedule_align_params(Schedule, S->getFullParamSpace().release());
+
+    if (!has_permutable || has_permutable < 0) {
+      Schedule = isl_schedule_free(Schedule);
+      DEBUG(dbgs() << getUniqueScopName(S)
+                   << " does not have permutable bands. Bailing out\n";);
+    } else {
+      const bool CreateTransferToFromDevice = !PollyManagedMemory;
+      Schedule = map_to_device(PPCGGen, Schedule, CreateTransferToFromDevice);
+      PPCGGen->tree = generate_code(PPCGGen, isl_schedule_copy(Schedule));
+    }
+
+    if (DumpSchedule) {
+      isl_printer *P = isl_printer_to_str(S->getIslCtx().get());
+      P = isl_printer_set_yaml_style(P, ISL_YAML_STYLE_BLOCK);
+      P = isl_printer_print_str(P, "Schedule\n");
+      P = isl_printer_print_str(P, "========\n");
+      if (Schedule)
+        P = isl_printer_print_schedule(P, Schedule);
+      else
+        P = isl_printer_print_str(P, "No schedule found\n");
+
+      printf("%s\n", isl_printer_get_str(P));
+      isl_printer_free(P);
+    }
+
+    if (DumpCode) {
+      printf("Code\n");
+      printf("====\n");
+      if (PPCGGen->tree)
+        printGPUTree(PPCGGen->tree, PPCGProg);
+      else
+        printf("No code generated\n");
+    }
+
+    isl_schedule_free(Schedule);
+
+    return PPCGGen;
+  }
+
+  /// Free gpu_gen structure.
+  ///
+  /// @param PPCGGen The ppcg_gen object to free.
+  void freePPCGGen(gpu_gen *PPCGGen) {
+    isl_ast_node_free(PPCGGen->tree);
+    isl_union_map_free(PPCGGen->sizes);
+    isl_union_map_free(PPCGGen->used_sizes);
+    free(PPCGGen);
+  }
+
+  /// Free the options in the ppcg scop structure.
+  ///
+  /// ppcg is not freeing these options for us. To avoid leaks we do this
+  /// ourselves.
+  ///
+  /// @param PPCGScop The scop referencing the options to free.
+  void freeOptions(ppcg_scop *PPCGScop) {
+    free(PPCGScop->options->debug);
+    PPCGScop->options->debug = nullptr;
+    free(PPCGScop->options);
+    PPCGScop->options = nullptr;
+  }
+
+  /// Approximate the number of points in the set.
+  ///
+  /// This function returns an ast expression that overapproximates the number
+  /// of points in an isl set through the rectangular hull surrounding this set.
+  ///
+  /// @param Set   The set to count.
+  /// @param Build The isl ast build object to use for creating the ast
+  ///              expression.
+  ///
+  /// @returns An approximation of the number of points in the set.
+  __isl_give isl_ast_expr *approxPointsInSet(__isl_take isl_set *Set,
+                                             __isl_keep isl_ast_build *Build) {
+
+    isl_val *One = isl_val_int_from_si(isl_set_get_ctx(Set), 1);
+    auto *Expr = isl_ast_expr_from_val(isl_val_copy(One));
+
+    isl_space *Space = isl_set_get_space(Set);
+    Space = isl_space_params(Space);
+    auto *Univ = isl_set_universe(Space);
+    isl_pw_aff *OneAff = isl_pw_aff_val_on_domain(Univ, One);
+
+    for (long i = 0, n = isl_set_dim(Set, isl_dim_set); i < n; i++) {
+      isl_pw_aff *Max = isl_set_dim_max(isl_set_copy(Set), i);
+      isl_pw_aff *Min = isl_set_dim_min(isl_set_copy(Set), i);
+      isl_pw_aff *DimSize = isl_pw_aff_sub(Max, Min);
+      DimSize = isl_pw_aff_add(DimSize, isl_pw_aff_copy(OneAff));
+      auto DimSizeExpr = isl_ast_build_expr_from_pw_aff(Build, DimSize);
+      Expr = isl_ast_expr_mul(Expr, DimSizeExpr);
+    }
+
+    isl_set_free(Set);
+    isl_pw_aff_free(OneAff);
+
+    return Expr;
+  }
+
+  /// Approximate a number of dynamic instructions executed by a given
+  /// statement.
+  ///
+  /// @param Stmt  The statement for which to compute the number of dynamic
+  ///              instructions.
+  /// @param Build The isl ast build object to use for creating the ast
+  ///              expression.
+  /// @returns An approximation of the number of dynamic instructions executed
+  ///          by @p Stmt.
+  __isl_give isl_ast_expr *approxDynamicInst(ScopStmt &Stmt,
+                                             __isl_keep isl_ast_build *Build) {
+    auto Iterations = approxPointsInSet(Stmt.getDomain().release(), Build);
+
+    long InstCount = 0;
+
+    if (Stmt.isBlockStmt()) {
+      auto *BB = Stmt.getBasicBlock();
+      InstCount = std::distance(BB->begin(), BB->end());
+    } else {
+      auto *R = Stmt.getRegion();
+
+      for (auto *BB : R->blocks()) {
+        InstCount += std::distance(BB->begin(), BB->end());
+      }
+    }
+
+    isl_val *InstVal = isl_val_int_from_si(S->getIslCtx().get(), InstCount);
+    auto *InstExpr = isl_ast_expr_from_val(InstVal);
+    return isl_ast_expr_mul(InstExpr, Iterations);
+  }
+
+  /// Approximate dynamic instructions executed in scop.
+  ///
+  /// @param S     The scop for which to approximate dynamic instructions.
+  /// @param Build The isl ast build object to use for creating the ast
+  ///              expression.
+  /// @returns An approximation of the number of dynamic instructions executed
+  ///          in @p S.
+  __isl_give isl_ast_expr *
+  getNumberOfIterations(Scop &S, __isl_keep isl_ast_build *Build) {
+    isl_ast_expr *Instructions;
+
+    isl_val *Zero = isl_val_int_from_si(S.getIslCtx().get(), 0);
+    Instructions = isl_ast_expr_from_val(Zero);
+
+    for (ScopStmt &Stmt : S) {
+      isl_ast_expr *StmtInstructions = approxDynamicInst(Stmt, Build);
+      Instructions = isl_ast_expr_add(Instructions, StmtInstructions);
+    }
+    return Instructions;
+  }
+
+  /// Create a check that ensures sufficient compute in scop.
+  ///
+  /// @param S     The scop for which to ensure sufficient compute.
+  /// @param Build The isl ast build object to use for creating the ast
+  ///              expression.
+  /// @returns An expression that evaluates to TRUE in case of sufficient
+  ///          compute and to FALSE, otherwise.
+  __isl_give isl_ast_expr *
+  createSufficientComputeCheck(Scop &S, __isl_keep isl_ast_build *Build) {
+    auto Iterations = getNumberOfIterations(S, Build);
+    auto *MinComputeVal = isl_val_int_from_si(S.getIslCtx().get(), MinCompute);
+    auto *MinComputeExpr = isl_ast_expr_from_val(MinComputeVal);
+    return isl_ast_expr_ge(Iterations, MinComputeExpr);
+  }
+
+  /// Check if the basic block contains a function we cannot codegen for GPU
+  /// kernels.
+  ///
+  /// If this basic block does something with a `Function` other than calling
+  /// a function that we support in a kernel, return true.
+  bool containsInvalidKernelFunctionInBlock(const BasicBlock *BB,
+                                            bool AllowCUDALibDevice) {
+    for (const Instruction &Inst : *BB) {
+      const CallInst *Call = dyn_cast<CallInst>(&Inst);
+      if (Call && isValidFunctionInKernel(Call->getCalledFunction(),
+                                          AllowCUDALibDevice))
+        continue;
+
+      for (Value *Op : Inst.operands())
+        // Look for (<func-type>*) among operands of Inst
+        if (auto PtrTy = dyn_cast<PointerType>(Op->getType())) {
+          if (isa<FunctionType>(PtrTy->getElementType())) {
+            DEBUG(dbgs() << Inst
+                         << " has illegal use of function in kernel.\n");
+            return true;
+          }
+        }
+    }
+    return false;
+  }
+
+  /// Return whether the Scop S uses functions in a way that we do not support.
+  bool containsInvalidKernelFunction(const Scop &S, bool AllowCUDALibDevice) {
+    for (auto &Stmt : S) {
+      if (Stmt.isBlockStmt()) {
+        if (containsInvalidKernelFunctionInBlock(Stmt.getBasicBlock(),
+                                                 AllowCUDALibDevice))
+          return true;
+      } else {
+        assert(Stmt.isRegionStmt() &&
+               "Stmt was neither block nor region statement");
+        for (const BasicBlock *BB : Stmt.getRegion()->blocks())
+          if (containsInvalidKernelFunctionInBlock(BB, AllowCUDALibDevice))
+            return true;
+      }
+    }
+    return false;
+  }
+
+  /// Generate code for a given GPU AST described by @p Root.
+  ///
+  /// @param Root An isl_ast_node pointing to the root of the GPU AST.
+  /// @param Prog The GPU Program to generate code for.
+  void generateCode(__isl_take isl_ast_node *Root, gpu_prog *Prog) {
+    ScopAnnotator Annotator;
+    Annotator.buildAliasScopes(*S);
+
+    Region *R = &S->getRegion();
+
+    simplifyRegion(R, DT, LI, RI);
+
+    BasicBlock *EnteringBB = R->getEnteringBlock();
+
+    PollyIRBuilder Builder = createPollyIRBuilder(EnteringBB, Annotator);
+
+    // Only build the run-time condition and parameters _after_ having
+    // introduced the conditional branch. This is important as the conditional
+    // branch will guard the original scop from new induction variables that
+    // the SCEVExpander may introduce while code generating the parameters and
+    // which may introduce scalar dependences that prevent us from correctly
+    // code generating this scop.
+    BBPair StartExitBlocks;
+    BranchInst *CondBr = nullptr;
+    std::tie(StartExitBlocks, CondBr) =
+        executeScopConditionally(*S, Builder.getTrue(), *DT, *RI, *LI);
+    BasicBlock *StartBlock = std::get<0>(StartExitBlocks);
+
+    assert(CondBr && "CondBr not initialized by executeScopConditionally");
+
+    GPUNodeBuilder NodeBuilder(Builder, Annotator, *DL, *LI, *SE, *DT, *S,
+                               StartBlock, Prog, Runtime, Architecture);
+
+    // TODO: Handle LICM
+    auto SplitBlock = StartBlock->getSinglePredecessor();
+    Builder.SetInsertPoint(SplitBlock->getTerminator());
+
+    isl_ast_build *Build = isl_ast_build_alloc(S->getIslCtx().get());
+    isl_ast_expr *Condition = IslAst::buildRunCondition(*S, Build);
+    isl_ast_expr *SufficientCompute = createSufficientComputeCheck(*S, Build);
+    Condition = isl_ast_expr_and(Condition, SufficientCompute);
+    isl_ast_build_free(Build);
+
+    // preload invariant loads. Note: This should happen before the RTC
+    // because the RTC may depend on values that are invariant load hoisted.
+    if (!NodeBuilder.preloadInvariantLoads()) {
+      // Patch the introduced branch condition to ensure that we always execute
+      // the original SCoP.
+      auto *FalseI1 = Builder.getFalse();
+      auto *SplitBBTerm = Builder.GetInsertBlock()->getTerminator();
+      SplitBBTerm->setOperand(0, FalseI1);
+
+      DEBUG(dbgs() << "preloading invariant loads failed in function: " +
+                          S->getFunction().getName() +
+                          " | Scop Region: " + S->getNameStr());
+      // adjust the dominator tree accordingly.
+      auto *ExitingBlock = StartBlock->getUniqueSuccessor();
+      assert(ExitingBlock);
+      auto *MergeBlock = ExitingBlock->getUniqueSuccessor();
+      assert(MergeBlock);
+      polly::markBlockUnreachable(*StartBlock, Builder);
+      polly::markBlockUnreachable(*ExitingBlock, Builder);
+      auto *ExitingBB = S->getExitingBlock();
+      assert(ExitingBB);
+
+      DT->changeImmediateDominator(MergeBlock, ExitingBB);
+      DT->eraseNode(ExitingBlock);
+      isl_ast_expr_free(Condition);
+      isl_ast_node_free(Root);
+    } else {
+
+      if (polly::PerfMonitoring) {
+        PerfMonitor P(*S, EnteringBB->getParent()->getParent());
+        P.initialize();
+        P.insertRegionStart(SplitBlock->getTerminator());
+
+        // TODO: actually think if this is the correct exiting block to place
+        // the `end` performance marker. Invariant load hoisting changes
+        // the CFG in a way that I do not precisely understand, so I
+        // (Siddharth<siddu.druid@gmail.com>) should come back to this and
+        // think about which exiting block to use.
+        auto *ExitingBlock = StartBlock->getUniqueSuccessor();
+        assert(ExitingBlock);
+        BasicBlock *MergeBlock = ExitingBlock->getUniqueSuccessor();
+        P.insertRegionEnd(MergeBlock->getTerminator());
+      }
+
+      NodeBuilder.addParameters(S->getContext().release());
+      Value *RTC = NodeBuilder.createRTC(Condition);
+      Builder.GetInsertBlock()->getTerminator()->setOperand(0, RTC);
+
+      Builder.SetInsertPoint(&*StartBlock->begin());
+
+      NodeBuilder.create(Root);
+    }
+
+    /// In case a sequential kernel has more surrounding loops as any parallel
+    /// kernel, the SCoP is probably mostly sequential. Hence, there is no
+    /// point in running it on a GPU.
+    if (NodeBuilder.DeepestSequential > NodeBuilder.DeepestParallel)
+      CondBr->setOperand(0, Builder.getFalse());
+
+    if (!NodeBuilder.BuildSuccessful)
+      CondBr->setOperand(0, Builder.getFalse());
+  }
+
+  bool runOnScop(Scop &CurrentScop) override {
+    S = &CurrentScop;
+    LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+    DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+    SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
+    DL = &S->getRegion().getEntry()->getModule()->getDataLayout();
+    RI = &getAnalysis<RegionInfoPass>().getRegionInfo();
+
+    DEBUG(dbgs() << "PPCGCodeGen running on : " << getUniqueScopName(S)
+                 << " | loop depth: " << S->getMaxLoopDepth() << "\n");
+
+    // We currently do not support functions other than intrinsics inside
+    // kernels, as code generation will need to offload function calls to the
+    // kernel. This may lead to a kernel trying to call a function on the host.
+    // This also allows us to prevent codegen from trying to take the
+    // address of an intrinsic function to send to the kernel.
+    if (containsInvalidKernelFunction(CurrentScop,
+                                      Architecture == GPUArch::NVPTX64)) {
+      DEBUG(
+          dbgs() << getUniqueScopName(S)
+                 << " contains function which cannot be materialised in a GPU "
+                    "kernel. Bailing out.\n";);
+      return false;
+    }
+
+    auto PPCGScop = createPPCGScop();
+    auto PPCGProg = createPPCGProg(PPCGScop);
+    auto PPCGGen = generateGPU(PPCGScop, PPCGProg);
+
+    if (PPCGGen->tree) {
+      generateCode(isl_ast_node_copy(PPCGGen->tree), PPCGProg);
+      CurrentScop.markAsToBeSkipped();
+    } else {
+      DEBUG(dbgs() << getUniqueScopName(S)
+                   << " has empty PPCGGen->tree. Bailing out.\n");
+    }
+
+    freeOptions(PPCGScop);
+    freePPCGGen(PPCGGen);
+    gpu_prog_free(PPCGProg);
+    ppcg_scop_free(PPCGScop);
+
+    return true;
+  }
+
+  void printScop(raw_ostream &, Scop &) const override {}
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    ScopPass::getAnalysisUsage(AU);
+
+    AU.addRequired<DominatorTreeWrapperPass>();
+    AU.addRequired<RegionInfoPass>();
+    AU.addRequired<ScalarEvolutionWrapperPass>();
+    AU.addRequired<ScopDetectionWrapperPass>();
+    AU.addRequired<ScopInfoRegionPass>();
+    AU.addRequired<LoopInfoWrapperPass>();
+
+    // FIXME: We do not yet add regions for the newly generated code to the
+    //        region tree.
+  }
+};
+} // namespace
+
+char PPCGCodeGeneration::ID = 1;
+
+Pass *polly::createPPCGCodeGenerationPass(GPUArch Arch, GPURuntime Runtime) {
+  PPCGCodeGeneration *generator = new PPCGCodeGeneration();
+  generator->Runtime = Runtime;
+  generator->Architecture = Arch;
+  return generator;
+}
+
+INITIALIZE_PASS_BEGIN(PPCGCodeGeneration, "polly-codegen-ppcg",
+                      "Polly - Apply PPCG translation to SCOP", false, false)
+INITIALIZE_PASS_DEPENDENCY(DependenceInfo);
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass);
+INITIALIZE_PASS_END(PPCGCodeGeneration, "polly-codegen-ppcg",
+                    "Polly - Apply PPCG translation to SCOP", false, false)
diff --git a/final/lib/CodeGen/PerfMonitor.cpp b/final/lib/CodeGen/PerfMonitor.cpp
new file mode 100644
index 0000000..fce65fd
--- /dev/null
+++ b/final/lib/CodeGen/PerfMonitor.cpp
@@ -0,0 +1,305 @@
+//===------ PerfMonitor.cpp - Generate a run-time performance monitor. -======//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/PerfMonitor.h"
+#include "polly/CodeGen/RuntimeDebugBuilder.h"
+#include "polly/ScopInfo.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/IR/Intrinsics.h"
+#include <sstream>
+
+using namespace llvm;
+using namespace polly;
+
+Function *PerfMonitor::getAtExit() {
+  const char *Name = "atexit";
+  Function *F = M->getFunction(Name);
+
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(),
+                                         {Builder.getInt8PtrTy()}, false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  return F;
+}
+
+void PerfMonitor::addToGlobalConstructors(Function *Fn) {
+  const char *Name = "llvm.global_ctors";
+  GlobalVariable *GV = M->getGlobalVariable(Name);
+  std::vector<Constant *> V;
+
+  if (GV) {
+    Constant *Array = GV->getInitializer();
+    for (Value *X : Array->operand_values())
+      V.push_back(cast<Constant>(X));
+    GV->eraseFromParent();
+  }
+
+  StructType *ST = StructType::get(Builder.getInt32Ty(), Fn->getType(),
+                                   Builder.getInt8PtrTy());
+
+  V.push_back(
+      ConstantStruct::get(ST, Builder.getInt32(10), Fn,
+                          ConstantPointerNull::get(Builder.getInt8PtrTy())));
+  ArrayType *Ty = ArrayType::get(ST, V.size());
+
+  GV = new GlobalVariable(*M, Ty, true, GlobalValue::AppendingLinkage,
+                          ConstantArray::get(Ty, V), Name, nullptr,
+                          GlobalVariable::NotThreadLocal);
+}
+
+Function *PerfMonitor::getRDTSCP() {
+  return Intrinsic::getDeclaration(M, Intrinsic::x86_rdtscp);
+}
+
+PerfMonitor::PerfMonitor(const Scop &S, Module *M)
+    : M(M), Builder(M->getContext()), S(S) {
+  if (Triple(M->getTargetTriple()).getArch() == llvm::Triple::x86_64)
+    Supported = true;
+  else
+    Supported = false;
+}
+
+static void TryRegisterGlobal(Module *M, const char *Name,
+                              Constant *InitialValue, Value **Location) {
+  *Location = M->getGlobalVariable(Name);
+
+  if (!*Location)
+    *Location = new GlobalVariable(
+        *M, InitialValue->getType(), true, GlobalValue::WeakAnyLinkage,
+        InitialValue, Name, nullptr, GlobalVariable::InitialExecTLSModel);
+}
+
+// Generate a unique name that is usable as a LLVM name for a scop to name its
+// performance counter.
+static std::string GetScopUniqueVarname(const Scop &S) {
+  std::stringstream Name;
+  std::string EntryString, ExitString;
+  std::tie(EntryString, ExitString) = S.getEntryExitStr();
+
+  Name << "__polly_perf_in_" << std::string(S.getFunction().getName())
+       << "_from__" << EntryString << "__to__" << ExitString;
+  return Name.str();
+}
+
+void PerfMonitor::addScopCounter() {
+  const std::string varname = GetScopUniqueVarname(S);
+  TryRegisterGlobal(M, (varname + "_cycles").c_str(), Builder.getInt64(0),
+                    &CyclesInCurrentScopPtr);
+
+  TryRegisterGlobal(M, (varname + "_trip_count").c_str(), Builder.getInt64(0),
+                    &TripCountForCurrentScopPtr);
+}
+
+void PerfMonitor::addGlobalVariables() {
+  TryRegisterGlobal(M, "__polly_perf_cycles_total_start", Builder.getInt64(0),
+                    &CyclesTotalStartPtr);
+
+  TryRegisterGlobal(M, "__polly_perf_initialized", Builder.getInt1(0),
+                    &AlreadyInitializedPtr);
+
+  TryRegisterGlobal(M, "__polly_perf_cycles_in_scops", Builder.getInt64(0),
+                    &CyclesInScopsPtr);
+
+  TryRegisterGlobal(M, "__polly_perf_cycles_in_scop_start", Builder.getInt64(0),
+                    &CyclesInScopStartPtr);
+
+  TryRegisterGlobal(M, "__polly_perf_write_loation", Builder.getInt32(0),
+                    &RDTSCPWriteLocation);
+}
+
+static const char *InitFunctionName = "__polly_perf_init";
+static const char *FinalReportingFunctionName = "__polly_perf_final";
+
+static BasicBlock *FinalStartBB = nullptr;
+static ReturnInst *ReturnFromFinal = nullptr;
+
+Function *PerfMonitor::insertFinalReporting() {
+  // Create new function.
+  GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage;
+  FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false);
+  Function *ExitFn =
+      Function::Create(Ty, Linkage, FinalReportingFunctionName, M);
+  FinalStartBB = BasicBlock::Create(M->getContext(), "start", ExitFn);
+  Builder.SetInsertPoint(FinalStartBB);
+
+  if (!Supported) {
+    RuntimeDebugBuilder::createCPUPrinter(
+        Builder, "Polly runtime information generation not supported\n");
+    Builder.CreateRetVoid();
+    return ExitFn;
+  }
+
+  // Measure current cycles and compute final timings.
+  Function *RDTSCPFn = getRDTSCP();
+  Value *CurrentCycles = Builder.CreateCall(
+      RDTSCPFn,
+      Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy()));
+  Value *CyclesStart = Builder.CreateLoad(CyclesTotalStartPtr, true);
+  Value *CyclesTotal = Builder.CreateSub(CurrentCycles, CyclesStart);
+  Value *CyclesInScops = Builder.CreateLoad(CyclesInScopsPtr, true);
+
+  // Print the runtime information.
+  RuntimeDebugBuilder::createCPUPrinter(Builder, "Polly runtime information\n");
+  RuntimeDebugBuilder::createCPUPrinter(Builder, "-------------------------\n");
+  RuntimeDebugBuilder::createCPUPrinter(Builder, "Total: ", CyclesTotal, "\n");
+  RuntimeDebugBuilder::createCPUPrinter(Builder, "Scops: ", CyclesInScops,
+                                        "\n");
+
+  // Print the preamble for per-scop information.
+  RuntimeDebugBuilder::createCPUPrinter(Builder, "\n");
+  RuntimeDebugBuilder::createCPUPrinter(Builder, "Per SCoP information\n");
+  RuntimeDebugBuilder::createCPUPrinter(Builder, "--------------------\n");
+
+  RuntimeDebugBuilder::createCPUPrinter(
+      Builder, "scop function, "
+               "entry block name, exit block name, total time, trip count\n");
+  ReturnFromFinal = Builder.CreateRetVoid();
+  return ExitFn;
+}
+
+void PerfMonitor::AppendScopReporting() {
+  if (!Supported)
+    return;
+
+  assert(FinalStartBB && "Expected FinalStartBB to be initialized by "
+                         "PerfMonitor::insertFinalReporting.");
+  assert(ReturnFromFinal && "Expected ReturnFromFinal to be initialized by "
+                            "PerfMonitor::insertFinalReporting.");
+
+  Builder.SetInsertPoint(FinalStartBB);
+  ReturnFromFinal->eraseFromParent();
+
+  Value *CyclesInCurrentScop =
+      Builder.CreateLoad(this->CyclesInCurrentScopPtr, true);
+
+  Value *TripCountForCurrentScop =
+      Builder.CreateLoad(this->TripCountForCurrentScopPtr, true);
+
+  std::string EntryName, ExitName;
+  std::tie(EntryName, ExitName) = S.getEntryExitStr();
+
+  // print in CSV for easy parsing with other tools.
+  RuntimeDebugBuilder::createCPUPrinter(
+      Builder, S.getFunction().getName(), ", ", EntryName, ", ", ExitName, ", ",
+      CyclesInCurrentScop, ", ", TripCountForCurrentScop, "\n");
+
+  ReturnFromFinal = Builder.CreateRetVoid();
+}
+
+static Function *FinalReporting = nullptr;
+
+void PerfMonitor::initialize() {
+  addGlobalVariables();
+  addScopCounter();
+
+  // Ensure that we only add the final reporting function once.
+  // On later invocations, append to the reporting function.
+  if (!FinalReporting) {
+    FinalReporting = insertFinalReporting();
+
+    Function *InitFn = insertInitFunction(FinalReporting);
+    addToGlobalConstructors(InitFn);
+  }
+
+  AppendScopReporting();
+}
+
+Function *PerfMonitor::insertInitFunction(Function *FinalReporting) {
+  // Insert function definition and BBs.
+  GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage;
+  FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false);
+  Function *InitFn = Function::Create(Ty, Linkage, InitFunctionName, M);
+  BasicBlock *Start = BasicBlock::Create(M->getContext(), "start", InitFn);
+  BasicBlock *EarlyReturn =
+      BasicBlock::Create(M->getContext(), "earlyreturn", InitFn);
+  BasicBlock *InitBB = BasicBlock::Create(M->getContext(), "initbb", InitFn);
+
+  Builder.SetInsertPoint(Start);
+
+  // Check if this function was already run. If yes, return.
+  //
+  // In case profiling has been enabled in multiple translation units, the
+  // initializer function will be added to the global constructors list of
+  // each translation unit. When merging translation units, the global
+  // constructor lists are just appended, such that the initializer will appear
+  // multiple times. To avoid initializations being run multiple times (and
+  // especially to avoid that atExitFn is called more than once), we bail
+  // out if the initializer is run more than once.
+  Value *HasRunBefore = Builder.CreateLoad(AlreadyInitializedPtr);
+  Builder.CreateCondBr(HasRunBefore, EarlyReturn, InitBB);
+  Builder.SetInsertPoint(EarlyReturn);
+  Builder.CreateRetVoid();
+
+  // Keep track that this function has been run once.
+  Builder.SetInsertPoint(InitBB);
+  Value *True = Builder.getInt1(true);
+  Builder.CreateStore(True, AlreadyInitializedPtr);
+
+  // Register the final reporting function with atexit().
+  Value *FinalReportingPtr =
+      Builder.CreatePointerCast(FinalReporting, Builder.getInt8PtrTy());
+  Function *AtExitFn = getAtExit();
+  Builder.CreateCall(AtExitFn, {FinalReportingPtr});
+
+  if (Supported) {
+    // Read the currently cycle counter and store the result for later.
+    Function *RDTSCPFn = getRDTSCP();
+    Value *CurrentCycles = Builder.CreateCall(
+        RDTSCPFn,
+        Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy()));
+    Builder.CreateStore(CurrentCycles, CyclesTotalStartPtr, true);
+  }
+  Builder.CreateRetVoid();
+
+  return InitFn;
+}
+
+void PerfMonitor::insertRegionStart(Instruction *InsertBefore) {
+  if (!Supported)
+    return;
+
+  Builder.SetInsertPoint(InsertBefore);
+  Function *RDTSCPFn = getRDTSCP();
+  Value *CurrentCycles = Builder.CreateCall(
+      RDTSCPFn,
+      Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy()));
+  Builder.CreateStore(CurrentCycles, CyclesInScopStartPtr, true);
+}
+
+void PerfMonitor::insertRegionEnd(Instruction *InsertBefore) {
+  if (!Supported)
+    return;
+
+  Builder.SetInsertPoint(InsertBefore);
+  Function *RDTSCPFn = getRDTSCP();
+  LoadInst *CyclesStart = Builder.CreateLoad(CyclesInScopStartPtr, true);
+  Value *CurrentCycles = Builder.CreateCall(
+      RDTSCPFn,
+      Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy()));
+  Value *CyclesInScop = Builder.CreateSub(CurrentCycles, CyclesStart);
+  Value *CyclesInScops = Builder.CreateLoad(CyclesInScopsPtr, true);
+  CyclesInScops = Builder.CreateAdd(CyclesInScops, CyclesInScop);
+  Builder.CreateStore(CyclesInScops, CyclesInScopsPtr, true);
+
+  Value *CyclesInCurrentScop = Builder.CreateLoad(CyclesInCurrentScopPtr, true);
+  CyclesInCurrentScop = Builder.CreateAdd(CyclesInCurrentScop, CyclesInScop);
+  Builder.CreateStore(CyclesInCurrentScop, CyclesInCurrentScopPtr, true);
+
+  Value *TripCountForCurrentScop =
+      Builder.CreateLoad(TripCountForCurrentScopPtr, true);
+  TripCountForCurrentScop =
+      Builder.CreateAdd(TripCountForCurrentScop, Builder.getInt64(1));
+  Builder.CreateStore(TripCountForCurrentScop, TripCountForCurrentScopPtr,
+                      true);
+}
diff --git a/final/lib/CodeGen/RuntimeDebugBuilder.cpp b/final/lib/CodeGen/RuntimeDebugBuilder.cpp
new file mode 100644
index 0000000..16a7a4c
--- /dev/null
+++ b/final/lib/CodeGen/RuntimeDebugBuilder.cpp
@@ -0,0 +1,275 @@
+//===--- RuntimeDebugBuilder.cpp - Helper to insert prints into LLVM-IR ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/RuntimeDebugBuilder.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Debug.h"
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using namespace polly;
+
+Function *RuntimeDebugBuilder::getVPrintF(PollyIRBuilder &Builder) {
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  const char *Name = "vprintf";
+  Function *F = M->getFunction(Name);
+
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    FunctionType *Ty = FunctionType::get(
+        Builder.getInt32Ty(), {Builder.getInt8PtrTy(), Builder.getInt8PtrTy()},
+        false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  return F;
+}
+
+Function *RuntimeDebugBuilder::getAddressSpaceCast(PollyIRBuilder &Builder,
+                                                   unsigned Src, unsigned Dst,
+                                                   unsigned SrcBits,
+                                                   unsigned DstBits) {
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  auto Name = std::string("llvm.nvvm.ptr.constant.to.gen.p") +
+              std::to_string(Dst) + "i" + std::to_string(DstBits) + ".p" +
+              std::to_string(Src) + "i" + std::to_string(SrcBits);
+  Function *F = M->getFunction(Name);
+
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    FunctionType *Ty = FunctionType::get(
+        PointerType::get(Builder.getIntNTy(DstBits), Dst),
+        PointerType::get(Builder.getIntNTy(SrcBits), Src), false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  return F;
+}
+
+std::vector<Value *>
+RuntimeDebugBuilder::getGPUThreadIdentifiers(PollyIRBuilder &Builder) {
+  std::vector<Value *> Identifiers;
+
+  auto M = Builder.GetInsertBlock()->getParent()->getParent();
+
+  std::vector<Function *> BlockIDs = {
+      Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_ctaid_x),
+      Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_ctaid_y),
+      Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_ctaid_z),
+  };
+
+  Identifiers.push_back(Builder.CreateGlobalStringPtr("> block-id: ", "", 4));
+  for (auto GetID : BlockIDs) {
+    Value *Id = Builder.CreateCall(GetID, {});
+    Id = Builder.CreateIntCast(Id, Builder.getInt64Ty(), false);
+    Identifiers.push_back(Id);
+    Identifiers.push_back(Builder.CreateGlobalStringPtr(" ", "", 4));
+  }
+
+  Identifiers.push_back(Builder.CreateGlobalStringPtr("| ", "", 4));
+
+  std::vector<Function *> ThreadIDs = {
+      Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_tid_x),
+      Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_tid_y),
+      Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_tid_z),
+  };
+
+  Identifiers.push_back(Builder.CreateGlobalStringPtr("thread-id: ", "", 4));
+  for (auto GetId : ThreadIDs) {
+    Value *Id = Builder.CreateCall(GetId, {});
+    Id = Builder.CreateIntCast(Id, Builder.getInt64Ty(), false);
+    Identifiers.push_back(Id);
+    Identifiers.push_back(Builder.CreateGlobalStringPtr(" ", "", 4));
+  }
+
+  return Identifiers;
+}
+
+void RuntimeDebugBuilder::createPrinter(PollyIRBuilder &Builder, bool IsGPU,
+                                        ArrayRef<Value *> Values) {
+  if (IsGPU)
+    createGPUPrinterT(Builder, Values);
+  else
+    createCPUPrinterT(Builder, Values);
+}
+
+static std::tuple<std::string, std::vector<Value *>>
+prepareValuesForPrinting(PollyIRBuilder &Builder, ArrayRef<Value *> Values) {
+  std::string FormatString;
+  std::vector<Value *> ValuesToPrint;
+
+  for (auto Val : Values) {
+    Type *Ty = Val->getType();
+
+    if (Ty->isFloatingPointTy()) {
+      if (!Ty->isDoubleTy())
+        Val = Builder.CreateFPExt(Val, Builder.getDoubleTy());
+    } else if (Ty->isIntegerTy()) {
+      if (Ty->getIntegerBitWidth() < 64)
+        Val = Builder.CreateSExt(Val, Builder.getInt64Ty());
+      else
+        assert(Ty->getIntegerBitWidth() &&
+               "Integer types larger 64 bit not supported");
+    } else if (isa<PointerType>(Ty)) {
+      if (Ty->getPointerElementType() == Builder.getInt8Ty() &&
+          Ty->getPointerAddressSpace() == 4) {
+        Val = Builder.CreateGEP(Val, Builder.getInt64(0));
+      } else {
+        Val = Builder.CreatePtrToInt(Val, Builder.getInt64Ty());
+      }
+    } else {
+      llvm_unreachable("Unknown type");
+    }
+
+    Ty = Val->getType();
+
+    if (Ty->isFloatingPointTy())
+      FormatString += "%f";
+    else if (Ty->isIntegerTy())
+      FormatString += "%ld";
+    else
+      FormatString += "%s";
+
+    ValuesToPrint.push_back(Val);
+  }
+
+  return std::make_tuple(FormatString, ValuesToPrint);
+}
+
+void RuntimeDebugBuilder::createCPUPrinterT(PollyIRBuilder &Builder,
+                                            ArrayRef<Value *> Values) {
+
+  std::string FormatString;
+  std::vector<Value *> ValuesToPrint;
+
+  std::tie(FormatString, ValuesToPrint) =
+      prepareValuesForPrinting(Builder, Values);
+
+  createPrintF(Builder, FormatString, ValuesToPrint);
+  createFlush(Builder);
+}
+
+void RuntimeDebugBuilder::createGPUPrinterT(PollyIRBuilder &Builder,
+                                            ArrayRef<Value *> Values) {
+  std::string str;
+
+  auto *Zero = Builder.getInt64(0);
+
+  auto ToPrint = getGPUThreadIdentifiers(Builder);
+
+  ToPrint.push_back(Builder.CreateGlobalStringPtr("\n  ", "", 4));
+  ToPrint.insert(ToPrint.end(), Values.begin(), Values.end());
+
+  const DataLayout &DL = Builder.GetInsertBlock()->getModule()->getDataLayout();
+
+  // Allocate print buffer (assuming 2*32 bit per element)
+  auto T = ArrayType::get(Builder.getInt32Ty(), ToPrint.size() * 2);
+  Value *Data = new AllocaInst(
+      T, DL.getAllocaAddrSpace(), "polly.vprint.buffer",
+      &Builder.GetInsertBlock()->getParent()->getEntryBlock().front());
+  auto *DataPtr = Builder.CreateGEP(Data, {Zero, Zero});
+
+  int Offset = 0;
+  for (auto Val : ToPrint) {
+    auto Ptr = Builder.CreateGEP(DataPtr, Builder.getInt64(Offset));
+    Type *Ty = Val->getType();
+
+    if (Ty->isFloatingPointTy()) {
+      if (!Ty->isDoubleTy())
+        Val = Builder.CreateFPExt(Val, Builder.getDoubleTy());
+    } else if (Ty->isIntegerTy()) {
+      if (Ty->getIntegerBitWidth() < 64)
+        Val = Builder.CreateSExt(Val, Builder.getInt64Ty());
+      else
+        assert(Ty->getIntegerBitWidth() &&
+               "Integer types larger 64 bit not supported");
+    } else if (auto PtTy = dyn_cast<PointerType>(Ty)) {
+      if (PtTy->getAddressSpace() == 4) {
+        // Pointers in constant address space are printed as strings
+        Val = Builder.CreateGEP(Val, Builder.getInt64(0));
+        auto F = RuntimeDebugBuilder::getAddressSpaceCast(Builder, 4, 0);
+        Val = Builder.CreateCall(F, Val);
+      } else {
+        Val = Builder.CreatePtrToInt(Val, Builder.getInt64Ty());
+      }
+    } else {
+      llvm_unreachable("Unknown type");
+    }
+
+    Ty = Val->getType();
+    Ptr = Builder.CreatePointerBitCastOrAddrSpaceCast(Ptr, Ty->getPointerTo(5));
+    Builder.CreateAlignedStore(Val, Ptr, 4);
+
+    if (Ty->isFloatingPointTy())
+      str += "%f";
+    else if (Ty->isIntegerTy())
+      str += "%ld";
+    else
+      str += "%s";
+
+    Offset += 2;
+  }
+
+  Value *Format = Builder.CreateGlobalStringPtr(str, "polly.vprintf.buffer", 4);
+  Format = Builder.CreateCall(getAddressSpaceCast(Builder, 4, 0), Format);
+
+  Data = Builder.CreateBitCast(Data, Builder.getInt8PtrTy());
+
+  Builder.CreateCall(getVPrintF(Builder), {Format, Data});
+}
+
+Function *RuntimeDebugBuilder::getPrintF(PollyIRBuilder &Builder) {
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  const char *Name = "printf";
+  Function *F = M->getFunction(Name);
+
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), true);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  return F;
+}
+
+void RuntimeDebugBuilder::createPrintF(PollyIRBuilder &Builder,
+                                       std::string Format,
+                                       ArrayRef<Value *> Values) {
+  Value *FormatString = Builder.CreateGlobalStringPtr(Format);
+  std::vector<Value *> Arguments;
+
+  Arguments.push_back(FormatString);
+  Arguments.insert(Arguments.end(), Values.begin(), Values.end());
+  Builder.CreateCall(getPrintF(Builder), Arguments);
+}
+
+void RuntimeDebugBuilder::createFlush(PollyIRBuilder &Builder) {
+  Module *M = Builder.GetInsertBlock()->getParent()->getParent();
+  const char *Name = "fflush";
+  Function *F = M->getFunction(Name);
+
+  if (!F) {
+    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
+    FunctionType *Ty =
+        FunctionType::get(Builder.getInt32Ty(), Builder.getInt8PtrTy(), false);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  // fflush(NULL) flushes _all_ open output streams.
+  //
+  // fflush is declared as 'int fflush(FILE *stream)'. As we only pass on a NULL
+  // pointer, the type we point to does conceptually not matter. However, if
+  // fflush is already declared in this translation unit, we use the very same
+  // type to ensure that LLVM does not complain about mismatching types.
+  Builder.CreateCall(F, Constant::getNullValue(F->arg_begin()->getType()));
+}
diff --git a/final/lib/CodeGen/Utils.cpp b/final/lib/CodeGen/Utils.cpp
new file mode 100644
index 0000000..4d595fb
--- /dev/null
+++ b/final/lib/CodeGen/Utils.cpp
@@ -0,0 +1,221 @@
+//===--- Utils.cpp - Utility functions for the code generation --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains utility functions for the code generation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/Utils.h"
+#include "polly/CodeGen/IRBuilder.h"
+#include "polly/ScopInfo.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+
+using namespace llvm;
+
+// Alternative to llvm::SplitCriticalEdge.
+//
+// Creates a new block which branches to Succ. The edge to split is redirected
+// to the new block.
+//
+// The issue with llvm::SplitCriticalEdge is that it does nothing if the edge is
+// not critical.
+// The issue with llvm::SplitEdge is that it does not always create the middle
+// block, but reuses Prev/Succ if it can. We always want a new middle block.
+static BasicBlock *splitEdge(BasicBlock *Prev, BasicBlock *Succ,
+                             const char *Suffix, DominatorTree *DT,
+                             LoopInfo *LI, RegionInfo *RI) {
+  assert(Prev && Succ);
+
+  // Before:
+  //   \    /     /   //
+  //    Prev     /    //
+  //     |  \___/     //
+  //     |   ___      //
+  //     |  /   \     //
+  //    Succ     \    //
+  //   /    \     \   //
+
+  // The algorithm to update DominatorTree and LoopInfo of
+  // llvm::SplitCriticalEdge is more efficient than
+  // llvm::SplitBlockPredecessors, which is more general. In the future we might
+  // either modify llvm::SplitCriticalEdge to allow skipping the critical edge
+  // check; or Copy&Pase it here.
+  BasicBlock *MiddleBlock = SplitBlockPredecessors(
+      Succ, ArrayRef<BasicBlock *>(Prev), Suffix, DT, LI);
+
+  if (RI) {
+    Region *PrevRegion = RI->getRegionFor(Prev);
+    Region *SuccRegion = RI->getRegionFor(Succ);
+    if (PrevRegion->contains(MiddleBlock)) {
+      RI->setRegionFor(MiddleBlock, PrevRegion);
+    } else {
+      RI->setRegionFor(MiddleBlock, SuccRegion);
+    }
+  }
+
+  // After:
+  //   \    /     /   //
+  //    Prev     /    //
+  //     |  \___/     //
+  //     |            //
+  // MiddleBlock      //
+  //     |   ___      //
+  //     |  /   \     //
+  //    Succ     \    //
+  //   /    \     \   //
+
+  return MiddleBlock;
+}
+
+std::pair<polly::BBPair, BranchInst *>
+polly::executeScopConditionally(Scop &S, Value *RTC, DominatorTree &DT,
+                                RegionInfo &RI, LoopInfo &LI) {
+  Region &R = S.getRegion();
+  PollyIRBuilder Builder(S.getEntry());
+
+  // Before:
+  //
+  //      \   /      //
+  //    EnteringBB   //
+  //   _____|_____   //
+  //  /  EntryBB  \  //
+  //  |  (region) |  //
+  //  \_ExitingBB_/  //
+  //        |        //
+  //      ExitBB     //
+  //      /    \     //
+
+  // Create a fork block.
+  BasicBlock *EnteringBB = S.getEnteringBlock();
+  BasicBlock *EntryBB = S.getEntry();
+  assert(EnteringBB && "Must be a simple region");
+  BasicBlock *SplitBlock =
+      splitEdge(EnteringBB, EntryBB, ".split_new_and_old", &DT, &LI, &RI);
+  SplitBlock->setName("polly.split_new_and_old");
+
+  // If EntryBB is the exit block of the region that includes Prev, exclude
+  // SplitBlock from that region by making it itself the exit block. This is
+  // trivially possible because there is just one edge to EnteringBB.
+  // This is necessary because we will add an outgoing edge from SplitBlock,
+  // which would violate the single exit block requirement of PrevRegion.
+  Region *PrevRegion = RI.getRegionFor(EnteringBB);
+  while (PrevRegion->getExit() == EntryBB) {
+    PrevRegion->replaceExit(SplitBlock);
+    PrevRegion = PrevRegion->getParent();
+  }
+  RI.setRegionFor(SplitBlock, PrevRegion);
+
+  // Create a join block
+  BasicBlock *ExitingBB = S.getExitingBlock();
+  BasicBlock *ExitBB = S.getExit();
+  assert(ExitingBB && "Must be a simple region");
+  BasicBlock *MergeBlock =
+      splitEdge(ExitingBB, ExitBB, ".merge_new_and_old", &DT, &LI, &RI);
+  MergeBlock->setName("polly.merge_new_and_old");
+
+  // Exclude the join block from the region.
+  R.replaceExitRecursive(MergeBlock);
+  RI.setRegionFor(MergeBlock, R.getParent());
+
+  //      \   /      //
+  //    EnteringBB   //
+  //        |        //
+  //    SplitBlock   //
+  //   _____|_____   //
+  //  /  EntryBB  \  //
+  //  |  (region) |  //
+  //  \_ExitingBB_/  //
+  //        |        //
+  //    MergeBlock   //
+  //        |        //
+  //      ExitBB     //
+  //      /    \     //
+
+  // Create the start and exiting block.
+  Function *F = SplitBlock->getParent();
+  BasicBlock *StartBlock =
+      BasicBlock::Create(F->getContext(), "polly.start", F);
+  BasicBlock *ExitingBlock =
+      BasicBlock::Create(F->getContext(), "polly.exiting", F);
+  SplitBlock->getTerminator()->eraseFromParent();
+  Builder.SetInsertPoint(SplitBlock);
+  BranchInst *CondBr = Builder.CreateCondBr(RTC, StartBlock, S.getEntry());
+
+  if (Loop *L = LI.getLoopFor(SplitBlock)) {
+    L->addBasicBlockToLoop(StartBlock, LI);
+    L->addBasicBlockToLoop(ExitingBlock, LI);
+  }
+  DT.addNewBlock(StartBlock, SplitBlock);
+  DT.addNewBlock(ExitingBlock, StartBlock);
+  RI.setRegionFor(StartBlock, RI.getRegionFor(SplitBlock));
+  RI.setRegionFor(ExitingBlock, RI.getRegionFor(SplitBlock));
+
+  //      \   /                    //
+  //    EnteringBB                 //
+  //        |                      //
+  //    SplitBlock---------\       //
+  //   _____|_____         |       //
+  //  /  EntryBB  \    StartBlock  //
+  //  |  (region) |        |       //
+  //  \_ExitingBB_/   ExitingBlock //
+  //        |                      //
+  //    MergeBlock                 //
+  //        |                      //
+  //      ExitBB                   //
+  //      /    \                   //
+
+  // Connect start block to exiting block.
+  Builder.SetInsertPoint(StartBlock);
+  Builder.CreateBr(ExitingBlock);
+  DT.changeImmediateDominator(ExitingBlock, StartBlock);
+
+  // Connect exiting block to join block.
+  Builder.SetInsertPoint(ExitingBlock);
+  Builder.CreateBr(MergeBlock);
+  DT.changeImmediateDominator(MergeBlock, SplitBlock);
+
+  //      \   /                    //
+  //    EnteringBB                 //
+  //        |                      //
+  //    SplitBlock---------\       //
+  //   _____|_____         |       //
+  //  /  EntryBB  \    StartBlock  //
+  //  |  (region) |        |       //
+  //  \_ExitingBB_/   ExitingBlock //
+  //        |              |       //
+  //    MergeBlock---------/       //
+  //        |                      //
+  //      ExitBB                   //
+  //      /    \                   //
+  //
+
+  // Split the edge between SplitBlock and EntryBB, to avoid a critical edge.
+  splitEdge(SplitBlock, EntryBB, ".pre_entry_bb", &DT, &LI, &RI);
+
+  //      \   /                    //
+  //    EnteringBB                 //
+  //        |                      //
+  //    SplitBlock---------\       //
+  //        |              |       //
+  //    PreEntryBB         |       //
+  //   _____|_____         |       //
+  //  /  EntryBB  \    StartBlock  //
+  //  |  (region) |        |       //
+  //  \_ExitingBB_/   ExitingBlock //
+  //        |              |       //
+  //    MergeBlock---------/       //
+  //        |                      //
+  //      ExitBB                   //
+  //      /    \                   //
+
+  return std::make_pair(std::make_pair(StartBlock, ExitingBlock), CondBr);
+}
diff --git a/final/lib/Exchange/JSONExporter.cpp b/final/lib/Exchange/JSONExporter.cpp
new file mode 100644
index 0000000..512c515
--- /dev/null
+++ b/final/lib/Exchange/JSONExporter.cpp
@@ -0,0 +1,831 @@
+//===-- JSONExporter.cpp  - Export Scops as JSON  -------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Export the Scops build by ScopInfo pass as a JSON file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/JSONExporter.h"
+#include "polly/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "polly/ScopPass.h"
+#include "polly/Support/ScopLocation.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/raw_ostream.h"
+#include "isl/constraint.h"
+#include "isl/map.h"
+#include "isl/printer.h"
+#include "isl/set.h"
+#include "isl/union_map.h"
+#include "json/reader.h"
+#include "json/writer.h"
+#include <memory>
+#include <string>
+#include <system_error>
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-import-jscop"
+
+STATISTIC(NewAccessMapFound, "Number of updated access functions");
+
+namespace {
+static cl::opt<std::string>
+    ImportDir("polly-import-jscop-dir",
+              cl::desc("The directory to import the .jscop files from."),
+              cl::Hidden, cl::value_desc("Directory path"), cl::ValueRequired,
+              cl::init("."), cl::cat(PollyCategory));
+
+static cl::opt<std::string>
+    ImportPostfix("polly-import-jscop-postfix",
+                  cl::desc("Postfix to append to the import .jsop files."),
+                  cl::Hidden, cl::value_desc("File postfix"), cl::ValueRequired,
+                  cl::init(""), cl::cat(PollyCategory));
+
+struct JSONExporter : public ScopPass {
+  static char ID;
+  explicit JSONExporter() : ScopPass(ID) {}
+
+  /// Export the SCoP @p S to a JSON file.
+  bool runOnScop(Scop &S) override;
+
+  /// Print the SCoP @p S as it is exported.
+  void printScop(raw_ostream &OS, Scop &S) const override;
+
+  /// Register all analyses and transformation required.
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+};
+
+struct JSONImporter : public ScopPass {
+  static char ID;
+  std::vector<std::string> NewAccessStrings;
+  explicit JSONImporter() : ScopPass(ID) {}
+  /// Import new access functions for SCoP @p S from a JSON file.
+  bool runOnScop(Scop &S) override;
+
+  /// Print the SCoP @p S and the imported access functions.
+  void printScop(raw_ostream &OS, Scop &S) const override;
+
+  /// Register all analyses and transformation required.
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+};
+} // namespace
+
+static std::string getFileName(Scop &S, StringRef Suffix = "") {
+  std::string FunctionName = S.getFunction().getName();
+  std::string FileName = FunctionName + "___" + S.getNameStr() + ".jscop";
+
+  if (Suffix != "")
+    FileName += "." + Suffix.str();
+
+  return FileName;
+}
+
+/// Export all arrays from the Scop.
+///
+/// @param S The Scop containing the arrays.
+///
+/// @returns Json::Value containing the arrays.
+static Json::Value exportArrays(const Scop &S) {
+  Json::Value Arrays;
+  std::string Buffer;
+  llvm::raw_string_ostream RawStringOstream(Buffer);
+
+  for (auto &SAI : S.arrays()) {
+    if (!SAI->isArrayKind())
+      continue;
+
+    Json::Value Array;
+    Array["name"] = SAI->getName();
+    unsigned i = 0;
+    if (!SAI->getDimensionSize(i)) {
+      Array["sizes"].append("*");
+      i++;
+    }
+    for (; i < SAI->getNumberOfDimensions(); i++) {
+      SAI->getDimensionSize(i)->print(RawStringOstream);
+      Array["sizes"].append(RawStringOstream.str());
+      Buffer.clear();
+    }
+    SAI->getElementType()->print(RawStringOstream);
+    Array["type"] = RawStringOstream.str();
+    Buffer.clear();
+    Arrays.append(Array);
+  }
+  return Arrays;
+}
+
+static Json::Value getJSON(Scop &S) {
+  Json::Value root;
+  unsigned LineBegin, LineEnd;
+  std::string FileName;
+
+  getDebugLocation(&S.getRegion(), LineBegin, LineEnd, FileName);
+  std::string Location;
+  if (LineBegin != (unsigned)-1)
+    Location = FileName + ":" + std::to_string(LineBegin) + "-" +
+               std::to_string(LineEnd);
+
+  root["name"] = S.getNameStr();
+  root["context"] = S.getContextStr();
+  if (LineBegin != (unsigned)-1)
+    root["location"] = Location;
+
+  root["arrays"] = exportArrays(S);
+
+  root["statements"];
+
+  for (ScopStmt &Stmt : S) {
+    Json::Value statement;
+
+    statement["name"] = Stmt.getBaseName();
+    statement["domain"] = Stmt.getDomainStr();
+    statement["schedule"] = Stmt.getScheduleStr();
+    statement["accesses"];
+
+    for (MemoryAccess *MA : Stmt) {
+      Json::Value access;
+
+      access["kind"] = MA->isRead() ? "read" : "write";
+      access["relation"] = MA->getAccessRelationStr();
+
+      statement["accesses"].append(access);
+    }
+
+    root["statements"].append(statement);
+  }
+
+  return root;
+}
+
+static void exportScop(Scop &S) {
+  std::string FileName = ImportDir + "/" + getFileName(S);
+
+  Json::Value jscop = getJSON(S);
+  Json::StyledWriter writer;
+  std::string fileContent = writer.write(jscop);
+
+  // Write to file.
+  std::error_code EC;
+  ToolOutputFile F(FileName, EC, llvm::sys::fs::F_Text);
+
+  std::string FunctionName = S.getFunction().getName();
+  errs() << "Writing JScop '" << S.getNameStr() << "' in function '"
+         << FunctionName << "' to '" << FileName << "'.\n";
+
+  if (!EC) {
+    F.os() << fileContent;
+    F.os().close();
+    if (!F.os().has_error()) {
+      errs() << "\n";
+      F.keep();
+      return;
+    }
+  }
+
+  errs() << "  error opening file for writing!\n";
+  F.os().clear_error();
+}
+
+typedef Dependences::StatementToIslMapTy StatementToIslMapTy;
+
+/// Import a new context from JScop.
+///
+/// @param S The scop to update.
+/// @param JScop The JScop file describing the new schedule.
+///
+/// @returns True if the import succeeded, otherwise False.
+static bool importContext(Scop &S, Json::Value &JScop) {
+  isl::set OldContext = S.getContext();
+
+  // Check if key 'context' is present.
+  if (!JScop.isMember("context")) {
+    errs() << "JScop file has no key named 'context'.\n";
+    return false;
+  }
+
+  isl::set NewContext =
+      isl::set{S.getIslCtx().get(), JScop["context"].asString()};
+
+  // Check whether the context was parsed successfully.
+  if (!NewContext) {
+    errs() << "The context was not parsed successfully by ISL.\n";
+    return false;
+  }
+
+  // Check if the isl_set is a parameter set.
+  if (!NewContext.is_params()) {
+    errs() << "The isl_set is not a parameter set.\n";
+    return false;
+  }
+
+  unsigned OldContextDim = OldContext.dim(isl::dim::param);
+  unsigned NewContextDim = NewContext.dim(isl::dim::param);
+
+  // Check if the imported context has the right number of parameters.
+  if (OldContextDim != NewContextDim) {
+    errs() << "Imported context has the wrong number of parameters : "
+           << "Found " << NewContextDim << " Expected " << OldContextDim
+           << "\n";
+    return false;
+  }
+
+  for (unsigned i = 0; i < OldContextDim; i++) {
+    isl::id Id = OldContext.get_dim_id(isl::dim::param, i);
+    NewContext = NewContext.set_dim_id(isl::dim::param, i, Id);
+  }
+
+  S.setContext(NewContext);
+  return true;
+}
+
+/// Import a new schedule from JScop.
+///
+/// ... and verify that the new schedule does preserve existing data
+/// dependences.
+///
+/// @param S The scop to update.
+/// @param JScop The JScop file describing the new schedule.
+/// @param D The data dependences of the @p S.
+///
+/// @returns True if the import succeeded, otherwise False.
+static bool importSchedule(Scop &S, Json::Value &JScop, const Dependences &D) {
+  StatementToIslMapTy NewSchedule;
+
+  // Check if key 'statements' is present.
+  if (!JScop.isMember("statements")) {
+    errs() << "JScop file has no key name 'statements'.\n";
+    return false;
+  }
+
+  Json::Value statements = JScop["statements"];
+
+  // Check whether the number of indices equals the number of statements
+  if (statements.size() != S.getSize()) {
+    errs() << "The number of indices and the number of statements differ.\n";
+    return false;
+  }
+
+  int Index = 0;
+  for (ScopStmt &Stmt : S) {
+    // Check if key 'schedule' is present.
+    if (!statements[Index].isMember("schedule")) {
+      errs() << "Statement " << Index << " has no 'schedule' key.\n";
+      for (auto Element : NewSchedule) {
+        isl_map_free(Element.second);
+      }
+      return false;
+    }
+    Json::Value Schedule = statements[Index]["schedule"];
+    assert(!Schedule.asString().empty() &&
+           "Schedules that contain extension nodes require special handling.");
+    isl_map *Map =
+        isl_map_read_from_str(S.getIslCtx().get(), Schedule.asCString());
+
+    // Check whether the schedule was parsed successfully
+    if (!Map) {
+      errs() << "The schedule was not parsed successfully (index = " << Index
+             << ").\n";
+      for (auto Element : NewSchedule) {
+        isl_map_free(Element.second);
+      }
+      return false;
+    }
+
+    isl_space *Space = Stmt.getDomainSpace().release();
+
+    // Copy the old tuple id. This is necessary to retain the user pointer,
+    // that stores the reference to the ScopStmt this schedule belongs to.
+    Map = isl_map_set_tuple_id(Map, isl_dim_in,
+                               isl_space_get_tuple_id(Space, isl_dim_set));
+    for (unsigned i = 0; i < isl_space_dim(Space, isl_dim_param); i++) {
+      isl_id *Id = isl_space_get_dim_id(Space, isl_dim_param, i);
+      Map = isl_map_set_dim_id(Map, isl_dim_param, i, Id);
+    }
+    isl_space_free(Space);
+    NewSchedule[&Stmt] = Map;
+    Index++;
+  }
+
+  // Check whether the new schedule is valid or not.
+  if (!D.isValidSchedule(S, &NewSchedule)) {
+    errs() << "JScop file contains a schedule that changes the "
+           << "dependences. Use -disable-polly-legality to continue anyways\n";
+    for (auto Element : NewSchedule)
+      isl_map_free(Element.second);
+    return false;
+  }
+
+  auto ScheduleMap = isl::union_map::empty(S.getParamSpace());
+  for (ScopStmt &Stmt : S) {
+    if (NewSchedule.find(&Stmt) != NewSchedule.end())
+      ScheduleMap = ScheduleMap.add_map(isl::manage(NewSchedule[&Stmt]));
+    else
+      ScheduleMap = ScheduleMap.add_map(Stmt.getSchedule());
+  }
+
+  S.setSchedule(ScheduleMap);
+
+  return true;
+}
+
+/// Import new memory accesses from JScop.
+///
+/// @param S The scop to update.
+/// @param JScop The JScop file describing the new schedule.
+/// @param DL The data layout to assume.
+/// @param NewAccessStrings optionally record the imported access strings
+///
+/// @returns True if the import succeeded, otherwise False.
+static bool
+importAccesses(Scop &S, Json::Value &JScop, const DataLayout &DL,
+               std::vector<std::string> *NewAccessStrings = nullptr) {
+  int StatementIdx = 0;
+
+  // Check if key 'statements' is present.
+  if (!JScop.isMember("statements")) {
+    errs() << "JScop file has no key name 'statements'.\n";
+    return false;
+  }
+  Json::Value statements = JScop["statements"];
+
+  // Check whether the number of indices equals the number of statements
+  if (statements.size() != S.getSize()) {
+    errs() << "The number of indices and the number of statements differ.\n";
+    return false;
+  }
+
+  for (ScopStmt &Stmt : S) {
+    int MemoryAccessIdx = 0;
+
+    // Check if key 'accesses' is present.
+    if (!statements[StatementIdx].isMember("accesses")) {
+      errs()
+          << "Statement from JScop file has no key name 'accesses' for index "
+          << StatementIdx << ".\n";
+      return false;
+    }
+
+    // Check whether the number of indices equals the number of memory
+    // accesses
+    if (Stmt.size() != statements[StatementIdx]["accesses"].size()) {
+      errs() << "The number of memory accesses in the JSop file and the number "
+                "of memory accesses differ for index "
+             << StatementIdx << ".\n";
+      return false;
+    }
+
+    for (MemoryAccess *MA : Stmt) {
+      // Check if key 'relation' is present.
+      Json::Value JsonMemoryAccess =
+          statements[StatementIdx]["accesses"][MemoryAccessIdx];
+      if (!JsonMemoryAccess.isMember("relation")) {
+        errs() << "Memory access number " << MemoryAccessIdx
+               << " has no key name 'relation' for statement number "
+               << StatementIdx << ".\n";
+        return false;
+      }
+      Json::Value Accesses = JsonMemoryAccess["relation"];
+      isl_map *NewAccessMap =
+          isl_map_read_from_str(S.getIslCtx().get(), Accesses.asCString());
+
+      // Check whether the access was parsed successfully
+      if (!NewAccessMap) {
+        errs() << "The access was not parsed successfully by ISL.\n";
+        return false;
+      }
+      isl_map *CurrentAccessMap = MA->getAccessRelation().release();
+
+      // Check if the number of parameter change
+      if (isl_map_dim(NewAccessMap, isl_dim_param) !=
+          isl_map_dim(CurrentAccessMap, isl_dim_param)) {
+        errs() << "JScop file changes the number of parameter dimensions.\n";
+        isl_map_free(CurrentAccessMap);
+        isl_map_free(NewAccessMap);
+        return false;
+      }
+
+      isl_id *NewOutId;
+
+      // If the NewAccessMap has zero dimensions, it is the scalar access; it
+      // must be the same as before.
+      // If it has at least one dimension, it's an array access; search for
+      // its ScopArrayInfo.
+      if (isl_map_dim(NewAccessMap, isl_dim_out) >= 1) {
+        NewOutId = isl_map_get_tuple_id(NewAccessMap, isl_dim_out);
+        auto *SAI = S.getArrayInfoByName(isl_id_get_name(NewOutId));
+        isl_id *OutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
+        auto *OutSAI = ScopArrayInfo::getFromId(isl::manage(OutId));
+        if (!SAI || SAI->getElementType() != OutSAI->getElementType()) {
+          errs() << "JScop file contains access function with undeclared "
+                    "ScopArrayInfo\n";
+          isl_map_free(CurrentAccessMap);
+          isl_map_free(NewAccessMap);
+          isl_id_free(NewOutId);
+          return false;
+        }
+        isl_id_free(NewOutId);
+        NewOutId = SAI->getBasePtrId().release();
+      } else {
+        NewOutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
+      }
+
+      NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_out, NewOutId);
+
+      if (MA->isArrayKind()) {
+        // We keep the old alignment, thus we cannot allow accesses to memory
+        // locations that were not accessed before if the alignment of the
+        // access is not the default alignment.
+        bool SpecialAlignment = true;
+        if (LoadInst *LoadI = dyn_cast<LoadInst>(MA->getAccessInstruction())) {
+          SpecialAlignment =
+              LoadI->getAlignment() &&
+              DL.getABITypeAlignment(LoadI->getType()) != LoadI->getAlignment();
+        } else if (StoreInst *StoreI =
+                       dyn_cast<StoreInst>(MA->getAccessInstruction())) {
+          SpecialAlignment =
+              StoreI->getAlignment() &&
+              DL.getABITypeAlignment(StoreI->getValueOperand()->getType()) !=
+                  StoreI->getAlignment();
+        }
+
+        if (SpecialAlignment) {
+          isl_set *NewAccessSet = isl_map_range(isl_map_copy(NewAccessMap));
+          isl_set *CurrentAccessSet =
+              isl_map_range(isl_map_copy(CurrentAccessMap));
+          bool IsSubset = isl_set_is_subset(NewAccessSet, CurrentAccessSet);
+          isl_set_free(NewAccessSet);
+          isl_set_free(CurrentAccessSet);
+
+          // Check if the JScop file changes the accessed memory.
+          if (!IsSubset) {
+            errs() << "JScop file changes the accessed memory\n";
+            isl_map_free(CurrentAccessMap);
+            isl_map_free(NewAccessMap);
+            return false;
+          }
+        }
+      }
+
+      // We need to copy the isl_ids for the parameter dimensions to the new
+      // map. Without doing this the current map would have different
+      // ids then the new one, even though both are named identically.
+      for (unsigned i = 0; i < isl_map_dim(CurrentAccessMap, isl_dim_param);
+           i++) {
+        isl_id *Id = isl_map_get_dim_id(CurrentAccessMap, isl_dim_param, i);
+        NewAccessMap = isl_map_set_dim_id(NewAccessMap, isl_dim_param, i, Id);
+      }
+
+      // Copy the old tuple id. This is necessary to retain the user pointer,
+      // that stores the reference to the ScopStmt this access belongs to.
+      isl_id *Id = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_in);
+      NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_in, Id);
+
+      auto NewAccessDomain = isl_map_domain(isl_map_copy(NewAccessMap));
+      auto CurrentAccessDomain = isl_map_domain(isl_map_copy(CurrentAccessMap));
+
+      if (!isl_set_has_equal_space(NewAccessDomain, CurrentAccessDomain)) {
+        errs() << "JScop file contains access function with incompatible "
+               << "dimensions\n";
+        isl_map_free(CurrentAccessMap);
+        isl_map_free(NewAccessMap);
+        isl_set_free(NewAccessDomain);
+        isl_set_free(CurrentAccessDomain);
+        return false;
+      }
+
+      NewAccessDomain =
+          isl_set_intersect_params(NewAccessDomain, S.getContext().release());
+      CurrentAccessDomain = isl_set_intersect_params(CurrentAccessDomain,
+                                                     S.getContext().release());
+
+      if (MA->isRead() &&
+          isl_set_is_subset(CurrentAccessDomain, NewAccessDomain) ==
+              isl_bool_false) {
+        errs() << "Mapping not defined for all iteration domain elements\n";
+        isl_set_free(CurrentAccessDomain);
+        isl_set_free(NewAccessDomain);
+        isl_map_free(CurrentAccessMap);
+        isl_map_free(NewAccessMap);
+        return false;
+      }
+
+      isl_set_free(CurrentAccessDomain);
+      isl_set_free(NewAccessDomain);
+
+      if (!isl_map_is_equal(NewAccessMap, CurrentAccessMap)) {
+        // Statistics.
+        ++NewAccessMapFound;
+        if (NewAccessStrings)
+          NewAccessStrings->push_back(Accesses.asCString());
+        MA->setNewAccessRelation(isl::manage(NewAccessMap));
+      } else {
+        isl_map_free(NewAccessMap);
+      }
+      isl_map_free(CurrentAccessMap);
+      MemoryAccessIdx++;
+    }
+    StatementIdx++;
+  }
+
+  return true;
+}
+
+/// Check whether @p SAI and @p Array represent the same array.
+static bool areArraysEqual(ScopArrayInfo *SAI, Json::Value Array) {
+  std::string Buffer;
+  llvm::raw_string_ostream RawStringOstream(Buffer);
+
+  // Check if key 'type' is present.
+  if (!Array.isMember("type")) {
+    errs() << "Array has no key 'type'.\n";
+    return false;
+  }
+
+  // Check if key 'sizes' is present.
+  if (!Array.isMember("sizes")) {
+    errs() << "Array has no key 'sizes'.\n";
+    return false;
+  }
+
+  // Check if key 'name' is present.
+  if (!Array.isMember("name")) {
+    errs() << "Array has no key 'name'.\n";
+    return false;
+  }
+
+  if (SAI->getName() != Array["name"].asCString())
+    return false;
+
+  if (SAI->getNumberOfDimensions() != Array["sizes"].size())
+    return false;
+
+  for (unsigned i = 1; i < Array["sizes"].size(); i++) {
+    SAI->getDimensionSize(i)->print(RawStringOstream);
+    if (RawStringOstream.str() != Array["sizes"][i].asCString())
+      return false;
+    Buffer.clear();
+  }
+
+  // Check if key 'type' differs from the current one or is not valid.
+  SAI->getElementType()->print(RawStringOstream);
+  if (RawStringOstream.str() != Array["type"].asCString()) {
+    errs() << "Array has not a valid type.\n";
+    return false;
+  }
+
+  return true;
+}
+
+/// Get the accepted primitive type from its textual representation
+///        @p TypeTextRepresentation.
+///
+/// @param TypeTextRepresentation The textual representation of the type.
+/// @return The pointer to the primitive type, if this type is accepted
+///         or nullptr otherwise.
+static Type *parseTextType(const std::string &TypeTextRepresentation,
+                           LLVMContext &LLVMContext) {
+  std::map<std::string, Type *> MapStrToType = {
+      {"void", Type::getVoidTy(LLVMContext)},
+      {"half", Type::getHalfTy(LLVMContext)},
+      {"float", Type::getFloatTy(LLVMContext)},
+      {"double", Type::getDoubleTy(LLVMContext)},
+      {"x86_fp80", Type::getX86_FP80Ty(LLVMContext)},
+      {"fp128", Type::getFP128Ty(LLVMContext)},
+      {"ppc_fp128", Type::getPPC_FP128Ty(LLVMContext)},
+      {"i1", Type::getInt1Ty(LLVMContext)},
+      {"i8", Type::getInt8Ty(LLVMContext)},
+      {"i16", Type::getInt16Ty(LLVMContext)},
+      {"i32", Type::getInt32Ty(LLVMContext)},
+      {"i64", Type::getInt64Ty(LLVMContext)},
+      {"i128", Type::getInt128Ty(LLVMContext)}};
+
+  auto It = MapStrToType.find(TypeTextRepresentation);
+  if (It != MapStrToType.end())
+    return It->second;
+
+  errs() << "Textual representation can not be parsed: "
+         << TypeTextRepresentation << "\n";
+  return nullptr;
+}
+
+/// Import new arrays from JScop.
+///
+/// @param S The scop to update.
+/// @param JScop The JScop file describing new arrays.
+///
+/// @returns True if the import succeeded, otherwise False.
+static bool importArrays(Scop &S, Json::Value &JScop) {
+  Json::Value Arrays = JScop["arrays"];
+  if (Arrays.size() == 0)
+    return true;
+
+  unsigned ArrayIdx = 0;
+  for (auto &SAI : S.arrays()) {
+    if (!SAI->isArrayKind())
+      continue;
+    if (ArrayIdx + 1 > Arrays.size()) {
+      errs() << "Not enough array entries in JScop file.\n";
+      return false;
+    }
+    if (!areArraysEqual(SAI, Arrays[ArrayIdx])) {
+      errs() << "No match for array '" << SAI->getName() << "' in JScop.\n";
+      return false;
+    }
+    ArrayIdx++;
+  }
+
+  for (; ArrayIdx < Arrays.size(); ArrayIdx++) {
+    auto &Array = Arrays[ArrayIdx];
+    auto *ElementType =
+        parseTextType(Array["type"].asCString(), S.getSE()->getContext());
+    if (!ElementType) {
+      errs() << "Error while parsing element type for new array.\n";
+      return false;
+    }
+    std::vector<unsigned> DimSizes;
+    for (unsigned i = 0; i < Array["sizes"].size(); i++) {
+      auto Size = std::stoi(Array["sizes"][i].asCString());
+
+      // Check if the size if positive.
+      if (Size <= 0) {
+        errs() << "The size at index " << i << " is =< 0.\n";
+        return false;
+      }
+
+      DimSizes.push_back(Size);
+    }
+
+    auto NewSAI =
+        S.createScopArrayInfo(ElementType, Array["name"].asCString(), DimSizes);
+
+    if (Array.isMember("allocation")) {
+      NewSAI->setIsOnHeap(Array["allocation"].asString() == "heap");
+    }
+  }
+
+  return true;
+}
+
+/// Import a Scop from a JSCOP file
+/// @param S The scop to be modified
+/// @param D Dependence Info
+/// @param DL The DataLayout of the function
+/// @param NewAccessStrings Optionally record the imported access strings
+///
+/// @returns true on success, false otherwise. Beware that if this returns
+/// false, the Scop may still have been modified. In this case the Scop contains
+/// invalid information.
+static bool importScop(Scop &S, const Dependences &D, const DataLayout &DL,
+                       std::vector<std::string> *NewAccessStrings = nullptr) {
+  std::string FileName = ImportDir + "/" + getFileName(S, ImportPostfix);
+
+  std::string FunctionName = S.getFunction().getName();
+  errs() << "Reading JScop '" << S.getNameStr() << "' in function '"
+         << FunctionName << "' from '" << FileName << "'.\n";
+  ErrorOr<std::unique_ptr<MemoryBuffer>> result =
+      MemoryBuffer::getFile(FileName);
+  std::error_code ec = result.getError();
+
+  if (ec) {
+    errs() << "File could not be read: " << ec.message() << "\n";
+    return false;
+  }
+
+  Json::Reader reader;
+  Json::Value jscop;
+
+  bool parsingSuccessful = reader.parse(result.get()->getBufferStart(), jscop);
+
+  if (!parsingSuccessful) {
+    errs() << "JSCoP file could not be parsed\n";
+    return false;
+  }
+
+  bool Success = importContext(S, jscop);
+
+  if (!Success)
+    return false;
+
+  Success = importSchedule(S, jscop, D);
+
+  if (!Success)
+    return false;
+
+  Success = importArrays(S, jscop);
+
+  if (!Success)
+    return false;
+
+  Success = importAccesses(S, jscop, DL, NewAccessStrings);
+
+  if (!Success)
+    return false;
+  return true;
+}
+
+char JSONExporter::ID = 0;
+void JSONExporter::printScop(raw_ostream &OS, Scop &S) const { OS << S; }
+
+bool JSONExporter::runOnScop(Scop &S) {
+  exportScop(S);
+  return false;
+}
+
+void JSONExporter::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.setPreservesAll();
+  AU.addRequired<ScopInfoRegionPass>();
+}
+
+Pass *polly::createJSONExporterPass() { return new JSONExporter(); }
+
+PreservedAnalyses JSONExportPass::run(Scop &S, ScopAnalysisManager &SAM,
+                                      ScopStandardAnalysisResults &SAR,
+                                      SPMUpdater &) {
+  exportScop(S);
+  return PreservedAnalyses::all();
+}
+
+char JSONImporter::ID = 0;
+
+void JSONImporter::printScop(raw_ostream &OS, Scop &S) const {
+  OS << S;
+  for (std::vector<std::string>::const_iterator I = NewAccessStrings.begin(),
+                                                E = NewAccessStrings.end();
+       I != E; I++)
+    OS << "New access function '" << *I << "' detected in JSCOP file\n";
+}
+
+bool JSONImporter::runOnScop(Scop &S) {
+  const Dependences &D =
+      getAnalysis<DependenceInfo>().getDependences(Dependences::AL_Statement);
+  const DataLayout &DL = S.getFunction().getParent()->getDataLayout();
+
+  if (!importScop(S, D, DL, &NewAccessStrings))
+    report_fatal_error("Tried to import a malformed jscop file.");
+
+  return false;
+}
+
+void JSONImporter::getAnalysisUsage(AnalysisUsage &AU) const {
+  ScopPass::getAnalysisUsage(AU);
+  AU.addRequired<DependenceInfo>();
+
+  // TODO: JSONImporter should throw away DependenceInfo.
+  AU.addPreserved<DependenceInfo>();
+}
+
+Pass *polly::createJSONImporterPass() { return new JSONImporter(); }
+
+PreservedAnalyses JSONImportPass::run(Scop &S, ScopAnalysisManager &SAM,
+                                      ScopStandardAnalysisResults &SAR,
+                                      SPMUpdater &) {
+  const Dependences &D =
+      SAM.getResult<DependenceAnalysis>(S, SAR).getDependences(
+          Dependences::AL_Statement);
+  const DataLayout &DL = S.getFunction().getParent()->getDataLayout();
+
+  if (!importScop(S, D, DL))
+    report_fatal_error("Tried to import a malformed jscop file.");
+
+  // This invalidates all analyses on Scop.
+  PreservedAnalyses PA;
+  PA.preserveSet<AllAnalysesOn<Module>>();
+  PA.preserveSet<AllAnalysesOn<Function>>();
+  PA.preserveSet<AllAnalysesOn<Loop>>();
+  return PA;
+}
+
+INITIALIZE_PASS_BEGIN(JSONExporter, "polly-export-jscop",
+                      "Polly - Export Scops as JSON"
+                      " (Writes a .jscop file for each Scop)",
+                      false, false);
+INITIALIZE_PASS_DEPENDENCY(DependenceInfo)
+INITIALIZE_PASS_END(JSONExporter, "polly-export-jscop",
+                    "Polly - Export Scops as JSON"
+                    " (Writes a .jscop file for each Scop)",
+                    false, false)
+
+INITIALIZE_PASS_BEGIN(JSONImporter, "polly-import-jscop",
+                      "Polly - Import Scops from JSON"
+                      " (Reads a .jscop file for each Scop)",
+                      false, false);
+INITIALIZE_PASS_DEPENDENCY(DependenceInfo)
+INITIALIZE_PASS_END(JSONImporter, "polly-import-jscop",
+                    "Polly - Import Scops from JSON"
+                    " (Reads a .jscop file for each Scop)",
+                    false, false)
diff --git a/final/lib/External/CMakeLists.txt b/final/lib/External/CMakeLists.txt
new file mode 100644
index 0000000..b3c6e73
--- /dev/null
+++ b/final/lib/External/CMakeLists.txt
@@ -0,0 +1,372 @@
+# External: Integer Set Library
+if (POLLY_BUNDLED_ISL)
+  set(ISL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/isl")
+  set(ISL_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/isl")
+
+  # Determine version of isl
+  if (EXISTS "${ISL_SOURCE_DIR}/GIT_HEAD_ID")
+    # The source comes from a 'make dist' archive
+    file(READ "${ISL_SOURCE_DIR}/GIT_HEAD_ID" ISL_GIT_HEAD_ID)
+    string(STRIP "${ISL_GIT_HEAD_ID}" ISL_GIT_HEAD_ID)
+  elseif (EXISTS "${ISL_SOURCE_DIR}/gitversion.h")
+    # The source directory is preconfigured
+    file(READ "${ISL_SOURCE_DIR}/gitversion.h" GITVERSION_H)
+    string(REGEX REPLACE ".*\\\"([^\\\"]*)\\\".*" "\\1" ISL_GIT_HEAD_ID "${GITVERSION_H}")
+  elseif ()
+    # Unknown revision
+    # TODO: We could look for a .git and get the revision from HEAD
+    set(ISL_GIT_HEAD_ID "UNKNOWN")
+  endif ()
+
+  message(STATUS "ISL version: ${ISL_GIT_HEAD_ID}")
+
+  # Enable small integer optimization and imath
+  set(USE_GMP_FOR_MP OFF)
+  set(USE_IMATH_FOR_MP ON)
+  set(USE_SMALL_INT_OPT ON)
+
+  # Determine compiler characteristics
+  include(CheckCSourceCompiles)
+
+  # Like check_c_source_compiles, but sets the result to either
+  # 0 (error while compiling) or 1 (compiled successfully)
+  # Required for compatibility with autotool's AC_CHECK_DECLS
+  function (check_c_source_compiles_numeric _prog _var)
+    check_c_source_compiles("${_prog}" "${_var}")
+    if ("${${_var}}")
+      set("${_var}" 1 PARENT_SCOPE)
+    else ()
+      set("${_var}" 0 PARENT_SCOPE)
+    endif ()
+  endfunction ()
+
+  # Check for the existance of a type
+  function (check_c_type_exists _type _files _variable)
+    set(_includes "")
+    foreach (file_name ${_files})
+      set(_includes "${_includes}#include<${file_name}>\n")
+    endforeach()
+    check_c_source_compiles("
+    ${_includes}
+    ${_type} typeVar;
+    int main() {
+    return 0;
+    }
+    " ${_variable})
+  endfunction ()
+
+
+  check_c_source_compiles("
+  int func(void) __attribute__((__warn_unused_result__));
+  int main() { return 0; }
+  " HAS_ATTRIBUTE_WARN_UNUSED_RESULT)
+  set(GCC_WARN_UNUSED_RESULT)
+  if (HAS_ATTRIBUTE_WARN_UNUSED_RESULT)
+    set(GCC_WARN_UNUSED_RESULT "__attribute__((__warn_unused_result__))")
+  endif ()
+
+  check_c_source_compiles("
+  __attribute__ ((unused)) static void foo(void);
+  int main() { return 0; }
+  " HAVE___ATTRIBUTE__)
+
+
+  check_c_source_compiles_numeric("
+  #include <strings.h>
+  int main() { (void)ffs(0); return 0; }
+  " HAVE_DECL_FFS)
+
+  check_c_source_compiles_numeric("
+  int main() { (void)__builtin_ffs(0); return 0; }
+  " HAVE_DECL___BUILTIN_FFS)
+
+  check_c_source_compiles_numeric("
+  #include <intrin.h>
+  int main() { (void)_BitScanForward(NULL, 0); return 0; }
+  " HAVE_DECL__BITSCANFORWARD)
+
+  if (NOT HAVE_DECL_FFS AND
+      NOT HAVE_DECL___BUILTIN_FFS AND
+      NOT HAVE_DECL__BITSCANFORWARD)
+    message(FATAL_ERROR "No ffs implementation found")
+  endif ()
+
+
+  check_c_source_compiles_numeric("
+  #include <strings.h>
+  int main() { (void)strcasecmp(\"\", \"\"); return 0; }
+  " HAVE_DECL_STRCASECMP)
+
+  check_c_source_compiles_numeric("
+  #include <string.h>
+  int main() { (void)_stricmp(\"\", \"\"); return 0; }
+  " HAVE_DECL__STRICMP)
+
+  if (NOT HAVE_DECL_STRCASECMP AND NOT HAVE_DECL__STRICMP)
+    message(FATAL_ERROR "No strcasecmp implementation found")
+  endif ()
+
+
+  check_c_source_compiles_numeric("
+  #include <strings.h>
+  int main() { (void)strncasecmp(\"\", \"\", 0); return 0; }
+  " HAVE_DECL_STRNCASECMP)
+
+  check_c_source_compiles_numeric("
+  #include <string.h>
+  int main() { (void)_strnicmp(\"\", \"\", 0); return 0; }
+  " HAVE_DECL__STRNICMP)
+
+  if (NOT HAVE_DECL_STRNCASECMP AND NOT HAVE_DECL__STRNICMP)
+    message(FATAL_ERROR "No strncasecmp implementation found")
+  endif ()
+
+
+  check_c_source_compiles_numeric("
+  #include <stdio.h>
+  int main() { snprintf((void*)0, 0, \" \"); return 0; }
+  " HAVE_DECL_SNPRINTF)
+
+  check_c_source_compiles_numeric("
+  #include <stdio.h>
+  int main() { _snprintf((void*)0, 0, \" \"); return 0; }
+  " HAVE_DECL__SNPRINTF)
+
+  if (NOT HAVE_DECL_SNPRINTF AND NOT HAVE_DECL__SNPRINTF)
+    message(FATAL_ERROR "No snprintf implementation found")
+  endif ()
+
+
+  check_c_type_exists(uint8_t "" HAVE_UINT8T)
+  check_c_type_exists(uint8_t "stdint.h" HAVE_STDINT_H)
+  check_c_type_exists(uint8_t "inttypes.h" HAVE_INTTYPES_H)
+  check_c_type_exists(uint8_t "sys/types.h" HAVE_SYS_INTTYPES_H)
+  if (HAVE_UINT8T)
+    set(INCLUDE_STDINT_H "")
+  elseif (HAVE_STDINT_H)
+    set(INCLUDE_STDINT_H "#include <stdint.h>")
+  elseif (HAVE_INTTYPES_H)
+    set(INCLUDE_STDINT_H "#include <inttypes.h>")
+  elseif (HAVE_SYS_INTTYPES_H)
+    set(INCLUDE_STDINT_H "#include <sys/inttypes.h>")
+  else ()
+    message(FATAL_ERROR "No stdint.h or compatible found")
+  endif ()
+
+  # Write configure result
+  # configure_file(... COPYONLY) avoids that the time stamp changes if the file is identical
+  file(WRITE "${ISL_BINARY_DIR}/gitversion.h.tmp"
+    "#define GIT_HEAD_ID \"${ISL_GIT_HEAD_ID}\"")
+  configure_file("${ISL_BINARY_DIR}/gitversion.h.tmp"
+    "${ISL_BINARY_DIR}/gitversion.h" COPYONLY)
+
+  file(WRITE "${ISL_BINARY_DIR}/include/isl/stdint.h.tmp"
+    "${INCLUDE_STDINT_H}\n")
+  configure_file("${ISL_BINARY_DIR}/include/isl/stdint.h.tmp"
+    "${ISL_BINARY_DIR}/include/isl/stdint.h" COPYONLY)
+
+  configure_file("isl_config.h.cmake" "${ISL_BINARY_DIR}/isl_config.h")
+  configure_file("isl_srcdir.c.cmake" "${ISL_BINARY_DIR}/isl_srcdir.c")
+
+  include_directories(BEFORE
+    ${ISL_BINARY_DIR}
+    ${ISL_SOURCE_DIR}/imath
+    ${ISL_SOURCE_DIR}/include
+    ${ISL_SOURCE_DIR}
+    )
+
+  # ISL files to compile
+  set (ISL_FILES
+    isl/basis_reduction_tab.c
+    isl/isl_aff.c
+    isl/isl_affine_hull.c
+    isl/isl_arg.c
+    isl/isl_ast_build.c
+    isl/isl_ast_build_expr.c
+    isl/isl_ast.c
+    isl/isl_ast_codegen.c
+    isl/isl_ast_graft.c
+    isl/isl_band.c
+    isl/isl_bernstein.c
+    isl/isl_blk.c
+    isl/isl_bound.c
+    isl/isl_coalesce.c
+    isl/isl_constraint.c
+    isl/isl_convex_hull.c
+    isl/isl_ctx.c
+    isl/isl_deprecated.c
+    isl/isl_dim_map.c
+    isl/isl_equalities.c
+    isl/isl_factorization.c
+    isl/isl_farkas.c
+    isl/isl_ffs.c
+    isl/isl_flow.c
+    isl/isl_fold.c
+    isl/isl_hash.c
+    isl/isl_id.c
+    isl/isl_id_to_ast_expr.c
+    isl/isl_id_to_id.c
+    isl/isl_id_to_pw_aff.c
+    isl/isl_ilp.c
+    isl/isl_imath.c
+    isl/isl_input.c
+    isl/isl_int_sioimath.c
+    isl/isl_local.c
+    isl/isl_local_space.c
+    isl/isl_lp.c
+    isl/isl_map.c
+    isl/isl_map_list.c
+    isl/isl_map_simplify.c
+    isl/isl_map_subtract.c
+    isl/isl_map_to_basic_set.c
+    isl/isl_mat.c
+    isl/isl_morph.c
+    isl/isl_obj.c
+    isl/isl_options.c
+    isl/isl_output.c
+    isl/isl_point.c
+    isl/isl_polynomial.c
+    isl/isl_printer.c
+    isl/isl_range.c
+    isl/isl_reordering.c
+    isl/isl_sample.c
+    isl/isl_scan.c
+    isl/isl_schedule.c
+    isl/isl_schedule_band.c
+    isl/isl_schedule_constraints.c
+    isl/isl_schedule_node.c
+    isl/isl_schedule_read.c
+    isl/isl_schedule_tree.c
+    isl/isl_scheduler.c
+    isl/isl_seq.c
+    isl/isl_set_list.c
+    isl/isl_sort.c
+    isl/isl_space.c
+    isl/isl_stream.c
+    isl/isl_tab.c
+    isl/isl_tab_pip.c
+    isl/isl_tarjan.c
+    isl/isl_transitive_closure.c
+    isl/isl_union_map.c
+    isl/isl_val.c
+    isl/isl_val_sioimath.c
+    isl/isl_vec.c
+    isl/isl_version.c
+    isl/isl_vertices.c
+    isl/print.c
+    isl/imath/gmp_compat.c
+    isl/imath/imath.c
+    isl/imath/imrat.c
+    )
+
+  add_polly_library(PollyISL
+    ${ISL_FILES}
+    )
+
+
+  if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+    install(DIRECTORY
+      ${ISL_SOURCE_DIR}/include/
+      ${ISL_BINARY_DIR}/include/
+      DESTINATION include/polly
+      FILES_MATCHING
+      PATTERN "*.h"
+      PATTERN "CMakeFiles" EXCLUDE
+      PATTERN ".svn" EXCLUDE
+      )
+  endif()
+
+  add_executable(polly-isl-test
+    isl/isl_test.c
+    )
+  set_target_properties(polly-isl-test PROPERTIES FOLDER "Polly")
+
+  target_link_libraries(polly-isl-test
+    PollyISL
+    )
+
+  # ISL requires at least C99 to compile. gcc < 5.0 use -std=gnu89 as default.
+  target_enable_c99(PollyISL)
+  target_enable_c99(polly-isl-test)
+endif (POLLY_BUNDLED_ISL)
+
+set(PET_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/pet")
+set(PPCG_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ppcg")
+set(PPCG_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/ppcg")
+
+# Determine version of ppcg
+if (EXISTS "${PPCG_SOURCE_DIR}/GIT_HEAD_ID")
+  # The source comes from a 'make dist' archive
+  file(READ "${PPCG_SOURCE_DIR}/GIT_HEAD_ID" PPCG_GIT_HEAD_ID)
+  string(STRIP "${PPCG_GIT_HEAD_ID}" PPCG_GIT_HEAD_ID)
+elseif (EXISTS "${PPCG_SOURCE_DIR}/gitversion.h")
+  # The source directory is preconfigured
+  file(READ "${PPCG_SOURCE_DIR}/gitversion.h" GITVERSION_H)
+  string(REGEX REPLACE ".*\\\"([^\\\"]*)\\\".*" "\\1" PPCG_GIT_HEAD_ID "${GITVERSION_H}")
+elseif ()
+  # Unknown revision
+  # TODO: We could look for a .git and get the revision from HEAD
+  set(PPCG_GIT_HEAD_ID "UNKNOWN")
+endif ()
+
+message(STATUS "PPCG version: ${PPCG_GIT_HEAD_ID}")
+
+set (PPCG_FILES
+     ppcg/cuda.c
+     ppcg/cuda_common.c
+     ppcg/external.c
+     ppcg/gpu_array_tile.c
+     ppcg/gpu.c
+     ppcg/gpu_array_tile.c
+     ppcg/gpu_group.c
+     ppcg/gpu_hybrid.c
+     ppcg/gpu_print.c
+     ppcg/gpu_tree.c
+     ppcg/grouping.c
+     ppcg/hybrid.c
+     ppcg/ppcg.c
+     ppcg/ppcg_options.c
+     ppcg/print.c
+     ppcg/schedule.c
+     ppcg/util.c
+     )
+
+include_directories(BEFORE
+  ${PPCG_BINARY_DIR}
+  ${PPCG_SOURCE_DIR}/imath
+  ${PPCG_SOURCE_DIR}/include
+  ${PET_SOURCE_DIR}/include
+)
+
+add_polly_library(PollyPPCG
+  ${PPCG_FILES}
+)
+
+target_link_libraries(PollyPPCG ${ISL_TARGET})
+
+# Disable warnings for upstream projects.
+if (MSVC)
+  set(DISABLE_WARNING_FLAGS
+    -wd4018 # 'expression' : signed/unsigned mismatch
+    -wd4090 # 'operation' : different 'modifier' qualifiers
+    -wd4200 # nonstandard extension used: zero-sized array in struct/union
+    -wd4201 # nonstandard extension used: nameless struct/union
+    -wd4334 # 'operator': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
+  )
+  if (POLLY_BUNDLED_ISL)
+    target_compile_options(PollyISL PRIVATE ${DISABLE_WARNING_FLAGS})
+    target_compile_options(polly-isl-test PRIVATE ${DISABLE_WARNING_FLAGS})
+  endif (POLLY_BUNDLED_ISL)
+  target_compile_options(PollyPPCG PRIVATE ${DISABLE_WARNING_FLAGS})
+else ()
+  if (POLLY_BUNDLED_ISL)
+    set_target_properties(PollyISL polly-isl-test PROPERTIES COMPILE_FLAGS "-w")
+  endif (POLLY_BUNDLED_ISL)
+  set_target_properties(PollyPPCG PROPERTIES COMPILE_FLAGS "-w")
+endif ()
+
+if(MSVC)
+  # In the Windows API (with some exceptions), the maximum length for a path is
+  # MAX_PATH, which is defined as 260 characters.
+  target_compile_definitions(PollyPPCG PRIVATE "-DPATH_MAX=260")
+endif ()
diff --git a/final/lib/External/JSON/LICENSE.txt b/final/lib/External/JSON/LICENSE.txt
new file mode 100644
index 0000000..1c37b11
--- /dev/null
+++ b/final/lib/External/JSON/LICENSE.txt
@@ -0,0 +1 @@
+The json-cpp library and this documentation are in Public Domain.
diff --git a/final/lib/External/JSON/include/json/autolink.h b/final/lib/External/JSON/include/json/autolink.h
new file mode 100644
index 0000000..37c9258
--- /dev/null
+++ b/final/lib/External/JSON/include/json/autolink.h
@@ -0,0 +1,19 @@
+#ifndef JSON_AUTOLINK_H_INCLUDED
+# define JSON_AUTOLINK_H_INCLUDED
+
+# include "config.h"
+
+# ifdef JSON_IN_CPPTL
+#  include <cpptl/cpptl_autolink.h>
+# endif
+
+# if !defined(JSON_NO_AUTOLINK)  &&  !defined(JSON_DLL_BUILD)  &&  !defined(JSON_IN_CPPTL)
+#  define CPPTL_AUTOLINK_NAME "json"
+#  undef CPPTL_AUTOLINK_DLL
+#  ifdef JSON_DLL
+#   define CPPTL_AUTOLINK_DLL
+#  endif
+#  include "autolink.h"
+# endif
+
+#endif // JSON_AUTOLINK_H_INCLUDED
diff --git a/final/lib/External/JSON/include/json/config.h b/final/lib/External/JSON/include/json/config.h
new file mode 100644
index 0000000..b6dde91
--- /dev/null
+++ b/final/lib/External/JSON/include/json/config.h
@@ -0,0 +1,43 @@
+#ifndef JSON_CONFIG_H_INCLUDED
+# define JSON_CONFIG_H_INCLUDED
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//#  define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of std::map
+/// as Value container.
+//#  define JSON_USE_CPPTL_SMALLMAP 1
+/// If defined, indicates that Json specific container should be used
+/// (hash table & simple deque container with customizable allocator).
+/// THIS FEATURE IS STILL EXPERIMENTAL!
+//#  define JSON_VALUE_USE_INTERNAL_MAP 1
+/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
+/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
+/// as if it was a POD) that may cause some validation tool to report errors.
+/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
+//#  define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
+
+/// If defined, indicates that Json use exception to report invalid type manipulation
+/// instead of C assert macro.
+# define JSON_USE_EXCEPTION 0
+
+# ifdef JSON_IN_CPPTL
+#  include <cpptl/config.h>
+#  ifndef JSON_USE_CPPTL
+#   define JSON_USE_CPPTL 1
+#  endif
+# endif
+
+# ifdef JSON_IN_CPPTL
+#  define JSON_API CPPTL_API
+# elif defined(JSON_DLL_BUILD)
+#  define JSON_API __declspec(dllexport)
+# elif defined(JSON_DLL)
+#  define JSON_API __declspec(dllimport)
+# else
+#  define JSON_API
+# endif
+
+#endif // JSON_CONFIG_H_INCLUDED
diff --git a/final/lib/External/JSON/include/json/features.h b/final/lib/External/JSON/include/json/features.h
new file mode 100644
index 0000000..5a9adec
--- /dev/null
+++ b/final/lib/External/JSON/include/json/features.h
@@ -0,0 +1,42 @@
+#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
+# define CPPTL_JSON_FEATURES_H_INCLUDED
+
+# include "forwards.h"
+
+namespace Json {
+
+   /** \brief Configuration passed to reader and writer.
+    * This configuration object can be used to force the Reader or Writer
+    * to behave in a standard conforming way.
+    */
+   class JSON_API Features
+   {
+   public:
+      /** \brief A configuration that allows all features and assumes all strings are UTF-8.
+       * - C & C++ comments are allowed
+       * - Root object can be any JSON value
+       * - Assumes Value strings are encoded in UTF-8
+       */
+      static Features all();
+
+      /** \brief A configuration that is strictly compatible with the JSON specification.
+       * - Comments are forbidden.
+       * - Root object must be either an array or an object value.
+       * - Assumes Value strings are encoded in UTF-8
+       */
+      static Features strictMode();
+
+      /** \brief Initialize the configuration like JsonConfig::allFeatures;
+       */
+      Features();
+
+      /// \c true if comments are allowed. Default: \c true.
+      bool allowComments_;
+
+      /// \c true if root must be either an array or an object value. Default: \c false.
+      bool strictRoot_;
+   };
+
+} // namespace Json
+
+#endif // CPPTL_JSON_FEATURES_H_INCLUDED
diff --git a/final/lib/External/JSON/include/json/forwards.h b/final/lib/External/JSON/include/json/forwards.h
new file mode 100644
index 0000000..d0ce830
--- /dev/null
+++ b/final/lib/External/JSON/include/json/forwards.h
@@ -0,0 +1,39 @@
+#ifndef JSON_FORWARDS_H_INCLUDED
+# define JSON_FORWARDS_H_INCLUDED
+
+# include "config.h"
+
+namespace Json {
+
+   // writer.h
+   class FastWriter;
+   class StyledWriter;
+
+   // reader.h
+   class Reader;
+
+   // features.h
+   class Features;
+
+   // value.h
+   typedef int Int;
+   typedef unsigned int UInt;
+   class StaticString;
+   class Path;
+   class PathArgument;
+   class Value;
+   class ValueIteratorBase;
+   class ValueIterator;
+   class ValueConstIterator;
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+   class ValueAllocator;
+   class ValueMapAllocator;
+   class ValueInternalLink;
+   class ValueInternalArray;
+   class ValueInternalMap;
+#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+} // namespace Json
+
+
+#endif // JSON_FORWARDS_H_INCLUDED
diff --git a/final/lib/External/JSON/include/json/json.h b/final/lib/External/JSON/include/json/json.h
new file mode 100644
index 0000000..c71ed65
--- /dev/null
+++ b/final/lib/External/JSON/include/json/json.h
@@ -0,0 +1,10 @@
+#ifndef JSON_JSON_H_INCLUDED
+# define JSON_JSON_H_INCLUDED
+
+# include "autolink.h"
+# include "value.h"
+# include "reader.h"
+# include "writer.h"
+# include "features.h"
+
+#endif // JSON_JSON_H_INCLUDED
diff --git a/final/lib/External/JSON/include/json/reader.h b/final/lib/External/JSON/include/json/reader.h
new file mode 100644
index 0000000..0fea022
--- /dev/null
+++ b/final/lib/External/JSON/include/json/reader.h
@@ -0,0 +1,195 @@
+#ifndef CPPTL_JSON_READER_H_INCLUDED
+# define CPPTL_JSON_READER_H_INCLUDED
+
+# include "features.h"
+# include "value.h"
+# include <deque>
+# include <stack>
+# include <string>
+# include <iostream>
+
+namespace Json {
+
+   /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
+    *
+    */
+   class JSON_API Reader
+   {
+   public:
+      typedef char Char;
+      typedef const Char *Location;
+
+      /** \brief Constructs a Reader allowing all features
+       * for parsing.
+       */
+      Reader();
+
+      /** \brief Constructs a Reader allowing the specified feature set
+       * for parsing.
+       */
+      Reader( const Features &features );
+
+      /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
+       * \param document UTF-8 encoded string containing the document to read.
+       * \param root [out] Contains the root value of the document if it was
+       *             successfully parsed.
+       * \param collectComments \c true to collect comment and allow writing them back during
+       *                        serialization, \c false to discard comments.
+       *                        This parameter is ignored if Features::allowComments_
+       *                        is \c false.
+       * \return \c true if the document was successfully parsed, \c false if an error occurred.
+       */
+      bool parse( const std::string &document, 
+                  Value &root,
+                  bool collectComments = true );
+
+      /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
+       * \param root [out] Contains the root value of the document if it was
+       *             successfully parsed.
+       * \param collectComments \c true to collect comment and allow writing them back during
+       *                        serialization, \c false to discard comments.
+       *                        This parameter is ignored if Features::allowComments_
+       *                        is \c false.
+       * \return \c true if the document was successfully parsed, \c false if an error occurred.
+       */
+      bool parse( const char *beginDoc, const char *endDoc, 
+                  Value &root,
+                  bool collectComments = true );
+
+      /// \brief Parse from input stream.
+      /// \see Json::operator>>(std::istream&, Json::Value&).
+      bool parse( std::istream &is,
+                  Value &root,
+                  bool collectComments = true );
+
+      /** \brief Returns a user friendly string that list errors in the parsed document.
+       * \return Formatted error message with the list of errors with their location in 
+       *         the parsed document. An empty string is returned if no error occurred
+       *         during parsing.
+       */
+      std::string getFormatedErrorMessages() const;
+
+   private:
+      enum TokenType
+      {
+         tokenEndOfStream = 0,
+         tokenObjectBegin,
+         tokenObjectEnd,
+         tokenArrayBegin,
+         tokenArrayEnd,
+         tokenString,
+         tokenNumber,
+         tokenTrue,
+         tokenFalse,
+         tokenNull,
+         tokenArraySeparator,
+         tokenMemberSeparator,
+         tokenComment,
+         tokenError
+      };
+
+      class Token
+      {
+      public:
+         TokenType type_;
+         Location start_;
+         Location end_;
+      };
+
+      class ErrorInfo
+      {
+      public:
+         Token token_;
+         std::string message_;
+         Location extra_;
+      };
+
+      typedef std::deque<ErrorInfo> Errors;
+
+      bool expectToken( TokenType type, Token &token, const char *message );
+      bool readToken( Token &token );
+      void skipSpaces();
+      bool match( Location pattern, 
+                  int patternLength );
+      bool readComment();
+      bool readCStyleComment();
+      bool readCppStyleComment();
+      bool readString();
+      void readNumber();
+      bool readValue();
+      bool readObject( Token &token );
+      bool readArray( Token &token );
+      bool decodeNumber( Token &token );
+      bool decodeString( Token &token );
+      bool decodeString( Token &token, std::string &decoded );
+      bool decodeDouble( Token &token );
+      bool decodeUnicodeCodePoint( Token &token, 
+                                   Location &current, 
+                                   Location end, 
+                                   unsigned int &unicode );
+      bool decodeUnicodeEscapeSequence( Token &token, 
+                                        Location &current, 
+                                        Location end, 
+                                        unsigned int &unicode );
+      bool addError( const std::string &message, 
+                     Token &token,
+                     Location extra = 0 );
+      bool recoverFromError( TokenType skipUntilToken );
+      bool addErrorAndRecover( const std::string &message, 
+                               Token &token,
+                               TokenType skipUntilToken );
+      void skipUntilSpace();
+      Value &currentValue();
+      Char getNextChar();
+      void getLocationLineAndColumn( Location location,
+                                     int &line,
+                                     int &column ) const;
+      std::string getLocationLineAndColumn( Location location ) const;
+      void addComment( Location begin, 
+                       Location end, 
+                       CommentPlacement placement );
+      void skipCommentTokens( Token &token );
+   
+      typedef std::stack<Value *> Nodes;
+      Nodes nodes_;
+      Errors errors_;
+      std::string document_;
+      Location begin_;
+      Location end_;
+      Location current_;
+      Location lastValueEnd_;
+      Value *lastValue_;
+      std::string commentsBefore_;
+      Features features_;
+      bool collectComments_;
+   };
+
+   /** \brief Read from 'sin' into 'root'.
+
+    Always keep comments from the input JSON.
+
+    This can be used to read a file into a particular sub-object.
+    For example:
+    \code
+    Json::Value root;
+    cin >> root["dir"]["file"];
+    cout << root;
+    \endcode
+    Result:
+    \verbatim
+    {
+	"dir": {
+	    "file": {
+		// The input stream JSON would be nested here.
+	    }
+	}
+    }
+    \endverbatim
+    \throw std::exception on parse error.
+    \see Json::operator<<()
+   */
+   std::istream& operator>>( std::istream&, Value& );
+
+} // namespace Json
+
+#endif // CPPTL_JSON_READER_H_INCLUDED
diff --git a/final/lib/External/JSON/include/json/value.h b/final/lib/External/JSON/include/json/value.h
new file mode 100644
index 0000000..aa25e3b
--- /dev/null
+++ b/final/lib/External/JSON/include/json/value.h
@@ -0,0 +1,1069 @@
+#ifndef CPPTL_JSON_H_INCLUDED
+# define CPPTL_JSON_H_INCLUDED
+
+# include "forwards.h"
+# include <string>
+# include <vector>
+
+# ifndef JSON_USE_CPPTL_SMALLMAP
+#  include <map>
+# else
+#  include <cpptl/smallmap.h>
+# endif
+# ifdef JSON_USE_CPPTL
+#  include <cpptl/forwards.h>
+# endif
+
+/** \brief JSON (JavaScript Object Notation).
+ */
+namespace Json {
+
+   /** \brief Type of the value held by a Value object.
+    */
+   enum ValueType
+   {
+      nullValue = 0, ///< 'null' value
+      intValue,      ///< signed integer value
+      uintValue,     ///< unsigned integer value
+      realValue,     ///< double value
+      stringValue,   ///< UTF-8 string value
+      booleanValue,  ///< bool value
+      arrayValue,    ///< array value (ordered list)
+      objectValue    ///< object value (collection of name/value pairs).
+   };
+
+   enum CommentPlacement
+   {
+      commentBefore = 0,        ///< a comment placed on the line before a value
+      commentAfterOnSameLine,   ///< a comment just after a value on the same line
+      commentAfter,             ///< a comment on the line after a value (only make sense for root value)
+      numberOfCommentPlacement
+   };
+
+//# ifdef JSON_USE_CPPTL
+//   typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
+//   typedef CppTL::AnyEnumerator<const Value &> EnumValues;
+//# endif
+
+   /** \brief Lightweight wrapper to tag static string.
+    *
+    * Value constructor and objectValue member assignement takes advantage of the
+    * StaticString and avoid the cost of string duplication when storing the
+    * string or the member name.
+    *
+    * Example of usage:
+    * \code
+    * Json::Value aValue( StaticString("some text") );
+    * Json::Value object;
+    * static const StaticString code("code");
+    * object[code] = 1234;
+    * \endcode
+    */
+   class JSON_API StaticString
+   {
+   public:
+      explicit StaticString( const char *czstring )
+         : str_( czstring )
+      {
+      }
+
+      operator const char *() const
+      {
+         return str_;
+      }
+
+      const char *c_str() const
+      {
+         return str_;
+      }
+
+   private:
+      const char *str_;
+   };
+
+   /** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
+    *
+    * This class is a discriminated union wrapper that can represents a:
+    * - signed integer [range: Value::minInt - Value::maxInt]
+    * - unsigned integer (range: 0 - Value::maxUInt)
+    * - double
+    * - UTF-8 string
+    * - boolean
+    * - 'null'
+    * - an ordered list of Value
+    * - collection of name/value pairs (javascript object)
+    *
+    * The type of the held value is represented by a #ValueType and 
+    * can be obtained using type().
+    *
+    * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. 
+    * Non const methods will automatically create the a #nullValue element 
+    * if it does not exist. 
+    * The sequence of an #arrayValue will be automatically resize and initialized 
+    * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
+    *
+    * The get() methods can be used to obtanis default value in the case the required element
+    * does not exist.
+    *
+    * It is possible to iterate over the list of a #objectValue values using 
+    * the getMemberNames() method.
+    */
+   class JSON_API Value 
+   {
+      friend class ValueIteratorBase;
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+      friend class ValueInternalLink;
+      friend class ValueInternalMap;
+# endif
+   public:
+      typedef std::vector<std::string> Members;
+      typedef ValueIterator iterator;
+      typedef ValueConstIterator const_iterator;
+      typedef Json::UInt UInt;
+      typedef Json::Int Int;
+      typedef UInt ArrayIndex;
+
+      static const Value null;
+      static const Int minInt;
+      static const Int maxInt;
+      static const UInt maxUInt;
+
+   private:
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+# ifndef JSON_VALUE_USE_INTERNAL_MAP
+      class CZString 
+      {
+      public:
+         enum DuplicationPolicy 
+         {
+            noDuplication = 0,
+            duplicate,
+            duplicateOnCopy
+         };
+         CZString( int index );
+         CZString( const char *cstr, DuplicationPolicy allocate );
+         CZString( const CZString &other );
+         ~CZString();
+         CZString &operator =( const CZString &other );
+         bool operator<( const CZString &other ) const;
+         bool operator==( const CZString &other ) const;
+         int index() const;
+         const char *c_str() const;
+         bool isStaticString() const;
+      private:
+         void swap( CZString &other );
+         const char *cstr_;
+         int index_;
+      };
+
+   public:
+#  ifndef JSON_USE_CPPTL_SMALLMAP
+      typedef std::map<CZString, Value> ObjectValues;
+#  else
+      typedef CppTL::SmallMap<CZString, Value> ObjectValues;
+#  endif // ifndef JSON_USE_CPPTL_SMALLMAP
+# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+   public:
+      /** \brief Create a default Value of the given type.
+
+        This is a very useful constructor.
+        To create an empty array, pass arrayValue.
+        To create an empty object, pass objectValue.
+        Another Value can then be set to this one by assignment.
+	This is useful since clear() and resize() will not alter types.
+
+        Examples:
+	\code
+	Json::Value null_value; // null
+	Json::Value arr_value(Json::arrayValue); // []
+	Json::Value obj_value(Json::objectValue); // {}
+	\endcode
+      */
+      Value( ValueType type = nullValue );
+      Value( Int value );
+      Value( UInt value );
+      Value( double value );
+      Value( const char *value );
+      Value( const char *beginValue, const char *endValue );
+      /** \brief Constructs a value from a static string.
+
+       * Like other value string constructor but do not duplicate the string for
+       * internal storage. The given string must remain alive after the call to this
+       * constructor.
+       * Example of usage:
+       * \code
+       * Json::Value aValue( StaticString("some text") );
+       * \endcode
+       */
+      Value( const StaticString &value );
+      Value( const std::string &value );
+# ifdef JSON_USE_CPPTL
+      Value( const CppTL::ConstString &value );
+# endif
+      Value( bool value );
+      Value( const Value &other );
+      ~Value();
+
+      Value &operator=( const Value &other );
+      /// Swap values.
+      /// \note Currently, comments are intentionally not swapped, for
+      /// both logic and efficiency.
+      void swap( Value &other );
+
+      ValueType type() const;
+
+      bool operator <( const Value &other ) const;
+      bool operator <=( const Value &other ) const;
+      bool operator >=( const Value &other ) const;
+      bool operator >( const Value &other ) const;
+
+      bool operator ==( const Value &other ) const;
+      bool operator !=( const Value &other ) const;
+
+      int compare( const Value &other );
+
+      const char *asCString() const;
+      std::string asString() const;
+# ifdef JSON_USE_CPPTL
+      CppTL::ConstString asConstString() const;
+# endif
+      Int asInt() const;
+      UInt asUInt() const;
+      double asDouble() const;
+      bool asBool() const;
+
+      bool isNull() const;
+      bool isBool() const;
+      bool isInt() const;
+      bool isUInt() const;
+      bool isIntegral() const;
+      bool isDouble() const;
+      bool isNumeric() const;
+      bool isString() const;
+      bool isArray() const;
+      bool isObject() const;
+
+      bool isConvertibleTo( ValueType other ) const;
+
+      /// Number of values in array or object
+      UInt size() const;
+
+      /// \brief Return true if empty array, empty object, or null;
+      /// otherwise, false.
+      bool empty() const;
+
+      /// Return isNull()
+      bool operator!() const;
+
+      /// Remove all object members and array elements.
+      /// \pre type() is arrayValue, objectValue, or nullValue
+      /// \post type() is unchanged
+      void clear();
+
+      /// Resize the array to size elements. 
+      /// New elements are initialized to null.
+      /// May only be called on nullValue or arrayValue.
+      /// \pre type() is arrayValue or nullValue
+      /// \post type() is arrayValue
+      void resize( UInt size );
+
+      /// Access an array element (zero based index ).
+      /// If the array contains less than index element, then null value are inserted
+      /// in the array so that its size is index+1.
+      /// (You may need to say 'value[0u]' to get your compiler to distinguish
+      ///  this from the operator[] which takes a string.)
+      Value &operator[]( UInt index );
+      /// Access an array element (zero based index )
+      /// (You may need to say 'value[0u]' to get your compiler to distinguish
+      ///  this from the operator[] which takes a string.)
+      const Value &operator[]( UInt index ) const;
+      /// If the array contains at least index+1 elements, returns the element value, 
+      /// otherwise returns defaultValue.
+      Value get( UInt index, 
+                 const Value &defaultValue ) const;
+      /// Return true if index < size().
+      bool isValidIndex( UInt index ) const;
+      /// \brief Append value to array at the end.
+      ///
+      /// Equivalent to jsonvalue[jsonvalue.size()] = value;
+      Value &append( const Value &value );
+
+      /// Access an object value by name, create a null member if it does not exist.
+      Value &operator[]( const char *key );
+      /// Access an object value by name, returns null if there is no member with that name.
+      const Value &operator[]( const char *key ) const;
+      /// Access an object value by name, create a null member if it does not exist.
+      Value &operator[]( const std::string &key );
+      /// Access an object value by name, returns null if there is no member with that name.
+      const Value &operator[]( const std::string &key ) const;
+      /** \brief Access an object value by name, create a null member if it does not exist.
+
+       * If the object as no entry for that name, then the member name used to store
+       * the new entry is not duplicated.
+       * Example of use:
+       * \code
+       * Json::Value object;
+       * static const StaticString code("code");
+       * object[code] = 1234;
+       * \endcode
+       */
+      Value &operator[]( const StaticString &key );
+# ifdef JSON_USE_CPPTL
+      /// Access an object value by name, create a null member if it does not exist.
+      Value &operator[]( const CppTL::ConstString &key );
+      /// Access an object value by name, returns null if there is no member with that name.
+      const Value &operator[]( const CppTL::ConstString &key ) const;
+# endif
+      /// Return the member named key if it exist, defaultValue otherwise.
+      Value get( const char *key, 
+                 const Value &defaultValue ) const;
+      /// Return the member named key if it exist, defaultValue otherwise.
+      Value get( const std::string &key,
+                 const Value &defaultValue ) const;
+# ifdef JSON_USE_CPPTL
+      /// Return the member named key if it exist, defaultValue otherwise.
+      Value get( const CppTL::ConstString &key,
+                 const Value &defaultValue ) const;
+# endif
+      /// \brief Remove and return the named member.  
+      ///
+      /// Do nothing if it did not exist.
+      /// \return the removed Value, or null.
+      /// \pre type() is objectValue or nullValue
+      /// \post type() is unchanged
+      Value removeMember( const char* key );
+      /// Same as removeMember(const char*)
+      Value removeMember( const std::string &key );
+
+      /// Return true if the object has a member named key.
+      bool isMember( const char *key ) const;
+      /// Return true if the object has a member named key.
+      bool isMember( const std::string &key ) const;
+# ifdef JSON_USE_CPPTL
+      /// Return true if the object has a member named key.
+      bool isMember( const CppTL::ConstString &key ) const;
+# endif
+
+      /// \brief Return a list of the member names.
+      ///
+      /// If null, return an empty list.
+      /// \pre type() is objectValue or nullValue
+      /// \post if type() was nullValue, it remains nullValue
+      Members getMemberNames() const;
+
+//# ifdef JSON_USE_CPPTL
+//      EnumMemberNames enumMemberNames() const;
+//      EnumValues enumValues() const;
+//# endif
+
+      /// Comments must be //... or /* ... */
+      void setComment( const char *comment,
+                       CommentPlacement placement );
+      /// Comments must be //... or /* ... */
+      void setComment( const std::string &comment,
+                       CommentPlacement placement );
+      bool hasComment( CommentPlacement placement ) const;
+      /// Include delimiters and embedded newlines.
+      std::string getComment( CommentPlacement placement ) const;
+
+      std::string toStyledString() const;
+
+      const_iterator begin() const;
+      const_iterator end() const;
+
+      iterator begin();
+      iterator end();
+
+   private:
+      Value &resolveReference( const char *key, 
+                               bool isStatic );
+
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+      inline bool isItemAvailable() const
+      {
+         return itemIsUsed_ == 0;
+      }
+
+      inline void setItemUsed( bool isUsed = true )
+      {
+         itemIsUsed_ = isUsed ? 1 : 0;
+      }
+
+      inline bool isMemberNameStatic() const
+      {
+         return memberNameIsStatic_ == 0;
+      }
+
+      inline void setMemberNameIsStatic( bool isStatic )
+      {
+         memberNameIsStatic_ = isStatic ? 1 : 0;
+      }
+# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+   private:
+      struct CommentInfo
+      {
+         CommentInfo();
+         ~CommentInfo();
+
+         void setComment( const char *text );
+
+         char *comment_;
+      };
+
+      //struct MemberNamesTransform
+      //{
+      //   typedef const char *result_type;
+      //   const char *operator()( const CZString &name ) const
+      //   {
+      //      return name.c_str();
+      //   }
+      //};
+
+      union ValueHolder
+      {
+         Int int_;
+         UInt uint_;
+         double real_;
+         bool bool_;
+         char *string_;
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+         ValueInternalArray *array_;
+         ValueInternalMap *map_;
+#else
+         ObjectValues *map_;
+# endif
+      } value_;
+      ValueType type_ : 8;
+      int allocated_ : 1;     // Notes: if declared as bool, bitfield is useless.
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+      unsigned int itemIsUsed_ : 1;      // used by the ValueInternalMap container.
+      int memberNameIsStatic_ : 1;       // used by the ValueInternalMap container.
+# endif
+      CommentInfo *comments_;
+   };
+
+
+   /** \brief Experimental and untested: represents an element of the "path" to access a node.
+    */
+   class PathArgument
+   {
+   public:
+      friend class Path;
+
+      PathArgument();
+      PathArgument( UInt index );
+      PathArgument( const char *key );
+      PathArgument( const std::string &key );
+
+   private:
+      enum Kind
+      {
+         kindNone = 0,
+         kindIndex,
+         kindKey
+      };
+      std::string key_;
+      UInt index_;
+      Kind kind_;
+   };
+
+   /** \brief Experimental and untested: represents a "path" to access a node.
+    *
+    * Syntax:
+    * - "." => root node
+    * - ".[n]" => elements at index 'n' of root node (an array value)
+    * - ".name" => member named 'name' of root node (an object value)
+    * - ".name1.name2.name3"
+    * - ".[0][1][2].name1[3]"
+    * - ".%" => member name is provided as parameter
+    * - ".[%]" => index is provied as parameter
+    */
+   class Path
+   {
+   public:
+      Path( const std::string &path,
+            const PathArgument &a1 = PathArgument(),
+            const PathArgument &a2 = PathArgument(),
+            const PathArgument &a3 = PathArgument(),
+            const PathArgument &a4 = PathArgument(),
+            const PathArgument &a5 = PathArgument() );
+
+      const Value &resolve( const Value &root ) const;
+      Value resolve( const Value &root, 
+                     const Value &defaultValue ) const;
+      /// Creates the "path" to access the specified node and returns a reference on the node.
+      Value &make( Value &root ) const;
+
+   private:
+      typedef std::vector<const PathArgument *> InArgs;
+      typedef std::vector<PathArgument> Args;
+
+      void makePath( const std::string &path,
+                     const InArgs &in );
+      void addPathInArg( const std::string &path, 
+                         const InArgs &in, 
+                         InArgs::const_iterator &itInArg, 
+                         PathArgument::Kind kind );
+      void invalidPath( const std::string &path, 
+                        int location );
+
+      Args args_;
+   };
+
+   /** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value.
+    *
+    * - makeMemberName() and releaseMemberName() are called to respectively duplicate and
+    *   free an Json::objectValue member name.
+    * - duplicateStringValue() and releaseStringValue() are called similarly to
+    *   duplicate and free a Json::stringValue value.
+    */
+   class ValueAllocator
+   {
+   public:
+      enum { unknown = (unsigned)-1 };
+
+      virtual ~ValueAllocator();
+
+      virtual char *makeMemberName( const char *memberName ) = 0;
+      virtual void releaseMemberName( char *memberName ) = 0;
+      virtual char *duplicateStringValue( const char *value, 
+                                          unsigned int length = unknown ) = 0;
+      virtual void releaseStringValue( char *value ) = 0;
+   };
+
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+   /** \brief Allocator to customize Value internal map.
+    * Below is an example of a simple implementation (default implementation actually
+    * use memory pool for speed).
+    * \code
+      class DefaultValueMapAllocator : public ValueMapAllocator
+      {
+      public: // overridden from ValueMapAllocator
+         virtual ValueInternalMap *newMap()
+         {
+            return new ValueInternalMap();
+         }
+
+         virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+         {
+            return new ValueInternalMap( other );
+         }
+
+         virtual void destructMap( ValueInternalMap *map )
+         {
+            delete map;
+         }
+
+         virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+         {
+            return new ValueInternalLink[size];
+         }
+
+         virtual void releaseMapBuckets( ValueInternalLink *links )
+         {
+            delete [] links;
+         }
+
+         virtual ValueInternalLink *allocateMapLink()
+         {
+            return new ValueInternalLink();
+         }
+
+         virtual void releaseMapLink( ValueInternalLink *link )
+         {
+            delete link;
+         }
+      };
+    * \endcode
+    */ 
+   class JSON_API ValueMapAllocator
+   {
+   public:
+      virtual ~ValueMapAllocator();
+      virtual ValueInternalMap *newMap() = 0;
+      virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0;
+      virtual void destructMap( ValueInternalMap *map ) = 0;
+      virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0;
+      virtual void releaseMapBuckets( ValueInternalLink *links ) = 0;
+      virtual ValueInternalLink *allocateMapLink() = 0;
+      virtual void releaseMapLink( ValueInternalLink *link ) = 0;
+   };
+
+   /** \brief ValueInternalMap hash-map bucket chain link (for internal use only).
+    * \internal previous_ & next_ allows for bidirectional traversal.
+    */
+   class JSON_API ValueInternalLink
+   {
+   public:
+      enum { itemPerLink = 6 };  // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
+      enum InternalFlags { 
+         flagAvailable = 0,
+         flagUsed = 1
+      };
+
+      ValueInternalLink();
+
+      ~ValueInternalLink();
+
+      Value items_[itemPerLink];
+      char *keys_[itemPerLink];
+      ValueInternalLink *previous_;
+      ValueInternalLink *next_;
+   };
+
+
+   /** \brief A linked page based hash-table implementation used internally by Value.
+    * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked
+    * list in each bucket to handle collision. There is an additional twist in that
+    * each node of the collision linked list is a page containing a fixed amount of
+    * value. This provides a better compromise between memory usage and speed.
+    * 
+    * Each bucket is made up of a chained list of ValueInternalLink. The last
+    * link of a given bucket can be found in the 'previous_' field of the following bucket.
+    * The last link of the last bucket is stored in tailLink_ as it has no following bucket.
+    * Only the last link of a bucket may contains 'available' item. The last link always
+    * contains at least one element unless is it the bucket one very first link.
+    */
+   class JSON_API ValueInternalMap
+   {
+      friend class ValueIteratorBase;
+      friend class Value;
+   public:
+      typedef unsigned int HashKey;
+      typedef unsigned int BucketIndex;
+
+# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+      struct IteratorState
+      {
+         IteratorState() 
+            : map_(0)
+            , link_(0)
+            , itemIndex_(0)
+            , bucketIndex_(0) 
+         {
+         }
+         ValueInternalMap *map_;
+         ValueInternalLink *link_;
+         BucketIndex itemIndex_;
+         BucketIndex bucketIndex_;
+      };
+# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+      ValueInternalMap();
+      ValueInternalMap( const ValueInternalMap &other );
+      ValueInternalMap &operator =( const ValueInternalMap &other );
+      ~ValueInternalMap();
+
+      void swap( ValueInternalMap &other );
+
+      BucketIndex size() const;
+
+      void clear();
+
+      bool reserveDelta( BucketIndex growth );
+
+      bool reserve( BucketIndex newItemCount );
+
+      const Value *find( const char *key ) const;
+
+      Value *find( const char *key );
+
+      Value &resolveReference( const char *key, 
+                               bool isStatic );
+
+      void remove( const char *key );
+
+      void doActualRemove( ValueInternalLink *link, 
+                           BucketIndex index,
+                           BucketIndex bucketIndex );
+
+      ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex );
+
+      Value &setNewItem( const char *key, 
+                         bool isStatic, 
+                         ValueInternalLink *link, 
+                         BucketIndex index );
+
+      Value &unsafeAdd( const char *key, 
+                        bool isStatic, 
+                        HashKey hashedKey );
+
+      HashKey hash( const char *key ) const;
+
+      int compare( const ValueInternalMap &other ) const;
+
+   private:
+      void makeBeginIterator( IteratorState &it ) const;
+      void makeEndIterator( IteratorState &it ) const;
+      static bool equals( const IteratorState &x, const IteratorState &other );
+      static void increment( IteratorState &iterator );
+      static void incrementBucket( IteratorState &iterator );
+      static void decrement( IteratorState &iterator );
+      static const char *key( const IteratorState &iterator );
+      static const char *key( const IteratorState &iterator, bool &isStatic );
+      static Value &value( const IteratorState &iterator );
+      static int distance( const IteratorState &x, const IteratorState &y );
+
+   private:
+      ValueInternalLink *buckets_;
+      ValueInternalLink *tailLink_;
+      BucketIndex bucketsSize_;
+      BucketIndex itemCount_;
+   };
+
+   /** \brief A simplified deque implementation used internally by Value.
+   * \internal
+   * It is based on a list of fixed "page", each page contains a fixed number of items.
+   * Instead of using a linked-list, a array of pointer is used for fast item look-up.
+   * Look-up for an element is as follow:
+   * - compute page index: pageIndex = itemIndex / itemsPerPage
+   * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]
+   *
+   * Insertion is amortized constant time (only the array containing the index of pointers
+   * need to be reallocated when items are appended).
+   */
+   class JSON_API ValueInternalArray
+   {
+      friend class Value;
+      friend class ValueIteratorBase;
+   public:
+      enum { itemsPerPage = 8 };    // should be a power of 2 for fast divide and modulo.
+      typedef Value::ArrayIndex ArrayIndex;
+      typedef unsigned int PageIndex;
+
+# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+      struct IteratorState // Must be a POD
+      {
+         IteratorState() 
+            : array_(0)
+            , currentPageIndex_(0)
+            , currentItemIndex_(0) 
+         {
+         }
+         ValueInternalArray *array_;
+         Value **currentPageIndex_;
+         unsigned int currentItemIndex_;
+      };
+# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+      ValueInternalArray();
+      ValueInternalArray( const ValueInternalArray &other );
+      ValueInternalArray &operator =( const ValueInternalArray &other );
+      ~ValueInternalArray();
+      void swap( ValueInternalArray &other );
+
+      void clear();
+      void resize( ArrayIndex newSize );
+
+      Value &resolveReference( ArrayIndex index );
+
+      Value *find( ArrayIndex index ) const;
+
+      ArrayIndex size() const;
+
+      int compare( const ValueInternalArray &other ) const;
+
+   private:
+      static bool equals( const IteratorState &x, const IteratorState &other );
+      static void increment( IteratorState &iterator );
+      static void decrement( IteratorState &iterator );
+      static Value &dereference( const IteratorState &iterator );
+      static Value &unsafeDereference( const IteratorState &iterator );
+      static int distance( const IteratorState &x, const IteratorState &y );
+      static ArrayIndex indexOf( const IteratorState &iterator );
+      void makeBeginIterator( IteratorState &it ) const;
+      void makeEndIterator( IteratorState &it ) const;
+      void makeIterator( IteratorState &it, ArrayIndex index ) const;
+
+      void makeIndexValid( ArrayIndex index );
+
+      Value **pages_;
+      ArrayIndex size_;
+      PageIndex pageCount_;
+   };
+
+   /** \brief Experimental: do not use. Allocator to customize Value internal array.
+    * Below is an example of a simple implementation (actual implementation use
+    * memory pool).
+      \code
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+   virtual ~DefaultValueArrayAllocator()
+   {
+   }
+
+   virtual ValueInternalArray *newArray()
+   {
+      return new ValueInternalArray();
+   }
+
+   virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+   {
+      return new ValueInternalArray( other );
+   }
+
+   virtual void destruct( ValueInternalArray *array )
+   {
+      delete array;
+   }
+
+   virtual void reallocateArrayPageIndex( Value **&indexes, 
+                                          ValueInternalArray::PageIndex &indexCount,
+                                          ValueInternalArray::PageIndex minNewIndexCount )
+   {
+      ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+      if ( minNewIndexCount > newIndexCount )
+         newIndexCount = minNewIndexCount;
+      void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+      if ( !newIndexes )
+         throw std::bad_alloc();
+      indexCount = newIndexCount;
+      indexes = static_cast<Value **>( newIndexes );
+   }
+   virtual void releaseArrayPageIndex( Value **indexes, 
+                                       ValueInternalArray::PageIndex indexCount )
+   {
+      if ( indexes )
+         free( indexes );
+   }
+
+   virtual Value *allocateArrayPage()
+   {
+      return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
+   }
+
+   virtual void releaseArrayPage( Value *value )
+   {
+      if ( value )
+         free( value );
+   }
+};
+      \endcode
+    */ 
+   class JSON_API ValueArrayAllocator
+   {
+   public:
+      virtual ~ValueArrayAllocator();
+      virtual ValueInternalArray *newArray() = 0;
+      virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0;
+      virtual void destructArray( ValueInternalArray *array ) = 0;
+      /** \brief Reallocate array page index.
+       * Reallocates an array of pointer on each page.
+       * \param indexes [input] pointer on the current index. May be \c NULL.
+       *                [output] pointer on the new index of at least 
+       *                         \a minNewIndexCount pages. 
+       * \param indexCount [input] current number of pages in the index.
+       *                   [output] number of page the reallocated index can handle.
+       *                            \b MUST be >= \a minNewIndexCount.
+       * \param minNewIndexCount Minimum number of page the new index must be able to
+       *                         handle.
+       */
+      virtual void reallocateArrayPageIndex( Value **&indexes, 
+                                             ValueInternalArray::PageIndex &indexCount,
+                                             ValueInternalArray::PageIndex minNewIndexCount ) = 0;
+      virtual void releaseArrayPageIndex( Value **indexes, 
+                                          ValueInternalArray::PageIndex indexCount ) = 0;
+      virtual Value *allocateArrayPage() = 0;
+      virtual void releaseArrayPage( Value *value ) = 0;
+   };
+#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+
+   /** \brief base class for Value iterators.
+    *
+    */
+   class ValueIteratorBase
+   {
+   public:
+      typedef unsigned int size_t;
+      typedef int difference_type;
+      typedef ValueIteratorBase SelfType;
+
+      ValueIteratorBase();
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+      explicit ValueIteratorBase( const Value::ObjectValues::iterator &current );
+#else
+      ValueIteratorBase( const ValueInternalArray::IteratorState &state );
+      ValueIteratorBase( const ValueInternalMap::IteratorState &state );
+#endif
+
+      bool operator ==( const SelfType &other ) const
+      {
+         return isEqual( other );
+      }
+
+      bool operator !=( const SelfType &other ) const
+      {
+         return !isEqual( other );
+      }
+
+      difference_type operator -( const SelfType &other ) const
+      {
+         return computeDistance( other );
+      }
+
+      /// Return either the index or the member name of the referenced value as a Value.
+      Value key() const;
+
+      /// Return the index of the referenced Value. -1 if it is not an arrayValue.
+      UInt index() const;
+
+      /// Return the member name of the referenced Value. "" if it is not an objectValue.
+      const char *memberName() const;
+
+   protected:
+      Value &deref() const;
+
+      void increment();
+
+      void decrement();
+
+      difference_type computeDistance( const SelfType &other ) const;
+
+      bool isEqual( const SelfType &other ) const;
+
+      void copy( const SelfType &other );
+
+   private:
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+      Value::ObjectValues::iterator current_;
+      // Indicates that iterator is for a null value.
+      bool isNull_;
+#else
+      union
+      {
+         ValueInternalArray::IteratorState array_;
+         ValueInternalMap::IteratorState map_;
+      } iterator_;
+      bool isArray_;
+#endif
+   };
+
+   /** \brief const iterator for object and array value.
+    *
+    */
+   class ValueConstIterator : public ValueIteratorBase
+   {
+      friend class Value;
+   public:
+      typedef unsigned int size_t;
+      typedef int difference_type;
+      typedef const Value &reference;
+      typedef const Value *pointer;
+      typedef ValueConstIterator SelfType;
+
+      ValueConstIterator();
+   private:
+      /*! \internal Use by Value to create an iterator.
+       */
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+      explicit ValueConstIterator( const Value::ObjectValues::iterator &current );
+#else
+      ValueConstIterator( const ValueInternalArray::IteratorState &state );
+      ValueConstIterator( const ValueInternalMap::IteratorState &state );
+#endif
+   public:
+      SelfType &operator =( const ValueIteratorBase &other );
+
+      SelfType operator++( int )
+      {
+         SelfType temp( *this );
+         ++*this;
+         return temp;
+      }
+
+      SelfType operator--( int )
+      {
+         SelfType temp( *this );
+         --*this;
+         return temp;
+      }
+
+      SelfType &operator--()
+      {
+         decrement();
+         return *this;
+      }
+
+      SelfType &operator++()
+      {
+         increment();
+         return *this;
+      }
+
+      reference operator *() const
+      {
+         return deref();
+      }
+   };
+
+
+   /** \brief Iterator for object and array value.
+    */
+   class ValueIterator : public ValueIteratorBase
+   {
+      friend class Value;
+   public:
+      typedef unsigned int size_t;
+      typedef int difference_type;
+      typedef Value &reference;
+      typedef Value *pointer;
+      typedef ValueIterator SelfType;
+
+      ValueIterator();
+      ValueIterator( const ValueConstIterator &other );
+      ValueIterator( const ValueIterator &other );
+   private:
+      /*! \internal Use by Value to create an iterator.
+       */
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+      explicit ValueIterator( const Value::ObjectValues::iterator &current );
+#else
+      ValueIterator( const ValueInternalArray::IteratorState &state );
+      ValueIterator( const ValueInternalMap::IteratorState &state );
+#endif
+   public:
+
+      SelfType &operator =( const SelfType &other );
+
+      SelfType operator++( int )
+      {
+         SelfType temp( *this );
+         ++*this;
+         return temp;
+      }
+
+      SelfType operator--( int )
+      {
+         SelfType temp( *this );
+         --*this;
+         return temp;
+      }
+
+      SelfType &operator--()
+      {
+         decrement();
+         return *this;
+      }
+
+      SelfType &operator++()
+      {
+         increment();
+         return *this;
+      }
+
+      reference operator *() const
+      {
+         return deref();
+      }
+   };
+
+
+} // namespace Json
+
+
+#endif // CPPTL_JSON_H_INCLUDED
diff --git a/final/lib/External/JSON/include/json/writer.h b/final/lib/External/JSON/include/json/writer.h
new file mode 100644
index 0000000..83def71
--- /dev/null
+++ b/final/lib/External/JSON/include/json/writer.h
@@ -0,0 +1,173 @@
+#ifndef JSON_WRITER_H_INCLUDED
+# define JSON_WRITER_H_INCLUDED
+
+# include "value.h"
+# include <vector>
+# include <string>
+# include <iostream>
+
+namespace Json {
+
+   class Value;
+
+   /** \brief Abstract class for writers.
+    */
+   class JSON_API Writer
+   {
+   public:
+      virtual ~Writer();
+
+      virtual std::string write( const Value &root ) = 0;
+   };
+
+   /** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
+    *
+    * The JSON document is written in a single line. It is not intended for 'human' consumption,
+    * but may be useful to support feature such as RPC where bandwidth is limited.
+    * \sa Reader, Value
+    */
+   class JSON_API FastWriter : public Writer
+   {
+   public:
+      FastWriter();
+      virtual ~FastWriter(){}
+
+      void enableYAMLCompatibility();
+
+   public: // overridden from Writer
+      virtual std::string write( const Value &root );
+
+   private:
+      void writeValue( const Value &value );
+
+      std::string document_;
+      bool yamlCompatiblityEnabled_;
+   };
+
+   /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
+    *
+    * The rules for line break and indent are as follow:
+    * - Object value:
+    *     - if empty then print {} without indent and line break
+    *     - if not empty the print '{', line break & indent, print one value per line
+    *       and then unindent and line break and print '}'.
+    * - Array value:
+    *     - if empty then print [] without indent and line break
+    *     - if the array contains no object value, empty array or some other value types,
+    *       and all the values fit on one lines, then print the array on a single line.
+    *     - otherwise, it the values do not fit on one line, or the array contains
+    *       object or non empty array, then print one value per line.
+    *
+    * If the Value have comments then they are outputed according to their #CommentPlacement.
+    *
+    * \sa Reader, Value, Value::setComment()
+    */
+   class JSON_API StyledWriter: public Writer
+   {
+   public:
+      StyledWriter();
+      virtual ~StyledWriter(){}
+
+   public: // overridden from Writer
+      /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+       * \param root Value to serialize.
+       * \return String containing the JSON document that represents the root value.
+       */
+      virtual std::string write( const Value &root );
+
+   private:
+      void writeValue( const Value &value );
+      void writeArrayValue( const Value &value );
+      bool isMultineArray( const Value &value );
+      void pushValue( const std::string &value );
+      void writeIndent();
+      void writeWithIndent( const std::string &value );
+      void indent();
+      void unindent();
+      void writeCommentBeforeValue( const Value &root );
+      void writeCommentAfterValueOnSameLine( const Value &root );
+      bool hasCommentForValue( const Value &value );
+      static std::string normalizeEOL( const std::string &text );
+
+      typedef std::vector<std::string> ChildValues;
+
+      ChildValues childValues_;
+      std::string document_;
+      std::string indentString_;
+      int rightMargin_;
+      int indentSize_;
+      bool addChildValues_;
+   };
+
+   /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
+        to a stream rather than to a string.
+    *
+    * The rules for line break and indent are as follow:
+    * - Object value:
+    *     - if empty then print {} without indent and line break
+    *     - if not empty the print '{', line break & indent, print one value per line
+    *       and then unindent and line break and print '}'.
+    * - Array value:
+    *     - if empty then print [] without indent and line break
+    *     - if the array contains no object value, empty array or some other value types,
+    *       and all the values fit on one lines, then print the array on a single line.
+    *     - otherwise, it the values do not fit on one line, or the array contains
+    *       object or non empty array, then print one value per line.
+    *
+    * If the Value have comments then they are outputed according to their #CommentPlacement.
+    *
+    * \sa Reader, Value, Value::setComment()
+    */
+   class JSON_API StyledStreamWriter
+   {
+   public:
+      StyledStreamWriter( std::string indentation="\t" );
+      ~StyledStreamWriter(){}
+
+   public:
+      /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+       * \param out Stream to write to. (Can be ostringstream, e.g.)
+       * \param root Value to serialize.
+       * \note There is no point in deriving from Writer, since write() should not return a value.
+       */
+      void write( std::ostream &out, const Value &root );
+
+   private:
+      void writeValue( const Value &value );
+      void writeArrayValue( const Value &value );
+      bool isMultineArray( const Value &value );
+      void pushValue( const std::string &value );
+      void writeIndent();
+      void writeWithIndent( const std::string &value );
+      void indent();
+      void unindent();
+      void writeCommentBeforeValue( const Value &root );
+      void writeCommentAfterValueOnSameLine( const Value &root );
+      bool hasCommentForValue( const Value &value );
+      static std::string normalizeEOL( const std::string &text );
+
+      typedef std::vector<std::string> ChildValues;
+
+      ChildValues childValues_;
+      std::ostream* document_;
+      std::string indentString_;
+      int rightMargin_;
+      std::string indentation_;
+      bool addChildValues_;
+   };
+
+   std::string JSON_API valueToString( Int value );
+   std::string JSON_API valueToString( UInt value );
+   std::string JSON_API valueToString( double value );
+   std::string JSON_API valueToString( bool value );
+   std::string JSON_API valueToQuotedString( const char *value );
+
+   /// \brief Output using the StyledStreamWriter.
+   /// \see Json::operator>>()
+   std::ostream& operator<<( std::ostream&, const Value &root );
+
+} // namespace Json
+
+
+
+#endif // JSON_WRITER_H_INCLUDED
diff --git a/final/lib/External/JSON/json_batchallocator.h b/final/lib/External/JSON/json_batchallocator.h
new file mode 100644
index 0000000..87ea5ed
--- /dev/null
+++ b/final/lib/External/JSON/json_batchallocator.h
@@ -0,0 +1,125 @@
+#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
+# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
+
+# include <stdlib.h>
+# include <assert.h>
+
+# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+namespace Json {
+
+/* Fast memory allocator.
+ *
+ * This memory allocator allocates memory for a batch of object (specified by
+ * the page size, the number of object in each page).
+ *
+ * It does not allow the destruction of a single object. All the allocated objects
+ * can be destroyed at once. The memory can be either released or reused for future
+ * allocation.
+ * 
+ * The in-place new operator must be used to construct the object using the pointer
+ * returned by allocate.
+ */
+template<typename AllocatedType
+        ,const unsigned int objectPerAllocation>
+class BatchAllocator
+{
+public:
+   typedef AllocatedType Type;
+
+   BatchAllocator( unsigned int objectsPerPage = 255 )
+      : freeHead_( 0 )
+      , objectsPerPage_( objectsPerPage )
+   {
+//      printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
+      assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
+      assert( objectsPerPage >= 16 );
+      batches_ = allocateBatch( 0 );   // allocated a dummy page
+      currentBatch_ = batches_;
+   }
+
+   ~BatchAllocator()
+   {
+      for ( BatchInfo *batch = batches_; batch;  )
+      {
+         BatchInfo *nextBatch = batch->next_;
+         free( batch );
+         batch = nextBatch;
+      }
+   }
+
+   /// allocate space for an array of objectPerAllocation object.
+   /// @warning it is the responsability of the caller to call objects constructors.
+   AllocatedType *allocate()
+   {
+      if ( freeHead_ ) // returns node from free list.
+      {
+         AllocatedType *object = freeHead_;
+         freeHead_ = *(AllocatedType **)object;
+         return object;
+      }
+      if ( currentBatch_->used_ == currentBatch_->end_ )
+      {
+         currentBatch_ = currentBatch_->next_;
+         while ( currentBatch_  &&  currentBatch_->used_ == currentBatch_->end_ )
+            currentBatch_ = currentBatch_->next_;
+
+         if ( !currentBatch_  ) // no free batch found, allocate a new one
+         { 
+            currentBatch_ = allocateBatch( objectsPerPage_ );
+            currentBatch_->next_ = batches_; // insert at the head of the list
+            batches_ = currentBatch_;
+         }
+      }
+      AllocatedType *allocated = currentBatch_->used_;
+      currentBatch_->used_ += objectPerAllocation;
+      return allocated;
+   }
+
+   /// Release the object.
+   /// @warning it is the responsability of the caller to actually destruct the object.
+   void release( AllocatedType *object )
+   {
+      assert( object != 0 );
+      *(AllocatedType **)object = freeHead_;
+      freeHead_ = object;
+   }
+
+private:
+   struct BatchInfo
+   {
+      BatchInfo *next_;
+      AllocatedType *used_;
+      AllocatedType *end_;
+      AllocatedType buffer_[objectPerAllocation];
+   };
+
+   // disabled copy constructor and assignement operator.
+   BatchAllocator( const BatchAllocator & );
+   void operator =( const BatchAllocator &);
+
+   static BatchInfo *allocateBatch( unsigned int objectsPerPage )
+   {
+      const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
+                                + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
+      BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
+      batch->next_ = 0;
+      batch->used_ = batch->buffer_;
+      batch->end_ = batch->buffer_ + objectsPerPage;
+      return batch;
+   }
+
+   BatchInfo *batches_;
+   BatchInfo *currentBatch_;
+   /// Head of a single linked list within the allocated space of freeed object
+   AllocatedType *freeHead_;
+   unsigned int objectsPerPage_;
+};
+
+
+} // namespace Json
+
+# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
+
+#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
+
diff --git a/final/lib/External/JSON/json_internalarray.inl b/final/lib/External/JSON/json_internalarray.inl
new file mode 100644
index 0000000..9b985d2
--- /dev/null
+++ b/final/lib/External/JSON/json_internalarray.inl
@@ -0,0 +1,448 @@
+// included by json_value.cpp
+// everything is within Json namespace
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalArray
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueArrayAllocator::~ValueArrayAllocator()
+{
+}
+
+// //////////////////////////////////////////////////////////////////
+// class DefaultValueArrayAllocator
+// //////////////////////////////////////////////////////////////////
+#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+   virtual ~DefaultValueArrayAllocator()
+   {
+   }
+
+   virtual ValueInternalArray *newArray()
+   {
+      return new ValueInternalArray();
+   }
+
+   virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+   {
+      return new ValueInternalArray( other );
+   }
+
+   virtual void destructArray( ValueInternalArray *array )
+   {
+      delete array;
+   }
+
+   virtual void reallocateArrayPageIndex( Value **&indexes, 
+                                          ValueInternalArray::PageIndex &indexCount,
+                                          ValueInternalArray::PageIndex minNewIndexCount )
+   {
+      ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+      if ( minNewIndexCount > newIndexCount )
+         newIndexCount = minNewIndexCount;
+      void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+      if ( !newIndexes )
+         throw std::bad_alloc();
+      indexCount = newIndexCount;
+      indexes = static_cast<Value **>( newIndexes );
+   }
+   virtual void releaseArrayPageIndex( Value **indexes, 
+                                       ValueInternalArray::PageIndex indexCount )
+   {
+      if ( indexes )
+         free( indexes );
+   }
+
+   virtual Value *allocateArrayPage()
+   {
+      return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
+   }
+
+   virtual void releaseArrayPage( Value *value )
+   {
+      if ( value )
+         free( value );
+   }
+};
+
+#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+/// @todo make this thread-safe (lock when accessign batch allocator)
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+   virtual ~DefaultValueArrayAllocator()
+   {
+   }
+
+   virtual ValueInternalArray *newArray()
+   {
+      ValueInternalArray *array = arraysAllocator_.allocate();
+      new (array) ValueInternalArray(); // placement new
+      return array;
+   }
+
+   virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+   {
+      ValueInternalArray *array = arraysAllocator_.allocate();
+      new (array) ValueInternalArray( other ); // placement new
+      return array;
+   }
+
+   virtual void destructArray( ValueInternalArray *array )
+   {
+      if ( array )
+      {
+         array->~ValueInternalArray();
+         arraysAllocator_.release( array );
+      }
+   }
+
+   virtual void reallocateArrayPageIndex( Value **&indexes, 
+                                          ValueInternalArray::PageIndex &indexCount,
+                                          ValueInternalArray::PageIndex minNewIndexCount )
+   {
+      ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+      if ( minNewIndexCount > newIndexCount )
+         newIndexCount = minNewIndexCount;
+      void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+      if ( !newIndexes )
+         throw std::bad_alloc();
+      indexCount = newIndexCount;
+      indexes = static_cast<Value **>( newIndexes );
+   }
+   virtual void releaseArrayPageIndex( Value **indexes, 
+                                       ValueInternalArray::PageIndex indexCount )
+   {
+      if ( indexes )
+         free( indexes );
+   }
+
+   virtual Value *allocateArrayPage()
+   {
+      return static_cast<Value *>( pagesAllocator_.allocate() );
+   }
+
+   virtual void releaseArrayPage( Value *value )
+   {
+      if ( value )
+         pagesAllocator_.release( value );
+   }
+private:
+   BatchAllocator<ValueInternalArray,1> arraysAllocator_;
+   BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_;
+};
+#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+
+static ValueArrayAllocator *&arrayAllocator()
+{
+   static DefaultValueArrayAllocator defaultAllocator;
+   static ValueArrayAllocator *arrayAllocator = &defaultAllocator;
+   return arrayAllocator;
+}
+
+static struct DummyArrayAllocatorInitializer {
+   DummyArrayAllocatorInitializer() 
+   {
+      arrayAllocator();      // ensure arrayAllocator() statics are initialized before main().
+   }
+} dummyArrayAllocatorInitializer;
+
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalArray
+// //////////////////////////////////////////////////////////////////
+bool 
+ValueInternalArray::equals( const IteratorState &x, 
+                            const IteratorState &other )
+{
+   return x.array_ == other.array_  
+          &&  x.currentItemIndex_ == other.currentItemIndex_  
+          &&  x.currentPageIndex_ == other.currentPageIndex_;
+}
+
+
+void 
+ValueInternalArray::increment( IteratorState &it )
+{
+   JSON_ASSERT_MESSAGE( it.array_  &&
+      (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
+      != it.array_->size_,
+      "ValueInternalArray::increment(): moving iterator beyond end" );
+   ++(it.currentItemIndex_);
+   if ( it.currentItemIndex_ == itemsPerPage )
+   {
+      it.currentItemIndex_ = 0;
+      ++(it.currentPageIndex_);
+   }
+}
+
+
+void 
+ValueInternalArray::decrement( IteratorState &it )
+{
+   JSON_ASSERT_MESSAGE( it.array_  &&  it.currentPageIndex_ == it.array_->pages_ 
+                        &&  it.currentItemIndex_ == 0,
+      "ValueInternalArray::decrement(): moving iterator beyond end" );
+   if ( it.currentItemIndex_ == 0 )
+   {
+      it.currentItemIndex_ = itemsPerPage-1;
+      --(it.currentPageIndex_);
+   }
+   else
+   {
+      --(it.currentItemIndex_);
+   }
+}
+
+
+Value &
+ValueInternalArray::unsafeDereference( const IteratorState &it )
+{
+   return (*(it.currentPageIndex_))[it.currentItemIndex_];
+}
+
+
+Value &
+ValueInternalArray::dereference( const IteratorState &it )
+{
+   JSON_ASSERT_MESSAGE( it.array_  &&
+      (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
+      < it.array_->size_,
+      "ValueInternalArray::dereference(): dereferencing invalid iterator" );
+   return unsafeDereference( it );
+}
+
+void 
+ValueInternalArray::makeBeginIterator( IteratorState &it ) const
+{
+   it.array_ = const_cast<ValueInternalArray *>( this );
+   it.currentItemIndex_ = 0;
+   it.currentPageIndex_ = pages_;
+}
+
+
+void 
+ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const
+{
+   it.array_ = const_cast<ValueInternalArray *>( this );
+   it.currentItemIndex_ = index % itemsPerPage;
+   it.currentPageIndex_ = pages_ + index / itemsPerPage;
+}
+
+
+void 
+ValueInternalArray::makeEndIterator( IteratorState &it ) const
+{
+   makeIterator( it, size_ );
+}
+
+
+ValueInternalArray::ValueInternalArray()
+   : pages_( 0 )
+   , size_( 0 )
+   , pageCount_( 0 )
+{
+}
+
+
+ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
+   : pages_( 0 )
+   , pageCount_( 0 )
+   , size_( other.size_ )
+{
+   PageIndex minNewPages = other.size_ / itemsPerPage;
+   arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
+   JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, 
+                        "ValueInternalArray::reserve(): bad reallocation" );
+   IteratorState itOther;
+   other.makeBeginIterator( itOther );
+   Value *value;
+   for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) )
+   {
+      if ( index % itemsPerPage == 0 )
+      {
+         PageIndex pageIndex = index / itemsPerPage;
+         value = arrayAllocator()->allocateArrayPage();
+         pages_[pageIndex] = value;
+      }
+      new (value) Value( dereference( itOther ) );
+   }
+}
+
+
+ValueInternalArray &
+ValueInternalArray::operator =( const ValueInternalArray &other )
+{
+   ValueInternalArray temp( other );
+   swap( temp );
+   return *this;
+}
+
+
+ValueInternalArray::~ValueInternalArray()
+{
+   // destroy all constructed items
+   IteratorState it;
+   IteratorState itEnd;
+   makeBeginIterator( it);
+   makeEndIterator( itEnd );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      Value *value = &dereference(it);
+      value->~Value();
+   }
+   // release all pages
+   PageIndex lastPageIndex = size_ / itemsPerPage;
+   for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )
+      arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
+   // release pages index
+   arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ );
+}
+
+
+void 
+ValueInternalArray::swap( ValueInternalArray &other )
+{
+   Value **tempPages = pages_;
+   pages_ = other.pages_;
+   other.pages_ = tempPages;
+   ArrayIndex tempSize = size_;
+   size_ = other.size_;
+   other.size_ = tempSize;
+   PageIndex tempPageCount = pageCount_;
+   pageCount_ = other.pageCount_;
+   other.pageCount_ = tempPageCount;
+}
+
+void 
+ValueInternalArray::clear()
+{
+   ValueInternalArray dummy;
+   swap( dummy );
+}
+
+
+void 
+ValueInternalArray::resize( ArrayIndex newSize )
+{
+   if ( newSize == 0 )
+      clear();
+   else if ( newSize < size_ )
+   {
+      IteratorState it;
+      IteratorState itEnd;
+      makeIterator( it, newSize );
+      makeIterator( itEnd, size_ );
+      for ( ; !equals(it,itEnd); increment(it) )
+      {
+         Value *value = &dereference(it);
+         value->~Value();
+      }
+      PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
+      PageIndex lastPageIndex = size_ / itemsPerPage;
+      for ( ; pageIndex < lastPageIndex; ++pageIndex )
+         arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
+      size_ = newSize;
+   }
+   else if ( newSize > size_ )
+      resolveReference( newSize );
+}
+
+
+void 
+ValueInternalArray::makeIndexValid( ArrayIndex index )
+{
+   // Need to enlarge page index ?
+   if ( index >= pageCount_ * itemsPerPage )
+   {
+      PageIndex minNewPages = (index + 1) / itemsPerPage;
+      arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
+      JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" );
+   }
+
+   // Need to allocate new pages ?
+   ArrayIndex nextPageIndex = 
+      (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage
+                                  : size_;
+   if ( nextPageIndex <= index )
+   {
+      PageIndex pageIndex = nextPageIndex / itemsPerPage;
+      PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
+      for ( ; pageToAllocate-- > 0; ++pageIndex )
+         pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
+   }
+
+   // Initialize all new entries
+   IteratorState it;
+   IteratorState itEnd;
+   makeIterator( it, size_ );
+   size_ = index + 1;
+   makeIterator( itEnd, size_ );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      Value *value = &dereference(it);
+      new (value) Value(); // Construct a default value using placement new
+   }
+}
+
+Value &
+ValueInternalArray::resolveReference( ArrayIndex index )
+{
+   if ( index >= size_ )
+      makeIndexValid( index );
+   return pages_[index/itemsPerPage][index%itemsPerPage];
+}
+
+Value *
+ValueInternalArray::find( ArrayIndex index ) const
+{
+   if ( index >= size_ )
+      return 0;
+   return &(pages_[index/itemsPerPage][index%itemsPerPage]);
+}
+
+ValueInternalArray::ArrayIndex 
+ValueInternalArray::size() const
+{
+   return size_;
+}
+
+int 
+ValueInternalArray::distance( const IteratorState &x, const IteratorState &y )
+{
+   return indexOf(y) - indexOf(x);
+}
+
+
+ValueInternalArray::ArrayIndex 
+ValueInternalArray::indexOf( const IteratorState &iterator )
+{
+   if ( !iterator.array_ )
+      return ArrayIndex(-1);
+   return ArrayIndex(
+      (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage 
+      + iterator.currentItemIndex_ );
+}
+
+
+int 
+ValueInternalArray::compare( const ValueInternalArray &other ) const
+{
+   int sizeDiff( size_ - other.size_ );
+   if ( sizeDiff != 0 )
+      return sizeDiff;
+   
+   for ( ArrayIndex index =0; index < size_; ++index )
+   {
+      int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare( 
+         other.pages_[index/itemsPerPage][index%itemsPerPage] );
+      if ( diff != 0 )
+         return diff;
+   }
+   return 0;
+}
diff --git a/final/lib/External/JSON/json_internalmap.inl b/final/lib/External/JSON/json_internalmap.inl
new file mode 100644
index 0000000..1977148
--- /dev/null
+++ b/final/lib/External/JSON/json_internalmap.inl
@@ -0,0 +1,607 @@
+// included by json_value.cpp
+// everything is within Json namespace
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalMap
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
+   * This optimization is used by the fast allocator.
+   */
+ValueInternalLink::ValueInternalLink()
+   : previous_( 0 )
+   , next_( 0 )
+{
+}
+
+ValueInternalLink::~ValueInternalLink()
+{ 
+   for ( int index =0; index < itemPerLink; ++index )
+   {
+      if ( !items_[index].isItemAvailable() )
+      {
+         if ( !items_[index].isMemberNameStatic() )
+            free( keys_[index] );
+      }
+      else
+         break;
+   }
+}
+
+
+
+ValueMapAllocator::~ValueMapAllocator()
+{
+}
+
+#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+class DefaultValueMapAllocator : public ValueMapAllocator
+{
+public: // overridden from ValueMapAllocator
+   virtual ValueInternalMap *newMap()
+   {
+      return new ValueInternalMap();
+   }
+
+   virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+   {
+      return new ValueInternalMap( other );
+   }
+
+   virtual void destructMap( ValueInternalMap *map )
+   {
+      delete map;
+   }
+
+   virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+   {
+      return new ValueInternalLink[size];
+   }
+
+   virtual void releaseMapBuckets( ValueInternalLink *links )
+   {
+      delete [] links;
+   }
+
+   virtual ValueInternalLink *allocateMapLink()
+   {
+      return new ValueInternalLink();
+   }
+
+   virtual void releaseMapLink( ValueInternalLink *link )
+   {
+      delete link;
+   }
+};
+#else
+/// @todo make this thread-safe (lock when accessign batch allocator)
+class DefaultValueMapAllocator : public ValueMapAllocator
+{
+public: // overridden from ValueMapAllocator
+   virtual ValueInternalMap *newMap()
+   {
+      ValueInternalMap *map = mapsAllocator_.allocate();
+      new (map) ValueInternalMap(); // placement new
+      return map;
+   }
+
+   virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+   {
+      ValueInternalMap *map = mapsAllocator_.allocate();
+      new (map) ValueInternalMap( other ); // placement new
+      return map;
+   }
+
+   virtual void destructMap( ValueInternalMap *map )
+   {
+      if ( map )
+      {
+         map->~ValueInternalMap();
+         mapsAllocator_.release( map );
+      }
+   }
+
+   virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+   {
+      return new ValueInternalLink[size];
+   }
+
+   virtual void releaseMapBuckets( ValueInternalLink *links )
+   {
+      delete [] links;
+   }
+
+   virtual ValueInternalLink *allocateMapLink()
+   {
+      ValueInternalLink *link = linksAllocator_.allocate();
+      memset( link, 0, sizeof(ValueInternalLink) );
+      return link;
+   }
+
+   virtual void releaseMapLink( ValueInternalLink *link )
+   {
+      link->~ValueInternalLink();
+      linksAllocator_.release( link );
+   }
+private:
+   BatchAllocator<ValueInternalMap,1> mapsAllocator_;
+   BatchAllocator<ValueInternalLink,1> linksAllocator_;
+};
+#endif
+
+static ValueMapAllocator *&mapAllocator()
+{
+   static DefaultValueMapAllocator defaultAllocator;
+   static ValueMapAllocator *mapAllocator = &defaultAllocator;
+   return mapAllocator;
+}
+
+static struct DummyMapAllocatorInitializer {
+   DummyMapAllocatorInitializer() 
+   {
+      mapAllocator();      // ensure mapAllocator() statics are initialized before main().
+   }
+} dummyMapAllocatorInitializer;
+
+
+
+// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
+
+/*
+use linked list hash map. 
+buckets array is a container.
+linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
+value have extra state: valid, available, deleted
+*/
+
+
+ValueInternalMap::ValueInternalMap()
+   : buckets_( 0 )
+   , tailLink_( 0 )
+   , bucketsSize_( 0 )
+   , itemCount_( 0 )
+{
+}
+
+
+ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
+   : buckets_( 0 )
+   , tailLink_( 0 )
+   , bucketsSize_( 0 )
+   , itemCount_( 0 )
+{
+   reserve( other.itemCount_ );
+   IteratorState it;
+   IteratorState itEnd;
+   other.makeBeginIterator( it );
+   other.makeEndIterator( itEnd );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      bool isStatic;
+      const char *memberName = key( it, isStatic );
+      const Value &aValue = value( it );
+      resolveReference(memberName, isStatic) = aValue;
+   }
+}
+
+
+ValueInternalMap &
+ValueInternalMap::operator =( const ValueInternalMap &other )
+{
+   ValueInternalMap dummy( other );
+   swap( dummy );
+   return *this;
+}
+
+
+ValueInternalMap::~ValueInternalMap()
+{
+   if ( buckets_ )
+   {
+      for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
+      {
+         ValueInternalLink *link = buckets_[bucketIndex].next_;
+         while ( link )
+         {
+            ValueInternalLink *linkToRelease = link;
+            link = link->next_;
+            mapAllocator()->releaseMapLink( linkToRelease );
+         }
+      }
+      mapAllocator()->releaseMapBuckets( buckets_ );
+   }
+}
+
+
+void 
+ValueInternalMap::swap( ValueInternalMap &other )
+{
+   ValueInternalLink *tempBuckets = buckets_;
+   buckets_ = other.buckets_;
+   other.buckets_ = tempBuckets;
+   ValueInternalLink *tempTailLink = tailLink_;
+   tailLink_ = other.tailLink_;
+   other.tailLink_ = tempTailLink;
+   BucketIndex tempBucketsSize = bucketsSize_;
+   bucketsSize_ = other.bucketsSize_;
+   other.bucketsSize_ = tempBucketsSize;
+   BucketIndex tempItemCount = itemCount_;
+   itemCount_ = other.itemCount_;
+   other.itemCount_ = tempItemCount;
+}
+
+
+void 
+ValueInternalMap::clear()
+{
+   ValueInternalMap dummy;
+   swap( dummy );
+}
+
+
+ValueInternalMap::BucketIndex 
+ValueInternalMap::size() const
+{
+   return itemCount_;
+}
+
+bool 
+ValueInternalMap::reserveDelta( BucketIndex growth )
+{
+   return reserve( itemCount_ + growth );
+}
+
+bool 
+ValueInternalMap::reserve( BucketIndex newItemCount )
+{
+   if ( !buckets_  &&  newItemCount > 0 )
+   {
+      buckets_ = mapAllocator()->allocateMapBuckets( 1 );
+      bucketsSize_ = 1;
+      tailLink_ = &buckets_[0];
+   }
+//   BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
+   return true;
+}
+
+
+const Value *
+ValueInternalMap::find( const char *key ) const
+{
+   if ( !bucketsSize_ )
+      return 0;
+   HashKey hashedKey = hash( key );
+   BucketIndex bucketIndex = hashedKey % bucketsSize_;
+   for ( const ValueInternalLink *current = &buckets_[bucketIndex]; 
+         current != 0; 
+         current = current->next_ )
+   {
+      for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
+      {
+         if ( current->items_[index].isItemAvailable() )
+            return 0;
+         if ( strcmp( key, current->keys_[index] ) == 0 )
+            return &current->items_[index];
+      }
+   }
+   return 0;
+}
+
+
+Value *
+ValueInternalMap::find( const char *key )
+{
+   const ValueInternalMap *constThis = this;
+   return const_cast<Value *>( constThis->find( key ) );
+}
+
+
+Value &
+ValueInternalMap::resolveReference( const char *key,
+                                    bool isStatic )
+{
+   HashKey hashedKey = hash( key );
+   if ( bucketsSize_ )
+   {
+      BucketIndex bucketIndex = hashedKey % bucketsSize_;
+      ValueInternalLink **previous = 0;
+      BucketIndex index;
+      for ( ValueInternalLink *current = &buckets_[bucketIndex]; 
+            current != 0; 
+            previous = &current->next_, current = current->next_ )
+      {
+         for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
+         {
+            if ( current->items_[index].isItemAvailable() )
+               return setNewItem( key, isStatic, current, index );
+            if ( strcmp( key, current->keys_[index] ) == 0 )
+               return current->items_[index];
+         }
+      }
+   }
+
+   reserveDelta( 1 );
+   return unsafeAdd( key, isStatic, hashedKey );
+}
+
+
+void 
+ValueInternalMap::remove( const char *key )
+{
+   HashKey hashedKey = hash( key );
+   if ( !bucketsSize_ )
+      return;
+   BucketIndex bucketIndex = hashedKey % bucketsSize_;
+   for ( ValueInternalLink *link = &buckets_[bucketIndex]; 
+         link != 0; 
+         link = link->next_ )
+   {
+      BucketIndex index;
+      for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
+      {
+         if ( link->items_[index].isItemAvailable() )
+            return;
+         if ( strcmp( key, link->keys_[index] ) == 0 )
+         {
+            doActualRemove( link, index, bucketIndex );
+            return;
+         }
+      }
+   }
+}
+
+void 
+ValueInternalMap::doActualRemove( ValueInternalLink *link, 
+                                  BucketIndex index,
+                                  BucketIndex bucketIndex )
+{
+   // find last item of the bucket and swap it with the 'removed' one.
+   // set removed items flags to 'available'.
+   // if last page only contains 'available' items, then desallocate it (it's empty)
+   ValueInternalLink *&lastLink = getLastLinkInBucket( index );
+   BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
+   for ( ;   
+         lastItemIndex < ValueInternalLink::itemPerLink; 
+         ++lastItemIndex ) // may be optimized with dicotomic search
+   {
+      if ( lastLink->items_[lastItemIndex].isItemAvailable() )
+         break;
+   }
+   
+   BucketIndex lastUsedIndex = lastItemIndex - 1;
+   Value *valueToDelete = &link->items_[index];
+   Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
+   if ( valueToDelete != valueToPreserve )
+      valueToDelete->swap( *valueToPreserve );
+   if ( lastUsedIndex == 0 )  // page is now empty
+   {  // remove it from bucket linked list and delete it.
+      ValueInternalLink *linkPreviousToLast = lastLink->previous_;
+      if ( linkPreviousToLast != 0 )   // can not deleted bucket link.
+      {
+         mapAllocator()->releaseMapLink( lastLink );
+         linkPreviousToLast->next_ = 0;
+         lastLink = linkPreviousToLast;
+      }
+   }
+   else
+   {
+      Value dummy;
+      valueToPreserve->swap( dummy ); // restore deleted to default Value.
+      valueToPreserve->setItemUsed( false );
+   }
+   --itemCount_;
+}
+
+
+ValueInternalLink *&
+ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
+{
+   if ( bucketIndex == bucketsSize_ - 1 )
+      return tailLink_;
+   ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
+   if ( !previous )
+      previous = &buckets_[bucketIndex];
+   return previous;
+}
+
+
+Value &
+ValueInternalMap::setNewItem( const char *key, 
+                              bool isStatic,
+                              ValueInternalLink *link, 
+                              BucketIndex index )
+{
+   char *duplicatedKey = valueAllocator()->makeMemberName( key );
+   ++itemCount_;
+   link->keys_[index] = duplicatedKey;
+   link->items_[index].setItemUsed();
+   link->items_[index].setMemberNameIsStatic( isStatic );
+   return link->items_[index]; // items already default constructed.
+}
+
+
+Value &
+ValueInternalMap::unsafeAdd( const char *key, 
+                             bool isStatic, 
+                             HashKey hashedKey )
+{
+   JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
+   BucketIndex bucketIndex = hashedKey % bucketsSize_;
+   ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
+   ValueInternalLink *link = previousLink;
+   BucketIndex index;
+   for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
+   {
+      if ( link->items_[index].isItemAvailable() )
+         break;
+   }
+   if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
+   {
+      ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
+      index = 0;
+      link->next_ = newLink;
+      previousLink = newLink;
+      link = newLink;
+   }
+   return setNewItem( key, isStatic, link, index );
+}
+
+
+ValueInternalMap::HashKey 
+ValueInternalMap::hash( const char *key ) const
+{
+   HashKey hash = 0;
+   while ( *key )
+      hash += *key++ * 37;
+   return hash;
+}
+
+
+int 
+ValueInternalMap::compare( const ValueInternalMap &other ) const
+{
+   int sizeDiff( itemCount_ - other.itemCount_ );
+   if ( sizeDiff != 0 )
+      return sizeDiff;
+   // Strict order guaranty is required. Compare all keys FIRST, then compare values.
+   IteratorState it;
+   IteratorState itEnd;
+   makeBeginIterator( it );
+   makeEndIterator( itEnd );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      if ( !other.find( key( it ) ) )
+         return 1;
+   }
+
+   // All keys are equals, let's compare values
+   makeBeginIterator( it );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      const Value *otherValue = other.find( key( it ) );
+      int valueDiff = value(it).compare( *otherValue );
+      if ( valueDiff != 0 )
+         return valueDiff;
+   }
+   return 0;
+}
+
+
+void 
+ValueInternalMap::makeBeginIterator( IteratorState &it ) const
+{
+   it.map_ = const_cast<ValueInternalMap *>( this );
+   it.bucketIndex_ = 0;
+   it.itemIndex_ = 0;
+   it.link_ = buckets_;
+}
+
+
+void 
+ValueInternalMap::makeEndIterator( IteratorState &it ) const
+{
+   it.map_ = const_cast<ValueInternalMap *>( this );
+   it.bucketIndex_ = bucketsSize_;
+   it.itemIndex_ = 0;
+   it.link_ = 0;
+}
+
+
+bool 
+ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
+{
+   return x.map_ == other.map_  
+          &&  x.bucketIndex_ == other.bucketIndex_  
+          &&  x.link_ == other.link_
+          &&  x.itemIndex_ == other.itemIndex_;
+}
+
+
+void 
+ValueInternalMap::incrementBucket( IteratorState &iterator )
+{
+   ++iterator.bucketIndex_;
+   JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
+      "ValueInternalMap::increment(): attempting to iterate beyond end." );
+   if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
+      iterator.link_ = 0;
+   else
+      iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
+   iterator.itemIndex_ = 0;
+}
+
+
+void 
+ValueInternalMap::increment( IteratorState &iterator )
+{
+   JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
+   ++iterator.itemIndex_;
+   if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
+   {
+      JSON_ASSERT_MESSAGE( iterator.link_ != 0,
+         "ValueInternalMap::increment(): attempting to iterate beyond end." );
+      iterator.link_ = iterator.link_->next_;
+      if ( iterator.link_ == 0 )
+         incrementBucket( iterator );
+   }
+   else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
+   {
+      incrementBucket( iterator );
+   }
+}
+
+
+void 
+ValueInternalMap::decrement( IteratorState &iterator )
+{
+   if ( iterator.itemIndex_ == 0 )
+   {
+      JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
+      if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
+      {
+         JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
+         --(iterator.bucketIndex_);
+      }
+      iterator.link_ = iterator.link_->previous_;
+      iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
+   }
+}
+
+
+const char *
+ValueInternalMap::key( const IteratorState &iterator )
+{
+   JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
+   return iterator.link_->keys_[iterator.itemIndex_];
+}
+
+const char *
+ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
+{
+   JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
+   isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
+   return iterator.link_->keys_[iterator.itemIndex_];
+}
+
+
+Value &
+ValueInternalMap::value( const IteratorState &iterator )
+{
+   JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
+   return iterator.link_->items_[iterator.itemIndex_];
+}
+
+
+int 
+ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
+{
+   int offset = 0;
+   IteratorState it = x;
+   while ( !equals( it, y ) )
+      increment( it );
+   return offset;
+}
diff --git a/final/lib/External/JSON/json_reader.cpp b/final/lib/External/JSON/json_reader.cpp
new file mode 100644
index 0000000..680c2b6
--- /dev/null
+++ b/final/lib/External/JSON/json_reader.cpp
@@ -0,0 +1,890 @@
+#include <json/reader.h>
+#include <json/value.h>
+#include <utility>
+#include <cstdio>
+#include <cassert>
+#include <cstring>
+#include <iostream>
+#include <stdexcept>
+
+#if _MSC_VER >= 1400 // VC++ 8.0
+#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.
+#endif
+
+namespace Json {
+
+// Implementation of class Features
+// ////////////////////////////////
+
+Features::Features()
+   : allowComments_( true )
+   , strictRoot_( false )
+{
+}
+
+
+Features 
+Features::all()
+{
+   return Features();
+}
+
+
+Features 
+Features::strictMode()
+{
+   Features features;
+   features.allowComments_ = false;
+   features.strictRoot_ = true;
+   return features;
+}
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+
+static inline bool 
+in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
+{
+   return c == c1  ||  c == c2  ||  c == c3  ||  c == c4;
+}
+
+static inline bool 
+in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
+{
+   return c == c1  ||  c == c2  ||  c == c3  ||  c == c4  ||  c == c5;
+}
+
+
+static bool 
+containsNewLine( Reader::Location begin, 
+                 Reader::Location end )
+{
+   for ( ;begin < end; ++begin )
+      if ( *begin == '\n'  ||  *begin == '\r' )
+         return true;
+   return false;
+}
+
+static std::string codePointToUTF8(unsigned int cp)
+{
+   std::string result;
+   
+   // based on description from http://en.wikipedia.org/wiki/UTF-8
+
+   if (cp <= 0x7f) 
+   {
+      result.resize(1);
+      result[0] = static_cast<char>(cp);
+   } 
+   else if (cp <= 0x7FF) 
+   {
+      result.resize(2);
+      result[1] = static_cast<char>(0x80 | (0x3f & cp));
+      result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
+   } 
+   else if (cp <= 0xFFFF) 
+   {
+      result.resize(3);
+      result[2] = static_cast<char>(0x80 | (0x3f & cp));
+      result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
+      result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
+   }
+   else if (cp <= 0x10FFFF) 
+   {
+      result.resize(4);
+      result[3] = static_cast<char>(0x80 | (0x3f & cp));
+      result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
+      result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
+      result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
+   }
+
+   return result;
+}
+
+
+// Class Reader
+// //////////////////////////////////////////////////////////////////
+
+Reader::Reader()
+   : features_( Features::all() )
+{
+}
+
+
+Reader::Reader( const Features &features )
+   : features_( features )
+{
+}
+
+
+bool
+Reader::parse( const std::string &document, 
+               Value &root,
+               bool collectComments )
+{
+   document_ = document;
+   const char *begin = document_.c_str();
+   const char *end = begin + document_.length();
+   return parse( begin, end, root, collectComments );
+}
+
+
+bool
+Reader::parse( std::istream& sin,
+               Value &root,
+               bool collectComments )
+{
+   //std::istream_iterator<char> begin(sin);
+   //std::istream_iterator<char> end;
+   // Those would allow streamed input from a file, if parse() were a
+   // template function.
+
+   // Since std::string is reference-counted, this at least does not
+   // create an extra copy.
+   std::string doc;
+   std::getline(sin, doc, (char)EOF);
+   return parse( doc, root, collectComments );
+}
+
+bool 
+Reader::parse( const char *beginDoc, const char *endDoc, 
+               Value &root,
+               bool collectComments )
+{
+   if ( !features_.allowComments_ )
+   {
+      collectComments = false;
+   }
+
+   begin_ = beginDoc;
+   end_ = endDoc;
+   collectComments_ = collectComments;
+   current_ = begin_;
+   lastValueEnd_ = 0;
+   lastValue_ = 0;
+   commentsBefore_ = "";
+   errors_.clear();
+   while ( !nodes_.empty() )
+      nodes_.pop();
+   nodes_.push( &root );
+   
+   bool successful = readValue();
+   Token token;
+   skipCommentTokens( token );
+   if ( collectComments_  &&  !commentsBefore_.empty() )
+      root.setComment( commentsBefore_, commentAfter );
+   if ( features_.strictRoot_ )
+   {
+      if ( !root.isArray()  &&  !root.isObject() )
+      {
+         // Set error location to start of doc, ideally should be first token found in doc
+         token.type_ = tokenError;
+         token.start_ = beginDoc;
+         token.end_ = endDoc;
+         addError( "A valid JSON document must be either an array or an object value.",
+                   token );
+         return false;
+      }
+   }
+   return successful;
+}
+
+
+bool
+Reader::readValue()
+{
+   Token token;
+   skipCommentTokens( token );
+   bool successful = true;
+
+   if ( collectComments_  &&  !commentsBefore_.empty() )
+   {
+      currentValue().setComment( commentsBefore_, commentBefore );
+      commentsBefore_ = "";
+   }
+
+
+   switch ( token.type_ )
+   {
+   case tokenObjectBegin:
+      successful = readObject( token );
+      break;
+   case tokenArrayBegin:
+      successful = readArray( token );
+      break;
+   case tokenNumber:
+      successful = decodeNumber( token );
+      break;
+   case tokenString:
+      successful = decodeString( token );
+      break;
+   case tokenTrue:
+      currentValue() = true;
+      break;
+   case tokenFalse:
+      currentValue() = false;
+      break;
+   case tokenNull:
+      currentValue() = Value();
+      break;
+   default:
+      return addError( "Syntax error: value, object or array expected.", token );
+   }
+
+   if ( collectComments_ )
+   {
+      lastValueEnd_ = current_;
+      lastValue_ = &currentValue();
+   }
+
+   return successful;
+}
+
+
+void 
+Reader::skipCommentTokens( Token &token )
+{
+   if ( features_.allowComments_ )
+   {
+      do
+      {
+         readToken( token );
+      }
+      while ( token.type_ == tokenComment );
+   }
+   else
+   {
+      readToken( token );
+   }
+}
+
+
+bool 
+Reader::expectToken( TokenType type, Token &token, const char *message )
+{
+   readToken( token );
+   if ( token.type_ != type )
+      return addError( message, token );
+   return true;
+}
+
+
+bool 
+Reader::readToken( Token &token )
+{
+   skipSpaces();
+   token.start_ = current_;
+   Char c = getNextChar();
+   bool ok = true;
+   switch ( c )
+   {
+   case '{':
+      token.type_ = tokenObjectBegin;
+      break;
+   case '}':
+      token.type_ = tokenObjectEnd;
+      break;
+   case '[':
+      token.type_ = tokenArrayBegin;
+      break;
+   case ']':
+      token.type_ = tokenArrayEnd;
+      break;
+   case '"':
+      token.type_ = tokenString;
+      ok = readString();
+      break;
+   case '/':
+      token.type_ = tokenComment;
+      ok = readComment();
+      break;
+   case '0':
+   case '1':
+   case '2':
+   case '3':
+   case '4':
+   case '5':
+   case '6':
+   case '7':
+   case '8':
+   case '9':
+   case '-':
+      token.type_ = tokenNumber;
+      readNumber();
+      break;
+   case 't':
+      token.type_ = tokenTrue;
+      ok = match( "rue", 3 );
+      break;
+   case 'f':
+      token.type_ = tokenFalse;
+      ok = match( "alse", 4 );
+      break;
+   case 'n':
+      token.type_ = tokenNull;
+      ok = match( "ull", 3 );
+      break;
+   case ',':
+      token.type_ = tokenArraySeparator;
+      break;
+   case ':':
+      token.type_ = tokenMemberSeparator;
+      break;
+   case 0:
+      token.type_ = tokenEndOfStream;
+      break;
+   default:
+      ok = false;
+      break;
+   }
+   if ( !ok )
+      token.type_ = tokenError;
+   token.end_ = current_;
+   return true;
+}
+
+
+void 
+Reader::skipSpaces()
+{
+   while ( current_ != end_ )
+   {
+      Char c = *current_;
+      if ( c == ' '  ||  c == '\t'  ||  c == '\r'  ||  c == '\n' )
+         ++current_;
+      else
+         break;
+   }
+}
+
+
+bool 
+Reader::match( Location pattern, 
+               int patternLength )
+{
+   if ( end_ - current_ < patternLength )
+      return false;
+   int index = patternLength;
+   while ( index-- )
+      if ( current_[index] != pattern[index] )
+         return false;
+   current_ += patternLength;
+   return true;
+}
+
+
+bool
+Reader::readComment()
+{
+   Location commentBegin = current_ - 1;
+   Char c = getNextChar();
+   bool successful = false;
+   if ( c == '*' )
+      successful = readCStyleComment();
+   else if ( c == '/' )
+      successful = readCppStyleComment();
+   if ( !successful )
+      return false;
+
+   if ( collectComments_ )
+   {
+      CommentPlacement placement = commentBefore;
+      if ( lastValueEnd_  &&  !containsNewLine( lastValueEnd_, commentBegin ) )
+      {
+         if ( c != '*'  ||  !containsNewLine( commentBegin, current_ ) )
+            placement = commentAfterOnSameLine;
+      }
+
+      addComment( commentBegin, current_, placement );
+   }
+   return true;
+}
+
+
+void 
+Reader::addComment( Location begin, 
+                    Location end, 
+                    CommentPlacement placement )
+{
+   assert( collectComments_ );
+   if ( placement == commentAfterOnSameLine )
+   {
+      assert( lastValue_ != 0 );
+      lastValue_->setComment( std::string( begin, end ), placement );
+   }
+   else
+   {
+      if ( !commentsBefore_.empty() )
+         commentsBefore_ += "\n";
+      commentsBefore_ += std::string( begin, end );
+   }
+}
+
+
+bool 
+Reader::readCStyleComment()
+{
+   while ( current_ != end_ )
+   {
+      Char c = getNextChar();
+      if ( c == '*'  &&  *current_ == '/' )
+         break;
+   }
+   return getNextChar() == '/';
+}
+
+
+bool 
+Reader::readCppStyleComment()
+{
+   while ( current_ != end_ )
+   {
+      Char c = getNextChar();
+      if (  c == '\r'  ||  c == '\n' )
+         break;
+   }
+   return true;
+}
+
+
+void 
+Reader::readNumber()
+{
+   while ( current_ != end_ )
+   {
+      if ( !(*current_ >= '0'  &&  *current_ <= '9')  &&
+           !in( *current_, '.', 'e', 'E', '+', '-' ) )
+         break;
+      ++current_;
+   }
+}
+
+bool
+Reader::readString()
+{
+   Char c = 0;
+   while ( current_ != end_ )
+   {
+      c = getNextChar();
+      if ( c == '\\' )
+         getNextChar();
+      else if ( c == '"' )
+         break;
+   }
+   return c == '"';
+}
+
+
+bool 
+Reader::readObject( Token &tokenStart )
+{
+   Token tokenName;
+   std::string name;
+   currentValue() = Value( objectValue );
+   while ( readToken( tokenName ) )
+   {
+      bool initialTokenOk = true;
+      while ( tokenName.type_ == tokenComment  &&  initialTokenOk )
+         initialTokenOk = readToken( tokenName );
+      if  ( !initialTokenOk )
+         break;
+      if ( tokenName.type_ == tokenObjectEnd  &&  name.empty() )  // empty object
+         return true;
+      if ( tokenName.type_ != tokenString )
+         break;
+      
+      name = "";
+      if ( !decodeString( tokenName, name ) )
+         return recoverFromError( tokenObjectEnd );
+
+      Token colon;
+      if ( !readToken( colon ) ||  colon.type_ != tokenMemberSeparator )
+      {
+         return addErrorAndRecover( "Missing ':' after object member name", 
+                                    colon, 
+                                    tokenObjectEnd );
+      }
+      Value &value = currentValue()[ name ];
+      nodes_.push( &value );
+      bool ok = readValue();
+      nodes_.pop();
+      if ( !ok ) // error already set
+         return recoverFromError( tokenObjectEnd );
+
+      Token comma;
+      if ( !readToken( comma )
+            ||  ( comma.type_ != tokenObjectEnd  &&  
+                  comma.type_ != tokenArraySeparator &&
+		  comma.type_ != tokenComment ) )
+      {
+         return addErrorAndRecover( "Missing ',' or '}' in object declaration", 
+                                    comma, 
+                                    tokenObjectEnd );
+      }
+      bool finalizeTokenOk = true;
+      while ( comma.type_ == tokenComment &&
+              finalizeTokenOk )
+         finalizeTokenOk = readToken( comma );
+      if ( comma.type_ == tokenObjectEnd )
+         return true;
+   }
+   return addErrorAndRecover( "Missing '}' or object member name", 
+                              tokenName, 
+                              tokenObjectEnd );
+}
+
+
+bool 
+Reader::readArray( Token &tokenStart )
+{
+   currentValue() = Value( arrayValue );
+   skipSpaces();
+   if ( *current_ == ']' ) // empty array
+   {
+      Token endArray;
+      readToken( endArray );
+      return true;
+   }
+   int index = 0;
+   while ( true )
+   {
+      Value &value = currentValue()[ index++ ];
+      nodes_.push( &value );
+      bool ok = readValue();
+      nodes_.pop();
+      if ( !ok ) // error already set
+         return recoverFromError( tokenArrayEnd );
+
+      Token token;
+      // Accept Comment after last item in the array.
+      ok = readToken( token );
+      while ( token.type_ == tokenComment  &&  ok )
+      {
+         ok = readToken( token );
+      }
+      bool badTokenType = ( token.type_ == tokenArraySeparator  &&  
+                            token.type_ == tokenArrayEnd );
+      if ( !ok  ||  badTokenType )
+      {
+         return addErrorAndRecover( "Missing ',' or ']' in array declaration", 
+                                    token, 
+                                    tokenArrayEnd );
+      }
+      if ( token.type_ == tokenArrayEnd )
+         break;
+   }
+   return true;
+}
+
+
+bool 
+Reader::decodeNumber( Token &token )
+{
+   bool isDouble = false;
+   for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
+   {
+      isDouble = isDouble  
+                 ||  in( *inspect, '.', 'e', 'E', '+' )  
+                 ||  ( *inspect == '-'  &&  inspect != token.start_ );
+   }
+   if ( isDouble )
+      return decodeDouble( token );
+   Location current = token.start_;
+   bool isNegative = *current == '-';
+   if ( isNegative )
+      ++current;
+   Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) 
+                                       : Value::maxUInt) / 10;
+   Value::UInt value = 0;
+   while ( current < token.end_ )
+   {
+      Char c = *current++;
+      if ( c < '0'  ||  c > '9' )
+         return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
+      if ( value >= threshold )
+         return decodeDouble( token );
+      value = value * 10 + Value::UInt(c - '0');
+   }
+   if ( isNegative )
+      currentValue() = -Value::Int( value );
+   else if ( value <= Value::UInt(Value::maxInt) )
+      currentValue() = Value::Int( value );
+   else
+      currentValue() = value;
+   return true;
+}
+
+
+bool 
+Reader::decodeDouble( Token &token )
+{
+   double value = 0;
+   const int bufferSize = 32;
+   int count;
+   int length = int(token.end_ - token.start_);
+   if ( length <= bufferSize )
+   {
+      Char buffer[bufferSize];
+      memcpy( buffer, token.start_, length );
+      buffer[length] = 0;
+      count = sscanf( buffer, "%lf", &value );
+   }
+   else
+   {
+      std::string buffer( token.start_, token.end_ );
+      count = sscanf( buffer.c_str(), "%lf", &value );
+   }
+
+   if ( count != 1 )
+      return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
+   currentValue() = value;
+   return true;
+}
+
+
+bool 
+Reader::decodeString( Token &token )
+{
+   std::string decoded;
+   if ( !decodeString( token, decoded ) )
+      return false;
+   currentValue() = decoded;
+   return true;
+}
+
+
+bool 
+Reader::decodeString( Token &token, std::string &decoded )
+{
+   decoded.reserve( token.end_ - token.start_ - 2 );
+   Location current = token.start_ + 1; // skip '"'
+   Location end = token.end_ - 1;      // do not include '"'
+   while ( current != end )
+   {
+      Char c = *current++;
+      if ( c == '"' )
+         break;
+      else if ( c == '\\' )
+      {
+         if ( current == end )
+            return addError( "Empty escape sequence in string", token, current );
+         Char escape = *current++;
+         switch ( escape )
+         {
+         case '"': decoded += '"'; break;
+         case '/': decoded += '/'; break;
+         case '\\': decoded += '\\'; break;
+         case 'b': decoded += '\b'; break;
+         case 'f': decoded += '\f'; break;
+         case 'n': decoded += '\n'; break;
+         case 'r': decoded += '\r'; break;
+         case 't': decoded += '\t'; break;
+         case 'u':
+            {
+               unsigned int unicode;
+               if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
+                  return false;
+               decoded += codePointToUTF8(unicode);
+            }
+            break;
+         default:
+            return addError( "Bad escape sequence in string", token, current );
+         }
+      }
+      else
+      {
+         decoded += c;
+      }
+   }
+   return true;
+}
+
+bool
+Reader::decodeUnicodeCodePoint( Token &token, 
+                                     Location &current, 
+                                     Location end, 
+                                     unsigned int &unicode )
+{
+
+   if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
+      return false;
+   if (unicode >= 0xD800 && unicode <= 0xDBFF)
+   {
+      // surrogate pairs
+      if (end - current < 6)
+         return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
+      unsigned int surrogatePair;
+      if (*(current++) == '\\' && *(current++)== 'u')
+      {
+         if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
+         {
+            unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+         } 
+         else
+            return false;
+      } 
+      else
+         return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
+   }
+   return true;
+}
+
+bool 
+Reader::decodeUnicodeEscapeSequence( Token &token, 
+                                     Location &current, 
+                                     Location end, 
+                                     unsigned int &unicode )
+{
+   if ( end - current < 4 )
+      return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
+   unicode = 0;
+   for ( int index =0; index < 4; ++index )
+   {
+      Char c = *current++;
+      unicode *= 16;
+      if ( c >= '0'  &&  c <= '9' )
+         unicode += c - '0';
+      else if ( c >= 'a'  &&  c <= 'f' )
+         unicode += c - 'a' + 10;
+      else if ( c >= 'A'  &&  c <= 'F' )
+         unicode += c - 'A' + 10;
+      else
+         return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
+   }
+   return true;
+}
+
+
+bool 
+Reader::addError( const std::string &message, 
+                  Token &token,
+                  Location extra )
+{
+   ErrorInfo info;
+   info.token_ = token;
+   info.message_ = message;
+   info.extra_ = extra;
+   errors_.push_back( info );
+   return false;
+}
+
+
+bool 
+Reader::recoverFromError( TokenType skipUntilToken )
+{
+   int errorCount = int(errors_.size());
+   Token skip;
+   while ( true )
+   {
+      if ( !readToken(skip) )
+         errors_.resize( errorCount ); // discard errors caused by recovery
+      if ( skip.type_ == skipUntilToken  ||  skip.type_ == tokenEndOfStream )
+         break;
+   }
+   errors_.resize( errorCount );
+   return false;
+}
+
+
+bool 
+Reader::addErrorAndRecover( const std::string &message, 
+                            Token &token,
+                            TokenType skipUntilToken )
+{
+   addError( message, token );
+   return recoverFromError( skipUntilToken );
+}
+
+
+Value &
+Reader::currentValue()
+{
+   return *(nodes_.top());
+}
+
+
+Reader::Char 
+Reader::getNextChar()
+{
+   if ( current_ == end_ )
+      return 0;
+   return *current_++;
+}
+
+
+void 
+Reader::getLocationLineAndColumn( Location location,
+                                  int &line,
+                                  int &column ) const
+{
+   Location current = begin_;
+   Location lastLineStart = current;
+   line = 0;
+   while ( current < location  &&  current != end_ )
+   {
+      Char c = *current++;
+      if ( c == '\r' )
+      {
+         if ( *current == '\n' )
+            ++current;
+         lastLineStart = current;
+         ++line;
+      }
+      else if ( c == '\n' )
+      {
+         lastLineStart = current;
+         ++line;
+      }
+   }
+   // column & line start at 1
+   column = int(location - lastLineStart) + 1;
+   ++line;
+}
+
+
+std::string
+Reader::getLocationLineAndColumn( Location location ) const
+{
+   int line, column;
+   getLocationLineAndColumn( location, line, column );
+   char buffer[18+16+16+1];
+   sprintf( buffer, "Line %d, Column %d", line, column );
+   return buffer;
+}
+
+
+std::string 
+Reader::getFormatedErrorMessages() const
+{
+   std::string formattedMessage;
+   for ( Errors::const_iterator itError = errors_.begin();
+         itError != errors_.end();
+         ++itError )
+   {
+      const ErrorInfo &error = *itError;
+      formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
+      formattedMessage += "  " + error.message_ + "\n";
+      if ( error.extra_ )
+         formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
+   }
+   return formattedMessage;
+}
+
+
+std::istream& operator>>( std::istream &sin, Value &root )
+{
+    Json::Reader reader;
+    bool ok = reader.parse(sin, root, true);
+    //JSON_ASSERT( ok );
+#if JSON_USE_EXCEPTION
+    if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());
+#else
+    assert(ok && "Bad Format!");
+    (void) ok;
+#endif
+    return sin;
+}
+
+
+} // namespace Json
diff --git a/final/lib/External/JSON/json_value.cpp b/final/lib/External/JSON/json_value.cpp
new file mode 100644
index 0000000..691e418
--- /dev/null
+++ b/final/lib/External/JSON/json_value.cpp
@@ -0,0 +1,1732 @@
+#include <iostream>
+#include <json/value.h>
+#include <json/writer.h>
+#include <utility>
+#include <stdexcept>
+#include <cstring>
+#include <cassert>
+#ifdef JSON_USE_CPPTL
+# include <cpptl/conststring.h>
+#endif
+#include <cstddef>    // size_t
+#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+# include "json_batchallocator.h"
+#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+
+// Disable warnings.  We do not fix these warnings, as this is a file imported
+// into Polly and we do not want to diverge from the original source.
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wcovered-switch-default"
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Woverflow"
+#endif
+
+#define JSON_ASSERT_UNREACHABLE assert( false )
+#define JSON_ASSERT( condition ) assert( condition );  // @todo <= change this into an exception throw
+// Do not use throw when exception is disable.
+#if JSON_USE_EXCEPTION
+#	define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message );
+#else
+#	define JSON_ASSERT_MESSAGE( condition, message ) JSON_ASSERT( condition ) // @todo <= provide the message
+#endif
+
+namespace Json {
+
+const Value Value::null;
+const Int Value::minInt = Int( ~(UInt(-1)/2) );
+const Int Value::maxInt = Int( UInt(-1)/2 );
+const UInt Value::maxUInt = UInt(-1);
+
+// A "safe" implementation of strdup. Allow null pointer to be passed.
+// Also avoid warning on msvc80.
+//
+//inline char *safeStringDup( const char *czstring )
+//{
+//   if ( czstring )
+//   {
+//      const size_t length = (unsigned int)( strlen(czstring) + 1 );
+//      char *newString = static_cast<char *>( malloc( length ) );
+//      memcpy( newString, czstring, length );
+//      return newString;
+//   }
+//   return 0;
+//}
+//
+//inline char *safeStringDup( const std::string &str )
+//{
+//   if ( !str.empty() )
+//   {
+//      const size_t length = str.length();
+//      char *newString = static_cast<char *>( malloc( length + 1 ) );
+//      memcpy( newString, str.c_str(), length );
+//      newString[length] = 0;
+//      return newString;
+//   }
+//   return 0;
+//}
+
+ValueAllocator::~ValueAllocator()
+{
+}
+
+class DefaultValueAllocator : public ValueAllocator
+{
+public:
+   virtual ~DefaultValueAllocator()
+   {
+   }
+
+   virtual char *makeMemberName( const char *memberName )
+   {
+      return duplicateStringValue( memberName );
+   }
+
+   virtual void releaseMemberName( char *memberName )
+   {
+      releaseStringValue( memberName );
+   }
+
+   virtual char *duplicateStringValue( const char *value,
+                                       unsigned int length = unknown )
+   {
+      //@todo invesgate this old optimization
+      //if ( !value  ||  value[0] == 0 )
+      //   return 0;
+
+      if ( length == unknown )
+         length = (unsigned int)strlen(value);
+      char *newString = static_cast<char *>( malloc( length + 1 ) );
+      memcpy( newString, value, length );
+      newString[length] = 0;
+      return newString;
+   }
+
+   virtual void releaseStringValue( char *value )
+   {
+      if ( value )
+         free( value );
+   }
+};
+
+static ValueAllocator *&valueAllocator()
+{
+   static DefaultValueAllocator defaultAllocator;
+   static ValueAllocator *valueAllocator = &defaultAllocator;
+   return valueAllocator;
+}
+
+static struct DummyValueAllocatorInitializer {
+   DummyValueAllocatorInitializer()
+   {
+      valueAllocator();      // ensure valueAllocator() statics are initialized before main().
+   }
+} dummyValueAllocatorInitializer;
+
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// ValueInternals...
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+# include "json_internalarray.inl"
+# include "json_internalmap.inl"
+#endif // JSON_VALUE_USE_INTERNAL_MAP
+
+# include "json_valueiterator.inl"
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CommentInfo
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+
+Value::CommentInfo::CommentInfo()
+   : comment_( 0 )
+{
+}
+
+Value::CommentInfo::~CommentInfo()
+{
+   if ( comment_ )
+      valueAllocator()->releaseStringValue( comment_ );
+}
+
+
+void
+Value::CommentInfo::setComment( const char *text )
+{
+   if ( comment_ )
+      valueAllocator()->releaseStringValue( comment_ );
+   JSON_ASSERT( text );
+   JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /");
+   // It seems that /**/ style comments are acceptable as well.
+   comment_ = valueAllocator()->duplicateStringValue( text );
+}
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CZString
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+# ifndef JSON_VALUE_USE_INTERNAL_MAP
+
+// Notes: index_ indicates if the string was allocated when
+// a string is stored.
+
+Value::CZString::CZString( int index )
+   : cstr_( 0 )
+   , index_( index )
+{
+}
+
+Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate )
+   : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr)
+                                  : cstr )
+   , index_( allocate )
+{
+}
+
+Value::CZString::CZString( const CZString &other )
+: cstr_( other.index_ != noDuplication &&  other.cstr_ != 0
+                ?  valueAllocator()->makeMemberName( other.cstr_ )
+                : other.cstr_ )
+   , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate)
+                         : other.index_ )
+{
+}
+
+Value::CZString::~CZString()
+{
+   if ( cstr_  &&  index_ == duplicate )
+      valueAllocator()->releaseMemberName( const_cast<char *>( cstr_ ) );
+}
+
+void
+Value::CZString::swap( CZString &other )
+{
+   std::swap( cstr_, other.cstr_ );
+   std::swap( index_, other.index_ );
+}
+
+Value::CZString &
+Value::CZString::operator =( const CZString &other )
+{
+   CZString temp( other );
+   swap( temp );
+   return *this;
+}
+
+bool
+Value::CZString::operator<( const CZString &other ) const
+{
+   if ( cstr_ )
+      return strcmp( cstr_, other.cstr_ ) < 0;
+   return index_ < other.index_;
+}
+
+bool
+Value::CZString::operator==( const CZString &other ) const
+{
+   if ( cstr_ )
+      return strcmp( cstr_, other.cstr_ ) == 0;
+   return index_ == other.index_;
+}
+
+
+int
+Value::CZString::index() const
+{
+   return index_;
+}
+
+
+const char *
+Value::CZString::c_str() const
+{
+   return cstr_;
+}
+
+bool
+Value::CZString::isStaticString() const
+{
+   return index_ == noDuplication;
+}
+
+#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::Value
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/*! \internal Default constructor initialization must be equivalent to:
+ * memset( this, 0, sizeof(Value) )
+ * This optimization is used in ValueInternalMap fast allocator.
+ */
+Value::Value( ValueType type )
+   : type_( type )
+   , allocated_( 0 )
+   , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+{
+   switch ( type )
+   {
+   case nullValue:
+      break;
+   case intValue:
+   case uintValue:
+      value_.int_ = 0;
+      break;
+   case realValue:
+      value_.real_ = 0.0;
+      break;
+   case stringValue:
+      value_.string_ = 0;
+      break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+   case objectValue:
+      value_.map_ = new ObjectValues();
+      break;
+#else
+   case arrayValue:
+      value_.array_ = arrayAllocator()->newArray();
+      break;
+   case objectValue:
+      value_.map_ = mapAllocator()->newMap();
+      break;
+#endif
+   case booleanValue:
+      value_.bool_ = false;
+      break;
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+}
+
+
+Value::Value( Int value )
+   : type_( intValue )
+   , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+{
+   value_.int_ = value;
+}
+
+
+Value::Value( UInt value )
+   : type_( uintValue )
+   , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+{
+   value_.uint_ = value;
+}
+
+Value::Value( double value )
+   : type_( realValue )
+   , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+{
+   value_.real_ = value;
+}
+
+Value::Value( const char *value )
+   : type_( stringValue )
+   , allocated_( true )
+   , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+{
+   value_.string_ = valueAllocator()->duplicateStringValue( value );
+}
+
+
+Value::Value( const char *beginValue,
+              const char *endValue )
+   : type_( stringValue )
+   , allocated_( true )
+   , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+{
+   value_.string_ = valueAllocator()->duplicateStringValue( beginValue,
+                                                            UInt(endValue - beginValue) );
+}
+
+
+Value::Value( const std::string &value )
+   : type_( stringValue )
+   , allocated_( true )
+   , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+{
+   value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(),
+                                                            (unsigned int)value.length() );
+
+}
+
+Value::Value( const StaticString &value )
+   : type_( stringValue )
+   , allocated_( false )
+   , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+{
+   value_.string_ = const_cast<char *>( value.c_str() );
+}
+
+
+# ifdef JSON_USE_CPPTL
+Value::Value( const CppTL::ConstString &value )
+   : type_( stringValue )
+   , allocated_( true )
+   , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+{
+   value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() );
+}
+# endif
+
+Value::Value( bool value )
+   : type_( booleanValue )
+   , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+{
+   value_.bool_ = value;
+}
+
+
+Value::Value( const Value &other )
+   : type_( other.type_ )
+   , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+{
+   switch ( type_ )
+   {
+   case nullValue:
+   case intValue:
+   case uintValue:
+   case realValue:
+   case booleanValue:
+      value_ = other.value_;
+      break;
+   case stringValue:
+      if ( other.value_.string_ )
+      {
+         value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ );
+         allocated_ = true;
+      }
+      else
+         value_.string_ = 0;
+      break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+   case objectValue:
+      value_.map_ = new ObjectValues( *other.value_.map_ );
+      break;
+#else
+   case arrayValue:
+      value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ );
+      break;
+   case objectValue:
+      value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ );
+      break;
+#endif
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   if ( other.comments_ )
+   {
+      comments_ = new CommentInfo[numberOfCommentPlacement];
+      for ( int comment =0; comment < numberOfCommentPlacement; ++comment )
+      {
+         const CommentInfo &otherComment = other.comments_[comment];
+         if ( otherComment.comment_ )
+            comments_[comment].setComment( otherComment.comment_ );
+      }
+   }
+}
+
+
+Value::~Value()
+{
+   switch ( type_ )
+   {
+   case nullValue:
+   case intValue:
+   case uintValue:
+   case realValue:
+   case booleanValue:
+      break;
+   case stringValue:
+      if ( allocated_ )
+         valueAllocator()->releaseStringValue( value_.string_ );
+      break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+   case objectValue:
+      delete value_.map_;
+      break;
+#else
+   case arrayValue:
+      arrayAllocator()->destructArray( value_.array_ );
+      break;
+   case objectValue:
+      mapAllocator()->destructMap( value_.map_ );
+      break;
+#endif
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+
+   if ( comments_ )
+      delete[] comments_;
+}
+
+Value &
+Value::operator=( const Value &other )
+{
+   Value temp( other );
+   swap( temp );
+   return *this;
+}
+
+void
+Value::swap( Value &other )
+{
+   ValueType temp = type_;
+   type_ = other.type_;
+   other.type_ = temp;
+   std::swap( value_, other.value_ );
+   int temp2 = allocated_;
+   allocated_ = other.allocated_;
+   other.allocated_ = temp2;
+}
+
+ValueType
+Value::type() const
+{
+   return type_;
+}
+
+
+int
+Value::compare( const Value &other )
+{
+   /*
+   int typeDelta = other.type_ - type_;
+   switch ( type_ )
+   {
+   case nullValue:
+
+      return other.type_ == type_;
+   case intValue:
+      if ( other.type_.isNumeric()
+   case uintValue:
+   case realValue:
+   case booleanValue:
+      break;
+   case stringValue,
+      break;
+   case arrayValue:
+      delete value_.array_;
+      break;
+   case objectValue:
+      delete value_.map_;
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   */
+   return 0;  // unreachable
+}
+
+bool
+Value::operator <( const Value &other ) const
+{
+   int typeDelta = type_ - other.type_;
+   if ( typeDelta )
+      return typeDelta < 0 ? true : false;
+   switch ( type_ )
+   {
+   case nullValue:
+      return false;
+   case intValue:
+      return value_.int_ < other.value_.int_;
+   case uintValue:
+      return value_.uint_ < other.value_.uint_;
+   case realValue:
+      return value_.real_ < other.value_.real_;
+   case booleanValue:
+      return value_.bool_ < other.value_.bool_;
+   case stringValue:
+      return ( value_.string_ == 0  &&  other.value_.string_ )
+             || ( other.value_.string_
+                  &&  value_.string_
+                  && strcmp( value_.string_, other.value_.string_ ) < 0 );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+   case objectValue:
+      {
+         int delta = int( value_.map_->size() - other.value_.map_->size() );
+         if ( delta )
+            return delta < 0;
+         return (*value_.map_) < (*other.value_.map_);
+      }
+#else
+   case arrayValue:
+      return value_.array_->compare( *(other.value_.array_) ) < 0;
+   case objectValue:
+      return value_.map_->compare( *(other.value_.map_) ) < 0;
+#endif
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   return 0;  // unreachable
+}
+
+bool
+Value::operator <=( const Value &other ) const
+{
+   return !(other > *this);
+}
+
+bool
+Value::operator >=( const Value &other ) const
+{
+   return !(*this < other);
+}
+
+bool
+Value::operator >( const Value &other ) const
+{
+   return other < *this;
+}
+
+bool
+Value::operator ==( const Value &other ) const
+{
+   //if ( type_ != other.type_ )
+   // GCC 2.95.3 says:
+   // attempt to take address of bit-field structure member `Json::Value::type_'
+   // Beats me, but a temp solves the problem.
+   int temp = other.type_;
+   if ( type_ != temp )
+      return false;
+   switch ( type_ )
+   {
+   case nullValue:
+      return true;
+   case intValue:
+      return value_.int_ == other.value_.int_;
+   case uintValue:
+      return value_.uint_ == other.value_.uint_;
+   case realValue:
+      return value_.real_ == other.value_.real_;
+   case booleanValue:
+      return value_.bool_ == other.value_.bool_;
+   case stringValue:
+      return ( value_.string_ == other.value_.string_ )
+             || ( other.value_.string_
+                  &&  value_.string_
+                  && strcmp( value_.string_, other.value_.string_ ) == 0 );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+   case objectValue:
+      return value_.map_->size() == other.value_.map_->size()
+             && (*value_.map_) == (*other.value_.map_);
+#else
+   case arrayValue:
+      return value_.array_->compare( *(other.value_.array_) ) == 0;
+   case objectValue:
+      return value_.map_->compare( *(other.value_.map_) ) == 0;
+#endif
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   return 0;  // unreachable
+}
+
+bool
+Value::operator !=( const Value &other ) const
+{
+   return !( *this == other );
+}
+
+const char *
+Value::asCString() const
+{
+   JSON_ASSERT( type_ == stringValue );
+   return value_.string_;
+}
+
+
+std::string
+Value::asString() const
+{
+   switch ( type_ )
+   {
+   case nullValue:
+      return "";
+   case stringValue:
+      return value_.string_ ? value_.string_ : "";
+   case booleanValue:
+      return value_.bool_ ? "true" : "false";
+   case intValue:
+   case uintValue:
+   case realValue:
+   case arrayValue:
+   case objectValue:
+      JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" );
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   return ""; // unreachable
+}
+
+# ifdef JSON_USE_CPPTL
+CppTL::ConstString
+Value::asConstString() const
+{
+   return CppTL::ConstString( asString().c_str() );
+}
+# endif
+
+Value::Int
+Value::asInt() const
+{
+   switch ( type_ )
+   {
+   case nullValue:
+      return 0;
+   case intValue:
+      return value_.int_;
+   case uintValue:
+      JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" );
+      return value_.uint_;
+   case realValue:
+      JSON_ASSERT_MESSAGE( value_.real_ >= minInt  &&  value_.real_ <= maxInt, "Real out of signed integer range" );
+      return Int( value_.real_ );
+   case booleanValue:
+      return value_.bool_ ? 1 : 0;
+   case stringValue:
+   case arrayValue:
+   case objectValue:
+      JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" );
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   return 0; // unreachable;
+}
+
+Value::UInt
+Value::asUInt() const
+{
+   switch ( type_ )
+   {
+   case nullValue:
+      return 0;
+   case intValue:
+      JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" );
+      return value_.int_;
+   case uintValue:
+      return value_.uint_;
+   case realValue:
+      JSON_ASSERT_MESSAGE( value_.real_ >= 0  &&  value_.real_ <= maxUInt,  "Real out of unsigned integer range" );
+      return UInt( value_.real_ );
+   case booleanValue:
+      return value_.bool_ ? 1 : 0;
+   case stringValue:
+   case arrayValue:
+   case objectValue:
+      JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" );
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   return 0; // unreachable;
+}
+
+double
+Value::asDouble() const
+{
+   switch ( type_ )
+   {
+   case nullValue:
+      return 0.0;
+   case intValue:
+      return value_.int_;
+   case uintValue:
+      return value_.uint_;
+   case realValue:
+      return value_.real_;
+   case booleanValue:
+      return value_.bool_ ? 1.0 : 0.0;
+   case stringValue:
+   case arrayValue:
+   case objectValue:
+      JSON_ASSERT_MESSAGE( false, "Type is not convertible to double" );
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   return 0; // unreachable;
+}
+
+bool
+Value::asBool() const
+{
+   switch ( type_ )
+   {
+   case nullValue:
+      return false;
+   case intValue:
+   case uintValue:
+      return value_.int_ != 0;
+   case realValue:
+      return value_.real_ != 0.0;
+   case booleanValue:
+      return value_.bool_;
+   case stringValue:
+      return value_.string_  &&  value_.string_[0] != 0;
+   case arrayValue:
+   case objectValue:
+      return value_.map_->size() != 0;
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   return false; // unreachable;
+}
+
+
+bool
+Value::isConvertibleTo( ValueType other ) const
+{
+   switch ( type_ )
+   {
+   case nullValue:
+      return true;
+   case intValue:
+      return ( other == nullValue  &&  value_.int_ == 0 )
+             || other == intValue
+             || ( other == uintValue  && value_.int_ >= 0 )
+             || other == realValue
+             || other == stringValue
+             || other == booleanValue;
+   case uintValue:
+      return ( other == nullValue  &&  value_.uint_ == 0 )
+             || ( other == intValue  && value_.uint_ <= (unsigned)maxInt )
+             || other == uintValue
+             || other == realValue
+             || other == stringValue
+             || other == booleanValue;
+   case realValue:
+      return ( other == nullValue  &&  value_.real_ == 0.0 )
+             || ( other == intValue  &&  value_.real_ >= minInt  &&  value_.real_ <= maxInt )
+             || ( other == uintValue  &&  value_.real_ >= 0  &&  value_.real_ <= maxUInt )
+             || other == realValue
+             || other == stringValue
+             || other == booleanValue;
+   case booleanValue:
+      return ( other == nullValue  &&  value_.bool_ == false )
+             || other == intValue
+             || other == uintValue
+             || other == realValue
+             || other == stringValue
+             || other == booleanValue;
+   case stringValue:
+      return other == stringValue
+             || ( other == nullValue  &&  (!value_.string_  ||  value_.string_[0] == 0) );
+   case arrayValue:
+      return other == arrayValue
+             ||  ( other == nullValue  &&  value_.map_->size() == 0 );
+   case objectValue:
+      return other == objectValue
+             ||  ( other == nullValue  &&  value_.map_->size() == 0 );
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   return false; // unreachable;
+}
+
+
+/// Number of values in array or object
+Value::UInt
+Value::size() const
+{
+   switch ( type_ )
+   {
+   case nullValue:
+   case intValue:
+   case uintValue:
+   case realValue:
+   case booleanValue:
+   case stringValue:
+      return 0;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:  // size of the array is highest index + 1
+      if ( !value_.map_->empty() )
+      {
+         ObjectValues::const_iterator itLast = value_.map_->end();
+         --itLast;
+         return (*itLast).first.index()+1;
+      }
+      return 0;
+   case objectValue:
+      return Int( value_.map_->size() );
+#else
+   case arrayValue:
+      return Int( value_.array_->size() );
+   case objectValue:
+      return Int( value_.map_->size() );
+#endif
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   return 0; // unreachable;
+}
+
+
+bool
+Value::empty() const
+{
+   if ( isNull() || isArray() || isObject() )
+      return size() == 0u;
+   else
+      return false;
+}
+
+
+bool
+Value::operator!() const
+{
+   return isNull();
+}
+
+
+void
+Value::clear()
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue  || type_ == objectValue );
+
+   switch ( type_ )
+   {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+   case objectValue:
+      value_.map_->clear();
+      break;
+#else
+   case arrayValue:
+      value_.array_->clear();
+      break;
+   case objectValue:
+      value_.map_->clear();
+      break;
+#endif
+   default:
+      break;
+   }
+}
+
+void
+Value::resize( UInt newSize )
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue );
+   if ( type_ == nullValue )
+      *this = Value( arrayValue );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   UInt oldSize = size();
+   if ( newSize == 0 )
+      clear();
+   else if ( newSize > oldSize )
+      (*this)[ newSize - 1 ];
+   else
+   {
+      for ( UInt index = newSize; index < oldSize; ++index )
+         value_.map_->erase( index );
+      assert( size() == newSize );
+   }
+#else
+   value_.array_->resize( newSize );
+#endif
+}
+
+
+Value &
+Value::operator[]( UInt index )
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue );
+   if ( type_ == nullValue )
+      *this = Value( arrayValue );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   CZString key( index );
+   ObjectValues::iterator it = value_.map_->lower_bound( key );
+   if ( it != value_.map_->end()  &&  (*it).first == key )
+      return (*it).second;
+
+   ObjectValues::value_type defaultValue( key, null );
+   it = value_.map_->insert( it, defaultValue );
+   return (*it).second;
+#else
+   return value_.array_->resolveReference( index );
+#endif
+}
+
+
+const Value &
+Value::operator[]( UInt index ) const
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue );
+   if ( type_ == nullValue )
+      return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   CZString key( index );
+   ObjectValues::const_iterator it = value_.map_->find( key );
+   if ( it == value_.map_->end() )
+      return null;
+   return (*it).second;
+#else
+   Value *value = value_.array_->find( index );
+   return value ? *value : null;
+#endif
+}
+
+
+Value &
+Value::operator[]( const char *key )
+{
+   return resolveReference( key, false );
+}
+
+
+Value &
+Value::resolveReference( const char *key,
+                         bool isStatic )
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );
+   if ( type_ == nullValue )
+      *this = Value( objectValue );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   CZString actualKey( key, isStatic ? CZString::noDuplication
+                                     : CZString::duplicateOnCopy );
+   ObjectValues::iterator it = value_.map_->lower_bound( actualKey );
+   if ( it != value_.map_->end()  &&  (*it).first == actualKey )
+      return (*it).second;
+
+   ObjectValues::value_type defaultValue( actualKey, null );
+   it = value_.map_->insert( it, defaultValue );
+   Value &value = (*it).second;
+   return value;
+#else
+   return value_.map_->resolveReference( key, isStatic );
+#endif
+}
+
+
+Value
+Value::get( UInt index,
+            const Value &defaultValue ) const
+{
+   const Value *value = &((*this)[index]);
+   return value == &null ? defaultValue : *value;
+}
+
+
+bool
+Value::isValidIndex( UInt index ) const
+{
+   return index < size();
+}
+
+
+
+const Value &
+Value::operator[]( const char *key ) const
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );
+   if ( type_ == nullValue )
+      return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   CZString actualKey( key, CZString::noDuplication );
+   ObjectValues::const_iterator it = value_.map_->find( actualKey );
+   if ( it == value_.map_->end() )
+      return null;
+   return (*it).second;
+#else
+   const Value *value = value_.map_->find( key );
+   return value ? *value : null;
+#endif
+}
+
+
+Value &
+Value::operator[]( const std::string &key )
+{
+   return (*this)[ key.c_str() ];
+}
+
+
+const Value &
+Value::operator[]( const std::string &key ) const
+{
+   return (*this)[ key.c_str() ];
+}
+
+Value &
+Value::operator[]( const StaticString &key )
+{
+   return resolveReference( key, true );
+}
+
+
+# ifdef JSON_USE_CPPTL
+Value &
+Value::operator[]( const CppTL::ConstString &key )
+{
+   return (*this)[ key.c_str() ];
+}
+
+
+const Value &
+Value::operator[]( const CppTL::ConstString &key ) const
+{
+   return (*this)[ key.c_str() ];
+}
+# endif
+
+
+Value &
+Value::append( const Value &value )
+{
+   return (*this)[size()] = value;
+}
+
+
+Value
+Value::get( const char *key,
+            const Value &defaultValue ) const
+{
+   const Value *value = &((*this)[key]);
+   return value == &null ? defaultValue : *value;
+}
+
+
+Value
+Value::get( const std::string &key,
+            const Value &defaultValue ) const
+{
+   return get( key.c_str(), defaultValue );
+}
+
+Value
+Value::removeMember( const char* key )
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );
+   if ( type_ == nullValue )
+      return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   CZString actualKey( key, CZString::noDuplication );
+   ObjectValues::iterator it = value_.map_->find( actualKey );
+   if ( it == value_.map_->end() )
+      return null;
+   Value old(it->second);
+   value_.map_->erase(it);
+   return old;
+#else
+   Value *value = value_.map_->find( key );
+   if (value){
+      Value old(*value);
+      value_.map_.remove( key );
+      return old;
+   } else {
+      return null;
+   }
+#endif
+}
+
+Value
+Value::removeMember( const std::string &key )
+{
+   return removeMember( key.c_str() );
+}
+
+# ifdef JSON_USE_CPPTL
+Value
+Value::get( const CppTL::ConstString &key,
+            const Value &defaultValue ) const
+{
+   return get( key.c_str(), defaultValue );
+}
+# endif
+
+bool
+Value::isMember( const char *key ) const
+{
+   const Value *value = &((*this)[key]);
+   return value != &null;
+}
+
+
+bool
+Value::isMember( const std::string &key ) const
+{
+   return isMember( key.c_str() );
+}
+
+
+# ifdef JSON_USE_CPPTL
+bool
+Value::isMember( const CppTL::ConstString &key ) const
+{
+   return isMember( key.c_str() );
+}
+#endif
+
+Value::Members
+Value::getMemberNames() const
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );
+   if ( type_ == nullValue )
+       return Value::Members();
+   Members members;
+   members.reserve( value_.map_->size() );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   ObjectValues::const_iterator it = value_.map_->begin();
+   ObjectValues::const_iterator itEnd = value_.map_->end();
+   for ( ; it != itEnd; ++it )
+      members.push_back( std::string( (*it).first.c_str() ) );
+#else
+   ValueInternalMap::IteratorState it;
+   ValueInternalMap::IteratorState itEnd;
+   value_.map_->makeBeginIterator( it );
+   value_.map_->makeEndIterator( itEnd );
+   for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) )
+      members.push_back( std::string( ValueInternalMap::key( it ) ) );
+#endif
+   return members;
+}
+//
+//# ifdef JSON_USE_CPPTL
+//EnumMemberNames
+//Value::enumMemberNames() const
+//{
+//   if ( type_ == objectValue )
+//   {
+//      return CppTL::Enum::any(  CppTL::Enum::transform(
+//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
+//         MemberNamesTransform() ) );
+//   }
+//   return EnumMemberNames();
+//}
+//
+//
+//EnumValues
+//Value::enumValues() const
+//{
+//   if ( type_ == objectValue  ||  type_ == arrayValue )
+//      return CppTL::Enum::anyValues( *(value_.map_),
+//                                     CppTL::Type<const Value &>() );
+//   return EnumValues();
+//}
+//
+//# endif
+
+
+bool
+Value::isNull() const
+{
+   return type_ == nullValue;
+}
+
+
+bool
+Value::isBool() const
+{
+   return type_ == booleanValue;
+}
+
+
+bool
+Value::isInt() const
+{
+   return type_ == intValue;
+}
+
+
+bool
+Value::isUInt() const
+{
+   return type_ == uintValue;
+}
+
+
+bool
+Value::isIntegral() const
+{
+   return type_ == intValue
+          ||  type_ == uintValue
+          ||  type_ == booleanValue;
+}
+
+
+bool
+Value::isDouble() const
+{
+   return type_ == realValue;
+}
+
+
+bool
+Value::isNumeric() const
+{
+   return isIntegral() || isDouble();
+}
+
+
+bool
+Value::isString() const
+{
+   return type_ == stringValue;
+}
+
+
+bool
+Value::isArray() const
+{
+   return type_ == nullValue  ||  type_ == arrayValue;
+}
+
+
+bool
+Value::isObject() const
+{
+   return type_ == nullValue  ||  type_ == objectValue;
+}
+
+
+void
+Value::setComment( const char *comment,
+                   CommentPlacement placement )
+{
+   if ( !comments_ )
+      comments_ = new CommentInfo[numberOfCommentPlacement];
+   comments_[placement].setComment( comment );
+}
+
+
+void
+Value::setComment( const std::string &comment,
+                   CommentPlacement placement )
+{
+   setComment( comment.c_str(), placement );
+}
+
+
+bool
+Value::hasComment( CommentPlacement placement ) const
+{
+   return comments_ != 0  &&  comments_[placement].comment_ != 0;
+}
+
+std::string
+Value::getComment( CommentPlacement placement ) const
+{
+   if ( hasComment(placement) )
+      return comments_[placement].comment_;
+   return "";
+}
+
+
+std::string
+Value::toStyledString() const
+{
+   StyledWriter writer;
+   return writer.write( *this );
+}
+
+
+Value::const_iterator
+Value::begin() const
+{
+   switch ( type_ )
+   {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+      if ( value_.array_ )
+      {
+         ValueInternalArray::IteratorState it;
+         value_.array_->makeBeginIterator( it );
+         return const_iterator( it );
+      }
+      break;
+   case objectValue:
+      if ( value_.map_ )
+      {
+         ValueInternalMap::IteratorState it;
+         value_.map_->makeBeginIterator( it );
+         return const_iterator( it );
+      }
+      break;
+#else
+   case arrayValue:
+   case objectValue:
+      if ( value_.map_ )
+         return const_iterator( value_.map_->begin() );
+      break;
+#endif
+   default:
+      break;
+   }
+   return const_iterator();
+}
+
+Value::const_iterator
+Value::end() const
+{
+   switch ( type_ )
+   {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+      if ( value_.array_ )
+      {
+         ValueInternalArray::IteratorState it;
+         value_.array_->makeEndIterator( it );
+         return const_iterator( it );
+      }
+      break;
+   case objectValue:
+      if ( value_.map_ )
+      {
+         ValueInternalMap::IteratorState it;
+         value_.map_->makeEndIterator( it );
+         return const_iterator( it );
+      }
+      break;
+#else
+   case arrayValue:
+   case objectValue:
+      if ( value_.map_ )
+         return const_iterator( value_.map_->end() );
+      break;
+#endif
+   default:
+      break;
+   }
+   return const_iterator();
+}
+
+
+Value::iterator
+Value::begin()
+{
+   switch ( type_ )
+   {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+      if ( value_.array_ )
+      {
+         ValueInternalArray::IteratorState it;
+         value_.array_->makeBeginIterator( it );
+         return iterator( it );
+      }
+      break;
+   case objectValue:
+      if ( value_.map_ )
+      {
+         ValueInternalMap::IteratorState it;
+         value_.map_->makeBeginIterator( it );
+         return iterator( it );
+      }
+      break;
+#else
+   case arrayValue:
+   case objectValue:
+      if ( value_.map_ )
+         return iterator( value_.map_->begin() );
+      break;
+#endif
+   default:
+      break;
+   }
+   return iterator();
+}
+
+Value::iterator
+Value::end()
+{
+   switch ( type_ )
+   {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+      if ( value_.array_ )
+      {
+         ValueInternalArray::IteratorState it;
+         value_.array_->makeEndIterator( it );
+         return iterator( it );
+      }
+      break;
+   case objectValue:
+      if ( value_.map_ )
+      {
+         ValueInternalMap::IteratorState it;
+         value_.map_->makeEndIterator( it );
+         return iterator( it );
+      }
+      break;
+#else
+   case arrayValue:
+   case objectValue:
+      if ( value_.map_ )
+         return iterator( value_.map_->end() );
+      break;
+#endif
+   default:
+      break;
+   }
+   return iterator();
+}
+
+
+// class PathArgument
+// //////////////////////////////////////////////////////////////////
+
+PathArgument::PathArgument()
+   : kind_( kindNone )
+{
+}
+
+
+PathArgument::PathArgument( Value::UInt index )
+   : index_( index )
+   , kind_( kindIndex )
+{
+}
+
+
+PathArgument::PathArgument( const char *key )
+   : key_( key )
+   , kind_( kindKey )
+{
+}
+
+
+PathArgument::PathArgument( const std::string &key )
+   : key_( key.c_str() )
+   , kind_( kindKey )
+{
+}
+
+// class Path
+// //////////////////////////////////////////////////////////////////
+
+Path::Path( const std::string &path,
+            const PathArgument &a1,
+            const PathArgument &a2,
+            const PathArgument &a3,
+            const PathArgument &a4,
+            const PathArgument &a5 )
+{
+   InArgs in;
+   in.push_back( &a1 );
+   in.push_back( &a2 );
+   in.push_back( &a3 );
+   in.push_back( &a4 );
+   in.push_back( &a5 );
+   makePath( path, in );
+}
+
+
+void
+Path::makePath( const std::string &path,
+                const InArgs &in )
+{
+   const char *current = path.c_str();
+   const char *end = current + path.length();
+   InArgs::const_iterator itInArg = in.begin();
+   while ( current != end )
+   {
+      if ( *current == '[' )
+      {
+         ++current;
+         if ( *current == '%' )
+            addPathInArg( path, in, itInArg, PathArgument::kindIndex );
+         else
+         {
+            Value::UInt index = 0;
+            for ( ; current != end && *current >= '0'  &&  *current <= '9'; ++current )
+               index = index * 10 + Value::UInt(*current - '0');
+            args_.push_back( index );
+         }
+         if ( current == end  ||  *current++ != ']' )
+            invalidPath( path, int(current - path.c_str()) );
+      }
+      else if ( *current == '%' )
+      {
+         addPathInArg( path, in, itInArg, PathArgument::kindKey );
+         ++current;
+      }
+      else if ( *current == '.' )
+      {
+         ++current;
+      }
+      else
+      {
+         const char *beginName = current;
+         while ( current != end  &&  !strchr( "[.", *current ) )
+            ++current;
+         args_.push_back( std::string( beginName, current ) );
+      }
+   }
+}
+
+
+void
+Path::addPathInArg( const std::string &path,
+                    const InArgs &in,
+                    InArgs::const_iterator &itInArg,
+                    PathArgument::Kind kind )
+{
+   if ( itInArg == in.end() )
+   {
+      // Error: missing argument %d
+   }
+   else if ( (*itInArg)->kind_ != kind )
+   {
+      // Error: bad argument type
+   }
+   else
+   {
+      args_.push_back( **itInArg );
+   }
+}
+
+
+void
+Path::invalidPath( const std::string &path,
+                   int location )
+{
+   // Error: invalid path.
+}
+
+
+const Value &
+Path::resolve( const Value &root ) const
+{
+   const Value *node = &root;
+   for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )
+   {
+      const PathArgument &arg = *it;
+      if ( arg.kind_ == PathArgument::kindIndex )
+      {
+         if ( !node->isArray()  ||  node->isValidIndex( arg.index_ ) )
+         {
+            // Error: unable to resolve path (array value expected at position...
+         }
+         node = &((*node)[arg.index_]);
+      }
+      else if ( arg.kind_ == PathArgument::kindKey )
+      {
+         if ( !node->isObject() )
+         {
+            // Error: unable to resolve path (object value expected at position...)
+         }
+         node = &((*node)[arg.key_]);
+         if ( node == &Value::null )
+         {
+            // Error: unable to resolve path (object has no member named '' at position...)
+         }
+      }
+   }
+   return *node;
+}
+
+
+Value
+Path::resolve( const Value &root,
+               const Value &defaultValue ) const
+{
+   const Value *node = &root;
+   for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )
+   {
+      const PathArgument &arg = *it;
+      if ( arg.kind_ == PathArgument::kindIndex )
+      {
+         if ( !node->isArray()  ||  node->isValidIndex( arg.index_ ) )
+            return defaultValue;
+         node = &((*node)[arg.index_]);
+      }
+      else if ( arg.kind_ == PathArgument::kindKey )
+      {
+         if ( !node->isObject() )
+            return defaultValue;
+         node = &((*node)[arg.key_]);
+         if ( node == &Value::null )
+            return defaultValue;
+      }
+   }
+   return *node;
+}
+
+
+Value &
+Path::make( Value &root ) const
+{
+   Value *node = &root;
+   for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )
+   {
+      const PathArgument &arg = *it;
+      if ( arg.kind_ == PathArgument::kindIndex )
+      {
+         if ( !node->isArray() )
+         {
+            // Error: node is not an array at position ...
+         }
+         node = &((*node)[arg.index_]);
+      }
+      else if ( arg.kind_ == PathArgument::kindKey )
+      {
+         if ( !node->isObject() )
+         {
+            // Error: node is not an object at position...
+         }
+         node = &((*node)[arg.key_]);
+      }
+   }
+   return *node;
+}
+
+
+} // namespace Json
diff --git a/final/lib/External/JSON/json_valueiterator.inl b/final/lib/External/JSON/json_valueiterator.inl
new file mode 100644
index 0000000..736e260
--- /dev/null
+++ b/final/lib/External/JSON/json_valueiterator.inl
@@ -0,0 +1,292 @@
+// included by json_value.cpp
+// everything is within Json namespace
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIteratorBase
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIteratorBase::ValueIteratorBase()
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   : current_()
+   , isNull_( true )
+{
+}
+#else
+   : isArray_( true )
+   , isNull_( true )
+{
+   iterator_.array_ = ValueInternalArray::IteratorState();
+}
+#endif
+
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator &current )
+   : current_( current )
+   , isNull_( false )
+{
+}
+#else
+ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state )
+   : isArray_( true )
+{
+   iterator_.array_ = state;
+}
+
+
+ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state )
+   : isArray_( false )
+{
+   iterator_.map_ = state;
+}
+#endif
+
+Value &
+ValueIteratorBase::deref() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   return current_->second;
+#else
+   if ( isArray_ )
+      return ValueInternalArray::dereference( iterator_.array_ );
+   return ValueInternalMap::value( iterator_.map_ );
+#endif
+}
+
+
+void 
+ValueIteratorBase::increment()
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   ++current_;
+#else
+   if ( isArray_ )
+      ValueInternalArray::increment( iterator_.array_ );
+   ValueInternalMap::increment( iterator_.map_ );
+#endif
+}
+
+
+void 
+ValueIteratorBase::decrement()
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   --current_;
+#else
+   if ( isArray_ )
+      ValueInternalArray::decrement( iterator_.array_ );
+   ValueInternalMap::decrement( iterator_.map_ );
+#endif
+}
+
+
+ValueIteratorBase::difference_type 
+ValueIteratorBase::computeDistance( const SelfType &other ) const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+# ifdef JSON_USE_CPPTL_SMALLMAP
+   return current_ - other.current_;
+# else
+   // Iterator for null value are initialized using the default
+   // constructor, which initialize current_ to the default
+   // std::map::iterator. As begin() and end() are two instance 
+   // of the default std::map::iterator, they can not be compared.
+   // To allow this, we handle this comparison specifically.
+   if ( isNull_  &&  other.isNull_ )
+   {
+      return 0;
+   }
+
+
+   // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,
+   // which is the one used by default).
+   // Using a portable hand-made version for non random iterator instead:
+   //   return difference_type( std::distance( current_, other.current_ ) );
+   difference_type myDistance = 0;
+   for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )
+   {
+      ++myDistance;
+   }
+   return myDistance;
+# endif
+#else
+   if ( isArray_ )
+      return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ );
+   return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ );
+#endif
+}
+
+
+bool 
+ValueIteratorBase::isEqual( const SelfType &other ) const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   if ( isNull_ )
+   {
+      return other.isNull_;
+   }
+   return current_ == other.current_;
+#else
+   if ( isArray_ )
+      return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ );
+   return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ );
+#endif
+}
+
+
+void 
+ValueIteratorBase::copy( const SelfType &other )
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   current_ = other.current_;
+#else
+   if ( isArray_ )
+      iterator_.array_ = other.iterator_.array_;
+   iterator_.map_ = other.iterator_.map_;
+#endif
+}
+
+
+Value 
+ValueIteratorBase::key() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   const Value::CZString czstring = (*current_).first;
+   if ( czstring.c_str() )
+   {
+      if ( czstring.isStaticString() )
+         return Value( StaticString( czstring.c_str() ) );
+      return Value( czstring.c_str() );
+   }
+   return Value( czstring.index() );
+#else
+   if ( isArray_ )
+      return Value( ValueInternalArray::indexOf( iterator_.array_ ) );
+   bool isStatic;
+   const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic );
+   if ( isStatic )
+      return Value( StaticString( memberName ) );
+   return Value( memberName );
+#endif
+}
+
+
+UInt 
+ValueIteratorBase::index() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   const Value::CZString czstring = (*current_).first;
+   if ( !czstring.c_str() )
+      return czstring.index();
+   return Value::UInt( -1 );
+#else
+   if ( isArray_ )
+      return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) );
+   return Value::UInt( -1 );
+#endif
+}
+
+
+const char *
+ValueIteratorBase::memberName() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   const char *name = (*current_).first.c_str();
+   return name ? name : "";
+#else
+   if ( !isArray_ )
+      return ValueInternalMap::key( iterator_.map_ );
+   return "";
+#endif
+}
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueConstIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueConstIterator::ValueConstIterator()
+{
+}
+
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator &current )
+   : ValueIteratorBase( current )
+{
+}
+#else
+ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state )
+   : ValueIteratorBase( state )
+{
+}
+
+ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state )
+   : ValueIteratorBase( state )
+{
+}
+#endif
+
+ValueConstIterator &
+ValueConstIterator::operator =( const ValueIteratorBase &other )
+{
+   copy( other );
+   return *this;
+}
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIterator::ValueIterator()
+{
+}
+
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueIterator::ValueIterator( const Value::ObjectValues::iterator &current )
+   : ValueIteratorBase( current )
+{
+}
+#else
+ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state )
+   : ValueIteratorBase( state )
+{
+}
+
+ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state )
+   : ValueIteratorBase( state )
+{
+}
+#endif
+
+ValueIterator::ValueIterator( const ValueConstIterator &other )
+   : ValueIteratorBase( other )
+{
+}
+
+ValueIterator::ValueIterator( const ValueIterator &other )
+   : ValueIteratorBase( other )
+{
+}
+
+ValueIterator &
+ValueIterator::operator =( const SelfType &other )
+{
+   copy( other );
+   return *this;
+}
diff --git a/final/lib/External/JSON/json_writer.cpp b/final/lib/External/JSON/json_writer.cpp
new file mode 100644
index 0000000..e1934bb
--- /dev/null
+++ b/final/lib/External/JSON/json_writer.cpp
@@ -0,0 +1,829 @@
+#include <json/writer.h>
+#include <utility>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+#if _MSC_VER >= 1400 // VC++ 8.0
+#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.
+#endif
+
+namespace Json {
+
+static bool isControlCharacter(char ch)
+{
+   return ch > 0 && ch <= 0x1F;
+}
+
+static bool containsControlCharacter( const char* str )
+{
+   while ( *str ) 
+   {
+      if ( isControlCharacter( *(str++) ) )
+         return true;
+   }
+   return false;
+}
+static void uintToString( unsigned int value, 
+                          char *&current )
+{
+   *--current = 0;
+   do
+   {
+      *--current = (value % 10) + '0';
+      value /= 10;
+   }
+   while ( value != 0 );
+}
+
+std::string valueToString( Int value )
+{
+   char buffer[32];
+   char *current = buffer + sizeof(buffer);
+   bool isNegative = value < 0;
+   if ( isNegative )
+      value = -value;
+   uintToString( UInt(value), current );
+   if ( isNegative )
+      *--current = '-';
+   assert( current >= buffer );
+   return current;
+}
+
+
+std::string valueToString( UInt value )
+{
+   char buffer[32];
+   char *current = buffer + sizeof(buffer);
+   uintToString( value, current );
+   assert( current >= buffer );
+   return current;
+}
+
+std::string valueToString( double value )
+{
+   char buffer[32];
+#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. 
+   sprintf_s(buffer, sizeof(buffer), "%#.16g", value); 
+#else	
+   sprintf(buffer, "%#.16g", value); 
+#endif
+   char* ch = buffer + strlen(buffer) - 1;
+   if (*ch != '0') return buffer; // nothing to truncate, so save time
+   while(ch > buffer && *ch == '0'){
+     --ch;
+   }
+   char* last_nonzero = ch;
+   while(ch >= buffer){
+     switch(*ch){
+     case '0':
+     case '1':
+     case '2':
+     case '3':
+     case '4':
+     case '5':
+     case '6':
+     case '7':
+     case '8':
+     case '9':
+       --ch;
+       continue;
+     case '.':
+       // Truncate zeroes to save bytes in output, but keep one.
+       *(last_nonzero+2) = '\0';
+       return buffer;
+     default:
+       return buffer;
+     }
+   }
+   return buffer;
+}
+
+
+std::string valueToString( bool value )
+{
+   return value ? "true" : "false";
+}
+
+std::string valueToQuotedString( const char *value )
+{
+   // Not sure how to handle unicode...
+   if (strpbrk(value, "\"\\\b\f\n\r\t") == nullptr && !containsControlCharacter( value ))
+      return std::string("\"") + value + "\"";
+   // We have to walk value and escape any special characters.
+   // Appending to std::string is not efficient, but this should be rare.
+   // (Note: forward slashes are *not* rare, but I am not escaping them.)
+   unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+nullptr
+   std::string result;
+   result.reserve(maxsize); // to avoid lots of mallocs
+   result += "\"";
+   for (const char* c = value; *c != 0; ++c)
+   {
+      switch(*c)
+      {
+         case '\"':
+            result += "\\\"";
+            break;
+         case '\\':
+            result += "\\\\";
+            break;
+         case '\b':
+            result += "\\b";
+            break;
+         case '\f':
+            result += "\\f";
+            break;
+         case '\n':
+            result += "\\n";
+            break;
+         case '\r':
+            result += "\\r";
+            break;
+         case '\t':
+            result += "\\t";
+            break;
+         //case '/':
+            // Even though \/ is considered a legal escape in JSON, a bare
+            // slash is also legal, so I see no reason to escape it.
+            // (I hope I am not misunderstanding something.
+            // blep notes: actually escaping \/ may be useful in javascript to avoid </ 
+            // sequence.
+            // Should add a flag to allow this compatibility mode and prevent this 
+            // sequence from occurring.
+         default:
+            if ( isControlCharacter( *c ) )
+            {
+               std::ostringstream oss;
+               oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
+               result += oss.str();
+            }
+            else
+            {
+               result += *c;
+            }
+            break;
+      }
+   }
+   result += "\"";
+   return result;
+}
+
+// Class Writer
+// //////////////////////////////////////////////////////////////////
+Writer::~Writer()
+{
+}
+
+
+// Class FastWriter
+// //////////////////////////////////////////////////////////////////
+
+FastWriter::FastWriter()
+   : yamlCompatiblityEnabled_( false )
+{
+}
+
+
+void 
+FastWriter::enableYAMLCompatibility()
+{
+   yamlCompatiblityEnabled_ = true;
+}
+
+
+std::string 
+FastWriter::write( const Value &root )
+{
+   document_ = "";
+   writeValue( root );
+   document_ += "\n";
+   return document_;
+}
+
+
+void 
+FastWriter::writeValue( const Value &value )
+{
+   switch ( value.type() )
+   {
+   case nullValue:
+      document_ += "null";
+      break;
+   case intValue:
+      document_ += valueToString( value.asInt() );
+      break;
+   case uintValue:
+      document_ += valueToString( value.asUInt() );
+      break;
+   case realValue:
+      document_ += valueToString( value.asDouble() );
+      break;
+   case stringValue:
+      document_ += valueToQuotedString( value.asCString() );
+      break;
+   case booleanValue:
+      document_ += valueToString( value.asBool() );
+      break;
+   case arrayValue:
+      {
+         document_ += "[";
+         int size = value.size();
+         for ( int index =0; index < size; ++index )
+         {
+            if ( index > 0 )
+               document_ += ",";
+            writeValue( value[index] );
+         }
+         document_ += "]";
+      }
+      break;
+   case objectValue:
+      {
+         Value::Members members( value.getMemberNames() );
+         document_ += "{";
+         for ( Value::Members::iterator it = members.begin(); 
+               it != members.end(); 
+               ++it )
+         {
+            const std::string &name = *it;
+            if ( it != members.begin() )
+               document_ += ",";
+            document_ += valueToQuotedString( name.c_str() );
+            document_ += yamlCompatiblityEnabled_ ? ": " 
+                                                  : ":";
+            writeValue( value[name] );
+         }
+         document_ += "}";
+      }
+      break;
+   }
+}
+
+
+// Class StyledWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledWriter::StyledWriter()
+   : rightMargin_( 74 )
+   , indentSize_( 3 )
+{
+}
+
+
+std::string 
+StyledWriter::write( const Value &root )
+{
+   document_ = "";
+   addChildValues_ = false;
+   indentString_ = "";
+   writeCommentBeforeValue( root );
+   writeValue( root );
+   writeCommentAfterValueOnSameLine( root );
+   document_ += "\n";
+   return document_;
+}
+
+
+void 
+StyledWriter::writeValue( const Value &value )
+{
+   switch ( value.type() )
+   {
+   case nullValue:
+      pushValue( "null" );
+      break;
+   case intValue:
+      pushValue( valueToString( value.asInt() ) );
+      break;
+   case uintValue:
+      pushValue( valueToString( value.asUInt() ) );
+      break;
+   case realValue:
+      pushValue( valueToString( value.asDouble() ) );
+      break;
+   case stringValue:
+      pushValue( valueToQuotedString( value.asCString() ) );
+      break;
+   case booleanValue:
+      pushValue( valueToString( value.asBool() ) );
+      break;
+   case arrayValue:
+      writeArrayValue( value);
+      break;
+   case objectValue:
+      {
+         Value::Members members( value.getMemberNames() );
+         if ( members.empty() )
+            pushValue( "{}" );
+         else
+         {
+            writeWithIndent( "{" );
+            indent();
+            Value::Members::iterator it = members.begin();
+            while ( true )
+            {
+               const std::string &name = *it;
+               const Value &childValue = value[name];
+               writeCommentBeforeValue( childValue );
+               writeWithIndent( valueToQuotedString( name.c_str() ) );
+               document_ += " : ";
+               writeValue( childValue );
+               if ( ++it == members.end() )
+               {
+                  writeCommentAfterValueOnSameLine( childValue );
+                  break;
+               }
+               document_ += ",";
+               writeCommentAfterValueOnSameLine( childValue );
+            }
+            unindent();
+            writeWithIndent( "}" );
+         }
+      }
+      break;
+   }
+}
+
+
+void 
+StyledWriter::writeArrayValue( const Value &value )
+{
+   unsigned size = value.size();
+   if ( size == 0 )
+      pushValue( "[]" );
+   else
+   {
+      bool isArrayMultiLine = isMultineArray( value );
+      if ( isArrayMultiLine )
+      {
+         writeWithIndent( "[" );
+         indent();
+         bool hasChildValue = !childValues_.empty();
+         unsigned index =0;
+         while ( true )
+         {
+            const Value &childValue = value[index];
+            writeCommentBeforeValue( childValue );
+            if ( hasChildValue )
+               writeWithIndent( childValues_[index] );
+            else
+            {
+               writeIndent();
+               writeValue( childValue );
+            }
+            if ( ++index == size )
+            {
+               writeCommentAfterValueOnSameLine( childValue );
+               break;
+            }
+            document_ += ",";
+            writeCommentAfterValueOnSameLine( childValue );
+         }
+         unindent();
+         writeWithIndent( "]" );
+      }
+      else // output on a single line
+      {
+         assert( childValues_.size() == size );
+         document_ += "[ ";
+         for ( unsigned index =0; index < size; ++index )
+         {
+            if ( index > 0 )
+               document_ += ", ";
+            document_ += childValues_[index];
+         }
+         document_ += " ]";
+      }
+   }
+}
+
+
+bool 
+StyledWriter::isMultineArray( const Value &value )
+{
+   int size = value.size();
+   bool isMultiLine = size*3 >= rightMargin_ ;
+   childValues_.clear();
+   for ( int index =0; index < size  &&  !isMultiLine; ++index )
+   {
+      const Value &childValue = value[index];
+      isMultiLine = isMultiLine  ||
+                     ( (childValue.isArray()  ||  childValue.isObject())  &&  
+                        childValue.size() > 0 );
+   }
+   if ( !isMultiLine ) // check if line length > max line length
+   {
+      childValues_.reserve( size );
+      addChildValues_ = true;
+      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
+      for ( int index =0; index < size  &&  !isMultiLine; ++index )
+      {
+         writeValue( value[index] );
+         lineLength += int( childValues_[index].length() );
+         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
+      }
+      addChildValues_ = false;
+      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
+   }
+   return isMultiLine;
+}
+
+
+void 
+StyledWriter::pushValue( const std::string &value )
+{
+   if ( addChildValues_ )
+      childValues_.push_back( value );
+   else
+      document_ += value;
+}
+
+
+void 
+StyledWriter::writeIndent()
+{
+   if ( !document_.empty() )
+   {
+      char last = document_[document_.length()-1];
+      if ( last == ' ' )     // already indented
+         return;
+      if ( last != '\n' )    // Comments may add new-line
+         document_ += '\n';
+   }
+   document_ += indentString_;
+}
+
+
+void 
+StyledWriter::writeWithIndent( const std::string &value )
+{
+   writeIndent();
+   document_ += value;
+}
+
+
+void 
+StyledWriter::indent()
+{
+   indentString_ += std::string( indentSize_, ' ' );
+}
+
+
+void 
+StyledWriter::unindent()
+{
+   assert( int(indentString_.size()) >= indentSize_ );
+   indentString_.resize( indentString_.size() - indentSize_ );
+}
+
+
+void 
+StyledWriter::writeCommentBeforeValue( const Value &root )
+{
+   if ( !root.hasComment( commentBefore ) )
+      return;
+   document_ += normalizeEOL( root.getComment( commentBefore ) );
+   document_ += "\n";
+}
+
+
+void 
+StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
+{
+   if ( root.hasComment( commentAfterOnSameLine ) )
+      document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
+
+   if ( root.hasComment( commentAfter ) )
+   {
+      document_ += "\n";
+      document_ += normalizeEOL( root.getComment( commentAfter ) );
+      document_ += "\n";
+   }
+}
+
+
+bool 
+StyledWriter::hasCommentForValue( const Value &value )
+{
+   return value.hasComment( commentBefore )
+          ||  value.hasComment( commentAfterOnSameLine )
+          ||  value.hasComment( commentAfter );
+}
+
+
+std::string 
+StyledWriter::normalizeEOL( const std::string &text )
+{
+   std::string normalized;
+   normalized.reserve( text.length() );
+   const char *begin = text.c_str();
+   const char *end = begin + text.length();
+   const char *current = begin;
+   while ( current != end )
+   {
+      char c = *current++;
+      if ( c == '\r' ) // mac or dos EOL
+      {
+         if ( *current == '\n' ) // convert dos EOL
+            ++current;
+         normalized += '\n';
+      }
+      else // handle unix EOL & other char
+         normalized += c;
+   }
+   return normalized;
+}
+
+
+// Class StyledStreamWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledStreamWriter::StyledStreamWriter( std::string indentation )
+   : document_(nullptr)
+   , rightMargin_( 74 )
+   , indentation_( indentation )
+{
+}
+
+
+void
+StyledStreamWriter::write( std::ostream &out, const Value &root )
+{
+   document_ = &out;
+   addChildValues_ = false;
+   indentString_ = "";
+   writeCommentBeforeValue( root );
+   writeValue( root );
+   writeCommentAfterValueOnSameLine( root );
+   *document_ << "\n";
+   document_ = nullptr; // Forget the stream, for safety.
+}
+
+
+void 
+StyledStreamWriter::writeValue( const Value &value )
+{
+   switch ( value.type() )
+   {
+   case nullValue:
+      pushValue( "null" );
+      break;
+   case intValue:
+      pushValue( valueToString( value.asInt() ) );
+      break;
+   case uintValue:
+      pushValue( valueToString( value.asUInt() ) );
+      break;
+   case realValue:
+      pushValue( valueToString( value.asDouble() ) );
+      break;
+   case stringValue:
+      pushValue( valueToQuotedString( value.asCString() ) );
+      break;
+   case booleanValue:
+      pushValue( valueToString( value.asBool() ) );
+      break;
+   case arrayValue:
+      writeArrayValue( value);
+      break;
+   case objectValue:
+      {
+         Value::Members members( value.getMemberNames() );
+         if ( members.empty() )
+            pushValue( "{}" );
+         else
+         {
+            writeWithIndent( "{" );
+            indent();
+            Value::Members::iterator it = members.begin();
+            while ( true )
+            {
+               const std::string &name = *it;
+               const Value &childValue = value[name];
+               writeCommentBeforeValue( childValue );
+               writeWithIndent( valueToQuotedString( name.c_str() ) );
+               *document_ << " : ";
+               writeValue( childValue );
+               if ( ++it == members.end() )
+               {
+                  writeCommentAfterValueOnSameLine( childValue );
+                  break;
+               }
+               *document_ << ",";
+               writeCommentAfterValueOnSameLine( childValue );
+            }
+            unindent();
+            writeWithIndent( "}" );
+         }
+      }
+      break;
+   }
+}
+
+
+void 
+StyledStreamWriter::writeArrayValue( const Value &value )
+{
+   unsigned size = value.size();
+   if ( size == 0 )
+      pushValue( "[]" );
+   else
+   {
+      bool isArrayMultiLine = isMultineArray( value );
+      if ( isArrayMultiLine )
+      {
+         writeWithIndent( "[" );
+         indent();
+         bool hasChildValue = !childValues_.empty();
+         unsigned index =0;
+         while ( true )
+         {
+            const Value &childValue = value[index];
+            writeCommentBeforeValue( childValue );
+            if ( hasChildValue )
+               writeWithIndent( childValues_[index] );
+            else
+            {
+	       writeIndent();
+               writeValue( childValue );
+            }
+            if ( ++index == size )
+            {
+               writeCommentAfterValueOnSameLine( childValue );
+               break;
+            }
+            *document_ << ",";
+            writeCommentAfterValueOnSameLine( childValue );
+         }
+         unindent();
+         writeWithIndent( "]" );
+      }
+      else // output on a single line
+      {
+         assert( childValues_.size() == size );
+         *document_ << "[ ";
+         for ( unsigned index =0; index < size; ++index )
+         {
+            if ( index > 0 )
+               *document_ << ", ";
+            *document_ << childValues_[index];
+         }
+         *document_ << " ]";
+      }
+   }
+}
+
+
+bool 
+StyledStreamWriter::isMultineArray( const Value &value )
+{
+   int size = value.size();
+   bool isMultiLine = size*3 >= rightMargin_ ;
+   childValues_.clear();
+   for ( int index =0; index < size  &&  !isMultiLine; ++index )
+   {
+      const Value &childValue = value[index];
+      isMultiLine = isMultiLine  ||
+                     ( (childValue.isArray()  ||  childValue.isObject())  &&  
+                        childValue.size() > 0 );
+   }
+   if ( !isMultiLine ) // check if line length > max line length
+   {
+      childValues_.reserve( size );
+      addChildValues_ = true;
+      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
+      for ( int index =0; index < size  &&  !isMultiLine; ++index )
+      {
+         writeValue( value[index] );
+         lineLength += int( childValues_[index].length() );
+         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
+      }
+      addChildValues_ = false;
+      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
+   }
+   return isMultiLine;
+}
+
+
+void 
+StyledStreamWriter::pushValue( const std::string &value )
+{
+   if ( addChildValues_ )
+      childValues_.push_back( value );
+   else
+      *document_ << value;
+}
+
+
+void 
+StyledStreamWriter::writeIndent()
+{
+  /*
+    Some comments in this method would have been nice. ;-)
+
+   if ( !document_.empty() )
+   {
+      char last = document_[document_.length()-1];
+      if ( last == ' ' )     // already indented
+         return;
+      if ( last != '\n' )    // Comments may add new-line
+         *document_ << '\n';
+   }
+  */
+   *document_ << '\n' << indentString_;
+}
+
+
+void 
+StyledStreamWriter::writeWithIndent( const std::string &value )
+{
+   writeIndent();
+   *document_ << value;
+}
+
+
+void 
+StyledStreamWriter::indent()
+{
+   indentString_ += indentation_;
+}
+
+
+void 
+StyledStreamWriter::unindent()
+{
+   assert( indentString_.size() >= indentation_.size() );
+   indentString_.resize( indentString_.size() - indentation_.size() );
+}
+
+
+void 
+StyledStreamWriter::writeCommentBeforeValue( const Value &root )
+{
+   if ( !root.hasComment( commentBefore ) )
+      return;
+   *document_ << normalizeEOL( root.getComment( commentBefore ) );
+   *document_ << "\n";
+}
+
+
+void 
+StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
+{
+   if ( root.hasComment( commentAfterOnSameLine ) )
+      *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
+
+   if ( root.hasComment( commentAfter ) )
+   {
+      *document_ << "\n";
+      *document_ << normalizeEOL( root.getComment( commentAfter ) );
+      *document_ << "\n";
+   }
+}
+
+
+bool 
+StyledStreamWriter::hasCommentForValue( const Value &value )
+{
+   return value.hasComment( commentBefore )
+          ||  value.hasComment( commentAfterOnSameLine )
+          ||  value.hasComment( commentAfter );
+}
+
+
+std::string 
+StyledStreamWriter::normalizeEOL( const std::string &text )
+{
+   std::string normalized;
+   normalized.reserve( text.length() );
+   const char *begin = text.c_str();
+   const char *end = begin + text.length();
+   const char *current = begin;
+   while ( current != end )
+   {
+      char c = *current++;
+      if ( c == '\r' ) // mac or dos EOL
+      {
+         if ( *current == '\n' ) // convert dos EOL
+            ++current;
+         normalized += '\n';
+      }
+      else // handle unix EOL & other char
+         normalized += c;
+   }
+   return normalized;
+}
+
+
+std::ostream& operator<<( std::ostream &sout, const Value &root )
+{
+   Json::StyledStreamWriter writer;
+   writer.write(sout, root);
+   return sout;
+}
+
+
+} // namespace Json
diff --git a/final/lib/External/JSON/sconscript b/final/lib/External/JSON/sconscript
new file mode 100644
index 0000000..6e7c6c8
--- /dev/null
+++ b/final/lib/External/JSON/sconscript
@@ -0,0 +1,8 @@
+Import( 'env buildLibrary' )
+
+buildLibrary( env, Split( """
+    json_reader.cpp 
+    json_value.cpp 
+    json_writer.cpp
+     """ ),
+    'json' )
diff --git a/final/lib/External/README.txt b/final/lib/External/README.txt
new file mode 100644
index 0000000..c99eda3
--- /dev/null
+++ b/final/lib/External/README.txt
@@ -0,0 +1,18 @@
+The libraries in this directory are mirrored from external projects.
+
+Patches to them should first be contributed upstream and then return to Polly
+as normal (re)imports of these updated libraries.
+
+We currently have the following external libraries.
+
+# isl
+License: MIT-STYLE
+Details: isl/LICENSE
+
+# imath
+License: MIT-STYLE
+Details: isl/imath/LICENSE
+
+To update these libraries run 'autoreconf -i && ./configure && make dist' in
+the isl git directory and move the resulting files into lib/External/isl.
+Alternatively, run the update-isl.sh script.
diff --git a/final/lib/External/isl/AUTHORS b/final/lib/External/isl/AUTHORS
new file mode 100644
index 0000000..975d5b6
--- /dev/null
+++ b/final/lib/External/isl/AUTHORS
@@ -0,0 +1,46 @@
+isl was written by
+
+	    Sven Verdoolaege
+2006-2007   Leiden Institute of Advanced Computer Science
+	    Universiteit Leiden
+	    Niels Bohrweg 1
+	    2333 CA Leiden
+	    The Netherlands
+2008-2009   K.U.Leuven
+	    Departement Computerwetenschappen
+	    Celestijnenlaan 200A
+	    B-3001 Leuven
+	    Belgium
+2010-2011   INRIA Saclay - Ile-de-France
+	    Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod
+	    91893 Orsay
+	    France
+2011-2012   consultant for Leiden Institute of Advanced Computer Science
+2012-2014   Ecole Normale Superieure
+	    45 rue d'Ulm, 75230 Paris
+	    France
+2014-2015   INRIA Rocquencourt
+	    Domaine de Voluceau - Rocquencourt, B.P. 105
+	    78153 Le Chesnay
+	    France
+2015-2016   Polly Labs
+
+Contributions by
+
+Mythri Alle
+Riyadh Baghdadi
+Serge Belyshev
+Ray Donnelly
+Johannes Doerfert
+Tobias Grosser
+Alexandre Isoard
+Andreas Kloeckner
+Michael Kruse
+Sebastian Pop
+Louis-Noel Pouchet
+Benoit Pradelle
+Uday Kumar Reddy
+Andreas Simbuerger
+Sven van Haastregt
+
+The merge sort implementation was written by Jeffrey Stedfast.
diff --git a/final/lib/External/isl/ChangeLog b/final/lib/External/isl/ChangeLog
new file mode 100644
index 0000000..249acdf
--- /dev/null
+++ b/final/lib/External/isl/ChangeLog
@@ -0,0 +1,193 @@
+version: 0.18
+date: Sun Dec 18 11:01:58 CET 2016
+changes:
+	- improve elimination of redundant existentially quantified variables
+	- improve coalescing
+	- improve parametric integer programming
+	- preserve isolate option in isl_schedule_node_band_split
+	- print AST nodes in YAML format
+	- minor improvements to Python bindings
+---
+version: 0.17.1
+date: Fri May  6 12:02:48 CEST 2016
+changes:
+	- fix bug in coalescing treatment
+---
+version: 0.17
+date: Tue May  3 14:26:43 CEST 2016
+changes:
+	- optionally combine SCCs incrementally in scheduler
+	- optionally maximize coincidence in scheduler
+	- optionally avoid loop coalescing in scheduler
+	- fix handling of nested integer divisions
+	- optionally detect min/max expressions during AST generation
+	- minor AST generator improvements
+	- simplify stride constraints
+	- improve support for expansions in schedule trees
+---
+version: 0.16.1
+date: Thu Jan 14 18:08:06 CET 2016
+changes:
+	- fix bug in simplification
+---
+version: 0.16
+date: Tue Jan 12 09:56:16 CET 2016
+changes:
+	- add 32 bit integer optimization for IMath
+	- minor AST generator improvements
+	- add isl_union_flow_get_full_{may,must}_dependence
+	- minor improvements to Python bindings
+	- minor improvements to set and map printing
+---
+version: 0.15
+date: Thu Jun 11 12:45:33 CEST 2015
+changes:
+	- improve coalescing
+	- add isl_union_access_info_compute_flow
+	- add mark nodes in AST
+	- add isl_union_pw_aff and isl_multi_union_pw_aff
+	- add schedule trees
+	- deprecate band forests
+	- deprecate separation_class AST generation option
+	- introduce isl_bool and isl_stat types
+---
+version: 0.14.1
+date: Thu Apr  9 12:57:23 CEST 2015
+changes:
+	- fix bug in affine expression normalization
+	- fix handling of conditional validity constraints
+---
+version: 0.14
+date: Sat Oct 25 16:08:47 CEST 2014
+changes:
+	- support IMath as an optional replacement for GMP
+	- minor AST generator improvements
+---
+version: 0.13
+date: Mon Apr 14 11:08:45 CEST 2014
+changes:
+	- deprecate isl_int
+	- improved support for multi piecewise quasi-affine expressions
+	- allow the user to impose a bound on the number of low-level operations
+	- add isl_id_to_ast_expr and isl_id_to_pw_aff
+	- add isl_schedule_constraints
+	- hide internal structure of isl_vec
+	- remove support for piplib
+---
+version: 0.12.2
+date: Sun Jan 12 12:09:46 CET 2014
+changes:
+	- MinGW-w64 build fix
+	- fix simplification bug
+---
+version: 0.12.1
+date: Wed Jul 24 12:54:46 CEST 2013
+changes:
+	- handle malloc returning NULL on zero-size allocation
+	- fix regression in AST generator
+---
+version: 0.12
+date: Sun Jun 23 20:23:05 CEST 2013
+changes:
+	- add isl_val abstraction
+---
+version: 0.11.2
+date: Tue Apr  9 18:45:10 CEST 2013
+changes:
+	- make code generation output the same on Solaris
+	- fix some hard to trigger bugs
+---
+version: 0.11.1
+date: Mon Dec 10 11:55:30 CET 2012
+changes:
+	- add LICENSE file to distribution
+	- make code generation output independent of endianness
+---
+version: 0.11
+date: Mon Dec  3 08:17:18 CET 2012
+changes:
+	- change license from LGPL 2.1 to MIT
+	- add support for multi piecewise quasi-affine expressions
+	- add code generation
+	- various minor bug fixes
+---
+version: 0.10
+date: Sun Jun  3 18:00:16 CEST 2012
+changes:
+	- support for interaction with dependence analysis
+	- add public API for vectors
+	- improved support for (piecewise) multi quasi-affine expressions
+	- various minor bug fixes
+---
+version: 0.09
+date: Sat Dec 17 18:19:26 CET 2011
+changes:
+	- improved argument parsing
+	- hide internal structure of isl_options
+	- improved support for parameter sets
+	- configurable scheduling
+---
+version: 0.08
+date: Fri Oct 21 12:36:20 CEST 2011
+changes:
+	- improved parsing
+	- drop isl_div abstraction
+	- rename isl_dim to isl_space
+	- |-
+	  explicitly differentiate between spaces of maps,
+	  sets and parameter sets
+	- add support for identifiers
+	- add support for (piecewise) multi quasi-affine expressions
+	- preliminary Python bindings
+---
+version: 0.07
+date: Tue Jul 12 19:34:51 CEST 2011
+changes:
+	- hide internal structures of isl_div and isl_constraint
+	- preliminary scheduling
+	- add support for local spaces and (piecewise) quasi-affine expressions
+---
+version: 0.06
+date: Fri Mar 18 15:59:16 CET 2011
+changes:
+	- improved parsing
+	- consistency changes in API
+	- hide internal structure of isl_ctx
+---
+version: 0.05.1
+date: Wed Jan  5 10:21:42 CET 2011
+changes:
+	- fix simple symmetry detection in parametric integer programming
+---
+version: 0.05
+date: Thu Dec 23 17:03:14 CET 2010
+changes:
+	- rename header files from isl_header.h to isl/header.h
+	- add higher level interface for dependence analysis
+	- improved argument parsing
+	- optionally triangulate domains during Bernstein expansion
+	- support extended PolyLib format
+	- hide internal structure of some data types
+	- improved coalescing
+	- add simple symmetry detection in parametric integer programming
+---
+version: 0.04
+date: Fri Sep 10 12:57:50 CEST 2010
+changes:
+	- rename isl_pw_qpolynomial_fold_add
+	- add isl_map_apply_pw_qpolynomial_fold
+	- support named and nested spaces
+	- support union sets and maps
+	- add public API for matrices
+---
+version: 0.03
+date: Tue Jun 29 13:16:46 CEST 2010
+changes:
+	- new printing functions
+	- support for "may" accesses in dependence analysis
+	- improved coalescing
+	- improved transitive closure
+	- fix several hard to trigger bugs
+	- improved argument parsing
+	- support parametric vertex enumeration for barvinok
+	- optionally use Bernstein expansion to compute bounds
diff --git a/final/lib/External/isl/GIT_HEAD_ID b/final/lib/External/isl/GIT_HEAD_ID
new file mode 100644
index 0000000..a2665ce
--- /dev/null
+++ b/final/lib/External/isl/GIT_HEAD_ID
@@ -0,0 +1 @@
+isl-0.18-812-g565da6e
diff --git a/final/lib/External/isl/LICENSE b/final/lib/External/isl/LICENSE
new file mode 100644
index 0000000..e93f597
--- /dev/null
+++ b/final/lib/External/isl/LICENSE
@@ -0,0 +1,19 @@
+MIT License (MIT)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/final/lib/External/isl/Makefile.am b/final/lib/External/isl/Makefile.am
new file mode 100644
index 0000000..4000277
--- /dev/null
+++ b/final/lib/External/isl/Makefile.am
@@ -0,0 +1,442 @@
+if HAVE_CLANG
+    MAYBE_INTERFACE = interface
+endif
+SUBDIRS = . $(MAYBE_INTERFACE) doc
+DIST_SUBDIRS = $(MAYBE_INTERFACE) doc
+
+ACLOCAL_AMFLAGS = -I m4
+AUTOMAKE_OPTIONS = nostdinc subdir-objects
+
+lib_LTLIBRARIES = libisl.la
+noinst_PROGRAMS = isl_test isl_polyhedron_sample isl_pip \
+	isl_polyhedron_minimize isl_polytope_scan \
+	isl_polyhedron_detect_equalities isl_cat \
+	isl_closure isl_bound isl_schedule isl_codegen isl_test_int \
+	isl_flow isl_flow_cmp isl_schedule_cmp
+TESTS = isl_test codegen_test.sh pip_test.sh bound_test.sh isl_test_int \
+	flow_test.sh schedule_test.sh
+
+if IMATH_FOR_MP
+
+MP_SRC = \
+	isl_hide_deprecated.h \
+	isl_imath.c \
+	isl_imath.h \
+	isl_int_imath.h \
+	imath_wrap/gmp_compat.h \
+	imath_wrap/imath.h \
+	imath_wrap/imrat.h \
+	imath_wrap/wrap.h \
+	imath_wrap/gmp_compat.c \
+	imath_wrap/imath.c \
+	imath_wrap/imrat.c
+
+noinst_PROGRAMS += isl_test_imath
+TESTS += isl_test_imath
+
+if SMALL_INT_OPT
+MP_SRC += isl_int_sioimath.h \
+	isl_int_sioimath.c \
+	isl_val_sioimath.c
+else
+MP_SRC += isl_val_imath.c
+endif
+
+DEPRECATED_SRC =
+MP_INCLUDE_H =
+endif
+
+if GMP_FOR_MP
+if NEED_GET_MEMORY_FUNCTIONS
+GET_MEMORY_FUNCTIONS=mp_get_memory_functions.c
+endif
+
+MP_SRC = \
+	$(GET_MEMORY_FUNCTIONS) \
+	isl_int_gmp.h \
+	isl_gmp.c \
+	isl_val_gmp.c
+
+DEPRECATED_SRC = isl_ast_int.c
+MP_INCLUDE_H = include/isl/val_gmp.h
+endif
+
+AM_CPPFLAGS = -I. -I$(srcdir) -I$(srcdir)/include -Iinclude/ @MP_CPPFLAGS@
+AM_CFLAGS = @WARNING_FLAGS@
+
+libisl_la_SOURCES = \
+	$(MP_SRC) \
+	$(DEPRECATED_SRC) \
+	isl_aff.c \
+	isl_aff_private.h \
+	isl_affine_hull.c \
+	isl_arg.c \
+	isl_ast.c \
+	isl_ast_private.h \
+	isl_ast_build.c \
+	isl_ast_build_private.h \
+	isl_ast_build_expr.c \
+	isl_ast_build_expr.h \
+	isl_ast_codegen.c \
+	isl_ast_graft.c \
+	isl_ast_graft_private.h \
+	isl_band.c \
+	isl_band_private.h \
+	isl_basis_reduction.h \
+	basis_reduction_tab.c \
+	isl_bernstein.c \
+	isl_bernstein.h \
+	isl_blk.c \
+	isl_blk.h \
+	isl_bound.c \
+	isl_bound.h \
+	isl_coalesce.c \
+	isl_constraint.c \
+	isl_constraint_private.h \
+	isl_convex_hull.c \
+	isl_ctx.c \
+	isl_ctx_private.h \
+	isl_deprecated.c \
+	isl_dim_map.h \
+	isl_dim_map.c \
+	isl_equalities.c \
+	isl_equalities.h \
+	isl_factorization.c \
+	isl_factorization.h \
+	isl_farkas.c \
+	isl_ffs.c \
+	isl_flow.c \
+	isl_fold.c \
+	isl_hash.c \
+	isl_hash_private.h \
+	isl_id_to_ast_expr.c \
+	isl_id_to_id.c \
+	isl_id_to_pw_aff.c \
+	isl_ilp.c \
+	isl_ilp_private.h \
+	isl_input.c \
+	isl_int.h \
+	isl_local.h \
+	isl_local.c \
+	isl_local_space_private.h \
+	isl_local_space.c \
+	isl_lp.c \
+	isl_lp_private.h \
+	isl_map.c \
+	isl_map_list.c \
+	isl_map_simplify.c \
+	isl_map_subtract.c \
+	isl_map_private.h \
+	isl_map_to_basic_set.c \
+	isl_mat.c \
+	isl_mat_private.h \
+	isl_morph.c \
+	isl_morph.h \
+	isl_id.c \
+	isl_id_private.h \
+	isl_obj.c \
+	isl_options.c \
+	isl_options_private.h \
+	isl_output.c \
+	isl_output_private.h \
+	isl_point_private.h \
+	isl_point.c \
+	isl_polynomial_private.h \
+	isl_polynomial.c \
+	isl_printer_private.h \
+	isl_printer.c \
+	print.c \
+	isl_range.c \
+	isl_range.h \
+	isl_reordering.c \
+	isl_reordering.h \
+	isl_sample.h \
+	isl_sample.c \
+	isl_scan.c \
+	isl_scan.h \
+	isl_schedule.c \
+	isl_schedule_band.c \
+	isl_schedule_band.h \
+	isl_schedule_node.c \
+	isl_schedule_node_private.h \
+	isl_schedule_read.c \
+	isl_schedule_tree.c \
+	isl_schedule_tree.h \
+	isl_schedule_private.h \
+	isl_schedule_constraints.c \
+	isl_schedule_constraints.h \
+	isl_scheduler.c \
+	isl_set_list.c \
+	isl_sort.c \
+	isl_sort.h \
+	isl_space.c \
+	isl_space_private.h \
+	isl_stream.c \
+	isl_stream_private.h \
+	isl_seq.c \
+	isl_seq.h \
+	isl_tab.c \
+	isl_tab.h \
+	isl_tab_pip.c \
+	isl_tarjan.c \
+	isl_tarjan.h \
+	isl_transitive_closure.c \
+	isl_union_map.c \
+	isl_union_map_private.h \
+	isl_union_set_private.h \
+	isl_val.c \
+	isl_val_private.h \
+	isl_vec_private.h \
+	isl_vec.c \
+	isl_version.c \
+	isl_vertices_private.h \
+	isl_vertices.c \
+	isl_yaml.h
+libisl_la_LIBADD = @MP_LIBS@
+libisl_la_LDFLAGS = -version-info @versioninfo@ \
+	@MP_LDFLAGS@
+
+isl_test_LDFLAGS = @MP_LDFLAGS@
+isl_test_LDADD = libisl.la @MP_LIBS@
+
+isl_test_int_LDFLAGS = @MP_LDFLAGS@
+isl_test_int_LDADD = libisl.la @MP_LIBS@
+
+if IMATH_FOR_MP
+isl_test_imath_LDFLAGS = @MP_LDFLAGS@
+isl_test_imath_LDADD = libisl.la @MP_LIBS@
+endif
+
+isl_polyhedron_sample_LDADD = libisl.la
+isl_polyhedron_sample_SOURCES = \
+	polyhedron_sample.c
+
+isl_pip_LDFLAGS = @MP_LDFLAGS@
+isl_pip_LDADD = libisl.la @MP_LIBS@
+isl_pip_SOURCES = \
+	pip.c
+
+isl_schedule_LDFLAGS = @MP_LDFLAGS@
+isl_schedule_LDADD = libisl.la @MP_LIBS@
+isl_schedule_SOURCES = \
+	schedule.c
+
+isl_schedule_cmp_LDFLAGS = @MP_LDFLAGS@
+isl_schedule_cmp_LDADD = libisl.la @MP_LIBS@
+isl_schedule_cmp_SOURCES = \
+	schedule_cmp.c
+
+isl_flow_LDFLAGS = @MP_LDFLAGS@
+isl_flow_LDADD = libisl.la @MP_LIBS@
+isl_flow_SOURCES = \
+	flow.c
+
+isl_flow_cmp_LDFLAGS = @MP_LDFLAGS@
+isl_flow_cmp_LDADD = libisl.la @MP_LIBS@
+isl_flow_cmp_SOURCES = \
+	flow_cmp.c
+
+isl_codegen_LDFLAGS = @MP_LDFLAGS@
+isl_codegen_LDADD = libisl.la @MP_LIBS@
+isl_codegen_SOURCES = \
+	codegen.c
+
+isl_bound_LDFLAGS = @MP_LDFLAGS@
+isl_bound_LDADD = libisl.la @MP_LIBS@
+isl_bound_SOURCES = \
+	bound.c
+
+isl_polyhedron_minimize_LDFLAGS = @MP_LDFLAGS@
+isl_polyhedron_minimize_LDADD = libisl.la @MP_LIBS@
+isl_polyhedron_minimize_SOURCES = \
+	polyhedron_minimize.c
+
+isl_polytope_scan_LDADD = libisl.la
+isl_polytope_scan_SOURCES = \
+	polytope_scan.c
+
+isl_polyhedron_detect_equalities_LDADD = libisl.la
+isl_polyhedron_detect_equalities_SOURCES = \
+	polyhedron_detect_equalities.c
+
+isl_cat_LDADD = libisl.la
+isl_cat_SOURCES = \
+	cat.c
+
+isl_closure_LDADD = libisl.la
+isl_closure_SOURCES = \
+	closure.c
+
+nodist_pkginclude_HEADERS = \
+	include/isl/stdint.h
+pkginclude_HEADERS = \
+	$(MP_INCLUDE_H) \
+	include/isl/aff.h \
+	include/isl/aff_type.h \
+	include/isl/arg.h \
+	include/isl/ast.h \
+	include/isl/ast_type.h \
+	include/isl/ast_build.h \
+	include/isl/band.h \
+	include/isl/constraint.h \
+	include/isl/ctx.h \
+	include/isl/flow.h \
+	include/isl/id.h \
+	include/isl/id_to_ast_expr.h \
+	include/isl/id_to_id.h \
+	include/isl/id_to_pw_aff.h \
+	include/isl/ilp.h \
+	include/isl/hash.h \
+	include/isl/hmap.h \
+	include/isl/hmap_templ.c \
+	include/isl/list.h \
+	include/isl/local_space.h \
+	include/isl/lp.h \
+	include/isl/mat.h \
+	include/isl/map.h \
+	include/isl/map_to_basic_set.h \
+	include/isl/map_type.h \
+	include/isl/maybe.h \
+	include/isl/maybe_ast_expr.h \
+	include/isl/maybe_basic_set.h \
+	include/isl/maybe_id.h \
+	include/isl/maybe_pw_aff.h \
+	include/isl/maybe_templ.h \
+	include/isl/multi.h \
+	include/isl/obj.h \
+	include/isl/options.h \
+	include/isl/point.h \
+	include/isl/polynomial.h \
+	include/isl/polynomial_type.h \
+	include/isl/printer.h \
+	include/isl/printer_type.h \
+	include/isl/schedule.h \
+	include/isl/schedule_node.h \
+	include/isl/schedule_type.h \
+	include/isl/set.h \
+	include/isl/set_type.h \
+	include/isl/space.h \
+	include/isl/stream.h \
+	include/isl/union_map.h \
+	include/isl/union_map_type.h \
+	include/isl/union_set.h \
+	include/isl/union_set_type.h \
+	include/isl/val.h \
+	include/isl/vec.h \
+	include/isl/version.h \
+	include/isl/vertices.h
+deprecateddir = $(pkgincludedir)/deprecated
+deprecated_HEADERS = \
+	include/isl/deprecated/int.h \
+	include/isl/deprecated/aff_int.h \
+	include/isl/deprecated/ast_int.h \
+	include/isl/deprecated/constraint_int.h \
+	include/isl/deprecated/ilp_int.h \
+	include/isl/deprecated/map_int.h \
+	include/isl/deprecated/mat_int.h \
+	include/isl/deprecated/point_int.h \
+	include/isl/deprecated/polynomial_int.h \
+	include/isl/deprecated/set_int.h \
+	include/isl/deprecated/union_map_int.h \
+	include/isl/deprecated/val_int.h \
+	include/isl/deprecated/vec_int.h
+
+BUILT_SOURCES = gitversion.h
+
+CLEANFILES = \
+	gitversion.h
+
+DISTCLEANFILES = \
+	isl-uninstalled.sh \
+	isl-uninstalled.pc \
+	isl.pc \
+	isl.pc.in \
+	include/isl/stdint.h
+
+EXTRA_DIST = \
+	LICENSE \
+	isl_config_post.h \
+	basis_reduction_templ.c \
+	bset_to_bmap.c \
+	bset_from_bmap.c \
+	extract_key.c \
+	isl_list_templ.c \
+	isl_list_templ.h \
+	isl_map_lexopt_templ.c \
+	isl_maybe_map.h \
+	isl_multi_macro.h \
+	isl_multi_templ.c \
+	isl_multi_templ.h \
+	isl_multi_apply_templ.c \
+	isl_multi_apply_set.c \
+	isl_multi_apply_union_set.c \
+	isl_multi_cmp.c \
+	isl_multi_coalesce.c \
+	isl_multi_floor.c \
+	isl_multi_gist.c \
+	isl_multi_hash.c \
+	isl_multi_intersect.c \
+	print_templ.c \
+	print_templ_yaml.c \
+	isl_power_templ.c \
+	isl_pw_macro.h \
+	isl_pw_templ.c \
+	isl_pw_hash.c \
+	isl_pw_union_opt.c \
+	read_in_string_templ.c \
+	set_to_map.c \
+	set_from_map.c \
+	isl_tab_lexopt_templ.c \
+	isl_union_macro.h \
+	isl_union_templ.c \
+	isl_union_single.c \
+	isl_union_multi.c \
+	isl_union_eval.c \
+	isl_union_neg.c \
+	isl.py \
+	doc/CodingStyle \
+	doc/SubmittingPatches \
+	doc/implementation.tex \
+	doc/isl.bib \
+	doc/mypod2latex \
+	doc/manual.tex \
+	doc/reading.tex \
+	doc/user.pod \
+	imath/gmp_compat.c \
+	imath/gmp_compat.h \
+	imath/imath.c \
+	imath/imath.h \
+	imath/imrat.c \
+	imath/imrat.h \
+	interface/all.h \
+	interface/isl.h.top \
+	interface/isl.py.top \
+	test_inputs
+
+dist-hook:
+	echo @GIT_HEAD_VERSION@ > $(distdir)/GIT_HEAD_ID
+	(cd doc; make manual.pdf)
+	cp doc/manual.pdf $(distdir)/doc/
+
+pkgconfigdir=$(pkgconfig_libdir)
+pkgconfig_DATA = $(pkgconfig_libfile)
+
+gitversion.h: @GIT_HEAD@
+	$(AM_V_GEN)echo '#define GIT_HEAD_ID "'@GIT_HEAD_VERSION@'"' > $@
+
+install-data-local: $(srcdir)/isl.py
+	@libisl=`sed -ne "/^library_names=/{s/.*='//;s/'$$//;s/ .*//;p;}" \
+		 $(builddir)/libisl.la`; \
+	case $$libisl in \
+	'') echo Cannot find isl library name. GDB bindings not installed.;; \
+	*) echo $(INSTALL_DATA) $(srcdir)/isl.py \
+		$(DESTDIR)$(libdir)/$$libisl-gdb.py; \
+	test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"; \
+	$(INSTALL_DATA) $(srcdir)/isl.py $(DESTDIR)$(libdir)/$$libisl-gdb.py; esac
+
+uninstall-local:
+	@libisl=`sed -ne "/^library_names=/{s/.*='//;s/'$$//;s/ .*//;p;}" \
+		 $(builddir)/libisl.la`; \
+	if test -n "$${libisl}"; then \
+		rm -f $(DESTDIR)$(libdir)/$$libisl-gdb.py; \
+	fi
diff --git a/final/lib/External/isl/Makefile.in b/final/lib/External/isl/Makefile.in
new file mode 100644
index 0000000..3ea3a2f
--- /dev/null
+++ b/final/lib/External/isl/Makefile.in
@@ -0,0 +1,2327 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = isl_test$(EXEEXT) isl_polyhedron_sample$(EXEEXT) \
+	isl_pip$(EXEEXT) isl_polyhedron_minimize$(EXEEXT) \
+	isl_polytope_scan$(EXEEXT) \
+	isl_polyhedron_detect_equalities$(EXEEXT) isl_cat$(EXEEXT) \
+	isl_closure$(EXEEXT) isl_bound$(EXEEXT) isl_schedule$(EXEEXT) \
+	isl_codegen$(EXEEXT) isl_test_int$(EXEEXT) isl_flow$(EXEEXT) \
+	isl_flow_cmp$(EXEEXT) isl_schedule_cmp$(EXEEXT) \
+	$(am__EXEEXT_1)
+TESTS = isl_test$(EXEEXT) codegen_test.sh pip_test.sh bound_test.sh \
+	isl_test_int$(EXEEXT) flow_test.sh schedule_test.sh \
+	$(am__EXEEXT_1)
+@IMATH_FOR_MP_TRUE@am__append_1 = isl_test_imath
+@IMATH_FOR_MP_TRUE@am__append_2 = isl_test_imath
+@IMATH_FOR_MP_TRUE@@SMALL_INT_OPT_TRUE@am__append_3 = isl_int_sioimath.h \
+@IMATH_FOR_MP_TRUE@@SMALL_INT_OPT_TRUE@	isl_int_sioimath.c \
+@IMATH_FOR_MP_TRUE@@SMALL_INT_OPT_TRUE@	isl_val_sioimath.c
+
+@IMATH_FOR_MP_TRUE@@SMALL_INT_OPT_FALSE@am__append_4 = isl_val_imath.c
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \
+	$(top_srcdir)/m4/ax_cc_maxopt.m4 \
+	$(top_srcdir)/m4/ax_check_compiler_flags.m4 \
+	$(top_srcdir)/m4/ax_compiler_vendor.m4 \
+	$(top_srcdir)/m4/ax_create_pkgconfig_info.m4 \
+	$(top_srcdir)/m4/ax_create_stdint_h.m4 \
+	$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/m4/ax_detect_clang.m4 \
+	$(top_srcdir)/m4/ax_detect_git_head.m4 \
+	$(top_srcdir)/m4/ax_detect_gmp.m4 \
+	$(top_srcdir)/m4/ax_detect_imath.m4 \
+	$(top_srcdir)/m4/ax_gcc_archflag.m4 \
+	$(top_srcdir)/m4/ax_gcc_warn_unused_result.m4 \
+	$(top_srcdir)/m4/ax_gcc_x86_cpuid.m4 \
+	$(top_srcdir)/m4/ax_set_warning_flags.m4 \
+	$(top_srcdir)/m4/ax_submodule.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+	$(am__configure_deps) $(deprecated_HEADERS) \
+	$(am__pkginclude_HEADERS_DIST) $(am__DIST_COMMON)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = isl_config.h
+CONFIG_CLEAN_FILES = isl_srcdir.c bound_test.sh codegen_test.sh \
+	pip_test.sh flow_test.sh schedule_test.sh
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" \
+	"$(DESTDIR)$(deprecateddir)" "$(DESTDIR)$(pkgincludedir)" \
+	"$(DESTDIR)$(pkgincludedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libisl_la_DEPENDENCIES =
+am__libisl_la_SOURCES_DIST = mp_get_memory_functions.c isl_int_gmp.h \
+	isl_gmp.c isl_val_gmp.c isl_hide_deprecated.h isl_imath.c \
+	isl_imath.h isl_int_imath.h imath_wrap/gmp_compat.h \
+	imath_wrap/imath.h imath_wrap/imrat.h imath_wrap/wrap.h \
+	imath_wrap/gmp_compat.c imath_wrap/imath.c imath_wrap/imrat.c \
+	isl_int_sioimath.h isl_int_sioimath.c isl_val_sioimath.c \
+	isl_val_imath.c isl_ast_int.c isl_aff.c isl_aff_private.h \
+	isl_affine_hull.c isl_arg.c isl_ast.c isl_ast_private.h \
+	isl_ast_build.c isl_ast_build_private.h isl_ast_build_expr.c \
+	isl_ast_build_expr.h isl_ast_codegen.c isl_ast_graft.c \
+	isl_ast_graft_private.h isl_band.c isl_band_private.h \
+	isl_basis_reduction.h basis_reduction_tab.c isl_bernstein.c \
+	isl_bernstein.h isl_blk.c isl_blk.h isl_bound.c isl_bound.h \
+	isl_coalesce.c isl_constraint.c isl_constraint_private.h \
+	isl_convex_hull.c isl_ctx.c isl_ctx_private.h isl_deprecated.c \
+	isl_dim_map.h isl_dim_map.c isl_equalities.c isl_equalities.h \
+	isl_factorization.c isl_factorization.h isl_farkas.c isl_ffs.c \
+	isl_flow.c isl_fold.c isl_hash.c isl_hash_private.h \
+	isl_id_to_ast_expr.c isl_id_to_id.c isl_id_to_pw_aff.c \
+	isl_ilp.c isl_ilp_private.h isl_input.c isl_int.h isl_local.h \
+	isl_local.c isl_local_space_private.h isl_local_space.c \
+	isl_lp.c isl_lp_private.h isl_map.c isl_map_list.c \
+	isl_map_simplify.c isl_map_subtract.c isl_map_private.h \
+	isl_map_to_basic_set.c isl_mat.c isl_mat_private.h isl_morph.c \
+	isl_morph.h isl_id.c isl_id_private.h isl_obj.c isl_options.c \
+	isl_options_private.h isl_output.c isl_output_private.h \
+	isl_point_private.h isl_point.c isl_polynomial_private.h \
+	isl_polynomial.c isl_printer_private.h isl_printer.c print.c \
+	isl_range.c isl_range.h isl_reordering.c isl_reordering.h \
+	isl_sample.h isl_sample.c isl_scan.c isl_scan.h isl_schedule.c \
+	isl_schedule_band.c isl_schedule_band.h isl_schedule_node.c \
+	isl_schedule_node_private.h isl_schedule_read.c \
+	isl_schedule_tree.c isl_schedule_tree.h isl_schedule_private.h \
+	isl_schedule_constraints.c isl_schedule_constraints.h \
+	isl_scheduler.c isl_set_list.c isl_sort.c isl_sort.h \
+	isl_space.c isl_space_private.h isl_stream.c \
+	isl_stream_private.h isl_seq.c isl_seq.h isl_tab.c isl_tab.h \
+	isl_tab_pip.c isl_tarjan.c isl_tarjan.h \
+	isl_transitive_closure.c isl_union_map.c \
+	isl_union_map_private.h isl_union_set_private.h isl_val.c \
+	isl_val_private.h isl_vec_private.h isl_vec.c isl_version.c \
+	isl_vertices_private.h isl_vertices.c isl_yaml.h
+@GMP_FOR_MP_TRUE@@NEED_GET_MEMORY_FUNCTIONS_TRUE@am__objects_1 = mp_get_memory_functions.lo
+am__dirstamp = $(am__leading_dot)dirstamp
+@IMATH_FOR_MP_TRUE@@SMALL_INT_OPT_TRUE@am__objects_2 =  \
+@IMATH_FOR_MP_TRUE@@SMALL_INT_OPT_TRUE@	isl_int_sioimath.lo \
+@IMATH_FOR_MP_TRUE@@SMALL_INT_OPT_TRUE@	isl_val_sioimath.lo
+@IMATH_FOR_MP_TRUE@@SMALL_INT_OPT_FALSE@am__objects_3 =  \
+@IMATH_FOR_MP_TRUE@@SMALL_INT_OPT_FALSE@	isl_val_imath.lo
+@GMP_FOR_MP_FALSE@@IMATH_FOR_MP_TRUE@am__objects_4 = isl_imath.lo \
+@GMP_FOR_MP_FALSE@@IMATH_FOR_MP_TRUE@	imath_wrap/gmp_compat.lo \
+@GMP_FOR_MP_FALSE@@IMATH_FOR_MP_TRUE@	imath_wrap/imath.lo \
+@GMP_FOR_MP_FALSE@@IMATH_FOR_MP_TRUE@	imath_wrap/imrat.lo \
+@GMP_FOR_MP_FALSE@@IMATH_FOR_MP_TRUE@	$(am__objects_2) \
+@GMP_FOR_MP_FALSE@@IMATH_FOR_MP_TRUE@	$(am__objects_3)
+@GMP_FOR_MP_TRUE@am__objects_4 = $(am__objects_1) isl_gmp.lo \
+@GMP_FOR_MP_TRUE@	isl_val_gmp.lo
+@GMP_FOR_MP_TRUE@am__objects_5 = isl_ast_int.lo
+am_libisl_la_OBJECTS = $(am__objects_4) $(am__objects_5) isl_aff.lo \
+	isl_affine_hull.lo isl_arg.lo isl_ast.lo isl_ast_build.lo \
+	isl_ast_build_expr.lo isl_ast_codegen.lo isl_ast_graft.lo \
+	isl_band.lo basis_reduction_tab.lo isl_bernstein.lo isl_blk.lo \
+	isl_bound.lo isl_coalesce.lo isl_constraint.lo \
+	isl_convex_hull.lo isl_ctx.lo isl_deprecated.lo isl_dim_map.lo \
+	isl_equalities.lo isl_factorization.lo isl_farkas.lo \
+	isl_ffs.lo isl_flow.lo isl_fold.lo isl_hash.lo \
+	isl_id_to_ast_expr.lo isl_id_to_id.lo isl_id_to_pw_aff.lo \
+	isl_ilp.lo isl_input.lo isl_local.lo isl_local_space.lo \
+	isl_lp.lo isl_map.lo isl_map_list.lo isl_map_simplify.lo \
+	isl_map_subtract.lo isl_map_to_basic_set.lo isl_mat.lo \
+	isl_morph.lo isl_id.lo isl_obj.lo isl_options.lo isl_output.lo \
+	isl_point.lo isl_polynomial.lo isl_printer.lo print.lo \
+	isl_range.lo isl_reordering.lo isl_sample.lo isl_scan.lo \
+	isl_schedule.lo isl_schedule_band.lo isl_schedule_node.lo \
+	isl_schedule_read.lo isl_schedule_tree.lo \
+	isl_schedule_constraints.lo isl_scheduler.lo isl_set_list.lo \
+	isl_sort.lo isl_space.lo isl_stream.lo isl_seq.lo isl_tab.lo \
+	isl_tab_pip.lo isl_tarjan.lo isl_transitive_closure.lo \
+	isl_union_map.lo isl_val.lo isl_vec.lo isl_version.lo \
+	isl_vertices.lo
+libisl_la_OBJECTS = $(am_libisl_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libisl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(libisl_la_LDFLAGS) $(LDFLAGS) -o $@
+@IMATH_FOR_MP_TRUE@am__EXEEXT_1 = isl_test_imath$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+am_isl_bound_OBJECTS = bound.$(OBJEXT)
+isl_bound_OBJECTS = $(am_isl_bound_OBJECTS)
+isl_bound_DEPENDENCIES = libisl.la
+isl_bound_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(isl_bound_LDFLAGS) $(LDFLAGS) -o $@
+am_isl_cat_OBJECTS = cat.$(OBJEXT)
+isl_cat_OBJECTS = $(am_isl_cat_OBJECTS)
+isl_cat_DEPENDENCIES = libisl.la
+am_isl_closure_OBJECTS = closure.$(OBJEXT)
+isl_closure_OBJECTS = $(am_isl_closure_OBJECTS)
+isl_closure_DEPENDENCIES = libisl.la
+am_isl_codegen_OBJECTS = codegen.$(OBJEXT)
+isl_codegen_OBJECTS = $(am_isl_codegen_OBJECTS)
+isl_codegen_DEPENDENCIES = libisl.la
+isl_codegen_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(isl_codegen_LDFLAGS) $(LDFLAGS) -o $@
+am_isl_flow_OBJECTS = flow.$(OBJEXT)
+isl_flow_OBJECTS = $(am_isl_flow_OBJECTS)
+isl_flow_DEPENDENCIES = libisl.la
+isl_flow_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(isl_flow_LDFLAGS) $(LDFLAGS) -o $@
+am_isl_flow_cmp_OBJECTS = flow_cmp.$(OBJEXT)
+isl_flow_cmp_OBJECTS = $(am_isl_flow_cmp_OBJECTS)
+isl_flow_cmp_DEPENDENCIES = libisl.la
+isl_flow_cmp_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(isl_flow_cmp_LDFLAGS) $(LDFLAGS) -o $@
+am_isl_pip_OBJECTS = pip.$(OBJEXT)
+isl_pip_OBJECTS = $(am_isl_pip_OBJECTS)
+isl_pip_DEPENDENCIES = libisl.la
+isl_pip_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(isl_pip_LDFLAGS) $(LDFLAGS) -o $@
+am_isl_polyhedron_detect_equalities_OBJECTS =  \
+	polyhedron_detect_equalities.$(OBJEXT)
+isl_polyhedron_detect_equalities_OBJECTS =  \
+	$(am_isl_polyhedron_detect_equalities_OBJECTS)
+isl_polyhedron_detect_equalities_DEPENDENCIES = libisl.la
+am_isl_polyhedron_minimize_OBJECTS = polyhedron_minimize.$(OBJEXT)
+isl_polyhedron_minimize_OBJECTS =  \
+	$(am_isl_polyhedron_minimize_OBJECTS)
+isl_polyhedron_minimize_DEPENDENCIES = libisl.la
+isl_polyhedron_minimize_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(AM_CFLAGS) $(CFLAGS) $(isl_polyhedron_minimize_LDFLAGS) \
+	$(LDFLAGS) -o $@
+am_isl_polyhedron_sample_OBJECTS = polyhedron_sample.$(OBJEXT)
+isl_polyhedron_sample_OBJECTS = $(am_isl_polyhedron_sample_OBJECTS)
+isl_polyhedron_sample_DEPENDENCIES = libisl.la
+am_isl_polytope_scan_OBJECTS = polytope_scan.$(OBJEXT)
+isl_polytope_scan_OBJECTS = $(am_isl_polytope_scan_OBJECTS)
+isl_polytope_scan_DEPENDENCIES = libisl.la
+am_isl_schedule_OBJECTS = schedule.$(OBJEXT)
+isl_schedule_OBJECTS = $(am_isl_schedule_OBJECTS)
+isl_schedule_DEPENDENCIES = libisl.la
+isl_schedule_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(isl_schedule_LDFLAGS) $(LDFLAGS) -o $@
+am_isl_schedule_cmp_OBJECTS = schedule_cmp.$(OBJEXT)
+isl_schedule_cmp_OBJECTS = $(am_isl_schedule_cmp_OBJECTS)
+isl_schedule_cmp_DEPENDENCIES = libisl.la
+isl_schedule_cmp_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(AM_CFLAGS) $(CFLAGS) $(isl_schedule_cmp_LDFLAGS) $(LDFLAGS) \
+	-o $@
+isl_test_SOURCES = isl_test.c
+isl_test_OBJECTS = isl_test.$(OBJEXT)
+isl_test_DEPENDENCIES = libisl.la
+isl_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(isl_test_LDFLAGS) $(LDFLAGS) -o $@
+isl_test_imath_SOURCES = isl_test_imath.c
+isl_test_imath_OBJECTS = isl_test_imath.$(OBJEXT)
+@IMATH_FOR_MP_TRUE@isl_test_imath_DEPENDENCIES = libisl.la
+isl_test_imath_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(AM_CFLAGS) $(CFLAGS) $(isl_test_imath_LDFLAGS) $(LDFLAGS) -o \
+	$@
+isl_test_int_SOURCES = isl_test_int.c
+isl_test_int_OBJECTS = isl_test_int.$(OBJEXT)
+isl_test_int_DEPENDENCIES = libisl.la
+isl_test_int_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(isl_test_int_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = 
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libisl_la_SOURCES) $(isl_bound_SOURCES) $(isl_cat_SOURCES) \
+	$(isl_closure_SOURCES) $(isl_codegen_SOURCES) \
+	$(isl_flow_SOURCES) $(isl_flow_cmp_SOURCES) $(isl_pip_SOURCES) \
+	$(isl_polyhedron_detect_equalities_SOURCES) \
+	$(isl_polyhedron_minimize_SOURCES) \
+	$(isl_polyhedron_sample_SOURCES) $(isl_polytope_scan_SOURCES) \
+	$(isl_schedule_SOURCES) $(isl_schedule_cmp_SOURCES) isl_test.c \
+	isl_test_imath.c isl_test_int.c
+DIST_SOURCES = $(am__libisl_la_SOURCES_DIST) $(isl_bound_SOURCES) \
+	$(isl_cat_SOURCES) $(isl_closure_SOURCES) \
+	$(isl_codegen_SOURCES) $(isl_flow_SOURCES) \
+	$(isl_flow_cmp_SOURCES) $(isl_pip_SOURCES) \
+	$(isl_polyhedron_detect_equalities_SOURCES) \
+	$(isl_polyhedron_minimize_SOURCES) \
+	$(isl_polyhedron_sample_SOURCES) $(isl_polytope_scan_SOURCES) \
+	$(isl_schedule_SOURCES) $(isl_schedule_cmp_SOURCES) isl_test.c \
+	isl_test_imath.c isl_test_int.c
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+DATA = $(pkgconfig_DATA)
+am__pkginclude_HEADERS_DIST = include/isl/val_gmp.h include/isl/aff.h \
+	include/isl/aff_type.h include/isl/arg.h include/isl/ast.h \
+	include/isl/ast_type.h include/isl/ast_build.h \
+	include/isl/band.h include/isl/constraint.h include/isl/ctx.h \
+	include/isl/flow.h include/isl/id.h \
+	include/isl/id_to_ast_expr.h include/isl/id_to_id.h \
+	include/isl/id_to_pw_aff.h include/isl/ilp.h \
+	include/isl/hash.h include/isl/hmap.h include/isl/hmap_templ.c \
+	include/isl/list.h include/isl/local_space.h include/isl/lp.h \
+	include/isl/mat.h include/isl/map.h \
+	include/isl/map_to_basic_set.h include/isl/map_type.h \
+	include/isl/maybe.h include/isl/maybe_ast_expr.h \
+	include/isl/maybe_basic_set.h include/isl/maybe_id.h \
+	include/isl/maybe_pw_aff.h include/isl/maybe_templ.h \
+	include/isl/multi.h include/isl/obj.h include/isl/options.h \
+	include/isl/point.h include/isl/polynomial.h \
+	include/isl/polynomial_type.h include/isl/printer.h \
+	include/isl/printer_type.h include/isl/schedule.h \
+	include/isl/schedule_node.h include/isl/schedule_type.h \
+	include/isl/set.h include/isl/set_type.h include/isl/space.h \
+	include/isl/stream.h include/isl/union_map.h \
+	include/isl/union_map_type.h include/isl/union_set.h \
+	include/isl/union_set_type.h include/isl/val.h \
+	include/isl/vec.h include/isl/version.h include/isl/vertices.h
+HEADERS = $(deprecated_HEADERS) $(nodist_pkginclude_HEADERS) \
+	$(pkginclude_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	cscope check recheck distdir dist dist-all distcheck
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+	$(LISP)isl_config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/bound_test.sh.in \
+	$(srcdir)/codegen_test.sh.in $(srcdir)/flow_test.sh.in \
+	$(srcdir)/isl_config.h.in $(srcdir)/isl_srcdir.c.in \
+	$(srcdir)/pip_test.sh.in $(srcdir)/schedule_test.sh.in AUTHORS \
+	ChangeLog README compile config.guess config.sub depcomp \
+	install-sh ltmain.sh missing test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  if test -d "$(distdir)"; then \
+    find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+      && rm -rf "$(distdir)" \
+      || { sleep 5 && rm -rf "$(distdir)"; }; \
+  else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+DIST_TARGETS = dist-gzip
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+  | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLANG_CXXFLAGS = @CLANG_CXXFLAGS@
+CLANG_LDFLAGS = @CLANG_LDFLAGS@
+CLANG_LIBS = @CLANG_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXX11FLAGS = @CXX11FLAGS@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GIT_HEAD = @GIT_HEAD@
+GIT_HEAD_ID = @GIT_HEAD_ID@
+GIT_HEAD_VERSION = @GIT_HEAD_VERSION@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLANG_EDIT = @LIB_CLANG_EDIT@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MP_CPPFLAGS = @MP_CPPFLAGS@
+MP_LDFLAGS = @MP_LDFLAGS@
+MP_LIBS = @MP_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PERL = @PERL@
+POD2HTML = @POD2HTML@
+PRTDIAG = @PRTDIAG@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARNING_FLAGS = @WARNING_FLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+llvm_config_found = @llvm_config_found@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfig_libdir = @pkgconfig_libdir@
+pkgconfig_libfile = @pkgconfig_libfile@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+versioninfo = @versioninfo@
+@HAVE_CLANG_TRUE@MAYBE_INTERFACE = interface
+SUBDIRS = . $(MAYBE_INTERFACE) doc
+DIST_SUBDIRS = $(MAYBE_INTERFACE) doc
+ACLOCAL_AMFLAGS = -I m4
+AUTOMAKE_OPTIONS = nostdinc subdir-objects
+lib_LTLIBRARIES = libisl.la
+@GMP_FOR_MP_TRUE@MP_SRC = \
+@GMP_FOR_MP_TRUE@	$(GET_MEMORY_FUNCTIONS) \
+@GMP_FOR_MP_TRUE@	isl_int_gmp.h \
+@GMP_FOR_MP_TRUE@	isl_gmp.c \
+@GMP_FOR_MP_TRUE@	isl_val_gmp.c
+
+@IMATH_FOR_MP_TRUE@MP_SRC = isl_hide_deprecated.h isl_imath.c \
+@IMATH_FOR_MP_TRUE@	isl_imath.h isl_int_imath.h \
+@IMATH_FOR_MP_TRUE@	imath_wrap/gmp_compat.h imath_wrap/imath.h \
+@IMATH_FOR_MP_TRUE@	imath_wrap/imrat.h imath_wrap/wrap.h \
+@IMATH_FOR_MP_TRUE@	imath_wrap/gmp_compat.c imath_wrap/imath.c \
+@IMATH_FOR_MP_TRUE@	imath_wrap/imrat.c $(am__append_3) \
+@IMATH_FOR_MP_TRUE@	$(am__append_4)
+@GMP_FOR_MP_TRUE@DEPRECATED_SRC = isl_ast_int.c
+@IMATH_FOR_MP_TRUE@DEPRECATED_SRC = 
+@GMP_FOR_MP_TRUE@MP_INCLUDE_H = include/isl/val_gmp.h
+@IMATH_FOR_MP_TRUE@MP_INCLUDE_H = 
+@GMP_FOR_MP_TRUE@@NEED_GET_MEMORY_FUNCTIONS_TRUE@GET_MEMORY_FUNCTIONS = mp_get_memory_functions.c
+AM_CPPFLAGS = -I. -I$(srcdir) -I$(srcdir)/include -Iinclude/ @MP_CPPFLAGS@
+AM_CFLAGS = @WARNING_FLAGS@
+libisl_la_SOURCES = \
+	$(MP_SRC) \
+	$(DEPRECATED_SRC) \
+	isl_aff.c \
+	isl_aff_private.h \
+	isl_affine_hull.c \
+	isl_arg.c \
+	isl_ast.c \
+	isl_ast_private.h \
+	isl_ast_build.c \
+	isl_ast_build_private.h \
+	isl_ast_build_expr.c \
+	isl_ast_build_expr.h \
+	isl_ast_codegen.c \
+	isl_ast_graft.c \
+	isl_ast_graft_private.h \
+	isl_band.c \
+	isl_band_private.h \
+	isl_basis_reduction.h \
+	basis_reduction_tab.c \
+	isl_bernstein.c \
+	isl_bernstein.h \
+	isl_blk.c \
+	isl_blk.h \
+	isl_bound.c \
+	isl_bound.h \
+	isl_coalesce.c \
+	isl_constraint.c \
+	isl_constraint_private.h \
+	isl_convex_hull.c \
+	isl_ctx.c \
+	isl_ctx_private.h \
+	isl_deprecated.c \
+	isl_dim_map.h \
+	isl_dim_map.c \
+	isl_equalities.c \
+	isl_equalities.h \
+	isl_factorization.c \
+	isl_factorization.h \
+	isl_farkas.c \
+	isl_ffs.c \
+	isl_flow.c \
+	isl_fold.c \
+	isl_hash.c \
+	isl_hash_private.h \
+	isl_id_to_ast_expr.c \
+	isl_id_to_id.c \
+	isl_id_to_pw_aff.c \
+	isl_ilp.c \
+	isl_ilp_private.h \
+	isl_input.c \
+	isl_int.h \
+	isl_local.h \
+	isl_local.c \
+	isl_local_space_private.h \
+	isl_local_space.c \
+	isl_lp.c \
+	isl_lp_private.h \
+	isl_map.c \
+	isl_map_list.c \
+	isl_map_simplify.c \
+	isl_map_subtract.c \
+	isl_map_private.h \
+	isl_map_to_basic_set.c \
+	isl_mat.c \
+	isl_mat_private.h \
+	isl_morph.c \
+	isl_morph.h \
+	isl_id.c \
+	isl_id_private.h \
+	isl_obj.c \
+	isl_options.c \
+	isl_options_private.h \
+	isl_output.c \
+	isl_output_private.h \
+	isl_point_private.h \
+	isl_point.c \
+	isl_polynomial_private.h \
+	isl_polynomial.c \
+	isl_printer_private.h \
+	isl_printer.c \
+	print.c \
+	isl_range.c \
+	isl_range.h \
+	isl_reordering.c \
+	isl_reordering.h \
+	isl_sample.h \
+	isl_sample.c \
+	isl_scan.c \
+	isl_scan.h \
+	isl_schedule.c \
+	isl_schedule_band.c \
+	isl_schedule_band.h \
+	isl_schedule_node.c \
+	isl_schedule_node_private.h \
+	isl_schedule_read.c \
+	isl_schedule_tree.c \
+	isl_schedule_tree.h \
+	isl_schedule_private.h \
+	isl_schedule_constraints.c \
+	isl_schedule_constraints.h \
+	isl_scheduler.c \
+	isl_set_list.c \
+	isl_sort.c \
+	isl_sort.h \
+	isl_space.c \
+	isl_space_private.h \
+	isl_stream.c \
+	isl_stream_private.h \
+	isl_seq.c \
+	isl_seq.h \
+	isl_tab.c \
+	isl_tab.h \
+	isl_tab_pip.c \
+	isl_tarjan.c \
+	isl_tarjan.h \
+	isl_transitive_closure.c \
+	isl_union_map.c \
+	isl_union_map_private.h \
+	isl_union_set_private.h \
+	isl_val.c \
+	isl_val_private.h \
+	isl_vec_private.h \
+	isl_vec.c \
+	isl_version.c \
+	isl_vertices_private.h \
+	isl_vertices.c \
+	isl_yaml.h
+
+libisl_la_LIBADD = @MP_LIBS@
+libisl_la_LDFLAGS = -version-info @versioninfo@ \
+	@MP_LDFLAGS@
+
+isl_test_LDFLAGS = @MP_LDFLAGS@
+isl_test_LDADD = libisl.la @MP_LIBS@
+isl_test_int_LDFLAGS = @MP_LDFLAGS@
+isl_test_int_LDADD = libisl.la @MP_LIBS@
+@IMATH_FOR_MP_TRUE@isl_test_imath_LDFLAGS = @MP_LDFLAGS@
+@IMATH_FOR_MP_TRUE@isl_test_imath_LDADD = libisl.la @MP_LIBS@
+isl_polyhedron_sample_LDADD = libisl.la
+isl_polyhedron_sample_SOURCES = \
+	polyhedron_sample.c
+
+isl_pip_LDFLAGS = @MP_LDFLAGS@
+isl_pip_LDADD = libisl.la @MP_LIBS@
+isl_pip_SOURCES = \
+	pip.c
+
+isl_schedule_LDFLAGS = @MP_LDFLAGS@
+isl_schedule_LDADD = libisl.la @MP_LIBS@
+isl_schedule_SOURCES = \
+	schedule.c
+
+isl_schedule_cmp_LDFLAGS = @MP_LDFLAGS@
+isl_schedule_cmp_LDADD = libisl.la @MP_LIBS@
+isl_schedule_cmp_SOURCES = \
+	schedule_cmp.c
+
+isl_flow_LDFLAGS = @MP_LDFLAGS@
+isl_flow_LDADD = libisl.la @MP_LIBS@
+isl_flow_SOURCES = \
+	flow.c
+
+isl_flow_cmp_LDFLAGS = @MP_LDFLAGS@
+isl_flow_cmp_LDADD = libisl.la @MP_LIBS@
+isl_flow_cmp_SOURCES = \
+	flow_cmp.c
+
+isl_codegen_LDFLAGS = @MP_LDFLAGS@
+isl_codegen_LDADD = libisl.la @MP_LIBS@
+isl_codegen_SOURCES = \
+	codegen.c
+
+isl_bound_LDFLAGS = @MP_LDFLAGS@
+isl_bound_LDADD = libisl.la @MP_LIBS@
+isl_bound_SOURCES = \
+	bound.c
+
+isl_polyhedron_minimize_LDFLAGS = @MP_LDFLAGS@
+isl_polyhedron_minimize_LDADD = libisl.la @MP_LIBS@
+isl_polyhedron_minimize_SOURCES = \
+	polyhedron_minimize.c
+
+isl_polytope_scan_LDADD = libisl.la
+isl_polytope_scan_SOURCES = \
+	polytope_scan.c
+
+isl_polyhedron_detect_equalities_LDADD = libisl.la
+isl_polyhedron_detect_equalities_SOURCES = \
+	polyhedron_detect_equalities.c
+
+isl_cat_LDADD = libisl.la
+isl_cat_SOURCES = \
+	cat.c
+
+isl_closure_LDADD = libisl.la
+isl_closure_SOURCES = \
+	closure.c
+
+nodist_pkginclude_HEADERS = \
+	include/isl/stdint.h
+
+pkginclude_HEADERS = \
+	$(MP_INCLUDE_H) \
+	include/isl/aff.h \
+	include/isl/aff_type.h \
+	include/isl/arg.h \
+	include/isl/ast.h \
+	include/isl/ast_type.h \
+	include/isl/ast_build.h \
+	include/isl/band.h \
+	include/isl/constraint.h \
+	include/isl/ctx.h \
+	include/isl/flow.h \
+	include/isl/id.h \
+	include/isl/id_to_ast_expr.h \
+	include/isl/id_to_id.h \
+	include/isl/id_to_pw_aff.h \
+	include/isl/ilp.h \
+	include/isl/hash.h \
+	include/isl/hmap.h \
+	include/isl/hmap_templ.c \
+	include/isl/list.h \
+	include/isl/local_space.h \
+	include/isl/lp.h \
+	include/isl/mat.h \
+	include/isl/map.h \
+	include/isl/map_to_basic_set.h \
+	include/isl/map_type.h \
+	include/isl/maybe.h \
+	include/isl/maybe_ast_expr.h \
+	include/isl/maybe_basic_set.h \
+	include/isl/maybe_id.h \
+	include/isl/maybe_pw_aff.h \
+	include/isl/maybe_templ.h \
+	include/isl/multi.h \
+	include/isl/obj.h \
+	include/isl/options.h \
+	include/isl/point.h \
+	include/isl/polynomial.h \
+	include/isl/polynomial_type.h \
+	include/isl/printer.h \
+	include/isl/printer_type.h \
+	include/isl/schedule.h \
+	include/isl/schedule_node.h \
+	include/isl/schedule_type.h \
+	include/isl/set.h \
+	include/isl/set_type.h \
+	include/isl/space.h \
+	include/isl/stream.h \
+	include/isl/union_map.h \
+	include/isl/union_map_type.h \
+	include/isl/union_set.h \
+	include/isl/union_set_type.h \
+	include/isl/val.h \
+	include/isl/vec.h \
+	include/isl/version.h \
+	include/isl/vertices.h
+
+deprecateddir = $(pkgincludedir)/deprecated
+deprecated_HEADERS = \
+	include/isl/deprecated/int.h \
+	include/isl/deprecated/aff_int.h \
+	include/isl/deprecated/ast_int.h \
+	include/isl/deprecated/constraint_int.h \
+	include/isl/deprecated/ilp_int.h \
+	include/isl/deprecated/map_int.h \
+	include/isl/deprecated/mat_int.h \
+	include/isl/deprecated/point_int.h \
+	include/isl/deprecated/polynomial_int.h \
+	include/isl/deprecated/set_int.h \
+	include/isl/deprecated/union_map_int.h \
+	include/isl/deprecated/val_int.h \
+	include/isl/deprecated/vec_int.h
+
+BUILT_SOURCES = gitversion.h
+CLEANFILES = \
+	gitversion.h
+
+DISTCLEANFILES = \
+	isl-uninstalled.sh \
+	isl-uninstalled.pc \
+	isl.pc \
+	isl.pc.in \
+	include/isl/stdint.h
+
+EXTRA_DIST = \
+	LICENSE \
+	isl_config_post.h \
+	basis_reduction_templ.c \
+	bset_to_bmap.c \
+	bset_from_bmap.c \
+	extract_key.c \
+	isl_list_templ.c \
+	isl_list_templ.h \
+	isl_map_lexopt_templ.c \
+	isl_maybe_map.h \
+	isl_multi_macro.h \
+	isl_multi_templ.c \
+	isl_multi_templ.h \
+	isl_multi_apply_templ.c \
+	isl_multi_apply_set.c \
+	isl_multi_apply_union_set.c \
+	isl_multi_cmp.c \
+	isl_multi_coalesce.c \
+	isl_multi_floor.c \
+	isl_multi_gist.c \
+	isl_multi_hash.c \
+	isl_multi_intersect.c \
+	print_templ.c \
+	print_templ_yaml.c \
+	isl_power_templ.c \
+	isl_pw_macro.h \
+	isl_pw_templ.c \
+	isl_pw_hash.c \
+	isl_pw_union_opt.c \
+	read_in_string_templ.c \
+	set_to_map.c \
+	set_from_map.c \
+	isl_tab_lexopt_templ.c \
+	isl_union_macro.h \
+	isl_union_templ.c \
+	isl_union_single.c \
+	isl_union_multi.c \
+	isl_union_eval.c \
+	isl_union_neg.c \
+	isl.py \
+	doc/CodingStyle \
+	doc/SubmittingPatches \
+	doc/implementation.tex \
+	doc/isl.bib \
+	doc/mypod2latex \
+	doc/manual.tex \
+	doc/reading.tex \
+	doc/user.pod \
+	imath/gmp_compat.c \
+	imath/gmp_compat.h \
+	imath/imath.c \
+	imath/imath.h \
+	imath/imrat.c \
+	imath/imrat.h \
+	interface/all.h \
+	interface/isl.h.top \
+	interface/isl.py.top \
+	test_inputs
+
+pkgconfigdir = $(pkgconfig_libdir)
+pkgconfig_DATA = $(pkgconfig_libfile)
+all: $(BUILT_SOURCES) isl_config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+am--refresh: Makefile
+	@:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+	      $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	$(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+isl_config.h: stamp-h1
+	@test -f $@ || rm -f stamp-h1
+	@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/isl_config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status isl_config.h
+$(srcdir)/isl_config.h.in:  $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f isl_config.h stamp-h1
+isl_srcdir.c: $(top_builddir)/config.status $(srcdir)/isl_srcdir.c.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+bound_test.sh: $(top_builddir)/config.status $(srcdir)/bound_test.sh.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+codegen_test.sh: $(top_builddir)/config.status $(srcdir)/codegen_test.sh.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+pip_test.sh: $(top_builddir)/config.status $(srcdir)/pip_test.sh.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+flow_test.sh: $(top_builddir)/config.status $(srcdir)/flow_test.sh.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+schedule_test.sh: $(top_builddir)/config.status $(srcdir)/schedule_test.sh.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+imath_wrap/$(am__dirstamp):
+	@$(MKDIR_P) imath_wrap
+	@: > imath_wrap/$(am__dirstamp)
+imath_wrap/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) imath_wrap/$(DEPDIR)
+	@: > imath_wrap/$(DEPDIR)/$(am__dirstamp)
+imath_wrap/gmp_compat.lo: imath_wrap/$(am__dirstamp) \
+	imath_wrap/$(DEPDIR)/$(am__dirstamp)
+imath_wrap/imath.lo: imath_wrap/$(am__dirstamp) \
+	imath_wrap/$(DEPDIR)/$(am__dirstamp)
+imath_wrap/imrat.lo: imath_wrap/$(am__dirstamp) \
+	imath_wrap/$(DEPDIR)/$(am__dirstamp)
+
+libisl.la: $(libisl_la_OBJECTS) $(libisl_la_DEPENDENCIES) $(EXTRA_libisl_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libisl_la_LINK) -rpath $(libdir) $(libisl_la_OBJECTS) $(libisl_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+	@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+isl_bound$(EXEEXT): $(isl_bound_OBJECTS) $(isl_bound_DEPENDENCIES) $(EXTRA_isl_bound_DEPENDENCIES) 
+	@rm -f isl_bound$(EXEEXT)
+	$(AM_V_CCLD)$(isl_bound_LINK) $(isl_bound_OBJECTS) $(isl_bound_LDADD) $(LIBS)
+
+isl_cat$(EXEEXT): $(isl_cat_OBJECTS) $(isl_cat_DEPENDENCIES) $(EXTRA_isl_cat_DEPENDENCIES) 
+	@rm -f isl_cat$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(isl_cat_OBJECTS) $(isl_cat_LDADD) $(LIBS)
+
+isl_closure$(EXEEXT): $(isl_closure_OBJECTS) $(isl_closure_DEPENDENCIES) $(EXTRA_isl_closure_DEPENDENCIES) 
+	@rm -f isl_closure$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(isl_closure_OBJECTS) $(isl_closure_LDADD) $(LIBS)
+
+isl_codegen$(EXEEXT): $(isl_codegen_OBJECTS) $(isl_codegen_DEPENDENCIES) $(EXTRA_isl_codegen_DEPENDENCIES) 
+	@rm -f isl_codegen$(EXEEXT)
+	$(AM_V_CCLD)$(isl_codegen_LINK) $(isl_codegen_OBJECTS) $(isl_codegen_LDADD) $(LIBS)
+
+isl_flow$(EXEEXT): $(isl_flow_OBJECTS) $(isl_flow_DEPENDENCIES) $(EXTRA_isl_flow_DEPENDENCIES) 
+	@rm -f isl_flow$(EXEEXT)
+	$(AM_V_CCLD)$(isl_flow_LINK) $(isl_flow_OBJECTS) $(isl_flow_LDADD) $(LIBS)
+
+isl_flow_cmp$(EXEEXT): $(isl_flow_cmp_OBJECTS) $(isl_flow_cmp_DEPENDENCIES) $(EXTRA_isl_flow_cmp_DEPENDENCIES) 
+	@rm -f isl_flow_cmp$(EXEEXT)
+	$(AM_V_CCLD)$(isl_flow_cmp_LINK) $(isl_flow_cmp_OBJECTS) $(isl_flow_cmp_LDADD) $(LIBS)
+
+isl_pip$(EXEEXT): $(isl_pip_OBJECTS) $(isl_pip_DEPENDENCIES) $(EXTRA_isl_pip_DEPENDENCIES) 
+	@rm -f isl_pip$(EXEEXT)
+	$(AM_V_CCLD)$(isl_pip_LINK) $(isl_pip_OBJECTS) $(isl_pip_LDADD) $(LIBS)
+
+isl_polyhedron_detect_equalities$(EXEEXT): $(isl_polyhedron_detect_equalities_OBJECTS) $(isl_polyhedron_detect_equalities_DEPENDENCIES) $(EXTRA_isl_polyhedron_detect_equalities_DEPENDENCIES) 
+	@rm -f isl_polyhedron_detect_equalities$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(isl_polyhedron_detect_equalities_OBJECTS) $(isl_polyhedron_detect_equalities_LDADD) $(LIBS)
+
+isl_polyhedron_minimize$(EXEEXT): $(isl_polyhedron_minimize_OBJECTS) $(isl_polyhedron_minimize_DEPENDENCIES) $(EXTRA_isl_polyhedron_minimize_DEPENDENCIES) 
+	@rm -f isl_polyhedron_minimize$(EXEEXT)
+	$(AM_V_CCLD)$(isl_polyhedron_minimize_LINK) $(isl_polyhedron_minimize_OBJECTS) $(isl_polyhedron_minimize_LDADD) $(LIBS)
+
+isl_polyhedron_sample$(EXEEXT): $(isl_polyhedron_sample_OBJECTS) $(isl_polyhedron_sample_DEPENDENCIES) $(EXTRA_isl_polyhedron_sample_DEPENDENCIES) 
+	@rm -f isl_polyhedron_sample$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(isl_polyhedron_sample_OBJECTS) $(isl_polyhedron_sample_LDADD) $(LIBS)
+
+isl_polytope_scan$(EXEEXT): $(isl_polytope_scan_OBJECTS) $(isl_polytope_scan_DEPENDENCIES) $(EXTRA_isl_polytope_scan_DEPENDENCIES) 
+	@rm -f isl_polytope_scan$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(isl_polytope_scan_OBJECTS) $(isl_polytope_scan_LDADD) $(LIBS)
+
+isl_schedule$(EXEEXT): $(isl_schedule_OBJECTS) $(isl_schedule_DEPENDENCIES) $(EXTRA_isl_schedule_DEPENDENCIES) 
+	@rm -f isl_schedule$(EXEEXT)
+	$(AM_V_CCLD)$(isl_schedule_LINK) $(isl_schedule_OBJECTS) $(isl_schedule_LDADD) $(LIBS)
+
+isl_schedule_cmp$(EXEEXT): $(isl_schedule_cmp_OBJECTS) $(isl_schedule_cmp_DEPENDENCIES) $(EXTRA_isl_schedule_cmp_DEPENDENCIES) 
+	@rm -f isl_schedule_cmp$(EXEEXT)
+	$(AM_V_CCLD)$(isl_schedule_cmp_LINK) $(isl_schedule_cmp_OBJECTS) $(isl_schedule_cmp_LDADD) $(LIBS)
+
+isl_test$(EXEEXT): $(isl_test_OBJECTS) $(isl_test_DEPENDENCIES) $(EXTRA_isl_test_DEPENDENCIES) 
+	@rm -f isl_test$(EXEEXT)
+	$(AM_V_CCLD)$(isl_test_LINK) $(isl_test_OBJECTS) $(isl_test_LDADD) $(LIBS)
+
+isl_test_imath$(EXEEXT): $(isl_test_imath_OBJECTS) $(isl_test_imath_DEPENDENCIES) $(EXTRA_isl_test_imath_DEPENDENCIES) 
+	@rm -f isl_test_imath$(EXEEXT)
+	$(AM_V_CCLD)$(isl_test_imath_LINK) $(isl_test_imath_OBJECTS) $(isl_test_imath_LDADD) $(LIBS)
+
+isl_test_int$(EXEEXT): $(isl_test_int_OBJECTS) $(isl_test_int_DEPENDENCIES) $(EXTRA_isl_test_int_DEPENDENCIES) 
+	@rm -f isl_test_int$(EXEEXT)
+	$(AM_V_CCLD)$(isl_test_int_LINK) $(isl_test_int_OBJECTS) $(isl_test_int_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+	-rm -f imath_wrap/*.$(OBJEXT)
+	-rm -f imath_wrap/*.lo
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basis_reduction_tab.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bound.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/closure.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/codegen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow_cmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_aff.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_affine_hull.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_arg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_ast.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_ast_build.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_ast_build_expr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_ast_codegen.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_ast_graft.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_ast_int.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_band.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_bernstein.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_blk.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_bound.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_coalesce.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_constraint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_convex_hull.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_ctx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_deprecated.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_dim_map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_equalities.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_factorization.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_farkas.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_ffs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_flow.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_fold.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_gmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_hash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_id.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_id_to_ast_expr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_id_to_id.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_id_to_pw_aff.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_ilp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_imath.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_input.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_int_sioimath.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_local.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_local_space.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_lp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_map_list.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_map_simplify.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_map_subtract.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_map_to_basic_set.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_mat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_morph.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_obj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_options.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_output.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_point.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_polynomial.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_printer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_range.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_reordering.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_sample.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_scan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_schedule.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_schedule_band.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_schedule_constraints.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_schedule_node.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_schedule_read.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_schedule_tree.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_scheduler.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_seq.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_set_list.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_sort.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_space.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_stream.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_tab.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_tab_pip.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_tarjan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_test_imath.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_test_int.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_transitive_closure.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_union_map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_val.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_val_gmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_val_imath.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_val_sioimath.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_vec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_version.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isl_vertices.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp_get_memory_functions.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pip.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/polyhedron_detect_equalities.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/polyhedron_minimize.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/polyhedron_sample.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/polytope_scan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/schedule.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/schedule_cmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@imath_wrap/$(DEPDIR)/gmp_compat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@imath_wrap/$(DEPDIR)/imath.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@imath_wrap/$(DEPDIR)/imrat.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+	-rm -rf imath_wrap/.libs imath_wrap/_libs
+
+distclean-libtool:
+	-rm -f libtool config.lt
+install-pkgconfigDATA: $(pkgconfig_DATA)
+	@$(NORMAL_INSTALL)
+	@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+	  $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+	done
+
+uninstall-pkgconfigDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
+install-deprecatedHEADERS: $(deprecated_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(deprecated_HEADERS)'; test -n "$(deprecateddir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(deprecateddir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(deprecateddir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(deprecateddir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(deprecateddir)" || exit $$?; \
+	done
+
+uninstall-deprecatedHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(deprecated_HEADERS)'; test -n "$(deprecateddir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(deprecateddir)'; $(am__uninstall_files_from_dir)
+install-nodist_pkgincludeHEADERS: $(nodist_pkginclude_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(nodist_pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \
+	done
+
+uninstall-nodist_pkgincludeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(nodist_pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir)
+install-pkgincludeHEADERS: $(pkginclude_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \
+	done
+
+uninstall-pkgincludeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+	test ! -s cscope.files \
+	  || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+	-rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+	-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all 
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+isl_test.log: isl_test$(EXEEXT)
+	@p='isl_test$(EXEEXT)'; \
+	b='isl_test'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+codegen_test.sh.log: codegen_test.sh
+	@p='codegen_test.sh'; \
+	b='codegen_test.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+pip_test.sh.log: pip_test.sh
+	@p='pip_test.sh'; \
+	b='pip_test.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+bound_test.sh.log: bound_test.sh
+	@p='bound_test.sh'; \
+	b='bound_test.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+isl_test_int.log: isl_test_int$(EXEEXT)
+	@p='isl_test_int$(EXEEXT)'; \
+	b='isl_test_int'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+flow_test.sh.log: flow_test.sh
+	@p='flow_test.sh'; \
+	b='flow_test.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+schedule_test.sh.log: schedule_test.sh
+	@p='schedule_test.sh'; \
+	b='schedule_test.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+isl_test_imath.log: isl_test_imath$(EXEEXT)
+	@p='isl_test_imath$(EXEEXT)'; \
+	b='isl_test_imath'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@	@p='$<'; \
+@am__EXEEXT_TRUE@	$(am__set_b); \
+@am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+	$(am__remove_distdir)
+	test -d "$(distdir)" || mkdir "$(distdir)"
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+	$(MAKE) $(AM_MAKEFLAGS) \
+	  top_distdir="$(top_distdir)" distdir="$(distdir)" \
+	  dist-hook
+	-test -n "$(am__skip_mode_fix)" \
+	|| find "$(distdir)" -type d ! -perm -755 \
+		-exec chmod u+rwx,go+rx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__post_remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+	$(am__post_remove_distdir)
+
+dist-lzip: distdir
+	tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+	$(am__post_remove_distdir)
+
+dist-xz: distdir
+	tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+	$(am__post_remove_distdir)
+
+dist-tarZ: distdir
+	@echo WARNING: "Support for distribution archives compressed with" \
+		       "legacy program 'compress' is deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__post_remove_distdir)
+
+dist-shar: distdir
+	@echo WARNING: "Support for shar distribution archives is" \
+	               "deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	$(am__post_remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__post_remove_distdir)
+
+dist dist-all:
+	$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+	$(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.lz*) \
+	  lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+	*.tar.xz*) \
+	  xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir)
+	chmod u+w $(distdir)
+	mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
+	chmod a-w $(distdir)
+	test -d $(distdir)/_build || exit 0; \
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && am__cwd=`pwd` \
+	  && $(am__cd) $(distdir)/_build/sub \
+	  && ../../configure \
+	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	    --srcdir=../.. --prefix="$$dc_install_base" \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+	  && cd "$$am__cwd" \
+	  || exit 1
+	$(am__post_remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+	@test -n '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: trying to run $@ with an empty' \
+	       '$$(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	$(am__cd) '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-recursive
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) \
+		isl_config.h
+installdirs: installdirs-recursive
+installdirs-am:
+	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(deprecateddir)" "$(DESTDIR)$(pkgincludedir)" "$(DESTDIR)$(pkgincludedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-rm -f imath_wrap/$(DEPDIR)/$(am__dirstamp)
+	-rm -f imath_wrap/$(am__dirstamp)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+	clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf ./$(DEPDIR) imath_wrap/$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-data-local install-deprecatedHEADERS \
+	install-nodist_pkgincludeHEADERS install-pkgconfigDATA \
+	install-pkgincludeHEADERS
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -rf ./$(DEPDIR) imath_wrap/$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-deprecatedHEADERS uninstall-libLTLIBRARIES \
+	uninstall-local uninstall-nodist_pkgincludeHEADERS \
+	uninstall-pkgconfigDATA uninstall-pkgincludeHEADERS
+
+.MAKE: $(am__recursive_targets) all check check-am install install-am \
+	install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+	am--refresh check check-TESTS check-am clean clean-cscope \
+	clean-generic clean-libLTLIBRARIES clean-libtool \
+	clean-noinstPROGRAMS cscope cscopelist-am ctags ctags-am dist \
+	dist-all dist-bzip2 dist-gzip dist-hook dist-lzip dist-shar \
+	dist-tarZ dist-xz dist-zip distcheck distclean \
+	distclean-compile distclean-generic distclean-hdr \
+	distclean-libtool distclean-tags distcleancheck distdir \
+	distuninstallcheck dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am \
+	install-data-local install-deprecatedHEADERS install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am \
+	install-libLTLIBRARIES install-man \
+	install-nodist_pkgincludeHEADERS install-pdf install-pdf-am \
+	install-pkgconfigDATA install-pkgincludeHEADERS install-ps \
+	install-ps-am install-strip installcheck installcheck-am \
+	installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	recheck tags tags-am uninstall uninstall-am \
+	uninstall-deprecatedHEADERS uninstall-libLTLIBRARIES \
+	uninstall-local uninstall-nodist_pkgincludeHEADERS \
+	uninstall-pkgconfigDATA uninstall-pkgincludeHEADERS
+
+.PRECIOUS: Makefile
+
+
+dist-hook:
+	echo @GIT_HEAD_VERSION@ > $(distdir)/GIT_HEAD_ID
+	(cd doc; make manual.pdf)
+	cp doc/manual.pdf $(distdir)/doc/
+
+gitversion.h: @GIT_HEAD@
+	$(AM_V_GEN)echo '#define GIT_HEAD_ID "'@GIT_HEAD_VERSION@'"' > $@
+
+install-data-local: $(srcdir)/isl.py
+	@libisl=`sed -ne "/^library_names=/{s/.*='//;s/'$$//;s/ .*//;p;}" \
+		 $(builddir)/libisl.la`; \
+	case $$libisl in \
+	'') echo Cannot find isl library name. GDB bindings not installed.;; \
+	*) echo $(INSTALL_DATA) $(srcdir)/isl.py \
+		$(DESTDIR)$(libdir)/$$libisl-gdb.py; \
+	test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"; \
+	$(INSTALL_DATA) $(srcdir)/isl.py $(DESTDIR)$(libdir)/$$libisl-gdb.py; esac
+
+uninstall-local:
+	@libisl=`sed -ne "/^library_names=/{s/.*='//;s/'$$//;s/ .*//;p;}" \
+		 $(builddir)/libisl.la`; \
+	if test -n "$${libisl}"; then \
+		rm -f $(DESTDIR)$(libdir)/$$libisl-gdb.py; \
+	fi
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/final/lib/External/isl/README b/final/lib/External/isl/README
new file mode 100644
index 0000000..9f48a0a
--- /dev/null
+++ b/final/lib/External/isl/README
@@ -0,0 +1,53 @@
+isl is a thread-safe C library for manipulating sets and relations
+of integer points bounded by affine constraints.  The descriptions of
+the sets and relations may involve both parameters and existentially
+quantified variables.  All computations are performed in exact integer
+arithmetic using GMP.
+
+isl is released under the MIT license, but depends on the LGPL GMP
+library.
+
+Minimal compilation instructions:
+
+	./configure
+	make
+	make install
+
+If you are taking the source from the git repository, then you first
+need to do
+
+	git clone git://repo.or.cz/isl.git
+	./autogen.sh
+
+For more information, see doc/user.pod or the generated documentation.
+
+New releases are announced on http://freecode.com/projects/isl
+
+If you use isl, you can let me know by stacking
+https://www.ohloh.net/p/isl on ohloh.
+
+For bug reports, feature requests and questions,
+contact http://groups.google.com/group/isl-development
+
+Whenever you report a bug, please mention the exact version of isl
+that you are using (output of "./isl_cat --version").  If you are unable
+to compile isl, then report the git version (output of "git describe")
+or the version included in the name of the tarball.
+
+If you use isl for your research, you are invited do cite
+the following paper and/or the paper(s) describing the specific
+operations you use.
+
+@incollection{Verdoolaege2010isl,
+   author = {Verdoolaege, Sven},
+   title = {isl: An Integer Set Library for the Polyhedral Model},
+   booktitle = {Mathematical Software - ICMS 2010},
+   series = {Lecture Notes in Computer Science},
+   editor = {Fukuda, Komei and Hoeven, Joris and Joswig, Michael and
+		Takayama, Nobuki},
+   publisher = {Springer},
+   isbn = {978-3-642-15581-9},
+   pages = {299-302},
+   volume = {6327},
+   year = {2010}
+}
diff --git a/final/lib/External/isl/aclocal.m4 b/final/lib/External/isl/aclocal.m4
new file mode 100644
index 0000000..638fadd
--- /dev/null
+++ b/final/lib/External/isl/aclocal.m4
@@ -0,0 +1,1174 @@
+# generated automatically by aclocal 1.15 -*- Autoconf -*-
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.15'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.15], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.15])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+       [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC],   [depcc="$CC"   am_compiler_list=],
+      [$1], [CXX],  [depcc="$CXX"  am_compiler_list=],
+      [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+      [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+      [$1], [UPC],  [depcc="$UPC"  am_compiler_list=],
+      [$1], [GCJ],  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                    [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  am__universal=false
+  m4_case([$1], [CC],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac],
+    [CXX],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac])
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+  [--enable-dependency-tracking],
+  [do not reject slow dependency extractors])
+AS_HELP_STRING(
+  [--disable-dependency-tracking],
+  [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`AS_DIRNAME("$mf")`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`AS_DIRNAME(["$file"])`
+      AS_MKDIR_P([$dirpart/$fdir])
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each '.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+             [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+  m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+  [ok:ok],,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+	      [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+			     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+		  [_AM_DEPENDENCIES([CC])],
+		  [m4_define([AC_PROG_CC],
+			     m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+		  [_AM_DEPENDENCIES([CXX])],
+		  [m4_define([AC_PROG_CXX],
+			     m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+		  [_AM_DEPENDENCIES([OBJC])],
+		  [m4_define([AC_PROG_OBJC],
+			     m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+		  [_AM_DEPENDENCIES([OBJCXX])],
+		  [m4_define([AC_PROG_OBJCXX],
+			     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+  fi
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes.	            -*- Autoconf -*-
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake.  We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+  [whether $CC understands -c and -o together],
+  [am_cv_prog_cc_c_o],
+  [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[[\\\"\#\$\&\'\`$am_lf]]*)
+    AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+  *[[\\\"\#\$\&\'\`$am_lf\ \	]]*)
+    AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$[*]" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$[*]" != "X $srcdir/configure conftest.file" \
+	&& test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment])
+     fi
+     if test "$[2]" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+  [AC_MSG_CHECKING([that generated files are newer than configure])
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+  [--enable-silent-rules],
+  [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+  [--disable-silent-rules],
+  [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+   [am_cv_make_support_nested_variables],
+   [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+  dnl Using '$V' instead of '$(V)' breaks IRIX make.
+  AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+  [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+  [m4_case([$1],
+    [ustar],
+     [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+      # There is notably a 21 bits limit for the UID and the GID.  In fact,
+      # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+      # and bug#13588).
+      am_max_uid=2097151 # 2^21 - 1
+      am_max_gid=$am_max_uid
+      # The $UID and $GID variables are not portable, so we need to resort
+      # to the POSIX-mandated id(1) utility.  Errors in the 'id' calls
+      # below are definitely unexpected, so allow the users to see them
+      # (that is, avoid stderr redirection).
+      am_uid=`id -u || echo unknown`
+      am_gid=`id -g || echo unknown`
+      AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+      if test $am_uid -le $am_max_uid; then
+         AC_MSG_RESULT([yes])
+      else
+         AC_MSG_RESULT([no])
+         _am_tools=none
+      fi
+      AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+      if test $am_gid -le $am_max_gid; then
+         AC_MSG_RESULT([yes])
+      else
+        AC_MSG_RESULT([no])
+        _am_tools=none
+      fi],
+
+  [pax],
+    [],
+
+  [m4_fatal([Unknown tar format])])
+
+  AC_MSG_CHECKING([how to create a $1 tar archive])
+
+  # Go ahead even if we have the value already cached.  We do so because we
+  # need to set the values for the 'am__tar' and 'am__untar' variables.
+  _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+  for _am_tool in $_am_tools; do
+    case $_am_tool in
+    gnutar)
+      for _am_tar in tar gnutar gtar; do
+        AM_RUN_LOG([$_am_tar --version]) && break
+      done
+      am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+      am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+      am__untar="$_am_tar -xf -"
+      ;;
+    plaintar)
+      # Must skip GNU tar: if it does not support --format= it doesn't create
+      # ustar tarball either.
+      (tar --version) >/dev/null 2>&1 && continue
+      am__tar='tar chf - "$$tardir"'
+      am__tar_='tar chf - "$tardir"'
+      am__untar='tar xf -'
+      ;;
+    pax)
+      am__tar='pax -L -x $1 -w "$$tardir"'
+      am__tar_='pax -L -x $1 -w "$tardir"'
+      am__untar='pax -r'
+      ;;
+    cpio)
+      am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+      am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+      am__untar='cpio -i -H $1 -d'
+      ;;
+    none)
+      am__tar=false
+      am__tar_=false
+      am__untar=false
+      ;;
+    esac
+
+    # If the value was cached, stop now.  We just wanted to have am__tar
+    # and am__untar set.
+    test -n "${am_cv_prog_tar_$1}" && break
+
+    # tar/untar a dummy directory, and stop if the command works.
+    rm -rf conftest.dir
+    mkdir conftest.dir
+    echo GrepMe > conftest.dir/file
+    AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+    rm -rf conftest.dir
+    if test -s conftest.tar; then
+      AM_RUN_LOG([$am__untar <conftest.tar])
+      AM_RUN_LOG([cat conftest.dir/file])
+      grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+    fi
+  done
+  rm -rf conftest.dir
+
+  AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+  AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/ax_c___attribute__.m4])
+m4_include([m4/ax_cc_maxopt.m4])
+m4_include([m4/ax_check_compiler_flags.m4])
+m4_include([m4/ax_compiler_vendor.m4])
+m4_include([m4/ax_create_pkgconfig_info.m4])
+m4_include([m4/ax_create_stdint_h.m4])
+m4_include([m4/ax_cxx_compile_stdcxx.m4])
+m4_include([m4/ax_cxx_compile_stdcxx_11.m4])
+m4_include([m4/ax_detect_clang.m4])
+m4_include([m4/ax_detect_git_head.m4])
+m4_include([m4/ax_detect_gmp.m4])
+m4_include([m4/ax_detect_imath.m4])
+m4_include([m4/ax_gcc_archflag.m4])
+m4_include([m4/ax_gcc_warn_unused_result.m4])
+m4_include([m4/ax_gcc_x86_cpuid.m4])
+m4_include([m4/ax_set_warning_flags.m4])
+m4_include([m4/ax_submodule.m4])
+m4_include([m4/libtool.m4])
+m4_include([m4/ltoptions.m4])
+m4_include([m4/ltsugar.m4])
+m4_include([m4/ltversion.m4])
+m4_include([m4/lt~obsolete.m4])
diff --git a/final/lib/External/isl/basis_reduction_tab.c b/final/lib/External/isl/basis_reduction_tab.c
new file mode 100644
index 0000000..b42f677
--- /dev/null
+++ b/final/lib/External/isl/basis_reduction_tab.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <assert.h>
+#include <isl_map_private.h>
+#include <isl_seq.h>
+#include "isl_tab.h"
+#include <isl_int.h>
+#include <isl_config.h>
+
+struct tab_lp {
+	struct isl_ctx  *ctx;
+	struct isl_vec  *row;
+	struct isl_tab  *tab;
+	struct isl_tab_undo	**stack;
+	isl_int		*obj;
+	isl_int		 opt;
+	isl_int		 opt_denom;
+	isl_int		 tmp;
+	isl_int		 tmp2;
+	int	         neq;
+	unsigned	 dim;
+	/* number of constraints in initial product tableau */
+	int		 con_offset;
+	/* objective function has fixed or no integer value */
+	int		 is_fixed;
+};
+
+#ifdef USE_GMP_FOR_MP
+#define GBR_type		    	    mpq_t
+#define GBR_init(v)		    	    mpq_init(v)
+#define GBR_clear(v)		    	    mpq_clear(v)
+#define GBR_set(a,b)			    mpq_set(a,b)
+#define GBR_set_ui(a,b)			    mpq_set_ui(a,b,1)
+#define GBR_mul(a,b,c)			    mpq_mul(a,b,c)
+#define GBR_lt(a,b)			    (mpq_cmp(a,b) < 0)
+#define GBR_is_zero(a)			    (mpq_sgn(a) == 0)
+#define GBR_numref(a)			    mpq_numref(a)
+#define GBR_denref(a)			    mpq_denref(a)
+#define GBR_floor(a,b)			    mpz_fdiv_q(a,GBR_numref(b),GBR_denref(b))
+#define GBR_ceil(a,b)			    mpz_cdiv_q(a,GBR_numref(b),GBR_denref(b))
+#define GBR_set_num_neg(a, b)		    mpz_neg(GBR_numref(*a), b);
+#define GBR_set_den(a, b)		    mpz_set(GBR_denref(*a), b);
+#endif /* USE_GMP_FOR_MP */
+
+#ifdef USE_IMATH_FOR_MP
+#include <imrat.h>
+
+#define GBR_type		    	    mp_rat
+#define GBR_init(v)		    	    v = mp_rat_alloc()
+#define GBR_clear(v)		    	    mp_rat_free(v)
+#define GBR_set(a,b)			    mp_rat_copy(b,a)
+#define GBR_set_ui(a,b)			    mp_rat_set_uvalue(a,b,1)
+#define GBR_mul(a,b,c)			    mp_rat_mul(b,c,a)
+#define GBR_lt(a,b)			    (mp_rat_compare(a,b) < 0)
+#define GBR_is_zero(a)			    (mp_rat_compare_zero(a) == 0)
+#ifdef USE_SMALL_INT_OPT
+#define GBR_numref(a)	isl_sioimath_encode_big(mp_rat_numer_ref(a))
+#define GBR_denref(a)	isl_sioimath_encode_big(mp_rat_denom_ref(a))
+#define GBR_floor(a, b)	isl_sioimath_fdiv_q((a), GBR_numref(b), GBR_denref(b))
+#define GBR_ceil(a, b)	isl_sioimath_cdiv_q((a), GBR_numref(b), GBR_denref(b))
+#define GBR_set_num_neg(a, b)                              \
+	do {                                               \
+		isl_sioimath_scratchspace_t scratch;       \
+		impz_neg(mp_rat_numer_ref(*a),             \
+		    isl_sioimath_bigarg_src(*b, &scratch));\
+	} while (0)
+#define GBR_set_den(a, b)                                  \
+	do {                                               \
+		isl_sioimath_scratchspace_t scratch;       \
+		impz_set(mp_rat_denom_ref(*a),             \
+		    isl_sioimath_bigarg_src(*b, &scratch));\
+	} while (0)
+#else /* USE_SMALL_INT_OPT */
+#define GBR_numref(a)		mp_rat_numer_ref(a)
+#define GBR_denref(a)		mp_rat_denom_ref(a)
+#define GBR_floor(a,b)		impz_fdiv_q(a,GBR_numref(b),GBR_denref(b))
+#define GBR_ceil(a,b)		impz_cdiv_q(a,GBR_numref(b),GBR_denref(b))
+#define GBR_set_num_neg(a, b)	impz_neg(GBR_numref(*a), b)
+#define GBR_set_den(a, b)	impz_set(GBR_denref(*a), b)
+#endif /* USE_SMALL_INT_OPT */
+#endif /* USE_IMATH_FOR_MP */
+
+static struct tab_lp *init_lp(struct isl_tab *tab);
+static void set_lp_obj(struct tab_lp *lp, isl_int *row, int dim);
+static int solve_lp(struct tab_lp *lp);
+static void get_obj_val(struct tab_lp* lp, GBR_type *F);
+static void delete_lp(struct tab_lp *lp);
+static int add_lp_row(struct tab_lp *lp, isl_int *row, int dim);
+static void get_alpha(struct tab_lp* lp, int row, GBR_type *alpha);
+static int del_lp_row(struct tab_lp *lp) WARN_UNUSED;
+static int cut_lp_to_hyperplane(struct tab_lp *lp, isl_int *row);
+
+#define GBR_LP			    	    struct tab_lp
+#define GBR_lp_init(P)		    	    init_lp(P)
+#define GBR_lp_set_obj(lp, obj, dim)	    set_lp_obj(lp, obj, dim)
+#define GBR_lp_solve(lp)		    solve_lp(lp)
+#define GBR_lp_get_obj_val(lp, F)	    get_obj_val(lp, F)
+#define GBR_lp_delete(lp)		    delete_lp(lp)
+#define GBR_lp_next_row(lp)		    lp->neq
+#define GBR_lp_add_row(lp, row, dim)	    add_lp_row(lp, row, dim)
+#define GBR_lp_get_alpha(lp, row, alpha)    get_alpha(lp, row, alpha)
+#define GBR_lp_del_row(lp)		    del_lp_row(lp)
+#define GBR_lp_is_fixed(lp)		    (lp)->is_fixed
+#define GBR_lp_cut(lp, obj)	    	    cut_lp_to_hyperplane(lp, obj)
+#include "basis_reduction_templ.c"
+
+/* Set up a tableau for the Cartesian product of bset with itself.
+ * This could be optimized by first setting up a tableau for bset
+ * and then performing the Cartesian product on the tableau.
+ */
+static struct isl_tab *gbr_tab(struct isl_tab *tab, struct isl_vec *row)
+{
+	unsigned dim;
+	struct isl_tab *prod;
+
+	if (!tab || !row)
+		return NULL;
+
+	dim = tab->n_var;
+	prod = isl_tab_product(tab, tab);
+	if (isl_tab_extend_cons(prod, 3 * dim + 1) < 0) {
+		isl_tab_free(prod);
+		return NULL;
+	}
+	return prod;
+}
+
+static struct tab_lp *init_lp(struct isl_tab *tab)
+{
+	struct tab_lp *lp = NULL;
+
+	if (!tab)
+		return NULL;
+
+	lp = isl_calloc_type(tab->mat->ctx, struct tab_lp);
+	if (!lp)
+		return NULL;
+
+	isl_int_init(lp->opt);
+	isl_int_init(lp->opt_denom);
+	isl_int_init(lp->tmp);
+	isl_int_init(lp->tmp2);
+
+	lp->dim = tab->n_var;
+
+	lp->ctx = tab->mat->ctx;
+	isl_ctx_ref(lp->ctx);
+
+	lp->stack = isl_alloc_array(lp->ctx, struct isl_tab_undo *, lp->dim);
+
+	lp->row = isl_vec_alloc(lp->ctx, 1 + 2 * lp->dim);
+	if (!lp->row)
+		goto error;
+	lp->tab = gbr_tab(tab, lp->row);
+	if (!lp->tab)
+		goto error;
+	lp->con_offset = lp->tab->n_con;
+	lp->obj = NULL;
+	lp->neq = 0;
+
+	return lp;
+error:
+	delete_lp(lp);
+	return NULL;
+}
+
+static void set_lp_obj(struct tab_lp *lp, isl_int *row, int dim)
+{
+	lp->obj = row;
+}
+
+static int solve_lp(struct tab_lp *lp)
+{
+	enum isl_lp_result res;
+	unsigned flags = 0;
+
+	lp->is_fixed = 0;
+
+	isl_int_set_si(lp->row->el[0], 0);
+	isl_seq_cpy(lp->row->el + 1, lp->obj, lp->dim);
+	isl_seq_neg(lp->row->el + 1 + lp->dim, lp->obj, lp->dim);
+	if (lp->neq)
+		flags = ISL_TAB_SAVE_DUAL;
+	res = isl_tab_min(lp->tab, lp->row->el, lp->ctx->one,
+			  &lp->opt, &lp->opt_denom, flags);
+	isl_int_mul_ui(lp->opt_denom, lp->opt_denom, 2);
+	if (isl_int_abs_lt(lp->opt, lp->opt_denom)) {
+		struct isl_vec *sample = isl_tab_get_sample_value(lp->tab);
+		if (!sample)
+			return -1;
+		isl_seq_inner_product(lp->obj, sample->el + 1, lp->dim, &lp->tmp);
+		isl_seq_inner_product(lp->obj, sample->el + 1 + lp->dim, lp->dim, &lp->tmp2);
+		isl_int_cdiv_q(lp->tmp, lp->tmp, sample->el[0]);
+		isl_int_fdiv_q(lp->tmp2, lp->tmp2, sample->el[0]);
+		if (isl_int_ge(lp->tmp, lp->tmp2))
+			lp->is_fixed = 1;
+		isl_vec_free(sample);
+	}
+	isl_int_divexact_ui(lp->opt_denom, lp->opt_denom, 2);
+	if (res < 0)
+		return -1;
+	if (res != isl_lp_ok)
+		isl_die(lp->ctx, isl_error_internal,
+			"unexpected missing (bounded) solution", return -1);
+	return 0;
+}
+
+/* The current objective function has a fixed (or no) integer value.
+ * Cut the tableau to the hyperplane that fixes this value in
+ * both halves of the tableau.
+ * Return 1 if the resulting tableau is empty.
+ */
+static int cut_lp_to_hyperplane(struct tab_lp *lp, isl_int *row)
+{
+	enum isl_lp_result res;
+
+	isl_int_set_si(lp->row->el[0], 0);
+	isl_seq_cpy(lp->row->el + 1, row, lp->dim);
+	isl_seq_clr(lp->row->el + 1 + lp->dim, lp->dim);
+	res = isl_tab_min(lp->tab, lp->row->el, lp->ctx->one,
+			  &lp->tmp, NULL, 0);
+	if (res != isl_lp_ok)
+		return -1;
+
+	isl_int_neg(lp->row->el[0], lp->tmp);
+	if (isl_tab_add_eq(lp->tab, lp->row->el) < 0)
+		return -1;
+
+	isl_seq_cpy(lp->row->el + 1 + lp->dim, row, lp->dim);
+	isl_seq_clr(lp->row->el + 1, lp->dim);
+	if (isl_tab_add_eq(lp->tab, lp->row->el) < 0)
+		return -1;
+
+	lp->con_offset += 2;
+
+	return lp->tab->empty;
+}
+
+static void get_obj_val(struct tab_lp* lp, GBR_type *F)
+{
+	GBR_set_num_neg(F, lp->opt);
+	GBR_set_den(F, lp->opt_denom);
+}
+
+static void delete_lp(struct tab_lp *lp)
+{
+	if (!lp)
+		return;
+
+	isl_int_clear(lp->opt);
+	isl_int_clear(lp->opt_denom);
+	isl_int_clear(lp->tmp);
+	isl_int_clear(lp->tmp2);
+	isl_vec_free(lp->row);
+	free(lp->stack);
+	isl_tab_free(lp->tab);
+	isl_ctx_deref(lp->ctx);
+	free(lp);
+}
+
+static int add_lp_row(struct tab_lp *lp, isl_int *row, int dim)
+{
+	lp->stack[lp->neq] = isl_tab_snap(lp->tab);
+
+	isl_int_set_si(lp->row->el[0], 0);
+	isl_seq_cpy(lp->row->el + 1, row, lp->dim);
+	isl_seq_neg(lp->row->el + 1 + lp->dim, row, lp->dim);
+
+	if (isl_tab_add_valid_eq(lp->tab, lp->row->el) < 0)
+		return -1;
+
+	return lp->neq++;
+}
+
+static void get_alpha(struct tab_lp* lp, int row, GBR_type *alpha)
+{
+	row += lp->con_offset;
+	GBR_set_num_neg(alpha, lp->tab->dual->el[1 + row]);
+	GBR_set_den(alpha, lp->tab->dual->el[0]);
+}
+
+static int del_lp_row(struct tab_lp *lp)
+{
+	lp->neq--;
+	return isl_tab_rollback(lp->tab, lp->stack[lp->neq]);
+}
diff --git a/final/lib/External/isl/basis_reduction_templ.c b/final/lib/External/isl/basis_reduction_templ.c
new file mode 100644
index 0000000..a5da1e6
--- /dev/null
+++ b/final/lib/External/isl/basis_reduction_templ.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2006-2007 Universiteit Leiden
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science,
+ * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands
+ * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A,
+ * B-3001 Leuven, Belgium
+ */
+
+#include <stdlib.h>
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_vec_private.h>
+#include <isl_options_private.h>
+#include "isl_basis_reduction.h"
+
+static void save_alpha(GBR_LP *lp, int first, int n, GBR_type *alpha)
+{
+	int i;
+
+	for (i = 0; i < n; ++i)
+		GBR_lp_get_alpha(lp, first + i, &alpha[i]);
+}
+
+/* Compute a reduced basis for the set represented by the tableau "tab".
+ * tab->basis, which must be initialized by the calling function to an affine
+ * unimodular basis, is updated to reflect the reduced basis.
+ * The first tab->n_zero rows of the basis (ignoring the constant row)
+ * are assumed to correspond to equalities and are left untouched.
+ * tab->n_zero is updated to reflect any additional equalities that
+ * have been detected in the first rows of the new basis.
+ * The final tab->n_unbounded rows of the basis are assumed to correspond
+ * to unbounded directions and are also left untouched.
+ * In particular this means that the remaining rows are assumed to
+ * correspond to bounded directions.
+ *
+ * This function implements the algorithm described in
+ * "An Implementation of the Generalized Basis Reduction Algorithm
+ *  for Integer Programming" of Cook el al. to compute a reduced basis.
+ * We use \epsilon = 1/4.
+ *
+ * If ctx->opt->gbr_only_first is set, the user is only interested
+ * in the first direction.  In this case we stop the basis reduction when
+ * the width in the first direction becomes smaller than 2.
+ */
+struct isl_tab *isl_tab_compute_reduced_basis(struct isl_tab *tab)
+{
+	unsigned dim;
+	struct isl_ctx *ctx;
+	struct isl_mat *B;
+	int i;
+	GBR_LP *lp = NULL;
+	GBR_type F_old, alpha, F_new;
+	int row;
+	isl_int tmp;
+	struct isl_vec *b_tmp;
+	GBR_type *F = NULL;
+	GBR_type *alpha_buffer[2] = { NULL, NULL };
+	GBR_type *alpha_saved;
+	GBR_type F_saved;
+	int use_saved = 0;
+	isl_int mu[2];
+	GBR_type mu_F[2];
+	GBR_type two;
+	GBR_type one;
+	int empty = 0;
+	int fixed = 0;
+	int fixed_saved = 0;
+	int mu_fixed[2];
+	int n_bounded;
+	int gbr_only_first;
+
+	if (!tab)
+		return NULL;
+
+	if (tab->empty)
+		return tab;
+
+	ctx = tab->mat->ctx;
+	gbr_only_first = ctx->opt->gbr_only_first;
+	dim = tab->n_var;
+	B = tab->basis;
+	if (!B)
+		return tab;
+
+	n_bounded = dim - tab->n_unbounded;
+	if (n_bounded <= tab->n_zero + 1)
+		return tab;
+
+	isl_int_init(tmp);
+	isl_int_init(mu[0]);
+	isl_int_init(mu[1]);
+
+	GBR_init(alpha);
+	GBR_init(F_old);
+	GBR_init(F_new);
+	GBR_init(F_saved);
+	GBR_init(mu_F[0]);
+	GBR_init(mu_F[1]);
+	GBR_init(two);
+	GBR_init(one);
+
+	b_tmp = isl_vec_alloc(ctx, dim);
+	if (!b_tmp)
+		goto error;
+
+	F = isl_alloc_array(ctx, GBR_type, n_bounded);
+	alpha_buffer[0] = isl_alloc_array(ctx, GBR_type, n_bounded);
+	alpha_buffer[1] = isl_alloc_array(ctx, GBR_type, n_bounded);
+	alpha_saved = alpha_buffer[0];
+
+	if (!F || !alpha_buffer[0] || !alpha_buffer[1])
+		goto error;
+
+	for (i = 0; i < n_bounded; ++i) {
+		GBR_init(F[i]);
+		GBR_init(alpha_buffer[0][i]);
+		GBR_init(alpha_buffer[1][i]);
+	}
+
+	GBR_set_ui(two, 2);
+	GBR_set_ui(one, 1);
+
+	lp = GBR_lp_init(tab);
+	if (!lp)
+		goto error;
+
+	i = tab->n_zero;
+
+	GBR_lp_set_obj(lp, B->row[1+i]+1, dim);
+	ctx->stats->gbr_solved_lps++;
+	if (GBR_lp_solve(lp) < 0)
+		goto error;
+	GBR_lp_get_obj_val(lp, &F[i]);
+
+	if (GBR_lt(F[i], one)) {
+		if (!GBR_is_zero(F[i])) {
+			empty = GBR_lp_cut(lp, B->row[1+i]+1);
+			if (empty)
+				goto done;
+			GBR_set_ui(F[i], 0);
+		}
+		tab->n_zero++;
+	}
+
+	do {
+		if (i+1 == tab->n_zero) {
+			GBR_lp_set_obj(lp, B->row[1+i+1]+1, dim);
+			ctx->stats->gbr_solved_lps++;
+			if (GBR_lp_solve(lp) < 0)
+				goto error;
+			GBR_lp_get_obj_val(lp, &F_new);
+			fixed = GBR_lp_is_fixed(lp);
+			GBR_set_ui(alpha, 0);
+		} else
+		if (use_saved) {
+			row = GBR_lp_next_row(lp);
+			GBR_set(F_new, F_saved);
+			fixed = fixed_saved;
+			GBR_set(alpha, alpha_saved[i]);
+		} else {
+			row = GBR_lp_add_row(lp, B->row[1+i]+1, dim);
+			GBR_lp_set_obj(lp, B->row[1+i+1]+1, dim);
+			ctx->stats->gbr_solved_lps++;
+			if (GBR_lp_solve(lp) < 0)
+				goto error;
+			GBR_lp_get_obj_val(lp, &F_new);
+			fixed = GBR_lp_is_fixed(lp);
+
+			GBR_lp_get_alpha(lp, row, &alpha);
+
+			if (i > 0)
+				save_alpha(lp, row-i, i, alpha_saved);
+
+			if (GBR_lp_del_row(lp) < 0)
+				goto error;
+		}
+		GBR_set(F[i+1], F_new);
+
+		GBR_floor(mu[0], alpha);
+		GBR_ceil(mu[1], alpha);
+
+		if (isl_int_eq(mu[0], mu[1]))
+			isl_int_set(tmp, mu[0]);
+		else {
+			int j;
+
+			for (j = 0; j <= 1; ++j) {
+				isl_int_set(tmp, mu[j]);
+				isl_seq_combine(b_tmp->el,
+						ctx->one, B->row[1+i+1]+1,
+						tmp, B->row[1+i]+1, dim);
+				GBR_lp_set_obj(lp, b_tmp->el, dim);
+				ctx->stats->gbr_solved_lps++;
+				if (GBR_lp_solve(lp) < 0)
+					goto error;
+				GBR_lp_get_obj_val(lp, &mu_F[j]);
+				mu_fixed[j] = GBR_lp_is_fixed(lp);
+				if (i > 0)
+					save_alpha(lp, row-i, i, alpha_buffer[j]);
+			}
+
+			if (GBR_lt(mu_F[0], mu_F[1]))
+				j = 0;
+			else
+				j = 1;
+
+			isl_int_set(tmp, mu[j]);
+			GBR_set(F_new, mu_F[j]);
+			fixed = mu_fixed[j];
+			alpha_saved = alpha_buffer[j];
+		}
+		isl_seq_combine(B->row[1+i+1]+1, ctx->one, B->row[1+i+1]+1,
+				tmp, B->row[1+i]+1, dim);
+
+		if (i+1 == tab->n_zero && fixed) {
+			if (!GBR_is_zero(F[i+1])) {
+				empty = GBR_lp_cut(lp, B->row[1+i+1]+1);
+				if (empty)
+					goto done;
+				GBR_set_ui(F[i+1], 0);
+			}
+			tab->n_zero++;
+		}
+
+		GBR_set(F_old, F[i]);
+
+		use_saved = 0;
+		/* mu_F[0] = 4 * F_new; mu_F[1] = 3 * F_old */
+		GBR_set_ui(mu_F[0], 4);
+		GBR_mul(mu_F[0], mu_F[0], F_new);
+		GBR_set_ui(mu_F[1], 3);
+		GBR_mul(mu_F[1], mu_F[1], F_old);
+		if (GBR_lt(mu_F[0], mu_F[1])) {
+			B = isl_mat_swap_rows(B, 1 + i, 1 + i + 1);
+			if (i > tab->n_zero) {
+				use_saved = 1;
+				GBR_set(F_saved, F_new);
+				fixed_saved = fixed;
+				if (GBR_lp_del_row(lp) < 0)
+					goto error;
+				--i;
+			} else {
+				GBR_set(F[tab->n_zero], F_new);
+				if (gbr_only_first && GBR_lt(F[tab->n_zero], two))
+					break;
+
+				if (fixed) {
+					if (!GBR_is_zero(F[tab->n_zero])) {
+						empty = GBR_lp_cut(lp, B->row[1+tab->n_zero]+1);
+						if (empty)
+							goto done;
+						GBR_set_ui(F[tab->n_zero], 0);
+					}
+					tab->n_zero++;
+				}
+			}
+		} else {
+			GBR_lp_add_row(lp, B->row[1+i]+1, dim);
+			++i;
+		}
+	} while (i < n_bounded - 1);
+
+	if (0) {
+done:
+		if (empty < 0) {
+error:
+			isl_mat_free(B);
+			B = NULL;
+		}
+	}
+
+	GBR_lp_delete(lp);
+
+	if (alpha_buffer[1])
+		for (i = 0; i < n_bounded; ++i) {
+			GBR_clear(F[i]);
+			GBR_clear(alpha_buffer[0][i]);
+			GBR_clear(alpha_buffer[1][i]);
+		}
+	free(F);
+	free(alpha_buffer[0]);
+	free(alpha_buffer[1]);
+
+	isl_vec_free(b_tmp);
+
+	GBR_clear(alpha);
+	GBR_clear(F_old);
+	GBR_clear(F_new);
+	GBR_clear(F_saved);
+	GBR_clear(mu_F[0]);
+	GBR_clear(mu_F[1]);
+	GBR_clear(two);
+	GBR_clear(one);
+
+	isl_int_clear(tmp);
+	isl_int_clear(mu[0]);
+	isl_int_clear(mu[1]);
+
+	tab->basis = B;
+
+	return tab;
+}
+
+/* Compute an affine form of a reduced basis of the given basic
+ * non-parametric set, which is assumed to be bounded and not
+ * include any integer divisions.
+ * The first column and the first row correspond to the constant term.
+ *
+ * If the input contains any equalities, we first create an initial
+ * basis with the equalities first.  Otherwise, we start off with
+ * the identity matrix.
+ */
+__isl_give isl_mat *isl_basic_set_reduced_basis(__isl_keep isl_basic_set *bset)
+{
+	struct isl_mat *basis;
+	struct isl_tab *tab;
+
+	if (!bset)
+		return NULL;
+
+	if (isl_basic_set_dim(bset, isl_dim_div) != 0)
+		isl_die(bset->ctx, isl_error_invalid,
+			"no integer division allowed", return NULL);
+	if (isl_basic_set_dim(bset, isl_dim_param) != 0)
+		isl_die(bset->ctx, isl_error_invalid,
+			"no parameters allowed", return NULL);
+
+	tab = isl_tab_from_basic_set(bset, 0);
+	if (!tab)
+		return NULL;
+
+	if (bset->n_eq == 0)
+		tab->basis = isl_mat_identity(bset->ctx, 1 + tab->n_var);
+	else {
+		isl_mat *eq;
+		unsigned nvar = isl_basic_set_total_dim(bset);
+		eq = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq,
+					1, nvar);
+		eq = isl_mat_left_hermite(eq, 0, NULL, &tab->basis);
+		tab->basis = isl_mat_lin_to_aff(tab->basis);
+		tab->n_zero = bset->n_eq;
+		isl_mat_free(eq);
+	}
+	tab = isl_tab_compute_reduced_basis(tab);
+	if (!tab)
+		return NULL;
+
+	basis = isl_mat_copy(tab->basis);
+
+	isl_tab_free(tab);
+
+	return basis;
+}
diff --git a/final/lib/External/isl/bound.c b/final/lib/External/isl/bound.c
new file mode 100644
index 0000000..00b643d
--- /dev/null
+++ b/final/lib/External/isl/bound.c
@@ -0,0 +1,289 @@
+#include <assert.h>
+#include <isl/stream.h>
+#include <isl_map_private.h>
+#include <isl_polynomial_private.h>
+#include <isl_scan.h>
+#include <isl/options.h>
+#include <isl/deprecated/point_int.h>
+#include <isl/deprecated/polynomial_int.h>
+
+struct bound_options {
+	struct isl_options	*isl;
+	unsigned		 verify;
+	int			 print_all;
+	int			 continue_on_error;
+};
+
+ISL_ARGS_START(struct bound_options, bound_options_args)
+ISL_ARG_CHILD(struct bound_options, isl, "isl", &isl_options_args,
+	"isl options")
+ISL_ARG_BOOL(struct bound_options, verify, 'T', "verify", 0, NULL)
+ISL_ARG_BOOL(struct bound_options, print_all, 'A', "print-all", 0, NULL)
+ISL_ARG_BOOL(struct bound_options, continue_on_error, '\0', "continue-on-error", 0, NULL)
+ISL_ARGS_END
+
+ISL_ARG_DEF(bound_options, struct bound_options, bound_options_args)
+
+static __isl_give isl_set *set_bounds(__isl_take isl_set *set)
+{
+	unsigned nparam;
+	int i, r;
+	isl_point *pt, *pt2;
+	isl_set *box;
+
+	nparam = isl_set_dim(set, isl_dim_param);
+	r = nparam >= 8 ? 5 : nparam >= 5 ? 15 : 50;
+
+	pt = isl_set_sample_point(isl_set_copy(set));
+	pt2 = isl_point_copy(pt);
+
+	for (i = 0; i < nparam; ++i) {
+		pt = isl_point_add_ui(pt, isl_dim_param, i, r);
+		pt2 = isl_point_sub_ui(pt2, isl_dim_param, i, r);
+	}
+
+	box = isl_set_box_from_points(pt, pt2);
+
+	return isl_set_intersect(set, box);
+}
+
+struct verify_point_bound {
+	struct bound_options *options;
+	int stride;
+	int n;
+	int exact;
+	int error;
+
+	isl_pw_qpolynomial_fold *pwf;
+	isl_pw_qpolynomial_fold *bound;
+};
+
+static isl_stat verify_point(__isl_take isl_point *pnt, void *user)
+{
+	int i;
+	unsigned nparam;
+	struct verify_point_bound *vpb = (struct verify_point_bound *) user;
+	isl_int t;
+	isl_ctx *ctx;
+	isl_pw_qpolynomial_fold *pwf;
+	isl_val *bound = NULL;
+	isl_val *opt = NULL;
+	isl_set *dom = NULL;
+	isl_printer *p;
+	const char *minmax;
+	isl_bool bounded;
+	int sign;
+	int ok;
+	FILE *out = vpb->options->print_all ? stdout : stderr;
+
+	vpb->n--;
+
+	if (1) {
+		minmax = "ub";
+		sign = 1;
+	} else {
+		minmax = "lb";
+		sign = -1;
+	}
+
+	ctx = isl_point_get_ctx(pnt);
+	p = isl_printer_to_file(ctx, out);
+
+	isl_int_init(t);
+
+	pwf = isl_pw_qpolynomial_fold_copy(vpb->pwf);
+
+	nparam = isl_pw_qpolynomial_fold_dim(pwf, isl_dim_param);
+	for (i = 0; i < nparam; ++i) {
+		isl_point_get_coordinate(pnt, isl_dim_param, i, &t);
+		pwf = isl_pw_qpolynomial_fold_fix_dim(pwf, isl_dim_param, i, t);
+	}
+
+	bound = isl_pw_qpolynomial_fold_eval(
+				    isl_pw_qpolynomial_fold_copy(vpb->bound),
+				    isl_point_copy(pnt));
+
+	dom = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf));
+	bounded = isl_set_is_bounded(dom);
+
+	if (bounded < 0)
+		goto error;
+
+	if (!bounded)
+		opt = isl_pw_qpolynomial_fold_eval(
+				    isl_pw_qpolynomial_fold_copy(pwf),
+				    isl_set_sample_point(isl_set_copy(dom)));
+	else if (sign > 0)
+		opt = isl_pw_qpolynomial_fold_max(isl_pw_qpolynomial_fold_copy(pwf));
+	else
+		opt = isl_pw_qpolynomial_fold_min(isl_pw_qpolynomial_fold_copy(pwf));
+
+	if (vpb->exact && bounded)
+		ok = isl_val_eq(opt, bound);
+	else if (sign > 0)
+		ok = isl_val_le(opt, bound);
+	else
+		ok = isl_val_le(bound, opt);
+	if (ok < 0)
+		goto error;
+
+	if (vpb->options->print_all || !ok) {
+		p = isl_printer_print_str(p, minmax);
+		p = isl_printer_print_str(p, "(");
+		for (i = 0; i < nparam; ++i) {
+			if (i)
+				p = isl_printer_print_str(p, ", ");
+			isl_point_get_coordinate(pnt, isl_dim_param, i, &t);
+			p = isl_printer_print_isl_int(p, t);
+		}
+		p = isl_printer_print_str(p, ") = ");
+		p = isl_printer_print_val(p, bound);
+		p = isl_printer_print_str(p, ", ");
+		p = isl_printer_print_str(p, bounded ? "opt" : "sample");
+		p = isl_printer_print_str(p, " = ");
+		p = isl_printer_print_val(p, opt);
+		if (ok)
+			p = isl_printer_print_str(p, ". OK");
+		else
+			p = isl_printer_print_str(p, ". NOT OK");
+		p = isl_printer_end_line(p);
+	} else if ((vpb->n % vpb->stride) == 0) {
+		p = isl_printer_print_str(p, "o");
+		p = isl_printer_flush(p);
+	}
+
+	if (0) {
+error:
+		ok = 0;
+	}
+
+	isl_pw_qpolynomial_fold_free(pwf);
+	isl_val_free(bound);
+	isl_val_free(opt);
+	isl_point_free(pnt);
+	isl_set_free(dom);
+
+	isl_int_clear(t);
+
+	isl_printer_free(p);
+
+	if (!ok)
+		vpb->error = 1;
+
+	if (vpb->options->continue_on_error)
+		ok = 1;
+
+	return (vpb->n >= 1 && ok) ? isl_stat_ok : isl_stat_error;
+}
+
+static int check_solution(__isl_take isl_pw_qpolynomial_fold *pwf,
+	__isl_take isl_pw_qpolynomial_fold *bound, int exact,
+	struct bound_options *options)
+{
+	struct verify_point_bound vpb;
+	isl_int count, max;
+	isl_set *dom;
+	isl_set *context;
+	int i, r, n;
+
+	dom = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf));
+	context = isl_set_params(isl_set_copy(dom));
+	context = isl_set_remove_divs(context);
+	context = set_bounds(context);
+
+	isl_int_init(count);
+	isl_int_init(max);
+
+	isl_int_set_si(max, 200);
+	r = isl_set_count_upto(context, max, &count);
+	assert(r >= 0);
+	n = isl_int_get_si(count);
+
+	isl_int_clear(max);
+	isl_int_clear(count);
+
+	vpb.options = options;
+	vpb.pwf = pwf;
+	vpb.bound = bound;
+	vpb.n = n;
+	vpb.stride = n > 70 ? 1 + (n + 1)/70 : 1;
+	vpb.error = 0;
+	vpb.exact = exact;
+
+	if (!options->print_all) {
+		for (i = 0; i < vpb.n; i += vpb.stride)
+			printf(".");
+		printf("\r");
+		fflush(stdout);
+	}
+
+	isl_set_foreach_point(context, verify_point, &vpb);
+
+	isl_set_free(context);
+	isl_set_free(dom);
+	isl_pw_qpolynomial_fold_free(pwf);
+	isl_pw_qpolynomial_fold_free(bound);
+
+	if (!options->print_all)
+		printf("\n");
+
+	if (vpb.error) {
+		fprintf(stderr, "Check failed !\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	isl_ctx *ctx;
+	isl_pw_qpolynomial_fold *copy;
+	isl_pw_qpolynomial_fold *pwf;
+	isl_stream *s;
+	struct isl_obj obj;
+	struct bound_options *options;
+	int exact;
+	int r = 0;
+
+	options = bound_options_new_with_defaults();
+	assert(options);
+	argc = bound_options_parse(options, argc, argv, ISL_ARG_ALL);
+
+	ctx = isl_ctx_alloc_with_options(&bound_options_args, options);
+
+	s = isl_stream_new_file(ctx, stdin);
+	obj = isl_stream_read_obj(s);
+	if (obj.type == isl_obj_pw_qpolynomial)
+		pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(isl_fold_max,
+								  obj.v);
+	else if (obj.type == isl_obj_pw_qpolynomial_fold)
+		pwf = obj.v;
+	else {
+		obj.type->free(obj.v);
+		isl_die(ctx, isl_error_invalid, "invalid input", goto error);
+	}
+
+	if (options->verify)
+		copy = isl_pw_qpolynomial_fold_copy(pwf);
+
+	pwf = isl_pw_qpolynomial_fold_bound(pwf, &exact);
+	pwf = isl_pw_qpolynomial_fold_coalesce(pwf);
+
+	if (options->verify) {
+		r = check_solution(copy, pwf, exact, options);
+	} else {
+		if (!exact)
+			printf("# NOT exact\n");
+		isl_pw_qpolynomial_fold_print(pwf, stdout, 0);
+		fprintf(stdout, "\n");
+		isl_pw_qpolynomial_fold_free(pwf);
+	}
+
+error:
+	isl_stream_free(s);
+
+	isl_ctx_free(ctx);
+
+	return r;
+}
diff --git a/final/lib/External/isl/bound_test.sh.in b/final/lib/External/isl/bound_test.sh.in
new file mode 100755
index 0000000..8f2f1ff
--- /dev/null
+++ b/final/lib/External/isl/bound_test.sh.in
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+EXEEXT=@EXEEXT@
+srcdir=@srcdir@
+
+BOUND_TESTS="\
+	basicLinear2.pwqp \
+	basicLinear.pwqp \
+	basicTestParameterPosNeg.pwqp \
+	basicTest.pwqp \
+	devos.pwqp \
+	equality1.pwqp \
+	equality2.pwqp \
+	equality3.pwqp \
+	equality4.pwqp \
+	equality5.pwqp \
+	faddeev.pwqp \
+	linearExample.pwqp \
+	neg.pwqp \
+	philippe3vars3pars.pwqp \
+	philippe3vars.pwqp \
+	philippeNeg.pwqp \
+	philippePolynomialCoeff1P.pwqp \
+	philippePolynomialCoeff.pwqp \
+	philippe.pwqp \
+	product.pwqp \
+	split.pwqp \
+	test3Deg3Var.pwqp \
+	toplas.pwqp \
+	unexpanded.pwqp"
+
+for i in $BOUND_TESTS; do
+	echo $i;
+	./isl_bound$EXEEXT -T --bound=bernstein < $srcdir/test_inputs/$i || exit
+	./isl_bound$EXEEXT -T --bound=range < $srcdir/test_inputs/$i || exit
+done
diff --git a/final/lib/External/isl/bset_from_bmap.c b/final/lib/External/isl/bset_from_bmap.c
new file mode 100644
index 0000000..9585080
--- /dev/null
+++ b/final/lib/External/isl/bset_from_bmap.c
@@ -0,0 +1,8 @@
+#include <isl/map_type.h>
+
+/* Return the basic set that was treated as the basic map "bmap".
+ */
+static __isl_give isl_basic_set *bset_from_bmap(__isl_take isl_basic_map *bmap)
+{
+	return (isl_basic_set *) bmap;
+}
diff --git a/final/lib/External/isl/bset_to_bmap.c b/final/lib/External/isl/bset_to_bmap.c
new file mode 100644
index 0000000..874fe71
--- /dev/null
+++ b/final/lib/External/isl/bset_to_bmap.c
@@ -0,0 +1,10 @@
+#include <isl/map_type.h>
+
+/* Treat "bset" as a basic map.
+ * Internally, isl_basic_set is defined to isl_basic_map, so in practice,
+ * this function performs a redundant cast.
+ */
+static __isl_give isl_basic_map *bset_to_bmap(__isl_take isl_basic_set *bset)
+{
+	return (isl_basic_map *) bset;
+}
diff --git a/final/lib/External/isl/cat.c b/final/lib/External/isl/cat.c
new file mode 100644
index 0000000..4f87133
--- /dev/null
+++ b/final/lib/External/isl/cat.c
@@ -0,0 +1,68 @@
+#include <assert.h>
+#include <isl/obj.h>
+#include <isl/printer.h>
+#include <isl/stream.h>
+#include <isl/options.h>
+
+struct isl_arg_choice cat_format[] = {
+	{"isl",		ISL_FORMAT_ISL},
+	{"omega",	ISL_FORMAT_OMEGA},
+	{"polylib",	ISL_FORMAT_POLYLIB},
+	{"ext-polylib",	ISL_FORMAT_EXT_POLYLIB},
+	{"latex",	ISL_FORMAT_LATEX},
+	{0}
+};
+
+struct isl_arg_choice cat_yaml_style[] = {
+	{ "block",	ISL_YAML_STYLE_BLOCK },
+	{ "flow",	ISL_YAML_STYLE_FLOW },
+	{ 0 }
+};
+
+struct cat_options {
+	struct isl_options	*isl;
+	unsigned		 format;
+	unsigned		 yaml_style;
+};
+
+ISL_ARGS_START(struct cat_options, cat_options_args)
+ISL_ARG_CHILD(struct cat_options, isl, "isl", &isl_options_args, "isl options")
+ISL_ARG_CHOICE(struct cat_options, format, 0, "format", \
+	cat_format,	ISL_FORMAT_ISL, "output format")
+ISL_ARG_CHOICE(struct cat_options, yaml_style, 0, "yaml-style", \
+	cat_yaml_style, ISL_YAML_STYLE_BLOCK, "output YAML style")
+ISL_ARGS_END
+
+ISL_ARG_DEF(cat_options, struct cat_options, cat_options_args)
+
+int main(int argc, char **argv)
+{
+	struct isl_ctx *ctx;
+	isl_stream *s;
+	struct isl_obj obj;
+	struct cat_options *options;
+	isl_printer *p;
+
+	options = cat_options_new_with_defaults();
+	assert(options);
+	argc = cat_options_parse(options, argc, argv, ISL_ARG_ALL);
+
+	ctx = isl_ctx_alloc_with_options(&cat_options_args, options);
+
+	s = isl_stream_new_file(ctx, stdin);
+	obj = isl_stream_read_obj(s);
+	isl_stream_free(s);
+
+	p = isl_printer_to_file(ctx, stdout);
+	p = isl_printer_set_output_format(p, options->format);
+	p = isl_printer_set_yaml_style(p, options->yaml_style);
+	p = obj.type->print(p, obj.v);
+	p = isl_printer_end_line(p);
+	isl_printer_free(p);
+
+	obj.type->free(obj.v);
+
+	isl_ctx_free(ctx);
+
+	return 0;
+}
diff --git a/final/lib/External/isl/closure.c b/final/lib/External/isl/closure.c
new file mode 100644
index 0000000..c76fb29
--- /dev/null
+++ b/final/lib/External/isl/closure.c
@@ -0,0 +1,39 @@
+#include <assert.h>
+#include <isl/map.h>
+#include <isl/options.h>
+
+int main(int argc, char **argv)
+{
+	struct isl_ctx *ctx;
+	struct isl_map *map;
+	struct isl_options *options;
+	isl_printer *p;
+	int exact;
+
+	options = isl_options_new_with_defaults();
+	assert(options);
+	argc = isl_options_parse(options, argc, argv, ISL_ARG_ALL);
+
+	ctx = isl_ctx_alloc_with_options(&isl_options_args, options);
+
+	p = isl_printer_to_file(ctx, stdout);
+
+	map = isl_map_read_from_file(ctx, stdin);
+	map = isl_map_transitive_closure(map, &exact);
+	if (!exact)
+		p = isl_printer_print_str(p, "# NOT exact\n");
+	p = isl_printer_print_map(p, map);
+	p = isl_printer_end_line(p);
+	map = isl_map_compute_divs(map);
+	map = isl_map_coalesce(map);
+	p = isl_printer_print_str(p, "# coalesced\n");
+	p = isl_printer_print_map(p, map);
+	p = isl_printer_end_line(p);
+	isl_map_free(map);
+
+	isl_printer_free(p);
+
+	isl_ctx_free(ctx);
+
+	return 0;
+}
diff --git a/final/lib/External/isl/codegen.c b/final/lib/External/isl/codegen.c
new file mode 100644
index 0000000..835b51d
--- /dev/null
+++ b/final/lib/External/isl/codegen.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2012,2014 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+/* This program prints an AST that scans the domain elements of
+ * the domain of a given schedule in the order specified by
+ * the schedule tree or by their image(s) in the schedule map.
+ *
+ * The input consists of either a schedule tree or
+ * a sequence of three sets/relations.
+ * - a schedule map
+ * - a context
+ * - a relation describing AST generation options
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <isl/ast.h>
+#include <isl/ast_build.h>
+#include <isl/options.h>
+#include <isl/set.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl/stream.h>
+#include <isl/schedule_node.h>
+
+struct options {
+	struct isl_options	*isl;
+	unsigned		 atomic;
+	unsigned		 separate;
+};
+
+ISL_ARGS_START(struct options, options_args)
+ISL_ARG_CHILD(struct options, isl, "isl", &isl_options_args, "isl options")
+ISL_ARG_BOOL(struct options, atomic, 0, "atomic", 0,
+	"globally set the atomic option")
+ISL_ARG_BOOL(struct options, separate, 0, "separate", 0,
+	"globally set the separate option")
+ISL_ARGS_END
+
+ISL_ARG_DEF(cg_options, struct options, options_args)
+ISL_ARG_CTX_DEF(cg_options, struct options, options_args)
+
+/* Return a universal, 1-dimensional set with the given name.
+ */
+static __isl_give isl_union_set *universe(isl_ctx *ctx, const char *name)
+{
+	isl_space *space;
+
+	space = isl_space_set_alloc(ctx, 0, 1);
+	space = isl_space_set_tuple_name(space, isl_dim_set, name);
+	return isl_union_set_from_set(isl_set_universe(space));
+}
+
+/* Set the "name" option for the entire schedule domain.
+ */
+static __isl_give isl_union_map *set_universe(__isl_take isl_union_map *opt,
+	__isl_keep isl_union_map *schedule, const char *name)
+{
+	isl_ctx *ctx;
+	isl_union_set *domain, *target;
+	isl_union_map *option;
+
+	ctx = isl_union_map_get_ctx(opt);
+
+	domain = isl_union_map_range(isl_union_map_copy(schedule));
+	domain = isl_union_set_universe(domain);
+	target = universe(ctx, name);
+	option = isl_union_map_from_domain_and_range(domain, target);
+	opt = isl_union_map_union(opt, option);
+
+	return opt;
+}
+
+/* Update the build options based on the user-specified options.
+ *
+ * If the --separate or --atomic options were specified, then
+ * we clear any separate or atomic options that may already exist in "opt".
+ */
+static __isl_give isl_ast_build *set_options(__isl_take isl_ast_build *build,
+	__isl_take isl_union_map *opt, struct options *options,
+	__isl_keep isl_union_map *schedule)
+{
+	if (options->separate || options->atomic) {
+		isl_ctx *ctx;
+		isl_union_set *target;
+
+		ctx = isl_union_map_get_ctx(schedule);
+
+		target = universe(ctx, "separate");
+		opt = isl_union_map_subtract_range(opt, target);
+		target = universe(ctx, "atomic");
+		opt = isl_union_map_subtract_range(opt, target);
+	}
+
+	if (options->separate)
+		opt = set_universe(opt, schedule, "separate");
+	if (options->atomic)
+		opt = set_universe(opt, schedule, "atomic");
+
+	build = isl_ast_build_set_options(build, opt);
+
+	return build;
+}
+
+/* Construct an AST in case the schedule is specified by a union map.
+ *
+ * We read the context and the options from "s" and construct the AST.
+ */
+static __isl_give isl_ast_node *construct_ast_from_union_map(
+	__isl_take isl_union_map *schedule, __isl_keep isl_stream *s)
+{
+	isl_set *context;
+	isl_union_map *options_map;
+	isl_ast_build *build;
+	isl_ast_node *tree;
+	struct options *options;
+
+	options = isl_ctx_peek_cg_options(isl_stream_get_ctx(s));
+
+	context = isl_stream_read_set(s);
+	options_map = isl_stream_read_union_map(s);
+
+	build = isl_ast_build_from_context(context);
+	build = set_options(build, options_map, options, schedule);
+	tree = isl_ast_build_node_from_schedule_map(build, schedule);
+	isl_ast_build_free(build);
+
+	return tree;
+}
+
+/* If "node" is a band node, then replace the AST build options
+ * by "options".
+ */
+static __isl_give isl_schedule_node *node_set_options(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	enum isl_ast_loop_type *type = user;
+	int i, n;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_band)
+		return node;
+
+	n = isl_schedule_node_band_n_member(node);
+	for (i = 0; i < n; ++i)
+		node = isl_schedule_node_band_member_set_ast_loop_type(node,
+								i, *type);
+	return node;
+}
+
+/* Replace the AST build options on all band nodes if requested
+ * by the user.
+ */
+static __isl_give isl_schedule *schedule_set_options(
+	__isl_take isl_schedule *schedule, struct options *options)
+{
+	enum isl_ast_loop_type type;
+
+	if (!options->separate && !options->atomic)
+		return schedule;
+
+	type = options->separate ? isl_ast_loop_separate : isl_ast_loop_atomic;
+	schedule = isl_schedule_map_schedule_node_bottom_up(schedule,
+						&node_set_options, &type);
+
+	return schedule;
+}
+
+/* Construct an AST in case the schedule is specified by a schedule tree.
+ */
+static __isl_give isl_ast_node *construct_ast_from_schedule(
+	__isl_take isl_schedule *schedule)
+{
+	isl_ast_build *build;
+	isl_ast_node *tree;
+	struct options *options;
+
+	options = isl_ctx_peek_cg_options(isl_schedule_get_ctx(schedule));
+
+	build = isl_ast_build_alloc(isl_schedule_get_ctx(schedule));
+	schedule = schedule_set_options(schedule, options);
+	tree = isl_ast_build_node_from_schedule(build, schedule);
+	isl_ast_build_free(build);
+
+	return tree;
+}
+
+/* Read an object from stdin.
+ * If it is a (union) map, then assume an input specified by
+ * schedule map, context and options and construct an AST from
+ * those elements
+ * If it is a schedule object, then construct the AST from the schedule.
+ */
+int main(int argc, char **argv)
+{
+	isl_ctx *ctx;
+	isl_stream *s;
+	isl_ast_node *tree = NULL;
+	struct options *options;
+	isl_printer *p;
+	struct isl_obj obj;
+	int r = EXIT_SUCCESS;
+
+	options = cg_options_new_with_defaults();
+	assert(options);
+	ctx = isl_ctx_alloc_with_options(&options_args, options);
+	isl_options_set_ast_build_detect_min_max(ctx, 1);
+	argc = cg_options_parse(options, argc, argv, ISL_ARG_ALL);
+
+	s = isl_stream_new_file(ctx, stdin);
+	obj = isl_stream_read_obj(s);
+	if (obj.v == NULL) {
+		r = EXIT_FAILURE;
+	} else if (obj.type == isl_obj_map) {
+		isl_union_map *umap;
+
+		umap = isl_union_map_from_map(obj.v);
+		tree = construct_ast_from_union_map(umap, s);
+	} else if (obj.type == isl_obj_union_map) {
+		tree = construct_ast_from_union_map(obj.v, s);
+	} else if (obj.type == isl_obj_schedule) {
+		tree = construct_ast_from_schedule(obj.v);
+	} else {
+		obj.type->free(obj.v);
+		isl_die(ctx, isl_error_invalid, "unknown input",
+			r = EXIT_FAILURE);
+	}
+	isl_stream_free(s);
+
+	p = isl_printer_to_file(ctx, stdout);
+	p = isl_printer_set_output_format(p, ISL_FORMAT_C);
+	p = isl_printer_print_ast_node(p, tree);
+	isl_printer_free(p);
+
+	isl_ast_node_free(tree);
+
+	isl_ctx_free(ctx);
+	return r;
+}
diff --git a/final/lib/External/isl/codegen_test.sh.in b/final/lib/External/isl/codegen_test.sh.in
new file mode 100644
index 0000000..5b519e7
--- /dev/null
+++ b/final/lib/External/isl/codegen_test.sh.in
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+EXEEXT=@EXEEXT@
+srcdir=@srcdir@
+
+failed=0
+
+for i in $srcdir/test_inputs/codegen/*.st \
+		$srcdir/test_inputs/codegen/cloog/*.st; do
+	echo $i;
+	base=`basename $i .st`
+	test=test-$base.c
+	dir=`dirname $i`
+	ref=$dir/$base.c
+	(./isl_codegen$EXEEXT < $i > $test &&
+	 diff -uw $ref $test && rm $test) || failed=1
+done
+for i in $srcdir/test_inputs/codegen/*.in \
+		$srcdir/test_inputs/codegen/omega/*.in \
+		$srcdir/test_inputs/codegen/pldi2012/*.in; do
+	echo $i;
+	base=`basename $i .in`
+	test=test-$base.c
+	dir=`dirname $i`
+	ref=$dir/$base.c
+	(./isl_codegen$EXEEXT < $i > $test &&
+	 diff -uw $ref $test && rm $test) || failed=1
+done
+
+test $failed -eq 0 || exit
diff --git a/final/lib/External/isl/compile b/final/lib/External/isl/compile
new file mode 100755
index 0000000..a85b723
--- /dev/null
+++ b/final/lib/External/isl/compile
@@ -0,0 +1,347 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2012-10-14.11; # UTC
+
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" ""	$nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+  file=$1
+  case $file in
+    / | /[!/]*) # absolute file, and not a UNC file
+      if test -z "$file_conv"; then
+	# lazily determine how to convert abs files
+	case `uname -s` in
+	  MINGW*)
+	    file_conv=mingw
+	    ;;
+	  CYGWIN*)
+	    file_conv=cygwin
+	    ;;
+	  *)
+	    file_conv=wine
+	    ;;
+	esac
+      fi
+      case $file_conv/,$2, in
+	*,$file_conv,*)
+	  ;;
+	mingw/*)
+	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+	  ;;
+	cygwin/*)
+	  file=`cygpath -m "$file" || echo "$file"`
+	  ;;
+	wine/*)
+	  file=`winepath -w "$file" || echo "$file"`
+	  ;;
+      esac
+      ;;
+  esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+  func_file_conv "$1"
+  if test -z "$lib_path"; then
+    lib_path=$file
+  else
+    lib_path="$lib_path;$file"
+  fi
+  linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+  lib=$1
+  found=no
+  save_IFS=$IFS
+  IFS=';'
+  for dir in $lib_path $LIB
+  do
+    IFS=$save_IFS
+    if $shared && test -f "$dir/$lib.dll.lib"; then
+      found=yes
+      lib=$dir/$lib.dll.lib
+      break
+    fi
+    if test -f "$dir/$lib.lib"; then
+      found=yes
+      lib=$dir/$lib.lib
+      break
+    fi
+    if test -f "$dir/lib$lib.a"; then
+      found=yes
+      lib=$dir/lib$lib.a
+      break
+    fi
+  done
+  IFS=$save_IFS
+
+  if test "$found" != yes; then
+    lib=$lib.lib
+  fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+  # Assume a capable shell
+  lib_path=
+  shared=:
+  linker_opts=
+  for arg
+  do
+    if test -n "$eat"; then
+      eat=
+    else
+      case $1 in
+	-o)
+	  # configure might choose to run compile as 'compile cc -o foo foo.c'.
+	  eat=1
+	  case $2 in
+	    *.o | *.[oO][bB][jJ])
+	      func_file_conv "$2"
+	      set x "$@" -Fo"$file"
+	      shift
+	      ;;
+	    *)
+	      func_file_conv "$2"
+	      set x "$@" -Fe"$file"
+	      shift
+	      ;;
+	  esac
+	  ;;
+	-I)
+	  eat=1
+	  func_file_conv "$2" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-I*)
+	  func_file_conv "${1#-I}" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-l)
+	  eat=1
+	  func_cl_dashl "$2"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-l*)
+	  func_cl_dashl "${1#-l}"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-L)
+	  eat=1
+	  func_cl_dashL "$2"
+	  ;;
+	-L*)
+	  func_cl_dashL "${1#-L}"
+	  ;;
+	-static)
+	  shared=false
+	  ;;
+	-Wl,*)
+	  arg=${1#-Wl,}
+	  save_ifs="$IFS"; IFS=','
+	  for flag in $arg; do
+	    IFS="$save_ifs"
+	    linker_opts="$linker_opts $flag"
+	  done
+	  IFS="$save_ifs"
+	  ;;
+	-Xlinker)
+	  eat=1
+	  linker_opts="$linker_opts $2"
+	  ;;
+	-*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+	*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+	  func_file_conv "$1"
+	  set x "$@" -Tp"$file"
+	  shift
+	  ;;
+	*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+	  func_file_conv "$1" mingw
+	  set x "$@" "$file"
+	  shift
+	  ;;
+	*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+      esac
+    fi
+    shift
+  done
+  if test -n "$linker_opts"; then
+    linker_opts="-link$linker_opts"
+  fi
+  exec "$@" $linker_opts
+  exit 1
+}
+
+eat=
+
+case $1 in
+  '')
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit $?
+    ;;
+  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+    func_cl_wrapper "$@"      # Doesn't return...
+    ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+	# configure might choose to run compile as 'compile cc -o foo foo.c'.
+	# So we strip '-o arg' only if arg is an object.
+	eat=1
+	case $2 in
+	  *.o | *.obj)
+	    ofile=$2
+	    ;;
+	  *)
+	    set x "$@" -o "$2"
+	    shift
+	    ;;
+	esac
+	;;
+      *.c)
+	cfile=$1
+	set x "$@" "$1"
+	shift
+	;;
+      *)
+	set x "$@" "$1"
+	shift
+	;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no '-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # '.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/final/lib/External/isl/config.guess b/final/lib/External/isl/config.guess
new file mode 100755
index 0000000..0967f2a
--- /dev/null
+++ b/final/lib/External/isl/config.guess
@@ -0,0 +1,1454 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
+
+timestamp='2016-04-02'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2016 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+	# If the system lacks a compiler, then just pick glibc.
+	# We could probably try harder.
+	LIBC=gnu
+
+	eval $set_cc_for_build
+	cat <<-EOF > $dummy.c
+	#include <features.h>
+	#if defined(__UCLIBC__)
+	LIBC=uclibc
+	#elif defined(__dietlibc__)
+	LIBC=dietlibc
+	#else
+	LIBC=gnu
+	#endif
+	EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+	;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+	    /sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || \
+	    echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    earmv*)
+		arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+		endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+		machine=${arch}${endian}-unknown
+		;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+		os=netbsd
+		;;
+	esac
+	# Determine ABI tags.
+	case "${UNAME_MACHINE_ARCH}" in
+	    earm*)
+		expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+		abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}${abi}"
+	exit ;;
+    *:Bitrig:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:LibertyBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:Sortix:*:*)
+	echo ${UNAME_MACHINE}-unknown-sortix
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE=alpha ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE=alpha ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE=alpha ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE=alphaev5 ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE=alphaev56 ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE=alphapca56 ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE=alphapca57 ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE=alphaev6 ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE=alphaev67 ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE=alphaev68 ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE=alphaev68 ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE=alphaev68 ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE=alphaev69 ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE=alphaev7 ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE=alphaev79 ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+	exitcode=$?
+	trap '' 0
+	exit $exitcode ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+	echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm*:riscos:*:*|arm*:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH=i386
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH=x86_64
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+	echo m68k-milan-mint${UNAME_RELEASE}
+	exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+	echo m68k-hades-mint${UNAME_RELEASE}
+	exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+	echo m68k-unknown-mint${UNAME_RELEASE}
+	exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+	# DG/UX returns AViiON for all architectures
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[4567])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/lslpp ] ; then
+		IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+			   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+		    case "${sc_cpu_version}" in
+		      523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+		      528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
+		      532)                      # CPU_PA_RISC2_0
+			case "${sc_kernel_bits}" in
+			  32) HP_ARCH=hppa2.0n ;;
+			  64) HP_ARCH=hppa2.0w ;;
+			  '') HP_ARCH=hppa2.0 ;;   # HP-UX 10.20
+			esac ;;
+		    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^		//' << EOF >$dummy.c
+
+		#define _HPUX_SOURCE
+		#include <stdlib.h>
+		#include <unistd.h>
+
+		int main ()
+		{
+		#if defined(_SC_KERNEL_BITS)
+		    long bits = sysconf(_SC_KERNEL_BITS);
+		#endif
+		    long cpu  = sysconf (_SC_CPU_VERSION);
+
+		    switch (cpu)
+			{
+			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+			case CPU_PA_RISC2_0:
+		#if defined(_SC_KERNEL_BITS)
+			    switch (bits)
+				{
+				case 64: puts ("hppa2.0w"); break;
+				case 32: puts ("hppa2.0n"); break;
+				default: puts ("hppa2.0"); break;
+				} break;
+		#else  /* !defined(_SC_KERNEL_BITS) */
+			    puts ("hppa2.0"); break;
+		#endif
+			default: puts ("hppa1.0"); break;
+			}
+		    exit (0);
+		}
+EOF
+		    (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = hppa2.0w ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH=hppa2.0w
+	    else
+		HP_ARCH=hppa64
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+	exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+	exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+	exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+	exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    5000:UNIX_System_V:4.*:*)
+	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	case ${UNAME_PROCESSOR} in
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW64*:*)
+	echo ${UNAME_MACHINE}-pc-mingw64
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    *:MSYS*:*)
+	echo ${UNAME_MACHINE}-pc-msys
+	exit ;;
+    i*:windows32*:*)
+	# uname -m includes "-pc" on this system.
+	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:*)
+	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    aarch64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    aarch64_be:Linux:*:*)
+	UNAME_MACHINE=aarch64_be
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+	esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arc:Linux:*:* | arceb:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	else
+	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+		| grep -q __ARM_PCS_VFP
+	    then
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+	    else
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+	    fi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    cris:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    crisv32:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    e2k:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    frv:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    hexagon:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:Linux:*:*)
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    k1om:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+	;;
+    openrisc*:Linux:*:*)
+	echo or1k-unknown-linux-${LIBC}
+	exit ;;
+    or32:Linux:*:* | or1k*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-${LIBC}
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-${LIBC}
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+	  *)    echo hppa-unknown-linux-${LIBC} ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-${LIBC}
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-${LIBC}
+	exit ;;
+    ppc64le:Linux:*:*)
+	echo powerpc64le-unknown-linux-${LIBC}
+	exit ;;
+    ppcle:Linux:*:*)
+	echo powerpcle-unknown-linux-${LIBC}
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+	exit ;;
+    sh64*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    tile*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+	exit ;;
+    x86_64:Linux:*:*)
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+	exit ;;
+    xtensa*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+	# Unixware is an offshoot of SVR4, but it has its own version
+	# number series starting with 2...
+	# I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+	# Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+	# uname -m prints for DJGPP always 'pc', but it prints nothing about
+	# the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configure will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+	exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+			# says <Richard.M.Bartel@ccMail.Census.GOV>
+	echo i586-unisys-sysv4
+	exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+		echo mips-nec-sysv${UNAME_RELEASE}
+	else
+		echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+	exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    x86_64:Haiku:*:*)
+	echo x86_64-unknown-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-ACE:SUPER-UX:*:*)
+	echo sxace-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	eval $set_cc_for_build
+	if test "$UNAME_PROCESSOR" = unknown ; then
+	    UNAME_PROCESSOR=powerpc
+	fi
+	if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+	    if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		    (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		    grep IS_64BIT_ARCH >/dev/null
+		then
+		    case $UNAME_PROCESSOR in
+			i386) UNAME_PROCESSOR=x86_64 ;;
+			powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		    esac
+		fi
+	    fi
+	elif test "$UNAME_PROCESSOR" = i386 ; then
+	    # Avoid executing cc on OS X 10.9, as it ships with a stub
+	    # that puts up a graphical alert prompting to install
+	    # developer tools.  Any system running Mac OS X 10.7 or
+	    # later (Darwin 11 and later) is required to have a 64-bit
+	    # processor. This is not true of the ARM version of Darwin
+	    # that Apple uses in portable devices.
+	    UNAME_PROCESSOR=x86_64
+	fi
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = x86; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSE-*:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = 386; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+	echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+    x86_64:VMkernel:*:*)
+	echo ${UNAME_MACHINE}-unknown-esx
+	exit ;;
+    amd64:Isilon\ OneFS:*:*)
+	echo x86_64-unknown-onefs
+	exit ;;
+esac
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/final/lib/External/isl/config.sub b/final/lib/External/isl/config.sub
new file mode 100755
index 0000000..8d39c4b
--- /dev/null
+++ b/final/lib/External/isl/config.sub
@@ -0,0 +1,1815 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
+
+timestamp='2016-03-30'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2016 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray | -microblaze*)
+		os=
+		basic_machine=$1
+		;;
+	-bluegene*)
+		os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+	-chorusrdb)
+		os=-chorusrdb
+		basic_machine=$1
+		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*178)
+		os=-lynxos178
+		;;
+	-lynx*5)
+		os=-lynxos5
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| aarch64 | aarch64_be \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arceb \
+	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+	| avr | avr32 \
+	| ba \
+	| be32 | be64 \
+	| bfin \
+	| c4x | c8051 | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| e2k | epiphany \
+	| fido | fr30 | frv | ft32 \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| hexagon \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| k1om \
+	| le32 | le64 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa32r6 | mipsisa32r6el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64r6 | mipsisa64r6el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipsr5900 | mipsr5900el \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nds32 | nds32le | nds32be \
+	| nios | nios2 | nios2eb | nios2el \
+	| ns16k | ns32k \
+	| open8 | or1k | or1knd | or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle \
+	| pyramid \
+	| riscv32 | riscv64 \
+	| rl78 | rx \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu \
+	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+	| ubicom32 \
+	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+	| visium \
+	| we32k \
+	| x86 | xc16x | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	c54x)
+		basic_machine=tic54x-unknown
+		;;
+	c55x)
+		basic_machine=tic55x-unknown
+		;;
+	c6x)
+		basic_machine=tic6x-unknown
+		;;
+	leon|leon[3-9])
+		basic_machine=sparc-$basic_machine
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	strongarm | thumb | xscale)
+		basic_machine=arm-unknown
+		;;
+	xgate)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	xscaleeb)
+		basic_machine=armeb-unknown
+		;;
+
+	xscaleel)
+		basic_machine=armel-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| aarch64-* | aarch64_be-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| ba-* \
+	| be32-* | be64-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* \
+	| c8051-* | clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| e2k-* | elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| hexagon-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| k1om-* \
+	| le32-* | le64-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+	| microblaze-* | microblazeel-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa32r6-* | mipsisa32r6el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64r6-* | mipsisa64r6el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipsr5900-* | mipsr5900el-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nds32-* | nds32le-* | nds32be-* \
+	| nios-* | nios2-* | nios2eb-* | nios2el-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| open8-* \
+	| or1k*-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+	| pyramid-* \
+	| riscv32-* | riscv64-* \
+	| rl78-* | romp-* | rs6000-* | rx-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
+	| tahoe-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tile*-* \
+	| tron-* \
+	| ubicom32-* \
+	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+	| vax-* \
+	| visium-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	asmjs)
+		basic_machine=asmjs-unknown
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c54x-*)
+		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c55x-*)
+		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c6x-*)
+		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16 | cr16-*)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	leon-*|leon[3-9]-*)
+		basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	microblaze*)
+		basic_machine=microblaze-xilinx
+		;;
+	mingw64)
+		basic_machine=x86_64-pc
+		os=-mingw64
+		;;
+	mingw32)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	moxiebox)
+		basic_machine=moxie-unknown
+		os=-moxiebox
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	msys)
+		basic_machine=i686-pc
+		os=-msys
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	nacl)
+		basic_machine=le32-unknown
+		os=-nacl
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	neo-tandem)
+		basic_machine=neo-tandem
+		;;
+	nse-tandem)
+		basic_machine=nse-tandem
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc | ppcbe)	basic_machine=powerpc-unknown
+		;;
+	ppc-* | ppcbe-*)
+		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos | rdos64)
+		basic_machine=x86_64-pc
+		os=-rdos
+		;;
+	rdos32)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	strongarm-* | thumb-*)
+		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tile*)
+		basic_machine=$basic_machine-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	xscale-* | xscalee[bl]-*)
+		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+	# First match some system type aliases
+	# that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-auroraux)
+		os=-auroraux
+		;;
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+	      | -sym* | -kopensolaris* | -plan9* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* | -cloudabi* | -sortix* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
+	      | -onefs* | -tirtos*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+	-os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+	-tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-nacl*)
+		;;
+	-ios)
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	score-*)
+		os=-elf
+		;;
+	spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+	c4x-* | tic4x-*)
+		os=-coff
+		;;
+	c8051-*)
+		os=-elf
+		;;
+	hexagon-*)
+		os=-elf
+		;;
+	tic54x-*)
+		os=-coff
+		;;
+	tic55x-*)
+		os=-coff
+		;;
+	tic6x-*)
+		os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+	mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/final/lib/External/isl/configure b/final/lib/External/isl/configure
new file mode 100755
index 0000000..d208abc
--- /dev/null
+++ b/final/lib/External/isl/configure
@@ -0,0 +1,23337 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for isl 0.18.
+#
+# Report bugs to <isl-development@googlegroups.com>.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1
+
+  test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org and
+$0: isl-development@googlegroups.com about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='isl'
+PACKAGE_TARNAME='isl'
+PACKAGE_VERSION='0.18'
+PACKAGE_STRING='isl 0.18'
+PACKAGE_BUGREPORT='isl-development@googlegroups.com'
+PACKAGE_URL=''
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+GIT_HEAD_VERSION
+GIT_HEAD
+GIT_HEAD_ID
+pkgconfig_libfile
+pkgconfig_libdir
+WARNING_FLAGS
+HAVE_CLANG_FALSE
+HAVE_CLANG_TRUE
+LIB_CLANG_EDIT
+llvm_config_found
+CLANG_LIBS
+CLANG_LDFLAGS
+CLANG_CXXFLAGS
+SMALL_INT_OPT_FALSE
+SMALL_INT_OPT_TRUE
+HAVE_CXX11_FALSE
+HAVE_CXX11_TRUE
+GMP_FOR_MP_FALSE
+GMP_FOR_MP_TRUE
+IMATH_FOR_MP_FALSE
+IMATH_FOR_MP_TRUE
+NEED_GET_MEMORY_FUNCTIONS_FALSE
+NEED_GET_MEMORY_FUNCTIONS_TRUE
+MP_LIBS
+MP_LDFLAGS
+MP_CPPFLAGS
+GENERATE_DOC_FALSE
+GENERATE_DOC_TRUE
+POD2HTML
+PDFLATEX
+PERL
+CXXCPP
+CPP
+LT_SYS_LIBRARY_PATH
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+MANIFEST_TOOL
+RANLIB
+ac_ct_AR
+AR
+DLLTOOL
+OBJDUMP
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+EGREP
+SED
+LIBTOOL
+GREP
+HAVE_CXX11
+CXX11FLAGS
+PRTDIAG
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+am__fastdepCXX_FALSE
+am__fastdepCXX_TRUE
+CXXDEPMODE
+ac_ct_CXX
+CXXFLAGS
+CXX
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+versioninfo
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_dependency_tracking
+enable_portable_binary
+with_gcc_arch
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_aix_soname
+with_gnu_ld
+with_sysroot
+enable_libtool_lock
+with_int
+with_gmp
+with_gmp_prefix
+with_gmp_exec_prefix
+with_gmp_builddir
+with_clang
+with_clang_prefix
+with_clang_exec_prefix
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CXX
+CXXFLAGS
+CCC
+LT_SYS_LIBRARY_PATH
+CPP
+CXXCPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir runstatedir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures isl 0.18 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/isl]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of isl 0.18:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-silent-rules   less verbose build output (undo: "make V=1")
+  --disable-silent-rules  verbose build output (undo: "make V=0")
+  --enable-dependency-tracking
+                          do not reject slow dependency extractors
+  --disable-dependency-tracking
+                          speeds up one-time build
+  --enable-portable-binary
+                          disable compiler optimizations that would produce
+                          unportable binaries
+  --enable-shared[=PKGS]  build shared libraries [default=yes]
+  --enable-static[=PKGS]  build static libraries [default=yes]
+  --enable-fast-install[=PKGS]
+                          optimize for fast installation [default=yes]
+  --disable-libtool-lock  avoid locking (might break parallel builds)
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-gcc-arch=<arch>  use architecture <arch> for gcc -march/-mtune,
+                          instead of guessing
+  --with-pic[=PKGS]       try to use only PIC/non-PIC objects [default=use
+                          both]
+  --with-aix-soname=aix|svr4|both
+                          shared library versioning (aka "SONAME") variant to
+                          provide on AIX, [default=aix].
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-sysroot[=DIR]    Search for dependent libraries within DIR (or the
+                          compiler's sysroot if not specified).
+  --with-int=gmp|imath|imath-32
+                          Which package to use to represent multi-precision
+                          integers [default=gmp]
+  --with-gmp=system|build Which gmp to use [default=system]
+  --with-gmp-prefix=DIR   Prefix of gmp installation
+  --with-gmp-exec-prefix=DIR
+                          Exec prefix of gmp installation
+  --with-gmp-builddir=DIR Location of gmp builddir
+  --with-clang=system|no  Which clang to use [default=no]
+  --with-clang-prefix=DIR Prefix of clang installation
+  --with-clang-exec-prefix=DIR
+                          Exec prefix of clang installation
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
+  LT_SYS_LIBRARY_PATH
+              User-defined run-time library search path.
+  CPP         C preprocessor
+  CXXCPP      C++ preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <isl-development@googlegroups.com>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+isl configure 0.18
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_cxx_try_cpp LINENO
+# ------------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_cpp
+
+# ac_fn_cxx_try_link LINENO
+# -------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_link
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=no"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+	 return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+	    return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+
+# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES
+# --------------------------------------------
+# Tries to find the compile-time value of EXPR in a program that includes
+# INCLUDES, setting VAR accordingly. Returns whether the value could be
+# computed
+ac_fn_c_compute_int ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if test "$cross_compiling" = yes; then
+    # Depending upon the size, compute the lo and hi bounds.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= 0)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid; break
+else
+  as_fn_arith $ac_mid + 1 && ac_lo=$as_val
+			if test $ac_lo -le $ac_mid; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) < 0)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=$ac_mid; break
+else
+  as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val
+			if test $ac_mid -le $ac_hi; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  ac_lo= ac_hi=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid
+else
+  as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in #((
+?*) eval "$3=\$ac_lo"; ac_retval=0 ;;
+'') ac_retval=1 ;;
+esac
+  else
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+static long int longval () { return $2; }
+static unsigned long int ulongval () { return $2; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (($2) < 0)
+    {
+      long int i = longval ();
+      if (i != ($2))
+	return 1;
+      fprintf (f, "%ld", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ($2))
+	return 1;
+      fprintf (f, "%lu", i);
+    }
+  /* Do not output a trailing newline, as this causes \r\n confusion
+     on some platforms.  */
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  echo >>conftest.val; read $3 <conftest.val; ac_retval=0
+else
+  ac_retval=1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.val
+
+  fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_compute_int
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ----------------------------------------------- ##
+## Report this to isl-development@googlegroups.com ##
+## ----------------------------------------------- ##"
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
+# ---------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_c_check_decl ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  as_decl_name=`echo $2|sed 's/ *(.*//'`
+  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+  (void) $as_decl_use;
+#else
+  (void) $as_decl_name;
+#endif
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_decl
+
+# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES
+# ---------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_cxx_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ----------------------------------------------- ##
+## Report this to isl-development@googlegroups.com ##
+## ----------------------------------------------- ##"
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_header_mongrel
+
+# ac_fn_cxx_check_header_compile LINENO HEADER VAR INCLUDES
+# ---------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_cxx_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_header_compile
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by isl $as_me 0.18, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_aux_dir=
+for ac_dir in . "$srcdir"/.; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in . \"$srcdir\"/." "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+
+am__api_version='1.15'
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[\\\"\#\$\&\'\`$am_lf]*)
+    as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+  *[\\\"\#\$\&\'\`$am_lf\ \	]*)
+    as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$*" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$*" != "X $srcdir/configure conftest.file" \
+	&& test "$*" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	as_fn_error $? "ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment" "$LINENO" 5
+     fi
+     if test "$2" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$2" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+  program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if ${ac_cv_path_mkdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in mkdir gmkdir; do
+	 for ac_exec_ext in '' $ac_executable_extensions; do
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+	     'mkdir (GNU coreutils) '* | \
+	     'mkdir (coreutils) '* | \
+	     'mkdir (fileutils) '4.1*)
+	       ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+	       break 3;;
+	   esac
+	 done
+       done
+  done
+IFS=$as_save_IFS
+
+fi
+
+  test -d ./--version && rmdir ./--version
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    MKDIR_P="$ac_install_sh -d"
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  am__isrc=' -I$(srcdir)'
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='isl'
+ VERSION='0.18'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
+# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar  pax cpio none'
+
+am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+
+
+
+
+
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+  fi
+fi
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=0;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+
+versioninfo=18:0:3
+
+if test "x$prefix" != "xNONE"; then
+	prefix_wd=`cd $prefix && pwd`
+	srcdir_wd=`cd $srcdir && pwd`
+	wd=`pwd`
+	if test "x$prefix_wd" = "x$srcdir_wd"; then
+		as_fn_error $? "Installation in source directory not supported" "$LINENO" 5
+	fi
+	if test "x$prefix_wd" = "x$wd"; then
+		as_fn_error $? "Installation in build directory not supported" "$LINENO" 5
+	fi
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+   ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+  enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CXX" && break
+done
+
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
+fi
+
+  fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if ${ac_cv_cxx_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if ${ac_cv_prog_cxx_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+else
+  CXXFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+	 CXXFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CXX"  am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CXX_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CXX_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CXX_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CXX_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; }
+CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
+  am__fastdepCXX_TRUE=
+  am__fastdepCXX_FALSE='#'
+else
+  am__fastdepCXX_TRUE='#'
+  am__fastdepCXX_FALSE=
+fi
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler vendor" >&5
+$as_echo_n "checking for C compiler vendor... " >&6; }
+if ${ax_cv_c_compiler_vendor+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ax_cv_c_compiler_vendor=unknown
+  # note: don't check for gcc first since some other compilers define __GNUC__
+  for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ pathscale:__PATHCC__,__PATHSCALE__ clang:__clang__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
+    vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+#if !($vencpp)
+      thisisanerror;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ax_cv_c_compiler_vendor=`echo $ventest | cut -d: -f1`; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_c_compiler_vendor" >&5
+$as_echo "$ax_cv_c_compiler_vendor" >&6; }
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+
+
+
+
+
+# Check whether --enable-portable-binary was given.
+if test "${enable_portable_binary+set}" = set; then :
+  enableval=$enable_portable_binary; acx_maxopt_portable=$withval
+else
+  acx_maxopt_portable=no
+fi
+
+
+# Try to determine "good" native compiler flags if none specified via CFLAGS
+if test "$ac_test_CFLAGS" != "set"; then
+  CFLAGS=""
+  case $ax_cv_c_compiler_vendor in
+    dec) CFLAGS="-newc -w0 -O5 -ansi_alias -ansi_args -fp_reorder -tune host"
+	 if test "x$acx_maxopt_portable" = xno; then
+           CFLAGS="$CFLAGS -arch host"
+         fi;;
+
+    sun) CFLAGS="-native -fast -xO5 -dalign"
+	 if test "x$acx_maxopt_portable" = xyes; then
+	   CFLAGS="$CFLAGS -xarch=generic"
+         fi;;
+
+    hp)  CFLAGS="+Oall +Optrs_ansi +DSnative"
+	 if test "x$acx_maxopt_portable" = xyes; then
+	   CFLAGS="$CFLAGS +DAportable"
+	 fi;;
+
+    ibm) if test "x$acx_maxopt_portable" = xno; then
+           xlc_opt="-qarch=auto -qtune=auto"
+	 else
+           xlc_opt="-qtune=auto"
+	 fi
+          { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $xlc_opt" >&5
+$as_echo_n "checking whether C compiler accepts $xlc_opt... " >&6; }
+ax_save_FLAGS=$CFLAGS
+   CFLAGS="$xlc_opt"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval `$as_echo "ax_cv_c_flags_$xlc_opt" | $as_tr_sh`=yes
+else
+  eval `$as_echo "ax_cv_c_flags_$xlc_opt" | $as_tr_sh`=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS=$ax_save_FLAGS
+eval ax_check_compiler_flags=$`$as_echo "ax_cv_c_flags_$xlc_opt" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5
+$as_echo "$ax_check_compiler_flags" >&6; }
+if test "x$ax_check_compiler_flags" = xyes; then
+	CFLAGS="-O3 -qansialias -w $xlc_opt"
+else
+	CFLAGS="-O3 -qansialias -w"
+                echo "******************************************************"
+                echo "*  You seem to have the IBM  C compiler.  It is      *"
+                echo "*  recommended for best performance that you use:    *"
+                echo "*                                                    *"
+                echo "*    CFLAGS=-O3 -qarch=xxx -qtune=xxx -qansialias -w *"
+                echo "*                      ^^^        ^^^                *"
+                echo "*  where xxx is pwr2, pwr3, 604, or whatever kind of *"
+                echo "*  CPU you have.  (Set the CFLAGS environment var.   *"
+                echo "*  and re-run configure.)  For more info, man cc.    *"
+                echo "******************************************************"
+fi
+
+         ;;
+
+    intel) CFLAGS="-O3 -ansi_alias"
+	if test "x$acx_maxopt_portable" = xno; then
+	  icc_archflag=unknown
+	  icc_flags=""
+	  case $host_cpu in
+	    i686*|x86_64*)
+              # icc accepts gcc assembly syntax, so these should work:
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x86 cpuid 0 output" >&5
+$as_echo_n "checking for x86 cpuid 0 output... " >&6; }
+if ${ax_cv_gcc_x86_cpuid_0+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ax_cv_gcc_x86_cpuid_0=unknown
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+
+     int op = 0, eax, ebx, ecx, edx;
+     FILE *f;
+      __asm__("cpuid"
+        : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+        : "a" (op));
+     f = fopen("conftest_cpuid", "w"); if (!f) return 1;
+     fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx);
+     fclose(f);
+     return 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ax_cv_gcc_x86_cpuid_0=`cat conftest_cpuid`; rm -f conftest_cpuid
+else
+  ax_cv_gcc_x86_cpuid_0=unknown; rm -f conftest_cpuid
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_gcc_x86_cpuid_0" >&5
+$as_echo "$ax_cv_gcc_x86_cpuid_0" >&6; }
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x86 cpuid 1 output" >&5
+$as_echo_n "checking for x86 cpuid 1 output... " >&6; }
+if ${ax_cv_gcc_x86_cpuid_1+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ax_cv_gcc_x86_cpuid_1=unknown
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+
+     int op = 1, eax, ebx, ecx, edx;
+     FILE *f;
+      __asm__("cpuid"
+        : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+        : "a" (op));
+     f = fopen("conftest_cpuid", "w"); if (!f) return 1;
+     fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx);
+     fclose(f);
+     return 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ax_cv_gcc_x86_cpuid_1=`cat conftest_cpuid`; rm -f conftest_cpuid
+else
+  ax_cv_gcc_x86_cpuid_1=unknown; rm -f conftest_cpuid
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_gcc_x86_cpuid_1" >&5
+$as_echo "$ax_cv_gcc_x86_cpuid_1" >&6; }
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+	      case $ax_cv_gcc_x86_cpuid_0 in # see AX_GCC_ARCHFLAG
+                *:756e6547:*:*) # Intel
+                  case $ax_cv_gcc_x86_cpuid_1 in
+                    *6a?:*[234]:*:*|*6[789b]?:*:*:*) icc_flags="-xK";;
+                    *f3[347]:*:*:*|*f41347:*:*:*) icc_flags="-xP -xN -xW -xK";;
+                    *f??:*:*:*) icc_flags="-xN -xW -xK";;
+                  esac ;;
+              esac ;;
+          esac
+          if test "x$icc_flags" != x; then
+            for flag in $icc_flags; do
+               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $flag" >&5
+$as_echo_n "checking whether C compiler accepts $flag... " >&6; }
+ax_save_FLAGS=$CFLAGS
+   CFLAGS="$flag"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval `$as_echo "ax_cv_c_flags_$flag" | $as_tr_sh`=yes
+else
+  eval `$as_echo "ax_cv_c_flags_$flag" | $as_tr_sh`=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS=$ax_save_FLAGS
+eval ax_check_compiler_flags=$`$as_echo "ax_cv_c_flags_$flag" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5
+$as_echo "$ax_check_compiler_flags" >&6; }
+if test "x$ax_check_compiler_flags" = xyes; then
+	icc_archflag=$flag; break
+else
+	:
+fi
+
+            done
+          fi
+          { $as_echo "$as_me:${as_lineno-$LINENO}: checking for icc architecture flag" >&5
+$as_echo_n "checking for icc architecture flag... " >&6; }
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $icc_archflag" >&5
+$as_echo "$icc_archflag" >&6; }
+          if test "x$icc_archflag" != xunknown; then
+            CFLAGS="$CFLAGS $icc_archflag"
+          fi
+        fi
+	;;
+
+    gnu)
+     # default optimization flags for gcc on all systems
+     CFLAGS="-O3 -fomit-frame-pointer"
+
+     # -malign-double for x86 systems
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -malign-double" >&5
+$as_echo_n "checking whether C compiler accepts -malign-double... " >&6; }
+if ${ax_cv_c_flags__malign_double+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+      ax_save_FLAGS=$CFLAGS
+      CFLAGS="-malign-double"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ax_cv_c_flags__malign_double=yes
+else
+  ax_cv_c_flags__malign_double=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+      CFLAGS=$ax_save_FLAGS
+fi
+
+eval ax_check_compiler_flags=$ax_cv_c_flags__malign_double
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5
+$as_echo "$ax_check_compiler_flags" >&6; }
+if test "x$ax_check_compiler_flags" = xyes; then
+	CFLAGS="$CFLAGS -malign-double"
+else
+	:
+fi
+
+
+     #  -fstrict-aliasing for gcc-2.95+
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fstrict-aliasing" >&5
+$as_echo_n "checking whether C compiler accepts -fstrict-aliasing... " >&6; }
+if ${ax_cv_c_flags__fstrict_aliasing+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+      ax_save_FLAGS=$CFLAGS
+      CFLAGS="-fstrict-aliasing"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ax_cv_c_flags__fstrict_aliasing=yes
+else
+  ax_cv_c_flags__fstrict_aliasing=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+      CFLAGS=$ax_save_FLAGS
+fi
+
+eval ax_check_compiler_flags=$ax_cv_c_flags__fstrict_aliasing
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5
+$as_echo "$ax_check_compiler_flags" >&6; }
+if test "x$ax_check_compiler_flags" = xyes; then
+	CFLAGS="$CFLAGS -fstrict-aliasing"
+else
+	:
+fi
+
+
+     # note that we enable "unsafe" fp optimization with other compilers, too
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -ffast-math" >&5
+$as_echo_n "checking whether C compiler accepts -ffast-math... " >&6; }
+if ${ax_cv_c_flags__ffast_math+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+      ax_save_FLAGS=$CFLAGS
+      CFLAGS="-ffast-math"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ax_cv_c_flags__ffast_math=yes
+else
+  ax_cv_c_flags__ffast_math=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+      CFLAGS=$ax_save_FLAGS
+fi
+
+eval ax_check_compiler_flags=$ax_cv_c_flags__ffast_math
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5
+$as_echo "$ax_check_compiler_flags" >&6; }
+if test "x$ax_check_compiler_flags" = xyes; then
+	CFLAGS="$CFLAGS -ffast-math"
+else
+	:
+fi
+
+
+
+
+
+
+# Check whether --with-gcc-arch was given.
+if test "${with_gcc_arch+set}" = set; then :
+  withval=$with_gcc_arch; ax_gcc_arch=$withval
+else
+  ax_gcc_arch=yes
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc architecture flag" >&5
+$as_echo_n "checking for gcc architecture flag... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5
+$as_echo "" >&6; }
+if ${ax_cv_gcc_archflag+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+ax_cv_gcc_archflag="unknown"
+
+if test "$GCC" = yes; then
+
+if test "x$ax_gcc_arch" = xyes; then
+ax_gcc_arch=""
+if test "$cross_compiling" = no; then
+case $host_cpu in
+  i[3456]86*|x86_64*) # use cpuid codes, in part from x86info-1.7 by D. Jones
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x86 cpuid 0 output" >&5
+$as_echo_n "checking for x86 cpuid 0 output... " >&6; }
+if ${ax_cv_gcc_x86_cpuid_0+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ax_cv_gcc_x86_cpuid_0=unknown
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+
+     int op = 0, eax, ebx, ecx, edx;
+     FILE *f;
+      __asm__("cpuid"
+        : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+        : "a" (op));
+     f = fopen("conftest_cpuid", "w"); if (!f) return 1;
+     fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx);
+     fclose(f);
+     return 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ax_cv_gcc_x86_cpuid_0=`cat conftest_cpuid`; rm -f conftest_cpuid
+else
+  ax_cv_gcc_x86_cpuid_0=unknown; rm -f conftest_cpuid
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_gcc_x86_cpuid_0" >&5
+$as_echo "$ax_cv_gcc_x86_cpuid_0" >&6; }
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x86 cpuid 1 output" >&5
+$as_echo_n "checking for x86 cpuid 1 output... " >&6; }
+if ${ax_cv_gcc_x86_cpuid_1+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ax_cv_gcc_x86_cpuid_1=unknown
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+
+     int op = 1, eax, ebx, ecx, edx;
+     FILE *f;
+      __asm__("cpuid"
+        : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+        : "a" (op));
+     f = fopen("conftest_cpuid", "w"); if (!f) return 1;
+     fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx);
+     fclose(f);
+     return 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ax_cv_gcc_x86_cpuid_1=`cat conftest_cpuid`; rm -f conftest_cpuid
+else
+  ax_cv_gcc_x86_cpuid_1=unknown; rm -f conftest_cpuid
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_gcc_x86_cpuid_1" >&5
+$as_echo "$ax_cv_gcc_x86_cpuid_1" >&6; }
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+     case $ax_cv_gcc_x86_cpuid_0 in
+       *:756e6547:*:*) # Intel
+          case $ax_cv_gcc_x86_cpuid_1 in
+	    *5[48]?:*:*:*) ax_gcc_arch="pentium-mmx pentium" ;;
+	    *5??:*:*:*) ax_gcc_arch=pentium ;;
+	    *6[3456]?:*:*:*) ax_gcc_arch="pentium2 pentiumpro" ;;
+	    *6a?:*[01]:*:*) ax_gcc_arch="pentium2 pentiumpro" ;;
+	    *6a?:*[234]:*:*) ax_gcc_arch="pentium3 pentiumpro" ;;
+	    *6[9d]?:*:*:*) ax_gcc_arch="pentium-m pentium3 pentiumpro" ;;
+	    *6[78b]?:*:*:*) ax_gcc_arch="pentium3 pentiumpro" ;;
+	    *6??:*:*:*) ax_gcc_arch=pentiumpro ;;
+            *f3[347]:*:*:*|*f41347:*:*:*)
+		case $host_cpu in
+                  x86_64*) ax_gcc_arch="nocona pentium4 pentiumpro" ;;
+                  *) ax_gcc_arch="prescott pentium4 pentiumpro" ;;
+                esac ;;
+            *f??:*:*:*) ax_gcc_arch="pentium4 pentiumpro";;
+          esac ;;
+       *:68747541:*:*) # AMD
+          case $ax_cv_gcc_x86_cpuid_1 in
+	    *5[67]?:*:*:*) ax_gcc_arch=k6 ;;
+	    *5[8d]?:*:*:*) ax_gcc_arch="k6-2 k6" ;;
+	    *5[9]?:*:*:*) ax_gcc_arch="k6-3 k6" ;;
+	    *60?:*:*:*) ax_gcc_arch=k7 ;;
+	    *6[12]?:*:*:*) ax_gcc_arch="athlon k7" ;;
+	    *6[34]?:*:*:*) ax_gcc_arch="athlon-tbird k7" ;;
+	    *67?:*:*:*) ax_gcc_arch="athlon-4 athlon k7" ;;
+	    *6[68a]?:*:*:*)
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x86 cpuid 0x80000006 output" >&5
+$as_echo_n "checking for x86 cpuid 0x80000006 output... " >&6; }
+if ${ax_cv_gcc_x86_cpuid_0x80000006+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ax_cv_gcc_x86_cpuid_0x80000006=unknown
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+
+     int op = 0x80000006, eax, ebx, ecx, edx;
+     FILE *f;
+      __asm__("cpuid"
+        : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+        : "a" (op));
+     f = fopen("conftest_cpuid", "w"); if (!f) return 1;
+     fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx);
+     fclose(f);
+     return 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ax_cv_gcc_x86_cpuid_0x80000006=`cat conftest_cpuid`; rm -f conftest_cpuid
+else
+  ax_cv_gcc_x86_cpuid_0x80000006=unknown; rm -f conftest_cpuid
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_gcc_x86_cpuid_0x80000006" >&5
+$as_echo "$ax_cv_gcc_x86_cpuid_0x80000006" >&6; }
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ # L2 cache size
+	       case $ax_cv_gcc_x86_cpuid_0x80000006 in
+                 *:*:*[1-9a-f]??????:*) # (L2 = ecx >> 16) >= 256
+			ax_gcc_arch="athlon-xp athlon-4 athlon k7" ;;
+                 *) ax_gcc_arch="athlon-4 athlon k7" ;;
+	       esac ;;
+	    *f[4cef8b]?:*:*:*) ax_gcc_arch="athlon64 k8" ;;
+	    *f5?:*:*:*) ax_gcc_arch="opteron k8" ;;
+	    *f7?:*:*:*) ax_gcc_arch="athlon-fx opteron k8" ;;
+	    *f??:*:*:*) ax_gcc_arch="k8" ;;
+          esac ;;
+	*:746e6543:*:*) # IDT
+	   case $ax_cv_gcc_x86_cpuid_1 in
+	     *54?:*:*:*) ax_gcc_arch=winchip-c6 ;;
+	     *58?:*:*:*) ax_gcc_arch=winchip2 ;;
+	     *6[78]?:*:*:*) ax_gcc_arch=c3 ;;
+	     *69?:*:*:*) ax_gcc_arch="c3-2 c3" ;;
+	   esac ;;
+     esac
+     if test x"$ax_gcc_arch" = x; then # fallback
+	case $host_cpu in
+	  i586*) ax_gcc_arch=pentium ;;
+	  i686*) ax_gcc_arch=pentiumpro ;;
+        esac
+     fi
+     ;;
+
+  sparc*)
+     # Extract the first word of "prtdiag", so it can be a program name with args.
+set dummy prtdiag; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PRTDIAG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PRTDIAG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PRTDIAG="$PRTDIAG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="$PATH:/usr/platform/`uname -i`/sbin/:/usr/platform/`uname -m`/sbin/"
+for as_dir in $as_dummy
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PRTDIAG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_PRTDIAG" && ac_cv_path_PRTDIAG="prtdiag"
+  ;;
+esac
+fi
+PRTDIAG=$ac_cv_path_PRTDIAG
+if test -n "$PRTDIAG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PRTDIAG" >&5
+$as_echo "$PRTDIAG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+     cputype=`(((grep cpu /proc/cpuinfo | cut -d: -f2) ; ($PRTDIAG -v |grep -i sparc) ; grep -i cpu /var/run/dmesg.boot ) | head -n 1) 2> /dev/null`
+     cputype=`echo "$cputype" | tr -d ' -' |tr $as_cr_LETTERS $as_cr_letters`
+     case $cputype in
+         *ultrasparciv*) ax_gcc_arch="ultrasparc4 ultrasparc3 ultrasparc v9" ;;
+         *ultrasparciii*) ax_gcc_arch="ultrasparc3 ultrasparc v9" ;;
+         *ultrasparc*) ax_gcc_arch="ultrasparc v9" ;;
+         *supersparc*|*tms390z5[05]*) ax_gcc_arch="supersparc v8" ;;
+         *hypersparc*|*rt62[056]*) ax_gcc_arch="hypersparc v8" ;;
+         *cypress*) ax_gcc_arch=cypress ;;
+     esac ;;
+
+  alphaev5) ax_gcc_arch=ev5 ;;
+  alphaev56) ax_gcc_arch=ev56 ;;
+  alphapca56) ax_gcc_arch="pca56 ev56" ;;
+  alphapca57) ax_gcc_arch="pca57 pca56 ev56" ;;
+  alphaev6) ax_gcc_arch=ev6 ;;
+  alphaev67) ax_gcc_arch=ev67 ;;
+  alphaev68) ax_gcc_arch="ev68 ev67" ;;
+  alphaev69) ax_gcc_arch="ev69 ev68 ev67" ;;
+  alphaev7) ax_gcc_arch="ev7 ev69 ev68 ev67" ;;
+  alphaev79) ax_gcc_arch="ev79 ev7 ev69 ev68 ev67" ;;
+
+  powerpc*)
+     cputype=`((grep cpu /proc/cpuinfo | head -n 1 | cut -d: -f2 | cut -d, -f1 | sed 's/ //g') ; /usr/bin/machine ; /bin/machine; grep CPU /var/run/dmesg.boot | head -n 1 | cut -d" " -f2) 2> /dev/null`
+     cputype=`echo $cputype | sed -e 's/ppc//g;s/ *//g'`
+     case $cputype in
+       *750*) ax_gcc_arch="750 G3" ;;
+       *740[0-9]*) ax_gcc_arch="$cputype 7400 G4" ;;
+       *74[4-5][0-9]*) ax_gcc_arch="$cputype 7450 G4" ;;
+       *74[0-9][0-9]*) ax_gcc_arch="$cputype G4" ;;
+       *970*) ax_gcc_arch="970 G5 power4";;
+       *POWER4*|*power4*|*gq*) ax_gcc_arch="power4 970";;
+       *POWER5*|*power5*|*gr*|*gs*) ax_gcc_arch="power5 power4 970";;
+       603ev|8240) ax_gcc_arch="$cputype 603e 603";;
+       *) ax_gcc_arch=$cputype ;;
+     esac
+     ax_gcc_arch="$ax_gcc_arch powerpc"
+     ;;
+esac
+fi # not cross-compiling
+fi # guess arch
+
+if test "x$ax_gcc_arch" != x -a "x$ax_gcc_arch" != xno; then
+for arch in $ax_gcc_arch; do
+  if test "x$acx_maxopt_portable" = xyes; then # if we require portable code
+    flags="-mtune=$arch"
+    # -mcpu=$arch and m$arch generate nonportable code on every arch except
+    # x86.  And some other arches (e.g. Alpha) don't accept -mtune.  Grrr.
+    case $host_cpu in i*86|x86_64*) flags="$flags -mcpu=$arch -m$arch";; esac
+  else
+    flags="-march=$arch -mcpu=$arch -m$arch"
+  fi
+  for flag in $flags; do
+     { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $flag" >&5
+$as_echo_n "checking whether C compiler accepts $flag... " >&6; }
+ax_save_FLAGS=$CFLAGS
+   CFLAGS="$flag"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval `$as_echo "ax_cv_c_flags_$flag" | $as_tr_sh`=yes
+else
+  eval `$as_echo "ax_cv_c_flags_$flag" | $as_tr_sh`=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS=$ax_save_FLAGS
+eval ax_check_compiler_flags=$`$as_echo "ax_cv_c_flags_$flag" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5
+$as_echo "$ax_check_compiler_flags" >&6; }
+if test "x$ax_check_compiler_flags" = xyes; then
+	ax_cv_gcc_archflag=$flag; break
+else
+	:
+fi
+
+  done
+  test "x$ax_cv_gcc_archflag" = xunknown || break
+done
+fi
+
+fi # $GCC=yes
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc architecture flag" >&5
+$as_echo_n "checking for gcc architecture flag... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_gcc_archflag" >&5
+$as_echo "$ax_cv_gcc_archflag" >&6; }
+if test "x$ax_cv_gcc_archflag" = xunknown; then
+  :
+else
+  CFLAGS="$CFLAGS $ax_cv_gcc_archflag"
+fi
+
+
+     # drop to -O1 for gcc 4.2
+     $CC --version |
+	sed -e 's/.* \([0-9][0-9]*\)\.\([0-9][0-9]*\).*/\1 \2/' |
+	(read major minor
+	    if test $major -eq 4 -a $minor -eq 2; then
+				exit 0
+	    fi
+	    exit 1
+	) && CFLAGS="-O1"
+     ;;
+  esac
+
+  if test -z "$CFLAGS"; then
+	echo ""
+	echo "********************************************************"
+        echo "* WARNING: Don't know the best CFLAGS for this system  *"
+        echo "* Use ./configure CFLAGS=... to specify your own flags *"
+	echo "* (otherwise, a default of CFLAGS=-O3 will be used)    *"
+	echo "********************************************************"
+	echo ""
+        CFLAGS="-O3"
+  fi
+
+   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $CFLAGS" >&5
+$as_echo_n "checking whether C compiler accepts $CFLAGS... " >&6; }
+ax_save_FLAGS=$CFLAGS
+   CFLAGS="$CFLAGS"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval `$as_echo "ax_cv_c_flags_$CFLAGS" | $as_tr_sh`=yes
+else
+  eval `$as_echo "ax_cv_c_flags_$CFLAGS" | $as_tr_sh`=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   CFLAGS=$ax_save_FLAGS
+eval ax_check_compiler_flags=$`$as_echo "ax_cv_c_flags_$CFLAGS" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5
+$as_echo "$ax_check_compiler_flags" >&6; }
+if test "x$ax_check_compiler_flags" = xyes; then
+	:
+else
+
+	echo ""
+        echo "********************************************************"
+        echo "* WARNING: The guessed CFLAGS don't seem to work with  *"
+        echo "* your compiler.                                       *"
+        echo "* Use ./configure CFLAGS=... to specify your own flags *"
+        echo "********************************************************"
+        echo ""
+        CFLAGS=""
+
+fi
+
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports function __attribute__((__warn_unused_result__))" >&5
+$as_echo_n "checking whether the compiler supports function __attribute__((__warn_unused_result__))... " >&6; }
+if ${ax_cv_gcc_warn_unused_result+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+__attribute__((__warn_unused_result__))
+ int f(int i) { return i; }
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ax_cv_gcc_warn_unused_result=yes
+else
+  ax_cv_gcc_warn_unused_result=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_gcc_warn_unused_result" >&5
+$as_echo "$ax_cv_gcc_warn_unused_result" >&6; }
+ if test "$ax_cv_gcc_warn_unused_result" = yes; then
+
+$as_echo "#define GCC_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))" >>confdefs.h
+
+ fi
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__" >&5
+$as_echo_n "checking for __attribute__... " >&6; }
+if ${ax_cv___attribute__+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+	  static void foo(void) __attribute__ ((unused));
+	  static void
+	  foo(void) {
+	      exit(1);
+	  }
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ax_cv___attribute__=yes
+else
+  ax_cv___attribute__=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv___attribute__" >&5
+$as_echo "$ax_cv___attribute__" >&6; }
+  if test "$ax_cv___attribute__" = "yes"; then
+
+$as_echo "#define HAVE___ATTRIBUTE__ 1" >>confdefs.h
+
+  fi
+
+
+# CXX11FLAGS contains the flags (if any) added by AX_CXX_COMPILE_STDCXX_11
+# Original state of CXX and CXXCPP is preserved because CXX11FLAGS
+# is only needed for compiling interface/isl_test_cpp
+
+ac_save_CXX="$CXX"
+ac_save_CXXCPP="$CXXCPP"
+
+  ax_cxx_compile_alternatives="11 0x"    ax_cxx_compile_cxx11_required=false
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+  ac_success=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5
+$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; }
+if ${ax_cv_cxx_compile_cxx11+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ax_cv_cxx_compile_cxx11=yes
+else
+  ax_cv_cxx_compile_cxx11=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5
+$as_echo "$ax_cv_cxx_compile_cxx11" >&6; }
+  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+    ac_success=yes
+  fi
+
+
+
+    if test x$ac_success = xno; then
+                for alternative in ${ax_cxx_compile_alternatives}; do
+      for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
+        cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh`
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5
+$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; }
+if eval \${$cachevar+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_CXX="$CXX"
+           CXX="$CXX $switch"
+           cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  eval $cachevar=yes
+else
+  eval $cachevar=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+           CXX="$ac_save_CXX"
+fi
+eval ac_res=\$$cachevar
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+        if eval test x\$$cachevar = xyes; then
+          CXX="$CXX $switch"
+          if test -n "$CXXCPP" ; then
+            CXXCPP="$CXXCPP $switch"
+          fi
+          ac_success=yes
+          break
+        fi
+      done
+      if test x$ac_success = xyes; then
+        break
+      fi
+    done
+  fi
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+  if test x$ax_cxx_compile_cxx11_required = xtrue; then
+    if test x$ac_success = xno; then
+      as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5
+    fi
+  fi
+  if test x$ac_success = xno; then
+    HAVE_CXX11=0
+    { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5
+$as_echo "$as_me: No compiler with C++11 support was found" >&6;}
+  else
+    HAVE_CXX11=1
+
+$as_echo "#define HAVE_CXX11 1" >>confdefs.h
+
+  fi
+
+
+
+CXX11FLAGS=${CXX#$ac_save_CXX}
+CXX="$ac_save_CXX"
+CXXCPP="$ac_save_CXXCPP"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+case `pwd` in
+  *\ * | *\	*)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.6'
+macro_revision='2.4.6'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain=$ac_aux_dir/ltmain.sh
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO ""
+}
+
+case $ECHO in
+  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+   then ac_cv_path_FGREP="$GREP -F"
+   else
+     if test -z "$FGREP"; then
+  ac_path_FGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in fgrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+  # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'FGREP' >> "conftest.nl"
+    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_FGREP="$ac_path_FGREP"
+      ac_path_FGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_FGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_FGREP"; then
+    as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_FGREP=$FGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+  withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test yes = "$GCC"; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return, which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD=$ac_prog
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test yes = "$with_gnu_ld"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS=$lt_save_ifs
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD=$ac_dir/$ac_prog
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test no != "$with_gnu_ld" && break
+	;;
+      *)
+	test yes != "$with_gnu_ld" && break
+	;;
+      esac
+    fi
+  done
+  IFS=$lt_save_ifs
+else
+  lt_cv_path_LD=$LD # Let the user override the test with a path.
+fi
+fi
+
+LD=$lt_cv_path_LD
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM=$NM
+else
+  lt_nm_to_check=${ac_tool_prefix}nm
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS=$lt_save_ifs
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm=$ac_dir/$lt_tmp_nm
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the 'sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	# MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+	case $build_os in
+	mingw*) lt_bad_file=conftest.nm/nofile ;;
+	*) lt_bad_file=/dev/null ;;
+	esac
+	case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+	*$lt_bad_file* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break 2
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break 2
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS=$lt_save_ifs
+  done
+  : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test no != "$lt_cv_path_NM"; then
+  NM=$lt_cv_path_NM
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in dumpbin "link -dump"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DUMPBIN"; then
+  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$DUMPBIN" && break
+  done
+fi
+if test -z "$DUMPBIN"; then
+  ac_ct_DUMPBIN=$DUMPBIN
+  for ac_prog in dumpbin "link -dump"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DUMPBIN"; then
+  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_DUMPBIN" && break
+done
+
+  if test "x$ac_ct_DUMPBIN" = x; then
+    DUMPBIN=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DUMPBIN=$ac_ct_DUMPBIN
+  fi
+fi
+
+    case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols -headers"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+
+  if test : != "$DUMPBIN"; then
+    NM=$DUMPBIN
+  fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+  cat conftest.out >&5
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+    i=0
+  teststring=ABCD
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[	 ]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len" && \
+       test undefined != "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test X`env echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test 17 != "$i" # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+
+fi
+
+if test -n "$lt_cv_sys_max_cmd_len"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
+if ${lt_cv_to_host_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+
+fi
+
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
+if ${lt_cv_to_tool_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  #assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+
+fi
+
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test yes != "$GCC"; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test yes = "$GCC"; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJDUMP"; then
+  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+  ac_ct_OBJDUMP=$OBJDUMP
+  # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJDUMP"; then
+  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OBJDUMP="objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJDUMP" = x; then
+    OBJDUMP="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OBJDUMP=$ac_ct_OBJDUMP
+  fi
+else
+  OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# 'unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[45]*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  if ( file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[3-9]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd* | netbsdelf*-gnu)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd* | bitrig*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+os2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+  ac_ct_DLLTOOL=$DLLTOOL
+  # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DLLTOOL"; then
+  ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DLLTOOL" = x; then
+    DLLTOOL="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DLLTOOL=$ac_ct_DLLTOOL
+  fi
+else
+  DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh;
+  # decide which one to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd=$ECHO
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in ar
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$AR" && break
+  done
+fi
+if test -z "$AR"; then
+  ac_ct_AR=$AR
+  for ac_prog in ar
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_AR" && break
+done
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+fi
+
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+$as_echo_n "checking for archiver @FILE support... " >&6; }
+if ${lt_cv_ar_at_file+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ar_at_file=no
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
+      { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+      if test 0 -eq "$ac_status"; then
+	# Ensure the archiver fails upon bogus file names.
+	rm -f conftest.$ac_objext libconftest.a
+	{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	if test 0 -ne "$ac_status"; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+$as_echo "$lt_cv_ar_at_file" >&6; }
+
+if test no = "$lt_cv_ar_at_file"; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  bitrig* | openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[BCDT]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[ABCDGISTW]'
+  ;;
+hpux*)
+  if test ia64 = "$host_cpu"; then
+    symcode='[ABCDEGRST]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[BCDEGRST]'
+  ;;
+osf*)
+  symcode='[BCDEGQRST]'
+  ;;
+solaris*)
+  symcode='[BDRT]'
+  ;;
+sco3.2v5*)
+  symcode='[DT]'
+  ;;
+sysv4.2uw2*)
+  symcode='[DT]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[ABDT]'
+  ;;
+sysv4)
+  symcode='[DFNSTU]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[ABCDGIRSTW]' ;;
+esac
+
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  # Gets list of data symbols to import.
+  lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+  # Adjust the below global symbol transforms to fixup imported variables.
+  lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+  lt_c_name_hook=" -e 's/^I .* \(.*\)$/  {\"\1\", (void *) 0},/p'"
+  lt_c_name_lib_hook="\
+  -e 's/^I .* \(lib.*\)$/  {\"\1\", (void *) 0},/p'\
+  -e 's/^I .* \(.*\)$/  {\"lib\1\", (void *) 0},/p'"
+else
+  # Disable hooks by default.
+  lt_cv_sys_global_symbol_to_import=
+  lt_cdecl_hook=
+  lt_c_name_hook=
+  lt_c_name_lib_hook=
+fi
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/  {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"lib\1\", (void *) \&\1},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function,
+    # D for any global variable and I for any imported variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK '"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+"     /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+"     /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+"     {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+"     s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[	 ]\($symcode$symcode*\)[	 ][	 ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+  (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_globsym_save_LIBS=$LIBS
+	  lt_globsym_save_CFLAGS=$CFLAGS
+	  LIBS=conftstm.$ac_objext
+	  CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest$ac_exeext; then
+	    pipe_works=yes
+	  fi
+	  LIBS=$lt_globsym_save_LIBS
+	  CFLAGS=$lt_globsym_save_CFLAGS
+	else
+	  echo "cannot find nm_test_func in $nlist" >&5
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&5
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+    fi
+  else
+    echo "$progname: failed program was:" >&5
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test yes = "$pipe_works"; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+$as_echo_n "checking for sysroot... " >&6; }
+
+# Check whether --with-sysroot was given.
+if test "${with_sysroot+set}" = set; then :
+  withval=$with_sysroot;
+else
+  with_sysroot=no
+fi
+
+
+lt_sysroot=
+case $with_sysroot in #(
+ yes)
+   if test yes = "$GCC"; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5
+$as_echo "$with_sysroot" >&6; }
+   as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
+   ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+$as_echo "${lt_sysroot:-no}" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5
+$as_echo_n "checking for a working dd... " >&6; }
+if ${ac_cv_path_lt_DD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+if test -z "$lt_DD"; then
+  ac_path_lt_DD_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in dd; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_lt_DD" || continue
+if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+  cmp -s conftest.i conftest.out \
+  && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi
+      $ac_path_lt_DD_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_lt_DD"; then
+    :
+  fi
+else
+  ac_cv_path_lt_DD=$lt_DD
+fi
+
+rm -f conftest.i conftest2.i conftest.out
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5
+$as_echo "$ac_cv_path_lt_DD" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5
+$as_echo_n "checking how to truncate binary pipes... " >&6; }
+if ${lt_cv_truncate_bin+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+  cmp -s conftest.i conftest.out \
+  && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5
+$as_echo "$lt_cv_truncate_bin" >&6; }
+
+
+
+
+
+
+
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+    for cc_temp in $*""; do
+      case $cc_temp in
+        compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+        distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+        \-*) ;;
+        *) break;;
+      esac
+    done
+    func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+  enableval=$enable_libtool_lock;
+fi
+
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out what ABI is being produced by ac_compile, and set mode
+  # options accordingly.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE=32
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE=64
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if test yes = "$lt_cv_prog_gnu_ld"; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+mips64*-*linux*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    emul=elf
+    case `/usr/bin/file conftest.$ac_objext` in
+      *32-bit*)
+	emul="${emul}32"
+	;;
+      *64-bit*)
+	emul="${emul}64"
+	;;
+    esac
+    case `/usr/bin/file conftest.$ac_objext` in
+      *MSB*)
+	emul="${emul}btsmip"
+	;;
+      *LSB*)
+	emul="${emul}ltsmip"
+	;;
+    esac
+    case `/usr/bin/file conftest.$ac_objext` in
+      *N32*)
+	emul="${emul}n32"
+	;;
+    esac
+    LD="${LD-ld} -m $emul"
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.  Note that the listed cases only cover the
+  # situations where additional linker options are needed (such as when
+  # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+  # vice versa); the common cases where no linker options are needed do
+  # not appear in the list.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    case `/usr/bin/file conftest.o` in
+	      *x86-64*)
+		LD="${LD-ld} -m elf32_x86_64"
+		;;
+	      *)
+		LD="${LD-ld} -m elf_i386"
+		;;
+	    esac
+	    ;;
+	  powerpc64le-*linux*)
+	    LD="${LD-ld} -m elf32lppclinux"
+	    ;;
+	  powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  powerpcle-*linux*)
+	    LD="${LD-ld} -m elf64lppc"
+	    ;;
+	  powerpc-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS=$CFLAGS
+  CFLAGS="$CFLAGS -belf"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_cc_needs_belf=yes
+else
+  lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+     ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+  if test yes != "$lt_cv_cc_needs_belf"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS=$SAVE_CFLAGS
+  fi
+  ;;
+*-*solaris*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*|x86_64-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD=${LD-ld}_sol2
+        fi
+        ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks=$enable_libtool_lock
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$MANIFEST_TOOL"; then
+  ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
+if test -n "$MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+$as_echo "$MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
+  ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
+  # Extract the first word of "mt", so it can be a program name with args.
+set dummy mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_MANIFEST_TOOL"; then
+  ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
+if test -n "$ac_ct_MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_MANIFEST_TOOL" = x; then
+    MANIFEST_TOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
+  fi
+else
+  MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
+fi
+
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if ${lt_cv_path_mainfest_tool+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&5
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+if test yes != "$lt_cv_path_mainfest_tool"; then
+  MANIFEST_TOOL=:
+fi
+
+
+
+
+
+
+  case $host_os in
+    rhapsody* | darwin*)
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DSYMUTIL"; then
+  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+  ac_ct_DSYMUTIL=$DSYMUTIL
+  # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DSYMUTIL"; then
+  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DSYMUTIL" = x; then
+    DSYMUTIL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DSYMUTIL=$ac_ct_DSYMUTIL
+  fi
+else
+  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NMEDIT"; then
+  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+  ac_ct_NMEDIT=$NMEDIT
+  # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_NMEDIT"; then
+  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_NMEDIT="nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_NMEDIT" = x; then
+    NMEDIT=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    NMEDIT=$ac_ct_NMEDIT
+  fi
+else
+  NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LIPO"; then
+  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+  ac_ct_LIPO=$LIPO
+  # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_LIPO"; then
+  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_LIPO="lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_LIPO" = x; then
+    LIPO=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    LIPO=$ac_ct_LIPO
+  fi
+else
+  LIPO="$ac_cv_prog_LIPO"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL"; then
+  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+  ac_ct_OTOOL=$OTOOL
+  # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL"; then
+  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL="otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL" = x; then
+    OTOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL=$ac_ct_OTOOL
+  fi
+else
+  OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL64"; then
+  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+  ac_ct_OTOOL64=$OTOOL64
+  # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL64"; then
+  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL64="otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL64" = x; then
+    OTOOL64=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL64=$ac_ct_OTOOL64
+  fi
+else
+  OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_apple_cc_single_mod=no
+      if test -z "$LT_MULTI_MODULE"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	# If there is a non-empty error log, and "single_module"
+	# appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+	  cat conftest.err >&5
+	# Otherwise, if the output was created with a 0 exit code from
+	# the compiler, it worked.
+	elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&5
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_ld_exported_symbols_list=yes
+else
+  lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+      echo "$AR cru libconftest.a conftest.o" >&5
+      $AR cru libconftest.a conftest.o 2>&5
+      echo "$RANLIB libconftest.a" >&5
+      $RANLIB libconftest.a 2>&5
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+	cat conftest.err >&5
+      elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&5
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+    case $host_os in
+    rhapsody* | darwin1.[012])
+      _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+	10.[012][,.]*)
+	  _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test yes = "$lt_cv_apple_cc_single_mod"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test yes = "$lt_cv_ld_exported_symbols_list"; then
+      _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
+    fi
+    if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+
+# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+#       string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+#       string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+#       string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+#       "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+#       VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+    case x$2 in
+    x)
+        ;;
+    *:)
+        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
+        ;;
+    x:*)
+        eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
+        ;;
+    *::*)
+        eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+        eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
+        ;;
+    *)
+        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
+        ;;
+    esac
+}
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dlfcn.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+func_stripname_cnf ()
+{
+  case $2 in
+  .*) func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%\\\\$2\$%%"`;;
+  *)  func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%$2\$%%"`;;
+  esac
+} # func_stripname_cnf
+
+
+
+
+
+# Set options
+
+
+
+        enable_dlopen=no
+
+
+  enable_win32_dll=no
+
+
+            # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+  enableval=$enable_shared; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac
+else
+  enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+  # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+  enableval=$enable_static; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac
+else
+  enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+  withval=$with_pic; lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for lt_pkg in $withval; do
+	IFS=$lt_save_ifs
+	if test "X$lt_pkg" = "X$lt_p"; then
+	  pic_mode=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac
+else
+  pic_mode=default
+fi
+
+
+
+
+
+
+
+
+  # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+  enableval=$enable_fast_install; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac
+else
+  enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+  shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[5-9]*,yes)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5
+$as_echo_n "checking which variant of shared library versioning to provide... " >&6; }
+
+# Check whether --with-aix-soname was given.
+if test "${with_aix_soname+set}" = set; then :
+  withval=$with_aix_soname; case $withval in
+    aix|svr4|both)
+      ;;
+    *)
+      as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5
+      ;;
+    esac
+    lt_cv_with_aix_soname=$with_aix_soname
+else
+  if ${lt_cv_with_aix_soname+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_with_aix_soname=aix
+fi
+
+    with_aix_soname=$lt_cv_with_aix_soname
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5
+$as_echo "$with_aix_soname" >&6; }
+  if test aix != "$with_aix_soname"; then
+    # For the AIX way of multilib, we name the shared archive member
+    # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+    # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+    # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+    # the AIX toolchain works better with OBJECT_MODE set (default 32).
+    if test 64 = "${OBJECT_MODE-32}"; then
+      shared_archive_member_spec=shr_64
+    else
+      shared_archive_member_spec=shr
+    fi
+  fi
+  ;;
+*)
+  with_aix_soname=aix
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS=$ltmain
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}"; then
+   setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test set != "${COLLECT_NAMES+set}"; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a '.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+old_CC=$CC
+old_CFLAGS=$CFLAGS
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+func_cc_basename $compiler
+cc_basename=$func_cc_basename_result
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD=$MAGIC_CMD
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS=$lt_save_ifs
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/${ac_tool_prefix}file"; then
+      lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS=$lt_save_ifs
+  MAGIC_CMD=$lt_save_MAGIC_CMD
+  ;;
+esac
+fi
+
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD=$MAGIC_CMD
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS=$lt_save_ifs
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/file"; then
+      lt_cv_path_MAGIC_CMD=$ac_dir/"file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS=$lt_save_ifs
+  MAGIC_CMD=$lt_save_MAGIC_CMD
+  ;;
+esac
+fi
+
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  else
+    MAGIC_CMD=:
+  fi
+fi
+
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC=$CC
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test yes = "$GCC"; then
+  case $cc_basename in
+  nvcc*)
+    lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+  *)
+    lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+  esac
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_rtti_exceptions=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="-fno-rtti -fno-exceptions"  ## exclude from sc_useless_quotes_in_assignment
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_rtti_exceptions=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then
+    lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+    :
+fi
+
+fi
+
+
+
+
+
+
+  lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+
+  if test yes = "$GCC"; then
+    lt_prog_compiler_wl='-Wl,'
+    lt_prog_compiler_static='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test ia64 = "$host_cpu"; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      lt_prog_compiler_pic='-fPIC'
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the '-m68020' flag to GCC prevents building anything better,
+            # like '-m68040'.
+            lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      case $host_os in
+      os2*)
+	lt_prog_compiler_static='$wl-static'
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      lt_prog_compiler_pic='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      lt_prog_compiler_wl='-Xlinker '
+      if test -n "$lt_prog_compiler_pic"; then
+        lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl='-Wl,'
+      if test ia64 = "$host_cpu"; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      else
+	lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      case $cc_basename in
+      nagfor*)
+        # NAG Fortran compiler
+        lt_prog_compiler_wl='-Wl,-Wl,,'
+        lt_prog_compiler_pic='-PIC'
+        lt_prog_compiler_static='-Bstatic'
+        ;;
+      esac
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      case $host_os in
+      os2*)
+	lt_prog_compiler_static='$wl-static'
+	;;
+      esac
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static='$wl-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+      case $cc_basename in
+      # old Intel for x86_64, which still supported -KPIC.
+      ecc*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-KPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='--shared'
+	lt_prog_compiler_static='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	lt_prog_compiler_wl='-Wl,-Wl,,'
+	lt_prog_compiler_pic='-PIC'
+	lt_prog_compiler_static='-Bstatic'
+	;;
+      tcc*)
+	# Fabrice Bellard et al's Tiny C Compiler
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fPIC'
+	lt_prog_compiler_static='-static'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fpic'
+	lt_prog_compiler_static='-Bstatic'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-qpic'
+	lt_prog_compiler_static='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Wl,'
+	  ;;
+        *Intel*\ [CF]*Compiler*)
+	  lt_prog_compiler_wl='-Wl,'
+	  lt_prog_compiler_pic='-fPIC'
+	  lt_prog_compiler_static='-static'
+	  ;;
+	*Portland\ Group*)
+	  lt_prog_compiler_wl='-Wl,'
+	  lt_prog_compiler_pic='-fpic'
+	  lt_prog_compiler_static='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    rdos*)
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	lt_prog_compiler_wl='-Qoption ld ';;
+      *)
+	lt_prog_compiler_wl='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl='-Qoption ld '
+      lt_prog_compiler_pic='-PIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic='-Kconform_pic'
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    unicos*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_can_build_shared=no
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic='-pic'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared=no
+      ;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms that do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic=
+    ;;
+  *)
+    lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+    ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"  ## exclude from sc_useless_quotes_in_assignment
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_pic_works"; then
+    case $lt_prog_compiler_pic in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+     esac
+else
+    lt_prog_compiler_pic=
+     lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works=no
+   save_LDFLAGS=$LDFLAGS
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_static_works"; then
+    :
+else
+    lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links=nottested
+if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test no = "$hard_links"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  runpath_var=
+  allow_undefined_flag=
+  always_export_symbols=no
+  archive_cmds=
+  archive_expsym_cmds=
+  compiler_needs_object=no
+  enable_shared_with_static_runtimes=no
+  export_dynamic_flag_spec=
+  export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  hardcode_automatic=no
+  hardcode_direct=no
+  hardcode_direct_absolute=no
+  hardcode_libdir_flag_spec=
+  hardcode_libdir_separator=
+  hardcode_minus_L=no
+  hardcode_shlibpath_var=unsupported
+  inherit_rpath=no
+  link_all_deplibs=unknown
+  module_cmds=
+  module_expsym_cmds=
+  old_archive_from_new_cmds=
+  old_archive_from_expsyms_cmds=
+  thread_safe_flag_spec=
+  whole_archive_flag_spec=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ' (' and ')$', so one must not match beginning or
+  # end of line.  Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+  # as well as any symbol that contains 'd'.
+  exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test yes != "$GCC"; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd* | bitrig*)
+    with_gnu_ld=no
+    ;;
+  linux* | k*bsd*-gnu | gnu*)
+    link_all_deplibs=no
+    ;;
+  esac
+
+  ld_shlibs=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test yes = "$with_gnu_ld"; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+	  *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test yes = "$lt_use_gnu_ld_interface"; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='$wl'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+    export_dynamic_flag_spec='$wl--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+    else
+      whole_archive_flag_spec=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[3-9]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test ia64 != "$host_cpu"; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	allow_undefined_flag=unsupported
+	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      export_dynamic_flag_spec='$wl--export-all-symbols'
+      allow_undefined_flag=unsupported
+      always_export_symbols=no
+      enable_shared_with_static_runtimes=yes
+      export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+      exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file, use it as
+	# is; otherwise, prepend EXPORTS...
+	archive_expsym_cmds='if   test DEF = "`$SED -n     -e '\''s/^[	 ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
+          cp $export_symbols $output_objdir/$soname.def;
+        else
+          echo EXPORTS > $output_objdir/$soname.def;
+          cat $export_symbols >> $output_objdir/$soname.def;
+        fi~
+        $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    haiku*)
+      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+      link_all_deplibs=yes
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      shrext_cmds=.dll
+      archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	prefix_cmds="$SED"~
+	if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	  prefix_cmds="$prefix_cmds -e 1d";
+	fi~
+	prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+      enable_shared_with_static_runtimes=yes
+      ;;
+
+    interix[3-9]*)
+      hardcode_direct=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+      export_dynamic_flag_spec='$wl-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test linux-dietlibc = "$host_os"; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test no = "$tmp_diet"
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  whole_archive_flag_spec=
+	  tmp_sharedflag='--shared' ;;
+        nagfor*)                        # NAGFOR 5.3
+          tmp_sharedflag='-Wl,-shared' ;;
+	xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  compiler_needs_object=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  compiler_needs_object=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+
+        if test yes = "$supports_anon_versioning"; then
+          archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+            cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+            echo "local: *; };" >> $output_objdir/$libname.ver~
+            $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	tcc*)
+	  export_dynamic_flag_spec='-rdynamic'
+	  ;;
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+	  hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+	  archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test yes = "$supports_anon_versioning"; then
+	    archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+              cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+              echo "local: *; };" >> $output_objdir/$libname.ver~
+              $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        ld_shlibs=no
+      fi
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+	    archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	    archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    ld_shlibs=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+    esac
+
+    if test no = "$ld_shlibs"; then
+      runpath_var=
+      hardcode_libdir_flag_spec=
+      export_dynamic_flag_spec=
+      whole_archive_flag_spec=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag=unsupported
+      always_export_symbols=yes
+      archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	hardcode_direct=unsupported
+      fi
+      ;;
+
+    aix[4-9]*)
+      if test ia64 = "$host_cpu"; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to GNU nm, but means don't demangle to AIX nm.
+	# Without the "-l" option, or with the "-B" option, AIX nm treats
+	# weak defined symbols like other global defined symbols, whereas
+	# GNU nm marks them as "W".
+	# While the 'weak' keyword is ignored in the Export File, we need
+	# it in the Import File for the 'aix-soname' feature, so we have
+	# to replace the "-B" option with "-P" for AIX nm.
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+	else
+	  export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# have runtime linking enabled, and use it for executables.
+	# For shared libraries, we enable/disable runtime linking
+	# depending on the kind of the shared library created -
+	# when "with_aix_soname,aix_use_runtimelinking" is:
+	# "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "aix,yes"  lib.so          shared, rtl:yes, for executables
+	#            lib.a           static archive
+	# "both,no"  lib.so.V(shr.o) shared, rtl:yes
+	#            lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a(lib.so.V) shared, rtl:no
+	# "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a           static archive
+	case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+	    # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	    # so we don't have lib.a shared libs to link our executables.
+	    # We have to force runtime linking in this case.
+	    aix_use_runtimelinking=yes
+	    LDFLAGS="$LDFLAGS -Wl,-brtl"
+	  fi
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds=''
+      hardcode_direct=yes
+      hardcode_direct_absolute=yes
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      file_list_spec='$wl-f,'
+      case $with_aix_soname,$aix_use_runtimelinking in
+      aix,*) ;; # traditional, no import file
+      svr4,* | *,yes) # use import file
+	# The Import File defines what to hardcode.
+	hardcode_direct=no
+	hardcode_direct_absolute=no
+	;;
+      esac
+
+      if test yes = "$GCC"; then
+	case $host_os in aix4.[012]|aix4.[012].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`$CC -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  hardcode_direct=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  hardcode_minus_L=yes
+	  hardcode_libdir_flag_spec='-L$libdir'
+	  hardcode_libdir_separator=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test yes = "$aix_use_runtimelinking"; then
+	  shared_flag="$shared_flag "'$wl-G'
+	fi
+	# Need to ensure runtime linking is disabled for the traditional
+	# shared library, or the linker may eventually find shared libraries
+	# /with/ Import File - we do not want to mix them.
+	shared_flag_aix='-shared'
+	shared_flag_svr4='-shared $wl-G'
+      else
+	# not using gcc
+	if test ia64 = "$host_cpu"; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test yes = "$aix_use_runtimelinking"; then
+	    shared_flag='$wl-G'
+	  else
+	    shared_flag='$wl-bM:SRE'
+	  fi
+	  shared_flag_aix='$wl-bM:SRE'
+	  shared_flag_svr4='$wl-G'
+	fi
+      fi
+
+      export_dynamic_flag_spec='$wl-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols=yes
+      if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	allow_undefined_flag='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        if test set = "${lt_cv_aix_libpath+set}"; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=/usr/lib:/lib
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+        hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
+        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+      else
+	if test ia64 = "$host_cpu"; then
+	  hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib'
+	  allow_undefined_flag="-z nodefs"
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 if test set = "${lt_cv_aix_libpath+set}"; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=/usr/lib:/lib
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+	 hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  no_undefined_flag=' $wl-bernotok'
+	  allow_undefined_flag=' $wl-berok'
+	  if test yes = "$with_gnu_ld"; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    whole_archive_flag_spec='$convenience'
+	  fi
+	  archive_cmds_need_lc=yes
+	  archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	  # -brtl affects multiple linker settings, -berok does not and is overridden later
+	  compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`'
+	  if test svr4 != "$with_aix_soname"; then
+	    # This is similar to how AIX traditionally builds its shared libraries.
+	    archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	  fi
+	  if test aix != "$with_aix_soname"; then
+	    archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	  else
+	    # used by -dlpreopen to get the symbols
+	    archive_expsym_cmds="$archive_expsym_cmds"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	  fi
+	  archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[45]*)
+      export_dynamic_flag_spec=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	hardcode_libdir_flag_spec=' '
+	allow_undefined_flag=unsupported
+	always_export_symbols=yes
+	file_list_spec='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=.dll
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	archive_expsym_cmds='if   test DEF = "`$SED -n     -e '\''s/^[	 ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
+            cp "$export_symbols" "$output_objdir/$soname.def";
+            echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+          else
+            $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+          fi~
+          $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+          linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, )='true'
+	enable_shared_with_static_runtimes=yes
+	exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	old_postinstall_cmds='chmod 644 $oldlib'
+	postlink_cmds='lt_outputfile="@OUTPUT@"~
+          lt_tool_outputfile="@TOOL_OUTPUT@"~
+          case $lt_outputfile in
+            *.exe|*.EXE) ;;
+            *)
+              lt_outputfile=$lt_outputfile.exe
+              lt_tool_outputfile=$lt_tool_outputfile.exe
+              ;;
+          esac~
+          if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+            $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+            $RM "$lt_outputfile.manifest";
+          fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	hardcode_libdir_flag_spec=' '
+	allow_undefined_flag=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=.dll
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	old_archive_from_new_cmds='true'
+	# FIXME: Should let the user specify the lib program.
+	old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	enable_shared_with_static_runtimes=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc=no
+  hardcode_direct=no
+  hardcode_automatic=yes
+  hardcode_shlibpath_var=unsupported
+  if test yes = "$lt_cv_ld_force_load"; then
+    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+  else
+    whole_archive_flag_spec=''
+  fi
+  link_all_deplibs=yes
+  allow_undefined_flag=$_lt_dar_allow_undefined
+  case $cc_basename in
+     ifort*|nagfor*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test yes = "$_lt_dar_can_shared"; then
+    output_verbose_link_cmd=func_echo_all
+    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+    archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+    module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+
+  else
+  ld_shlibs=no
+  fi
+
+      ;;
+
+    dgux*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    hpux9*)
+      if test yes = "$GCC"; then
+	archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+      else
+	archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec='$wl+b $wl$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      export_dynamic_flag_spec='$wl-E'
+      ;;
+
+    hpux10*)
+      if test yes,no = "$GCC,$with_gnu_ld"; then
+	archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test no = "$with_gnu_ld"; then
+	hardcode_libdir_flag_spec='$wl+b $wl$libdir'
+	hardcode_libdir_separator=:
+	hardcode_direct=yes
+	hardcode_direct_absolute=yes
+	export_dynamic_flag_spec='$wl-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	hardcode_minus_L=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test yes,no = "$GCC,$with_gnu_ld"; then
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler__b=no
+   save_LDFLAGS=$LDFLAGS
+   LDFLAGS="$LDFLAGS -b"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler__b=yes
+       fi
+     else
+       lt_cv_prog_compiler__b=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test yes = "$lt_cv_prog_compiler__b"; then
+    archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+    archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+	  ;;
+	esac
+      fi
+      if test no = "$with_gnu_ld"; then
+	hardcode_libdir_flag_spec='$wl+b $wl$libdir'
+	hardcode_libdir_separator=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  hardcode_direct=no
+	  hardcode_shlibpath_var=no
+	  ;;
+	*)
+	  hardcode_direct=yes
+	  hardcode_direct_absolute=yes
+	  export_dynamic_flag_spec='$wl-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test yes = "$GCC"; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  save_LDFLAGS=$LDFLAGS
+	   LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
+	   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int foo (void) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_irix_exported_symbol=yes
+else
+  lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+           LDFLAGS=$save_LDFLAGS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+	if test yes = "$lt_cv_irix_exported_symbol"; then
+          archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
+	fi
+	link_all_deplibs=no
+      else
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+      hardcode_libdir_separator=:
+      inherit_rpath=yes
+      link_all_deplibs=yes
+      ;;
+
+    linux*)
+      case $cc_basename in
+      tcc*)
+	# Fabrice Bellard et al's Tiny C Compiler
+	ld_shlibs=yes
+	archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	;;
+      esac
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    newsos6)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+      hardcode_libdir_separator=:
+      hardcode_shlibpath_var=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd* | bitrig*)
+      if test -f /usr/libexec/ld.so; then
+	hardcode_direct=yes
+	hardcode_shlibpath_var=no
+	hardcode_direct_absolute=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+	  hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+	  export_dynamic_flag_spec='$wl-E'
+	else
+	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+	fi
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      shrext_cmds=.dll
+      archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	prefix_cmds="$SED"~
+	if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	  prefix_cmds="$prefix_cmds -e 1d";
+	fi~
+	prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+      enable_shared_with_static_runtimes=yes
+      ;;
+
+    osf3*)
+      if test yes = "$GCC"; then
+	allow_undefined_flag=' $wl-expect_unresolved $wl\*'
+	archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+      hardcode_libdir_separator=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test yes = "$GCC"; then
+	allow_undefined_flag=' $wl-expect_unresolved $wl\*'
+	archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+          $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_separator=:
+      ;;
+
+    solaris*)
+      no_undefined_flag=' -z defs'
+      if test yes = "$GCC"; then
+	wlarc='$wl'
+	archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+          $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+            $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='$wl'
+	  archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+            $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_shlibpath_var=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands '-z linker_flag'.  GCC discards it without '$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test yes = "$GCC"; then
+	  whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+	else
+	  whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      link_all_deplibs=yes
+      ;;
+
+    sunos4*)
+      if test sequent = "$host_vendor"; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  reload_cmds='$CC -r -o $output$reload_objs'
+	  hardcode_direct=no
+        ;;
+	motorola)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var=no
+      export_dynamic_flag_spec='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	hardcode_shlibpath_var=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	ld_shlibs=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag='$wl-z,text'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      runpath_var='LD_RUN_PATH'
+
+      if test yes = "$GCC"; then
+	archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We CANNOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      no_undefined_flag='$wl-z,text'
+      allow_undefined_flag='$wl-z,nodefs'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='$wl-R,$libdir'
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      export_dynamic_flag_spec='$wl-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test yes = "$GCC"; then
+	archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      ld_shlibs=no
+      ;;
+    esac
+
+    if test sni = "$host_vendor"; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	export_dynamic_flag_spec='$wl-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test no = "$ld_shlibs" && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc=yes
+
+  if test yes,yes = "$GCC,$enable_shared"; then
+    case $archive_cmds in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$lt_prog_compiler_wl
+	  pic_flag=$lt_prog_compiler_pic
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$allow_undefined_flag
+	  allow_undefined_flag=
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	  then
+	    lt_cv_archive_cmds_need_lc=no
+	  else
+	    lt_cv_archive_cmds_need_lc=yes
+	  fi
+	  allow_undefined_flag=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+      archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test yes = "$GCC"; then
+  case $host_os in
+    darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+    *) lt_awk_arg='/^libraries:/' ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;;
+    *) lt_sed_strip_eq='s|=/|/|g' ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary...
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  # ...but if some path component already ends with the multilib dir we assume
+  # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+  case "$lt_multi_os_dir; $lt_search_path_spec " in
+  "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+    lt_multi_os_dir=
+    ;;
+  esac
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+    elif test -n "$lt_multi_os_dir"; then
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS = " "; FS = "/|\n";} {
+  lt_foo = "";
+  lt_count = 0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo = "/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[lt_foo]++; }
+  if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's|/\([A-Za-z]:\)|\1|g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=.so
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='$libname$release$shared_ext$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test ia64 = "$host_cpu"; then
+    # AIX 5 supports IA64
+    library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line '#! .'.  This would cause the generated library to
+    # depend on '.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # Using Import Files as archive members, it is possible to support
+    # filename-based versioning of shared library archives on AIX. While
+    # this would work for both with and without runtime linking, it will
+    # prevent static linking of such archives. So we do filename-based
+    # shared library versioning with .so extension only, which is used
+    # when both runtime linking and shared linking is enabled.
+    # Unfortunately, runtime linking may impact performance, so we do
+    # not want this to be the default eventually. Also, we use the
+    # versioned .so libs for executables only if there is the -brtl
+    # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+    # To allow for filename-based versioning support, we need to create
+    # libNAME.so.V as an archive file, containing:
+    # *) an Import File, referring to the versioned filename of the
+    #    archive as well as the shared archive member, telling the
+    #    bitwidth (32 or 64) of that shared object, and providing the
+    #    list of exported symbols of that shared object, eventually
+    #    decorated with the 'weak' keyword
+    # *) the shared object with the F_LOADONLY flag set, to really avoid
+    #    it being seen by the linker.
+    # At run time we better use the real file rather than another symlink,
+    # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+    case $with_aix_soname,$aix_use_runtimelinking in
+    # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    aix,yes) # traditional libtool
+      dynamic_linker='AIX unversionable lib.so'
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      ;;
+    aix,no) # traditional AIX only
+      dynamic_linker='AIX lib.a(lib.so.V)'
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      ;;
+    svr4,*) # full svr4 only
+      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,yes) # both, prefer svr4
+      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # unpreferred sharedlib libNAME.a needs extra handling
+      postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+      postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,no) # both, prefer aix
+      dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)"
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+      postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+      postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+      ;;
+    esac
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='$libname$shared_ext'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+    library_names_spec='$libname.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec=$LIB
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$major$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[23].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      soname_spec='$libname$release$shared_ext$major'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    if test 32 = "$HPUX_IA64_MODE"; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux32
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux64
+    fi
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[3-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test yes = "$lt_cv_prog_gnu_ld"; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+  sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+linux*android*)
+  version_type=none # Android doesn't support versioned libraries.
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext'
+  soname_spec='$libname$release$shared_ext'
+  finish_cmds=
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  dynamic_linker='Android linker'
+  # Don't embed -rpath directories since the linker doesn't support them.
+  hardcode_libdir_flag_spec='-L$libdir'
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+	 LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+  lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Ideally, we could use ldconfig to report *all* directores which are
+  # searched for libraries, however this is still not possible.  Aside from not
+  # being certain /sbin/ldconfig is available, command
+  # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+  # even though it is searched at run-time.  Try to do the best guess by
+  # appending ld.so.conf contents (and includes) to the search path.
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsdelf*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='NetBSD ld.elf_so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd* | bitrig*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec=/usr/lib
+  need_lib_prefix=no
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    need_version=no
+  else
+    need_version=yes
+  fi
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+os2*)
+  libname_spec='$name'
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
+  need_lib_prefix=no
+  # OS/2 can only load a DLL with a base name of 8 characters or less.
+  soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+    v=$($ECHO $release$versuffix | tr -d .-);
+    n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+    $ECHO $n$v`$shared_ext'
+  library_names_spec='${libname}_dll.$libext'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=BEGINLIBPATH
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  postinstall_cmds='base_file=`basename \$file`~
+    dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+    dldir=$destdir/`dirname \$dlpath`~
+    test -d \$dldir || mkdir -p \$dldir~
+    $install_prog $dir/$dlname \$dldir/$dlname~
+    chmod a+x \$dldir/$dlname~
+    if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+      eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+    fi'
+  postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+    dlpath=$dir/\$dldll~
+    $RM \$dlpath'
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test yes = "$with_gnu_ld"; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec; then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+    soname_spec='$libname$shared_ext.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=sco
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test yes = "$with_gnu_ld"; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test no = "$dynamic_linker" && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test yes = "$GCC"; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+  sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
+fi
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+  sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
+fi
+
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+   test -n "$runpath_var" ||
+   test yes = "$hardcode_automatic"; then
+
+  # We can hardcode non-existent directories.
+  if test no != "$hardcode_direct" &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" &&
+     test no != "$hardcode_minus_L"; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test relink = "$hardcode_action" ||
+   test yes = "$inherit_rpath"; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test yes = "$shlibpath_overrides_runpath" ||
+     test no = "$enable_shared"; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+  if test yes != "$enable_dlopen"; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen=load_add_on
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen=LoadLibrary
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen=dlopen
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+    # if libdl is installed we need to link against it
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
+else
+
+    lt_cv_dlopen=dyld
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+
+fi
+
+    ;;
+
+  tpf*)
+    # Don't try to run any link tests for TPF.  We know it's impossible
+    # because TPF is a cross-compiler, and we know how we open DSOs.
+    lt_cv_dlopen=dlopen
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=no
+    ;;
+
+  *)
+    ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+  lt_cv_dlopen=shl_load
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_shl_load=yes
+else
+  ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+  lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld
+else
+  ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+  lt_cv_dlopen=dlopen
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_svld_dlopen=yes
+else
+  ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+  lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_dld_link=yes
+else
+  ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+  lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+    ;;
+  esac
+
+  if test no = "$lt_cv_dlopen"; then
+    enable_dlopen=no
+  else
+    enable_dlopen=yes
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS=$CPPFLAGS
+    test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS=$LDFLAGS
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS=$LIBS
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test yes = "$cross_compiling"; then :
+  lt_cv_dlopen_self=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+    if test yes = "$lt_cv_dlopen_self"; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test yes = "$cross_compiling"; then :
+  lt_cv_dlopen_self_static=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self_static=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+    fi
+
+    CPPFLAGS=$save_CPPFLAGS
+    LDFLAGS=$save_LDFLAGS
+    LIBS=$save_LIBS
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP"; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    fi
+    ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+  # Report what library types will actually be built
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+  test no = "$can_build_shared" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test yes = "$enable_shared" && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[4-9]*)
+    if test ia64 != "$host_cpu"; then
+      case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+      yes,aix,yes) ;;			# shared object as lib.so file only
+      yes,svr4,*) ;;			# shared object as lib.so archive member only
+      yes,*) enable_static=no ;;	# shared object in lib.a archive as well
+      esac
+    fi
+    ;;
+  esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+  # Make sure either enable_shared or enable_static is yes.
+  test yes = "$enable_shared" || enable_static=yes
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC=$lt_save_CC
+
+      if test -n "$CXX" && ( test no != "$CXX" &&
+    ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
+    (test g++ != "$CXX"))); then
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+  if ${ac_cv_prog_CXXCPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CXXCPP needs to be expanded
+    for CXXCPP in "$CXX -E" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+  CXXCPP=$ac_cv_prog_CXXCPP
+else
+  ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+else
+  _lt_caught_CXX_error=yes
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+archive_cmds_need_lc_CXX=no
+allow_undefined_flag_CXX=
+always_export_symbols_CXX=no
+archive_expsym_cmds_CXX=
+compiler_needs_object_CXX=no
+export_dynamic_flag_spec_CXX=
+hardcode_direct_CXX=no
+hardcode_direct_absolute_CXX=no
+hardcode_libdir_flag_spec_CXX=
+hardcode_libdir_separator_CXX=
+hardcode_minus_L_CXX=no
+hardcode_shlibpath_var_CXX=unsupported
+hardcode_automatic_CXX=no
+inherit_rpath_CXX=no
+module_cmds_CXX=
+module_expsym_cmds_CXX=
+link_all_deplibs_CXX=unknown
+old_archive_cmds_CXX=$old_archive_cmds
+reload_flag_CXX=$reload_flag
+reload_cmds_CXX=$reload_cmds
+no_undefined_flag_CXX=
+whole_archive_flag_spec_CXX=
+enable_shared_with_static_runtimes_CXX=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+objext_CXX=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_caught_CXX_error"; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+  # save warnings/boilerplate of simple test code
+  ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+  ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_CFLAGS=$CFLAGS
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  CFLAGS=$CXXFLAGS
+  compiler=$CC
+  compiler_CXX=$CC
+  func_cc_basename $compiler
+cc_basename=$func_cc_basename_result
+
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test yes = "$GXX"; then
+      lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
+    else
+      lt_prog_compiler_no_builtin_flag_CXX=
+    fi
+
+    if test yes = "$GXX"; then
+      # Set up default GNU C++ configuration
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+  withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test yes = "$GCC"; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return, which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD=$ac_prog
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test yes = "$with_gnu_ld"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS=$lt_save_ifs
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD=$ac_dir/$ac_prog
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test no != "$with_gnu_ld" && break
+	;;
+      *)
+	test yes != "$with_gnu_ld" && break
+	;;
+      esac
+    fi
+  done
+  IFS=$lt_save_ifs
+else
+  lt_cv_path_LD=$LD # Let the user override the test with a path.
+fi
+fi
+
+LD=$lt_cv_path_LD
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test yes = "$with_gnu_ld"; then
+        archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+        archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+
+        hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+        export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='$wl'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+	  $GREP 'no-whole-archive' > /dev/null; then
+          whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+        else
+          whole_archive_flag_spec_CXX=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+    ld_shlibs_CXX=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+      aix[4-9]*)
+        if test ia64 = "$host_cpu"; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # have runtime linking enabled, and use it for executables.
+          # For shared libraries, we enable/disable runtime linking
+          # depending on the kind of the shared library created -
+          # when "with_aix_soname,aix_use_runtimelinking" is:
+          # "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "aix,yes"  lib.so          shared, rtl:yes, for executables
+          #            lib.a           static archive
+          # "both,no"  lib.so.V(shr.o) shared, rtl:yes
+          #            lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a(lib.so.V) shared, rtl:no
+          # "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a           static archive
+          case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	    for ld_flag in $LDFLAGS; do
+	      case $ld_flag in
+	      *-brtl*)
+	        aix_use_runtimelinking=yes
+	        break
+	        ;;
+	      esac
+	    done
+	    if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+	      # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	      # so we don't have lib.a shared libs to link our executables.
+	      # We have to force runtime linking in this case.
+	      aix_use_runtimelinking=yes
+	      LDFLAGS="$LDFLAGS -Wl,-brtl"
+	    fi
+	    ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        archive_cmds_CXX=''
+        hardcode_direct_CXX=yes
+        hardcode_direct_absolute_CXX=yes
+        hardcode_libdir_separator_CXX=':'
+        link_all_deplibs_CXX=yes
+        file_list_spec_CXX='$wl-f,'
+        case $with_aix_soname,$aix_use_runtimelinking in
+        aix,*) ;;	# no import file
+        svr4,* | *,yes) # use import file
+          # The Import File defines what to hardcode.
+          hardcode_direct_CXX=no
+          hardcode_direct_absolute_CXX=no
+          ;;
+        esac
+
+        if test yes = "$GXX"; then
+          case $host_os in aix4.[012]|aix4.[012].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+	  collect2name=`$CC -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	    # We have reworked collect2
+	    :
+	  else
+	    # We have old collect2
+	    hardcode_direct_CXX=unsupported
+	    # It fails to find uninstalled libraries when the uninstalled
+	    # path is not listed in the libpath.  Setting hardcode_minus_L
+	    # to unsupported forces relinking
+	    hardcode_minus_L_CXX=yes
+	    hardcode_libdir_flag_spec_CXX='-L$libdir'
+	    hardcode_libdir_separator_CXX=
+	  fi
+          esac
+          shared_flag='-shared'
+	  if test yes = "$aix_use_runtimelinking"; then
+	    shared_flag=$shared_flag' $wl-G'
+	  fi
+	  # Need to ensure runtime linking is disabled for the traditional
+	  # shared library, or the linker may eventually find shared libraries
+	  # /with/ Import File - we do not want to mix them.
+	  shared_flag_aix='-shared'
+	  shared_flag_svr4='-shared $wl-G'
+        else
+          # not using gcc
+          if test ia64 = "$host_cpu"; then
+	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	  # chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+          else
+	    if test yes = "$aix_use_runtimelinking"; then
+	      shared_flag='$wl-G'
+	    else
+	      shared_flag='$wl-bM:SRE'
+	    fi
+	    shared_flag_aix='$wl-bM:SRE'
+	    shared_flag_svr4='$wl-G'
+          fi
+        fi
+
+        export_dynamic_flag_spec_CXX='$wl-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+	# export.
+        always_export_symbols_CXX=yes
+	if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          # The "-G" linker flag allows undefined symbols.
+          no_undefined_flag_CXX='-bernotok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          if test set = "${lt_cv_aix_libpath+set}"; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath__CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath__CXX"; then
+    lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath__CXX"; then
+    lt_cv_aix_libpath__CXX=/usr/lib:/lib
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath__CXX
+fi
+
+          hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath"
+
+          archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+        else
+          if test ia64 = "$host_cpu"; then
+	    hardcode_libdir_flag_spec_CXX='$wl-R $libdir:/usr/lib:/lib'
+	    allow_undefined_flag_CXX="-z nodefs"
+	    archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+          else
+	    # Determine the default libpath from the value encoded in an
+	    # empty executable.
+	    if test set = "${lt_cv_aix_libpath+set}"; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath__CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath__CXX"; then
+    lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath__CXX"; then
+    lt_cv_aix_libpath__CXX=/usr/lib:/lib
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath__CXX
+fi
+
+	    hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath"
+	    # Warning - without using the other run time loading flags,
+	    # -berok will link without error, but may produce a broken library.
+	    no_undefined_flag_CXX=' $wl-bernotok'
+	    allow_undefined_flag_CXX=' $wl-berok'
+	    if test yes = "$with_gnu_ld"; then
+	      # We only use this code for GNU lds that support --whole-archive.
+	      whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive'
+	    else
+	      # Exported symbols can be pulled into shared objects from archives
+	      whole_archive_flag_spec_CXX='$convenience'
+	    fi
+	    archive_cmds_need_lc_CXX=yes
+	    archive_expsym_cmds_CXX='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	    # -brtl affects multiple linker settings, -berok does not and is overridden later
+	    compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`'
+	    if test svr4 != "$with_aix_soname"; then
+	      # This is similar to how AIX traditionally builds its shared
+	      # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+	      archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	    fi
+	    if test aix != "$with_aix_soname"; then
+	      archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	    else
+	      # used by -dlpreopen to get the symbols
+	      archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	    fi
+	    archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$RM -r $output_objdir/$realname.d'
+          fi
+        fi
+        ;;
+
+      beos*)
+	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	  allow_undefined_flag_CXX=unsupported
+	  # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	  # support --undefined.  This deserves some investigation.  FIXME
+	  archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	else
+	  ld_shlibs_CXX=no
+	fi
+	;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+	  # FIXME: insert proper C++ library support
+	  ld_shlibs_CXX=no
+	  ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+	case $GXX,$cc_basename in
+	,cl* | no,cl*)
+	  # Native MSVC
+	  # hardcode_libdir_flag_spec is actually meaningless, as there is
+	  # no search path for DLLs.
+	  hardcode_libdir_flag_spec_CXX=' '
+	  allow_undefined_flag_CXX=unsupported
+	  always_export_symbols_CXX=yes
+	  file_list_spec_CXX='@'
+	  # Tell ltmain to make .lib files, not .a files.
+	  libext=lib
+	  # Tell ltmain to make .dll files, not .so files.
+	  shrext_cmds=.dll
+	  # FIXME: Setting linknames here is a bad hack.
+	  archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	  archive_expsym_cmds_CXX='if   test DEF = "`$SED -n     -e '\''s/^[	 ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
+              cp "$export_symbols" "$output_objdir/$soname.def";
+              echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+            else
+              $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+            fi~
+            $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+            linknames='
+	  # The linker will not automatically build a static lib if we build a DLL.
+	  # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true'
+	  enable_shared_with_static_runtimes_CXX=yes
+	  # Don't use ranlib
+	  old_postinstall_cmds_CXX='chmod 644 $oldlib'
+	  postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~
+            lt_tool_outputfile="@TOOL_OUTPUT@"~
+            case $lt_outputfile in
+              *.exe|*.EXE) ;;
+              *)
+                lt_outputfile=$lt_outputfile.exe
+                lt_tool_outputfile=$lt_tool_outputfile.exe
+                ;;
+            esac~
+            func_to_tool_file "$lt_outputfile"~
+            if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+              $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+              $RM "$lt_outputfile.manifest";
+            fi'
+	  ;;
+	*)
+	  # g++
+	  # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
+	  # as there is no search path for DLLs.
+	  hardcode_libdir_flag_spec_CXX='-L$libdir'
+	  export_dynamic_flag_spec_CXX='$wl--export-all-symbols'
+	  allow_undefined_flag_CXX=unsupported
+	  always_export_symbols_CXX=no
+	  enable_shared_with_static_runtimes_CXX=yes
+
+	  if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+	    archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    # If the export-symbols file already is a .def file, use it as
+	    # is; otherwise, prepend EXPORTS...
+	    archive_expsym_cmds_CXX='if   test DEF = "`$SED -n     -e '\''s/^[	 ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
+              cp $export_symbols $output_objdir/$soname.def;
+            else
+              echo EXPORTS > $output_objdir/$soname.def;
+              cat $export_symbols >> $output_objdir/$soname.def;
+            fi~
+            $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	  else
+	    ld_shlibs_CXX=no
+	  fi
+	  ;;
+	esac
+	;;
+      darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc_CXX=no
+  hardcode_direct_CXX=no
+  hardcode_automatic_CXX=yes
+  hardcode_shlibpath_var_CXX=unsupported
+  if test yes = "$lt_cv_ld_force_load"; then
+    whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+  else
+    whole_archive_flag_spec_CXX=''
+  fi
+  link_all_deplibs_CXX=yes
+  allow_undefined_flag_CXX=$_lt_dar_allow_undefined
+  case $cc_basename in
+     ifort*|nagfor*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test yes = "$_lt_dar_can_shared"; then
+    output_verbose_link_cmd=func_echo_all
+    archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+    module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+    archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+    module_expsym_cmds_CXX="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+       if test yes != "$lt_cv_apple_cc_single_mod"; then
+      archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
+      archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
+    fi
+
+  else
+  ld_shlibs_CXX=no
+  fi
+
+	;;
+
+      os2*)
+	hardcode_libdir_flag_spec_CXX='-L$libdir'
+	hardcode_minus_L_CXX=yes
+	allow_undefined_flag_CXX=unsupported
+	shrext_cmds=.dll
+	archive_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	  $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	  $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	  $ECHO EXPORTS >> $output_objdir/$libname.def~
+	  emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	  $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	  emximp -o $lib $output_objdir/$libname.def'
+	archive_expsym_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	  $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	  $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	  $ECHO EXPORTS >> $output_objdir/$libname.def~
+	  prefix_cmds="$SED"~
+	  if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	    prefix_cmds="$prefix_cmds -e 1d";
+	  fi~
+	  prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	  cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	  $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	  emximp -o $lib $output_objdir/$libname.def'
+	old_archive_From_new_cmds_CXX='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+	enable_shared_with_static_runtimes_CXX=yes
+	;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          ghcx*)
+	    # Green Hills C++ Compiler
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+        esac
+        ;;
+
+      freebsd2.*)
+        # C++ shared libraries reported to be fairly broken before
+	# switch to ELF
+        ld_shlibs_CXX=no
+        ;;
+
+      freebsd-elf*)
+        archive_cmds_need_lc_CXX=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        ld_shlibs_CXX=yes
+        ;;
+
+      haiku*)
+        archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+        link_all_deplibs_CXX=yes
+        ;;
+
+      hpux9*)
+        hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir'
+        hardcode_libdir_separator_CXX=:
+        export_dynamic_flag_spec_CXX='$wl-E'
+        hardcode_direct_CXX=yes
+        hardcode_minus_L_CXX=yes # Not in the search PATH,
+				             # but as the default
+				             # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            ld_shlibs_CXX=no
+            ;;
+          aCC*)
+            archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            ;;
+          *)
+            if test yes = "$GXX"; then
+              archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              ld_shlibs_CXX=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test no = "$with_gnu_ld"; then
+	  hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir'
+	  hardcode_libdir_separator_CXX=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+	      export_dynamic_flag_spec_CXX='$wl-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            hardcode_direct_CXX=no
+            hardcode_shlibpath_var_CXX=no
+            ;;
+          *)
+            hardcode_direct_CXX=yes
+            hardcode_direct_absolute_CXX=yes
+            hardcode_minus_L_CXX=yes # Not in the search PATH,
+					         # but as the default
+					         # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          aCC*)
+	    case $host_cpu in
+	      hppa*64*)
+	        archive_cmds_CXX='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      ia64*)
+	        archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      *)
+	        archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	    esac
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+          *)
+	    if test yes = "$GXX"; then
+	      if test no = "$with_gnu_ld"; then
+	        case $host_cpu in
+	          hppa*64*)
+	            archive_cmds_CXX='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          ia64*)
+	            archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          *)
+	            archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	        esac
+	      fi
+	    else
+	      # FIXME: insert proper C++ library support
+	      ld_shlibs_CXX=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      interix[3-9]*)
+	hardcode_direct_CXX=no
+	hardcode_shlibpath_var_CXX=no
+	hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	export_dynamic_flag_spec_CXX='$wl-E'
+	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+	# Instead, shared libraries are loaded at an image base (0x10000000 by
+	# default) and relocated if they conflict, which is a slow very memory
+	# consuming and fragmenting process.  To avoid this, we pick a random,
+	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+	archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	archive_expsym_cmds_CXX='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+	    # SGI C++
+	    archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    if test yes = "$GXX"; then
+	      if test no = "$with_gnu_ld"; then
+	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	      else
+	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
+	      fi
+	    fi
+	    link_all_deplibs_CXX=yes
+	    ;;
+        esac
+        hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+        hardcode_libdir_separator_CXX=:
+        inherit_rpath_CXX=yes
+        ;;
+
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+	    hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	    export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	    old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+	    ;;
+	  icpc* | ecpc* )
+	    # Intel C++
+	    with_gnu_ld=yes
+	    # version 8.0 and above of icpc choke on multiply defined symbols
+	    # if we add $predep_objects and $postdep_objects, however 7.1 and
+	    # earlier do not add the objects themselves.
+	    case `$CC -V 2>&1` in
+	      *"Version 7."*)
+	        archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+		archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	      *)  # Version 8.0 or newer
+	        tmp_idyn=
+	        case $host_cpu in
+		  ia64*) tmp_idyn=' -i_dynamic';;
+		esac
+	        archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+		archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	    esac
+	    archive_cmds_need_lc_CXX=no
+	    hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	    export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+	    whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive'
+	    ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+	    case `$CC -V` in
+	    *pgCC\ [1-5].* | *pgcpp\ [1-5].*)
+	      prelink_cmds_CXX='tpldir=Template.dir~
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+               compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+	      old_archive_cmds_CXX='tpldir=Template.dir~
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+                $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+                $RANLIB $oldlib'
+	      archive_cmds_CXX='tpldir=Template.dir~
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	      archive_expsym_cmds_CXX='tpldir=Template.dir~
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+	      ;;
+	    *) # Version 6 and above use weak symbols
+	      archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	      archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+	      ;;
+	    esac
+
+	    hardcode_libdir_flag_spec_CXX='$wl--rpath $wl$libdir'
+	    export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+	    whole_archive_flag_spec_CXX='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+            ;;
+	  cxx*)
+	    # Compaq C++
+	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	    archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname  -o $lib $wl-retain-symbols-file $wl$export_symbols'
+
+	    runpath_var=LD_RUN_PATH
+	    hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+	    hardcode_libdir_separator_CXX=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+	    ;;
+	  xl* | mpixl* | bgxl*)
+	    # IBM XL 8.0 on PPC, with GNU ld
+	    hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+	    export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+	    archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	    if test yes = "$supports_anon_versioning"; then
+	      archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~
+                cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+                echo "local: *; };" >> $output_objdir/$libname.ver~
+                $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+	    fi
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      no_undefined_flag_CXX=' -zdefs'
+	      archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      archive_expsym_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
+	      hardcode_libdir_flag_spec_CXX='-R$libdir'
+	      whole_archive_flag_spec_CXX='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	      compiler_needs_object_CXX=yes
+
+	      # Not sure whether something based on
+	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	      # would be better.
+	      output_verbose_link_cmd='func_echo_all'
+
+	      # Archives containing C++ object files must be created using
+	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	      # necessary to make sure instantiated templates are included
+	      # in the archive.
+	      old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+	;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+	  *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+	esac
+	;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	  archive_cmds_CXX='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+	  wlarc=
+	  hardcode_libdir_flag_spec_CXX='-R$libdir'
+	  hardcode_direct_CXX=yes
+	  hardcode_shlibpath_var_CXX=no
+	fi
+	# Workaround some broken pre-1.5 toolchains
+	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+	;;
+
+      *nto* | *qnx*)
+        ld_shlibs_CXX=yes
+	;;
+
+      openbsd* | bitrig*)
+	if test -f /usr/libexec/ld.so; then
+	  hardcode_direct_CXX=yes
+	  hardcode_shlibpath_var_CXX=no
+	  hardcode_direct_absolute_CXX=yes
+	  archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+	  hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
+	    archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
+	    export_dynamic_flag_spec_CXX='$wl-E'
+	    whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+	  fi
+	  output_verbose_link_cmd=func_echo_all
+	else
+	  ld_shlibs_CXX=no
+	fi
+	;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	    hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	    hardcode_libdir_separator_CXX=:
+
+	    # Archives containing C++ object files must be created using
+	    # the KAI C++ compiler.
+	    case $host in
+	      osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;;
+	      *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;;
+	    esac
+	    ;;
+          RCC*)
+	    # Rational C++ 2.4.1
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          cxx*)
+	    case $host in
+	      osf3*)
+	        allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*'
+	        archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	        hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+		;;
+	      *)
+	        allow_undefined_flag_CXX=' -expect_unresolved \*'
+	        archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	        archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+                  echo "-hidden">> $lib.exp~
+                  $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
+                  $RM $lib.exp'
+	        hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+		;;
+	    esac
+
+	    hardcode_libdir_separator_CXX=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+	  *)
+	    if test yes,no = "$GXX,$with_gnu_ld"; then
+	      allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*'
+	      case $host in
+	        osf3*)
+	          archive_cmds_CXX='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+		  ;;
+	        *)
+	          archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+		  ;;
+	      esac
+
+	      hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+	      hardcode_libdir_separator_CXX=:
+
+	      # Commands to make compiler produce verbose output that lists
+	      # what "hidden" libraries, object files and flags are used when
+	      # linking a shared library.
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+	    else
+	      # FIXME: insert proper C++ library support
+	      ld_shlibs_CXX=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.x
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          lcc*)
+	    # Lucid
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+            archive_cmds_need_lc_CXX=yes
+	    no_undefined_flag_CXX=' -zdefs'
+	    archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+              $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	    hardcode_libdir_flag_spec_CXX='-R$libdir'
+	    hardcode_shlibpath_var_CXX=no
+	    case $host_os in
+	      solaris2.[0-5] | solaris2.[0-5].*) ;;
+	      *)
+		# The compiler driver will combine and reorder linker options,
+		# but understands '-z linker_flag'.
+	        # Supported since Solaris 2.6 (maybe 2.5.1?)
+		whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract'
+	        ;;
+	    esac
+	    link_all_deplibs_CXX=yes
+
+	    output_verbose_link_cmd='func_echo_all'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+	    ;;
+          gcx*)
+	    # Green Hills C++ Compiler
+	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+
+	    # The C++ compiler must be used to create the archive.
+	    old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    # GNU C++ compiler with Solaris linker
+	    if test yes,no = "$GXX,$with_gnu_ld"; then
+	      no_undefined_flag_CXX=' $wl-z ${wl}defs'
+	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+	        archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+                  $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      else
+	        # g++ 2.7 appears to require '-G' NOT '-shared' on this
+	        # platform.
+	        archive_cmds_CXX='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+	        archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+                  $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      fi
+
+	      hardcode_libdir_flag_spec_CXX='$wl-R $wl$libdir'
+	      case $host_os in
+		solaris2.[0-5] | solaris2.[0-5].*) ;;
+		*)
+		  whole_archive_flag_spec_CXX='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+		  ;;
+	      esac
+	    fi
+	    ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag_CXX='$wl-z,text'
+      archive_cmds_need_lc_CXX=no
+      hardcode_shlibpath_var_CXX=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+	  archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+	# Note: We CANNOT use -z defs as we might desire, because we do not
+	# link with -lc, and that would cause any symbols used from libc to
+	# always be unresolved, which means just about no library would
+	# ever link correctly.  If we're not using GNU ld we use -z text
+	# though, which does catch some bad symbols but isn't as heavy-handed
+	# as -z defs.
+	no_undefined_flag_CXX='$wl-z,text'
+	allow_undefined_flag_CXX='$wl-z,nodefs'
+	archive_cmds_need_lc_CXX=no
+	hardcode_shlibpath_var_CXX=no
+	hardcode_libdir_flag_spec_CXX='$wl-R,$libdir'
+	hardcode_libdir_separator_CXX=':'
+	link_all_deplibs_CXX=yes
+	export_dynamic_flag_spec_CXX='$wl-Bexport'
+	runpath_var='LD_RUN_PATH'
+
+	case $cc_basename in
+          CC*)
+	    archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~
+              '"$old_archive_cmds_CXX"
+	    reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~
+              '"$reload_cmds_CXX"
+	    ;;
+	  *)
+	    archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+	    # NonStop-UX NCC 3.20
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+    esac
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+    test no = "$ld_shlibs_CXX" && can_build_shared=no
+
+    GCC_CXX=$GXX
+    LD_CXX=$LD
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    # Dependencies to place before and after the object being linked:
+predep_objects_CXX=
+postdep_objects_CXX=
+predeps_CXX=
+postdeps_CXX=
+compiler_lib_search_path_CXX=
+
+cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case $prev$p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test x-L = "$p" ||
+          test x-R = "$p"; then
+	 prev=$p
+	 continue
+       fi
+
+       # Expand the sysroot to ease extracting the directories later.
+       if test -z "$prev"; then
+         case $p in
+         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+         esac
+       fi
+       case $p in
+       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+       esac
+       if test no = "$pre_test_object_deps_done"; then
+	 case $prev in
+	 -L | -R)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$compiler_lib_search_path_CXX"; then
+	     compiler_lib_search_path_CXX=$prev$p
+	   else
+	     compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} $prev$p"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$postdeps_CXX"; then
+	   postdeps_CXX=$prev$p
+	 else
+	   postdeps_CXX="${postdeps_CXX} $prev$p"
+	 fi
+       fi
+       prev=
+       ;;
+
+    *.lto.$objext) ;; # Ignore GCC LTO objects
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test no = "$pre_test_object_deps_done"; then
+	 if test -z "$predep_objects_CXX"; then
+	   predep_objects_CXX=$p
+	 else
+	   predep_objects_CXX="$predep_objects_CXX $p"
+	 fi
+       else
+	 if test -z "$postdep_objects_CXX"; then
+	   postdep_objects_CXX=$p
+	 else
+	   postdep_objects_CXX="$postdep_objects_CXX $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling CXX test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+case $host_os in
+interix[3-9]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  predep_objects_CXX=
+  postdep_objects_CXX=
+  postdeps_CXX=
+  ;;
+esac
+
+
+case " $postdeps_CXX " in
+*" -lc "*) archive_cmds_need_lc_CXX=no ;;
+esac
+ compiler_lib_search_dirs_CXX=
+if test -n "${compiler_lib_search_path_CXX}"; then
+ compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | $SED -e 's! -L! !g' -e 's!^ !!'`
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    lt_prog_compiler_wl_CXX=
+lt_prog_compiler_pic_CXX=
+lt_prog_compiler_static_CXX=
+
+
+  # C++ specific cases for pic, static, wl, etc.
+  if test yes = "$GXX"; then
+    lt_prog_compiler_wl_CXX='-Wl,'
+    lt_prog_compiler_static_CXX='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test ia64 = "$host_cpu"; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static_CXX='-Bstatic'
+      fi
+      lt_prog_compiler_pic_CXX='-fPIC'
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic_CXX='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the '-m68020' flag to GCC prevents building anything better,
+            # like '-m68040'.
+            lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+      case $host_os in
+      os2*)
+	lt_prog_compiler_static_CXX='$wl-static'
+	;;
+      esac
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic_CXX='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      lt_prog_compiler_pic_CXX=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static_CXX=
+      ;;
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic_CXX=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	;;
+      *)
+	lt_prog_compiler_pic_CXX='-fPIC'
+	;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic_CXX='-fPIC -shared'
+      ;;
+    *)
+      lt_prog_compiler_pic_CXX='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[4-9]*)
+	# All AIX code is PIC.
+	if test ia64 = "$host_cpu"; then
+	  # AIX 5 now supports IA64 processor
+	  lt_prog_compiler_static_CXX='-Bstatic'
+	else
+	  lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      mingw* | cygwin* | os2* | pw32* | cegcc*)
+	# This hack is so that the source file can tell whether it is being
+	# built for inclusion in a dll (and should export symbols for example).
+	lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='$wl-a ${wl}archive'
+	    if test ia64 != "$host_cpu"; then
+	      lt_prog_compiler_pic_CXX='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='$wl-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      lt_prog_compiler_pic_CXX='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    lt_prog_compiler_wl_CXX='--backend -Wl,'
+	    lt_prog_compiler_pic_CXX='-fPIC'
+	    ;;
+	  ecpc* )
+	    # old Intel C++ for x86_64, which still supported -KPIC.
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-static'
+	    ;;
+	  icpc* )
+	    # Intel C++, used to be incompatible with GCC.
+	    # ICC 10 doesn't accept -KPIC any more.
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-fPIC'
+	    lt_prog_compiler_static_CXX='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-fpic'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    lt_prog_compiler_pic_CXX=
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    ;;
+	  xlc* | xlC* | bgxl[cC]* | mpixl[cC]*)
+	    # IBM XL 8.0, 9.0 on PPC and BlueGene
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-qpic'
+	    lt_prog_compiler_static_CXX='-qstaticlink'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      lt_prog_compiler_pic_CXX='-KPIC'
+	      lt_prog_compiler_static_CXX='-Bstatic'
+	      lt_prog_compiler_wl_CXX='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    lt_prog_compiler_pic_CXX='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd* | netbsdelf*-gnu)
+	;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        lt_prog_compiler_pic_CXX='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    lt_prog_compiler_wl_CXX='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    lt_prog_compiler_pic_CXX=
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    lt_prog_compiler_wl_CXX='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    lt_prog_compiler_pic_CXX='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    lt_prog_compiler_pic_CXX='-pic'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	lt_prog_compiler_can_build_shared_CXX=no
+	;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms that do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic_CXX=
+    ;;
+  *)
+    lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC"
+    ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; }
+lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works_CXX=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"  ## exclude from sc_useless_quotes_in_assignment
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works_CXX=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_pic_works_CXX"; then
+    case $lt_prog_compiler_pic_CXX in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
+     esac
+else
+    lt_prog_compiler_pic_CXX=
+     lt_prog_compiler_can_build_shared_CXX=no
+fi
+
+fi
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works_CXX=no
+   save_LDFLAGS=$LDFLAGS
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works_CXX=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works_CXX=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_static_works_CXX"; then
+    :
+else
+    lt_prog_compiler_static_CXX=
+fi
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o_CXX=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o_CXX=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o_CXX=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o_CXX=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+
+hard_links=nottested
+if test no = "$lt_cv_prog_compiler_c_o_CXX" && test no != "$need_locks"; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test no = "$hard_links"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  case $host_os in
+  aix[4-9]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+    # Without the "-l" option, or with the "-B" option, AIX nm treats
+    # weak defined symbols like other global defined symbols, whereas
+    # GNU nm marks them as "W".
+    # While the 'weak' keyword is ignored in the Export File, we need
+    # it in the Import File for the 'aix-soname' feature, so we have
+    # to replace the "-B" option with "-P" for AIX nm.
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+    else
+      export_symbols_cmds_CXX='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    export_symbols_cmds_CXX=$ltdll_cmds
+    ;;
+  cygwin* | mingw* | cegcc*)
+    case $cc_basename in
+    cl*)
+      exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+      ;;
+    *)
+      export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+      exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+      ;;
+    esac
+    ;;
+  linux* | k*bsd*-gnu | gnu*)
+    link_all_deplibs_CXX=no
+    ;;
+  *)
+    export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+    ;;
+  esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+test no = "$ld_shlibs_CXX" && can_build_shared=no
+
+with_gnu_ld_CXX=$with_gnu_ld
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_CXX" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc_CXX=yes
+
+  if test yes,yes = "$GCC,$enable_shared"; then
+    case $archive_cmds_CXX in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$lt_prog_compiler_wl_CXX
+	  pic_flag=$lt_prog_compiler_pic_CXX
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$allow_undefined_flag_CXX
+	  allow_undefined_flag_CXX=
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	  then
+	    lt_cv_archive_cmds_need_lc_CXX=no
+	  else
+	    lt_cv_archive_cmds_need_lc_CXX=yes
+	  fi
+	  allow_undefined_flag_CXX=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; }
+      archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=.so
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='$libname$release$shared_ext$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test ia64 = "$host_cpu"; then
+    # AIX 5 supports IA64
+    library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line '#! .'.  This would cause the generated library to
+    # depend on '.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # Using Import Files as archive members, it is possible to support
+    # filename-based versioning of shared library archives on AIX. While
+    # this would work for both with and without runtime linking, it will
+    # prevent static linking of such archives. So we do filename-based
+    # shared library versioning with .so extension only, which is used
+    # when both runtime linking and shared linking is enabled.
+    # Unfortunately, runtime linking may impact performance, so we do
+    # not want this to be the default eventually. Also, we use the
+    # versioned .so libs for executables only if there is the -brtl
+    # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+    # To allow for filename-based versioning support, we need to create
+    # libNAME.so.V as an archive file, containing:
+    # *) an Import File, referring to the versioned filename of the
+    #    archive as well as the shared archive member, telling the
+    #    bitwidth (32 or 64) of that shared object, and providing the
+    #    list of exported symbols of that shared object, eventually
+    #    decorated with the 'weak' keyword
+    # *) the shared object with the F_LOADONLY flag set, to really avoid
+    #    it being seen by the linker.
+    # At run time we better use the real file rather than another symlink,
+    # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+    case $with_aix_soname,$aix_use_runtimelinking in
+    # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    aix,yes) # traditional libtool
+      dynamic_linker='AIX unversionable lib.so'
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      ;;
+    aix,no) # traditional AIX only
+      dynamic_linker='AIX lib.a(lib.so.V)'
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      ;;
+    svr4,*) # full svr4 only
+      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,yes) # both, prefer svr4
+      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # unpreferred sharedlib libNAME.a needs extra handling
+      postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+      postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,no) # both, prefer aix
+      dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)"
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+      postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+      postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+      ;;
+    esac
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='$libname$shared_ext'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+    library_names_spec='$libname.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec=$LIB
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$major$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[23].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      soname_spec='$libname$release$shared_ext$major'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    if test 32 = "$HPUX_IA64_MODE"; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux32
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux64
+    fi
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[3-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test yes = "$lt_cv_prog_gnu_ld"; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+  sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+linux*android*)
+  version_type=none # Android doesn't support versioned libraries.
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext'
+  soname_spec='$libname$release$shared_ext'
+  finish_cmds=
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  dynamic_linker='Android linker'
+  # Don't embed -rpath directories since the linker doesn't support them.
+  hardcode_libdir_flag_spec_CXX='-L$libdir'
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \
+	 LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\""
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+  lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Ideally, we could use ldconfig to report *all* directores which are
+  # searched for libraries, however this is still not possible.  Aside from not
+  # being certain /sbin/ldconfig is available, command
+  # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+  # even though it is searched at run-time.  Try to do the best guess by
+  # appending ld.so.conf contents (and includes) to the search path.
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsdelf*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='NetBSD ld.elf_so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd* | bitrig*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec=/usr/lib
+  need_lib_prefix=no
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    need_version=no
+  else
+    need_version=yes
+  fi
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+os2*)
+  libname_spec='$name'
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
+  need_lib_prefix=no
+  # OS/2 can only load a DLL with a base name of 8 characters or less.
+  soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+    v=$($ECHO $release$versuffix | tr -d .-);
+    n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+    $ECHO $n$v`$shared_ext'
+  library_names_spec='${libname}_dll.$libext'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=BEGINLIBPATH
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  postinstall_cmds='base_file=`basename \$file`~
+    dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+    dldir=$destdir/`dirname \$dlpath`~
+    test -d \$dldir || mkdir -p \$dldir~
+    $install_prog $dir/$dlname \$dldir/$dlname~
+    chmod a+x \$dldir/$dlname~
+    if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+      eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+    fi'
+  postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+    dlpath=$dir/\$dldll~
+    $RM \$dlpath'
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test yes = "$with_gnu_ld"; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec; then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+    soname_spec='$libname$shared_ext.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=sco
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test yes = "$with_gnu_ld"; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test no = "$dynamic_linker" && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test yes = "$GCC"; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+  sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
+fi
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+  sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
+fi
+
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action_CXX=
+if test -n "$hardcode_libdir_flag_spec_CXX" ||
+   test -n "$runpath_var_CXX" ||
+   test yes = "$hardcode_automatic_CXX"; then
+
+  # We can hardcode non-existent directories.
+  if test no != "$hardcode_direct_CXX" &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" &&
+     test no != "$hardcode_minus_L_CXX"; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action_CXX=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action_CXX=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action_CXX=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5
+$as_echo "$hardcode_action_CXX" >&6; }
+
+if test relink = "$hardcode_action_CXX" ||
+   test yes = "$inherit_rpath_CXX"; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test yes = "$shlibpath_overrides_runpath" ||
+     test no = "$enable_shared"; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test yes != "$_lt_caught_CXX_error"
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+
+# Extract the first word of "perl", so it can be a program name with args.
+set dummy perl; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PERL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$PERL"; then
+  ac_cv_prog_PERL="$PERL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_PERL="perl"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+PERL=$ac_cv_prog_PERL
+if test -n "$PERL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5
+$as_echo "$PERL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# Extract the first word of "pdflatex", so it can be a program name with args.
+set dummy pdflatex; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PDFLATEX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$PDFLATEX"; then
+  ac_cv_prog_PDFLATEX="$PDFLATEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_PDFLATEX="pdflatex"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+PDFLATEX=$ac_cv_prog_PDFLATEX
+if test -n "$PDFLATEX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PDFLATEX" >&5
+$as_echo "$PDFLATEX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# Extract the first word of "pod2html", so it can be a program name with args.
+set dummy pod2html; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_POD2HTML+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$POD2HTML"; then
+  ac_cv_prog_POD2HTML="$POD2HTML" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_POD2HTML="pod2html"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+POD2HTML=$ac_cv_prog_POD2HTML
+if test -n "$POD2HTML"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $POD2HTML" >&5
+$as_echo "$POD2HTML" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+ if test -n "$PERL" -a -n "$PDFLATEX" -a -n "$POD2HTML"; then
+  GENERATE_DOC_TRUE=
+  GENERATE_DOC_FALSE='#'
+else
+  GENERATE_DOC_TRUE='#'
+  GENERATE_DOC_FALSE=
+fi
+
+
+# ------ AX CREATE STDINT H -------------------------------------
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdint types" >&5
+$as_echo_n "checking for stdint types... " >&6; }
+ac_stdint_h=`echo include/isl/stdint.h`
+# try to shortcircuit - if the default include path of the compiler
+# can find a "stdint.h" header then we assume that all compilers can.
+if ${ac_cv_header_stdint_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+old_CXXFLAGS="$CXXFLAGS" ; CXXFLAGS=""
+old_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS=""
+old_CFLAGS="$CFLAGS"     ; CFLAGS=""
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdint.h>
+int
+main ()
+{
+int_least32_t v = 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_stdint_result="(assuming C99 compatible system)"
+ ac_cv_header_stdint_t="stdint.h";
+else
+  ac_cv_header_stdint_t=""
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+if test "$GCC" = "yes" && test ".$ac_cv_header_stdint_t" = "."; then
+CFLAGS="-std=c99"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdint.h>
+int
+main ()
+{
+int_least32_t v = 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: your GCC compiler has a defunct stdint.h for its default-mode" >&5
+$as_echo "$as_me: WARNING: your GCC compiler has a defunct stdint.h for its default-mode" >&2;}
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+CXXFLAGS="$old_CXXFLAGS"
+CPPFLAGS="$old_CPPFLAGS"
+CFLAGS="$old_CFLAGS"
+fi
+
+
+v="... $ac_cv_header_stdint_h"
+if test "$ac_stdint_h" = "stdint.h" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: (are you sure you want them in ./stdint.h?)" >&5
+$as_echo "(are you sure you want them in ./stdint.h?)" >&6; }
+elif test "$ac_stdint_h" = "inttypes.h" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: (are you sure you want them in ./inttypes.h?)" >&5
+$as_echo "(are you sure you want them in ./inttypes.h?)" >&6; }
+elif test "_$ac_cv_header_stdint_t" = "_" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: (putting them into $ac_stdint_h)$v" >&5
+$as_echo "(putting them into $ac_stdint_h)$v" >&6; }
+else
+ ac_cv_header_stdint="$ac_cv_header_stdint_t"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdint (shortcircuit)" >&5
+$as_echo "$ac_cv_header_stdint (shortcircuit)" >&6; }
+fi
+
+if test "_$ac_cv_header_stdint_t" = "_" ; then # can not shortcircuit..
+
+
+inttype_headers=`echo  | sed -e 's/,/ /g'`
+
+ac_cv_stdint_result="(no helpful system typedefs seen)"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdint uintptr_t" >&5
+$as_echo_n "checking for stdint uintptr_t... " >&6; }
+if ${ac_cv_header_stdint_x+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+ ac_cv_header_stdint_x="" # the 1997 typedefs (inttypes.h)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: (..)" >&5
+$as_echo "(..)" >&6; }
+  for i in    stdint.h inttypes.h sys/inttypes.h $inttype_headers
+  do
+   unset ac_cv_type_uintptr_t
+   unset ac_cv_type_uint64_t
+   ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "#include <$i>
+"
+if test "x$ac_cv_type_uintptr_t" = xyes; then :
+  ac_cv_header_stdint_x=$i
+else
+  continue
+fi
+
+   ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "#include<$i>
+"
+if test "x$ac_cv_type_uint64_t" = xyes; then :
+  and64="/uint64_t"
+else
+  and64=""
+fi
+
+   ac_cv_stdint_result="(seen uintptr_t$and64 in $i)"
+ break
+  done
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdint uintptr_t" >&5
+$as_echo_n "checking for stdint uintptr_t... " >&6; }
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdint_x" >&5
+$as_echo "$ac_cv_header_stdint_x" >&6; }
+
+
+if test "_$ac_cv_header_stdint_x" = "_" ; then
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdint uint32_t" >&5
+$as_echo_n "checking for stdint uint32_t... " >&6; }
+if ${ac_cv_header_stdint_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+ ac_cv_header_stdint_o="" # the 1995 typedefs (sys/inttypes.h)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: (..)" >&5
+$as_echo "(..)" >&6; }
+  for i in    inttypes.h sys/inttypes.h stdint.h $inttype_headers
+  do
+   unset ac_cv_type_uint32_t
+   unset ac_cv_type_uint64_t
+   ac_fn_c_check_type "$LINENO" "uint32_t" "ac_cv_type_uint32_t" "#include <$i>
+"
+if test "x$ac_cv_type_uint32_t" = xyes; then :
+  ac_cv_header_stdint_o=$i
+else
+  continue
+fi
+
+   ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "#include<$i>
+"
+if test "x$ac_cv_type_uint64_t" = xyes; then :
+  and64="/uint64_t"
+else
+  and64=""
+fi
+
+   ac_cv_stdint_result="(seen uint32_t$and64 in $i)"
+ break
+   break;
+  done
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdint uint32_t" >&5
+$as_echo_n "checking for stdint uint32_t... " >&6; }
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdint_o" >&5
+$as_echo "$ac_cv_header_stdint_o" >&6; }
+
+fi
+
+if test "_$ac_cv_header_stdint_x" = "_" ; then
+if test "_$ac_cv_header_stdint_o" = "_" ; then
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdint u_int32_t" >&5
+$as_echo_n "checking for stdint u_int32_t... " >&6; }
+if ${ac_cv_header_stdint_u+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+ ac_cv_header_stdint_u="" # the BSD typedefs (sys/types.h)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: (..)" >&5
+$as_echo "(..)" >&6; }
+  for i in    sys/types.h inttypes.h sys/inttypes.h $inttype_headers ; do
+   unset ac_cv_type_u_int32_t
+   unset ac_cv_type_u_int64_t
+   ac_fn_c_check_type "$LINENO" "u_int32_t" "ac_cv_type_u_int32_t" "#include <$i>
+"
+if test "x$ac_cv_type_u_int32_t" = xyes; then :
+  ac_cv_header_stdint_u=$i
+else
+  continue
+fi
+
+   ac_fn_c_check_type "$LINENO" "u_int64_t" "ac_cv_type_u_int64_t" "#include<$i>
+"
+if test "x$ac_cv_type_u_int64_t" = xyes; then :
+  and64="/u_int64_t"
+else
+  and64=""
+fi
+
+   ac_cv_stdint_result="(seen u_int32_t$and64 in $i)"
+ break
+   break;
+  done
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdint u_int32_t" >&5
+$as_echo_n "checking for stdint u_int32_t... " >&6; }
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdint_u" >&5
+$as_echo "$ac_cv_header_stdint_u" >&6; }
+
+fi fi
+
+if test "_$ac_cv_header_stdint_x" = "_" ; then
+   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdint datatype model" >&5
+$as_echo_n "checking for stdint datatype model... " >&6; }
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: (..)" >&5
+$as_echo "(..)" >&6; }
+
+   # The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char" >&5
+$as_echo_n "checking size of char... " >&6; }
+if ${ac_cv_sizeof_char+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char))" "ac_cv_sizeof_char"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_char" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (char)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_char=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char" >&5
+$as_echo "$ac_cv_sizeof_char" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_CHAR $ac_cv_sizeof_char
+_ACEOF
+
+
+   # The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5
+$as_echo_n "checking size of short... " >&6; }
+if ${ac_cv_sizeof_short+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_short" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (short)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_short=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5
+$as_echo "$ac_cv_sizeof_short" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SHORT $ac_cv_sizeof_short
+_ACEOF
+
+
+   # The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5
+$as_echo_n "checking size of int... " >&6; }
+if ${ac_cv_sizeof_int+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_int" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (int)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_int=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5
+$as_echo "$ac_cv_sizeof_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+_ACEOF
+
+
+   # The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
+$as_echo_n "checking size of long... " >&6; }
+if ${ac_cv_sizeof_long+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_long" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (long)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_long=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5
+$as_echo "$ac_cv_sizeof_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG $ac_cv_sizeof_long
+_ACEOF
+
+
+   # The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void*" >&5
+$as_echo_n "checking size of void*... " >&6; }
+if ${ac_cv_sizeof_voidp+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void*))" "ac_cv_sizeof_voidp"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_voidp" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (void*)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_voidp=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_voidp" >&5
+$as_echo "$ac_cv_sizeof_voidp" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_VOIDP $ac_cv_sizeof_voidp
+_ACEOF
+
+
+   ac_cv_char_data_model=""
+   ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_char"
+   ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_short"
+   ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_int"
+   ac_cv_long_data_model=""
+   ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_int"
+   ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_long"
+   ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_voidp"
+   { $as_echo "$as_me:${as_lineno-$LINENO}: checking data model" >&5
+$as_echo_n "checking data model... " >&6; }
+   case "$ac_cv_char_data_model/$ac_cv_long_data_model" in
+    122/242)     ac_cv_data_model="IP16"  ; n="standard 16bit machine" ;;
+    122/244)     ac_cv_data_model="LP32"  ; n="standard 32bit machine" ;;
+    122/*)       ac_cv_data_model="i16"   ; n="unusual int16 model" ;;
+    124/444)     ac_cv_data_model="ILP32" ; n="standard 32bit unixish" ;;
+    124/488)     ac_cv_data_model="LP64"  ; n="standard 64bit unixish" ;;
+    124/448)     ac_cv_data_model="LLP64" ; n="unusual 64bit unixish" ;;
+    124/*)       ac_cv_data_model="i32"   ; n="unusual int32 model" ;;
+    128/888)     ac_cv_data_model="ILP64" ; n="unusual 64bit numeric" ;;
+    128/*)       ac_cv_data_model="i64"   ; n="unusual int64 model" ;;
+    222/*2)      ac_cv_data_model="DSP16" ; n="strict 16bit dsptype" ;;
+    333/*3)      ac_cv_data_model="DSP24" ; n="strict 24bit dsptype" ;;
+    444/*4)      ac_cv_data_model="DSP32" ; n="strict 32bit dsptype" ;;
+    666/*6)      ac_cv_data_model="DSP48" ; n="strict 48bit dsptype" ;;
+    888/*8)      ac_cv_data_model="DSP64" ; n="strict 64bit dsptype" ;;
+    222/*|333/*|444/*|666/*|888/*) :
+                 ac_cv_data_model="iDSP"  ; n="unusual dsptype" ;;
+     *)          ac_cv_data_model="none"  ; n="very unusual model" ;;
+   esac
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_data_model ($ac_cv_long_data_model, $n)" >&5
+$as_echo "$ac_cv_data_model ($ac_cv_long_data_model, $n)" >&6; }
+
+fi
+
+if test "_$ac_cv_header_stdint_x" != "_" ; then
+   ac_cv_header_stdint="$ac_cv_header_stdint_x"
+elif  test "_$ac_cv_header_stdint_o" != "_" ; then
+   ac_cv_header_stdint="$ac_cv_header_stdint_o"
+elif  test "_$ac_cv_header_stdint_u" != "_" ; then
+   ac_cv_header_stdint="$ac_cv_header_stdint_u"
+else
+   ac_cv_header_stdint="stddef.h"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for extra inttypes in chosen header" >&5
+$as_echo_n "checking for extra inttypes in chosen header... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ($ac_cv_header_stdint)" >&5
+$as_echo "($ac_cv_header_stdint)" >&6; }
+unset ac_cv_type_int_least32_t
+unset ac_cv_type_int_fast32_t
+ac_fn_c_check_type "$LINENO" "int_least32_t" "ac_cv_type_int_least32_t" "#include <$ac_cv_header_stdint>
+"
+if test "x$ac_cv_type_int_least32_t" = xyes; then :
+
+fi
+
+ac_fn_c_check_type "$LINENO" "int_fast32_t" "ac_cv_type_int_fast32_t" "#include<$ac_cv_header_stdint>
+"
+if test "x$ac_cv_type_int_fast32_t" = xyes; then :
+
+fi
+
+ac_fn_c_check_type "$LINENO" "intmax_t" "ac_cv_type_intmax_t" "#include <$ac_cv_header_stdint>
+"
+if test "x$ac_cv_type_intmax_t" = xyes; then :
+
+fi
+
+
+fi # shortcircut to system "stdint.h"
+# ------------------ PREPARE VARIABLES ------------------------------
+if test "$GCC" = "yes" ; then
+ac_cv_stdint_message="using gnu compiler "`$CC --version | head -1`
+else
+ac_cv_stdint_message="using $CC"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: make use of $ac_cv_header_stdint in $ac_stdint_h $ac_cv_stdint_result" >&5
+$as_echo "make use of $ac_cv_header_stdint in $ac_stdint_h $ac_cv_stdint_result" >&6; }
+
+# ----------------- DONE inttypes.h checks START header -------------
+ac_config_commands="$ac_config_commands $ac_stdint_h"
+
+
+
+
+# Check whether --with-int was given.
+if test "${with_int+set}" = set; then :
+  withval=$with_int;
+else
+  with_int=gmp
+fi
+
+case "$with_int" in
+gmp|imath|imath-32)
+	;;
+*)
+	as_fn_error $? "bad value ${withval} for --with-int (use gmp, imath or imath-32)" "$LINENO" 5
+esac
+
+
+
+
+case "$with_int" in
+gmp)
+
+
+$as_echo "#define USE_GMP_FOR_MP /**/" >>confdefs.h
+
+
+
+
+# Check whether --with-gmp was given.
+if test "${with_gmp+set}" = set; then :
+  withval=$with_gmp;
+fi
+
+case "system" in
+system|build)
+
+# Check whether --with-gmp_prefix was given.
+if test "${with_gmp_prefix+set}" = set; then :
+  withval=$with_gmp_prefix;
+fi
+
+
+# Check whether --with-gmp_exec_prefix was given.
+if test "${with_gmp_exec_prefix+set}" = set; then :
+  withval=$with_gmp_exec_prefix;
+fi
+
+esac
+
+# Check whether --with-gmp_builddir was given.
+if test "${with_gmp_builddir+set}" = set; then :
+  withval=$with_gmp_builddir;
+fi
+
+if test "x$with_gmp_prefix" != "x" -a "x$with_gmp_exec_prefix" = "x"; then
+	with_gmp_exec_prefix=$with_gmp_prefix
+fi
+if test "x$with_gmp_prefix" != "x" -o "x$with_gmp_exec_prefix" != "x"; then
+	if test "x$with_gmp" != "x" -a "x$with_gmp" != "xyes" -a "x$with_gmp" != "xsystem"; then
+		as_fn_error $? "Setting $with_gmp_prefix implies use of system gmp" "$LINENO" 5
+	fi
+	with_gmp="system"
+fi
+if test "x$with_gmp_builddir" != "x"; then
+	if test "x$with_gmp" != "x" -a "x$with_gmp" != "xyes" -a "x$with_gmp" != "xbuild"; then
+		as_fn_error $? "Setting $with_gmp_builddir implies use of build gmp" "$LINENO" 5
+	fi
+	with_gmp="build"
+	gmp_srcdir=`echo @abs_srcdir@ | $with_gmp_builddir/config.status --file=-`
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: gmp sources in $gmp_srcdir" >&5
+$as_echo "$as_me: gmp sources in $gmp_srcdir" >&6;}
+fi
+if test "x$with_gmp_exec_prefix" != "x"; then
+	export PKG_CONFIG_PATH="$with_gmp_exec_prefix/lib/pkgconfig${PKG_CONFIG_PATH+:$PKG_CONFIG_PATH}"
+fi
+case "$with_gmp" in
+system|build)
+	;;
+*)
+	case "system" in
+	bundled)
+		if test -d $srcdir/.git -a \
+			-d $srcdir/gmp -a \
+			! -d $srcdir/gmp/.git; then
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: git repo detected, but submodule gmp not initialized" >&5
+$as_echo "$as_me: WARNING: git repo detected, but submodule gmp not initialized" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You may want to run" >&5
+$as_echo "$as_me: WARNING: You may want to run" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 	git submodule init" >&5
+$as_echo "$as_me: WARNING: 	git submodule init" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 	git submodule update" >&5
+$as_echo "$as_me: WARNING: 	git submodule update" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 	sh autogen.sh" >&5
+$as_echo "$as_me: WARNING: 	sh autogen.sh" >&2;}
+		fi
+		if test -f $srcdir/gmp/configure; then
+			with_gmp="bundled"
+		else
+			with_gmp="no"
+		fi
+		;;
+	*)
+		with_gmp="system"
+		;;
+	esac
+	;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which gmp to use" >&5
+$as_echo_n "checking which gmp to use... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_gmp" >&5
+$as_echo "$with_gmp" >&6; }
+
+
+case "$with_gmp" in
+system)
+	if test "x$with_gmp_prefix" != "x"; then
+		isl_configure_args="$isl_configure_args --with-gmp=$with_gmp_prefix"
+		MP_CPPFLAGS="-I$with_gmp_prefix/include"
+		MP_LDFLAGS="-L$with_gmp_prefix/lib"
+	fi
+	MP_LIBS=-lgmp
+	SAVE_CPPFLAGS="$CPPFLAGS"
+	SAVE_LDFLAGS="$LDFLAGS"
+	SAVE_LIBS="$LIBS"
+	CPPFLAGS="$MP_CPPFLAGS $CPPFLAGS"
+	LDFLAGS="$MP_LDFLAGS $LDFLAGS"
+	LIBS="$MP_LIBS $LIBS"
+	ac_fn_c_check_header_mongrel "$LINENO" "gmp.h" "ac_cv_header_gmp_h" "$ac_includes_default"
+if test "x$ac_cv_header_gmp_h" = xyes; then :
+
+else
+  as_fn_error $? "gmp.h header not found" "$LINENO" 5
+fi
+
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lgmp" >&5
+$as_echo_n "checking for main in -lgmp... " >&6; }
+if ${ac_cv_lib_gmp_main+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgmp  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_gmp_main=yes
+else
+  ac_cv_lib_gmp_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gmp_main" >&5
+$as_echo "$ac_cv_lib_gmp_main" >&6; }
+if test "x$ac_cv_lib_gmp_main" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBGMP 1
+_ACEOF
+
+  LIBS="-lgmp $LIBS"
+
+else
+  as_fn_error $? "gmp library not found" "$LINENO" 5
+fi
+
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <gmp.h>
+int
+main ()
+{
+
+		mpz_t n, d;
+		if (mpz_divisible_p(n, d))
+			mpz_divexact_ui(n, n, 4);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  as_fn_error $? "gmp library too old" "$LINENO" 5
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	CPPFLAGS="$SAVE_CPPFLAGS"
+	LDFLAGS="$SAVE_LDFLAGS"
+	LIBS="$SAVE_LIBS"
+	;;
+build)
+	MP_CPPFLAGS="-I$gmp_srcdir -I$with_gmp_builddir"
+	MP_LIBS="$with_gmp_builddir/libgmp.la"
+	;;
+esac
+SAVE_CPPFLAGS="$CPPFLAGS"
+SAVE_LDFLAGS="$LDFLAGS"
+SAVE_LIBS="$LIBS"
+CPPFLAGS="$MP_CPPFLAGS $CPPFLAGS"
+LDFLAGS="$MP_LDFLAGS $LDFLAGS"
+LIBS="$MP_LIBS $LIBS"
+need_get_memory_functions=false
+ac_fn_c_check_decl "$LINENO" "mp_get_memory_functions" "ac_cv_have_decl_mp_get_memory_functions" "#include <gmp.h>
+"
+if test "x$ac_cv_have_decl_mp_get_memory_functions" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_MP_GET_MEMORY_FUNCTIONS $ac_have_decl
+_ACEOF
+if test $ac_have_decl = 1; then :
+
+else
+
+	need_get_memory_functions=true
+
+fi
+
+CPPFLAGS="$SAVE_CPPFLAGS"
+LDFLAGS="$SAVE_LDFLAGS"
+LIBS="$SAVE_LIBS"
+ if test x$need_get_memory_functions = xtrue; then
+  NEED_GET_MEMORY_FUNCTIONS_TRUE=
+  NEED_GET_MEMORY_FUNCTIONS_FALSE='#'
+else
+  NEED_GET_MEMORY_FUNCTIONS_TRUE='#'
+  NEED_GET_MEMORY_FUNCTIONS_FALSE=
+fi
+
+
+	;;
+imath|imath-32)
+
+
+$as_echo "#define USE_IMATH_FOR_MP /**/" >>confdefs.h
+
+
+MP_CPPFLAGS="-I$srcdir/imath_wrap"
+MP_LDFLAGS=""
+MP_LIBS=""
+
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$MP_CPPFLAGS $CPPFLAGS"
+ac_fn_c_check_header_mongrel "$LINENO" "imath.h" "ac_cv_header_imath_h" "$ac_includes_default"
+if test "x$ac_cv_header_imath_h" = xyes; then :
+
+else
+  as_fn_error $? "imath.h header not found" "$LINENO" 5
+fi
+
+
+ac_fn_c_check_header_mongrel "$LINENO" "gmp_compat.h" "ac_cv_header_gmp_compat_h" "$ac_includes_default"
+if test "x$ac_cv_header_gmp_compat_h" = xyes; then :
+
+else
+  as_fn_error $? "gmp_compat.h header not found" "$LINENO" 5
+fi
+
+
+CPPFLAGS="$SAVE_CPPFLAGS"
+
+ if test x = xfalse; then
+  NEED_GET_MEMORY_FUNCTIONS_TRUE=
+  NEED_GET_MEMORY_FUNCTIONS_FALSE='#'
+else
+  NEED_GET_MEMORY_FUNCTIONS_TRUE='#'
+  NEED_GET_MEMORY_FUNCTIONS_FALSE=
+fi
+
+
+	;;
+esac
+if test "x$with_int" = "ximath-32" -a "x$GCC" = "xyes"; then
+	MP_CPPFLAGS="-std=gnu99 $MP_CPPFLAGS"
+fi
+
+ if test x$with_int = ximath -o x$with_int = ximath-32; then
+  IMATH_FOR_MP_TRUE=
+  IMATH_FOR_MP_FALSE='#'
+else
+  IMATH_FOR_MP_TRUE='#'
+  IMATH_FOR_MP_FALSE=
+fi
+
+ if test x$with_int = xgmp; then
+  GMP_FOR_MP_TRUE=
+  GMP_FOR_MP_FALSE='#'
+else
+  GMP_FOR_MP_TRUE='#'
+  GMP_FOR_MP_FALSE=
+fi
+
+
+ if test "x$HAVE_CXX11" = "x1"; then
+  HAVE_CXX11_TRUE=
+  HAVE_CXX11_FALSE='#'
+else
+  HAVE_CXX11_TRUE='#'
+  HAVE_CXX11_FALSE=
+fi
+
+ if test "x$with_int" == "ximath-32"; then
+  SMALL_INT_OPT_TRUE=
+  SMALL_INT_OPT_FALSE='#'
+else
+  SMALL_INT_OPT_TRUE='#'
+  SMALL_INT_OPT_FALSE=
+fi
+
+if test "x$with_int" == "ximath-32"; then :
+
+
+$as_echo "#define USE_SMALL_INT_OPT /**/" >>confdefs.h
+
+
+fi
+
+ac_fn_c_check_decl "$LINENO" "ffs" "ac_cv_have_decl_ffs" "#include <strings.h>
+"
+if test "x$ac_cv_have_decl_ffs" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FFS $ac_have_decl
+_ACEOF
+
+ac_fn_c_check_decl "$LINENO" "__builtin_ffs" "ac_cv_have_decl___builtin_ffs" "$ac_includes_default"
+if test "x$ac_cv_have_decl___builtin_ffs" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL___BUILTIN_FFS $ac_have_decl
+_ACEOF
+
+ac_fn_c_check_decl "$LINENO" "_BitScanForward" "ac_cv_have_decl__BitScanForward" "#include <intrin.h>
+"
+if test "x$ac_cv_have_decl__BitScanForward" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL__BITSCANFORWARD $ac_have_decl
+_ACEOF
+
+if test "x$ac_cv_have_decl_ffs" = xno -a \
+		"x$ac_cv_have_decl___builtin_ffs" = xno -a \
+		"x$ac_cv_have_decl__BitScanForward" = xno; then
+	as_fn_error $? "No ffs implementation found" "$LINENO" 5
+fi
+ac_fn_c_check_decl "$LINENO" "strcasecmp" "ac_cv_have_decl_strcasecmp" "#include <strings.h>
+"
+if test "x$ac_cv_have_decl_strcasecmp" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_STRCASECMP $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "strncasecmp" "ac_cv_have_decl_strncasecmp" "#include <strings.h>
+"
+if test "x$ac_cv_have_decl_strncasecmp" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_STRNCASECMP $ac_have_decl
+_ACEOF
+
+ac_fn_c_check_decl "$LINENO" "_stricmp" "ac_cv_have_decl__stricmp" "#include <string.h>
+"
+if test "x$ac_cv_have_decl__stricmp" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL__STRICMP $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "_strnicmp" "ac_cv_have_decl__strnicmp" "#include <string.h>
+"
+if test "x$ac_cv_have_decl__strnicmp" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL__STRNICMP $ac_have_decl
+_ACEOF
+
+if test "x$ac_cv_have_decl_strcasecmp" = xno -a \
+		"x$ac_cv_have_decl__stricmp" = xno; then
+	as_fn_error $? "No strcasecmp implementation found" "$LINENO" 5
+fi
+if test "x$ac_cv_have_decl_strncasecmp" = xno -a \
+		"x$ac_cv_have_decl__strnicmp" = xno; then
+	as_fn_error $? "No strncasecmp implementation found" "$LINENO" 5
+fi
+ac_fn_c_check_decl "$LINENO" "snprintf" "ac_cv_have_decl_snprintf" "#include <stdio.h>
+"
+if test "x$ac_cv_have_decl_snprintf" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SNPRINTF $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "_snprintf" "ac_cv_have_decl__snprintf" "#include <stdio.h>
+"
+if test "x$ac_cv_have_decl__snprintf" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL__SNPRINTF $ac_have_decl
+_ACEOF
+
+if test "x$ac_cv_have_decl_snprintf" = xno -a \
+		"x$ac_cv_have_decl__snprintf" = xno; then
+	as_fn_error $? "No snprintf implementation found" "$LINENO" 5
+fi
+
+
+
+
+# Check whether --with-clang was given.
+if test "${with_clang+set}" = set; then :
+  withval=$with_clang;
+fi
+
+case "system" in
+system|no)
+
+# Check whether --with-clang_prefix was given.
+if test "${with_clang_prefix+set}" = set; then :
+  withval=$with_clang_prefix;
+fi
+
+
+# Check whether --with-clang_exec_prefix was given.
+if test "${with_clang_exec_prefix+set}" = set; then :
+  withval=$with_clang_exec_prefix;
+fi
+
+esac
+
+if test "x$with_clang_prefix" != "x" -a "x$with_clang_exec_prefix" = "x"; then
+	with_clang_exec_prefix=$with_clang_prefix
+fi
+if test "x$with_clang_prefix" != "x" -o "x$with_clang_exec_prefix" != "x"; then
+	if test "x$with_clang" != "x" -a "x$with_clang" != "xyes" -a "x$with_clang" != "xsystem"; then
+		as_fn_error $? "Setting $with_clang_prefix implies use of system clang" "$LINENO" 5
+	fi
+	with_clang="system"
+fi
+if test "x$with_clang_builddir" != "x"; then
+	if test "x$with_clang" != "x" -a "x$with_clang" != "xyes" -a "x$with_clang" != "xbuild"; then
+		as_fn_error $? "Setting $with_clang_builddir implies use of build clang" "$LINENO" 5
+	fi
+	with_clang="build"
+	clang_srcdir=`echo @abs_srcdir@ | $with_clang_builddir/config.status --file=-`
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: clang sources in $clang_srcdir" >&5
+$as_echo "$as_me: clang sources in $clang_srcdir" >&6;}
+fi
+if test "x$with_clang_exec_prefix" != "x"; then
+	export PKG_CONFIG_PATH="$with_clang_exec_prefix/lib/pkgconfig${PKG_CONFIG_PATH+:$PKG_CONFIG_PATH}"
+fi
+case "$with_clang" in
+system|no)
+	;;
+*)
+	case "no" in
+	bundled)
+		if test -d $srcdir/.git -a \
+			-d $srcdir/clang -a \
+			! -d $srcdir/clang/.git; then
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: git repo detected, but submodule clang not initialized" >&5
+$as_echo "$as_me: WARNING: git repo detected, but submodule clang not initialized" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You may want to run" >&5
+$as_echo "$as_me: WARNING: You may want to run" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 	git submodule init" >&5
+$as_echo "$as_me: WARNING: 	git submodule init" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 	git submodule update" >&5
+$as_echo "$as_me: WARNING: 	git submodule update" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 	sh autogen.sh" >&5
+$as_echo "$as_me: WARNING: 	sh autogen.sh" >&2;}
+		fi
+		if test -f $srcdir/clang/configure; then
+			with_clang="bundled"
+		else
+			with_clang="no"
+		fi
+		;;
+	*)
+		with_clang="no"
+		;;
+	esac
+	;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which clang to use" >&5
+$as_echo_n "checking which clang to use... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_clang" >&5
+$as_echo "$with_clang" >&6; }
+
+
+case "$with_clang" in
+system)
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+llvm_config="llvm-config"
+# Extract the first word of ""$llvm_config"", so it can be a program name with args.
+set dummy "$llvm_config"; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_llvm_config_found+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$llvm_config_found"; then
+  ac_cv_prog_llvm_config_found="$llvm_config_found" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_llvm_config_found="yes"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+llvm_config_found=$ac_cv_prog_llvm_config_found
+if test -n "$llvm_config_found"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $llvm_config_found" >&5
+$as_echo "$llvm_config_found" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+if test "x$with_clang_prefix" != "x"; then
+	llvm_config="$with_clang_prefix/bin/llvm-config"
+	if test -x "$llvm_config"; then
+		llvm_config_found=yes
+	fi
+fi
+if test "$llvm_config_found" != yes; then
+	as_fn_error $? "llvm-config not found" "$LINENO" 5
+fi
+CLANG_CXXFLAGS=`$llvm_config --cxxflags | \
+	$SED -e 's/-Wcovered-switch-default//;s/-gsplit-dwarf//'`
+CLANG_LDFLAGS=`$llvm_config --ldflags`
+targets=`$llvm_config --targets-built`
+components="$targets asmparser bitreader support mc"
+$llvm_config --components | $GREP option > /dev/null 2> /dev/null
+if test $? -eq 0; then
+	components="$components option"
+fi
+CLANG_LIBS=`$llvm_config --libs $components`
+systemlibs=`$llvm_config --system-libs 2> /dev/null | tail -1`
+if test $? -eq 0; then
+	CLANG_LIBS="$CLANG_LIBS $systemlibs"
+fi
+CLANG_PREFIX=`$llvm_config --prefix`
+
+cat >>confdefs.h <<_ACEOF
+#define CLANG_PREFIX "$CLANG_PREFIX"
+_ACEOF
+
+
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CLANG_CXXFLAGS $CPPFLAGS"
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+ac_fn_cxx_check_header_mongrel "$LINENO" "clang/Basic/SourceLocation.h" "ac_cv_header_clang_Basic_SourceLocation_h" "$ac_includes_default"
+if test "x$ac_cv_header_clang_Basic_SourceLocation_h" = xyes; then :
+
+else
+  as_fn_error $? "clang header file not found" "$LINENO" 5
+fi
+
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <llvm/Support/Host.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "getDefaultTargetTriple" >/dev/null 2>&1; then :
+
+else
+
+$as_echo "#define getDefaultTargetTriple getHostTriple" >>confdefs.h
+
+fi
+rm -f conftest*
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Basic/SourceLocation.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "getExpansionLineNumber" >/dev/null 2>&1; then :
+
+else
+
+$as_echo "#define getExpansionLineNumber getInstantiationLineNumber" >>confdefs.h
+
+fi
+rm -f conftest*
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Basic/Diagnostic.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "DiagnosticsEngine" >/dev/null 2>&1; then :
+
+else
+
+$as_echo "#define DiagnosticsEngine Diagnostic" >>confdefs.h
+
+fi
+rm -f conftest*
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Driver/Driver.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ArrayRef" >/dev/null 2>&1; then :
+
+$as_echo "#define USE_ARRAYREF /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Driver/Driver.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "CXXIsProduction" >/dev/null 2>&1; then :
+
+$as_echo "#define HAVE_CXXISPRODUCTION /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Driver/Driver.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP " IsProduction" >/dev/null 2>&1; then :
+
+$as_echo "#define HAVE_ISPRODUCTION /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Driver/Driver.h>
+int
+main ()
+{
+
+	using namespace clang;
+	DiagnosticsEngine *Diags;
+	new driver::Driver("", "", "", *Diags);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+$as_echo "#define DRIVER_CTOR_TAKES_DEFAULTIMAGENAME /**/" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/AST/ASTConsumer.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "void HandleTopLevelDecl\(" >/dev/null 2>&1; then :
+
+$as_echo "#define HandleTopLevelDeclReturn void" >>confdefs.h
+
+
+$as_echo "#define HandleTopLevelDeclContinue /**/" >>confdefs.h
+
+else
+
+$as_echo "#define HandleTopLevelDeclReturn bool" >>confdefs.h
+
+
+$as_echo "#define HandleTopLevelDeclContinue true" >>confdefs.h
+
+fi
+rm -f conftest*
+
+ac_fn_cxx_check_header_mongrel "$LINENO" "clang/Basic/DiagnosticOptions.h" "ac_cv_header_clang_Basic_DiagnosticOptions_h" "$ac_includes_default"
+if test "x$ac_cv_header_clang_Basic_DiagnosticOptions_h" = xyes; then :
+
+$as_echo "#define HAVE_BASIC_DIAGNOSTICOPTIONS_H /**/" >>confdefs.h
+
+fi
+
+
+ac_fn_cxx_check_header_compile "$LINENO" "clang/Lex/PreprocessorOptions.h" "ac_cv_header_clang_Lex_PreprocessorOptions_h" "#include <clang/Basic/LLVM.h>
+"
+if test "x$ac_cv_header_clang_Lex_PreprocessorOptions_h" = xyes; then :
+
+$as_echo "#define HAVE_LEX_PREPROCESSOROPTIONS_H /**/" >>confdefs.h
+
+fi
+
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Basic/TargetInfo.h>
+int
+main ()
+{
+
+	using namespace clang;
+	std::shared_ptr<TargetOptions> TO;
+	DiagnosticsEngine *Diags;
+	TargetInfo::CreateTargetInfo(*Diags, TO);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+$as_echo "#define CREATETARGETINFO_TAKES_SHARED_PTR /**/" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Basic/TargetInfo.h>
+int
+main ()
+{
+
+	using namespace clang;
+	TargetOptions *TO;
+	DiagnosticsEngine *Diags;
+	TargetInfo::CreateTargetInfo(*Diags, TO);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+$as_echo "#define CREATETARGETINFO_TAKES_POINTER /**/" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Frontend/CompilerInstance.h>
+int
+main ()
+{
+
+	using namespace clang;
+	DiagnosticConsumer *client;
+	CompilerInstance *Clang;
+	Clang->createDiagnostics(client);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+
+$as_echo "#define CREATEDIAGNOSTICS_TAKES_ARG /**/" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Lex/HeaderSearchOptions.h>
+int
+main ()
+{
+
+	using namespace clang;
+	HeaderSearchOptions HSO;
+	HSO.AddPath("", frontend::Angled, false, false);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+$as_echo "#define ADDPATH_TAKES_4_ARGUMENTS /**/" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/AST/CanonicalType.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "getNumParams" >/dev/null 2>&1; then :
+
+$as_echo "#define getNumArgs getNumParams" >>confdefs.h
+
+
+$as_echo "#define getArgType getParamType" >>confdefs.h
+
+fi
+rm -f conftest*
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/AST/CanonicalType.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "getReturnType" >/dev/null 2>&1; then :
+
+else
+
+$as_echo "#define getReturnType getResultType" >>confdefs.h
+
+fi
+rm -f conftest*
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Frontend/CompilerInstance.h>
+int
+main ()
+{
+
+	using namespace clang;
+	CompilerInstance *Clang;
+	Clang->createPreprocessor(TU_Complete);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+$as_echo "#define CREATEPREPROCESSOR_TAKES_TUKIND /**/" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Basic/SourceManager.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "setMainFileID" >/dev/null 2>&1; then :
+
+$as_echo "#define HAVE_SETMAINFILEID /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+ac_fn_cxx_check_header_mongrel "$LINENO" "llvm/ADT/OwningPtr.h" "ac_cv_header_llvm_ADT_OwningPtr_h" "$ac_includes_default"
+if test "x$ac_cv_header_llvm_ADT_OwningPtr_h" = xyes; then :
+
+$as_echo "#define HAVE_ADT_OWNINGPTR_H /**/" >>confdefs.h
+
+fi
+
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Basic/Builtins.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "initializeBuiltins" >/dev/null 2>&1; then :
+
+else
+
+$as_echo "#define initializeBuiltins InitializeBuiltins" >>confdefs.h
+
+fi
+rm -f conftest*
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <clang/Frontend/FrontendOptions.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "IK_C" >/dev/null 2>&1; then :
+
+else
+
+$as_echo "#define IK_C InputKind::C" >>confdefs.h
+
+fi
+rm -f conftest*
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+	#include <clang/Basic/TargetOptions.h>
+	#include <clang/Lex/PreprocessorOptions.h>
+	#include <clang/Frontend/CompilerInstance.h>
+
+int
+main ()
+{
+
+	using namespace clang;
+	CompilerInstance *Clang;
+	TargetOptions TO;
+	llvm::Triple T(TO.Triple);
+	PreprocessorOptions PO;
+	CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C,
+			T, PO, LangStandard::lang_unspecified);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+$as_echo "#define SETLANGDEFAULTS_TAKES_5_ARGUMENTS /**/" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+	#include <clang/Frontend/CompilerInstance.h>
+	#include <clang/Frontend/CompilerInvocation.h>
+
+int
+main ()
+{
+
+	using namespace clang;
+	CompilerInvocation *invocation;
+	CompilerInstance *Clang;
+	Clang->setInvocation(std::make_shared<CompilerInvocation>(*invocation));
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+$as_echo "#define SETINVOCATION_TAKES_SHARED_PTR /**/" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CPPFLAGS="$SAVE_CPPFLAGS"
+
+SAVE_LDFLAGS="$LDFLAGS"
+LDFLAGS="$CLANG_LDFLAGS $LDFLAGS"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lclangEdit" >&5
+$as_echo_n "checking for main in -lclangEdit... " >&6; }
+if ${ac_cv_lib_clangEdit_main+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lclangEdit  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_clangEdit_main=yes
+else
+  ac_cv_lib_clangEdit_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_clangEdit_main" >&5
+$as_echo "$ac_cv_lib_clangEdit_main" >&6; }
+if test "x$ac_cv_lib_clangEdit_main" = xyes; then :
+  LIB_CLANG_EDIT=-lclangEdit
+fi
+
+LDFLAGS="$SAVE_LDFLAGS"
+
+	;;
+esac
+ if test $with_clang = system; then
+  HAVE_CLANG_TRUE=
+  HAVE_CLANG_FALSE='#'
+else
+  HAVE_CLANG_TRUE='#'
+  HAVE_CLANG_FALSE=
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler vendor" >&5
+$as_echo_n "checking for C compiler vendor... " >&6; }
+if ${ax_cv_c_compiler_vendor+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ax_cv_c_compiler_vendor=unknown
+  # note: don't check for gcc first since some other compilers define __GNUC__
+  for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ pathscale:__PATHCC__,__PATHSCALE__ clang:__clang__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
+    vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+#if !($vencpp)
+      thisisanerror;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ax_cv_c_compiler_vendor=`echo $ventest | cut -d: -f1`; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_c_compiler_vendor" >&5
+$as_echo "$ax_cv_c_compiler_vendor" >&6; }
+
+
+	WARNING_FLAGS=""
+
+	if test "${ax_cv_c_compiler_vendor}" = "clang"; then
+												WARNING_FLAGS="-Wall"
+	fi
+
+
+
+
+PACKAGE_CFLAGS="$MP_CPPFLAGS"
+PACKAGE_LDFLAGS="$MP_LDFLAGS"
+PACKAGE_LIBS="-lisl $MP_LIBS"
+
+# we need the expanded forms...
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking our pkgconfig libname" >&5
+$as_echo_n "checking our pkgconfig libname... " >&6; }
+test ".$ax_create_pkgconfig_libname" != "." || \
+ax_create_pkgconfig_libname="${PACKAGE_NAME}"
+test ".$ax_create_pkgconfig_libname" != "." || \
+ax_create_pkgconfig_libname="$PACKAGE"
+ax_create_pkgconfig_libname=`eval echo "$ax_create_pkgconfig_libname"`
+ax_create_pkgconfig_libname=`eval echo "$ax_create_pkgconfig_libname"`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_create_pkgconfig_libname" >&5
+$as_echo "$ax_create_pkgconfig_libname" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking our pkgconfig version" >&5
+$as_echo_n "checking our pkgconfig version... " >&6; }
+test ".$ax_create_pkgconfig_version" != "." || \
+ax_create_pkgconfig_version="${PACKAGE_VERSION}"
+test ".$ax_create_pkgconfig_version" != "." || \
+ax_create_pkgconfig_version="$VERSION"
+ax_create_pkgconfig_version=`eval echo "$ax_create_pkgconfig_version"`
+ax_create_pkgconfig_version=`eval echo "$ax_create_pkgconfig_version"`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_create_pkgconfig_version" >&5
+$as_echo "$ax_create_pkgconfig_version" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking our pkgconfig_libdir" >&5
+$as_echo_n "checking our pkgconfig_libdir... " >&6; }
+test ".$pkgconfig_libdir" = "." && \
+pkgconfig_libdir='${libdir}/pkgconfig'
+ax_create_pkgconfig_libdir=`eval echo "$pkgconfig_libdir"`
+ax_create_pkgconfig_libdir=`eval echo "$ax_create_pkgconfig_libdir"`
+ax_create_pkgconfig_libdir=`eval echo "$ax_create_pkgconfig_libdir"`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pkgconfig_libdir" >&5
+$as_echo "$pkgconfig_libdir" >&6; }
+test "$pkgconfig_libdir" != "$ax_create_pkgconfig_libdir" && (
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: expanded our pkgconfig_libdir... $ax_create_pkgconfig_libdir" >&5
+$as_echo "expanded our pkgconfig_libdir... $ax_create_pkgconfig_libdir" >&6; })
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking our pkgconfig_libfile" >&5
+$as_echo_n "checking our pkgconfig_libfile... " >&6; }
+test ".$pkgconfig_libfile" != "." || \
+pkgconfig_libfile="$ax_create_pkgconfig_libname.pc"
+ax_create_pkgconfig_libfile=`eval echo "$pkgconfig_libfile"`
+ax_create_pkgconfig_libfile=`eval echo "$ax_create_pkgconfig_libfile"`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pkgconfig_libfile" >&5
+$as_echo "$pkgconfig_libfile" >&6; }
+test "$pkgconfig_libfile" != "$ax_create_pkgconfig_libfile" && (
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: expanded our pkgconfig_libfile... $ax_create_pkgconfig_libfile" >&5
+$as_echo "expanded our pkgconfig_libfile... $ax_create_pkgconfig_libfile" >&6; })
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking our package / suffix" >&5
+$as_echo_n "checking our package / suffix... " >&6; }
+ax_create_pkgconfig_suffix="$program_suffix"
+test ".$ax_create_pkgconfig_suffix" != .NONE || ax_create_pkgconfig_suffix=""
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${PACKAGE_NAME} / ${ax_create_pkgconfig_suffix}" >&5
+$as_echo "${PACKAGE_NAME} / ${ax_create_pkgconfig_suffix}" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking our pkgconfig description" >&5
+$as_echo_n "checking our pkgconfig description... " >&6; }
+ax_create_pkgconfig_description="$PACKAGE_SUMMARY"
+test ".$ax_create_pkgconfig_description" != "." || \
+ax_create_pkgconfig_description="$ax_create_pkgconfig_libname Library"
+ax_create_pkgconfig_description=`eval echo "$ax_create_pkgconfig_description"`
+ax_create_pkgconfig_description=`eval echo "$ax_create_pkgconfig_description"`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_create_pkgconfig_description" >&5
+$as_echo "$ax_create_pkgconfig_description" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking our pkgconfig requires" >&5
+$as_echo_n "checking our pkgconfig requires... " >&6; }
+ax_create_pkgconfig_requires="$PACKAGE_REQUIRES"
+ax_create_pkgconfig_requires=`eval echo "$ax_create_pkgconfig_requires"`
+ax_create_pkgconfig_requires=`eval echo "$ax_create_pkgconfig_requires"`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_create_pkgconfig_requires" >&5
+$as_echo "$ax_create_pkgconfig_requires" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking our pkgconfig ext libs" >&5
+$as_echo_n "checking our pkgconfig ext libs... " >&6; }
+ax_create_pkgconfig_pkglibs="$PACKAGE_LIBS"
+test ".$ax_create_pkgconfig_pkglibs" != "." || ax_create_pkgconfig_pkglibs="-l$ax_create_pkgconfig_libname"
+ax_create_pkgconfig_libs="$ax_create_pkgconfig_pkglibs $LIBS"
+ax_create_pkgconfig_libs=`eval echo "$ax_create_pkgconfig_libs"`
+ax_create_pkgconfig_libs=`eval echo "$ax_create_pkgconfig_libs"`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_create_pkgconfig_libs" >&5
+$as_echo "$ax_create_pkgconfig_libs" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking our pkgconfig cppflags" >&5
+$as_echo_n "checking our pkgconfig cppflags... " >&6; }
+ax_create_pkgconfig_cppflags="$PACKAGE_CFLAGS"
+ax_create_pkgconfig_cppflags=`eval echo "$ax_create_pkgconfig_cppflags"`
+ax_create_pkgconfig_cppflags=`eval echo "$ax_create_pkgconfig_cppflags"`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_create_pkgconfig_cppflags" >&5
+$as_echo "$ax_create_pkgconfig_cppflags" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking our pkgconfig ldflags" >&5
+$as_echo_n "checking our pkgconfig ldflags... " >&6; }
+ax_create_pkgconfig_ldflags="$PACKAGE_LDFLAGS"
+ax_create_pkgconfig_ldflags=`eval echo "$ax_create_pkgconfig_ldflags"`
+ax_create_pkgconfig_ldflags=`eval echo "$ax_create_pkgconfig_ldflags"`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_create_pkgconfig_ldflags" >&5
+$as_echo "$ax_create_pkgconfig_ldflags" >&6; }
+
+test ".$ax_create_pkgconfig_generate" != "." || \
+ax_create_pkgconfig_generate="$ax_create_pkgconfig_libname.pc"
+ax_create_pkgconfig_generate=`eval echo "$ax_create_pkgconfig_generate"`
+ax_create_pkgconfig_generate=`eval echo "$ax_create_pkgconfig_generate"`
+test "$pkgconfig_libfile" != "$ax_create_pkgconfig_generate" && (
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: generate the pkgconfig later... $ax_create_pkgconfig_generate" >&5
+$as_echo "generate the pkgconfig later... $ax_create_pkgconfig_generate" >&6; })
+
+if test ".$ax_create_pkgconfig_src_libdir" = "." ; then
+ax_create_pkgconfig_src_libdir=`pwd`
+ax_create_pkgconfig_src_libdir=`$as_dirname -- "$ax_create_pkgconfig_src_libdir/$ax_create_pkgconfig_generate" ||
+$as_expr X"$ax_create_pkgconfig_src_libdir/$ax_create_pkgconfig_generate" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ax_create_pkgconfig_src_libdir/$ax_create_pkgconfig_generate" : 'X\(//\)[^/]' \| \
+	 X"$ax_create_pkgconfig_src_libdir/$ax_create_pkgconfig_generate" : 'X\(//\)$' \| \
+	 X"$ax_create_pkgconfig_src_libdir/$ax_create_pkgconfig_generate" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ax_create_pkgconfig_src_libdir/$ax_create_pkgconfig_generate" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+test ! -d $ax_create_pkgconfig_src_libdir/src || \
+ax_create_pkgconfig_src_libdir="$ax_create_pkgconfig_src_libdir/src"
+case ".$objdir" in
+*libs) ax_create_pkgconfig_src_libdir="$ax_create_pkgconfig_src_libdir/$objdir" ;; esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: noninstalled pkgconfig -L $ax_create_pkgconfig_src_libdir" >&5
+$as_echo "noninstalled pkgconfig -L $ax_create_pkgconfig_src_libdir" >&6; }
+fi
+
+if test ".$ax_create_pkgconfig_src_headers" = "." ; then
+ax_create_pkgconfig_src_headers=`pwd`
+v="$ac_top_srcdir" ;
+test ".$v" != "." || v="$ax_spec_dir"
+test ".$v" != "." || v="$srcdir"
+case "$v" in /*) ax_create_pkgconfig_src_headers="" ;; esac
+ax_create_pkgconfig_src_headers=`$as_dirname -- "$ax_create_pkgconfig_src_headers/$v/x" ||
+$as_expr X"$ax_create_pkgconfig_src_headers/$v/x" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ax_create_pkgconfig_src_headers/$v/x" : 'X\(//\)[^/]' \| \
+	 X"$ax_create_pkgconfig_src_headers/$v/x" : 'X\(//\)$' \| \
+	 X"$ax_create_pkgconfig_src_headers/$v/x" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ax_create_pkgconfig_src_headers/$v/x" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+test ! -d $ax_create_pkgconfig_src_headers/include || \
+ax_create_pkgconfig_src_headers="$ax_create_pkgconfig_src_headers/include"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: noninstalled pkgconfig -I $ax_create_pkgconfig_src_headers" >&5
+$as_echo "noninstalled pkgconfig -I $ax_create_pkgconfig_src_headers" >&6; }
+fi
+
+
+ac_config_commands="$ac_config_commands $ax_create_pkgconfig_generate"
+
+
+
+
+
+
+	if test -f $srcdir/.git; then
+		gitdir=`GIT_DIR=$srcdir/.git git rev-parse --git-dir`
+		GIT_HEAD="$gitdir/index"
+		GIT_REPO="$gitdir"
+		GIT_HEAD_ID=`GIT_DIR=$GIT_REPO git describe --always`
+	elif test -f $srcdir/.git/HEAD; then
+		GIT_HEAD="$srcdir/.git/index"
+		GIT_REPO="$srcdir/.git"
+		GIT_HEAD_ID=`GIT_DIR=$GIT_REPO git describe --always`
+	elif test -f $srcdir/GIT_HEAD_ID; then
+		GIT_HEAD_ID=`cat $srcdir/GIT_HEAD_ID`
+	else
+		mysrcdir=`(cd $srcdir; pwd)`
+		head=`basename $mysrcdir | sed -e 's/.*-//'`
+		head2=`echo $head | sed -e 's/^0-9a-f//'`
+		head3=`echo $head2 | sed -e 's/........................................//'`
+		if test "x$head3" = "x" -a "x$head" = "x$head2"; then
+			GIT_HEAD_ID="$head"
+		else
+			GIT_HEAD_ID="UNKNOWN"
+		fi
+	fi
+	if test -z "$GIT_REPO" ; then
+		GIT_HEAD_VERSION="$GIT_HEAD_ID"
+	else
+	    GIT_HEAD_VERSION="\`GIT_DIR=$GIT_REPO git describe --always\`"
+	fi
+
+
+
+ac_config_headers="$ac_config_headers isl_config.h"
+
+ac_config_files="$ac_config_files isl_srcdir.c"
+
+ac_config_files="$ac_config_files Makefile"
+
+ac_config_files="$ac_config_files doc/Makefile"
+
+if test $with_clang = system; then
+	ac_config_files="$ac_config_files interface/Makefile"
+
+fi
+ac_config_files="$ac_config_files bound_test.sh"
+
+ac_config_files="$ac_config_files codegen_test.sh"
+
+ac_config_files="$ac_config_files pip_test.sh"
+
+ac_config_files="$ac_config_files flow_test.sh"
+
+ac_config_files="$ac_config_files schedule_test.sh"
+
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+  am__EXEEXT_TRUE=
+  am__EXEEXT_FALSE='#'
+else
+  am__EXEEXT_TRUE='#'
+  am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+  as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${GENERATE_DOC_TRUE}" && test -z "${GENERATE_DOC_FALSE}"; then
+  as_fn_error $? "conditional \"GENERATE_DOC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${NEED_GET_MEMORY_FUNCTIONS_TRUE}" && test -z "${NEED_GET_MEMORY_FUNCTIONS_FALSE}"; then
+  as_fn_error $? "conditional \"NEED_GET_MEMORY_FUNCTIONS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${NEED_GET_MEMORY_FUNCTIONS_TRUE}" && test -z "${NEED_GET_MEMORY_FUNCTIONS_FALSE}"; then
+  as_fn_error $? "conditional \"NEED_GET_MEMORY_FUNCTIONS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${IMATH_FOR_MP_TRUE}" && test -z "${IMATH_FOR_MP_FALSE}"; then
+  as_fn_error $? "conditional \"IMATH_FOR_MP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${GMP_FOR_MP_TRUE}" && test -z "${GMP_FOR_MP_FALSE}"; then
+  as_fn_error $? "conditional \"GMP_FOR_MP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_CXX11_TRUE}" && test -z "${HAVE_CXX11_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_CXX11\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${SMALL_INT_OPT_TRUE}" && test -z "${SMALL_INT_OPT_FALSE}"; then
+  as_fn_error $? "conditional \"SMALL_INT_OPT\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_CLANG_TRUE}" && test -z "${HAVE_CLANG_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_CLANG\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by isl $as_me 0.18, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <isl-development@googlegroups.com>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+isl config.status 0.18
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
+want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`'
+nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
+lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`'
+configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`'
+predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`'
+postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`'
+predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`'
+postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`'
+LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`'
+reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`'
+reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`'
+GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`'
+inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`'
+always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`'
+predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`'
+postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SHELL \
+ECHO \
+PATH_SEPARATOR \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+file_magic_glob \
+want_nocaseglob \
+DLLTOOL \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+archiver_list_spec \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_import \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+lt_cv_nm_interface \
+nm_file_list_spec \
+lt_cv_truncate_bin \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_pic \
+lt_prog_compiler_wl \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+MANIFEST_TOOL \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_separator \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib \
+compiler_lib_search_dirs \
+predep_objects \
+postdep_objects \
+predeps \
+postdeps \
+compiler_lib_search_path \
+LD_CXX \
+reload_flag_CXX \
+compiler_CXX \
+lt_prog_compiler_no_builtin_flag_CXX \
+lt_prog_compiler_pic_CXX \
+lt_prog_compiler_wl_CXX \
+lt_prog_compiler_static_CXX \
+lt_cv_prog_compiler_c_o_CXX \
+export_dynamic_flag_spec_CXX \
+whole_archive_flag_spec_CXX \
+compiler_needs_object_CXX \
+with_gnu_ld_CXX \
+allow_undefined_flag_CXX \
+no_undefined_flag_CXX \
+hardcode_libdir_flag_spec_CXX \
+hardcode_libdir_separator_CXX \
+exclude_expsyms_CXX \
+include_expsyms_CXX \
+file_list_spec_CXX \
+compiler_lib_search_dirs_CXX \
+predep_objects_CXX \
+postdep_objects_CXX \
+predeps_CXX \
+postdeps_CXX \
+compiler_lib_search_path_CXX; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postlink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+configure_time_dlsearch_path \
+configure_time_lt_sys_library_path \
+reload_cmds_CXX \
+old_archive_cmds_CXX \
+old_archive_from_new_cmds_CXX \
+old_archive_from_expsyms_cmds_CXX \
+archive_cmds_CXX \
+archive_expsym_cmds_CXX \
+module_cmds_CXX \
+module_expsym_cmds_CXX \
+export_symbols_cmds_CXX \
+prelink_cmds_CXX \
+postlink_cmds_CXX; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+
+# See if we are running on zsh, and set the options that allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}"; then
+   setopt NO_GLOB_SUBST
+fi
+
+
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    RM='$RM'
+    ofile='$ofile'
+
+
+
+
+
+# variables for create stdint.h replacement
+PACKAGE="$PACKAGE"
+VERSION="$VERSION"
+ac_stdint_h="$ac_stdint_h"
+_ac_stdint_h=`$as_echo "_$PACKAGE-$ac_stdint_h" | $as_tr_cpp`
+ac_cv_stdint_message="$ac_cv_stdint_message"
+ac_cv_header_stdint_t="$ac_cv_header_stdint_t"
+ac_cv_header_stdint_x="$ac_cv_header_stdint_x"
+ac_cv_header_stdint_o="$ac_cv_header_stdint_o"
+ac_cv_header_stdint_u="$ac_cv_header_stdint_u"
+ac_cv_type_uint64_t="$ac_cv_type_uint64_t"
+ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t"
+ac_cv_char_data_model="$ac_cv_char_data_model"
+ac_cv_long_data_model="$ac_cv_long_data_model"
+ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t"
+ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t"
+ac_cv_type_intmax_t="$ac_cv_type_intmax_t"
+
+
+ax_create_pkgconfig_generate="$ax_create_pkgconfig_generate"
+pkgconfig_prefix='$prefix'
+pkgconfig_execprefix='$exec_prefix'
+pkgconfig_bindir='$bindir'
+pkgconfig_libdir='$libdir'
+pkgconfig_includedir='$includedir'
+pkgconfig_datarootdir='$datarootdir'
+pkgconfig_datadir='$datadir'
+pkgconfig_sysconfdir='$sysconfdir'
+pkgconfig_suffix='$ax_create_pkgconfig_suffix'
+pkgconfig_package='$PACKAGE_NAME'
+pkgconfig_libname='$ax_create_pkgconfig_libname'
+pkgconfig_description='$ax_create_pkgconfig_description'
+pkgconfig_version='$ax_create_pkgconfig_version'
+pkgconfig_requires='$ax_create_pkgconfig_requires'
+pkgconfig_libs='$ax_create_pkgconfig_libs'
+pkgconfig_ldflags='$ax_create_pkgconfig_ldflags'
+pkgconfig_cppflags='$ax_create_pkgconfig_cppflags'
+pkgconfig_src_libdir='$ax_create_pkgconfig_src_libdir'
+pkgconfig_src_headers='$ax_create_pkgconfig_src_headers'
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+    "$ac_stdint_h") CONFIG_COMMANDS="$CONFIG_COMMANDS $ac_stdint_h" ;;
+    "$ax_create_pkgconfig_generate") CONFIG_COMMANDS="$CONFIG_COMMANDS $ax_create_pkgconfig_generate" ;;
+    "isl_config.h") CONFIG_HEADERS="$CONFIG_HEADERS isl_config.h" ;;
+    "isl_srcdir.c") CONFIG_FILES="$CONFIG_FILES isl_srcdir.c" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+    "interface/Makefile") CONFIG_FILES="$CONFIG_FILES interface/Makefile" ;;
+    "bound_test.sh") CONFIG_FILES="$CONFIG_FILES bound_test.sh" ;;
+    "codegen_test.sh") CONFIG_FILES="$CONFIG_FILES codegen_test.sh" ;;
+    "pip_test.sh") CONFIG_FILES="$CONFIG_FILES pip_test.sh" ;;
+    "flow_test.sh") CONFIG_FILES="$CONFIG_FILES flow_test.sh" ;;
+    "schedule_test.sh") CONFIG_FILES="$CONFIG_FILES schedule_test.sh" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+  ac_MKDIR_P=$MKDIR_P
+  case $MKDIR_P in
+  [\\/$]* | ?:[\\/]* ) ;;
+  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$_am_arg" : 'X\(//\)[^/]' \| \
+	 X"$_am_arg" : 'X\(//\)$' \| \
+	 X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$mf" : 'X\(//\)[^/]' \| \
+	 X"$mf" : 'X\(//\)$' \| \
+	 X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$file" : 'X\(//\)[^/]' \| \
+	 X"$file" : 'X\(//\)$' \| \
+	 X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      as_dir=$dirpart/$fdir; as_fn_mkdir_p
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+ ;;
+    "libtool":C)
+
+    # See if we are running on zsh, and set the options that allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}"; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile=${ofile}T
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+# Generated automatically by $as_me ($PACKAGE) $VERSION
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the  same
+# distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags='CXX '
+
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shared archive member basename,for filename based shared library versioning on AIX.
+shared_archive_member_spec=$shared_archive_member_spec
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The PATH separator for the build system.
+PATH_SEPARATOR=$lt_PATH_SEPARATOR
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm into a list of symbols to manually relocate.
+global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# The name lister interface.
+nm_interface=$lt_lt_cv_nm_interface
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and where our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# Command to truncate a binary pipe.
+lt_truncate_bin=$lt_lt_cv_truncate_bin
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Detected run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path
+
+# Explicit LT_SYS_LIBRARY_PATH set during ./configure time.
+configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \$shlibpath_var if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects
+postdep_objects=$lt_postdep_objects
+predeps=$lt_predeps
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+    cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+#       string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+#       string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+#       string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+#       "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+#       VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+    case x$2 in
+    x)
+        ;;
+    *:)
+        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
+        ;;
+    x:*)
+        eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
+        ;;
+    *::*)
+        eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+        eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
+        ;;
+    *)
+        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
+        ;;
+    esac
+}
+
+
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+    for cc_temp in $*""; do
+      case $cc_temp in
+        compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+        distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+        \-*) ;;
+        *) break;;
+      esac
+    done
+    func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test set != "${COLLECT_NAMES+set}"; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+
+ltmain=$ac_aux_dir/ltmain.sh
+
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+
+
+    cat <<_LT_EOF >> "$ofile"
+
+# ### BEGIN LIBTOOL TAG CONFIG: CXX
+
+# The linker used to build libraries.
+LD=$lt_LD_CXX
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag_CXX
+reload_cmds=$lt_reload_cmds_CXX
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds_CXX
+
+# A language specific compiler.
+CC=$lt_compiler_CXX
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC_CXX
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_CXX
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_CXX
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_CXX
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_CXX
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object_CXX
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds_CXX
+archive_expsym_cmds=$lt_archive_expsym_cmds_CXX
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds_CXX
+module_expsym_cmds=$lt_module_expsym_cmds_CXX
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld_CXX
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_CXX
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_CXX
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
+
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct_CXX
+
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \$shlibpath_var if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute_CXX
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L_CXX
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic_CXX
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath_CXX
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_CXX
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols_CXX
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_CXX
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_CXX
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_CXX
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds_CXX
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds_CXX
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec_CXX
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_CXX
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects_CXX
+postdep_objects=$lt_postdep_objects_CXX
+predeps=$lt_predeps_CXX
+postdeps=$lt_postdeps_CXX
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
+
+# ### END LIBTOOL TAG CONFIG: CXX
+_LT_EOF
+
+ ;;
+    "$ac_stdint_h":C)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_stdint_h : $_ac_stdint_h" >&5
+$as_echo "$as_me: creating $ac_stdint_h : $_ac_stdint_h" >&6;}
+ac_stdint=$tmp/_stdint.h
+
+echo "#ifndef" $_ac_stdint_h >$ac_stdint
+echo "#define" $_ac_stdint_h "1" >>$ac_stdint
+echo "#ifndef" _GENERATED_STDINT_H >>$ac_stdint
+echo "#define" _GENERATED_STDINT_H '"'$PACKAGE $VERSION'"' >>$ac_stdint
+echo "/* generated $ac_cv_stdint_message */" >>$ac_stdint
+if test "_$ac_cv_header_stdint_t" != "_" ; then
+echo "#define _STDINT_HAVE_STDINT_H" "1" >>$ac_stdint
+echo "#include <stdint.h>" >>$ac_stdint
+echo "#endif" >>$ac_stdint
+echo "#endif" >>$ac_stdint
+else
+
+cat >>$ac_stdint <<STDINT_EOF
+
+/* ................... shortcircuit part ........................... */
+
+#if defined HAVE_STDINT_H || defined _STDINT_HAVE_STDINT_H
+#include <stdint.h>
+#else
+#include <stddef.h>
+
+/* .................... configured part ............................ */
+
+STDINT_EOF
+
+echo "/* whether we have a C99 compatible stdint header file */" >>$ac_stdint
+if test "_$ac_cv_header_stdint_x" != "_" ; then
+  ac_header="$ac_cv_header_stdint_x"
+  echo "#define _STDINT_HEADER_INTPTR" '"'"$ac_header"'"' >>$ac_stdint
+else
+  echo "/* #undef _STDINT_HEADER_INTPTR */" >>$ac_stdint
+fi
+
+echo "/* whether we have a C96 compatible inttypes header file */" >>$ac_stdint
+if  test "_$ac_cv_header_stdint_o" != "_" ; then
+  ac_header="$ac_cv_header_stdint_o"
+  echo "#define _STDINT_HEADER_UINT32" '"'"$ac_header"'"' >>$ac_stdint
+else
+  echo "/* #undef _STDINT_HEADER_UINT32 */" >>$ac_stdint
+fi
+
+echo "/* whether we have a BSD compatible inet types header */" >>$ac_stdint
+if  test "_$ac_cv_header_stdint_u" != "_" ; then
+  ac_header="$ac_cv_header_stdint_u"
+  echo "#define _STDINT_HEADER_U_INT32" '"'"$ac_header"'"' >>$ac_stdint
+else
+  echo "/* #undef _STDINT_HEADER_U_INT32 */" >>$ac_stdint
+fi
+
+echo "" >>$ac_stdint
+
+if test "_$ac_header" != "_" ; then if test "$ac_header" != "stddef.h" ; then
+  echo "#include <$ac_header>" >>$ac_stdint
+  echo "" >>$ac_stdint
+fi fi
+
+echo "/* which 64bit typedef has been found */" >>$ac_stdint
+if test "$ac_cv_type_uint64_t" = "yes" ; then
+echo "#define   _STDINT_HAVE_UINT64_T" "1"  >>$ac_stdint
+else
+echo "/* #undef _STDINT_HAVE_UINT64_T */" >>$ac_stdint
+fi
+if test "$ac_cv_type_u_int64_t" = "yes" ; then
+echo "#define   _STDINT_HAVE_U_INT64_T" "1"  >>$ac_stdint
+else
+echo "/* #undef _STDINT_HAVE_U_INT64_T */" >>$ac_stdint
+fi
+echo "" >>$ac_stdint
+
+echo "/* which type model has been detected */" >>$ac_stdint
+if test "_$ac_cv_char_data_model" != "_" ; then
+echo "#define   _STDINT_CHAR_MODEL" "$ac_cv_char_data_model" >>$ac_stdint
+echo "#define   _STDINT_LONG_MODEL" "$ac_cv_long_data_model" >>$ac_stdint
+else
+echo "/* #undef _STDINT_CHAR_MODEL // skipped */" >>$ac_stdint
+echo "/* #undef _STDINT_LONG_MODEL // skipped */" >>$ac_stdint
+fi
+echo "" >>$ac_stdint
+
+echo "/* whether int_least types were detected */" >>$ac_stdint
+if test "$ac_cv_type_int_least32_t" = "yes"; then
+echo "#define   _STDINT_HAVE_INT_LEAST32_T" "1"  >>$ac_stdint
+else
+echo "/* #undef _STDINT_HAVE_INT_LEAST32_T */" >>$ac_stdint
+fi
+echo "/* whether int_fast types were detected */" >>$ac_stdint
+if test "$ac_cv_type_int_fast32_t" = "yes"; then
+echo "#define   _STDINT_HAVE_INT_FAST32_T" "1" >>$ac_stdint
+else
+echo "/* #undef _STDINT_HAVE_INT_FAST32_T */" >>$ac_stdint
+fi
+echo "/* whether intmax_t type was detected */" >>$ac_stdint
+if test "$ac_cv_type_intmax_t" = "yes"; then
+echo "#define   _STDINT_HAVE_INTMAX_T" "1" >>$ac_stdint
+else
+echo "/* #undef _STDINT_HAVE_INTMAX_T */" >>$ac_stdint
+fi
+echo "" >>$ac_stdint
+
+  cat >>$ac_stdint <<STDINT_EOF
+/* .................... detections part ............................ */
+
+/* whether we need to define bitspecific types from compiler base types */
+#ifndef _STDINT_HEADER_INTPTR
+#ifndef _STDINT_HEADER_UINT32
+#ifndef _STDINT_HEADER_U_INT32
+#define _STDINT_NEED_INT_MODEL_T
+#else
+#define _STDINT_HAVE_U_INT_TYPES
+#endif
+#endif
+#endif
+
+#ifdef _STDINT_HAVE_U_INT_TYPES
+#undef _STDINT_NEED_INT_MODEL_T
+#endif
+
+#ifdef  _STDINT_CHAR_MODEL
+#if     _STDINT_CHAR_MODEL+0 == 122 || _STDINT_CHAR_MODEL+0 == 124
+#ifndef _STDINT_BYTE_MODEL
+#define _STDINT_BYTE_MODEL 12
+#endif
+#endif
+#endif
+
+#ifndef _STDINT_HAVE_INT_LEAST32_T
+#define _STDINT_NEED_INT_LEAST_T
+#endif
+
+#ifndef _STDINT_HAVE_INT_FAST32_T
+#define _STDINT_NEED_INT_FAST_T
+#endif
+
+#ifndef _STDINT_HEADER_INTPTR
+#define _STDINT_NEED_INTPTR_T
+#ifndef _STDINT_HAVE_INTMAX_T
+#define _STDINT_NEED_INTMAX_T
+#endif
+#endif
+
+
+/* .................... definition part ............................ */
+
+/* some system headers have good uint64_t */
+#ifndef _HAVE_UINT64_T
+#if     defined _STDINT_HAVE_UINT64_T  || defined HAVE_UINT64_T
+#define _HAVE_UINT64_T
+#elif   defined _STDINT_HAVE_U_INT64_T || defined HAVE_U_INT64_T
+#define _HAVE_UINT64_T
+typedef u_int64_t uint64_t;
+#endif
+#endif
+
+#ifndef _HAVE_UINT64_T
+/* .. here are some common heuristics using compiler runtime specifics */
+#if defined __STDC_VERSION__ && defined __STDC_VERSION__ >= 199901L
+#define _HAVE_UINT64_T
+#define _HAVE_LONGLONG_UINT64_T
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+
+#elif !defined __STRICT_ANSI__
+#if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__
+#define _HAVE_UINT64_T
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+#elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__
+/* note: all ELF-systems seem to have loff-support which needs 64-bit */
+#if !defined _NO_LONGLONG
+#define _HAVE_UINT64_T
+#define _HAVE_LONGLONG_UINT64_T
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+#endif
+
+#elif defined __alpha || (defined __mips && defined _ABIN32)
+#if !defined _NO_LONGLONG
+typedef long int64_t;
+typedef unsigned long uint64_t;
+#endif
+  /* compiler/cpu type to define int64_t */
+#endif
+#endif
+#endif
+
+#if defined _STDINT_HAVE_U_INT_TYPES
+/* int8_t int16_t int32_t defined by inet code, redeclare the u_intXX types */
+typedef u_int8_t uint8_t;
+typedef u_int16_t uint16_t;
+typedef u_int32_t uint32_t;
+
+/* glibc compatibility */
+#ifndef __int8_t_defined
+#define __int8_t_defined
+#endif
+#endif
+
+#ifdef _STDINT_NEED_INT_MODEL_T
+/* we must guess all the basic types. Apart from byte-adressable system, */
+/* there a few 32-bit-only dsp-systems that we guard with BYTE_MODEL 8-} */
+/* (btw, those nibble-addressable systems are way off, or so we assume) */
+
+
+#if defined _STDINT_BYTE_MODEL
+#if _STDINT_LONG_MODEL+0 == 242
+/* 2:4:2 =  IP16 = a normal 16-bit system                */
+typedef unsigned char   uint8_t;
+typedef unsigned short  uint16_t;
+typedef unsigned long   uint32_t;
+#ifndef __int8_t_defined
+#define __int8_t_defined
+typedef          char    int8_t;
+typedef          short   int16_t;
+typedef          long    int32_t;
+#endif
+#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL == 444
+/* 2:4:4 =  LP32 = a 32-bit system derived from a 16-bit */
+/* 4:4:4 = ILP32 = a normal 32-bit system                */
+typedef unsigned char   uint8_t;
+typedef unsigned short  uint16_t;
+typedef unsigned int    uint32_t;
+#ifndef __int8_t_defined
+#define __int8_t_defined
+typedef          char    int8_t;
+typedef          short   int16_t;
+typedef          int     int32_t;
+#endif
+#elif _STDINT_LONG_MODEL+0 == 484 || _STDINT_LONG_MODEL+0 == 488
+/* 4:8:4 =  IP32 = a 32-bit system prepared for 64-bit    */
+/* 4:8:8 =  LP64 = a normal 64-bit system                 */
+typedef unsigned char   uint8_t;
+typedef unsigned short  uint16_t;
+typedef unsigned int    uint32_t;
+#ifndef __int8_t_defined
+#define __int8_t_defined
+typedef          char    int8_t;
+typedef          short   int16_t;
+typedef          int     int32_t;
+#endif
+/* this system has a "long" of 64bit */
+#ifndef _HAVE_UINT64_T
+#define _HAVE_UINT64_T
+typedef unsigned long   uint64_t;
+typedef          long    int64_t;
+#endif
+#elif _STDINT_LONG_MODEL+0 == 448
+/*      LLP64   a 64-bit system derived from a 32-bit system */
+typedef unsigned char   uint8_t;
+typedef unsigned short  uint16_t;
+typedef unsigned int    uint32_t;
+#ifndef __int8_t_defined
+#define __int8_t_defined
+typedef          char    int8_t;
+typedef          short   int16_t;
+typedef          int     int32_t;
+#endif
+/* assuming the system has a "long long" */
+#ifndef _HAVE_UINT64_T
+#define _HAVE_UINT64_T
+#define _HAVE_LONGLONG_UINT64_T
+typedef unsigned long long uint64_t;
+typedef          long long  int64_t;
+#endif
+#else
+#define _STDINT_NO_INT32_T
+#endif
+#else
+#define _STDINT_NO_INT8_T
+#define _STDINT_NO_INT32_T
+#endif
+#endif
+
+/*
+ * quote from SunOS-5.8 sys/inttypes.h:
+ * Use at your own risk.  As of February 1996, the committee is squarely
+ * behind the fixed sized types; the "least" and "fast" types are still being
+ * discussed.  The probability that the "fast" types may be removed before
+ * the standard is finalized is high enough that they are not currently
+ * implemented.
+ */
+
+#if defined _STDINT_NEED_INT_LEAST_T
+typedef  int8_t    int_least8_t;
+typedef  int16_t   int_least16_t;
+typedef  int32_t   int_least32_t;
+#ifdef _HAVE_UINT64_T
+typedef  int64_t   int_least64_t;
+#endif
+
+typedef uint8_t   uint_least8_t;
+typedef uint16_t  uint_least16_t;
+typedef uint32_t  uint_least32_t;
+#ifdef _HAVE_UINT64_T
+typedef uint64_t  uint_least64_t;
+#endif
+  /* least types */
+#endif
+
+#if defined _STDINT_NEED_INT_FAST_T
+typedef  int8_t    int_fast8_t;
+typedef  int       int_fast16_t;
+typedef  int32_t   int_fast32_t;
+#ifdef _HAVE_UINT64_T
+typedef  int64_t   int_fast64_t;
+#endif
+
+typedef uint8_t   uint_fast8_t;
+typedef unsigned  uint_fast16_t;
+typedef uint32_t  uint_fast32_t;
+#ifdef _HAVE_UINT64_T
+typedef uint64_t  uint_fast64_t;
+#endif
+  /* fast types */
+#endif
+
+#ifdef _STDINT_NEED_INTMAX_T
+#ifdef _HAVE_UINT64_T
+typedef  int64_t       intmax_t;
+typedef uint64_t      uintmax_t;
+#else
+typedef          long  intmax_t;
+typedef unsigned long uintmax_t;
+#endif
+#endif
+
+#ifdef _STDINT_NEED_INTPTR_T
+#ifndef __intptr_t_defined
+#define __intptr_t_defined
+/* we encourage using "long" to store pointer values, never use "int" ! */
+#if   _STDINT_LONG_MODEL+0 == 242 || _STDINT_LONG_MODEL+0 == 484
+typedef  unsigned int   uintptr_t;
+typedef           int    intptr_t;
+#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL+0 == 444
+typedef  unsigned long  uintptr_t;
+typedef           long   intptr_t;
+#elif _STDINT_LONG_MODEL+0 == 448 && defined _HAVE_UINT64_T
+typedef        uint64_t uintptr_t;
+typedef         int64_t  intptr_t;
+#else /* matches typical system types ILP32 and LP64 - but not IP16 or LLP64 */
+typedef  unsigned long  uintptr_t;
+typedef           long   intptr_t;
+#endif
+#endif
+#endif
+
+/* The ISO C99 standard specifies that in C++ implementations these
+   should only be defined if explicitly requested.  */
+#if !defined __cplusplus || defined __STDC_CONSTANT_MACROS
+#ifndef UINT32_C
+
+/* Signed.  */
+# define INT8_C(c)      c
+# define INT16_C(c)     c
+# define INT32_C(c)     c
+# ifdef _HAVE_LONGLONG_UINT64_T
+#  define INT64_C(c)    c ## L
+# else
+#  define INT64_C(c)    c ## LL
+# endif
+
+/* Unsigned.  */
+# define UINT8_C(c)     c ## U
+# define UINT16_C(c)    c ## U
+# define UINT32_C(c)    c ## U
+# ifdef _HAVE_LONGLONG_UINT64_T
+#  define UINT64_C(c)   c ## UL
+# else
+#  define UINT64_C(c)   c ## ULL
+# endif
+
+/* Maximal type.  */
+# ifdef _HAVE_LONGLONG_UINT64_T
+#  define INTMAX_C(c)   c ## L
+#  define UINTMAX_C(c)  c ## UL
+# else
+#  define INTMAX_C(c)   c ## LL
+#  define UINTMAX_C(c)  c ## ULL
+# endif
+
+  /* literalnumbers */
+#endif
+#endif
+
+/* These limits are merily those of a two complement byte-oriented system */
+
+/* Minimum of signed integral types.  */
+# define INT8_MIN               (-128)
+# define INT16_MIN              (-32767-1)
+# define INT32_MIN              (-2147483647-1)
+#ifndef INT64_MIN
+# define INT64_MIN              (-__INT64_C(9223372036854775807)-1)
+#endif
+/* Maximum of signed integral types.  */
+# define INT8_MAX               (127)
+# define INT16_MAX              (32767)
+# define INT32_MAX              (2147483647)
+#ifndef INT64_MAX
+# define INT64_MAX              (__INT64_C(9223372036854775807))
+#endif
+
+/* Maximum of unsigned integral types.  */
+#ifndef UINT8_MAX
+# define UINT8_MAX              (255)
+#endif
+#ifndef UINT16_MAX
+# define UINT16_MAX             (65535)
+#endif
+# define UINT32_MAX             (4294967295U)
+#ifndef UINT64_MAX
+# define UINT64_MAX             (__UINT64_C(18446744073709551615))
+#endif
+
+/* Minimum of signed integral types having a minimum size.  */
+# define INT_LEAST8_MIN         INT8_MIN
+# define INT_LEAST16_MIN        INT16_MIN
+# define INT_LEAST32_MIN        INT32_MIN
+# define INT_LEAST64_MIN        INT64_MIN
+/* Maximum of signed integral types having a minimum size.  */
+# define INT_LEAST8_MAX         INT8_MAX
+# define INT_LEAST16_MAX        INT16_MAX
+# define INT_LEAST32_MAX        INT32_MAX
+# define INT_LEAST64_MAX        INT64_MAX
+
+/* Maximum of unsigned integral types having a minimum size.  */
+# define UINT_LEAST8_MAX        UINT8_MAX
+# define UINT_LEAST16_MAX       UINT16_MAX
+# define UINT_LEAST32_MAX       UINT32_MAX
+# define UINT_LEAST64_MAX       UINT64_MAX
+
+  /* shortcircuit*/
+#endif
+  /* once */
+#endif
+#endif
+STDINT_EOF
+fi
+    if cmp -s $ac_stdint_h $ac_stdint 2>/dev/null; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_stdint_h is unchanged" >&5
+$as_echo "$as_me: $ac_stdint_h is unchanged" >&6;}
+    else
+      ac_dir=`$as_dirname -- "$ac_stdint_h" ||
+$as_expr X"$ac_stdint_h" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_stdint_h" : 'X\(//\)[^/]' \| \
+	 X"$ac_stdint_h" : 'X\(//\)$' \| \
+	 X"$ac_stdint_h" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_stdint_h" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      as_dir="$ac_dir"; as_fn_mkdir_p
+      rm -f $ac_stdint_h
+      mv $ac_stdint $ac_stdint_h
+    fi
+ ;;
+    "$ax_create_pkgconfig_generate":C)
+pkgconfig_generate="$ax_create_pkgconfig_generate"
+if test ! -f "$pkgconfig_generate.in"
+then generate="true"
+elif grep ' generated by configure ' $pkgconfig_generate.in >/dev/null
+then generate="true"
+else generate="false";
+fi
+if $generate ; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $pkgconfig_generate.in" >&5
+$as_echo "$as_me: creating $pkgconfig_generate.in" >&6;}
+cat > $pkgconfig_generate.in <<AXEOF
+# generated by configure / remove this line to disable regeneration
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+libdir=@libdir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+includedir=@includedir@
+package=@PACKAGE@
+suffix=@suffix@
+
+Name: @PACKAGE_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @PACKAGE_VERSION@
+Requires: @PACKAGE_REQUIRES@
+Libs: -L\${libdir} @LDFLAGS@ @LIBS@
+Cflags: -I\${includedir} @CPPFLAGS@
+AXEOF
+fi # DONE generate $pkgconfig_generate.in
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $pkgconfig_generate" >&5
+$as_echo "$as_me: creating $pkgconfig_generate" >&6;}
+cat >conftest.sed <<AXEOF
+s|@prefix@|${pkgconfig_prefix}|
+s|@exec_prefix@|${pkgconfig_execprefix}|
+s|@bindir@|${pkgconfig_bindir}|
+s|@libdir@|${pkgconfig_libdir}|
+s|@datarootdir@|${pkgconfig_datarootdir}|
+s|@datadir@|${pkgconfig_datadir}|
+s|@sysconfdir@|${pkgconfig_sysconfdir}|
+s|@includedir@|${pkgconfig_includedir}|
+s|@suffix@|${pkgconfig_suffix}|
+s|@PACKAGE@|${pkgconfig_package}|
+s|@PACKAGE_NAME@|${pkgconfig_libname}|
+s|@PACKAGE_DESCRIPTION@|${pkgconfig_description}|
+s|@PACKAGE_VERSION@|${pkgconfig_version}|
+s|@PACKAGE_REQUIRES@|${pkgconfig_requires}|
+s|@LIBS@|${pkgconfig_libs}|
+s|@LDFLAGS@|${pkgconfig_ldflags}|
+s|@CPPFLAGS@|${pkgconfig_cppflags}|
+AXEOF
+sed -f conftest.sed  $pkgconfig_generate.in > $pkgconfig_generate
+if test ! -s $pkgconfig_generate ; then
+    as_fn_error $? "$pkgconfig_generate is empty" "$LINENO" 5
+fi ; rm conftest.sed # DONE generate $pkgconfig_generate
+pkgconfig_uninstalled=`echo $pkgconfig_generate |sed 's/.pc$/-uninstalled.pc/'`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $pkgconfig_uninstalled" >&5
+$as_echo "$as_me: creating $pkgconfig_uninstalled" >&6;}
+cat >conftest.sed <<AXEOF
+s|@prefix@|${pkgconfig_prefix}|
+s|@exec_prefix@|${pkgconfig_execprefix}|
+s|@bindir@|${pkgconfig_bindir}|
+s|@libdir@|${pkgconfig_src_libdir}|
+s|@datarootdir@|${pkgconfig_datarootdir}|
+s|@datadir@|${pkgconfig_datadir}|
+s|@sysconfdir@|${pkgconfig_sysconfdir}|
+s|@includedir@|${pkgconfig_src_headers}|
+s|@suffix@|${pkgconfig_suffix}|
+s|@PACKAGE@|${pkgconfig_package}|
+s|@PACKAGE_NAME@|${pkgconfig_libname}|
+s|@PACKAGE_DESCRIPTION@|${pkgconfig_description}|
+s|@PACKAGE_VERSION@|${pkgconfig_version}|
+s|@PACKAGE_REQUIRES@|${pkgconfig_requires}|
+s|@LIBS@|${pkgconfig_libs}|
+s|@LDFLAGS@|${pkgconfig_ldflags}|
+s|@CPPFLAGS@|${pkgconfig_cppflags}|
+AXEOF
+sed -f conftest.sed $pkgconfig_generate.in > $pkgconfig_uninstalled
+if test ! -s $pkgconfig_uninstalled ; then
+    as_fn_error $? "$pkgconfig_uninstalled is empty" "$LINENO" 5
+fi ; rm conftest.sed # DONE generate $pkgconfig_uninstalled
+           pkgconfig_requires_add=`echo ${pkgconfig_requires}`
+if test ".$pkgconfig_requires_add" != "." ; then
+           pkgconfig_requires_add="pkg-config $pkgconfig_requires_add"
+    else   pkgconfig_requires_add=":" ; fi
+pkgconfig_uninstalled=`echo $pkgconfig_generate |sed 's/.pc$/-uninstalled.sh/'`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $pkgconfig_uninstalled" >&5
+$as_echo "$as_me: creating $pkgconfig_uninstalled" >&6;}
+cat >conftest.sed <<AXEOF
+s|@prefix@|\"${pkgconfig_prefix}\"|
+s|@exec_prefix@|\"${pkgconfig_execprefix}\"|
+s|@bindir@|\"${pkgconfig_bindir}\"|
+s|@libdir@|\"${pkgconfig_src_libdir}\"|
+s|@datarootdir@|\"${pkgconfig_datarootdir}\"|
+s|@datadir@|\"${pkgconfig_datadir}\"|
+s|@sysconfdir@|\"${pkgconfig_sysconfdir}\"|
+s|@includedir@|\"${pkgconfig_src_headers}\"|
+s|@suffix@|\"${pkgconfig_suffix}\"|
+s|@PACKAGE@|\"${pkgconfig_package}\"|
+s|@PACKAGE_NAME@|\"${pkgconfig_libname}\"|
+s|@PACKAGE_DESCRIPTION@|\"${pkgconfig_description}\"|
+s|@PACKAGE_VERSION@|\"${pkgconfig_version}\"|
+s|@PACKAGE_REQUIRES@|\"${pkgconfig_requires}\"|
+s|@LIBS@|\"${pkgconfig_libs}\"|
+s|@LDFLAGS@|\"${pkgconfig_ldflags}\"|
+s|@CPPFLAGS@|\"${pkgconfig_cppflags}\"|
+s>Name:>for option\\; do case \"\$option\" in --list-all|--name) echo >
+s>Description: *>\\;\\; --help) pkg-config --help \\; echo Buildscript Of >
+s>Version: *>\\;\\; --modversion|--version) echo >
+s>Requires:>\\;\\; --requires) echo $pkgconfig_requires_add>
+s>Libs: *>\\;\\; --libs) echo >
+s>Cflags: *>\\;\\; --cflags) echo >
+/--libs)/a\\
+       $pkgconfig_requires_add
+/--cflags)/a\\
+       $pkgconfig_requires_add\\
+;; --variable=*) eval echo '\$'\`echo \$option | sed -e 's/.*=//'\`\\
+;; --uninstalled) exit 0 \\
+;; *) ;; esac done
+AXEOF
+sed -f conftest.sed  $pkgconfig_generate.in > $pkgconfig_uninstalled
+if test ! -s $pkgconfig_uninstalled ; then
+    as_fn_error $? "$pkgconfig_uninstalled is empty" "$LINENO" 5
+fi ; rm conftest.sed # DONE generate $pkgconfig_uninstalled
+ ;;
+    "bound_test.sh":F) chmod +x bound_test.sh ;;
+    "codegen_test.sh":F) chmod +x codegen_test.sh ;;
+    "pip_test.sh":F) chmod +x pip_test.sh ;;
+    "flow_test.sh":F) chmod +x flow_test.sh ;;
+    "schedule_test.sh":F) chmod +x schedule_test.sh ;;
+
+  esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+			ac_configure_args="$ac_configure_args $isl_configure_args"
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/final/lib/External/isl/configure.ac b/final/lib/External/isl/configure.ac
new file mode 100644
index 0000000..5de7b5a
--- /dev/null
+++ b/final/lib/External/isl/configure.ac
@@ -0,0 +1,149 @@
+AC_INIT([isl], [0.18], [isl-development@googlegroups.com])
+AC_CONFIG_AUX_DIR([.])
+AC_CONFIG_MACRO_DIR([m4])
+AM_INIT_AUTOMAKE([foreign])
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
+AC_SUBST(versioninfo)
+versioninfo=18:0:3
+
+if test "x$prefix" != "xNONE"; then
+	prefix_wd=`cd $prefix && pwd`
+	srcdir_wd=`cd $srcdir && pwd`
+	wd=`pwd`
+	if test "x$prefix_wd" = "x$srcdir_wd"; then
+		AC_MSG_ERROR(Installation in source directory not supported)
+	fi
+	if test "x$prefix_wd" = "x$wd"; then
+		AC_MSG_ERROR(Installation in build directory not supported)
+	fi
+fi
+
+AC_PROG_CC
+AC_PROG_CXX
+
+AX_CC_MAXOPT
+AX_GCC_WARN_UNUSED_RESULT
+AX_C___ATTRIBUTE__
+
+# CXX11FLAGS contains the flags (if any) added by AX_CXX_COMPILE_STDCXX_11
+# Original state of CXX and CXXCPP is preserved because CXX11FLAGS
+# is only needed for compiling interface/isl_test_cpp
+AC_SUBST(CXX11FLAGS)
+ac_save_CXX="$CXX"
+ac_save_CXXCPP="$CXXCPP"
+AX_CXX_COMPILE_STDCXX_11([noext], [optional])
+CXX11FLAGS=${CXX#$ac_save_CXX}
+CXX="$ac_save_CXX"
+CXXCPP="$ac_save_CXXCPP"
+
+AC_PROG_GREP
+AC_PROG_LIBTOOL
+AC_PROG_SED
+
+AC_CHECK_PROG(PERL, perl, perl, [])
+AC_CHECK_PROG(PDFLATEX, pdflatex, pdflatex, [])
+AC_CHECK_PROG(POD2HTML, pod2html, pod2html, [])
+
+AM_CONDITIONAL(GENERATE_DOC, test -n "$PERL" -a -n "$PDFLATEX" -a -n "$POD2HTML")
+
+AX_CREATE_STDINT_H(include/isl/stdint.h)
+
+AC_ARG_WITH([int],
+	    [AS_HELP_STRING([--with-int=gmp|imath|imath-32],
+			    [Which package to use to represent
+				multi-precision integers [default=gmp]])],
+	    [], [with_int=gmp])
+case "$with_int" in
+gmp|imath|imath-32)
+	;;
+*)
+	AC_MSG_ERROR(
+	    [bad value ${withval} for --with-int (use gmp, imath or imath-32)])
+esac
+
+AC_SUBST(MP_CPPFLAGS)
+AC_SUBST(MP_LDFLAGS)
+AC_SUBST(MP_LIBS)
+case "$with_int" in
+gmp)
+	AX_DETECT_GMP
+	;;
+imath|imath-32)
+	AX_DETECT_IMATH
+	;;
+esac
+if test "x$with_int" = "ximath-32" -a "x$GCC" = "xyes"; then
+	MP_CPPFLAGS="-std=gnu99 $MP_CPPFLAGS"
+fi
+
+AM_CONDITIONAL(IMATH_FOR_MP, test x$with_int = ximath -o x$with_int = ximath-32)
+AM_CONDITIONAL(GMP_FOR_MP, test x$with_int = xgmp)
+
+AM_CONDITIONAL(HAVE_CXX11, test "x$HAVE_CXX11" = "x1")
+AM_CONDITIONAL(SMALL_INT_OPT, test "x$with_int" == "ximath-32")
+AS_IF([test "x$with_int" == "ximath-32"], [
+	AC_DEFINE([USE_SMALL_INT_OPT], [], [Use small integer optimization])
+])
+
+AC_CHECK_DECLS(ffs,[],[],[#include <strings.h>])
+AC_CHECK_DECLS(__builtin_ffs,[],[],[])
+AC_CHECK_DECLS([_BitScanForward],[],[],[#include <intrin.h>])
+if test "x$ac_cv_have_decl_ffs" = xno -a \
+		"x$ac_cv_have_decl___builtin_ffs" = xno -a \
+		"x$ac_cv_have_decl__BitScanForward" = xno; then
+	AC_MSG_ERROR([No ffs implementation found])
+fi
+AC_CHECK_DECLS([strcasecmp,strncasecmp],[],[],[#include <strings.h>])
+AC_CHECK_DECLS([_stricmp,_strnicmp],[],[],[#include <string.h>])
+if test "x$ac_cv_have_decl_strcasecmp" = xno -a \
+		"x$ac_cv_have_decl__stricmp" = xno; then
+	AC_MSG_ERROR([No strcasecmp implementation found])
+fi
+if test "x$ac_cv_have_decl_strncasecmp" = xno -a \
+		"x$ac_cv_have_decl__strnicmp" = xno; then
+	AC_MSG_ERROR([No strncasecmp implementation found])
+fi
+AC_CHECK_DECLS([snprintf,_snprintf],[],[],[#include <stdio.h>])
+if test "x$ac_cv_have_decl_snprintf" = xno -a \
+		"x$ac_cv_have_decl__snprintf" = xno; then
+	AC_MSG_ERROR([No snprintf implementation found])
+fi
+
+AX_SUBMODULE(clang,system|no,no)
+case "$with_clang" in
+system)
+	AX_DETECT_CLANG
+	;;
+esac
+AM_CONDITIONAL(HAVE_CLANG, test $with_clang = system)
+
+AX_SET_WARNING_FLAGS
+
+AC_SUBST(WARNING_FLAGS)
+
+PACKAGE_CFLAGS="$MP_CPPFLAGS"
+PACKAGE_LDFLAGS="$MP_LDFLAGS"
+PACKAGE_LIBS="-lisl $MP_LIBS"
+AX_CREATE_PKGCONFIG_INFO
+
+AX_DETECT_GIT_HEAD
+
+AH_BOTTOM([#include <isl_config_post.h>])
+AC_CONFIG_HEADERS(isl_config.h)
+AC_CONFIG_FILES(isl_srcdir.c)
+AC_CONFIG_FILES(Makefile)
+AC_CONFIG_FILES(doc/Makefile)
+if test $with_clang = system; then
+	AC_CONFIG_FILES(interface/Makefile)
+fi
+AC_CONFIG_FILES([bound_test.sh], [chmod +x bound_test.sh])
+AC_CONFIG_FILES([codegen_test.sh], [chmod +x codegen_test.sh])
+AC_CONFIG_FILES([pip_test.sh], [chmod +x pip_test.sh])
+AC_CONFIG_FILES([flow_test.sh], [chmod +x flow_test.sh])
+AC_CONFIG_FILES([schedule_test.sh], [chmod +x schedule_test.sh])
+AC_CONFIG_COMMANDS_POST([
+	dnl pass on arguments to subdir configures, but don't
+	dnl add them to config.status
+	ac_configure_args="$ac_configure_args $isl_configure_args"
+])
+AC_OUTPUT
diff --git a/final/lib/External/isl/depcomp b/final/lib/External/isl/depcomp
new file mode 100755
index 0000000..fc98710
--- /dev/null
+++ b/final/lib/External/isl/depcomp
@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2013-05-30.07; # UTC
+
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+  '')
+    echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+    exit 1;
+    ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+  depmode     Dependency tracking mode.
+  source      Source file read by 'PROGRAMS ARGS'.
+  object      Object file output by 'PROGRAMS ARGS'.
+  DEPDIR      directory where to store dependencies.
+  depfile     Dependency file to output.
+  tmpdepfile  Temporary file to use when outputting dependencies.
+  libtool     Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "depcomp $scriptversion"
+    exit $?
+    ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'.  Note that this directory component will
+# be either empty or ending with a '/' character.  This is deliberate.
+set_dir_from ()
+{
+  case $1 in
+    */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+      *) dir=;;
+  esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+  base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+  echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+  # If the compiler actually managed to produce a dependency file,
+  # post-process it.
+  if test -f "$tmpdepfile"; then
+    # Each line is of the form 'foo.o: dependency.h'.
+    # Do two passes, one to just change these to
+    #   $object: dependency.h
+    # and one to simply output
+    #   dependency.h:
+    # which is needed to avoid the deleted-header problem.
+    { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+      sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+    } > "$depfile"
+    rm -f "$tmpdepfile"
+  else
+    make_dummy_depfile
+  fi
+}
+
+# A tabulation character.
+tab='	'
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+  # This is just like dashmstdout with a different argument.
+  dashmflag=-xM
+  depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+  # This is just like msvisualcpp but w/o cygpath translation.
+  # Just convert the backslash-escaped backslashes to single forward
+  # slashes to satisfy depend.m4
+  cygpath_u='sed s,\\\\,/,g'
+  depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+  # This is just like msvc7 but w/o cygpath translation.
+  # Just convert the backslash-escaped backslashes to single forward
+  # slashes to satisfy depend.m4
+  cygpath_u='sed s,\\\\,/,g'
+  depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+  # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+  gccflag=-qmakedep=gcc,-MF
+  depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am.  Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+  for arg
+  do
+    case $arg in
+    -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+    *)  set fnord "$@" "$arg" ;;
+    esac
+    shift # fnord
+    shift # $arg
+  done
+  "$@"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).  Also, it might not be
+##   supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The second -e expression handles DOS-style file names with drive
+  # letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'.  On the theory
+## that the space means something, we add a space to the output as
+## well.  hp depmode also adds that space, but also prefixes the VPATH
+## to the object.  Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+  tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like '#:fec' to the end of the
+    # dependency line.
+    tr ' ' "$nl" < "$tmpdepfile" \
+      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+      | tr "$nl" ' ' >> "$depfile"
+    echo >> "$depfile"
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' "$nl" < "$tmpdepfile" \
+      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+      >> "$depfile"
+  else
+    make_dummy_depfile
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+xlc)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts '$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  set_dir_from "$object"
+  set_base_from "$object"
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$base.u
+    tmpdepfile3=$dir.libs/$base.u
+    "$@" -Wc,-M
+  else
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$dir$base.u
+    tmpdepfile3=$dir$base.u
+    "$@" -M
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  aix_post_process_depfile
+  ;;
+
+tcc)
+  # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+  # FIXME: That version still under development at the moment of writing.
+  #        Make that this statement remains true also for stable, released
+  #        versions.
+  # It will wrap lines (doesn't matter whether long or short) with a
+  # trailing '\', as in:
+  #
+  #   foo.o : \
+  #    foo.c \
+  #    foo.h \
+  #
+  # It will put a trailing '\' even on the last line, and will use leading
+  # spaces rather than leading tabs (at least since its commit 0394caf7
+  # "Emit spaces for -MD").
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+  # We have to change lines of the first kind to '$object: \'.
+  sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+  # And for each line of the second kind, we have to emit a 'dep.h:'
+  # dummy dependency, to avoid the deleted-header problem.
+  sed -n -e 's|^  *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file.  A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+  # Portland's C compiler understands '-MD'.
+  # Will always output deps to 'file.d' where file is the root name of the
+  # source file under compilation, even if file resides in a subdirectory.
+  # The object file name does not affect the name of the '.d' file.
+  # pgcc 10.2 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using '\' :
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+  set_dir_from "$object"
+  # Use the source, not the object, to determine the base name, since
+  # that's sadly what pgcc will do too.
+  set_base_from "$source"
+  tmpdepfile=$base.d
+
+  # For projects that build the same source file twice into different object
+  # files, the pgcc approach of using the *source* file root name can cause
+  # problems in parallel builds.  Use a locking strategy to avoid stomping on
+  # the same $tmpdepfile.
+  lockdir=$base.d-lock
+  trap "
+    echo '$0: caught signal, cleaning up...' >&2
+    rmdir '$lockdir'
+    exit 1
+  " 1 2 13 15
+  numtries=100
+  i=$numtries
+  while test $i -gt 0; do
+    # mkdir is a portable test-and-set.
+    if mkdir "$lockdir" 2>/dev/null; then
+      # This process acquired the lock.
+      "$@" -MD
+      stat=$?
+      # Release the lock.
+      rmdir "$lockdir"
+      break
+    else
+      # If the lock is being held by a different process, wait
+      # until the winning process is done or we timeout.
+      while test -d "$lockdir" && test $i -gt 0; do
+        sleep 1
+        i=`expr $i - 1`
+      done
+    fi
+    i=`expr $i - 1`
+  done
+  trap - 1 2 13 15
+  if test $i -le 0; then
+    echo "$0: failed to acquire lock after $numtries attempts" >&2
+    echo "$0: check lockdir '$lockdir'" >&2
+    exit 1
+  fi
+
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form `foo.o: dependent.h',
+  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # `$object: dependent.h' and one to simply `dependent.h:'.
+  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp2)
+  # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+  # compilers, which have integrated preprocessors.  The correct option
+  # to use with these is +Maked; it writes dependencies to a file named
+  # 'foo.d', which lands next to the object file, wherever that
+  # happens to be.
+  # Much of this is similar to the tru64 case; see comments there.
+  set_dir_from  "$object"
+  set_base_from "$object"
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir.libs/$base.d
+    "$@" -Wc,+Maked
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    "$@" +Maked
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+     rm -f "$tmpdepfile1" "$tmpdepfile2"
+     exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+    # Add 'dependent.h:' lines.
+    sed -ne '2,${
+               s/^ *//
+               s/ \\*$//
+               s/$/:/
+               p
+             }' "$tmpdepfile" >> "$depfile"
+  else
+    make_dummy_depfile
+  fi
+  rm -f "$tmpdepfile" "$tmpdepfile2"
+  ;;
+
+tru64)
+  # The Tru64 compiler uses -MD to generate dependencies as a side
+  # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+  # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+  # dependencies in 'foo.d' instead, so we check for that too.
+  # Subdirectories are respected.
+  set_dir_from  "$object"
+  set_base_from "$object"
+
+  if test "$libtool" = yes; then
+    # Libtool generates 2 separate objects for the 2 libraries.  These
+    # two compilations output dependencies in $dir.libs/$base.o.d and
+    # in $dir$base.o.d.  We have to check for both files, because
+    # one of the two compilations can be disabled.  We should prefer
+    # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+    # automatically cleaned when .libs/ is deleted, while ignoring
+    # the former would cause a distcleancheck panic.
+    tmpdepfile1=$dir$base.o.d          # libtool 1.5
+    tmpdepfile2=$dir.libs/$base.o.d    # Likewise.
+    tmpdepfile3=$dir.libs/$base.d      # Compaq CCC V6.2-504
+    "$@" -Wc,-MD
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    tmpdepfile3=$dir$base.d
+    "$@" -MD
+  fi
+
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  # Same post-processing that is required for AIX mode.
+  aix_post_process_depfile
+  ;;
+
+msvc7)
+  if test "$libtool" = yes; then
+    showIncludes=-Wc,-showIncludes
+  else
+    showIncludes=-showIncludes
+  fi
+  "$@" $showIncludes > "$tmpdepfile"
+  stat=$?
+  grep -v '^Note: including file: ' "$tmpdepfile"
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The first sed program below extracts the file names and escapes
+  # backslashes for cygpath.  The second sed program outputs the file
+  # name when reading, but also accumulates all include files in the
+  # hold buffer in order to output them again at the end.  This only
+  # works with sed implementations that can handle large buffers.
+  sed < "$tmpdepfile" -n '
+/^Note: including file:  *\(.*\)/ {
+  s//\1/
+  s/\\/\\\\/g
+  p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+  s/.*/'"$tab"'/
+  G
+  p
+}' >> "$depfile"
+  echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+  rm -f "$tmpdepfile"
+  ;;
+
+msvc7msys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for ':'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+  "$@" $dashmflag |
+    sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this sed invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no eat=no
+  for arg
+  do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    if test $eat = yes; then
+      eat=no
+      continue
+    fi
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -arch)
+      eat=yes ;;
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix=`echo "$object" | sed 's/^.*\././'`
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  # makedepend may prepend the VPATH from the source file name to the object.
+  # No need to regex-escape $object, excess matching of '.' is harmless.
+  sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process the last invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed '1,2d' "$tmpdepfile" \
+    | tr ' ' "$nl" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E \
+    | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+             -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+    | sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+        set fnord "$@"
+        shift
+        shift
+        ;;
+    *)
+        set fnord "$@" "$arg"
+        shift
+        shift
+        ;;
+    esac
+  done
+  "$@" -E 2>/dev/null |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+  echo "$tab" >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvcmsys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/final/lib/External/isl/doc/CodingStyle b/final/lib/External/isl/doc/CodingStyle
new file mode 100644
index 0000000..21f2e56
--- /dev/null
+++ b/final/lib/External/isl/doc/CodingStyle
@@ -0,0 +1,42 @@
+This document describes some aspects of the coding style of isl,
+which is similar to that of the linux kernel and git.
+
+The general rule is to use the same style as that of the surrounding code.
+
+More specific rules:
+	- every line should have at most 80 columns
+	- use tabs for indentation, where a tab counts for 8 characters
+	- use single spaces around binary operators such as '+', '-', '=', '!='
+	- no space after unary operators such as '!'
+	- use a single space after a comma and a semicolon
+	  (except at the end of a line)
+	- no space between function name and arguments
+	- use a single space after control keywords such as if, for and while
+	- use a single space between the type of a cast and the value
+	  that is being cast
+	- no whitespace at the end of a line
+	- opening brace of a function is placed on a new line
+	- opening brace of other blocks stays on the same line
+	- the body of a control statement is placed on the next line(s)
+	- an else appears on the same line as the closing brace of
+	  the then branch, if there is such a closing brace
+	- if either the then or the else branch of an if has braces,
+	  then they both have braces
+	- no parentheses around argument of return keyword
+	- use only C style comments (/* ... */)
+	- no comments inside function bodies;
+	  if some part of a function deserves additional comments, then
+	  extract it out into a separate function first
+	- no #ifs inside function bodies
+	- variables are declared at the start of a block, before any
+	  other statements
+
+There are some exceptions to the general rule of using
+the same style as the surrounding code, most notably
+when the surrounding code is very old.
+In particular, an "isl_space" used to be called "isl_dim" and
+some variables of this type are still called "dim" or some variant thereof.
+New variables of this type should be called "space" or a more specific name.
+Some old functions do not have memory management annotations yet.
+All new functions should have memory management annotations,
+whenever appropriate
diff --git a/final/lib/External/isl/doc/Makefile.am b/final/lib/External/isl/doc/Makefile.am
new file mode 100644
index 0000000..1d61dd7
--- /dev/null
+++ b/final/lib/External/isl/doc/Makefile.am
@@ -0,0 +1,32 @@
+
+CLEANFILES = \
+	manual.toc \
+	manual.bbl \
+	version.tex \
+	user.tex \
+	manual.pdf \
+	manual.aux \
+	manual.out \
+	manual.blg \
+	manual.log \
+	manual.brf \
+	manual.bcf \
+	manual.run.xml
+
+if GENERATE_DOC
+export TEXINPUTS := $(srcdir):$(TEXINPUTS)
+export BIBINPUTS := $(srcdir):$(BIBINPUTS)
+export BSTINPUTS := $(srcdir):$(BSTINPUTS)
+
+user.tex: user.pod
+	$(PERL) $(srcdir)/mypod2latex $< $@
+manual.pdf: manual.tex user.tex $(srcdir)/implementation.tex reading.tex
+	(cd ..; echo "@GIT_HEAD_VERSION@") > version.tex
+	$(PDFLATEX) $<
+	biber manual
+	$(PDFLATEX) $<
+	$(PDFLATEX) $<
+user.html: user.pod
+	(cd ..; echo "@GIT_HEAD_VERSION@") > version
+	$(POD2HTML) --infile=$< --outfile=$@ --title="Integer Set Library: Manual [version `cat version`]"
+endif
diff --git a/final/lib/External/isl/doc/Makefile.in b/final/lib/External/isl/doc/Makefile.in
new file mode 100644
index 0000000..b5d1905
--- /dev/null
+++ b/final/lib/External/isl/doc/Makefile.in
@@ -0,0 +1,508 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \
+	$(top_srcdir)/m4/ax_cc_maxopt.m4 \
+	$(top_srcdir)/m4/ax_check_compiler_flags.m4 \
+	$(top_srcdir)/m4/ax_compiler_vendor.m4 \
+	$(top_srcdir)/m4/ax_create_pkgconfig_info.m4 \
+	$(top_srcdir)/m4/ax_create_stdint_h.m4 \
+	$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+	$(top_srcdir)/m4/ax_detect_clang.m4 \
+	$(top_srcdir)/m4/ax_detect_git_head.m4 \
+	$(top_srcdir)/m4/ax_detect_gmp.m4 \
+	$(top_srcdir)/m4/ax_detect_imath.m4 \
+	$(top_srcdir)/m4/ax_gcc_archflag.m4 \
+	$(top_srcdir)/m4/ax_gcc_warn_unused_result.m4 \
+	$(top_srcdir)/m4/ax_gcc_x86_cpuid.m4 \
+	$(top_srcdir)/m4/ax_set_warning_flags.m4 \
+	$(top_srcdir)/m4/ax_submodule.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/isl_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLANG_CXXFLAGS = @CLANG_CXXFLAGS@
+CLANG_LDFLAGS = @CLANG_LDFLAGS@
+CLANG_LIBS = @CLANG_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXX11FLAGS = @CXX11FLAGS@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GIT_HEAD = @GIT_HEAD@
+GIT_HEAD_ID = @GIT_HEAD_ID@
+GIT_HEAD_VERSION = @GIT_HEAD_VERSION@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_CLANG_EDIT = @LIB_CLANG_EDIT@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MP_CPPFLAGS = @MP_CPPFLAGS@
+MP_LDFLAGS = @MP_LDFLAGS@
+MP_LIBS = @MP_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PERL = @PERL@
+POD2HTML = @POD2HTML@
+PRTDIAG = @PRTDIAG@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARNING_FLAGS = @WARNING_FLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+llvm_config_found = @llvm_config_found@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfig_libdir = @pkgconfig_libdir@
+pkgconfig_libfile = @pkgconfig_libfile@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+versioninfo = @versioninfo@
+CLEANFILES = \
+	manual.toc \
+	manual.bbl \
+	version.tex \
+	user.tex \
+	manual.pdf \
+	manual.aux \
+	manual.out \
+	manual.blg \
+	manual.log \
+	manual.brf \
+	manual.bcf \
+	manual.run.xml
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign doc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	cscopelist-am ctags-am distclean distclean-generic \
+	distclean-libtool distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+@GENERATE_DOC_TRUE@export TEXINPUTS := $(srcdir):$(TEXINPUTS)
+@GENERATE_DOC_TRUE@export BIBINPUTS := $(srcdir):$(BIBINPUTS)
+@GENERATE_DOC_TRUE@export BSTINPUTS := $(srcdir):$(BSTINPUTS)
+
+@GENERATE_DOC_TRUE@user.tex: user.pod
+@GENERATE_DOC_TRUE@	$(PERL) $(srcdir)/mypod2latex $< $@
+@GENERATE_DOC_TRUE@manual.pdf: manual.tex user.tex $(srcdir)/implementation.tex reading.tex
+@GENERATE_DOC_TRUE@	(cd ..; echo "@GIT_HEAD_VERSION@") > version.tex
+@GENERATE_DOC_TRUE@	$(PDFLATEX) $<
+@GENERATE_DOC_TRUE@	biber manual
+@GENERATE_DOC_TRUE@	$(PDFLATEX) $<
+@GENERATE_DOC_TRUE@	$(PDFLATEX) $<
+@GENERATE_DOC_TRUE@user.html: user.pod
+@GENERATE_DOC_TRUE@	(cd ..; echo "@GIT_HEAD_VERSION@") > version
+@GENERATE_DOC_TRUE@	$(POD2HTML) --infile=$< --outfile=$@ --title="Integer Set Library: Manual [version `cat version`]"
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/final/lib/External/isl/doc/SubmittingPatches b/final/lib/External/isl/doc/SubmittingPatches
new file mode 100644
index 0000000..2c2b938
--- /dev/null
+++ b/final/lib/External/isl/doc/SubmittingPatches
@@ -0,0 +1,52 @@
+[Mostly copied from git's SubmittingPatches]
+
+	Commits:
+
+	- make commits of logical units
+	- check for unnecessary whitespace with "git diff --check"
+	  before committing
+	- do not check in commented out code or unneeded files
+	- the first line of the commit message should be a short
+	  description and should skip the full stop
+	- the body should provide a meaningful commit message, which
+	  includes motivation for the change, and contrasts
+	  its implementation with previous behaviour
+	- if you want your work included in isl.git, add a
+	  "Signed-off-by: Your Name <you@example.com>" line to the
+	  commit message (or just use the option "-s" when
+	  committing) to confirm that you agree to the Developer's
+	  Certificate of Origin
+	- make sure that you have tests for the bug you are fixing
+	- make sure that the test suite passes after your commit
+
+	Patch:
+
+	- use "git format-patch -M" to create the patch
+	- do not PGP sign your patch
+	- send a single patch per mail, e.g., using git-send-email(1)
+	- do not attach your patch, but read in the mail
+	  body, unless you cannot teach your mailer to
+	  leave the formatting of the patch alone.
+	- be careful doing cut & paste into your mailer, not to
+	  corrupt whitespaces.
+	- provide additional information (which is unsuitable for
+	  the commit message) between the "---" and the diffstat
+	- if you change, add, or remove a command line option or
+	  make some other user interface change, the associated
+	  documentation should be updated as well.
+	- if your name is not writable in ASCII, make sure that
+	  you send off a message in the correct encoding.
+	- send the patch to the development mailing list
+	  (isl-development@googlegroups.com).  If you use
+	  git-send-email(1), please test it first by sending email
+	  to yourself.
+
+	Revisions:
+
+	- add the revision number inside square brackets to
+	  the subject line (e.g., use --subject-prefix='PATCH v2'
+	  when creating the patch)
+	- recall the major issues discovered during the previous
+	  review and explain how you addressed them or why you
+	  disagree.  Do so either in a cover letter, between the
+	  "---" and the diffstat or in a separate message.
diff --git a/final/lib/External/isl/doc/implementation.tex b/final/lib/External/isl/doc/implementation.tex
new file mode 100644
index 0000000..698adb9
--- /dev/null
+++ b/final/lib/External/isl/doc/implementation.tex
@@ -0,0 +1,2049 @@
+\section{Sets and Relations}
+
+\begin{definition}[Polyhedral Set]
+A {\em polyhedral set}\index{polyhedral set} $S$ is a finite union of basic sets
+$S = \bigcup_i S_i$, each of which can be represented using affine
+constraints
+$$
+S_i : \Z^n \to 2^{\Z^d} : \vec s \mapsto
+S_i(\vec s) =
+\{\, \vec x \in \Z^d \mid \exists \vec z \in \Z^e :
+A \vec x + B \vec s + D \vec z + \vec c \geq \vec 0 \,\}
+,
+$$
+with $A \in \Z^{m \times d}$,
+$B \in \Z^{m \times n}$,
+$D \in \Z^{m \times e}$
+and $\vec c \in \Z^m$.
+\end{definition}
+
+\begin{definition}[Parameter Domain of a Set]
+Let $S \in \Z^n \to 2^{\Z^d}$ be a set.
+The {\em parameter domain} of $S$ is the set
+$$\pdom S \coloneqq \{\, \vec s \in \Z^n \mid S(\vec s) \ne \emptyset \,\}.$$
+\end{definition}
+
+\begin{definition}[Polyhedral Relation]
+A {\em polyhedral relation}\index{polyhedral relation}
+$R$ is a finite union of basic relations
+$R = \bigcup_i R_i$ of type
+$\Z^n \to 2^{\Z^{d_1+d_2}}$,
+each of which can be represented using affine
+constraints
+$$
+R_i = \vec s \mapsto
+R_i(\vec s) =
+\{\, \vec x_1 \to \vec x_2 \in \Z^{d_1} \times \Z^{d_2}
+\mid \exists \vec z \in \Z^e :
+A_1 \vec x_1 + A_2 \vec x_2 + B \vec s + D \vec z + \vec c \geq \vec 0 \,\}
+,
+$$
+with $A_i \in \Z^{m \times d_i}$,
+$B \in \Z^{m \times n}$,
+$D \in \Z^{m \times e}$
+and $\vec c \in \Z^m$.
+\end{definition}
+
+\begin{definition}[Parameter Domain of a Relation]
+Let $R \in \Z^n \to 2^{\Z^{d+d}}$ be a relation.
+The {\em parameter domain} of $R$ is the set
+$$\pdom R \coloneqq \{\, \vec s \in \Z^n \mid R(\vec s) \ne \emptyset \,\}.$$
+\end{definition}
+
+\begin{definition}[Domain of a Relation]
+Let $R \in \Z^n \to 2^{\Z^{d+d}}$ be a relation.
+The {\em domain} of $R$ is the polyhedral set
+$$\domain R \coloneqq \vec s \mapsto
+\{\, \vec x_1 \in \Z^{d_1} \mid \exists \vec x_2 \in \Z^{d_2} :
+(\vec x_1, \vec x_2) \in R(\vec s) \,\}
+.
+$$
+\end{definition}
+
+\begin{definition}[Range of a Relation]
+Let $R \in \Z^n \to 2^{\Z^{d+d}}$ be a relation.
+The {\em range} of $R$ is the polyhedral set
+$$
+\range R \coloneqq \vec s \mapsto
+\{\, \vec x_2 \in \Z^{d_2} \mid \exists \vec x_1 \in \Z^{d_1} :
+(\vec x_1, \vec x_2) \in R(\vec s) \,\}
+.
+$$
+\end{definition}
+
+\begin{definition}[Composition of Relations]
+Let $R \in \Z^n \to 2^{\Z^{d_1+d_2}}$ and
+$S \in \Z^n \to 2^{\Z^{d_2+d_3}}$ be two relations,
+then the composition of
+$R$ and $S$ is defined as
+$$
+S \circ R \coloneqq
+\vec s \mapsto
+\{\, \vec x_1 \to \vec x_3 \in \Z^{d_1} \times \Z^{d_3}
+\mid \exists \vec x_2 \in \Z^{d_2} :
+\vec x_1 \to \vec x_2 \in R(\vec s) \wedge
+\vec x_2 \to \vec x_3 \in S(\vec s)
+\,\}
+.
+$$
+\end{definition}
+
+\begin{definition}[Difference Set of a Relation]
+Let $R \in \Z^n \to 2^{\Z^{d+d}}$ be a relation.
+The difference set ($\Delta \, R$) of $R$ is the set
+of differences between image elements and the corresponding
+domain elements,
+$$
+\diff R \coloneqq
+\vec s \mapsto
+\{\, \vec \delta \in \Z^{d} \mid \exists \vec x \to \vec y \in R :
+\vec \delta = \vec y - \vec x
+\,\}
+$$
+\end{definition}
+
+\section{Simple Hull}\label{s:simple hull}
+
+It is sometimes useful to have a single
+basic set or basic relation that contains a given set or relation.
+For rational sets, the obvious choice would be to compute the
+(rational) convex hull.  For integer sets, the obvious choice
+would be the integer hull.
+However, {\tt isl} currently does not support an integer hull operation
+and even if it did, it would be fairly expensive to compute.
+The convex hull operation is supported, but it is also fairly
+expensive to compute given only an implicit representation.
+
+Usually, it is not required to compute the exact integer hull,
+and an overapproximation of this hull is sufficient.
+The ``simple hull'' of a set is such an overapproximation
+and it is defined as the (inclusion-wise) smallest basic set
+that is described by constraints that are translates of
+the constraints in the input set.
+This means that the simple hull is relatively cheap to compute
+and that the number of constraints in the simple hull is no
+larger than the number of constraints in the input.
+\begin{definition}[Simple Hull of a Set]
+The {\em simple hull} of a set
+$S = \bigcup_{1 \le i \le v} S_i$, with
+$$
+S : \Z^n \to 2^{\Z^d} : \vec s \mapsto
+S(\vec s) =
+\left\{\, \vec x \in \Z^d \mid \exists \vec z \in \Z^e :
+\bigvee_{1 \le i \le v}
+A_i \vec x + B_i \vec s + D_i \vec z + \vec c_i \geq \vec 0 \,\right\}
+$$
+is the set
+$$
+H : \Z^n \to 2^{\Z^d} : \vec s \mapsto
+S(\vec s) =
+\left\{\, \vec x \in \Z^d \mid \exists \vec z \in \Z^e :
+\bigwedge_{1 \le i \le v}
+A_i \vec x + B_i \vec s + D_i \vec z + \vec c_i + \vec K_i \geq \vec 0
+\,\right\}
+,
+$$
+with $\vec K_i$ the (component-wise) smallest non-negative integer vectors
+such that $S \subseteq H$.
+\end{definition}
+The $\vec K_i$ can be obtained by solving a number of
+LP problems, one for each element of each $\vec K_i$.
+If any LP problem is unbounded, then the corresponding constraint
+is dropped.
+
+\section{Parametric Integer Programming}
+
+\subsection{Introduction}\label{s:intro}
+
+Parametric integer programming \parencite{Feautrier88parametric}
+is used to solve many problems within the context of the polyhedral model.
+Here, we are mainly interested in dependence analysis \parencite{Fea91}
+and in computing a unique representation for existentially quantified
+variables.  The latter operation has been used for counting elements
+in sets involving such variables
+\parencite{BouletRe98,Verdoolaege2005experiences} and lies at the core
+of the internal representation of {\tt isl}.
+
+Parametric integer programming was first implemented in \texttt{PipLib}.
+An alternative method for parametric integer programming
+was later implemented in {\tt barvinok} \cite{barvinok-0.22}.
+This method is not based on Feautrier's algorithm, but on rational
+generating functions \cite{Woods2003short} and was inspired by the
+``digging'' technique of \textcite{DeLoera2004Three} for solving
+non-parametric integer programming problems.
+
+In the following sections, we briefly recall the dual simplex
+method combined with Gomory cuts and describe some extensions
+and optimizations.  The main algorithm is applied to a matrix
+data structure known as a tableau.  In case of parametric problems,
+there are two tableaus, one for the main problem and one for
+the constraints on the parameters, known as the context tableau.
+The handling of the context tableau is described in \autoref{s:context}.
+
+\subsection{The Dual Simplex Method}
+
+Tableaus can be represented in several slightly different ways.
+In {\tt isl}, the dual simplex method uses the same representation
+as that used by its incremental LP solver based on the \emph{primal}
+simplex method.  The implementation of this LP solver is based
+on that of {\tt Simplify} \parencite{Detlefs2005simplify}, which, in turn,
+was derived from the work of \textcite{Nelson1980phd}.
+In the original \parencite{Nelson1980phd}, the tableau was implemented
+as a sparse matrix, but neither {\tt Simplify} nor the current
+implementation of {\tt isl} does so.
+
+Given some affine constraints on the variables,
+$A \vec x + \vec b \ge \vec 0$, the tableau represents the relationship
+between the variables $\vec x$ and non-negative variables
+$\vec y = A \vec x + \vec b$ corresponding to the constraints.
+The initial tableau contains $\begin{pmatrix}
+\vec b & A
+\end{pmatrix}$ and expresses the constraints $\vec y$ in the rows in terms
+of the variables $\vec x$ in the columns.  The main operation defined
+on a tableau exchanges a column and a row variable and is called a pivot.
+During this process, some coefficients may become rational.
+As in the \texttt{PipLib} implementation,
+{\tt isl} maintains a shared denominator per row.
+The sample value of a tableau is one where each column variable is assigned
+zero and each row variable is assigned the constant term of the row.
+This sample value represents a valid solution if each constraint variable
+is assigned a non-negative value, i.e., if the constant terms of
+rows corresponding to constraints are all non-negative.
+
+The dual simplex method starts from an initial sample value that
+may be invalid, but that is known to be (lexicographically) no
+greater than any solution, and gradually increments this sample value
+through pivoting until a valid solution is obtained.
+In particular, each pivot exchanges a row variable
+$r = -n + \sum_i a_i \, c_i$ with negative
+sample value $-n$ with a column variable $c_j$
+such that $a_j > 0$.  Since $c_j = (n + r - \sum_{i\ne j} a_i \, c_i)/a_j$,
+the new row variable will have a positive sample value $n$.
+If no such column can be found, then the problem is infeasible.
+By always choosing the column that leads to the (lexicographically)
+smallest increment in the variables $\vec x$,
+the first solution found is guaranteed to be the (lexicographically)
+minimal solution \cite{Feautrier88parametric}.
+In order to be able to determine the smallest increment, the tableau
+is (implicitly) extended with extra rows defining the original
+variables in terms of the column variables.
+If we assume that all variables are non-negative, then we know
+that the zero vector is no greater than the minimal solution and
+then the initial extended tableau looks as follows.
+$$
+\begin{tikzpicture}
+\matrix (m) [matrix of math nodes]
+{
+& {} & 1 & \vec c \\
+\vec x && |(top)| \vec 0 & I \\
+\vec r && \vec b & |(bottom)|A \\
+};
+\begin{pgfonlayer}{background}
+\node (core) [inner sep=0pt,fill=black!20,right delimiter=),left delimiter=(,fit=(top)(bottom)] {};
+\end{pgfonlayer}
+\end{tikzpicture}
+$$
+Each column in this extended tableau is lexicographically positive
+and will remain so because of the column choice explained above.
+It is then clear that the value of $\vec x$ will increase in each step.
+Note that there is no need to store the extra rows explicitly.
+If a given $x_i$ is a column variable, then the corresponding row
+is the unit vector $e_i$.  If, on the other hand, it is a row variable,
+then the row already appears somewhere else in the tableau.
+
+In case of parametric problems, the sign of the constant term
+may depend on the parameters.  Each time the constant term of a constraint row
+changes, we therefore need to check whether the new term can attain
+negative and/or positive values over the current set of possible
+parameter values, i.e., the context.
+If all these terms can only attain non-negative values, the current
+state of the tableau represents a solution.  If one of the terms
+can only attain non-positive values and is not identically zero,
+the corresponding row can be pivoted.
+Otherwise, we pick one of the terms that can attain both positive
+and negative values and split the context into a part where
+it only attains non-negative values and a part where it only attains
+negative values.
+
+\subsection{Gomory Cuts}
+
+The solution found by the dual simplex method may have
+non-integral coordinates.  If so, some rational solutions
+(including the current sample value), can be cut off by
+applying a (parametric) Gomory cut.
+Let $r = b(\vec p) + \sp {\vec a} {\vec c}$ be the row
+corresponding to the first non-integral coordinate of $\vec x$,
+with $b(\vec p)$ the constant term, an affine expression in the
+parameters $\vec p$, i.e., $b(\vec p) = \sp {\vec f} {\vec p} + g$.
+Note that only row variables can attain
+non-integral values as the sample value of the column variables is zero.
+Consider the expression
+$b(\vec p) - \ceil{b(\vec p)} + \sp {\fract{\vec a}} {\vec c}$,
+with $\ceil\cdot$ the ceiling function and $\fract\cdot$ the
+fractional part.  This expression is negative at the sample value
+since $\vec c = \vec 0$ and $r = b(\vec p)$ is fractional, i.e.,
+$\ceil{b(\vec p)} > b(\vec p)$.  On the other hand, for each integral
+value of $r$ and $\vec c \ge 0$, the expression is non-negative
+because $b(\vec p) - \ceil{b(\vec p)} > -1$.
+Imposing this expression to be non-negative therefore does not
+invalidate any integral solutions, while it does cut away the current
+fractional sample value.  To be able to formulate this constraint,
+a new variable $q = \floor{-b(\vec p)} = - \ceil{b(\vec p)}$ is added
+to the context.  This integral variable is uniquely defined by the constraints
+$0 \le -d \, b(\vec p) - d \, q \le d - 1$, with $d$ the common
+denominator of $\vec f$ and $g$.  In practice, the variable
+$q' = \floor{\sp {\fract{-f}} {\vec p} + \fract{-g}}$ is used instead
+and the coefficients of the new constraint are adjusted accordingly.
+The sign of the constant term of this new constraint need not be determined
+as it is non-positive by construction.
+When several of these extra context variables are added, it is important
+to avoid adding duplicates.
+Recent versions of {\tt PipLib} also check for such duplicates.
+
+\subsection{Negative Unknowns and Maximization}
+
+There are two places in the above algorithm where the unknowns $\vec x$
+are assumed to be non-negative: the initial tableau starts from
+sample value $\vec x = \vec 0$ and $\vec c$ is assumed to be non-negative
+during the construction of Gomory cuts.
+To deal with negative unknowns, \textcite[Appendix A.2]{Fea91}
+proposed to use a ``big parameter'', say $M$, that is taken to be
+an arbitrarily large positive number.  Instead of looking for the
+lexicographically minimal value of $\vec x$, we search instead
+for the lexicographically minimal value of $\vec x' = \vec M + \vec x$.
+The sample value $\vec x' = \vec 0$ of the initial tableau then
+corresponds to $\vec x = -\vec M$, which is clearly not greater than
+any potential solution.  The sign of the constant term of a row
+is determined lexicographically, with the coefficient of $M$ considered
+first.  That is, if the coefficient of $M$ is not zero, then its sign
+is the sign of the entire term.  Otherwise, the sign is determined
+by the remaining affine expression in the parameters.
+If the original problem has a bounded optimum, then the final sample
+value will be of the form $\vec M + \vec v$ and the optimal value
+of the original problem is then $\vec v$.
+Maximization problems can be handled in a similar way by computing
+the minimum of $\vec M - \vec x$.
+
+When the optimum is unbounded, the optimal value computed for
+the original problem will involve the big parameter.
+In the original implementation of {\tt PipLib}, the big parameter could
+even appear in some of the extra variables $\vec q$ created during
+the application of a Gomory cut.  The final result could then contain
+implicit conditions on the big parameter through conditions on such
+$\vec q$ variables.  This problem was resolved in later versions
+of {\tt PipLib} by taking $M$ to be divisible by any positive number.
+The big parameter can then never appear in any $\vec q$ because
+$\fract {\alpha M } = 0$.  It should be noted, though, that an unbounded
+problem usually (but not always)
+indicates an incorrect formulation of the problem.
+
+The original version of {\tt PipLib} required the user to ``manually''
+add a big parameter, perform the reformulation and interpret the result
+\parencite{Feautrier02}.  Recent versions allow the user to simply
+specify that the unknowns may be negative or that the maximum should
+be computed and then these transformations are performed internally.
+Although there are some application, e.g.,
+that of \textcite{Feautrier92multi},
+where it is useful to have explicit control over the big parameter,
+negative unknowns and maximization are by far the most common applications
+of the big parameter and we believe that the user should not be bothered
+with such implementation issues.
+The current version of {\tt isl} therefore does not
+provide any interface for specifying big parameters.  Instead, the user
+can specify whether a maximum needs to be computed and no assumptions
+are made on the sign of the unknowns.  Instead, the sign of the unknowns
+is checked internally and a big parameter is automatically introduced when
+needed.  For compatibility with {\tt PipLib}, the {\tt isl\_pip} tool
+does explicitly add non-negativity constraints on the unknowns unless
+the \verb+Urs_unknowns+ option is specified.
+Currently, there is also no way in {\tt isl} of expressing a big
+parameter in the output.  Even though
+{\tt isl} makes the same divisibility assumption on the big parameter
+as recent versions of {\tt PipLib}, it will therefore eventually
+produce an error if the problem turns out to be unbounded.
+
+\subsection{Preprocessing}
+
+In this section, we describe some transformations that are
+or can be applied in advance to reduce the running time
+of the actual dual simplex method with Gomory cuts.
+
+\subsubsection{Feasibility Check and Detection of Equalities}
+
+Experience with the original {\tt PipLib} has shown that Gomory cuts
+do not perform very well on problems that are (non-obviously) empty,
+i.e., problems with rational solutions, but no integer solutions.
+In {\tt isl}, we therefore first perform a feasibility check on
+the original problem considered as a non-parametric problem
+over the combined space of unknowns and parameters.
+In fact, we do not simply check the feasibility, but we also
+check for implicit equalities among the integer points by computing
+the integer affine hull.  The algorithm used is the same as that
+described in \autoref{s:GBR} below.
+Computing the affine hull is fairly expensive, but it can
+bring huge benefits if any equalities can be found or if the problem
+turns out to be empty.
+
+\subsubsection{Constraint Simplification}
+
+If the coefficients of the unknown and parameters in a constraint
+have a common factor, then this factor should be removed, possibly
+rounding down the constant term.  For example, the constraint
+$2 x - 5 \ge 0$ should be simplified to $x - 3 \ge 0$.
+{\tt isl} performs such simplifications on all sets and relations.
+Recent versions of {\tt PipLib} also perform this simplification
+on the input.
+
+\subsubsection{Exploiting Equalities}\label{s:equalities}
+
+If there are any (explicit) equalities in the input description,
+{\tt PipLib} converts each into a pair of inequalities.
+It is also possible to write $r$ equalities as $r+1$ inequalities
+\parencite{Feautrier02}, but it is even better to \emph{exploit} the
+equalities to reduce the dimensionality of the problem.
+Given an equality involving at least one unknown, we pivot
+the row corresponding to the equality with the column corresponding
+to the last unknown with non-zero coefficient.  The new column variable
+can then be removed completely because it is identically zero,
+thereby reducing the dimensionality of the problem by one.
+The last unknown is chosen to ensure that the columns of the initial
+tableau remain lexicographically positive.  In particular, if
+the equality is of the form $b + \sum_{i \le j} a_i \, x_i = 0$ with
+$a_j \ne 0$, then the (implicit) top rows of the initial tableau
+are changed as follows
+$$
+\begin{tikzpicture}
+\matrix [matrix of math nodes]
+{
+ & {} & |(top)| 0 & I_1 & |(j)| &  \\
+j && 0 & & 1 & \\
+  && 0 & & & |(bottom)|I_2 \\
+};
+\node[overlay,above=2mm of j,anchor=south]{j};
+\begin{pgfonlayer}{background}
+\node (m) [inner sep=0pt,fill=black!20,right delimiter=),left delimiter=(,fit=(top)(bottom)] {};
+\end{pgfonlayer}
+\begin{scope}[xshift=4cm]
+\matrix [matrix of math nodes]
+{
+ & {} & |(top)| 0 & I_1 &  \\
+j && |(left)| -b/a_j & -a_i/a_j & \\
+  && 0 & & |(bottom)|I_2 \\
+};
+\begin{pgfonlayer}{background}
+\node (m2) [inner sep=0pt,fill=black!20,right delimiter=),left delimiter=(,fit=(top)(bottom)(left)] {};
+\end{pgfonlayer}
+\end{scope}
+ \draw [shorten >=7mm,-to,thick,decorate,
+        decoration={snake,amplitude=.4mm,segment length=2mm,
+                    pre=moveto,pre length=5mm,post length=8mm}]
+   (m) -- (m2);
+\end{tikzpicture}
+$$
+Currently, {\tt isl} also eliminates equalities involving only parameters
+in a similar way, provided at least one of the coefficients is equal to one.
+The application of parameter compression (see below)
+would obviate the need for removing parametric equalities.
+
+\subsubsection{Offline Symmetry Detection}\label{s:offline}
+
+Some problems, notably those of \textcite{Bygde2010licentiate},
+have a collection of constraints, say
+$b_i(\vec p) + \sp {\vec a} {\vec x} \ge 0$,
+that only differ in their (parametric) constant terms.
+These constant terms will be non-negative on different parts
+of the context and this context may have to be split for each
+of the constraints.  In the worst case, the basic algorithm may
+have to consider all possible orderings of the constant terms.
+Instead, {\tt isl} introduces a new parameter, say $u$, and
+replaces the collection of constraints by the single
+constraint $u + \sp {\vec a} {\vec x} \ge 0$ along with
+context constraints $u \le b_i(\vec p)$.
+Any solution to the new system is also a solution
+to the original system since
+$\sp {\vec a} {\vec x} \ge -u \ge -b_i(\vec p)$.
+Conversely, $m = \min_i b_i(\vec p)$ satisfies the constraints
+on $u$ and therefore extends a solution to the new system.
+It can also be plugged into a new solution.
+See \autoref{s:post} for how this substitution is currently performed
+in {\tt isl}.
+The method described in this section can only detect symmetries
+that are explicitly available in the input.
+See \autoref{s:online} for the detection
+and exploitation of symmetries that appear during the course of
+the dual simplex method.
+
+Note that the replacement of the $b_i(\vec p)$ by $u$ may lose
+information if the parameters that occur in $b_i(\vec p)$ also
+occur in other constraints.  The replacement is therefore currently
+only applied when all the parameters in all of the $b_i(\vec p)$
+only occur in a single constraint, i.e., the one in which
+the parameter is removed.
+This is the case for the examples from \textcite{Bygde2010licentiate}
+in \autoref{t:comparison}.
+The version of {\tt isl} that was used during the experiments
+of \autoref{s:pip:experiments} did not take into account
+this single-occurrence constraint.
+
+\subsubsection{Parameter Compression}\label{s:compression}
+
+It may in some cases be apparent from the equalities in the problem
+description that there can only be a solution for a sublattice
+of the parameters.  In such cases ``parameter compression''
+\parencite{Meister2004PhD,Meister2008} can be used to replace
+the parameters by alternative ``dense'' parameters.
+For example, if there is a constraint $2x = n$, then the system
+will only have solutions for even values of $n$ and $n$ can be replaced
+by $2n'$.  Similarly, the parameters $n$ and $m$ in a system with
+the constraint $2n = 3m$ can be replaced by a single parameter $n'$
+with $n=3n'$ and $m=2n'$.
+It is also possible to perform a similar compression on the unknowns,
+but it would be more complicated as the compression would have to
+preserve the lexicographical order.  Moreover, due to our handling
+of equalities described above there should be
+no need for such variable compression.
+Although parameter compression has been implemented in {\tt isl},
+it is currently not yet used during parametric integer programming.
+
+\subsection{Postprocessing}\label{s:post}
+
+The output of {\tt PipLib} is a quast (quasi-affine selection tree).
+Each internal node in this tree corresponds to a split of the context
+based on a parametric constant term in the main tableau with indeterminate
+sign.  Each of these nodes may introduce extra variables in the context
+corresponding to integer divisions.  Each leaf of the tree prescribes
+the solution in that part of the context that satisfies all the conditions
+on the path leading to the leaf.
+Such a quast is a very economical way of representing the solution, but
+it would not be suitable as the (only) internal representation of
+sets and relations in {\tt isl}.  Instead, {\tt isl} represents
+the constraints of a set or relation in disjunctive normal form.
+The result of a parametric integer programming problem is then also
+converted to this internal representation.  Unfortunately, the conversion
+to disjunctive normal form can lead to an explosion of the size
+of the representation.
+In some cases, this overhead would have to be paid anyway in subsequent
+operations, but in other cases, especially for outside users that just
+want to solve parametric integer programming problems, we would like
+to avoid this overhead in future.  That is, we are planning on introducing
+quasts or a related representation as one of several possible internal
+representations and on allowing the output of {\tt isl\_pip} to optionally
+be printed as a quast.
+
+Currently, {\tt isl} also does not have an internal representation
+for expressions such as $\min_i b_i(\vec p)$ from the offline
+symmetry detection of \autoref{s:offline}.
+Assume that one of these expressions has $n$ bounds $b_i(\vec p)$.
+If the expression
+does not appear in the affine expression describing the solution,
+but only in the constraints, and if moreover, the expression
+only appears with a positive coefficient, i.e.,
+$\min_i b_i(\vec p) \ge f_j(\vec p)$, then each of these constraints
+can simply be reduplicated $n$ times, once for each of the bounds.
+Otherwise, a conversion to disjunctive normal form
+leads to $n$ cases, each described as $u = b_i(\vec p)$ with constraints
+$b_i(\vec p) \le b_j(\vec p)$ for $j > i$
+and
+$b_i(\vec p)  < b_j(\vec p)$ for $j < i$.
+Note that even though this conversion leads to a size increase
+by a factor of $n$, not detecting the symmetry could lead to
+an increase by a factor of $n!$ if all possible orderings end up being
+considered.
+
+\subsection{Context Tableau}\label{s:context}
+
+The main operation that a context tableau needs to provide is a test
+on the sign of an affine expression over the elements of the context.
+This sign can be determined by solving two integer linear feasibility
+problems, one with a constraint added to the context that enforces
+the expression to be non-negative and one where the expression is
+negative.  As already mentioned by \textcite{Feautrier88parametric},
+any integer linear feasibility solver could be used, but the {\tt PipLib}
+implementation uses a recursive call to the dual simplex with Gomory
+cuts algorithm to determine the feasibility of a context.
+In {\tt isl}, two ways of handling the context have been implemented,
+one that performs the recursive call and one, used by default, that
+uses generalized basis reduction.
+We start with some optimizations that are shared between the two
+implementations and then discuss additional details of each of them.
+
+\subsubsection{Maintaining Witnesses}\label{s:witness}
+
+A common feature of both integer linear feasibility solvers is that
+they will not only say whether a set is empty or not, but if the set
+is non-empty, they will also provide a \emph{witness} for this result,
+i.e., a point that belongs to the set.  By maintaining a list of such
+witnesses, we can avoid many feasibility tests during the determination
+of the signs of affine expressions.  In particular, if the expression
+evaluates to a positive number on some of these points and to a negative
+number on some others, then no feasibility test needs to be performed.
+If all the evaluations are non-negative, we only need to check for the
+possibility of a negative value and similarly in case of all
+non-positive evaluations.  Finally, in the rare case that all points
+evaluate to zero or at the start, when no points have been collected yet,
+one or two feasibility tests need to be performed depending on the result
+of the first test.
+
+When a new constraint is added to the context, the points that
+violate the constraint are temporarily removed.  They are reconsidered
+when we backtrack over the addition of the constraint, as they will
+satisfy the negation of the constraint.  It is only when we backtrack
+over the addition of the points that they are finally removed completely.
+When an extra integer division is added to the context,
+the new coordinates of the
+witnesses can easily be computed by evaluating the integer division.
+The idea of keeping track of witnesses was first used in {\tt barvinok}.
+
+\subsubsection{Choice of Constant Term on which to Split}
+
+Recall that if there are no rows with a non-positive constant term,
+but there are rows with an indeterminate sign, then the context
+needs to be split along the constant term of one of these rows.
+If there is more than one such row, then we need to choose which row
+to split on first.  {\tt PipLib} uses a heuristic based on the (absolute)
+sizes of the coefficients.  In particular, it takes the largest coefficient
+of each row and then selects the row where this largest coefficient is smaller
+than those of the other rows.
+
+In {\tt isl}, we take that row for which non-negativity of its constant
+term implies non-negativity of as many of the constant terms of the other
+rows as possible.  The intuition behind this heuristic is that on the
+positive side, we will have fewer negative and indeterminate signs,
+while on the negative side, we need to perform a pivot, which may
+affect any number of rows meaning that the effect on the signs
+is difficult to predict.  This heuristic is of course much more
+expensive to evaluate than the heuristic used by {\tt PipLib}.
+More extensive tests are needed to evaluate whether the heuristic is worthwhile.
+
+\subsubsection{Dual Simplex + Gomory Cuts}
+
+When a new constraint is added to the context, the first steps
+of the dual simplex method applied to this new context will be the same
+or at least very similar to those taken on the original context, i.e.,
+before the constraint was added.  In {\tt isl}, we therefore apply
+the dual simplex method incrementally on the context and backtrack
+to a previous state when a constraint is removed again.
+An initial implementation that was never made public would also
+keep the Gomory cuts, but the current implementation backtracks
+to before the point where Gomory cuts are added before adding
+an extra constraint to the context.
+Keeping the Gomory cuts has the advantage that the sample value
+is always an integer point and that this point may also satisfy
+the new constraint.  However, due to the technique of maintaining
+witnesses explained above,
+we would not perform a feasibility test in such cases and then
+the previously added cuts may be redundant, possibly resulting
+in an accumulation of a large number of cuts.
+
+If the parameters may be negative, then the same big parameter trick
+used in the main tableau is applied to the context.  This big parameter
+is of course unrelated to the big parameter from the main tableau.
+Note that it is not a requirement for this parameter to be ``big'',
+but it does allow for some code reuse in {\tt isl}.
+In {\tt PipLib}, the extra parameter is not ``big'', but this may be because
+the big parameter of the main tableau also appears
+in the context tableau.
+
+Finally, it was reported by \textcite{Galea2009personal}, who
+worked on a parametric integer programming implementation
+in {\tt PPL} \parencite{PPL},
+that it is beneficial to add cuts for \emph{all} rational coordinates
+in the context tableau.  Based on this report,
+the initial {\tt isl} implementation was adapted accordingly.
+
+\subsubsection{Generalized Basis Reduction}\label{s:GBR}
+
+The default algorithm used in {\tt isl} for feasibility checking
+is generalized basis reduction \parencite{Cook1991implementation}.
+This algorithm is also used in the {\tt barvinok} implementation.
+The algorithm is fairly robust, but it has some overhead.
+We therefore try to avoid calling the algorithm in easy cases.
+In particular, we incrementally keep track of points for which
+the entire unit hypercube positioned at that point lies in the context.
+This set is described by translates of the constraints of the context
+and if (rationally) non-empty, any rational point
+in the set can be rounded up to yield an integer point in the context.
+
+A restriction of the algorithm is that it only works on bounded sets.
+The affine hull of the recession cone therefore needs to be projected
+out first.  As soon as the algorithm is invoked, we then also
+incrementally keep track of this recession cone.  The reduced basis
+found by one call of the algorithm is also reused as initial basis
+for the next call.
+
+Some problems lead to the
+introduction of many integer divisions.  Within a given context,
+some of these integer divisions may be equal to each other, even
+if the expressions are not identical, or they may be equal to some
+affine combination of other variables.
+To detect such cases, we compute the affine hull of the context
+each time a new integer division is added.  The algorithm used
+for computing this affine hull is that of \textcite{Karr1976affine},
+while the points used in this algorithm are obtained by performing
+integer feasibility checks on that part of the context outside
+the current approximation of the affine hull.
+The list of witnesses is used to construct an initial approximation
+of the hull, while any extra points found during the construction
+of the hull is added to this list.
+Any equality found in this way that expresses an integer division
+as an \emph{integer} affine combination of other variables is
+propagated to the main tableau, where it is used to eliminate that
+integer division.
+
+\subsection{Experiments}\label{s:pip:experiments}
+
+\autoref{t:comparison} compares the execution times of {\tt isl}
+(with both types of context tableau)
+on some more difficult instances to those of other tools,
+run on an Intel Xeon W3520 @ 2.66GHz.
+These instances are available in the \lstinline{testsets/pip} directory
+of the {\tt isl} distribution.
+Easier problems such as the
+test cases distributed with {\tt Pip\-Lib} can be solved so quickly
+that we would only be measuring overhead such as input/output and conversions
+and not the running time of the actual algorithm.
+We compare the following versions:
+{\tt piplib-1.4.0-5-g0132fd9},
+{\tt barvinok-0.32.1-73-gc5d7751},
+{\tt isl-0.05.1-82-g3a37260}
+and {\tt PPL} version 0.11.2.
+
+The first test case is the following dependence analysis problem
+originating from the Phideo project \parencite{Verhaegh1995PhD}
+that was communicated to us by Bart Kienhuis:
+\begin{lstlisting}[flexiblecolumns=true,breaklines=true]{}
+lexmax { [j1,j2] -> [i1,i2,i3,i4,i5,i6,i7,i8,i9,i10] : 1 <= i1,j1 <= 8 and 1 <= i2,i3,i4,i5,i6,i7,i8,i9,i10 <= 2 and 1 <= j2 <= 128 and i1-1 = j1-1 and i2-1+2*i3-2+4*i4-4+8*i5-8+16*i6-16+32*i7-32+64*i8-64+128*i9-128+256*i10-256=3*j2-3+66 };
+\end{lstlisting}
+This problem was the main inspiration
+for some of the optimizations in \autoref{s:GBR}.
+The second group of test cases are projections used during counting.
+The first nine of these come from \textcite{Seghir2006minimizing}.
+The remaining two come from \textcite{Verdoolaege2005experiences} and
+were used to drive the first, Gomory cuts based, implementation
+in {\tt isl}.
+The third and final group of test cases are borrowed from
+\textcite{Bygde2010licentiate} and inspired the offline symmetry detection
+of \autoref{s:offline}.  Without symmetry detection, the running times
+are 11s and 5.9s.
+All running times of {\tt barvinok} and {\tt isl} include a conversion
+to disjunctive normal form.  Without this conversion, the final two
+cases can be solved in 0.07s and 0.21s.
+The {\tt PipLib} implementation has some fixed limits and will
+sometimes report the problem to be too complex (TC), while on some other
+problems it will run out of memory (OOM).
+The {\tt barvinok} implementation does not support problems
+with a non-trivial lineality space (line) nor maximization problems (max).
+The Gomory cuts based {\tt isl} implementation was terminated after 1000
+minutes on the first problem.  The gbr version introduces some
+overhead on some of the easier problems, but is overall the clear winner.
+
+\begin{table}
+\begin{center}
+\begin{tabular}{lrrrrr}
+    & {\tt PipLib} & {\tt barvinok} & {\tt isl} cut & {\tt isl} gbr & {\tt PPL} \\
+\hline
+\hline
+% bart.pip
+Phideo & TC    & 793m   & $>$999m &   2.7s  & 372m \\
+\hline
+e1 & 0.33s & 3.5s & 0.08s & 0.11s & 0.18s \\
+e3 & 0.14s & 0.13s & 0.10s & 0.10s & 0.17s \\
+e4 & 0.24s & 9.1s & 0.09s & 0.11s & 0.70s \\
+e5 & 0.12s & 6.0s & 0.06s & 0.14s & 0.17s \\
+e6 & 0.10s & 6.8s & 0.17s & 0.08s & 0.21s \\
+e7 & 0.03s & 0.27s & 0.04s & 0.04s & 0.03s \\
+e8 & 0.03s & 0.18s & 0.03s & 0.04s & 0.01s \\
+e9 & OOM & 70m & 2.6s & 0.94s & 22s \\
+vd & 0.04s & 0.10s & 0.03s & 0.03s & 0.03s \\
+bouleti & 0.25s & line & 0.06s & 0.06s & 0.15s \\
+difficult & OOM & 1.3s & 1.7s & 0.33s & 1.4s \\
+\hline
+cnt/sum & TC & max & 2.2s & 2.2s & OOM \\
+jcomplex & TC & max & 3.7s & 3.9s & OOM \\
+\end{tabular}
+\caption{Comparison of Execution Times}
+\label{t:comparison}
+\end{center}
+\end{table}
+
+\subsection{Online Symmetry Detection}\label{s:online}
+
+Manual experiments on small instances of the problems of
+\textcite{Bygde2010licentiate} and an analysis of the results
+by the approximate MPA method developed by \textcite{Bygde2010licentiate}
+have revealed that these problems contain many more symmetries
+than can be detected using the offline method of \autoref{s:offline}.
+In this section, we present an online detection mechanism that has
+not been implemented yet, but that has shown promising results
+in manual applications.
+
+Let us first consider what happens when we do not perform offline
+symmetry detection.  At some point, one of the
+$b_i(\vec p) + \sp {\vec a} {\vec x} \ge 0$ constraints,
+say the $j$th constraint, appears as a column
+variable, say $c_1$, while the other constraints are represented
+as rows of the form $b_i(\vec p) - b_j(\vec p) + c$.
+The context is then split according to the relative order of
+$b_j(\vec p)$ and one of the remaining $b_i(\vec p)$.
+The offline method avoids this split by replacing all $b_i(\vec p)$
+by a single newly introduced parameter that represents the minimum
+of these $b_i(\vec p)$.
+In the online method the split is similarly avoided by the introduction
+of a new parameter.  In particular, a new parameter is introduced
+that represents
+$\left| b_j(\vec p) - b_i(\vec p) \right|_+ =
+\max(b_j(\vec p) - b_i(\vec p), 0)$.
+
+In general, let $r = b(\vec p) + \sp {\vec a} {\vec c}$ be a row
+of the tableau such that the sign of $b(\vec p)$ is indeterminate
+and such that exactly one of the elements of $\vec a$ is a $1$,
+while all remaining elements are non-positive.
+That is, $r = b(\vec p) + c_j - f$ with $f = -\sum_{i\ne j} a_i c_i \ge 0$.
+We introduce a new parameter $t$ with
+context constraints $t \ge -b(\vec p)$ and $t \ge 0$ and replace
+the column variable $c_j$ by $c' + t$.  The row $r$ is now equal
+to $b(\vec p) + t + c' - f$.  The constant term of this row is always
+non-negative because any negative value of $b(\vec p)$ is compensated
+by $t \ge -b(\vec p)$ while and non-negative value remains non-negative
+because $t \ge 0$.
+
+We need to show that this transformation does not eliminate any valid
+solutions and that it does not introduce any spurious solutions.
+Given a valid solution for the original problem, we need to find
+a non-negative value of $c'$ satisfying the constraints.
+If $b(\vec p) \ge 0$, we can take $t = 0$ so that
+$c' = c_j - t = c_j \ge 0$.
+If $b(\vec p) < 0$, we can take $t = -b(\vec p)$.
+Since $r = b(\vec p) + c_j - f \ge 0$ and $f \ge 0$, we have 
+$c' = c_j + b(\vec p) \ge 0$.
+Note that these choices amount to plugging in
+$t = \left|-b(\vec p)\right|_+ = \max(-b(\vec p), 0)$.
+Conversely, given a solution to the new problem, we need to find
+a non-negative value of $c_j$, but this is easy since $c_j = c' + t$
+and both of these are non-negative.
+
+Plugging in $t = \max(-b(\vec p), 0)$ can be performed as in
+\autoref{s:post}, but, as in the case of offline symmetry detection,
+it may be better to provide a direct representation for such
+expressions in the internal representation of sets and relations
+or at least in a quast-like output format.
+
+\section{Coalescing}\label{s:coalescing}
+
+See \textcite{Verdoolaege2015impact} for details on integer set coalescing.
+
+\section{Transitive Closure}
+
+\subsection{Introduction}
+
+\begin{definition}[Power of a Relation]
+Let $R \in \Z^n \to 2^{\Z^{d+d}}$ be a relation and
+$k \in \Z_{\ge 1}$
+a positive number, then power $k$ of relation $R$ is defined as
+\begin{equation}
+\label{eq:transitive:power}
+R^k \coloneqq
+\begin{cases}
+R & \text{if $k = 1$}
+\\
+R \circ R^{k-1} & \text{if $k \ge 2$}
+.
+\end{cases}
+\end{equation}
+\end{definition}
+
+\begin{definition}[Transitive Closure of a Relation]
+Let $R \in \Z^n \to 2^{\Z^{d+d}}$ be a relation,
+then the transitive closure $R^+$ of $R$ is the union
+of all positive powers of $R$,
+$$
+R^+ \coloneqq \bigcup_{k \ge 1} R^k
+.
+$$
+\end{definition}
+Alternatively, the transitive closure may be defined
+inductively as
+\begin{equation}
+\label{eq:transitive:inductive}
+R^+ \coloneqq R \cup \left(R \circ R^+\right)
+.
+\end{equation}
+
+Since the transitive closure of a polyhedral relation
+may no longer be a polyhedral relation \parencite{Kelly1996closure},
+we can, in the general case, only compute an approximation
+of the transitive closure.
+Whereas \textcite{Kelly1996closure} compute underapproximations,
+we, like \textcite{Beletska2009}, compute overapproximations.
+That is, given a relation $R$, we will compute a relation $T$
+such that $R^+ \subseteq T$.  Of course, we want this approximation
+to be as close as possible to the actual transitive closure
+$R^+$ and we want to detect the cases where the approximation is
+exact, i.e., where $T = R^+$.
+
+For computing an approximation of the transitive closure of $R$,
+we follow the same general strategy as \textcite{Beletska2009}
+and first compute an approximation of $R^k$ for $k \ge 1$ and then project
+out the parameter $k$ from the resulting relation.
+
+\begin{example}
+As a trivial example, consider the relation
+$R = \{\, x \to x + 1 \,\}$.  The $k$th power of this map
+for arbitrary $k$ is
+$$
+R^k = k \mapsto \{\, x \to x + k \mid k \ge 1 \,\}
+.
+$$
+The transitive closure is then
+$$
+\begin{aligned}
+R^+ & = \{\, x \to y \mid \exists k \in \Z_{\ge 1} : y = x + k \,\}
+\\
+& = \{\, x \to y \mid y \ge x + 1 \,\}
+.
+\end{aligned}
+$$
+\end{example}
+
+\subsection{Computing an Approximation of $R^k$}
+\label{s:power}
+
+There are some special cases where the computation of $R^k$ is very easy.
+One such case is that where $R$ does not compose with itself,
+i.e., $R \circ R = \emptyset$ or $\domain R \cap \range R = \emptyset$.
+In this case, $R^k$ is only non-empty for $k=1$ where it is equal
+to $R$ itself.
+
+In general, it is impossible to construct a closed form
+of $R^k$ as a polyhedral relation.
+We will therefore need to make some approximations.
+As a first approximations, we will consider each of the basic
+relations in $R$ as simply adding one or more offsets to a domain element
+to arrive at an image element and ignore the fact that some of these
+offsets may only be applied to some of the domain elements.
+That is, we will only consider the difference set $\Delta\,R$ of the relation.
+In particular, we will first construct a collection $P$ of paths
+that move through
+a total of $k$ offsets and then intersect domain and range of this
+collection with those of $R$.
+That is, 
+\begin{equation}
+\label{eq:transitive:approx}
+K = P \cap \left(\domain R \to \range R\right)
+,
+\end{equation}
+with
+\begin{equation}
+\label{eq:transitive:path}
+P = \vec s \mapsto \{\, \vec x \to \vec y \mid
+\exists k_i \in \Z_{\ge 0}, \vec\delta_i \in k_i \, \Delta_i(\vec s) :
+\vec y = \vec x + \sum_i \vec\delta_i
+\wedge
+\sum_i k_i = k > 0
+\,\}
+\end{equation}
+and with $\Delta_i$ the basic sets that compose
+the difference set $\Delta\,R$.
+Note that the number of basic sets $\Delta_i$ need not be
+the same as the number of basic relations in $R$.
+Also note that since addition is commutative, it does not
+matter in which order we add the offsets and so we are allowed
+to group them as we did in \eqref{eq:transitive:path}.
+
+If all the $\Delta_i$s are singleton sets
+$\Delta_i = \{\, \vec \delta_i \,\}$ with $\vec \delta_i \in \Z^d$,
+then \eqref{eq:transitive:path} simplifies to
+\begin{equation}
+\label{eq:transitive:singleton}
+P = \{\, \vec x \to \vec y \mid
+\exists k_i \in \Z_{\ge 0} :
+\vec y = \vec x + \sum_i k_i \, \vec \delta_i
+\wedge
+\sum_i k_i = k > 0
+\,\}
+\end{equation}
+and then the approximation computed in \eqref{eq:transitive:approx}
+is essentially the same as that of \textcite{Beletska2009}.
+If some of the $\Delta_i$s are not singleton sets or if
+some of $\vec \delta_i$s are parametric, then we need
+to resort to further approximations.
+
+To ease both the exposition and the implementation, we will for
+the remainder of this section work with extended offsets
+$\Delta_i' = \Delta_i \times \{\, 1 \,\}$.
+That is, each offset is extended with an extra coordinate that is
+set equal to one.  The paths constructed by summing such extended
+offsets have the length encoded as the difference of their
+final coordinates.  The path $P'$ can then be decomposed into
+paths $P_i'$, one for each $\Delta_i$,
+\begin{equation}
+\label{eq:transitive:decompose}
+P' = \left(
+(P_m' \cup \identity) \circ \cdots \circ
+(P_2' \cup \identity) \circ
+(P_1' \cup \identity)
+\right) \cap
+\{\,
+\vec x' \to \vec y' \mid y_{d+1} - x_{d+1} = k > 0
+\,\}
+,
+\end{equation}
+with
+$$
+P_i' = \vec s \mapsto \{\, \vec x' \to \vec y' \mid
+\exists k \in \Z_{\ge 1}, \vec \delta \in k \, \Delta_i'(\vec s) :
+\vec y' = \vec x' + \vec \delta
+\,\}
+.
+$$
+Note that each $P_i'$ contains paths of length at least one.
+We therefore need to take the union with the identity relation
+when composing the $P_i'$s to allow for paths that do not contain
+any offsets from one or more $\Delta_i'$.
+The path that consists of only identity relations is removed
+by imposing the constraint $y_{d+1} - x_{d+1} > 0$.
+Taking the union with the identity relation means that
+that the relations we compose in \eqref{eq:transitive:decompose}
+each consist of two basic relations.  If there are $m$
+disjuncts in the input relation, then a direct application
+of the composition operation may therefore result in a relation
+with $2^m$ disjuncts, which is prohibitively expensive.
+It is therefore crucial to apply coalescing (\autoref{s:coalescing})
+after each composition.
+
+Let us now consider how to compute an overapproximation of $P_i'$.
+Those that correspond to singleton $\Delta_i$s are grouped together
+and handled as in \eqref{eq:transitive:singleton}.
+Note that this is just an optimization.  The procedure described
+below would produce results that are at least as accurate.
+For simplicity, we first assume that no constraint in $\Delta_i'$
+involves any existentially quantified variables.
+We will return to existentially quantified variables at the end
+of this section.
+Without existentially quantified variables, we can classify
+the constraints of $\Delta_i'$ as follows
+\begin{enumerate}
+\item non-parametric constraints
+\begin{equation}
+\label{eq:transitive:non-parametric}
+A_1 \vec x + \vec c_1 \geq \vec 0
+\end{equation}
+\item purely parametric constraints
+\begin{equation}
+\label{eq:transitive:parametric}
+B_2 \vec s + \vec c_2 \geq \vec 0
+\end{equation}
+\item negative mixed constraints
+\begin{equation}
+\label{eq:transitive:mixed}
+A_3 \vec x + B_3 \vec s + \vec c_3 \geq \vec 0
+\end{equation}
+such that for each row $j$ and for all $\vec s$,
+$$
+\Delta_i'(\vec s) \cap
+\{\, \vec \delta' \mid B_{3,j} \vec s + c_{3,j} > 0 \,\}
+= \emptyset
+$$
+\item positive mixed constraints
+$$
+A_4 \vec x + B_4 \vec s + \vec c_4 \geq \vec 0
+$$
+such that for each row $j$, there is at least one $\vec s$ such that
+$$
+\Delta_i'(\vec s) \cap
+\{\, \vec \delta' \mid B_{4,j} \vec s + c_{4,j} > 0 \,\}
+\ne \emptyset
+$$
+\end{enumerate}
+We will use the following approximation $Q_i$ for $P_i'$:
+\begin{equation}
+\label{eq:transitive:Q}
+\begin{aligned}
+Q_i = \vec s \mapsto
+\{\,
+\vec x' \to \vec y'
+\mid {} & \exists k \in \Z_{\ge 1}, \vec f \in \Z^d :
+\vec y' = \vec x' + (\vec f, k)
+\wedge {}
+\\
+&
+A_1 \vec f + k \vec c_1 \geq \vec 0
+\wedge
+B_2 \vec s + \vec c_2 \geq \vec 0
+\wedge
+A_3 \vec f + B_3 \vec s + \vec c_3 \geq \vec 0
+\,\}
+.
+\end{aligned}
+\end{equation}
+To prove that $Q_i$ is indeed an overapproximation of $P_i'$,
+we need to show that for every $\vec s \in \Z^n$, for every
+$k \in \Z_{\ge 1}$ and for every $\vec f \in k \, \Delta_i(\vec s)$
+we have that
+$(\vec f, k)$ satisfies the constraints in \eqref{eq:transitive:Q}.
+If $\Delta_i(\vec s)$ is non-empty, then $\vec s$ must satisfy
+the constraints in \eqref{eq:transitive:parametric}.
+Each element $(\vec f, k) \in k \, \Delta_i'(\vec s)$ is a sum
+of $k$ elements $(\vec f_j, 1)$ in $\Delta_i'(\vec s)$.
+Each of these elements satisfies the constraints in
+\eqref{eq:transitive:non-parametric}, i.e.,
+$$
+\left[
+\begin{matrix}
+A_1 & \vec c_1
+\end{matrix}
+\right]
+\left[
+\begin{matrix}
+\vec f_j \\ 1
+\end{matrix}
+\right]
+\ge \vec 0
+.
+$$
+The sum of these elements therefore satisfies the same set of inequalities,
+i.e., $A_1 \vec f + k \vec c_1 \geq \vec 0$.
+Finally, the constraints in \eqref{eq:transitive:mixed} are such
+that for any $\vec s$ in the parameter domain of $\Delta$,
+we have $-\vec r(\vec s) \coloneqq B_3 \vec s + \vec c_3 \le \vec 0$,
+i.e., $A_3 \vec f_j \ge \vec r(\vec s) \ge \vec 0$
+and therefore also $A_3 \vec f \ge \vec r(\vec s)$.
+Note that if there are no mixed constraints and if the
+rational relaxation of $\Delta_i(\vec s)$, i.e.,
+$\{\, \vec x \in \Q^d \mid A_1 \vec x + \vec c_1 \ge \vec 0\,\}$,
+has integer vertices, then the approximation is exact, i.e.,
+$Q_i = P_i'$.  In this case, the vertices of $\Delta'_i(\vec s)$
+generate the rational cone
+$\{\, \vec x' \in \Q^{d+1} \mid \left[
+\begin{matrix}
+A_1 & \vec c_1
+\end{matrix}
+\right] \vec x' \,\}$ and therefore $\Delta'_i(\vec s)$ is
+a Hilbert basis of this cone \parencite[Theorem~16.4]{Schrijver1986}.
+
+Note however that, as pointed out by \textcite{DeSmet2010personal},
+if there \emph{are} any mixed constraints, then the above procedure may
+not compute the most accurate affine approximation of
+$k \, \Delta_i(\vec s)$ with $k \ge 1$.
+In particular, we only consider the negative mixed constraints that
+happen to appear in the description of $\Delta_i(\vec s)$, while we
+should instead consider \emph{all} valid such constraints.
+It is also sufficient to consider those constraints because any
+constraint that is valid for $k \, \Delta_i(\vec s)$ is also
+valid for $1 \, \Delta_i(\vec s) = \Delta_i(\vec s)$.
+Take therefore any constraint
+$\spv a x + \spv b s + c \ge 0$ valid for $\Delta_i(\vec s)$.
+This constraint is also valid for $k \, \Delta_i(\vec s)$ iff
+$k \, \spv a x + \spv b s + c \ge 0$.
+If $\spv b s + c$ can attain any positive value, then $\spv a x$
+may be negative for some elements of $\Delta_i(\vec s)$.
+We then have $k \, \spv a x < \spv a x$ for $k > 1$ and so the constraint
+is not valid for $k \, \Delta_i(\vec s)$.
+We therefore need to impose $\spv b s + c \le 0$ for all values
+of $\vec s$ such that $\Delta_i(\vec s)$ is non-empty, i.e.,
+$\vec b$ and $c$ need to be such that $- \spv b s - c \ge 0$ is a valid
+constraint of $\Delta_i(\vec s)$.  That is, $(\vec b, c)$ are the opposites
+of the coefficients of a valid constraint of $\Delta_i(\vec s)$.
+The approximation of $k \, \Delta_i(\vec s)$ can therefore be obtained
+using three applications of Farkas' lemma.  The first obtains the coefficients
+of constraints valid for $\Delta_i(\vec s)$.  The second obtains
+the coefficients of constraints valid for the projection of $\Delta_i(\vec s)$
+onto the parameters.  The opposite of the second set is then computed
+and intersected with the first set.  The result is the set of coefficients
+of constraints valid for $k \, \Delta_i(\vec s)$.  A final application
+of Farkas' lemma is needed to obtain the approximation of
+$k \, \Delta_i(\vec s)$ itself.
+
+\begin{example}
+Consider the relation
+$$
+n \to \{\, (x, y) \to (1 + x, 1 - n + y) \mid n \ge 2 \,\}
+.
+$$
+The difference set of this relation is
+$$
+\Delta = n \to \{\, (1, 1 - n) \mid n \ge 2 \,\}
+.
+$$
+Using our approach, we would only consider the mixed constraint
+$y - 1 + n \ge 0$, leading to the following approximation of the
+transitive closure:
+$$
+n \to \{\, (x, y) \to (o_0, o_1) \mid n \ge 2 \wedge o_1 \le 1 - n + y \wedge o_0 \ge 1 + x \,\}
+.
+$$
+If, instead, we apply Farkas's lemma to $\Delta$, i.e.,
+\begin{verbatim}
+D := [n] -> { [1, 1 - n] : n >= 2 };
+CD := coefficients D;
+CD;
+\end{verbatim}
+we obtain
+\begin{verbatim}
+{ rat: coefficients[[c_cst, c_n] -> [i2, i3]] : i3 <= c_n and
+  i3 <= c_cst + 2c_n + i2 }
+\end{verbatim}
+The pure-parametric constraints valid for $\Delta$,
+\begin{verbatim}
+P := { [a,b] -> [] }(D);
+CP := coefficients P;
+CP;
+\end{verbatim}
+are
+\begin{verbatim}
+{ rat: coefficients[[c_cst, c_n] -> []] : c_n >= 0 and 2c_n >= -c_cst }
+\end{verbatim}
+Negating these coefficients and intersecting with \verb+CD+,
+\begin{verbatim}
+NCP := { rat: coefficients[[a,b] -> []]
+              -> coefficients[[-a,-b] -> []] }(CP);
+CK := wrap((unwrap CD) * (dom (unwrap NCP)));
+CK;
+\end{verbatim}
+we obtain
+\begin{verbatim}
+{ rat: [[c_cst, c_n] -> [i2, i3]] : i3 <= c_n and
+  i3 <= c_cst + 2c_n + i2 and c_n <= 0 and 2c_n <= -c_cst }
+\end{verbatim}
+The approximation for $k\,\Delta$,
+\begin{verbatim}
+K := solutions CK;
+K;
+\end{verbatim}
+is then
+\begin{verbatim}
+[n] -> { rat: [i0, i1] : i1 <= -i0 and i0 >= 1 and i1 <= 2 - n - i0 }
+\end{verbatim}
+Finally, the computed approximation for $R^+$,
+\begin{verbatim}
+T := unwrap({ [dx,dy] -> [[x,y] -> [x+dx,y+dy]] }(K));
+R := [n] -> { [x,y] -> [x+1,y+1-n] : n >= 2 };
+T := T * ((dom R) -> (ran R));
+T;
+\end{verbatim}
+is
+\begin{verbatim}
+[n] -> { [x, y] -> [o0, o1] : o1 <= x + y - o0 and
+         o0 >= 1 + x and o1 <= 2 - n + x + y - o0 and n >= 2 }
+\end{verbatim}
+\end{example}
+
+Existentially quantified variables can be handled by
+classifying them into variables that are uniquely
+determined by the parameters, variables that are independent
+of the parameters and others.  The first set can be treated
+as parameters and the second as variables.  Constraints involving
+the other existentially quantified variables are removed.
+
+\begin{example}
+Consider the relation
+$$
+R =
+n \to \{\, x \to y \mid \exists \, \alpha_0, \alpha_1: 7\alpha_0 = -2 + n \wedge 5\alpha_1 = -1 - x + y \wedge y \ge 6 + x \,\}
+.
+$$
+The difference set of this relation is
+$$
+\Delta = \Delta \, R =
+n \to \{\, x \mid \exists \, \alpha_0, \alpha_1: 7\alpha_0 = -2 + n \wedge 5\alpha_1 = -1 + x \wedge x \ge 6 \,\}
+.
+$$
+The existentially quantified variables can be defined in terms
+of the parameters and variables as
+$$
+\alpha_0 = \floor{\frac{-2 + n}7}
+\qquad
+\text{and}
+\qquad
+\alpha_1 = \floor{\frac{-1 + x}5}
+.
+$$
+$\alpha_0$ can therefore be treated as a parameter,
+while $\alpha_1$ can be treated as a variable.
+This in turn means that $7\alpha_0 = -2 + n$ can be treated as
+a purely parametric constraint, while the other two constraints are
+non-parametric.
+The corresponding $Q$~\eqref{eq:transitive:Q} is therefore
+$$
+\begin{aligned}
+n \to \{\, (x,z) \to (y,w) \mid
+\exists\, \alpha_0, \alpha_1, k, f : {} &
+k \ge 1 \wedge
+y = x + f \wedge
+w = z + k \wedge {} \\
+&
+7\alpha_0 = -2 + n \wedge
+5\alpha_1 = -k + x \wedge
+x \ge 6 k
+\,\}
+.
+\end{aligned}
+$$
+Projecting out the final coordinates encoding the length of the paths,
+results in the exact transitive closure
+$$
+R^+ =
+n \to \{\, x \to y \mid \exists \, \alpha_0, \alpha_1: 7\alpha_1 = -2 + n \wedge 6\alpha_0 \ge -x + y \wedge 5\alpha_0 \le -1 - x + y \,\}
+.
+$$
+\end{example}
+
+The fact that we ignore some impure constraints clearly leads
+to a loss of accuracy.  In some cases, some of this loss can be recovered
+by not considering the parameters in a special way.
+That is, instead of considering the set
+$$
+\Delta = \diff R =
+\vec s \mapsto
+\{\, \vec \delta \in \Z^{d} \mid \exists \vec x \to \vec y \in R :
+\vec \delta = \vec y - \vec x
+\,\}
+$$
+we consider the set
+$$
+\Delta' = \diff R' =
+\{\, \vec \delta \in \Z^{n+d} \mid \exists
+(\vec s, \vec x) \to (\vec s, \vec y) \in R' :
+\vec \delta = (\vec s - \vec s, \vec y - \vec x)
+\,\}
+.
+$$
+The first $n$ coordinates of every element in $\Delta'$ are zero.
+Projecting out these zero coordinates from $\Delta'$ is equivalent
+to projecting out the parameters in $\Delta$.
+The result is obviously a superset of $\Delta$, but all its constraints
+are of type \eqref{eq:transitive:non-parametric} and they can therefore
+all be used in the construction of $Q_i$.
+
+\begin{example}
+Consider the relation
+$$
+% [n] -> { [x, y] -> [1 + x, 1 - n + y] | n >= 2 }
+R = n \to \{\, (x, y) \to (1 + x, 1 - n + y) \mid n \ge 2 \,\}
+.
+$$
+We have
+$$
+\diff R = n \to \{\, (1, 1 - n) \mid n \ge 2 \,\}
+$$
+and so, by treating the parameters in a special way, we obtain
+the following approximation for $R^+$:
+$$
+n \to \{\, (x, y) \to (x', y') \mid n \ge 2 \wedge y' \le 1 - n + y \wedge x' \ge 1 + x \,\}
+.
+$$
+If we consider instead
+$$
+R' = \{\, (n, x, y) \to (n, 1 + x, 1 - n + y) \mid n \ge 2 \,\}
+$$
+then
+$$
+\diff R' = \{\, (0, 1, y) \mid y \le -1 \,\}
+$$
+and we obtain the approximation
+$$
+n \to \{\, (x, y) \to (x', y') \mid n \ge 2 \wedge x' \ge 1 + x \wedge y' \le x + y - x' \,\}
+.
+$$
+If we consider both $\diff R$ and $\diff R'$, then we obtain
+$$
+n \to \{\, (x, y) \to (x', y') \mid n \ge 2 \wedge y' \le 1 - n + y \wedge x' \ge 1 + x \wedge y' \le x + y - x' \,\}
+.
+$$
+Note, however, that this is not the most accurate affine approximation that
+can be obtained.  That would be
+$$
+n \to \{\, (x, y) \to (x', y') \mid y' \le 2 - n + x + y - x' \wedge n \ge 2 \wedge x' \ge 1 + x \,\}
+.
+$$
+\end{example}
+
+\subsection{Checking Exactness}
+
+The approximation $T$ for the transitive closure $R^+$ can be obtained
+by projecting out the parameter $k$ from the approximation $K$
+\eqref{eq:transitive:approx} of the power $R^k$.
+Since $K$ is an overapproximation of $R^k$, $T$ will also be an
+overapproximation of $R^+$.
+To check whether the results are exact, we need to consider two
+cases depending on whether $R$ is {\em cyclic}, where $R$ is defined
+to be cyclic if $R^+$ maps any element to itself, i.e.,
+$R^+ \cap \identity \ne \emptyset$.
+If $R$ is acyclic, then the inductive definition of
+\eqref{eq:transitive:inductive} is equivalent to its completion,
+i.e.,
+$$
+R^+ = R \cup \left(R \circ R^+\right)
+$$
+is a defining property.
+Since $T$ is known to be an overapproximation, we only need to check
+whether
+$$
+T \subseteq R \cup \left(R \circ T\right)
+.
+$$
+This is essentially Theorem~5 of \textcite{Kelly1996closure}.
+The only difference is that they only consider lexicographically
+forward relations, a special case of acyclic relations.
+
+If, on the other hand, $R$ is cyclic, then we have to resort
+to checking whether the approximation $K$ of the power is exact.
+Note that $T$ may be exact even if $K$ is not exact, so the check
+is sound, but incomplete.
+To check exactness of the power, we simply need to check
+\eqref{eq:transitive:power}.  Since again $K$ is known
+to be an overapproximation, we only need to check whether
+$$
+\begin{aligned}
+K'|_{y_{d+1} - x_{d+1} = 1} & \subseteq R'
+\\
+K'|_{y_{d+1} - x_{d+1} \ge 2} & \subseteq R' \circ K'|_{y_{d+1} - x_{d+1} \ge 1}
+,
+\end{aligned}
+$$
+where $R' = \{\, \vec x' \to \vec y' \mid \vec x \to \vec y \in R
+\wedge y_{d+1} - x_{d+1} = 1\,\}$, i.e., $R$ extended with path
+lengths equal to 1.
+
+All that remains is to explain how to check the cyclicity of $R$.
+Note that the exactness on the power is always sound, even
+in the acyclic case, so we only need to be careful that we find
+all cyclic cases.  Now, if $R$ is cyclic, i.e.,
+$R^+ \cap \identity \ne \emptyset$, then, since $T$ is
+an overapproximation of $R^+$, also
+$T \cap \identity \ne \emptyset$.  This in turn means
+that $\Delta \, K'$ contains a point whose first $d$ coordinates
+are zero and whose final coordinate is positive.
+In the implementation we currently perform this test on $P'$ instead of $K'$.
+Note that if $R^+$ is acyclic and $T$ is not, then the approximation
+is clearly not exact and the approximation of the power $K$
+will not be exact either.
+
+\subsection{Decomposing $R$ into strongly connected components}
+
+If the input relation $R$ is a union of several basic relations
+that can be partially ordered
+then the accuracy of the approximation may be improved by computing
+an approximation of each strongly connected components separately.
+For example, if $R = R_1 \cup R_2$ and $R_1 \circ R_2 = \emptyset$,
+then we know that any path that passes through $R_2$ cannot later
+pass through $R_1$, i.e.,
+\begin{equation}
+\label{eq:transitive:components}
+R^+ = R_1^+ \cup R_2^+ \cup \left(R_2^+ \circ R_1^+\right)
+.
+\end{equation}
+We can therefore compute (approximations of) transitive closures
+of $R_1$ and $R_2$ separately.
+Note, however, that the condition $R_1 \circ R_2 = \emptyset$
+is actually too strong.
+If $R_1 \circ R_2$ is a subset of $R_2 \circ R_1$
+then we can reorder the segments
+in any path that moves through both $R_1$ and $R_2$ to
+first move through $R_1$ and then through $R_2$.
+
+This idea can be generalized to relations that are unions
+of more than two basic relations by constructing the
+strongly connected components in the graph with as vertices
+the basic relations and an edge between two basic relations
+$R_i$ and $R_j$ if $R_i$ needs to follow $R_j$ in some paths.
+That is, there is an edge from $R_i$ to $R_j$ iff
+\begin{equation}
+\label{eq:transitive:edge}
+R_i \circ R_j
+\not\subseteq
+R_j \circ R_i
+.
+\end{equation}
+The components can be obtained from the graph by applying
+Tarjan's algorithm \parencite{Tarjan1972}.
+
+In practice, we compute the (extended) powers $K_i'$ of each component
+separately and then compose them as in \eqref{eq:transitive:decompose}.
+Note, however, that in this case the order in which we apply them is
+important and should correspond to a topological ordering of the
+strongly connected components.  Simply applying Tarjan's
+algorithm will produce topologically sorted strongly connected components.
+The graph on which Tarjan's algorithm is applied is constructed on-the-fly.
+That is, whenever the algorithm checks if there is an edge between
+two vertices, we evaluate \eqref{eq:transitive:edge}.
+The exactness check is performed on each component separately.
+If the approximation turns out to be inexact for any of the components,
+then the entire result is marked inexact and the exactness check
+is skipped on the components that still need to be handled.
+
+It should be noted that \eqref{eq:transitive:components}
+is only valid for exact transitive closures.
+If overapproximations are computed in the right hand side, then the result will
+still be an overapproximation of the left hand side, but this result
+may not be transitively closed.  If we only separate components based
+on the condition $R_i \circ R_j = \emptyset$, then there is no problem,
+as this condition will still hold on the computed approximations
+of the transitive closures.  If, however, we have exploited
+\eqref{eq:transitive:edge} during the decomposition and if the
+result turns out not to be exact, then we check whether
+the result is transitively closed.  If not, we recompute
+the transitive closure, skipping the decomposition.
+Note that testing for transitive closedness on the result may
+be fairly expensive, so we may want to make this check
+configurable.
+
+\begin{figure}
+\begin{center}
+\begin{tikzpicture}[x=0.5cm,y=0.5cm,>=stealth,shorten >=1pt]
+\foreach \x in {1,...,10}{
+    \foreach \y in {1,...,10}{
+	\draw[->] (\x,\y) -- (\x,\y+1);
+    }
+}
+\foreach \x in {1,...,20}{
+    \foreach \y in {5,...,15}{
+	\draw[->] (\x,\y) -- (\x+1,\y);
+    }
+}
+\end{tikzpicture}
+\end{center}
+\caption{The relation from \autoref{ex:closure4}}
+\label{f:closure4}
+\end{figure}
+\begin{example}
+\label{ex:closure4}
+Consider the relation in example {\tt closure4} that comes with
+the Omega calculator~\parencite{Omega_calc}, $R = R_1 \cup R_2$,
+with
+$$
+\begin{aligned}
+R_1 & = \{\, (x,y) \to (x,y+1) \mid 1 \le x,y \le 10 \,\}
+\\
+R_2 & = \{\, (x,y) \to (x+1,y) \mid 1 \le x \le 20 \wedge 5 \le y \le 15 \,\}
+.
+\end{aligned}
+$$
+This relation is shown graphically in \autoref{f:closure4}.
+We have
+$$
+\begin{aligned}
+R_1 \circ R_2 &=
+\{\, (x,y) \to (x+1,y+1) \mid 1 \le x \le 9 \wedge 5 \le y \le 10 \,\}
+\\
+R_2 \circ R_1 &=
+\{\, (x,y) \to (x+1,y+1) \mid 1 \le x \le 10 \wedge 4 \le y \le 10 \,\}
+.
+\end{aligned}
+$$
+Clearly, $R_1 \circ R_2 \subseteq R_2 \circ R_1$ and so
+$$
+\left(
+R_1 \cup R_2
+\right)^+
+=
+\left(R_2^+ \circ R_1^+\right)
+\cup R_1^+
+\cup R_2^+
+.
+$$
+\end{example}
+
+\begin{figure}
+\newcounter{n}
+\newcounter{t1}
+\newcounter{t2}
+\newcounter{t3}
+\newcounter{t4}
+\begin{center}
+\begin{tikzpicture}[>=stealth,shorten >=1pt]
+\setcounter{n}{7}
+\foreach \i in {1,...,\value{n}}{
+    \foreach \j in {1,...,\value{n}}{
+	\setcounter{t1}{2 * \j - 4 - \i + 1}
+	\setcounter{t2}{\value{n} - 3 - \i + 1}
+	\setcounter{t3}{2 * \i - 1 - \j + 1}
+	\setcounter{t4}{\value{n} - \j + 1}
+	\ifnum\value{t1}>0\ifnum\value{t2}>0
+	\ifnum\value{t3}>0\ifnum\value{t4}>0
+	    \draw[thick,->] (\i,\j) to[out=20] (\i+3,\j);
+	\fi\fi\fi\fi
+	\setcounter{t1}{2 * \j - 1 - \i + 1}
+	\setcounter{t2}{\value{n} - \i + 1}
+	\setcounter{t3}{2 * \i - 4 - \j + 1}
+	\setcounter{t4}{\value{n} - 3 - \j + 1}
+	\ifnum\value{t1}>0\ifnum\value{t2}>0
+	\ifnum\value{t3}>0\ifnum\value{t4}>0
+	    \draw[thick,->] (\i,\j) to[in=-20,out=20] (\i,\j+3);
+	\fi\fi\fi\fi
+	\setcounter{t1}{2 * \j - 1 - \i + 1}
+	\setcounter{t2}{\value{n} - 1 - \i + 1}
+	\setcounter{t3}{2 * \i - 1 - \j + 1}
+	\setcounter{t4}{\value{n} - 1 - \j + 1}
+	\ifnum\value{t1}>0\ifnum\value{t2}>0
+	\ifnum\value{t3}>0\ifnum\value{t4}>0
+	    \draw[thick,->] (\i,\j) to (\i+1,\j+1);
+	\fi\fi\fi\fi
+    }
+}
+\end{tikzpicture}
+\end{center}
+\caption{The relation from \autoref{ex:decomposition}}
+\label{f:decomposition}
+\end{figure}
+\begin{example}
+\label{ex:decomposition}
+Consider the relation on the right of \textcite[Figure~2]{Beletska2009},
+reproduced in \autoref{f:decomposition}.
+The relation can be described as $R = R_1 \cup R_2 \cup R_3$,
+with
+$$
+\begin{aligned}
+R_1 &= n \mapsto \{\, (i,j) \to (i+3,j) \mid
+i \le 2 j - 4 \wedge
+i \le n - 3 \wedge
+j \le 2 i - 1 \wedge
+j \le n \,\}
+\\
+R_2 &= n \mapsto \{\, (i,j) \to (i,j+3) \mid
+i \le 2 j - 1 \wedge
+i \le n \wedge
+j \le 2 i - 4 \wedge
+j \le n - 3 \,\}
+\\
+R_3 &= n \mapsto \{\, (i,j) \to (i+1,j+1) \mid
+i \le 2 j - 1 \wedge
+i \le n - 1 \wedge
+j \le 2 i - 1 \wedge
+j \le n - 1\,\}
+.
+\end{aligned}
+$$
+The figure shows this relation for $n = 7$.
+Both
+$R_3 \circ R_1 \subseteq R_1 \circ R_3$
+and
+$R_3 \circ R_2 \subseteq R_2 \circ R_3$,
+which the reader can verify using the {\tt iscc} calculator:
+\begin{verbatim}
+R1 := [n] -> { [i,j] -> [i+3,j] : i <= 2 j - 4 and i <= n - 3 and
+                                  j <= 2 i - 1 and j <= n };
+R2 := [n] -> { [i,j] -> [i,j+3] : i <= 2 j - 1 and i <= n and
+                                  j <= 2 i - 4 and j <= n - 3 };
+R3 := [n] -> { [i,j] -> [i+1,j+1] : i <= 2 j - 1 and i <= n - 1 and
+                                    j <= 2 i - 1 and j <= n - 1 };
+(R1 . R3) - (R3 . R1);
+(R2 . R3) - (R3 . R2);
+\end{verbatim}
+$R_3$ can therefore be moved forward in any path.
+For the other two basic relations, we have both
+$R_2 \circ R_1 \not\subseteq R_1 \circ R_2$
+and
+$R_1 \circ R_2 \not\subseteq R_2 \circ R_1$
+and so $R_1$ and $R_2$ form a strongly connected component.
+By computing the power of $R_3$ and $R_1 \cup R_2$ separately
+and composing the results, the power of $R$ can be computed exactly
+using \eqref{eq:transitive:singleton}.
+As explained by \textcite{Beletska2009}, applying the same formula
+to $R$ directly, without a decomposition, would result in
+an overapproximation of the power.
+\end{example}
+
+\subsection{Partitioning the domains and ranges of $R$}
+
+The algorithm of \autoref{s:power} assumes that the input relation $R$
+can be treated as a union of translations.
+This is a reasonable assumption if $R$ maps elements of a given
+abstract domain to the same domain.
+However, if $R$ is a union of relations that map between different
+domains, then this assumption no longer holds.
+In particular, when an entire dependence graph is encoded
+in a single relation, as is done by, e.g.,
+\textcite[Section~6.1]{Barthou2000MSE}, then it does not make
+sense to look at differences between iterations of different domains.
+Now, arguably, a modified Floyd-Warshall algorithm should
+be applied to the dependence graph, as advocated by
+\textcite{Kelly1996closure}, with the transitive closure operation
+only being applied to relations from a given domain to itself.
+However, it is also possible to detect disjoint domains and ranges
+and to apply Floyd-Warshall internally.
+
+\LinesNumbered
+\begin{algorithm}
+\caption{The modified Floyd-Warshall algorithm of
+\protect\textcite{Kelly1996closure}}
+\label{a:Floyd}
+\SetKwInput{Input}{Input}
+\SetKwInput{Output}{Output}
+\Input{Relations $R_{pq}$, $0 \le p, q < n$}
+\Output{Updated relations $R_{pq}$ such that each relation
+$R_{pq}$ contains all indirect paths from $p$ to $q$ in the input graph}
+%
+\BlankLine
+\SetAlgoVlined
+\DontPrintSemicolon
+%
+\For{$r \in [0, n-1]$}{
+    $R_{rr} \coloneqq R_{rr}^+$ \nllabel{l:Floyd:closure}\;
+    \For{$p \in [0, n-1]$}{
+	\For{$q \in [0, n-1]$}{
+	    \If{$p \ne r$ or $q \ne r$}{
+		$R_{pq} \coloneqq R_{pq} \cup \left(R_{rq} \circ R_{pr}\right)
+			     \cup \left(R_{rq} \circ R_{rr} \circ R_{pr}\right)$
+	     \nllabel{l:Floyd:update}
+	     }
+	}
+    }
+}
+\end{algorithm}
+
+Let the input relation $R$ be a union of $m$ basic relations $R_i$.
+Let $D_{2i}$ be the domains of $R_i$ and $D_{2i+1}$ the ranges of $R_i$.
+The first step is to group overlapping $D_j$ until a partition is
+obtained.  If the resulting partition consists of a single part,
+then we continue with the algorithm of \autoref{s:power}.
+Otherwise, we apply Floyd-Warshall on the graph with as vertices
+the parts of the partition and as edges the $R_i$ attached to
+the appropriate pairs of vertices.
+In particular, let there be $n$ parts $P_k$ in the partition.
+We construct $n^2$ relations
+$$
+R_{pq} \coloneqq \bigcup_{i \text{ s.t. } \domain R_i \subseteq P_p \wedge
+				 \range R_i \subseteq P_q} R_i
+,
+$$
+apply \autoref{a:Floyd} and return the union of all resulting
+$R_{pq}$ as the transitive closure of $R$.
+Each iteration of the $r$-loop in \autoref{a:Floyd} updates
+all relations $R_{pq}$ to include paths that go from $p$ to $r$,
+possibly stay there for a while, and then go from $r$ to $q$.
+Note that paths that ``stay in $r$'' include all paths that
+pass through earlier vertices since $R_{rr}$ itself has been updated
+accordingly in previous iterations of the outer loop.
+In principle, it would be sufficient to use the $R_{pr}$
+and $R_{rq}$ computed in the previous iteration of the
+$r$-loop in Line~\ref{l:Floyd:update}.
+However, from an implementation perspective, it is easier
+to allow either or both of these to have been updated
+in the same iteration of the $r$-loop.
+This may result in duplicate paths, but these can usually
+be removed by coalescing (\autoref{s:coalescing}) the result of the union
+in Line~\ref{l:Floyd:update}, which should be done in any case.
+The transitive closure in Line~\ref{l:Floyd:closure}
+is performed using a recursive call.  This recursive call
+includes the partitioning step, but the resulting partition will
+usually be a singleton.
+The result of the recursive call will either be exact or an
+overapproximation.  The final result of Floyd-Warshall is therefore
+also exact or an overapproximation.
+
+\begin{figure}
+\begin{center}
+\begin{tikzpicture}[x=1cm,y=1cm,>=stealth,shorten >=3pt]
+\foreach \x/\y in {0/0,1/1,3/2} {
+    \fill (\x,\y) circle (2pt);
+}
+\foreach \x/\y in {0/1,2/2,3/3} {
+    \draw (\x,\y) circle (2pt);
+}
+\draw[->] (0,0) -- (0,1);
+\draw[->] (0,1) -- (1,1);
+\draw[->] (2,2) -- (3,2);
+\draw[->] (3,2) -- (3,3);
+\draw[->,dashed] (2,2) -- (3,3);
+\draw[->,dotted] (0,0) -- (1,1);
+\end{tikzpicture}
+\end{center}
+\caption{The relation (solid arrows) on the right of Figure~1 of
+\protect\textcite{Beletska2009} and its transitive closure}
+\label{f:COCOA:1}
+\end{figure}
+\begin{example}
+Consider the relation on the right of Figure~1 of
+\textcite{Beletska2009},
+reproduced in \autoref{f:COCOA:1}.
+This relation can be described as
+$$
+\begin{aligned}
+\{\, (x, y) \to (x_2, y_2) \mid {} & (3y = 2x \wedge x_2 = x \wedge 3y_2 = 3 + 2x \wedge x \ge 0 \wedge x \le 3) \vee {} \\
+& (x_2 = 1 + x \wedge y_2 = y \wedge x \ge 0 \wedge 3y \ge 2 + 2x \wedge x \le 2 \wedge 3y \le 3 + 2x) \,\}
+.
+\end{aligned}
+$$
+Note that the domain of the upward relation overlaps with the range
+of the rightward relation and vice versa, but that the domain
+of neither relation overlaps with its own range or the domain of
+the other relation.
+The domains and ranges can therefore be partitioned into two parts,
+$P_0$ and $P_1$, shown as the white and black dots in \autoref{f:COCOA:1},
+respectively.
+Initially, we have
+$$
+\begin{aligned}
+R_{00} & = \emptyset
+\\
+R_{01} & = 
+\{\, (x, y) \to (x+1, y) \mid 
+(x \ge 0 \wedge 3y \ge 2 + 2x \wedge x \le 2 \wedge 3y \le 3 + 2x) \,\}
+\\
+R_{10} & =
+\{\, (x, y) \to (x_2, y_2) \mid (3y = 2x \wedge x_2 = x \wedge 3y_2 = 3 + 2x \wedge x \ge 0 \wedge x \le 3) \,\}
+\\
+R_{11} & = \emptyset
+.
+\end{aligned}
+$$
+In the first iteration, $R_{00}$ remains the same ($\emptyset^+ = \emptyset$).
+$R_{01}$ and $R_{10}$ are therefore also unaffected, but
+$R_{11}$ is updated to include $R_{01} \circ R_{10}$, i.e.,
+the dashed arrow in the figure.
+This new $R_{11}$ is obviously transitively closed, so it is not
+changed in the second iteration and it does not have an effect
+on $R_{01}$ and $R_{10}$.  However, $R_{00}$ is updated to
+include $R_{10} \circ R_{01}$, i.e., the dotted arrow in the figure.
+The transitive closure of the original relation is then equal to
+$R_{00} \cup R_{01} \cup R_{10} \cup R_{11}$.
+\end{example}
+
+\subsection{Incremental Computation}
+\label{s:incremental}
+
+In some cases it is possible and useful to compute the transitive closure
+of union of basic relations incrementally.  In particular,
+if $R$ is a union of $m$ basic maps,
+$$
+R = \bigcup_j R_j
+,
+$$
+then we can pick some $R_i$ and compute the transitive closure of $R$ as
+\begin{equation}
+\label{eq:transitive:incremental}
+R^+ = R_i^+ \cup
+\left(
+\bigcup_{j \ne i}
+R_i^* \circ R_j \circ R_i^*
+\right)^+
+.
+\end{equation}
+For this approach to be successful, it is crucial that each
+of the disjuncts in the argument of the second transitive
+closure in \eqref{eq:transitive:incremental} be representable
+as a single basic relation, i.e., without a union.
+If this condition holds, then by using \eqref{eq:transitive:incremental},
+the number of disjuncts in the argument of the transitive closure
+can be reduced by one.
+Now, $R_i^* = R_i^+ \cup \identity$, but in some cases it is possible
+to relax the constraints of $R_i^+$ to include part of the identity relation,
+say on domain $D$.  We will use the notation
+${\cal C}(R_i,D) = R_i^+ \cup \identity_D$ to represent
+this relaxed version of $R^+$.
+\textcite{Kelly1996closure} use the notation $R_i^?$.
+${\cal C}(R_i,D)$ can be computed by allowing $k$ to attain
+the value $0$ in \eqref{eq:transitive:Q} and by using
+$$
+P \cap \left(D \to D\right)
+$$
+instead of \eqref{eq:transitive:approx}.
+Typically, $D$ will be a strict superset of both $\domain R_i$
+and $\range R_i$.  We therefore need to check that domain
+and range of the transitive closure are part of ${\cal C}(R_i,D)$,
+i.e., the part that results from the paths of positive length ($k \ge 1$),
+are equal to the domain and range of $R_i$.
+If not, then the incremental approach cannot be applied for
+the given choice of $R_i$ and $D$.
+
+In order to be able to replace $R^*$ by ${\cal C}(R_i,D)$
+in \eqref{eq:transitive:incremental}, $D$ should be chosen
+to include both $\domain R$ and $\range R$, i.e., such
+that $\identity_D \circ R_j \circ \identity_D = R_j$ for all $j\ne i$.
+\textcite{Kelly1996closure} say that they use
+$D = \domain R_i \cup \range R_i$, but presumably they mean that
+they use $D = \domain R \cup \range R$.
+Now, this expression of $D$ contains a union, so it not directly usable.
+\textcite{Kelly1996closure} do not explain how they avoid this union.
+Apparently, in their implementation,
+they are using the convex hull of $\domain R \cup \range R$
+or at least an approximation of this convex hull.
+We use the simple hull (\autoref{s:simple hull}) of $\domain R \cup \range R$.
+
+It is also possible to use a domain $D$ that does {\em not\/}
+include $\domain R \cup \range R$, but then we have to
+compose with ${\cal C}(R_i,D)$ more selectively.
+In particular, if we have
+\begin{equation}
+\label{eq:transitive:right}
+\text{for each $j \ne i$ either }
+\domain R_j \subseteq D \text{ or } \domain R_j \cap \range R_i = \emptyset
+\end{equation}
+and, similarly,
+\begin{equation}
+\label{eq:transitive:left}
+\text{for each $j \ne i$ either }
+\range R_j \subseteq D \text{ or } \range R_j \cap \domain R_i = \emptyset
+\end{equation}
+then we can refine \eqref{eq:transitive:incremental} to
+$$
+R_i^+ \cup
+\left(
+\left(
+\bigcup_{\shortstack{$\scriptstyle\domain R_j \subseteq D $\\
+		     $\scriptstyle\range R_j \subseteq D$}}
+{\cal C} \circ R_j \circ {\cal C}
+\right)
+\cup
+\left(
+\bigcup_{\shortstack{$\scriptstyle\domain R_j \cap \range R_i = \emptyset$\\
+		     $\scriptstyle\range R_j \subseteq D$}}
+\!\!\!\!\!
+{\cal C} \circ R_j
+\right)
+\cup
+\left(
+\bigcup_{\shortstack{$\scriptstyle\domain R_j \subseteq D $\\
+		     $\scriptstyle\range R_j \cap \domain R_i = \emptyset$}}
+\!\!\!\!\!
+R_j \circ {\cal C}
+\right)
+\cup
+\left(
+\bigcup_{\shortstack{$\scriptstyle\domain R_j \cap \range R_i = \emptyset$\\
+		     $\scriptstyle\range R_j \cap \domain R_i = \emptyset$}}
+\!\!\!\!\!
+R_j
+\right)
+\right)^+
+.
+$$
+If only property~\eqref{eq:transitive:right} holds,
+we can use
+$$
+R_i^+ \cup
+\left(
+\left(
+R_i^+ \cup \identity
+\right)
+\circ
+\left(
+\left(
+\bigcup_{\shortstack{$\scriptstyle\domain R_j \subseteq D $}}
+R_j \circ {\cal C}
+\right)
+\cup
+\left(
+\bigcup_{\shortstack{$\scriptstyle\domain R_j \cap \range R_i = \emptyset$}}
+\!\!\!\!\!
+R_j
+\right)
+\right)^+
+\right)
+,
+$$
+while if only property~\eqref{eq:transitive:left} holds,
+we can use
+$$
+R_i^+ \cup
+\left(
+\left(
+\left(
+\bigcup_{\shortstack{$\scriptstyle\range R_j \subseteq D $}}
+{\cal C} \circ R_j
+\right)
+\cup
+\left(
+\bigcup_{\shortstack{$\scriptstyle\range R_j \cap \domain R_i = \emptyset$}}
+\!\!\!\!\!
+R_j
+\right)
+\right)^+
+\circ
+\left(
+R_i^+ \cup \identity
+\right)
+\right)
+.
+$$
+
+It should be noted that if we want the result of the incremental
+approach to be transitively closed, then we can only apply it
+if all of the transitive closure operations involved are exact.
+If, say, the second transitive closure in \eqref{eq:transitive:incremental}
+contains extra elements, then the result does not necessarily contain
+the composition of these extra elements with powers of $R_i$.
+
+\subsection{An {\tt Omega}-like implementation}
+
+While the main algorithm of \textcite{Kelly1996closure} is
+designed to compute and underapproximation of the transitive closure,
+the authors mention that they could also compute overapproximations.
+In this section, we describe our implementation of an algorithm
+that is based on their ideas.
+Note that the {\tt Omega} library computes underapproximations
+\parencite[Section 6.4]{Omega_lib}.
+
+The main tool is Equation~(2) of \textcite{Kelly1996closure}.
+The input relation $R$ is first overapproximated by a ``d-form'' relation
+$$
+\{\, \vec i \to \vec j \mid \exists \vec \alpha :
+\vec L \le \vec j - \vec i \le \vec U
+\wedge
+(\forall p : j_p - i_p = M_p \alpha_p)
+\,\}
+,
+$$
+where $p$ ranges over the dimensions and $\vec L$, $\vec U$ and
+$\vec M$ are constant integer vectors.  The elements of $\vec U$
+may be $\infty$, meaning that there is no upper bound corresponding
+to that element, and similarly for $\vec L$.
+Such an overapproximation can be obtained by computing strides,
+lower and upper bounds on the difference set $\Delta \, R$.
+The transitive closure of such a ``d-form'' relation is
+\begin{equation}
+\label{eq:omega}
+\{\, \vec i \to \vec j \mid \exists \vec \alpha, k :
+k \ge 1 \wedge
+k \, \vec L \le \vec j - \vec i \le k \, \vec U
+\wedge
+(\forall p : j_p - i_p = M_p \alpha_p)
+\,\}
+.
+\end{equation}
+The domain and range of this transitive closure are then
+intersected with those of the input relation.
+This is a special case of the algorithm in \autoref{s:power}.
+
+In their algorithm for computing lower bounds, the authors
+use the above algorithm as a substep on the disjuncts in the relation.
+At the end, they say
+\begin{quote}
+If an upper bound is required, it can be calculated in a manner
+similar to that of a single conjunct [sic] relation.
+\end{quote}
+Presumably, the authors mean that a ``d-form'' approximation
+of the whole input relation should be used.
+However, the accuracy can be improved by also trying to
+apply the incremental technique from the same paper,
+which is explained in more detail in \autoref{s:incremental}.
+In this case, ${\cal C}(R_i,D)$ can be obtained by
+allowing the value zero for $k$ in \eqref{eq:omega},
+i.e., by computing
+$$
+\{\, \vec i \to \vec j \mid \exists \vec \alpha, k :
+k \ge 0 \wedge
+k \, \vec L \le \vec j - \vec i \le k \, \vec U
+\wedge
+(\forall p : j_p - i_p = M_p \alpha_p)
+\,\}
+.
+$$
+In our implementation we take as $D$ the simple hull
+(\autoref{s:simple hull}) of $\domain R \cup \range R$.
+To determine whether it is safe to use ${\cal C}(R_i,D)$,
+we check the following conditions, as proposed by
+\textcite{Kelly1996closure}:
+${\cal C}(R_i,D) - R_i^+$ is not a union and for each $j \ne i$
+the condition
+$$
+\left({\cal C}(R_i,D) - R_i^+\right)
+\circ
+R_j
+\circ
+\left({\cal C}(R_i,D) - R_i^+\right)
+=
+R_j
+$$
+holds.
diff --git a/final/lib/External/isl/doc/isl.bib b/final/lib/External/isl/doc/isl.bib
new file mode 100644
index 0000000..42074b2
--- /dev/null
+++ b/final/lib/External/isl/doc/isl.bib
@@ -0,0 +1,485 @@
+@inproceedings{Kelly1996closure,
+  author    = {Wayne Kelly and
+               William Pugh and
+               Evan Rosser and
+               Tatiana Shpeisman},
+  title     = {Transitive Closure of Infinite Graphs and Its Applications},
+  pages     = {126-140},
+  editor    = {Chua-Huang Huang and
+               P. Sadayappan and
+               Utpal Banerjee and
+               David Gelernter and
+               Alexandru Nicolau and
+               David A. Padua},
+  booktitle = {Languages and Compilers for Parallel Computing, 8th International
+               Workshop, LCPC'95, Columbus, Ohio, USA, August 10-12, 1995,
+               Proceedings},
+  publisher = {Springer},
+  series    = {Lecture Notes in Computer Science},
+  volume    = {1033},
+  year      = {1996},
+  isbn      = {3-540-60765-X},
+	doi = "10.1007/BFb0014196",
+}
+
+@inproceedings{Beletska2009,
+  author = {Beletska, Anna and Barthou, Denis and Bielecki, Wlodzimierz and Cohen, Albert},
+  title = {Computing the Transitive Closure of a Union of Affine Integer Tuple Relations},
+  booktitle = {COCOA '09: Proceedings of the 3rd International Conference on Combinatorial Optimization and Applications},
+  year = {2009},
+  isbn = {978-3-642-02025-4},
+  pages = {98--109},
+  location = {Huangshan, China},
+  doi = {10.1007/978-3-642-02026-1_9},
+  publisher = {Springer-Verlag},
+  address = {Berlin, Heidelberg},
+}
+
+@book{Schrijver1986,
+    author  =	"Schrijver, Alexander",
+    title   =	"Theory of Linear and Integer Programming",
+    publisher	=   "John Wiley \& Sons",
+    year    =	1986
+}
+
+@article{Tarjan1972,
+    author = {Tarjan, Robert},
+    journal = {SIAM Journal on Computing},
+    number = {2},
+    pages = {146--160},
+    publisher = {SIAM},
+    title = {Depth-First Search and Linear Graph Algorithms},
+    volume = {1},
+    year = {1972},
+    doi = "10.1137/0201010",
+}
+
+@TechReport{ Omega_calc,
+    author = "Wayne Kelly and Vadim Maslov and William Pugh and Evan Rosser and Tatiana Shpeisman and Dave Wonnacott",
+    title = "The {Omega} Calculator and Library",
+    month = nov,
+    institution = "University of Maryland",
+    year = 1996
+}
+
+@TechReport{ Omega_lib,
+    author = "Wayne Kelly and Vadim Maslov and William Pugh and Evan Rosser and Tatiana Shpeisman and Dave Wonnacott",
+    title = "The {Omega} Library",
+    month = nov,
+    institution = "University of Maryland",
+    year = 1996
+}
+
+@unpublished{Verdoolaege2009isl,
+  author = "Verdoolaege, Sven",
+  title = "An integer set library for program analysis",
+  note = "Advances in the Theory of Integer Linear Optimization and its Extensions,AMS 2009 Spring Western Section Meeting, San Francisco, California, 25-26 April 2009",
+  month = Apr,
+  year = "2009",
+  url = "https://lirias.kuleuven.be/handle/123456789/228373",
+}
+
+@article{Barthou2000MSE,
+  author = {Barthou, Denis and Cohen, Albert and Collard, Jean-Fran\c{c}ois},
+  title = {Maximal Static Expansion},
+  journal = {Int. J. Parallel Program.},
+  volume = {28},
+  number = {3},
+  year = {2000},
+  issn = {0885-7458},
+  pages = {213--243},
+  doi = {10.1023/A:1007500431910},
+  publisher = {Kluwer Academic Publishers},
+  address = {Norwell, MA, USA},
+}
+
+@article{ Feautrier88parametric,
+    author = "P. Feautrier",
+    title = "Parametric Integer Programming",
+    journal = "RAIRO Recherche Op\'erationnelle",
+    volume = "22",
+    number = "3",
+    pages = "243--268",
+    year = "1988",
+}
+
+@Article{ Fea91,
+  author =       {Feautrier, P.},
+  title =        {Dataflow analysis of array and scalar references},
+  journal =      {International Journal of Parallel Programming},
+  year =         {1991},
+  OPTkey =         {},
+  volume =       {20},
+  number =       {1},
+  OPTmonth =     {},
+  pages =        {23--53},
+  OPTnote =      {},
+  OPTannote =    {},
+	doi = "10.1007/BF01407931",
+}
+
+@INPROCEEDINGS{BouletRe98,
+  AUTHOR = {Pierre Boulet and Xavier Redon},
+  TITLE = {Communication Pre-evaluation in {HPF}},
+  BOOKTITLE = {EUROPAR'98},
+  PAGES = {263--272},
+  YEAR = 1998,
+  VOLUME = 1470,
+  series =	 {Lecture Notes in Computer Science},
+  PUBLISHER = {Springer-Verlag, Berlin},
+  ABSTRACT = {  Parallel computers are difficult to program efficiently.  We believe
+  that a good way to help programmers write efficient programs is to
+  provide them with tools that show them how their programs behave on
+  a parallel computer.  Data distribution is the major performance
+  factor of data-parallel programs and so automatic data layout for
+  HPF programs has been studied by many researchers recently.  The
+  communication volume induced by a data distribution is a good
+  estimator of the efficiency of this data distribution.
+
+  We present here a symbolic method to compute the communication
+  volume generated by a given data distribution during the program
+  writing phase (before compilation). We stay machine-independent to
+  assure portability.  Our goal is to help the programmer understand
+  the data movements its program generates and thus find a good data
+  distribution. Our method is based on parametric polyhedral
+  computations. It can be applied to a large class of regular codes.},
+    doi = "10.1007/BFb0057861",
+}
+
+@INPROCEEDINGS {Verdoolaege2005experiences,
+  AUTHOR = "Verdoolaege, Sven and Beyls, Kristof and Bruynooghe, Maurice and Catthoor, Francky",
+  TITLE = {{E}xperiences with enumeration of integer projections of parametric polytopes},
+  BOOKTITLE = {{P}roceedings of 14th {I}nternational {C}onference on {C}ompiler {C}onstruction, {E}dinburgh, {S}cotland},
+  YEAR = {2005},
+  EDITOR = {Bodik, R.},
+  VOLUME = 3443,
+    pages = "91-105",
+    series = "Lecture Notes in Computer Science",
+    publisher = "Springer-Verlag",
+    address = "Berlin",
+    doi = "10.1007/b107108",
+}
+
+@article{Detlefs2005simplify,
+ author = {David Detlefs and Greg Nelson and James B. Saxe},
+ title = {Simplify: a theorem prover for program checking},
+ journal = {J. ACM},
+ volume = {52},
+ number = {3},
+ year = {2005},
+ issn = {0004-5411},
+ pages = {365--473},
+ doi = {10.1145/1066100.1066102},
+ publisher = {ACM},
+ address = {New York, NY, USA},
+ }
+
+@phdthesis{Nelson1980phd,
+ author = {Charles Gregory Nelson},
+ title = {Techniques for program verification},
+ year = {1980},
+ order_no = {AAI8011683},
+ school = {Stanford University},
+ address = {Stanford, CA, USA},
+ }
+
+@article{Woods2003short,
+    year = 2003,
+    Journal = "J. Amer. Math. Soc.",
+    volume =  16,
+    pages = "957--979",
+    month = apr,
+    title = {{Short rational generating functions for lattice point
+        problems}},
+    author = {Alexander Barvinok and Kevin Woods},
+    doi = "10.1090/S0894-0347-03-00428-4",
+}
+
+@misc{barvinok-0.22,
+  author = {Sven Verdoolaege},
+  title = {{\texttt{barvinok}}, version 0.22},
+  howpublished = {Available from \url{http://barvinok.gforge.inria.fr/}},
+  year = 2006
+}
+
+@inproceedings{DeLoera2004Three,
+    title = "Three Kinds of Integer Programming Algorithms based on Barvinok's Rational Functions",
+    author = "De Loera, J. A. and D. Haws and R. Hemmecke and P. Huggins and R. Yoshida",
+    booktitle = "Integer Programming and Combinatorial Optimization: 10th International IPCO Conference",
+    year = "2004",
+    month = jan,
+    series = "Lecture Notes in Computer Science",
+    Volume = 3064,
+    Pages = "244-255",
+    doi = "10.1007/978-3-540-25960-2_19",
+}
+
+@TechReport{Feautrier02,
+  author = 	 {P. Feautrier and J. Collard and C. Bastoul},
+  title = 	 {Solving systems of affine (in)equalities},
+  institution =  {PRiSM, Versailles University},
+  year = 	 2002
+}
+
+@article{ Feautrier92multi,
+    author = "Paul Feautrier",
+    title = "Some Efficient Solutions to the Affine Scheduling Problem. {P}art {II}. Multidimensional Time",
+    journal = "International Journal of Parallel Programming",
+    volume = "21",
+    number = "6",
+    pages = "389--420",
+    year = "1992",
+    month = dec,
+    url = "citeseer.nj.nec.com/article/feautrier92some.html",
+	doi = "10.1007/BF01379404",
+}
+
+@misc{Bygde2010licentiate,
+   author = {Stefan Bygde},
+   title = {Static {WCET} Analysis based on Abstract Interpretation and Counting of Elements},
+   month = {March},
+   year = {2010},
+   howpublished = {Licentiate thesis},
+   publisher = {M{\"{a}}lardalen University Press},
+   url = {http://www.mrtc.mdh.se/index.php?choice=publications&id=2144},
+}
+
+@phdthesis{Meister2004PhD,
+	title = {Stating and Manipulating Periodicity in the Polytope Model. Applications to Program Analysis and Optimization},
+	author= {Beno\^it Meister},
+ 	school = {Universit\'e Louis Pasteur},
+	month = Dec,
+	year  = {2004},
+}
+
+@inproceedings{Meister2008,
+  author = {Beno\^it Meister and Sven Verdoolaege},
+  title = {Polynomial Approximations in the Polytope Model: Bringing the Power
+  of Quasi-Polynomials to the Masses},
+  year = {2008},
+  booktitle = {Digest of the 6th Workshop on Optimization for DSP and Embedded Systems, ODES-6},
+  editor = "Jagadeesh Sankaran and Vander Aa, Tom",
+  month = apr,
+}
+
+@misc{Galea2009personal,
+    author = "Fran\c{c}ois Galea",
+    title = "personal communication",
+    year = 2009,
+    month = nov,
+}
+
+@misc{PPL,
+  author = "R. Bagnara and P. M. Hill and E. Zaffanella",
+  title = "The {Parma Polyhedra Library}",
+  howpublished = {\url{http://www.cs.unipr.it/ppl/}},
+}
+
+@TECHREPORT{Cook1991implementation,
+AUTHOR={William Cook and Thomas Rutherford and Herbert E. Scarf and David F. Shallcross},
+TITLE={An Implementation of the Generalized Basis Reduction Algorithm for Integer Programming},
+YEAR=1991,
+MONTH=Aug,
+INSTITUTION={Cowles Foundation, Yale University},
+TYPE={Cowles Foundation Discussion Papers},
+NOTE={available at \url{http://ideas.repec.org/p/cwl/cwldpp/990.html}},
+NUMBER={990},
+}
+
+ @article{Karr1976affine,
+author={ Michael Karr},
+title={ Affine Relationships Among Variables of a Program },
+journal={Acta Informatica},
+Volume={6},
+pages={133-151},
+year={1976},
+publisher={Springer-Verlag},
+ignore={ },
+	doi = "10.1007/BF00268497",
+}
+
+@PhdThesis{Verhaegh1995PhD,
+	title = "Multidimensional Periodic Scheduling",
+	author = "Wim F. J. Verhaegh",
+	school = "Technische Universiteit Eindhoven",
+	year = 1995,
+}
+
+@INPROCEEDINGS{Seghir2006minimizing,
+  AUTHOR = "Rachid Seghir and Vincent Loechner",
+  TITLE = {Memory Optimization by Counting Points in Integer Transformations of Parametric Polytopes},
+  BOOKTITLE = {{P}roceedings of the {I}nternational {C}onference on {C}ompilers, {A}rchitectures, and {S}ynthesis for {E}mbedded Systems, CASES 2006, {S}eoul, {K}orea},
+  month = oct,
+  YEAR = {2006},
+  doi = {10.1145/1176760.1176771},
+}
+
+@misc{DeSmet2010personal,
+    author = "De Smet, Sven",
+    title = "personal communication",
+    year = 2010,
+    month = apr,
+}
+
+@inproceedings{Verdoolaege2015impact,
+ author = {Verdoolaege, Sven},
+ title = {Integer Set Coalescing},
+ booktitle = {Proceedings of the 5th International Workshop on
+	Polyhedral Compilation Techniques},
+ year   = 2015,
+ month  = Jan,
+ address = {Amsterdam, The Netherlands},
+ abstract = {
+In polyhedral compilation, various core concepts such as the set
+of statement instances, the access relations, the dependences and
+the schedule are represented or approximated using sets and binary
+relations of sequences of integers bounded by (quasi-)affine constraints.
+When these sets and relations are represented in disjunctive normal form,
+it is important to keep the number of disjuncts small, both for efficiency
+and to improve the computation of transitive closure overapproximations
+and AST generation.  This paper describes the set coalescing operation
+of isl that looks for opportunities to combine several disjuncts into
+a single disjunct without affecting the elements in the set.  The main
+purpose of the paper is to explain the various heuristics and to prove
+their correctness.
+ },
+	doi = "10.13140/2.1.1313.6968",
+}
+
+@misc{Verdoolaege2016tutorial,
+	author = "Sven Verdoolaege",
+	title = "Presburger Formulas and Polyhedral Compilation",
+	year = 2016,
+	doi = "10.13140/RG.2.1.1174.6323",
+}
+
+@inproceedings{Verdoolaege2009equivalence,
+	author = "Sven Verdoolaege and Gerda Janssens and Maurice Bruynooghe",
+	title = "Equivalence checking of static affine programs using widening to handle recurrences",
+	booktitle = "Computer Aided Verification 21",
+	month = Jun,
+	year = 2009,
+	pages = "599--613",
+	publisher = "Springer",
+	doi = "10.1007/978-3-642-02658-4_44",
+}
+
+@incollection{Verdoolaege2010isl,
+   author = {Verdoolaege, Sven},
+   title = {isl: An Integer Set Library for the Polyhedral Model},
+   booktitle = {Mathematical Software - ICMS 2010},
+   series = {Lecture Notes in Computer Science},
+   editor = {Fukuda, Komei and Hoeven, Joris and Joswig, Michael and Takayama, Nobuki},
+   publisher = {Springer},
+   isbn = {},
+   pages = {299-302},
+   volume = {6327},
+   year = {2010},
+   doi = {10.1007/978-3-642-15582-6_49},
+}
+
+@incollection{Verdoolaege2010networks,
+  author = "Verdoolaege, Sven",
+  title = "Polyhedral process networks",
+  editor = "Bhattacharrya, Shuvra and Deprettere, Ed and Leupers, Rainer and Takala, Jarmo",
+  publisher = "Springer",
+  year = "2010",
+  doi = "10.1007/978-1-4419-6345-1\_{}33",
+  pages = "931--965",
+  booktitle = "Handbook of Signal Processing Systems",
+  url = "https://lirias.kuleuven.be/handle/123456789/235370",
+	doi = "10.1007/978-1-4419-6345-1_33",
+}
+
+@InProceedings{Verdoolaege2011iscc,
+  author = 	 {Sven Verdoolaege},
+  title = 	 {Counting Affine Calculator and Applications},
+  booktitle = { First International Workshop on Polyhedral Compilation Techniques (IMPACT'11)},
+  address = { Chamonix, France},
+  month = 	 apr,
+  year = 	 {2011},
+	doi = "10.13140/RG.2.1.2959.5601",
+}
+
+@inproceedings{Verdoolaege2011closure,
+ author = {Verdoolaege, Sven and Cohen, Albert and Beletska, Anna},
+ title = {Transitive Closures of Affine Integer Tuple Relations and Their Overapproximations},
+ booktitle = {Proceedings of the 18th International Conference on Static Analysis},
+ series = {SAS'11},
+ year = {2011},
+ isbn = {978-3-642-23701-0},
+ location = {Venice, Italy},
+ pages = {216--232},
+ numpages = {17},
+ acmid = {2041570},
+ publisher = {Springer-Verlag},
+ address = {Berlin, Heidelberg},
+ doi = "10.1007/978-3-642-23702-7_18",
+}
+
+@article{Verdoolaege2013PPCG,
+  title={Polyhedral parallel code generation for {CUDA}},
+  author={Verdoolaege, Sven and Juega, Juan Carlos and Cohen, Albert and G{\'o}mez, Jos{\'e} Ignacio and Tenllado, Christian and Catthoor, Francky},
+  journal = {ACM Trans. Archit. Code Optim.},
+  volume={9},
+  number={4},
+  pages={54},
+  year={2013},
+  publisher={ACM},
+    doi = {10.1145/2400682.2400713},
+}
+
+@inproceedings{Verdoolaege2014impact,
+ author = {Verdoolaege, Sven and Guelton, Serge and
+	Grosser, Tobias and Cohen, Albert},
+ title = {Schedule Trees},
+ booktitle = {Proceedings of the 4th International Workshop on Polyhedral Compilation Techniques},
+ year   = 2014,
+ month  = Jan,
+ address = {Vienna, Austria},
+ url = {http://impact.gforge.inria.fr/impact2014/papers/impact2014-verdoolaege.pdf},
+ abstract = {
+ Schedules in the polyhedral model, both those that represent the original
+execution order and those produced by scheduling algorithms, naturally have the
+form of a tree. Generic schedule representations proposed in the literature
+encode this tree structure such that it is only implicitly available.
+Following the internal representation of isl , we propose to represent
+schedules as explicit trees and further extend the concept by introducing
+different kinds of nodes. We compare our schedule trees to other
+representations in detail and illustrate how they have been successfully used
+to simplify the implementation of a non-trivial polyhedral compiler.
+ },
+	DOI = {10.13140/RG.2.1.4475.6001},
+}
+
+@article{Grosser2015AST,
+	author = "Tobias Grosser and Sven Verdoolaege and Albert Cohen",
+	title = "Polyhedral {AST} generation is more than scanning polyhedra",
+	journal = "ACM Transactions on Programming Languages and Systems",
+ issue_date = {August 2015},
+ volume = {37},
+ number = {4},
+ month = jul,
+ year = {2015},
+ issn = {0164-0925},
+ pages = {12:1--12:50},
+ articleno = {12},
+ numpages = {50},
+ url = {http://doi.acm.org/10.1145/2743016},
+ doi = {10.1145/2743016},
+ acmid = {2743016},
+ publisher = {ACM},
+ address = {New York, NY, USA},
+ keywords = {Polyhedral compilation, Presburger relations, code generation, index set splitting, unrolling},
+}
+
+@inproceedings{Verdoolaege2016reordering,
+	author = {Sven Verdoolaege and Albert Cohen},
+	title = "Live-Range Reordering",
+ booktitle = {Proceedings of the sixth International Workshop on
+	Polyhedral Compilation Techniques},
+ year   = 2016,
+ month  = Jan,
+ address = {Prague, Czech Republic},
+	doi = "10.13140/RG.2.1.3272.9680",
+}
diff --git a/final/lib/External/isl/doc/manual.tex b/final/lib/External/isl/doc/manual.tex
new file mode 100644
index 0000000..3116241
--- /dev/null
+++ b/final/lib/External/isl/doc/manual.tex
@@ -0,0 +1,95 @@
+\documentclass{report}
+\usepackage[T1]{fontenc}
+\usepackage[plainpages=false,pdfpagelabels,breaklinks]{hyperref}
+\usepackage[backend=biber,isbn=false,url=false,doi=true,%
+maxbibnames=99,style=authoryear,sortcites=true,sorting=nyt,backref=true,%
+indexing=true,mincitenames=2,maxcitenames=2,datelabel=comp,dashed=false,%
+useprefix=true]{biblatex}
+\usepackage{amsmath}
+\usepackage{amssymb}
+\usepackage{txfonts}
+\usepackage{aliascnt}
+\usepackage{tikz}
+\usepackage{calc}
+\usepackage[ruled]{algorithm2e}
+\usetikzlibrary{matrix,fit,backgrounds,decorations.pathmorphing,positioning}
+\usepackage{listings}
+
+\addbibresource{isl.bib}
+
+\renewbibmacro*{finentry}{\iflistundef{pageref}{}{\renewcommand{\finentrypunct}{}}\finentry}
+\renewbibmacro*{pageref}{%
+  \iflistundef{pageref}
+    {}
+    {\setunit{\adddot\addspace}\printtext{%
+  \mbox{}\penalty100\hfill\hbox{[\printlist[pageref][-\value{listtotal}]{pageref}]}}}}
+
+\lstset{basicstyle=\tt,flexiblecolumns=false}
+
+\def\vec#1{\mathchoice{\mbox{\boldmath$\displaystyle\bf#1$}}
+{\mbox{\boldmath$\textstyle\bf#1$}}
+{\mbox{\boldmath$\scriptstyle\bf#1$}}
+{\mbox{\boldmath$\scriptscriptstyle\bf#1$}}}
+
+\providecommand{\fract}[1]{\left\{#1\right\}}
+\providecommand{\floor}[1]{\left\lfloor#1\right\rfloor}
+\providecommand{\ceil}[1]{\left\lceil#1\right\rceil}
+\def\sp#1#2{\langle #1, #2 \rangle}
+\def\spv#1#2{\langle\vec #1,\vec #2\rangle}
+
+\newtheorem{theorem}{Theorem}
+\newaliascnt{example}{theorem}
+\newtheorem{example}[example]{Example}
+\newaliascnt{def}{theorem}
+\newtheorem{definition}[def]{Definition}
+\aliascntresetthe{example}
+\aliascntresetthe{def}
+\numberwithin{theorem}{section}
+\numberwithin{def}{section}
+\numberwithin{example}{section}
+
+\newcommand{\algocflineautorefname}{Algorithm}
+\newcommand{\exampleautorefname}{Example}
+\newcommand{\lstnumberautorefname}{Line}
+\renewcommand{\sectionautorefname}{Section}
+\renewcommand{\subsectionautorefname}{Section}
+\renewcommand{\algorithmautorefname}{Algorithm}
+
+\DeclareFieldFormat{date}{\hypertarget{\thefield{entrykey}}{#1}}
+\def\isl{\hyperlink{Verdoolaege2010isl}{\texttt{isl}}\xspace}
+
+\def\Z{\mathbb{Z}}
+\def\Q{\mathbb{Q}}
+
+\def\pdom{\mathop{\rm pdom}\nolimits}
+\def\domain{\mathop{\rm dom}\nolimits}
+\def\range{\mathop{\rm ran}\nolimits}
+\def\identity{\mathop{\rm Id}\nolimits}
+\def\diff{\mathop{\Delta}\nolimits}
+
+\providecommand{\floor}[1]{\left\lfloor#1\right\rfloor}
+
+\begin{document}
+
+\title{Integer Set Library: Manual\\
+\small Version: \input{version} }
+\author{Sven Verdoolaege}
+
+\maketitle
+\tableofcontents
+
+\chapter{User Manual}
+
+\input{user}
+
+\chapter{Implementation Details}
+
+\input{implementation}
+
+\chapter{Further Reading}
+
+\input{reading}
+
+\printbibliography
+
+\end{document}
diff --git a/final/lib/External/isl/doc/mypod2latex b/final/lib/External/isl/doc/mypod2latex
new file mode 100755
index 0000000..b11c059
--- /dev/null
+++ b/final/lib/External/isl/doc/mypod2latex
@@ -0,0 +1,14 @@
+#!/usr/bin/perl
+
+use strict;
+use Pod::LaTeX;
+
+my ($in, $out) = @ARGV;
+
+my $parser = new Pod::LaTeX(
+		AddPreamble => 0,
+		AddPostamble => 0,
+		LevelNoNum => 5,
+	     );
+
+$parser->parse_from_file($in, $out);
diff --git a/final/lib/External/isl/doc/reading.tex b/final/lib/External/isl/doc/reading.tex
new file mode 100644
index 0000000..6498000
--- /dev/null
+++ b/final/lib/External/isl/doc/reading.tex
@@ -0,0 +1,46 @@
+\textcite{Verdoolaege2016tutorial} describes the concepts behind
+\isl in some detail, mainly focusing on Presburger formulas,
+but also including some information on polyhedral compilation,
+especially on dependence analysis.
+Individual aspects of \isl are described in the following publications.
+\begin{itemize}
+\item
+\textcite{Verdoolaege2009equivalence} introduce \isl as a library
+for manipulating sets of integers defined by linear inequalities and
+integer divisions that is used in their equivalence checker.
+
+\item
+\textcite{Verdoolaege2010isl} provides a more detailed description
+of \isl at the time and still stands as the official reference for
+\isl.  However, many features were only added later on and one or
+more of the publications below may be more appropriate as
+a reference to these features.
+
+\item
+\textcite[Section 5.1]{Verdoolaege2010networks} provides some
+details on the dataflow analysis step, but also see
+\textcite[Chapter 6]{Verdoolaege2016tutorial} and
+\textcite{Verdoolaege2016reordering} for a more recent treatment.
+
+\item The concepts of structured and named spaces and the manipulation
+of sets containing elements in different spaces were introduced
+by \textcite{Verdoolaege2011iscc}.
+
+\item The transitive closure operation is described
+by \textcite{Verdoolaege2011closure}.
+
+\item The scheduler is briefly described by
+\textcite[Section 6.2]{Verdoolaege2013PPCG} and
+\textcite[Section 2.4]{Verdoolaege2016reordering}.
+
+\item Schedule trees started out as ``trees of bands''
+\parencite[Section 6.2]{Verdoolaege2013PPCG}, were formally
+introduced by \textcite{Verdoolaege2014impact}, and were
+slightly refined by \textcite{Grosser2015AST}.
+
+\item The coalescing operation is described by
+\textcite{Verdoolaege2015impact}.
+
+\item The AST generator is described by \textcite{Grosser2015AST}.
+
+\end{itemize}
diff --git a/final/lib/External/isl/doc/user.pod b/final/lib/External/isl/doc/user.pod
new file mode 100644
index 0000000..1bb0da4
--- /dev/null
+++ b/final/lib/External/isl/doc/user.pod
@@ -0,0 +1,10854 @@
+=head1 Introduction
+
+C<isl> is a thread-safe C library for manipulating
+sets and relations of integer points bounded by affine constraints.
+The descriptions of the sets and relations may involve
+both parameters and existentially quantified variables.
+All computations are performed in exact integer arithmetic
+using C<GMP> or C<imath>.
+The C<isl> library offers functionality that is similar
+to that offered by the C<Omega> and C<Omega+> libraries,
+but the underlying algorithms are in most cases completely different.
+
+The library is by no means complete and some fairly basic
+functionality is still missing.
+Still, even in its current form, the library has been successfully
+used as a backend polyhedral library for the polyhedral
+scanner C<CLooG> and as part of an equivalence checker of
+static affine programs.
+For bug reports, feature requests and questions,
+visit the discussion group at
+L<http://groups.google.com/group/isl-development>.
+
+=head2 Backward Incompatible Changes
+
+=head3 Changes since isl-0.02
+
+=over
+
+=item * The old printing functions have been deprecated
+and replaced by C<isl_printer> functions, see L<Input and Output>.
+
+=item * Most functions related to dependence analysis have acquired
+an extra C<must> argument.  To obtain the old behavior, this argument
+should be given the value 1.  See L<Dependence Analysis>.
+
+=back
+
+=head3 Changes since isl-0.03
+
+=over
+
+=item * The function C<isl_pw_qpolynomial_fold_add> has been
+renamed to C<isl_pw_qpolynomial_fold_fold>.
+Similarly, C<isl_union_pw_qpolynomial_fold_add> has been
+renamed to C<isl_union_pw_qpolynomial_fold_fold>.
+
+=back
+
+=head3 Changes since isl-0.04
+
+=over
+
+=item * All header files have been renamed from C<isl_header.h>
+to C<isl/header.h>.
+
+=back
+
+=head3 Changes since isl-0.05
+
+=over
+
+=item * The functions C<isl_printer_print_basic_set> and
+C<isl_printer_print_basic_map> no longer print a newline.
+
+=item * The functions C<isl_flow_get_no_source>
+and C<isl_union_map_compute_flow> now return
+the accesses for which no source could be found instead of
+the iterations where those accesses occur.
+
+=item * The functions C<isl_basic_map_identity> and
+C<isl_map_identity> now take a B<map> space as input.  An old call
+C<isl_map_identity(space)> can be rewritten to
+C<isl_map_identity(isl_space_map_from_set(space))>.
+
+=item * The function C<isl_map_power> no longer takes
+a parameter position as input.  Instead, the exponent
+is now expressed as the domain of the resulting relation.
+
+=back
+
+=head3 Changes since isl-0.06
+
+=over
+
+=item * The format of C<isl_printer_print_qpolynomial>'s
+C<ISL_FORMAT_ISL> output has changed.
+Use C<ISL_FORMAT_C> to obtain the old output.
+
+=item * The C<*_fast_*> functions have been renamed to C<*_plain_*>.
+Some of the old names have been kept for backward compatibility,
+but they will be removed in the future.
+
+=back
+
+=head3 Changes since isl-0.07
+
+=over
+
+=item * The function C<isl_pw_aff_max> has been renamed to
+C<isl_pw_aff_union_max>.
+Similarly, the function C<isl_pw_aff_add> has been renamed to
+C<isl_pw_aff_union_add>.
+
+=item * The C<isl_dim> type has been renamed to C<isl_space>
+along with the associated functions.
+Some of the old names have been kept for backward compatibility,
+but they will be removed in the future.
+
+=item * Spaces of maps, sets and parameter domains are now
+treated differently.  The distinction between map spaces and set spaces
+has always been made on a conceptual level, but proper use of such spaces
+was never checked.  Furthermore, up until isl-0.07 there was no way
+of explicitly creating a parameter space.  These can now be created
+directly using C<isl_space_params_alloc> or from other spaces using
+C<isl_space_params>.
+
+=item * The space in which C<isl_aff>, C<isl_pw_aff>, C<isl_qpolynomial>,
+C<isl_pw_qpolynomial>, C<isl_qpolynomial_fold> and C<isl_pw_qpolynomial_fold>
+objects live is now a map space
+instead of a set space.  This means, for example, that the dimensions
+of the domain of an C<isl_aff> are now considered to be of type
+C<isl_dim_in> instead of C<isl_dim_set>.  Extra functions have been
+added to obtain the domain space.  Some of the constructors still
+take a domain space and have therefore been renamed.
+
+=item * The functions C<isl_equality_alloc> and C<isl_inequality_alloc>
+now take an C<isl_local_space> instead of an C<isl_space>.
+An C<isl_local_space> can be created from an C<isl_space>
+using C<isl_local_space_from_space>.
+
+=item * The C<isl_div> type has been removed.  Functions that used
+to return an C<isl_div> now return an C<isl_aff>.
+Note that the space of an C<isl_aff> is that of relation.
+When replacing a call to C<isl_div_get_coefficient> by a call to
+C<isl_aff_get_coefficient> any C<isl_dim_set> argument needs
+to be replaced by C<isl_dim_in>.
+A call to C<isl_aff_from_div> can be replaced by a call
+to C<isl_aff_floor>.
+A call to C<isl_qpolynomial_div(div)> call be replaced by
+the nested call
+
+	isl_qpolynomial_from_aff(isl_aff_floor(div))
+
+The function C<isl_constraint_div> has also been renamed
+to C<isl_constraint_get_div>.
+
+=item * The C<nparam> argument has been removed from
+C<isl_map_read_from_str> and similar functions.
+When reading input in the original PolyLib format,
+the result will have no parameters.
+If parameters are expected, the caller may want to perform
+dimension manipulation on the result.
+
+=back
+
+=head3 Changes since isl-0.09
+
+=over
+
+=item * The C<schedule_split_parallel> option has been replaced
+by the C<schedule_split_scaled> option.
+
+=item * The first argument of C<isl_pw_aff_cond> is now
+an C<isl_pw_aff> instead of an C<isl_set>.
+A call C<isl_pw_aff_cond(a, b, c)> can be replaced by
+
+	isl_pw_aff_cond(isl_set_indicator_function(a), b, c)
+
+=back
+
+=head3 Changes since isl-0.10
+
+=over
+
+=item * The functions C<isl_set_dim_has_lower_bound> and
+C<isl_set_dim_has_upper_bound> have been renamed to
+C<isl_set_dim_has_any_lower_bound> and
+C<isl_set_dim_has_any_upper_bound>.
+The new C<isl_set_dim_has_lower_bound> and
+C<isl_set_dim_has_upper_bound> have slightly different meanings.
+
+=back
+
+=head3 Changes since isl-0.12
+
+=over
+
+=item * C<isl_int> has been replaced by C<isl_val>.
+Some of the old functions are still available in C<isl/deprecated/*.h>
+but they will be removed in the future.
+
+=item * The functions C<isl_pw_qpolynomial_eval>,
+C<isl_union_pw_qpolynomial_eval>, C<isl_pw_qpolynomial_fold_eval>
+and C<isl_union_pw_qpolynomial_fold_eval> have been changed to return
+an C<isl_val> instead of an C<isl_qpolynomial>.
+
+=item * The function C<isl_band_member_is_zero_distance>
+has been removed.  Essentially the same functionality is available
+through C<isl_band_member_is_coincident>, except that it requires
+setting up coincidence constraints.
+The option C<schedule_outer_zero_distance> has accordingly been
+replaced by the option C<schedule_outer_coincidence>.
+
+=item * The function C<isl_vertex_get_expr> has been changed
+to return an C<isl_multi_aff> instead of a rational C<isl_basic_set>.
+The function C<isl_vertex_get_domain> has been changed to return
+a regular basic set, rather than a rational basic set.
+
+=back
+
+=head3 Changes since isl-0.14
+
+=over
+
+=item * The function C<isl_union_pw_multi_aff_add> now consistently
+computes the sum on the shared definition domain.
+The function C<isl_union_pw_multi_aff_union_add> has been added
+to compute the sum on the union of definition domains.
+The original behavior of C<isl_union_pw_multi_aff_add> was
+confused and is no longer available.
+
+=item * Band forests have been replaced by schedule trees.
+
+=item * The function C<isl_union_map_compute_flow> has been
+replaced by the function C<isl_union_access_info_compute_flow>.
+Note that the may dependence relation returned by
+C<isl_union_flow_get_may_dependence> is the union of
+the two dependence relations returned by
+C<isl_union_map_compute_flow>.  Similarly for the no source relations.
+The function C<isl_union_map_compute_flow> is still available
+for backward compatibility, but it will be removed in the future.
+
+=item * The function C<isl_basic_set_drop_constraint> has been
+deprecated.
+
+=item * The function C<isl_ast_build_ast_from_schedule> has been
+renamed to C<isl_ast_build_node_from_schedule_map>.
+The original name is still available
+for backward compatibility, but it will be removed in the future.
+
+=item * The C<separation_class> AST generation option has been
+deprecated.
+
+=item * The functions C<isl_equality_alloc> and C<isl_inequality_alloc>
+have been renamed to C<isl_constraint_alloc_equality> and
+C<isl_constraint_alloc_inequality>.  The original names have been
+kept for backward compatibility, but they will be removed in the future.
+
+=item * The C<schedule_fuse> option has been replaced
+by the C<schedule_serialize_sccs> option.  The effect
+of setting the C<schedule_fuse> option to C<ISL_SCHEDULE_FUSE_MIN>
+is now obtained by turning on the C<schedule_serialize_sccs> option.
+
+=back
+
+=head3 Changes since isl-0.17
+
+=over
+
+=item * The function C<isl_printer_print_ast_expr> no longer prints
+in C format by default.  To print in C format, the output format
+of the printer needs to have been explicitly set to C<ISL_FORMAT_C>.
+As a result, the function C<isl_ast_expr_to_str> no longer prints
+the expression in C format.  Use C<isl_ast_expr_to_C_str> instead.
+
+=item * The functions C<isl_set_align_divs> and C<isl_map_align_divs>
+have been deprecated.  The function C<isl_set_lift> has an effect
+that is similar to C<isl_set_align_divs> and could in some cases
+be used as an alternative.
+
+=back
+
+=head1 License
+
+C<isl> is released under the MIT license.
+
+=over
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+=back
+
+Note that by default C<isl> requires C<GMP>, which is released
+under the GNU Lesser General Public License (LGPL).  This means
+that code linked against C<isl> is also linked against LGPL code.
+
+When configuring with C<--with-int=imath> or C<--with-int=imath-32>, C<isl>
+will link against C<imath>, a library for exact integer arithmetic released
+under the MIT license.
+
+=head1 Installation
+
+The source of C<isl> can be obtained either as a tarball
+or from the git repository.  Both are available from
+L<http://isl.gforge.inria.fr/>.
+The installation process depends on how you obtained
+the source.
+
+=head2 Installation from the git repository
+
+=over
+
+=item 1 Clone or update the repository
+
+The first time the source is obtained, you need to clone
+the repository.
+
+	git clone git://repo.or.cz/isl.git
+
+To obtain updates, you need to pull in the latest changes
+
+	git pull
+
+=item 2 Optionally get C<imath> submodule
+
+To build C<isl> with C<imath>, you need to obtain the C<imath>
+submodule by running in the git source tree of C<isl>
+
+       git submodule init
+       git submodule update
+
+This will fetch the required version of C<imath> in a subdirectory of C<isl>.
+
+=item 2 Generate C<configure>
+
+	./autogen.sh
+
+=back
+
+After performing the above steps, continue
+with the L<Common installation instructions>.
+
+=head2 Common installation instructions
+
+=over
+
+=item 1 Obtain C<GMP>
+
+By default, building C<isl> requires C<GMP>, including its headers files.
+Your distribution may not provide these header files by default
+and you may need to install a package called C<gmp-devel> or something
+similar.  Alternatively, C<GMP> can be built from
+source, available from L<http://gmplib.org/>.
+C<GMP> is not needed if you build C<isl> with C<imath>.
+
+=item 2 Configure
+
+C<isl> uses the standard C<autoconf> C<configure> script.
+To run it, just type
+
+	./configure
+
+optionally followed by some configure options.
+A complete list of options can be obtained by running
+
+	./configure --help
+
+Below we discuss some of the more common options.
+
+=over
+
+=item C<--prefix>
+
+Installation prefix for C<isl>
+
+=item C<--with-int=[gmp|imath|imath-32]>
+
+Select the integer library to be used by C<isl>, the default is C<gmp>.
+With C<imath-32>, C<isl> will use 32 bit integers, but fall back to C<imath>
+for values out of the 32 bit range. In most applications, C<isl> will run
+fastest with the C<imath-32> option, followed by C<gmp> and C<imath>, the
+slowest.
+
+=item C<--with-gmp-prefix>
+
+Installation prefix for C<GMP> (architecture-independent files).
+
+=item C<--with-gmp-exec-prefix>
+
+Installation prefix for C<GMP> (architecture-dependent files).
+
+=back
+
+=item 3 Compile
+
+	make
+
+=item 4 Install (optional)
+
+	make install
+
+=back
+
+=head1 Integer Set Library
+
+=head2 Memory Management
+
+Since a high-level operation on isl objects usually involves
+several substeps and since the user is usually not interested in
+the intermediate results, most functions that return a new object
+will also release all the objects passed as arguments.
+If the user still wants to use one or more of these arguments
+after the function call, she should pass along a copy of the
+object rather than the object itself.
+The user is then responsible for making sure that the original
+object gets used somewhere else or is explicitly freed.
+
+The arguments and return values of all documented functions are
+annotated to make clear which arguments are released and which
+arguments are preserved.  In particular, the following annotations
+are used
+
+=over
+
+=item C<__isl_give>
+
+C<__isl_give> means that a new object is returned.
+The user should make sure that the returned pointer is
+used exactly once as a value for an C<__isl_take> argument.
+In between, it can be used as a value for as many
+C<__isl_keep> arguments as the user likes.
+There is one exception, and that is the case where the
+pointer returned is C<NULL>.  Is this case, the user
+is free to use it as an C<__isl_take> argument or not.
+When applied to a C<char *>, the returned pointer needs to be
+freed using C<free>.
+
+=item C<__isl_null>
+
+C<__isl_null> means that a C<NULL> value is returned.
+
+=item C<__isl_take>
+
+C<__isl_take> means that the object the argument points to
+is taken over by the function and may no longer be used
+by the user as an argument to any other function.
+The pointer value must be one returned by a function
+returning an C<__isl_give> pointer.
+If the user passes in a C<NULL> value, then this will
+be treated as an error in the sense that the function will
+not perform its usual operation.  However, it will still
+make sure that all the other C<__isl_take> arguments
+are released.
+
+=item C<__isl_keep>
+
+C<__isl_keep> means that the function will only use the object
+temporarily.  After the function has finished, the user
+can still use it as an argument to other functions.
+A C<NULL> value will be treated in the same way as
+a C<NULL> value for an C<__isl_take> argument.
+This annotation may also be used on return values of
+type C<const char *>, in which case the returned pointer should
+not be freed by the user and is only valid until the object
+from which it was derived is updated or freed.
+
+=back
+
+=head2 Initialization
+
+All manipulations of integer sets and relations occur within
+the context of an C<isl_ctx>.
+A given C<isl_ctx> can only be used within a single thread.
+All arguments of a function are required to have been allocated
+within the same context.
+There are currently no functions available for moving an object
+from one C<isl_ctx> to another C<isl_ctx>.  This means that
+there is currently no way of safely moving an object from one
+thread to another, unless the whole C<isl_ctx> is moved.
+
+An C<isl_ctx> can be allocated using C<isl_ctx_alloc> and
+freed using C<isl_ctx_free>.
+All objects allocated within an C<isl_ctx> should be freed
+before the C<isl_ctx> itself is freed.
+
+	isl_ctx *isl_ctx_alloc();
+	void isl_ctx_free(isl_ctx *ctx);
+
+The user can impose a bound on the number of low-level I<operations>
+that can be performed by an C<isl_ctx>.  This bound can be set and
+retrieved using the following functions.  A bound of zero means that
+no bound is imposed.  The number of operations performed can be
+reset using C<isl_ctx_reset_operations>.  Note that the number
+of low-level operations needed to perform a high-level computation
+may differ significantly across different versions
+of C<isl>, but it should be the same across different platforms
+for the same version of C<isl>.
+
+Warning: This feature is experimental.  C<isl> has good support to abort and
+bail out during the computation, but this feature may exercise error code paths
+that are normally not used that much. Consequently, it is not unlikely that
+hidden bugs will be exposed.
+
+	void isl_ctx_set_max_operations(isl_ctx *ctx,
+		unsigned long max_operations);
+	unsigned long isl_ctx_get_max_operations(isl_ctx *ctx);
+	void isl_ctx_reset_operations(isl_ctx *ctx);
+
+In order to be able to create an object in the same context
+as another object, most object types (described later in
+this document) provide a function to obtain the context
+in which the object was created.
+
+	#include <isl/val.h>
+	isl_ctx *isl_val_get_ctx(__isl_keep isl_val *val);
+	isl_ctx *isl_multi_val_get_ctx(
+		__isl_keep isl_multi_val *mv);
+
+	#include <isl/id.h>
+	isl_ctx *isl_id_get_ctx(__isl_keep isl_id *id);
+
+	#include <isl/local_space.h>
+	isl_ctx *isl_local_space_get_ctx(
+		__isl_keep isl_local_space *ls);
+
+	#include <isl/set.h>
+	isl_ctx *isl_set_list_get_ctx(
+		__isl_keep isl_set_list *list);
+
+	#include <isl/aff.h>
+	isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff);
+	isl_ctx *isl_multi_aff_get_ctx(
+		__isl_keep isl_multi_aff *maff);
+	isl_ctx *isl_pw_aff_get_ctx(__isl_keep isl_pw_aff *pa);
+	isl_ctx *isl_pw_multi_aff_get_ctx(
+		__isl_keep isl_pw_multi_aff *pma);
+	isl_ctx *isl_multi_pw_aff_get_ctx(
+		__isl_keep isl_multi_pw_aff *mpa);
+	isl_ctx *isl_union_pw_aff_get_ctx(
+		__isl_keep isl_union_pw_aff *upa);
+	isl_ctx *isl_union_pw_multi_aff_get_ctx(
+		__isl_keep isl_union_pw_multi_aff *upma);
+	isl_ctx *isl_multi_union_pw_aff_get_ctx(
+		__isl_keep isl_multi_union_pw_aff *mupa);
+
+	#include <isl/id_to_ast_expr.h>
+	isl_ctx *isl_id_to_ast_expr_get_ctx(
+		__isl_keep isl_id_to_ast_expr *id2expr);
+
+	#include <isl/point.h>
+	isl_ctx *isl_point_get_ctx(__isl_keep isl_point *pnt);
+
+	#include <isl/vec.h>
+	isl_ctx *isl_vec_get_ctx(__isl_keep isl_vec *vec);
+
+	#include <isl/mat.h>
+	isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat);
+
+	#include <isl/vertices.h>
+	isl_ctx *isl_vertices_get_ctx(
+		__isl_keep isl_vertices *vertices);
+	isl_ctx *isl_vertex_get_ctx(__isl_keep isl_vertex *vertex);
+	isl_ctx *isl_cell_get_ctx(__isl_keep isl_cell *cell);
+
+	#include <isl/flow.h>
+	isl_ctx *isl_restriction_get_ctx(
+		__isl_keep isl_restriction *restr);
+	isl_ctx *isl_union_access_info_get_ctx(
+		__isl_keep isl_union_access_info *access);
+	isl_ctx *isl_union_flow_get_ctx(
+		__isl_keep isl_union_flow *flow);
+
+	#include <isl/schedule.h>
+	isl_ctx *isl_schedule_get_ctx(
+		__isl_keep isl_schedule *sched);
+	isl_ctx *isl_schedule_constraints_get_ctx(
+		__isl_keep isl_schedule_constraints *sc);
+
+	#include <isl/schedule_node.h>
+	isl_ctx *isl_schedule_node_get_ctx(
+		__isl_keep isl_schedule_node *node);
+
+	#include <isl/band.h>
+	isl_ctx *isl_band_get_ctx(__isl_keep isl_band *band);
+
+	#include <isl/ast_build.h>
+	isl_ctx *isl_ast_build_get_ctx(
+		__isl_keep isl_ast_build *build);
+
+	#include <isl/ast.h>
+	isl_ctx *isl_ast_expr_get_ctx(
+		__isl_keep isl_ast_expr *expr);
+	isl_ctx *isl_ast_node_get_ctx(
+		__isl_keep isl_ast_node *node);
+
+=head2 Return Types
+
+C<isl> uses two special return types for functions that either return
+a boolean or that in principle do not return anything.
+In particular, the C<isl_bool> type has three possible values:
+C<isl_bool_true> (a positive integer value), indicating I<true> or I<yes>;
+C<isl_bool_false> (the integer value zero), indicating I<false> or I<no>; and
+C<isl_bool_error> (a negative integer value), indicating that something
+went wrong.  The following function can be used to negate an C<isl_bool>,
+where the negation of C<isl_bool_error> is C<isl_bool_error> again.
+
+	#include <isl/val.h>
+	isl_bool isl_bool_not(isl_bool b);
+
+The C<isl_stat> type has two possible values:
+C<isl_stat_ok> (the integer value zero), indicating a successful
+operation; and
+C<isl_stat_error> (a negative integer value), indicating that something
+went wrong.
+See L</"Error Handling"> for more information on
+C<isl_bool_error> and C<isl_stat_error>.
+
+=head2 Values
+
+An C<isl_val> represents an integer value, a rational value
+or one of three special values, infinity, negative infinity and NaN.
+Some predefined values can be created using the following functions.
+
+	#include <isl/val.h>
+	__isl_give isl_val *isl_val_zero(isl_ctx *ctx);
+	__isl_give isl_val *isl_val_one(isl_ctx *ctx);
+	__isl_give isl_val *isl_val_negone(isl_ctx *ctx);
+	__isl_give isl_val *isl_val_nan(isl_ctx *ctx);
+	__isl_give isl_val *isl_val_infty(isl_ctx *ctx);
+	__isl_give isl_val *isl_val_neginfty(isl_ctx *ctx);
+
+Specific integer values can be created using the following functions.
+
+	#include <isl/val.h>
+	__isl_give isl_val *isl_val_int_from_si(isl_ctx *ctx,
+		long i);
+	__isl_give isl_val *isl_val_int_from_ui(isl_ctx *ctx,
+		unsigned long u);
+	__isl_give isl_val *isl_val_int_from_chunks(isl_ctx *ctx,
+		size_t n, size_t size, const void *chunks);
+
+The function C<isl_val_int_from_chunks> constructs an C<isl_val>
+from the C<n> I<digits>, each consisting of C<size> bytes, stored at C<chunks>.
+The least significant digit is assumed to be stored first.
+
+Value objects can be copied and freed using the following functions.
+
+	#include <isl/val.h>
+	__isl_give isl_val *isl_val_copy(__isl_keep isl_val *v);
+	__isl_null isl_val *isl_val_free(__isl_take isl_val *v);
+
+They can be inspected using the following functions.
+
+	#include <isl/val.h>
+	long isl_val_get_num_si(__isl_keep isl_val *v);
+	long isl_val_get_den_si(__isl_keep isl_val *v);
+	__isl_give isl_val *isl_val_get_den_val(
+		__isl_keep isl_val *v);
+	double isl_val_get_d(__isl_keep isl_val *v);
+	size_t isl_val_n_abs_num_chunks(__isl_keep isl_val *v,
+		size_t size);
+	int isl_val_get_abs_num_chunks(__isl_keep isl_val *v,
+		size_t size, void *chunks);
+
+C<isl_val_n_abs_num_chunks> returns the number of I<digits>
+of C<size> bytes needed to store the absolute value of the
+numerator of C<v>.
+C<isl_val_get_abs_num_chunks> stores these digits at C<chunks>,
+which is assumed to have been preallocated by the caller.
+The least significant digit is stored first.
+Note that C<isl_val_get_num_si>, C<isl_val_get_den_si>,
+C<isl_val_get_d>, C<isl_val_n_abs_num_chunks>
+and C<isl_val_get_abs_num_chunks> can only be applied to rational values.
+
+An C<isl_val> can be modified using the following function.
+
+	#include <isl/val.h>
+	__isl_give isl_val *isl_val_set_si(__isl_take isl_val *v,
+		long i);
+
+The following unary properties are defined on C<isl_val>s.
+
+	#include <isl/val.h>
+	int isl_val_sgn(__isl_keep isl_val *v);
+	isl_bool isl_val_is_zero(__isl_keep isl_val *v);
+	isl_bool isl_val_is_one(__isl_keep isl_val *v);
+	isl_bool isl_val_is_negone(__isl_keep isl_val *v);
+	isl_bool isl_val_is_nonneg(__isl_keep isl_val *v);
+	isl_bool isl_val_is_nonpos(__isl_keep isl_val *v);
+	isl_bool isl_val_is_pos(__isl_keep isl_val *v);
+	isl_bool isl_val_is_neg(__isl_keep isl_val *v);
+	isl_bool isl_val_is_int(__isl_keep isl_val *v);
+	isl_bool isl_val_is_rat(__isl_keep isl_val *v);
+	isl_bool isl_val_is_nan(__isl_keep isl_val *v);
+	isl_bool isl_val_is_infty(__isl_keep isl_val *v);
+	isl_bool isl_val_is_neginfty(__isl_keep isl_val *v);
+
+Note that the sign of NaN is undefined.
+
+The following binary properties are defined on pairs of C<isl_val>s.
+
+	#include <isl/val.h>
+	isl_bool isl_val_lt(__isl_keep isl_val *v1,
+		__isl_keep isl_val *v2);
+	isl_bool isl_val_le(__isl_keep isl_val *v1,
+		__isl_keep isl_val *v2);
+	isl_bool isl_val_gt(__isl_keep isl_val *v1,
+		__isl_keep isl_val *v2);
+	isl_bool isl_val_ge(__isl_keep isl_val *v1,
+		__isl_keep isl_val *v2);
+	isl_bool isl_val_eq(__isl_keep isl_val *v1,
+		__isl_keep isl_val *v2);
+	isl_bool isl_val_ne(__isl_keep isl_val *v1,
+		__isl_keep isl_val *v2);
+	isl_bool isl_val_abs_eq(__isl_keep isl_val *v1,
+		__isl_keep isl_val *v2);
+
+Comparisons to NaN always return false.
+That is, a NaN is not considered to hold any relative position
+with respect to any value.  In particular, a NaN
+is neither considered to be equal to nor to be different from
+any value (including another NaN).
+The function C<isl_val_abs_eq> checks whether its two arguments
+are equal in absolute value.
+
+For integer C<isl_val>s we additionally have the following binary property.
+
+	#include <isl/val.h>
+	isl_bool isl_val_is_divisible_by(__isl_keep isl_val *v1,
+		__isl_keep isl_val *v2);
+
+An C<isl_val> can also be compared to an integer using the following
+function.  The result is undefined for NaN.
+
+	#include <isl/val.h>
+	int isl_val_cmp_si(__isl_keep isl_val *v, long i);
+
+The following unary operations are available on C<isl_val>s.
+
+	#include <isl/val.h>
+	__isl_give isl_val *isl_val_abs(__isl_take isl_val *v);
+	__isl_give isl_val *isl_val_neg(__isl_take isl_val *v);
+	__isl_give isl_val *isl_val_floor(__isl_take isl_val *v);
+	__isl_give isl_val *isl_val_ceil(__isl_take isl_val *v);
+	__isl_give isl_val *isl_val_trunc(__isl_take isl_val *v);
+	__isl_give isl_val *isl_val_inv(__isl_take isl_val *v);
+	__isl_give isl_val *isl_val_2exp(__isl_take isl_val *v);
+
+The following binary operations are available on C<isl_val>s.
+
+	#include <isl/val.h>
+	__isl_give isl_val *isl_val_min(__isl_take isl_val *v1,
+		__isl_take isl_val *v2);
+	__isl_give isl_val *isl_val_max(__isl_take isl_val *v1,
+		__isl_take isl_val *v2);
+	__isl_give isl_val *isl_val_add(__isl_take isl_val *v1,
+		__isl_take isl_val *v2);
+	__isl_give isl_val *isl_val_add_ui(__isl_take isl_val *v1,
+		unsigned long v2);
+	__isl_give isl_val *isl_val_sub(__isl_take isl_val *v1,
+		__isl_take isl_val *v2);
+	__isl_give isl_val *isl_val_sub_ui(__isl_take isl_val *v1,
+		unsigned long v2);
+	__isl_give isl_val *isl_val_mul(__isl_take isl_val *v1,
+		__isl_take isl_val *v2);
+	__isl_give isl_val *isl_val_mul_ui(__isl_take isl_val *v1,
+		unsigned long v2);
+	__isl_give isl_val *isl_val_div(__isl_take isl_val *v1,
+		__isl_take isl_val *v2);
+	__isl_give isl_val *isl_val_div_ui(__isl_take isl_val *v1,
+		unsigned long v2);
+
+On integer values, we additionally have the following operations.
+
+	#include <isl/val.h>
+	__isl_give isl_val *isl_val_2exp(__isl_take isl_val *v);
+	__isl_give isl_val *isl_val_mod(__isl_take isl_val *v1,
+		__isl_take isl_val *v2);
+	__isl_give isl_val *isl_val_gcd(__isl_take isl_val *v1,
+		__isl_take isl_val *v2);
+	__isl_give isl_val *isl_val_gcdext(__isl_take isl_val *v1,
+		__isl_take isl_val *v2, __isl_give isl_val **x,
+		__isl_give isl_val **y);
+
+The function C<isl_val_gcdext> returns the greatest common divisor g
+of C<v1> and C<v2> as well as two integers C<*x> and C<*y> such
+that C<*x> * C<v1> + C<*y> * C<v2> = g.
+
+=head3 GMP specific functions
+
+These functions are only available if C<isl> has been compiled with C<GMP>
+support.
+
+Specific integer and rational values can be created from C<GMP> values using
+the following functions.
+
+	#include <isl/val_gmp.h>
+	__isl_give isl_val *isl_val_int_from_gmp(isl_ctx *ctx,
+		mpz_t z);
+	__isl_give isl_val *isl_val_from_gmp(isl_ctx *ctx,
+		const mpz_t n, const mpz_t d);
+
+The numerator and denominator of a rational value can be extracted as
+C<GMP> values using the following functions.
+
+	#include <isl/val_gmp.h>
+	int isl_val_get_num_gmp(__isl_keep isl_val *v, mpz_t z);
+	int isl_val_get_den_gmp(__isl_keep isl_val *v, mpz_t z);
+
+=head2 Sets and Relations
+
+C<isl> uses six types of objects for representing sets and relations,
+C<isl_basic_set>, C<isl_basic_map>, C<isl_set>, C<isl_map>,
+C<isl_union_set> and C<isl_union_map>.
+C<isl_basic_set> and C<isl_basic_map> represent sets and relations that
+can be described as a conjunction of affine constraints, while
+C<isl_set> and C<isl_map> represent unions of
+C<isl_basic_set>s and C<isl_basic_map>s, respectively.
+However, all C<isl_basic_set>s or C<isl_basic_map>s in the union need
+to live in the same space.  C<isl_union_set>s and C<isl_union_map>s
+represent unions of C<isl_set>s or C<isl_map>s in I<different> spaces,
+where spaces are considered different if they have a different number
+of dimensions and/or different names (see L<"Spaces">).
+The difference between sets and relations (maps) is that sets have
+one set of variables, while relations have two sets of variables,
+input variables and output variables.
+
+=head2 Error Handling
+
+C<isl> supports different ways to react in case a runtime error is triggered.
+Runtime errors arise, e.g., if a function such as C<isl_map_intersect> is called
+with two maps that have incompatible spaces. There are three possible ways
+to react on error: to warn, to continue or to abort.
+
+The default behavior is to warn. In this mode, C<isl> prints a warning, stores
+the last error in the corresponding C<isl_ctx> and the function in which the
+error was triggered returns a value indicating that some error has
+occurred.  In case of functions returning a pointer, this value is
+C<NULL>.  In case of functions returning an C<isl_bool> or an
+C<isl_stat>, this valus is C<isl_bool_error> or C<isl_stat_error>.
+An error does not corrupt internal state,
+such that isl can continue to be used. C<isl> also provides functions to
+read the last error and to reset the memory that stores the last error. The
+last error is only stored for information purposes. Its presence does not
+change the behavior of C<isl>. Hence, resetting an error is not required to
+continue to use isl, but only to observe new errors.
+
+	#include <isl/ctx.h>
+	enum isl_error isl_ctx_last_error(isl_ctx *ctx);
+	void isl_ctx_reset_error(isl_ctx *ctx);
+
+Another option is to continue on error. This is similar to warn on error mode,
+except that C<isl> does not print any warning. This allows a program to
+implement its own error reporting.
+
+The last option is to directly abort the execution of the program from within
+the isl library. This makes it obviously impossible to recover from an error,
+but it allows to directly spot the error location. By aborting on error,
+debuggers break at the location the error occurred and can provide a stack
+trace. Other tools that automatically provide stack traces on abort or that do
+not want to continue execution after an error was triggered may also prefer to
+abort on error.
+
+The on error behavior of isl can be specified by calling
+C<isl_options_set_on_error> or by setting the command line option
+C<--isl-on-error>. Valid arguments for the function call are
+C<ISL_ON_ERROR_WARN>, C<ISL_ON_ERROR_CONTINUE> and C<ISL_ON_ERROR_ABORT>. The
+choices for the command line option are C<warn>, C<continue> and C<abort>.
+It is also possible to query the current error mode.
+
+	#include <isl/options.h>
+	isl_stat isl_options_set_on_error(isl_ctx *ctx, int val);
+	int isl_options_get_on_error(isl_ctx *ctx);
+
+=head2 Identifiers
+
+Identifiers are used to identify both individual dimensions
+and tuples of dimensions.  They consist of an optional name and an optional
+user pointer.  The name and the user pointer cannot both be C<NULL>, however.
+Identifiers with the same name but different pointer values
+are considered to be distinct.
+Similarly, identifiers with different names but the same pointer value
+are also considered to be distinct.
+Equal identifiers are represented using the same object.
+Pairs of identifiers can therefore be tested for equality using the
+C<==> operator.
+Identifiers can be constructed, copied, freed, inspected and printed
+using the following functions.
+
+	#include <isl/id.h>
+	__isl_give isl_id *isl_id_alloc(isl_ctx *ctx,
+		__isl_keep const char *name, void *user);
+	__isl_give isl_id *isl_id_set_free_user(
+		__isl_take isl_id *id,
+		void (*free_user)(void *user));
+	__isl_give isl_id *isl_id_copy(isl_id *id);
+	__isl_null isl_id *isl_id_free(__isl_take isl_id *id);
+
+	void *isl_id_get_user(__isl_keep isl_id *id);
+	__isl_keep const char *isl_id_get_name(__isl_keep isl_id *id);
+
+	__isl_give isl_printer *isl_printer_print_id(
+		__isl_take isl_printer *p, __isl_keep isl_id *id);
+
+The callback set by C<isl_id_set_free_user> is called on the user
+pointer when the last reference to the C<isl_id> is freed.
+Note that C<isl_id_get_name> returns a pointer to some internal
+data structure, so the result can only be used while the
+corresponding C<isl_id> is alive.
+
+=head2 Spaces
+
+Whenever a new set, relation or similar object is created from scratch,
+the space in which it lives needs to be specified using an C<isl_space>.
+Each space involves zero or more parameters and zero, one or two
+tuples of set or input/output dimensions.  The parameters and dimensions
+are identified by an C<isl_dim_type> and a position.
+The type C<isl_dim_param> refers to parameters,
+the type C<isl_dim_set> refers to set dimensions (for spaces
+with a single tuple of dimensions) and the types C<isl_dim_in>
+and C<isl_dim_out> refer to input and output dimensions
+(for spaces with two tuples of dimensions).
+Local spaces (see L</"Local Spaces">) also contain dimensions
+of type C<isl_dim_div>.
+Note that parameters are only identified by their position within
+a given object.  Across different objects, parameters are (usually)
+identified by their names or identifiers.  Only unnamed parameters
+are identified by their positions across objects.  The use of unnamed
+parameters is discouraged.
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_alloc(isl_ctx *ctx,
+		unsigned nparam, unsigned n_in, unsigned n_out);
+	__isl_give isl_space *isl_space_params_alloc(isl_ctx *ctx,
+		unsigned nparam);
+	__isl_give isl_space *isl_space_set_alloc(isl_ctx *ctx,
+		unsigned nparam, unsigned dim);
+	__isl_give isl_space *isl_space_copy(__isl_keep isl_space *space);
+	__isl_null isl_space *isl_space_free(__isl_take isl_space *space);
+
+The space used for creating a parameter domain
+needs to be created using C<isl_space_params_alloc>.
+For other sets, the space
+needs to be created using C<isl_space_set_alloc>, while
+for a relation, the space
+needs to be created using C<isl_space_alloc>.
+
+To check whether a given space is that of a set or a map
+or whether it is a parameter space, use these functions:
+
+	#include <isl/space.h>
+	isl_bool isl_space_is_params(__isl_keep isl_space *space);
+	isl_bool isl_space_is_set(__isl_keep isl_space *space);
+	isl_bool isl_space_is_map(__isl_keep isl_space *space);
+
+Spaces can be compared using the following functions:
+
+	#include <isl/space.h>
+	isl_bool isl_space_is_equal(__isl_keep isl_space *space1,
+		__isl_keep isl_space *space2);
+	isl_bool isl_space_has_equal_params(
+		__isl_keep isl_space *space1,
+		__isl_keep isl_space *space2);
+	isl_bool isl_space_has_equal_tuples(
+		__isl_keep isl_space *space1,
+		__isl_keep isl_space *space2);
+	isl_bool isl_space_is_domain(__isl_keep isl_space *space1,
+		__isl_keep isl_space *space2);
+	isl_bool isl_space_is_range(__isl_keep isl_space *space1,
+		__isl_keep isl_space *space2);
+	isl_bool isl_space_tuple_is_equal(
+		__isl_keep isl_space *space1,
+		enum isl_dim_type type1,
+		__isl_keep isl_space *space2,
+		enum isl_dim_type type2);
+
+C<isl_space_is_domain> checks whether the first argument is equal
+to the domain of the second argument.  This requires in particular that
+the first argument is a set space and that the second argument
+is a map space.  C<isl_space_tuple_is_equal> checks whether the given
+tuples (C<isl_dim_in>, C<isl_dim_out> or C<isl_dim_set>) of the given
+spaces are the same.  That is, it checks if they have the same
+identifier (if any), the same dimension and the same internal structure
+(if any).
+The function
+C<isl_space_has_equal_params> checks whether two spaces
+have the same parameters in the same order.
+C<isl_space_has_equal_tuples> check whether two spaces have
+the same tuples.  In contrast to C<isl_space_is_equal> below,
+it does not check the
+parameters.  This is useful because many C<isl> functions align the
+parameters before they perform their operations, such that equivalence
+is not necessary.
+C<isl_space_is_equal> checks whether two spaces are identical,
+meaning that they have the same parameters and the same tuples.
+That is, it checks whether both C<isl_space_has_equal_params> and
+C<isl_space_has_equal_tuples> hold.
+
+It is often useful to create objects that live in the
+same space as some other object.  This can be accomplished
+by creating the new objects
+(see L</"Creating New Sets and Relations"> or
+L</"Functions">) based on the space
+of the original object.
+
+	#include <isl/set.h>
+	__isl_give isl_space *isl_basic_set_get_space(
+		__isl_keep isl_basic_set *bset);
+	__isl_give isl_space *isl_set_get_space(__isl_keep isl_set *set);
+
+	#include <isl/union_set.h>
+	__isl_give isl_space *isl_union_set_get_space(
+		__isl_keep isl_union_set *uset);
+
+	#include <isl/map.h>
+	__isl_give isl_space *isl_basic_map_get_space(
+		__isl_keep isl_basic_map *bmap);
+	__isl_give isl_space *isl_map_get_space(__isl_keep isl_map *map);
+
+	#include <isl/union_map.h>
+	__isl_give isl_space *isl_union_map_get_space(
+		__isl_keep isl_union_map *umap);
+
+	#include <isl/constraint.h>
+	__isl_give isl_space *isl_constraint_get_space(
+		__isl_keep isl_constraint *constraint);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_space *isl_qpolynomial_get_domain_space(
+		__isl_keep isl_qpolynomial *qp);
+	__isl_give isl_space *isl_qpolynomial_get_space(
+		__isl_keep isl_qpolynomial *qp);
+	__isl_give isl_space *
+	isl_qpolynomial_fold_get_domain_space(
+		__isl_keep isl_qpolynomial_fold *fold);
+	__isl_give isl_space *isl_qpolynomial_fold_get_space(
+		__isl_keep isl_qpolynomial_fold *fold);
+	__isl_give isl_space *isl_pw_qpolynomial_get_domain_space(
+		__isl_keep isl_pw_qpolynomial *pwqp);
+	__isl_give isl_space *isl_pw_qpolynomial_get_space(
+		__isl_keep isl_pw_qpolynomial *pwqp);
+	__isl_give isl_space *isl_pw_qpolynomial_fold_get_domain_space(
+		__isl_keep isl_pw_qpolynomial_fold *pwf);
+	__isl_give isl_space *isl_pw_qpolynomial_fold_get_space(
+		__isl_keep isl_pw_qpolynomial_fold *pwf);
+	__isl_give isl_space *isl_union_pw_qpolynomial_get_space(
+		__isl_keep isl_union_pw_qpolynomial *upwqp);
+	__isl_give isl_space *isl_union_pw_qpolynomial_fold_get_space(
+		__isl_keep isl_union_pw_qpolynomial_fold *upwf);
+
+	#include <isl/val.h>
+	__isl_give isl_space *isl_multi_val_get_space(
+		__isl_keep isl_multi_val *mv);
+
+	#include <isl/aff.h>
+	__isl_give isl_space *isl_aff_get_domain_space(
+		__isl_keep isl_aff *aff);
+	__isl_give isl_space *isl_aff_get_space(
+		__isl_keep isl_aff *aff);
+	__isl_give isl_space *isl_pw_aff_get_domain_space(
+		__isl_keep isl_pw_aff *pwaff);
+	__isl_give isl_space *isl_pw_aff_get_space(
+		__isl_keep isl_pw_aff *pwaff);
+	__isl_give isl_space *isl_multi_aff_get_domain_space(
+		__isl_keep isl_multi_aff *maff);
+	__isl_give isl_space *isl_multi_aff_get_space(
+		__isl_keep isl_multi_aff *maff);
+	__isl_give isl_space *isl_pw_multi_aff_get_domain_space(
+		__isl_keep isl_pw_multi_aff *pma);
+	__isl_give isl_space *isl_pw_multi_aff_get_space(
+		__isl_keep isl_pw_multi_aff *pma);
+	__isl_give isl_space *isl_union_pw_aff_get_space(
+		__isl_keep isl_union_pw_aff *upa);
+	__isl_give isl_space *isl_union_pw_multi_aff_get_space(
+		__isl_keep isl_union_pw_multi_aff *upma);
+	__isl_give isl_space *isl_multi_pw_aff_get_domain_space(
+		__isl_keep isl_multi_pw_aff *mpa);
+	__isl_give isl_space *isl_multi_pw_aff_get_space(
+		__isl_keep isl_multi_pw_aff *mpa);
+	__isl_give isl_space *
+	isl_multi_union_pw_aff_get_domain_space(
+		__isl_keep isl_multi_union_pw_aff *mupa);
+	__isl_give isl_space *
+	isl_multi_union_pw_aff_get_space(
+		__isl_keep isl_multi_union_pw_aff *mupa);
+
+	#include <isl/point.h>
+	__isl_give isl_space *isl_point_get_space(
+		__isl_keep isl_point *pnt);
+
+The number of dimensions of a given type of space
+may be read off from a space or an object that lives
+in a space using the following functions.
+In case of C<isl_space_dim>, type may be
+C<isl_dim_param>, C<isl_dim_in> (only for relations),
+C<isl_dim_out> (only for relations), C<isl_dim_set>
+(only for sets) or C<isl_dim_all>.
+
+	#include <isl/space.h>
+	unsigned isl_space_dim(__isl_keep isl_space *space,
+		enum isl_dim_type type);
+
+	#include <isl/local_space.h>
+	int isl_local_space_dim(__isl_keep isl_local_space *ls,
+		enum isl_dim_type type);
+
+	#include <isl/set.h>
+	unsigned isl_basic_set_dim(__isl_keep isl_basic_set *bset,
+		enum isl_dim_type type);
+	unsigned isl_set_dim(__isl_keep isl_set *set,
+		enum isl_dim_type type);
+
+	#include <isl/union_set.h>
+	unsigned isl_union_set_dim(__isl_keep isl_union_set *uset,
+		enum isl_dim_type type);
+
+	#include <isl/map.h>
+	unsigned isl_basic_map_dim(__isl_keep isl_basic_map *bmap,
+		enum isl_dim_type type);
+	unsigned isl_map_dim(__isl_keep isl_map *map,
+		enum isl_dim_type type);
+
+	#include <isl/union_map.h>
+	unsigned isl_union_map_dim(__isl_keep isl_union_map *umap,
+		enum isl_dim_type type);
+
+	#include <isl/val.h>
+	unsigned isl_multi_val_dim(__isl_keep isl_multi_val *mv,
+		enum isl_dim_type type);
+
+	#include <isl/aff.h>
+	int isl_aff_dim(__isl_keep isl_aff *aff,
+		enum isl_dim_type type);
+	unsigned isl_multi_aff_dim(__isl_keep isl_multi_aff *maff,
+		enum isl_dim_type type);
+	unsigned isl_pw_aff_dim(__isl_keep isl_pw_aff *pwaff,
+		enum isl_dim_type type);
+	unsigned isl_pw_multi_aff_dim(
+		__isl_keep isl_pw_multi_aff *pma,
+		enum isl_dim_type type);
+	unsigned isl_multi_pw_aff_dim(
+		__isl_keep isl_multi_pw_aff *mpa,
+		enum isl_dim_type type);
+	unsigned isl_union_pw_aff_dim(
+		__isl_keep isl_union_pw_aff *upa,
+		enum isl_dim_type type);
+	unsigned isl_union_pw_multi_aff_dim(
+		__isl_keep isl_union_pw_multi_aff *upma,
+		enum isl_dim_type type);
+	unsigned isl_multi_union_pw_aff_dim(
+		__isl_keep isl_multi_union_pw_aff *mupa,
+		enum isl_dim_type type);
+
+	#include <isl/polynomial.h>
+	unsigned isl_union_pw_qpolynomial_dim(
+		__isl_keep isl_union_pw_qpolynomial *upwqp,
+		enum isl_dim_type type);
+	unsigned isl_union_pw_qpolynomial_fold_dim(
+		__isl_keep isl_union_pw_qpolynomial_fold *upwf,
+		enum isl_dim_type type);
+
+Note that an C<isl_union_set>, an C<isl_union_map>,
+an C<isl_union_pw_multi_aff>,
+an C<isl_union_pw_qpolynomial> and
+an C<isl_union_pw_qpolynomial_fold>
+only have parameters.
+
+The identifiers or names of the individual dimensions of spaces
+may be set or read off using the following functions on spaces
+or objects that live in spaces.
+These functions are mostly useful to obtain the identifiers, positions
+or names of the parameters.  Identifiers of individual dimensions are
+essentially only useful for printing.  They are ignored by all other
+operations and may not be preserved across those operations.
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_set_dim_id(
+		__isl_take isl_space *space,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_id *id);
+	isl_bool isl_space_has_dim_id(__isl_keep isl_space *space,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_id *isl_space_get_dim_id(
+		__isl_keep isl_space *space,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_space *isl_space_set_dim_name(
+		__isl_take isl_space *space,
+		 enum isl_dim_type type, unsigned pos,
+		 __isl_keep const char *name);
+	isl_bool isl_space_has_dim_name(__isl_keep isl_space *space,
+		enum isl_dim_type type, unsigned pos);
+	__isl_keep const char *isl_space_get_dim_name(
+		__isl_keep isl_space *space,
+		enum isl_dim_type type, unsigned pos);
+
+	#include <isl/local_space.h>
+	__isl_give isl_local_space *isl_local_space_set_dim_id(
+		__isl_take isl_local_space *ls,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_id *id);
+	isl_bool isl_local_space_has_dim_id(
+		__isl_keep isl_local_space *ls,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_id *isl_local_space_get_dim_id(
+		__isl_keep isl_local_space *ls,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_local_space *isl_local_space_set_dim_name(
+		__isl_take isl_local_space *ls,
+		enum isl_dim_type type, unsigned pos, const char *s);
+	isl_bool isl_local_space_has_dim_name(
+		__isl_keep isl_local_space *ls,
+		enum isl_dim_type type, unsigned pos)
+	const char *isl_local_space_get_dim_name(
+		__isl_keep isl_local_space *ls,
+		enum isl_dim_type type, unsigned pos);
+
+	#include <isl/constraint.h>
+	const char *isl_constraint_get_dim_name(
+		__isl_keep isl_constraint *constraint,
+		enum isl_dim_type type, unsigned pos);
+
+	#include <isl/set.h>
+	__isl_give isl_id *isl_basic_set_get_dim_id(
+		__isl_keep isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_set *isl_set_set_dim_id(
+		__isl_take isl_set *set, enum isl_dim_type type,
+		unsigned pos, __isl_take isl_id *id);
+	isl_bool isl_set_has_dim_id(__isl_keep isl_set *set,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_id *isl_set_get_dim_id(
+		__isl_keep isl_set *set, enum isl_dim_type type,
+		unsigned pos);
+	const char *isl_basic_set_get_dim_name(
+		__isl_keep isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos);
+	isl_bool isl_set_has_dim_name(__isl_keep isl_set *set,
+		enum isl_dim_type type, unsigned pos);
+	const char *isl_set_get_dim_name(
+		__isl_keep isl_set *set,
+		enum isl_dim_type type, unsigned pos);
+
+	#include <isl/map.h>
+	__isl_give isl_map *isl_map_set_dim_id(
+		__isl_take isl_map *map, enum isl_dim_type type,
+		unsigned pos, __isl_take isl_id *id);
+	isl_bool isl_basic_map_has_dim_id(
+		__isl_keep isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos);
+	isl_bool isl_map_has_dim_id(__isl_keep isl_map *map,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_id *isl_map_get_dim_id(
+		__isl_keep isl_map *map, enum isl_dim_type type,
+		unsigned pos);
+	__isl_give isl_id *isl_union_map_get_dim_id(
+		__isl_keep isl_union_map *umap,
+		enum isl_dim_type type, unsigned pos);
+	const char *isl_basic_map_get_dim_name(
+		__isl_keep isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos);
+	isl_bool isl_map_has_dim_name(__isl_keep isl_map *map,
+		enum isl_dim_type type, unsigned pos);
+	const char *isl_map_get_dim_name(
+		__isl_keep isl_map *map,
+		enum isl_dim_type type, unsigned pos);
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_set_dim_id(
+		__isl_take isl_multi_val *mv,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_id *id);
+	__isl_give isl_id *isl_multi_val_get_dim_id(
+		__isl_keep isl_multi_val *mv,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_multi_val *isl_multi_val_set_dim_name(
+		__isl_take isl_multi_val *mv,
+		enum isl_dim_type type, unsigned pos, const char *s);
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_set_dim_id(
+		__isl_take isl_aff *aff, enum isl_dim_type type,
+		unsigned pos, __isl_take isl_id *id);
+	__isl_give isl_multi_aff *isl_multi_aff_set_dim_id(
+		__isl_take isl_multi_aff *maff,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_id *id);
+	__isl_give isl_pw_aff *isl_pw_aff_set_dim_id(
+		__isl_take isl_pw_aff *pma,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_id *id);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_set_dim_id(
+		__isl_take isl_multi_pw_aff *mpa,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_id *id);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_set_dim_id(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_id *id);
+	__isl_give isl_id *isl_multi_aff_get_dim_id(
+		__isl_keep isl_multi_aff *ma,
+		enum isl_dim_type type, unsigned pos);
+	isl_bool isl_pw_aff_has_dim_id(__isl_keep isl_pw_aff *pa,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_id *isl_pw_aff_get_dim_id(
+		__isl_keep isl_pw_aff *pa,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_id *isl_pw_multi_aff_get_dim_id(
+		__isl_keep isl_pw_multi_aff *pma,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_id *isl_multi_pw_aff_get_dim_id(
+		__isl_keep isl_multi_pw_aff *mpa,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_id *isl_multi_union_pw_aff_get_dim_id(
+		__isl_keep isl_multi_union_pw_aff *mupa,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_aff *isl_aff_set_dim_name(
+		__isl_take isl_aff *aff, enum isl_dim_type type,
+		unsigned pos, const char *s);
+	__isl_give isl_multi_aff *isl_multi_aff_set_dim_name(
+		__isl_take isl_multi_aff *maff,
+		enum isl_dim_type type, unsigned pos, const char *s);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_set_dim_name(
+		__isl_take isl_multi_pw_aff *mpa,
+		enum isl_dim_type type, unsigned pos, const char *s);
+	__isl_give isl_union_pw_aff *
+	isl_union_pw_aff_set_dim_name(
+		__isl_take isl_union_pw_aff *upa,
+		enum isl_dim_type type, unsigned pos,
+		const char *s);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_set_dim_name(
+		__isl_take isl_union_pw_multi_aff *upma,
+		enum isl_dim_type type, unsigned pos,
+		const char *s);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_set_dim_name(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		enum isl_dim_type type, unsigned pos,
+	const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff,
+		enum isl_dim_type type, unsigned pos);
+	const char *isl_pw_aff_get_dim_name(
+		__isl_keep isl_pw_aff *pa,
+		enum isl_dim_type type, unsigned pos);
+	const char *isl_pw_multi_aff_get_dim_name(
+		__isl_keep isl_pw_multi_aff *pma,
+		enum isl_dim_type type, unsigned pos);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_qpolynomial *isl_qpolynomial_set_dim_name(
+		__isl_take isl_qpolynomial *qp,
+		enum isl_dim_type type, unsigned pos,
+		const char *s);
+	__isl_give isl_pw_qpolynomial *
+	isl_pw_qpolynomial_set_dim_name(
+		__isl_take isl_pw_qpolynomial *pwqp,
+		enum isl_dim_type type, unsigned pos,
+		const char *s);
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_set_dim_name(
+		__isl_take isl_pw_qpolynomial_fold *pwf,
+		enum isl_dim_type type, unsigned pos,
+		const char *s);
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_set_dim_name(
+		__isl_take isl_union_pw_qpolynomial *upwqp,
+		enum isl_dim_type type, unsigned pos,
+		const char *s);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_set_dim_name(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf,
+		enum isl_dim_type type, unsigned pos,
+		const char *s);
+
+Note that C<isl_space_get_name> returns a pointer to some internal
+data structure, so the result can only be used while the
+corresponding C<isl_space> is alive.
+Also note that every function that operates on two sets or relations
+requires that both arguments have the same parameters.  This also
+means that if one of the arguments has named parameters, then the
+other needs to have named parameters too and the names need to match.
+Pairs of C<isl_set>, C<isl_map>, C<isl_union_set> and/or C<isl_union_map>
+arguments may have different parameters (as long as they are named),
+in which case the result will have as parameters the union of the parameters of
+the arguments.
+
+Given the identifier or name of a dimension (typically a parameter),
+its position can be obtained from the following functions.
+
+	#include <isl/space.h>
+	int isl_space_find_dim_by_id(__isl_keep isl_space *space,
+		enum isl_dim_type type, __isl_keep isl_id *id);
+	int isl_space_find_dim_by_name(__isl_keep isl_space *space,
+		enum isl_dim_type type, const char *name);
+
+	#include <isl/local_space.h>
+	int isl_local_space_find_dim_by_name(
+		__isl_keep isl_local_space *ls,
+		enum isl_dim_type type, const char *name);
+
+	#include <isl/val.h>
+	int isl_multi_val_find_dim_by_id(
+		__isl_keep isl_multi_val *mv,
+		enum isl_dim_type type, __isl_keep isl_id *id);
+	int isl_multi_val_find_dim_by_name(
+		__isl_keep isl_multi_val *mv,
+		enum isl_dim_type type, const char *name);
+
+	#include <isl/set.h>
+	int isl_set_find_dim_by_id(__isl_keep isl_set *set,
+		enum isl_dim_type type, __isl_keep isl_id *id);
+	int isl_set_find_dim_by_name(__isl_keep isl_set *set,
+		enum isl_dim_type type, const char *name);
+
+	#include <isl/map.h>
+	int isl_map_find_dim_by_id(__isl_keep isl_map *map,
+		enum isl_dim_type type, __isl_keep isl_id *id);
+	int isl_basic_map_find_dim_by_name(
+		__isl_keep isl_basic_map *bmap,
+		enum isl_dim_type type, const char *name);
+	int isl_map_find_dim_by_name(__isl_keep isl_map *map,
+		enum isl_dim_type type, const char *name);
+	int isl_union_map_find_dim_by_name(
+		__isl_keep isl_union_map *umap,
+		enum isl_dim_type type, const char *name);
+
+	#include <isl/aff.h>
+	int isl_multi_aff_find_dim_by_id(
+		__isl_keep isl_multi_aff *ma,
+		enum isl_dim_type type, __isl_keep isl_id *id);
+	int isl_multi_pw_aff_find_dim_by_id(
+		__isl_keep isl_multi_pw_aff *mpa,
+		enum isl_dim_type type, __isl_keep isl_id *id);
+	int isl_multi_union_pw_aff_find_dim_by_id(
+		__isl_keep isl_union_multi_pw_aff *mupa,
+		enum isl_dim_type type, __isl_keep isl_id *id);
+	int isl_aff_find_dim_by_name(__isl_keep isl_aff *aff,
+		enum isl_dim_type type, const char *name);
+	int isl_multi_aff_find_dim_by_name(
+		__isl_keep isl_multi_aff *ma,
+		enum isl_dim_type type, const char *name);
+	int isl_pw_aff_find_dim_by_name(__isl_keep isl_pw_aff *pa,
+		enum isl_dim_type type, const char *name);
+	int isl_multi_pw_aff_find_dim_by_name(
+		__isl_keep isl_multi_pw_aff *mpa,
+		enum isl_dim_type type, const char *name);
+	int isl_pw_multi_aff_find_dim_by_name(
+		__isl_keep isl_pw_multi_aff *pma,
+		enum isl_dim_type type, const char *name);
+	int isl_union_pw_aff_find_dim_by_name(
+		__isl_keep isl_union_pw_aff *upa,
+		enum isl_dim_type type, const char *name);
+	int isl_union_pw_multi_aff_find_dim_by_name(
+		__isl_keep isl_union_pw_multi_aff *upma,
+		enum isl_dim_type type, const char *name);
+	int isl_multi_union_pw_aff_find_dim_by_name(
+		__isl_keep isl_multi_union_pw_aff *mupa,
+		enum isl_dim_type type, const char *name);
+
+	#include <isl/polynomial.h>
+	int isl_pw_qpolynomial_find_dim_by_name(
+		__isl_keep isl_pw_qpolynomial *pwqp,
+		enum isl_dim_type type, const char *name);
+	int isl_pw_qpolynomial_fold_find_dim_by_name(
+		__isl_keep isl_pw_qpolynomial_fold *pwf,
+		enum isl_dim_type type, const char *name);
+	int isl_union_pw_qpolynomial_find_dim_by_name(
+		__isl_keep isl_union_pw_qpolynomial *upwqp,
+		enum isl_dim_type type, const char *name);
+	int isl_union_pw_qpolynomial_fold_find_dim_by_name(
+		__isl_keep isl_union_pw_qpolynomial_fold *upwf,
+		enum isl_dim_type type, const char *name);
+
+The identifiers or names of entire spaces may be set or read off
+using the following functions.
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_set_tuple_id(
+		__isl_take isl_space *space,
+		enum isl_dim_type type, __isl_take isl_id *id);
+	__isl_give isl_space *isl_space_reset_tuple_id(
+		__isl_take isl_space *space, enum isl_dim_type type);
+	isl_bool isl_space_has_tuple_id(
+		__isl_keep isl_space *space,
+		enum isl_dim_type type);
+	__isl_give isl_id *isl_space_get_tuple_id(
+		__isl_keep isl_space *space, enum isl_dim_type type);
+	__isl_give isl_space *isl_space_set_tuple_name(
+		__isl_take isl_space *space,
+		enum isl_dim_type type, const char *s);
+	isl_bool isl_space_has_tuple_name(
+		__isl_keep isl_space *space,
+		enum isl_dim_type type);
+	__isl_keep const char *isl_space_get_tuple_name(
+		__isl_keep isl_space *space,
+		enum isl_dim_type type);
+
+	#include <isl/local_space.h>
+	__isl_give isl_local_space *isl_local_space_set_tuple_id(
+		__isl_take isl_local_space *ls,
+		enum isl_dim_type type, __isl_take isl_id *id);
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_set_tuple_id(
+		__isl_take isl_basic_set *bset,
+		__isl_take isl_id *id);
+	__isl_give isl_set *isl_set_set_tuple_id(
+		__isl_take isl_set *set, __isl_take isl_id *id);
+	__isl_give isl_set *isl_set_reset_tuple_id(
+		__isl_take isl_set *set);
+	isl_bool isl_set_has_tuple_id(__isl_keep isl_set *set);
+	__isl_give isl_id *isl_set_get_tuple_id(
+		__isl_keep isl_set *set);
+	__isl_give isl_basic_set *isl_basic_set_set_tuple_name(
+		__isl_take isl_basic_set *set, const char *s);
+	__isl_give isl_set *isl_set_set_tuple_name(
+		__isl_take isl_set *set, const char *s);
+	const char *isl_basic_set_get_tuple_name(
+		__isl_keep isl_basic_set *bset);
+	isl_bool isl_set_has_tuple_name(__isl_keep isl_set *set);
+	const char *isl_set_get_tuple_name(
+		__isl_keep isl_set *set);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_set_tuple_id(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, __isl_take isl_id *id);
+	__isl_give isl_map *isl_map_set_tuple_id(
+		__isl_take isl_map *map, enum isl_dim_type type,
+		__isl_take isl_id *id);
+	__isl_give isl_map *isl_map_reset_tuple_id(
+		__isl_take isl_map *map, enum isl_dim_type type);
+	isl_bool isl_map_has_tuple_id(__isl_keep isl_map *map,
+		enum isl_dim_type type);
+	__isl_give isl_id *isl_map_get_tuple_id(
+		__isl_keep isl_map *map, enum isl_dim_type type);
+	__isl_give isl_map *isl_map_set_tuple_name(
+		__isl_take isl_map *map,
+		enum isl_dim_type type, const char *s);
+	const char *isl_basic_map_get_tuple_name(
+		__isl_keep isl_basic_map *bmap,
+		enum isl_dim_type type);
+	__isl_give isl_basic_map *isl_basic_map_set_tuple_name(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, const char *s);
+	isl_bool isl_map_has_tuple_name(__isl_keep isl_map *map,
+		enum isl_dim_type type);
+	const char *isl_map_get_tuple_name(
+		__isl_keep isl_map *map,
+		enum isl_dim_type type);
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_set_tuple_id(
+		__isl_take isl_multi_val *mv,
+		enum isl_dim_type type, __isl_take isl_id *id);
+	__isl_give isl_multi_val *isl_multi_val_reset_tuple_id(
+		__isl_take isl_multi_val *mv,
+		enum isl_dim_type type);
+	isl_bool isl_multi_val_has_tuple_id(
+		__isl_keep isl_multi_val *mv,
+		enum isl_dim_type type);
+	__isl_give isl_id *isl_multi_val_get_tuple_id(
+		__isl_keep isl_multi_val *mv,
+		enum isl_dim_type type);
+	__isl_give isl_multi_val *isl_multi_val_set_tuple_name(
+		__isl_take isl_multi_val *mv,
+		enum isl_dim_type type, const char *s);
+	const char *isl_multi_val_get_tuple_name(
+		__isl_keep isl_multi_val *mv,
+		enum isl_dim_type type);
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_set_tuple_id(
+		__isl_take isl_aff *aff,
+		enum isl_dim_type type, __isl_take isl_id *id);
+	__isl_give isl_multi_aff *isl_multi_aff_set_tuple_id(
+		__isl_take isl_multi_aff *maff,
+		enum isl_dim_type type, __isl_take isl_id *id);
+	__isl_give isl_pw_aff *isl_pw_aff_set_tuple_id(
+		__isl_take isl_pw_aff *pwaff,
+		enum isl_dim_type type, __isl_take isl_id *id);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_tuple_id(
+		__isl_take isl_pw_multi_aff *pma,
+		enum isl_dim_type type, __isl_take isl_id *id);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_set_tuple_id(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		enum isl_dim_type type, __isl_take isl_id *id);
+	__isl_give isl_multi_aff *isl_multi_aff_reset_tuple_id(
+		__isl_take isl_multi_aff *ma,
+		enum isl_dim_type type);
+	__isl_give isl_pw_aff *isl_pw_aff_reset_tuple_id(
+		__isl_take isl_pw_aff *pa,
+		enum isl_dim_type type);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_reset_tuple_id(
+		__isl_take isl_multi_pw_aff *mpa,
+		enum isl_dim_type type);
+	__isl_give isl_pw_multi_aff *
+	isl_pw_multi_aff_reset_tuple_id(
+		__isl_take isl_pw_multi_aff *pma,
+		enum isl_dim_type type);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_reset_tuple_id(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		enum isl_dim_type type);
+	isl_bool isl_multi_aff_has_tuple_id(
+		__isl_keep isl_multi_aff *ma,
+		enum isl_dim_type type);
+	__isl_give isl_id *isl_multi_aff_get_tuple_id(
+		__isl_keep isl_multi_aff *ma,
+		enum isl_dim_type type);
+	isl_bool isl_pw_aff_has_tuple_id(__isl_keep isl_pw_aff *pa,
+		enum isl_dim_type type);
+	__isl_give isl_id *isl_pw_aff_get_tuple_id(
+		__isl_keep isl_pw_aff *pa,
+		enum isl_dim_type type);
+	isl_bool isl_pw_multi_aff_has_tuple_id(
+		__isl_keep isl_pw_multi_aff *pma,
+		enum isl_dim_type type);
+	__isl_give isl_id *isl_pw_multi_aff_get_tuple_id(
+		__isl_keep isl_pw_multi_aff *pma,
+		enum isl_dim_type type);
+	isl_bool isl_multi_pw_aff_has_tuple_id(
+		__isl_keep isl_multi_pw_aff *mpa,
+		enum isl_dim_type type);
+	__isl_give isl_id *isl_multi_pw_aff_get_tuple_id(
+		__isl_keep isl_multi_pw_aff *mpa,
+		enum isl_dim_type type);
+	isl_bool isl_multi_union_pw_aff_has_tuple_id(
+		__isl_keep isl_multi_union_pw_aff *mupa,
+		enum isl_dim_type type);
+	__isl_give isl_id *isl_multi_union_pw_aff_get_tuple_id(
+		__isl_keep isl_multi_union_pw_aff *mupa,
+		enum isl_dim_type type);
+	__isl_give isl_multi_aff *isl_multi_aff_set_tuple_name(
+		__isl_take isl_multi_aff *maff,
+		enum isl_dim_type type, const char *s);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_set_tuple_name(
+		__isl_take isl_multi_pw_aff *mpa,
+		enum isl_dim_type type, const char *s);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_set_tuple_name(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		enum isl_dim_type type, const char *s);
+	const char *isl_multi_aff_get_tuple_name(
+		__isl_keep isl_multi_aff *multi,
+		enum isl_dim_type type);
+	isl_bool isl_pw_multi_aff_has_tuple_name(
+		__isl_keep isl_pw_multi_aff *pma,
+		enum isl_dim_type type);
+	const char *isl_pw_multi_aff_get_tuple_name(
+		__isl_keep isl_pw_multi_aff *pma,
+		enum isl_dim_type type);
+	const char *isl_multi_union_pw_aff_get_tuple_name(
+		__isl_keep isl_multi_union_pw_aff *mupa,
+		enum isl_dim_type type);
+
+The C<type> argument needs to be one of C<isl_dim_in>, C<isl_dim_out>
+or C<isl_dim_set>.  As with C<isl_space_get_name>,
+the C<isl_space_get_tuple_name> function returns a pointer to some internal
+data structure.
+Binary operations require the corresponding spaces of their arguments
+to have the same name.
+
+To keep the names of all parameters and tuples, but reset the user pointers
+of all the corresponding identifiers, use the following function.
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_reset_user(
+		__isl_take isl_space *space);
+
+	#include <isl/set.h>
+	__isl_give isl_set *isl_set_reset_user(
+		__isl_take isl_set *set);
+
+	#include <isl/map.h>
+	__isl_give isl_map *isl_map_reset_user(
+		__isl_take isl_map *map);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_set *isl_union_set_reset_user(
+		__isl_take isl_union_set *uset);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_reset_user(
+		__isl_take isl_union_map *umap);
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_reset_user(
+		__isl_take isl_multi_val *mv);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_reset_user(
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_pw_aff *isl_pw_aff_reset_user(
+		__isl_take isl_pw_aff *pa);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_reset_user(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_user(
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_reset_user(
+		__isl_take isl_union_pw_aff *upa);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_reset_user(
+		__isl_take isl_multi_union_pw_aff *mupa);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_reset_user(
+		__isl_take isl_union_pw_multi_aff *upma);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial *
+	isl_pw_qpolynomial_reset_user(
+		__isl_take isl_pw_qpolynomial *pwqp);
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_reset_user(
+		__isl_take isl_union_pw_qpolynomial *upwqp);
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_reset_user(
+		__isl_take isl_pw_qpolynomial_fold *pwf);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_reset_user(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf);
+
+Spaces can be nested.  In particular, the domain of a set or
+the domain or range of a relation can be a nested relation.
+This process is also called I<wrapping>.
+The functions for detecting, constructing and deconstructing
+such nested spaces can be found in the wrapping properties
+of L</"Unary Properties">, the wrapping operations
+of L</"Unary Operations"> and the Cartesian product operations
+of L</"Basic Operations">.
+
+Spaces can be created from other spaces
+using the functions described in L</"Unary Operations">
+and L</"Binary Operations">.
+
+=head2 Local Spaces
+
+A local space is essentially a space with
+zero or more existentially quantified variables.
+The local space of various objects can be obtained
+using the following functions.
+
+	#include <isl/constraint.h>
+	__isl_give isl_local_space *isl_constraint_get_local_space(
+		__isl_keep isl_constraint *constraint);
+
+	#include <isl/set.h>
+	__isl_give isl_local_space *isl_basic_set_get_local_space(
+		__isl_keep isl_basic_set *bset);
+
+	#include <isl/map.h>
+	__isl_give isl_local_space *isl_basic_map_get_local_space(
+		__isl_keep isl_basic_map *bmap);
+
+	#include <isl/aff.h>
+	__isl_give isl_local_space *isl_aff_get_domain_local_space(
+		__isl_keep isl_aff *aff);
+	__isl_give isl_local_space *isl_aff_get_local_space(
+		__isl_keep isl_aff *aff);
+
+A new local space can be created from a space using
+
+	#include <isl/local_space.h>
+	__isl_give isl_local_space *isl_local_space_from_space(
+		__isl_take isl_space *space);
+
+They can be inspected, modified, copied and freed using the following functions.
+
+	#include <isl/local_space.h>
+	isl_bool isl_local_space_is_params(
+		__isl_keep isl_local_space *ls);
+	isl_bool isl_local_space_is_set(
+		__isl_keep isl_local_space *ls);
+	__isl_give isl_space *isl_local_space_get_space(
+		__isl_keep isl_local_space *ls);
+	__isl_give isl_aff *isl_local_space_get_div(
+		__isl_keep isl_local_space *ls, int pos);
+	__isl_give isl_local_space *isl_local_space_copy(
+		__isl_keep isl_local_space *ls);
+	__isl_null isl_local_space *isl_local_space_free(
+		__isl_take isl_local_space *ls);
+
+Note that C<isl_local_space_get_div> can only be used on local spaces
+of sets.
+
+Two local spaces can be compared using
+
+	isl_bool isl_local_space_is_equal(
+		__isl_keep isl_local_space *ls1,
+		__isl_keep isl_local_space *ls2);
+
+Local spaces can be created from other local spaces
+using the functions described in L</"Unary Operations">
+and L</"Binary Operations">.
+
+=head2 Creating New Sets and Relations
+
+C<isl> has functions for creating some standard sets and relations.
+
+=over
+
+=item * Empty sets and relations
+
+	__isl_give isl_basic_set *isl_basic_set_empty(
+		__isl_take isl_space *space);
+	__isl_give isl_basic_map *isl_basic_map_empty(
+		__isl_take isl_space *space);
+	__isl_give isl_set *isl_set_empty(
+		__isl_take isl_space *space);
+	__isl_give isl_map *isl_map_empty(
+		__isl_take isl_space *space);
+	__isl_give isl_union_set *isl_union_set_empty(
+		__isl_take isl_space *space);
+	__isl_give isl_union_map *isl_union_map_empty(
+		__isl_take isl_space *space);
+
+For C<isl_union_set>s and C<isl_union_map>s, the space
+is only used to specify the parameters.
+
+=item * Universe sets and relations
+
+	__isl_give isl_basic_set *isl_basic_set_universe(
+		__isl_take isl_space *space);
+	__isl_give isl_basic_map *isl_basic_map_universe(
+		__isl_take isl_space *space);
+	__isl_give isl_set *isl_set_universe(
+		__isl_take isl_space *space);
+	__isl_give isl_map *isl_map_universe(
+		__isl_take isl_space *space);
+	__isl_give isl_union_set *isl_union_set_universe(
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_map *isl_union_map_universe(
+		__isl_take isl_union_map *umap);
+
+The sets and relations constructed by the functions above
+contain all integer values, while those constructed by the
+functions below only contain non-negative values.
+
+	__isl_give isl_basic_set *isl_basic_set_nat_universe(
+		__isl_take isl_space *space);
+	__isl_give isl_basic_map *isl_basic_map_nat_universe(
+		__isl_take isl_space *space);
+	__isl_give isl_set *isl_set_nat_universe(
+		__isl_take isl_space *space);
+	__isl_give isl_map *isl_map_nat_universe(
+		__isl_take isl_space *space);
+
+=item * Identity relations
+
+	__isl_give isl_basic_map *isl_basic_map_identity(
+		__isl_take isl_space *space);
+	__isl_give isl_map *isl_map_identity(
+		__isl_take isl_space *space);
+
+The number of input and output dimensions in C<space> needs
+to be the same.
+
+=item * Lexicographic order
+
+	__isl_give isl_map *isl_map_lex_lt(
+		__isl_take isl_space *set_space);
+	__isl_give isl_map *isl_map_lex_le(
+		__isl_take isl_space *set_space);
+	__isl_give isl_map *isl_map_lex_gt(
+		__isl_take isl_space *set_space);
+	__isl_give isl_map *isl_map_lex_ge(
+		__isl_take isl_space *set_space);
+	__isl_give isl_map *isl_map_lex_lt_first(
+		__isl_take isl_space *space, unsigned n);
+	__isl_give isl_map *isl_map_lex_le_first(
+		__isl_take isl_space *space, unsigned n);
+	__isl_give isl_map *isl_map_lex_gt_first(
+		__isl_take isl_space *space, unsigned n);
+	__isl_give isl_map *isl_map_lex_ge_first(
+		__isl_take isl_space *space, unsigned n);
+
+The first four functions take a space for a B<set>
+and return relations that express that the elements in the domain
+are lexicographically less
+(C<isl_map_lex_lt>), less or equal (C<isl_map_lex_le>),
+greater (C<isl_map_lex_gt>) or greater or equal (C<isl_map_lex_ge>)
+than the elements in the range.
+The last four functions take a space for a map
+and return relations that express that the first C<n> dimensions
+in the domain are lexicographically less
+(C<isl_map_lex_lt_first>), less or equal (C<isl_map_lex_le_first>),
+greater (C<isl_map_lex_gt_first>) or greater or equal (C<isl_map_lex_ge_first>)
+than the first C<n> dimensions in the range.
+
+=back
+
+A basic set or relation can be converted to a set or relation
+using the following functions.
+
+	__isl_give isl_set *isl_set_from_basic_set(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_map *isl_map_from_basic_map(
+		__isl_take isl_basic_map *bmap);
+
+Sets and relations can be converted to union sets and relations
+using the following functions.
+
+	__isl_give isl_union_set *isl_union_set_from_basic_set(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_union_map *isl_union_map_from_basic_map(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_union_set *isl_union_set_from_set(
+		__isl_take isl_set *set);
+	__isl_give isl_union_map *isl_union_map_from_map(
+		__isl_take isl_map *map);
+
+The inverse conversions below can only be used if the input
+union set or relation is known to contain elements in exactly one
+space.
+
+	__isl_give isl_set *isl_set_from_union_set(
+		__isl_take isl_union_set *uset);
+	__isl_give isl_map *isl_map_from_union_map(
+		__isl_take isl_union_map *umap);
+
+Sets and relations can be copied and freed again using the following
+functions.
+
+	__isl_give isl_basic_set *isl_basic_set_copy(
+		__isl_keep isl_basic_set *bset);
+	__isl_give isl_set *isl_set_copy(__isl_keep isl_set *set);
+	__isl_give isl_union_set *isl_union_set_copy(
+		__isl_keep isl_union_set *uset);
+	__isl_give isl_basic_map *isl_basic_map_copy(
+		__isl_keep isl_basic_map *bmap);
+	__isl_give isl_map *isl_map_copy(__isl_keep isl_map *map);
+	__isl_give isl_union_map *isl_union_map_copy(
+		__isl_keep isl_union_map *umap);
+	__isl_null isl_basic_set *isl_basic_set_free(
+		__isl_take isl_basic_set *bset);
+	__isl_null isl_set *isl_set_free(__isl_take isl_set *set);
+	__isl_null isl_union_set *isl_union_set_free(
+		__isl_take isl_union_set *uset);
+	__isl_null isl_basic_map *isl_basic_map_free(
+		__isl_take isl_basic_map *bmap);
+	__isl_null isl_map *isl_map_free(__isl_take isl_map *map);
+	__isl_null isl_union_map *isl_union_map_free(
+		__isl_take isl_union_map *umap);
+
+Other sets and relations can be constructed by starting
+from a universe set or relation, adding equality and/or
+inequality constraints and then projecting out the
+existentially quantified variables, if any.
+Constraints can be constructed, manipulated and
+added to (or removed from) (basic) sets and relations
+using the following functions.
+
+	#include <isl/constraint.h>
+	__isl_give isl_constraint *isl_constraint_alloc_equality(
+		__isl_take isl_local_space *ls);
+	__isl_give isl_constraint *isl_constraint_alloc_inequality(
+		__isl_take isl_local_space *ls);
+	__isl_give isl_constraint *isl_constraint_set_constant_si(
+		__isl_take isl_constraint *constraint, int v);
+	__isl_give isl_constraint *isl_constraint_set_constant_val(
+		__isl_take isl_constraint *constraint,
+		__isl_take isl_val *v);
+	__isl_give isl_constraint *isl_constraint_set_coefficient_si(
+		__isl_take isl_constraint *constraint,
+		enum isl_dim_type type, int pos, int v);
+	__isl_give isl_constraint *
+	isl_constraint_set_coefficient_val(
+		__isl_take isl_constraint *constraint,
+		enum isl_dim_type type, int pos,
+		__isl_take isl_val *v);
+	__isl_give isl_basic_map *isl_basic_map_add_constraint(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_constraint *constraint);
+	__isl_give isl_basic_set *isl_basic_set_add_constraint(
+		__isl_take isl_basic_set *bset,
+		__isl_take isl_constraint *constraint);
+	__isl_give isl_map *isl_map_add_constraint(
+		__isl_take isl_map *map,
+		__isl_take isl_constraint *constraint);
+	__isl_give isl_set *isl_set_add_constraint(
+		__isl_take isl_set *set,
+		__isl_take isl_constraint *constraint);
+
+For example, to create a set containing the even integers
+between 10 and 42, you would use the following code.
+
+	isl_space *space;
+	isl_local_space *ls;
+	isl_constraint *c;
+	isl_basic_set *bset;
+
+	space = isl_space_set_alloc(ctx, 0, 2);
+	bset = isl_basic_set_universe(isl_space_copy(space));
+	ls = isl_local_space_from_space(space);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1);
+	c = isl_constraint_set_coefficient_si(c, isl_dim_set, 1, 2);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = isl_constraint_alloc_inequality(isl_local_space_copy(ls));
+	c = isl_constraint_set_constant_si(c, -10);
+	c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, 1);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = isl_constraint_alloc_inequality(ls);
+	c = isl_constraint_set_constant_si(c, 42);
+	c = isl_constraint_set_coefficient_si(c, isl_dim_set, 0, -1);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 1, 1);
+
+Or, alternatively,
+
+	isl_basic_set *bset;
+	bset = isl_basic_set_read_from_str(ctx,
+		"{[i] : exists (a : i = 2a and i >= 10 and i <= 42)}");
+
+A basic set or relation can also be constructed from two matrices
+describing the equalities and the inequalities.
+
+	__isl_give isl_basic_set *isl_basic_set_from_constraint_matrices(
+		__isl_take isl_space *space,
+		__isl_take isl_mat *eq, __isl_take isl_mat *ineq,
+		enum isl_dim_type c1,
+		enum isl_dim_type c2, enum isl_dim_type c3,
+		enum isl_dim_type c4);
+	__isl_give isl_basic_map *isl_basic_map_from_constraint_matrices(
+		__isl_take isl_space *space,
+		__isl_take isl_mat *eq, __isl_take isl_mat *ineq,
+		enum isl_dim_type c1,
+		enum isl_dim_type c2, enum isl_dim_type c3,
+		enum isl_dim_type c4, enum isl_dim_type c5);
+
+The C<isl_dim_type> arguments indicate the order in which
+different kinds of variables appear in the input matrices
+and should be a permutation of C<isl_dim_cst>, C<isl_dim_param>,
+C<isl_dim_set> and C<isl_dim_div> for sets and
+of C<isl_dim_cst>, C<isl_dim_param>,
+C<isl_dim_in>, C<isl_dim_out> and C<isl_dim_div> for relations.
+
+A (basic or union) set or relation can also be constructed from a
+(union) (piecewise) (multiple) affine expression
+or a list of affine expressions
+(See L</"Functions">), provided these affine expressions do not
+involve any NaN.
+
+	__isl_give isl_basic_map *isl_basic_map_from_aff(
+		__isl_take isl_aff *aff);
+	__isl_give isl_map *isl_map_from_aff(
+		__isl_take isl_aff *aff);
+	__isl_give isl_set *isl_set_from_pw_aff(
+		__isl_take isl_pw_aff *pwaff);
+	__isl_give isl_map *isl_map_from_pw_aff(
+		__isl_take isl_pw_aff *pwaff);
+	__isl_give isl_basic_map *isl_basic_map_from_aff_list(
+		__isl_take isl_space *domain_space,
+		__isl_take isl_aff_list *list);
+	__isl_give isl_basic_map *isl_basic_map_from_multi_aff(
+		__isl_take isl_multi_aff *maff)
+	__isl_give isl_map *isl_map_from_multi_aff(
+		__isl_take isl_multi_aff *maff)
+	__isl_give isl_set *isl_set_from_pw_multi_aff(
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_map *isl_map_from_pw_multi_aff(
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_set *isl_set_from_multi_pw_aff(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_map *isl_map_from_multi_pw_aff(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_union_map *isl_union_map_from_union_pw_aff(
+		__isl_take isl_union_pw_aff *upa);
+	__isl_give isl_union_map *
+	isl_union_map_from_union_pw_multi_aff(
+		__isl_take isl_union_pw_multi_aff *upma);
+	__isl_give isl_union_map *
+	isl_union_map_from_multi_union_pw_aff(
+		__isl_take isl_multi_union_pw_aff *mupa);
+
+The C<domain_space> argument describes the domain of the resulting
+basic relation.  It is required because the C<list> may consist
+of zero affine expressions.
+The C<mupa> passed to C<isl_union_map_from_multi_union_pw_aff>
+is not allowed to be zero-dimensional.  The domain of the result
+is the shared domain of the union piecewise affine elements.
+
+=head2 Inspecting Sets and Relations
+
+Usually, the user should not have to care about the actual constraints
+of the sets and maps, but should instead apply the abstract operations
+explained in the following sections.
+Occasionally, however, it may be required to inspect the individual
+coefficients of the constraints.  This section explains how to do so.
+In these cases, it may also be useful to have C<isl> compute
+an explicit representation of the existentially quantified variables.
+
+	__isl_give isl_set *isl_set_compute_divs(
+		__isl_take isl_set *set);
+	__isl_give isl_map *isl_map_compute_divs(
+		__isl_take isl_map *map);
+	__isl_give isl_union_set *isl_union_set_compute_divs(
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_map *isl_union_map_compute_divs(
+		__isl_take isl_union_map *umap);
+
+This explicit representation defines the existentially quantified
+variables as integer divisions of the other variables, possibly
+including earlier existentially quantified variables.
+An explicitly represented existentially quantified variable therefore
+has a unique value when the values of the other variables are known.
+
+Alternatively, the existentially quantified variables can be removed
+using the following functions, which compute an overapproximation.
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_remove_divs(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_set *isl_set_remove_divs(
+		__isl_take isl_set *set);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_remove_divs(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_map *isl_map_remove_divs(
+		__isl_take isl_map *map);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_set *isl_union_set_remove_divs(
+		__isl_take isl_union_set *bset);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_remove_divs(
+		__isl_take isl_union_map *bmap);
+
+It is also possible to only remove those divs that are defined
+in terms of a given range of dimensions or only those for which
+no explicit representation is known.
+
+	__isl_give isl_basic_set *
+	isl_basic_set_remove_divs_involving_dims(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_basic_map *
+	isl_basic_map_remove_divs_involving_dims(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_set *isl_set_remove_divs_involving_dims(
+		__isl_take isl_set *set, enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_map *isl_map_remove_divs_involving_dims(
+		__isl_take isl_map *map, enum isl_dim_type type,
+		unsigned first, unsigned n);
+
+	__isl_give isl_basic_set *
+	isl_basic_set_remove_unknown_divs(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_set *isl_set_remove_unknown_divs(
+		__isl_take isl_set *set);
+	__isl_give isl_map *isl_map_remove_unknown_divs(
+		__isl_take isl_map *map);
+
+To iterate over all the sets or maps in a union set or map, use
+
+	isl_stat isl_union_set_foreach_set(
+		__isl_keep isl_union_set *uset,
+		isl_stat (*fn)(__isl_take isl_set *set, void *user),
+		void *user);
+	isl_stat isl_union_map_foreach_map(
+		__isl_keep isl_union_map *umap,
+		isl_stat (*fn)(__isl_take isl_map *map, void *user),
+		void *user);
+
+These functions call the callback function once for each
+(pair of) space(s) for which there are elements in the input.
+The argument to the callback contains all elements in the input
+with that (pair of) space(s).
+
+The number of sets or maps in a union set or map can be obtained
+from
+
+	int isl_union_set_n_set(__isl_keep isl_union_set *uset);
+	int isl_union_map_n_map(__isl_keep isl_union_map *umap);
+
+To extract the set or map in a given space from a union, use
+
+	__isl_give isl_set *isl_union_set_extract_set(
+		__isl_keep isl_union_set *uset,
+		__isl_take isl_space *space);
+	__isl_give isl_map *isl_union_map_extract_map(
+		__isl_keep isl_union_map *umap,
+		__isl_take isl_space *space);
+
+To iterate over all the basic sets or maps in a set or map, use
+
+	isl_stat isl_set_foreach_basic_set(__isl_keep isl_set *set,
+		isl_stat (*fn)(__isl_take isl_basic_set *bset,
+			void *user),
+		void *user);
+	isl_stat isl_map_foreach_basic_map(__isl_keep isl_map *map,
+		isl_stat (*fn)(__isl_take isl_basic_map *bmap,
+			void *user),
+		void *user);
+
+The callback function C<fn> should return 0 if successful and
+-1 if an error occurs.  In the latter case, or if any other error
+occurs, the above functions will return -1.
+
+It should be noted that C<isl> does not guarantee that
+the basic sets or maps passed to C<fn> are disjoint.
+If this is required, then the user should call one of
+the following functions first.
+
+	__isl_give isl_set *isl_set_make_disjoint(
+		__isl_take isl_set *set);
+	__isl_give isl_map *isl_map_make_disjoint(
+		__isl_take isl_map *map);
+
+The number of basic sets in a set can be obtained
+or the number of basic maps in a map can be obtained
+from
+
+	#include <isl/set.h>
+	int isl_set_n_basic_set(__isl_keep isl_set *set);
+
+	#include <isl/map.h>
+	int isl_map_n_basic_map(__isl_keep isl_map *map);
+
+It is also possible to obtain a list of basic sets from a set
+or union set
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set_list *isl_set_get_basic_set_list(
+		__isl_keep isl_set *set);
+
+	#include <isl/union_set.h>
+	__isl_give isl_basic_set_list *
+	isl_union_set_get_basic_set_list(
+		__isl_keep isl_union_set *uset);
+
+The returned list can be manipulated using the functions in L<"Lists">.
+
+To iterate over the constraints of a basic set or map, use
+
+	#include <isl/constraint.h>
+
+	int isl_basic_set_n_constraint(
+		__isl_keep isl_basic_set *bset);
+	isl_stat isl_basic_set_foreach_constraint(
+		__isl_keep isl_basic_set *bset,
+		isl_stat (*fn)(__isl_take isl_constraint *c,
+			void *user),
+		void *user);
+	int isl_basic_map_n_constraint(
+		__isl_keep isl_basic_map *bmap);
+	isl_stat isl_basic_map_foreach_constraint(
+		__isl_keep isl_basic_map *bmap,
+		isl_stat (*fn)(__isl_take isl_constraint *c,
+			void *user),
+		void *user);
+	__isl_null isl_constraint *isl_constraint_free(
+		__isl_take isl_constraint *c);
+
+Again, the callback function C<fn> should return 0 if successful and
+-1 if an error occurs.  In the latter case, or if any other error
+occurs, the above functions will return -1.
+The constraint C<c> represents either an equality or an inequality.
+Use the following function to find out whether a constraint
+represents an equality.  If not, it represents an inequality.
+
+	isl_bool isl_constraint_is_equality(
+		__isl_keep isl_constraint *constraint);
+
+It is also possible to obtain a list of constraints from a basic
+map or set
+
+	#include <isl/constraint.h>
+	__isl_give isl_constraint_list *
+	isl_basic_map_get_constraint_list(
+		__isl_keep isl_basic_map *bmap);
+	__isl_give isl_constraint_list *
+	isl_basic_set_get_constraint_list(
+		__isl_keep isl_basic_set *bset);
+
+These functions require that all existentially quantified variables
+have an explicit representation.
+The returned list can be manipulated using the functions in L<"Lists">.
+
+The coefficients of the constraints can be inspected using
+the following functions.
+
+	isl_bool isl_constraint_is_lower_bound(
+		__isl_keep isl_constraint *constraint,
+		enum isl_dim_type type, unsigned pos);
+	isl_bool isl_constraint_is_upper_bound(
+		__isl_keep isl_constraint *constraint,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_val *isl_constraint_get_constant_val(
+		__isl_keep isl_constraint *constraint);
+	__isl_give isl_val *isl_constraint_get_coefficient_val(
+		__isl_keep isl_constraint *constraint,
+		enum isl_dim_type type, int pos);
+
+The explicit representations of the existentially quantified
+variables can be inspected using the following function.
+Note that the user is only allowed to use this function
+if the inspected set or map is the result of a call
+to C<isl_set_compute_divs> or C<isl_map_compute_divs>.
+The existentially quantified variable is equal to the floor
+of the returned affine expression.  The affine expression
+itself can be inspected using the functions in
+L</"Functions">.
+
+	__isl_give isl_aff *isl_constraint_get_div(
+		__isl_keep isl_constraint *constraint, int pos);
+
+To obtain the constraints of a basic set or map in matrix
+form, use the following functions.
+
+	__isl_give isl_mat *isl_basic_set_equalities_matrix(
+		__isl_keep isl_basic_set *bset,
+		enum isl_dim_type c1, enum isl_dim_type c2,
+		enum isl_dim_type c3, enum isl_dim_type c4);
+	__isl_give isl_mat *isl_basic_set_inequalities_matrix(
+		__isl_keep isl_basic_set *bset,
+		enum isl_dim_type c1, enum isl_dim_type c2,
+		enum isl_dim_type c3, enum isl_dim_type c4);
+	__isl_give isl_mat *isl_basic_map_equalities_matrix(
+		__isl_keep isl_basic_map *bmap,
+		enum isl_dim_type c1,
+		enum isl_dim_type c2, enum isl_dim_type c3,
+		enum isl_dim_type c4, enum isl_dim_type c5);
+	__isl_give isl_mat *isl_basic_map_inequalities_matrix(
+		__isl_keep isl_basic_map *bmap,
+		enum isl_dim_type c1,
+		enum isl_dim_type c2, enum isl_dim_type c3,
+		enum isl_dim_type c4, enum isl_dim_type c5);
+
+The C<isl_dim_type> arguments dictate the order in which
+different kinds of variables appear in the resulting matrix.
+For set inputs, they should be a permutation of
+C<isl_dim_cst>, C<isl_dim_param>, C<isl_dim_set> and C<isl_dim_div>.
+For map inputs, they should be a permutation of
+C<isl_dim_cst>, C<isl_dim_param>,
+C<isl_dim_in>, C<isl_dim_out> and C<isl_dim_div>.
+
+=head2 Points
+
+Points are elements of a set.  They can be used to construct
+simple sets (boxes) or they can be used to represent the
+individual elements of a set.
+The zero point (the origin) can be created using
+
+	__isl_give isl_point *isl_point_zero(__isl_take isl_space *space);
+
+The coordinates of a point can be inspected, set and changed
+using
+
+	__isl_give isl_val *isl_point_get_coordinate_val(
+		__isl_keep isl_point *pnt,
+		enum isl_dim_type type, int pos);
+	__isl_give isl_point *isl_point_set_coordinate_val(
+		__isl_take isl_point *pnt,
+		enum isl_dim_type type, int pos,
+		__isl_take isl_val *v);
+
+	__isl_give isl_point *isl_point_add_ui(
+		__isl_take isl_point *pnt,
+		enum isl_dim_type type, int pos, unsigned val);
+	__isl_give isl_point *isl_point_sub_ui(
+		__isl_take isl_point *pnt,
+		enum isl_dim_type type, int pos, unsigned val);
+
+Points can be copied or freed using
+
+	__isl_give isl_point *isl_point_copy(
+		__isl_keep isl_point *pnt);
+	__isl_null isl_point *isl_point_free(
+		__isl_take isl_point *pnt);
+
+A singleton set can be created from a point using
+
+	__isl_give isl_basic_set *isl_basic_set_from_point(
+		__isl_take isl_point *pnt);
+	__isl_give isl_set *isl_set_from_point(
+		__isl_take isl_point *pnt);
+	__isl_give isl_union_set *isl_union_set_from_point(
+		__isl_take isl_point *pnt);
+
+and a box can be created from two opposite extremal points using
+
+	__isl_give isl_basic_set *isl_basic_set_box_from_points(
+		__isl_take isl_point *pnt1,
+		__isl_take isl_point *pnt2);
+	__isl_give isl_set *isl_set_box_from_points(
+		__isl_take isl_point *pnt1,
+		__isl_take isl_point *pnt2);
+
+All elements of a B<bounded> (union) set can be enumerated using
+the following functions.
+
+	isl_stat isl_set_foreach_point(__isl_keep isl_set *set,
+		isl_stat (*fn)(__isl_take isl_point *pnt,
+			void *user),
+		void *user);
+	isl_stat isl_union_set_foreach_point(
+		__isl_keep isl_union_set *uset,
+		isl_stat (*fn)(__isl_take isl_point *pnt,
+			void *user),
+		void *user);
+
+The function C<fn> is called for each integer point in
+C<set> with as second argument the last argument of
+the C<isl_set_foreach_point> call.  The function C<fn>
+should return C<0> on success and C<-1> on failure.
+In the latter case, C<isl_set_foreach_point> will stop
+enumerating and return C<-1> as well.
+If the enumeration is performed successfully and to completion,
+then C<isl_set_foreach_point> returns C<0>.
+
+To obtain a single point of a (basic or union) set, use
+
+	__isl_give isl_point *isl_basic_set_sample_point(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_point *isl_set_sample_point(
+		__isl_take isl_set *set);
+	__isl_give isl_point *isl_union_set_sample_point(
+		__isl_take isl_union_set *uset);
+
+If C<set> does not contain any (integer) points, then the
+resulting point will be ``void'', a property that can be
+tested using
+
+	isl_bool isl_point_is_void(__isl_keep isl_point *pnt);
+
+=head2 Functions
+
+Besides sets and relation, C<isl> also supports various types of functions.
+Each of these types is derived from the value type (see L</"Values">)
+or from one of two primitive function types
+through the application of zero or more type constructors.
+We first describe the primitive type and then we describe
+the types derived from these primitive types.
+
+=head3 Primitive Functions
+
+C<isl> support two primitive function types, quasi-affine
+expressions and quasipolynomials.
+A quasi-affine expression is defined either over a parameter
+space or over a set and is composed of integer constants,
+parameters and set variables, addition, subtraction and
+integer division by an integer constant.
+For example, the quasi-affine expression
+
+	[n] -> { [x] -> [2*floor((4 n + x)/9] }
+
+maps C<x> to C<2*floor((4 n + x)/9>.
+A quasipolynomial is a polynomial expression in quasi-affine
+expression.  That is, it additionally allows for multiplication.
+Note, though, that it is not allowed to construct an integer
+division of an expression involving multiplications.
+Here is an example of a quasipolynomial that is not
+quasi-affine expression
+
+	[n] -> { [x] -> (n*floor((4 n + x)/9) }
+
+Note that the external representations of quasi-affine expressions
+and quasipolynomials are different.  Quasi-affine expressions
+use a notation with square brackets just like binary relations,
+while quasipolynomials do not.  This might change at some point.
+
+If a primitive function is defined over a parameter space,
+then the space of the function itself is that of a set.
+If it is defined over a set, then the space of the function
+is that of a relation.  In both cases, the set space (or
+the output space) is single-dimensional, anonymous and unstructured.
+To create functions with multiple dimensions or with other kinds
+of set or output spaces, use multiple expressions
+(see L</"Multiple Expressions">).
+
+=over
+
+=item * Quasi-affine Expressions
+
+Besides the expressions described above, a quasi-affine
+expression can also be set to NaN.  Such expressions
+typically represent a failure to represent a result
+as a quasi-affine expression.
+
+The zero quasi affine expression or the quasi affine expression
+that is equal to a given value or
+a specified dimension on a given domain can be created using
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_zero_on_domain(
+		__isl_take isl_local_space *ls);
+	__isl_give isl_aff *isl_aff_val_on_domain(
+		__isl_take isl_local_space *ls,
+		__isl_take isl_val *val);
+	__isl_give isl_aff *isl_aff_var_on_domain(
+		__isl_take isl_local_space *ls,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_aff *isl_aff_nan_on_domain(
+		__isl_take isl_local_space *ls);
+
+Quasi affine expressions can be copied and freed using
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_copy(
+		__isl_keep isl_aff *aff);
+	__isl_null isl_aff *isl_aff_free(
+		__isl_take isl_aff *aff);
+
+A (rational) bound on a dimension can be extracted from an C<isl_constraint>
+using the following function.  The constraint is required to have
+a non-zero coefficient for the specified dimension.
+
+	#include <isl/constraint.h>
+	__isl_give isl_aff *isl_constraint_get_bound(
+		__isl_keep isl_constraint *constraint,
+		enum isl_dim_type type, int pos);
+
+The entire affine expression of the constraint can also be extracted
+using the following function.
+
+	#include <isl/constraint.h>
+	__isl_give isl_aff *isl_constraint_get_aff(
+		__isl_keep isl_constraint *constraint);
+
+Conversely, an equality constraint equating
+the affine expression to zero or an inequality constraint enforcing
+the affine expression to be non-negative, can be constructed using
+
+	__isl_give isl_constraint *isl_equality_from_aff(
+		__isl_take isl_aff *aff);
+	__isl_give isl_constraint *isl_inequality_from_aff(
+		__isl_take isl_aff *aff);
+
+The coefficients and the integer divisions of an affine expression
+can be inspected using the following functions.
+
+	#include <isl/aff.h>
+	__isl_give isl_val *isl_aff_get_constant_val(
+		__isl_keep isl_aff *aff);
+	__isl_give isl_val *isl_aff_get_coefficient_val(
+		__isl_keep isl_aff *aff,
+		enum isl_dim_type type, int pos);
+	int isl_aff_coefficient_sgn(__isl_keep isl_aff *aff,
+		enum isl_dim_type type, int pos);
+	__isl_give isl_val *isl_aff_get_denominator_val(
+		__isl_keep isl_aff *aff);
+	__isl_give isl_aff *isl_aff_get_div(
+		__isl_keep isl_aff *aff, int pos);
+
+They can be modified using the following functions.
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_set_constant_si(
+		__isl_take isl_aff *aff, int v);
+	__isl_give isl_aff *isl_aff_set_constant_val(
+		__isl_take isl_aff *aff, __isl_take isl_val *v);
+	__isl_give isl_aff *isl_aff_set_coefficient_si(
+		__isl_take isl_aff *aff,
+		enum isl_dim_type type, int pos, int v);
+	__isl_give isl_aff *isl_aff_set_coefficient_val(
+		__isl_take isl_aff *aff,
+		enum isl_dim_type type, int pos,
+		__isl_take isl_val *v);
+
+	__isl_give isl_aff *isl_aff_add_constant_si(
+		__isl_take isl_aff *aff, int v);
+	__isl_give isl_aff *isl_aff_add_constant_val(
+		__isl_take isl_aff *aff, __isl_take isl_val *v);
+	__isl_give isl_aff *isl_aff_add_constant_num_si(
+		__isl_take isl_aff *aff, int v);
+	__isl_give isl_aff *isl_aff_add_coefficient_si(
+		__isl_take isl_aff *aff,
+		enum isl_dim_type type, int pos, int v);
+	__isl_give isl_aff *isl_aff_add_coefficient_val(
+		__isl_take isl_aff *aff,
+		enum isl_dim_type type, int pos,
+		__isl_take isl_val *v);
+
+Note that C<isl_aff_set_constant_si> and C<isl_aff_set_coefficient_si>
+set the I<numerator> of the constant or coefficient, while
+C<isl_aff_set_constant_val> and C<isl_aff_set_coefficient_val> set
+the constant or coefficient as a whole.
+The C<add_constant> and C<add_coefficient> functions add an integer
+or rational value to
+the possibly rational constant or coefficient.
+The C<add_constant_num> functions add an integer value to
+the numerator.
+
+=item * Quasipolynomials
+
+Some simple quasipolynomials can be created using the following functions.
+
+	#include <isl/polynomial.h>
+	__isl_give isl_qpolynomial *isl_qpolynomial_zero_on_domain(
+		__isl_take isl_space *domain);
+	__isl_give isl_qpolynomial *isl_qpolynomial_one_on_domain(
+		__isl_take isl_space *domain);
+	__isl_give isl_qpolynomial *isl_qpolynomial_infty_on_domain(
+		__isl_take isl_space *domain);
+	__isl_give isl_qpolynomial *isl_qpolynomial_neginfty_on_domain(
+		__isl_take isl_space *domain);
+	__isl_give isl_qpolynomial *isl_qpolynomial_nan_on_domain(
+		__isl_take isl_space *domain);
+	__isl_give isl_qpolynomial *isl_qpolynomial_val_on_domain(
+		__isl_take isl_space *domain,
+		__isl_take isl_val *val);
+	__isl_give isl_qpolynomial *isl_qpolynomial_var_on_domain(
+		__isl_take isl_space *domain,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_qpolynomial *isl_qpolynomial_from_aff(
+		__isl_take isl_aff *aff);
+
+Recall that the space in which a quasipolynomial lives is a map space
+with a one-dimensional range.  The C<domain> argument in some of
+the functions above corresponds to the domain of this map space.
+
+Quasipolynomials can be copied and freed again using the following
+functions.
+
+	#include <isl/polynomial.h>
+	__isl_give isl_qpolynomial *isl_qpolynomial_copy(
+		__isl_keep isl_qpolynomial *qp);
+	__isl_null isl_qpolynomial *isl_qpolynomial_free(
+		__isl_take isl_qpolynomial *qp);
+
+The constant term of a quasipolynomial can be extracted using
+
+	__isl_give isl_val *isl_qpolynomial_get_constant_val(
+		__isl_keep isl_qpolynomial *qp);
+
+To iterate over all terms in a quasipolynomial,
+use
+
+	isl_stat isl_qpolynomial_foreach_term(
+		__isl_keep isl_qpolynomial *qp,
+		isl_stat (*fn)(__isl_take isl_term *term,
+			  void *user), void *user);
+
+The terms themselves can be inspected and freed using
+these functions
+
+	unsigned isl_term_dim(__isl_keep isl_term *term,
+		enum isl_dim_type type);
+	__isl_give isl_val *isl_term_get_coefficient_val(
+		__isl_keep isl_term *term);
+	int isl_term_get_exp(__isl_keep isl_term *term,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_aff *isl_term_get_div(
+		__isl_keep isl_term *term, unsigned pos);
+	void isl_term_free(__isl_take isl_term *term);
+
+Each term is a product of parameters, set variables and
+integer divisions.  The function C<isl_term_get_exp>
+returns the exponent of a given dimensions in the given term.
+
+=back
+
+=head3 Reductions
+
+A reduction represents a maximum or a minimum of its
+base expressions.
+The only reduction type defined by C<isl> is
+C<isl_qpolynomial_fold>.
+
+There are currently no functions to directly create such
+objects, but they do appear in the piecewise quasipolynomial
+reductions returned by the C<isl_pw_qpolynomial_bound> function.
+See
+L</"Bounds on Piecewise Quasipolynomials and Piecewise Quasipolynomial Reductions">.
+
+Reductions can be copied and freed using
+the following functions.
+
+	#include <isl/polynomial.h>
+	__isl_give isl_qpolynomial_fold *
+	isl_qpolynomial_fold_copy(
+		__isl_keep isl_qpolynomial_fold *fold);
+	void isl_qpolynomial_fold_free(
+		__isl_take isl_qpolynomial_fold *fold);
+
+To iterate over all quasipolynomials in a reduction, use
+
+	isl_stat isl_qpolynomial_fold_foreach_qpolynomial(
+		__isl_keep isl_qpolynomial_fold *fold,
+		isl_stat (*fn)(__isl_take isl_qpolynomial *qp,
+			  void *user), void *user);
+
+=head3 Multiple Expressions
+
+A multiple expression represents a sequence of zero or
+more base expressions, all defined on the same domain space.
+The domain space of the multiple expression is the same
+as that of the base expressions, but the range space
+can be any space.  In case the base expressions have
+a set space, the corresponding multiple expression
+also has a set space.
+Objects of the value type do not have an associated space.
+The space of a multiple value is therefore always a set space.
+Similarly, the space of a multiple union piecewise
+affine expression is always a set space.
+
+The multiple expression types defined by C<isl>
+are C<isl_multi_val>, C<isl_multi_aff>, C<isl_multi_pw_aff>,
+C<isl_multi_union_pw_aff>.
+
+A multiple expression with the value zero for
+each output (or set) dimension can be created
+using the following functions.
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_zero(
+		__isl_take isl_space *space);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_zero(
+		__isl_take isl_space *space);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_zero(
+		__isl_take isl_space *space);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_zero(
+		__isl_take isl_space *space);
+
+Since there is no canonical way of representing a zero
+value of type C<isl_union_pw_aff>, the space passed
+to C<isl_multi_union_pw_aff_zero> needs to be zero-dimensional.
+
+An identity function can be created using the following
+functions.  The space needs to be that of a relation
+with the same number of input and output dimensions.
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_identity(
+		__isl_take isl_space *space);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_identity(
+		__isl_take isl_space *space);
+
+A function that performs a projection on a universe
+relation or set can be created using the following functions.
+See also the corresponding
+projection operations in L</"Unary Operations">.
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_domain_map(
+		__isl_take isl_space *space);
+	__isl_give isl_multi_aff *isl_multi_aff_range_map(
+		__isl_take isl_space *space);
+	__isl_give isl_multi_aff *isl_multi_aff_project_out_map(
+		__isl_take isl_space *space,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+
+A multiple expression can be created from a single
+base expression using the following functions.
+The space of the created multiple expression is the same
+as that of the base expression, except for
+C<isl_multi_union_pw_aff_from_union_pw_aff> where the input
+lives in a parameter space and the output lives
+in a single-dimensional set space.
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_from_aff(
+		__isl_take isl_aff *aff);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_aff(
+		__isl_take isl_pw_aff *pa);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_from_union_pw_aff(
+		__isl_take isl_union_pw_aff *upa);
+
+A multiple expression can be created from a list
+of base expression in a specified space.
+The domain of this space needs to be the same
+as the domains of the base expressions in the list.
+If the base expressions have a set space (or no associated space),
+then this space also needs to be a set space.
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_from_val_list(
+		__isl_take isl_space *space,
+		__isl_take isl_val_list *list);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_from_aff_list(
+		__isl_take isl_space *space,
+		__isl_take isl_aff_list *list);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_from_pw_aff_list(
+		__isl_take isl_space *space,
+		__isl_take isl_pw_aff_list *list);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_from_union_pw_aff_list(
+		__isl_take isl_space *space,
+		__isl_take isl_union_pw_aff_list *list);
+
+As a convenience, a multiple piecewise expression can
+also be created from a multiple expression.
+Each piecewise expression in the result has a single
+universe cell.
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_from_multi_aff(
+		__isl_take isl_multi_aff *ma);
+
+Similarly, a multiple union expression can be
+created from a multiple expression.
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_from_multi_aff(
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_from_multi_pw_aff(
+		__isl_take isl_multi_pw_aff *mpa);
+
+A multiple quasi-affine expression can be created from
+a multiple value with a given domain space using the following
+function.
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *
+	isl_multi_aff_multi_val_on_space(
+		__isl_take isl_space *space,
+		__isl_take isl_multi_val *mv);
+
+Similarly,
+a multiple union piecewise affine expression can be created from
+a multiple value with a given domain or
+a multiple affine expression with a given domain
+using the following functions.
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_multi_val_on_domain(
+		__isl_take isl_union_set *domain,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_multi_aff_on_domain(
+		__isl_take isl_union_set *domain,
+		__isl_take isl_multi_aff *ma);
+
+Multiple expressions can be copied and freed using
+the following functions.
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_copy(
+		__isl_keep isl_multi_val *mv);
+	__isl_null isl_multi_val *isl_multi_val_free(
+		__isl_take isl_multi_val *mv);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_copy(
+		__isl_keep isl_multi_aff *maff);
+	__isl_null isl_multi_aff *isl_multi_aff_free(
+		__isl_take isl_multi_aff *maff);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_copy(
+		__isl_keep isl_multi_pw_aff *mpa);
+	__isl_null isl_multi_pw_aff *isl_multi_pw_aff_free(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_copy(
+		__isl_keep isl_multi_union_pw_aff *mupa);
+	__isl_null isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_free(
+		__isl_take isl_multi_union_pw_aff *mupa);
+
+The base expression at a given position of a multiple
+expression can be extracted using the following functions.
+
+	#include <isl/val.h>
+	__isl_give isl_val *isl_multi_val_get_val(
+		__isl_keep isl_multi_val *mv, int pos);
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_multi_aff_get_aff(
+		__isl_keep isl_multi_aff *multi, int pos);
+	__isl_give isl_pw_aff *isl_multi_pw_aff_get_pw_aff(
+		__isl_keep isl_multi_pw_aff *mpa, int pos);
+	__isl_give isl_union_pw_aff *
+	isl_multi_union_pw_aff_get_union_pw_aff(
+		__isl_keep isl_multi_union_pw_aff *mupa, int pos);
+
+It can be replaced using the following functions.
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_set_val(
+		__isl_take isl_multi_val *mv, int pos,
+		__isl_take isl_val *val);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_set_aff(
+		__isl_take isl_multi_aff *multi, int pos,
+		__isl_take isl_aff *aff);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_set_union_pw_aff(
+		__isl_take isl_multi_union_pw_aff *mupa, int pos,
+		__isl_take isl_union_pw_aff *upa);
+
+As a convenience, a sequence of base expressions that have
+their domains in a given space can be extracted from a sequence
+of union expressions using the following function.
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_pw_aff *
+	isl_multi_union_pw_aff_extract_multi_pw_aff(
+		__isl_keep isl_multi_union_pw_aff *mupa,
+		__isl_take isl_space *space);
+
+Note that there is a difference between C<isl_multi_union_pw_aff>
+and C<isl_union_pw_multi_aff> objects.  The first is a sequence
+of unions of piecewise expressions, while the second is a union
+of piecewise sequences.  In particular, multiple affine expressions
+in an C<isl_union_pw_multi_aff> may live in different spaces,
+while there is only a single multiple expression in
+an C<isl_multi_union_pw_aff>, which can therefore only live
+in a single space.  This means that not every
+C<isl_union_pw_multi_aff> can be converted to
+an C<isl_multi_union_pw_aff>.  Conversely, a zero-dimensional
+C<isl_multi_union_pw_aff> carries no information
+about any possible domain and therefore cannot be converted
+to an C<isl_union_pw_multi_aff>.  Moreover, the elements
+of an C<isl_multi_union_pw_aff> may be defined over different domains,
+while each multiple expression inside an C<isl_union_pw_multi_aff>
+has a single domain.  The conversion of an C<isl_union_pw_multi_aff>
+of dimension greater than one may therefore not be exact.
+The following functions can
+be used to perform these conversions when they are possible.
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_from_union_pw_multi_aff(
+		__isl_take isl_union_pw_multi_aff *upma);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_from_multi_union_pw_aff(
+		__isl_take isl_multi_union_pw_aff *mupa);
+
+=head3 Piecewise Expressions
+
+A piecewise expression is an expression that is described
+using zero or more base expression defined over the same
+number of cells in the domain space of the base expressions.
+All base expressions are defined over the same
+domain space and the cells are disjoint.
+The space of a piecewise expression is the same as
+that of the base expressions.
+If the union of the cells is a strict subset of the domain
+space, then the value of the piecewise expression outside
+this union is different for types derived from quasi-affine
+expressions and those derived from quasipolynomials.
+Piecewise expressions derived from quasi-affine expressions
+are considered to be undefined outside the union of their cells.
+Piecewise expressions derived from quasipolynomials
+are considered to be zero outside the union of their cells.
+
+Piecewise quasipolynomials are mainly used by the C<barvinok>
+library for representing the number of elements in a parametric set or map.
+For example, the piecewise quasipolynomial
+
+	[n] -> { [x] -> ((1 + n) - x) : x <= n and x >= 0 }
+
+represents the number of points in the map
+
+	[n] -> { [x] -> [y] : x,y >= 0 and 0 <= x + y <= n }
+
+The piecewise expression types defined by C<isl>
+are C<isl_pw_aff>, C<isl_pw_multi_aff>,
+C<isl_pw_qpolynomial> and C<isl_pw_qpolynomial_fold>.
+
+A piecewise expression with no cells can be created using
+the following functions.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_aff_empty(
+		__isl_take isl_space *space);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_empty(
+		__isl_take isl_space *space);
+
+A piecewise expression with a single universe cell can be
+created using the following functions.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_aff_from_aff(
+		__isl_take isl_aff *aff);
+	__isl_give isl_pw_multi_aff *
+	isl_pw_multi_aff_from_multi_aff(
+		__isl_take isl_multi_aff *ma);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial *
+	isl_pw_qpolynomial_from_qpolynomial(
+		__isl_take isl_qpolynomial *qp);
+
+A piecewise expression with a single specified cell can be
+created using the following functions.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_aff_alloc(
+		__isl_take isl_set *set, __isl_take isl_aff *aff);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_alloc(
+		__isl_take isl_set *set,
+		__isl_take isl_multi_aff *maff);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_alloc(
+		__isl_take isl_set *set,
+		__isl_take isl_qpolynomial *qp);
+
+The following convenience functions first create a base expression and
+then create a piecewise expression over a universe domain.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_aff_zero_on_domain(
+		__isl_take isl_local_space *ls);
+	__isl_give isl_pw_aff *isl_pw_aff_var_on_domain(
+		__isl_take isl_local_space *ls,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_pw_aff *isl_pw_aff_nan_on_domain(
+		__isl_take isl_local_space *ls);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_zero(
+		__isl_take isl_space *space);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity(
+		__isl_take isl_space *space);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_map(
+		__isl_take isl_space *space);
+	__isl_give isl_pw_multi_aff *
+	isl_pw_multi_aff_project_out_map(
+		__isl_take isl_space *space,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_zero(
+		__isl_take isl_space *space);
+
+The following convenience functions first create a base expression and
+then create a piecewise expression over a given domain.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_aff_val_on_domain(
+		__isl_take isl_set *domain,
+		__isl_take isl_val *v);
+	__isl_give isl_pw_multi_aff *
+	isl_pw_multi_aff_multi_val_on_domain(
+		__isl_take isl_set *domain,
+		__isl_take isl_multi_val *mv);
+
+As a convenience, a piecewise multiple expression can
+also be created from a piecewise expression.
+Each multiple expression in the result is derived
+from the corresponding base expression.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_pw_aff(
+		__isl_take isl_pw_aff *pa);
+
+Similarly, a piecewise quasipolynomial can be
+created from a piecewise quasi-affine expression using
+the following function.
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial *
+	isl_pw_qpolynomial_from_pw_aff(
+		__isl_take isl_pw_aff *pwaff);
+
+Piecewise expressions can be copied and freed using the following functions.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_aff_copy(
+		__isl_keep isl_pw_aff *pwaff);
+	__isl_null isl_pw_aff *isl_pw_aff_free(
+		__isl_take isl_pw_aff *pwaff);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_copy(
+		__isl_keep isl_pw_multi_aff *pma);
+	__isl_null isl_pw_multi_aff *isl_pw_multi_aff_free(
+		__isl_take isl_pw_multi_aff *pma);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_copy(
+		__isl_keep isl_pw_qpolynomial *pwqp);
+	__isl_null isl_pw_qpolynomial *isl_pw_qpolynomial_free(
+		__isl_take isl_pw_qpolynomial *pwqp);
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_copy(
+		__isl_keep isl_pw_qpolynomial_fold *pwf);
+	__isl_null isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_free(
+		__isl_take isl_pw_qpolynomial_fold *pwf);
+
+To iterate over the different cells of a piecewise expression,
+use the following functions.
+
+	#include <isl/aff.h>
+	isl_bool isl_pw_aff_is_empty(__isl_keep isl_pw_aff *pwaff);
+	int isl_pw_aff_n_piece(__isl_keep isl_pw_aff *pwaff);
+	isl_stat isl_pw_aff_foreach_piece(
+		__isl_keep isl_pw_aff *pwaff,
+		isl_stat (*fn)(__isl_take isl_set *set,
+			  __isl_take isl_aff *aff,
+			  void *user), void *user);
+	int isl_pw_multi_aff_n_piece(
+		__isl_keep isl_pw_multi_aff *pma);
+	isl_stat isl_pw_multi_aff_foreach_piece(
+		__isl_keep isl_pw_multi_aff *pma,
+		isl_stat (*fn)(__isl_take isl_set *set,
+			    __isl_take isl_multi_aff *maff,
+			    void *user), void *user);
+
+	#include <isl/polynomial.h>
+	int isl_pw_qpolynomial_n_piece(
+		__isl_keep isl_pw_qpolynomial *pwqp);
+	isl_stat isl_pw_qpolynomial_foreach_piece(
+		__isl_keep isl_pw_qpolynomial *pwqp,
+		isl_stat (*fn)(__isl_take isl_set *set,
+			  __isl_take isl_qpolynomial *qp,
+			  void *user), void *user);
+	isl_stat isl_pw_qpolynomial_foreach_lifted_piece(
+		__isl_keep isl_pw_qpolynomial *pwqp,
+		isl_stat (*fn)(__isl_take isl_set *set,
+			  __isl_take isl_qpolynomial *qp,
+			  void *user), void *user);
+	int isl_pw_qpolynomial_fold_n_piece(
+		__isl_keep isl_pw_qpolynomial_fold *pwf);
+	isl_stat isl_pw_qpolynomial_fold_foreach_piece(
+		__isl_keep isl_pw_qpolynomial_fold *pwf,
+		isl_stat (*fn)(__isl_take isl_set *set,
+			  __isl_take isl_qpolynomial_fold *fold,
+			  void *user), void *user);
+	isl_stat isl_pw_qpolynomial_fold_foreach_lifted_piece(
+		__isl_keep isl_pw_qpolynomial_fold *pwf,
+		isl_stat (*fn)(__isl_take isl_set *set,
+			  __isl_take isl_qpolynomial_fold *fold,
+			  void *user), void *user);
+
+As usual, the function C<fn> should return C<0> on success
+and C<-1> on failure.  The difference between
+C<isl_pw_qpolynomial_foreach_piece> and
+C<isl_pw_qpolynomial_foreach_lifted_piece> is that
+C<isl_pw_qpolynomial_foreach_lifted_piece> will first
+compute unique representations for all existentially quantified
+variables and then turn these existentially quantified variables
+into extra set variables, adapting the associated quasipolynomial
+accordingly.  This means that the C<set> passed to C<fn>
+will not have any existentially quantified variables, but that
+the dimensions of the sets may be different for different
+invocations of C<fn>.
+Similarly for C<isl_pw_qpolynomial_fold_foreach_piece>
+and C<isl_pw_qpolynomial_fold_foreach_lifted_piece>.
+
+A piecewise expression consisting of the expressions at a given
+position of a piecewise multiple expression can be extracted
+using the following function.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_multi_aff_get_pw_aff(
+		__isl_keep isl_pw_multi_aff *pma, int pos);
+
+These expressions can be replaced using the following function.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_pw_aff(
+		__isl_take isl_pw_multi_aff *pma, unsigned pos,
+		__isl_take isl_pw_aff *pa);
+
+Note that there is a difference between C<isl_multi_pw_aff> and
+C<isl_pw_multi_aff> objects.  The first is a sequence of piecewise
+affine expressions, while the second is a piecewise sequence
+of affine expressions.  In particular, each of the piecewise
+affine expressions in an C<isl_multi_pw_aff> may have a different
+domain, while all multiple expressions associated to a cell
+in an C<isl_pw_multi_aff> have the same domain.
+It is possible to convert between the two, but when converting
+an C<isl_multi_pw_aff> to an C<isl_pw_multi_aff>, the domain
+of the result is the intersection of the domains of the input.
+The reverse conversion is exact.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_multi_aff *
+	isl_pw_multi_aff_from_multi_pw_aff(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_from_pw_multi_aff(
+		__isl_take isl_pw_multi_aff *pma);
+
+=head3 Union Expressions
+
+A union expression collects base expressions defined
+over different domains.  The space of a union expression
+is that of the shared parameter space.
+
+The union expression types defined by C<isl>
+are C<isl_union_pw_aff>, C<isl_union_pw_multi_aff>,
+C<isl_union_pw_qpolynomial> and C<isl_union_pw_qpolynomial_fold>.
+In case of
+C<isl_union_pw_aff>,
+C<isl_union_pw_qpolynomial> and C<isl_union_pw_qpolynomial_fold>,
+there can be at most one base expression for a given domain space.
+In case of
+C<isl_union_pw_multi_aff>,
+there can be multiple such expressions for a given domain space,
+but the domains of these expressions need to be disjoint.
+
+An empty union expression can be created using the following functions.
+
+	#include <isl/aff.h>
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_empty(
+		__isl_take isl_space *space);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_empty(
+		__isl_take isl_space *space);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_zero(
+		__isl_take isl_space *space);
+
+A union expression containing a single base expression
+can be created using the following functions.
+
+	#include <isl/aff.h>
+	__isl_give isl_union_pw_aff *
+	isl_union_pw_aff_from_pw_aff(
+		__isl_take isl_pw_aff *pa);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_from_aff(
+		__isl_take isl_aff *aff);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_from_pw_multi_aff(
+		__isl_take isl_pw_multi_aff *pma);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_from_pw_qpolynomial(
+		__isl_take isl_pw_qpolynomial *pwqp);
+
+The following functions create a base expression on each
+of the sets in the union set and collect the results.
+
+	#include <isl/aff.h>
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_from_union_pw_aff(
+		__isl_take isl_union_pw_aff *upa);
+	__isl_give isl_union_pw_aff *
+	isl_union_pw_multi_aff_get_union_pw_aff(
+		__isl_keep isl_union_pw_multi_aff *upma, int pos);
+	__isl_give isl_union_pw_aff *
+	isl_union_pw_aff_val_on_domain(
+		__isl_take isl_union_set *domain,
+		__isl_take isl_val *v);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_multi_val_on_domain(
+		__isl_take isl_union_set *domain,
+		__isl_take isl_multi_val *mv);
+
+An C<isl_union_pw_aff> that is equal to a (parametric) affine
+expression on a given domain can be created using the following
+function.
+
+	#include <isl/aff.h>
+	__isl_give isl_union_pw_aff *
+	isl_union_pw_aff_aff_on_domain(
+		__isl_take isl_union_set *domain,
+		__isl_take isl_aff *aff);
+
+A base expression can be added to a union expression using
+the following functions.
+
+	#include <isl/aff.h>
+	__isl_give isl_union_pw_aff *
+	isl_union_pw_aff_add_pw_aff(
+		__isl_take isl_union_pw_aff *upa,
+		__isl_take isl_pw_aff *pa);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_add_pw_multi_aff(
+		__isl_take isl_union_pw_multi_aff *upma,
+		__isl_take isl_pw_multi_aff *pma);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_add_pw_qpolynomial(
+		__isl_take isl_union_pw_qpolynomial *upwqp,
+		__isl_take isl_pw_qpolynomial *pwqp);
+
+Union expressions can be copied and freed using
+the following functions.
+
+	#include <isl/aff.h>
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_copy(
+		__isl_keep isl_union_pw_aff *upa);
+	__isl_null isl_union_pw_aff *isl_union_pw_aff_free(
+		__isl_take isl_union_pw_aff *upa);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_copy(
+		__isl_keep isl_union_pw_multi_aff *upma);
+	__isl_null isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_free(
+		__isl_take isl_union_pw_multi_aff *upma);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_copy(
+		__isl_keep isl_union_pw_qpolynomial *upwqp);
+	__isl_null isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_free(
+		__isl_take isl_union_pw_qpolynomial *upwqp);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_copy(
+		__isl_keep isl_union_pw_qpolynomial_fold *upwf);
+	__isl_null isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_free(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf);
+
+To iterate over the base expressions in a union expression,
+use the following functions.
+
+	#include <isl/aff.h>
+	int isl_union_pw_aff_n_pw_aff(
+		__isl_keep isl_union_pw_aff *upa);
+	isl_stat isl_union_pw_aff_foreach_pw_aff(
+		__isl_keep isl_union_pw_aff *upa,
+		isl_stat (*fn)(__isl_take isl_pw_aff *pa,
+			void *user), void *user);
+	int isl_union_pw_multi_aff_n_pw_multi_aff(
+		__isl_keep isl_union_pw_multi_aff *upma);
+	isl_stat isl_union_pw_multi_aff_foreach_pw_multi_aff(
+		__isl_keep isl_union_pw_multi_aff *upma,
+		isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma,
+			    void *user), void *user);
+
+	#include <isl/polynomial.h>
+	int isl_union_pw_qpolynomial_n_pw_qpolynomial(
+		__isl_keep isl_union_pw_qpolynomial *upwqp);
+	isl_stat isl_union_pw_qpolynomial_foreach_pw_qpolynomial(
+		__isl_keep isl_union_pw_qpolynomial *upwqp,
+		isl_stat (*fn)(__isl_take isl_pw_qpolynomial *pwqp,
+			    void *user), void *user);
+	int isl_union_pw_qpolynomial_fold_n_pw_qpolynomial_fold(
+		__isl_keep isl_union_pw_qpolynomial_fold *upwf);
+	isl_stat isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(
+		__isl_keep isl_union_pw_qpolynomial_fold *upwf,
+		isl_stat (*fn)(__isl_take isl_pw_qpolynomial_fold *pwf,
+			    void *user), void *user);
+
+To extract the base expression in a given space from a union, use
+the following functions.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_union_pw_aff_extract_pw_aff(
+		__isl_keep isl_union_pw_aff *upa,
+		__isl_take isl_space *space);
+	__isl_give isl_pw_multi_aff *
+	isl_union_pw_multi_aff_extract_pw_multi_aff(
+		__isl_keep isl_union_pw_multi_aff *upma,
+		__isl_take isl_space *space);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial *
+	isl_union_pw_qpolynomial_extract_pw_qpolynomial(
+		__isl_keep isl_union_pw_qpolynomial *upwqp,
+		__isl_take isl_space *space);
+
+=head2 Input and Output
+
+For set and relation,
+C<isl> supports its own input/output format, which is similar
+to the C<Omega> format, but also supports the C<PolyLib> format
+in some cases.
+For other object types, typically only an C<isl> format is supported.
+
+=head3 C<isl> format
+
+The C<isl> format is similar to that of C<Omega>, but has a different
+syntax for describing the parameters and allows for the definition
+of an existentially quantified variable as the integer division
+of an affine expression.
+For example, the set of integers C<i> between C<0> and C<n>
+such that C<i % 10 <= 6> can be described as
+
+	[n] -> { [i] : exists (a = [i/10] : 0 <= i and i <= n and
+				i - 10 a <= 6) }
+
+A set or relation can have several disjuncts, separated
+by the keyword C<or>.  Each disjunct is either a conjunction
+of constraints or a projection (C<exists>) of a conjunction
+of constraints.  The constraints are separated by the keyword
+C<and>.
+
+=head3 C<PolyLib> format
+
+If the represented set is a union, then the first line
+contains a single number representing the number of disjuncts.
+Otherwise, a line containing the number C<1> is optional.
+
+Each disjunct is represented by a matrix of constraints.
+The first line contains two numbers representing
+the number of rows and columns,
+where the number of rows is equal to the number of constraints
+and the number of columns is equal to two plus the number of variables.
+The following lines contain the actual rows of the constraint matrix.
+In each row, the first column indicates whether the constraint
+is an equality (C<0>) or inequality (C<1>).  The final column
+corresponds to the constant term.
+
+If the set is parametric, then the coefficients of the parameters
+appear in the last columns before the constant column.
+The coefficients of any existentially quantified variables appear
+between those of the set variables and those of the parameters.
+
+=head3 Extended C<PolyLib> format
+
+The extended C<PolyLib> format is nearly identical to the
+C<PolyLib> format.  The only difference is that the line
+containing the number of rows and columns of a constraint matrix
+also contains four additional numbers:
+the number of output dimensions, the number of input dimensions,
+the number of local dimensions (i.e., the number of existentially
+quantified variables) and the number of parameters.
+For sets, the number of ``output'' dimensions is equal
+to the number of set dimensions, while the number of ``input''
+dimensions is zero.
+
+=head3 Input
+
+Objects can be read from input using the following functions.
+
+	#include <isl/val.h>
+	__isl_give isl_val *isl_val_read_from_str(isl_ctx *ctx,
+		const char *str);
+	__isl_give isl_multi_val *isl_multi_val_read_from_str(
+		isl_ctx *ctx, const char *str);
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_read_from_file(
+		isl_ctx *ctx, FILE *input);
+	__isl_give isl_basic_set *isl_basic_set_read_from_str(
+		isl_ctx *ctx, const char *str);
+	__isl_give isl_set *isl_set_read_from_file(isl_ctx *ctx,
+		FILE *input);
+	__isl_give isl_set *isl_set_read_from_str(isl_ctx *ctx,
+		const char *str);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_read_from_file(
+		isl_ctx *ctx, FILE *input);
+	__isl_give isl_basic_map *isl_basic_map_read_from_str(
+		isl_ctx *ctx, const char *str);
+	__isl_give isl_map *isl_map_read_from_file(
+		isl_ctx *ctx, FILE *input);
+	__isl_give isl_map *isl_map_read_from_str(isl_ctx *ctx,
+		const char *str);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_set *isl_union_set_read_from_file(
+		isl_ctx *ctx, FILE *input);
+	__isl_give isl_union_set *isl_union_set_read_from_str(
+		isl_ctx *ctx, const char *str);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_read_from_file(
+		isl_ctx *ctx, FILE *input);
+	__isl_give isl_union_map *isl_union_map_read_from_str(
+		isl_ctx *ctx, const char *str);
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_read_from_str(
+		isl_ctx *ctx, const char *str);
+	__isl_give isl_multi_aff *isl_multi_aff_read_from_str(
+		isl_ctx *ctx, const char *str);
+	__isl_give isl_pw_aff *isl_pw_aff_read_from_str(
+		isl_ctx *ctx, const char *str);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(
+		isl_ctx *ctx, const char *str);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(
+		isl_ctx *ctx, const char *str);
+	__isl_give isl_union_pw_aff *
+	isl_union_pw_aff_read_from_str(
+		isl_ctx *ctx, const char *str);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_read_from_str(
+		isl_ctx *ctx, const char *str);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_read_from_str(
+		isl_ctx *ctx, const char *str);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_read_from_str(
+		isl_ctx *ctx, const char *str);
+
+For sets and relations,
+the input format is autodetected and may be either the C<PolyLib> format
+or the C<isl> format.
+
+=head3 Output
+
+Before anything can be printed, an C<isl_printer> needs to
+be created.
+
+	__isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx,
+		FILE *file);
+	__isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx);
+	__isl_null isl_printer *isl_printer_free(
+		__isl_take isl_printer *printer);
+
+C<isl_printer_to_file> prints to the given file, while
+C<isl_printer_to_str> prints to a string that can be extracted
+using the following function.
+
+	#include <isl/printer.h>
+	__isl_give char *isl_printer_get_str(
+		__isl_keep isl_printer *printer);
+
+The printer can be inspected using the following functions.
+
+	FILE *isl_printer_get_file(
+		__isl_keep isl_printer *printer);
+	int isl_printer_get_output_format(
+		__isl_keep isl_printer *p);
+	int isl_printer_get_yaml_style(__isl_keep isl_printer *p);
+
+The behavior of the printer can be modified in various ways
+
+	__isl_give isl_printer *isl_printer_set_output_format(
+		__isl_take isl_printer *p, int output_format);
+	__isl_give isl_printer *isl_printer_set_indent(
+		__isl_take isl_printer *p, int indent);
+	__isl_give isl_printer *isl_printer_set_indent_prefix(
+		__isl_take isl_printer *p, const char *prefix);
+	__isl_give isl_printer *isl_printer_indent(
+		__isl_take isl_printer *p, int indent);
+	__isl_give isl_printer *isl_printer_set_prefix(
+		__isl_take isl_printer *p, const char *prefix);
+	__isl_give isl_printer *isl_printer_set_suffix(
+		__isl_take isl_printer *p, const char *suffix);
+	__isl_give isl_printer *isl_printer_set_yaml_style(
+		__isl_take isl_printer *p, int yaml_style);
+
+The C<output_format> may be either C<ISL_FORMAT_ISL>, C<ISL_FORMAT_OMEGA>,
+C<ISL_FORMAT_POLYLIB>, C<ISL_FORMAT_EXT_POLYLIB> or C<ISL_FORMAT_LATEX>
+and defaults to C<ISL_FORMAT_ISL>.
+Each line in the output is prefixed by C<indent_prefix>,
+indented by C<indent> (set by C<isl_printer_set_indent>) spaces
+(default: 0), prefixed by C<prefix> and suffixed by C<suffix>.
+In the C<PolyLib> format output,
+the coefficients of the existentially quantified variables
+appear between those of the set variables and those
+of the parameters.
+The function C<isl_printer_indent> increases the indentation
+by the specified amount (which may be negative).
+The YAML style may be either C<ISL_YAML_STYLE_BLOCK> or
+C<ISL_YAML_STYLE_FLOW> and when we are printing something
+in YAML format.
+
+To actually print something, use
+
+	#include <isl/printer.h>
+	__isl_give isl_printer *isl_printer_print_double(
+		__isl_take isl_printer *p, double d);
+
+	#include <isl/val.h>
+	__isl_give isl_printer *isl_printer_print_val(
+		__isl_take isl_printer *p, __isl_keep isl_val *v);
+
+	#include <isl/set.h>
+	__isl_give isl_printer *isl_printer_print_basic_set(
+		__isl_take isl_printer *printer,
+		__isl_keep isl_basic_set *bset);
+	__isl_give isl_printer *isl_printer_print_set(
+		__isl_take isl_printer *printer,
+		__isl_keep isl_set *set);
+
+	#include <isl/map.h>
+	__isl_give isl_printer *isl_printer_print_basic_map(
+		__isl_take isl_printer *printer,
+		__isl_keep isl_basic_map *bmap);
+	__isl_give isl_printer *isl_printer_print_map(
+		__isl_take isl_printer *printer,
+		__isl_keep isl_map *map);
+
+	#include <isl/union_set.h>
+	__isl_give isl_printer *isl_printer_print_union_set(
+		__isl_take isl_printer *p,
+		__isl_keep isl_union_set *uset);
+
+	#include <isl/union_map.h>
+	__isl_give isl_printer *isl_printer_print_union_map(
+		__isl_take isl_printer *p,
+		__isl_keep isl_union_map *umap);
+
+	#include <isl/val.h>
+	__isl_give isl_printer *isl_printer_print_multi_val(
+		__isl_take isl_printer *p,
+		__isl_keep isl_multi_val *mv);
+
+	#include <isl/aff.h>
+	__isl_give isl_printer *isl_printer_print_aff(
+		__isl_take isl_printer *p, __isl_keep isl_aff *aff);
+	__isl_give isl_printer *isl_printer_print_multi_aff(
+		__isl_take isl_printer *p,
+		__isl_keep isl_multi_aff *maff);
+	__isl_give isl_printer *isl_printer_print_pw_aff(
+		__isl_take isl_printer *p,
+		__isl_keep isl_pw_aff *pwaff);
+	__isl_give isl_printer *isl_printer_print_pw_multi_aff(
+		__isl_take isl_printer *p,
+		__isl_keep isl_pw_multi_aff *pma);
+	__isl_give isl_printer *isl_printer_print_multi_pw_aff(
+		__isl_take isl_printer *p,
+		__isl_keep isl_multi_pw_aff *mpa);
+	__isl_give isl_printer *isl_printer_print_union_pw_aff(
+		__isl_take isl_printer *p,
+		__isl_keep isl_union_pw_aff *upa);
+	__isl_give isl_printer *isl_printer_print_union_pw_multi_aff(
+		__isl_take isl_printer *p,
+		__isl_keep isl_union_pw_multi_aff *upma);
+	__isl_give isl_printer *
+	isl_printer_print_multi_union_pw_aff(
+		__isl_take isl_printer *p,
+		__isl_keep isl_multi_union_pw_aff *mupa);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_printer *isl_printer_print_qpolynomial(
+		__isl_take isl_printer *p,
+		__isl_keep isl_qpolynomial *qp);
+	__isl_give isl_printer *isl_printer_print_pw_qpolynomial(
+		__isl_take isl_printer *p,
+		__isl_keep isl_pw_qpolynomial *pwqp);
+	__isl_give isl_printer *isl_printer_print_union_pw_qpolynomial(
+		__isl_take isl_printer *p,
+		__isl_keep isl_union_pw_qpolynomial *upwqp);
+
+	__isl_give isl_printer *
+	isl_printer_print_pw_qpolynomial_fold(
+		__isl_take isl_printer *p,
+		__isl_keep isl_pw_qpolynomial_fold *pwf);
+	__isl_give isl_printer *
+	isl_printer_print_union_pw_qpolynomial_fold(
+		__isl_take isl_printer *p,
+		__isl_keep isl_union_pw_qpolynomial_fold *upwf);
+
+For C<isl_printer_print_qpolynomial>,
+C<isl_printer_print_pw_qpolynomial> and
+C<isl_printer_print_pw_qpolynomial_fold>,
+the output format of the printer
+needs to be set to either C<ISL_FORMAT_ISL> or C<ISL_FORMAT_C>.
+For C<isl_printer_print_union_pw_qpolynomial> and
+C<isl_printer_print_union_pw_qpolynomial_fold>, only C<ISL_FORMAT_ISL>
+is supported.
+In case of printing in C<ISL_FORMAT_C>, the user may want
+to set the names of all dimensions first.
+
+C<isl> also provides limited support for printing YAML documents,
+just enough for the internal use for printing such documents.
+
+	#include <isl/printer.h>
+	__isl_give isl_printer *isl_printer_yaml_start_mapping(
+		__isl_take isl_printer *p);
+	__isl_give isl_printer *isl_printer_yaml_end_mapping(
+		__isl_take isl_printer *p);
+	__isl_give isl_printer *isl_printer_yaml_start_sequence(
+		__isl_take isl_printer *p);
+	__isl_give isl_printer *isl_printer_yaml_end_sequence(
+		__isl_take isl_printer *p);
+	__isl_give isl_printer *isl_printer_yaml_next(
+		__isl_take isl_printer *p);
+
+A document is started by a call to either
+C<isl_printer_yaml_start_mapping> or C<isl_printer_yaml_start_sequence>.
+Anything printed to the printer after such a call belong to the
+first key of the mapping or the first element in the sequence.
+The function C<isl_printer_yaml_next> moves to the value if
+we are currently printing a mapping key, the next key if we
+are printing a value or the next element if we are printing
+an element in a sequence.
+Nested mappings and sequences are initiated by the same
+C<isl_printer_yaml_start_mapping> or C<isl_printer_yaml_start_sequence>.
+Each call to these functions needs to have a corresponding call to
+C<isl_printer_yaml_end_mapping> or C<isl_printer_yaml_end_sequence>.
+
+When called on a file printer, the following function flushes
+the file.  When called on a string printer, the buffer is cleared.
+
+	__isl_give isl_printer *isl_printer_flush(
+		__isl_take isl_printer *p);
+
+The following functions allow the user to attach
+notes to a printer in order to keep track of additional state.
+
+	#include <isl/printer.h>
+	isl_bool isl_printer_has_note(__isl_keep isl_printer *p,
+		__isl_keep isl_id *id);
+	__isl_give isl_id *isl_printer_get_note(
+		__isl_keep isl_printer *p, __isl_take isl_id *id);
+	__isl_give isl_printer *isl_printer_set_note(
+		__isl_take isl_printer *p,
+		__isl_take isl_id *id, __isl_take isl_id *note);
+
+C<isl_printer_set_note> associates the given note to the given
+identifier in the printer.
+C<isl_printer_get_note> retrieves a note associated to an
+identifier, while
+C<isl_printer_has_note> checks if there is such a note.
+C<isl_printer_get_note> fails if the requested note does not exist.
+
+Alternatively, a string representation can be obtained
+directly using the following functions, which always print
+in isl format.
+
+	#include <isl/id.h>
+	__isl_give char *isl_id_to_str(
+		__isl_keep isl_id *id);
+
+	#include <isl/space.h>
+	__isl_give char *isl_space_to_str(
+		__isl_keep isl_space *space);
+
+	#include <isl/val.h>
+	__isl_give char *isl_val_to_str(__isl_keep isl_val *v);
+	__isl_give char *isl_multi_val_to_str(
+		__isl_keep isl_multi_val *mv);
+
+	#include <isl/set.h>
+	__isl_give char *isl_basic_set_to_str(
+		__isl_keep isl_basic_set *bset);
+	__isl_give char *isl_set_to_str(
+		__isl_keep isl_set *set);
+
+	#include <isl/union_set.h>
+	__isl_give char *isl_union_set_to_str(
+		__isl_keep isl_union_set *uset);
+
+	#include <isl/map.h>
+	__isl_give char *isl_basic_map_to_str(
+		__isl_keep isl_basic_map *bmap);
+	__isl_give char *isl_map_to_str(
+		__isl_keep isl_map *map);
+
+	#include <isl/union_map.h>
+	__isl_give char *isl_union_map_to_str(
+		__isl_keep isl_union_map *umap);
+
+	#include <isl/aff.h>
+	__isl_give char *isl_aff_to_str(__isl_keep isl_aff *aff);
+	__isl_give char *isl_pw_aff_to_str(
+		__isl_keep isl_pw_aff *pa);
+	__isl_give char *isl_multi_aff_to_str(
+		__isl_keep isl_multi_aff *ma);
+	__isl_give char *isl_pw_multi_aff_to_str(
+		__isl_keep isl_pw_multi_aff *pma);
+	__isl_give char *isl_multi_pw_aff_to_str(
+		__isl_keep isl_multi_pw_aff *mpa);
+	__isl_give char *isl_union_pw_aff_to_str(
+		__isl_keep isl_union_pw_aff *upa);
+	__isl_give char *isl_union_pw_multi_aff_to_str(
+		__isl_keep isl_union_pw_multi_aff *upma);
+	__isl_give char *isl_multi_union_pw_aff_to_str(
+		__isl_keep isl_multi_union_pw_aff *mupa);
+
+	#include <isl/point.h>
+	__isl_give char *isl_point_to_str(
+		__isl_keep isl_point *pnt);
+
+	#include <isl/polynomial.h>
+	__isl_give char *isl_pw_qpolynomial_to_str(
+		__isl_keep isl_pw_qpolynomial *pwqp);
+	__isl_give char *isl_union_pw_qpolynomial_to_str(
+		__isl_keep isl_union_pw_qpolynomial *upwqp);
+
+=head2 Properties
+
+=head3 Unary Properties
+
+=over
+
+=item * Emptiness
+
+The following functions test whether the given set or relation
+contains any integer points.  The ``plain'' variants do not perform
+any computations, but simply check if the given set or relation
+is already known to be empty.
+
+	isl_bool isl_basic_set_plain_is_empty(
+		__isl_keep isl_basic_set *bset);
+	isl_bool isl_basic_set_is_empty(
+		__isl_keep isl_basic_set *bset);
+	isl_bool isl_set_plain_is_empty(
+		__isl_keep isl_set *set);
+	isl_bool isl_set_is_empty(__isl_keep isl_set *set);
+	isl_bool isl_union_set_is_empty(
+		__isl_keep isl_union_set *uset);
+	isl_bool isl_basic_map_plain_is_empty(
+		__isl_keep isl_basic_map *bmap);
+	isl_bool isl_basic_map_is_empty(
+		__isl_keep isl_basic_map *bmap);
+	isl_bool isl_map_plain_is_empty(
+		__isl_keep isl_map *map);
+	isl_bool isl_map_is_empty(__isl_keep isl_map *map);
+	isl_bool isl_union_map_is_empty(
+		__isl_keep isl_union_map *umap);
+
+=item * Universality
+
+	isl_bool isl_basic_set_plain_is_universe(
+		__isl_keep isl_basic_set *bset);
+	isl_bool isl_basic_set_is_universe(
+		__isl_keep isl_basic_set *bset);
+	isl_bool isl_basic_map_plain_is_universe(
+		__isl_keep isl_basic_map *bmap);
+	isl_bool isl_basic_map_is_universe(
+		__isl_keep isl_basic_map *bmap);
+	isl_bool isl_set_plain_is_universe(
+		__isl_keep isl_set *set);
+	isl_bool isl_map_plain_is_universe(
+		__isl_keep isl_map *map);
+
+=item * Single-valuedness
+
+	#include <isl/set.h>
+	isl_bool isl_set_is_singleton(__isl_keep isl_set *set);
+
+	#include <isl/map.h>
+	isl_bool isl_basic_map_is_single_valued(
+		__isl_keep isl_basic_map *bmap);
+	isl_bool isl_map_plain_is_single_valued(
+		__isl_keep isl_map *map);
+	isl_bool isl_map_is_single_valued(__isl_keep isl_map *map);
+
+	#include <isl/union_map.h>
+	isl_bool isl_union_map_is_single_valued(
+		__isl_keep isl_union_map *umap);
+
+=item * Injectivity
+
+	isl_bool isl_map_plain_is_injective(
+		__isl_keep isl_map *map);
+	isl_bool isl_map_is_injective(
+		__isl_keep isl_map *map);
+	isl_bool isl_union_map_plain_is_injective(
+		__isl_keep isl_union_map *umap);
+	isl_bool isl_union_map_is_injective(
+		__isl_keep isl_union_map *umap);
+
+=item * Bijectivity
+
+	isl_bool isl_map_is_bijective(
+		__isl_keep isl_map *map);
+	isl_bool isl_union_map_is_bijective(
+		__isl_keep isl_union_map *umap);
+
+=item * Identity
+
+The following functions test whether the given relation
+only maps elements to themselves.
+
+	#include <isl/map.h>
+	isl_bool isl_map_is_identity(
+		__isl_keep isl_map *map);
+
+	#include <isl/union_map.h>
+	isl_bool isl_union_map_is_identity(
+		__isl_keep isl_union_map *umap);
+
+=item * Position
+
+	__isl_give isl_val *
+	isl_basic_map_plain_get_val_if_fixed(
+		__isl_keep isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_val *isl_set_plain_get_val_if_fixed(
+		__isl_keep isl_set *set,
+		enum isl_dim_type type, unsigned pos);
+	__isl_give isl_val *isl_map_plain_get_val_if_fixed(
+		__isl_keep isl_map *map,
+		enum isl_dim_type type, unsigned pos);
+
+If the set or relation obviously lies on a hyperplane where the given dimension
+has a fixed value, then return that value.
+Otherwise return NaN.
+
+=item * Stride
+
+	isl_stat isl_set_dim_residue_class_val(
+		__isl_keep isl_set *set,
+		int pos, __isl_give isl_val **modulo,
+		__isl_give isl_val **residue);
+
+Check if the values of the given set dimension are equal to a fixed
+value modulo some integer value.  If so, assign the modulo to C<*modulo>
+and the fixed value to C<*residue>.  If the given dimension attains only
+a single value, then assign C<0> to C<*modulo> and the fixed value to
+C<*residue>.
+If the dimension does not attain only a single value and if no modulo
+can be found then assign C<1> to C<*modulo> and C<1> to C<*residue>.
+
+=item * Dependence
+
+To check whether the description of a set, relation or function depends
+on one or more given dimensions,
+the following functions can be used.
+
+	#include <isl/constraint.h>
+	isl_bool isl_constraint_involves_dims(
+		__isl_keep isl_constraint *constraint,
+		enum isl_dim_type type, unsigned first, unsigned n);
+
+	#include <isl/set.h>
+	isl_bool isl_basic_set_involves_dims(
+		__isl_keep isl_basic_set *bset,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	isl_bool isl_set_involves_dims(__isl_keep isl_set *set,
+		enum isl_dim_type type, unsigned first, unsigned n);
+
+	#include <isl/map.h>
+	isl_bool isl_basic_map_involves_dims(
+		__isl_keep isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	isl_bool isl_map_involves_dims(__isl_keep isl_map *map,
+		enum isl_dim_type type, unsigned first, unsigned n);
+
+	#include <isl/union_map.h>
+	isl_bool isl_union_map_involves_dims(
+		__isl_keep isl_union_map *umap,
+		enum isl_dim_type type, unsigned first, unsigned n);
+
+	#include <isl/aff.h>
+	isl_bool isl_aff_involves_dims(__isl_keep isl_aff *aff,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	isl_bool isl_pw_aff_involves_dims(
+		__isl_keep isl_pw_aff *pwaff,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	isl_bool isl_multi_aff_involves_dims(
+		__isl_keep isl_multi_aff *ma,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	isl_bool isl_multi_pw_aff_involves_dims(
+		__isl_keep isl_multi_pw_aff *mpa,
+		enum isl_dim_type type, unsigned first, unsigned n);
+
+	#include <isl/polynomial.h>
+	isl_bool isl_qpolynomial_involves_dims(
+		__isl_keep isl_qpolynomial *qp,
+		enum isl_dim_type type, unsigned first, unsigned n);
+
+Similarly, the following functions can be used to check whether
+a given dimension is involved in any lower or upper bound.
+
+	#include <isl/set.h>
+	isl_bool isl_set_dim_has_any_lower_bound(
+		__isl_keep isl_set *set,
+		enum isl_dim_type type, unsigned pos);
+	isl_bool isl_set_dim_has_any_upper_bound(
+		__isl_keep isl_set *set,
+		enum isl_dim_type type, unsigned pos);
+
+Note that these functions return true even if there is a bound on
+the dimension on only some of the basic sets of C<set>.
+To check if they have a bound for all of the basic sets in C<set>,
+use the following functions instead.
+
+	#include <isl/set.h>
+	isl_bool isl_set_dim_has_lower_bound(
+		__isl_keep isl_set *set,
+		enum isl_dim_type type, unsigned pos);
+	isl_bool isl_set_dim_has_upper_bound(
+		__isl_keep isl_set *set,
+		enum isl_dim_type type, unsigned pos);
+
+=item * Space
+
+To check whether a set is a parameter domain, use this function:
+
+	isl_bool isl_set_is_params(__isl_keep isl_set *set);
+	isl_bool isl_union_set_is_params(
+		__isl_keep isl_union_set *uset);
+
+=item * Wrapping
+
+The following functions check whether the space of the given
+(basic) set or relation domain and/or range is a wrapped relation.
+
+	#include <isl/space.h>
+	isl_bool isl_space_is_wrapping(
+		__isl_keep isl_space *space);
+	isl_bool isl_space_domain_is_wrapping(
+		__isl_keep isl_space *space);
+	isl_bool isl_space_range_is_wrapping(
+		__isl_keep isl_space *space);
+	isl_bool isl_space_is_product(
+		__isl_keep isl_space *space);
+
+	#include <isl/set.h>
+	isl_bool isl_basic_set_is_wrapping(
+		__isl_keep isl_basic_set *bset);
+	isl_bool isl_set_is_wrapping(__isl_keep isl_set *set);
+
+	#include <isl/map.h>
+	isl_bool isl_map_domain_is_wrapping(
+		__isl_keep isl_map *map);
+	isl_bool isl_map_range_is_wrapping(
+		__isl_keep isl_map *map);
+	isl_bool isl_map_is_product(__isl_keep isl_map *map);
+
+	#include <isl/val.h>
+	isl_bool isl_multi_val_range_is_wrapping(
+		__isl_keep isl_multi_val *mv);
+
+	#include <isl/aff.h>
+	isl_bool isl_multi_aff_range_is_wrapping(
+		__isl_keep isl_multi_aff *ma);
+	isl_bool isl_multi_pw_aff_range_is_wrapping(
+		__isl_keep isl_multi_pw_aff *mpa);
+	isl_bool isl_multi_union_pw_aff_range_is_wrapping(
+		__isl_keep isl_multi_union_pw_aff *mupa);
+
+The input to C<isl_space_is_wrapping> should
+be the space of a set, while that of
+C<isl_space_domain_is_wrapping> and
+C<isl_space_range_is_wrapping> should be the space of a relation.
+The input to C<isl_space_is_product> can be either the space
+of a set or that of a binary relation.
+In case the input is the space of a binary relation, it checks
+whether both domain and range are wrapping.
+
+=item * Internal Product
+
+	isl_bool isl_basic_map_can_zip(
+		__isl_keep isl_basic_map *bmap);
+	isl_bool isl_map_can_zip(__isl_keep isl_map *map);
+
+Check whether the product of domain and range of the given relation
+can be computed,
+i.e., whether both domain and range are nested relations.
+
+=item * Currying
+
+	#include <isl/space.h>
+	isl_bool isl_space_can_curry(
+		__isl_keep isl_space *space);
+
+	#include <isl/map.h>
+	isl_bool isl_basic_map_can_curry(
+		__isl_keep isl_basic_map *bmap);
+	isl_bool isl_map_can_curry(__isl_keep isl_map *map);
+
+Check whether the domain of the (basic) relation is a wrapped relation.
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_uncurry(
+		__isl_take isl_space *space);
+
+	#include <isl/map.h>
+	isl_bool isl_basic_map_can_uncurry(
+		__isl_keep isl_basic_map *bmap);
+	isl_bool isl_map_can_uncurry(__isl_keep isl_map *map);
+
+Check whether the range of the (basic) relation is a wrapped relation.
+
+	#include <isl/space.h>
+	isl_bool isl_space_can_range_curry(
+		__isl_keep isl_space *space);
+
+	#include <isl/map.h>
+	isl_bool isl_map_can_range_curry(
+		__isl_keep isl_map *map);
+
+Check whether the domain of the relation wrapped in the range of
+the input is itself a wrapped relation.
+
+=item * Special Values
+
+	#include <isl/aff.h>
+	isl_bool isl_aff_is_cst(__isl_keep isl_aff *aff);
+	isl_bool isl_pw_aff_is_cst(__isl_keep isl_pw_aff *pwaff);
+	isl_bool isl_multi_pw_aff_is_cst(
+		__isl_keep isl_multi_pw_aff *mpa);
+
+Check whether the given expression is a constant.
+
+	#include <isl/val.h>
+	isl_bool isl_multi_val_involves_nan(
+		__isl_keep isl_multi_val *mv);
+
+	#include <isl/aff.h>
+	isl_bool isl_aff_is_nan(__isl_keep isl_aff *aff);
+	isl_bool isl_multi_aff_involves_nan(
+		__isl_keep isl_multi_aff *ma);
+	isl_bool isl_pw_aff_involves_nan(
+		__isl_keep isl_pw_aff *pa);
+	isl_bool isl_pw_multi_aff_involves_nan(
+		__isl_keep isl_pw_multi_aff *pma);
+	isl_bool isl_multi_pw_aff_involves_nan(
+		__isl_keep isl_multi_pw_aff *mpa);
+	isl_bool isl_union_pw_aff_involves_nan(
+		__isl_keep isl_union_pw_aff *upa);
+	isl_bool isl_union_pw_multi_aff_involves_nan(
+		__isl_keep isl_union_pw_multi_aff *upma);
+	isl_bool isl_multi_union_pw_aff_involves_nan(
+		__isl_keep isl_multi_union_pw_aff *mupa);
+
+	#include <isl/polynomial.h>
+	isl_bool isl_qpolynomial_is_nan(
+		__isl_keep isl_qpolynomial *qp);
+	isl_bool isl_qpolynomial_fold_is_nan(
+		__isl_keep isl_qpolynomial_fold *fold);
+	isl_bool isl_pw_qpolynomial_involves_nan(
+		__isl_keep isl_pw_qpolynomial *pwqp);
+	isl_bool isl_pw_qpolynomial_fold_involves_nan(
+		__isl_keep isl_pw_qpolynomial_fold *pwf);
+	isl_bool isl_union_pw_qpolynomial_involves_nan(
+		__isl_keep isl_union_pw_qpolynomial *upwqp);
+	isl_bool isl_union_pw_qpolynomial_fold_involves_nan(
+		__isl_keep isl_union_pw_qpolynomial_fold *upwf);
+
+Check whether the given expression is equal to or involves NaN.
+
+	#include <isl/aff.h>
+	isl_bool isl_aff_plain_is_zero(
+		__isl_keep isl_aff *aff);
+
+Check whether the affine expression is obviously zero.
+
+=back
+
+=head3 Binary Properties
+
+=over
+
+=item * Equality
+
+The following functions check whether two objects
+represent the same set, relation or function.
+The C<plain> variants only return true if the objects
+are obviously the same.  That is, they may return false
+even if the objects are the same, but they will never
+return true if the objects are not the same.
+
+	#include <isl/set.h>
+	isl_bool isl_basic_set_plain_is_equal(
+		__isl_keep isl_basic_set *bset1,
+		__isl_keep isl_basic_set *bset2);
+	isl_bool isl_basic_set_is_equal(
+		__isl_keep isl_basic_set *bset1,
+		__isl_keep isl_basic_set *bset2);
+	isl_bool isl_set_plain_is_equal(
+		__isl_keep isl_set *set1,
+		__isl_keep isl_set *set2);
+	isl_bool isl_set_is_equal(__isl_keep isl_set *set1,
+		__isl_keep isl_set *set2);
+
+	#include <isl/map.h>
+	isl_bool isl_basic_map_is_equal(
+		__isl_keep isl_basic_map *bmap1,
+		__isl_keep isl_basic_map *bmap2);
+	isl_bool isl_map_is_equal(__isl_keep isl_map *map1,
+		__isl_keep isl_map *map2);
+	isl_bool isl_map_plain_is_equal(
+		__isl_keep isl_map *map1,
+		__isl_keep isl_map *map2);
+
+	#include <isl/union_set.h>
+	isl_bool isl_union_set_is_equal(
+		__isl_keep isl_union_set *uset1,
+		__isl_keep isl_union_set *uset2);
+
+	#include <isl/union_map.h>
+	isl_bool isl_union_map_is_equal(
+		__isl_keep isl_union_map *umap1,
+		__isl_keep isl_union_map *umap2);
+
+	#include <isl/aff.h>
+	isl_bool isl_aff_plain_is_equal(
+		__isl_keep isl_aff *aff1,
+		__isl_keep isl_aff *aff2);
+	isl_bool isl_multi_aff_plain_is_equal(
+		__isl_keep isl_multi_aff *maff1,
+		__isl_keep isl_multi_aff *maff2);
+	isl_bool isl_pw_aff_plain_is_equal(
+		__isl_keep isl_pw_aff *pwaff1,
+		__isl_keep isl_pw_aff *pwaff2);
+	isl_bool isl_pw_aff_is_equal(
+		__isl_keep isl_pw_aff *pa1,
+		__isl_keep isl_pw_aff *pa2);
+	isl_bool isl_pw_multi_aff_plain_is_equal(
+		__isl_keep isl_pw_multi_aff *pma1,
+		__isl_keep isl_pw_multi_aff *pma2);
+	isl_bool isl_pw_multi_aff_is_equal(
+		__isl_keep isl_pw_multi_aff *pma1,
+		__isl_keep isl_pw_multi_aff *pma2);
+	isl_bool isl_multi_pw_aff_plain_is_equal(
+		__isl_keep isl_multi_pw_aff *mpa1,
+		__isl_keep isl_multi_pw_aff *mpa2);
+	isl_bool isl_multi_pw_aff_is_equal(
+		__isl_keep isl_multi_pw_aff *mpa1,
+		__isl_keep isl_multi_pw_aff *mpa2);
+	isl_bool isl_union_pw_aff_plain_is_equal(
+		__isl_keep isl_union_pw_aff *upa1,
+		__isl_keep isl_union_pw_aff *upa2);
+	isl_bool isl_union_pw_multi_aff_plain_is_equal(
+		__isl_keep isl_union_pw_multi_aff *upma1,
+		__isl_keep isl_union_pw_multi_aff *upma2);
+	isl_bool isl_multi_union_pw_aff_plain_is_equal(
+		__isl_keep isl_multi_union_pw_aff *mupa1,
+		__isl_keep isl_multi_union_pw_aff *mupa2);
+
+	#include <isl/polynomial.h>
+	isl_bool isl_union_pw_qpolynomial_plain_is_equal(
+		__isl_keep isl_union_pw_qpolynomial *upwqp1,
+		__isl_keep isl_union_pw_qpolynomial *upwqp2);
+	isl_bool isl_union_pw_qpolynomial_fold_plain_is_equal(
+		__isl_keep isl_union_pw_qpolynomial_fold *upwf1,
+		__isl_keep isl_union_pw_qpolynomial_fold *upwf2);
+
+=item * Disjointness
+
+	#include <isl/set.h>
+	isl_bool isl_basic_set_is_disjoint(
+		__isl_keep isl_basic_set *bset1,
+		__isl_keep isl_basic_set *bset2);
+	isl_bool isl_set_plain_is_disjoint(
+		__isl_keep isl_set *set1,
+		__isl_keep isl_set *set2);
+	isl_bool isl_set_is_disjoint(__isl_keep isl_set *set1,
+		__isl_keep isl_set *set2);
+
+	#include <isl/map.h>
+	isl_bool isl_basic_map_is_disjoint(
+		__isl_keep isl_basic_map *bmap1,
+		__isl_keep isl_basic_map *bmap2);
+	isl_bool isl_map_is_disjoint(__isl_keep isl_map *map1,
+		__isl_keep isl_map *map2);
+
+	#include <isl/union_set.h>
+	isl_bool isl_union_set_is_disjoint(
+		__isl_keep isl_union_set *uset1,
+		__isl_keep isl_union_set *uset2);
+
+	#include <isl/union_map.h>
+	isl_bool isl_union_map_is_disjoint(
+		__isl_keep isl_union_map *umap1,
+		__isl_keep isl_union_map *umap2);
+
+=item * Subset
+
+	isl_bool isl_basic_set_is_subset(
+		__isl_keep isl_basic_set *bset1,
+		__isl_keep isl_basic_set *bset2);
+	isl_bool isl_set_is_subset(__isl_keep isl_set *set1,
+		__isl_keep isl_set *set2);
+	isl_bool isl_set_is_strict_subset(
+		__isl_keep isl_set *set1,
+		__isl_keep isl_set *set2);
+	isl_bool isl_union_set_is_subset(
+		__isl_keep isl_union_set *uset1,
+		__isl_keep isl_union_set *uset2);
+	isl_bool isl_union_set_is_strict_subset(
+		__isl_keep isl_union_set *uset1,
+		__isl_keep isl_union_set *uset2);
+	isl_bool isl_basic_map_is_subset(
+		__isl_keep isl_basic_map *bmap1,
+		__isl_keep isl_basic_map *bmap2);
+	isl_bool isl_basic_map_is_strict_subset(
+		__isl_keep isl_basic_map *bmap1,
+		__isl_keep isl_basic_map *bmap2);
+	isl_bool isl_map_is_subset(
+		__isl_keep isl_map *map1,
+		__isl_keep isl_map *map2);
+	isl_bool isl_map_is_strict_subset(
+		__isl_keep isl_map *map1,
+		__isl_keep isl_map *map2);
+	isl_bool isl_union_map_is_subset(
+		__isl_keep isl_union_map *umap1,
+		__isl_keep isl_union_map *umap2);
+	isl_bool isl_union_map_is_strict_subset(
+		__isl_keep isl_union_map *umap1,
+		__isl_keep isl_union_map *umap2);
+
+Check whether the first argument is a (strict) subset of the
+second argument.
+
+=item * Order
+
+Every comparison function returns a negative value if the first
+argument is considered smaller than the second, a positive value
+if the first argument is considered greater and zero if the two
+constraints are considered the same by the comparison criterion.
+
+	#include <isl/constraint.h>
+	int isl_constraint_plain_cmp(
+		__isl_keep isl_constraint *c1,
+		__isl_keep isl_constraint *c2);
+
+This function is useful for sorting C<isl_constraint>s.
+The order depends on the internal representation of the inputs.
+The order is fixed over different calls to the function (assuming
+the internal representation of the inputs has not changed), but may
+change over different versions of C<isl>.
+
+	#include <isl/constraint.h>
+	int isl_constraint_cmp_last_non_zero(
+		__isl_keep isl_constraint *c1,
+		__isl_keep isl_constraint *c2);
+
+This function can be used to sort constraints that live in the same
+local space.  Constraints that involve ``earlier'' dimensions or
+that have a smaller coefficient for the shared latest dimension
+are considered smaller than other constraints.
+This function only defines a B<partial> order.
+
+	#include <isl/set.h>
+	int isl_set_plain_cmp(__isl_keep isl_set *set1,
+		__isl_keep isl_set *set2);
+
+This function is useful for sorting C<isl_set>s.
+The order depends on the internal representation of the inputs.
+The order is fixed over different calls to the function (assuming
+the internal representation of the inputs has not changed), but may
+change over different versions of C<isl>.
+
+	#include <isl/aff.h>
+	int isl_multi_aff_plain_cmp(
+		__isl_keep isl_multi_aff *ma1,
+		__isl_keep isl_multi_aff *ma2);
+	int isl_pw_aff_plain_cmp(__isl_keep isl_pw_aff *pa1,
+		__isl_keep isl_pw_aff *pa2);
+
+The functions C<isl_multi_aff_plain_cmp> and
+C<isl_pw_aff_plain_cmp> can be used to sort C<isl_multi_aff>s and
+C<isl_pw_aff>s.  The order is not strictly defined.
+The current order sorts expressions that only involve
+earlier dimensions before those that involve later dimensions.
+
+=back
+
+=head2 Unary Operations
+
+=over
+
+=item * Complement
+
+	__isl_give isl_set *isl_set_complement(
+		__isl_take isl_set *set);
+	__isl_give isl_map *isl_map_complement(
+		__isl_take isl_map *map);
+
+=item * Inverse map
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_reverse(
+		__isl_take isl_space *space);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_reverse(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_map *isl_map_reverse(
+		__isl_take isl_map *map);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_reverse(
+		__isl_take isl_union_map *umap);
+
+=item * Projection
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_domain(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_range(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_params(
+		__isl_take isl_space *space);
+
+	#include <isl/local_space.h>
+	__isl_give isl_local_space *isl_local_space_domain(
+		__isl_take isl_local_space *ls);
+	__isl_give isl_local_space *isl_local_space_range(
+		__isl_take isl_local_space *ls);
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_project_out(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_set *isl_set_project_out(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_map *isl_set_project_onto_map(
+		__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned first,
+		unsigned n);
+	__isl_give isl_basic_set *isl_basic_set_params(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_set *isl_set_params(__isl_take isl_set *set);
+
+The function C<isl_set_project_onto_map> returns a relation
+that projects the input set onto the given set dimensions.
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_project_out(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_map *isl_map_project_out(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_basic_set *isl_basic_map_domain(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_basic_set *isl_basic_map_range(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_set *isl_map_params(__isl_take isl_map *map);
+	__isl_give isl_set *isl_map_domain(
+		__isl_take isl_map *bmap);
+	__isl_give isl_set *isl_map_range(
+		__isl_take isl_map *map);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_set *isl_union_set_project_out(
+		__isl_take isl_union_set *uset,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_set *isl_union_set_params(
+		__isl_take isl_union_set *uset);
+
+The function C<isl_union_set_project_out> can only project out
+parameters.
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_project_out(
+		__isl_take isl_union_map *umap,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_set *isl_union_map_params(
+		__isl_take isl_union_map *umap);
+	__isl_give isl_union_set *isl_union_map_domain(
+		__isl_take isl_union_map *umap);
+	__isl_give isl_union_set *isl_union_map_range(
+		__isl_take isl_union_map *umap);
+
+The function C<isl_union_map_project_out> can only project out
+parameters.
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_project_domain_on_params(
+		__isl_take isl_aff *aff);
+	__isl_give isl_pw_aff *
+	isl_pw_aff_project_domain_on_params(
+		__isl_take isl_pw_aff *pa);
+	__isl_give isl_pw_multi_aff *
+	isl_pw_multi_aff_project_domain_on_params(
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_set *isl_pw_aff_domain(
+		__isl_take isl_pw_aff *pwaff);
+	__isl_give isl_set *isl_pw_multi_aff_domain(
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_set *isl_multi_pw_aff_domain(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_union_set *isl_union_pw_aff_domain(
+		__isl_take isl_union_pw_aff *upa);
+	__isl_give isl_union_set *isl_union_pw_multi_aff_domain(
+		__isl_take isl_union_pw_multi_aff *upma);
+	__isl_give isl_union_set *
+	isl_multi_union_pw_aff_domain(
+		__isl_take isl_multi_union_pw_aff *mupa);
+	__isl_give isl_set *isl_pw_aff_params(
+		__isl_take isl_pw_aff *pwa);
+
+The function C<isl_multi_union_pw_aff_domain> requires its
+input to have at least one set dimension.
+
+	#include <isl/polynomial.h>
+	__isl_give isl_qpolynomial *
+	isl_qpolynomial_project_domain_on_params(
+		__isl_take isl_qpolynomial *qp);
+	__isl_give isl_pw_qpolynomial *
+	isl_pw_qpolynomial_project_domain_on_params(
+		__isl_take isl_pw_qpolynomial *pwqp);
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_project_domain_on_params(
+		__isl_take isl_pw_qpolynomial_fold *pwf);
+	__isl_give isl_set *isl_pw_qpolynomial_domain(
+		__isl_take isl_pw_qpolynomial *pwqp);
+	__isl_give isl_union_set *isl_union_pw_qpolynomial_fold_domain(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf);
+	__isl_give isl_union_set *isl_union_pw_qpolynomial_domain(
+		__isl_take isl_union_pw_qpolynomial *upwqp);
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_domain_map(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_range_map(
+		__isl_take isl_space *space);
+
+	#include <isl/map.h>
+	__isl_give isl_map *isl_set_wrapped_domain_map(
+		__isl_take isl_set *set);
+	__isl_give isl_basic_map *isl_basic_map_domain_map(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_basic_map *isl_basic_map_range_map(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_map *isl_map_domain_map(__isl_take isl_map *map);
+	__isl_give isl_map *isl_map_range_map(__isl_take isl_map *map);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_domain_map(
+		__isl_take isl_union_map *umap);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_map_domain_map_union_pw_multi_aff(
+		__isl_take isl_union_map *umap);
+	__isl_give isl_union_map *isl_union_map_range_map(
+		__isl_take isl_union_map *umap);
+	__isl_give isl_union_map *
+	isl_union_set_wrapped_domain_map(
+		__isl_take isl_union_set *uset);
+
+The functions above construct a (basic, regular or union) relation
+that maps (a wrapped version of) the input relation to its domain or range.
+C<isl_set_wrapped_domain_map> maps the input set to the domain
+of its wrapped relation.
+
+=item * Elimination
+
+	__isl_give isl_basic_set *isl_basic_set_eliminate(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_set *isl_set_eliminate(
+		__isl_take isl_set *set, enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_basic_map *isl_basic_map_eliminate(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_map *isl_map_eliminate(
+		__isl_take isl_map *map, enum isl_dim_type type,
+		unsigned first, unsigned n);
+
+Eliminate the coefficients for the given dimensions from the constraints,
+without removing the dimensions.
+
+=item * Constructing a set from a parameter domain
+
+A zero-dimensional space or (basic) set can be constructed
+on a given parameter domain using the following functions.
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_set_from_params(
+		__isl_take isl_space *space);
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_from_params(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_set *isl_set_from_params(
+		__isl_take isl_set *set);
+
+=item * Constructing a relation from one or two sets
+
+Create a relation with the given set(s) as domain and/or range.
+If only the domain or the range is specified, then
+the range or domain of the created relation is a zero-dimensional
+flat anonymous space.
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_from_domain(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_from_range(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_map_from_set(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_map_from_domain_and_range(
+		__isl_take isl_space *domain,
+		__isl_take isl_space *range);
+
+	#include <isl/local_space.h>
+	__isl_give isl_local_space *isl_local_space_from_domain(
+		__isl_take isl_local_space *ls);
+
+	#include <isl/map.h>
+	__isl_give isl_map *isl_map_from_domain(
+		__isl_take isl_set *set);
+	__isl_give isl_map *isl_map_from_range(
+		__isl_take isl_set *set);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *
+	isl_union_map_from_domain_and_range(
+		__isl_take isl_union_set *domain,
+		__isl_take isl_union_set *range);
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_from_range(
+		__isl_take isl_multi_val *mv);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_from_range(
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_pw_aff *isl_pw_aff_from_range(
+		__isl_take isl_pw_aff *pwa);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_range(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_from_range(
+		__isl_take isl_multi_union_pw_aff *mupa);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_domain(
+		__isl_take isl_set *set);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_from_domain(
+		__isl_take isl_union_set *uset);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial *
+	isl_pw_qpolynomial_from_range(
+		__isl_take isl_pw_qpolynomial *pwqp);
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_from_range(
+		__isl_take isl_pw_qpolynomial_fold *pwf);
+
+=item * Slicing
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_fix_si(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos, int value);
+	__isl_give isl_basic_set *isl_basic_set_fix_val(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_val *v);
+	__isl_give isl_set *isl_set_fix_si(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, int value);
+	__isl_give isl_set *isl_set_fix_val(
+		__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_val *v);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_fix_si(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos, int value);
+	__isl_give isl_basic_map *isl_basic_map_fix_val(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_val *v);
+	__isl_give isl_map *isl_map_fix_si(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, int value);
+	__isl_give isl_map *isl_map_fix_val(
+		__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_val *v);
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_fix_si(
+		__isl_take isl_pw_multi_aff *pma,
+		enum isl_dim_type type, unsigned pos, int value);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_fix_val(
+		__isl_take isl_pw_qpolynomial *pwqp,
+		enum isl_dim_type type, unsigned n,
+		__isl_take isl_val *v);
+
+Intersect the set, relation or function domain
+with the hyperplane where the given
+dimension has the fixed given value.
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *
+	isl_basic_set_lower_bound_val(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_val *value);
+	__isl_give isl_basic_set *
+	isl_basic_set_upper_bound_val(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_val *value);
+	__isl_give isl_set *isl_set_lower_bound_si(
+		__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, int value);
+	__isl_give isl_set *isl_set_lower_bound_val(
+		__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_val *value);
+	__isl_give isl_set *isl_set_upper_bound_si(
+		__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, int value);
+	__isl_give isl_set *isl_set_upper_bound_val(
+		__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos,
+		__isl_take isl_val *value);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_lower_bound_si(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos, int value);
+	__isl_give isl_basic_map *isl_basic_map_upper_bound_si(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos, int value);
+	__isl_give isl_map *isl_map_lower_bound_si(
+		__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, int value);
+	__isl_give isl_map *isl_map_upper_bound_si(
+		__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, int value);
+
+Intersect the set or relation with the half-space where the given
+dimension has a value bounded by the fixed given integer value.
+
+	__isl_give isl_set *isl_set_equate(__isl_take isl_set *set,
+		enum isl_dim_type type1, int pos1,
+		enum isl_dim_type type2, int pos2);
+	__isl_give isl_basic_map *isl_basic_map_equate(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type1, int pos1,
+		enum isl_dim_type type2, int pos2);
+	__isl_give isl_map *isl_map_equate(__isl_take isl_map *map,
+		enum isl_dim_type type1, int pos1,
+		enum isl_dim_type type2, int pos2);
+
+Intersect the set or relation with the hyperplane where the given
+dimensions are equal to each other.
+
+	__isl_give isl_map *isl_map_oppose(__isl_take isl_map *map,
+		enum isl_dim_type type1, int pos1,
+		enum isl_dim_type type2, int pos2);
+
+Intersect the relation with the hyperplane where the given
+dimensions have opposite values.
+
+	__isl_give isl_map *isl_map_order_le(
+		__isl_take isl_map *map,
+		enum isl_dim_type type1, int pos1,
+		enum isl_dim_type type2, int pos2);
+	__isl_give isl_basic_map *isl_basic_map_order_ge(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type1, int pos1,
+		enum isl_dim_type type2, int pos2);
+	__isl_give isl_map *isl_map_order_ge(
+		__isl_take isl_map *map,
+		enum isl_dim_type type1, int pos1,
+		enum isl_dim_type type2, int pos2);
+	__isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map,
+		enum isl_dim_type type1, int pos1,
+		enum isl_dim_type type2, int pos2);
+	__isl_give isl_basic_map *isl_basic_map_order_gt(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type1, int pos1,
+		enum isl_dim_type type2, int pos2);
+	__isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map,
+		enum isl_dim_type type1, int pos1,
+		enum isl_dim_type type2, int pos2);
+
+Intersect the relation with the half-space where the given
+dimensions satisfy the given ordering.
+
+=item * Locus
+
+	#include <isl/aff.h>
+	__isl_give isl_basic_set *isl_aff_zero_basic_set(
+		__isl_take isl_aff *aff);
+	__isl_give isl_basic_set *isl_aff_neg_basic_set(
+		__isl_take isl_aff *aff);
+	__isl_give isl_set *isl_pw_aff_pos_set(
+		__isl_take isl_pw_aff *pa);
+	__isl_give isl_set *isl_pw_aff_nonneg_set(
+		__isl_take isl_pw_aff *pwaff);
+	__isl_give isl_set *isl_pw_aff_zero_set(
+		__isl_take isl_pw_aff *pwaff);
+	__isl_give isl_set *isl_pw_aff_non_zero_set(
+		__isl_take isl_pw_aff *pwaff);
+	__isl_give isl_union_set *
+	isl_union_pw_aff_zero_union_set(
+		__isl_take isl_union_pw_aff *upa);
+	__isl_give isl_union_set *
+	isl_multi_union_pw_aff_zero_union_set(
+		__isl_take isl_multi_union_pw_aff *mupa);
+
+The function C<isl_aff_neg_basic_set> returns a basic set
+containing those elements in the domain space
+of C<aff> where C<aff> is negative.
+The function C<isl_pw_aff_nonneg_set> returns a set
+containing those elements in the domain
+of C<pwaff> where C<pwaff> is non-negative.
+The function C<isl_multi_union_pw_aff_zero_union_set>
+returns a union set containing those elements
+in the domains of its elements where they are all zero.
+
+=item * Identity
+
+	__isl_give isl_map *isl_set_identity(
+		__isl_take isl_set *set);
+	__isl_give isl_union_map *isl_union_set_identity(
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_set_identity_union_pw_multi_aff(
+		__isl_take isl_union_set *uset);
+
+Construct an identity relation on the given (union) set.
+
+=item * Function Extraction
+
+A piecewise quasi affine expression that is equal to 1 on a set
+and 0 outside the set can be created using the following function.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_set_indicator_function(
+		__isl_take isl_set *set);
+
+A piecewise multiple quasi affine expression can be extracted
+from an C<isl_set> or C<isl_map>, provided the C<isl_set> is a singleton
+and the C<isl_map> is single-valued.
+In case of a conversion from an C<isl_union_map>
+to an C<isl_union_pw_multi_aff>, these properties need to hold
+in each domain space.
+A conversion to a C<isl_multi_union_pw_aff> additionally
+requires that the input is non-empty and involves only a single
+range space.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(
+		__isl_take isl_set *set);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map(
+		__isl_take isl_map *map);
+
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_from_union_set(
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_from_union_map(
+		__isl_take isl_union_map *umap);
+
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_from_union_map(
+		__isl_take isl_union_map *umap);
+
+=item * Deltas
+
+	__isl_give isl_basic_set *isl_basic_map_deltas(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_set *isl_map_deltas(__isl_take isl_map *map);
+	__isl_give isl_union_set *isl_union_map_deltas(
+		__isl_take isl_union_map *umap);
+
+These functions return a (basic) set containing the differences
+between image elements and corresponding domain elements in the input.
+
+	__isl_give isl_basic_map *isl_basic_map_deltas_map(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_map *isl_map_deltas_map(
+		__isl_take isl_map *map);
+	__isl_give isl_union_map *isl_union_map_deltas_map(
+		__isl_take isl_union_map *umap);
+
+The functions above construct a (basic, regular or union) relation
+that maps (a wrapped version of) the input relation to its delta set.
+
+=item * Coalescing
+
+Simplify the representation of a set, relation or functions by trying
+to combine pairs of basic sets or relations into a single
+basic set or relation.
+
+	#include <isl/set.h>
+	__isl_give isl_set *isl_set_coalesce(__isl_take isl_set *set);
+
+	#include <isl/map.h>
+	__isl_give isl_map *isl_map_coalesce(__isl_take isl_map *map);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_set *isl_union_set_coalesce(
+		__isl_take isl_union_set *uset);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_coalesce(
+		__isl_take isl_union_map *umap);
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_aff_coalesce(
+		__isl_take isl_pw_aff *pwqp);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_coalesce(
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_coalesce(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_coalesce(
+		__isl_take isl_union_pw_aff *upa);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_coalesce(
+		__isl_take isl_union_pw_multi_aff *upma);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_coalesce(
+		__isl_take isl_multi_union_pw_aff *aff);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_coalesce(
+		__isl_take isl_pw_qpolynomial_fold *pwf);
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_coalesce(
+		__isl_take isl_union_pw_qpolynomial *upwqp);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_coalesce(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf);
+
+One of the methods for combining pairs of basic sets or relations
+can result in coefficients that are much larger than those that appear
+in the constraints of the input.  By default, the coefficients are
+not allowed to grow larger, but this can be changed by unsetting
+the following option.
+
+	isl_stat isl_options_set_coalesce_bounded_wrapping(
+		isl_ctx *ctx, int val);
+	int isl_options_get_coalesce_bounded_wrapping(
+		isl_ctx *ctx);
+
+=item * Detecting equalities
+
+	__isl_give isl_basic_set *isl_basic_set_detect_equalities(
+                __isl_take isl_basic_set *bset);
+	__isl_give isl_basic_map *isl_basic_map_detect_equalities(
+                __isl_take isl_basic_map *bmap);
+	__isl_give isl_set *isl_set_detect_equalities(
+		__isl_take isl_set *set);
+	__isl_give isl_map *isl_map_detect_equalities(
+		__isl_take isl_map *map);
+	__isl_give isl_union_set *isl_union_set_detect_equalities(
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_map *isl_union_map_detect_equalities(
+		__isl_take isl_union_map *umap);
+
+Simplify the representation of a set or relation by detecting implicit
+equalities.
+
+=item * Removing redundant constraints
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_remove_redundancies(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_set *isl_set_remove_redundancies(
+		__isl_take isl_set *set);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_set *
+	isl_union_set_remove_redundancies(
+		__isl_take isl_union_set *uset);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_remove_redundancies(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_map *isl_map_remove_redundancies(
+		__isl_take isl_map *map);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *
+	isl_union_map_remove_redundancies(
+		__isl_take isl_union_map *umap);
+
+=item * Convex hull
+
+	__isl_give isl_basic_set *isl_set_convex_hull(
+		__isl_take isl_set *set);
+	__isl_give isl_basic_map *isl_map_convex_hull(
+		__isl_take isl_map *map);
+
+If the input set or relation has any existentially quantified
+variables, then the result of these operations is currently undefined.
+
+=item * Simple hull
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *
+	isl_set_unshifted_simple_hull(
+		__isl_take isl_set *set);
+	__isl_give isl_basic_set *isl_set_simple_hull(
+		__isl_take isl_set *set);
+	__isl_give isl_basic_set *
+	isl_set_plain_unshifted_simple_hull(
+		__isl_take isl_set *set);
+	__isl_give isl_basic_set *
+	isl_set_unshifted_simple_hull_from_set_list(
+		__isl_take isl_set *set,
+		__isl_take isl_set_list *list);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *
+	isl_map_unshifted_simple_hull(
+		__isl_take isl_map *map);
+	__isl_give isl_basic_map *isl_map_simple_hull(
+		__isl_take isl_map *map);
+	__isl_give isl_basic_map *
+	isl_map_plain_unshifted_simple_hull(
+		__isl_take isl_map *map);
+		__isl_give isl_basic_map *
+	isl_map_unshifted_simple_hull_from_map_list(
+		__isl_take isl_map *map,
+		__isl_take isl_map_list *list);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_simple_hull(
+		__isl_take isl_union_map *umap);
+
+These functions compute a single basic set or relation
+that contains the whole input set or relation.
+In particular, the output is described by translates
+of the constraints describing the basic sets or relations in the input.
+In case of C<isl_set_unshifted_simple_hull>, only the original
+constraints are used, without any translation.
+In case of C<isl_set_plain_unshifted_simple_hull> and
+C<isl_map_plain_unshifted_simple_hull>, the result is described
+by original constraints that are obviously satisfied
+by the entire input set or relation.
+In case of C<isl_set_unshifted_simple_hull_from_set_list> and
+C<isl_map_unshifted_simple_hull_from_map_list>, the
+constraints are taken from the elements of the second argument.
+
+=begin latex
+
+(See \autoref{s:simple hull}.)
+
+=end latex
+
+=item * Affine hull
+
+	__isl_give isl_basic_set *isl_basic_set_affine_hull(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_basic_set *isl_set_affine_hull(
+		__isl_take isl_set *set);
+	__isl_give isl_union_set *isl_union_set_affine_hull(
+		__isl_take isl_union_set *uset);
+	__isl_give isl_basic_map *isl_basic_map_affine_hull(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_basic_map *isl_map_affine_hull(
+		__isl_take isl_map *map);
+	__isl_give isl_union_map *isl_union_map_affine_hull(
+		__isl_take isl_union_map *umap);
+
+In case of union sets and relations, the affine hull is computed
+per space.
+
+=item * Polyhedral hull
+
+	__isl_give isl_basic_set *isl_set_polyhedral_hull(
+		__isl_take isl_set *set);
+	__isl_give isl_basic_map *isl_map_polyhedral_hull(
+		__isl_take isl_map *map);
+	__isl_give isl_union_set *isl_union_set_polyhedral_hull(
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_map *isl_union_map_polyhedral_hull(
+		__isl_take isl_union_map *umap);
+
+These functions compute a single basic set or relation
+not involving any existentially quantified variables
+that contains the whole input set or relation.
+In case of union sets and relations, the polyhedral hull is computed
+per space.
+
+=item * Other approximations
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *
+	isl_basic_set_drop_constraints_involving_dims(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_basic_set *
+	isl_basic_set_drop_constraints_not_involving_dims(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_set *
+	isl_set_drop_constraints_involving_dims(
+		__isl_take isl_set *set,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_set *
+	isl_set_drop_constraints_not_involving_dims(
+		__isl_take isl_set *set,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *
+	isl_basic_map_drop_constraints_involving_dims(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_basic_map *
+	isl_basic_map_drop_constraints_not_involving_dims(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_map *
+	isl_map_drop_constraints_involving_dims(
+		__isl_take isl_map *map,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_map *
+	isl_map_drop_constraints_not_involving_dims(
+		__isl_take isl_map *map,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+
+These functions drop any constraints (not) involving the specified dimensions.
+Note that the result depends on the representation of the input.
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_to_polynomial(
+		__isl_take isl_pw_qpolynomial *pwqp, int sign);
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_to_polynomial(
+		__isl_take isl_union_pw_qpolynomial *upwqp, int sign);
+
+Approximate each quasipolynomial by a polynomial.  If C<sign> is positive,
+the polynomial will be an overapproximation.  If C<sign> is negative,
+it will be an underapproximation.  If C<sign> is zero, the approximation
+will lie somewhere in between.
+
+=item * Feasibility
+
+	__isl_give isl_basic_set *isl_basic_set_sample(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_basic_set *isl_set_sample(
+		__isl_take isl_set *set);
+	__isl_give isl_basic_map *isl_basic_map_sample(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_basic_map *isl_map_sample(
+		__isl_take isl_map *map);
+
+If the input (basic) set or relation is non-empty, then return
+a singleton subset of the input.  Otherwise, return an empty set.
+
+=item * Optimization
+
+	#include <isl/ilp.h>
+	__isl_give isl_val *isl_basic_set_max_val(
+		__isl_keep isl_basic_set *bset,
+		__isl_keep isl_aff *obj);
+	__isl_give isl_val *isl_set_min_val(
+		__isl_keep isl_set *set,
+		__isl_keep isl_aff *obj);
+	__isl_give isl_val *isl_set_max_val(
+		__isl_keep isl_set *set,
+		__isl_keep isl_aff *obj);
+	__isl_give isl_multi_val *
+	isl_union_set_min_multi_union_pw_aff(
+		__isl_keep isl_union_set *set,
+		__isl_keep isl_multi_union_pw_aff *obj);
+
+Compute the minimum or maximum of the integer affine expression C<obj>
+over the points in C<set>, returning the result in C<opt>.
+The result is C<NULL> in case of an error, the optimal value in case
+there is one, negative infinity or infinity if the problem is unbounded and
+NaN if the problem is empty.
+
+=item * Parametric optimization
+
+	__isl_give isl_pw_aff *isl_set_dim_min(
+		__isl_take isl_set *set, int pos);
+	__isl_give isl_pw_aff *isl_set_dim_max(
+		__isl_take isl_set *set, int pos);
+	__isl_give isl_pw_aff *isl_map_dim_min(
+		__isl_take isl_map *map, int pos);
+	__isl_give isl_pw_aff *isl_map_dim_max(
+		__isl_take isl_map *map, int pos);
+
+Compute the minimum or maximum of the given set or output dimension
+as a function of the parameters (and input dimensions), but independently
+of the other set or output dimensions.
+For lexicographic optimization, see L<"Lexicographic Optimization">.
+
+=item * Dual
+
+The following functions compute either the set of (rational) coefficient
+values of valid constraints for the given set or the set of (rational)
+values satisfying the constraints with coefficients from the given set.
+Internally, these two sets of functions perform essentially the
+same operations, except that the set of coefficients is assumed to
+be a cone, while the set of values may be any polyhedron.
+The current implementation is based on the Farkas lemma and
+Fourier-Motzkin elimination, but this may change or be made optional
+in future.  In particular, future implementations may use different
+dualization algorithms or skip the elimination step.
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_coefficients(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_basic_set_list *
+	isl_basic_set_list_coefficients(
+		__isl_take isl_basic_set_list *list);
+	__isl_give isl_basic_set *isl_set_coefficients(
+		__isl_take isl_set *set);
+	__isl_give isl_union_set *isl_union_set_coefficients(
+		__isl_take isl_union_set *bset);
+	__isl_give isl_basic_set *isl_basic_set_solutions(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_basic_set *isl_set_solutions(
+		__isl_take isl_set *set);
+	__isl_give isl_union_set *isl_union_set_solutions(
+		__isl_take isl_union_set *bset);
+
+=item * Power
+
+	__isl_give isl_map *isl_map_fixed_power_val(
+		__isl_take isl_map *map,
+		__isl_take isl_val *exp);
+	__isl_give isl_union_map *
+	isl_union_map_fixed_power_val(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_val *exp);
+
+Compute the given power of C<map>, where C<exp> is assumed to be non-zero.
+If the exponent C<exp> is negative, then the -C<exp> th power of the inverse
+of C<map> is computed.
+
+	__isl_give isl_map *isl_map_power(__isl_take isl_map *map,
+		int *exact);
+	__isl_give isl_union_map *isl_union_map_power(
+		__isl_take isl_union_map *umap, int *exact);
+
+Compute a parametric representation for all positive powers I<k> of C<map>.
+The result maps I<k> to a nested relation corresponding to the
+I<k>th power of C<map>.
+The result may be an overapproximation.  If the result is known to be exact,
+then C<*exact> is set to C<1>.
+
+=item * Transitive closure
+
+	__isl_give isl_map *isl_map_transitive_closure(
+		__isl_take isl_map *map, int *exact);
+	__isl_give isl_union_map *isl_union_map_transitive_closure(
+		__isl_take isl_union_map *umap, int *exact);
+
+Compute the transitive closure of C<map>.
+The result may be an overapproximation.  If the result is known to be exact,
+then C<*exact> is set to C<1>.
+
+=item * Reaching path lengths
+
+	__isl_give isl_map *isl_map_reaching_path_lengths(
+		__isl_take isl_map *map, int *exact);
+
+Compute a relation that maps each element in the range of C<map>
+to the lengths of all paths composed of edges in C<map> that
+end up in the given element.
+The result may be an overapproximation.  If the result is known to be exact,
+then C<*exact> is set to C<1>.
+To compute the I<maximal> path length, the resulting relation
+should be postprocessed by C<isl_map_lexmax>.
+In particular, if the input relation is a dependence relation
+(mapping sources to sinks), then the maximal path length corresponds
+to the free schedule.
+Note, however, that C<isl_map_lexmax> expects the maximum to be
+finite, so if the path lengths are unbounded (possibly due to
+the overapproximation), then you will get an error message.
+
+=item * Wrapping
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_wrap(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_unwrap(
+		__isl_take isl_space *space);
+
+	#include <isl/local_space.h>
+	__isl_give isl_local_space *isl_local_space_wrap(
+		__isl_take isl_local_space *ls);
+
+	#include <isl/set.h>
+	__isl_give isl_basic_map *isl_basic_set_unwrap(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_map *isl_set_unwrap(
+		__isl_take isl_set *set);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_set *isl_basic_map_wrap(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_set *isl_map_wrap(
+		__isl_take isl_map *map);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_map *isl_union_set_unwrap(
+		__isl_take isl_union_set *uset);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_set *isl_union_map_wrap(
+		__isl_take isl_union_map *umap);
+
+The input to C<isl_space_unwrap> should
+be the space of a set, while that of
+C<isl_space_wrap> should be the space of a relation.
+Conversely, the output of C<isl_space_unwrap> is the space
+of a relation, while that of C<isl_space_wrap> is the space of a set.
+
+=item * Flattening
+
+Remove any internal structure of domain (and range) of the given
+set or relation.  If there is any such internal structure in the input,
+then the name of the space is also removed.
+
+	#include <isl/local_space.h>
+	__isl_give isl_local_space *
+	isl_local_space_flatten_domain(
+		__isl_take isl_local_space *ls);
+	__isl_give isl_local_space *
+	isl_local_space_flatten_range(
+		__isl_take isl_local_space *ls);
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_flatten(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_set *isl_set_flatten(
+		__isl_take isl_set *set);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_flatten_domain(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_basic_map *isl_basic_map_flatten_range(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_map *isl_map_flatten_range(
+		__isl_take isl_map *map);
+	__isl_give isl_map *isl_map_flatten_domain(
+		__isl_take isl_map *map);
+	__isl_give isl_basic_map *isl_basic_map_flatten(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_map *isl_map_flatten(
+		__isl_take isl_map *map);
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_flatten_range(
+		__isl_take isl_multi_val *mv);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_flatten_domain(
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_multi_aff *isl_multi_aff_flatten_range(
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_flatten_range(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_flatten_range(
+		__isl_take isl_multi_union_pw_aff *mupa);
+
+	#include <isl/map.h>
+	__isl_give isl_map *isl_set_flatten_map(
+		__isl_take isl_set *set);
+
+The function above constructs a relation
+that maps the input set to a flattened version of the set.
+
+=item * Lifting
+
+Lift the input set to a space with extra dimensions corresponding
+to the existentially quantified variables in the input.
+In particular, the result lives in a wrapped map where the domain
+is the original space and the range corresponds to the original
+existentially quantified variables.
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_lift(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_set *isl_set_lift(
+		__isl_take isl_set *set);
+	__isl_give isl_union_set *isl_union_set_lift(
+		__isl_take isl_union_set *uset);
+
+Given a local space that contains the existentially quantified
+variables of a set, a basic relation that, when applied to
+a basic set, has essentially the same effect as C<isl_basic_set_lift>,
+can be constructed using the following function.
+
+	#include <isl/local_space.h>
+	__isl_give isl_basic_map *isl_local_space_lifting(
+		__isl_take isl_local_space *ls);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_lift(
+		__isl_take isl_multi_aff *maff,
+		__isl_give isl_local_space **ls);
+
+If the C<ls> argument of C<isl_multi_aff_lift> is not C<NULL>,
+then it is assigned the local space that lies at the basis of
+the lifting applied.
+
+=item * Internal Product
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_zip(
+		__isl_take isl_space *space);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_zip(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_map *isl_map_zip(
+		__isl_take isl_map *map);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_zip(
+		__isl_take isl_union_map *umap);
+
+Given a relation with nested relations for domain and range,
+interchange the range of the domain with the domain of the range.
+
+=item * Currying
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_curry(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_uncurry(
+		__isl_take isl_space *space);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_curry(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_basic_map *isl_basic_map_uncurry(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_map *isl_map_curry(
+		__isl_take isl_map *map);
+	__isl_give isl_map *isl_map_uncurry(
+		__isl_take isl_map *map);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_curry(
+		__isl_take isl_union_map *umap);
+	__isl_give isl_union_map *isl_union_map_uncurry(
+		__isl_take isl_union_map *umap);
+
+Given a relation with a nested relation for domain,
+the C<curry> functions
+move the range of the nested relation out of the domain
+and use it as the domain of a nested relation in the range,
+with the original range as range of this nested relation.
+The C<uncurry> functions perform the inverse operation.
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_range_curry(
+		__isl_take isl_space *space);
+
+	#include <isl/map.h>
+	__isl_give isl_map *isl_map_range_curry(
+		__isl_take isl_map *map);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_range_curry(
+		__isl_take isl_union_map *umap);
+
+These functions apply the currying to the relation that
+is nested inside the range of the input.
+
+=item * Aligning parameters
+
+Change the order of the parameters of the given set, relation
+or function
+such that the first parameters match those of C<model>.
+This may involve the introduction of extra parameters.
+All parameters need to be named.
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_align_params(
+		__isl_take isl_space *space1,
+		__isl_take isl_space *space2)
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_align_params(
+		__isl_take isl_basic_set *bset,
+		__isl_take isl_space *model);
+	__isl_give isl_set *isl_set_align_params(
+		__isl_take isl_set *set,
+		__isl_take isl_space *model);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_align_params(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_space *model);
+	__isl_give isl_map *isl_map_align_params(
+		__isl_take isl_map *map,
+		__isl_take isl_space *model);
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_align_params(
+		__isl_take isl_multi_val *mv,
+		__isl_take isl_space *model);
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_align_params(
+		__isl_take isl_aff *aff,
+		__isl_take isl_space *model);
+	__isl_give isl_multi_aff *isl_multi_aff_align_params(
+		__isl_take isl_multi_aff *multi,
+		__isl_take isl_space *model);
+	__isl_give isl_pw_aff *isl_pw_aff_align_params(
+		__isl_take isl_pw_aff *pwaff,
+		__isl_take isl_space *model);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_align_params(
+		__isl_take isl_pw_multi_aff *pma,
+		__isl_take isl_space *model);
+	__isl_give isl_union_pw_aff *
+	isl_union_pw_aff_align_params(
+		__isl_take isl_union_pw_aff *upa,
+		__isl_take isl_space *model);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_align_params(
+		__isl_take isl_union_pw_multi_aff *upma,
+		__isl_take isl_space *model);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_align_params(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_space *model);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_qpolynomial *isl_qpolynomial_align_params(
+		__isl_take isl_qpolynomial *qp,
+		__isl_take isl_space *model);
+
+=item * Unary Arithmetic Operations
+
+	#include <isl/set.h>
+	__isl_give isl_set *isl_set_neg(
+		__isl_take isl_set *set);
+	#include <isl/map.h>
+	__isl_give isl_map *isl_map_neg(
+		__isl_take isl_map *map);
+
+C<isl_set_neg> constructs a set containing the opposites of
+the elements in its argument.
+The domain of the result of C<isl_map_neg> is the same
+as the domain of its argument.  The corresponding range
+elements are the opposites of the corresponding range
+elements in the argument.
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_neg(
+		__isl_take isl_multi_val *mv);
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_neg(
+		__isl_take isl_aff *aff);
+	__isl_give isl_multi_aff *isl_multi_aff_neg(
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_pw_aff *isl_pw_aff_neg(
+		__isl_take isl_pw_aff *pwaff);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_neg(
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_neg(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_neg(
+		__isl_take isl_union_pw_aff *upa);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_neg(
+		__isl_take isl_union_pw_multi_aff *upma);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_neg(
+		__isl_take isl_multi_union_pw_aff *mupa);
+	__isl_give isl_aff *isl_aff_ceil(
+		__isl_take isl_aff *aff);
+	__isl_give isl_pw_aff *isl_pw_aff_ceil(
+		__isl_take isl_pw_aff *pwaff);
+	__isl_give isl_aff *isl_aff_floor(
+		__isl_take isl_aff *aff);
+	__isl_give isl_multi_aff *isl_multi_aff_floor(
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_pw_aff *isl_pw_aff_floor(
+		__isl_take isl_pw_aff *pwaff);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_floor(
+		__isl_take isl_union_pw_aff *upa);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_floor(
+		__isl_take isl_multi_union_pw_aff *mupa);
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_aff_list_min(
+		__isl_take isl_pw_aff_list *list);
+	__isl_give isl_pw_aff *isl_pw_aff_list_max(
+		__isl_take isl_pw_aff_list *list);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_qpolynomial *isl_qpolynomial_neg(
+		__isl_take isl_qpolynomial *qp);
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_neg(
+		__isl_take isl_pw_qpolynomial *pwqp);
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_neg(
+		__isl_take isl_union_pw_qpolynomial *upwqp);
+	__isl_give isl_qpolynomial *isl_qpolynomial_pow(
+		__isl_take isl_qpolynomial *qp,
+		unsigned exponent);
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_pow(
+		__isl_take isl_pw_qpolynomial *pwqp,
+		unsigned exponent);
+
+=item * Evaluation
+
+The following functions evaluate a function in a point.
+
+	#include <isl/polynomial.h>
+	__isl_give isl_val *isl_pw_qpolynomial_eval(
+		__isl_take isl_pw_qpolynomial *pwqp,
+		__isl_take isl_point *pnt);
+	__isl_give isl_val *isl_pw_qpolynomial_fold_eval(
+		__isl_take isl_pw_qpolynomial_fold *pwf,
+		__isl_take isl_point *pnt);
+	__isl_give isl_val *isl_union_pw_qpolynomial_eval(
+		__isl_take isl_union_pw_qpolynomial *upwqp,
+		__isl_take isl_point *pnt);
+	__isl_give isl_val *isl_union_pw_qpolynomial_fold_eval(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf,
+		__isl_take isl_point *pnt);
+
+=item * Dimension manipulation
+
+It is usually not advisable to directly change the (input or output)
+space of a set or a relation as this removes the name and the internal
+structure of the space.  However, the functions below can be useful
+to add new parameters, assuming
+C<isl_set_align_params> and C<isl_map_align_params>
+are not sufficient.
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_add_dims(
+		__isl_take isl_space *space,
+		enum isl_dim_type type, unsigned n);
+	__isl_give isl_space *isl_space_insert_dims(
+		__isl_take isl_space *space,
+		enum isl_dim_type type, unsigned pos, unsigned n);
+	__isl_give isl_space *isl_space_drop_dims(
+		__isl_take isl_space *space,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_space *isl_space_move_dims(
+		__isl_take isl_space *space,
+		enum isl_dim_type dst_type, unsigned dst_pos,
+		enum isl_dim_type src_type, unsigned src_pos,
+		unsigned n);
+
+	#include <isl/local_space.h>
+	__isl_give isl_local_space *isl_local_space_add_dims(
+		__isl_take isl_local_space *ls,
+		enum isl_dim_type type, unsigned n);
+	__isl_give isl_local_space *isl_local_space_insert_dims(
+		__isl_take isl_local_space *ls,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_local_space *isl_local_space_drop_dims(
+		__isl_take isl_local_space *ls,
+		enum isl_dim_type type, unsigned first, unsigned n);
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_add_dims(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned n);
+	__isl_give isl_set *isl_set_add_dims(
+		__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned n);
+	__isl_give isl_basic_set *isl_basic_set_insert_dims(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos,
+		unsigned n);
+	__isl_give isl_set *isl_set_insert_dims(
+		__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, unsigned n);
+	__isl_give isl_basic_set *isl_basic_set_move_dims(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type dst_type, unsigned dst_pos,
+		enum isl_dim_type src_type, unsigned src_pos,
+		unsigned n);
+	__isl_give isl_set *isl_set_move_dims(
+		__isl_take isl_set *set,
+		enum isl_dim_type dst_type, unsigned dst_pos,
+		enum isl_dim_type src_type, unsigned src_pos,
+		unsigned n);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_add_dims(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned n);
+	__isl_give isl_map *isl_map_add_dims(
+		__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned n);
+	__isl_give isl_basic_map *isl_basic_map_insert_dims(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos,
+		unsigned n);
+	__isl_give isl_map *isl_map_insert_dims(
+		__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, unsigned n);
+	__isl_give isl_basic_map *isl_basic_map_move_dims(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type dst_type, unsigned dst_pos,
+		enum isl_dim_type src_type, unsigned src_pos,
+		unsigned n);
+	__isl_give isl_map *isl_map_move_dims(
+		__isl_take isl_map *map,
+		enum isl_dim_type dst_type, unsigned dst_pos,
+		enum isl_dim_type src_type, unsigned src_pos,
+		unsigned n);
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_insert_dims(
+		__isl_take isl_multi_val *mv,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_multi_val *isl_multi_val_add_dims(
+		__isl_take isl_multi_val *mv,
+		enum isl_dim_type type, unsigned n);
+	__isl_give isl_multi_val *isl_multi_val_drop_dims(
+		__isl_take isl_multi_val *mv,
+		enum isl_dim_type type, unsigned first, unsigned n);
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_insert_dims(
+		__isl_take isl_aff *aff,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_multi_aff *isl_multi_aff_insert_dims(
+		__isl_take isl_multi_aff *ma,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_pw_aff *isl_pw_aff_insert_dims(
+		__isl_take isl_pw_aff *pwaff,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_insert_dims(
+		__isl_take isl_multi_pw_aff *mpa,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_aff *isl_aff_add_dims(
+		__isl_take isl_aff *aff,
+		enum isl_dim_type type, unsigned n);
+	__isl_give isl_multi_aff *isl_multi_aff_add_dims(
+		__isl_take isl_multi_aff *ma,
+		enum isl_dim_type type, unsigned n);
+	__isl_give isl_pw_aff *isl_pw_aff_add_dims(
+		__isl_take isl_pw_aff *pwaff,
+		enum isl_dim_type type, unsigned n);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_add_dims(
+		__isl_take isl_multi_pw_aff *mpa,
+		enum isl_dim_type type, unsigned n);
+	__isl_give isl_aff *isl_aff_drop_dims(
+		__isl_take isl_aff *aff,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_multi_aff *isl_multi_aff_drop_dims(
+		__isl_take isl_multi_aff *maff,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_pw_aff *isl_pw_aff_drop_dims(
+		__isl_take isl_pw_aff *pwaff,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_drop_dims(
+		__isl_take isl_pw_multi_aff *pma,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_drop_dims(
+		__isl_take isl_union_pw_aff *upa,
+		enum isl_dim_type type, unsigned first, unsigned n);
+	__isl_give isl_union_pw_multi_aff *
+		isl_union_pw_multi_aff_drop_dims(
+		__isl_take isl_union_pw_multi_aff *upma,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_drop_dims(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		enum isl_dim_type type, unsigned first,
+		unsigned n);
+	__isl_give isl_aff *isl_aff_move_dims(
+		__isl_take isl_aff *aff,
+		enum isl_dim_type dst_type, unsigned dst_pos,
+		enum isl_dim_type src_type, unsigned src_pos,
+		unsigned n);
+	__isl_give isl_multi_aff *isl_multi_aff_move_dims(
+		__isl_take isl_multi_aff *ma,
+		enum isl_dim_type dst_type, unsigned dst_pos,
+		enum isl_dim_type src_type, unsigned src_pos,
+		unsigned n);
+	__isl_give isl_pw_aff *isl_pw_aff_move_dims(
+		__isl_take isl_pw_aff *pa,
+		enum isl_dim_type dst_type, unsigned dst_pos,
+		enum isl_dim_type src_type, unsigned src_pos,
+		unsigned n);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_move_dims(
+		__isl_take isl_multi_pw_aff *pma,
+		enum isl_dim_type dst_type, unsigned dst_pos,
+		enum isl_dim_type src_type, unsigned src_pos,
+		unsigned n);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_drop_dims(
+		__isl_take isl_union_pw_qpolynomial *upwqp,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+	__isl_give isl_union_pw_qpolynomial_fold *
+		isl_union_pw_qpolynomial_fold_drop_dims(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf,
+		enum isl_dim_type type,
+		unsigned first, unsigned n);
+
+The operations on union expressions can only manipulate parameters.
+
+=back
+
+=head2 Binary Operations
+
+The two arguments of a binary operation not only need to live
+in the same C<isl_ctx>, they currently also need to have
+the same (number of) parameters.
+
+=head3 Basic Operations
+
+=over
+
+=item * Intersection
+
+	#include <isl/local_space.h>
+	__isl_give isl_local_space *isl_local_space_intersect(
+		__isl_take isl_local_space *ls1,
+		__isl_take isl_local_space *ls2);
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_intersect_params(
+		__isl_take isl_basic_set *bset1,
+		__isl_take isl_basic_set *bset2);
+	__isl_give isl_basic_set *isl_basic_set_intersect(
+		__isl_take isl_basic_set *bset1,
+		__isl_take isl_basic_set *bset2);
+	__isl_give isl_basic_set *isl_basic_set_list_intersect(
+		__isl_take struct isl_basic_set_list *list);
+	__isl_give isl_set *isl_set_intersect_params(
+		__isl_take isl_set *set,
+		__isl_take isl_set *params);
+	__isl_give isl_set *isl_set_intersect(
+		__isl_take isl_set *set1,
+		__isl_take isl_set *set2);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_intersect_domain(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_basic_map *isl_basic_map_intersect_range(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_basic_map *isl_basic_map_intersect(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+	__isl_give isl_basic_map *isl_basic_map_list_intersect(
+		__isl_take isl_basic_map_list *list);
+	__isl_give isl_map *isl_map_intersect_params(
+		__isl_take isl_map *map,
+		__isl_take isl_set *params);
+	__isl_give isl_map *isl_map_intersect_domain(
+		__isl_take isl_map *map,
+		__isl_take isl_set *set);
+	__isl_give isl_map *isl_map_intersect_range(
+		__isl_take isl_map *map,
+		__isl_take isl_set *set);
+	__isl_give isl_map *isl_map_intersect(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+	__isl_give isl_map *
+	isl_map_intersect_domain_factor_range(
+		__isl_take isl_map *map,
+		__isl_take isl_map *factor);
+	__isl_give isl_map *
+	isl_map_intersect_range_factor_range(
+		__isl_take isl_map *map,
+		__isl_take isl_map *factor);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_set *isl_union_set_intersect_params(
+		__isl_take isl_union_set *uset,
+		__isl_take isl_set *set);
+	__isl_give isl_union_set *isl_union_set_intersect(
+		__isl_take isl_union_set *uset1,
+		__isl_take isl_union_set *uset2);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_intersect_params(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_set *set);
+	__isl_give isl_union_map *isl_union_map_intersect_domain(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_map *isl_union_map_intersect_range(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_map *isl_union_map_intersect(
+		__isl_take isl_union_map *umap1,
+		__isl_take isl_union_map *umap2);
+	__isl_give isl_union_map *
+	isl_union_map_intersect_range_factor_range(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_union_map *factor);
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_aff_intersect_domain(
+		__isl_take isl_pw_aff *pa,
+		__isl_take isl_set *set);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_intersect_domain(
+		__isl_take isl_multi_pw_aff *mpa,
+		__isl_take isl_set *domain);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_intersect_domain(
+		__isl_take isl_pw_multi_aff *pma,
+		__isl_take isl_set *set);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_intersect_domain(
+		__isl_take isl_union_pw_aff *upa,
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_intersect_domain(
+		__isl_take isl_union_pw_multi_aff *upma,
+		__isl_take isl_union_set *uset);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_intersect_domain(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_union_set *uset);
+	__isl_give isl_pw_aff *isl_pw_aff_intersect_params(
+		__isl_take isl_pw_aff *pa,
+		__isl_take isl_set *set);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_intersect_params(
+		__isl_take isl_multi_pw_aff *mpa,
+		__isl_take isl_set *set);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_intersect_params(
+		__isl_take isl_pw_multi_aff *pma,
+		__isl_take isl_set *set);
+	__isl_give isl_union_pw_aff *
+	isl_union_pw_aff_intersect_params(
+		__isl_take isl_union_pw_aff *upa,
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_intersect_params(
+		__isl_take isl_union_pw_multi_aff *upma,
+		__isl_take isl_set *set);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_intersect_params(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_set *params);
+	isl_multi_union_pw_aff_intersect_range(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_set *set);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial *
+	isl_pw_qpolynomial_intersect_domain(
+		__isl_take isl_pw_qpolynomial *pwpq,
+		__isl_take isl_set *set);
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_intersect_domain(
+		__isl_take isl_union_pw_qpolynomial *upwpq,
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_intersect_domain(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf,
+		__isl_take isl_union_set *uset);
+	__isl_give isl_pw_qpolynomial *
+	isl_pw_qpolynomial_intersect_params(
+		__isl_take isl_pw_qpolynomial *pwpq,
+		__isl_take isl_set *set);
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_intersect_params(
+		__isl_take isl_pw_qpolynomial_fold *pwf,
+		__isl_take isl_set *set);
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_intersect_params(
+		__isl_take isl_union_pw_qpolynomial *upwpq,
+		__isl_take isl_set *set);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_intersect_params(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf,
+		__isl_take isl_set *set);
+
+The second argument to the C<_params> functions needs to be
+a parametric (basic) set.  For the other functions, a parametric set
+for either argument is only allowed if the other argument is
+a parametric set as well.
+The list passed to C<isl_basic_set_list_intersect> needs to have
+at least one element and all elements need to live in the same space.
+The function C<isl_multi_union_pw_aff_intersect_range>
+restricts the input function to those shared domain elements
+that map to the specified range.
+
+=item * Union
+
+	#include <isl/set.h>
+	__isl_give isl_set *isl_basic_set_union(
+		__isl_take isl_basic_set *bset1,
+		__isl_take isl_basic_set *bset2);
+	__isl_give isl_set *isl_set_union(
+		__isl_take isl_set *set1,
+		__isl_take isl_set *set2);
+	__isl_give isl_set *isl_set_list_union(
+		__isl_take isl_set_list *list);
+
+	#include <isl/map.h>
+	__isl_give isl_map *isl_basic_map_union(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+	__isl_give isl_map *isl_map_union(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_set *isl_union_set_union(
+		__isl_take isl_union_set *uset1,
+		__isl_take isl_union_set *uset2);
+	__isl_give isl_union_set *isl_union_set_list_union(
+		__isl_take isl_union_set_list *list);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_union(
+		__isl_take isl_union_map *umap1,
+		__isl_take isl_union_map *umap2);
+
+The list passed to C<isl_set_list_union> needs to have
+at least one element and all elements need to live in the same space.
+
+=item * Set difference
+
+	#include <isl/set.h>
+	__isl_give isl_set *isl_set_subtract(
+		__isl_take isl_set *set1,
+		__isl_take isl_set *set2);
+
+	#include <isl/map.h>
+	__isl_give isl_map *isl_map_subtract(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+	__isl_give isl_map *isl_map_subtract_domain(
+		__isl_take isl_map *map,
+		__isl_take isl_set *dom);
+	__isl_give isl_map *isl_map_subtract_range(
+		__isl_take isl_map *map,
+		__isl_take isl_set *dom);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_set *isl_union_set_subtract(
+		__isl_take isl_union_set *uset1,
+		__isl_take isl_union_set *uset2);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_subtract(
+		__isl_take isl_union_map *umap1,
+		__isl_take isl_union_map *umap2);
+	__isl_give isl_union_map *isl_union_map_subtract_domain(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_union_set *dom);
+	__isl_give isl_union_map *isl_union_map_subtract_range(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_union_set *dom);
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_aff_subtract_domain(
+		__isl_take isl_pw_aff *pa,
+		__isl_take isl_set *set);
+	__isl_give isl_pw_multi_aff *
+	isl_pw_multi_aff_subtract_domain(
+		__isl_take isl_pw_multi_aff *pma,
+		__isl_take isl_set *set);
+	__isl_give isl_union_pw_aff *
+	isl_union_pw_aff_subtract_domain(
+		__isl_take isl_union_pw_aff *upa,
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_subtract_domain(
+		__isl_take isl_union_pw_multi_aff *upma,
+		__isl_take isl_set *set);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial *
+	isl_pw_qpolynomial_subtract_domain(
+		__isl_take isl_pw_qpolynomial *pwpq,
+		__isl_take isl_set *set);
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_subtract_domain(
+		__isl_take isl_pw_qpolynomial_fold *pwf,
+		__isl_take isl_set *set);
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_subtract_domain(
+		__isl_take isl_union_pw_qpolynomial *upwpq,
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_subtract_domain(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf,
+		__isl_take isl_union_set *uset);
+
+=item * Application
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_join(
+		__isl_take isl_space *left,
+		__isl_take isl_space *right);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_set *isl_basic_set_apply(
+		__isl_take isl_basic_set *bset,
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_set *isl_set_apply(
+		__isl_take isl_set *set,
+		__isl_take isl_map *map);
+	__isl_give isl_union_set *isl_union_set_apply(
+		__isl_take isl_union_set *uset,
+		__isl_take isl_union_map *umap);
+	__isl_give isl_basic_map *isl_basic_map_apply_domain(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+	__isl_give isl_basic_map *isl_basic_map_apply_range(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+	__isl_give isl_map *isl_map_apply_domain(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+	__isl_give isl_map *isl_map_apply_range(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_apply_domain(
+		__isl_take isl_union_map *umap1,
+		__isl_take isl_union_map *umap2);
+	__isl_give isl_union_map *isl_union_map_apply_range(
+		__isl_take isl_union_map *umap1,
+		__isl_take isl_union_map *umap2);
+
+	#include <isl/aff.h>
+	__isl_give isl_union_pw_aff *
+	isl_multi_union_pw_aff_apply_aff(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_aff *aff);
+	__isl_give isl_union_pw_aff *
+	isl_multi_union_pw_aff_apply_pw_aff(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_pw_aff *pa);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_apply_multi_aff(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_apply_pw_multi_aff(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_pw_multi_aff *pma);
+
+The result of C<isl_multi_union_pw_aff_apply_aff> is defined
+over the shared domain of the elements of the input.  The dimension is
+required to be greater than zero.
+The C<isl_multi_union_pw_aff> argument of
+C<isl_multi_union_pw_aff_apply_multi_aff> is allowed to be zero-dimensional,
+but only if the range of the C<isl_multi_aff> argument
+is also zero-dimensional.
+Similarly for C<isl_multi_union_pw_aff_apply_pw_multi_aff>.
+
+	#include <isl/polynomial.h>
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_set_apply_pw_qpolynomial_fold(
+		__isl_take isl_set *set,
+		__isl_take isl_pw_qpolynomial_fold *pwf,
+		int *tight);
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_map_apply_pw_qpolynomial_fold(
+		__isl_take isl_map *map,
+		__isl_take isl_pw_qpolynomial_fold *pwf,
+		int *tight);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_set_apply_union_pw_qpolynomial_fold(
+		__isl_take isl_union_set *uset,
+		__isl_take isl_union_pw_qpolynomial_fold *upwf,
+		int *tight);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_map_apply_union_pw_qpolynomial_fold(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_union_pw_qpolynomial_fold *upwf,
+		int *tight);
+
+The functions taking a map
+compose the given map with the given piecewise quasipolynomial reduction.
+That is, compute a bound (of the same type as C<pwf> or C<upwf> itself)
+over all elements in the intersection of the range of the map
+and the domain of the piecewise quasipolynomial reduction
+as a function of an element in the domain of the map.
+The functions taking a set compute a bound over all elements in the
+intersection of the set and the domain of the
+piecewise quasipolynomial reduction.
+
+=item * Preimage
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *
+	isl_basic_set_preimage_multi_aff(
+		__isl_take isl_basic_set *bset,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_set *isl_set_preimage_multi_aff(
+		__isl_take isl_set *set,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_set *isl_set_preimage_pw_multi_aff(
+		__isl_take isl_set *set,
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_set *isl_set_preimage_multi_pw_aff(
+		__isl_take isl_set *set,
+		__isl_take isl_multi_pw_aff *mpa);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_set *
+	isl_union_set_preimage_multi_aff(
+		__isl_take isl_union_set *uset,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_union_set *
+	isl_union_set_preimage_pw_multi_aff(
+		__isl_take isl_union_set *uset,
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_union_set *
+	isl_union_set_preimage_union_pw_multi_aff(
+		__isl_take isl_union_set *uset,
+		__isl_take isl_union_pw_multi_aff *upma);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *
+	isl_basic_map_preimage_domain_multi_aff(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_map *isl_map_preimage_domain_multi_aff(
+		__isl_take isl_map *map,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_map *isl_map_preimage_range_multi_aff(
+		__isl_take isl_map *map,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_map *
+	isl_map_preimage_domain_pw_multi_aff(
+		__isl_take isl_map *map,
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_map *
+	isl_map_preimage_range_pw_multi_aff(
+		__isl_take isl_map *map,
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_map *
+	isl_map_preimage_domain_multi_pw_aff(
+		__isl_take isl_map *map,
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_basic_map *
+	isl_basic_map_preimage_range_multi_aff(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_multi_aff *ma);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *
+	isl_union_map_preimage_domain_multi_aff(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_union_map *
+	isl_union_map_preimage_range_multi_aff(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_union_map *
+	isl_union_map_preimage_domain_pw_multi_aff(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_union_map *
+	isl_union_map_preimage_range_pw_multi_aff(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_union_map *
+	isl_union_map_preimage_domain_union_pw_multi_aff(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_union_pw_multi_aff *upma);
+	__isl_give isl_union_map *
+	isl_union_map_preimage_range_union_pw_multi_aff(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_union_pw_multi_aff *upma);
+
+These functions compute the preimage of the given set or map domain/range under
+the given function.  In other words, the expression is plugged
+into the set description or into the domain/range of the map.
+
+=item * Pullback
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_pullback_aff(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_aff *isl_aff_pullback_multi_aff(
+		__isl_take isl_aff *aff,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_pw_aff *isl_pw_aff_pullback_multi_aff(
+		__isl_take isl_pw_aff *pa,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_pw_aff *isl_pw_aff_pullback_pw_multi_aff(
+		__isl_take isl_pw_aff *pa,
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff(
+		__isl_take isl_pw_aff *pa,
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff(
+		__isl_take isl_multi_aff *ma1,
+		__isl_take isl_multi_aff *ma2);
+	__isl_give isl_pw_multi_aff *
+	isl_pw_multi_aff_pullback_multi_aff(
+		__isl_take isl_pw_multi_aff *pma,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_pullback_multi_aff(
+		__isl_take isl_multi_pw_aff *mpa,
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_pw_multi_aff *
+	isl_pw_multi_aff_pullback_pw_multi_aff(
+		__isl_take isl_pw_multi_aff *pma1,
+		__isl_take isl_pw_multi_aff *pma2);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_pullback_pw_multi_aff(
+		__isl_take isl_multi_pw_aff *mpa,
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_pullback_multi_pw_aff(
+		__isl_take isl_multi_pw_aff *mpa1,
+		__isl_take isl_multi_pw_aff *mpa2);
+	__isl_give isl_union_pw_aff *
+	isl_union_pw_aff_pullback_union_pw_multi_aff(
+		__isl_take isl_union_pw_aff *upa,
+		__isl_take isl_union_pw_multi_aff *upma);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_pullback_union_pw_multi_aff(
+		__isl_take isl_union_pw_multi_aff *upma1,
+		__isl_take isl_union_pw_multi_aff *upma2);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_pullback_union_pw_multi_aff(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_union_pw_multi_aff *upma);
+
+These functions precompose the first expression by the second function.
+In other words, the second function is plugged
+into the first expression.
+
+=item * Locus
+
+	#include <isl/aff.h>
+	__isl_give isl_basic_set *isl_aff_eq_basic_set(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_set *isl_aff_eq_set(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_set *isl_aff_ne_set(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_basic_set *isl_aff_le_basic_set(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_set *isl_aff_le_set(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_basic_set *isl_aff_lt_basic_set(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_set *isl_aff_lt_set(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_basic_set *isl_aff_ge_basic_set(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_set *isl_aff_ge_set(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_basic_set *isl_aff_gt_basic_set(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_set *isl_aff_gt_set(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_set *isl_pw_aff_eq_set(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+	__isl_give isl_set *isl_pw_aff_ne_set(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+	__isl_give isl_set *isl_pw_aff_le_set(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+	__isl_give isl_set *isl_pw_aff_lt_set(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+	__isl_give isl_set *isl_pw_aff_ge_set(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+	__isl_give isl_set *isl_pw_aff_gt_set(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+
+	__isl_give isl_set *isl_multi_aff_lex_le_set(
+		__isl_take isl_multi_aff *ma1,
+		__isl_take isl_multi_aff *ma2);
+	__isl_give isl_set *isl_multi_aff_lex_lt_set(
+		__isl_take isl_multi_aff *ma1,
+		__isl_take isl_multi_aff *ma2);
+	__isl_give isl_set *isl_multi_aff_lex_ge_set(
+		__isl_take isl_multi_aff *ma1,
+		__isl_take isl_multi_aff *ma2);
+	__isl_give isl_set *isl_multi_aff_lex_gt_set(
+		__isl_take isl_multi_aff *ma1,
+		__isl_take isl_multi_aff *ma2);
+
+	__isl_give isl_set *isl_pw_aff_list_eq_set(
+		__isl_take isl_pw_aff_list *list1,
+		__isl_take isl_pw_aff_list *list2);
+	__isl_give isl_set *isl_pw_aff_list_ne_set(
+		__isl_take isl_pw_aff_list *list1,
+		__isl_take isl_pw_aff_list *list2);
+	__isl_give isl_set *isl_pw_aff_list_le_set(
+		__isl_take isl_pw_aff_list *list1,
+		__isl_take isl_pw_aff_list *list2);
+	__isl_give isl_set *isl_pw_aff_list_lt_set(
+		__isl_take isl_pw_aff_list *list1,
+		__isl_take isl_pw_aff_list *list2);
+	__isl_give isl_set *isl_pw_aff_list_ge_set(
+		__isl_take isl_pw_aff_list *list1,
+		__isl_take isl_pw_aff_list *list2);
+	__isl_give isl_set *isl_pw_aff_list_gt_set(
+		__isl_take isl_pw_aff_list *list1,
+		__isl_take isl_pw_aff_list *list2);
+
+The function C<isl_aff_ge_basic_set> returns a basic set
+containing those elements in the shared space
+of C<aff1> and C<aff2> where C<aff1> is greater than or equal to C<aff2>.
+The function C<isl_pw_aff_ge_set> returns a set
+containing those elements in the shared domain
+of C<pwaff1> and C<pwaff2> where C<pwaff1> is
+greater than or equal to C<pwaff2>.
+The function C<isl_multi_aff_lex_le_set> returns a set
+containing those elements in the shared domain space
+where C<ma1> is lexicographically smaller than or
+equal to C<ma2>.
+The functions operating on C<isl_pw_aff_list> apply the corresponding
+C<isl_pw_aff> function to each pair of elements in the two lists.
+
+	#include <isl/aff.h>
+	__isl_give isl_map *isl_pw_aff_eq_map(
+		__isl_take isl_pw_aff *pa1,
+		__isl_take isl_pw_aff *pa2);
+	__isl_give isl_map *isl_pw_aff_lt_map(
+		__isl_take isl_pw_aff *pa1,
+		__isl_take isl_pw_aff *pa2);
+	__isl_give isl_map *isl_pw_aff_gt_map(
+		__isl_take isl_pw_aff *pa1,
+		__isl_take isl_pw_aff *pa2);
+
+	__isl_give isl_map *isl_multi_pw_aff_eq_map(
+		__isl_take isl_multi_pw_aff *mpa1,
+		__isl_take isl_multi_pw_aff *mpa2);
+	__isl_give isl_map *isl_multi_pw_aff_lex_lt_map(
+		__isl_take isl_multi_pw_aff *mpa1,
+		__isl_take isl_multi_pw_aff *mpa2);
+	__isl_give isl_map *isl_multi_pw_aff_lex_gt_map(
+		__isl_take isl_multi_pw_aff *mpa1,
+		__isl_take isl_multi_pw_aff *mpa2);
+
+These functions return a map between domain elements of the arguments
+where the function values satisfy the given relation.
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *
+	isl_union_map_eq_at_multi_union_pw_aff(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_multi_union_pw_aff *mupa);
+	__isl_give isl_union_map *
+	isl_union_map_lex_lt_at_multi_union_pw_aff(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_multi_union_pw_aff *mupa);
+	__isl_give isl_union_map *
+	isl_union_map_lex_gt_at_multi_union_pw_aff(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_multi_union_pw_aff *mupa);
+
+These functions select the subset of elements in the union map
+that have an equal or lexicographically smaller function value.
+
+=item * Cartesian Product
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_product(
+		__isl_take isl_space *space1,
+		__isl_take isl_space *space2);
+	__isl_give isl_space *isl_space_domain_product(
+		__isl_take isl_space *space1,
+		__isl_take isl_space *space2);
+	__isl_give isl_space *isl_space_range_product(
+		__isl_take isl_space *space1,
+		__isl_take isl_space *space2);
+
+The functions
+C<isl_space_product>, C<isl_space_domain_product>
+and C<isl_space_range_product> take pairs or relation spaces and
+produce a single relations space, where either the domain, the range
+or both domain and range are wrapped spaces of relations between
+the domains and/or ranges of the input spaces.
+If the product is only constructed over the domain or the range
+then the ranges or the domains of the inputs should be the same.
+The function C<isl_space_product> also accepts a pair of set spaces,
+in which case it returns a wrapped space of a relation between the
+two input spaces.
+
+	#include <isl/set.h>
+	__isl_give isl_set *isl_set_product(
+		__isl_take isl_set *set1,
+		__isl_take isl_set *set2);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_domain_product(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+	__isl_give isl_basic_map *isl_basic_map_range_product(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+	__isl_give isl_basic_map *isl_basic_map_product(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+	__isl_give isl_map *isl_map_domain_product(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+	__isl_give isl_map *isl_map_range_product(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+	__isl_give isl_map *isl_map_product(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_set *isl_union_set_product(
+		__isl_take isl_union_set *uset1,
+		__isl_take isl_union_set *uset2);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_domain_product(
+		__isl_take isl_union_map *umap1,
+		__isl_take isl_union_map *umap2);
+	__isl_give isl_union_map *isl_union_map_range_product(
+		__isl_take isl_union_map *umap1,
+		__isl_take isl_union_map *umap2);
+	__isl_give isl_union_map *isl_union_map_product(
+		__isl_take isl_union_map *umap1,
+		__isl_take isl_union_map *umap2);
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_range_product(
+		__isl_take isl_multi_val *mv1,
+		__isl_take isl_multi_val *mv2);
+	__isl_give isl_multi_val *isl_multi_val_product(
+		__isl_take isl_multi_val *mv1,
+		__isl_take isl_multi_val *mv2);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_range_product(
+		__isl_take isl_multi_aff *ma1,
+		__isl_take isl_multi_aff *ma2);
+	__isl_give isl_multi_aff *isl_multi_aff_product(
+		__isl_take isl_multi_aff *ma1,
+		__isl_take isl_multi_aff *ma2);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_range_product(
+		__isl_take isl_multi_pw_aff *mpa1,
+		__isl_take isl_multi_pw_aff *mpa2);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_product(
+		__isl_take isl_multi_pw_aff *mpa1,
+		__isl_take isl_multi_pw_aff *mpa2);
+	__isl_give isl_pw_multi_aff *
+	isl_pw_multi_aff_range_product(
+		__isl_take isl_pw_multi_aff *pma1,
+		__isl_take isl_pw_multi_aff *pma2);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_product(
+		__isl_take isl_pw_multi_aff *pma1,
+		__isl_take isl_pw_multi_aff *pma2);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_range_product(
+		__isl_take isl_multi_union_pw_aff *mupa1,
+		__isl_take isl_multi_union_pw_aff *mupa2);
+
+The above functions compute the cross product of the given
+sets, relations or functions.  The domains and ranges of the results
+are wrapped maps between domains and ranges of the inputs.
+To obtain a ``flat'' product, use the following functions
+instead.
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_flat_product(
+		__isl_take isl_basic_set *bset1,
+		__isl_take isl_basic_set *bset2);
+	__isl_give isl_set *isl_set_flat_product(
+		__isl_take isl_set *set1,
+		__isl_take isl_set *set2);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_flat_range_product(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+	__isl_give isl_map *isl_map_flat_domain_product(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+	__isl_give isl_map *isl_map_flat_range_product(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+	__isl_give isl_basic_map *isl_basic_map_flat_product(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+	__isl_give isl_map *isl_map_flat_product(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *
+	isl_union_map_flat_domain_product(
+		__isl_take isl_union_map *umap1,
+		__isl_take isl_union_map *umap2);
+	__isl_give isl_union_map *
+	isl_union_map_flat_range_product(
+		__isl_take isl_union_map *umap1,
+		__isl_take isl_union_map *umap2);
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_flat_range_product(
+		__isl_take isl_multi_val *mv1,
+		__isl_take isl_multi_aff *mv2);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_flat_range_product(
+		__isl_take isl_multi_aff *ma1,
+		__isl_take isl_multi_aff *ma2);
+	__isl_give isl_pw_multi_aff *
+	isl_pw_multi_aff_flat_range_product(
+		__isl_take isl_pw_multi_aff *pma1,
+		__isl_take isl_pw_multi_aff *pma2);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_flat_range_product(
+		__isl_take isl_multi_pw_aff *mpa1,
+		__isl_take isl_multi_pw_aff *mpa2);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_flat_range_product(
+		__isl_take isl_union_pw_multi_aff *upma1,
+		__isl_take isl_union_pw_multi_aff *upma2);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_flat_range_product(
+		__isl_take isl_multi_union_pw_aff *mupa1,
+		__isl_take isl_multi_union_pw_aff *mupa2);
+
+	#include <isl/space.h>
+	__isl_give isl_space *isl_space_factor_domain(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_factor_range(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_domain_factor_domain(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_domain_factor_range(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_range_factor_domain(
+		__isl_take isl_space *space);
+	__isl_give isl_space *isl_space_range_factor_range(
+		__isl_take isl_space *space);
+
+The functions C<isl_space_range_factor_domain> and
+C<isl_space_range_factor_range> extract the two arguments from
+the result of a call to C<isl_space_range_product>.
+
+The arguments of a call to a product can be extracted
+from the result using the following functions.
+
+	#include <isl/map.h>
+	__isl_give isl_map *isl_map_factor_domain(
+		__isl_take isl_map *map);
+	__isl_give isl_map *isl_map_factor_range(
+		__isl_take isl_map *map);
+	__isl_give isl_map *isl_map_domain_factor_domain(
+		__isl_take isl_map *map);
+	__isl_give isl_map *isl_map_domain_factor_range(
+		__isl_take isl_map *map);
+	__isl_give isl_map *isl_map_range_factor_domain(
+		__isl_take isl_map *map);
+	__isl_give isl_map *isl_map_range_factor_range(
+		__isl_take isl_map *map);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_factor_domain(
+		__isl_take isl_union_map *umap);
+	__isl_give isl_union_map *isl_union_map_factor_range(
+		__isl_take isl_union_map *umap);
+	__isl_give isl_union_map *
+	isl_union_map_domain_factor_domain(
+		__isl_take isl_union_map *umap);
+	__isl_give isl_union_map *
+	isl_union_map_domain_factor_range(
+		__isl_take isl_union_map *umap);
+	__isl_give isl_union_map *
+	isl_union_map_range_factor_domain(
+		__isl_take isl_union_map *umap);
+	__isl_give isl_union_map *
+	isl_union_map_range_factor_range(
+		__isl_take isl_union_map *umap);
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_factor_range(
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_multi_val *
+	isl_multi_val_range_factor_domain(
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_multi_val *
+	isl_multi_val_range_factor_range(
+		__isl_take isl_multi_val *mv);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_factor_range(
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_multi_aff *
+	isl_multi_aff_range_factor_domain(
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_multi_aff *
+	isl_multi_aff_range_factor_range(
+		__isl_take isl_multi_aff *ma);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_factor_range(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_range_factor_domain(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_range_factor_range(
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_factor_range(
+		__isl_take isl_multi_union_pw_aff *mupa);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_range_factor_domain(
+		__isl_take isl_multi_union_pw_aff *mupa);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_range_factor_range(
+		__isl_take isl_multi_union_pw_aff *mupa);
+
+The splice functions are a generalization of the flat product functions,
+where the second argument may be inserted at any position inside
+the first argument rather than being placed at the end.
+The functions C<isl_multi_val_factor_range>,
+C<isl_multi_aff_factor_range>,
+C<isl_multi_pw_aff_factor_range> and
+C<isl_multi_union_pw_aff_factor_range>
+take functions that live in a set space.
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_range_splice(
+		__isl_take isl_multi_val *mv1, unsigned pos,
+		__isl_take isl_multi_val *mv2);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_range_splice(
+		__isl_take isl_multi_aff *ma1, unsigned pos,
+		__isl_take isl_multi_aff *ma2);
+	__isl_give isl_multi_aff *isl_multi_aff_splice(
+		__isl_take isl_multi_aff *ma1,
+		unsigned in_pos, unsigned out_pos,
+		__isl_take isl_multi_aff *ma2);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_range_splice(
+		__isl_take isl_multi_pw_aff *mpa1, unsigned pos,
+		__isl_take isl_multi_pw_aff *mpa2);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_splice(
+		__isl_take isl_multi_pw_aff *mpa1,
+		unsigned in_pos, unsigned out_pos,
+		__isl_take isl_multi_pw_aff *mpa2);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_range_splice(
+		__isl_take isl_multi_union_pw_aff *mupa1,
+		unsigned pos,
+		__isl_take isl_multi_union_pw_aff *mupa2);
+
+=item * Simplification
+
+When applied to a set or relation,
+the gist operation returns a set or relation that has the
+same intersection with the context as the input set or relation.
+Any implicit equality in the intersection is made explicit in the result,
+while all inequalities that are redundant with respect to the intersection
+are removed.
+In case of union sets and relations, the gist operation is performed
+per space.
+
+When applied to a function,
+the gist operation applies the set gist operation to each of
+the cells in the domain of the input piecewise expression.
+The context is also exploited
+to simplify the expression associated to each cell.
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set *isl_basic_set_gist(
+		__isl_take isl_basic_set *bset,
+		__isl_take isl_basic_set *context);
+	__isl_give isl_set *isl_set_gist(__isl_take isl_set *set,
+		__isl_take isl_set *context);
+	__isl_give isl_set *isl_set_gist_params(
+		__isl_take isl_set *set,
+		__isl_take isl_set *context);
+
+	#include <isl/map.h>
+	__isl_give isl_basic_map *isl_basic_map_gist(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_basic_map *context);
+	__isl_give isl_basic_map *isl_basic_map_gist_domain(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_basic_set *context);
+	__isl_give isl_map *isl_map_gist(__isl_take isl_map *map,
+		__isl_take isl_map *context);
+	__isl_give isl_map *isl_map_gist_params(
+		__isl_take isl_map *map,
+		__isl_take isl_set *context);
+	__isl_give isl_map *isl_map_gist_domain(
+		__isl_take isl_map *map,
+		__isl_take isl_set *context);
+	__isl_give isl_map *isl_map_gist_range(
+		__isl_take isl_map *map,
+		__isl_take isl_set *context);
+
+	#include <isl/union_set.h>
+	__isl_give isl_union_set *isl_union_set_gist(
+		__isl_take isl_union_set *uset,
+		__isl_take isl_union_set *context);
+	__isl_give isl_union_set *isl_union_set_gist_params(
+		__isl_take isl_union_set *uset,
+		__isl_take isl_set *set);
+
+	#include <isl/union_map.h>
+	__isl_give isl_union_map *isl_union_map_gist(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_union_map *context);
+	__isl_give isl_union_map *isl_union_map_gist_params(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_set *set);
+	__isl_give isl_union_map *isl_union_map_gist_domain(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_map *isl_union_map_gist_range(
+		__isl_take isl_union_map *umap,
+		__isl_take isl_union_set *uset);
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_gist_params(
+		__isl_take isl_aff *aff,
+		__isl_take isl_set *context);
+	__isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff,
+		__isl_take isl_set *context);
+	__isl_give isl_multi_aff *isl_multi_aff_gist_params(
+		__isl_take isl_multi_aff *maff,
+		__isl_take isl_set *context);
+	__isl_give isl_multi_aff *isl_multi_aff_gist(
+		__isl_take isl_multi_aff *maff,
+		__isl_take isl_set *context);
+	__isl_give isl_pw_aff *isl_pw_aff_gist_params(
+		__isl_take isl_pw_aff *pwaff,
+		__isl_take isl_set *context);
+	__isl_give isl_pw_aff *isl_pw_aff_gist(
+		__isl_take isl_pw_aff *pwaff,
+		__isl_take isl_set *context);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_gist_params(
+		__isl_take isl_pw_multi_aff *pma,
+		__isl_take isl_set *set);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_gist(
+		__isl_take isl_pw_multi_aff *pma,
+		__isl_take isl_set *set);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_gist_params(
+		__isl_take isl_multi_pw_aff *mpa,
+		__isl_take isl_set *set);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_gist(
+		__isl_take isl_multi_pw_aff *mpa,
+		__isl_take isl_set *set);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_gist(
+		__isl_take isl_union_pw_aff *upa,
+		__isl_take isl_union_set *context);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_gist_params(
+		__isl_take isl_union_pw_aff *upa,
+		__isl_take isl_set *context);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_gist_params(
+		__isl_take isl_union_pw_multi_aff *upma,
+		__isl_take isl_set *context);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_gist(
+		__isl_take isl_union_pw_multi_aff *upma,
+		__isl_take isl_union_set *context);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_gist_params(
+		__isl_take isl_multi_union_pw_aff *aff,
+		__isl_take isl_set *context);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_gist(
+		__isl_take isl_multi_union_pw_aff *aff,
+		__isl_take isl_union_set *context);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_qpolynomial *isl_qpolynomial_gist_params(
+		__isl_take isl_qpolynomial *qp,
+		__isl_take isl_set *context);
+	__isl_give isl_qpolynomial *isl_qpolynomial_gist(
+		__isl_take isl_qpolynomial *qp,
+		__isl_take isl_set *context);
+	__isl_give isl_qpolynomial_fold *
+	isl_qpolynomial_fold_gist_params(
+		__isl_take isl_qpolynomial_fold *fold,
+		__isl_take isl_set *context);
+	__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
+		__isl_take isl_qpolynomial_fold *fold,
+		__isl_take isl_set *context);
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_gist_params(
+		__isl_take isl_pw_qpolynomial *pwqp,
+		__isl_take isl_set *context);
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_gist(
+		__isl_take isl_pw_qpolynomial *pwqp,
+		__isl_take isl_set *context);
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_gist(
+		__isl_take isl_pw_qpolynomial_fold *pwf,
+		__isl_take isl_set *context);
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_gist_params(
+		__isl_take isl_pw_qpolynomial_fold *pwf,
+		__isl_take isl_set *context);
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_gist_params(
+		__isl_take isl_union_pw_qpolynomial *upwqp,
+		__isl_take isl_set *context);
+	__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_gist(
+		__isl_take isl_union_pw_qpolynomial *upwqp,
+		__isl_take isl_union_set *context);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_gist(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf,
+		__isl_take isl_union_set *context);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_gist_params(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf,
+		__isl_take isl_set *context);
+
+=item * Binary Arithmetic Operations
+
+	#include <isl/set.h>
+	__isl_give isl_set *isl_set_sum(
+		__isl_take isl_set *set1,
+		__isl_take isl_set *set2);
+	#include <isl/map.h>
+	__isl_give isl_map *isl_map_sum(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+
+C<isl_set_sum> computes the Minkowski sum of its two arguments,
+i.e., the set containing the sums of pairs of elements from
+C<set1> and C<set2>.
+The domain of the result of C<isl_map_sum> is the intersection
+of the domains of its two arguments.  The corresponding range
+elements are the sums of the corresponding range elements
+in the two arguments.
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_add(
+		__isl_take isl_multi_val *mv1,
+		__isl_take isl_multi_val *mv2);
+	__isl_give isl_multi_val *isl_multi_val_sub(
+		__isl_take isl_multi_val *mv1,
+		__isl_take isl_multi_val *mv2);
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_add(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_multi_aff *isl_multi_aff_add(
+		__isl_take isl_multi_aff *maff1,
+		__isl_take isl_multi_aff *maff2);
+	__isl_give isl_pw_aff *isl_pw_aff_add(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_add(
+		__isl_take isl_multi_pw_aff *mpa1,
+		__isl_take isl_multi_pw_aff *mpa2);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_add(
+		__isl_take isl_pw_multi_aff *pma1,
+		__isl_take isl_pw_multi_aff *pma2);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_add(
+		__isl_take isl_union_pw_aff *upa1,
+		__isl_take isl_union_pw_aff *upa2);
+	__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_add(
+		__isl_take isl_union_pw_multi_aff *upma1,
+		__isl_take isl_union_pw_multi_aff *upma2);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_add(
+		__isl_take isl_multi_union_pw_aff *mupa1,
+		__isl_take isl_multi_union_pw_aff *mupa2);
+	__isl_give isl_pw_aff *isl_pw_aff_min(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+	__isl_give isl_pw_aff *isl_pw_aff_max(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+	__isl_give isl_aff *isl_aff_sub(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_multi_aff *isl_multi_aff_sub(
+		__isl_take isl_multi_aff *ma1,
+		__isl_take isl_multi_aff *ma2);
+	__isl_give isl_pw_aff *isl_pw_aff_sub(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_sub(
+		__isl_take isl_multi_pw_aff *mpa1,
+		__isl_take isl_multi_pw_aff *mpa2);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub(
+		__isl_take isl_pw_multi_aff *pma1,
+		__isl_take isl_pw_multi_aff *pma2);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_sub(
+		__isl_take isl_union_pw_aff *upa1,
+		__isl_take isl_union_pw_aff *upa2);
+	__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_sub(
+		__isl_take isl_union_pw_multi_aff *upma1,
+		__isl_take isl_union_pw_multi_aff *upma2);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_sub(
+		__isl_take isl_multi_union_pw_aff *mupa1,
+		__isl_take isl_multi_union_pw_aff *mupa2);
+
+C<isl_aff_sub> subtracts the second argument from the first.
+
+	#include <isl/polynomial.h>
+	__isl_give isl_qpolynomial *isl_qpolynomial_add(
+		__isl_take isl_qpolynomial *qp1,
+		__isl_take isl_qpolynomial *qp2);
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add(
+		__isl_take isl_pw_qpolynomial *pwqp1,
+		__isl_take isl_pw_qpolynomial *pwqp2);
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_disjoint(
+		__isl_take isl_pw_qpolynomial *pwqp1,
+		__isl_take isl_pw_qpolynomial *pwqp2);
+	__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add(
+		__isl_take isl_pw_qpolynomial_fold *pwf1,
+		__isl_take isl_pw_qpolynomial_fold *pwf2);
+	__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_add(
+		__isl_take isl_union_pw_qpolynomial *upwqp1,
+		__isl_take isl_union_pw_qpolynomial *upwqp2);
+	__isl_give isl_qpolynomial *isl_qpolynomial_sub(
+		__isl_take isl_qpolynomial *qp1,
+		__isl_take isl_qpolynomial *qp2);
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_sub(
+		__isl_take isl_pw_qpolynomial *pwqp1,
+		__isl_take isl_pw_qpolynomial *pwqp2);
+	__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_sub(
+		__isl_take isl_union_pw_qpolynomial *upwqp1,
+		__isl_take isl_union_pw_qpolynomial *upwqp2);
+	__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold(
+		__isl_take isl_pw_qpolynomial_fold *pwf1,
+		__isl_take isl_pw_qpolynomial_fold *pwf2);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_fold(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf1,
+		__isl_take isl_union_pw_qpolynomial_fold *upwf2);
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_aff_union_add(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add(
+		__isl_take isl_pw_multi_aff *pma1,
+		__isl_take isl_pw_multi_aff *pma2);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_union_add(
+		__isl_take isl_union_pw_aff *upa1,
+		__isl_take isl_union_pw_aff *upa2);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_union_add(
+		__isl_take isl_union_pw_multi_aff *upma1,
+		__isl_take isl_union_pw_multi_aff *upma2);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_union_add(
+		__isl_take isl_multi_union_pw_aff *mupa1,
+		__isl_take isl_multi_union_pw_aff *mupa2);
+	__isl_give isl_pw_aff *isl_pw_aff_union_min(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+	__isl_give isl_pw_aff *isl_pw_aff_union_max(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+
+The function C<isl_pw_aff_union_max> computes a piecewise quasi-affine
+expression with a domain that is the union of those of C<pwaff1> and
+C<pwaff2> and such that on each cell, the quasi-affine expression is
+the maximum of those of C<pwaff1> and C<pwaff2>.  If only one of
+C<pwaff1> or C<pwaff2> is defined on a given cell, then the
+associated expression is the defined one.
+This in contrast to the C<isl_pw_aff_max> function, which is
+only defined on the shared definition domain of the arguments.
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_add_val(
+		__isl_take isl_multi_val *mv,
+		__isl_take isl_val *v);
+	__isl_give isl_multi_val *isl_multi_val_mod_val(
+		__isl_take isl_multi_val *mv,
+		__isl_take isl_val *v);
+	__isl_give isl_multi_val *isl_multi_val_scale_val(
+		__isl_take isl_multi_val *mv,
+		__isl_take isl_val *v);
+	__isl_give isl_multi_val *isl_multi_val_scale_down_val(
+		__isl_take isl_multi_val *mv,
+		__isl_take isl_val *v);
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_mod_val(__isl_take isl_aff *aff,
+		__isl_take isl_val *mod);
+	__isl_give isl_pw_aff *isl_pw_aff_mod_val(
+		__isl_take isl_pw_aff *pa,
+		__isl_take isl_val *mod);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_mod_val(
+		__isl_take isl_union_pw_aff *upa,
+		__isl_take isl_val *f);
+	__isl_give isl_aff *isl_aff_scale_val(__isl_take isl_aff *aff,
+		__isl_take isl_val *v);
+	__isl_give isl_multi_aff *isl_multi_aff_scale_val(
+		__isl_take isl_multi_aff *ma,
+		__isl_take isl_val *v);
+	__isl_give isl_pw_aff *isl_pw_aff_scale_val(
+		__isl_take isl_pw_aff *pa, __isl_take isl_val *v);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_scale_val(
+		__isl_take isl_multi_pw_aff *mpa,
+		__isl_take isl_val *v);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_val(
+		__isl_take isl_pw_multi_aff *pma,
+		__isl_take isl_val *v);
+	__isl_give isl_union_pw_multi_aff *
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_scale_val(
+		__isl_take isl_union_pw_aff *upa,
+		__isl_take isl_val *f);
+	isl_union_pw_multi_aff_scale_val(
+		__isl_take isl_union_pw_multi_aff *upma,
+		__isl_take isl_val *val);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_scale_val(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_val *v);
+	__isl_give isl_aff *isl_aff_scale_down_ui(
+		__isl_take isl_aff *aff, unsigned f);
+	__isl_give isl_aff *isl_aff_scale_down_val(
+		__isl_take isl_aff *aff, __isl_take isl_val *v);
+	__isl_give isl_multi_aff *isl_multi_aff_scale_down_val(
+		__isl_take isl_multi_aff *ma,
+		__isl_take isl_val *v);
+	__isl_give isl_pw_aff *isl_pw_aff_scale_down_val(
+		__isl_take isl_pw_aff *pa,
+		__isl_take isl_val *f);
+	__isl_give isl_multi_pw_aff *isl_multi_pw_aff_scale_down_val(
+		__isl_take isl_multi_pw_aff *mpa,
+		__isl_take isl_val *v);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_down_val(
+		__isl_take isl_pw_multi_aff *pma,
+		__isl_take isl_val *v);
+	__isl_give isl_union_pw_aff *isl_union_pw_aff_scale_down_val(
+		__isl_take isl_union_pw_aff *upa,
+		__isl_take isl_val *v);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_scale_down_val(
+		__isl_take isl_union_pw_multi_aff *upma,
+		__isl_take isl_val *val);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_scale_down_val(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_val *v);
+
+	#include <isl/polynomial.h>
+	__isl_give isl_qpolynomial *isl_qpolynomial_scale_val(
+		__isl_take isl_qpolynomial *qp,
+		__isl_take isl_val *v);
+	__isl_give isl_qpolynomial_fold *
+	isl_qpolynomial_fold_scale_val(
+		__isl_take isl_qpolynomial_fold *fold,
+		__isl_take isl_val *v);
+	__isl_give isl_pw_qpolynomial *
+	isl_pw_qpolynomial_scale_val(
+		__isl_take isl_pw_qpolynomial *pwqp,
+		__isl_take isl_val *v);
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_scale_val(
+		__isl_take isl_pw_qpolynomial_fold *pwf,
+		__isl_take isl_val *v);
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_scale_val(
+		__isl_take isl_union_pw_qpolynomial *upwqp,
+		__isl_take isl_val *v);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_scale_val(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf,
+		__isl_take isl_val *v);
+	__isl_give isl_qpolynomial *
+	isl_qpolynomial_scale_down_val(
+		__isl_take isl_qpolynomial *qp,
+		__isl_take isl_val *v);
+	__isl_give isl_qpolynomial_fold *
+	isl_qpolynomial_fold_scale_down_val(
+		__isl_take isl_qpolynomial_fold *fold,
+		__isl_take isl_val *v);
+	__isl_give isl_pw_qpolynomial *
+	isl_pw_qpolynomial_scale_down_val(
+		__isl_take isl_pw_qpolynomial *pwqp,
+		__isl_take isl_val *v);
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_fold_scale_down_val(
+		__isl_take isl_pw_qpolynomial_fold *pwf,
+		__isl_take isl_val *v);
+	__isl_give isl_union_pw_qpolynomial *
+	isl_union_pw_qpolynomial_scale_down_val(
+		__isl_take isl_union_pw_qpolynomial *upwqp,
+		__isl_take isl_val *v);
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_scale_down_val(
+		__isl_take isl_union_pw_qpolynomial_fold *upwf,
+		__isl_take isl_val *v);
+
+	#include <isl/val.h>
+	__isl_give isl_multi_val *isl_multi_val_mod_multi_val(
+		__isl_take isl_multi_val *mv1,
+		__isl_take isl_multi_val *mv2);
+	__isl_give isl_multi_val *isl_multi_val_scale_multi_val(
+		__isl_take isl_multi_val *mv1,
+		__isl_take isl_multi_val *mv2);
+	__isl_give isl_multi_val *
+	isl_multi_val_scale_down_multi_val(
+		__isl_take isl_multi_val *mv1,
+		__isl_take isl_multi_val *mv2);
+
+	#include <isl/aff.h>
+	__isl_give isl_multi_aff *isl_multi_aff_mod_multi_val(
+		__isl_take isl_multi_aff *ma,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_mod_multi_val(
+		__isl_take isl_multi_union_pw_aff *upma,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_mod_multi_val(
+		__isl_take isl_multi_pw_aff *mpa,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_multi_aff *isl_multi_aff_scale_multi_val(
+		__isl_take isl_multi_aff *ma,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_pw_multi_aff *
+	isl_pw_multi_aff_scale_multi_val(
+		__isl_take isl_pw_multi_aff *pma,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_scale_multi_val(
+		__isl_take isl_multi_pw_aff *mpa,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_scale_multi_val(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_union_pw_multi_aff *
+	isl_union_pw_multi_aff_scale_multi_val(
+		__isl_take isl_union_pw_multi_aff *upma,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_multi_aff *
+	isl_multi_aff_scale_down_multi_val(
+		__isl_take isl_multi_aff *ma,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_multi_pw_aff *
+	isl_multi_pw_aff_scale_down_multi_val(
+		__isl_take isl_multi_pw_aff *mpa,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_multi_union_pw_aff *
+	isl_multi_union_pw_aff_scale_down_multi_val(
+		__isl_take isl_multi_union_pw_aff *mupa,
+		__isl_take isl_multi_val *mv);
+
+C<isl_multi_aff_scale_multi_val> scales the elements of C<ma>
+by the corresponding elements of C<mv>.
+
+	#include <isl/aff.h>
+	__isl_give isl_aff *isl_aff_mul(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_aff *isl_aff_div(
+		__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2);
+	__isl_give isl_pw_aff *isl_pw_aff_mul(
+		__isl_take isl_pw_aff *pwaff1,
+		__isl_take isl_pw_aff *pwaff2);
+	__isl_give isl_pw_aff *isl_pw_aff_div(
+		__isl_take isl_pw_aff *pa1,
+		__isl_take isl_pw_aff *pa2);
+	__isl_give isl_pw_aff *isl_pw_aff_tdiv_q(
+		__isl_take isl_pw_aff *pa1,
+		__isl_take isl_pw_aff *pa2);
+	__isl_give isl_pw_aff *isl_pw_aff_tdiv_r(
+		__isl_take isl_pw_aff *pa1,
+		__isl_take isl_pw_aff *pa2);
+
+When multiplying two affine expressions, at least one of the two needs
+to be a constant.  Similarly, when dividing an affine expression by another,
+the second expression needs to be a constant.
+C<isl_pw_aff_tdiv_q> computes the quotient of an integer division with
+rounding towards zero.  C<isl_pw_aff_tdiv_r> computes the corresponding
+remainder.
+
+	#include <isl/polynomial.h>
+	__isl_give isl_qpolynomial *isl_qpolynomial_mul(
+		__isl_take isl_qpolynomial *qp1,
+		__isl_take isl_qpolynomial *qp2);
+	__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_mul(
+		__isl_take isl_pw_qpolynomial *pwqp1,
+		__isl_take isl_pw_qpolynomial *pwqp2);
+	__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_mul(
+		__isl_take isl_union_pw_qpolynomial *upwqp1,
+		__isl_take isl_union_pw_qpolynomial *upwqp2);
+
+=back
+
+=head3 Lexicographic Optimization
+
+Given a (basic) set C<set> (or C<bset>) and a zero-dimensional domain C<dom>,
+the following functions
+compute a set that contains the lexicographic minimum or maximum
+of the elements in C<set> (or C<bset>) for those values of the parameters
+that satisfy C<dom>.
+If C<empty> is not C<NULL>, then C<*empty> is assigned a set
+that contains the parameter values in C<dom> for which C<set> (or C<bset>)
+has no elements.
+In other words, the union of the parameter values
+for which the result is non-empty and of C<*empty>
+is equal to C<dom>.
+
+	#include <isl/set.h>
+	__isl_give isl_set *isl_basic_set_partial_lexmin(
+		__isl_take isl_basic_set *bset,
+		__isl_take isl_basic_set *dom,
+		__isl_give isl_set **empty);
+	__isl_give isl_set *isl_basic_set_partial_lexmax(
+		__isl_take isl_basic_set *bset,
+		__isl_take isl_basic_set *dom,
+		__isl_give isl_set **empty);
+	__isl_give isl_set *isl_set_partial_lexmin(
+		__isl_take isl_set *set, __isl_take isl_set *dom,
+		__isl_give isl_set **empty);
+	__isl_give isl_set *isl_set_partial_lexmax(
+		__isl_take isl_set *set, __isl_take isl_set *dom,
+		__isl_give isl_set **empty);
+
+Given a (basic) set C<set> (or C<bset>), the following functions simply
+return a set containing the lexicographic minimum or maximum
+of the elements in C<set> (or C<bset>).
+In case of union sets, the optimum is computed per space.
+
+	#include <isl/set.h>
+	__isl_give isl_set *isl_basic_set_lexmin(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_set *isl_basic_set_lexmax(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_set *isl_set_lexmin(
+		__isl_take isl_set *set);
+	__isl_give isl_set *isl_set_lexmax(
+		__isl_take isl_set *set);
+	__isl_give isl_union_set *isl_union_set_lexmin(
+		__isl_take isl_union_set *uset);
+	__isl_give isl_union_set *isl_union_set_lexmax(
+		__isl_take isl_union_set *uset);
+
+Given a (basic) relation C<map> (or C<bmap>) and a domain C<dom>,
+the following functions
+compute a relation that maps each element of C<dom>
+to the single lexicographic minimum or maximum
+of the elements that are associated to that same
+element in C<map> (or C<bmap>).
+If C<empty> is not C<NULL>, then C<*empty> is assigned a set
+that contains the elements in C<dom> that do not map
+to any elements in C<map> (or C<bmap>).
+In other words, the union of the domain of the result and of C<*empty>
+is equal to C<dom>.
+
+	#include <isl/map.h>
+	__isl_give isl_map *isl_basic_map_partial_lexmax(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_basic_set *dom,
+		__isl_give isl_set **empty);
+	__isl_give isl_map *isl_basic_map_partial_lexmin(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_basic_set *dom,
+		__isl_give isl_set **empty);
+	__isl_give isl_map *isl_map_partial_lexmax(
+		__isl_take isl_map *map, __isl_take isl_set *dom,
+		__isl_give isl_set **empty);
+	__isl_give isl_map *isl_map_partial_lexmin(
+		__isl_take isl_map *map, __isl_take isl_set *dom,
+		__isl_give isl_set **empty);
+
+Given a (basic) map C<map> (or C<bmap>), the following functions simply
+return a map mapping each element in the domain of
+C<map> (or C<bmap>) to the lexicographic minimum or maximum
+of all elements associated to that element.
+In case of union relations, the optimum is computed per space.
+
+	#include <isl/map.h>
+	__isl_give isl_map *isl_basic_map_lexmin(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_map *isl_basic_map_lexmax(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_map *isl_map_lexmin(
+		__isl_take isl_map *map);
+	__isl_give isl_map *isl_map_lexmax(
+		__isl_take isl_map *map);
+	__isl_give isl_union_map *isl_union_map_lexmin(
+		__isl_take isl_union_map *umap);
+	__isl_give isl_union_map *isl_union_map_lexmax(
+		__isl_take isl_union_map *umap);
+
+The following functions return their result in the form of
+a piecewise multi-affine expression,
+but are otherwise equivalent to the corresponding functions
+returning a basic set or relation.
+
+	#include <isl/set.h>
+	__isl_give isl_pw_multi_aff *
+	isl_basic_set_partial_lexmin_pw_multi_aff(
+		__isl_take isl_basic_set *bset,
+		__isl_take isl_basic_set *dom,
+		__isl_give isl_set **empty);
+	__isl_give isl_pw_multi_aff *
+	isl_basic_set_partial_lexmax_pw_multi_aff(
+		__isl_take isl_basic_set *bset,
+		__isl_take isl_basic_set *dom,
+		__isl_give isl_set **empty);
+	__isl_give isl_pw_multi_aff *isl_set_lexmin_pw_multi_aff(
+		__isl_take isl_set *set);
+	__isl_give isl_pw_multi_aff *isl_set_lexmax_pw_multi_aff(
+		__isl_take isl_set *set);
+
+	#include <isl/map.h>
+	__isl_give isl_pw_multi_aff *
+	isl_basic_map_lexmin_pw_multi_aff(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_pw_multi_aff *
+	isl_basic_map_partial_lexmin_pw_multi_aff(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_basic_set *dom,
+		__isl_give isl_set **empty);
+	__isl_give isl_pw_multi_aff *
+	isl_basic_map_partial_lexmax_pw_multi_aff(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_basic_set *dom,
+		__isl_give isl_set **empty);
+	__isl_give isl_pw_multi_aff *isl_map_lexmin_pw_multi_aff(
+		__isl_take isl_map *map);
+	__isl_give isl_pw_multi_aff *isl_map_lexmax_pw_multi_aff(
+		__isl_take isl_map *map);
+
+The following functions return the lexicographic minimum or maximum
+on the shared domain of the inputs and the single defined function
+on those parts of the domain where only a single function is defined.
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin(
+		__isl_take isl_pw_multi_aff *pma1,
+		__isl_take isl_pw_multi_aff *pma2);
+	__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmax(
+		__isl_take isl_pw_multi_aff *pma1,
+		__isl_take isl_pw_multi_aff *pma2);
+
+If the input to a lexicographic optimization problem has
+multiple constraints with the same coefficients for the optimized
+variables, then, by default, this symmetry is exploited by
+replacing those constraints by a single constraint with
+an abstract bound, which is in turn bounded by the corresponding terms
+in the original constraints.
+Without this optimization, the solver would typically consider
+all possible orderings of those original bounds, resulting in a needless
+decomposition of the domain.
+However, the optimization can also result in slowdowns since
+an extra parameter is introduced that may get used in additional
+integer divisions.
+The following option determines whether symmetry detection is applied
+during lexicographic optimization.
+
+	#include <isl/options.h>
+	isl_stat isl_options_set_pip_symmetry(isl_ctx *ctx,
+		int val);
+	int isl_options_get_pip_symmetry(isl_ctx *ctx);
+
+=begin latex
+
+See also \autoref{s:offline}.
+
+=end latex
+
+=head2 Ternary Operations
+
+	#include <isl/aff.h>
+	__isl_give isl_pw_aff *isl_pw_aff_cond(
+		__isl_take isl_pw_aff *cond,
+		__isl_take isl_pw_aff *pwaff_true,
+		__isl_take isl_pw_aff *pwaff_false);
+
+The function C<isl_pw_aff_cond> performs a conditional operator
+and returns an expression that is equal to C<pwaff_true>
+for elements where C<cond> is non-zero and equal to C<pwaff_false> for elements
+where C<cond> is zero.
+
+=head2 Lists
+
+Lists are defined over several element types, including
+C<isl_val>, C<isl_id>, C<isl_aff>, C<isl_pw_aff>, C<isl_union_pw_aff>,
+C<isl_union_pw_multi_aff>, C<isl_constraint>,
+C<isl_basic_set>, C<isl_set>, C<isl_basic_map>, C<isl_map>, C<isl_union_set>,
+C<isl_union_map>, C<isl_ast_expr> and C<isl_ast_node>.
+Here we take lists of C<isl_set>s as an example.
+Lists can be created, copied, modified and freed using the following functions.
+
+	#include <isl/set.h>
+	__isl_give isl_set_list *isl_set_list_from_set(
+		__isl_take isl_set *el);
+	__isl_give isl_set_list *isl_set_list_alloc(
+		isl_ctx *ctx, int n);
+	__isl_give isl_set_list *isl_set_list_copy(
+		__isl_keep isl_set_list *list);
+	__isl_give isl_set_list *isl_set_list_insert(
+		__isl_take isl_set_list *list, unsigned pos,
+		__isl_take isl_set *el);
+	__isl_give isl_set_list *isl_set_list_add(
+		__isl_take isl_set_list *list,
+		__isl_take isl_set *el);
+	__isl_give isl_set_list *isl_set_list_drop(
+		__isl_take isl_set_list *list,
+		unsigned first, unsigned n);
+	__isl_give isl_set_list *isl_set_list_set_set(
+		__isl_take isl_set_list *list, int index,
+		__isl_take isl_set *set);
+	__isl_give isl_set_list *isl_set_list_concat(
+		__isl_take isl_set_list *list1,
+		__isl_take isl_set_list *list2);
+	__isl_give isl_set_list *isl_set_list_map(
+		__isl_take isl_set_list *list,
+		__isl_give isl_set *(*fn)(__isl_take isl_set *el,
+			void *user),
+		void *user);
+	__isl_give isl_set_list *isl_set_list_sort(
+		__isl_take isl_set_list *list,
+		int (*cmp)(__isl_keep isl_set *a,
+			__isl_keep isl_set *b, void *user),
+		void *user);
+	__isl_null isl_set_list *isl_set_list_free(
+		__isl_take isl_set_list *list);
+
+C<isl_set_list_alloc> creates an empty list with an initial capacity
+for C<n> elements.  C<isl_set_list_insert> and C<isl_set_list_add>
+add elements to a list, increasing its capacity as needed.
+C<isl_set_list_from_set> creates a list with a single element.
+
+Lists can be inspected using the following functions.
+
+	#include <isl/set.h>
+	int isl_set_list_n_set(__isl_keep isl_set_list *list);
+	__isl_give isl_set *isl_set_list_get_set(
+		__isl_keep isl_set_list *list, int index);
+	isl_stat isl_set_list_foreach(__isl_keep isl_set_list *list,
+		isl_stat (*fn)(__isl_take isl_set *el, void *user),
+		void *user);
+	isl_stat isl_set_list_foreach_scc(
+		__isl_keep isl_set_list *list,
+		isl_bool (*follows)(__isl_keep isl_set *a,
+			__isl_keep isl_set *b, void *user),
+		void *follows_user,
+		isl_stat (*fn)(__isl_take isl_set *el, void *user),
+		void *fn_user);
+
+The function C<isl_set_list_foreach_scc> calls C<fn> on each of the
+strongly connected components of the graph with as vertices the elements
+of C<list> and a directed edge from vertex C<b> to vertex C<a>
+iff C<follows(a, b)> returns C<isl_bool_true>.  The callbacks C<follows> and
+C<fn> should return C<isl_bool_error> or C<isl_stat_error> on error.
+
+Lists can be printed using
+
+	#include <isl/set.h>
+	__isl_give isl_printer *isl_printer_print_set_list(
+		__isl_take isl_printer *p,
+		__isl_keep isl_set_list *list);
+
+=head2 Associative arrays
+
+Associative arrays map isl objects of a specific type to isl objects
+of some (other) specific type.  They are defined for several pairs
+of types, including (C<isl_map>, C<isl_basic_set>),
+(C<isl_id>, C<isl_ast_expr>),
+(C<isl_id>, C<isl_id>) and
+(C<isl_id>, C<isl_pw_aff>).
+Here, we take associative arrays that map C<isl_id>s to C<isl_ast_expr>s
+as an example.
+
+Associative arrays can be created, copied and freed using
+the following functions.
+
+	#include <isl/id_to_ast_expr.h>
+	__isl_give isl_id_to_ast_expr *isl_id_to_ast_expr_alloc(
+		isl_ctx *ctx, int min_size);
+	__isl_give isl_id_to_ast_expr *isl_id_to_ast_expr_copy(
+		__isl_keep isl_id_to_ast_expr *id2expr);
+	__isl_null isl_id_to_ast_expr *isl_id_to_ast_expr_free(
+		__isl_take isl_id_to_ast_expr *id2expr);
+
+The C<min_size> argument to C<isl_id_to_ast_expr_alloc> can be used
+to specify the expected size of the associative array.
+The associative array will be grown automatically as needed.
+
+Associative arrays can be inspected using the following functions.
+
+	#include <isl/id_to_ast_expr.h>
+	__isl_give isl_maybe_isl_ast_expr
+	isl_id_to_ast_expr_try_get(
+		__isl_keep isl_id_to_ast_expr *id2expr,
+		__isl_keep isl_id *key);
+	isl_bool isl_id_to_ast_expr_has(
+		__isl_keep isl_id_to_ast_expr *id2expr,
+		__isl_keep isl_id *key);
+	__isl_give isl_ast_expr *isl_id_to_ast_expr_get(
+		__isl_keep isl_id_to_ast_expr *id2expr,
+		__isl_take isl_id *key);
+	isl_stat isl_id_to_ast_expr_foreach(
+		__isl_keep isl_id_to_ast_expr *id2expr,
+		isl_stat (*fn)(__isl_take isl_id *key,
+			__isl_take isl_ast_expr *val, void *user),
+		void *user);
+
+The function C<isl_id_to_ast_expr_try_get> returns a structure
+containing two elements, C<valid> and C<value>.
+If there is a value associated to the key, then C<valid>
+is set to C<isl_bool_true> and C<value> contains a copy of
+the associated value.  Otherwise C<value> is C<NULL> and
+C<valid> may be C<isl_bool_error> or C<isl_bool_false> depending
+on whether some error has occurred or there simply is no associated value.
+The function C<isl_id_to_ast_expr_has> returns the C<valid> field
+in the structure and
+the function C<isl_id_to_ast_expr_get> returns the C<value> field.
+
+Associative arrays can be modified using the following functions.
+
+	#include <isl/id_to_ast_expr.h>
+	__isl_give isl_id_to_ast_expr *isl_id_to_ast_expr_set(
+		__isl_take isl_id_to_ast_expr *id2expr,
+		__isl_take isl_id *key,
+		__isl_take isl_ast_expr *val);
+	__isl_give isl_id_to_ast_expr *isl_id_to_ast_expr_drop(
+		__isl_take isl_id_to_ast_expr *id2expr,
+		__isl_take isl_id *key);
+
+Associative arrays can be printed using the following function.
+
+	#include <isl/id_to_ast_expr.h>
+	__isl_give isl_printer *isl_printer_print_id_to_ast_expr(
+		__isl_take isl_printer *p,
+		__isl_keep isl_id_to_ast_expr *id2expr);
+
+=head2 Vectors
+
+Vectors can be created, copied and freed using the following functions.
+
+	#include <isl/vec.h>
+	__isl_give isl_vec *isl_vec_alloc(isl_ctx *ctx,
+		unsigned size);
+	__isl_give isl_vec *isl_vec_copy(__isl_keep isl_vec *vec);
+	__isl_null isl_vec *isl_vec_free(__isl_take isl_vec *vec);
+
+Note that the elements of a newly created vector may have arbitrary values.
+The elements can be changed and inspected using the following functions.
+
+	int isl_vec_size(__isl_keep isl_vec *vec);
+	__isl_give isl_val *isl_vec_get_element_val(
+		__isl_keep isl_vec *vec, int pos);
+	__isl_give isl_vec *isl_vec_set_element_si(
+		__isl_take isl_vec *vec, int pos, int v);
+	__isl_give isl_vec *isl_vec_set_element_val(
+		__isl_take isl_vec *vec, int pos,
+		__isl_take isl_val *v);
+	__isl_give isl_vec *isl_vec_set_si(__isl_take isl_vec *vec,
+		int v);
+	__isl_give isl_vec *isl_vec_set_val(
+		__isl_take isl_vec *vec, __isl_take isl_val *v);
+	int isl_vec_cmp_element(__isl_keep isl_vec *vec1,
+		__isl_keep isl_vec *vec2, int pos);
+
+C<isl_vec_get_element> will return a negative value if anything went wrong.
+In that case, the value of C<*v> is undefined.
+
+The following function can be used to concatenate two vectors.
+
+	__isl_give isl_vec *isl_vec_concat(__isl_take isl_vec *vec1,
+		__isl_take isl_vec *vec2);
+
+=head2 Matrices
+
+Matrices can be created, copied and freed using the following functions.
+
+	#include <isl/mat.h>
+	__isl_give isl_mat *isl_mat_alloc(isl_ctx *ctx,
+		unsigned n_row, unsigned n_col);
+	__isl_give isl_mat *isl_mat_copy(__isl_keep isl_mat *mat);
+	__isl_null isl_mat *isl_mat_free(__isl_take isl_mat *mat);
+
+Note that the elements of a newly created matrix may have arbitrary values.
+The elements can be changed and inspected using the following functions.
+
+	int isl_mat_rows(__isl_keep isl_mat *mat);
+	int isl_mat_cols(__isl_keep isl_mat *mat);
+	__isl_give isl_val *isl_mat_get_element_val(
+		__isl_keep isl_mat *mat, int row, int col);
+	__isl_give isl_mat *isl_mat_set_element_si(__isl_take isl_mat *mat,
+		int row, int col, int v);
+	__isl_give isl_mat *isl_mat_set_element_val(
+		__isl_take isl_mat *mat, int row, int col,
+		__isl_take isl_val *v);
+
+C<isl_mat_get_element> will return a negative value if anything went wrong.
+In that case, the value of C<*v> is undefined.
+
+The following function can be used to compute the (right) inverse
+of a matrix, i.e., a matrix such that the product of the original
+and the inverse (in that order) is a multiple of the identity matrix.
+The input matrix is assumed to be of full row-rank.
+
+	__isl_give isl_mat *isl_mat_right_inverse(__isl_take isl_mat *mat);
+
+The following function can be used to compute the (right) kernel
+(or null space) of a matrix, i.e., a matrix such that the product of
+the original and the kernel (in that order) is the zero matrix.
+
+	__isl_give isl_mat *isl_mat_right_kernel(__isl_take isl_mat *mat);
+
+=head2 Bounds on Piecewise Quasipolynomials and Piecewise Quasipolynomial Reductions
+
+The following functions determine
+an upper or lower bound on a quasipolynomial over its domain.
+
+	__isl_give isl_pw_qpolynomial_fold *
+	isl_pw_qpolynomial_bound(
+		__isl_take isl_pw_qpolynomial *pwqp,
+		enum isl_fold type, int *tight);
+
+	__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_bound(
+		__isl_take isl_union_pw_qpolynomial *upwqp,
+		enum isl_fold type, int *tight);
+
+The C<type> argument may be either C<isl_fold_min> or C<isl_fold_max>.
+If C<tight> is not C<NULL>, then C<*tight> is set to C<1>
+is the returned bound is known be tight, i.e., for each value
+of the parameters there is at least
+one element in the domain that reaches the bound.
+If the domain of C<pwqp> is not wrapping, then the bound is computed
+over all elements in that domain and the result has a purely parametric
+domain.  If the domain of C<pwqp> is wrapping, then the bound is
+computed over the range of the wrapped relation.  The domain of the
+wrapped relation becomes the domain of the result.
+
+=head2 Parametric Vertex Enumeration
+
+The parametric vertex enumeration described in this section
+is mainly intended to be used internally and by the C<barvinok>
+library.
+
+	#include <isl/vertices.h>
+	__isl_give isl_vertices *isl_basic_set_compute_vertices(
+		__isl_keep isl_basic_set *bset);
+
+The function C<isl_basic_set_compute_vertices> performs the
+actual computation of the parametric vertices and the chamber
+decomposition and stores the result in an C<isl_vertices> object.
+This information can be queried by either iterating over all
+the vertices or iterating over all the chambers or cells
+and then iterating over all vertices that are active on the chamber.
+
+	isl_stat isl_vertices_foreach_vertex(
+		__isl_keep isl_vertices *vertices,
+		isl_stat (*fn)(__isl_take isl_vertex *vertex,
+			void *user), void *user);
+
+	isl_stat isl_vertices_foreach_cell(
+		__isl_keep isl_vertices *vertices,
+		isl_stat (*fn)(__isl_take isl_cell *cell,
+			void *user), void *user);
+	isl_stat isl_cell_foreach_vertex(__isl_keep isl_cell *cell,
+		isl_stat (*fn)(__isl_take isl_vertex *vertex,
+			void *user), void *user);
+
+Other operations that can be performed on an C<isl_vertices> object are
+the following.
+
+	int isl_vertices_get_n_vertices(
+		__isl_keep isl_vertices *vertices);
+	__isl_null isl_vertices *isl_vertices_free(
+		__isl_take isl_vertices *vertices);
+
+Vertices can be inspected and destroyed using the following functions.
+
+	int isl_vertex_get_id(__isl_keep isl_vertex *vertex);
+	__isl_give isl_basic_set *isl_vertex_get_domain(
+		__isl_keep isl_vertex *vertex);
+	__isl_give isl_multi_aff *isl_vertex_get_expr(
+		__isl_keep isl_vertex *vertex);
+	void isl_vertex_free(__isl_take isl_vertex *vertex);
+
+C<isl_vertex_get_expr> returns a multiple quasi-affine expression
+describing the vertex in terms of the parameters,
+while C<isl_vertex_get_domain> returns the activity domain
+of the vertex.
+
+Chambers can be inspected and destroyed using the following functions.
+
+	__isl_give isl_basic_set *isl_cell_get_domain(
+		__isl_keep isl_cell *cell);
+	void isl_cell_free(__isl_take isl_cell *cell);
+
+=head1 Polyhedral Compilation Library
+
+This section collects functionality in C<isl> that has been specifically
+designed for use during polyhedral compilation.
+
+=head2 Schedule Trees
+
+A schedule tree is a structured representation of a schedule,
+assigning a relative order to a set of domain elements.
+The relative order expressed by the schedule tree is
+defined recursively.  In particular, the order between
+two domain elements is determined by the node that is closest
+to the root that refers to both elements and that orders them apart.
+Each node in the tree is of one of several types.
+The root node is always of type C<isl_schedule_node_domain>
+(or C<isl_schedule_node_extension>)
+and it describes the (extra) domain elements to which the schedule applies.
+The other types of nodes are as follows.
+
+=over
+
+=item C<isl_schedule_node_band>
+
+A band of schedule dimensions.  Each schedule dimension is represented
+by a union piecewise quasi-affine expression.  If this expression
+assigns a different value to two domain elements, while all previous
+schedule dimensions in the same band assign them the same value,
+then the two domain elements are ordered according to these two
+different values.
+Each expression is required to be total in the domain elements
+that reach the band node.
+
+=item C<isl_schedule_node_expansion>
+
+An expansion node maps each of the domain elements that reach the node
+to one or more domain elements.  The image of this mapping forms
+the set of domain elements that reach the child of the expansion node.
+The function that maps each of the expanded domain elements
+to the original domain element from which it was expanded
+is called the contraction.
+
+=item C<isl_schedule_node_filter>
+
+A filter node does not impose any ordering, but rather intersects
+the set of domain elements that the current subtree refers to
+with a given union set.  The subtree of the filter node only
+refers to domain elements in the intersection.
+A filter node is typically only used as a child of a sequence or
+set node.
+
+=item C<isl_schedule_node_leaf>
+
+A leaf of the schedule tree.  Leaf nodes do not impose any ordering.
+
+=item C<isl_schedule_node_mark>
+
+A mark node can be used to attach any kind of information to a subtree
+of the schedule tree.
+
+=item C<isl_schedule_node_sequence>
+
+A sequence node has one or more children, each of which is a filter node.
+The filters on these filter nodes form a partition of
+the domain elements that the current subtree refers to.
+If two domain elements appear in distinct filters then the sequence
+node orders them according to the child positions of the corresponding
+filter nodes.
+
+=item C<isl_schedule_node_set>
+
+A set node is similar to a sequence node, except that
+it expresses that domain elements appearing in distinct filters
+may have any order.  The order of the children of a set node
+is therefore also immaterial.
+
+=back
+
+The following node types are only supported by the AST generator.
+
+=over
+
+=item C<isl_schedule_node_context>
+
+The context describes constraints on the parameters and
+the schedule dimensions of outer
+bands that the AST generator may assume to hold.  It is also the only
+kind of node that may introduce additional parameters.
+The space of the context is that of the flat product of the outer
+band nodes.  In particular, if there are no outer band nodes, then
+this space is the unnamed zero-dimensional space.
+Since a context node references the outer band nodes, any tree
+containing a context node is considered to be anchored.
+
+=item C<isl_schedule_node_extension>
+
+An extension node instructs the AST generator to add additional
+domain elements that need to be scheduled.
+The additional domain elements are described by the range of
+the extension map in terms of the outer schedule dimensions,
+i.e., the flat product of the outer band nodes.
+Note that domain elements are added whenever the AST generator
+reaches the extension node, meaning that there are still some
+active domain elements for which an AST needs to be generated.
+The conditions under which some domain elements are still active
+may however not be completely described by the outer AST nodes
+generated at that point.
+
+An extension node may also appear as the root of a schedule tree,
+when it is intended to be inserted into another tree
+using C<isl_schedule_node_graft_before> or C<isl_schedule_node_graft_after>.
+In this case, the domain of the extension node should
+correspond to the flat product of the outer band nodes
+in this other schedule tree at the point where the extension tree
+will be inserted.
+
+=item C<isl_schedule_node_guard>
+
+The guard describes constraints on the parameters and
+the schedule dimensions of outer
+bands that need to be enforced by the outer nodes
+in the generated AST.
+The space of the guard is that of the flat product of the outer
+band nodes.  In particular, if there are no outer band nodes, then
+this space is the unnamed zero-dimensional space.
+Since a guard node references the outer band nodes, any tree
+containing a guard node is considered to be anchored.
+
+=back
+
+Except for the C<isl_schedule_node_context> nodes,
+none of the nodes may introduce any parameters that were not
+already present in the root domain node.
+
+A schedule tree is encapsulated in an C<isl_schedule> object.
+The simplest such objects, those with a tree consisting of single domain node,
+can be created using the following functions with either an empty
+domain or a given domain.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *isl_schedule_empty(
+		__isl_take isl_space *space);
+	__isl_give isl_schedule *isl_schedule_from_domain(
+		__isl_take isl_union_set *domain);
+
+The function C<isl_schedule_constraints_compute_schedule> described
+in L</"Scheduling"> can also be used to construct schedules.
+
+C<isl_schedule> objects may be copied and freed using the following functions.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *isl_schedule_copy(
+		__isl_keep isl_schedule *sched);
+	__isl_null isl_schedule *isl_schedule_free(
+		__isl_take isl_schedule *sched);
+
+The following functions checks whether two C<isl_schedule> objects
+are obviously the same.
+
+	#include <isl/schedule.h>
+	isl_bool isl_schedule_plain_is_equal(
+		__isl_keep isl_schedule *schedule1,
+		__isl_keep isl_schedule *schedule2);
+
+The domain of the schedule, i.e., the domain described by the root node,
+can be obtained using the following function.
+
+	#include <isl/schedule.h>
+	__isl_give isl_union_set *isl_schedule_get_domain(
+		__isl_keep isl_schedule *schedule);
+
+An extra top-level band node (right underneath the domain node) can
+be introduced into the schedule using the following function.
+The schedule tree is assumed not to have any anchored nodes.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *
+	isl_schedule_insert_partial_schedule(
+		__isl_take isl_schedule *schedule,
+		__isl_take isl_multi_union_pw_aff *partial);
+
+A top-level context node (right underneath the domain node) can
+be introduced into the schedule using the following function.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *isl_schedule_insert_context(
+		__isl_take isl_schedule *schedule,
+		__isl_take isl_set *context)
+
+A top-level guard node (right underneath the domain node) can
+be introduced into the schedule using the following function.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *isl_schedule_insert_guard(
+		__isl_take isl_schedule *schedule,
+		__isl_take isl_set *guard)
+
+A schedule that combines two schedules either in the given
+order or in an arbitrary order, i.e., with an C<isl_schedule_node_sequence>
+or an C<isl_schedule_node_set> node,
+can be created using the following functions.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *isl_schedule_sequence(
+		__isl_take isl_schedule *schedule1,
+		__isl_take isl_schedule *schedule2);
+	__isl_give isl_schedule *isl_schedule_set(
+		__isl_take isl_schedule *schedule1,
+		__isl_take isl_schedule *schedule2);
+
+The domains of the two input schedules need to be disjoint.
+
+The following function can be used to restrict the domain
+of a schedule with a domain node as root to be a subset of the given union set.
+This operation may remove nodes in the tree that have become
+redundant.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *isl_schedule_intersect_domain(
+		__isl_take isl_schedule *schedule,
+		__isl_take isl_union_set *domain);
+
+The following function can be used to simplify the domain
+of a schedule with a domain node as root with respect to the given
+parameter domain.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *isl_schedule_gist_domain_params(
+		__isl_take isl_schedule *schedule,
+		__isl_take isl_set *context);
+
+The following function resets the user pointers on all parameter
+and tuple identifiers referenced by the nodes of the given schedule.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *isl_schedule_reset_user(
+		__isl_take isl_schedule *schedule);
+
+The following function aligns the parameters of all nodes
+in the given schedule to the given space.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *isl_schedule_align_params(
+		__isl_take isl_schedule *schedule,
+		__isl_take isl_space *space);
+
+The following function allows the user to plug in a given function
+in the iteration domains.  The input schedule is not allowed to contain
+any expansion nodes.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *
+	isl_schedule_pullback_union_pw_multi_aff(
+		__isl_take isl_schedule *schedule,
+		__isl_take isl_union_pw_multi_aff *upma);
+
+The following function can be used to plug in the schedule C<expansion>
+in the leaves of C<schedule>, where C<contraction> describes how
+the domain elements of C<expansion> map to the domain elements
+at the original leaves of C<schedule>.
+The resulting schedule will contain expansion nodes, unless
+C<contraction> is an identity function.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *isl_schedule_expand(
+		__isl_take isl_schedule *schedule,
+		__isl_take isl_union_pw_multi_aff *contraction,
+		__isl_take isl_schedule *expansion);
+
+An C<isl_union_map> representation of the schedule can be obtained
+from an C<isl_schedule> using the following function.
+
+	#include <isl/schedule.h>
+	__isl_give isl_union_map *isl_schedule_get_map(
+		__isl_keep isl_schedule *sched);
+
+The resulting relation encodes the same relative ordering as
+the schedule by mapping the domain elements to a common schedule space.
+If the schedule_separate_components option is set, then the order
+of the children of a set node is explicitly encoded in the result.
+If the tree contains any expansion nodes, then the relation
+is formulated in terms of the expanded domain elements.
+
+Schedules can be read from input using the following functions.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *isl_schedule_read_from_file(
+		isl_ctx *ctx, FILE *input);
+	__isl_give isl_schedule *isl_schedule_read_from_str(
+		isl_ctx *ctx, const char *str);
+
+A representation of the schedule can be printed using
+
+	#include <isl/schedule.h>
+	__isl_give isl_printer *isl_printer_print_schedule(
+		__isl_take isl_printer *p,
+		__isl_keep isl_schedule *schedule);
+	__isl_give char *isl_schedule_to_str(
+		__isl_keep isl_schedule *schedule);
+
+C<isl_schedule_to_str> prints the schedule in flow format.
+
+The schedule tree can be traversed through the use of
+C<isl_schedule_node> objects that point to a particular
+position in the schedule tree.  Whenever a C<isl_schedule_node>
+is use to modify a node in the schedule tree, the original schedule
+tree is left untouched and the modifications are performed to a copy
+of the tree.  The returned C<isl_schedule_node> then points to
+this modified copy of the tree.
+
+The root of the schedule tree can be obtained using the following function.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule_node *isl_schedule_get_root(
+		__isl_keep isl_schedule *schedule);
+
+A pointer to a newly created schedule tree with a single domain
+node can be created using the following functions.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_from_domain(
+		__isl_take isl_union_set *domain);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_from_extension(
+		__isl_take isl_union_map *extension);
+
+C<isl_schedule_node_from_extension> creates a tree with an extension
+node as root.
+
+Schedule nodes can be copied and freed using the following functions.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *isl_schedule_node_copy(
+		__isl_keep isl_schedule_node *node);
+	__isl_null isl_schedule_node *isl_schedule_node_free(
+		__isl_take isl_schedule_node *node);
+
+The following functions can be used to check if two schedule
+nodes point to the same position in the same schedule.
+
+	#include <isl/schedule_node.h>
+	isl_bool isl_schedule_node_is_equal(
+		__isl_keep isl_schedule_node *node1,
+		__isl_keep isl_schedule_node *node2);
+
+The following properties can be obtained from a schedule node.
+
+	#include <isl/schedule_node.h>
+	enum isl_schedule_node_type isl_schedule_node_get_type(
+		__isl_keep isl_schedule_node *node);
+	enum isl_schedule_node_type
+	isl_schedule_node_get_parent_type(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_schedule *isl_schedule_node_get_schedule(
+		__isl_keep isl_schedule_node *node);
+
+The function C<isl_schedule_node_get_type> returns the type of
+the node, while C<isl_schedule_node_get_parent_type> returns
+type of the parent of the node, which is required to exist.
+The function C<isl_schedule_node_get_schedule> returns a copy
+to the schedule to which the node belongs.
+
+The following functions can be used to move the schedule node
+to a different position in the tree or to check if such a position
+exists.
+
+	#include <isl/schedule_node.h>
+	isl_bool isl_schedule_node_has_parent(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_schedule_node *isl_schedule_node_parent(
+		__isl_take isl_schedule_node *node);
+	__isl_give isl_schedule_node *isl_schedule_node_root(
+		__isl_take isl_schedule_node *node);
+	__isl_give isl_schedule_node *isl_schedule_node_ancestor(
+		__isl_take isl_schedule_node *node,
+		int generation);
+	int isl_schedule_node_n_children(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_schedule_node *isl_schedule_node_child(
+		__isl_take isl_schedule_node *node, int pos);
+	isl_bool isl_schedule_node_has_children(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_schedule_node *isl_schedule_node_first_child(
+		__isl_take isl_schedule_node *node);
+	isl_bool isl_schedule_node_has_previous_sibling(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_previous_sibling(
+		__isl_take isl_schedule_node *node);
+	isl_bool isl_schedule_node_has_next_sibling(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_next_sibling(
+		__isl_take isl_schedule_node *node);
+
+For C<isl_schedule_node_ancestor>, the ancestor of generation 0
+is the node itself, the ancestor of generation 1 is its parent and so on.
+
+It is also possible to query the number of ancestors of a node,
+the position of the current node
+within the children of its parent, the position of the subtree
+containing a node within the children of an ancestor
+or to obtain a copy of a given
+child without destroying the current node.
+Given two nodes that point to the same schedule, their closest
+shared ancestor can be obtained using
+C<isl_schedule_node_get_shared_ancestor>.
+
+	#include <isl/schedule_node.h>
+	int isl_schedule_node_get_tree_depth(
+		__isl_keep isl_schedule_node *node);
+	int isl_schedule_node_get_child_position(
+		__isl_keep isl_schedule_node *node);
+	int isl_schedule_node_get_ancestor_child_position(
+		__isl_keep isl_schedule_node *node,
+		__isl_keep isl_schedule_node *ancestor);
+	__isl_give isl_schedule_node *isl_schedule_node_get_child(
+		__isl_keep isl_schedule_node *node, int pos);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_get_shared_ancestor(
+		__isl_keep isl_schedule_node *node1,
+		__isl_keep isl_schedule_node *node2);
+
+All nodes in a schedule tree or
+all descendants of a specific node (including the node) can be visited
+in depth-first pre-order using the following functions.
+
+	#include <isl/schedule.h>
+	isl_stat isl_schedule_foreach_schedule_node_top_down(
+		__isl_keep isl_schedule *sched,
+		isl_bool (*fn)(__isl_keep isl_schedule_node *node,
+			void *user), void *user);
+
+	#include <isl/schedule_node.h>
+	isl_stat isl_schedule_node_foreach_descendant_top_down(
+		__isl_keep isl_schedule_node *node,
+		isl_bool (*fn)(__isl_keep isl_schedule_node *node,
+			void *user), void *user);
+
+The callback function is slightly different from the usual
+callbacks in that it not only indicates success (non-negative result)
+or failure (negative result), but also indicates whether the children
+of the given node should be visited.  In particular, if the callback
+returns a positive value, then the children are visited, but if
+the callback returns zero, then the children are not visited.
+
+The ancestors of a node in a schedule tree can be visited from
+the root down to and including the parent of the node using
+the following function.
+
+	#include <isl/schedule_node.h>
+	isl_stat isl_schedule_node_foreach_ancestor_top_down(
+		__isl_keep isl_schedule_node *node,
+		isl_stat (*fn)(__isl_keep isl_schedule_node *node,
+			void *user), void *user);
+
+The following functions allows for a depth-first post-order
+traversal of the nodes in a schedule tree or
+of the descendants of a specific node (including the node
+itself), where the user callback is allowed to modify the
+visited node.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *
+	isl_schedule_map_schedule_node_bottom_up(
+		__isl_take isl_schedule *schedule,
+		__isl_give isl_schedule_node *(*fn)(
+			__isl_take isl_schedule_node *node,
+			void *user), void *user);
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_map_descendant_bottom_up(
+		__isl_take isl_schedule_node *node,
+		__isl_give isl_schedule_node *(*fn)(
+			__isl_take isl_schedule_node *node,
+			void *user), void *user);
+
+The traversal continues from the node returned by the callback function.
+It is the responsibility of the user to ensure that this does not
+lead to an infinite loop.  It is safest to always return a pointer
+to the same position (same ancestors and child positions) as the input node.
+
+The following function removes a node (along with its descendants)
+from a schedule tree and returns a pointer to the leaf at the
+same position in the updated tree.
+It is not allowed to remove the root of a schedule tree or
+a child of a set or sequence node.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *isl_schedule_node_cut(
+		__isl_take isl_schedule_node *node);
+
+The following function removes a single node
+from a schedule tree and returns a pointer to the child
+of the node, now located at the position of the original node
+or to a leaf node at that position if there was no child.
+It is not allowed to remove the root of a schedule tree,
+a set or sequence node, a child of a set or sequence node or
+a band node with an anchored subtree.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *isl_schedule_node_delete(
+		__isl_take isl_schedule_node *node);
+
+Most nodes in a schedule tree only contain local information.
+In some cases, however, a node may also refer to the schedule dimensions
+of its outer band nodes.
+This means that the position of the node within the tree should
+not be changed, or at least that no changes are performed to the
+outer band nodes.  The following function can be used to test
+whether the subtree rooted at a given node contains any such nodes.
+
+	#include <isl/schedule_node.h>
+	isl_bool isl_schedule_node_is_subtree_anchored(
+		__isl_keep isl_schedule_node *node);
+
+The following function resets the user pointers on all parameter
+and tuple identifiers referenced by the given schedule node.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *isl_schedule_node_reset_user(
+		__isl_take isl_schedule_node *node);
+
+The following function aligns the parameters of the given schedule
+node to the given space.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_align_params(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_space *space);
+
+Several node types have their own functions for querying
+(and in some cases setting) some node type specific properties.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_space *isl_schedule_node_band_get_space(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_multi_union_pw_aff *
+	isl_schedule_node_band_get_partial_schedule(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_union_map *
+	isl_schedule_node_band_get_partial_schedule_union_map(
+		__isl_keep isl_schedule_node *node);
+	unsigned isl_schedule_node_band_n_member(
+		__isl_keep isl_schedule_node *node);
+	isl_bool isl_schedule_node_band_member_get_coincident(
+		__isl_keep isl_schedule_node *node, int pos);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_band_member_set_coincident(
+		__isl_take isl_schedule_node *node, int pos,
+		int coincident);
+	isl_bool isl_schedule_node_band_get_permutable(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_band_set_permutable(
+		__isl_take isl_schedule_node *node, int permutable);
+	enum isl_ast_loop_type
+	isl_schedule_node_band_member_get_ast_loop_type(
+		__isl_keep isl_schedule_node *node, int pos);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_band_member_set_ast_loop_type(
+		__isl_take isl_schedule_node *node, int pos,
+		enum isl_ast_loop_type type);
+	__isl_give isl_union_set *
+	enum isl_ast_loop_type
+	isl_schedule_node_band_member_get_isolate_ast_loop_type(
+		__isl_keep isl_schedule_node *node, int pos);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_band_member_set_isolate_ast_loop_type(
+		__isl_take isl_schedule_node *node, int pos,
+		enum isl_ast_loop_type type);
+	isl_schedule_node_band_get_ast_build_options(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_band_set_ast_build_options(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_union_set *options);
+	__isl_give isl_set *
+	isl_schedule_node_band_get_ast_isolate_option(
+		__isl_keep isl_schedule_node *node);
+
+The function C<isl_schedule_node_band_get_space> returns the space
+of the partial schedule of the band.
+The function C<isl_schedule_node_band_get_partial_schedule_union_map>
+returns a representation of the partial schedule of the band node
+in the form of an C<isl_union_map>.
+The coincident and permutable properties are set by
+C<isl_schedule_constraints_compute_schedule> on the schedule tree
+it produces.
+A scheduling dimension is considered to be ``coincident''
+if it satisfies the coincidence constraints within its band.
+That is, if the dependence distances of the coincidence
+constraints are all zero in that direction (for fixed
+iterations of outer bands).
+A band is marked permutable if it was produced using the Pluto-like scheduler.
+Note that the scheduler may have to resort to a Feautrier style scheduling
+step even if the default scheduler is used.
+An C<isl_ast_loop_type> is one of C<isl_ast_loop_default>,
+C<isl_ast_loop_atomic>, C<isl_ast_loop_unroll> or C<isl_ast_loop_separate>.
+For the meaning of these loop AST generation types and the difference
+between the regular loop AST generation type and the isolate
+loop AST generation type, see L</"AST Generation Options (Schedule Tree)">.
+The functions C<isl_schedule_node_band_member_get_ast_loop_type>
+and C<isl_schedule_node_band_member_get_isolate_ast_loop_type>
+may return C<isl_ast_loop_error> if an error occurs.
+The AST build options govern how an AST is generated for
+the individual schedule dimensions during AST generation.
+See L</"AST Generation Options (Schedule Tree)">.
+The isolate option for the given node can be extracted from these
+AST build options using the function
+C<isl_schedule_node_band_get_ast_isolate_option>.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_set *
+	isl_schedule_node_context_get_context(
+		__isl_keep isl_schedule_node *node);
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_union_set *
+	isl_schedule_node_domain_get_domain(
+		__isl_keep isl_schedule_node *node);
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_union_map *
+	isl_schedule_node_expansion_get_expansion(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_union_pw_multi_aff *
+	isl_schedule_node_expansion_get_contraction(
+		__isl_keep isl_schedule_node *node);
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_union_map *
+	isl_schedule_node_extension_get_extension(
+		__isl_keep isl_schedule_node *node);
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_union_set *
+	isl_schedule_node_filter_get_filter(
+		__isl_keep isl_schedule_node *node);
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_set *isl_schedule_node_guard_get_guard(
+		__isl_keep isl_schedule_node *node);
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_id *isl_schedule_node_mark_get_id(
+		__isl_keep isl_schedule_node *node);
+
+The following functions can be used to obtain an C<isl_multi_union_pw_aff>,
+an C<isl_union_pw_multi_aff> or C<isl_union_map> representation of
+partial schedules related to the node.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_multi_union_pw_aff *
+	isl_schedule_node_get_prefix_schedule_multi_union_pw_aff(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_union_pw_multi_aff *
+	isl_schedule_node_get_prefix_schedule_union_pw_multi_aff(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_union_map *
+	isl_schedule_node_get_prefix_schedule_union_map(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_union_map *
+	isl_schedule_node_get_prefix_schedule_relation(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_union_map *
+	isl_schedule_node_get_subtree_schedule_union_map(
+		__isl_keep isl_schedule_node *node);
+
+In particular, the functions
+C<isl_schedule_node_get_prefix_schedule_multi_union_pw_aff>,
+C<isl_schedule_node_get_prefix_schedule_union_pw_multi_aff>
+and C<isl_schedule_node_get_prefix_schedule_union_map>
+return a relative ordering on the domain elements that reach the given
+node determined by its ancestors.
+The function C<isl_schedule_node_get_prefix_schedule_relation>
+additionally includes the domain constraints in the result.
+The function C<isl_schedule_node_get_subtree_schedule_union_map>
+returns a representation of the partial schedule defined by the
+subtree rooted at the given node.
+If the tree contains any expansion nodes, then the subtree schedule
+is formulated in terms of the expanded domain elements.
+The tree passed to functions returning a prefix schedule
+may only contain extension nodes if these would not affect
+the result of these functions.  That is, if one of the ancestors
+is an extension node, then all of the domain elements that were
+added by the extension node need to have been filtered out
+by filter nodes between the extension node and the input node.
+The tree passed to C<isl_schedule_node_get_subtree_schedule_union_map>
+may not contain in extension nodes in the selected subtree.
+
+The expansion/contraction defined by an entire subtree, combining
+the expansions/contractions
+on the expansion nodes in the subtree, can be obtained using
+the following functions.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_union_map *
+	isl_schedule_node_get_subtree_expansion(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_union_pw_multi_aff *
+	isl_schedule_node_get_subtree_contraction(
+		__isl_keep isl_schedule_node *node);
+
+The total number of outer band members of given node, i.e.,
+the shared output dimension of the maps in the result
+of C<isl_schedule_node_get_prefix_schedule_union_map> can be obtained
+using the following function.
+
+	#include <isl/schedule_node.h>
+	int isl_schedule_node_get_schedule_depth(
+		__isl_keep isl_schedule_node *node);
+
+The following functions return the elements that reach the given node
+or the union of universes in the spaces that contain these elements.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_union_set *
+	isl_schedule_node_get_domain(
+		__isl_keep isl_schedule_node *node);
+	__isl_give isl_union_set *
+	isl_schedule_node_get_universe_domain(
+		__isl_keep isl_schedule_node *node);
+
+The input tree of C<isl_schedule_node_get_domain>
+may only contain extension nodes if these would not affect
+the result of this function.  That is, if one of the ancestors
+is an extension node, then all of the domain elements that were
+added by the extension node need to have been filtered out
+by filter nodes between the extension node and the input node.
+
+The following functions can be used to introduce additional nodes
+in the schedule tree.  The new node is introduced at the point
+in the tree where the C<isl_schedule_node> points to and
+the results points to the new node.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_insert_partial_schedule(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_multi_union_pw_aff *schedule);
+
+This function inserts a new band node with (the greatest integer
+part of) the given partial schedule.
+The subtree rooted at the given node is assumed not to have
+any anchored nodes.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_insert_context(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_set *context);
+
+This function inserts a new context node with the given context constraints.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_insert_filter(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_union_set *filter);
+
+This function inserts a new filter node with the given filter.
+If the original node already pointed to a filter node, then the
+two filter nodes are merged into one.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_insert_guard(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_set *guard);
+
+This function inserts a new guard node with the given guard constraints.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_insert_mark(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_id *mark);
+
+This function inserts a new mark node with the give mark identifier.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_insert_sequence(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_union_set_list *filters);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_insert_set(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_union_set_list *filters);
+
+These functions insert a new sequence or set node with the given
+filters as children.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *isl_schedule_node_group(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_id *group_id);
+
+This function introduces an expansion node in between the current
+node and its parent that expands instances of a space with tuple
+identifier C<group_id> to the original domain elements that reach
+the node.  The group instances are identified by the prefix schedule
+of those domain elements.  The ancestors of the node are adjusted
+to refer to the group instances instead of the original domain
+elements.  The return value points to the same node in the updated
+schedule tree as the input node, i.e., to the child of the newly
+introduced expansion node.  Grouping instances of different statements
+ensures that they will be treated as a single statement by the
+AST generator up to the point of the expansion node.
+
+The following function can be used to flatten a nested
+sequence.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_sequence_splice_child(
+		__isl_take isl_schedule_node *node, int pos);
+
+That is, given a sequence node C<node> that has another sequence node
+in its child at position C<pos> (in particular, the child of that filter
+node is a sequence node), attach the children of that other sequence
+node as children of C<node>, replacing the original child at position
+C<pos>.
+
+The partial schedule of a band node can be scaled (down) or reduced using
+the following functions.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_band_scale(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_band_scale_down(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_multi_val *mv);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_band_mod(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_multi_val *mv);
+
+The spaces of the two arguments need to match.
+After scaling, the partial schedule is replaced by its greatest
+integer part to ensure that the schedule remains integral.
+
+The partial schedule of a band node can be shifted by an
+C<isl_multi_union_pw_aff> with a domain that is a superset
+of the domain of the partial schedule using
+the following function.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_band_shift(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_multi_union_pw_aff *shift);
+
+A band node can be tiled using the following function.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *isl_schedule_node_band_tile(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_multi_val *sizes);
+
+	isl_stat isl_options_set_tile_scale_tile_loops(isl_ctx *ctx,
+		int val);
+	int isl_options_get_tile_scale_tile_loops(isl_ctx *ctx);
+	isl_stat isl_options_set_tile_shift_point_loops(isl_ctx *ctx,
+		int val);
+	int isl_options_get_tile_shift_point_loops(isl_ctx *ctx);
+
+The C<isl_schedule_node_band_tile> function tiles
+the band using the given tile sizes inside its schedule.
+A new child band node is created to represent the point loops and it is
+inserted between the modified band and its children.
+The subtree rooted at the given node is assumed not to have
+any anchored nodes.
+The C<tile_scale_tile_loops> option specifies whether the tile
+loops iterators should be scaled by the tile sizes.
+If the C<tile_shift_point_loops> option is set, then the point loops
+are shifted to start at zero.
+
+A band node can be split into two nested band nodes
+using the following function.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *isl_schedule_node_band_split(
+		__isl_take isl_schedule_node *node, int pos);
+
+The resulting outer band node contains the first C<pos> dimensions of
+the schedule of C<node> while the inner band contains the remaining dimensions.
+The schedules of the two band nodes live in anonymous spaces.
+The loop AST generation type options and the isolate option
+are split over the the two band nodes.
+
+A band node can be moved down to the leaves of the subtree rooted
+at the band node using the following function.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *isl_schedule_node_band_sink(
+		__isl_take isl_schedule_node *node);
+
+The subtree rooted at the given node is assumed not to have
+any anchored nodes.
+The result points to the node in the resulting tree that is in the same
+position as the node pointed to by C<node> in the original tree.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_order_before(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_union_set *filter);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_order_after(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_union_set *filter);
+
+These functions split the domain elements that reach C<node>
+into those that satisfy C<filter> and those that do not and
+arranges for the elements that do satisfy the filter to be
+executed before (in case of C<isl_schedule_node_order_before>)
+or after (in case of C<isl_schedule_node_order_after>)
+those that do not.  The order is imposed by
+a sequence node, possibly reusing the grandparent of C<node>
+on two copies of the subtree attached to the original C<node>.
+Both copies are simplified with respect to their filter.
+
+Return a pointer to the copy of the subtree that does not
+satisfy C<filter>.  If there is no such copy (because all
+reaching domain elements satisfy the filter), then return
+the original pointer.
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_schedule_node *
+	isl_schedule_node_graft_before(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_schedule_node *graft);
+	__isl_give isl_schedule_node *
+	isl_schedule_node_graft_after(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_schedule_node *graft);
+
+This function inserts the C<graft> tree into the tree containing C<node>
+such that it is executed before (in case of C<isl_schedule_node_graft_before>)
+or after (in case of C<isl_schedule_node_graft_after>) C<node>.
+The root node of C<graft>
+should be an extension node where the domain of the extension
+is the flat product of all outer band nodes of C<node>.
+The root node may also be a domain node.
+The elements of the domain or the range of the extension may not
+intersect with the domain elements that reach "node".
+The schedule tree of C<graft> may not be anchored.
+
+The schedule tree of C<node> is modified to include an extension node
+corresponding to the root node of C<graft> as a child of the original
+parent of C<node>.  The original node that C<node> points to and the
+child of the root node of C<graft> are attached to this extension node
+through a sequence, with appropriate filters and with the child
+of C<graft> appearing before or after the original C<node>.
+
+If C<node> already appears inside a sequence that is the child of
+an extension node and if the spaces of the new domain elements
+do not overlap with those of the original domain elements,
+then that extension node is extended with the new extension
+rather than introducing a new segment of extension and sequence nodes.
+
+Return a pointer to the same node in the modified tree that
+C<node> pointed to in the original tree.
+
+A representation of the schedule node can be printed using
+
+	#include <isl/schedule_node.h>
+	__isl_give isl_printer *isl_printer_print_schedule_node(
+		__isl_take isl_printer *p,
+		__isl_keep isl_schedule_node *node);
+	__isl_give char *isl_schedule_node_to_str(
+		__isl_keep isl_schedule_node *node);
+
+C<isl_schedule_node_to_str> prints the schedule node in block format.
+
+=head2 Dependence Analysis
+
+C<isl> contains specialized functionality for performing
+array dataflow analysis.  That is, given a I<sink> access relation,
+a collection of possible I<source> accesses and
+a collection of I<kill> accesses,
+C<isl> can compute relations that describe
+for each iteration of the sink access, which iterations
+of which of the source access relations may have
+accessed the same data element before the given iteration
+of the sink access without any intermediate kill of that data element.
+The resulting dependence relations map source iterations
+to either the corresponding sink iterations or
+pairs of corresponding sink iterations and accessed data elements.
+To compute standard flow dependences, the sink should be
+a read, while the sources should be writes.
+If no kills are specified,
+then memory based dependence analysis is performed.
+If, on the other hand, all sources are also kills,
+then value based dependence analysis is performed.
+If any of the source accesses are marked as being I<must>
+accesses, then they are also treated as kills.
+Furthermore, the specification of must-sources results
+in the computation of must-dependences.
+Only dependences originating in a must access not coscheduled
+with any other access to the same element and without
+any may accesses between the must access and the sink access
+are considered to be must dependences.
+
+=head3 High-level Interface
+
+A high-level interface to dependence analysis is provided
+by the following function.
+
+	#include <isl/flow.h>
+	__isl_give isl_union_flow *
+	isl_union_access_info_compute_flow(
+		__isl_take isl_union_access_info *access);
+
+The input C<isl_union_access_info> object describes the sink
+access relations, the source access relations and a schedule,
+while the output C<isl_union_flow> object describes
+the resulting dependence relations and the subsets of the
+sink relations for which no source was found.
+
+An C<isl_union_access_info> is created, modified, copied and freed using
+the following functions.
+
+	#include <isl/flow.h>
+	__isl_give isl_union_access_info *
+	isl_union_access_info_from_sink(
+		__isl_take isl_union_map *sink);
+	__isl_give isl_union_access_info *
+	isl_union_access_info_set_kill(
+		__isl_take isl_union_access_info *access,
+		__isl_take isl_union_map *kill);
+	__isl_give isl_union_access_info *
+	isl_union_access_info_set_may_source(
+		__isl_take isl_union_access_info *access,
+		__isl_take isl_union_map *may_source);
+	__isl_give isl_union_access_info *
+	isl_union_access_info_set_must_source(
+		__isl_take isl_union_access_info *access,
+		__isl_take isl_union_map *must_source);
+	__isl_give isl_union_access_info *
+	isl_union_access_info_set_schedule(
+		__isl_take isl_union_access_info *access,
+		__isl_take isl_schedule *schedule);
+	__isl_give isl_union_access_info *
+	isl_union_access_info_set_schedule_map(
+		__isl_take isl_union_access_info *access,
+		__isl_take isl_union_map *schedule_map);
+	__isl_give isl_union_access_info *
+	isl_union_access_info_copy(
+		__isl_keep isl_union_access_info *access);
+	__isl_null isl_union_access_info *
+	isl_union_access_info_free(
+		__isl_take isl_union_access_info *access);
+
+The may sources set by C<isl_union_access_info_set_may_source>
+do not need to include the must sources set by
+C<isl_union_access_info_set_must_source> as a subset.
+The kills set by C<isl_union_access_info_set_kill> may overlap
+with the may-sources and/or must-sources.
+The user is free not to call one (or more) of these functions,
+in which case the corresponding set is kept to its empty default.
+Similarly, the default schedule initialized by
+C<isl_union_access_info_from_sink> is empty.
+The current schedule is determined by the last call to either
+C<isl_union_access_info_set_schedule> or
+C<isl_union_access_info_set_schedule_map>.
+The domain of the schedule corresponds to the domains of
+the access relations.  In particular, the domains of the access
+relations are effectively intersected with the domain of the schedule
+and only the resulting accesses are considered by the dependence analysis.
+
+An C<isl_union_access_info> object can be read from input
+using the following function.
+
+	#include <isl/flow.h>
+	__isl_give isl_union_access_info *
+	isl_union_access_info_read_from_file(isl_ctx *ctx,
+		FILE *input);
+
+A representation of the information contained in an object
+of type C<isl_union_access_info> can be obtained using
+
+	#include <isl/flow.h>
+	__isl_give isl_printer *
+	isl_printer_print_union_access_info(
+		__isl_take isl_printer *p,
+		__isl_keep isl_union_access_info *access);
+	__isl_give char *isl_union_access_info_to_str(
+		__isl_keep isl_union_access_info *access);
+
+C<isl_union_access_info_to_str> prints the information in flow format.
+
+The output of C<isl_union_access_info_compute_flow> can be examined,
+copied, and freed using the following functions.
+
+	#include <isl/flow.h>
+	__isl_give isl_union_map *isl_union_flow_get_must_dependence(
+		__isl_keep isl_union_flow *flow);
+	__isl_give isl_union_map *isl_union_flow_get_may_dependence(
+		__isl_keep isl_union_flow *flow);
+	__isl_give isl_union_map *
+	isl_union_flow_get_full_must_dependence(
+		__isl_keep isl_union_flow *flow);
+	__isl_give isl_union_map *
+	isl_union_flow_get_full_may_dependence(
+		__isl_keep isl_union_flow *flow);
+	__isl_give isl_union_map *isl_union_flow_get_must_no_source(
+		__isl_keep isl_union_flow *flow);
+	__isl_give isl_union_map *isl_union_flow_get_may_no_source(
+		__isl_keep isl_union_flow *flow);
+	__isl_give isl_union_flow *isl_union_flow_copy(
+		__isl_keep isl_union_flow *flow);
+	__isl_null isl_union_flow *isl_union_flow_free(
+		__isl_take isl_union_flow *flow);
+
+The relation returned by C<isl_union_flow_get_must_dependence>
+relates domain elements of must sources to domain elements of the sink.
+The relation returned by C<isl_union_flow_get_may_dependence>
+relates domain elements of must or may sources to domain elements of the sink
+and includes the previous relation as a subset.
+The relation returned by C<isl_union_flow_get_full_must_dependence>
+relates domain elements of must sources to pairs of domain elements of the sink
+and accessed data elements.
+The relation returned by C<isl_union_flow_get_full_may_dependence>
+relates domain elements of must or may sources to pairs of
+domain elements of the sink and accessed data elements.
+This relation includes the previous relation as a subset.
+The relation returned by C<isl_union_flow_get_must_no_source> is the subset
+of the sink relation for which no dependences have been found.
+The relation returned by C<isl_union_flow_get_may_no_source> is the subset
+of the sink relation for which no definite dependences have been found.
+That is, it contains those sink access that do not contribute to any
+of the elements in the relation returned
+by C<isl_union_flow_get_must_dependence>.
+
+A representation of the information contained in an object
+of type C<isl_union_flow> can be obtained using
+
+	#include <isl/flow.h>
+	__isl_give isl_printer *isl_printer_print_union_flow(
+		__isl_take isl_printer *p,
+		__isl_keep isl_union_flow *flow);
+	__isl_give char *isl_union_flow_to_str(
+		__isl_keep isl_union_flow *flow);
+
+C<isl_union_flow_to_str> prints the information in flow format.
+
+=head3 Low-level Interface
+
+A lower-level interface is provided by the following functions.
+
+	#include <isl/flow.h>
+
+	typedef int (*isl_access_level_before)(void *first, void *second);
+
+	__isl_give isl_access_info *isl_access_info_alloc(
+		__isl_take isl_map *sink,
+		void *sink_user, isl_access_level_before fn,
+		int max_source);
+	__isl_give isl_access_info *isl_access_info_add_source(
+		__isl_take isl_access_info *acc,
+		__isl_take isl_map *source, int must,
+		void *source_user);
+	__isl_null isl_access_info *isl_access_info_free(
+		__isl_take isl_access_info *acc);
+
+	__isl_give isl_flow *isl_access_info_compute_flow(
+		__isl_take isl_access_info *acc);
+
+	isl_stat isl_flow_foreach(__isl_keep isl_flow *deps,
+		isl_stat (*fn)(__isl_take isl_map *dep, int must,
+			  void *dep_user, void *user),
+		void *user);
+	__isl_give isl_map *isl_flow_get_no_source(
+		__isl_keep isl_flow *deps, int must);
+	void isl_flow_free(__isl_take isl_flow *deps);
+
+The function C<isl_access_info_compute_flow> performs the actual
+dependence analysis.  The other functions are used to construct
+the input for this function or to read off the output.
+
+The input is collected in an C<isl_access_info>, which can
+be created through a call to C<isl_access_info_alloc>.
+The arguments to this functions are the sink access relation
+C<sink>, a token C<sink_user> used to identify the sink
+access to the user, a callback function for specifying the
+relative order of source and sink accesses, and the number
+of source access relations that will be added.
+
+The callback function has type C<int (*)(void *first, void *second)>.
+The function is called with two user supplied tokens identifying
+either a source or the sink and it should return the shared nesting
+level and the relative order of the two accesses.
+In particular, let I<n> be the number of loops shared by
+the two accesses.  If C<first> precedes C<second> textually,
+then the function should return I<2 * n + 1>; otherwise,
+it should return I<2 * n>.
+The low-level interface assumes that no sources are coscheduled.
+If the information returned by the callback does not allow
+the relative order to be determined, then one of the sources
+is arbitrarily taken to be executed after the other(s).
+
+The sources can be added to the C<isl_access_info> object by performing
+(at most) C<max_source> calls to C<isl_access_info_add_source>.
+C<must> indicates whether the source is a I<must> access
+or a I<may> access.  Note that a multi-valued access relation
+should only be marked I<must> if every iteration in the domain
+of the relation accesses I<all> elements in its image.
+The C<source_user> token is again used to identify
+the source access.  The range of the source access relation
+C<source> should have the same dimension as the range
+of the sink access relation.
+The C<isl_access_info_free> function should usually not be
+called explicitly, because it is already called implicitly by
+C<isl_access_info_compute_flow>.
+
+The result of the dependence analysis is collected in an
+C<isl_flow>.  There may be elements of
+the sink access for which no preceding source access could be
+found or for which all preceding sources are I<may> accesses.
+The relations containing these elements can be obtained through
+calls to C<isl_flow_get_no_source>, the first with C<must> set
+and the second with C<must> unset.
+In the case of standard flow dependence analysis,
+with the sink a read and the sources I<must> writes,
+the first relation corresponds to the reads from uninitialized
+array elements and the second relation is empty.
+The actual flow dependences can be extracted using
+C<isl_flow_foreach>.  This function will call the user-specified
+callback function C<fn> for each B<non-empty> dependence between
+a source and the sink.  The callback function is called
+with four arguments, the actual flow dependence relation
+mapping source iterations to sink iterations, a boolean that
+indicates whether it is a I<must> or I<may> dependence, a token
+identifying the source and an additional C<void *> with value
+equal to the third argument of the C<isl_flow_foreach> call.
+A dependence is marked I<must> if it originates from a I<must>
+source and if it is not followed by any I<may> sources.
+
+After finishing with an C<isl_flow>, the user should call
+C<isl_flow_free> to free all associated memory.
+
+=head3 Interaction with the Low-level Interface
+
+During the dependence analysis, we frequently need to perform
+the following operation.  Given a relation between sink iterations
+and potential source iterations from a particular source domain,
+what is the last potential source iteration corresponding to each
+sink iteration.  It can sometimes be convenient to adjust
+the set of potential source iterations before or after each such operation.
+The prototypical example is fuzzy array dataflow analysis,
+where we need to analyze if, based on data-dependent constraints,
+the sink iteration can ever be executed without one or more of
+the corresponding potential source iterations being executed.
+If so, we can introduce extra parameters and select an unknown
+but fixed source iteration from the potential source iterations.
+To be able to perform such manipulations, C<isl> provides the following
+function.
+
+	#include <isl/flow.h>
+
+	typedef __isl_give isl_restriction *(*isl_access_restrict)(
+		__isl_keep isl_map *source_map,
+		__isl_keep isl_set *sink, void *source_user,
+		void *user);
+	__isl_give isl_access_info *isl_access_info_set_restrict(
+		__isl_take isl_access_info *acc,
+		isl_access_restrict fn, void *user);
+
+The function C<isl_access_info_set_restrict> should be called
+before calling C<isl_access_info_compute_flow> and registers a callback function
+that will be called any time C<isl> is about to compute the last
+potential source.  The first argument is the (reverse) proto-dependence,
+mapping sink iterations to potential source iterations.
+The second argument represents the sink iterations for which
+we want to compute the last source iteration.
+The third argument is the token corresponding to the source
+and the final argument is the token passed to C<isl_access_info_set_restrict>.
+The callback is expected to return a restriction on either the input or
+the output of the operation computing the last potential source.
+If the input needs to be restricted then restrictions are needed
+for both the source and the sink iterations.  The sink iterations
+and the potential source iterations will be intersected with these sets.
+If the output needs to be restricted then only a restriction on the source
+iterations is required.
+If any error occurs, the callback should return C<NULL>.
+An C<isl_restriction> object can be created, freed and inspected
+using the following functions.
+
+	#include <isl/flow.h>
+
+	__isl_give isl_restriction *isl_restriction_input(
+		__isl_take isl_set *source_restr,
+		__isl_take isl_set *sink_restr);
+	__isl_give isl_restriction *isl_restriction_output(
+		__isl_take isl_set *source_restr);
+	__isl_give isl_restriction *isl_restriction_none(
+		__isl_take isl_map *source_map);
+	__isl_give isl_restriction *isl_restriction_empty(
+		__isl_take isl_map *source_map);
+	__isl_null isl_restriction *isl_restriction_free(
+		__isl_take isl_restriction *restr);
+
+C<isl_restriction_none> and C<isl_restriction_empty> are special
+cases of C<isl_restriction_input>.  C<isl_restriction_none>
+is essentially equivalent to
+
+	isl_restriction_input(isl_set_universe(
+	    isl_space_range(isl_map_get_space(source_map))),
+			    isl_set_universe(
+	    isl_space_domain(isl_map_get_space(source_map))));
+
+whereas C<isl_restriction_empty> is essentially equivalent to
+
+	isl_restriction_input(isl_set_empty(
+	    isl_space_range(isl_map_get_space(source_map))),
+			    isl_set_universe(
+	    isl_space_domain(isl_map_get_space(source_map))));
+
+=head2 Scheduling
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *
+	isl_schedule_constraints_compute_schedule(
+		__isl_take isl_schedule_constraints *sc);
+
+The function C<isl_schedule_constraints_compute_schedule> can be
+used to compute a schedule that satisfies the given schedule constraints.
+These schedule constraints include the iteration domain for which
+a schedule should be computed and dependences between pairs of
+iterations.  In particular, these dependences include
+I<validity> dependences and I<proximity> dependences.
+By default, the algorithm used to construct the schedule is similar
+to that of C<Pluto>.
+Alternatively, Feautrier's multi-dimensional scheduling algorithm can
+be selected.
+The generated schedule respects all validity dependences.
+That is, all dependence distances over these dependences in the
+scheduled space are lexicographically positive.
+
+The default algorithm tries to ensure that the dependence distances
+over coincidence constraints are zero and to minimize the
+dependence distances over proximity dependences.
+Moreover, it tries to obtain sequences (bands) of schedule dimensions
+for groups of domains where the dependence distances over validity
+dependences have only non-negative values.
+Note that when minimizing the maximal dependence distance
+over proximity dependences, a single affine expression in the parameters
+is constructed that bounds all dependence distances.  If no such expression
+exists, then the algorithm will fail and resort to an alternative
+scheduling algorithm.  In particular, this means that adding proximity
+dependences may eliminate valid solutions.  A typical example where this
+phenomenon may occur is when some subset of the proximity dependences
+has no restriction on some parameter, forcing the coefficient of that
+parameter to be zero, while some other subset forces the dependence
+distance to depend on that parameter, requiring the same coefficient
+to be non-zero.
+When using Feautrier's algorithm, the coincidence and proximity constraints
+are only taken into account during the extension to a
+full-dimensional schedule.
+
+An C<isl_schedule_constraints> object can be constructed
+and manipulated using the following functions.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule_constraints *
+	isl_schedule_constraints_copy(
+		__isl_keep isl_schedule_constraints *sc);
+	__isl_give isl_schedule_constraints *
+	isl_schedule_constraints_on_domain(
+		__isl_take isl_union_set *domain);
+	__isl_give isl_schedule_constraints *
+	isl_schedule_constraints_set_context(
+		__isl_take isl_schedule_constraints *sc,
+		__isl_take isl_set *context);
+	__isl_give isl_schedule_constraints *
+	isl_schedule_constraints_set_validity(
+		__isl_take isl_schedule_constraints *sc,
+		__isl_take isl_union_map *validity);
+	__isl_give isl_schedule_constraints *
+	isl_schedule_constraints_set_coincidence(
+		__isl_take isl_schedule_constraints *sc,
+		__isl_take isl_union_map *coincidence);
+	__isl_give isl_schedule_constraints *
+	isl_schedule_constraints_set_proximity(
+		__isl_take isl_schedule_constraints *sc,
+		__isl_take isl_union_map *proximity);
+	__isl_give isl_schedule_constraints *
+	isl_schedule_constraints_set_conditional_validity(
+		__isl_take isl_schedule_constraints *sc,
+		__isl_take isl_union_map *condition,
+		__isl_take isl_union_map *validity);
+	__isl_give isl_schedule_constraints *
+	isl_schedule_constraints_apply(
+		__isl_take isl_schedule_constraints *sc,
+		__isl_take isl_union_map *umap);
+	__isl_null isl_schedule_constraints *
+	isl_schedule_constraints_free(
+		__isl_take isl_schedule_constraints *sc);
+
+The initial C<isl_schedule_constraints> object created by
+C<isl_schedule_constraints_on_domain> does not impose any constraints.
+That is, it has an empty set of dependences.
+The function C<isl_schedule_constraints_set_context> allows the user
+to specify additional constraints on the parameters that may
+be assumed to hold during the construction of the schedule.
+The function C<isl_schedule_constraints_set_validity> replaces the
+validity dependences, mapping domain elements I<i> to domain
+elements that should be scheduled after I<i>.
+The function C<isl_schedule_constraints_set_coincidence> replaces the
+coincidence dependences, mapping domain elements I<i> to domain
+elements that should be scheduled together with I<I>, if possible.
+The function C<isl_schedule_constraints_set_proximity> replaces the
+proximity dependences, mapping domain elements I<i> to domain
+elements that should be scheduled either before I<I>
+or as early as possible after I<i>.
+
+The function C<isl_schedule_constraints_set_conditional_validity>
+replaces the conditional validity constraints.
+A conditional validity constraint is only imposed when any of the corresponding
+conditions is satisfied, i.e., when any of them is non-zero.
+That is, the scheduler ensures that within each band if the dependence
+distances over the condition constraints are not all zero
+then all corresponding conditional validity constraints are respected.
+A conditional validity constraint corresponds to a condition
+if the two are adjacent, i.e., if the domain of one relation intersect
+the range of the other relation.
+The typical use case of conditional validity constraints is
+to allow order constraints between live ranges to be violated
+as long as the live ranges themselves are local to the band.
+To allow more fine-grained control over which conditions correspond
+to which conditional validity constraints, the domains and ranges
+of these relations may include I<tags>.  That is, the domains and
+ranges of those relation may themselves be wrapped relations
+where the iteration domain appears in the domain of those wrapped relations
+and the range of the wrapped relations can be arbitrarily chosen
+by the user.  Conditions and conditional validity constraints are only
+considered adjacent to each other if the entire wrapped relation matches.
+In particular, a relation with a tag will never be considered adjacent
+to a relation without a tag.
+
+The function C<isl_schedule_constraints_compute_schedule> takes
+schedule constraints that are defined on some set of domain elements
+and transforms them to schedule constraints on the elements
+to which these domain elements are mapped by the given transformation.
+
+An C<isl_schedule_constraints> object can be inspected
+using the following functions.
+
+	#include <isl/schedule.h>
+	__isl_give isl_union_set *
+	isl_schedule_constraints_get_domain(
+		__isl_keep isl_schedule_constraints *sc);
+	__isl_give isl_set *isl_schedule_constraints_get_context(
+		__isl_keep isl_schedule_constraints *sc);
+	__isl_give isl_union_map *
+	isl_schedule_constraints_get_validity(
+		__isl_keep isl_schedule_constraints *sc);
+	__isl_give isl_union_map *
+	isl_schedule_constraints_get_coincidence(
+		__isl_keep isl_schedule_constraints *sc);
+	__isl_give isl_union_map *
+	isl_schedule_constraints_get_proximity(
+		__isl_keep isl_schedule_constraints *sc);
+	__isl_give isl_union_map *
+	isl_schedule_constraints_get_conditional_validity(
+		__isl_keep isl_schedule_constraints *sc);
+	__isl_give isl_union_map *
+	isl_schedule_constraints_get_conditional_validity_condition(
+		__isl_keep isl_schedule_constraints *sc);
+
+An C<isl_schedule_constraints> object can be read from input
+using the following functions.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule_constraints *
+	isl_schedule_constraints_read_from_str(isl_ctx *ctx,
+		const char *str);
+	__isl_give isl_schedule_constraints *
+	isl_schedule_constraints_read_from_file(isl_ctx *ctx,
+		FILE *input);
+
+The contents of an C<isl_schedule_constraints> object can be printed
+using the following functions.
+
+	#include <isl/schedule.h>
+	__isl_give isl_printer *
+	isl_printer_print_schedule_constraints(
+		__isl_take isl_printer *p,
+		__isl_keep isl_schedule_constraints *sc);
+	__isl_give char *isl_schedule_constraints_to_str(
+		__isl_keep isl_schedule_constraints *sc);
+
+The following function computes a schedule directly from
+an iteration domain and validity and proximity dependences
+and is implemented in terms of the functions described above.
+The use of C<isl_union_set_compute_schedule> is discouraged.
+
+	#include <isl/schedule.h>
+	__isl_give isl_schedule *isl_union_set_compute_schedule(
+		__isl_take isl_union_set *domain,
+		__isl_take isl_union_map *validity,
+		__isl_take isl_union_map *proximity);
+
+The generated schedule represents a schedule tree.
+For more information on schedule trees, see
+L</"Schedule Trees">.
+
+=head3 Options
+
+	#include <isl/schedule.h>
+	isl_stat isl_options_set_schedule_max_coefficient(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_max_coefficient(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_schedule_max_constant_term(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_max_constant_term(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_schedule_serialize_sccs(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_serialize_sccs(isl_ctx *ctx);
+	isl_stat isl_options_set_schedule_whole_component(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_whole_component(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_schedule_maximize_band_depth(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_maximize_band_depth(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_schedule_maximize_coincidence(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_maximize_coincidence(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_schedule_outer_coincidence(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_outer_coincidence(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_schedule_split_scaled(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_split_scaled(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_schedule_treat_coalescing(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_treat_coalescing(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_schedule_algorithm(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_algorithm(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_schedule_carry_self_first(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_carry_self_first(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_schedule_separate_components(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_separate_components(
+		isl_ctx *ctx);
+
+=over
+
+=item * schedule_max_coefficient
+
+This option enforces that the coefficients for variable and parameter
+dimensions in the calculated schedule are not larger than the specified value.
+This option can significantly increase the speed of the scheduling calculation
+and may also prevent fusing of unrelated dimensions. A value of -1 means that
+this option does not introduce bounds on the variable or parameter
+coefficients.
+
+=item * schedule_max_constant_term
+
+This option enforces that the constant coefficients in the calculated schedule
+are not larger than the maximal constant term. This option can significantly
+increase the speed of the scheduling calculation and may also prevent fusing of
+unrelated dimensions. A value of -1 means that this option does not introduce
+bounds on the constant coefficients.
+
+=item * schedule_serialize_sccs
+
+If this option is set, then all strongly connected components
+in the dependence graph are serialized as soon as they are detected.
+This means in particular that instances of statements will only
+appear in the same band node if these statements belong
+to the same strongly connected component at the point where
+the band node is constructed.
+
+=item * schedule_whole_component
+
+If this option is set, then entire (weakly) connected
+components in the dependence graph are scheduled together
+as a whole.
+Otherwise, each strongly connected component within
+such a weakly connected component is first scheduled separately
+and then combined with other strongly connected components.
+This option has no effect if C<schedule_serialize_sccs> is set.
+
+=item * schedule_maximize_band_depth
+
+If this option is set, then the scheduler tries to maximize
+the width of the bands.  Wider bands give more possibilities for tiling.
+In particular, if the C<schedule_whole_component> option is set,
+then bands are split if this might result in wider bands.
+Otherwise, the effect of this option is to only allow
+strongly connected components to be combined if this does
+not reduce the width of the bands.
+Note that if the C<schedule_serialize_sccs> options is set, then
+the C<schedule_maximize_band_depth> option therefore has no effect.
+
+=item * schedule_maximize_coincidence
+
+This option is only effective if the C<schedule_whole_component>
+option is turned off.
+If the C<schedule_maximize_coincidence> option is set, then (clusters of)
+strongly connected components are only combined with each other
+if this does not reduce the number of coincident band members.
+
+=item * schedule_outer_coincidence
+
+If this option is set, then we try to construct schedules
+where the outermost scheduling dimension in each band
+satisfies the coincidence constraints.
+
+=item * schedule_algorithm
+
+Selects the scheduling algorithm to be used.
+Available scheduling algorithms are C<ISL_SCHEDULE_ALGORITHM_ISL>
+and C<ISL_SCHEDULE_ALGORITHM_FEAUTRIER>.
+
+=item * schedule_split_scaled
+
+If this option is set, then we try to construct schedules in which the
+constant term is split off from the linear part if the linear parts of
+the scheduling rows for all nodes in the graph have a common non-trivial
+divisor.
+The constant term is then dropped and the linear
+part is reduced.
+This option is only effective when the Feautrier style scheduler is
+being used, either as the main scheduler or as a fallback for the
+Pluto-like scheduler.
+
+=item * schedule_treat_coalescing
+
+If this option is set, then the scheduler will try and avoid
+producing schedules that perform loop coalescing.
+In particular, for the Pluto-like scheduler, this option places
+bounds on the schedule coefficients based on the sizes of the instance sets.
+For the Feautrier style scheduler, this option detects potentially
+coalescing schedules and then tries to adjust the schedule to avoid
+the coalescing.
+
+=item * schedule_carry_self_first
+
+If this option is set, then the Feautrier style scheduler
+(when used as a fallback for the Pluto-like scheduler) will
+first try to only carry self-dependences.
+
+=item * schedule_separate_components
+
+If this option is set then the function C<isl_schedule_get_map>
+will treat set nodes in the same way as sequence nodes.
+
+=back
+
+=head2 AST Generation
+
+This section describes the C<isl> functionality for generating
+ASTs that visit all the elements
+in a domain in an order specified by a schedule tree or
+a schedule map.
+In case the schedule given as a C<isl_union_map>, an AST is generated
+that visits all the elements in the domain of the C<isl_union_map>
+according to the lexicographic order of the corresponding image
+element(s).  If the range of the C<isl_union_map> consists of
+elements in more than one space, then each of these spaces is handled
+separately in an arbitrary order.
+It should be noted that the schedule tree or the image elements
+in a schedule map only specify the I<order>
+in which the corresponding domain elements should be visited.
+No direct relation between the partial schedule values
+or the image elements on the one hand and the loop iterators
+in the generated AST on the other hand should be assumed.
+
+Each AST is generated within a build.  The initial build
+simply specifies the constraints on the parameters (if any)
+and can be created, inspected, copied and freed using the following functions.
+
+	#include <isl/ast_build.h>
+	__isl_give isl_ast_build *isl_ast_build_alloc(
+		isl_ctx *ctx);
+	__isl_give isl_ast_build *isl_ast_build_from_context(
+		__isl_take isl_set *set);
+	__isl_give isl_ast_build *isl_ast_build_copy(
+		__isl_keep isl_ast_build *build);
+	__isl_null isl_ast_build *isl_ast_build_free(
+		__isl_take isl_ast_build *build);
+
+The C<set> argument is usually a parameter set with zero or more parameters.
+In fact, when creating an AST using C<isl_ast_build_node_from_schedule>,
+this set is required to be a parameter set.
+An C<isl_ast_build> created using C<isl_ast_build_alloc> does not
+specify any parameter constraints.
+More C<isl_ast_build> functions are described in L</"Nested AST Generation">
+and L</"Fine-grained Control over AST Generation">.
+Finally, the AST itself can be constructed using one of the following
+functions.
+
+	#include <isl/ast_build.h>
+	__isl_give isl_ast_node *isl_ast_build_node_from_schedule(
+		__isl_keep isl_ast_build *build,
+		__isl_take isl_schedule *schedule);
+	__isl_give isl_ast_node *
+	isl_ast_build_node_from_schedule_map(
+		__isl_keep isl_ast_build *build,
+		__isl_take isl_union_map *schedule);
+
+=head3 Inspecting the AST
+
+The basic properties of an AST node can be obtained as follows.
+
+	#include <isl/ast.h>
+	enum isl_ast_node_type isl_ast_node_get_type(
+		__isl_keep isl_ast_node *node);
+
+The type of an AST node is one of
+C<isl_ast_node_for>,
+C<isl_ast_node_if>,
+C<isl_ast_node_block>,
+C<isl_ast_node_mark> or
+C<isl_ast_node_user>.
+An C<isl_ast_node_for> represents a for node.
+An C<isl_ast_node_if> represents an if node.
+An C<isl_ast_node_block> represents a compound node.
+An C<isl_ast_node_mark> introduces a mark in the AST.
+An C<isl_ast_node_user> represents an expression statement.
+An expression statement typically corresponds to a domain element, i.e.,
+one of the elements that is visited by the AST.
+
+Each type of node has its own additional properties.
+
+	#include <isl/ast.h>
+	__isl_give isl_ast_expr *isl_ast_node_for_get_iterator(
+		__isl_keep isl_ast_node *node);
+	__isl_give isl_ast_expr *isl_ast_node_for_get_init(
+		__isl_keep isl_ast_node *node);
+	__isl_give isl_ast_expr *isl_ast_node_for_get_cond(
+		__isl_keep isl_ast_node *node);
+	__isl_give isl_ast_expr *isl_ast_node_for_get_inc(
+		__isl_keep isl_ast_node *node);
+	__isl_give isl_ast_node *isl_ast_node_for_get_body(
+		__isl_keep isl_ast_node *node);
+	isl_bool isl_ast_node_for_is_degenerate(
+		__isl_keep isl_ast_node *node);
+
+An C<isl_ast_for> is considered degenerate if it is known to execute
+exactly once.
+
+	#include <isl/ast.h>
+	__isl_give isl_ast_expr *isl_ast_node_if_get_cond(
+		__isl_keep isl_ast_node *node);
+	__isl_give isl_ast_node *isl_ast_node_if_get_then(
+		__isl_keep isl_ast_node *node);
+	isl_bool isl_ast_node_if_has_else(
+		__isl_keep isl_ast_node *node);
+	__isl_give isl_ast_node *isl_ast_node_if_get_else(
+		__isl_keep isl_ast_node *node);
+
+	__isl_give isl_ast_node_list *
+	isl_ast_node_block_get_children(
+		__isl_keep isl_ast_node *node);
+
+	__isl_give isl_id *isl_ast_node_mark_get_id(
+		__isl_keep isl_ast_node *node);
+	__isl_give isl_ast_node *isl_ast_node_mark_get_node(
+		__isl_keep isl_ast_node *node);
+
+C<isl_ast_node_mark_get_id> returns the identifier of the mark.
+C<isl_ast_node_mark_get_node> returns the child node that is being marked.
+
+	#include <isl/ast.h>
+	__isl_give isl_ast_expr *isl_ast_node_user_get_expr(
+		__isl_keep isl_ast_node *node);
+
+All descendants of a specific node in the AST (including the node itself)
+can be visited
+in depth-first pre-order using the following function.
+
+	#include <isl/ast.h>
+	isl_stat isl_ast_node_foreach_descendant_top_down(
+		__isl_keep isl_ast_node *node,
+		isl_bool (*fn)(__isl_keep isl_ast_node *node,
+			void *user), void *user);
+
+The callback function should return C<isl_bool_true> if the children
+of the given node should be visited and C<isl_bool_false> if they should not.
+It should return C<isl_bool_error> in case of failure, in which case
+the entire traversal is aborted.
+
+Each of the returned C<isl_ast_expr>s can in turn be inspected using
+the following functions.
+
+	#include <isl/ast.h>
+	enum isl_ast_expr_type isl_ast_expr_get_type(
+		__isl_keep isl_ast_expr *expr);
+
+The type of an AST expression is one of
+C<isl_ast_expr_op>,
+C<isl_ast_expr_id> or
+C<isl_ast_expr_int>.
+An C<isl_ast_expr_op> represents the result of an operation.
+An C<isl_ast_expr_id> represents an identifier.
+An C<isl_ast_expr_int> represents an integer value.
+
+Each type of expression has its own additional properties.
+
+	#include <isl/ast.h>
+	enum isl_ast_op_type isl_ast_expr_get_op_type(
+		__isl_keep isl_ast_expr *expr);
+	int isl_ast_expr_get_op_n_arg(__isl_keep isl_ast_expr *expr);
+	__isl_give isl_ast_expr *isl_ast_expr_get_op_arg(
+		__isl_keep isl_ast_expr *expr, int pos);
+	isl_stat isl_ast_expr_foreach_ast_op_type(
+		__isl_keep isl_ast_expr *expr,
+		isl_stat (*fn)(enum isl_ast_op_type type,
+			void *user), void *user);
+	isl_stat isl_ast_node_foreach_ast_op_type(
+		__isl_keep isl_ast_node *node,
+		isl_stat (*fn)(enum isl_ast_op_type type,
+			void *user), void *user);
+
+C<isl_ast_expr_get_op_type> returns the type of the operation
+performed.  C<isl_ast_expr_get_op_n_arg> returns the number of
+arguments.  C<isl_ast_expr_get_op_arg> returns the specified
+argument.
+C<isl_ast_expr_foreach_ast_op_type> calls C<fn> for each distinct
+C<isl_ast_op_type> that appears in C<expr>.
+C<isl_ast_node_foreach_ast_op_type> does the same for each distinct
+C<isl_ast_op_type> that appears in C<node>.
+The operation type is one of the following.
+
+=over
+
+=item C<isl_ast_op_and>
+
+Logical I<and> of two arguments.
+Both arguments can be evaluated.
+
+=item C<isl_ast_op_and_then>
+
+Logical I<and> of two arguments.
+The second argument can only be evaluated if the first evaluates to true.
+
+=item C<isl_ast_op_or>
+
+Logical I<or> of two arguments.
+Both arguments can be evaluated.
+
+=item C<isl_ast_op_or_else>
+
+Logical I<or> of two arguments.
+The second argument can only be evaluated if the first evaluates to false.
+
+=item C<isl_ast_op_max>
+
+Maximum of two or more arguments.
+
+=item C<isl_ast_op_min>
+
+Minimum of two or more arguments.
+
+=item C<isl_ast_op_minus>
+
+Change sign.
+
+=item C<isl_ast_op_add>
+
+Sum of two arguments.
+
+=item C<isl_ast_op_sub>
+
+Difference of two arguments.
+
+=item C<isl_ast_op_mul>
+
+Product of two arguments.
+
+=item C<isl_ast_op_div>
+
+Exact division.  That is, the result is known to be an integer.
+
+=item C<isl_ast_op_fdiv_q>
+
+Result of integer division, rounded towards negative
+infinity.
+
+=item C<isl_ast_op_pdiv_q>
+
+Result of integer division, where dividend is known to be non-negative.
+
+=item C<isl_ast_op_pdiv_r>
+
+Remainder of integer division, where dividend is known to be non-negative.
+
+=item C<isl_ast_op_zdiv_r>
+
+Equal to zero iff the remainder on integer division is zero.
+
+=item C<isl_ast_op_cond>
+
+Conditional operator defined on three arguments.
+If the first argument evaluates to true, then the result
+is equal to the second argument.  Otherwise, the result
+is equal to the third argument.
+The second and third argument may only be evaluated if
+the first argument evaluates to true and false, respectively.
+Corresponds to C<a ? b : c> in C.
+
+=item C<isl_ast_op_select>
+
+Conditional operator defined on three arguments.
+If the first argument evaluates to true, then the result
+is equal to the second argument.  Otherwise, the result
+is equal to the third argument.
+The second and third argument may be evaluated independently
+of the value of the first argument.
+Corresponds to C<a * b + (1 - a) * c> in C.
+
+=item C<isl_ast_op_eq>
+
+Equality relation.
+
+=item C<isl_ast_op_le>
+
+Less than or equal relation.
+
+=item C<isl_ast_op_lt>
+
+Less than relation.
+
+=item C<isl_ast_op_ge>
+
+Greater than or equal relation.
+
+=item C<isl_ast_op_gt>
+
+Greater than relation.
+
+=item C<isl_ast_op_call>
+
+A function call.
+The number of arguments of the C<isl_ast_expr> is one more than
+the number of arguments in the function call, the first argument
+representing the function being called.
+
+=item C<isl_ast_op_access>
+
+An array access.
+The number of arguments of the C<isl_ast_expr> is one more than
+the number of index expressions in the array access, the first argument
+representing the array being accessed.
+
+=item C<isl_ast_op_member>
+
+A member access.
+This operation has two arguments, a structure and the name of
+the member of the structure being accessed.
+
+=back
+
+	#include <isl/ast.h>
+	__isl_give isl_id *isl_ast_expr_get_id(
+		__isl_keep isl_ast_expr *expr);
+
+Return the identifier represented by the AST expression.
+
+	#include <isl/ast.h>
+	__isl_give isl_val *isl_ast_expr_get_val(
+		__isl_keep isl_ast_expr *expr);
+
+Return the integer represented by the AST expression.
+
+=head3 Properties of ASTs
+
+	#include <isl/ast.h>
+	isl_bool isl_ast_expr_is_equal(
+		__isl_keep isl_ast_expr *expr1,
+		__isl_keep isl_ast_expr *expr2);
+
+Check if two C<isl_ast_expr>s are equal to each other.
+
+=head3 Manipulating and printing the AST
+
+AST nodes can be copied and freed using the following functions.
+
+	#include <isl/ast.h>
+	__isl_give isl_ast_node *isl_ast_node_copy(
+		__isl_keep isl_ast_node *node);
+	__isl_null isl_ast_node *isl_ast_node_free(
+		__isl_take isl_ast_node *node);
+
+AST expressions can be copied and freed using the following functions.
+
+	#include <isl/ast.h>
+	__isl_give isl_ast_expr *isl_ast_expr_copy(
+		__isl_keep isl_ast_expr *expr);
+	__isl_null isl_ast_expr *isl_ast_expr_free(
+		__isl_take isl_ast_expr *expr);
+
+New AST expressions can be created either directly or within
+the context of an C<isl_ast_build>.
+
+	#include <isl/ast.h>
+	__isl_give isl_ast_expr *isl_ast_expr_from_val(
+		__isl_take isl_val *v);
+	__isl_give isl_ast_expr *isl_ast_expr_from_id(
+		__isl_take isl_id *id);
+	__isl_give isl_ast_expr *isl_ast_expr_neg(
+		__isl_take isl_ast_expr *expr);
+	__isl_give isl_ast_expr *isl_ast_expr_address_of(
+		__isl_take isl_ast_expr *expr);
+	__isl_give isl_ast_expr *isl_ast_expr_add(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2);
+	__isl_give isl_ast_expr *isl_ast_expr_sub(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2);
+	__isl_give isl_ast_expr *isl_ast_expr_mul(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2);
+	__isl_give isl_ast_expr *isl_ast_expr_div(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2);
+	__isl_give isl_ast_expr *isl_ast_expr_pdiv_q(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2);
+	__isl_give isl_ast_expr *isl_ast_expr_pdiv_r(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2);
+	__isl_give isl_ast_expr *isl_ast_expr_and(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2)
+	__isl_give isl_ast_expr *isl_ast_expr_and_then(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2)
+	__isl_give isl_ast_expr *isl_ast_expr_or(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2)
+	__isl_give isl_ast_expr *isl_ast_expr_or_else(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2)
+	__isl_give isl_ast_expr *isl_ast_expr_eq(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2);
+	__isl_give isl_ast_expr *isl_ast_expr_le(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2);
+	__isl_give isl_ast_expr *isl_ast_expr_lt(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2);
+	__isl_give isl_ast_expr *isl_ast_expr_ge(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2);
+	__isl_give isl_ast_expr *isl_ast_expr_gt(
+		__isl_take isl_ast_expr *expr1,
+		__isl_take isl_ast_expr *expr2);
+	__isl_give isl_ast_expr *isl_ast_expr_access(
+		__isl_take isl_ast_expr *array,
+		__isl_take isl_ast_expr_list *indices);
+	__isl_give isl_ast_expr *isl_ast_expr_call(
+		__isl_take isl_ast_expr *function,
+		__isl_take isl_ast_expr_list *arguments);
+
+The function C<isl_ast_expr_address_of> can be applied to an
+C<isl_ast_expr> of type C<isl_ast_op_access> only. It is meant
+to represent the address of the C<isl_ast_expr_access>. The function
+C<isl_ast_expr_and_then> as well as C<isl_ast_expr_or_else> are short-circuit
+versions of C<isl_ast_expr_and> and C<isl_ast_expr_or>, respectively.
+
+	#include <isl/ast_build.h>
+	__isl_give isl_ast_expr *isl_ast_build_expr_from_set(
+		__isl_keep isl_ast_build *build,
+		__isl_take isl_set *set);
+	__isl_give isl_ast_expr *isl_ast_build_expr_from_pw_aff(
+		__isl_keep isl_ast_build *build,
+		__isl_take isl_pw_aff *pa);
+	__isl_give isl_ast_expr *
+	isl_ast_build_access_from_pw_multi_aff(
+		__isl_keep isl_ast_build *build,
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_ast_expr *
+	isl_ast_build_access_from_multi_pw_aff(
+		__isl_keep isl_ast_build *build,
+		__isl_take isl_multi_pw_aff *mpa);
+	__isl_give isl_ast_expr *
+	isl_ast_build_call_from_pw_multi_aff(
+		__isl_keep isl_ast_build *build,
+		__isl_take isl_pw_multi_aff *pma);
+	__isl_give isl_ast_expr *
+	isl_ast_build_call_from_multi_pw_aff(
+		__isl_keep isl_ast_build *build,
+		__isl_take isl_multi_pw_aff *mpa);
+
+The set <set> and
+the domains of C<pa>, C<mpa> and C<pma> should correspond
+to the schedule space of C<build>.
+The tuple id of C<mpa> or C<pma> is used as the array being accessed or
+the function being called.
+If the accessed space is a nested relation, then it is taken
+to represent an access of the member specified by the range
+of this nested relation of the structure specified by the domain
+of the nested relation.
+
+The following functions can be used to modify an C<isl_ast_expr>.
+
+	#include <isl/ast.h>
+	__isl_give isl_ast_expr *isl_ast_expr_set_op_arg(
+		__isl_take isl_ast_expr *expr, int pos,
+		__isl_take isl_ast_expr *arg);
+
+Replace the argument of C<expr> at position C<pos> by C<arg>.
+
+	#include <isl/ast.h>
+	__isl_give isl_ast_expr *isl_ast_expr_substitute_ids(
+		__isl_take isl_ast_expr *expr,
+		__isl_take isl_id_to_ast_expr *id2expr);
+
+The function C<isl_ast_expr_substitute_ids> replaces the
+subexpressions of C<expr> of type C<isl_ast_expr_id>
+by the corresponding expression in C<id2expr>, if there is any.
+
+
+User specified data can be attached to an C<isl_ast_node> and obtained
+from the same C<isl_ast_node> using the following functions.
+
+	#include <isl/ast.h>
+	__isl_give isl_ast_node *isl_ast_node_set_annotation(
+		__isl_take isl_ast_node *node,
+		__isl_take isl_id *annotation);
+	__isl_give isl_id *isl_ast_node_get_annotation(
+		__isl_keep isl_ast_node *node);
+
+Basic printing can be performed using the following functions.
+
+	#include <isl/ast.h>
+	__isl_give isl_printer *isl_printer_print_ast_expr(
+		__isl_take isl_printer *p,
+		__isl_keep isl_ast_expr *expr);
+	__isl_give isl_printer *isl_printer_print_ast_node(
+		__isl_take isl_printer *p,
+		__isl_keep isl_ast_node *node);
+	__isl_give char *isl_ast_expr_to_str(
+		__isl_keep isl_ast_expr *expr);
+	__isl_give char *isl_ast_node_to_str(
+		__isl_keep isl_ast_node *node);
+	__isl_give char *isl_ast_expr_to_C_str(
+		__isl_keep isl_ast_expr *expr);
+	__isl_give char *isl_ast_node_to_C_str(
+		__isl_keep isl_ast_node *node);
+
+The functions C<isl_ast_expr_to_C_str> and
+C<isl_ast_node_to_C_str> are convenience functions
+that return a string representation of the input in C format.
+
+More advanced printing can be performed using the following functions.
+
+	#include <isl/ast.h>
+	__isl_give isl_printer *isl_ast_op_type_set_print_name(
+		__isl_take isl_printer *p,
+		enum isl_ast_op_type type,
+		__isl_keep const char *name);
+	isl_stat isl_options_set_ast_print_macro_once(
+		isl_ctx *ctx, int val);
+	int isl_options_get_ast_print_macro_once(isl_ctx *ctx);
+	__isl_give isl_printer *isl_ast_op_type_print_macro(
+		enum isl_ast_op_type type,
+		__isl_take isl_printer *p);
+	__isl_give isl_printer *isl_ast_expr_print_macros(
+		__isl_keep isl_ast_expr *expr,
+		__isl_take isl_printer *p);
+	__isl_give isl_printer *isl_ast_node_print_macros(
+		__isl_keep isl_ast_node *node,
+		__isl_take isl_printer *p);
+	__isl_give isl_printer *isl_ast_node_print(
+		__isl_keep isl_ast_node *node,
+		__isl_take isl_printer *p,
+		__isl_take isl_ast_print_options *options);
+	__isl_give isl_printer *isl_ast_node_for_print(
+		__isl_keep isl_ast_node *node,
+		__isl_take isl_printer *p,
+		__isl_take isl_ast_print_options *options);
+	__isl_give isl_printer *isl_ast_node_if_print(
+		__isl_keep isl_ast_node *node,
+		__isl_take isl_printer *p,
+		__isl_take isl_ast_print_options *options);
+
+While printing an C<isl_ast_node> in C<ISL_FORMAT_C>,
+C<isl> may print out an AST that makes use of macros such
+as C<floord>, C<min> and C<max>.
+The names of these macros may be modified by a call
+to C<isl_ast_op_type_set_print_name>.  The user-specified
+names are associated to the printer object.
+C<isl_ast_op_type_print_macro> prints out the macro
+corresponding to a specific C<isl_ast_op_type>.
+If the print-macro-once option is set, then a given macro definition
+is only printed once to any given printer object.
+C<isl_ast_expr_print_macros> scans the C<isl_ast_expr>
+for subexpressions where these macros would be used and prints
+out the required macro definitions.
+Essentially, C<isl_ast_expr_print_macros> calls
+C<isl_ast_expr_foreach_ast_op_type> with C<isl_ast_op_type_print_macro>
+as function argument.
+C<isl_ast_node_print_macros> does the same
+for expressions in its C<isl_ast_node> argument.
+C<isl_ast_node_print>, C<isl_ast_node_for_print> and
+C<isl_ast_node_if_print> print an C<isl_ast_node>
+in C<ISL_FORMAT_C>, but allow for some extra control
+through an C<isl_ast_print_options> object.
+This object can be created using the following functions.
+
+	#include <isl/ast.h>
+	__isl_give isl_ast_print_options *
+	isl_ast_print_options_alloc(isl_ctx *ctx);
+	__isl_give isl_ast_print_options *
+	isl_ast_print_options_copy(
+		__isl_keep isl_ast_print_options *options);
+	__isl_null isl_ast_print_options *
+	isl_ast_print_options_free(
+		__isl_take isl_ast_print_options *options);
+
+	__isl_give isl_ast_print_options *
+	isl_ast_print_options_set_print_user(
+		__isl_take isl_ast_print_options *options,
+		__isl_give isl_printer *(*print_user)(
+			__isl_take isl_printer *p,
+			__isl_take isl_ast_print_options *options,
+			__isl_keep isl_ast_node *node, void *user),
+		void *user);
+	__isl_give isl_ast_print_options *
+	isl_ast_print_options_set_print_for(
+		__isl_take isl_ast_print_options *options,
+		__isl_give isl_printer *(*print_for)(
+			__isl_take isl_printer *p,
+			__isl_take isl_ast_print_options *options,
+			__isl_keep isl_ast_node *node, void *user),
+		void *user);
+
+The callback set by C<isl_ast_print_options_set_print_user>
+is called whenever a node of type C<isl_ast_node_user> needs to
+be printed.
+The callback set by C<isl_ast_print_options_set_print_for>
+is called whenever a node of type C<isl_ast_node_for> needs to
+be printed.
+Note that C<isl_ast_node_for_print> will I<not> call the
+callback set by C<isl_ast_print_options_set_print_for> on the node
+on which C<isl_ast_node_for_print> is called, but only on nested
+nodes of type C<isl_ast_node_for>.  It is therefore safe to
+call C<isl_ast_node_for_print> from within the callback set by
+C<isl_ast_print_options_set_print_for>.
+
+The following option determines the type to be used for iterators
+while printing the AST.
+
+	isl_stat isl_options_set_ast_iterator_type(
+		isl_ctx *ctx, const char *val);
+	const char *isl_options_get_ast_iterator_type(
+		isl_ctx *ctx);
+
+The AST printer only prints body nodes as blocks if these
+blocks cannot be safely omitted.
+For example, a C<for> node with one body node will not be
+surrounded with braces in C<ISL_FORMAT_C>.
+A block will always be printed by setting the following option.
+
+	isl_stat isl_options_set_ast_always_print_block(isl_ctx *ctx,
+		int val);
+	int isl_options_get_ast_always_print_block(isl_ctx *ctx);
+
+=head3 Options
+
+	#include <isl/ast_build.h>
+	isl_stat isl_options_set_ast_build_atomic_upper_bound(
+		isl_ctx *ctx, int val);
+	int isl_options_get_ast_build_atomic_upper_bound(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_ast_build_prefer_pdiv(isl_ctx *ctx,
+		int val);
+	int isl_options_get_ast_build_prefer_pdiv(isl_ctx *ctx);
+	isl_stat isl_options_set_ast_build_detect_min_max(
+		isl_ctx *ctx, int val);
+	int isl_options_get_ast_build_detect_min_max(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_ast_build_exploit_nested_bounds(
+		isl_ctx *ctx, int val);
+	int isl_options_get_ast_build_exploit_nested_bounds(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_ast_build_group_coscheduled(
+		isl_ctx *ctx, int val);
+	int isl_options_get_ast_build_group_coscheduled(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_ast_build_scale_strides(
+		isl_ctx *ctx, int val);
+	int isl_options_get_ast_build_scale_strides(
+		isl_ctx *ctx);
+	isl_stat isl_options_set_ast_build_allow_else(isl_ctx *ctx,
+		int val);
+	int isl_options_get_ast_build_allow_else(isl_ctx *ctx);
+	isl_stat isl_options_set_ast_build_allow_or(isl_ctx *ctx,
+		int val);
+	int isl_options_get_ast_build_allow_or(isl_ctx *ctx);
+
+=over
+
+=item * ast_build_atomic_upper_bound
+
+Generate loop upper bounds that consist of the current loop iterator,
+an operator and an expression not involving the iterator.
+If this option is not set, then the current loop iterator may appear
+several times in the upper bound.
+For example, when this option is turned off, AST generation
+for the schedule
+
+	[n] -> { A[i] -> [i] : 0 <= i <= 100, n }
+
+produces
+
+	for (int c0 = 0; c0 <= 100 && n >= c0; c0 += 1)
+	  A(c0);
+
+When the option is turned on, the following AST is generated
+
+	for (int c0 = 0; c0 <= min(100, n); c0 += 1)
+	  A(c0);
+
+=item * ast_build_prefer_pdiv
+
+If this option is turned off, then the AST generation will
+produce ASTs that may only contain C<isl_ast_op_fdiv_q>
+operators, but no C<isl_ast_op_pdiv_q> or
+C<isl_ast_op_pdiv_r> operators.
+If this option is turned on, then C<isl> will try to convert
+some of the C<isl_ast_op_fdiv_q> operators to (expressions containing)
+C<isl_ast_op_pdiv_q> or C<isl_ast_op_pdiv_r> operators.
+
+=item * ast_build_detect_min_max
+
+If this option is turned on, then C<isl> will try and detect
+min or max-expressions when building AST expressions from
+piecewise affine expressions.
+
+=item * ast_build_exploit_nested_bounds
+
+Simplify conditions based on bounds of nested for loops.
+In particular, remove conditions that are implied by the fact
+that one or more nested loops have at least one iteration,
+meaning that the upper bound is at least as large as the lower bound.
+For example, when this option is turned off, AST generation
+for the schedule
+
+	[N,M] -> { A[i,j] -> [i,j] : 0 <= i <= N and
+					0 <= j <= M }
+
+produces
+
+	if (M >= 0)
+	  for (int c0 = 0; c0 <= N; c0 += 1)
+	    for (int c1 = 0; c1 <= M; c1 += 1)
+	      A(c0, c1);
+
+When the option is turned on, the following AST is generated
+
+	for (int c0 = 0; c0 <= N; c0 += 1)
+	  for (int c1 = 0; c1 <= M; c1 += 1)
+	    A(c0, c1);
+
+=item * ast_build_group_coscheduled
+
+If two domain elements are assigned the same schedule point, then
+they may be executed in any order and they may even appear in different
+loops.  If this options is set, then the AST generator will make
+sure that coscheduled domain elements do not appear in separate parts
+of the AST.  This is useful in case of nested AST generation
+if the outer AST generation is given only part of a schedule
+and the inner AST generation should handle the domains that are
+coscheduled by this initial part of the schedule together.
+For example if an AST is generated for a schedule
+
+	{ A[i] -> [0]; B[i] -> [0] }
+
+then the C<isl_ast_build_set_create_leaf> callback described
+below may get called twice, once for each domain.
+Setting this option ensures that the callback is only called once
+on both domains together.
+
+=item * ast_build_separation_bounds
+
+This option specifies which bounds to use during separation.
+If this option is set to C<ISL_AST_BUILD_SEPARATION_BOUNDS_IMPLICIT>
+then all (possibly implicit) bounds on the current dimension will
+be used during separation.
+If this option is set to C<ISL_AST_BUILD_SEPARATION_BOUNDS_EXPLICIT>
+then only those bounds that are explicitly available will
+be used during separation.
+
+=item * ast_build_scale_strides
+
+This option specifies whether the AST generator is allowed
+to scale down iterators of strided loops.
+
+=item * ast_build_allow_else
+
+This option specifies whether the AST generator is allowed
+to construct if statements with else branches.
+
+=item * ast_build_allow_or
+
+This option specifies whether the AST generator is allowed
+to construct if conditions with disjunctions.
+
+=back
+
+=head3 AST Generation Options (Schedule Tree)
+
+In case of AST construction from a schedule tree, the options
+that control how an AST is created from the individual schedule
+dimensions are stored in the band nodes of the tree
+(see L</"Schedule Trees">).
+
+In particular, a schedule dimension can be handled in four
+different ways, atomic, separate, unroll or the default.
+This loop AST generation type can be set using
+C<isl_schedule_node_band_member_set_ast_loop_type>.
+Alternatively,
+the first three can be selected by including a one-dimensional
+element with as value the position of the schedule dimension
+within the band and as name one of C<atomic>, C<separate>
+or C<unroll> in the options
+set by C<isl_schedule_node_band_set_ast_build_options>.
+Only one of these three may be specified for
+any given schedule dimension within a band node.
+If none of these is specified, then the default
+is used.  The meaning of the options is as follows.
+
+=over
+
+=item C<atomic>
+
+When this option is specified, the AST generator will make
+sure that a given domains space only appears in a single
+loop at the specified level.
+
+For example, for the schedule tree
+
+	domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }"
+	child:
+	  schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]"
+	  options: "{ atomic[x] }"
+
+the following AST will be generated
+
+	for (int c0 = 0; c0 <= 10; c0 += 1) {
+	  if (c0 >= 1)
+	    b(c0 - 1);
+	  if (c0 <= 9)
+	    a(c0);
+	}
+
+On the other hand, for the schedule tree
+
+	domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }"
+	child:
+	  schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]"
+	  options: "{ separate[x] }"
+
+the following AST will be generated
+
+	{
+	  a(0);
+	  for (int c0 = 1; c0 <= 9; c0 += 1) {
+	    b(c0 - 1);
+	    a(c0);
+	  }
+	  b(9);
+	}
+
+If neither C<atomic> nor C<separate> is specified, then the AST generator
+may produce either of these two results or some intermediate form.
+
+=item C<separate>
+
+When this option is specified, the AST generator will
+split the domain of the specified schedule dimension
+into pieces with a fixed set of statements for which
+instances need to be executed by the iterations in
+the schedule domain part.  This option tends to avoid
+the generation of guards inside the corresponding loops.
+See also the C<atomic> option.
+
+=item C<unroll>
+
+When this option is specified, the AST generator will
+I<completely> unroll the corresponding schedule dimension.
+It is the responsibility of the user to ensure that such
+unrolling is possible.
+To obtain a partial unrolling, the user should apply an additional
+strip-mining to the schedule and fully unroll the inner schedule
+dimension.
+
+=back
+
+The C<isolate> option is a bit more involved.  It allows the user
+to isolate a range of schedule dimension values from smaller and
+greater values.  Additionally, the user may specify a different
+atomic/separate/unroll choice for the isolated part and the remaining
+parts.  The typical use case of the C<isolate> option is to isolate
+full tiles from partial tiles.
+The part that needs to be isolated may depend on outer schedule dimensions.
+The option therefore needs to be able to reference those outer schedule
+dimensions.  In particular, the space of the C<isolate> option is that
+of a wrapped map with as domain the flat product of all outer band nodes
+and as range the space of the current band node.
+The atomic/separate/unroll choice for the isolated part is determined
+by an option that lives in an unnamed wrapped space with as domain
+a zero-dimensional C<isolate> space and as range the regular
+C<atomic>, C<separate> or C<unroll> space.
+This option may also be set directly using
+C<isl_schedule_node_band_member_set_isolate_ast_loop_type>.
+The atomic/separate/unroll choice for the remaining part is determined
+by the regular C<atomic>, C<separate> or C<unroll> option.
+Since the C<isolate> option references outer schedule dimensions,
+its use in a band node causes any tree containing the node
+to be considered anchored.
+
+As an example, consider the isolation of full tiles from partial tiles
+in a tiling of a triangular domain.  The original schedule is as follows.
+
+	domain: "{ A[i,j] : 0 <= i,j and i + j <= 100 }"
+	child:
+	  schedule: "[{ A[i,j] -> [floor(i/10)] }, \
+		{ A[i,j] -> [floor(j/10)] }, \
+		{ A[i,j] -> [i] }, { A[i,j] -> [j] }]"
+
+The output is
+
+	for (int c0 = 0; c0 <= 10; c0 += 1)
+	  for (int c1 = 0; c1 <= -c0 + 10; c1 += 1)
+	    for (int c2 = 10 * c0;
+                 c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1)
+	      for (int c3 = 10 * c1;
+                   c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1)
+		A(c2, c3);
+
+Isolating the full tiles, we have the following input
+
+	domain: "{ A[i,j] : 0 <= i,j and i + j <= 100 }"
+	child:
+	  schedule: "[{ A[i,j] -> [floor(i/10)] }, \
+		{ A[i,j] -> [floor(j/10)] }, \
+		{ A[i,j] -> [i] }, { A[i,j] -> [j] }]"
+	  options: "{ isolate[[] -> [a,b,c,d]] : 0 <= 10a,10b and \
+		10a+9+10b+9 <= 100 }"
+
+and output
+
+	{
+	  for (int c0 = 0; c0 <= 8; c0 += 1) {
+	    for (int c1 = 0; c1 <= -c0 + 8; c1 += 1)
+	      for (int c2 = 10 * c0;
+		   c2 <= 10 * c0 + 9; c2 += 1)
+		for (int c3 = 10 * c1;
+		     c3 <= 10 * c1 + 9; c3 += 1)
+		  A(c2, c3);
+	    for (int c1 = -c0 + 9; c1 <= -c0 + 10; c1 += 1)
+	      for (int c2 = 10 * c0;
+                   c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1)
+		for (int c3 = 10 * c1;
+                     c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1)
+		  A(c2, c3);
+	  }
+	  for (int c0 = 9; c0 <= 10; c0 += 1)
+	    for (int c1 = 0; c1 <= -c0 + 10; c1 += 1)
+	      for (int c2 = 10 * c0;
+                   c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1)
+		for (int c3 = 10 * c1;
+                     c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1)
+		  A(c2, c3);
+	}
+
+We may then additionally unroll the innermost loop of the isolated part
+
+	domain: "{ A[i,j] : 0 <= i,j and i + j <= 100 }"
+	child:
+	  schedule: "[{ A[i,j] -> [floor(i/10)] }, \
+		{ A[i,j] -> [floor(j/10)] }, \
+		{ A[i,j] -> [i] }, { A[i,j] -> [j] }]"
+	  options: "{ isolate[[] -> [a,b,c,d]] : 0 <= 10a,10b and \
+		10a+9+10b+9 <= 100; [isolate[] -> unroll[3]] }"
+
+to obtain
+
+	{
+	  for (int c0 = 0; c0 <= 8; c0 += 1) {
+	    for (int c1 = 0; c1 <= -c0 + 8; c1 += 1)
+	      for (int c2 = 10 * c0; c2 <= 10 * c0 + 9; c2 += 1) {
+		A(c2, 10 * c1);
+		A(c2, 10 * c1 + 1);
+		A(c2, 10 * c1 + 2);
+		A(c2, 10 * c1 + 3);
+		A(c2, 10 * c1 + 4);
+		A(c2, 10 * c1 + 5);
+		A(c2, 10 * c1 + 6);
+		A(c2, 10 * c1 + 7);
+		A(c2, 10 * c1 + 8);
+		A(c2, 10 * c1 + 9);
+	      }
+	    for (int c1 = -c0 + 9; c1 <= -c0 + 10; c1 += 1)
+	      for (int c2 = 10 * c0;
+                   c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1)
+		for (int c3 = 10 * c1;
+		     c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1)
+		  A(c2, c3);
+	  }
+	  for (int c0 = 9; c0 <= 10; c0 += 1)
+	    for (int c1 = 0; c1 <= -c0 + 10; c1 += 1)
+	      for (int c2 = 10 * c0;
+		   c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1)
+		for (int c3 = 10 * c1;
+		     c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1)
+		  A(c2, c3);
+	}
+
+
+=head3 AST Generation Options (Schedule Map)
+
+In case of AST construction using
+C<isl_ast_build_node_from_schedule_map>, the options
+that control how an AST is created from the individual schedule
+dimensions are stored in the C<isl_ast_build>.
+They can be set using the following function.
+
+	#include <isl/ast_build.h>
+	__isl_give isl_ast_build *
+	isl_ast_build_set_options(
+		__isl_take isl_ast_build *control,
+		__isl_take isl_union_map *options);
+
+The options are encoded in an C<isl_union_map>.
+The domain of this union relation refers to the schedule domain,
+i.e., the range of the schedule passed
+to C<isl_ast_build_node_from_schedule_map>.
+In the case of nested AST generation (see L</"Nested AST Generation">),
+the domain of C<options> should refer to the extra piece of the schedule.
+That is, it should be equal to the range of the wrapped relation in the
+range of the schedule.
+The range of the options can consist of elements in one or more spaces,
+the names of which determine the effect of the option.
+The values of the range typically also refer to the schedule dimension
+to which the option applies.  In case of nested AST generation
+(see L</"Nested AST Generation">), these values refer to the position
+of the schedule dimension within the innermost AST generation.
+The constraints on the domain elements of
+the option should only refer to this dimension and earlier dimensions.
+We consider the following spaces.
+
+=over
+
+=item C<separation_class>
+
+B<This option has been deprecated.  Use the isolate option on
+schedule trees instead.>
+
+This space is a wrapped relation between two one dimensional spaces.
+The input space represents the schedule dimension to which the option
+applies and the output space represents the separation class.
+While constructing a loop corresponding to the specified schedule
+dimension(s), the AST generator will try to generate separate loops
+for domain elements that are assigned different classes.
+If only some of the elements are assigned a class, then those elements
+that are not assigned any class will be treated as belonging to a class
+that is separate from the explicitly assigned classes.
+The typical use case for this option is to separate full tiles from
+partial tiles.
+The other options, described below, are applied after the separation
+into classes.
+
+As an example, consider the separation into full and partial tiles
+of a tiling of a triangular domain.
+Take, for example, the domain
+
+	{ A[i,j] : 0 <= i,j and i + j <= 100 }
+
+and a tiling into tiles of 10 by 10.  The input to the AST generator
+is then the schedule
+
+	{ A[i,j] -> [([i/10]),[j/10],i,j] : 0 <= i,j and
+						i + j <= 100 }
+
+Without any options, the following AST is generated
+
+	for (int c0 = 0; c0 <= 10; c0 += 1)
+	  for (int c1 = 0; c1 <= -c0 + 10; c1 += 1)
+	    for (int c2 = 10 * c0;
+		 c2 <= min(-10 * c1 + 100, 10 * c0 + 9);
+		 c2 += 1)
+	      for (int c3 = 10 * c1;
+		   c3 <= min(10 * c1 + 9, -c2 + 100);
+		   c3 += 1)
+		A(c2, c3);
+
+Separation into full and partial tiles can be obtained by assigning
+a class, say C<0>, to the full tiles.  The full tiles are represented by those
+values of the first and second schedule dimensions for which there are
+values of the third and fourth dimensions to cover an entire tile.
+That is, we need to specify the following option
+
+	{ [a,b,c,d] -> separation_class[[0]->[0]] :
+		exists b': 0 <= 10a,10b' and
+			   10a+9+10b'+9 <= 100;
+	  [a,b,c,d] -> separation_class[[1]->[0]] :
+		0 <= 10a,10b and 10a+9+10b+9 <= 100 }
+
+which simplifies to
+
+	{ [a, b, c, d] -> separation_class[[1] -> [0]] :
+		a >= 0 and b >= 0 and b <= 8 - a;
+	  [a, b, c, d] -> separation_class[[0] -> [0]] :
+		a >= 0 and a <= 8 }
+
+With this option, the generated AST is as follows
+
+	{
+	  for (int c0 = 0; c0 <= 8; c0 += 1) {
+	    for (int c1 = 0; c1 <= -c0 + 8; c1 += 1)
+	      for (int c2 = 10 * c0;
+		   c2 <= 10 * c0 + 9; c2 += 1)
+		for (int c3 = 10 * c1;
+		     c3 <= 10 * c1 + 9; c3 += 1)
+		  A(c2, c3);
+	    for (int c1 = -c0 + 9; c1 <= -c0 + 10; c1 += 1)
+	      for (int c2 = 10 * c0;
+		   c2 <= min(-10 * c1 + 100, 10 * c0 + 9);
+		   c2 += 1)
+		for (int c3 = 10 * c1;
+		     c3 <= min(-c2 + 100, 10 * c1 + 9);
+		     c3 += 1)
+		  A(c2, c3);
+	  }
+	  for (int c0 = 9; c0 <= 10; c0 += 1)
+	    for (int c1 = 0; c1 <= -c0 + 10; c1 += 1)
+	      for (int c2 = 10 * c0;
+		   c2 <= min(-10 * c1 + 100, 10 * c0 + 9);
+		   c2 += 1)
+		for (int c3 = 10 * c1;
+		     c3 <= min(10 * c1 + 9, -c2 + 100);
+		     c3 += 1)
+		  A(c2, c3);
+	}
+
+=item C<separate>
+
+This is a single-dimensional space representing the schedule dimension(s)
+to which ``separation'' should be applied.  Separation tries to split
+a loop into several pieces if this can avoid the generation of guards
+inside the loop.
+See also the C<atomic> option.
+
+=item C<atomic>
+
+This is a single-dimensional space representing the schedule dimension(s)
+for which the domains should be considered ``atomic''.  That is, the
+AST generator will make sure that any given domain space will only appear
+in a single loop at the specified level.
+
+Consider the following schedule
+
+	{ a[i] -> [i] : 0 <= i < 10;
+	  b[i] -> [i+1] : 0 <= i < 10 }
+
+If the following option is specified
+
+	{ [i] -> separate[x] }
+
+then the following AST will be generated
+
+	{
+	  a(0);
+	  for (int c0 = 1; c0 <= 9; c0 += 1) {
+	    a(c0);
+	    b(c0 - 1);
+	  }
+	  b(9);
+	}
+
+If, on the other hand, the following option is specified
+
+	{ [i] -> atomic[x] }
+
+then the following AST will be generated
+
+	for (int c0 = 0; c0 <= 10; c0 += 1) {
+	  if (c0 <= 9)
+	    a(c0);
+	  if (c0 >= 1)
+	    b(c0 - 1);
+	}
+
+If neither C<atomic> nor C<separate> is specified, then the AST generator
+may produce either of these two results or some intermediate form.
+
+=item C<unroll>
+
+This is a single-dimensional space representing the schedule dimension(s)
+that should be I<completely> unrolled.
+To obtain a partial unrolling, the user should apply an additional
+strip-mining to the schedule and fully unroll the inner loop.
+
+=back
+
+=head3 Fine-grained Control over AST Generation
+
+Besides specifying the constraints on the parameters,
+an C<isl_ast_build> object can be used to control
+various aspects of the AST generation process.
+In case of AST construction using
+C<isl_ast_build_node_from_schedule_map>,
+the most prominent way of control is through ``options'',
+as explained above.
+
+Additional control is available through the following functions.
+
+	#include <isl/ast_build.h>
+	__isl_give isl_ast_build *
+	isl_ast_build_set_iterators(
+		__isl_take isl_ast_build *control,
+		__isl_take isl_id_list *iterators);
+
+The function C<isl_ast_build_set_iterators> allows the user to
+specify a list of iterator C<isl_id>s to be used as iterators.
+If the input schedule is injective, then
+the number of elements in this list should be as large as the dimension
+of the schedule space, but no direct correspondence should be assumed
+between dimensions and elements.
+If the input schedule is not injective, then an additional number
+of C<isl_id>s equal to the largest dimension of the input domains
+may be required.
+If the number of provided C<isl_id>s is insufficient, then additional
+names are automatically generated.
+
+	#include <isl/ast_build.h>
+	__isl_give isl_ast_build *
+	isl_ast_build_set_create_leaf(
+		__isl_take isl_ast_build *control,
+		__isl_give isl_ast_node *(*fn)(
+			__isl_take isl_ast_build *build,
+			void *user), void *user);
+
+The
+C<isl_ast_build_set_create_leaf> function allows for the
+specification of a callback that should be called whenever the AST
+generator arrives at an element of the schedule domain.
+The callback should return an AST node that should be inserted
+at the corresponding position of the AST.  The default action (when
+the callback is not set) is to continue generating parts of the AST to scan
+all the domain elements associated to the schedule domain element
+and to insert user nodes, ``calling'' the domain element, for each of them.
+The C<build> argument contains the current state of the C<isl_ast_build>.
+To ease nested AST generation (see L</"Nested AST Generation">),
+all control information that is
+specific to the current AST generation such as the options and
+the callbacks has been removed from this C<isl_ast_build>.
+The callback would typically return the result of a nested
+AST generation or a
+user defined node created using the following function.
+
+	#include <isl/ast.h>
+	__isl_give isl_ast_node *isl_ast_node_alloc_user(
+		__isl_take isl_ast_expr *expr);
+
+	#include <isl/ast_build.h>
+	__isl_give isl_ast_build *
+	isl_ast_build_set_at_each_domain(
+		__isl_take isl_ast_build *build,
+		__isl_give isl_ast_node *(*fn)(
+			__isl_take isl_ast_node *node,
+			__isl_keep isl_ast_build *build,
+			void *user), void *user);
+	__isl_give isl_ast_build *
+	isl_ast_build_set_before_each_for(
+		__isl_take isl_ast_build *build,
+		__isl_give isl_id *(*fn)(
+			__isl_keep isl_ast_build *build,
+			void *user), void *user);
+	__isl_give isl_ast_build *
+	isl_ast_build_set_after_each_for(
+		__isl_take isl_ast_build *build,
+		__isl_give isl_ast_node *(*fn)(
+			__isl_take isl_ast_node *node,
+			__isl_keep isl_ast_build *build,
+			void *user), void *user);
+	__isl_give isl_ast_build *
+	isl_ast_build_set_before_each_mark(
+		__isl_take isl_ast_build *build,
+		isl_stat (*fn)(__isl_keep isl_id *mark,
+			__isl_keep isl_ast_build *build,
+			void *user), void *user);
+	__isl_give isl_ast_build *
+	isl_ast_build_set_after_each_mark(
+		__isl_take isl_ast_build *build,
+		__isl_give isl_ast_node *(*fn)(
+			__isl_take isl_ast_node *node,
+			__isl_keep isl_ast_build *build,
+			void *user), void *user);
+
+The callback set by C<isl_ast_build_set_at_each_domain> will
+be called for each domain AST node.
+The callbacks set by C<isl_ast_build_set_before_each_for>
+and C<isl_ast_build_set_after_each_for> will be called
+for each for AST node.  The first will be called in depth-first
+pre-order, while the second will be called in depth-first post-order.
+Since C<isl_ast_build_set_before_each_for> is called before the for
+node is actually constructed, it is only passed an C<isl_ast_build>.
+The returned C<isl_id> will be added as an annotation (using
+C<isl_ast_node_set_annotation>) to the constructed for node.
+In particular, if the user has also specified an C<after_each_for>
+callback, then the annotation can be retrieved from the node passed to
+that callback using C<isl_ast_node_get_annotation>.
+The callbacks set by C<isl_ast_build_set_before_each_mark>
+and C<isl_ast_build_set_after_each_mark> will be called for each
+mark AST node that is created, i.e., for each mark schedule node
+in the input schedule tree.  The first will be called in depth-first
+pre-order, while the second will be called in depth-first post-order.
+Since the callback set by C<isl_ast_build_set_before_each_mark>
+is called before the mark AST node is actually constructed, it is passed
+the identifier of the mark node.
+All callbacks should C<NULL> (or -1) on failure.
+The given C<isl_ast_build> can be used to create new
+C<isl_ast_expr> objects using C<isl_ast_build_expr_from_pw_aff>
+or C<isl_ast_build_call_from_pw_multi_aff>.
+
+=head3 Nested AST Generation
+
+C<isl> allows the user to create an AST within the context
+of another AST.  These nested ASTs are created using the
+same C<isl_ast_build_node_from_schedule_map> function that is used to create
+the outer AST.  The C<build> argument should be an C<isl_ast_build>
+passed to a callback set by
+C<isl_ast_build_set_create_leaf>.
+The space of the range of the C<schedule> argument should refer
+to this build.  In particular, the space should be a wrapped
+relation and the domain of this wrapped relation should be the
+same as that of the range of the schedule returned by
+C<isl_ast_build_get_schedule> below.
+In practice, the new schedule is typically
+created by calling C<isl_union_map_range_product> on the old schedule
+and some extra piece of the schedule.
+The space of the schedule domain is also available from
+the C<isl_ast_build>.
+
+	#include <isl/ast_build.h>
+	__isl_give isl_union_map *isl_ast_build_get_schedule(
+		__isl_keep isl_ast_build *build);
+	__isl_give isl_space *isl_ast_build_get_schedule_space(
+		__isl_keep isl_ast_build *build);
+	__isl_give isl_ast_build *isl_ast_build_restrict(
+		__isl_take isl_ast_build *build,
+		__isl_take isl_set *set);
+
+The C<isl_ast_build_get_schedule> function returns a (partial)
+schedule for the domains elements for which part of the AST still needs to
+be generated in the current build.
+In particular, the domain elements are mapped to those iterations of the loops
+enclosing the current point of the AST generation inside which
+the domain elements are executed.
+No direct correspondence between
+the input schedule and this schedule should be assumed.
+The space obtained from C<isl_ast_build_get_schedule_space> can be used
+to create a set for C<isl_ast_build_restrict> to intersect
+with the current build.  In particular, the set passed to
+C<isl_ast_build_restrict> can have additional parameters.
+The ids of the set dimensions in the space returned by
+C<isl_ast_build_get_schedule_space> correspond to the
+iterators of the already generated loops.
+The user should not rely on the ids of the output dimensions
+of the relations in the union relation returned by
+C<isl_ast_build_get_schedule> having any particular value.
+
+=head1 Applications
+
+Although C<isl> is mainly meant to be used as a library,
+it also contains some basic applications that use some
+of the functionality of C<isl>.
+For applications that take one or more polytopes or polyhedra
+as input, this input may be specified in either the L<isl format>
+or the L<PolyLib format>.
+
+=head2 C<isl_polyhedron_sample>
+
+C<isl_polyhedron_sample> takes a polyhedron as input and prints
+an integer element of the polyhedron, if there is any.
+The first column in the output is the denominator and is always
+equal to 1.  If the polyhedron contains no integer points,
+then a vector of length zero is printed.
+
+=head2 C<isl_pip>
+
+C<isl_pip> takes the same input as the C<example> program
+from the C<piplib> distribution, i.e., a set of constraints
+on the parameters, a line containing only -1 and finally a set
+of constraints on a parametric polyhedron.
+The coefficients of the parameters appear in the last columns
+(but before the final constant column).
+The output is the lexicographic minimum of the parametric polyhedron.
+As C<isl> currently does not have its own output format, the output
+is just a dump of the internal state.
+
+=head2 C<isl_polyhedron_minimize>
+
+C<isl_polyhedron_minimize> computes the minimum of some linear
+or affine objective function over the integer points in a polyhedron.
+If an affine objective function
+is given, then the constant should appear in the last column.
+
+=head2 C<isl_polytope_scan>
+
+Given a polytope, C<isl_polytope_scan> prints
+all integer points in the polytope.
+
+=head2 C<isl_flow>
+
+Given an C<isl_union_access_info> object as input,
+C<isl_flow> prints out the corresponding dependences,
+as computed by C<isl_union_access_info_compute_flow>.
+
+=head2 C<isl_codegen>
+
+Given either a schedule tree or a sequence consisting of
+a schedule map, a context set and an options relation,
+C<isl_codegen> prints out an AST that scans the domain elements
+of the schedule in the order of their image(s) taking into account
+the constraints in the context set.
+
+=head2 C<isl_schedule>
+
+Given an C<isl_schedule_constraints> object as input,
+C<isl_schedule> prints out a schedule that satisfies the given
+constraints.
diff --git a/final/lib/External/isl/extract_key.c b/final/lib/External/isl/extract_key.c
new file mode 100644
index 0000000..070c1f6
--- /dev/null
+++ b/final/lib/External/isl/extract_key.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2013      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <string.h>
+
+/* Extract a mapping key from the token "tok".
+ * Return KEY_ERROR on error, i.e., if "tok" does not
+ * correspond to any known key.
+ */
+static KEY extract_key(__isl_keep isl_stream *s, struct isl_token *tok)
+{
+	int type;
+	char *name;
+	KEY key;
+	isl_ctx *ctx;
+
+	if (!tok)
+		return KEY_ERROR;
+	type = isl_token_get_type(tok);
+	if (type != ISL_TOKEN_IDENT && type != ISL_TOKEN_STRING) {
+		isl_stream_error(s, tok, "expecting key");
+		return KEY_ERROR;
+	}
+
+	ctx = isl_stream_get_ctx(s);
+	name = isl_token_get_str(ctx, tok);
+	if (!name)
+		return KEY_ERROR;
+
+	for (key = 0; key < KEY_END; ++key) {
+		if (!strcmp(name, key_str[key]))
+			break;
+	}
+	free(name);
+
+	if (key >= KEY_END)
+		isl_die(ctx, isl_error_invalid, "unknown key",
+			return KEY_ERROR);
+	return key;
+}
+
+/* Read a key from "s" and return the corresponding enum.
+ * Return KEY_ERROR on error, i.e., if the first token
+ * on the stream does not correspond to any known key.
+ */
+static KEY get_key(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+	KEY key;
+
+	tok = isl_stream_next_token(s);
+	key = extract_key(s, tok);
+	isl_token_free(tok);
+
+	return key;
+}
diff --git a/final/lib/External/isl/flow.c b/final/lib/External/isl/flow.c
new file mode 100644
index 0000000..9472c5b
--- /dev/null
+++ b/final/lib/External/isl/flow.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege.
+ */
+
+/* This program takes an isl_union_access_info object as input and
+ * prints the corresponding dependences.
+ */
+
+#include <isl/options.h>
+#include <isl/printer.h>
+#include <isl/union_map.h>
+#include <isl/flow.h>
+#include <isl/schedule.h>
+
+int main(int argc, char **argv)
+{
+	isl_ctx *ctx;
+	isl_printer *p;
+	isl_union_access_info *access;
+	isl_union_flow *flow;
+	struct isl_options *options;
+
+	options = isl_options_new_with_defaults();
+	argc = isl_options_parse(options, argc, argv, ISL_ARG_ALL);
+	ctx = isl_ctx_alloc_with_options(&isl_options_args, options);
+
+	access = isl_union_access_info_read_from_file(ctx, stdin);
+	flow = isl_union_access_info_compute_flow(access);
+
+	p = isl_printer_to_file(ctx, stdout);
+	p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_BLOCK);
+	p = isl_printer_print_union_flow(p, flow);
+	isl_printer_free(p);
+
+	isl_union_flow_free(flow);
+
+	isl_ctx_free(ctx);
+
+	return 0;
+}
diff --git a/final/lib/External/isl/flow_cmp.c b/final/lib/External/isl/flow_cmp.c
new file mode 100644
index 0000000..ca7e377
--- /dev/null
+++ b/final/lib/External/isl/flow_cmp.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2017      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege.
+ */
+
+#include <stdlib.h>
+
+#include <isl/arg.h>
+#include <isl/options.h>
+#include <isl/union_map.h>
+#include <isl/stream.h>
+
+struct options {
+	struct isl_options *isl;
+	char *flow1;
+	char *flow2;
+};
+
+ISL_ARGS_START(struct options, options_args)
+ISL_ARG_CHILD(struct options, isl, "isl", &isl_options_args, "isl options")
+ISL_ARG_ARG(struct options, flow1, "flow1", NULL)
+ISL_ARG_ARG(struct options, flow2, "flow2", NULL)
+ISL_ARGS_END
+
+ISL_ARG_DEF(options, struct options, options_args)
+
+static void die(const char *msg)
+{
+	fprintf(stderr, "%s\n", msg);
+	exit(EXIT_FAILURE);
+}
+
+static FILE *open_or_die(const char *filename)
+{
+	FILE *file;
+
+	file = fopen(filename, "r");
+	if (!file) {
+		fprintf(stderr, "Unable to open %s\n", filename);
+		exit(EXIT_FAILURE);
+	}
+	return file;
+}
+
+#undef BASE
+#define BASE union_map
+#include "read_in_string_templ.c"
+
+/* Given two YAML descriptions of isl_union_flow objects, check whether
+ * they are equivalent.
+ * Return EXIT_SUCCESS if they are and EXIT_FAILURE if they are not
+ * or if anything else went wrong.
+ *
+ * The descriptions are checked field by field, meaning that the fields
+ * are expected to appear in the same order in both inputs.
+ */
+int main(int argc, char **argv)
+{
+	int more;
+	isl_ctx *ctx;
+	struct options *options;
+	FILE *input1, *input2;
+	isl_stream *s1, *s2;
+
+	options = options_new_with_defaults();
+	if (!options)
+		return EXIT_FAILURE;
+
+	ctx = isl_ctx_alloc_with_options(&options_args, options);
+	argc = options_parse(options, argc, argv, ISL_ARG_ALL);
+
+	input1 = open_or_die(options->flow1);
+	input2 = open_or_die(options->flow2);
+	s1 = isl_stream_new_file(ctx, input1);
+	s2 = isl_stream_new_file(ctx, input2);
+
+	if (isl_stream_yaml_read_start_mapping(s1))
+		isl_die(ctx, isl_error_unknown, "arg1 not a YAML mapping",
+			return EXIT_FAILURE);
+	if (isl_stream_yaml_read_start_mapping(s2))
+		isl_die(ctx, isl_error_unknown, "arg2 not a YAML mapping",
+			return EXIT_FAILURE);
+
+	while ((more = isl_stream_yaml_next(s1)) > 0) {
+		int more2;
+		isl_bool equal;
+		isl_union_map *umap1, *umap2;
+
+		more2 = isl_stream_yaml_next(s2);
+		if (more2 < 0)
+			return EXIT_FAILURE;
+		if (!more2)
+			isl_die(ctx, isl_error_unknown, "arg2 shorter",
+				return EXIT_FAILURE);
+		if (isl_stream_eat(s1, ISL_TOKEN_IDENT) < 0)
+			return EXIT_FAILURE;
+		if (isl_stream_eat(s2, ISL_TOKEN_IDENT) < 0)
+			return EXIT_FAILURE;
+		more = isl_stream_yaml_next(s1);
+		more2 = isl_stream_yaml_next(s2);
+		if (more < 0 || more2 < 0)
+			return EXIT_FAILURE;
+		if (!more || !more2)
+			isl_die(ctx, isl_error_unknown, "missing value",
+				return EXIT_FAILURE);
+
+		umap1 = read_union_map(s1);
+		umap2 = read_union_map(s2);
+		equal = isl_union_map_is_equal(umap1, umap2);
+		isl_union_map_free(umap1);
+		isl_union_map_free(umap2);
+		if (equal < 0)
+			return EXIT_FAILURE;
+		if (!equal)
+			die("field not equal");
+	}
+	if (more < 0)
+		return EXIT_FAILURE;
+
+
+	if (isl_stream_yaml_read_end_mapping(s1) < 0) {
+		isl_stream_error(s1, NULL, "unexpected extra elements");
+		return EXIT_FAILURE;
+	}
+	if (isl_stream_yaml_read_end_mapping(s2) < 0) {
+		isl_stream_error(s2, NULL, "unexpected extra elements");
+		return EXIT_FAILURE;
+	}
+
+	isl_stream_free(s1);
+	isl_stream_free(s2);
+	fclose(input1);
+	fclose(input2);
+	isl_ctx_free(ctx);
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/isl/flow_test.sh.in b/final/lib/External/isl/flow_test.sh.in
new file mode 100644
index 0000000..fa9177c
--- /dev/null
+++ b/final/lib/External/isl/flow_test.sh.in
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+EXEEXT=@EXEEXT@
+srcdir=@srcdir@
+
+failed=0
+
+for i in $srcdir/test_inputs/flow/*.ai; do
+	echo $i;
+	base=`basename $i .ai`
+	test=test-$base.flow
+	dir=`dirname $i`
+	ref=$dir/$base.flow
+	(./isl_flow$EXEEXT < $i > $test &&
+	./isl_flow_cmp$EXEEXT $ref $test && rm $test) || failed=1
+done
+
+test $failed -eq 0 || exit
diff --git a/final/lib/External/isl/imath/gmp_compat.c b/final/lib/External/isl/imath/gmp_compat.c
new file mode 100644
index 0000000..fb45547
--- /dev/null
+++ b/final/lib/External/isl/imath/gmp_compat.c
@@ -0,0 +1,857 @@
+/*
+  Name:     gmp_compat.c
+  Purpose:  Provide GMP compatiable routines for imath library
+  Author:   David Peixotto
+
+  Copyright (c) 2012 Qualcomm Innovation Center, Inc. All rights reserved.
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+ */
+#include "gmp_compat.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+
+#if defined(_MSC_VER)
+#include <BaseTsd.h>
+typedef SSIZE_T ssize_t;
+#endif
+
+#ifdef  NDEBUG
+#define CHECK(res) (res)
+#else
+#define CHECK(res) assert(((res) == MP_OK) && "expected MP_OK")
+#endif
+
+/* *(signed char *)&endian_test will thus either be:
+ *     0b00000001 =  1 on big-endian
+ *     0b11111111 = -1 on little-endian */
+static const uint16_t endian_test = 0x1FF;
+#define HOST_ENDIAN (*(signed char *)&endian_test)
+
+/*************************************************************************
+ *
+ * Functions with direct translations
+ *
+ *************************************************************************/
+/* gmp: mpq_clear */
+void GMPQAPI(clear)(mp_rat x) {
+  mp_rat_clear(x);
+}
+
+/* gmp: mpq_cmp */
+int GMPQAPI(cmp)(mp_rat op1, mp_rat op2) {
+  return mp_rat_compare(op1, op2);
+}
+
+/* gmp: mpq_init */
+void GMPQAPI(init)(mp_rat x) {
+  CHECK(mp_rat_init(x));
+}
+
+/* gmp: mpq_mul */
+void GMPQAPI(mul)(mp_rat product, mp_rat multiplier, mp_rat multiplicand) {
+  CHECK(mp_rat_mul(multiplier, multiplicand, product));
+}
+
+/* gmp: mpq_set*/
+void GMPQAPI(set)(mp_rat rop, mp_rat op) {
+  CHECK(mp_rat_copy(op, rop));
+}
+
+/* gmp: mpz_abs */
+void GMPZAPI(abs)(mp_int rop, mp_int op) {
+  CHECK(mp_int_abs(op, rop));
+}
+
+/* gmp: mpz_add */
+void GMPZAPI(add)(mp_int rop, mp_int op1, mp_int op2) {
+  CHECK(mp_int_add(op1, op2, rop));
+}
+
+/* gmp: mpz_clear */
+void GMPZAPI(clear)(mp_int x) {
+  mp_int_clear(x);
+}
+
+/* gmp: mpz_cmp_si */
+int GMPZAPI(cmp_si)(mp_int op1, long op2) {
+  return mp_int_compare_value(op1, op2);
+}
+
+/* gmp: mpz_cmpabs */
+int GMPZAPI(cmpabs)(mp_int op1, mp_int op2) {
+  return mp_int_compare_unsigned(op1, op2);
+}
+
+/* gmp: mpz_cmp */
+int GMPZAPI(cmp)(mp_int op1, mp_int op2) {
+  return mp_int_compare(op1, op2);
+}
+
+/* gmp: mpz_init */
+void GMPZAPI(init)(mp_int x) {
+  CHECK(mp_int_init(x));
+}
+
+/* gmp: mpz_mul */
+void GMPZAPI(mul)(mp_int rop, mp_int op1, mp_int op2) {
+  CHECK(mp_int_mul(op1, op2, rop));
+}
+
+/* gmp: mpz_neg */
+void GMPZAPI(neg)(mp_int rop, mp_int op) {
+  CHECK(mp_int_neg(op, rop));
+}
+
+/* gmp: mpz_set_si */
+void GMPZAPI(set_si)(mp_int rop, long op) {
+  CHECK(mp_int_set_value(rop, op));
+}
+
+/* gmp: mpz_set */
+void GMPZAPI(set)(mp_int rop, mp_int op) {
+  CHECK(mp_int_copy(op, rop));
+}
+
+/* gmp: mpz_sub */
+void GMPZAPI(sub)(mp_int rop, mp_int op1, mp_int op2) {
+  CHECK(mp_int_sub(op1, op2, rop));
+}
+
+/* gmp: mpz_swap */
+void GMPZAPI(swap)(mp_int rop1, mp_int rop2) {
+  mp_int_swap(rop1, rop2);
+}
+
+/* gmp: mpq_sgn */
+int GMPQAPI(sgn)(mp_rat op) {
+  return mp_rat_compare_zero(op);
+}
+
+/* gmp: mpz_sgn */
+int GMPZAPI(sgn)(mp_int op) {
+  return mp_int_compare_zero(op);
+}
+
+/* gmp: mpq_set_ui */
+void GMPQAPI(set_ui)(mp_rat rop, unsigned long op1, unsigned long op2) {
+  CHECK(mp_rat_set_uvalue(rop, op1, op2));
+}
+
+/* gmp: mpz_set_ui */
+void GMPZAPI(set_ui)(mp_int rop, unsigned long op) {
+  CHECK(mp_int_set_uvalue(rop, op));
+}
+
+/* gmp: mpq_den_ref */
+mp_int GMPQAPI(denref)(mp_rat op) {
+  return mp_rat_denom_ref(op);
+}
+
+/* gmp: mpq_num_ref */
+mp_int GMPQAPI(numref)(mp_rat op) {
+  return mp_rat_numer_ref(op);
+}
+
+/* gmp: mpq_canonicalize */
+void GMPQAPI(canonicalize)(mp_rat op) {
+  CHECK(mp_rat_reduce(op));
+}
+
+/*************************************************************************
+ *
+ * Functions that can be implemented as a combination of imath functions
+ *
+ *************************************************************************/
+/* gmp: mpz_addmul */
+/* gmp: rop = rop + (op1 * op2) */
+void GMPZAPI(addmul)(mp_int rop, mp_int op1, mp_int op2) {
+  mpz_t tempz;
+  mp_int temp = &tempz;
+  mp_int_init(temp);
+
+  CHECK(mp_int_mul(op1, op2, temp));
+  CHECK(mp_int_add(rop, temp, rop));
+  mp_int_clear(temp);
+}
+
+/* gmp: mpz_divexact */
+/* gmp: only produces correct results when d divides n */
+void GMPZAPI(divexact)(mp_int q, mp_int n, mp_int d) {
+  CHECK(mp_int_div(n, d, q, NULL));
+}
+
+/* gmp: mpz_divisible_p */
+/* gmp: return 1 if d divides n, 0 otherwise */
+/* gmp: 0 is considered to divide only 0 */
+int GMPZAPI(divisible_p)(mp_int n, mp_int d) {
+  /* variables to hold remainder */
+  mpz_t rz;
+  mp_int r = &rz;
+  int r_is_zero;
+
+  /* check for d = 0 */
+  int n_is_zero = mp_int_compare_zero(n) == 0;
+  int d_is_zero = mp_int_compare_zero(d) == 0;
+  if (d_is_zero)
+    return n_is_zero;
+
+  /* return true if remainder is 0 */
+  CHECK(mp_int_init(r));
+  CHECK(mp_int_div(n, d, NULL, r));
+  r_is_zero = mp_int_compare_zero(r) == 0;
+  mp_int_clear(r);
+
+  return r_is_zero;
+}
+
+/* gmp: mpz_submul */
+/* gmp: rop = rop - (op1 * op2) */
+void GMPZAPI(submul)(mp_int rop, mp_int op1, mp_int op2) {
+  mpz_t tempz;
+  mp_int temp = &tempz;
+  mp_int_init(temp);
+
+  CHECK(mp_int_mul(op1, op2, temp));
+  CHECK(mp_int_sub(rop, temp, rop));
+
+  mp_int_clear(temp);
+}
+
+/* gmp: mpz_add_ui */
+void GMPZAPI(add_ui)(mp_int rop, mp_int op1, unsigned long op2) {
+  mpz_t tempz;
+  mp_int temp = &tempz;
+  CHECK(mp_int_init_uvalue(temp, op2));
+
+  CHECK(mp_int_add(op1, temp, rop));
+
+  mp_int_clear(temp);
+}
+
+/* gmp: mpz_divexact_ui */
+/* gmp: only produces correct results when d divides n */
+void GMPZAPI(divexact_ui)(mp_int q, mp_int n, unsigned long d) {
+  mpz_t tempz;
+  mp_int temp = &tempz;
+  CHECK(mp_int_init_uvalue(temp, d));
+
+  CHECK(mp_int_div(n, temp, q, NULL));
+
+  mp_int_clear(temp);
+}
+
+/* gmp: mpz_mul_ui */
+void GMPZAPI(mul_ui)(mp_int rop, mp_int op1, unsigned long op2) {
+  mpz_t tempz;
+  mp_int temp = &tempz;
+  CHECK(mp_int_init_uvalue(temp, op2));
+
+  CHECK(mp_int_mul(op1, temp, rop));
+
+  mp_int_clear(temp);
+}
+
+/* gmp: mpz_pow_ui */
+/* gmp: 0^0 = 1 */
+void GMPZAPI(pow_ui)(mp_int rop, mp_int base, unsigned long exp) {
+  mpz_t tempz;
+  mp_int temp = &tempz;
+
+  /* check for 0^0 */
+  if (exp == 0 && mp_int_compare_zero(base) == 0) {
+    CHECK(mp_int_set_value(rop, 1));
+    return;
+  }
+
+  /* rop = base^exp */
+  CHECK(mp_int_init_uvalue(temp, exp));
+  CHECK(mp_int_expt_full(base, temp, rop));
+  mp_int_clear(temp);
+}
+
+/* gmp: mpz_sub_ui */
+void GMPZAPI(sub_ui)(mp_int rop, mp_int op1, unsigned long op2) {
+  mpz_t tempz;
+  mp_int temp = &tempz;
+  CHECK(mp_int_init_uvalue(temp, op2));
+
+  CHECK(mp_int_sub(op1, temp, rop));
+
+  mp_int_clear(temp);
+}
+
+/*************************************************************************
+ *
+ * Functions with different behavior in corner cases
+ *
+ *************************************************************************/
+
+/* gmp: mpz_gcd */
+void GMPZAPI(gcd)(mp_int rop, mp_int op1, mp_int op2) {
+  int op1_is_zero = mp_int_compare_zero(op1) == 0;
+  int op2_is_zero = mp_int_compare_zero(op2) == 0;
+
+  if (op1_is_zero && op2_is_zero) {
+    mp_int_zero(rop);
+    return;
+  }
+
+  CHECK(mp_int_gcd(op1, op2, rop));
+}
+
+/* gmp: mpz_get_str */
+char* GMPZAPI(get_str)(char *str, int radix, mp_int op) {
+  int i, r, len;
+
+  /* Support negative radix like gmp */
+  r = radix;
+  if (r < 0)
+    r = -r;
+
+  /* Compute the length of the string needed to hold the int */
+  len = mp_int_string_len(op, r);
+  if (str == NULL) {
+    str = malloc(len);
+  }
+
+  /* Convert to string using imath function */
+  CHECK(mp_int_to_string(op, r, str, len));
+
+  /* Change case to match gmp */
+  for (i = 0; i < len - 1; i++)
+    if (radix < 0)
+      str[i] = toupper(str[i]);
+    else
+      str[i] = tolower(str[i]);
+  return str;
+}
+
+/* gmp: mpq_get_str */
+char* GMPQAPI(get_str)(char *str, int radix, mp_rat op) {
+  int i, r, len;
+
+  /* Only print numerator if it is a whole number */
+  if (mp_int_compare_value(mp_rat_denom_ref(op), 1) == 0)
+    return GMPZAPI(get_str)(str, radix, mp_rat_numer_ref(op));
+
+  /* Support negative radix like gmp */
+  r = radix;
+  if (r < 0)
+    r = -r;
+
+  /* Compute the length of the string needed to hold the int */
+  len = mp_rat_string_len(op, r);
+  if (str == NULL) {
+    str = malloc(len);
+  }
+
+  /* Convert to string using imath function */
+  CHECK(mp_rat_to_string(op, r, str, len));
+
+  /* Change case to match gmp */
+  for (i = 0; i < len; i++)
+    if (radix < 0)
+      str[i] = toupper(str[i]);
+    else
+      str[i] = tolower(str[i]);
+
+  return str;
+}
+
+/* gmp: mpz_set_str */
+int GMPZAPI(set_str)(mp_int rop, char *str, int base) {
+  mp_result res = mp_int_read_string(rop, base, str);
+  return ((res == MP_OK) ? 0 : -1);
+}
+
+/* gmp: mpq_set_str */
+int GMPQAPI(set_str)(mp_rat rop, char *s, int base) {
+  char *slash;
+  char *str;
+  mp_result resN;
+  mp_result resD;
+  int res = 0;
+
+  /* Copy string to temporary storage so we can modify it below */
+  str = malloc(strlen(s)+1);
+  strcpy(str, s);
+
+  /* Properly format the string as an int by terminating at the / */
+  slash = strchr(str, '/');
+  if (slash)
+    *slash = '\0';
+
+  /* Parse numerator */
+  resN = mp_int_read_string(mp_rat_numer_ref(rop), base, str);
+
+  /* Parse denomenator if given or set to 1 if not */
+  if (slash)
+    resD = mp_int_read_string(mp_rat_denom_ref(rop), base, slash+1);
+  else
+    resD = mp_int_set_uvalue(mp_rat_denom_ref(rop), 1);
+
+  /* Return failure if either parse failed */
+  if (resN != MP_OK || resD != MP_OK)
+    res = -1;
+
+  free(str);
+  return res;
+}
+
+static unsigned long get_long_bits(mp_int op) {
+  /* Deal with integer that does not fit into unsigned long. We want to grab
+   * the least significant digits that will fit into the long.  Read the digits
+   * into the long starting at the most significant digit that fits into a
+   * long. The long is shifted over by MP_DIGIT_BIT before each digit is added.
+   * The shift is decomposed into two steps to follow the patten used in the
+   * rest of the imath library. The two step shift is used to accomedate
+   * architectures that don't deal well with 32-bit shifts. */
+  mp_size num_digits_in_long = sizeof(unsigned long) / sizeof(mp_digit);
+  mp_digit *digits = MP_DIGITS(op);
+  unsigned long out = 0;
+  int i;
+
+  for (i = num_digits_in_long - 1; i >= 0; i--) {
+    out <<= (MP_DIGIT_BIT/2);
+    out <<= (MP_DIGIT_BIT/2);
+    out  |= digits[i];
+  }
+
+  return out;
+}
+
+/* gmp: mpz_get_ui */
+unsigned long GMPZAPI(get_ui)(mp_int op) {
+  unsigned long out;
+
+  /* Try a standard conversion that fits into an unsigned long */
+  mp_result res = mp_int_to_uint(op, &out);
+  if (res == MP_OK)
+    return out;
+
+  /* Abort the try if we don't have a range error in the conversion.
+   * The range error indicates that the value cannot fit into a long. */
+  CHECK(res == MP_RANGE ? MP_OK : MP_RANGE);
+  if (res != MP_RANGE)
+    return 0;
+
+  return get_long_bits(op);
+}
+
+/* gmp: mpz_get_si */
+long GMPZAPI(get_si)(mp_int op) {
+  long out;
+  unsigned long uout;
+  int long_msb;
+
+  /* Try a standard conversion that fits into a long */
+  mp_result res = mp_int_to_int(op, &out);
+  if (res == MP_OK)
+    return out;
+
+  /* Abort the try if we don't have a range error in the conversion.
+   * The range error indicates that the value cannot fit into a long. */
+  CHECK(res == MP_RANGE ? MP_OK : MP_RANGE);
+  if (res != MP_RANGE)
+    return 0;
+
+  /* get least significant bits into an unsigned long */
+  uout = get_long_bits(op);
+
+  /* clear the top bit */
+  long_msb = (sizeof(unsigned long) * 8) - 1;
+  uout &= (~(1UL << long_msb));
+
+  /* convert to negative if needed based on sign of op */
+  if (MP_SIGN(op) == MP_NEG)
+    uout = 0 - uout;
+
+  out = (long) uout;
+  return out;
+}
+
+/* gmp: mpz_lcm */
+void GMPZAPI(lcm)(mp_int rop, mp_int op1, mp_int op2) {
+  int op1_is_zero = mp_int_compare_zero(op1) == 0;
+  int op2_is_zero = mp_int_compare_zero(op2) == 0;
+
+  if (op1_is_zero || op2_is_zero) {
+    mp_int_zero(rop);
+    return;
+  }
+
+  CHECK(mp_int_lcm(op1, op2, rop));
+  CHECK(mp_int_abs(rop, rop));
+}
+
+/* gmp: mpz_mul_2exp */
+/* gmp: allow big values for op2 when op1 == 0 */
+void GMPZAPI(mul_2exp)(mp_int rop, mp_int op1, unsigned long op2) {
+  if (mp_int_compare_zero(op1) == 0)
+    mp_int_zero(rop);
+  else
+    CHECK(mp_int_mul_pow2(op1, op2, rop));
+}
+
+/*************************************************************************
+ *
+ * Functions needing expanded functionality
+ *
+ *************************************************************************/
+/* [Note]Overview of division implementation
+
+    All division operations (N / D) compute q and r such that
+
+      N = q * D + r, with 0 <= abs(r) < abs(d)
+
+    The q and r values are not uniquely specified by N and D. To specify which q
+    and r values should be used, GMP implements three different rounding modes
+    for integer division:
+
+      ceiling  - round q twords +infinity, r has opposite sign as d
+      floor    - round q twords -infinity, r has same sign as d
+      truncate - round q twords zero,      r has same sign as n
+
+    The imath library only supports truncate as a rounding mode. We need to
+    implement the other rounding modes in terms of truncating division. We first
+    perform the division in trucate mode and then adjust q accordingly. Once we
+    know q, we can easily compute the correct r according the the formula above
+    by computing:
+
+      r = N - q * D
+
+    The main task is to compute q. We can compute the correct q from a trucated
+    version as follows.
+
+    For ceiling rounding mode, if q is less than 0 then the truncated rounding
+    mode is the same as the ceiling rounding mode.  If q is greater than zero
+    then we need to round q up by one because the truncated version was rounded
+    down to zero. If q equals zero then check to see if the result of the
+    divison is positive. A positive result needs to increment q to one.
+
+    For floor rounding mode, if q is greater than 0 then the trucated rounding
+    mode is the same as the floor rounding mode. If q is less than zero then we
+    need to round q down by one because the trucated mode rounded q up by one
+    twords zero. If q is zero then we need to check to see if the result of the
+    division is negative. A negative result needs to decrement q to negative
+    one.
+ */
+
+/* gmp: mpz_cdiv_q */
+void GMPZAPI(cdiv_q)(mp_int q, mp_int n, mp_int d) {
+  mpz_t rz;
+  mp_int r = &rz;
+  int qsign, rsign, nsign, dsign;
+  CHECK(mp_int_init(r));
+
+  /* save signs before division because q can alias with n or d */
+  nsign = mp_int_compare_zero(n);
+  dsign = mp_int_compare_zero(d);
+
+  /* truncating division */
+  CHECK(mp_int_div(n, d, q, r));
+
+  /* see: [Note]Overview of division implementation */
+  qsign = mp_int_compare_zero(q);
+  rsign = mp_int_compare_zero(r);
+  if (qsign > 0) {    /* q > 0 */
+    if (rsign != 0) { /* r != 0 */
+      CHECK(mp_int_add_value(q, 1, q));
+    }
+  }
+  else if (qsign == 0) { /* q == 0 */
+    if (rsign != 0) {    /* r != 0 */
+      if ((nsign > 0 && dsign > 0) || (nsign < 0 && dsign < 0)) {
+        CHECK(mp_int_set_value(q, 1));
+      }
+    }
+  }
+  mp_int_clear(r);
+}
+
+/* gmp: mpz_fdiv_q */
+void GMPZAPI(fdiv_q)(mp_int q, mp_int n, mp_int d) {
+  mpz_t rz;
+  mp_int r = &rz;
+  int qsign, rsign, nsign, dsign;
+  CHECK(mp_int_init(r));
+
+  /* save signs before division because q can alias with n or d */
+  nsign = mp_int_compare_zero(n);
+  dsign = mp_int_compare_zero(d);
+
+  /* truncating division */
+  CHECK(mp_int_div(n, d, q, r));
+
+  /* see: [Note]Overview of division implementation */
+  qsign = mp_int_compare_zero(q);
+  rsign = mp_int_compare_zero(r);
+  if (qsign < 0) {    /* q  < 0 */
+    if (rsign != 0) { /* r != 0 */
+      CHECK(mp_int_sub_value(q, 1, q));
+    }
+  }
+  else if (qsign == 0) { /* q == 0 */
+    if (rsign != 0) {    /* r != 0 */
+      if ((nsign < 0 && dsign > 0) || (nsign > 0 && dsign < 0)) {
+        CHECK(mp_int_set_value(q, -1));
+      }
+    }
+  }
+  mp_int_clear(r);
+}
+
+/* gmp: mpz_fdiv_r */
+void GMPZAPI(fdiv_r)(mp_int r, mp_int n, mp_int d) {
+  mpz_t qz;
+  mpz_t tempz;
+  mpz_t orig_dz;
+  mpz_t orig_nz;
+  mp_int q = &qz;
+  mp_int temp = &tempz;
+  mp_int orig_d = &orig_dz;
+  mp_int orig_n = &orig_nz;
+  CHECK(mp_int_init(q));
+  CHECK(mp_int_init(temp));
+  /* Make a copy of n in case n and d in case they overlap with q */
+  CHECK(mp_int_init_copy(orig_d, d));
+  CHECK(mp_int_init_copy(orig_n, n));
+
+  /* floor division */
+  GMPZAPI(fdiv_q)(q, n, d);
+
+  /* see: [Note]Overview of division implementation */
+  /* n = q * d + r  ==>  r = n - q * d */
+  mp_int_mul(q, orig_d, temp);
+  mp_int_sub(orig_n, temp, r);
+
+  mp_int_clear(q);
+  mp_int_clear(temp);
+  mp_int_clear(orig_d);
+  mp_int_clear(orig_n);
+}
+
+/* gmp: mpz_tdiv_q */
+void GMPZAPI(tdiv_q)(mp_int q, mp_int n, mp_int d) {
+  /* truncating division*/
+  CHECK(mp_int_div(n, d, q, NULL));
+}
+
+/* gmp: mpz_fdiv_q_ui */
+unsigned long GMPZAPI(fdiv_q_ui)(mp_int q, mp_int n, unsigned long d) {
+  mpz_t tempz;
+  mp_int temp = &tempz;
+  mpz_t rz;
+  mp_int r = &rz;
+  mpz_t orig_nz;
+  mp_int orig_n = &orig_nz;
+  unsigned long rl;
+  CHECK(mp_int_init_uvalue(temp, d));
+  CHECK(mp_int_init(r));
+  /* Make a copy of n in case n and q overlap */
+  CHECK(mp_int_init_copy(orig_n, n));
+
+  /* use floor division mode to compute q and r */
+  GMPZAPI(fdiv_q)(q, n, temp);
+  GMPZAPI(fdiv_r)(r, orig_n, temp);
+  CHECK(mp_int_to_uint(r, &rl));
+
+  mp_int_clear(temp);
+  mp_int_clear(r);
+  mp_int_clear(orig_n);
+
+  return rl;
+}
+
+/* gmp: mpz_export */
+void* GMPZAPI(export)(void *rop, size_t *countp, int order, size_t size, int endian, size_t nails, mp_int op) {
+  int i, j;
+  int num_used_bytes;
+  size_t num_words, num_missing_bytes;
+  ssize_t word_offset;
+  unsigned char* dst;
+  mp_digit* src;
+  int src_bits;
+
+  /* We do not have a complete implementation. Assert to ensure our
+   * restrictions are in place. */
+  assert(nails  == 0 && "Do not support non-full words");
+  assert(endian == 1 || endian == 0 || endian == -1);
+  assert(order == 1 || order == -1);
+
+  /* Test for zero */
+  if (mp_int_compare_zero(op) == 0) {
+    if (countp)
+      *countp = 0;
+    return rop;
+  }
+
+  /* Calculate how many words we need */
+  num_used_bytes  = mp_int_unsigned_len(op);
+  num_words       = (num_used_bytes + (size-1)) / size; /* ceil division */
+  assert(num_used_bytes > 0);
+
+  /* Check to see if we will have missing bytes in the last word.
+
+     Missing bytes can only occur when the size of words we output is
+     greater than the size of words used internally by imath. The number of
+     missing bytes is the number of bytes needed to fill out the last word. If
+     this number is greater than the size of a single mp_digit, then we need to
+     pad the word with extra zeros. Otherwise, the missing bytes can be filled
+     directly from the zeros in the last digit in the number.
+   */
+  num_missing_bytes   = (size * num_words) - num_used_bytes;
+  assert(num_missing_bytes < size);
+
+  /* Allocate space for the result if needed */
+  if (rop == NULL) {
+    rop = malloc(num_words * size);
+  }
+
+  if (endian == 0) {
+    endian = HOST_ENDIAN;
+  }
+
+  /* Initialize dst and src pointers */
+  dst = (unsigned char *) rop + (order >= 0 ? (num_words-1) * size : 0) + (endian >= 0 ? size-1 : 0);
+  src = MP_DIGITS(op);
+  src_bits = MP_DIGIT_BIT;
+
+  word_offset = (endian >= 0 ? size : -size) + (order < 0 ? size : -size);
+
+  for (i = 0; i < num_words; i++) {
+    for (j = 0; j < size && i * size + j < num_used_bytes; j++) {
+      if (src_bits == 0) {
+        ++src;
+        src_bits = MP_DIGIT_BIT;
+      }
+      *dst = (*src >> (MP_DIGIT_BIT - src_bits)) & 0xFF;
+      src_bits -= 8;
+      dst -= endian;
+    }
+    for (; j < size; j++) {
+      *dst = 0;
+      dst -= endian;
+    }
+    dst += word_offset;
+  }
+
+  if (countp)
+    *countp = num_words;
+  return rop;
+}
+
+/* gmp: mpz_import */
+void GMPZAPI(import)(mp_int rop, size_t count, int order, size_t size, int endian, size_t nails, const void* op) {
+  mpz_t tmpz;
+  mp_int tmp = &tmpz;
+  size_t total_size;
+  size_t num_digits;
+  ssize_t word_offset;
+  const unsigned char *src;
+  mp_digit *dst;
+  int dst_bits;
+  int i, j;
+  if (count == 0 || op == NULL)
+    return;
+
+  /* We do not have a complete implementation. Assert to ensure our
+   * restrictions are in place. */
+  assert(nails  == 0 && "Do not support non-full words");
+  assert(endian == 1 || endian == 0 || endian == -1);
+  assert(order == 1 || order == -1);
+
+  if (endian == 0) {
+    endian = HOST_ENDIAN;
+  }
+
+  /* Compute number of needed digits by ceil division */
+  total_size = count * size;
+  num_digits = (total_size + sizeof(mp_digit) - 1) / sizeof(mp_digit);
+
+  /* Init temporary */
+  mp_int_init_size(tmp, num_digits);
+  for (i = 0; i < num_digits; i++)
+    tmp->digits[i] = 0;
+
+  /* Copy bytes */
+  src = (const unsigned char *) op + (order >= 0 ? (count-1) * size : 0) + (endian >= 0 ? size-1 : 0);
+  dst = MP_DIGITS(tmp);
+  dst_bits = 0;
+
+  word_offset = (endian >= 0 ? size : -size) + (order < 0 ? size : -size);
+
+  for (i = 0; i < count; i++) {
+    for (j = 0; j < size; j++) {
+      if (dst_bits == MP_DIGIT_BIT) {
+        ++dst;
+        dst_bits = 0;
+      }
+      *dst |= ((mp_digit)*src) << dst_bits;
+      dst_bits += 8;
+      src -= endian;
+    }
+    src += word_offset;
+  }
+
+  MP_USED(tmp) = num_digits;
+
+  /* Remove leading zeros from number */
+  {
+    mp_size uz_   = MP_USED(tmp);
+    mp_digit *dz_ = MP_DIGITS(tmp) + uz_ -1;
+    while (uz_ > 1 && (*dz_-- == 0))
+      --uz_;
+    MP_USED(tmp) = uz_;
+  }
+
+  /* Copy to destination */
+  mp_int_copy(tmp, rop);
+  mp_int_clear(tmp);
+}
+
+/* gmp: mpz_sizeinbase */
+size_t GMPZAPI(sizeinbase)(mp_int op, int base) {
+  mp_result res;
+  size_t size;
+
+  /* If op == 0, return 1 */
+  if (mp_int_compare_zero(op) == 0)
+    return 1;
+
+  /* Compute string length in base */
+  res = mp_int_string_len(op, base);
+  CHECK((res > 0) == MP_OK);
+
+  /* Now adjust the final size by getting rid of string artifacts */
+  size = res;
+
+  /* subtract one for the null terminator */
+  size -= 1;
+
+  /* subtract one for the negative sign */
+  if (mp_int_compare_zero(op) < 0)
+    size -= 1;
+
+  return size;
+}
diff --git a/final/lib/External/isl/imath/gmp_compat.h b/final/lib/External/isl/imath/gmp_compat.h
new file mode 100644
index 0000000..949e377
--- /dev/null
+++ b/final/lib/External/isl/imath/gmp_compat.h
@@ -0,0 +1,229 @@
+/*
+  Name:     gmp_compat.h
+  Purpose:  Provide GMP compatiable routines for imath library
+  Author:   David Peixotto
+
+  Copyright (c) 2012 Qualcomm Innovation Center, Inc. All rights reserved.
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+ */
+
+#ifndef IMATH_GMP_COMPAT_H_
+#define IMATH_GMP_COMPAT_H_
+#include "imath.h"
+#include "imrat.h"
+#include <stddef.h>
+
+#define GMPZAPI(fun) impz_ ## fun
+#define GMPQAPI(fun) impq_ ## fun
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*************************************************************************
+ *
+ * Functions with direct translations
+ *
+ *************************************************************************/
+/* gmp: mpq_clear */
+void GMPQAPI(clear)(mp_rat x);
+
+/* gmp: mpq_cmp */
+int GMPQAPI(cmp)(mp_rat op1, mp_rat op2);
+
+/* gmp: mpq_init */
+void GMPQAPI(init)(mp_rat x);
+
+/* gmp: mpq_mul */
+void GMPQAPI(mul)(mp_rat product, mp_rat multiplier, mp_rat multiplicand);
+
+/* gmp: mpq_set */
+void GMPQAPI(set)(mp_rat rop, mp_rat op);
+
+/* gmp: mpz_abs */
+void GMPZAPI(abs)(mp_int rop, mp_int op);
+
+/* gmp: mpz_add */
+void GMPZAPI(add)(mp_int rop, mp_int op1, mp_int op2);
+
+/* gmp: mpz_clear */
+void GMPZAPI(clear)(mp_int x);
+
+/* gmp: mpz_cmp_si */
+int GMPZAPI(cmp_si)(mp_int op1, long op2);
+
+/* gmp: mpz_cmpabs */
+int GMPZAPI(cmpabs)(mp_int op1, mp_int op2);
+
+/* gmp: mpz_cmp */
+int GMPZAPI(cmp)(mp_int op1, mp_int op2);
+
+/* gmp: mpz_init */
+void GMPZAPI(init)(mp_int x);
+
+/* gmp: mpz_mul */
+void GMPZAPI(mul)(mp_int rop, mp_int op1, mp_int op2);
+
+/* gmp: mpz_neg */
+void GMPZAPI(neg)(mp_int rop, mp_int op);
+
+/* gmp: mpz_set_si */
+void GMPZAPI(set_si)(mp_int rop, long op);
+
+/* gmp: mpz_set */
+void GMPZAPI(set)(mp_int rop, mp_int op);
+
+/* gmp: mpz_sub */
+void GMPZAPI(sub)(mp_int rop, mp_int op1, mp_int op2);
+
+/* gmp: mpz_swap */
+void GMPZAPI(swap)(mp_int rop1, mp_int rop2);
+
+/* gmp: mpq_sgn */
+int GMPQAPI(sgn)(mp_rat op);
+
+/* gmp: mpz_sgn */
+int GMPZAPI(sgn)(mp_int op);
+
+/* gmp: mpq_set_ui */
+void GMPQAPI(set_ui)(mp_rat rop, unsigned long op1, unsigned long op2);
+
+/* gmp: mpz_set_ui */
+void GMPZAPI(set_ui)(mp_int rop, unsigned long op);
+
+/* gmp: mpq_den_ref */
+mp_int GMPQAPI(denref)(mp_rat op);
+
+/* gmp: mpq_num_ref */
+mp_int GMPQAPI(numref)(mp_rat op);
+
+/* gmp: mpq_canonicalize */
+void GMPQAPI(canonicalize)(mp_rat op);
+
+/*************************************************************************
+ *
+ * Functions that can be implemented as a combination of imath functions
+ *
+ *************************************************************************/
+/* gmp: mpz_addmul */
+void GMPZAPI(addmul)(mp_int rop, mp_int op1, mp_int op2);
+
+/* gmp: mpz_divexact */
+void GMPZAPI(divexact)(mp_int q, mp_int n, mp_int d);
+
+/* gmp: mpz_divisible_p */
+int GMPZAPI(divisible_p)(mp_int n, mp_int d);
+
+/* gmp: mpz_submul */
+void GMPZAPI(submul)(mp_int rop, mp_int op1, mp_int op2);
+
+/* gmp: mpz_add_ui */
+void GMPZAPI(add_ui)(mp_int rop, mp_int op1, unsigned long op2);
+
+/* gmp: mpz_divexact_ui */
+void GMPZAPI(divexact_ui)(mp_int q, mp_int n, unsigned long d);
+
+/* gmp: mpz_mul_ui */
+void GMPZAPI(mul_ui)(mp_int rop, mp_int op1, unsigned long op2);
+
+/* gmp: mpz_pow_ui */
+void GMPZAPI(pow_ui)(mp_int rop, mp_int base, unsigned long exp);
+
+/* gmp: mpz_sub_ui */
+void GMPZAPI(sub_ui)(mp_int rop, mp_int op1, unsigned long op2);
+
+/* gmp: mpz_fdiv_q_ui */
+unsigned long GMPZAPI(fdiv_q_ui)(mp_int q, mp_int n, unsigned long d);
+
+/* gmp: mpz_sizeinbase */
+size_t GMPZAPI(sizeinbase)(mp_int op, int base);
+
+/*************************************************************************
+ *
+ * Functions with different behavior in corner cases
+ *
+ *************************************************************************/
+/* gmp: mpz_gcd */
+/* gmp: When op1 = 0 and op2 = 0, return 0.*/
+void GMPZAPI(gcd)(mp_int rop, mp_int op1, mp_int op2);
+
+/* gmp: mpz_get_str */
+/* gmp: If str is NULL then allocate space using the default allocator. */
+char* GMPZAPI(get_str)(char *str, int radix, mp_int op);
+
+/* gmp: mpq_get_str */
+/* gmp: If str is NULL then allocate space using the default allocator. */
+/* gmp: If value is a whole number do not print denomenator. */
+/* TODO: Need to handle 0 values better. GMP prints 0/4 instead of 0.*/
+char* GMPQAPI(get_str)(char *str, int radix, mp_rat op);
+
+/* gmp: mpz_set_str */
+/* gmp: Allow and ignore spaces in string. */
+int GMPZAPI(set_str)(mp_int rop, char *str, int base);
+
+/* gmp: mpq_set_str */
+int GMPQAPI(set_str)(mp_rat rop, char *str, int base);
+
+/* gmp: mpz_get_ui */
+/* gmp: Return least significant bits if value is too big for a long. */
+unsigned long GMPZAPI(get_ui)(mp_int op);
+
+/* gmp: mpz_get_si */
+/* gmp: Return least significant bits if value is too bit for a long. */
+/* gmp: If value is too big for long, return the least significant
+        (8*sizeof(long)-1) bits from the op and set the sign bit according to
+        the sign of the op. */
+long GMPZAPI(get_si)(mp_int op);
+
+/* gmp: mpz_lcm */
+/* gmp: When op1 = 0 or op2 = 0, return 0.*/
+/* gmp: The resutl of lcm(a,b) is always positive. */
+void GMPZAPI(lcm)(mp_int rop, mp_int op1, mp_int op2);
+
+/* gmp: mpz_mul_2exp */
+/* gmp: allow big values for op2 when op1 == 0 */
+void GMPZAPI(mul_2exp)(mp_int rop, mp_int op1, unsigned long op2);
+
+/*************************************************************************
+ *
+ * Functions needing expanded functionality
+ *
+ *************************************************************************/
+/* gmp: mpz_cdiv_q */
+void GMPZAPI(cdiv_q)(mp_int q, mp_int n, mp_int d);
+
+/* gmp: mpz_fdiv_q */
+void GMPZAPI(fdiv_q)(mp_int q, mp_int n, mp_int d);
+
+/* gmp: mpz_fdiv_r */
+void GMPZAPI(fdiv_r)(mp_int r, mp_int n, mp_int d);
+
+/* gmp: mpz_tdiv_q */
+void GMPZAPI(tdiv_q)(mp_int q, mp_int n, mp_int d);
+
+/* gmp: mpz_export */
+void* GMPZAPI(export)(void *rop, size_t *countp, int order, size_t size, int endian, size_t nails, mp_int op);
+
+/* gmp: mpz_import */
+void GMPZAPI(import)(mp_int rop, size_t count, int order, size_t size, int endian, size_t nails, const void* op);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* end IMATH_GMP_COMPAT_H_ */
diff --git a/final/lib/External/isl/imath/imath.c b/final/lib/External/isl/imath/imath.c
new file mode 100644
index 0000000..be99305
--- /dev/null
+++ b/final/lib/External/isl/imath/imath.c
@@ -0,0 +1,3156 @@
+/*
+  Name:     imath.c
+  Purpose:  Arbitrary precision integer arithmetic routines.
+  Author:   M. J. Fromberger <http://spinning-yarns.org/michael/>
+
+  Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved.
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+ */
+
+#include "imath.h"
+
+#if DEBUG
+#include <stdio.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <assert.h>
+
+#if DEBUG
+#define STATIC /* public */
+#else
+#define STATIC static
+#endif
+
+const mp_result MP_OK     = 0;  /* no error, all is well  */
+const mp_result MP_FALSE  = 0;  /* boolean false          */
+const mp_result MP_TRUE   = -1; /* boolean true           */
+const mp_result MP_MEMORY = -2; /* out of memory          */
+const mp_result MP_RANGE  = -3; /* argument out of range  */
+const mp_result MP_UNDEF  = -4; /* result undefined       */
+const mp_result MP_TRUNC  = -5; /* output truncated       */
+const mp_result MP_BADARG = -6; /* invalid null argument  */
+const mp_result MP_MINERR = -6;
+
+const mp_sign   MP_NEG  = 1;    /* value is strictly negative */
+const mp_sign   MP_ZPOS = 0;    /* value is non-negative      */
+
+STATIC const char *s_unknown_err = "unknown result code";
+STATIC const char *s_error_msg[] = {
+  "error code 0",
+  "boolean true",
+  "out of memory",
+  "argument out of range",
+  "result undefined",
+  "output truncated",
+  "invalid argument",
+  NULL
+};
+
+/* Argument checking macros
+   Use CHECK() where a return value is required; NRCHECK() elsewhere */
+#define CHECK(TEST)   assert(TEST)
+#define NRCHECK(TEST) assert(TEST)
+
+/* The ith entry of this table gives the value of log_i(2).
+
+   An integer value n requires ceil(log_i(n)) digits to be represented
+   in base i.  Since it is easy to compute lg(n), by counting bits, we
+   can compute log_i(n) = lg(n) * log_i(2).
+
+   The use of this table eliminates a dependency upon linkage against
+   the standard math libraries.
+
+   If MP_MAX_RADIX is increased, this table should be expanded too.
+ */
+STATIC const double s_log2[] = {
+   0.000000000, 0.000000000, 1.000000000, 0.630929754, 	/* (D)(D) 2  3 */
+   0.500000000, 0.430676558, 0.386852807, 0.356207187, 	/*  4  5  6  7 */
+   0.333333333, 0.315464877, 0.301029996, 0.289064826, 	/*  8  9 10 11 */
+   0.278942946, 0.270238154, 0.262649535, 0.255958025, 	/* 12 13 14 15 */
+   0.250000000, 0.244650542, 0.239812467, 0.235408913, 	/* 16 17 18 19 */
+   0.231378213, 0.227670249, 0.224243824, 0.221064729, 	/* 20 21 22 23 */
+   0.218104292, 0.215338279, 0.212746054, 0.210309918, 	/* 24 25 26 27 */
+   0.208014598, 0.205846832, 0.203795047, 0.201849087, 	/* 28 29 30 31 */
+   0.200000000, 0.198239863, 0.196561632, 0.194959022, 	/* 32 33 34 35 */
+   0.193426404,                                         /* 36          */
+};
+
+
+
+/* Return the number of digits needed to represent a static value */
+#define MP_VALUE_DIGITS(V) \
+((sizeof(V)+(sizeof(mp_digit)-1))/sizeof(mp_digit))
+
+/* Round precision P to nearest word boundary */
+#define ROUND_PREC(P) ((mp_size)(2*(((P)+1)/2)))
+
+/* Set array P of S digits to zero */
+#define ZERO(P, S) \
+do{ \
+  mp_size i__ = (S) * sizeof(mp_digit); \
+  mp_digit *p__ = (P); \
+  memset(p__, 0, i__); \
+} while(0)
+
+/* Copy S digits from array P to array Q */
+#define COPY(P, Q, S) \
+do{ \
+  mp_size i__ = (S) * sizeof(mp_digit); \
+  mp_digit *p__ = (P), *q__ = (Q); \
+  memcpy(q__, p__, i__); \
+} while(0)
+
+/* Reverse N elements of type T in array A */
+#define REV(T, A, N) \
+do{ \
+  T *u_ = (A), *v_ = u_ + (N) - 1; \
+  while (u_ < v_) { \
+    T xch = *u_; \
+    *u_++ = *v_; \
+    *v_-- = xch; \
+  } \
+} while(0)
+
+#define CLAMP(Z) \
+do{ \
+  mp_int z_ = (Z); \
+  mp_size uz_ = MP_USED(z_); \
+  mp_digit *dz_ = MP_DIGITS(z_) + uz_ -1; \
+  while (uz_ > 1 && (*dz_-- == 0)) \
+    --uz_; \
+  MP_USED(z_) = uz_; \
+} while(0)
+
+/* Select min/max.  Do not provide expressions for which multiple
+   evaluation would be problematic, e.g. x++ */
+#define MIN(A, B) ((B)<(A)?(B):(A))
+#define MAX(A, B) ((B)>(A)?(B):(A))
+
+/* Exchange lvalues A and B of type T, e.g.
+   SWAP(int, x, y) where x and y are variables of type int. */
+#define SWAP(T, A, B) \
+do{ \
+  T t_ = (A); \
+  A = (B); \
+  B = t_; \
+} while(0)
+
+/* Used to set up and access simple temp stacks within functions. */
+#define DECLARE_TEMP(N) \
+  mpz_t temp[(N)]; \
+  int last__ = 0
+#define CLEANUP_TEMP() \
+ CLEANUP: \
+  while (--last__ >= 0) \
+    mp_int_clear(TEMP(last__))
+#define TEMP(K) (temp + (K))
+#define LAST_TEMP() TEMP(last__)
+#define SETUP(E) \
+do{ \
+  if ((res = (E)) != MP_OK) \
+    goto CLEANUP; \
+  ++(last__); \
+} while(0)
+
+/* Compare value to zero. */
+#define CMPZ(Z) \
+(((Z)->used==1&&(Z)->digits[0]==0)?0:((Z)->sign==MP_NEG)?-1:1)
+
+/* Multiply X by Y into Z, ignoring signs.  Requires that Z have
+   enough storage preallocated to hold the result. */
+#define UMUL(X, Y, Z) \
+do{ \
+  mp_size ua_ = MP_USED(X), ub_ = MP_USED(Y); \
+  mp_size o_ = ua_ + ub_; \
+  ZERO(MP_DIGITS(Z), o_); \
+  (void) s_kmul(MP_DIGITS(X), MP_DIGITS(Y), MP_DIGITS(Z), ua_, ub_); \
+  MP_USED(Z) = o_; \
+  CLAMP(Z); \
+} while(0)
+
+/* Square X into Z.  Requires that Z have enough storage to hold the
+   result. */
+#define USQR(X, Z) \
+do{ \
+  mp_size ua_ = MP_USED(X), o_ = ua_ + ua_; \
+  ZERO(MP_DIGITS(Z), o_); \
+  (void) s_ksqr(MP_DIGITS(X), MP_DIGITS(Z), ua_); \
+  MP_USED(Z) = o_; \
+  CLAMP(Z); \
+} while(0)
+
+#define UPPER_HALF(W)           ((mp_word)((W) >> MP_DIGIT_BIT))
+#define LOWER_HALF(W)           ((mp_digit)(W))
+#define HIGH_BIT_SET(W)         ((W) >> (MP_WORD_BIT - 1))
+#define ADD_WILL_OVERFLOW(W, V) ((MP_WORD_MAX - (V)) < (W))
+
+
+
+/* Default number of digits allocated to a new mp_int */
+#if IMATH_TEST
+mp_size default_precision = MP_DEFAULT_PREC;
+#else
+STATIC const mp_size default_precision = MP_DEFAULT_PREC;
+#endif
+
+/* Minimum number of digits to invoke recursive multiply */
+#if IMATH_TEST
+mp_size multiply_threshold = MP_MULT_THRESH;
+#else
+STATIC const mp_size multiply_threshold = MP_MULT_THRESH;
+#endif
+
+/* Allocate a buffer of (at least) num digits, or return
+   NULL if that couldn't be done.  */
+STATIC mp_digit *s_alloc(mp_size num);
+
+/* Release a buffer of digits allocated by s_alloc(). */
+STATIC void s_free(void *ptr);
+
+/* Insure that z has at least min digits allocated, resizing if
+   necessary.  Returns true if successful, false if out of memory. */
+STATIC int  s_pad(mp_int z, mp_size min);
+
+/* Fill in a "fake" mp_int on the stack with a given value */
+STATIC void      s_fake(mp_int z, mp_small value, mp_digit vbuf[]);
+STATIC void      s_ufake(mp_int z, mp_usmall value, mp_digit vbuf[]);
+
+/* Compare two runs of digits of given length, returns <0, 0, >0 */
+STATIC int       s_cdig(mp_digit *da, mp_digit *db, mp_size len);
+
+/* Pack the unsigned digits of v into array t */
+STATIC int       s_uvpack(mp_usmall v, mp_digit t[]);
+
+/* Compare magnitudes of a and b, returns <0, 0, >0 */
+STATIC int       s_ucmp(mp_int a, mp_int b);
+
+/* Compare magnitudes of a and v, returns <0, 0, >0 */
+STATIC int       s_vcmp(mp_int a, mp_small v);
+STATIC int       s_uvcmp(mp_int a, mp_usmall uv);
+
+/* Unsigned magnitude addition; assumes dc is big enough.
+   Carry out is returned (no memory allocated). */
+STATIC mp_digit  s_uadd(mp_digit *da, mp_digit *db, mp_digit *dc,
+		        mp_size size_a, mp_size size_b);
+
+/* Unsigned magnitude subtraction.  Assumes dc is big enough. */
+STATIC void      s_usub(mp_digit *da, mp_digit *db, mp_digit *dc,
+		        mp_size size_a, mp_size size_b);
+
+/* Unsigned recursive multiplication.  Assumes dc is big enough. */
+STATIC int       s_kmul(mp_digit *da, mp_digit *db, mp_digit *dc,
+			mp_size size_a, mp_size size_b);
+
+/* Unsigned magnitude multiplication.  Assumes dc is big enough. */
+STATIC void      s_umul(mp_digit *da, mp_digit *db, mp_digit *dc,
+			mp_size size_a, mp_size size_b);
+
+/* Unsigned recursive squaring.  Assumes dc is big enough. */
+STATIC int       s_ksqr(mp_digit *da, mp_digit *dc, mp_size size_a);
+
+/* Unsigned magnitude squaring.  Assumes dc is big enough. */
+STATIC void      s_usqr(mp_digit *da, mp_digit *dc, mp_size size_a);
+
+/* Single digit addition.  Assumes a is big enough. */
+STATIC void      s_dadd(mp_int a, mp_digit b);
+
+/* Single digit multiplication.  Assumes a is big enough. */
+STATIC void      s_dmul(mp_int a, mp_digit b);
+
+/* Single digit multiplication on buffers; assumes dc is big enough. */
+STATIC void      s_dbmul(mp_digit *da, mp_digit b, mp_digit *dc,
+			 mp_size size_a);
+
+/* Single digit division.  Replaces a with the quotient,
+   returns the remainder.  */
+STATIC mp_digit  s_ddiv(mp_int a, mp_digit b);
+
+/* Quick division by a power of 2, replaces z (no allocation) */
+STATIC void      s_qdiv(mp_int z, mp_size p2);
+
+/* Quick remainder by a power of 2, replaces z (no allocation) */
+STATIC void      s_qmod(mp_int z, mp_size p2);
+
+/* Quick multiplication by a power of 2, replaces z.
+   Allocates if necessary; returns false in case this fails. */
+STATIC int       s_qmul(mp_int z, mp_size p2);
+
+/* Quick subtraction from a power of 2, replaces z.
+   Allocates if necessary; returns false in case this fails. */
+STATIC int       s_qsub(mp_int z, mp_size p2);
+
+/* Return maximum k such that 2^k divides z. */
+STATIC int       s_dp2k(mp_int z);
+
+/* Return k >= 0 such that z = 2^k, or -1 if there is no such k. */
+STATIC int       s_isp2(mp_int z);
+
+/* Set z to 2^k.  May allocate; returns false in case this fails. */
+STATIC int       s_2expt(mp_int z, mp_small k);
+
+/* Normalize a and b for division, returns normalization constant */
+STATIC int       s_norm(mp_int a, mp_int b);
+
+/* Compute constant mu for Barrett reduction, given modulus m, result
+   replaces z, m is untouched. */
+STATIC mp_result s_brmu(mp_int z, mp_int m);
+
+/* Reduce a modulo m, using Barrett's algorithm. */
+STATIC int       s_reduce(mp_int x, mp_int m, mp_int mu, mp_int q1, mp_int q2);
+
+/* Modular exponentiation, using Barrett reduction */
+STATIC mp_result s_embar(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c);
+
+/* Unsigned magnitude division.  Assumes |a| > |b|.  Allocates temporaries;
+   overwrites a with quotient, b with remainder. */
+STATIC mp_result s_udiv_knuth(mp_int a, mp_int b);
+
+/* Compute the number of digits in radix r required to represent the given
+   value.  Does not account for sign flags, terminators, etc. */
+STATIC int       s_outlen(mp_int z, mp_size r);
+
+/* Guess how many digits of precision will be needed to represent a radix r
+   value of the specified number of digits.  Returns a value guaranteed to be
+   no smaller than the actual number required. */
+STATIC mp_size   s_inlen(int len, mp_size r);
+
+/* Convert a character to a digit value in radix r, or
+   -1 if out of range */
+STATIC int       s_ch2val(char c, int r);
+
+/* Convert a digit value to a character */
+STATIC char      s_val2ch(int v, int caps);
+
+/* Take 2's complement of a buffer in place */
+STATIC void      s_2comp(unsigned char *buf, int len);
+
+/* Convert a value to binary, ignoring sign.  On input, *limpos is the bound on
+   how many bytes should be written to buf; on output, *limpos is set to the
+   number of bytes actually written. */
+STATIC mp_result s_tobin(mp_int z, unsigned char *buf, int *limpos, int pad);
+
+#if DEBUG
+/* Dump a representation of the mp_int to standard output */
+void      s_print(char *tag, mp_int z);
+void      s_print_buf(char *tag, mp_digit *buf, mp_size num);
+#endif
+
+mp_result mp_int_init(mp_int z)
+{
+  if (z == NULL)
+    return MP_BADARG;
+
+  z->single = 0;
+  z->digits = &(z->single);
+  z->alloc  = 1;
+  z->used   = 1;
+  z->sign   = MP_ZPOS;
+
+  return MP_OK;
+}
+
+mp_int    mp_int_alloc(void)
+{
+  mp_int out = malloc(sizeof(mpz_t));
+
+  if (out != NULL)
+    mp_int_init(out);
+
+  return out;
+}
+
+mp_result mp_int_init_size(mp_int z, mp_size prec)
+{
+  CHECK(z != NULL);
+
+  if (prec == 0)
+    prec = default_precision;
+  else if (prec == 1)
+    return mp_int_init(z);
+  else
+    prec = (mp_size) ROUND_PREC(prec);
+
+  if ((MP_DIGITS(z) = s_alloc(prec)) == NULL)
+    return MP_MEMORY;
+
+  z->digits[0] = 0;
+  MP_USED(z) = 1;
+  MP_ALLOC(z) = prec;
+  MP_SIGN(z) = MP_ZPOS;
+
+  return MP_OK;
+}
+
+mp_result mp_int_init_copy(mp_int z, mp_int old)
+{
+  mp_result res;
+  mp_size uold;
+
+  CHECK(z != NULL && old != NULL);
+
+  uold = MP_USED(old);
+  if (uold == 1) {
+    mp_int_init(z);
+  }
+  else {
+    mp_size target = MAX(uold, default_precision);
+
+    if ((res = mp_int_init_size(z, target)) != MP_OK)
+      return res;
+  }
+
+  MP_USED(z) = uold;
+  MP_SIGN(z) = MP_SIGN(old);
+  COPY(MP_DIGITS(old), MP_DIGITS(z), uold);
+
+  return MP_OK;
+}
+
+mp_result mp_int_init_value(mp_int z, mp_small value)
+{
+  mpz_t    vtmp;
+  mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+  s_fake(&vtmp, value, vbuf);
+  return mp_int_init_copy(z, &vtmp);
+}
+
+mp_result mp_int_init_uvalue(mp_int z, mp_usmall uvalue)
+{
+  mpz_t    vtmp;
+  mp_digit vbuf[MP_VALUE_DIGITS(uvalue)];
+
+  s_ufake(&vtmp, uvalue, vbuf);
+  return mp_int_init_copy(z, &vtmp);
+}
+
+mp_result  mp_int_set_value(mp_int z, mp_small value)
+{
+  mpz_t    vtmp;
+  mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+  s_fake(&vtmp, value, vbuf);
+  return mp_int_copy(&vtmp, z);
+}
+
+mp_result  mp_int_set_uvalue(mp_int z, mp_usmall uvalue)
+{
+  mpz_t    vtmp;
+  mp_digit vbuf[MP_VALUE_DIGITS(uvalue)];
+
+  s_ufake(&vtmp, uvalue, vbuf);
+  return mp_int_copy(&vtmp, z);
+}
+
+void      mp_int_clear(mp_int z)
+{
+  if (z == NULL)
+    return;
+
+  if (MP_DIGITS(z) != NULL) {
+    if (MP_DIGITS(z) != &(z->single))
+      s_free(MP_DIGITS(z));
+
+    MP_DIGITS(z) = NULL;
+  }
+}
+
+void      mp_int_free(mp_int z)
+{
+  NRCHECK(z != NULL);
+
+  mp_int_clear(z);
+  free(z); /* note: NOT s_free() */
+}
+
+mp_result mp_int_copy(mp_int a, mp_int c)
+{
+  CHECK(a != NULL && c != NULL);
+
+  if (a != c) {
+    mp_size ua = MP_USED(a);
+    mp_digit *da, *dc;
+
+    if (!s_pad(c, ua))
+      return MP_MEMORY;
+
+    da = MP_DIGITS(a); dc = MP_DIGITS(c);
+    COPY(da, dc, ua);
+
+    MP_USED(c) = ua;
+    MP_SIGN(c) = MP_SIGN(a);
+  }
+
+  return MP_OK;
+}
+
+void      mp_int_swap(mp_int a, mp_int c)
+{
+  if (a != c) {
+    mpz_t tmp = *a;
+
+    *a = *c;
+    *c = tmp;
+
+    if (MP_DIGITS(a) == &(c->single))
+      MP_DIGITS(a) = &(a->single);
+    if (MP_DIGITS(c) == &(a->single))
+      MP_DIGITS(c) = &(c->single);
+  }
+}
+
+void      mp_int_zero(mp_int z)
+{
+  NRCHECK(z != NULL);
+
+  z->digits[0] = 0;
+  MP_USED(z) = 1;
+  MP_SIGN(z) = MP_ZPOS;
+}
+
+mp_result mp_int_abs(mp_int a, mp_int c)
+{
+  mp_result res;
+
+  CHECK(a != NULL && c != NULL);
+
+  if ((res = mp_int_copy(a, c)) != MP_OK)
+    return res;
+
+  MP_SIGN(c) = MP_ZPOS;
+  return MP_OK;
+}
+
+mp_result mp_int_neg(mp_int a, mp_int c)
+{
+  mp_result res;
+
+  CHECK(a != NULL && c != NULL);
+
+  if ((res = mp_int_copy(a, c)) != MP_OK)
+    return res;
+
+  if (CMPZ(c) != 0)
+    MP_SIGN(c) = 1 - MP_SIGN(a);
+
+  return MP_OK;
+}
+
+mp_result mp_int_add(mp_int a, mp_int b, mp_int c)
+{
+  mp_size ua, ub, uc, max;
+
+  CHECK(a != NULL && b != NULL && c != NULL);
+
+  ua = MP_USED(a); ub = MP_USED(b); uc = MP_USED(c);
+  max = MAX(ua, ub);
+
+  if (MP_SIGN(a) == MP_SIGN(b)) {
+    /* Same sign -- add magnitudes, preserve sign of addends */
+    mp_digit carry;
+
+    if (!s_pad(c, max))
+      return MP_MEMORY;
+
+    carry = s_uadd(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub);
+    uc = max;
+
+    if (carry) {
+      if (!s_pad(c, max + 1))
+	return MP_MEMORY;
+
+      c->digits[max] = carry;
+      ++uc;
+    }
+
+    MP_USED(c) = uc;
+    MP_SIGN(c) = MP_SIGN(a);
+
+  }
+  else {
+    /* Different signs -- subtract magnitudes, preserve sign of greater */
+    mp_int  x, y;
+    int     cmp = s_ucmp(a, b); /* magnitude comparision, sign ignored */
+
+    /* Set x to max(a, b), y to min(a, b) to simplify later code.
+       A special case yields zero for equal magnitudes.
+    */
+    if (cmp == 0) {
+      mp_int_zero(c);
+      return MP_OK;
+    }
+    else if (cmp < 0) {
+      x = b; y = a;
+    }
+    else {
+      x = a; y = b;
+    }
+
+    if (!s_pad(c, MP_USED(x)))
+      return MP_MEMORY;
+
+    /* Subtract smaller from larger */
+    s_usub(MP_DIGITS(x), MP_DIGITS(y), MP_DIGITS(c), MP_USED(x), MP_USED(y));
+    MP_USED(c) = MP_USED(x);
+    CLAMP(c);
+
+    /* Give result the sign of the larger */
+    MP_SIGN(c) = MP_SIGN(x);
+  }
+
+  return MP_OK;
+}
+
+mp_result mp_int_add_value(mp_int a, mp_small value, mp_int c)
+{
+  mpz_t    vtmp;
+  mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+  s_fake(&vtmp, value, vbuf);
+
+  return mp_int_add(a, &vtmp, c);
+}
+
+mp_result mp_int_sub(mp_int a, mp_int b, mp_int c)
+{
+  mp_size ua, ub, uc, max;
+
+  CHECK(a != NULL && b != NULL && c != NULL);
+
+  ua = MP_USED(a); ub = MP_USED(b); uc = MP_USED(c);
+  max = MAX(ua, ub);
+
+  if (MP_SIGN(a) != MP_SIGN(b)) {
+    /* Different signs -- add magnitudes and keep sign of a */
+    mp_digit carry;
+
+    if (!s_pad(c, max))
+      return MP_MEMORY;
+
+    carry = s_uadd(MP_DIGITS(a), MP_DIGITS(b), MP_DIGITS(c), ua, ub);
+    uc = max;
+
+    if (carry) {
+      if (!s_pad(c, max + 1))
+	return MP_MEMORY;
+
+      c->digits[max] = carry;
+      ++uc;
+    }
+
+    MP_USED(c) = uc;
+    MP_SIGN(c) = MP_SIGN(a);
+
+  }
+  else {
+    /* Same signs -- subtract magnitudes */
+    mp_int  x, y;
+    mp_sign osign;
+    int     cmp = s_ucmp(a, b);
+
+    if (!s_pad(c, max))
+      return MP_MEMORY;
+
+    if (cmp >= 0) {
+      x = a; y = b; osign = MP_ZPOS;
+    }
+    else {
+      x = b; y = a; osign = MP_NEG;
+    }
+
+    if (MP_SIGN(a) == MP_NEG && cmp != 0)
+      osign = 1 - osign;
+
+    s_usub(MP_DIGITS(x), MP_DIGITS(y), MP_DIGITS(c), MP_USED(x), MP_USED(y));
+    MP_USED(c) = MP_USED(x);
+    CLAMP(c);
+
+    MP_SIGN(c) = osign;
+  }
+
+  return MP_OK;
+}
+
+mp_result mp_int_sub_value(mp_int a, mp_small value, mp_int c)
+{
+  mpz_t    vtmp;
+  mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+  s_fake(&vtmp, value, vbuf);
+
+  return mp_int_sub(a, &vtmp, c);
+}
+
+mp_result mp_int_mul(mp_int a, mp_int b, mp_int c)
+{
+  mp_digit *out;
+  mp_size   osize, ua, ub, p = 0;
+  mp_sign   osign;
+
+  CHECK(a != NULL && b != NULL && c != NULL);
+
+  /* If either input is zero, we can shortcut multiplication */
+  if (mp_int_compare_zero(a) == 0 || mp_int_compare_zero(b) == 0) {
+    mp_int_zero(c);
+    return MP_OK;
+  }
+
+  /* Output is positive if inputs have same sign, otherwise negative */
+  osign = (MP_SIGN(a) == MP_SIGN(b)) ? MP_ZPOS : MP_NEG;
+
+  /* If the output is not identical to any of the inputs, we'll write the
+     results directly; otherwise, allocate a temporary space. */
+  ua = MP_USED(a); ub = MP_USED(b);
+  osize = MAX(ua, ub);
+  osize = 4 * ((osize + 1) / 2);
+
+  if (c == a || c == b) {
+    p = ROUND_PREC(osize);
+    p = MAX(p, default_precision);
+
+    if ((out = s_alloc(p)) == NULL)
+      return MP_MEMORY;
+  }
+  else {
+    if (!s_pad(c, osize))
+      return MP_MEMORY;
+
+    out = MP_DIGITS(c);
+  }
+  ZERO(out, osize);
+
+  if (!s_kmul(MP_DIGITS(a), MP_DIGITS(b), out, ua, ub))
+    return MP_MEMORY;
+
+  /* If we allocated a new buffer, get rid of whatever memory c was already
+     using, and fix up its fields to reflect that.
+   */
+  if (out != MP_DIGITS(c)) {
+    if ((void *) MP_DIGITS(c) != (void *) c)
+      s_free(MP_DIGITS(c));
+    MP_DIGITS(c) = out;
+    MP_ALLOC(c) = p;
+  }
+
+  MP_USED(c) = osize; /* might not be true, but we'll fix it ... */
+  CLAMP(c);           /* ... right here */
+  MP_SIGN(c) = osign;
+
+  return MP_OK;
+}
+
+mp_result mp_int_mul_value(mp_int a, mp_small value, mp_int c)
+{
+  mpz_t    vtmp;
+  mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+  s_fake(&vtmp, value, vbuf);
+
+  return mp_int_mul(a, &vtmp, c);
+}
+
+mp_result mp_int_mul_pow2(mp_int a, mp_small p2, mp_int c)
+{
+  mp_result res;
+  CHECK(a != NULL && c != NULL && p2 >= 0);
+
+  if ((res = mp_int_copy(a, c)) != MP_OK)
+    return res;
+
+  if (s_qmul(c, (mp_size) p2))
+    return MP_OK;
+  else
+    return MP_MEMORY;
+}
+
+mp_result mp_int_sqr(mp_int a, mp_int c)
+{
+  mp_digit *out;
+  mp_size   osize, p = 0;
+
+  CHECK(a != NULL && c != NULL);
+
+  /* Get a temporary buffer big enough to hold the result */
+  osize = (mp_size) 4 * ((MP_USED(a) + 1) / 2);
+  if (a == c) {
+    p = ROUND_PREC(osize);
+    p = MAX(p, default_precision);
+
+    if ((out = s_alloc(p)) == NULL)
+      return MP_MEMORY;
+  }
+  else {
+    if (!s_pad(c, osize))
+      return MP_MEMORY;
+
+    out = MP_DIGITS(c);
+  }
+  ZERO(out, osize);
+
+  s_ksqr(MP_DIGITS(a), out, MP_USED(a));
+
+  /* Get rid of whatever memory c was already using, and fix up its fields to
+     reflect the new digit array it's using
+   */
+  if (out != MP_DIGITS(c)) {
+    if ((void *) MP_DIGITS(c) != (void *) c)
+      s_free(MP_DIGITS(c));
+    MP_DIGITS(c) = out;
+    MP_ALLOC(c) = p;
+  }
+
+  MP_USED(c) = osize; /* might not be true, but we'll fix it ... */
+  CLAMP(c);           /* ... right here */
+  MP_SIGN(c) = MP_ZPOS;
+
+  return MP_OK;
+}
+
+mp_result mp_int_div(mp_int a, mp_int b, mp_int q, mp_int r)
+{
+  int cmp, lg;
+  mp_result res = MP_OK;
+  mp_int qout, rout;
+  mp_sign sa = MP_SIGN(a), sb = MP_SIGN(b);
+  DECLARE_TEMP(2);
+
+  CHECK(a != NULL && b != NULL && q != r);
+
+  if (CMPZ(b) == 0)
+    return MP_UNDEF;
+  else if ((cmp = s_ucmp(a, b)) < 0) {
+    /* If |a| < |b|, no division is required:
+       q = 0, r = a
+     */
+    if (r && (res = mp_int_copy(a, r)) != MP_OK)
+      return res;
+
+    if (q)
+      mp_int_zero(q);
+
+    return MP_OK;
+  }
+  else if (cmp == 0) {
+    /* If |a| = |b|, no division is required:
+       q = 1 or -1, r = 0
+     */
+    if (r)
+      mp_int_zero(r);
+
+    if (q) {
+      mp_int_zero(q);
+      q->digits[0] = 1;
+
+      if (sa != sb)
+	MP_SIGN(q) = MP_NEG;
+    }
+
+    return MP_OK;
+  }
+
+  /* When |a| > |b|, real division is required.  We need someplace to store
+     quotient and remainder, but q and r are allowed to be NULL or to overlap
+     with the inputs.
+   */
+  if ((lg = s_isp2(b)) < 0) {
+    if (q && b != q) {
+      if ((res = mp_int_copy(a, q)) != MP_OK)
+	goto CLEANUP;
+      else
+	qout = q;
+    }
+    else {
+      qout = LAST_TEMP();
+      SETUP(mp_int_init_copy(LAST_TEMP(), a));
+    }
+
+    if (r && a != r) {
+      if ((res = mp_int_copy(b, r)) != MP_OK)
+	goto CLEANUP;
+      else
+	rout = r;
+    }
+    else {
+      rout = LAST_TEMP();
+      SETUP(mp_int_init_copy(LAST_TEMP(), b));
+    }
+
+    if ((res = s_udiv_knuth(qout, rout)) != MP_OK) goto CLEANUP;
+  }
+  else {
+    if (q && (res = mp_int_copy(a, q)) != MP_OK) goto CLEANUP;
+    if (r && (res = mp_int_copy(a, r)) != MP_OK) goto CLEANUP;
+
+    if (q) s_qdiv(q, (mp_size) lg); qout = q;
+    if (r) s_qmod(r, (mp_size) lg); rout = r;
+  }
+
+  /* Recompute signs for output */
+  if (rout) {
+    MP_SIGN(rout) = sa;
+    if (CMPZ(rout) == 0)
+      MP_SIGN(rout) = MP_ZPOS;
+  }
+  if (qout) {
+    MP_SIGN(qout) = (sa == sb) ? MP_ZPOS : MP_NEG;
+    if (CMPZ(qout) == 0)
+      MP_SIGN(qout) = MP_ZPOS;
+  }
+
+  if (q && (res = mp_int_copy(qout, q)) != MP_OK) goto CLEANUP;
+  if (r && (res = mp_int_copy(rout, r)) != MP_OK) goto CLEANUP;
+
+  CLEANUP_TEMP();
+  return res;
+}
+
+mp_result mp_int_mod(mp_int a, mp_int m, mp_int c)
+{
+  mp_result res;
+  mpz_t     tmp;
+  mp_int    out;
+
+  if (m == c) {
+    mp_int_init(&tmp);
+    out = &tmp;
+  }
+  else {
+    out = c;
+  }
+
+  if ((res = mp_int_div(a, m, NULL, out)) != MP_OK)
+    goto CLEANUP;
+
+  if (CMPZ(out) < 0)
+    res = mp_int_add(out, m, c);
+  else
+    res = mp_int_copy(out, c);
+
+ CLEANUP:
+  if (out != c)
+    mp_int_clear(&tmp);
+
+  return res;
+}
+
+mp_result mp_int_div_value(mp_int a, mp_small value, mp_int q, mp_small *r)
+{
+  mpz_t     vtmp, rtmp;
+  mp_digit  vbuf[MP_VALUE_DIGITS(value)];
+  mp_result res;
+
+  mp_int_init(&rtmp);
+  s_fake(&vtmp, value, vbuf);
+
+  if ((res = mp_int_div(a, &vtmp, q, &rtmp)) != MP_OK)
+    goto CLEANUP;
+
+  if (r)
+    (void) mp_int_to_int(&rtmp, r); /* can't fail */
+
+ CLEANUP:
+  mp_int_clear(&rtmp);
+  return res;
+}
+
+mp_result mp_int_div_pow2(mp_int a, mp_small p2, mp_int q, mp_int r)
+{
+  mp_result res = MP_OK;
+
+  CHECK(a != NULL && p2 >= 0 && q != r);
+
+  if (q != NULL && (res = mp_int_copy(a, q)) == MP_OK)
+    s_qdiv(q, (mp_size) p2);
+
+  if (res == MP_OK && r != NULL && (res = mp_int_copy(a, r)) == MP_OK)
+    s_qmod(r, (mp_size) p2);
+
+  return res;
+}
+
+mp_result mp_int_expt(mp_int a, mp_small b, mp_int c)
+{
+  mpz_t t;
+  mp_result res;
+  unsigned int v = labs(b);
+
+  CHECK(c != NULL);
+  if (b < 0)
+    return MP_RANGE;
+
+  if ((res = mp_int_init_copy(&t, a)) != MP_OK)
+    return res;
+
+  (void) mp_int_set_value(c, 1);
+  while (v != 0) {
+    if (v & 1) {
+      if ((res = mp_int_mul(c, &t, c)) != MP_OK)
+	goto CLEANUP;
+    }
+
+    v >>= 1;
+    if (v == 0) break;
+
+    if ((res = mp_int_sqr(&t, &t)) != MP_OK)
+      goto CLEANUP;
+  }
+
+ CLEANUP:
+  mp_int_clear(&t);
+  return res;
+}
+
+mp_result mp_int_expt_value(mp_small a, mp_small b, mp_int c)
+{
+  mpz_t     t;
+  mp_result res;
+  unsigned int v = labs(b);
+
+  CHECK(c != NULL);
+  if (b < 0)
+    return MP_RANGE;
+
+  if ((res = mp_int_init_value(&t, a)) != MP_OK)
+    return res;
+
+  (void) mp_int_set_value(c, 1);
+  while (v != 0) {
+    if (v & 1) {
+      if ((res = mp_int_mul(c, &t, c)) != MP_OK)
+	goto CLEANUP;
+    }
+
+    v >>= 1;
+    if (v == 0) break;
+
+    if ((res = mp_int_sqr(&t, &t)) != MP_OK)
+      goto CLEANUP;
+  }
+
+ CLEANUP:
+  mp_int_clear(&t);
+  return res;
+}
+
+mp_result mp_int_expt_full(mp_int a, mp_int b, mp_int c)
+{
+  mpz_t t;
+  mp_result res;
+  unsigned ix, jx;
+
+  CHECK(a != NULL && b != NULL && c != NULL);
+  if (MP_SIGN(b) == MP_NEG)
+    return MP_RANGE;
+
+  if ((res = mp_int_init_copy(&t, a)) != MP_OK)
+    return res;
+
+  (void) mp_int_set_value(c, 1);
+  for (ix = 0; ix < MP_USED(b); ++ix) {
+    mp_digit d = b->digits[ix];
+
+    for (jx = 0; jx < MP_DIGIT_BIT; ++jx) {
+      if (d & 1) {
+	if ((res = mp_int_mul(c, &t, c)) != MP_OK)
+	  goto CLEANUP;
+      }
+
+      d >>= 1;
+      if (d == 0 && ix + 1 == MP_USED(b))
+	break;
+      if ((res = mp_int_sqr(&t, &t)) != MP_OK)
+	goto CLEANUP;
+    }
+  }
+
+ CLEANUP:
+  mp_int_clear(&t);
+  return res;
+}
+
+int       mp_int_compare(mp_int a, mp_int b)
+{
+  mp_sign sa;
+
+  CHECK(a != NULL && b != NULL);
+
+  sa = MP_SIGN(a);
+  if (sa == MP_SIGN(b)) {
+    int cmp = s_ucmp(a, b);
+
+    /* If they're both zero or positive, the normal comparison applies; if both
+       negative, the sense is reversed. */
+    if (sa == MP_ZPOS)
+      return cmp;
+    else
+      return -cmp;
+
+  }
+  else {
+    if (sa == MP_ZPOS)
+      return 1;
+    else
+      return -1;
+  }
+}
+
+int       mp_int_compare_unsigned(mp_int a, mp_int b)
+{
+  NRCHECK(a != NULL && b != NULL);
+
+  return s_ucmp(a, b);
+}
+
+int       mp_int_compare_zero(mp_int z)
+{
+  NRCHECK(z != NULL);
+
+  if (MP_USED(z) == 1 && z->digits[0] == 0)
+    return 0;
+  else if (MP_SIGN(z) == MP_ZPOS)
+    return 1;
+  else
+    return -1;
+}
+
+int       mp_int_compare_value(mp_int z, mp_small value)
+{
+  mp_sign vsign = (value < 0) ? MP_NEG : MP_ZPOS;
+  int cmp;
+
+  CHECK(z != NULL);
+
+  if (vsign == MP_SIGN(z)) {
+    cmp = s_vcmp(z, value);
+
+    return (vsign == MP_ZPOS) ? cmp : -cmp;
+  }
+  else {
+    return (value < 0) ? 1 : -1;
+  }
+}
+
+int       mp_int_compare_uvalue(mp_int z, mp_usmall uv)
+{
+  CHECK(z != NULL);
+
+  if (MP_SIGN(z) == MP_NEG)
+    return -1;
+  else
+    return s_uvcmp(z, uv);
+}
+
+mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m, mp_int c)
+{
+  mp_result res;
+  mp_size um;
+  mp_int s;
+  DECLARE_TEMP(3);
+
+  CHECK(a != NULL && b != NULL && c != NULL && m != NULL);
+
+  /* Zero moduli and negative exponents are not considered. */
+  if (CMPZ(m) == 0)
+    return MP_UNDEF;
+  if (CMPZ(b) < 0)
+    return MP_RANGE;
+
+  um = MP_USED(m);
+  SETUP(mp_int_init_size(TEMP(0), 2 * um));
+  SETUP(mp_int_init_size(TEMP(1), 2 * um));
+
+  if (c == b || c == m) {
+    SETUP(mp_int_init_size(TEMP(2), 2 * um));
+    s = TEMP(2);
+  }
+  else {
+    s = c;
+  }
+
+  if ((res = mp_int_mod(a, m, TEMP(0))) != MP_OK) goto CLEANUP;
+
+  if ((res = s_brmu(TEMP(1), m)) != MP_OK) goto CLEANUP;
+
+  if ((res = s_embar(TEMP(0), b, m, TEMP(1), s)) != MP_OK)
+    goto CLEANUP;
+
+  res = mp_int_copy(s, c);
+
+  CLEANUP_TEMP();
+  return res;
+}
+
+mp_result mp_int_exptmod_evalue(mp_int a, mp_small value, mp_int m, mp_int c)
+{
+  mpz_t vtmp;
+  mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+  s_fake(&vtmp, value, vbuf);
+
+  return mp_int_exptmod(a, &vtmp, m, c);
+}
+
+mp_result mp_int_exptmod_bvalue(mp_small value, mp_int b,
+				mp_int m, mp_int c)
+{
+  mpz_t vtmp;
+  mp_digit vbuf[MP_VALUE_DIGITS(value)];
+
+  s_fake(&vtmp, value, vbuf);
+
+  return mp_int_exptmod(&vtmp, b, m, c);
+}
+
+mp_result mp_int_exptmod_known(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c)
+{
+  mp_result res;
+  mp_size um;
+  mp_int s;
+  DECLARE_TEMP(2);
+
+  CHECK(a && b && m && c);
+
+  /* Zero moduli and negative exponents are not considered. */
+  if (CMPZ(m) == 0)
+    return MP_UNDEF;
+  if (CMPZ(b) < 0)
+    return MP_RANGE;
+
+  um = MP_USED(m);
+  SETUP(mp_int_init_size(TEMP(0), 2 * um));
+
+  if (c == b || c == m) {
+    SETUP(mp_int_init_size(TEMP(1), 2 * um));
+    s = TEMP(1);
+  }
+  else {
+    s = c;
+  }
+
+  if ((res = mp_int_mod(a, m, TEMP(0))) != MP_OK) goto CLEANUP;
+
+  if ((res = s_embar(TEMP(0), b, m, mu, s)) != MP_OK)
+    goto CLEANUP;
+
+  res = mp_int_copy(s, c);
+
+  CLEANUP_TEMP();
+  return res;
+}
+
+mp_result mp_int_redux_const(mp_int m, mp_int c)
+{
+  CHECK(m != NULL && c != NULL && m != c);
+
+  return s_brmu(c, m);
+}
+
+mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c)
+{
+  mp_result res;
+  mp_sign sa;
+  DECLARE_TEMP(2);
+
+  CHECK(a != NULL && m != NULL && c != NULL);
+
+  if (CMPZ(a) == 0 || CMPZ(m) <= 0)
+    return MP_RANGE;
+
+  sa = MP_SIGN(a); /* need this for the result later */
+
+  for (last__ = 0; last__ < 2; ++last__)
+    mp_int_init(LAST_TEMP());
+
+  if ((res = mp_int_egcd(a, m, TEMP(0), TEMP(1), NULL)) != MP_OK)
+    goto CLEANUP;
+
+  if (mp_int_compare_value(TEMP(0), 1) != 0) {
+    res = MP_UNDEF;
+    goto CLEANUP;
+  }
+
+  /* It is first necessary to constrain the value to the proper range */
+  if ((res = mp_int_mod(TEMP(1), m, TEMP(1))) != MP_OK)
+    goto CLEANUP;
+
+  /* Now, if 'a' was originally negative, the value we have is actually the
+     magnitude of the negative representative; to get the positive value we
+     have to subtract from the modulus.  Otherwise, the value is okay as it
+     stands.
+   */
+  if (sa == MP_NEG)
+    res = mp_int_sub(m, TEMP(1), c);
+  else
+    res = mp_int_copy(TEMP(1), c);
+
+  CLEANUP_TEMP();
+  return res;
+}
+
+/* Binary GCD algorithm due to Josef Stein, 1961 */
+mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c)
+{
+  int ca, cb, k = 0;
+  mpz_t u, v, t;
+  mp_result res;
+
+  CHECK(a != NULL && b != NULL && c != NULL);
+
+  ca = CMPZ(a);
+  cb = CMPZ(b);
+  if (ca == 0 && cb == 0)
+    return MP_UNDEF;
+  else if (ca == 0)
+    return mp_int_abs(b, c);
+  else if (cb == 0)
+    return mp_int_abs(a, c);
+
+  mp_int_init(&t);
+  if ((res = mp_int_init_copy(&u, a)) != MP_OK)
+    goto U;
+  if ((res = mp_int_init_copy(&v, b)) != MP_OK)
+    goto V;
+
+  MP_SIGN(&u) = MP_ZPOS; MP_SIGN(&v) = MP_ZPOS;
+
+  { /* Divide out common factors of 2 from u and v */
+    int div2_u = s_dp2k(&u), div2_v = s_dp2k(&v);
+
+    k = MIN(div2_u, div2_v);
+    s_qdiv(&u, (mp_size) k);
+    s_qdiv(&v, (mp_size) k);
+  }
+
+  if (mp_int_is_odd(&u)) {
+    if ((res = mp_int_neg(&v, &t)) != MP_OK)
+      goto CLEANUP;
+  }
+  else {
+    if ((res = mp_int_copy(&u, &t)) != MP_OK)
+      goto CLEANUP;
+  }
+
+  for (;;) {
+    s_qdiv(&t, s_dp2k(&t));
+
+    if (CMPZ(&t) > 0) {
+      if ((res = mp_int_copy(&t, &u)) != MP_OK)
+	goto CLEANUP;
+    }
+    else {
+      if ((res = mp_int_neg(&t, &v)) != MP_OK)
+	goto CLEANUP;
+    }
+
+    if ((res = mp_int_sub(&u, &v, &t)) != MP_OK)
+      goto CLEANUP;
+
+    if (CMPZ(&t) == 0)
+      break;
+  }
+
+  if ((res = mp_int_abs(&u, c)) != MP_OK)
+    goto CLEANUP;
+  if (!s_qmul(c, (mp_size) k))
+    res = MP_MEMORY;
+
+ CLEANUP:
+  mp_int_clear(&v);
+ V: mp_int_clear(&u);
+ U: mp_int_clear(&t);
+
+  return res;
+}
+
+/* This is the binary GCD algorithm again, but this time we keep track of the
+   elementary matrix operations as we go, so we can get values x and y
+   satisfying c = ax + by.
+ */
+mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c,
+		      mp_int x, mp_int y)
+{
+  int k, ca, cb;
+  mp_result res;
+  DECLARE_TEMP(8);
+
+  CHECK(a != NULL && b != NULL && c != NULL &&
+	(x != NULL || y != NULL));
+
+  ca = CMPZ(a);
+  cb = CMPZ(b);
+  if (ca == 0 && cb == 0)
+    return MP_UNDEF;
+  else if (ca == 0) {
+    if ((res = mp_int_abs(b, c)) != MP_OK) return res;
+    mp_int_zero(x); (void) mp_int_set_value(y, 1); return MP_OK;
+  }
+  else if (cb == 0) {
+    if ((res = mp_int_abs(a, c)) != MP_OK) return res;
+    (void) mp_int_set_value(x, 1); mp_int_zero(y); return MP_OK;
+  }
+
+  /* Initialize temporaries:
+     A:0, B:1, C:2, D:3, u:4, v:5, ou:6, ov:7 */
+  for (last__ = 0; last__ < 4; ++last__)
+    mp_int_init(LAST_TEMP());
+  TEMP(0)->digits[0] = 1;
+  TEMP(3)->digits[0] = 1;
+
+  SETUP(mp_int_init_copy(TEMP(4), a));
+  SETUP(mp_int_init_copy(TEMP(5), b));
+
+  /* We will work with absolute values here */
+  MP_SIGN(TEMP(4)) = MP_ZPOS;
+  MP_SIGN(TEMP(5)) = MP_ZPOS;
+
+  { /* Divide out common factors of 2 from u and v */
+    int  div2_u = s_dp2k(TEMP(4)), div2_v = s_dp2k(TEMP(5));
+
+    k = MIN(div2_u, div2_v);
+    s_qdiv(TEMP(4), k);
+    s_qdiv(TEMP(5), k);
+  }
+
+  SETUP(mp_int_init_copy(TEMP(6), TEMP(4)));
+  SETUP(mp_int_init_copy(TEMP(7), TEMP(5)));
+
+  for (;;) {
+    while (mp_int_is_even(TEMP(4))) {
+      s_qdiv(TEMP(4), 1);
+
+      if (mp_int_is_odd(TEMP(0)) || mp_int_is_odd(TEMP(1))) {
+	if ((res = mp_int_add(TEMP(0), TEMP(7), TEMP(0))) != MP_OK)
+	  goto CLEANUP;
+	if ((res = mp_int_sub(TEMP(1), TEMP(6), TEMP(1))) != MP_OK)
+	  goto CLEANUP;
+      }
+
+      s_qdiv(TEMP(0), 1);
+      s_qdiv(TEMP(1), 1);
+    }
+
+    while (mp_int_is_even(TEMP(5))) {
+      s_qdiv(TEMP(5), 1);
+
+      if (mp_int_is_odd(TEMP(2)) || mp_int_is_odd(TEMP(3))) {
+	if ((res = mp_int_add(TEMP(2), TEMP(7), TEMP(2))) != MP_OK)
+	  goto CLEANUP;
+	if ((res = mp_int_sub(TEMP(3), TEMP(6), TEMP(3))) != MP_OK)
+	  goto CLEANUP;
+      }
+
+      s_qdiv(TEMP(2), 1);
+      s_qdiv(TEMP(3), 1);
+    }
+
+    if (mp_int_compare(TEMP(4), TEMP(5)) >= 0) {
+      if ((res = mp_int_sub(TEMP(4), TEMP(5), TEMP(4))) != MP_OK) goto CLEANUP;
+      if ((res = mp_int_sub(TEMP(0), TEMP(2), TEMP(0))) != MP_OK) goto CLEANUP;
+      if ((res = mp_int_sub(TEMP(1), TEMP(3), TEMP(1))) != MP_OK) goto CLEANUP;
+    }
+    else {
+      if ((res = mp_int_sub(TEMP(5), TEMP(4), TEMP(5))) != MP_OK) goto CLEANUP;
+      if ((res = mp_int_sub(TEMP(2), TEMP(0), TEMP(2))) != MP_OK) goto CLEANUP;
+      if ((res = mp_int_sub(TEMP(3), TEMP(1), TEMP(3))) != MP_OK) goto CLEANUP;
+    }
+
+    if (CMPZ(TEMP(4)) == 0) {
+      if (x && (res = mp_int_copy(TEMP(2), x)) != MP_OK) goto CLEANUP;
+      if (y && (res = mp_int_copy(TEMP(3), y)) != MP_OK) goto CLEANUP;
+      if (c) {
+	if (!s_qmul(TEMP(5), k)) {
+	  res = MP_MEMORY;
+	  goto CLEANUP;
+	}
+
+	res = mp_int_copy(TEMP(5), c);
+      }
+
+      break;
+    }
+  }
+
+  CLEANUP_TEMP();
+  return res;
+}
+
+mp_result mp_int_lcm(mp_int a, mp_int b, mp_int c)
+{
+  mpz_t lcm;
+  mp_result res;
+
+  CHECK(a != NULL && b != NULL && c != NULL);
+
+  /* Since a * b = gcd(a, b) * lcm(a, b), we can compute
+     lcm(a, b) = (a / gcd(a, b)) * b.
+
+     This formulation insures everything works even if the input
+     variables share space.
+   */
+  if ((res = mp_int_init(&lcm)) != MP_OK)
+    return res;
+  if ((res = mp_int_gcd(a, b, &lcm)) != MP_OK)
+    goto CLEANUP;
+  if ((res = mp_int_div(a, &lcm, &lcm, NULL)) != MP_OK)
+    goto CLEANUP;
+  if ((res = mp_int_mul(&lcm, b, &lcm)) != MP_OK)
+    goto CLEANUP;
+
+  res = mp_int_copy(&lcm, c);
+
+  CLEANUP:
+    mp_int_clear(&lcm);
+
+  return res;
+}
+
+int       mp_int_divisible_value(mp_int a, mp_small v)
+{
+  mp_small rem = 0;
+
+  if (mp_int_div_value(a, v, NULL, &rem) != MP_OK)
+    return 0;
+
+  return rem == 0;
+}
+
+int       mp_int_is_pow2(mp_int z)
+{
+  CHECK(z != NULL);
+
+  return s_isp2(z);
+}
+
+/* Implementation of Newton's root finding method, based loosely on a patch
+   contributed by Hal Finkel <half@halssoftware.com>
+   modified by M. J. Fromberger.
+ */
+mp_result mp_int_root(mp_int a, mp_small b, mp_int c)
+{
+  mp_result res = MP_OK;
+  int flips = 0;
+  DECLARE_TEMP(5);
+
+  CHECK(a != NULL && c != NULL && b > 0);
+
+  if (b == 1) {
+    return mp_int_copy(a, c);
+  }
+  if (MP_SIGN(a) == MP_NEG) {
+    if (b % 2 == 0)
+      return MP_UNDEF; /* root does not exist for negative a with even b */
+    else
+      flips = 1;
+  }
+
+  SETUP(mp_int_init_copy(LAST_TEMP(), a));
+  SETUP(mp_int_init_copy(LAST_TEMP(), a));
+  SETUP(mp_int_init(LAST_TEMP()));
+  SETUP(mp_int_init(LAST_TEMP()));
+  SETUP(mp_int_init(LAST_TEMP()));
+
+  (void) mp_int_abs(TEMP(0), TEMP(0));
+  (void) mp_int_abs(TEMP(1), TEMP(1));
+
+  for (;;) {
+    if ((res = mp_int_expt(TEMP(1), b, TEMP(2))) != MP_OK)
+      goto CLEANUP;
+
+    if (mp_int_compare_unsigned(TEMP(2), TEMP(0)) <= 0)
+      break;
+
+    if ((res = mp_int_sub(TEMP(2), TEMP(0), TEMP(2))) != MP_OK)
+      goto CLEANUP;
+    if ((res = mp_int_expt(TEMP(1), b - 1, TEMP(3))) != MP_OK)
+      goto CLEANUP;
+    if ((res = mp_int_mul_value(TEMP(3), b, TEMP(3))) != MP_OK)
+      goto CLEANUP;
+    if ((res = mp_int_div(TEMP(2), TEMP(3), TEMP(4), NULL)) != MP_OK)
+      goto CLEANUP;
+    if ((res = mp_int_sub(TEMP(1), TEMP(4), TEMP(4))) != MP_OK)
+      goto CLEANUP;
+
+    if (mp_int_compare_unsigned(TEMP(1), TEMP(4)) == 0) {
+      if ((res = mp_int_sub_value(TEMP(4), 1, TEMP(4))) != MP_OK)
+	goto CLEANUP;
+    }
+    if ((res = mp_int_copy(TEMP(4), TEMP(1))) != MP_OK)
+      goto CLEANUP;
+  }
+
+  if ((res = mp_int_copy(TEMP(1), c)) != MP_OK)
+    goto CLEANUP;
+
+  /* If the original value of a was negative, flip the output sign. */
+  if (flips)
+    (void) mp_int_neg(c, c); /* cannot fail */
+
+  CLEANUP_TEMP();
+  return res;
+}
+
+mp_result mp_int_to_int(mp_int z, mp_small *out)
+{
+  mp_usmall uv = 0;
+  mp_size   uz;
+  mp_digit *dz;
+  mp_sign   sz;
+
+  CHECK(z != NULL);
+
+  /* Make sure the value is representable as a small integer */
+  sz = MP_SIGN(z);
+  if ((sz == MP_ZPOS && mp_int_compare_value(z, MP_SMALL_MAX) > 0) ||
+      mp_int_compare_value(z, MP_SMALL_MIN) < 0)
+    return MP_RANGE;
+
+  uz = MP_USED(z);
+  dz = MP_DIGITS(z) + uz - 1;
+
+  while (uz > 0) {
+    uv <<= MP_DIGIT_BIT/2;
+    uv = (uv << (MP_DIGIT_BIT/2)) | *dz--;
+    --uz;
+  }
+
+  if (out)
+    *out = (mp_small)((sz == MP_NEG) ? -uv : uv);
+
+  return MP_OK;
+}
+
+mp_result mp_int_to_uint(mp_int z, mp_usmall *out)
+{
+  mp_usmall uv = 0;
+  mp_size   uz;
+  mp_digit *dz;
+  mp_sign   sz;
+  
+  CHECK(z != NULL);
+
+  /* Make sure the value is representable as an unsigned small integer */
+  sz = MP_SIGN(z);
+  if (sz == MP_NEG || mp_int_compare_uvalue(z, MP_USMALL_MAX) > 0)
+    return MP_RANGE;
+     
+  uz = MP_USED(z);
+  dz = MP_DIGITS(z) + uz - 1;
+  
+  while (uz > 0) {
+    uv <<= MP_DIGIT_BIT/2;
+    uv = (uv << (MP_DIGIT_BIT/2)) | *dz--;
+    --uz;
+  }
+  
+  if (out)
+    *out = uv;
+  
+  return MP_OK;
+}
+
+mp_result mp_int_to_string(mp_int z, mp_size radix,
+			   char *str, int limit)
+{
+  mp_result res;
+  int       cmp = 0;
+
+  CHECK(z != NULL && str != NULL && limit >= 2);
+
+  if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX)
+    return MP_RANGE;
+
+  if (CMPZ(z) == 0) {
+    *str++ = s_val2ch(0, 1);
+  }
+  else {
+    mpz_t tmp;
+    char  *h, *t;
+
+    if ((res = mp_int_init_copy(&tmp, z)) != MP_OK)
+      return res;
+
+    if (MP_SIGN(z) == MP_NEG) {
+      *str++ = '-';
+      --limit;
+    }
+    h = str;
+
+    /* Generate digits in reverse order until finished or limit reached */
+    for (/* */; limit > 0; --limit) {
+      mp_digit d;
+
+      if ((cmp = CMPZ(&tmp)) == 0)
+	break;
+
+      d = s_ddiv(&tmp, (mp_digit)radix);
+      *str++ = s_val2ch(d, 1);
+    }
+    t = str - 1;
+
+    /* Put digits back in correct output order */
+    while (h < t) {
+      char tc = *h;
+      *h++ = *t;
+      *t-- = tc;
+    }
+
+    mp_int_clear(&tmp);
+  }
+
+  *str = '\0';
+  if (cmp == 0)
+    return MP_OK;
+  else
+    return MP_TRUNC;
+}
+
+mp_result mp_int_string_len(mp_int z, mp_size radix)
+{
+  int  len;
+
+  CHECK(z != NULL);
+
+  if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX)
+    return MP_RANGE;
+
+  len = s_outlen(z, radix) + 1; /* for terminator */
+
+  /* Allow for sign marker on negatives */
+  if (MP_SIGN(z) == MP_NEG)
+    len += 1;
+
+  return len;
+}
+
+/* Read zero-terminated string into z */
+mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str)
+{
+  return mp_int_read_cstring(z, radix, str, NULL);
+}
+
+mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str, char **end)
+{
+  int ch;
+
+  CHECK(z != NULL && str != NULL);
+
+  if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX)
+    return MP_RANGE;
+
+  /* Skip leading whitespace */
+  while (isspace((int)*str))
+    ++str;
+
+  /* Handle leading sign tag (+/-, positive default) */
+  switch (*str) {
+  case '-':
+    MP_SIGN(z) = MP_NEG;
+    ++str;
+    break;
+  case '+':
+    ++str; /* fallthrough */
+  default:
+    MP_SIGN(z) = MP_ZPOS;
+    break;
+  }
+
+  /* Skip leading zeroes */
+  while ((ch = s_ch2val(*str, radix)) == 0)
+    ++str;
+
+  /* Make sure there is enough space for the value */
+  if (!s_pad(z, s_inlen(strlen(str), radix)))
+    return MP_MEMORY;
+
+  MP_USED(z) = 1; z->digits[0] = 0;
+
+  while (*str != '\0' && ((ch = s_ch2val(*str, radix)) >= 0)) {
+    s_dmul(z, (mp_digit)radix);
+    s_dadd(z, (mp_digit)ch);
+    ++str;
+  }
+
+  CLAMP(z);
+
+  /* Override sign for zero, even if negative specified. */
+  if (CMPZ(z) == 0)
+    MP_SIGN(z) = MP_ZPOS;
+
+  if (end != NULL)
+    *end = (char *)str;
+
+  /* Return a truncation error if the string has unprocessed characters
+     remaining, so the caller can tell if the whole string was done */
+  if (*str != '\0')
+    return MP_TRUNC;
+  else
+    return MP_OK;
+}
+
+mp_result mp_int_count_bits(mp_int z)
+{
+  mp_size  nbits = 0, uz;
+  mp_digit d;
+
+  CHECK(z != NULL);
+
+  uz = MP_USED(z);
+  if (uz == 1 && z->digits[0] == 0)
+    return 1;
+
+  --uz;
+  nbits = uz * MP_DIGIT_BIT;
+  d = z->digits[uz];
+
+  while (d != 0) {
+    d >>= 1;
+    ++nbits;
+  }
+
+  return nbits;
+}
+
+mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit)
+{
+  static const int PAD_FOR_2C = 1;
+
+  mp_result res;
+  int limpos = limit;
+
+  CHECK(z != NULL && buf != NULL);
+
+  res = s_tobin(z, buf, &limpos, PAD_FOR_2C);
+
+  if (MP_SIGN(z) == MP_NEG)
+    s_2comp(buf, limpos);
+
+  return res;
+}
+
+mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len)
+{
+  mp_size need, i;
+  unsigned char *tmp;
+  mp_digit *dz;
+
+  CHECK(z != NULL && buf != NULL && len > 0);
+
+  /* Figure out how many digits are needed to represent this value */
+  need = ((len * CHAR_BIT) + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT;
+  if (!s_pad(z, need))
+    return MP_MEMORY;
+
+  mp_int_zero(z);
+
+  /* If the high-order bit is set, take the 2's complement before reading the
+     value (it will be restored afterward) */
+  if (buf[0] >> (CHAR_BIT - 1)) {
+    MP_SIGN(z) = MP_NEG;
+    s_2comp(buf, len);
+  }
+
+  dz = MP_DIGITS(z);
+  for (tmp = buf, i = len; i > 0; --i, ++tmp) {
+    s_qmul(z, (mp_size) CHAR_BIT);
+    *dz |= *tmp;
+  }
+
+  /* Restore 2's complement if we took it before */
+  if (MP_SIGN(z) == MP_NEG)
+    s_2comp(buf, len);
+
+  return MP_OK;
+}
+
+mp_result mp_int_binary_len(mp_int z)
+{
+  mp_result  res = mp_int_count_bits(z);
+  int        bytes = mp_int_unsigned_len(z);
+
+  if (res <= 0)
+    return res;
+
+  bytes = (res + (CHAR_BIT - 1)) / CHAR_BIT;
+
+  /* If the highest-order bit falls exactly on a byte boundary, we need to pad
+     with an extra byte so that the sign will be read correctly when reading it
+     back in. */
+  if (bytes * CHAR_BIT == res)
+    ++bytes;
+
+  return bytes;
+}
+
+mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit)
+{
+  static const int NO_PADDING = 0;
+
+  CHECK(z != NULL && buf != NULL);
+
+  return s_tobin(z, buf, &limit, NO_PADDING);
+}
+
+mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len)
+{
+  mp_size need, i;
+  unsigned char *tmp;
+
+  CHECK(z != NULL && buf != NULL && len > 0);
+
+  /* Figure out how many digits are needed to represent this value */
+  need = ((len * CHAR_BIT) + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT;
+  if (!s_pad(z, need))
+    return MP_MEMORY;
+
+  mp_int_zero(z);
+
+  for (tmp = buf, i = len; i > 0; --i, ++tmp) {
+    (void) s_qmul(z, CHAR_BIT);
+    *MP_DIGITS(z) |= *tmp;
+  }
+
+  return MP_OK;
+}
+
+mp_result mp_int_unsigned_len(mp_int z)
+{
+  mp_result  res = mp_int_count_bits(z);
+  int        bytes;
+
+  if (res <= 0)
+    return res;
+
+  bytes = (res + (CHAR_BIT - 1)) / CHAR_BIT;
+
+  return bytes;
+}
+
+const char *mp_error_string(mp_result res)
+{
+  int ix;
+  if (res > 0)
+    return s_unknown_err;
+
+  res = -res;
+  for (ix = 0; ix < res && s_error_msg[ix] != NULL; ++ix)
+    ;
+
+  if (s_error_msg[ix] != NULL)
+    return s_error_msg[ix];
+  else
+    return s_unknown_err;
+}
+
+/*------------------------------------------------------------------------*/
+/* Private functions for internal use.  These make assumptions.           */
+
+STATIC mp_digit *s_alloc(mp_size num)
+{
+  mp_digit *out = malloc(num * sizeof(mp_digit));
+
+  assert(out != NULL); /* for debugging */
+#if DEBUG > 1
+  {
+    mp_digit v = (mp_digit) 0xdeadbeef;
+    int      ix;
+
+    for (ix = 0; ix < num; ++ix)
+      out[ix] = v;
+  }
+#endif
+
+  return out;
+}
+
+STATIC mp_digit *s_realloc(mp_digit *old, mp_size osize, mp_size nsize)
+{
+#if DEBUG > 1
+  mp_digit *new = s_alloc(nsize);
+  int       ix;
+
+  for (ix = 0; ix < nsize; ++ix)
+    new[ix] = (mp_digit) 0xdeadbeef;
+
+  memcpy(new, old, osize * sizeof(mp_digit));
+#else
+  mp_digit *new = realloc(old, nsize * sizeof(mp_digit));
+
+  assert(new != NULL); /* for debugging */
+#endif
+  return new;
+}
+
+STATIC void s_free(void *ptr)
+{
+  free(ptr);
+}
+
+STATIC int      s_pad(mp_int z, mp_size min)
+{
+  if (MP_ALLOC(z) < min) {
+    mp_size nsize = ROUND_PREC(min);
+    mp_digit *tmp;
+
+    if ((void *)z->digits == (void *)z) {
+      if ((tmp = s_alloc(nsize)) == NULL)
+        return 0;
+
+      COPY(MP_DIGITS(z), tmp, MP_USED(z));
+    }
+    else if ((tmp = s_realloc(MP_DIGITS(z), MP_ALLOC(z), nsize)) == NULL)
+      return 0;
+
+    MP_DIGITS(z) = tmp;
+    MP_ALLOC(z) = nsize;
+  }
+
+  return 1;
+}
+
+/* Note: This will not work correctly when value == MP_SMALL_MIN */
+STATIC void      s_fake(mp_int z, mp_small value, mp_digit vbuf[])
+{
+  mp_usmall uv = (mp_usmall) (value < 0) ? -value : value;
+  s_ufake(z, uv, vbuf);
+  if (value < 0)
+    z->sign = MP_NEG;
+}
+
+STATIC void      s_ufake(mp_int z, mp_usmall value, mp_digit vbuf[])
+{
+  mp_size ndig = (mp_size) s_uvpack(value, vbuf);
+
+  z->used = ndig;
+  z->alloc = MP_VALUE_DIGITS(value);
+  z->sign = MP_ZPOS;
+  z->digits = vbuf;
+}
+
+STATIC int      s_cdig(mp_digit *da, mp_digit *db, mp_size len)
+{
+  mp_digit *dat = da + len - 1, *dbt = db + len - 1;
+
+  for (/* */; len != 0; --len, --dat, --dbt) {
+    if (*dat > *dbt)
+      return 1;
+    else if (*dat < *dbt)
+      return -1;
+  }
+
+  return 0;
+}
+
+STATIC int       s_uvpack(mp_usmall uv, mp_digit t[])
+{
+  int ndig = 0;
+
+  if (uv == 0)
+    t[ndig++] = 0;
+  else {
+    while (uv != 0) {
+      t[ndig++] = (mp_digit) uv;
+      uv >>= MP_DIGIT_BIT/2;
+      uv >>= MP_DIGIT_BIT/2;
+    }
+  }
+
+  return ndig;
+}
+
+STATIC int      s_ucmp(mp_int a, mp_int b)
+{
+  mp_size  ua = MP_USED(a), ub = MP_USED(b);
+
+  if (ua > ub)
+    return 1;
+  else if (ub > ua)
+    return -1;
+  else
+    return s_cdig(MP_DIGITS(a), MP_DIGITS(b), ua);
+}
+
+STATIC int      s_vcmp(mp_int a, mp_small v)
+{
+  mp_usmall uv = (v < 0) ? -(mp_usmall) v : (mp_usmall) v;
+  return s_uvcmp(a, uv);
+}
+
+STATIC int      s_uvcmp(mp_int a, mp_usmall uv)
+{
+  mpz_t vtmp;
+  mp_digit vdig[MP_VALUE_DIGITS(uv)];
+
+  s_ufake(&vtmp, uv, vdig);
+  return s_ucmp(a, &vtmp);
+}
+
+STATIC mp_digit s_uadd(mp_digit *da, mp_digit *db, mp_digit *dc,
+		       mp_size size_a, mp_size size_b)
+{
+  mp_size pos;
+  mp_word w = 0;
+
+  /* Insure that da is the longer of the two to simplify later code */
+  if (size_b > size_a) {
+    SWAP(mp_digit *, da, db);
+    SWAP(mp_size, size_a, size_b);
+  }
+
+  /* Add corresponding digits until the shorter number runs out */
+  for (pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) {
+    w = w + (mp_word) *da + (mp_word) *db;
+    *dc = LOWER_HALF(w);
+    w = UPPER_HALF(w);
+  }
+
+  /* Propagate carries as far as necessary */
+  for (/* */; pos < size_a; ++pos, ++da, ++dc) {
+    w = w + *da;
+
+    *dc = LOWER_HALF(w);
+    w = UPPER_HALF(w);
+  }
+
+  /* Return carry out */
+  return (mp_digit)w;
+}
+
+STATIC void     s_usub(mp_digit *da, mp_digit *db, mp_digit *dc,
+		       mp_size size_a, mp_size size_b)
+{
+  mp_size pos;
+  mp_word w = 0;
+
+  /* We assume that |a| >= |b| so this should definitely hold */
+  assert(size_a >= size_b);
+
+  /* Subtract corresponding digits and propagate borrow */
+  for (pos = 0; pos < size_b; ++pos, ++da, ++db, ++dc) {
+    w = ((mp_word)MP_DIGIT_MAX + 1 +  /* MP_RADIX */
+	 (mp_word)*da) - w - (mp_word)*db;
+
+    *dc = LOWER_HALF(w);
+    w = (UPPER_HALF(w) == 0);
+  }
+
+  /* Finish the subtraction for remaining upper digits of da */
+  for (/* */; pos < size_a; ++pos, ++da, ++dc) {
+    w = ((mp_word)MP_DIGIT_MAX + 1 +  /* MP_RADIX */
+	 (mp_word)*da) - w;
+
+    *dc = LOWER_HALF(w);
+    w = (UPPER_HALF(w) == 0);
+  }
+
+  /* If there is a borrow out at the end, it violates the precondition */
+  assert(w == 0);
+}
+
+STATIC int       s_kmul(mp_digit *da, mp_digit *db, mp_digit *dc,
+			mp_size size_a, mp_size size_b)
+{
+  mp_size  bot_size;
+
+  /* Make sure b is the smaller of the two input values */
+  if (size_b > size_a) {
+    SWAP(mp_digit *, da, db);
+    SWAP(mp_size, size_a, size_b);
+  }
+
+  /* Insure that the bottom is the larger half in an odd-length split; the code
+     below relies on this being true.
+   */
+  bot_size = (size_a + 1) / 2;
+
+  /* If the values are big enough to bother with recursion, use the Karatsuba
+     algorithm to compute the product; otherwise use the normal multiplication
+     algorithm
+   */
+  if (multiply_threshold &&
+      size_a >= multiply_threshold &&
+      size_b > bot_size) {
+
+    mp_digit *t1, *t2, *t3, carry;
+
+    mp_digit *a_top = da + bot_size;
+    mp_digit *b_top = db + bot_size;
+
+    mp_size  at_size = size_a - bot_size;
+    mp_size  bt_size = size_b - bot_size;
+    mp_size  buf_size = 2 * bot_size;
+
+    /* Do a single allocation for all three temporary buffers needed; each
+       buffer must be big enough to hold the product of two bottom halves, and
+       one buffer needs space for the completed product; twice the space is
+       plenty.
+     */
+    if ((t1 = s_alloc(4 * buf_size)) == NULL) return 0;
+    t2 = t1 + buf_size;
+    t3 = t2 + buf_size;
+    ZERO(t1, 4 * buf_size);
+
+    /* t1 and t2 are initially used as temporaries to compute the inner product
+       (a1 + a0)(b1 + b0) = a1b1 + a1b0 + a0b1 + a0b0
+     */
+    carry = s_uadd(da, a_top, t1, bot_size, at_size);      /* t1 = a1 + a0 */
+    t1[bot_size] = carry;
+
+    carry = s_uadd(db, b_top, t2, bot_size, bt_size);      /* t2 = b1 + b0 */
+    t2[bot_size] = carry;
+
+    (void) s_kmul(t1, t2, t3, bot_size + 1, bot_size + 1); /* t3 = t1 * t2 */
+
+    /* Now we'll get t1 = a0b0 and t2 = a1b1, and subtract them out so that
+       we're left with only the pieces we want:  t3 = a1b0 + a0b1
+     */
+    ZERO(t1, buf_size);
+    ZERO(t2, buf_size);
+    (void) s_kmul(da, db, t1, bot_size, bot_size);     /* t1 = a0 * b0 */
+    (void) s_kmul(a_top, b_top, t2, at_size, bt_size); /* t2 = a1 * b1 */
+
+    /* Subtract out t1 and t2 to get the inner product */
+    s_usub(t3, t1, t3, buf_size + 2, buf_size);
+    s_usub(t3, t2, t3, buf_size + 2, buf_size);
+
+    /* Assemble the output value */
+    COPY(t1, dc, buf_size);
+    carry = s_uadd(t3, dc + bot_size, dc + bot_size,
+		   buf_size + 1, buf_size);
+    assert(carry == 0);
+
+    carry = s_uadd(t2, dc + 2*bot_size, dc + 2*bot_size,
+		   buf_size, buf_size);
+    assert(carry == 0);
+
+    s_free(t1); /* note t2 and t3 are just internal pointers to t1 */
+  }
+  else {
+    s_umul(da, db, dc, size_a, size_b);
+  }
+
+  return 1;
+}
+
+STATIC void     s_umul(mp_digit *da, mp_digit *db, mp_digit *dc,
+		       mp_size size_a, mp_size size_b)
+{
+  mp_size a, b;
+  mp_word w;
+
+  for (a = 0; a < size_a; ++a, ++dc, ++da) {
+    mp_digit *dct = dc;
+    mp_digit *dbt = db;
+
+    if (*da == 0)
+      continue;
+
+    w = 0;
+    for (b = 0; b < size_b; ++b, ++dbt, ++dct) {
+      w = (mp_word)*da * (mp_word)*dbt + w + (mp_word)*dct;
+
+      *dct = LOWER_HALF(w);
+      w = UPPER_HALF(w);
+    }
+
+    *dct = (mp_digit)w;
+  }
+}
+
+STATIC int       s_ksqr(mp_digit *da, mp_digit *dc, mp_size size_a)
+{
+  if (multiply_threshold && size_a > multiply_threshold) {
+    mp_size  bot_size = (size_a + 1) / 2;
+    mp_digit *a_top = da + bot_size;
+    mp_digit *t1, *t2, *t3, carry;
+    mp_size  at_size = size_a - bot_size;
+    mp_size  buf_size = 2 * bot_size;
+
+    if ((t1 = s_alloc(4 * buf_size)) == NULL) return 0;
+    t2 = t1 + buf_size;
+    t3 = t2 + buf_size;
+    ZERO(t1, 4 * buf_size);
+
+    (void) s_ksqr(da, t1, bot_size);    /* t1 = a0 ^ 2 */
+    (void) s_ksqr(a_top, t2, at_size);  /* t2 = a1 ^ 2 */
+
+    (void) s_kmul(da, a_top, t3, bot_size, at_size);  /* t3 = a0 * a1 */
+
+    /* Quick multiply t3 by 2, shifting left (can't overflow) */
+    {
+      int i, top = bot_size + at_size;
+      mp_word w, save = 0;
+
+      for (i = 0; i < top; ++i) {
+	w = t3[i];
+	w = (w << 1) | save;
+	t3[i] = LOWER_HALF(w);
+	save = UPPER_HALF(w);
+      }
+      t3[i] = LOWER_HALF(save);
+    }
+
+    /* Assemble the output value */
+    COPY(t1, dc, 2 * bot_size);
+    carry = s_uadd(t3, dc + bot_size, dc + bot_size,
+		   buf_size + 1, buf_size);
+    assert(carry == 0);
+
+    carry = s_uadd(t2, dc + 2*bot_size, dc + 2*bot_size,
+		   buf_size, buf_size);
+    assert(carry == 0);
+
+    s_free(t1); /* note that t2 and t2 are internal pointers only */
+
+  } 
+  else {
+    s_usqr(da, dc, size_a);
+  }
+
+  return 1;
+}
+
+STATIC void      s_usqr(mp_digit *da, mp_digit *dc, mp_size size_a)
+{
+  mp_size i, j;
+  mp_word w;
+
+  for (i = 0; i < size_a; ++i, dc += 2, ++da) {
+    mp_digit  *dct = dc, *dat = da;
+
+    if (*da == 0)
+      continue;
+
+    /* Take care of the first digit, no rollover */
+    w = (mp_word)*dat * (mp_word)*dat + (mp_word)*dct;
+    *dct = LOWER_HALF(w);
+    w = UPPER_HALF(w);
+    ++dat; ++dct;
+
+    for (j = i + 1; j < size_a; ++j, ++dat, ++dct) {
+      mp_word  t = (mp_word)*da * (mp_word)*dat;
+      mp_word  u = w + (mp_word)*dct, ov = 0;
+
+      /* Check if doubling t will overflow a word */
+      if (HIGH_BIT_SET(t))
+	ov = 1;
+
+      w = t + t;
+
+      /* Check if adding u to w will overflow a word */
+      if (ADD_WILL_OVERFLOW(w, u))
+	ov = 1;
+
+      w += u;
+
+      *dct = LOWER_HALF(w);
+      w = UPPER_HALF(w);
+      if (ov) {
+	w += MP_DIGIT_MAX; /* MP_RADIX */
+	++w;
+      }
+    }
+
+    w = w + *dct;
+    *dct = (mp_digit)w;
+    while ((w = UPPER_HALF(w)) != 0) {
+      ++dct; w = w + *dct;
+      *dct = LOWER_HALF(w);
+    }
+
+    assert(w == 0);
+  }
+}
+
+STATIC void      s_dadd(mp_int a, mp_digit b)
+{
+  mp_word w = 0;
+  mp_digit *da = MP_DIGITS(a);
+  mp_size ua = MP_USED(a);
+
+  w = (mp_word)*da + b;
+  *da++ = LOWER_HALF(w);
+  w = UPPER_HALF(w);
+
+  for (ua -= 1; ua > 0; --ua, ++da) {
+    w = (mp_word)*da + w;
+
+    *da = LOWER_HALF(w);
+    w = UPPER_HALF(w);
+  }
+
+  if (w) {
+    *da = (mp_digit)w;
+    MP_USED(a) += 1;
+  }
+}
+
+STATIC void      s_dmul(mp_int a, mp_digit b)
+{
+  mp_word w = 0;
+  mp_digit *da = MP_DIGITS(a);
+  mp_size ua = MP_USED(a);
+
+  while (ua > 0) {
+    w = (mp_word)*da * b + w;
+    *da++ = LOWER_HALF(w);
+    w = UPPER_HALF(w);
+    --ua;
+  }
+
+  if (w) {
+    *da = (mp_digit)w;
+    MP_USED(a) += 1;
+  }
+}
+
+STATIC void      s_dbmul(mp_digit *da, mp_digit b, mp_digit *dc, mp_size size_a)
+{
+  mp_word  w = 0;
+
+  while (size_a > 0) {
+    w = (mp_word)*da++ * (mp_word)b + w;
+
+    *dc++ = LOWER_HALF(w);
+    w = UPPER_HALF(w);
+    --size_a;
+  }
+
+  if (w)
+    *dc = LOWER_HALF(w);
+}
+
+STATIC mp_digit  s_ddiv(mp_int a, mp_digit b)
+{
+  mp_word w = 0, qdigit;
+  mp_size ua = MP_USED(a);
+  mp_digit *da = MP_DIGITS(a) + ua - 1;
+
+  for (/* */; ua > 0; --ua, --da) {
+    w = (w << MP_DIGIT_BIT) | *da;
+
+    if (w >= b) {
+      qdigit = w / b;
+      w = w % b;
+    }
+    else {
+      qdigit = 0;
+    }
+
+    *da = (mp_digit)qdigit;
+  }
+
+  CLAMP(a);
+  return (mp_digit)w;
+}
+
+STATIC void     s_qdiv(mp_int z, mp_size p2)
+{
+  mp_size ndig = p2 / MP_DIGIT_BIT, nbits = p2 % MP_DIGIT_BIT;
+  mp_size uz = MP_USED(z);
+
+  if (ndig) {
+    mp_size  mark;
+    mp_digit *to, *from;
+
+    if (ndig >= uz) {
+      mp_int_zero(z);
+      return;
+    }
+
+    to = MP_DIGITS(z); from = to + ndig;
+
+    for (mark = ndig; mark < uz; ++mark)
+      *to++ = *from++;
+
+    MP_USED(z) = uz - ndig;
+  }
+
+  if (nbits) {
+    mp_digit d = 0, *dz, save;
+    mp_size  up = MP_DIGIT_BIT - nbits;
+
+    uz = MP_USED(z);
+    dz = MP_DIGITS(z) + uz - 1;
+
+    for (/* */; uz > 0; --uz, --dz) {
+      save = *dz;
+
+      *dz = (*dz >> nbits) | (d << up);
+      d = save;
+    }
+
+    CLAMP(z);
+  }
+
+  if (MP_USED(z) == 1 && z->digits[0] == 0)
+    MP_SIGN(z) = MP_ZPOS;
+}
+
+STATIC void     s_qmod(mp_int z, mp_size p2)
+{
+  mp_size start = p2 / MP_DIGIT_BIT + 1, rest = p2 % MP_DIGIT_BIT;
+  mp_size uz = MP_USED(z);
+  mp_digit mask = (1u << rest) - 1;
+
+  if (start <= uz) {
+    MP_USED(z) = start;
+    z->digits[start - 1] &= mask;
+    CLAMP(z);
+  }
+}
+
+STATIC int      s_qmul(mp_int z, mp_size p2)
+{
+  mp_size   uz, need, rest, extra, i;
+  mp_digit *from, *to, d;
+
+  if (p2 == 0)
+    return 1;
+
+  uz = MP_USED(z); 
+  need = p2 / MP_DIGIT_BIT; rest = p2 % MP_DIGIT_BIT;
+
+  /* Figure out if we need an extra digit at the top end; this occurs if the
+     topmost `rest' bits of the high-order digit of z are not zero, meaning
+     they will be shifted off the end if not preserved */
+  extra = 0;
+  if (rest != 0) {
+    mp_digit *dz = MP_DIGITS(z) + uz - 1;
+
+    if ((*dz >> (MP_DIGIT_BIT - rest)) != 0)
+      extra = 1;
+  }
+
+  if (!s_pad(z, uz + need + extra))
+    return 0;
+
+  /* If we need to shift by whole digits, do that in one pass, then
+     to back and shift by partial digits.
+   */
+  if (need > 0) {
+    from = MP_DIGITS(z) + uz - 1;
+    to = from + need;
+
+    for (i = 0; i < uz; ++i)
+      *to-- = *from--;
+
+    ZERO(MP_DIGITS(z), need);
+    uz += need;
+  }
+
+  if (rest) {
+    d = 0;
+    for (i = need, from = MP_DIGITS(z) + need; i < uz; ++i, ++from) {
+      mp_digit save = *from;
+      
+      *from = (*from << rest) | (d >> (MP_DIGIT_BIT - rest));
+      d = save;
+    }
+
+    d >>= (MP_DIGIT_BIT - rest);
+    if (d != 0) {
+      *from = d;
+      uz += extra;
+    }
+  }
+
+  MP_USED(z) = uz;
+  CLAMP(z);
+
+  return 1;
+}
+
+/* Compute z = 2^p2 - |z|; requires that 2^p2 >= |z|
+   The sign of the result is always zero/positive.
+ */
+STATIC int       s_qsub(mp_int z, mp_size p2)
+{
+  mp_digit hi = (1 << (p2 % MP_DIGIT_BIT)), *zp;
+  mp_size  tdig = (p2 / MP_DIGIT_BIT), pos;
+  mp_word  w = 0;
+
+  if (!s_pad(z, tdig + 1))
+    return 0;
+
+  for (pos = 0, zp = MP_DIGITS(z); pos < tdig; ++pos, ++zp) {
+    w = ((mp_word) MP_DIGIT_MAX + 1) - w - (mp_word)*zp;
+
+    *zp = LOWER_HALF(w);
+    w = UPPER_HALF(w) ? 0 : 1;
+  }
+
+  w = ((mp_word) MP_DIGIT_MAX + 1 + hi) - w - (mp_word)*zp;
+  *zp = LOWER_HALF(w);
+
+  assert(UPPER_HALF(w) != 0); /* no borrow out should be possible */
+
+  MP_SIGN(z) = MP_ZPOS;
+  CLAMP(z);
+
+  return 1;
+}
+
+STATIC int      s_dp2k(mp_int z)
+{
+  int       k = 0;
+  mp_digit *dp = MP_DIGITS(z), d;
+
+  if (MP_USED(z) == 1 && *dp == 0)
+    return 1;
+
+  while (*dp == 0) {
+    k += MP_DIGIT_BIT;
+    ++dp;
+  }
+
+  d = *dp;
+  while ((d & 1) == 0) {
+    d >>= 1;
+    ++k;
+  }
+
+  return k;
+}
+
+STATIC int       s_isp2(mp_int z)
+{
+  mp_size uz = MP_USED(z), k = 0;
+  mp_digit *dz = MP_DIGITS(z), d;
+
+  while (uz > 1) {
+    if (*dz++ != 0)
+      return -1;
+    k += MP_DIGIT_BIT;
+    --uz;
+  }
+
+  d = *dz;
+  while (d > 1) {
+    if (d & 1)
+      return -1;
+    ++k; d >>= 1;
+  }
+
+  return (int) k;
+}
+
+STATIC int       s_2expt(mp_int z, mp_small k)
+{
+  mp_size  ndig, rest;
+  mp_digit *dz;
+
+  ndig = (k + MP_DIGIT_BIT) / MP_DIGIT_BIT;
+  rest = k % MP_DIGIT_BIT;
+
+  if (!s_pad(z, ndig))
+    return 0;
+
+  dz = MP_DIGITS(z);
+  ZERO(dz, ndig);
+  *(dz + ndig - 1) = (1 << rest);
+  MP_USED(z) = ndig;
+
+  return 1;
+}
+
+STATIC int      s_norm(mp_int a, mp_int b)
+{
+  mp_digit d = b->digits[MP_USED(b) - 1];
+  int k = 0;
+
+  while (d < (1u << (mp_digit)(MP_DIGIT_BIT - 1))) { /* d < (MP_RADIX / 2) */
+    d <<= 1;
+    ++k;
+  }
+
+  /* These multiplications can't fail */
+  if (k != 0) {
+    (void) s_qmul(a, (mp_size) k);
+    (void) s_qmul(b, (mp_size) k);
+  }
+
+  return k;
+}
+
+STATIC mp_result s_brmu(mp_int z, mp_int m)
+{
+  mp_size um = MP_USED(m) * 2;
+
+  if (!s_pad(z, um))
+    return MP_MEMORY;
+
+  s_2expt(z, MP_DIGIT_BIT * um);
+  return mp_int_div(z, m, z, NULL);
+}
+
+STATIC int       s_reduce(mp_int x, mp_int m, mp_int mu, mp_int q1, mp_int q2)
+{
+  mp_size   um = MP_USED(m), umb_p1, umb_m1;
+
+  umb_p1 = (um + 1) * MP_DIGIT_BIT;
+  umb_m1 = (um - 1) * MP_DIGIT_BIT;
+
+  if (mp_int_copy(x, q1) != MP_OK)
+    return 0;
+
+  /* Compute q2 = floor((floor(x / b^(k-1)) * mu) / b^(k+1)) */
+  s_qdiv(q1, umb_m1);
+  UMUL(q1, mu, q2);
+  s_qdiv(q2, umb_p1);
+
+  /* Set x = x mod b^(k+1) */
+  s_qmod(x, umb_p1);
+
+  /* Now, q is a guess for the quotient a / m.
+     Compute x - q * m mod b^(k+1), replacing x.  This may be off
+     by a factor of 2m, but no more than that.
+   */
+  UMUL(q2, m, q1);
+  s_qmod(q1, umb_p1);
+  (void) mp_int_sub(x, q1, x); /* can't fail */
+
+  /* The result may be < 0; if it is, add b^(k+1) to pin it in the proper
+     range. */
+  if ((CMPZ(x) < 0) && !s_qsub(x, umb_p1))
+    return 0;
+
+  /* If x > m, we need to back it off until it is in range.  This will be
+     required at most twice.  */
+  if (mp_int_compare(x, m) >= 0) {
+    (void) mp_int_sub(x, m, x);
+    if (mp_int_compare(x, m) >= 0)
+      (void) mp_int_sub(x, m, x);
+  }
+
+  /* At this point, x has been properly reduced. */
+  return 1;
+}
+
+/* Perform modular exponentiation using Barrett's method, where mu is the
+   reduction constant for m.  Assumes a < m, b > 0. */
+STATIC mp_result s_embar(mp_int a, mp_int b, mp_int m, mp_int mu, mp_int c)
+{
+  mp_digit  *db, *dbt, umu, d;
+  mp_result res;
+  DECLARE_TEMP(3);
+
+  umu = MP_USED(mu); db = MP_DIGITS(b); dbt = db + MP_USED(b) - 1;
+
+  while (last__ < 3) {
+    SETUP(mp_int_init_size(LAST_TEMP(), 4 * umu));
+    ZERO(MP_DIGITS(TEMP(last__ - 1)), MP_ALLOC(TEMP(last__ - 1)));
+  }
+
+  (void) mp_int_set_value(c, 1);
+
+  /* Take care of low-order digits */
+  while (db < dbt) {
+    int      i;
+
+    for (d = *db, i = MP_DIGIT_BIT; i > 0; --i, d >>= 1) {
+      if (d & 1) {
+	/* The use of a second temporary avoids allocation */
+	UMUL(c, a, TEMP(0));
+	if (!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) {
+	  res = MP_MEMORY; goto CLEANUP;
+	}
+	mp_int_copy(TEMP(0), c);
+      }
+
+
+      USQR(a, TEMP(0));
+      assert(MP_SIGN(TEMP(0)) == MP_ZPOS);
+      if (!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) {
+	res = MP_MEMORY; goto CLEANUP;
+      }
+      assert(MP_SIGN(TEMP(0)) == MP_ZPOS);
+      mp_int_copy(TEMP(0), a);
+    }
+
+    ++db;
+  }
+
+  /* Take care of highest-order digit */
+  d = *dbt;
+  for (;;) {
+    if (d & 1) {
+      UMUL(c, a, TEMP(0));
+      if (!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) {
+	res = MP_MEMORY; goto CLEANUP;
+      }
+      mp_int_copy(TEMP(0), c);
+    }
+
+    d >>= 1;
+    if (!d) break;
+
+    USQR(a, TEMP(0));
+    if (!s_reduce(TEMP(0), m, mu, TEMP(1), TEMP(2))) {
+      res = MP_MEMORY; goto CLEANUP;
+    }
+    (void) mp_int_copy(TEMP(0), a);
+  }
+
+  CLEANUP_TEMP();
+  return res;
+}
+
+/* Division of nonnegative integers
+
+   This function implements division algorithm for unsigned multi-precision
+   integers. The algorithm is based on Algorithm D from Knuth's "The Art of
+   Computer Programming", 3rd ed. 1998, pg 272-273.
+
+   We diverge from Knuth's algorithm in that we do not perform the subtraction
+   from the remainder until we have determined that we have the correct
+   quotient digit. This makes our algorithm less efficient that Knuth because
+   we might have to perform multiple multiplication and comparison steps before
+   the subtraction. The advantage is that it is easy to implement and ensure
+   correctness without worrying about underflow from the subtraction.
+
+   inputs: u   a n+m digit integer in base b (b is 2^MP_DIGIT_BIT)
+           v   a n   digit integer in base b (b is 2^MP_DIGIT_BIT)
+           n >= 1
+           m >= 0
+  outputs: u / v stored in u
+           u % v stored in v
+ */
+STATIC mp_result s_udiv_knuth(mp_int u, mp_int v) {
+  mpz_t q, r, t;
+  mp_result
+  res = MP_OK;
+  int k,j;
+  mp_size m,n;
+
+  /* Force signs to positive */
+  MP_SIGN(u) = MP_ZPOS;
+  MP_SIGN(v) = MP_ZPOS;
+
+  /* Use simple division algorithm when v is only one digit long */
+  if (MP_USED(v) == 1) {
+    mp_digit d, rem;
+    d   = v->digits[0];
+    rem = s_ddiv(u, d);
+    mp_int_set_value(v, rem);
+    return MP_OK;
+  }
+
+  /* Algorithm D
+
+     The n and m variables are defined as used by Knuth.
+     u is an n digit number with digits u_{n-1}..u_0.
+     v is an n+m digit number with digits from v_{m+n-1}..v_0.
+     We require that n > 1 and m >= 0
+   */
+  n = MP_USED(v);
+  m = MP_USED(u) - n;
+  assert(n > 1);
+  assert(m >= 0);
+
+  /* D1: Normalize.
+     The normalization step provides the necessary condition for Theorem B,
+     which states that the quotient estimate for q_j, call it qhat
+
+       qhat = u_{j+n}u_{j+n-1} / v_{n-1}
+
+     is bounded by
+
+      qhat - 2 <= q_j <= qhat.
+
+     That is, qhat is always greater than the actual quotient digit q,
+     and it is never more than two larger than the actual quotient digit.
+   */
+  k = s_norm(u, v);
+
+  /* Extend size of u by one if needed.
+
+     The algorithm begins with a value of u that has one more digit of input.
+     The normalization step sets u_{m+n}..u_0 = 2^k * u_{m+n-1}..u_0. If the
+     multiplication did not increase the number of digits of u, we need to add
+     a leading zero here.
+   */
+  if (k == 0 || MP_USED(u) != m + n + 1) {
+    if (!s_pad(u, m+n+1))
+      return MP_MEMORY;
+    u->digits[m+n] = 0;
+    u->used = m+n+1;
+  }
+
+  /* Add a leading 0 to v.
+
+     The multiplication in step D4 multiplies qhat * 0v_{n-1}..v_0.  We need to
+     add the leading zero to v here to ensure that the multiplication will
+     produce the full n+1 digit result.
+   */
+  if (!s_pad(v, n+1)) return MP_MEMORY; v->digits[n] = 0;
+
+  /* Initialize temporary variables q and t.
+     q allocates space for m+1 digits to store the quotient digits
+     t allocates space for n+1 digits to hold the result of q_j*v
+   */
+  if ((res = mp_int_init_size(&q, m + 1)) != MP_OK) return res;
+  if ((res = mp_int_init_size(&t, n + 1)) != MP_OK) goto CLEANUP;
+
+  /* D2: Initialize j */
+  j = m;
+  r.digits = MP_DIGITS(u) + j;  /* The contents of r are shared with u */
+  r.used   = n + 1;
+  r.sign   = MP_ZPOS;
+  r.alloc  = MP_ALLOC(u);
+  ZERO(t.digits, t.alloc);
+
+  /* Calculate the m+1 digits of the quotient result */
+  for (; j >= 0; j--) {
+    /* D3: Calculate q' */
+    /* r->digits is aligned to position j of the number u */
+    mp_word pfx, qhat;
+    pfx   = r.digits[n];
+    pfx <<= MP_DIGIT_BIT / 2;
+    pfx <<= MP_DIGIT_BIT / 2;
+    pfx |= r.digits[n-1]; /* pfx = u_{j+n}{j+n-1} */
+
+    qhat = pfx / v->digits[n-1];
+    /* Check to see if qhat > b, and decrease qhat if so.
+       Theorem B guarantess that qhat is at most 2 larger than the
+       actual value, so it is possible that qhat is greater than
+       the maximum value that will fit in a digit */
+    if (qhat > MP_DIGIT_MAX)
+      qhat = MP_DIGIT_MAX;
+
+    /* D4,D5,D6: Multiply qhat * v and test for a correct value of q
+
+       We proceed a bit different than the way described by Knuth. This way is
+       simpler but less efficent. Instead of doing the multiply and subtract
+       then checking for underflow, we first do the multiply of qhat * v and
+       see if it is larger than the current remainder r. If it is larger, we
+       decrease qhat by one and try again. We may need to decrease qhat one
+       more time before we get a value that is smaller than r.
+
+       This way is less efficent than Knuth becuase we do more multiplies, but
+       we do not need to worry about underflow this way.
+     */
+    /* t = qhat * v */
+    s_dbmul(MP_DIGITS(v), (mp_digit) qhat, t.digits, n+1); t.used = n + 1;
+    CLAMP(&t);
+
+    /* Clamp r for the comparison. Comparisons do not like leading zeros. */
+    CLAMP(&r);
+    if (s_ucmp(&t, &r) > 0) {   /* would the remainder be negative? */
+      qhat -= 1;   /* try a smaller q */
+      s_dbmul(MP_DIGITS(v), (mp_digit) qhat, t.digits, n+1);
+      t.used = n + 1; CLAMP(&t);
+      if (s_ucmp(&t, &r) > 0) { /* would the remainder be negative? */
+        assert(qhat > 0);
+        qhat -= 1; /* try a smaller q */
+        s_dbmul(MP_DIGITS(v), (mp_digit) qhat, t.digits, n+1);
+        t.used = n + 1; CLAMP(&t);
+      }
+      assert(s_ucmp(&t, &r) <=  0 && "The mathematics failed us.");
+    }
+    /* Unclamp r. The D algorithm expects r = u_{j+n}..u_j to always be n+1
+       digits long. */
+    r.used = n + 1;
+
+    /* D4: Multiply and subtract
+
+       Note: The multiply was completed above so we only need to subtract here.
+     */
+    s_usub(r.digits, t.digits, r.digits, r.used, t.used);
+
+    /* D5: Test remainder
+
+       Note: Not needed because we always check that qhat is the correct value
+             before performing the subtract.  Value cast to mp_digit to prevent
+             warning, qhat has been clamped to MP_DIGIT_MAX
+     */
+    q.digits[j] = (mp_digit)qhat;
+
+    /* D6: Add back
+       Note: Not needed because we always check that qhat is the correct value
+             before performing the subtract.
+     */
+
+    /* D7: Loop on j */
+    r.digits--;
+    ZERO(t.digits, t.alloc);
+  }
+
+  /* Get rid of leading zeros in q */
+  q.used = m + 1;
+  CLAMP(&q);
+
+  /* Denormalize the remainder */
+  CLAMP(u); /* use u here because the r.digits pointer is off-by-one */
+  if (k != 0)
+    s_qdiv(u, k);
+
+  mp_int_copy(u, v);  /* ok:  0 <= r < v */
+  mp_int_copy(&q, u); /* ok:  q <= u     */
+
+  mp_int_clear(&t);
+ CLEANUP:
+  mp_int_clear(&q);
+  return res;
+}
+
+STATIC int       s_outlen(mp_int z, mp_size r)
+{
+  mp_result bits;
+  double raw;
+
+  assert(r >= MP_MIN_RADIX && r <= MP_MAX_RADIX);
+
+  bits = mp_int_count_bits(z);
+  raw = (double)bits * s_log2[r];
+
+  return (int)(raw + 0.999999);
+}
+
+STATIC mp_size   s_inlen(int len, mp_size r)
+{
+  double  raw = (double)len / s_log2[r];
+  mp_size bits = (mp_size)(raw + 0.5);
+
+  return (mp_size)((bits + (MP_DIGIT_BIT - 1)) / MP_DIGIT_BIT) + 1;
+}
+
+STATIC int       s_ch2val(char c, int r)
+{
+  int out;
+
+  if (isdigit((unsigned char) c))
+    out = c - '0';
+  else if (r > 10 && isalpha((unsigned char) c))
+    out = toupper(c) - 'A' + 10;
+  else
+    return -1;
+
+  return (out >= r) ? -1 : out;
+}
+
+STATIC char      s_val2ch(int v, int caps)
+{
+  assert(v >= 0);
+
+  if (v < 10)
+    return v + '0';
+  else {
+    char out = (v - 10) + 'a';
+
+    if (caps)
+      return toupper(out);
+    else
+      return out;
+  }
+}
+
+STATIC void      s_2comp(unsigned char *buf, int len)
+{
+  int i;
+  unsigned short s = 1;
+
+  for (i = len - 1; i >= 0; --i) {
+    unsigned char c = ~buf[i];
+
+    s = c + s;
+    c = s & UCHAR_MAX;
+    s >>= CHAR_BIT;
+
+    buf[i] = c;
+  }
+
+  /* last carry out is ignored */
+}
+
+STATIC mp_result s_tobin(mp_int z, unsigned char *buf, int *limpos, int pad)
+{
+  mp_size uz;
+  mp_digit *dz;
+  int pos = 0, limit = *limpos;
+
+  uz = MP_USED(z); dz = MP_DIGITS(z);
+  while (uz > 0 && pos < limit) {
+    mp_digit d = *dz++;
+    int i;
+
+    for (i = sizeof(mp_digit); i > 0 && pos < limit; --i) {
+      buf[pos++] = (unsigned char)d;
+      d >>= CHAR_BIT;
+
+      /* Don't write leading zeroes */
+      if (d == 0 && uz == 1)
+	i = 0; /* exit loop without signaling truncation */
+    }
+
+    /* Detect truncation (loop exited with pos >= limit) */
+    if (i > 0) break;
+
+    --uz;
+  }
+
+  if (pad != 0 && (buf[pos - 1] >> (CHAR_BIT - 1))) {
+    if (pos < limit)
+      buf[pos++] = 0;
+    else
+      uz = 1;
+  }
+
+  /* Digits are in reverse order, fix that */
+  REV(unsigned char, buf, pos);
+
+  /* Return the number of bytes actually written */
+  *limpos = pos;
+
+  return (uz == 0) ? MP_OK : MP_TRUNC;
+}
+
+#if DEBUG
+void      s_print(char *tag, mp_int z)
+{
+  int  i;
+
+  fprintf(stderr, "%s: %c ", tag,
+	  (MP_SIGN(z) == MP_NEG) ? '-' : '+');
+
+  for (i = MP_USED(z) - 1; i >= 0; --i)
+    fprintf(stderr, "%0*X", (int)(MP_DIGIT_BIT / 4), z->digits[i]);
+
+  fputc('\n', stderr);
+
+}
+
+void      s_print_buf(char *tag, mp_digit *buf, mp_size num)
+{
+  int i;
+
+  fprintf(stderr, "%s: ", tag);
+
+  for (i = num - 1; i >= 0; --i)
+    fprintf(stderr, "%0*X", (int)(MP_DIGIT_BIT / 4), buf[i]);
+
+  fputc('\n', stderr);
+}
+#endif
+
+/* Here there be dragons */
diff --git a/final/lib/External/isl/imath/imath.h b/final/lib/External/isl/imath/imath.h
new file mode 100644
index 0000000..a9f5e40
--- /dev/null
+++ b/final/lib/External/isl/imath/imath.h
@@ -0,0 +1,232 @@
+/*
+  Name:     imath.h
+  Purpose:  Arbitrary precision integer arithmetic routines.
+  Author:   M. J. Fromberger <http://spinning-yarns.org/michael/>
+
+  Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved.
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+ */
+
+#ifndef IMATH_H_
+#define IMATH_H_
+
+#include <stdint.h>
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned char      mp_sign;
+typedef unsigned int       mp_size;
+typedef int                mp_result;
+typedef long               mp_small;  /* must be a signed type */
+typedef unsigned long      mp_usmall; /* must be an unsigned type */
+
+/* Force building with uint64_t so that the library builds consistently
+ * whether we build from the makefile or by embedding imath in another project.
+ */
+#undef  USE_64BIT_WORDS
+#define USE_64BIT_WORDS
+#ifdef  USE_64BIT_WORDS
+typedef uint32_t           mp_digit;
+typedef uint64_t           mp_word;
+#else
+typedef uint16_t           mp_digit;
+typedef uint32_t           mp_word;
+#endif
+
+typedef struct mpz {
+  mp_digit    single;
+  mp_digit   *digits;
+  mp_size     alloc;
+  mp_size     used;
+  mp_sign     sign;
+} mpz_t, *mp_int;
+
+#define MP_DIGITS(Z) ((Z)->digits)
+#define MP_ALLOC(Z)  ((Z)->alloc)
+#define MP_USED(Z)   ((Z)->used)
+#define MP_SIGN(Z)   ((Z)->sign)
+
+extern const mp_result MP_OK;
+extern const mp_result MP_FALSE;
+extern const mp_result MP_TRUE;
+extern const mp_result MP_MEMORY;
+extern const mp_result MP_RANGE;
+extern const mp_result MP_UNDEF;
+extern const mp_result MP_TRUNC;
+extern const mp_result MP_BADARG;
+extern const mp_result MP_MINERR;
+
+#define MP_DIGIT_BIT    (sizeof(mp_digit) * CHAR_BIT)
+#define MP_WORD_BIT     (sizeof(mp_word) * CHAR_BIT)
+#define MP_SMALL_MIN    LONG_MIN
+#define MP_SMALL_MAX    LONG_MAX
+#define MP_USMALL_MIN   ULONG_MIN
+#define MP_USMALL_MAX   ULONG_MAX
+
+#ifdef USE_64BIT_WORDS
+#  define MP_DIGIT_MAX   (UINT32_MAX * UINT64_C(1))
+#  define MP_WORD_MAX    (UINT64_MAX)
+#else
+#  define MP_DIGIT_MAX   (UINT16_MAX * 1UL)
+#  define MP_WORD_MAX    (UINT32_MAX * 1UL)
+#endif
+
+#define MP_MIN_RADIX    2
+#define MP_MAX_RADIX    36
+
+/* Values with fewer than this many significant digits use the standard
+   multiplication algorithm; otherwise, a recursive algorithm is used.  
+   Choose a value to suit your platform.
+ */
+#define MP_MULT_THRESH  22
+
+#define MP_DEFAULT_PREC 8   /* default memory allocation, in digits */
+
+extern const mp_sign   MP_NEG;
+extern const mp_sign   MP_ZPOS;
+
+#define mp_int_is_odd(Z)  ((Z)->digits[0] & 1)
+#define mp_int_is_even(Z) !((Z)->digits[0] & 1)
+
+mp_result mp_int_init(mp_int z);
+mp_int    mp_int_alloc(void);
+mp_result mp_int_init_size(mp_int z, mp_size prec);
+mp_result mp_int_init_copy(mp_int z, mp_int old);
+mp_result mp_int_init_value(mp_int z, mp_small value);
+mp_result mp_int_init_uvalue(mp_int z, mp_usmall uvalue);
+mp_result mp_int_set_value(mp_int z, mp_small value);
+mp_result mp_int_set_uvalue(mp_int z, mp_usmall uvalue);
+void      mp_int_clear(mp_int z);
+void      mp_int_free(mp_int z);
+
+mp_result mp_int_copy(mp_int a, mp_int c);           /* c = a     */
+void      mp_int_swap(mp_int a, mp_int c);           /* swap a, c */
+void      mp_int_zero(mp_int z);                     /* z = 0     */
+mp_result mp_int_abs(mp_int a, mp_int c);            /* c = |a|   */
+mp_result mp_int_neg(mp_int a, mp_int c);            /* c = -a    */
+mp_result mp_int_add(mp_int a, mp_int b, mp_int c);  /* c = a + b */
+mp_result mp_int_add_value(mp_int a, mp_small value, mp_int c);
+mp_result mp_int_sub(mp_int a, mp_int b, mp_int c);  /* c = a - b */
+mp_result mp_int_sub_value(mp_int a, mp_small value, mp_int c);
+mp_result mp_int_mul(mp_int a, mp_int b, mp_int c);  /* c = a * b */
+mp_result mp_int_mul_value(mp_int a, mp_small value, mp_int c);
+mp_result mp_int_mul_pow2(mp_int a, mp_small p2, mp_int c);
+mp_result mp_int_sqr(mp_int a, mp_int c);            /* c = a * a */
+mp_result mp_int_div(mp_int a, mp_int b,             /* q = a / b */
+		     mp_int q, mp_int r);            /* r = a % b */
+mp_result mp_int_div_value(mp_int a, mp_small value, /* q = a / value */
+			   mp_int q, mp_small *r);   /* r = a % value */
+mp_result mp_int_div_pow2(mp_int a, mp_small p2,     /* q = a / 2^p2  */
+			  mp_int q, mp_int r);       /* r = q % 2^p2  */
+mp_result mp_int_mod(mp_int a, mp_int m, mp_int c);  /* c = a % m */
+#define   mp_int_mod_value(A, V, R) mp_int_div_value((A), (V), 0, (R))
+mp_result mp_int_expt(mp_int a, mp_small b, mp_int c);         /* c = a^b */
+mp_result mp_int_expt_value(mp_small a, mp_small b, mp_int c); /* c = a^b */
+mp_result mp_int_expt_full(mp_int a, mp_int b, mp_int c);      /* c = a^b */
+
+int       mp_int_compare(mp_int a, mp_int b);          /* a <=> b     */
+int       mp_int_compare_unsigned(mp_int a, mp_int b); /* |a| <=> |b| */
+int       mp_int_compare_zero(mp_int z);                 /* a <=> 0  */
+int       mp_int_compare_value(mp_int z, mp_small v);    /* a <=> v  */
+int       mp_int_compare_uvalue(mp_int z, mp_usmall uv); /* a <=> uv */
+
+/* Returns true if v|a, false otherwise (including errors) */
+int       mp_int_divisible_value(mp_int a, mp_small v);
+
+/* Returns k >= 0 such that z = 2^k, if one exists; otherwise < 0 */
+int       mp_int_is_pow2(mp_int z);
+
+mp_result mp_int_exptmod(mp_int a, mp_int b, mp_int m,
+			 mp_int c);                    /* c = a^b (mod m) */
+mp_result mp_int_exptmod_evalue(mp_int a, mp_small value,
+				mp_int m, mp_int c);   /* c = a^v (mod m) */
+mp_result mp_int_exptmod_bvalue(mp_small value, mp_int b,
+				mp_int m, mp_int c);   /* c = v^b (mod m) */
+mp_result mp_int_exptmod_known(mp_int a, mp_int b,
+			       mp_int m, mp_int mu,
+			       mp_int c);              /* c = a^b (mod m) */
+mp_result mp_int_redux_const(mp_int m, mp_int c);
+
+mp_result mp_int_invmod(mp_int a, mp_int m, mp_int c); /* c = 1/a (mod m) */
+
+mp_result mp_int_gcd(mp_int a, mp_int b, mp_int c);    /* c = gcd(a, b)   */
+
+mp_result mp_int_egcd(mp_int a, mp_int b, mp_int c,    /* c = gcd(a, b)   */
+		      mp_int x, mp_int y);             /* c = ax + by     */
+
+mp_result mp_int_lcm(mp_int a, mp_int b, mp_int c);    /* c = lcm(a, b)   */
+
+mp_result mp_int_root(mp_int a, mp_small b, mp_int c); /* c = floor(a^{1/b}) */
+#define   mp_int_sqrt(a, c) mp_int_root(a, 2, c)       /* c = floor(sqrt(a)) */
+
+/* Convert to a small int, if representable; else MP_RANGE */
+mp_result mp_int_to_int(mp_int z, mp_small *out);
+mp_result mp_int_to_uint(mp_int z, mp_usmall *out);
+
+/* Convert to nul-terminated string with the specified radix, writing at
+   most limit characters including the nul terminator  */
+mp_result mp_int_to_string(mp_int z, mp_size radix,
+			   char *str, int limit);
+
+/* Return the number of characters required to represent
+   z in the given radix.  May over-estimate. */
+mp_result mp_int_string_len(mp_int z, mp_size radix);
+
+/* Read zero-terminated string into z */
+mp_result mp_int_read_string(mp_int z, mp_size radix, const char *str);
+mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str,
+			      char **end);
+
+/* Return the number of significant bits in z */
+mp_result mp_int_count_bits(mp_int z);
+
+/* Convert z to two's complement binary, writing at most limit bytes */
+mp_result mp_int_to_binary(mp_int z, unsigned char *buf, int limit);
+
+/* Read a two's complement binary value into z from the given buffer */
+mp_result mp_int_read_binary(mp_int z, unsigned char *buf, int len);
+
+/* Return the number of bytes required to represent z in binary. */
+mp_result mp_int_binary_len(mp_int z);
+
+/* Convert z to unsigned binary, writing at most limit bytes */
+mp_result mp_int_to_unsigned(mp_int z, unsigned char *buf, int limit);
+
+/* Read an unsigned binary value into z from the given buffer */
+mp_result mp_int_read_unsigned(mp_int z, unsigned char *buf, int len);
+
+/* Return the number of bytes required to represent z as unsigned output */
+mp_result mp_int_unsigned_len(mp_int z);
+
+/* Return a statically allocated string describing error code res */
+const char *mp_error_string(mp_result res);
+
+#if DEBUG
+void      s_print(char *tag, mp_int z);
+void      s_print_buf(char *tag, mp_digit *buf, mp_size num);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* end IMATH_H_ */
diff --git a/final/lib/External/isl/imath/imrat.c b/final/lib/External/isl/imath/imrat.c
new file mode 100644
index 0000000..49448fe
--- /dev/null
+++ b/final/lib/External/isl/imath/imrat.c
@@ -0,0 +1,958 @@
+/*
+  Name:     imrat.c
+  Purpose:  Arbitrary precision rational arithmetic routines.
+  Author:   M. J. Fromberger <http://spinning-yarns.org/michael/>
+
+  Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved.
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+ */
+
+#include "imrat.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#define TEMP(K) (temp + (K))
+#define SETUP(E, C) \
+do{if((res = (E)) != MP_OK) goto CLEANUP; ++(C);}while(0)
+
+/* Argument checking:
+   Use CHECK() where a return value is required; NRCHECK() elsewhere */
+#define CHECK(TEST)   assert(TEST)
+#define NRCHECK(TEST) assert(TEST)
+
+/* Reduce the given rational, in place, to lowest terms and canonical form.
+   Zero is represented as 0/1, one as 1/1.  Signs are adjusted so that the sign
+   of the numerator is definitive. */
+static mp_result s_rat_reduce(mp_rat r);
+
+/* Common code for addition and subtraction operations on rationals. */
+static mp_result s_rat_combine(mp_rat a, mp_rat b, mp_rat c,
+			       mp_result (*comb_f)(mp_int, mp_int, mp_int));
+
+mp_result mp_rat_init(mp_rat r)
+{
+  mp_result res;
+
+  if ((res = mp_int_init(MP_NUMER_P(r))) != MP_OK)
+    return res;
+  if ((res = mp_int_init(MP_DENOM_P(r))) != MP_OK) {
+    mp_int_clear(MP_NUMER_P(r));
+    return res;
+  }
+
+  return mp_int_set_value(MP_DENOM_P(r), 1);
+}
+
+mp_rat mp_rat_alloc(void)
+{
+  mp_rat out = malloc(sizeof(*out));
+
+  if (out != NULL) {
+    if (mp_rat_init(out) != MP_OK) {
+      free(out);
+      return NULL;
+    }
+  }
+
+  return out;
+}
+
+mp_result mp_rat_reduce(mp_rat r) {
+  return s_rat_reduce(r);
+}
+
+mp_result mp_rat_init_size(mp_rat r, mp_size n_prec, mp_size d_prec)
+{
+  mp_result res;
+
+  if ((res = mp_int_init_size(MP_NUMER_P(r), n_prec)) != MP_OK)
+    return res;
+  if ((res = mp_int_init_size(MP_DENOM_P(r), d_prec)) != MP_OK) {
+    mp_int_clear(MP_NUMER_P(r));
+    return res;
+  }
+  
+  return mp_int_set_value(MP_DENOM_P(r), 1);
+}
+
+mp_result mp_rat_init_copy(mp_rat r, mp_rat old)
+{
+  mp_result res;
+
+  if ((res = mp_int_init_copy(MP_NUMER_P(r), MP_NUMER_P(old))) != MP_OK)
+    return res;
+  if ((res = mp_int_init_copy(MP_DENOM_P(r), MP_DENOM_P(old))) != MP_OK) 
+    mp_int_clear(MP_NUMER_P(r));
+  
+  return res;
+}
+
+mp_result mp_rat_set_value(mp_rat r, mp_small numer, mp_small denom)
+{
+  mp_result res;
+
+  if (denom == 0)
+    return MP_UNDEF;
+
+  if ((res = mp_int_set_value(MP_NUMER_P(r), numer)) != MP_OK)
+    return res;
+  if ((res = mp_int_set_value(MP_DENOM_P(r), denom)) != MP_OK)
+    return res;
+
+  return s_rat_reduce(r);
+}
+
+mp_result mp_rat_set_uvalue(mp_rat r, mp_usmall numer, mp_usmall denom)
+{
+  mp_result res;
+
+  if (denom == 0)
+    return MP_UNDEF;
+
+  if ((res = mp_int_set_uvalue(MP_NUMER_P(r), numer)) != MP_OK)
+    return res;
+  if ((res = mp_int_set_uvalue(MP_DENOM_P(r), denom)) != MP_OK)
+    return res;
+
+  return s_rat_reduce(r);
+}
+
+void      mp_rat_clear(mp_rat r)
+{
+  mp_int_clear(MP_NUMER_P(r));
+  mp_int_clear(MP_DENOM_P(r));
+
+}
+
+void      mp_rat_free(mp_rat r)
+{
+  NRCHECK(r != NULL);
+  
+  if (r->num.digits != NULL)
+    mp_rat_clear(r);
+
+  free(r);
+}
+
+mp_result mp_rat_numer(mp_rat r, mp_int z)
+{
+  return mp_int_copy(MP_NUMER_P(r), z);
+}
+
+mp_int mp_rat_numer_ref(mp_rat r)
+{
+  return MP_NUMER_P(r);
+}
+
+
+mp_result mp_rat_denom(mp_rat r, mp_int z)
+{
+  return mp_int_copy(MP_DENOM_P(r), z);
+}
+
+mp_int    mp_rat_denom_ref(mp_rat r)
+{
+  return MP_DENOM_P(r);
+}
+
+mp_sign   mp_rat_sign(mp_rat r)
+{
+  return MP_SIGN(MP_NUMER_P(r));
+}
+
+mp_result mp_rat_copy(mp_rat a, mp_rat c)
+{
+  mp_result res;
+
+  if ((res = mp_int_copy(MP_NUMER_P(a), MP_NUMER_P(c))) != MP_OK)
+    return res;
+  
+  res = mp_int_copy(MP_DENOM_P(a), MP_DENOM_P(c));
+  return res;
+}
+
+void      mp_rat_zero(mp_rat r)
+{
+  mp_int_zero(MP_NUMER_P(r));
+  mp_int_set_value(MP_DENOM_P(r), 1);
+  
+}
+
+mp_result mp_rat_abs(mp_rat a, mp_rat c)
+{
+  mp_result res;
+
+  if ((res = mp_int_abs(MP_NUMER_P(a), MP_NUMER_P(c))) != MP_OK)
+    return res;
+  
+  res = mp_int_abs(MP_DENOM_P(a), MP_DENOM_P(c));
+  return res;
+}
+
+mp_result mp_rat_neg(mp_rat a, mp_rat c)
+{
+  mp_result res;
+
+  if ((res = mp_int_neg(MP_NUMER_P(a), MP_NUMER_P(c))) != MP_OK)
+    return res;
+
+  res = mp_int_copy(MP_DENOM_P(a), MP_DENOM_P(c));
+  return res;
+}
+
+mp_result mp_rat_recip(mp_rat a, mp_rat c)
+{
+  mp_result res;
+
+  if (mp_rat_compare_zero(a) == 0)
+    return MP_UNDEF;
+
+  if ((res = mp_rat_copy(a, c)) != MP_OK)
+    return res;
+
+  mp_int_swap(MP_NUMER_P(c), MP_DENOM_P(c));
+
+  /* Restore the signs of the swapped elements */
+  {
+    mp_sign tmp = MP_SIGN(MP_NUMER_P(c));
+
+    MP_SIGN(MP_NUMER_P(c)) = MP_SIGN(MP_DENOM_P(c));
+    MP_SIGN(MP_DENOM_P(c)) = tmp;
+  }
+
+  return MP_OK;
+}
+
+mp_result mp_rat_add(mp_rat a, mp_rat b, mp_rat c)
+{
+  return s_rat_combine(a, b, c, mp_int_add);
+
+}
+
+mp_result mp_rat_sub(mp_rat a, mp_rat b, mp_rat c)
+{
+  return s_rat_combine(a, b, c, mp_int_sub);
+
+}
+
+mp_result mp_rat_mul(mp_rat a, mp_rat b, mp_rat c)
+{
+  mp_result res;
+
+  if ((res = mp_int_mul(MP_NUMER_P(a), MP_NUMER_P(b), MP_NUMER_P(c))) != MP_OK)
+    return res;
+
+  if (mp_int_compare_zero(MP_NUMER_P(c)) != 0) {
+    if ((res = mp_int_mul(MP_DENOM_P(a), MP_DENOM_P(b), MP_DENOM_P(c))) != MP_OK)
+      return res;
+  }
+
+  return s_rat_reduce(c);
+}
+
+mp_result mp_rat_div(mp_rat a, mp_rat b, mp_rat c)
+{
+  mp_result res = MP_OK;
+
+  if (mp_rat_compare_zero(b) == 0)
+    return MP_UNDEF;
+
+  if (c == a || c == b) {
+    mpz_t tmp;
+
+    if ((res = mp_int_init(&tmp)) != MP_OK) return res;
+    if ((res = mp_int_mul(MP_NUMER_P(a), MP_DENOM_P(b), &tmp)) != MP_OK) 
+      goto CLEANUP;
+    if ((res = mp_int_mul(MP_DENOM_P(a), MP_NUMER_P(b), MP_DENOM_P(c))) != MP_OK)
+      goto CLEANUP;
+    res = mp_int_copy(&tmp, MP_NUMER_P(c));
+
+  CLEANUP:
+    mp_int_clear(&tmp);
+  }
+  else {
+    if ((res = mp_int_mul(MP_NUMER_P(a), MP_DENOM_P(b), MP_NUMER_P(c))) != MP_OK)
+      return res;
+    if ((res = mp_int_mul(MP_DENOM_P(a), MP_NUMER_P(b), MP_DENOM_P(c))) != MP_OK)
+      return res;
+  }
+
+  if (res != MP_OK)
+    return res;
+  else
+    return s_rat_reduce(c);
+}
+
+mp_result mp_rat_add_int(mp_rat a, mp_int b, mp_rat c)
+{
+  mpz_t tmp;
+  mp_result res;
+
+  if ((res = mp_int_init_copy(&tmp, b)) != MP_OK)
+    return res;
+
+  if ((res = mp_int_mul(&tmp, MP_DENOM_P(a), &tmp)) != MP_OK)
+    goto CLEANUP;
+
+  if ((res = mp_rat_copy(a, c)) != MP_OK)
+    goto CLEANUP;
+
+  if ((res = mp_int_add(MP_NUMER_P(c), &tmp, MP_NUMER_P(c))) != MP_OK)
+    goto CLEANUP;
+
+  res = s_rat_reduce(c);
+
+ CLEANUP:
+  mp_int_clear(&tmp);
+  return res;
+}
+
+mp_result mp_rat_sub_int(mp_rat a, mp_int b, mp_rat c)
+{
+  mpz_t tmp;
+  mp_result res;
+
+  if ((res = mp_int_init_copy(&tmp, b)) != MP_OK)
+    return res;
+
+  if ((res = mp_int_mul(&tmp, MP_DENOM_P(a), &tmp)) != MP_OK)
+    goto CLEANUP;
+
+  if ((res = mp_rat_copy(a, c)) != MP_OK)
+    goto CLEANUP;
+
+  if ((res = mp_int_sub(MP_NUMER_P(c), &tmp, MP_NUMER_P(c))) != MP_OK)
+    goto CLEANUP;
+
+  res = s_rat_reduce(c);
+
+ CLEANUP:
+  mp_int_clear(&tmp);
+  return res;
+}
+
+mp_result mp_rat_mul_int(mp_rat a, mp_int b, mp_rat c)
+{
+  mp_result res;
+
+  if ((res = mp_rat_copy(a, c)) != MP_OK)
+    return res;
+
+  if ((res = mp_int_mul(MP_NUMER_P(c), b, MP_NUMER_P(c))) != MP_OK)
+    return res;
+
+  return s_rat_reduce(c);
+}
+
+mp_result mp_rat_div_int(mp_rat a, mp_int b, mp_rat c)
+{
+  mp_result res;
+
+  if (mp_int_compare_zero(b) == 0)
+    return MP_UNDEF;
+
+  if ((res = mp_rat_copy(a, c)) != MP_OK)
+    return res;
+
+  if ((res = mp_int_mul(MP_DENOM_P(c), b, MP_DENOM_P(c))) != MP_OK)
+    return res;
+
+  return s_rat_reduce(c);
+}
+
+mp_result mp_rat_expt(mp_rat a, mp_small b, mp_rat c)
+{
+  mp_result  res;
+
+  /* Special cases for easy powers. */
+  if (b == 0)
+    return mp_rat_set_value(c, 1, 1);
+  else if(b == 1)
+    return mp_rat_copy(a, c);
+
+  /* Since rationals are always stored in lowest terms, it is not necessary to
+     reduce again when raising to an integer power. */
+  if ((res = mp_int_expt(MP_NUMER_P(a), b, MP_NUMER_P(c))) != MP_OK)
+    return res;
+
+  return mp_int_expt(MP_DENOM_P(a), b, MP_DENOM_P(c));
+}
+
+int       mp_rat_compare(mp_rat a, mp_rat b)
+{
+  /* Quick check for opposite signs.  Works because the sign of the numerator
+     is always definitive. */
+  if (MP_SIGN(MP_NUMER_P(a)) != MP_SIGN(MP_NUMER_P(b))) {
+    if (MP_SIGN(MP_NUMER_P(a)) == MP_ZPOS)
+      return 1;
+    else
+      return -1;
+  }
+  else {
+    /* Compare absolute magnitudes; if both are positive, the answer stands,
+       otherwise it needs to be reflected about zero. */
+    int cmp = mp_rat_compare_unsigned(a, b);
+
+    if (MP_SIGN(MP_NUMER_P(a)) == MP_ZPOS)
+      return cmp;
+    else
+      return -cmp;
+  }
+}
+
+int       mp_rat_compare_unsigned(mp_rat a, mp_rat b)
+{
+  /* If the denominators are equal, we can quickly compare numerators without
+     multiplying.  Otherwise, we actually have to do some work. */
+  if (mp_int_compare_unsigned(MP_DENOM_P(a), MP_DENOM_P(b)) == 0)
+    return mp_int_compare_unsigned(MP_NUMER_P(a), MP_NUMER_P(b));
+
+  else {
+    mpz_t  temp[2];
+    mp_result res;
+    int  cmp = INT_MAX, last = 0;
+
+    /* t0 = num(a) * den(b), t1 = num(b) * den(a) */
+    SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(a)), last);
+    SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(b)), last);
+
+    if ((res = mp_int_mul(TEMP(0), MP_DENOM_P(b), TEMP(0))) != MP_OK ||
+	(res = mp_int_mul(TEMP(1), MP_DENOM_P(a), TEMP(1))) != MP_OK)
+      goto CLEANUP;
+    
+    cmp = mp_int_compare_unsigned(TEMP(0), TEMP(1));
+    
+  CLEANUP:
+    while (--last >= 0)
+      mp_int_clear(TEMP(last));
+
+    return cmp;
+  }
+}
+
+int       mp_rat_compare_zero(mp_rat r)
+{
+  return mp_int_compare_zero(MP_NUMER_P(r));
+}
+
+int       mp_rat_compare_value(mp_rat r, mp_small n, mp_small d)
+{
+  mpq_t tmp;
+  mp_result res;
+  int  out = INT_MAX;
+
+  if ((res = mp_rat_init(&tmp)) != MP_OK)
+    return out;
+  if ((res = mp_rat_set_value(&tmp, n, d)) != MP_OK)
+    goto CLEANUP;
+  
+  out = mp_rat_compare(r, &tmp);
+  
+ CLEANUP:
+  mp_rat_clear(&tmp);
+  return out;
+}
+
+int       mp_rat_is_integer(mp_rat r)
+{
+  return (mp_int_compare_value(MP_DENOM_P(r), 1) == 0);
+}
+
+mp_result mp_rat_to_ints(mp_rat r, mp_small *num, mp_small *den)
+{
+  mp_result res;
+
+  if ((res = mp_int_to_int(MP_NUMER_P(r), num)) != MP_OK)
+    return res;
+
+  res = mp_int_to_int(MP_DENOM_P(r), den);
+  return res;
+}
+
+mp_result mp_rat_to_string(mp_rat r, mp_size radix, char *str, int limit)
+{
+  char *start;
+  int   len;
+  mp_result res;
+
+  /* Write the numerator.  The sign of the rational number is written by the
+     underlying integer implementation. */
+  if ((res = mp_int_to_string(MP_NUMER_P(r), radix, str, limit)) != MP_OK)
+    return res;
+
+  /* If the value is zero, don't bother writing any denominator */
+  if (mp_int_compare_zero(MP_NUMER_P(r)) == 0)
+    return MP_OK;
+  
+  /* Locate the end of the numerator, and make sure we are not going to exceed
+     the limit by writing a slash. */
+  len = strlen(str);
+  start = str + len;
+  limit -= len;
+  if(limit == 0)
+    return MP_TRUNC;
+
+  *start++ = '/';
+  limit -= 1;
+  
+  res = mp_int_to_string(MP_DENOM_P(r), radix, start, limit);
+  return res;
+}
+
+mp_result mp_rat_to_decimal(mp_rat r, mp_size radix, mp_size prec,
+                            mp_round_mode round, char *str, int limit)
+{
+  mpz_t temp[3];
+  mp_result res;
+  char *start = str;
+  int len, lead_0, left = limit, last = 0;
+    
+  SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(r)), last);
+  SETUP(mp_int_init(TEMP(last)), last);
+  SETUP(mp_int_init(TEMP(last)), last);
+
+  /* Get the unsigned integer part by dividing denominator into the absolute
+     value of the numerator. */
+  mp_int_abs(TEMP(0), TEMP(0));
+  if ((res = mp_int_div(TEMP(0), MP_DENOM_P(r), TEMP(0), TEMP(1))) != MP_OK)
+    goto CLEANUP;
+
+  /* Now:  T0 = integer portion, unsigned;
+           T1 = remainder, from which fractional part is computed. */
+
+  /* Count up leading zeroes after the radix point. */
+  for (lead_0 = 0; lead_0 < prec && mp_int_compare(TEMP(1), MP_DENOM_P(r)) < 0; 
+      ++lead_0) {
+    if ((res = mp_int_mul_value(TEMP(1), radix, TEMP(1))) != MP_OK)
+      goto CLEANUP;
+  }
+
+  /* Multiply remainder by a power of the radix sufficient to get the right
+     number of significant figures. */
+  if (prec > lead_0) {
+    if ((res = mp_int_expt_value(radix, prec - lead_0, TEMP(2))) != MP_OK)
+      goto CLEANUP;
+    if ((res = mp_int_mul(TEMP(1), TEMP(2), TEMP(1))) != MP_OK)
+      goto CLEANUP;
+  }
+  if ((res = mp_int_div(TEMP(1), MP_DENOM_P(r), TEMP(1), TEMP(2))) != MP_OK)
+    goto CLEANUP;
+
+  /* Now:  T1 = significant digits of fractional part;
+           T2 = leftovers, to use for rounding. 
+
+     At this point, what we do depends on the rounding mode.  The default is
+     MP_ROUND_DOWN, for which everything is as it should be already.
+  */
+  switch (round) {
+    int cmp;
+
+  case MP_ROUND_UP:
+    if (mp_int_compare_zero(TEMP(2)) != 0) {
+      if (prec == 0)
+	res = mp_int_add_value(TEMP(0), 1, TEMP(0));
+      else
+	res = mp_int_add_value(TEMP(1), 1, TEMP(1));
+    }
+    break;
+
+  case MP_ROUND_HALF_UP:
+  case MP_ROUND_HALF_DOWN:
+    if ((res = mp_int_mul_pow2(TEMP(2), 1, TEMP(2))) != MP_OK)
+      goto CLEANUP;
+
+    cmp = mp_int_compare(TEMP(2), MP_DENOM_P(r));    
+
+    if (round == MP_ROUND_HALF_UP)
+      cmp += 1;
+
+    if (cmp > 0) {
+      if (prec == 0)
+	res = mp_int_add_value(TEMP(0), 1, TEMP(0));
+      else
+	res = mp_int_add_value(TEMP(1), 1, TEMP(1));
+    }
+    break;
+    
+  case MP_ROUND_DOWN:
+    break;  /* No action required */
+
+  default: 
+    return MP_BADARG; /* Invalid rounding specifier */
+  }
+
+  /* The sign of the output should be the sign of the numerator, but if all the
+     displayed digits will be zero due to the precision, a negative shouldn't
+     be shown. */
+  if (MP_SIGN(MP_NUMER_P(r)) == MP_NEG &&
+      (mp_int_compare_zero(TEMP(0)) != 0 ||
+       mp_int_compare_zero(TEMP(1)) != 0)) {
+    *start++ = '-';
+    left -= 1;
+  }
+
+  if ((res = mp_int_to_string(TEMP(0), radix, start, left)) != MP_OK)
+    goto CLEANUP;
+  
+  len = strlen(start);
+  start += len;
+  left -= len;
+  
+  if (prec == 0) 
+    goto CLEANUP;
+  
+  *start++ = '.';
+  left -= 1;
+  
+  if (left < prec + 1) {
+    res = MP_TRUNC;
+    goto CLEANUP;
+  }
+
+  memset(start, '0', lead_0 - 1);
+  left -= lead_0;
+  start += lead_0 - 1;
+
+  res = mp_int_to_string(TEMP(1), radix, start, left);
+
+ CLEANUP:
+  while (--last >= 0)
+    mp_int_clear(TEMP(last));
+  
+  return res;
+}
+
+mp_result mp_rat_string_len(mp_rat r, mp_size radix)
+{
+  mp_result n_len, d_len = 0;
+
+  n_len = mp_int_string_len(MP_NUMER_P(r), radix);
+
+  if (mp_int_compare_zero(MP_NUMER_P(r)) != 0)
+    d_len = mp_int_string_len(MP_DENOM_P(r), radix);
+
+  /* Though simplistic, this formula is correct.  Space for the sign flag is
+     included in n_len, and the space for the NUL that is counted in n_len
+     counts for the separator here.  The space for the NUL counted in d_len
+     counts for the final terminator here. */
+
+  return n_len + d_len;
+
+}
+
+mp_result mp_rat_decimal_len(mp_rat r, mp_size radix, mp_size prec)
+{
+  int  z_len, f_len;
+
+  z_len = mp_int_string_len(MP_NUMER_P(r), radix);
+  
+  if (prec == 0)
+    f_len = 1; /* terminator only */
+  else
+    f_len = 1 + prec + 1; /* decimal point, digits, terminator */
+  
+  return z_len + f_len;
+}
+
+mp_result mp_rat_read_string(mp_rat r, mp_size radix, const char *str)
+{
+  return mp_rat_read_cstring(r, radix, str, NULL);
+}
+
+mp_result mp_rat_read_cstring(mp_rat r, mp_size radix, const char *str, 
+			      char **end)
+{
+  mp_result res;
+  char *endp;
+
+  if ((res = mp_int_read_cstring(MP_NUMER_P(r), radix, str, &endp)) != MP_OK &&
+      (res != MP_TRUNC))
+    return res;
+
+  /* Skip whitespace between numerator and (possible) separator */
+  while (isspace((unsigned char) *endp))
+    ++endp;
+  
+  /* If there is no separator, we will stop reading at this point. */
+  if (*endp != '/') {
+    mp_int_set_value(MP_DENOM_P(r), 1);
+    if (end != NULL)
+      *end = endp;
+    return res;
+  }
+  
+  ++endp; /* skip separator */
+  if ((res = mp_int_read_cstring(MP_DENOM_P(r), radix, endp, end)) != MP_OK)
+    return res;
+  
+  /* Make sure the value is well-defined */
+  if (mp_int_compare_zero(MP_DENOM_P(r)) == 0)
+    return MP_UNDEF;
+
+  /* Reduce to lowest terms */
+  return s_rat_reduce(r);
+}
+
+/* Read a string and figure out what format it's in.  The radix may be supplied
+   as zero to use "default" behaviour.
+
+   This function will accept either a/b notation or decimal notation.
+ */
+mp_result mp_rat_read_ustring(mp_rat r, mp_size radix, const char *str, 
+			      char **end)
+{
+  char      *endp;
+  mp_result  res;
+
+  if (radix == 0)
+    radix = 10;  /* default to decimal input */
+
+  if ((res = mp_rat_read_cstring(r, radix, str, &endp)) != MP_OK) {
+    if (res == MP_TRUNC) {
+      if (*endp == '.')
+	res = mp_rat_read_cdecimal(r, radix, str, &endp);
+    }
+    else
+      return res;
+  }
+
+  if (end != NULL)
+    *end = endp;
+
+  return res;
+}
+
+mp_result mp_rat_read_decimal(mp_rat r, mp_size radix, const char *str)
+{
+  return mp_rat_read_cdecimal(r, radix, str, NULL);
+}
+
+mp_result mp_rat_read_cdecimal(mp_rat r, mp_size radix, const char *str, 
+			       char **end)
+{
+  mp_result res;
+  mp_sign   osign;
+  char *endp;
+
+  while (isspace((unsigned char) *str))
+    ++str;
+  
+  switch (*str) {
+  case '-':
+    osign = MP_NEG;
+    break;
+  default:
+    osign = MP_ZPOS;
+  }
+  
+  if ((res = mp_int_read_cstring(MP_NUMER_P(r), radix, str, &endp)) != MP_OK &&
+     (res != MP_TRUNC))
+    return res;
+
+  /* This needs to be here. */
+  (void) mp_int_set_value(MP_DENOM_P(r), 1);
+
+  if (*endp != '.') {
+    if (end != NULL)
+      *end = endp;
+    return res;
+  }
+
+  /* If the character following the decimal point is whitespace or a sign flag,
+     we will consider this a truncated value.  This special case is because
+     mp_int_read_string() will consider whitespace or sign flags to be valid
+     starting characters for a value, and we do not want them following the
+     decimal point.
+
+     Once we have done this check, it is safe to read in the value of the
+     fractional piece as a regular old integer.
+  */
+  ++endp;
+  if (*endp == '\0') {
+    if (end != NULL)
+      *end = endp;
+    return MP_OK;
+  }
+  else if(isspace((unsigned char) *endp) || *endp == '-' || *endp == '+') {
+    return MP_TRUNC;
+  }
+  else {
+    mpz_t  frac;
+    mp_result save_res;
+    char  *save = endp;
+    int    num_lz = 0;
+
+    /* Make a temporary to hold the part after the decimal point. */
+    if ((res = mp_int_init(&frac)) != MP_OK)
+      return res;
+    
+    if ((res = mp_int_read_cstring(&frac, radix, endp, &endp)) != MP_OK &&
+       (res != MP_TRUNC))
+      goto CLEANUP;
+
+    /* Save this response for later. */
+    save_res = res;
+
+    if (mp_int_compare_zero(&frac) == 0)
+      goto FINISHED;
+
+    /* Discard trailing zeroes (somewhat inefficiently) */
+    while (mp_int_divisible_value(&frac, radix))
+      if ((res = mp_int_div_value(&frac, radix, &frac, NULL)) != MP_OK)
+	goto CLEANUP;
+    
+    /* Count leading zeros after the decimal point */
+    while (save[num_lz] == '0')
+      ++num_lz;
+
+    /* Find the least power of the radix that is at least as large as the
+       significant value of the fractional part, ignoring leading zeroes.  */
+    (void) mp_int_set_value(MP_DENOM_P(r), radix); 
+    
+    while (mp_int_compare(MP_DENOM_P(r), &frac) < 0) {
+      if ((res = mp_int_mul_value(MP_DENOM_P(r), radix, MP_DENOM_P(r))) != MP_OK)
+	goto CLEANUP;
+    }
+    
+    /* Also shift by enough to account for leading zeroes */
+    while (num_lz > 0) {
+      if ((res = mp_int_mul_value(MP_DENOM_P(r), radix, MP_DENOM_P(r))) != MP_OK)
+	goto CLEANUP;
+
+      --num_lz;
+    }
+
+    /* Having found this power, shift the numerator leftward that many, digits,
+       and add the nonzero significant digits of the fractional part to get the
+       result. */
+    if ((res = mp_int_mul(MP_NUMER_P(r), MP_DENOM_P(r), MP_NUMER_P(r))) != MP_OK)
+      goto CLEANUP;
+    
+    { /* This addition needs to be unsigned. */
+      MP_SIGN(MP_NUMER_P(r)) = MP_ZPOS;
+      if ((res = mp_int_add(MP_NUMER_P(r), &frac, MP_NUMER_P(r))) != MP_OK)
+	goto CLEANUP;
+
+      MP_SIGN(MP_NUMER_P(r)) = osign;
+    }
+    if ((res = s_rat_reduce(r)) != MP_OK)
+      goto CLEANUP;
+
+    /* At this point, what we return depends on whether reading the fractional
+       part was truncated or not.  That information is saved from when we
+       called mp_int_read_string() above. */
+  FINISHED:
+    res = save_res;
+    if (end != NULL)
+      *end = endp;
+
+  CLEANUP:
+    mp_int_clear(&frac);
+
+    return res;
+  }
+}
+
+/* Private functions for internal use.  Make unchecked assumptions about format
+   and validity of inputs. */
+
+static mp_result s_rat_reduce(mp_rat r)
+{
+  mpz_t gcd;
+  mp_result res = MP_OK;
+
+  if (mp_int_compare_zero(MP_NUMER_P(r)) == 0) {
+    mp_int_set_value(MP_DENOM_P(r), 1);
+    return MP_OK;
+  }
+
+  /* If the greatest common divisor of the numerator and denominator is greater
+     than 1, divide it out. */
+  if ((res = mp_int_init(&gcd)) != MP_OK)
+    return res;
+
+  if ((res = mp_int_gcd(MP_NUMER_P(r), MP_DENOM_P(r), &gcd)) != MP_OK)
+    goto CLEANUP;
+
+  if (mp_int_compare_value(&gcd, 1) != 0) {
+    if ((res = mp_int_div(MP_NUMER_P(r), &gcd, MP_NUMER_P(r), NULL)) != MP_OK)
+      goto CLEANUP;
+    if ((res = mp_int_div(MP_DENOM_P(r), &gcd, MP_DENOM_P(r), NULL)) != MP_OK)
+      goto CLEANUP;
+  }
+
+  /* Fix up the signs of numerator and denominator */
+  if (MP_SIGN(MP_NUMER_P(r)) == MP_SIGN(MP_DENOM_P(r)))
+    MP_SIGN(MP_NUMER_P(r)) = MP_SIGN(MP_DENOM_P(r)) = MP_ZPOS;
+  else {
+    MP_SIGN(MP_NUMER_P(r)) = MP_NEG;
+    MP_SIGN(MP_DENOM_P(r)) = MP_ZPOS;
+  }
+
+ CLEANUP:
+  mp_int_clear(&gcd);
+
+  return res;
+}
+
+static mp_result s_rat_combine(mp_rat a, mp_rat b, mp_rat c, 
+			       mp_result (*comb_f)(mp_int, mp_int, mp_int))
+{
+  mp_result res;
+
+  /* Shortcut when denominators are already common */
+  if (mp_int_compare(MP_DENOM_P(a), MP_DENOM_P(b)) == 0) {
+    if ((res = (comb_f)(MP_NUMER_P(a), MP_NUMER_P(b), MP_NUMER_P(c))) != MP_OK)
+      return res;
+    if ((res = mp_int_copy(MP_DENOM_P(a), MP_DENOM_P(c))) != MP_OK)
+      return res;
+    
+    return s_rat_reduce(c);
+  }
+  else {
+    mpz_t  temp[2];
+    int    last = 0;
+
+    SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(a)), last);
+    SETUP(mp_int_init_copy(TEMP(last), MP_NUMER_P(b)), last);
+    
+    if ((res = mp_int_mul(TEMP(0), MP_DENOM_P(b), TEMP(0))) != MP_OK)
+      goto CLEANUP;
+    if ((res = mp_int_mul(TEMP(1), MP_DENOM_P(a), TEMP(1))) != MP_OK)
+      goto CLEANUP;
+    if ((res = (comb_f)(TEMP(0), TEMP(1), MP_NUMER_P(c))) != MP_OK)
+      goto CLEANUP;
+
+    res = mp_int_mul(MP_DENOM_P(a), MP_DENOM_P(b), MP_DENOM_P(c));
+
+  CLEANUP:
+    while (--last >= 0) 
+      mp_int_clear(TEMP(last));
+
+    if (res == MP_OK)
+      return s_rat_reduce(c);
+    else
+      return res;
+  }
+}
+
+/* Here there be dragons */
diff --git a/final/lib/External/isl/imath/imrat.h b/final/lib/External/isl/imath/imrat.h
new file mode 100644
index 0000000..a3678a2
--- /dev/null
+++ b/final/lib/External/isl/imath/imrat.h
@@ -0,0 +1,124 @@
+/*
+  Name:     imrat.h
+  Purpose:  Arbitrary precision rational arithmetic routines.
+  Author:   M. J. Fromberger <http://spinning-yarns.org/michael/>
+
+  Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved.
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+ */
+
+#ifndef IMRAT_H_
+#define IMRAT_H_
+
+#include "imath.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct mpq {
+  mpz_t   num;    /* Numerator         */
+  mpz_t   den;    /* Denominator, <> 0 */
+} mpq_t, *mp_rat;
+
+#define MP_NUMER_P(Q)  (&((Q)->num)) /* Pointer to numerator   */
+#define MP_DENOM_P(Q)  (&((Q)->den)) /* Pointer to denominator */
+
+/* Rounding constants */
+typedef enum {
+  MP_ROUND_DOWN,
+  MP_ROUND_HALF_UP,
+  MP_ROUND_UP,
+  MP_ROUND_HALF_DOWN
+} mp_round_mode;
+
+mp_result mp_rat_init(mp_rat r);
+mp_rat    mp_rat_alloc(void);
+mp_result mp_rat_reduce(mp_rat r);
+mp_result mp_rat_init_size(mp_rat r, mp_size n_prec, mp_size d_prec);
+mp_result mp_rat_init_copy(mp_rat r, mp_rat old);
+mp_result mp_rat_set_value(mp_rat r, mp_small numer, mp_small denom);
+mp_result mp_rat_set_uvalue(mp_rat r, mp_usmall numer, mp_usmall denom);
+void      mp_rat_clear(mp_rat r);
+void      mp_rat_free(mp_rat r);
+mp_result mp_rat_numer(mp_rat r, mp_int z);             /* z = num(r)  */
+mp_int    mp_rat_numer_ref(mp_rat r);                   /* &num(r)     */
+mp_result mp_rat_denom(mp_rat r, mp_int z);             /* z = den(r)  */
+mp_int    mp_rat_denom_ref(mp_rat r);                   /* &den(r)     */
+mp_sign   mp_rat_sign(mp_rat r);
+
+mp_result mp_rat_copy(mp_rat a, mp_rat c);              /* c = a       */
+void      mp_rat_zero(mp_rat r);                        /* r = 0       */
+mp_result mp_rat_abs(mp_rat a, mp_rat c);               /* c = |a|     */
+mp_result mp_rat_neg(mp_rat a, mp_rat c);               /* c = -a      */
+mp_result mp_rat_recip(mp_rat a, mp_rat c);             /* c = 1 / a   */
+mp_result mp_rat_add(mp_rat a, mp_rat b, mp_rat c);     /* c = a + b   */
+mp_result mp_rat_sub(mp_rat a, mp_rat b, mp_rat c);     /* c = a - b   */
+mp_result mp_rat_mul(mp_rat a, mp_rat b, mp_rat c);     /* c = a * b   */
+mp_result mp_rat_div(mp_rat a, mp_rat b, mp_rat c);     /* c = a / b   */
+
+mp_result mp_rat_add_int(mp_rat a, mp_int b, mp_rat c); /* c = a + b   */
+mp_result mp_rat_sub_int(mp_rat a, mp_int b, mp_rat c); /* c = a - b   */
+mp_result mp_rat_mul_int(mp_rat a, mp_int b, mp_rat c); /* c = a * b   */
+mp_result mp_rat_div_int(mp_rat a, mp_int b, mp_rat c); /* c = a / b   */
+mp_result mp_rat_expt(mp_rat a, mp_small b, mp_rat c);  /* c = a ^ b   */
+
+int       mp_rat_compare(mp_rat a, mp_rat b);           /* a <=> b     */
+int       mp_rat_compare_unsigned(mp_rat a, mp_rat b);  /* |a| <=> |b| */
+int       mp_rat_compare_zero(mp_rat r);                /* r <=> 0     */
+int       mp_rat_compare_value(mp_rat r, mp_small n, mp_small d); /* r <=> n/d */
+int       mp_rat_is_integer(mp_rat r);
+
+/* Convert to integers, if representable (returns MP_RANGE if not). */
+mp_result mp_rat_to_ints(mp_rat r, mp_small *num, mp_small *den);
+
+/* Convert to nul-terminated string with the specified radix, writing
+   at most limit characters including the nul terminator. */
+mp_result mp_rat_to_string(mp_rat r, mp_size radix, char *str, int limit);
+
+/* Convert to decimal format in the specified radix and precision,
+   writing at most limit characters including a nul terminator. */
+mp_result mp_rat_to_decimal(mp_rat r, mp_size radix, mp_size prec,
+                            mp_round_mode round, char *str, int limit);
+
+/* Return the number of characters required to represent r in the given
+   radix.  May over-estimate. */
+mp_result mp_rat_string_len(mp_rat r, mp_size radix);
+
+/* Return the number of characters required to represent r in decimal
+   format with the given radix and precision.  May over-estimate. */
+mp_result mp_rat_decimal_len(mp_rat r, mp_size radix, mp_size prec);
+
+/* Read zero-terminated string into r */
+mp_result mp_rat_read_string(mp_rat r, mp_size radix, const char *str);
+mp_result mp_rat_read_cstring(mp_rat r, mp_size radix, const char *str,
+			      char **end);
+mp_result mp_rat_read_ustring(mp_rat r, mp_size radix, const char *str,
+			      char **end);
+
+/* Read zero-terminated string in decimal format into r */
+mp_result mp_rat_read_decimal(mp_rat r, mp_size radix, const char *str);
+mp_result mp_rat_read_cdecimal(mp_rat r, mp_size radix, const char *str,
+			       char **end);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* IMRAT_H_ */
diff --git a/final/lib/External/isl/imath_wrap/gmp_compat.c b/final/lib/External/isl/imath_wrap/gmp_compat.c
new file mode 100644
index 0000000..a116913
--- /dev/null
+++ b/final/lib/External/isl/imath_wrap/gmp_compat.c
@@ -0,0 +1,2 @@
+#include "wrap.h"
+#include "../imath/gmp_compat.c"
diff --git a/final/lib/External/isl/imath_wrap/gmp_compat.h b/final/lib/External/isl/imath_wrap/gmp_compat.h
new file mode 100644
index 0000000..11a332d
--- /dev/null
+++ b/final/lib/External/isl/imath_wrap/gmp_compat.h
@@ -0,0 +1,2 @@
+#include "wrap.h"
+#include "../imath/gmp_compat.h"
diff --git a/final/lib/External/isl/imath_wrap/imath.c b/final/lib/External/isl/imath_wrap/imath.c
new file mode 100644
index 0000000..c4e35c1
--- /dev/null
+++ b/final/lib/External/isl/imath_wrap/imath.c
@@ -0,0 +1,2 @@
+#include "wrap.h"
+#include "../imath/imath.c"
diff --git a/final/lib/External/isl/imath_wrap/imath.h b/final/lib/External/isl/imath_wrap/imath.h
new file mode 100644
index 0000000..12029ce
--- /dev/null
+++ b/final/lib/External/isl/imath_wrap/imath.h
@@ -0,0 +1,2 @@
+#include "wrap.h"
+#include "../imath/imath.h"
diff --git a/final/lib/External/isl/imath_wrap/imrat.c b/final/lib/External/isl/imath_wrap/imrat.c
new file mode 100644
index 0000000..0c7feaa
--- /dev/null
+++ b/final/lib/External/isl/imath_wrap/imrat.c
@@ -0,0 +1,2 @@
+#include "wrap.h"
+#include "../imath/imrat.c"
diff --git a/final/lib/External/isl/imath_wrap/imrat.h b/final/lib/External/isl/imath_wrap/imrat.h
new file mode 100644
index 0000000..c998390
--- /dev/null
+++ b/final/lib/External/isl/imath_wrap/imrat.h
@@ -0,0 +1,2 @@
+#include "wrap.h"
+#include "../imath/imrat.h"
diff --git a/final/lib/External/isl/imath_wrap/wrap.h b/final/lib/External/isl/imath_wrap/wrap.h
new file mode 100644
index 0000000..a2ea88f
--- /dev/null
+++ b/final/lib/External/isl/imath_wrap/wrap.h
@@ -0,0 +1,171 @@
+#ifndef ISL_IMATH_WRAP
+#define ISL_IMATH_WRAP
+
+#define MP_BADARG	ISL_MP_BADARG
+#define MP_FALSE	ISL_MP_FALSE
+#define MP_MEMORY	ISL_MP_MEMORY
+#define MP_MINERR	ISL_MP_MINERR
+#define MP_NEG	ISL_MP_NEG
+#define MP_OK	ISL_MP_OK
+#define MP_RANGE	ISL_MP_RANGE
+#define MP_TRUE	ISL_MP_TRUE
+#define MP_TRUNC	ISL_MP_TRUNC
+#define MP_UNDEF	ISL_MP_UNDEF
+#define MP_ZPOS	ISL_MP_ZPOS
+
+#define impq_canonicalize	isl_impq_canonicalize
+#define impq_clear	isl_impq_clear
+#define impq_cmp	isl_impq_cmp
+#define impq_denref	isl_impq_denref
+#define impq_get_str	isl_impq_get_str
+#define impq_init	isl_impq_init
+#define impq_mul	isl_impq_mul
+#define impq_numref	isl_impq_numref
+#define impq_set	isl_impq_set
+#define impq_set_str	isl_impq_set_str
+#define impq_set_ui	isl_impq_set_ui
+#define impq_sgn	isl_impq_sgn
+#define impz_abs	isl_impz_abs
+#define impz_add	isl_impz_add
+#define impz_addmul	isl_impz_addmul
+#define impz_add_ui	isl_impz_add_ui
+#define impz_cdiv_q	isl_impz_cdiv_q
+#define impz_clear	isl_impz_clear
+#define impz_cmp	isl_impz_cmp
+#define impz_cmpabs	isl_impz_cmpabs
+#define impz_cmp_si	isl_impz_cmp_si
+#define impz_divexact	isl_impz_divexact
+#define impz_divexact_ui	isl_impz_divexact_ui
+#define impz_divisible_p	isl_impz_divisible_p
+#define impz_export	isl_impz_export
+#define impz_fdiv_q	isl_impz_fdiv_q
+#define impz_fdiv_r	isl_impz_fdiv_r
+#define impz_gcd	isl_impz_gcd
+#define impz_get_si	isl_impz_get_si
+#define impz_get_str	isl_impz_get_str
+#define impz_get_ui	isl_impz_get_ui
+#define impz_import	isl_impz_import
+#define impz_init	isl_impz_init
+#define impz_lcm	isl_impz_lcm
+#define impz_mul	isl_impz_mul
+#define impz_mul_2exp	isl_impz_mul_2exp
+#define impz_mul_ui	isl_impz_mul_ui
+#define impz_neg	isl_impz_neg
+#define impz_pow_ui	isl_impz_pow_ui
+#define impz_set	isl_impz_set
+#define impz_set_si	isl_impz_set_si
+#define impz_set_str	isl_impz_set_str
+#define impz_set_ui	isl_impz_set_ui
+#define impz_sgn	isl_impz_sgn
+#define impz_sizeinbase	isl_impz_sizeinbase
+#define impz_sub	isl_impz_sub
+#define impz_submul	isl_impz_submul
+#define impz_sub_ui	isl_impz_sub_ui
+#define impz_swap	isl_impz_swap
+#define impz_tdiv_q	isl_impz_tdiv_q
+#define mp_error_string	isl_mp_error_string
+#define mp_int_abs	isl_mp_int_abs
+#define mp_int_add	isl_mp_int_add
+#define mp_int_add_value	isl_mp_int_add_value
+#define mp_int_alloc	isl_mp_int_alloc
+#define mp_int_binary_len	isl_mp_int_binary_len
+#define mp_int_clear	isl_mp_int_clear
+#define mp_int_compare	isl_mp_int_compare
+#define mp_int_compare_unsigned	isl_mp_int_compare_unsigned
+#define mp_int_compare_uvalue	isl_mp_int_compare_uvalue
+#define mp_int_compare_value	isl_mp_int_compare_value
+#define mp_int_compare_zero	isl_mp_int_compare_zero
+#define mp_int_copy	isl_mp_int_copy
+#define mp_int_count_bits	isl_mp_int_count_bits
+#define mp_int_div	isl_mp_int_div
+#define mp_int_divisible_value	isl_mp_int_divisible_value
+#define mp_int_div_pow2	isl_mp_int_div_pow2
+#define mp_int_div_value	isl_mp_int_div_value
+#define mp_int_egcd	isl_mp_int_egcd
+#define mp_int_expt	isl_mp_int_expt
+#define mp_int_expt_full	isl_mp_int_expt_full
+#define mp_int_exptmod	isl_mp_int_exptmod
+#define mp_int_exptmod_bvalue	isl_mp_int_exptmod_bvalue
+#define mp_int_exptmod_evalue	isl_mp_int_exptmod_evalue
+#define mp_int_exptmod_known	isl_mp_int_exptmod_known
+#define mp_int_expt_value	isl_mp_int_expt_value
+#define mp_int_free	isl_mp_int_free
+#define mp_int_gcd	isl_mp_int_gcd
+#define mp_int_init	isl_mp_int_init
+#define mp_int_init_copy	isl_mp_int_init_copy
+#define mp_int_init_size	isl_mp_int_init_size
+#define mp_int_init_uvalue	isl_mp_int_init_uvalue
+#define mp_int_init_value	isl_mp_int_init_value
+#define mp_int_invmod	isl_mp_int_invmod
+#define mp_int_is_pow2	isl_mp_int_is_pow2
+#define mp_int_lcm	isl_mp_int_lcm
+#define mp_int_mod	isl_mp_int_mod
+#define mp_int_mul	isl_mp_int_mul
+#define mp_int_mul_pow2	isl_mp_int_mul_pow2
+#define mp_int_mul_value	isl_mp_int_mul_value
+#define mp_int_neg	isl_mp_int_neg
+#define mp_int_read_binary	isl_mp_int_read_binary
+#define mp_int_read_cstring	isl_mp_int_read_cstring
+#define mp_int_read_string	isl_mp_int_read_string
+#define mp_int_read_unsigned	isl_mp_int_read_unsigned
+#define mp_int_redux_const	isl_mp_int_redux_const
+#define mp_int_root	isl_mp_int_root
+#define mp_int_set_uvalue	isl_mp_int_set_uvalue
+#define mp_int_set_value	isl_mp_int_set_value
+#define mp_int_sqr	isl_mp_int_sqr
+#define mp_int_string_len	isl_mp_int_string_len
+#define mp_int_sub	isl_mp_int_sub
+#define mp_int_sub_value	isl_mp_int_sub_value
+#define mp_int_swap	isl_mp_int_swap
+#define mp_int_to_binary	isl_mp_int_to_binary
+#define mp_int_to_int	isl_mp_int_to_int
+#define mp_int_to_string	isl_mp_int_to_string
+#define mp_int_to_uint	isl_mp_int_to_uint
+#define mp_int_to_unsigned	isl_mp_int_to_unsigned
+#define mp_int_unsigned_len	isl_mp_int_unsigned_len
+#define mp_int_zero	isl_mp_int_zero
+#define mp_rat_abs	isl_mp_rat_abs
+#define mp_rat_add	isl_mp_rat_add
+#define mp_rat_add_int	isl_mp_rat_add_int
+#define mp_rat_alloc	isl_mp_rat_alloc
+#define mp_rat_clear	isl_mp_rat_clear
+#define mp_rat_compare	isl_mp_rat_compare
+#define mp_rat_compare_unsigned	isl_mp_rat_compare_unsigned
+#define mp_rat_compare_value	isl_mp_rat_compare_value
+#define mp_rat_compare_zero	isl_mp_rat_compare_zero
+#define mp_rat_copy	isl_mp_rat_copy
+#define mp_rat_decimal_len	isl_mp_rat_decimal_len
+#define mp_rat_denom	isl_mp_rat_denom
+#define mp_rat_denom_ref	isl_mp_rat_denom_ref
+#define mp_rat_div	isl_mp_rat_div
+#define mp_rat_div_int	isl_mp_rat_div_int
+#define mp_rat_expt	isl_mp_rat_expt
+#define mp_rat_free	isl_mp_rat_free
+#define mp_rat_init	isl_mp_rat_init
+#define mp_rat_init_copy	isl_mp_rat_init_copy
+#define mp_rat_init_size	isl_mp_rat_init_size
+#define mp_rat_is_integer	isl_mp_rat_is_integer
+#define mp_rat_mul	isl_mp_rat_mul
+#define mp_rat_mul_int	isl_mp_rat_mul_int
+#define mp_rat_neg	isl_mp_rat_neg
+#define mp_rat_numer	isl_mp_rat_numer
+#define mp_rat_numer_ref	isl_mp_rat_numer_ref
+#define mp_rat_read_cdecimal	isl_mp_rat_read_cdecimal
+#define mp_rat_read_cstring	isl_mp_rat_read_cstring
+#define mp_rat_read_decimal	isl_mp_rat_read_decimal
+#define mp_rat_read_string	isl_mp_rat_read_string
+#define mp_rat_read_ustring	isl_mp_rat_read_ustring
+#define mp_rat_recip	isl_mp_rat_recip
+#define mp_rat_reduce	isl_mp_rat_reduce
+#define mp_rat_set_uvalue	isl_mp_rat_set_uvalue
+#define mp_rat_set_value	isl_mp_rat_set_value
+#define mp_rat_sign	isl_mp_rat_sign
+#define mp_rat_string_len	isl_mp_rat_string_len
+#define mp_rat_sub	isl_mp_rat_sub
+#define mp_rat_sub_int	isl_mp_rat_sub_int
+#define mp_rat_to_decimal	isl_mp_rat_to_decimal
+#define mp_rat_to_ints	isl_mp_rat_to_ints
+#define mp_rat_to_string	isl_mp_rat_to_string
+#define mp_rat_zero	isl_mp_rat_zero
+
+#endif
diff --git a/final/lib/External/isl/include/isl/aff.h b/final/lib/External/isl/include/isl/aff.h
new file mode 100644
index 0000000..b032ab1
--- /dev/null
+++ b/final/lib/External/isl/include/isl/aff.h
@@ -0,0 +1,1042 @@
+#ifndef ISL_AFF_H
+#define ISL_AFF_H
+
+#include <isl/local_space.h>
+#include <isl/printer.h>
+#include <isl/set_type.h>
+#include <isl/aff_type.h>
+#include <isl/list.h>
+#include <isl/multi.h>
+#include <isl/union_set_type.h>
+#include <isl/val.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_aff *isl_aff_zero_on_domain(__isl_take isl_local_space *ls);
+__isl_give isl_aff *isl_aff_val_on_domain(__isl_take isl_local_space *ls,
+	__isl_take isl_val *val);
+__isl_give isl_aff *isl_aff_var_on_domain(__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_aff *isl_aff_nan_on_domain(__isl_take isl_local_space *ls);
+
+__isl_give isl_aff *isl_aff_copy(__isl_keep isl_aff *aff);
+__isl_null isl_aff *isl_aff_free(__isl_take isl_aff *aff);
+
+isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff);
+uint32_t isl_aff_get_hash(__isl_keep isl_aff *aff);
+
+int isl_aff_dim(__isl_keep isl_aff *aff, enum isl_dim_type type);
+isl_bool isl_aff_involves_dims(__isl_keep isl_aff *aff,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+__isl_give isl_space *isl_aff_get_domain_space(__isl_keep isl_aff *aff);
+__isl_give isl_space *isl_aff_get_space(__isl_keep isl_aff *aff);
+__isl_give isl_local_space *isl_aff_get_domain_local_space(
+	__isl_keep isl_aff *aff);
+__isl_give isl_local_space *isl_aff_get_local_space(__isl_keep isl_aff *aff);
+
+const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_val *isl_aff_get_constant_val(__isl_keep isl_aff *aff);
+__isl_give isl_val *isl_aff_get_coefficient_val(__isl_keep isl_aff *aff,
+	enum isl_dim_type type, int pos);
+int isl_aff_coefficient_sgn(__isl_keep isl_aff *aff,
+	enum isl_dim_type type, int pos);
+__isl_give isl_val *isl_aff_get_denominator_val(__isl_keep isl_aff *aff);
+__isl_give isl_aff *isl_aff_set_constant_si(__isl_take isl_aff *aff, int v);
+__isl_give isl_aff *isl_aff_set_constant_val(__isl_take isl_aff *aff,
+	__isl_take isl_val *v);
+__isl_give isl_aff *isl_aff_set_coefficient_si(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, int v);
+__isl_give isl_aff *isl_aff_set_coefficient_val(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, __isl_take isl_val *v);
+__isl_give isl_aff *isl_aff_add_constant_si(__isl_take isl_aff *aff, int v);
+__isl_give isl_aff *isl_aff_add_constant_val(__isl_take isl_aff *aff,
+	__isl_take isl_val *v);
+__isl_give isl_aff *isl_aff_add_constant_num_si(__isl_take isl_aff *aff, int v);
+__isl_give isl_aff *isl_aff_add_coefficient_si(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, int v);
+__isl_give isl_aff *isl_aff_add_coefficient_val(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, __isl_take isl_val *v);
+
+isl_bool isl_aff_is_cst(__isl_keep isl_aff *aff);
+
+__isl_give isl_aff *isl_aff_set_tuple_id(__isl_take isl_aff *aff,
+	enum isl_dim_type type, __isl_take isl_id *id);
+__isl_give isl_aff *isl_aff_set_dim_name(__isl_take isl_aff *aff,
+	enum isl_dim_type type, unsigned pos, const char *s);
+__isl_give isl_aff *isl_aff_set_dim_id(__isl_take isl_aff *aff,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id);
+
+int isl_aff_find_dim_by_name(__isl_keep isl_aff *aff, enum isl_dim_type type,
+	const char *name);
+
+isl_bool isl_aff_plain_is_equal(__isl_keep isl_aff *aff1,
+	__isl_keep isl_aff *aff2);
+isl_bool isl_aff_plain_is_zero(__isl_keep isl_aff *aff);
+isl_bool isl_aff_is_nan(__isl_keep isl_aff *aff);
+
+__isl_give isl_aff *isl_aff_get_div(__isl_keep isl_aff *aff, int pos);
+
+__isl_export
+__isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff);
+__isl_export
+__isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff);
+__isl_export
+__isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff);
+__isl_overload
+__isl_give isl_aff *isl_aff_mod_val(__isl_take isl_aff *aff,
+	__isl_take isl_val *mod);
+
+__isl_export
+__isl_give isl_aff *isl_aff_mul(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_export
+__isl_give isl_aff *isl_aff_div(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_export
+__isl_give isl_aff *isl_aff_add(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_export
+__isl_give isl_aff *isl_aff_sub(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+
+__isl_overload
+__isl_give isl_aff *isl_aff_scale_val(__isl_take isl_aff *aff,
+	__isl_take isl_val *v);
+__isl_give isl_aff *isl_aff_scale_down_ui(__isl_take isl_aff *aff, unsigned f);
+__isl_overload
+__isl_give isl_aff *isl_aff_scale_down_val(__isl_take isl_aff *aff,
+	__isl_take isl_val *v);
+
+__isl_give isl_aff *isl_aff_insert_dims(__isl_take isl_aff *aff,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_aff *isl_aff_add_dims(__isl_take isl_aff *aff,
+	enum isl_dim_type type, unsigned n);
+__isl_give isl_aff *isl_aff_move_dims(__isl_take isl_aff *aff,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+__isl_give isl_aff *isl_aff_drop_dims(__isl_take isl_aff *aff,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_aff *isl_aff_project_domain_on_params(__isl_take isl_aff *aff);
+
+__isl_give isl_aff *isl_aff_align_params(__isl_take isl_aff *aff,
+	__isl_take isl_space *model);
+
+__isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff,
+	__isl_take isl_set *context);
+__isl_give isl_aff *isl_aff_gist_params(__isl_take isl_aff *aff,
+	__isl_take isl_set *context);
+
+__isl_give isl_aff *isl_aff_pullback_aff(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_overload
+__isl_give isl_aff *isl_aff_pullback_multi_aff(__isl_take isl_aff *aff,
+	__isl_take isl_multi_aff *ma);
+
+__isl_give isl_basic_set *isl_aff_zero_basic_set(__isl_take isl_aff *aff);
+__isl_give isl_basic_set *isl_aff_neg_basic_set(__isl_take isl_aff *aff);
+
+__isl_give isl_basic_set *isl_aff_eq_basic_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_export
+__isl_give isl_set *isl_aff_eq_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_export
+__isl_give isl_set *isl_aff_ne_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_give isl_basic_set *isl_aff_le_basic_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_export
+__isl_give isl_set *isl_aff_le_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_give isl_basic_set *isl_aff_lt_basic_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_export
+__isl_give isl_set *isl_aff_lt_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_give isl_basic_set *isl_aff_ge_basic_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_export
+__isl_give isl_set *isl_aff_ge_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_give isl_basic_set *isl_aff_gt_basic_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_export
+__isl_give isl_set *isl_aff_gt_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+
+__isl_constructor
+__isl_give isl_aff *isl_aff_read_from_str(isl_ctx *ctx, const char *str);
+__isl_give char *isl_aff_to_str(__isl_keep isl_aff *aff);
+__isl_give isl_printer *isl_printer_print_aff(__isl_take isl_printer *p,
+	__isl_keep isl_aff *aff);
+void isl_aff_dump(__isl_keep isl_aff *aff);
+
+isl_ctx *isl_pw_aff_get_ctx(__isl_keep isl_pw_aff *pwaff);
+uint32_t isl_pw_aff_get_hash(__isl_keep isl_pw_aff *pa);
+__isl_give isl_space *isl_pw_aff_get_domain_space(__isl_keep isl_pw_aff *pwaff);
+__isl_give isl_space *isl_pw_aff_get_space(__isl_keep isl_pw_aff *pwaff);
+
+__isl_constructor
+__isl_give isl_pw_aff *isl_pw_aff_from_aff(__isl_take isl_aff *aff);
+__isl_give isl_pw_aff *isl_pw_aff_empty(__isl_take isl_space *dim);
+__isl_give isl_pw_aff *isl_pw_aff_alloc(__isl_take isl_set *set,
+	__isl_take isl_aff *aff);
+__isl_give isl_pw_aff *isl_pw_aff_zero_on_domain(
+	__isl_take isl_local_space *ls);
+__isl_give isl_pw_aff *isl_pw_aff_var_on_domain(__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_pw_aff *isl_pw_aff_nan_on_domain(__isl_take isl_local_space *ls);
+__isl_give isl_pw_aff *isl_pw_aff_val_on_domain(__isl_take isl_set *domain,
+	__isl_take isl_val *v);
+
+__isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set);
+
+const char *isl_pw_aff_get_dim_name(__isl_keep isl_pw_aff *pa,
+	enum isl_dim_type type, unsigned pos);
+isl_bool isl_pw_aff_has_dim_id(__isl_keep isl_pw_aff *pa,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_id *isl_pw_aff_get_dim_id(__isl_keep isl_pw_aff *pa,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_pw_aff *isl_pw_aff_set_dim_id(__isl_take isl_pw_aff *pma,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id);
+
+int isl_pw_aff_find_dim_by_name(__isl_keep isl_pw_aff *pa,
+	enum isl_dim_type type, const char *name);
+
+isl_bool isl_pw_aff_is_empty(__isl_keep isl_pw_aff *pwaff);
+isl_bool isl_pw_aff_involves_nan(__isl_keep isl_pw_aff *pa);
+int isl_pw_aff_plain_cmp(__isl_keep isl_pw_aff *pa1,
+	__isl_keep isl_pw_aff *pa2);
+isl_bool isl_pw_aff_plain_is_equal(__isl_keep isl_pw_aff *pwaff1,
+	__isl_keep isl_pw_aff *pwaff2);
+isl_bool isl_pw_aff_is_equal(__isl_keep isl_pw_aff *pa1,
+	__isl_keep isl_pw_aff *pa2);
+
+__isl_give isl_pw_aff *isl_pw_aff_union_min(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_give isl_pw_aff *isl_pw_aff_union_max(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_union_add(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+
+__isl_give isl_pw_aff *isl_pw_aff_copy(__isl_keep isl_pw_aff *pwaff);
+__isl_null isl_pw_aff *isl_pw_aff_free(__isl_take isl_pw_aff *pwaff);
+
+unsigned isl_pw_aff_dim(__isl_keep isl_pw_aff *pwaff, enum isl_dim_type type);
+isl_bool isl_pw_aff_involves_dims(__isl_keep isl_pw_aff *pwaff,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+isl_bool isl_pw_aff_is_cst(__isl_keep isl_pw_aff *pwaff);
+
+__isl_give isl_pw_aff *isl_pw_aff_project_domain_on_params(
+	__isl_take isl_pw_aff *pa);
+
+__isl_give isl_pw_aff *isl_pw_aff_align_params(__isl_take isl_pw_aff *pwaff,
+	__isl_take isl_space *model);
+
+isl_bool isl_pw_aff_has_tuple_id(__isl_keep isl_pw_aff *pa,
+	enum isl_dim_type type);
+__isl_give isl_id *isl_pw_aff_get_tuple_id(__isl_keep isl_pw_aff *pa,
+	enum isl_dim_type type);
+__isl_give isl_pw_aff *isl_pw_aff_set_tuple_id(__isl_take isl_pw_aff *pwaff,
+	enum isl_dim_type type, __isl_take isl_id *id);
+__isl_give isl_pw_aff *isl_pw_aff_reset_tuple_id(__isl_take isl_pw_aff *pa,
+	enum isl_dim_type type);
+__isl_give isl_pw_aff *isl_pw_aff_reset_user(__isl_take isl_pw_aff *pa);
+
+__isl_give isl_set *isl_pw_aff_params(__isl_take isl_pw_aff *pwa);
+__isl_give isl_set *isl_pw_aff_domain(__isl_take isl_pw_aff *pwaff);
+__isl_give isl_pw_aff *isl_pw_aff_from_range(__isl_take isl_pw_aff *pwa);
+
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_max(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_mul(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_div(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2);
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_add(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_sub(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_neg(__isl_take isl_pw_aff *pwaff);
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff);
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_floor(__isl_take isl_pw_aff *pwaff);
+__isl_overload
+__isl_give isl_pw_aff *isl_pw_aff_mod_val(__isl_take isl_pw_aff *pa,
+	__isl_take isl_val *mod);
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_tdiv_q(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2);
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_tdiv_r(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2);
+
+__isl_give isl_pw_aff *isl_pw_aff_intersect_params(__isl_take isl_pw_aff *pa,
+	__isl_take isl_set *set);
+__isl_give isl_pw_aff *isl_pw_aff_intersect_domain(__isl_take isl_pw_aff *pa,
+	__isl_take isl_set *set);
+__isl_give isl_pw_aff *isl_pw_aff_subtract_domain(__isl_take isl_pw_aff *pa,
+	__isl_take isl_set *set);
+
+__isl_export
+__isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_pw_aff *cond,
+	__isl_take isl_pw_aff *pwaff_true, __isl_take isl_pw_aff *pwaff_false);
+
+__isl_overload
+__isl_give isl_pw_aff *isl_pw_aff_scale_val(__isl_take isl_pw_aff *pa,
+	__isl_take isl_val *v);
+__isl_overload
+__isl_give isl_pw_aff *isl_pw_aff_scale_down_val(__isl_take isl_pw_aff *pa,
+	__isl_take isl_val *f);
+
+__isl_give isl_pw_aff *isl_pw_aff_insert_dims(__isl_take isl_pw_aff *pwaff,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_pw_aff *isl_pw_aff_add_dims(__isl_take isl_pw_aff *pwaff,
+	enum isl_dim_type type, unsigned n);
+__isl_give isl_pw_aff *isl_pw_aff_move_dims(__isl_take isl_pw_aff *pa,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+__isl_give isl_pw_aff *isl_pw_aff_drop_dims(__isl_take isl_pw_aff *pwaff,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+__isl_give isl_pw_aff *isl_pw_aff_coalesce(__isl_take isl_pw_aff *pwqp);
+__isl_give isl_pw_aff *isl_pw_aff_gist(__isl_take isl_pw_aff *pwaff,
+	__isl_take isl_set *context);
+__isl_give isl_pw_aff *isl_pw_aff_gist_params(__isl_take isl_pw_aff *pwaff,
+	__isl_take isl_set *context);
+
+__isl_overload
+__isl_give isl_pw_aff *isl_pw_aff_pullback_multi_aff(
+	__isl_take isl_pw_aff *pa, __isl_take isl_multi_aff *ma);
+__isl_overload
+__isl_give isl_pw_aff *isl_pw_aff_pullback_pw_multi_aff(
+	__isl_take isl_pw_aff *pa, __isl_take isl_pw_multi_aff *pma);
+__isl_overload
+__isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff(
+	__isl_take isl_pw_aff *pa, __isl_take isl_multi_pw_aff *mpa);
+
+int isl_pw_aff_n_piece(__isl_keep isl_pw_aff *pwaff);
+isl_stat isl_pw_aff_foreach_piece(__isl_keep isl_pw_aff *pwaff,
+	isl_stat (*fn)(__isl_take isl_set *set, __isl_take isl_aff *aff,
+		    void *user), void *user);
+
+__isl_give isl_set *isl_set_from_pw_aff(__isl_take isl_pw_aff *pwaff);
+__isl_give isl_map *isl_map_from_pw_aff(__isl_take isl_pw_aff *pwaff);
+
+__isl_give isl_set *isl_pw_aff_pos_set(__isl_take isl_pw_aff *pa);
+__isl_give isl_set *isl_pw_aff_nonneg_set(__isl_take isl_pw_aff *pwaff);
+__isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff);
+__isl_give isl_set *isl_pw_aff_non_zero_set(__isl_take isl_pw_aff *pwaff);
+
+__isl_export
+__isl_give isl_set *isl_pw_aff_eq_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_export
+__isl_give isl_set *isl_pw_aff_ne_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_export
+__isl_give isl_set *isl_pw_aff_le_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_export
+__isl_give isl_set *isl_pw_aff_lt_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_export
+__isl_give isl_set *isl_pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_export
+__isl_give isl_set *isl_pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+
+__isl_give isl_map *isl_pw_aff_eq_map(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2);
+__isl_give isl_map *isl_pw_aff_lt_map(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2);
+__isl_give isl_map *isl_pw_aff_gt_map(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2);
+
+__isl_constructor
+__isl_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str);
+__isl_give char *isl_pw_aff_to_str(__isl_keep isl_pw_aff *pa);
+__isl_give isl_printer *isl_printer_print_pw_aff(__isl_take isl_printer *p,
+	__isl_keep isl_pw_aff *pwaff);
+void isl_pw_aff_dump(__isl_keep isl_pw_aff *pwaff);
+
+__isl_give isl_pw_aff *isl_pw_aff_list_min(__isl_take isl_pw_aff_list *list);
+__isl_give isl_pw_aff *isl_pw_aff_list_max(__isl_take isl_pw_aff_list *list);
+
+__isl_give isl_set *isl_pw_aff_list_eq_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2);
+__isl_give isl_set *isl_pw_aff_list_ne_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2);
+__isl_give isl_set *isl_pw_aff_list_le_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2);
+__isl_give isl_set *isl_pw_aff_list_lt_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2);
+__isl_give isl_set *isl_pw_aff_list_ge_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2);
+__isl_give isl_set *isl_pw_aff_list_gt_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2);
+
+ISL_DECLARE_MULTI(aff)
+ISL_DECLARE_MULTI_CMP(aff)
+ISL_DECLARE_MULTI_NEG(aff)
+ISL_DECLARE_MULTI_DIMS(aff)
+ISL_DECLARE_MULTI_WITH_DOMAIN(aff)
+
+__isl_constructor
+__isl_give isl_multi_aff *isl_multi_aff_from_aff(__isl_take isl_aff *aff);
+__isl_give isl_multi_aff *isl_multi_aff_identity(__isl_take isl_space *space);
+__isl_give isl_multi_aff *isl_multi_aff_domain_map(__isl_take isl_space *space);
+__isl_give isl_multi_aff *isl_multi_aff_range_map(__isl_take isl_space *space);
+__isl_give isl_multi_aff *isl_multi_aff_project_out_map(
+	__isl_take isl_space *space, enum isl_dim_type type,
+	unsigned first, unsigned n);
+
+__isl_give isl_multi_aff *isl_multi_aff_multi_val_on_space(
+	__isl_take isl_space *space, __isl_take isl_multi_val *mv);
+
+__isl_give isl_multi_aff *isl_multi_aff_floor(__isl_take isl_multi_aff *ma);
+
+__isl_give isl_multi_aff *isl_multi_aff_gist_params(
+	__isl_take isl_multi_aff *maff, __isl_take isl_set *context);
+__isl_give isl_multi_aff *isl_multi_aff_gist(__isl_take isl_multi_aff *maff,
+	__isl_take isl_set *context);
+
+__isl_give isl_multi_aff *isl_multi_aff_lift(__isl_take isl_multi_aff *maff,
+	__isl_give isl_local_space **ls);
+
+__isl_overload
+__isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff(
+	__isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2);
+
+__isl_give isl_multi_aff *isl_multi_aff_move_dims(__isl_take isl_multi_aff *ma,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+
+__isl_give isl_set *isl_multi_aff_lex_lt_set(__isl_take isl_multi_aff *ma1,
+	__isl_take isl_multi_aff *ma2);
+__isl_give isl_set *isl_multi_aff_lex_le_set(__isl_take isl_multi_aff *ma1,
+	__isl_take isl_multi_aff *ma2);
+__isl_give isl_set *isl_multi_aff_lex_gt_set(__isl_take isl_multi_aff *ma1,
+	__isl_take isl_multi_aff *ma2);
+__isl_give isl_set *isl_multi_aff_lex_ge_set(__isl_take isl_multi_aff *ma1,
+	__isl_take isl_multi_aff *ma2);
+
+__isl_give char *isl_multi_aff_to_str(__isl_keep isl_multi_aff *ma);
+__isl_give isl_printer *isl_printer_print_multi_aff(__isl_take isl_printer *p,
+	__isl_keep isl_multi_aff *maff);
+
+__isl_constructor
+__isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx,
+		const char *str);
+void isl_multi_aff_dump(__isl_keep isl_multi_aff *maff);
+
+ISL_DECLARE_MULTI(pw_aff)
+ISL_DECLARE_MULTI_NEG(pw_aff)
+ISL_DECLARE_MULTI_DIMS(pw_aff)
+ISL_DECLARE_MULTI_WITH_DOMAIN(pw_aff)
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_zero(__isl_take isl_space *space);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity(
+	__isl_take isl_space *space);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_map(
+	__isl_take isl_space *space);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_out_map(
+	__isl_take isl_space *space, enum isl_dim_type type,
+	unsigned first, unsigned n);
+__isl_constructor
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_aff(
+	__isl_take isl_multi_aff *ma);
+__isl_constructor
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_pw_aff(
+	__isl_take isl_pw_aff *pa);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_alloc(__isl_take isl_set *set,
+	__isl_take isl_multi_aff *maff);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_copy(
+	__isl_keep isl_pw_multi_aff *pma);
+__isl_null isl_pw_multi_aff *isl_pw_multi_aff_free(
+	__isl_take isl_pw_multi_aff *pma);
+
+unsigned isl_pw_multi_aff_dim(__isl_keep isl_pw_multi_aff *pma,
+	enum isl_dim_type type);
+__isl_give isl_pw_aff *isl_pw_multi_aff_get_pw_aff(
+	__isl_keep isl_pw_multi_aff *pma, int pos);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_pw_aff(
+	__isl_take isl_pw_multi_aff *pma, unsigned pos,
+	__isl_take isl_pw_aff *pa);
+
+isl_ctx *isl_pw_multi_aff_get_ctx(__isl_keep isl_pw_multi_aff *pma);
+__isl_give isl_space *isl_pw_multi_aff_get_domain_space(
+	__isl_keep isl_pw_multi_aff *pma);
+__isl_give isl_space *isl_pw_multi_aff_get_space(
+	__isl_keep isl_pw_multi_aff *pma);
+isl_bool isl_pw_multi_aff_has_tuple_name(__isl_keep isl_pw_multi_aff *pma,
+	enum isl_dim_type type);
+const char *isl_pw_multi_aff_get_tuple_name(__isl_keep isl_pw_multi_aff *pma,
+	enum isl_dim_type type);
+__isl_give isl_id *isl_pw_multi_aff_get_tuple_id(
+	__isl_keep isl_pw_multi_aff *pma, enum isl_dim_type type);
+isl_bool isl_pw_multi_aff_has_tuple_id(__isl_keep isl_pw_multi_aff *pma,
+	enum isl_dim_type type);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_tuple_id(
+	__isl_take isl_pw_multi_aff *pma,
+	enum isl_dim_type type, __isl_take isl_id *id);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_tuple_id(
+	__isl_take isl_pw_multi_aff *pma, enum isl_dim_type type);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_user(
+	__isl_take isl_pw_multi_aff *pma);
+
+int isl_pw_multi_aff_find_dim_by_name(__isl_keep isl_pw_multi_aff *pma,
+	enum isl_dim_type type, const char *name);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_drop_dims(
+	__isl_take isl_pw_multi_aff *pma,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+__isl_give isl_set *isl_pw_multi_aff_domain(__isl_take isl_pw_multi_aff *pma);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_empty(__isl_take isl_space *space);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_domain(
+	__isl_take isl_set *set);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_multi_val_on_domain(
+	__isl_take isl_set *domain, __isl_take isl_multi_val *mv);
+
+const char *isl_pw_multi_aff_get_dim_name(__isl_keep isl_pw_multi_aff *pma,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_id *isl_pw_multi_aff_get_dim_id(
+	__isl_keep isl_pw_multi_aff *pma, enum isl_dim_type type,
+	unsigned pos);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_dim_id(
+	__isl_take isl_pw_multi_aff *pma,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id);
+
+isl_bool isl_pw_multi_aff_involves_nan(__isl_keep isl_pw_multi_aff *pma);
+isl_bool isl_pw_multi_aff_plain_is_equal(__isl_keep isl_pw_multi_aff *pma1,
+	__isl_keep isl_pw_multi_aff *pma2);
+isl_bool isl_pw_multi_aff_is_equal(__isl_keep isl_pw_multi_aff *pma1,
+	__isl_keep isl_pw_multi_aff *pma2);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_fix_si(
+	__isl_take isl_pw_multi_aff *pma, enum isl_dim_type type,
+	unsigned pos, int value);
+
+__isl_export
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_neg(
+	__isl_take isl_pw_multi_aff *pma);
+
+__isl_export
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_add(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_val(
+	__isl_take isl_pw_multi_aff *pma, __isl_take isl_val *v);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_down_val(
+	__isl_take isl_pw_multi_aff *pma, __isl_take isl_val *v);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_multi_val(
+	__isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin(
+	__isl_take isl_pw_multi_aff *pma1,
+	__isl_take isl_pw_multi_aff *pma2);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmax(
+	__isl_take isl_pw_multi_aff *pma1,
+	__isl_take isl_pw_multi_aff *pma2);
+
+__isl_give isl_multi_aff *isl_multi_aff_flatten_domain(
+	__isl_take isl_multi_aff *ma);
+
+__isl_export
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_product(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2);
+__isl_export
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_flat_range_product(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2);
+__isl_export
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_product(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_intersect_params(
+	__isl_take isl_pw_multi_aff *pma, __isl_take isl_set *set);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_intersect_domain(
+	__isl_take isl_pw_multi_aff *pma, __isl_take isl_set *set);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_subtract_domain(
+	__isl_take isl_pw_multi_aff *pma, __isl_take isl_set *set);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_domain_on_params(
+	__isl_take isl_pw_multi_aff *pma);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_align_params(
+	__isl_take isl_pw_multi_aff *pma, __isl_take isl_space *model);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_coalesce(
+	__isl_take isl_pw_multi_aff *pma);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_gist_params(
+	__isl_take isl_pw_multi_aff *pma, __isl_take isl_set *set);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_gist(
+	__isl_take isl_pw_multi_aff *pma, __isl_take isl_set *set);
+
+__isl_overload
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_pullback_multi_aff(
+	__isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_aff *ma);
+__isl_overload
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_pullback_pw_multi_aff(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2);
+
+int isl_pw_multi_aff_n_piece(__isl_keep isl_pw_multi_aff *pma);
+isl_stat isl_pw_multi_aff_foreach_piece(__isl_keep isl_pw_multi_aff *pma,
+	isl_stat (*fn)(__isl_take isl_set *set, __isl_take isl_multi_aff *maff,
+		    void *user), void *user);
+
+__isl_give isl_map *isl_map_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma);
+__isl_give isl_set *isl_set_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma);
+
+__isl_give char *isl_pw_multi_aff_to_str(__isl_keep isl_pw_multi_aff *pma);
+__isl_give isl_printer *isl_printer_print_pw_multi_aff(__isl_take isl_printer *p,
+	__isl_keep isl_pw_multi_aff *pma);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(__isl_take isl_set *set);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map(__isl_take isl_map *map);
+
+__isl_constructor
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx,
+	const char *str);
+void isl_pw_multi_aff_dump(__isl_keep isl_pw_multi_aff *pma);
+
+
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_empty(
+	__isl_take isl_space *space);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_aff(
+	__isl_take isl_aff *aff);
+__isl_constructor
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_pw_multi_aff(
+	__isl_take isl_pw_multi_aff *pma);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_domain(
+	__isl_take isl_union_set *uset);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_multi_val_on_domain(
+	__isl_take isl_union_set *domain, __isl_take isl_multi_val *mv);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_copy(
+	__isl_keep isl_union_pw_multi_aff *upma);
+__isl_null isl_union_pw_multi_aff *isl_union_pw_multi_aff_free(
+	__isl_take isl_union_pw_multi_aff *upma);
+
+__isl_give isl_union_pw_multi_aff *isl_union_set_identity_union_pw_multi_aff(
+	__isl_take isl_union_set *uset);
+
+__isl_give isl_union_pw_aff *isl_union_pw_multi_aff_get_union_pw_aff(
+	__isl_keep isl_union_pw_multi_aff *upma, int pos);
+
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_add_pw_multi_aff(
+	__isl_take isl_union_pw_multi_aff *upma,
+	__isl_take isl_pw_multi_aff *pma);
+
+isl_ctx *isl_union_pw_multi_aff_get_ctx(
+	__isl_keep isl_union_pw_multi_aff *upma);
+__isl_give isl_space *isl_union_pw_multi_aff_get_space(
+	__isl_keep isl_union_pw_multi_aff *upma);
+
+unsigned isl_union_pw_multi_aff_dim(__isl_keep isl_union_pw_multi_aff *upma,
+	enum isl_dim_type type);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_set_dim_name(
+	__isl_take isl_union_pw_multi_aff *upma,
+	enum isl_dim_type type, unsigned pos, const char *s);
+
+int isl_union_pw_multi_aff_find_dim_by_name(
+	__isl_keep isl_union_pw_multi_aff *upma, enum isl_dim_type type,
+	const char *name);
+
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_drop_dims(
+	__isl_take isl_union_pw_multi_aff *upma,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_reset_user(
+	__isl_take isl_union_pw_multi_aff *upma);
+
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_coalesce(
+	__isl_take isl_union_pw_multi_aff *upma);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_gist_params(
+	__isl_take isl_union_pw_multi_aff *upma, __isl_take isl_set *context);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_gist(
+	__isl_take isl_union_pw_multi_aff *upma,
+	__isl_take isl_union_set *context);
+
+__isl_overload
+__isl_give isl_union_pw_multi_aff *
+isl_union_pw_multi_aff_pullback_union_pw_multi_aff(
+	__isl_take isl_union_pw_multi_aff *upma1,
+	__isl_take isl_union_pw_multi_aff *upma2);
+
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_align_params(
+	__isl_take isl_union_pw_multi_aff *upma, __isl_take isl_space *model);
+
+int isl_union_pw_multi_aff_n_pw_multi_aff(
+	__isl_keep isl_union_pw_multi_aff *upma);
+
+isl_stat isl_union_pw_multi_aff_foreach_pw_multi_aff(
+	__isl_keep isl_union_pw_multi_aff *upma,
+	isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, void *user),
+	void *user);
+__isl_give isl_pw_multi_aff *isl_union_pw_multi_aff_extract_pw_multi_aff(
+	__isl_keep isl_union_pw_multi_aff *upma, __isl_take isl_space *space);
+
+isl_bool isl_union_pw_multi_aff_involves_nan(
+	__isl_keep isl_union_pw_multi_aff *upma);
+isl_bool isl_union_pw_multi_aff_plain_is_equal(
+	__isl_keep isl_union_pw_multi_aff *upma1,
+	__isl_keep isl_union_pw_multi_aff *upma2);
+
+__isl_give isl_union_set *isl_union_pw_multi_aff_domain(
+	__isl_take isl_union_pw_multi_aff *upma);
+
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_neg(
+	__isl_take isl_union_pw_multi_aff *upma);
+
+__isl_export
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_add(
+	__isl_take isl_union_pw_multi_aff *upma1,
+	__isl_take isl_union_pw_multi_aff *upma2);
+__isl_export
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_union_add(
+	__isl_take isl_union_pw_multi_aff *upma1,
+	__isl_take isl_union_pw_multi_aff *upma2);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_sub(
+	__isl_take isl_union_pw_multi_aff *upma1,
+	__isl_take isl_union_pw_multi_aff *upma2);
+
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_val(
+	__isl_take isl_union_pw_multi_aff *upma, __isl_take isl_val *val);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_down_val(
+	__isl_take isl_union_pw_multi_aff *upma, __isl_take isl_val *val);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_multi_val(
+	__isl_take isl_union_pw_multi_aff *upma, __isl_take isl_multi_val *mv);
+
+__isl_export
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_flat_range_product(
+	__isl_take isl_union_pw_multi_aff *upma1,
+	__isl_take isl_union_pw_multi_aff *upma2);
+
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_intersect_params(
+	__isl_take isl_union_pw_multi_aff *upma, __isl_take isl_set *set);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_intersect_domain(
+	__isl_take isl_union_pw_multi_aff *upma,
+	__isl_take isl_union_set *uset);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_subtract_domain(
+	__isl_take isl_union_pw_multi_aff *upma,
+	__isl_take isl_union_set *uset);
+
+__isl_overload
+__isl_give isl_union_map *isl_union_map_from_union_pw_multi_aff(
+	__isl_take isl_union_pw_multi_aff *upma);
+
+__isl_give isl_printer *isl_printer_print_union_pw_multi_aff(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma);
+
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_set(
+	__isl_take isl_union_set *uset);
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_map(
+	__isl_take isl_union_map *umap);
+
+__isl_constructor
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_read_from_str(
+	isl_ctx *ctx, const char *str);
+void isl_union_pw_multi_aff_dump(__isl_keep isl_union_pw_multi_aff *upma);
+__isl_give char *isl_union_pw_multi_aff_to_str(
+	__isl_keep isl_union_pw_multi_aff *upma);
+
+uint32_t isl_multi_pw_aff_get_hash(__isl_keep isl_multi_pw_aff *mpa);
+
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_identity(
+	__isl_take isl_space *space);
+__isl_constructor
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_multi_aff(
+	__isl_take isl_multi_aff *ma);
+__isl_constructor
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_aff(
+	__isl_take isl_pw_aff *pa);
+__isl_give isl_set *isl_multi_pw_aff_domain(__isl_take isl_multi_pw_aff *mpa);
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_intersect_params(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_set *set);
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_intersect_domain(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_set *domain);
+
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_coalesce(
+	__isl_take isl_multi_pw_aff *mpa);
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_gist(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_set *set);
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_gist_params(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_set *set);
+
+isl_bool isl_multi_pw_aff_is_cst(__isl_keep isl_multi_pw_aff *mpa);
+isl_bool isl_multi_pw_aff_is_equal(__isl_keep isl_multi_pw_aff *mpa1,
+	__isl_keep isl_multi_pw_aff *mpa2);
+
+__isl_overload
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_aff(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_multi_aff *ma);
+__isl_overload
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_pw_multi_aff(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_multi_aff *pma);
+__isl_overload
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_pw_aff(
+	__isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2);
+
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_move_dims(
+	__isl_take isl_multi_pw_aff *pma,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+
+__isl_give isl_set *isl_set_from_multi_pw_aff(__isl_take isl_multi_pw_aff *mpa);
+__isl_give isl_map *isl_map_from_multi_pw_aff(__isl_take isl_multi_pw_aff *mpa);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_pw_aff(
+	__isl_take isl_multi_pw_aff *mpa);
+__isl_constructor
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_multi_aff(
+	__isl_take isl_pw_multi_aff *pma);
+
+__isl_give isl_map *isl_multi_pw_aff_eq_map(__isl_take isl_multi_pw_aff *mpa1,
+	__isl_take isl_multi_pw_aff *mpa2);
+__isl_give isl_map *isl_multi_pw_aff_lex_lt_map(
+	__isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2);
+__isl_give isl_map *isl_multi_pw_aff_lex_gt_map(
+	__isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2);
+
+__isl_constructor
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(isl_ctx *ctx,
+	const char *str);
+__isl_give char *isl_multi_pw_aff_to_str(__isl_keep isl_multi_pw_aff *mpa);
+__isl_give isl_printer *isl_printer_print_multi_pw_aff(
+	__isl_take isl_printer *p, __isl_keep isl_multi_pw_aff *mpa);
+void isl_multi_pw_aff_dump(__isl_keep isl_multi_pw_aff *mpa);
+
+__isl_give isl_union_pw_aff *isl_union_pw_aff_copy(
+	__isl_keep isl_union_pw_aff *upa);
+__isl_null isl_union_pw_aff *isl_union_pw_aff_free(
+	__isl_take isl_union_pw_aff *upa);
+
+isl_ctx *isl_union_pw_aff_get_ctx(__isl_keep isl_union_pw_aff *upa);
+__isl_give isl_space *isl_union_pw_aff_get_space(
+	__isl_keep isl_union_pw_aff *upa);
+
+unsigned isl_union_pw_aff_dim(__isl_keep isl_union_pw_aff *upa,
+	enum isl_dim_type type);
+__isl_give isl_union_pw_aff *isl_union_pw_aff_set_dim_name(
+	__isl_take isl_union_pw_aff *upa, enum isl_dim_type type,
+	unsigned pos, const char *s);
+
+int isl_union_pw_aff_find_dim_by_name(__isl_keep isl_union_pw_aff *upa,
+	enum isl_dim_type type, const char *name);
+
+__isl_give isl_union_pw_aff *isl_union_pw_aff_drop_dims(
+	__isl_take isl_union_pw_aff *upa,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_union_pw_aff *isl_union_pw_aff_reset_user(
+	__isl_take isl_union_pw_aff *upa);
+
+__isl_give isl_union_pw_aff *isl_union_pw_aff_empty(
+	__isl_take isl_space *space);
+__isl_constructor
+__isl_give isl_union_pw_aff *isl_union_pw_aff_from_pw_aff(
+	__isl_take isl_pw_aff *pa);
+__isl_give isl_union_pw_aff *isl_union_pw_aff_val_on_domain(
+	__isl_take isl_union_set *domain, __isl_take isl_val *v);
+__isl_give isl_union_pw_aff *isl_union_pw_aff_aff_on_domain(
+	__isl_take isl_union_set *domain, __isl_take isl_aff *aff);
+__isl_give isl_union_pw_aff *isl_union_pw_aff_add_pw_aff(
+	__isl_take isl_union_pw_aff *upa, __isl_take isl_pw_aff *pa);
+
+__isl_constructor
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_pw_aff(
+	__isl_take isl_union_pw_aff *upa);
+
+int isl_union_pw_aff_n_pw_aff(__isl_keep isl_union_pw_aff *upa);
+
+isl_stat isl_union_pw_aff_foreach_pw_aff(__isl_keep isl_union_pw_aff *upa,
+	isl_stat (*fn)(__isl_take isl_pw_aff *pa, void *user), void *user);
+__isl_give isl_pw_aff *isl_union_pw_aff_extract_pw_aff(
+	__isl_keep isl_union_pw_aff *upa, __isl_take isl_space *space);
+
+isl_bool isl_union_pw_aff_involves_nan(__isl_keep isl_union_pw_aff *upa);
+isl_bool isl_union_pw_aff_plain_is_equal(__isl_keep isl_union_pw_aff *upa1,
+	__isl_keep isl_union_pw_aff *upa2);
+
+__isl_give isl_union_set *isl_union_pw_aff_domain(
+	__isl_take isl_union_pw_aff *upa);
+
+__isl_give isl_union_pw_aff *isl_union_pw_aff_neg(
+	__isl_take isl_union_pw_aff *upa);
+
+__isl_export
+__isl_give isl_union_pw_aff *isl_union_pw_aff_add(
+	__isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2);
+__isl_export
+__isl_give isl_union_pw_aff *isl_union_pw_aff_union_add(
+	__isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2);
+__isl_give isl_union_pw_aff *isl_union_pw_aff_sub(
+	__isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2);
+
+__isl_give isl_union_pw_aff *isl_union_pw_aff_coalesce(
+	__isl_take isl_union_pw_aff *upa);
+__isl_give isl_union_pw_aff *isl_union_pw_aff_gist(
+	__isl_take isl_union_pw_aff *upa, __isl_take isl_union_set *context);
+__isl_give isl_union_pw_aff *isl_union_pw_aff_gist_params(
+	__isl_take isl_union_pw_aff *upa, __isl_take isl_set *context);
+
+__isl_overload
+__isl_give isl_union_pw_aff *isl_union_pw_aff_pullback_union_pw_multi_aff(
+	__isl_take isl_union_pw_aff *upa,
+	__isl_take isl_union_pw_multi_aff *upma);
+
+__isl_give isl_union_pw_aff *isl_union_pw_aff_floor(
+	__isl_take isl_union_pw_aff *upa);
+
+__isl_give isl_union_pw_aff *isl_union_pw_aff_scale_val(
+	__isl_take isl_union_pw_aff *upa, __isl_take isl_val *v);
+__isl_give isl_union_pw_aff *isl_union_pw_aff_scale_down_val(
+	__isl_take isl_union_pw_aff *upa, __isl_take isl_val *v);
+__isl_give isl_union_pw_aff *isl_union_pw_aff_mod_val(
+	__isl_take isl_union_pw_aff *upa, __isl_take isl_val *f);
+
+__isl_give isl_union_pw_aff *isl_union_pw_aff_align_params(
+	__isl_take isl_union_pw_aff *upa, __isl_take isl_space *model);
+
+__isl_give isl_union_pw_aff *isl_union_pw_aff_intersect_params(
+	__isl_take isl_union_pw_aff *upa, __isl_take isl_set *set);
+__isl_give isl_union_pw_aff *isl_union_pw_aff_intersect_domain(
+	__isl_take isl_union_pw_aff *upa, __isl_take isl_union_set *uset);
+__isl_give isl_union_pw_aff *isl_union_pw_aff_subtract_domain(
+	__isl_take isl_union_pw_aff *upa, __isl_take isl_union_set *uset);
+
+__isl_give isl_union_pw_aff *isl_union_pw_aff_set_dim_name(
+	__isl_take isl_union_pw_aff *upa,
+	enum isl_dim_type type, unsigned pos, const char *s);
+
+__isl_give isl_union_set *isl_union_pw_aff_zero_union_set(
+	__isl_take isl_union_pw_aff *upa);
+
+__isl_give isl_union_map *isl_union_map_from_union_pw_aff(
+	__isl_take isl_union_pw_aff *upa);
+
+__isl_constructor
+__isl_give isl_union_pw_aff *isl_union_pw_aff_read_from_str(isl_ctx *ctx,
+	const char *str);
+__isl_give char *isl_union_pw_aff_to_str(__isl_keep isl_union_pw_aff *upa);
+__isl_give isl_printer *isl_printer_print_union_pw_aff(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa);
+void isl_union_pw_aff_dump(__isl_keep isl_union_pw_aff *upa);
+
+ISL_DECLARE_MULTI(union_pw_aff)
+ISL_DECLARE_MULTI_NEG(union_pw_aff)
+
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_aff(
+	__isl_take isl_multi_aff *ma);
+__isl_constructor
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_pw_aff(
+	__isl_take isl_union_pw_aff *upa);
+__isl_constructor
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_pw_aff(
+	__isl_take isl_multi_pw_aff *mpa);
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_val_on_domain(
+	__isl_take isl_union_set *domain, __isl_take isl_multi_val *mv);
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_aff_on_domain(
+	__isl_take isl_union_set *domain, __isl_take isl_multi_aff *ma);
+
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_floor(
+	__isl_take isl_multi_union_pw_aff *mupa);
+
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_domain(
+	__isl_take isl_multi_union_pw_aff *mupa,
+	__isl_take isl_union_set *uset);
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_params(
+	__isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *params);
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_range(
+	__isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *set);
+
+__isl_give isl_union_set *isl_multi_union_pw_aff_domain(
+	__isl_take isl_multi_union_pw_aff *mupa);
+
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_coalesce(
+	__isl_take isl_multi_union_pw_aff *aff);
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_gist(
+	__isl_take isl_multi_union_pw_aff *aff,
+	__isl_take isl_union_set *context);
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_gist_params(
+	__isl_take isl_multi_union_pw_aff *aff, __isl_take isl_set *context);
+
+__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_aff(
+	__isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff);
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_multi_aff(
+	__isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma);
+__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_pw_aff(
+	__isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_pw_aff *pa);
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_pw_multi_aff(
+	__isl_take isl_multi_union_pw_aff *mupa,
+	__isl_take isl_pw_multi_aff *pma);
+
+__isl_overload
+__isl_give isl_multi_union_pw_aff *
+isl_multi_union_pw_aff_pullback_union_pw_multi_aff(
+	__isl_take isl_multi_union_pw_aff *mupa,
+	__isl_take isl_union_pw_multi_aff *upma);
+
+__isl_give isl_union_pw_multi_aff *
+isl_union_pw_multi_aff_from_multi_union_pw_aff(
+	__isl_take isl_multi_union_pw_aff *mupa);
+
+__isl_export
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_union_add(
+	__isl_take isl_multi_union_pw_aff *mupa1,
+	__isl_take isl_multi_union_pw_aff *mupa2);
+
+__isl_give isl_multi_union_pw_aff *
+isl_multi_union_pw_aff_from_union_pw_multi_aff(
+	__isl_take isl_union_pw_multi_aff *upma);
+
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_map(
+	__isl_take isl_union_map *umap);
+__isl_overload
+__isl_give isl_union_map *isl_union_map_from_multi_union_pw_aff(
+	__isl_take isl_multi_union_pw_aff *mupa);
+
+__isl_give isl_union_set *isl_multi_union_pw_aff_zero_union_set(
+	__isl_take isl_multi_union_pw_aff *mupa);
+
+__isl_give isl_multi_pw_aff *isl_multi_union_pw_aff_extract_multi_pw_aff(
+	__isl_keep isl_multi_union_pw_aff *mupa, __isl_take isl_space *space);
+
+__isl_constructor
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_read_from_str(
+	isl_ctx *ctx, const char *str);
+__isl_give char *isl_multi_union_pw_aff_to_str(
+	__isl_keep isl_multi_union_pw_aff *mupa);
+__isl_give isl_printer *isl_printer_print_multi_union_pw_aff(
+	__isl_take isl_printer *p, __isl_keep isl_multi_union_pw_aff *mupa);
+void isl_multi_union_pw_aff_dump(__isl_keep isl_multi_union_pw_aff *mupa);
+
+ISL_DECLARE_LIST_FN(union_pw_aff)
+ISL_DECLARE_LIST_FN(union_pw_multi_aff)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/aff_type.h b/final/lib/External/isl/include/isl/aff_type.h
new file mode 100644
index 0000000..6cffa18
--- /dev/null
+++ b/final/lib/External/isl/include/isl/aff_type.h
@@ -0,0 +1,50 @@
+#ifndef ISL_AFF_TYPE_H
+#define ISL_AFF_TYPE_H
+
+#include <isl/list.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct __isl_subclass(isl_multi_aff) __isl_subclass(isl_pw_aff) isl_aff;
+typedef struct isl_aff isl_aff;
+
+ISL_DECLARE_LIST(aff)
+
+struct __isl_subclass(isl_multi_pw_aff) __isl_subclass(isl_pw_multi_aff)
+	__isl_subclass(isl_union_pw_aff) isl_pw_aff;
+typedef struct isl_pw_aff isl_pw_aff;
+
+ISL_DECLARE_LIST(pw_aff)
+
+struct __isl_subclass(isl_multi_union_pw_aff)
+	__isl_subclass(isl_union_pw_multi_aff) isl_union_pw_aff;
+typedef struct isl_union_pw_aff isl_union_pw_aff;
+
+ISL_DECLARE_LIST_TYPE(union_pw_aff)
+
+struct __isl_subclass(isl_multi_pw_aff) __isl_subclass(isl_pw_multi_aff)
+	isl_multi_aff;
+typedef struct isl_multi_aff isl_multi_aff;
+
+struct __isl_subclass(isl_multi_pw_aff) __isl_subclass(isl_union_pw_multi_aff)
+	isl_pw_multi_aff;
+typedef struct isl_pw_multi_aff isl_pw_multi_aff;
+
+struct __isl_export isl_union_pw_multi_aff;
+typedef struct isl_union_pw_multi_aff isl_union_pw_multi_aff;
+
+ISL_DECLARE_LIST_TYPE(union_pw_multi_aff)
+
+struct __isl_subclass(isl_multi_union_pw_aff) isl_multi_pw_aff;
+typedef struct isl_multi_pw_aff isl_multi_pw_aff;
+
+struct __isl_export isl_multi_union_pw_aff;
+typedef struct isl_multi_union_pw_aff isl_multi_union_pw_aff;
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/arg.h b/final/lib/External/isl/include/isl/arg.h
new file mode 100644
index 0000000..0d37d1c
--- /dev/null
+++ b/final/lib/External/isl/include/isl/arg.h
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_ARG_H
+#define ISL_ARG_H
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_arg_choice {
+	const char	*name;
+	unsigned	 value;
+};
+
+struct isl_arg_flags {
+	const char	*name;
+	unsigned	 mask;
+	unsigned	 value;
+};
+
+enum isl_arg_type {
+	isl_arg_end,
+	isl_arg_alias,
+	isl_arg_arg,
+	isl_arg_bool,
+	isl_arg_child,
+	isl_arg_choice,
+	isl_arg_flags,
+	isl_arg_footer,
+	isl_arg_int,
+	isl_arg_user,
+	isl_arg_long,
+	isl_arg_ulong,
+	isl_arg_str,
+	isl_arg_str_list,
+	isl_arg_version
+};
+
+struct isl_args;
+
+struct isl_arg {
+	enum isl_arg_type	 type;
+	char			 short_name;
+	const char		*long_name;
+	const char		*argument_name;
+	size_t			 offset;
+	const char		*help_msg;
+#define ISL_ARG_SINGLE_DASH	(1 << 0)
+#define ISL_ARG_BOOL_ARG	(1 << 1)
+#define ISL_ARG_HIDDEN		(1 << 2)
+	unsigned		 flags;
+	union {
+	struct {
+		struct isl_arg_choice	*choice;
+		unsigned	 	 default_value;
+		unsigned	 	 default_selected;
+		int (*set)(void *opt, unsigned val);
+	} choice;
+	struct {
+		struct isl_arg_flags	*flags;
+		unsigned	 	 default_value;
+	} flags;
+	struct {
+		unsigned		 default_value;
+		int (*set)(void *opt, unsigned val);
+	} b;
+	struct {
+		int			default_value;
+	} i;
+	struct {
+		long		 	default_value;
+		long		 	default_selected;
+		int (*set)(void *opt, long val);
+	} l;
+	struct {
+		unsigned long		default_value;
+	} ul;
+	struct {
+		const char		*default_value;
+	} str;
+	struct {
+		size_t			 offset_n;
+	} str_list;
+	struct {
+		struct isl_args		*child;
+	} child;
+	struct {
+		void (*print_version)(void);
+	} version;
+	struct {
+		int (*init)(void*);
+		void (*clear)(void*);
+	} user;
+	} u;
+};
+
+struct isl_args {
+	size_t			 options_size;
+	struct isl_arg		*args;
+};
+
+#define ISL_ARGS_START(s,name)						\
+	struct isl_arg name ## LIST[];					\
+	struct isl_args name = { sizeof(s), name ## LIST };		\
+	struct isl_arg name ## LIST[] = {
+#define ISL_ARGS_END							\
+	{ isl_arg_end } };
+
+#define ISL_ARG_ALIAS(l)	{					\
+	.type = isl_arg_alias,						\
+	.long_name = l,							\
+},
+#define ISL_ARG_ARG(st,f,a,d)	{					\
+	.type = isl_arg_arg,						\
+	.argument_name = a,						\
+	.offset = offsetof(st, f),					\
+	.u = { .str = { .default_value = d } }				\
+},
+#define ISL_ARG_FOOTER(h)	{					\
+	.type = isl_arg_footer,						\
+	.help_msg = h,							\
+},
+#define ISL_ARG_CHOICE(st,f,s,l,c,d,h)	{				\
+	.type = isl_arg_choice,						\
+	.short_name = s,						\
+	.long_name = l,							\
+	.offset = offsetof(st, f),					\
+	.help_msg = h,							\
+	.u = { .choice = { .choice = c, .default_value = d,		\
+			    .default_selected = d, .set = NULL } }	\
+},
+#define ISL_ARG_OPT_CHOICE(st,f,s,l,c,d,ds,h)	{			\
+	.type = isl_arg_choice,						\
+	.short_name = s,						\
+	.long_name = l,							\
+	.offset = offsetof(st, f),					\
+	.help_msg = h,							\
+	.u = { .choice = { .choice = c, .default_value = d,		\
+			    .default_selected = ds, .set = NULL } }	\
+},
+#define ISL_ARG_PHANTOM_USER_CHOICE_F(s,l,c,setter,d,h,fl)	{	\
+	.type = isl_arg_choice,						\
+	.short_name = s,						\
+	.long_name = l,							\
+	.offset = -1,							\
+	.help_msg = h,							\
+	.flags = fl,							\
+	.u = { .choice = { .choice = c, .default_value = d,		\
+			    .default_selected = d, .set = setter } }	\
+},
+#define ISL_ARG_USER_OPT_CHOICE(st,f,s,l,c,setter,d,ds,h)	{	\
+	.type = isl_arg_choice,						\
+	.short_name = s,						\
+	.long_name = l,							\
+	.offset = offsetof(st, f),					\
+	.help_msg = h,							\
+	.u = { .choice = { .choice = c, .default_value = d,		\
+			    .default_selected = ds, .set = setter } }	\
+},
+#define _ISL_ARG_BOOL_F(o,s,l,setter,d,h,fl)	{			\
+	.type = isl_arg_bool,						\
+	.short_name = s,						\
+	.long_name = l,							\
+	.offset = o,							\
+	.help_msg = h,							\
+	.flags = fl,							\
+	.u = { .b = { .default_value = d, .set = setter } }		\
+},
+#define ISL_ARG_BOOL_F(st,f,s,l,d,h,fl)					\
+	_ISL_ARG_BOOL_F(offsetof(st, f),s,l,NULL,d,h,fl)
+#define ISL_ARG_BOOL(st,f,s,l,d,h)					\
+	ISL_ARG_BOOL_F(st,f,s,l,d,h,0)
+#define ISL_ARG_PHANTOM_BOOL_F(s,l,setter,h,fl)				\
+	_ISL_ARG_BOOL_F(-1,s,l,setter,0,h,fl)
+#define ISL_ARG_PHANTOM_BOOL(s,l,setter,h)				\
+	ISL_ARG_PHANTOM_BOOL_F(s,l,setter,h,0)
+#define ISL_ARG_INT_F(st,f,s,l,a,d,h,fl)	{			\
+	.type = isl_arg_int,						\
+	.short_name = s,						\
+	.long_name = l,							\
+	.argument_name = a,						\
+	.offset = offsetof(st, f),					\
+	.help_msg = h,							\
+	.flags = fl,							\
+	.u = { .ul = { .default_value = d } }				\
+},
+#define ISL_ARG_INT(st,f,s,l,a,d,h)					\
+	ISL_ARG_INT_F(st,f,s,l,a,d,h,0)
+#define ISL_ARG_LONG(st,f,s,lo,d,h)	{				\
+	.type = isl_arg_long,						\
+	.short_name = s,						\
+	.long_name = lo,						\
+	.offset = offsetof(st, f),					\
+	.help_msg = h,							\
+	.u = { .l = { .default_value = d, .default_selected = d,	\
+		      .set = NULL } }					\
+},
+#define ISL_ARG_USER_LONG(st,f,s,lo,setter,d,h)	{			\
+	.type = isl_arg_long,						\
+	.short_name = s,						\
+	.long_name = lo,						\
+	.offset = offsetof(st, f),					\
+	.help_msg = h,							\
+	.u = { .l = { .default_value = d, .default_selected = d,	\
+		      .set = setter } }					\
+},
+#define ISL_ARG_OPT_LONG(st,f,s,lo,d,ds,h)	{			\
+	.type = isl_arg_long,						\
+	.short_name = s,						\
+	.long_name = lo,						\
+	.offset = offsetof(st, f),					\
+	.help_msg = h,							\
+	.u = { .l = { .default_value = d, .default_selected = ds,	\
+		      .set = NULL } }					\
+},
+#define ISL_ARG_ULONG(st,f,s,l,d,h)	{				\
+	.type = isl_arg_ulong,						\
+	.short_name = s,						\
+	.long_name = l,							\
+	.offset = offsetof(st, f),					\
+	.help_msg = h,							\
+	.u = { .ul = { .default_value = d } }				\
+},
+#define ISL_ARG_STR_F(st,f,s,l,a,d,h,fl)	{			\
+	.type = isl_arg_str,						\
+	.short_name = s,						\
+	.long_name = l,							\
+	.argument_name = a,						\
+	.offset = offsetof(st, f),					\
+	.help_msg = h,							\
+	.flags = fl,							\
+	.u = { .str = { .default_value = d } }				\
+},
+#define ISL_ARG_STR(st,f,s,l,a,d,h)					\
+	ISL_ARG_STR_F(st,f,s,l,a,d,h,0)
+#define ISL_ARG_STR_LIST(st,f_n,f_l,s,l,a,h)	{			\
+	.type = isl_arg_str_list,					\
+	.short_name = s,						\
+	.long_name = l,							\
+	.argument_name = a,						\
+	.offset = offsetof(st, f_l),					\
+	.help_msg = h,							\
+	.u = { .str_list = { .offset_n = offsetof(st, f_n) } }		\
+},
+#define _ISL_ARG_CHILD(o,l,c,h,fl)	{				\
+	.type = isl_arg_child,						\
+	.long_name = l,							\
+	.offset = o,							\
+	.help_msg = h,							\
+	.flags = fl,							\
+	.u = { .child = { .child = c } }				\
+},
+#define ISL_ARG_CHILD(st,f,l,c,h)					\
+	_ISL_ARG_CHILD(offsetof(st, f),l,c,h,0)
+#define ISL_ARG_GROUP_F(l,c,h,fl)					\
+	_ISL_ARG_CHILD(-1,l,c,h,fl)
+#define ISL_ARG_GROUP(l,c,h)						\
+	ISL_ARG_GROUP_F(l,c,h,0)
+#define ISL_ARG_FLAGS(st,f,s,l,c,d,h)	{				\
+	.type = isl_arg_flags,						\
+	.short_name = s,						\
+	.long_name = l,							\
+	.offset = offsetof(st, f),					\
+	.help_msg = h,							\
+	.u = { .flags = { .flags = c, .default_value = d } }		\
+},
+#define ISL_ARG_USER(st,f,i,c) {					\
+	.type = isl_arg_user,						\
+	.offset = offsetof(st, f),					\
+	.u = { .user = { .init = i, .clear = c} }			\
+},
+#define ISL_ARG_VERSION(print) {					\
+	.type = isl_arg_version,					\
+	.u = { .version = { .print_version = print } }			\
+},
+
+#define ISL_ARG_ALL		(1 << 0)
+#define ISL_ARG_SKIP_HELP	(1 << 1)
+
+void isl_args_set_defaults(struct isl_args *args, void *opt);
+void isl_args_free(struct isl_args *args, void *opt);
+int isl_args_parse(struct isl_args *args, int argc, char **argv, void *opt,
+	unsigned flags);
+
+#define ISL_ARG_DECL(prefix,st,args)					\
+extern struct isl_args args;						\
+st *prefix ## _new_with_defaults(void);					\
+void prefix ## _free(st *opt);						\
+int prefix ## _parse(st *opt, int argc, char **argv, unsigned flags);
+
+#define ISL_ARG_DEF(prefix,st,args)					\
+st *prefix ## _new_with_defaults()					\
+{									\
+	st *opt = (st *)calloc(1, sizeof(st));				\
+	if (opt)							\
+		isl_args_set_defaults(&(args), opt);			\
+	return opt;							\
+}									\
+									\
+void prefix ## _free(st *opt)						\
+{									\
+	isl_args_free(&(args), opt);					\
+}									\
+									\
+int prefix ## _parse(st *opt, int argc, char **argv, unsigned flags)	\
+{									\
+	return isl_args_parse(&(args), argc, argv, opt, flags);		\
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/ast.h b/final/lib/External/isl/include/isl/ast.h
new file mode 100644
index 0000000..2793e16
--- /dev/null
+++ b/final/lib/External/isl/include/isl/ast.h
@@ -0,0 +1,193 @@
+#ifndef ISL_AST_H
+#define ISL_AST_H
+
+#include <isl/ctx.h>
+#include <isl/ast_type.h>
+#include <isl/id.h>
+#include <isl/id_to_ast_expr.h>
+#include <isl/val.h>
+#include <isl/list.h>
+#include <isl/printer.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+isl_stat isl_options_set_ast_iterator_type(isl_ctx *ctx, const char *val);
+const char *isl_options_get_ast_iterator_type(isl_ctx *ctx);
+
+isl_stat isl_options_set_ast_always_print_block(isl_ctx *ctx, int val);
+int isl_options_get_ast_always_print_block(isl_ctx *ctx);
+
+__isl_give isl_ast_expr *isl_ast_expr_from_val(__isl_take isl_val *v);
+__isl_give isl_ast_expr *isl_ast_expr_from_id(__isl_take isl_id *id);
+__isl_give isl_ast_expr *isl_ast_expr_neg(__isl_take isl_ast_expr *expr);
+__isl_give isl_ast_expr *isl_ast_expr_add(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_sub(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_mul(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_div(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_pdiv_q(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_pdiv_r(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_and(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_and_then(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_or(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_or_else(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_le(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_lt(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_ge(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_gt(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_eq(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2);
+__isl_give isl_ast_expr *isl_ast_expr_access(__isl_take isl_ast_expr *array,
+	__isl_take isl_ast_expr_list *indices);
+__isl_give isl_ast_expr *isl_ast_expr_call(__isl_take isl_ast_expr *function,
+	__isl_take isl_ast_expr_list *arguments);
+__isl_give isl_ast_expr *isl_ast_expr_address_of(__isl_take isl_ast_expr *expr);
+
+__isl_give isl_ast_expr *isl_ast_expr_copy(__isl_keep isl_ast_expr *expr);
+__isl_null isl_ast_expr *isl_ast_expr_free(__isl_take isl_ast_expr *expr);
+
+isl_ctx *isl_ast_expr_get_ctx(__isl_keep isl_ast_expr *expr);
+enum isl_ast_expr_type isl_ast_expr_get_type(__isl_keep isl_ast_expr *expr);
+__isl_give isl_val *isl_ast_expr_get_val(__isl_keep isl_ast_expr *expr);
+__isl_give isl_id *isl_ast_expr_get_id(__isl_keep isl_ast_expr *expr);
+
+enum isl_ast_op_type isl_ast_expr_get_op_type(__isl_keep isl_ast_expr *expr);
+int isl_ast_expr_get_op_n_arg(__isl_keep isl_ast_expr *expr);
+__isl_give isl_ast_expr *isl_ast_expr_get_op_arg(__isl_keep isl_ast_expr *expr,
+	int pos);
+__isl_give isl_ast_expr *isl_ast_expr_set_op_arg(__isl_take isl_ast_expr *expr,
+	int pos, __isl_take isl_ast_expr *arg);
+
+isl_bool isl_ast_expr_is_equal(__isl_keep isl_ast_expr *expr1,
+	__isl_keep isl_ast_expr *expr2);
+
+__isl_give isl_ast_expr *isl_ast_expr_substitute_ids(
+	__isl_take isl_ast_expr *expr, __isl_take isl_id_to_ast_expr *id2expr);
+
+__isl_give isl_printer *isl_printer_print_ast_expr(__isl_take isl_printer *p,
+	__isl_keep isl_ast_expr *expr);
+void isl_ast_expr_dump(__isl_keep isl_ast_expr *expr);
+__isl_give char *isl_ast_expr_to_str(__isl_keep isl_ast_expr *expr);
+__isl_export
+__isl_give char *isl_ast_expr_to_C_str(__isl_keep isl_ast_expr *expr);
+
+__isl_give isl_ast_node *isl_ast_node_alloc_user(__isl_take isl_ast_expr *expr);
+__isl_give isl_ast_node *isl_ast_node_copy(__isl_keep isl_ast_node *node);
+__isl_null isl_ast_node *isl_ast_node_free(__isl_take isl_ast_node *node);
+
+isl_ctx *isl_ast_node_get_ctx(__isl_keep isl_ast_node *node);
+enum isl_ast_node_type isl_ast_node_get_type(__isl_keep isl_ast_node *node);
+
+__isl_give isl_ast_node *isl_ast_node_set_annotation(
+	__isl_take isl_ast_node *node, __isl_take isl_id *annotation);
+__isl_give isl_id *isl_ast_node_get_annotation(__isl_keep isl_ast_node *node);
+
+__isl_give isl_ast_expr *isl_ast_node_for_get_iterator(
+	__isl_keep isl_ast_node *node);
+__isl_give isl_ast_expr *isl_ast_node_for_get_init(
+	__isl_keep isl_ast_node *node);
+__isl_give isl_ast_expr *isl_ast_node_for_get_cond(
+	__isl_keep isl_ast_node *node);
+__isl_give isl_ast_expr *isl_ast_node_for_get_inc(
+	__isl_keep isl_ast_node *node);
+__isl_give isl_ast_node *isl_ast_node_for_get_body(
+	__isl_keep isl_ast_node *node);
+isl_bool isl_ast_node_for_is_degenerate(__isl_keep isl_ast_node *node);
+
+__isl_give isl_ast_expr *isl_ast_node_if_get_cond(
+	__isl_keep isl_ast_node *node);
+__isl_give isl_ast_node *isl_ast_node_if_get_then(
+	__isl_keep isl_ast_node *node);
+isl_bool isl_ast_node_if_has_else(__isl_keep isl_ast_node *node);
+__isl_give isl_ast_node *isl_ast_node_if_get_else(
+	__isl_keep isl_ast_node *node);
+
+__isl_give isl_ast_node_list *isl_ast_node_block_get_children(
+	__isl_keep isl_ast_node *node);
+
+__isl_give isl_id *isl_ast_node_mark_get_id(__isl_keep isl_ast_node *node);
+__isl_give isl_ast_node *isl_ast_node_mark_get_node(
+	__isl_keep isl_ast_node *node);
+
+__isl_give isl_ast_expr *isl_ast_node_user_get_expr(
+	__isl_keep isl_ast_node *node);
+
+isl_stat isl_ast_node_foreach_descendant_top_down(
+	__isl_keep isl_ast_node *node,
+	isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user), void *user);
+
+__isl_give isl_printer *isl_printer_print_ast_node(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node);
+void isl_ast_node_dump(__isl_keep isl_ast_node *node);
+__isl_give char *isl_ast_node_to_str(__isl_keep isl_ast_node *node);
+
+__isl_give isl_ast_print_options *isl_ast_print_options_alloc(isl_ctx *ctx);
+__isl_give isl_ast_print_options *isl_ast_print_options_copy(
+	__isl_keep isl_ast_print_options *options);
+__isl_null isl_ast_print_options *isl_ast_print_options_free(
+	__isl_take isl_ast_print_options *options);
+isl_ctx *isl_ast_print_options_get_ctx(
+	__isl_keep isl_ast_print_options *options);
+
+__isl_give isl_ast_print_options *isl_ast_print_options_set_print_user(
+	__isl_take isl_ast_print_options *options,
+	__isl_give isl_printer *(*print_user)(__isl_take isl_printer *p,
+		__isl_take isl_ast_print_options *options,
+		__isl_keep isl_ast_node *node, void *user),
+	void *user);
+__isl_give isl_ast_print_options *isl_ast_print_options_set_print_for(
+	__isl_take isl_ast_print_options *options,
+	__isl_give isl_printer *(*print_for)(__isl_take isl_printer *p,
+		__isl_take isl_ast_print_options *options,
+		__isl_keep isl_ast_node *node, void *user),
+	void *user);
+
+isl_stat isl_options_set_ast_print_macro_once(isl_ctx *ctx, int val);
+int isl_options_get_ast_print_macro_once(isl_ctx *ctx);
+
+isl_stat isl_ast_expr_foreach_ast_op_type(__isl_keep isl_ast_expr *expr,
+	isl_stat (*fn)(enum isl_ast_op_type type, void *user), void *user);
+isl_stat isl_ast_node_foreach_ast_op_type(__isl_keep isl_ast_node *node,
+	isl_stat (*fn)(enum isl_ast_op_type type, void *user), void *user);
+__isl_give isl_printer *isl_ast_op_type_set_print_name(
+	__isl_take isl_printer *p, enum isl_ast_op_type type,
+	__isl_keep const char *name);
+__isl_give isl_printer *isl_ast_op_type_print_macro(
+	enum isl_ast_op_type type, __isl_take isl_printer *p);
+__isl_give isl_printer *isl_ast_expr_print_macros(
+	__isl_keep isl_ast_expr *expr, __isl_take isl_printer *p);
+__isl_give isl_printer *isl_ast_node_print_macros(
+	__isl_keep isl_ast_node *node, __isl_take isl_printer *p);
+__isl_give isl_printer *isl_ast_node_print(__isl_keep isl_ast_node *node,
+	__isl_take isl_printer *p,
+	__isl_take isl_ast_print_options *options);
+__isl_give isl_printer *isl_ast_node_for_print(__isl_keep isl_ast_node *node,
+	__isl_take isl_printer *p,
+	__isl_take isl_ast_print_options *options);
+__isl_give isl_printer *isl_ast_node_if_print(__isl_keep isl_ast_node *node,
+	__isl_take isl_printer *p,
+	__isl_take isl_ast_print_options *options);
+
+__isl_export
+__isl_give char *isl_ast_node_to_C_str(__isl_keep isl_ast_node *node);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/ast_build.h b/final/lib/External/isl/include/isl/ast_build.h
new file mode 100644
index 0000000..bf08e03
--- /dev/null
+++ b/final/lib/External/isl/include/isl/ast_build.h
@@ -0,0 +1,128 @@
+#ifndef ISL_AST_CONTEXT_H
+#define ISL_AST_CONTEXT_H
+
+#include <isl/ctx.h>
+#include <isl/set.h>
+#include <isl/ast.h>
+#include <isl/schedule.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct __isl_export isl_ast_build;
+typedef struct isl_ast_build isl_ast_build;
+
+
+isl_stat isl_options_set_ast_build_atomic_upper_bound(isl_ctx *ctx, int val);
+int isl_options_get_ast_build_atomic_upper_bound(isl_ctx *ctx);
+
+isl_stat isl_options_set_ast_build_prefer_pdiv(isl_ctx *ctx, int val);
+int isl_options_get_ast_build_prefer_pdiv(isl_ctx *ctx);
+
+isl_stat isl_options_set_ast_build_detect_min_max(isl_ctx *ctx, int val);
+int isl_options_get_ast_build_detect_min_max(isl_ctx *ctx);
+
+isl_stat isl_options_set_ast_build_exploit_nested_bounds(isl_ctx *ctx, int val);
+int isl_options_get_ast_build_exploit_nested_bounds(isl_ctx *ctx);
+
+isl_stat isl_options_set_ast_build_group_coscheduled(isl_ctx *ctx, int val);
+int isl_options_get_ast_build_group_coscheduled(isl_ctx *ctx);
+
+#define ISL_AST_BUILD_SEPARATION_BOUNDS_EXPLICIT		0
+#define ISL_AST_BUILD_SEPARATION_BOUNDS_IMPLICIT		1
+isl_stat isl_options_set_ast_build_separation_bounds(isl_ctx *ctx, int val);
+int isl_options_get_ast_build_separation_bounds(isl_ctx *ctx);
+
+isl_stat isl_options_set_ast_build_scale_strides(isl_ctx *ctx, int val);
+int isl_options_get_ast_build_scale_strides(isl_ctx *ctx);
+
+isl_stat isl_options_set_ast_build_allow_else(isl_ctx *ctx, int val);
+int isl_options_get_ast_build_allow_else(isl_ctx *ctx);
+
+isl_stat isl_options_set_ast_build_allow_or(isl_ctx *ctx, int val);
+int isl_options_get_ast_build_allow_or(isl_ctx *ctx);
+
+isl_ctx *isl_ast_build_get_ctx(__isl_keep isl_ast_build *build);
+
+__isl_constructor
+__isl_give isl_ast_build *isl_ast_build_alloc(isl_ctx *ctx);
+__isl_export
+__isl_give isl_ast_build *isl_ast_build_from_context(__isl_take isl_set *set);
+
+__isl_give isl_space *isl_ast_build_get_schedule_space(
+	__isl_keep isl_ast_build *build);
+__isl_give isl_union_map *isl_ast_build_get_schedule(
+	__isl_keep isl_ast_build *build);
+
+__isl_give isl_ast_build *isl_ast_build_restrict(
+	__isl_take isl_ast_build *build, __isl_take isl_set *set);
+
+__isl_give isl_ast_build *isl_ast_build_copy(
+	__isl_keep isl_ast_build *build);
+__isl_null isl_ast_build *isl_ast_build_free(
+	__isl_take isl_ast_build *build);
+
+__isl_give isl_ast_build *isl_ast_build_set_options(
+	__isl_take isl_ast_build *build,
+	__isl_take isl_union_map *options);
+__isl_give isl_ast_build *isl_ast_build_set_iterators(
+	__isl_take isl_ast_build *build,
+	__isl_take isl_id_list *iterators);
+__isl_give isl_ast_build *isl_ast_build_set_at_each_domain(
+	__isl_take isl_ast_build *build,
+	__isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node,
+		__isl_keep isl_ast_build *build, void *user), void *user);
+__isl_give isl_ast_build *isl_ast_build_set_before_each_for(
+	__isl_take isl_ast_build *build,
+	__isl_give isl_id *(*fn)(__isl_keep isl_ast_build *build,
+		void *user), void *user);
+__isl_give isl_ast_build *isl_ast_build_set_after_each_for(
+	__isl_take isl_ast_build *build,
+	__isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node,
+		__isl_keep isl_ast_build *build, void *user), void *user);
+__isl_give isl_ast_build *isl_ast_build_set_before_each_mark(
+	__isl_take isl_ast_build *build,
+	isl_stat (*fn)(__isl_keep isl_id *mark, __isl_keep isl_ast_build *build,
+		void *user), void *user);
+__isl_give isl_ast_build *isl_ast_build_set_after_each_mark(
+	__isl_take isl_ast_build *build,
+	__isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node,
+		__isl_keep isl_ast_build *build, void *user), void *user);
+__isl_give isl_ast_build *isl_ast_build_set_create_leaf(
+	__isl_take isl_ast_build *build,
+	__isl_give isl_ast_node *(*fn)(__isl_take isl_ast_build *build,
+		void *user), void *user);
+
+__isl_overload
+__isl_give isl_ast_expr *isl_ast_build_expr_from_set(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *set);
+__isl_overload
+__isl_give isl_ast_expr *isl_ast_build_expr_from_pw_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa);
+__isl_overload
+__isl_give isl_ast_expr *isl_ast_build_access_from_pw_multi_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma);
+__isl_overload
+__isl_give isl_ast_expr *isl_ast_build_access_from_multi_pw_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_multi_pw_aff *mpa);
+__isl_overload
+__isl_give isl_ast_expr *isl_ast_build_call_from_pw_multi_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma);
+__isl_overload
+__isl_give isl_ast_expr *isl_ast_build_call_from_multi_pw_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_multi_pw_aff *mpa);
+
+__isl_give isl_ast_node *isl_ast_build_node_from_schedule(
+	__isl_keep isl_ast_build *build, __isl_take isl_schedule *schedule);
+__isl_export
+__isl_give isl_ast_node *isl_ast_build_node_from_schedule_map(
+	__isl_keep isl_ast_build *build, __isl_take isl_union_map *schedule);
+__isl_give isl_ast_node *isl_ast_build_ast_from_schedule(
+	__isl_keep isl_ast_build *build, __isl_take isl_union_map *schedule);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/ast_type.h b/final/lib/External/isl/include/isl/ast_type.h
new file mode 100644
index 0000000..1e09b3b
--- /dev/null
+++ b/final/lib/External/isl/include/isl/ast_type.h
@@ -0,0 +1,80 @@
+#ifndef ISL_AST_TYPE_H
+#define ISL_AST_TYPE_H
+
+#include <isl/list.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct __isl_export isl_ast_expr;
+typedef struct isl_ast_expr isl_ast_expr;
+
+struct __isl_export isl_ast_node;
+typedef struct isl_ast_node isl_ast_node;
+
+enum isl_ast_op_type {
+	isl_ast_op_error = -1,
+	isl_ast_op_and,
+	isl_ast_op_and_then,
+	isl_ast_op_or,
+	isl_ast_op_or_else,
+	isl_ast_op_max,
+	isl_ast_op_min,
+	isl_ast_op_minus,
+	isl_ast_op_add,
+	isl_ast_op_sub,
+	isl_ast_op_mul,
+	isl_ast_op_div,
+	isl_ast_op_fdiv_q,	/* Round towards -infty */
+	isl_ast_op_pdiv_q,	/* Dividend is non-negative */
+	isl_ast_op_pdiv_r,	/* Dividend is non-negative */
+	isl_ast_op_zdiv_r,	/* Result only compared against zero */
+	isl_ast_op_cond,
+	isl_ast_op_select,
+	isl_ast_op_eq,
+	isl_ast_op_le,
+	isl_ast_op_lt,
+	isl_ast_op_ge,
+	isl_ast_op_gt,
+	isl_ast_op_call,
+	isl_ast_op_access,
+	isl_ast_op_member,
+	isl_ast_op_address_of
+};
+
+enum isl_ast_expr_type {
+	isl_ast_expr_error = -1,
+	isl_ast_expr_op,
+	isl_ast_expr_id,
+	isl_ast_expr_int
+};
+
+enum isl_ast_node_type {
+	isl_ast_node_error = -1,
+	isl_ast_node_for = 1,
+	isl_ast_node_if,
+	isl_ast_node_block,
+	isl_ast_node_mark,
+	isl_ast_node_user
+};
+
+enum isl_ast_loop_type {
+	isl_ast_loop_error = -1,
+	isl_ast_loop_default = 0,
+	isl_ast_loop_atomic,
+	isl_ast_loop_unroll,
+	isl_ast_loop_separate
+};
+
+struct isl_ast_print_options;
+typedef struct isl_ast_print_options isl_ast_print_options;
+
+ISL_DECLARE_LIST(ast_expr)
+ISL_DECLARE_LIST(ast_node)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/band.h b/final/lib/External/isl/include/isl/band.h
new file mode 100644
index 0000000..6dd19ba
--- /dev/null
+++ b/final/lib/External/isl/include/isl/band.h
@@ -0,0 +1,56 @@
+#ifndef ISL_BAND_H
+#define ISL_BAND_H
+
+#include <isl/printer.h>
+#include <isl/list.h>
+#include <isl/union_map_type.h>
+#include <isl/vec.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_band;
+typedef struct isl_band isl_band;
+
+ISL_DECLARE_LIST(band)
+
+__isl_give isl_band *isl_band_copy(__isl_keep isl_band *band);
+__isl_null isl_band *isl_band_free(__isl_take isl_band *band);
+
+isl_ctx *isl_band_get_ctx(__isl_keep isl_band *band);
+
+int isl_band_has_children(__isl_keep isl_band *band);
+__isl_give isl_band_list *isl_band_get_children(
+	__isl_keep isl_band *band);
+
+__isl_give isl_union_map *isl_band_get_prefix_schedule(
+	__isl_keep isl_band *band);
+__isl_give isl_union_map *isl_band_get_partial_schedule(
+	__isl_keep isl_band *band);
+__isl_give isl_union_map *isl_band_get_suffix_schedule(
+	__isl_keep isl_band *band);
+
+isl_stat isl_options_set_tile_scale_tile_loops(isl_ctx *ctx, int val);
+int isl_options_get_tile_scale_tile_loops(isl_ctx *ctx);
+isl_stat isl_options_set_tile_shift_point_loops(isl_ctx *ctx, int val);
+int isl_options_get_tile_shift_point_loops(isl_ctx *ctx);
+
+int isl_band_tile(__isl_keep isl_band *band, __isl_take isl_vec *sizes);
+int isl_band_split(__isl_keep isl_band *band, int pos);
+
+int isl_band_n_member(__isl_keep isl_band *band);
+int isl_band_member_is_coincident(__isl_keep isl_band *band, int pos);
+
+int isl_band_list_foreach_band(__isl_keep isl_band_list *list,
+	int (*fn)(__isl_keep isl_band *band, void *user), void *user);
+
+__isl_give isl_printer *isl_printer_print_band(__isl_take isl_printer *p,
+	__isl_keep isl_band *band);
+void isl_band_dump(__isl_keep isl_band *band);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/constraint.h b/final/lib/External/isl/include/isl/constraint.h
new file mode 100644
index 0000000..92fa029
--- /dev/null
+++ b/final/lib/External/isl/include/isl/constraint.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_CONSTRAINT_H
+#define ISL_CONSTRAINT_H
+
+#include <isl/local_space.h>
+#include <isl/space.h>
+#include <isl/aff_type.h>
+#include <isl/set_type.h>
+#include <isl/list.h>
+#include <isl/val.h>
+#include <isl/printer.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_constraint;
+typedef struct isl_constraint isl_constraint;
+
+ISL_DECLARE_LIST(constraint)
+
+isl_ctx *isl_constraint_get_ctx(__isl_keep isl_constraint *c);
+
+__isl_give isl_constraint *isl_constraint_alloc_equality(
+	__isl_take isl_local_space *ls);
+__isl_give isl_constraint *isl_constraint_alloc_inequality(
+	__isl_take isl_local_space *ls);
+__isl_give isl_constraint *isl_equality_alloc(__isl_take isl_local_space *ls);
+__isl_give isl_constraint *isl_inequality_alloc(__isl_take isl_local_space *ls);
+
+struct isl_constraint *isl_constraint_cow(struct isl_constraint *c);
+struct isl_constraint *isl_constraint_copy(struct isl_constraint *c);
+__isl_null isl_constraint *isl_constraint_free(__isl_take isl_constraint *c);
+
+int isl_basic_map_n_constraint(__isl_keep isl_basic_map *bmap);
+int isl_basic_set_n_constraint(__isl_keep isl_basic_set *bset);
+isl_stat isl_basic_map_foreach_constraint(__isl_keep isl_basic_map *bmap,
+	isl_stat (*fn)(__isl_take isl_constraint *c, void *user), void *user);
+isl_stat isl_basic_set_foreach_constraint(__isl_keep isl_basic_set *bset,
+	isl_stat (*fn)(__isl_take isl_constraint *c, void *user), void *user);
+__isl_give isl_constraint_list *isl_basic_map_get_constraint_list(
+	__isl_keep isl_basic_map *bmap);
+__isl_give isl_constraint_list *isl_basic_set_get_constraint_list(
+	__isl_keep isl_basic_set *bset);
+int isl_constraint_is_equal(struct isl_constraint *constraint1,
+			    struct isl_constraint *constraint2);
+
+isl_stat isl_basic_set_foreach_bound_pair(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos,
+	isl_stat (*fn)(__isl_take isl_constraint *lower,
+		  __isl_take isl_constraint *upper,
+		  __isl_take isl_basic_set *bset, void *user), void *user);
+
+__isl_give isl_basic_map *isl_basic_map_add_constraint(
+	__isl_take isl_basic_map *bmap, __isl_take isl_constraint *constraint);
+__isl_give isl_basic_set *isl_basic_set_add_constraint(
+	__isl_take isl_basic_set *bset, __isl_take isl_constraint *constraint);
+__isl_give isl_map *isl_map_add_constraint(__isl_take isl_map *map,
+	__isl_take isl_constraint *constraint);
+__isl_give isl_set *isl_set_add_constraint(__isl_take isl_set *set,
+	__isl_take isl_constraint *constraint);
+
+isl_bool isl_basic_map_has_defining_equality(
+	__isl_keep isl_basic_map *bmap, enum isl_dim_type type, int pos,
+	__isl_give isl_constraint **c);
+isl_bool isl_basic_set_has_defining_equality(
+	struct isl_basic_set *bset, enum isl_dim_type type, int pos,
+	struct isl_constraint **constraint);
+isl_bool isl_basic_set_has_defining_inequalities(
+	struct isl_basic_set *bset, enum isl_dim_type type, int pos,
+	struct isl_constraint **lower,
+	struct isl_constraint **upper);
+
+__isl_give isl_space *isl_constraint_get_space(
+	__isl_keep isl_constraint *constraint);
+__isl_give isl_local_space *isl_constraint_get_local_space(
+	__isl_keep isl_constraint *constraint);
+int isl_constraint_dim(struct isl_constraint *constraint,
+	enum isl_dim_type type);
+
+isl_bool isl_constraint_involves_dims(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+const char *isl_constraint_get_dim_name(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_val *isl_constraint_get_constant_val(
+	__isl_keep isl_constraint *constraint);
+__isl_give isl_val *isl_constraint_get_coefficient_val(
+	__isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos);
+__isl_give isl_constraint *isl_constraint_set_constant_si(
+	__isl_take isl_constraint *constraint, int v);
+__isl_give isl_constraint *isl_constraint_set_constant_val(
+	__isl_take isl_constraint *constraint, __isl_take isl_val *v);
+__isl_give isl_constraint *isl_constraint_set_coefficient_si(
+	__isl_take isl_constraint *constraint,
+	enum isl_dim_type type, int pos, int v);
+__isl_give isl_constraint *isl_constraint_set_coefficient_val(
+	__isl_take isl_constraint *constraint,
+	enum isl_dim_type type, int pos, __isl_take isl_val *v);
+
+__isl_give isl_aff *isl_constraint_get_div(__isl_keep isl_constraint *constraint,
+	int pos);
+
+struct isl_constraint *isl_constraint_negate(struct isl_constraint *constraint);
+
+isl_bool isl_constraint_is_equality(__isl_keep isl_constraint *constraint);
+int isl_constraint_is_div_constraint(__isl_keep isl_constraint *constraint);
+
+isl_bool isl_constraint_is_lower_bound(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, unsigned pos);
+isl_bool isl_constraint_is_upper_bound(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, unsigned pos);
+
+__isl_give isl_basic_map *isl_basic_map_from_constraint(
+	__isl_take isl_constraint *constraint);
+__isl_give isl_basic_set *isl_basic_set_from_constraint(
+	__isl_take isl_constraint *constraint);
+
+__isl_give isl_aff *isl_constraint_get_bound(
+	__isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos);
+__isl_give isl_aff *isl_constraint_get_aff(
+	__isl_keep isl_constraint *constraint);
+__isl_give isl_constraint *isl_equality_from_aff(__isl_take isl_aff *aff);
+__isl_give isl_constraint *isl_inequality_from_aff(__isl_take isl_aff *aff);
+
+int isl_constraint_plain_cmp(__isl_keep isl_constraint *c1,
+	__isl_keep isl_constraint *c2);
+int isl_constraint_cmp_last_non_zero(__isl_keep isl_constraint *c1,
+	__isl_keep isl_constraint *c2);
+
+__isl_give isl_printer *isl_printer_print_constraint(__isl_take isl_printer *p,
+	__isl_keep isl_constraint *c);
+void isl_constraint_dump(__isl_keep isl_constraint *c);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/ctx.h b/final/lib/External/isl/include/isl/ctx.h
new file mode 100644
index 0000000..7c92523
--- /dev/null
+++ b/final/lib/External/isl/include/isl/ctx.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_CTX_H
+#define ISL_CTX_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <isl/arg.h>
+
+#ifndef __isl_give
+#define __isl_give
+#endif
+#ifndef __isl_take
+#define __isl_take
+#endif
+#ifndef __isl_keep
+#define __isl_keep
+#endif
+#ifndef __isl_null
+#define __isl_null
+#endif
+#ifndef __isl_export
+#define __isl_export
+#endif
+#ifndef __isl_overload
+#define __isl_overload
+#endif
+#ifndef __isl_constructor
+#define __isl_constructor
+#endif
+#ifndef __isl_subclass
+#define __isl_subclass(super)
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Nearly all isa functions require a struct isl_ctx allocated using
+ * isl_ctx_alloc.  This ctx contains (or will contain) options that
+ * control the behavior of the library and some caches.
+ *
+ * An object allocated within a given ctx should never be used inside
+ * another ctx.  Functions for moving objects from one ctx to another
+ * will be added as the need arises.
+ *
+ * A given context should only be used inside a single thread.
+ * A global context for synchronization between different threads
+ * as well as functions for moving a context to a different thread
+ * will be added as the need arises.
+ *
+ * If anything goes wrong (out of memory, failed assertion), then
+ * the library will currently simply abort.  This will be made
+ * configurable in the future.
+ * Users of the library should expect functions that return
+ * a pointer to a structure, to return NULL, indicating failure.
+ * Any function accepting a pointer to a structure will treat
+ * a NULL argument as a failure, resulting in the function freeing
+ * the remaining structures (if any) and returning NULL itself
+ * (in case of pointer return type).
+ * The only exception is the isl_ctx argument, which should never be NULL.
+ */
+struct isl_stats {
+	long	gbr_solved_lps;
+};
+enum isl_error {
+	isl_error_none = 0,
+	isl_error_abort,
+	isl_error_alloc,
+	isl_error_unknown,
+	isl_error_internal,
+	isl_error_invalid,
+	isl_error_quota,
+	isl_error_unsupported
+};
+typedef enum {
+	isl_stat_error = -1,
+	isl_stat_ok = 0
+} isl_stat;
+typedef enum {
+	isl_bool_error = -1,
+	isl_bool_false = 0,
+	isl_bool_true = 1
+} isl_bool;
+isl_bool isl_bool_not(isl_bool b);
+struct isl_ctx;
+typedef struct isl_ctx isl_ctx;
+
+/* Some helper macros */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+#define ISL_DEPRECATED	__attribute__((__deprecated__))
+#else
+#define ISL_DEPRECATED
+#endif
+
+#define ISL_FL_INIT(l, f)   (l) = (f)               /* Specific flags location. */
+#define ISL_FL_SET(l, f)    ((l) |= (f))
+#define ISL_FL_CLR(l, f)    ((l) &= ~(f))
+#define ISL_FL_ISSET(l, f)  (!!((l) & (f)))
+
+#define ISL_F_INIT(p, f)    ISL_FL_INIT((p)->flags, f)  /* Structure element flags. */
+#define ISL_F_SET(p, f)     ISL_FL_SET((p)->flags, f)
+#define ISL_F_CLR(p, f)     ISL_FL_CLR((p)->flags, f)
+#define ISL_F_ISSET(p, f)   ISL_FL_ISSET((p)->flags, f)
+
+void *isl_malloc_or_die(isl_ctx *ctx, size_t size);
+void *isl_calloc_or_die(isl_ctx *ctx, size_t nmemb, size_t size);
+void *isl_realloc_or_die(isl_ctx *ctx, void *ptr, size_t size);
+
+#define isl_alloc(ctx,type,size)	((type *)isl_malloc_or_die(ctx, size))
+#define isl_calloc(ctx,type,size)	((type *)isl_calloc_or_die(ctx,\
+								    1, size))
+#define isl_realloc(ctx,ptr,type,size)	((type *)isl_realloc_or_die(ctx,\
+								    ptr, size))
+#define isl_alloc_type(ctx,type)	isl_alloc(ctx,type,sizeof(type))
+#define isl_calloc_type(ctx,type)	isl_calloc(ctx,type,sizeof(type))
+#define isl_realloc_type(ctx,ptr,type)	isl_realloc(ctx,ptr,type,sizeof(type))
+#define isl_alloc_array(ctx,type,n)	isl_alloc(ctx,type,(n)*sizeof(type))
+#define isl_calloc_array(ctx,type,n)	((type *)isl_calloc_or_die(ctx,\
+							    n, sizeof(type)))
+#define isl_realloc_array(ctx,ptr,type,n) \
+				    isl_realloc(ctx,ptr,type,(n)*sizeof(type))
+
+#define isl_die(ctx,errno,msg,code)					\
+	do {								\
+		isl_handle_error(ctx, errno, msg, __FILE__, __LINE__);	\
+		code;							\
+	} while (0)
+
+void isl_handle_error(isl_ctx *ctx, enum isl_error error, const char *msg,
+	const char *file, int line);
+
+#define isl_assert4(ctx,test,code,errno)				\
+	do {								\
+		if (test)						\
+			break;						\
+		isl_die(ctx, errno, "Assertion \"" #test "\" failed", code);	\
+	} while (0)
+#define isl_assert(ctx,test,code)					\
+	isl_assert4(ctx,test,code,isl_error_unknown)
+
+#define isl_min(a,b)			((a < b) ? (a) : (b))
+
+/* struct isl_ctx functions */
+
+struct isl_options *isl_ctx_options(isl_ctx *ctx);
+
+isl_ctx *isl_ctx_alloc_with_options(struct isl_args *args,
+	__isl_take void *opt);
+isl_ctx *isl_ctx_alloc(void);
+void *isl_ctx_peek_options(isl_ctx *ctx, struct isl_args *args);
+int isl_ctx_parse_options(isl_ctx *ctx, int argc, char **argv, unsigned flags);
+void isl_ctx_ref(struct isl_ctx *ctx);
+void isl_ctx_deref(struct isl_ctx *ctx);
+void isl_ctx_free(isl_ctx *ctx);
+
+void isl_ctx_abort(isl_ctx *ctx);
+void isl_ctx_resume(isl_ctx *ctx);
+int isl_ctx_aborted(isl_ctx *ctx);
+
+void isl_ctx_set_max_operations(isl_ctx *ctx, unsigned long max_operations);
+unsigned long isl_ctx_get_max_operations(isl_ctx *ctx);
+void isl_ctx_reset_operations(isl_ctx *ctx);
+
+#define ISL_ARG_CTX_DECL(prefix,st,args)				\
+st *isl_ctx_peek_ ## prefix(isl_ctx *ctx);
+
+#define ISL_ARG_CTX_DEF(prefix,st,args)					\
+st *isl_ctx_peek_ ## prefix(isl_ctx *ctx)				\
+{									\
+	return (st *)isl_ctx_peek_options(ctx, &(args));		\
+}
+
+#define ISL_CTX_GET_INT_DEF(prefix,st,args,field)			\
+int prefix ## _get_ ## field(isl_ctx *ctx)				\
+{									\
+	st *options;							\
+	options = isl_ctx_peek_ ## prefix(ctx);				\
+	if (!options)							\
+		isl_die(ctx, isl_error_invalid,				\
+			"isl_ctx does not reference " #prefix,		\
+			return -1);					\
+	return options->field;						\
+}
+
+#define ISL_CTX_SET_INT_DEF(prefix,st,args,field)			\
+isl_stat prefix ## _set_ ## field(isl_ctx *ctx, int val)		\
+{									\
+	st *options;							\
+	options = isl_ctx_peek_ ## prefix(ctx);				\
+	if (!options)							\
+		isl_die(ctx, isl_error_invalid,				\
+			"isl_ctx does not reference " #prefix,		\
+			return isl_stat_error);				\
+	options->field = val;						\
+	return isl_stat_ok;						\
+}
+
+#define ISL_CTX_GET_STR_DEF(prefix,st,args,field)			\
+const char *prefix ## _get_ ## field(isl_ctx *ctx)			\
+{									\
+	st *options;							\
+	options = isl_ctx_peek_ ## prefix(ctx);				\
+	if (!options)							\
+		isl_die(ctx, isl_error_invalid,				\
+			"isl_ctx does not reference " #prefix,		\
+			return NULL);					\
+	return options->field;						\
+}
+
+#define ISL_CTX_SET_STR_DEF(prefix,st,args,field)			\
+isl_stat prefix ## _set_ ## field(isl_ctx *ctx, const char *val)	\
+{									\
+	st *options;							\
+	options = isl_ctx_peek_ ## prefix(ctx);				\
+	if (!options)							\
+		isl_die(ctx, isl_error_invalid,				\
+			"isl_ctx does not reference " #prefix,		\
+			return isl_stat_error);				\
+	if (!val)							\
+		return isl_stat_error;					\
+	free(options->field);						\
+	options->field = strdup(val);					\
+	if (!options->field)						\
+		return isl_stat_error;					\
+	return isl_stat_ok;						\
+}
+
+#define ISL_CTX_GET_BOOL_DEF(prefix,st,args,field)			\
+	ISL_CTX_GET_INT_DEF(prefix,st,args,field)
+
+#define ISL_CTX_SET_BOOL_DEF(prefix,st,args,field)			\
+	ISL_CTX_SET_INT_DEF(prefix,st,args,field)
+
+#define ISL_CTX_GET_CHOICE_DEF(prefix,st,args,field)			\
+	ISL_CTX_GET_INT_DEF(prefix,st,args,field)
+
+#define ISL_CTX_SET_CHOICE_DEF(prefix,st,args,field)			\
+	ISL_CTX_SET_INT_DEF(prefix,st,args,field)
+
+enum isl_error isl_ctx_last_error(isl_ctx *ctx);
+void isl_ctx_reset_error(isl_ctx *ctx);
+void isl_ctx_set_error(isl_ctx *ctx, enum isl_error error);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/aff_int.h b/final/lib/External/isl/include/isl/deprecated/aff_int.h
new file mode 100644
index 0000000..a067374
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/aff_int.h
@@ -0,0 +1,45 @@
+#ifndef ISL_DEPRECATED_AFF_INT_H
+#define ISL_DEPRECATED_AFF_INT_H
+
+#include <isl/deprecated/int.h>
+#include <isl/aff_type.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+int isl_aff_get_constant(__isl_keep isl_aff *aff, isl_int *v);
+int isl_aff_get_coefficient(__isl_keep isl_aff *aff,
+	enum isl_dim_type type, int pos, isl_int *v);
+isl_stat isl_aff_get_denominator(__isl_keep isl_aff *aff, isl_int *v);
+__isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_int v);
+__isl_give isl_aff *isl_aff_set_coefficient(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, isl_int v);
+__isl_give isl_aff *isl_aff_set_denominator(__isl_take isl_aff *aff, isl_int v);
+__isl_give isl_aff *isl_aff_add_constant(__isl_take isl_aff *aff, isl_int v);
+__isl_give isl_aff *isl_aff_add_constant_num(__isl_take isl_aff *aff,
+	isl_int v);
+__isl_give isl_aff *isl_aff_add_coefficient(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, isl_int v);
+
+__isl_give isl_aff *isl_aff_mod(__isl_take isl_aff *aff, isl_int mod);
+
+__isl_give isl_aff *isl_aff_scale(__isl_take isl_aff *aff, isl_int f);
+__isl_give isl_aff *isl_aff_scale_down(__isl_take isl_aff *aff, isl_int f);
+
+__isl_give isl_pw_aff *isl_pw_aff_mod(__isl_take isl_pw_aff *pwaff,
+	isl_int mod);
+
+__isl_give isl_pw_aff *isl_pw_aff_scale(__isl_take isl_pw_aff *pwaff,
+	isl_int f);
+__isl_give isl_pw_aff *isl_pw_aff_scale_down(__isl_take isl_pw_aff *pwaff,
+	isl_int f);
+
+__isl_give isl_multi_aff *isl_multi_aff_scale(__isl_take isl_multi_aff *maff,
+	isl_int f);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/ast_int.h b/final/lib/External/isl/include/isl/deprecated/ast_int.h
new file mode 100644
index 0000000..7d2039b
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/ast_int.h
@@ -0,0 +1,17 @@
+#ifndef ISL_DEPRECATED_AST_INT_H
+#define ISL_DEPRECATED_AST_INT_H
+
+#include <isl/deprecated/int.h>
+#include <isl/ast.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+int isl_ast_expr_get_int(__isl_keep isl_ast_expr *expr, isl_int *v);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/constraint_int.h b/final/lib/External/isl/include/isl/deprecated/constraint_int.h
new file mode 100644
index 0000000..c5ab0aa
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/constraint_int.h
@@ -0,0 +1,25 @@
+#ifndef ISL_DEPRECATED_CONSTRAINT_INT_H
+#define ISL_DEPRECATED_CONSTRAINT_INT_H
+
+#include <isl/deprecated/int.h>
+#include <isl/constraint.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void isl_constraint_get_constant(__isl_keep isl_constraint *constraint,
+	isl_int *v);
+void isl_constraint_get_coefficient(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, int pos, isl_int *v);
+__isl_give isl_constraint *isl_constraint_set_constant(
+	__isl_take isl_constraint *constraint, isl_int v);
+__isl_give isl_constraint *isl_constraint_set_coefficient(
+	__isl_take isl_constraint *constraint,
+	enum isl_dim_type type, int pos, isl_int v);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/ilp_int.h b/final/lib/External/isl/include/isl/deprecated/ilp_int.h
new file mode 100644
index 0000000..b952e1b
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/ilp_int.h
@@ -0,0 +1,23 @@
+#ifndef ISL_DEPRECATED_ILP_INT_H
+#define ISL_DEPRECATED_ILP_INT_H
+
+#include <isl/deprecated/int.h>
+#include <isl/lp.h>
+#include <isl/ilp.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+enum isl_lp_result isl_basic_set_max(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_aff *obj, isl_int *opt);
+enum isl_lp_result isl_set_min(__isl_keep isl_set *set,
+	__isl_keep isl_aff *obj, isl_int *opt);
+enum isl_lp_result isl_set_max(__isl_keep isl_set *set,
+	__isl_keep isl_aff *obj, isl_int *opt);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/int.h b/final/lib/External/isl/include/isl/deprecated/int.h
new file mode 100644
index 0000000..9878234
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/int.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_DEPRECATED_INT_H
+#define ISL_DEPRECATED_INT_H
+
+#include <isl/hash.h>
+#include <string.h>
+#include <gmp.h>
+#if defined(__cplusplus)
+#include <iostream>
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef mp_get_memory_functions
+void mp_get_memory_functions(
+		void *(**alloc_func_ptr) (size_t),
+		void *(**realloc_func_ptr) (void *, size_t, size_t),
+		void (**free_func_ptr) (void *, size_t));
+#endif
+
+/* isl_int is the basic integer type.  It currently always corresponds
+ * to a gmp mpz_t, but in the future, different types such as long long
+ * or cln::cl_I will be supported.
+ */
+typedef mpz_t	isl_int;
+
+#define isl_int_init(i)		mpz_init(i)
+#define isl_int_clear(i)	mpz_clear(i)
+
+#define isl_int_set(r,i)	mpz_set(r,i)
+#define isl_int_set_gmp(r,i)	mpz_set(r,i)
+#define isl_int_set_si(r,i)	mpz_set_si(r,i)
+#define isl_int_set_ui(r,i)	mpz_set_ui(r,i)
+#define isl_int_get_gmp(i,g)	mpz_set(g,i)
+#define isl_int_get_si(r)	mpz_get_si(r)
+#define isl_int_get_ui(r)	mpz_get_ui(r)
+#define isl_int_get_d(r)	mpz_get_d(r)
+#define isl_int_get_str(r)	mpz_get_str(0, 10, r)
+typedef void (*isl_int_print_gmp_free_t)(void *, size_t);
+#define isl_int_free_str(s)					\
+	do {								\
+		isl_int_print_gmp_free_t gmp_free;			\
+		mp_get_memory_functions(NULL, NULL, &gmp_free);		\
+		(*gmp_free)(s, strlen(s) + 1);				\
+	} while (0)
+#define isl_int_abs(r,i)	mpz_abs(r,i)
+#define isl_int_neg(r,i)	mpz_neg(r,i)
+#define isl_int_swap(i,j)	mpz_swap(i,j)
+#define isl_int_swap_or_set(i,j)	mpz_swap(i,j)
+#define isl_int_add_ui(r,i,j)	mpz_add_ui(r,i,j)
+#define isl_int_sub_ui(r,i,j)	mpz_sub_ui(r,i,j)
+
+#define isl_int_add(r,i,j)	mpz_add(r,i,j)
+#define isl_int_sub(r,i,j)	mpz_sub(r,i,j)
+#define isl_int_mul(r,i,j)	mpz_mul(r,i,j)
+#define isl_int_mul_2exp(r,i,j)	mpz_mul_2exp(r,i,j)
+#define isl_int_mul_ui(r,i,j)	mpz_mul_ui(r,i,j)
+#define isl_int_pow_ui(r,i,j)	mpz_pow_ui(r,i,j)
+#define isl_int_addmul(r,i,j)	mpz_addmul(r,i,j)
+#define isl_int_submul(r,i,j)	mpz_submul(r,i,j)
+
+#define isl_int_gcd(r,i,j)	mpz_gcd(r,i,j)
+#define isl_int_lcm(r,i,j)	mpz_lcm(r,i,j)
+#define isl_int_divexact(r,i,j)	mpz_divexact(r,i,j)
+#define isl_int_divexact_ui(r,i,j)	mpz_divexact_ui(r,i,j)
+#define isl_int_tdiv_q(r,i,j)	mpz_tdiv_q(r,i,j)
+#define isl_int_cdiv_q(r,i,j)	mpz_cdiv_q(r,i,j)
+#define isl_int_fdiv_q(r,i,j)	mpz_fdiv_q(r,i,j)
+#define isl_int_fdiv_r(r,i,j)	mpz_fdiv_r(r,i,j)
+#define isl_int_fdiv_q_ui(r,i,j)	mpz_fdiv_q_ui(r,i,j)
+
+#define isl_int_read(r,s)	mpz_set_str(r,s,10)
+#define isl_int_print(out,i,width)					\
+	do {								\
+		char *s;						\
+		s = mpz_get_str(0, 10, i);				\
+		fprintf(out, "%*s", width, s);				\
+		isl_int_free_str(s);                                        \
+	} while (0)
+
+#define isl_int_sgn(i)		mpz_sgn(i)
+#define isl_int_cmp(i,j)	mpz_cmp(i,j)
+#define isl_int_cmp_si(i,si)	mpz_cmp_si(i,si)
+#define isl_int_eq(i,j)		(mpz_cmp(i,j) == 0)
+#define isl_int_ne(i,j)		(mpz_cmp(i,j) != 0)
+#define isl_int_lt(i,j)		(mpz_cmp(i,j) < 0)
+#define isl_int_le(i,j)		(mpz_cmp(i,j) <= 0)
+#define isl_int_gt(i,j)		(mpz_cmp(i,j) > 0)
+#define isl_int_ge(i,j)		(mpz_cmp(i,j) >= 0)
+#define isl_int_abs_eq(i,j)	(mpz_cmpabs(i,j) == 0)
+#define isl_int_abs_ne(i,j)	(mpz_cmpabs(i,j) != 0)
+#define isl_int_abs_lt(i,j)	(mpz_cmpabs(i,j) < 0)
+#define isl_int_abs_gt(i,j)	(mpz_cmpabs(i,j) > 0)
+#define isl_int_abs_ge(i,j)	(mpz_cmpabs(i,j) >= 0)
+
+
+#define isl_int_is_zero(i)	(isl_int_sgn(i) == 0)
+#define isl_int_is_one(i)	(isl_int_cmp_si(i,1) == 0)
+#define isl_int_is_negone(i)	(isl_int_cmp_si(i,-1) == 0)
+#define isl_int_is_pos(i)	(isl_int_sgn(i) > 0)
+#define isl_int_is_neg(i)	(isl_int_sgn(i) < 0)
+#define isl_int_is_nonpos(i)	(isl_int_sgn(i) <= 0)
+#define isl_int_is_nonneg(i)	(isl_int_sgn(i) >= 0)
+#define isl_int_is_divisible_by(i,j)	mpz_divisible_p(i,j)
+
+uint32_t isl_gmp_hash(mpz_t v, uint32_t hash);
+#define isl_int_hash(v,h)	isl_gmp_hash(v,h)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#if defined(__cplusplus)
+extern "C" { typedef void (*isl_gmp_free_t)(void *, size_t); }
+
+static inline std::ostream &operator<<(std::ostream &os, isl_int i)
+{
+	char *s;
+	s = mpz_get_str(0, 10, i);
+	os << s;
+	isl_int_free_str(s);
+	return os;
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/map_int.h b/final/lib/External/isl/include/isl/deprecated/map_int.h
new file mode 100644
index 0000000..c120c40
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/map_int.h
@@ -0,0 +1,25 @@
+#ifndef ISL_DEPRECATED_MAP_INT_H
+#define ISL_DEPRECATED_MAP_INT_H
+
+#include <isl/deprecated/int.h>
+#include <isl/map_type.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+isl_bool isl_basic_map_plain_is_fixed(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, isl_int *val);
+
+__isl_give isl_map *isl_map_fix(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int value);
+isl_bool isl_map_plain_is_fixed(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int *val);
+
+__isl_give isl_map *isl_map_fixed_power(__isl_take isl_map *map, isl_int exp);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/mat_int.h b/final/lib/External/isl/include/isl/deprecated/mat_int.h
new file mode 100644
index 0000000..efacd4e
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/mat_int.h
@@ -0,0 +1,19 @@
+#ifndef ISL_DEPRECATED_MAT_INT_H
+#define ISL_DEPRECATED_MAT_INT_H
+
+#include <isl/deprecated/int.h>
+#include <isl/mat.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+int isl_mat_get_element(__isl_keep isl_mat *mat, int row, int col, isl_int *v);
+__isl_give isl_mat *isl_mat_set_element(__isl_take isl_mat *mat,
+	int row, int col, isl_int v);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/point_int.h b/final/lib/External/isl/include/isl/deprecated/point_int.h
new file mode 100644
index 0000000..2e1a98b
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/point_int.h
@@ -0,0 +1,20 @@
+#ifndef ISL_DEPRECATED_POINT_INT_H
+#define ISL_DEPRECATED_POINT_INT_H
+
+#include <isl/deprecated/int.h>
+#include <isl/point.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+int isl_point_get_coordinate(__isl_keep isl_point *pnt,
+	enum isl_dim_type type, int pos, isl_int *v);
+__isl_give isl_point *isl_point_set_coordinate(__isl_take isl_point *pnt,
+	enum isl_dim_type type, int pos, isl_int v);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/polynomial_int.h b/final/lib/External/isl/include/isl/deprecated/polynomial_int.h
new file mode 100644
index 0000000..b86fcf2
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/polynomial_int.h
@@ -0,0 +1,32 @@
+#ifndef ISL_DEPRECATED_POLYNOMIAL_INT_H
+#define ISL_DEPRECATED_POLYNOMIAL_INT_H
+
+#include <isl/deprecated/int.h>
+#include <isl/polynomial.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_qpolynomial *isl_qpolynomial_rat_cst_on_domain(
+	__isl_take isl_space *space, const isl_int n, const isl_int d);
+int isl_qpolynomial_is_cst(__isl_keep isl_qpolynomial *qp,
+	isl_int *n, isl_int *d);
+__isl_give isl_qpolynomial *isl_qpolynomial_scale(
+	__isl_take isl_qpolynomial *qp, isl_int v);
+
+void isl_term_get_num(__isl_keep isl_term *term, isl_int *n);
+void isl_term_get_den(__isl_keep isl_term *term, isl_int *d);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale(
+	__isl_take isl_qpolynomial_fold *fold, isl_int v);
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fix_dim(
+	__isl_take isl_pw_qpolynomial_fold *pwf,
+	enum isl_dim_type type, unsigned n, isl_int v);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/set_int.h b/final/lib/External/isl/include/isl/deprecated/set_int.h
new file mode 100644
index 0000000..6f9ed06
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/set_int.h
@@ -0,0 +1,27 @@
+#ifndef ISL_DEPRECATED_SET_INT_H
+#define ISL_DEPRECATED_SET_INT_H
+
+#include <isl/deprecated/int.h>
+#include <isl/set_type.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_basic_set *isl_basic_set_fix(__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos, isl_int value);
+__isl_give isl_set *isl_set_lower_bound(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, isl_int value);
+__isl_give isl_set *isl_set_upper_bound(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, isl_int value);
+__isl_give isl_set *isl_set_fix(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, isl_int value);
+
+isl_bool isl_set_plain_is_fixed(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos, isl_int *val);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/union_map_int.h b/final/lib/External/isl/include/isl/deprecated/union_map_int.h
new file mode 100644
index 0000000..4a57997
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/union_map_int.h
@@ -0,0 +1,18 @@
+#ifndef ISL_DEPRECATED_UNION_MAP_INT_H
+#define ISL_DEPRECATED_UNION_MAP_INT_H
+
+#include <isl/deprecated/int.h>
+#include <isl/union_map_type.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_union_map *isl_union_map_fixed_power(
+	__isl_take isl_union_map *umap, isl_int exp);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/val_int.h b/final/lib/External/isl/include/isl/deprecated/val_int.h
new file mode 100644
index 0000000..ef2eba2
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/val_int.h
@@ -0,0 +1,18 @@
+#ifndef ISL_DEPRECATED_VAL_INT_H
+#define ISL_DEPRECATED_VAL_INT_H
+
+#include <isl/deprecated/int.h>
+#include <isl/val.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_val *isl_val_int_from_isl_int(isl_ctx *ctx, isl_int n);
+int isl_val_get_num_isl_int(__isl_keep isl_val *v, isl_int *n);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/deprecated/vec_int.h b/final/lib/External/isl/include/isl/deprecated/vec_int.h
new file mode 100644
index 0000000..c072997
--- /dev/null
+++ b/final/lib/External/isl/include/isl/deprecated/vec_int.h
@@ -0,0 +1,22 @@
+#ifndef ISL_DEPRECATED_VEC_INT_H
+#define ISL_DEPRECATED_VEC_INT_H
+
+#include <isl/deprecated/int.h>
+#include <isl/vec.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+int isl_vec_get_element(__isl_keep isl_vec *vec, int pos, isl_int *v);
+__isl_give isl_vec *isl_vec_set_element(__isl_take isl_vec *vec,
+	int pos, isl_int v);
+
+__isl_give isl_vec *isl_vec_set(__isl_take isl_vec *vec, isl_int v);
+__isl_give isl_vec *isl_vec_fdiv_r(__isl_take isl_vec *vec, isl_int m);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/flow.h b/final/lib/External/isl/include/isl/flow.h
new file mode 100644
index 0000000..f606549
--- /dev/null
+++ b/final/lib/External/isl/include/isl/flow.h
@@ -0,0 +1,156 @@
+#ifndef ISL_FLOW_H
+#define ISL_FLOW_H
+
+#include <stdio.h>
+
+#include <isl/set_type.h>
+#include <isl/map_type.h>
+#include <isl/union_set_type.h>
+#include <isl/union_map_type.h>
+#include <isl/schedule.h>
+#include <isl/printer.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Let n (>= 0) be the number of iterators shared by first and second.
+ * If first precedes second textually return 2 * n + 1,
+ * otherwise return 2 * n.
+ */
+typedef int (*isl_access_level_before)(void *first, void *second);
+
+struct isl_restriction;
+typedef struct isl_restriction isl_restriction;
+
+__isl_null isl_restriction *isl_restriction_free(
+	__isl_take isl_restriction *restr);
+__isl_give isl_restriction *isl_restriction_empty(
+	__isl_take isl_map *source_map);
+__isl_give isl_restriction *isl_restriction_none(
+	__isl_take isl_map *source_map);
+__isl_give isl_restriction *isl_restriction_input(
+	__isl_take isl_set *source_restr, __isl_take isl_set *sink_restr);
+__isl_give isl_restriction *isl_restriction_output(
+	__isl_take isl_set *source_restr);
+
+isl_ctx *isl_restriction_get_ctx(__isl_keep isl_restriction *restr);
+
+typedef __isl_give isl_restriction *(*isl_access_restrict)(
+	__isl_keep isl_map *source_map, __isl_keep isl_set *sink,
+	void *source_user, void *user);
+
+struct isl_access_info;
+typedef struct isl_access_info isl_access_info;
+struct isl_flow;
+typedef struct isl_flow isl_flow;
+
+__isl_give isl_access_info *isl_access_info_alloc(__isl_take isl_map *sink,
+	void *sink_user, isl_access_level_before fn, int max_source);
+__isl_give isl_access_info *isl_access_info_set_restrict(
+	__isl_take isl_access_info *acc, isl_access_restrict fn, void *user);
+__isl_give isl_access_info *isl_access_info_add_source(
+	__isl_take isl_access_info *acc, __isl_take isl_map *source,
+	int must, void *source_user);
+__isl_null isl_access_info *isl_access_info_free(
+	__isl_take isl_access_info *acc);
+
+isl_ctx *isl_access_info_get_ctx(__isl_keep isl_access_info *acc);
+
+__isl_give isl_flow *isl_access_info_compute_flow(__isl_take isl_access_info *acc);
+isl_stat isl_flow_foreach(__isl_keep isl_flow *deps,
+	isl_stat (*fn)(__isl_take isl_map *dep, int must, void *dep_user,
+		void *user),
+	void *user);
+__isl_give isl_map *isl_flow_get_no_source(__isl_keep isl_flow *deps, int must);
+void isl_flow_free(__isl_take isl_flow *deps);
+
+isl_ctx *isl_flow_get_ctx(__isl_keep isl_flow *deps);
+
+struct __isl_export isl_union_access_info;
+typedef struct isl_union_access_info isl_union_access_info;
+struct __isl_export isl_union_flow;
+typedef struct isl_union_flow isl_union_flow;
+
+__isl_constructor
+__isl_give isl_union_access_info *isl_union_access_info_from_sink(
+	__isl_take isl_union_map *sink);
+__isl_export
+__isl_give isl_union_access_info *isl_union_access_info_set_must_source(
+	__isl_take isl_union_access_info *access,
+	__isl_take isl_union_map *must_source);
+__isl_export
+__isl_give isl_union_access_info *isl_union_access_info_set_may_source(
+	__isl_take isl_union_access_info *access,
+	__isl_take isl_union_map *may_source);
+__isl_export
+__isl_give isl_union_access_info *isl_union_access_info_set_kill(
+	__isl_take isl_union_access_info *access,
+	__isl_take isl_union_map *kill);
+__isl_export
+__isl_give isl_union_access_info *isl_union_access_info_set_schedule(
+	__isl_take isl_union_access_info *access,
+	__isl_take isl_schedule *schedule);
+__isl_export
+__isl_give isl_union_access_info *isl_union_access_info_set_schedule_map(
+	__isl_take isl_union_access_info *access,
+	__isl_take isl_union_map *schedule_map);
+__isl_give isl_union_access_info *isl_union_access_info_copy(
+	__isl_keep isl_union_access_info *access);
+__isl_null isl_union_access_info *isl_union_access_info_free(
+	__isl_take isl_union_access_info *access);
+
+isl_ctx *isl_union_access_info_get_ctx(
+	__isl_keep isl_union_access_info *access);
+
+__isl_give isl_union_access_info *isl_union_access_info_read_from_file(
+	isl_ctx *ctx, FILE *input);
+__isl_give isl_printer *isl_printer_print_union_access_info(
+	__isl_take isl_printer *p, __isl_keep isl_union_access_info *access);
+__isl_give char *isl_union_access_info_to_str(
+	__isl_keep isl_union_access_info *access);
+
+__isl_export
+__isl_give isl_union_flow *isl_union_access_info_compute_flow(
+	__isl_take isl_union_access_info *access);
+
+isl_ctx *isl_union_flow_get_ctx(__isl_keep isl_union_flow *flow);
+__isl_give isl_union_flow *isl_union_flow_copy(
+	__isl_keep isl_union_flow *flow);
+__isl_export
+__isl_give isl_union_map *isl_union_flow_get_must_dependence(
+	__isl_keep isl_union_flow *flow);
+__isl_export
+__isl_give isl_union_map *isl_union_flow_get_may_dependence(
+	__isl_keep isl_union_flow *flow);
+__isl_export
+__isl_give isl_union_map *isl_union_flow_get_full_must_dependence(
+	__isl_keep isl_union_flow *flow);
+__isl_export
+__isl_give isl_union_map *isl_union_flow_get_full_may_dependence(
+	__isl_keep isl_union_flow *flow);
+__isl_export
+__isl_give isl_union_map *isl_union_flow_get_must_no_source(
+	__isl_keep isl_union_flow *flow);
+__isl_export
+__isl_give isl_union_map *isl_union_flow_get_may_no_source(
+	__isl_keep isl_union_flow *flow);
+__isl_null isl_union_flow *isl_union_flow_free(__isl_take isl_union_flow *flow);
+
+__isl_give isl_printer *isl_printer_print_union_flow(
+	__isl_take isl_printer *p, __isl_keep isl_union_flow *flow);
+__isl_give char *isl_union_flow_to_str(__isl_keep isl_union_flow *flow);
+
+int isl_union_map_compute_flow(__isl_take isl_union_map *sink,
+	__isl_take isl_union_map *must_source,
+	__isl_take isl_union_map *may_source,
+	__isl_take isl_union_map *schedule,
+	__isl_give isl_union_map **must_dep, __isl_give isl_union_map **may_dep,
+	__isl_give isl_union_map **must_no_source,
+	__isl_give isl_union_map **may_no_source);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/hash.h b/final/lib/External/isl/include/isl/hash.h
new file mode 100644
index 0000000..d5de9ba
--- /dev/null
+++ b/final/lib/External/isl/include/isl/hash.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_HASH_H
+#define ISL_HASH_H
+
+#include <stdlib.h>
+#include <isl/stdint.h>
+#include <isl/ctx.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define isl_hash_init()		(2166136261u)
+#define isl_hash_byte(h,b)	do {					\
+					h *= 16777619;			\
+					h ^= b;				\
+				} while(0)
+#define isl_hash_hash(h,h2)						\
+	do {								\
+		isl_hash_byte(h, (h2) & 0xFF);				\
+		isl_hash_byte(h, ((h2) >> 8) & 0xFF);			\
+		isl_hash_byte(h, ((h2) >> 16) & 0xFF);			\
+		isl_hash_byte(h, ((h2) >> 24) & 0xFF);			\
+	} while(0)
+#define isl_hash_bits(h,bits)						\
+	((bits) == 32) ? (h) :						\
+	((bits) >= 16) ?						\
+	      ((h) >> (bits)) ^ ((h) & (((uint32_t)1 << (bits)) - 1)) :	\
+	      (((h) >> (bits)) ^ (h)) & (((uint32_t)1 << (bits)) - 1)
+
+uint32_t isl_hash_string(uint32_t hash, const char *s);
+uint32_t isl_hash_mem(uint32_t hash, const void *p, size_t len);
+
+#define isl_hash_builtin(h,l)	isl_hash_mem(h, &l, sizeof(l))
+
+struct isl_hash_table_entry
+{
+	uint32_t  hash;
+	void     *data;
+};
+
+struct isl_hash_table {
+	int    bits;
+	int    n;
+	struct isl_hash_table_entry *entries;
+};
+
+struct isl_hash_table *isl_hash_table_alloc(struct isl_ctx *ctx, int min_size);
+void isl_hash_table_free(struct isl_ctx *ctx, struct isl_hash_table *table);
+
+int isl_hash_table_init(struct isl_ctx *ctx, struct isl_hash_table *table,
+			int min_size);
+void isl_hash_table_clear(struct isl_hash_table *table);
+struct isl_hash_table_entry *isl_hash_table_find(struct isl_ctx *ctx,
+				struct isl_hash_table *table,
+				uint32_t key_hash,
+				int (*eq)(const void *entry, const void *val),
+				const void *val, int reserve);
+isl_stat isl_hash_table_foreach(isl_ctx *ctx, struct isl_hash_table *table,
+	isl_stat (*fn)(void **entry, void *user), void *user);
+void isl_hash_table_remove(struct isl_ctx *ctx,
+				struct isl_hash_table *table,
+				struct isl_hash_table_entry *entry);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/hmap.h b/final/lib/External/isl/include/isl/hmap.h
new file mode 100644
index 0000000..2161221
--- /dev/null
+++ b/final/lib/External/isl/include/isl/hmap.h
@@ -0,0 +1,55 @@
+#include <isl/ctx.h>
+#include <isl/maybe.h>
+#include <isl/printer.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define ISL_xCAT(A,B) A ## B
+#define ISL_CAT(A,B) ISL_xCAT(A,B)
+#define ISL_xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define ISL_FN(TYPE,NAME) ISL_xFN(TYPE,NAME)
+
+struct ISL_HMAP;
+typedef struct ISL_HMAP	ISL_HMAP;
+
+__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,alloc)(isl_ctx *ctx, int min_size);
+__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,copy)(__isl_keep ISL_HMAP *hmap);
+__isl_null ISL_HMAP *ISL_FN(ISL_HMAP,free)(__isl_take ISL_HMAP *hmap);
+
+isl_ctx *ISL_FN(ISL_HMAP,get_ctx)(__isl_keep ISL_HMAP *hmap);
+
+__isl_give ISL_MAYBE(ISL_VAL) ISL_FN(ISL_HMAP,try_get)(
+	__isl_keep ISL_HMAP *hmap, __isl_keep ISL_KEY *key);
+isl_bool ISL_FN(ISL_HMAP,has)(__isl_keep ISL_HMAP *hmap,
+	__isl_keep ISL_KEY *key);
+__isl_give ISL_VAL *ISL_FN(ISL_HMAP,get)(__isl_keep ISL_HMAP *hmap,
+	__isl_take ISL_KEY *key);
+__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,set)(__isl_take ISL_HMAP *hmap,
+	__isl_take ISL_KEY *key, __isl_take ISL_VAL *val);
+__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,drop)(__isl_take ISL_HMAP *hmap,
+	__isl_take ISL_KEY *key);
+
+isl_stat ISL_FN(ISL_HMAP,foreach)(__isl_keep ISL_HMAP *hmap,
+	isl_stat (*fn)(__isl_take ISL_KEY *key, __isl_take ISL_VAL *val,
+		void *user),
+	void *user);
+
+__isl_give isl_printer *ISL_FN(isl_printer_print,ISL_HMAP_SUFFIX)(
+	__isl_take isl_printer *p, __isl_keep ISL_HMAP *hmap);
+void ISL_FN(ISL_HMAP,dump)(__isl_keep ISL_HMAP *hmap);
+
+#undef ISL_xCAT
+#undef ISL_CAT
+#undef ISL_KEY
+#undef ISL_VAL
+#undef ISL_xFN
+#undef ISL_FN
+#undef ISL_xHMAP
+#undef ISL_yHMAP
+#undef ISL_HMAP
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/final/lib/External/isl/include/isl/hmap_templ.c b/final/lib/External/isl/include/isl/hmap_templ.c
new file mode 100644
index 0000000..3519a8d
--- /dev/null
+++ b/final/lib/External/isl/include/isl/hmap_templ.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2011      INRIA Saclay
+ * Copyright 2013      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl/ctx.h>
+#include <isl/hash.h>
+
+#define ISL_xCAT(A,B) A ## B
+#define ISL_CAT(A,B) ISL_xCAT(A,B)
+#define ISL_xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define ISL_FN(TYPE,NAME) ISL_xFN(TYPE,NAME)
+#define ISL_xS(TYPE1,TYPE2,NAME) struct isl_ ## TYPE1 ## _ ## TYPE2 ## _ ## NAME
+#define ISL_yS(TYPE1,TYPE2,NAME) ISL_xS(TYPE1,TYPE2,NAME)
+#define ISL_S(NAME) ISL_yS(ISL_KEY,ISL_VAL,NAME)
+
+struct ISL_HMAP {
+	int ref;
+	isl_ctx *ctx;
+	struct isl_hash_table table;
+};
+
+ISL_S(pair) {
+	ISL_KEY *key;
+	ISL_VAL *val;
+};
+
+__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,alloc)(isl_ctx *ctx, int min_size)
+{
+	ISL_HMAP *hmap;
+
+	hmap = isl_calloc_type(ctx, ISL_HMAP);
+	if (!hmap)
+		return NULL;
+
+	hmap->ctx = ctx;
+	isl_ctx_ref(ctx);
+	hmap->ref = 1;
+
+	if (isl_hash_table_init(ctx, &hmap->table, min_size) < 0)
+		return ISL_FN(ISL_HMAP,free)(hmap);
+
+	return hmap;
+}
+
+static isl_stat free_pair(void **entry, void *user)
+{
+	ISL_S(pair) *pair = *entry;
+	ISL_FN(ISL_KEY,free)(pair->key);
+	ISL_FN(ISL_VAL,free)(pair->val);
+	free(pair);
+	*entry = NULL;
+	return isl_stat_ok;
+}
+
+__isl_null ISL_HMAP *ISL_FN(ISL_HMAP,free)(__isl_take ISL_HMAP *hmap)
+{
+	if (!hmap)
+		return NULL;
+	if (--hmap->ref > 0)
+		return NULL;
+	isl_hash_table_foreach(hmap->ctx, &hmap->table, &free_pair, NULL);
+	isl_hash_table_clear(&hmap->table);
+	isl_ctx_deref(hmap->ctx);
+	free(hmap);
+	return NULL;
+}
+
+isl_ctx *ISL_FN(ISL_HMAP,get_ctx)(__isl_keep ISL_HMAP *hmap)
+{
+	return hmap ? hmap->ctx : NULL;
+}
+
+/* Add a mapping from "key" to "val" to the associative array
+ * pointed to by user.
+ */
+static isl_stat add_key_val(__isl_take ISL_KEY *key, __isl_take ISL_VAL *val,
+	void *user)
+{
+	ISL_HMAP **hmap = (ISL_HMAP **) user;
+
+	*hmap = ISL_FN(ISL_HMAP,set)(*hmap, key, val);
+
+	if (!*hmap)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,dup)(__isl_keep ISL_HMAP *hmap)
+{
+	ISL_HMAP *dup;
+
+	if (!hmap)
+		return NULL;
+
+	dup = ISL_FN(ISL_HMAP,alloc)(hmap->ctx, hmap->table.n);
+	if (ISL_FN(ISL_HMAP,foreach)(hmap, &add_key_val, &dup) < 0)
+		return ISL_FN(ISL_HMAP,free)(dup);
+
+	return dup;
+}
+
+__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,cow)(__isl_take ISL_HMAP *hmap)
+{
+	if (!hmap)
+		return NULL;
+
+	if (hmap->ref == 1)
+		return hmap;
+	hmap->ref--;
+	return ISL_FN(ISL_HMAP,dup)(hmap);
+}
+
+__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,copy)(__isl_keep ISL_HMAP *hmap)
+{
+	if (!hmap)
+		return NULL;
+
+	hmap->ref++;
+	return hmap;
+}
+
+static int has_key(const void *entry, const void *c_key)
+{
+	const ISL_S(pair) *pair = entry;
+	ISL_KEY *key = (ISL_KEY *) c_key;
+
+	return ISL_KEY_IS_EQUAL(pair->key, key);
+}
+
+/* If "hmap" contains a value associated to "key", then return
+ * (isl_bool_true, copy of value).
+ * Otherwise, return
+ * (isl_bool_false, NULL).
+ * If an error occurs, then return
+ * (isl_bool_error, NULL).
+ */
+__isl_give ISL_MAYBE(ISL_VAL) ISL_FN(ISL_HMAP,try_get)(
+	__isl_keep ISL_HMAP *hmap, __isl_keep ISL_KEY *key)
+{
+	struct isl_hash_table_entry *entry;
+	ISL_S(pair) *pair;
+	uint32_t hash;
+	ISL_MAYBE(ISL_VAL) res = { isl_bool_false, NULL };
+
+	if (!hmap || !key)
+		goto error;
+
+	hash = ISL_FN(ISL_KEY,get_hash)(key);
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+
+	if (!entry)
+		return res;
+
+	pair = entry->data;
+
+	res.valid = isl_bool_true;
+	res.value = ISL_FN(ISL_VAL,copy)(pair->val);
+	if (!res.value)
+		res.valid = isl_bool_error;
+	return res;
+error:
+	res.valid = isl_bool_error;
+	res.value = NULL;
+	return res;
+}
+
+/* If "hmap" contains a value associated to "key", then return
+ * isl_bool_true.  Otherwise, return isl_bool_false.
+ * Return isl_bool_error on error.
+ */
+isl_bool ISL_FN(ISL_HMAP,has)(__isl_keep ISL_HMAP *hmap,
+	__isl_keep ISL_KEY *key)
+{
+	ISL_MAYBE(ISL_VAL) res;
+
+	res = ISL_FN(ISL_HMAP,try_get)(hmap, key);
+	ISL_FN(ISL_VAL,free)(res.value);
+
+	return res.valid;
+}
+
+/* If "hmap" contains a value associated to "key", then return
+ * a copy of that value.  Otherwise, return NULL.
+ * Return NULL on error.
+ */
+__isl_give ISL_VAL *ISL_FN(ISL_HMAP,get)(__isl_keep ISL_HMAP *hmap,
+	__isl_take ISL_KEY *key)
+{
+	ISL_VAL *res;
+
+	res = ISL_FN(ISL_HMAP,try_get)(hmap, key).value;
+	ISL_FN(ISL_KEY,free)(key);
+	return res;
+}
+
+/* Remove the mapping between "key" and its associated value (if any)
+ * from "hmap".
+ *
+ * If "key" is not mapped to anything, then we leave "hmap" untouched"
+ */
+__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,drop)(__isl_take ISL_HMAP *hmap,
+	__isl_take ISL_KEY *key)
+{
+	struct isl_hash_table_entry *entry;
+	ISL_S(pair) *pair;
+	uint32_t hash;
+
+	if (!hmap || !key)
+		goto error;
+
+	hash = ISL_FN(ISL_KEY,get_hash)(key);
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+	if (!entry) {
+		ISL_FN(ISL_KEY,free)(key);
+		return hmap;
+	}
+
+	hmap = ISL_FN(ISL_HMAP,cow)(hmap);
+	if (!hmap)
+		goto error;
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+	ISL_FN(ISL_KEY,free)(key);
+
+	if (!entry)
+		isl_die(hmap->ctx, isl_error_internal,
+			"missing entry" , goto error);
+
+	pair = entry->data;
+	isl_hash_table_remove(hmap->ctx, &hmap->table, entry);
+	ISL_FN(ISL_KEY,free)(pair->key);
+	ISL_FN(ISL_VAL,free)(pair->val);
+	free(pair);
+
+	return hmap;
+error:
+	ISL_FN(ISL_KEY,free)(key);
+	ISL_FN(ISL_HMAP,free)(hmap);
+	return NULL;
+}
+
+/* Add a mapping from "key" to "val" to "hmap".
+ * If "key" was already mapped to something else, then that mapping
+ * is replaced.
+ * If key happened to be mapped to "val" already, then we leave
+ * "hmap" untouched.
+ */
+__isl_give ISL_HMAP *ISL_FN(ISL_HMAP,set)(__isl_take ISL_HMAP *hmap,
+	__isl_take ISL_KEY *key, __isl_take ISL_VAL *val)
+{
+	struct isl_hash_table_entry *entry;
+	ISL_S(pair) *pair;
+	uint32_t hash;
+
+	if (!hmap || !key || !val)
+		goto error;
+
+	hash = ISL_FN(ISL_KEY,get_hash)(key);
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+	if (entry) {
+		int equal;
+		pair = entry->data;
+		equal = ISL_VAL_IS_EQUAL(pair->val, val);
+		if (equal < 0)
+			goto error;
+		if (equal) {
+			ISL_FN(ISL_KEY,free)(key);
+			ISL_FN(ISL_VAL,free)(val);
+			return hmap;
+		}
+	}
+
+	hmap = ISL_FN(ISL_HMAP,cow)(hmap);
+	if (!hmap)
+		goto error;
+
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 1);
+
+	if (!entry)
+		goto error;
+
+	if (entry->data) {
+		pair = entry->data;
+		ISL_FN(ISL_VAL,free)(pair->val);
+		pair->val = val;
+		ISL_FN(ISL_KEY,free)(key);
+		return hmap;
+	}
+
+	pair = isl_alloc_type(hmap->ctx, ISL_S(pair));
+	if (!pair)
+		goto error;
+
+	entry->data = pair;
+	pair->key = key;
+	pair->val = val;
+	return hmap;
+error:
+	ISL_FN(ISL_KEY,free)(key);
+	ISL_FN(ISL_VAL,free)(val);
+	return ISL_FN(ISL_HMAP,free)(hmap);
+}
+
+/* Internal data structure for isl_map_to_basic_set_foreach.
+ *
+ * fn is the function that should be called on each entry.
+ * user is the user-specified final argument to fn.
+ */
+ISL_S(foreach_data) {
+	isl_stat (*fn)(__isl_take ISL_KEY *key, __isl_take ISL_VAL *val,
+		void *user);
+	void *user;
+};
+
+/* Call data->fn on a copy of the key and value in *entry.
+ */
+static isl_stat call_on_copy(void **entry, void *user)
+{
+	ISL_S(pair) *pair = *entry;
+	ISL_S(foreach_data) *data = (ISL_S(foreach_data) *) user;
+
+	return data->fn(ISL_FN(ISL_KEY,copy)(pair->key),
+			ISL_FN(ISL_VAL,copy)(pair->val), data->user);
+}
+
+/* Call "fn" on each pair of key and value in "hmap".
+ */
+isl_stat ISL_FN(ISL_HMAP,foreach)(__isl_keep ISL_HMAP *hmap,
+	isl_stat (*fn)(__isl_take ISL_KEY *key, __isl_take ISL_VAL *val,
+		void *user),
+	void *user)
+{
+	ISL_S(foreach_data) data = { fn, user };
+
+	if (!hmap)
+		return isl_stat_error;
+
+	return isl_hash_table_foreach(hmap->ctx, &hmap->table,
+				      &call_on_copy, &data);
+}
+
+/* Internal data structure for print_pair.
+ *
+ * p is the printer on which the associative array is being printed.
+ * first is set if the current key-value pair is the first to be printed.
+ */
+ISL_S(print_data) {
+	isl_printer *p;
+	int first;
+};
+
+/* Print the given key-value pair to data->p.
+ */
+static isl_stat print_pair(__isl_take ISL_KEY *key, __isl_take ISL_VAL *val,
+	void *user)
+{
+	ISL_S(print_data) *data = user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, ", ");
+	data->p = ISL_KEY_PRINT(data->p, key);
+	data->p = isl_printer_print_str(data->p, ": ");
+	data->p = ISL_VAL_PRINT(data->p, val);
+	data->first = 0;
+
+	ISL_FN(ISL_KEY,free)(key);
+	ISL_FN(ISL_VAL,free)(val);
+	return isl_stat_ok;
+}
+
+/* Print the associative array to "p".
+ */
+__isl_give isl_printer *ISL_FN(isl_printer_print,ISL_HMAP_SUFFIX)(
+	__isl_take isl_printer *p, __isl_keep ISL_HMAP *hmap)
+{
+	ISL_S(print_data) data;
+
+	if (!p || !hmap)
+		return isl_printer_free(p);
+
+	p = isl_printer_print_str(p, "{");
+	data.p = p;
+	data.first = 1;
+	if (ISL_FN(ISL_HMAP,foreach)(hmap, &print_pair, &data) < 0)
+		data.p = isl_printer_free(data.p);
+	p = data.p;
+	p = isl_printer_print_str(p, "}");
+
+	return p;
+}
+
+void ISL_FN(ISL_HMAP,dump)(__isl_keep ISL_HMAP *hmap)
+{
+	isl_printer *printer;
+
+	if (!hmap)
+		return;
+
+	printer = isl_printer_to_file(ISL_FN(ISL_HMAP,get_ctx)(hmap), stderr);
+	printer = ISL_FN(isl_printer_print,ISL_HMAP_SUFFIX)(printer, hmap);
+	printer = isl_printer_end_line(printer);
+
+	isl_printer_free(printer);
+}
diff --git a/final/lib/External/isl/include/isl/id.h b/final/lib/External/isl/include/isl/id.h
new file mode 100644
index 0000000..c025d51
--- /dev/null
+++ b/final/lib/External/isl/include/isl/id.h
@@ -0,0 +1,41 @@
+#ifndef ISL_ID_H
+#define ISL_ID_H
+
+#include <isl/ctx.h>
+#include <isl/list.h>
+#include <isl/printer_type.h>
+#include <isl/stdint.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_id;
+typedef struct isl_id isl_id;
+
+ISL_DECLARE_LIST(id)
+
+isl_ctx *isl_id_get_ctx(__isl_keep isl_id *id);
+uint32_t isl_id_get_hash(__isl_keep isl_id *id);
+
+__isl_give isl_id *isl_id_alloc(isl_ctx *ctx,
+	__isl_keep const char *name, void *user);
+__isl_give isl_id *isl_id_copy(isl_id *id);
+__isl_null isl_id *isl_id_free(__isl_take isl_id *id);
+
+void *isl_id_get_user(__isl_keep isl_id *id);
+__isl_keep const char *isl_id_get_name(__isl_keep isl_id *id);
+
+__isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id,
+	void (*free_user)(void *user));
+
+__isl_give char *isl_id_to_str(__isl_keep isl_id *id);
+__isl_give isl_printer *isl_printer_print_id(__isl_take isl_printer *p,
+	__isl_keep isl_id *id);
+void isl_id_dump(__isl_keep isl_id *id);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/id_to_ast_expr.h b/final/lib/External/isl/include/isl/id_to_ast_expr.h
new file mode 100644
index 0000000..a160a9f
--- /dev/null
+++ b/final/lib/External/isl/include/isl/id_to_ast_expr.h
@@ -0,0 +1,18 @@
+#ifndef ISL_ID_TO_AST_EXPR_H
+#define ISL_ID_TO_AST_EXPR_H
+
+#include <isl/id.h>
+#include <isl/ast_type.h>
+#include <isl/maybe_ast_expr.h>
+
+#define ISL_KEY		isl_id
+#define ISL_VAL		isl_ast_expr
+#define ISL_HMAP_SUFFIX	id_to_ast_expr
+#define ISL_HMAP	isl_id_to_ast_expr
+#include <isl/hmap.h>
+#undef ISL_KEY
+#undef ISL_VAL
+#undef ISL_HMAP_SUFFIX
+#undef ISL_HMAP
+
+#endif
diff --git a/final/lib/External/isl/include/isl/id_to_id.h b/final/lib/External/isl/include/isl/id_to_id.h
new file mode 100644
index 0000000..26bbc59
--- /dev/null
+++ b/final/lib/External/isl/include/isl/id_to_id.h
@@ -0,0 +1,17 @@
+#ifndef ISL_ID_TO_ID_H
+#define ISL_ID_TO_ID_H
+
+#include <isl/id.h>
+#include <isl/maybe_id.h>
+
+#define ISL_KEY		isl_id
+#define ISL_VAL		isl_id
+#define ISL_HMAP_SUFFIX	id_to_id
+#define ISL_HMAP	isl_id_to_id
+#include <isl/hmap.h>
+#undef ISL_KEY
+#undef ISL_VAL
+#undef ISL_HMAP_SUFFIX
+#undef ISL_HMAP
+
+#endif
diff --git a/final/lib/External/isl/include/isl/id_to_pw_aff.h b/final/lib/External/isl/include/isl/id_to_pw_aff.h
new file mode 100644
index 0000000..081cc84
--- /dev/null
+++ b/final/lib/External/isl/include/isl/id_to_pw_aff.h
@@ -0,0 +1,18 @@
+#ifndef ISL_ID_TO_PW_AFF_H
+#define ISL_ID_TO_PW_AFF_H
+
+#include <isl/id.h>
+#include <isl/aff_type.h>
+#include <isl/maybe_pw_aff.h>
+
+#define ISL_KEY		isl_id
+#define ISL_VAL		isl_pw_aff
+#define ISL_HMAP_SUFFIX	id_to_pw_aff
+#define ISL_HMAP	isl_id_to_pw_aff
+#include <isl/hmap.h>
+#undef ISL_KEY
+#undef ISL_VAL
+#undef ISL_HMAP_SUFFIX
+#undef ISL_HMAP
+
+#endif
diff --git a/final/lib/External/isl/include/isl/ilp.h b/final/lib/External/isl/include/isl/ilp.h
new file mode 100644
index 0000000..2b8898b
--- /dev/null
+++ b/final/lib/External/isl/include/isl/ilp.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_ILP_H
+#define ISL_ILP_H
+
+#include <isl/aff_type.h>
+#include <isl/set_type.h>
+#include <isl/union_set_type.h>
+#include <isl/val.h>
+#include <isl/vec.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_val *isl_basic_set_max_val(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_aff *obj);
+__isl_export
+__isl_give isl_val *isl_set_min_val(__isl_keep isl_set *set,
+	__isl_keep isl_aff *obj);
+__isl_export
+__isl_give isl_val *isl_set_max_val(__isl_keep isl_set *set,
+	__isl_keep isl_aff *obj);
+__isl_give isl_multi_val *isl_union_set_min_multi_union_pw_aff(
+	__isl_keep isl_union_set *set, __isl_keep isl_multi_union_pw_aff *obj);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/isl-noexceptions.h b/final/lib/External/isl/include/isl/isl-noexceptions.h
new file mode 100644
index 0000000..b1d5c6d
--- /dev/null
+++ b/final/lib/External/isl/include/isl/isl-noexceptions.h
@@ -0,0 +1,15252 @@
+/// These are automatically generated C++ bindings for isl.
+///
+/// isl is a library for computing with integer sets and maps described by
+/// Presburger formulas. On top of this, isl provides various tools for
+/// polyhedral compilation, ranging from dependence analysis over scheduling
+/// to AST generation.
+
+#ifndef ISL_CPP_NOEXCEPTIONS
+#define ISL_CPP_NOEXCEPTIONS
+
+#include <isl/aff.h>
+#include <isl/ast_build.h>
+#include <isl/constraint.h>
+#include <isl/flow.h>
+#include <isl/id.h>
+#include <isl/ilp.h>
+#include <isl/map.h>
+#include <isl/schedule.h>
+#include <isl/schedule_node.h>
+#include <isl/set.h>
+#include <isl/union_map.h>
+#include <isl/union_set.h>
+#include <isl/val.h>
+#include <isl/polynomial.h>
+
+#include <functional>
+#include <string>
+
+namespace isl {
+inline namespace noexceptions {
+
+#define ISLPP_STRINGIZE_(X) #X
+#define ISLPP_STRINGIZE(X) ISLPP_STRINGIZE_(X)
+
+#define ISLPP_ASSERT(test, message)                          \
+  do {                                                       \
+    if (test)                                                \
+      break;                                                 \
+    fputs("Assertion \"" #test "\" failed at " __FILE__      \
+      ":" ISLPP_STRINGIZE(__LINE__) "\n  " message "\n",     \
+      stderr);                                               \
+  } while (0)
+
+class boolean {
+private:
+  isl_bool val;
+
+  friend isl::boolean manage(isl_bool val);
+  boolean(isl_bool val): val(val) {}
+public:
+  boolean()
+      : val(isl_bool_error) {}
+
+  /* implicit */ boolean(bool val)
+      : val(val ? isl_bool_true : isl_bool_false) {}
+
+  bool is_error() const { return val == isl_bool_error; }
+  bool is_false() const { return val == isl_bool_false; }
+  bool is_true() const { return val == isl_bool_true; }
+
+  operator bool() const {
+    ISLPP_ASSERT(!is_error(), "IMPLEMENTATION ERROR: Unhandled error state");
+    return is_true();
+  }
+
+  boolean operator!() const {
+    if (is_error())
+      return *this;
+    return !is_true();
+  }
+};
+
+inline isl::boolean manage(isl_bool val) {
+  return isl::boolean(val);
+}
+
+class ctx {
+  isl_ctx *ptr;
+public:
+  /* implicit */ ctx(isl_ctx *ctx)
+      : ptr(ctx) {}
+  isl_ctx *release() {
+    auto tmp = ptr;
+    ptr = nullptr;
+    return tmp;
+  }
+  isl_ctx *get() {
+    return ptr;
+  }
+};
+
+enum class stat {
+  ok = isl_stat_ok,
+  error = isl_stat_error
+};
+
+enum class dim {
+  cst = isl_dim_cst,
+  param = isl_dim_param,
+  in = isl_dim_in,
+  out = isl_dim_out,
+  set = isl_dim_set,
+  div = isl_dim_div,
+  all = isl_dim_all
+};
+
+}
+} // namespace isl
+
+namespace isl {
+
+inline namespace noexceptions {
+
+// forward declarations
+class aff;
+class aff_list;
+class ast_build;
+class ast_expr;
+class ast_expr_list;
+class ast_node;
+class ast_node_list;
+class band_list;
+class basic_map;
+class basic_map_list;
+class basic_set;
+class basic_set_list;
+class constraint;
+class constraint_list;
+class id;
+class id_list;
+class id_to_ast_expr;
+class local_space;
+class map;
+class map_list;
+class multi_aff;
+class multi_pw_aff;
+class multi_union_pw_aff;
+class multi_val;
+class point;
+class pw_aff;
+class pw_aff_list;
+class pw_multi_aff;
+class pw_qpolynomial;
+class qpolynomial;
+class schedule;
+class schedule_constraints;
+class schedule_node;
+class set;
+class set_list;
+class space;
+class term;
+class union_access_info;
+class union_flow;
+class union_map;
+class union_map_list;
+class union_pw_aff;
+class union_pw_aff_list;
+class union_pw_multi_aff;
+class union_pw_multi_aff_list;
+class union_pw_qpolynomial;
+class union_set;
+class union_set_list;
+class val;
+class val_list;
+
+// declarations for isl::aff
+inline isl::aff manage(__isl_take isl_aff *ptr);
+inline isl::aff give(__isl_take isl_aff *ptr);
+
+
+class aff {
+  friend inline isl::aff manage(__isl_take isl_aff *ptr);
+
+  isl_aff *ptr = nullptr;
+
+  inline explicit aff(__isl_take isl_aff *ptr);
+
+public:
+  inline /* implicit */ aff();
+  inline /* implicit */ aff(const isl::aff &obj);
+  inline /* implicit */ aff(std::nullptr_t);
+  inline explicit aff(isl::local_space ls);
+  inline explicit aff(isl::local_space ls, isl::val val);
+  inline explicit aff(isl::ctx ctx, const std::string &str);
+  inline isl::aff &operator=(isl::aff obj);
+  inline ~aff();
+  inline __isl_give isl_aff *copy() const &;
+  inline __isl_give isl_aff *copy() && = delete;
+  inline __isl_keep isl_aff *get() const;
+  inline __isl_give isl_aff *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_aff *keep() const;
+  inline __isl_give isl_aff *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::aff add(isl::aff aff2) const;
+  inline isl::aff add_coefficient_si(isl::dim type, int pos, int v) const;
+  inline isl::aff add_coefficient_val(isl::dim type, int pos, isl::val v) const;
+  inline isl::aff add_constant_num_si(int v) const;
+  inline isl::aff add_constant_si(int v) const;
+  inline isl::aff add_constant_val(isl::val v) const;
+  inline isl::aff add_dims(isl::dim type, unsigned int n) const;
+  inline isl::aff align_params(isl::space model) const;
+  inline isl::aff ceil() const;
+  inline int coefficient_sgn(isl::dim type, int pos) const;
+  inline int dim(isl::dim type) const;
+  inline isl::aff div(isl::aff aff2) const;
+  inline isl::aff drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::basic_set eq_basic_set(isl::aff aff2) const;
+  inline isl::set eq_set(isl::aff aff2) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::aff floor() const;
+  inline isl::basic_set ge_basic_set(isl::aff aff2) const;
+  inline isl::set ge_set(isl::aff aff2) const;
+  inline isl::val get_coefficient_val(isl::dim type, int pos) const;
+  inline isl::val get_constant_val() const;
+  inline isl::val get_denominator_val() const;
+  inline std::string get_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::aff get_div(int pos) const;
+  inline isl::local_space get_domain_local_space() const;
+  inline isl::space get_domain_space() const;
+  inline uint32_t get_hash() const;
+  inline isl::local_space get_local_space() const;
+  inline isl::space get_space() const;
+  inline isl::aff gist(isl::set context) const;
+  inline isl::aff gist_params(isl::set context) const;
+  inline isl::basic_set gt_basic_set(isl::aff aff2) const;
+  inline isl::set gt_set(isl::aff aff2) const;
+  inline isl::aff insert_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean is_cst() const;
+  inline isl::boolean is_nan() const;
+  inline isl::basic_set le_basic_set(isl::aff aff2) const;
+  inline isl::set le_set(isl::aff aff2) const;
+  inline isl::basic_set lt_basic_set(isl::aff aff2) const;
+  inline isl::set lt_set(isl::aff aff2) const;
+  inline isl::aff mod(isl::val mod) const;
+  inline isl::aff move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const;
+  inline isl::aff mul(isl::aff aff2) const;
+  static inline isl::aff nan_on_domain(isl::local_space ls);
+  inline isl::set ne_set(isl::aff aff2) const;
+  inline isl::aff neg() const;
+  inline isl::basic_set neg_basic_set() const;
+  inline isl::boolean plain_is_equal(const isl::aff &aff2) const;
+  inline isl::boolean plain_is_zero() const;
+  inline isl::aff project_domain_on_params() const;
+  inline isl::aff pullback(isl::multi_aff ma) const;
+  inline isl::aff pullback_aff(isl::aff aff2) const;
+  inline isl::aff scale(isl::val v) const;
+  inline isl::aff scale_down(isl::val v) const;
+  inline isl::aff scale_down_ui(unsigned int f) const;
+  inline isl::aff set_coefficient_si(isl::dim type, int pos, int v) const;
+  inline isl::aff set_coefficient_val(isl::dim type, int pos, isl::val v) const;
+  inline isl::aff set_constant_si(int v) const;
+  inline isl::aff set_constant_val(isl::val v) const;
+  inline isl::aff set_dim_id(isl::dim type, unsigned int pos, isl::id id) const;
+  inline isl::aff set_tuple_id(isl::dim type, isl::id id) const;
+  inline isl::aff sub(isl::aff aff2) const;
+  static inline isl::aff var_on_domain(isl::local_space ls, isl::dim type, unsigned int pos);
+  inline isl::basic_set zero_basic_set() const;
+};
+
+// declarations for isl::aff_list
+inline isl::aff_list manage(__isl_take isl_aff_list *ptr);
+inline isl::aff_list give(__isl_take isl_aff_list *ptr);
+
+
+class aff_list {
+  friend inline isl::aff_list manage(__isl_take isl_aff_list *ptr);
+
+  isl_aff_list *ptr = nullptr;
+
+  inline explicit aff_list(__isl_take isl_aff_list *ptr);
+
+public:
+  inline /* implicit */ aff_list();
+  inline /* implicit */ aff_list(const isl::aff_list &obj);
+  inline /* implicit */ aff_list(std::nullptr_t);
+  inline isl::aff_list &operator=(isl::aff_list obj);
+  inline ~aff_list();
+  inline __isl_give isl_aff_list *copy() const &;
+  inline __isl_give isl_aff_list *copy() && = delete;
+  inline __isl_keep isl_aff_list *get() const;
+  inline __isl_give isl_aff_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_aff_list *keep() const;
+  inline __isl_give isl_aff_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::ast_build
+inline isl::ast_build manage(__isl_take isl_ast_build *ptr);
+inline isl::ast_build give(__isl_take isl_ast_build *ptr);
+
+
+class ast_build {
+  friend inline isl::ast_build manage(__isl_take isl_ast_build *ptr);
+
+  isl_ast_build *ptr = nullptr;
+
+  inline explicit ast_build(__isl_take isl_ast_build *ptr);
+
+public:
+  inline /* implicit */ ast_build();
+  inline /* implicit */ ast_build(const isl::ast_build &obj);
+  inline /* implicit */ ast_build(std::nullptr_t);
+  inline explicit ast_build(isl::ctx ctx);
+  inline isl::ast_build &operator=(isl::ast_build obj);
+  inline ~ast_build();
+  inline __isl_give isl_ast_build *copy() const &;
+  inline __isl_give isl_ast_build *copy() && = delete;
+  inline __isl_keep isl_ast_build *get() const;
+  inline __isl_give isl_ast_build *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_ast_build *keep() const;
+  inline __isl_give isl_ast_build *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+
+  inline isl::ast_expr access_from(isl::pw_multi_aff pma) const;
+  inline isl::ast_expr access_from(isl::multi_pw_aff mpa) const;
+  inline isl::ast_node ast_from_schedule(isl::union_map schedule) const;
+  inline isl::ast_expr call_from(isl::pw_multi_aff pma) const;
+  inline isl::ast_expr call_from(isl::multi_pw_aff mpa) const;
+  inline isl::ast_expr expr_from(isl::set set) const;
+  inline isl::ast_expr expr_from(isl::pw_aff pa) const;
+  static inline isl::ast_build from_context(isl::set set);
+  inline isl::union_map get_schedule() const;
+  inline isl::space get_schedule_space() const;
+  inline isl::ast_node node_from_schedule(isl::schedule schedule) const;
+  inline isl::ast_node node_from_schedule_map(isl::union_map schedule) const;
+  inline isl::ast_build restrict(isl::set set) const;
+};
+
+// declarations for isl::ast_expr
+inline isl::ast_expr manage(__isl_take isl_ast_expr *ptr);
+inline isl::ast_expr give(__isl_take isl_ast_expr *ptr);
+
+
+class ast_expr {
+  friend inline isl::ast_expr manage(__isl_take isl_ast_expr *ptr);
+
+  isl_ast_expr *ptr = nullptr;
+
+  inline explicit ast_expr(__isl_take isl_ast_expr *ptr);
+
+public:
+  inline /* implicit */ ast_expr();
+  inline /* implicit */ ast_expr(const isl::ast_expr &obj);
+  inline /* implicit */ ast_expr(std::nullptr_t);
+  inline isl::ast_expr &operator=(isl::ast_expr obj);
+  inline ~ast_expr();
+  inline __isl_give isl_ast_expr *copy() const &;
+  inline __isl_give isl_ast_expr *copy() && = delete;
+  inline __isl_keep isl_ast_expr *get() const;
+  inline __isl_give isl_ast_expr *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_ast_expr *keep() const;
+  inline __isl_give isl_ast_expr *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::ast_expr access(isl::ast_expr_list indices) const;
+  inline isl::ast_expr add(isl::ast_expr expr2) const;
+  inline isl::ast_expr address_of() const;
+  inline isl::ast_expr call(isl::ast_expr_list arguments) const;
+  inline isl::ast_expr div(isl::ast_expr expr2) const;
+  inline isl::ast_expr eq(isl::ast_expr expr2) const;
+  static inline isl::ast_expr from_id(isl::id id);
+  static inline isl::ast_expr from_val(isl::val v);
+  inline isl::ast_expr ge(isl::ast_expr expr2) const;
+  inline isl::id get_id() const;
+  inline isl::ast_expr get_op_arg(int pos) const;
+  inline isl::val get_val() const;
+  inline isl::ast_expr gt(isl::ast_expr expr2) const;
+  inline isl::boolean is_equal(const isl::ast_expr &expr2) const;
+  inline isl::ast_expr le(isl::ast_expr expr2) const;
+  inline isl::ast_expr lt(isl::ast_expr expr2) const;
+  inline isl::ast_expr mul(isl::ast_expr expr2) const;
+  inline isl::ast_expr neg() const;
+  inline isl::ast_expr pdiv_q(isl::ast_expr expr2) const;
+  inline isl::ast_expr pdiv_r(isl::ast_expr expr2) const;
+  inline isl::ast_expr set_op_arg(int pos, isl::ast_expr arg) const;
+  inline isl::ast_expr sub(isl::ast_expr expr2) const;
+  inline isl::ast_expr substitute_ids(isl::id_to_ast_expr id2expr) const;
+  inline std::string to_C_str() const;
+};
+
+// declarations for isl::ast_expr_list
+inline isl::ast_expr_list manage(__isl_take isl_ast_expr_list *ptr);
+inline isl::ast_expr_list give(__isl_take isl_ast_expr_list *ptr);
+
+
+class ast_expr_list {
+  friend inline isl::ast_expr_list manage(__isl_take isl_ast_expr_list *ptr);
+
+  isl_ast_expr_list *ptr = nullptr;
+
+  inline explicit ast_expr_list(__isl_take isl_ast_expr_list *ptr);
+
+public:
+  inline /* implicit */ ast_expr_list();
+  inline /* implicit */ ast_expr_list(const isl::ast_expr_list &obj);
+  inline /* implicit */ ast_expr_list(std::nullptr_t);
+  inline isl::ast_expr_list &operator=(isl::ast_expr_list obj);
+  inline ~ast_expr_list();
+  inline __isl_give isl_ast_expr_list *copy() const &;
+  inline __isl_give isl_ast_expr_list *copy() && = delete;
+  inline __isl_keep isl_ast_expr_list *get() const;
+  inline __isl_give isl_ast_expr_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_ast_expr_list *keep() const;
+  inline __isl_give isl_ast_expr_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::ast_node
+inline isl::ast_node manage(__isl_take isl_ast_node *ptr);
+inline isl::ast_node give(__isl_take isl_ast_node *ptr);
+
+
+class ast_node {
+  friend inline isl::ast_node manage(__isl_take isl_ast_node *ptr);
+
+  isl_ast_node *ptr = nullptr;
+
+  inline explicit ast_node(__isl_take isl_ast_node *ptr);
+
+public:
+  inline /* implicit */ ast_node();
+  inline /* implicit */ ast_node(const isl::ast_node &obj);
+  inline /* implicit */ ast_node(std::nullptr_t);
+  inline isl::ast_node &operator=(isl::ast_node obj);
+  inline ~ast_node();
+  inline __isl_give isl_ast_node *copy() const &;
+  inline __isl_give isl_ast_node *copy() && = delete;
+  inline __isl_keep isl_ast_node *get() const;
+  inline __isl_give isl_ast_node *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_ast_node *keep() const;
+  inline __isl_give isl_ast_node *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  static inline isl::ast_node alloc_user(isl::ast_expr expr);
+  inline isl::ast_node_list block_get_children() const;
+  inline isl::ast_node for_get_body() const;
+  inline isl::ast_expr for_get_cond() const;
+  inline isl::ast_expr for_get_inc() const;
+  inline isl::ast_expr for_get_init() const;
+  inline isl::ast_expr for_get_iterator() const;
+  inline isl::boolean for_is_degenerate() const;
+  inline isl::id get_annotation() const;
+  inline isl::ast_expr if_get_cond() const;
+  inline isl::ast_node if_get_else() const;
+  inline isl::ast_node if_get_then() const;
+  inline isl::boolean if_has_else() const;
+  inline isl::id mark_get_id() const;
+  inline isl::ast_node mark_get_node() const;
+  inline isl::ast_node set_annotation(isl::id annotation) const;
+  inline std::string to_C_str() const;
+  inline isl::ast_expr user_get_expr() const;
+};
+
+// declarations for isl::ast_node_list
+inline isl::ast_node_list manage(__isl_take isl_ast_node_list *ptr);
+inline isl::ast_node_list give(__isl_take isl_ast_node_list *ptr);
+
+
+class ast_node_list {
+  friend inline isl::ast_node_list manage(__isl_take isl_ast_node_list *ptr);
+
+  isl_ast_node_list *ptr = nullptr;
+
+  inline explicit ast_node_list(__isl_take isl_ast_node_list *ptr);
+
+public:
+  inline /* implicit */ ast_node_list();
+  inline /* implicit */ ast_node_list(const isl::ast_node_list &obj);
+  inline /* implicit */ ast_node_list(std::nullptr_t);
+  inline isl::ast_node_list &operator=(isl::ast_node_list obj);
+  inline ~ast_node_list();
+  inline __isl_give isl_ast_node_list *copy() const &;
+  inline __isl_give isl_ast_node_list *copy() && = delete;
+  inline __isl_keep isl_ast_node_list *get() const;
+  inline __isl_give isl_ast_node_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_ast_node_list *keep() const;
+  inline __isl_give isl_ast_node_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::band_list
+inline isl::band_list manage(__isl_take isl_band_list *ptr);
+inline isl::band_list give(__isl_take isl_band_list *ptr);
+
+
+class band_list {
+  friend inline isl::band_list manage(__isl_take isl_band_list *ptr);
+
+  isl_band_list *ptr = nullptr;
+
+  inline explicit band_list(__isl_take isl_band_list *ptr);
+
+public:
+  inline /* implicit */ band_list();
+  inline /* implicit */ band_list(const isl::band_list &obj);
+  inline /* implicit */ band_list(std::nullptr_t);
+  inline isl::band_list &operator=(isl::band_list obj);
+  inline ~band_list();
+  inline __isl_give isl_band_list *copy() const &;
+  inline __isl_give isl_band_list *copy() && = delete;
+  inline __isl_keep isl_band_list *get() const;
+  inline __isl_give isl_band_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_band_list *keep() const;
+  inline __isl_give isl_band_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::basic_map
+inline isl::basic_map manage(__isl_take isl_basic_map *ptr);
+inline isl::basic_map give(__isl_take isl_basic_map *ptr);
+
+
+class basic_map {
+  friend inline isl::basic_map manage(__isl_take isl_basic_map *ptr);
+
+  isl_basic_map *ptr = nullptr;
+
+  inline explicit basic_map(__isl_take isl_basic_map *ptr);
+
+public:
+  inline /* implicit */ basic_map();
+  inline /* implicit */ basic_map(const isl::basic_map &obj);
+  inline /* implicit */ basic_map(std::nullptr_t);
+  inline explicit basic_map(isl::ctx ctx, const std::string &str);
+  inline isl::basic_map &operator=(isl::basic_map obj);
+  inline ~basic_map();
+  inline __isl_give isl_basic_map *copy() const &;
+  inline __isl_give isl_basic_map *copy() && = delete;
+  inline __isl_keep isl_basic_map *get() const;
+  inline __isl_give isl_basic_map *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_basic_map *keep() const;
+  inline __isl_give isl_basic_map *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::basic_map add_constraint(isl::constraint constraint) const;
+  inline isl::basic_map add_dims(isl::dim type, unsigned int n) const;
+  inline isl::basic_map affine_hull() const;
+  inline isl::basic_map align_params(isl::space model) const;
+  inline isl::basic_map apply_domain(isl::basic_map bmap2) const;
+  inline isl::basic_map apply_range(isl::basic_map bmap2) const;
+  inline isl::boolean can_curry() const;
+  inline isl::boolean can_uncurry() const;
+  inline isl::boolean can_zip() const;
+  inline isl::basic_map curry() const;
+  inline isl::basic_set deltas() const;
+  inline isl::basic_map deltas_map() const;
+  inline isl::basic_map detect_equalities() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::basic_set domain() const;
+  inline isl::basic_map domain_map() const;
+  inline isl::basic_map domain_product(isl::basic_map bmap2) const;
+  inline isl::basic_map drop_constraints_involving_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::basic_map drop_constraints_not_involving_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::basic_map eliminate(isl::dim type, unsigned int first, unsigned int n) const;
+  static inline isl::basic_map empty(isl::space dim);
+  static inline isl::basic_map equal(isl::space dim, unsigned int n_equal);
+  inline isl::basic_map equate(isl::dim type1, int pos1, isl::dim type2, int pos2) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::basic_map fix_si(isl::dim type, unsigned int pos, int value) const;
+  inline isl::basic_map fix_val(isl::dim type, unsigned int pos, isl::val v) const;
+  inline isl::basic_map flat_product(isl::basic_map bmap2) const;
+  inline isl::basic_map flat_range_product(isl::basic_map bmap2) const;
+  inline isl::basic_map flatten() const;
+  inline isl::basic_map flatten_domain() const;
+  inline isl::basic_map flatten_range() const;
+  inline isl::stat foreach_constraint(const std::function<isl::stat(isl::constraint)> &fn) const;
+  static inline isl::basic_map from_aff(isl::aff aff);
+  static inline isl::basic_map from_aff_list(isl::space domain_dim, isl::aff_list list);
+  static inline isl::basic_map from_constraint(isl::constraint constraint);
+  static inline isl::basic_map from_domain(isl::basic_set bset);
+  static inline isl::basic_map from_domain_and_range(isl::basic_set domain, isl::basic_set range);
+  static inline isl::basic_map from_multi_aff(isl::multi_aff maff);
+  static inline isl::basic_map from_qpolynomial(isl::qpolynomial qp);
+  static inline isl::basic_map from_range(isl::basic_set bset);
+  inline isl::constraint_list get_constraint_list() const;
+  inline std::string get_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::aff get_div(int pos) const;
+  inline isl::local_space get_local_space() const;
+  inline isl::space get_space() const;
+  inline std::string get_tuple_name(isl::dim type) const;
+  inline isl::basic_map gist(isl::basic_map context) const;
+  inline isl::basic_map gist_domain(isl::basic_set context) const;
+  inline isl::boolean has_dim_id(isl::dim type, unsigned int pos) const;
+  static inline isl::basic_map identity(isl::space dim);
+  inline isl::boolean image_is_bounded() const;
+  inline isl::basic_map insert_dims(isl::dim type, unsigned int pos, unsigned int n) const;
+  inline isl::basic_map intersect(isl::basic_map bmap2) const;
+  inline isl::basic_map intersect_domain(isl::basic_set bset) const;
+  inline isl::basic_map intersect_range(isl::basic_set bset) const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean is_disjoint(const isl::basic_map &bmap2) const;
+  inline isl::boolean is_empty() const;
+  inline isl::boolean is_equal(const isl::basic_map &bmap2) const;
+  inline isl::boolean is_rational() const;
+  inline isl::boolean is_single_valued() const;
+  inline isl::boolean is_strict_subset(const isl::basic_map &bmap2) const;
+  inline isl::boolean is_subset(const isl::basic_map &bmap2) const;
+  inline isl::boolean is_universe() const;
+  static inline isl::basic_map less_at(isl::space dim, unsigned int pos);
+  inline isl::map lexmax() const;
+  inline isl::map lexmin() const;
+  inline isl::pw_multi_aff lexmin_pw_multi_aff() const;
+  inline isl::basic_map lower_bound_si(isl::dim type, unsigned int pos, int value) const;
+  static inline isl::basic_map more_at(isl::space dim, unsigned int pos);
+  inline isl::basic_map move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const;
+  static inline isl::basic_map nat_universe(isl::space dim);
+  inline isl::basic_map neg() const;
+  inline isl::basic_map order_ge(isl::dim type1, int pos1, isl::dim type2, int pos2) const;
+  inline isl::basic_map order_gt(isl::dim type1, int pos1, isl::dim type2, int pos2) const;
+  inline isl::val plain_get_val_if_fixed(isl::dim type, unsigned int pos) const;
+  inline isl::boolean plain_is_empty() const;
+  inline isl::boolean plain_is_universe() const;
+  inline isl::basic_map preimage_domain_multi_aff(isl::multi_aff ma) const;
+  inline isl::basic_map preimage_range_multi_aff(isl::multi_aff ma) const;
+  inline isl::basic_map product(isl::basic_map bmap2) const;
+  inline isl::basic_map project_out(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::basic_set range() const;
+  inline isl::basic_map range_map() const;
+  inline isl::basic_map range_product(isl::basic_map bmap2) const;
+  inline isl::basic_map remove_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::basic_map remove_divs() const;
+  inline isl::basic_map remove_divs_involving_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::basic_map remove_redundancies() const;
+  inline isl::basic_map reverse() const;
+  inline isl::basic_map sample() const;
+  inline isl::basic_map set_tuple_id(isl::dim type, isl::id id) const;
+  inline isl::basic_map set_tuple_name(isl::dim type, const std::string &s) const;
+  inline isl::basic_map sum(isl::basic_map bmap2) const;
+  inline isl::basic_map uncurry() const;
+  inline isl::map unite(isl::basic_map bmap2) const;
+  static inline isl::basic_map universe(isl::space dim);
+  inline isl::basic_map upper_bound_si(isl::dim type, unsigned int pos, int value) const;
+  inline isl::basic_set wrap() const;
+  inline isl::basic_map zip() const;
+};
+
+// declarations for isl::basic_map_list
+inline isl::basic_map_list manage(__isl_take isl_basic_map_list *ptr);
+inline isl::basic_map_list give(__isl_take isl_basic_map_list *ptr);
+
+
+class basic_map_list {
+  friend inline isl::basic_map_list manage(__isl_take isl_basic_map_list *ptr);
+
+  isl_basic_map_list *ptr = nullptr;
+
+  inline explicit basic_map_list(__isl_take isl_basic_map_list *ptr);
+
+public:
+  inline /* implicit */ basic_map_list();
+  inline /* implicit */ basic_map_list(const isl::basic_map_list &obj);
+  inline /* implicit */ basic_map_list(std::nullptr_t);
+  inline isl::basic_map_list &operator=(isl::basic_map_list obj);
+  inline ~basic_map_list();
+  inline __isl_give isl_basic_map_list *copy() const &;
+  inline __isl_give isl_basic_map_list *copy() && = delete;
+  inline __isl_keep isl_basic_map_list *get() const;
+  inline __isl_give isl_basic_map_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_basic_map_list *keep() const;
+  inline __isl_give isl_basic_map_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::basic_set
+inline isl::basic_set manage(__isl_take isl_basic_set *ptr);
+inline isl::basic_set give(__isl_take isl_basic_set *ptr);
+
+
+class basic_set {
+  friend inline isl::basic_set manage(__isl_take isl_basic_set *ptr);
+
+  isl_basic_set *ptr = nullptr;
+
+  inline explicit basic_set(__isl_take isl_basic_set *ptr);
+
+public:
+  inline /* implicit */ basic_set();
+  inline /* implicit */ basic_set(const isl::basic_set &obj);
+  inline /* implicit */ basic_set(std::nullptr_t);
+  inline explicit basic_set(isl::ctx ctx, const std::string &str);
+  inline /* implicit */ basic_set(isl::point pnt);
+  inline isl::basic_set &operator=(isl::basic_set obj);
+  inline ~basic_set();
+  inline __isl_give isl_basic_set *copy() const &;
+  inline __isl_give isl_basic_set *copy() && = delete;
+  inline __isl_keep isl_basic_set *get() const;
+  inline __isl_give isl_basic_set *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_basic_set *keep() const;
+  inline __isl_give isl_basic_set *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::basic_set affine_hull() const;
+  inline isl::basic_set align_params(isl::space model) const;
+  inline isl::basic_set apply(isl::basic_map bmap) const;
+  static inline isl::basic_set box_from_points(isl::point pnt1, isl::point pnt2);
+  inline isl::basic_set coefficients() const;
+  inline isl::basic_set detect_equalities() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::basic_set drop_constraints_involving_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::basic_set drop_constraints_not_involving_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::basic_set eliminate(isl::dim type, unsigned int first, unsigned int n) const;
+  static inline isl::basic_set empty(isl::space dim);
+  inline isl::basic_set fix_si(isl::dim type, unsigned int pos, int value) const;
+  inline isl::basic_set fix_val(isl::dim type, unsigned int pos, isl::val v) const;
+  inline isl::basic_set flat_product(isl::basic_set bset2) const;
+  inline isl::basic_set flatten() const;
+  inline isl::stat foreach_bound_pair(isl::dim type, unsigned int pos, const std::function<isl::stat(isl::constraint, isl::constraint, isl::basic_set)> &fn) const;
+  inline isl::stat foreach_constraint(const std::function<isl::stat(isl::constraint)> &fn) const;
+  static inline isl::basic_set from_constraint(isl::constraint constraint);
+  inline isl::basic_set from_params() const;
+  inline isl::constraint_list get_constraint_list() const;
+  inline isl::id get_dim_id(isl::dim type, unsigned int pos) const;
+  inline std::string get_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::aff get_div(int pos) const;
+  inline isl::local_space get_local_space() const;
+  inline isl::space get_space() const;
+  inline std::string get_tuple_name() const;
+  inline isl::basic_set gist(isl::basic_set context) const;
+  inline isl::basic_set insert_dims(isl::dim type, unsigned int pos, unsigned int n) const;
+  inline isl::basic_set intersect(isl::basic_set bset2) const;
+  inline isl::basic_set intersect_params(isl::basic_set bset2) const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean is_bounded() const;
+  inline isl::boolean is_disjoint(const isl::basic_set &bset2) const;
+  inline isl::boolean is_empty() const;
+  inline isl::boolean is_equal(const isl::basic_set &bset2) const;
+  inline int is_rational() const;
+  inline isl::boolean is_subset(const isl::basic_set &bset2) const;
+  inline isl::boolean is_universe() const;
+  inline isl::boolean is_wrapping() const;
+  inline isl::set lexmax() const;
+  inline isl::set lexmin() const;
+  inline isl::basic_set lower_bound_val(isl::dim type, unsigned int pos, isl::val value) const;
+  inline isl::val max_val(const isl::aff &obj) const;
+  inline isl::basic_set move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const;
+  static inline isl::basic_set nat_universe(isl::space dim);
+  inline isl::basic_set neg() const;
+  inline isl::basic_set params() const;
+  inline isl::boolean plain_is_empty() const;
+  inline isl::boolean plain_is_equal(const isl::basic_set &bset2) const;
+  inline isl::boolean plain_is_universe() const;
+  static inline isl::basic_set positive_orthant(isl::space space);
+  inline isl::basic_set preimage_multi_aff(isl::multi_aff ma) const;
+  inline isl::basic_set project_out(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::basic_set remove_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::basic_set remove_divs() const;
+  inline isl::basic_set remove_divs_involving_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::basic_set remove_redundancies() const;
+  inline isl::basic_set remove_unknown_divs() const;
+  inline isl::basic_set sample() const;
+  inline isl::point sample_point() const;
+  inline isl::basic_set set_tuple_id(isl::id id) const;
+  inline isl::basic_set set_tuple_name(const std::string &s) const;
+  inline isl::basic_set solutions() const;
+  inline isl::set unite(isl::basic_set bset2) const;
+  static inline isl::basic_set universe(isl::space dim);
+  inline isl::basic_map unwrap() const;
+  inline isl::basic_set upper_bound_val(isl::dim type, unsigned int pos, isl::val value) const;
+};
+
+// declarations for isl::basic_set_list
+inline isl::basic_set_list manage(__isl_take isl_basic_set_list *ptr);
+inline isl::basic_set_list give(__isl_take isl_basic_set_list *ptr);
+
+
+class basic_set_list {
+  friend inline isl::basic_set_list manage(__isl_take isl_basic_set_list *ptr);
+
+  isl_basic_set_list *ptr = nullptr;
+
+  inline explicit basic_set_list(__isl_take isl_basic_set_list *ptr);
+
+public:
+  inline /* implicit */ basic_set_list();
+  inline /* implicit */ basic_set_list(const isl::basic_set_list &obj);
+  inline /* implicit */ basic_set_list(std::nullptr_t);
+  inline isl::basic_set_list &operator=(isl::basic_set_list obj);
+  inline ~basic_set_list();
+  inline __isl_give isl_basic_set_list *copy() const &;
+  inline __isl_give isl_basic_set_list *copy() && = delete;
+  inline __isl_keep isl_basic_set_list *get() const;
+  inline __isl_give isl_basic_set_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_basic_set_list *keep() const;
+  inline __isl_give isl_basic_set_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::constraint
+inline isl::constraint manage(__isl_take isl_constraint *ptr);
+inline isl::constraint give(__isl_take isl_constraint *ptr);
+
+
+class constraint {
+  friend inline isl::constraint manage(__isl_take isl_constraint *ptr);
+
+  isl_constraint *ptr = nullptr;
+
+  inline explicit constraint(__isl_take isl_constraint *ptr);
+
+public:
+  inline /* implicit */ constraint();
+  inline /* implicit */ constraint(const isl::constraint &obj);
+  inline /* implicit */ constraint(std::nullptr_t);
+  inline isl::constraint &operator=(isl::constraint obj);
+  inline ~constraint();
+  inline __isl_give isl_constraint *copy() const &;
+  inline __isl_give isl_constraint *copy() && = delete;
+  inline __isl_keep isl_constraint *get() const;
+  inline __isl_give isl_constraint *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_constraint *keep() const;
+  inline __isl_give isl_constraint *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+  static inline isl::constraint alloc_equality(isl::local_space ls);
+  static inline isl::constraint alloc_inequality(isl::local_space ls);
+  inline int cmp_last_non_zero(const isl::constraint &c2) const;
+  inline isl::aff get_aff() const;
+  inline isl::aff get_bound(isl::dim type, int pos) const;
+  inline isl::val get_coefficient_val(isl::dim type, int pos) const;
+  inline isl::val get_constant_val() const;
+  inline std::string get_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::aff get_div(int pos) const;
+  inline isl::local_space get_local_space() const;
+  inline isl::space get_space() const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline int is_div_constraint() const;
+  inline isl::boolean is_lower_bound(isl::dim type, unsigned int pos) const;
+  inline isl::boolean is_upper_bound(isl::dim type, unsigned int pos) const;
+  inline int plain_cmp(const isl::constraint &c2) const;
+  inline isl::constraint set_coefficient_si(isl::dim type, int pos, int v) const;
+  inline isl::constraint set_coefficient_val(isl::dim type, int pos, isl::val v) const;
+  inline isl::constraint set_constant_si(int v) const;
+  inline isl::constraint set_constant_val(isl::val v) const;
+};
+
+// declarations for isl::constraint_list
+inline isl::constraint_list manage(__isl_take isl_constraint_list *ptr);
+inline isl::constraint_list give(__isl_take isl_constraint_list *ptr);
+
+
+class constraint_list {
+  friend inline isl::constraint_list manage(__isl_take isl_constraint_list *ptr);
+
+  isl_constraint_list *ptr = nullptr;
+
+  inline explicit constraint_list(__isl_take isl_constraint_list *ptr);
+
+public:
+  inline /* implicit */ constraint_list();
+  inline /* implicit */ constraint_list(const isl::constraint_list &obj);
+  inline /* implicit */ constraint_list(std::nullptr_t);
+  inline isl::constraint_list &operator=(isl::constraint_list obj);
+  inline ~constraint_list();
+  inline __isl_give isl_constraint_list *copy() const &;
+  inline __isl_give isl_constraint_list *copy() && = delete;
+  inline __isl_keep isl_constraint_list *get() const;
+  inline __isl_give isl_constraint_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_constraint_list *keep() const;
+  inline __isl_give isl_constraint_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::id
+inline isl::id manage(__isl_take isl_id *ptr);
+inline isl::id give(__isl_take isl_id *ptr);
+
+
+class id {
+  friend inline isl::id manage(__isl_take isl_id *ptr);
+
+  isl_id *ptr = nullptr;
+
+  inline explicit id(__isl_take isl_id *ptr);
+
+public:
+  inline /* implicit */ id();
+  inline /* implicit */ id(const isl::id &obj);
+  inline /* implicit */ id(std::nullptr_t);
+  inline isl::id &operator=(isl::id obj);
+  inline ~id();
+  inline __isl_give isl_id *copy() const &;
+  inline __isl_give isl_id *copy() && = delete;
+  inline __isl_keep isl_id *get() const;
+  inline __isl_give isl_id *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_id *keep() const;
+  inline __isl_give isl_id *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  static inline isl::id alloc(isl::ctx ctx, const std::string &name, void * user);
+  inline uint32_t get_hash() const;
+  inline std::string get_name() const;
+  inline void * get_user() const;
+};
+
+// declarations for isl::id_list
+inline isl::id_list manage(__isl_take isl_id_list *ptr);
+inline isl::id_list give(__isl_take isl_id_list *ptr);
+
+
+class id_list {
+  friend inline isl::id_list manage(__isl_take isl_id_list *ptr);
+
+  isl_id_list *ptr = nullptr;
+
+  inline explicit id_list(__isl_take isl_id_list *ptr);
+
+public:
+  inline /* implicit */ id_list();
+  inline /* implicit */ id_list(const isl::id_list &obj);
+  inline /* implicit */ id_list(std::nullptr_t);
+  inline isl::id_list &operator=(isl::id_list obj);
+  inline ~id_list();
+  inline __isl_give isl_id_list *copy() const &;
+  inline __isl_give isl_id_list *copy() && = delete;
+  inline __isl_keep isl_id_list *get() const;
+  inline __isl_give isl_id_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_id_list *keep() const;
+  inline __isl_give isl_id_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::id_to_ast_expr
+inline isl::id_to_ast_expr manage(__isl_take isl_id_to_ast_expr *ptr);
+inline isl::id_to_ast_expr give(__isl_take isl_id_to_ast_expr *ptr);
+
+
+class id_to_ast_expr {
+  friend inline isl::id_to_ast_expr manage(__isl_take isl_id_to_ast_expr *ptr);
+
+  isl_id_to_ast_expr *ptr = nullptr;
+
+  inline explicit id_to_ast_expr(__isl_take isl_id_to_ast_expr *ptr);
+
+public:
+  inline /* implicit */ id_to_ast_expr();
+  inline /* implicit */ id_to_ast_expr(const isl::id_to_ast_expr &obj);
+  inline /* implicit */ id_to_ast_expr(std::nullptr_t);
+  inline isl::id_to_ast_expr &operator=(isl::id_to_ast_expr obj);
+  inline ~id_to_ast_expr();
+  inline __isl_give isl_id_to_ast_expr *copy() const &;
+  inline __isl_give isl_id_to_ast_expr *copy() && = delete;
+  inline __isl_keep isl_id_to_ast_expr *get() const;
+  inline __isl_give isl_id_to_ast_expr *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_id_to_ast_expr *keep() const;
+  inline __isl_give isl_id_to_ast_expr *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+  static inline isl::id_to_ast_expr alloc(isl::ctx ctx, int min_size);
+  inline isl::id_to_ast_expr drop(isl::id key) const;
+  inline isl::stat foreach(const std::function<isl::stat(isl::id, isl::ast_expr)> &fn) const;
+  inline isl::ast_expr get(isl::id key) const;
+  inline isl::boolean has(const isl::id &key) const;
+  inline isl::id_to_ast_expr set(isl::id key, isl::ast_expr val) const;
+};
+
+// declarations for isl::local_space
+inline isl::local_space manage(__isl_take isl_local_space *ptr);
+inline isl::local_space give(__isl_take isl_local_space *ptr);
+
+
+class local_space {
+  friend inline isl::local_space manage(__isl_take isl_local_space *ptr);
+
+  isl_local_space *ptr = nullptr;
+
+  inline explicit local_space(__isl_take isl_local_space *ptr);
+
+public:
+  inline /* implicit */ local_space();
+  inline /* implicit */ local_space(const isl::local_space &obj);
+  inline /* implicit */ local_space(std::nullptr_t);
+  inline explicit local_space(isl::space dim);
+  inline isl::local_space &operator=(isl::local_space obj);
+  inline ~local_space();
+  inline __isl_give isl_local_space *copy() const &;
+  inline __isl_give isl_local_space *copy() && = delete;
+  inline __isl_keep isl_local_space *get() const;
+  inline __isl_give isl_local_space *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_local_space *keep() const;
+  inline __isl_give isl_local_space *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+  inline isl::local_space add_dims(isl::dim type, unsigned int n) const;
+  inline int dim(isl::dim type) const;
+  inline isl::local_space domain() const;
+  inline isl::local_space drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::local_space flatten_domain() const;
+  inline isl::local_space flatten_range() const;
+  inline isl::local_space from_domain() const;
+  inline isl::id get_dim_id(isl::dim type, unsigned int pos) const;
+  inline std::string get_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::aff get_div(int pos) const;
+  inline isl::space get_space() const;
+  inline isl::boolean has_dim_id(isl::dim type, unsigned int pos) const;
+  inline isl::boolean has_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::local_space insert_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::local_space intersect(isl::local_space ls2) const;
+  inline isl::boolean is_equal(const isl::local_space &ls2) const;
+  inline isl::boolean is_params() const;
+  inline isl::boolean is_set() const;
+  inline isl::local_space range() const;
+  inline isl::local_space set_dim_id(isl::dim type, unsigned int pos, isl::id id) const;
+  inline isl::local_space set_tuple_id(isl::dim type, isl::id id) const;
+  inline isl::local_space wrap() const;
+};
+
+// declarations for isl::map
+inline isl::map manage(__isl_take isl_map *ptr);
+inline isl::map give(__isl_take isl_map *ptr);
+
+
+class map {
+  friend inline isl::map manage(__isl_take isl_map *ptr);
+
+  isl_map *ptr = nullptr;
+
+  inline explicit map(__isl_take isl_map *ptr);
+
+public:
+  inline /* implicit */ map();
+  inline /* implicit */ map(const isl::map &obj);
+  inline /* implicit */ map(std::nullptr_t);
+  inline explicit map(isl::ctx ctx, const std::string &str);
+  inline /* implicit */ map(isl::basic_map bmap);
+  inline isl::map &operator=(isl::map obj);
+  inline ~map();
+  inline __isl_give isl_map *copy() const &;
+  inline __isl_give isl_map *copy() && = delete;
+  inline __isl_keep isl_map *get() const;
+  inline __isl_give isl_map *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_map *keep() const;
+  inline __isl_give isl_map *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::map add_constraint(isl::constraint constraint) const;
+  inline isl::map add_dims(isl::dim type, unsigned int n) const;
+  inline isl::basic_map affine_hull() const;
+  inline isl::map align_params(isl::space model) const;
+  inline isl::map apply_domain(isl::map map2) const;
+  inline isl::map apply_range(isl::map map2) const;
+  inline isl::boolean can_curry() const;
+  inline isl::boolean can_range_curry() const;
+  inline isl::boolean can_uncurry() const;
+  inline isl::boolean can_zip() const;
+  inline isl::map coalesce() const;
+  inline isl::map complement() const;
+  inline isl::basic_map convex_hull() const;
+  inline isl::map curry() const;
+  inline isl::set deltas() const;
+  inline isl::map deltas_map() const;
+  inline isl::map detect_equalities() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::pw_aff dim_max(int pos) const;
+  inline isl::pw_aff dim_min(int pos) const;
+  inline isl::set domain() const;
+  inline isl::map domain_factor_domain() const;
+  inline isl::map domain_factor_range() const;
+  inline isl::boolean domain_is_wrapping() const;
+  inline isl::map domain_map() const;
+  inline isl::map domain_product(isl::map map2) const;
+  inline isl::map drop_constraints_involving_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::map drop_constraints_not_involving_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::map eliminate(isl::dim type, unsigned int first, unsigned int n) const;
+  static inline isl::map empty(isl::space dim);
+  inline isl::map equate(isl::dim type1, int pos1, isl::dim type2, int pos2) const;
+  inline isl::map factor_domain() const;
+  inline isl::map factor_range() const;
+  inline int find_dim_by_id(isl::dim type, const isl::id &id) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::map fix_si(isl::dim type, unsigned int pos, int value) const;
+  inline isl::map fix_val(isl::dim type, unsigned int pos, isl::val v) const;
+  inline isl::map fixed_power_val(isl::val exp) const;
+  inline isl::map flat_domain_product(isl::map map2) const;
+  inline isl::map flat_product(isl::map map2) const;
+  inline isl::map flat_range_product(isl::map map2) const;
+  inline isl::map flatten() const;
+  inline isl::map flatten_domain() const;
+  inline isl::map flatten_range() const;
+  inline isl::map floordiv_val(isl::val d) const;
+  inline isl::stat foreach_basic_map(const std::function<isl::stat(isl::basic_map)> &fn) const;
+  static inline isl::map from_aff(isl::aff aff);
+  static inline isl::map from_domain(isl::set set);
+  static inline isl::map from_domain_and_range(isl::set domain, isl::set range);
+  static inline isl::map from_multi_aff(isl::multi_aff maff);
+  static inline isl::map from_multi_pw_aff(isl::multi_pw_aff mpa);
+  static inline isl::map from_pw_aff(isl::pw_aff pwaff);
+  static inline isl::map from_pw_multi_aff(isl::pw_multi_aff pma);
+  static inline isl::map from_range(isl::set set);
+  static inline isl::map from_union_map(isl::union_map umap);
+  inline isl::id get_dim_id(isl::dim type, unsigned int pos) const;
+  inline std::string get_dim_name(isl::dim type, unsigned int pos) const;
+  inline uint32_t get_hash() const;
+  inline isl::space get_space() const;
+  inline isl::id get_tuple_id(isl::dim type) const;
+  inline std::string get_tuple_name(isl::dim type) const;
+  inline isl::map gist(isl::map context) const;
+  inline isl::map gist_basic_map(isl::basic_map context) const;
+  inline isl::map gist_domain(isl::set context) const;
+  inline isl::map gist_params(isl::set context) const;
+  inline isl::map gist_range(isl::set context) const;
+  inline isl::boolean has_dim_id(isl::dim type, unsigned int pos) const;
+  inline isl::boolean has_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::boolean has_equal_space(const isl::map &map2) const;
+  inline isl::boolean has_tuple_id(isl::dim type) const;
+  inline isl::boolean has_tuple_name(isl::dim type) const;
+  static inline isl::map identity(isl::space dim);
+  inline isl::map insert_dims(isl::dim type, unsigned int pos, unsigned int n) const;
+  inline isl::map intersect(isl::map map2) const;
+  inline isl::map intersect_domain(isl::set set) const;
+  inline isl::map intersect_domain_factor_range(isl::map factor) const;
+  inline isl::map intersect_params(isl::set params) const;
+  inline isl::map intersect_range(isl::set set) const;
+  inline isl::map intersect_range_factor_range(isl::map factor) const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean is_bijective() const;
+  inline isl::boolean is_disjoint(const isl::map &map2) const;
+  inline isl::boolean is_empty() const;
+  inline isl::boolean is_equal(const isl::map &map2) const;
+  inline isl::boolean is_identity() const;
+  inline isl::boolean is_injective() const;
+  inline isl::boolean is_product() const;
+  inline isl::boolean is_single_valued() const;
+  inline isl::boolean is_strict_subset(const isl::map &map2) const;
+  inline isl::boolean is_subset(const isl::map &map2) const;
+  inline int is_translation() const;
+  static inline isl::map lex_ge(isl::space set_dim);
+  static inline isl::map lex_ge_first(isl::space dim, unsigned int n);
+  inline isl::map lex_ge_map(isl::map map2) const;
+  static inline isl::map lex_gt(isl::space set_dim);
+  static inline isl::map lex_gt_first(isl::space dim, unsigned int n);
+  inline isl::map lex_gt_map(isl::map map2) const;
+  static inline isl::map lex_le(isl::space set_dim);
+  static inline isl::map lex_le_first(isl::space dim, unsigned int n);
+  inline isl::map lex_le_map(isl::map map2) const;
+  static inline isl::map lex_lt(isl::space set_dim);
+  static inline isl::map lex_lt_first(isl::space dim, unsigned int n);
+  inline isl::map lex_lt_map(isl::map map2) const;
+  inline isl::map lexmax() const;
+  inline isl::pw_multi_aff lexmax_pw_multi_aff() const;
+  inline isl::map lexmin() const;
+  inline isl::pw_multi_aff lexmin_pw_multi_aff() const;
+  inline isl::map lower_bound_si(isl::dim type, unsigned int pos, int value) const;
+  inline isl::map move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const;
+  static inline isl::map nat_universe(isl::space dim);
+  inline isl::map neg() const;
+  inline isl::map oppose(isl::dim type1, int pos1, isl::dim type2, int pos2) const;
+  inline isl::map order_ge(isl::dim type1, int pos1, isl::dim type2, int pos2) const;
+  inline isl::map order_gt(isl::dim type1, int pos1, isl::dim type2, int pos2) const;
+  inline isl::map order_le(isl::dim type1, int pos1, isl::dim type2, int pos2) const;
+  inline isl::map order_lt(isl::dim type1, int pos1, isl::dim type2, int pos2) const;
+  inline isl::set params() const;
+  inline isl::val plain_get_val_if_fixed(isl::dim type, unsigned int pos) const;
+  inline isl::boolean plain_is_empty() const;
+  inline isl::boolean plain_is_equal(const isl::map &map2) const;
+  inline isl::boolean plain_is_injective() const;
+  inline isl::boolean plain_is_single_valued() const;
+  inline isl::boolean plain_is_universe() const;
+  inline isl::basic_map plain_unshifted_simple_hull() const;
+  inline isl::basic_map polyhedral_hull() const;
+  inline isl::map preimage_domain_multi_aff(isl::multi_aff ma) const;
+  inline isl::map preimage_domain_multi_pw_aff(isl::multi_pw_aff mpa) const;
+  inline isl::map preimage_domain_pw_multi_aff(isl::pw_multi_aff pma) const;
+  inline isl::map preimage_range_multi_aff(isl::multi_aff ma) const;
+  inline isl::map preimage_range_pw_multi_aff(isl::pw_multi_aff pma) const;
+  inline isl::map product(isl::map map2) const;
+  inline isl::map project_out(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::set range() const;
+  inline isl::map range_curry() const;
+  inline isl::map range_factor_domain() const;
+  inline isl::map range_factor_range() const;
+  inline isl::boolean range_is_wrapping() const;
+  inline isl::map range_map() const;
+  inline isl::map range_product(isl::map map2) const;
+  inline isl::map remove_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::map remove_divs() const;
+  inline isl::map remove_divs_involving_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::map remove_redundancies() const;
+  inline isl::map remove_unknown_divs() const;
+  inline isl::map reset_tuple_id(isl::dim type) const;
+  inline isl::map reset_user() const;
+  inline isl::map reverse() const;
+  inline isl::basic_map sample() const;
+  inline isl::map set_dim_id(isl::dim type, unsigned int pos, isl::id id) const;
+  inline isl::map set_tuple_id(isl::dim type, isl::id id) const;
+  inline isl::map set_tuple_name(isl::dim type, const std::string &s) const;
+  inline isl::basic_map simple_hull() const;
+  inline isl::map subtract(isl::map map2) const;
+  inline isl::map subtract_domain(isl::set dom) const;
+  inline isl::map subtract_range(isl::set dom) const;
+  inline isl::map sum(isl::map map2) const;
+  inline isl::map uncurry() const;
+  inline isl::map unite(isl::map map2) const;
+  static inline isl::map universe(isl::space dim);
+  inline isl::basic_map unshifted_simple_hull() const;
+  inline isl::basic_map unshifted_simple_hull_from_map_list(isl::map_list list) const;
+  inline isl::map upper_bound_si(isl::dim type, unsigned int pos, int value) const;
+  inline isl::set wrap() const;
+  inline isl::map zip() const;
+};
+
+// declarations for isl::map_list
+inline isl::map_list manage(__isl_take isl_map_list *ptr);
+inline isl::map_list give(__isl_take isl_map_list *ptr);
+
+
+class map_list {
+  friend inline isl::map_list manage(__isl_take isl_map_list *ptr);
+
+  isl_map_list *ptr = nullptr;
+
+  inline explicit map_list(__isl_take isl_map_list *ptr);
+
+public:
+  inline /* implicit */ map_list();
+  inline /* implicit */ map_list(const isl::map_list &obj);
+  inline /* implicit */ map_list(std::nullptr_t);
+  inline isl::map_list &operator=(isl::map_list obj);
+  inline ~map_list();
+  inline __isl_give isl_map_list *copy() const &;
+  inline __isl_give isl_map_list *copy() && = delete;
+  inline __isl_keep isl_map_list *get() const;
+  inline __isl_give isl_map_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_map_list *keep() const;
+  inline __isl_give isl_map_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::multi_aff
+inline isl::multi_aff manage(__isl_take isl_multi_aff *ptr);
+inline isl::multi_aff give(__isl_take isl_multi_aff *ptr);
+
+
+class multi_aff {
+  friend inline isl::multi_aff manage(__isl_take isl_multi_aff *ptr);
+
+  isl_multi_aff *ptr = nullptr;
+
+  inline explicit multi_aff(__isl_take isl_multi_aff *ptr);
+
+public:
+  inline /* implicit */ multi_aff();
+  inline /* implicit */ multi_aff(const isl::multi_aff &obj);
+  inline /* implicit */ multi_aff(std::nullptr_t);
+  inline explicit multi_aff(isl::ctx ctx, const std::string &str);
+  inline /* implicit */ multi_aff(isl::aff aff);
+  inline isl::multi_aff &operator=(isl::multi_aff obj);
+  inline ~multi_aff();
+  inline __isl_give isl_multi_aff *copy() const &;
+  inline __isl_give isl_multi_aff *copy() && = delete;
+  inline __isl_keep isl_multi_aff *get() const;
+  inline __isl_give isl_multi_aff *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_multi_aff *keep() const;
+  inline __isl_give isl_multi_aff *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::multi_aff add(isl::multi_aff multi2) const;
+  inline isl::multi_aff add_dims(isl::dim type, unsigned int n) const;
+  inline isl::multi_aff align_params(isl::space model) const;
+  inline unsigned int dim(isl::dim type) const;
+  static inline isl::multi_aff domain_map(isl::space space);
+  inline isl::multi_aff drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::multi_aff factor_range() const;
+  inline int find_dim_by_id(isl::dim type, const isl::id &id) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::multi_aff flat_range_product(isl::multi_aff multi2) const;
+  inline isl::multi_aff flatten_domain() const;
+  inline isl::multi_aff flatten_range() const;
+  inline isl::multi_aff floor() const;
+  static inline isl::multi_aff from_aff_list(isl::space space, isl::aff_list list);
+  inline isl::multi_aff from_range() const;
+  inline isl::aff get_aff(int pos) const;
+  inline isl::id get_dim_id(isl::dim type, unsigned int pos) const;
+  inline isl::space get_domain_space() const;
+  inline isl::space get_space() const;
+  inline isl::id get_tuple_id(isl::dim type) const;
+  inline std::string get_tuple_name(isl::dim type) const;
+  inline isl::multi_aff gist(isl::set context) const;
+  inline isl::multi_aff gist_params(isl::set context) const;
+  inline isl::boolean has_tuple_id(isl::dim type) const;
+  static inline isl::multi_aff identity(isl::space space);
+  inline isl::multi_aff insert_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean involves_nan() const;
+  inline isl::set lex_ge_set(isl::multi_aff ma2) const;
+  inline isl::set lex_gt_set(isl::multi_aff ma2) const;
+  inline isl::set lex_le_set(isl::multi_aff ma2) const;
+  inline isl::set lex_lt_set(isl::multi_aff ma2) const;
+  inline isl::multi_aff mod_multi_val(isl::multi_val mv) const;
+  inline isl::multi_aff move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const;
+  static inline isl::multi_aff multi_val_on_space(isl::space space, isl::multi_val mv);
+  inline isl::multi_aff neg() const;
+  inline int plain_cmp(const isl::multi_aff &multi2) const;
+  inline isl::boolean plain_is_equal(const isl::multi_aff &multi2) const;
+  inline isl::multi_aff product(isl::multi_aff multi2) const;
+  static inline isl::multi_aff project_out_map(isl::space space, isl::dim type, unsigned int first, unsigned int n);
+  inline isl::multi_aff pullback(isl::multi_aff ma2) const;
+  inline isl::multi_aff range_factor_domain() const;
+  inline isl::multi_aff range_factor_range() const;
+  inline isl::boolean range_is_wrapping() const;
+  static inline isl::multi_aff range_map(isl::space space);
+  inline isl::multi_aff range_product(isl::multi_aff multi2) const;
+  inline isl::multi_aff range_splice(unsigned int pos, isl::multi_aff multi2) const;
+  inline isl::multi_aff reset_tuple_id(isl::dim type) const;
+  inline isl::multi_aff reset_user() const;
+  inline isl::multi_aff scale_down_multi_val(isl::multi_val mv) const;
+  inline isl::multi_aff scale_down_val(isl::val v) const;
+  inline isl::multi_aff scale_multi_val(isl::multi_val mv) const;
+  inline isl::multi_aff scale_val(isl::val v) const;
+  inline isl::multi_aff set_aff(int pos, isl::aff el) const;
+  inline isl::multi_aff set_dim_id(isl::dim type, unsigned int pos, isl::id id) const;
+  inline isl::multi_aff set_tuple_id(isl::dim type, isl::id id) const;
+  inline isl::multi_aff set_tuple_name(isl::dim type, const std::string &s) const;
+  inline isl::multi_aff splice(unsigned int in_pos, unsigned int out_pos, isl::multi_aff multi2) const;
+  inline isl::multi_aff sub(isl::multi_aff multi2) const;
+  static inline isl::multi_aff zero(isl::space space);
+};
+
+// declarations for isl::multi_pw_aff
+inline isl::multi_pw_aff manage(__isl_take isl_multi_pw_aff *ptr);
+inline isl::multi_pw_aff give(__isl_take isl_multi_pw_aff *ptr);
+
+
+class multi_pw_aff {
+  friend inline isl::multi_pw_aff manage(__isl_take isl_multi_pw_aff *ptr);
+
+  isl_multi_pw_aff *ptr = nullptr;
+
+  inline explicit multi_pw_aff(__isl_take isl_multi_pw_aff *ptr);
+
+public:
+  inline /* implicit */ multi_pw_aff();
+  inline /* implicit */ multi_pw_aff(const isl::multi_pw_aff &obj);
+  inline /* implicit */ multi_pw_aff(std::nullptr_t);
+  inline /* implicit */ multi_pw_aff(isl::multi_aff ma);
+  inline /* implicit */ multi_pw_aff(isl::pw_aff pa);
+  inline /* implicit */ multi_pw_aff(isl::pw_multi_aff pma);
+  inline explicit multi_pw_aff(isl::ctx ctx, const std::string &str);
+  inline isl::multi_pw_aff &operator=(isl::multi_pw_aff obj);
+  inline ~multi_pw_aff();
+  inline __isl_give isl_multi_pw_aff *copy() const &;
+  inline __isl_give isl_multi_pw_aff *copy() && = delete;
+  inline __isl_keep isl_multi_pw_aff *get() const;
+  inline __isl_give isl_multi_pw_aff *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_multi_pw_aff *keep() const;
+  inline __isl_give isl_multi_pw_aff *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::multi_pw_aff add(isl::multi_pw_aff multi2) const;
+  inline isl::multi_pw_aff add_dims(isl::dim type, unsigned int n) const;
+  inline isl::multi_pw_aff align_params(isl::space model) const;
+  inline isl::multi_pw_aff coalesce() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::set domain() const;
+  inline isl::multi_pw_aff drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::map eq_map(isl::multi_pw_aff mpa2) const;
+  inline isl::multi_pw_aff factor_range() const;
+  inline int find_dim_by_id(isl::dim type, const isl::id &id) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::multi_pw_aff flat_range_product(isl::multi_pw_aff multi2) const;
+  inline isl::multi_pw_aff flatten_range() const;
+  static inline isl::multi_pw_aff from_pw_aff_list(isl::space space, isl::pw_aff_list list);
+  inline isl::multi_pw_aff from_range() const;
+  inline isl::id get_dim_id(isl::dim type, unsigned int pos) const;
+  inline isl::space get_domain_space() const;
+  inline uint32_t get_hash() const;
+  inline isl::pw_aff get_pw_aff(int pos) const;
+  inline isl::space get_space() const;
+  inline isl::id get_tuple_id(isl::dim type) const;
+  inline std::string get_tuple_name(isl::dim type) const;
+  inline isl::multi_pw_aff gist(isl::set set) const;
+  inline isl::multi_pw_aff gist_params(isl::set set) const;
+  inline isl::boolean has_tuple_id(isl::dim type) const;
+  static inline isl::multi_pw_aff identity(isl::space space);
+  inline isl::multi_pw_aff insert_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::multi_pw_aff intersect_domain(isl::set domain) const;
+  inline isl::multi_pw_aff intersect_params(isl::set set) const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean involves_nan() const;
+  inline isl::boolean is_cst() const;
+  inline isl::boolean is_equal(const isl::multi_pw_aff &mpa2) const;
+  inline isl::map lex_gt_map(isl::multi_pw_aff mpa2) const;
+  inline isl::map lex_lt_map(isl::multi_pw_aff mpa2) const;
+  inline isl::multi_pw_aff mod_multi_val(isl::multi_val mv) const;
+  inline isl::multi_pw_aff move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const;
+  inline isl::multi_pw_aff neg() const;
+  inline isl::boolean plain_is_equal(const isl::multi_pw_aff &multi2) const;
+  inline isl::multi_pw_aff product(isl::multi_pw_aff multi2) const;
+  inline isl::multi_pw_aff pullback(isl::multi_aff ma) const;
+  inline isl::multi_pw_aff pullback(isl::pw_multi_aff pma) const;
+  inline isl::multi_pw_aff pullback(isl::multi_pw_aff mpa2) const;
+  inline isl::multi_pw_aff range_factor_domain() const;
+  inline isl::multi_pw_aff range_factor_range() const;
+  inline isl::boolean range_is_wrapping() const;
+  inline isl::multi_pw_aff range_product(isl::multi_pw_aff multi2) const;
+  inline isl::multi_pw_aff range_splice(unsigned int pos, isl::multi_pw_aff multi2) const;
+  inline isl::multi_pw_aff reset_tuple_id(isl::dim type) const;
+  inline isl::multi_pw_aff reset_user() const;
+  inline isl::multi_pw_aff scale_down_multi_val(isl::multi_val mv) const;
+  inline isl::multi_pw_aff scale_down_val(isl::val v) const;
+  inline isl::multi_pw_aff scale_multi_val(isl::multi_val mv) const;
+  inline isl::multi_pw_aff scale_val(isl::val v) const;
+  inline isl::multi_pw_aff set_dim_id(isl::dim type, unsigned int pos, isl::id id) const;
+  inline isl::multi_pw_aff set_pw_aff(int pos, isl::pw_aff el) const;
+  inline isl::multi_pw_aff set_tuple_id(isl::dim type, isl::id id) const;
+  inline isl::multi_pw_aff set_tuple_name(isl::dim type, const std::string &s) const;
+  inline isl::multi_pw_aff splice(unsigned int in_pos, unsigned int out_pos, isl::multi_pw_aff multi2) const;
+  inline isl::multi_pw_aff sub(isl::multi_pw_aff multi2) const;
+  static inline isl::multi_pw_aff zero(isl::space space);
+};
+
+// declarations for isl::multi_union_pw_aff
+inline isl::multi_union_pw_aff manage(__isl_take isl_multi_union_pw_aff *ptr);
+inline isl::multi_union_pw_aff give(__isl_take isl_multi_union_pw_aff *ptr);
+
+
+class multi_union_pw_aff {
+  friend inline isl::multi_union_pw_aff manage(__isl_take isl_multi_union_pw_aff *ptr);
+
+  isl_multi_union_pw_aff *ptr = nullptr;
+
+  inline explicit multi_union_pw_aff(__isl_take isl_multi_union_pw_aff *ptr);
+
+public:
+  inline /* implicit */ multi_union_pw_aff();
+  inline /* implicit */ multi_union_pw_aff(const isl::multi_union_pw_aff &obj);
+  inline /* implicit */ multi_union_pw_aff(std::nullptr_t);
+  inline /* implicit */ multi_union_pw_aff(isl::union_pw_aff upa);
+  inline /* implicit */ multi_union_pw_aff(isl::multi_pw_aff mpa);
+  inline explicit multi_union_pw_aff(isl::union_pw_multi_aff upma);
+  inline explicit multi_union_pw_aff(isl::ctx ctx, const std::string &str);
+  inline isl::multi_union_pw_aff &operator=(isl::multi_union_pw_aff obj);
+  inline ~multi_union_pw_aff();
+  inline __isl_give isl_multi_union_pw_aff *copy() const &;
+  inline __isl_give isl_multi_union_pw_aff *copy() && = delete;
+  inline __isl_keep isl_multi_union_pw_aff *get() const;
+  inline __isl_give isl_multi_union_pw_aff *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_multi_union_pw_aff *keep() const;
+  inline __isl_give isl_multi_union_pw_aff *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::multi_union_pw_aff add(isl::multi_union_pw_aff multi2) const;
+  inline isl::multi_union_pw_aff align_params(isl::space model) const;
+  inline isl::union_pw_aff apply_aff(isl::aff aff) const;
+  inline isl::union_pw_aff apply_pw_aff(isl::pw_aff pa) const;
+  inline isl::multi_union_pw_aff apply_pw_multi_aff(isl::pw_multi_aff pma) const;
+  inline isl::multi_union_pw_aff coalesce() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::union_set domain() const;
+  inline isl::multi_union_pw_aff drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::multi_pw_aff extract_multi_pw_aff(isl::space space) const;
+  inline isl::multi_union_pw_aff factor_range() const;
+  inline int find_dim_by_id(isl::dim type, const isl::id &id) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::multi_union_pw_aff flat_range_product(isl::multi_union_pw_aff multi2) const;
+  inline isl::multi_union_pw_aff flatten_range() const;
+  inline isl::multi_union_pw_aff floor() const;
+  static inline isl::multi_union_pw_aff from_multi_aff(isl::multi_aff ma);
+  inline isl::multi_union_pw_aff from_range() const;
+  static inline isl::multi_union_pw_aff from_union_map(isl::union_map umap);
+  static inline isl::multi_union_pw_aff from_union_pw_aff_list(isl::space space, isl::union_pw_aff_list list);
+  inline isl::id get_dim_id(isl::dim type, unsigned int pos) const;
+  inline isl::space get_domain_space() const;
+  inline isl::space get_space() const;
+  inline isl::id get_tuple_id(isl::dim type) const;
+  inline std::string get_tuple_name(isl::dim type) const;
+  inline isl::union_pw_aff get_union_pw_aff(int pos) const;
+  inline isl::multi_union_pw_aff gist(isl::union_set context) const;
+  inline isl::multi_union_pw_aff gist_params(isl::set context) const;
+  inline isl::boolean has_tuple_id(isl::dim type) const;
+  inline isl::multi_union_pw_aff intersect_domain(isl::union_set uset) const;
+  inline isl::multi_union_pw_aff intersect_params(isl::set params) const;
+  inline isl::multi_union_pw_aff intersect_range(isl::set set) const;
+  inline isl::boolean involves_nan() const;
+  inline isl::multi_union_pw_aff mod_multi_val(isl::multi_val mv) const;
+  static inline isl::multi_union_pw_aff multi_aff_on_domain(isl::union_set domain, isl::multi_aff ma);
+  static inline isl::multi_union_pw_aff multi_val_on_domain(isl::union_set domain, isl::multi_val mv);
+  inline isl::multi_union_pw_aff neg() const;
+  inline isl::boolean plain_is_equal(const isl::multi_union_pw_aff &multi2) const;
+  inline isl::multi_union_pw_aff pullback(isl::union_pw_multi_aff upma) const;
+  inline isl::multi_union_pw_aff range_factor_domain() const;
+  inline isl::multi_union_pw_aff range_factor_range() const;
+  inline isl::boolean range_is_wrapping() const;
+  inline isl::multi_union_pw_aff range_product(isl::multi_union_pw_aff multi2) const;
+  inline isl::multi_union_pw_aff range_splice(unsigned int pos, isl::multi_union_pw_aff multi2) const;
+  inline isl::multi_union_pw_aff reset_tuple_id(isl::dim type) const;
+  inline isl::multi_union_pw_aff reset_user() const;
+  inline isl::multi_union_pw_aff scale_down_multi_val(isl::multi_val mv) const;
+  inline isl::multi_union_pw_aff scale_down_val(isl::val v) const;
+  inline isl::multi_union_pw_aff scale_multi_val(isl::multi_val mv) const;
+  inline isl::multi_union_pw_aff scale_val(isl::val v) const;
+  inline isl::multi_union_pw_aff set_dim_id(isl::dim type, unsigned int pos, isl::id id) const;
+  inline isl::multi_union_pw_aff set_tuple_id(isl::dim type, isl::id id) const;
+  inline isl::multi_union_pw_aff set_tuple_name(isl::dim type, const std::string &s) const;
+  inline isl::multi_union_pw_aff set_union_pw_aff(int pos, isl::union_pw_aff el) const;
+  inline isl::multi_union_pw_aff sub(isl::multi_union_pw_aff multi2) const;
+  inline isl::multi_union_pw_aff union_add(isl::multi_union_pw_aff mupa2) const;
+  static inline isl::multi_union_pw_aff zero(isl::space space);
+  inline isl::union_set zero_union_set() const;
+};
+
+// declarations for isl::multi_val
+inline isl::multi_val manage(__isl_take isl_multi_val *ptr);
+inline isl::multi_val give(__isl_take isl_multi_val *ptr);
+
+
+class multi_val {
+  friend inline isl::multi_val manage(__isl_take isl_multi_val *ptr);
+
+  isl_multi_val *ptr = nullptr;
+
+  inline explicit multi_val(__isl_take isl_multi_val *ptr);
+
+public:
+  inline /* implicit */ multi_val();
+  inline /* implicit */ multi_val(const isl::multi_val &obj);
+  inline /* implicit */ multi_val(std::nullptr_t);
+  inline explicit multi_val(isl::ctx ctx, const std::string &str);
+  inline isl::multi_val &operator=(isl::multi_val obj);
+  inline ~multi_val();
+  inline __isl_give isl_multi_val *copy() const &;
+  inline __isl_give isl_multi_val *copy() && = delete;
+  inline __isl_keep isl_multi_val *get() const;
+  inline __isl_give isl_multi_val *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_multi_val *keep() const;
+  inline __isl_give isl_multi_val *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::multi_val add(isl::multi_val multi2) const;
+  inline isl::multi_val add_dims(isl::dim type, unsigned int n) const;
+  inline isl::multi_val add_val(isl::val v) const;
+  inline isl::multi_val align_params(isl::space model) const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::multi_val drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::multi_val factor_range() const;
+  inline int find_dim_by_id(isl::dim type, const isl::id &id) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::multi_val flat_range_product(isl::multi_val multi2) const;
+  inline isl::multi_val flatten_range() const;
+  inline isl::multi_val from_range() const;
+  static inline isl::multi_val from_val_list(isl::space space, isl::val_list list);
+  inline isl::id get_dim_id(isl::dim type, unsigned int pos) const;
+  inline isl::space get_domain_space() const;
+  inline isl::space get_space() const;
+  inline isl::id get_tuple_id(isl::dim type) const;
+  inline std::string get_tuple_name(isl::dim type) const;
+  inline isl::val get_val(int pos) const;
+  inline isl::boolean has_tuple_id(isl::dim type) const;
+  inline isl::multi_val insert_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean involves_nan() const;
+  inline isl::multi_val mod_multi_val(isl::multi_val mv) const;
+  inline isl::multi_val mod_val(isl::val v) const;
+  inline isl::multi_val neg() const;
+  inline isl::boolean plain_is_equal(const isl::multi_val &multi2) const;
+  inline isl::multi_val product(isl::multi_val multi2) const;
+  inline isl::multi_val range_factor_domain() const;
+  inline isl::multi_val range_factor_range() const;
+  inline isl::boolean range_is_wrapping() const;
+  inline isl::multi_val range_product(isl::multi_val multi2) const;
+  inline isl::multi_val range_splice(unsigned int pos, isl::multi_val multi2) const;
+  inline isl::multi_val reset_tuple_id(isl::dim type) const;
+  inline isl::multi_val reset_user() const;
+  inline isl::multi_val scale_down_multi_val(isl::multi_val mv) const;
+  inline isl::multi_val scale_down_val(isl::val v) const;
+  inline isl::multi_val scale_multi_val(isl::multi_val mv) const;
+  inline isl::multi_val scale_val(isl::val v) const;
+  inline isl::multi_val set_dim_id(isl::dim type, unsigned int pos, isl::id id) const;
+  inline isl::multi_val set_tuple_id(isl::dim type, isl::id id) const;
+  inline isl::multi_val set_tuple_name(isl::dim type, const std::string &s) const;
+  inline isl::multi_val set_val(int pos, isl::val el) const;
+  inline isl::multi_val splice(unsigned int in_pos, unsigned int out_pos, isl::multi_val multi2) const;
+  inline isl::multi_val sub(isl::multi_val multi2) const;
+  static inline isl::multi_val zero(isl::space space);
+};
+
+// declarations for isl::point
+inline isl::point manage(__isl_take isl_point *ptr);
+inline isl::point give(__isl_take isl_point *ptr);
+
+
+class point {
+  friend inline isl::point manage(__isl_take isl_point *ptr);
+
+  isl_point *ptr = nullptr;
+
+  inline explicit point(__isl_take isl_point *ptr);
+
+public:
+  inline /* implicit */ point();
+  inline /* implicit */ point(const isl::point &obj);
+  inline /* implicit */ point(std::nullptr_t);
+  inline explicit point(isl::space dim);
+  inline isl::point &operator=(isl::point obj);
+  inline ~point();
+  inline __isl_give isl_point *copy() const &;
+  inline __isl_give isl_point *copy() && = delete;
+  inline __isl_keep isl_point *get() const;
+  inline __isl_give isl_point *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_point *keep() const;
+  inline __isl_give isl_point *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::point add_ui(isl::dim type, int pos, unsigned int val) const;
+  inline isl::val get_coordinate_val(isl::dim type, int pos) const;
+  inline isl::space get_space() const;
+  inline isl::point set_coordinate_val(isl::dim type, int pos, isl::val v) const;
+  inline isl::point sub_ui(isl::dim type, int pos, unsigned int val) const;
+};
+
+// declarations for isl::pw_aff
+inline isl::pw_aff manage(__isl_take isl_pw_aff *ptr);
+inline isl::pw_aff give(__isl_take isl_pw_aff *ptr);
+
+
+class pw_aff {
+  friend inline isl::pw_aff manage(__isl_take isl_pw_aff *ptr);
+
+  isl_pw_aff *ptr = nullptr;
+
+  inline explicit pw_aff(__isl_take isl_pw_aff *ptr);
+
+public:
+  inline /* implicit */ pw_aff();
+  inline /* implicit */ pw_aff(const isl::pw_aff &obj);
+  inline /* implicit */ pw_aff(std::nullptr_t);
+  inline /* implicit */ pw_aff(isl::aff aff);
+  inline explicit pw_aff(isl::local_space ls);
+  inline explicit pw_aff(isl::set domain, isl::val v);
+  inline explicit pw_aff(isl::ctx ctx, const std::string &str);
+  inline isl::pw_aff &operator=(isl::pw_aff obj);
+  inline ~pw_aff();
+  inline __isl_give isl_pw_aff *copy() const &;
+  inline __isl_give isl_pw_aff *copy() && = delete;
+  inline __isl_keep isl_pw_aff *get() const;
+  inline __isl_give isl_pw_aff *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_pw_aff *keep() const;
+  inline __isl_give isl_pw_aff *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::pw_aff add(isl::pw_aff pwaff2) const;
+  inline isl::pw_aff add_dims(isl::dim type, unsigned int n) const;
+  inline isl::pw_aff align_params(isl::space model) const;
+  static inline isl::pw_aff alloc(isl::set set, isl::aff aff);
+  inline isl::pw_aff ceil() const;
+  inline isl::pw_aff coalesce() const;
+  inline isl::pw_aff cond(isl::pw_aff pwaff_true, isl::pw_aff pwaff_false) const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::pw_aff div(isl::pw_aff pa2) const;
+  inline isl::set domain() const;
+  inline isl::pw_aff drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  static inline isl::pw_aff empty(isl::space dim);
+  inline isl::map eq_map(isl::pw_aff pa2) const;
+  inline isl::set eq_set(isl::pw_aff pwaff2) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::pw_aff floor() const;
+  inline isl::stat foreach_piece(const std::function<isl::stat(isl::set, isl::aff)> &fn) const;
+  inline isl::pw_aff from_range() const;
+  inline isl::set ge_set(isl::pw_aff pwaff2) const;
+  inline isl::id get_dim_id(isl::dim type, unsigned int pos) const;
+  inline std::string get_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::space get_domain_space() const;
+  inline uint32_t get_hash() const;
+  inline isl::space get_space() const;
+  inline isl::id get_tuple_id(isl::dim type) const;
+  inline isl::pw_aff gist(isl::set context) const;
+  inline isl::pw_aff gist_params(isl::set context) const;
+  inline isl::map gt_map(isl::pw_aff pa2) const;
+  inline isl::set gt_set(isl::pw_aff pwaff2) const;
+  inline isl::boolean has_dim_id(isl::dim type, unsigned int pos) const;
+  inline isl::boolean has_tuple_id(isl::dim type) const;
+  inline isl::pw_aff insert_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::pw_aff intersect_domain(isl::set set) const;
+  inline isl::pw_aff intersect_params(isl::set set) const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean involves_nan() const;
+  inline isl::boolean is_cst() const;
+  inline isl::boolean is_empty() const;
+  inline isl::boolean is_equal(const isl::pw_aff &pa2) const;
+  inline isl::set le_set(isl::pw_aff pwaff2) const;
+  inline isl::map lt_map(isl::pw_aff pa2) const;
+  inline isl::set lt_set(isl::pw_aff pwaff2) const;
+  inline isl::pw_aff max(isl::pw_aff pwaff2) const;
+  inline isl::pw_aff min(isl::pw_aff pwaff2) const;
+  inline isl::pw_aff mod(isl::val mod) const;
+  inline isl::pw_aff move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const;
+  inline isl::pw_aff mul(isl::pw_aff pwaff2) const;
+  static inline isl::pw_aff nan_on_domain(isl::local_space ls);
+  inline isl::set ne_set(isl::pw_aff pwaff2) const;
+  inline isl::pw_aff neg() const;
+  inline isl::set non_zero_set() const;
+  inline isl::set nonneg_set() const;
+  inline isl::set params() const;
+  inline int plain_cmp(const isl::pw_aff &pa2) const;
+  inline isl::boolean plain_is_equal(const isl::pw_aff &pwaff2) const;
+  inline isl::set pos_set() const;
+  inline isl::pw_aff project_domain_on_params() const;
+  inline isl::pw_aff pullback(isl::multi_aff ma) const;
+  inline isl::pw_aff pullback(isl::pw_multi_aff pma) const;
+  inline isl::pw_aff pullback(isl::multi_pw_aff mpa) const;
+  inline isl::pw_aff reset_tuple_id(isl::dim type) const;
+  inline isl::pw_aff reset_user() const;
+  inline isl::pw_aff scale(isl::val v) const;
+  inline isl::pw_aff scale_down(isl::val f) const;
+  inline isl::pw_aff set_dim_id(isl::dim type, unsigned int pos, isl::id id) const;
+  inline isl::pw_aff set_tuple_id(isl::dim type, isl::id id) const;
+  inline isl::pw_aff sub(isl::pw_aff pwaff2) const;
+  inline isl::pw_aff subtract_domain(isl::set set) const;
+  inline isl::pw_aff tdiv_q(isl::pw_aff pa2) const;
+  inline isl::pw_aff tdiv_r(isl::pw_aff pa2) const;
+  inline isl::pw_aff union_add(isl::pw_aff pwaff2) const;
+  inline isl::pw_aff union_max(isl::pw_aff pwaff2) const;
+  inline isl::pw_aff union_min(isl::pw_aff pwaff2) const;
+  static inline isl::pw_aff var_on_domain(isl::local_space ls, isl::dim type, unsigned int pos);
+  inline isl::set zero_set() const;
+};
+
+// declarations for isl::pw_aff_list
+inline isl::pw_aff_list manage(__isl_take isl_pw_aff_list *ptr);
+inline isl::pw_aff_list give(__isl_take isl_pw_aff_list *ptr);
+
+
+class pw_aff_list {
+  friend inline isl::pw_aff_list manage(__isl_take isl_pw_aff_list *ptr);
+
+  isl_pw_aff_list *ptr = nullptr;
+
+  inline explicit pw_aff_list(__isl_take isl_pw_aff_list *ptr);
+
+public:
+  inline /* implicit */ pw_aff_list();
+  inline /* implicit */ pw_aff_list(const isl::pw_aff_list &obj);
+  inline /* implicit */ pw_aff_list(std::nullptr_t);
+  inline isl::pw_aff_list &operator=(isl::pw_aff_list obj);
+  inline ~pw_aff_list();
+  inline __isl_give isl_pw_aff_list *copy() const &;
+  inline __isl_give isl_pw_aff_list *copy() && = delete;
+  inline __isl_keep isl_pw_aff_list *get() const;
+  inline __isl_give isl_pw_aff_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_pw_aff_list *keep() const;
+  inline __isl_give isl_pw_aff_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::pw_multi_aff
+inline isl::pw_multi_aff manage(__isl_take isl_pw_multi_aff *ptr);
+inline isl::pw_multi_aff give(__isl_take isl_pw_multi_aff *ptr);
+
+
+class pw_multi_aff {
+  friend inline isl::pw_multi_aff manage(__isl_take isl_pw_multi_aff *ptr);
+
+  isl_pw_multi_aff *ptr = nullptr;
+
+  inline explicit pw_multi_aff(__isl_take isl_pw_multi_aff *ptr);
+
+public:
+  inline /* implicit */ pw_multi_aff();
+  inline /* implicit */ pw_multi_aff(const isl::pw_multi_aff &obj);
+  inline /* implicit */ pw_multi_aff(std::nullptr_t);
+  inline /* implicit */ pw_multi_aff(isl::multi_aff ma);
+  inline /* implicit */ pw_multi_aff(isl::pw_aff pa);
+  inline explicit pw_multi_aff(isl::ctx ctx, const std::string &str);
+  inline isl::pw_multi_aff &operator=(isl::pw_multi_aff obj);
+  inline ~pw_multi_aff();
+  inline __isl_give isl_pw_multi_aff *copy() const &;
+  inline __isl_give isl_pw_multi_aff *copy() && = delete;
+  inline __isl_keep isl_pw_multi_aff *get() const;
+  inline __isl_give isl_pw_multi_aff *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_pw_multi_aff *keep() const;
+  inline __isl_give isl_pw_multi_aff *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::pw_multi_aff add(isl::pw_multi_aff pma2) const;
+  inline isl::pw_multi_aff align_params(isl::space model) const;
+  static inline isl::pw_multi_aff alloc(isl::set set, isl::multi_aff maff);
+  inline isl::pw_multi_aff coalesce() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::set domain() const;
+  inline isl::pw_multi_aff drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  static inline isl::pw_multi_aff empty(isl::space space);
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::pw_multi_aff fix_si(isl::dim type, unsigned int pos, int value) const;
+  inline isl::pw_multi_aff flat_range_product(isl::pw_multi_aff pma2) const;
+  inline isl::stat foreach_piece(const std::function<isl::stat(isl::set, isl::multi_aff)> &fn) const;
+  static inline isl::pw_multi_aff from_domain(isl::set set);
+  static inline isl::pw_multi_aff from_map(isl::map map);
+  static inline isl::pw_multi_aff from_multi_pw_aff(isl::multi_pw_aff mpa);
+  static inline isl::pw_multi_aff from_set(isl::set set);
+  inline isl::id get_dim_id(isl::dim type, unsigned int pos) const;
+  inline std::string get_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::space get_domain_space() const;
+  inline isl::pw_aff get_pw_aff(int pos) const;
+  inline isl::space get_space() const;
+  inline isl::id get_tuple_id(isl::dim type) const;
+  inline std::string get_tuple_name(isl::dim type) const;
+  inline isl::pw_multi_aff gist(isl::set set) const;
+  inline isl::pw_multi_aff gist_params(isl::set set) const;
+  inline isl::boolean has_tuple_id(isl::dim type) const;
+  inline isl::boolean has_tuple_name(isl::dim type) const;
+  static inline isl::pw_multi_aff identity(isl::space space);
+  inline isl::pw_multi_aff intersect_domain(isl::set set) const;
+  inline isl::pw_multi_aff intersect_params(isl::set set) const;
+  inline isl::boolean involves_nan() const;
+  inline isl::boolean is_equal(const isl::pw_multi_aff &pma2) const;
+  static inline isl::pw_multi_aff multi_val_on_domain(isl::set domain, isl::multi_val mv);
+  inline isl::pw_multi_aff neg() const;
+  inline isl::boolean plain_is_equal(const isl::pw_multi_aff &pma2) const;
+  inline isl::pw_multi_aff product(isl::pw_multi_aff pma2) const;
+  inline isl::pw_multi_aff project_domain_on_params() const;
+  static inline isl::pw_multi_aff project_out_map(isl::space space, isl::dim type, unsigned int first, unsigned int n);
+  inline isl::pw_multi_aff pullback(isl::multi_aff ma) const;
+  inline isl::pw_multi_aff pullback(isl::pw_multi_aff pma2) const;
+  static inline isl::pw_multi_aff range_map(isl::space space);
+  inline isl::pw_multi_aff range_product(isl::pw_multi_aff pma2) const;
+  inline isl::pw_multi_aff reset_tuple_id(isl::dim type) const;
+  inline isl::pw_multi_aff reset_user() const;
+  inline isl::pw_multi_aff scale_down_val(isl::val v) const;
+  inline isl::pw_multi_aff scale_multi_val(isl::multi_val mv) const;
+  inline isl::pw_multi_aff scale_val(isl::val v) const;
+  inline isl::pw_multi_aff set_dim_id(isl::dim type, unsigned int pos, isl::id id) const;
+  inline isl::pw_multi_aff set_pw_aff(unsigned int pos, isl::pw_aff pa) const;
+  inline isl::pw_multi_aff set_tuple_id(isl::dim type, isl::id id) const;
+  inline isl::pw_multi_aff sub(isl::pw_multi_aff pma2) const;
+  inline isl::pw_multi_aff subtract_domain(isl::set set) const;
+  inline isl::pw_multi_aff union_add(isl::pw_multi_aff pma2) const;
+  inline isl::pw_multi_aff union_lexmax(isl::pw_multi_aff pma2) const;
+  inline isl::pw_multi_aff union_lexmin(isl::pw_multi_aff pma2) const;
+  static inline isl::pw_multi_aff zero(isl::space space);
+};
+
+// declarations for isl::pw_qpolynomial
+inline isl::pw_qpolynomial manage(__isl_take isl_pw_qpolynomial *ptr);
+inline isl::pw_qpolynomial give(__isl_take isl_pw_qpolynomial *ptr);
+
+
+class pw_qpolynomial {
+  friend inline isl::pw_qpolynomial manage(__isl_take isl_pw_qpolynomial *ptr);
+
+  isl_pw_qpolynomial *ptr = nullptr;
+
+  inline explicit pw_qpolynomial(__isl_take isl_pw_qpolynomial *ptr);
+
+public:
+  inline /* implicit */ pw_qpolynomial();
+  inline /* implicit */ pw_qpolynomial(const isl::pw_qpolynomial &obj);
+  inline /* implicit */ pw_qpolynomial(std::nullptr_t);
+  inline explicit pw_qpolynomial(isl::ctx ctx, const std::string &str);
+  inline isl::pw_qpolynomial &operator=(isl::pw_qpolynomial obj);
+  inline ~pw_qpolynomial();
+  inline __isl_give isl_pw_qpolynomial *copy() const &;
+  inline __isl_give isl_pw_qpolynomial *copy() && = delete;
+  inline __isl_keep isl_pw_qpolynomial *get() const;
+  inline __isl_give isl_pw_qpolynomial *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_pw_qpolynomial *keep() const;
+  inline __isl_give isl_pw_qpolynomial *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::pw_qpolynomial add(isl::pw_qpolynomial pwqp2) const;
+  inline isl::pw_qpolynomial add_dims(isl::dim type, unsigned int n) const;
+  static inline isl::pw_qpolynomial alloc(isl::set set, isl::qpolynomial qp);
+  inline isl::pw_qpolynomial coalesce() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::set domain() const;
+  inline isl::pw_qpolynomial drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::val eval(isl::point pnt) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::pw_qpolynomial fix_val(isl::dim type, unsigned int n, isl::val v) const;
+  inline isl::stat foreach_piece(const std::function<isl::stat(isl::set, isl::qpolynomial)> &fn) const;
+  static inline isl::pw_qpolynomial from_pw_aff(isl::pw_aff pwaff);
+  static inline isl::pw_qpolynomial from_qpolynomial(isl::qpolynomial qp);
+  inline isl::pw_qpolynomial from_range() const;
+  inline isl::space get_domain_space() const;
+  inline isl::space get_space() const;
+  inline isl::pw_qpolynomial gist(isl::set context) const;
+  inline isl::pw_qpolynomial gist_params(isl::set context) const;
+  inline isl::boolean has_equal_space(const isl::pw_qpolynomial &pwqp2) const;
+  inline isl::pw_qpolynomial insert_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::pw_qpolynomial intersect_domain(isl::set set) const;
+  inline isl::pw_qpolynomial intersect_params(isl::set set) const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean involves_nan() const;
+  inline isl::boolean is_zero() const;
+  inline isl::val max() const;
+  inline isl::val min() const;
+  inline isl::pw_qpolynomial move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const;
+  inline isl::pw_qpolynomial mul(isl::pw_qpolynomial pwqp2) const;
+  inline isl::pw_qpolynomial neg() const;
+  inline isl::boolean plain_is_equal(const isl::pw_qpolynomial &pwqp2) const;
+  inline isl::pw_qpolynomial pow(unsigned int exponent) const;
+  inline isl::pw_qpolynomial project_domain_on_params() const;
+  inline isl::pw_qpolynomial reset_domain_space(isl::space dim) const;
+  inline isl::pw_qpolynomial reset_user() const;
+  inline isl::pw_qpolynomial scale_down_val(isl::val v) const;
+  inline isl::pw_qpolynomial scale_val(isl::val v) const;
+  inline isl::pw_qpolynomial split_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::pw_qpolynomial split_periods(int max_periods) const;
+  inline isl::pw_qpolynomial sub(isl::pw_qpolynomial pwqp2) const;
+  inline isl::pw_qpolynomial subtract_domain(isl::set set) const;
+  inline isl::pw_qpolynomial to_polynomial(int sign) const;
+  static inline isl::pw_qpolynomial zero(isl::space dim);
+};
+
+// declarations for isl::qpolynomial
+inline isl::qpolynomial manage(__isl_take isl_qpolynomial *ptr);
+inline isl::qpolynomial give(__isl_take isl_qpolynomial *ptr);
+
+
+class qpolynomial {
+  friend inline isl::qpolynomial manage(__isl_take isl_qpolynomial *ptr);
+
+  isl_qpolynomial *ptr = nullptr;
+
+  inline explicit qpolynomial(__isl_take isl_qpolynomial *ptr);
+
+public:
+  inline /* implicit */ qpolynomial();
+  inline /* implicit */ qpolynomial(const isl::qpolynomial &obj);
+  inline /* implicit */ qpolynomial(std::nullptr_t);
+  inline isl::qpolynomial &operator=(isl::qpolynomial obj);
+  inline ~qpolynomial();
+  inline __isl_give isl_qpolynomial *copy() const &;
+  inline __isl_give isl_qpolynomial *copy() && = delete;
+  inline __isl_keep isl_qpolynomial *get() const;
+  inline __isl_give isl_qpolynomial *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_qpolynomial *keep() const;
+  inline __isl_give isl_qpolynomial *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+  inline isl::qpolynomial add(isl::qpolynomial qp2) const;
+  inline isl::qpolynomial add_dims(isl::dim type, unsigned int n) const;
+  inline isl::qpolynomial align_params(isl::space model) const;
+  inline isl::stat as_polynomial_on_domain(const isl::basic_set &bset, const std::function<isl::stat(isl::basic_set, isl::qpolynomial)> &fn) const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::qpolynomial drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::val eval(isl::point pnt) const;
+  inline isl::stat foreach_term(const std::function<isl::stat(isl::term)> &fn) const;
+  static inline isl::qpolynomial from_aff(isl::aff aff);
+  static inline isl::qpolynomial from_constraint(isl::constraint c, isl::dim type, unsigned int pos);
+  static inline isl::qpolynomial from_term(isl::term term);
+  inline isl::val get_constant_val() const;
+  inline isl::space get_domain_space() const;
+  inline isl::space get_space() const;
+  inline isl::qpolynomial gist(isl::set context) const;
+  inline isl::qpolynomial gist_params(isl::set context) const;
+  inline isl::qpolynomial homogenize() const;
+  static inline isl::qpolynomial infty_on_domain(isl::space dim);
+  inline isl::qpolynomial insert_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean is_infty() const;
+  inline isl::boolean is_nan() const;
+  inline isl::boolean is_neginfty() const;
+  inline isl::boolean is_zero() const;
+  inline isl::qpolynomial move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const;
+  inline isl::qpolynomial mul(isl::qpolynomial qp2) const;
+  static inline isl::qpolynomial nan_on_domain(isl::space dim);
+  inline isl::qpolynomial neg() const;
+  static inline isl::qpolynomial neginfty_on_domain(isl::space dim);
+  static inline isl::qpolynomial one_on_domain(isl::space dim);
+  inline isl::boolean plain_is_equal(const isl::qpolynomial &qp2) const;
+  inline isl::qpolynomial pow(unsigned int power) const;
+  inline isl::qpolynomial project_domain_on_params() const;
+  inline isl::qpolynomial scale_down_val(isl::val v) const;
+  inline isl::qpolynomial scale_val(isl::val v) const;
+  inline int sgn() const;
+  inline isl::qpolynomial sub(isl::qpolynomial qp2) const;
+  static inline isl::qpolynomial val_on_domain(isl::space space, isl::val val);
+  static inline isl::qpolynomial var_on_domain(isl::space dim, isl::dim type, unsigned int pos);
+  static inline isl::qpolynomial zero_on_domain(isl::space dim);
+};
+
+// declarations for isl::schedule
+inline isl::schedule manage(__isl_take isl_schedule *ptr);
+inline isl::schedule give(__isl_take isl_schedule *ptr);
+
+
+class schedule {
+  friend inline isl::schedule manage(__isl_take isl_schedule *ptr);
+
+  isl_schedule *ptr = nullptr;
+
+  inline explicit schedule(__isl_take isl_schedule *ptr);
+
+public:
+  inline /* implicit */ schedule();
+  inline /* implicit */ schedule(const isl::schedule &obj);
+  inline /* implicit */ schedule(std::nullptr_t);
+  inline explicit schedule(isl::ctx ctx, const std::string &str);
+  inline isl::schedule &operator=(isl::schedule obj);
+  inline ~schedule();
+  inline __isl_give isl_schedule *copy() const &;
+  inline __isl_give isl_schedule *copy() && = delete;
+  inline __isl_keep isl_schedule *get() const;
+  inline __isl_give isl_schedule *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_schedule *keep() const;
+  inline __isl_give isl_schedule *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::schedule align_params(isl::space space) const;
+  static inline isl::schedule empty(isl::space space);
+  static inline isl::schedule from_domain(isl::union_set domain);
+  inline isl::union_set get_domain() const;
+  inline isl::union_map get_map() const;
+  inline isl::schedule_node get_root() const;
+  inline isl::schedule gist_domain_params(isl::set context) const;
+  inline isl::schedule insert_context(isl::set context) const;
+  inline isl::schedule insert_guard(isl::set guard) const;
+  inline isl::schedule insert_partial_schedule(isl::multi_union_pw_aff partial) const;
+  inline isl::schedule intersect_domain(isl::union_set domain) const;
+  inline isl::boolean plain_is_equal(const isl::schedule &schedule2) const;
+  inline isl::schedule pullback(isl::union_pw_multi_aff upma) const;
+  inline isl::schedule reset_user() const;
+  inline isl::schedule sequence(isl::schedule schedule2) const;
+  inline isl::schedule set(isl::schedule schedule2) const;
+};
+
+// declarations for isl::schedule_constraints
+inline isl::schedule_constraints manage(__isl_take isl_schedule_constraints *ptr);
+inline isl::schedule_constraints give(__isl_take isl_schedule_constraints *ptr);
+
+
+class schedule_constraints {
+  friend inline isl::schedule_constraints manage(__isl_take isl_schedule_constraints *ptr);
+
+  isl_schedule_constraints *ptr = nullptr;
+
+  inline explicit schedule_constraints(__isl_take isl_schedule_constraints *ptr);
+
+public:
+  inline /* implicit */ schedule_constraints();
+  inline /* implicit */ schedule_constraints(const isl::schedule_constraints &obj);
+  inline /* implicit */ schedule_constraints(std::nullptr_t);
+  inline explicit schedule_constraints(isl::ctx ctx, const std::string &str);
+  inline isl::schedule_constraints &operator=(isl::schedule_constraints obj);
+  inline ~schedule_constraints();
+  inline __isl_give isl_schedule_constraints *copy() const &;
+  inline __isl_give isl_schedule_constraints *copy() && = delete;
+  inline __isl_keep isl_schedule_constraints *get() const;
+  inline __isl_give isl_schedule_constraints *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_schedule_constraints *keep() const;
+  inline __isl_give isl_schedule_constraints *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::schedule_constraints apply(isl::union_map umap) const;
+  inline isl::schedule compute_schedule() const;
+  inline isl::union_map get_coincidence() const;
+  inline isl::union_map get_conditional_validity() const;
+  inline isl::union_map get_conditional_validity_condition() const;
+  inline isl::set get_context() const;
+  inline isl::union_set get_domain() const;
+  inline isl::union_map get_proximity() const;
+  inline isl::union_map get_validity() const;
+  static inline isl::schedule_constraints on_domain(isl::union_set domain);
+  inline isl::schedule_constraints set_coincidence(isl::union_map coincidence) const;
+  inline isl::schedule_constraints set_conditional_validity(isl::union_map condition, isl::union_map validity) const;
+  inline isl::schedule_constraints set_context(isl::set context) const;
+  inline isl::schedule_constraints set_proximity(isl::union_map proximity) const;
+  inline isl::schedule_constraints set_validity(isl::union_map validity) const;
+};
+
+// declarations for isl::schedule_node
+inline isl::schedule_node manage(__isl_take isl_schedule_node *ptr);
+inline isl::schedule_node give(__isl_take isl_schedule_node *ptr);
+
+
+class schedule_node {
+  friend inline isl::schedule_node manage(__isl_take isl_schedule_node *ptr);
+
+  isl_schedule_node *ptr = nullptr;
+
+  inline explicit schedule_node(__isl_take isl_schedule_node *ptr);
+
+public:
+  inline /* implicit */ schedule_node();
+  inline /* implicit */ schedule_node(const isl::schedule_node &obj);
+  inline /* implicit */ schedule_node(std::nullptr_t);
+  inline isl::schedule_node &operator=(isl::schedule_node obj);
+  inline ~schedule_node();
+  inline __isl_give isl_schedule_node *copy() const &;
+  inline __isl_give isl_schedule_node *copy() && = delete;
+  inline __isl_keep isl_schedule_node *get() const;
+  inline __isl_give isl_schedule_node *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_schedule_node *keep() const;
+  inline __isl_give isl_schedule_node *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::schedule_node align_params(isl::space space) const;
+  inline isl::schedule_node ancestor(int generation) const;
+  inline isl::boolean band_member_get_coincident(int pos) const;
+  inline isl::schedule_node band_member_set_coincident(int pos, int coincident) const;
+  inline isl::schedule_node band_set_ast_build_options(isl::union_set options) const;
+  inline isl::schedule_node child(int pos) const;
+  inline isl::set context_get_context() const;
+  inline isl::schedule_node cut() const;
+  inline isl::union_set domain_get_domain() const;
+  inline isl::union_pw_multi_aff expansion_get_contraction() const;
+  inline isl::union_map expansion_get_expansion() const;
+  inline isl::union_map extension_get_extension() const;
+  inline isl::union_set filter_get_filter() const;
+  inline isl::schedule_node first_child() const;
+  inline isl::stat foreach_ancestor_top_down(const std::function<isl::stat(isl::schedule_node)> &fn) const;
+  static inline isl::schedule_node from_domain(isl::union_set domain);
+  static inline isl::schedule_node from_extension(isl::union_map extension);
+  inline int get_ancestor_child_position(const isl::schedule_node &ancestor) const;
+  inline isl::schedule_node get_child(int pos) const;
+  inline int get_child_position() const;
+  inline isl::union_set get_domain() const;
+  inline isl::multi_union_pw_aff get_prefix_schedule_multi_union_pw_aff() const;
+  inline isl::union_map get_prefix_schedule_relation() const;
+  inline isl::union_map get_prefix_schedule_union_map() const;
+  inline isl::union_pw_multi_aff get_prefix_schedule_union_pw_multi_aff() const;
+  inline isl::schedule get_schedule() const;
+  inline int get_schedule_depth() const;
+  inline isl::schedule_node get_shared_ancestor(const isl::schedule_node &node2) const;
+  inline isl::union_pw_multi_aff get_subtree_contraction() const;
+  inline isl::union_map get_subtree_expansion() const;
+  inline isl::union_map get_subtree_schedule_union_map() const;
+  inline int get_tree_depth() const;
+  inline isl::union_set get_universe_domain() const;
+  inline isl::schedule_node graft_after(isl::schedule_node graft) const;
+  inline isl::schedule_node graft_before(isl::schedule_node graft) const;
+  inline isl::schedule_node group(isl::id group_id) const;
+  inline isl::set guard_get_guard() const;
+  inline isl::boolean has_children() const;
+  inline isl::boolean has_next_sibling() const;
+  inline isl::boolean has_parent() const;
+  inline isl::boolean has_previous_sibling() const;
+  inline isl::schedule_node insert_context(isl::set context) const;
+  inline isl::schedule_node insert_filter(isl::union_set filter) const;
+  inline isl::schedule_node insert_guard(isl::set context) const;
+  inline isl::schedule_node insert_mark(isl::id mark) const;
+  inline isl::schedule_node insert_partial_schedule(isl::multi_union_pw_aff schedule) const;
+  inline isl::schedule_node insert_sequence(isl::union_set_list filters) const;
+  inline isl::schedule_node insert_set(isl::union_set_list filters) const;
+  inline isl::boolean is_equal(const isl::schedule_node &node2) const;
+  inline isl::boolean is_subtree_anchored() const;
+  inline isl::id mark_get_id() const;
+  inline isl::schedule_node next_sibling() const;
+  inline isl::schedule_node order_after(isl::union_set filter) const;
+  inline isl::schedule_node order_before(isl::union_set filter) const;
+  inline isl::schedule_node parent() const;
+  inline isl::schedule_node previous_sibling() const;
+  inline isl::schedule_node reset_user() const;
+  inline isl::schedule_node root() const;
+  inline isl::schedule_node sequence_splice_child(int pos) const;
+};
+
+// declarations for isl::set
+inline isl::set manage(__isl_take isl_set *ptr);
+inline isl::set give(__isl_take isl_set *ptr);
+
+
+class set {
+  friend inline isl::set manage(__isl_take isl_set *ptr);
+
+  isl_set *ptr = nullptr;
+
+  inline explicit set(__isl_take isl_set *ptr);
+
+public:
+  inline /* implicit */ set();
+  inline /* implicit */ set(const isl::set &obj);
+  inline /* implicit */ set(std::nullptr_t);
+  inline explicit set(isl::union_set uset);
+  inline explicit set(isl::ctx ctx, const std::string &str);
+  inline /* implicit */ set(isl::basic_set bset);
+  inline /* implicit */ set(isl::point pnt);
+  inline isl::set &operator=(isl::set obj);
+  inline ~set();
+  inline __isl_give isl_set *copy() const &;
+  inline __isl_give isl_set *copy() && = delete;
+  inline __isl_keep isl_set *get() const;
+  inline __isl_give isl_set *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_set *keep() const;
+  inline __isl_give isl_set *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::set add_constraint(isl::constraint constraint) const;
+  inline isl::set add_dims(isl::dim type, unsigned int n) const;
+  inline isl::basic_set affine_hull() const;
+  inline isl::set align_params(isl::space model) const;
+  inline isl::set apply(isl::map map) const;
+  inline isl::basic_set bounded_simple_hull() const;
+  static inline isl::set box_from_points(isl::point pnt1, isl::point pnt2);
+  inline isl::set coalesce() const;
+  inline isl::basic_set coefficients() const;
+  inline isl::set complement() const;
+  inline isl::basic_set convex_hull() const;
+  inline isl::val count_val() const;
+  inline isl::set detect_equalities() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::boolean dim_has_any_lower_bound(isl::dim type, unsigned int pos) const;
+  inline isl::boolean dim_has_any_upper_bound(isl::dim type, unsigned int pos) const;
+  inline isl::boolean dim_has_lower_bound(isl::dim type, unsigned int pos) const;
+  inline isl::boolean dim_has_upper_bound(isl::dim type, unsigned int pos) const;
+  inline isl::boolean dim_is_bounded(isl::dim type, unsigned int pos) const;
+  inline isl::pw_aff dim_max(int pos) const;
+  inline isl::pw_aff dim_min(int pos) const;
+  inline isl::set drop_constraints_involving_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::set drop_constraints_not_involving_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::set eliminate(isl::dim type, unsigned int first, unsigned int n) const;
+  static inline isl::set empty(isl::space dim);
+  inline isl::set equate(isl::dim type1, int pos1, isl::dim type2, int pos2) const;
+  inline int find_dim_by_id(isl::dim type, const isl::id &id) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::set fix_si(isl::dim type, unsigned int pos, int value) const;
+  inline isl::set fix_val(isl::dim type, unsigned int pos, isl::val v) const;
+  inline isl::set flat_product(isl::set set2) const;
+  inline isl::set flatten() const;
+  inline isl::map flatten_map() const;
+  inline int follows_at(const isl::set &set2, int pos) const;
+  inline isl::stat foreach_basic_set(const std::function<isl::stat(isl::basic_set)> &fn) const;
+  inline isl::stat foreach_point(const std::function<isl::stat(isl::point)> &fn) const;
+  static inline isl::set from_multi_pw_aff(isl::multi_pw_aff mpa);
+  inline isl::set from_params() const;
+  static inline isl::set from_pw_aff(isl::pw_aff pwaff);
+  static inline isl::set from_pw_multi_aff(isl::pw_multi_aff pma);
+  inline isl::basic_set_list get_basic_set_list() const;
+  inline isl::id get_dim_id(isl::dim type, unsigned int pos) const;
+  inline std::string get_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::space get_space() const;
+  inline isl::id get_tuple_id() const;
+  inline std::string get_tuple_name() const;
+  inline isl::set gist(isl::set context) const;
+  inline isl::set gist_basic_set(isl::basic_set context) const;
+  inline isl::set gist_params(isl::set context) const;
+  inline isl::boolean has_dim_id(isl::dim type, unsigned int pos) const;
+  inline isl::boolean has_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::boolean has_equal_space(const isl::set &set2) const;
+  inline isl::boolean has_tuple_id() const;
+  inline isl::boolean has_tuple_name() const;
+  inline isl::map identity() const;
+  inline isl::pw_aff indicator_function() const;
+  inline isl::set insert_dims(isl::dim type, unsigned int pos, unsigned int n) const;
+  inline isl::set intersect(isl::set set2) const;
+  inline isl::set intersect_params(isl::set params) const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean is_bounded() const;
+  inline isl::boolean is_box() const;
+  inline isl::boolean is_disjoint(const isl::set &set2) const;
+  inline isl::boolean is_empty() const;
+  inline isl::boolean is_equal(const isl::set &set2) const;
+  inline isl::boolean is_params() const;
+  inline isl::boolean is_singleton() const;
+  inline isl::boolean is_strict_subset(const isl::set &set2) const;
+  inline isl::boolean is_subset(const isl::set &set2) const;
+  inline isl::boolean is_wrapping() const;
+  inline isl::map lex_ge_set(isl::set set2) const;
+  inline isl::map lex_gt_set(isl::set set2) const;
+  inline isl::map lex_le_set(isl::set set2) const;
+  inline isl::map lex_lt_set(isl::set set2) const;
+  inline isl::set lexmax() const;
+  inline isl::pw_multi_aff lexmax_pw_multi_aff() const;
+  inline isl::set lexmin() const;
+  inline isl::pw_multi_aff lexmin_pw_multi_aff() const;
+  inline isl::set lower_bound_si(isl::dim type, unsigned int pos, int value) const;
+  inline isl::set lower_bound_val(isl::dim type, unsigned int pos, isl::val value) const;
+  inline isl::val max_val(const isl::aff &obj) const;
+  inline isl::val min_val(const isl::aff &obj) const;
+  inline isl::set move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const;
+  static inline isl::set nat_universe(isl::space dim);
+  inline isl::set neg() const;
+  inline isl::set params() const;
+  inline int plain_cmp(const isl::set &set2) const;
+  inline isl::val plain_get_val_if_fixed(isl::dim type, unsigned int pos) const;
+  inline isl::boolean plain_is_disjoint(const isl::set &set2) const;
+  inline isl::boolean plain_is_empty() const;
+  inline isl::boolean plain_is_equal(const isl::set &set2) const;
+  inline isl::boolean plain_is_universe() const;
+  inline isl::basic_set plain_unshifted_simple_hull() const;
+  inline isl::basic_set polyhedral_hull() const;
+  inline isl::set preimage_multi_aff(isl::multi_aff ma) const;
+  inline isl::set preimage_multi_pw_aff(isl::multi_pw_aff mpa) const;
+  inline isl::set preimage_pw_multi_aff(isl::pw_multi_aff pma) const;
+  inline isl::set product(isl::set set2) const;
+  inline isl::map project_onto_map(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::set project_out(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::set remove_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::set remove_divs() const;
+  inline isl::set remove_divs_involving_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::set remove_redundancies() const;
+  inline isl::set remove_unknown_divs() const;
+  inline isl::set reset_space(isl::space dim) const;
+  inline isl::set reset_tuple_id() const;
+  inline isl::set reset_user() const;
+  inline isl::basic_set sample() const;
+  inline isl::point sample_point() const;
+  inline isl::set set_dim_id(isl::dim type, unsigned int pos, isl::id id) const;
+  inline isl::set set_tuple_id(isl::id id) const;
+  inline isl::set set_tuple_name(const std::string &s) const;
+  inline isl::basic_set simple_hull() const;
+  inline int size() const;
+  inline isl::basic_set solutions() const;
+  inline isl::set split_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::set subtract(isl::set set2) const;
+  inline isl::set sum(isl::set set2) const;
+  inline isl::set unite(isl::set set2) const;
+  static inline isl::set universe(isl::space dim);
+  inline isl::basic_set unshifted_simple_hull() const;
+  inline isl::basic_set unshifted_simple_hull_from_set_list(isl::set_list list) const;
+  inline isl::map unwrap() const;
+  inline isl::set upper_bound_si(isl::dim type, unsigned int pos, int value) const;
+  inline isl::set upper_bound_val(isl::dim type, unsigned int pos, isl::val value) const;
+  inline isl::map wrapped_domain_map() const;
+};
+
+// declarations for isl::set_list
+inline isl::set_list manage(__isl_take isl_set_list *ptr);
+inline isl::set_list give(__isl_take isl_set_list *ptr);
+
+
+class set_list {
+  friend inline isl::set_list manage(__isl_take isl_set_list *ptr);
+
+  isl_set_list *ptr = nullptr;
+
+  inline explicit set_list(__isl_take isl_set_list *ptr);
+
+public:
+  inline /* implicit */ set_list();
+  inline /* implicit */ set_list(const isl::set_list &obj);
+  inline /* implicit */ set_list(std::nullptr_t);
+  inline isl::set_list &operator=(isl::set_list obj);
+  inline ~set_list();
+  inline __isl_give isl_set_list *copy() const &;
+  inline __isl_give isl_set_list *copy() && = delete;
+  inline __isl_keep isl_set_list *get() const;
+  inline __isl_give isl_set_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_set_list *keep() const;
+  inline __isl_give isl_set_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::space
+inline isl::space manage(__isl_take isl_space *ptr);
+inline isl::space give(__isl_take isl_space *ptr);
+
+
+class space {
+  friend inline isl::space manage(__isl_take isl_space *ptr);
+
+  isl_space *ptr = nullptr;
+
+  inline explicit space(__isl_take isl_space *ptr);
+
+public:
+  inline /* implicit */ space();
+  inline /* implicit */ space(const isl::space &obj);
+  inline /* implicit */ space(std::nullptr_t);
+  inline explicit space(isl::ctx ctx, unsigned int nparam, unsigned int n_in, unsigned int n_out);
+  inline explicit space(isl::ctx ctx, unsigned int nparam, unsigned int dim);
+  inline isl::space &operator=(isl::space obj);
+  inline ~space();
+  inline __isl_give isl_space *copy() const &;
+  inline __isl_give isl_space *copy() && = delete;
+  inline __isl_keep isl_space *get() const;
+  inline __isl_give isl_space *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_space *keep() const;
+  inline __isl_give isl_space *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::space add_dims(isl::dim type, unsigned int n) const;
+  inline isl::space align_params(isl::space dim2) const;
+  inline isl::boolean can_curry() const;
+  inline isl::boolean can_range_curry() const;
+  inline isl::boolean can_uncurry() const;
+  inline isl::boolean can_zip() const;
+  inline isl::space curry() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::space domain() const;
+  inline isl::space domain_factor_domain() const;
+  inline isl::space domain_factor_range() const;
+  inline isl::boolean domain_is_wrapping() const;
+  inline isl::space domain_map() const;
+  inline isl::space domain_product(isl::space right) const;
+  inline isl::space drop_dims(isl::dim type, unsigned int first, unsigned int num) const;
+  inline isl::space factor_domain() const;
+  inline isl::space factor_range() const;
+  inline int find_dim_by_id(isl::dim type, const isl::id &id) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::space from_domain() const;
+  inline isl::space from_range() const;
+  inline isl::id get_dim_id(isl::dim type, unsigned int pos) const;
+  inline std::string get_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::id get_tuple_id(isl::dim type) const;
+  inline std::string get_tuple_name(isl::dim type) const;
+  inline isl::boolean has_dim_id(isl::dim type, unsigned int pos) const;
+  inline isl::boolean has_dim_name(isl::dim type, unsigned int pos) const;
+  inline isl::boolean has_equal_params(const isl::space &space2) const;
+  inline isl::boolean has_equal_tuples(const isl::space &space2) const;
+  inline isl::boolean has_tuple_id(isl::dim type) const;
+  inline isl::boolean has_tuple_name(isl::dim type) const;
+  inline isl::space insert_dims(isl::dim type, unsigned int pos, unsigned int n) const;
+  inline isl::boolean is_domain(const isl::space &space2) const;
+  inline isl::boolean is_equal(const isl::space &space2) const;
+  inline isl::boolean is_map() const;
+  inline isl::boolean is_params() const;
+  inline isl::boolean is_product() const;
+  inline isl::boolean is_range(const isl::space &space2) const;
+  inline isl::boolean is_set() const;
+  inline isl::boolean is_wrapping() const;
+  inline isl::space join(isl::space right) const;
+  inline isl::space map_from_domain_and_range(isl::space range) const;
+  inline isl::space map_from_set() const;
+  inline isl::space move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const;
+  inline isl::space params() const;
+  static inline isl::space params_alloc(isl::ctx ctx, unsigned int nparam);
+  inline isl::space product(isl::space right) const;
+  inline isl::space range() const;
+  inline isl::space range_curry() const;
+  inline isl::space range_factor_domain() const;
+  inline isl::space range_factor_range() const;
+  inline isl::boolean range_is_wrapping() const;
+  inline isl::space range_map() const;
+  inline isl::space range_product(isl::space right) const;
+  inline isl::space reset_tuple_id(isl::dim type) const;
+  inline isl::space reset_user() const;
+  inline isl::space reverse() const;
+  inline isl::space set_dim_id(isl::dim type, unsigned int pos, isl::id id) const;
+  inline isl::space set_from_params() const;
+  inline isl::space set_tuple_id(isl::dim type, isl::id id) const;
+  inline isl::space set_tuple_name(isl::dim type, const std::string &s) const;
+  inline isl::boolean tuple_is_equal(isl::dim type1, const isl::space &space2, isl::dim type2) const;
+  inline isl::space uncurry() const;
+  inline isl::space unwrap() const;
+  inline isl::space wrap() const;
+  inline isl::space zip() const;
+};
+
+// declarations for isl::term
+inline isl::term manage(__isl_take isl_term *ptr);
+inline isl::term give(__isl_take isl_term *ptr);
+
+
+class term {
+  friend inline isl::term manage(__isl_take isl_term *ptr);
+
+  isl_term *ptr = nullptr;
+
+  inline explicit term(__isl_take isl_term *ptr);
+
+public:
+  inline /* implicit */ term();
+  inline /* implicit */ term(const isl::term &obj);
+  inline /* implicit */ term(std::nullptr_t);
+  inline isl::term &operator=(isl::term obj);
+  inline ~term();
+  inline __isl_give isl_term *copy() const &;
+  inline __isl_give isl_term *copy() && = delete;
+  inline __isl_keep isl_term *get() const;
+  inline __isl_give isl_term *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_term *keep() const;
+  inline __isl_give isl_term *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::val get_coefficient_val() const;
+  inline isl::aff get_div(unsigned int pos) const;
+  inline int get_exp(isl::dim type, unsigned int pos) const;
+};
+
+// declarations for isl::union_access_info
+inline isl::union_access_info manage(__isl_take isl_union_access_info *ptr);
+inline isl::union_access_info give(__isl_take isl_union_access_info *ptr);
+
+
+class union_access_info {
+  friend inline isl::union_access_info manage(__isl_take isl_union_access_info *ptr);
+
+  isl_union_access_info *ptr = nullptr;
+
+  inline explicit union_access_info(__isl_take isl_union_access_info *ptr);
+
+public:
+  inline /* implicit */ union_access_info();
+  inline /* implicit */ union_access_info(const isl::union_access_info &obj);
+  inline /* implicit */ union_access_info(std::nullptr_t);
+  inline explicit union_access_info(isl::union_map sink);
+  inline isl::union_access_info &operator=(isl::union_access_info obj);
+  inline ~union_access_info();
+  inline __isl_give isl_union_access_info *copy() const &;
+  inline __isl_give isl_union_access_info *copy() && = delete;
+  inline __isl_keep isl_union_access_info *get() const;
+  inline __isl_give isl_union_access_info *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_union_access_info *keep() const;
+  inline __isl_give isl_union_access_info *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+
+  inline isl::union_flow compute_flow() const;
+  inline isl::union_access_info set_kill(isl::union_map kill) const;
+  inline isl::union_access_info set_may_source(isl::union_map may_source) const;
+  inline isl::union_access_info set_must_source(isl::union_map must_source) const;
+  inline isl::union_access_info set_schedule(isl::schedule schedule) const;
+  inline isl::union_access_info set_schedule_map(isl::union_map schedule_map) const;
+};
+
+// declarations for isl::union_flow
+inline isl::union_flow manage(__isl_take isl_union_flow *ptr);
+inline isl::union_flow give(__isl_take isl_union_flow *ptr);
+
+
+class union_flow {
+  friend inline isl::union_flow manage(__isl_take isl_union_flow *ptr);
+
+  isl_union_flow *ptr = nullptr;
+
+  inline explicit union_flow(__isl_take isl_union_flow *ptr);
+
+public:
+  inline /* implicit */ union_flow();
+  inline /* implicit */ union_flow(const isl::union_flow &obj);
+  inline /* implicit */ union_flow(std::nullptr_t);
+  inline isl::union_flow &operator=(isl::union_flow obj);
+  inline ~union_flow();
+  inline __isl_give isl_union_flow *copy() const &;
+  inline __isl_give isl_union_flow *copy() && = delete;
+  inline __isl_keep isl_union_flow *get() const;
+  inline __isl_give isl_union_flow *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_union_flow *keep() const;
+  inline __isl_give isl_union_flow *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+
+  inline isl::union_map get_full_may_dependence() const;
+  inline isl::union_map get_full_must_dependence() const;
+  inline isl::union_map get_may_dependence() const;
+  inline isl::union_map get_may_no_source() const;
+  inline isl::union_map get_must_dependence() const;
+  inline isl::union_map get_must_no_source() const;
+};
+
+// declarations for isl::union_map
+inline isl::union_map manage(__isl_take isl_union_map *ptr);
+inline isl::union_map give(__isl_take isl_union_map *ptr);
+
+
+class union_map {
+  friend inline isl::union_map manage(__isl_take isl_union_map *ptr);
+
+  isl_union_map *ptr = nullptr;
+
+  inline explicit union_map(__isl_take isl_union_map *ptr);
+
+public:
+  inline /* implicit */ union_map();
+  inline /* implicit */ union_map(const isl::union_map &obj);
+  inline /* implicit */ union_map(std::nullptr_t);
+  inline explicit union_map(isl::union_pw_aff upa);
+  inline /* implicit */ union_map(isl::basic_map bmap);
+  inline /* implicit */ union_map(isl::map map);
+  inline explicit union_map(isl::ctx ctx, const std::string &str);
+  inline isl::union_map &operator=(isl::union_map obj);
+  inline ~union_map();
+  inline __isl_give isl_union_map *copy() const &;
+  inline __isl_give isl_union_map *copy() && = delete;
+  inline __isl_keep isl_union_map *get() const;
+  inline __isl_give isl_union_map *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_union_map *keep() const;
+  inline __isl_give isl_union_map *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::union_map add_map(isl::map map) const;
+  inline isl::union_map affine_hull() const;
+  inline isl::union_map align_params(isl::space model) const;
+  inline isl::union_map apply_domain(isl::union_map umap2) const;
+  inline isl::union_map apply_range(isl::union_map umap2) const;
+  inline isl::union_map coalesce() const;
+  inline isl::boolean contains(const isl::space &space) const;
+  inline isl::union_map curry() const;
+  inline isl::union_set deltas() const;
+  inline isl::union_map deltas_map() const;
+  inline isl::union_map detect_equalities() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::union_set domain() const;
+  inline isl::union_map domain_factor_domain() const;
+  inline isl::union_map domain_factor_range() const;
+  inline isl::union_map domain_map() const;
+  inline isl::union_pw_multi_aff domain_map_union_pw_multi_aff() const;
+  inline isl::union_map domain_product(isl::union_map umap2) const;
+  static inline isl::union_map empty(isl::space dim);
+  inline isl::union_map eq_at_multi_union_pw_aff(isl::multi_union_pw_aff mupa) const;
+  inline isl::map extract_map(isl::space dim) const;
+  inline isl::union_map factor_domain() const;
+  inline isl::union_map factor_range() const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::union_map fixed_power(isl::val exp) const;
+  inline isl::union_map flat_domain_product(isl::union_map umap2) const;
+  inline isl::union_map flat_range_product(isl::union_map umap2) const;
+  inline isl::stat foreach_map(const std::function<isl::stat(isl::map)> &fn) const;
+  static inline isl::union_map from(isl::union_pw_multi_aff upma);
+  static inline isl::union_map from(isl::multi_union_pw_aff mupa);
+  static inline isl::union_map from_domain(isl::union_set uset);
+  static inline isl::union_map from_domain_and_range(isl::union_set domain, isl::union_set range);
+  static inline isl::union_map from_range(isl::union_set uset);
+  inline isl::id get_dim_id(isl::dim type, unsigned int pos) const;
+  inline uint32_t get_hash() const;
+  inline isl::space get_space() const;
+  inline isl::union_map gist(isl::union_map context) const;
+  inline isl::union_map gist_domain(isl::union_set uset) const;
+  inline isl::union_map gist_params(isl::set set) const;
+  inline isl::union_map gist_range(isl::union_set uset) const;
+  inline isl::union_map intersect(isl::union_map umap2) const;
+  inline isl::union_map intersect_domain(isl::union_set uset) const;
+  inline isl::union_map intersect_params(isl::set set) const;
+  inline isl::union_map intersect_range(isl::union_set uset) const;
+  inline isl::union_map intersect_range_factor_range(isl::union_map factor) const;
+  inline isl::boolean involves_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::boolean is_bijective() const;
+  inline isl::boolean is_disjoint(const isl::union_map &umap2) const;
+  inline isl::boolean is_empty() const;
+  inline isl::boolean is_equal(const isl::union_map &umap2) const;
+  inline isl::boolean is_identity() const;
+  inline isl::boolean is_injective() const;
+  inline isl::boolean is_single_valued() const;
+  inline isl::boolean is_strict_subset(const isl::union_map &umap2) const;
+  inline isl::boolean is_subset(const isl::union_map &umap2) const;
+  inline isl::union_map lex_ge_union_map(isl::union_map umap2) const;
+  inline isl::union_map lex_gt_at_multi_union_pw_aff(isl::multi_union_pw_aff mupa) const;
+  inline isl::union_map lex_gt_union_map(isl::union_map umap2) const;
+  inline isl::union_map lex_le_union_map(isl::union_map umap2) const;
+  inline isl::union_map lex_lt_at_multi_union_pw_aff(isl::multi_union_pw_aff mupa) const;
+  inline isl::union_map lex_lt_union_map(isl::union_map umap2) const;
+  inline isl::union_map lexmax() const;
+  inline isl::union_map lexmin() const;
+  inline isl::set params() const;
+  inline isl::boolean plain_is_injective() const;
+  inline isl::union_map polyhedral_hull() const;
+  inline isl::union_map preimage_domain_multi_aff(isl::multi_aff ma) const;
+  inline isl::union_map preimage_domain_multi_pw_aff(isl::multi_pw_aff mpa) const;
+  inline isl::union_map preimage_domain_pw_multi_aff(isl::pw_multi_aff pma) const;
+  inline isl::union_map preimage_domain_union_pw_multi_aff(isl::union_pw_multi_aff upma) const;
+  inline isl::union_map preimage_range_multi_aff(isl::multi_aff ma) const;
+  inline isl::union_map preimage_range_pw_multi_aff(isl::pw_multi_aff pma) const;
+  inline isl::union_map preimage_range_union_pw_multi_aff(isl::union_pw_multi_aff upma) const;
+  inline isl::union_map product(isl::union_map umap2) const;
+  inline isl::union_map project_out(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::union_set range() const;
+  inline isl::union_map range_curry() const;
+  inline isl::union_map range_factor_domain() const;
+  inline isl::union_map range_factor_range() const;
+  inline isl::union_map range_map() const;
+  inline isl::union_map range_product(isl::union_map umap2) const;
+  inline isl::union_map remove_divs() const;
+  inline isl::union_map remove_redundancies() const;
+  inline isl::union_map reset_user() const;
+  inline isl::union_map reverse() const;
+  inline isl::basic_map sample() const;
+  inline isl::union_map simple_hull() const;
+  inline isl::union_map subtract(isl::union_map umap2) const;
+  inline isl::union_map subtract_domain(isl::union_set dom) const;
+  inline isl::union_map subtract_range(isl::union_set dom) const;
+  inline isl::union_map uncurry() const;
+  inline isl::union_map unite(isl::union_map umap2) const;
+  inline isl::union_map universe() const;
+  inline isl::union_set wrap() const;
+  inline isl::union_map zip() const;
+};
+
+// declarations for isl::union_map_list
+inline isl::union_map_list manage(__isl_take isl_union_map_list *ptr);
+inline isl::union_map_list give(__isl_take isl_union_map_list *ptr);
+
+
+class union_map_list {
+  friend inline isl::union_map_list manage(__isl_take isl_union_map_list *ptr);
+
+  isl_union_map_list *ptr = nullptr;
+
+  inline explicit union_map_list(__isl_take isl_union_map_list *ptr);
+
+public:
+  inline /* implicit */ union_map_list();
+  inline /* implicit */ union_map_list(const isl::union_map_list &obj);
+  inline /* implicit */ union_map_list(std::nullptr_t);
+  inline isl::union_map_list &operator=(isl::union_map_list obj);
+  inline ~union_map_list();
+  inline __isl_give isl_union_map_list *copy() const &;
+  inline __isl_give isl_union_map_list *copy() && = delete;
+  inline __isl_keep isl_union_map_list *get() const;
+  inline __isl_give isl_union_map_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_union_map_list *keep() const;
+  inline __isl_give isl_union_map_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::union_pw_aff
+inline isl::union_pw_aff manage(__isl_take isl_union_pw_aff *ptr);
+inline isl::union_pw_aff give(__isl_take isl_union_pw_aff *ptr);
+
+
+class union_pw_aff {
+  friend inline isl::union_pw_aff manage(__isl_take isl_union_pw_aff *ptr);
+
+  isl_union_pw_aff *ptr = nullptr;
+
+  inline explicit union_pw_aff(__isl_take isl_union_pw_aff *ptr);
+
+public:
+  inline /* implicit */ union_pw_aff();
+  inline /* implicit */ union_pw_aff(const isl::union_pw_aff &obj);
+  inline /* implicit */ union_pw_aff(std::nullptr_t);
+  inline /* implicit */ union_pw_aff(isl::pw_aff pa);
+  inline explicit union_pw_aff(isl::union_set domain, isl::val v);
+  inline explicit union_pw_aff(isl::ctx ctx, const std::string &str);
+  inline isl::union_pw_aff &operator=(isl::union_pw_aff obj);
+  inline ~union_pw_aff();
+  inline __isl_give isl_union_pw_aff *copy() const &;
+  inline __isl_give isl_union_pw_aff *copy() && = delete;
+  inline __isl_keep isl_union_pw_aff *get() const;
+  inline __isl_give isl_union_pw_aff *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_union_pw_aff *keep() const;
+  inline __isl_give isl_union_pw_aff *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::union_pw_aff add(isl::union_pw_aff upa2) const;
+  inline isl::union_pw_aff add_pw_aff(isl::pw_aff pa) const;
+  static inline isl::union_pw_aff aff_on_domain(isl::union_set domain, isl::aff aff);
+  inline isl::union_pw_aff align_params(isl::space model) const;
+  inline isl::union_pw_aff coalesce() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::union_set domain() const;
+  inline isl::union_pw_aff drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  static inline isl::union_pw_aff empty(isl::space space);
+  inline isl::pw_aff extract_pw_aff(isl::space space) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::union_pw_aff floor() const;
+  inline isl::stat foreach_pw_aff(const std::function<isl::stat(isl::pw_aff)> &fn) const;
+  inline isl::space get_space() const;
+  inline isl::union_pw_aff gist(isl::union_set context) const;
+  inline isl::union_pw_aff gist_params(isl::set context) const;
+  inline isl::union_pw_aff intersect_domain(isl::union_set uset) const;
+  inline isl::union_pw_aff intersect_params(isl::set set) const;
+  inline isl::boolean involves_nan() const;
+  inline isl::union_pw_aff mod_val(isl::val f) const;
+  inline isl::union_pw_aff neg() const;
+  inline isl::boolean plain_is_equal(const isl::union_pw_aff &upa2) const;
+  inline isl::union_pw_aff pullback(isl::union_pw_multi_aff upma) const;
+  inline isl::union_pw_aff reset_user() const;
+  inline isl::union_pw_aff scale_down_val(isl::val v) const;
+  inline isl::union_pw_aff scale_val(isl::val v) const;
+  inline isl::union_pw_aff sub(isl::union_pw_aff upa2) const;
+  inline isl::union_pw_aff subtract_domain(isl::union_set uset) const;
+  inline isl::union_pw_aff union_add(isl::union_pw_aff upa2) const;
+  inline isl::union_set zero_union_set() const;
+};
+
+// declarations for isl::union_pw_aff_list
+inline isl::union_pw_aff_list manage(__isl_take isl_union_pw_aff_list *ptr);
+inline isl::union_pw_aff_list give(__isl_take isl_union_pw_aff_list *ptr);
+
+
+class union_pw_aff_list {
+  friend inline isl::union_pw_aff_list manage(__isl_take isl_union_pw_aff_list *ptr);
+
+  isl_union_pw_aff_list *ptr = nullptr;
+
+  inline explicit union_pw_aff_list(__isl_take isl_union_pw_aff_list *ptr);
+
+public:
+  inline /* implicit */ union_pw_aff_list();
+  inline /* implicit */ union_pw_aff_list(const isl::union_pw_aff_list &obj);
+  inline /* implicit */ union_pw_aff_list(std::nullptr_t);
+  inline isl::union_pw_aff_list &operator=(isl::union_pw_aff_list obj);
+  inline ~union_pw_aff_list();
+  inline __isl_give isl_union_pw_aff_list *copy() const &;
+  inline __isl_give isl_union_pw_aff_list *copy() && = delete;
+  inline __isl_keep isl_union_pw_aff_list *get() const;
+  inline __isl_give isl_union_pw_aff_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_union_pw_aff_list *keep() const;
+  inline __isl_give isl_union_pw_aff_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::union_pw_multi_aff
+inline isl::union_pw_multi_aff manage(__isl_take isl_union_pw_multi_aff *ptr);
+inline isl::union_pw_multi_aff give(__isl_take isl_union_pw_multi_aff *ptr);
+
+
+class union_pw_multi_aff {
+  friend inline isl::union_pw_multi_aff manage(__isl_take isl_union_pw_multi_aff *ptr);
+
+  isl_union_pw_multi_aff *ptr = nullptr;
+
+  inline explicit union_pw_multi_aff(__isl_take isl_union_pw_multi_aff *ptr);
+
+public:
+  inline /* implicit */ union_pw_multi_aff();
+  inline /* implicit */ union_pw_multi_aff(const isl::union_pw_multi_aff &obj);
+  inline /* implicit */ union_pw_multi_aff(std::nullptr_t);
+  inline /* implicit */ union_pw_multi_aff(isl::pw_multi_aff pma);
+  inline explicit union_pw_multi_aff(isl::union_set uset);
+  inline explicit union_pw_multi_aff(isl::union_map umap);
+  inline explicit union_pw_multi_aff(isl::ctx ctx, const std::string &str);
+  inline /* implicit */ union_pw_multi_aff(isl::union_pw_aff upa);
+  inline isl::union_pw_multi_aff &operator=(isl::union_pw_multi_aff obj);
+  inline ~union_pw_multi_aff();
+  inline __isl_give isl_union_pw_multi_aff *copy() const &;
+  inline __isl_give isl_union_pw_multi_aff *copy() && = delete;
+  inline __isl_keep isl_union_pw_multi_aff *get() const;
+  inline __isl_give isl_union_pw_multi_aff *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_union_pw_multi_aff *keep() const;
+  inline __isl_give isl_union_pw_multi_aff *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::union_pw_multi_aff add(isl::union_pw_multi_aff upma2) const;
+  inline isl::union_pw_multi_aff add_pw_multi_aff(isl::pw_multi_aff pma) const;
+  inline isl::union_pw_multi_aff align_params(isl::space model) const;
+  inline isl::union_pw_multi_aff coalesce() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::union_set domain() const;
+  inline isl::union_pw_multi_aff drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  static inline isl::union_pw_multi_aff empty(isl::space space);
+  inline isl::pw_multi_aff extract_pw_multi_aff(isl::space space) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::union_pw_multi_aff flat_range_product(isl::union_pw_multi_aff upma2) const;
+  inline isl::stat foreach_pw_multi_aff(const std::function<isl::stat(isl::pw_multi_aff)> &fn) const;
+  static inline isl::union_pw_multi_aff from_aff(isl::aff aff);
+  static inline isl::union_pw_multi_aff from_multi_union_pw_aff(isl::multi_union_pw_aff mupa);
+  static inline isl::union_pw_multi_aff from_union_set(isl::union_set uset);
+  inline isl::space get_space() const;
+  inline isl::union_pw_aff get_union_pw_aff(int pos) const;
+  inline isl::union_pw_multi_aff gist(isl::union_set context) const;
+  inline isl::union_pw_multi_aff gist_params(isl::set context) const;
+  inline isl::union_pw_multi_aff intersect_domain(isl::union_set uset) const;
+  inline isl::union_pw_multi_aff intersect_params(isl::set set) const;
+  inline isl::boolean involves_nan() const;
+  static inline isl::union_pw_multi_aff multi_val_on_domain(isl::union_set domain, isl::multi_val mv);
+  inline isl::union_pw_multi_aff neg() const;
+  inline isl::boolean plain_is_equal(const isl::union_pw_multi_aff &upma2) const;
+  inline isl::union_pw_multi_aff pullback(isl::union_pw_multi_aff upma2) const;
+  inline isl::union_pw_multi_aff reset_user() const;
+  inline isl::union_pw_multi_aff scale_down_val(isl::val val) const;
+  inline isl::union_pw_multi_aff scale_multi_val(isl::multi_val mv) const;
+  inline isl::union_pw_multi_aff scale_val(isl::val val) const;
+  inline isl::union_pw_multi_aff sub(isl::union_pw_multi_aff upma2) const;
+  inline isl::union_pw_multi_aff subtract_domain(isl::union_set uset) const;
+  inline isl::union_pw_multi_aff union_add(isl::union_pw_multi_aff upma2) const;
+};
+
+// declarations for isl::union_pw_multi_aff_list
+inline isl::union_pw_multi_aff_list manage(__isl_take isl_union_pw_multi_aff_list *ptr);
+inline isl::union_pw_multi_aff_list give(__isl_take isl_union_pw_multi_aff_list *ptr);
+
+
+class union_pw_multi_aff_list {
+  friend inline isl::union_pw_multi_aff_list manage(__isl_take isl_union_pw_multi_aff_list *ptr);
+
+  isl_union_pw_multi_aff_list *ptr = nullptr;
+
+  inline explicit union_pw_multi_aff_list(__isl_take isl_union_pw_multi_aff_list *ptr);
+
+public:
+  inline /* implicit */ union_pw_multi_aff_list();
+  inline /* implicit */ union_pw_multi_aff_list(const isl::union_pw_multi_aff_list &obj);
+  inline /* implicit */ union_pw_multi_aff_list(std::nullptr_t);
+  inline isl::union_pw_multi_aff_list &operator=(isl::union_pw_multi_aff_list obj);
+  inline ~union_pw_multi_aff_list();
+  inline __isl_give isl_union_pw_multi_aff_list *copy() const &;
+  inline __isl_give isl_union_pw_multi_aff_list *copy() && = delete;
+  inline __isl_keep isl_union_pw_multi_aff_list *get() const;
+  inline __isl_give isl_union_pw_multi_aff_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_union_pw_multi_aff_list *keep() const;
+  inline __isl_give isl_union_pw_multi_aff_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::union_pw_qpolynomial
+inline isl::union_pw_qpolynomial manage(__isl_take isl_union_pw_qpolynomial *ptr);
+inline isl::union_pw_qpolynomial give(__isl_take isl_union_pw_qpolynomial *ptr);
+
+
+class union_pw_qpolynomial {
+  friend inline isl::union_pw_qpolynomial manage(__isl_take isl_union_pw_qpolynomial *ptr);
+
+  isl_union_pw_qpolynomial *ptr = nullptr;
+
+  inline explicit union_pw_qpolynomial(__isl_take isl_union_pw_qpolynomial *ptr);
+
+public:
+  inline /* implicit */ union_pw_qpolynomial();
+  inline /* implicit */ union_pw_qpolynomial(const isl::union_pw_qpolynomial &obj);
+  inline /* implicit */ union_pw_qpolynomial(std::nullptr_t);
+  inline explicit union_pw_qpolynomial(isl::ctx ctx, const std::string &str);
+  inline isl::union_pw_qpolynomial &operator=(isl::union_pw_qpolynomial obj);
+  inline ~union_pw_qpolynomial();
+  inline __isl_give isl_union_pw_qpolynomial *copy() const &;
+  inline __isl_give isl_union_pw_qpolynomial *copy() && = delete;
+  inline __isl_keep isl_union_pw_qpolynomial *get() const;
+  inline __isl_give isl_union_pw_qpolynomial *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_union_pw_qpolynomial *keep() const;
+  inline __isl_give isl_union_pw_qpolynomial *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+
+  inline isl::union_pw_qpolynomial add(isl::union_pw_qpolynomial upwqp2) const;
+  inline isl::union_pw_qpolynomial add_pw_qpolynomial(isl::pw_qpolynomial pwqp) const;
+  inline isl::union_pw_qpolynomial align_params(isl::space model) const;
+  inline isl::union_pw_qpolynomial coalesce() const;
+  inline unsigned int dim(isl::dim type) const;
+  inline isl::union_set domain() const;
+  inline isl::union_pw_qpolynomial drop_dims(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::val eval(isl::point pnt) const;
+  inline isl::pw_qpolynomial extract_pw_qpolynomial(isl::space dim) const;
+  inline int find_dim_by_name(isl::dim type, const std::string &name) const;
+  inline isl::stat foreach_pw_qpolynomial(const std::function<isl::stat(isl::pw_qpolynomial)> &fn) const;
+  static inline isl::union_pw_qpolynomial from_pw_qpolynomial(isl::pw_qpolynomial pwqp);
+  inline isl::space get_space() const;
+  inline isl::union_pw_qpolynomial gist(isl::union_set context) const;
+  inline isl::union_pw_qpolynomial gist_params(isl::set context) const;
+  inline isl::union_pw_qpolynomial intersect_domain(isl::union_set uset) const;
+  inline isl::union_pw_qpolynomial intersect_params(isl::set set) const;
+  inline isl::boolean involves_nan() const;
+  inline isl::union_pw_qpolynomial mul(isl::union_pw_qpolynomial upwqp2) const;
+  inline isl::union_pw_qpolynomial neg() const;
+  inline isl::boolean plain_is_equal(const isl::union_pw_qpolynomial &upwqp2) const;
+  inline isl::union_pw_qpolynomial reset_user() const;
+  inline isl::union_pw_qpolynomial scale_down_val(isl::val v) const;
+  inline isl::union_pw_qpolynomial scale_val(isl::val v) const;
+  inline isl::union_pw_qpolynomial sub(isl::union_pw_qpolynomial upwqp2) const;
+  inline isl::union_pw_qpolynomial subtract_domain(isl::union_set uset) const;
+  inline isl::union_pw_qpolynomial to_polynomial(int sign) const;
+  static inline isl::union_pw_qpolynomial zero(isl::space dim);
+};
+
+// declarations for isl::union_set
+inline isl::union_set manage(__isl_take isl_union_set *ptr);
+inline isl::union_set give(__isl_take isl_union_set *ptr);
+
+
+class union_set {
+  friend inline isl::union_set manage(__isl_take isl_union_set *ptr);
+
+  isl_union_set *ptr = nullptr;
+
+  inline explicit union_set(__isl_take isl_union_set *ptr);
+
+public:
+  inline /* implicit */ union_set();
+  inline /* implicit */ union_set(const isl::union_set &obj);
+  inline /* implicit */ union_set(std::nullptr_t);
+  inline /* implicit */ union_set(isl::point pnt);
+  inline explicit union_set(isl::ctx ctx, const std::string &str);
+  inline /* implicit */ union_set(isl::basic_set bset);
+  inline /* implicit */ union_set(isl::set set);
+  inline isl::union_set &operator=(isl::union_set obj);
+  inline ~union_set();
+  inline __isl_give isl_union_set *copy() const &;
+  inline __isl_give isl_union_set *copy() && = delete;
+  inline __isl_keep isl_union_set *get() const;
+  inline __isl_give isl_union_set *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_union_set *keep() const;
+  inline __isl_give isl_union_set *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::union_set add_set(isl::set set) const;
+  inline isl::union_set affine_hull() const;
+  inline isl::union_set align_params(isl::space model) const;
+  inline isl::union_set apply(isl::union_map umap) const;
+  inline isl::union_set coalesce() const;
+  inline isl::union_set coefficients() const;
+  inline isl::schedule compute_schedule(isl::union_map validity, isl::union_map proximity) const;
+  inline isl::boolean contains(const isl::space &space) const;
+  inline isl::union_set detect_equalities() const;
+  inline unsigned int dim(isl::dim type) const;
+  static inline isl::union_set empty(isl::space dim);
+  inline isl::set extract_set(isl::space dim) const;
+  inline isl::stat foreach_point(const std::function<isl::stat(isl::point)> &fn) const;
+  inline isl::stat foreach_set(const std::function<isl::stat(isl::set)> &fn) const;
+  inline isl::basic_set_list get_basic_set_list() const;
+  inline uint32_t get_hash() const;
+  inline isl::space get_space() const;
+  inline isl::union_set gist(isl::union_set context) const;
+  inline isl::union_set gist_params(isl::set set) const;
+  inline isl::union_map identity() const;
+  inline isl::union_pw_multi_aff identity_union_pw_multi_aff() const;
+  inline isl::union_set intersect(isl::union_set uset2) const;
+  inline isl::union_set intersect_params(isl::set set) const;
+  inline isl::boolean is_disjoint(const isl::union_set &uset2) const;
+  inline isl::boolean is_empty() const;
+  inline isl::boolean is_equal(const isl::union_set &uset2) const;
+  inline isl::boolean is_params() const;
+  inline isl::boolean is_strict_subset(const isl::union_set &uset2) const;
+  inline isl::boolean is_subset(const isl::union_set &uset2) const;
+  inline isl::union_map lex_ge_union_set(isl::union_set uset2) const;
+  inline isl::union_map lex_gt_union_set(isl::union_set uset2) const;
+  inline isl::union_map lex_le_union_set(isl::union_set uset2) const;
+  inline isl::union_map lex_lt_union_set(isl::union_set uset2) const;
+  inline isl::union_set lexmax() const;
+  inline isl::union_set lexmin() const;
+  inline isl::multi_val min_multi_union_pw_aff(const isl::multi_union_pw_aff &obj) const;
+  inline isl::set params() const;
+  inline isl::union_set polyhedral_hull() const;
+  inline isl::union_set preimage_multi_aff(isl::multi_aff ma) const;
+  inline isl::union_set preimage_pw_multi_aff(isl::pw_multi_aff pma) const;
+  inline isl::union_set preimage_union_pw_multi_aff(isl::union_pw_multi_aff upma) const;
+  inline isl::union_set product(isl::union_set uset2) const;
+  inline isl::union_set project_out(isl::dim type, unsigned int first, unsigned int n) const;
+  inline isl::union_set remove_divs() const;
+  inline isl::union_set remove_redundancies() const;
+  inline isl::union_set reset_user() const;
+  inline isl::basic_set sample() const;
+  inline isl::point sample_point() const;
+  inline isl::union_set simple_hull() const;
+  inline isl::union_set solutions() const;
+  inline isl::union_set subtract(isl::union_set uset2) const;
+  inline isl::union_set unite(isl::union_set uset2) const;
+  inline isl::union_set universe() const;
+  inline isl::union_map unwrap() const;
+  inline isl::union_map wrapped_domain_map() const;
+};
+
+// declarations for isl::union_set_list
+inline isl::union_set_list manage(__isl_take isl_union_set_list *ptr);
+inline isl::union_set_list give(__isl_take isl_union_set_list *ptr);
+
+
+class union_set_list {
+  friend inline isl::union_set_list manage(__isl_take isl_union_set_list *ptr);
+
+  isl_union_set_list *ptr = nullptr;
+
+  inline explicit union_set_list(__isl_take isl_union_set_list *ptr);
+
+public:
+  inline /* implicit */ union_set_list();
+  inline /* implicit */ union_set_list(const isl::union_set_list &obj);
+  inline /* implicit */ union_set_list(std::nullptr_t);
+  inline isl::union_set_list &operator=(isl::union_set_list obj);
+  inline ~union_set_list();
+  inline __isl_give isl_union_set_list *copy() const &;
+  inline __isl_give isl_union_set_list *copy() && = delete;
+  inline __isl_keep isl_union_set_list *get() const;
+  inline __isl_give isl_union_set_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_union_set_list *keep() const;
+  inline __isl_give isl_union_set_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// declarations for isl::val
+inline isl::val manage(__isl_take isl_val *ptr);
+inline isl::val give(__isl_take isl_val *ptr);
+
+
+class val {
+  friend inline isl::val manage(__isl_take isl_val *ptr);
+
+  isl_val *ptr = nullptr;
+
+  inline explicit val(__isl_take isl_val *ptr);
+
+public:
+  inline /* implicit */ val();
+  inline /* implicit */ val(const isl::val &obj);
+  inline /* implicit */ val(std::nullptr_t);
+  inline explicit val(isl::ctx ctx, long i);
+  inline explicit val(isl::ctx ctx, const std::string &str);
+  inline isl::val &operator=(isl::val obj);
+  inline ~val();
+  inline __isl_give isl_val *copy() const &;
+  inline __isl_give isl_val *copy() && = delete;
+  inline __isl_keep isl_val *get() const;
+  inline __isl_give isl_val *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_val *keep() const;
+  inline __isl_give isl_val *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline std::string to_str() const;
+  inline void dump() const;
+
+  inline isl::val two_exp() const;
+  inline isl::val abs() const;
+  inline isl::boolean abs_eq(const isl::val &v2) const;
+  inline isl::val add(isl::val v2) const;
+  inline isl::val add_ui(unsigned long v2) const;
+  inline isl::val ceil() const;
+  inline int cmp_si(long i) const;
+  inline isl::val div(isl::val v2) const;
+  inline isl::val div_ui(unsigned long v2) const;
+  inline isl::boolean eq(const isl::val &v2) const;
+  inline isl::val floor() const;
+  inline isl::val gcd(isl::val v2) const;
+  inline isl::boolean ge(const isl::val &v2) const;
+  inline uint32_t get_hash() const;
+  inline long get_num_si() const;
+  inline isl::boolean gt(const isl::val &v2) const;
+  static inline isl::val infty(isl::ctx ctx);
+  static inline isl::val int_from_ui(isl::ctx ctx, unsigned long u);
+  inline isl::val inv() const;
+  inline isl::boolean is_divisible_by(const isl::val &v2) const;
+  inline isl::boolean is_infty() const;
+  inline isl::boolean is_int() const;
+  inline isl::boolean is_nan() const;
+  inline isl::boolean is_neg() const;
+  inline isl::boolean is_neginfty() const;
+  inline isl::boolean is_negone() const;
+  inline isl::boolean is_nonneg() const;
+  inline isl::boolean is_nonpos() const;
+  inline isl::boolean is_one() const;
+  inline isl::boolean is_pos() const;
+  inline isl::boolean is_rat() const;
+  inline isl::boolean is_zero() const;
+  inline isl::boolean le(const isl::val &v2) const;
+  inline isl::boolean lt(const isl::val &v2) const;
+  inline isl::val max(isl::val v2) const;
+  inline isl::val min(isl::val v2) const;
+  inline isl::val mod(isl::val v2) const;
+  inline isl::val mul(isl::val v2) const;
+  inline isl::val mul_ui(unsigned long v2) const;
+  static inline isl::val nan(isl::ctx ctx);
+  inline isl::boolean ne(const isl::val &v2) const;
+  inline isl::val neg() const;
+  static inline isl::val neginfty(isl::ctx ctx);
+  static inline isl::val negone(isl::ctx ctx);
+  static inline isl::val one(isl::ctx ctx);
+  inline isl::val set_si(long i) const;
+  inline int sgn() const;
+  inline isl::val sub(isl::val v2) const;
+  inline isl::val sub_ui(unsigned long v2) const;
+  inline isl::val trunc() const;
+  static inline isl::val zero(isl::ctx ctx);
+};
+
+// declarations for isl::val_list
+inline isl::val_list manage(__isl_take isl_val_list *ptr);
+inline isl::val_list give(__isl_take isl_val_list *ptr);
+
+
+class val_list {
+  friend inline isl::val_list manage(__isl_take isl_val_list *ptr);
+
+  isl_val_list *ptr = nullptr;
+
+  inline explicit val_list(__isl_take isl_val_list *ptr);
+
+public:
+  inline /* implicit */ val_list();
+  inline /* implicit */ val_list(const isl::val_list &obj);
+  inline /* implicit */ val_list(std::nullptr_t);
+  inline isl::val_list &operator=(isl::val_list obj);
+  inline ~val_list();
+  inline __isl_give isl_val_list *copy() const &;
+  inline __isl_give isl_val_list *copy() && = delete;
+  inline __isl_keep isl_val_list *get() const;
+  inline __isl_give isl_val_list *release();
+  inline bool is_null() const;
+  inline __isl_keep isl_val_list *keep() const;
+  inline __isl_give isl_val_list *take();
+  inline explicit operator bool() const;
+  inline isl::ctx get_ctx() const;
+  inline void dump() const;
+
+};
+
+// implementations for isl::aff
+isl::aff manage(__isl_take isl_aff *ptr) {
+  return aff(ptr);
+}
+isl::aff give(__isl_take isl_aff *ptr) {
+  return manage(ptr);
+}
+
+
+aff::aff()
+    : ptr(nullptr) {}
+
+aff::aff(const isl::aff &obj)
+    : ptr(obj.copy()) {}
+aff::aff(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+aff::aff(__isl_take isl_aff *ptr)
+    : ptr(ptr) {}
+
+aff::aff(isl::local_space ls) {
+  auto res = isl_aff_zero_on_domain(ls.release());
+  ptr = res;
+}
+aff::aff(isl::local_space ls, isl::val val) {
+  auto res = isl_aff_val_on_domain(ls.release(), val.release());
+  ptr = res;
+}
+aff::aff(isl::ctx ctx, const std::string &str) {
+  auto res = isl_aff_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+aff &aff::operator=(isl::aff obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+aff::~aff() {
+  if (ptr)
+    isl_aff_free(ptr);
+}
+
+__isl_give isl_aff *aff::copy() const & {
+  return isl_aff_copy(ptr);
+}
+
+__isl_keep isl_aff *aff::get() const {
+  return ptr;
+}
+
+__isl_give isl_aff *aff::release() {
+  isl_aff *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool aff::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_aff *aff::keep() const {
+  return get();
+}
+
+__isl_give isl_aff *aff::take() {
+  return release();
+}
+
+aff::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx aff::get_ctx() const {
+  return isl::ctx(isl_aff_get_ctx(ptr));
+}
+
+
+std::string aff::to_str() const {
+  char *Tmp = isl_aff_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void aff::dump() const {
+  isl_aff_dump(get());
+}
+
+
+isl::aff aff::add(isl::aff aff2) const {
+  auto res = isl_aff_add(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::aff aff::add_coefficient_si(isl::dim type, int pos, int v) const {
+  auto res = isl_aff_add_coefficient_si(copy(), static_cast<enum isl_dim_type>(type), pos, v);
+  return manage(res);
+}
+
+isl::aff aff::add_coefficient_val(isl::dim type, int pos, isl::val v) const {
+  auto res = isl_aff_add_coefficient_val(copy(), static_cast<enum isl_dim_type>(type), pos, v.release());
+  return manage(res);
+}
+
+isl::aff aff::add_constant_num_si(int v) const {
+  auto res = isl_aff_add_constant_num_si(copy(), v);
+  return manage(res);
+}
+
+isl::aff aff::add_constant_si(int v) const {
+  auto res = isl_aff_add_constant_si(copy(), v);
+  return manage(res);
+}
+
+isl::aff aff::add_constant_val(isl::val v) const {
+  auto res = isl_aff_add_constant_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::aff aff::add_dims(isl::dim type, unsigned int n) const {
+  auto res = isl_aff_add_dims(copy(), static_cast<enum isl_dim_type>(type), n);
+  return manage(res);
+}
+
+isl::aff aff::align_params(isl::space model) const {
+  auto res = isl_aff_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::aff aff::ceil() const {
+  auto res = isl_aff_ceil(copy());
+  return manage(res);
+}
+
+int aff::coefficient_sgn(isl::dim type, int pos) const {
+  auto res = isl_aff_coefficient_sgn(get(), static_cast<enum isl_dim_type>(type), pos);
+  return res;
+}
+
+int aff::dim(isl::dim type) const {
+  auto res = isl_aff_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::aff aff::div(isl::aff aff2) const {
+  auto res = isl_aff_div(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::aff aff::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_aff_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_set aff::eq_basic_set(isl::aff aff2) const {
+  auto res = isl_aff_eq_basic_set(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::set aff::eq_set(isl::aff aff2) const {
+  auto res = isl_aff_eq_set(copy(), aff2.release());
+  return manage(res);
+}
+
+int aff::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_aff_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::aff aff::floor() const {
+  auto res = isl_aff_floor(copy());
+  return manage(res);
+}
+
+isl::basic_set aff::ge_basic_set(isl::aff aff2) const {
+  auto res = isl_aff_ge_basic_set(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::set aff::ge_set(isl::aff aff2) const {
+  auto res = isl_aff_ge_set(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::val aff::get_coefficient_val(isl::dim type, int pos) const {
+  auto res = isl_aff_get_coefficient_val(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::val aff::get_constant_val() const {
+  auto res = isl_aff_get_constant_val(get());
+  return manage(res);
+}
+
+isl::val aff::get_denominator_val() const {
+  auto res = isl_aff_get_denominator_val(get());
+  return manage(res);
+}
+
+std::string aff::get_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_aff_get_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::aff aff::get_div(int pos) const {
+  auto res = isl_aff_get_div(get(), pos);
+  return manage(res);
+}
+
+isl::local_space aff::get_domain_local_space() const {
+  auto res = isl_aff_get_domain_local_space(get());
+  return manage(res);
+}
+
+isl::space aff::get_domain_space() const {
+  auto res = isl_aff_get_domain_space(get());
+  return manage(res);
+}
+
+uint32_t aff::get_hash() const {
+  auto res = isl_aff_get_hash(get());
+  return res;
+}
+
+isl::local_space aff::get_local_space() const {
+  auto res = isl_aff_get_local_space(get());
+  return manage(res);
+}
+
+isl::space aff::get_space() const {
+  auto res = isl_aff_get_space(get());
+  return manage(res);
+}
+
+isl::aff aff::gist(isl::set context) const {
+  auto res = isl_aff_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::aff aff::gist_params(isl::set context) const {
+  auto res = isl_aff_gist_params(copy(), context.release());
+  return manage(res);
+}
+
+isl::basic_set aff::gt_basic_set(isl::aff aff2) const {
+  auto res = isl_aff_gt_basic_set(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::set aff::gt_set(isl::aff aff2) const {
+  auto res = isl_aff_gt_set(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::aff aff::insert_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_aff_insert_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean aff::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_aff_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean aff::is_cst() const {
+  auto res = isl_aff_is_cst(get());
+  return manage(res);
+}
+
+isl::boolean aff::is_nan() const {
+  auto res = isl_aff_is_nan(get());
+  return manage(res);
+}
+
+isl::basic_set aff::le_basic_set(isl::aff aff2) const {
+  auto res = isl_aff_le_basic_set(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::set aff::le_set(isl::aff aff2) const {
+  auto res = isl_aff_le_set(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::basic_set aff::lt_basic_set(isl::aff aff2) const {
+  auto res = isl_aff_lt_basic_set(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::set aff::lt_set(isl::aff aff2) const {
+  auto res = isl_aff_lt_set(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::aff aff::mod(isl::val mod) const {
+  auto res = isl_aff_mod_val(copy(), mod.release());
+  return manage(res);
+}
+
+isl::aff aff::move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const {
+  auto res = isl_aff_move_dims(copy(), static_cast<enum isl_dim_type>(dst_type), dst_pos, static_cast<enum isl_dim_type>(src_type), src_pos, n);
+  return manage(res);
+}
+
+isl::aff aff::mul(isl::aff aff2) const {
+  auto res = isl_aff_mul(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::aff aff::nan_on_domain(isl::local_space ls) {
+  auto res = isl_aff_nan_on_domain(ls.release());
+  return manage(res);
+}
+
+isl::set aff::ne_set(isl::aff aff2) const {
+  auto res = isl_aff_ne_set(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::aff aff::neg() const {
+  auto res = isl_aff_neg(copy());
+  return manage(res);
+}
+
+isl::basic_set aff::neg_basic_set() const {
+  auto res = isl_aff_neg_basic_set(copy());
+  return manage(res);
+}
+
+isl::boolean aff::plain_is_equal(const isl::aff &aff2) const {
+  auto res = isl_aff_plain_is_equal(get(), aff2.get());
+  return manage(res);
+}
+
+isl::boolean aff::plain_is_zero() const {
+  auto res = isl_aff_plain_is_zero(get());
+  return manage(res);
+}
+
+isl::aff aff::project_domain_on_params() const {
+  auto res = isl_aff_project_domain_on_params(copy());
+  return manage(res);
+}
+
+isl::aff aff::pullback(isl::multi_aff ma) const {
+  auto res = isl_aff_pullback_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::aff aff::pullback_aff(isl::aff aff2) const {
+  auto res = isl_aff_pullback_aff(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::aff aff::scale(isl::val v) const {
+  auto res = isl_aff_scale_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::aff aff::scale_down(isl::val v) const {
+  auto res = isl_aff_scale_down_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::aff aff::scale_down_ui(unsigned int f) const {
+  auto res = isl_aff_scale_down_ui(copy(), f);
+  return manage(res);
+}
+
+isl::aff aff::set_coefficient_si(isl::dim type, int pos, int v) const {
+  auto res = isl_aff_set_coefficient_si(copy(), static_cast<enum isl_dim_type>(type), pos, v);
+  return manage(res);
+}
+
+isl::aff aff::set_coefficient_val(isl::dim type, int pos, isl::val v) const {
+  auto res = isl_aff_set_coefficient_val(copy(), static_cast<enum isl_dim_type>(type), pos, v.release());
+  return manage(res);
+}
+
+isl::aff aff::set_constant_si(int v) const {
+  auto res = isl_aff_set_constant_si(copy(), v);
+  return manage(res);
+}
+
+isl::aff aff::set_constant_val(isl::val v) const {
+  auto res = isl_aff_set_constant_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::aff aff::set_dim_id(isl::dim type, unsigned int pos, isl::id id) const {
+  auto res = isl_aff_set_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos, id.release());
+  return manage(res);
+}
+
+isl::aff aff::set_tuple_id(isl::dim type, isl::id id) const {
+  auto res = isl_aff_set_tuple_id(copy(), static_cast<enum isl_dim_type>(type), id.release());
+  return manage(res);
+}
+
+isl::aff aff::sub(isl::aff aff2) const {
+  auto res = isl_aff_sub(copy(), aff2.release());
+  return manage(res);
+}
+
+isl::aff aff::var_on_domain(isl::local_space ls, isl::dim type, unsigned int pos) {
+  auto res = isl_aff_var_on_domain(ls.release(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::basic_set aff::zero_basic_set() const {
+  auto res = isl_aff_zero_basic_set(copy());
+  return manage(res);
+}
+
+// implementations for isl::aff_list
+isl::aff_list manage(__isl_take isl_aff_list *ptr) {
+  return aff_list(ptr);
+}
+isl::aff_list give(__isl_take isl_aff_list *ptr) {
+  return manage(ptr);
+}
+
+
+aff_list::aff_list()
+    : ptr(nullptr) {}
+
+aff_list::aff_list(const isl::aff_list &obj)
+    : ptr(obj.copy()) {}
+aff_list::aff_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+aff_list::aff_list(__isl_take isl_aff_list *ptr)
+    : ptr(ptr) {}
+
+
+aff_list &aff_list::operator=(isl::aff_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+aff_list::~aff_list() {
+  if (ptr)
+    isl_aff_list_free(ptr);
+}
+
+__isl_give isl_aff_list *aff_list::copy() const & {
+  return isl_aff_list_copy(ptr);
+}
+
+__isl_keep isl_aff_list *aff_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_aff_list *aff_list::release() {
+  isl_aff_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool aff_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_aff_list *aff_list::keep() const {
+  return get();
+}
+
+__isl_give isl_aff_list *aff_list::take() {
+  return release();
+}
+
+aff_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx aff_list::get_ctx() const {
+  return isl::ctx(isl_aff_list_get_ctx(ptr));
+}
+
+
+
+void aff_list::dump() const {
+  isl_aff_list_dump(get());
+}
+
+
+
+// implementations for isl::ast_build
+isl::ast_build manage(__isl_take isl_ast_build *ptr) {
+  return ast_build(ptr);
+}
+isl::ast_build give(__isl_take isl_ast_build *ptr) {
+  return manage(ptr);
+}
+
+
+ast_build::ast_build()
+    : ptr(nullptr) {}
+
+ast_build::ast_build(const isl::ast_build &obj)
+    : ptr(obj.copy()) {}
+ast_build::ast_build(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+ast_build::ast_build(__isl_take isl_ast_build *ptr)
+    : ptr(ptr) {}
+
+ast_build::ast_build(isl::ctx ctx) {
+  auto res = isl_ast_build_alloc(ctx.release());
+  ptr = res;
+}
+
+ast_build &ast_build::operator=(isl::ast_build obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+ast_build::~ast_build() {
+  if (ptr)
+    isl_ast_build_free(ptr);
+}
+
+__isl_give isl_ast_build *ast_build::copy() const & {
+  return isl_ast_build_copy(ptr);
+}
+
+__isl_keep isl_ast_build *ast_build::get() const {
+  return ptr;
+}
+
+__isl_give isl_ast_build *ast_build::release() {
+  isl_ast_build *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool ast_build::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_ast_build *ast_build::keep() const {
+  return get();
+}
+
+__isl_give isl_ast_build *ast_build::take() {
+  return release();
+}
+
+ast_build::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx ast_build::get_ctx() const {
+  return isl::ctx(isl_ast_build_get_ctx(ptr));
+}
+
+
+
+
+isl::ast_expr ast_build::access_from(isl::pw_multi_aff pma) const {
+  auto res = isl_ast_build_access_from_pw_multi_aff(get(), pma.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_build::access_from(isl::multi_pw_aff mpa) const {
+  auto res = isl_ast_build_access_from_multi_pw_aff(get(), mpa.release());
+  return manage(res);
+}
+
+isl::ast_node ast_build::ast_from_schedule(isl::union_map schedule) const {
+  auto res = isl_ast_build_ast_from_schedule(get(), schedule.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_build::call_from(isl::pw_multi_aff pma) const {
+  auto res = isl_ast_build_call_from_pw_multi_aff(get(), pma.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_build::call_from(isl::multi_pw_aff mpa) const {
+  auto res = isl_ast_build_call_from_multi_pw_aff(get(), mpa.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_build::expr_from(isl::set set) const {
+  auto res = isl_ast_build_expr_from_set(get(), set.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_build::expr_from(isl::pw_aff pa) const {
+  auto res = isl_ast_build_expr_from_pw_aff(get(), pa.release());
+  return manage(res);
+}
+
+isl::ast_build ast_build::from_context(isl::set set) {
+  auto res = isl_ast_build_from_context(set.release());
+  return manage(res);
+}
+
+isl::union_map ast_build::get_schedule() const {
+  auto res = isl_ast_build_get_schedule(get());
+  return manage(res);
+}
+
+isl::space ast_build::get_schedule_space() const {
+  auto res = isl_ast_build_get_schedule_space(get());
+  return manage(res);
+}
+
+isl::ast_node ast_build::node_from_schedule(isl::schedule schedule) const {
+  auto res = isl_ast_build_node_from_schedule(get(), schedule.release());
+  return manage(res);
+}
+
+isl::ast_node ast_build::node_from_schedule_map(isl::union_map schedule) const {
+  auto res = isl_ast_build_node_from_schedule_map(get(), schedule.release());
+  return manage(res);
+}
+
+isl::ast_build ast_build::restrict(isl::set set) const {
+  auto res = isl_ast_build_restrict(copy(), set.release());
+  return manage(res);
+}
+
+// implementations for isl::ast_expr
+isl::ast_expr manage(__isl_take isl_ast_expr *ptr) {
+  return ast_expr(ptr);
+}
+isl::ast_expr give(__isl_take isl_ast_expr *ptr) {
+  return manage(ptr);
+}
+
+
+ast_expr::ast_expr()
+    : ptr(nullptr) {}
+
+ast_expr::ast_expr(const isl::ast_expr &obj)
+    : ptr(obj.copy()) {}
+ast_expr::ast_expr(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+ast_expr::ast_expr(__isl_take isl_ast_expr *ptr)
+    : ptr(ptr) {}
+
+
+ast_expr &ast_expr::operator=(isl::ast_expr obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+ast_expr::~ast_expr() {
+  if (ptr)
+    isl_ast_expr_free(ptr);
+}
+
+__isl_give isl_ast_expr *ast_expr::copy() const & {
+  return isl_ast_expr_copy(ptr);
+}
+
+__isl_keep isl_ast_expr *ast_expr::get() const {
+  return ptr;
+}
+
+__isl_give isl_ast_expr *ast_expr::release() {
+  isl_ast_expr *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool ast_expr::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_ast_expr *ast_expr::keep() const {
+  return get();
+}
+
+__isl_give isl_ast_expr *ast_expr::take() {
+  return release();
+}
+
+ast_expr::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx ast_expr::get_ctx() const {
+  return isl::ctx(isl_ast_expr_get_ctx(ptr));
+}
+
+
+std::string ast_expr::to_str() const {
+  char *Tmp = isl_ast_expr_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void ast_expr::dump() const {
+  isl_ast_expr_dump(get());
+}
+
+
+isl::ast_expr ast_expr::access(isl::ast_expr_list indices) const {
+  auto res = isl_ast_expr_access(copy(), indices.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::add(isl::ast_expr expr2) const {
+  auto res = isl_ast_expr_add(copy(), expr2.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::address_of() const {
+  auto res = isl_ast_expr_address_of(copy());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::call(isl::ast_expr_list arguments) const {
+  auto res = isl_ast_expr_call(copy(), arguments.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::div(isl::ast_expr expr2) const {
+  auto res = isl_ast_expr_div(copy(), expr2.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::eq(isl::ast_expr expr2) const {
+  auto res = isl_ast_expr_eq(copy(), expr2.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::from_id(isl::id id) {
+  auto res = isl_ast_expr_from_id(id.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::from_val(isl::val v) {
+  auto res = isl_ast_expr_from_val(v.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::ge(isl::ast_expr expr2) const {
+  auto res = isl_ast_expr_ge(copy(), expr2.release());
+  return manage(res);
+}
+
+isl::id ast_expr::get_id() const {
+  auto res = isl_ast_expr_get_id(get());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::get_op_arg(int pos) const {
+  auto res = isl_ast_expr_get_op_arg(get(), pos);
+  return manage(res);
+}
+
+isl::val ast_expr::get_val() const {
+  auto res = isl_ast_expr_get_val(get());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::gt(isl::ast_expr expr2) const {
+  auto res = isl_ast_expr_gt(copy(), expr2.release());
+  return manage(res);
+}
+
+isl::boolean ast_expr::is_equal(const isl::ast_expr &expr2) const {
+  auto res = isl_ast_expr_is_equal(get(), expr2.get());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::le(isl::ast_expr expr2) const {
+  auto res = isl_ast_expr_le(copy(), expr2.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::lt(isl::ast_expr expr2) const {
+  auto res = isl_ast_expr_lt(copy(), expr2.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::mul(isl::ast_expr expr2) const {
+  auto res = isl_ast_expr_mul(copy(), expr2.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::neg() const {
+  auto res = isl_ast_expr_neg(copy());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::pdiv_q(isl::ast_expr expr2) const {
+  auto res = isl_ast_expr_pdiv_q(copy(), expr2.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::pdiv_r(isl::ast_expr expr2) const {
+  auto res = isl_ast_expr_pdiv_r(copy(), expr2.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::set_op_arg(int pos, isl::ast_expr arg) const {
+  auto res = isl_ast_expr_set_op_arg(copy(), pos, arg.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::sub(isl::ast_expr expr2) const {
+  auto res = isl_ast_expr_sub(copy(), expr2.release());
+  return manage(res);
+}
+
+isl::ast_expr ast_expr::substitute_ids(isl::id_to_ast_expr id2expr) const {
+  auto res = isl_ast_expr_substitute_ids(copy(), id2expr.release());
+  return manage(res);
+}
+
+std::string ast_expr::to_C_str() const {
+  auto res = isl_ast_expr_to_C_str(get());
+  std::string tmp(res);
+  free(res);
+  return tmp;
+}
+
+// implementations for isl::ast_expr_list
+isl::ast_expr_list manage(__isl_take isl_ast_expr_list *ptr) {
+  return ast_expr_list(ptr);
+}
+isl::ast_expr_list give(__isl_take isl_ast_expr_list *ptr) {
+  return manage(ptr);
+}
+
+
+ast_expr_list::ast_expr_list()
+    : ptr(nullptr) {}
+
+ast_expr_list::ast_expr_list(const isl::ast_expr_list &obj)
+    : ptr(obj.copy()) {}
+ast_expr_list::ast_expr_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+ast_expr_list::ast_expr_list(__isl_take isl_ast_expr_list *ptr)
+    : ptr(ptr) {}
+
+
+ast_expr_list &ast_expr_list::operator=(isl::ast_expr_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+ast_expr_list::~ast_expr_list() {
+  if (ptr)
+    isl_ast_expr_list_free(ptr);
+}
+
+__isl_give isl_ast_expr_list *ast_expr_list::copy() const & {
+  return isl_ast_expr_list_copy(ptr);
+}
+
+__isl_keep isl_ast_expr_list *ast_expr_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_ast_expr_list *ast_expr_list::release() {
+  isl_ast_expr_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool ast_expr_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_ast_expr_list *ast_expr_list::keep() const {
+  return get();
+}
+
+__isl_give isl_ast_expr_list *ast_expr_list::take() {
+  return release();
+}
+
+ast_expr_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx ast_expr_list::get_ctx() const {
+  return isl::ctx(isl_ast_expr_list_get_ctx(ptr));
+}
+
+
+
+void ast_expr_list::dump() const {
+  isl_ast_expr_list_dump(get());
+}
+
+
+
+// implementations for isl::ast_node
+isl::ast_node manage(__isl_take isl_ast_node *ptr) {
+  return ast_node(ptr);
+}
+isl::ast_node give(__isl_take isl_ast_node *ptr) {
+  return manage(ptr);
+}
+
+
+ast_node::ast_node()
+    : ptr(nullptr) {}
+
+ast_node::ast_node(const isl::ast_node &obj)
+    : ptr(obj.copy()) {}
+ast_node::ast_node(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+ast_node::ast_node(__isl_take isl_ast_node *ptr)
+    : ptr(ptr) {}
+
+
+ast_node &ast_node::operator=(isl::ast_node obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+ast_node::~ast_node() {
+  if (ptr)
+    isl_ast_node_free(ptr);
+}
+
+__isl_give isl_ast_node *ast_node::copy() const & {
+  return isl_ast_node_copy(ptr);
+}
+
+__isl_keep isl_ast_node *ast_node::get() const {
+  return ptr;
+}
+
+__isl_give isl_ast_node *ast_node::release() {
+  isl_ast_node *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool ast_node::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_ast_node *ast_node::keep() const {
+  return get();
+}
+
+__isl_give isl_ast_node *ast_node::take() {
+  return release();
+}
+
+ast_node::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx ast_node::get_ctx() const {
+  return isl::ctx(isl_ast_node_get_ctx(ptr));
+}
+
+
+std::string ast_node::to_str() const {
+  char *Tmp = isl_ast_node_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void ast_node::dump() const {
+  isl_ast_node_dump(get());
+}
+
+
+isl::ast_node ast_node::alloc_user(isl::ast_expr expr) {
+  auto res = isl_ast_node_alloc_user(expr.release());
+  return manage(res);
+}
+
+isl::ast_node_list ast_node::block_get_children() const {
+  auto res = isl_ast_node_block_get_children(get());
+  return manage(res);
+}
+
+isl::ast_node ast_node::for_get_body() const {
+  auto res = isl_ast_node_for_get_body(get());
+  return manage(res);
+}
+
+isl::ast_expr ast_node::for_get_cond() const {
+  auto res = isl_ast_node_for_get_cond(get());
+  return manage(res);
+}
+
+isl::ast_expr ast_node::for_get_inc() const {
+  auto res = isl_ast_node_for_get_inc(get());
+  return manage(res);
+}
+
+isl::ast_expr ast_node::for_get_init() const {
+  auto res = isl_ast_node_for_get_init(get());
+  return manage(res);
+}
+
+isl::ast_expr ast_node::for_get_iterator() const {
+  auto res = isl_ast_node_for_get_iterator(get());
+  return manage(res);
+}
+
+isl::boolean ast_node::for_is_degenerate() const {
+  auto res = isl_ast_node_for_is_degenerate(get());
+  return manage(res);
+}
+
+isl::id ast_node::get_annotation() const {
+  auto res = isl_ast_node_get_annotation(get());
+  return manage(res);
+}
+
+isl::ast_expr ast_node::if_get_cond() const {
+  auto res = isl_ast_node_if_get_cond(get());
+  return manage(res);
+}
+
+isl::ast_node ast_node::if_get_else() const {
+  auto res = isl_ast_node_if_get_else(get());
+  return manage(res);
+}
+
+isl::ast_node ast_node::if_get_then() const {
+  auto res = isl_ast_node_if_get_then(get());
+  return manage(res);
+}
+
+isl::boolean ast_node::if_has_else() const {
+  auto res = isl_ast_node_if_has_else(get());
+  return manage(res);
+}
+
+isl::id ast_node::mark_get_id() const {
+  auto res = isl_ast_node_mark_get_id(get());
+  return manage(res);
+}
+
+isl::ast_node ast_node::mark_get_node() const {
+  auto res = isl_ast_node_mark_get_node(get());
+  return manage(res);
+}
+
+isl::ast_node ast_node::set_annotation(isl::id annotation) const {
+  auto res = isl_ast_node_set_annotation(copy(), annotation.release());
+  return manage(res);
+}
+
+std::string ast_node::to_C_str() const {
+  auto res = isl_ast_node_to_C_str(get());
+  std::string tmp(res);
+  free(res);
+  return tmp;
+}
+
+isl::ast_expr ast_node::user_get_expr() const {
+  auto res = isl_ast_node_user_get_expr(get());
+  return manage(res);
+}
+
+// implementations for isl::ast_node_list
+isl::ast_node_list manage(__isl_take isl_ast_node_list *ptr) {
+  return ast_node_list(ptr);
+}
+isl::ast_node_list give(__isl_take isl_ast_node_list *ptr) {
+  return manage(ptr);
+}
+
+
+ast_node_list::ast_node_list()
+    : ptr(nullptr) {}
+
+ast_node_list::ast_node_list(const isl::ast_node_list &obj)
+    : ptr(obj.copy()) {}
+ast_node_list::ast_node_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+ast_node_list::ast_node_list(__isl_take isl_ast_node_list *ptr)
+    : ptr(ptr) {}
+
+
+ast_node_list &ast_node_list::operator=(isl::ast_node_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+ast_node_list::~ast_node_list() {
+  if (ptr)
+    isl_ast_node_list_free(ptr);
+}
+
+__isl_give isl_ast_node_list *ast_node_list::copy() const & {
+  return isl_ast_node_list_copy(ptr);
+}
+
+__isl_keep isl_ast_node_list *ast_node_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_ast_node_list *ast_node_list::release() {
+  isl_ast_node_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool ast_node_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_ast_node_list *ast_node_list::keep() const {
+  return get();
+}
+
+__isl_give isl_ast_node_list *ast_node_list::take() {
+  return release();
+}
+
+ast_node_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx ast_node_list::get_ctx() const {
+  return isl::ctx(isl_ast_node_list_get_ctx(ptr));
+}
+
+
+
+void ast_node_list::dump() const {
+  isl_ast_node_list_dump(get());
+}
+
+
+
+// implementations for isl::band_list
+isl::band_list manage(__isl_take isl_band_list *ptr) {
+  return band_list(ptr);
+}
+isl::band_list give(__isl_take isl_band_list *ptr) {
+  return manage(ptr);
+}
+
+
+band_list::band_list()
+    : ptr(nullptr) {}
+
+band_list::band_list(const isl::band_list &obj)
+    : ptr(obj.copy()) {}
+band_list::band_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+band_list::band_list(__isl_take isl_band_list *ptr)
+    : ptr(ptr) {}
+
+
+band_list &band_list::operator=(isl::band_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+band_list::~band_list() {
+  if (ptr)
+    isl_band_list_free(ptr);
+}
+
+__isl_give isl_band_list *band_list::copy() const & {
+  return isl_band_list_copy(ptr);
+}
+
+__isl_keep isl_band_list *band_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_band_list *band_list::release() {
+  isl_band_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool band_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_band_list *band_list::keep() const {
+  return get();
+}
+
+__isl_give isl_band_list *band_list::take() {
+  return release();
+}
+
+band_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx band_list::get_ctx() const {
+  return isl::ctx(isl_band_list_get_ctx(ptr));
+}
+
+
+
+void band_list::dump() const {
+  isl_band_list_dump(get());
+}
+
+
+
+// implementations for isl::basic_map
+isl::basic_map manage(__isl_take isl_basic_map *ptr) {
+  return basic_map(ptr);
+}
+isl::basic_map give(__isl_take isl_basic_map *ptr) {
+  return manage(ptr);
+}
+
+
+basic_map::basic_map()
+    : ptr(nullptr) {}
+
+basic_map::basic_map(const isl::basic_map &obj)
+    : ptr(obj.copy()) {}
+basic_map::basic_map(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+basic_map::basic_map(__isl_take isl_basic_map *ptr)
+    : ptr(ptr) {}
+
+basic_map::basic_map(isl::ctx ctx, const std::string &str) {
+  auto res = isl_basic_map_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+basic_map &basic_map::operator=(isl::basic_map obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+basic_map::~basic_map() {
+  if (ptr)
+    isl_basic_map_free(ptr);
+}
+
+__isl_give isl_basic_map *basic_map::copy() const & {
+  return isl_basic_map_copy(ptr);
+}
+
+__isl_keep isl_basic_map *basic_map::get() const {
+  return ptr;
+}
+
+__isl_give isl_basic_map *basic_map::release() {
+  isl_basic_map *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool basic_map::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_basic_map *basic_map::keep() const {
+  return get();
+}
+
+__isl_give isl_basic_map *basic_map::take() {
+  return release();
+}
+
+basic_map::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx basic_map::get_ctx() const {
+  return isl::ctx(isl_basic_map_get_ctx(ptr));
+}
+
+
+std::string basic_map::to_str() const {
+  char *Tmp = isl_basic_map_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void basic_map::dump() const {
+  isl_basic_map_dump(get());
+}
+
+
+isl::basic_map basic_map::add_constraint(isl::constraint constraint) const {
+  auto res = isl_basic_map_add_constraint(copy(), constraint.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::add_dims(isl::dim type, unsigned int n) const {
+  auto res = isl_basic_map_add_dims(copy(), static_cast<enum isl_dim_type>(type), n);
+  return manage(res);
+}
+
+isl::basic_map basic_map::affine_hull() const {
+  auto res = isl_basic_map_affine_hull(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::align_params(isl::space model) const {
+  auto res = isl_basic_map_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::apply_domain(isl::basic_map bmap2) const {
+  auto res = isl_basic_map_apply_domain(copy(), bmap2.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::apply_range(isl::basic_map bmap2) const {
+  auto res = isl_basic_map_apply_range(copy(), bmap2.release());
+  return manage(res);
+}
+
+isl::boolean basic_map::can_curry() const {
+  auto res = isl_basic_map_can_curry(get());
+  return manage(res);
+}
+
+isl::boolean basic_map::can_uncurry() const {
+  auto res = isl_basic_map_can_uncurry(get());
+  return manage(res);
+}
+
+isl::boolean basic_map::can_zip() const {
+  auto res = isl_basic_map_can_zip(get());
+  return manage(res);
+}
+
+isl::basic_map basic_map::curry() const {
+  auto res = isl_basic_map_curry(copy());
+  return manage(res);
+}
+
+isl::basic_set basic_map::deltas() const {
+  auto res = isl_basic_map_deltas(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::deltas_map() const {
+  auto res = isl_basic_map_deltas_map(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::detect_equalities() const {
+  auto res = isl_basic_map_detect_equalities(copy());
+  return manage(res);
+}
+
+unsigned int basic_map::dim(isl::dim type) const {
+  auto res = isl_basic_map_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::basic_set basic_map::domain() const {
+  auto res = isl_basic_map_domain(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::domain_map() const {
+  auto res = isl_basic_map_domain_map(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::domain_product(isl::basic_map bmap2) const {
+  auto res = isl_basic_map_domain_product(copy(), bmap2.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::drop_constraints_involving_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_map_drop_constraints_involving_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_map basic_map::drop_constraints_not_involving_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_map_drop_constraints_not_involving_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_map basic_map::eliminate(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_map_eliminate(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_map basic_map::empty(isl::space dim) {
+  auto res = isl_basic_map_empty(dim.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::equal(isl::space dim, unsigned int n_equal) {
+  auto res = isl_basic_map_equal(dim.release(), n_equal);
+  return manage(res);
+}
+
+isl::basic_map basic_map::equate(isl::dim type1, int pos1, isl::dim type2, int pos2) const {
+  auto res = isl_basic_map_equate(copy(), static_cast<enum isl_dim_type>(type1), pos1, static_cast<enum isl_dim_type>(type2), pos2);
+  return manage(res);
+}
+
+int basic_map::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_basic_map_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::basic_map basic_map::fix_si(isl::dim type, unsigned int pos, int value) const {
+  auto res = isl_basic_map_fix_si(copy(), static_cast<enum isl_dim_type>(type), pos, value);
+  return manage(res);
+}
+
+isl::basic_map basic_map::fix_val(isl::dim type, unsigned int pos, isl::val v) const {
+  auto res = isl_basic_map_fix_val(copy(), static_cast<enum isl_dim_type>(type), pos, v.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::flat_product(isl::basic_map bmap2) const {
+  auto res = isl_basic_map_flat_product(copy(), bmap2.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::flat_range_product(isl::basic_map bmap2) const {
+  auto res = isl_basic_map_flat_range_product(copy(), bmap2.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::flatten() const {
+  auto res = isl_basic_map_flatten(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::flatten_domain() const {
+  auto res = isl_basic_map_flatten_domain(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::flatten_range() const {
+  auto res = isl_basic_map_flatten_range(copy());
+  return manage(res);
+}
+
+isl::stat basic_map::foreach_constraint(const std::function<isl::stat(isl::constraint)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_constraint *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::constraint)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_basic_map_foreach_constraint(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::basic_map basic_map::from_aff(isl::aff aff) {
+  auto res = isl_basic_map_from_aff(aff.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::from_aff_list(isl::space domain_dim, isl::aff_list list) {
+  auto res = isl_basic_map_from_aff_list(domain_dim.release(), list.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::from_constraint(isl::constraint constraint) {
+  auto res = isl_basic_map_from_constraint(constraint.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::from_domain(isl::basic_set bset) {
+  auto res = isl_basic_map_from_domain(bset.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::from_domain_and_range(isl::basic_set domain, isl::basic_set range) {
+  auto res = isl_basic_map_from_domain_and_range(domain.release(), range.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::from_multi_aff(isl::multi_aff maff) {
+  auto res = isl_basic_map_from_multi_aff(maff.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::from_qpolynomial(isl::qpolynomial qp) {
+  auto res = isl_basic_map_from_qpolynomial(qp.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::from_range(isl::basic_set bset) {
+  auto res = isl_basic_map_from_range(bset.release());
+  return manage(res);
+}
+
+isl::constraint_list basic_map::get_constraint_list() const {
+  auto res = isl_basic_map_get_constraint_list(get());
+  return manage(res);
+}
+
+std::string basic_map::get_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_basic_map_get_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::aff basic_map::get_div(int pos) const {
+  auto res = isl_basic_map_get_div(get(), pos);
+  return manage(res);
+}
+
+isl::local_space basic_map::get_local_space() const {
+  auto res = isl_basic_map_get_local_space(get());
+  return manage(res);
+}
+
+isl::space basic_map::get_space() const {
+  auto res = isl_basic_map_get_space(get());
+  return manage(res);
+}
+
+std::string basic_map::get_tuple_name(isl::dim type) const {
+  auto res = isl_basic_map_get_tuple_name(get(), static_cast<enum isl_dim_type>(type));
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::basic_map basic_map::gist(isl::basic_map context) const {
+  auto res = isl_basic_map_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::gist_domain(isl::basic_set context) const {
+  auto res = isl_basic_map_gist_domain(copy(), context.release());
+  return manage(res);
+}
+
+isl::boolean basic_map::has_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_basic_map_has_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::basic_map basic_map::identity(isl::space dim) {
+  auto res = isl_basic_map_identity(dim.release());
+  return manage(res);
+}
+
+isl::boolean basic_map::image_is_bounded() const {
+  auto res = isl_basic_map_image_is_bounded(get());
+  return manage(res);
+}
+
+isl::basic_map basic_map::insert_dims(isl::dim type, unsigned int pos, unsigned int n) const {
+  auto res = isl_basic_map_insert_dims(copy(), static_cast<enum isl_dim_type>(type), pos, n);
+  return manage(res);
+}
+
+isl::basic_map basic_map::intersect(isl::basic_map bmap2) const {
+  auto res = isl_basic_map_intersect(copy(), bmap2.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::intersect_domain(isl::basic_set bset) const {
+  auto res = isl_basic_map_intersect_domain(copy(), bset.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::intersect_range(isl::basic_set bset) const {
+  auto res = isl_basic_map_intersect_range(copy(), bset.release());
+  return manage(res);
+}
+
+isl::boolean basic_map::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_map_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean basic_map::is_disjoint(const isl::basic_map &bmap2) const {
+  auto res = isl_basic_map_is_disjoint(get(), bmap2.get());
+  return manage(res);
+}
+
+isl::boolean basic_map::is_empty() const {
+  auto res = isl_basic_map_is_empty(get());
+  return manage(res);
+}
+
+isl::boolean basic_map::is_equal(const isl::basic_map &bmap2) const {
+  auto res = isl_basic_map_is_equal(get(), bmap2.get());
+  return manage(res);
+}
+
+isl::boolean basic_map::is_rational() const {
+  auto res = isl_basic_map_is_rational(get());
+  return manage(res);
+}
+
+isl::boolean basic_map::is_single_valued() const {
+  auto res = isl_basic_map_is_single_valued(get());
+  return manage(res);
+}
+
+isl::boolean basic_map::is_strict_subset(const isl::basic_map &bmap2) const {
+  auto res = isl_basic_map_is_strict_subset(get(), bmap2.get());
+  return manage(res);
+}
+
+isl::boolean basic_map::is_subset(const isl::basic_map &bmap2) const {
+  auto res = isl_basic_map_is_subset(get(), bmap2.get());
+  return manage(res);
+}
+
+isl::boolean basic_map::is_universe() const {
+  auto res = isl_basic_map_is_universe(get());
+  return manage(res);
+}
+
+isl::basic_map basic_map::less_at(isl::space dim, unsigned int pos) {
+  auto res = isl_basic_map_less_at(dim.release(), pos);
+  return manage(res);
+}
+
+isl::map basic_map::lexmax() const {
+  auto res = isl_basic_map_lexmax(copy());
+  return manage(res);
+}
+
+isl::map basic_map::lexmin() const {
+  auto res = isl_basic_map_lexmin(copy());
+  return manage(res);
+}
+
+isl::pw_multi_aff basic_map::lexmin_pw_multi_aff() const {
+  auto res = isl_basic_map_lexmin_pw_multi_aff(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::lower_bound_si(isl::dim type, unsigned int pos, int value) const {
+  auto res = isl_basic_map_lower_bound_si(copy(), static_cast<enum isl_dim_type>(type), pos, value);
+  return manage(res);
+}
+
+isl::basic_map basic_map::more_at(isl::space dim, unsigned int pos) {
+  auto res = isl_basic_map_more_at(dim.release(), pos);
+  return manage(res);
+}
+
+isl::basic_map basic_map::move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const {
+  auto res = isl_basic_map_move_dims(copy(), static_cast<enum isl_dim_type>(dst_type), dst_pos, static_cast<enum isl_dim_type>(src_type), src_pos, n);
+  return manage(res);
+}
+
+isl::basic_map basic_map::nat_universe(isl::space dim) {
+  auto res = isl_basic_map_nat_universe(dim.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::neg() const {
+  auto res = isl_basic_map_neg(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::order_ge(isl::dim type1, int pos1, isl::dim type2, int pos2) const {
+  auto res = isl_basic_map_order_ge(copy(), static_cast<enum isl_dim_type>(type1), pos1, static_cast<enum isl_dim_type>(type2), pos2);
+  return manage(res);
+}
+
+isl::basic_map basic_map::order_gt(isl::dim type1, int pos1, isl::dim type2, int pos2) const {
+  auto res = isl_basic_map_order_gt(copy(), static_cast<enum isl_dim_type>(type1), pos1, static_cast<enum isl_dim_type>(type2), pos2);
+  return manage(res);
+}
+
+isl::val basic_map::plain_get_val_if_fixed(isl::dim type, unsigned int pos) const {
+  auto res = isl_basic_map_plain_get_val_if_fixed(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean basic_map::plain_is_empty() const {
+  auto res = isl_basic_map_plain_is_empty(get());
+  return manage(res);
+}
+
+isl::boolean basic_map::plain_is_universe() const {
+  auto res = isl_basic_map_plain_is_universe(get());
+  return manage(res);
+}
+
+isl::basic_map basic_map::preimage_domain_multi_aff(isl::multi_aff ma) const {
+  auto res = isl_basic_map_preimage_domain_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::preimage_range_multi_aff(isl::multi_aff ma) const {
+  auto res = isl_basic_map_preimage_range_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::product(isl::basic_map bmap2) const {
+  auto res = isl_basic_map_product(copy(), bmap2.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::project_out(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_map_project_out(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_set basic_map::range() const {
+  auto res = isl_basic_map_range(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::range_map() const {
+  auto res = isl_basic_map_range_map(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::range_product(isl::basic_map bmap2) const {
+  auto res = isl_basic_map_range_product(copy(), bmap2.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::remove_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_map_remove_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_map basic_map::remove_divs() const {
+  auto res = isl_basic_map_remove_divs(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::remove_divs_involving_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_map_remove_divs_involving_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_map basic_map::remove_redundancies() const {
+  auto res = isl_basic_map_remove_redundancies(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::reverse() const {
+  auto res = isl_basic_map_reverse(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::sample() const {
+  auto res = isl_basic_map_sample(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::set_tuple_id(isl::dim type, isl::id id) const {
+  auto res = isl_basic_map_set_tuple_id(copy(), static_cast<enum isl_dim_type>(type), id.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::set_tuple_name(isl::dim type, const std::string &s) const {
+  auto res = isl_basic_map_set_tuple_name(copy(), static_cast<enum isl_dim_type>(type), s.c_str());
+  return manage(res);
+}
+
+isl::basic_map basic_map::sum(isl::basic_map bmap2) const {
+  auto res = isl_basic_map_sum(copy(), bmap2.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::uncurry() const {
+  auto res = isl_basic_map_uncurry(copy());
+  return manage(res);
+}
+
+isl::map basic_map::unite(isl::basic_map bmap2) const {
+  auto res = isl_basic_map_union(copy(), bmap2.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::universe(isl::space dim) {
+  auto res = isl_basic_map_universe(dim.release());
+  return manage(res);
+}
+
+isl::basic_map basic_map::upper_bound_si(isl::dim type, unsigned int pos, int value) const {
+  auto res = isl_basic_map_upper_bound_si(copy(), static_cast<enum isl_dim_type>(type), pos, value);
+  return manage(res);
+}
+
+isl::basic_set basic_map::wrap() const {
+  auto res = isl_basic_map_wrap(copy());
+  return manage(res);
+}
+
+isl::basic_map basic_map::zip() const {
+  auto res = isl_basic_map_zip(copy());
+  return manage(res);
+}
+
+// implementations for isl::basic_map_list
+isl::basic_map_list manage(__isl_take isl_basic_map_list *ptr) {
+  return basic_map_list(ptr);
+}
+isl::basic_map_list give(__isl_take isl_basic_map_list *ptr) {
+  return manage(ptr);
+}
+
+
+basic_map_list::basic_map_list()
+    : ptr(nullptr) {}
+
+basic_map_list::basic_map_list(const isl::basic_map_list &obj)
+    : ptr(obj.copy()) {}
+basic_map_list::basic_map_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+basic_map_list::basic_map_list(__isl_take isl_basic_map_list *ptr)
+    : ptr(ptr) {}
+
+
+basic_map_list &basic_map_list::operator=(isl::basic_map_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+basic_map_list::~basic_map_list() {
+  if (ptr)
+    isl_basic_map_list_free(ptr);
+}
+
+__isl_give isl_basic_map_list *basic_map_list::copy() const & {
+  return isl_basic_map_list_copy(ptr);
+}
+
+__isl_keep isl_basic_map_list *basic_map_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_basic_map_list *basic_map_list::release() {
+  isl_basic_map_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool basic_map_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_basic_map_list *basic_map_list::keep() const {
+  return get();
+}
+
+__isl_give isl_basic_map_list *basic_map_list::take() {
+  return release();
+}
+
+basic_map_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx basic_map_list::get_ctx() const {
+  return isl::ctx(isl_basic_map_list_get_ctx(ptr));
+}
+
+
+
+void basic_map_list::dump() const {
+  isl_basic_map_list_dump(get());
+}
+
+
+
+// implementations for isl::basic_set
+isl::basic_set manage(__isl_take isl_basic_set *ptr) {
+  return basic_set(ptr);
+}
+isl::basic_set give(__isl_take isl_basic_set *ptr) {
+  return manage(ptr);
+}
+
+
+basic_set::basic_set()
+    : ptr(nullptr) {}
+
+basic_set::basic_set(const isl::basic_set &obj)
+    : ptr(obj.copy()) {}
+basic_set::basic_set(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+basic_set::basic_set(__isl_take isl_basic_set *ptr)
+    : ptr(ptr) {}
+
+basic_set::basic_set(isl::ctx ctx, const std::string &str) {
+  auto res = isl_basic_set_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+basic_set::basic_set(isl::point pnt) {
+  auto res = isl_basic_set_from_point(pnt.release());
+  ptr = res;
+}
+
+basic_set &basic_set::operator=(isl::basic_set obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+basic_set::~basic_set() {
+  if (ptr)
+    isl_basic_set_free(ptr);
+}
+
+__isl_give isl_basic_set *basic_set::copy() const & {
+  return isl_basic_set_copy(ptr);
+}
+
+__isl_keep isl_basic_set *basic_set::get() const {
+  return ptr;
+}
+
+__isl_give isl_basic_set *basic_set::release() {
+  isl_basic_set *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool basic_set::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_basic_set *basic_set::keep() const {
+  return get();
+}
+
+__isl_give isl_basic_set *basic_set::take() {
+  return release();
+}
+
+basic_set::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx basic_set::get_ctx() const {
+  return isl::ctx(isl_basic_set_get_ctx(ptr));
+}
+
+
+std::string basic_set::to_str() const {
+  char *Tmp = isl_basic_set_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void basic_set::dump() const {
+  isl_basic_set_dump(get());
+}
+
+
+isl::basic_set basic_set::affine_hull() const {
+  auto res = isl_basic_set_affine_hull(copy());
+  return manage(res);
+}
+
+isl::basic_set basic_set::align_params(isl::space model) const {
+  auto res = isl_basic_set_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::apply(isl::basic_map bmap) const {
+  auto res = isl_basic_set_apply(copy(), bmap.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::box_from_points(isl::point pnt1, isl::point pnt2) {
+  auto res = isl_basic_set_box_from_points(pnt1.release(), pnt2.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::coefficients() const {
+  auto res = isl_basic_set_coefficients(copy());
+  return manage(res);
+}
+
+isl::basic_set basic_set::detect_equalities() const {
+  auto res = isl_basic_set_detect_equalities(copy());
+  return manage(res);
+}
+
+unsigned int basic_set::dim(isl::dim type) const {
+  auto res = isl_basic_set_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::basic_set basic_set::drop_constraints_involving_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_set_drop_constraints_involving_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_set basic_set::drop_constraints_not_involving_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_set_drop_constraints_not_involving_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_set basic_set::eliminate(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_set_eliminate(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_set basic_set::empty(isl::space dim) {
+  auto res = isl_basic_set_empty(dim.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::fix_si(isl::dim type, unsigned int pos, int value) const {
+  auto res = isl_basic_set_fix_si(copy(), static_cast<enum isl_dim_type>(type), pos, value);
+  return manage(res);
+}
+
+isl::basic_set basic_set::fix_val(isl::dim type, unsigned int pos, isl::val v) const {
+  auto res = isl_basic_set_fix_val(copy(), static_cast<enum isl_dim_type>(type), pos, v.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::flat_product(isl::basic_set bset2) const {
+  auto res = isl_basic_set_flat_product(copy(), bset2.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::flatten() const {
+  auto res = isl_basic_set_flatten(copy());
+  return manage(res);
+}
+
+isl::stat basic_set::foreach_bound_pair(isl::dim type, unsigned int pos, const std::function<isl::stat(isl::constraint, isl::constraint, isl::basic_set)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_constraint *arg_0, isl_constraint *arg_1, isl_basic_set *arg_2, void *arg_3) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::constraint, isl::constraint, isl::basic_set)> **>(arg_3);
+    stat ret = (*func)(isl::manage(arg_0), isl::manage(arg_1), isl::manage(arg_2));
+    return isl_stat(ret);
+  };
+  auto res = isl_basic_set_foreach_bound_pair(get(), static_cast<enum isl_dim_type>(type), pos, fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::stat basic_set::foreach_constraint(const std::function<isl::stat(isl::constraint)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_constraint *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::constraint)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_basic_set_foreach_constraint(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::basic_set basic_set::from_constraint(isl::constraint constraint) {
+  auto res = isl_basic_set_from_constraint(constraint.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::from_params() const {
+  auto res = isl_basic_set_from_params(copy());
+  return manage(res);
+}
+
+isl::constraint_list basic_set::get_constraint_list() const {
+  auto res = isl_basic_set_get_constraint_list(get());
+  return manage(res);
+}
+
+isl::id basic_set::get_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_basic_set_get_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+std::string basic_set::get_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_basic_set_get_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::aff basic_set::get_div(int pos) const {
+  auto res = isl_basic_set_get_div(get(), pos);
+  return manage(res);
+}
+
+isl::local_space basic_set::get_local_space() const {
+  auto res = isl_basic_set_get_local_space(get());
+  return manage(res);
+}
+
+isl::space basic_set::get_space() const {
+  auto res = isl_basic_set_get_space(get());
+  return manage(res);
+}
+
+std::string basic_set::get_tuple_name() const {
+  auto res = isl_basic_set_get_tuple_name(get());
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::basic_set basic_set::gist(isl::basic_set context) const {
+  auto res = isl_basic_set_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::insert_dims(isl::dim type, unsigned int pos, unsigned int n) const {
+  auto res = isl_basic_set_insert_dims(copy(), static_cast<enum isl_dim_type>(type), pos, n);
+  return manage(res);
+}
+
+isl::basic_set basic_set::intersect(isl::basic_set bset2) const {
+  auto res = isl_basic_set_intersect(copy(), bset2.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::intersect_params(isl::basic_set bset2) const {
+  auto res = isl_basic_set_intersect_params(copy(), bset2.release());
+  return manage(res);
+}
+
+isl::boolean basic_set::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_set_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean basic_set::is_bounded() const {
+  auto res = isl_basic_set_is_bounded(get());
+  return manage(res);
+}
+
+isl::boolean basic_set::is_disjoint(const isl::basic_set &bset2) const {
+  auto res = isl_basic_set_is_disjoint(get(), bset2.get());
+  return manage(res);
+}
+
+isl::boolean basic_set::is_empty() const {
+  auto res = isl_basic_set_is_empty(get());
+  return manage(res);
+}
+
+isl::boolean basic_set::is_equal(const isl::basic_set &bset2) const {
+  auto res = isl_basic_set_is_equal(get(), bset2.get());
+  return manage(res);
+}
+
+int basic_set::is_rational() const {
+  auto res = isl_basic_set_is_rational(get());
+  return res;
+}
+
+isl::boolean basic_set::is_subset(const isl::basic_set &bset2) const {
+  auto res = isl_basic_set_is_subset(get(), bset2.get());
+  return manage(res);
+}
+
+isl::boolean basic_set::is_universe() const {
+  auto res = isl_basic_set_is_universe(get());
+  return manage(res);
+}
+
+isl::boolean basic_set::is_wrapping() const {
+  auto res = isl_basic_set_is_wrapping(get());
+  return manage(res);
+}
+
+isl::set basic_set::lexmax() const {
+  auto res = isl_basic_set_lexmax(copy());
+  return manage(res);
+}
+
+isl::set basic_set::lexmin() const {
+  auto res = isl_basic_set_lexmin(copy());
+  return manage(res);
+}
+
+isl::basic_set basic_set::lower_bound_val(isl::dim type, unsigned int pos, isl::val value) const {
+  auto res = isl_basic_set_lower_bound_val(copy(), static_cast<enum isl_dim_type>(type), pos, value.release());
+  return manage(res);
+}
+
+isl::val basic_set::max_val(const isl::aff &obj) const {
+  auto res = isl_basic_set_max_val(get(), obj.get());
+  return manage(res);
+}
+
+isl::basic_set basic_set::move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const {
+  auto res = isl_basic_set_move_dims(copy(), static_cast<enum isl_dim_type>(dst_type), dst_pos, static_cast<enum isl_dim_type>(src_type), src_pos, n);
+  return manage(res);
+}
+
+isl::basic_set basic_set::nat_universe(isl::space dim) {
+  auto res = isl_basic_set_nat_universe(dim.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::neg() const {
+  auto res = isl_basic_set_neg(copy());
+  return manage(res);
+}
+
+isl::basic_set basic_set::params() const {
+  auto res = isl_basic_set_params(copy());
+  return manage(res);
+}
+
+isl::boolean basic_set::plain_is_empty() const {
+  auto res = isl_basic_set_plain_is_empty(get());
+  return manage(res);
+}
+
+isl::boolean basic_set::plain_is_equal(const isl::basic_set &bset2) const {
+  auto res = isl_basic_set_plain_is_equal(get(), bset2.get());
+  return manage(res);
+}
+
+isl::boolean basic_set::plain_is_universe() const {
+  auto res = isl_basic_set_plain_is_universe(get());
+  return manage(res);
+}
+
+isl::basic_set basic_set::positive_orthant(isl::space space) {
+  auto res = isl_basic_set_positive_orthant(space.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::preimage_multi_aff(isl::multi_aff ma) const {
+  auto res = isl_basic_set_preimage_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::project_out(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_set_project_out(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_set basic_set::remove_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_set_remove_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_set basic_set::remove_divs() const {
+  auto res = isl_basic_set_remove_divs(copy());
+  return manage(res);
+}
+
+isl::basic_set basic_set::remove_divs_involving_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_basic_set_remove_divs_involving_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::basic_set basic_set::remove_redundancies() const {
+  auto res = isl_basic_set_remove_redundancies(copy());
+  return manage(res);
+}
+
+isl::basic_set basic_set::remove_unknown_divs() const {
+  auto res = isl_basic_set_remove_unknown_divs(copy());
+  return manage(res);
+}
+
+isl::basic_set basic_set::sample() const {
+  auto res = isl_basic_set_sample(copy());
+  return manage(res);
+}
+
+isl::point basic_set::sample_point() const {
+  auto res = isl_basic_set_sample_point(copy());
+  return manage(res);
+}
+
+isl::basic_set basic_set::set_tuple_id(isl::id id) const {
+  auto res = isl_basic_set_set_tuple_id(copy(), id.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::set_tuple_name(const std::string &s) const {
+  auto res = isl_basic_set_set_tuple_name(copy(), s.c_str());
+  return manage(res);
+}
+
+isl::basic_set basic_set::solutions() const {
+  auto res = isl_basic_set_solutions(copy());
+  return manage(res);
+}
+
+isl::set basic_set::unite(isl::basic_set bset2) const {
+  auto res = isl_basic_set_union(copy(), bset2.release());
+  return manage(res);
+}
+
+isl::basic_set basic_set::universe(isl::space dim) {
+  auto res = isl_basic_set_universe(dim.release());
+  return manage(res);
+}
+
+isl::basic_map basic_set::unwrap() const {
+  auto res = isl_basic_set_unwrap(copy());
+  return manage(res);
+}
+
+isl::basic_set basic_set::upper_bound_val(isl::dim type, unsigned int pos, isl::val value) const {
+  auto res = isl_basic_set_upper_bound_val(copy(), static_cast<enum isl_dim_type>(type), pos, value.release());
+  return manage(res);
+}
+
+// implementations for isl::basic_set_list
+isl::basic_set_list manage(__isl_take isl_basic_set_list *ptr) {
+  return basic_set_list(ptr);
+}
+isl::basic_set_list give(__isl_take isl_basic_set_list *ptr) {
+  return manage(ptr);
+}
+
+
+basic_set_list::basic_set_list()
+    : ptr(nullptr) {}
+
+basic_set_list::basic_set_list(const isl::basic_set_list &obj)
+    : ptr(obj.copy()) {}
+basic_set_list::basic_set_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+basic_set_list::basic_set_list(__isl_take isl_basic_set_list *ptr)
+    : ptr(ptr) {}
+
+
+basic_set_list &basic_set_list::operator=(isl::basic_set_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+basic_set_list::~basic_set_list() {
+  if (ptr)
+    isl_basic_set_list_free(ptr);
+}
+
+__isl_give isl_basic_set_list *basic_set_list::copy() const & {
+  return isl_basic_set_list_copy(ptr);
+}
+
+__isl_keep isl_basic_set_list *basic_set_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_basic_set_list *basic_set_list::release() {
+  isl_basic_set_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool basic_set_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_basic_set_list *basic_set_list::keep() const {
+  return get();
+}
+
+__isl_give isl_basic_set_list *basic_set_list::take() {
+  return release();
+}
+
+basic_set_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx basic_set_list::get_ctx() const {
+  return isl::ctx(isl_basic_set_list_get_ctx(ptr));
+}
+
+
+
+void basic_set_list::dump() const {
+  isl_basic_set_list_dump(get());
+}
+
+
+
+// implementations for isl::constraint
+isl::constraint manage(__isl_take isl_constraint *ptr) {
+  return constraint(ptr);
+}
+isl::constraint give(__isl_take isl_constraint *ptr) {
+  return manage(ptr);
+}
+
+
+constraint::constraint()
+    : ptr(nullptr) {}
+
+constraint::constraint(const isl::constraint &obj)
+    : ptr(obj.copy()) {}
+constraint::constraint(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+constraint::constraint(__isl_take isl_constraint *ptr)
+    : ptr(ptr) {}
+
+
+constraint &constraint::operator=(isl::constraint obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+constraint::~constraint() {
+  if (ptr)
+    isl_constraint_free(ptr);
+}
+
+__isl_give isl_constraint *constraint::copy() const & {
+  return isl_constraint_copy(ptr);
+}
+
+__isl_keep isl_constraint *constraint::get() const {
+  return ptr;
+}
+
+__isl_give isl_constraint *constraint::release() {
+  isl_constraint *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool constraint::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_constraint *constraint::keep() const {
+  return get();
+}
+
+__isl_give isl_constraint *constraint::take() {
+  return release();
+}
+
+constraint::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx constraint::get_ctx() const {
+  return isl::ctx(isl_constraint_get_ctx(ptr));
+}
+
+
+
+void constraint::dump() const {
+  isl_constraint_dump(get());
+}
+
+
+isl::constraint constraint::alloc_equality(isl::local_space ls) {
+  auto res = isl_constraint_alloc_equality(ls.release());
+  return manage(res);
+}
+
+isl::constraint constraint::alloc_inequality(isl::local_space ls) {
+  auto res = isl_constraint_alloc_inequality(ls.release());
+  return manage(res);
+}
+
+int constraint::cmp_last_non_zero(const isl::constraint &c2) const {
+  auto res = isl_constraint_cmp_last_non_zero(get(), c2.get());
+  return res;
+}
+
+isl::aff constraint::get_aff() const {
+  auto res = isl_constraint_get_aff(get());
+  return manage(res);
+}
+
+isl::aff constraint::get_bound(isl::dim type, int pos) const {
+  auto res = isl_constraint_get_bound(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::val constraint::get_coefficient_val(isl::dim type, int pos) const {
+  auto res = isl_constraint_get_coefficient_val(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::val constraint::get_constant_val() const {
+  auto res = isl_constraint_get_constant_val(get());
+  return manage(res);
+}
+
+std::string constraint::get_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_constraint_get_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::aff constraint::get_div(int pos) const {
+  auto res = isl_constraint_get_div(get(), pos);
+  return manage(res);
+}
+
+isl::local_space constraint::get_local_space() const {
+  auto res = isl_constraint_get_local_space(get());
+  return manage(res);
+}
+
+isl::space constraint::get_space() const {
+  auto res = isl_constraint_get_space(get());
+  return manage(res);
+}
+
+isl::boolean constraint::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_constraint_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+int constraint::is_div_constraint() const {
+  auto res = isl_constraint_is_div_constraint(get());
+  return res;
+}
+
+isl::boolean constraint::is_lower_bound(isl::dim type, unsigned int pos) const {
+  auto res = isl_constraint_is_lower_bound(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean constraint::is_upper_bound(isl::dim type, unsigned int pos) const {
+  auto res = isl_constraint_is_upper_bound(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+int constraint::plain_cmp(const isl::constraint &c2) const {
+  auto res = isl_constraint_plain_cmp(get(), c2.get());
+  return res;
+}
+
+isl::constraint constraint::set_coefficient_si(isl::dim type, int pos, int v) const {
+  auto res = isl_constraint_set_coefficient_si(copy(), static_cast<enum isl_dim_type>(type), pos, v);
+  return manage(res);
+}
+
+isl::constraint constraint::set_coefficient_val(isl::dim type, int pos, isl::val v) const {
+  auto res = isl_constraint_set_coefficient_val(copy(), static_cast<enum isl_dim_type>(type), pos, v.release());
+  return manage(res);
+}
+
+isl::constraint constraint::set_constant_si(int v) const {
+  auto res = isl_constraint_set_constant_si(copy(), v);
+  return manage(res);
+}
+
+isl::constraint constraint::set_constant_val(isl::val v) const {
+  auto res = isl_constraint_set_constant_val(copy(), v.release());
+  return manage(res);
+}
+
+// implementations for isl::constraint_list
+isl::constraint_list manage(__isl_take isl_constraint_list *ptr) {
+  return constraint_list(ptr);
+}
+isl::constraint_list give(__isl_take isl_constraint_list *ptr) {
+  return manage(ptr);
+}
+
+
+constraint_list::constraint_list()
+    : ptr(nullptr) {}
+
+constraint_list::constraint_list(const isl::constraint_list &obj)
+    : ptr(obj.copy()) {}
+constraint_list::constraint_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+constraint_list::constraint_list(__isl_take isl_constraint_list *ptr)
+    : ptr(ptr) {}
+
+
+constraint_list &constraint_list::operator=(isl::constraint_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+constraint_list::~constraint_list() {
+  if (ptr)
+    isl_constraint_list_free(ptr);
+}
+
+__isl_give isl_constraint_list *constraint_list::copy() const & {
+  return isl_constraint_list_copy(ptr);
+}
+
+__isl_keep isl_constraint_list *constraint_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_constraint_list *constraint_list::release() {
+  isl_constraint_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool constraint_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_constraint_list *constraint_list::keep() const {
+  return get();
+}
+
+__isl_give isl_constraint_list *constraint_list::take() {
+  return release();
+}
+
+constraint_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx constraint_list::get_ctx() const {
+  return isl::ctx(isl_constraint_list_get_ctx(ptr));
+}
+
+
+
+void constraint_list::dump() const {
+  isl_constraint_list_dump(get());
+}
+
+
+
+// implementations for isl::id
+isl::id manage(__isl_take isl_id *ptr) {
+  return id(ptr);
+}
+isl::id give(__isl_take isl_id *ptr) {
+  return manage(ptr);
+}
+
+
+id::id()
+    : ptr(nullptr) {}
+
+id::id(const isl::id &obj)
+    : ptr(obj.copy()) {}
+id::id(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+id::id(__isl_take isl_id *ptr)
+    : ptr(ptr) {}
+
+
+id &id::operator=(isl::id obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+id::~id() {
+  if (ptr)
+    isl_id_free(ptr);
+}
+
+__isl_give isl_id *id::copy() const & {
+  return isl_id_copy(ptr);
+}
+
+__isl_keep isl_id *id::get() const {
+  return ptr;
+}
+
+__isl_give isl_id *id::release() {
+  isl_id *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool id::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_id *id::keep() const {
+  return get();
+}
+
+__isl_give isl_id *id::take() {
+  return release();
+}
+
+id::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx id::get_ctx() const {
+  return isl::ctx(isl_id_get_ctx(ptr));
+}
+
+
+std::string id::to_str() const {
+  char *Tmp = isl_id_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void id::dump() const {
+  isl_id_dump(get());
+}
+
+
+isl::id id::alloc(isl::ctx ctx, const std::string &name, void * user) {
+  auto res = isl_id_alloc(ctx.release(), name.c_str(), user);
+  return manage(res);
+}
+
+uint32_t id::get_hash() const {
+  auto res = isl_id_get_hash(get());
+  return res;
+}
+
+std::string id::get_name() const {
+  auto res = isl_id_get_name(get());
+  std::string tmp(res);
+  return tmp;
+}
+
+void * id::get_user() const {
+  auto res = isl_id_get_user(get());
+  return res;
+}
+
+// implementations for isl::id_list
+isl::id_list manage(__isl_take isl_id_list *ptr) {
+  return id_list(ptr);
+}
+isl::id_list give(__isl_take isl_id_list *ptr) {
+  return manage(ptr);
+}
+
+
+id_list::id_list()
+    : ptr(nullptr) {}
+
+id_list::id_list(const isl::id_list &obj)
+    : ptr(obj.copy()) {}
+id_list::id_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+id_list::id_list(__isl_take isl_id_list *ptr)
+    : ptr(ptr) {}
+
+
+id_list &id_list::operator=(isl::id_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+id_list::~id_list() {
+  if (ptr)
+    isl_id_list_free(ptr);
+}
+
+__isl_give isl_id_list *id_list::copy() const & {
+  return isl_id_list_copy(ptr);
+}
+
+__isl_keep isl_id_list *id_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_id_list *id_list::release() {
+  isl_id_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool id_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_id_list *id_list::keep() const {
+  return get();
+}
+
+__isl_give isl_id_list *id_list::take() {
+  return release();
+}
+
+id_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx id_list::get_ctx() const {
+  return isl::ctx(isl_id_list_get_ctx(ptr));
+}
+
+
+
+void id_list::dump() const {
+  isl_id_list_dump(get());
+}
+
+
+
+// implementations for isl::id_to_ast_expr
+isl::id_to_ast_expr manage(__isl_take isl_id_to_ast_expr *ptr) {
+  return id_to_ast_expr(ptr);
+}
+isl::id_to_ast_expr give(__isl_take isl_id_to_ast_expr *ptr) {
+  return manage(ptr);
+}
+
+
+id_to_ast_expr::id_to_ast_expr()
+    : ptr(nullptr) {}
+
+id_to_ast_expr::id_to_ast_expr(const isl::id_to_ast_expr &obj)
+    : ptr(obj.copy()) {}
+id_to_ast_expr::id_to_ast_expr(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+id_to_ast_expr::id_to_ast_expr(__isl_take isl_id_to_ast_expr *ptr)
+    : ptr(ptr) {}
+
+
+id_to_ast_expr &id_to_ast_expr::operator=(isl::id_to_ast_expr obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+id_to_ast_expr::~id_to_ast_expr() {
+  if (ptr)
+    isl_id_to_ast_expr_free(ptr);
+}
+
+__isl_give isl_id_to_ast_expr *id_to_ast_expr::copy() const & {
+  return isl_id_to_ast_expr_copy(ptr);
+}
+
+__isl_keep isl_id_to_ast_expr *id_to_ast_expr::get() const {
+  return ptr;
+}
+
+__isl_give isl_id_to_ast_expr *id_to_ast_expr::release() {
+  isl_id_to_ast_expr *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool id_to_ast_expr::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_id_to_ast_expr *id_to_ast_expr::keep() const {
+  return get();
+}
+
+__isl_give isl_id_to_ast_expr *id_to_ast_expr::take() {
+  return release();
+}
+
+id_to_ast_expr::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx id_to_ast_expr::get_ctx() const {
+  return isl::ctx(isl_id_to_ast_expr_get_ctx(ptr));
+}
+
+
+
+void id_to_ast_expr::dump() const {
+  isl_id_to_ast_expr_dump(get());
+}
+
+
+isl::id_to_ast_expr id_to_ast_expr::alloc(isl::ctx ctx, int min_size) {
+  auto res = isl_id_to_ast_expr_alloc(ctx.release(), min_size);
+  return manage(res);
+}
+
+isl::id_to_ast_expr id_to_ast_expr::drop(isl::id key) const {
+  auto res = isl_id_to_ast_expr_drop(copy(), key.release());
+  return manage(res);
+}
+
+isl::stat id_to_ast_expr::foreach(const std::function<isl::stat(isl::id, isl::ast_expr)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_id *arg_0, isl_ast_expr *arg_1, void *arg_2) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::id, isl::ast_expr)> **>(arg_2);
+    stat ret = (*func)(isl::manage(arg_0), isl::manage(arg_1));
+    return isl_stat(ret);
+  };
+  auto res = isl_id_to_ast_expr_foreach(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::ast_expr id_to_ast_expr::get(isl::id key) const {
+  auto res = isl_id_to_ast_expr_get(get(), key.release());
+  return manage(res);
+}
+
+isl::boolean id_to_ast_expr::has(const isl::id &key) const {
+  auto res = isl_id_to_ast_expr_has(get(), key.get());
+  return manage(res);
+}
+
+isl::id_to_ast_expr id_to_ast_expr::set(isl::id key, isl::ast_expr val) const {
+  auto res = isl_id_to_ast_expr_set(copy(), key.release(), val.release());
+  return manage(res);
+}
+
+// implementations for isl::local_space
+isl::local_space manage(__isl_take isl_local_space *ptr) {
+  return local_space(ptr);
+}
+isl::local_space give(__isl_take isl_local_space *ptr) {
+  return manage(ptr);
+}
+
+
+local_space::local_space()
+    : ptr(nullptr) {}
+
+local_space::local_space(const isl::local_space &obj)
+    : ptr(obj.copy()) {}
+local_space::local_space(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+local_space::local_space(__isl_take isl_local_space *ptr)
+    : ptr(ptr) {}
+
+local_space::local_space(isl::space dim) {
+  auto res = isl_local_space_from_space(dim.release());
+  ptr = res;
+}
+
+local_space &local_space::operator=(isl::local_space obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+local_space::~local_space() {
+  if (ptr)
+    isl_local_space_free(ptr);
+}
+
+__isl_give isl_local_space *local_space::copy() const & {
+  return isl_local_space_copy(ptr);
+}
+
+__isl_keep isl_local_space *local_space::get() const {
+  return ptr;
+}
+
+__isl_give isl_local_space *local_space::release() {
+  isl_local_space *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool local_space::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_local_space *local_space::keep() const {
+  return get();
+}
+
+__isl_give isl_local_space *local_space::take() {
+  return release();
+}
+
+local_space::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx local_space::get_ctx() const {
+  return isl::ctx(isl_local_space_get_ctx(ptr));
+}
+
+
+
+void local_space::dump() const {
+  isl_local_space_dump(get());
+}
+
+
+isl::local_space local_space::add_dims(isl::dim type, unsigned int n) const {
+  auto res = isl_local_space_add_dims(copy(), static_cast<enum isl_dim_type>(type), n);
+  return manage(res);
+}
+
+int local_space::dim(isl::dim type) const {
+  auto res = isl_local_space_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::local_space local_space::domain() const {
+  auto res = isl_local_space_domain(copy());
+  return manage(res);
+}
+
+isl::local_space local_space::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_local_space_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+int local_space::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_local_space_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::local_space local_space::flatten_domain() const {
+  auto res = isl_local_space_flatten_domain(copy());
+  return manage(res);
+}
+
+isl::local_space local_space::flatten_range() const {
+  auto res = isl_local_space_flatten_range(copy());
+  return manage(res);
+}
+
+isl::local_space local_space::from_domain() const {
+  auto res = isl_local_space_from_domain(copy());
+  return manage(res);
+}
+
+isl::id local_space::get_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_local_space_get_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+std::string local_space::get_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_local_space_get_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::aff local_space::get_div(int pos) const {
+  auto res = isl_local_space_get_div(get(), pos);
+  return manage(res);
+}
+
+isl::space local_space::get_space() const {
+  auto res = isl_local_space_get_space(get());
+  return manage(res);
+}
+
+isl::boolean local_space::has_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_local_space_has_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean local_space::has_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_local_space_has_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::local_space local_space::insert_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_local_space_insert_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::local_space local_space::intersect(isl::local_space ls2) const {
+  auto res = isl_local_space_intersect(copy(), ls2.release());
+  return manage(res);
+}
+
+isl::boolean local_space::is_equal(const isl::local_space &ls2) const {
+  auto res = isl_local_space_is_equal(get(), ls2.get());
+  return manage(res);
+}
+
+isl::boolean local_space::is_params() const {
+  auto res = isl_local_space_is_params(get());
+  return manage(res);
+}
+
+isl::boolean local_space::is_set() const {
+  auto res = isl_local_space_is_set(get());
+  return manage(res);
+}
+
+isl::local_space local_space::range() const {
+  auto res = isl_local_space_range(copy());
+  return manage(res);
+}
+
+isl::local_space local_space::set_dim_id(isl::dim type, unsigned int pos, isl::id id) const {
+  auto res = isl_local_space_set_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos, id.release());
+  return manage(res);
+}
+
+isl::local_space local_space::set_tuple_id(isl::dim type, isl::id id) const {
+  auto res = isl_local_space_set_tuple_id(copy(), static_cast<enum isl_dim_type>(type), id.release());
+  return manage(res);
+}
+
+isl::local_space local_space::wrap() const {
+  auto res = isl_local_space_wrap(copy());
+  return manage(res);
+}
+
+// implementations for isl::map
+isl::map manage(__isl_take isl_map *ptr) {
+  return map(ptr);
+}
+isl::map give(__isl_take isl_map *ptr) {
+  return manage(ptr);
+}
+
+
+map::map()
+    : ptr(nullptr) {}
+
+map::map(const isl::map &obj)
+    : ptr(obj.copy()) {}
+map::map(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+map::map(__isl_take isl_map *ptr)
+    : ptr(ptr) {}
+
+map::map(isl::ctx ctx, const std::string &str) {
+  auto res = isl_map_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+map::map(isl::basic_map bmap) {
+  auto res = isl_map_from_basic_map(bmap.release());
+  ptr = res;
+}
+
+map &map::operator=(isl::map obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+map::~map() {
+  if (ptr)
+    isl_map_free(ptr);
+}
+
+__isl_give isl_map *map::copy() const & {
+  return isl_map_copy(ptr);
+}
+
+__isl_keep isl_map *map::get() const {
+  return ptr;
+}
+
+__isl_give isl_map *map::release() {
+  isl_map *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool map::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_map *map::keep() const {
+  return get();
+}
+
+__isl_give isl_map *map::take() {
+  return release();
+}
+
+map::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx map::get_ctx() const {
+  return isl::ctx(isl_map_get_ctx(ptr));
+}
+
+
+std::string map::to_str() const {
+  char *Tmp = isl_map_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void map::dump() const {
+  isl_map_dump(get());
+}
+
+
+isl::map map::add_constraint(isl::constraint constraint) const {
+  auto res = isl_map_add_constraint(copy(), constraint.release());
+  return manage(res);
+}
+
+isl::map map::add_dims(isl::dim type, unsigned int n) const {
+  auto res = isl_map_add_dims(copy(), static_cast<enum isl_dim_type>(type), n);
+  return manage(res);
+}
+
+isl::basic_map map::affine_hull() const {
+  auto res = isl_map_affine_hull(copy());
+  return manage(res);
+}
+
+isl::map map::align_params(isl::space model) const {
+  auto res = isl_map_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::map map::apply_domain(isl::map map2) const {
+  auto res = isl_map_apply_domain(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::apply_range(isl::map map2) const {
+  auto res = isl_map_apply_range(copy(), map2.release());
+  return manage(res);
+}
+
+isl::boolean map::can_curry() const {
+  auto res = isl_map_can_curry(get());
+  return manage(res);
+}
+
+isl::boolean map::can_range_curry() const {
+  auto res = isl_map_can_range_curry(get());
+  return manage(res);
+}
+
+isl::boolean map::can_uncurry() const {
+  auto res = isl_map_can_uncurry(get());
+  return manage(res);
+}
+
+isl::boolean map::can_zip() const {
+  auto res = isl_map_can_zip(get());
+  return manage(res);
+}
+
+isl::map map::coalesce() const {
+  auto res = isl_map_coalesce(copy());
+  return manage(res);
+}
+
+isl::map map::complement() const {
+  auto res = isl_map_complement(copy());
+  return manage(res);
+}
+
+isl::basic_map map::convex_hull() const {
+  auto res = isl_map_convex_hull(copy());
+  return manage(res);
+}
+
+isl::map map::curry() const {
+  auto res = isl_map_curry(copy());
+  return manage(res);
+}
+
+isl::set map::deltas() const {
+  auto res = isl_map_deltas(copy());
+  return manage(res);
+}
+
+isl::map map::deltas_map() const {
+  auto res = isl_map_deltas_map(copy());
+  return manage(res);
+}
+
+isl::map map::detect_equalities() const {
+  auto res = isl_map_detect_equalities(copy());
+  return manage(res);
+}
+
+unsigned int map::dim(isl::dim type) const {
+  auto res = isl_map_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::pw_aff map::dim_max(int pos) const {
+  auto res = isl_map_dim_max(copy(), pos);
+  return manage(res);
+}
+
+isl::pw_aff map::dim_min(int pos) const {
+  auto res = isl_map_dim_min(copy(), pos);
+  return manage(res);
+}
+
+isl::set map::domain() const {
+  auto res = isl_map_domain(copy());
+  return manage(res);
+}
+
+isl::map map::domain_factor_domain() const {
+  auto res = isl_map_domain_factor_domain(copy());
+  return manage(res);
+}
+
+isl::map map::domain_factor_range() const {
+  auto res = isl_map_domain_factor_range(copy());
+  return manage(res);
+}
+
+isl::boolean map::domain_is_wrapping() const {
+  auto res = isl_map_domain_is_wrapping(get());
+  return manage(res);
+}
+
+isl::map map::domain_map() const {
+  auto res = isl_map_domain_map(copy());
+  return manage(res);
+}
+
+isl::map map::domain_product(isl::map map2) const {
+  auto res = isl_map_domain_product(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::drop_constraints_involving_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_map_drop_constraints_involving_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::map map::drop_constraints_not_involving_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_map_drop_constraints_not_involving_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::map map::eliminate(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_map_eliminate(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::map map::empty(isl::space dim) {
+  auto res = isl_map_empty(dim.release());
+  return manage(res);
+}
+
+isl::map map::equate(isl::dim type1, int pos1, isl::dim type2, int pos2) const {
+  auto res = isl_map_equate(copy(), static_cast<enum isl_dim_type>(type1), pos1, static_cast<enum isl_dim_type>(type2), pos2);
+  return manage(res);
+}
+
+isl::map map::factor_domain() const {
+  auto res = isl_map_factor_domain(copy());
+  return manage(res);
+}
+
+isl::map map::factor_range() const {
+  auto res = isl_map_factor_range(copy());
+  return manage(res);
+}
+
+int map::find_dim_by_id(isl::dim type, const isl::id &id) const {
+  auto res = isl_map_find_dim_by_id(get(), static_cast<enum isl_dim_type>(type), id.get());
+  return res;
+}
+
+int map::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_map_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::map map::fix_si(isl::dim type, unsigned int pos, int value) const {
+  auto res = isl_map_fix_si(copy(), static_cast<enum isl_dim_type>(type), pos, value);
+  return manage(res);
+}
+
+isl::map map::fix_val(isl::dim type, unsigned int pos, isl::val v) const {
+  auto res = isl_map_fix_val(copy(), static_cast<enum isl_dim_type>(type), pos, v.release());
+  return manage(res);
+}
+
+isl::map map::fixed_power_val(isl::val exp) const {
+  auto res = isl_map_fixed_power_val(copy(), exp.release());
+  return manage(res);
+}
+
+isl::map map::flat_domain_product(isl::map map2) const {
+  auto res = isl_map_flat_domain_product(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::flat_product(isl::map map2) const {
+  auto res = isl_map_flat_product(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::flat_range_product(isl::map map2) const {
+  auto res = isl_map_flat_range_product(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::flatten() const {
+  auto res = isl_map_flatten(copy());
+  return manage(res);
+}
+
+isl::map map::flatten_domain() const {
+  auto res = isl_map_flatten_domain(copy());
+  return manage(res);
+}
+
+isl::map map::flatten_range() const {
+  auto res = isl_map_flatten_range(copy());
+  return manage(res);
+}
+
+isl::map map::floordiv_val(isl::val d) const {
+  auto res = isl_map_floordiv_val(copy(), d.release());
+  return manage(res);
+}
+
+isl::stat map::foreach_basic_map(const std::function<isl::stat(isl::basic_map)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_basic_map *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::basic_map)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_map_foreach_basic_map(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::map map::from_aff(isl::aff aff) {
+  auto res = isl_map_from_aff(aff.release());
+  return manage(res);
+}
+
+isl::map map::from_domain(isl::set set) {
+  auto res = isl_map_from_domain(set.release());
+  return manage(res);
+}
+
+isl::map map::from_domain_and_range(isl::set domain, isl::set range) {
+  auto res = isl_map_from_domain_and_range(domain.release(), range.release());
+  return manage(res);
+}
+
+isl::map map::from_multi_aff(isl::multi_aff maff) {
+  auto res = isl_map_from_multi_aff(maff.release());
+  return manage(res);
+}
+
+isl::map map::from_multi_pw_aff(isl::multi_pw_aff mpa) {
+  auto res = isl_map_from_multi_pw_aff(mpa.release());
+  return manage(res);
+}
+
+isl::map map::from_pw_aff(isl::pw_aff pwaff) {
+  auto res = isl_map_from_pw_aff(pwaff.release());
+  return manage(res);
+}
+
+isl::map map::from_pw_multi_aff(isl::pw_multi_aff pma) {
+  auto res = isl_map_from_pw_multi_aff(pma.release());
+  return manage(res);
+}
+
+isl::map map::from_range(isl::set set) {
+  auto res = isl_map_from_range(set.release());
+  return manage(res);
+}
+
+isl::map map::from_union_map(isl::union_map umap) {
+  auto res = isl_map_from_union_map(umap.release());
+  return manage(res);
+}
+
+isl::id map::get_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_map_get_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+std::string map::get_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_map_get_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  std::string tmp(res);
+  return tmp;
+}
+
+uint32_t map::get_hash() const {
+  auto res = isl_map_get_hash(get());
+  return res;
+}
+
+isl::space map::get_space() const {
+  auto res = isl_map_get_space(get());
+  return manage(res);
+}
+
+isl::id map::get_tuple_id(isl::dim type) const {
+  auto res = isl_map_get_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+std::string map::get_tuple_name(isl::dim type) const {
+  auto res = isl_map_get_tuple_name(get(), static_cast<enum isl_dim_type>(type));
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::map map::gist(isl::map context) const {
+  auto res = isl_map_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::map map::gist_basic_map(isl::basic_map context) const {
+  auto res = isl_map_gist_basic_map(copy(), context.release());
+  return manage(res);
+}
+
+isl::map map::gist_domain(isl::set context) const {
+  auto res = isl_map_gist_domain(copy(), context.release());
+  return manage(res);
+}
+
+isl::map map::gist_params(isl::set context) const {
+  auto res = isl_map_gist_params(copy(), context.release());
+  return manage(res);
+}
+
+isl::map map::gist_range(isl::set context) const {
+  auto res = isl_map_gist_range(copy(), context.release());
+  return manage(res);
+}
+
+isl::boolean map::has_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_map_has_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean map::has_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_map_has_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean map::has_equal_space(const isl::map &map2) const {
+  auto res = isl_map_has_equal_space(get(), map2.get());
+  return manage(res);
+}
+
+isl::boolean map::has_tuple_id(isl::dim type) const {
+  auto res = isl_map_has_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::boolean map::has_tuple_name(isl::dim type) const {
+  auto res = isl_map_has_tuple_name(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::map map::identity(isl::space dim) {
+  auto res = isl_map_identity(dim.release());
+  return manage(res);
+}
+
+isl::map map::insert_dims(isl::dim type, unsigned int pos, unsigned int n) const {
+  auto res = isl_map_insert_dims(copy(), static_cast<enum isl_dim_type>(type), pos, n);
+  return manage(res);
+}
+
+isl::map map::intersect(isl::map map2) const {
+  auto res = isl_map_intersect(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::intersect_domain(isl::set set) const {
+  auto res = isl_map_intersect_domain(copy(), set.release());
+  return manage(res);
+}
+
+isl::map map::intersect_domain_factor_range(isl::map factor) const {
+  auto res = isl_map_intersect_domain_factor_range(copy(), factor.release());
+  return manage(res);
+}
+
+isl::map map::intersect_params(isl::set params) const {
+  auto res = isl_map_intersect_params(copy(), params.release());
+  return manage(res);
+}
+
+isl::map map::intersect_range(isl::set set) const {
+  auto res = isl_map_intersect_range(copy(), set.release());
+  return manage(res);
+}
+
+isl::map map::intersect_range_factor_range(isl::map factor) const {
+  auto res = isl_map_intersect_range_factor_range(copy(), factor.release());
+  return manage(res);
+}
+
+isl::boolean map::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_map_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean map::is_bijective() const {
+  auto res = isl_map_is_bijective(get());
+  return manage(res);
+}
+
+isl::boolean map::is_disjoint(const isl::map &map2) const {
+  auto res = isl_map_is_disjoint(get(), map2.get());
+  return manage(res);
+}
+
+isl::boolean map::is_empty() const {
+  auto res = isl_map_is_empty(get());
+  return manage(res);
+}
+
+isl::boolean map::is_equal(const isl::map &map2) const {
+  auto res = isl_map_is_equal(get(), map2.get());
+  return manage(res);
+}
+
+isl::boolean map::is_identity() const {
+  auto res = isl_map_is_identity(get());
+  return manage(res);
+}
+
+isl::boolean map::is_injective() const {
+  auto res = isl_map_is_injective(get());
+  return manage(res);
+}
+
+isl::boolean map::is_product() const {
+  auto res = isl_map_is_product(get());
+  return manage(res);
+}
+
+isl::boolean map::is_single_valued() const {
+  auto res = isl_map_is_single_valued(get());
+  return manage(res);
+}
+
+isl::boolean map::is_strict_subset(const isl::map &map2) const {
+  auto res = isl_map_is_strict_subset(get(), map2.get());
+  return manage(res);
+}
+
+isl::boolean map::is_subset(const isl::map &map2) const {
+  auto res = isl_map_is_subset(get(), map2.get());
+  return manage(res);
+}
+
+int map::is_translation() const {
+  auto res = isl_map_is_translation(get());
+  return res;
+}
+
+isl::map map::lex_ge(isl::space set_dim) {
+  auto res = isl_map_lex_ge(set_dim.release());
+  return manage(res);
+}
+
+isl::map map::lex_ge_first(isl::space dim, unsigned int n) {
+  auto res = isl_map_lex_ge_first(dim.release(), n);
+  return manage(res);
+}
+
+isl::map map::lex_ge_map(isl::map map2) const {
+  auto res = isl_map_lex_ge_map(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::lex_gt(isl::space set_dim) {
+  auto res = isl_map_lex_gt(set_dim.release());
+  return manage(res);
+}
+
+isl::map map::lex_gt_first(isl::space dim, unsigned int n) {
+  auto res = isl_map_lex_gt_first(dim.release(), n);
+  return manage(res);
+}
+
+isl::map map::lex_gt_map(isl::map map2) const {
+  auto res = isl_map_lex_gt_map(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::lex_le(isl::space set_dim) {
+  auto res = isl_map_lex_le(set_dim.release());
+  return manage(res);
+}
+
+isl::map map::lex_le_first(isl::space dim, unsigned int n) {
+  auto res = isl_map_lex_le_first(dim.release(), n);
+  return manage(res);
+}
+
+isl::map map::lex_le_map(isl::map map2) const {
+  auto res = isl_map_lex_le_map(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::lex_lt(isl::space set_dim) {
+  auto res = isl_map_lex_lt(set_dim.release());
+  return manage(res);
+}
+
+isl::map map::lex_lt_first(isl::space dim, unsigned int n) {
+  auto res = isl_map_lex_lt_first(dim.release(), n);
+  return manage(res);
+}
+
+isl::map map::lex_lt_map(isl::map map2) const {
+  auto res = isl_map_lex_lt_map(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::lexmax() const {
+  auto res = isl_map_lexmax(copy());
+  return manage(res);
+}
+
+isl::pw_multi_aff map::lexmax_pw_multi_aff() const {
+  auto res = isl_map_lexmax_pw_multi_aff(copy());
+  return manage(res);
+}
+
+isl::map map::lexmin() const {
+  auto res = isl_map_lexmin(copy());
+  return manage(res);
+}
+
+isl::pw_multi_aff map::lexmin_pw_multi_aff() const {
+  auto res = isl_map_lexmin_pw_multi_aff(copy());
+  return manage(res);
+}
+
+isl::map map::lower_bound_si(isl::dim type, unsigned int pos, int value) const {
+  auto res = isl_map_lower_bound_si(copy(), static_cast<enum isl_dim_type>(type), pos, value);
+  return manage(res);
+}
+
+isl::map map::move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const {
+  auto res = isl_map_move_dims(copy(), static_cast<enum isl_dim_type>(dst_type), dst_pos, static_cast<enum isl_dim_type>(src_type), src_pos, n);
+  return manage(res);
+}
+
+isl::map map::nat_universe(isl::space dim) {
+  auto res = isl_map_nat_universe(dim.release());
+  return manage(res);
+}
+
+isl::map map::neg() const {
+  auto res = isl_map_neg(copy());
+  return manage(res);
+}
+
+isl::map map::oppose(isl::dim type1, int pos1, isl::dim type2, int pos2) const {
+  auto res = isl_map_oppose(copy(), static_cast<enum isl_dim_type>(type1), pos1, static_cast<enum isl_dim_type>(type2), pos2);
+  return manage(res);
+}
+
+isl::map map::order_ge(isl::dim type1, int pos1, isl::dim type2, int pos2) const {
+  auto res = isl_map_order_ge(copy(), static_cast<enum isl_dim_type>(type1), pos1, static_cast<enum isl_dim_type>(type2), pos2);
+  return manage(res);
+}
+
+isl::map map::order_gt(isl::dim type1, int pos1, isl::dim type2, int pos2) const {
+  auto res = isl_map_order_gt(copy(), static_cast<enum isl_dim_type>(type1), pos1, static_cast<enum isl_dim_type>(type2), pos2);
+  return manage(res);
+}
+
+isl::map map::order_le(isl::dim type1, int pos1, isl::dim type2, int pos2) const {
+  auto res = isl_map_order_le(copy(), static_cast<enum isl_dim_type>(type1), pos1, static_cast<enum isl_dim_type>(type2), pos2);
+  return manage(res);
+}
+
+isl::map map::order_lt(isl::dim type1, int pos1, isl::dim type2, int pos2) const {
+  auto res = isl_map_order_lt(copy(), static_cast<enum isl_dim_type>(type1), pos1, static_cast<enum isl_dim_type>(type2), pos2);
+  return manage(res);
+}
+
+isl::set map::params() const {
+  auto res = isl_map_params(copy());
+  return manage(res);
+}
+
+isl::val map::plain_get_val_if_fixed(isl::dim type, unsigned int pos) const {
+  auto res = isl_map_plain_get_val_if_fixed(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean map::plain_is_empty() const {
+  auto res = isl_map_plain_is_empty(get());
+  return manage(res);
+}
+
+isl::boolean map::plain_is_equal(const isl::map &map2) const {
+  auto res = isl_map_plain_is_equal(get(), map2.get());
+  return manage(res);
+}
+
+isl::boolean map::plain_is_injective() const {
+  auto res = isl_map_plain_is_injective(get());
+  return manage(res);
+}
+
+isl::boolean map::plain_is_single_valued() const {
+  auto res = isl_map_plain_is_single_valued(get());
+  return manage(res);
+}
+
+isl::boolean map::plain_is_universe() const {
+  auto res = isl_map_plain_is_universe(get());
+  return manage(res);
+}
+
+isl::basic_map map::plain_unshifted_simple_hull() const {
+  auto res = isl_map_plain_unshifted_simple_hull(copy());
+  return manage(res);
+}
+
+isl::basic_map map::polyhedral_hull() const {
+  auto res = isl_map_polyhedral_hull(copy());
+  return manage(res);
+}
+
+isl::map map::preimage_domain_multi_aff(isl::multi_aff ma) const {
+  auto res = isl_map_preimage_domain_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::map map::preimage_domain_multi_pw_aff(isl::multi_pw_aff mpa) const {
+  auto res = isl_map_preimage_domain_multi_pw_aff(copy(), mpa.release());
+  return manage(res);
+}
+
+isl::map map::preimage_domain_pw_multi_aff(isl::pw_multi_aff pma) const {
+  auto res = isl_map_preimage_domain_pw_multi_aff(copy(), pma.release());
+  return manage(res);
+}
+
+isl::map map::preimage_range_multi_aff(isl::multi_aff ma) const {
+  auto res = isl_map_preimage_range_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::map map::preimage_range_pw_multi_aff(isl::pw_multi_aff pma) const {
+  auto res = isl_map_preimage_range_pw_multi_aff(copy(), pma.release());
+  return manage(res);
+}
+
+isl::map map::product(isl::map map2) const {
+  auto res = isl_map_product(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::project_out(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_map_project_out(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::set map::range() const {
+  auto res = isl_map_range(copy());
+  return manage(res);
+}
+
+isl::map map::range_curry() const {
+  auto res = isl_map_range_curry(copy());
+  return manage(res);
+}
+
+isl::map map::range_factor_domain() const {
+  auto res = isl_map_range_factor_domain(copy());
+  return manage(res);
+}
+
+isl::map map::range_factor_range() const {
+  auto res = isl_map_range_factor_range(copy());
+  return manage(res);
+}
+
+isl::boolean map::range_is_wrapping() const {
+  auto res = isl_map_range_is_wrapping(get());
+  return manage(res);
+}
+
+isl::map map::range_map() const {
+  auto res = isl_map_range_map(copy());
+  return manage(res);
+}
+
+isl::map map::range_product(isl::map map2) const {
+  auto res = isl_map_range_product(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::remove_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_map_remove_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::map map::remove_divs() const {
+  auto res = isl_map_remove_divs(copy());
+  return manage(res);
+}
+
+isl::map map::remove_divs_involving_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_map_remove_divs_involving_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::map map::remove_redundancies() const {
+  auto res = isl_map_remove_redundancies(copy());
+  return manage(res);
+}
+
+isl::map map::remove_unknown_divs() const {
+  auto res = isl_map_remove_unknown_divs(copy());
+  return manage(res);
+}
+
+isl::map map::reset_tuple_id(isl::dim type) const {
+  auto res = isl_map_reset_tuple_id(copy(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::map map::reset_user() const {
+  auto res = isl_map_reset_user(copy());
+  return manage(res);
+}
+
+isl::map map::reverse() const {
+  auto res = isl_map_reverse(copy());
+  return manage(res);
+}
+
+isl::basic_map map::sample() const {
+  auto res = isl_map_sample(copy());
+  return manage(res);
+}
+
+isl::map map::set_dim_id(isl::dim type, unsigned int pos, isl::id id) const {
+  auto res = isl_map_set_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos, id.release());
+  return manage(res);
+}
+
+isl::map map::set_tuple_id(isl::dim type, isl::id id) const {
+  auto res = isl_map_set_tuple_id(copy(), static_cast<enum isl_dim_type>(type), id.release());
+  return manage(res);
+}
+
+isl::map map::set_tuple_name(isl::dim type, const std::string &s) const {
+  auto res = isl_map_set_tuple_name(copy(), static_cast<enum isl_dim_type>(type), s.c_str());
+  return manage(res);
+}
+
+isl::basic_map map::simple_hull() const {
+  auto res = isl_map_simple_hull(copy());
+  return manage(res);
+}
+
+isl::map map::subtract(isl::map map2) const {
+  auto res = isl_map_subtract(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::subtract_domain(isl::set dom) const {
+  auto res = isl_map_subtract_domain(copy(), dom.release());
+  return manage(res);
+}
+
+isl::map map::subtract_range(isl::set dom) const {
+  auto res = isl_map_subtract_range(copy(), dom.release());
+  return manage(res);
+}
+
+isl::map map::sum(isl::map map2) const {
+  auto res = isl_map_sum(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::uncurry() const {
+  auto res = isl_map_uncurry(copy());
+  return manage(res);
+}
+
+isl::map map::unite(isl::map map2) const {
+  auto res = isl_map_union(copy(), map2.release());
+  return manage(res);
+}
+
+isl::map map::universe(isl::space dim) {
+  auto res = isl_map_universe(dim.release());
+  return manage(res);
+}
+
+isl::basic_map map::unshifted_simple_hull() const {
+  auto res = isl_map_unshifted_simple_hull(copy());
+  return manage(res);
+}
+
+isl::basic_map map::unshifted_simple_hull_from_map_list(isl::map_list list) const {
+  auto res = isl_map_unshifted_simple_hull_from_map_list(copy(), list.release());
+  return manage(res);
+}
+
+isl::map map::upper_bound_si(isl::dim type, unsigned int pos, int value) const {
+  auto res = isl_map_upper_bound_si(copy(), static_cast<enum isl_dim_type>(type), pos, value);
+  return manage(res);
+}
+
+isl::set map::wrap() const {
+  auto res = isl_map_wrap(copy());
+  return manage(res);
+}
+
+isl::map map::zip() const {
+  auto res = isl_map_zip(copy());
+  return manage(res);
+}
+
+// implementations for isl::map_list
+isl::map_list manage(__isl_take isl_map_list *ptr) {
+  return map_list(ptr);
+}
+isl::map_list give(__isl_take isl_map_list *ptr) {
+  return manage(ptr);
+}
+
+
+map_list::map_list()
+    : ptr(nullptr) {}
+
+map_list::map_list(const isl::map_list &obj)
+    : ptr(obj.copy()) {}
+map_list::map_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+map_list::map_list(__isl_take isl_map_list *ptr)
+    : ptr(ptr) {}
+
+
+map_list &map_list::operator=(isl::map_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+map_list::~map_list() {
+  if (ptr)
+    isl_map_list_free(ptr);
+}
+
+__isl_give isl_map_list *map_list::copy() const & {
+  return isl_map_list_copy(ptr);
+}
+
+__isl_keep isl_map_list *map_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_map_list *map_list::release() {
+  isl_map_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool map_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_map_list *map_list::keep() const {
+  return get();
+}
+
+__isl_give isl_map_list *map_list::take() {
+  return release();
+}
+
+map_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx map_list::get_ctx() const {
+  return isl::ctx(isl_map_list_get_ctx(ptr));
+}
+
+
+
+void map_list::dump() const {
+  isl_map_list_dump(get());
+}
+
+
+
+// implementations for isl::multi_aff
+isl::multi_aff manage(__isl_take isl_multi_aff *ptr) {
+  return multi_aff(ptr);
+}
+isl::multi_aff give(__isl_take isl_multi_aff *ptr) {
+  return manage(ptr);
+}
+
+
+multi_aff::multi_aff()
+    : ptr(nullptr) {}
+
+multi_aff::multi_aff(const isl::multi_aff &obj)
+    : ptr(obj.copy()) {}
+multi_aff::multi_aff(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+multi_aff::multi_aff(__isl_take isl_multi_aff *ptr)
+    : ptr(ptr) {}
+
+multi_aff::multi_aff(isl::ctx ctx, const std::string &str) {
+  auto res = isl_multi_aff_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+multi_aff::multi_aff(isl::aff aff) {
+  auto res = isl_multi_aff_from_aff(aff.release());
+  ptr = res;
+}
+
+multi_aff &multi_aff::operator=(isl::multi_aff obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+multi_aff::~multi_aff() {
+  if (ptr)
+    isl_multi_aff_free(ptr);
+}
+
+__isl_give isl_multi_aff *multi_aff::copy() const & {
+  return isl_multi_aff_copy(ptr);
+}
+
+__isl_keep isl_multi_aff *multi_aff::get() const {
+  return ptr;
+}
+
+__isl_give isl_multi_aff *multi_aff::release() {
+  isl_multi_aff *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool multi_aff::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_multi_aff *multi_aff::keep() const {
+  return get();
+}
+
+__isl_give isl_multi_aff *multi_aff::take() {
+  return release();
+}
+
+multi_aff::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx multi_aff::get_ctx() const {
+  return isl::ctx(isl_multi_aff_get_ctx(ptr));
+}
+
+
+std::string multi_aff::to_str() const {
+  char *Tmp = isl_multi_aff_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void multi_aff::dump() const {
+  isl_multi_aff_dump(get());
+}
+
+
+isl::multi_aff multi_aff::add(isl::multi_aff multi2) const {
+  auto res = isl_multi_aff_add(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::add_dims(isl::dim type, unsigned int n) const {
+  auto res = isl_multi_aff_add_dims(copy(), static_cast<enum isl_dim_type>(type), n);
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::align_params(isl::space model) const {
+  auto res = isl_multi_aff_align_params(copy(), model.release());
+  return manage(res);
+}
+
+unsigned int multi_aff::dim(isl::dim type) const {
+  auto res = isl_multi_aff_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::multi_aff multi_aff::domain_map(isl::space space) {
+  auto res = isl_multi_aff_domain_map(space.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_multi_aff_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::factor_range() const {
+  auto res = isl_multi_aff_factor_range(copy());
+  return manage(res);
+}
+
+int multi_aff::find_dim_by_id(isl::dim type, const isl::id &id) const {
+  auto res = isl_multi_aff_find_dim_by_id(get(), static_cast<enum isl_dim_type>(type), id.get());
+  return res;
+}
+
+int multi_aff::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_multi_aff_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::multi_aff multi_aff::flat_range_product(isl::multi_aff multi2) const {
+  auto res = isl_multi_aff_flat_range_product(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::flatten_domain() const {
+  auto res = isl_multi_aff_flatten_domain(copy());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::flatten_range() const {
+  auto res = isl_multi_aff_flatten_range(copy());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::floor() const {
+  auto res = isl_multi_aff_floor(copy());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::from_aff_list(isl::space space, isl::aff_list list) {
+  auto res = isl_multi_aff_from_aff_list(space.release(), list.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::from_range() const {
+  auto res = isl_multi_aff_from_range(copy());
+  return manage(res);
+}
+
+isl::aff multi_aff::get_aff(int pos) const {
+  auto res = isl_multi_aff_get_aff(get(), pos);
+  return manage(res);
+}
+
+isl::id multi_aff::get_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_multi_aff_get_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::space multi_aff::get_domain_space() const {
+  auto res = isl_multi_aff_get_domain_space(get());
+  return manage(res);
+}
+
+isl::space multi_aff::get_space() const {
+  auto res = isl_multi_aff_get_space(get());
+  return manage(res);
+}
+
+isl::id multi_aff::get_tuple_id(isl::dim type) const {
+  auto res = isl_multi_aff_get_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+std::string multi_aff::get_tuple_name(isl::dim type) const {
+  auto res = isl_multi_aff_get_tuple_name(get(), static_cast<enum isl_dim_type>(type));
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::multi_aff multi_aff::gist(isl::set context) const {
+  auto res = isl_multi_aff_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::gist_params(isl::set context) const {
+  auto res = isl_multi_aff_gist_params(copy(), context.release());
+  return manage(res);
+}
+
+isl::boolean multi_aff::has_tuple_id(isl::dim type) const {
+  auto res = isl_multi_aff_has_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::identity(isl::space space) {
+  auto res = isl_multi_aff_identity(space.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::insert_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_multi_aff_insert_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean multi_aff::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_multi_aff_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean multi_aff::involves_nan() const {
+  auto res = isl_multi_aff_involves_nan(get());
+  return manage(res);
+}
+
+isl::set multi_aff::lex_ge_set(isl::multi_aff ma2) const {
+  auto res = isl_multi_aff_lex_ge_set(copy(), ma2.release());
+  return manage(res);
+}
+
+isl::set multi_aff::lex_gt_set(isl::multi_aff ma2) const {
+  auto res = isl_multi_aff_lex_gt_set(copy(), ma2.release());
+  return manage(res);
+}
+
+isl::set multi_aff::lex_le_set(isl::multi_aff ma2) const {
+  auto res = isl_multi_aff_lex_le_set(copy(), ma2.release());
+  return manage(res);
+}
+
+isl::set multi_aff::lex_lt_set(isl::multi_aff ma2) const {
+  auto res = isl_multi_aff_lex_lt_set(copy(), ma2.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::mod_multi_val(isl::multi_val mv) const {
+  auto res = isl_multi_aff_mod_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const {
+  auto res = isl_multi_aff_move_dims(copy(), static_cast<enum isl_dim_type>(dst_type), dst_pos, static_cast<enum isl_dim_type>(src_type), src_pos, n);
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::multi_val_on_space(isl::space space, isl::multi_val mv) {
+  auto res = isl_multi_aff_multi_val_on_space(space.release(), mv.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::neg() const {
+  auto res = isl_multi_aff_neg(copy());
+  return manage(res);
+}
+
+int multi_aff::plain_cmp(const isl::multi_aff &multi2) const {
+  auto res = isl_multi_aff_plain_cmp(get(), multi2.get());
+  return res;
+}
+
+isl::boolean multi_aff::plain_is_equal(const isl::multi_aff &multi2) const {
+  auto res = isl_multi_aff_plain_is_equal(get(), multi2.get());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::product(isl::multi_aff multi2) const {
+  auto res = isl_multi_aff_product(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::project_out_map(isl::space space, isl::dim type, unsigned int first, unsigned int n) {
+  auto res = isl_multi_aff_project_out_map(space.release(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::pullback(isl::multi_aff ma2) const {
+  auto res = isl_multi_aff_pullback_multi_aff(copy(), ma2.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::range_factor_domain() const {
+  auto res = isl_multi_aff_range_factor_domain(copy());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::range_factor_range() const {
+  auto res = isl_multi_aff_range_factor_range(copy());
+  return manage(res);
+}
+
+isl::boolean multi_aff::range_is_wrapping() const {
+  auto res = isl_multi_aff_range_is_wrapping(get());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::range_map(isl::space space) {
+  auto res = isl_multi_aff_range_map(space.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::range_product(isl::multi_aff multi2) const {
+  auto res = isl_multi_aff_range_product(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::range_splice(unsigned int pos, isl::multi_aff multi2) const {
+  auto res = isl_multi_aff_range_splice(copy(), pos, multi2.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::reset_tuple_id(isl::dim type) const {
+  auto res = isl_multi_aff_reset_tuple_id(copy(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::reset_user() const {
+  auto res = isl_multi_aff_reset_user(copy());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::scale_down_multi_val(isl::multi_val mv) const {
+  auto res = isl_multi_aff_scale_down_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::scale_down_val(isl::val v) const {
+  auto res = isl_multi_aff_scale_down_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::scale_multi_val(isl::multi_val mv) const {
+  auto res = isl_multi_aff_scale_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::scale_val(isl::val v) const {
+  auto res = isl_multi_aff_scale_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::set_aff(int pos, isl::aff el) const {
+  auto res = isl_multi_aff_set_aff(copy(), pos, el.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::set_dim_id(isl::dim type, unsigned int pos, isl::id id) const {
+  auto res = isl_multi_aff_set_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos, id.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::set_tuple_id(isl::dim type, isl::id id) const {
+  auto res = isl_multi_aff_set_tuple_id(copy(), static_cast<enum isl_dim_type>(type), id.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::set_tuple_name(isl::dim type, const std::string &s) const {
+  auto res = isl_multi_aff_set_tuple_name(copy(), static_cast<enum isl_dim_type>(type), s.c_str());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::splice(unsigned int in_pos, unsigned int out_pos, isl::multi_aff multi2) const {
+  auto res = isl_multi_aff_splice(copy(), in_pos, out_pos, multi2.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::sub(isl::multi_aff multi2) const {
+  auto res = isl_multi_aff_sub(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_aff multi_aff::zero(isl::space space) {
+  auto res = isl_multi_aff_zero(space.release());
+  return manage(res);
+}
+
+// implementations for isl::multi_pw_aff
+isl::multi_pw_aff manage(__isl_take isl_multi_pw_aff *ptr) {
+  return multi_pw_aff(ptr);
+}
+isl::multi_pw_aff give(__isl_take isl_multi_pw_aff *ptr) {
+  return manage(ptr);
+}
+
+
+multi_pw_aff::multi_pw_aff()
+    : ptr(nullptr) {}
+
+multi_pw_aff::multi_pw_aff(const isl::multi_pw_aff &obj)
+    : ptr(obj.copy()) {}
+multi_pw_aff::multi_pw_aff(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+multi_pw_aff::multi_pw_aff(__isl_take isl_multi_pw_aff *ptr)
+    : ptr(ptr) {}
+
+multi_pw_aff::multi_pw_aff(isl::multi_aff ma) {
+  auto res = isl_multi_pw_aff_from_multi_aff(ma.release());
+  ptr = res;
+}
+multi_pw_aff::multi_pw_aff(isl::pw_aff pa) {
+  auto res = isl_multi_pw_aff_from_pw_aff(pa.release());
+  ptr = res;
+}
+multi_pw_aff::multi_pw_aff(isl::pw_multi_aff pma) {
+  auto res = isl_multi_pw_aff_from_pw_multi_aff(pma.release());
+  ptr = res;
+}
+multi_pw_aff::multi_pw_aff(isl::ctx ctx, const std::string &str) {
+  auto res = isl_multi_pw_aff_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+multi_pw_aff &multi_pw_aff::operator=(isl::multi_pw_aff obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+multi_pw_aff::~multi_pw_aff() {
+  if (ptr)
+    isl_multi_pw_aff_free(ptr);
+}
+
+__isl_give isl_multi_pw_aff *multi_pw_aff::copy() const & {
+  return isl_multi_pw_aff_copy(ptr);
+}
+
+__isl_keep isl_multi_pw_aff *multi_pw_aff::get() const {
+  return ptr;
+}
+
+__isl_give isl_multi_pw_aff *multi_pw_aff::release() {
+  isl_multi_pw_aff *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool multi_pw_aff::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_multi_pw_aff *multi_pw_aff::keep() const {
+  return get();
+}
+
+__isl_give isl_multi_pw_aff *multi_pw_aff::take() {
+  return release();
+}
+
+multi_pw_aff::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx multi_pw_aff::get_ctx() const {
+  return isl::ctx(isl_multi_pw_aff_get_ctx(ptr));
+}
+
+
+std::string multi_pw_aff::to_str() const {
+  char *Tmp = isl_multi_pw_aff_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void multi_pw_aff::dump() const {
+  isl_multi_pw_aff_dump(get());
+}
+
+
+isl::multi_pw_aff multi_pw_aff::add(isl::multi_pw_aff multi2) const {
+  auto res = isl_multi_pw_aff_add(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::add_dims(isl::dim type, unsigned int n) const {
+  auto res = isl_multi_pw_aff_add_dims(copy(), static_cast<enum isl_dim_type>(type), n);
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::align_params(isl::space model) const {
+  auto res = isl_multi_pw_aff_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::coalesce() const {
+  auto res = isl_multi_pw_aff_coalesce(copy());
+  return manage(res);
+}
+
+unsigned int multi_pw_aff::dim(isl::dim type) const {
+  auto res = isl_multi_pw_aff_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::set multi_pw_aff::domain() const {
+  auto res = isl_multi_pw_aff_domain(copy());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_multi_pw_aff_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::map multi_pw_aff::eq_map(isl::multi_pw_aff mpa2) const {
+  auto res = isl_multi_pw_aff_eq_map(copy(), mpa2.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::factor_range() const {
+  auto res = isl_multi_pw_aff_factor_range(copy());
+  return manage(res);
+}
+
+int multi_pw_aff::find_dim_by_id(isl::dim type, const isl::id &id) const {
+  auto res = isl_multi_pw_aff_find_dim_by_id(get(), static_cast<enum isl_dim_type>(type), id.get());
+  return res;
+}
+
+int multi_pw_aff::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_multi_pw_aff_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::multi_pw_aff multi_pw_aff::flat_range_product(isl::multi_pw_aff multi2) const {
+  auto res = isl_multi_pw_aff_flat_range_product(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::flatten_range() const {
+  auto res = isl_multi_pw_aff_flatten_range(copy());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::from_pw_aff_list(isl::space space, isl::pw_aff_list list) {
+  auto res = isl_multi_pw_aff_from_pw_aff_list(space.release(), list.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::from_range() const {
+  auto res = isl_multi_pw_aff_from_range(copy());
+  return manage(res);
+}
+
+isl::id multi_pw_aff::get_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_multi_pw_aff_get_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::space multi_pw_aff::get_domain_space() const {
+  auto res = isl_multi_pw_aff_get_domain_space(get());
+  return manage(res);
+}
+
+uint32_t multi_pw_aff::get_hash() const {
+  auto res = isl_multi_pw_aff_get_hash(get());
+  return res;
+}
+
+isl::pw_aff multi_pw_aff::get_pw_aff(int pos) const {
+  auto res = isl_multi_pw_aff_get_pw_aff(get(), pos);
+  return manage(res);
+}
+
+isl::space multi_pw_aff::get_space() const {
+  auto res = isl_multi_pw_aff_get_space(get());
+  return manage(res);
+}
+
+isl::id multi_pw_aff::get_tuple_id(isl::dim type) const {
+  auto res = isl_multi_pw_aff_get_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+std::string multi_pw_aff::get_tuple_name(isl::dim type) const {
+  auto res = isl_multi_pw_aff_get_tuple_name(get(), static_cast<enum isl_dim_type>(type));
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::multi_pw_aff multi_pw_aff::gist(isl::set set) const {
+  auto res = isl_multi_pw_aff_gist(copy(), set.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::gist_params(isl::set set) const {
+  auto res = isl_multi_pw_aff_gist_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::boolean multi_pw_aff::has_tuple_id(isl::dim type) const {
+  auto res = isl_multi_pw_aff_has_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::identity(isl::space space) {
+  auto res = isl_multi_pw_aff_identity(space.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::insert_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_multi_pw_aff_insert_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::intersect_domain(isl::set domain) const {
+  auto res = isl_multi_pw_aff_intersect_domain(copy(), domain.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::intersect_params(isl::set set) const {
+  auto res = isl_multi_pw_aff_intersect_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::boolean multi_pw_aff::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_multi_pw_aff_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean multi_pw_aff::involves_nan() const {
+  auto res = isl_multi_pw_aff_involves_nan(get());
+  return manage(res);
+}
+
+isl::boolean multi_pw_aff::is_cst() const {
+  auto res = isl_multi_pw_aff_is_cst(get());
+  return manage(res);
+}
+
+isl::boolean multi_pw_aff::is_equal(const isl::multi_pw_aff &mpa2) const {
+  auto res = isl_multi_pw_aff_is_equal(get(), mpa2.get());
+  return manage(res);
+}
+
+isl::map multi_pw_aff::lex_gt_map(isl::multi_pw_aff mpa2) const {
+  auto res = isl_multi_pw_aff_lex_gt_map(copy(), mpa2.release());
+  return manage(res);
+}
+
+isl::map multi_pw_aff::lex_lt_map(isl::multi_pw_aff mpa2) const {
+  auto res = isl_multi_pw_aff_lex_lt_map(copy(), mpa2.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::mod_multi_val(isl::multi_val mv) const {
+  auto res = isl_multi_pw_aff_mod_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const {
+  auto res = isl_multi_pw_aff_move_dims(copy(), static_cast<enum isl_dim_type>(dst_type), dst_pos, static_cast<enum isl_dim_type>(src_type), src_pos, n);
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::neg() const {
+  auto res = isl_multi_pw_aff_neg(copy());
+  return manage(res);
+}
+
+isl::boolean multi_pw_aff::plain_is_equal(const isl::multi_pw_aff &multi2) const {
+  auto res = isl_multi_pw_aff_plain_is_equal(get(), multi2.get());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::product(isl::multi_pw_aff multi2) const {
+  auto res = isl_multi_pw_aff_product(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::pullback(isl::multi_aff ma) const {
+  auto res = isl_multi_pw_aff_pullback_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::pullback(isl::pw_multi_aff pma) const {
+  auto res = isl_multi_pw_aff_pullback_pw_multi_aff(copy(), pma.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::pullback(isl::multi_pw_aff mpa2) const {
+  auto res = isl_multi_pw_aff_pullback_multi_pw_aff(copy(), mpa2.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::range_factor_domain() const {
+  auto res = isl_multi_pw_aff_range_factor_domain(copy());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::range_factor_range() const {
+  auto res = isl_multi_pw_aff_range_factor_range(copy());
+  return manage(res);
+}
+
+isl::boolean multi_pw_aff::range_is_wrapping() const {
+  auto res = isl_multi_pw_aff_range_is_wrapping(get());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::range_product(isl::multi_pw_aff multi2) const {
+  auto res = isl_multi_pw_aff_range_product(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::range_splice(unsigned int pos, isl::multi_pw_aff multi2) const {
+  auto res = isl_multi_pw_aff_range_splice(copy(), pos, multi2.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::reset_tuple_id(isl::dim type) const {
+  auto res = isl_multi_pw_aff_reset_tuple_id(copy(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::reset_user() const {
+  auto res = isl_multi_pw_aff_reset_user(copy());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::scale_down_multi_val(isl::multi_val mv) const {
+  auto res = isl_multi_pw_aff_scale_down_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::scale_down_val(isl::val v) const {
+  auto res = isl_multi_pw_aff_scale_down_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::scale_multi_val(isl::multi_val mv) const {
+  auto res = isl_multi_pw_aff_scale_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::scale_val(isl::val v) const {
+  auto res = isl_multi_pw_aff_scale_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::set_dim_id(isl::dim type, unsigned int pos, isl::id id) const {
+  auto res = isl_multi_pw_aff_set_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos, id.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::set_pw_aff(int pos, isl::pw_aff el) const {
+  auto res = isl_multi_pw_aff_set_pw_aff(copy(), pos, el.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::set_tuple_id(isl::dim type, isl::id id) const {
+  auto res = isl_multi_pw_aff_set_tuple_id(copy(), static_cast<enum isl_dim_type>(type), id.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::set_tuple_name(isl::dim type, const std::string &s) const {
+  auto res = isl_multi_pw_aff_set_tuple_name(copy(), static_cast<enum isl_dim_type>(type), s.c_str());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::splice(unsigned int in_pos, unsigned int out_pos, isl::multi_pw_aff multi2) const {
+  auto res = isl_multi_pw_aff_splice(copy(), in_pos, out_pos, multi2.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::sub(isl::multi_pw_aff multi2) const {
+  auto res = isl_multi_pw_aff_sub(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_pw_aff::zero(isl::space space) {
+  auto res = isl_multi_pw_aff_zero(space.release());
+  return manage(res);
+}
+
+// implementations for isl::multi_union_pw_aff
+isl::multi_union_pw_aff manage(__isl_take isl_multi_union_pw_aff *ptr) {
+  return multi_union_pw_aff(ptr);
+}
+isl::multi_union_pw_aff give(__isl_take isl_multi_union_pw_aff *ptr) {
+  return manage(ptr);
+}
+
+
+multi_union_pw_aff::multi_union_pw_aff()
+    : ptr(nullptr) {}
+
+multi_union_pw_aff::multi_union_pw_aff(const isl::multi_union_pw_aff &obj)
+    : ptr(obj.copy()) {}
+multi_union_pw_aff::multi_union_pw_aff(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+multi_union_pw_aff::multi_union_pw_aff(__isl_take isl_multi_union_pw_aff *ptr)
+    : ptr(ptr) {}
+
+multi_union_pw_aff::multi_union_pw_aff(isl::union_pw_aff upa) {
+  auto res = isl_multi_union_pw_aff_from_union_pw_aff(upa.release());
+  ptr = res;
+}
+multi_union_pw_aff::multi_union_pw_aff(isl::multi_pw_aff mpa) {
+  auto res = isl_multi_union_pw_aff_from_multi_pw_aff(mpa.release());
+  ptr = res;
+}
+multi_union_pw_aff::multi_union_pw_aff(isl::union_pw_multi_aff upma) {
+  auto res = isl_multi_union_pw_aff_from_union_pw_multi_aff(upma.release());
+  ptr = res;
+}
+multi_union_pw_aff::multi_union_pw_aff(isl::ctx ctx, const std::string &str) {
+  auto res = isl_multi_union_pw_aff_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+multi_union_pw_aff &multi_union_pw_aff::operator=(isl::multi_union_pw_aff obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+multi_union_pw_aff::~multi_union_pw_aff() {
+  if (ptr)
+    isl_multi_union_pw_aff_free(ptr);
+}
+
+__isl_give isl_multi_union_pw_aff *multi_union_pw_aff::copy() const & {
+  return isl_multi_union_pw_aff_copy(ptr);
+}
+
+__isl_keep isl_multi_union_pw_aff *multi_union_pw_aff::get() const {
+  return ptr;
+}
+
+__isl_give isl_multi_union_pw_aff *multi_union_pw_aff::release() {
+  isl_multi_union_pw_aff *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool multi_union_pw_aff::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_multi_union_pw_aff *multi_union_pw_aff::keep() const {
+  return get();
+}
+
+__isl_give isl_multi_union_pw_aff *multi_union_pw_aff::take() {
+  return release();
+}
+
+multi_union_pw_aff::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx multi_union_pw_aff::get_ctx() const {
+  return isl::ctx(isl_multi_union_pw_aff_get_ctx(ptr));
+}
+
+
+std::string multi_union_pw_aff::to_str() const {
+  char *Tmp = isl_multi_union_pw_aff_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void multi_union_pw_aff::dump() const {
+  isl_multi_union_pw_aff_dump(get());
+}
+
+
+isl::multi_union_pw_aff multi_union_pw_aff::add(isl::multi_union_pw_aff multi2) const {
+  auto res = isl_multi_union_pw_aff_add(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::align_params(isl::space model) const {
+  auto res = isl_multi_union_pw_aff_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::union_pw_aff multi_union_pw_aff::apply_aff(isl::aff aff) const {
+  auto res = isl_multi_union_pw_aff_apply_aff(copy(), aff.release());
+  return manage(res);
+}
+
+isl::union_pw_aff multi_union_pw_aff::apply_pw_aff(isl::pw_aff pa) const {
+  auto res = isl_multi_union_pw_aff_apply_pw_aff(copy(), pa.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::apply_pw_multi_aff(isl::pw_multi_aff pma) const {
+  auto res = isl_multi_union_pw_aff_apply_pw_multi_aff(copy(), pma.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::coalesce() const {
+  auto res = isl_multi_union_pw_aff_coalesce(copy());
+  return manage(res);
+}
+
+unsigned int multi_union_pw_aff::dim(isl::dim type) const {
+  auto res = isl_multi_union_pw_aff_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::union_set multi_union_pw_aff::domain() const {
+  auto res = isl_multi_union_pw_aff_domain(copy());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_multi_union_pw_aff_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::multi_pw_aff multi_union_pw_aff::extract_multi_pw_aff(isl::space space) const {
+  auto res = isl_multi_union_pw_aff_extract_multi_pw_aff(get(), space.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::factor_range() const {
+  auto res = isl_multi_union_pw_aff_factor_range(copy());
+  return manage(res);
+}
+
+int multi_union_pw_aff::find_dim_by_id(isl::dim type, const isl::id &id) const {
+  auto res = isl_multi_union_pw_aff_find_dim_by_id(get(), static_cast<enum isl_dim_type>(type), id.get());
+  return res;
+}
+
+int multi_union_pw_aff::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_multi_union_pw_aff_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::flat_range_product(isl::multi_union_pw_aff multi2) const {
+  auto res = isl_multi_union_pw_aff_flat_range_product(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::flatten_range() const {
+  auto res = isl_multi_union_pw_aff_flatten_range(copy());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::floor() const {
+  auto res = isl_multi_union_pw_aff_floor(copy());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::from_multi_aff(isl::multi_aff ma) {
+  auto res = isl_multi_union_pw_aff_from_multi_aff(ma.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::from_range() const {
+  auto res = isl_multi_union_pw_aff_from_range(copy());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::from_union_map(isl::union_map umap) {
+  auto res = isl_multi_union_pw_aff_from_union_map(umap.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::from_union_pw_aff_list(isl::space space, isl::union_pw_aff_list list) {
+  auto res = isl_multi_union_pw_aff_from_union_pw_aff_list(space.release(), list.release());
+  return manage(res);
+}
+
+isl::id multi_union_pw_aff::get_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_multi_union_pw_aff_get_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::space multi_union_pw_aff::get_domain_space() const {
+  auto res = isl_multi_union_pw_aff_get_domain_space(get());
+  return manage(res);
+}
+
+isl::space multi_union_pw_aff::get_space() const {
+  auto res = isl_multi_union_pw_aff_get_space(get());
+  return manage(res);
+}
+
+isl::id multi_union_pw_aff::get_tuple_id(isl::dim type) const {
+  auto res = isl_multi_union_pw_aff_get_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+std::string multi_union_pw_aff::get_tuple_name(isl::dim type) const {
+  auto res = isl_multi_union_pw_aff_get_tuple_name(get(), static_cast<enum isl_dim_type>(type));
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::union_pw_aff multi_union_pw_aff::get_union_pw_aff(int pos) const {
+  auto res = isl_multi_union_pw_aff_get_union_pw_aff(get(), pos);
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::gist(isl::union_set context) const {
+  auto res = isl_multi_union_pw_aff_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::gist_params(isl::set context) const {
+  auto res = isl_multi_union_pw_aff_gist_params(copy(), context.release());
+  return manage(res);
+}
+
+isl::boolean multi_union_pw_aff::has_tuple_id(isl::dim type) const {
+  auto res = isl_multi_union_pw_aff_has_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::intersect_domain(isl::union_set uset) const {
+  auto res = isl_multi_union_pw_aff_intersect_domain(copy(), uset.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::intersect_params(isl::set params) const {
+  auto res = isl_multi_union_pw_aff_intersect_params(copy(), params.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::intersect_range(isl::set set) const {
+  auto res = isl_multi_union_pw_aff_intersect_range(copy(), set.release());
+  return manage(res);
+}
+
+isl::boolean multi_union_pw_aff::involves_nan() const {
+  auto res = isl_multi_union_pw_aff_involves_nan(get());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::mod_multi_val(isl::multi_val mv) const {
+  auto res = isl_multi_union_pw_aff_mod_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::multi_aff_on_domain(isl::union_set domain, isl::multi_aff ma) {
+  auto res = isl_multi_union_pw_aff_multi_aff_on_domain(domain.release(), ma.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::multi_val_on_domain(isl::union_set domain, isl::multi_val mv) {
+  auto res = isl_multi_union_pw_aff_multi_val_on_domain(domain.release(), mv.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::neg() const {
+  auto res = isl_multi_union_pw_aff_neg(copy());
+  return manage(res);
+}
+
+isl::boolean multi_union_pw_aff::plain_is_equal(const isl::multi_union_pw_aff &multi2) const {
+  auto res = isl_multi_union_pw_aff_plain_is_equal(get(), multi2.get());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::pullback(isl::union_pw_multi_aff upma) const {
+  auto res = isl_multi_union_pw_aff_pullback_union_pw_multi_aff(copy(), upma.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::range_factor_domain() const {
+  auto res = isl_multi_union_pw_aff_range_factor_domain(copy());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::range_factor_range() const {
+  auto res = isl_multi_union_pw_aff_range_factor_range(copy());
+  return manage(res);
+}
+
+isl::boolean multi_union_pw_aff::range_is_wrapping() const {
+  auto res = isl_multi_union_pw_aff_range_is_wrapping(get());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::range_product(isl::multi_union_pw_aff multi2) const {
+  auto res = isl_multi_union_pw_aff_range_product(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::range_splice(unsigned int pos, isl::multi_union_pw_aff multi2) const {
+  auto res = isl_multi_union_pw_aff_range_splice(copy(), pos, multi2.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::reset_tuple_id(isl::dim type) const {
+  auto res = isl_multi_union_pw_aff_reset_tuple_id(copy(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::reset_user() const {
+  auto res = isl_multi_union_pw_aff_reset_user(copy());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::scale_down_multi_val(isl::multi_val mv) const {
+  auto res = isl_multi_union_pw_aff_scale_down_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::scale_down_val(isl::val v) const {
+  auto res = isl_multi_union_pw_aff_scale_down_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::scale_multi_val(isl::multi_val mv) const {
+  auto res = isl_multi_union_pw_aff_scale_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::scale_val(isl::val v) const {
+  auto res = isl_multi_union_pw_aff_scale_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::set_dim_id(isl::dim type, unsigned int pos, isl::id id) const {
+  auto res = isl_multi_union_pw_aff_set_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos, id.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::set_tuple_id(isl::dim type, isl::id id) const {
+  auto res = isl_multi_union_pw_aff_set_tuple_id(copy(), static_cast<enum isl_dim_type>(type), id.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::set_tuple_name(isl::dim type, const std::string &s) const {
+  auto res = isl_multi_union_pw_aff_set_tuple_name(copy(), static_cast<enum isl_dim_type>(type), s.c_str());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::set_union_pw_aff(int pos, isl::union_pw_aff el) const {
+  auto res = isl_multi_union_pw_aff_set_union_pw_aff(copy(), pos, el.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::sub(isl::multi_union_pw_aff multi2) const {
+  auto res = isl_multi_union_pw_aff_sub(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::union_add(isl::multi_union_pw_aff mupa2) const {
+  auto res = isl_multi_union_pw_aff_union_add(copy(), mupa2.release());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff multi_union_pw_aff::zero(isl::space space) {
+  auto res = isl_multi_union_pw_aff_zero(space.release());
+  return manage(res);
+}
+
+isl::union_set multi_union_pw_aff::zero_union_set() const {
+  auto res = isl_multi_union_pw_aff_zero_union_set(copy());
+  return manage(res);
+}
+
+// implementations for isl::multi_val
+isl::multi_val manage(__isl_take isl_multi_val *ptr) {
+  return multi_val(ptr);
+}
+isl::multi_val give(__isl_take isl_multi_val *ptr) {
+  return manage(ptr);
+}
+
+
+multi_val::multi_val()
+    : ptr(nullptr) {}
+
+multi_val::multi_val(const isl::multi_val &obj)
+    : ptr(obj.copy()) {}
+multi_val::multi_val(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+multi_val::multi_val(__isl_take isl_multi_val *ptr)
+    : ptr(ptr) {}
+
+multi_val::multi_val(isl::ctx ctx, const std::string &str) {
+  auto res = isl_multi_val_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+multi_val &multi_val::operator=(isl::multi_val obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+multi_val::~multi_val() {
+  if (ptr)
+    isl_multi_val_free(ptr);
+}
+
+__isl_give isl_multi_val *multi_val::copy() const & {
+  return isl_multi_val_copy(ptr);
+}
+
+__isl_keep isl_multi_val *multi_val::get() const {
+  return ptr;
+}
+
+__isl_give isl_multi_val *multi_val::release() {
+  isl_multi_val *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool multi_val::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_multi_val *multi_val::keep() const {
+  return get();
+}
+
+__isl_give isl_multi_val *multi_val::take() {
+  return release();
+}
+
+multi_val::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx multi_val::get_ctx() const {
+  return isl::ctx(isl_multi_val_get_ctx(ptr));
+}
+
+
+std::string multi_val::to_str() const {
+  char *Tmp = isl_multi_val_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void multi_val::dump() const {
+  isl_multi_val_dump(get());
+}
+
+
+isl::multi_val multi_val::add(isl::multi_val multi2) const {
+  auto res = isl_multi_val_add(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::add_dims(isl::dim type, unsigned int n) const {
+  auto res = isl_multi_val_add_dims(copy(), static_cast<enum isl_dim_type>(type), n);
+  return manage(res);
+}
+
+isl::multi_val multi_val::add_val(isl::val v) const {
+  auto res = isl_multi_val_add_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::align_params(isl::space model) const {
+  auto res = isl_multi_val_align_params(copy(), model.release());
+  return manage(res);
+}
+
+unsigned int multi_val::dim(isl::dim type) const {
+  auto res = isl_multi_val_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::multi_val multi_val::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_multi_val_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::multi_val multi_val::factor_range() const {
+  auto res = isl_multi_val_factor_range(copy());
+  return manage(res);
+}
+
+int multi_val::find_dim_by_id(isl::dim type, const isl::id &id) const {
+  auto res = isl_multi_val_find_dim_by_id(get(), static_cast<enum isl_dim_type>(type), id.get());
+  return res;
+}
+
+int multi_val::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_multi_val_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::multi_val multi_val::flat_range_product(isl::multi_val multi2) const {
+  auto res = isl_multi_val_flat_range_product(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::flatten_range() const {
+  auto res = isl_multi_val_flatten_range(copy());
+  return manage(res);
+}
+
+isl::multi_val multi_val::from_range() const {
+  auto res = isl_multi_val_from_range(copy());
+  return manage(res);
+}
+
+isl::multi_val multi_val::from_val_list(isl::space space, isl::val_list list) {
+  auto res = isl_multi_val_from_val_list(space.release(), list.release());
+  return manage(res);
+}
+
+isl::id multi_val::get_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_multi_val_get_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::space multi_val::get_domain_space() const {
+  auto res = isl_multi_val_get_domain_space(get());
+  return manage(res);
+}
+
+isl::space multi_val::get_space() const {
+  auto res = isl_multi_val_get_space(get());
+  return manage(res);
+}
+
+isl::id multi_val::get_tuple_id(isl::dim type) const {
+  auto res = isl_multi_val_get_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+std::string multi_val::get_tuple_name(isl::dim type) const {
+  auto res = isl_multi_val_get_tuple_name(get(), static_cast<enum isl_dim_type>(type));
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::val multi_val::get_val(int pos) const {
+  auto res = isl_multi_val_get_val(get(), pos);
+  return manage(res);
+}
+
+isl::boolean multi_val::has_tuple_id(isl::dim type) const {
+  auto res = isl_multi_val_has_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::multi_val multi_val::insert_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_multi_val_insert_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean multi_val::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_multi_val_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean multi_val::involves_nan() const {
+  auto res = isl_multi_val_involves_nan(get());
+  return manage(res);
+}
+
+isl::multi_val multi_val::mod_multi_val(isl::multi_val mv) const {
+  auto res = isl_multi_val_mod_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::mod_val(isl::val v) const {
+  auto res = isl_multi_val_mod_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::neg() const {
+  auto res = isl_multi_val_neg(copy());
+  return manage(res);
+}
+
+isl::boolean multi_val::plain_is_equal(const isl::multi_val &multi2) const {
+  auto res = isl_multi_val_plain_is_equal(get(), multi2.get());
+  return manage(res);
+}
+
+isl::multi_val multi_val::product(isl::multi_val multi2) const {
+  auto res = isl_multi_val_product(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::range_factor_domain() const {
+  auto res = isl_multi_val_range_factor_domain(copy());
+  return manage(res);
+}
+
+isl::multi_val multi_val::range_factor_range() const {
+  auto res = isl_multi_val_range_factor_range(copy());
+  return manage(res);
+}
+
+isl::boolean multi_val::range_is_wrapping() const {
+  auto res = isl_multi_val_range_is_wrapping(get());
+  return manage(res);
+}
+
+isl::multi_val multi_val::range_product(isl::multi_val multi2) const {
+  auto res = isl_multi_val_range_product(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::range_splice(unsigned int pos, isl::multi_val multi2) const {
+  auto res = isl_multi_val_range_splice(copy(), pos, multi2.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::reset_tuple_id(isl::dim type) const {
+  auto res = isl_multi_val_reset_tuple_id(copy(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::multi_val multi_val::reset_user() const {
+  auto res = isl_multi_val_reset_user(copy());
+  return manage(res);
+}
+
+isl::multi_val multi_val::scale_down_multi_val(isl::multi_val mv) const {
+  auto res = isl_multi_val_scale_down_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::scale_down_val(isl::val v) const {
+  auto res = isl_multi_val_scale_down_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::scale_multi_val(isl::multi_val mv) const {
+  auto res = isl_multi_val_scale_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::scale_val(isl::val v) const {
+  auto res = isl_multi_val_scale_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::set_dim_id(isl::dim type, unsigned int pos, isl::id id) const {
+  auto res = isl_multi_val_set_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos, id.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::set_tuple_id(isl::dim type, isl::id id) const {
+  auto res = isl_multi_val_set_tuple_id(copy(), static_cast<enum isl_dim_type>(type), id.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::set_tuple_name(isl::dim type, const std::string &s) const {
+  auto res = isl_multi_val_set_tuple_name(copy(), static_cast<enum isl_dim_type>(type), s.c_str());
+  return manage(res);
+}
+
+isl::multi_val multi_val::set_val(int pos, isl::val el) const {
+  auto res = isl_multi_val_set_val(copy(), pos, el.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::splice(unsigned int in_pos, unsigned int out_pos, isl::multi_val multi2) const {
+  auto res = isl_multi_val_splice(copy(), in_pos, out_pos, multi2.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::sub(isl::multi_val multi2) const {
+  auto res = isl_multi_val_sub(copy(), multi2.release());
+  return manage(res);
+}
+
+isl::multi_val multi_val::zero(isl::space space) {
+  auto res = isl_multi_val_zero(space.release());
+  return manage(res);
+}
+
+// implementations for isl::point
+isl::point manage(__isl_take isl_point *ptr) {
+  return point(ptr);
+}
+isl::point give(__isl_take isl_point *ptr) {
+  return manage(ptr);
+}
+
+
+point::point()
+    : ptr(nullptr) {}
+
+point::point(const isl::point &obj)
+    : ptr(obj.copy()) {}
+point::point(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+point::point(__isl_take isl_point *ptr)
+    : ptr(ptr) {}
+
+point::point(isl::space dim) {
+  auto res = isl_point_zero(dim.release());
+  ptr = res;
+}
+
+point &point::operator=(isl::point obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+point::~point() {
+  if (ptr)
+    isl_point_free(ptr);
+}
+
+__isl_give isl_point *point::copy() const & {
+  return isl_point_copy(ptr);
+}
+
+__isl_keep isl_point *point::get() const {
+  return ptr;
+}
+
+__isl_give isl_point *point::release() {
+  isl_point *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool point::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_point *point::keep() const {
+  return get();
+}
+
+__isl_give isl_point *point::take() {
+  return release();
+}
+
+point::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx point::get_ctx() const {
+  return isl::ctx(isl_point_get_ctx(ptr));
+}
+
+
+std::string point::to_str() const {
+  char *Tmp = isl_point_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void point::dump() const {
+  isl_point_dump(get());
+}
+
+
+isl::point point::add_ui(isl::dim type, int pos, unsigned int val) const {
+  auto res = isl_point_add_ui(copy(), static_cast<enum isl_dim_type>(type), pos, val);
+  return manage(res);
+}
+
+isl::val point::get_coordinate_val(isl::dim type, int pos) const {
+  auto res = isl_point_get_coordinate_val(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::space point::get_space() const {
+  auto res = isl_point_get_space(get());
+  return manage(res);
+}
+
+isl::point point::set_coordinate_val(isl::dim type, int pos, isl::val v) const {
+  auto res = isl_point_set_coordinate_val(copy(), static_cast<enum isl_dim_type>(type), pos, v.release());
+  return manage(res);
+}
+
+isl::point point::sub_ui(isl::dim type, int pos, unsigned int val) const {
+  auto res = isl_point_sub_ui(copy(), static_cast<enum isl_dim_type>(type), pos, val);
+  return manage(res);
+}
+
+// implementations for isl::pw_aff
+isl::pw_aff manage(__isl_take isl_pw_aff *ptr) {
+  return pw_aff(ptr);
+}
+isl::pw_aff give(__isl_take isl_pw_aff *ptr) {
+  return manage(ptr);
+}
+
+
+pw_aff::pw_aff()
+    : ptr(nullptr) {}
+
+pw_aff::pw_aff(const isl::pw_aff &obj)
+    : ptr(obj.copy()) {}
+pw_aff::pw_aff(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+pw_aff::pw_aff(__isl_take isl_pw_aff *ptr)
+    : ptr(ptr) {}
+
+pw_aff::pw_aff(isl::aff aff) {
+  auto res = isl_pw_aff_from_aff(aff.release());
+  ptr = res;
+}
+pw_aff::pw_aff(isl::local_space ls) {
+  auto res = isl_pw_aff_zero_on_domain(ls.release());
+  ptr = res;
+}
+pw_aff::pw_aff(isl::set domain, isl::val v) {
+  auto res = isl_pw_aff_val_on_domain(domain.release(), v.release());
+  ptr = res;
+}
+pw_aff::pw_aff(isl::ctx ctx, const std::string &str) {
+  auto res = isl_pw_aff_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+pw_aff &pw_aff::operator=(isl::pw_aff obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+pw_aff::~pw_aff() {
+  if (ptr)
+    isl_pw_aff_free(ptr);
+}
+
+__isl_give isl_pw_aff *pw_aff::copy() const & {
+  return isl_pw_aff_copy(ptr);
+}
+
+__isl_keep isl_pw_aff *pw_aff::get() const {
+  return ptr;
+}
+
+__isl_give isl_pw_aff *pw_aff::release() {
+  isl_pw_aff *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool pw_aff::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_pw_aff *pw_aff::keep() const {
+  return get();
+}
+
+__isl_give isl_pw_aff *pw_aff::take() {
+  return release();
+}
+
+pw_aff::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx pw_aff::get_ctx() const {
+  return isl::ctx(isl_pw_aff_get_ctx(ptr));
+}
+
+
+std::string pw_aff::to_str() const {
+  char *Tmp = isl_pw_aff_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void pw_aff::dump() const {
+  isl_pw_aff_dump(get());
+}
+
+
+isl::pw_aff pw_aff::add(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_add(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::add_dims(isl::dim type, unsigned int n) const {
+  auto res = isl_pw_aff_add_dims(copy(), static_cast<enum isl_dim_type>(type), n);
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::align_params(isl::space model) const {
+  auto res = isl_pw_aff_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::alloc(isl::set set, isl::aff aff) {
+  auto res = isl_pw_aff_alloc(set.release(), aff.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::ceil() const {
+  auto res = isl_pw_aff_ceil(copy());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::coalesce() const {
+  auto res = isl_pw_aff_coalesce(copy());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::cond(isl::pw_aff pwaff_true, isl::pw_aff pwaff_false) const {
+  auto res = isl_pw_aff_cond(copy(), pwaff_true.release(), pwaff_false.release());
+  return manage(res);
+}
+
+unsigned int pw_aff::dim(isl::dim type) const {
+  auto res = isl_pw_aff_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::pw_aff pw_aff::div(isl::pw_aff pa2) const {
+  auto res = isl_pw_aff_div(copy(), pa2.release());
+  return manage(res);
+}
+
+isl::set pw_aff::domain() const {
+  auto res = isl_pw_aff_domain(copy());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_pw_aff_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::empty(isl::space dim) {
+  auto res = isl_pw_aff_empty(dim.release());
+  return manage(res);
+}
+
+isl::map pw_aff::eq_map(isl::pw_aff pa2) const {
+  auto res = isl_pw_aff_eq_map(copy(), pa2.release());
+  return manage(res);
+}
+
+isl::set pw_aff::eq_set(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_eq_set(copy(), pwaff2.release());
+  return manage(res);
+}
+
+int pw_aff::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_pw_aff_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::pw_aff pw_aff::floor() const {
+  auto res = isl_pw_aff_floor(copy());
+  return manage(res);
+}
+
+isl::stat pw_aff::foreach_piece(const std::function<isl::stat(isl::set, isl::aff)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_set *arg_0, isl_aff *arg_1, void *arg_2) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::set, isl::aff)> **>(arg_2);
+    stat ret = (*func)(isl::manage(arg_0), isl::manage(arg_1));
+    return isl_stat(ret);
+  };
+  auto res = isl_pw_aff_foreach_piece(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::pw_aff pw_aff::from_range() const {
+  auto res = isl_pw_aff_from_range(copy());
+  return manage(res);
+}
+
+isl::set pw_aff::ge_set(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_ge_set(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::id pw_aff::get_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_pw_aff_get_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+std::string pw_aff::get_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_pw_aff_get_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::space pw_aff::get_domain_space() const {
+  auto res = isl_pw_aff_get_domain_space(get());
+  return manage(res);
+}
+
+uint32_t pw_aff::get_hash() const {
+  auto res = isl_pw_aff_get_hash(get());
+  return res;
+}
+
+isl::space pw_aff::get_space() const {
+  auto res = isl_pw_aff_get_space(get());
+  return manage(res);
+}
+
+isl::id pw_aff::get_tuple_id(isl::dim type) const {
+  auto res = isl_pw_aff_get_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::gist(isl::set context) const {
+  auto res = isl_pw_aff_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::gist_params(isl::set context) const {
+  auto res = isl_pw_aff_gist_params(copy(), context.release());
+  return manage(res);
+}
+
+isl::map pw_aff::gt_map(isl::pw_aff pa2) const {
+  auto res = isl_pw_aff_gt_map(copy(), pa2.release());
+  return manage(res);
+}
+
+isl::set pw_aff::gt_set(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_gt_set(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::boolean pw_aff::has_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_pw_aff_has_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean pw_aff::has_tuple_id(isl::dim type) const {
+  auto res = isl_pw_aff_has_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::insert_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_pw_aff_insert_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::intersect_domain(isl::set set) const {
+  auto res = isl_pw_aff_intersect_domain(copy(), set.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::intersect_params(isl::set set) const {
+  auto res = isl_pw_aff_intersect_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::boolean pw_aff::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_pw_aff_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean pw_aff::involves_nan() const {
+  auto res = isl_pw_aff_involves_nan(get());
+  return manage(res);
+}
+
+isl::boolean pw_aff::is_cst() const {
+  auto res = isl_pw_aff_is_cst(get());
+  return manage(res);
+}
+
+isl::boolean pw_aff::is_empty() const {
+  auto res = isl_pw_aff_is_empty(get());
+  return manage(res);
+}
+
+isl::boolean pw_aff::is_equal(const isl::pw_aff &pa2) const {
+  auto res = isl_pw_aff_is_equal(get(), pa2.get());
+  return manage(res);
+}
+
+isl::set pw_aff::le_set(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_le_set(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::map pw_aff::lt_map(isl::pw_aff pa2) const {
+  auto res = isl_pw_aff_lt_map(copy(), pa2.release());
+  return manage(res);
+}
+
+isl::set pw_aff::lt_set(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_lt_set(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::max(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_max(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::min(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_min(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::mod(isl::val mod) const {
+  auto res = isl_pw_aff_mod_val(copy(), mod.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const {
+  auto res = isl_pw_aff_move_dims(copy(), static_cast<enum isl_dim_type>(dst_type), dst_pos, static_cast<enum isl_dim_type>(src_type), src_pos, n);
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::mul(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_mul(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::nan_on_domain(isl::local_space ls) {
+  auto res = isl_pw_aff_nan_on_domain(ls.release());
+  return manage(res);
+}
+
+isl::set pw_aff::ne_set(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_ne_set(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::neg() const {
+  auto res = isl_pw_aff_neg(copy());
+  return manage(res);
+}
+
+isl::set pw_aff::non_zero_set() const {
+  auto res = isl_pw_aff_non_zero_set(copy());
+  return manage(res);
+}
+
+isl::set pw_aff::nonneg_set() const {
+  auto res = isl_pw_aff_nonneg_set(copy());
+  return manage(res);
+}
+
+isl::set pw_aff::params() const {
+  auto res = isl_pw_aff_params(copy());
+  return manage(res);
+}
+
+int pw_aff::plain_cmp(const isl::pw_aff &pa2) const {
+  auto res = isl_pw_aff_plain_cmp(get(), pa2.get());
+  return res;
+}
+
+isl::boolean pw_aff::plain_is_equal(const isl::pw_aff &pwaff2) const {
+  auto res = isl_pw_aff_plain_is_equal(get(), pwaff2.get());
+  return manage(res);
+}
+
+isl::set pw_aff::pos_set() const {
+  auto res = isl_pw_aff_pos_set(copy());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::project_domain_on_params() const {
+  auto res = isl_pw_aff_project_domain_on_params(copy());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::pullback(isl::multi_aff ma) const {
+  auto res = isl_pw_aff_pullback_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::pullback(isl::pw_multi_aff pma) const {
+  auto res = isl_pw_aff_pullback_pw_multi_aff(copy(), pma.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::pullback(isl::multi_pw_aff mpa) const {
+  auto res = isl_pw_aff_pullback_multi_pw_aff(copy(), mpa.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::reset_tuple_id(isl::dim type) const {
+  auto res = isl_pw_aff_reset_tuple_id(copy(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::reset_user() const {
+  auto res = isl_pw_aff_reset_user(copy());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::scale(isl::val v) const {
+  auto res = isl_pw_aff_scale_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::scale_down(isl::val f) const {
+  auto res = isl_pw_aff_scale_down_val(copy(), f.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::set_dim_id(isl::dim type, unsigned int pos, isl::id id) const {
+  auto res = isl_pw_aff_set_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos, id.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::set_tuple_id(isl::dim type, isl::id id) const {
+  auto res = isl_pw_aff_set_tuple_id(copy(), static_cast<enum isl_dim_type>(type), id.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::sub(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_sub(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::subtract_domain(isl::set set) const {
+  auto res = isl_pw_aff_subtract_domain(copy(), set.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::tdiv_q(isl::pw_aff pa2) const {
+  auto res = isl_pw_aff_tdiv_q(copy(), pa2.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::tdiv_r(isl::pw_aff pa2) const {
+  auto res = isl_pw_aff_tdiv_r(copy(), pa2.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::union_add(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_union_add(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::union_max(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_union_max(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::union_min(isl::pw_aff pwaff2) const {
+  auto res = isl_pw_aff_union_min(copy(), pwaff2.release());
+  return manage(res);
+}
+
+isl::pw_aff pw_aff::var_on_domain(isl::local_space ls, isl::dim type, unsigned int pos) {
+  auto res = isl_pw_aff_var_on_domain(ls.release(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::set pw_aff::zero_set() const {
+  auto res = isl_pw_aff_zero_set(copy());
+  return manage(res);
+}
+
+// implementations for isl::pw_aff_list
+isl::pw_aff_list manage(__isl_take isl_pw_aff_list *ptr) {
+  return pw_aff_list(ptr);
+}
+isl::pw_aff_list give(__isl_take isl_pw_aff_list *ptr) {
+  return manage(ptr);
+}
+
+
+pw_aff_list::pw_aff_list()
+    : ptr(nullptr) {}
+
+pw_aff_list::pw_aff_list(const isl::pw_aff_list &obj)
+    : ptr(obj.copy()) {}
+pw_aff_list::pw_aff_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+pw_aff_list::pw_aff_list(__isl_take isl_pw_aff_list *ptr)
+    : ptr(ptr) {}
+
+
+pw_aff_list &pw_aff_list::operator=(isl::pw_aff_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+pw_aff_list::~pw_aff_list() {
+  if (ptr)
+    isl_pw_aff_list_free(ptr);
+}
+
+__isl_give isl_pw_aff_list *pw_aff_list::copy() const & {
+  return isl_pw_aff_list_copy(ptr);
+}
+
+__isl_keep isl_pw_aff_list *pw_aff_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_pw_aff_list *pw_aff_list::release() {
+  isl_pw_aff_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool pw_aff_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_pw_aff_list *pw_aff_list::keep() const {
+  return get();
+}
+
+__isl_give isl_pw_aff_list *pw_aff_list::take() {
+  return release();
+}
+
+pw_aff_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx pw_aff_list::get_ctx() const {
+  return isl::ctx(isl_pw_aff_list_get_ctx(ptr));
+}
+
+
+
+void pw_aff_list::dump() const {
+  isl_pw_aff_list_dump(get());
+}
+
+
+
+// implementations for isl::pw_multi_aff
+isl::pw_multi_aff manage(__isl_take isl_pw_multi_aff *ptr) {
+  return pw_multi_aff(ptr);
+}
+isl::pw_multi_aff give(__isl_take isl_pw_multi_aff *ptr) {
+  return manage(ptr);
+}
+
+
+pw_multi_aff::pw_multi_aff()
+    : ptr(nullptr) {}
+
+pw_multi_aff::pw_multi_aff(const isl::pw_multi_aff &obj)
+    : ptr(obj.copy()) {}
+pw_multi_aff::pw_multi_aff(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+pw_multi_aff::pw_multi_aff(__isl_take isl_pw_multi_aff *ptr)
+    : ptr(ptr) {}
+
+pw_multi_aff::pw_multi_aff(isl::multi_aff ma) {
+  auto res = isl_pw_multi_aff_from_multi_aff(ma.release());
+  ptr = res;
+}
+pw_multi_aff::pw_multi_aff(isl::pw_aff pa) {
+  auto res = isl_pw_multi_aff_from_pw_aff(pa.release());
+  ptr = res;
+}
+pw_multi_aff::pw_multi_aff(isl::ctx ctx, const std::string &str) {
+  auto res = isl_pw_multi_aff_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+pw_multi_aff &pw_multi_aff::operator=(isl::pw_multi_aff obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+pw_multi_aff::~pw_multi_aff() {
+  if (ptr)
+    isl_pw_multi_aff_free(ptr);
+}
+
+__isl_give isl_pw_multi_aff *pw_multi_aff::copy() const & {
+  return isl_pw_multi_aff_copy(ptr);
+}
+
+__isl_keep isl_pw_multi_aff *pw_multi_aff::get() const {
+  return ptr;
+}
+
+__isl_give isl_pw_multi_aff *pw_multi_aff::release() {
+  isl_pw_multi_aff *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool pw_multi_aff::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_pw_multi_aff *pw_multi_aff::keep() const {
+  return get();
+}
+
+__isl_give isl_pw_multi_aff *pw_multi_aff::take() {
+  return release();
+}
+
+pw_multi_aff::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx pw_multi_aff::get_ctx() const {
+  return isl::ctx(isl_pw_multi_aff_get_ctx(ptr));
+}
+
+
+std::string pw_multi_aff::to_str() const {
+  char *Tmp = isl_pw_multi_aff_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void pw_multi_aff::dump() const {
+  isl_pw_multi_aff_dump(get());
+}
+
+
+isl::pw_multi_aff pw_multi_aff::add(isl::pw_multi_aff pma2) const {
+  auto res = isl_pw_multi_aff_add(copy(), pma2.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::align_params(isl::space model) const {
+  auto res = isl_pw_multi_aff_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::alloc(isl::set set, isl::multi_aff maff) {
+  auto res = isl_pw_multi_aff_alloc(set.release(), maff.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::coalesce() const {
+  auto res = isl_pw_multi_aff_coalesce(copy());
+  return manage(res);
+}
+
+unsigned int pw_multi_aff::dim(isl::dim type) const {
+  auto res = isl_pw_multi_aff_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::set pw_multi_aff::domain() const {
+  auto res = isl_pw_multi_aff_domain(copy());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_pw_multi_aff_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::empty(isl::space space) {
+  auto res = isl_pw_multi_aff_empty(space.release());
+  return manage(res);
+}
+
+int pw_multi_aff::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_pw_multi_aff_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::pw_multi_aff pw_multi_aff::fix_si(isl::dim type, unsigned int pos, int value) const {
+  auto res = isl_pw_multi_aff_fix_si(copy(), static_cast<enum isl_dim_type>(type), pos, value);
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::flat_range_product(isl::pw_multi_aff pma2) const {
+  auto res = isl_pw_multi_aff_flat_range_product(copy(), pma2.release());
+  return manage(res);
+}
+
+isl::stat pw_multi_aff::foreach_piece(const std::function<isl::stat(isl::set, isl::multi_aff)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_set *arg_0, isl_multi_aff *arg_1, void *arg_2) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::set, isl::multi_aff)> **>(arg_2);
+    stat ret = (*func)(isl::manage(arg_0), isl::manage(arg_1));
+    return isl_stat(ret);
+  };
+  auto res = isl_pw_multi_aff_foreach_piece(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::from_domain(isl::set set) {
+  auto res = isl_pw_multi_aff_from_domain(set.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::from_map(isl::map map) {
+  auto res = isl_pw_multi_aff_from_map(map.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::from_multi_pw_aff(isl::multi_pw_aff mpa) {
+  auto res = isl_pw_multi_aff_from_multi_pw_aff(mpa.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::from_set(isl::set set) {
+  auto res = isl_pw_multi_aff_from_set(set.release());
+  return manage(res);
+}
+
+isl::id pw_multi_aff::get_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_pw_multi_aff_get_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+std::string pw_multi_aff::get_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_pw_multi_aff_get_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::space pw_multi_aff::get_domain_space() const {
+  auto res = isl_pw_multi_aff_get_domain_space(get());
+  return manage(res);
+}
+
+isl::pw_aff pw_multi_aff::get_pw_aff(int pos) const {
+  auto res = isl_pw_multi_aff_get_pw_aff(get(), pos);
+  return manage(res);
+}
+
+isl::space pw_multi_aff::get_space() const {
+  auto res = isl_pw_multi_aff_get_space(get());
+  return manage(res);
+}
+
+isl::id pw_multi_aff::get_tuple_id(isl::dim type) const {
+  auto res = isl_pw_multi_aff_get_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+std::string pw_multi_aff::get_tuple_name(isl::dim type) const {
+  auto res = isl_pw_multi_aff_get_tuple_name(get(), static_cast<enum isl_dim_type>(type));
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::pw_multi_aff pw_multi_aff::gist(isl::set set) const {
+  auto res = isl_pw_multi_aff_gist(copy(), set.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::gist_params(isl::set set) const {
+  auto res = isl_pw_multi_aff_gist_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::boolean pw_multi_aff::has_tuple_id(isl::dim type) const {
+  auto res = isl_pw_multi_aff_has_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::boolean pw_multi_aff::has_tuple_name(isl::dim type) const {
+  auto res = isl_pw_multi_aff_has_tuple_name(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::identity(isl::space space) {
+  auto res = isl_pw_multi_aff_identity(space.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::intersect_domain(isl::set set) const {
+  auto res = isl_pw_multi_aff_intersect_domain(copy(), set.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::intersect_params(isl::set set) const {
+  auto res = isl_pw_multi_aff_intersect_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::boolean pw_multi_aff::involves_nan() const {
+  auto res = isl_pw_multi_aff_involves_nan(get());
+  return manage(res);
+}
+
+isl::boolean pw_multi_aff::is_equal(const isl::pw_multi_aff &pma2) const {
+  auto res = isl_pw_multi_aff_is_equal(get(), pma2.get());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::multi_val_on_domain(isl::set domain, isl::multi_val mv) {
+  auto res = isl_pw_multi_aff_multi_val_on_domain(domain.release(), mv.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::neg() const {
+  auto res = isl_pw_multi_aff_neg(copy());
+  return manage(res);
+}
+
+isl::boolean pw_multi_aff::plain_is_equal(const isl::pw_multi_aff &pma2) const {
+  auto res = isl_pw_multi_aff_plain_is_equal(get(), pma2.get());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::product(isl::pw_multi_aff pma2) const {
+  auto res = isl_pw_multi_aff_product(copy(), pma2.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::project_domain_on_params() const {
+  auto res = isl_pw_multi_aff_project_domain_on_params(copy());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::project_out_map(isl::space space, isl::dim type, unsigned int first, unsigned int n) {
+  auto res = isl_pw_multi_aff_project_out_map(space.release(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::pullback(isl::multi_aff ma) const {
+  auto res = isl_pw_multi_aff_pullback_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::pullback(isl::pw_multi_aff pma2) const {
+  auto res = isl_pw_multi_aff_pullback_pw_multi_aff(copy(), pma2.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::range_map(isl::space space) {
+  auto res = isl_pw_multi_aff_range_map(space.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::range_product(isl::pw_multi_aff pma2) const {
+  auto res = isl_pw_multi_aff_range_product(copy(), pma2.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::reset_tuple_id(isl::dim type) const {
+  auto res = isl_pw_multi_aff_reset_tuple_id(copy(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::reset_user() const {
+  auto res = isl_pw_multi_aff_reset_user(copy());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::scale_down_val(isl::val v) const {
+  auto res = isl_pw_multi_aff_scale_down_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::scale_multi_val(isl::multi_val mv) const {
+  auto res = isl_pw_multi_aff_scale_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::scale_val(isl::val v) const {
+  auto res = isl_pw_multi_aff_scale_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::set_dim_id(isl::dim type, unsigned int pos, isl::id id) const {
+  auto res = isl_pw_multi_aff_set_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos, id.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::set_pw_aff(unsigned int pos, isl::pw_aff pa) const {
+  auto res = isl_pw_multi_aff_set_pw_aff(copy(), pos, pa.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::set_tuple_id(isl::dim type, isl::id id) const {
+  auto res = isl_pw_multi_aff_set_tuple_id(copy(), static_cast<enum isl_dim_type>(type), id.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::sub(isl::pw_multi_aff pma2) const {
+  auto res = isl_pw_multi_aff_sub(copy(), pma2.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::subtract_domain(isl::set set) const {
+  auto res = isl_pw_multi_aff_subtract_domain(copy(), set.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::union_add(isl::pw_multi_aff pma2) const {
+  auto res = isl_pw_multi_aff_union_add(copy(), pma2.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::union_lexmax(isl::pw_multi_aff pma2) const {
+  auto res = isl_pw_multi_aff_union_lexmax(copy(), pma2.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::union_lexmin(isl::pw_multi_aff pma2) const {
+  auto res = isl_pw_multi_aff_union_lexmin(copy(), pma2.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff pw_multi_aff::zero(isl::space space) {
+  auto res = isl_pw_multi_aff_zero(space.release());
+  return manage(res);
+}
+
+// implementations for isl::pw_qpolynomial
+isl::pw_qpolynomial manage(__isl_take isl_pw_qpolynomial *ptr) {
+  return pw_qpolynomial(ptr);
+}
+isl::pw_qpolynomial give(__isl_take isl_pw_qpolynomial *ptr) {
+  return manage(ptr);
+}
+
+
+pw_qpolynomial::pw_qpolynomial()
+    : ptr(nullptr) {}
+
+pw_qpolynomial::pw_qpolynomial(const isl::pw_qpolynomial &obj)
+    : ptr(obj.copy()) {}
+pw_qpolynomial::pw_qpolynomial(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+pw_qpolynomial::pw_qpolynomial(__isl_take isl_pw_qpolynomial *ptr)
+    : ptr(ptr) {}
+
+pw_qpolynomial::pw_qpolynomial(isl::ctx ctx, const std::string &str) {
+  auto res = isl_pw_qpolynomial_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+pw_qpolynomial &pw_qpolynomial::operator=(isl::pw_qpolynomial obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+pw_qpolynomial::~pw_qpolynomial() {
+  if (ptr)
+    isl_pw_qpolynomial_free(ptr);
+}
+
+__isl_give isl_pw_qpolynomial *pw_qpolynomial::copy() const & {
+  return isl_pw_qpolynomial_copy(ptr);
+}
+
+__isl_keep isl_pw_qpolynomial *pw_qpolynomial::get() const {
+  return ptr;
+}
+
+__isl_give isl_pw_qpolynomial *pw_qpolynomial::release() {
+  isl_pw_qpolynomial *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool pw_qpolynomial::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_pw_qpolynomial *pw_qpolynomial::keep() const {
+  return get();
+}
+
+__isl_give isl_pw_qpolynomial *pw_qpolynomial::take() {
+  return release();
+}
+
+pw_qpolynomial::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx pw_qpolynomial::get_ctx() const {
+  return isl::ctx(isl_pw_qpolynomial_get_ctx(ptr));
+}
+
+
+std::string pw_qpolynomial::to_str() const {
+  char *Tmp = isl_pw_qpolynomial_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void pw_qpolynomial::dump() const {
+  isl_pw_qpolynomial_dump(get());
+}
+
+
+isl::pw_qpolynomial pw_qpolynomial::add(isl::pw_qpolynomial pwqp2) const {
+  auto res = isl_pw_qpolynomial_add(copy(), pwqp2.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::add_dims(isl::dim type, unsigned int n) const {
+  auto res = isl_pw_qpolynomial_add_dims(copy(), static_cast<enum isl_dim_type>(type), n);
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::alloc(isl::set set, isl::qpolynomial qp) {
+  auto res = isl_pw_qpolynomial_alloc(set.release(), qp.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::coalesce() const {
+  auto res = isl_pw_qpolynomial_coalesce(copy());
+  return manage(res);
+}
+
+unsigned int pw_qpolynomial::dim(isl::dim type) const {
+  auto res = isl_pw_qpolynomial_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::set pw_qpolynomial::domain() const {
+  auto res = isl_pw_qpolynomial_domain(copy());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_pw_qpolynomial_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::val pw_qpolynomial::eval(isl::point pnt) const {
+  auto res = isl_pw_qpolynomial_eval(copy(), pnt.release());
+  return manage(res);
+}
+
+int pw_qpolynomial::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_pw_qpolynomial_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::pw_qpolynomial pw_qpolynomial::fix_val(isl::dim type, unsigned int n, isl::val v) const {
+  auto res = isl_pw_qpolynomial_fix_val(copy(), static_cast<enum isl_dim_type>(type), n, v.release());
+  return manage(res);
+}
+
+isl::stat pw_qpolynomial::foreach_piece(const std::function<isl::stat(isl::set, isl::qpolynomial)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_set *arg_0, isl_qpolynomial *arg_1, void *arg_2) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::set, isl::qpolynomial)> **>(arg_2);
+    stat ret = (*func)(isl::manage(arg_0), isl::manage(arg_1));
+    return isl_stat(ret);
+  };
+  auto res = isl_pw_qpolynomial_foreach_piece(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::from_pw_aff(isl::pw_aff pwaff) {
+  auto res = isl_pw_qpolynomial_from_pw_aff(pwaff.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::from_qpolynomial(isl::qpolynomial qp) {
+  auto res = isl_pw_qpolynomial_from_qpolynomial(qp.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::from_range() const {
+  auto res = isl_pw_qpolynomial_from_range(copy());
+  return manage(res);
+}
+
+isl::space pw_qpolynomial::get_domain_space() const {
+  auto res = isl_pw_qpolynomial_get_domain_space(get());
+  return manage(res);
+}
+
+isl::space pw_qpolynomial::get_space() const {
+  auto res = isl_pw_qpolynomial_get_space(get());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::gist(isl::set context) const {
+  auto res = isl_pw_qpolynomial_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::gist_params(isl::set context) const {
+  auto res = isl_pw_qpolynomial_gist_params(copy(), context.release());
+  return manage(res);
+}
+
+isl::boolean pw_qpolynomial::has_equal_space(const isl::pw_qpolynomial &pwqp2) const {
+  auto res = isl_pw_qpolynomial_has_equal_space(get(), pwqp2.get());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::insert_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_pw_qpolynomial_insert_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::intersect_domain(isl::set set) const {
+  auto res = isl_pw_qpolynomial_intersect_domain(copy(), set.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::intersect_params(isl::set set) const {
+  auto res = isl_pw_qpolynomial_intersect_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::boolean pw_qpolynomial::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_pw_qpolynomial_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean pw_qpolynomial::involves_nan() const {
+  auto res = isl_pw_qpolynomial_involves_nan(get());
+  return manage(res);
+}
+
+isl::boolean pw_qpolynomial::is_zero() const {
+  auto res = isl_pw_qpolynomial_is_zero(get());
+  return manage(res);
+}
+
+isl::val pw_qpolynomial::max() const {
+  auto res = isl_pw_qpolynomial_max(copy());
+  return manage(res);
+}
+
+isl::val pw_qpolynomial::min() const {
+  auto res = isl_pw_qpolynomial_min(copy());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const {
+  auto res = isl_pw_qpolynomial_move_dims(copy(), static_cast<enum isl_dim_type>(dst_type), dst_pos, static_cast<enum isl_dim_type>(src_type), src_pos, n);
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::mul(isl::pw_qpolynomial pwqp2) const {
+  auto res = isl_pw_qpolynomial_mul(copy(), pwqp2.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::neg() const {
+  auto res = isl_pw_qpolynomial_neg(copy());
+  return manage(res);
+}
+
+isl::boolean pw_qpolynomial::plain_is_equal(const isl::pw_qpolynomial &pwqp2) const {
+  auto res = isl_pw_qpolynomial_plain_is_equal(get(), pwqp2.get());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::pow(unsigned int exponent) const {
+  auto res = isl_pw_qpolynomial_pow(copy(), exponent);
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::project_domain_on_params() const {
+  auto res = isl_pw_qpolynomial_project_domain_on_params(copy());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::reset_domain_space(isl::space dim) const {
+  auto res = isl_pw_qpolynomial_reset_domain_space(copy(), dim.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::reset_user() const {
+  auto res = isl_pw_qpolynomial_reset_user(copy());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::scale_down_val(isl::val v) const {
+  auto res = isl_pw_qpolynomial_scale_down_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::scale_val(isl::val v) const {
+  auto res = isl_pw_qpolynomial_scale_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::split_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_pw_qpolynomial_split_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::split_periods(int max_periods) const {
+  auto res = isl_pw_qpolynomial_split_periods(copy(), max_periods);
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::sub(isl::pw_qpolynomial pwqp2) const {
+  auto res = isl_pw_qpolynomial_sub(copy(), pwqp2.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::subtract_domain(isl::set set) const {
+  auto res = isl_pw_qpolynomial_subtract_domain(copy(), set.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::to_polynomial(int sign) const {
+  auto res = isl_pw_qpolynomial_to_polynomial(copy(), sign);
+  return manage(res);
+}
+
+isl::pw_qpolynomial pw_qpolynomial::zero(isl::space dim) {
+  auto res = isl_pw_qpolynomial_zero(dim.release());
+  return manage(res);
+}
+
+// implementations for isl::qpolynomial
+isl::qpolynomial manage(__isl_take isl_qpolynomial *ptr) {
+  return qpolynomial(ptr);
+}
+isl::qpolynomial give(__isl_take isl_qpolynomial *ptr) {
+  return manage(ptr);
+}
+
+
+qpolynomial::qpolynomial()
+    : ptr(nullptr) {}
+
+qpolynomial::qpolynomial(const isl::qpolynomial &obj)
+    : ptr(obj.copy()) {}
+qpolynomial::qpolynomial(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+qpolynomial::qpolynomial(__isl_take isl_qpolynomial *ptr)
+    : ptr(ptr) {}
+
+
+qpolynomial &qpolynomial::operator=(isl::qpolynomial obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+qpolynomial::~qpolynomial() {
+  if (ptr)
+    isl_qpolynomial_free(ptr);
+}
+
+__isl_give isl_qpolynomial *qpolynomial::copy() const & {
+  return isl_qpolynomial_copy(ptr);
+}
+
+__isl_keep isl_qpolynomial *qpolynomial::get() const {
+  return ptr;
+}
+
+__isl_give isl_qpolynomial *qpolynomial::release() {
+  isl_qpolynomial *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool qpolynomial::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_qpolynomial *qpolynomial::keep() const {
+  return get();
+}
+
+__isl_give isl_qpolynomial *qpolynomial::take() {
+  return release();
+}
+
+qpolynomial::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx qpolynomial::get_ctx() const {
+  return isl::ctx(isl_qpolynomial_get_ctx(ptr));
+}
+
+
+
+void qpolynomial::dump() const {
+  isl_qpolynomial_dump(get());
+}
+
+
+isl::qpolynomial qpolynomial::add(isl::qpolynomial qp2) const {
+  auto res = isl_qpolynomial_add(copy(), qp2.release());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::add_dims(isl::dim type, unsigned int n) const {
+  auto res = isl_qpolynomial_add_dims(copy(), static_cast<enum isl_dim_type>(type), n);
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::align_params(isl::space model) const {
+  auto res = isl_qpolynomial_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::stat qpolynomial::as_polynomial_on_domain(const isl::basic_set &bset, const std::function<isl::stat(isl::basic_set, isl::qpolynomial)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_basic_set *arg_0, isl_qpolynomial *arg_1, void *arg_2) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::basic_set, isl::qpolynomial)> **>(arg_2);
+    stat ret = (*func)(isl::manage(arg_0), isl::manage(arg_1));
+    return isl_stat(ret);
+  };
+  auto res = isl_qpolynomial_as_polynomial_on_domain(get(), bset.get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+unsigned int qpolynomial::dim(isl::dim type) const {
+  auto res = isl_qpolynomial_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::qpolynomial qpolynomial::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_qpolynomial_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::val qpolynomial::eval(isl::point pnt) const {
+  auto res = isl_qpolynomial_eval(copy(), pnt.release());
+  return manage(res);
+}
+
+isl::stat qpolynomial::foreach_term(const std::function<isl::stat(isl::term)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_term *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::term)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_qpolynomial_foreach_term(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::qpolynomial qpolynomial::from_aff(isl::aff aff) {
+  auto res = isl_qpolynomial_from_aff(aff.release());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::from_constraint(isl::constraint c, isl::dim type, unsigned int pos) {
+  auto res = isl_qpolynomial_from_constraint(c.release(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::from_term(isl::term term) {
+  auto res = isl_qpolynomial_from_term(term.release());
+  return manage(res);
+}
+
+isl::val qpolynomial::get_constant_val() const {
+  auto res = isl_qpolynomial_get_constant_val(get());
+  return manage(res);
+}
+
+isl::space qpolynomial::get_domain_space() const {
+  auto res = isl_qpolynomial_get_domain_space(get());
+  return manage(res);
+}
+
+isl::space qpolynomial::get_space() const {
+  auto res = isl_qpolynomial_get_space(get());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::gist(isl::set context) const {
+  auto res = isl_qpolynomial_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::gist_params(isl::set context) const {
+  auto res = isl_qpolynomial_gist_params(copy(), context.release());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::homogenize() const {
+  auto res = isl_qpolynomial_homogenize(copy());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::infty_on_domain(isl::space dim) {
+  auto res = isl_qpolynomial_infty_on_domain(dim.release());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::insert_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_qpolynomial_insert_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean qpolynomial::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_qpolynomial_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean qpolynomial::is_infty() const {
+  auto res = isl_qpolynomial_is_infty(get());
+  return manage(res);
+}
+
+isl::boolean qpolynomial::is_nan() const {
+  auto res = isl_qpolynomial_is_nan(get());
+  return manage(res);
+}
+
+isl::boolean qpolynomial::is_neginfty() const {
+  auto res = isl_qpolynomial_is_neginfty(get());
+  return manage(res);
+}
+
+isl::boolean qpolynomial::is_zero() const {
+  auto res = isl_qpolynomial_is_zero(get());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const {
+  auto res = isl_qpolynomial_move_dims(copy(), static_cast<enum isl_dim_type>(dst_type), dst_pos, static_cast<enum isl_dim_type>(src_type), src_pos, n);
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::mul(isl::qpolynomial qp2) const {
+  auto res = isl_qpolynomial_mul(copy(), qp2.release());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::nan_on_domain(isl::space dim) {
+  auto res = isl_qpolynomial_nan_on_domain(dim.release());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::neg() const {
+  auto res = isl_qpolynomial_neg(copy());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::neginfty_on_domain(isl::space dim) {
+  auto res = isl_qpolynomial_neginfty_on_domain(dim.release());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::one_on_domain(isl::space dim) {
+  auto res = isl_qpolynomial_one_on_domain(dim.release());
+  return manage(res);
+}
+
+isl::boolean qpolynomial::plain_is_equal(const isl::qpolynomial &qp2) const {
+  auto res = isl_qpolynomial_plain_is_equal(get(), qp2.get());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::pow(unsigned int power) const {
+  auto res = isl_qpolynomial_pow(copy(), power);
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::project_domain_on_params() const {
+  auto res = isl_qpolynomial_project_domain_on_params(copy());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::scale_down_val(isl::val v) const {
+  auto res = isl_qpolynomial_scale_down_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::scale_val(isl::val v) const {
+  auto res = isl_qpolynomial_scale_val(copy(), v.release());
+  return manage(res);
+}
+
+int qpolynomial::sgn() const {
+  auto res = isl_qpolynomial_sgn(get());
+  return res;
+}
+
+isl::qpolynomial qpolynomial::sub(isl::qpolynomial qp2) const {
+  auto res = isl_qpolynomial_sub(copy(), qp2.release());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::val_on_domain(isl::space space, isl::val val) {
+  auto res = isl_qpolynomial_val_on_domain(space.release(), val.release());
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::var_on_domain(isl::space dim, isl::dim type, unsigned int pos) {
+  auto res = isl_qpolynomial_var_on_domain(dim.release(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::qpolynomial qpolynomial::zero_on_domain(isl::space dim) {
+  auto res = isl_qpolynomial_zero_on_domain(dim.release());
+  return manage(res);
+}
+
+// implementations for isl::schedule
+isl::schedule manage(__isl_take isl_schedule *ptr) {
+  return schedule(ptr);
+}
+isl::schedule give(__isl_take isl_schedule *ptr) {
+  return manage(ptr);
+}
+
+
+schedule::schedule()
+    : ptr(nullptr) {}
+
+schedule::schedule(const isl::schedule &obj)
+    : ptr(obj.copy()) {}
+schedule::schedule(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+schedule::schedule(__isl_take isl_schedule *ptr)
+    : ptr(ptr) {}
+
+schedule::schedule(isl::ctx ctx, const std::string &str) {
+  auto res = isl_schedule_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+schedule &schedule::operator=(isl::schedule obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+schedule::~schedule() {
+  if (ptr)
+    isl_schedule_free(ptr);
+}
+
+__isl_give isl_schedule *schedule::copy() const & {
+  return isl_schedule_copy(ptr);
+}
+
+__isl_keep isl_schedule *schedule::get() const {
+  return ptr;
+}
+
+__isl_give isl_schedule *schedule::release() {
+  isl_schedule *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool schedule::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_schedule *schedule::keep() const {
+  return get();
+}
+
+__isl_give isl_schedule *schedule::take() {
+  return release();
+}
+
+schedule::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx schedule::get_ctx() const {
+  return isl::ctx(isl_schedule_get_ctx(ptr));
+}
+
+
+std::string schedule::to_str() const {
+  char *Tmp = isl_schedule_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void schedule::dump() const {
+  isl_schedule_dump(get());
+}
+
+
+isl::schedule schedule::align_params(isl::space space) const {
+  auto res = isl_schedule_align_params(copy(), space.release());
+  return manage(res);
+}
+
+isl::schedule schedule::empty(isl::space space) {
+  auto res = isl_schedule_empty(space.release());
+  return manage(res);
+}
+
+isl::schedule schedule::from_domain(isl::union_set domain) {
+  auto res = isl_schedule_from_domain(domain.release());
+  return manage(res);
+}
+
+isl::union_set schedule::get_domain() const {
+  auto res = isl_schedule_get_domain(get());
+  return manage(res);
+}
+
+isl::union_map schedule::get_map() const {
+  auto res = isl_schedule_get_map(get());
+  return manage(res);
+}
+
+isl::schedule_node schedule::get_root() const {
+  auto res = isl_schedule_get_root(get());
+  return manage(res);
+}
+
+isl::schedule schedule::gist_domain_params(isl::set context) const {
+  auto res = isl_schedule_gist_domain_params(copy(), context.release());
+  return manage(res);
+}
+
+isl::schedule schedule::insert_context(isl::set context) const {
+  auto res = isl_schedule_insert_context(copy(), context.release());
+  return manage(res);
+}
+
+isl::schedule schedule::insert_guard(isl::set guard) const {
+  auto res = isl_schedule_insert_guard(copy(), guard.release());
+  return manage(res);
+}
+
+isl::schedule schedule::insert_partial_schedule(isl::multi_union_pw_aff partial) const {
+  auto res = isl_schedule_insert_partial_schedule(copy(), partial.release());
+  return manage(res);
+}
+
+isl::schedule schedule::intersect_domain(isl::union_set domain) const {
+  auto res = isl_schedule_intersect_domain(copy(), domain.release());
+  return manage(res);
+}
+
+isl::boolean schedule::plain_is_equal(const isl::schedule &schedule2) const {
+  auto res = isl_schedule_plain_is_equal(get(), schedule2.get());
+  return manage(res);
+}
+
+isl::schedule schedule::pullback(isl::union_pw_multi_aff upma) const {
+  auto res = isl_schedule_pullback_union_pw_multi_aff(copy(), upma.release());
+  return manage(res);
+}
+
+isl::schedule schedule::reset_user() const {
+  auto res = isl_schedule_reset_user(copy());
+  return manage(res);
+}
+
+isl::schedule schedule::sequence(isl::schedule schedule2) const {
+  auto res = isl_schedule_sequence(copy(), schedule2.release());
+  return manage(res);
+}
+
+isl::schedule schedule::set(isl::schedule schedule2) const {
+  auto res = isl_schedule_set(copy(), schedule2.release());
+  return manage(res);
+}
+
+// implementations for isl::schedule_constraints
+isl::schedule_constraints manage(__isl_take isl_schedule_constraints *ptr) {
+  return schedule_constraints(ptr);
+}
+isl::schedule_constraints give(__isl_take isl_schedule_constraints *ptr) {
+  return manage(ptr);
+}
+
+
+schedule_constraints::schedule_constraints()
+    : ptr(nullptr) {}
+
+schedule_constraints::schedule_constraints(const isl::schedule_constraints &obj)
+    : ptr(obj.copy()) {}
+schedule_constraints::schedule_constraints(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+schedule_constraints::schedule_constraints(__isl_take isl_schedule_constraints *ptr)
+    : ptr(ptr) {}
+
+schedule_constraints::schedule_constraints(isl::ctx ctx, const std::string &str) {
+  auto res = isl_schedule_constraints_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+schedule_constraints &schedule_constraints::operator=(isl::schedule_constraints obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+schedule_constraints::~schedule_constraints() {
+  if (ptr)
+    isl_schedule_constraints_free(ptr);
+}
+
+__isl_give isl_schedule_constraints *schedule_constraints::copy() const & {
+  return isl_schedule_constraints_copy(ptr);
+}
+
+__isl_keep isl_schedule_constraints *schedule_constraints::get() const {
+  return ptr;
+}
+
+__isl_give isl_schedule_constraints *schedule_constraints::release() {
+  isl_schedule_constraints *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool schedule_constraints::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_schedule_constraints *schedule_constraints::keep() const {
+  return get();
+}
+
+__isl_give isl_schedule_constraints *schedule_constraints::take() {
+  return release();
+}
+
+schedule_constraints::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx schedule_constraints::get_ctx() const {
+  return isl::ctx(isl_schedule_constraints_get_ctx(ptr));
+}
+
+
+std::string schedule_constraints::to_str() const {
+  char *Tmp = isl_schedule_constraints_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void schedule_constraints::dump() const {
+  isl_schedule_constraints_dump(get());
+}
+
+
+isl::schedule_constraints schedule_constraints::apply(isl::union_map umap) const {
+  auto res = isl_schedule_constraints_apply(copy(), umap.release());
+  return manage(res);
+}
+
+isl::schedule schedule_constraints::compute_schedule() const {
+  auto res = isl_schedule_constraints_compute_schedule(copy());
+  return manage(res);
+}
+
+isl::union_map schedule_constraints::get_coincidence() const {
+  auto res = isl_schedule_constraints_get_coincidence(get());
+  return manage(res);
+}
+
+isl::union_map schedule_constraints::get_conditional_validity() const {
+  auto res = isl_schedule_constraints_get_conditional_validity(get());
+  return manage(res);
+}
+
+isl::union_map schedule_constraints::get_conditional_validity_condition() const {
+  auto res = isl_schedule_constraints_get_conditional_validity_condition(get());
+  return manage(res);
+}
+
+isl::set schedule_constraints::get_context() const {
+  auto res = isl_schedule_constraints_get_context(get());
+  return manage(res);
+}
+
+isl::union_set schedule_constraints::get_domain() const {
+  auto res = isl_schedule_constraints_get_domain(get());
+  return manage(res);
+}
+
+isl::union_map schedule_constraints::get_proximity() const {
+  auto res = isl_schedule_constraints_get_proximity(get());
+  return manage(res);
+}
+
+isl::union_map schedule_constraints::get_validity() const {
+  auto res = isl_schedule_constraints_get_validity(get());
+  return manage(res);
+}
+
+isl::schedule_constraints schedule_constraints::on_domain(isl::union_set domain) {
+  auto res = isl_schedule_constraints_on_domain(domain.release());
+  return manage(res);
+}
+
+isl::schedule_constraints schedule_constraints::set_coincidence(isl::union_map coincidence) const {
+  auto res = isl_schedule_constraints_set_coincidence(copy(), coincidence.release());
+  return manage(res);
+}
+
+isl::schedule_constraints schedule_constraints::set_conditional_validity(isl::union_map condition, isl::union_map validity) const {
+  auto res = isl_schedule_constraints_set_conditional_validity(copy(), condition.release(), validity.release());
+  return manage(res);
+}
+
+isl::schedule_constraints schedule_constraints::set_context(isl::set context) const {
+  auto res = isl_schedule_constraints_set_context(copy(), context.release());
+  return manage(res);
+}
+
+isl::schedule_constraints schedule_constraints::set_proximity(isl::union_map proximity) const {
+  auto res = isl_schedule_constraints_set_proximity(copy(), proximity.release());
+  return manage(res);
+}
+
+isl::schedule_constraints schedule_constraints::set_validity(isl::union_map validity) const {
+  auto res = isl_schedule_constraints_set_validity(copy(), validity.release());
+  return manage(res);
+}
+
+// implementations for isl::schedule_node
+isl::schedule_node manage(__isl_take isl_schedule_node *ptr) {
+  return schedule_node(ptr);
+}
+isl::schedule_node give(__isl_take isl_schedule_node *ptr) {
+  return manage(ptr);
+}
+
+
+schedule_node::schedule_node()
+    : ptr(nullptr) {}
+
+schedule_node::schedule_node(const isl::schedule_node &obj)
+    : ptr(obj.copy()) {}
+schedule_node::schedule_node(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+schedule_node::schedule_node(__isl_take isl_schedule_node *ptr)
+    : ptr(ptr) {}
+
+
+schedule_node &schedule_node::operator=(isl::schedule_node obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+schedule_node::~schedule_node() {
+  if (ptr)
+    isl_schedule_node_free(ptr);
+}
+
+__isl_give isl_schedule_node *schedule_node::copy() const & {
+  return isl_schedule_node_copy(ptr);
+}
+
+__isl_keep isl_schedule_node *schedule_node::get() const {
+  return ptr;
+}
+
+__isl_give isl_schedule_node *schedule_node::release() {
+  isl_schedule_node *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool schedule_node::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_schedule_node *schedule_node::keep() const {
+  return get();
+}
+
+__isl_give isl_schedule_node *schedule_node::take() {
+  return release();
+}
+
+schedule_node::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx schedule_node::get_ctx() const {
+  return isl::ctx(isl_schedule_node_get_ctx(ptr));
+}
+
+
+std::string schedule_node::to_str() const {
+  char *Tmp = isl_schedule_node_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void schedule_node::dump() const {
+  isl_schedule_node_dump(get());
+}
+
+
+isl::schedule_node schedule_node::align_params(isl::space space) const {
+  auto res = isl_schedule_node_align_params(copy(), space.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::ancestor(int generation) const {
+  auto res = isl_schedule_node_ancestor(copy(), generation);
+  return manage(res);
+}
+
+isl::boolean schedule_node::band_member_get_coincident(int pos) const {
+  auto res = isl_schedule_node_band_member_get_coincident(get(), pos);
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::band_member_set_coincident(int pos, int coincident) const {
+  auto res = isl_schedule_node_band_member_set_coincident(copy(), pos, coincident);
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::band_set_ast_build_options(isl::union_set options) const {
+  auto res = isl_schedule_node_band_set_ast_build_options(copy(), options.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::child(int pos) const {
+  auto res = isl_schedule_node_child(copy(), pos);
+  return manage(res);
+}
+
+isl::set schedule_node::context_get_context() const {
+  auto res = isl_schedule_node_context_get_context(get());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::cut() const {
+  auto res = isl_schedule_node_cut(copy());
+  return manage(res);
+}
+
+isl::union_set schedule_node::domain_get_domain() const {
+  auto res = isl_schedule_node_domain_get_domain(get());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff schedule_node::expansion_get_contraction() const {
+  auto res = isl_schedule_node_expansion_get_contraction(get());
+  return manage(res);
+}
+
+isl::union_map schedule_node::expansion_get_expansion() const {
+  auto res = isl_schedule_node_expansion_get_expansion(get());
+  return manage(res);
+}
+
+isl::union_map schedule_node::extension_get_extension() const {
+  auto res = isl_schedule_node_extension_get_extension(get());
+  return manage(res);
+}
+
+isl::union_set schedule_node::filter_get_filter() const {
+  auto res = isl_schedule_node_filter_get_filter(get());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::first_child() const {
+  auto res = isl_schedule_node_first_child(copy());
+  return manage(res);
+}
+
+isl::stat schedule_node::foreach_ancestor_top_down(const std::function<isl::stat(isl::schedule_node)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_schedule_node *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::schedule_node)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_schedule_node_foreach_ancestor_top_down(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::schedule_node schedule_node::from_domain(isl::union_set domain) {
+  auto res = isl_schedule_node_from_domain(domain.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::from_extension(isl::union_map extension) {
+  auto res = isl_schedule_node_from_extension(extension.release());
+  return manage(res);
+}
+
+int schedule_node::get_ancestor_child_position(const isl::schedule_node &ancestor) const {
+  auto res = isl_schedule_node_get_ancestor_child_position(get(), ancestor.get());
+  return res;
+}
+
+isl::schedule_node schedule_node::get_child(int pos) const {
+  auto res = isl_schedule_node_get_child(get(), pos);
+  return manage(res);
+}
+
+int schedule_node::get_child_position() const {
+  auto res = isl_schedule_node_get_child_position(get());
+  return res;
+}
+
+isl::union_set schedule_node::get_domain() const {
+  auto res = isl_schedule_node_get_domain(get());
+  return manage(res);
+}
+
+isl::multi_union_pw_aff schedule_node::get_prefix_schedule_multi_union_pw_aff() const {
+  auto res = isl_schedule_node_get_prefix_schedule_multi_union_pw_aff(get());
+  return manage(res);
+}
+
+isl::union_map schedule_node::get_prefix_schedule_relation() const {
+  auto res = isl_schedule_node_get_prefix_schedule_relation(get());
+  return manage(res);
+}
+
+isl::union_map schedule_node::get_prefix_schedule_union_map() const {
+  auto res = isl_schedule_node_get_prefix_schedule_union_map(get());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff schedule_node::get_prefix_schedule_union_pw_multi_aff() const {
+  auto res = isl_schedule_node_get_prefix_schedule_union_pw_multi_aff(get());
+  return manage(res);
+}
+
+isl::schedule schedule_node::get_schedule() const {
+  auto res = isl_schedule_node_get_schedule(get());
+  return manage(res);
+}
+
+int schedule_node::get_schedule_depth() const {
+  auto res = isl_schedule_node_get_schedule_depth(get());
+  return res;
+}
+
+isl::schedule_node schedule_node::get_shared_ancestor(const isl::schedule_node &node2) const {
+  auto res = isl_schedule_node_get_shared_ancestor(get(), node2.get());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff schedule_node::get_subtree_contraction() const {
+  auto res = isl_schedule_node_get_subtree_contraction(get());
+  return manage(res);
+}
+
+isl::union_map schedule_node::get_subtree_expansion() const {
+  auto res = isl_schedule_node_get_subtree_expansion(get());
+  return manage(res);
+}
+
+isl::union_map schedule_node::get_subtree_schedule_union_map() const {
+  auto res = isl_schedule_node_get_subtree_schedule_union_map(get());
+  return manage(res);
+}
+
+int schedule_node::get_tree_depth() const {
+  auto res = isl_schedule_node_get_tree_depth(get());
+  return res;
+}
+
+isl::union_set schedule_node::get_universe_domain() const {
+  auto res = isl_schedule_node_get_universe_domain(get());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::graft_after(isl::schedule_node graft) const {
+  auto res = isl_schedule_node_graft_after(copy(), graft.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::graft_before(isl::schedule_node graft) const {
+  auto res = isl_schedule_node_graft_before(copy(), graft.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::group(isl::id group_id) const {
+  auto res = isl_schedule_node_group(copy(), group_id.release());
+  return manage(res);
+}
+
+isl::set schedule_node::guard_get_guard() const {
+  auto res = isl_schedule_node_guard_get_guard(get());
+  return manage(res);
+}
+
+isl::boolean schedule_node::has_children() const {
+  auto res = isl_schedule_node_has_children(get());
+  return manage(res);
+}
+
+isl::boolean schedule_node::has_next_sibling() const {
+  auto res = isl_schedule_node_has_next_sibling(get());
+  return manage(res);
+}
+
+isl::boolean schedule_node::has_parent() const {
+  auto res = isl_schedule_node_has_parent(get());
+  return manage(res);
+}
+
+isl::boolean schedule_node::has_previous_sibling() const {
+  auto res = isl_schedule_node_has_previous_sibling(get());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::insert_context(isl::set context) const {
+  auto res = isl_schedule_node_insert_context(copy(), context.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::insert_filter(isl::union_set filter) const {
+  auto res = isl_schedule_node_insert_filter(copy(), filter.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::insert_guard(isl::set context) const {
+  auto res = isl_schedule_node_insert_guard(copy(), context.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::insert_mark(isl::id mark) const {
+  auto res = isl_schedule_node_insert_mark(copy(), mark.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::insert_partial_schedule(isl::multi_union_pw_aff schedule) const {
+  auto res = isl_schedule_node_insert_partial_schedule(copy(), schedule.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::insert_sequence(isl::union_set_list filters) const {
+  auto res = isl_schedule_node_insert_sequence(copy(), filters.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::insert_set(isl::union_set_list filters) const {
+  auto res = isl_schedule_node_insert_set(copy(), filters.release());
+  return manage(res);
+}
+
+isl::boolean schedule_node::is_equal(const isl::schedule_node &node2) const {
+  auto res = isl_schedule_node_is_equal(get(), node2.get());
+  return manage(res);
+}
+
+isl::boolean schedule_node::is_subtree_anchored() const {
+  auto res = isl_schedule_node_is_subtree_anchored(get());
+  return manage(res);
+}
+
+isl::id schedule_node::mark_get_id() const {
+  auto res = isl_schedule_node_mark_get_id(get());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::next_sibling() const {
+  auto res = isl_schedule_node_next_sibling(copy());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::order_after(isl::union_set filter) const {
+  auto res = isl_schedule_node_order_after(copy(), filter.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::order_before(isl::union_set filter) const {
+  auto res = isl_schedule_node_order_before(copy(), filter.release());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::parent() const {
+  auto res = isl_schedule_node_parent(copy());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::previous_sibling() const {
+  auto res = isl_schedule_node_previous_sibling(copy());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::reset_user() const {
+  auto res = isl_schedule_node_reset_user(copy());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::root() const {
+  auto res = isl_schedule_node_root(copy());
+  return manage(res);
+}
+
+isl::schedule_node schedule_node::sequence_splice_child(int pos) const {
+  auto res = isl_schedule_node_sequence_splice_child(copy(), pos);
+  return manage(res);
+}
+
+// implementations for isl::set
+isl::set manage(__isl_take isl_set *ptr) {
+  return set(ptr);
+}
+isl::set give(__isl_take isl_set *ptr) {
+  return manage(ptr);
+}
+
+
+set::set()
+    : ptr(nullptr) {}
+
+set::set(const isl::set &obj)
+    : ptr(obj.copy()) {}
+set::set(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+set::set(__isl_take isl_set *ptr)
+    : ptr(ptr) {}
+
+set::set(isl::union_set uset) {
+  auto res = isl_set_from_union_set(uset.release());
+  ptr = res;
+}
+set::set(isl::ctx ctx, const std::string &str) {
+  auto res = isl_set_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+set::set(isl::basic_set bset) {
+  auto res = isl_set_from_basic_set(bset.release());
+  ptr = res;
+}
+set::set(isl::point pnt) {
+  auto res = isl_set_from_point(pnt.release());
+  ptr = res;
+}
+
+set &set::operator=(isl::set obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+set::~set() {
+  if (ptr)
+    isl_set_free(ptr);
+}
+
+__isl_give isl_set *set::copy() const & {
+  return isl_set_copy(ptr);
+}
+
+__isl_keep isl_set *set::get() const {
+  return ptr;
+}
+
+__isl_give isl_set *set::release() {
+  isl_set *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool set::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_set *set::keep() const {
+  return get();
+}
+
+__isl_give isl_set *set::take() {
+  return release();
+}
+
+set::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx set::get_ctx() const {
+  return isl::ctx(isl_set_get_ctx(ptr));
+}
+
+
+std::string set::to_str() const {
+  char *Tmp = isl_set_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void set::dump() const {
+  isl_set_dump(get());
+}
+
+
+isl::set set::add_constraint(isl::constraint constraint) const {
+  auto res = isl_set_add_constraint(copy(), constraint.release());
+  return manage(res);
+}
+
+isl::set set::add_dims(isl::dim type, unsigned int n) const {
+  auto res = isl_set_add_dims(copy(), static_cast<enum isl_dim_type>(type), n);
+  return manage(res);
+}
+
+isl::basic_set set::affine_hull() const {
+  auto res = isl_set_affine_hull(copy());
+  return manage(res);
+}
+
+isl::set set::align_params(isl::space model) const {
+  auto res = isl_set_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::set set::apply(isl::map map) const {
+  auto res = isl_set_apply(copy(), map.release());
+  return manage(res);
+}
+
+isl::basic_set set::bounded_simple_hull() const {
+  auto res = isl_set_bounded_simple_hull(copy());
+  return manage(res);
+}
+
+isl::set set::box_from_points(isl::point pnt1, isl::point pnt2) {
+  auto res = isl_set_box_from_points(pnt1.release(), pnt2.release());
+  return manage(res);
+}
+
+isl::set set::coalesce() const {
+  auto res = isl_set_coalesce(copy());
+  return manage(res);
+}
+
+isl::basic_set set::coefficients() const {
+  auto res = isl_set_coefficients(copy());
+  return manage(res);
+}
+
+isl::set set::complement() const {
+  auto res = isl_set_complement(copy());
+  return manage(res);
+}
+
+isl::basic_set set::convex_hull() const {
+  auto res = isl_set_convex_hull(copy());
+  return manage(res);
+}
+
+isl::val set::count_val() const {
+  auto res = isl_set_count_val(get());
+  return manage(res);
+}
+
+isl::set set::detect_equalities() const {
+  auto res = isl_set_detect_equalities(copy());
+  return manage(res);
+}
+
+unsigned int set::dim(isl::dim type) const {
+  auto res = isl_set_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::boolean set::dim_has_any_lower_bound(isl::dim type, unsigned int pos) const {
+  auto res = isl_set_dim_has_any_lower_bound(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean set::dim_has_any_upper_bound(isl::dim type, unsigned int pos) const {
+  auto res = isl_set_dim_has_any_upper_bound(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean set::dim_has_lower_bound(isl::dim type, unsigned int pos) const {
+  auto res = isl_set_dim_has_lower_bound(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean set::dim_has_upper_bound(isl::dim type, unsigned int pos) const {
+  auto res = isl_set_dim_has_upper_bound(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean set::dim_is_bounded(isl::dim type, unsigned int pos) const {
+  auto res = isl_set_dim_is_bounded(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::pw_aff set::dim_max(int pos) const {
+  auto res = isl_set_dim_max(copy(), pos);
+  return manage(res);
+}
+
+isl::pw_aff set::dim_min(int pos) const {
+  auto res = isl_set_dim_min(copy(), pos);
+  return manage(res);
+}
+
+isl::set set::drop_constraints_involving_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_set_drop_constraints_involving_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::set set::drop_constraints_not_involving_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_set_drop_constraints_not_involving_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::set set::eliminate(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_set_eliminate(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::set set::empty(isl::space dim) {
+  auto res = isl_set_empty(dim.release());
+  return manage(res);
+}
+
+isl::set set::equate(isl::dim type1, int pos1, isl::dim type2, int pos2) const {
+  auto res = isl_set_equate(copy(), static_cast<enum isl_dim_type>(type1), pos1, static_cast<enum isl_dim_type>(type2), pos2);
+  return manage(res);
+}
+
+int set::find_dim_by_id(isl::dim type, const isl::id &id) const {
+  auto res = isl_set_find_dim_by_id(get(), static_cast<enum isl_dim_type>(type), id.get());
+  return res;
+}
+
+int set::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_set_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::set set::fix_si(isl::dim type, unsigned int pos, int value) const {
+  auto res = isl_set_fix_si(copy(), static_cast<enum isl_dim_type>(type), pos, value);
+  return manage(res);
+}
+
+isl::set set::fix_val(isl::dim type, unsigned int pos, isl::val v) const {
+  auto res = isl_set_fix_val(copy(), static_cast<enum isl_dim_type>(type), pos, v.release());
+  return manage(res);
+}
+
+isl::set set::flat_product(isl::set set2) const {
+  auto res = isl_set_flat_product(copy(), set2.release());
+  return manage(res);
+}
+
+isl::set set::flatten() const {
+  auto res = isl_set_flatten(copy());
+  return manage(res);
+}
+
+isl::map set::flatten_map() const {
+  auto res = isl_set_flatten_map(copy());
+  return manage(res);
+}
+
+int set::follows_at(const isl::set &set2, int pos) const {
+  auto res = isl_set_follows_at(get(), set2.get(), pos);
+  return res;
+}
+
+isl::stat set::foreach_basic_set(const std::function<isl::stat(isl::basic_set)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_basic_set *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::basic_set)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_set_foreach_basic_set(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::stat set::foreach_point(const std::function<isl::stat(isl::point)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_point *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::point)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_set_foreach_point(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::set set::from_multi_pw_aff(isl::multi_pw_aff mpa) {
+  auto res = isl_set_from_multi_pw_aff(mpa.release());
+  return manage(res);
+}
+
+isl::set set::from_params() const {
+  auto res = isl_set_from_params(copy());
+  return manage(res);
+}
+
+isl::set set::from_pw_aff(isl::pw_aff pwaff) {
+  auto res = isl_set_from_pw_aff(pwaff.release());
+  return manage(res);
+}
+
+isl::set set::from_pw_multi_aff(isl::pw_multi_aff pma) {
+  auto res = isl_set_from_pw_multi_aff(pma.release());
+  return manage(res);
+}
+
+isl::basic_set_list set::get_basic_set_list() const {
+  auto res = isl_set_get_basic_set_list(get());
+  return manage(res);
+}
+
+isl::id set::get_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_set_get_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+std::string set::get_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_set_get_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::space set::get_space() const {
+  auto res = isl_set_get_space(get());
+  return manage(res);
+}
+
+isl::id set::get_tuple_id() const {
+  auto res = isl_set_get_tuple_id(get());
+  return manage(res);
+}
+
+std::string set::get_tuple_name() const {
+  auto res = isl_set_get_tuple_name(get());
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::set set::gist(isl::set context) const {
+  auto res = isl_set_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::set set::gist_basic_set(isl::basic_set context) const {
+  auto res = isl_set_gist_basic_set(copy(), context.release());
+  return manage(res);
+}
+
+isl::set set::gist_params(isl::set context) const {
+  auto res = isl_set_gist_params(copy(), context.release());
+  return manage(res);
+}
+
+isl::boolean set::has_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_set_has_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean set::has_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_set_has_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean set::has_equal_space(const isl::set &set2) const {
+  auto res = isl_set_has_equal_space(get(), set2.get());
+  return manage(res);
+}
+
+isl::boolean set::has_tuple_id() const {
+  auto res = isl_set_has_tuple_id(get());
+  return manage(res);
+}
+
+isl::boolean set::has_tuple_name() const {
+  auto res = isl_set_has_tuple_name(get());
+  return manage(res);
+}
+
+isl::map set::identity() const {
+  auto res = isl_set_identity(copy());
+  return manage(res);
+}
+
+isl::pw_aff set::indicator_function() const {
+  auto res = isl_set_indicator_function(copy());
+  return manage(res);
+}
+
+isl::set set::insert_dims(isl::dim type, unsigned int pos, unsigned int n) const {
+  auto res = isl_set_insert_dims(copy(), static_cast<enum isl_dim_type>(type), pos, n);
+  return manage(res);
+}
+
+isl::set set::intersect(isl::set set2) const {
+  auto res = isl_set_intersect(copy(), set2.release());
+  return manage(res);
+}
+
+isl::set set::intersect_params(isl::set params) const {
+  auto res = isl_set_intersect_params(copy(), params.release());
+  return manage(res);
+}
+
+isl::boolean set::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_set_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean set::is_bounded() const {
+  auto res = isl_set_is_bounded(get());
+  return manage(res);
+}
+
+isl::boolean set::is_box() const {
+  auto res = isl_set_is_box(get());
+  return manage(res);
+}
+
+isl::boolean set::is_disjoint(const isl::set &set2) const {
+  auto res = isl_set_is_disjoint(get(), set2.get());
+  return manage(res);
+}
+
+isl::boolean set::is_empty() const {
+  auto res = isl_set_is_empty(get());
+  return manage(res);
+}
+
+isl::boolean set::is_equal(const isl::set &set2) const {
+  auto res = isl_set_is_equal(get(), set2.get());
+  return manage(res);
+}
+
+isl::boolean set::is_params() const {
+  auto res = isl_set_is_params(get());
+  return manage(res);
+}
+
+isl::boolean set::is_singleton() const {
+  auto res = isl_set_is_singleton(get());
+  return manage(res);
+}
+
+isl::boolean set::is_strict_subset(const isl::set &set2) const {
+  auto res = isl_set_is_strict_subset(get(), set2.get());
+  return manage(res);
+}
+
+isl::boolean set::is_subset(const isl::set &set2) const {
+  auto res = isl_set_is_subset(get(), set2.get());
+  return manage(res);
+}
+
+isl::boolean set::is_wrapping() const {
+  auto res = isl_set_is_wrapping(get());
+  return manage(res);
+}
+
+isl::map set::lex_ge_set(isl::set set2) const {
+  auto res = isl_set_lex_ge_set(copy(), set2.release());
+  return manage(res);
+}
+
+isl::map set::lex_gt_set(isl::set set2) const {
+  auto res = isl_set_lex_gt_set(copy(), set2.release());
+  return manage(res);
+}
+
+isl::map set::lex_le_set(isl::set set2) const {
+  auto res = isl_set_lex_le_set(copy(), set2.release());
+  return manage(res);
+}
+
+isl::map set::lex_lt_set(isl::set set2) const {
+  auto res = isl_set_lex_lt_set(copy(), set2.release());
+  return manage(res);
+}
+
+isl::set set::lexmax() const {
+  auto res = isl_set_lexmax(copy());
+  return manage(res);
+}
+
+isl::pw_multi_aff set::lexmax_pw_multi_aff() const {
+  auto res = isl_set_lexmax_pw_multi_aff(copy());
+  return manage(res);
+}
+
+isl::set set::lexmin() const {
+  auto res = isl_set_lexmin(copy());
+  return manage(res);
+}
+
+isl::pw_multi_aff set::lexmin_pw_multi_aff() const {
+  auto res = isl_set_lexmin_pw_multi_aff(copy());
+  return manage(res);
+}
+
+isl::set set::lower_bound_si(isl::dim type, unsigned int pos, int value) const {
+  auto res = isl_set_lower_bound_si(copy(), static_cast<enum isl_dim_type>(type), pos, value);
+  return manage(res);
+}
+
+isl::set set::lower_bound_val(isl::dim type, unsigned int pos, isl::val value) const {
+  auto res = isl_set_lower_bound_val(copy(), static_cast<enum isl_dim_type>(type), pos, value.release());
+  return manage(res);
+}
+
+isl::val set::max_val(const isl::aff &obj) const {
+  auto res = isl_set_max_val(get(), obj.get());
+  return manage(res);
+}
+
+isl::val set::min_val(const isl::aff &obj) const {
+  auto res = isl_set_min_val(get(), obj.get());
+  return manage(res);
+}
+
+isl::set set::move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const {
+  auto res = isl_set_move_dims(copy(), static_cast<enum isl_dim_type>(dst_type), dst_pos, static_cast<enum isl_dim_type>(src_type), src_pos, n);
+  return manage(res);
+}
+
+isl::set set::nat_universe(isl::space dim) {
+  auto res = isl_set_nat_universe(dim.release());
+  return manage(res);
+}
+
+isl::set set::neg() const {
+  auto res = isl_set_neg(copy());
+  return manage(res);
+}
+
+isl::set set::params() const {
+  auto res = isl_set_params(copy());
+  return manage(res);
+}
+
+int set::plain_cmp(const isl::set &set2) const {
+  auto res = isl_set_plain_cmp(get(), set2.get());
+  return res;
+}
+
+isl::val set::plain_get_val_if_fixed(isl::dim type, unsigned int pos) const {
+  auto res = isl_set_plain_get_val_if_fixed(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean set::plain_is_disjoint(const isl::set &set2) const {
+  auto res = isl_set_plain_is_disjoint(get(), set2.get());
+  return manage(res);
+}
+
+isl::boolean set::plain_is_empty() const {
+  auto res = isl_set_plain_is_empty(get());
+  return manage(res);
+}
+
+isl::boolean set::plain_is_equal(const isl::set &set2) const {
+  auto res = isl_set_plain_is_equal(get(), set2.get());
+  return manage(res);
+}
+
+isl::boolean set::plain_is_universe() const {
+  auto res = isl_set_plain_is_universe(get());
+  return manage(res);
+}
+
+isl::basic_set set::plain_unshifted_simple_hull() const {
+  auto res = isl_set_plain_unshifted_simple_hull(copy());
+  return manage(res);
+}
+
+isl::basic_set set::polyhedral_hull() const {
+  auto res = isl_set_polyhedral_hull(copy());
+  return manage(res);
+}
+
+isl::set set::preimage_multi_aff(isl::multi_aff ma) const {
+  auto res = isl_set_preimage_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::set set::preimage_multi_pw_aff(isl::multi_pw_aff mpa) const {
+  auto res = isl_set_preimage_multi_pw_aff(copy(), mpa.release());
+  return manage(res);
+}
+
+isl::set set::preimage_pw_multi_aff(isl::pw_multi_aff pma) const {
+  auto res = isl_set_preimage_pw_multi_aff(copy(), pma.release());
+  return manage(res);
+}
+
+isl::set set::product(isl::set set2) const {
+  auto res = isl_set_product(copy(), set2.release());
+  return manage(res);
+}
+
+isl::map set::project_onto_map(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_set_project_onto_map(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::set set::project_out(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_set_project_out(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::set set::remove_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_set_remove_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::set set::remove_divs() const {
+  auto res = isl_set_remove_divs(copy());
+  return manage(res);
+}
+
+isl::set set::remove_divs_involving_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_set_remove_divs_involving_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::set set::remove_redundancies() const {
+  auto res = isl_set_remove_redundancies(copy());
+  return manage(res);
+}
+
+isl::set set::remove_unknown_divs() const {
+  auto res = isl_set_remove_unknown_divs(copy());
+  return manage(res);
+}
+
+isl::set set::reset_space(isl::space dim) const {
+  auto res = isl_set_reset_space(copy(), dim.release());
+  return manage(res);
+}
+
+isl::set set::reset_tuple_id() const {
+  auto res = isl_set_reset_tuple_id(copy());
+  return manage(res);
+}
+
+isl::set set::reset_user() const {
+  auto res = isl_set_reset_user(copy());
+  return manage(res);
+}
+
+isl::basic_set set::sample() const {
+  auto res = isl_set_sample(copy());
+  return manage(res);
+}
+
+isl::point set::sample_point() const {
+  auto res = isl_set_sample_point(copy());
+  return manage(res);
+}
+
+isl::set set::set_dim_id(isl::dim type, unsigned int pos, isl::id id) const {
+  auto res = isl_set_set_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos, id.release());
+  return manage(res);
+}
+
+isl::set set::set_tuple_id(isl::id id) const {
+  auto res = isl_set_set_tuple_id(copy(), id.release());
+  return manage(res);
+}
+
+isl::set set::set_tuple_name(const std::string &s) const {
+  auto res = isl_set_set_tuple_name(copy(), s.c_str());
+  return manage(res);
+}
+
+isl::basic_set set::simple_hull() const {
+  auto res = isl_set_simple_hull(copy());
+  return manage(res);
+}
+
+int set::size() const {
+  auto res = isl_set_size(get());
+  return res;
+}
+
+isl::basic_set set::solutions() const {
+  auto res = isl_set_solutions(copy());
+  return manage(res);
+}
+
+isl::set set::split_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_set_split_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::set set::subtract(isl::set set2) const {
+  auto res = isl_set_subtract(copy(), set2.release());
+  return manage(res);
+}
+
+isl::set set::sum(isl::set set2) const {
+  auto res = isl_set_sum(copy(), set2.release());
+  return manage(res);
+}
+
+isl::set set::unite(isl::set set2) const {
+  auto res = isl_set_union(copy(), set2.release());
+  return manage(res);
+}
+
+isl::set set::universe(isl::space dim) {
+  auto res = isl_set_universe(dim.release());
+  return manage(res);
+}
+
+isl::basic_set set::unshifted_simple_hull() const {
+  auto res = isl_set_unshifted_simple_hull(copy());
+  return manage(res);
+}
+
+isl::basic_set set::unshifted_simple_hull_from_set_list(isl::set_list list) const {
+  auto res = isl_set_unshifted_simple_hull_from_set_list(copy(), list.release());
+  return manage(res);
+}
+
+isl::map set::unwrap() const {
+  auto res = isl_set_unwrap(copy());
+  return manage(res);
+}
+
+isl::set set::upper_bound_si(isl::dim type, unsigned int pos, int value) const {
+  auto res = isl_set_upper_bound_si(copy(), static_cast<enum isl_dim_type>(type), pos, value);
+  return manage(res);
+}
+
+isl::set set::upper_bound_val(isl::dim type, unsigned int pos, isl::val value) const {
+  auto res = isl_set_upper_bound_val(copy(), static_cast<enum isl_dim_type>(type), pos, value.release());
+  return manage(res);
+}
+
+isl::map set::wrapped_domain_map() const {
+  auto res = isl_set_wrapped_domain_map(copy());
+  return manage(res);
+}
+
+// implementations for isl::set_list
+isl::set_list manage(__isl_take isl_set_list *ptr) {
+  return set_list(ptr);
+}
+isl::set_list give(__isl_take isl_set_list *ptr) {
+  return manage(ptr);
+}
+
+
+set_list::set_list()
+    : ptr(nullptr) {}
+
+set_list::set_list(const isl::set_list &obj)
+    : ptr(obj.copy()) {}
+set_list::set_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+set_list::set_list(__isl_take isl_set_list *ptr)
+    : ptr(ptr) {}
+
+
+set_list &set_list::operator=(isl::set_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+set_list::~set_list() {
+  if (ptr)
+    isl_set_list_free(ptr);
+}
+
+__isl_give isl_set_list *set_list::copy() const & {
+  return isl_set_list_copy(ptr);
+}
+
+__isl_keep isl_set_list *set_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_set_list *set_list::release() {
+  isl_set_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool set_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_set_list *set_list::keep() const {
+  return get();
+}
+
+__isl_give isl_set_list *set_list::take() {
+  return release();
+}
+
+set_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx set_list::get_ctx() const {
+  return isl::ctx(isl_set_list_get_ctx(ptr));
+}
+
+
+
+void set_list::dump() const {
+  isl_set_list_dump(get());
+}
+
+
+
+// implementations for isl::space
+isl::space manage(__isl_take isl_space *ptr) {
+  return space(ptr);
+}
+isl::space give(__isl_take isl_space *ptr) {
+  return manage(ptr);
+}
+
+
+space::space()
+    : ptr(nullptr) {}
+
+space::space(const isl::space &obj)
+    : ptr(obj.copy()) {}
+space::space(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+space::space(__isl_take isl_space *ptr)
+    : ptr(ptr) {}
+
+space::space(isl::ctx ctx, unsigned int nparam, unsigned int n_in, unsigned int n_out) {
+  auto res = isl_space_alloc(ctx.release(), nparam, n_in, n_out);
+  ptr = res;
+}
+space::space(isl::ctx ctx, unsigned int nparam, unsigned int dim) {
+  auto res = isl_space_set_alloc(ctx.release(), nparam, dim);
+  ptr = res;
+}
+
+space &space::operator=(isl::space obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+space::~space() {
+  if (ptr)
+    isl_space_free(ptr);
+}
+
+__isl_give isl_space *space::copy() const & {
+  return isl_space_copy(ptr);
+}
+
+__isl_keep isl_space *space::get() const {
+  return ptr;
+}
+
+__isl_give isl_space *space::release() {
+  isl_space *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool space::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_space *space::keep() const {
+  return get();
+}
+
+__isl_give isl_space *space::take() {
+  return release();
+}
+
+space::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx space::get_ctx() const {
+  return isl::ctx(isl_space_get_ctx(ptr));
+}
+
+
+std::string space::to_str() const {
+  char *Tmp = isl_space_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void space::dump() const {
+  isl_space_dump(get());
+}
+
+
+isl::space space::add_dims(isl::dim type, unsigned int n) const {
+  auto res = isl_space_add_dims(copy(), static_cast<enum isl_dim_type>(type), n);
+  return manage(res);
+}
+
+isl::space space::align_params(isl::space dim2) const {
+  auto res = isl_space_align_params(copy(), dim2.release());
+  return manage(res);
+}
+
+isl::boolean space::can_curry() const {
+  auto res = isl_space_can_curry(get());
+  return manage(res);
+}
+
+isl::boolean space::can_range_curry() const {
+  auto res = isl_space_can_range_curry(get());
+  return manage(res);
+}
+
+isl::boolean space::can_uncurry() const {
+  auto res = isl_space_can_uncurry(get());
+  return manage(res);
+}
+
+isl::boolean space::can_zip() const {
+  auto res = isl_space_can_zip(get());
+  return manage(res);
+}
+
+isl::space space::curry() const {
+  auto res = isl_space_curry(copy());
+  return manage(res);
+}
+
+unsigned int space::dim(isl::dim type) const {
+  auto res = isl_space_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::space space::domain() const {
+  auto res = isl_space_domain(copy());
+  return manage(res);
+}
+
+isl::space space::domain_factor_domain() const {
+  auto res = isl_space_domain_factor_domain(copy());
+  return manage(res);
+}
+
+isl::space space::domain_factor_range() const {
+  auto res = isl_space_domain_factor_range(copy());
+  return manage(res);
+}
+
+isl::boolean space::domain_is_wrapping() const {
+  auto res = isl_space_domain_is_wrapping(get());
+  return manage(res);
+}
+
+isl::space space::domain_map() const {
+  auto res = isl_space_domain_map(copy());
+  return manage(res);
+}
+
+isl::space space::domain_product(isl::space right) const {
+  auto res = isl_space_domain_product(copy(), right.release());
+  return manage(res);
+}
+
+isl::space space::drop_dims(isl::dim type, unsigned int first, unsigned int num) const {
+  auto res = isl_space_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, num);
+  return manage(res);
+}
+
+isl::space space::factor_domain() const {
+  auto res = isl_space_factor_domain(copy());
+  return manage(res);
+}
+
+isl::space space::factor_range() const {
+  auto res = isl_space_factor_range(copy());
+  return manage(res);
+}
+
+int space::find_dim_by_id(isl::dim type, const isl::id &id) const {
+  auto res = isl_space_find_dim_by_id(get(), static_cast<enum isl_dim_type>(type), id.get());
+  return res;
+}
+
+int space::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_space_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::space space::from_domain() const {
+  auto res = isl_space_from_domain(copy());
+  return manage(res);
+}
+
+isl::space space::from_range() const {
+  auto res = isl_space_from_range(copy());
+  return manage(res);
+}
+
+isl::id space::get_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_space_get_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+std::string space::get_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_space_get_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::id space::get_tuple_id(isl::dim type) const {
+  auto res = isl_space_get_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+std::string space::get_tuple_name(isl::dim type) const {
+  auto res = isl_space_get_tuple_name(get(), static_cast<enum isl_dim_type>(type));
+  std::string tmp(res);
+  return tmp;
+}
+
+isl::boolean space::has_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_space_has_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean space::has_dim_name(isl::dim type, unsigned int pos) const {
+  auto res = isl_space_has_dim_name(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+isl::boolean space::has_equal_params(const isl::space &space2) const {
+  auto res = isl_space_has_equal_params(get(), space2.get());
+  return manage(res);
+}
+
+isl::boolean space::has_equal_tuples(const isl::space &space2) const {
+  auto res = isl_space_has_equal_tuples(get(), space2.get());
+  return manage(res);
+}
+
+isl::boolean space::has_tuple_id(isl::dim type) const {
+  auto res = isl_space_has_tuple_id(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::boolean space::has_tuple_name(isl::dim type) const {
+  auto res = isl_space_has_tuple_name(get(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::space space::insert_dims(isl::dim type, unsigned int pos, unsigned int n) const {
+  auto res = isl_space_insert_dims(copy(), static_cast<enum isl_dim_type>(type), pos, n);
+  return manage(res);
+}
+
+isl::boolean space::is_domain(const isl::space &space2) const {
+  auto res = isl_space_is_domain(get(), space2.get());
+  return manage(res);
+}
+
+isl::boolean space::is_equal(const isl::space &space2) const {
+  auto res = isl_space_is_equal(get(), space2.get());
+  return manage(res);
+}
+
+isl::boolean space::is_map() const {
+  auto res = isl_space_is_map(get());
+  return manage(res);
+}
+
+isl::boolean space::is_params() const {
+  auto res = isl_space_is_params(get());
+  return manage(res);
+}
+
+isl::boolean space::is_product() const {
+  auto res = isl_space_is_product(get());
+  return manage(res);
+}
+
+isl::boolean space::is_range(const isl::space &space2) const {
+  auto res = isl_space_is_range(get(), space2.get());
+  return manage(res);
+}
+
+isl::boolean space::is_set() const {
+  auto res = isl_space_is_set(get());
+  return manage(res);
+}
+
+isl::boolean space::is_wrapping() const {
+  auto res = isl_space_is_wrapping(get());
+  return manage(res);
+}
+
+isl::space space::join(isl::space right) const {
+  auto res = isl_space_join(copy(), right.release());
+  return manage(res);
+}
+
+isl::space space::map_from_domain_and_range(isl::space range) const {
+  auto res = isl_space_map_from_domain_and_range(copy(), range.release());
+  return manage(res);
+}
+
+isl::space space::map_from_set() const {
+  auto res = isl_space_map_from_set(copy());
+  return manage(res);
+}
+
+isl::space space::move_dims(isl::dim dst_type, unsigned int dst_pos, isl::dim src_type, unsigned int src_pos, unsigned int n) const {
+  auto res = isl_space_move_dims(copy(), static_cast<enum isl_dim_type>(dst_type), dst_pos, static_cast<enum isl_dim_type>(src_type), src_pos, n);
+  return manage(res);
+}
+
+isl::space space::params() const {
+  auto res = isl_space_params(copy());
+  return manage(res);
+}
+
+isl::space space::params_alloc(isl::ctx ctx, unsigned int nparam) {
+  auto res = isl_space_params_alloc(ctx.release(), nparam);
+  return manage(res);
+}
+
+isl::space space::product(isl::space right) const {
+  auto res = isl_space_product(copy(), right.release());
+  return manage(res);
+}
+
+isl::space space::range() const {
+  auto res = isl_space_range(copy());
+  return manage(res);
+}
+
+isl::space space::range_curry() const {
+  auto res = isl_space_range_curry(copy());
+  return manage(res);
+}
+
+isl::space space::range_factor_domain() const {
+  auto res = isl_space_range_factor_domain(copy());
+  return manage(res);
+}
+
+isl::space space::range_factor_range() const {
+  auto res = isl_space_range_factor_range(copy());
+  return manage(res);
+}
+
+isl::boolean space::range_is_wrapping() const {
+  auto res = isl_space_range_is_wrapping(get());
+  return manage(res);
+}
+
+isl::space space::range_map() const {
+  auto res = isl_space_range_map(copy());
+  return manage(res);
+}
+
+isl::space space::range_product(isl::space right) const {
+  auto res = isl_space_range_product(copy(), right.release());
+  return manage(res);
+}
+
+isl::space space::reset_tuple_id(isl::dim type) const {
+  auto res = isl_space_reset_tuple_id(copy(), static_cast<enum isl_dim_type>(type));
+  return manage(res);
+}
+
+isl::space space::reset_user() const {
+  auto res = isl_space_reset_user(copy());
+  return manage(res);
+}
+
+isl::space space::reverse() const {
+  auto res = isl_space_reverse(copy());
+  return manage(res);
+}
+
+isl::space space::set_dim_id(isl::dim type, unsigned int pos, isl::id id) const {
+  auto res = isl_space_set_dim_id(copy(), static_cast<enum isl_dim_type>(type), pos, id.release());
+  return manage(res);
+}
+
+isl::space space::set_from_params() const {
+  auto res = isl_space_set_from_params(copy());
+  return manage(res);
+}
+
+isl::space space::set_tuple_id(isl::dim type, isl::id id) const {
+  auto res = isl_space_set_tuple_id(copy(), static_cast<enum isl_dim_type>(type), id.release());
+  return manage(res);
+}
+
+isl::space space::set_tuple_name(isl::dim type, const std::string &s) const {
+  auto res = isl_space_set_tuple_name(copy(), static_cast<enum isl_dim_type>(type), s.c_str());
+  return manage(res);
+}
+
+isl::boolean space::tuple_is_equal(isl::dim type1, const isl::space &space2, isl::dim type2) const {
+  auto res = isl_space_tuple_is_equal(get(), static_cast<enum isl_dim_type>(type1), space2.get(), static_cast<enum isl_dim_type>(type2));
+  return manage(res);
+}
+
+isl::space space::uncurry() const {
+  auto res = isl_space_uncurry(copy());
+  return manage(res);
+}
+
+isl::space space::unwrap() const {
+  auto res = isl_space_unwrap(copy());
+  return manage(res);
+}
+
+isl::space space::wrap() const {
+  auto res = isl_space_wrap(copy());
+  return manage(res);
+}
+
+isl::space space::zip() const {
+  auto res = isl_space_zip(copy());
+  return manage(res);
+}
+
+// implementations for isl::term
+isl::term manage(__isl_take isl_term *ptr) {
+  return term(ptr);
+}
+isl::term give(__isl_take isl_term *ptr) {
+  return manage(ptr);
+}
+
+
+term::term()
+    : ptr(nullptr) {}
+
+term::term(const isl::term &obj)
+    : ptr(obj.copy()) {}
+term::term(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+term::term(__isl_take isl_term *ptr)
+    : ptr(ptr) {}
+
+
+term &term::operator=(isl::term obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+term::~term() {
+  if (ptr)
+    isl_term_free(ptr);
+}
+
+__isl_give isl_term *term::copy() const & {
+  return isl_term_copy(ptr);
+}
+
+__isl_keep isl_term *term::get() const {
+  return ptr;
+}
+
+__isl_give isl_term *term::release() {
+  isl_term *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool term::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_term *term::keep() const {
+  return get();
+}
+
+__isl_give isl_term *term::take() {
+  return release();
+}
+
+term::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx term::get_ctx() const {
+  return isl::ctx(isl_term_get_ctx(ptr));
+}
+
+
+
+
+unsigned int term::dim(isl::dim type) const {
+  auto res = isl_term_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::val term::get_coefficient_val() const {
+  auto res = isl_term_get_coefficient_val(get());
+  return manage(res);
+}
+
+isl::aff term::get_div(unsigned int pos) const {
+  auto res = isl_term_get_div(get(), pos);
+  return manage(res);
+}
+
+int term::get_exp(isl::dim type, unsigned int pos) const {
+  auto res = isl_term_get_exp(get(), static_cast<enum isl_dim_type>(type), pos);
+  return res;
+}
+
+// implementations for isl::union_access_info
+isl::union_access_info manage(__isl_take isl_union_access_info *ptr) {
+  return union_access_info(ptr);
+}
+isl::union_access_info give(__isl_take isl_union_access_info *ptr) {
+  return manage(ptr);
+}
+
+
+union_access_info::union_access_info()
+    : ptr(nullptr) {}
+
+union_access_info::union_access_info(const isl::union_access_info &obj)
+    : ptr(obj.copy()) {}
+union_access_info::union_access_info(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+union_access_info::union_access_info(__isl_take isl_union_access_info *ptr)
+    : ptr(ptr) {}
+
+union_access_info::union_access_info(isl::union_map sink) {
+  auto res = isl_union_access_info_from_sink(sink.release());
+  ptr = res;
+}
+
+union_access_info &union_access_info::operator=(isl::union_access_info obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+union_access_info::~union_access_info() {
+  if (ptr)
+    isl_union_access_info_free(ptr);
+}
+
+__isl_give isl_union_access_info *union_access_info::copy() const & {
+  return isl_union_access_info_copy(ptr);
+}
+
+__isl_keep isl_union_access_info *union_access_info::get() const {
+  return ptr;
+}
+
+__isl_give isl_union_access_info *union_access_info::release() {
+  isl_union_access_info *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool union_access_info::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_union_access_info *union_access_info::keep() const {
+  return get();
+}
+
+__isl_give isl_union_access_info *union_access_info::take() {
+  return release();
+}
+
+union_access_info::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx union_access_info::get_ctx() const {
+  return isl::ctx(isl_union_access_info_get_ctx(ptr));
+}
+
+
+std::string union_access_info::to_str() const {
+  char *Tmp = isl_union_access_info_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+
+isl::union_flow union_access_info::compute_flow() const {
+  auto res = isl_union_access_info_compute_flow(copy());
+  return manage(res);
+}
+
+isl::union_access_info union_access_info::set_kill(isl::union_map kill) const {
+  auto res = isl_union_access_info_set_kill(copy(), kill.release());
+  return manage(res);
+}
+
+isl::union_access_info union_access_info::set_may_source(isl::union_map may_source) const {
+  auto res = isl_union_access_info_set_may_source(copy(), may_source.release());
+  return manage(res);
+}
+
+isl::union_access_info union_access_info::set_must_source(isl::union_map must_source) const {
+  auto res = isl_union_access_info_set_must_source(copy(), must_source.release());
+  return manage(res);
+}
+
+isl::union_access_info union_access_info::set_schedule(isl::schedule schedule) const {
+  auto res = isl_union_access_info_set_schedule(copy(), schedule.release());
+  return manage(res);
+}
+
+isl::union_access_info union_access_info::set_schedule_map(isl::union_map schedule_map) const {
+  auto res = isl_union_access_info_set_schedule_map(copy(), schedule_map.release());
+  return manage(res);
+}
+
+// implementations for isl::union_flow
+isl::union_flow manage(__isl_take isl_union_flow *ptr) {
+  return union_flow(ptr);
+}
+isl::union_flow give(__isl_take isl_union_flow *ptr) {
+  return manage(ptr);
+}
+
+
+union_flow::union_flow()
+    : ptr(nullptr) {}
+
+union_flow::union_flow(const isl::union_flow &obj)
+    : ptr(obj.copy()) {}
+union_flow::union_flow(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+union_flow::union_flow(__isl_take isl_union_flow *ptr)
+    : ptr(ptr) {}
+
+
+union_flow &union_flow::operator=(isl::union_flow obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+union_flow::~union_flow() {
+  if (ptr)
+    isl_union_flow_free(ptr);
+}
+
+__isl_give isl_union_flow *union_flow::copy() const & {
+  return isl_union_flow_copy(ptr);
+}
+
+__isl_keep isl_union_flow *union_flow::get() const {
+  return ptr;
+}
+
+__isl_give isl_union_flow *union_flow::release() {
+  isl_union_flow *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool union_flow::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_union_flow *union_flow::keep() const {
+  return get();
+}
+
+__isl_give isl_union_flow *union_flow::take() {
+  return release();
+}
+
+union_flow::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx union_flow::get_ctx() const {
+  return isl::ctx(isl_union_flow_get_ctx(ptr));
+}
+
+
+std::string union_flow::to_str() const {
+  char *Tmp = isl_union_flow_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+
+isl::union_map union_flow::get_full_may_dependence() const {
+  auto res = isl_union_flow_get_full_may_dependence(get());
+  return manage(res);
+}
+
+isl::union_map union_flow::get_full_must_dependence() const {
+  auto res = isl_union_flow_get_full_must_dependence(get());
+  return manage(res);
+}
+
+isl::union_map union_flow::get_may_dependence() const {
+  auto res = isl_union_flow_get_may_dependence(get());
+  return manage(res);
+}
+
+isl::union_map union_flow::get_may_no_source() const {
+  auto res = isl_union_flow_get_may_no_source(get());
+  return manage(res);
+}
+
+isl::union_map union_flow::get_must_dependence() const {
+  auto res = isl_union_flow_get_must_dependence(get());
+  return manage(res);
+}
+
+isl::union_map union_flow::get_must_no_source() const {
+  auto res = isl_union_flow_get_must_no_source(get());
+  return manage(res);
+}
+
+// implementations for isl::union_map
+isl::union_map manage(__isl_take isl_union_map *ptr) {
+  return union_map(ptr);
+}
+isl::union_map give(__isl_take isl_union_map *ptr) {
+  return manage(ptr);
+}
+
+
+union_map::union_map()
+    : ptr(nullptr) {}
+
+union_map::union_map(const isl::union_map &obj)
+    : ptr(obj.copy()) {}
+union_map::union_map(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+union_map::union_map(__isl_take isl_union_map *ptr)
+    : ptr(ptr) {}
+
+union_map::union_map(isl::union_pw_aff upa) {
+  auto res = isl_union_map_from_union_pw_aff(upa.release());
+  ptr = res;
+}
+union_map::union_map(isl::basic_map bmap) {
+  auto res = isl_union_map_from_basic_map(bmap.release());
+  ptr = res;
+}
+union_map::union_map(isl::map map) {
+  auto res = isl_union_map_from_map(map.release());
+  ptr = res;
+}
+union_map::union_map(isl::ctx ctx, const std::string &str) {
+  auto res = isl_union_map_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+union_map &union_map::operator=(isl::union_map obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+union_map::~union_map() {
+  if (ptr)
+    isl_union_map_free(ptr);
+}
+
+__isl_give isl_union_map *union_map::copy() const & {
+  return isl_union_map_copy(ptr);
+}
+
+__isl_keep isl_union_map *union_map::get() const {
+  return ptr;
+}
+
+__isl_give isl_union_map *union_map::release() {
+  isl_union_map *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool union_map::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_union_map *union_map::keep() const {
+  return get();
+}
+
+__isl_give isl_union_map *union_map::take() {
+  return release();
+}
+
+union_map::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx union_map::get_ctx() const {
+  return isl::ctx(isl_union_map_get_ctx(ptr));
+}
+
+
+std::string union_map::to_str() const {
+  char *Tmp = isl_union_map_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void union_map::dump() const {
+  isl_union_map_dump(get());
+}
+
+
+isl::union_map union_map::add_map(isl::map map) const {
+  auto res = isl_union_map_add_map(copy(), map.release());
+  return manage(res);
+}
+
+isl::union_map union_map::affine_hull() const {
+  auto res = isl_union_map_affine_hull(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::align_params(isl::space model) const {
+  auto res = isl_union_map_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::union_map union_map::apply_domain(isl::union_map umap2) const {
+  auto res = isl_union_map_apply_domain(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::apply_range(isl::union_map umap2) const {
+  auto res = isl_union_map_apply_range(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::coalesce() const {
+  auto res = isl_union_map_coalesce(copy());
+  return manage(res);
+}
+
+isl::boolean union_map::contains(const isl::space &space) const {
+  auto res = isl_union_map_contains(get(), space.get());
+  return manage(res);
+}
+
+isl::union_map union_map::curry() const {
+  auto res = isl_union_map_curry(copy());
+  return manage(res);
+}
+
+isl::union_set union_map::deltas() const {
+  auto res = isl_union_map_deltas(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::deltas_map() const {
+  auto res = isl_union_map_deltas_map(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::detect_equalities() const {
+  auto res = isl_union_map_detect_equalities(copy());
+  return manage(res);
+}
+
+unsigned int union_map::dim(isl::dim type) const {
+  auto res = isl_union_map_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::union_set union_map::domain() const {
+  auto res = isl_union_map_domain(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::domain_factor_domain() const {
+  auto res = isl_union_map_domain_factor_domain(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::domain_factor_range() const {
+  auto res = isl_union_map_domain_factor_range(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::domain_map() const {
+  auto res = isl_union_map_domain_map(copy());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_map::domain_map_union_pw_multi_aff() const {
+  auto res = isl_union_map_domain_map_union_pw_multi_aff(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::domain_product(isl::union_map umap2) const {
+  auto res = isl_union_map_domain_product(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::empty(isl::space dim) {
+  auto res = isl_union_map_empty(dim.release());
+  return manage(res);
+}
+
+isl::union_map union_map::eq_at_multi_union_pw_aff(isl::multi_union_pw_aff mupa) const {
+  auto res = isl_union_map_eq_at_multi_union_pw_aff(copy(), mupa.release());
+  return manage(res);
+}
+
+isl::map union_map::extract_map(isl::space dim) const {
+  auto res = isl_union_map_extract_map(get(), dim.release());
+  return manage(res);
+}
+
+isl::union_map union_map::factor_domain() const {
+  auto res = isl_union_map_factor_domain(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::factor_range() const {
+  auto res = isl_union_map_factor_range(copy());
+  return manage(res);
+}
+
+int union_map::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_union_map_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::union_map union_map::fixed_power(isl::val exp) const {
+  auto res = isl_union_map_fixed_power_val(copy(), exp.release());
+  return manage(res);
+}
+
+isl::union_map union_map::flat_domain_product(isl::union_map umap2) const {
+  auto res = isl_union_map_flat_domain_product(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::flat_range_product(isl::union_map umap2) const {
+  auto res = isl_union_map_flat_range_product(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::stat union_map::foreach_map(const std::function<isl::stat(isl::map)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::map)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_union_map_foreach_map(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::union_map union_map::from(isl::union_pw_multi_aff upma) {
+  auto res = isl_union_map_from_union_pw_multi_aff(upma.release());
+  return manage(res);
+}
+
+isl::union_map union_map::from(isl::multi_union_pw_aff mupa) {
+  auto res = isl_union_map_from_multi_union_pw_aff(mupa.release());
+  return manage(res);
+}
+
+isl::union_map union_map::from_domain(isl::union_set uset) {
+  auto res = isl_union_map_from_domain(uset.release());
+  return manage(res);
+}
+
+isl::union_map union_map::from_domain_and_range(isl::union_set domain, isl::union_set range) {
+  auto res = isl_union_map_from_domain_and_range(domain.release(), range.release());
+  return manage(res);
+}
+
+isl::union_map union_map::from_range(isl::union_set uset) {
+  auto res = isl_union_map_from_range(uset.release());
+  return manage(res);
+}
+
+isl::id union_map::get_dim_id(isl::dim type, unsigned int pos) const {
+  auto res = isl_union_map_get_dim_id(get(), static_cast<enum isl_dim_type>(type), pos);
+  return manage(res);
+}
+
+uint32_t union_map::get_hash() const {
+  auto res = isl_union_map_get_hash(get());
+  return res;
+}
+
+isl::space union_map::get_space() const {
+  auto res = isl_union_map_get_space(get());
+  return manage(res);
+}
+
+isl::union_map union_map::gist(isl::union_map context) const {
+  auto res = isl_union_map_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::union_map union_map::gist_domain(isl::union_set uset) const {
+  auto res = isl_union_map_gist_domain(copy(), uset.release());
+  return manage(res);
+}
+
+isl::union_map union_map::gist_params(isl::set set) const {
+  auto res = isl_union_map_gist_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::union_map union_map::gist_range(isl::union_set uset) const {
+  auto res = isl_union_map_gist_range(copy(), uset.release());
+  return manage(res);
+}
+
+isl::union_map union_map::intersect(isl::union_map umap2) const {
+  auto res = isl_union_map_intersect(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::intersect_domain(isl::union_set uset) const {
+  auto res = isl_union_map_intersect_domain(copy(), uset.release());
+  return manage(res);
+}
+
+isl::union_map union_map::intersect_params(isl::set set) const {
+  auto res = isl_union_map_intersect_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::union_map union_map::intersect_range(isl::union_set uset) const {
+  auto res = isl_union_map_intersect_range(copy(), uset.release());
+  return manage(res);
+}
+
+isl::union_map union_map::intersect_range_factor_range(isl::union_map factor) const {
+  auto res = isl_union_map_intersect_range_factor_range(copy(), factor.release());
+  return manage(res);
+}
+
+isl::boolean union_map::involves_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_union_map_involves_dims(get(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::boolean union_map::is_bijective() const {
+  auto res = isl_union_map_is_bijective(get());
+  return manage(res);
+}
+
+isl::boolean union_map::is_disjoint(const isl::union_map &umap2) const {
+  auto res = isl_union_map_is_disjoint(get(), umap2.get());
+  return manage(res);
+}
+
+isl::boolean union_map::is_empty() const {
+  auto res = isl_union_map_is_empty(get());
+  return manage(res);
+}
+
+isl::boolean union_map::is_equal(const isl::union_map &umap2) const {
+  auto res = isl_union_map_is_equal(get(), umap2.get());
+  return manage(res);
+}
+
+isl::boolean union_map::is_identity() const {
+  auto res = isl_union_map_is_identity(get());
+  return manage(res);
+}
+
+isl::boolean union_map::is_injective() const {
+  auto res = isl_union_map_is_injective(get());
+  return manage(res);
+}
+
+isl::boolean union_map::is_single_valued() const {
+  auto res = isl_union_map_is_single_valued(get());
+  return manage(res);
+}
+
+isl::boolean union_map::is_strict_subset(const isl::union_map &umap2) const {
+  auto res = isl_union_map_is_strict_subset(get(), umap2.get());
+  return manage(res);
+}
+
+isl::boolean union_map::is_subset(const isl::union_map &umap2) const {
+  auto res = isl_union_map_is_subset(get(), umap2.get());
+  return manage(res);
+}
+
+isl::union_map union_map::lex_ge_union_map(isl::union_map umap2) const {
+  auto res = isl_union_map_lex_ge_union_map(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::lex_gt_at_multi_union_pw_aff(isl::multi_union_pw_aff mupa) const {
+  auto res = isl_union_map_lex_gt_at_multi_union_pw_aff(copy(), mupa.release());
+  return manage(res);
+}
+
+isl::union_map union_map::lex_gt_union_map(isl::union_map umap2) const {
+  auto res = isl_union_map_lex_gt_union_map(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::lex_le_union_map(isl::union_map umap2) const {
+  auto res = isl_union_map_lex_le_union_map(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::lex_lt_at_multi_union_pw_aff(isl::multi_union_pw_aff mupa) const {
+  auto res = isl_union_map_lex_lt_at_multi_union_pw_aff(copy(), mupa.release());
+  return manage(res);
+}
+
+isl::union_map union_map::lex_lt_union_map(isl::union_map umap2) const {
+  auto res = isl_union_map_lex_lt_union_map(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::lexmax() const {
+  auto res = isl_union_map_lexmax(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::lexmin() const {
+  auto res = isl_union_map_lexmin(copy());
+  return manage(res);
+}
+
+isl::set union_map::params() const {
+  auto res = isl_union_map_params(copy());
+  return manage(res);
+}
+
+isl::boolean union_map::plain_is_injective() const {
+  auto res = isl_union_map_plain_is_injective(get());
+  return manage(res);
+}
+
+isl::union_map union_map::polyhedral_hull() const {
+  auto res = isl_union_map_polyhedral_hull(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::preimage_domain_multi_aff(isl::multi_aff ma) const {
+  auto res = isl_union_map_preimage_domain_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::union_map union_map::preimage_domain_multi_pw_aff(isl::multi_pw_aff mpa) const {
+  auto res = isl_union_map_preimage_domain_multi_pw_aff(copy(), mpa.release());
+  return manage(res);
+}
+
+isl::union_map union_map::preimage_domain_pw_multi_aff(isl::pw_multi_aff pma) const {
+  auto res = isl_union_map_preimage_domain_pw_multi_aff(copy(), pma.release());
+  return manage(res);
+}
+
+isl::union_map union_map::preimage_domain_union_pw_multi_aff(isl::union_pw_multi_aff upma) const {
+  auto res = isl_union_map_preimage_domain_union_pw_multi_aff(copy(), upma.release());
+  return manage(res);
+}
+
+isl::union_map union_map::preimage_range_multi_aff(isl::multi_aff ma) const {
+  auto res = isl_union_map_preimage_range_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::union_map union_map::preimage_range_pw_multi_aff(isl::pw_multi_aff pma) const {
+  auto res = isl_union_map_preimage_range_pw_multi_aff(copy(), pma.release());
+  return manage(res);
+}
+
+isl::union_map union_map::preimage_range_union_pw_multi_aff(isl::union_pw_multi_aff upma) const {
+  auto res = isl_union_map_preimage_range_union_pw_multi_aff(copy(), upma.release());
+  return manage(res);
+}
+
+isl::union_map union_map::product(isl::union_map umap2) const {
+  auto res = isl_union_map_product(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::project_out(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_union_map_project_out(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::union_set union_map::range() const {
+  auto res = isl_union_map_range(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::range_curry() const {
+  auto res = isl_union_map_range_curry(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::range_factor_domain() const {
+  auto res = isl_union_map_range_factor_domain(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::range_factor_range() const {
+  auto res = isl_union_map_range_factor_range(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::range_map() const {
+  auto res = isl_union_map_range_map(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::range_product(isl::union_map umap2) const {
+  auto res = isl_union_map_range_product(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::remove_divs() const {
+  auto res = isl_union_map_remove_divs(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::remove_redundancies() const {
+  auto res = isl_union_map_remove_redundancies(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::reset_user() const {
+  auto res = isl_union_map_reset_user(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::reverse() const {
+  auto res = isl_union_map_reverse(copy());
+  return manage(res);
+}
+
+isl::basic_map union_map::sample() const {
+  auto res = isl_union_map_sample(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::simple_hull() const {
+  auto res = isl_union_map_simple_hull(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::subtract(isl::union_map umap2) const {
+  auto res = isl_union_map_subtract(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::subtract_domain(isl::union_set dom) const {
+  auto res = isl_union_map_subtract_domain(copy(), dom.release());
+  return manage(res);
+}
+
+isl::union_map union_map::subtract_range(isl::union_set dom) const {
+  auto res = isl_union_map_subtract_range(copy(), dom.release());
+  return manage(res);
+}
+
+isl::union_map union_map::uncurry() const {
+  auto res = isl_union_map_uncurry(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::unite(isl::union_map umap2) const {
+  auto res = isl_union_map_union(copy(), umap2.release());
+  return manage(res);
+}
+
+isl::union_map union_map::universe() const {
+  auto res = isl_union_map_universe(copy());
+  return manage(res);
+}
+
+isl::union_set union_map::wrap() const {
+  auto res = isl_union_map_wrap(copy());
+  return manage(res);
+}
+
+isl::union_map union_map::zip() const {
+  auto res = isl_union_map_zip(copy());
+  return manage(res);
+}
+
+// implementations for isl::union_map_list
+isl::union_map_list manage(__isl_take isl_union_map_list *ptr) {
+  return union_map_list(ptr);
+}
+isl::union_map_list give(__isl_take isl_union_map_list *ptr) {
+  return manage(ptr);
+}
+
+
+union_map_list::union_map_list()
+    : ptr(nullptr) {}
+
+union_map_list::union_map_list(const isl::union_map_list &obj)
+    : ptr(obj.copy()) {}
+union_map_list::union_map_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+union_map_list::union_map_list(__isl_take isl_union_map_list *ptr)
+    : ptr(ptr) {}
+
+
+union_map_list &union_map_list::operator=(isl::union_map_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+union_map_list::~union_map_list() {
+  if (ptr)
+    isl_union_map_list_free(ptr);
+}
+
+__isl_give isl_union_map_list *union_map_list::copy() const & {
+  return isl_union_map_list_copy(ptr);
+}
+
+__isl_keep isl_union_map_list *union_map_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_union_map_list *union_map_list::release() {
+  isl_union_map_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool union_map_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_union_map_list *union_map_list::keep() const {
+  return get();
+}
+
+__isl_give isl_union_map_list *union_map_list::take() {
+  return release();
+}
+
+union_map_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx union_map_list::get_ctx() const {
+  return isl::ctx(isl_union_map_list_get_ctx(ptr));
+}
+
+
+
+void union_map_list::dump() const {
+  isl_union_map_list_dump(get());
+}
+
+
+
+// implementations for isl::union_pw_aff
+isl::union_pw_aff manage(__isl_take isl_union_pw_aff *ptr) {
+  return union_pw_aff(ptr);
+}
+isl::union_pw_aff give(__isl_take isl_union_pw_aff *ptr) {
+  return manage(ptr);
+}
+
+
+union_pw_aff::union_pw_aff()
+    : ptr(nullptr) {}
+
+union_pw_aff::union_pw_aff(const isl::union_pw_aff &obj)
+    : ptr(obj.copy()) {}
+union_pw_aff::union_pw_aff(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+union_pw_aff::union_pw_aff(__isl_take isl_union_pw_aff *ptr)
+    : ptr(ptr) {}
+
+union_pw_aff::union_pw_aff(isl::pw_aff pa) {
+  auto res = isl_union_pw_aff_from_pw_aff(pa.release());
+  ptr = res;
+}
+union_pw_aff::union_pw_aff(isl::union_set domain, isl::val v) {
+  auto res = isl_union_pw_aff_val_on_domain(domain.release(), v.release());
+  ptr = res;
+}
+union_pw_aff::union_pw_aff(isl::ctx ctx, const std::string &str) {
+  auto res = isl_union_pw_aff_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+union_pw_aff &union_pw_aff::operator=(isl::union_pw_aff obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+union_pw_aff::~union_pw_aff() {
+  if (ptr)
+    isl_union_pw_aff_free(ptr);
+}
+
+__isl_give isl_union_pw_aff *union_pw_aff::copy() const & {
+  return isl_union_pw_aff_copy(ptr);
+}
+
+__isl_keep isl_union_pw_aff *union_pw_aff::get() const {
+  return ptr;
+}
+
+__isl_give isl_union_pw_aff *union_pw_aff::release() {
+  isl_union_pw_aff *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool union_pw_aff::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_union_pw_aff *union_pw_aff::keep() const {
+  return get();
+}
+
+__isl_give isl_union_pw_aff *union_pw_aff::take() {
+  return release();
+}
+
+union_pw_aff::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx union_pw_aff::get_ctx() const {
+  return isl::ctx(isl_union_pw_aff_get_ctx(ptr));
+}
+
+
+std::string union_pw_aff::to_str() const {
+  char *Tmp = isl_union_pw_aff_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void union_pw_aff::dump() const {
+  isl_union_pw_aff_dump(get());
+}
+
+
+isl::union_pw_aff union_pw_aff::add(isl::union_pw_aff upa2) const {
+  auto res = isl_union_pw_aff_add(copy(), upa2.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::add_pw_aff(isl::pw_aff pa) const {
+  auto res = isl_union_pw_aff_add_pw_aff(copy(), pa.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::aff_on_domain(isl::union_set domain, isl::aff aff) {
+  auto res = isl_union_pw_aff_aff_on_domain(domain.release(), aff.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::align_params(isl::space model) const {
+  auto res = isl_union_pw_aff_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::coalesce() const {
+  auto res = isl_union_pw_aff_coalesce(copy());
+  return manage(res);
+}
+
+unsigned int union_pw_aff::dim(isl::dim type) const {
+  auto res = isl_union_pw_aff_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::union_set union_pw_aff::domain() const {
+  auto res = isl_union_pw_aff_domain(copy());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_union_pw_aff_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::empty(isl::space space) {
+  auto res = isl_union_pw_aff_empty(space.release());
+  return manage(res);
+}
+
+isl::pw_aff union_pw_aff::extract_pw_aff(isl::space space) const {
+  auto res = isl_union_pw_aff_extract_pw_aff(get(), space.release());
+  return manage(res);
+}
+
+int union_pw_aff::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_union_pw_aff_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::union_pw_aff union_pw_aff::floor() const {
+  auto res = isl_union_pw_aff_floor(copy());
+  return manage(res);
+}
+
+isl::stat union_pw_aff::foreach_pw_aff(const std::function<isl::stat(isl::pw_aff)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_pw_aff *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::pw_aff)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_union_pw_aff_foreach_pw_aff(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::space union_pw_aff::get_space() const {
+  auto res = isl_union_pw_aff_get_space(get());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::gist(isl::union_set context) const {
+  auto res = isl_union_pw_aff_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::gist_params(isl::set context) const {
+  auto res = isl_union_pw_aff_gist_params(copy(), context.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::intersect_domain(isl::union_set uset) const {
+  auto res = isl_union_pw_aff_intersect_domain(copy(), uset.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::intersect_params(isl::set set) const {
+  auto res = isl_union_pw_aff_intersect_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::boolean union_pw_aff::involves_nan() const {
+  auto res = isl_union_pw_aff_involves_nan(get());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::mod_val(isl::val f) const {
+  auto res = isl_union_pw_aff_mod_val(copy(), f.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::neg() const {
+  auto res = isl_union_pw_aff_neg(copy());
+  return manage(res);
+}
+
+isl::boolean union_pw_aff::plain_is_equal(const isl::union_pw_aff &upa2) const {
+  auto res = isl_union_pw_aff_plain_is_equal(get(), upa2.get());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::pullback(isl::union_pw_multi_aff upma) const {
+  auto res = isl_union_pw_aff_pullback_union_pw_multi_aff(copy(), upma.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::reset_user() const {
+  auto res = isl_union_pw_aff_reset_user(copy());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::scale_down_val(isl::val v) const {
+  auto res = isl_union_pw_aff_scale_down_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::scale_val(isl::val v) const {
+  auto res = isl_union_pw_aff_scale_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::sub(isl::union_pw_aff upa2) const {
+  auto res = isl_union_pw_aff_sub(copy(), upa2.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::subtract_domain(isl::union_set uset) const {
+  auto res = isl_union_pw_aff_subtract_domain(copy(), uset.release());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_aff::union_add(isl::union_pw_aff upa2) const {
+  auto res = isl_union_pw_aff_union_add(copy(), upa2.release());
+  return manage(res);
+}
+
+isl::union_set union_pw_aff::zero_union_set() const {
+  auto res = isl_union_pw_aff_zero_union_set(copy());
+  return manage(res);
+}
+
+// implementations for isl::union_pw_aff_list
+isl::union_pw_aff_list manage(__isl_take isl_union_pw_aff_list *ptr) {
+  return union_pw_aff_list(ptr);
+}
+isl::union_pw_aff_list give(__isl_take isl_union_pw_aff_list *ptr) {
+  return manage(ptr);
+}
+
+
+union_pw_aff_list::union_pw_aff_list()
+    : ptr(nullptr) {}
+
+union_pw_aff_list::union_pw_aff_list(const isl::union_pw_aff_list &obj)
+    : ptr(obj.copy()) {}
+union_pw_aff_list::union_pw_aff_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+union_pw_aff_list::union_pw_aff_list(__isl_take isl_union_pw_aff_list *ptr)
+    : ptr(ptr) {}
+
+
+union_pw_aff_list &union_pw_aff_list::operator=(isl::union_pw_aff_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+union_pw_aff_list::~union_pw_aff_list() {
+  if (ptr)
+    isl_union_pw_aff_list_free(ptr);
+}
+
+__isl_give isl_union_pw_aff_list *union_pw_aff_list::copy() const & {
+  return isl_union_pw_aff_list_copy(ptr);
+}
+
+__isl_keep isl_union_pw_aff_list *union_pw_aff_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_union_pw_aff_list *union_pw_aff_list::release() {
+  isl_union_pw_aff_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool union_pw_aff_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_union_pw_aff_list *union_pw_aff_list::keep() const {
+  return get();
+}
+
+__isl_give isl_union_pw_aff_list *union_pw_aff_list::take() {
+  return release();
+}
+
+union_pw_aff_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx union_pw_aff_list::get_ctx() const {
+  return isl::ctx(isl_union_pw_aff_list_get_ctx(ptr));
+}
+
+
+
+void union_pw_aff_list::dump() const {
+  isl_union_pw_aff_list_dump(get());
+}
+
+
+
+// implementations for isl::union_pw_multi_aff
+isl::union_pw_multi_aff manage(__isl_take isl_union_pw_multi_aff *ptr) {
+  return union_pw_multi_aff(ptr);
+}
+isl::union_pw_multi_aff give(__isl_take isl_union_pw_multi_aff *ptr) {
+  return manage(ptr);
+}
+
+
+union_pw_multi_aff::union_pw_multi_aff()
+    : ptr(nullptr) {}
+
+union_pw_multi_aff::union_pw_multi_aff(const isl::union_pw_multi_aff &obj)
+    : ptr(obj.copy()) {}
+union_pw_multi_aff::union_pw_multi_aff(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+union_pw_multi_aff::union_pw_multi_aff(__isl_take isl_union_pw_multi_aff *ptr)
+    : ptr(ptr) {}
+
+union_pw_multi_aff::union_pw_multi_aff(isl::pw_multi_aff pma) {
+  auto res = isl_union_pw_multi_aff_from_pw_multi_aff(pma.release());
+  ptr = res;
+}
+union_pw_multi_aff::union_pw_multi_aff(isl::union_set uset) {
+  auto res = isl_union_pw_multi_aff_from_domain(uset.release());
+  ptr = res;
+}
+union_pw_multi_aff::union_pw_multi_aff(isl::union_map umap) {
+  auto res = isl_union_pw_multi_aff_from_union_map(umap.release());
+  ptr = res;
+}
+union_pw_multi_aff::union_pw_multi_aff(isl::ctx ctx, const std::string &str) {
+  auto res = isl_union_pw_multi_aff_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+union_pw_multi_aff::union_pw_multi_aff(isl::union_pw_aff upa) {
+  auto res = isl_union_pw_multi_aff_from_union_pw_aff(upa.release());
+  ptr = res;
+}
+
+union_pw_multi_aff &union_pw_multi_aff::operator=(isl::union_pw_multi_aff obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+union_pw_multi_aff::~union_pw_multi_aff() {
+  if (ptr)
+    isl_union_pw_multi_aff_free(ptr);
+}
+
+__isl_give isl_union_pw_multi_aff *union_pw_multi_aff::copy() const & {
+  return isl_union_pw_multi_aff_copy(ptr);
+}
+
+__isl_keep isl_union_pw_multi_aff *union_pw_multi_aff::get() const {
+  return ptr;
+}
+
+__isl_give isl_union_pw_multi_aff *union_pw_multi_aff::release() {
+  isl_union_pw_multi_aff *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool union_pw_multi_aff::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_union_pw_multi_aff *union_pw_multi_aff::keep() const {
+  return get();
+}
+
+__isl_give isl_union_pw_multi_aff *union_pw_multi_aff::take() {
+  return release();
+}
+
+union_pw_multi_aff::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx union_pw_multi_aff::get_ctx() const {
+  return isl::ctx(isl_union_pw_multi_aff_get_ctx(ptr));
+}
+
+
+std::string union_pw_multi_aff::to_str() const {
+  char *Tmp = isl_union_pw_multi_aff_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void union_pw_multi_aff::dump() const {
+  isl_union_pw_multi_aff_dump(get());
+}
+
+
+isl::union_pw_multi_aff union_pw_multi_aff::add(isl::union_pw_multi_aff upma2) const {
+  auto res = isl_union_pw_multi_aff_add(copy(), upma2.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::add_pw_multi_aff(isl::pw_multi_aff pma) const {
+  auto res = isl_union_pw_multi_aff_add_pw_multi_aff(copy(), pma.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::align_params(isl::space model) const {
+  auto res = isl_union_pw_multi_aff_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::coalesce() const {
+  auto res = isl_union_pw_multi_aff_coalesce(copy());
+  return manage(res);
+}
+
+unsigned int union_pw_multi_aff::dim(isl::dim type) const {
+  auto res = isl_union_pw_multi_aff_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::union_set union_pw_multi_aff::domain() const {
+  auto res = isl_union_pw_multi_aff_domain(copy());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_union_pw_multi_aff_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::empty(isl::space space) {
+  auto res = isl_union_pw_multi_aff_empty(space.release());
+  return manage(res);
+}
+
+isl::pw_multi_aff union_pw_multi_aff::extract_pw_multi_aff(isl::space space) const {
+  auto res = isl_union_pw_multi_aff_extract_pw_multi_aff(get(), space.release());
+  return manage(res);
+}
+
+int union_pw_multi_aff::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_union_pw_multi_aff_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::flat_range_product(isl::union_pw_multi_aff upma2) const {
+  auto res = isl_union_pw_multi_aff_flat_range_product(copy(), upma2.release());
+  return manage(res);
+}
+
+isl::stat union_pw_multi_aff::foreach_pw_multi_aff(const std::function<isl::stat(isl::pw_multi_aff)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_pw_multi_aff *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::pw_multi_aff)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_union_pw_multi_aff_foreach_pw_multi_aff(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::from_aff(isl::aff aff) {
+  auto res = isl_union_pw_multi_aff_from_aff(aff.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::from_multi_union_pw_aff(isl::multi_union_pw_aff mupa) {
+  auto res = isl_union_pw_multi_aff_from_multi_union_pw_aff(mupa.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::from_union_set(isl::union_set uset) {
+  auto res = isl_union_pw_multi_aff_from_union_set(uset.release());
+  return manage(res);
+}
+
+isl::space union_pw_multi_aff::get_space() const {
+  auto res = isl_union_pw_multi_aff_get_space(get());
+  return manage(res);
+}
+
+isl::union_pw_aff union_pw_multi_aff::get_union_pw_aff(int pos) const {
+  auto res = isl_union_pw_multi_aff_get_union_pw_aff(get(), pos);
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::gist(isl::union_set context) const {
+  auto res = isl_union_pw_multi_aff_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::gist_params(isl::set context) const {
+  auto res = isl_union_pw_multi_aff_gist_params(copy(), context.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::intersect_domain(isl::union_set uset) const {
+  auto res = isl_union_pw_multi_aff_intersect_domain(copy(), uset.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::intersect_params(isl::set set) const {
+  auto res = isl_union_pw_multi_aff_intersect_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::boolean union_pw_multi_aff::involves_nan() const {
+  auto res = isl_union_pw_multi_aff_involves_nan(get());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::multi_val_on_domain(isl::union_set domain, isl::multi_val mv) {
+  auto res = isl_union_pw_multi_aff_multi_val_on_domain(domain.release(), mv.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::neg() const {
+  auto res = isl_union_pw_multi_aff_neg(copy());
+  return manage(res);
+}
+
+isl::boolean union_pw_multi_aff::plain_is_equal(const isl::union_pw_multi_aff &upma2) const {
+  auto res = isl_union_pw_multi_aff_plain_is_equal(get(), upma2.get());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::pullback(isl::union_pw_multi_aff upma2) const {
+  auto res = isl_union_pw_multi_aff_pullback_union_pw_multi_aff(copy(), upma2.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::reset_user() const {
+  auto res = isl_union_pw_multi_aff_reset_user(copy());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::scale_down_val(isl::val val) const {
+  auto res = isl_union_pw_multi_aff_scale_down_val(copy(), val.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::scale_multi_val(isl::multi_val mv) const {
+  auto res = isl_union_pw_multi_aff_scale_multi_val(copy(), mv.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::scale_val(isl::val val) const {
+  auto res = isl_union_pw_multi_aff_scale_val(copy(), val.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::sub(isl::union_pw_multi_aff upma2) const {
+  auto res = isl_union_pw_multi_aff_sub(copy(), upma2.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::subtract_domain(isl::union_set uset) const {
+  auto res = isl_union_pw_multi_aff_subtract_domain(copy(), uset.release());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_pw_multi_aff::union_add(isl::union_pw_multi_aff upma2) const {
+  auto res = isl_union_pw_multi_aff_union_add(copy(), upma2.release());
+  return manage(res);
+}
+
+// implementations for isl::union_pw_multi_aff_list
+isl::union_pw_multi_aff_list manage(__isl_take isl_union_pw_multi_aff_list *ptr) {
+  return union_pw_multi_aff_list(ptr);
+}
+isl::union_pw_multi_aff_list give(__isl_take isl_union_pw_multi_aff_list *ptr) {
+  return manage(ptr);
+}
+
+
+union_pw_multi_aff_list::union_pw_multi_aff_list()
+    : ptr(nullptr) {}
+
+union_pw_multi_aff_list::union_pw_multi_aff_list(const isl::union_pw_multi_aff_list &obj)
+    : ptr(obj.copy()) {}
+union_pw_multi_aff_list::union_pw_multi_aff_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+union_pw_multi_aff_list::union_pw_multi_aff_list(__isl_take isl_union_pw_multi_aff_list *ptr)
+    : ptr(ptr) {}
+
+
+union_pw_multi_aff_list &union_pw_multi_aff_list::operator=(isl::union_pw_multi_aff_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+union_pw_multi_aff_list::~union_pw_multi_aff_list() {
+  if (ptr)
+    isl_union_pw_multi_aff_list_free(ptr);
+}
+
+__isl_give isl_union_pw_multi_aff_list *union_pw_multi_aff_list::copy() const & {
+  return isl_union_pw_multi_aff_list_copy(ptr);
+}
+
+__isl_keep isl_union_pw_multi_aff_list *union_pw_multi_aff_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_union_pw_multi_aff_list *union_pw_multi_aff_list::release() {
+  isl_union_pw_multi_aff_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool union_pw_multi_aff_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_union_pw_multi_aff_list *union_pw_multi_aff_list::keep() const {
+  return get();
+}
+
+__isl_give isl_union_pw_multi_aff_list *union_pw_multi_aff_list::take() {
+  return release();
+}
+
+union_pw_multi_aff_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx union_pw_multi_aff_list::get_ctx() const {
+  return isl::ctx(isl_union_pw_multi_aff_list_get_ctx(ptr));
+}
+
+
+
+void union_pw_multi_aff_list::dump() const {
+  isl_union_pw_multi_aff_list_dump(get());
+}
+
+
+
+// implementations for isl::union_pw_qpolynomial
+isl::union_pw_qpolynomial manage(__isl_take isl_union_pw_qpolynomial *ptr) {
+  return union_pw_qpolynomial(ptr);
+}
+isl::union_pw_qpolynomial give(__isl_take isl_union_pw_qpolynomial *ptr) {
+  return manage(ptr);
+}
+
+
+union_pw_qpolynomial::union_pw_qpolynomial()
+    : ptr(nullptr) {}
+
+union_pw_qpolynomial::union_pw_qpolynomial(const isl::union_pw_qpolynomial &obj)
+    : ptr(obj.copy()) {}
+union_pw_qpolynomial::union_pw_qpolynomial(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+union_pw_qpolynomial::union_pw_qpolynomial(__isl_take isl_union_pw_qpolynomial *ptr)
+    : ptr(ptr) {}
+
+union_pw_qpolynomial::union_pw_qpolynomial(isl::ctx ctx, const std::string &str) {
+  auto res = isl_union_pw_qpolynomial_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+union_pw_qpolynomial &union_pw_qpolynomial::operator=(isl::union_pw_qpolynomial obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+union_pw_qpolynomial::~union_pw_qpolynomial() {
+  if (ptr)
+    isl_union_pw_qpolynomial_free(ptr);
+}
+
+__isl_give isl_union_pw_qpolynomial *union_pw_qpolynomial::copy() const & {
+  return isl_union_pw_qpolynomial_copy(ptr);
+}
+
+__isl_keep isl_union_pw_qpolynomial *union_pw_qpolynomial::get() const {
+  return ptr;
+}
+
+__isl_give isl_union_pw_qpolynomial *union_pw_qpolynomial::release() {
+  isl_union_pw_qpolynomial *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool union_pw_qpolynomial::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_union_pw_qpolynomial *union_pw_qpolynomial::keep() const {
+  return get();
+}
+
+__isl_give isl_union_pw_qpolynomial *union_pw_qpolynomial::take() {
+  return release();
+}
+
+union_pw_qpolynomial::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx union_pw_qpolynomial::get_ctx() const {
+  return isl::ctx(isl_union_pw_qpolynomial_get_ctx(ptr));
+}
+
+
+std::string union_pw_qpolynomial::to_str() const {
+  char *Tmp = isl_union_pw_qpolynomial_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::add(isl::union_pw_qpolynomial upwqp2) const {
+  auto res = isl_union_pw_qpolynomial_add(copy(), upwqp2.release());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::add_pw_qpolynomial(isl::pw_qpolynomial pwqp) const {
+  auto res = isl_union_pw_qpolynomial_add_pw_qpolynomial(copy(), pwqp.release());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::align_params(isl::space model) const {
+  auto res = isl_union_pw_qpolynomial_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::coalesce() const {
+  auto res = isl_union_pw_qpolynomial_coalesce(copy());
+  return manage(res);
+}
+
+unsigned int union_pw_qpolynomial::dim(isl::dim type) const {
+  auto res = isl_union_pw_qpolynomial_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::union_set union_pw_qpolynomial::domain() const {
+  auto res = isl_union_pw_qpolynomial_domain(copy());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::drop_dims(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_union_pw_qpolynomial_drop_dims(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::val union_pw_qpolynomial::eval(isl::point pnt) const {
+  auto res = isl_union_pw_qpolynomial_eval(copy(), pnt.release());
+  return manage(res);
+}
+
+isl::pw_qpolynomial union_pw_qpolynomial::extract_pw_qpolynomial(isl::space dim) const {
+  auto res = isl_union_pw_qpolynomial_extract_pw_qpolynomial(get(), dim.release());
+  return manage(res);
+}
+
+int union_pw_qpolynomial::find_dim_by_name(isl::dim type, const std::string &name) const {
+  auto res = isl_union_pw_qpolynomial_find_dim_by_name(get(), static_cast<enum isl_dim_type>(type), name.c_str());
+  return res;
+}
+
+isl::stat union_pw_qpolynomial::foreach_pw_qpolynomial(const std::function<isl::stat(isl::pw_qpolynomial)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_pw_qpolynomial *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::pw_qpolynomial)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::from_pw_qpolynomial(isl::pw_qpolynomial pwqp) {
+  auto res = isl_union_pw_qpolynomial_from_pw_qpolynomial(pwqp.release());
+  return manage(res);
+}
+
+isl::space union_pw_qpolynomial::get_space() const {
+  auto res = isl_union_pw_qpolynomial_get_space(get());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::gist(isl::union_set context) const {
+  auto res = isl_union_pw_qpolynomial_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::gist_params(isl::set context) const {
+  auto res = isl_union_pw_qpolynomial_gist_params(copy(), context.release());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::intersect_domain(isl::union_set uset) const {
+  auto res = isl_union_pw_qpolynomial_intersect_domain(copy(), uset.release());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::intersect_params(isl::set set) const {
+  auto res = isl_union_pw_qpolynomial_intersect_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::boolean union_pw_qpolynomial::involves_nan() const {
+  auto res = isl_union_pw_qpolynomial_involves_nan(get());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::mul(isl::union_pw_qpolynomial upwqp2) const {
+  auto res = isl_union_pw_qpolynomial_mul(copy(), upwqp2.release());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::neg() const {
+  auto res = isl_union_pw_qpolynomial_neg(copy());
+  return manage(res);
+}
+
+isl::boolean union_pw_qpolynomial::plain_is_equal(const isl::union_pw_qpolynomial &upwqp2) const {
+  auto res = isl_union_pw_qpolynomial_plain_is_equal(get(), upwqp2.get());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::reset_user() const {
+  auto res = isl_union_pw_qpolynomial_reset_user(copy());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::scale_down_val(isl::val v) const {
+  auto res = isl_union_pw_qpolynomial_scale_down_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::scale_val(isl::val v) const {
+  auto res = isl_union_pw_qpolynomial_scale_val(copy(), v.release());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::sub(isl::union_pw_qpolynomial upwqp2) const {
+  auto res = isl_union_pw_qpolynomial_sub(copy(), upwqp2.release());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::subtract_domain(isl::union_set uset) const {
+  auto res = isl_union_pw_qpolynomial_subtract_domain(copy(), uset.release());
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::to_polynomial(int sign) const {
+  auto res = isl_union_pw_qpolynomial_to_polynomial(copy(), sign);
+  return manage(res);
+}
+
+isl::union_pw_qpolynomial union_pw_qpolynomial::zero(isl::space dim) {
+  auto res = isl_union_pw_qpolynomial_zero(dim.release());
+  return manage(res);
+}
+
+// implementations for isl::union_set
+isl::union_set manage(__isl_take isl_union_set *ptr) {
+  return union_set(ptr);
+}
+isl::union_set give(__isl_take isl_union_set *ptr) {
+  return manage(ptr);
+}
+
+
+union_set::union_set()
+    : ptr(nullptr) {}
+
+union_set::union_set(const isl::union_set &obj)
+    : ptr(obj.copy()) {}
+union_set::union_set(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+union_set::union_set(__isl_take isl_union_set *ptr)
+    : ptr(ptr) {}
+
+union_set::union_set(isl::point pnt) {
+  auto res = isl_union_set_from_point(pnt.release());
+  ptr = res;
+}
+union_set::union_set(isl::ctx ctx, const std::string &str) {
+  auto res = isl_union_set_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+union_set::union_set(isl::basic_set bset) {
+  auto res = isl_union_set_from_basic_set(bset.release());
+  ptr = res;
+}
+union_set::union_set(isl::set set) {
+  auto res = isl_union_set_from_set(set.release());
+  ptr = res;
+}
+
+union_set &union_set::operator=(isl::union_set obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+union_set::~union_set() {
+  if (ptr)
+    isl_union_set_free(ptr);
+}
+
+__isl_give isl_union_set *union_set::copy() const & {
+  return isl_union_set_copy(ptr);
+}
+
+__isl_keep isl_union_set *union_set::get() const {
+  return ptr;
+}
+
+__isl_give isl_union_set *union_set::release() {
+  isl_union_set *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool union_set::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_union_set *union_set::keep() const {
+  return get();
+}
+
+__isl_give isl_union_set *union_set::take() {
+  return release();
+}
+
+union_set::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx union_set::get_ctx() const {
+  return isl::ctx(isl_union_set_get_ctx(ptr));
+}
+
+
+std::string union_set::to_str() const {
+  char *Tmp = isl_union_set_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void union_set::dump() const {
+  isl_union_set_dump(get());
+}
+
+
+isl::union_set union_set::add_set(isl::set set) const {
+  auto res = isl_union_set_add_set(copy(), set.release());
+  return manage(res);
+}
+
+isl::union_set union_set::affine_hull() const {
+  auto res = isl_union_set_affine_hull(copy());
+  return manage(res);
+}
+
+isl::union_set union_set::align_params(isl::space model) const {
+  auto res = isl_union_set_align_params(copy(), model.release());
+  return manage(res);
+}
+
+isl::union_set union_set::apply(isl::union_map umap) const {
+  auto res = isl_union_set_apply(copy(), umap.release());
+  return manage(res);
+}
+
+isl::union_set union_set::coalesce() const {
+  auto res = isl_union_set_coalesce(copy());
+  return manage(res);
+}
+
+isl::union_set union_set::coefficients() const {
+  auto res = isl_union_set_coefficients(copy());
+  return manage(res);
+}
+
+isl::schedule union_set::compute_schedule(isl::union_map validity, isl::union_map proximity) const {
+  auto res = isl_union_set_compute_schedule(copy(), validity.release(), proximity.release());
+  return manage(res);
+}
+
+isl::boolean union_set::contains(const isl::space &space) const {
+  auto res = isl_union_set_contains(get(), space.get());
+  return manage(res);
+}
+
+isl::union_set union_set::detect_equalities() const {
+  auto res = isl_union_set_detect_equalities(copy());
+  return manage(res);
+}
+
+unsigned int union_set::dim(isl::dim type) const {
+  auto res = isl_union_set_dim(get(), static_cast<enum isl_dim_type>(type));
+  return res;
+}
+
+isl::union_set union_set::empty(isl::space dim) {
+  auto res = isl_union_set_empty(dim.release());
+  return manage(res);
+}
+
+isl::set union_set::extract_set(isl::space dim) const {
+  auto res = isl_union_set_extract_set(get(), dim.release());
+  return manage(res);
+}
+
+isl::stat union_set::foreach_point(const std::function<isl::stat(isl::point)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_point *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::point)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_union_set_foreach_point(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::stat union_set::foreach_set(const std::function<isl::stat(isl::set)> &fn) const {
+  auto fn_p = &fn;
+  auto fn_lambda = [](isl_set *arg_0, void *arg_1) -> isl_stat {
+    auto *func = *static_cast<const std::function<isl::stat(isl::set)> **>(arg_1);
+    stat ret = (*func)(isl::manage(arg_0));
+    return isl_stat(ret);
+  };
+  auto res = isl_union_set_foreach_set(get(), fn_lambda, &fn_p);
+  return isl::stat(res);
+}
+
+isl::basic_set_list union_set::get_basic_set_list() const {
+  auto res = isl_union_set_get_basic_set_list(get());
+  return manage(res);
+}
+
+uint32_t union_set::get_hash() const {
+  auto res = isl_union_set_get_hash(get());
+  return res;
+}
+
+isl::space union_set::get_space() const {
+  auto res = isl_union_set_get_space(get());
+  return manage(res);
+}
+
+isl::union_set union_set::gist(isl::union_set context) const {
+  auto res = isl_union_set_gist(copy(), context.release());
+  return manage(res);
+}
+
+isl::union_set union_set::gist_params(isl::set set) const {
+  auto res = isl_union_set_gist_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::union_map union_set::identity() const {
+  auto res = isl_union_set_identity(copy());
+  return manage(res);
+}
+
+isl::union_pw_multi_aff union_set::identity_union_pw_multi_aff() const {
+  auto res = isl_union_set_identity_union_pw_multi_aff(copy());
+  return manage(res);
+}
+
+isl::union_set union_set::intersect(isl::union_set uset2) const {
+  auto res = isl_union_set_intersect(copy(), uset2.release());
+  return manage(res);
+}
+
+isl::union_set union_set::intersect_params(isl::set set) const {
+  auto res = isl_union_set_intersect_params(copy(), set.release());
+  return manage(res);
+}
+
+isl::boolean union_set::is_disjoint(const isl::union_set &uset2) const {
+  auto res = isl_union_set_is_disjoint(get(), uset2.get());
+  return manage(res);
+}
+
+isl::boolean union_set::is_empty() const {
+  auto res = isl_union_set_is_empty(get());
+  return manage(res);
+}
+
+isl::boolean union_set::is_equal(const isl::union_set &uset2) const {
+  auto res = isl_union_set_is_equal(get(), uset2.get());
+  return manage(res);
+}
+
+isl::boolean union_set::is_params() const {
+  auto res = isl_union_set_is_params(get());
+  return manage(res);
+}
+
+isl::boolean union_set::is_strict_subset(const isl::union_set &uset2) const {
+  auto res = isl_union_set_is_strict_subset(get(), uset2.get());
+  return manage(res);
+}
+
+isl::boolean union_set::is_subset(const isl::union_set &uset2) const {
+  auto res = isl_union_set_is_subset(get(), uset2.get());
+  return manage(res);
+}
+
+isl::union_map union_set::lex_ge_union_set(isl::union_set uset2) const {
+  auto res = isl_union_set_lex_ge_union_set(copy(), uset2.release());
+  return manage(res);
+}
+
+isl::union_map union_set::lex_gt_union_set(isl::union_set uset2) const {
+  auto res = isl_union_set_lex_gt_union_set(copy(), uset2.release());
+  return manage(res);
+}
+
+isl::union_map union_set::lex_le_union_set(isl::union_set uset2) const {
+  auto res = isl_union_set_lex_le_union_set(copy(), uset2.release());
+  return manage(res);
+}
+
+isl::union_map union_set::lex_lt_union_set(isl::union_set uset2) const {
+  auto res = isl_union_set_lex_lt_union_set(copy(), uset2.release());
+  return manage(res);
+}
+
+isl::union_set union_set::lexmax() const {
+  auto res = isl_union_set_lexmax(copy());
+  return manage(res);
+}
+
+isl::union_set union_set::lexmin() const {
+  auto res = isl_union_set_lexmin(copy());
+  return manage(res);
+}
+
+isl::multi_val union_set::min_multi_union_pw_aff(const isl::multi_union_pw_aff &obj) const {
+  auto res = isl_union_set_min_multi_union_pw_aff(get(), obj.get());
+  return manage(res);
+}
+
+isl::set union_set::params() const {
+  auto res = isl_union_set_params(copy());
+  return manage(res);
+}
+
+isl::union_set union_set::polyhedral_hull() const {
+  auto res = isl_union_set_polyhedral_hull(copy());
+  return manage(res);
+}
+
+isl::union_set union_set::preimage_multi_aff(isl::multi_aff ma) const {
+  auto res = isl_union_set_preimage_multi_aff(copy(), ma.release());
+  return manage(res);
+}
+
+isl::union_set union_set::preimage_pw_multi_aff(isl::pw_multi_aff pma) const {
+  auto res = isl_union_set_preimage_pw_multi_aff(copy(), pma.release());
+  return manage(res);
+}
+
+isl::union_set union_set::preimage_union_pw_multi_aff(isl::union_pw_multi_aff upma) const {
+  auto res = isl_union_set_preimage_union_pw_multi_aff(copy(), upma.release());
+  return manage(res);
+}
+
+isl::union_set union_set::product(isl::union_set uset2) const {
+  auto res = isl_union_set_product(copy(), uset2.release());
+  return manage(res);
+}
+
+isl::union_set union_set::project_out(isl::dim type, unsigned int first, unsigned int n) const {
+  auto res = isl_union_set_project_out(copy(), static_cast<enum isl_dim_type>(type), first, n);
+  return manage(res);
+}
+
+isl::union_set union_set::remove_divs() const {
+  auto res = isl_union_set_remove_divs(copy());
+  return manage(res);
+}
+
+isl::union_set union_set::remove_redundancies() const {
+  auto res = isl_union_set_remove_redundancies(copy());
+  return manage(res);
+}
+
+isl::union_set union_set::reset_user() const {
+  auto res = isl_union_set_reset_user(copy());
+  return manage(res);
+}
+
+isl::basic_set union_set::sample() const {
+  auto res = isl_union_set_sample(copy());
+  return manage(res);
+}
+
+isl::point union_set::sample_point() const {
+  auto res = isl_union_set_sample_point(copy());
+  return manage(res);
+}
+
+isl::union_set union_set::simple_hull() const {
+  auto res = isl_union_set_simple_hull(copy());
+  return manage(res);
+}
+
+isl::union_set union_set::solutions() const {
+  auto res = isl_union_set_solutions(copy());
+  return manage(res);
+}
+
+isl::union_set union_set::subtract(isl::union_set uset2) const {
+  auto res = isl_union_set_subtract(copy(), uset2.release());
+  return manage(res);
+}
+
+isl::union_set union_set::unite(isl::union_set uset2) const {
+  auto res = isl_union_set_union(copy(), uset2.release());
+  return manage(res);
+}
+
+isl::union_set union_set::universe() const {
+  auto res = isl_union_set_universe(copy());
+  return manage(res);
+}
+
+isl::union_map union_set::unwrap() const {
+  auto res = isl_union_set_unwrap(copy());
+  return manage(res);
+}
+
+isl::union_map union_set::wrapped_domain_map() const {
+  auto res = isl_union_set_wrapped_domain_map(copy());
+  return manage(res);
+}
+
+// implementations for isl::union_set_list
+isl::union_set_list manage(__isl_take isl_union_set_list *ptr) {
+  return union_set_list(ptr);
+}
+isl::union_set_list give(__isl_take isl_union_set_list *ptr) {
+  return manage(ptr);
+}
+
+
+union_set_list::union_set_list()
+    : ptr(nullptr) {}
+
+union_set_list::union_set_list(const isl::union_set_list &obj)
+    : ptr(obj.copy()) {}
+union_set_list::union_set_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+union_set_list::union_set_list(__isl_take isl_union_set_list *ptr)
+    : ptr(ptr) {}
+
+
+union_set_list &union_set_list::operator=(isl::union_set_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+union_set_list::~union_set_list() {
+  if (ptr)
+    isl_union_set_list_free(ptr);
+}
+
+__isl_give isl_union_set_list *union_set_list::copy() const & {
+  return isl_union_set_list_copy(ptr);
+}
+
+__isl_keep isl_union_set_list *union_set_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_union_set_list *union_set_list::release() {
+  isl_union_set_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool union_set_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_union_set_list *union_set_list::keep() const {
+  return get();
+}
+
+__isl_give isl_union_set_list *union_set_list::take() {
+  return release();
+}
+
+union_set_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx union_set_list::get_ctx() const {
+  return isl::ctx(isl_union_set_list_get_ctx(ptr));
+}
+
+
+
+void union_set_list::dump() const {
+  isl_union_set_list_dump(get());
+}
+
+
+
+// implementations for isl::val
+isl::val manage(__isl_take isl_val *ptr) {
+  return val(ptr);
+}
+isl::val give(__isl_take isl_val *ptr) {
+  return manage(ptr);
+}
+
+
+val::val()
+    : ptr(nullptr) {}
+
+val::val(const isl::val &obj)
+    : ptr(obj.copy()) {}
+val::val(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+val::val(__isl_take isl_val *ptr)
+    : ptr(ptr) {}
+
+val::val(isl::ctx ctx, long i) {
+  auto res = isl_val_int_from_si(ctx.release(), i);
+  ptr = res;
+}
+val::val(isl::ctx ctx, const std::string &str) {
+  auto res = isl_val_read_from_str(ctx.release(), str.c_str());
+  ptr = res;
+}
+
+val &val::operator=(isl::val obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+val::~val() {
+  if (ptr)
+    isl_val_free(ptr);
+}
+
+__isl_give isl_val *val::copy() const & {
+  return isl_val_copy(ptr);
+}
+
+__isl_keep isl_val *val::get() const {
+  return ptr;
+}
+
+__isl_give isl_val *val::release() {
+  isl_val *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool val::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_val *val::keep() const {
+  return get();
+}
+
+__isl_give isl_val *val::take() {
+  return release();
+}
+
+val::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx val::get_ctx() const {
+  return isl::ctx(isl_val_get_ctx(ptr));
+}
+
+
+std::string val::to_str() const {
+  char *Tmp = isl_val_to_str(get());
+  if (!Tmp)
+    return "";
+  std::string S(Tmp);
+  free(Tmp);
+  return S;
+}
+
+
+void val::dump() const {
+  isl_val_dump(get());
+}
+
+
+isl::val val::two_exp() const {
+  auto res = isl_val_2exp(copy());
+  return manage(res);
+}
+
+isl::val val::abs() const {
+  auto res = isl_val_abs(copy());
+  return manage(res);
+}
+
+isl::boolean val::abs_eq(const isl::val &v2) const {
+  auto res = isl_val_abs_eq(get(), v2.get());
+  return manage(res);
+}
+
+isl::val val::add(isl::val v2) const {
+  auto res = isl_val_add(copy(), v2.release());
+  return manage(res);
+}
+
+isl::val val::add_ui(unsigned long v2) const {
+  auto res = isl_val_add_ui(copy(), v2);
+  return manage(res);
+}
+
+isl::val val::ceil() const {
+  auto res = isl_val_ceil(copy());
+  return manage(res);
+}
+
+int val::cmp_si(long i) const {
+  auto res = isl_val_cmp_si(get(), i);
+  return res;
+}
+
+isl::val val::div(isl::val v2) const {
+  auto res = isl_val_div(copy(), v2.release());
+  return manage(res);
+}
+
+isl::val val::div_ui(unsigned long v2) const {
+  auto res = isl_val_div_ui(copy(), v2);
+  return manage(res);
+}
+
+isl::boolean val::eq(const isl::val &v2) const {
+  auto res = isl_val_eq(get(), v2.get());
+  return manage(res);
+}
+
+isl::val val::floor() const {
+  auto res = isl_val_floor(copy());
+  return manage(res);
+}
+
+isl::val val::gcd(isl::val v2) const {
+  auto res = isl_val_gcd(copy(), v2.release());
+  return manage(res);
+}
+
+isl::boolean val::ge(const isl::val &v2) const {
+  auto res = isl_val_ge(get(), v2.get());
+  return manage(res);
+}
+
+uint32_t val::get_hash() const {
+  auto res = isl_val_get_hash(get());
+  return res;
+}
+
+long val::get_num_si() const {
+  auto res = isl_val_get_num_si(get());
+  return res;
+}
+
+isl::boolean val::gt(const isl::val &v2) const {
+  auto res = isl_val_gt(get(), v2.get());
+  return manage(res);
+}
+
+isl::val val::infty(isl::ctx ctx) {
+  auto res = isl_val_infty(ctx.release());
+  return manage(res);
+}
+
+isl::val val::int_from_ui(isl::ctx ctx, unsigned long u) {
+  auto res = isl_val_int_from_ui(ctx.release(), u);
+  return manage(res);
+}
+
+isl::val val::inv() const {
+  auto res = isl_val_inv(copy());
+  return manage(res);
+}
+
+isl::boolean val::is_divisible_by(const isl::val &v2) const {
+  auto res = isl_val_is_divisible_by(get(), v2.get());
+  return manage(res);
+}
+
+isl::boolean val::is_infty() const {
+  auto res = isl_val_is_infty(get());
+  return manage(res);
+}
+
+isl::boolean val::is_int() const {
+  auto res = isl_val_is_int(get());
+  return manage(res);
+}
+
+isl::boolean val::is_nan() const {
+  auto res = isl_val_is_nan(get());
+  return manage(res);
+}
+
+isl::boolean val::is_neg() const {
+  auto res = isl_val_is_neg(get());
+  return manage(res);
+}
+
+isl::boolean val::is_neginfty() const {
+  auto res = isl_val_is_neginfty(get());
+  return manage(res);
+}
+
+isl::boolean val::is_negone() const {
+  auto res = isl_val_is_negone(get());
+  return manage(res);
+}
+
+isl::boolean val::is_nonneg() const {
+  auto res = isl_val_is_nonneg(get());
+  return manage(res);
+}
+
+isl::boolean val::is_nonpos() const {
+  auto res = isl_val_is_nonpos(get());
+  return manage(res);
+}
+
+isl::boolean val::is_one() const {
+  auto res = isl_val_is_one(get());
+  return manage(res);
+}
+
+isl::boolean val::is_pos() const {
+  auto res = isl_val_is_pos(get());
+  return manage(res);
+}
+
+isl::boolean val::is_rat() const {
+  auto res = isl_val_is_rat(get());
+  return manage(res);
+}
+
+isl::boolean val::is_zero() const {
+  auto res = isl_val_is_zero(get());
+  return manage(res);
+}
+
+isl::boolean val::le(const isl::val &v2) const {
+  auto res = isl_val_le(get(), v2.get());
+  return manage(res);
+}
+
+isl::boolean val::lt(const isl::val &v2) const {
+  auto res = isl_val_lt(get(), v2.get());
+  return manage(res);
+}
+
+isl::val val::max(isl::val v2) const {
+  auto res = isl_val_max(copy(), v2.release());
+  return manage(res);
+}
+
+isl::val val::min(isl::val v2) const {
+  auto res = isl_val_min(copy(), v2.release());
+  return manage(res);
+}
+
+isl::val val::mod(isl::val v2) const {
+  auto res = isl_val_mod(copy(), v2.release());
+  return manage(res);
+}
+
+isl::val val::mul(isl::val v2) const {
+  auto res = isl_val_mul(copy(), v2.release());
+  return manage(res);
+}
+
+isl::val val::mul_ui(unsigned long v2) const {
+  auto res = isl_val_mul_ui(copy(), v2);
+  return manage(res);
+}
+
+isl::val val::nan(isl::ctx ctx) {
+  auto res = isl_val_nan(ctx.release());
+  return manage(res);
+}
+
+isl::boolean val::ne(const isl::val &v2) const {
+  auto res = isl_val_ne(get(), v2.get());
+  return manage(res);
+}
+
+isl::val val::neg() const {
+  auto res = isl_val_neg(copy());
+  return manage(res);
+}
+
+isl::val val::neginfty(isl::ctx ctx) {
+  auto res = isl_val_neginfty(ctx.release());
+  return manage(res);
+}
+
+isl::val val::negone(isl::ctx ctx) {
+  auto res = isl_val_negone(ctx.release());
+  return manage(res);
+}
+
+isl::val val::one(isl::ctx ctx) {
+  auto res = isl_val_one(ctx.release());
+  return manage(res);
+}
+
+isl::val val::set_si(long i) const {
+  auto res = isl_val_set_si(copy(), i);
+  return manage(res);
+}
+
+int val::sgn() const {
+  auto res = isl_val_sgn(get());
+  return res;
+}
+
+isl::val val::sub(isl::val v2) const {
+  auto res = isl_val_sub(copy(), v2.release());
+  return manage(res);
+}
+
+isl::val val::sub_ui(unsigned long v2) const {
+  auto res = isl_val_sub_ui(copy(), v2);
+  return manage(res);
+}
+
+isl::val val::trunc() const {
+  auto res = isl_val_trunc(copy());
+  return manage(res);
+}
+
+isl::val val::zero(isl::ctx ctx) {
+  auto res = isl_val_zero(ctx.release());
+  return manage(res);
+}
+
+// implementations for isl::val_list
+isl::val_list manage(__isl_take isl_val_list *ptr) {
+  return val_list(ptr);
+}
+isl::val_list give(__isl_take isl_val_list *ptr) {
+  return manage(ptr);
+}
+
+
+val_list::val_list()
+    : ptr(nullptr) {}
+
+val_list::val_list(const isl::val_list &obj)
+    : ptr(obj.copy()) {}
+val_list::val_list(std::nullptr_t)
+    : ptr(nullptr) {}
+
+
+val_list::val_list(__isl_take isl_val_list *ptr)
+    : ptr(ptr) {}
+
+
+val_list &val_list::operator=(isl::val_list obj) {
+  std::swap(this->ptr, obj.ptr);
+  return *this;
+}
+
+val_list::~val_list() {
+  if (ptr)
+    isl_val_list_free(ptr);
+}
+
+__isl_give isl_val_list *val_list::copy() const & {
+  return isl_val_list_copy(ptr);
+}
+
+__isl_keep isl_val_list *val_list::get() const {
+  return ptr;
+}
+
+__isl_give isl_val_list *val_list::release() {
+  isl_val_list *tmp = ptr;
+  ptr = nullptr;
+  return tmp;
+}
+
+bool val_list::is_null() const {
+  return ptr == nullptr;
+}
+__isl_keep isl_val_list *val_list::keep() const {
+  return get();
+}
+
+__isl_give isl_val_list *val_list::take() {
+  return release();
+}
+
+val_list::operator bool() const {
+  return !is_null();
+}
+
+isl::ctx val_list::get_ctx() const {
+  return isl::ctx(isl_val_list_get_ctx(ptr));
+}
+
+
+
+void val_list::dump() const {
+  isl_val_list_dump(get());
+}
+
+
+} // namespace noexceptions
+} // namespace isl
+
+#endif /* ISL_CPP_NOEXCEPTIONS */
diff --git a/final/lib/External/isl/include/isl/list.h b/final/lib/External/isl/include/isl/list.h
new file mode 100644
index 0000000..803fd3a
--- /dev/null
+++ b/final/lib/External/isl/include/isl/list.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_LIST_H
+#define ISL_LIST_H
+
+#include <isl/ctx.h>
+#include <isl/printer_type.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define ISL_DECLARE_LIST_TYPE(EL)					\
+struct isl_##EL;							\
+struct isl_##EL##_list;							\
+typedef struct isl_##EL##_list isl_##EL##_list;
+#define ISL_DECLARE_LIST_FN(EL)						\
+isl_ctx *isl_##EL##_list_get_ctx(__isl_keep isl_##EL##_list *list);	\
+__isl_give isl_##EL##_list *isl_##EL##_list_from_##EL(			\
+	__isl_take struct isl_##EL *el);				\
+__isl_give isl_##EL##_list *isl_##EL##_list_alloc(isl_ctx *ctx, int n);	\
+__isl_give isl_##EL##_list *isl_##EL##_list_copy(			\
+	__isl_keep isl_##EL##_list *list);				\
+__isl_null isl_##EL##_list *isl_##EL##_list_free(			\
+	__isl_take isl_##EL##_list *list);				\
+__isl_give isl_##EL##_list *isl_##EL##_list_add(			\
+	__isl_take isl_##EL##_list *list,				\
+	__isl_take struct isl_##EL *el);				\
+__isl_give isl_##EL##_list *isl_##EL##_list_insert(			\
+	__isl_take isl_##EL##_list *list, unsigned pos,			\
+	__isl_take struct isl_##EL *el);				\
+__isl_give isl_##EL##_list *isl_##EL##_list_drop(			\
+	__isl_take isl_##EL##_list *list, unsigned first, unsigned n);	\
+__isl_give isl_##EL##_list *isl_##EL##_list_concat(			\
+	__isl_take isl_##EL##_list *list1,				\
+	__isl_take isl_##EL##_list *list2);				\
+int isl_##EL##_list_n_##EL(__isl_keep isl_##EL##_list *list);		\
+__isl_give struct isl_##EL *isl_##EL##_list_get_##EL(			\
+	__isl_keep isl_##EL##_list *list, int index);			\
+__isl_give struct isl_##EL##_list *isl_##EL##_list_set_##EL(		\
+	__isl_take struct isl_##EL##_list *list, int index,		\
+	__isl_take struct isl_##EL *el);				\
+isl_stat isl_##EL##_list_foreach(__isl_keep isl_##EL##_list *list,	\
+	isl_stat (*fn)(__isl_take struct isl_##EL *el, void *user),	\
+	void *user);							\
+__isl_give isl_##EL##_list *isl_##EL##_list_map(			\
+	__isl_take isl_##EL##_list *list,				\
+	__isl_give isl_##EL * (*fn)(__isl_take isl_##EL *el,		\
+		void *user),						\
+	void *user);							\
+__isl_give isl_##EL##_list *isl_##EL##_list_sort(			\
+	__isl_take isl_##EL##_list *list,				\
+	int (*cmp)(__isl_keep struct isl_##EL *a,			\
+		__isl_keep struct isl_##EL *b,				\
+		void *user), void *user);				\
+isl_stat isl_##EL##_list_foreach_scc(__isl_keep isl_##EL##_list *list,	\
+	isl_bool (*follows)(__isl_keep struct isl_##EL *a,		\
+			__isl_keep struct isl_##EL *b, void *user),	\
+	void *follows_user,						\
+	isl_stat (*fn)(__isl_take isl_##EL##_list *scc, void *user),	\
+	void *fn_user);							\
+__isl_give isl_printer *isl_printer_print_##EL##_list(			\
+	__isl_take isl_printer *p, __isl_keep isl_##EL##_list *list);	\
+void isl_##EL##_list_dump(__isl_keep isl_##EL##_list *list);
+
+#define ISL_DECLARE_LIST(EL)						\
+	ISL_DECLARE_LIST_TYPE(EL)					\
+	ISL_DECLARE_LIST_FN(EL)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/local_space.h b/final/lib/External/isl/include/isl/local_space.h
new file mode 100644
index 0000000..5ad8329
--- /dev/null
+++ b/final/lib/External/isl/include/isl/local_space.h
@@ -0,0 +1,95 @@
+#ifndef ISL_LOCAL_SPACE_H
+#define ISL_LOCAL_SPACE_H
+
+#include <isl/aff_type.h>
+#include <isl/space.h>
+#include <isl/printer.h>
+#include <isl/map_type.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_local_space;
+typedef struct isl_local_space isl_local_space;
+
+isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls);
+
+__isl_give isl_local_space *isl_local_space_from_space(__isl_take isl_space *dim);
+
+__isl_give isl_local_space *isl_local_space_copy(
+	__isl_keep isl_local_space *ls);
+__isl_null isl_local_space *isl_local_space_free(
+	__isl_take isl_local_space *ls);
+
+isl_bool isl_local_space_is_params(__isl_keep isl_local_space *ls);
+isl_bool isl_local_space_is_set(__isl_keep isl_local_space *ls);
+
+__isl_give isl_local_space *isl_local_space_set_tuple_id(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, __isl_take isl_id *id);
+
+int isl_local_space_dim(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type);
+isl_bool isl_local_space_has_dim_name(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos);
+const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_local_space *isl_local_space_set_dim_name(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, const char *s);
+isl_bool isl_local_space_has_dim_id(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_id *isl_local_space_get_dim_id(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_local_space *isl_local_space_set_dim_id(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id);
+__isl_give isl_space *isl_local_space_get_space(__isl_keep isl_local_space *ls);
+__isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls,
+	int pos);
+
+int isl_local_space_find_dim_by_name(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, const char *name);
+
+__isl_give isl_local_space *isl_local_space_domain(
+	__isl_take isl_local_space *ls);
+__isl_give isl_local_space *isl_local_space_range(
+	__isl_take isl_local_space *ls);
+__isl_give isl_local_space *isl_local_space_from_domain(
+	__isl_take isl_local_space *ls);
+__isl_give isl_local_space *isl_local_space_add_dims(
+	__isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n);
+__isl_give isl_local_space *isl_local_space_drop_dims(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_local_space *isl_local_space_insert_dims(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+__isl_give isl_local_space *isl_local_space_intersect(
+	__isl_take isl_local_space *ls1, __isl_take isl_local_space *ls2);
+
+__isl_give isl_local_space *isl_local_space_wrap(
+	__isl_take isl_local_space *ls);
+
+isl_bool isl_local_space_is_equal(__isl_keep isl_local_space *ls1,
+	__isl_keep isl_local_space *ls2);
+
+__isl_give isl_basic_map *isl_local_space_lifting(
+	__isl_take isl_local_space *ls);
+
+__isl_give isl_local_space *isl_local_space_flatten_domain(
+	__isl_take isl_local_space *ls);
+__isl_give isl_local_space *isl_local_space_flatten_range(
+	__isl_take isl_local_space *ls);
+
+__isl_give isl_printer *isl_printer_print_local_space(__isl_take isl_printer *p,
+	__isl_keep isl_local_space *ls);
+void isl_local_space_dump(__isl_keep isl_local_space *ls);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/lp.h b/final/lib/External/isl/include/isl/lp.h
new file mode 100644
index 0000000..461ae00
--- /dev/null
+++ b/final/lib/External/isl/include/isl/lp.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_LP_H
+#define ISL_LP_H
+
+#include <isl/aff.h>
+#include <isl/val.h>
+#include <isl/set_type.h>
+
+enum isl_lp_result {
+	isl_lp_error = -1,
+	isl_lp_ok = 0,
+	isl_lp_unbounded,
+	isl_lp_empty
+};
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_val *isl_basic_set_min_lp_val(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_aff *obj);
+__isl_give isl_val *isl_basic_set_max_lp_val(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_aff *obj);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/map.h b/final/lib/External/isl/include/isl/map.h
new file mode 100644
index 0000000..a4e6533
--- /dev/null
+++ b/final/lib/External/isl/include/isl/map.h
@@ -0,0 +1,675 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_MAP_H
+#define ISL_MAP_H
+
+#include <stdio.h>
+
+#include <isl/ctx.h>
+#include <isl/space.h>
+#include <isl/vec.h>
+#include <isl/mat.h>
+#include <isl/printer.h>
+#include <isl/local_space.h>
+#include <isl/aff_type.h>
+#include <isl/list.h>
+#include <isl/map_type.h>
+#include <isl/val.h>
+#include <isl/stdint.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+ISL_DEPRECATED
+unsigned isl_basic_map_n_in(__isl_keep const isl_basic_map *bmap);
+ISL_DEPRECATED
+unsigned isl_basic_map_n_out(__isl_keep const isl_basic_map *bmap);
+ISL_DEPRECATED
+unsigned isl_basic_map_n_param(__isl_keep const isl_basic_map *bmap);
+ISL_DEPRECATED
+unsigned isl_basic_map_n_div(__isl_keep const isl_basic_map *bmap);
+unsigned isl_basic_map_total_dim(__isl_keep const isl_basic_map *bmap);
+unsigned isl_basic_map_dim(__isl_keep isl_basic_map *bmap,
+				enum isl_dim_type type);
+
+ISL_DEPRECATED
+unsigned isl_map_n_in(__isl_keep const isl_map *map);
+ISL_DEPRECATED
+unsigned isl_map_n_out(__isl_keep const isl_map *map);
+ISL_DEPRECATED
+unsigned isl_map_n_param(__isl_keep const isl_map *map);
+unsigned isl_map_dim(__isl_keep isl_map *map, enum isl_dim_type type);
+
+isl_ctx *isl_basic_map_get_ctx(__isl_keep isl_basic_map *bmap);
+isl_ctx *isl_map_get_ctx(__isl_keep isl_map *map);
+__isl_give isl_space *isl_basic_map_get_space(__isl_keep isl_basic_map *bmap);
+__isl_give isl_space *isl_map_get_space(__isl_keep isl_map *map);
+
+__isl_give isl_aff *isl_basic_map_get_div(__isl_keep isl_basic_map *bmap,
+	int pos);
+
+__isl_give isl_local_space *isl_basic_map_get_local_space(
+	__isl_keep isl_basic_map *bmap);
+
+__isl_give isl_basic_map *isl_basic_map_set_tuple_name(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type, const char *s);
+const char *isl_basic_map_get_tuple_name(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type);
+isl_bool isl_map_has_tuple_name(__isl_keep isl_map *map,
+	enum isl_dim_type type);
+const char *isl_map_get_tuple_name(__isl_keep isl_map *map,
+	enum isl_dim_type type);
+__isl_give isl_map *isl_map_set_tuple_name(__isl_take isl_map *map,
+	enum isl_dim_type type, const char *s);
+const char *isl_basic_map_get_dim_name(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos);
+isl_bool isl_map_has_dim_name(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos);
+const char *isl_map_get_dim_name(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_basic_map *isl_basic_map_set_dim_name(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, const char *s);
+__isl_give isl_map *isl_map_set_dim_name(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, const char *s);
+
+__isl_give isl_basic_map *isl_basic_map_set_tuple_id(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, __isl_take isl_id *id);
+__isl_give isl_map *isl_map_set_dim_id(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id);
+isl_bool isl_basic_map_has_dim_id(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos);
+isl_bool isl_map_has_dim_id(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_id *isl_map_get_dim_id(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_map *isl_map_set_tuple_id(__isl_take isl_map *map,
+	enum isl_dim_type type, __isl_take isl_id *id);
+__isl_give isl_map *isl_map_reset_tuple_id(__isl_take isl_map *map,
+	enum isl_dim_type type);
+isl_bool isl_map_has_tuple_id(__isl_keep isl_map *map, enum isl_dim_type type);
+__isl_give isl_id *isl_map_get_tuple_id(__isl_keep isl_map *map,
+	enum isl_dim_type type);
+__isl_give isl_map *isl_map_reset_user(__isl_take isl_map *map);
+
+int isl_basic_map_find_dim_by_name(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, const char *name);
+int isl_map_find_dim_by_id(__isl_keep isl_map *map, enum isl_dim_type type,
+	__isl_keep isl_id *id);
+int isl_map_find_dim_by_name(__isl_keep isl_map *map, enum isl_dim_type type,
+	const char *name);
+
+isl_bool isl_basic_map_is_rational(__isl_keep isl_basic_map *bmap);
+
+__isl_give isl_basic_map *isl_basic_map_identity(__isl_take isl_space *dim);
+__isl_null isl_basic_map *isl_basic_map_free(__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_map *isl_basic_map_copy(__isl_keep isl_basic_map *bmap);
+__isl_give isl_basic_map *isl_basic_map_equal(
+	__isl_take isl_space *dim, unsigned n_equal);
+__isl_give isl_basic_map *isl_basic_map_less_at(__isl_take isl_space *dim,
+	unsigned pos);
+__isl_give isl_basic_map *isl_basic_map_more_at(__isl_take isl_space *dim,
+	unsigned pos);
+__isl_give isl_basic_map *isl_basic_map_empty(__isl_take isl_space *dim);
+__isl_give isl_basic_map *isl_basic_map_universe(__isl_take isl_space *dim);
+__isl_give isl_basic_map *isl_basic_map_nat_universe(__isl_take isl_space *dim);
+__isl_give isl_basic_map *isl_basic_map_remove_redundancies(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_remove_redundancies(__isl_take isl_map *map);
+__isl_give isl_basic_map *isl_map_simple_hull(__isl_take isl_map *map);
+__isl_export
+__isl_give isl_basic_map *isl_map_unshifted_simple_hull(
+	__isl_take isl_map *map);
+__isl_give isl_basic_map *isl_map_plain_unshifted_simple_hull(
+	__isl_take isl_map *map);
+__isl_give isl_basic_map *isl_map_unshifted_simple_hull_from_map_list(
+	__isl_take isl_map *map, __isl_take isl_map_list *list);
+
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_intersect_domain(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_basic_set *bset);
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_intersect_range(
+		__isl_take isl_basic_map *bmap,
+		__isl_take isl_basic_set *bset);
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_intersect(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+__isl_give isl_basic_map *isl_basic_map_list_intersect(
+	__isl_take isl_basic_map_list *list);
+__isl_export
+__isl_give isl_map *isl_basic_map_union(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_apply_domain(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_apply_range(
+		__isl_take isl_basic_map *bmap1,
+		__isl_take isl_basic_map *bmap2);
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_affine_hull(
+		__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_map *isl_basic_map_preimage_domain_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma);
+__isl_give isl_basic_map *isl_basic_map_preimage_range_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma);
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_reverse(__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_set *isl_basic_map_domain(__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_set *isl_basic_map_range(__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_map *isl_basic_map_domain_map(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_map *isl_basic_map_range_map(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_map *isl_basic_map_remove_dims(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_basic_map *isl_basic_map_eliminate(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_sample(__isl_take isl_basic_map *bmap);
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_detect_equalities(
+						__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_map *isl_basic_map_read_from_file(isl_ctx *ctx,
+	FILE *input);
+__isl_constructor
+__isl_give isl_basic_map *isl_basic_map_read_from_str(isl_ctx *ctx,
+	const char *str);
+__isl_give isl_map *isl_map_read_from_file(isl_ctx *ctx, FILE *input);
+__isl_constructor
+__isl_give isl_map *isl_map_read_from_str(isl_ctx *ctx, const char *str);
+void isl_basic_map_dump(__isl_keep isl_basic_map *bmap);
+void isl_map_dump(__isl_keep isl_map *map);
+__isl_give char *isl_basic_map_to_str(__isl_keep isl_basic_map *bmap);
+__isl_give isl_printer *isl_printer_print_basic_map(
+	__isl_take isl_printer *printer, __isl_keep isl_basic_map *bmap);
+__isl_give char *isl_map_to_str(__isl_keep isl_map *map);
+__isl_give isl_printer *isl_printer_print_map(__isl_take isl_printer *printer,
+	__isl_keep isl_map *map);
+__isl_give isl_basic_map *isl_basic_map_fix_si(__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos, int value);
+__isl_give isl_basic_map *isl_basic_map_fix_val(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v);
+__isl_give isl_basic_map *isl_basic_map_lower_bound_si(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos, int value);
+__isl_give isl_basic_map *isl_basic_map_upper_bound_si(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, int value);
+
+__isl_give isl_basic_map *isl_basic_map_sum(__isl_take isl_basic_map *bmap1,
+	__isl_take isl_basic_map *bmap2);
+__isl_give isl_basic_map *isl_basic_map_neg(__isl_take isl_basic_map *bmap);
+
+__isl_give isl_map *isl_map_sum(__isl_take isl_map *map1,
+	__isl_take isl_map *map2);
+__isl_give isl_map *isl_map_neg(__isl_take isl_map *map);
+__isl_give isl_map *isl_map_floordiv_val(__isl_take isl_map *map,
+	__isl_take isl_val *d);
+
+__isl_export
+isl_bool isl_basic_map_is_equal(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2);
+isl_bool isl_basic_map_is_disjoint(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2);
+
+__isl_give isl_map *isl_basic_map_partial_lexmax(
+		__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+		__isl_give isl_set **empty);
+__isl_give isl_map *isl_basic_map_partial_lexmin(
+		__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+		__isl_give isl_set **empty);
+__isl_give isl_map *isl_map_partial_lexmax(
+		__isl_take isl_map *map, __isl_take isl_set *dom,
+		__isl_give isl_set **empty);
+__isl_give isl_map *isl_map_partial_lexmin(
+		__isl_take isl_map *map, __isl_take isl_set *dom,
+		__isl_give isl_set **empty);
+__isl_export
+__isl_give isl_map *isl_basic_map_lexmin(__isl_take isl_basic_map *bmap);
+__isl_export
+__isl_give isl_map *isl_basic_map_lexmax(__isl_take isl_basic_map *bmap);
+__isl_export
+__isl_give isl_map *isl_map_lexmin(__isl_take isl_map *map);
+__isl_export
+__isl_give isl_map *isl_map_lexmax(__isl_take isl_map *map);
+__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexmin_pw_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty);
+__isl_give isl_pw_multi_aff *isl_basic_map_partial_lexmax_pw_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty);
+__isl_give isl_pw_multi_aff *isl_basic_map_lexmin_pw_multi_aff(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_pw_multi_aff *isl_map_lexmin_pw_multi_aff(
+	__isl_take isl_map *map);
+__isl_give isl_pw_multi_aff *isl_map_lexmax_pw_multi_aff(
+	__isl_take isl_map *map);
+
+void isl_basic_map_print_internal(__isl_keep isl_basic_map *bmap,
+	FILE *out, int indent);
+
+__isl_give isl_val *isl_basic_map_plain_get_val_if_fixed(
+	__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos);
+
+isl_bool isl_basic_map_image_is_bounded(__isl_keep isl_basic_map *bmap);
+isl_bool isl_basic_map_plain_is_universe(__isl_keep isl_basic_map *bmap);
+isl_bool isl_basic_map_is_universe(__isl_keep isl_basic_map *bmap);
+isl_bool isl_basic_map_plain_is_empty(__isl_keep isl_basic_map *bmap);
+__isl_export
+isl_bool isl_basic_map_is_empty(__isl_keep isl_basic_map *bmap);
+__isl_export
+isl_bool isl_basic_map_is_subset(__isl_keep isl_basic_map *bmap1,
+		__isl_keep isl_basic_map *bmap2);
+isl_bool isl_basic_map_is_strict_subset(__isl_keep isl_basic_map *bmap1,
+		__isl_keep isl_basic_map *bmap2);
+
+__isl_give isl_map *isl_map_universe(__isl_take isl_space *dim);
+__isl_give isl_map *isl_map_nat_universe(__isl_take isl_space *dim);
+__isl_give isl_map *isl_map_empty(__isl_take isl_space *dim);
+__isl_give isl_map *isl_map_identity(__isl_take isl_space *dim);
+__isl_give isl_map *isl_map_lex_lt_first(__isl_take isl_space *dim, unsigned n);
+__isl_give isl_map *isl_map_lex_le_first(__isl_take isl_space *dim, unsigned n);
+__isl_give isl_map *isl_map_lex_lt(__isl_take isl_space *set_dim);
+__isl_give isl_map *isl_map_lex_le(__isl_take isl_space *set_dim);
+__isl_give isl_map *isl_map_lex_gt_first(__isl_take isl_space *dim, unsigned n);
+__isl_give isl_map *isl_map_lex_ge_first(__isl_take isl_space *dim, unsigned n);
+__isl_give isl_map *isl_map_lex_gt(__isl_take isl_space *set_dim);
+__isl_give isl_map *isl_map_lex_ge(__isl_take isl_space *set_dim);
+__isl_null isl_map *isl_map_free(__isl_take isl_map *map);
+__isl_give isl_map *isl_map_copy(__isl_keep isl_map *map);
+__isl_export
+__isl_give isl_map *isl_map_reverse(__isl_take isl_map *map);
+__isl_export
+__isl_give isl_map *isl_map_union(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+__isl_give isl_map *isl_map_union_disjoint(
+		__isl_take isl_map *map1, __isl_take isl_map *map2);
+__isl_export
+__isl_give isl_map *isl_map_intersect_domain(
+		__isl_take isl_map *map,
+		__isl_take isl_set *set);
+__isl_export
+__isl_give isl_map *isl_map_intersect_range(
+		__isl_take isl_map *map,
+		__isl_take isl_set *set);
+__isl_give isl_map *isl_map_intersect_domain_factor_range(
+	__isl_take isl_map *map, __isl_take isl_map *factor);
+__isl_give isl_map *isl_map_intersect_range_factor_range(
+	__isl_take isl_map *map, __isl_take isl_map *factor);
+__isl_export
+__isl_give isl_map *isl_map_apply_domain(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+__isl_export
+__isl_give isl_map *isl_map_apply_range(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+__isl_give isl_map *isl_map_preimage_domain_multi_aff(__isl_take isl_map *map,
+	__isl_take isl_multi_aff *ma);
+__isl_give isl_map *isl_map_preimage_range_multi_aff(__isl_take isl_map *map,
+	__isl_take isl_multi_aff *ma);
+__isl_give isl_map *isl_map_preimage_domain_pw_multi_aff(
+	__isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma);
+__isl_give isl_map *isl_map_preimage_range_pw_multi_aff(
+	__isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma);
+__isl_give isl_map *isl_map_preimage_domain_multi_pw_aff(
+	__isl_take isl_map *map, __isl_take isl_multi_pw_aff *mpa);
+__isl_give isl_basic_map *isl_basic_map_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2);
+__isl_give isl_map *isl_map_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2);
+__isl_give isl_basic_map *isl_basic_map_domain_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2);
+__isl_give isl_basic_map *isl_basic_map_range_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2);
+__isl_give isl_map *isl_map_domain_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2);
+__isl_give isl_map *isl_map_range_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2);
+__isl_give isl_basic_map *isl_basic_map_flat_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2);
+__isl_give isl_map *isl_map_flat_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2);
+__isl_give isl_basic_map *isl_basic_map_flat_range_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2);
+__isl_give isl_map *isl_map_flat_domain_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2);
+__isl_give isl_map *isl_map_flat_range_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2);
+isl_bool isl_map_domain_is_wrapping(__isl_keep isl_map *map);
+isl_bool isl_map_range_is_wrapping(__isl_keep isl_map *map);
+isl_bool isl_map_is_product(__isl_keep isl_map *map);
+__isl_give isl_map *isl_map_factor_domain(__isl_take isl_map *map);
+__isl_give isl_map *isl_map_factor_range(__isl_take isl_map *map);
+__isl_give isl_map *isl_map_domain_factor_domain(__isl_take isl_map *map);
+__isl_give isl_map *isl_map_domain_factor_range(__isl_take isl_map *map);
+__isl_give isl_map *isl_map_range_factor_domain(__isl_take isl_map *map);
+__isl_give isl_map *isl_map_range_factor_range(__isl_take isl_map *map);
+__isl_export
+__isl_give isl_map *isl_map_intersect(__isl_take isl_map *map1,
+				      __isl_take isl_map *map2);
+__isl_export
+__isl_give isl_map *isl_map_intersect_params(__isl_take isl_map *map,
+		__isl_take isl_set *params);
+__isl_export
+__isl_give isl_map *isl_map_subtract(
+		__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+__isl_give isl_map *isl_map_subtract_domain(__isl_take isl_map *map,
+	__isl_take isl_set *dom);
+__isl_give isl_map *isl_map_subtract_range(__isl_take isl_map *map,
+	__isl_take isl_set *dom);
+__isl_export
+__isl_give isl_map *isl_map_complement(__isl_take isl_map *map);
+struct isl_map *isl_map_fix_input_si(struct isl_map *map,
+		unsigned input, int value);
+__isl_give isl_map *isl_map_fix_si(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, int value);
+__isl_give isl_map *isl_map_fix_val(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v);
+__isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, int value);
+__isl_give isl_map *isl_map_upper_bound_si(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, int value);
+__isl_export
+__isl_give isl_basic_set *isl_basic_map_deltas(__isl_take isl_basic_map *bmap);
+__isl_export
+__isl_give isl_set *isl_map_deltas(__isl_take isl_map *map);
+__isl_give isl_basic_map *isl_basic_map_deltas_map(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_deltas_map(__isl_take isl_map *map);
+__isl_export
+__isl_give isl_map *isl_map_detect_equalities(__isl_take isl_map *map);
+__isl_export
+__isl_give isl_basic_map *isl_map_affine_hull(__isl_take isl_map *map);
+__isl_give isl_basic_map *isl_map_convex_hull(__isl_take isl_map *map);
+__isl_export
+__isl_give isl_basic_map *isl_map_polyhedral_hull(__isl_take isl_map *map);
+__isl_give isl_basic_map *isl_basic_map_add_dims(__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned n);
+__isl_give isl_map *isl_map_add_dims(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned n);
+__isl_give isl_basic_map *isl_basic_map_insert_dims(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type,
+	unsigned pos, unsigned n);
+__isl_give isl_map *isl_map_insert_dims(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, unsigned n);
+__isl_give isl_basic_map *isl_basic_map_move_dims(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+__isl_give isl_map *isl_map_move_dims(__isl_take isl_map *map,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+__isl_give isl_basic_map *isl_basic_map_project_out(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_map *isl_map_project_out(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_basic_map *isl_basic_map_remove_divs(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_remove_unknown_divs(__isl_take isl_map *map);
+__isl_give isl_map *isl_map_remove_divs(__isl_take isl_map *map);
+__isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_map *isl_map_remove_dims(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_basic_map *isl_basic_map_remove_divs_involving_dims(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_map *isl_map_remove_divs_involving_dims(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n);
+struct isl_map *isl_map_remove_inputs(struct isl_map *map,
+	unsigned first, unsigned n);
+
+__isl_give isl_basic_map *isl_basic_map_equate(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
+__isl_give isl_basic_map *isl_basic_map_order_ge(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
+__isl_give isl_map *isl_map_order_ge(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
+__isl_give isl_map *isl_map_order_le(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
+__isl_give isl_map *isl_map_equate(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
+__isl_give isl_map *isl_map_oppose(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
+__isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
+__isl_give isl_basic_map *isl_basic_map_order_gt(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
+__isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
+
+__isl_export
+__isl_give isl_map *isl_set_identity(__isl_take isl_set *set);
+
+__isl_export
+isl_bool isl_basic_set_is_wrapping(__isl_keep isl_basic_set *bset);
+__isl_export
+isl_bool isl_set_is_wrapping(__isl_keep isl_set *set);
+__isl_give isl_basic_set *isl_basic_map_wrap(__isl_take isl_basic_map *bmap);
+__isl_give isl_set *isl_map_wrap(__isl_take isl_map *map);
+__isl_give isl_basic_map *isl_basic_set_unwrap(__isl_take isl_basic_set *bset);
+__isl_give isl_map *isl_set_unwrap(__isl_take isl_set *set);
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_flatten(__isl_take isl_basic_map *bmap);
+__isl_export
+__isl_give isl_map *isl_map_flatten(__isl_take isl_map *map);
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_flatten_domain(
+	__isl_take isl_basic_map *bmap);
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_flatten_range(
+	__isl_take isl_basic_map *bmap);
+__isl_export
+__isl_give isl_map *isl_map_flatten_domain(__isl_take isl_map *map);
+__isl_export
+__isl_give isl_map *isl_map_flatten_range(__isl_take isl_map *map);
+__isl_export
+__isl_give isl_basic_set *isl_basic_set_flatten(__isl_take isl_basic_set *bset);
+__isl_export
+__isl_give isl_set *isl_set_flatten(__isl_take isl_set *set);
+__isl_give isl_map *isl_set_flatten_map(__isl_take isl_set *set);
+__isl_give isl_set *isl_map_params(__isl_take isl_map *map);
+__isl_give isl_set *isl_map_domain(__isl_take isl_map *bmap);
+__isl_give isl_set *isl_map_range(__isl_take isl_map *map);
+__isl_give isl_map *isl_map_domain_map(__isl_take isl_map *map);
+__isl_give isl_map *isl_map_range_map(__isl_take isl_map *map);
+__isl_give isl_map *isl_set_wrapped_domain_map(__isl_take isl_set *set);
+__isl_constructor
+__isl_give isl_map *isl_map_from_basic_map(__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_from_domain(__isl_take isl_set *set);
+__isl_give isl_basic_map *isl_basic_map_from_domain(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_basic_map *isl_basic_map_from_range(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_map *isl_map_from_range(__isl_take isl_set *set);
+__isl_give isl_basic_map *isl_basic_map_from_domain_and_range(
+	__isl_take isl_basic_set *domain, __isl_take isl_basic_set *range);
+__isl_give isl_map *isl_map_from_domain_and_range(__isl_take isl_set *domain,
+	__isl_take isl_set *range);
+__isl_export
+__isl_give isl_basic_map *isl_map_sample(__isl_take isl_map *map);
+
+isl_bool isl_map_plain_is_empty(__isl_keep isl_map *map);
+isl_bool isl_map_plain_is_universe(__isl_keep isl_map *map);
+__isl_export
+isl_bool isl_map_is_empty(__isl_keep isl_map *map);
+__isl_export
+isl_bool isl_map_is_subset(__isl_keep isl_map *map1, __isl_keep isl_map *map2);
+__isl_export
+isl_bool isl_map_is_strict_subset(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2);
+__isl_export
+isl_bool isl_map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2);
+__isl_export
+isl_bool isl_map_is_disjoint(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2);
+isl_bool isl_basic_map_is_single_valued(__isl_keep isl_basic_map *bmap);
+isl_bool isl_map_plain_is_single_valued(__isl_keep isl_map *map);
+__isl_export
+isl_bool isl_map_is_single_valued(__isl_keep isl_map *map);
+isl_bool isl_map_plain_is_injective(__isl_keep isl_map *map);
+__isl_export
+isl_bool isl_map_is_injective(__isl_keep isl_map *map);
+__isl_export
+isl_bool isl_map_is_bijective(__isl_keep isl_map *map);
+isl_bool isl_map_is_identity(__isl_keep isl_map *map);
+int isl_map_is_translation(__isl_keep isl_map *map);
+isl_bool isl_map_has_equal_space(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2);
+
+isl_bool isl_basic_map_can_zip(__isl_keep isl_basic_map *bmap);
+isl_bool isl_map_can_zip(__isl_keep isl_map *map);
+__isl_give isl_basic_map *isl_basic_map_zip(__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_zip(__isl_take isl_map *map);
+
+isl_bool isl_basic_map_can_curry(__isl_keep isl_basic_map *bmap);
+isl_bool isl_map_can_curry(__isl_keep isl_map *map);
+__isl_give isl_basic_map *isl_basic_map_curry(__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_curry(__isl_take isl_map *map);
+
+isl_bool isl_map_can_range_curry(__isl_keep isl_map *map);
+__isl_give isl_map *isl_map_range_curry(__isl_take isl_map *map);
+
+isl_bool isl_basic_map_can_uncurry(__isl_keep isl_basic_map *bmap);
+isl_bool isl_map_can_uncurry(__isl_keep isl_map *map);
+__isl_give isl_basic_map *isl_basic_map_uncurry(__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_uncurry(__isl_take isl_map *map);
+
+__isl_give isl_map *isl_map_make_disjoint(__isl_take isl_map *map);
+__isl_give isl_map *isl_basic_map_compute_divs(__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_compute_divs(__isl_take isl_map *map);
+ISL_DEPRECATED
+__isl_give isl_map *isl_map_align_divs(__isl_take isl_map *map);
+
+__isl_give isl_basic_map *isl_basic_map_drop_constraints_involving_dims(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_basic_map *isl_basic_map_drop_constraints_not_involving_dims(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_map *isl_map_drop_constraints_involving_dims(
+	__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_map *isl_map_drop_constraints_not_involving_dims(
+	__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+isl_bool isl_basic_map_involves_dims(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n);
+isl_bool isl_map_involves_dims(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+void isl_map_print_internal(__isl_keep isl_map *map, FILE *out, int indent);
+
+__isl_give isl_val *isl_map_plain_get_val_if_fixed(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos);
+
+__isl_give isl_basic_map *isl_basic_map_gist_domain(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *context);
+__isl_export
+__isl_give isl_basic_map *isl_basic_map_gist(__isl_take isl_basic_map *bmap,
+	__isl_take isl_basic_map *context);
+__isl_export
+__isl_give isl_map *isl_map_gist(__isl_take isl_map *map,
+	__isl_take isl_map *context);
+__isl_export
+__isl_give isl_map *isl_map_gist_domain(__isl_take isl_map *map,
+	__isl_take isl_set *context);
+__isl_give isl_map *isl_map_gist_range(__isl_take isl_map *map,
+	__isl_take isl_set *context);
+__isl_give isl_map *isl_map_gist_params(__isl_take isl_map *map,
+	__isl_take isl_set *context);
+__isl_give isl_map *isl_map_gist_basic_map(__isl_take isl_map *map,
+	__isl_take isl_basic_map *context);
+
+__isl_export
+__isl_give isl_map *isl_map_coalesce(__isl_take isl_map *map);
+
+isl_bool isl_map_plain_is_equal(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2);
+
+uint32_t isl_map_get_hash(__isl_keep isl_map *map);
+
+int isl_map_n_basic_map(__isl_keep isl_map *map);
+__isl_export
+isl_stat isl_map_foreach_basic_map(__isl_keep isl_map *map,
+	isl_stat (*fn)(__isl_take isl_basic_map *bmap, void *user), void *user);
+
+__isl_give isl_map *isl_map_fixed_power_val(__isl_take isl_map *map,
+	__isl_take isl_val *exp);
+__isl_give isl_map *isl_map_power(__isl_take isl_map *map, int *exact);
+__isl_give isl_map *isl_map_reaching_path_lengths(__isl_take isl_map *map,
+	int *exact);
+__isl_give isl_map *isl_map_transitive_closure(__isl_take isl_map *map,
+	int *exact);
+
+__isl_give isl_map *isl_map_lex_le_map(__isl_take isl_map *map1,
+	__isl_take isl_map *map2);
+__isl_give isl_map *isl_map_lex_lt_map(__isl_take isl_map *map1,
+	__isl_take isl_map *map2);
+__isl_give isl_map *isl_map_lex_ge_map(__isl_take isl_map *map1,
+	__isl_take isl_map *map2);
+__isl_give isl_map *isl_map_lex_gt_map(__isl_take isl_map *map1,
+	__isl_take isl_map *map2);
+
+__isl_give isl_basic_map *isl_basic_map_align_params(
+	__isl_take isl_basic_map *bmap, __isl_take isl_space *model);
+__isl_give isl_map *isl_map_align_params(__isl_take isl_map *map,
+	__isl_take isl_space *model);
+
+__isl_give isl_mat *isl_basic_map_equalities_matrix(
+		__isl_keep isl_basic_map *bmap, enum isl_dim_type c1,
+		enum isl_dim_type c2, enum isl_dim_type c3,
+		enum isl_dim_type c4, enum isl_dim_type c5);
+__isl_give isl_mat *isl_basic_map_inequalities_matrix(
+		__isl_keep isl_basic_map *bmap, enum isl_dim_type c1,
+		enum isl_dim_type c2, enum isl_dim_type c3,
+		enum isl_dim_type c4, enum isl_dim_type c5);
+__isl_give isl_basic_map *isl_basic_map_from_constraint_matrices(
+	__isl_take isl_space *dim,
+	__isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1,
+	enum isl_dim_type c2, enum isl_dim_type c3,
+	enum isl_dim_type c4, enum isl_dim_type c5);
+
+__isl_give isl_basic_map *isl_basic_map_from_aff(__isl_take isl_aff *aff);
+__isl_give isl_basic_map *isl_basic_map_from_multi_aff(
+	__isl_take isl_multi_aff *maff);
+__isl_give isl_basic_map *isl_basic_map_from_aff_list(
+	__isl_take isl_space *domain_dim, __isl_take isl_aff_list *list);
+
+__isl_give isl_map *isl_map_from_aff(__isl_take isl_aff *aff);
+__isl_give isl_map *isl_map_from_multi_aff(__isl_take isl_multi_aff *maff);
+
+__isl_give isl_pw_aff *isl_map_dim_min(__isl_take isl_map *map, int pos);
+__isl_give isl_pw_aff *isl_map_dim_max(__isl_take isl_map *map, int pos);
+
+ISL_DECLARE_LIST_FN(basic_map)
+ISL_DECLARE_LIST_FN(map)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/map_to_basic_set.h b/final/lib/External/isl/include/isl/map_to_basic_set.h
new file mode 100644
index 0000000..80e9ab5
--- /dev/null
+++ b/final/lib/External/isl/include/isl/map_to_basic_set.h
@@ -0,0 +1,18 @@
+#ifndef ISL_MAP_TO_BASIC_SET_H
+#define ISL_MAP_TO_BASIC_SET_H
+
+#include <isl/set_type.h>
+#include <isl/map_type.h>
+#include <isl/maybe_basic_set.h>
+
+#define ISL_KEY		isl_map
+#define ISL_VAL		isl_basic_set
+#define ISL_HMAP_SUFFIX	map_to_basic_set
+#define ISL_HMAP	isl_map_to_basic_set
+#include <isl/hmap.h>
+#undef ISL_KEY
+#undef ISL_VAL
+#undef ISL_HMAP_SUFFIX
+#undef ISL_HMAP
+
+#endif
diff --git a/final/lib/External/isl/include/isl/map_type.h b/final/lib/External/isl/include/isl/map_type.h
new file mode 100644
index 0000000..7c30056
--- /dev/null
+++ b/final/lib/External/isl/include/isl/map_type.h
@@ -0,0 +1,37 @@
+#ifndef ISL_MAP_TYPE_H
+#define ISL_MAP_TYPE_H
+
+#include <isl/ctx.h>
+#include <isl/list.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct __isl_subclass(isl_map) isl_basic_map;
+typedef struct isl_basic_map isl_basic_map;
+ISL_DECLARE_LIST_TYPE(basic_map)
+struct __isl_subclass(isl_union_map) isl_map;
+typedef struct isl_map isl_map;
+ISL_DECLARE_LIST_TYPE(map)
+
+#ifndef isl_basic_set
+struct __isl_subclass(isl_set) isl_basic_set;
+typedef struct isl_basic_set isl_basic_set;
+ISL_DECLARE_LIST_TYPE(basic_set)
+#endif
+
+#ifndef isl_set
+struct __isl_subclass(isl_union_set) isl_set;
+typedef struct isl_set isl_set;
+ISL_DECLARE_LIST_TYPE(set)
+#endif
+
+ISL_DECLARE_LIST_FN(basic_set)
+ISL_DECLARE_LIST_FN(set)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/mat.h b/final/lib/External/isl/include/isl/mat.h
new file mode 100644
index 0000000..8764c96
--- /dev/null
+++ b/final/lib/External/isl/include/isl/mat.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_MAT_H
+#define ISL_MAT_H
+
+#include <stdio.h>
+
+#include <isl/ctx.h>
+#include <isl/vec.h>
+#include <isl/val.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_mat;
+typedef struct isl_mat	isl_mat;
+
+isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat);
+
+__isl_give isl_mat *isl_mat_alloc(isl_ctx *ctx,
+	unsigned n_row, unsigned n_col);
+__isl_give isl_mat *isl_mat_dup(__isl_keep isl_mat *mat);
+struct isl_mat *isl_mat_extend(struct isl_mat *mat,
+	unsigned n_row, unsigned n_col);
+struct isl_mat *isl_mat_identity(struct isl_ctx *ctx, unsigned n_row);
+__isl_give isl_mat *isl_mat_copy(__isl_keep isl_mat *mat);
+__isl_give isl_mat *isl_mat_cow(__isl_take isl_mat *mat);
+__isl_null isl_mat *isl_mat_free(__isl_take isl_mat *mat);
+
+int isl_mat_rows(__isl_keep isl_mat *mat);
+int isl_mat_cols(__isl_keep isl_mat *mat);
+__isl_give isl_val *isl_mat_get_element_val(__isl_keep isl_mat *mat,
+	int row, int col);
+__isl_give isl_mat *isl_mat_set_element_si(__isl_take isl_mat *mat,
+	int row, int col, int v);
+__isl_give isl_mat *isl_mat_set_element_val(__isl_take isl_mat *mat,
+	int row, int col, __isl_take isl_val *v);
+
+__isl_give isl_mat *isl_mat_swap_cols(__isl_take isl_mat *mat,
+	unsigned i, unsigned j);
+__isl_give isl_mat *isl_mat_swap_rows(__isl_take isl_mat *mat,
+	unsigned i, unsigned j);
+
+__isl_give isl_vec *isl_mat_vec_product(__isl_take isl_mat *mat,
+	__isl_take isl_vec *vec);
+__isl_give isl_vec *isl_vec_mat_product(__isl_take isl_vec *vec,
+	__isl_take isl_mat *mat);
+__isl_give isl_vec *isl_mat_vec_inverse_product(__isl_take isl_mat *mat,
+						__isl_take isl_vec *vec);
+__isl_give isl_mat *isl_mat_aff_direct_sum(__isl_take isl_mat *left,
+	__isl_take isl_mat *right);
+__isl_give isl_mat *isl_mat_diagonal(__isl_take isl_mat *mat1,
+	__isl_take isl_mat *mat2);
+__isl_give isl_mat *isl_mat_left_hermite(__isl_take isl_mat *M, int neg,
+	__isl_give isl_mat **U, __isl_give isl_mat **Q);
+__isl_give isl_mat *isl_mat_lin_to_aff(__isl_take isl_mat *mat);
+__isl_give isl_mat *isl_mat_inverse_product(__isl_take isl_mat *left,
+	__isl_take isl_mat *right);
+__isl_give isl_mat *isl_mat_product(__isl_take isl_mat *left,
+	__isl_take isl_mat *right);
+__isl_give isl_mat *isl_mat_transpose(__isl_take isl_mat *mat);
+__isl_give isl_mat *isl_mat_right_inverse(__isl_take isl_mat *mat);
+__isl_give isl_mat *isl_mat_right_kernel(__isl_take isl_mat *mat);
+
+__isl_give isl_mat *isl_mat_normalize(__isl_take isl_mat *mat);
+__isl_give isl_mat *isl_mat_normalize_row(__isl_take isl_mat *mat, int row);
+
+__isl_give isl_mat *isl_mat_drop_cols(__isl_take isl_mat *mat,
+	unsigned col, unsigned n);
+__isl_give isl_mat *isl_mat_drop_rows(__isl_take isl_mat *mat,
+				unsigned row, unsigned n);
+__isl_give isl_mat *isl_mat_insert_cols(__isl_take isl_mat *mat,
+				unsigned col, unsigned n);
+__isl_give isl_mat *isl_mat_insert_rows(__isl_take isl_mat *mat,
+				unsigned row, unsigned n);
+__isl_give isl_mat *isl_mat_move_cols(__isl_take isl_mat *mat,
+	unsigned dst_col, unsigned src_col, unsigned n);
+__isl_give isl_mat *isl_mat_add_rows(__isl_take isl_mat *mat, unsigned n);
+__isl_give isl_mat *isl_mat_insert_zero_cols(__isl_take isl_mat *mat,
+	unsigned first, unsigned n);
+__isl_give isl_mat *isl_mat_add_zero_cols(__isl_take isl_mat *mat, unsigned n);
+__isl_give isl_mat *isl_mat_insert_zero_rows(__isl_take isl_mat *mat,
+	unsigned row, unsigned n);
+__isl_give isl_mat *isl_mat_add_zero_rows(__isl_take isl_mat *mat, unsigned n);
+
+void isl_mat_col_add(__isl_keep isl_mat *mat, int dst_col, int src_col);
+
+__isl_give isl_mat *isl_mat_unimodular_complete(__isl_take isl_mat *M, int row);
+
+__isl_give isl_mat *isl_mat_from_row_vec(__isl_take isl_vec *vec);
+__isl_give isl_mat *isl_mat_concat(__isl_take isl_mat *top,
+	__isl_take isl_mat *bot);
+__isl_give isl_mat *isl_mat_vec_concat(__isl_take isl_mat *top,
+	__isl_take isl_vec *bot);
+
+isl_bool isl_mat_is_equal(__isl_keep isl_mat *mat1, __isl_keep isl_mat *mat2);
+
+int isl_mat_initial_non_zero_cols(__isl_keep isl_mat *mat);
+
+void isl_mat_print_internal(__isl_keep isl_mat *mat, FILE *out, int indent);
+void isl_mat_dump(__isl_keep isl_mat *mat);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/maybe.h b/final/lib/External/isl/include/isl/maybe.h
new file mode 100644
index 0000000..1fb3573
--- /dev/null
+++ b/final/lib/External/isl/include/isl/maybe.h
@@ -0,0 +1,7 @@
+#ifndef ISL_MAYBE_H
+#define ISL_MAYBE_H
+
+#define ISL_xMAYBE(TYPE)	isl_maybe_ ## TYPE
+#define ISL_MAYBE(TYPE)		ISL_xMAYBE(TYPE)
+
+#endif
diff --git a/final/lib/External/isl/include/isl/maybe_ast_expr.h b/final/lib/External/isl/include/isl/maybe_ast_expr.h
new file mode 100644
index 0000000..260fa34
--- /dev/null
+++ b/final/lib/External/isl/include/isl/maybe_ast_expr.h
@@ -0,0 +1,8 @@
+#ifndef ISL_MAYBE_AST_EXPR_H
+#define ISL_MAYBE_AST_EXPR_H
+
+#define ISL_TYPE	isl_ast_expr
+#include <isl/maybe_templ.h>
+#undef ISL_TYPE
+
+#endif
diff --git a/final/lib/External/isl/include/isl/maybe_basic_set.h b/final/lib/External/isl/include/isl/maybe_basic_set.h
new file mode 100644
index 0000000..1dc0881
--- /dev/null
+++ b/final/lib/External/isl/include/isl/maybe_basic_set.h
@@ -0,0 +1,8 @@
+#ifndef ISL_MAYBE_BASIC_SET_H
+#define ISL_MAYBE_BASIC_SET_H
+
+#define ISL_TYPE	isl_basic_set
+#include <isl/maybe_templ.h>
+#undef ISL_TYPE
+
+#endif
diff --git a/final/lib/External/isl/include/isl/maybe_id.h b/final/lib/External/isl/include/isl/maybe_id.h
new file mode 100644
index 0000000..24ea308
--- /dev/null
+++ b/final/lib/External/isl/include/isl/maybe_id.h
@@ -0,0 +1,8 @@
+#ifndef ISL_MAYBE_ID_H
+#define ISL_MAYBE_ID_H
+
+#define ISL_TYPE	isl_id
+#include <isl/maybe_templ.h>
+#undef ISL_TYPE
+
+#endif
diff --git a/final/lib/External/isl/include/isl/maybe_pw_aff.h b/final/lib/External/isl/include/isl/maybe_pw_aff.h
new file mode 100644
index 0000000..bc0dd9c
--- /dev/null
+++ b/final/lib/External/isl/include/isl/maybe_pw_aff.h
@@ -0,0 +1,8 @@
+#ifndef ISL_MAYBE_PW_AFF_H
+#define ISL_MAYBE_PW_AFF_H
+
+#define ISL_TYPE	isl_pw_aff
+#include <isl/maybe_templ.h>
+#undef ISL_TYPE
+
+#endif
diff --git a/final/lib/External/isl/include/isl/maybe_templ.h b/final/lib/External/isl/include/isl/maybe_templ.h
new file mode 100644
index 0000000..4dac253
--- /dev/null
+++ b/final/lib/External/isl/include/isl/maybe_templ.h
@@ -0,0 +1,12 @@
+#include <isl/ctx.h>
+#include <isl/maybe.h>
+
+/* A structure that possibly contains a pointer to an object of type ISL_TYPE.
+ * The pointer in "value" is only valid if "valid" is isl_bool_true.
+ * Otherwise, "value" is set to NULL.
+ */
+struct ISL_MAYBE(ISL_TYPE) {
+	isl_bool	valid;
+	ISL_TYPE	*value;
+};
+typedef struct ISL_MAYBE(ISL_TYPE) ISL_MAYBE(ISL_TYPE);
diff --git a/final/lib/External/isl/include/isl/multi.h b/final/lib/External/isl/include/isl/multi.h
new file mode 100644
index 0000000..a678b32
--- /dev/null
+++ b/final/lib/External/isl/include/isl/multi.h
@@ -0,0 +1,152 @@
+#ifndef ISL_MULTI_H
+#define ISL_MULTI_H
+
+#include <isl/space.h>
+#include <isl/list.h>
+#include <isl/set_type.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define ISL_DECLARE_MULTI(BASE)						\
+unsigned isl_multi_##BASE##_dim(__isl_keep isl_multi_##BASE *multi,	\
+	enum isl_dim_type type);					\
+isl_ctx *isl_multi_##BASE##_get_ctx(					\
+	__isl_keep isl_multi_##BASE *multi);				\
+__isl_give isl_space *isl_multi_##BASE##_get_space(			\
+	__isl_keep isl_multi_##BASE *multi);				\
+__isl_give isl_space *isl_multi_##BASE##_get_domain_space(		\
+	__isl_keep isl_multi_##BASE *multi);				\
+int isl_multi_##BASE##_find_dim_by_name(				\
+	__isl_keep isl_multi_##BASE *multi,				\
+	enum isl_dim_type type, const char *name);			\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_from_##BASE##_list(	\
+	__isl_take isl_space *space, __isl_take isl_##BASE##_list *list); \
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_zero(			\
+	__isl_take isl_space *space);					\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_copy(			\
+	__isl_keep isl_multi_##BASE *multi);				\
+__isl_null isl_multi_##BASE *isl_multi_##BASE##_free(			\
+	__isl_take isl_multi_##BASE *multi);				\
+isl_bool isl_multi_##BASE##_plain_is_equal(				\
+	__isl_keep isl_multi_##BASE *multi1,				\
+	__isl_keep isl_multi_##BASE *multi2);				\
+isl_bool isl_multi_##BASE##_involves_nan(				\
+	__isl_keep isl_multi_##BASE *multi);				\
+int isl_multi_##BASE##_find_dim_by_id(					\
+	__isl_keep isl_multi_##BASE *multi, enum isl_dim_type type,	\
+	__isl_keep isl_id *id);						\
+__isl_give isl_id *isl_multi_##BASE##_get_dim_id(			\
+	__isl_take isl_multi_##BASE *multi,				\
+	enum isl_dim_type type, unsigned pos);				\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_dim_name(		\
+	__isl_take isl_multi_##BASE *multi,				\
+	enum isl_dim_type type, unsigned pos, const char *s);		\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_dim_id(		\
+	__isl_take isl_multi_##BASE *multi,				\
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id);	\
+const char *isl_multi_##BASE##_get_tuple_name(				\
+	__isl_keep isl_multi_##BASE *multi, enum isl_dim_type type);	\
+isl_bool isl_multi_##BASE##_has_tuple_id(				\
+	__isl_keep isl_multi_##BASE *multi, enum isl_dim_type type);	\
+__isl_give isl_id *isl_multi_##BASE##_get_tuple_id(			\
+	__isl_keep isl_multi_##BASE *multi, enum isl_dim_type type);	\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_tuple_name(		\
+	__isl_take isl_multi_##BASE *multi,				\
+	enum isl_dim_type type, const char *s);				\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_tuple_id(		\
+	__isl_take isl_multi_##BASE *multi,				\
+	enum isl_dim_type type, __isl_take isl_id *id);			\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_reset_tuple_id(		\
+	__isl_take isl_multi_##BASE *multi, enum isl_dim_type type);	\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_reset_user(		\
+	__isl_take isl_multi_##BASE *multi);				\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_drop_dims(		\
+	__isl_take isl_multi_##BASE *multi, enum isl_dim_type type,	\
+	unsigned first, unsigned n);					\
+__isl_give isl_##BASE *isl_multi_##BASE##_get_##BASE(			\
+	__isl_keep isl_multi_##BASE *multi, int pos);			\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_set_##BASE(		\
+	__isl_take isl_multi_##BASE *multi, int pos,			\
+	__isl_take isl_##BASE *el);					\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_range_splice(		\
+	__isl_take isl_multi_##BASE *multi1, unsigned pos,		\
+	__isl_take isl_multi_##BASE *multi2);				\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_flatten_range(		\
+	__isl_take isl_multi_##BASE *multi);				\
+__isl_export								\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_flat_range_product(	\
+	__isl_take isl_multi_##BASE *multi1,				\
+	__isl_take isl_multi_##BASE *multi2);				\
+__isl_export								\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_range_product(		\
+	__isl_take isl_multi_##BASE *multi1,				\
+	__isl_take isl_multi_##BASE *multi2);				\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_factor_range(		\
+	__isl_take isl_multi_##BASE *multi);				\
+isl_bool isl_multi_##BASE##_range_is_wrapping(				\
+	__isl_keep isl_multi_##BASE *multi);				\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_range_factor_domain(	\
+	__isl_take isl_multi_##BASE *multi);				\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_range_factor_range(	\
+	__isl_take isl_multi_##BASE *multi);				\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_scale_val(		\
+	__isl_take isl_multi_##BASE *multi, __isl_take isl_val *v);	\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_scale_down_val(		\
+	__isl_take isl_multi_##BASE *multi, __isl_take isl_val *v);	\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_scale_multi_val(	\
+	__isl_take isl_multi_##BASE *multi,				\
+	__isl_take isl_multi_val *mv);					\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_scale_down_multi_val(	\
+	__isl_take isl_multi_##BASE *multi,				\
+	__isl_take isl_multi_val *mv);					\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_mod_multi_val(		\
+	__isl_take isl_multi_##BASE *multi,				\
+	__isl_take isl_multi_val *mv);					\
+__isl_export								\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_add(			\
+	__isl_take isl_multi_##BASE *multi1,				\
+	__isl_take isl_multi_##BASE *multi2);				\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_sub(			\
+	__isl_take isl_multi_##BASE *multi1,				\
+	__isl_take isl_multi_##BASE *multi2);				\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_align_params(		\
+	__isl_take isl_multi_##BASE *multi,				\
+	__isl_take isl_space *model);					\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_from_range(		\
+	__isl_take isl_multi_##BASE *multi);
+
+#define ISL_DECLARE_MULTI_CMP(BASE)					\
+int isl_multi_##BASE##_plain_cmp(__isl_keep isl_multi_##BASE *multi1,	\
+	__isl_keep isl_multi_##BASE *multi2);
+
+#define ISL_DECLARE_MULTI_NEG(BASE)					\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_neg(		 	\
+	__isl_take isl_multi_##BASE *multi);
+
+#define ISL_DECLARE_MULTI_DIMS(BASE)					\
+isl_bool isl_multi_##BASE##_involves_dims(				\
+	__isl_keep isl_multi_##BASE *multi, enum isl_dim_type type,	\
+	unsigned first, unsigned n);					\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_insert_dims(		\
+	__isl_take isl_multi_##BASE *multi, enum isl_dim_type type,	\
+	unsigned first, unsigned n);					\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_add_dims(		\
+	__isl_take isl_multi_##BASE *multi, enum isl_dim_type type,	\
+	unsigned n);
+
+#define ISL_DECLARE_MULTI_WITH_DOMAIN(BASE)				\
+__isl_export								\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_product(		\
+	__isl_take isl_multi_##BASE *multi1,				\
+	__isl_take isl_multi_##BASE *multi2);				\
+__isl_give isl_multi_##BASE *isl_multi_##BASE##_splice(			\
+	__isl_take isl_multi_##BASE *multi1, unsigned in_pos,		\
+	unsigned out_pos, __isl_take isl_multi_##BASE *multi2);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/obj.h b/final/lib/External/isl/include/isl/obj.h
new file mode 100644
index 0000000..07c6bf3
--- /dev/null
+++ b/final/lib/External/isl/include/isl/obj.h
@@ -0,0 +1,57 @@
+#ifndef ISL_OBJ_H
+#define ISL_OBJ_H
+
+#include <isl/set_type.h>
+#include <isl/map_type.h>
+#include <isl/union_set_type.h>
+#include <isl/union_map_type.h>
+#include <isl/polynomial_type.h>
+#include <isl/printer.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_obj_vtable {
+	void *(*copy)(void *v1);
+	void *(*add)(void *v1, void *v2);
+	__isl_give isl_printer *(*print)(__isl_take isl_printer *p, void *v);
+	void (*free)(void *v);
+};
+typedef struct isl_obj_vtable *isl_obj_type;
+extern struct isl_obj_vtable isl_obj_none_vtable;
+#define isl_obj_none		(&isl_obj_none_vtable)
+extern struct isl_obj_vtable isl_obj_int_vtable;
+#define isl_obj_int		(&isl_obj_int_vtable)
+extern struct isl_obj_vtable isl_obj_val_vtable;
+#define isl_obj_val		(&isl_obj_val_vtable)
+extern struct isl_obj_vtable isl_obj_set_vtable;
+#define isl_obj_set		(&isl_obj_set_vtable)
+extern struct isl_obj_vtable isl_obj_union_set_vtable;
+#define isl_obj_union_set	(&isl_obj_union_set_vtable)
+extern struct isl_obj_vtable isl_obj_map_vtable;
+#define isl_obj_map		(&isl_obj_map_vtable)
+extern struct isl_obj_vtable isl_obj_union_map_vtable;
+#define isl_obj_union_map	(&isl_obj_union_map_vtable)
+extern struct isl_obj_vtable isl_obj_pw_multi_aff_vtable;
+#define isl_obj_pw_multi_aff	(&isl_obj_pw_multi_aff_vtable)
+extern struct isl_obj_vtable isl_obj_pw_qpolynomial_vtable;
+#define isl_obj_pw_qpolynomial	(&isl_obj_pw_qpolynomial_vtable)
+extern struct isl_obj_vtable isl_obj_union_pw_qpolynomial_vtable;
+#define isl_obj_union_pw_qpolynomial	(&isl_obj_union_pw_qpolynomial_vtable)
+extern struct isl_obj_vtable isl_obj_pw_qpolynomial_fold_vtable;
+#define isl_obj_pw_qpolynomial_fold	(&isl_obj_pw_qpolynomial_fold_vtable)
+extern struct isl_obj_vtable isl_obj_union_pw_qpolynomial_fold_vtable;
+#define isl_obj_union_pw_qpolynomial_fold	(&isl_obj_union_pw_qpolynomial_fold_vtable)
+extern struct isl_obj_vtable isl_obj_schedule_vtable;
+#define isl_obj_schedule	(&isl_obj_schedule_vtable)
+struct isl_obj {
+	isl_obj_type	type;
+	void		*v;
+};
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/options.h b/final/lib/External/isl/include/isl/options.h
new file mode 100644
index 0000000..c09dee6
--- /dev/null
+++ b/final/lib/External/isl/include/isl/options.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_OPTIONS_H
+#define ISL_OPTIONS_H
+
+#include <isl/arg.h>
+#include <isl/ctx.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_options;
+
+ISL_ARG_DECL(isl_options, struct isl_options, isl_options_args)
+
+#define			ISL_BOUND_BERNSTEIN	0
+#define			ISL_BOUND_RANGE		1
+isl_stat isl_options_set_bound(isl_ctx *ctx, int val);
+int isl_options_get_bound(isl_ctx *ctx);
+
+#define			ISL_ON_ERROR_WARN	0
+#define			ISL_ON_ERROR_CONTINUE	1
+#define			ISL_ON_ERROR_ABORT	2
+isl_stat isl_options_set_on_error(isl_ctx *ctx, int val);
+int isl_options_get_on_error(isl_ctx *ctx);
+
+isl_stat isl_options_set_gbr_only_first(isl_ctx *ctx, int val);
+int isl_options_get_gbr_only_first(isl_ctx *ctx);
+
+#define		ISL_SCHEDULE_ALGORITHM_ISL		0
+#define		ISL_SCHEDULE_ALGORITHM_FEAUTRIER	1
+isl_stat isl_options_set_schedule_algorithm(isl_ctx *ctx, int val);
+int isl_options_get_schedule_algorithm(isl_ctx *ctx);
+
+isl_stat isl_options_set_pip_symmetry(isl_ctx *ctx, int val);
+int isl_options_get_pip_symmetry(isl_ctx *ctx);
+
+isl_stat isl_options_set_coalesce_bounded_wrapping(isl_ctx *ctx, int val);
+int isl_options_get_coalesce_bounded_wrapping(isl_ctx *ctx);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/point.h b/final/lib/External/isl/include/isl/point.h
new file mode 100644
index 0000000..97c3c46
--- /dev/null
+++ b/final/lib/External/isl/include/isl/point.h
@@ -0,0 +1,44 @@
+#ifndef ISL_POINT_H
+#define ISL_POINT_H
+
+#include <stdio.h>
+#include <isl/space.h>
+#include <isl/val.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct __isl_subclass(isl_basic_set) isl_point;
+typedef struct isl_point isl_point;
+
+isl_ctx *isl_point_get_ctx(__isl_keep isl_point *pnt);
+__isl_give isl_space *isl_point_get_space(__isl_keep isl_point *pnt);
+
+__isl_give isl_point *isl_point_zero(__isl_take isl_space *dim);
+__isl_give isl_point *isl_point_copy(__isl_keep isl_point *pnt);
+__isl_null isl_point *isl_point_free(__isl_take isl_point *pnt);
+
+__isl_give isl_val *isl_point_get_coordinate_val(__isl_keep isl_point *pnt,
+	enum isl_dim_type type, int pos);
+__isl_give isl_point *isl_point_set_coordinate_val(__isl_take isl_point *pnt,
+	enum isl_dim_type type, int pos, __isl_take isl_val *v);
+
+__isl_give isl_point *isl_point_add_ui(__isl_take isl_point *pnt,
+	enum isl_dim_type type, int pos, unsigned val);
+__isl_give isl_point *isl_point_sub_ui(__isl_take isl_point *pnt,
+	enum isl_dim_type type, int pos, unsigned val);
+
+__isl_give isl_point *isl_point_void(__isl_take isl_space *dim);
+isl_bool isl_point_is_void(__isl_keep isl_point *pnt);
+
+__isl_give isl_printer *isl_printer_print_point(
+	__isl_take isl_printer *printer, __isl_keep isl_point *pnt);
+__isl_give char *isl_point_to_str(__isl_keep isl_point *pnt);
+void isl_point_dump(__isl_keep isl_point *pnt);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/polynomial.h b/final/lib/External/isl/include/isl/polynomial.h
new file mode 100644
index 0000000..bb285ab
--- /dev/null
+++ b/final/lib/External/isl/include/isl/polynomial.h
@@ -0,0 +1,692 @@
+#ifndef ISL_POLYNOMIAL_H
+#define ISL_POLYNOMIAL_H
+
+#include <isl/ctx.h>
+#include <isl/constraint.h>
+#include <isl/space.h>
+#include <isl/set_type.h>
+#include <isl/point.h>
+#include <isl/printer.h>
+#include <isl/union_set_type.h>
+#include <isl/aff_type.h>
+#include <isl/polynomial_type.h>
+#include <isl/val.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+isl_ctx *isl_qpolynomial_get_ctx(__isl_keep isl_qpolynomial *qp);
+__isl_give isl_space *isl_qpolynomial_get_domain_space(
+	__isl_keep isl_qpolynomial *qp);
+__isl_give isl_space *isl_qpolynomial_get_space(__isl_keep isl_qpolynomial *qp);
+unsigned isl_qpolynomial_dim(__isl_keep isl_qpolynomial *qp,
+	enum isl_dim_type type);
+isl_bool isl_qpolynomial_involves_dims(__isl_keep isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+__isl_give isl_val *isl_qpolynomial_get_constant_val(
+	__isl_keep isl_qpolynomial *qp);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_set_dim_name(
+	__isl_take isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned pos, const char *s);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_zero_on_domain(__isl_take isl_space *dim);
+__isl_give isl_qpolynomial *isl_qpolynomial_one_on_domain(__isl_take isl_space *dim);
+__isl_give isl_qpolynomial *isl_qpolynomial_infty_on_domain(__isl_take isl_space *dim);
+__isl_give isl_qpolynomial *isl_qpolynomial_neginfty_on_domain(__isl_take isl_space *dim);
+__isl_give isl_qpolynomial *isl_qpolynomial_nan_on_domain(__isl_take isl_space *dim);
+__isl_give isl_qpolynomial *isl_qpolynomial_val_on_domain(
+	__isl_take isl_space *space, __isl_take isl_val *val);
+__isl_give isl_qpolynomial *isl_qpolynomial_var_on_domain(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_qpolynomial *isl_qpolynomial_copy(__isl_keep isl_qpolynomial *qp);
+__isl_null isl_qpolynomial *isl_qpolynomial_free(
+	__isl_take isl_qpolynomial *qp);
+
+isl_bool isl_qpolynomial_plain_is_equal(__isl_keep isl_qpolynomial *qp1,
+	__isl_keep isl_qpolynomial *qp2);
+isl_bool isl_qpolynomial_is_zero(__isl_keep isl_qpolynomial *qp);
+isl_bool isl_qpolynomial_is_nan(__isl_keep isl_qpolynomial *qp);
+isl_bool isl_qpolynomial_is_infty(__isl_keep isl_qpolynomial *qp);
+isl_bool isl_qpolynomial_is_neginfty(__isl_keep isl_qpolynomial *qp);
+int isl_qpolynomial_sgn(__isl_keep isl_qpolynomial *qp);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_neg(__isl_take isl_qpolynomial *qp);
+__isl_give isl_qpolynomial *isl_qpolynomial_add(__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2);
+__isl_give isl_qpolynomial *isl_qpolynomial_sub(__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2);
+__isl_give isl_qpolynomial *isl_qpolynomial_mul(__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2);
+__isl_give isl_qpolynomial *isl_qpolynomial_pow(__isl_take isl_qpolynomial *qp,
+	unsigned power);
+__isl_give isl_qpolynomial *isl_qpolynomial_scale_val(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_val *v);
+__isl_give isl_qpolynomial *isl_qpolynomial_scale_down_val(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_val *v);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_insert_dims(
+	__isl_take isl_qpolynomial *qp, enum isl_dim_type type,
+	unsigned first, unsigned n);
+__isl_give isl_qpolynomial *isl_qpolynomial_add_dims(
+	__isl_take isl_qpolynomial *qp, enum isl_dim_type type, unsigned n);
+__isl_give isl_qpolynomial *isl_qpolynomial_move_dims(
+	__isl_take isl_qpolynomial *qp,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+__isl_give isl_qpolynomial *isl_qpolynomial_project_domain_on_params(
+	__isl_take isl_qpolynomial *qp);
+__isl_give isl_qpolynomial *isl_qpolynomial_drop_dims(
+	__isl_take isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_substitute(
+	__isl_take isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned first, unsigned n,
+	__isl_keep isl_qpolynomial **subs);
+
+isl_stat isl_qpolynomial_as_polynomial_on_domain(__isl_keep isl_qpolynomial *qp,
+	__isl_keep isl_basic_set *bset,
+	isl_stat (*fn)(__isl_take isl_basic_set *bset,
+		  __isl_take isl_qpolynomial *poly, void *user), void *user);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_homogenize(
+	__isl_take isl_qpolynomial *poly);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_align_params(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_space *model);
+
+isl_ctx *isl_term_get_ctx(__isl_keep isl_term *term);
+
+__isl_give isl_term *isl_term_copy(__isl_keep isl_term *term);
+void isl_term_free(__isl_take isl_term *term);
+
+unsigned isl_term_dim(__isl_keep isl_term *term, enum isl_dim_type type);
+__isl_give isl_val *isl_term_get_coefficient_val(__isl_keep isl_term *term);
+int isl_term_get_exp(__isl_keep isl_term *term,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_aff *isl_term_get_div(__isl_keep isl_term *term, unsigned pos);
+
+isl_stat isl_qpolynomial_foreach_term(__isl_keep isl_qpolynomial *qp,
+	isl_stat (*fn)(__isl_take isl_term *term, void *user), void *user);
+
+__isl_give isl_val *isl_qpolynomial_eval(__isl_take isl_qpolynomial *qp,
+	__isl_take isl_point *pnt);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_gist_params(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_set *context);
+__isl_give isl_qpolynomial *isl_qpolynomial_gist(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_set *context);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_from_constraint(
+	__isl_take isl_constraint *c, enum isl_dim_type type, unsigned pos);
+__isl_give isl_qpolynomial *isl_qpolynomial_from_term(__isl_take isl_term *term);
+__isl_give isl_qpolynomial *isl_qpolynomial_from_aff(__isl_take isl_aff *aff);
+__isl_give isl_basic_map *isl_basic_map_from_qpolynomial(
+	__isl_take isl_qpolynomial *qp);
+
+__isl_give isl_printer *isl_printer_print_qpolynomial(
+	__isl_take isl_printer *p, __isl_keep isl_qpolynomial *qp);
+void isl_qpolynomial_print(__isl_keep isl_qpolynomial *qp, FILE *out,
+	unsigned output_format);
+void isl_qpolynomial_dump(__isl_keep isl_qpolynomial *qp);
+
+isl_ctx *isl_pw_qpolynomial_get_ctx(__isl_keep isl_pw_qpolynomial *pwqp);
+
+isl_bool isl_pw_qpolynomial_involves_nan(__isl_keep isl_pw_qpolynomial *pwqp);
+isl_bool isl_pw_qpolynomial_plain_is_equal(__isl_keep isl_pw_qpolynomial *pwqp1,
+	__isl_keep isl_pw_qpolynomial *pwqp2);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_zero(__isl_take isl_space *dim);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_alloc(__isl_take isl_set *set,
+	__isl_take isl_qpolynomial *qp);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_qpolynomial(
+	__isl_take isl_qpolynomial *qp);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_copy(
+	__isl_keep isl_pw_qpolynomial *pwqp);
+__isl_null isl_pw_qpolynomial *isl_pw_qpolynomial_free(
+	__isl_take isl_pw_qpolynomial *pwqp);
+
+isl_bool isl_pw_qpolynomial_is_zero(__isl_keep isl_pw_qpolynomial *pwqp);
+
+__isl_give isl_space *isl_pw_qpolynomial_get_domain_space(
+	__isl_keep isl_pw_qpolynomial *pwqp);
+__isl_give isl_space *isl_pw_qpolynomial_get_space(
+	__isl_keep isl_pw_qpolynomial *pwqp);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_reset_domain_space(
+	__isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_space *dim);
+unsigned isl_pw_qpolynomial_dim(__isl_keep isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type type);
+isl_bool isl_pw_qpolynomial_involves_dims(__isl_keep isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type type, unsigned first, unsigned n);
+isl_bool isl_pw_qpolynomial_has_equal_space(
+	__isl_keep isl_pw_qpolynomial *pwqp1,
+	__isl_keep isl_pw_qpolynomial *pwqp2);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_set_dim_name(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type type, unsigned pos, const char *s);
+
+int isl_pw_qpolynomial_find_dim_by_name(__isl_keep isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type type, const char *name);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_reset_user(
+	__isl_take isl_pw_qpolynomial *pwqp);
+
+__isl_export
+__isl_give isl_set *isl_pw_qpolynomial_domain(__isl_take isl_pw_qpolynomial *pwqp);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_intersect_domain(
+	__isl_take isl_pw_qpolynomial *pwpq, __isl_take isl_set *set);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_intersect_params(
+	__isl_take isl_pw_qpolynomial *pwpq, __isl_take isl_set *set);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_subtract_domain(
+	__isl_take isl_pw_qpolynomial *pwpq, __isl_take isl_set *set);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_project_domain_on_params(
+	__isl_take isl_pw_qpolynomial *pwqp);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_range(
+	__isl_take isl_pw_qpolynomial *pwqp);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_drop_dims(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_split_dims(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add(
+	__isl_take isl_pw_qpolynomial *pwqp1,
+	__isl_take isl_pw_qpolynomial *pwqp2);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_sub(
+	__isl_take isl_pw_qpolynomial *pwqp1,
+	__isl_take isl_pw_qpolynomial *pwqp2);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_disjoint(
+	__isl_take isl_pw_qpolynomial *pwqp1,
+	__isl_take isl_pw_qpolynomial *pwqp2);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_neg(
+	__isl_take isl_pw_qpolynomial *pwqp);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_mul(
+	__isl_take isl_pw_qpolynomial *pwqp1,
+	__isl_take isl_pw_qpolynomial *pwqp2);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_scale_val(
+	__isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_val *v);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_scale_down_val(
+	__isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_val *v);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_pow(
+	__isl_take isl_pw_qpolynomial *pwqp, unsigned exponent);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_insert_dims(
+	__isl_take isl_pw_qpolynomial *pwqp, enum isl_dim_type type,
+	unsigned first, unsigned n);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_dims(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type type, unsigned n);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_move_dims(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_fix_val(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type type, unsigned n, __isl_take isl_val *v);
+
+__isl_export
+__isl_give isl_val *isl_pw_qpolynomial_eval(
+	__isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_point *pnt);
+
+__isl_give isl_val *isl_pw_qpolynomial_max(__isl_take isl_pw_qpolynomial *pwqp);
+__isl_give isl_val *isl_pw_qpolynomial_min(__isl_take isl_pw_qpolynomial *pwqp);
+
+int isl_pw_qpolynomial_n_piece(__isl_keep isl_pw_qpolynomial *pwqp);
+isl_stat isl_pw_qpolynomial_foreach_piece(__isl_keep isl_pw_qpolynomial *pwqp,
+	isl_stat (*fn)(__isl_take isl_set *set, __isl_take isl_qpolynomial *qp,
+		    void *user), void *user);
+isl_stat isl_pw_qpolynomial_foreach_lifted_piece(
+	__isl_keep isl_pw_qpolynomial *pwqp,
+	isl_stat (*fn)(__isl_take isl_set *set, __isl_take isl_qpolynomial *qp,
+		    void *user), void *user);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_pw_aff(
+	__isl_take isl_pw_aff *pwaff);
+
+__isl_constructor
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_str(isl_ctx *ctx,
+		const char *str);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_file(isl_ctx *ctx,
+		FILE *input);
+__isl_give char *isl_pw_qpolynomial_to_str(__isl_keep isl_pw_qpolynomial *pwqp);
+__isl_give isl_printer *isl_printer_print_pw_qpolynomial(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp);
+void isl_pw_qpolynomial_print(__isl_keep isl_pw_qpolynomial *pwqp, FILE *out,
+	unsigned output_format);
+void isl_pw_qpolynomial_dump(__isl_keep isl_pw_qpolynomial *pwqp);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_coalesce(
+	__isl_take isl_pw_qpolynomial *pwqp);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_gist(
+	__isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_set *context);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_gist_params(
+	__isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_set *context);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_split_periods(
+	__isl_take isl_pw_qpolynomial *pwqp, int max_periods);
+
+__isl_give isl_pw_qpolynomial *isl_basic_set_multiplicative_call(
+	__isl_take isl_basic_set *bset,
+	__isl_give isl_pw_qpolynomial *(*fn)(__isl_take isl_basic_set *bset));
+
+isl_ctx *isl_qpolynomial_fold_get_ctx(__isl_keep isl_qpolynomial_fold *fold);
+enum isl_fold isl_qpolynomial_fold_get_type(__isl_keep isl_qpolynomial_fold *fold);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type,
+	__isl_take isl_space *dim);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_alloc(
+	enum isl_fold type, __isl_take isl_qpolynomial *qp);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_copy(
+	__isl_keep isl_qpolynomial_fold *fold);
+void isl_qpolynomial_fold_free(__isl_take isl_qpolynomial_fold *fold);
+
+int isl_qpolynomial_fold_is_empty(__isl_keep isl_qpolynomial_fold *fold);
+isl_bool isl_qpolynomial_fold_is_nan(__isl_keep isl_qpolynomial_fold *fold);
+int isl_qpolynomial_fold_plain_is_equal(__isl_keep isl_qpolynomial_fold *fold1,
+	__isl_keep isl_qpolynomial_fold *fold2);
+
+__isl_give isl_space *isl_qpolynomial_fold_get_domain_space(
+	__isl_keep isl_qpolynomial_fold *fold);
+__isl_give isl_space *isl_qpolynomial_fold_get_space(
+	__isl_keep isl_qpolynomial_fold *fold);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold(
+	__isl_take isl_qpolynomial_fold *fold1,
+	__isl_take isl_qpolynomial_fold *fold2);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_val(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_down_val(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims(
+	__isl_take isl_qpolynomial_fold *fold,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute(
+	__isl_take isl_qpolynomial_fold *fold,
+	enum isl_dim_type type, unsigned first, unsigned n,
+	__isl_keep isl_qpolynomial **subs);
+
+__isl_give isl_val *isl_qpolynomial_fold_eval(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_point *pnt);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context);
+
+isl_stat isl_qpolynomial_fold_foreach_qpolynomial(
+	__isl_keep isl_qpolynomial_fold *fold,
+	isl_stat (*fn)(__isl_take isl_qpolynomial *qp, void *user), void *user);
+
+__isl_give isl_printer *isl_printer_print_qpolynomial_fold(
+	__isl_take isl_printer *p, __isl_keep isl_qpolynomial_fold *fold);
+void isl_qpolynomial_fold_print(__isl_keep isl_qpolynomial_fold *fold, FILE *out,
+	unsigned output_format);
+void isl_qpolynomial_fold_dump(__isl_keep isl_qpolynomial_fold *fold);
+
+isl_ctx *isl_pw_qpolynomial_fold_get_ctx(__isl_keep isl_pw_qpolynomial_fold *pwf);
+
+isl_bool isl_pw_qpolynomial_fold_involves_nan(
+	__isl_keep isl_pw_qpolynomial_fold *pwf);
+isl_bool isl_pw_qpolynomial_fold_plain_is_equal(
+	__isl_keep isl_pw_qpolynomial_fold *pwf1,
+	__isl_keep isl_pw_qpolynomial_fold *pwf2);
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial(
+	enum isl_fold type, __isl_take isl_pw_qpolynomial *pwqp);
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_alloc(
+	enum isl_fold type,
+	__isl_take isl_set *set, __isl_take isl_qpolynomial_fold *fold);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_copy(
+	__isl_keep isl_pw_qpolynomial_fold *pwf);
+__isl_null isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_free(
+	__isl_take isl_pw_qpolynomial_fold *pwf);
+
+isl_bool isl_pw_qpolynomial_fold_is_zero(
+	__isl_keep isl_pw_qpolynomial_fold *pwf);
+
+__isl_give isl_space *isl_pw_qpolynomial_fold_get_domain_space(
+	__isl_keep isl_pw_qpolynomial_fold *pwf);
+__isl_give isl_space *isl_pw_qpolynomial_fold_get_space(
+	__isl_keep isl_pw_qpolynomial_fold *pwf);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_reset_space(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_space *dim);
+unsigned isl_pw_qpolynomial_fold_dim(__isl_keep isl_pw_qpolynomial_fold *pwf,
+	enum isl_dim_type type);
+isl_bool isl_pw_qpolynomial_fold_has_equal_space(
+	__isl_keep isl_pw_qpolynomial_fold *pwf1,
+	__isl_keep isl_pw_qpolynomial_fold *pwf2);
+
+size_t isl_pw_qpolynomial_fold_size(__isl_keep isl_pw_qpolynomial_fold *pwf);
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_zero(
+	__isl_take isl_space *dim, enum isl_fold type);
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_set_dim_name(
+	__isl_take isl_pw_qpolynomial_fold *pwf,
+	enum isl_dim_type type, unsigned pos, const char *s);
+
+int isl_pw_qpolynomial_fold_find_dim_by_name(
+	__isl_keep isl_pw_qpolynomial_fold *pwf,
+	enum isl_dim_type type, const char *name);
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_reset_user(
+	__isl_take isl_pw_qpolynomial_fold *pwf);
+
+__isl_give isl_set *isl_pw_qpolynomial_fold_domain(
+	__isl_take isl_pw_qpolynomial_fold *pwf);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_intersect_domain(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *set);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_intersect_params(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *set);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_subtract_domain(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *set);
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add(
+	__isl_take isl_pw_qpolynomial_fold *pwf1,
+	__isl_take isl_pw_qpolynomial_fold *pwf2);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold(
+	__isl_take isl_pw_qpolynomial_fold *pwf1,
+	__isl_take isl_pw_qpolynomial_fold *pwf2);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add_disjoint(
+	__isl_take isl_pw_qpolynomial_fold *pwf1,
+	__isl_take isl_pw_qpolynomial_fold *pwf2);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_scale_val(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_val *v);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_scale_down_val(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_val *v);
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_project_domain_on_params(
+	__isl_take isl_pw_qpolynomial_fold *pwf);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_range(
+	__isl_take isl_pw_qpolynomial_fold *pwf);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_drop_dims(
+	__isl_take isl_pw_qpolynomial_fold *pwf,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_move_dims(
+	__isl_take isl_pw_qpolynomial_fold *pwf,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+
+__isl_give isl_val *isl_pw_qpolynomial_fold_eval(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_point *pnt);
+
+int isl_pw_qpolynomial_fold_n_piece(__isl_keep isl_pw_qpolynomial_fold *pwf);
+isl_stat isl_pw_qpolynomial_fold_foreach_piece(
+	__isl_keep isl_pw_qpolynomial_fold *pwf,
+	isl_stat (*fn)(__isl_take isl_set *set,
+		__isl_take isl_qpolynomial_fold *fold, void *user), void *user);
+isl_stat isl_pw_qpolynomial_fold_foreach_lifted_piece(
+	__isl_keep isl_pw_qpolynomial_fold *pwf,
+	isl_stat (*fn)(__isl_take isl_set *set,
+		__isl_take isl_qpolynomial_fold *fold, void *user), void *user);
+
+__isl_give isl_printer *isl_printer_print_pw_qpolynomial_fold(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf);
+void isl_pw_qpolynomial_fold_print(__isl_keep isl_pw_qpolynomial_fold *pwf,
+	FILE *out, unsigned output_format);
+void isl_pw_qpolynomial_fold_dump(__isl_keep isl_pw_qpolynomial_fold *pwf);
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_coalesce(
+	__isl_take isl_pw_qpolynomial_fold *pwf);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_gist(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *context);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_gist_params(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_set *context);
+
+__isl_give isl_val *isl_pw_qpolynomial_fold_max(
+	__isl_take isl_pw_qpolynomial_fold *pwf);
+__isl_give isl_val *isl_pw_qpolynomial_fold_min(
+	__isl_take isl_pw_qpolynomial_fold *pwf);
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_bound(
+	__isl_take isl_pw_qpolynomial *pwqp, enum isl_fold type, int *tight);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_bound(
+	__isl_take isl_pw_qpolynomial_fold *pwf, int *tight);
+__isl_give isl_pw_qpolynomial_fold *isl_set_apply_pw_qpolynomial_fold(
+	__isl_take isl_set *set, __isl_take isl_pw_qpolynomial_fold *pwf,
+	int *tight);
+__isl_give isl_pw_qpolynomial_fold *isl_map_apply_pw_qpolynomial_fold(
+	__isl_take isl_map *map, __isl_take isl_pw_qpolynomial_fold *pwf,
+	int *tight);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_to_polynomial(
+	__isl_take isl_pw_qpolynomial *pwqp, int sign);
+
+isl_ctx *isl_union_pw_qpolynomial_get_ctx(
+	__isl_keep isl_union_pw_qpolynomial *upwqp);
+
+unsigned isl_union_pw_qpolynomial_dim(
+	__isl_keep isl_union_pw_qpolynomial *upwqp, enum isl_dim_type type);
+
+isl_bool isl_union_pw_qpolynomial_involves_nan(
+	__isl_keep isl_union_pw_qpolynomial *upwqp);
+isl_bool isl_union_pw_qpolynomial_plain_is_equal(
+	__isl_keep isl_union_pw_qpolynomial *upwqp1,
+	__isl_keep isl_union_pw_qpolynomial *upwqp2);
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_from_pw_qpolynomial(__isl_take isl_pw_qpolynomial *pwqp);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_zero(
+	__isl_take isl_space *dim);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_add_pw_qpolynomial(
+	__isl_take isl_union_pw_qpolynomial *upwqp,
+	__isl_take isl_pw_qpolynomial *pwqp);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_copy(
+	__isl_keep isl_union_pw_qpolynomial *upwqp);
+__isl_null isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_free(
+	__isl_take isl_union_pw_qpolynomial *upwqp);
+
+__isl_constructor
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_read_from_str(
+	isl_ctx *ctx, const char *str);
+__isl_give char *isl_union_pw_qpolynomial_to_str(
+	__isl_keep isl_union_pw_qpolynomial *upwqp);
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_neg(
+	__isl_take isl_union_pw_qpolynomial *upwqp);
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_add(
+	__isl_take isl_union_pw_qpolynomial *upwqp1,
+	__isl_take isl_union_pw_qpolynomial *upwqp2);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_sub(
+	__isl_take isl_union_pw_qpolynomial *upwqp1,
+	__isl_take isl_union_pw_qpolynomial *upwqp2);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_mul(
+	__isl_take isl_union_pw_qpolynomial *upwqp1,
+	__isl_take isl_union_pw_qpolynomial *upwqp2);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_scale_val(
+	__isl_take isl_union_pw_qpolynomial *upwqp, __isl_take isl_val *v);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_scale_down_val(
+	__isl_take isl_union_pw_qpolynomial *upwqp, __isl_take isl_val *v);
+
+__isl_export
+__isl_give isl_union_set *isl_union_pw_qpolynomial_domain(
+	__isl_take isl_union_pw_qpolynomial *upwqp);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_intersect_domain(
+	__isl_take isl_union_pw_qpolynomial *upwpq,
+	__isl_take isl_union_set *uset);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_intersect_params(
+	__isl_take isl_union_pw_qpolynomial *upwpq,
+	__isl_take isl_set *set);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_subtract_domain(
+	__isl_take isl_union_pw_qpolynomial *upwpq,
+	__isl_take isl_union_set *uset);
+
+__isl_give isl_space *isl_union_pw_qpolynomial_get_space(
+	__isl_keep isl_union_pw_qpolynomial *upwqp);
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_set_dim_name(
+	__isl_take isl_union_pw_qpolynomial *upwqp,
+	enum isl_dim_type type, unsigned pos, const char *s);
+
+int isl_union_pw_qpolynomial_find_dim_by_name(
+	__isl_keep isl_union_pw_qpolynomial *upwqp,
+	enum isl_dim_type type, const char *name);
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_drop_dims(
+	__isl_take isl_union_pw_qpolynomial *upwqp,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_reset_user(
+	__isl_take isl_union_pw_qpolynomial *upwqp);
+
+__isl_export
+__isl_give isl_val *isl_union_pw_qpolynomial_eval(
+	__isl_take isl_union_pw_qpolynomial *upwqp, __isl_take isl_point *pnt);
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_coalesce(
+	__isl_take isl_union_pw_qpolynomial *upwqp);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_gist(
+	__isl_take isl_union_pw_qpolynomial *upwqp,
+	__isl_take isl_union_set *context);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_gist_params(
+	__isl_take isl_union_pw_qpolynomial *upwqp,
+	__isl_take isl_set *context);
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_align_params(
+	__isl_take isl_union_pw_qpolynomial *upwqp,
+	__isl_take isl_space *model);
+
+int isl_union_pw_qpolynomial_n_pw_qpolynomial(
+	__isl_keep isl_union_pw_qpolynomial *upwqp);
+isl_stat isl_union_pw_qpolynomial_foreach_pw_qpolynomial(
+	__isl_keep isl_union_pw_qpolynomial *upwqp,
+	isl_stat (*fn)(__isl_take isl_pw_qpolynomial *pwqp, void *user),
+	void *user);
+__isl_give isl_pw_qpolynomial *isl_union_pw_qpolynomial_extract_pw_qpolynomial(
+	__isl_keep isl_union_pw_qpolynomial *upwqp, __isl_take isl_space *dim);
+
+__isl_give isl_printer *isl_printer_print_union_pw_qpolynomial(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_qpolynomial *upwqp);
+
+isl_ctx *isl_union_pw_qpolynomial_fold_get_ctx(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf);
+
+unsigned isl_union_pw_qpolynomial_fold_dim(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf, enum isl_dim_type type);
+
+isl_bool isl_union_pw_qpolynomial_fold_involves_nan(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf);
+isl_bool isl_union_pw_qpolynomial_fold_plain_is_equal(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf1,
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf2);
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_from_pw_qpolynomial_fold(__isl_take isl_pw_qpolynomial_fold *pwf);
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_zero(
+	__isl_take isl_space *dim, enum isl_fold type);
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
+	__isl_take isl_union_pw_qpolynomial_fold *upwqp,
+	__isl_take isl_pw_qpolynomial_fold *pwqp);
+__isl_null isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_free(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf);
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_copy(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf);
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf1,
+	__isl_take isl_union_pw_qpolynomial_fold *upwf2);
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf,
+	__isl_take isl_union_pw_qpolynomial *upwqp);
+__isl_give isl_union_pw_qpolynomial_fold *
+isl_union_pw_qpolynomial_fold_scale_val(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf, __isl_take isl_val *v);
+__isl_give isl_union_pw_qpolynomial_fold *
+isl_union_pw_qpolynomial_fold_scale_down_val(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf, __isl_take isl_val *v);
+
+__isl_give isl_union_set *isl_union_pw_qpolynomial_fold_domain(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf);
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_intersect_domain(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf,
+	__isl_take isl_union_set *uset);
+__isl_give isl_union_pw_qpolynomial_fold *
+isl_union_pw_qpolynomial_fold_intersect_params(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf,
+	__isl_take isl_set *set);
+__isl_give isl_union_pw_qpolynomial_fold *
+isl_union_pw_qpolynomial_fold_subtract_domain(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf,
+	__isl_take isl_union_set *uset);
+
+enum isl_fold isl_union_pw_qpolynomial_fold_get_type(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf);
+__isl_give isl_space *isl_union_pw_qpolynomial_fold_get_space(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf);
+
+__isl_give isl_union_pw_qpolynomial_fold *
+isl_union_pw_qpolynomial_fold_set_dim_name(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf,
+	enum isl_dim_type type, unsigned pos, const char *s);
+
+int isl_union_pw_qpolynomial_fold_find_dim_by_name(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf,
+	enum isl_dim_type type, const char *name);
+
+__isl_give isl_union_pw_qpolynomial_fold *
+	isl_union_pw_qpolynomial_fold_drop_dims(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_union_pw_qpolynomial_fold *
+isl_union_pw_qpolynomial_fold_reset_user(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf);
+
+__isl_give isl_val *isl_union_pw_qpolynomial_fold_eval(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf,
+	__isl_take isl_point *pnt);
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_coalesce(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf);
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_gist(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf,
+	__isl_take isl_union_set *context);
+__isl_give isl_union_pw_qpolynomial_fold *
+isl_union_pw_qpolynomial_fold_gist_params(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf,
+	__isl_take isl_set *context);
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_align_params(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf,
+	__isl_take isl_space *model);
+
+int isl_union_pw_qpolynomial_fold_n_pw_qpolynomial_fold(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf);
+isl_stat isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf,
+	isl_stat (*fn)(__isl_take isl_pw_qpolynomial_fold *pwf,
+		    void *user), void *user);
+__isl_give isl_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_extract_pw_qpolynomial_fold(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf, __isl_take isl_space *dim);
+
+__isl_give isl_printer *isl_printer_print_union_pw_qpolynomial_fold(
+	__isl_take isl_printer *p,
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf);
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_bound(
+	__isl_take isl_union_pw_qpolynomial *upwqp,
+	enum isl_fold type, int *tight);
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_set_apply_union_pw_qpolynomial_fold(
+	__isl_take isl_union_set *uset,
+	__isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight);
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_map_apply_union_pw_qpolynomial_fold(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight);
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_to_polynomial(
+	__isl_take isl_union_pw_qpolynomial *upwqp, int sign);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/polynomial_type.h b/final/lib/External/isl/include/isl/polynomial_type.h
new file mode 100644
index 0000000..df432bd
--- /dev/null
+++ b/final/lib/External/isl/include/isl/polynomial_type.h
@@ -0,0 +1,31 @@
+#ifndef ISL_POLYNOMIAL_TYPE_H
+#define ISL_POLYNOMIAL_TYPE_H
+
+struct isl_qpolynomial;
+typedef struct isl_qpolynomial isl_qpolynomial;
+
+struct isl_term;
+typedef struct isl_term isl_term;
+
+struct __isl_export isl_pw_qpolynomial;
+typedef struct isl_pw_qpolynomial isl_pw_qpolynomial;
+
+enum isl_fold {
+	isl_fold_min,
+	isl_fold_max,
+	isl_fold_list
+};
+
+struct isl_qpolynomial_fold;
+typedef struct isl_qpolynomial_fold isl_qpolynomial_fold;
+
+struct isl_pw_qpolynomial_fold;
+typedef struct isl_pw_qpolynomial_fold isl_pw_qpolynomial_fold;
+
+struct __isl_export isl_union_pw_qpolynomial;
+typedef struct isl_union_pw_qpolynomial isl_union_pw_qpolynomial;
+
+struct isl_union_pw_qpolynomial_fold;
+typedef struct isl_union_pw_qpolynomial_fold isl_union_pw_qpolynomial_fold;
+
+#endif
diff --git a/final/lib/External/isl/include/isl/printer.h b/final/lib/External/isl/include/isl/printer.h
new file mode 100644
index 0000000..dd50e91
--- /dev/null
+++ b/final/lib/External/isl/include/isl/printer.h
@@ -0,0 +1,84 @@
+#ifndef ISL_PRINTER_H
+#define ISL_PRINTER_H
+
+#include <stdio.h>
+#include <isl/ctx.h>
+#include <isl/printer_type.h>
+#include <isl/id.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file);
+__isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx);
+__isl_null isl_printer *isl_printer_free(__isl_take isl_printer *printer);
+
+isl_ctx *isl_printer_get_ctx(__isl_keep isl_printer *printer);
+FILE *isl_printer_get_file(__isl_keep isl_printer *printer);
+
+__isl_give char *isl_printer_get_str(__isl_keep isl_printer *printer);
+
+__isl_give isl_printer *isl_printer_set_indent(__isl_take isl_printer *p,
+	int indent);
+__isl_give isl_printer *isl_printer_indent(__isl_take isl_printer *p,
+	int indent);
+
+#define ISL_FORMAT_ISL			0
+#define ISL_FORMAT_POLYLIB		1
+#define ISL_FORMAT_POLYLIB_CONSTRAINTS	2
+#define ISL_FORMAT_OMEGA		3
+#define ISL_FORMAT_C			4
+#define ISL_FORMAT_LATEX		5
+#define ISL_FORMAT_EXT_POLYLIB		6
+__isl_give isl_printer *isl_printer_set_output_format(__isl_take isl_printer *p,
+	int output_format);
+int isl_printer_get_output_format(__isl_keep isl_printer *p);
+
+#define ISL_YAML_STYLE_BLOCK		0
+#define ISL_YAML_STYLE_FLOW		1
+__isl_give isl_printer *isl_printer_set_yaml_style(__isl_take isl_printer *p,
+	int yaml_style);
+int isl_printer_get_yaml_style(__isl_keep isl_printer *p);
+
+__isl_give isl_printer *isl_printer_set_indent_prefix(__isl_take isl_printer *p,
+	const char *prefix);
+__isl_give isl_printer *isl_printer_set_prefix(__isl_take isl_printer *p,
+	const char *prefix);
+__isl_give isl_printer *isl_printer_set_suffix(__isl_take isl_printer *p,
+	const char *suffix);
+__isl_give isl_printer *isl_printer_set_isl_int_width(__isl_take isl_printer *p,
+	int width);
+
+isl_bool isl_printer_has_note(__isl_keep isl_printer *p,
+	__isl_keep isl_id *id);
+__isl_give isl_id *isl_printer_get_note(__isl_keep isl_printer *p,
+	__isl_take isl_id *id);
+__isl_give isl_printer *isl_printer_set_note(__isl_take isl_printer *p,
+	__isl_take isl_id *id, __isl_take isl_id *note);
+
+__isl_give isl_printer *isl_printer_start_line(__isl_take isl_printer *p);
+__isl_give isl_printer *isl_printer_end_line(__isl_take isl_printer *p);
+__isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p,
+	double d);
+__isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i);
+__isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p,
+	const char *s);
+
+__isl_give isl_printer *isl_printer_yaml_start_mapping(
+	__isl_take isl_printer *p);
+__isl_give isl_printer *isl_printer_yaml_end_mapping(
+	__isl_take isl_printer *p);
+__isl_give isl_printer *isl_printer_yaml_start_sequence(
+	__isl_take isl_printer *p);
+__isl_give isl_printer *isl_printer_yaml_end_sequence(
+	__isl_take isl_printer *p);
+__isl_give isl_printer *isl_printer_yaml_next(__isl_take isl_printer *p);
+
+__isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/printer_type.h b/final/lib/External/isl/include/isl/printer_type.h
new file mode 100644
index 0000000..985f8ca
--- /dev/null
+++ b/final/lib/External/isl/include/isl/printer_type.h
@@ -0,0 +1,15 @@
+#ifndef ISL_PRINTER_TYPE_H
+#define ISL_PRINTER_TYPE_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_printer;
+typedef struct isl_printer isl_printer;
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/schedule.h b/final/lib/External/isl/include/isl/schedule.h
new file mode 100644
index 0000000..7970b64
--- /dev/null
+++ b/final/lib/External/isl/include/isl/schedule.h
@@ -0,0 +1,205 @@
+#ifndef ISL_SCHEDULE_H
+#define ISL_SCHEDULE_H
+
+#include <isl/union_set_type.h>
+#include <isl/union_map_type.h>
+#include <isl/schedule_type.h>
+#include <isl/aff_type.h>
+#include <isl/band.h>
+#include <isl/space.h>
+#include <isl/set_type.h>
+#include <isl/list.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct __isl_export isl_schedule_constraints;
+typedef struct isl_schedule_constraints isl_schedule_constraints;
+
+isl_stat isl_options_set_schedule_max_coefficient(isl_ctx *ctx, int val);
+int isl_options_get_schedule_max_coefficient(isl_ctx *ctx);
+
+isl_stat isl_options_set_schedule_max_constant_term(isl_ctx *ctx, int val);
+int isl_options_get_schedule_max_constant_term(isl_ctx *ctx);
+
+isl_stat isl_options_set_schedule_maximize_band_depth(isl_ctx *ctx, int val);
+int isl_options_get_schedule_maximize_band_depth(isl_ctx *ctx);
+
+isl_stat isl_options_set_schedule_maximize_coincidence(isl_ctx *ctx, int val);
+int isl_options_get_schedule_maximize_coincidence(isl_ctx *ctx);
+
+isl_stat isl_options_set_schedule_outer_coincidence(isl_ctx *ctx, int val);
+int isl_options_get_schedule_outer_coincidence(isl_ctx *ctx);
+
+isl_stat isl_options_set_schedule_split_scaled(isl_ctx *ctx, int val);
+int isl_options_get_schedule_split_scaled(isl_ctx *ctx);
+
+isl_stat isl_options_set_schedule_treat_coalescing(isl_ctx *ctx, int val);
+int isl_options_get_schedule_treat_coalescing(isl_ctx *ctx);
+
+isl_stat isl_options_set_schedule_separate_components(isl_ctx *ctx, int val);
+int isl_options_get_schedule_separate_components(isl_ctx *ctx);
+
+isl_stat isl_options_set_schedule_serialize_sccs(isl_ctx *ctx, int val);
+int isl_options_get_schedule_serialize_sccs(isl_ctx *ctx);
+
+isl_stat isl_options_set_schedule_whole_component(isl_ctx *ctx, int val);
+int isl_options_get_schedule_whole_component(isl_ctx *ctx);
+
+isl_stat isl_options_set_schedule_carry_self_first(isl_ctx *ctx, int val);
+int isl_options_get_schedule_carry_self_first(isl_ctx *ctx);
+
+__isl_give isl_schedule_constraints *isl_schedule_constraints_copy(
+	__isl_keep isl_schedule_constraints *sc);
+__isl_export
+__isl_give isl_schedule_constraints *isl_schedule_constraints_on_domain(
+	__isl_take isl_union_set *domain);
+__isl_export
+__isl_give isl_schedule_constraints *isl_schedule_constraints_set_context(
+	__isl_take isl_schedule_constraints *sc, __isl_take isl_set *context);
+__isl_export
+__isl_give isl_schedule_constraints *isl_schedule_constraints_set_validity(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *validity);
+__isl_export
+__isl_give isl_schedule_constraints *isl_schedule_constraints_set_coincidence(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *coincidence);
+__isl_export
+__isl_give isl_schedule_constraints *isl_schedule_constraints_set_proximity(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *proximity);
+__isl_export
+__isl_give isl_schedule_constraints *
+isl_schedule_constraints_set_conditional_validity(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *condition,
+	__isl_take isl_union_map *validity);
+__isl_null isl_schedule_constraints *isl_schedule_constraints_free(
+	__isl_take isl_schedule_constraints *sc);
+
+isl_ctx *isl_schedule_constraints_get_ctx(
+	__isl_keep isl_schedule_constraints *sc);
+__isl_export
+__isl_give isl_union_set *isl_schedule_constraints_get_domain(
+	__isl_keep isl_schedule_constraints *sc);
+__isl_export
+__isl_give isl_set *isl_schedule_constraints_get_context(
+	__isl_keep isl_schedule_constraints *sc);
+__isl_export
+__isl_give isl_union_map *isl_schedule_constraints_get_validity(
+	__isl_keep isl_schedule_constraints *sc);
+__isl_export
+__isl_give isl_union_map *isl_schedule_constraints_get_coincidence(
+	__isl_keep isl_schedule_constraints *sc);
+__isl_export
+__isl_give isl_union_map *isl_schedule_constraints_get_proximity(
+	__isl_keep isl_schedule_constraints *sc);
+__isl_export
+__isl_give isl_union_map *isl_schedule_constraints_get_conditional_validity(
+	__isl_keep isl_schedule_constraints *sc);
+__isl_export
+__isl_give isl_union_map *
+isl_schedule_constraints_get_conditional_validity_condition(
+	__isl_keep isl_schedule_constraints *sc);
+
+__isl_give isl_schedule_constraints *isl_schedule_constraints_apply(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *umap);
+
+__isl_constructor
+__isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_str(
+	isl_ctx *ctx, const char *str);
+__isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_file(
+	isl_ctx *ctx, FILE *input);
+__isl_give isl_printer *isl_printer_print_schedule_constraints(
+	__isl_take isl_printer *p, __isl_keep isl_schedule_constraints *sc);
+void isl_schedule_constraints_dump(__isl_keep isl_schedule_constraints *sc);
+__isl_give char *isl_schedule_constraints_to_str(
+	__isl_keep isl_schedule_constraints *sc);
+
+__isl_export
+__isl_give isl_schedule *isl_schedule_constraints_compute_schedule(
+	__isl_take isl_schedule_constraints *sc);
+
+__isl_give isl_schedule *isl_union_set_compute_schedule(
+	__isl_take isl_union_set *domain,
+	__isl_take isl_union_map *validity,
+	__isl_take isl_union_map *proximity);
+
+__isl_give isl_schedule *isl_schedule_empty(__isl_take isl_space *space);
+__isl_give isl_schedule *isl_schedule_from_domain(
+	__isl_take isl_union_set *domain);
+__isl_give isl_schedule *isl_schedule_copy(__isl_keep isl_schedule *sched);
+__isl_null isl_schedule *isl_schedule_free(__isl_take isl_schedule *sched);
+__isl_export
+__isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched);
+
+isl_ctx *isl_schedule_get_ctx(__isl_keep isl_schedule *sched);
+isl_bool isl_schedule_plain_is_equal(__isl_keep isl_schedule *schedule1,
+	__isl_keep isl_schedule *schedule2);
+
+__isl_export
+__isl_give isl_schedule_node *isl_schedule_get_root(
+	__isl_keep isl_schedule *schedule);
+__isl_give isl_union_set *isl_schedule_get_domain(
+	__isl_keep isl_schedule *schedule);
+
+isl_stat isl_schedule_foreach_schedule_node_top_down(
+	__isl_keep isl_schedule *sched,
+	isl_bool (*fn)(__isl_keep isl_schedule_node *node, void *user),
+	void *user);
+__isl_give isl_schedule *isl_schedule_map_schedule_node_bottom_up(
+	__isl_take isl_schedule *schedule,
+	__isl_give isl_schedule_node *(*fn)(
+		__isl_take isl_schedule_node *node, void *user), void *user);
+
+__isl_give isl_schedule *isl_schedule_insert_context(
+	__isl_take isl_schedule *schedule, __isl_take isl_set *context);
+__isl_give isl_schedule *isl_schedule_insert_partial_schedule(
+	__isl_take isl_schedule *schedule,
+	__isl_take isl_multi_union_pw_aff *partial);
+__isl_give isl_schedule *isl_schedule_insert_guard(
+	__isl_take isl_schedule *schedule, __isl_take isl_set *guard);
+__isl_give isl_schedule *isl_schedule_sequence(
+	__isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2);
+__isl_give isl_schedule *isl_schedule_set(
+	__isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2);
+__isl_give isl_schedule *isl_schedule_intersect_domain(
+	__isl_take isl_schedule *schedule, __isl_take isl_union_set *domain);
+__isl_give isl_schedule *isl_schedule_gist_domain_params(
+	__isl_take isl_schedule *schedule, __isl_take isl_set *context);
+
+__isl_give isl_schedule *isl_schedule_reset_user(
+	__isl_take isl_schedule *schedule);
+__isl_give isl_schedule *isl_schedule_align_params(
+	__isl_take isl_schedule *schedule, __isl_take isl_space *space);
+__isl_overload
+__isl_give isl_schedule *isl_schedule_pullback_union_pw_multi_aff(
+	__isl_take isl_schedule *schedule,
+	__isl_take isl_union_pw_multi_aff *upma);
+__isl_give isl_schedule *isl_schedule_expand(__isl_take isl_schedule *schedule,
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_schedule *expansion);
+
+__isl_give isl_band_list *isl_schedule_get_band_forest(
+	__isl_keep isl_schedule *schedule);
+
+__isl_give isl_schedule *isl_schedule_read_from_file(isl_ctx *ctx, FILE *input);
+__isl_constructor
+__isl_give isl_schedule *isl_schedule_read_from_str(isl_ctx *ctx,
+	const char *str);
+__isl_give isl_printer *isl_printer_print_schedule(__isl_take isl_printer *p,
+	__isl_keep isl_schedule *schedule);
+void isl_schedule_dump(__isl_keep isl_schedule *schedule);
+__isl_give char *isl_schedule_to_str(__isl_keep isl_schedule *schedule);
+
+int isl_schedule_foreach_band(__isl_keep isl_schedule *sched,
+	int (*fn)(__isl_keep isl_band *band, void *user), void *user);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/schedule_node.h b/final/lib/External/isl/include/isl/schedule_node.h
new file mode 100644
index 0000000..51b31f9
--- /dev/null
+++ b/final/lib/External/isl/include/isl/schedule_node.h
@@ -0,0 +1,239 @@
+#ifndef ISL_SCHEDULE_NODE_H
+#define ISL_SCHEDULE_NODE_H
+
+#include <isl/schedule_type.h>
+#include <isl/union_set_type.h>
+#include <isl/aff_type.h>
+#include <isl/ast_type.h>
+#include <isl/val.h>
+#include <isl/space.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_schedule_node *isl_schedule_node_from_domain(
+	__isl_take isl_union_set *domain);
+__isl_give isl_schedule_node *isl_schedule_node_from_extension(
+	__isl_take isl_union_map *extension);
+__isl_give isl_schedule_node *isl_schedule_node_copy(
+	__isl_keep isl_schedule_node *node);
+__isl_null isl_schedule_node *isl_schedule_node_free(
+	__isl_take isl_schedule_node *node);
+
+isl_bool isl_schedule_node_is_equal(__isl_keep isl_schedule_node *node1,
+	__isl_keep isl_schedule_node *node2);
+
+isl_ctx *isl_schedule_node_get_ctx(__isl_keep isl_schedule_node *node);
+enum isl_schedule_node_type isl_schedule_node_get_type(
+	__isl_keep isl_schedule_node *node);
+enum isl_schedule_node_type isl_schedule_node_get_parent_type(
+	__isl_keep isl_schedule_node *node);
+__isl_export
+__isl_give isl_schedule *isl_schedule_node_get_schedule(
+	__isl_keep isl_schedule_node *node);
+
+isl_stat isl_schedule_node_foreach_descendant_top_down(
+	__isl_keep isl_schedule_node *node,
+	isl_bool (*fn)(__isl_keep isl_schedule_node *node, void *user),
+	void *user);
+isl_stat isl_schedule_node_foreach_ancestor_top_down(
+	__isl_keep isl_schedule_node *node,
+	isl_stat (*fn)(__isl_keep isl_schedule_node *node, void *user),
+	void *user);
+__isl_give isl_schedule_node *isl_schedule_node_map_descendant_bottom_up(
+	__isl_take isl_schedule_node *node,
+	__isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node,
+		void *user), void *user);
+
+int isl_schedule_node_get_tree_depth(__isl_keep isl_schedule_node *node);
+isl_bool isl_schedule_node_has_parent(__isl_keep isl_schedule_node *node);
+isl_bool isl_schedule_node_has_children(__isl_keep isl_schedule_node *node);
+isl_bool isl_schedule_node_has_previous_sibling(
+	__isl_keep isl_schedule_node *node);
+isl_bool isl_schedule_node_has_next_sibling(__isl_keep isl_schedule_node *node);
+int isl_schedule_node_n_children(__isl_keep isl_schedule_node *node);
+int isl_schedule_node_get_child_position(__isl_keep isl_schedule_node *node);
+int isl_schedule_node_get_ancestor_child_position(
+	__isl_keep isl_schedule_node *node,
+	__isl_keep isl_schedule_node *ancestor);
+__isl_give isl_schedule_node *isl_schedule_node_get_child(
+	__isl_keep isl_schedule_node *node, int pos);
+__isl_give isl_schedule_node *isl_schedule_node_get_shared_ancestor(
+	__isl_keep isl_schedule_node *node1,
+	__isl_keep isl_schedule_node *node2);
+
+__isl_give isl_schedule_node *isl_schedule_node_root(
+	__isl_take isl_schedule_node *node);
+__isl_export
+__isl_give isl_schedule_node *isl_schedule_node_parent(
+	__isl_take isl_schedule_node *node);
+__isl_give isl_schedule_node *isl_schedule_node_ancestor(
+	__isl_take isl_schedule_node *node, int generation);
+__isl_export
+__isl_give isl_schedule_node *isl_schedule_node_child(
+	__isl_take isl_schedule_node *node, int pos);
+__isl_give isl_schedule_node *isl_schedule_node_first_child(
+	__isl_take isl_schedule_node *node);
+__isl_give isl_schedule_node *isl_schedule_node_previous_sibling(
+	__isl_take isl_schedule_node *node);
+__isl_give isl_schedule_node *isl_schedule_node_next_sibling(
+	__isl_take isl_schedule_node *node);
+
+isl_bool isl_schedule_node_is_subtree_anchored(
+	__isl_keep isl_schedule_node *node);
+
+__isl_give isl_schedule_node *isl_schedule_node_group(
+	__isl_take isl_schedule_node *node, __isl_take isl_id *group_id);
+
+__isl_give isl_schedule_node *isl_schedule_node_sequence_splice_child(
+	__isl_take isl_schedule_node *node, int pos);
+
+__isl_give isl_space *isl_schedule_node_band_get_space(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_multi_union_pw_aff *isl_schedule_node_band_get_partial_schedule(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_union_map *isl_schedule_node_band_get_partial_schedule_union_map(
+	__isl_keep isl_schedule_node *node);
+enum isl_ast_loop_type isl_schedule_node_band_member_get_ast_loop_type(
+	__isl_keep isl_schedule_node *node, int pos);
+__isl_give isl_schedule_node *isl_schedule_node_band_member_set_ast_loop_type(
+	__isl_take isl_schedule_node *node, int pos,
+	enum isl_ast_loop_type type);
+enum isl_ast_loop_type isl_schedule_node_band_member_get_isolate_ast_loop_type(
+	__isl_keep isl_schedule_node *node, int pos);
+__isl_give isl_schedule_node *
+isl_schedule_node_band_member_set_isolate_ast_loop_type(
+	__isl_take isl_schedule_node *node, int pos,
+	enum isl_ast_loop_type type);
+__isl_give isl_union_set *isl_schedule_node_band_get_ast_build_options(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_schedule_node *isl_schedule_node_band_set_ast_build_options(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *options);
+__isl_give isl_set *isl_schedule_node_band_get_ast_isolate_option(
+	__isl_keep isl_schedule_node *node);
+unsigned isl_schedule_node_band_n_member(__isl_keep isl_schedule_node *node);
+__isl_export
+isl_bool isl_schedule_node_band_member_get_coincident(
+	__isl_keep isl_schedule_node *node, int pos);
+__isl_export
+__isl_give isl_schedule_node *isl_schedule_node_band_member_set_coincident(
+	__isl_take isl_schedule_node *node, int pos, int coincident);
+isl_bool isl_schedule_node_band_get_permutable(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_schedule_node *isl_schedule_node_band_set_permutable(
+	__isl_take isl_schedule_node *node, int permutable);
+
+isl_stat isl_options_set_tile_scale_tile_loops(isl_ctx *ctx, int val);
+int isl_options_get_tile_scale_tile_loops(isl_ctx *ctx);
+isl_stat isl_options_set_tile_shift_point_loops(isl_ctx *ctx, int val);
+int isl_options_get_tile_shift_point_loops(isl_ctx *ctx);
+
+__isl_give isl_schedule_node *isl_schedule_node_band_scale(
+	__isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv);
+__isl_give isl_schedule_node *isl_schedule_node_band_scale_down(
+	__isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv);
+__isl_give isl_schedule_node *isl_schedule_node_band_mod(
+	__isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv);
+__isl_give isl_schedule_node *isl_schedule_node_band_shift(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_multi_union_pw_aff *shift);
+__isl_give isl_schedule_node *isl_schedule_node_band_tile(
+	__isl_take isl_schedule_node *node, __isl_take isl_multi_val *sizes);
+__isl_give isl_schedule_node *isl_schedule_node_band_sink(
+	__isl_take isl_schedule_node *node);
+__isl_give isl_schedule_node *isl_schedule_node_band_split(
+	__isl_take isl_schedule_node *node, int pos);
+
+__isl_give isl_set *isl_schedule_node_context_get_context(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_union_set *isl_schedule_node_domain_get_domain(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_union_map *isl_schedule_node_expansion_get_expansion(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_union_pw_multi_aff *isl_schedule_node_expansion_get_contraction(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_union_map *isl_schedule_node_extension_get_extension(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_union_set *isl_schedule_node_filter_get_filter(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_set *isl_schedule_node_guard_get_guard(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_id *isl_schedule_node_mark_get_id(
+	__isl_keep isl_schedule_node *node);
+
+int isl_schedule_node_get_schedule_depth(__isl_keep isl_schedule_node *node);
+__isl_give isl_union_set *isl_schedule_node_get_domain(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_union_set *isl_schedule_node_get_universe_domain(
+	__isl_keep isl_schedule_node *node);
+__isl_export
+__isl_give isl_multi_union_pw_aff *
+isl_schedule_node_get_prefix_schedule_multi_union_pw_aff(
+	__isl_keep isl_schedule_node *node);
+__isl_export
+__isl_give isl_union_pw_multi_aff *
+isl_schedule_node_get_prefix_schedule_union_pw_multi_aff(
+	__isl_keep isl_schedule_node *node);
+__isl_export
+__isl_give isl_union_map *isl_schedule_node_get_prefix_schedule_union_map(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_union_map *isl_schedule_node_get_prefix_schedule_relation(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_union_map *isl_schedule_node_get_subtree_schedule_union_map(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_union_map *isl_schedule_node_get_subtree_expansion(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_union_pw_multi_aff *isl_schedule_node_get_subtree_contraction(
+	__isl_keep isl_schedule_node *node);
+
+__isl_give isl_schedule_node *isl_schedule_node_insert_context(
+	__isl_take isl_schedule_node *node, __isl_take isl_set *context);
+__isl_give isl_schedule_node *isl_schedule_node_insert_partial_schedule(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_multi_union_pw_aff *schedule);
+__isl_give isl_schedule_node *isl_schedule_node_insert_filter(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *filter);
+__isl_give isl_schedule_node *isl_schedule_node_insert_guard(
+	__isl_take isl_schedule_node *node, __isl_take isl_set *context);
+__isl_give isl_schedule_node *isl_schedule_node_insert_mark(
+	__isl_take isl_schedule_node *node, __isl_take isl_id *mark);
+__isl_give isl_schedule_node *isl_schedule_node_insert_sequence(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_set_list *filters);
+__isl_give isl_schedule_node *isl_schedule_node_insert_set(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_set_list *filters);
+
+__isl_give isl_schedule_node *isl_schedule_node_cut(
+	__isl_take isl_schedule_node *node);
+__isl_give isl_schedule_node *isl_schedule_node_delete(
+	__isl_take isl_schedule_node *node);
+
+__isl_give isl_schedule_node *isl_schedule_node_order_before(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *filter);
+__isl_give isl_schedule_node *isl_schedule_node_order_after(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *filter);
+
+__isl_give isl_schedule_node *isl_schedule_node_graft_before(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_schedule_node *graft);
+__isl_give isl_schedule_node *isl_schedule_node_graft_after(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_schedule_node *graft);
+
+__isl_give isl_schedule_node *isl_schedule_node_reset_user(
+	__isl_take isl_schedule_node *node);
+__isl_give isl_schedule_node *isl_schedule_node_align_params(
+	__isl_take isl_schedule_node *node, __isl_take isl_space *space);
+
+__isl_give isl_printer *isl_printer_print_schedule_node(
+	__isl_take isl_printer *p, __isl_keep isl_schedule_node *node);
+void isl_schedule_node_dump(__isl_keep isl_schedule_node *node);
+__isl_give char *isl_schedule_node_to_str(__isl_keep isl_schedule_node *node);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/schedule_type.h b/final/lib/External/isl/include/isl/schedule_type.h
new file mode 100644
index 0000000..f5a6d4c
--- /dev/null
+++ b/final/lib/External/isl/include/isl/schedule_type.h
@@ -0,0 +1,33 @@
+#ifndef ISL_SCHEDULE_TYPE_H
+#define ISL_SCHEDULE_TYPE_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+enum isl_schedule_node_type {
+	isl_schedule_node_error = -1,
+	isl_schedule_node_band,
+	isl_schedule_node_context,
+	isl_schedule_node_domain,
+	isl_schedule_node_expansion,
+	isl_schedule_node_extension,
+	isl_schedule_node_filter,
+	isl_schedule_node_leaf,
+	isl_schedule_node_guard,
+	isl_schedule_node_mark,
+	isl_schedule_node_sequence,
+	isl_schedule_node_set
+};
+
+struct __isl_export isl_schedule_node;
+typedef struct isl_schedule_node isl_schedule_node;
+
+struct __isl_export isl_schedule;
+typedef struct isl_schedule isl_schedule;
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/set.h b/final/lib/External/isl/include/isl/set.h
new file mode 100644
index 0000000..76c00fa
--- /dev/null
+++ b/final/lib/External/isl/include/isl/set.h
@@ -0,0 +1,515 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_SET_H
+#define ISL_SET_H
+
+#include <isl/map_type.h>
+#include <isl/aff_type.h>
+#include <isl/list.h>
+#include <isl/mat.h>
+#include <isl/point.h>
+#include <isl/local_space.h>
+#include <isl/val.h>
+#include <isl/stdint.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+unsigned isl_basic_set_n_dim(__isl_keep isl_basic_set *bset);
+unsigned isl_basic_set_n_param(__isl_keep isl_basic_set *bset);
+unsigned isl_basic_set_total_dim(__isl_keep const isl_basic_set *bset);
+unsigned isl_basic_set_dim(__isl_keep isl_basic_set *bset,
+				enum isl_dim_type type);
+
+unsigned isl_set_n_dim(__isl_keep isl_set *set);
+unsigned isl_set_n_param(__isl_keep isl_set *set);
+unsigned isl_set_dim(__isl_keep isl_set *set, enum isl_dim_type type);
+
+isl_ctx *isl_basic_set_get_ctx(__isl_keep isl_basic_set *bset);
+isl_ctx *isl_set_get_ctx(__isl_keep isl_set *set);
+__isl_give isl_space *isl_basic_set_get_space(__isl_keep isl_basic_set *bset);
+__isl_give isl_space *isl_set_get_space(__isl_keep isl_set *set);
+__isl_give isl_set *isl_set_reset_space(__isl_take isl_set *set,
+	__isl_take isl_space *dim);
+
+__isl_give isl_aff *isl_basic_set_get_div(__isl_keep isl_basic_set *bset,
+	int pos);
+
+__isl_give isl_local_space *isl_basic_set_get_local_space(
+	__isl_keep isl_basic_set *bset);
+
+const char *isl_basic_set_get_tuple_name(__isl_keep isl_basic_set *bset);
+isl_bool isl_set_has_tuple_name(__isl_keep isl_set *set);
+const char *isl_set_get_tuple_name(__isl_keep isl_set *set);
+__isl_give isl_basic_set *isl_basic_set_set_tuple_name(
+	__isl_take isl_basic_set *set, const char *s);
+__isl_give isl_set *isl_set_set_tuple_name(__isl_take isl_set *set,
+	const char *s);
+const char *isl_basic_set_get_dim_name(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_basic_set *isl_basic_set_set_dim_name(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, const char *s);
+isl_bool isl_set_has_dim_name(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos);
+const char *isl_set_get_dim_name(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_set *isl_set_set_dim_name(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, const char *s);
+
+__isl_give isl_id *isl_basic_set_get_dim_id(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_basic_set *isl_basic_set_set_tuple_id(
+	__isl_take isl_basic_set *bset, __isl_take isl_id *id);
+__isl_give isl_set *isl_set_set_dim_id(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id);
+isl_bool isl_set_has_dim_id(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_id *isl_set_get_dim_id(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_set *isl_set_set_tuple_id(__isl_take isl_set *set,
+	__isl_take isl_id *id);
+__isl_give isl_set *isl_set_reset_tuple_id(__isl_take isl_set *set);
+isl_bool isl_set_has_tuple_id(__isl_keep isl_set *set);
+__isl_give isl_id *isl_set_get_tuple_id(__isl_keep isl_set *set);
+__isl_give isl_set *isl_set_reset_user(__isl_take isl_set *set);
+
+int isl_set_find_dim_by_id(__isl_keep isl_set *set, enum isl_dim_type type,
+	__isl_keep isl_id *id);
+int isl_set_find_dim_by_name(__isl_keep isl_set *set, enum isl_dim_type type,
+	const char *name);
+
+int isl_basic_set_is_rational(__isl_keep isl_basic_set *bset);
+
+__isl_null isl_basic_set *isl_basic_set_free(__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_basic_set_copy(__isl_keep isl_basic_set *bset);
+__isl_give isl_basic_set *isl_basic_set_empty(__isl_take isl_space *dim);
+__isl_give isl_basic_set *isl_basic_set_universe(__isl_take isl_space *dim);
+__isl_give isl_basic_set *isl_basic_set_nat_universe(__isl_take isl_space *dim);
+__isl_give isl_basic_set *isl_basic_set_positive_orthant(
+	__isl_take isl_space *space);
+void isl_basic_set_print_internal(__isl_keep isl_basic_set *bset,
+				FILE *out, int indent);
+__isl_export
+__isl_give isl_basic_set *isl_basic_set_intersect(
+		__isl_take isl_basic_set *bset1,
+		__isl_take isl_basic_set *bset2);
+__isl_export
+__isl_give isl_basic_set *isl_basic_set_intersect_params(
+	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2);
+__isl_export
+__isl_give isl_basic_set *isl_basic_set_apply(
+		__isl_take isl_basic_set *bset,
+		__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_set *isl_basic_set_preimage_multi_aff(
+	__isl_take isl_basic_set *bset, __isl_take isl_multi_aff *ma);
+__isl_export
+__isl_give isl_basic_set *isl_basic_set_affine_hull(
+		__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_basic_set_remove_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_export
+__isl_give isl_basic_set *isl_basic_set_sample(__isl_take isl_basic_set *bset);
+__isl_export
+__isl_give isl_basic_set *isl_basic_set_detect_equalities(
+						__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_basic_set_remove_redundancies(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_set *isl_set_remove_redundancies(__isl_take isl_set *set);
+__isl_give isl_basic_set *isl_basic_set_list_intersect(
+	__isl_take struct isl_basic_set_list *list);
+
+__isl_give isl_set *isl_set_list_union(__isl_take isl_set_list *list);
+
+__isl_give isl_basic_set *isl_basic_set_read_from_file(isl_ctx *ctx,
+	FILE *input);
+__isl_constructor
+__isl_give isl_basic_set *isl_basic_set_read_from_str(isl_ctx *ctx,
+	const char *str);
+__isl_give isl_set *isl_set_read_from_file(isl_ctx *ctx, FILE *input);
+__isl_constructor
+__isl_give isl_set *isl_set_read_from_str(isl_ctx *ctx, const char *str);
+void isl_basic_set_dump(__isl_keep isl_basic_set *bset);
+void isl_set_dump(__isl_keep isl_set *set);
+__isl_give isl_printer *isl_printer_print_basic_set(
+	__isl_take isl_printer *printer, __isl_keep isl_basic_set *bset);
+__isl_give isl_printer *isl_printer_print_set(__isl_take isl_printer *printer,
+	__isl_keep isl_set *map);
+__isl_give isl_basic_set *isl_basic_set_fix_si(__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos, int value);
+__isl_give isl_basic_set *isl_basic_set_fix_val(__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v);
+__isl_give isl_set *isl_set_fix_si(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, int value);
+__isl_give isl_set *isl_set_lower_bound_si(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, int value);
+__isl_give isl_basic_set *isl_basic_set_lower_bound_val(
+	__isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos,
+	__isl_take isl_val *value);
+__isl_give isl_set *isl_set_lower_bound_val(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *value);
+__isl_give isl_set *isl_set_upper_bound_si(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, int value);
+__isl_give isl_basic_set *isl_basic_set_upper_bound_val(
+	__isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos,
+	__isl_take isl_val *value);
+__isl_give isl_set *isl_set_upper_bound_val(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *value);
+
+__isl_give isl_set *isl_set_equate(__isl_take isl_set *set,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2);
+
+__isl_export
+isl_bool isl_basic_set_is_equal(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2);
+isl_bool isl_basic_set_is_disjoint(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2);
+
+__isl_give isl_set *isl_basic_set_partial_lexmin(
+		__isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
+		__isl_give isl_set **empty);
+__isl_give isl_set *isl_basic_set_partial_lexmax(
+		__isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
+		__isl_give isl_set **empty);
+__isl_give isl_set *isl_set_partial_lexmin(
+		__isl_take isl_set *set, __isl_take isl_set *dom,
+		__isl_give isl_set **empty);
+__isl_give isl_set *isl_set_partial_lexmax(
+		__isl_take isl_set *set, __isl_take isl_set *dom,
+		__isl_give isl_set **empty);
+__isl_export
+__isl_give isl_set *isl_basic_set_lexmin(__isl_take isl_basic_set *bset);
+__isl_export
+__isl_give isl_set *isl_basic_set_lexmax(__isl_take isl_basic_set *bset);
+__isl_export
+__isl_give isl_set *isl_set_lexmin(__isl_take isl_set *set);
+__isl_export
+__isl_give isl_set *isl_set_lexmax(__isl_take isl_set *set);
+__isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmin_pw_multi_aff(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty);
+__isl_give isl_pw_multi_aff *isl_basic_set_partial_lexmax_pw_multi_aff(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty);
+__isl_give isl_pw_multi_aff *isl_set_lexmin_pw_multi_aff(
+	__isl_take isl_set *set);
+__isl_give isl_pw_multi_aff *isl_set_lexmax_pw_multi_aff(
+	__isl_take isl_set *set);
+
+__isl_export
+__isl_give isl_set *isl_basic_set_union(
+		__isl_take isl_basic_set *bset1,
+		__isl_take isl_basic_set *bset2);
+
+int isl_basic_set_compare_at(struct isl_basic_set *bset1,
+	struct isl_basic_set *bset2, int pos);
+int isl_set_follows_at(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2, int pos);
+
+__isl_give isl_basic_set *isl_basic_set_params(__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_basic_set_from_params(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_set *isl_set_params(__isl_take isl_set *set);
+__isl_give isl_set *isl_set_from_params(__isl_take isl_set *set);
+
+isl_stat isl_basic_set_dims_get_sign(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, unsigned n, int *signs);
+
+isl_bool isl_basic_set_plain_is_universe(__isl_keep isl_basic_set *bset);
+isl_bool isl_basic_set_is_universe(__isl_keep isl_basic_set *bset);
+isl_bool isl_basic_set_plain_is_empty(__isl_keep isl_basic_set *bset);
+__isl_export
+isl_bool isl_basic_set_is_empty(__isl_keep isl_basic_set *bset);
+isl_bool isl_basic_set_is_bounded(__isl_keep isl_basic_set *bset);
+__isl_export
+isl_bool isl_basic_set_is_subset(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2);
+isl_bool isl_basic_set_plain_is_equal(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2);
+
+__isl_give isl_set *isl_set_empty(__isl_take isl_space *dim);
+__isl_give isl_set *isl_set_universe(__isl_take isl_space *dim);
+__isl_give isl_set *isl_set_nat_universe(__isl_take isl_space *dim);
+__isl_give isl_set *isl_set_copy(__isl_keep isl_set *set);
+__isl_null isl_set *isl_set_free(__isl_take isl_set *set);
+__isl_constructor
+__isl_give isl_set *isl_set_from_basic_set(__isl_take isl_basic_set *bset);
+__isl_export
+__isl_give isl_basic_set *isl_set_sample(__isl_take isl_set *set);
+__isl_export
+__isl_give isl_point *isl_basic_set_sample_point(__isl_take isl_basic_set *bset);
+__isl_export
+__isl_give isl_point *isl_set_sample_point(__isl_take isl_set *set);
+__isl_export
+__isl_give isl_set *isl_set_detect_equalities(__isl_take isl_set *set);
+__isl_export
+__isl_give isl_basic_set *isl_set_affine_hull(__isl_take isl_set *set);
+__isl_give isl_basic_set *isl_set_convex_hull(__isl_take isl_set *set);
+__isl_export
+__isl_give isl_basic_set *isl_set_polyhedral_hull(__isl_take isl_set *set);
+__isl_give isl_basic_set *isl_set_simple_hull(__isl_take isl_set *set);
+__isl_export
+__isl_give isl_basic_set *isl_set_unshifted_simple_hull(
+	__isl_take isl_set *set);
+__isl_give isl_basic_set *isl_set_plain_unshifted_simple_hull(
+	__isl_take isl_set *set);
+__isl_give isl_basic_set *isl_set_unshifted_simple_hull_from_set_list(
+	__isl_take isl_set *set, __isl_take isl_set_list *list);
+__isl_give isl_basic_set *isl_set_bounded_simple_hull(__isl_take isl_set *set);
+
+__isl_give isl_set *isl_set_union_disjoint(
+	__isl_take isl_set *set1, __isl_take isl_set *set2);
+__isl_export
+__isl_give isl_set *isl_set_union(
+		__isl_take isl_set *set1,
+		__isl_take isl_set *set2);
+__isl_give isl_set *isl_set_product(__isl_take isl_set *set1,
+	__isl_take isl_set *set2);
+__isl_give isl_basic_set *isl_basic_set_flat_product(
+	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2);
+__isl_give isl_set *isl_set_flat_product(__isl_take isl_set *set1,
+	__isl_take isl_set *set2);
+__isl_export
+__isl_give isl_set *isl_set_intersect(
+		__isl_take isl_set *set1,
+		__isl_take isl_set *set2);
+__isl_export
+__isl_give isl_set *isl_set_intersect_params(__isl_take isl_set *set,
+		__isl_take isl_set *params);
+__isl_export
+__isl_give isl_set *isl_set_subtract(
+		__isl_take isl_set *set1,
+		__isl_take isl_set *set2);
+__isl_export
+__isl_give isl_set *isl_set_complement(__isl_take isl_set *set);
+__isl_export
+__isl_give isl_set *isl_set_apply(
+		__isl_take isl_set *set,
+		__isl_take isl_map *map);
+__isl_give isl_set *isl_set_preimage_multi_aff(__isl_take isl_set *set,
+	__isl_take isl_multi_aff *ma);
+__isl_give isl_set *isl_set_preimage_pw_multi_aff(__isl_take isl_set *set,
+	__isl_take isl_pw_multi_aff *pma);
+__isl_give isl_set *isl_set_preimage_multi_pw_aff(__isl_take isl_set *set,
+	__isl_take isl_multi_pw_aff *mpa);
+__isl_give isl_set *isl_set_fix_val(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v);
+struct isl_set *isl_set_fix_dim_si(struct isl_set *set,
+		unsigned dim, int value);
+__isl_give isl_basic_set *isl_basic_set_insert_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, unsigned n);
+__isl_give isl_set *isl_set_insert_dims(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, unsigned n);
+__isl_give isl_basic_set *isl_basic_set_add_dims(__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned n);
+ISL_DEPRECATED
+__isl_give isl_basic_set *isl_basic_set_add(__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned n);
+__isl_give isl_set *isl_set_add_dims(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned n);
+__isl_give isl_basic_set *isl_basic_set_move_dims(__isl_take isl_basic_set *bset,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+__isl_give isl_set *isl_set_move_dims(__isl_take isl_set *set,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+__isl_give isl_basic_set *isl_basic_set_project_out(
+		__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_set *isl_set_project_out(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_map *isl_set_project_onto_map(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_basic_set *isl_basic_set_remove_divs(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_basic_set_eliminate(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_set *isl_set_eliminate_dims(__isl_take isl_set *set,
+		unsigned first, unsigned n);
+__isl_give isl_set *isl_set_remove_dims(__isl_take isl_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_basic_set *isl_basic_set_remove_divs_involving_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_set *isl_set_remove_divs_involving_dims(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_basic_set *isl_basic_set_remove_unknown_divs(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_set *isl_set_remove_unknown_divs(__isl_take isl_set *set);
+__isl_give isl_set *isl_set_remove_divs(__isl_take isl_set *set);
+__isl_give isl_set *isl_set_split_dims(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+__isl_give isl_basic_set *isl_basic_set_drop_constraints_involving_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_basic_set *isl_basic_set_drop_constraints_not_involving_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_set *isl_set_drop_constraints_involving_dims(
+	__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_set *isl_set_drop_constraints_not_involving_dims(
+	__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+isl_bool isl_basic_set_involves_dims(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n);
+isl_bool isl_set_involves_dims(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+void isl_set_print_internal(__isl_keep isl_set *set, FILE *out, int indent);
+isl_bool isl_set_plain_is_empty(__isl_keep isl_set *set);
+isl_bool isl_set_plain_is_universe(__isl_keep isl_set *set);
+isl_bool isl_set_is_params(__isl_keep isl_set *set);
+__isl_export
+isl_bool isl_set_is_empty(__isl_keep isl_set *set);
+isl_bool isl_set_is_bounded(__isl_keep isl_set *set);
+__isl_export
+isl_bool isl_set_is_subset(__isl_keep isl_set *set1, __isl_keep isl_set *set2);
+__isl_export
+isl_bool isl_set_is_strict_subset(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2);
+__isl_export
+isl_bool isl_set_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2);
+__isl_export
+isl_bool isl_set_is_disjoint(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2);
+isl_bool isl_set_is_singleton(__isl_keep isl_set *set);
+isl_bool isl_set_is_box(__isl_keep isl_set *set);
+isl_bool isl_set_has_equal_space(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2);
+
+__isl_give isl_set *isl_set_sum(__isl_take isl_set *set1,
+	__isl_take isl_set *set2);
+__isl_give isl_basic_set *isl_basic_set_neg(__isl_take isl_basic_set *bset);
+__isl_give isl_set *isl_set_neg(__isl_take isl_set *set);
+
+__isl_give isl_set *isl_set_make_disjoint(__isl_take isl_set *set);
+__isl_give isl_set *isl_basic_set_compute_divs(__isl_take isl_basic_set *bset);
+__isl_give isl_set *isl_set_compute_divs(__isl_take isl_set *set);
+ISL_DEPRECATED
+__isl_give isl_set *isl_set_align_divs(__isl_take isl_set *set);
+
+__isl_give isl_val *isl_set_plain_get_val_if_fixed(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos);
+isl_bool isl_set_dim_is_bounded(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos);
+isl_bool isl_set_dim_has_lower_bound(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos);
+isl_bool isl_set_dim_has_upper_bound(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos);
+isl_bool isl_set_dim_has_any_lower_bound(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos);
+isl_bool isl_set_dim_has_any_upper_bound(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos);
+
+__isl_export
+__isl_give isl_basic_set *isl_basic_set_gist(__isl_take isl_basic_set *bset,
+					    __isl_take isl_basic_set *context);
+__isl_give isl_set *isl_set_gist_basic_set(__isl_take isl_set *set,
+	__isl_take isl_basic_set *context);
+__isl_export
+__isl_give isl_set *isl_set_gist(__isl_take isl_set *set,
+	__isl_take isl_set *context);
+__isl_give isl_set *isl_set_gist_params(__isl_take isl_set *set,
+	__isl_take isl_set *context);
+isl_stat isl_set_dim_residue_class_val(__isl_keep isl_set *set,
+	int pos, __isl_give isl_val **modulo, __isl_give isl_val **residue);
+
+__isl_export
+__isl_give isl_set *isl_set_coalesce(__isl_take isl_set *set);
+
+int isl_set_plain_cmp(__isl_keep isl_set *set1, __isl_keep isl_set *set2);
+isl_bool isl_set_plain_is_equal(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2);
+isl_bool isl_set_plain_is_disjoint(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2);
+
+uint32_t isl_set_get_hash(struct isl_set *set);
+
+int isl_set_n_basic_set(__isl_keep isl_set *set);
+__isl_export
+isl_stat isl_set_foreach_basic_set(__isl_keep isl_set *set,
+	isl_stat (*fn)(__isl_take isl_basic_set *bset, void *user), void *user);
+__isl_give isl_basic_set_list *isl_set_get_basic_set_list(
+	__isl_keep isl_set *set);
+
+isl_stat isl_set_foreach_point(__isl_keep isl_set *set,
+	isl_stat (*fn)(__isl_take isl_point *pnt, void *user), void *user);
+__isl_give isl_val *isl_set_count_val(__isl_keep isl_set *set);
+
+__isl_constructor
+__isl_give isl_basic_set *isl_basic_set_from_point(__isl_take isl_point *pnt);
+__isl_constructor
+__isl_give isl_set *isl_set_from_point(__isl_take isl_point *pnt);
+__isl_give isl_basic_set *isl_basic_set_box_from_points(
+	__isl_take isl_point *pnt1, __isl_take isl_point *pnt2);
+__isl_give isl_set *isl_set_box_from_points(__isl_take isl_point *pnt1,
+	__isl_take isl_point *pnt2);
+
+__isl_give isl_basic_set *isl_basic_set_lift(__isl_take isl_basic_set *bset);
+__isl_give isl_set *isl_set_lift(__isl_take isl_set *set);
+
+__isl_give isl_map *isl_set_lex_le_set(__isl_take isl_set *set1,
+	__isl_take isl_set *set2);
+__isl_give isl_map *isl_set_lex_lt_set(__isl_take isl_set *set1,
+	__isl_take isl_set *set2);
+__isl_give isl_map *isl_set_lex_ge_set(__isl_take isl_set *set1,
+	__isl_take isl_set *set2);
+__isl_give isl_map *isl_set_lex_gt_set(__isl_take isl_set *set1,
+	__isl_take isl_set *set2);
+
+int isl_set_size(__isl_keep isl_set *set);
+
+__isl_give isl_basic_set *isl_basic_set_align_params(
+	__isl_take isl_basic_set *bset, __isl_take isl_space *model);
+__isl_give isl_set *isl_set_align_params(__isl_take isl_set *set,
+	__isl_take isl_space *model);
+
+__isl_give isl_mat *isl_basic_set_equalities_matrix(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type c1,
+	enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4);
+__isl_give isl_mat *isl_basic_set_inequalities_matrix(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type c1,
+	enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4);
+__isl_give isl_basic_set *isl_basic_set_from_constraint_matrices(
+	__isl_take isl_space *dim,
+	__isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1,
+	enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4);
+
+__isl_give isl_mat *isl_basic_set_reduced_basis(__isl_keep isl_basic_set *bset);
+
+__isl_give isl_basic_set *isl_basic_set_coefficients(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set_list *isl_basic_set_list_coefficients(
+	__isl_take isl_basic_set_list *list);
+__isl_give isl_basic_set *isl_set_coefficients(__isl_take isl_set *set);
+__isl_give isl_basic_set *isl_basic_set_solutions(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_set_solutions(__isl_take isl_set *set);
+
+__isl_give isl_pw_aff *isl_set_dim_max(__isl_take isl_set *set, int pos);
+__isl_give isl_pw_aff *isl_set_dim_min(__isl_take isl_set *set, int pos);
+
+__isl_give char *isl_basic_set_to_str(__isl_keep isl_basic_set *bset);
+__isl_give char *isl_set_to_str(__isl_keep isl_set *set);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/set_type.h b/final/lib/External/isl/include/isl/set_type.h
new file mode 100644
index 0000000..ce349e1
--- /dev/null
+++ b/final/lib/External/isl/include/isl/set_type.h
@@ -0,0 +1,6 @@
+#ifndef ISL_SET_TYPE_H
+#define ISL_SET_TYPE_H
+
+#include <isl/map_type.h>
+
+#endif
diff --git a/final/lib/External/isl/include/isl/space.h b/final/lib/External/isl/include/isl/space.h
new file mode 100644
index 0000000..78a1818
--- /dev/null
+++ b/final/lib/External/isl/include/isl/space.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_SPACE_H
+#define ISL_SPACE_H
+
+#include <isl/ctx.h>
+#include <isl/id.h>
+#include <isl/printer.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_space;
+typedef struct isl_space isl_space;
+
+enum isl_dim_type {
+	isl_dim_cst,
+	isl_dim_param,
+	isl_dim_in,
+	isl_dim_out,
+	isl_dim_set = isl_dim_out,
+	isl_dim_div,
+	isl_dim_all
+};
+
+isl_ctx *isl_space_get_ctx(__isl_keep isl_space *dim);
+__isl_give isl_space *isl_space_alloc(isl_ctx *ctx,
+			unsigned nparam, unsigned n_in, unsigned n_out);
+__isl_give isl_space *isl_space_set_alloc(isl_ctx *ctx,
+			unsigned nparam, unsigned dim);
+__isl_give isl_space *isl_space_params_alloc(isl_ctx *ctx, unsigned nparam);
+__isl_give isl_space *isl_space_copy(__isl_keep isl_space *dim);
+__isl_null isl_space *isl_space_free(__isl_take isl_space *space);
+
+isl_bool isl_space_is_params(__isl_keep isl_space *space);
+isl_bool isl_space_is_set(__isl_keep isl_space *space);
+isl_bool isl_space_is_map(__isl_keep isl_space *space);
+
+__isl_give isl_space *isl_space_set_tuple_name(__isl_take isl_space *dim,
+	enum isl_dim_type type, const char *s);
+isl_bool isl_space_has_tuple_name(__isl_keep isl_space *space,
+	enum isl_dim_type type);
+__isl_keep const char *isl_space_get_tuple_name(__isl_keep isl_space *dim,
+				 enum isl_dim_type type);
+__isl_give isl_space *isl_space_set_tuple_id(__isl_take isl_space *dim,
+	enum isl_dim_type type, __isl_take isl_id *id);
+__isl_give isl_space *isl_space_reset_tuple_id(__isl_take isl_space *dim,
+	enum isl_dim_type type);
+isl_bool isl_space_has_tuple_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type);
+__isl_give isl_id *isl_space_get_tuple_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type);
+__isl_give isl_space *isl_space_reset_user(__isl_take isl_space *space);
+
+__isl_give isl_space *isl_space_set_dim_id(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id);
+isl_bool isl_space_has_dim_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_id *isl_space_get_dim_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned pos);
+
+int isl_space_find_dim_by_id(__isl_keep isl_space *dim, enum isl_dim_type type,
+	__isl_keep isl_id *id);
+int isl_space_find_dim_by_name(__isl_keep isl_space *space,
+	enum isl_dim_type type, const char *name);
+
+isl_bool isl_space_has_dim_name(__isl_keep isl_space *space,
+	enum isl_dim_type type, unsigned pos);
+__isl_give isl_space *isl_space_set_dim_name(__isl_take isl_space *dim,
+				 enum isl_dim_type type, unsigned pos,
+				 __isl_keep const char *name);
+__isl_keep const char *isl_space_get_dim_name(__isl_keep isl_space *dim,
+				 enum isl_dim_type type, unsigned pos);
+
+ISL_DEPRECATED
+__isl_give isl_space *isl_space_extend(__isl_take isl_space *dim,
+			unsigned nparam, unsigned n_in, unsigned n_out);
+__isl_give isl_space *isl_space_add_dims(__isl_take isl_space *space,
+	enum isl_dim_type type, unsigned n);
+__isl_give isl_space *isl_space_move_dims(__isl_take isl_space *space,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+__isl_give isl_space *isl_space_insert_dims(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned pos, unsigned n);
+__isl_give isl_space *isl_space_join(__isl_take isl_space *left,
+	__isl_take isl_space *right);
+__isl_give isl_space *isl_space_product(__isl_take isl_space *left,
+	__isl_take isl_space *right);
+__isl_give isl_space *isl_space_domain_product(__isl_take isl_space *left,
+	__isl_take isl_space *right);
+__isl_give isl_space *isl_space_range_product(__isl_take isl_space *left,
+	__isl_take isl_space *right);
+__isl_give isl_space *isl_space_factor_domain(__isl_take isl_space *space);
+__isl_give isl_space *isl_space_factor_range(__isl_take isl_space *space);
+__isl_give isl_space *isl_space_domain_factor_domain(
+	__isl_take isl_space *space);
+__isl_give isl_space *isl_space_domain_factor_range(
+	__isl_take isl_space *space);
+__isl_give isl_space *isl_space_range_factor_domain(
+	__isl_take isl_space *space);
+__isl_give isl_space *isl_space_range_factor_range(
+	__isl_take isl_space *space);
+__isl_give isl_space *isl_space_map_from_set(__isl_take isl_space *space);
+__isl_give isl_space *isl_space_map_from_domain_and_range(
+	__isl_take isl_space *domain, __isl_take isl_space *range);
+__isl_give isl_space *isl_space_reverse(__isl_take isl_space *dim);
+__isl_give isl_space *isl_space_drop_dims(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned first, unsigned num);
+ISL_DEPRECATED
+__isl_give isl_space *isl_space_drop_inputs(__isl_take isl_space *dim,
+		unsigned first, unsigned n);
+ISL_DEPRECATED
+__isl_give isl_space *isl_space_drop_outputs(__isl_take isl_space *dim,
+		unsigned first, unsigned n);
+__isl_give isl_space *isl_space_domain(__isl_take isl_space *space);
+__isl_give isl_space *isl_space_from_domain(__isl_take isl_space *dim);
+__isl_give isl_space *isl_space_range(__isl_take isl_space *space);
+__isl_give isl_space *isl_space_from_range(__isl_take isl_space *dim);
+__isl_give isl_space *isl_space_domain_map(__isl_take isl_space *space);
+__isl_give isl_space *isl_space_range_map(__isl_take isl_space *space);
+__isl_give isl_space *isl_space_params(__isl_take isl_space *space);
+__isl_give isl_space *isl_space_set_from_params(__isl_take isl_space *space);
+
+__isl_give isl_space *isl_space_align_params(__isl_take isl_space *dim1,
+	__isl_take isl_space *dim2);
+
+isl_bool isl_space_is_wrapping(__isl_keep isl_space *dim);
+isl_bool isl_space_domain_is_wrapping(__isl_keep isl_space *space);
+isl_bool isl_space_range_is_wrapping(__isl_keep isl_space *space);
+isl_bool isl_space_is_product(__isl_keep isl_space *space);
+__isl_give isl_space *isl_space_wrap(__isl_take isl_space *dim);
+__isl_give isl_space *isl_space_unwrap(__isl_take isl_space *dim);
+
+isl_bool isl_space_can_zip(__isl_keep isl_space *space);
+__isl_give isl_space *isl_space_zip(__isl_take isl_space *dim);
+
+isl_bool isl_space_can_curry(__isl_keep isl_space *space);
+__isl_give isl_space *isl_space_curry(__isl_take isl_space *space);
+
+isl_bool isl_space_can_range_curry(__isl_keep isl_space *space);
+__isl_give isl_space *isl_space_range_curry(__isl_take isl_space *space);
+
+isl_bool isl_space_can_uncurry(__isl_keep isl_space *space);
+__isl_give isl_space *isl_space_uncurry(__isl_take isl_space *space);
+
+isl_bool isl_space_is_domain(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2);
+isl_bool isl_space_is_range(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2);
+isl_bool isl_space_is_equal(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2);
+isl_bool isl_space_has_equal_params(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2);
+isl_bool isl_space_has_equal_tuples(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2);
+isl_bool isl_space_tuple_is_equal(__isl_keep isl_space *space1,
+	enum isl_dim_type type1, __isl_keep isl_space *space2,
+	enum isl_dim_type type2);
+ISL_DEPRECATED
+isl_bool isl_space_match(__isl_keep isl_space *space1, enum isl_dim_type type1,
+	__isl_keep isl_space *space2, enum isl_dim_type type2);
+ISL_DEPRECATED
+int isl_space_tuple_match(__isl_keep isl_space *space1, enum isl_dim_type type1,
+	__isl_keep isl_space *space2, enum isl_dim_type type2);
+unsigned isl_space_dim(__isl_keep isl_space *dim, enum isl_dim_type type);
+
+__isl_give char *isl_space_to_str(__isl_keep isl_space *space);
+__isl_give isl_printer *isl_printer_print_space(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim);
+void isl_space_dump(__isl_keep isl_space *dim);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/stream.h b/final/lib/External/isl/include/isl/stream.h
new file mode 100644
index 0000000..b0eb096
--- /dev/null
+++ b/final/lib/External/isl/include/isl/stream.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_STREAM_H
+#define ISL_STREAM_H
+
+#include <stdio.h>
+#include <isl/hash.h>
+#include <isl/aff_type.h>
+#include <isl/obj.h>
+#include <isl/val.h>
+#include <isl/schedule_type.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+enum isl_token_type { ISL_TOKEN_ERROR = -1,
+			ISL_TOKEN_UNKNOWN = 256, ISL_TOKEN_VALUE,
+			ISL_TOKEN_IDENT, ISL_TOKEN_GE,
+			ISL_TOKEN_LE, ISL_TOKEN_GT, ISL_TOKEN_LT,
+			ISL_TOKEN_NE, ISL_TOKEN_EQ_EQ,
+			ISL_TOKEN_LEX_GE, ISL_TOKEN_LEX_LE,
+			ISL_TOKEN_LEX_GT, ISL_TOKEN_LEX_LT,
+			ISL_TOKEN_TO, ISL_TOKEN_AND,
+			ISL_TOKEN_OR, ISL_TOKEN_EXISTS, ISL_TOKEN_NOT,
+			ISL_TOKEN_DEF, ISL_TOKEN_INFTY, ISL_TOKEN_NAN,
+			ISL_TOKEN_MIN, ISL_TOKEN_MAX, ISL_TOKEN_RAT,
+			ISL_TOKEN_TRUE, ISL_TOKEN_FALSE,
+			ISL_TOKEN_CEILD, ISL_TOKEN_FLOORD, ISL_TOKEN_MOD,
+			ISL_TOKEN_STRING,
+			ISL_TOKEN_MAP, ISL_TOKEN_AFF,
+			ISL_TOKEN_CEIL, ISL_TOKEN_FLOOR,
+			ISL_TOKEN_IMPLIES,
+			ISL_TOKEN_LAST };
+
+struct isl_token;
+
+__isl_give isl_val *isl_token_get_val(isl_ctx *ctx, struct isl_token *tok);
+__isl_give char *isl_token_get_str(isl_ctx *ctx, struct isl_token *tok);
+int isl_token_get_type(struct isl_token *tok);
+void isl_token_free(struct isl_token *tok);
+
+struct isl_stream;
+typedef struct isl_stream isl_stream;
+
+__isl_give isl_stream *isl_stream_new_file(isl_ctx *ctx, FILE *file);
+__isl_give isl_stream *isl_stream_new_str(isl_ctx *ctx, const char *str);
+void isl_stream_free(__isl_take isl_stream *s);
+
+isl_ctx *isl_stream_get_ctx(__isl_keep isl_stream *s);
+
+void isl_stream_error(__isl_keep isl_stream *s, struct isl_token *tok,
+	char *msg);
+
+struct isl_token *isl_stream_next_token(__isl_keep isl_stream *s);
+struct isl_token *isl_stream_next_token_on_same_line(__isl_keep isl_stream *s);
+int isl_stream_next_token_is(__isl_keep isl_stream *s, int type);
+void isl_stream_push_token(__isl_keep isl_stream *s, struct isl_token *tok);
+void isl_stream_flush_tokens(__isl_keep isl_stream *s);
+int isl_stream_eat_if_available(__isl_keep isl_stream *s, int type);
+char *isl_stream_read_ident_if_available(__isl_keep isl_stream *s);
+int isl_stream_eat(__isl_keep isl_stream *s, int type);
+int isl_stream_is_empty(__isl_keep isl_stream *s);
+int isl_stream_skip_line(__isl_keep isl_stream *s);
+
+enum isl_token_type isl_stream_register_keyword(__isl_keep isl_stream *s,
+	const char *name);
+
+struct isl_obj isl_stream_read_obj(__isl_keep isl_stream *s);
+__isl_give isl_val *isl_stream_read_val(__isl_keep isl_stream *s);
+__isl_give isl_multi_aff *isl_stream_read_multi_aff(__isl_keep isl_stream *s);
+__isl_give isl_map *isl_stream_read_map(__isl_keep isl_stream *s);
+__isl_give isl_set *isl_stream_read_set(__isl_keep isl_stream *s);
+__isl_give isl_pw_qpolynomial *isl_stream_read_pw_qpolynomial(
+	__isl_keep isl_stream *s);
+__isl_give isl_union_set *isl_stream_read_union_set(__isl_keep isl_stream *s);
+__isl_give isl_union_map *isl_stream_read_union_map(__isl_keep isl_stream *s);
+__isl_give isl_schedule *isl_stream_read_schedule(isl_stream *s);
+
+int isl_stream_yaml_read_start_mapping(__isl_keep isl_stream *s);
+int isl_stream_yaml_read_end_mapping(__isl_keep isl_stream *s);
+int isl_stream_yaml_read_start_sequence(__isl_keep isl_stream *s);
+int isl_stream_yaml_read_end_sequence(__isl_keep isl_stream *s);
+int isl_stream_yaml_next(__isl_keep isl_stream *s);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/union_map.h b/final/lib/External/isl/include/isl/union_map.h
new file mode 100644
index 0000000..a3efe6f
--- /dev/null
+++ b/final/lib/External/isl/include/isl/union_map.h
@@ -0,0 +1,299 @@
+#ifndef ISL_UNION_MAP_H
+#define ISL_UNION_MAP_H
+
+#include <isl/space.h>
+#include <isl/aff_type.h>
+#include <isl/map_type.h>
+#include <isl/union_map_type.h>
+#include <isl/printer.h>
+#include <isl/val.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+unsigned isl_union_map_dim(__isl_keep isl_union_map *umap,
+	enum isl_dim_type type);
+isl_bool isl_union_map_involves_dims(__isl_keep isl_union_map *umap,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_id *isl_union_map_get_dim_id(__isl_keep isl_union_map *umap,
+	enum isl_dim_type type, unsigned pos);
+
+__isl_constructor
+__isl_give isl_union_map *isl_union_map_from_basic_map(
+	__isl_take isl_basic_map *bmap);
+__isl_constructor
+__isl_give isl_union_map *isl_union_map_from_map(__isl_take isl_map *map);
+__isl_give isl_union_map *isl_union_map_empty(__isl_take isl_space *dim);
+__isl_give isl_union_map *isl_union_map_copy(__isl_keep isl_union_map *umap);
+__isl_null isl_union_map *isl_union_map_free(__isl_take isl_union_map *umap);
+
+isl_ctx *isl_union_map_get_ctx(__isl_keep isl_union_map *umap);
+__isl_give isl_space *isl_union_map_get_space(__isl_keep isl_union_map *umap);
+
+__isl_give isl_union_map *isl_union_map_reset_user(
+	__isl_take isl_union_map *umap);
+
+int isl_union_map_find_dim_by_name(__isl_keep isl_union_map *umap,
+	enum isl_dim_type type, const char *name);
+
+__isl_give isl_union_map *isl_union_map_universe(
+	__isl_take isl_union_map *umap);
+__isl_give isl_set *isl_union_map_params(__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_set *isl_union_map_domain(__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_set *isl_union_map_range(__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_domain_map(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_pw_multi_aff *isl_union_map_domain_map_union_pw_multi_aff(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_range_map(
+	__isl_take isl_union_map *umap);
+__isl_give isl_union_map *isl_union_set_wrapped_domain_map(
+	__isl_take isl_union_set *uset);
+__isl_give isl_union_map *isl_union_map_from_domain(
+	__isl_take isl_union_set *uset);
+__isl_give isl_union_map *isl_union_map_from_range(
+	__isl_take isl_union_set *uset);
+
+__isl_export
+__isl_give isl_union_map *isl_union_map_affine_hull(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_polyhedral_hull(
+	__isl_take isl_union_map *umap);
+__isl_give isl_union_map *isl_union_map_remove_redundancies(
+	__isl_take isl_union_map *umap);
+__isl_give isl_union_map *isl_union_map_simple_hull(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_coalesce(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_compute_divs(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_lexmin(__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_lexmax(__isl_take isl_union_map *umap);
+
+__isl_give isl_union_map *isl_union_map_add_map(__isl_take isl_union_map *umap,
+	__isl_take isl_map *map);
+__isl_export
+__isl_give isl_union_map *isl_union_map_union(__isl_take isl_union_map *umap1,
+	__isl_take isl_union_map *umap2);
+__isl_export
+__isl_give isl_union_map *isl_union_map_subtract(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+__isl_export
+__isl_give isl_union_map *isl_union_map_intersect(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+__isl_export
+__isl_give isl_union_map *isl_union_map_intersect_params(
+	__isl_take isl_union_map *umap, __isl_take isl_set *set);
+__isl_export
+__isl_give isl_union_map *isl_union_map_product(__isl_take isl_union_map *umap1,
+	__isl_take isl_union_map *umap2);
+__isl_export
+__isl_give isl_union_map *isl_union_map_domain_product(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+__isl_give isl_union_map *isl_union_map_flat_domain_product(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+__isl_export
+__isl_give isl_union_map *isl_union_map_range_product(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+__isl_give isl_union_map *isl_union_map_flat_range_product(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+__isl_export
+__isl_give isl_union_map *isl_union_map_domain_factor_domain(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_domain_factor_range(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_range_factor_domain(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_range_factor_range(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_factor_domain(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_factor_range(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_gist(__isl_take isl_union_map *umap,
+	__isl_take isl_union_map *context);
+__isl_export
+__isl_give isl_union_map *isl_union_map_gist_params(
+	__isl_take isl_union_map *umap, __isl_take isl_set *set);
+__isl_export
+__isl_give isl_union_map *isl_union_map_gist_domain(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset);
+__isl_export
+__isl_give isl_union_map *isl_union_map_gist_range(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset);
+
+__isl_export
+__isl_give isl_union_map *isl_union_map_intersect_domain(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset);
+__isl_export
+__isl_give isl_union_map *isl_union_map_intersect_range(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset);
+__isl_give isl_union_map *isl_union_map_intersect_range_factor_range(
+	__isl_take isl_union_map *umap, __isl_take isl_union_map *factor);
+
+__isl_export
+__isl_give isl_union_map *isl_union_map_subtract_domain(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *dom);
+__isl_export
+__isl_give isl_union_map *isl_union_map_subtract_range(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *dom);
+
+__isl_export
+__isl_give isl_union_map *isl_union_map_apply_domain(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+__isl_export
+__isl_give isl_union_map *isl_union_map_apply_range(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+__isl_give isl_union_map *isl_union_map_preimage_domain_multi_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_multi_aff *ma);
+__isl_give isl_union_map *isl_union_map_preimage_range_multi_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_multi_aff *ma);
+__isl_give isl_union_map *isl_union_map_preimage_domain_pw_multi_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma);
+__isl_give isl_union_map *isl_union_map_preimage_range_pw_multi_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma);
+__isl_give isl_union_map *isl_union_map_preimage_domain_multi_pw_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_multi_pw_aff *mpa);
+__isl_give isl_union_map *isl_union_map_preimage_domain_union_pw_multi_aff(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_union_pw_multi_aff *upma);
+__isl_give isl_union_map *isl_union_map_preimage_range_union_pw_multi_aff(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_union_pw_multi_aff *upma);
+__isl_export
+__isl_give isl_union_map *isl_union_map_reverse(__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_map_from_domain_and_range(
+	__isl_take isl_union_set *domain, __isl_take isl_union_set *range);
+
+__isl_export
+__isl_give isl_union_map *isl_union_map_detect_equalities(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_set *isl_union_map_deltas(__isl_take isl_union_map *umap);
+__isl_give isl_union_map *isl_union_map_deltas_map(
+	__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_set_identity(__isl_take isl_union_set *uset);
+
+__isl_give isl_union_map *isl_union_map_project_out(
+	__isl_take isl_union_map *umap,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_union_map *isl_union_map_remove_divs(
+	__isl_take isl_union_map *bmap);
+
+__isl_export
+isl_bool isl_union_map_is_empty(__isl_keep isl_union_map *umap);
+__isl_export
+isl_bool isl_union_map_is_single_valued(__isl_keep isl_union_map *umap);
+isl_bool isl_union_map_plain_is_injective(__isl_keep isl_union_map *umap);
+__isl_export
+isl_bool isl_union_map_is_injective(__isl_keep isl_union_map *umap);
+__isl_export
+isl_bool isl_union_map_is_bijective(__isl_keep isl_union_map *umap);
+isl_bool isl_union_map_is_identity(__isl_keep isl_union_map *umap);
+
+__isl_export
+isl_bool isl_union_map_is_subset(__isl_keep isl_union_map *umap1,
+	__isl_keep isl_union_map *umap2);
+__isl_export
+isl_bool isl_union_map_is_equal(__isl_keep isl_union_map *umap1,
+	__isl_keep isl_union_map *umap2);
+isl_bool isl_union_map_is_disjoint(__isl_keep isl_union_map *umap1,
+	__isl_keep isl_union_map *umap2);
+__isl_export
+isl_bool isl_union_map_is_strict_subset(__isl_keep isl_union_map *umap1,
+	__isl_keep isl_union_map *umap2);
+
+uint32_t isl_union_map_get_hash(__isl_keep isl_union_map *umap);
+
+int isl_union_map_n_map(__isl_keep isl_union_map *umap);
+__isl_export
+isl_stat isl_union_map_foreach_map(__isl_keep isl_union_map *umap,
+	isl_stat (*fn)(__isl_take isl_map *map, void *user), void *user);
+isl_bool isl_union_map_contains(__isl_keep isl_union_map *umap,
+	__isl_keep isl_space *space);
+__isl_give isl_map *isl_union_map_extract_map(__isl_keep isl_union_map *umap,
+	__isl_take isl_space *dim);
+__isl_give isl_map *isl_map_from_union_map(__isl_take isl_union_map *umap);
+
+__isl_give isl_basic_map *isl_union_map_sample(__isl_take isl_union_map *umap);
+
+__isl_overload
+__isl_give isl_union_map *isl_union_map_fixed_power_val(
+	__isl_take isl_union_map *umap, __isl_take isl_val *exp);
+__isl_give isl_union_map *isl_union_map_power(__isl_take isl_union_map *umap,
+	int *exact);
+__isl_give isl_union_map *isl_union_map_transitive_closure(
+	__isl_take isl_union_map *umap, int *exact);
+
+__isl_give isl_union_map *isl_union_map_lex_lt_union_map(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+__isl_give isl_union_map *isl_union_map_lex_le_union_map(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+__isl_give isl_union_map *isl_union_map_lex_gt_union_map(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+__isl_give isl_union_map *isl_union_map_lex_ge_union_map(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2);
+
+__isl_give isl_union_map *isl_union_map_eq_at_multi_union_pw_aff(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_multi_union_pw_aff *mupa);
+__isl_give isl_union_map *isl_union_map_lex_lt_at_multi_union_pw_aff(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_multi_union_pw_aff *mupa);
+__isl_give isl_union_map *isl_union_map_lex_gt_at_multi_union_pw_aff(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_multi_union_pw_aff *mupa);
+
+__isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx,
+	FILE *input);
+__isl_constructor
+__isl_give isl_union_map *isl_union_map_read_from_str(isl_ctx *ctx,
+	const char *str);
+__isl_give char *isl_union_map_to_str(__isl_keep isl_union_map *umap);
+__isl_give isl_printer *isl_printer_print_union_map(__isl_take isl_printer *p,
+	__isl_keep isl_union_map *umap);
+void isl_union_map_dump(__isl_keep isl_union_map *umap);
+
+__isl_export
+__isl_give isl_union_set *isl_union_map_wrap(__isl_take isl_union_map *umap);
+__isl_export
+__isl_give isl_union_map *isl_union_set_unwrap(__isl_take isl_union_set *uset);
+
+__isl_export
+__isl_give isl_union_map *isl_union_map_zip(__isl_take isl_union_map *umap);
+__isl_give isl_union_map *isl_union_map_curry(__isl_take isl_union_map *umap);
+__isl_give isl_union_map *isl_union_map_range_curry(
+	__isl_take isl_union_map *umap);
+__isl_give isl_union_map *isl_union_map_uncurry(__isl_take isl_union_map *umap);
+
+__isl_give isl_union_map *isl_union_map_align_params(
+	__isl_take isl_union_map *umap, __isl_take isl_space *model);
+__isl_give isl_union_set *isl_union_set_align_params(
+	__isl_take isl_union_set *uset, __isl_take isl_space *model);
+
+ISL_DECLARE_LIST_FN(union_map)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/union_map_type.h b/final/lib/External/isl/include/isl/union_map_type.h
new file mode 100644
index 0000000..72fdffd
--- /dev/null
+++ b/final/lib/External/isl/include/isl/union_map_type.h
@@ -0,0 +1,24 @@
+#ifndef ISL_UNION_MAP_TYPE_H
+#define ISL_UNION_MAP_TYPE_H
+
+#include <isl/ctx.h>
+#include <isl/list.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct __isl_export isl_union_map;
+typedef struct isl_union_map isl_union_map;
+ISL_DECLARE_LIST_TYPE(union_map)
+#ifndef isl_union_set
+struct __isl_export isl_union_set;
+typedef struct isl_union_set isl_union_set;
+ISL_DECLARE_LIST_TYPE(union_set)
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/union_set.h b/final/lib/External/isl/include/isl/union_set.h
new file mode 100644
index 0000000..ca4090b
--- /dev/null
+++ b/final/lib/External/isl/include/isl/union_set.h
@@ -0,0 +1,173 @@
+#ifndef ISL_UNION_SET_H
+#define ISL_UNION_SET_H
+
+#include <isl/point.h>
+#include <isl/union_map.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+unsigned isl_union_set_dim(__isl_keep isl_union_set *uset,
+	enum isl_dim_type type);
+
+__isl_constructor
+__isl_give isl_union_set *isl_union_set_from_basic_set(
+	__isl_take isl_basic_set *bset);
+__isl_constructor
+__isl_give isl_union_set *isl_union_set_from_set(__isl_take isl_set *set);
+__isl_give isl_union_set *isl_union_set_empty(__isl_take isl_space *dim);
+__isl_give isl_union_set *isl_union_set_copy(__isl_keep isl_union_set *uset);
+__isl_null isl_union_set *isl_union_set_free(__isl_take isl_union_set *uset);
+
+isl_ctx *isl_union_set_get_ctx(__isl_keep isl_union_set *uset);
+__isl_give isl_space *isl_union_set_get_space(__isl_keep isl_union_set *uset);
+
+__isl_give isl_union_set *isl_union_set_reset_user(
+	__isl_take isl_union_set *uset);
+
+__isl_give isl_union_set *isl_union_set_universe(
+	__isl_take isl_union_set *uset);
+__isl_give isl_set *isl_union_set_params(__isl_take isl_union_set *uset);
+
+__isl_export
+__isl_give isl_union_set *isl_union_set_detect_equalities(
+	__isl_take isl_union_set *uset);
+__isl_export
+__isl_give isl_union_set *isl_union_set_affine_hull(
+	__isl_take isl_union_set *uset);
+__isl_export
+__isl_give isl_union_set *isl_union_set_polyhedral_hull(
+	__isl_take isl_union_set *uset);
+__isl_give isl_union_set *isl_union_set_remove_redundancies(
+	__isl_take isl_union_set *uset);
+__isl_give isl_union_set *isl_union_set_simple_hull(
+	__isl_take isl_union_set *uset);
+__isl_export
+__isl_give isl_union_set *isl_union_set_coalesce(
+	__isl_take isl_union_set *uset);
+__isl_export
+__isl_give isl_union_set *isl_union_set_compute_divs(
+	__isl_take isl_union_set *uset);
+__isl_export
+__isl_give isl_union_set *isl_union_set_lexmin(__isl_take isl_union_set *uset);
+__isl_export
+__isl_give isl_union_set *isl_union_set_lexmax(__isl_take isl_union_set *uset);
+
+__isl_give isl_union_set *isl_union_set_add_set(__isl_take isl_union_set *uset,
+	__isl_take isl_set *set);
+__isl_export
+__isl_give isl_union_set *isl_union_set_union(__isl_take isl_union_set *uset1,
+	__isl_take isl_union_set *uset2);
+__isl_export
+__isl_give isl_union_set *isl_union_set_subtract(
+	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2);
+__isl_export
+__isl_give isl_union_set *isl_union_set_intersect(
+	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2);
+__isl_export
+__isl_give isl_union_set *isl_union_set_intersect_params(
+	__isl_take isl_union_set *uset, __isl_take isl_set *set);
+__isl_give isl_union_set *isl_union_set_product(__isl_take isl_union_set *uset1,
+	__isl_take isl_union_set *uset2);
+__isl_export
+__isl_give isl_union_set *isl_union_set_gist(__isl_take isl_union_set *uset,
+	__isl_take isl_union_set *context);
+__isl_export
+__isl_give isl_union_set *isl_union_set_gist_params(
+	__isl_take isl_union_set *uset, __isl_take isl_set *set);
+
+__isl_export
+__isl_give isl_union_set *isl_union_set_apply(
+	__isl_take isl_union_set *uset, __isl_take isl_union_map *umap);
+__isl_give isl_union_set *isl_union_set_preimage_multi_aff(
+	__isl_take isl_union_set *uset, __isl_take isl_multi_aff *ma);
+__isl_give isl_union_set *isl_union_set_preimage_pw_multi_aff(
+	__isl_take isl_union_set *uset, __isl_take isl_pw_multi_aff *pma);
+__isl_give isl_union_set *isl_union_set_preimage_union_pw_multi_aff(
+	__isl_take isl_union_set *uset,
+	__isl_take isl_union_pw_multi_aff *upma);
+
+__isl_give isl_union_set *isl_union_set_project_out(
+	__isl_take isl_union_set *uset,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_union_set *isl_union_set_remove_divs(
+	__isl_take isl_union_set *bset);
+
+isl_bool isl_union_set_is_params(__isl_keep isl_union_set *uset);
+__isl_export
+isl_bool isl_union_set_is_empty(__isl_keep isl_union_set *uset);
+
+__isl_export
+isl_bool isl_union_set_is_subset(__isl_keep isl_union_set *uset1,
+	__isl_keep isl_union_set *uset2);
+__isl_export
+isl_bool isl_union_set_is_equal(__isl_keep isl_union_set *uset1,
+	__isl_keep isl_union_set *uset2);
+isl_bool isl_union_set_is_disjoint(__isl_keep isl_union_set *uset1,
+	__isl_keep isl_union_set *uset2);
+__isl_export
+isl_bool isl_union_set_is_strict_subset(__isl_keep isl_union_set *uset1,
+	__isl_keep isl_union_set *uset2);
+
+uint32_t isl_union_set_get_hash(__isl_keep isl_union_set *uset);
+
+int isl_union_set_n_set(__isl_keep isl_union_set *uset);
+__isl_export
+isl_stat isl_union_set_foreach_set(__isl_keep isl_union_set *uset,
+	isl_stat (*fn)(__isl_take isl_set *set, void *user), void *user);
+__isl_give isl_basic_set_list *isl_union_set_get_basic_set_list(
+	__isl_keep isl_union_set *uset);
+isl_bool isl_union_set_contains(__isl_keep isl_union_set *uset,
+	__isl_keep isl_space *space);
+__isl_give isl_set *isl_union_set_extract_set(__isl_keep isl_union_set *uset,
+	__isl_take isl_space *dim);
+__isl_give isl_set *isl_set_from_union_set(__isl_take isl_union_set *uset);
+__isl_export
+isl_stat isl_union_set_foreach_point(__isl_keep isl_union_set *uset,
+	isl_stat (*fn)(__isl_take isl_point *pnt, void *user), void *user);
+
+__isl_give isl_basic_set *isl_union_set_sample(__isl_take isl_union_set *uset);
+__isl_export
+__isl_give isl_point *isl_union_set_sample_point(
+	__isl_take isl_union_set *uset);
+
+__isl_constructor
+__isl_give isl_union_set *isl_union_set_from_point(__isl_take isl_point *pnt);
+
+__isl_give isl_union_set *isl_union_set_lift(__isl_take isl_union_set *uset);
+
+__isl_give isl_union_map *isl_union_set_lex_lt_union_set(
+	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2);
+__isl_give isl_union_map *isl_union_set_lex_le_union_set(
+	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2);
+__isl_give isl_union_map *isl_union_set_lex_gt_union_set(
+	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2);
+__isl_give isl_union_map *isl_union_set_lex_ge_union_set(
+	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2);
+
+__isl_give isl_union_set *isl_union_set_coefficients(
+	__isl_take isl_union_set *bset);
+__isl_give isl_union_set *isl_union_set_solutions(
+	__isl_take isl_union_set *bset);
+
+__isl_give isl_union_set *isl_union_set_read_from_file(isl_ctx *ctx,
+	FILE *input);
+__isl_constructor
+__isl_give isl_union_set *isl_union_set_read_from_str(isl_ctx *ctx,
+	const char *str);
+__isl_give char *isl_union_set_to_str(__isl_keep isl_union_set *uset);
+__isl_give isl_printer *isl_printer_print_union_set(__isl_take isl_printer *p,
+	__isl_keep isl_union_set *uset);
+void isl_union_set_dump(__isl_keep isl_union_set *uset);
+
+ISL_DECLARE_LIST_FN(union_set)
+
+__isl_give isl_union_set *isl_union_set_list_union(
+	__isl_take isl_union_set_list *list);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/union_set_type.h b/final/lib/External/isl/include/isl/union_set_type.h
new file mode 100644
index 0000000..86b2c31
--- /dev/null
+++ b/final/lib/External/isl/include/isl/union_set_type.h
@@ -0,0 +1,6 @@
+#ifndef ISL_UNION_SET_TYPE_H
+#define ISL_UNION_SET_TYPE_H
+
+#include <isl/union_map_type.h>
+
+#endif
diff --git a/final/lib/External/isl/include/isl/val.h b/final/lib/External/isl/include/isl/val.h
new file mode 100644
index 0000000..fb50eaa
--- /dev/null
+++ b/final/lib/External/isl/include/isl/val.h
@@ -0,0 +1,167 @@
+#ifndef ISL_VAL_H
+#define ISL_VAL_H
+
+#include <isl/ctx.h>
+#include <isl/list.h>
+#include <isl/multi.h>
+#include <isl/printer.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct __isl_export isl_val;
+typedef struct isl_val isl_val;
+
+ISL_DECLARE_LIST(val)
+
+struct __isl_export isl_multi_val;
+typedef struct isl_multi_val isl_multi_val;
+
+ISL_DECLARE_MULTI(val)
+ISL_DECLARE_MULTI_NEG(val)
+ISL_DECLARE_MULTI_DIMS(val)
+ISL_DECLARE_MULTI_WITH_DOMAIN(val)
+
+__isl_export
+__isl_give isl_val *isl_val_zero(isl_ctx *ctx);
+__isl_export
+__isl_give isl_val *isl_val_one(isl_ctx *ctx);
+__isl_export
+__isl_give isl_val *isl_val_negone(isl_ctx *ctx);
+__isl_export
+__isl_give isl_val *isl_val_nan(isl_ctx *ctx);
+__isl_export
+__isl_give isl_val *isl_val_infty(isl_ctx *ctx);
+__isl_export
+__isl_give isl_val *isl_val_neginfty(isl_ctx *ctx);
+__isl_constructor
+__isl_give isl_val *isl_val_int_from_si(isl_ctx *ctx, long i);
+__isl_give isl_val *isl_val_int_from_ui(isl_ctx *ctx, unsigned long u);
+__isl_give isl_val *isl_val_int_from_chunks(isl_ctx *ctx, size_t n,
+	size_t size, const void *chunks);
+
+__isl_give isl_val *isl_val_copy(__isl_keep isl_val *v);
+__isl_null isl_val *isl_val_free(__isl_take isl_val *v);
+
+isl_ctx *isl_val_get_ctx(__isl_keep isl_val *val);
+uint32_t isl_val_get_hash(__isl_keep isl_val *val);
+long isl_val_get_num_si(__isl_keep isl_val *v);
+long isl_val_get_den_si(__isl_keep isl_val *v);
+__isl_give isl_val *isl_val_get_den_val(__isl_keep isl_val *v);
+double isl_val_get_d(__isl_keep isl_val *v);
+size_t isl_val_n_abs_num_chunks(__isl_keep isl_val *v, size_t size);
+int isl_val_get_abs_num_chunks(__isl_keep isl_val *v, size_t size,
+	void *chunks);
+
+__isl_give isl_val *isl_val_set_si(__isl_take isl_val *v, long i);
+
+__isl_export
+__isl_give isl_val *isl_val_abs(__isl_take isl_val *v);
+__isl_export
+__isl_give isl_val *isl_val_neg(__isl_take isl_val *v);
+__isl_export
+__isl_give isl_val *isl_val_inv(__isl_take isl_val *v);
+__isl_export
+__isl_give isl_val *isl_val_floor(__isl_take isl_val *v);
+__isl_export
+__isl_give isl_val *isl_val_ceil(__isl_take isl_val *v);
+__isl_export
+__isl_give isl_val *isl_val_trunc(__isl_take isl_val *v);
+__isl_give isl_val *isl_val_2exp(__isl_take isl_val *v);
+__isl_export
+__isl_give isl_val *isl_val_min(__isl_take isl_val *v1, __isl_take isl_val *v2);
+__isl_export
+__isl_give isl_val *isl_val_max(__isl_take isl_val *v1, __isl_take isl_val *v2);
+__isl_export
+__isl_give isl_val *isl_val_add(__isl_take isl_val *v1, __isl_take isl_val *v2);
+__isl_give isl_val *isl_val_add_ui(__isl_take isl_val *v1, unsigned long v2);
+__isl_export
+__isl_give isl_val *isl_val_sub(__isl_take isl_val *v1, __isl_take isl_val *v2);
+__isl_give isl_val *isl_val_sub_ui(__isl_take isl_val *v1, unsigned long v2);
+__isl_export
+__isl_give isl_val *isl_val_mul(__isl_take isl_val *v1, __isl_take isl_val *v2);
+__isl_give isl_val *isl_val_mul_ui(__isl_take isl_val *v1, unsigned long v2);
+__isl_export
+__isl_give isl_val *isl_val_div(__isl_take isl_val *v1, __isl_take isl_val *v2);
+__isl_give isl_val *isl_val_div_ui(__isl_take isl_val *v1, unsigned long v2);
+__isl_export
+__isl_give isl_val *isl_val_mod(__isl_take isl_val *v1, __isl_take isl_val *v2);
+__isl_export
+__isl_give isl_val *isl_val_gcd(__isl_take isl_val *v1, __isl_take isl_val *v2);
+__isl_give isl_val *isl_val_gcdext(__isl_take isl_val *v1,
+	__isl_take isl_val *v2, __isl_give isl_val **x, __isl_give isl_val **y);
+
+__isl_export
+int isl_val_sgn(__isl_keep isl_val *v);
+__isl_export
+isl_bool isl_val_is_zero(__isl_keep isl_val *v);
+__isl_export
+isl_bool isl_val_is_one(__isl_keep isl_val *v);
+__isl_export
+isl_bool isl_val_is_negone(__isl_keep isl_val *v);
+__isl_export
+isl_bool isl_val_is_nonneg(__isl_keep isl_val *v);
+__isl_export
+isl_bool isl_val_is_nonpos(__isl_keep isl_val *v);
+__isl_export
+isl_bool isl_val_is_pos(__isl_keep isl_val *v);
+__isl_export
+isl_bool isl_val_is_neg(__isl_keep isl_val *v);
+__isl_export
+isl_bool isl_val_is_int(__isl_keep isl_val *v);
+__isl_export
+isl_bool isl_val_is_rat(__isl_keep isl_val *v);
+__isl_export
+isl_bool isl_val_is_nan(__isl_keep isl_val *v);
+__isl_export
+isl_bool isl_val_is_infty(__isl_keep isl_val *v);
+__isl_export
+isl_bool isl_val_is_neginfty(__isl_keep isl_val *v);
+
+__isl_export
+int isl_val_cmp_si(__isl_keep isl_val *v, long i);
+
+__isl_export
+isl_bool isl_val_lt(__isl_keep isl_val *v1, __isl_keep isl_val *v2);
+__isl_export
+isl_bool isl_val_le(__isl_keep isl_val *v1, __isl_keep isl_val *v2);
+__isl_export
+isl_bool isl_val_gt(__isl_keep isl_val *v1, __isl_keep isl_val *v2);
+__isl_export
+isl_bool isl_val_ge(__isl_keep isl_val *v1, __isl_keep isl_val *v2);
+__isl_export
+isl_bool isl_val_eq(__isl_keep isl_val *v1, __isl_keep isl_val *v2);
+__isl_export
+isl_bool isl_val_ne(__isl_keep isl_val *v1, __isl_keep isl_val *v2);
+__isl_export
+isl_bool isl_val_abs_eq(__isl_keep isl_val *v1, __isl_keep isl_val *v2);
+
+__isl_export
+isl_bool isl_val_is_divisible_by(__isl_keep isl_val *v1,
+	__isl_keep isl_val *v2);
+
+__isl_constructor
+__isl_give isl_val *isl_val_read_from_str(isl_ctx *ctx, const char *str);
+__isl_give isl_printer *isl_printer_print_val(__isl_take isl_printer *p,
+	__isl_keep isl_val *v);
+void isl_val_dump(__isl_keep isl_val *v);
+__isl_give char *isl_val_to_str(__isl_keep isl_val *v);
+
+__isl_give isl_multi_val *isl_multi_val_add_val(__isl_take isl_multi_val *mv,
+	__isl_take isl_val *v);
+__isl_give isl_multi_val *isl_multi_val_mod_val(__isl_take isl_multi_val *mv,
+	__isl_take isl_val *v);
+
+__isl_give isl_multi_val *isl_multi_val_read_from_str(isl_ctx *ctx,
+	const char *str);
+__isl_give isl_printer *isl_printer_print_multi_val(__isl_take isl_printer *p,
+	__isl_keep isl_multi_val *mv);
+void isl_multi_val_dump(__isl_keep isl_multi_val *mv);
+__isl_give char *isl_multi_val_to_str(__isl_keep isl_multi_val *mv);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/val_gmp.h b/final/lib/External/isl/include/isl/val_gmp.h
new file mode 100644
index 0000000..9558c1a
--- /dev/null
+++ b/final/lib/External/isl/include/isl/val_gmp.h
@@ -0,0 +1,21 @@
+#ifndef ISL_VAL_GMP_H
+#define ISL_VAL_GMP_H
+
+#include <gmp.h>
+#include <isl/val.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_val *isl_val_int_from_gmp(isl_ctx *ctx, mpz_t z);
+__isl_give isl_val *isl_val_from_gmp(isl_ctx *ctx,
+	const mpz_t n, const mpz_t d);
+int isl_val_get_num_gmp(__isl_keep isl_val *v, mpz_t z);
+int isl_val_get_den_gmp(__isl_keep isl_val *v, mpz_t z);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/vec.h b/final/lib/External/isl/include/isl/vec.h
new file mode 100644
index 0000000..6b58794
--- /dev/null
+++ b/final/lib/External/isl/include/isl/vec.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_VEC_H
+#define ISL_VEC_H
+
+#include <stdio.h>
+
+#include <isl/ctx.h>
+#include <isl/val.h>
+#include <isl/printer.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_vec;
+typedef struct isl_vec isl_vec;
+
+__isl_give isl_vec *isl_vec_alloc(isl_ctx *ctx, unsigned size);
+__isl_give isl_vec *isl_vec_copy(__isl_keep isl_vec *vec);
+__isl_null isl_vec *isl_vec_free(__isl_take isl_vec *vec);
+
+isl_ctx *isl_vec_get_ctx(__isl_keep isl_vec *vec);
+
+int isl_vec_size(__isl_keep isl_vec *vec);
+__isl_give isl_val *isl_vec_get_element_val(__isl_keep isl_vec *vec, int pos);
+__isl_give isl_vec *isl_vec_set_element_si(__isl_take isl_vec *vec,
+	int pos, int v);
+__isl_give isl_vec *isl_vec_set_element_val(__isl_take isl_vec *vec,
+	int pos, __isl_take isl_val *v);
+
+isl_bool isl_vec_is_equal(__isl_keep isl_vec *vec1, __isl_keep isl_vec *vec2);
+int isl_vec_cmp_element(__isl_keep isl_vec *vec1, __isl_keep isl_vec *vec2,
+	int pos);
+
+void isl_vec_dump(__isl_keep isl_vec *vec);
+__isl_give isl_printer *isl_printer_print_vec(__isl_take isl_printer *printer,
+	__isl_keep isl_vec *vec);
+
+__isl_give isl_vec *isl_vec_ceil(__isl_take isl_vec *vec);
+struct isl_vec *isl_vec_normalize(struct isl_vec *vec);
+__isl_give isl_vec *isl_vec_set_si(__isl_take isl_vec *vec, int v);
+__isl_give isl_vec *isl_vec_set_val(__isl_take isl_vec *vec,
+	__isl_take isl_val *v);
+__isl_give isl_vec *isl_vec_clr(__isl_take isl_vec *vec);
+__isl_give isl_vec *isl_vec_neg(__isl_take isl_vec *vec);
+__isl_give isl_vec *isl_vec_add(__isl_take isl_vec *vec1,
+	__isl_take isl_vec *vec2);
+__isl_give isl_vec *isl_vec_extend(__isl_take isl_vec *vec, unsigned size);
+__isl_give isl_vec *isl_vec_zero_extend(__isl_take isl_vec *vec, unsigned size);
+__isl_give isl_vec *isl_vec_concat(__isl_take isl_vec *vec1,
+	__isl_take isl_vec *vec2);
+
+__isl_give isl_vec *isl_vec_sort(__isl_take isl_vec *vec);
+
+__isl_give isl_vec *isl_vec_read_from_file(isl_ctx *ctx, FILE *input);
+
+__isl_give isl_vec *isl_vec_drop_els(__isl_take isl_vec *vec,
+	unsigned pos, unsigned n);
+__isl_give isl_vec *isl_vec_insert_els(__isl_take isl_vec *vec,
+	unsigned pos, unsigned n);
+__isl_give isl_vec *isl_vec_insert_zero_els(__isl_take isl_vec *vec,
+	unsigned pos, unsigned n);
+__isl_give isl_vec *isl_vec_move_els(__isl_take isl_vec *vec,
+	unsigned dst_col, unsigned src_col, unsigned n);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/version.h b/final/lib/External/isl/include/isl/version.h
new file mode 100644
index 0000000..7f8f23d
--- /dev/null
+++ b/final/lib/External/isl/include/isl/version.h
@@ -0,0 +1,14 @@
+#ifndef ISL_VERSION_H
+#define ISL_VERSION_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+const char *isl_version(void);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/include/isl/vertices.h b/final/lib/External/isl/include/isl/vertices.h
new file mode 100644
index 0000000..6a7ee6a
--- /dev/null
+++ b/final/lib/External/isl/include/isl/vertices.h
@@ -0,0 +1,47 @@
+#ifndef ISL_VERTICES_H
+#define ISL_VERTICES_H
+
+#include <isl/aff_type.h>
+#include <isl/set_type.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_external_vertex;
+typedef struct isl_external_vertex	isl_vertex;
+
+struct isl_cell;
+typedef struct isl_cell		isl_cell;
+
+struct isl_vertices;
+typedef struct isl_vertices	isl_vertices;
+
+isl_ctx *isl_vertex_get_ctx(__isl_keep isl_vertex *vertex);
+int isl_vertex_get_id(__isl_keep isl_vertex *vertex);
+__isl_give isl_basic_set *isl_vertex_get_domain(__isl_keep isl_vertex *vertex);
+__isl_give isl_multi_aff *isl_vertex_get_expr(__isl_keep isl_vertex *vertex);
+void isl_vertex_free(__isl_take isl_vertex *vertex);
+
+__isl_give isl_vertices *isl_basic_set_compute_vertices(
+	__isl_keep isl_basic_set *bset);
+isl_ctx *isl_vertices_get_ctx(__isl_keep isl_vertices *vertices);
+int isl_vertices_get_n_vertices(__isl_keep isl_vertices *vertices);
+isl_stat isl_vertices_foreach_vertex(__isl_keep isl_vertices *vertices,
+	isl_stat (*fn)(__isl_take isl_vertex *vertex, void *user), void *user);
+__isl_null isl_vertices *isl_vertices_free(__isl_take isl_vertices *vertices);
+
+isl_ctx *isl_cell_get_ctx(__isl_keep isl_cell *cell);
+__isl_give isl_basic_set *isl_cell_get_domain(__isl_keep isl_cell *cell);
+isl_stat isl_cell_foreach_vertex(__isl_keep isl_cell *cell,
+	isl_stat (*fn)(__isl_take isl_vertex *vertex, void *user), void *user);
+void isl_cell_free(__isl_take isl_cell *cell);
+
+isl_stat isl_vertices_foreach_cell(__isl_keep isl_vertices *vertices,
+	isl_stat (*fn)(__isl_take isl_cell *cell, void *user), void *user);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/install-sh b/final/lib/External/isl/install-sh
new file mode 100755
index 0000000..59990a1
--- /dev/null
+++ b/final/lib/External/isl/install-sh
@@ -0,0 +1,508 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2014-09-12.12; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+tab='	'
+nl='
+'
+IFS=" $tab$nl"
+
+# Set DOITPROG to "echo" to test this script.
+
+doit=${DOITPROG-}
+doit_exec=${doit:-exec}
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+is_target_a_directory=possibly
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+     --help     display this help and exit.
+     --version  display version info and exit.
+
+  -c            (ignored)
+  -C            install only if different (preserve the last data modification time)
+  -d            create directories instead of installing files.
+  -g GROUP      $chgrpprog installed files to GROUP.
+  -m MODE       $chmodprog installed files to MODE.
+  -o USER       $chownprog installed files to USER.
+  -s            $stripprog installed files.
+  -t DIRECTORY  install into DIRECTORY.
+  -T            report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+  RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+  case $1 in
+    -c) ;;
+
+    -C) copy_on_change=true;;
+
+    -d) dir_arg=true;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+        shift;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) mode=$2
+        case $mode in
+          *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+            echo "$0: invalid mode: $mode" >&2
+            exit 1;;
+        esac
+        shift;;
+
+    -o) chowncmd="$chownprog $2"
+        shift;;
+
+    -s) stripcmd=$stripprog;;
+
+    -t)
+        is_target_a_directory=always
+        dst_arg=$2
+        # Protect names problematic for 'test' and other utilities.
+        case $dst_arg in
+          -* | [=\(\)!]) dst_arg=./$dst_arg;;
+        esac
+        shift;;
+
+    -T) is_target_a_directory=never;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    --) shift
+        break;;
+
+    -*) echo "$0: invalid option: $1" >&2
+        exit 1;;
+
+    *)  break;;
+  esac
+  shift
+done
+
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+  if test -n "$dst_arg"; then
+    echo "$0: target directory not allowed when installing a directory." >&2
+    exit 1
+  fi
+fi
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dst_arg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dst_arg"
+      shift # fnord
+    fi
+    shift # arg
+    dst_arg=$arg
+    # Protect names problematic for 'test' and other utilities.
+    case $dst_arg in
+      -* | [=\(\)!]) dst_arg=./$dst_arg;;
+    esac
+  done
+fi
+
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call 'install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  if test $# -gt 1 || test "$is_target_a_directory" = always; then
+    if test ! -d "$dst_arg"; then
+      echo "$0: $dst_arg: Is not a directory." >&2
+      exit 1
+    fi
+  fi
+fi
+
+if test -z "$dir_arg"; then
+  do_exit='(exit $ret); exit $ret'
+  trap "ret=129; $do_exit" 1
+  trap "ret=130; $do_exit" 2
+  trap "ret=141; $do_exit" 13
+  trap "ret=143; $do_exit" 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+        u_plus_rw=
+      else
+        u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+        u_plus_rw=
+      else
+        u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
+
+for src
+do
+  # Protect names problematic for 'test' and other utilities.
+  case $src in
+    -* | [=\(\)!]) src=./$src;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dst_arg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+    dst=$dst_arg
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test "$is_target_a_directory" = never; then
+        echo "$0: $dst_arg: Is a directory" >&2
+        exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      dstdir=`dirname "$dst"`
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+        # Create intermediate dirs using mode 755 as modified by the umask.
+        # This is like FreeBSD 'install' as of 1997-10-28.
+        umask=`umask`
+        case $stripcmd.$umask in
+          # Optimize common cases.
+          *[2367][2367]) mkdir_umask=$umask;;
+          .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+          *[0-7])
+            mkdir_umask=`expr $umask + 22 \
+              - $umask % 100 % 40 + $umask % 20 \
+              - $umask % 10 % 4 + $umask % 2
+            `;;
+          *) mkdir_umask=$umask,go-w;;
+        esac
+
+        # With -d, create the new directory with the user-specified mode.
+        # Otherwise, rely on $mkdir_umask.
+        if test -n "$dir_arg"; then
+          mkdir_mode=-m$mode
+        else
+          mkdir_mode=
+        fi
+
+        posix_mkdir=false
+        case $umask in
+          *[123567][0-7][0-7])
+            # POSIX mkdir -p sets u+wx bits regardless of umask, which
+            # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+            ;;
+          *)
+            # $RANDOM is not portable (e.g. dash);  use it when possible to
+            # lower collision chance
+            tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+            trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+            # As "mkdir -p" follows symlinks and we work in /tmp possibly;  so
+            # create the $tmpdir first (and fail if unsuccessful) to make sure
+            # that nobody tries to guess the $tmpdir name.
+            if (umask $mkdir_umask &&
+                $mkdirprog $mkdir_mode "$tmpdir" &&
+                exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+            then
+              if test -z "$dir_arg" || {
+                   # Check for POSIX incompatibilities with -m.
+                   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+                   # other-writable bit of parent directory when it shouldn't.
+                   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+                   test_tmpdir="$tmpdir/a"
+                   ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+                   case $ls_ld_tmpdir in
+                     d????-?r-*) different_mode=700;;
+                     d????-?--*) different_mode=755;;
+                     *) false;;
+                   esac &&
+                   $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+                     ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+                     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+                   }
+                 }
+              then posix_mkdir=:
+              fi
+              rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+            else
+              # Remove any dirs left behind by ancient mkdir implementations.
+              rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+            fi
+            trap '' 0;;
+        esac;;
+    esac
+
+    if
+      $posix_mkdir && (
+        umask $mkdir_umask &&
+        $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+        /*) prefix='/';;
+        [-=\(\)!]*) prefix='./';;
+        *)  prefix='';;
+      esac
+
+      oIFS=$IFS
+      IFS=/
+      set -f
+      set fnord $dstdir
+      shift
+      set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+        test X"$d" = X && continue
+
+        prefix=$prefix$d
+        if test -d "$prefix"; then
+          prefixes=
+        else
+          if $posix_mkdir; then
+            (umask=$mkdir_umask &&
+             $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+            # Don't fail if two instances are running concurrently.
+            test -d "$prefix" || exit 1
+          else
+            case $prefix in
+              *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+              *) qprefix=$prefix;;
+            esac
+            prefixes="$prefixes '$qprefix'"
+          fi
+        fi
+        prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+        # Don't fail if two instances are running concurrently.
+        (umask $mkdir_umask &&
+         eval "\$doit_exec \$mkdirprog $prefixes") ||
+          test -d "$dstdir" || exit 1
+        obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # If -C, don't bother to copy if it wouldn't change the file.
+    if $copy_on_change &&
+       old=`LC_ALL=C ls -dlL "$dst"     2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"  2>/dev/null` &&
+       set -f &&
+       set X $old && old=:$2:$4:$5:$6 &&
+       set X $new && new=:$2:$4:$5:$6 &&
+       set +f &&
+       test "$old" = "$new" &&
+       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+    then
+      rm -f "$dsttmp"
+    else
+      # Rename the file to the real destination.
+      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+      # The rename failed, perhaps because mv can't rename something else
+      # to itself, or perhaps because mv is so ancient that it does not
+      # support -f.
+      {
+        # Now remove or move aside any old file at destination location.
+        # We try this two ways since rm can't unlink itself on some
+        # systems and the destination file might be busy for other
+        # reasons.  In this case, the final cleanup might fail but the new
+        # file should still install successfully.
+        {
+          test ! -f "$dst" ||
+          $doit $rmcmd -f "$dst" 2>/dev/null ||
+          { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+            { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+          } ||
+          { echo "$0: cannot unlink or rename $dst" >&2
+            (exit 1); exit 1
+          }
+        } &&
+
+        # Now rename the file to the real destination.
+        $doit $mvcmd "$dsttmp" "$dst"
+      }
+    fi || exit 1
+
+    trap '' 0
+  fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/final/lib/External/isl/interface/all.h b/final/lib/External/isl/interface/all.h
new file mode 100644
index 0000000..ea0b498
--- /dev/null
+++ b/final/lib/External/isl/interface/all.h
@@ -0,0 +1,11 @@
+#include <isl/val.h>
+#include <isl/aff.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/ilp.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl/flow.h>
+#include <isl/schedule.h>
+#include <isl/schedule_node.h>
+#include <isl/ast_build.h>
diff --git a/final/lib/External/isl/interface/isl.h.top b/final/lib/External/isl/interface/isl.h.top
new file mode 100644
index 0000000..37749c2
--- /dev/null
+++ b/final/lib/External/isl/interface/isl.h.top
@@ -0,0 +1,95 @@
+/// These are automatically generated C++ bindings for isl.
+///
+/// isl is a library for computing with integer sets and maps described by
+/// Presburger formulas. On top of this, isl provides various tools for
+/// polyhedral compilation, ranging from dependence analysis over scheduling
+/// to AST generation.
+
+#ifndef ISL_CPP_NOEXCEPTIONS
+#define ISL_CPP_NOEXCEPTIONS
+
+#include <isl/aff.h>
+#include <isl/ast_build.h>
+#include <isl/flow.h>
+#include <isl/ilp.h>
+#include <isl/map.h>
+#include <isl/schedule.h>
+#include <isl/schedule_node.h>
+#include <isl/set.h>
+#include <isl/union_map.h>
+#include <isl/union_set.h>
+#include <isl/val.h>
+
+#include <functional>
+#include <string>
+
+namespace isl {
+inline namespace noexceptions {
+
+#define ISLPP_STRINGIZE_(X) #X
+#define ISLPP_STRINGIZE(X) ISLPP_STRINGIZE_(X)
+
+#define ISLPP_ASSERT(test, message)                          \
+  do {                                                       \
+    if (test)                                                \
+      break;                                                 \
+    fputs("Assertion \"" #test "\" failed at " __FILE__      \
+      ":" ISLPP_STRINGIZE(__LINE__) "\n  " message "\n",     \
+      stderr);                                               \
+  } while (0)
+
+class boolean {
+private:
+  isl_bool val;
+
+  friend isl::boolean manage(isl_bool val);
+  boolean(isl_bool val): val(val) {}
+public:
+  boolean()
+      : val(isl_bool_error) {}
+
+  /* implicit */ boolean(bool val)
+      : val(val ? isl_bool_true : isl_bool_false) {}
+
+  bool is_error() const { return val == isl_bool_error; }
+  bool is_false() const { return val == isl_bool_false; }
+  bool is_true() const { return val == isl_bool_true; }
+
+  explicit operator bool() const {
+    ISLPP_ASSERT(!is_error(), "IMPLEMENTATION ERROR: Unhandled error state");
+    return is_true();
+  }
+
+  boolean operator!() const {
+    if (is_error())
+      return *this;
+    return !is_true();
+  }
+};
+
+inline isl::boolean manage(isl_bool val) {
+  return isl::boolean(val);
+}
+
+class ctx {
+  isl_ctx *ptr;
+public:
+  /* implicit */ ctx(isl_ctx *ctx)
+      : ptr(ctx) {}
+  isl_ctx *release() {
+    auto tmp = ptr;
+    ptr = nullptr;
+    return tmp;
+  }
+  isl_ctx *get() {
+    return ptr;
+  }
+};
+
+enum class stat {
+  ok = isl_stat_ok,
+  error = isl_stat_error
+};
+
+}
+} // namespace isl
diff --git a/final/lib/External/isl/interface/isl.py.top b/final/lib/External/isl/interface/isl.py.top
new file mode 100644
index 0000000..71c2b0d
--- /dev/null
+++ b/final/lib/External/isl/interface/isl.py.top
@@ -0,0 +1,29 @@
+from ctypes import *
+
+isl = cdll.LoadLibrary("libisl.so")
+libc = cdll.LoadLibrary("libc.so.6")
+
+class Error(Exception):
+    pass
+
+class Context:
+    defaultInstance = None
+
+    def __init__(self):
+        ptr = isl.isl_ctx_alloc()
+        self.ptr = ptr
+
+    def __del__(self):
+        isl.isl_ctx_free(self)
+
+    def from_param(self):
+        return c_void_p(self.ptr)
+
+    @staticmethod
+    def getDefaultInstance():
+        if Context.defaultInstance == None:
+            Context.defaultInstance = Context()
+        return Context.defaultInstance
+
+isl.isl_ctx_alloc.restype = c_void_p
+isl.isl_ctx_free.argtypes = [Context]
diff --git a/final/lib/External/isl/isl.py b/final/lib/External/isl/isl.py
new file mode 100644
index 0000000..6382f63
--- /dev/null
+++ b/final/lib/External/isl/isl.py
@@ -0,0 +1,100 @@
+import gdb
+import re
+
+# GDB Pretty Printers for most isl objects
+class IslObjectPrinter:
+	"""Print an isl object"""
+	def __init__ (self, val, type):
+                self.val = val
+                self.type = type
+
+	def to_string (self):
+                # Cast val to a void pointer to stop gdb using this pretty
+                # printer for the pointer which would lead to an infinite loop.
+                void_ptr = gdb.lookup_type('void').pointer()
+                value = str(self.val.cast(void_ptr))
+                printer = gdb.parse_and_eval("isl_printer_to_str(isl_"
+                                             + str(self.type)
+					     + "_get_ctx(" + value + "))")
+                printer = gdb.parse_and_eval("isl_printer_print_"
+                                             + str(self.type) + "("
+                                             + str(printer) + ", "
+                                             + value + ")")
+                string = gdb.parse_and_eval("(char*)isl_printer_get_str("
+                                            + str(printer) + ")")
+                gdb.parse_and_eval("isl_printer_free(" + str(printer) + ")")
+                return string
+
+	def display_hint (self):
+                return 'string'
+
+class IslIntPrinter:
+	"""Print an isl_int """
+	def __init__ (self, val):
+                self.val = val
+
+	def to_string (self):
+                # Cast val to a void pointer to stop gdb using this pretty
+                # printer for the pointer which would lead to an infinite loop.
+                void_ptr = gdb.lookup_type('void').pointer()
+                value = str(self.val.cast(void_ptr))
+
+                context = gdb.parse_and_eval("isl_ctx_alloc()")
+                printer = gdb.parse_and_eval("isl_printer_to_str("
+                                             + str(context) + ")")
+                printer = gdb.parse_and_eval("isl_printer_print_isl_int("
+                                             + str(printer) + ", "
+                                             + value + ")")
+                string = gdb.parse_and_eval("(char*)isl_printer_get_str("
+                                            + str(printer) + ")")
+                gdb.parse_and_eval("isl_printer_free(" + str(printer) + ")")
+                gdb.parse_and_eval("isl_ctx_free(" + str(context) + ")")
+                return string
+
+	def display_hint (self):
+                return 'string'
+
+class IslPrintCommand (gdb.Command):
+        """Print an isl value."""
+        def __init__ (self):
+                super (IslPrintCommand, self).__init__ ("islprint",
+                                                        gdb.COMMAND_OBSCURE)
+        def invoke (self, arg, from_tty):
+                arg = gdb.parse_and_eval(arg);
+                printer = str_lookup_function(arg)
+
+                if printer == None:
+                        print "No isl printer for this type"
+                        return
+
+                print printer.to_string()
+
+IslPrintCommand()
+
+def str_lookup_function (val):
+	if val.type.code != gdb.TYPE_CODE_PTR:
+		if str(val.type) == "isl_int":
+			return IslIntPrinter(val)
+                else:
+                        return None
+
+	lookup_tag = val.type.target()
+	regex = re.compile ("^isl_(.*)$")
+
+	if lookup_tag == None:
+		return None
+
+	m = regex.match (str(lookup_tag))
+
+	if m:
+                # Those types of printers defined in isl.
+                if m.group(1) in ["basic_set", "set", "union_set", "basic_map",
+                                  "map", "union_map", "qpolynomial",
+                                  "pw_qpolynomial", "pw_qpolynomial_fold",
+                                  "union_pw_qpolynomial",
+                                  "union_pw_qpolynomial_fold"]:
+                        return IslObjectPrinter(val, m.group(1))
+        return None
+
+# Do not register the pretty printer.
+# gdb.current_objfile().pretty_printers.append(str_lookup_function)
diff --git a/final/lib/External/isl/isl_aff.c b/final/lib/External/isl/isl_aff.c
new file mode 100644
index 0000000..8b3f82b
--- /dev/null
+++ b/final/lib/External/isl/isl_aff.c
@@ -0,0 +1,8962 @@
+/*
+ * Copyright 2011      INRIA Saclay
+ * Copyright 2011      Sven Verdoolaege
+ * Copyright 2012-2014 Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <isl_ctx_private.h>
+#define ISL_DIM_H
+#include <isl_map_private.h>
+#include <isl_union_map_private.h>
+#include <isl_aff_private.h>
+#include <isl_space_private.h>
+#include <isl_local_space_private.h>
+#include <isl_vec_private.h>
+#include <isl_mat_private.h>
+#include <isl/constraint.h>
+#include <isl_seq.h>
+#include <isl/set.h>
+#include <isl_val_private.h>
+#include <isl/deprecated/aff_int.h>
+#include <isl_config.h>
+
+#undef BASE
+#define BASE aff
+
+#include <isl_list_templ.c>
+
+#undef BASE
+#define BASE pw_aff
+
+#include <isl_list_templ.c>
+
+#undef BASE
+#define BASE union_pw_aff
+
+#include <isl_list_templ.c>
+
+#undef BASE
+#define BASE union_pw_multi_aff
+
+#include <isl_list_templ.c>
+
+__isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls,
+	__isl_take isl_vec *v)
+{
+	isl_aff *aff;
+
+	if (!ls || !v)
+		goto error;
+
+	aff = isl_calloc_type(v->ctx, struct isl_aff);
+	if (!aff)
+		goto error;
+
+	aff->ref = 1;
+	aff->ls = ls;
+	aff->v = v;
+
+	return aff;
+error:
+	isl_local_space_free(ls);
+	isl_vec_free(v);
+	return NULL;
+}
+
+__isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls)
+{
+	isl_ctx *ctx;
+	isl_vec *v;
+	unsigned total;
+
+	if (!ls)
+		return NULL;
+
+	ctx = isl_local_space_get_ctx(ls);
+	if (!isl_local_space_divs_known(ls))
+		isl_die(ctx, isl_error_invalid, "local space has unknown divs",
+			goto error);
+	if (!isl_local_space_is_set(ls))
+		isl_die(ctx, isl_error_invalid,
+			"domain of affine expression should be a set",
+			goto error);
+
+	total = isl_local_space_dim(ls, isl_dim_all);
+	v = isl_vec_alloc(ctx, 1 + 1 + total);
+	return isl_aff_alloc_vec(ls, v);
+error:
+	isl_local_space_free(ls);
+	return NULL;
+}
+
+__isl_give isl_aff *isl_aff_zero_on_domain(__isl_take isl_local_space *ls)
+{
+	isl_aff *aff;
+
+	aff = isl_aff_alloc(ls);
+	if (!aff)
+		return NULL;
+
+	isl_int_set_si(aff->v->el[0], 1);
+	isl_seq_clr(aff->v->el + 1, aff->v->size - 1);
+
+	return aff;
+}
+
+/* Return a piecewise affine expression defined on the specified domain
+ * that is equal to zero.
+ */
+__isl_give isl_pw_aff *isl_pw_aff_zero_on_domain(__isl_take isl_local_space *ls)
+{
+	return isl_pw_aff_from_aff(isl_aff_zero_on_domain(ls));
+}
+
+/* Return an affine expression defined on the specified domain
+ * that represents NaN.
+ */
+__isl_give isl_aff *isl_aff_nan_on_domain(__isl_take isl_local_space *ls)
+{
+	isl_aff *aff;
+
+	aff = isl_aff_alloc(ls);
+	if (!aff)
+		return NULL;
+
+	isl_seq_clr(aff->v->el, aff->v->size);
+
+	return aff;
+}
+
+/* Return a piecewise affine expression defined on the specified domain
+ * that represents NaN.
+ */
+__isl_give isl_pw_aff *isl_pw_aff_nan_on_domain(__isl_take isl_local_space *ls)
+{
+	return isl_pw_aff_from_aff(isl_aff_nan_on_domain(ls));
+}
+
+/* Return an affine expression that is equal to "val" on
+ * domain local space "ls".
+ */
+__isl_give isl_aff *isl_aff_val_on_domain(__isl_take isl_local_space *ls,
+	__isl_take isl_val *val)
+{
+	isl_aff *aff;
+
+	if (!ls || !val)
+		goto error;
+	if (!isl_val_is_rat(val))
+		isl_die(isl_val_get_ctx(val), isl_error_invalid,
+			"expecting rational value", goto error);
+
+	aff = isl_aff_alloc(isl_local_space_copy(ls));
+	if (!aff)
+		goto error;
+
+	isl_seq_clr(aff->v->el + 2, aff->v->size - 2);
+	isl_int_set(aff->v->el[1], val->n);
+	isl_int_set(aff->v->el[0], val->d);
+
+	isl_local_space_free(ls);
+	isl_val_free(val);
+	return aff;
+error:
+	isl_local_space_free(ls);
+	isl_val_free(val);
+	return NULL;
+}
+
+/* Return an affine expression that is equal to the specified dimension
+ * in "ls".
+ */
+__isl_give isl_aff *isl_aff_var_on_domain(__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos)
+{
+	isl_space *space;
+	isl_aff *aff;
+
+	if (!ls)
+		return NULL;
+
+	space = isl_local_space_get_space(ls);
+	if (!space)
+		goto error;
+	if (isl_space_is_map(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"expecting (parameter) set space", goto error);
+	if (pos >= isl_local_space_dim(ls, type))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"position out of bounds", goto error);
+
+	isl_space_free(space);
+	aff = isl_aff_alloc(ls);
+	if (!aff)
+		return NULL;
+
+	pos += isl_local_space_offset(aff->ls, type);
+
+	isl_int_set_si(aff->v->el[0], 1);
+	isl_seq_clr(aff->v->el + 1, aff->v->size - 1);
+	isl_int_set_si(aff->v->el[1 + pos], 1);
+
+	return aff;
+error:
+	isl_local_space_free(ls);
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Return a piecewise affine expression that is equal to
+ * the specified dimension in "ls".
+ */
+__isl_give isl_pw_aff *isl_pw_aff_var_on_domain(__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_pw_aff_from_aff(isl_aff_var_on_domain(ls, type, pos));
+}
+
+__isl_give isl_aff *isl_aff_copy(__isl_keep isl_aff *aff)
+{
+	if (!aff)
+		return NULL;
+
+	aff->ref++;
+	return aff;
+}
+
+__isl_give isl_aff *isl_aff_dup(__isl_keep isl_aff *aff)
+{
+	if (!aff)
+		return NULL;
+
+	return isl_aff_alloc_vec(isl_local_space_copy(aff->ls),
+				 isl_vec_copy(aff->v));
+}
+
+__isl_give isl_aff *isl_aff_cow(__isl_take isl_aff *aff)
+{
+	if (!aff)
+		return NULL;
+
+	if (aff->ref == 1)
+		return aff;
+	aff->ref--;
+	return isl_aff_dup(aff);
+}
+
+__isl_null isl_aff *isl_aff_free(__isl_take isl_aff *aff)
+{
+	if (!aff)
+		return NULL;
+
+	if (--aff->ref > 0)
+		return NULL;
+
+	isl_local_space_free(aff->ls);
+	isl_vec_free(aff->v);
+
+	free(aff);
+
+	return NULL;
+}
+
+isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff)
+{
+	return aff ? isl_local_space_get_ctx(aff->ls) : NULL;
+}
+
+/* Return a hash value that digests "aff".
+ */
+uint32_t isl_aff_get_hash(__isl_keep isl_aff *aff)
+{
+	uint32_t hash, ls_hash, v_hash;
+
+	if (!aff)
+		return 0;
+
+	hash = isl_hash_init();
+	ls_hash = isl_local_space_get_hash(aff->ls);
+	isl_hash_hash(hash, ls_hash);
+	v_hash = isl_vec_get_hash(aff->v);
+	isl_hash_hash(hash, v_hash);
+
+	return hash;
+}
+
+/* Externally, an isl_aff has a map space, but internally, the
+ * ls field corresponds to the domain of that space.
+ */
+int isl_aff_dim(__isl_keep isl_aff *aff, enum isl_dim_type type)
+{
+	if (!aff)
+		return 0;
+	if (type == isl_dim_out)
+		return 1;
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	return isl_local_space_dim(aff->ls, type);
+}
+
+/* Return the position of the dimension of the given type and name
+ * in "aff".
+ * Return -1 if no such dimension can be found.
+ */
+int isl_aff_find_dim_by_name(__isl_keep isl_aff *aff, enum isl_dim_type type,
+	const char *name)
+{
+	if (!aff)
+		return -1;
+	if (type == isl_dim_out)
+		return -1;
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	return isl_local_space_find_dim_by_name(aff->ls, type, name);
+}
+
+__isl_give isl_space *isl_aff_get_domain_space(__isl_keep isl_aff *aff)
+{
+	return aff ? isl_local_space_get_space(aff->ls) : NULL;
+}
+
+__isl_give isl_space *isl_aff_get_space(__isl_keep isl_aff *aff)
+{
+	isl_space *space;
+	if (!aff)
+		return NULL;
+	space = isl_local_space_get_space(aff->ls);
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, 1);
+	return space;
+}
+
+__isl_give isl_local_space *isl_aff_get_domain_local_space(
+	__isl_keep isl_aff *aff)
+{
+	return aff ? isl_local_space_copy(aff->ls) : NULL;
+}
+
+__isl_give isl_local_space *isl_aff_get_local_space(__isl_keep isl_aff *aff)
+{
+	isl_local_space *ls;
+	if (!aff)
+		return NULL;
+	ls = isl_local_space_copy(aff->ls);
+	ls = isl_local_space_from_domain(ls);
+	ls = isl_local_space_add_dims(ls, isl_dim_out, 1);
+	return ls;
+}
+
+/* Externally, an isl_aff has a map space, but internally, the
+ * ls field corresponds to the domain of that space.
+ */
+const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!aff)
+		return NULL;
+	if (type == isl_dim_out)
+		return NULL;
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	return isl_local_space_get_dim_name(aff->ls, type, pos);
+}
+
+__isl_give isl_aff *isl_aff_reset_domain_space(__isl_take isl_aff *aff,
+	__isl_take isl_space *dim)
+{
+	aff = isl_aff_cow(aff);
+	if (!aff || !dim)
+		goto error;
+
+	aff->ls = isl_local_space_reset_space(aff->ls, dim);
+	if (!aff->ls)
+		return isl_aff_free(aff);
+
+	return aff;
+error:
+	isl_aff_free(aff);
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Reset the space of "aff".  This function is called from isl_pw_templ.c
+ * and doesn't know if the space of an element object is represented
+ * directly or through its domain.  It therefore passes along both.
+ */
+__isl_give isl_aff *isl_aff_reset_space_and_domain(__isl_take isl_aff *aff,
+	__isl_take isl_space *space, __isl_take isl_space *domain)
+{
+	isl_space_free(space);
+	return isl_aff_reset_domain_space(aff, domain);
+}
+
+/* Reorder the coefficients of the affine expression based
+ * on the given reordering.
+ * The reordering r is assumed to have been extended with the local
+ * variables.
+ */
+static __isl_give isl_vec *vec_reorder(__isl_take isl_vec *vec,
+	__isl_take isl_reordering *r, int n_div)
+{
+	isl_vec *res;
+	int i;
+
+	if (!vec || !r)
+		goto error;
+
+	res = isl_vec_alloc(vec->ctx,
+			    2 + isl_space_dim(r->dim, isl_dim_all) + n_div);
+	if (!res)
+		goto error;
+	isl_seq_cpy(res->el, vec->el, 2);
+	isl_seq_clr(res->el + 2, res->size - 2);
+	for (i = 0; i < r->len; ++i)
+		isl_int_set(res->el[2 + r->pos[i]], vec->el[2 + i]);
+
+	isl_reordering_free(r);
+	isl_vec_free(vec);
+	return res;
+error:
+	isl_vec_free(vec);
+	isl_reordering_free(r);
+	return NULL;
+}
+
+/* Reorder the dimensions of the domain of "aff" according
+ * to the given reordering.
+ */
+__isl_give isl_aff *isl_aff_realign_domain(__isl_take isl_aff *aff,
+	__isl_take isl_reordering *r)
+{
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		goto error;
+
+	r = isl_reordering_extend(r, aff->ls->div->n_row);
+	aff->v = vec_reorder(aff->v, isl_reordering_copy(r),
+				aff->ls->div->n_row);
+	aff->ls = isl_local_space_realign(aff->ls, r);
+
+	if (!aff->v || !aff->ls)
+		return isl_aff_free(aff);
+
+	return aff;
+error:
+	isl_aff_free(aff);
+	isl_reordering_free(r);
+	return NULL;
+}
+
+__isl_give isl_aff *isl_aff_align_params(__isl_take isl_aff *aff,
+	__isl_take isl_space *model)
+{
+	isl_bool equal_params;
+
+	if (!aff || !model)
+		goto error;
+
+	equal_params = isl_space_has_equal_params(aff->ls->dim, model);
+	if (equal_params < 0)
+		goto error;
+	if (!equal_params) {
+		isl_reordering *exp;
+
+		model = isl_space_drop_dims(model, isl_dim_in,
+					0, isl_space_dim(model, isl_dim_in));
+		model = isl_space_drop_dims(model, isl_dim_out,
+					0, isl_space_dim(model, isl_dim_out));
+		exp = isl_parameter_alignment_reordering(aff->ls->dim, model);
+		exp = isl_reordering_extend_space(exp,
+					isl_aff_get_domain_space(aff));
+		aff = isl_aff_realign_domain(aff, exp);
+	}
+
+	isl_space_free(model);
+	return aff;
+error:
+	isl_space_free(model);
+	isl_aff_free(aff);
+	return NULL;
+}
+
+/* Is "aff" obviously equal to zero?
+ *
+ * If the denominator is zero, then "aff" is not equal to zero.
+ */
+isl_bool isl_aff_plain_is_zero(__isl_keep isl_aff *aff)
+{
+	if (!aff)
+		return isl_bool_error;
+
+	if (isl_int_is_zero(aff->v->el[0]))
+		return isl_bool_false;
+	return isl_seq_first_non_zero(aff->v->el + 1, aff->v->size - 1) < 0;
+}
+
+/* Does "aff" represent NaN?
+ */
+isl_bool isl_aff_is_nan(__isl_keep isl_aff *aff)
+{
+	if (!aff)
+		return isl_bool_error;
+
+	return isl_seq_first_non_zero(aff->v->el, 2) < 0;
+}
+
+/* Are "aff1" and "aff2" obviously equal?
+ *
+ * NaN is not equal to anything, not even to another NaN.
+ */
+isl_bool isl_aff_plain_is_equal(__isl_keep isl_aff *aff1,
+	__isl_keep isl_aff *aff2)
+{
+	isl_bool equal;
+
+	if (!aff1 || !aff2)
+		return isl_bool_error;
+
+	if (isl_aff_is_nan(aff1) || isl_aff_is_nan(aff2))
+		return isl_bool_false;
+
+	equal = isl_local_space_is_equal(aff1->ls, aff2->ls);
+	if (equal < 0 || !equal)
+		return equal;
+
+	return isl_vec_is_equal(aff1->v, aff2->v);
+}
+
+/* Return the common denominator of "aff" in "v".
+ *
+ * We cannot return anything meaningful in case of a NaN.
+ */
+isl_stat isl_aff_get_denominator(__isl_keep isl_aff *aff, isl_int *v)
+{
+	if (!aff)
+		return isl_stat_error;
+	if (isl_aff_is_nan(aff))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"cannot get denominator of NaN", return isl_stat_error);
+	isl_int_set(*v, aff->v->el[0]);
+	return isl_stat_ok;
+}
+
+/* Return the common denominator of "aff".
+ */
+__isl_give isl_val *isl_aff_get_denominator_val(__isl_keep isl_aff *aff)
+{
+	isl_ctx *ctx;
+
+	if (!aff)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(aff);
+	if (isl_aff_is_nan(aff))
+		return isl_val_nan(ctx);
+	return isl_val_int_from_isl_int(ctx, aff->v->el[0]);
+}
+
+/* Return the constant term of "aff" in "v".
+ *
+ * We cannot return anything meaningful in case of a NaN.
+ */
+int isl_aff_get_constant(__isl_keep isl_aff *aff, isl_int *v)
+{
+	if (!aff)
+		return -1;
+	if (isl_aff_is_nan(aff))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"cannot get constant term of NaN", return -1);
+	isl_int_set(*v, aff->v->el[1]);
+	return 0;
+}
+
+/* Return the constant term of "aff".
+ */
+__isl_give isl_val *isl_aff_get_constant_val(__isl_keep isl_aff *aff)
+{
+	isl_ctx *ctx;
+	isl_val *v;
+
+	if (!aff)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(aff);
+	if (isl_aff_is_nan(aff))
+		return isl_val_nan(ctx);
+	v = isl_val_rat_from_isl_int(ctx, aff->v->el[1], aff->v->el[0]);
+	return isl_val_normalize(v);
+}
+
+/* Return the coefficient of the variable of type "type" at position "pos"
+ * of "aff" in "v".
+ *
+ * We cannot return anything meaningful in case of a NaN.
+ */
+int isl_aff_get_coefficient(__isl_keep isl_aff *aff,
+	enum isl_dim_type type, int pos, isl_int *v)
+{
+	if (!aff)
+		return -1;
+
+	if (type == isl_dim_out)
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"output/set dimension does not have a coefficient",
+			return -1);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	if (pos >= isl_local_space_dim(aff->ls, type))
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"position out of bounds", return -1);
+
+	if (isl_aff_is_nan(aff))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"cannot get coefficient of NaN", return -1);
+	pos += isl_local_space_offset(aff->ls, type);
+	isl_int_set(*v, aff->v->el[1 + pos]);
+
+	return 0;
+}
+
+/* Return the coefficient of the variable of type "type" at position "pos"
+ * of "aff".
+ */
+__isl_give isl_val *isl_aff_get_coefficient_val(__isl_keep isl_aff *aff,
+	enum isl_dim_type type, int pos)
+{
+	isl_ctx *ctx;
+	isl_val *v;
+
+	if (!aff)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(aff);
+	if (type == isl_dim_out)
+		isl_die(ctx, isl_error_invalid,
+			"output/set dimension does not have a coefficient",
+			return NULL);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	if (pos >= isl_local_space_dim(aff->ls, type))
+		isl_die(ctx, isl_error_invalid,
+			"position out of bounds", return NULL);
+
+	if (isl_aff_is_nan(aff))
+		return isl_val_nan(ctx);
+	pos += isl_local_space_offset(aff->ls, type);
+	v = isl_val_rat_from_isl_int(ctx, aff->v->el[1 + pos], aff->v->el[0]);
+	return isl_val_normalize(v);
+}
+
+/* Return the sign of the coefficient of the variable of type "type"
+ * at position "pos" of "aff".
+ */
+int isl_aff_coefficient_sgn(__isl_keep isl_aff *aff, enum isl_dim_type type,
+	int pos)
+{
+	isl_ctx *ctx;
+
+	if (!aff)
+		return 0;
+
+	ctx = isl_aff_get_ctx(aff);
+	if (type == isl_dim_out)
+		isl_die(ctx, isl_error_invalid,
+			"output/set dimension does not have a coefficient",
+			return 0);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	if (pos >= isl_local_space_dim(aff->ls, type))
+		isl_die(ctx, isl_error_invalid,
+			"position out of bounds", return 0);
+
+	pos += isl_local_space_offset(aff->ls, type);
+	return isl_int_sgn(aff->v->el[1 + pos]);
+}
+
+/* Replace the denominator of "aff" by "v".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_set_denominator(__isl_take isl_aff *aff, isl_int v)
+{
+	if (!aff)
+		return NULL;
+	if (isl_aff_is_nan(aff))
+		return aff;
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	isl_int_set(aff->v->el[0], v);
+
+	return aff;
+}
+
+/* Replace the numerator of the constant term of "aff" by "v".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_int v)
+{
+	if (!aff)
+		return NULL;
+	if (isl_aff_is_nan(aff))
+		return aff;
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	isl_int_set(aff->v->el[1], v);
+
+	return aff;
+}
+
+/* Replace the constant term of "aff" by "v".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_set_constant_val(__isl_take isl_aff *aff,
+	__isl_take isl_val *v)
+{
+	if (!aff || !v)
+		goto error;
+
+	if (isl_aff_is_nan(aff)) {
+		isl_val_free(v);
+		return aff;
+	}
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"expecting rational value", goto error);
+
+	if (isl_int_eq(aff->v->el[1], v->n) &&
+	    isl_int_eq(aff->v->el[0], v->d)) {
+		isl_val_free(v);
+		return aff;
+	}
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		goto error;
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		goto error;
+
+	if (isl_int_eq(aff->v->el[0], v->d)) {
+		isl_int_set(aff->v->el[1], v->n);
+	} else if (isl_int_is_one(v->d)) {
+		isl_int_mul(aff->v->el[1], aff->v->el[0], v->n);
+	} else {
+		isl_seq_scale(aff->v->el + 1,
+				aff->v->el + 1, v->d, aff->v->size - 1);
+		isl_int_mul(aff->v->el[1], aff->v->el[0], v->n);
+		isl_int_mul(aff->v->el[0], aff->v->el[0], v->d);
+		aff->v = isl_vec_normalize(aff->v);
+		if (!aff->v)
+			goto error;
+	}
+
+	isl_val_free(v);
+	return aff;
+error:
+	isl_aff_free(aff);
+	isl_val_free(v);
+	return NULL;
+}
+
+/* Add "v" to the constant term of "aff".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_add_constant(__isl_take isl_aff *aff, isl_int v)
+{
+	if (isl_int_is_zero(v))
+		return aff;
+
+	if (!aff)
+		return NULL;
+	if (isl_aff_is_nan(aff))
+		return aff;
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	isl_int_addmul(aff->v->el[1], aff->v->el[0], v);
+
+	return aff;
+}
+
+/* Add "v" to the constant term of "aff".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_add_constant_val(__isl_take isl_aff *aff,
+	__isl_take isl_val *v)
+{
+	if (!aff || !v)
+		goto error;
+
+	if (isl_aff_is_nan(aff) || isl_val_is_zero(v)) {
+		isl_val_free(v);
+		return aff;
+	}
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"expecting rational value", goto error);
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		goto error;
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		goto error;
+
+	if (isl_int_is_one(v->d)) {
+		isl_int_addmul(aff->v->el[1], aff->v->el[0], v->n);
+	} else if (isl_int_eq(aff->v->el[0], v->d)) {
+		isl_int_add(aff->v->el[1], aff->v->el[1], v->n);
+		aff->v = isl_vec_normalize(aff->v);
+		if (!aff->v)
+			goto error;
+	} else {
+		isl_seq_scale(aff->v->el + 1,
+				aff->v->el + 1, v->d, aff->v->size - 1);
+		isl_int_addmul(aff->v->el[1], aff->v->el[0], v->n);
+		isl_int_mul(aff->v->el[0], aff->v->el[0], v->d);
+		aff->v = isl_vec_normalize(aff->v);
+		if (!aff->v)
+			goto error;
+	}
+
+	isl_val_free(v);
+	return aff;
+error:
+	isl_aff_free(aff);
+	isl_val_free(v);
+	return NULL;
+}
+
+__isl_give isl_aff *isl_aff_add_constant_si(__isl_take isl_aff *aff, int v)
+{
+	isl_int t;
+
+	isl_int_init(t);
+	isl_int_set_si(t, v);
+	aff = isl_aff_add_constant(aff, t);
+	isl_int_clear(t);
+
+	return aff;
+}
+
+/* Add "v" to the numerator of the constant term of "aff".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_add_constant_num(__isl_take isl_aff *aff, isl_int v)
+{
+	if (isl_int_is_zero(v))
+		return aff;
+
+	if (!aff)
+		return NULL;
+	if (isl_aff_is_nan(aff))
+		return aff;
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	isl_int_add(aff->v->el[1], aff->v->el[1], v);
+
+	return aff;
+}
+
+/* Add "v" to the numerator of the constant term of "aff".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_add_constant_num_si(__isl_take isl_aff *aff, int v)
+{
+	isl_int t;
+
+	if (v == 0)
+		return aff;
+
+	isl_int_init(t);
+	isl_int_set_si(t, v);
+	aff = isl_aff_add_constant_num(aff, t);
+	isl_int_clear(t);
+
+	return aff;
+}
+
+/* Replace the numerator of the constant term of "aff" by "v".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_set_constant_si(__isl_take isl_aff *aff, int v)
+{
+	if (!aff)
+		return NULL;
+	if (isl_aff_is_nan(aff))
+		return aff;
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	isl_int_set_si(aff->v->el[1], v);
+
+	return aff;
+}
+
+/* Replace the numerator of the coefficient of the variable of type "type"
+ * at position "pos" of "aff" by "v".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_set_coefficient(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, isl_int v)
+{
+	if (!aff)
+		return NULL;
+
+	if (type == isl_dim_out)
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"output/set dimension does not have a coefficient",
+			return isl_aff_free(aff));
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	if (pos >= isl_local_space_dim(aff->ls, type))
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"position out of bounds", return isl_aff_free(aff));
+
+	if (isl_aff_is_nan(aff))
+		return aff;
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	pos += isl_local_space_offset(aff->ls, type);
+	isl_int_set(aff->v->el[1 + pos], v);
+
+	return aff;
+}
+
+/* Replace the numerator of the coefficient of the variable of type "type"
+ * at position "pos" of "aff" by "v".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_set_coefficient_si(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, int v)
+{
+	if (!aff)
+		return NULL;
+
+	if (type == isl_dim_out)
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"output/set dimension does not have a coefficient",
+			return isl_aff_free(aff));
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	if (pos < 0 || pos >= isl_local_space_dim(aff->ls, type))
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"position out of bounds", return isl_aff_free(aff));
+
+	if (isl_aff_is_nan(aff))
+		return aff;
+	pos += isl_local_space_offset(aff->ls, type);
+	if (isl_int_cmp_si(aff->v->el[1 + pos], v) == 0)
+		return aff;
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	isl_int_set_si(aff->v->el[1 + pos], v);
+
+	return aff;
+}
+
+/* Replace the coefficient of the variable of type "type" at position "pos"
+ * of "aff" by "v".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_set_coefficient_val(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, __isl_take isl_val *v)
+{
+	if (!aff || !v)
+		goto error;
+
+	if (type == isl_dim_out)
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"output/set dimension does not have a coefficient",
+			goto error);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	if (pos >= isl_local_space_dim(aff->ls, type))
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"position out of bounds", goto error);
+
+	if (isl_aff_is_nan(aff)) {
+		isl_val_free(v);
+		return aff;
+	}
+	if (!isl_val_is_rat(v))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"expecting rational value", goto error);
+
+	pos += isl_local_space_offset(aff->ls, type);
+	if (isl_int_eq(aff->v->el[1 + pos], v->n) &&
+	    isl_int_eq(aff->v->el[0], v->d)) {
+		isl_val_free(v);
+		return aff;
+	}
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		goto error;
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		goto error;
+
+	if (isl_int_eq(aff->v->el[0], v->d)) {
+		isl_int_set(aff->v->el[1 + pos], v->n);
+	} else if (isl_int_is_one(v->d)) {
+		isl_int_mul(aff->v->el[1 + pos], aff->v->el[0], v->n);
+	} else {
+		isl_seq_scale(aff->v->el + 1,
+				aff->v->el + 1, v->d, aff->v->size - 1);
+		isl_int_mul(aff->v->el[1 + pos], aff->v->el[0], v->n);
+		isl_int_mul(aff->v->el[0], aff->v->el[0], v->d);
+		aff->v = isl_vec_normalize(aff->v);
+		if (!aff->v)
+			goto error;
+	}
+
+	isl_val_free(v);
+	return aff;
+error:
+	isl_aff_free(aff);
+	isl_val_free(v);
+	return NULL;
+}
+
+/* Add "v" to the coefficient of the variable of type "type"
+ * at position "pos" of "aff".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_add_coefficient(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, isl_int v)
+{
+	if (!aff)
+		return NULL;
+
+	if (type == isl_dim_out)
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"output/set dimension does not have a coefficient",
+			return isl_aff_free(aff));
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	if (pos >= isl_local_space_dim(aff->ls, type))
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"position out of bounds", return isl_aff_free(aff));
+
+	if (isl_aff_is_nan(aff))
+		return aff;
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	pos += isl_local_space_offset(aff->ls, type);
+	isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v);
+
+	return aff;
+}
+
+/* Add "v" to the coefficient of the variable of type "type"
+ * at position "pos" of "aff".
+ *
+ * A NaN is unaffected by this operation.
+ */
+__isl_give isl_aff *isl_aff_add_coefficient_val(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, __isl_take isl_val *v)
+{
+	if (!aff || !v)
+		goto error;
+
+	if (isl_val_is_zero(v)) {
+		isl_val_free(v);
+		return aff;
+	}
+
+	if (type == isl_dim_out)
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"output/set dimension does not have a coefficient",
+			goto error);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	if (pos >= isl_local_space_dim(aff->ls, type))
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"position out of bounds", goto error);
+
+	if (isl_aff_is_nan(aff)) {
+		isl_val_free(v);
+		return aff;
+	}
+	if (!isl_val_is_rat(v))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"expecting rational value", goto error);
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		goto error;
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		goto error;
+
+	pos += isl_local_space_offset(aff->ls, type);
+	if (isl_int_is_one(v->d)) {
+		isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v->n);
+	} else if (isl_int_eq(aff->v->el[0], v->d)) {
+		isl_int_add(aff->v->el[1 + pos], aff->v->el[1 + pos], v->n);
+		aff->v = isl_vec_normalize(aff->v);
+		if (!aff->v)
+			goto error;
+	} else {
+		isl_seq_scale(aff->v->el + 1,
+				aff->v->el + 1, v->d, aff->v->size - 1);
+		isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v->n);
+		isl_int_mul(aff->v->el[0], aff->v->el[0], v->d);
+		aff->v = isl_vec_normalize(aff->v);
+		if (!aff->v)
+			goto error;
+	}
+
+	isl_val_free(v);
+	return aff;
+error:
+	isl_aff_free(aff);
+	isl_val_free(v);
+	return NULL;
+}
+
+__isl_give isl_aff *isl_aff_add_coefficient_si(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, int v)
+{
+	isl_int t;
+
+	isl_int_init(t);
+	isl_int_set_si(t, v);
+	aff = isl_aff_add_coefficient(aff, type, pos, t);
+	isl_int_clear(t);
+
+	return aff;
+}
+
+__isl_give isl_aff *isl_aff_get_div(__isl_keep isl_aff *aff, int pos)
+{
+	if (!aff)
+		return NULL;
+
+	return isl_local_space_get_div(aff->ls, pos);
+}
+
+/* Return the negation of "aff".
+ *
+ * As a special case, -NaN = NaN.
+ */
+__isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff)
+{
+	if (!aff)
+		return NULL;
+	if (isl_aff_is_nan(aff))
+		return aff;
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	isl_seq_neg(aff->v->el + 1, aff->v->el + 1, aff->v->size - 1);
+
+	return aff;
+}
+
+/* Remove divs from the local space that do not appear in the affine
+ * expression.
+ * We currently only remove divs at the end.
+ * Some intermediate divs may also not appear directly in the affine
+ * expression, but we would also need to check that no other divs are
+ * defined in terms of them.
+ */
+__isl_give isl_aff *isl_aff_remove_unused_divs(__isl_take isl_aff *aff)
+{
+	int pos;
+	int off;
+	int n;
+
+	if (!aff)
+		return NULL;
+
+	n = isl_local_space_dim(aff->ls, isl_dim_div);
+	off = isl_local_space_offset(aff->ls, isl_dim_div);
+
+	pos = isl_seq_last_non_zero(aff->v->el + 1 + off, n) + 1;
+	if (pos == n)
+		return aff;
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->ls = isl_local_space_drop_dims(aff->ls, isl_dim_div, pos, n - pos);
+	aff->v = isl_vec_drop_els(aff->v, 1 + off + pos, n - pos);
+	if (!aff->ls || !aff->v)
+		return isl_aff_free(aff);
+
+	return aff;
+}
+
+/* Look for any divs in the aff->ls with a denominator equal to one
+ * and plug them into the affine expression and any subsequent divs
+ * that may reference the div.
+ */
+static __isl_give isl_aff *plug_in_integral_divs(__isl_take isl_aff *aff)
+{
+	int i, n;
+	int len;
+	isl_int v;
+	isl_vec *vec;
+	isl_local_space *ls;
+	unsigned pos;
+
+	if (!aff)
+		return NULL;
+
+	n = isl_local_space_dim(aff->ls, isl_dim_div);
+	len = aff->v->size;
+	for (i = 0; i < n; ++i) {
+		if (!isl_int_is_one(aff->ls->div->row[i][0]))
+			continue;
+		ls = isl_local_space_copy(aff->ls);
+		ls = isl_local_space_substitute_seq(ls, isl_dim_div, i,
+				aff->ls->div->row[i], len, i + 1, n - (i + 1));
+		vec = isl_vec_copy(aff->v);
+		vec = isl_vec_cow(vec);
+		if (!ls || !vec)
+			goto error;
+
+		isl_int_init(v);
+
+		pos = isl_local_space_offset(aff->ls, isl_dim_div) + i;
+		isl_seq_substitute(vec->el, pos, aff->ls->div->row[i],
+					len, len, v);
+
+		isl_int_clear(v);
+
+		isl_vec_free(aff->v);
+		aff->v = vec;
+		isl_local_space_free(aff->ls);
+		aff->ls = ls;
+	}
+
+	return aff;
+error:
+	isl_vec_free(vec);
+	isl_local_space_free(ls);
+	return isl_aff_free(aff);
+}
+
+/* Look for any divs j that appear with a unit coefficient inside
+ * the definitions of other divs i and plug them into the definitions
+ * of the divs i.
+ *
+ * In particular, an expression of the form
+ *
+ *	floor((f(..) + floor(g(..)/n))/m)
+ *
+ * is simplified to
+ *
+ *	floor((n * f(..) + g(..))/(n * m))
+ *
+ * This simplification is correct because we can move the expression
+ * f(..) into the inner floor in the original expression to obtain
+ *
+ *	floor(floor((n * f(..) + g(..))/n)/m)
+ *
+ * from which we can derive the simplified expression.
+ */
+static __isl_give isl_aff *plug_in_unit_divs(__isl_take isl_aff *aff)
+{
+	int i, j, n;
+	int off;
+
+	if (!aff)
+		return NULL;
+
+	n = isl_local_space_dim(aff->ls, isl_dim_div);
+	off = isl_local_space_offset(aff->ls, isl_dim_div);
+	for (i = 1; i < n; ++i) {
+		for (j = 0; j < i; ++j) {
+			if (!isl_int_is_one(aff->ls->div->row[i][1 + off + j]))
+				continue;
+			aff->ls = isl_local_space_substitute_seq(aff->ls,
+				isl_dim_div, j, aff->ls->div->row[j],
+				aff->v->size, i, 1);
+			if (!aff->ls)
+				return isl_aff_free(aff);
+		}
+	}
+
+	return aff;
+}
+
+/* Swap divs "a" and "b" in "aff", which is assumed to be non-NULL.
+ *
+ * Even though this function is only called on isl_affs with a single
+ * reference, we are careful to only change aff->v and aff->ls together.
+ */
+static __isl_give isl_aff *swap_div(__isl_take isl_aff *aff, int a, int b)
+{
+	unsigned off = isl_local_space_offset(aff->ls, isl_dim_div);
+	isl_local_space *ls;
+	isl_vec *v;
+
+	ls = isl_local_space_copy(aff->ls);
+	ls = isl_local_space_swap_div(ls, a, b);
+	v = isl_vec_copy(aff->v);
+	v = isl_vec_cow(v);
+	if (!ls || !v)
+		goto error;
+
+	isl_int_swap(v->el[1 + off + a], v->el[1 + off + b]);
+	isl_vec_free(aff->v);
+	aff->v = v;
+	isl_local_space_free(aff->ls);
+	aff->ls = ls;
+
+	return aff;
+error:
+	isl_vec_free(v);
+	isl_local_space_free(ls);
+	return isl_aff_free(aff);
+}
+
+/* Merge divs "a" and "b" in "aff", which is assumed to be non-NULL.
+ *
+ * We currently do not actually remove div "b", but simply add its
+ * coefficient to that of "a" and then zero it out.
+ */
+static __isl_give isl_aff *merge_divs(__isl_take isl_aff *aff, int a, int b)
+{
+	unsigned off = isl_local_space_offset(aff->ls, isl_dim_div);
+
+	if (isl_int_is_zero(aff->v->el[1 + off + b]))
+		return aff;
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	isl_int_add(aff->v->el[1 + off + a],
+		    aff->v->el[1 + off + a], aff->v->el[1 + off + b]);
+	isl_int_set_si(aff->v->el[1 + off + b], 0);
+
+	return aff;
+}
+
+/* Sort the divs in the local space of "aff" according to
+ * the comparison function "cmp_row" in isl_local_space.c,
+ * combining the coefficients of identical divs.
+ *
+ * Reordering divs does not change the semantics of "aff",
+ * so there is no need to call isl_aff_cow.
+ * Moreover, this function is currently only called on isl_affs
+ * with a single reference.
+ */
+static __isl_give isl_aff *sort_divs(__isl_take isl_aff *aff)
+{
+	int i, j, n;
+
+	if (!aff)
+		return NULL;
+
+	n = isl_aff_dim(aff, isl_dim_div);
+	for (i = 1; i < n; ++i) {
+		for (j = i - 1; j >= 0; --j) {
+			int cmp = isl_mat_cmp_div(aff->ls->div, j, j + 1);
+			if (cmp < 0)
+				break;
+			if (cmp == 0)
+				aff = merge_divs(aff, j, j + 1);
+			else
+				aff = swap_div(aff, j, j + 1);
+			if (!aff)
+				return NULL;
+		}
+	}
+
+	return aff;
+}
+
+/* Normalize the representation of "aff".
+ *
+ * This function should only be called of "new" isl_affs, i.e.,
+ * with only a single reference.  We therefore do not need to
+ * worry about affecting other instances.
+ */
+__isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff)
+{
+	if (!aff)
+		return NULL;
+	aff->v = isl_vec_normalize(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+	aff = plug_in_integral_divs(aff);
+	aff = plug_in_unit_divs(aff);
+	aff = sort_divs(aff);
+	aff = isl_aff_remove_unused_divs(aff);
+	return aff;
+}
+
+/* Given f, return floor(f).
+ * If f is an integer expression, then just return f.
+ * If f is a constant, then return the constant floor(f).
+ * Otherwise, if f = g/m, write g = q m + r,
+ * create a new div d = [r/m] and return the expression q + d.
+ * The coefficients in r are taken to lie between -m/2 and m/2.
+ *
+ * reduce_div_coefficients performs the same normalization.
+ *
+ * As a special case, floor(NaN) = NaN.
+ */
+__isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff)
+{
+	int i;
+	int size;
+	isl_ctx *ctx;
+	isl_vec *div;
+
+	if (!aff)
+		return NULL;
+
+	if (isl_aff_is_nan(aff))
+		return aff;
+	if (isl_int_is_one(aff->v->el[0]))
+		return aff;
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	if (isl_aff_is_cst(aff)) {
+		isl_int_fdiv_q(aff->v->el[1], aff->v->el[1], aff->v->el[0]);
+		isl_int_set_si(aff->v->el[0], 1);
+		return aff;
+	}
+
+	div = isl_vec_copy(aff->v);
+	div = isl_vec_cow(div);
+	if (!div)
+		return isl_aff_free(aff);
+
+	ctx = isl_aff_get_ctx(aff);
+	isl_int_fdiv_q(aff->v->el[0], aff->v->el[0], ctx->two);
+	for (i = 1; i < aff->v->size; ++i) {
+		isl_int_fdiv_r(div->el[i], div->el[i], div->el[0]);
+		isl_int_fdiv_q(aff->v->el[i], aff->v->el[i], div->el[0]);
+		if (isl_int_gt(div->el[i], aff->v->el[0])) {
+			isl_int_sub(div->el[i], div->el[i], div->el[0]);
+			isl_int_add_ui(aff->v->el[i], aff->v->el[i], 1);
+		}
+	}
+
+	aff->ls = isl_local_space_add_div(aff->ls, div);
+	if (!aff->ls)
+		return isl_aff_free(aff);
+
+	size = aff->v->size;
+	aff->v = isl_vec_extend(aff->v, size + 1);
+	if (!aff->v)
+		return isl_aff_free(aff);
+	isl_int_set_si(aff->v->el[0], 1);
+	isl_int_set_si(aff->v->el[size], 1);
+
+	aff = isl_aff_normalize(aff);
+
+	return aff;
+}
+
+/* Compute
+ *
+ *	aff mod m = aff - m * floor(aff/m)
+ */
+__isl_give isl_aff *isl_aff_mod(__isl_take isl_aff *aff, isl_int m)
+{
+	isl_aff *res;
+
+	res = isl_aff_copy(aff);
+	aff = isl_aff_scale_down(aff, m);
+	aff = isl_aff_floor(aff);
+	aff = isl_aff_scale(aff, m);
+	res = isl_aff_sub(res, aff);
+
+	return res;
+}
+
+/* Compute
+ *
+ *	aff mod m = aff - m * floor(aff/m)
+ *
+ * with m an integer value.
+ */
+__isl_give isl_aff *isl_aff_mod_val(__isl_take isl_aff *aff,
+	__isl_take isl_val *m)
+{
+	isl_aff *res;
+
+	if (!aff || !m)
+		goto error;
+
+	if (!isl_val_is_int(m))
+		isl_die(isl_val_get_ctx(m), isl_error_invalid,
+			"expecting integer modulo", goto error);
+
+	res = isl_aff_copy(aff);
+	aff = isl_aff_scale_down_val(aff, isl_val_copy(m));
+	aff = isl_aff_floor(aff);
+	aff = isl_aff_scale_val(aff, m);
+	res = isl_aff_sub(res, aff);
+
+	return res;
+error:
+	isl_aff_free(aff);
+	isl_val_free(m);
+	return NULL;
+}
+
+/* Compute
+ *
+ *	pwaff mod m = pwaff - m * floor(pwaff/m)
+ */
+__isl_give isl_pw_aff *isl_pw_aff_mod(__isl_take isl_pw_aff *pwaff, isl_int m)
+{
+	isl_pw_aff *res;
+
+	res = isl_pw_aff_copy(pwaff);
+	pwaff = isl_pw_aff_scale_down(pwaff, m);
+	pwaff = isl_pw_aff_floor(pwaff);
+	pwaff = isl_pw_aff_scale(pwaff, m);
+	res = isl_pw_aff_sub(res, pwaff);
+
+	return res;
+}
+
+/* Compute
+ *
+ *	pa mod m = pa - m * floor(pa/m)
+ *
+ * with m an integer value.
+ */
+__isl_give isl_pw_aff *isl_pw_aff_mod_val(__isl_take isl_pw_aff *pa,
+	__isl_take isl_val *m)
+{
+	if (!pa || !m)
+		goto error;
+	if (!isl_val_is_int(m))
+		isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
+			"expecting integer modulo", goto error);
+	pa = isl_pw_aff_mod(pa, m->n);
+	isl_val_free(m);
+	return pa;
+error:
+	isl_pw_aff_free(pa);
+	isl_val_free(m);
+	return NULL;
+}
+
+/* Given f, return ceil(f).
+ * If f is an integer expression, then just return f.
+ * Otherwise, let f be the expression
+ *
+ *	e/m
+ *
+ * then return
+ *
+ *	floor((e + m - 1)/m)
+ *
+ * As a special case, ceil(NaN) = NaN.
+ */
+__isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff)
+{
+	if (!aff)
+		return NULL;
+
+	if (isl_aff_is_nan(aff))
+		return aff;
+	if (isl_int_is_one(aff->v->el[0]))
+		return aff;
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	isl_int_add(aff->v->el[1], aff->v->el[1], aff->v->el[0]);
+	isl_int_sub_ui(aff->v->el[1], aff->v->el[1], 1);
+	aff = isl_aff_floor(aff);
+
+	return aff;
+}
+
+/* Apply the expansion computed by isl_merge_divs.
+ * The expansion itself is given by "exp" while the resulting
+ * list of divs is given by "div".
+ */
+__isl_give isl_aff *isl_aff_expand_divs(__isl_take isl_aff *aff,
+	__isl_take isl_mat *div, int *exp)
+{
+	int old_n_div;
+	int new_n_div;
+	int offset;
+
+	aff = isl_aff_cow(aff);
+	if (!aff || !div)
+		goto error;
+
+	old_n_div = isl_local_space_dim(aff->ls, isl_dim_div);
+	new_n_div = isl_mat_rows(div);
+	offset = 1 + isl_local_space_offset(aff->ls, isl_dim_div);
+
+	aff->v = isl_vec_expand(aff->v, offset, old_n_div, exp, new_n_div);
+	aff->ls = isl_local_space_replace_divs(aff->ls, div);
+	if (!aff->v || !aff->ls)
+		return isl_aff_free(aff);
+	return aff;
+error:
+	isl_aff_free(aff);
+	isl_mat_free(div);
+	return NULL;
+}
+
+/* Add two affine expressions that live in the same local space.
+ */
+static __isl_give isl_aff *add_expanded(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	isl_int gcd, f;
+
+	aff1 = isl_aff_cow(aff1);
+	if (!aff1 || !aff2)
+		goto error;
+
+	aff1->v = isl_vec_cow(aff1->v);
+	if (!aff1->v)
+		goto error;
+
+	isl_int_init(gcd);
+	isl_int_init(f);
+	isl_int_gcd(gcd, aff1->v->el[0], aff2->v->el[0]);
+	isl_int_divexact(f, aff2->v->el[0], gcd);
+	isl_seq_scale(aff1->v->el + 1, aff1->v->el + 1, f, aff1->v->size - 1);
+	isl_int_divexact(f, aff1->v->el[0], gcd);
+	isl_seq_addmul(aff1->v->el + 1, f, aff2->v->el + 1, aff1->v->size - 1);
+	isl_int_divexact(f, aff2->v->el[0], gcd);
+	isl_int_mul(aff1->v->el[0], aff1->v->el[0], f);
+	isl_int_clear(f);
+	isl_int_clear(gcd);
+
+	isl_aff_free(aff2);
+	return aff1;
+error:
+	isl_aff_free(aff1);
+	isl_aff_free(aff2);
+	return NULL;
+}
+
+/* Return the sum of "aff1" and "aff2".
+ *
+ * If either of the two is NaN, then the result is NaN.
+ */
+__isl_give isl_aff *isl_aff_add(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	isl_ctx *ctx;
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_mat *div;
+	int n_div1, n_div2;
+
+	if (!aff1 || !aff2)
+		goto error;
+
+	ctx = isl_aff_get_ctx(aff1);
+	if (!isl_space_is_equal(aff1->ls->dim, aff2->ls->dim))
+		isl_die(ctx, isl_error_invalid,
+			"spaces don't match", goto error);
+
+	if (isl_aff_is_nan(aff1)) {
+		isl_aff_free(aff2);
+		return aff1;
+	}
+	if (isl_aff_is_nan(aff2)) {
+		isl_aff_free(aff1);
+		return aff2;
+	}
+
+	n_div1 = isl_aff_dim(aff1, isl_dim_div);
+	n_div2 = isl_aff_dim(aff2, isl_dim_div);
+	if (n_div1 == 0 && n_div2 == 0)
+		return add_expanded(aff1, aff2);
+
+	exp1 = isl_alloc_array(ctx, int, n_div1);
+	exp2 = isl_alloc_array(ctx, int, n_div2);
+	if ((n_div1 && !exp1) || (n_div2 && !exp2))
+		goto error;
+
+	div = isl_merge_divs(aff1->ls->div, aff2->ls->div, exp1, exp2);
+	aff1 = isl_aff_expand_divs(aff1, isl_mat_copy(div), exp1);
+	aff2 = isl_aff_expand_divs(aff2, div, exp2);
+	free(exp1);
+	free(exp2);
+
+	return add_expanded(aff1, aff2);
+error:
+	free(exp1);
+	free(exp2);
+	isl_aff_free(aff1);
+	isl_aff_free(aff2);
+	return NULL;
+}
+
+__isl_give isl_aff *isl_aff_sub(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	return isl_aff_add(aff1, isl_aff_neg(aff2));
+}
+
+/* Return the result of scaling "aff" by a factor of "f".
+ *
+ * As a special case, f * NaN = NaN.
+ */
+__isl_give isl_aff *isl_aff_scale(__isl_take isl_aff *aff, isl_int f)
+{
+	isl_int gcd;
+
+	if (!aff)
+		return NULL;
+	if (isl_aff_is_nan(aff))
+		return aff;
+
+	if (isl_int_is_one(f))
+		return aff;
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	if (isl_int_is_pos(f) && isl_int_is_divisible_by(aff->v->el[0], f)) {
+		isl_int_divexact(aff->v->el[0], aff->v->el[0], f);
+		return aff;
+	}
+
+	isl_int_init(gcd);
+	isl_int_gcd(gcd, aff->v->el[0], f);
+	isl_int_divexact(aff->v->el[0], aff->v->el[0], gcd);
+	isl_int_divexact(gcd, f, gcd);
+	isl_seq_scale(aff->v->el + 1, aff->v->el + 1, gcd, aff->v->size - 1);
+	isl_int_clear(gcd);
+
+	return aff;
+}
+
+/* Multiple "aff" by "v".
+ */
+__isl_give isl_aff *isl_aff_scale_val(__isl_take isl_aff *aff,
+	__isl_take isl_val *v)
+{
+	if (!aff || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return aff;
+	}
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"expecting rational factor", goto error);
+
+	aff = isl_aff_scale(aff, v->n);
+	aff = isl_aff_scale_down(aff, v->d);
+
+	isl_val_free(v);
+	return aff;
+error:
+	isl_aff_free(aff);
+	isl_val_free(v);
+	return NULL;
+}
+
+/* Return the result of scaling "aff" down by a factor of "f".
+ *
+ * As a special case, NaN/f = NaN.
+ */
+__isl_give isl_aff *isl_aff_scale_down(__isl_take isl_aff *aff, isl_int f)
+{
+	isl_int gcd;
+
+	if (!aff)
+		return NULL;
+	if (isl_aff_is_nan(aff))
+		return aff;
+
+	if (isl_int_is_one(f))
+		return aff;
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	if (isl_int_is_zero(f))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"cannot scale down by zero", return isl_aff_free(aff));
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	isl_int_init(gcd);
+	isl_seq_gcd(aff->v->el + 1, aff->v->size - 1, &gcd);
+	isl_int_gcd(gcd, gcd, f);
+	isl_seq_scale_down(aff->v->el + 1, aff->v->el + 1, gcd, aff->v->size - 1);
+	isl_int_divexact(gcd, f, gcd);
+	isl_int_mul(aff->v->el[0], aff->v->el[0], gcd);
+	isl_int_clear(gcd);
+
+	return aff;
+}
+
+/* Divide "aff" by "v".
+ */
+__isl_give isl_aff *isl_aff_scale_down_val(__isl_take isl_aff *aff,
+	__isl_take isl_val *v)
+{
+	if (!aff || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return aff;
+	}
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"expecting rational factor", goto error);
+	if (!isl_val_is_pos(v))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"factor needs to be positive", goto error);
+
+	aff = isl_aff_scale(aff, v->d);
+	aff = isl_aff_scale_down(aff, v->n);
+
+	isl_val_free(v);
+	return aff;
+error:
+	isl_aff_free(aff);
+	isl_val_free(v);
+	return NULL;
+}
+
+__isl_give isl_aff *isl_aff_scale_down_ui(__isl_take isl_aff *aff, unsigned f)
+{
+	isl_int v;
+
+	if (f == 1)
+		return aff;
+
+	isl_int_init(v);
+	isl_int_set_ui(v, f);
+	aff = isl_aff_scale_down(aff, v);
+	isl_int_clear(v);
+
+	return aff;
+}
+
+__isl_give isl_aff *isl_aff_set_dim_name(__isl_take isl_aff *aff,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+	if (type == isl_dim_out)
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"cannot set name of output/set dimension",
+			return isl_aff_free(aff));
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	aff->ls = isl_local_space_set_dim_name(aff->ls, type, pos, s);
+	if (!aff->ls)
+		return isl_aff_free(aff);
+
+	return aff;
+}
+
+__isl_give isl_aff *isl_aff_set_dim_id(__isl_take isl_aff *aff,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		goto error;
+	if (type == isl_dim_out)
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"cannot set name of output/set dimension",
+			goto error);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	aff->ls = isl_local_space_set_dim_id(aff->ls, type, pos, id);
+	if (!aff->ls)
+		return isl_aff_free(aff);
+
+	return aff;
+error:
+	isl_id_free(id);
+	isl_aff_free(aff);
+	return NULL;
+}
+
+/* Replace the identifier of the input tuple of "aff" by "id".
+ * type is currently required to be equal to isl_dim_in
+ */
+__isl_give isl_aff *isl_aff_set_tuple_id(__isl_take isl_aff *aff,
+	enum isl_dim_type type, __isl_take isl_id *id)
+{
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		goto error;
+	if (type != isl_dim_out)
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"cannot only set id of input tuple", goto error);
+	aff->ls = isl_local_space_set_tuple_id(aff->ls, isl_dim_set, id);
+	if (!aff->ls)
+		return isl_aff_free(aff);
+
+	return aff;
+error:
+	isl_id_free(id);
+	isl_aff_free(aff);
+	return NULL;
+}
+
+/* Exploit the equalities in "eq" to simplify the affine expression
+ * and the expressions of the integer divisions in the local space.
+ * The integer divisions in this local space are assumed to appear
+ * as regular dimensions in "eq".
+ */
+static __isl_give isl_aff *isl_aff_substitute_equalities_lifted(
+	__isl_take isl_aff *aff, __isl_take isl_basic_set *eq)
+{
+	int i, j;
+	unsigned total;
+	unsigned n_div;
+
+	if (!eq)
+		goto error;
+	if (eq->n_eq == 0) {
+		isl_basic_set_free(eq);
+		return aff;
+	}
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		goto error;
+
+	aff->ls = isl_local_space_substitute_equalities(aff->ls,
+							isl_basic_set_copy(eq));
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->ls || !aff->v)
+		goto error;
+
+	total = 1 + isl_space_dim(eq->dim, isl_dim_all);
+	n_div = eq->n_div;
+	for (i = 0; i < eq->n_eq; ++i) {
+		j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
+		if (j < 0 || j == 0 || j >= total)
+			continue;
+
+		isl_seq_elim(aff->v->el + 1, eq->eq[i], j, total,
+				&aff->v->el[0]);
+	}
+
+	isl_basic_set_free(eq);
+	aff = isl_aff_normalize(aff);
+	return aff;
+error:
+	isl_basic_set_free(eq);
+	isl_aff_free(aff);
+	return NULL;
+}
+
+/* Exploit the equalities in "eq" to simplify the affine expression
+ * and the expressions of the integer divisions in the local space.
+ */
+__isl_give isl_aff *isl_aff_substitute_equalities(__isl_take isl_aff *aff,
+	__isl_take isl_basic_set *eq)
+{
+	int n_div;
+
+	if (!aff || !eq)
+		goto error;
+	n_div = isl_local_space_dim(aff->ls, isl_dim_div);
+	if (n_div > 0)
+		eq = isl_basic_set_add_dims(eq, isl_dim_set, n_div);
+	return isl_aff_substitute_equalities_lifted(aff, eq);
+error:
+	isl_basic_set_free(eq);
+	isl_aff_free(aff);
+	return NULL;
+}
+
+/* Look for equalities among the variables shared by context and aff
+ * and the integer divisions of aff, if any.
+ * The equalities are then used to eliminate coefficients and/or integer
+ * divisions from aff.
+ */
+__isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff,
+	__isl_take isl_set *context)
+{
+	isl_basic_set *hull;
+	int n_div;
+
+	if (!aff)
+		goto error;
+	n_div = isl_local_space_dim(aff->ls, isl_dim_div);
+	if (n_div > 0) {
+		isl_basic_set *bset;
+		isl_local_space *ls;
+		context = isl_set_add_dims(context, isl_dim_set, n_div);
+		ls = isl_aff_get_domain_local_space(aff);
+		bset = isl_basic_set_from_local_space(ls);
+		bset = isl_basic_set_lift(bset);
+		bset = isl_basic_set_flatten(bset);
+		context = isl_set_intersect(context,
+					    isl_set_from_basic_set(bset));
+	}
+
+	hull = isl_set_affine_hull(context);
+	return isl_aff_substitute_equalities_lifted(aff, hull);
+error:
+	isl_aff_free(aff);
+	isl_set_free(context);
+	return NULL;
+}
+
+__isl_give isl_aff *isl_aff_gist_params(__isl_take isl_aff *aff,
+	__isl_take isl_set *context)
+{
+	isl_set *dom_context = isl_set_universe(isl_aff_get_domain_space(aff));
+	dom_context = isl_set_intersect_params(dom_context, context);
+	return isl_aff_gist(aff, dom_context);
+}
+
+/* Return a basic set containing those elements in the space
+ * of aff where it is positive.  "rational" should not be set.
+ *
+ * If "aff" is NaN, then it is not positive.
+ */
+static __isl_give isl_basic_set *aff_pos_basic_set(__isl_take isl_aff *aff,
+	int rational)
+{
+	isl_constraint *ineq;
+	isl_basic_set *bset;
+	isl_val *c;
+
+	if (!aff)
+		return NULL;
+	if (isl_aff_is_nan(aff)) {
+		isl_space *space = isl_aff_get_domain_space(aff);
+		isl_aff_free(aff);
+		return isl_basic_set_empty(space);
+	}
+	if (rational)
+		isl_die(isl_aff_get_ctx(aff), isl_error_unsupported,
+			"rational sets not supported", goto error);
+
+	ineq = isl_inequality_from_aff(aff);
+	c = isl_constraint_get_constant_val(ineq);
+	c = isl_val_sub_ui(c, 1);
+	ineq = isl_constraint_set_constant_val(ineq, c);
+
+	bset = isl_basic_set_from_constraint(ineq);
+	bset = isl_basic_set_simplify(bset);
+	return bset;
+error:
+	isl_aff_free(aff);
+	return NULL;
+}
+
+/* Return a basic set containing those elements in the space
+ * of aff where it is non-negative.
+ * If "rational" is set, then return a rational basic set.
+ *
+ * If "aff" is NaN, then it is not non-negative (it's not negative either).
+ */
+static __isl_give isl_basic_set *aff_nonneg_basic_set(
+	__isl_take isl_aff *aff, int rational)
+{
+	isl_constraint *ineq;
+	isl_basic_set *bset;
+
+	if (!aff)
+		return NULL;
+	if (isl_aff_is_nan(aff)) {
+		isl_space *space = isl_aff_get_domain_space(aff);
+		isl_aff_free(aff);
+		return isl_basic_set_empty(space);
+	}
+
+	ineq = isl_inequality_from_aff(aff);
+
+	bset = isl_basic_set_from_constraint(ineq);
+	if (rational)
+		bset = isl_basic_set_set_rational(bset);
+	bset = isl_basic_set_simplify(bset);
+	return bset;
+}
+
+/* Return a basic set containing those elements in the space
+ * of aff where it is non-negative.
+ */
+__isl_give isl_basic_set *isl_aff_nonneg_basic_set(__isl_take isl_aff *aff)
+{
+	return aff_nonneg_basic_set(aff, 0);
+}
+
+/* Return a basic set containing those elements in the domain space
+ * of "aff" where it is positive.
+ */
+__isl_give isl_basic_set *isl_aff_pos_basic_set(__isl_take isl_aff *aff)
+{
+	aff = isl_aff_add_constant_num_si(aff, -1);
+	return isl_aff_nonneg_basic_set(aff);
+}
+
+/* Return a basic set containing those elements in the domain space
+ * of aff where it is negative.
+ */
+__isl_give isl_basic_set *isl_aff_neg_basic_set(__isl_take isl_aff *aff)
+{
+	aff = isl_aff_neg(aff);
+	return isl_aff_pos_basic_set(aff);
+}
+
+/* Return a basic set containing those elements in the space
+ * of aff where it is zero.
+ * If "rational" is set, then return a rational basic set.
+ *
+ * If "aff" is NaN, then it is not zero.
+ */
+static __isl_give isl_basic_set *aff_zero_basic_set(__isl_take isl_aff *aff,
+	int rational)
+{
+	isl_constraint *ineq;
+	isl_basic_set *bset;
+
+	if (!aff)
+		return NULL;
+	if (isl_aff_is_nan(aff)) {
+		isl_space *space = isl_aff_get_domain_space(aff);
+		isl_aff_free(aff);
+		return isl_basic_set_empty(space);
+	}
+
+	ineq = isl_equality_from_aff(aff);
+
+	bset = isl_basic_set_from_constraint(ineq);
+	if (rational)
+		bset = isl_basic_set_set_rational(bset);
+	bset = isl_basic_set_simplify(bset);
+	return bset;
+}
+
+/* Return a basic set containing those elements in the space
+ * of aff where it is zero.
+ */
+__isl_give isl_basic_set *isl_aff_zero_basic_set(__isl_take isl_aff *aff)
+{
+	return aff_zero_basic_set(aff, 0);
+}
+
+/* Return a basic set containing those elements in the shared space
+ * of aff1 and aff2 where aff1 is greater than or equal to aff2.
+ */
+__isl_give isl_basic_set *isl_aff_ge_basic_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	aff1 = isl_aff_sub(aff1, aff2);
+
+	return isl_aff_nonneg_basic_set(aff1);
+}
+
+/* Return a basic set containing those elements in the shared domain space
+ * of "aff1" and "aff2" where "aff1" is greater than "aff2".
+ */
+__isl_give isl_basic_set *isl_aff_gt_basic_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	aff1 = isl_aff_sub(aff1, aff2);
+
+	return isl_aff_pos_basic_set(aff1);
+}
+
+/* Return a set containing those elements in the shared space
+ * of aff1 and aff2 where aff1 is greater than or equal to aff2.
+ */
+__isl_give isl_set *isl_aff_ge_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	return isl_set_from_basic_set(isl_aff_ge_basic_set(aff1, aff2));
+}
+
+/* Return a set containing those elements in the shared domain space
+ * of aff1 and aff2 where aff1 is greater than aff2.
+ *
+ * If either of the two inputs is NaN, then the result is empty,
+ * as comparisons with NaN always return false.
+ */
+__isl_give isl_set *isl_aff_gt_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	return isl_set_from_basic_set(isl_aff_gt_basic_set(aff1, aff2));
+}
+
+/* Return a basic set containing those elements in the shared space
+ * of aff1 and aff2 where aff1 is smaller than or equal to aff2.
+ */
+__isl_give isl_basic_set *isl_aff_le_basic_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	return isl_aff_ge_basic_set(aff2, aff1);
+}
+
+/* Return a basic set containing those elements in the shared domain space
+ * of "aff1" and "aff2" where "aff1" is smaller than "aff2".
+ */
+__isl_give isl_basic_set *isl_aff_lt_basic_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	return isl_aff_gt_basic_set(aff2, aff1);
+}
+
+/* Return a set containing those elements in the shared space
+ * of aff1 and aff2 where aff1 is smaller than or equal to aff2.
+ */
+__isl_give isl_set *isl_aff_le_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	return isl_aff_ge_set(aff2, aff1);
+}
+
+/* Return a set containing those elements in the shared domain space
+ * of "aff1" and "aff2" where "aff1" is smaller than "aff2".
+ */
+__isl_give isl_set *isl_aff_lt_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	return isl_set_from_basic_set(isl_aff_lt_basic_set(aff1, aff2));
+}
+
+/* Return a basic set containing those elements in the shared space
+ * of aff1 and aff2 where aff1 and aff2 are equal.
+ */
+__isl_give isl_basic_set *isl_aff_eq_basic_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	aff1 = isl_aff_sub(aff1, aff2);
+
+	return isl_aff_zero_basic_set(aff1);
+}
+
+/* Return a set containing those elements in the shared space
+ * of aff1 and aff2 where aff1 and aff2 are equal.
+ */
+__isl_give isl_set *isl_aff_eq_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	return isl_set_from_basic_set(isl_aff_eq_basic_set(aff1, aff2));
+}
+
+/* Return a set containing those elements in the shared domain space
+ * of aff1 and aff2 where aff1 and aff2 are not equal.
+ *
+ * If either of the two inputs is NaN, then the result is empty,
+ * as comparisons with NaN always return false.
+ */
+__isl_give isl_set *isl_aff_ne_set(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	isl_set *set_lt, *set_gt;
+
+	set_lt = isl_aff_lt_set(isl_aff_copy(aff1),
+				isl_aff_copy(aff2));
+	set_gt = isl_aff_gt_set(aff1, aff2);
+	return isl_set_union_disjoint(set_lt, set_gt);
+}
+
+__isl_give isl_aff *isl_aff_add_on_domain(__isl_keep isl_set *dom,
+	__isl_take isl_aff *aff1, __isl_take isl_aff *aff2)
+{
+	aff1 = isl_aff_add(aff1, aff2);
+	aff1 = isl_aff_gist(aff1, isl_set_copy(dom));
+	return aff1;
+}
+
+int isl_aff_is_empty(__isl_keep isl_aff *aff)
+{
+	if (!aff)
+		return -1;
+
+	return 0;
+}
+
+/* Check whether the given affine expression has non-zero coefficient
+ * for any dimension in the given range or if any of these dimensions
+ * appear with non-zero coefficients in any of the integer divisions
+ * involved in the affine expression.
+ */
+isl_bool isl_aff_involves_dims(__isl_keep isl_aff *aff,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	isl_ctx *ctx;
+	int *active = NULL;
+	isl_bool involves = isl_bool_false;
+
+	if (!aff)
+		return isl_bool_error;
+	if (n == 0)
+		return isl_bool_false;
+
+	ctx = isl_aff_get_ctx(aff);
+	if (first + n > isl_aff_dim(aff, type))
+		isl_die(ctx, isl_error_invalid,
+			"range out of bounds", return isl_bool_error);
+
+	active = isl_local_space_get_active(aff->ls, aff->v->el + 2);
+	if (!active)
+		goto error;
+
+	first += isl_local_space_offset(aff->ls, type) - 1;
+	for (i = 0; i < n; ++i)
+		if (active[first + i]) {
+			involves = isl_bool_true;
+			break;
+		}
+
+	free(active);
+
+	return involves;
+error:
+	free(active);
+	return isl_bool_error;
+}
+
+__isl_give isl_aff *isl_aff_drop_dims(__isl_take isl_aff *aff,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	isl_ctx *ctx;
+
+	if (!aff)
+		return NULL;
+	if (type == isl_dim_out)
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"cannot drop output/set dimension",
+			return isl_aff_free(aff));
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	if (n == 0 && !isl_local_space_is_named_or_nested(aff->ls, type))
+		return aff;
+
+	ctx = isl_aff_get_ctx(aff);
+	if (first + n > isl_local_space_dim(aff->ls, type))
+		isl_die(ctx, isl_error_invalid, "range out of bounds",
+			return isl_aff_free(aff));
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->ls = isl_local_space_drop_dims(aff->ls, type, first, n);
+	if (!aff->ls)
+		return isl_aff_free(aff);
+
+	first += 1 + isl_local_space_offset(aff->ls, type);
+	aff->v = isl_vec_drop_els(aff->v, first, n);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	return aff;
+}
+
+/* Project the domain of the affine expression onto its parameter space.
+ * The affine expression may not involve any of the domain dimensions.
+ */
+__isl_give isl_aff *isl_aff_project_domain_on_params(__isl_take isl_aff *aff)
+{
+	isl_space *space;
+	unsigned n;
+	int involves;
+
+	n = isl_aff_dim(aff, isl_dim_in);
+	involves = isl_aff_involves_dims(aff, isl_dim_in, 0, n);
+	if (involves < 0)
+		return isl_aff_free(aff);
+	if (involves)
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+		    "affine expression involves some of the domain dimensions",
+		    return isl_aff_free(aff));
+	aff = isl_aff_drop_dims(aff, isl_dim_in, 0, n);
+	space = isl_aff_get_domain_space(aff);
+	space = isl_space_params(space);
+	aff = isl_aff_reset_domain_space(aff, space);
+	return aff;
+}
+
+__isl_give isl_aff *isl_aff_insert_dims(__isl_take isl_aff *aff,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	isl_ctx *ctx;
+
+	if (!aff)
+		return NULL;
+	if (type == isl_dim_out)
+		isl_die(aff->v->ctx, isl_error_invalid,
+			"cannot insert output/set dimensions",
+			return isl_aff_free(aff));
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	if (n == 0 && !isl_local_space_is_named_or_nested(aff->ls, type))
+		return aff;
+
+	ctx = isl_aff_get_ctx(aff);
+	if (first > isl_local_space_dim(aff->ls, type))
+		isl_die(ctx, isl_error_invalid, "position out of bounds",
+			return isl_aff_free(aff));
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->ls = isl_local_space_insert_dims(aff->ls, type, first, n);
+	if (!aff->ls)
+		return isl_aff_free(aff);
+
+	first += 1 + isl_local_space_offset(aff->ls, type);
+	aff->v = isl_vec_insert_zero_els(aff->v, first, n);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	return aff;
+}
+
+__isl_give isl_aff *isl_aff_add_dims(__isl_take isl_aff *aff,
+	enum isl_dim_type type, unsigned n)
+{
+	unsigned pos;
+
+	pos = isl_aff_dim(aff, type);
+
+	return isl_aff_insert_dims(aff, type, pos, n);
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_add_dims(__isl_take isl_pw_aff *pwaff,
+	enum isl_dim_type type, unsigned n)
+{
+	unsigned pos;
+
+	pos = isl_pw_aff_dim(pwaff, type);
+
+	return isl_pw_aff_insert_dims(pwaff, type, pos, n);
+}
+
+/* Move the "n" dimensions of "src_type" starting at "src_pos" of "aff"
+ * to dimensions of "dst_type" at "dst_pos".
+ *
+ * We only support moving input dimensions to parameters and vice versa.
+ */
+__isl_give isl_aff *isl_aff_move_dims(__isl_take isl_aff *aff,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	unsigned g_dst_pos;
+	unsigned g_src_pos;
+
+	if (!aff)
+		return NULL;
+	if (n == 0 &&
+	    !isl_local_space_is_named_or_nested(aff->ls, src_type) &&
+	    !isl_local_space_is_named_or_nested(aff->ls, dst_type))
+		return aff;
+
+	if (dst_type == isl_dim_out || src_type == isl_dim_out)
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"cannot move output/set dimension",
+			return isl_aff_free(aff));
+	if (dst_type == isl_dim_div || src_type == isl_dim_div)
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"cannot move divs", return isl_aff_free(aff));
+	if (dst_type == isl_dim_in)
+		dst_type = isl_dim_set;
+	if (src_type == isl_dim_in)
+		src_type = isl_dim_set;
+
+	if (src_pos + n > isl_local_space_dim(aff->ls, src_type))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"range out of bounds", return isl_aff_free(aff));
+	if (dst_type == src_type)
+		isl_die(isl_aff_get_ctx(aff), isl_error_unsupported,
+			"moving dims within the same type not supported",
+			return isl_aff_free(aff));
+
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	g_src_pos = 1 + isl_local_space_offset(aff->ls, src_type) + src_pos;
+	g_dst_pos = 1 + isl_local_space_offset(aff->ls, dst_type) + dst_pos;
+	if (dst_type > src_type)
+		g_dst_pos -= n;
+
+	aff->v = isl_vec_move_els(aff->v, g_dst_pos, g_src_pos, n);
+	aff->ls = isl_local_space_move_dims(aff->ls, dst_type, dst_pos,
+						src_type, src_pos, n);
+	if (!aff->v || !aff->ls)
+		return isl_aff_free(aff);
+
+	aff = sort_divs(aff);
+
+	return aff;
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_from_aff(__isl_take isl_aff *aff)
+{
+	isl_set *dom = isl_set_universe(isl_aff_get_domain_space(aff));
+	return isl_pw_aff_alloc(dom, aff);
+}
+
+#define isl_aff_involves_nan isl_aff_is_nan
+
+#undef PW
+#define PW isl_pw_aff
+#undef EL
+#define EL isl_aff
+#undef EL_IS_ZERO
+#define EL_IS_ZERO is_empty
+#undef ZERO
+#define ZERO empty
+#undef IS_ZERO
+#define IS_ZERO is_empty
+#undef FIELD
+#define FIELD aff
+#undef DEFAULT_IS_ZERO
+#define DEFAULT_IS_ZERO 0
+
+#define NO_EVAL
+#define NO_OPT
+#define NO_LIFT
+#define NO_MORPH
+
+#include <isl_pw_templ.c>
+#include <isl_pw_hash.c>
+#include <isl_pw_union_opt.c>
+
+#undef UNION
+#define UNION isl_union_pw_aff
+#undef PART
+#define PART isl_pw_aff
+#undef PARTS
+#define PARTS pw_aff
+
+#include <isl_union_single.c>
+#include <isl_union_neg.c>
+
+static __isl_give isl_set *align_params_pw_pw_set_and(
+	__isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2,
+	__isl_give isl_set *(*fn)(__isl_take isl_pw_aff *pwaff1,
+				    __isl_take isl_pw_aff *pwaff2))
+{
+	isl_bool equal_params;
+
+	if (!pwaff1 || !pwaff2)
+		goto error;
+	equal_params = isl_space_has_equal_params(pwaff1->dim, pwaff2->dim);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params)
+		return fn(pwaff1, pwaff2);
+	if (!isl_space_has_named_params(pwaff1->dim) ||
+	    !isl_space_has_named_params(pwaff2->dim))
+		isl_die(isl_pw_aff_get_ctx(pwaff1), isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	pwaff1 = isl_pw_aff_align_params(pwaff1, isl_pw_aff_get_space(pwaff2));
+	pwaff2 = isl_pw_aff_align_params(pwaff2, isl_pw_aff_get_space(pwaff1));
+	return fn(pwaff1, pwaff2);
+error:
+	isl_pw_aff_free(pwaff1);
+	isl_pw_aff_free(pwaff2);
+	return NULL;
+}
+
+/* Align the parameters of the to isl_pw_aff arguments and
+ * then apply a function "fn" on them that returns an isl_map.
+ */
+static __isl_give isl_map *align_params_pw_pw_map_and(
+	__isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2,
+	__isl_give isl_map *(*fn)(__isl_take isl_pw_aff *pa1,
+				    __isl_take isl_pw_aff *pa2))
+{
+	isl_bool equal_params;
+
+	if (!pa1 || !pa2)
+		goto error;
+	equal_params = isl_space_has_equal_params(pa1->dim, pa2->dim);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params)
+		return fn(pa1, pa2);
+	if (!isl_space_has_named_params(pa1->dim) ||
+	    !isl_space_has_named_params(pa2->dim))
+		isl_die(isl_pw_aff_get_ctx(pa1), isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	pa1 = isl_pw_aff_align_params(pa1, isl_pw_aff_get_space(pa2));
+	pa2 = isl_pw_aff_align_params(pa2, isl_pw_aff_get_space(pa1));
+	return fn(pa1, pa2);
+error:
+	isl_pw_aff_free(pa1);
+	isl_pw_aff_free(pa2);
+	return NULL;
+}
+
+/* Compute a piecewise quasi-affine expression with a domain that
+ * is the union of those of pwaff1 and pwaff2 and such that on each
+ * cell, the quasi-affine expression is the maximum of those of pwaff1
+ * and pwaff2.  If only one of pwaff1 or pwaff2 is defined on a given
+ * cell, then the associated expression is the defined one.
+ */
+static __isl_give isl_pw_aff *pw_aff_union_max(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return isl_pw_aff_union_opt_cmp(pwaff1, pwaff2, &isl_aff_ge_set);
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_union_max(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2,
+							&pw_aff_union_max);
+}
+
+/* Compute a piecewise quasi-affine expression with a domain that
+ * is the union of those of pwaff1 and pwaff2 and such that on each
+ * cell, the quasi-affine expression is the minimum of those of pwaff1
+ * and pwaff2.  If only one of pwaff1 or pwaff2 is defined on a given
+ * cell, then the associated expression is the defined one.
+ */
+static __isl_give isl_pw_aff *pw_aff_union_min(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return isl_pw_aff_union_opt_cmp(pwaff1, pwaff2, &isl_aff_le_set);
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_union_min(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2,
+							&pw_aff_union_min);
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_union_opt(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2, int max)
+{
+	if (max)
+		return isl_pw_aff_union_max(pwaff1, pwaff2);
+	else
+		return isl_pw_aff_union_min(pwaff1, pwaff2);
+}
+
+/* Construct a map with as domain the domain of pwaff and
+ * one-dimensional range corresponding to the affine expressions.
+ */
+static __isl_give isl_map *map_from_pw_aff(__isl_take isl_pw_aff *pwaff)
+{
+	int i;
+	isl_space *dim;
+	isl_map *map;
+
+	if (!pwaff)
+		return NULL;
+
+	dim = isl_pw_aff_get_space(pwaff);
+	map = isl_map_empty(dim);
+
+	for (i = 0; i < pwaff->n; ++i) {
+		isl_basic_map *bmap;
+		isl_map *map_i;
+
+		bmap = isl_basic_map_from_aff(isl_aff_copy(pwaff->p[i].aff));
+		map_i = isl_map_from_basic_map(bmap);
+		map_i = isl_map_intersect_domain(map_i,
+						isl_set_copy(pwaff->p[i].set));
+		map = isl_map_union_disjoint(map, map_i);
+	}
+
+	isl_pw_aff_free(pwaff);
+
+	return map;
+}
+
+/* Construct a map with as domain the domain of pwaff and
+ * one-dimensional range corresponding to the affine expressions.
+ */
+__isl_give isl_map *isl_map_from_pw_aff(__isl_take isl_pw_aff *pwaff)
+{
+	if (!pwaff)
+		return NULL;
+	if (isl_space_is_set(pwaff->dim))
+		isl_die(isl_pw_aff_get_ctx(pwaff), isl_error_invalid,
+			"space of input is not a map", goto error);
+	return map_from_pw_aff(pwaff);
+error:
+	isl_pw_aff_free(pwaff);
+	return NULL;
+}
+
+/* Construct a one-dimensional set with as parameter domain
+ * the domain of pwaff and the single set dimension
+ * corresponding to the affine expressions.
+ */
+__isl_give isl_set *isl_set_from_pw_aff(__isl_take isl_pw_aff *pwaff)
+{
+	if (!pwaff)
+		return NULL;
+	if (!isl_space_is_set(pwaff->dim))
+		isl_die(isl_pw_aff_get_ctx(pwaff), isl_error_invalid,
+			"space of input is not a set", goto error);
+	return map_from_pw_aff(pwaff);
+error:
+	isl_pw_aff_free(pwaff);
+	return NULL;
+}
+
+/* Return a set containing those elements in the domain
+ * of "pwaff" where it satisfies "fn" (if complement is 0) or
+ * does not satisfy "fn" (if complement is 1).
+ *
+ * The pieces with a NaN never belong to the result since
+ * NaN does not satisfy any property.
+ */
+static __isl_give isl_set *pw_aff_locus(__isl_take isl_pw_aff *pwaff,
+	__isl_give isl_basic_set *(*fn)(__isl_take isl_aff *aff, int rational),
+	int complement)
+{
+	int i;
+	isl_set *set;
+
+	if (!pwaff)
+		return NULL;
+
+	set = isl_set_empty(isl_pw_aff_get_domain_space(pwaff));
+
+	for (i = 0; i < pwaff->n; ++i) {
+		isl_basic_set *bset;
+		isl_set *set_i, *locus;
+		isl_bool rational;
+
+		if (isl_aff_is_nan(pwaff->p[i].aff))
+			continue;
+
+		rational = isl_set_has_rational(pwaff->p[i].set);
+		bset = fn(isl_aff_copy(pwaff->p[i].aff), rational);
+		locus = isl_set_from_basic_set(bset);
+		set_i = isl_set_copy(pwaff->p[i].set);
+		if (complement)
+			set_i = isl_set_subtract(set_i, locus);
+		else
+			set_i = isl_set_intersect(set_i, locus);
+		set = isl_set_union_disjoint(set, set_i);
+	}
+
+	isl_pw_aff_free(pwaff);
+
+	return set;
+}
+
+/* Return a set containing those elements in the domain
+ * of "pa" where it is positive.
+ */
+__isl_give isl_set *isl_pw_aff_pos_set(__isl_take isl_pw_aff *pa)
+{
+	return pw_aff_locus(pa, &aff_pos_basic_set, 0);
+}
+
+/* Return a set containing those elements in the domain
+ * of pwaff where it is non-negative.
+ */
+__isl_give isl_set *isl_pw_aff_nonneg_set(__isl_take isl_pw_aff *pwaff)
+{
+	return pw_aff_locus(pwaff, &aff_nonneg_basic_set, 0);
+}
+
+/* Return a set containing those elements in the domain
+ * of pwaff where it is zero.
+ */
+__isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff)
+{
+	return pw_aff_locus(pwaff, &aff_zero_basic_set, 0);
+}
+
+/* Return a set containing those elements in the domain
+ * of pwaff where it is not zero.
+ */
+__isl_give isl_set *isl_pw_aff_non_zero_set(__isl_take isl_pw_aff *pwaff)
+{
+	return pw_aff_locus(pwaff, &aff_zero_basic_set, 1);
+}
+
+/* Return a set containing those elements in the shared domain
+ * of pwaff1 and pwaff2 where pwaff1 is greater than (or equal) to pwaff2.
+ *
+ * We compute the difference on the shared domain and then construct
+ * the set of values where this difference is non-negative.
+ * If strict is set, we first subtract 1 from the difference.
+ * If equal is set, we only return the elements where pwaff1 and pwaff2
+ * are equal.
+ */
+static __isl_give isl_set *pw_aff_gte_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2, int strict, int equal)
+{
+	isl_set *set1, *set2;
+
+	set1 = isl_pw_aff_domain(isl_pw_aff_copy(pwaff1));
+	set2 = isl_pw_aff_domain(isl_pw_aff_copy(pwaff2));
+	set1 = isl_set_intersect(set1, set2);
+	pwaff1 = isl_pw_aff_intersect_domain(pwaff1, isl_set_copy(set1));
+	pwaff2 = isl_pw_aff_intersect_domain(pwaff2, isl_set_copy(set1));
+	pwaff1 = isl_pw_aff_add(pwaff1, isl_pw_aff_neg(pwaff2));
+
+	if (strict) {
+		isl_space *dim = isl_set_get_space(set1);
+		isl_aff *aff;
+		aff = isl_aff_zero_on_domain(isl_local_space_from_space(dim));
+		aff = isl_aff_add_constant_si(aff, -1);
+		pwaff1 = isl_pw_aff_add(pwaff1, isl_pw_aff_alloc(set1, aff));
+	} else
+		isl_set_free(set1);
+
+	if (equal)
+		return isl_pw_aff_zero_set(pwaff1);
+	return isl_pw_aff_nonneg_set(pwaff1);
+}
+
+/* Return a set containing those elements in the shared domain
+ * of pwaff1 and pwaff2 where pwaff1 is equal to pwaff2.
+ */
+static __isl_give isl_set *pw_aff_eq_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return pw_aff_gte_set(pwaff1, pwaff2, 0, 1);
+}
+
+__isl_give isl_set *isl_pw_aff_eq_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_eq_set);
+}
+
+/* Return a set containing those elements in the shared domain
+ * of pwaff1 and pwaff2 where pwaff1 is greater than or equal to pwaff2.
+ */
+static __isl_give isl_set *pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return pw_aff_gte_set(pwaff1, pwaff2, 0, 0);
+}
+
+__isl_give isl_set *isl_pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_ge_set);
+}
+
+/* Return a set containing those elements in the shared domain
+ * of pwaff1 and pwaff2 where pwaff1 is strictly greater than pwaff2.
+ */
+static __isl_give isl_set *pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return pw_aff_gte_set(pwaff1, pwaff2, 1, 0);
+}
+
+__isl_give isl_set *isl_pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_gt_set);
+}
+
+__isl_give isl_set *isl_pw_aff_le_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return isl_pw_aff_ge_set(pwaff2, pwaff1);
+}
+
+__isl_give isl_set *isl_pw_aff_lt_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return isl_pw_aff_gt_set(pwaff2, pwaff1);
+}
+
+/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
+ * where the function values are ordered in the same way as "order",
+ * which returns a set in the shared domain of its two arguments.
+ * The parameters of "pa1" and "pa2" are assumed to have been aligned.
+ *
+ * Let "pa1" and "pa2" be defined on domains A and B respectively.
+ * We first pull back the two functions such that they are defined on
+ * the domain [A -> B].  Then we apply "order", resulting in a set
+ * in the space [A -> B].  Finally, we unwrap this set to obtain
+ * a map in the space A -> B.
+ */
+static __isl_give isl_map *isl_pw_aff_order_map_aligned(
+	__isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2,
+	__isl_give isl_set *(*order)(__isl_take isl_pw_aff *pa1,
+		__isl_take isl_pw_aff *pa2))
+{
+	isl_space *space1, *space2;
+	isl_multi_aff *ma;
+	isl_set *set;
+
+	space1 = isl_space_domain(isl_pw_aff_get_space(pa1));
+	space2 = isl_space_domain(isl_pw_aff_get_space(pa2));
+	space1 = isl_space_map_from_domain_and_range(space1, space2);
+	ma = isl_multi_aff_domain_map(isl_space_copy(space1));
+	pa1 = isl_pw_aff_pullback_multi_aff(pa1, ma);
+	ma = isl_multi_aff_range_map(space1);
+	pa2 = isl_pw_aff_pullback_multi_aff(pa2, ma);
+	set = order(pa1, pa2);
+
+	return isl_set_unwrap(set);
+}
+
+/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
+ * where the function values are equal.
+ * The parameters of "pa1" and "pa2" are assumed to have been aligned.
+ */
+static __isl_give isl_map *isl_pw_aff_eq_map_aligned(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2)
+{
+	return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_eq_set);
+}
+
+/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
+ * where the function values are equal.
+ */
+__isl_give isl_map *isl_pw_aff_eq_map(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2)
+{
+	return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_eq_map_aligned);
+}
+
+/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
+ * where the function value of "pa1" is less than the function value of "pa2".
+ * The parameters of "pa1" and "pa2" are assumed to have been aligned.
+ */
+static __isl_give isl_map *isl_pw_aff_lt_map_aligned(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2)
+{
+	return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_lt_set);
+}
+
+/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
+ * where the function value of "pa1" is less than the function value of "pa2".
+ */
+__isl_give isl_map *isl_pw_aff_lt_map(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2)
+{
+	return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_lt_map_aligned);
+}
+
+/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
+ * where the function value of "pa1" is greater than the function value
+ * of "pa2".
+ * The parameters of "pa1" and "pa2" are assumed to have been aligned.
+ */
+static __isl_give isl_map *isl_pw_aff_gt_map_aligned(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2)
+{
+	return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_gt_set);
+}
+
+/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"
+ * where the function value of "pa1" is greater than the function value
+ * of "pa2".
+ */
+__isl_give isl_map *isl_pw_aff_gt_map(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2)
+{
+	return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_gt_map_aligned);
+}
+
+/* Return a set containing those elements in the shared domain
+ * of the elements of list1 and list2 where each element in list1
+ * has the relation specified by "fn" with each element in list2.
+ */
+static __isl_give isl_set *pw_aff_list_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2,
+	__isl_give isl_set *(*fn)(__isl_take isl_pw_aff *pwaff1,
+				    __isl_take isl_pw_aff *pwaff2))
+{
+	int i, j;
+	isl_ctx *ctx;
+	isl_set *set;
+
+	if (!list1 || !list2)
+		goto error;
+
+	ctx = isl_pw_aff_list_get_ctx(list1);
+	if (list1->n < 1 || list2->n < 1)
+		isl_die(ctx, isl_error_invalid,
+			"list should contain at least one element", goto error);
+
+	set = isl_set_universe(isl_pw_aff_get_domain_space(list1->p[0]));
+	for (i = 0; i < list1->n; ++i)
+		for (j = 0; j < list2->n; ++j) {
+			isl_set *set_ij;
+
+			set_ij = fn(isl_pw_aff_copy(list1->p[i]),
+				    isl_pw_aff_copy(list2->p[j]));
+			set = isl_set_intersect(set, set_ij);
+		}
+
+	isl_pw_aff_list_free(list1);
+	isl_pw_aff_list_free(list2);
+	return set;
+error:
+	isl_pw_aff_list_free(list1);
+	isl_pw_aff_list_free(list2);
+	return NULL;
+}
+
+/* Return a set containing those elements in the shared domain
+ * of the elements of list1 and list2 where each element in list1
+ * is equal to each element in list2.
+ */
+__isl_give isl_set *isl_pw_aff_list_eq_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2)
+{
+	return pw_aff_list_set(list1, list2, &isl_pw_aff_eq_set);
+}
+
+__isl_give isl_set *isl_pw_aff_list_ne_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2)
+{
+	return pw_aff_list_set(list1, list2, &isl_pw_aff_ne_set);
+}
+
+/* Return a set containing those elements in the shared domain
+ * of the elements of list1 and list2 where each element in list1
+ * is less than or equal to each element in list2.
+ */
+__isl_give isl_set *isl_pw_aff_list_le_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2)
+{
+	return pw_aff_list_set(list1, list2, &isl_pw_aff_le_set);
+}
+
+__isl_give isl_set *isl_pw_aff_list_lt_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2)
+{
+	return pw_aff_list_set(list1, list2, &isl_pw_aff_lt_set);
+}
+
+__isl_give isl_set *isl_pw_aff_list_ge_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2)
+{
+	return pw_aff_list_set(list1, list2, &isl_pw_aff_ge_set);
+}
+
+__isl_give isl_set *isl_pw_aff_list_gt_set(__isl_take isl_pw_aff_list *list1,
+	__isl_take isl_pw_aff_list *list2)
+{
+	return pw_aff_list_set(list1, list2, &isl_pw_aff_gt_set);
+}
+
+
+/* Return a set containing those elements in the shared domain
+ * of pwaff1 and pwaff2 where pwaff1 is not equal to pwaff2.
+ */
+static __isl_give isl_set *pw_aff_ne_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	isl_set *set_lt, *set_gt;
+
+	set_lt = isl_pw_aff_lt_set(isl_pw_aff_copy(pwaff1),
+				   isl_pw_aff_copy(pwaff2));
+	set_gt = isl_pw_aff_gt_set(pwaff1, pwaff2);
+	return isl_set_union_disjoint(set_lt, set_gt);
+}
+
+__isl_give isl_set *isl_pw_aff_ne_set(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_ne_set);
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_scale_down(__isl_take isl_pw_aff *pwaff,
+	isl_int v)
+{
+	int i;
+
+	if (isl_int_is_one(v))
+		return pwaff;
+	if (!isl_int_is_pos(v))
+		isl_die(isl_pw_aff_get_ctx(pwaff), isl_error_invalid,
+			"factor needs to be positive",
+			return isl_pw_aff_free(pwaff));
+	pwaff = isl_pw_aff_cow(pwaff);
+	if (!pwaff)
+		return NULL;
+	if (pwaff->n == 0)
+		return pwaff;
+
+	for (i = 0; i < pwaff->n; ++i) {
+		pwaff->p[i].aff = isl_aff_scale_down(pwaff->p[i].aff, v);
+		if (!pwaff->p[i].aff)
+			return isl_pw_aff_free(pwaff);
+	}
+
+	return pwaff;
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_floor(__isl_take isl_pw_aff *pwaff)
+{
+	int i;
+
+	pwaff = isl_pw_aff_cow(pwaff);
+	if (!pwaff)
+		return NULL;
+	if (pwaff->n == 0)
+		return pwaff;
+
+	for (i = 0; i < pwaff->n; ++i) {
+		pwaff->p[i].aff = isl_aff_floor(pwaff->p[i].aff);
+		if (!pwaff->p[i].aff)
+			return isl_pw_aff_free(pwaff);
+	}
+
+	return pwaff;
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff)
+{
+	int i;
+
+	pwaff = isl_pw_aff_cow(pwaff);
+	if (!pwaff)
+		return NULL;
+	if (pwaff->n == 0)
+		return pwaff;
+
+	for (i = 0; i < pwaff->n; ++i) {
+		pwaff->p[i].aff = isl_aff_ceil(pwaff->p[i].aff);
+		if (!pwaff->p[i].aff)
+			return isl_pw_aff_free(pwaff);
+	}
+
+	return pwaff;
+}
+
+/* Assuming that "cond1" and "cond2" are disjoint,
+ * return an affine expression that is equal to pwaff1 on cond1
+ * and to pwaff2 on cond2.
+ */
+static __isl_give isl_pw_aff *isl_pw_aff_select(
+	__isl_take isl_set *cond1, __isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_set *cond2, __isl_take isl_pw_aff *pwaff2)
+{
+	pwaff1 = isl_pw_aff_intersect_domain(pwaff1, cond1);
+	pwaff2 = isl_pw_aff_intersect_domain(pwaff2, cond2);
+
+	return isl_pw_aff_add_disjoint(pwaff1, pwaff2);
+}
+
+/* Return an affine expression that is equal to pwaff_true for elements
+ * where "cond" is non-zero and to pwaff_false for elements where "cond"
+ * is zero.
+ * That is, return cond ? pwaff_true : pwaff_false;
+ *
+ * If "cond" involves and NaN, then we conservatively return a NaN
+ * on its entire domain.  In principle, we could consider the pieces
+ * where it is NaN separately from those where it is not.
+ *
+ * If "pwaff_true" and "pwaff_false" are obviously equal to each other,
+ * then only use the domain of "cond" to restrict the domain.
+ */
+__isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_pw_aff *cond,
+	__isl_take isl_pw_aff *pwaff_true, __isl_take isl_pw_aff *pwaff_false)
+{
+	isl_set *cond_true, *cond_false;
+	isl_bool equal;
+
+	if (!cond)
+		goto error;
+	if (isl_pw_aff_involves_nan(cond)) {
+		isl_space *space = isl_pw_aff_get_domain_space(cond);
+		isl_local_space *ls = isl_local_space_from_space(space);
+		isl_pw_aff_free(cond);
+		isl_pw_aff_free(pwaff_true);
+		isl_pw_aff_free(pwaff_false);
+		return isl_pw_aff_nan_on_domain(ls);
+	}
+
+	pwaff_true = isl_pw_aff_align_params(pwaff_true,
+					    isl_pw_aff_get_space(pwaff_false));
+	pwaff_false = isl_pw_aff_align_params(pwaff_false,
+					    isl_pw_aff_get_space(pwaff_true));
+	equal = isl_pw_aff_plain_is_equal(pwaff_true, pwaff_false);
+	if (equal < 0)
+		goto error;
+	if (equal) {
+		isl_set *dom;
+
+		dom = isl_set_coalesce(isl_pw_aff_domain(cond));
+		isl_pw_aff_free(pwaff_false);
+		return isl_pw_aff_intersect_domain(pwaff_true, dom);
+	}
+
+	cond_true = isl_pw_aff_non_zero_set(isl_pw_aff_copy(cond));
+	cond_false = isl_pw_aff_zero_set(cond);
+	return isl_pw_aff_select(cond_true, pwaff_true,
+				 cond_false, pwaff_false);
+error:
+	isl_pw_aff_free(cond);
+	isl_pw_aff_free(pwaff_true);
+	isl_pw_aff_free(pwaff_false);
+	return NULL;
+}
+
+isl_bool isl_aff_is_cst(__isl_keep isl_aff *aff)
+{
+	if (!aff)
+		return isl_bool_error;
+
+	return isl_seq_first_non_zero(aff->v->el + 2, aff->v->size - 2) == -1;
+}
+
+/* Check whether pwaff is a piecewise constant.
+ */
+isl_bool isl_pw_aff_is_cst(__isl_keep isl_pw_aff *pwaff)
+{
+	int i;
+
+	if (!pwaff)
+		return isl_bool_error;
+
+	for (i = 0; i < pwaff->n; ++i) {
+		isl_bool is_cst = isl_aff_is_cst(pwaff->p[i].aff);
+		if (is_cst < 0 || !is_cst)
+			return is_cst;
+	}
+
+	return isl_bool_true;
+}
+
+/* Are all elements of "mpa" piecewise constants?
+ */
+isl_bool isl_multi_pw_aff_is_cst(__isl_keep isl_multi_pw_aff *mpa)
+{
+	int i;
+
+	if (!mpa)
+		return isl_bool_error;
+
+	for (i = 0; i < mpa->n; ++i) {
+		isl_bool is_cst = isl_pw_aff_is_cst(mpa->p[i]);
+		if (is_cst < 0 || !is_cst)
+			return is_cst;
+	}
+
+	return isl_bool_true;
+}
+
+/* Return the product of "aff1" and "aff2".
+ *
+ * If either of the two is NaN, then the result is NaN.
+ *
+ * Otherwise, at least one of "aff1" or "aff2" needs to be a constant.
+ */
+__isl_give isl_aff *isl_aff_mul(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	if (!aff1 || !aff2)
+		goto error;
+
+	if (isl_aff_is_nan(aff1)) {
+		isl_aff_free(aff2);
+		return aff1;
+	}
+	if (isl_aff_is_nan(aff2)) {
+		isl_aff_free(aff1);
+		return aff2;
+	}
+
+	if (!isl_aff_is_cst(aff2) && isl_aff_is_cst(aff1))
+		return isl_aff_mul(aff2, aff1);
+
+	if (!isl_aff_is_cst(aff2))
+		isl_die(isl_aff_get_ctx(aff1), isl_error_invalid,
+			"at least one affine expression should be constant",
+			goto error);
+
+	aff1 = isl_aff_cow(aff1);
+	if (!aff1 || !aff2)
+		goto error;
+
+	aff1 = isl_aff_scale(aff1, aff2->v->el[1]);
+	aff1 = isl_aff_scale_down(aff1, aff2->v->el[0]);
+
+	isl_aff_free(aff2);
+	return aff1;
+error:
+	isl_aff_free(aff1);
+	isl_aff_free(aff2);
+	return NULL;
+}
+
+/* Divide "aff1" by "aff2", assuming "aff2" is a constant.
+ *
+ * If either of the two is NaN, then the result is NaN.
+ */
+__isl_give isl_aff *isl_aff_div(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	int is_cst;
+	int neg;
+
+	if (!aff1 || !aff2)
+		goto error;
+
+	if (isl_aff_is_nan(aff1)) {
+		isl_aff_free(aff2);
+		return aff1;
+	}
+	if (isl_aff_is_nan(aff2)) {
+		isl_aff_free(aff1);
+		return aff2;
+	}
+
+	is_cst = isl_aff_is_cst(aff2);
+	if (is_cst < 0)
+		goto error;
+	if (!is_cst)
+		isl_die(isl_aff_get_ctx(aff2), isl_error_invalid,
+			"second argument should be a constant", goto error);
+
+	if (!aff2)
+		goto error;
+
+	neg = isl_int_is_neg(aff2->v->el[1]);
+	if (neg) {
+		isl_int_neg(aff2->v->el[0], aff2->v->el[0]);
+		isl_int_neg(aff2->v->el[1], aff2->v->el[1]);
+	}
+
+	aff1 = isl_aff_scale(aff1, aff2->v->el[0]);
+	aff1 = isl_aff_scale_down(aff1, aff2->v->el[1]);
+
+	if (neg) {
+		isl_int_neg(aff2->v->el[0], aff2->v->el[0]);
+		isl_int_neg(aff2->v->el[1], aff2->v->el[1]);
+	}
+
+	isl_aff_free(aff2);
+	return aff1;
+error:
+	isl_aff_free(aff1);
+	isl_aff_free(aff2);
+	return NULL;
+}
+
+static __isl_give isl_pw_aff *pw_aff_add(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return isl_pw_aff_on_shared_domain(pwaff1, pwaff2, &isl_aff_add);
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_add(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2, &pw_aff_add);
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_union_add(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return isl_pw_aff_union_add_(pwaff1, pwaff2);
+}
+
+static __isl_give isl_pw_aff *pw_aff_mul(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return isl_pw_aff_on_shared_domain(pwaff1, pwaff2, &isl_aff_mul);
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_mul(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2, &pw_aff_mul);
+}
+
+static __isl_give isl_pw_aff *pw_aff_div(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2)
+{
+	return isl_pw_aff_on_shared_domain(pa1, pa2, &isl_aff_div);
+}
+
+/* Divide "pa1" by "pa2", assuming "pa2" is a piecewise constant.
+ */
+__isl_give isl_pw_aff *isl_pw_aff_div(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2)
+{
+	int is_cst;
+
+	is_cst = isl_pw_aff_is_cst(pa2);
+	if (is_cst < 0)
+		goto error;
+	if (!is_cst)
+		isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid,
+			"second argument should be a piecewise constant",
+			goto error);
+	return isl_pw_aff_align_params_pw_pw_and(pa1, pa2, &pw_aff_div);
+error:
+	isl_pw_aff_free(pa1);
+	isl_pw_aff_free(pa2);
+	return NULL;
+}
+
+/* Compute the quotient of the integer division of "pa1" by "pa2"
+ * with rounding towards zero.
+ * "pa2" is assumed to be a piecewise constant.
+ *
+ * In particular, return
+ *
+ *	pa1 >= 0 ? floor(pa1/pa2) : ceil(pa1/pa2)
+ *
+ */
+__isl_give isl_pw_aff *isl_pw_aff_tdiv_q(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2)
+{
+	int is_cst;
+	isl_set *cond;
+	isl_pw_aff *f, *c;
+
+	is_cst = isl_pw_aff_is_cst(pa2);
+	if (is_cst < 0)
+		goto error;
+	if (!is_cst)
+		isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid,
+			"second argument should be a piecewise constant",
+			goto error);
+
+	pa1 = isl_pw_aff_div(pa1, pa2);
+
+	cond = isl_pw_aff_nonneg_set(isl_pw_aff_copy(pa1));
+	f = isl_pw_aff_floor(isl_pw_aff_copy(pa1));
+	c = isl_pw_aff_ceil(pa1);
+	return isl_pw_aff_cond(isl_set_indicator_function(cond), f, c);
+error:
+	isl_pw_aff_free(pa1);
+	isl_pw_aff_free(pa2);
+	return NULL;
+}
+
+/* Compute the remainder of the integer division of "pa1" by "pa2"
+ * with rounding towards zero.
+ * "pa2" is assumed to be a piecewise constant.
+ *
+ * In particular, return
+ *
+ *	pa1 - pa2 * (pa1 >= 0 ? floor(pa1/pa2) : ceil(pa1/pa2))
+ *
+ */
+__isl_give isl_pw_aff *isl_pw_aff_tdiv_r(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2)
+{
+	int is_cst;
+	isl_pw_aff *res;
+
+	is_cst = isl_pw_aff_is_cst(pa2);
+	if (is_cst < 0)
+		goto error;
+	if (!is_cst)
+		isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid,
+			"second argument should be a piecewise constant",
+			goto error);
+	res = isl_pw_aff_tdiv_q(isl_pw_aff_copy(pa1), isl_pw_aff_copy(pa2));
+	res = isl_pw_aff_mul(pa2, res);
+	res = isl_pw_aff_sub(pa1, res);
+	return res;
+error:
+	isl_pw_aff_free(pa1);
+	isl_pw_aff_free(pa2);
+	return NULL;
+}
+
+/* Does either of "pa1" or "pa2" involve any NaN2?
+ */
+static isl_bool either_involves_nan(__isl_keep isl_pw_aff *pa1,
+	__isl_keep isl_pw_aff *pa2)
+{
+	isl_bool has_nan;
+
+	has_nan = isl_pw_aff_involves_nan(pa1);
+	if (has_nan < 0 || has_nan)
+		return has_nan;
+	return isl_pw_aff_involves_nan(pa2);
+}
+
+/* Replace "pa1" and "pa2" (at least one of which involves a NaN)
+ * by a NaN on their shared domain.
+ *
+ * In principle, the result could be refined to only being NaN
+ * on the parts of this domain where at least one of "pa1" or "pa2" is NaN.
+ */
+static __isl_give isl_pw_aff *replace_by_nan(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2)
+{
+	isl_local_space *ls;
+	isl_set *dom;
+	isl_pw_aff *pa;
+
+	dom = isl_set_intersect(isl_pw_aff_domain(pa1), isl_pw_aff_domain(pa2));
+	ls = isl_local_space_from_space(isl_set_get_space(dom));
+	pa = isl_pw_aff_nan_on_domain(ls);
+	pa = isl_pw_aff_intersect_domain(pa, dom);
+
+	return pa;
+}
+
+static __isl_give isl_pw_aff *pw_aff_min(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	isl_set *le;
+	isl_set *dom;
+
+	dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)),
+				isl_pw_aff_domain(isl_pw_aff_copy(pwaff2)));
+	le = isl_pw_aff_le_set(isl_pw_aff_copy(pwaff1),
+				isl_pw_aff_copy(pwaff2));
+	dom = isl_set_subtract(dom, isl_set_copy(le));
+	return isl_pw_aff_select(le, pwaff1, dom, pwaff2);
+}
+
+static __isl_give isl_pw_aff *pw_aff_max(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	isl_set *ge;
+	isl_set *dom;
+
+	dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)),
+				isl_pw_aff_domain(isl_pw_aff_copy(pwaff2)));
+	ge = isl_pw_aff_ge_set(isl_pw_aff_copy(pwaff1),
+				isl_pw_aff_copy(pwaff2));
+	dom = isl_set_subtract(dom, isl_set_copy(ge));
+	return isl_pw_aff_select(ge, pwaff1, dom, pwaff2);
+}
+
+/* Return an expression for the minimum (if "max" is not set) or
+ * the maximum (if "max" is set) of "pa1" and "pa2".
+ * If either expression involves any NaN, then return a NaN
+ * on the shared domain as result.
+ */
+static __isl_give isl_pw_aff *pw_aff_min_max(__isl_take isl_pw_aff *pa1,
+	__isl_take isl_pw_aff *pa2, int max)
+{
+	isl_bool has_nan;
+
+	has_nan = either_involves_nan(pa1, pa2);
+	if (has_nan < 0)
+		pa1 = isl_pw_aff_free(pa1);
+	else if (has_nan)
+		return replace_by_nan(pa1, pa2);
+
+	if (max)
+		return isl_pw_aff_align_params_pw_pw_and(pa1, pa2, &pw_aff_max);
+	else
+		return isl_pw_aff_align_params_pw_pw_and(pa1, pa2, &pw_aff_min);
+}
+
+/* Return an expression for the minimum of "pwaff1" and "pwaff2".
+ */
+__isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return pw_aff_min_max(pwaff1, pwaff2, 0);
+}
+
+/* Return an expression for the maximum of "pwaff1" and "pwaff2".
+ */
+__isl_give isl_pw_aff *isl_pw_aff_max(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2)
+{
+	return pw_aff_min_max(pwaff1, pwaff2, 1);
+}
+
+static __isl_give isl_pw_aff *pw_aff_list_reduce(
+	__isl_take isl_pw_aff_list *list,
+	__isl_give isl_pw_aff *(*fn)(__isl_take isl_pw_aff *pwaff1,
+					__isl_take isl_pw_aff *pwaff2))
+{
+	int i;
+	isl_ctx *ctx;
+	isl_pw_aff *res;
+
+	if (!list)
+		return NULL;
+
+	ctx = isl_pw_aff_list_get_ctx(list);
+	if (list->n < 1)
+		isl_die(ctx, isl_error_invalid,
+			"list should contain at least one element", goto error);
+
+	res = isl_pw_aff_copy(list->p[0]);
+	for (i = 1; i < list->n; ++i)
+		res = fn(res, isl_pw_aff_copy(list->p[i]));
+
+	isl_pw_aff_list_free(list);
+	return res;
+error:
+	isl_pw_aff_list_free(list);
+	return NULL;
+}
+
+/* Return an isl_pw_aff that maps each element in the intersection of the
+ * domains of the elements of list to the minimal corresponding affine
+ * expression.
+ */
+__isl_give isl_pw_aff *isl_pw_aff_list_min(__isl_take isl_pw_aff_list *list)
+{
+	return pw_aff_list_reduce(list, &isl_pw_aff_min);
+}
+
+/* Return an isl_pw_aff that maps each element in the intersection of the
+ * domains of the elements of list to the maximal corresponding affine
+ * expression.
+ */
+__isl_give isl_pw_aff *isl_pw_aff_list_max(__isl_take isl_pw_aff_list *list)
+{
+	return pw_aff_list_reduce(list, &isl_pw_aff_max);
+}
+
+/* Mark the domains of "pwaff" as rational.
+ */
+__isl_give isl_pw_aff *isl_pw_aff_set_rational(__isl_take isl_pw_aff *pwaff)
+{
+	int i;
+
+	pwaff = isl_pw_aff_cow(pwaff);
+	if (!pwaff)
+		return NULL;
+	if (pwaff->n == 0)
+		return pwaff;
+
+	for (i = 0; i < pwaff->n; ++i) {
+		pwaff->p[i].set = isl_set_set_rational(pwaff->p[i].set);
+		if (!pwaff->p[i].set)
+			return isl_pw_aff_free(pwaff);
+	}
+
+	return pwaff;
+}
+
+/* Mark the domains of the elements of "list" as rational.
+ */
+__isl_give isl_pw_aff_list *isl_pw_aff_list_set_rational(
+	__isl_take isl_pw_aff_list *list)
+{
+	int i, n;
+
+	if (!list)
+		return NULL;
+	if (list->n == 0)
+		return list;
+
+	n = list->n;
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+
+		pa = isl_pw_aff_list_get_pw_aff(list, i);
+		pa = isl_pw_aff_set_rational(pa);
+		list = isl_pw_aff_list_set_pw_aff(list, i, pa);
+	}
+
+	return list;
+}
+
+/* Do the parameters of "aff" match those of "space"?
+ */
+isl_bool isl_aff_matching_params(__isl_keep isl_aff *aff,
+	__isl_keep isl_space *space)
+{
+	isl_space *aff_space;
+	isl_bool match;
+
+	if (!aff || !space)
+		return isl_bool_error;
+
+	aff_space = isl_aff_get_domain_space(aff);
+
+	match = isl_space_has_equal_params(space, aff_space);
+
+	isl_space_free(aff_space);
+	return match;
+}
+
+/* Check that the domain space of "aff" matches "space".
+ */
+isl_stat isl_aff_check_match_domain_space(__isl_keep isl_aff *aff,
+	__isl_keep isl_space *space)
+{
+	isl_space *aff_space;
+	isl_bool match;
+
+	if (!aff || !space)
+		return isl_stat_error;
+
+	aff_space = isl_aff_get_domain_space(aff);
+
+	match = isl_space_has_equal_params(space, aff_space);
+	if (match < 0)
+		goto error;
+	if (!match)
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"parameters don't match", goto error);
+	match = isl_space_tuple_is_equal(space, isl_dim_in,
+					aff_space, isl_dim_set);
+	if (match < 0)
+		goto error;
+	if (!match)
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"domains don't match", goto error);
+	isl_space_free(aff_space);
+	return isl_stat_ok;
+error:
+	isl_space_free(aff_space);
+	return isl_stat_error;
+}
+
+#undef BASE
+#define BASE aff
+#undef DOMBASE
+#define DOMBASE set
+#define NO_DOMAIN
+
+#include <isl_multi_templ.c>
+#include <isl_multi_apply_set.c>
+#include <isl_multi_cmp.c>
+#include <isl_multi_floor.c>
+#include <isl_multi_gist.c>
+
+#undef NO_DOMAIN
+
+/* Construct an isl_multi_aff living in "space" that corresponds
+ * to the affine transformation matrix "mat".
+ */
+__isl_give isl_multi_aff *isl_multi_aff_from_aff_mat(
+	__isl_take isl_space *space, __isl_take isl_mat *mat)
+{
+	isl_ctx *ctx;
+	isl_local_space *ls = NULL;
+	isl_multi_aff *ma = NULL;
+	int n_row, n_col, n_out, total;
+	int i;
+
+	if (!space || !mat)
+		goto error;
+
+	ctx = isl_mat_get_ctx(mat);
+
+	n_row = isl_mat_rows(mat);
+	n_col = isl_mat_cols(mat);
+	if (n_row < 1)
+		isl_die(ctx, isl_error_invalid,
+			"insufficient number of rows", goto error);
+	if (n_col < 1)
+		isl_die(ctx, isl_error_invalid,
+			"insufficient number of columns", goto error);
+	n_out = isl_space_dim(space, isl_dim_out);
+	total = isl_space_dim(space, isl_dim_all);
+	if (1 + n_out != n_row || 2 + total != n_row + n_col)
+		isl_die(ctx, isl_error_invalid,
+			"dimension mismatch", goto error);
+
+	ma = isl_multi_aff_zero(isl_space_copy(space));
+	ls = isl_local_space_from_space(isl_space_domain(space));
+
+	for (i = 0; i < n_row - 1; ++i) {
+		isl_vec *v;
+		isl_aff *aff;
+
+		v = isl_vec_alloc(ctx, 1 + n_col);
+		if (!v)
+			goto error;
+		isl_int_set(v->el[0], mat->row[0][0]);
+		isl_seq_cpy(v->el + 1, mat->row[1 + i], n_col);
+		v = isl_vec_normalize(v);
+		aff = isl_aff_alloc_vec(isl_local_space_copy(ls), v);
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+
+	isl_local_space_free(ls);
+	isl_mat_free(mat);
+	return ma;
+error:
+	isl_local_space_free(ls);
+	isl_mat_free(mat);
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+/* Remove any internal structure of the domain of "ma".
+ * If there is any such internal structure in the input,
+ * then the name of the corresponding space is also removed.
+ */
+__isl_give isl_multi_aff *isl_multi_aff_flatten_domain(
+	__isl_take isl_multi_aff *ma)
+{
+	isl_space *space;
+
+	if (!ma)
+		return NULL;
+
+	if (!ma->space->nested[0])
+		return ma;
+
+	space = isl_multi_aff_get_space(ma);
+	space = isl_space_flatten_domain(space);
+	ma = isl_multi_aff_reset_space(ma, space);
+
+	return ma;
+}
+
+/* Given a map space, return an isl_multi_aff that maps a wrapped copy
+ * of the space to its domain.
+ */
+__isl_give isl_multi_aff *isl_multi_aff_domain_map(__isl_take isl_space *space)
+{
+	int i, n_in;
+	isl_local_space *ls;
+	isl_multi_aff *ma;
+
+	if (!space)
+		return NULL;
+	if (!isl_space_is_map(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"not a map space", goto error);
+
+	n_in = isl_space_dim(space, isl_dim_in);
+	space = isl_space_domain_map(space);
+
+	ma = isl_multi_aff_alloc(isl_space_copy(space));
+	if (n_in == 0) {
+		isl_space_free(space);
+		return ma;
+	}
+
+	space = isl_space_domain(space);
+	ls = isl_local_space_from_space(space);
+	for (i = 0; i < n_in; ++i) {
+		isl_aff *aff;
+
+		aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
+						isl_dim_set, i);
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+	isl_local_space_free(ls);
+	return ma;
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Given a map space, return an isl_multi_aff that maps a wrapped copy
+ * of the space to its range.
+ */
+__isl_give isl_multi_aff *isl_multi_aff_range_map(__isl_take isl_space *space)
+{
+	int i, n_in, n_out;
+	isl_local_space *ls;
+	isl_multi_aff *ma;
+
+	if (!space)
+		return NULL;
+	if (!isl_space_is_map(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"not a map space", goto error);
+
+	n_in = isl_space_dim(space, isl_dim_in);
+	n_out = isl_space_dim(space, isl_dim_out);
+	space = isl_space_range_map(space);
+
+	ma = isl_multi_aff_alloc(isl_space_copy(space));
+	if (n_out == 0) {
+		isl_space_free(space);
+		return ma;
+	}
+
+	space = isl_space_domain(space);
+	ls = isl_local_space_from_space(space);
+	for (i = 0; i < n_out; ++i) {
+		isl_aff *aff;
+
+		aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
+						isl_dim_set, n_in + i);
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+	isl_local_space_free(ls);
+	return ma;
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Given a map space, return an isl_pw_multi_aff that maps a wrapped copy
+ * of the space to its range.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_map(
+	__isl_take isl_space *space)
+{
+	return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_range_map(space));
+}
+
+/* Given the space of a set and a range of set dimensions,
+ * construct an isl_multi_aff that projects out those dimensions.
+ */
+__isl_give isl_multi_aff *isl_multi_aff_project_out_map(
+	__isl_take isl_space *space, enum isl_dim_type type,
+	unsigned first, unsigned n)
+{
+	int i, dim;
+	isl_local_space *ls;
+	isl_multi_aff *ma;
+
+	if (!space)
+		return NULL;
+	if (!isl_space_is_set(space))
+		isl_die(isl_space_get_ctx(space), isl_error_unsupported,
+			"expecting set space", goto error);
+	if (type != isl_dim_set)
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"only set dimensions can be projected out", goto error);
+
+	dim = isl_space_dim(space, isl_dim_set);
+	if (first + n > dim)
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"range out of bounds", goto error);
+
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, dim - n);
+
+	if (dim == n)
+		return isl_multi_aff_alloc(space);
+
+	ma = isl_multi_aff_alloc(isl_space_copy(space));
+	space = isl_space_domain(space);
+	ls = isl_local_space_from_space(space);
+
+	for (i = 0; i < first; ++i) {
+		isl_aff *aff;
+
+		aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
+						isl_dim_set, i);
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+
+	for (i = 0; i < dim - (first + n); ++i) {
+		isl_aff *aff;
+
+		aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
+						isl_dim_set, first + n + i);
+		ma = isl_multi_aff_set_aff(ma, first + i, aff);
+	}
+
+	isl_local_space_free(ls);
+	return ma;
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Given the space of a set and a range of set dimensions,
+ * construct an isl_pw_multi_aff that projects out those dimensions.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_out_map(
+	__isl_take isl_space *space, enum isl_dim_type type,
+	unsigned first, unsigned n)
+{
+	isl_multi_aff *ma;
+
+	ma = isl_multi_aff_project_out_map(space, type, first, n);
+	return isl_pw_multi_aff_from_multi_aff(ma);
+}
+
+/* Create an isl_pw_multi_aff with the given isl_multi_aff on a universe
+ * domain.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_aff(
+	__isl_take isl_multi_aff *ma)
+{
+	isl_set *dom = isl_set_universe(isl_multi_aff_get_domain_space(ma));
+	return isl_pw_multi_aff_alloc(dom, ma);
+}
+
+/* Create a piecewise multi-affine expression in the given space that maps each
+ * input dimension to the corresponding output dimension.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity(
+	__isl_take isl_space *space)
+{
+	return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_identity(space));
+}
+
+/* Exploit the equalities in "eq" to simplify the affine expressions.
+ */
+static __isl_give isl_multi_aff *isl_multi_aff_substitute_equalities(
+	__isl_take isl_multi_aff *maff, __isl_take isl_basic_set *eq)
+{
+	int i;
+
+	maff = isl_multi_aff_cow(maff);
+	if (!maff || !eq)
+		goto error;
+
+	for (i = 0; i < maff->n; ++i) {
+		maff->p[i] = isl_aff_substitute_equalities(maff->p[i],
+						    isl_basic_set_copy(eq));
+		if (!maff->p[i])
+			goto error;
+	}
+
+	isl_basic_set_free(eq);
+	return maff;
+error:
+	isl_basic_set_free(eq);
+	isl_multi_aff_free(maff);
+	return NULL;
+}
+
+__isl_give isl_multi_aff *isl_multi_aff_scale(__isl_take isl_multi_aff *maff,
+	isl_int f)
+{
+	int i;
+
+	maff = isl_multi_aff_cow(maff);
+	if (!maff)
+		return NULL;
+
+	for (i = 0; i < maff->n; ++i) {
+		maff->p[i] = isl_aff_scale(maff->p[i], f);
+		if (!maff->p[i])
+			return isl_multi_aff_free(maff);
+	}
+
+	return maff;
+}
+
+__isl_give isl_multi_aff *isl_multi_aff_add_on_domain(__isl_keep isl_set *dom,
+	__isl_take isl_multi_aff *maff1, __isl_take isl_multi_aff *maff2)
+{
+	maff1 = isl_multi_aff_add(maff1, maff2);
+	maff1 = isl_multi_aff_gist(maff1, isl_set_copy(dom));
+	return maff1;
+}
+
+int isl_multi_aff_is_empty(__isl_keep isl_multi_aff *maff)
+{
+	if (!maff)
+		return -1;
+
+	return 0;
+}
+
+/* Return the set of domain elements where "ma1" is lexicographically
+ * smaller than or equal to "ma2".
+ */
+__isl_give isl_set *isl_multi_aff_lex_le_set(__isl_take isl_multi_aff *ma1,
+	__isl_take isl_multi_aff *ma2)
+{
+	return isl_multi_aff_lex_ge_set(ma2, ma1);
+}
+
+/* Return the set of domain elements where "ma1" is lexicographically
+ * smaller than "ma2".
+ */
+__isl_give isl_set *isl_multi_aff_lex_lt_set(__isl_take isl_multi_aff *ma1,
+	__isl_take isl_multi_aff *ma2)
+{
+	return isl_multi_aff_lex_gt_set(ma2, ma1);
+}
+
+/* Return the set of domain elements where "ma1" and "ma2"
+ * satisfy "order".
+ */
+static __isl_give isl_set *isl_multi_aff_order_set(
+	__isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2,
+	__isl_give isl_map *order(__isl_take isl_space *set_space))
+{
+	isl_space *space;
+	isl_map *map1, *map2;
+	isl_map *map, *ge;
+
+	map1 = isl_map_from_multi_aff(ma1);
+	map2 = isl_map_from_multi_aff(ma2);
+	map = isl_map_range_product(map1, map2);
+	space = isl_space_range(isl_map_get_space(map));
+	space = isl_space_domain(isl_space_unwrap(space));
+	ge = order(space);
+	map = isl_map_intersect_range(map, isl_map_wrap(ge));
+
+	return isl_map_domain(map);
+}
+
+/* Return the set of domain elements where "ma1" is lexicographically
+ * greater than or equal to "ma2".
+ */
+__isl_give isl_set *isl_multi_aff_lex_ge_set(__isl_take isl_multi_aff *ma1,
+	__isl_take isl_multi_aff *ma2)
+{
+	return isl_multi_aff_order_set(ma1, ma2, &isl_map_lex_ge);
+}
+
+/* Return the set of domain elements where "ma1" is lexicographically
+ * greater than "ma2".
+ */
+__isl_give isl_set *isl_multi_aff_lex_gt_set(__isl_take isl_multi_aff *ma1,
+	__isl_take isl_multi_aff *ma2)
+{
+	return isl_multi_aff_order_set(ma1, ma2, &isl_map_lex_gt);
+}
+
+#undef PW
+#define PW isl_pw_multi_aff
+#undef EL
+#define EL isl_multi_aff
+#undef EL_IS_ZERO
+#define EL_IS_ZERO is_empty
+#undef ZERO
+#define ZERO empty
+#undef IS_ZERO
+#define IS_ZERO is_empty
+#undef FIELD
+#define FIELD maff
+#undef DEFAULT_IS_ZERO
+#define DEFAULT_IS_ZERO 0
+
+#define NO_SUB
+#define NO_EVAL
+#define NO_OPT
+#define NO_INVOLVES_DIMS
+#define NO_INSERT_DIMS
+#define NO_LIFT
+#define NO_MORPH
+
+#include <isl_pw_templ.c>
+#include <isl_pw_union_opt.c>
+
+#undef NO_SUB
+
+#undef UNION
+#define UNION isl_union_pw_multi_aff
+#undef PART
+#define PART isl_pw_multi_aff
+#undef PARTS
+#define PARTS pw_multi_aff
+
+#include <isl_union_multi.c>
+#include <isl_union_neg.c>
+
+static __isl_give isl_pw_multi_aff *pw_multi_aff_union_lexmax(
+	__isl_take isl_pw_multi_aff *pma1,
+	__isl_take isl_pw_multi_aff *pma2)
+{
+	return isl_pw_multi_aff_union_opt_cmp(pma1, pma2,
+					    &isl_multi_aff_lex_ge_set);
+}
+
+/* Given two piecewise multi affine expressions, return a piecewise
+ * multi-affine expression defined on the union of the definition domains
+ * of the inputs that is equal to the lexicographic maximum of the two
+ * inputs on each cell.  If only one of the two inputs is defined on
+ * a given cell, then it is considered to be the maximum.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmax(
+	__isl_take isl_pw_multi_aff *pma1,
+	__isl_take isl_pw_multi_aff *pma2)
+{
+	return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
+						    &pw_multi_aff_union_lexmax);
+}
+
+static __isl_give isl_pw_multi_aff *pw_multi_aff_union_lexmin(
+	__isl_take isl_pw_multi_aff *pma1,
+	__isl_take isl_pw_multi_aff *pma2)
+{
+	return isl_pw_multi_aff_union_opt_cmp(pma1, pma2,
+					    &isl_multi_aff_lex_le_set);
+}
+
+/* Given two piecewise multi affine expressions, return a piecewise
+ * multi-affine expression defined on the union of the definition domains
+ * of the inputs that is equal to the lexicographic minimum of the two
+ * inputs on each cell.  If only one of the two inputs is defined on
+ * a given cell, then it is considered to be the minimum.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin(
+	__isl_take isl_pw_multi_aff *pma1,
+	__isl_take isl_pw_multi_aff *pma2)
+{
+	return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
+						    &pw_multi_aff_union_lexmin);
+}
+
+static __isl_give isl_pw_multi_aff *pw_multi_aff_add(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+	return isl_pw_multi_aff_on_shared_domain(pma1, pma2,
+						&isl_multi_aff_add);
+}
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_add(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+	return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
+						&pw_multi_aff_add);
+}
+
+static __isl_give isl_pw_multi_aff *pw_multi_aff_sub(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+	return isl_pw_multi_aff_on_shared_domain(pma1, pma2,
+						&isl_multi_aff_sub);
+}
+
+/* Subtract "pma2" from "pma1" and return the result.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+	return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
+						&pw_multi_aff_sub);
+}
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+	return isl_pw_multi_aff_union_add_(pma1, pma2);
+}
+
+/* Compute the sum of "upa1" and "upa2" on the union of their domains,
+ * with the actual sum on the shared domain and
+ * the defined expression on the symmetric difference of the domains.
+ */
+__isl_give isl_union_pw_aff *isl_union_pw_aff_union_add(
+	__isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2)
+{
+	return isl_union_pw_aff_union_add_(upa1, upa2);
+}
+
+/* Compute the sum of "upma1" and "upma2" on the union of their domains,
+ * with the actual sum on the shared domain and
+ * the defined expression on the symmetric difference of the domains.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_union_add(
+	__isl_take isl_union_pw_multi_aff *upma1,
+	__isl_take isl_union_pw_multi_aff *upma2)
+{
+	return isl_union_pw_multi_aff_union_add_(upma1, upma2);
+}
+
+/* Given two piecewise multi-affine expressions A -> B and C -> D,
+ * construct a piecewise multi-affine expression [A -> C] -> [B -> D].
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_product(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+	int i, j, n;
+	isl_space *space;
+	isl_pw_multi_aff *res;
+
+	if (!pma1 || !pma2)
+		goto error;
+
+	n = pma1->n * pma2->n;
+	space = isl_space_product(isl_space_copy(pma1->dim),
+				  isl_space_copy(pma2->dim));
+	res = isl_pw_multi_aff_alloc_size(space, n);
+
+	for (i = 0; i < pma1->n; ++i) {
+		for (j = 0; j < pma2->n; ++j) {
+			isl_set *domain;
+			isl_multi_aff *ma;
+
+			domain = isl_set_product(isl_set_copy(pma1->p[i].set),
+						 isl_set_copy(pma2->p[j].set));
+			ma = isl_multi_aff_product(
+					isl_multi_aff_copy(pma1->p[i].maff),
+					isl_multi_aff_copy(pma2->p[j].maff));
+			res = isl_pw_multi_aff_add_piece(res, domain, ma);
+		}
+	}
+
+	isl_pw_multi_aff_free(pma1);
+	isl_pw_multi_aff_free(pma2);
+	return res;
+error:
+	isl_pw_multi_aff_free(pma1);
+	isl_pw_multi_aff_free(pma2);
+	return NULL;
+}
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_product(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+	return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
+						&pw_multi_aff_product);
+}
+
+/* Construct a map mapping the domain of the piecewise multi-affine expression
+ * to its range, with each dimension in the range equated to the
+ * corresponding affine expression on its cell.
+ *
+ * If the domain of "pma" is rational, then so is the constructed "map".
+ */
+__isl_give isl_map *isl_map_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma)
+{
+	int i;
+	isl_map *map;
+
+	if (!pma)
+		return NULL;
+
+	map = isl_map_empty(isl_pw_multi_aff_get_space(pma));
+
+	for (i = 0; i < pma->n; ++i) {
+		isl_bool rational;
+		isl_multi_aff *maff;
+		isl_basic_map *bmap;
+		isl_map *map_i;
+
+		rational = isl_set_is_rational(pma->p[i].set);
+		if (rational < 0)
+			map = isl_map_free(map);
+		maff = isl_multi_aff_copy(pma->p[i].maff);
+		bmap = isl_basic_map_from_multi_aff2(maff, rational);
+		map_i = isl_map_from_basic_map(bmap);
+		map_i = isl_map_intersect_domain(map_i,
+						isl_set_copy(pma->p[i].set));
+		map = isl_map_union_disjoint(map, map_i);
+	}
+
+	isl_pw_multi_aff_free(pma);
+	return map;
+}
+
+__isl_give isl_set *isl_set_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma)
+{
+	if (!pma)
+		return NULL;
+
+	if (!isl_space_is_set(pma->dim))
+		isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
+			"isl_pw_multi_aff cannot be converted into an isl_set",
+			goto error);
+
+	return isl_map_from_pw_multi_aff(pma);
+error:
+	isl_pw_multi_aff_free(pma);
+	return NULL;
+}
+
+/* Subtract the initial "n" elements in "ma" with coefficients in "c" and
+ * denominator "denom".
+ * "denom" is allowed to be negative, in which case the actual denominator
+ * is -denom and the expressions are added instead.
+ */
+static __isl_give isl_aff *subtract_initial(__isl_take isl_aff *aff,
+	__isl_keep isl_multi_aff *ma, int n, isl_int *c, isl_int denom)
+{
+	int i, first;
+	int sign;
+	isl_int d;
+
+	first = isl_seq_first_non_zero(c, n);
+	if (first == -1)
+		return aff;
+
+	sign = isl_int_sgn(denom);
+	isl_int_init(d);
+	isl_int_abs(d, denom);
+	for (i = first; i < n; ++i) {
+		isl_aff *aff_i;
+
+		if (isl_int_is_zero(c[i]))
+			continue;
+		aff_i = isl_multi_aff_get_aff(ma, i);
+		aff_i = isl_aff_scale(aff_i, c[i]);
+		aff_i = isl_aff_scale_down(aff_i, d);
+		if (sign >= 0)
+			aff = isl_aff_sub(aff, aff_i);
+		else
+			aff = isl_aff_add(aff, aff_i);
+	}
+	isl_int_clear(d);
+
+	return aff;
+}
+
+/* Extract an affine expression that expresses the output dimension "pos"
+ * of "bmap" in terms of the parameters and input dimensions from
+ * equality "eq".
+ * Note that this expression may involve integer divisions defined
+ * in terms of parameters and input dimensions.
+ * The equality may also involve references to earlier (but not later)
+ * output dimensions.  These are replaced by the corresponding elements
+ * in "ma".
+ *
+ * If the equality is of the form
+ *
+ *	f(i) + h(j) + a x + g(i) = 0,
+ *
+ * with f(i) a linear combinations of the parameters and input dimensions,
+ * g(i) a linear combination of integer divisions defined in terms of the same
+ * and h(j) a linear combinations of earlier output dimensions,
+ * then the affine expression is
+ *
+ *	(-f(i) - g(i))/a - h(j)/a
+ *
+ * If the equality is of the form
+ *
+ *	f(i) + h(j) - a x + g(i) = 0,
+ *
+ * then the affine expression is
+ *
+ *	(f(i) + g(i))/a - h(j)/(-a)
+ *
+ *
+ * If "div" refers to an integer division (i.e., it is smaller than
+ * the number of integer divisions), then the equality constraint
+ * does involve an integer division (the one at position "div") that
+ * is defined in terms of output dimensions.  However, this integer
+ * division can be eliminated by exploiting a pair of constraints
+ * x >= l and x <= l + n, with n smaller than the coefficient of "div"
+ * in the equality constraint.  "ineq" refers to inequality x >= l, i.e.,
+ * -l + x >= 0.
+ * In particular, let
+ *
+ *	x = e(i) + m floor(...)
+ *
+ * with e(i) the expression derived above and floor(...) the integer
+ * division involving output dimensions.
+ * From
+ *
+ *	l <= x <= l + n,
+ *
+ * we have
+ *
+ *	0 <= x - l <= n
+ *
+ * This means
+ *
+ *	e(i) + m floor(...) - l = (e(i) + m floor(...) - l) mod m
+ *	                        = (e(i) - l) mod m
+ *
+ * Therefore,
+ *
+ *	x - l = (e(i) - l) mod m
+ *
+ * or
+ *
+ *	x = ((e(i) - l) mod m) + l
+ *
+ * The variable "shift" below contains the expression -l, which may
+ * also involve a linear combination of earlier output dimensions.
+ */
+static __isl_give isl_aff *extract_aff_from_equality(
+	__isl_keep isl_basic_map *bmap, int pos, int eq, int div, int ineq,
+	__isl_keep isl_multi_aff *ma)
+{
+	unsigned o_out;
+	unsigned n_div, n_out;
+	isl_ctx *ctx;
+	isl_local_space *ls;
+	isl_aff *aff, *shift;
+	isl_val *mod;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	ls = isl_basic_map_get_local_space(bmap);
+	ls = isl_local_space_domain(ls);
+	aff = isl_aff_alloc(isl_local_space_copy(ls));
+	if (!aff)
+		goto error;
+	o_out = isl_basic_map_offset(bmap, isl_dim_out);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	if (isl_int_is_neg(bmap->eq[eq][o_out + pos])) {
+		isl_seq_cpy(aff->v->el + 1, bmap->eq[eq], o_out);
+		isl_seq_cpy(aff->v->el + 1 + o_out,
+			    bmap->eq[eq] + o_out + n_out, n_div);
+	} else {
+		isl_seq_neg(aff->v->el + 1, bmap->eq[eq], o_out);
+		isl_seq_neg(aff->v->el + 1 + o_out,
+			    bmap->eq[eq] + o_out + n_out, n_div);
+	}
+	if (div < n_div)
+		isl_int_set_si(aff->v->el[1 + o_out + div], 0);
+	isl_int_abs(aff->v->el[0], bmap->eq[eq][o_out + pos]);
+	aff = subtract_initial(aff, ma, pos, bmap->eq[eq] + o_out,
+			    bmap->eq[eq][o_out + pos]);
+	if (div < n_div) {
+		shift = isl_aff_alloc(isl_local_space_copy(ls));
+		if (!shift)
+			goto error;
+		isl_seq_cpy(shift->v->el + 1, bmap->ineq[ineq], o_out);
+		isl_seq_cpy(shift->v->el + 1 + o_out,
+			    bmap->ineq[ineq] + o_out + n_out, n_div);
+		isl_int_set_si(shift->v->el[0], 1);
+		shift = subtract_initial(shift, ma, pos,
+					bmap->ineq[ineq] + o_out, ctx->negone);
+		aff = isl_aff_add(aff, isl_aff_copy(shift));
+		mod = isl_val_int_from_isl_int(ctx,
+					    bmap->eq[eq][o_out + n_out + div]);
+		mod = isl_val_abs(mod);
+		aff = isl_aff_mod_val(aff, mod);
+		aff = isl_aff_sub(aff, shift);
+	}
+
+	isl_local_space_free(ls);
+	return aff;
+error:
+	isl_local_space_free(ls);
+	isl_aff_free(aff);
+	return NULL;
+}
+
+/* Given a basic map with output dimensions defined
+ * in terms of the parameters input dimensions and earlier
+ * output dimensions using an equality (and possibly a pair on inequalities),
+ * extract an isl_aff that expresses output dimension "pos" in terms
+ * of the parameters and input dimensions.
+ * Note that this expression may involve integer divisions defined
+ * in terms of parameters and input dimensions.
+ * "ma" contains the expressions corresponding to earlier output dimensions.
+ *
+ * This function shares some similarities with
+ * isl_basic_map_has_defining_equality and isl_constraint_get_bound.
+ */
+static __isl_give isl_aff *extract_isl_aff_from_basic_map(
+	__isl_keep isl_basic_map *bmap, int pos, __isl_keep isl_multi_aff *ma)
+{
+	int eq, div, ineq;
+	isl_aff *aff;
+
+	if (!bmap)
+		return NULL;
+	eq = isl_basic_map_output_defining_equality(bmap, pos, &div, &ineq);
+	if (eq >= bmap->n_eq)
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"unable to find suitable equality", return NULL);
+	aff = extract_aff_from_equality(bmap, pos, eq, div, ineq, ma);
+
+	aff = isl_aff_remove_unused_divs(aff);
+	return aff;
+}
+
+/* Given a basic map where each output dimension is defined
+ * in terms of the parameters and input dimensions using an equality,
+ * extract an isl_multi_aff that expresses the output dimensions in terms
+ * of the parameters and input dimensions.
+ */
+static __isl_give isl_multi_aff *extract_isl_multi_aff_from_basic_map(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+	unsigned n_out;
+	isl_multi_aff *ma;
+
+	if (!bmap)
+		return NULL;
+
+	ma = isl_multi_aff_alloc(isl_basic_map_get_space(bmap));
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+
+	for (i = 0; i < n_out; ++i) {
+		isl_aff *aff;
+
+		aff = extract_isl_aff_from_basic_map(bmap, i, ma);
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+
+	isl_basic_map_free(bmap);
+
+	return ma;
+}
+
+/* Given a basic set where each set dimension is defined
+ * in terms of the parameters using an equality,
+ * extract an isl_multi_aff that expresses the set dimensions in terms
+ * of the parameters.
+ */
+__isl_give isl_multi_aff *isl_multi_aff_from_basic_set_equalities(
+	__isl_take isl_basic_set *bset)
+{
+	return extract_isl_multi_aff_from_basic_map(bset);
+}
+
+/* Create an isl_pw_multi_aff that is equivalent to
+ * isl_map_intersect_domain(isl_map_from_basic_map(bmap), domain).
+ * The given basic map is such that each output dimension is defined
+ * in terms of the parameters and input dimensions using an equality.
+ *
+ * Since some applications expect the result of isl_pw_multi_aff_from_map
+ * to only contain integer affine expressions, we compute the floor
+ * of the expression before returning.
+ *
+ * Remove all constraints involving local variables without
+ * an explicit representation (resulting in the removal of those
+ * local variables) prior to the actual extraction to ensure
+ * that the local spaces in which the resulting affine expressions
+ * are created do not contain any unknown local variables.
+ * Removing such constraints is safe because constraints involving
+ * unknown local variables are not used to determine whether
+ * a basic map is obviously single-valued.
+ */
+static __isl_give isl_pw_multi_aff *plain_pw_multi_aff_from_map(
+	__isl_take isl_set *domain, __isl_take isl_basic_map *bmap)
+{
+	isl_multi_aff *ma;
+
+	bmap = isl_basic_map_drop_constraint_involving_unknown_divs(bmap);
+	ma = extract_isl_multi_aff_from_basic_map(bmap);
+	ma = isl_multi_aff_floor(ma);
+	return isl_pw_multi_aff_alloc(domain, ma);
+}
+
+/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map.
+ * This obviously only works if the input "map" is single-valued.
+ * If so, we compute the lexicographic minimum of the image in the form
+ * of an isl_pw_multi_aff.  Since the image is unique, it is equal
+ * to its lexicographic minimum.
+ * If the input is not single-valued, we produce an error.
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_base(
+	__isl_take isl_map *map)
+{
+	int i;
+	int sv;
+	isl_pw_multi_aff *pma;
+
+	sv = isl_map_is_single_valued(map);
+	if (sv < 0)
+		goto error;
+	if (!sv)
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"map is not single-valued", goto error);
+	map = isl_map_make_disjoint(map);
+	if (!map)
+		return NULL;
+
+	pma = isl_pw_multi_aff_empty(isl_map_get_space(map));
+
+	for (i = 0; i < map->n; ++i) {
+		isl_pw_multi_aff *pma_i;
+		isl_basic_map *bmap;
+		bmap = isl_basic_map_copy(map->p[i]);
+		pma_i = isl_basic_map_lexmin_pw_multi_aff(bmap);
+		pma = isl_pw_multi_aff_add_disjoint(pma, pma_i);
+	}
+
+	isl_map_free(map);
+	return pma;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map,
+ * taking into account that the output dimension at position "d"
+ * can be represented as
+ *
+ *	x = floor((e(...) + c1) / m)
+ *
+ * given that constraint "i" is of the form
+ *
+ *	e(...) + c1 - m x >= 0
+ *
+ *
+ * Let "map" be of the form
+ *
+ *	A -> B
+ *
+ * We construct a mapping
+ *
+ *	A -> [A -> x = floor(...)]
+ *
+ * apply that to the map, obtaining
+ *
+ *	[A -> x = floor(...)] -> B
+ *
+ * and equate dimension "d" to x.
+ * We then compute a isl_pw_multi_aff representation of the resulting map
+ * and plug in the mapping above.
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_div(
+	__isl_take isl_map *map, __isl_take isl_basic_map *hull, int d, int i)
+{
+	isl_ctx *ctx;
+	isl_space *space;
+	isl_local_space *ls;
+	isl_multi_aff *ma;
+	isl_aff *aff;
+	isl_vec *v;
+	isl_map *insert;
+	int offset;
+	int n;
+	int n_in;
+	isl_pw_multi_aff *pma;
+	isl_bool is_set;
+
+	is_set = isl_map_is_set(map);
+	if (is_set < 0)
+		goto error;
+
+	offset = isl_basic_map_offset(hull, isl_dim_out);
+	ctx = isl_map_get_ctx(map);
+	space = isl_space_domain(isl_map_get_space(map));
+	n_in = isl_space_dim(space, isl_dim_set);
+	n = isl_space_dim(space, isl_dim_all);
+
+	v = isl_vec_alloc(ctx, 1 + 1 + n);
+	if (v) {
+		isl_int_neg(v->el[0], hull->ineq[i][offset + d]);
+		isl_seq_cpy(v->el + 1, hull->ineq[i], 1 + n);
+	}
+	isl_basic_map_free(hull);
+
+	ls = isl_local_space_from_space(isl_space_copy(space));
+	aff = isl_aff_alloc_vec(ls, v);
+	aff = isl_aff_floor(aff);
+	if (is_set) {
+		isl_space_free(space);
+		ma = isl_multi_aff_from_aff(aff);
+	} else {
+		ma = isl_multi_aff_identity(isl_space_map_from_set(space));
+		ma = isl_multi_aff_range_product(ma,
+						isl_multi_aff_from_aff(aff));
+	}
+
+	insert = isl_map_from_multi_aff(isl_multi_aff_copy(ma));
+	map = isl_map_apply_domain(map, insert);
+	map = isl_map_equate(map, isl_dim_in, n_in, isl_dim_out, d);
+	pma = isl_pw_multi_aff_from_map(map);
+	pma = isl_pw_multi_aff_pullback_multi_aff(pma, ma);
+
+	return pma;
+error:
+	isl_map_free(map);
+	isl_basic_map_free(hull);
+	return NULL;
+}
+
+/* Is constraint "c" of the form
+ *
+ *	e(...) + c1 - m x >= 0
+ *
+ * or
+ *
+ *	-e(...) + c2 + m x >= 0
+ *
+ * where m > 1 and e only depends on parameters and input dimemnsions?
+ *
+ * "offset" is the offset of the output dimensions
+ * "pos" is the position of output dimension x.
+ */
+static int is_potential_div_constraint(isl_int *c, int offset, int d, int total)
+{
+	if (isl_int_is_zero(c[offset + d]))
+		return 0;
+	if (isl_int_is_one(c[offset + d]))
+		return 0;
+	if (isl_int_is_negone(c[offset + d]))
+		return 0;
+	if (isl_seq_first_non_zero(c + offset, d) != -1)
+		return 0;
+	if (isl_seq_first_non_zero(c + offset + d + 1,
+				    total - (offset + d + 1)) != -1)
+		return 0;
+	return 1;
+}
+
+/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map.
+ *
+ * As a special case, we first check if there is any pair of constraints,
+ * shared by all the basic maps in "map" that force a given dimension
+ * to be equal to the floor of some affine combination of the input dimensions.
+ *
+ * In particular, if we can find two constraints
+ *
+ *	e(...) + c1 - m x >= 0		i.e.,		m x <= e(...) + c1
+ *
+ * and
+ *
+ *	-e(...) + c2 + m x >= 0		i.e.,		m x >= e(...) - c2
+ *
+ * where m > 1 and e only depends on parameters and input dimemnsions,
+ * and such that
+ *
+ *	c1 + c2 < m			i.e.,		-c2 >= c1 - (m - 1)
+ *
+ * then we know that we can take
+ *
+ *	x = floor((e(...) + c1) / m)
+ *
+ * without having to perform any computation.
+ *
+ * Note that we know that
+ *
+ *	c1 + c2 >= 1
+ *
+ * If c1 + c2 were 0, then we would have detected an equality during
+ * simplification.  If c1 + c2 were negative, then we would have detected
+ * a contradiction.
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_check_div(
+	__isl_take isl_map *map)
+{
+	int d, dim;
+	int i, j, n;
+	int offset, total;
+	isl_int sum;
+	isl_basic_map *hull;
+
+	hull = isl_map_unshifted_simple_hull(isl_map_copy(map));
+	if (!hull)
+		goto error;
+
+	isl_int_init(sum);
+	dim = isl_map_dim(map, isl_dim_out);
+	offset = isl_basic_map_offset(hull, isl_dim_out);
+	total = 1 + isl_basic_map_total_dim(hull);
+	n = hull->n_ineq;
+	for (d = 0; d < dim; ++d) {
+		for (i = 0; i < n; ++i) {
+			if (!is_potential_div_constraint(hull->ineq[i],
+							offset, d, total))
+				continue;
+			for (j = i + 1; j < n; ++j) {
+				if (!isl_seq_is_neg(hull->ineq[i] + 1,
+						hull->ineq[j] + 1, total - 1))
+					continue;
+				isl_int_add(sum, hull->ineq[i][0],
+						hull->ineq[j][0]);
+				if (isl_int_abs_lt(sum,
+						    hull->ineq[i][offset + d]))
+					break;
+
+			}
+			if (j >= n)
+				continue;
+			isl_int_clear(sum);
+			if (isl_int_is_pos(hull->ineq[j][offset + d]))
+				j = i;
+			return pw_multi_aff_from_map_div(map, hull, d, j);
+		}
+	}
+	isl_int_clear(sum);
+	isl_basic_map_free(hull);
+	return pw_multi_aff_from_map_base(map);
+error:
+	isl_map_free(map);
+	isl_basic_map_free(hull);
+	return NULL;
+}
+
+/* Given an affine expression
+ *
+ *	[A -> B] -> f(A,B)
+ *
+ * construct an isl_multi_aff
+ *
+ *	[A -> B] -> B'
+ *
+ * such that dimension "d" in B' is set to "aff" and the remaining
+ * dimensions are set equal to the corresponding dimensions in B.
+ * "n_in" is the dimension of the space A.
+ * "n_out" is the dimension of the space B.
+ *
+ * If "is_set" is set, then the affine expression is of the form
+ *
+ *	[B] -> f(B)
+ *
+ * and we construct an isl_multi_aff
+ *
+ *	B -> B'
+ */
+static __isl_give isl_multi_aff *range_map(__isl_take isl_aff *aff, int d,
+	unsigned n_in, unsigned n_out, int is_set)
+{
+	int i;
+	isl_multi_aff *ma;
+	isl_space *space, *space2;
+	isl_local_space *ls;
+
+	space = isl_aff_get_domain_space(aff);
+	ls = isl_local_space_from_space(isl_space_copy(space));
+	space2 = isl_space_copy(space);
+	if (!is_set)
+		space2 = isl_space_range(isl_space_unwrap(space2));
+	space = isl_space_map_from_domain_and_range(space, space2);
+	ma = isl_multi_aff_alloc(space);
+	ma = isl_multi_aff_set_aff(ma, d, aff);
+
+	for (i = 0; i < n_out; ++i) {
+		if (i == d)
+			continue;
+		aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
+						isl_dim_set, n_in + i);
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+
+	isl_local_space_free(ls);
+
+	return ma;
+}
+
+/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map,
+ * taking into account that the dimension at position "d" can be written as
+ *
+ *	x = m a + f(..)						(1)
+ *
+ * where m is equal to "gcd".
+ * "i" is the index of the equality in "hull" that defines f(..).
+ * In particular, the equality is of the form
+ *
+ *	f(..) - x + m g(existentials) = 0
+ *
+ * or
+ *
+ *	-f(..) + x + m g(existentials) = 0
+ *
+ * We basically plug (1) into "map", resulting in a map with "a"
+ * in the range instead of "x".  The corresponding isl_pw_multi_aff
+ * defining "a" is then plugged back into (1) to obtain a definition for "x".
+ *
+ * Specifically, given the input map
+ *
+ *	A -> B
+ *
+ * We first wrap it into a set
+ *
+ *	[A -> B]
+ *
+ * and define (1) on top of the corresponding space, resulting in "aff".
+ * We use this to create an isl_multi_aff that maps the output position "d"
+ * from "a" to "x", leaving all other (intput and output) dimensions unchanged.
+ * We plug this into the wrapped map, unwrap the result and compute the
+ * corresponding isl_pw_multi_aff.
+ * The result is an expression
+ *
+ *	A -> T(A)
+ *
+ * We adjust that to
+ *
+ *	A -> [A -> T(A)]
+ *
+ * so that we can plug that into "aff", after extending the latter to
+ * a mapping
+ *
+ *	[A -> B] -> B'
+ *
+ *
+ * If "map" is actually a set, then there is no "A" space, meaning
+ * that we do not need to perform any wrapping, and that the result
+ * of the recursive call is of the form
+ *
+ *	[T]
+ *
+ * which is plugged into a mapping of the form
+ *
+ *	B -> B'
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_stride(
+	__isl_take isl_map *map, __isl_take isl_basic_map *hull, int d, int i,
+	isl_int gcd)
+{
+	isl_set *set;
+	isl_space *space;
+	isl_local_space *ls;
+	isl_aff *aff;
+	isl_multi_aff *ma;
+	isl_pw_multi_aff *pma, *id;
+	unsigned n_in;
+	unsigned o_out;
+	unsigned n_out;
+	isl_bool is_set;
+
+	is_set = isl_map_is_set(map);
+	if (is_set < 0)
+		goto error;
+
+	n_in = isl_basic_map_dim(hull, isl_dim_in);
+	n_out = isl_basic_map_dim(hull, isl_dim_out);
+	o_out = isl_basic_map_offset(hull, isl_dim_out);
+
+	if (is_set)
+		set = map;
+	else
+		set = isl_map_wrap(map);
+	space = isl_space_map_from_set(isl_set_get_space(set));
+	ma = isl_multi_aff_identity(space);
+	ls = isl_local_space_from_space(isl_set_get_space(set));
+	aff = isl_aff_alloc(ls);
+	if (aff) {
+		isl_int_set_si(aff->v->el[0], 1);
+		if (isl_int_is_one(hull->eq[i][o_out + d]))
+			isl_seq_neg(aff->v->el + 1, hull->eq[i],
+				    aff->v->size - 1);
+		else
+			isl_seq_cpy(aff->v->el + 1, hull->eq[i],
+				    aff->v->size - 1);
+		isl_int_set(aff->v->el[1 + o_out + d], gcd);
+	}
+	ma = isl_multi_aff_set_aff(ma, n_in + d, isl_aff_copy(aff));
+	set = isl_set_preimage_multi_aff(set, ma);
+
+	ma = range_map(aff, d, n_in, n_out, is_set);
+
+	if (is_set)
+		map = set;
+	else
+		map = isl_set_unwrap(set);
+	pma = isl_pw_multi_aff_from_map(map);
+
+	if (!is_set) {
+		space = isl_pw_multi_aff_get_domain_space(pma);
+		space = isl_space_map_from_set(space);
+		id = isl_pw_multi_aff_identity(space);
+		pma = isl_pw_multi_aff_range_product(id, pma);
+	}
+	id = isl_pw_multi_aff_from_multi_aff(ma);
+	pma = isl_pw_multi_aff_pullback_pw_multi_aff(id, pma);
+
+	isl_basic_map_free(hull);
+	return pma;
+error:
+	isl_map_free(map);
+	isl_basic_map_free(hull);
+	return NULL;
+}
+
+/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map.
+ * "hull" contains the equalities valid for "map".
+ *
+ * Check if any of the output dimensions is "strided".
+ * That is, we check if it can be written as
+ *
+ *	x = m a + f(..)
+ *
+ * with m greater than 1, a some combination of existentially quantified
+ * variables and f an expression in the parameters and input dimensions.
+ * If so, we remove the stride in pw_multi_aff_from_map_stride.
+ *
+ * Otherwise, we continue with pw_multi_aff_from_map_check_div for a further
+ * special case.
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_check_strides(
+	__isl_take isl_map *map, __isl_take isl_basic_map *hull)
+{
+	int i, j;
+	unsigned n_out;
+	unsigned o_out;
+	unsigned n_div;
+	unsigned o_div;
+	isl_int gcd;
+
+	n_div = isl_basic_map_dim(hull, isl_dim_div);
+	o_div = isl_basic_map_offset(hull, isl_dim_div);
+
+	if (n_div == 0) {
+		isl_basic_map_free(hull);
+		return pw_multi_aff_from_map_check_div(map);
+	}
+
+	isl_int_init(gcd);
+
+	n_out = isl_basic_map_dim(hull, isl_dim_out);
+	o_out = isl_basic_map_offset(hull, isl_dim_out);
+
+	for (i = 0; i < n_out; ++i) {
+		for (j = 0; j < hull->n_eq; ++j) {
+			isl_int *eq = hull->eq[j];
+			isl_pw_multi_aff *res;
+
+			if (!isl_int_is_one(eq[o_out + i]) &&
+			    !isl_int_is_negone(eq[o_out + i]))
+				continue;
+			if (isl_seq_first_non_zero(eq + o_out, i) != -1)
+				continue;
+			if (isl_seq_first_non_zero(eq + o_out + i + 1,
+						    n_out - (i + 1)) != -1)
+				continue;
+			isl_seq_gcd(eq + o_div, n_div, &gcd);
+			if (isl_int_is_zero(gcd))
+				continue;
+			if (isl_int_is_one(gcd))
+				continue;
+
+			res = pw_multi_aff_from_map_stride(map, hull,
+								i, j, gcd);
+			isl_int_clear(gcd);
+			return res;
+		}
+	}
+
+	isl_int_clear(gcd);
+	isl_basic_map_free(hull);
+	return pw_multi_aff_from_map_check_div(map);
+}
+
+/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map.
+ *
+ * As a special case, we first check if all output dimensions are uniquely
+ * defined in terms of the parameters and input dimensions over the entire
+ * domain.  If so, we extract the desired isl_pw_multi_aff directly
+ * from the affine hull of "map" and its domain.
+ *
+ * Otherwise, continue with pw_multi_aff_from_map_check_strides for more
+ * special cases.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map(__isl_take isl_map *map)
+{
+	isl_bool sv;
+	isl_basic_map *hull;
+
+	if (!map)
+		return NULL;
+
+	if (isl_map_n_basic_map(map) == 1) {
+		hull = isl_map_unshifted_simple_hull(isl_map_copy(map));
+		hull = isl_basic_map_plain_affine_hull(hull);
+		sv = isl_basic_map_plain_is_single_valued(hull);
+		if (sv >= 0 && sv)
+			return plain_pw_multi_aff_from_map(isl_map_domain(map),
+							    hull);
+		isl_basic_map_free(hull);
+	}
+	map = isl_map_detect_equalities(map);
+	hull = isl_map_unshifted_simple_hull(isl_map_copy(map));
+	sv = isl_basic_map_plain_is_single_valued(hull);
+	if (sv >= 0 && sv)
+		return plain_pw_multi_aff_from_map(isl_map_domain(map), hull);
+	if (sv >= 0)
+		return pw_multi_aff_from_map_check_strides(map, hull);
+	isl_basic_map_free(hull);
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(__isl_take isl_set *set)
+{
+	return isl_pw_multi_aff_from_map(set);
+}
+
+/* Convert "map" into an isl_pw_multi_aff (if possible) and
+ * add it to *user.
+ */
+static isl_stat pw_multi_aff_from_map(__isl_take isl_map *map, void *user)
+{
+	isl_union_pw_multi_aff **upma = user;
+	isl_pw_multi_aff *pma;
+
+	pma = isl_pw_multi_aff_from_map(map);
+	*upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma);
+
+	return *upma ? isl_stat_ok : isl_stat_error;
+}
+
+/* Create an isl_union_pw_multi_aff with the given isl_aff on a universe
+ * domain.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_aff(
+	__isl_take isl_aff *aff)
+{
+	isl_multi_aff *ma;
+	isl_pw_multi_aff *pma;
+
+	ma = isl_multi_aff_from_aff(aff);
+	pma = isl_pw_multi_aff_from_multi_aff(ma);
+	return isl_union_pw_multi_aff_from_pw_multi_aff(pma);
+}
+
+/* Try and create an isl_union_pw_multi_aff that is equivalent
+ * to the given isl_union_map.
+ * The isl_union_map is required to be single-valued in each space.
+ * Otherwise, an error is produced.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_map(
+	__isl_take isl_union_map *umap)
+{
+	isl_space *space;
+	isl_union_pw_multi_aff *upma;
+
+	space = isl_union_map_get_space(umap);
+	upma = isl_union_pw_multi_aff_empty(space);
+	if (isl_union_map_foreach_map(umap, &pw_multi_aff_from_map, &upma) < 0)
+		upma = isl_union_pw_multi_aff_free(upma);
+	isl_union_map_free(umap);
+
+	return upma;
+}
+
+/* Try and create an isl_union_pw_multi_aff that is equivalent
+ * to the given isl_union_set.
+ * The isl_union_set is required to be a singleton in each space.
+ * Otherwise, an error is produced.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_set(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_pw_multi_aff_from_union_map(uset);
+}
+
+/* Return the piecewise affine expression "set ? 1 : 0".
+ */
+__isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set)
+{
+	isl_pw_aff *pa;
+	isl_space *space = isl_set_get_space(set);
+	isl_local_space *ls = isl_local_space_from_space(space);
+	isl_aff *zero = isl_aff_zero_on_domain(isl_local_space_copy(ls));
+	isl_aff *one = isl_aff_zero_on_domain(ls);
+
+	one = isl_aff_add_constant_si(one, 1);
+	pa = isl_pw_aff_alloc(isl_set_copy(set), one);
+	set = isl_set_complement(set);
+	pa = isl_pw_aff_add_disjoint(pa, isl_pw_aff_alloc(set, zero));
+
+	return pa;
+}
+
+/* Plug in "subs" for dimension "type", "pos" of "aff".
+ *
+ * Let i be the dimension to replace and let "subs" be of the form
+ *
+ *	f/d
+ *
+ * and "aff" of the form
+ *
+ *	(a i + g)/m
+ *
+ * The result is
+ *
+ *	(a f + d g')/(m d)
+ *
+ * where g' is the result of plugging in "subs" in each of the integer
+ * divisions in g.
+ */
+__isl_give isl_aff *isl_aff_substitute(__isl_take isl_aff *aff,
+	enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
+{
+	isl_ctx *ctx;
+	isl_int v;
+
+	aff = isl_aff_cow(aff);
+	if (!aff || !subs)
+		return isl_aff_free(aff);
+
+	ctx = isl_aff_get_ctx(aff);
+	if (!isl_space_is_equal(aff->ls->dim, subs->ls->dim))
+		isl_die(ctx, isl_error_invalid,
+			"spaces don't match", return isl_aff_free(aff));
+	if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
+		isl_die(ctx, isl_error_unsupported,
+			"cannot handle divs yet", return isl_aff_free(aff));
+
+	aff->ls = isl_local_space_substitute(aff->ls, type, pos, subs);
+	if (!aff->ls)
+		return isl_aff_free(aff);
+
+	aff->v = isl_vec_cow(aff->v);
+	if (!aff->v)
+		return isl_aff_free(aff);
+
+	pos += isl_local_space_offset(aff->ls, type);
+
+	isl_int_init(v);
+	isl_seq_substitute(aff->v->el, pos, subs->v->el,
+			    aff->v->size, subs->v->size, v);
+	isl_int_clear(v);
+
+	return aff;
+}
+
+/* Plug in "subs" for dimension "type", "pos" in each of the affine
+ * expressions in "maff".
+ */
+__isl_give isl_multi_aff *isl_multi_aff_substitute(
+	__isl_take isl_multi_aff *maff, enum isl_dim_type type, unsigned pos,
+	__isl_keep isl_aff *subs)
+{
+	int i;
+
+	maff = isl_multi_aff_cow(maff);
+	if (!maff || !subs)
+		return isl_multi_aff_free(maff);
+
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	for (i = 0; i < maff->n; ++i) {
+		maff->p[i] = isl_aff_substitute(maff->p[i], type, pos, subs);
+		if (!maff->p[i])
+			return isl_multi_aff_free(maff);
+	}
+
+	return maff;
+}
+
+/* Plug in "subs" for dimension "type", "pos" of "pma".
+ *
+ * pma is of the form
+ *
+ *	A_i(v) -> M_i(v)
+ *
+ * while subs is of the form
+ *
+ *	v' = B_j(v) -> S_j
+ *
+ * Each pair i,j such that C_ij = A_i \cap B_i is non-empty
+ * has a contribution in the result, in particular
+ *
+ *	C_ij(S_j) -> M_i(S_j)
+ *
+ * Note that plugging in S_j in C_ij may also result in an empty set
+ * and this contribution should simply be discarded.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_substitute(
+	__isl_take isl_pw_multi_aff *pma, enum isl_dim_type type, unsigned pos,
+	__isl_keep isl_pw_aff *subs)
+{
+	int i, j, n;
+	isl_pw_multi_aff *res;
+
+	if (!pma || !subs)
+		return isl_pw_multi_aff_free(pma);
+
+	n = pma->n * subs->n;
+	res = isl_pw_multi_aff_alloc_size(isl_space_copy(pma->dim), n);
+
+	for (i = 0; i < pma->n; ++i) {
+		for (j = 0; j < subs->n; ++j) {
+			isl_set *common;
+			isl_multi_aff *res_ij;
+			int empty;
+
+			common = isl_set_intersect(
+					isl_set_copy(pma->p[i].set),
+					isl_set_copy(subs->p[j].set));
+			common = isl_set_substitute(common,
+					type, pos, subs->p[j].aff);
+			empty = isl_set_plain_is_empty(common);
+			if (empty < 0 || empty) {
+				isl_set_free(common);
+				if (empty < 0)
+					goto error;
+				continue;
+			}
+
+			res_ij = isl_multi_aff_substitute(
+					isl_multi_aff_copy(pma->p[i].maff),
+					type, pos, subs->p[j].aff);
+
+			res = isl_pw_multi_aff_add_piece(res, common, res_ij);
+		}
+	}
+
+	isl_pw_multi_aff_free(pma);
+	return res;
+error:
+	isl_pw_multi_aff_free(pma);
+	isl_pw_multi_aff_free(res);
+	return NULL;
+}
+
+/* Compute the preimage of a range of dimensions in the affine expression "src"
+ * under "ma" and put the result in "dst".  The number of dimensions in "src"
+ * that precede the range is given by "n_before".  The number of dimensions
+ * in the range is given by the number of output dimensions of "ma".
+ * The number of dimensions that follow the range is given by "n_after".
+ * If "has_denom" is set (to one),
+ * then "src" and "dst" have an extra initial denominator.
+ * "n_div_ma" is the number of existentials in "ma"
+ * "n_div_bset" is the number of existentials in "src"
+ * The resulting "dst" (which is assumed to have been allocated by
+ * the caller) contains coefficients for both sets of existentials,
+ * first those in "ma" and then those in "src".
+ * f, c1, c2 and g are temporary objects that have been initialized
+ * by the caller.
+ *
+ * Let src represent the expression
+ *
+ *	(a(p) + f_u u + b v + f_w w + c(divs))/d
+ *
+ * and let ma represent the expressions
+ *
+ *	v_i = (r_i(p) + s_i(y) + t_i(divs'))/m_i
+ *
+ * We start out with the following expression for dst:
+ *
+ *	(a(p) + f_u u + 0 y + f_w w + 0 divs' + c(divs) + f \sum_i b_i v_i)/d
+ *
+ * with the multiplication factor f initially equal to 1
+ * and f \sum_i b_i v_i kept separately.
+ * For each x_i that we substitute, we multiply the numerator
+ * (and denominator) of dst by c_1 = m_i and add the numerator
+ * of the x_i expression multiplied by c_2 = f b_i,
+ * after removing the common factors of c_1 and c_2.
+ * The multiplication factor f also needs to be multiplied by c_1
+ * for the next x_j, j > i.
+ */
+void isl_seq_preimage(isl_int *dst, isl_int *src,
+	__isl_keep isl_multi_aff *ma, int n_before, int n_after,
+	int n_div_ma, int n_div_bmap,
+	isl_int f, isl_int c1, isl_int c2, isl_int g, int has_denom)
+{
+	int i;
+	int n_param, n_in, n_out;
+	int o_dst, o_src;
+
+	n_param = isl_multi_aff_dim(ma, isl_dim_param);
+	n_in = isl_multi_aff_dim(ma, isl_dim_in);
+	n_out = isl_multi_aff_dim(ma, isl_dim_out);
+
+	isl_seq_cpy(dst, src, has_denom + 1 + n_param + n_before);
+	o_dst = o_src = has_denom + 1 + n_param + n_before;
+	isl_seq_clr(dst + o_dst, n_in);
+	o_dst += n_in;
+	o_src += n_out;
+	isl_seq_cpy(dst + o_dst, src + o_src, n_after);
+	o_dst += n_after;
+	o_src += n_after;
+	isl_seq_clr(dst + o_dst, n_div_ma);
+	o_dst += n_div_ma;
+	isl_seq_cpy(dst + o_dst, src + o_src, n_div_bmap);
+
+	isl_int_set_si(f, 1);
+
+	for (i = 0; i < n_out; ++i) {
+		int offset = has_denom + 1 + n_param + n_before + i;
+
+		if (isl_int_is_zero(src[offset]))
+			continue;
+		isl_int_set(c1, ma->p[i]->v->el[0]);
+		isl_int_mul(c2, f, src[offset]);
+		isl_int_gcd(g, c1, c2);
+		isl_int_divexact(c1, c1, g);
+		isl_int_divexact(c2, c2, g);
+
+		isl_int_mul(f, f, c1);
+		o_dst = has_denom;
+		o_src = 1;
+		isl_seq_combine(dst + o_dst, c1, dst + o_dst,
+				c2, ma->p[i]->v->el + o_src, 1 + n_param);
+		o_dst += 1 + n_param;
+		o_src += 1 + n_param;
+		isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_before);
+		o_dst += n_before;
+		isl_seq_combine(dst + o_dst, c1, dst + o_dst,
+				c2, ma->p[i]->v->el + o_src, n_in);
+		o_dst += n_in;
+		o_src += n_in;
+		isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_after);
+		o_dst += n_after;
+		isl_seq_combine(dst + o_dst, c1, dst + o_dst,
+				c2, ma->p[i]->v->el + o_src, n_div_ma);
+		o_dst += n_div_ma;
+		o_src += n_div_ma;
+		isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_div_bmap);
+		if (has_denom)
+			isl_int_mul(dst[0], dst[0], c1);
+	}
+}
+
+/* Compute the pullback of "aff" by the function represented by "ma".
+ * In other words, plug in "ma" in "aff".  The result is an affine expression
+ * defined over the domain space of "ma".
+ *
+ * If "aff" is represented by
+ *
+ *	(a(p) + b x + c(divs))/d
+ *
+ * and ma is represented by
+ *
+ *	x = D(p) + F(y) + G(divs')
+ *
+ * then the result is
+ *
+ *	(a(p) + b D(p) + b F(y) + b G(divs') + c(divs))/d
+ *
+ * The divs in the local space of the input are similarly adjusted
+ * through a call to isl_local_space_preimage_multi_aff.
+ */
+__isl_give isl_aff *isl_aff_pullback_multi_aff(__isl_take isl_aff *aff,
+	__isl_take isl_multi_aff *ma)
+{
+	isl_aff *res = NULL;
+	isl_local_space *ls;
+	int n_div_aff, n_div_ma;
+	isl_int f, c1, c2, g;
+
+	ma = isl_multi_aff_align_divs(ma);
+	if (!aff || !ma)
+		goto error;
+
+	n_div_aff = isl_aff_dim(aff, isl_dim_div);
+	n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0;
+
+	ls = isl_aff_get_domain_local_space(aff);
+	ls = isl_local_space_preimage_multi_aff(ls, isl_multi_aff_copy(ma));
+	res = isl_aff_alloc(ls);
+	if (!res)
+		goto error;
+
+	isl_int_init(f);
+	isl_int_init(c1);
+	isl_int_init(c2);
+	isl_int_init(g);
+
+	isl_seq_preimage(res->v->el, aff->v->el, ma, 0, 0, n_div_ma, n_div_aff,
+			f, c1, c2, g, 1);
+
+	isl_int_clear(f);
+	isl_int_clear(c1);
+	isl_int_clear(c2);
+	isl_int_clear(g);
+
+	isl_aff_free(aff);
+	isl_multi_aff_free(ma);
+	res = isl_aff_normalize(res);
+	return res;
+error:
+	isl_aff_free(aff);
+	isl_multi_aff_free(ma);
+	isl_aff_free(res);
+	return NULL;
+}
+
+/* Compute the pullback of "aff1" by the function represented by "aff2".
+ * In other words, plug in "aff2" in "aff1".  The result is an affine expression
+ * defined over the domain space of "aff1".
+ *
+ * The domain of "aff1" should match the range of "aff2", which means
+ * that it should be single-dimensional.
+ */
+__isl_give isl_aff *isl_aff_pullback_aff(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2)
+{
+	isl_multi_aff *ma;
+
+	ma = isl_multi_aff_from_aff(aff2);
+	return isl_aff_pullback_multi_aff(aff1, ma);
+}
+
+/* Compute the pullback of "ma1" by the function represented by "ma2".
+ * In other words, plug in "ma2" in "ma1".
+ *
+ * The parameters of "ma1" and "ma2" are assumed to have been aligned.
+ */
+static __isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff_aligned(
+	__isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2)
+{
+	int i;
+	isl_space *space = NULL;
+
+	ma2 = isl_multi_aff_align_divs(ma2);
+	ma1 = isl_multi_aff_cow(ma1);
+	if (!ma1 || !ma2)
+		goto error;
+
+	space = isl_space_join(isl_multi_aff_get_space(ma2),
+				isl_multi_aff_get_space(ma1));
+
+	for (i = 0; i < ma1->n; ++i) {
+		ma1->p[i] = isl_aff_pullback_multi_aff(ma1->p[i],
+						    isl_multi_aff_copy(ma2));
+		if (!ma1->p[i])
+			goto error;
+	}
+
+	ma1 = isl_multi_aff_reset_space(ma1, space);
+	isl_multi_aff_free(ma2);
+	return ma1;
+error:
+	isl_space_free(space);
+	isl_multi_aff_free(ma2);
+	isl_multi_aff_free(ma1);
+	return NULL;
+}
+
+/* Compute the pullback of "ma1" by the function represented by "ma2".
+ * In other words, plug in "ma2" in "ma1".
+ */
+__isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff(
+	__isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2)
+{
+	return isl_multi_aff_align_params_multi_multi_and(ma1, ma2,
+				&isl_multi_aff_pullback_multi_aff_aligned);
+}
+
+/* Extend the local space of "dst" to include the divs
+ * in the local space of "src".
+ *
+ * If "src" does not have any divs or if the local spaces of "dst" and
+ * "src" are the same, then no extension is required.
+ */
+__isl_give isl_aff *isl_aff_align_divs(__isl_take isl_aff *dst,
+	__isl_keep isl_aff *src)
+{
+	isl_ctx *ctx;
+	int src_n_div, dst_n_div;
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_bool equal;
+	isl_mat *div;
+
+	if (!src || !dst)
+		return isl_aff_free(dst);
+
+	ctx = isl_aff_get_ctx(src);
+	equal = isl_local_space_has_equal_space(src->ls, dst->ls);
+	if (equal < 0)
+		return isl_aff_free(dst);
+	if (!equal)
+		isl_die(ctx, isl_error_invalid,
+			"spaces don't match", goto error);
+
+	src_n_div = isl_local_space_dim(src->ls, isl_dim_div);
+	if (src_n_div == 0)
+		return dst;
+	equal = isl_local_space_is_equal(src->ls, dst->ls);
+	if (equal < 0)
+		return isl_aff_free(dst);
+	if (equal)
+		return dst;
+
+	dst_n_div = isl_local_space_dim(dst->ls, isl_dim_div);
+	exp1 = isl_alloc_array(ctx, int, src_n_div);
+	exp2 = isl_alloc_array(ctx, int, dst_n_div);
+	if (!exp1 || (dst_n_div && !exp2))
+		goto error;
+
+	div = isl_merge_divs(src->ls->div, dst->ls->div, exp1, exp2);
+	dst = isl_aff_expand_divs(dst, div, exp2);
+	free(exp1);
+	free(exp2);
+
+	return dst;
+error:
+	free(exp1);
+	free(exp2);
+	return isl_aff_free(dst);
+}
+
+/* Adjust the local spaces of the affine expressions in "maff"
+ * such that they all have the save divs.
+ */
+__isl_give isl_multi_aff *isl_multi_aff_align_divs(
+	__isl_take isl_multi_aff *maff)
+{
+	int i;
+
+	if (!maff)
+		return NULL;
+	if (maff->n == 0)
+		return maff;
+	maff = isl_multi_aff_cow(maff);
+	if (!maff)
+		return NULL;
+
+	for (i = 1; i < maff->n; ++i)
+		maff->p[0] = isl_aff_align_divs(maff->p[0], maff->p[i]);
+	for (i = 1; i < maff->n; ++i) {
+		maff->p[i] = isl_aff_align_divs(maff->p[i], maff->p[0]);
+		if (!maff->p[i])
+			return isl_multi_aff_free(maff);
+	}
+
+	return maff;
+}
+
+__isl_give isl_aff *isl_aff_lift(__isl_take isl_aff *aff)
+{
+	aff = isl_aff_cow(aff);
+	if (!aff)
+		return NULL;
+
+	aff->ls = isl_local_space_lift(aff->ls);
+	if (!aff->ls)
+		return isl_aff_free(aff);
+
+	return aff;
+}
+
+/* Lift "maff" to a space with extra dimensions such that the result
+ * has no more existentially quantified variables.
+ * If "ls" is not NULL, then *ls is assigned the local space that lies
+ * at the basis of the lifting applied to "maff".
+ */
+__isl_give isl_multi_aff *isl_multi_aff_lift(__isl_take isl_multi_aff *maff,
+	__isl_give isl_local_space **ls)
+{
+	int i;
+	isl_space *space;
+	unsigned n_div;
+
+	if (ls)
+		*ls = NULL;
+
+	if (!maff)
+		return NULL;
+
+	if (maff->n == 0) {
+		if (ls) {
+			isl_space *space = isl_multi_aff_get_domain_space(maff);
+			*ls = isl_local_space_from_space(space);
+			if (!*ls)
+				return isl_multi_aff_free(maff);
+		}
+		return maff;
+	}
+
+	maff = isl_multi_aff_cow(maff);
+	maff = isl_multi_aff_align_divs(maff);
+	if (!maff)
+		return NULL;
+
+	n_div = isl_aff_dim(maff->p[0], isl_dim_div);
+	space = isl_multi_aff_get_space(maff);
+	space = isl_space_lift(isl_space_domain(space), n_div);
+	space = isl_space_extend_domain_with_range(space,
+						isl_multi_aff_get_space(maff));
+	if (!space)
+		return isl_multi_aff_free(maff);
+	isl_space_free(maff->space);
+	maff->space = space;
+
+	if (ls) {
+		*ls = isl_aff_get_domain_local_space(maff->p[0]);
+		if (!*ls)
+			return isl_multi_aff_free(maff);
+	}
+
+	for (i = 0; i < maff->n; ++i) {
+		maff->p[i] = isl_aff_lift(maff->p[i]);
+		if (!maff->p[i])
+			goto error;
+	}
+
+	return maff;
+error:
+	if (ls)
+		isl_local_space_free(*ls);
+	return isl_multi_aff_free(maff);
+}
+
+
+/* Extract an isl_pw_aff corresponding to output dimension "pos" of "pma".
+ */
+__isl_give isl_pw_aff *isl_pw_multi_aff_get_pw_aff(
+	__isl_keep isl_pw_multi_aff *pma, int pos)
+{
+	int i;
+	int n_out;
+	isl_space *space;
+	isl_pw_aff *pa;
+
+	if (!pma)
+		return NULL;
+
+	n_out = isl_pw_multi_aff_dim(pma, isl_dim_out);
+	if (pos < 0 || pos >= n_out)
+		isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
+			"index out of bounds", return NULL);
+
+	space = isl_pw_multi_aff_get_space(pma);
+	space = isl_space_drop_dims(space, isl_dim_out,
+				    pos + 1, n_out - pos - 1);
+	space = isl_space_drop_dims(space, isl_dim_out, 0, pos);
+
+	pa = isl_pw_aff_alloc_size(space, pma->n);
+	for (i = 0; i < pma->n; ++i) {
+		isl_aff *aff;
+		aff = isl_multi_aff_get_aff(pma->p[i].maff, pos);
+		pa = isl_pw_aff_add_piece(pa, isl_set_copy(pma->p[i].set), aff);
+	}
+
+	return pa;
+}
+
+/* Return an isl_pw_multi_aff with the given "set" as domain and
+ * an unnamed zero-dimensional range.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_domain(
+	__isl_take isl_set *set)
+{
+	isl_multi_aff *ma;
+	isl_space *space;
+
+	space = isl_set_get_space(set);
+	space = isl_space_from_domain(space);
+	ma = isl_multi_aff_zero(space);
+	return isl_pw_multi_aff_alloc(set, ma);
+}
+
+/* Add an isl_pw_multi_aff with the given "set" as domain and
+ * an unnamed zero-dimensional range to *user.
+ */
+static isl_stat add_pw_multi_aff_from_domain(__isl_take isl_set *set,
+	void *user)
+{
+	isl_union_pw_multi_aff **upma = user;
+	isl_pw_multi_aff *pma;
+
+	pma = isl_pw_multi_aff_from_domain(set);
+	*upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma);
+
+	return isl_stat_ok;
+}
+
+/* Return an isl_union_pw_multi_aff with the given "uset" as domain and
+ * an unnamed zero-dimensional range.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_domain(
+	__isl_take isl_union_set *uset)
+{
+	isl_space *space;
+	isl_union_pw_multi_aff *upma;
+
+	if (!uset)
+		return NULL;
+
+	space = isl_union_set_get_space(uset);
+	upma = isl_union_pw_multi_aff_empty(space);
+
+	if (isl_union_set_foreach_set(uset,
+				    &add_pw_multi_aff_from_domain, &upma) < 0)
+		goto error;
+
+	isl_union_set_free(uset);
+	return upma;
+error:
+	isl_union_set_free(uset);
+	isl_union_pw_multi_aff_free(upma);
+	return NULL;
+}
+
+/* Convert "pma" to an isl_map and add it to *umap.
+ */
+static isl_stat map_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma,
+	void *user)
+{
+	isl_union_map **umap = user;
+	isl_map *map;
+
+	map = isl_map_from_pw_multi_aff(pma);
+	*umap = isl_union_map_add_map(*umap, map);
+
+	return isl_stat_ok;
+}
+
+/* Construct a union map mapping the domain of the union
+ * piecewise multi-affine expression to its range, with each dimension
+ * in the range equated to the corresponding affine expression on its cell.
+ */
+__isl_give isl_union_map *isl_union_map_from_union_pw_multi_aff(
+	__isl_take isl_union_pw_multi_aff *upma)
+{
+	isl_space *space;
+	isl_union_map *umap;
+
+	if (!upma)
+		return NULL;
+
+	space = isl_union_pw_multi_aff_get_space(upma);
+	umap = isl_union_map_empty(space);
+
+	if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
+					&map_from_pw_multi_aff, &umap) < 0)
+		goto error;
+
+	isl_union_pw_multi_aff_free(upma);
+	return umap;
+error:
+	isl_union_pw_multi_aff_free(upma);
+	isl_union_map_free(umap);
+	return NULL;
+}
+
+/* Local data for bin_entry and the callback "fn".
+ */
+struct isl_union_pw_multi_aff_bin_data {
+	isl_union_pw_multi_aff *upma2;
+	isl_union_pw_multi_aff *res;
+	isl_pw_multi_aff *pma;
+	isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, void *user);
+};
+
+/* Given an isl_pw_multi_aff from upma1, store it in data->pma
+ * and call data->fn for each isl_pw_multi_aff in data->upma2.
+ */
+static isl_stat bin_entry(__isl_take isl_pw_multi_aff *pma, void *user)
+{
+	struct isl_union_pw_multi_aff_bin_data *data = user;
+	isl_stat r;
+
+	data->pma = pma;
+	r = isl_union_pw_multi_aff_foreach_pw_multi_aff(data->upma2,
+				   data->fn, data);
+	isl_pw_multi_aff_free(pma);
+
+	return r;
+}
+
+/* Call "fn" on each pair of isl_pw_multi_affs in "upma1" and "upma2".
+ * The isl_pw_multi_aff from upma1 is stored in data->pma (where data is
+ * passed as user field) and the isl_pw_multi_aff from upma2 is available
+ * as *entry.  The callback should adjust data->res if desired.
+ */
+static __isl_give isl_union_pw_multi_aff *bin_op(
+	__isl_take isl_union_pw_multi_aff *upma1,
+	__isl_take isl_union_pw_multi_aff *upma2,
+	isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, void *user))
+{
+	isl_space *space;
+	struct isl_union_pw_multi_aff_bin_data data = { NULL, NULL, NULL, fn };
+
+	space = isl_union_pw_multi_aff_get_space(upma2);
+	upma1 = isl_union_pw_multi_aff_align_params(upma1, space);
+	space = isl_union_pw_multi_aff_get_space(upma1);
+	upma2 = isl_union_pw_multi_aff_align_params(upma2, space);
+
+	if (!upma1 || !upma2)
+		goto error;
+
+	data.upma2 = upma2;
+	data.res = isl_union_pw_multi_aff_alloc_same_size(upma1);
+	if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma1,
+				   &bin_entry, &data) < 0)
+		goto error;
+
+	isl_union_pw_multi_aff_free(upma1);
+	isl_union_pw_multi_aff_free(upma2);
+	return data.res;
+error:
+	isl_union_pw_multi_aff_free(upma1);
+	isl_union_pw_multi_aff_free(upma2);
+	isl_union_pw_multi_aff_free(data.res);
+	return NULL;
+}
+
+/* Given two aligned isl_pw_multi_affs A -> B and C -> D,
+ * construct an isl_pw_multi_aff (A * C) -> [B -> D].
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_range_product(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+	isl_space *space;
+
+	space = isl_space_range_product(isl_pw_multi_aff_get_space(pma1),
+					isl_pw_multi_aff_get_space(pma2));
+	return isl_pw_multi_aff_on_shared_domain_in(pma1, pma2, space,
+					    &isl_multi_aff_range_product);
+}
+
+/* Given two isl_pw_multi_affs A -> B and C -> D,
+ * construct an isl_pw_multi_aff (A * C) -> [B -> D].
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_product(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+	return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
+					    &pw_multi_aff_range_product);
+}
+
+/* Given two aligned isl_pw_multi_affs A -> B and C -> D,
+ * construct an isl_pw_multi_aff (A * C) -> (B, D).
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_flat_range_product(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+	isl_space *space;
+
+	space = isl_space_range_product(isl_pw_multi_aff_get_space(pma1),
+					isl_pw_multi_aff_get_space(pma2));
+	space = isl_space_flatten_range(space);
+	return isl_pw_multi_aff_on_shared_domain_in(pma1, pma2, space,
+					    &isl_multi_aff_flat_range_product);
+}
+
+/* Given two isl_pw_multi_affs A -> B and C -> D,
+ * construct an isl_pw_multi_aff (A * C) -> (B, D).
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_flat_range_product(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)
+{
+	return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2,
+					    &pw_multi_aff_flat_range_product);
+}
+
+/* If data->pma and "pma2" have the same domain space, then compute
+ * their flat range product and the result to data->res.
+ */
+static isl_stat flat_range_product_entry(__isl_take isl_pw_multi_aff *pma2,
+	void *user)
+{
+	struct isl_union_pw_multi_aff_bin_data *data = user;
+
+	if (!isl_space_tuple_is_equal(data->pma->dim, isl_dim_in,
+				 pma2->dim, isl_dim_in)) {
+		isl_pw_multi_aff_free(pma2);
+		return isl_stat_ok;
+	}
+
+	pma2 = isl_pw_multi_aff_flat_range_product(
+					isl_pw_multi_aff_copy(data->pma), pma2);
+
+	data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma2);
+
+	return isl_stat_ok;
+}
+
+/* Given two isl_union_pw_multi_affs A -> B and C -> D,
+ * construct an isl_union_pw_multi_aff (A * C) -> (B, D).
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_flat_range_product(
+	__isl_take isl_union_pw_multi_aff *upma1,
+	__isl_take isl_union_pw_multi_aff *upma2)
+{
+	return bin_op(upma1, upma2, &flat_range_product_entry);
+}
+
+/* Replace the affine expressions at position "pos" in "pma" by "pa".
+ * The parameters are assumed to have been aligned.
+ *
+ * The implementation essentially performs an isl_pw_*_on_shared_domain,
+ * except that it works on two different isl_pw_* types.
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_set_pw_aff(
+	__isl_take isl_pw_multi_aff *pma, unsigned pos,
+	__isl_take isl_pw_aff *pa)
+{
+	int i, j, n;
+	isl_pw_multi_aff *res = NULL;
+
+	if (!pma || !pa)
+		goto error;
+
+	if (!isl_space_tuple_is_equal(pma->dim, isl_dim_in,
+					pa->dim, isl_dim_in))
+		isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
+			"domains don't match", goto error);
+	if (pos >= isl_pw_multi_aff_dim(pma, isl_dim_out))
+		isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	n = pma->n * pa->n;
+	res = isl_pw_multi_aff_alloc_size(isl_pw_multi_aff_get_space(pma), n);
+
+	for (i = 0; i < pma->n; ++i) {
+		for (j = 0; j < pa->n; ++j) {
+			isl_set *common;
+			isl_multi_aff *res_ij;
+			int empty;
+
+			common = isl_set_intersect(isl_set_copy(pma->p[i].set),
+						   isl_set_copy(pa->p[j].set));
+			empty = isl_set_plain_is_empty(common);
+			if (empty < 0 || empty) {
+				isl_set_free(common);
+				if (empty < 0)
+					goto error;
+				continue;
+			}
+
+			res_ij = isl_multi_aff_set_aff(
+					isl_multi_aff_copy(pma->p[i].maff), pos,
+					isl_aff_copy(pa->p[j].aff));
+			res_ij = isl_multi_aff_gist(res_ij,
+					isl_set_copy(common));
+
+			res = isl_pw_multi_aff_add_piece(res, common, res_ij);
+		}
+	}
+
+	isl_pw_multi_aff_free(pma);
+	isl_pw_aff_free(pa);
+	return res;
+error:
+	isl_pw_multi_aff_free(pma);
+	isl_pw_aff_free(pa);
+	return isl_pw_multi_aff_free(res);
+}
+
+/* Replace the affine expressions at position "pos" in "pma" by "pa".
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_pw_aff(
+	__isl_take isl_pw_multi_aff *pma, unsigned pos,
+	__isl_take isl_pw_aff *pa)
+{
+	isl_bool equal_params;
+
+	if (!pma || !pa)
+		goto error;
+	equal_params = isl_space_has_equal_params(pma->dim, pa->dim);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params)
+		return pw_multi_aff_set_pw_aff(pma, pos, pa);
+	if (!isl_space_has_named_params(pma->dim) ||
+	    !isl_space_has_named_params(pa->dim))
+		isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	pma = isl_pw_multi_aff_align_params(pma, isl_pw_aff_get_space(pa));
+	pa = isl_pw_aff_align_params(pa, isl_pw_multi_aff_get_space(pma));
+	return pw_multi_aff_set_pw_aff(pma, pos, pa);
+error:
+	isl_pw_multi_aff_free(pma);
+	isl_pw_aff_free(pa);
+	return NULL;
+}
+
+/* Do the parameters of "pa" match those of "space"?
+ */
+isl_bool isl_pw_aff_matching_params(__isl_keep isl_pw_aff *pa,
+	__isl_keep isl_space *space)
+{
+	isl_space *pa_space;
+	isl_bool match;
+
+	if (!pa || !space)
+		return isl_bool_error;
+
+	pa_space = isl_pw_aff_get_space(pa);
+
+	match = isl_space_has_equal_params(space, pa_space);
+
+	isl_space_free(pa_space);
+	return match;
+}
+
+/* Check that the domain space of "pa" matches "space".
+ */
+isl_stat isl_pw_aff_check_match_domain_space(__isl_keep isl_pw_aff *pa,
+	__isl_keep isl_space *space)
+{
+	isl_space *pa_space;
+	isl_bool match;
+
+	if (!pa || !space)
+		return isl_stat_error;
+
+	pa_space = isl_pw_aff_get_space(pa);
+
+	match = isl_space_has_equal_params(space, pa_space);
+	if (match < 0)
+		goto error;
+	if (!match)
+		isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
+			"parameters don't match", goto error);
+	match = isl_space_tuple_is_equal(space, isl_dim_in,
+					pa_space, isl_dim_in);
+	if (match < 0)
+		goto error;
+	if (!match)
+		isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
+			"domains don't match", goto error);
+	isl_space_free(pa_space);
+	return isl_stat_ok;
+error:
+	isl_space_free(pa_space);
+	return isl_stat_error;
+}
+
+#undef BASE
+#define BASE pw_aff
+#undef DOMBASE
+#define DOMBASE set
+
+#include <isl_multi_templ.c>
+#include <isl_multi_apply_set.c>
+#include <isl_multi_coalesce.c>
+#include <isl_multi_gist.c>
+#include <isl_multi_hash.c>
+#include <isl_multi_intersect.c>
+
+/* Scale the elements of "pma" by the corresponding elements of "mv".
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_multi_val(
+	__isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv)
+{
+	int i;
+	isl_bool equal_params;
+
+	pma = isl_pw_multi_aff_cow(pma);
+	if (!pma || !mv)
+		goto error;
+	if (!isl_space_tuple_is_equal(pma->dim, isl_dim_out,
+					mv->space, isl_dim_set))
+		isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
+			"spaces don't match", goto error);
+	equal_params = isl_space_has_equal_params(pma->dim, mv->space);
+	if (equal_params < 0)
+		goto error;
+	if (!equal_params) {
+		pma = isl_pw_multi_aff_align_params(pma,
+					    isl_multi_val_get_space(mv));
+		mv = isl_multi_val_align_params(mv,
+					    isl_pw_multi_aff_get_space(pma));
+		if (!pma || !mv)
+			goto error;
+	}
+
+	for (i = 0; i < pma->n; ++i) {
+		pma->p[i].maff = isl_multi_aff_scale_multi_val(pma->p[i].maff,
+							isl_multi_val_copy(mv));
+		if (!pma->p[i].maff)
+			goto error;
+	}
+
+	isl_multi_val_free(mv);
+	return pma;
+error:
+	isl_multi_val_free(mv);
+	isl_pw_multi_aff_free(pma);
+	return NULL;
+}
+
+/* This function is called for each entry of an isl_union_pw_multi_aff.
+ * If the space of the entry matches that of data->mv,
+ * then apply isl_pw_multi_aff_scale_multi_val and return the result.
+ * Otherwise, return an empty isl_pw_multi_aff.
+ */
+static __isl_give isl_pw_multi_aff *union_pw_multi_aff_scale_multi_val_entry(
+	__isl_take isl_pw_multi_aff *pma, void *user)
+{
+	isl_multi_val *mv = user;
+
+	if (!pma)
+		return NULL;
+	if (!isl_space_tuple_is_equal(pma->dim, isl_dim_out,
+				    mv->space, isl_dim_set)) {
+		isl_space *space = isl_pw_multi_aff_get_space(pma);
+		isl_pw_multi_aff_free(pma);
+		return isl_pw_multi_aff_empty(space);
+	}
+
+	return isl_pw_multi_aff_scale_multi_val(pma, isl_multi_val_copy(mv));
+}
+
+/* Scale the elements of "upma" by the corresponding elements of "mv",
+ * for those entries that match the space of "mv".
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_multi_val(
+	__isl_take isl_union_pw_multi_aff *upma, __isl_take isl_multi_val *mv)
+{
+	upma = isl_union_pw_multi_aff_align_params(upma,
+						isl_multi_val_get_space(mv));
+	mv = isl_multi_val_align_params(mv,
+					isl_union_pw_multi_aff_get_space(upma));
+	if (!upma || !mv)
+		goto error;
+
+	return isl_union_pw_multi_aff_transform(upma,
+		       &union_pw_multi_aff_scale_multi_val_entry, mv);
+
+	isl_multi_val_free(mv);
+	return upma;
+error:
+	isl_multi_val_free(mv);
+	isl_union_pw_multi_aff_free(upma);
+	return NULL;
+}
+
+/* Construct and return a piecewise multi affine expression
+ * in the given space with value zero in each of the output dimensions and
+ * a universe domain.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_zero(__isl_take isl_space *space)
+{
+	return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_zero(space));
+}
+
+/* Construct and return a piecewise multi affine expression
+ * that is equal to the given piecewise affine expression.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_pw_aff(
+	__isl_take isl_pw_aff *pa)
+{
+	int i;
+	isl_space *space;
+	isl_pw_multi_aff *pma;
+
+	if (!pa)
+		return NULL;
+
+	space = isl_pw_aff_get_space(pa);
+	pma = isl_pw_multi_aff_alloc_size(space, pa->n);
+
+	for (i = 0; i < pa->n; ++i) {
+		isl_set *set;
+		isl_multi_aff *ma;
+
+		set = isl_set_copy(pa->p[i].set);
+		ma = isl_multi_aff_from_aff(isl_aff_copy(pa->p[i].aff));
+		pma = isl_pw_multi_aff_add_piece(pma, set, ma);
+	}
+
+	isl_pw_aff_free(pa);
+	return pma;
+}
+
+/* Construct a set or map mapping the shared (parameter) domain
+ * of the piecewise affine expressions to the range of "mpa"
+ * with each dimension in the range equated to the
+ * corresponding piecewise affine expression.
+ */
+static __isl_give isl_map *map_from_multi_pw_aff(
+	__isl_take isl_multi_pw_aff *mpa)
+{
+	int i;
+	isl_space *space;
+	isl_map *map;
+
+	if (!mpa)
+		return NULL;
+
+	if (isl_space_dim(mpa->space, isl_dim_out) != mpa->n)
+		isl_die(isl_multi_pw_aff_get_ctx(mpa), isl_error_internal,
+			"invalid space", goto error);
+
+	space = isl_multi_pw_aff_get_domain_space(mpa);
+	map = isl_map_universe(isl_space_from_domain(space));
+
+	for (i = 0; i < mpa->n; ++i) {
+		isl_pw_aff *pa;
+		isl_map *map_i;
+
+		pa = isl_pw_aff_copy(mpa->p[i]);
+		map_i = map_from_pw_aff(pa);
+
+		map = isl_map_flat_range_product(map, map_i);
+	}
+
+	map = isl_map_reset_space(map, isl_multi_pw_aff_get_space(mpa));
+
+	isl_multi_pw_aff_free(mpa);
+	return map;
+error:
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Construct a map mapping the shared domain
+ * of the piecewise affine expressions to the range of "mpa"
+ * with each dimension in the range equated to the
+ * corresponding piecewise affine expression.
+ */
+__isl_give isl_map *isl_map_from_multi_pw_aff(__isl_take isl_multi_pw_aff *mpa)
+{
+	if (!mpa)
+		return NULL;
+	if (isl_space_is_set(mpa->space))
+		isl_die(isl_multi_pw_aff_get_ctx(mpa), isl_error_internal,
+			"space of input is not a map", goto error);
+
+	return map_from_multi_pw_aff(mpa);
+error:
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Construct a set mapping the shared parameter domain
+ * of the piecewise affine expressions to the space of "mpa"
+ * with each dimension in the range equated to the
+ * corresponding piecewise affine expression.
+ */
+__isl_give isl_set *isl_set_from_multi_pw_aff(__isl_take isl_multi_pw_aff *mpa)
+{
+	if (!mpa)
+		return NULL;
+	if (!isl_space_is_set(mpa->space))
+		isl_die(isl_multi_pw_aff_get_ctx(mpa), isl_error_internal,
+			"space of input is not a set", goto error);
+
+	return map_from_multi_pw_aff(mpa);
+error:
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Construct and return a piecewise multi affine expression
+ * that is equal to the given multi piecewise affine expression
+ * on the shared domain of the piecewise affine expressions.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_pw_aff(
+	__isl_take isl_multi_pw_aff *mpa)
+{
+	int i;
+	isl_space *space;
+	isl_pw_aff *pa;
+	isl_pw_multi_aff *pma;
+
+	if (!mpa)
+		return NULL;
+
+	space = isl_multi_pw_aff_get_space(mpa);
+
+	if (mpa->n == 0) {
+		isl_multi_pw_aff_free(mpa);
+		return isl_pw_multi_aff_zero(space);
+	}
+
+	pa = isl_multi_pw_aff_get_pw_aff(mpa, 0);
+	pma = isl_pw_multi_aff_from_pw_aff(pa);
+
+	for (i = 1; i < mpa->n; ++i) {
+		isl_pw_multi_aff *pma_i;
+
+		pa = isl_multi_pw_aff_get_pw_aff(mpa, i);
+		pma_i = isl_pw_multi_aff_from_pw_aff(pa);
+		pma = isl_pw_multi_aff_range_product(pma, pma_i);
+	}
+
+	pma = isl_pw_multi_aff_reset_space(pma, space);
+
+	isl_multi_pw_aff_free(mpa);
+	return pma;
+}
+
+/* Construct and return a multi piecewise affine expression
+ * that is equal to the given multi affine expression.
+ */
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_multi_aff(
+	__isl_take isl_multi_aff *ma)
+{
+	int i, n;
+	isl_multi_pw_aff *mpa;
+
+	if (!ma)
+		return NULL;
+
+	n = isl_multi_aff_dim(ma, isl_dim_out);
+	mpa = isl_multi_pw_aff_alloc(isl_multi_aff_get_space(ma));
+
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+
+		pa = isl_pw_aff_from_aff(isl_multi_aff_get_aff(ma, i));
+		mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);
+	}
+
+	isl_multi_aff_free(ma);
+	return mpa;
+}
+
+/* Construct and return a multi piecewise affine expression
+ * that is equal to the given piecewise multi affine expression.
+ */
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_multi_aff(
+	__isl_take isl_pw_multi_aff *pma)
+{
+	int i, n;
+	isl_space *space;
+	isl_multi_pw_aff *mpa;
+
+	if (!pma)
+		return NULL;
+
+	n = isl_pw_multi_aff_dim(pma, isl_dim_out);
+	space = isl_pw_multi_aff_get_space(pma);
+	mpa = isl_multi_pw_aff_alloc(space);
+
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+
+		pa = isl_pw_multi_aff_get_pw_aff(pma, i);
+		mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);
+	}
+
+	isl_pw_multi_aff_free(pma);
+	return mpa;
+}
+
+/* Do "pa1" and "pa2" represent the same function?
+ *
+ * We first check if they are obviously equal.
+ * If not, we convert them to maps and check if those are equal.
+ *
+ * If "pa1" or "pa2" contain any NaNs, then they are considered
+ * not to be the same.  A NaN is not equal to anything, not even
+ * to another NaN.
+ */
+isl_bool isl_pw_aff_is_equal(__isl_keep isl_pw_aff *pa1,
+	__isl_keep isl_pw_aff *pa2)
+{
+	isl_bool equal;
+	isl_bool has_nan;
+	isl_map *map1, *map2;
+
+	if (!pa1 || !pa2)
+		return isl_bool_error;
+
+	equal = isl_pw_aff_plain_is_equal(pa1, pa2);
+	if (equal < 0 || equal)
+		return equal;
+	has_nan = either_involves_nan(pa1, pa2);
+	if (has_nan < 0)
+		return isl_bool_error;
+	if (has_nan)
+		return isl_bool_false;
+
+	map1 = map_from_pw_aff(isl_pw_aff_copy(pa1));
+	map2 = map_from_pw_aff(isl_pw_aff_copy(pa2));
+	equal = isl_map_is_equal(map1, map2);
+	isl_map_free(map1);
+	isl_map_free(map2);
+
+	return equal;
+}
+
+/* Do "mpa1" and "mpa2" represent the same function?
+ *
+ * Note that we cannot convert the entire isl_multi_pw_aff
+ * to a map because the domains of the piecewise affine expressions
+ * may not be the same.
+ */
+isl_bool isl_multi_pw_aff_is_equal(__isl_keep isl_multi_pw_aff *mpa1,
+	__isl_keep isl_multi_pw_aff *mpa2)
+{
+	int i;
+	isl_bool equal, equal_params;
+
+	if (!mpa1 || !mpa2)
+		return isl_bool_error;
+
+	equal_params = isl_space_has_equal_params(mpa1->space, mpa2->space);
+	if (equal_params < 0)
+		return isl_bool_error;
+	if (!equal_params) {
+		if (!isl_space_has_named_params(mpa1->space))
+			return isl_bool_false;
+		if (!isl_space_has_named_params(mpa2->space))
+			return isl_bool_false;
+		mpa1 = isl_multi_pw_aff_copy(mpa1);
+		mpa2 = isl_multi_pw_aff_copy(mpa2);
+		mpa1 = isl_multi_pw_aff_align_params(mpa1,
+					    isl_multi_pw_aff_get_space(mpa2));
+		mpa2 = isl_multi_pw_aff_align_params(mpa2,
+					    isl_multi_pw_aff_get_space(mpa1));
+		equal = isl_multi_pw_aff_is_equal(mpa1, mpa2);
+		isl_multi_pw_aff_free(mpa1);
+		isl_multi_pw_aff_free(mpa2);
+		return equal;
+	}
+
+	equal = isl_space_is_equal(mpa1->space, mpa2->space);
+	if (equal < 0 || !equal)
+		return equal;
+
+	for (i = 0; i < mpa1->n; ++i) {
+		equal = isl_pw_aff_is_equal(mpa1->p[i], mpa2->p[i]);
+		if (equal < 0 || !equal)
+			return equal;
+	}
+
+	return isl_bool_true;
+}
+
+/* Do "pma1" and "pma2" represent the same function?
+ *
+ * First check if they are obviously equal.
+ * If not, then convert them to maps and check if those are equal.
+ *
+ * If "pa1" or "pa2" contain any NaNs, then they are considered
+ * not to be the same.  A NaN is not equal to anything, not even
+ * to another NaN.
+ */
+isl_bool isl_pw_multi_aff_is_equal(__isl_keep isl_pw_multi_aff *pma1,
+	__isl_keep isl_pw_multi_aff *pma2)
+{
+	isl_bool equal;
+	isl_bool has_nan;
+	isl_map *map1, *map2;
+
+	if (!pma1 || !pma2)
+		return isl_bool_error;
+
+	equal = isl_pw_multi_aff_plain_is_equal(pma1, pma2);
+	if (equal < 0 || equal)
+		return equal;
+	has_nan = isl_pw_multi_aff_involves_nan(pma1);
+	if (has_nan >= 0 && !has_nan)
+		has_nan = isl_pw_multi_aff_involves_nan(pma2);
+	if (has_nan < 0 || has_nan)
+		return isl_bool_not(has_nan);
+
+	map1 = isl_map_from_pw_multi_aff(isl_pw_multi_aff_copy(pma1));
+	map2 = isl_map_from_pw_multi_aff(isl_pw_multi_aff_copy(pma2));
+	equal = isl_map_is_equal(map1, map2);
+	isl_map_free(map1);
+	isl_map_free(map2);
+
+	return equal;
+}
+
+/* Compute the pullback of "mpa" by the function represented by "ma".
+ * In other words, plug in "ma" in "mpa".
+ *
+ * The parameters of "mpa" and "ma" are assumed to have been aligned.
+ */
+static __isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_aff_aligned(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_multi_aff *ma)
+{
+	int i;
+	isl_space *space = NULL;
+
+	mpa = isl_multi_pw_aff_cow(mpa);
+	if (!mpa || !ma)
+		goto error;
+
+	space = isl_space_join(isl_multi_aff_get_space(ma),
+				isl_multi_pw_aff_get_space(mpa));
+	if (!space)
+		goto error;
+
+	for (i = 0; i < mpa->n; ++i) {
+		mpa->p[i] = isl_pw_aff_pullback_multi_aff(mpa->p[i],
+						    isl_multi_aff_copy(ma));
+		if (!mpa->p[i])
+			goto error;
+	}
+
+	isl_multi_aff_free(ma);
+	isl_space_free(mpa->space);
+	mpa->space = space;
+	return mpa;
+error:
+	isl_space_free(space);
+	isl_multi_pw_aff_free(mpa);
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+/* Compute the pullback of "mpa" by the function represented by "ma".
+ * In other words, plug in "ma" in "mpa".
+ */
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_aff(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_multi_aff *ma)
+{
+	isl_bool equal_params;
+
+	if (!mpa || !ma)
+		goto error;
+	equal_params = isl_space_has_equal_params(mpa->space, ma->space);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params)
+		return isl_multi_pw_aff_pullback_multi_aff_aligned(mpa, ma);
+	mpa = isl_multi_pw_aff_align_params(mpa, isl_multi_aff_get_space(ma));
+	ma = isl_multi_aff_align_params(ma, isl_multi_pw_aff_get_space(mpa));
+	return isl_multi_pw_aff_pullback_multi_aff_aligned(mpa, ma);
+error:
+	isl_multi_pw_aff_free(mpa);
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+/* Compute the pullback of "mpa" by the function represented by "pma".
+ * In other words, plug in "pma" in "mpa".
+ *
+ * The parameters of "mpa" and "mpa" are assumed to have been aligned.
+ */
+static __isl_give isl_multi_pw_aff *
+isl_multi_pw_aff_pullback_pw_multi_aff_aligned(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_multi_aff *pma)
+{
+	int i;
+	isl_space *space = NULL;
+
+	mpa = isl_multi_pw_aff_cow(mpa);
+	if (!mpa || !pma)
+		goto error;
+
+	space = isl_space_join(isl_pw_multi_aff_get_space(pma),
+				isl_multi_pw_aff_get_space(mpa));
+
+	for (i = 0; i < mpa->n; ++i) {
+		mpa->p[i] = isl_pw_aff_pullback_pw_multi_aff_aligned(mpa->p[i],
+						    isl_pw_multi_aff_copy(pma));
+		if (!mpa->p[i])
+			goto error;
+	}
+
+	isl_pw_multi_aff_free(pma);
+	isl_space_free(mpa->space);
+	mpa->space = space;
+	return mpa;
+error:
+	isl_space_free(space);
+	isl_multi_pw_aff_free(mpa);
+	isl_pw_multi_aff_free(pma);
+	return NULL;
+}
+
+/* Compute the pullback of "mpa" by the function represented by "pma".
+ * In other words, plug in "pma" in "mpa".
+ */
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_pw_multi_aff(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_multi_aff *pma)
+{
+	isl_bool equal_params;
+
+	if (!mpa || !pma)
+		goto error;
+	equal_params = isl_space_has_equal_params(mpa->space, pma->dim);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params)
+		return isl_multi_pw_aff_pullback_pw_multi_aff_aligned(mpa, pma);
+	mpa = isl_multi_pw_aff_align_params(mpa,
+					    isl_pw_multi_aff_get_space(pma));
+	pma = isl_pw_multi_aff_align_params(pma,
+					    isl_multi_pw_aff_get_space(mpa));
+	return isl_multi_pw_aff_pullback_pw_multi_aff_aligned(mpa, pma);
+error:
+	isl_multi_pw_aff_free(mpa);
+	isl_pw_multi_aff_free(pma);
+	return NULL;
+}
+
+/* Apply "aff" to "mpa".  The range of "mpa" needs to be compatible
+ * with the domain of "aff".  The domain of the result is the same
+ * as that of "mpa".
+ * "mpa" and "aff" are assumed to have been aligned.
+ *
+ * We first extract the parametric constant from "aff", defined
+ * over the correct domain.
+ * Then we add the appropriate combinations of the members of "mpa".
+ * Finally, we add the integer divisions through recursive calls.
+ */
+static __isl_give isl_pw_aff *isl_multi_pw_aff_apply_aff_aligned(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_aff *aff)
+{
+	int i, n_in, n_div;
+	isl_space *space;
+	isl_val *v;
+	isl_pw_aff *pa;
+	isl_aff *tmp;
+
+	n_in = isl_aff_dim(aff, isl_dim_in);
+	n_div = isl_aff_dim(aff, isl_dim_div);
+
+	space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
+	tmp = isl_aff_copy(aff);
+	tmp = isl_aff_drop_dims(tmp, isl_dim_div, 0, n_div);
+	tmp = isl_aff_drop_dims(tmp, isl_dim_in, 0, n_in);
+	tmp = isl_aff_add_dims(tmp, isl_dim_in,
+				isl_space_dim(space, isl_dim_set));
+	tmp = isl_aff_reset_domain_space(tmp, space);
+	pa = isl_pw_aff_from_aff(tmp);
+
+	for (i = 0; i < n_in; ++i) {
+		isl_pw_aff *pa_i;
+
+		if (!isl_aff_involves_dims(aff, isl_dim_in, i, 1))
+			continue;
+		v = isl_aff_get_coefficient_val(aff, isl_dim_in, i);
+		pa_i = isl_multi_pw_aff_get_pw_aff(mpa, i);
+		pa_i = isl_pw_aff_scale_val(pa_i, v);
+		pa = isl_pw_aff_add(pa, pa_i);
+	}
+
+	for (i = 0; i < n_div; ++i) {
+		isl_aff *div;
+		isl_pw_aff *pa_i;
+
+		if (!isl_aff_involves_dims(aff, isl_dim_div, i, 1))
+			continue;
+		div = isl_aff_get_div(aff, i);
+		pa_i = isl_multi_pw_aff_apply_aff_aligned(
+					    isl_multi_pw_aff_copy(mpa), div);
+		pa_i = isl_pw_aff_floor(pa_i);
+		v = isl_aff_get_coefficient_val(aff, isl_dim_div, i);
+		pa_i = isl_pw_aff_scale_val(pa_i, v);
+		pa = isl_pw_aff_add(pa, pa_i);
+	}
+
+	isl_multi_pw_aff_free(mpa);
+	isl_aff_free(aff);
+
+	return pa;
+}
+
+/* Apply "aff" to "mpa".  The range of "mpa" needs to be compatible
+ * with the domain of "aff".  The domain of the result is the same
+ * as that of "mpa".
+ */
+__isl_give isl_pw_aff *isl_multi_pw_aff_apply_aff(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_aff *aff)
+{
+	isl_bool equal_params;
+
+	if (!aff || !mpa)
+		goto error;
+	equal_params = isl_space_has_equal_params(aff->ls->dim, mpa->space);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params)
+		return isl_multi_pw_aff_apply_aff_aligned(mpa, aff);
+
+	aff = isl_aff_align_params(aff, isl_multi_pw_aff_get_space(mpa));
+	mpa = isl_multi_pw_aff_align_params(mpa, isl_aff_get_space(aff));
+
+	return isl_multi_pw_aff_apply_aff_aligned(mpa, aff);
+error:
+	isl_aff_free(aff);
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Apply "pa" to "mpa".  The range of "mpa" needs to be compatible
+ * with the domain of "pa".  The domain of the result is the same
+ * as that of "mpa".
+ * "mpa" and "pa" are assumed to have been aligned.
+ *
+ * We consider each piece in turn.  Note that the domains of the
+ * pieces are assumed to be disjoint and they remain disjoint
+ * after taking the preimage (over the same function).
+ */
+static __isl_give isl_pw_aff *isl_multi_pw_aff_apply_pw_aff_aligned(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_aff *pa)
+{
+	isl_space *space;
+	isl_pw_aff *res;
+	int i;
+
+	if (!mpa || !pa)
+		goto error;
+
+	space = isl_space_join(isl_multi_pw_aff_get_space(mpa),
+				isl_pw_aff_get_space(pa));
+	res = isl_pw_aff_empty(space);
+
+	for (i = 0; i < pa->n; ++i) {
+		isl_pw_aff *pa_i;
+		isl_set *domain;
+
+		pa_i = isl_multi_pw_aff_apply_aff_aligned(
+					isl_multi_pw_aff_copy(mpa),
+					isl_aff_copy(pa->p[i].aff));
+		domain = isl_set_copy(pa->p[i].set);
+		domain = isl_set_preimage_multi_pw_aff(domain,
+					isl_multi_pw_aff_copy(mpa));
+		pa_i = isl_pw_aff_intersect_domain(pa_i, domain);
+		res = isl_pw_aff_add_disjoint(res, pa_i);
+	}
+
+	isl_pw_aff_free(pa);
+	isl_multi_pw_aff_free(mpa);
+	return res;
+error:
+	isl_pw_aff_free(pa);
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Apply "pa" to "mpa".  The range of "mpa" needs to be compatible
+ * with the domain of "pa".  The domain of the result is the same
+ * as that of "mpa".
+ */
+__isl_give isl_pw_aff *isl_multi_pw_aff_apply_pw_aff(
+	__isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_aff *pa)
+{
+	isl_bool equal_params;
+
+	if (!pa || !mpa)
+		goto error;
+	equal_params = isl_space_has_equal_params(pa->dim, mpa->space);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params)
+		return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa);
+
+	pa = isl_pw_aff_align_params(pa, isl_multi_pw_aff_get_space(mpa));
+	mpa = isl_multi_pw_aff_align_params(mpa, isl_pw_aff_get_space(pa));
+
+	return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa);
+error:
+	isl_pw_aff_free(pa);
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Compute the pullback of "pa" by the function represented by "mpa".
+ * In other words, plug in "mpa" in "pa".
+ * "pa" and "mpa" are assumed to have been aligned.
+ *
+ * The pullback is computed by applying "pa" to "mpa".
+ */
+static __isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff_aligned(
+	__isl_take isl_pw_aff *pa, __isl_take isl_multi_pw_aff *mpa)
+{
+	return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa);
+}
+
+/* Compute the pullback of "pa" by the function represented by "mpa".
+ * In other words, plug in "mpa" in "pa".
+ *
+ * The pullback is computed by applying "pa" to "mpa".
+ */
+__isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff(
+	__isl_take isl_pw_aff *pa, __isl_take isl_multi_pw_aff *mpa)
+{
+	return isl_multi_pw_aff_apply_pw_aff(mpa, pa);
+}
+
+/* Compute the pullback of "mpa1" by the function represented by "mpa2".
+ * In other words, plug in "mpa2" in "mpa1".
+ *
+ * The parameters of "mpa1" and "mpa2" are assumed to have been aligned.
+ *
+ * We pullback each member of "mpa1" in turn.
+ */
+static __isl_give isl_multi_pw_aff *
+isl_multi_pw_aff_pullback_multi_pw_aff_aligned(
+	__isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2)
+{
+	int i;
+	isl_space *space = NULL;
+
+	mpa1 = isl_multi_pw_aff_cow(mpa1);
+	if (!mpa1 || !mpa2)
+		goto error;
+
+	space = isl_space_join(isl_multi_pw_aff_get_space(mpa2),
+				isl_multi_pw_aff_get_space(mpa1));
+
+	for (i = 0; i < mpa1->n; ++i) {
+		mpa1->p[i] = isl_pw_aff_pullback_multi_pw_aff_aligned(
+				mpa1->p[i], isl_multi_pw_aff_copy(mpa2));
+		if (!mpa1->p[i])
+			goto error;
+	}
+
+	mpa1 = isl_multi_pw_aff_reset_space(mpa1, space);
+
+	isl_multi_pw_aff_free(mpa2);
+	return mpa1;
+error:
+	isl_space_free(space);
+	isl_multi_pw_aff_free(mpa1);
+	isl_multi_pw_aff_free(mpa2);
+	return NULL;
+}
+
+/* Compute the pullback of "mpa1" by the function represented by "mpa2".
+ * In other words, plug in "mpa2" in "mpa1".
+ */
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_pullback_multi_pw_aff(
+	__isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2)
+{
+	return isl_multi_pw_aff_align_params_multi_multi_and(mpa1, mpa2,
+			&isl_multi_pw_aff_pullback_multi_pw_aff_aligned);
+}
+
+/* Align the parameters of "mpa1" and "mpa2", check that the ranges
+ * of "mpa1" and "mpa2" live in the same space, construct map space
+ * between the domain spaces of "mpa1" and "mpa2" and call "order"
+ * with this map space as extract argument.
+ */
+static __isl_give isl_map *isl_multi_pw_aff_order_map(
+	__isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2,
+	__isl_give isl_map *(*order)(__isl_keep isl_multi_pw_aff *mpa1,
+		__isl_keep isl_multi_pw_aff *mpa2, __isl_take isl_space *space))
+{
+	int match;
+	isl_space *space1, *space2;
+	isl_map *res;
+
+	mpa1 = isl_multi_pw_aff_align_params(mpa1,
+					    isl_multi_pw_aff_get_space(mpa2));
+	mpa2 = isl_multi_pw_aff_align_params(mpa2,
+					    isl_multi_pw_aff_get_space(mpa1));
+	if (!mpa1 || !mpa2)
+		goto error;
+	match = isl_space_tuple_is_equal(mpa1->space, isl_dim_out,
+					mpa2->space, isl_dim_out);
+	if (match < 0)
+		goto error;
+	if (!match)
+		isl_die(isl_multi_pw_aff_get_ctx(mpa1), isl_error_invalid,
+			"range spaces don't match", goto error);
+	space1 = isl_space_domain(isl_multi_pw_aff_get_space(mpa1));
+	space2 = isl_space_domain(isl_multi_pw_aff_get_space(mpa2));
+	space1 = isl_space_map_from_domain_and_range(space1, space2);
+
+	res = order(mpa1, mpa2, space1);
+	isl_multi_pw_aff_free(mpa1);
+	isl_multi_pw_aff_free(mpa2);
+	return res;
+error:
+	isl_multi_pw_aff_free(mpa1);
+	isl_multi_pw_aff_free(mpa2);
+	return NULL;
+}
+
+/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
+ * where the function values are equal.  "space" is the space of the result.
+ * The parameters of "mpa1" and "mpa2" are assumed to have been aligned.
+ *
+ * "mpa1" and "mpa2" are equal when each of the pairs of elements
+ * in the sequences are equal.
+ */
+static __isl_give isl_map *isl_multi_pw_aff_eq_map_on_space(
+	__isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2,
+	__isl_take isl_space *space)
+{
+	int i, n;
+	isl_map *res;
+
+	res = isl_map_universe(space);
+
+	n = isl_multi_pw_aff_dim(mpa1, isl_dim_out);
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa1, *pa2;
+		isl_map *map;
+
+		pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i);
+		pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i);
+		map = isl_pw_aff_eq_map(pa1, pa2);
+		res = isl_map_intersect(res, map);
+	}
+
+	return res;
+}
+
+/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
+ * where the function values are equal.
+ */
+__isl_give isl_map *isl_multi_pw_aff_eq_map(__isl_take isl_multi_pw_aff *mpa1,
+	__isl_take isl_multi_pw_aff *mpa2)
+{
+	return isl_multi_pw_aff_order_map(mpa1, mpa2,
+					    &isl_multi_pw_aff_eq_map_on_space);
+}
+
+/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
+ * where the function values of "mpa1" is lexicographically satisfies "base"
+ * compared to that of "mpa2".  "space" is the space of the result.
+ * The parameters of "mpa1" and "mpa2" are assumed to have been aligned.
+ *
+ * "mpa1" lexicographically satisfies "base" compared to "mpa2"
+ * if its i-th element satisfies "base" when compared to
+ * the i-th element of "mpa2" while all previous elements are
+ * pairwise equal.
+ */
+static __isl_give isl_map *isl_multi_pw_aff_lex_map_on_space(
+	__isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2,
+	__isl_give isl_map *(*base)(__isl_take isl_pw_aff *pa1,
+		__isl_take isl_pw_aff *pa2),
+	__isl_take isl_space *space)
+{
+	int i, n;
+	isl_map *res, *rest;
+
+	res = isl_map_empty(isl_space_copy(space));
+	rest = isl_map_universe(space);
+
+	n = isl_multi_pw_aff_dim(mpa1, isl_dim_out);
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa1, *pa2;
+		isl_map *map;
+
+		pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i);
+		pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i);
+		map = base(pa1, pa2);
+		map = isl_map_intersect(map, isl_map_copy(rest));
+		res = isl_map_union(res, map);
+
+		if (i == n - 1)
+			continue;
+
+		pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i);
+		pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i);
+		map = isl_pw_aff_eq_map(pa1, pa2);
+		rest = isl_map_intersect(rest, map);
+	}
+
+	isl_map_free(rest);
+	return res;
+}
+
+/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
+ * where the function value of "mpa1" is lexicographically less than that
+ * of "mpa2".  "space" is the space of the result.
+ * The parameters of "mpa1" and "mpa2" are assumed to have been aligned.
+ *
+ * "mpa1" is less than "mpa2" if its i-th element is smaller
+ * than the i-th element of "mpa2" while all previous elements are
+ * pairwise equal.
+ */
+__isl_give isl_map *isl_multi_pw_aff_lex_lt_map_on_space(
+	__isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2,
+	__isl_take isl_space *space)
+{
+	return isl_multi_pw_aff_lex_map_on_space(mpa1, mpa2,
+						&isl_pw_aff_lt_map, space);
+}
+
+/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
+ * where the function value of "mpa1" is lexicographically less than that
+ * of "mpa2".
+ */
+__isl_give isl_map *isl_multi_pw_aff_lex_lt_map(
+	__isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2)
+{
+	return isl_multi_pw_aff_order_map(mpa1, mpa2,
+					&isl_multi_pw_aff_lex_lt_map_on_space);
+}
+
+/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
+ * where the function value of "mpa1" is lexicographically greater than that
+ * of "mpa2".  "space" is the space of the result.
+ * The parameters of "mpa1" and "mpa2" are assumed to have been aligned.
+ *
+ * "mpa1" is greater than "mpa2" if its i-th element is greater
+ * than the i-th element of "mpa2" while all previous elements are
+ * pairwise equal.
+ */
+__isl_give isl_map *isl_multi_pw_aff_lex_gt_map_on_space(
+	__isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2,
+	__isl_take isl_space *space)
+{
+	return isl_multi_pw_aff_lex_map_on_space(mpa1, mpa2,
+						&isl_pw_aff_gt_map, space);
+}
+
+/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"
+ * where the function value of "mpa1" is lexicographically greater than that
+ * of "mpa2".
+ */
+__isl_give isl_map *isl_multi_pw_aff_lex_gt_map(
+	__isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2)
+{
+	return isl_multi_pw_aff_order_map(mpa1, mpa2,
+					&isl_multi_pw_aff_lex_gt_map_on_space);
+}
+
+/* Compare two isl_affs.
+ *
+ * Return -1 if "aff1" is "smaller" than "aff2", 1 if "aff1" is "greater"
+ * than "aff2" and 0 if they are equal.
+ *
+ * The order is fairly arbitrary.  We do consider expressions that only involve
+ * earlier dimensions as "smaller".
+ */
+int isl_aff_plain_cmp(__isl_keep isl_aff *aff1, __isl_keep isl_aff *aff2)
+{
+	int cmp;
+	int last1, last2;
+
+	if (aff1 == aff2)
+		return 0;
+
+	if (!aff1)
+		return -1;
+	if (!aff2)
+		return 1;
+
+	cmp = isl_local_space_cmp(aff1->ls, aff2->ls);
+	if (cmp != 0)
+		return cmp;
+
+	last1 = isl_seq_last_non_zero(aff1->v->el + 1, aff1->v->size - 1);
+	last2 = isl_seq_last_non_zero(aff2->v->el + 1, aff1->v->size - 1);
+	if (last1 != last2)
+		return last1 - last2;
+
+	return isl_seq_cmp(aff1->v->el, aff2->v->el, aff1->v->size);
+}
+
+/* Compare two isl_pw_affs.
+ *
+ * Return -1 if "pa1" is "smaller" than "pa2", 1 if "pa1" is "greater"
+ * than "pa2" and 0 if they are equal.
+ *
+ * The order is fairly arbitrary.  We do consider expressions that only involve
+ * earlier dimensions as "smaller".
+ */
+int isl_pw_aff_plain_cmp(__isl_keep isl_pw_aff *pa1,
+	__isl_keep isl_pw_aff *pa2)
+{
+	int i;
+	int cmp;
+
+	if (pa1 == pa2)
+		return 0;
+
+	if (!pa1)
+		return -1;
+	if (!pa2)
+		return 1;
+
+	cmp = isl_space_cmp(pa1->dim, pa2->dim);
+	if (cmp != 0)
+		return cmp;
+
+	if (pa1->n != pa2->n)
+		return pa1->n - pa2->n;
+
+	for (i = 0; i < pa1->n; ++i) {
+		cmp = isl_set_plain_cmp(pa1->p[i].set, pa2->p[i].set);
+		if (cmp != 0)
+			return cmp;
+		cmp = isl_aff_plain_cmp(pa1->p[i].aff, pa2->p[i].aff);
+		if (cmp != 0)
+			return cmp;
+	}
+
+	return 0;
+}
+
+/* Return a piecewise affine expression that is equal to "v" on "domain".
+ */
+__isl_give isl_pw_aff *isl_pw_aff_val_on_domain(__isl_take isl_set *domain,
+	__isl_take isl_val *v)
+{
+	isl_space *space;
+	isl_local_space *ls;
+	isl_aff *aff;
+
+	space = isl_set_get_space(domain);
+	ls = isl_local_space_from_space(space);
+	aff = isl_aff_val_on_domain(ls, v);
+
+	return isl_pw_aff_alloc(domain, aff);
+}
+
+/* Return a multi affine expression that is equal to "mv" on domain
+ * space "space".
+ */
+__isl_give isl_multi_aff *isl_multi_aff_multi_val_on_space(
+	__isl_take isl_space *space, __isl_take isl_multi_val *mv)
+{
+	int i, n;
+	isl_space *space2;
+	isl_local_space *ls;
+	isl_multi_aff *ma;
+
+	if (!space || !mv)
+		goto error;
+
+	n = isl_multi_val_dim(mv, isl_dim_set);
+	space2 = isl_multi_val_get_space(mv);
+	space2 = isl_space_align_params(space2, isl_space_copy(space));
+	space = isl_space_align_params(space, isl_space_copy(space2));
+	space = isl_space_map_from_domain_and_range(space, space2);
+	ma = isl_multi_aff_alloc(isl_space_copy(space));
+	ls = isl_local_space_from_space(isl_space_domain(space));
+	for (i = 0; i < n; ++i) {
+		isl_val *v;
+		isl_aff *aff;
+
+		v = isl_multi_val_get_val(mv, i);
+		aff = isl_aff_val_on_domain(isl_local_space_copy(ls), v);
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+	isl_local_space_free(ls);
+
+	isl_multi_val_free(mv);
+	return ma;
+error:
+	isl_space_free(space);
+	isl_multi_val_free(mv);
+	return NULL;
+}
+
+/* Return a piecewise multi-affine expression
+ * that is equal to "mv" on "domain".
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_multi_val_on_domain(
+	__isl_take isl_set *domain, __isl_take isl_multi_val *mv)
+{
+	isl_space *space;
+	isl_multi_aff *ma;
+
+	space = isl_set_get_space(domain);
+	ma = isl_multi_aff_multi_val_on_space(space, mv);
+
+	return isl_pw_multi_aff_alloc(domain, ma);
+}
+
+/* Internal data structure for isl_union_pw_multi_aff_multi_val_on_domain.
+ * mv is the value that should be attained on each domain set
+ * res collects the results
+ */
+struct isl_union_pw_multi_aff_multi_val_on_domain_data {
+	isl_multi_val *mv;
+	isl_union_pw_multi_aff *res;
+};
+
+/* Create an isl_pw_multi_aff equal to data->mv on "domain"
+ * and add it to data->res.
+ */
+static isl_stat pw_multi_aff_multi_val_on_domain(__isl_take isl_set *domain,
+	void *user)
+{
+	struct isl_union_pw_multi_aff_multi_val_on_domain_data *data = user;
+	isl_pw_multi_aff *pma;
+	isl_multi_val *mv;
+
+	mv = isl_multi_val_copy(data->mv);
+	pma = isl_pw_multi_aff_multi_val_on_domain(domain, mv);
+	data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma);
+
+	return data->res ? isl_stat_ok : isl_stat_error;
+}
+
+/* Return a union piecewise multi-affine expression
+ * that is equal to "mv" on "domain".
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_multi_val_on_domain(
+	__isl_take isl_union_set *domain, __isl_take isl_multi_val *mv)
+{
+	struct isl_union_pw_multi_aff_multi_val_on_domain_data data;
+	isl_space *space;
+
+	space = isl_union_set_get_space(domain);
+	data.res = isl_union_pw_multi_aff_empty(space);
+	data.mv = mv;
+	if (isl_union_set_foreach_set(domain,
+			&pw_multi_aff_multi_val_on_domain, &data) < 0)
+		data.res = isl_union_pw_multi_aff_free(data.res);
+	isl_union_set_free(domain);
+	isl_multi_val_free(mv);
+	return data.res;
+}
+
+/* Compute the pullback of data->pma by the function represented by "pma2",
+ * provided the spaces match, and add the results to data->res.
+ */
+static isl_stat pullback_entry(__isl_take isl_pw_multi_aff *pma2, void *user)
+{
+	struct isl_union_pw_multi_aff_bin_data *data = user;
+
+	if (!isl_space_tuple_is_equal(data->pma->dim, isl_dim_in,
+				 pma2->dim, isl_dim_out)) {
+		isl_pw_multi_aff_free(pma2);
+		return isl_stat_ok;
+	}
+
+	pma2 = isl_pw_multi_aff_pullback_pw_multi_aff(
+					isl_pw_multi_aff_copy(data->pma), pma2);
+
+	data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma2);
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Compute the pullback of "upma1" by the function represented by "upma2".
+ */
+__isl_give isl_union_pw_multi_aff *
+isl_union_pw_multi_aff_pullback_union_pw_multi_aff(
+	__isl_take isl_union_pw_multi_aff *upma1,
+	__isl_take isl_union_pw_multi_aff *upma2)
+{
+	return bin_op(upma1, upma2, &pullback_entry);
+}
+
+/* Check that the domain space of "upa" matches "space".
+ *
+ * This function is called from isl_multi_union_pw_aff_set_union_pw_aff and
+ * can in principle never fail since the space "space" is that
+ * of the isl_multi_union_pw_aff and is a set space such that
+ * there is no domain space to match.
+ *
+ * We check the parameters and double-check that "space" is
+ * indeed that of a set.
+ */
+static isl_stat isl_union_pw_aff_check_match_domain_space(
+	__isl_keep isl_union_pw_aff *upa, __isl_keep isl_space *space)
+{
+	isl_space *upa_space;
+	isl_bool match;
+
+	if (!upa || !space)
+		return isl_stat_error;
+
+	match = isl_space_is_set(space);
+	if (match < 0)
+		return isl_stat_error;
+	if (!match)
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"expecting set space", return -1);
+
+	upa_space = isl_union_pw_aff_get_space(upa);
+	match = isl_space_has_equal_params(space, upa_space);
+	if (match < 0)
+		goto error;
+	if (!match)
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"parameters don't match", goto error);
+
+	isl_space_free(upa_space);
+	return isl_stat_ok;
+error:
+	isl_space_free(upa_space);
+	return isl_stat_error;
+}
+
+/* Do the parameters of "upa" match those of "space"?
+ */
+static isl_bool isl_union_pw_aff_matching_params(
+	__isl_keep isl_union_pw_aff *upa, __isl_keep isl_space *space)
+{
+	isl_space *upa_space;
+	isl_bool match;
+
+	if (!upa || !space)
+		return isl_bool_error;
+
+	upa_space = isl_union_pw_aff_get_space(upa);
+
+	match = isl_space_has_equal_params(space, upa_space);
+
+	isl_space_free(upa_space);
+	return match;
+}
+
+/* Internal data structure for isl_union_pw_aff_reset_domain_space.
+ * space represents the new parameters.
+ * res collects the results.
+ */
+struct isl_union_pw_aff_reset_params_data {
+	isl_space *space;
+	isl_union_pw_aff *res;
+};
+
+/* Replace the parameters of "pa" by data->space and
+ * add the result to data->res.
+ */
+static isl_stat reset_params(__isl_take isl_pw_aff *pa, void *user)
+{
+	struct isl_union_pw_aff_reset_params_data *data = user;
+	isl_space *space;
+
+	space = isl_pw_aff_get_space(pa);
+	space = isl_space_replace(space, isl_dim_param, data->space);
+	pa = isl_pw_aff_reset_space(pa, space);
+	data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);
+
+	return data->res ? isl_stat_ok : isl_stat_error;
+}
+
+/* Replace the domain space of "upa" by "space".
+ * Since a union expression does not have a (single) domain space,
+ * "space" is necessarily a parameter space.
+ *
+ * Since the order and the names of the parameters determine
+ * the hash value, we need to create a new hash table.
+ */
+static __isl_give isl_union_pw_aff *isl_union_pw_aff_reset_domain_space(
+	__isl_take isl_union_pw_aff *upa, __isl_take isl_space *space)
+{
+	struct isl_union_pw_aff_reset_params_data data = { space };
+	isl_bool match;
+
+	match = isl_union_pw_aff_matching_params(upa, space);
+	if (match < 0)
+		upa = isl_union_pw_aff_free(upa);
+	else if (match) {
+		isl_space_free(space);
+		return upa;
+	}
+
+	data.res = isl_union_pw_aff_empty(isl_space_copy(space));
+	if (isl_union_pw_aff_foreach_pw_aff(upa, &reset_params, &data) < 0)
+		data.res = isl_union_pw_aff_free(data.res);
+
+	isl_union_pw_aff_free(upa);
+	isl_space_free(space);
+	return data.res;
+}
+
+/* Return the floor of "pa".
+ */
+static __isl_give isl_pw_aff *floor_entry(__isl_take isl_pw_aff *pa, void *user)
+{
+	return isl_pw_aff_floor(pa);
+}
+
+/* Given f, return floor(f).
+ */
+__isl_give isl_union_pw_aff *isl_union_pw_aff_floor(
+	__isl_take isl_union_pw_aff *upa)
+{
+	return isl_union_pw_aff_transform_inplace(upa, &floor_entry, NULL);
+}
+
+/* Compute
+ *
+ *	upa mod m = upa - m * floor(upa/m)
+ *
+ * with m an integer value.
+ */
+__isl_give isl_union_pw_aff *isl_union_pw_aff_mod_val(
+	__isl_take isl_union_pw_aff *upa, __isl_take isl_val *m)
+{
+	isl_union_pw_aff *res;
+
+	if (!upa || !m)
+		goto error;
+
+	if (!isl_val_is_int(m))
+		isl_die(isl_val_get_ctx(m), isl_error_invalid,
+			"expecting integer modulo", goto error);
+	if (!isl_val_is_pos(m))
+		isl_die(isl_val_get_ctx(m), isl_error_invalid,
+			"expecting positive modulo", goto error);
+
+	res = isl_union_pw_aff_copy(upa);
+	upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(m));
+	upa = isl_union_pw_aff_floor(upa);
+	upa = isl_union_pw_aff_scale_val(upa, m);
+	res = isl_union_pw_aff_sub(res, upa);
+
+	return res;
+error:
+	isl_val_free(m);
+	isl_union_pw_aff_free(upa);
+	return NULL;
+}
+
+/* Internal data structure for isl_union_pw_aff_aff_on_domain.
+ * "aff" is the symbolic value that the resulting isl_union_pw_aff
+ * needs to attain.
+ * "res" collects the results.
+ */
+struct isl_union_pw_aff_aff_on_domain_data {
+	isl_aff *aff;
+	isl_union_pw_aff *res;
+};
+
+/* Construct a piecewise affine expression that is equal to data->aff
+ * on "domain" and add the result to data->res.
+ */
+static isl_stat pw_aff_aff_on_domain(__isl_take isl_set *domain, void *user)
+{
+	struct isl_union_pw_aff_aff_on_domain_data *data = user;
+	isl_pw_aff *pa;
+	isl_aff *aff;
+	int dim;
+
+	aff = isl_aff_copy(data->aff);
+	dim = isl_set_dim(domain, isl_dim_set);
+	aff = isl_aff_add_dims(aff, isl_dim_in, dim);
+	aff = isl_aff_reset_domain_space(aff, isl_set_get_space(domain));
+	pa = isl_pw_aff_alloc(domain, aff);
+	data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);
+
+	return data->res ? isl_stat_ok : isl_stat_error;
+}
+
+/* Internal data structure for isl_union_pw_multi_aff_get_union_pw_aff.
+ * pos is the output position that needs to be extracted.
+ * res collects the results.
+ */
+struct isl_union_pw_multi_aff_get_union_pw_aff_data {
+	int pos;
+	isl_union_pw_aff *res;
+};
+
+/* Extract an isl_pw_aff corresponding to output dimension "pos" of "pma"
+ * (assuming it has such a dimension) and add it to data->res.
+ */
+static isl_stat get_union_pw_aff(__isl_take isl_pw_multi_aff *pma, void *user)
+{
+	struct isl_union_pw_multi_aff_get_union_pw_aff_data *data = user;
+	int n_out;
+	isl_pw_aff *pa;
+
+	if (!pma)
+		return isl_stat_error;
+
+	n_out = isl_pw_multi_aff_dim(pma, isl_dim_out);
+	if (data->pos >= n_out) {
+		isl_pw_multi_aff_free(pma);
+		return isl_stat_ok;
+	}
+
+	pa = isl_pw_multi_aff_get_pw_aff(pma, data->pos);
+	isl_pw_multi_aff_free(pma);
+
+	data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);
+
+	return data->res ? isl_stat_ok : isl_stat_error;
+}
+
+/* Extract an isl_union_pw_aff corresponding to
+ * output dimension "pos" of "upma".
+ */
+__isl_give isl_union_pw_aff *isl_union_pw_multi_aff_get_union_pw_aff(
+	__isl_keep isl_union_pw_multi_aff *upma, int pos)
+{
+	struct isl_union_pw_multi_aff_get_union_pw_aff_data data;
+	isl_space *space;
+
+	if (!upma)
+		return NULL;
+
+	if (pos < 0)
+		isl_die(isl_union_pw_multi_aff_get_ctx(upma), isl_error_invalid,
+			"cannot extract at negative position", return NULL);
+
+	space = isl_union_pw_multi_aff_get_space(upma);
+	data.res = isl_union_pw_aff_empty(space);
+	data.pos = pos;
+	if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
+						&get_union_pw_aff, &data) < 0)
+		data.res = isl_union_pw_aff_free(data.res);
+
+	return data.res;
+}
+
+/* Return a union piecewise affine expression
+ * that is equal to "aff" on "domain".
+ *
+ * Construct an isl_pw_aff on each of the sets in "domain" and
+ * collect the results.
+ */
+__isl_give isl_union_pw_aff *isl_union_pw_aff_aff_on_domain(
+	__isl_take isl_union_set *domain, __isl_take isl_aff *aff)
+{
+	struct isl_union_pw_aff_aff_on_domain_data data;
+	isl_space *space;
+
+	if (!domain || !aff)
+		goto error;
+	if (!isl_local_space_is_params(aff->ls))
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"expecting parametric expression", goto error);
+
+	space = isl_union_set_get_space(domain);
+	data.res = isl_union_pw_aff_empty(space);
+	data.aff = aff;
+	if (isl_union_set_foreach_set(domain, &pw_aff_aff_on_domain, &data) < 0)
+		data.res = isl_union_pw_aff_free(data.res);
+	isl_union_set_free(domain);
+	isl_aff_free(aff);
+	return data.res;
+error:
+	isl_union_set_free(domain);
+	isl_aff_free(aff);
+	return NULL;
+}
+
+/* Internal data structure for isl_union_pw_aff_val_on_domain.
+ * "v" is the value that the resulting isl_union_pw_aff needs to attain.
+ * "res" collects the results.
+ */
+struct isl_union_pw_aff_val_on_domain_data {
+	isl_val *v;
+	isl_union_pw_aff *res;
+};
+
+/* Construct a piecewise affine expression that is equal to data->v
+ * on "domain" and add the result to data->res.
+ */
+static isl_stat pw_aff_val_on_domain(__isl_take isl_set *domain, void *user)
+{
+	struct isl_union_pw_aff_val_on_domain_data *data = user;
+	isl_pw_aff *pa;
+	isl_val *v;
+
+	v = isl_val_copy(data->v);
+	pa = isl_pw_aff_val_on_domain(domain, v);
+	data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);
+
+	return data->res ? isl_stat_ok : isl_stat_error;
+}
+
+/* Return a union piecewise affine expression
+ * that is equal to "v" on "domain".
+ *
+ * Construct an isl_pw_aff on each of the sets in "domain" and
+ * collect the results.
+ */
+__isl_give isl_union_pw_aff *isl_union_pw_aff_val_on_domain(
+	__isl_take isl_union_set *domain, __isl_take isl_val *v)
+{
+	struct isl_union_pw_aff_val_on_domain_data data;
+	isl_space *space;
+
+	space = isl_union_set_get_space(domain);
+	data.res = isl_union_pw_aff_empty(space);
+	data.v = v;
+	if (isl_union_set_foreach_set(domain, &pw_aff_val_on_domain, &data) < 0)
+		data.res = isl_union_pw_aff_free(data.res);
+	isl_union_set_free(domain);
+	isl_val_free(v);
+	return data.res;
+}
+
+/* Construct a piecewise multi affine expression
+ * that is equal to "pa" and add it to upma.
+ */
+static isl_stat pw_multi_aff_from_pw_aff_entry(__isl_take isl_pw_aff *pa,
+	void *user)
+{
+	isl_union_pw_multi_aff **upma = user;
+	isl_pw_multi_aff *pma;
+
+	pma = isl_pw_multi_aff_from_pw_aff(pa);
+	*upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma);
+
+	return *upma ? isl_stat_ok : isl_stat_error;
+}
+
+/* Construct and return a union piecewise multi affine expression
+ * that is equal to the given union piecewise affine expression.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_pw_aff(
+	__isl_take isl_union_pw_aff *upa)
+{
+	isl_space *space;
+	isl_union_pw_multi_aff *upma;
+
+	if (!upa)
+		return NULL;
+
+	space = isl_union_pw_aff_get_space(upa);
+	upma = isl_union_pw_multi_aff_empty(space);
+
+	if (isl_union_pw_aff_foreach_pw_aff(upa,
+				&pw_multi_aff_from_pw_aff_entry, &upma) < 0)
+		upma = isl_union_pw_multi_aff_free(upma);
+
+	isl_union_pw_aff_free(upa);
+	return upma;
+}
+
+/* Compute the set of elements in the domain of "pa" where it is zero and
+ * add this set to "uset".
+ */
+static isl_stat zero_union_set(__isl_take isl_pw_aff *pa, void *user)
+{
+	isl_union_set **uset = (isl_union_set **)user;
+
+	*uset = isl_union_set_add_set(*uset, isl_pw_aff_zero_set(pa));
+
+	return *uset ? isl_stat_ok : isl_stat_error;
+}
+
+/* Return a union set containing those elements in the domain
+ * of "upa" where it is zero.
+ */
+__isl_give isl_union_set *isl_union_pw_aff_zero_union_set(
+	__isl_take isl_union_pw_aff *upa)
+{
+	isl_union_set *zero;
+
+	zero = isl_union_set_empty(isl_union_pw_aff_get_space(upa));
+	if (isl_union_pw_aff_foreach_pw_aff(upa, &zero_union_set, &zero) < 0)
+		zero = isl_union_set_free(zero);
+
+	isl_union_pw_aff_free(upa);
+	return zero;
+}
+
+/* Convert "pa" to an isl_map and add it to *umap.
+ */
+static isl_stat map_from_pw_aff_entry(__isl_take isl_pw_aff *pa, void *user)
+{
+	isl_union_map **umap = user;
+	isl_map *map;
+
+	map = isl_map_from_pw_aff(pa);
+	*umap = isl_union_map_add_map(*umap, map);
+
+	return *umap ? isl_stat_ok : isl_stat_error;
+}
+
+/* Construct a union map mapping the domain of the union
+ * piecewise affine expression to its range, with the single output dimension
+ * equated to the corresponding affine expressions on their cells.
+ */
+__isl_give isl_union_map *isl_union_map_from_union_pw_aff(
+	__isl_take isl_union_pw_aff *upa)
+{
+	isl_space *space;
+	isl_union_map *umap;
+
+	if (!upa)
+		return NULL;
+
+	space = isl_union_pw_aff_get_space(upa);
+	umap = isl_union_map_empty(space);
+
+	if (isl_union_pw_aff_foreach_pw_aff(upa, &map_from_pw_aff_entry,
+						&umap) < 0)
+		umap = isl_union_map_free(umap);
+
+	isl_union_pw_aff_free(upa);
+	return umap;
+}
+
+/* Internal data structure for isl_union_pw_aff_pullback_union_pw_multi_aff.
+ * upma is the function that is plugged in.
+ * pa is the current part of the function in which upma is plugged in.
+ * res collects the results.
+ */
+struct isl_union_pw_aff_pullback_upma_data {
+	isl_union_pw_multi_aff *upma;
+	isl_pw_aff *pa;
+	isl_union_pw_aff *res;
+};
+
+/* Check if "pma" can be plugged into data->pa.
+ * If so, perform the pullback and add the result to data->res.
+ */
+static isl_stat pa_pb_pma(__isl_take isl_pw_multi_aff *pma, void *user)
+{
+	struct isl_union_pw_aff_pullback_upma_data *data = user;
+	isl_pw_aff *pa;
+
+	if (!isl_space_tuple_is_equal(data->pa->dim, isl_dim_in,
+				 pma->dim, isl_dim_out)) {
+		isl_pw_multi_aff_free(pma);
+		return isl_stat_ok;
+	}
+
+	pa = isl_pw_aff_copy(data->pa);
+	pa = isl_pw_aff_pullback_pw_multi_aff(pa, pma);
+
+	data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);
+
+	return data->res ? isl_stat_ok : isl_stat_error;
+}
+
+/* Check if any of the elements of data->upma can be plugged into pa,
+ * add if so add the result to data->res.
+ */
+static isl_stat upa_pb_upma(__isl_take isl_pw_aff *pa, void *user)
+{
+	struct isl_union_pw_aff_pullback_upma_data *data = user;
+	isl_stat r;
+
+	data->pa = pa;
+	r = isl_union_pw_multi_aff_foreach_pw_multi_aff(data->upma,
+				   &pa_pb_pma, data);
+	isl_pw_aff_free(pa);
+
+	return r;
+}
+
+/* Compute the pullback of "upa" by the function represented by "upma".
+ * In other words, plug in "upma" in "upa".  The result contains
+ * expressions defined over the domain space of "upma".
+ *
+ * Run over all pairs of elements in "upa" and "upma", perform
+ * the pullback when appropriate and collect the results.
+ * If the hash value were based on the domain space rather than
+ * the function space, then we could run through all elements
+ * of "upma" and directly pick out the corresponding element of "upa".
+ */
+__isl_give isl_union_pw_aff *isl_union_pw_aff_pullback_union_pw_multi_aff(
+	__isl_take isl_union_pw_aff *upa,
+	__isl_take isl_union_pw_multi_aff *upma)
+{
+	struct isl_union_pw_aff_pullback_upma_data data = { NULL, NULL };
+	isl_space *space;
+
+	space = isl_union_pw_multi_aff_get_space(upma);
+	upa = isl_union_pw_aff_align_params(upa, space);
+	space = isl_union_pw_aff_get_space(upa);
+	upma = isl_union_pw_multi_aff_align_params(upma, space);
+
+	if (!upa || !upma)
+		goto error;
+
+	data.upma = upma;
+	data.res = isl_union_pw_aff_alloc_same_size(upa);
+	if (isl_union_pw_aff_foreach_pw_aff(upa, &upa_pb_upma, &data) < 0)
+		data.res = isl_union_pw_aff_free(data.res);
+
+	isl_union_pw_aff_free(upa);
+	isl_union_pw_multi_aff_free(upma);
+	return data.res;
+error:
+	isl_union_pw_aff_free(upa);
+	isl_union_pw_multi_aff_free(upma);
+	return NULL;
+}
+
+#undef BASE
+#define BASE union_pw_aff
+#undef DOMBASE
+#define DOMBASE union_set
+
+#define NO_MOVE_DIMS
+#define NO_DIMS
+#define NO_DOMAIN
+#define NO_PRODUCT
+#define NO_SPLICE
+#define NO_ZERO
+#define NO_IDENTITY
+#define NO_GIST
+
+#include <isl_multi_templ.c>
+#include <isl_multi_apply_set.c>
+#include <isl_multi_apply_union_set.c>
+#include <isl_multi_coalesce.c>
+#include <isl_multi_floor.c>
+#include <isl_multi_gist.c>
+#include <isl_multi_intersect.c>
+
+/* Construct a multiple union piecewise affine expression
+ * in the given space with value zero in each of the output dimensions.
+ *
+ * Since there is no canonical zero value for
+ * a union piecewise affine expression, we can only construct
+ * zero-dimensional "zero" value.
+ */
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_zero(
+	__isl_take isl_space *space)
+{
+	if (!space)
+		return NULL;
+
+	if (!isl_space_is_set(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"expecting set space", goto error);
+	if (isl_space_dim(space , isl_dim_out) != 0)
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"expecting 0D space", goto error);
+
+	return isl_multi_union_pw_aff_alloc(space);
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Compute the sum of "mupa1" and "mupa2" on the union of their domains,
+ * with the actual sum on the shared domain and
+ * the defined expression on the symmetric difference of the domains.
+ *
+ * We simply iterate over the elements in both arguments and
+ * call isl_union_pw_aff_union_add on each of them.
+ */
+static __isl_give isl_multi_union_pw_aff *
+isl_multi_union_pw_aff_union_add_aligned(
+	__isl_take isl_multi_union_pw_aff *mupa1,
+	__isl_take isl_multi_union_pw_aff *mupa2)
+{
+	return isl_multi_union_pw_aff_bin_op(mupa1, mupa2,
+					    &isl_union_pw_aff_union_add);
+}
+
+/* Compute the sum of "mupa1" and "mupa2" on the union of their domains,
+ * with the actual sum on the shared domain and
+ * the defined expression on the symmetric difference of the domains.
+ */
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_union_add(
+	__isl_take isl_multi_union_pw_aff *mupa1,
+	__isl_take isl_multi_union_pw_aff *mupa2)
+{
+	return isl_multi_union_pw_aff_align_params_multi_multi_and(mupa1, mupa2,
+				    &isl_multi_union_pw_aff_union_add_aligned);
+}
+
+/* Construct and return a multi union piecewise affine expression
+ * that is equal to the given multi affine expression.
+ */
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_aff(
+	__isl_take isl_multi_aff *ma)
+{
+	isl_multi_pw_aff *mpa;
+
+	mpa = isl_multi_pw_aff_from_multi_aff(ma);
+	return isl_multi_union_pw_aff_from_multi_pw_aff(mpa);
+}
+
+/* Construct and return a multi union piecewise affine expression
+ * that is equal to the given multi piecewise affine expression.
+ */
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_pw_aff(
+	__isl_take isl_multi_pw_aff *mpa)
+{
+	int i, n;
+	isl_space *space;
+	isl_multi_union_pw_aff *mupa;
+
+	if (!mpa)
+		return NULL;
+
+	space = isl_multi_pw_aff_get_space(mpa);
+	space = isl_space_range(space);
+	mupa = isl_multi_union_pw_aff_alloc(space);
+
+	n = isl_multi_pw_aff_dim(mpa, isl_dim_out);
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+		isl_union_pw_aff *upa;
+
+		pa = isl_multi_pw_aff_get_pw_aff(mpa, i);
+		upa = isl_union_pw_aff_from_pw_aff(pa);
+		mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);
+	}
+
+	isl_multi_pw_aff_free(mpa);
+
+	return mupa;
+}
+
+/* Extract the range space of "pma" and assign it to *space.
+ * If *space has already been set (through a previous call to this function),
+ * then check that the range space is the same.
+ */
+static isl_stat extract_space(__isl_take isl_pw_multi_aff *pma, void *user)
+{
+	isl_space **space = user;
+	isl_space *pma_space;
+	isl_bool equal;
+
+	pma_space = isl_space_range(isl_pw_multi_aff_get_space(pma));
+	isl_pw_multi_aff_free(pma);
+
+	if (!pma_space)
+		return isl_stat_error;
+	if (!*space) {
+		*space = pma_space;
+		return isl_stat_ok;
+	}
+
+	equal = isl_space_is_equal(pma_space, *space);
+	isl_space_free(pma_space);
+
+	if (equal < 0)
+		return isl_stat_error;
+	if (!equal)
+		isl_die(isl_space_get_ctx(*space), isl_error_invalid,
+			"range spaces not the same", return isl_stat_error);
+	return isl_stat_ok;
+}
+
+/* Construct and return a multi union piecewise affine expression
+ * that is equal to the given union piecewise multi affine expression.
+ *
+ * In order to be able to perform the conversion, the input
+ * needs to be non-empty and may only involve a single range space.
+ */
+__isl_give isl_multi_union_pw_aff *
+isl_multi_union_pw_aff_from_union_pw_multi_aff(
+	__isl_take isl_union_pw_multi_aff *upma)
+{
+	isl_space *space = NULL;
+	isl_multi_union_pw_aff *mupa;
+	int i, n;
+
+	if (!upma)
+		return NULL;
+	if (isl_union_pw_multi_aff_n_pw_multi_aff(upma) == 0)
+		isl_die(isl_union_pw_multi_aff_get_ctx(upma), isl_error_invalid,
+			"cannot extract range space from empty input",
+			goto error);
+	if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, &extract_space,
+							&space) < 0)
+		goto error;
+
+	if (!space)
+		goto error;
+
+	n = isl_space_dim(space, isl_dim_set);
+	mupa = isl_multi_union_pw_aff_alloc(space);
+
+	for (i = 0; i < n; ++i) {
+		isl_union_pw_aff *upa;
+
+		upa = isl_union_pw_multi_aff_get_union_pw_aff(upma, i);
+		mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);
+	}
+
+	isl_union_pw_multi_aff_free(upma);
+	return mupa;
+error:
+	isl_space_free(space);
+	isl_union_pw_multi_aff_free(upma);
+	return NULL;
+}
+
+/* Try and create an isl_multi_union_pw_aff that is equivalent
+ * to the given isl_union_map.
+ * The isl_union_map is required to be single-valued in each space.
+ * Moreover, it cannot be empty and all range spaces need to be the same.
+ * Otherwise, an error is produced.
+ */
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_map(
+	__isl_take isl_union_map *umap)
+{
+	isl_union_pw_multi_aff *upma;
+
+	upma = isl_union_pw_multi_aff_from_union_map(umap);
+	return isl_multi_union_pw_aff_from_union_pw_multi_aff(upma);
+}
+
+/* Return a multiple union piecewise affine expression
+ * that is equal to "mv" on "domain", assuming "domain" and "mv"
+ * have been aligned.
+ */
+static __isl_give isl_multi_union_pw_aff *
+isl_multi_union_pw_aff_multi_val_on_domain_aligned(
+	__isl_take isl_union_set *domain, __isl_take isl_multi_val *mv)
+{
+	int i, n;
+	isl_space *space;
+	isl_multi_union_pw_aff *mupa;
+
+	if (!domain || !mv)
+		goto error;
+
+	n = isl_multi_val_dim(mv, isl_dim_set);
+	space = isl_multi_val_get_space(mv);
+	mupa = isl_multi_union_pw_aff_alloc(space);
+	for (i = 0; i < n; ++i) {
+		isl_val *v;
+		isl_union_pw_aff *upa;
+
+		v = isl_multi_val_get_val(mv, i);
+		upa = isl_union_pw_aff_val_on_domain(isl_union_set_copy(domain),
+							v);
+		mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);
+	}
+
+	isl_union_set_free(domain);
+	isl_multi_val_free(mv);
+	return mupa;
+error:
+	isl_union_set_free(domain);
+	isl_multi_val_free(mv);
+	return NULL;
+}
+
+/* Return a multiple union piecewise affine expression
+ * that is equal to "mv" on "domain".
+ */
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_val_on_domain(
+	__isl_take isl_union_set *domain, __isl_take isl_multi_val *mv)
+{
+	isl_bool equal_params;
+
+	if (!domain || !mv)
+		goto error;
+	equal_params = isl_space_has_equal_params(domain->dim, mv->space);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params)
+		return isl_multi_union_pw_aff_multi_val_on_domain_aligned(
+								    domain, mv);
+	domain = isl_union_set_align_params(domain,
+						isl_multi_val_get_space(mv));
+	mv = isl_multi_val_align_params(mv, isl_union_set_get_space(domain));
+	return isl_multi_union_pw_aff_multi_val_on_domain_aligned(domain, mv);
+error:
+	isl_union_set_free(domain);
+	isl_multi_val_free(mv);
+	return NULL;
+}
+
+/* Return a multiple union piecewise affine expression
+ * that is equal to "ma" on "domain", assuming "domain" and "ma"
+ * have been aligned.
+ */
+static __isl_give isl_multi_union_pw_aff *
+isl_multi_union_pw_aff_multi_aff_on_domain_aligned(
+	__isl_take isl_union_set *domain, __isl_take isl_multi_aff *ma)
+{
+	int i, n;
+	isl_space *space;
+	isl_multi_union_pw_aff *mupa;
+
+	if (!domain || !ma)
+		goto error;
+
+	n = isl_multi_aff_dim(ma, isl_dim_set);
+	space = isl_multi_aff_get_space(ma);
+	mupa = isl_multi_union_pw_aff_alloc(space);
+	for (i = 0; i < n; ++i) {
+		isl_aff *aff;
+		isl_union_pw_aff *upa;
+
+		aff = isl_multi_aff_get_aff(ma, i);
+		upa = isl_union_pw_aff_aff_on_domain(isl_union_set_copy(domain),
+							aff);
+		mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);
+	}
+
+	isl_union_set_free(domain);
+	isl_multi_aff_free(ma);
+	return mupa;
+error:
+	isl_union_set_free(domain);
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+/* Return a multiple union piecewise affine expression
+ * that is equal to "ma" on "domain".
+ */
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_aff_on_domain(
+	__isl_take isl_union_set *domain, __isl_take isl_multi_aff *ma)
+{
+	isl_bool equal_params;
+
+	if (!domain || !ma)
+		goto error;
+	equal_params = isl_space_has_equal_params(domain->dim, ma->space);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params)
+		return isl_multi_union_pw_aff_multi_aff_on_domain_aligned(
+								    domain, ma);
+	domain = isl_union_set_align_params(domain,
+						isl_multi_aff_get_space(ma));
+	ma = isl_multi_aff_align_params(ma, isl_union_set_get_space(domain));
+	return isl_multi_union_pw_aff_multi_aff_on_domain_aligned(domain, ma);
+error:
+	isl_union_set_free(domain);
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+/* Return a union set containing those elements in the domains
+ * of the elements of "mupa" where they are all zero.
+ */
+__isl_give isl_union_set *isl_multi_union_pw_aff_zero_union_set(
+	__isl_take isl_multi_union_pw_aff *mupa)
+{
+	int i, n;
+	isl_union_pw_aff *upa;
+	isl_union_set *zero;
+
+	if (!mupa)
+		return NULL;
+
+	n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
+	if (n == 0)
+		isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid,
+			"cannot determine zero set "
+			"of zero-dimensional function", goto error);
+
+	upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0);
+	zero = isl_union_pw_aff_zero_union_set(upa);
+
+	for (i = 1; i < n; ++i) {
+		isl_union_set *zero_i;
+
+		upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
+		zero_i = isl_union_pw_aff_zero_union_set(upa);
+
+		zero = isl_union_set_intersect(zero, zero_i);
+	}
+
+	isl_multi_union_pw_aff_free(mupa);
+	return zero;
+error:
+	isl_multi_union_pw_aff_free(mupa);
+	return NULL;
+}
+
+/* Construct a union map mapping the shared domain
+ * of the union piecewise affine expressions to the range of "mupa"
+ * with each dimension in the range equated to the
+ * corresponding union piecewise affine expression.
+ *
+ * The input cannot be zero-dimensional as there is
+ * no way to extract a domain from a zero-dimensional isl_multi_union_pw_aff.
+ */
+__isl_give isl_union_map *isl_union_map_from_multi_union_pw_aff(
+	__isl_take isl_multi_union_pw_aff *mupa)
+{
+	int i, n;
+	isl_space *space;
+	isl_union_map *umap;
+	isl_union_pw_aff *upa;
+
+	if (!mupa)
+		return NULL;
+
+	n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
+	if (n == 0)
+		isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid,
+			"cannot determine domain of zero-dimensional "
+			"isl_multi_union_pw_aff", goto error);
+
+	upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0);
+	umap = isl_union_map_from_union_pw_aff(upa);
+
+	for (i = 1; i < n; ++i) {
+		isl_union_map *umap_i;
+
+		upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
+		umap_i = isl_union_map_from_union_pw_aff(upa);
+		umap = isl_union_map_flat_range_product(umap, umap_i);
+	}
+
+	space = isl_multi_union_pw_aff_get_space(mupa);
+	umap = isl_union_map_reset_range_space(umap, space);
+
+	isl_multi_union_pw_aff_free(mupa);
+	return umap;
+error:
+	isl_multi_union_pw_aff_free(mupa);
+	return NULL;
+}
+
+/* Internal data structure for isl_union_pw_multi_aff_reset_range_space.
+ * "range" is the space from which to set the range space.
+ * "res" collects the results.
+ */
+struct isl_union_pw_multi_aff_reset_range_space_data {
+	isl_space *range;
+	isl_union_pw_multi_aff *res;
+};
+
+/* Replace the range space of "pma" by the range space of data->range and
+ * add the result to data->res.
+ */
+static isl_stat reset_range_space(__isl_take isl_pw_multi_aff *pma, void *user)
+{
+	struct isl_union_pw_multi_aff_reset_range_space_data *data = user;
+	isl_space *space;
+
+	space = isl_pw_multi_aff_get_space(pma);
+	space = isl_space_domain(space);
+	space = isl_space_extend_domain_with_range(space,
+						isl_space_copy(data->range));
+	pma = isl_pw_multi_aff_reset_space(pma, space);
+	data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma);
+
+	return data->res ? isl_stat_ok : isl_stat_error;
+}
+
+/* Replace the range space of all the piecewise affine expressions in "upma" by
+ * the range space of "space".
+ *
+ * This assumes that all these expressions have the same output dimension.
+ *
+ * Since the spaces of the expressions change, so do their hash values.
+ * We therefore need to create a new isl_union_pw_multi_aff.
+ * Note that the hash value is currently computed based on the entire
+ * space even though there can only be a single expression with a given
+ * domain space.
+ */
+static __isl_give isl_union_pw_multi_aff *
+isl_union_pw_multi_aff_reset_range_space(
+	__isl_take isl_union_pw_multi_aff *upma, __isl_take isl_space *space)
+{
+	struct isl_union_pw_multi_aff_reset_range_space_data data = { space };
+	isl_space *space_upma;
+
+	space_upma = isl_union_pw_multi_aff_get_space(upma);
+	data.res = isl_union_pw_multi_aff_empty(space_upma);
+	if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
+					&reset_range_space, &data) < 0)
+		data.res = isl_union_pw_multi_aff_free(data.res);
+
+	isl_space_free(space);
+	isl_union_pw_multi_aff_free(upma);
+	return data.res;
+}
+
+/* Construct and return a union piecewise multi affine expression
+ * that is equal to the given multi union piecewise affine expression.
+ *
+ * In order to be able to perform the conversion, the input
+ * needs to have a least one output dimension.
+ */
+__isl_give isl_union_pw_multi_aff *
+isl_union_pw_multi_aff_from_multi_union_pw_aff(
+	__isl_take isl_multi_union_pw_aff *mupa)
+{
+	int i, n;
+	isl_space *space;
+	isl_union_pw_multi_aff *upma;
+	isl_union_pw_aff *upa;
+
+	if (!mupa)
+		return NULL;
+
+	n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
+	if (n == 0)
+		isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid,
+			"cannot determine domain of zero-dimensional "
+			"isl_multi_union_pw_aff", goto error);
+
+	space = isl_multi_union_pw_aff_get_space(mupa);
+	upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0);
+	upma = isl_union_pw_multi_aff_from_union_pw_aff(upa);
+
+	for (i = 1; i < n; ++i) {
+		isl_union_pw_multi_aff *upma_i;
+
+		upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
+		upma_i = isl_union_pw_multi_aff_from_union_pw_aff(upa);
+		upma = isl_union_pw_multi_aff_flat_range_product(upma, upma_i);
+	}
+
+	upma = isl_union_pw_multi_aff_reset_range_space(upma, space);
+
+	isl_multi_union_pw_aff_free(mupa);
+	return upma;
+error:
+	isl_multi_union_pw_aff_free(mupa);
+	return NULL;
+}
+
+/* Intersect the range of "mupa" with "range".
+ * That is, keep only those domain elements that have a function value
+ * in "range".
+ */
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_range(
+	__isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *range)
+{
+	isl_union_pw_multi_aff *upma;
+	isl_union_set *domain;
+	isl_space *space;
+	int n;
+	int match;
+
+	if (!mupa || !range)
+		goto error;
+
+	space = isl_set_get_space(range);
+	match = isl_space_tuple_is_equal(mupa->space, isl_dim_set,
+					space, isl_dim_set);
+	isl_space_free(space);
+	if (match < 0)
+		goto error;
+	if (!match)
+		isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid,
+			"space don't match", goto error);
+	n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
+	if (n == 0)
+		isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid,
+			"cannot intersect range of zero-dimensional "
+			"isl_multi_union_pw_aff", goto error);
+
+	upma = isl_union_pw_multi_aff_from_multi_union_pw_aff(
+					isl_multi_union_pw_aff_copy(mupa));
+	domain = isl_union_set_from_set(range);
+	domain = isl_union_set_preimage_union_pw_multi_aff(domain, upma);
+	mupa = isl_multi_union_pw_aff_intersect_domain(mupa, domain);
+
+	return mupa;
+error:
+	isl_multi_union_pw_aff_free(mupa);
+	isl_set_free(range);
+	return NULL;
+}
+
+/* Return the shared domain of the elements of "mupa".
+ */
+__isl_give isl_union_set *isl_multi_union_pw_aff_domain(
+	__isl_take isl_multi_union_pw_aff *mupa)
+{
+	int i, n;
+	isl_union_pw_aff *upa;
+	isl_union_set *dom;
+
+	if (!mupa)
+		return NULL;
+
+	n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
+	if (n == 0)
+		isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid,
+			"cannot determine domain", goto error);
+
+	upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0);
+	dom = isl_union_pw_aff_domain(upa);
+	for (i = 1; i < n; ++i) {
+		isl_union_set *dom_i;
+
+		upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
+		dom_i = isl_union_pw_aff_domain(upa);
+		dom = isl_union_set_intersect(dom, dom_i);
+	}
+
+	isl_multi_union_pw_aff_free(mupa);
+	return dom;
+error:
+	isl_multi_union_pw_aff_free(mupa);
+	return NULL;
+}
+
+/* Apply "aff" to "mupa".  The space of "mupa" is equal to the domain of "aff".
+ * In particular, the spaces have been aligned.
+ * The result is defined over the shared domain of the elements of "mupa"
+ *
+ * We first extract the parametric constant part of "aff" and
+ * define that over the shared domain.
+ * Then we iterate over all input dimensions of "aff" and add the corresponding
+ * multiples of the elements of "mupa".
+ * Finally, we consider the integer divisions, calling the function
+ * recursively to obtain an isl_union_pw_aff corresponding to the
+ * integer division argument.
+ */
+static __isl_give isl_union_pw_aff *multi_union_pw_aff_apply_aff(
+	__isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff)
+{
+	int i, n_in, n_div;
+	isl_union_pw_aff *upa;
+	isl_union_set *uset;
+	isl_val *v;
+	isl_aff *cst;
+
+	n_in = isl_aff_dim(aff, isl_dim_in);
+	n_div = isl_aff_dim(aff, isl_dim_div);
+
+	uset = isl_multi_union_pw_aff_domain(isl_multi_union_pw_aff_copy(mupa));
+	cst = isl_aff_copy(aff);
+	cst = isl_aff_drop_dims(cst, isl_dim_div, 0, n_div);
+	cst = isl_aff_drop_dims(cst, isl_dim_in, 0, n_in);
+	cst = isl_aff_project_domain_on_params(cst);
+	upa = isl_union_pw_aff_aff_on_domain(uset, cst);
+
+	for (i = 0; i < n_in; ++i) {
+		isl_union_pw_aff *upa_i;
+
+		if (!isl_aff_involves_dims(aff, isl_dim_in, i, 1))
+			continue;
+		v = isl_aff_get_coefficient_val(aff, isl_dim_in, i);
+		upa_i = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
+		upa_i = isl_union_pw_aff_scale_val(upa_i, v);
+		upa = isl_union_pw_aff_add(upa, upa_i);
+	}
+
+	for (i = 0; i < n_div; ++i) {
+		isl_aff *div;
+		isl_union_pw_aff *upa_i;
+
+		if (!isl_aff_involves_dims(aff, isl_dim_div, i, 1))
+			continue;
+		div = isl_aff_get_div(aff, i);
+		upa_i = multi_union_pw_aff_apply_aff(
+					isl_multi_union_pw_aff_copy(mupa), div);
+		upa_i = isl_union_pw_aff_floor(upa_i);
+		v = isl_aff_get_coefficient_val(aff, isl_dim_div, i);
+		upa_i = isl_union_pw_aff_scale_val(upa_i, v);
+		upa = isl_union_pw_aff_add(upa, upa_i);
+	}
+
+	isl_multi_union_pw_aff_free(mupa);
+	isl_aff_free(aff);
+
+	return upa;
+}
+
+/* Apply "aff" to "mupa".  The space of "mupa" needs to be compatible
+ * with the domain of "aff".
+ * Furthermore, the dimension of this space needs to be greater than zero.
+ * The result is defined over the shared domain of the elements of "mupa"
+ *
+ * We perform these checks and then hand over control to
+ * multi_union_pw_aff_apply_aff.
+ */
+__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_aff(
+	__isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff)
+{
+	isl_space *space1, *space2;
+	int equal;
+
+	mupa = isl_multi_union_pw_aff_align_params(mupa,
+						isl_aff_get_space(aff));
+	aff = isl_aff_align_params(aff, isl_multi_union_pw_aff_get_space(mupa));
+	if (!mupa || !aff)
+		goto error;
+
+	space1 = isl_multi_union_pw_aff_get_space(mupa);
+	space2 = isl_aff_get_domain_space(aff);
+	equal = isl_space_is_equal(space1, space2);
+	isl_space_free(space1);
+	isl_space_free(space2);
+	if (equal < 0)
+		goto error;
+	if (!equal)
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"spaces don't match", goto error);
+	if (isl_aff_dim(aff, isl_dim_in) == 0)
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"cannot determine domains", goto error);
+
+	return multi_union_pw_aff_apply_aff(mupa, aff);
+error:
+	isl_multi_union_pw_aff_free(mupa);
+	isl_aff_free(aff);
+	return NULL;
+}
+
+/* Apply "ma" to "mupa".  The space of "mupa" needs to be compatible
+ * with the domain of "ma".
+ * Furthermore, the dimension of this space needs to be greater than zero,
+ * unless the dimension of the target space of "ma" is also zero.
+ * The result is defined over the shared domain of the elements of "mupa"
+ */
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_multi_aff(
+	__isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma)
+{
+	isl_space *space1, *space2;
+	isl_multi_union_pw_aff *res;
+	int equal;
+	int i, n_out;
+
+	mupa = isl_multi_union_pw_aff_align_params(mupa,
+						isl_multi_aff_get_space(ma));
+	ma = isl_multi_aff_align_params(ma,
+					isl_multi_union_pw_aff_get_space(mupa));
+	if (!mupa || !ma)
+		goto error;
+
+	space1 = isl_multi_union_pw_aff_get_space(mupa);
+	space2 = isl_multi_aff_get_domain_space(ma);
+	equal = isl_space_is_equal(space1, space2);
+	isl_space_free(space1);
+	isl_space_free(space2);
+	if (equal < 0)
+		goto error;
+	if (!equal)
+		isl_die(isl_multi_aff_get_ctx(ma), isl_error_invalid,
+			"spaces don't match", goto error);
+	n_out = isl_multi_aff_dim(ma, isl_dim_out);
+	if (isl_multi_aff_dim(ma, isl_dim_in) == 0 && n_out != 0)
+		isl_die(isl_multi_aff_get_ctx(ma), isl_error_invalid,
+			"cannot determine domains", goto error);
+
+	space1 = isl_space_range(isl_multi_aff_get_space(ma));
+	res = isl_multi_union_pw_aff_alloc(space1);
+
+	for (i = 0; i < n_out; ++i) {
+		isl_aff *aff;
+		isl_union_pw_aff *upa;
+
+		aff = isl_multi_aff_get_aff(ma, i);
+		upa = multi_union_pw_aff_apply_aff(
+					isl_multi_union_pw_aff_copy(mupa), aff);
+		res = isl_multi_union_pw_aff_set_union_pw_aff(res, i, upa);
+	}
+
+	isl_multi_aff_free(ma);
+	isl_multi_union_pw_aff_free(mupa);
+	return res;
+error:
+	isl_multi_union_pw_aff_free(mupa);
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+/* Apply "pa" to "mupa".  The space of "mupa" needs to be compatible
+ * with the domain of "pa".
+ * Furthermore, the dimension of this space needs to be greater than zero.
+ * The result is defined over the shared domain of the elements of "mupa"
+ */
+__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_pw_aff(
+	__isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_pw_aff *pa)
+{
+	int i;
+	int equal;
+	isl_space *space, *space2;
+	isl_union_pw_aff *upa;
+
+	mupa = isl_multi_union_pw_aff_align_params(mupa,
+						isl_pw_aff_get_space(pa));
+	pa = isl_pw_aff_align_params(pa,
+				    isl_multi_union_pw_aff_get_space(mupa));
+	if (!mupa || !pa)
+		goto error;
+
+	space = isl_multi_union_pw_aff_get_space(mupa);
+	space2 = isl_pw_aff_get_domain_space(pa);
+	equal = isl_space_is_equal(space, space2);
+	isl_space_free(space);
+	isl_space_free(space2);
+	if (equal < 0)
+		goto error;
+	if (!equal)
+		isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
+			"spaces don't match", goto error);
+	if (isl_pw_aff_dim(pa, isl_dim_in) == 0)
+		isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
+			"cannot determine domains", goto error);
+
+	space = isl_space_params(isl_multi_union_pw_aff_get_space(mupa));
+	upa = isl_union_pw_aff_empty(space);
+
+	for (i = 0; i < pa->n; ++i) {
+		isl_aff *aff;
+		isl_set *domain;
+		isl_multi_union_pw_aff *mupa_i;
+		isl_union_pw_aff *upa_i;
+
+		mupa_i = isl_multi_union_pw_aff_copy(mupa);
+		domain = isl_set_copy(pa->p[i].set);
+		mupa_i = isl_multi_union_pw_aff_intersect_range(mupa_i, domain);
+		aff = isl_aff_copy(pa->p[i].aff);
+		upa_i = multi_union_pw_aff_apply_aff(mupa_i, aff);
+		upa = isl_union_pw_aff_union_add(upa, upa_i);
+	}
+
+	isl_multi_union_pw_aff_free(mupa);
+	isl_pw_aff_free(pa);
+	return upa;
+error:
+	isl_multi_union_pw_aff_free(mupa);
+	isl_pw_aff_free(pa);
+	return NULL;
+}
+
+/* Apply "pma" to "mupa".  The space of "mupa" needs to be compatible
+ * with the domain of "pma".
+ * Furthermore, the dimension of this space needs to be greater than zero,
+ * unless the dimension of the target space of "pma" is also zero.
+ * The result is defined over the shared domain of the elements of "mupa"
+ */
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_pw_multi_aff(
+	__isl_take isl_multi_union_pw_aff *mupa,
+	__isl_take isl_pw_multi_aff *pma)
+{
+	isl_space *space1, *space2;
+	isl_multi_union_pw_aff *res;
+	int equal;
+	int i, n_out;
+
+	mupa = isl_multi_union_pw_aff_align_params(mupa,
+					isl_pw_multi_aff_get_space(pma));
+	pma = isl_pw_multi_aff_align_params(pma,
+					isl_multi_union_pw_aff_get_space(mupa));
+	if (!mupa || !pma)
+		goto error;
+
+	space1 = isl_multi_union_pw_aff_get_space(mupa);
+	space2 = isl_pw_multi_aff_get_domain_space(pma);
+	equal = isl_space_is_equal(space1, space2);
+	isl_space_free(space1);
+	isl_space_free(space2);
+	if (equal < 0)
+		goto error;
+	if (!equal)
+		isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
+			"spaces don't match", goto error);
+	n_out = isl_pw_multi_aff_dim(pma, isl_dim_out);
+	if (isl_pw_multi_aff_dim(pma, isl_dim_in) == 0 && n_out != 0)
+		isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,
+			"cannot determine domains", goto error);
+
+	space1 = isl_space_range(isl_pw_multi_aff_get_space(pma));
+	res = isl_multi_union_pw_aff_alloc(space1);
+
+	for (i = 0; i < n_out; ++i) {
+		isl_pw_aff *pa;
+		isl_union_pw_aff *upa;
+
+		pa = isl_pw_multi_aff_get_pw_aff(pma, i);
+		upa = isl_multi_union_pw_aff_apply_pw_aff(
+					isl_multi_union_pw_aff_copy(mupa), pa);
+		res = isl_multi_union_pw_aff_set_union_pw_aff(res, i, upa);
+	}
+
+	isl_pw_multi_aff_free(pma);
+	isl_multi_union_pw_aff_free(mupa);
+	return res;
+error:
+	isl_multi_union_pw_aff_free(mupa);
+	isl_pw_multi_aff_free(pma);
+	return NULL;
+}
+
+/* Compute the pullback of "mupa" by the function represented by "upma".
+ * In other words, plug in "upma" in "mupa".  The result contains
+ * expressions defined over the domain space of "upma".
+ *
+ * Run over all elements of "mupa" and plug in "upma" in each of them.
+ */
+__isl_give isl_multi_union_pw_aff *
+isl_multi_union_pw_aff_pullback_union_pw_multi_aff(
+	__isl_take isl_multi_union_pw_aff *mupa,
+	__isl_take isl_union_pw_multi_aff *upma)
+{
+	int i, n;
+
+	mupa = isl_multi_union_pw_aff_align_params(mupa,
+				    isl_union_pw_multi_aff_get_space(upma));
+	upma = isl_union_pw_multi_aff_align_params(upma,
+				    isl_multi_union_pw_aff_get_space(mupa));
+	if (!mupa || !upma)
+		goto error;
+
+	n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
+	for (i = 0; i < n; ++i) {
+		isl_union_pw_aff *upa;
+
+		upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
+		upa = isl_union_pw_aff_pullback_union_pw_multi_aff(upa,
+					    isl_union_pw_multi_aff_copy(upma));
+		mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);
+	}
+
+	isl_union_pw_multi_aff_free(upma);
+	return mupa;
+error:
+	isl_multi_union_pw_aff_free(mupa);
+	isl_union_pw_multi_aff_free(upma);
+	return NULL;
+}
+
+/* Extract the sequence of elements in "mupa" with domain space "space"
+ * (ignoring parameters).
+ *
+ * For the elements of "mupa" that are not defined on the specified space,
+ * the corresponding element in the result is empty.
+ */
+__isl_give isl_multi_pw_aff *isl_multi_union_pw_aff_extract_multi_pw_aff(
+	__isl_keep isl_multi_union_pw_aff *mupa, __isl_take isl_space *space)
+{
+	int i, n;
+	isl_bool equal_params;
+	isl_space *space_mpa = NULL;
+	isl_multi_pw_aff *mpa;
+
+	if (!mupa || !space)
+		goto error;
+
+	space_mpa = isl_multi_union_pw_aff_get_space(mupa);
+	equal_params = isl_space_has_equal_params(space_mpa, space);
+	if (equal_params < 0)
+		goto error;
+	if (!equal_params) {
+		space = isl_space_drop_dims(space, isl_dim_param,
+					0, isl_space_dim(space, isl_dim_param));
+		space = isl_space_align_params(space,
+					isl_space_copy(space_mpa));
+		if (!space)
+			goto error;
+	}
+	space_mpa = isl_space_map_from_domain_and_range(isl_space_copy(space),
+							space_mpa);
+	mpa = isl_multi_pw_aff_alloc(space_mpa);
+
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, 1);
+	n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
+	for (i = 0; i < n; ++i) {
+		isl_union_pw_aff *upa;
+		isl_pw_aff *pa;
+
+		upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);
+		pa = isl_union_pw_aff_extract_pw_aff(upa,
+							isl_space_copy(space));
+		mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);
+		isl_union_pw_aff_free(upa);
+	}
+
+	isl_space_free(space);
+	return mpa;
+error:
+	isl_space_free(space_mpa);
+	isl_space_free(space);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_aff_private.h b/final/lib/External/isl/isl_aff_private.h
new file mode 100644
index 0000000..d503c41
--- /dev/null
+++ b/final/lib/External/isl/isl_aff_private.h
@@ -0,0 +1,180 @@
+#ifndef ISL_AFF_PRIVATE_H
+#define ISL_AFF_PRIVATE_H
+
+#include <isl/aff.h>
+#include <isl/vec.h>
+#include <isl/mat.h>
+#include <isl/local_space.h>
+#include <isl_int.h>
+#include <isl_reordering.h>
+
+/* ls represents the domain space.
+ *
+ * If the first two elements of "v" (the denominator and the constant term)
+ * are zero, then the isl_aff represents NaN.
+ */
+struct isl_aff {
+	int ref;
+
+	isl_local_space	*ls;
+	isl_vec		*v;
+};
+
+#undef EL
+#define EL isl_aff
+
+#include <isl_list_templ.h>
+
+struct isl_pw_aff_piece {
+	struct isl_set *set;
+	struct isl_aff *aff;
+};
+
+struct isl_pw_aff {
+	int ref;
+
+	isl_space *dim;
+
+	int n;
+
+	size_t size;
+	struct isl_pw_aff_piece p[1];
+};
+
+#undef EL
+#define EL isl_pw_aff
+
+#include <isl_list_templ.h>
+
+struct isl_pw_multi_aff_piece {
+	isl_set *set;
+	isl_multi_aff *maff;
+};
+
+struct isl_pw_multi_aff {
+	int ref;
+
+	isl_space *dim;
+
+	int n;
+
+	size_t size;
+	struct isl_pw_multi_aff_piece p[1];
+};
+
+__isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls,
+	__isl_take isl_vec *v);
+__isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls);
+
+__isl_give isl_aff *isl_aff_reset_space_and_domain(__isl_take isl_aff *aff,
+	__isl_take isl_space *space, __isl_take isl_space *domain);
+__isl_give isl_aff *isl_aff_reset_domain_space(__isl_take isl_aff *aff,
+	__isl_take isl_space *dim);
+__isl_give isl_aff *isl_aff_realign_domain(__isl_take isl_aff *aff,
+	__isl_take isl_reordering *r);
+
+int isl_aff_get_constant(__isl_keep isl_aff *aff, isl_int *v);
+__isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_int v);
+__isl_give isl_aff *isl_aff_set_coefficient(__isl_take isl_aff *aff,
+	enum isl_dim_type type, int pos, isl_int v);
+__isl_give isl_aff *isl_aff_add_constant(__isl_take isl_aff *aff, isl_int v);
+
+int isl_aff_plain_cmp(__isl_keep isl_aff *aff1, __isl_keep isl_aff *aff2);
+
+__isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff);
+
+__isl_give isl_aff *isl_aff_expand_divs( __isl_take isl_aff *aff,
+	__isl_take isl_mat *div, int *exp);
+
+__isl_give isl_pw_aff *isl_pw_aff_alloc_size(__isl_take isl_space *space,
+	int n);
+__isl_give isl_pw_aff *isl_pw_aff_reset_space(__isl_take isl_pw_aff *pwaff,
+	__isl_take isl_space *dim);
+__isl_give isl_pw_aff *isl_pw_aff_reset_domain_space(
+	__isl_take isl_pw_aff *pwaff, __isl_take isl_space *space);
+__isl_give isl_pw_aff *isl_pw_aff_add_disjoint(
+	__isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2);
+
+__isl_give isl_pw_aff *isl_pw_aff_union_opt(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2, int max);
+
+__isl_give isl_pw_aff *isl_pw_aff_set_rational(__isl_take isl_pw_aff *pwaff);
+__isl_give isl_pw_aff_list *isl_pw_aff_list_set_rational(
+	__isl_take isl_pw_aff_list *list);
+
+__isl_give isl_pw_aff *isl_pw_aff_scale(__isl_take isl_pw_aff *pwaff,
+	isl_int f);
+__isl_give isl_pw_aff *isl_pw_aff_scale_down(__isl_take isl_pw_aff *pwaff,
+	isl_int f);
+
+isl_bool isl_aff_matching_params(__isl_keep isl_aff *aff,
+	__isl_keep isl_space *space);
+isl_stat isl_aff_check_match_domain_space(__isl_keep isl_aff *aff,
+	__isl_keep isl_space *space);
+
+#undef BASE
+#define BASE aff
+
+#include <isl_multi_templ.h>
+
+__isl_give isl_multi_aff *isl_multi_aff_dup(__isl_keep isl_multi_aff *multi);
+
+__isl_give isl_multi_aff *isl_multi_aff_align_divs(
+	__isl_take isl_multi_aff *maff);
+
+__isl_give isl_multi_aff *isl_multi_aff_from_basic_set_equalities(
+	__isl_take isl_basic_set *bset);
+
+__isl_give isl_multi_aff *isl_multi_aff_from_aff_mat(
+	__isl_take isl_space *space, __isl_take isl_mat *mat);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_domain_space(
+	__isl_take isl_pw_multi_aff *pwmaff, __isl_take isl_space *space);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_reset_space(
+	__isl_take isl_pw_multi_aff *pwmaff, __isl_take isl_space *space);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_add_disjoint(
+	__isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2);
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_out(
+	__isl_take isl_pw_multi_aff *pma,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+void isl_seq_preimage(isl_int *dst, isl_int *src,
+	__isl_keep isl_multi_aff *ma, int n_before, int n_after,
+	int n_div_ma, int n_div_bmap,
+	isl_int f, isl_int c1, isl_int c2, isl_int g, int has_denom);
+
+__isl_give isl_aff *isl_aff_substitute_equalities(__isl_take isl_aff *aff,
+	__isl_take isl_basic_set *eq);
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_substitute(
+	__isl_take isl_pw_multi_aff *pma, enum isl_dim_type type, unsigned pos,
+	__isl_keep isl_pw_aff *subs);
+
+isl_bool isl_pw_aff_matching_params(__isl_keep isl_pw_aff *pa,
+	__isl_keep isl_space *space);
+isl_stat isl_pw_aff_check_match_domain_space(__isl_keep isl_pw_aff *pa,
+	__isl_keep isl_space *space);
+
+__isl_give isl_basic_set *isl_aff_pos_basic_set(__isl_take isl_aff *aff);
+
+#undef BASE
+#define BASE pw_aff
+
+#include <isl_multi_templ.h>
+
+#undef EL
+#define EL isl_union_pw_aff
+
+#include <isl_list_templ.h>
+
+#undef BASE
+#define BASE union_pw_aff
+
+#include <isl_multi_templ.h>
+
+#undef EL
+#define EL isl_union_pw_multi_aff
+
+#include <isl_list_templ.h>
+
+#endif
diff --git a/final/lib/External/isl/isl_affine_hull.c b/final/lib/External/isl/isl_affine_hull.c
new file mode 100644
index 0000000..a60a34c
--- /dev/null
+++ b/final/lib/External/isl/isl_affine_hull.c
@@ -0,0 +1,1220 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_seq.h>
+#include <isl/set.h>
+#include <isl/lp.h>
+#include <isl/map.h>
+#include "isl_equalities.h"
+#include "isl_sample.h"
+#include "isl_tab.h"
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+
+#include <bset_to_bmap.c>
+#include <bset_from_bmap.c>
+#include <set_to_map.c>
+#include <set_from_map.c>
+
+__isl_give isl_basic_map *isl_basic_map_implicit_equalities(
+	__isl_take isl_basic_map *bmap)
+{
+	struct isl_tab *tab;
+
+	if (!bmap)
+		return bmap;
+
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+		return bmap;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NO_IMPLICIT))
+		return bmap;
+	if (bmap->n_ineq <= 1)
+		return bmap;
+
+	tab = isl_tab_from_basic_map(bmap, 0);
+	if (isl_tab_detect_implicit_equalities(tab) < 0)
+		goto error;
+	bmap = isl_basic_map_update_from_tab(bmap, tab);
+	isl_tab_free(tab);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	ISL_F_SET(bmap, ISL_BASIC_MAP_NO_IMPLICIT);
+	return bmap;
+error:
+	isl_tab_free(tab);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_implicit_equalities(
+						struct isl_basic_set *bset)
+{
+	return bset_from_bmap(
+		isl_basic_map_implicit_equalities(bset_to_bmap(bset)));
+}
+
+/* Make eq[row][col] of both bmaps equal so we can add the row
+ * add the column to the common matrix.
+ * Note that because of the echelon form, the columns of row row
+ * after column col are zero.
+ */
+static void set_common_multiple(
+	struct isl_basic_set *bset1, struct isl_basic_set *bset2,
+	unsigned row, unsigned col)
+{
+	isl_int m, c;
+
+	if (isl_int_eq(bset1->eq[row][col], bset2->eq[row][col]))
+		return;
+
+	isl_int_init(c);
+	isl_int_init(m);
+	isl_int_lcm(m, bset1->eq[row][col], bset2->eq[row][col]);
+	isl_int_divexact(c, m, bset1->eq[row][col]);
+	isl_seq_scale(bset1->eq[row], bset1->eq[row], c, col+1);
+	isl_int_divexact(c, m, bset2->eq[row][col]);
+	isl_seq_scale(bset2->eq[row], bset2->eq[row], c, col+1);
+	isl_int_clear(c);
+	isl_int_clear(m);
+}
+
+/* Delete a given equality, moving all the following equalities one up.
+ */
+static void delete_row(struct isl_basic_set *bset, unsigned row)
+{
+	isl_int *t;
+	int r;
+
+	t = bset->eq[row];
+	bset->n_eq--;
+	for (r = row; r < bset->n_eq; ++r)
+		bset->eq[r] = bset->eq[r+1];
+	bset->eq[bset->n_eq] = t;
+}
+
+/* Make first row entries in column col of bset1 identical to
+ * those of bset2, using the fact that entry bset1->eq[row][col]=a
+ * is non-zero.  Initially, these elements of bset1 are all zero.
+ * For each row i < row, we set
+ *		A[i] = a * A[i] + B[i][col] * A[row]
+ *		B[i] = a * B[i]
+ * so that
+ *		A[i][col] = B[i][col] = a * old(B[i][col])
+ */
+static void construct_column(
+	struct isl_basic_set *bset1, struct isl_basic_set *bset2,
+	unsigned row, unsigned col)
+{
+	int r;
+	isl_int a;
+	isl_int b;
+	unsigned total;
+
+	isl_int_init(a);
+	isl_int_init(b);
+	total = 1 + isl_basic_set_n_dim(bset1);
+	for (r = 0; r < row; ++r) {
+		if (isl_int_is_zero(bset2->eq[r][col]))
+			continue;
+		isl_int_gcd(b, bset2->eq[r][col], bset1->eq[row][col]);
+		isl_int_divexact(a, bset1->eq[row][col], b);
+		isl_int_divexact(b, bset2->eq[r][col], b);
+		isl_seq_combine(bset1->eq[r], a, bset1->eq[r],
+					      b, bset1->eq[row], total);
+		isl_seq_scale(bset2->eq[r], bset2->eq[r], a, total);
+	}
+	isl_int_clear(a);
+	isl_int_clear(b);
+	delete_row(bset1, row);
+}
+
+/* Make first row entries in column col of bset1 identical to
+ * those of bset2, using only these entries of the two matrices.
+ * Let t be the last row with different entries.
+ * For each row i < t, we set
+ *	A[i] = (A[t][col]-B[t][col]) * A[i] + (B[i][col]-A[i][col) * A[t]
+ *	B[i] = (A[t][col]-B[t][col]) * B[i] + (B[i][col]-A[i][col) * B[t]
+ * so that
+ *	A[i][col] = B[i][col] = old(A[t][col]*B[i][col]-A[i][col]*B[t][col])
+ */
+static int transform_column(
+	struct isl_basic_set *bset1, struct isl_basic_set *bset2,
+	unsigned row, unsigned col)
+{
+	int i, t;
+	isl_int a, b, g;
+	unsigned total;
+
+	for (t = row-1; t >= 0; --t)
+		if (isl_int_ne(bset1->eq[t][col], bset2->eq[t][col]))
+			break;
+	if (t < 0)
+		return 0;
+
+	total = 1 + isl_basic_set_n_dim(bset1);
+	isl_int_init(a);
+	isl_int_init(b);
+	isl_int_init(g);
+	isl_int_sub(b, bset1->eq[t][col], bset2->eq[t][col]);
+	for (i = 0; i < t; ++i) {
+		isl_int_sub(a, bset2->eq[i][col], bset1->eq[i][col]);
+		isl_int_gcd(g, a, b);
+		isl_int_divexact(a, a, g);
+		isl_int_divexact(g, b, g);
+		isl_seq_combine(bset1->eq[i], g, bset1->eq[i], a, bset1->eq[t],
+				total);
+		isl_seq_combine(bset2->eq[i], g, bset2->eq[i], a, bset2->eq[t],
+				total);
+	}
+	isl_int_clear(a);
+	isl_int_clear(b);
+	isl_int_clear(g);
+	delete_row(bset1, t);
+	delete_row(bset2, t);
+	return 1;
+}
+
+/* The implementation is based on Section 5.2 of Michael Karr,
+ * "Affine Relationships Among Variables of a Program",
+ * except that the echelon form we use starts from the last column
+ * and that we are dealing with integer coefficients.
+ */
+static struct isl_basic_set *affine_hull(
+	struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+	unsigned total;
+	int col;
+	int row;
+
+	if (!bset1 || !bset2)
+		goto error;
+
+	total = 1 + isl_basic_set_n_dim(bset1);
+
+	row = 0;
+	for (col = total-1; col >= 0; --col) {
+		int is_zero1 = row >= bset1->n_eq ||
+			isl_int_is_zero(bset1->eq[row][col]);
+		int is_zero2 = row >= bset2->n_eq ||
+			isl_int_is_zero(bset2->eq[row][col]);
+		if (!is_zero1 && !is_zero2) {
+			set_common_multiple(bset1, bset2, row, col);
+			++row;
+		} else if (!is_zero1 && is_zero2) {
+			construct_column(bset1, bset2, row, col);
+		} else if (is_zero1 && !is_zero2) {
+			construct_column(bset2, bset1, row, col);
+		} else {
+			if (transform_column(bset1, bset2, row, col))
+				--row;
+		}
+	}
+	isl_assert(bset1->ctx, row == bset1->n_eq, goto error);
+	isl_basic_set_free(bset2);
+	bset1 = isl_basic_set_normalize_constraints(bset1);
+	return bset1;
+error:
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return NULL;
+}
+
+/* Find an integer point in the set represented by "tab"
+ * that lies outside of the equality "eq" e(x) = 0.
+ * If "up" is true, look for a point satisfying e(x) - 1 >= 0.
+ * Otherwise, look for a point satisfying -e(x) - 1 >= 0 (i.e., e(x) <= -1).
+ * The point, if found, is returned.
+ * If no point can be found, a zero-length vector is returned.
+ *
+ * Before solving an ILP problem, we first check if simply
+ * adding the normal of the constraint to one of the known
+ * integer points in the basic set represented by "tab"
+ * yields another point inside the basic set.
+ *
+ * The caller of this function ensures that the tableau is bounded or
+ * that tab->basis and tab->n_unbounded have been set appropriately.
+ */
+static struct isl_vec *outside_point(struct isl_tab *tab, isl_int *eq, int up)
+{
+	struct isl_ctx *ctx;
+	struct isl_vec *sample = NULL;
+	struct isl_tab_undo *snap;
+	unsigned dim;
+
+	if (!tab)
+		return NULL;
+	ctx = tab->mat->ctx;
+
+	dim = tab->n_var;
+	sample = isl_vec_alloc(ctx, 1 + dim);
+	if (!sample)
+		return NULL;
+	isl_int_set_si(sample->el[0], 1);
+	isl_seq_combine(sample->el + 1,
+		ctx->one, tab->bmap->sample->el + 1,
+		up ? ctx->one : ctx->negone, eq + 1, dim);
+	if (isl_basic_map_contains(tab->bmap, sample))
+		return sample;
+	isl_vec_free(sample);
+	sample = NULL;
+
+	snap = isl_tab_snap(tab);
+
+	if (!up)
+		isl_seq_neg(eq, eq, 1 + dim);
+	isl_int_sub_ui(eq[0], eq[0], 1);
+
+	if (isl_tab_extend_cons(tab, 1) < 0)
+		goto error;
+	if (isl_tab_add_ineq(tab, eq) < 0)
+		goto error;
+
+	sample = isl_tab_sample(tab);
+
+	isl_int_add_ui(eq[0], eq[0], 1);
+	if (!up)
+		isl_seq_neg(eq, eq, 1 + dim);
+
+	if (sample && isl_tab_rollback(tab, snap) < 0)
+		goto error;
+
+	return sample;
+error:
+	isl_vec_free(sample);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_recession_cone(
+	__isl_take isl_basic_set *bset)
+{
+	int i;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		return NULL;
+	isl_assert(bset->ctx, bset->n_div == 0, goto error);
+
+	for (i = 0; i < bset->n_eq; ++i)
+		isl_int_set_si(bset->eq[i][0], 0);
+
+	for (i = 0; i < bset->n_ineq; ++i)
+		isl_int_set_si(bset->ineq[i][0], 0);
+
+	ISL_F_CLR(bset, ISL_BASIC_SET_NO_IMPLICIT);
+	return isl_basic_set_implicit_equalities(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Move "sample" to a point that is one up (or down) from the original
+ * point in dimension "pos".
+ */
+static void adjacent_point(__isl_keep isl_vec *sample, int pos, int up)
+{
+	if (up)
+		isl_int_add_ui(sample->el[1 + pos], sample->el[1 + pos], 1);
+	else
+		isl_int_sub_ui(sample->el[1 + pos], sample->el[1 + pos], 1);
+}
+
+/* Check if any points that are adjacent to "sample" also belong to "bset".
+ * If so, add them to "hull" and return the updated hull.
+ *
+ * Before checking whether and adjacent point belongs to "bset", we first
+ * check whether it already belongs to "hull" as this test is typically
+ * much cheaper.
+ */
+static __isl_give isl_basic_set *add_adjacent_points(
+	__isl_take isl_basic_set *hull, __isl_take isl_vec *sample,
+	__isl_keep isl_basic_set *bset)
+{
+	int i, up;
+	int dim;
+
+	if (!sample)
+		goto error;
+
+	dim = isl_basic_set_dim(hull, isl_dim_set);
+
+	for (i = 0; i < dim; ++i) {
+		for (up = 0; up <= 1; ++up) {
+			int contains;
+			isl_basic_set *point;
+
+			adjacent_point(sample, i, up);
+			contains = isl_basic_set_contains(hull, sample);
+			if (contains < 0)
+				goto error;
+			if (contains) {
+				adjacent_point(sample, i, !up);
+				continue;
+			}
+			contains = isl_basic_set_contains(bset, sample);
+			if (contains < 0)
+				goto error;
+			if (contains) {
+				point = isl_basic_set_from_vec(
+							isl_vec_copy(sample));
+				hull = affine_hull(hull, point);
+			}
+			adjacent_point(sample, i, !up);
+			if (contains)
+				break;
+		}
+	}
+
+	isl_vec_free(sample);
+
+	return hull;
+error:
+	isl_vec_free(sample);
+	isl_basic_set_free(hull);
+	return NULL;
+}
+
+/* Extend an initial (under-)approximation of the affine hull of basic
+ * set represented by the tableau "tab"
+ * by looking for points that do not satisfy one of the equalities
+ * in the current approximation and adding them to that approximation
+ * until no such points can be found any more.
+ *
+ * The caller of this function ensures that "tab" is bounded or
+ * that tab->basis and tab->n_unbounded have been set appropriately.
+ *
+ * "bset" may be either NULL or the basic set represented by "tab".
+ * If "bset" is not NULL, we check for any point we find if any
+ * of its adjacent points also belong to "bset".
+ */
+static __isl_give isl_basic_set *extend_affine_hull(struct isl_tab *tab,
+	__isl_take isl_basic_set *hull, __isl_keep isl_basic_set *bset)
+{
+	int i, j;
+	unsigned dim;
+
+	if (!tab || !hull)
+		goto error;
+
+	dim = tab->n_var;
+
+	if (isl_tab_extend_cons(tab, 2 * dim + 1) < 0)
+		goto error;
+
+	for (i = 0; i < dim; ++i) {
+		struct isl_vec *sample;
+		struct isl_basic_set *point;
+		for (j = 0; j < hull->n_eq; ++j) {
+			sample = outside_point(tab, hull->eq[j], 1);
+			if (!sample)
+				goto error;
+			if (sample->size > 0)
+				break;
+			isl_vec_free(sample);
+			sample = outside_point(tab, hull->eq[j], 0);
+			if (!sample)
+				goto error;
+			if (sample->size > 0)
+				break;
+			isl_vec_free(sample);
+
+			if (isl_tab_add_eq(tab, hull->eq[j]) < 0)
+				goto error;
+		}
+		if (j == hull->n_eq)
+			break;
+		if (tab->samples &&
+		    isl_tab_add_sample(tab, isl_vec_copy(sample)) < 0)
+			hull = isl_basic_set_free(hull);
+		if (bset)
+			hull = add_adjacent_points(hull, isl_vec_copy(sample),
+						    bset);
+		point = isl_basic_set_from_vec(sample);
+		hull = affine_hull(hull, point);
+		if (!hull)
+			return NULL;
+	}
+
+	return hull;
+error:
+	isl_basic_set_free(hull);
+	return NULL;
+}
+
+/* Construct an initial underapproximation of the hull of "bset"
+ * from "sample" and any of its adjacent points that also belong to "bset".
+ */
+static __isl_give isl_basic_set *initialize_hull(__isl_keep isl_basic_set *bset,
+	__isl_take isl_vec *sample)
+{
+	isl_basic_set *hull;
+
+	hull = isl_basic_set_from_vec(isl_vec_copy(sample));
+	hull = add_adjacent_points(hull, sample, bset);
+
+	return hull;
+}
+
+/* Look for all equalities satisfied by the integer points in bset,
+ * which is assumed to be bounded.
+ *
+ * The equalities are obtained by successively looking for
+ * a point that is affinely independent of the points found so far.
+ * In particular, for each equality satisfied by the points so far,
+ * we check if there is any point on a hyperplane parallel to the
+ * corresponding hyperplane shifted by at least one (in either direction).
+ */
+static struct isl_basic_set *uset_affine_hull_bounded(struct isl_basic_set *bset)
+{
+	struct isl_vec *sample = NULL;
+	struct isl_basic_set *hull;
+	struct isl_tab *tab = NULL;
+	unsigned dim;
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return bset;
+
+	dim = isl_basic_set_n_dim(bset);
+
+	if (bset->sample && bset->sample->size == 1 + dim) {
+		int contains = isl_basic_set_contains(bset, bset->sample);
+		if (contains < 0)
+			goto error;
+		if (contains) {
+			if (dim == 0)
+				return bset;
+			sample = isl_vec_copy(bset->sample);
+		} else {
+			isl_vec_free(bset->sample);
+			bset->sample = NULL;
+		}
+	}
+
+	tab = isl_tab_from_basic_set(bset, 1);
+	if (!tab)
+		goto error;
+	if (tab->empty) {
+		isl_tab_free(tab);
+		isl_vec_free(sample);
+		return isl_basic_set_set_to_empty(bset);
+	}
+
+	if (!sample) {
+		struct isl_tab_undo *snap;
+		snap = isl_tab_snap(tab);
+		sample = isl_tab_sample(tab);
+		if (isl_tab_rollback(tab, snap) < 0)
+			goto error;
+		isl_vec_free(tab->bmap->sample);
+		tab->bmap->sample = isl_vec_copy(sample);
+	}
+
+	if (!sample)
+		goto error;
+	if (sample->size == 0) {
+		isl_tab_free(tab);
+		isl_vec_free(sample);
+		return isl_basic_set_set_to_empty(bset);
+	}
+
+	hull = initialize_hull(bset, sample);
+
+	hull = extend_affine_hull(tab, hull, bset);
+	isl_basic_set_free(bset);
+	isl_tab_free(tab);
+
+	return hull;
+error:
+	isl_vec_free(sample);
+	isl_tab_free(tab);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Given an unbounded tableau and an integer point satisfying the tableau,
+ * construct an initial affine hull containing the recession cone
+ * shifted to the given point.
+ *
+ * The unbounded directions are taken from the last rows of the basis,
+ * which is assumed to have been initialized appropriately.
+ */
+static __isl_give isl_basic_set *initial_hull(struct isl_tab *tab,
+	__isl_take isl_vec *vec)
+{
+	int i;
+	int k;
+	struct isl_basic_set *bset = NULL;
+	struct isl_ctx *ctx;
+	unsigned dim;
+
+	if (!vec || !tab)
+		return NULL;
+	ctx = vec->ctx;
+	isl_assert(ctx, vec->size != 0, goto error);
+
+	bset = isl_basic_set_alloc(ctx, 0, vec->size - 1, 0, vec->size - 1, 0);
+	if (!bset)
+		goto error;
+	dim = isl_basic_set_n_dim(bset) - tab->n_unbounded;
+	for (i = 0; i < dim; ++i) {
+		k = isl_basic_set_alloc_equality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bset->eq[k] + 1, tab->basis->row[1 + i] + 1,
+			    vec->size - 1);
+		isl_seq_inner_product(bset->eq[k] + 1, vec->el +1,
+				      vec->size - 1, &bset->eq[k][0]);
+		isl_int_neg(bset->eq[k][0], bset->eq[k][0]);
+	}
+	bset->sample = vec;
+	bset = isl_basic_set_gauss(bset, NULL);
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+/* Given a tableau of a set and a tableau of the corresponding
+ * recession cone, detect and add all equalities to the tableau.
+ * If the tableau is bounded, then we can simply keep the
+ * tableau in its state after the return from extend_affine_hull.
+ * However, if the tableau is unbounded, then
+ * isl_tab_set_initial_basis_with_cone will add some additional
+ * constraints to the tableau that have to be removed again.
+ * In this case, we therefore rollback to the state before
+ * any constraints were added and then add the equalities back in.
+ */
+struct isl_tab *isl_tab_detect_equalities(struct isl_tab *tab,
+	struct isl_tab *tab_cone)
+{
+	int j;
+	struct isl_vec *sample;
+	struct isl_basic_set *hull = NULL;
+	struct isl_tab_undo *snap;
+
+	if (!tab || !tab_cone)
+		goto error;
+
+	snap = isl_tab_snap(tab);
+
+	isl_mat_free(tab->basis);
+	tab->basis = NULL;
+
+	isl_assert(tab->mat->ctx, tab->bmap, goto error);
+	isl_assert(tab->mat->ctx, tab->samples, goto error);
+	isl_assert(tab->mat->ctx, tab->samples->n_col == 1 + tab->n_var, goto error);
+	isl_assert(tab->mat->ctx, tab->n_sample > tab->n_outside, goto error);
+
+	if (isl_tab_set_initial_basis_with_cone(tab, tab_cone) < 0)
+		goto error;
+
+	sample = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var);
+	if (!sample)
+		goto error;
+
+	isl_seq_cpy(sample->el, tab->samples->row[tab->n_outside], sample->size);
+
+	isl_vec_free(tab->bmap->sample);
+	tab->bmap->sample = isl_vec_copy(sample);
+
+	if (tab->n_unbounded == 0)
+		hull = isl_basic_set_from_vec(isl_vec_copy(sample));
+	else
+		hull = initial_hull(tab, isl_vec_copy(sample));
+
+	for (j = tab->n_outside + 1; j < tab->n_sample; ++j) {
+		isl_seq_cpy(sample->el, tab->samples->row[j], sample->size);
+		hull = affine_hull(hull,
+				isl_basic_set_from_vec(isl_vec_copy(sample)));
+	}
+
+	isl_vec_free(sample);
+
+	hull = extend_affine_hull(tab, hull, NULL);
+	if (!hull)
+		goto error;
+
+	if (tab->n_unbounded == 0) {
+		isl_basic_set_free(hull);
+		return tab;
+	}
+
+	if (isl_tab_rollback(tab, snap) < 0)
+		goto error;
+
+	if (hull->n_eq > tab->n_zero) {
+		for (j = 0; j < hull->n_eq; ++j) {
+			isl_seq_normalize(tab->mat->ctx, hull->eq[j], 1 + tab->n_var);
+			if (isl_tab_add_eq(tab, hull->eq[j]) < 0)
+				goto error;
+		}
+	}
+
+	isl_basic_set_free(hull);
+
+	return tab;
+error:
+	isl_basic_set_free(hull);
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Compute the affine hull of "bset", where "cone" is the recession cone
+ * of "bset".
+ *
+ * We first compute a unimodular transformation that puts the unbounded
+ * directions in the last dimensions.  In particular, we take a transformation
+ * that maps all equalities to equalities (in HNF) on the first dimensions.
+ * Let x be the original dimensions and y the transformed, with y_1 bounded
+ * and y_2 unbounded.
+ *
+ *	       [ y_1 ]			[ y_1 ]   [ Q_1 ]
+ *	x = U  [ y_2 ]			[ y_2 ] = [ Q_2 ] x
+ *
+ * Let's call the input basic set S.  We compute S' = preimage(S, U)
+ * and drop the final dimensions including any constraints involving them.
+ * This results in set S''.
+ * Then we compute the affine hull A'' of S''.
+ * Let F y_1 >= g be the constraint system of A''.  In the transformed
+ * space the y_2 are unbounded, so we can add them back without any constraints,
+ * resulting in
+ *
+ *		        [ y_1 ]
+ *		[ F 0 ] [ y_2 ] >= g
+ * or
+ *		        [ Q_1 ]
+ *		[ F 0 ] [ Q_2 ] x >= g
+ * or
+ *		F Q_1 x >= g
+ *
+ * The affine hull in the original space is then obtained as
+ * A = preimage(A'', Q_1).
+ */
+static struct isl_basic_set *affine_hull_with_cone(struct isl_basic_set *bset,
+	struct isl_basic_set *cone)
+{
+	unsigned total;
+	unsigned cone_dim;
+	struct isl_basic_set *hull;
+	struct isl_mat *M, *U, *Q;
+
+	if (!bset || !cone)
+		goto error;
+
+	total = isl_basic_set_total_dim(cone);
+	cone_dim = total - cone->n_eq;
+
+	M = isl_mat_sub_alloc6(bset->ctx, cone->eq, 0, cone->n_eq, 1, total);
+	M = isl_mat_left_hermite(M, 0, &U, &Q);
+	if (!M)
+		goto error;
+	isl_mat_free(M);
+
+	U = isl_mat_lin_to_aff(U);
+	bset = isl_basic_set_preimage(bset, isl_mat_copy(U));
+
+	bset = isl_basic_set_drop_constraints_involving(bset, total - cone_dim,
+							cone_dim);
+	bset = isl_basic_set_drop_dims(bset, total - cone_dim, cone_dim);
+
+	Q = isl_mat_lin_to_aff(Q);
+	Q = isl_mat_drop_rows(Q, 1 + total - cone_dim, cone_dim);
+
+	if (bset && bset->sample && bset->sample->size == 1 + total)
+		bset->sample = isl_mat_vec_product(isl_mat_copy(Q), bset->sample);
+
+	hull = uset_affine_hull_bounded(bset);
+
+	if (!hull) {
+		isl_mat_free(Q);
+		isl_mat_free(U);
+	} else {
+		struct isl_vec *sample = isl_vec_copy(hull->sample);
+		U = isl_mat_drop_cols(U, 1 + total - cone_dim, cone_dim);
+		if (sample && sample->size > 0)
+			sample = isl_mat_vec_product(U, sample);
+		else
+			isl_mat_free(U);
+		hull = isl_basic_set_preimage(hull, Q);
+		if (hull) {
+			isl_vec_free(hull->sample);
+			hull->sample = sample;
+		} else
+			isl_vec_free(sample);
+	}
+
+	isl_basic_set_free(cone);
+
+	return hull;
+error:
+	isl_basic_set_free(bset);
+	isl_basic_set_free(cone);
+	return NULL;
+}
+
+/* Look for all equalities satisfied by the integer points in bset,
+ * which is assumed not to have any explicit equalities.
+ *
+ * The equalities are obtained by successively looking for
+ * a point that is affinely independent of the points found so far.
+ * In particular, for each equality satisfied by the points so far,
+ * we check if there is any point on a hyperplane parallel to the
+ * corresponding hyperplane shifted by at least one (in either direction).
+ *
+ * Before looking for any outside points, we first compute the recession
+ * cone.  The directions of this recession cone will always be part
+ * of the affine hull, so there is no need for looking for any points
+ * in these directions.
+ * In particular, if the recession cone is full-dimensional, then
+ * the affine hull is simply the whole universe.
+ */
+static struct isl_basic_set *uset_affine_hull(struct isl_basic_set *bset)
+{
+	struct isl_basic_set *cone;
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return bset;
+
+	cone = isl_basic_set_recession_cone(isl_basic_set_copy(bset));
+	if (!cone)
+		goto error;
+	if (cone->n_eq == 0) {
+		isl_space *space;
+		space = isl_basic_set_get_space(bset);
+		isl_basic_set_free(cone);
+		isl_basic_set_free(bset);
+		return isl_basic_set_universe(space);
+	}
+
+	if (cone->n_eq < isl_basic_set_total_dim(cone))
+		return affine_hull_with_cone(bset, cone);
+
+	isl_basic_set_free(cone);
+	return uset_affine_hull_bounded(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Look for all equalities satisfied by the integer points in bmap
+ * that are independent of the equalities already explicitly available
+ * in bmap.
+ *
+ * We first remove all equalities already explicitly available,
+ * then look for additional equalities in the reduced space
+ * and then transform the result to the original space.
+ * The original equalities are _not_ added to this set.  This is
+ * the responsibility of the calling function.
+ * The resulting basic set has all meaning about the dimensions removed.
+ * In particular, dimensions that correspond to existential variables
+ * in bmap and that are found to be fixed are not removed.
+ */
+static struct isl_basic_set *equalities_in_underlying_set(
+						struct isl_basic_map *bmap)
+{
+	struct isl_mat *T1 = NULL;
+	struct isl_mat *T2 = NULL;
+	struct isl_basic_set *bset = NULL;
+	struct isl_basic_set *hull = NULL;
+
+	bset = isl_basic_map_underlying_set(bmap);
+	if (!bset)
+		return NULL;
+	if (bset->n_eq)
+		bset = isl_basic_set_remove_equalities(bset, &T1, &T2);
+	if (!bset)
+		goto error;
+
+	hull = uset_affine_hull(bset);
+	if (!T2)
+		return hull;
+
+	if (!hull) {
+		isl_mat_free(T1);
+		isl_mat_free(T2);
+	} else {
+		struct isl_vec *sample = isl_vec_copy(hull->sample);
+		if (sample && sample->size > 0)
+			sample = isl_mat_vec_product(T1, sample);
+		else
+			isl_mat_free(T1);
+		hull = isl_basic_set_preimage(hull, T2);
+		if (hull) {
+			isl_vec_free(hull->sample);
+			hull->sample = sample;
+		} else
+			isl_vec_free(sample);
+	}
+
+	return hull;
+error:
+	isl_mat_free(T1);
+	isl_mat_free(T2);
+	isl_basic_set_free(bset);
+	isl_basic_set_free(hull);
+	return NULL;
+}
+
+/* Detect and make explicit all equalities satisfied by the (integer)
+ * points in bmap.
+ */
+__isl_give isl_basic_map *isl_basic_map_detect_equalities(
+	__isl_take isl_basic_map *bmap)
+{
+	int i, j;
+	struct isl_basic_set *hull = NULL;
+
+	if (!bmap)
+		return NULL;
+	if (bmap->n_ineq == 0)
+		return bmap;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+		return bmap;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_ALL_EQUALITIES))
+		return bmap;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+		return isl_basic_map_implicit_equalities(bmap);
+
+	hull = equalities_in_underlying_set(isl_basic_map_copy(bmap));
+	if (!hull)
+		goto error;
+	if (ISL_F_ISSET(hull, ISL_BASIC_SET_EMPTY)) {
+		isl_basic_set_free(hull);
+		return isl_basic_map_set_to_empty(bmap);
+	}
+	bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim), 0,
+					hull->n_eq, 0);
+	for (i = 0; i < hull->n_eq; ++i) {
+		j = isl_basic_map_alloc_equality(bmap);
+		if (j < 0)
+			goto error;
+		isl_seq_cpy(bmap->eq[j], hull->eq[i],
+				1 + isl_basic_set_total_dim(hull));
+	}
+	isl_vec_free(bmap->sample);
+	bmap->sample = isl_vec_copy(hull->sample);
+	isl_basic_set_free(hull);
+	ISL_F_SET(bmap, ISL_BASIC_MAP_NO_IMPLICIT | ISL_BASIC_MAP_ALL_EQUALITIES);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_set_free(hull);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_detect_equalities(
+						__isl_take isl_basic_set *bset)
+{
+	return bset_from_bmap(
+		isl_basic_map_detect_equalities(bset_to_bmap(bset)));
+}
+
+__isl_give isl_map *isl_map_detect_equalities(__isl_take isl_map *map)
+{
+	return isl_map_inline_foreach_basic_map(map,
+					    &isl_basic_map_detect_equalities);
+}
+
+__isl_give isl_set *isl_set_detect_equalities(__isl_take isl_set *set)
+{
+	return set_from_map(isl_map_detect_equalities(set_to_map(set)));
+}
+
+/* Return the superset of "bmap" described by the equalities
+ * satisfied by "bmap" that are already known.
+ */
+__isl_give isl_basic_map *isl_basic_map_plain_affine_hull(
+	__isl_take isl_basic_map *bmap)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (bmap)
+		isl_basic_map_free_inequality(bmap, bmap->n_ineq);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+}
+
+/* Return the superset of "bset" described by the equalities
+ * satisfied by "bset" that are already known.
+ */
+__isl_give isl_basic_set *isl_basic_set_plain_affine_hull(
+	__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_plain_affine_hull(bset);
+}
+
+/* After computing the rational affine hull (by detecting the implicit
+ * equalities), we compute the additional equalities satisfied by
+ * the integer points (if any) and add the original equalities back in.
+ */
+__isl_give isl_basic_map *isl_basic_map_affine_hull(
+	__isl_take isl_basic_map *bmap)
+{
+	bmap = isl_basic_map_detect_equalities(bmap);
+	bmap = isl_basic_map_plain_affine_hull(bmap);
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_affine_hull(struct isl_basic_set *bset)
+{
+	return bset_from_bmap(isl_basic_map_affine_hull(bset_to_bmap(bset)));
+}
+
+/* Given a rational affine matrix "M", add stride constraints to "bmap"
+ * that ensure that
+ *
+ *		M(x)
+ *
+ * is an integer vector.  The variables x include all the variables
+ * of "bmap" except the unknown divs.
+ *
+ * If d is the common denominator of M, then we need to impose that
+ *
+ *		d M(x) = 0 	mod d
+ *
+ * or
+ *
+ *		exists alpha : d M(x) = d alpha
+ *
+ * This function is similar to add_strides in isl_morph.c
+ */
+static __isl_give isl_basic_map *add_strides(__isl_take isl_basic_map *bmap,
+	__isl_keep isl_mat *M, int n_known)
+{
+	int i, div, k;
+	isl_int gcd;
+
+	if (isl_int_is_one(M->row[0][0]))
+		return bmap;
+
+	bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+					M->n_row - 1, M->n_row - 1, 0);
+
+	isl_int_init(gcd);
+	for (i = 1; i < M->n_row; ++i) {
+		isl_seq_gcd(M->row[i], M->n_col, &gcd);
+		if (isl_int_is_divisible_by(gcd, M->row[0][0]))
+			continue;
+		div = isl_basic_map_alloc_div(bmap);
+		if (div < 0)
+			goto error;
+		isl_int_set_si(bmap->div[div][0], 0);
+		k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bmap->eq[k], M->row[i], M->n_col);
+		isl_seq_clr(bmap->eq[k] + M->n_col, bmap->n_div - n_known);
+		isl_int_set(bmap->eq[k][M->n_col - n_known + div],
+			    M->row[0][0]);
+	}
+	isl_int_clear(gcd);
+
+	return bmap;
+error:
+	isl_int_clear(gcd);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* If there are any equalities that involve (multiple) unknown divs,
+ * then extract the stride information encoded by those equalities
+ * and make it explicitly available in "bmap".
+ *
+ * We first sort the divs so that the unknown divs appear last and
+ * then we count how many equalities involve these divs.
+ *
+ * Let these equalities be of the form
+ *
+ *		A(x) + B y = 0
+ *
+ * where y represents the unknown divs and x the remaining variables.
+ * Let [H 0] be the Hermite Normal Form of B, i.e.,
+ *
+ *		B = [H 0] Q
+ *
+ * Then x is a solution of the equalities iff
+ *
+ *		H^-1 A(x) (= - [I 0] Q y)
+ *
+ * is an integer vector.  Let d be the common denominator of H^-1.
+ * We impose
+ *
+ *		d H^-1 A(x) = d alpha
+ *
+ * in add_strides, with alpha fresh existentially quantified variables.
+ */
+static __isl_give isl_basic_map *isl_basic_map_make_strides_explicit(
+	__isl_take isl_basic_map *bmap)
+{
+	int known;
+	int n_known;
+	int n, n_col;
+	int total;
+	isl_ctx *ctx;
+	isl_mat *A, *B, *M;
+
+	known = isl_basic_map_divs_known(bmap);
+	if (known < 0)
+		return isl_basic_map_free(bmap);
+	if (known)
+		return bmap;
+	bmap = isl_basic_map_sort_divs(bmap);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	if (!bmap)
+		return NULL;
+
+	for (n_known = 0; n_known < bmap->n_div; ++n_known)
+		if (isl_int_is_zero(bmap->div[n_known][0]))
+			break;
+	ctx = isl_basic_map_get_ctx(bmap);
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+	for (n = 0; n < bmap->n_eq; ++n)
+		if (isl_seq_first_non_zero(bmap->eq[n] + 1 + total + n_known,
+					    bmap->n_div - n_known) == -1)
+			break;
+	if (n == 0)
+		return bmap;
+	B = isl_mat_sub_alloc6(ctx, bmap->eq, 0, n, 0, 1 + total + n_known);
+	n_col = bmap->n_div - n_known;
+	A = isl_mat_sub_alloc6(ctx, bmap->eq, 0, n, 1 + total + n_known, n_col);
+	A = isl_mat_left_hermite(A, 0, NULL, NULL);
+	A = isl_mat_drop_cols(A, n, n_col - n);
+	A = isl_mat_lin_to_aff(A);
+	A = isl_mat_right_inverse(A);
+	B = isl_mat_insert_zero_rows(B, 0, 1);
+	B = isl_mat_set_element_si(B, 0, 0, 1);
+	M = isl_mat_product(A, B);
+	if (!M)
+		return isl_basic_map_free(bmap);
+	bmap = add_strides(bmap, M, n_known);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	isl_mat_free(M);
+
+	return bmap;
+}
+
+/* Compute the affine hull of each basic map in "map" separately
+ * and make all stride information explicit so that we can remove
+ * all unknown divs without losing this information.
+ * The result is also guaranteed to be gaussed.
+ *
+ * In simple cases where a div is determined by an equality,
+ * calling isl_basic_map_gauss is enough to make the stride information
+ * explicit, as it will derive an explicit representation for the div
+ * from the equality.  If, however, the stride information
+ * is encoded through multiple unknown divs then we need to make
+ * some extra effort in isl_basic_map_make_strides_explicit.
+ */
+static __isl_give isl_map *isl_map_local_affine_hull(__isl_take isl_map *map)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_affine_hull(map->p[i]);
+		map->p[i] = isl_basic_map_gauss(map->p[i], NULL);
+		map->p[i] = isl_basic_map_make_strides_explicit(map->p[i]);
+		if (!map->p[i])
+			return isl_map_free(map);
+	}
+
+	return map;
+}
+
+static __isl_give isl_set *isl_set_local_affine_hull(__isl_take isl_set *set)
+{
+	return isl_map_local_affine_hull(set);
+}
+
+/* Return an empty basic map living in the same space as "map".
+ */
+static __isl_give isl_basic_map *replace_map_by_empty_basic_map(
+	__isl_take isl_map *map)
+{
+	isl_space *space;
+
+	space = isl_map_get_space(map);
+	isl_map_free(map);
+	return isl_basic_map_empty(space);
+}
+
+/* Compute the affine hull of "map".
+ *
+ * We first compute the affine hull of each basic map separately.
+ * Then we align the divs and recompute the affine hulls of the basic
+ * maps since some of them may now have extra divs.
+ * In order to avoid performing parametric integer programming to
+ * compute explicit expressions for the divs, possible leading to
+ * an explosion in the number of basic maps, we first drop all unknown
+ * divs before aligning the divs.  Note that isl_map_local_affine_hull tries
+ * to make sure that all stride information is explicitly available
+ * in terms of known divs.  This involves calling isl_basic_set_gauss,
+ * which is also needed because affine_hull assumes its input has been gaussed,
+ * while isl_map_affine_hull may be called on input that has not been gaussed,
+ * in particular from initial_facet_constraint.
+ * Similarly, align_divs may reorder some divs so that we need to
+ * gauss the result again.
+ * Finally, we combine the individual affine hulls into a single
+ * affine hull.
+ */
+__isl_give isl_basic_map *isl_map_affine_hull(__isl_take isl_map *map)
+{
+	struct isl_basic_map *model = NULL;
+	struct isl_basic_map *hull = NULL;
+	struct isl_set *set;
+	isl_basic_set *bset;
+
+	map = isl_map_detect_equalities(map);
+	map = isl_map_local_affine_hull(map);
+	map = isl_map_remove_empty_parts(map);
+	map = isl_map_remove_unknown_divs(map);
+	map = isl_map_align_divs_internal(map);
+
+	if (!map)
+		return NULL;
+
+	if (map->n == 0)
+		return replace_map_by_empty_basic_map(map);
+
+	model = isl_basic_map_copy(map->p[0]);
+	set = isl_map_underlying_set(map);
+	set = isl_set_cow(set);
+	set = isl_set_local_affine_hull(set);
+	if (!set)
+		goto error;
+
+	while (set->n > 1)
+		set->p[0] = affine_hull(set->p[0], set->p[--set->n]);
+
+	bset = isl_basic_set_copy(set->p[0]);
+	hull = isl_basic_map_overlying_set(bset, model);
+	isl_set_free(set);
+	hull = isl_basic_map_simplify(hull);
+	return isl_basic_map_finalize(hull);
+error:
+	isl_basic_map_free(model);
+	isl_set_free(set);
+	return NULL;
+}
+
+struct isl_basic_set *isl_set_affine_hull(struct isl_set *set)
+{
+	return bset_from_bmap(isl_map_affine_hull(set_to_map(set)));
+}
diff --git a/final/lib/External/isl/isl_arg.c b/final/lib/External/isl/isl_arg.c
new file mode 100644
index 0000000..4798a42
--- /dev/null
+++ b/final/lib/External/isl/isl_arg.c
@@ -0,0 +1,1311 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isl/arg.h>
+#include <isl/ctx.h>
+#include <isl_config.h>
+
+static struct isl_arg help_arg[] = {
+ISL_ARG_PHANTOM_BOOL('h', "help", NULL, "print this help, then exit")
+};
+
+static void set_default_choice(struct isl_arg *arg, void *opt)
+{
+	if (arg->offset == (size_t) -1)
+		return;
+	*(unsigned *)(((char *)opt) + arg->offset) = arg->u.choice.default_value;
+}
+
+static void set_default_flags(struct isl_arg *arg, void *opt)
+{
+	*(unsigned *)(((char *)opt) + arg->offset) = arg->u.flags.default_value;
+}
+
+static void set_default_bool(struct isl_arg *arg, void *opt)
+{
+	if (arg->offset == (size_t) -1)
+		return;
+	*(unsigned *)(((char *)opt) + arg->offset) = arg->u.b.default_value;
+}
+
+static void set_default_child(struct isl_arg *arg, void *opt)
+{
+	void *child;
+
+	if (arg->offset == (size_t) -1)
+		child = opt;
+	else {
+		child = calloc(1, arg->u.child.child->options_size);
+		*(void **)(((char *)opt) + arg->offset) = child;
+	}
+
+	if (child)
+		isl_args_set_defaults(arg->u.child.child, child);
+}
+
+static void set_default_user(struct isl_arg *arg, void *opt)
+{
+	arg->u.user.init(((char *)opt) + arg->offset);
+}
+
+static void set_default_int(struct isl_arg *arg, void *opt)
+{
+	*(int *)(((char *)opt) + arg->offset) = arg->u.i.default_value;
+}
+
+static void set_default_long(struct isl_arg *arg, void *opt)
+{
+	*(long *)(((char *)opt) + arg->offset) = arg->u.l.default_value;
+}
+
+static void set_default_ulong(struct isl_arg *arg, void *opt)
+{
+	*(unsigned long *)(((char *)opt) + arg->offset) = arg->u.ul.default_value;
+}
+
+static void set_default_str(struct isl_arg *arg, void *opt)
+{
+	const char *str = NULL;
+	if (arg->u.str.default_value)
+		str = strdup(arg->u.str.default_value);
+	*(const char **)(((char *)opt) + arg->offset) = str;
+}
+
+static void set_default_str_list(struct isl_arg *arg, void *opt)
+{
+	*(const char ***)(((char *) opt) + arg->offset) = NULL;
+	*(int *)(((char *) opt) + arg->u.str_list.offset_n) = 0;
+}
+
+void isl_args_set_defaults(struct isl_args *args, void *opt)
+{
+	int i;
+
+	for (i = 0; args->args[i].type != isl_arg_end; ++i) {
+		switch (args->args[i].type) {
+		case isl_arg_choice:
+			set_default_choice(&args->args[i], opt);
+			break;
+		case isl_arg_flags:
+			set_default_flags(&args->args[i], opt);
+			break;
+		case isl_arg_bool:
+			set_default_bool(&args->args[i], opt);
+			break;
+		case isl_arg_child:
+			set_default_child(&args->args[i], opt);
+			break;
+		case isl_arg_user:
+			set_default_user(&args->args[i], opt);
+			break;
+		case isl_arg_int:
+			set_default_int(&args->args[i], opt);
+			break;
+		case isl_arg_long:
+			set_default_long(&args->args[i], opt);
+			break;
+		case isl_arg_ulong:
+			set_default_ulong(&args->args[i], opt);
+			break;
+		case isl_arg_arg:
+		case isl_arg_str:
+			set_default_str(&args->args[i], opt);
+			break;
+		case isl_arg_str_list:
+			set_default_str_list(&args->args[i], opt);
+			break;
+		case isl_arg_alias:
+		case isl_arg_footer:
+		case isl_arg_version:
+		case isl_arg_end:
+			break;
+		}
+	}
+}
+
+static void free_args(struct isl_arg *arg, void *opt);
+
+static void free_child(struct isl_arg *arg, void *opt)
+{
+	if (arg->offset == (size_t) -1)
+		free_args(arg->u.child.child->args, opt);
+	else
+		isl_args_free(arg->u.child.child,
+			    *(void **)(((char *)opt) + arg->offset));
+}
+
+static void free_str_list(struct isl_arg *arg, void *opt)
+{
+	int i;
+	int n = *(int *)(((char *) opt) + arg->u.str_list.offset_n);
+	char **list = *(char ***)(((char *) opt) + arg->offset);
+
+	for (i = 0; i < n; ++i)
+		free(list[i]);
+	free(list);
+}
+
+static void free_user(struct isl_arg *arg, void *opt)
+{
+	if (arg->u.user.clear)
+		arg->u.user.clear(((char *)opt) + arg->offset);
+}
+
+static void free_args(struct isl_arg *arg, void *opt)
+{
+	int i;
+
+	for (i = 0; arg[i].type != isl_arg_end; ++i) {
+		switch (arg[i].type) {
+		case isl_arg_child:
+			free_child(&arg[i], opt);
+			break;
+		case isl_arg_arg:
+		case isl_arg_str:
+			free(*(char **)(((char *)opt) + arg[i].offset));
+			break;
+		case isl_arg_str_list:
+			free_str_list(&arg[i], opt);
+			break;
+		case isl_arg_user:
+			free_user(&arg[i], opt);
+			break;
+		case isl_arg_alias:
+		case isl_arg_bool:
+		case isl_arg_choice:
+		case isl_arg_flags:
+		case isl_arg_int:
+		case isl_arg_long:
+		case isl_arg_ulong:
+		case isl_arg_version:
+		case isl_arg_footer:
+		case isl_arg_end:
+			break;
+		}
+	}
+}
+
+void isl_args_free(struct isl_args *args, void *opt)
+{
+	if (!opt)
+		return;
+
+	free_args(args->args, opt);
+
+	free(opt);
+}
+
+/* Data structure for collecting the prefixes of ancestor nodes.
+ *
+ * n is the number of prefixes.
+ * prefix[i] for i < n is a prefix of an ancestor.
+ * len[i] for i < n is the length of prefix[i].
+ */
+struct isl_prefixes {
+	int n;
+	const char *prefix[10];
+	size_t len[10];
+};
+
+/* Add "prefix" to the list of prefixes and return the updated
+ * number of prefixes.
+ */
+static int add_prefix(struct isl_prefixes *prefixes, const char *prefix)
+{
+	int n = prefixes->n;
+
+	if (!prefix)
+		return n;
+
+	if (prefixes->n >= 10) {
+		fprintf(stderr, "too many prefixes\n");
+		exit(EXIT_FAILURE);
+	}
+	prefixes->len[prefixes->n] = strlen(prefix);
+	prefixes->prefix[prefixes->n] = prefix;
+	prefixes->n++;
+
+	return n;
+}
+
+/* Drop all prefixes starting at "first".
+ */
+static void drop_prefix(struct isl_prefixes *prefixes, int first)
+{
+	prefixes->n = first;
+}
+
+/* Print the prefixes in "prefixes".
+ */
+static int print_prefixes(struct isl_prefixes *prefixes)
+{
+	int i;
+	int len = 0;
+
+	if (!prefixes)
+		return 0;
+
+	for (i = 0; i < prefixes->n; ++i) {
+		printf("%s-", prefixes->prefix[i]);
+		len += strlen(prefixes->prefix[i]) + 1;
+	}
+
+	return len;
+}
+
+/* Check if "name" starts with one or more of the prefixes in "prefixes",
+ * starting at *first.  If so, advance the pointer beyond the prefixes
+ * and return the updated pointer.  Additionally, update *first to
+ * the index after the last prefix found.
+ */
+static const char *skip_prefixes(const char *name,
+	struct isl_prefixes *prefixes, int *first)
+{
+	int i;
+
+	for (i = first ? *first : 0; i < prefixes->n; ++i) {
+		size_t len = prefixes->len[i];
+		const char *prefix = prefixes->prefix[i];
+		if (strncmp(name, prefix, len) == 0 && name[len] == '-') {
+			name += len + 1;
+			if (first)
+				*first = i + 1;
+		}
+	}
+
+	return name;
+}
+
+static int print_arg_help(struct isl_arg *decl, struct isl_prefixes *prefixes,
+	int no)
+{
+	int len = 0;
+
+	if (!decl->long_name) {
+		printf("  -%c", decl->short_name);
+		return 4;
+	}
+
+	if (decl->short_name) {
+		printf("  -%c, --", decl->short_name);
+		len += 8;
+	} else if (decl->flags & ISL_ARG_SINGLE_DASH) {
+		printf("  -");
+		len += 3;
+	} else {
+		printf("      --");
+		len += 8;
+	}
+
+	if (no) {
+		printf("no-");
+		len += 3;
+	}
+	len += print_prefixes(prefixes);
+	printf("%s", decl->long_name);
+	len += strlen(decl->long_name);
+
+	while ((++decl)->type == isl_arg_alias) {
+		printf(", --");
+		len += 4;
+		if (no) {
+			printf("no-");
+			len += 3;
+		}
+		printf("%s", decl->long_name);
+		len += strlen(decl->long_name);
+	}
+
+	return len;
+}
+
+const void *isl_memrchr(const void *s, int c, size_t n)
+{
+	const char *p = s;
+	while (n-- > 0)
+		if (p[n] == c)
+			return p + n;
+	return NULL;
+}
+
+static int wrap_msg(const char *s, int indent, int pos)
+{
+	int len;
+	int wrap_len = 75 - indent;
+
+	if (pos + 1 >= indent)
+		printf("\n%*s", indent, "");
+	else
+		printf("%*s", indent - pos, "");
+
+	len = strlen(s);
+	while (len > wrap_len) {
+		const char *space = isl_memrchr(s, ' ', wrap_len);
+		int l;
+
+		if (!space)
+			space = strchr(s + wrap_len, ' ');
+		if (!space)
+			break;
+		l = space - s;
+		printf("%.*s", l, s);
+		s = space + 1;
+		len -= l + 1;
+		printf("\n%*s", indent, "");
+	}
+
+	printf("%s", s);
+	return len;
+}
+
+static int print_help_msg(struct isl_arg *decl, int pos)
+{
+	if (!decl->help_msg)
+		return pos;
+
+	return wrap_msg(decl->help_msg, 30, pos);
+}
+
+static void print_default(struct isl_arg *decl, const char *def, int pos)
+{
+	const char *default_prefix = "[default: ";
+	const char *default_suffix = "]";
+	int len;
+
+	len = strlen(default_prefix) + strlen(def) + strlen(default_suffix);
+
+	if (!decl->help_msg) {
+		if (pos >= 29)
+			printf("\n%30s", "");
+		else
+			printf("%*s", 30 - pos, "");
+	} else {
+		if (pos + len >= 48)
+			printf("\n%30s", "");
+		else
+			printf(" ");
+	}
+	printf("%s%s%s", default_prefix, def, default_suffix);
+}
+
+static void print_default_choice(struct isl_arg *decl, void *opt, int pos)
+{
+	int i;
+	const char *s = "none";
+	unsigned *p;
+
+	p = (unsigned *)(((char *) opt) + decl->offset);
+	for (i = 0; decl->u.choice.choice[i].name; ++i)
+		if (decl->u.choice.choice[i].value == *p) {
+			s = decl->u.choice.choice[i].name;
+			break;
+		}
+
+	print_default(decl, s, pos);
+}
+
+static void print_choice_help(struct isl_arg *decl,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int i;
+	int pos;
+
+	pos = print_arg_help(decl, prefixes, 0);
+	printf("=");
+	pos++;
+
+	for (i = 0; decl->u.choice.choice[i].name; ++i) {
+		if (i) {
+			printf("|");
+			pos++;
+		}
+		printf("%s", decl->u.choice.choice[i].name);
+		pos += strlen(decl->u.choice.choice[i].name);
+	}
+
+	pos = print_help_msg(decl, pos);
+	print_default_choice(decl, opt, pos);
+
+	printf("\n");
+}
+
+static void print_default_flags(struct isl_arg *decl, void *opt, int pos)
+{
+	int i, first;
+	const char *default_prefix = "[default: ";
+	const char *default_suffix = "]";
+	int len = strlen(default_prefix) + strlen(default_suffix);
+	unsigned *p;
+
+	p = (unsigned *)(((char *) opt) + decl->offset);
+	for (i = 0; decl->u.flags.flags[i].name; ++i)
+		if ((*p & decl->u.flags.flags[i].mask) ==
+		     decl->u.flags.flags[i].value)
+			len += strlen(decl->u.flags.flags[i].name);
+
+	if (!decl->help_msg) {
+		if (pos >= 29)
+			printf("\n%30s", "");
+		else
+			printf("%*s", 30 - pos, "");
+	} else {
+		if (pos + len >= 48)
+			printf("\n%30s", "");
+		else
+			printf(" ");
+	}
+	printf("%s", default_prefix);
+
+	for (first = 1, i = 0; decl->u.flags.flags[i].name; ++i)
+		if ((*p & decl->u.flags.flags[i].mask) ==
+		     decl->u.flags.flags[i].value) {
+			if (!first)
+				printf(",");
+			printf("%s", decl->u.flags.flags[i].name);
+			first = 0;
+		}
+
+	printf("%s", default_suffix);
+}
+
+static void print_flags_help(struct isl_arg *decl,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int i, j;
+	int pos;
+
+	pos = print_arg_help(decl, prefixes, 0);
+	printf("=");
+	pos++;
+
+	for (i = 0; decl->u.flags.flags[i].name; ++i) {
+		if (i) {
+			printf(",");
+			pos++;
+		}
+		for (j = i;
+		     decl->u.flags.flags[j].mask == decl->u.flags.flags[i].mask;
+		     ++j) {
+			if (j != i) {
+				printf("|");
+				pos++;
+			}
+			printf("%s", decl->u.flags.flags[j].name);
+			pos += strlen(decl->u.flags.flags[j].name);
+		}
+		i = j - 1;
+	}
+
+	pos = print_help_msg(decl, pos);
+	print_default_flags(decl, opt, pos);
+
+	printf("\n");
+}
+
+static void print_bool_help(struct isl_arg *decl,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int pos;
+	unsigned *p = opt ? (unsigned *)(((char *) opt) + decl->offset) : NULL;
+	int no = p ? *p == 1 : 0;
+	pos = print_arg_help(decl, prefixes, no);
+	pos = print_help_msg(decl, pos);
+	if (decl->offset != (size_t) -1)
+		print_default(decl, no ? "yes" : "no", pos);
+	printf("\n");
+}
+
+static int print_argument_name(struct isl_arg *decl, const char *name, int pos)
+{
+	printf("%c<%s>", decl->long_name ? '=' : ' ', name);
+	return pos + 3 + strlen(name);
+}
+
+static void print_int_help(struct isl_arg *decl,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int pos;
+	char val[20];
+	int *p = (int *)(((char *) opt) + decl->offset);
+	pos = print_arg_help(decl, prefixes, 0);
+	pos = print_argument_name(decl, decl->argument_name, pos);
+	pos = print_help_msg(decl, pos);
+	snprintf(val, sizeof(val), "%d", *p);
+	print_default(decl, val, pos);
+	printf("\n");
+}
+
+static void print_long_help(struct isl_arg *decl,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int pos;
+	long *p = (long *)(((char *) opt) + decl->offset);
+	pos = print_arg_help(decl, prefixes, 0);
+	if (*p != decl->u.l.default_selected) {
+		printf("[");
+		pos++;
+	}
+	printf("=long");
+	pos += 5;
+	if (*p != decl->u.l.default_selected) {
+		printf("]");
+		pos++;
+	}
+	print_help_msg(decl, pos);
+	printf("\n");
+}
+
+static void print_ulong_help(struct isl_arg *decl,
+	struct isl_prefixes *prefixes)
+{
+	int pos;
+	pos = print_arg_help(decl, prefixes, 0);
+	printf("=ulong");
+	pos += 6;
+	print_help_msg(decl, pos);
+	printf("\n");
+}
+
+static void print_str_help(struct isl_arg *decl,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int pos;
+	const char *a = decl->argument_name ? decl->argument_name : "string";
+	const char **p = (const char **)(((char *) opt) + decl->offset);
+	pos = print_arg_help(decl, prefixes, 0);
+	pos = print_argument_name(decl, a, pos);
+	pos = print_help_msg(decl, pos);
+	if (*p)
+		print_default(decl, *p, pos);
+	printf("\n");
+}
+
+static void print_str_list_help(struct isl_arg *decl,
+	struct isl_prefixes *prefixes)
+{
+	int pos;
+	const char *a = decl->argument_name ? decl->argument_name : "string";
+	pos = print_arg_help(decl, prefixes, 0);
+	pos = print_argument_name(decl, a, pos);
+	pos = print_help_msg(decl, pos);
+	printf("\n");
+}
+
+static void print_help(struct isl_arg *arg,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int i;
+	int any = 0;
+
+	for (i = 0; arg[i].type != isl_arg_end; ++i) {
+		if (arg[i].flags & ISL_ARG_HIDDEN)
+			continue;
+		switch (arg[i].type) {
+		case isl_arg_flags:
+			print_flags_help(&arg[i], prefixes, opt);
+			any = 1;
+			break;
+		case isl_arg_choice:
+			print_choice_help(&arg[i], prefixes, opt);
+			any = 1;
+			break;
+		case isl_arg_bool:
+			print_bool_help(&arg[i], prefixes, opt);
+			any = 1;
+			break;
+		case isl_arg_int:
+			print_int_help(&arg[i], prefixes, opt);
+			any = 1;
+			break;
+		case isl_arg_long:
+			print_long_help(&arg[i], prefixes, opt);
+			any = 1;
+			break;
+		case isl_arg_ulong:
+			print_ulong_help(&arg[i], prefixes);
+			any = 1;
+			break;
+		case isl_arg_str:
+			print_str_help(&arg[i], prefixes, opt);
+			any = 1;
+			break;
+		case isl_arg_str_list:
+			print_str_list_help(&arg[i], prefixes);
+			any = 1;
+			break;
+		case isl_arg_alias:
+		case isl_arg_version:
+		case isl_arg_arg:
+		case isl_arg_footer:
+		case isl_arg_child:
+		case isl_arg_user:
+		case isl_arg_end:
+			break;
+		}
+	}
+
+	for (i = 0; arg[i].type != isl_arg_end; ++i) {
+		void *child;
+		int first;
+
+		if (arg[i].type != isl_arg_child)
+			continue;
+		if (arg[i].flags & ISL_ARG_HIDDEN)
+			continue;
+
+		if (any)
+			printf("\n");
+		if (arg[i].help_msg)
+			printf(" %s\n", arg[i].help_msg);
+		if (arg[i].offset == (size_t) -1)
+			child = opt;
+		else
+			child = *(void **)(((char *) opt) + arg[i].offset);
+		first = add_prefix(prefixes, arg[i].long_name);
+		print_help(arg[i].u.child.child->args, prefixes, child);
+		drop_prefix(prefixes, first);
+		any = 1;
+	}
+}
+
+static const char *prog_name(const char *prog)
+{
+	const char *slash;
+
+	slash = strrchr(prog, '/');
+	if (slash)
+		prog = slash + 1;
+	if (strncmp(prog, "lt-", 3) == 0)
+		prog += 3;
+
+	return prog;
+}
+
+static int any_version(struct isl_arg *decl)
+{
+	int i;
+
+	for (i = 0; decl[i].type != isl_arg_end; ++i) {
+		switch (decl[i].type) {
+		case isl_arg_version:
+			return 1;
+		case isl_arg_child:
+			if (any_version(decl[i].u.child.child->args))
+				return 1;
+			break;
+		default:
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static void print_help_and_exit(struct isl_arg *arg, const char *prog,
+	void *opt)
+{
+	int i;
+	struct isl_prefixes prefixes = { 0 };
+
+	printf("Usage: %s [OPTION...]", prog_name(prog));
+
+	for (i = 0; arg[i].type != isl_arg_end; ++i)
+		if (arg[i].type == isl_arg_arg)
+			printf(" %s", arg[i].argument_name);
+
+	printf("\n\n");
+
+	print_help(arg, &prefixes, opt);
+	printf("\n");
+	if (any_version(arg))
+		printf("  -V, --version\n");
+	print_bool_help(help_arg, NULL, NULL);
+
+	for (i = 0; arg[i].type != isl_arg_end; ++i) {
+		if (arg[i].type != isl_arg_footer)
+			continue;
+		wrap_msg(arg[i].help_msg, 0, 0);
+		printf("\n");
+	}
+
+	exit(0);
+}
+
+static int match_long_name(struct isl_arg *decl,
+	const char *start, const char *end)
+{
+	do {
+		if (end - start == strlen(decl->long_name) &&
+		    !strncmp(start, decl->long_name, end - start))
+			return 1;
+	} while ((++decl)->type == isl_arg_alias);
+
+	return 0;
+}
+
+static const char *skip_dash_dash(struct isl_arg *decl, const char *arg)
+{
+	if (!strncmp(arg, "--", 2))
+		return arg + 2;
+	if ((decl->flags & ISL_ARG_SINGLE_DASH) && arg[0] == '-')
+		return arg + 1;
+	return NULL;
+}
+
+static const char *skip_name(struct isl_arg *decl, const char *arg,
+	struct isl_prefixes *prefixes, int need_argument, int *has_argument)
+{
+	const char *equal;
+	const char *name;
+	const char *end;
+
+	if (arg[0] == '-' && arg[1] && arg[1] == decl->short_name) {
+		if (need_argument && !arg[2])
+			return NULL;
+		if (has_argument)
+			*has_argument = arg[2] != '\0';
+		return arg + 2;
+	}
+	if (!decl->long_name)
+		return NULL;
+
+	name = skip_dash_dash(decl, arg);
+	if (!name)
+		return NULL;
+
+	equal = strchr(name, '=');
+	if (need_argument && !equal)
+		return NULL;
+
+	if (has_argument)
+		*has_argument = !!equal;
+	end = equal ? equal : name + strlen(name);
+
+	name = skip_prefixes(name, prefixes, NULL);
+
+	if (!match_long_name(decl, name, end))
+		return NULL;
+
+	return equal ? equal + 1 : end;
+}
+
+static int parse_choice_option(struct isl_arg *decl, char **arg,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int i;
+	int has_argument;
+	const char *choice;
+
+	choice = skip_name(decl, arg[0], prefixes, 0, &has_argument);
+	if (!choice)
+		return 0;
+
+	if (!has_argument && (!arg[1] || arg[1][0] == '-')) {
+		unsigned u = decl->u.choice.default_selected;
+		if (decl->offset != (size_t) -1)
+			*(unsigned *)(((char *)opt) + decl->offset) = u;
+		if (decl->u.choice.set)
+			decl->u.choice.set(opt, u);
+
+		return 1;
+	}
+
+	if (!has_argument)
+		choice = arg[1];
+
+	for (i = 0; decl->u.choice.choice[i].name; ++i) {
+		unsigned u;
+
+		if (strcmp(choice, decl->u.choice.choice[i].name))
+			continue;
+
+		u = decl->u.choice.choice[i].value;
+		if (decl->offset != (size_t) -1)
+			*(unsigned *)(((char *)opt) + decl->offset) = u;
+		if (decl->u.choice.set)
+			decl->u.choice.set(opt, u);
+
+		return has_argument ? 1 : 2;
+	}
+
+	return 0;
+}
+
+static int set_flag(struct isl_arg *decl, unsigned *val, const char *flag,
+	size_t len)
+{
+	int i;
+
+	for (i = 0; decl->u.flags.flags[i].name; ++i) {
+		if (strncmp(flag, decl->u.flags.flags[i].name, len))
+			continue;
+
+		*val &= ~decl->u.flags.flags[i].mask;
+		*val |= decl->u.flags.flags[i].value;
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static int parse_flags_option(struct isl_arg *decl, char **arg,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int has_argument;
+	const char *flags;
+	const char *comma;
+	unsigned val;
+
+	flags = skip_name(decl, arg[0], prefixes, 0, &has_argument);
+	if (!flags)
+		return 0;
+
+	if (!has_argument && !arg[1])
+		return 0;
+
+	if (!has_argument)
+		flags = arg[1];
+
+	val = 0;
+
+	while ((comma = strchr(flags, ',')) != NULL) {
+		if (!set_flag(decl, &val, flags, comma - flags))
+			return 0;
+		flags = comma + 1;
+	}
+	if (!set_flag(decl, &val, flags, strlen(flags)))
+		return 0;
+
+	*(unsigned *)(((char *)opt) + decl->offset) = val;
+
+	return has_argument ? 1 : 2;
+}
+
+static int parse_bool_option(struct isl_arg *decl, char **arg,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	const char *name;
+	unsigned *p = (unsigned *)(((char *)opt) + decl->offset);
+	int next_prefix;
+
+	if (skip_name(decl, arg[0], prefixes, 0, NULL)) {
+		if ((decl->flags & ISL_ARG_BOOL_ARG) && arg[1]) {
+			char *endptr;
+			int val = strtol(arg[1], &endptr, 0);
+			if (*endptr == '\0' && (val == 0 || val == 1)) {
+				if (decl->offset != (size_t) -1)
+					*p = val;
+				if (decl->u.b.set)
+					decl->u.b.set(opt, val);
+				return 2;
+			}
+		}
+		if (decl->offset != (size_t) -1)
+			*p = 1;
+		if (decl->u.b.set)
+			decl->u.b.set(opt, 1);
+
+		return 1;
+	}
+
+	if (!decl->long_name)
+		return 0;
+
+	name = skip_dash_dash(decl, arg[0]);
+	if (!name)
+		return 0;
+
+	next_prefix = 0;
+	name = skip_prefixes(name, prefixes, &next_prefix);
+
+	if (strncmp(name, "no-", 3))
+		return 0;
+	name += 3;
+
+	name = skip_prefixes(name, prefixes, &next_prefix);
+
+	if (match_long_name(decl, name, name + strlen(name))) {
+		if (decl->offset != (size_t) -1)
+			*p = 0;
+		if (decl->u.b.set)
+			decl->u.b.set(opt, 0);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static int parse_str_option(struct isl_arg *decl, char **arg,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int has_argument;
+	const char *s;
+	char **p = (char **)(((char *)opt) + decl->offset);
+
+	s = skip_name(decl, arg[0], prefixes, 0, &has_argument);
+	if (!s)
+		return 0;
+
+	if (has_argument) {
+		free(*p);
+		*p = strdup(s);
+		return 1;
+	}
+
+	if (arg[1]) {
+		free(*p);
+		*p = strdup(arg[1]);
+		return 2;
+	}
+
+	return 0;
+}
+
+static int isl_arg_str_list_append(struct isl_arg *decl, void *opt,
+	const char *s)
+{
+	int *n = (int *)(((char *) opt) + decl->u.str_list.offset_n);
+	char **list = *(char ***)(((char *) opt) + decl->offset);
+
+	list = realloc(list, (*n + 1) * sizeof(char *));
+	if (!list)
+		return -1;
+	*(char ***)(((char *) opt) + decl->offset) = list;
+	list[*n] = strdup(s);
+	(*n)++;
+	return 0;
+}
+
+static int parse_str_list_option(struct isl_arg *decl, char **arg,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int has_argument;
+	const char *s;
+
+	s = skip_name(decl, arg[0], prefixes, 0, &has_argument);
+	if (!s)
+		return 0;
+
+	if (has_argument) {
+		isl_arg_str_list_append(decl, opt, s);
+		return 1;
+	}
+
+	if (arg[1]) {
+		isl_arg_str_list_append(decl, opt, arg[1]);
+		return 2;
+	}
+
+	return 0;
+}
+
+static int parse_int_option(struct isl_arg *decl, char **arg,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int has_argument;
+	const char *val;
+	char *endptr;
+	int *p = (int *)(((char *)opt) + decl->offset);
+
+	val = skip_name(decl, arg[0], prefixes, 0, &has_argument);
+	if (!val)
+		return 0;
+
+	if (has_argument) {
+		*p = atoi(val);
+		return 1;
+	}
+
+	if (arg[1]) {
+		int i = strtol(arg[1], &endptr, 0);
+		if (*endptr == '\0') {
+			*p = i;
+			return 2;
+		}
+	}
+
+	return 0;
+}
+
+static int parse_long_option(struct isl_arg *decl, char **arg,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int has_argument;
+	const char *val;
+	char *endptr;
+	long *p = (long *)(((char *)opt) + decl->offset);
+
+	val = skip_name(decl, arg[0], prefixes, 0, &has_argument);
+	if (!val)
+		return 0;
+
+	if (has_argument) {
+		long l = strtol(val, NULL, 0);
+		*p = l;
+		if (decl->u.l.set)
+			decl->u.l.set(opt, l);
+		return 1;
+	}
+
+	if (arg[1]) {
+		long l = strtol(arg[1], &endptr, 0);
+		if (*endptr == '\0') {
+			*p = l;
+			if (decl->u.l.set)
+				decl->u.l.set(opt, l);
+			return 2;
+		}
+	}
+
+	if (decl->u.l.default_value != decl->u.l.default_selected) {
+		*p = decl->u.l.default_selected;
+		if (decl->u.l.set)
+			decl->u.l.set(opt, decl->u.l.default_selected);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int parse_ulong_option(struct isl_arg *decl, char **arg,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int has_argument;
+	const char *val;
+	char *endptr;
+	unsigned long *p = (unsigned long *)(((char *)opt) + decl->offset);
+
+	val = skip_name(decl, arg[0], prefixes, 0, &has_argument);
+	if (!val)
+		return 0;
+
+	if (has_argument) {
+		*p = strtoul(val, NULL, 0);
+		return 1;
+	}
+
+	if (arg[1]) {
+		unsigned long ul = strtoul(arg[1], &endptr, 0);
+		if (*endptr == '\0') {
+			*p = ul;
+			return 2;
+		}
+	}
+
+	return 0;
+}
+
+static int parse_option(struct isl_arg *decl, char **arg,
+	struct isl_prefixes *prefixes, void *opt);
+
+static int parse_child_option(struct isl_arg *decl, char **arg,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	void *child;
+	int first, parsed;
+
+	if (decl->offset == (size_t) -1)
+		child = opt;
+	else
+		child = *(void **)(((char *)opt) + decl->offset);
+
+	first = add_prefix(prefixes, decl->long_name);
+	parsed = parse_option(decl->u.child.child->args, arg, prefixes, child);
+	drop_prefix(prefixes, first);
+
+	return parsed;
+}
+
+static int parse_option(struct isl_arg *decl, char **arg,
+	struct isl_prefixes *prefixes, void *opt)
+{
+	int i;
+
+	for (i = 0; decl[i].type != isl_arg_end; ++i) {
+		int parsed = 0;
+		switch (decl[i].type) {
+		case isl_arg_choice:
+			parsed = parse_choice_option(&decl[i], arg,
+							prefixes, opt);
+			break;
+		case isl_arg_flags:
+			parsed = parse_flags_option(&decl[i], arg,
+							prefixes, opt);
+			break;
+		case isl_arg_int:
+			parsed = parse_int_option(&decl[i], arg, prefixes, opt);
+			break;
+		case isl_arg_long:
+			parsed = parse_long_option(&decl[i], arg,
+							prefixes, opt);
+			break;
+		case isl_arg_ulong:
+			parsed = parse_ulong_option(&decl[i], arg,
+							prefixes, opt);
+			break;
+		case isl_arg_bool:
+			parsed = parse_bool_option(&decl[i], arg,
+							prefixes, opt);
+			break;
+		case isl_arg_str:
+			parsed = parse_str_option(&decl[i], arg, prefixes, opt);
+			break;
+		case isl_arg_str_list:
+			parsed = parse_str_list_option(&decl[i], arg, prefixes,
+							opt);
+			break;
+		case isl_arg_child:
+			parsed = parse_child_option(&decl[i], arg,
+							prefixes, opt);
+			break;
+		case isl_arg_alias:
+		case isl_arg_arg:
+		case isl_arg_footer:
+		case isl_arg_user:
+		case isl_arg_version:
+		case isl_arg_end:
+			break;
+		}
+		if (parsed)
+			return parsed;
+	}
+
+	return 0;
+}
+
+static void print_version(struct isl_arg *decl)
+{
+	int i;
+
+	for (i = 0; decl[i].type != isl_arg_end; ++i) {
+		switch (decl[i].type) {
+		case isl_arg_version:
+			decl[i].u.version.print_version();
+			break;
+		case isl_arg_child:
+			print_version(decl[i].u.child.child->args);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static void print_version_and_exit(struct isl_arg *decl)
+{
+	print_version(decl);
+
+	exit(0);
+}
+
+static int drop_argument(int argc, char **argv, int drop, int n)
+{
+	for (; drop + n < argc; ++drop)
+		argv[drop] = argv[drop + n];
+
+	return argc - n;
+}
+
+static int n_arg(struct isl_arg *arg)
+{
+	int i;
+	int n_arg = 0;
+
+	for (i = 0; arg[i].type != isl_arg_end; ++i)
+		if (arg[i].type == isl_arg_arg)
+			n_arg++;
+
+	return n_arg;
+}
+
+static int next_arg(struct isl_arg *arg, int a)
+{
+	for (++a; arg[a].type != isl_arg_end; ++a)
+		if (arg[a].type == isl_arg_arg)
+			return a;
+
+	return -1;
+}
+
+/* Unless ISL_ARG_SKIP_HELP is set, check if "arg" is
+ * equal to "--help" and if so call print_help_and_exit.
+ */
+static void check_help(struct isl_args *args, char *arg, char *prog, void *opt,
+	unsigned flags)
+{
+	if (ISL_FL_ISSET(flags, ISL_ARG_SKIP_HELP))
+		return;
+
+	if (strcmp(arg, "--help") == 0)
+		print_help_and_exit(args->args, prog, opt);
+}
+
+int isl_args_parse(struct isl_args *args, int argc, char **argv, void *opt,
+	unsigned flags)
+{
+	int a = -1;
+	int skip = 0;
+	int i;
+	int n;
+	struct isl_prefixes prefixes = { 0 };
+
+	n = n_arg(args->args);
+
+	for (i = 1; i < argc; ++i) {
+		if ((strcmp(argv[i], "--version") == 0 ||
+		     strcmp(argv[i], "-V") == 0) && any_version(args->args))
+			print_version_and_exit(args->args);
+	}
+
+	while (argc > 1 + skip) {
+		int parsed;
+		if (argv[1 + skip][0] != '-') {
+			a = next_arg(args->args, a);
+			if (a >= 0) {
+				char **p;
+				p = (char **)(((char *)opt)+args->args[a].offset);
+				free(*p);
+				*p = strdup(argv[1 + skip]);
+				argc = drop_argument(argc, argv, 1 + skip, 1);
+				--n;
+			} else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) {
+				fprintf(stderr, "%s: extra argument: %s\n",
+					    prog_name(argv[0]), argv[1 + skip]);
+				exit(-1);
+			} else
+				++skip;
+			continue;
+		}
+		check_help(args, argv[1 + skip], argv[0], opt, flags);
+		parsed = parse_option(args->args, &argv[1 + skip],
+					&prefixes, opt);
+		if (parsed)
+			argc = drop_argument(argc, argv, 1 + skip, parsed);
+		else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) {
+			fprintf(stderr, "%s: unrecognized option: %s\n",
+					prog_name(argv[0]), argv[1 + skip]);
+			exit(-1);
+		} else
+			++skip;
+	}
+
+	if (n > 0) {
+		fprintf(stderr, "%s: expecting %d more argument(s)\n",
+				prog_name(argv[0]), n);
+		exit(-1);
+	}
+
+	return argc;
+}
diff --git a/final/lib/External/isl/isl_ast.c b/final/lib/External/isl/isl_ast.c
new file mode 100644
index 0000000..f13f8a6
--- /dev/null
+++ b/final/lib/External/isl/isl_ast.c
@@ -0,0 +1,2831 @@
+/*
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <string.h>
+
+#include <isl_ast_private.h>
+
+#undef BASE
+#define BASE ast_expr
+
+#include <isl_list_templ.c>
+
+#undef BASE
+#define BASE ast_node
+
+#include <isl_list_templ.c>
+
+isl_ctx *isl_ast_print_options_get_ctx(
+	__isl_keep isl_ast_print_options *options)
+{
+	return options ? options->ctx : NULL;
+}
+
+__isl_give isl_ast_print_options *isl_ast_print_options_alloc(isl_ctx *ctx)
+{
+	isl_ast_print_options *options;
+
+	options = isl_calloc_type(ctx, isl_ast_print_options);
+	if (!options)
+		return NULL;
+
+	options->ctx = ctx;
+	isl_ctx_ref(ctx);
+	options->ref = 1;
+
+	return options;
+}
+
+__isl_give isl_ast_print_options *isl_ast_print_options_dup(
+	__isl_keep isl_ast_print_options *options)
+{
+	isl_ctx *ctx;
+	isl_ast_print_options *dup;
+
+	if (!options)
+		return NULL;
+
+	ctx = isl_ast_print_options_get_ctx(options);
+	dup = isl_ast_print_options_alloc(ctx);
+	if (!dup)
+		return NULL;
+
+	dup->print_for = options->print_for;
+	dup->print_for_user = options->print_for_user;
+	dup->print_user = options->print_user;
+	dup->print_user_user = options->print_user_user;
+
+	return dup;
+}
+
+__isl_give isl_ast_print_options *isl_ast_print_options_cow(
+	__isl_take isl_ast_print_options *options)
+{
+	if (!options)
+		return NULL;
+
+	if (options->ref == 1)
+		return options;
+	options->ref--;
+	return isl_ast_print_options_dup(options);
+}
+
+__isl_give isl_ast_print_options *isl_ast_print_options_copy(
+	__isl_keep isl_ast_print_options *options)
+{
+	if (!options)
+		return NULL;
+
+	options->ref++;
+	return options;
+}
+
+__isl_null isl_ast_print_options *isl_ast_print_options_free(
+	__isl_take isl_ast_print_options *options)
+{
+	if (!options)
+		return NULL;
+
+	if (--options->ref > 0)
+		return NULL;
+
+	isl_ctx_deref(options->ctx);
+
+	free(options);
+	return NULL;
+}
+
+/* Set the print_user callback of "options" to "print_user".
+ *
+ * If this callback is set, then it used to print user nodes in the AST.
+ * Otherwise, the expression associated to the user node is printed.
+ */
+__isl_give isl_ast_print_options *isl_ast_print_options_set_print_user(
+	__isl_take isl_ast_print_options *options,
+	__isl_give isl_printer *(*print_user)(__isl_take isl_printer *p,
+		__isl_take isl_ast_print_options *options,
+		__isl_keep isl_ast_node *node, void *user),
+	void *user)
+{
+	options = isl_ast_print_options_cow(options);
+	if (!options)
+		return NULL;
+
+	options->print_user = print_user;
+	options->print_user_user = user;
+
+	return options;
+}
+
+/* Set the print_for callback of "options" to "print_for".
+ *
+ * If this callback is set, then it used to print for nodes in the AST.
+ */
+__isl_give isl_ast_print_options *isl_ast_print_options_set_print_for(
+	__isl_take isl_ast_print_options *options,
+	__isl_give isl_printer *(*print_for)(__isl_take isl_printer *p,
+		__isl_take isl_ast_print_options *options,
+		__isl_keep isl_ast_node *node, void *user),
+	void *user)
+{
+	options = isl_ast_print_options_cow(options);
+	if (!options)
+		return NULL;
+
+	options->print_for = print_for;
+	options->print_for_user = user;
+
+	return options;
+}
+
+__isl_give isl_ast_expr *isl_ast_expr_copy(__isl_keep isl_ast_expr *expr)
+{
+	if (!expr)
+		return NULL;
+
+	expr->ref++;
+	return expr;
+}
+
+__isl_give isl_ast_expr *isl_ast_expr_dup(__isl_keep isl_ast_expr *expr)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_ast_expr *dup;
+
+	if (!expr)
+		return NULL;
+
+	ctx = isl_ast_expr_get_ctx(expr);
+	switch (expr->type) {
+	case isl_ast_expr_int:
+		dup = isl_ast_expr_from_val(isl_val_copy(expr->u.v));
+		break;
+	case isl_ast_expr_id:
+		dup = isl_ast_expr_from_id(isl_id_copy(expr->u.id));
+		break;
+	case isl_ast_expr_op:
+		dup = isl_ast_expr_alloc_op(ctx,
+					    expr->u.op.op, expr->u.op.n_arg);
+		if (!dup)
+			return NULL;
+		for (i = 0; i < expr->u.op.n_arg; ++i)
+			dup->u.op.args[i] =
+				isl_ast_expr_copy(expr->u.op.args[i]);
+		break;
+	case isl_ast_expr_error:
+		dup = NULL;
+	}
+
+	if (!dup)
+		return NULL;
+
+	return dup;
+}
+
+__isl_give isl_ast_expr *isl_ast_expr_cow(__isl_take isl_ast_expr *expr)
+{
+	if (!expr)
+		return NULL;
+
+	if (expr->ref == 1)
+		return expr;
+	expr->ref--;
+	return isl_ast_expr_dup(expr);
+}
+
+__isl_null isl_ast_expr *isl_ast_expr_free(__isl_take isl_ast_expr *expr)
+{
+	int i;
+
+	if (!expr)
+		return NULL;
+
+	if (--expr->ref > 0)
+		return NULL;
+
+	isl_ctx_deref(expr->ctx);
+
+	switch (expr->type) {
+	case isl_ast_expr_int:
+		isl_val_free(expr->u.v);
+		break;
+	case isl_ast_expr_id:
+		isl_id_free(expr->u.id);
+		break;
+	case isl_ast_expr_op:
+		if (expr->u.op.args)
+			for (i = 0; i < expr->u.op.n_arg; ++i)
+				isl_ast_expr_free(expr->u.op.args[i]);
+		free(expr->u.op.args);
+		break;
+	case isl_ast_expr_error:
+		break;
+	}
+
+	free(expr);
+	return NULL;
+}
+
+isl_ctx *isl_ast_expr_get_ctx(__isl_keep isl_ast_expr *expr)
+{
+	return expr ? expr->ctx : NULL;
+}
+
+enum isl_ast_expr_type isl_ast_expr_get_type(__isl_keep isl_ast_expr *expr)
+{
+	return expr ? expr->type : isl_ast_expr_error;
+}
+
+/* Return the integer value represented by "expr".
+ */
+__isl_give isl_val *isl_ast_expr_get_val(__isl_keep isl_ast_expr *expr)
+{
+	if (!expr)
+		return NULL;
+	if (expr->type != isl_ast_expr_int)
+		isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid,
+			"expression not an int", return NULL);
+	return isl_val_copy(expr->u.v);
+}
+
+__isl_give isl_id *isl_ast_expr_get_id(__isl_keep isl_ast_expr *expr)
+{
+	if (!expr)
+		return NULL;
+	if (expr->type != isl_ast_expr_id)
+		isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid,
+			"expression not an identifier", return NULL);
+
+	return isl_id_copy(expr->u.id);
+}
+
+enum isl_ast_op_type isl_ast_expr_get_op_type(__isl_keep isl_ast_expr *expr)
+{
+	if (!expr)
+		return isl_ast_op_error;
+	if (expr->type != isl_ast_expr_op)
+		isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid,
+			"expression not an operation", return isl_ast_op_error);
+	return expr->u.op.op;
+}
+
+int isl_ast_expr_get_op_n_arg(__isl_keep isl_ast_expr *expr)
+{
+	if (!expr)
+		return -1;
+	if (expr->type != isl_ast_expr_op)
+		isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid,
+			"expression not an operation", return -1);
+	return expr->u.op.n_arg;
+}
+
+__isl_give isl_ast_expr *isl_ast_expr_get_op_arg(__isl_keep isl_ast_expr *expr,
+	int pos)
+{
+	if (!expr)
+		return NULL;
+	if (expr->type != isl_ast_expr_op)
+		isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid,
+			"expression not an operation", return NULL);
+	if (pos < 0 || pos >= expr->u.op.n_arg)
+		isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid,
+			"index out of bounds", return NULL);
+
+	return isl_ast_expr_copy(expr->u.op.args[pos]);
+}
+
+/* Replace the argument at position "pos" of "expr" by "arg".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_set_op_arg(__isl_take isl_ast_expr *expr,
+	int pos, __isl_take isl_ast_expr *arg)
+{
+	expr = isl_ast_expr_cow(expr);
+	if (!expr || !arg)
+		goto error;
+	if (expr->type != isl_ast_expr_op)
+		isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid,
+			"expression not an operation", goto error);
+	if (pos < 0 || pos >= expr->u.op.n_arg)
+		isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	isl_ast_expr_free(expr->u.op.args[pos]);
+	expr->u.op.args[pos] = arg;
+
+	return expr;
+error:
+	isl_ast_expr_free(arg);
+	return isl_ast_expr_free(expr);
+}
+
+/* Is "expr1" equal to "expr2"?
+ */
+isl_bool isl_ast_expr_is_equal(__isl_keep isl_ast_expr *expr1,
+	__isl_keep isl_ast_expr *expr2)
+{
+	int i;
+
+	if (!expr1 || !expr2)
+		return isl_bool_error;
+
+	if (expr1 == expr2)
+		return isl_bool_true;
+	if (expr1->type != expr2->type)
+		return isl_bool_false;
+	switch (expr1->type) {
+	case isl_ast_expr_int:
+		return isl_val_eq(expr1->u.v, expr2->u.v);
+	case isl_ast_expr_id:
+		return expr1->u.id == expr2->u.id;
+	case isl_ast_expr_op:
+		if (expr1->u.op.op != expr2->u.op.op)
+			return isl_bool_false;
+		if (expr1->u.op.n_arg != expr2->u.op.n_arg)
+			return isl_bool_false;
+		for (i = 0; i < expr1->u.op.n_arg; ++i) {
+			isl_bool equal;
+			equal = isl_ast_expr_is_equal(expr1->u.op.args[i],
+							expr2->u.op.args[i]);
+			if (equal < 0 || !equal)
+				return equal;
+		}
+		return 1;
+	case isl_ast_expr_error:
+		return isl_bool_error;
+	}
+
+	isl_die(isl_ast_expr_get_ctx(expr1), isl_error_internal,
+		"unhandled case", return isl_bool_error);
+}
+
+/* Create a new operation expression of operation type "op",
+ * with "n_arg" as yet unspecified arguments.
+ */
+__isl_give isl_ast_expr *isl_ast_expr_alloc_op(isl_ctx *ctx,
+	enum isl_ast_op_type op, int n_arg)
+{
+	isl_ast_expr *expr;
+
+	expr = isl_calloc_type(ctx, isl_ast_expr);
+	if (!expr)
+		return NULL;
+
+	expr->ctx = ctx;
+	isl_ctx_ref(ctx);
+	expr->ref = 1;
+	expr->type = isl_ast_expr_op;
+	expr->u.op.op = op;
+	expr->u.op.n_arg = n_arg;
+	expr->u.op.args = isl_calloc_array(ctx, isl_ast_expr *, n_arg);
+
+	if (n_arg && !expr->u.op.args)
+		return isl_ast_expr_free(expr);
+
+	return expr;
+}
+
+/* Create a new id expression representing "id".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_from_id(__isl_take isl_id *id)
+{
+	isl_ctx *ctx;
+	isl_ast_expr *expr;
+
+	if (!id)
+		return NULL;
+
+	ctx = isl_id_get_ctx(id);
+	expr = isl_calloc_type(ctx, isl_ast_expr);
+	if (!expr)
+		goto error;
+
+	expr->ctx = ctx;
+	isl_ctx_ref(ctx);
+	expr->ref = 1;
+	expr->type = isl_ast_expr_id;
+	expr->u.id = id;
+
+	return expr;
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+/* Create a new integer expression representing "i".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_alloc_int_si(isl_ctx *ctx, int i)
+{
+	isl_ast_expr *expr;
+
+	expr = isl_calloc_type(ctx, isl_ast_expr);
+	if (!expr)
+		return NULL;
+
+	expr->ctx = ctx;
+	isl_ctx_ref(ctx);
+	expr->ref = 1;
+	expr->type = isl_ast_expr_int;
+	expr->u.v = isl_val_int_from_si(ctx, i);
+	if (!expr->u.v)
+		return isl_ast_expr_free(expr);
+
+	return expr;
+}
+
+/* Create a new integer expression representing "v".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_from_val(__isl_take isl_val *v)
+{
+	isl_ctx *ctx;
+	isl_ast_expr *expr;
+
+	if (!v)
+		return NULL;
+	if (!isl_val_is_int(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting integer value", goto error);
+
+	ctx = isl_val_get_ctx(v);
+	expr = isl_calloc_type(ctx, isl_ast_expr);
+	if (!expr)
+		goto error;
+
+	expr->ctx = ctx;
+	isl_ctx_ref(ctx);
+	expr->ref = 1;
+	expr->type = isl_ast_expr_int;
+	expr->u.v = v;
+
+	return expr;
+error:
+	isl_val_free(v);
+	return NULL;
+}
+
+/* Create an expression representing the unary operation "type" applied to
+ * "arg".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_alloc_unary(enum isl_ast_op_type type,
+	__isl_take isl_ast_expr *arg)
+{
+	isl_ctx *ctx;
+	isl_ast_expr *expr = NULL;
+
+	if (!arg)
+		return NULL;
+
+	ctx = isl_ast_expr_get_ctx(arg);
+	expr = isl_ast_expr_alloc_op(ctx, type, 1);
+	if (!expr)
+		goto error;
+
+	expr->u.op.args[0] = arg;
+
+	return expr;
+error:
+	isl_ast_expr_free(arg);
+	return NULL;
+}
+
+/* Create an expression representing the negation of "arg".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_neg(__isl_take isl_ast_expr *arg)
+{
+	return isl_ast_expr_alloc_unary(isl_ast_op_minus, arg);
+}
+
+/* Create an expression representing the address of "expr".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_address_of(__isl_take isl_ast_expr *expr)
+{
+	if (!expr)
+		return NULL;
+
+	if (isl_ast_expr_get_type(expr) != isl_ast_expr_op ||
+	    isl_ast_expr_get_op_type(expr) != isl_ast_op_access)
+		isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid,
+			"can only take address of access expressions",
+			return isl_ast_expr_free(expr));
+
+	return isl_ast_expr_alloc_unary(isl_ast_op_address_of, expr);
+}
+
+/* Create an expression representing the binary operation "type"
+ * applied to "expr1" and "expr2".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_alloc_binary(enum isl_ast_op_type type,
+	__isl_take isl_ast_expr *expr1, __isl_take isl_ast_expr *expr2)
+{
+	isl_ctx *ctx;
+	isl_ast_expr *expr = NULL;
+
+	if (!expr1 || !expr2)
+		goto error;
+
+	ctx = isl_ast_expr_get_ctx(expr1);
+	expr = isl_ast_expr_alloc_op(ctx, type, 2);
+	if (!expr)
+		goto error;
+
+	expr->u.op.args[0] = expr1;
+	expr->u.op.args[1] = expr2;
+
+	return expr;
+error:
+	isl_ast_expr_free(expr1);
+	isl_ast_expr_free(expr2);
+	return NULL;
+}
+
+/* Create an expression representing the sum of "expr1" and "expr2".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_add(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_add, expr1, expr2);
+}
+
+/* Create an expression representing the difference of "expr1" and "expr2".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_sub(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_sub, expr1, expr2);
+}
+
+/* Create an expression representing the product of "expr1" and "expr2".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_mul(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_mul, expr1, expr2);
+}
+
+/* Create an expression representing the quotient of "expr1" and "expr2".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_div(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_div, expr1, expr2);
+}
+
+/* Create an expression representing the quotient of the integer
+ * division of "expr1" by "expr2", where "expr1" is known to be
+ * non-negative.
+ */
+__isl_give isl_ast_expr *isl_ast_expr_pdiv_q(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_pdiv_q, expr1, expr2);
+}
+
+/* Create an expression representing the remainder of the integer
+ * division of "expr1" by "expr2", where "expr1" is known to be
+ * non-negative.
+ */
+__isl_give isl_ast_expr *isl_ast_expr_pdiv_r(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_pdiv_r, expr1, expr2);
+}
+
+/* Create an expression representing the conjunction of "expr1" and "expr2".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_and(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_and, expr1, expr2);
+}
+
+/* Create an expression representing the conjunction of "expr1" and "expr2",
+ * where "expr2" is evaluated only if "expr1" is evaluated to true.
+ */
+__isl_give isl_ast_expr *isl_ast_expr_and_then(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_and_then, expr1, expr2);
+}
+
+/* Create an expression representing the disjunction of "expr1" and "expr2".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_or(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_or, expr1, expr2);
+}
+
+/* Create an expression representing the disjunction of "expr1" and "expr2",
+ * where "expr2" is evaluated only if "expr1" is evaluated to false.
+ */
+__isl_give isl_ast_expr *isl_ast_expr_or_else(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_or_else, expr1, expr2);
+}
+
+/* Create an expression representing "expr1" less than or equal to "expr2".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_le(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_le, expr1, expr2);
+}
+
+/* Create an expression representing "expr1" less than "expr2".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_lt(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_lt, expr1, expr2);
+}
+
+/* Create an expression representing "expr1" greater than or equal to "expr2".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_ge(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_ge, expr1, expr2);
+}
+
+/* Create an expression representing "expr1" greater than "expr2".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_gt(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_gt, expr1, expr2);
+}
+
+/* Create an expression representing "expr1" equal to "expr2".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_eq(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	return isl_ast_expr_alloc_binary(isl_ast_op_eq, expr1, expr2);
+}
+
+/* Create an expression of type "type" with as arguments "arg0" followed
+ * by "arguments".
+ */
+static __isl_give isl_ast_expr *ast_expr_with_arguments(
+	enum isl_ast_op_type type, __isl_take isl_ast_expr *arg0,
+	__isl_take isl_ast_expr_list *arguments)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_ast_expr *res = NULL;
+
+	if (!arg0 || !arguments)
+		goto error;
+
+	ctx = isl_ast_expr_get_ctx(arg0);
+	n = isl_ast_expr_list_n_ast_expr(arguments);
+	res = isl_ast_expr_alloc_op(ctx, type, 1 + n);
+	if (!res)
+		goto error;
+	for (i = 0; i < n; ++i) {
+		isl_ast_expr *arg;
+		arg = isl_ast_expr_list_get_ast_expr(arguments, i);
+		res->u.op.args[1 + i] = arg;
+		if (!arg)
+			goto error;
+	}
+	res->u.op.args[0] = arg0;
+
+	isl_ast_expr_list_free(arguments);
+	return res;
+error:
+	isl_ast_expr_free(arg0);
+	isl_ast_expr_list_free(arguments);
+	isl_ast_expr_free(res);
+	return NULL;
+}
+
+/* Create an expression representing an access to "array" with index
+ * expressions "indices".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_access(__isl_take isl_ast_expr *array,
+	__isl_take isl_ast_expr_list *indices)
+{
+	return ast_expr_with_arguments(isl_ast_op_access, array, indices);
+}
+
+/* Create an expression representing a call to "function" with argument
+ * expressions "arguments".
+ */
+__isl_give isl_ast_expr *isl_ast_expr_call(__isl_take isl_ast_expr *function,
+	__isl_take isl_ast_expr_list *arguments)
+{
+	return ast_expr_with_arguments(isl_ast_op_call, function, arguments);
+}
+
+/* For each subexpression of "expr" of type isl_ast_expr_id,
+ * if it appears in "id2expr", then replace it by the corresponding
+ * expression.
+ */
+__isl_give isl_ast_expr *isl_ast_expr_substitute_ids(
+	__isl_take isl_ast_expr *expr, __isl_take isl_id_to_ast_expr *id2expr)
+{
+	int i;
+	isl_maybe_isl_ast_expr m;
+
+	if (!expr || !id2expr)
+		goto error;
+
+	switch (expr->type) {
+	case isl_ast_expr_int:
+		break;
+	case isl_ast_expr_id:
+		m = isl_id_to_ast_expr_try_get(id2expr, expr->u.id);
+		if (m.valid < 0)
+			goto error;
+		if (!m.valid)
+			break;
+		isl_ast_expr_free(expr);
+		expr = m.value;
+		break;
+	case isl_ast_expr_op:
+		for (i = 0; i < expr->u.op.n_arg; ++i) {
+			isl_ast_expr *arg;
+			arg = isl_ast_expr_copy(expr->u.op.args[i]);
+			arg = isl_ast_expr_substitute_ids(arg,
+					    isl_id_to_ast_expr_copy(id2expr));
+			if (arg == expr->u.op.args[i]) {
+				isl_ast_expr_free(arg);
+				continue;
+			}
+			if (!arg)
+				expr = isl_ast_expr_free(expr);
+			expr = isl_ast_expr_cow(expr);
+			if (!expr) {
+				isl_ast_expr_free(arg);
+				break;
+			}
+			isl_ast_expr_free(expr->u.op.args[i]);
+			expr->u.op.args[i] = arg;
+		}
+		break;
+	case isl_ast_expr_error:
+		expr = isl_ast_expr_free(expr);
+		break;
+	}
+
+	isl_id_to_ast_expr_free(id2expr);
+	return expr;
+error:
+	isl_ast_expr_free(expr);
+	isl_id_to_ast_expr_free(id2expr);
+	return NULL;
+}
+
+isl_ctx *isl_ast_node_get_ctx(__isl_keep isl_ast_node *node)
+{
+	return node ? node->ctx : NULL;
+}
+
+enum isl_ast_node_type isl_ast_node_get_type(__isl_keep isl_ast_node *node)
+{
+	return node ? node->type : isl_ast_node_error;
+}
+
+__isl_give isl_ast_node *isl_ast_node_alloc(isl_ctx *ctx,
+	enum isl_ast_node_type type)
+{
+	isl_ast_node *node;
+
+	node = isl_calloc_type(ctx, isl_ast_node);
+	if (!node)
+		return NULL;
+
+	node->ctx = ctx;
+	isl_ctx_ref(ctx);
+	node->ref = 1;
+	node->type = type;
+
+	return node;
+}
+
+/* Create an if node with the given guard.
+ *
+ * The then body needs to be filled in later.
+ */
+__isl_give isl_ast_node *isl_ast_node_alloc_if(__isl_take isl_ast_expr *guard)
+{
+	isl_ast_node *node;
+
+	if (!guard)
+		return NULL;
+
+	node = isl_ast_node_alloc(isl_ast_expr_get_ctx(guard), isl_ast_node_if);
+	if (!node)
+		goto error;
+	node->u.i.guard = guard;
+
+	return node;
+error:
+	isl_ast_expr_free(guard);
+	return NULL;
+}
+
+/* Create a for node with the given iterator.
+ *
+ * The remaining fields need to be filled in later.
+ */
+__isl_give isl_ast_node *isl_ast_node_alloc_for(__isl_take isl_id *id)
+{
+	isl_ast_node *node;
+	isl_ctx *ctx;
+
+	if (!id)
+		return NULL;
+
+	ctx = isl_id_get_ctx(id);
+	node = isl_ast_node_alloc(ctx, isl_ast_node_for);
+	if (!node)
+		goto error;
+
+	node->u.f.iterator = isl_ast_expr_from_id(id);
+	if (!node->u.f.iterator)
+		return isl_ast_node_free(node);
+
+	return node;
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+/* Create a mark node, marking "node" with "id".
+ */
+__isl_give isl_ast_node *isl_ast_node_alloc_mark(__isl_take isl_id *id,
+	__isl_take isl_ast_node *node)
+{
+	isl_ctx *ctx;
+	isl_ast_node *mark;
+
+	if (!id || !node)
+		goto error;
+
+	ctx = isl_id_get_ctx(id);
+	mark = isl_ast_node_alloc(ctx, isl_ast_node_mark);
+	if (!mark)
+		goto error;
+
+	mark->u.m.mark = id;
+	mark->u.m.node = node;
+
+	return mark;
+error:
+	isl_id_free(id);
+	isl_ast_node_free(node);
+	return NULL;
+}
+
+/* Create a user node evaluating "expr".
+ */
+__isl_give isl_ast_node *isl_ast_node_alloc_user(__isl_take isl_ast_expr *expr)
+{
+	isl_ctx *ctx;
+	isl_ast_node *node;
+
+	if (!expr)
+		return NULL;
+
+	ctx = isl_ast_expr_get_ctx(expr);
+	node = isl_ast_node_alloc(ctx, isl_ast_node_user);
+	if (!node)
+		goto error;
+
+	node->u.e.expr = expr;
+
+	return node;
+error:
+	isl_ast_expr_free(expr);
+	return NULL;
+}
+
+/* Create a block node with the given children.
+ */
+__isl_give isl_ast_node *isl_ast_node_alloc_block(
+	__isl_take isl_ast_node_list *list)
+{
+	isl_ast_node *node;
+	isl_ctx *ctx;
+
+	if (!list)
+		return NULL;
+
+	ctx = isl_ast_node_list_get_ctx(list);
+	node = isl_ast_node_alloc(ctx, isl_ast_node_block);
+	if (!node)
+		goto error;
+
+	node->u.b.children = list;
+
+	return node;
+error:
+	isl_ast_node_list_free(list);
+	return NULL;
+}
+
+/* Represent the given list of nodes as a single node, either by
+ * extract the node from a single element list or by creating
+ * a block node with the list of nodes as children.
+ */
+__isl_give isl_ast_node *isl_ast_node_from_ast_node_list(
+	__isl_take isl_ast_node_list *list)
+{
+	isl_ast_node *node;
+
+	if (isl_ast_node_list_n_ast_node(list) != 1)
+		return isl_ast_node_alloc_block(list);
+
+	node = isl_ast_node_list_get_ast_node(list, 0);
+	isl_ast_node_list_free(list);
+
+	return node;
+}
+
+__isl_give isl_ast_node *isl_ast_node_copy(__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+
+	node->ref++;
+	return node;
+}
+
+__isl_give isl_ast_node *isl_ast_node_dup(__isl_keep isl_ast_node *node)
+{
+	isl_ast_node *dup;
+
+	if (!node)
+		return NULL;
+
+	dup = isl_ast_node_alloc(isl_ast_node_get_ctx(node), node->type);
+	if (!dup)
+		return NULL;
+
+	switch (node->type) {
+	case isl_ast_node_if:
+		dup->u.i.guard = isl_ast_expr_copy(node->u.i.guard);
+		dup->u.i.then = isl_ast_node_copy(node->u.i.then);
+		dup->u.i.else_node = isl_ast_node_copy(node->u.i.else_node);
+		if (!dup->u.i.guard  || !dup->u.i.then ||
+		    (node->u.i.else_node && !dup->u.i.else_node))
+			return isl_ast_node_free(dup);
+		break;
+	case isl_ast_node_for:
+		dup->u.f.iterator = isl_ast_expr_copy(node->u.f.iterator);
+		dup->u.f.init = isl_ast_expr_copy(node->u.f.init);
+		dup->u.f.cond = isl_ast_expr_copy(node->u.f.cond);
+		dup->u.f.inc = isl_ast_expr_copy(node->u.f.inc);
+		dup->u.f.body = isl_ast_node_copy(node->u.f.body);
+		if (!dup->u.f.iterator || !dup->u.f.init || !dup->u.f.cond ||
+		    !dup->u.f.inc || !dup->u.f.body)
+			return isl_ast_node_free(dup);
+		break;
+	case isl_ast_node_block:
+		dup->u.b.children = isl_ast_node_list_copy(node->u.b.children);
+		if (!dup->u.b.children)
+			return isl_ast_node_free(dup);
+		break;
+	case isl_ast_node_mark:
+		dup->u.m.mark = isl_id_copy(node->u.m.mark);
+		dup->u.m.node = isl_ast_node_copy(node->u.m.node);
+		if (!dup->u.m.mark || !dup->u.m.node)
+			return isl_ast_node_free(dup);
+		break;
+	case isl_ast_node_user:
+		dup->u.e.expr = isl_ast_expr_copy(node->u.e.expr);
+		if (!dup->u.e.expr)
+			return isl_ast_node_free(dup);
+		break;
+	case isl_ast_node_error:
+		break;
+	}
+
+	return dup;
+}
+
+__isl_give isl_ast_node *isl_ast_node_cow(__isl_take isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+
+	if (node->ref == 1)
+		return node;
+	node->ref--;
+	return isl_ast_node_dup(node);
+}
+
+__isl_null isl_ast_node *isl_ast_node_free(__isl_take isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+
+	if (--node->ref > 0)
+		return NULL;
+
+	switch (node->type) {
+	case isl_ast_node_if:
+		isl_ast_expr_free(node->u.i.guard);
+		isl_ast_node_free(node->u.i.then);
+		isl_ast_node_free(node->u.i.else_node);
+		break;
+	case isl_ast_node_for:
+		isl_ast_expr_free(node->u.f.iterator);
+		isl_ast_expr_free(node->u.f.init);
+		isl_ast_expr_free(node->u.f.cond);
+		isl_ast_expr_free(node->u.f.inc);
+		isl_ast_node_free(node->u.f.body);
+		break;
+	case isl_ast_node_block:
+		isl_ast_node_list_free(node->u.b.children);
+		break;
+	case isl_ast_node_mark:
+		isl_id_free(node->u.m.mark);
+		isl_ast_node_free(node->u.m.node);
+		break;
+	case isl_ast_node_user:
+		isl_ast_expr_free(node->u.e.expr);
+		break;
+	case isl_ast_node_error:
+		break;
+	}
+
+	isl_id_free(node->annotation);
+	isl_ctx_deref(node->ctx);
+	free(node);
+
+	return NULL;
+}
+
+/* Replace the body of the for node "node" by "body".
+ */
+__isl_give isl_ast_node *isl_ast_node_for_set_body(
+	__isl_take isl_ast_node *node, __isl_take isl_ast_node *body)
+{
+	node = isl_ast_node_cow(node);
+	if (!node || !body)
+		goto error;
+	if (node->type != isl_ast_node_for)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a for node", goto error);
+
+	isl_ast_node_free(node->u.f.body);
+	node->u.f.body = body;
+
+	return node;
+error:
+	isl_ast_node_free(node);
+	isl_ast_node_free(body);
+	return NULL;
+}
+
+__isl_give isl_ast_node *isl_ast_node_for_get_body(
+	__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+	if (node->type != isl_ast_node_for)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a for node", return NULL);
+	return isl_ast_node_copy(node->u.f.body);
+}
+
+/* Mark the given for node as being degenerate.
+ */
+__isl_give isl_ast_node *isl_ast_node_for_mark_degenerate(
+	__isl_take isl_ast_node *node)
+{
+	node = isl_ast_node_cow(node);
+	if (!node)
+		return NULL;
+	node->u.f.degenerate = 1;
+	return node;
+}
+
+isl_bool isl_ast_node_for_is_degenerate(__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return isl_bool_error;
+	if (node->type != isl_ast_node_for)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a for node", return isl_bool_error);
+	return node->u.f.degenerate;
+}
+
+__isl_give isl_ast_expr *isl_ast_node_for_get_iterator(
+	__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+	if (node->type != isl_ast_node_for)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a for node", return NULL);
+	return isl_ast_expr_copy(node->u.f.iterator);
+}
+
+__isl_give isl_ast_expr *isl_ast_node_for_get_init(
+	__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+	if (node->type != isl_ast_node_for)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a for node", return NULL);
+	return isl_ast_expr_copy(node->u.f.init);
+}
+
+/* Return the condition expression of the given for node.
+ *
+ * If the for node is degenerate, then the condition is not explicitly
+ * stored in the node.  Instead, it is constructed as
+ *
+ *	iterator <= init
+ */
+__isl_give isl_ast_expr *isl_ast_node_for_get_cond(
+	__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+	if (node->type != isl_ast_node_for)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a for node", return NULL);
+	if (!node->u.f.degenerate)
+		return isl_ast_expr_copy(node->u.f.cond);
+
+	return isl_ast_expr_alloc_binary(isl_ast_op_le,
+				isl_ast_expr_copy(node->u.f.iterator),
+				isl_ast_expr_copy(node->u.f.init));
+}
+
+/* Return the increment of the given for node.
+ *
+ * If the for node is degenerate, then the increment is not explicitly
+ * stored in the node.  We simply return "1".
+ */
+__isl_give isl_ast_expr *isl_ast_node_for_get_inc(
+	__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+	if (node->type != isl_ast_node_for)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a for node", return NULL);
+	if (!node->u.f.degenerate)
+		return isl_ast_expr_copy(node->u.f.inc);
+	return isl_ast_expr_alloc_int_si(isl_ast_node_get_ctx(node), 1);
+}
+
+/* Replace the then branch of the if node "node" by "child".
+ */
+__isl_give isl_ast_node *isl_ast_node_if_set_then(
+	__isl_take isl_ast_node *node, __isl_take isl_ast_node *child)
+{
+	node = isl_ast_node_cow(node);
+	if (!node || !child)
+		goto error;
+	if (node->type != isl_ast_node_if)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not an if node", goto error);
+
+	isl_ast_node_free(node->u.i.then);
+	node->u.i.then = child;
+
+	return node;
+error:
+	isl_ast_node_free(node);
+	isl_ast_node_free(child);
+	return NULL;
+}
+
+__isl_give isl_ast_node *isl_ast_node_if_get_then(
+	__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+	if (node->type != isl_ast_node_if)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not an if node", return NULL);
+	return isl_ast_node_copy(node->u.i.then);
+}
+
+isl_bool isl_ast_node_if_has_else(
+	__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return isl_bool_error;
+	if (node->type != isl_ast_node_if)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not an if node", return isl_bool_error);
+	return node->u.i.else_node != NULL;
+}
+
+__isl_give isl_ast_node *isl_ast_node_if_get_else(
+	__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+	if (node->type != isl_ast_node_if)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not an if node", return NULL);
+	return isl_ast_node_copy(node->u.i.else_node);
+}
+
+__isl_give isl_ast_expr *isl_ast_node_if_get_cond(
+	__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+	if (node->type != isl_ast_node_if)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a guard node", return NULL);
+	return isl_ast_expr_copy(node->u.i.guard);
+}
+
+__isl_give isl_ast_node_list *isl_ast_node_block_get_children(
+	__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+	if (node->type != isl_ast_node_block)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a block node", return NULL);
+	return isl_ast_node_list_copy(node->u.b.children);
+}
+
+__isl_give isl_ast_expr *isl_ast_node_user_get_expr(
+	__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+	if (node->type != isl_ast_node_user)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a user node", return NULL);
+
+	return isl_ast_expr_copy(node->u.e.expr);
+}
+
+/* Return the mark identifier of the mark node "node".
+ */
+__isl_give isl_id *isl_ast_node_mark_get_id(__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+	if (node->type != isl_ast_node_mark)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a mark node", return NULL);
+
+	return isl_id_copy(node->u.m.mark);
+}
+
+/* Return the node marked by mark node "node".
+ */
+__isl_give isl_ast_node *isl_ast_node_mark_get_node(
+	__isl_keep isl_ast_node *node)
+{
+	if (!node)
+		return NULL;
+	if (node->type != isl_ast_node_mark)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a mark node", return NULL);
+
+	return isl_ast_node_copy(node->u.m.node);
+}
+
+__isl_give isl_id *isl_ast_node_get_annotation(__isl_keep isl_ast_node *node)
+{
+	return node ? isl_id_copy(node->annotation) : NULL;
+}
+
+/* Replace node->annotation by "annotation".
+ */
+__isl_give isl_ast_node *isl_ast_node_set_annotation(
+	__isl_take isl_ast_node *node, __isl_take isl_id *annotation)
+{
+	node = isl_ast_node_cow(node);
+	if (!node || !annotation)
+		goto error;
+
+	isl_id_free(node->annotation);
+	node->annotation = annotation;
+
+	return node;
+error:
+	isl_id_free(annotation);
+	return isl_ast_node_free(node);
+}
+
+/* Traverse the elements of "list" and all their descendants
+ * in depth first preorder.
+ *
+ * Return isl_stat_ok on success and isl_stat_error on failure.
+ */
+static isl_stat nodelist_foreach(__isl_keep isl_ast_node_list *list,
+	isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user), void *user)
+{
+	int i;
+
+	if (!list)
+		return isl_stat_error;
+
+	for (i = 0; i < list->n; ++i) {
+		isl_stat ok;
+		isl_ast_node *node = list->p[i];
+
+		ok = isl_ast_node_foreach_descendant_top_down(node, fn, user);
+		if (ok < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Traverse the descendants of "node" (including the node itself)
+ * in depth first preorder.
+ *
+ * If "fn" returns isl_bool_error on any of the nodes, then the traversal
+ * is aborted.
+ * If "fn" returns isl_bool_false on any of the nodes, then the subtree rooted
+ * at that node is skipped.
+ *
+ * Return isl_stat_ok on success and isl_stat_error on failure.
+ */
+isl_stat isl_ast_node_foreach_descendant_top_down(
+	__isl_keep isl_ast_node *node,
+	isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user), void *user)
+{
+	isl_bool more;
+	isl_stat ok;
+
+	if (!node)
+		return isl_stat_error;
+
+	more = fn(node, user);
+	if (more < 0)
+		return isl_stat_error;
+	if (!more)
+		return isl_stat_ok;
+
+	switch (node->type) {
+	case isl_ast_node_for:
+		node = node->u.f.body;
+		return isl_ast_node_foreach_descendant_top_down(node, fn, user);
+	case isl_ast_node_if:
+		ok = isl_ast_node_foreach_descendant_top_down(node->u.i.then,
+								fn, user);
+		if (ok < 0)
+			return isl_stat_error;
+		if (!node->u.i.else_node)
+			return isl_stat_ok;
+		node = node->u.i.else_node;
+		return isl_ast_node_foreach_descendant_top_down(node, fn, user);
+	case isl_ast_node_block:
+		return nodelist_foreach(node->u.b.children, fn, user);
+	case isl_ast_node_mark:
+		node = node->u.m.node;
+		return isl_ast_node_foreach_descendant_top_down(node, fn, user);
+	case isl_ast_node_user:
+		break;
+	case isl_ast_node_error:
+		return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Textual C representation of the various operators.
+ */
+static char *op_str_c[] = {
+	[isl_ast_op_and] = "&&",
+	[isl_ast_op_and_then] = "&&",
+	[isl_ast_op_or] = "||",
+	[isl_ast_op_or_else] = "||",
+	[isl_ast_op_max] = "max",
+	[isl_ast_op_min] = "min",
+	[isl_ast_op_minus] = "-",
+	[isl_ast_op_add] = "+",
+	[isl_ast_op_sub] = "-",
+	[isl_ast_op_mul] = "*",
+	[isl_ast_op_fdiv_q] = "floord",
+	[isl_ast_op_pdiv_q] = "/",
+	[isl_ast_op_pdiv_r] = "%",
+	[isl_ast_op_zdiv_r] = "%",
+	[isl_ast_op_div] = "/",
+	[isl_ast_op_eq] = "==",
+	[isl_ast_op_le] = "<=",
+	[isl_ast_op_ge] = ">=",
+	[isl_ast_op_lt] = "<",
+	[isl_ast_op_gt] = ">",
+	[isl_ast_op_member] = ".",
+	[isl_ast_op_address_of] = "&"
+};
+
+/* Precedence in C of the various operators.
+ * Based on http://en.wikipedia.org/wiki/Operators_in_C_and_C++
+ * Lowest value means highest precedence.
+ */
+static int op_prec[] = {
+	[isl_ast_op_and] = 13,
+	[isl_ast_op_and_then] = 13,
+	[isl_ast_op_or] = 14,
+	[isl_ast_op_or_else] = 14,
+	[isl_ast_op_max] = 2,
+	[isl_ast_op_min] = 2,
+	[isl_ast_op_minus] = 3,
+	[isl_ast_op_add] = 6,
+	[isl_ast_op_sub] = 6,
+	[isl_ast_op_mul] = 5,
+	[isl_ast_op_div] = 5,
+	[isl_ast_op_fdiv_q] = 2,
+	[isl_ast_op_pdiv_q] = 5,
+	[isl_ast_op_pdiv_r] = 5,
+	[isl_ast_op_zdiv_r] = 5,
+	[isl_ast_op_cond] = 15,
+	[isl_ast_op_select] = 15,
+	[isl_ast_op_eq] = 9,
+	[isl_ast_op_le] = 8,
+	[isl_ast_op_ge] = 8,
+	[isl_ast_op_lt] = 8,
+	[isl_ast_op_gt] = 8,
+	[isl_ast_op_call] = 2,
+	[isl_ast_op_access] = 2,
+	[isl_ast_op_member] = 2,
+	[isl_ast_op_address_of] = 3
+};
+
+/* Is the operator left-to-right associative?
+ */
+static int op_left[] = {
+	[isl_ast_op_and] = 1,
+	[isl_ast_op_and_then] = 1,
+	[isl_ast_op_or] = 1,
+	[isl_ast_op_or_else] = 1,
+	[isl_ast_op_max] = 1,
+	[isl_ast_op_min] = 1,
+	[isl_ast_op_minus] = 0,
+	[isl_ast_op_add] = 1,
+	[isl_ast_op_sub] = 1,
+	[isl_ast_op_mul] = 1,
+	[isl_ast_op_div] = 1,
+	[isl_ast_op_fdiv_q] = 1,
+	[isl_ast_op_pdiv_q] = 1,
+	[isl_ast_op_pdiv_r] = 1,
+	[isl_ast_op_zdiv_r] = 1,
+	[isl_ast_op_cond] = 0,
+	[isl_ast_op_select] = 0,
+	[isl_ast_op_eq] = 1,
+	[isl_ast_op_le] = 1,
+	[isl_ast_op_ge] = 1,
+	[isl_ast_op_lt] = 1,
+	[isl_ast_op_gt] = 1,
+	[isl_ast_op_call] = 1,
+	[isl_ast_op_access] = 1,
+	[isl_ast_op_member] = 1,
+	[isl_ast_op_address_of] = 0
+};
+
+static int is_and(enum isl_ast_op_type op)
+{
+	return op == isl_ast_op_and || op == isl_ast_op_and_then;
+}
+
+static int is_or(enum isl_ast_op_type op)
+{
+	return op == isl_ast_op_or || op == isl_ast_op_or_else;
+}
+
+static int is_add_sub(enum isl_ast_op_type op)
+{
+	return op == isl_ast_op_add || op == isl_ast_op_sub;
+}
+
+static int is_div_mod(enum isl_ast_op_type op)
+{
+	return op == isl_ast_op_div ||
+	       op == isl_ast_op_pdiv_r ||
+	       op == isl_ast_op_zdiv_r;
+}
+
+static __isl_give isl_printer *print_ast_expr_c(__isl_take isl_printer *p,
+	__isl_keep isl_ast_expr *expr);
+
+/* Do we need/want parentheses around "expr" as a subexpression of
+ * an "op" operation?  If "left" is set, then "expr" is the left-most
+ * operand.
+ *
+ * We only need parentheses if "expr" represents an operation.
+ *
+ * If op has a higher precedence than expr->u.op.op, then we need
+ * parentheses.
+ * If op and expr->u.op.op have the same precedence, but the operations
+ * are performed in an order that is different from the associativity,
+ * then we need parentheses.
+ *
+ * An and inside an or technically does not require parentheses,
+ * but some compilers complain about that, so we add them anyway.
+ *
+ * Computations such as "a / b * c" and "a % b + c" can be somewhat
+ * difficult to read, so we add parentheses for those as well.
+ */
+static int sub_expr_need_parens(enum isl_ast_op_type op,
+	__isl_keep isl_ast_expr *expr, int left)
+{
+	if (expr->type != isl_ast_expr_op)
+		return 0;
+
+	if (op_prec[expr->u.op.op] > op_prec[op])
+		return 1;
+	if (op_prec[expr->u.op.op] == op_prec[op] && left != op_left[op])
+		return 1;
+
+	if (is_or(op) && is_and(expr->u.op.op))
+		return 1;
+	if (op == isl_ast_op_mul && expr->u.op.op != isl_ast_op_mul &&
+	    op_prec[expr->u.op.op] == op_prec[op])
+		return 1;
+	if (is_add_sub(op) && is_div_mod(expr->u.op.op))
+		return 1;
+
+	return 0;
+}
+
+/* Print "expr" as a subexpression of an "op" operation in C format.
+ * If "left" is set, then "expr" is the left-most operand.
+ */
+static __isl_give isl_printer *print_sub_expr_c(__isl_take isl_printer *p,
+	enum isl_ast_op_type op, __isl_keep isl_ast_expr *expr, int left)
+{
+	int need_parens;
+
+	need_parens = sub_expr_need_parens(op, expr, left);
+
+	if (need_parens)
+		p = isl_printer_print_str(p, "(");
+	p = print_ast_expr_c(p, expr);
+	if (need_parens)
+		p = isl_printer_print_str(p, ")");
+	return p;
+}
+
+#define isl_ast_op_last	isl_ast_op_address_of
+
+/* Data structure that holds the user-specified textual
+ * representations for the operators in C format.
+ * The entries are either NULL or copies of strings.
+ * A NULL entry means that the default name should be used.
+ */
+struct isl_ast_op_names {
+	char *op_str[isl_ast_op_last + 1];
+};
+
+/* Create an empty struct isl_ast_op_names.
+ */
+static void *create_names(isl_ctx *ctx)
+{
+	return isl_calloc_type(ctx, struct isl_ast_op_names);
+}
+
+/* Free a struct isl_ast_op_names along with all memory
+ * owned by the struct.
+ */
+static void free_names(void *user)
+{
+	int i;
+	struct isl_ast_op_names *names = user;
+
+	if (!user)
+		return;
+
+	for (i = 0; i <= isl_ast_op_last; ++i)
+		free(names->op_str[i]);
+	free(user);
+}
+
+/* Create an identifier that is used to store
+ * an isl_ast_op_names note.
+ */
+static __isl_give isl_id *names_id(isl_ctx *ctx)
+{
+	return isl_id_alloc(ctx, "isl_ast_op_type_names", NULL);
+}
+
+/* Ensure that "p" has a note identified by "id".
+ * If there is no such note yet, then it is created by "note_create" and
+ * scheduled do be freed by "note_free".
+ */
+static __isl_give isl_printer *alloc_note(__isl_take isl_printer *p,
+	__isl_keep isl_id *id, void *(*note_create)(isl_ctx *),
+	void (*note_free)(void *))
+{
+	isl_ctx *ctx;
+	isl_id *note_id;
+	isl_bool has_note;
+	void *note;
+
+	has_note = isl_printer_has_note(p, id);
+	if (has_note < 0)
+		return isl_printer_free(p);
+	if (has_note)
+		return p;
+
+	ctx = isl_printer_get_ctx(p);
+	note = note_create(ctx);
+	if (!note)
+		return isl_printer_free(p);
+	note_id = isl_id_alloc(ctx, NULL, note);
+	if (!note_id)
+		note_free(note);
+	else
+		note_id = isl_id_set_free_user(note_id, note_free);
+
+	p = isl_printer_set_note(p, isl_id_copy(id), note_id);
+
+	return p;
+}
+
+/* Ensure that "p" has an isl_ast_op_names note identified by "id".
+ */
+static __isl_give isl_printer *alloc_names(__isl_take isl_printer *p,
+	__isl_keep isl_id *id)
+{
+	return alloc_note(p, id, &create_names, &free_names);
+}
+
+/* Retrieve the note identified by "id" from "p".
+ * The note is assumed to exist.
+ */
+static void *get_note(__isl_keep isl_printer *p, __isl_keep isl_id *id)
+{
+	void *note;
+
+	id = isl_printer_get_note(p, isl_id_copy(id));
+	note = isl_id_get_user(id);
+	isl_id_free(id);
+
+	return note;
+}
+
+/* Use "name" to print operations of type "type" to "p".
+ *
+ * Store the name in an isl_ast_op_names note attached to "p", such that
+ * it can be retrieved by get_op_str.
+ */
+__isl_give isl_printer *isl_ast_op_type_set_print_name(
+	__isl_take isl_printer *p, enum isl_ast_op_type type,
+	__isl_keep const char *name)
+{
+	isl_id *id;
+	struct isl_ast_op_names *names;
+
+	if (!p)
+		return NULL;
+	if (type > isl_ast_op_last)
+		isl_die(isl_printer_get_ctx(p), isl_error_invalid,
+			"invalid type", return isl_printer_free(p));
+
+	id = names_id(isl_printer_get_ctx(p));
+	p = alloc_names(p, id);
+	names = get_note(p, id);
+	isl_id_free(id);
+	if (!names)
+		return isl_printer_free(p);
+	free(names->op_str[type]);
+	names->op_str[type] = strdup(name);
+
+	return p;
+}
+
+/* Return the textual representation of "type" in C format.
+ *
+ * If there is a user-specified name in an isl_ast_op_names note
+ * associated to "p", then return that.
+ * Otherwise, return the default name in op_str.
+ */
+static const char *get_op_str_c(__isl_keep isl_printer *p,
+	enum isl_ast_op_type type)
+{
+	isl_id *id;
+	isl_bool has_names;
+	struct isl_ast_op_names *names = NULL;
+
+	id = names_id(isl_printer_get_ctx(p));
+	has_names = isl_printer_has_note(p, id);
+	if (has_names >= 0 && has_names)
+		names = get_note(p, id);
+	isl_id_free(id);
+	if (names && names->op_str[type])
+		return names->op_str[type];
+	return op_str_c[type];
+}
+
+/* Print a min or max reduction "expr" in C format.
+ */
+static __isl_give isl_printer *print_min_max_c(__isl_take isl_printer *p,
+	__isl_keep isl_ast_expr *expr)
+{
+	int i = 0;
+
+	for (i = 1; i < expr->u.op.n_arg; ++i) {
+		p = isl_printer_print_str(p, get_op_str_c(p, expr->u.op.op));
+		p = isl_printer_print_str(p, "(");
+	}
+	p = isl_printer_print_ast_expr(p, expr->u.op.args[0]);
+	for (i = 1; i < expr->u.op.n_arg; ++i) {
+		p = isl_printer_print_str(p, ", ");
+		p = print_ast_expr_c(p, expr->u.op.args[i]);
+		p = isl_printer_print_str(p, ")");
+	}
+
+	return p;
+}
+
+/* Print a function call "expr" in C format.
+ *
+ * The first argument represents the function to be called.
+ */
+static __isl_give isl_printer *print_call_c(__isl_take isl_printer *p,
+	__isl_keep isl_ast_expr *expr)
+{
+	int i = 0;
+
+	p = print_ast_expr_c(p, expr->u.op.args[0]);
+	p = isl_printer_print_str(p, "(");
+	for (i = 1; i < expr->u.op.n_arg; ++i) {
+		if (i != 1)
+			p = isl_printer_print_str(p, ", ");
+		p = print_ast_expr_c(p, expr->u.op.args[i]);
+	}
+	p = isl_printer_print_str(p, ")");
+
+	return p;
+}
+
+/* Print an array access "expr" in C format.
+ *
+ * The first argument represents the array being accessed.
+ */
+static __isl_give isl_printer *print_access_c(__isl_take isl_printer *p,
+	__isl_keep isl_ast_expr *expr)
+{
+	int i = 0;
+
+	p = print_ast_expr_c(p, expr->u.op.args[0]);
+	for (i = 1; i < expr->u.op.n_arg; ++i) {
+		p = isl_printer_print_str(p, "[");
+		p = print_ast_expr_c(p, expr->u.op.args[i]);
+		p = isl_printer_print_str(p, "]");
+	}
+
+	return p;
+}
+
+/* Print "expr" to "p" in C format.
+ */
+static __isl_give isl_printer *print_ast_expr_c(__isl_take isl_printer *p,
+	__isl_keep isl_ast_expr *expr)
+{
+	if (!p)
+		return NULL;
+	if (!expr)
+		return isl_printer_free(p);
+
+	switch (expr->type) {
+	case isl_ast_expr_op:
+		if (expr->u.op.op == isl_ast_op_call) {
+			p = print_call_c(p, expr);
+			break;
+		}
+		if (expr->u.op.op == isl_ast_op_access) {
+			p = print_access_c(p, expr);
+			break;
+		}
+		if (expr->u.op.n_arg == 1) {
+			p = isl_printer_print_str(p,
+						get_op_str_c(p, expr->u.op.op));
+			p = print_sub_expr_c(p, expr->u.op.op,
+						expr->u.op.args[0], 0);
+			break;
+		}
+		if (expr->u.op.op == isl_ast_op_fdiv_q) {
+			const char *name = get_op_str_c(p, isl_ast_op_fdiv_q);
+			p = isl_printer_print_str(p, name);
+			p = isl_printer_print_str(p, "(");
+			p = print_ast_expr_c(p, expr->u.op.args[0]);
+			p = isl_printer_print_str(p, ", ");
+			p = print_ast_expr_c(p, expr->u.op.args[1]);
+			p = isl_printer_print_str(p, ")");
+			break;
+		}
+		if (expr->u.op.op == isl_ast_op_max ||
+		    expr->u.op.op == isl_ast_op_min) {
+			p = print_min_max_c(p, expr);
+			break;
+		}
+		if (expr->u.op.op == isl_ast_op_cond ||
+		    expr->u.op.op == isl_ast_op_select) {
+			p = print_ast_expr_c(p, expr->u.op.args[0]);
+			p = isl_printer_print_str(p, " ? ");
+			p = print_ast_expr_c(p, expr->u.op.args[1]);
+			p = isl_printer_print_str(p, " : ");
+			p = print_ast_expr_c(p, expr->u.op.args[2]);
+			break;
+		}
+		if (expr->u.op.n_arg != 2)
+			isl_die(isl_printer_get_ctx(p), isl_error_internal,
+				"operation should have two arguments",
+				return isl_printer_free(p));
+		p = print_sub_expr_c(p, expr->u.op.op, expr->u.op.args[0], 1);
+		if (expr->u.op.op != isl_ast_op_member)
+			p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_str(p, get_op_str_c(p, expr->u.op.op));
+		if (expr->u.op.op != isl_ast_op_member)
+			p = isl_printer_print_str(p, " ");
+		p = print_sub_expr_c(p, expr->u.op.op, expr->u.op.args[1], 0);
+		break;
+	case isl_ast_expr_id:
+		p = isl_printer_print_str(p, isl_id_get_name(expr->u.id));
+		break;
+	case isl_ast_expr_int:
+		p = isl_printer_print_val(p, expr->u.v);
+		break;
+	case isl_ast_expr_error:
+		break;
+	}
+
+	return p;
+}
+
+/* Textual representation of the isl_ast_op_type elements
+ * for use in a YAML representation of an isl_ast_expr.
+ */
+static char *op_str[] = {
+	[isl_ast_op_and] = "and",
+	[isl_ast_op_and_then] = "and_then",
+	[isl_ast_op_or] = "or",
+	[isl_ast_op_or_else] = "or_else",
+	[isl_ast_op_max] = "max",
+	[isl_ast_op_min] = "min",
+	[isl_ast_op_minus] = "minus",
+	[isl_ast_op_add] = "add",
+	[isl_ast_op_sub] = "sub",
+	[isl_ast_op_mul] = "mul",
+	[isl_ast_op_div] = "div",
+	[isl_ast_op_fdiv_q] = "fdiv_q",
+	[isl_ast_op_pdiv_q] = "pdiv_q",
+	[isl_ast_op_pdiv_r] = "pdiv_r",
+	[isl_ast_op_zdiv_r] = "zdiv_r",
+	[isl_ast_op_cond] = "cond",
+	[isl_ast_op_select] = "select",
+	[isl_ast_op_eq] = "eq",
+	[isl_ast_op_le] = "le",
+	[isl_ast_op_lt] = "lt",
+	[isl_ast_op_ge] = "ge",
+	[isl_ast_op_gt] = "gt",
+	[isl_ast_op_call] = "call",
+	[isl_ast_op_access] = "access",
+	[isl_ast_op_member] = "member",
+	[isl_ast_op_address_of] = "address_of"
+};
+
+static __isl_give isl_printer *print_ast_expr_isl(__isl_take isl_printer *p,
+	__isl_keep isl_ast_expr *expr);
+
+/* Print the arguments of "expr" to "p" in isl format.
+ *
+ * If there are no arguments, then nothing needs to be printed.
+ * Otherwise add an "args" key to the current mapping with as value
+ * the list of arguments of "expr".
+ */
+static __isl_give isl_printer *print_arguments(__isl_take isl_printer *p,
+	__isl_keep isl_ast_expr *expr)
+{
+	int i, n;
+
+	n = isl_ast_expr_get_op_n_arg(expr);
+	if (n < 0)
+		return isl_printer_free(p);
+	if (n == 0)
+		return p;
+
+	p = isl_printer_print_str(p, "args");
+	p = isl_printer_yaml_next(p);
+	p = isl_printer_yaml_start_sequence(p);
+	for (i = 0; i < n; ++i) {
+		isl_ast_expr *arg;
+
+		arg = isl_ast_expr_get_op_arg(expr, i);
+		p = print_ast_expr_isl(p, arg);
+		isl_ast_expr_free(arg);
+		p = isl_printer_yaml_next(p);
+	}
+	p = isl_printer_yaml_end_sequence(p);
+
+	return p;
+}
+
+/* Print "expr" to "p" in isl format.
+ *
+ * In particular, print the isl_ast_expr as a YAML document.
+ */
+static __isl_give isl_printer *print_ast_expr_isl(__isl_take isl_printer *p,
+	__isl_keep isl_ast_expr *expr)
+{
+	enum isl_ast_expr_type type;
+	enum isl_ast_op_type op;
+	isl_id *id;
+	isl_val *v;
+
+	if (!expr)
+		return isl_printer_free(p);
+
+	p = isl_printer_yaml_start_mapping(p);
+	type = isl_ast_expr_get_type(expr);
+	switch (type) {
+	case isl_ast_expr_error:
+		return isl_printer_free(p);
+	case isl_ast_expr_op:
+		op = isl_ast_expr_get_op_type(expr);
+		if (op == isl_ast_op_error)
+			return isl_printer_free(p);
+		p = isl_printer_print_str(p, "op");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, op_str[op]);
+		p = isl_printer_yaml_next(p);
+		p = print_arguments(p, expr);
+		break;
+	case isl_ast_expr_id:
+		p = isl_printer_print_str(p, "id");
+		p = isl_printer_yaml_next(p);
+		id = isl_ast_expr_get_id(expr);
+		p = isl_printer_print_id(p, id);
+		isl_id_free(id);
+		break;
+	case isl_ast_expr_int:
+		p = isl_printer_print_str(p, "val");
+		p = isl_printer_yaml_next(p);
+		v = isl_ast_expr_get_val(expr);
+		p = isl_printer_print_val(p, v);
+		isl_val_free(v);
+		break;
+	}
+	p = isl_printer_yaml_end_mapping(p);
+
+	return p;
+}
+
+/* Print "expr" to "p".
+ *
+ * Only an isl and a C format are supported.
+ */
+__isl_give isl_printer *isl_printer_print_ast_expr(__isl_take isl_printer *p,
+	__isl_keep isl_ast_expr *expr)
+{
+	int format;
+
+	if (!p)
+		return NULL;
+
+	format = isl_printer_get_output_format(p);
+	switch (format) {
+	case ISL_FORMAT_ISL:
+		p = print_ast_expr_isl(p, expr);
+		break;
+	case ISL_FORMAT_C:
+		p = print_ast_expr_c(p, expr);
+		break;
+	default:
+		isl_die(isl_printer_get_ctx(p), isl_error_unsupported,
+			"output format not supported for ast_expr",
+			return isl_printer_free(p));
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_ast_node_isl(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node);
+
+/* Print a YAML sequence containing the entries in "list" to "p".
+ */
+static __isl_give isl_printer *print_ast_node_list(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node_list *list)
+{
+	int i, n;
+
+	n = isl_ast_node_list_n_ast_node(list);
+	if (n < 0)
+		return isl_printer_free(p);
+
+	p = isl_printer_yaml_start_sequence(p);
+	for (i = 0; i < n; ++i) {
+		isl_ast_node *node;
+
+		node = isl_ast_node_list_get_ast_node(list, i);
+		p = print_ast_node_isl(p, node);
+		isl_ast_node_free(node);
+		p = isl_printer_yaml_next(p);
+	}
+	p = isl_printer_yaml_end_sequence(p);
+
+	return p;
+}
+
+/* Print "node" to "p" in "isl format".
+ *
+ * In particular, print the isl_ast_node as a YAML document.
+ */
+static __isl_give isl_printer *print_ast_node_isl(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node)
+{
+	switch (node->type) {
+	case isl_ast_node_for:
+		p = isl_printer_yaml_start_mapping(p);
+		p = isl_printer_print_str(p, "iterator");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_ast_expr(p, node->u.f.iterator);
+		p = isl_printer_yaml_next(p);
+		if (node->u.f.degenerate) {
+			p = isl_printer_print_str(p, "value");
+			p = isl_printer_yaml_next(p);
+			p = isl_printer_print_ast_expr(p, node->u.f.init);
+			p = isl_printer_yaml_next(p);
+		} else {
+			p = isl_printer_print_str(p, "init");
+			p = isl_printer_yaml_next(p);
+			p = isl_printer_print_ast_expr(p, node->u.f.init);
+			p = isl_printer_yaml_next(p);
+			p = isl_printer_print_str(p, "cond");
+			p = isl_printer_yaml_next(p);
+			p = isl_printer_print_ast_expr(p, node->u.f.cond);
+			p = isl_printer_yaml_next(p);
+			p = isl_printer_print_str(p, "inc");
+			p = isl_printer_yaml_next(p);
+			p = isl_printer_print_ast_expr(p, node->u.f.inc);
+			p = isl_printer_yaml_next(p);
+		}
+		if (node->u.f.body) {
+			p = isl_printer_print_str(p, "body");
+			p = isl_printer_yaml_next(p);
+			p = isl_printer_print_ast_node(p, node->u.f.body);
+			p = isl_printer_yaml_next(p);
+		}
+		p = isl_printer_yaml_end_mapping(p);
+		break;
+	case isl_ast_node_mark:
+		p = isl_printer_yaml_start_mapping(p);
+		p = isl_printer_print_str(p, "mark");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_id(p, node->u.m.mark);
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "node");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_ast_node(p, node->u.m.node);
+		p = isl_printer_yaml_end_mapping(p);
+		break;
+	case isl_ast_node_user:
+		p = isl_printer_yaml_start_mapping(p);
+		p = isl_printer_print_str(p, "user");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_ast_expr(p, node->u.e.expr);
+		p = isl_printer_yaml_end_mapping(p);
+		break;
+	case isl_ast_node_if:
+		p = isl_printer_yaml_start_mapping(p);
+		p = isl_printer_print_str(p, "guard");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_ast_expr(p, node->u.i.guard);
+		p = isl_printer_yaml_next(p);
+		if (node->u.i.then) {
+			p = isl_printer_print_str(p, "then");
+			p = isl_printer_yaml_next(p);
+			p = isl_printer_print_ast_node(p, node->u.i.then);
+			p = isl_printer_yaml_next(p);
+		}
+		if (node->u.i.else_node) {
+			p = isl_printer_print_str(p, "else");
+			p = isl_printer_yaml_next(p);
+			p = isl_printer_print_ast_node(p, node->u.i.else_node);
+		}
+		p = isl_printer_yaml_end_mapping(p);
+		break;
+	case isl_ast_node_block:
+		p = print_ast_node_list(p, node->u.b.children);
+		break;
+	case isl_ast_node_error:
+		break;
+	}
+	return p;
+}
+
+/* Do we need to print a block around the body "node" of a for or if node?
+ *
+ * If the node is a block, then we need to print a block.
+ * Also if the node is a degenerate for then we will print it as
+ * an assignment followed by the body of the for loop, so we need a block
+ * as well.
+ * If the node is an if node with an else, then we print a block
+ * to avoid spurious dangling else warnings emitted by some compilers.
+ * If the node is a mark, then in principle, we would have to check
+ * the child of the mark node.  However, even if the child would not
+ * require us to print a block, for readability it is probably best
+ * to print a block anyway.
+ * If the ast_always_print_block option has been set, then we print a block.
+ */
+static int need_block(__isl_keep isl_ast_node *node)
+{
+	isl_ctx *ctx;
+
+	if (node->type == isl_ast_node_block)
+		return 1;
+	if (node->type == isl_ast_node_for && node->u.f.degenerate)
+		return 1;
+	if (node->type == isl_ast_node_if && node->u.i.else_node)
+		return 1;
+	if (node->type == isl_ast_node_mark)
+		return 1;
+
+	ctx = isl_ast_node_get_ctx(node);
+	return isl_options_get_ast_always_print_block(ctx);
+}
+
+static __isl_give isl_printer *print_ast_node_c(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node,
+	__isl_keep isl_ast_print_options *options, int in_block, int in_list);
+static __isl_give isl_printer *print_if_c(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node,
+	__isl_keep isl_ast_print_options *options, int new_line,
+	int force_block);
+
+/* Print the body "node" of a for or if node.
+ * If "else_node" is set, then it is printed as well.
+ * If "force_block" is set, then print out the body as a block.
+ *
+ * We first check if we need to print out a block.
+ * We always print out a block if there is an else node to make
+ * sure that the else node is matched to the correct if node.
+ * For consistency, the corresponding else node is also printed as a block.
+ *
+ * If the else node is itself an if, then we print it as
+ *
+ *	} else if (..) {
+ *	}
+ *
+ * Otherwise the else node is printed as
+ *
+ *	} else {
+ *	  node
+ *	}
+ */
+static __isl_give isl_printer *print_body_c(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node, __isl_keep isl_ast_node *else_node,
+	__isl_keep isl_ast_print_options *options, int force_block)
+{
+	if (!node)
+		return isl_printer_free(p);
+
+	if (!force_block && !else_node && !need_block(node)) {
+		p = isl_printer_end_line(p);
+		p = isl_printer_indent(p, 2);
+		p = isl_ast_node_print(node, p,
+					isl_ast_print_options_copy(options));
+		p = isl_printer_indent(p, -2);
+		return p;
+	}
+
+	p = isl_printer_print_str(p, " {");
+	p = isl_printer_end_line(p);
+	p = isl_printer_indent(p, 2);
+	p = print_ast_node_c(p, node, options, 1, 0);
+	p = isl_printer_indent(p, -2);
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "}");
+	if (else_node) {
+		if (else_node->type == isl_ast_node_if) {
+			p = isl_printer_print_str(p, " else ");
+			p = print_if_c(p, else_node, options, 0, 1);
+		} else {
+			p = isl_printer_print_str(p, " else");
+			p = print_body_c(p, else_node, NULL, options, 1);
+		}
+	} else
+		p = isl_printer_end_line(p);
+
+	return p;
+}
+
+/* Print the start of a compound statement.
+ */
+static __isl_give isl_printer *start_block(__isl_take isl_printer *p)
+{
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "{");
+	p = isl_printer_end_line(p);
+	p = isl_printer_indent(p, 2);
+
+	return p;
+}
+
+/* Print the end of a compound statement.
+ */
+static __isl_give isl_printer *end_block(__isl_take isl_printer *p)
+{
+	p = isl_printer_indent(p, -2);
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "}");
+	p = isl_printer_end_line(p);
+
+	return p;
+}
+
+/* Print the for node "node".
+ *
+ * If the for node is degenerate, it is printed as
+ *
+ *	type iterator = init;
+ *	body
+ *
+ * Otherwise, it is printed as
+ *
+ *	for (type iterator = init; cond; iterator += inc)
+ *		body
+ *
+ * "in_block" is set if we are currently inside a block.
+ * "in_list" is set if the current node is not alone in the block.
+ * If we are not in a block or if the current not is not alone in the block
+ * then we print a block around a degenerate for loop such that the variable
+ * declaration will not conflict with any potential other declaration
+ * of the same variable.
+ */
+static __isl_give isl_printer *print_for_c(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node,
+	__isl_keep isl_ast_print_options *options, int in_block, int in_list)
+{
+	isl_id *id;
+	const char *name;
+	const char *type;
+
+	type = isl_options_get_ast_iterator_type(isl_printer_get_ctx(p));
+	if (!node->u.f.degenerate) {
+		id = isl_ast_expr_get_id(node->u.f.iterator);
+		name = isl_id_get_name(id);
+		isl_id_free(id);
+		p = isl_printer_start_line(p);
+		p = isl_printer_print_str(p, "for (");
+		p = isl_printer_print_str(p, type);
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_str(p, name);
+		p = isl_printer_print_str(p, " = ");
+		p = isl_printer_print_ast_expr(p, node->u.f.init);
+		p = isl_printer_print_str(p, "; ");
+		p = isl_printer_print_ast_expr(p, node->u.f.cond);
+		p = isl_printer_print_str(p, "; ");
+		p = isl_printer_print_str(p, name);
+		p = isl_printer_print_str(p, " += ");
+		p = isl_printer_print_ast_expr(p, node->u.f.inc);
+		p = isl_printer_print_str(p, ")");
+		p = print_body_c(p, node->u.f.body, NULL, options, 0);
+	} else {
+		id = isl_ast_expr_get_id(node->u.f.iterator);
+		name = isl_id_get_name(id);
+		isl_id_free(id);
+		if (!in_block || in_list)
+			p = start_block(p);
+		p = isl_printer_start_line(p);
+		p = isl_printer_print_str(p, type);
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_str(p, name);
+		p = isl_printer_print_str(p, " = ");
+		p = isl_printer_print_ast_expr(p, node->u.f.init);
+		p = isl_printer_print_str(p, ";");
+		p = isl_printer_end_line(p);
+		p = print_ast_node_c(p, node->u.f.body, options, 1, 0);
+		if (!in_block || in_list)
+			p = end_block(p);
+	}
+
+	return p;
+}
+
+/* Print the if node "node".
+ * If "new_line" is set then the if node should be printed on a new line.
+ * If "force_block" is set, then print out the body as a block.
+ */
+static __isl_give isl_printer *print_if_c(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node,
+	__isl_keep isl_ast_print_options *options, int new_line,
+	int force_block)
+{
+	if (new_line)
+		p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "if (");
+	p = isl_printer_print_ast_expr(p, node->u.i.guard);
+	p = isl_printer_print_str(p, ")");
+	p = print_body_c(p, node->u.i.then, node->u.i.else_node, options,
+			force_block);
+
+	return p;
+}
+
+/* Print the "node" to "p".
+ *
+ * "in_block" is set if we are currently inside a block.
+ * If so, we do not print a block around the children of a block node.
+ * We do this to avoid an extra block around the body of a degenerate
+ * for node.
+ *
+ * "in_list" is set if the current node is not alone in the block.
+ */
+static __isl_give isl_printer *print_ast_node_c(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node,
+	__isl_keep isl_ast_print_options *options, int in_block, int in_list)
+{
+	switch (node->type) {
+	case isl_ast_node_for:
+		if (options->print_for)
+			return options->print_for(p,
+					isl_ast_print_options_copy(options),
+					node, options->print_for_user);
+		p = print_for_c(p, node, options, in_block, in_list);
+		break;
+	case isl_ast_node_if:
+		p = print_if_c(p, node, options, 1, 0);
+		break;
+	case isl_ast_node_block:
+		if (!in_block)
+			p = start_block(p);
+		p = isl_ast_node_list_print(node->u.b.children, p, options);
+		if (!in_block)
+			p = end_block(p);
+		break;
+	case isl_ast_node_mark:
+		p = isl_printer_start_line(p);
+		p = isl_printer_print_str(p, "// ");
+		p = isl_printer_print_str(p, isl_id_get_name(node->u.m.mark));
+		p = isl_printer_end_line(p);
+		p = print_ast_node_c(p, node->u.m.node, options, 0, in_list);
+		break;
+	case isl_ast_node_user:
+		if (options->print_user)
+			return options->print_user(p,
+					isl_ast_print_options_copy(options),
+					node, options->print_user_user);
+		p = isl_printer_start_line(p);
+		p = isl_printer_print_ast_expr(p, node->u.e.expr);
+		p = isl_printer_print_str(p, ";");
+		p = isl_printer_end_line(p);
+		break;
+	case isl_ast_node_error:
+		break;
+	}
+	return p;
+}
+
+/* Print the for node "node" to "p".
+ */
+__isl_give isl_printer *isl_ast_node_for_print(__isl_keep isl_ast_node *node,
+	__isl_take isl_printer *p, __isl_take isl_ast_print_options *options)
+{
+	if (!node || !options)
+		goto error;
+	if (node->type != isl_ast_node_for)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not a for node", goto error);
+	p = print_for_c(p, node, options, 0, 0);
+	isl_ast_print_options_free(options);
+	return p;
+error:
+	isl_ast_print_options_free(options);
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print the if node "node" to "p".
+ */
+__isl_give isl_printer *isl_ast_node_if_print(__isl_keep isl_ast_node *node,
+	__isl_take isl_printer *p, __isl_take isl_ast_print_options *options)
+{
+	if (!node || !options)
+		goto error;
+	if (node->type != isl_ast_node_if)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_invalid,
+			"not an if node", goto error);
+	p = print_if_c(p, node, options, 1, 0);
+	isl_ast_print_options_free(options);
+	return p;
+error:
+	isl_ast_print_options_free(options);
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print "node" to "p".
+ */
+__isl_give isl_printer *isl_ast_node_print(__isl_keep isl_ast_node *node,
+	__isl_take isl_printer *p, __isl_take isl_ast_print_options *options)
+{
+	if (!options || !node)
+		goto error;
+	p = print_ast_node_c(p, node, options, 0, 0);
+	isl_ast_print_options_free(options);
+	return p;
+error:
+	isl_ast_print_options_free(options);
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print "node" to "p".
+ */
+__isl_give isl_printer *isl_printer_print_ast_node(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node)
+{
+	int format;
+	isl_ast_print_options *options;
+
+	if (!p)
+		return NULL;
+
+	format = isl_printer_get_output_format(p);
+	switch (format) {
+	case ISL_FORMAT_ISL:
+		p = print_ast_node_isl(p, node);
+		break;
+	case ISL_FORMAT_C:
+		options = isl_ast_print_options_alloc(isl_printer_get_ctx(p));
+		p = isl_ast_node_print(node, p, options);
+		break;
+	default:
+		isl_die(isl_printer_get_ctx(p), isl_error_unsupported,
+			"output format not supported for ast_node",
+			return isl_printer_free(p));
+	}
+
+	return p;
+}
+
+/* Print the list of nodes "list" to "p".
+ */
+__isl_give isl_printer *isl_ast_node_list_print(
+	__isl_keep isl_ast_node_list *list, __isl_take isl_printer *p,
+	__isl_keep isl_ast_print_options *options)
+{
+	int i;
+
+	if (!p || !list || !options)
+		return isl_printer_free(p);
+
+	for (i = 0; i < list->n; ++i)
+		p = print_ast_node_c(p, list->p[i], options, 1, 1);
+
+	return p;
+}
+
+#define ISL_AST_MACRO_FLOORD	(1 << 0)
+#define ISL_AST_MACRO_MIN	(1 << 1)
+#define ISL_AST_MACRO_MAX	(1 << 2)
+#define ISL_AST_MACRO_ALL	(ISL_AST_MACRO_FLOORD | \
+				 ISL_AST_MACRO_MIN | \
+				 ISL_AST_MACRO_MAX)
+
+/* If "expr" contains an isl_ast_op_min, isl_ast_op_max or isl_ast_op_fdiv_q
+ * then set the corresponding bit in "macros".
+ */
+static int ast_expr_required_macros(__isl_keep isl_ast_expr *expr, int macros)
+{
+	int i;
+
+	if (macros == ISL_AST_MACRO_ALL)
+		return macros;
+
+	if (expr->type != isl_ast_expr_op)
+		return macros;
+
+	if (expr->u.op.op == isl_ast_op_min)
+		macros |= ISL_AST_MACRO_MIN;
+	if (expr->u.op.op == isl_ast_op_max)
+		macros |= ISL_AST_MACRO_MAX;
+	if (expr->u.op.op == isl_ast_op_fdiv_q)
+		macros |= ISL_AST_MACRO_FLOORD;
+
+	for (i = 0; i < expr->u.op.n_arg; ++i)
+		macros = ast_expr_required_macros(expr->u.op.args[i], macros);
+
+	return macros;
+}
+
+static int ast_node_list_required_macros(__isl_keep isl_ast_node_list *list,
+	int macros);
+
+/* If "node" contains an isl_ast_op_min, isl_ast_op_max or isl_ast_op_fdiv_q
+ * then set the corresponding bit in "macros".
+ */
+static int ast_node_required_macros(__isl_keep isl_ast_node *node, int macros)
+{
+	if (macros == ISL_AST_MACRO_ALL)
+		return macros;
+
+	switch (node->type) {
+	case isl_ast_node_for:
+		macros = ast_expr_required_macros(node->u.f.init, macros);
+		if (!node->u.f.degenerate) {
+			macros = ast_expr_required_macros(node->u.f.cond,
+								macros);
+			macros = ast_expr_required_macros(node->u.f.inc,
+								macros);
+		}
+		macros = ast_node_required_macros(node->u.f.body, macros);
+		break;
+	case isl_ast_node_if:
+		macros = ast_expr_required_macros(node->u.i.guard, macros);
+		macros = ast_node_required_macros(node->u.i.then, macros);
+		if (node->u.i.else_node)
+			macros = ast_node_required_macros(node->u.i.else_node,
+								macros);
+		break;
+	case isl_ast_node_block:
+		macros = ast_node_list_required_macros(node->u.b.children,
+							macros);
+		break;
+	case isl_ast_node_mark:
+		macros = ast_node_required_macros(node->u.m.node, macros);
+		break;
+	case isl_ast_node_user:
+		macros = ast_expr_required_macros(node->u.e.expr, macros);
+		break;
+	case isl_ast_node_error:
+		break;
+	}
+
+	return macros;
+}
+
+/* If "list" contains an isl_ast_op_min, isl_ast_op_max or isl_ast_op_fdiv_q
+ * then set the corresponding bit in "macros".
+ */
+static int ast_node_list_required_macros(__isl_keep isl_ast_node_list *list,
+	int macros)
+{
+	int i;
+
+	for (i = 0; i < list->n; ++i)
+		macros = ast_node_required_macros(list->p[i], macros);
+
+	return macros;
+}
+
+/* Data structure for keeping track of whether a macro definition
+ * for a given type has already been printed.
+ * The value is zero if no definition has been printed and non-zero otherwise.
+ */
+struct isl_ast_op_printed {
+	char printed[isl_ast_op_last + 1];
+};
+
+/* Create an empty struct isl_ast_op_printed.
+ */
+static void *create_printed(isl_ctx *ctx)
+{
+	return isl_calloc_type(ctx, struct isl_ast_op_printed);
+}
+
+/* Free a struct isl_ast_op_printed.
+ */
+static void free_printed(void *user)
+{
+	free(user);
+}
+
+/* Ensure that "p" has an isl_ast_op_printed note identified by "id".
+ */
+static __isl_give isl_printer *alloc_printed(__isl_take isl_printer *p,
+	__isl_keep isl_id *id)
+{
+	return alloc_note(p, id, &create_printed, &free_printed);
+}
+
+/* Create an identifier that is used to store
+ * an isl_ast_op_printed note.
+ */
+static __isl_give isl_id *printed_id(isl_ctx *ctx)
+{
+	return isl_id_alloc(ctx, "isl_ast_op_type_printed", NULL);
+}
+
+/* Did the user specify that a macro definition should only be
+ * printed once and has a macro definition for "type" already
+ * been printed to "p"?
+ * If definitions should only be printed once, but a definition
+ * for "p" has not yet been printed, then mark it as having been
+ * printed so that it will not printed again.
+ * The actual printing is taken care of by the caller.
+ */
+static isl_bool already_printed_once(__isl_keep isl_printer *p,
+	enum isl_ast_op_type type)
+{
+	isl_ctx *ctx;
+	isl_id *id;
+	struct isl_ast_op_printed *printed;
+
+	if (!p)
+		return isl_bool_error;
+
+	ctx = isl_printer_get_ctx(p);
+	if (!isl_options_get_ast_print_macro_once(ctx))
+		return isl_bool_false;
+
+	if (type > isl_ast_op_last)
+		isl_die(isl_printer_get_ctx(p), isl_error_invalid,
+			"invalid type", return isl_bool_error);
+
+	id = printed_id(isl_printer_get_ctx(p));
+	p = alloc_printed(p, id);
+	printed = get_note(p, id);
+	isl_id_free(id);
+	if (!printed)
+		return isl_bool_error;
+
+	if (printed->printed[type])
+		return isl_bool_true;
+
+	printed->printed[type] = 1;
+	return isl_bool_false;
+}
+
+/* Print a macro definition for the operator "type".
+ *
+ * If the user has specified that a macro definition should
+ * only be printed once to any given printer and if the macro definition
+ * has already been printed to "p", then do not print the definition.
+ */
+__isl_give isl_printer *isl_ast_op_type_print_macro(
+	enum isl_ast_op_type type, __isl_take isl_printer *p)
+{
+	isl_bool skip;
+
+	skip = already_printed_once(p, type);
+	if (skip < 0)
+		return isl_printer_free(p);
+	if (skip)
+		return p;
+
+	switch (type) {
+	case isl_ast_op_min:
+		p = isl_printer_start_line(p);
+		p = isl_printer_print_str(p, "#define ");
+		p = isl_printer_print_str(p, get_op_str_c(p, type));
+		p = isl_printer_print_str(p,
+			"(x,y)    ((x) < (y) ? (x) : (y))");
+		p = isl_printer_end_line(p);
+		break;
+	case isl_ast_op_max:
+		p = isl_printer_start_line(p);
+		p = isl_printer_print_str(p, "#define ");
+		p = isl_printer_print_str(p, get_op_str_c(p, type));
+		p = isl_printer_print_str(p,
+			"(x,y)    ((x) > (y) ? (x) : (y))");
+		p = isl_printer_end_line(p);
+		break;
+	case isl_ast_op_fdiv_q:
+		p = isl_printer_start_line(p);
+		p = isl_printer_print_str(p, "#define ");
+		p = isl_printer_print_str(p, get_op_str_c(p, type));
+		p = isl_printer_print_str(p,
+			"(n,d) "
+			"(((n)<0) ? -((-(n)+(d)-1)/(d)) : (n)/(d))");
+		p = isl_printer_end_line(p);
+		break;
+	default:
+		break;
+	}
+
+	return p;
+}
+
+/* Call "fn" for each type of operation represented in the "macros"
+ * bit vector.
+ */
+static isl_stat foreach_ast_op_type(int macros,
+	isl_stat (*fn)(enum isl_ast_op_type type, void *user), void *user)
+{
+	if (macros & ISL_AST_MACRO_MIN && fn(isl_ast_op_min, user) < 0)
+		return isl_stat_error;
+	if (macros & ISL_AST_MACRO_MAX && fn(isl_ast_op_max, user) < 0)
+		return isl_stat_error;
+	if (macros & ISL_AST_MACRO_FLOORD && fn(isl_ast_op_fdiv_q, user) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Call "fn" for each type of operation that appears in "expr"
+ * and that requires a macro definition.
+ */
+isl_stat isl_ast_expr_foreach_ast_op_type(__isl_keep isl_ast_expr *expr,
+	isl_stat (*fn)(enum isl_ast_op_type type, void *user), void *user)
+{
+	int macros;
+
+	if (!expr)
+		return isl_stat_error;
+
+	macros = ast_expr_required_macros(expr, 0);
+	return foreach_ast_op_type(macros, fn, user);
+}
+
+/* Call "fn" for each type of operation that appears in "node"
+ * and that requires a macro definition.
+ */
+isl_stat isl_ast_node_foreach_ast_op_type(__isl_keep isl_ast_node *node,
+	isl_stat (*fn)(enum isl_ast_op_type type, void *user), void *user)
+{
+	int macros;
+
+	if (!node)
+		return isl_stat_error;
+
+	macros = ast_node_required_macros(node, 0);
+	return foreach_ast_op_type(macros, fn, user);
+}
+
+static isl_stat ast_op_type_print_macro(enum isl_ast_op_type type, void *user)
+{
+	isl_printer **p = user;
+
+	*p = isl_ast_op_type_print_macro(type, *p);
+
+	return isl_stat_ok;
+}
+
+/* Print macro definitions for all the macros used in the result
+ * of printing "expr".
+ */
+__isl_give isl_printer *isl_ast_expr_print_macros(
+	__isl_keep isl_ast_expr *expr, __isl_take isl_printer *p)
+{
+	if (isl_ast_expr_foreach_ast_op_type(expr,
+					    &ast_op_type_print_macro, &p) < 0)
+		return isl_printer_free(p);
+	return p;
+}
+
+/* Print macro definitions for all the macros used in the result
+ * of printing "node".
+ */
+__isl_give isl_printer *isl_ast_node_print_macros(
+	__isl_keep isl_ast_node *node, __isl_take isl_printer *p)
+{
+	if (isl_ast_node_foreach_ast_op_type(node,
+					    &ast_op_type_print_macro, &p) < 0)
+		return isl_printer_free(p);
+	return p;
+}
+
+/* Return a string containing C code representing this isl_ast_expr.
+ */
+__isl_give char *isl_ast_expr_to_C_str(__isl_keep isl_ast_expr *expr)
+{
+	isl_printer *p;
+	char *str;
+
+	if (!expr)
+		return NULL;
+
+	p = isl_printer_to_str(isl_ast_expr_get_ctx(expr));
+	p = isl_printer_set_output_format(p, ISL_FORMAT_C);
+	p = isl_printer_print_ast_expr(p, expr);
+
+	str = isl_printer_get_str(p);
+
+	isl_printer_free(p);
+
+	return str;
+}
+
+/* Return a string containing C code representing this isl_ast_node.
+ */
+__isl_give char *isl_ast_node_to_C_str(__isl_keep isl_ast_node *node)
+{
+	isl_printer *p;
+	char *str;
+
+	if (!node)
+		return NULL;
+
+	p = isl_printer_to_str(isl_ast_node_get_ctx(node));
+	p = isl_printer_set_output_format(p, ISL_FORMAT_C);
+	p = isl_printer_print_ast_node(p, node);
+
+	str = isl_printer_get_str(p);
+
+	isl_printer_free(p);
+
+	return str;
+}
diff --git a/final/lib/External/isl/isl_ast_build.c b/final/lib/External/isl/isl_ast_build.c
new file mode 100644
index 0000000..65ab6d5
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_build.c
@@ -0,0 +1,2566 @@
+/*
+ * Copyright 2012-2013 Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <isl/map.h>
+#include <isl/aff.h>
+#include <isl/constraint.h>
+#include <isl/map.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl_ast_build_private.h>
+#include <isl_ast_private.h>
+#include <isl_config.h>
+
+/* Construct a map that isolates the current dimension.
+ *
+ * Essentially, the current dimension of "set" is moved to the single output
+ * dimension in the result, with the current dimension in the domain replaced
+ * by an unconstrained variable.
+ */
+__isl_give isl_map *isl_ast_build_map_to_iterator(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *set)
+{
+	isl_map *map;
+
+	map = isl_map_from_domain(set);
+	map = isl_map_add_dims(map, isl_dim_out, 1);
+
+	if (!build)
+		return isl_map_free(map);
+
+	map = isl_map_equate(map, isl_dim_in, build->depth, isl_dim_out, 0);
+	map = isl_map_eliminate(map, isl_dim_in, build->depth, 1);
+
+	return map;
+}
+
+/* Initialize the information derived during the AST generation to default
+ * values for a schedule domain in "space".
+ *
+ * We also check that the remaining fields are not NULL so that
+ * the calling functions don't have to perform this test.
+ */
+static __isl_give isl_ast_build *isl_ast_build_init_derived(
+	__isl_take isl_ast_build *build, __isl_take isl_space *space)
+{
+	isl_ctx *ctx;
+	isl_vec *strides;
+
+	build = isl_ast_build_cow(build);
+	if (!build || !build->domain)
+		goto error;
+
+	ctx = isl_ast_build_get_ctx(build);
+	strides = isl_vec_alloc(ctx, isl_space_dim(space, isl_dim_set));
+	strides = isl_vec_set_si(strides, 1);
+
+	isl_vec_free(build->strides);
+	build->strides = strides;
+
+	space = isl_space_map_from_set(space);
+	isl_multi_aff_free(build->offsets);
+	build->offsets = isl_multi_aff_zero(isl_space_copy(space));
+	isl_multi_aff_free(build->values);
+	build->values = isl_multi_aff_identity(isl_space_copy(space));
+	isl_multi_aff_free(build->internal2input);
+	build->internal2input = isl_multi_aff_identity(space);
+
+	if (!build->iterators || !build->domain || !build->generated ||
+	    !build->pending || !build->values || !build->internal2input ||
+	    !build->strides || !build->offsets || !build->options)
+		return isl_ast_build_free(build);
+
+	return build;
+error:
+	isl_space_free(space);
+	return isl_ast_build_free(build);
+}
+
+/* Return an isl_id called "c%d", with "%d" set to "i".
+ * If an isl_id with such a name already appears among the parameters
+ * in build->domain, then adjust the name to "c%d_%d".
+ */
+static __isl_give isl_id *generate_name(isl_ctx *ctx, int i,
+	__isl_keep isl_ast_build *build)
+{
+	int j;
+	char name[16];
+	isl_set *dom = build->domain;
+
+	snprintf(name, sizeof(name), "c%d", i);
+	j = 0;
+	while (isl_set_find_dim_by_name(dom, isl_dim_param, name) >= 0)
+		snprintf(name, sizeof(name), "c%d_%d", i, j++);
+	return isl_id_alloc(ctx, name, NULL);
+}
+
+/* Create an isl_ast_build with "set" as domain.
+ *
+ * The input set is usually a parameter domain, but we currently allow it to
+ * be any kind of set.  We set the domain of the returned isl_ast_build
+ * to "set" and initialize all the other fields to default values.
+ */
+__isl_give isl_ast_build *isl_ast_build_from_context(__isl_take isl_set *set)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_space *space;
+	isl_ast_build *build;
+
+	set = isl_set_compute_divs(set);
+	if (!set)
+		return NULL;
+
+	ctx = isl_set_get_ctx(set);
+
+	build = isl_calloc_type(ctx, isl_ast_build);
+	if (!build)
+		goto error;
+
+	build->ref = 1;
+	build->domain = set;
+	build->generated = isl_set_copy(build->domain);
+	build->pending = isl_set_universe(isl_set_get_space(build->domain));
+	build->options = isl_union_map_empty(isl_space_params_alloc(ctx, 0));
+	n = isl_set_dim(set, isl_dim_set);
+	build->depth = n;
+	build->iterators = isl_id_list_alloc(ctx, n);
+	for (i = 0; i < n; ++i) {
+		isl_id *id;
+		if (isl_set_has_dim_id(set, isl_dim_set, i))
+			id = isl_set_get_dim_id(set, isl_dim_set, i);
+		else
+			id = generate_name(ctx, i, build);
+		build->iterators = isl_id_list_add(build->iterators, id);
+	}
+	space = isl_set_get_space(set);
+	if (isl_space_is_params(space))
+		space = isl_space_set_from_params(space);
+
+	return isl_ast_build_init_derived(build, space);
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Create an isl_ast_build with a universe (parametric) context.
+ */
+__isl_give isl_ast_build *isl_ast_build_alloc(isl_ctx *ctx)
+{
+	isl_space *space;
+	isl_set *context;
+
+	space = isl_space_params_alloc(ctx, 0);
+	context = isl_set_universe(space);
+
+	return isl_ast_build_from_context(context);
+}
+
+__isl_give isl_ast_build *isl_ast_build_copy(__isl_keep isl_ast_build *build)
+{
+	if (!build)
+		return NULL;
+
+	build->ref++;
+	return build;
+}
+
+__isl_give isl_ast_build *isl_ast_build_dup(__isl_keep isl_ast_build *build)
+{
+	isl_ctx *ctx;
+	isl_ast_build *dup;
+
+	if (!build)
+		return NULL;
+
+	ctx = isl_ast_build_get_ctx(build);
+	dup = isl_calloc_type(ctx, isl_ast_build);
+	if (!dup)
+		return NULL;
+
+	dup->ref = 1;
+	dup->outer_pos = build->outer_pos;
+	dup->depth = build->depth;
+	dup->iterators = isl_id_list_copy(build->iterators);
+	dup->domain = isl_set_copy(build->domain);
+	dup->generated = isl_set_copy(build->generated);
+	dup->pending = isl_set_copy(build->pending);
+	dup->values = isl_multi_aff_copy(build->values);
+	dup->internal2input = isl_multi_aff_copy(build->internal2input);
+	dup->value = isl_pw_aff_copy(build->value);
+	dup->strides = isl_vec_copy(build->strides);
+	dup->offsets = isl_multi_aff_copy(build->offsets);
+	dup->executed = isl_union_map_copy(build->executed);
+	dup->single_valued = build->single_valued;
+	dup->options = isl_union_map_copy(build->options);
+	dup->at_each_domain = build->at_each_domain;
+	dup->at_each_domain_user = build->at_each_domain_user;
+	dup->before_each_for = build->before_each_for;
+	dup->before_each_for_user = build->before_each_for_user;
+	dup->after_each_for = build->after_each_for;
+	dup->after_each_for_user = build->after_each_for_user;
+	dup->before_each_mark = build->before_each_mark;
+	dup->before_each_mark_user = build->before_each_mark_user;
+	dup->after_each_mark = build->after_each_mark;
+	dup->after_each_mark_user = build->after_each_mark_user;
+	dup->create_leaf = build->create_leaf;
+	dup->create_leaf_user = build->create_leaf_user;
+	dup->node = isl_schedule_node_copy(build->node);
+	if (build->loop_type) {
+		int i;
+
+		dup->n = build->n;
+		dup->loop_type = isl_alloc_array(ctx,
+						enum isl_ast_loop_type, dup->n);
+		if (dup->n && !dup->loop_type)
+			return isl_ast_build_free(dup);
+		for (i = 0; i < dup->n; ++i)
+			dup->loop_type[i] = build->loop_type[i];
+	}
+
+	if (!dup->iterators || !dup->domain || !dup->generated ||
+	    !dup->pending || !dup->values ||
+	    !dup->strides || !dup->offsets || !dup->options ||
+	    (build->internal2input && !dup->internal2input) ||
+	    (build->executed && !dup->executed) ||
+	    (build->value && !dup->value) ||
+	    (build->node && !dup->node))
+		return isl_ast_build_free(dup);
+
+	return dup;
+}
+
+/* Align the parameters of "build" to those of "model", introducing
+ * additional parameters if needed.
+ */
+__isl_give isl_ast_build *isl_ast_build_align_params(
+	__isl_take isl_ast_build *build, __isl_take isl_space *model)
+{
+	build = isl_ast_build_cow(build);
+	if (!build)
+		goto error;
+
+	build->domain = isl_set_align_params(build->domain,
+						isl_space_copy(model));
+	build->generated = isl_set_align_params(build->generated,
+						isl_space_copy(model));
+	build->pending = isl_set_align_params(build->pending,
+						isl_space_copy(model));
+	build->values = isl_multi_aff_align_params(build->values,
+						isl_space_copy(model));
+	build->offsets = isl_multi_aff_align_params(build->offsets,
+						isl_space_copy(model));
+	build->options = isl_union_map_align_params(build->options,
+						isl_space_copy(model));
+	if (build->internal2input) {
+		build->internal2input =
+			isl_multi_aff_align_params(build->internal2input,
+						model);
+		if (!build->internal2input)
+			return isl_ast_build_free(build);
+	} else {
+		isl_space_free(model);
+	}
+
+	if (!build->domain || !build->values || !build->offsets ||
+	    !build->options)
+		return isl_ast_build_free(build);
+
+	return build;
+error:
+	isl_space_free(model);
+	return NULL;
+}
+
+__isl_give isl_ast_build *isl_ast_build_cow(__isl_take isl_ast_build *build)
+{
+	if (!build)
+		return NULL;
+
+	if (build->ref == 1)
+		return build;
+	build->ref--;
+	return isl_ast_build_dup(build);
+}
+
+__isl_null isl_ast_build *isl_ast_build_free(
+	__isl_take isl_ast_build *build)
+{
+	if (!build)
+		return NULL;
+
+	if (--build->ref > 0)
+		return NULL;
+
+	isl_id_list_free(build->iterators);
+	isl_set_free(build->domain);
+	isl_set_free(build->generated);
+	isl_set_free(build->pending);
+	isl_multi_aff_free(build->values);
+	isl_multi_aff_free(build->internal2input);
+	isl_pw_aff_free(build->value);
+	isl_vec_free(build->strides);
+	isl_multi_aff_free(build->offsets);
+	isl_multi_aff_free(build->schedule_map);
+	isl_union_map_free(build->executed);
+	isl_union_map_free(build->options);
+	isl_schedule_node_free(build->node);
+	free(build->loop_type);
+	isl_set_free(build->isolated);
+
+	free(build);
+
+	return NULL;
+}
+
+isl_ctx *isl_ast_build_get_ctx(__isl_keep isl_ast_build *build)
+{
+	return build ? isl_set_get_ctx(build->domain) : NULL;
+}
+
+/* Replace build->options by "options".
+ */
+__isl_give isl_ast_build *isl_ast_build_set_options(
+	__isl_take isl_ast_build *build, __isl_take isl_union_map *options)
+{
+	build = isl_ast_build_cow(build);
+
+	if (!build || !options)
+		goto error;
+
+	isl_union_map_free(build->options);
+	build->options = options;
+
+	return build;
+error:
+	isl_union_map_free(options);
+	return isl_ast_build_free(build);
+}
+
+/* Set the iterators for the next code generation.
+ *
+ * If we still have some iterators left from the previous code generation
+ * (if any) or if iterators have already been set by a previous
+ * call to this function, then we remove them first.
+ */
+__isl_give isl_ast_build *isl_ast_build_set_iterators(
+	__isl_take isl_ast_build *build, __isl_take isl_id_list *iterators)
+{
+	int dim, n_it;
+
+	build = isl_ast_build_cow(build);
+	if (!build)
+		goto error;
+
+	dim = isl_set_dim(build->domain, isl_dim_set);
+	n_it = isl_id_list_n_id(build->iterators);
+	if (n_it < dim)
+		isl_die(isl_ast_build_get_ctx(build), isl_error_internal,
+			"isl_ast_build in inconsistent state", goto error);
+	if (n_it > dim)
+		build->iterators = isl_id_list_drop(build->iterators,
+							dim, n_it - dim);
+	build->iterators = isl_id_list_concat(build->iterators, iterators);
+	if (!build->iterators)
+		return isl_ast_build_free(build);
+
+	return build;
+error:
+	isl_id_list_free(iterators);
+	return isl_ast_build_free(build);
+}
+
+/* Set the "at_each_domain" callback of "build" to "fn".
+ */
+__isl_give isl_ast_build *isl_ast_build_set_at_each_domain(
+	__isl_take isl_ast_build *build,
+	__isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node,
+		__isl_keep isl_ast_build *build, void *user), void *user)
+{
+	build = isl_ast_build_cow(build);
+
+	if (!build)
+		return NULL;
+
+	build->at_each_domain = fn;
+	build->at_each_domain_user = user;
+
+	return build;
+}
+
+/* Set the "before_each_for" callback of "build" to "fn".
+ */
+__isl_give isl_ast_build *isl_ast_build_set_before_each_for(
+	__isl_take isl_ast_build *build,
+	__isl_give isl_id *(*fn)(__isl_keep isl_ast_build *build,
+		void *user), void *user)
+{
+	build = isl_ast_build_cow(build);
+
+	if (!build)
+		return NULL;
+
+	build->before_each_for = fn;
+	build->before_each_for_user = user;
+
+	return build;
+}
+
+/* Set the "after_each_for" callback of "build" to "fn".
+ */
+__isl_give isl_ast_build *isl_ast_build_set_after_each_for(
+	__isl_take isl_ast_build *build,
+	__isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node,
+		__isl_keep isl_ast_build *build, void *user), void *user)
+{
+	build = isl_ast_build_cow(build);
+
+	if (!build)
+		return NULL;
+
+	build->after_each_for = fn;
+	build->after_each_for_user = user;
+
+	return build;
+}
+
+/* Set the "before_each_mark" callback of "build" to "fn".
+ */
+__isl_give isl_ast_build *isl_ast_build_set_before_each_mark(
+	__isl_take isl_ast_build *build,
+	isl_stat (*fn)(__isl_keep isl_id *mark, __isl_keep isl_ast_build *build,
+		void *user), void *user)
+{
+	build = isl_ast_build_cow(build);
+
+	if (!build)
+		return NULL;
+
+	build->before_each_mark = fn;
+	build->before_each_mark_user = user;
+
+	return build;
+}
+
+/* Set the "after_each_mark" callback of "build" to "fn".
+ */
+__isl_give isl_ast_build *isl_ast_build_set_after_each_mark(
+	__isl_take isl_ast_build *build,
+	__isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node,
+		__isl_keep isl_ast_build *build, void *user), void *user)
+{
+	build = isl_ast_build_cow(build);
+
+	if (!build)
+		return NULL;
+
+	build->after_each_mark = fn;
+	build->after_each_mark_user = user;
+
+	return build;
+}
+
+/* Set the "create_leaf" callback of "build" to "fn".
+ */
+__isl_give isl_ast_build *isl_ast_build_set_create_leaf(
+	__isl_take isl_ast_build *build,
+	__isl_give isl_ast_node *(*fn)(__isl_take isl_ast_build *build,
+		void *user), void *user)
+{
+	build = isl_ast_build_cow(build);
+
+	if (!build)
+		return NULL;
+
+	build->create_leaf = fn;
+	build->create_leaf_user = user;
+
+	return build;
+}
+
+/* Clear all information that is specific to this code generation
+ * and that is (probably) not meaningful to any nested code generation.
+ */
+__isl_give isl_ast_build *isl_ast_build_clear_local_info(
+	__isl_take isl_ast_build *build)
+{
+	isl_space *space;
+
+	build = isl_ast_build_cow(build);
+	if (!build)
+		return NULL;
+
+	space = isl_union_map_get_space(build->options);
+	isl_union_map_free(build->options);
+	build->options = isl_union_map_empty(space);
+
+	build->at_each_domain = NULL;
+	build->at_each_domain_user = NULL;
+	build->before_each_for = NULL;
+	build->before_each_for_user = NULL;
+	build->after_each_for = NULL;
+	build->after_each_for_user = NULL;
+	build->before_each_mark = NULL;
+	build->before_each_mark_user = NULL;
+	build->after_each_mark = NULL;
+	build->after_each_mark_user = NULL;
+	build->create_leaf = NULL;
+	build->create_leaf_user = NULL;
+
+	if (!build->options)
+		return isl_ast_build_free(build);
+
+	return build;
+}
+
+/* Have any loops been eliminated?
+ * That is, do any of the original schedule dimensions have a fixed
+ * value that has been substituted?
+ */
+static int any_eliminated(isl_ast_build *build)
+{
+	int i;
+
+	for (i = 0; i < build->depth; ++i)
+		if (isl_ast_build_has_affine_value(build, i))
+			return 1;
+
+	return 0;
+}
+
+/* Clear build->schedule_map.
+ * This function should be called whenever anything that might affect
+ * the result of isl_ast_build_get_schedule_map_multi_aff changes.
+ * In particular, it should be called when the depth is changed or
+ * when an iterator is determined to have a fixed value.
+ */
+static void isl_ast_build_reset_schedule_map(__isl_keep isl_ast_build *build)
+{
+	if (!build)
+		return;
+	isl_multi_aff_free(build->schedule_map);
+	build->schedule_map = NULL;
+}
+
+/* Do we need a (non-trivial) schedule map?
+ * That is, is the internal schedule space different from
+ * the external schedule space?
+ *
+ * The internal and external schedule spaces are only the same
+ * if code has been generated for the entire schedule and if none
+ * of the loops have been eliminated.
+ */
+__isl_give int isl_ast_build_need_schedule_map(__isl_keep isl_ast_build *build)
+{
+	int dim;
+
+	if (!build)
+		return -1;
+
+	dim = isl_set_dim(build->domain, isl_dim_set);
+	return build->depth != dim || any_eliminated(build);
+}
+
+/* Return a mapping from the internal schedule space to the external
+ * schedule space in the form of an isl_multi_aff.
+ * The internal schedule space originally corresponds to that of the
+ * input schedule.  This may change during the code generation if
+ * if isl_ast_build_insert_dim is ever called.
+ * The external schedule space corresponds to the
+ * loops that have been generated.
+ *
+ * Currently, the only difference between the internal schedule domain
+ * and the external schedule domain is that some dimensions are projected
+ * out in the external schedule domain.  In particular, the dimensions
+ * for which no code has been generated yet and the dimensions that correspond
+ * to eliminated loops.
+ *
+ * We cache a copy of the schedule_map in build->schedule_map.
+ * The cache is cleared through isl_ast_build_reset_schedule_map
+ * whenever anything changes that might affect the result of this function.
+ */
+__isl_give isl_multi_aff *isl_ast_build_get_schedule_map_multi_aff(
+	__isl_keep isl_ast_build *build)
+{
+	isl_space *space;
+	isl_multi_aff *ma;
+
+	if (!build)
+		return NULL;
+	if (build->schedule_map)
+		return isl_multi_aff_copy(build->schedule_map);
+
+	space = isl_ast_build_get_space(build, 1);
+	space = isl_space_map_from_set(space);
+	ma = isl_multi_aff_identity(space);
+	if (isl_ast_build_need_schedule_map(build)) {
+		int i;
+		int dim = isl_set_dim(build->domain, isl_dim_set);
+		ma = isl_multi_aff_drop_dims(ma, isl_dim_out,
+					build->depth, dim - build->depth);
+		for (i = build->depth - 1; i >= 0; --i)
+			if (isl_ast_build_has_affine_value(build, i))
+				ma = isl_multi_aff_drop_dims(ma,
+							isl_dim_out, i, 1);
+	}
+
+	build->schedule_map = ma;
+	return isl_multi_aff_copy(build->schedule_map);
+}
+
+/* Return a mapping from the internal schedule space to the external
+ * schedule space in the form of an isl_map.
+ */
+__isl_give isl_map *isl_ast_build_get_schedule_map(
+	__isl_keep isl_ast_build *build)
+{
+	isl_multi_aff *ma;
+
+	ma = isl_ast_build_get_schedule_map_multi_aff(build);
+	return isl_map_from_multi_aff(ma);
+}
+
+/* Return the position of the dimension in build->domain for which
+ * an AST node is currently being generated.
+ */
+int isl_ast_build_get_depth(__isl_keep isl_ast_build *build)
+{
+	return build ? build->depth : -1;
+}
+
+/* Prepare for generating code for the next level.
+ * In particular, increase the depth and reset any information
+ * that is local to the current depth.
+ */
+__isl_give isl_ast_build *isl_ast_build_increase_depth(
+	__isl_take isl_ast_build *build)
+{
+	build = isl_ast_build_cow(build);
+	if (!build)
+		return NULL;
+	build->depth++;
+	isl_ast_build_reset_schedule_map(build);
+	build->value = isl_pw_aff_free(build->value);
+	return build;
+}
+
+void isl_ast_build_dump(__isl_keep isl_ast_build *build)
+{
+	if (!build)
+		return;
+
+	fprintf(stderr, "domain: ");
+	isl_set_dump(build->domain);
+	fprintf(stderr, "generated: ");
+	isl_set_dump(build->generated);
+	fprintf(stderr, "pending: ");
+	isl_set_dump(build->pending);
+	fprintf(stderr, "iterators: ");
+	isl_id_list_dump(build->iterators);
+	fprintf(stderr, "values: ");
+	isl_multi_aff_dump(build->values);
+	if (build->value) {
+		fprintf(stderr, "value: ");
+		isl_pw_aff_dump(build->value);
+	}
+	fprintf(stderr, "strides: ");
+	isl_vec_dump(build->strides);
+	fprintf(stderr, "offsets: ");
+	isl_multi_aff_dump(build->offsets);
+	fprintf(stderr, "internal2input: ");
+	isl_multi_aff_dump(build->internal2input);
+}
+
+/* Initialize "build" for AST construction in schedule space "space"
+ * in the case that build->domain is a parameter set.
+ *
+ * build->iterators is assumed to have been updated already.
+ */
+static __isl_give isl_ast_build *isl_ast_build_init(
+	__isl_take isl_ast_build *build, __isl_take isl_space *space)
+{
+	isl_set *set;
+
+	build = isl_ast_build_cow(build);
+	if (!build)
+		goto error;
+
+	set = isl_set_universe(isl_space_copy(space));
+	build->domain = isl_set_intersect_params(isl_set_copy(set),
+						    build->domain);
+	build->pending = isl_set_intersect_params(isl_set_copy(set),
+						    build->pending);
+	build->generated = isl_set_intersect_params(set, build->generated);
+
+	return isl_ast_build_init_derived(build, space);
+error:
+	isl_ast_build_free(build);
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Assign "aff" to *user and return -1, effectively extracting
+ * the first (and presumably only) affine expression in the isl_pw_aff
+ * on which this function is used.
+ */
+static isl_stat extract_single_piece(__isl_take isl_set *set,
+	__isl_take isl_aff *aff, void *user)
+{
+	isl_aff **p = user;
+
+	*p = aff;
+	isl_set_free(set);
+
+	return isl_stat_error;
+}
+
+/* Intersect "set" with the stride constraint of "build", if any.
+ */
+static __isl_give isl_set *intersect_stride_constraint(__isl_take isl_set *set,
+	__isl_keep isl_ast_build *build)
+{
+	isl_set *stride;
+
+	if (!build)
+		return isl_set_free(set);
+	if (!isl_ast_build_has_stride(build, build->depth))
+		return set;
+
+	stride = isl_ast_build_get_stride_constraint(build);
+	return isl_set_intersect(set, stride);
+}
+
+/* Check if the given bounds on the current dimension (together with
+ * the stride constraint, if any) imply that
+ * this current dimension attains only a single value (in terms of
+ * parameters and outer dimensions).
+ * If so, we record it in build->value.
+ * If, moreover, this value can be represented as a single affine expression,
+ * then we also update build->values, effectively marking the current
+ * dimension as "eliminated".
+ *
+ * When computing the gist of the fixed value that can be represented
+ * as a single affine expression, it is important to only take into
+ * account the domain constraints in the original AST build and
+ * not the domain of the affine expression itself.
+ * Otherwise, a [i/3] is changed into a i/3 because we know that i
+ * is a multiple of 3, but then we end up not expressing anywhere
+ * in the context that i is a multiple of 3.
+ */
+static __isl_give isl_ast_build *update_values(
+	__isl_take isl_ast_build *build, __isl_take isl_basic_set *bounds)
+{
+	int sv;
+	isl_pw_multi_aff *pma;
+	isl_aff *aff = NULL;
+	isl_map *it_map;
+	isl_set *set;
+
+	set = isl_set_from_basic_set(bounds);
+	set = isl_set_intersect(set, isl_set_copy(build->domain));
+	set = intersect_stride_constraint(set, build);
+	it_map = isl_ast_build_map_to_iterator(build, set);
+
+	sv = isl_map_is_single_valued(it_map);
+	if (sv < 0)
+		build = isl_ast_build_free(build);
+	if (!build || !sv) {
+		isl_map_free(it_map);
+		return build;
+	}
+
+	pma = isl_pw_multi_aff_from_map(it_map);
+	build->value = isl_pw_multi_aff_get_pw_aff(pma, 0);
+	build->value = isl_ast_build_compute_gist_pw_aff(build, build->value);
+	build->value = isl_pw_aff_coalesce(build->value);
+	isl_pw_multi_aff_free(pma);
+
+	if (!build->value)
+		return isl_ast_build_free(build);
+
+	if (isl_pw_aff_n_piece(build->value) != 1)
+		return build;
+
+	isl_pw_aff_foreach_piece(build->value, &extract_single_piece, &aff);
+
+	build->values = isl_multi_aff_set_aff(build->values, build->depth, aff);
+	if (!build->values)
+		return isl_ast_build_free(build);
+	isl_ast_build_reset_schedule_map(build);
+	return build;
+}
+
+/* Update the AST build based on the given loop bounds for
+ * the current dimension and the stride information available in the build.
+ *
+ * We first make sure that the bounds do not refer to any iterators
+ * that have already been eliminated.
+ * Then, we check if the bounds imply that the current iterator
+ * has a fixed value.
+ * If they do and if this fixed value can be expressed as a single
+ * affine expression, we eliminate the iterators from the bounds.
+ * Note that we cannot simply plug in this single value using
+ * isl_basic_set_preimage_multi_aff as the single value may only
+ * be defined on a subset of the domain.  Plugging in the value
+ * would restrict the build domain to this subset, while this
+ * restriction may not be reflected in the generated code.
+ * Finally, we intersect build->domain with the updated bounds.
+ * We also add the stride constraint unless we have been able
+ * to find a fixed value expressed as a single affine expression.
+ *
+ * Note that the check for a fixed value in update_values requires
+ * us to intersect the bounds with the current build domain.
+ * When we intersect build->domain with the updated bounds in
+ * the final step, we make sure that these updated bounds have
+ * not been intersected with the old build->domain.
+ * Otherwise, we would indirectly intersect the build domain with itself,
+ * which can lead to inefficiencies, in particular if the build domain
+ * contains any unknown divs.
+ *
+ * The pending and generated sets are not updated by this function to
+ * match the updated domain.
+ * The caller still needs to call isl_ast_build_set_pending_generated.
+ */
+__isl_give isl_ast_build *isl_ast_build_set_loop_bounds(
+	__isl_take isl_ast_build *build, __isl_take isl_basic_set *bounds)
+{
+	isl_set *set;
+
+	build = isl_ast_build_cow(build);
+	if (!build)
+		goto error;
+
+	build = update_values(build, isl_basic_set_copy(bounds));
+	if (!build)
+		goto error;
+	set = isl_set_from_basic_set(isl_basic_set_copy(bounds));
+	if (isl_ast_build_has_affine_value(build, build->depth)) {
+		set = isl_set_eliminate(set, isl_dim_set, build->depth, 1);
+		set = isl_set_compute_divs(set);
+		build->pending = isl_set_intersect(build->pending,
+							isl_set_copy(set));
+		build->domain = isl_set_intersect(build->domain, set);
+	} else {
+		build->domain = isl_set_intersect(build->domain, set);
+		build = isl_ast_build_include_stride(build);
+		if (!build)
+			goto error;
+	}
+	isl_basic_set_free(bounds);
+
+	if (!build->domain || !build->pending || !build->generated)
+		return isl_ast_build_free(build);
+
+	return build;
+error:
+	isl_ast_build_free(build);
+	isl_basic_set_free(bounds);
+	return NULL;
+}
+
+/* Update the pending and generated sets of "build" according to "bounds".
+ * If the build has an affine value at the current depth,
+ * then isl_ast_build_set_loop_bounds has already set the pending set.
+ * Otherwise, do it here.
+ */
+__isl_give isl_ast_build *isl_ast_build_set_pending_generated(
+	__isl_take isl_ast_build *build, __isl_take isl_basic_set *bounds)
+{
+	isl_basic_set *generated, *pending;
+
+	if (!build)
+		goto error;
+
+	if (isl_ast_build_has_affine_value(build, build->depth)) {
+		isl_basic_set_free(bounds);
+		return build;
+	}
+
+	build = isl_ast_build_cow(build);
+	if (!build)
+		goto error;
+
+	pending = isl_basic_set_copy(bounds);
+	pending = isl_basic_set_drop_constraints_involving_dims(pending,
+				isl_dim_set, build->depth, 1);
+	build->pending = isl_set_intersect(build->pending,
+				isl_set_from_basic_set(pending));
+	generated = bounds;
+	generated = isl_basic_set_drop_constraints_not_involving_dims(
+			    generated, isl_dim_set, build->depth, 1);
+	build->generated = isl_set_intersect(build->generated,
+				isl_set_from_basic_set(generated));
+
+	if (!build->pending || !build->generated)
+		return isl_ast_build_free(build);
+
+	return build;
+error:
+	isl_ast_build_free(build);
+	isl_basic_set_free(bounds);
+	return NULL;
+}
+
+/* Intersect build->domain with "set", where "set" is specified
+ * in terms of the internal schedule domain.
+ */
+static __isl_give isl_ast_build *isl_ast_build_restrict_internal(
+	__isl_take isl_ast_build *build, __isl_take isl_set *set)
+{
+	build = isl_ast_build_cow(build);
+	if (!build)
+		goto error;
+
+	set = isl_set_compute_divs(set);
+	build->domain = isl_set_intersect(build->domain, set);
+	build->domain = isl_set_coalesce(build->domain);
+
+	if (!build->domain)
+		return isl_ast_build_free(build);
+
+	return build;
+error:
+	isl_ast_build_free(build);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Intersect build->generated and build->domain with "set",
+ * where "set" is specified in terms of the internal schedule domain.
+ */
+__isl_give isl_ast_build *isl_ast_build_restrict_generated(
+	__isl_take isl_ast_build *build, __isl_take isl_set *set)
+{
+	set = isl_set_compute_divs(set);
+	build = isl_ast_build_restrict_internal(build, isl_set_copy(set));
+	build = isl_ast_build_cow(build);
+	if (!build)
+		goto error;
+
+	build->generated = isl_set_intersect(build->generated, set);
+	build->generated = isl_set_coalesce(build->generated);
+
+	if (!build->generated)
+		return isl_ast_build_free(build);
+
+	return build;
+error:
+	isl_ast_build_free(build);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Replace the set of pending constraints by "guard", which is then
+ * no longer considered as pending.
+ * That is, add "guard" to the generated constraints and clear all pending
+ * constraints, making the domain equal to the generated constraints.
+ */
+__isl_give isl_ast_build *isl_ast_build_replace_pending_by_guard(
+	__isl_take isl_ast_build *build, __isl_take isl_set *guard)
+{
+	build = isl_ast_build_restrict_generated(build, guard);
+	build = isl_ast_build_cow(build);
+	if (!build)
+		return NULL;
+
+	isl_set_free(build->domain);
+	build->domain = isl_set_copy(build->generated);
+	isl_set_free(build->pending);
+	build->pending = isl_set_universe(isl_set_get_space(build->domain));
+
+	if (!build->pending)
+		return isl_ast_build_free(build);
+
+	return build;
+}
+
+/* Intersect build->domain with "set", where "set" is specified
+ * in terms of the external schedule domain.
+ */
+__isl_give isl_ast_build *isl_ast_build_restrict(
+	__isl_take isl_ast_build *build, __isl_take isl_set *set)
+{
+	if (isl_set_is_params(set))
+		return isl_ast_build_restrict_generated(build, set);
+
+	if (isl_ast_build_need_schedule_map(build)) {
+		isl_multi_aff *ma;
+		ma = isl_ast_build_get_schedule_map_multi_aff(build);
+		set = isl_set_preimage_multi_aff(set, ma);
+	}
+	return isl_ast_build_restrict_generated(build, set);
+}
+
+/* Replace build->executed by "executed".
+ */
+__isl_give isl_ast_build *isl_ast_build_set_executed(
+	__isl_take isl_ast_build *build, __isl_take isl_union_map *executed)
+{
+	build = isl_ast_build_cow(build);
+	if (!build)
+		goto error;
+
+	isl_union_map_free(build->executed);
+	build->executed = executed;
+
+	return build;
+error:
+	isl_ast_build_free(build);
+	isl_union_map_free(executed);
+	return NULL;
+}
+
+/* Does "build" point to a band node?
+ * That is, are we currently handling a band node inside a schedule tree?
+ */
+int isl_ast_build_has_schedule_node(__isl_keep isl_ast_build *build)
+{
+	if (!build)
+		return -1;
+	return build->node != NULL;
+}
+
+/* Return a copy of the band node that "build" refers to.
+ */
+__isl_give isl_schedule_node *isl_ast_build_get_schedule_node(
+	__isl_keep isl_ast_build *build)
+{
+	if (!build)
+		return NULL;
+	return isl_schedule_node_copy(build->node);
+}
+
+/* Extract the loop AST generation types for the members of build->node
+ * and store them in build->loop_type.
+ */
+static __isl_give isl_ast_build *extract_loop_types(
+	__isl_take isl_ast_build *build)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_schedule_node *node;
+
+	if (!build)
+		return NULL;
+	ctx = isl_ast_build_get_ctx(build);
+	if (!build->node)
+		isl_die(ctx, isl_error_internal, "missing AST node",
+			return isl_ast_build_free(build));
+
+	free(build->loop_type);
+	build->n = isl_schedule_node_band_n_member(build->node);
+	build->loop_type = isl_alloc_array(ctx,
+					    enum isl_ast_loop_type, build->n);
+	if (build->n && !build->loop_type)
+		return isl_ast_build_free(build);
+	node = build->node;
+	for (i = 0; i < build->n; ++i)
+		build->loop_type[i] =
+		    isl_schedule_node_band_member_get_ast_loop_type(node, i);
+
+	return build;
+}
+
+/* Replace the band node that "build" refers to by "node" and
+ * extract the corresponding loop AST generation types.
+ */
+__isl_give isl_ast_build *isl_ast_build_set_schedule_node(
+	__isl_take isl_ast_build *build,
+	__isl_take isl_schedule_node *node)
+{
+	build = isl_ast_build_cow(build);
+	if (!build || !node)
+		goto error;
+
+	isl_schedule_node_free(build->node);
+	build->node = node;
+
+	build = extract_loop_types(build);
+
+	return build;
+error:
+	isl_ast_build_free(build);
+	isl_schedule_node_free(node);
+	return NULL;
+}
+
+/* Remove any reference to a band node from "build".
+ */
+__isl_give isl_ast_build *isl_ast_build_reset_schedule_node(
+	__isl_take isl_ast_build *build)
+{
+	build = isl_ast_build_cow(build);
+	if (!build)
+		return NULL;
+
+	isl_schedule_node_free(build->node);
+	build->node = NULL;
+
+	return build;
+}
+
+/* Return a copy of the current schedule domain.
+ */
+__isl_give isl_set *isl_ast_build_get_domain(__isl_keep isl_ast_build *build)
+{
+	return build ? isl_set_copy(build->domain) : NULL;
+}
+
+/* Return a copy of the set of pending constraints.
+ */
+__isl_give isl_set *isl_ast_build_get_pending(
+	__isl_keep isl_ast_build *build)
+{
+	return build ? isl_set_copy(build->pending) : NULL;
+}
+
+/* Return a copy of the set of generated constraints.
+ */
+__isl_give isl_set *isl_ast_build_get_generated(
+	__isl_keep isl_ast_build *build)
+{
+	return build ? isl_set_copy(build->generated) : NULL;
+}
+
+/* Return a copy of the map from the internal schedule domain
+ * to the original input schedule domain.
+ */
+__isl_give isl_multi_aff *isl_ast_build_get_internal2input(
+	__isl_keep isl_ast_build *build)
+{
+	return build ? isl_multi_aff_copy(build->internal2input) : NULL;
+}
+
+/* Return the number of variables of the given type
+ * in the (internal) schedule space.
+ */
+unsigned isl_ast_build_dim(__isl_keep isl_ast_build *build,
+	enum isl_dim_type type)
+{
+	if (!build)
+		return 0;
+	return isl_set_dim(build->domain, type);
+}
+
+/* Return the (schedule) space of "build".
+ *
+ * If "internal" is set, then this space is the space of the internal
+ * representation of the entire schedule, including those parts for
+ * which no code has been generated yet.
+ *
+ * If "internal" is not set, then this space is the external representation
+ * of the loops generated so far.
+ */
+__isl_give isl_space *isl_ast_build_get_space(__isl_keep isl_ast_build *build,
+	int internal)
+{
+	int i;
+	int dim;
+	isl_space *space;
+
+	if (!build)
+		return NULL;
+
+	space = isl_set_get_space(build->domain);
+	if (internal)
+		return space;
+
+	if (!isl_ast_build_need_schedule_map(build))
+		return space;
+
+	dim = isl_set_dim(build->domain, isl_dim_set);
+	space = isl_space_drop_dims(space, isl_dim_set,
+				    build->depth, dim - build->depth);
+	for (i = build->depth - 1; i >= 0; --i)
+		if (isl_ast_build_has_affine_value(build, i))
+			space = isl_space_drop_dims(space, isl_dim_set, i, 1);
+
+	return space;
+}
+
+/* Return the external representation of the schedule space of "build",
+ * i.e., a space with a dimension for each loop generated so far,
+ * with the names of the dimensions set to the loop iterators.
+ */
+__isl_give isl_space *isl_ast_build_get_schedule_space(
+	__isl_keep isl_ast_build *build)
+{
+	isl_space *space;
+	int i, skip;
+
+	if (!build)
+		return NULL;
+
+	space = isl_ast_build_get_space(build, 0);
+
+	skip = 0;
+	for (i = 0; i < build->depth; ++i) {
+		isl_id *id;
+
+		if (isl_ast_build_has_affine_value(build, i)) {
+			skip++;
+			continue;
+		}
+
+		id = isl_ast_build_get_iterator_id(build, i);
+		space = isl_space_set_dim_id(space, isl_dim_set, i - skip, id);
+	}
+
+	return space;
+}
+
+/* Return the current schedule, as stored in build->executed, in terms
+ * of the external schedule domain.
+ */
+__isl_give isl_union_map *isl_ast_build_get_schedule(
+	__isl_keep isl_ast_build *build)
+{
+	isl_union_map *executed;
+	isl_union_map *schedule;
+
+	if (!build)
+		return NULL;
+
+	executed = isl_union_map_copy(build->executed);
+	if (isl_ast_build_need_schedule_map(build)) {
+		isl_map *proj = isl_ast_build_get_schedule_map(build);
+		executed = isl_union_map_apply_domain(executed,
+					isl_union_map_from_map(proj));
+	}
+	schedule = isl_union_map_reverse(executed);
+
+	return schedule;
+}
+
+/* Return the iterator attached to the internal schedule dimension "pos".
+ */
+__isl_give isl_id *isl_ast_build_get_iterator_id(
+	__isl_keep isl_ast_build *build, int pos)
+{
+	if (!build)
+		return NULL;
+
+	return isl_id_list_get_id(build->iterators, pos);
+}
+
+/* Set the stride and offset of the current dimension to the given
+ * value and expression.
+ *
+ * If we had already found a stride before, then the two strides
+ * are combined into a single stride.
+ *
+ * In particular, if the new stride information is of the form
+ *
+ *	i = f + s (...)
+ *
+ * and the old stride information is of the form
+ *
+ *	i = f2 + s2 (...)
+ *
+ * then we compute the extended gcd of s and s2
+ *
+ *	a s + b s2 = g,
+ *
+ * with g = gcd(s,s2), multiply the first equation with t1 = b s2/g
+ * and the second with t2 = a s1/g.
+ * This results in
+ *
+ *	i = (b s2 + a s1)/g i = t1 f + t2 f2 + (s s2)/g (...)
+ *
+ * so that t1 f + t2 f2 is the combined offset and (s s2)/g = lcm(s,s2)
+ * is the combined stride.
+ */
+static __isl_give isl_ast_build *set_stride(__isl_take isl_ast_build *build,
+	__isl_take isl_val *stride, __isl_take isl_aff *offset)
+{
+	int pos;
+
+	build = isl_ast_build_cow(build);
+	if (!build || !stride || !offset)
+		goto error;
+
+	pos = build->depth;
+
+	if (isl_ast_build_has_stride(build, pos)) {
+		isl_val *stride2, *a, *b, *g;
+		isl_aff *offset2;
+
+		stride2 = isl_vec_get_element_val(build->strides, pos);
+		g = isl_val_gcdext(isl_val_copy(stride), isl_val_copy(stride2),
+					&a, &b);
+		a = isl_val_mul(a, isl_val_copy(stride));
+		a = isl_val_div(a, isl_val_copy(g));
+		stride2 = isl_val_div(stride2, g);
+		b = isl_val_mul(b, isl_val_copy(stride2));
+		stride = isl_val_mul(stride, stride2);
+
+		offset2 = isl_multi_aff_get_aff(build->offsets, pos);
+		offset2 = isl_aff_scale_val(offset2, a);
+		offset = isl_aff_scale_val(offset, b);
+		offset = isl_aff_add(offset, offset2);
+	}
+
+	build->strides = isl_vec_set_element_val(build->strides, pos, stride);
+	build->offsets = isl_multi_aff_set_aff(build->offsets, pos, offset);
+	if (!build->strides || !build->offsets)
+		return isl_ast_build_free(build);
+
+	return build;
+error:
+	isl_val_free(stride);
+	isl_aff_free(offset);
+	return isl_ast_build_free(build);
+}
+
+/* Return a set expressing the stride constraint at the current depth.
+ *
+ * In particular, if the current iterator (i) is known to attain values
+ *
+ *	f + s a
+ *
+ * where f is the offset and s is the stride, then the returned set
+ * expresses the constraint
+ *
+ *	(f - i) mod s = 0
+ */
+__isl_give isl_set *isl_ast_build_get_stride_constraint(
+	__isl_keep isl_ast_build *build)
+{
+	isl_aff *aff;
+	isl_set *set;
+	isl_val *stride;
+	int pos;
+
+	if (!build)
+		return NULL;
+
+	pos = build->depth;
+
+	if (!isl_ast_build_has_stride(build, pos))
+		return isl_set_universe(isl_ast_build_get_space(build, 1));
+
+	stride = isl_ast_build_get_stride(build, pos);
+	aff = isl_ast_build_get_offset(build, pos);
+	aff = isl_aff_add_coefficient_si(aff, isl_dim_in, pos, -1);
+	aff = isl_aff_mod_val(aff, stride);
+	set = isl_set_from_basic_set(isl_aff_zero_basic_set(aff));
+
+	return set;
+}
+
+/* Return the expansion implied by the stride and offset at the current
+ * depth.
+ *
+ * That is, return the mapping
+ *
+ *	[i_0, ..., i_{d-1}, i_d, i_{d+1}, ...]
+ *		-> [i_0, ..., i_{d-1}, s * i_d + offset(i),  i_{d+1}, ...]
+ *
+ * where s is the stride at the current depth d and offset(i) is
+ * the corresponding offset.
+ */
+__isl_give isl_multi_aff *isl_ast_build_get_stride_expansion(
+	__isl_keep isl_ast_build *build)
+{
+	isl_space *space;
+	isl_multi_aff *ma;
+	int pos;
+	isl_aff *aff, *offset;
+	isl_val *stride;
+
+	if (!build)
+		return NULL;
+
+	pos = isl_ast_build_get_depth(build);
+	space = isl_ast_build_get_space(build, 1);
+	space = isl_space_map_from_set(space);
+	ma = isl_multi_aff_identity(space);
+
+	if (!isl_ast_build_has_stride(build, pos))
+		return ma;
+
+	offset = isl_ast_build_get_offset(build, pos);
+	stride = isl_ast_build_get_stride(build, pos);
+	aff = isl_multi_aff_get_aff(ma, pos);
+	aff = isl_aff_scale_val(aff, stride);
+	aff = isl_aff_add(aff, offset);
+	ma = isl_multi_aff_set_aff(ma, pos, aff);
+
+	return ma;
+}
+
+/* Add constraints corresponding to any previously detected
+ * stride on the current dimension to build->domain.
+ */
+__isl_give isl_ast_build *isl_ast_build_include_stride(
+	__isl_take isl_ast_build *build)
+{
+	isl_set *set;
+
+	if (!build)
+		return NULL;
+	if (!isl_ast_build_has_stride(build, build->depth))
+		return build;
+	build = isl_ast_build_cow(build);
+	if (!build)
+		return NULL;
+
+	set = isl_ast_build_get_stride_constraint(build);
+
+	build->domain = isl_set_intersect(build->domain, isl_set_copy(set));
+	build->generated = isl_set_intersect(build->generated, set);
+	if (!build->domain || !build->generated)
+		return isl_ast_build_free(build);
+
+	return build;
+}
+
+/* Information used inside detect_stride.
+ *
+ * "build" may be updated by detect_stride to include stride information.
+ * "pos" is equal to build->depth.
+ */
+struct isl_detect_stride_data {
+	isl_ast_build *build;
+	int pos;
+};
+
+/* Check if constraint "c" imposes any stride on dimension data->pos
+ * and, if so, update the stride information in data->build.
+ *
+ * In order to impose a stride on the dimension, "c" needs to be an equality
+ * and it needs to involve the dimension.  Note that "c" may also be
+ * a div constraint and thus an inequality that we cannot use.
+ *
+ * Let c be of the form
+ *
+ *	h(p) + g * v * i + g * stride * f(alpha) = 0
+ *
+ * with h(p) an expression in terms of the parameters and outer dimensions
+ * and f(alpha) an expression in terms of the existentially quantified
+ * variables.  Note that the inner dimensions have been eliminated so
+ * they do not appear in "c".
+ *
+ * If "stride" is not zero and not one, then it represents a non-trivial stride
+ * on "i".  We compute a and b such that
+ *
+ *	a v + b stride = 1
+ *
+ * We have
+ *
+ *	g v i = -h(p) + g stride f(alpha)
+ *
+ *	a g v i = -a h(p) + g stride f(alpha)
+ *
+ *	a g v i + b g stride i = -a h(p) + g stride * (...)
+ *
+ *	g i = -a h(p) + g stride * (...)
+ *
+ *	i = -a h(p)/g + stride * (...)
+ *
+ * The expression "-a h(p)/g" can therefore be used as offset.
+ */
+static isl_stat detect_stride(__isl_take isl_constraint *c, void *user)
+{
+	struct isl_detect_stride_data *data = user;
+	int i, n_div;
+	isl_ctx *ctx;
+	isl_val *v, *stride, *m;
+
+	if (!isl_constraint_is_equality(c) ||
+	    !isl_constraint_involves_dims(c, isl_dim_set, data->pos, 1)) {
+		isl_constraint_free(c);
+		return isl_stat_ok;
+	}
+
+	ctx = isl_constraint_get_ctx(c);
+	stride = isl_val_zero(ctx);
+	n_div = isl_constraint_dim(c, isl_dim_div);
+	for (i = 0; i < n_div; ++i) {
+		v = isl_constraint_get_coefficient_val(c, isl_dim_div, i);
+		stride = isl_val_gcd(stride, v);
+	}
+
+	v = isl_constraint_get_coefficient_val(c, isl_dim_set, data->pos);
+	m = isl_val_gcd(isl_val_copy(stride), isl_val_copy(v));
+	stride = isl_val_div(stride, isl_val_copy(m));
+	v = isl_val_div(v, isl_val_copy(m));
+
+	if (!isl_val_is_zero(stride) && !isl_val_is_one(stride)) {
+		isl_aff *aff;
+		isl_val *gcd, *a, *b;
+
+		gcd = isl_val_gcdext(v, isl_val_copy(stride), &a, &b);
+		isl_val_free(gcd);
+		isl_val_free(b);
+
+		aff = isl_constraint_get_aff(c);
+		for (i = 0; i < n_div; ++i)
+			aff = isl_aff_set_coefficient_si(aff,
+							 isl_dim_div, i, 0);
+		aff = isl_aff_set_coefficient_si(aff, isl_dim_in, data->pos, 0);
+		a = isl_val_neg(a);
+		aff = isl_aff_scale_val(aff, a);
+		aff = isl_aff_scale_down_val(aff, m);
+		data->build = set_stride(data->build, stride, aff);
+	} else {
+		isl_val_free(stride);
+		isl_val_free(m);
+		isl_val_free(v);
+	}
+
+	isl_constraint_free(c);
+	return isl_stat_ok;
+}
+
+/* Check if the constraints in "set" imply any stride on the current
+ * dimension and, if so, record the stride information in "build"
+ * and return the updated "build".
+ *
+ * We compute the affine hull and then check if any of the constraints
+ * in the hull imposes any stride on the current dimension.
+ *
+ * We assume that inner dimensions have been eliminated from "set"
+ * by the caller.  This is needed because the common stride
+ * may be imposed by different inner dimensions on different parts of
+ * the domain.
+ */
+__isl_give isl_ast_build *isl_ast_build_detect_strides(
+	__isl_take isl_ast_build *build, __isl_take isl_set *set)
+{
+	isl_basic_set *hull;
+	struct isl_detect_stride_data data;
+
+	if (!build)
+		goto error;
+
+	data.build = build;
+	data.pos = isl_ast_build_get_depth(build);
+	hull = isl_set_affine_hull(set);
+
+	if (isl_basic_set_foreach_constraint(hull, &detect_stride, &data) < 0)
+		data.build = isl_ast_build_free(data.build);
+
+	isl_basic_set_free(hull);
+	return data.build;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+struct isl_ast_build_involves_data {
+	int depth;
+	int involves;
+};
+
+/* Check if "map" involves the input dimension data->depth.
+ */
+static isl_stat involves_depth(__isl_take isl_map *map, void *user)
+{
+	struct isl_ast_build_involves_data *data = user;
+
+	data->involves = isl_map_involves_dims(map, isl_dim_in, data->depth, 1);
+	isl_map_free(map);
+
+	if (data->involves < 0 || data->involves)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Do any options depend on the value of the dimension at the current depth?
+ */
+int isl_ast_build_options_involve_depth(__isl_keep isl_ast_build *build)
+{
+	struct isl_ast_build_involves_data data;
+
+	if (!build)
+		return -1;
+
+	data.depth = build->depth;
+	data.involves = 0;
+
+	if (isl_union_map_foreach_map(build->options,
+					&involves_depth, &data) < 0) {
+		if (data.involves < 0 || !data.involves)
+			return -1;
+	}
+
+	return data.involves;
+}
+
+/* Construct the map
+ *
+ *	{ [i] -> [i] : i < pos; [i] -> [i + 1] : i >= pos }
+ *
+ * with "space" the parameter space of the constructed map.
+ */
+static __isl_give isl_map *construct_insertion_map(__isl_take isl_space *space,
+	int pos)
+{
+	isl_constraint *c;
+	isl_basic_map *bmap1, *bmap2;
+
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, 1);
+	space = isl_space_map_from_set(space);
+	c = isl_constraint_alloc_equality(isl_local_space_from_space(space));
+	c = isl_constraint_set_coefficient_si(c, isl_dim_in, 0, 1);
+	c = isl_constraint_set_coefficient_si(c, isl_dim_out, 0, -1);
+	bmap1 = isl_basic_map_from_constraint(isl_constraint_copy(c));
+	c = isl_constraint_set_constant_si(c, 1);
+	bmap2 = isl_basic_map_from_constraint(c);
+
+	bmap1 = isl_basic_map_upper_bound_si(bmap1, isl_dim_in, 0, pos - 1);
+	bmap2 = isl_basic_map_lower_bound_si(bmap2, isl_dim_in, 0, pos);
+
+	return isl_basic_map_union(bmap1, bmap2);
+}
+
+static const char *option_str[] = {
+	[isl_ast_loop_atomic] = "atomic",
+	[isl_ast_loop_unroll] = "unroll",
+	[isl_ast_loop_separate] = "separate"
+};
+
+/* Update the "options" to reflect the insertion of a dimension
+ * at position "pos" in the schedule domain space.
+ * "space" is the original domain space before the insertion and
+ * may be named and/or structured.
+ *
+ * The (relevant) input options all have "space" as domain, which
+ * has to be mapped to the extended space.
+ * The values of the ranges also refer to the schedule domain positions
+ * and they therefore also need to be adjusted.  In particular, values
+ * smaller than pos do not need to change, while values greater than or
+ * equal to pos need to be incremented.
+ * That is, we need to apply the following map.
+ *
+ *	{ atomic[i] -> atomic[i] : i < pos; [i] -> [i + 1] : i >= pos;
+ *	  unroll[i] -> unroll[i] : i < pos; [i] -> [i + 1] : i >= pos;
+ *	  separate[i] -> separate[i] : i < pos; [i] -> [i + 1] : i >= pos;
+ *	  separation_class[[i] -> [c]]
+ *		-> separation_class[[i] -> [c]] : i < pos;
+ *	  separation_class[[i] -> [c]]
+ *		-> separation_class[[i + 1] -> [c]] : i >= pos }
+ */
+static __isl_give isl_union_map *options_insert_dim(
+	__isl_take isl_union_map *options, __isl_take isl_space *space, int pos)
+{
+	isl_map *map;
+	isl_union_map *insertion;
+	enum isl_ast_loop_type type;
+	const char *name = "separation_class";
+
+	space = isl_space_map_from_set(space);
+	map = isl_map_identity(space);
+	map = isl_map_insert_dims(map, isl_dim_out, pos, 1);
+	options = isl_union_map_apply_domain(options,
+						isl_union_map_from_map(map));
+
+	if (!options)
+		return NULL;
+
+	map = construct_insertion_map(isl_union_map_get_space(options), pos);
+
+	insertion = isl_union_map_empty(isl_union_map_get_space(options));
+
+	for (type = isl_ast_loop_atomic;
+	    type <= isl_ast_loop_separate; ++type) {
+		isl_map *map_type = isl_map_copy(map);
+		const char *name = option_str[type];
+		map_type = isl_map_set_tuple_name(map_type, isl_dim_in, name);
+		map_type = isl_map_set_tuple_name(map_type, isl_dim_out, name);
+		insertion = isl_union_map_add_map(insertion, map_type);
+	}
+
+	map = isl_map_product(map, isl_map_identity(isl_map_get_space(map)));
+	map = isl_map_set_tuple_name(map, isl_dim_in, name);
+	map = isl_map_set_tuple_name(map, isl_dim_out, name);
+	insertion = isl_union_map_add_map(insertion, map);
+
+	options = isl_union_map_apply_range(options, insertion);
+
+	return options;
+}
+
+/* If we are generating an AST from a schedule tree (build->node is set),
+ * then update the loop AST generation types
+ * to reflect the insertion of a dimension at (global) position "pos"
+ * in the schedule domain space.
+ * We do not need to adjust any isolate option since we would not be inserting
+ * any dimensions if there were any isolate option.
+ */
+static __isl_give isl_ast_build *node_insert_dim(
+	__isl_take isl_ast_build *build, int pos)
+{
+	int i;
+	int local_pos;
+	enum isl_ast_loop_type *loop_type;
+	isl_ctx *ctx;
+
+	build = isl_ast_build_cow(build);
+	if (!build)
+		return NULL;
+	if (!build->node)
+		return build;
+
+	ctx = isl_ast_build_get_ctx(build);
+	local_pos = pos - build->outer_pos;
+	loop_type = isl_realloc_array(ctx, build->loop_type,
+					enum isl_ast_loop_type, build->n + 1);
+	if (!loop_type)
+		return isl_ast_build_free(build);
+	build->loop_type = loop_type;
+	for (i = build->n - 1; i >= local_pos; --i)
+		loop_type[i + 1] = loop_type[i];
+	loop_type[local_pos] = isl_ast_loop_default;
+	build->n++;
+
+	return build;
+}
+
+/* Insert a single dimension in the schedule domain at position "pos".
+ * The new dimension is given an isl_id with the empty string as name.
+ *
+ * The main difficulty is updating build->options to reflect the
+ * extra dimension.  This is handled in options_insert_dim.
+ *
+ * Note that because of the dimension manipulations, the resulting
+ * schedule domain space will always be unnamed and unstructured.
+ * However, the original schedule domain space may be named and/or
+ * structured, so we have to take this possibility into account
+ * while performing the transformations.
+ *
+ * Since the inserted schedule dimension is used by the caller
+ * to differentiate between different domain spaces, there is
+ * no longer a uniform mapping from the internal schedule space
+ * to the input schedule space.  The internal2input mapping is
+ * therefore removed.
+ */
+__isl_give isl_ast_build *isl_ast_build_insert_dim(
+	__isl_take isl_ast_build *build, int pos)
+{
+	isl_ctx *ctx;
+	isl_space *space, *ma_space;
+	isl_id *id;
+	isl_multi_aff *ma;
+
+	build = isl_ast_build_cow(build);
+	if (!build)
+		return NULL;
+
+	ctx = isl_ast_build_get_ctx(build);
+	id = isl_id_alloc(ctx, "", NULL);
+	if (!build->node)
+		space = isl_ast_build_get_space(build, 1);
+	build->iterators = isl_id_list_insert(build->iterators, pos, id);
+	build->domain = isl_set_insert_dims(build->domain,
+						isl_dim_set, pos, 1);
+	build->generated = isl_set_insert_dims(build->generated,
+						isl_dim_set, pos, 1);
+	build->pending = isl_set_insert_dims(build->pending,
+						isl_dim_set, pos, 1);
+	build->strides = isl_vec_insert_els(build->strides, pos, 1);
+	build->strides = isl_vec_set_element_si(build->strides, pos, 1);
+	ma_space = isl_space_params(isl_multi_aff_get_space(build->offsets));
+	ma_space = isl_space_set_from_params(ma_space);
+	ma_space = isl_space_add_dims(ma_space, isl_dim_set, 1);
+	ma_space = isl_space_map_from_set(ma_space);
+	ma = isl_multi_aff_zero(isl_space_copy(ma_space));
+	build->offsets = isl_multi_aff_splice(build->offsets, pos, pos, ma);
+	ma = isl_multi_aff_identity(ma_space);
+	build->values = isl_multi_aff_splice(build->values, pos, pos, ma);
+	if (!build->node)
+		build->options = options_insert_dim(build->options, space, pos);
+	build->internal2input = isl_multi_aff_free(build->internal2input);
+
+	if (!build->iterators || !build->domain || !build->generated ||
+	    !build->pending || !build->values ||
+	    !build->strides || !build->offsets || !build->options)
+		return isl_ast_build_free(build);
+
+	build = node_insert_dim(build, pos);
+
+	return build;
+}
+
+/* Scale down the current dimension by a factor of "m".
+ * "umap" is an isl_union_map that implements the scaling down.
+ * That is, it is of the form
+ *
+ *	{ [.... i ....] -> [.... i' ....] : i = m i' }
+ *
+ * This function is called right after the strides have been
+ * detected, but before any constraints on the current dimension
+ * have been included in build->domain.
+ * We therefore only need to update stride, offset, the options and
+ * the mapping from internal schedule space to the original schedule
+ * space, if we are still keeping track of such a mapping.
+ * The latter mapping is updated by plugging in
+ * { [... i ...] -> [... m i ... ] }.
+ */
+__isl_give isl_ast_build *isl_ast_build_scale_down(
+	__isl_take isl_ast_build *build, __isl_take isl_val *m,
+	__isl_take isl_union_map *umap)
+{
+	isl_aff *aff;
+	isl_val *v;
+	int depth;
+
+	build = isl_ast_build_cow(build);
+	if (!build || !umap || !m)
+		goto error;
+
+	depth = build->depth;
+
+	if (build->internal2input) {
+		isl_space *space;
+		isl_multi_aff *ma;
+		isl_aff *aff;
+
+		space = isl_multi_aff_get_space(build->internal2input);
+		space = isl_space_map_from_set(isl_space_domain(space));
+		ma = isl_multi_aff_identity(space);
+		aff = isl_multi_aff_get_aff(ma, depth);
+		aff = isl_aff_scale_val(aff, isl_val_copy(m));
+		ma = isl_multi_aff_set_aff(ma, depth, aff);
+		build->internal2input =
+		    isl_multi_aff_pullback_multi_aff(build->internal2input, ma);
+		if (!build->internal2input)
+			goto error;
+	}
+
+	v = isl_vec_get_element_val(build->strides, depth);
+	v = isl_val_div(v, isl_val_copy(m));
+	build->strides = isl_vec_set_element_val(build->strides, depth, v);
+
+	aff = isl_multi_aff_get_aff(build->offsets, depth);
+	aff = isl_aff_scale_down_val(aff, m);
+	build->offsets = isl_multi_aff_set_aff(build->offsets, depth, aff);
+	build->options = isl_union_map_apply_domain(build->options, umap);
+	if (!build->strides || !build->offsets || !build->options)
+		return isl_ast_build_free(build);
+
+	return build;
+error:
+	isl_val_free(m);
+	isl_union_map_free(umap);
+	return isl_ast_build_free(build);
+}
+
+/* Return a list of "n" isl_ids called "c%d", with "%d" starting at "first".
+ * If an isl_id with such a name already appears among the parameters
+ * in build->domain, then adjust the name to "c%d_%d".
+ */
+static __isl_give isl_id_list *generate_names(isl_ctx *ctx, int n, int first,
+	__isl_keep isl_ast_build *build)
+{
+	int i;
+	isl_id_list *names;
+
+	names = isl_id_list_alloc(ctx, n);
+	for (i = 0; i < n; ++i) {
+		isl_id *id;
+
+		id = generate_name(ctx, first + i, build);
+		names = isl_id_list_add(names, id);
+	}
+
+	return names;
+}
+
+/* Embed "options" into the given isl_ast_build space.
+ *
+ * This function is called from within a nested call to
+ * isl_ast_build_node_from_schedule_map.
+ * "options" refers to the additional schedule,
+ * while space refers to both the space of the outer isl_ast_build and
+ * that of the additional schedule.
+ * Specifically, space is of the form
+ *
+ *	[I -> S]
+ *
+ * while options lives in the space(s)
+ *
+ *	S -> *
+ *
+ * We compute
+ *
+ *	[I -> S] -> S
+ *
+ * and compose this with options, to obtain the new options
+ * living in the space(s)
+ *
+ *	[I -> S] -> *
+ */
+static __isl_give isl_union_map *embed_options(
+	__isl_take isl_union_map *options, __isl_take isl_space *space)
+{
+	isl_map *map;
+
+	map = isl_map_universe(isl_space_unwrap(space));
+	map = isl_map_range_map(map);
+
+	options = isl_union_map_apply_range(
+				isl_union_map_from_map(map), options);
+
+	return options;
+}
+
+/* Update "build" for use in a (possibly nested) code generation.  That is,
+ * extend "build" from an AST build on some domain O to an AST build
+ * on domain [O -> S], with S corresponding to "space".
+ * If the original domain is a parameter domain, then the new domain is
+ * simply S.
+ * "iterators" is a list of iterators for S, but the number of elements
+ * may be smaller or greater than the number of set dimensions of S.
+ * If "keep_iterators" is set, then any extra ids in build->iterators
+ * are reused for S.  Otherwise, these extra ids are dropped.
+ *
+ * We first update build->outer_pos to the current depth.
+ * This depth is zero in case this is the outermost code generation.
+ *
+ * We then add additional ids such that the number of iterators is at least
+ * equal to the dimension of the new build domain.
+ *
+ * If the original domain is parametric, then we are constructing
+ * an isl_ast_build for the outer code generation and we pass control
+ * to isl_ast_build_init.
+ *
+ * Otherwise, we adjust the fields of "build" to include "space".
+ */
+__isl_give isl_ast_build *isl_ast_build_product(
+	__isl_take isl_ast_build *build, __isl_take isl_space *space)
+{
+	isl_ctx *ctx;
+	isl_vec *strides;
+	isl_set *set;
+	isl_multi_aff *embedding;
+	int dim, n_it;
+
+	build = isl_ast_build_cow(build);
+	if (!build)
+		goto error;
+
+	build->outer_pos = build->depth;
+
+	ctx = isl_ast_build_get_ctx(build);
+	dim = isl_set_dim(build->domain, isl_dim_set);
+	dim += isl_space_dim(space, isl_dim_set);
+	n_it = isl_id_list_n_id(build->iterators);
+	if (n_it < dim) {
+		isl_id_list *l;
+		l = generate_names(ctx, dim - n_it, n_it, build);
+		build->iterators = isl_id_list_concat(build->iterators, l);
+	}
+
+	if (isl_set_is_params(build->domain))
+		return isl_ast_build_init(build, space);
+
+	set = isl_set_universe(isl_space_copy(space));
+	build->domain = isl_set_product(build->domain, isl_set_copy(set));
+	build->pending = isl_set_product(build->pending, isl_set_copy(set));
+	build->generated = isl_set_product(build->generated, set);
+
+	strides = isl_vec_alloc(ctx, isl_space_dim(space, isl_dim_set));
+	strides = isl_vec_set_si(strides, 1);
+	build->strides = isl_vec_concat(build->strides, strides);
+
+	space = isl_space_map_from_set(space);
+	build->offsets = isl_multi_aff_align_params(build->offsets,
+						    isl_space_copy(space));
+	build->offsets = isl_multi_aff_product(build->offsets,
+				isl_multi_aff_zero(isl_space_copy(space)));
+	build->values = isl_multi_aff_align_params(build->values,
+						    isl_space_copy(space));
+	embedding = isl_multi_aff_identity(space);
+	build->values = isl_multi_aff_product(build->values,
+					isl_multi_aff_copy(embedding));
+	if (build->internal2input) {
+		build->internal2input =
+			isl_multi_aff_product(build->internal2input, embedding);
+		build->internal2input =
+			isl_multi_aff_flatten_range(build->internal2input);
+		if (!build->internal2input)
+			return isl_ast_build_free(build);
+	} else {
+		isl_multi_aff_free(embedding);
+	}
+
+	space = isl_ast_build_get_space(build, 1);
+	build->options = embed_options(build->options, space);
+
+	if (!build->iterators || !build->domain || !build->generated ||
+	    !build->pending || !build->values ||
+	    !build->strides || !build->offsets || !build->options)
+		return isl_ast_build_free(build);
+
+	return build;
+error:
+	isl_ast_build_free(build);
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Does "aff" only attain non-negative values over build->domain?
+ * That is, does it not attain any negative values?
+ */
+int isl_ast_build_aff_is_nonneg(__isl_keep isl_ast_build *build,
+	__isl_keep isl_aff *aff)
+{
+	isl_set *test;
+	int empty;
+
+	if (!build)
+		return -1;
+
+	aff = isl_aff_copy(aff);
+	test = isl_set_from_basic_set(isl_aff_neg_basic_set(aff));
+	test = isl_set_intersect(test, isl_set_copy(build->domain));
+	empty = isl_set_is_empty(test);
+	isl_set_free(test);
+
+	return empty;
+}
+
+/* Does the dimension at (internal) position "pos" have a non-trivial stride?
+ */
+isl_bool isl_ast_build_has_stride(__isl_keep isl_ast_build *build, int pos)
+{
+	isl_val *v;
+	isl_bool has_stride;
+
+	if (!build)
+		return isl_bool_error;
+
+	v = isl_vec_get_element_val(build->strides, pos);
+	has_stride = isl_bool_not(isl_val_is_one(v));
+	isl_val_free(v);
+
+	return has_stride;
+}
+
+/* Given that the dimension at position "pos" takes on values
+ *
+ *	f + s a
+ *
+ * with a an integer, return s through *stride.
+ */
+__isl_give isl_val *isl_ast_build_get_stride(__isl_keep isl_ast_build *build,
+	int pos)
+{
+	if (!build)
+		return NULL;
+
+	return isl_vec_get_element_val(build->strides, pos);
+}
+
+/* Given that the dimension at position "pos" takes on values
+ *
+ *	f + s a
+ *
+ * with a an integer, return f.
+ */
+__isl_give isl_aff *isl_ast_build_get_offset(
+	__isl_keep isl_ast_build *build, int pos)
+{
+	if (!build)
+		return NULL;
+
+	return isl_multi_aff_get_aff(build->offsets, pos);
+}
+
+/* Is the dimension at position "pos" known to attain only a single
+ * value that, moreover, can be described by a single affine expression
+ * in terms of the outer dimensions and parameters?
+ *
+ * If not, then the corresponding affine expression in build->values
+ * is set to be equal to the same input dimension.
+ * Otherwise, it is set to the requested expression in terms of
+ * outer dimensions and parameters.
+ */
+int isl_ast_build_has_affine_value(__isl_keep isl_ast_build *build,
+	int pos)
+{
+	isl_aff *aff;
+	int involves;
+
+	if (!build)
+		return -1;
+
+	aff = isl_multi_aff_get_aff(build->values, pos);
+	involves = isl_aff_involves_dims(aff, isl_dim_in, pos, 1);
+	isl_aff_free(aff);
+
+	if (involves < 0)
+		return -1;
+
+	return !involves;
+}
+
+/* Plug in the known values (fixed affine expressions in terms of
+ * parameters and outer loop iterators) of all loop iterators
+ * in the domain of "umap".
+ *
+ * We simply precompose "umap" with build->values.
+ */
+__isl_give isl_union_map *isl_ast_build_substitute_values_union_map_domain(
+	__isl_keep isl_ast_build *build, __isl_take isl_union_map *umap)
+{
+	isl_multi_aff *values;
+
+	if (!build)
+		return isl_union_map_free(umap);
+
+	values = isl_multi_aff_copy(build->values);
+	umap = isl_union_map_preimage_domain_multi_aff(umap, values);
+
+	return umap;
+}
+
+/* Is the current dimension known to attain only a single value?
+ */
+int isl_ast_build_has_value(__isl_keep isl_ast_build *build)
+{
+	if (!build)
+		return -1;
+
+	return build->value != NULL;
+}
+
+/* Simplify the basic set "bset" based on what we know about
+ * the iterators of already generated loops.
+ *
+ * "bset" is assumed to live in the (internal) schedule domain.
+ */
+__isl_give isl_basic_set *isl_ast_build_compute_gist_basic_set(
+	__isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset)
+{
+	if (!build)
+		goto error;
+
+	bset = isl_basic_set_preimage_multi_aff(bset,
+					isl_multi_aff_copy(build->values));
+	bset = isl_basic_set_gist(bset,
+			isl_set_simple_hull(isl_set_copy(build->domain)));
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Simplify the set "set" based on what we know about
+ * the iterators of already generated loops.
+ *
+ * "set" is assumed to live in the (internal) schedule domain.
+ */
+__isl_give isl_set *isl_ast_build_compute_gist(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *set)
+{
+	if (!build)
+		goto error;
+
+	if (!isl_set_is_params(set))
+		set = isl_set_preimage_multi_aff(set,
+					isl_multi_aff_copy(build->values));
+	set = isl_set_gist(set, isl_set_copy(build->domain));
+
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Include information about what we know about the iterators of
+ * already generated loops to "set".
+ *
+ * We currently only plug in the known affine values of outer loop
+ * iterators.
+ * In principle we could also introduce equalities or even other
+ * constraints implied by the intersection of "set" and build->domain.
+ */
+__isl_give isl_set *isl_ast_build_specialize(__isl_keep isl_ast_build *build,
+	__isl_take isl_set *set)
+{
+	if (!build)
+		return isl_set_free(set);
+
+	return isl_set_preimage_multi_aff(set,
+					isl_multi_aff_copy(build->values));
+}
+
+/* Plug in the known affine values of outer loop iterators in "bset".
+ */
+__isl_give isl_basic_set *isl_ast_build_specialize_basic_set(
+	__isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset)
+{
+	if (!build)
+		return isl_basic_set_free(bset);
+
+	return isl_basic_set_preimage_multi_aff(bset,
+					isl_multi_aff_copy(build->values));
+}
+
+/* Simplify the map "map" based on what we know about
+ * the iterators of already generated loops.
+ *
+ * The domain of "map" is assumed to live in the (internal) schedule domain.
+ */
+__isl_give isl_map *isl_ast_build_compute_gist_map_domain(
+	__isl_keep isl_ast_build *build, __isl_take isl_map *map)
+{
+	if (!build)
+		goto error;
+
+	map = isl_map_gist_domain(map, isl_set_copy(build->domain));
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Simplify the affine expression "aff" based on what we know about
+ * the iterators of already generated loops.
+ *
+ * The domain of "aff" is assumed to live in the (internal) schedule domain.
+ */
+__isl_give isl_aff *isl_ast_build_compute_gist_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_aff *aff)
+{
+	if (!build)
+		goto error;
+
+	aff = isl_aff_gist(aff, isl_set_copy(build->domain));
+
+	return aff;
+error:
+	isl_aff_free(aff);
+	return NULL;
+}
+
+/* Simplify the piecewise affine expression "aff" based on what we know about
+ * the iterators of already generated loops.
+ *
+ * The domain of "pa" is assumed to live in the (internal) schedule domain.
+ */
+__isl_give isl_pw_aff *isl_ast_build_compute_gist_pw_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa)
+{
+	if (!build)
+		goto error;
+
+	if (!isl_set_is_params(build->domain))
+		pa = isl_pw_aff_pullback_multi_aff(pa,
+					isl_multi_aff_copy(build->values));
+	pa = isl_pw_aff_gist(pa, isl_set_copy(build->domain));
+
+	return pa;
+error:
+	isl_pw_aff_free(pa);
+	return NULL;
+}
+
+/* Simplify the piecewise multi-affine expression "aff" based on what
+ * we know about the iterators of already generated loops.
+ *
+ * The domain of "pma" is assumed to live in the (internal) schedule domain.
+ */
+__isl_give isl_pw_multi_aff *isl_ast_build_compute_gist_pw_multi_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma)
+{
+	if (!build)
+		goto error;
+
+	pma = isl_pw_multi_aff_pullback_multi_aff(pma,
+					isl_multi_aff_copy(build->values));
+	pma = isl_pw_multi_aff_gist(pma, isl_set_copy(build->domain));
+
+	return pma;
+error:
+	isl_pw_multi_aff_free(pma);
+	return NULL;
+}
+
+/* Extract the schedule domain of the given type from build->options
+ * at the current depth.
+ *
+ * In particular, find the subset of build->options that is of
+ * the following form
+ *
+ *	schedule_domain -> type[depth]
+ *
+ * and return the corresponding domain, after eliminating inner dimensions
+ * and divs that depend on the current dimension.
+ *
+ * Note that the domain of build->options has been reformulated
+ * in terms of the internal build space in embed_options,
+ * but the position is still that within the current code generation.
+ */
+__isl_give isl_set *isl_ast_build_get_option_domain(
+	__isl_keep isl_ast_build *build, enum isl_ast_loop_type type)
+{
+	const char *name;
+	isl_space *space;
+	isl_map *option;
+	isl_set *domain;
+	int local_pos;
+
+	if (!build)
+		return NULL;
+
+	name = option_str[type];
+	local_pos = build->depth - build->outer_pos;
+
+	space = isl_ast_build_get_space(build, 1);
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, 1);
+	space = isl_space_set_tuple_name(space, isl_dim_out, name);
+
+	option = isl_union_map_extract_map(build->options, space);
+	option = isl_map_fix_si(option, isl_dim_out, 0, local_pos);
+
+	domain = isl_map_domain(option);
+	domain = isl_ast_build_eliminate(build, domain);
+
+	return domain;
+}
+
+/* How does the user want the current schedule dimension to be generated?
+ * These choices have been extracted from the schedule node
+ * in extract_loop_types and stored in build->loop_type.
+ * They have been updated to reflect any dimension insertion in
+ * node_insert_dim.
+ * Return isl_ast_domain_error on error.
+ *
+ * If "isolated" is set, then we get the loop AST generation type
+ * directly from the band node since node_insert_dim cannot have been
+ * called on a band with the isolate option.
+ */
+enum isl_ast_loop_type isl_ast_build_get_loop_type(
+	__isl_keep isl_ast_build *build, int isolated)
+{
+	int local_pos;
+	isl_ctx *ctx;
+
+	if (!build)
+		return isl_ast_loop_error;
+	ctx = isl_ast_build_get_ctx(build);
+	if (!build->node)
+		isl_die(ctx, isl_error_internal,
+			"only works for schedule tree based AST generation",
+			return isl_ast_loop_error);
+
+	local_pos = build->depth - build->outer_pos;
+	if (!isolated)
+		return build->loop_type[local_pos];
+	return isl_schedule_node_band_member_get_isolate_ast_loop_type(
+							build->node, local_pos);
+}
+
+/* Extract the isolated set from the isolate option, if any,
+ * and store in the build.
+ * If there is no isolate option, then the isolated set is
+ * set to the empty set.
+ *
+ * The isolate option is of the form
+ *
+ *	isolate[[outer bands] -> current_band]
+ *
+ * We flatten this set and then map it back to the internal
+ * schedule space.
+ *
+ * If we have already extracted the isolated set
+ * or if internal2input is no longer set, then we do not
+ * need to do anything.  In the latter case, we know
+ * that the current band cannot have any isolate option.
+ */
+__isl_give isl_ast_build *isl_ast_build_extract_isolated(
+	__isl_take isl_ast_build *build)
+{
+	isl_set *isolated;
+
+	if (!build)
+		return NULL;
+	if (!build->internal2input)
+		return build;
+	if (build->isolated)
+		return build;
+
+	build = isl_ast_build_cow(build);
+	if (!build)
+		return NULL;
+
+	isolated = isl_schedule_node_band_get_ast_isolate_option(build->node);
+	isolated = isl_set_flatten(isolated);
+	isolated = isl_set_preimage_multi_aff(isolated,
+				    isl_multi_aff_copy(build->internal2input));
+
+	build->isolated = isolated;
+	if (!build->isolated)
+		return isl_ast_build_free(build);
+
+	return build;
+}
+
+/* Does "build" have a non-empty isolated set?
+ *
+ * The caller is assumed to have called isl_ast_build_extract_isolated first.
+ */
+int isl_ast_build_has_isolated(__isl_keep isl_ast_build *build)
+{
+	int empty;
+
+	if (!build)
+		return -1;
+	if (!build->internal2input)
+		return 0;
+	if (!build->isolated)
+		isl_die(isl_ast_build_get_ctx(build), isl_error_internal,
+			"isolated set not extracted yet", return -1);
+
+	empty = isl_set_plain_is_empty(build->isolated);
+	return empty < 0 ? -1 : !empty;
+}
+
+/* Return a copy of the isolated set of "build".
+ *
+ * The caller is assume to have called isl_ast_build_has_isolated first,
+ * with this function returning true.
+ * In particular, this function should not be called if we are no
+ * longer keeping track of internal2input (and there therefore could
+ * not possibly be any isolated set).
+ */
+__isl_give isl_set *isl_ast_build_get_isolated(__isl_keep isl_ast_build *build)
+{
+	if (!build)
+		return NULL;
+	if (!build->internal2input)
+		isl_die(isl_ast_build_get_ctx(build), isl_error_internal,
+			"build cannot have isolated set", return NULL);
+
+	return isl_set_copy(build->isolated);
+}
+
+/* Extract the separation class mapping at the current depth.
+ *
+ * In particular, find and return the subset of build->options that is of
+ * the following form
+ *
+ *	schedule_domain -> separation_class[[depth] -> [class]]
+ *
+ * The caller is expected to eliminate inner dimensions from the domain.
+ *
+ * Note that the domain of build->options has been reformulated
+ * in terms of the internal build space in embed_options,
+ * but the position is still that within the current code generation.
+ */
+__isl_give isl_map *isl_ast_build_get_separation_class(
+	__isl_keep isl_ast_build *build)
+{
+	isl_ctx *ctx;
+	isl_space *space_sep, *space;
+	isl_map *res;
+	int local_pos;
+
+	if (!build)
+		return NULL;
+
+	local_pos = build->depth - build->outer_pos;
+	ctx = isl_ast_build_get_ctx(build);
+	space_sep = isl_space_alloc(ctx, 0, 1, 1);
+	space_sep = isl_space_wrap(space_sep);
+	space_sep = isl_space_set_tuple_name(space_sep, isl_dim_set,
+						"separation_class");
+	space = isl_ast_build_get_space(build, 1);
+	space_sep = isl_space_align_params(space_sep, isl_space_copy(space));
+	space = isl_space_map_from_domain_and_range(space, space_sep);
+
+	res = isl_union_map_extract_map(build->options, space);
+	res = isl_map_fix_si(res, isl_dim_out, 0, local_pos);
+	res = isl_map_coalesce(res);
+
+	return res;
+}
+
+/* Eliminate dimensions inner to the current dimension.
+ */
+__isl_give isl_set *isl_ast_build_eliminate_inner(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *set)
+{
+	int dim;
+	int depth;
+
+	if (!build)
+		return isl_set_free(set);
+
+	dim = isl_set_dim(set, isl_dim_set);
+	depth = build->depth;
+	set = isl_set_detect_equalities(set);
+	set = isl_set_eliminate(set, isl_dim_set, depth + 1, dim - (depth + 1));
+
+	return set;
+}
+
+/* Eliminate unknown divs and divs that depend on the current dimension.
+ *
+ * Note that during the elimination of unknown divs, we may discover
+ * an explicit representation of some other unknown divs, which may
+ * depend on the current dimension.  We therefore need to eliminate
+ * unknown divs first.
+ */
+__isl_give isl_set *isl_ast_build_eliminate_divs(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *set)
+{
+	int depth;
+
+	if (!build)
+		return isl_set_free(set);
+
+	set = isl_set_remove_unknown_divs(set);
+	depth = build->depth;
+	set = isl_set_remove_divs_involving_dims(set, isl_dim_set, depth, 1);
+
+	return set;
+}
+
+/* Eliminate dimensions inner to the current dimension as well as
+ * unknown divs and divs that depend on the current dimension.
+ * The result then consists only of constraints that are independent
+ * of the current dimension and upper and lower bounds on the current
+ * dimension.
+ */
+__isl_give isl_set *isl_ast_build_eliminate(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *domain)
+{
+	domain = isl_ast_build_eliminate_inner(build, domain);
+	domain = isl_ast_build_eliminate_divs(build, domain);
+	return domain;
+}
+
+/* Replace build->single_valued by "sv".
+ */
+__isl_give isl_ast_build *isl_ast_build_set_single_valued(
+	__isl_take isl_ast_build *build, int sv)
+{
+	if (!build)
+		return build;
+	if (build->single_valued == sv)
+		return build;
+	build = isl_ast_build_cow(build);
+	if (!build)
+		return build;
+	build->single_valued = sv;
+
+	return build;
+}
diff --git a/final/lib/External/isl/isl_ast_build_expr.c b/final/lib/External/isl/isl_ast_build_expr.c
new file mode 100644
index 0000000..3213886
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_build_expr.c
@@ -0,0 +1,2489 @@
+/*
+ * Copyright 2012-2014 Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <isl/constraint.h>
+#include <isl/ilp.h>
+#include <isl_ast_build_expr.h>
+#include <isl_ast_private.h>
+#include <isl_ast_build_private.h>
+#include <isl_sort.h>
+
+/* Compute the "opposite" of the (numerator of the) argument of a div
+ * with denominator "d".
+ *
+ * In particular, compute
+ *
+ *	-aff + (d - 1)
+ */
+static __isl_give isl_aff *oppose_div_arg(__isl_take isl_aff *aff,
+	__isl_take isl_val *d)
+{
+	aff = isl_aff_neg(aff);
+	aff = isl_aff_add_constant_val(aff, d);
+	aff = isl_aff_add_constant_si(aff, -1);
+
+	return aff;
+}
+
+/* Internal data structure used inside isl_ast_expr_add_term.
+ * The domain of "build" is used to simplify the expressions.
+ * "build" needs to be set by the caller of isl_ast_expr_add_term.
+ * "cst" is the constant term of the expression in which the added term
+ * appears.  It may be modified by isl_ast_expr_add_term.
+ *
+ * "v" is the coefficient of the term that is being constructed and
+ * is set internally by isl_ast_expr_add_term.
+ */
+struct isl_ast_add_term_data {
+	isl_ast_build *build;
+	isl_val *cst;
+	isl_val *v;
+};
+
+/* Given the numerator "aff" of the argument of an integer division
+ * with denominator "d", check if it can be made non-negative over
+ * data->build->domain by stealing part of the constant term of
+ * the expression in which the integer division appears.
+ *
+ * In particular, the outer expression is of the form
+ *
+ *	v * floor(aff/d) + cst
+ *
+ * We already know that "aff" itself may attain negative values.
+ * Here we check if aff + d*floor(cst/v) is non-negative, such
+ * that we could rewrite the expression to
+ *
+ *	v * floor((aff + d*floor(cst/v))/d) + cst - v*floor(cst/v)
+ *
+ * Note that aff + d*floor(cst/v) can only possibly be non-negative
+ * if data->cst and data->v have the same sign.
+ * Similarly, if floor(cst/v) is zero, then there is no point in
+ * checking again.
+ */
+static int is_non_neg_after_stealing(__isl_keep isl_aff *aff,
+	__isl_keep isl_val *d, struct isl_ast_add_term_data *data)
+{
+	isl_aff *shifted;
+	isl_val *shift;
+	int is_zero;
+	int non_neg;
+
+	if (isl_val_sgn(data->cst) != isl_val_sgn(data->v))
+		return 0;
+
+	shift = isl_val_div(isl_val_copy(data->cst), isl_val_copy(data->v));
+	shift = isl_val_floor(shift);
+	is_zero = isl_val_is_zero(shift);
+	if (is_zero < 0 || is_zero) {
+		isl_val_free(shift);
+		return is_zero < 0 ? -1 : 0;
+	}
+	shift = isl_val_mul(shift, isl_val_copy(d));
+	shifted = isl_aff_copy(aff);
+	shifted = isl_aff_add_constant_val(shifted, shift);
+	non_neg = isl_ast_build_aff_is_nonneg(data->build, shifted);
+	isl_aff_free(shifted);
+
+	return non_neg;
+}
+
+/* Given the numerator "aff' of the argument of an integer division
+ * with denominator "d", steal part of the constant term of
+ * the expression in which the integer division appears to make it
+ * non-negative over data->build->domain.
+ *
+ * In particular, the outer expression is of the form
+ *
+ *	v * floor(aff/d) + cst
+ *
+ * We know that "aff" itself may attain negative values,
+ * but that aff + d*floor(cst/v) is non-negative.
+ * Find the minimal positive value that we need to add to "aff"
+ * to make it positive and adjust data->cst accordingly.
+ * That is, compute the minimal value "m" of "aff" over
+ * data->build->domain and take
+ *
+ *	s = ceil(m/d)
+ *
+ * such that
+ *
+ *	aff + d * s >= 0
+ *
+ * and rewrite the expression to
+ *
+ *	v * floor((aff + s*d)/d) + (cst - v*s)
+ */
+static __isl_give isl_aff *steal_from_cst(__isl_take isl_aff *aff,
+	__isl_keep isl_val *d, struct isl_ast_add_term_data *data)
+{
+	isl_set *domain;
+	isl_val *shift, *t;
+
+	domain = isl_ast_build_get_domain(data->build);
+	shift = isl_set_min_val(domain, aff);
+	isl_set_free(domain);
+
+	shift = isl_val_neg(shift);
+	shift = isl_val_div(shift, isl_val_copy(d));
+	shift = isl_val_ceil(shift);
+
+	t = isl_val_copy(shift);
+	t = isl_val_mul(t, isl_val_copy(data->v));
+	data->cst = isl_val_sub(data->cst, t);
+
+	shift = isl_val_mul(shift, isl_val_copy(d));
+	return isl_aff_add_constant_val(aff, shift);
+}
+
+/* Create an isl_ast_expr evaluating the div at position "pos" in "ls".
+ * The result is simplified in terms of data->build->domain.
+ * This function may change (the sign of) data->v.
+ *
+ * "ls" is known to be non-NULL.
+ *
+ * Let the div be of the form floor(e/d).
+ * If the ast_build_prefer_pdiv option is set then we check if "e"
+ * is non-negative, so that we can generate
+ *
+ *	(pdiv_q, expr(e), expr(d))
+ *
+ * instead of
+ *
+ *	(fdiv_q, expr(e), expr(d))
+ *
+ * If the ast_build_prefer_pdiv option is set and
+ * if "e" is not non-negative, then we check if "-e + d - 1" is non-negative.
+ * If so, we can rewrite
+ *
+ *	floor(e/d) = -ceil(-e/d) = -floor((-e + d - 1)/d)
+ *
+ * and still use pdiv_q, while changing the sign of data->v.
+ *
+ * Otherwise, we check if
+ *
+ *	e + d*floor(cst/v)
+ *
+ * is non-negative and if so, replace floor(e/d) by
+ *
+ *	floor((e + s*d)/d) - s
+ *
+ * with s the minimal shift that makes the argument non-negative.
+ */
+static __isl_give isl_ast_expr *var_div(struct isl_ast_add_term_data *data,
+	__isl_keep isl_local_space *ls, int pos)
+{
+	isl_ctx *ctx = isl_local_space_get_ctx(ls);
+	isl_aff *aff;
+	isl_ast_expr *num, *den;
+	isl_val *d;
+	enum isl_ast_op_type type;
+
+	aff = isl_local_space_get_div(ls, pos);
+	d = isl_aff_get_denominator_val(aff);
+	aff = isl_aff_scale_val(aff, isl_val_copy(d));
+	den = isl_ast_expr_from_val(isl_val_copy(d));
+
+	type = isl_ast_op_fdiv_q;
+	if (isl_options_get_ast_build_prefer_pdiv(ctx)) {
+		int non_neg = isl_ast_build_aff_is_nonneg(data->build, aff);
+		if (non_neg >= 0 && !non_neg) {
+			isl_aff *opp = oppose_div_arg(isl_aff_copy(aff),
+							isl_val_copy(d));
+			non_neg = isl_ast_build_aff_is_nonneg(data->build, opp);
+			if (non_neg >= 0 && non_neg) {
+				data->v = isl_val_neg(data->v);
+				isl_aff_free(aff);
+				aff = opp;
+			} else
+				isl_aff_free(opp);
+		}
+		if (non_neg >= 0 && !non_neg) {
+			non_neg = is_non_neg_after_stealing(aff, d, data);
+			if (non_neg >= 0 && non_neg)
+				aff = steal_from_cst(aff, d, data);
+		}
+		if (non_neg < 0)
+			aff = isl_aff_free(aff);
+		else if (non_neg)
+			type = isl_ast_op_pdiv_q;
+	}
+
+	isl_val_free(d);
+	num = isl_ast_expr_from_aff(aff, data->build);
+	return isl_ast_expr_alloc_binary(type, num, den);
+}
+
+/* Create an isl_ast_expr evaluating the specified dimension of "ls".
+ * The result is simplified in terms of data->build->domain.
+ * This function may change (the sign of) data->v.
+ *
+ * The isl_ast_expr is constructed based on the type of the dimension.
+ * - divs are constructed by var_div
+ * - set variables are constructed from the iterator isl_ids in data->build
+ * - parameters are constructed from the isl_ids in "ls"
+ */
+static __isl_give isl_ast_expr *var(struct isl_ast_add_term_data *data,
+	__isl_keep isl_local_space *ls, enum isl_dim_type type, int pos)
+{
+	isl_ctx *ctx = isl_local_space_get_ctx(ls);
+	isl_id *id;
+
+	if (type == isl_dim_div)
+		return var_div(data, ls, pos);
+
+	if (type == isl_dim_set) {
+		id = isl_ast_build_get_iterator_id(data->build, pos);
+		return isl_ast_expr_from_id(id);
+	}
+
+	if (!isl_local_space_has_dim_id(ls, type, pos))
+		isl_die(ctx, isl_error_internal, "unnamed dimension",
+			return NULL);
+	id = isl_local_space_get_dim_id(ls, type, pos);
+	return isl_ast_expr_from_id(id);
+}
+
+/* Does "expr" represent the zero integer?
+ */
+static int ast_expr_is_zero(__isl_keep isl_ast_expr *expr)
+{
+	if (!expr)
+		return -1;
+	if (expr->type != isl_ast_expr_int)
+		return 0;
+	return isl_val_is_zero(expr->u.v);
+}
+
+/* Create an expression representing the sum of "expr1" and "expr2",
+ * provided neither of the two expressions is identically zero.
+ */
+static __isl_give isl_ast_expr *ast_expr_add(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	if (!expr1 || !expr2)
+		goto error;
+
+	if (ast_expr_is_zero(expr1)) {
+		isl_ast_expr_free(expr1);
+		return expr2;
+	}
+
+	if (ast_expr_is_zero(expr2)) {
+		isl_ast_expr_free(expr2);
+		return expr1;
+	}
+
+	return isl_ast_expr_add(expr1, expr2);
+error:
+	isl_ast_expr_free(expr1);
+	isl_ast_expr_free(expr2);
+	return NULL;
+}
+
+/* Subtract expr2 from expr1.
+ *
+ * If expr2 is zero, we simply return expr1.
+ * If expr1 is zero, we return
+ *
+ *	(isl_ast_op_minus, expr2)
+ *
+ * Otherwise, we return
+ *
+ *	(isl_ast_op_sub, expr1, expr2)
+ */
+static __isl_give isl_ast_expr *ast_expr_sub(__isl_take isl_ast_expr *expr1,
+	__isl_take isl_ast_expr *expr2)
+{
+	if (!expr1 || !expr2)
+		goto error;
+
+	if (ast_expr_is_zero(expr2)) {
+		isl_ast_expr_free(expr2);
+		return expr1;
+	}
+
+	if (ast_expr_is_zero(expr1)) {
+		isl_ast_expr_free(expr1);
+		return isl_ast_expr_neg(expr2);
+	}
+
+	return isl_ast_expr_sub(expr1, expr2);
+error:
+	isl_ast_expr_free(expr1);
+	isl_ast_expr_free(expr2);
+	return NULL;
+}
+
+/* Return an isl_ast_expr that represents
+ *
+ *	v * (aff mod d)
+ *
+ * v is assumed to be non-negative.
+ * The result is simplified in terms of build->domain.
+ */
+static __isl_give isl_ast_expr *isl_ast_expr_mod(__isl_keep isl_val *v,
+	__isl_keep isl_aff *aff, __isl_keep isl_val *d,
+	__isl_keep isl_ast_build *build)
+{
+	isl_ast_expr *expr;
+	isl_ast_expr *c;
+
+	if (!aff)
+		return NULL;
+
+	expr = isl_ast_expr_from_aff(isl_aff_copy(aff), build);
+
+	c = isl_ast_expr_from_val(isl_val_copy(d));
+	expr = isl_ast_expr_alloc_binary(isl_ast_op_pdiv_r, expr, c);
+
+	if (!isl_val_is_one(v)) {
+		c = isl_ast_expr_from_val(isl_val_copy(v));
+		expr = isl_ast_expr_mul(c, expr);
+	}
+
+	return expr;
+}
+
+/* Create an isl_ast_expr that scales "expr" by "v".
+ *
+ * If v is 1, we simply return expr.
+ * If v is -1, we return
+ *
+ *	(isl_ast_op_minus, expr)
+ *
+ * Otherwise, we return
+ *
+ *	(isl_ast_op_mul, expr(v), expr)
+ */
+static __isl_give isl_ast_expr *scale(__isl_take isl_ast_expr *expr,
+	__isl_take isl_val *v)
+{
+	isl_ast_expr *c;
+
+	if (!expr || !v)
+		goto error;
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return expr;
+	}
+
+	if (isl_val_is_negone(v)) {
+		isl_val_free(v);
+		expr = isl_ast_expr_neg(expr);
+	} else {
+		c = isl_ast_expr_from_val(v);
+		expr = isl_ast_expr_mul(c, expr);
+	}
+
+	return expr;
+error:
+	isl_val_free(v);
+	isl_ast_expr_free(expr);
+	return NULL;
+}
+
+/* Add an expression for "*v" times the specified dimension of "ls"
+ * to expr.
+ * If the dimension is an integer division, then this function
+ * may modify data->cst in order to make the numerator non-negative.
+ * The result is simplified in terms of data->build->domain.
+ *
+ * Let e be the expression for the specified dimension,
+ * multiplied by the absolute value of "*v".
+ * If "*v" is negative, we create
+ *
+ *	(isl_ast_op_sub, expr, e)
+ *
+ * except when expr is trivially zero, in which case we create
+ *
+ *	(isl_ast_op_minus, e)
+ *
+ * instead.
+ *
+ * If "*v" is positive, we simply create
+ *
+ *	(isl_ast_op_add, expr, e)
+ *
+ */
+static __isl_give isl_ast_expr *isl_ast_expr_add_term(
+	__isl_take isl_ast_expr *expr,
+	__isl_keep isl_local_space *ls, enum isl_dim_type type, int pos,
+	__isl_take isl_val *v, struct isl_ast_add_term_data *data)
+{
+	isl_ast_expr *term;
+
+	if (!expr)
+		return NULL;
+
+	data->v = v;
+	term = var(data, ls, type, pos);
+	v = data->v;
+
+	if (isl_val_is_neg(v) && !ast_expr_is_zero(expr)) {
+		v = isl_val_neg(v);
+		term = scale(term, v);
+		return ast_expr_sub(expr, term);
+	} else {
+		term = scale(term, v);
+		return ast_expr_add(expr, term);
+	}
+}
+
+/* Add an expression for "v" to expr.
+ */
+static __isl_give isl_ast_expr *isl_ast_expr_add_int(
+	__isl_take isl_ast_expr *expr, __isl_take isl_val *v)
+{
+	isl_ast_expr *expr_int;
+
+	if (!expr || !v)
+		goto error;
+
+	if (isl_val_is_zero(v)) {
+		isl_val_free(v);
+		return expr;
+	}
+
+	if (isl_val_is_neg(v) && !ast_expr_is_zero(expr)) {
+		v = isl_val_neg(v);
+		expr_int = isl_ast_expr_from_val(v);
+		return ast_expr_sub(expr, expr_int);
+	} else {
+		expr_int = isl_ast_expr_from_val(v);
+		return ast_expr_add(expr, expr_int);
+	}
+error:
+	isl_ast_expr_free(expr);
+	isl_val_free(v);
+	return NULL;
+}
+
+/* Internal data structure used inside extract_modulos.
+ *
+ * If any modulo expressions are detected in "aff", then the
+ * expression is removed from "aff" and added to either "pos" or "neg"
+ * depending on the sign of the coefficient of the modulo expression
+ * inside "aff".
+ *
+ * "add" is an expression that needs to be added to "aff" at the end of
+ * the computation.  It is NULL as long as no modulos have been extracted.
+ *
+ * "i" is the position in "aff" of the div under investigation
+ * "v" is the coefficient in "aff" of the div
+ * "div" is the argument of the div, with the denominator removed
+ * "d" is the original denominator of the argument of the div
+ *
+ * "nonneg" is an affine expression that is non-negative over "build"
+ * and that can be used to extract a modulo expression from "div".
+ * In particular, if "sign" is 1, then the coefficients of "nonneg"
+ * are equal to those of "div" modulo "d".  If "sign" is -1, then
+ * the coefficients of "nonneg" are opposite to those of "div" modulo "d".
+ * If "sign" is 0, then no such affine expression has been found (yet).
+ */
+struct isl_extract_mod_data {
+	isl_ast_build *build;
+	isl_aff *aff;
+
+	isl_ast_expr *pos;
+	isl_ast_expr *neg;
+
+	isl_aff *add;
+
+	int i;
+	isl_val *v;
+	isl_val *d;
+	isl_aff *div;
+
+	isl_aff *nonneg;
+	int sign;
+};
+
+/* Given that data->v * div_i in data->aff is equal to
+ *
+ *	f * (term - (arg mod d))
+ *
+ * with data->d * f = data->v, add
+ *
+ *	f * term
+ *
+ * to data->add and
+ *
+ *	abs(f) * (arg mod d)
+ *
+ * to data->neg or data->pos depending on the sign of -f.
+ */
+static int extract_term_and_mod(struct isl_extract_mod_data *data,
+	__isl_take isl_aff *term, __isl_take isl_aff *arg)
+{
+	isl_ast_expr *expr;
+	int s;
+
+	data->v = isl_val_div(data->v, isl_val_copy(data->d));
+	s = isl_val_sgn(data->v);
+	data->v = isl_val_abs(data->v);
+	expr = isl_ast_expr_mod(data->v, arg, data->d, data->build);
+	isl_aff_free(arg);
+	if (s > 0)
+		data->neg = ast_expr_add(data->neg, expr);
+	else
+		data->pos = ast_expr_add(data->pos, expr);
+	data->aff = isl_aff_set_coefficient_si(data->aff,
+						isl_dim_div, data->i, 0);
+	if (s < 0)
+		data->v = isl_val_neg(data->v);
+	term = isl_aff_scale_val(term, isl_val_copy(data->v));
+
+	if (!data->add)
+		data->add = term;
+	else
+		data->add = isl_aff_add(data->add, term);
+	if (!data->add)
+		return -1;
+
+	return 0;
+}
+
+/* Given that data->v * div_i in data->aff is of the form
+ *
+ *	f * d * floor(div/d)
+ *
+ * with div nonnegative on data->build, rewrite it as
+ *
+ *	f * (div - (div mod d)) = f * div - f * (div mod d)
+ *
+ * and add
+ *
+ *	f * div
+ *
+ * to data->add and
+ *
+ *	abs(f) * (div mod d)
+ *
+ * to data->neg or data->pos depending on the sign of -f.
+ */
+static int extract_mod(struct isl_extract_mod_data *data)
+{
+	return extract_term_and_mod(data, isl_aff_copy(data->div),
+			isl_aff_copy(data->div));
+}
+
+/* Given that data->v * div_i in data->aff is of the form
+ *
+ *	f * d * floor(div/d)					(1)
+ *
+ * check if div is non-negative on data->build and, if so,
+ * extract the corresponding modulo from data->aff.
+ * If not, then check if
+ *
+ *	-div + d - 1
+ *
+ * is non-negative on data->build.  If so, replace (1) by
+ *
+ *	-f * d * floor((-div + d - 1)/d)
+ *
+ * and extract the corresponding modulo from data->aff.
+ *
+ * This function may modify data->div.
+ */
+static int extract_nonneg_mod(struct isl_extract_mod_data *data)
+{
+	int mod;
+
+	mod = isl_ast_build_aff_is_nonneg(data->build, data->div);
+	if (mod < 0)
+		goto error;
+	if (mod)
+		return extract_mod(data);
+
+	data->div = oppose_div_arg(data->div, isl_val_copy(data->d));
+	mod = isl_ast_build_aff_is_nonneg(data->build, data->div);
+	if (mod < 0)
+		goto error;
+	if (mod) {
+		data->v = isl_val_neg(data->v);
+		return extract_mod(data);
+	}
+
+	return 0;
+error:
+	data->aff = isl_aff_free(data->aff);
+	return -1;
+}
+
+/* Is the affine expression of constraint "c" "simpler" than data->nonneg
+ * for use in extracting a modulo expression?
+ *
+ * We currently only consider the constant term of the affine expression.
+ * In particular, we prefer the affine expression with the smallest constant
+ * term.
+ * This means that if there are two constraints, say x >= 0 and -x + 10 >= 0,
+ * then we would pick x >= 0
+ *
+ * More detailed heuristics could be used if it turns out that there is a need.
+ */
+static int mod_constraint_is_simpler(struct isl_extract_mod_data *data,
+	__isl_keep isl_constraint *c)
+{
+	isl_val *v1, *v2;
+	int simpler;
+
+	if (!data->nonneg)
+		return 1;
+
+	v1 = isl_val_abs(isl_constraint_get_constant_val(c));
+	v2 = isl_val_abs(isl_aff_get_constant_val(data->nonneg));
+	simpler = isl_val_lt(v1, v2);
+	isl_val_free(v1);
+	isl_val_free(v2);
+
+	return simpler;
+}
+
+/* Check if the coefficients of "c" are either equal or opposite to those
+ * of data->div modulo data->d.  If so, and if "c" is "simpler" than
+ * data->nonneg, then replace data->nonneg by the affine expression of "c"
+ * and set data->sign accordingly.
+ *
+ * Both "c" and data->div are assumed not to involve any integer divisions.
+ *
+ * Before we start the actual comparison, we first quickly check if
+ * "c" and data->div have the same non-zero coefficients.
+ * If not, then we assume that "c" is not of the desired form.
+ * Note that while the coefficients of data->div can be reasonably expected
+ * not to involve any coefficients that are multiples of d, "c" may
+ * very well involve such coefficients.  This means that we may actually
+ * miss some cases.
+ *
+ * If the constant term is "too large", then the constraint is rejected,
+ * where "too large" is fairly arbitrarily set to 1 << 15.
+ * We do this to avoid picking up constraints that bound a variable
+ * by a very large number, say the largest or smallest possible
+ * variable in the representation of some integer type.
+ */
+static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c,
+	void *user)
+{
+	struct isl_extract_mod_data *data = user;
+	enum isl_dim_type c_type[2] = { isl_dim_param, isl_dim_set };
+	enum isl_dim_type a_type[2] = { isl_dim_param, isl_dim_in };
+	int i, t;
+	int n[2];
+	int parallel = 1, opposite = 1;
+
+	for (t = 0; t < 2; ++t) {
+		n[t] = isl_constraint_dim(c, c_type[t]);
+		for (i = 0; i < n[t]; ++i) {
+			int a, b;
+
+			a = isl_constraint_involves_dims(c, c_type[t], i, 1);
+			b = isl_aff_involves_dims(data->div, a_type[t], i, 1);
+			if (a != b)
+				parallel = opposite = 0;
+		}
+	}
+
+	if (parallel || opposite) {
+		isl_val *v;
+
+		v = isl_val_abs(isl_constraint_get_constant_val(c));
+		if (isl_val_cmp_si(v, 1 << 15) > 0)
+			parallel = opposite = 0;
+		isl_val_free(v);
+	}
+
+	for (t = 0; t < 2; ++t) {
+		for (i = 0; i < n[t]; ++i) {
+			isl_val *v1, *v2;
+
+			if (!parallel && !opposite)
+				break;
+			v1 = isl_constraint_get_coefficient_val(c,
+								c_type[t], i);
+			v2 = isl_aff_get_coefficient_val(data->div,
+								a_type[t], i);
+			if (parallel) {
+				v1 = isl_val_sub(v1, isl_val_copy(v2));
+				parallel = isl_val_is_divisible_by(v1, data->d);
+				v1 = isl_val_add(v1, isl_val_copy(v2));
+			}
+			if (opposite) {
+				v1 = isl_val_add(v1, isl_val_copy(v2));
+				opposite = isl_val_is_divisible_by(v1, data->d);
+			}
+			isl_val_free(v1);
+			isl_val_free(v2);
+		}
+	}
+
+	if ((parallel || opposite) && mod_constraint_is_simpler(data, c)) {
+		isl_aff_free(data->nonneg);
+		data->nonneg = isl_constraint_get_aff(c);
+		data->sign = parallel ? 1 : -1;
+	}
+
+	isl_constraint_free(c);
+
+	if (data->sign != 0 && data->nonneg == NULL)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Given that data->v * div_i in data->aff is of the form
+ *
+ *	f * d * floor(div/d)					(1)
+ *
+ * see if we can find an expression div' that is non-negative over data->build
+ * and that is related to div through
+ *
+ *	div' = div + d * e
+ *
+ * or
+ *
+ *	div' = -div + d - 1 + d * e
+ *
+ * with e some affine expression.
+ * If so, we write (1) as
+ *
+ *	f * div + f * (div' mod d)
+ *
+ * or
+ *
+ *	-f * (-div + d - 1) - f * (div' mod d)
+ *
+ * exploiting (in the second case) the fact that
+ *
+ *	f * d * floor(div/d) =	-f * d * floor((-div + d - 1)/d)
+ *
+ *
+ * We first try to find an appropriate expression for div'
+ * from the constraints of data->build->domain (which is therefore
+ * guaranteed to be non-negative on data->build), where we remove
+ * any integer divisions from the constraints and skip this step
+ * if "div" itself involves any integer divisions.
+ * If we cannot find an appropriate expression this way, then
+ * we pass control to extract_nonneg_mod where check
+ * if div or "-div + d -1" themselves happen to be
+ * non-negative on data->build.
+ *
+ * While looking for an appropriate constraint in data->build->domain,
+ * we ignore the constant term, so after finding such a constraint,
+ * we still need to fix up the constant term.
+ * In particular, if a is the constant term of "div"
+ * (or d - 1 - the constant term of "div" if data->sign < 0)
+ * and b is the constant term of the constraint, then we need to find
+ * a non-negative constant c such that
+ *
+ *	b + c \equiv a	mod d
+ *
+ * We therefore take
+ *
+ *	c = (a - b) mod d
+ *
+ * and add it to b to obtain the constant term of div'.
+ * If this constant term is "too negative", then we add an appropriate
+ * multiple of d to make it positive.
+ *
+ *
+ * Note that the above is a only a very simple heuristic for finding an
+ * appropriate expression.  We could try a bit harder by also considering
+ * sums of constraints that involve disjoint sets of variables or
+ * we could consider arbitrary linear combinations of constraints,
+ * although that could potentially be much more expensive as it involves
+ * the solution of an LP problem.
+ *
+ * In particular, if v_i is a column vector representing constraint i,
+ * w represents div and e_i is the i-th unit vector, then we are looking
+ * for a solution of the constraints
+ *
+ *	\sum_i lambda_i v_i = w + \sum_i alpha_i d e_i
+ *
+ * with \lambda_i >= 0 and alpha_i of unrestricted sign.
+ * If we are not just interested in a non-negative expression, but
+ * also in one with a minimal range, then we don't just want
+ * c = \sum_i lambda_i v_i to be non-negative over the domain,
+ * but also beta - c = \sum_i mu_i v_i, where beta is a scalar
+ * that we want to minimize and we now also have to take into account
+ * the constant terms of the constraints.
+ * Alternatively, we could first compute the dual of the domain
+ * and plug in the constraints on the coefficients.
+ */
+static int try_extract_mod(struct isl_extract_mod_data *data)
+{
+	isl_basic_set *hull;
+	isl_val *v1, *v2;
+	int r, n;
+
+	if (!data->build)
+		goto error;
+
+	n = isl_aff_dim(data->div, isl_dim_div);
+
+	if (isl_aff_involves_dims(data->div, isl_dim_div, 0, n))
+		return extract_nonneg_mod(data);
+
+	hull = isl_set_simple_hull(isl_set_copy(data->build->domain));
+	hull = isl_basic_set_remove_divs(hull);
+	data->sign = 0;
+	data->nonneg = NULL;
+	r = isl_basic_set_foreach_constraint(hull, &check_parallel_or_opposite,
+					data);
+	isl_basic_set_free(hull);
+
+	if (!data->sign || r < 0) {
+		isl_aff_free(data->nonneg);
+		if (r < 0)
+			goto error;
+		return extract_nonneg_mod(data);
+	}
+
+	v1 = isl_aff_get_constant_val(data->div);
+	v2 = isl_aff_get_constant_val(data->nonneg);
+	if (data->sign < 0) {
+		v1 = isl_val_neg(v1);
+		v1 = isl_val_add(v1, isl_val_copy(data->d));
+		v1 = isl_val_sub_ui(v1, 1);
+	}
+	v1 = isl_val_sub(v1, isl_val_copy(v2));
+	v1 = isl_val_mod(v1, isl_val_copy(data->d));
+	v1 = isl_val_add(v1, v2);
+	v2 = isl_val_div(isl_val_copy(v1), isl_val_copy(data->d));
+	v2 = isl_val_ceil(v2);
+	if (isl_val_is_neg(v2)) {
+		v2 = isl_val_mul(v2, isl_val_copy(data->d));
+		v1 = isl_val_sub(v1, isl_val_copy(v2));
+	}
+	data->nonneg = isl_aff_set_constant_val(data->nonneg, v1);
+	isl_val_free(v2);
+
+	if (data->sign < 0) {
+		data->div = oppose_div_arg(data->div, isl_val_copy(data->d));
+		data->v = isl_val_neg(data->v);
+	}
+
+	return extract_term_and_mod(data,
+				    isl_aff_copy(data->div), data->nonneg);
+error:
+	data->aff = isl_aff_free(data->aff);
+	return -1;
+}
+
+/* Check if "data->aff" involves any (implicit) modulo computations based
+ * on div "data->i".
+ * If so, remove them from aff and add expressions corresponding
+ * to those modulo computations to data->pos and/or data->neg.
+ *
+ * "aff" is assumed to be an integer affine expression.
+ *
+ * In particular, check if (v * div_j) is of the form
+ *
+ *	f * m * floor(a / m)
+ *
+ * and, if so, rewrite it as
+ *
+ *	f * (a - (a mod m)) = f * a - f * (a mod m)
+ *
+ * and extract out -f * (a mod m).
+ * In particular, if f > 0, we add (f * (a mod m)) to *neg.
+ * If f < 0, we add ((-f) * (a mod m)) to *pos.
+ *
+ * Note that in order to represent "a mod m" as
+ *
+ *	(isl_ast_op_pdiv_r, a, m)
+ *
+ * we need to make sure that a is non-negative.
+ * If not, we check if "-a + m - 1" is non-negative.
+ * If so, we can rewrite
+ *
+ *	floor(a/m) = -ceil(-a/m) = -floor((-a + m - 1)/m)
+ *
+ * and still extract a modulo.
+ */
+static int extract_modulo(struct isl_extract_mod_data *data)
+{
+	data->div = isl_aff_get_div(data->aff, data->i);
+	data->d = isl_aff_get_denominator_val(data->div);
+	if (isl_val_is_divisible_by(data->v, data->d)) {
+		data->div = isl_aff_scale_val(data->div, isl_val_copy(data->d));
+		if (try_extract_mod(data) < 0)
+			data->aff = isl_aff_free(data->aff);
+	}
+	isl_aff_free(data->div);
+	isl_val_free(data->d);
+	return 0;
+}
+
+/* Check if "aff" involves any (implicit) modulo computations.
+ * If so, remove them from aff and add expressions corresponding
+ * to those modulo computations to *pos and/or *neg.
+ * We only do this if the option ast_build_prefer_pdiv is set.
+ *
+ * "aff" is assumed to be an integer affine expression.
+ *
+ * A modulo expression is of the form
+ *
+ *	a mod m = a - m * floor(a / m)
+ *
+ * To detect them in aff, we look for terms of the form
+ *
+ *	f * m * floor(a / m)
+ *
+ * rewrite them as
+ *
+ *	f * (a - (a mod m)) = f * a - f * (a mod m)
+ *
+ * and extract out -f * (a mod m).
+ * In particular, if f > 0, we add (f * (a mod m)) to *neg.
+ * If f < 0, we add ((-f) * (a mod m)) to *pos.
+ */
+static __isl_give isl_aff *extract_modulos(__isl_take isl_aff *aff,
+	__isl_keep isl_ast_expr **pos, __isl_keep isl_ast_expr **neg,
+	__isl_keep isl_ast_build *build)
+{
+	struct isl_extract_mod_data data = { build, aff, *pos, *neg };
+	isl_ctx *ctx;
+	int n;
+
+	if (!aff)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(aff);
+	if (!isl_options_get_ast_build_prefer_pdiv(ctx))
+		return aff;
+
+	n = isl_aff_dim(data.aff, isl_dim_div);
+	for (data.i = 0; data.i < n; ++data.i) {
+		data.v = isl_aff_get_coefficient_val(data.aff,
+							isl_dim_div, data.i);
+		if (!data.v)
+			return isl_aff_free(aff);
+		if (isl_val_is_zero(data.v) ||
+		    isl_val_is_one(data.v) || isl_val_is_negone(data.v)) {
+			isl_val_free(data.v);
+			continue;
+		}
+		if (extract_modulo(&data) < 0)
+			data.aff = isl_aff_free(data.aff);
+		isl_val_free(data.v);
+		if (!data.aff)
+			break;
+	}
+
+	if (data.add)
+		data.aff = isl_aff_add(data.aff, data.add);
+
+	*pos = data.pos;
+	*neg = data.neg;
+	return data.aff;
+}
+
+/* Check if aff involves any non-integer coefficients.
+ * If so, split aff into
+ *
+ *	aff = aff1 + (aff2 / d)
+ *
+ * with both aff1 and aff2 having only integer coefficients.
+ * Return aff1 and add (aff2 / d) to *expr.
+ */
+static __isl_give isl_aff *extract_rational(__isl_take isl_aff *aff,
+	__isl_keep isl_ast_expr **expr, __isl_keep isl_ast_build *build)
+{
+	int i, j, n;
+	isl_aff *rat = NULL;
+	isl_local_space *ls = NULL;
+	isl_ast_expr *rat_expr;
+	isl_val *v, *d;
+	enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_div };
+	enum isl_dim_type l[] = { isl_dim_param, isl_dim_set, isl_dim_div };
+
+	if (!aff)
+		return NULL;
+	d = isl_aff_get_denominator_val(aff);
+	if (!d)
+		goto error;
+	if (isl_val_is_one(d)) {
+		isl_val_free(d);
+		return aff;
+	}
+
+	aff = isl_aff_scale_val(aff, isl_val_copy(d));
+
+	ls = isl_aff_get_domain_local_space(aff);
+	rat = isl_aff_zero_on_domain(isl_local_space_copy(ls));
+
+	for (i = 0; i < 3; ++i) {
+		n = isl_aff_dim(aff, t[i]);
+		for (j = 0; j < n; ++j) {
+			isl_aff *rat_j;
+
+			v = isl_aff_get_coefficient_val(aff, t[i], j);
+			if (!v)
+				goto error;
+			if (isl_val_is_divisible_by(v, d)) {
+				isl_val_free(v);
+				continue;
+			}
+			rat_j = isl_aff_var_on_domain(isl_local_space_copy(ls),
+							l[i], j);
+			rat_j = isl_aff_scale_val(rat_j, v);
+			rat = isl_aff_add(rat, rat_j);
+		}
+	}
+
+	v = isl_aff_get_constant_val(aff);
+	if (isl_val_is_divisible_by(v, d)) {
+		isl_val_free(v);
+	} else {
+		isl_aff *rat_0;
+
+		rat_0 = isl_aff_val_on_domain(isl_local_space_copy(ls), v);
+		rat = isl_aff_add(rat, rat_0);
+	}
+
+	isl_local_space_free(ls);
+
+	aff = isl_aff_sub(aff, isl_aff_copy(rat));
+	aff = isl_aff_scale_down_val(aff, isl_val_copy(d));
+
+	rat_expr = isl_ast_expr_from_aff(rat, build);
+	rat_expr = isl_ast_expr_div(rat_expr, isl_ast_expr_from_val(d));
+	*expr = ast_expr_add(*expr, rat_expr);
+
+	return aff;
+error:
+	isl_aff_free(rat);
+	isl_local_space_free(ls);
+	isl_aff_free(aff);
+	isl_val_free(d);
+	return NULL;
+}
+
+/* Construct an isl_ast_expr that evaluates the affine expression "aff",
+ * The result is simplified in terms of build->domain.
+ *
+ * We first extract hidden modulo computations from the affine expression
+ * and then add terms for each variable with a non-zero coefficient.
+ * Finally, if the affine expression has a non-trivial denominator,
+ * we divide the resulting isl_ast_expr by this denominator.
+ */
+__isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff,
+	__isl_keep isl_ast_build *build)
+{
+	int i, j;
+	int n;
+	isl_val *v;
+	isl_ctx *ctx = isl_aff_get_ctx(aff);
+	isl_ast_expr *expr, *expr_neg;
+	enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_div };
+	enum isl_dim_type l[] = { isl_dim_param, isl_dim_set, isl_dim_div };
+	isl_local_space *ls;
+	struct isl_ast_add_term_data data;
+
+	if (!aff)
+		return NULL;
+
+	expr = isl_ast_expr_alloc_int_si(ctx, 0);
+	expr_neg = isl_ast_expr_alloc_int_si(ctx, 0);
+
+	aff = extract_rational(aff, &expr, build);
+
+	aff = extract_modulos(aff, &expr, &expr_neg, build);
+	expr = ast_expr_sub(expr, expr_neg);
+
+	ls = isl_aff_get_domain_local_space(aff);
+
+	data.build = build;
+	data.cst = isl_aff_get_constant_val(aff);
+	for (i = 0; i < 3; ++i) {
+		n = isl_aff_dim(aff, t[i]);
+		for (j = 0; j < n; ++j) {
+			v = isl_aff_get_coefficient_val(aff, t[i], j);
+			if (!v)
+				expr = isl_ast_expr_free(expr);
+			if (isl_val_is_zero(v)) {
+				isl_val_free(v);
+				continue;
+			}
+			expr = isl_ast_expr_add_term(expr,
+							ls, l[i], j, v, &data);
+		}
+	}
+
+	expr = isl_ast_expr_add_int(expr, data.cst);
+
+	isl_local_space_free(ls);
+	isl_aff_free(aff);
+	return expr;
+}
+
+/* Add terms to "expr" for each variable in "aff" with a coefficient
+ * with sign equal to "sign".
+ * The result is simplified in terms of data->build->domain.
+ */
+static __isl_give isl_ast_expr *add_signed_terms(__isl_take isl_ast_expr *expr,
+	__isl_keep isl_aff *aff, int sign, struct isl_ast_add_term_data *data)
+{
+	int i, j;
+	isl_val *v;
+	enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_div };
+	enum isl_dim_type l[] = { isl_dim_param, isl_dim_set, isl_dim_div };
+	isl_local_space *ls;
+
+	ls = isl_aff_get_domain_local_space(aff);
+
+	for (i = 0; i < 3; ++i) {
+		int n = isl_aff_dim(aff, t[i]);
+		for (j = 0; j < n; ++j) {
+			v = isl_aff_get_coefficient_val(aff, t[i], j);
+			if (sign * isl_val_sgn(v) <= 0) {
+				isl_val_free(v);
+				continue;
+			}
+			v = isl_val_abs(v);
+			expr = isl_ast_expr_add_term(expr,
+						ls, l[i], j, v, data);
+		}
+	}
+
+	isl_local_space_free(ls);
+
+	return expr;
+}
+
+/* Should the constant term "v" be considered positive?
+ *
+ * A positive constant will be added to "pos" by the caller,
+ * while a negative constant will be added to "neg".
+ * If either "pos" or "neg" is exactly zero, then we prefer
+ * to add the constant "v" to that side, irrespective of the sign of "v".
+ * This results in slightly shorter expressions and may reduce the risk
+ * of overflows.
+ */
+static int constant_is_considered_positive(__isl_keep isl_val *v,
+	__isl_keep isl_ast_expr *pos, __isl_keep isl_ast_expr *neg)
+{
+	if (ast_expr_is_zero(pos))
+		return 1;
+	if (ast_expr_is_zero(neg))
+		return 0;
+	return isl_val_is_pos(v);
+}
+
+/* Check if the equality
+ *
+ *	aff = 0
+ *
+ * represents a stride constraint on the integer division "pos".
+ *
+ * In particular, if the integer division "pos" is equal to
+ *
+ *	floor(e/d)
+ *
+ * then check if aff is equal to
+ *
+ *	e - d floor(e/d)
+ *
+ * or its opposite.
+ *
+ * If so, the equality is exactly
+ *
+ *	e mod d = 0
+ *
+ * Note that in principle we could also accept
+ *
+ *	e - d floor(e'/d)
+ *
+ * where e and e' differ by a constant.
+ */
+static int is_stride_constraint(__isl_keep isl_aff *aff, int pos)
+{
+	isl_aff *div;
+	isl_val *c, *d;
+	int eq;
+
+	div = isl_aff_get_div(aff, pos);
+	c = isl_aff_get_coefficient_val(aff, isl_dim_div, pos);
+	d = isl_aff_get_denominator_val(div);
+	eq = isl_val_abs_eq(c, d);
+	if (eq >= 0 && eq) {
+		aff = isl_aff_copy(aff);
+		aff = isl_aff_set_coefficient_si(aff, isl_dim_div, pos, 0);
+		div = isl_aff_scale_val(div, d);
+		if (isl_val_is_pos(c))
+			div = isl_aff_neg(div);
+		eq = isl_aff_plain_is_equal(div, aff);
+		isl_aff_free(aff);
+	} else
+		isl_val_free(d);
+	isl_val_free(c);
+	isl_aff_free(div);
+
+	return eq;
+}
+
+/* Are all coefficients of "aff" (zero or) negative?
+ */
+static int all_negative_coefficients(__isl_keep isl_aff *aff)
+{
+	int i, n;
+
+	if (!aff)
+		return 0;
+
+	n = isl_aff_dim(aff, isl_dim_param);
+	for (i = 0; i < n; ++i)
+		if (isl_aff_coefficient_sgn(aff, isl_dim_param, i) > 0)
+			return 0;
+
+	n = isl_aff_dim(aff, isl_dim_in);
+	for (i = 0; i < n; ++i)
+		if (isl_aff_coefficient_sgn(aff, isl_dim_in, i) > 0)
+			return 0;
+
+	return 1;
+}
+
+/* Give an equality of the form
+ *
+ *	aff = e - d floor(e/d) = 0
+ *
+ * or
+ *
+ *	aff = -e + d floor(e/d) = 0
+ *
+ * with the integer division "pos" equal to floor(e/d),
+ * construct the AST expression
+ *
+ *	(isl_ast_op_eq, (isl_ast_op_zdiv_r, expr(e), expr(d)), expr(0))
+ *
+ * If e only has negative coefficients, then construct
+ *
+ *	(isl_ast_op_eq, (isl_ast_op_zdiv_r, expr(-e), expr(d)), expr(0))
+ *
+ * instead.
+ */
+static __isl_give isl_ast_expr *extract_stride_constraint(
+	__isl_take isl_aff *aff, int pos, __isl_keep isl_ast_build *build)
+{
+	isl_ctx *ctx;
+	isl_val *c;
+	isl_ast_expr *expr, *cst;
+
+	if (!aff)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(aff);
+
+	c = isl_aff_get_coefficient_val(aff, isl_dim_div, pos);
+	aff = isl_aff_set_coefficient_si(aff, isl_dim_div, pos, 0);
+
+	if (all_negative_coefficients(aff))
+		aff = isl_aff_neg(aff);
+
+	cst = isl_ast_expr_from_val(isl_val_abs(c));
+	expr = isl_ast_expr_from_aff(aff, build);
+
+	expr = isl_ast_expr_alloc_binary(isl_ast_op_zdiv_r, expr, cst);
+	cst = isl_ast_expr_alloc_int_si(ctx, 0);
+	expr = isl_ast_expr_alloc_binary(isl_ast_op_eq, expr, cst);
+
+	return expr;
+}
+
+/* Construct an isl_ast_expr that evaluates the condition "constraint",
+ * The result is simplified in terms of build->domain.
+ *
+ * We first check if the constraint is an equality of the form
+ *
+ *	e - d floor(e/d) = 0
+ *
+ * i.e.,
+ *
+ *	e mod d = 0
+ *
+ * If so, we convert it to
+ *
+ *	(isl_ast_op_eq, (isl_ast_op_zdiv_r, expr(e), expr(d)), expr(0))
+ *
+ * Otherwise, let the constraint by either "a >= 0" or "a == 0".
+ * We first extract hidden modulo computations from "a"
+ * and then collect all the terms with a positive coefficient in cons_pos
+ * and the terms with a negative coefficient in cons_neg.
+ *
+ * The result is then of the form
+ *
+ *	(isl_ast_op_ge, expr(pos), expr(-neg)))
+ *
+ * or
+ *
+ *	(isl_ast_op_eq, expr(pos), expr(-neg)))
+ *
+ * However, if the first expression is an integer constant (and the second
+ * is not), then we swap the two expressions.  This ensures that we construct,
+ * e.g., "i <= 5" rather than "5 >= i".
+ *
+ * Furthermore, is there are no terms with positive coefficients (or no terms
+ * with negative coefficients), then the constant term is added to "pos"
+ * (or "neg"), ignoring the sign of the constant term.
+ */
+static __isl_give isl_ast_expr *isl_ast_expr_from_constraint(
+	__isl_take isl_constraint *constraint, __isl_keep isl_ast_build *build)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_ast_expr *expr_pos;
+	isl_ast_expr *expr_neg;
+	isl_ast_expr *expr;
+	isl_aff *aff;
+	int eq;
+	enum isl_ast_op_type type;
+	struct isl_ast_add_term_data data;
+
+	if (!constraint)
+		return NULL;
+
+	aff = isl_constraint_get_aff(constraint);
+	eq = isl_constraint_is_equality(constraint);
+	isl_constraint_free(constraint);
+
+	n = isl_aff_dim(aff, isl_dim_div);
+	if (eq && n > 0)
+		for (i = 0; i < n; ++i) {
+			int is_stride;
+			is_stride = is_stride_constraint(aff, i);
+			if (is_stride < 0)
+				goto error;
+			if (is_stride)
+				return extract_stride_constraint(aff, i, build);
+		}
+
+	ctx = isl_aff_get_ctx(aff);
+	expr_pos = isl_ast_expr_alloc_int_si(ctx, 0);
+	expr_neg = isl_ast_expr_alloc_int_si(ctx, 0);
+
+	aff = extract_modulos(aff, &expr_pos, &expr_neg, build);
+
+	data.build = build;
+	data.cst = isl_aff_get_constant_val(aff);
+	expr_pos = add_signed_terms(expr_pos, aff, 1, &data);
+	data.cst = isl_val_neg(data.cst);
+	expr_neg = add_signed_terms(expr_neg, aff, -1, &data);
+	data.cst = isl_val_neg(data.cst);
+
+	if (constant_is_considered_positive(data.cst, expr_pos, expr_neg)) {
+		expr_pos = isl_ast_expr_add_int(expr_pos, data.cst);
+	} else {
+		data.cst = isl_val_neg(data.cst);
+		expr_neg = isl_ast_expr_add_int(expr_neg, data.cst);
+	}
+
+	if (isl_ast_expr_get_type(expr_pos) == isl_ast_expr_int &&
+	    isl_ast_expr_get_type(expr_neg) != isl_ast_expr_int) {
+		type = eq ? isl_ast_op_eq : isl_ast_op_le;
+		expr = isl_ast_expr_alloc_binary(type, expr_neg, expr_pos);
+	} else {
+		type = eq ? isl_ast_op_eq : isl_ast_op_ge;
+		expr = isl_ast_expr_alloc_binary(type, expr_pos, expr_neg);
+	}
+
+	isl_aff_free(aff);
+	return expr;
+error:
+	isl_aff_free(aff);
+	return NULL;
+}
+
+/* Wrapper around isl_constraint_cmp_last_non_zero for use
+ * as a callback to isl_constraint_list_sort.
+ * If isl_constraint_cmp_last_non_zero cannot tell the constraints
+ * apart, then use isl_constraint_plain_cmp instead.
+ */
+static int cmp_constraint(__isl_keep isl_constraint *a,
+	__isl_keep isl_constraint *b, void *user)
+{
+	int cmp;
+
+	cmp = isl_constraint_cmp_last_non_zero(a, b);
+	if (cmp != 0)
+		return cmp;
+	return isl_constraint_plain_cmp(a, b);
+}
+
+/* Construct an isl_ast_expr that evaluates the conditions defining "bset".
+ * The result is simplified in terms of build->domain.
+ *
+ * If "bset" is not bounded by any constraint, then we contruct
+ * the expression "1", i.e., "true".
+ *
+ * Otherwise, we sort the constraints, putting constraints that involve
+ * integer divisions after those that do not, and construct an "and"
+ * of the ast expressions of the individual constraints.
+ *
+ * Each constraint is added to the generated constraints of the build
+ * after it has been converted to an AST expression so that it can be used
+ * to simplify the following constraints.  This may change the truth value
+ * of subsequent constraints that do not satisfy the earlier constraints,
+ * but this does not affect the outcome of the conjunction as it is
+ * only true if all the conjuncts are true (no matter in what order
+ * they are evaluated).  In particular, the constraints that do not
+ * involve integer divisions may serve to simplify some constraints
+ * that do involve integer divisions.
+ */
+__isl_give isl_ast_expr *isl_ast_build_expr_from_basic_set(
+	 __isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset)
+{
+	int i, n;
+	isl_constraint *c;
+	isl_constraint_list *list;
+	isl_ast_expr *res;
+	isl_set *set;
+
+	list = isl_basic_set_get_constraint_list(bset);
+	isl_basic_set_free(bset);
+	list = isl_constraint_list_sort(list, &cmp_constraint, NULL);
+	if (!list)
+		return NULL;
+	n = isl_constraint_list_n_constraint(list);
+	if (n == 0) {
+		isl_ctx *ctx = isl_constraint_list_get_ctx(list);
+		isl_constraint_list_free(list);
+		return isl_ast_expr_alloc_int_si(ctx, 1);
+	}
+
+	build = isl_ast_build_copy(build);
+
+	c = isl_constraint_list_get_constraint(list, 0);
+	bset = isl_basic_set_from_constraint(isl_constraint_copy(c));
+	set = isl_set_from_basic_set(bset);
+	res = isl_ast_expr_from_constraint(c, build);
+	build = isl_ast_build_restrict_generated(build, set);
+
+	for (i = 1; i < n; ++i) {
+		isl_ast_expr *expr;
+
+		c = isl_constraint_list_get_constraint(list, i);
+		bset = isl_basic_set_from_constraint(isl_constraint_copy(c));
+		set = isl_set_from_basic_set(bset);
+		expr = isl_ast_expr_from_constraint(c, build);
+		build = isl_ast_build_restrict_generated(build, set);
+		res = isl_ast_expr_and(res, expr);
+	}
+
+	isl_constraint_list_free(list);
+	isl_ast_build_free(build);
+	return res;
+}
+
+/* Construct an isl_ast_expr that evaluates the conditions defining "set".
+ * The result is simplified in terms of build->domain.
+ *
+ * If "set" is an (obviously) empty set, then return the expression "0".
+ *
+ * If there are multiple disjuncts in the description of the set,
+ * then subsequent disjuncts are simplified in a context where
+ * the previous disjuncts have been removed from build->domain.
+ * In particular, constraints that ensure that there is no overlap
+ * with these previous disjuncts, can be removed.
+ * This is mostly useful for disjuncts that are only defined by
+ * a single constraint (relative to the build domain) as the opposite
+ * of that single constraint can then be removed from the other disjuncts.
+ * In order not to increase the number of disjuncts in the build domain
+ * after subtracting the previous disjuncts of "set", the simple hull
+ * is computed after taking the difference with each of these disjuncts.
+ * This means that constraints that prevent overlap with a union
+ * of multiple previous disjuncts are not removed.
+ *
+ * "set" lives in the internal schedule space.
+ */
+__isl_give isl_ast_expr *isl_ast_build_expr_from_set_internal(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *set)
+{
+	int i, n;
+	isl_basic_set *bset;
+	isl_basic_set_list *list;
+	isl_set *domain;
+	isl_ast_expr *res;
+
+	list = isl_set_get_basic_set_list(set);
+	isl_set_free(set);
+
+	if (!list)
+		return NULL;
+	n = isl_basic_set_list_n_basic_set(list);
+	if (n == 0) {
+		isl_ctx *ctx = isl_ast_build_get_ctx(build);
+		isl_basic_set_list_free(list);
+		return isl_ast_expr_from_val(isl_val_zero(ctx));
+	}
+
+	domain = isl_ast_build_get_domain(build);
+
+	bset = isl_basic_set_list_get_basic_set(list, 0);
+	set = isl_set_from_basic_set(isl_basic_set_copy(bset));
+	res = isl_ast_build_expr_from_basic_set(build, bset);
+
+	for (i = 1; i < n; ++i) {
+		isl_ast_expr *expr;
+		isl_set *rest;
+
+		rest = isl_set_subtract(isl_set_copy(domain), set);
+		rest = isl_set_from_basic_set(isl_set_simple_hull(rest));
+		domain = isl_set_intersect(domain, rest);
+		bset = isl_basic_set_list_get_basic_set(list, i);
+		set = isl_set_from_basic_set(isl_basic_set_copy(bset));
+		bset = isl_basic_set_gist(bset,
+				isl_set_simple_hull(isl_set_copy(domain)));
+		expr = isl_ast_build_expr_from_basic_set(build, bset);
+		res = isl_ast_expr_or(res, expr);
+	}
+
+	isl_set_free(domain);
+	isl_set_free(set);
+	isl_basic_set_list_free(list);
+	return res;
+}
+
+/* Construct an isl_ast_expr that evaluates the conditions defining "set".
+ * The result is simplified in terms of build->domain.
+ *
+ * If "set" is an (obviously) empty set, then return the expression "0".
+ *
+ * "set" lives in the external schedule space.
+ *
+ * The internal AST expression generation assumes that there are
+ * no unknown divs, so make sure an explicit representation is available.
+ * Since the set comes from the outside, it may have constraints that
+ * are redundant with respect to the build domain.  Remove them first.
+ */
+__isl_give isl_ast_expr *isl_ast_build_expr_from_set(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *set)
+{
+	if (isl_ast_build_need_schedule_map(build)) {
+		isl_multi_aff *ma;
+		ma = isl_ast_build_get_schedule_map_multi_aff(build);
+		set = isl_set_preimage_multi_aff(set, ma);
+	}
+
+	set = isl_set_compute_divs(set);
+	set = isl_ast_build_compute_gist(build, set);
+	return isl_ast_build_expr_from_set_internal(build, set);
+}
+
+/* State of data about previous pieces in
+ * isl_ast_build_expr_from_pw_aff_internal.
+ *
+ * isl_state_none: no data about previous pieces
+ * isl_state_single: data about a single previous piece
+ * isl_state_min: data represents minimum of several pieces
+ * isl_state_max: data represents maximum of several pieces
+ */
+enum isl_from_pw_aff_state {
+	isl_state_none,
+	isl_state_single,
+	isl_state_min,
+	isl_state_max
+};
+
+/* Internal date structure representing a single piece in the input of
+ * isl_ast_build_expr_from_pw_aff_internal.
+ *
+ * If "state" is isl_state_none, then "set_list" and "aff_list" are not used.
+ * If "state" is isl_state_single, then "set_list" and "aff_list" contain the
+ * single previous subpiece.
+ * If "state" is isl_state_min, then "set_list" and "aff_list" contain
+ * a sequence of several previous subpieces that are equal to the minimum
+ * of the entries in "aff_list" over the union of "set_list"
+ * If "state" is isl_state_max, then "set_list" and "aff_list" contain
+ * a sequence of several previous subpieces that are equal to the maximum
+ * of the entries in "aff_list" over the union of "set_list"
+ *
+ * During the construction of the pieces, "set" is NULL.
+ * After the construction, "set" is set to the union of the elements
+ * in "set_list", at which point "set_list" is set to NULL.
+ */
+struct isl_from_pw_aff_piece {
+	enum isl_from_pw_aff_state state;
+	isl_set *set;
+	isl_set_list *set_list;
+	isl_aff_list *aff_list;
+};
+
+/* Internal data structure for isl_ast_build_expr_from_pw_aff_internal.
+ *
+ * "build" specifies the domain against which the result is simplified.
+ * "dom" is the domain of the entire isl_pw_aff.
+ *
+ * "n" is the number of pieces constructed already.
+ * In particular, during the construction of the pieces, "n" points to
+ * the piece that is being constructed.  After the construction of the
+ * pieces, "n" is set to the total number of pieces.
+ * "max" is the total number of allocated entries.
+ * "p" contains the individual pieces.
+ */
+struct isl_from_pw_aff_data {
+	isl_ast_build *build;
+	isl_set *dom;
+
+	int n;
+	int max;
+	struct isl_from_pw_aff_piece *p;
+};
+
+/* Initialize "data" based on "build" and "pa".
+ */
+static isl_stat isl_from_pw_aff_data_init(struct isl_from_pw_aff_data *data,
+	__isl_keep isl_ast_build *build, __isl_keep isl_pw_aff *pa)
+{
+	int n;
+	isl_ctx *ctx;
+
+	ctx = isl_pw_aff_get_ctx(pa);
+	n = isl_pw_aff_n_piece(pa);
+	if (n == 0)
+		isl_die(ctx, isl_error_invalid,
+			"cannot handle void expression", return isl_stat_error);
+	data->max = n;
+	data->p = isl_calloc_array(ctx, struct isl_from_pw_aff_piece, n);
+	if (!data->p)
+		return isl_stat_error;
+	data->build = build;
+	data->dom = isl_pw_aff_domain(isl_pw_aff_copy(pa));
+	data->n = 0;
+
+	return isl_stat_ok;
+}
+
+/* Free all memory allocated for "data".
+ */
+static void isl_from_pw_aff_data_clear(struct isl_from_pw_aff_data *data)
+{
+	int i;
+
+	isl_set_free(data->dom);
+	if (!data->p)
+		return;
+
+	for (i = 0; i < data->max; ++i) {
+		isl_set_free(data->p[i].set);
+		isl_set_list_free(data->p[i].set_list);
+		isl_aff_list_free(data->p[i].aff_list);
+	}
+	free(data->p);
+}
+
+/* Initialize the current entry of "data" to an unused piece.
+ */
+static void set_none(struct isl_from_pw_aff_data *data)
+{
+	data->p[data->n].state = isl_state_none;
+	data->p[data->n].set_list = NULL;
+	data->p[data->n].aff_list = NULL;
+}
+
+/* Store "set" and "aff" in the current entry of "data" as a single subpiece.
+ */
+static void set_single(struct isl_from_pw_aff_data *data,
+	__isl_take isl_set *set, __isl_take isl_aff *aff)
+{
+	data->p[data->n].state = isl_state_single;
+	data->p[data->n].set_list = isl_set_list_from_set(set);
+	data->p[data->n].aff_list = isl_aff_list_from_aff(aff);
+}
+
+/* Extend the current entry of "data" with "set" and "aff"
+ * as a minimum expression.
+ */
+static isl_stat extend_min(struct isl_from_pw_aff_data *data,
+	__isl_take isl_set *set, __isl_take isl_aff *aff)
+{
+	int n = data->n;
+	data->p[n].state = isl_state_min;
+	data->p[n].set_list = isl_set_list_add(data->p[n].set_list, set);
+	data->p[n].aff_list = isl_aff_list_add(data->p[n].aff_list, aff);
+
+	if (!data->p[n].set_list || !data->p[n].aff_list)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Extend the current entry of "data" with "set" and "aff"
+ * as a maximum expression.
+ */
+static isl_stat extend_max(struct isl_from_pw_aff_data *data,
+	__isl_take isl_set *set, __isl_take isl_aff *aff)
+{
+	int n = data->n;
+	data->p[n].state = isl_state_max;
+	data->p[n].set_list = isl_set_list_add(data->p[n].set_list, set);
+	data->p[n].aff_list = isl_aff_list_add(data->p[n].aff_list, aff);
+
+	if (!data->p[n].set_list || !data->p[n].aff_list)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Extend the domain of the current entry of "data", which is assumed
+ * to contain a single subpiece, with "set".  If "replace" is set,
+ * then also replace the affine function by "aff".  Otherwise,
+ * simply free "aff".
+ */
+static isl_stat extend_domain(struct isl_from_pw_aff_data *data,
+	__isl_take isl_set *set, __isl_take isl_aff *aff, int replace)
+{
+	int n = data->n;
+	isl_set *set_n;
+
+	set_n = isl_set_list_get_set(data->p[n].set_list, 0);
+	set_n = isl_set_union(set_n, set);
+	data->p[n].set_list =
+		isl_set_list_set_set(data->p[n].set_list, 0, set_n);
+
+	if (replace)
+		data->p[n].aff_list =
+			isl_aff_list_set_aff(data->p[n].aff_list, 0, aff);
+	else
+		isl_aff_free(aff);
+
+	if (!data->p[n].set_list || !data->p[n].aff_list)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Construct an isl_ast_expr from "list" within "build".
+ * If "state" is isl_state_single, then "list" contains a single entry and
+ * an isl_ast_expr is constructed for that entry.
+ * Otherwise a min or max expression is constructed from "list"
+ * depending on "state".
+ */
+static __isl_give isl_ast_expr *ast_expr_from_aff_list(
+	__isl_take isl_aff_list *list, enum isl_from_pw_aff_state state,
+	__isl_keep isl_ast_build *build)
+{
+	int i, n;
+	isl_aff *aff;
+	isl_ast_expr *expr;
+	enum isl_ast_op_type op_type;
+
+	if (state == isl_state_single) {
+		aff = isl_aff_list_get_aff(list, 0);
+		isl_aff_list_free(list);
+		return isl_ast_expr_from_aff(aff, build);
+	}
+	n = isl_aff_list_n_aff(list);
+	op_type = state == isl_state_min ? isl_ast_op_min : isl_ast_op_max;
+	expr = isl_ast_expr_alloc_op(isl_ast_build_get_ctx(build), op_type, n);
+	if (!expr)
+		goto error;
+
+	for (i = 0; i < n; ++i) {
+		isl_ast_expr *expr_i;
+
+		aff = isl_aff_list_get_aff(list, i);
+		expr_i = isl_ast_expr_from_aff(aff, build);
+		if (!expr_i)
+			goto error;
+		expr->u.op.args[i] = expr_i;
+	}
+
+	isl_aff_list_free(list);
+	return expr;
+error:
+	isl_aff_list_free(list);
+	isl_ast_expr_free(expr);
+	return NULL;
+}
+
+/* Extend the expression in "next" to take into account
+ * the piece at position "pos" in "data", allowing for a further extension
+ * for the next piece(s).
+ * In particular, "next" is set to a select operation that selects
+ * an isl_ast_expr corresponding to data->aff_list on data->set and
+ * to an expression that will be filled in by later calls.
+ * Return a pointer to this location.
+ * Afterwards, the state of "data" is set to isl_state_none.
+ *
+ * The constraints of data->set are added to the generated
+ * constraints of the build such that they can be exploited to simplify
+ * the AST expression constructed from data->aff_list.
+ */
+static isl_ast_expr **add_intermediate_piece(struct isl_from_pw_aff_data *data,
+	int pos, isl_ast_expr **next)
+{
+	isl_ctx *ctx;
+	isl_ast_build *build;
+	isl_ast_expr *ternary, *arg;
+	isl_set *set, *gist;
+
+	set = data->p[pos].set;
+	data->p[pos].set = NULL;
+	ctx = isl_ast_build_get_ctx(data->build);
+	ternary = isl_ast_expr_alloc_op(ctx, isl_ast_op_select, 3);
+	gist = isl_set_gist(isl_set_copy(set), isl_set_copy(data->dom));
+	arg = isl_ast_build_expr_from_set_internal(data->build, gist);
+	ternary = isl_ast_expr_set_op_arg(ternary, 0, arg);
+	build = isl_ast_build_copy(data->build);
+	build = isl_ast_build_restrict_generated(build, set);
+	arg = ast_expr_from_aff_list(data->p[pos].aff_list,
+					data->p[pos].state, build);
+	data->p[pos].aff_list = NULL;
+	isl_ast_build_free(build);
+	ternary = isl_ast_expr_set_op_arg(ternary, 1, arg);
+	data->p[pos].state = isl_state_none;
+	if (!ternary)
+		return NULL;
+
+	*next = ternary;
+	return &ternary->u.op.args[2];
+}
+
+/* Extend the expression in "next" to take into account
+ * the final piece, located at position "pos" in "data".
+ * In particular, "next" is set to evaluate data->aff_list
+ * and the domain is ignored.
+ * Return isl_stat_ok on success and isl_stat_error on failure.
+ *
+ * The constraints of data->set are however added to the generated
+ * constraints of the build such that they can be exploited to simplify
+ * the AST expression constructed from data->aff_list.
+ */
+static isl_stat add_last_piece(struct isl_from_pw_aff_data *data,
+	int pos, isl_ast_expr **next)
+{
+	isl_ast_build *build;
+
+	if (data->p[pos].state == isl_state_none)
+		isl_die(isl_ast_build_get_ctx(data->build), isl_error_invalid,
+			"cannot handle void expression", return isl_stat_error);
+
+	build = isl_ast_build_copy(data->build);
+	build = isl_ast_build_restrict_generated(build, data->p[pos].set);
+	data->p[pos].set = NULL;
+	*next = ast_expr_from_aff_list(data->p[pos].aff_list,
+						data->p[pos].state, build);
+	data->p[pos].aff_list = NULL;
+	isl_ast_build_free(build);
+	data->p[pos].state = isl_state_none;
+	if (!*next)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Return -1 if the piece "p1" should be sorted before "p2"
+ * and 1 if it should be sorted after "p2".
+ * Return 0 if they do not need to be sorted in a specific order.
+ *
+ * Pieces are sorted according to the number of disjuncts
+ * in their domains.
+ */
+static int sort_pieces_cmp(const void *p1, const void *p2, void *arg)
+{
+	const struct isl_from_pw_aff_piece *piece1 = p1;
+	const struct isl_from_pw_aff_piece *piece2 = p2;
+	int n1, n2;
+
+	n1 = isl_set_n_basic_set(piece1->set);
+	n2 = isl_set_n_basic_set(piece2->set);
+
+	return n1 - n2;
+}
+
+/* Construct an isl_ast_expr from the pieces in "data".
+ * Return the result or NULL on failure.
+ *
+ * When this function is called, data->n points to the current piece.
+ * If this is an effective piece, then first increment data->n such
+ * that data->n contains the number of pieces.
+ * The "set_list" fields are subsequently replaced by the corresponding
+ * "set" fields, after which the pieces are sorted according to
+ * the number of disjuncts in these "set" fields.
+ *
+ * Construct intermediate AST expressions for the initial pieces and
+ * finish off with the final pieces.
+ */
+static isl_ast_expr *build_pieces(struct isl_from_pw_aff_data *data)
+{
+	int i;
+	isl_ast_expr *res = NULL;
+	isl_ast_expr **next = &res;
+
+	if (data->p[data->n].state != isl_state_none)
+		data->n++;
+	if (data->n == 0)
+		isl_die(isl_ast_build_get_ctx(data->build), isl_error_invalid,
+			"cannot handle void expression", return NULL);
+
+	for (i = 0; i < data->n; ++i) {
+		data->p[i].set = isl_set_list_union(data->p[i].set_list);
+		if (data->p[i].state != isl_state_single)
+			data->p[i].set = isl_set_coalesce(data->p[i].set);
+		data->p[i].set_list = NULL;
+	}
+
+	if (isl_sort(data->p, data->n, sizeof(data->p[0]),
+			&sort_pieces_cmp, NULL) < 0)
+		return isl_ast_expr_free(res);
+
+	for (i = 0; i + 1 < data->n; ++i) {
+		next = add_intermediate_piece(data, i, next);
+		if (!next)
+			return isl_ast_expr_free(res);
+	}
+
+	if (add_last_piece(data, data->n - 1, next) < 0)
+		return isl_ast_expr_free(res);
+
+	return res;
+}
+
+/* Is the domain of the current entry of "data", which is assumed
+ * to contain a single subpiece, a subset of "set"?
+ */
+static isl_bool single_is_subset(struct isl_from_pw_aff_data *data,
+	__isl_keep isl_set *set)
+{
+	isl_bool subset;
+	isl_set *set_n;
+
+	set_n = isl_set_list_get_set(data->p[data->n].set_list, 0);
+	subset = isl_set_is_subset(set_n, set);
+	isl_set_free(set_n);
+
+	return subset;
+}
+
+/* Is "aff" a rational expression, i.e., does it have a denominator
+ * different from one?
+ */
+static isl_bool aff_is_rational(__isl_keep isl_aff *aff)
+{
+	isl_bool rational;
+	isl_val *den;
+
+	den = isl_aff_get_denominator_val(aff);
+	rational = isl_bool_not(isl_val_is_one(den));
+	isl_val_free(den);
+
+	return rational;
+}
+
+/* Does "list" consist of a single rational affine expression?
+ */
+static isl_bool is_single_rational_aff(__isl_keep isl_aff_list *list)
+{
+	isl_bool rational;
+	isl_aff *aff;
+
+	if (isl_aff_list_n_aff(list) != 1)
+		return isl_bool_false;
+	aff = isl_aff_list_get_aff(list, 0);
+	rational = aff_is_rational(aff);
+	isl_aff_free(aff);
+
+	return rational;
+}
+
+/* Can the list of subpieces in the last piece of "data" be extended with
+ * "set" and "aff" based on "test"?
+ * In particular, is it the case for each entry (set_i, aff_i) that
+ *
+ *	test(aff, aff_i) holds on set_i, and
+ *	test(aff_i, aff) holds on set?
+ *
+ * "test" returns the set of elements where the tests holds, meaning
+ * that test(aff_i, aff) holds on set if set is a subset of test(aff_i, aff).
+ *
+ * This function is used to detect min/max expressions.
+ * If the ast_build_detect_min_max option is turned off, then
+ * do not even try and perform any detection and return false instead.
+ *
+ * Rational affine expressions are not considered for min/max expressions
+ * since the combined expression will be defined on the union of the domains,
+ * while a rational expression may only yield integer values
+ * on its own definition domain.
+ */
+static isl_bool extends(struct isl_from_pw_aff_data *data,
+	__isl_keep isl_set *set, __isl_keep isl_aff *aff,
+	__isl_give isl_basic_set *(*test)(__isl_take isl_aff *aff1,
+		__isl_take isl_aff *aff2))
+{
+	int i, n;
+	isl_bool is_rational;
+	isl_ctx *ctx;
+	isl_set *dom;
+
+	is_rational = aff_is_rational(aff);
+	if (is_rational >= 0 && !is_rational)
+		is_rational = is_single_rational_aff(data->p[data->n].aff_list);
+	if (is_rational < 0 || is_rational)
+		return isl_bool_not(is_rational);
+
+	ctx = isl_ast_build_get_ctx(data->build);
+	if (!isl_options_get_ast_build_detect_min_max(ctx))
+		return isl_bool_false;
+
+	dom = isl_ast_build_get_domain(data->build);
+	set = isl_set_intersect(dom, isl_set_copy(set));
+
+	n = isl_set_list_n_set(data->p[data->n].set_list);
+	for (i = 0; i < n ; ++i) {
+		isl_aff *aff_i;
+		isl_set *valid;
+		isl_set *dom, *required;
+		isl_bool is_valid;
+
+		aff_i = isl_aff_list_get_aff(data->p[data->n].aff_list, i);
+		valid = isl_set_from_basic_set(test(isl_aff_copy(aff), aff_i));
+		required = isl_set_list_get_set(data->p[data->n].set_list, i);
+		dom = isl_ast_build_get_domain(data->build);
+		required = isl_set_intersect(dom, required);
+		is_valid = isl_set_is_subset(required, valid);
+		isl_set_free(required);
+		isl_set_free(valid);
+		if (is_valid < 0 || !is_valid) {
+			isl_set_free(set);
+			return is_valid;
+		}
+
+		aff_i = isl_aff_list_get_aff(data->p[data->n].aff_list, i);
+		valid = isl_set_from_basic_set(test(aff_i, isl_aff_copy(aff)));
+		is_valid = isl_set_is_subset(set, valid);
+		isl_set_free(valid);
+		if (is_valid < 0 || !is_valid) {
+			isl_set_free(set);
+			return is_valid;
+		}
+	}
+
+	isl_set_free(set);
+	return isl_bool_true;
+}
+
+/* Can the list of pieces in "data" be extended with "set" and "aff"
+ * to form/preserve a minimum expression?
+ * In particular, is it the case for each entry (set_i, aff_i) that
+ *
+ *	aff >= aff_i on set_i, and
+ *	aff_i >= aff on set?
+ */
+static isl_bool extends_min(struct isl_from_pw_aff_data *data,
+	__isl_keep isl_set *set,  __isl_keep isl_aff *aff)
+{
+	return extends(data, set, aff, &isl_aff_ge_basic_set);
+}
+
+/* Can the list of pieces in "data" be extended with "set" and "aff"
+ * to form/preserve a maximum expression?
+ * In particular, is it the case for each entry (set_i, aff_i) that
+ *
+ *	aff <= aff_i on set_i, and
+ *	aff_i <= aff on set?
+ */
+static isl_bool extends_max(struct isl_from_pw_aff_data *data,
+	__isl_keep isl_set *set,  __isl_keep isl_aff *aff)
+{
+	return extends(data, set, aff, &isl_aff_le_basic_set);
+}
+
+/* This function is called during the construction of an isl_ast_expr
+ * that evaluates an isl_pw_aff.
+ * If the last piece of "data" contains a single subpiece and
+ * if its affine function is equal to "aff" on a part of the domain
+ * that includes either "set" or the domain of that single subpiece,
+ * then extend the domain of that single subpiece with "set".
+ * If it was the original domain of the single subpiece where
+ * the two affine functions are equal, then also replace
+ * the affine function of the single subpiece by "aff".
+ * If the last piece of "data" contains either a single subpiece
+ * or a minimum, then check if this minimum expression can be extended
+ * with (set, aff).
+ * If so, extend the sequence and return.
+ * Perform the same operation for maximum expressions.
+ * If no such extension can be performed, then move to the next piece
+ * in "data" (if the current piece contains any data), and then store
+ * the current subpiece in the current piece of "data" for later handling.
+ */
+static isl_stat ast_expr_from_pw_aff(__isl_take isl_set *set,
+	__isl_take isl_aff *aff, void *user)
+{
+	struct isl_from_pw_aff_data *data = user;
+	isl_bool test;
+	enum isl_from_pw_aff_state state;
+
+	state = data->p[data->n].state;
+	if (state == isl_state_single) {
+		isl_aff *aff0;
+		isl_set *eq;
+		isl_bool subset1, subset2 = isl_bool_false;
+		aff0 = isl_aff_list_get_aff(data->p[data->n].aff_list, 0);
+		eq = isl_aff_eq_set(isl_aff_copy(aff), aff0);
+		subset1 = isl_set_is_subset(set, eq);
+		if (subset1 >= 0 && !subset1)
+			subset2 = single_is_subset(data, eq);
+		isl_set_free(eq);
+		if (subset1 < 0 || subset2 < 0)
+			goto error;
+		if (subset1)
+			return extend_domain(data, set, aff, 0);
+		if (subset2)
+			return extend_domain(data, set, aff, 1);
+	}
+	if (state == isl_state_single || state == isl_state_min) {
+		test = extends_min(data, set, aff);
+		if (test < 0)
+			goto error;
+		if (test)
+			return extend_min(data, set, aff);
+	}
+	if (state == isl_state_single || state == isl_state_max) {
+		test = extends_max(data, set, aff);
+		if (test < 0)
+			goto error;
+		if (test)
+			return extend_max(data, set, aff);
+	}
+	if (state != isl_state_none)
+		data->n++;
+	set_single(data, set, aff);
+
+	return isl_stat_ok;
+error:
+	isl_set_free(set);
+	isl_aff_free(aff);
+	return isl_stat_error;
+}
+
+/* Construct an isl_ast_expr that evaluates "pa".
+ * The result is simplified in terms of build->domain.
+ *
+ * The domain of "pa" lives in the internal schedule space.
+ */
+__isl_give isl_ast_expr *isl_ast_build_expr_from_pw_aff_internal(
+	__isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa)
+{
+	struct isl_from_pw_aff_data data = { NULL };
+	isl_ast_expr *res = NULL;
+
+	pa = isl_ast_build_compute_gist_pw_aff(build, pa);
+	pa = isl_pw_aff_coalesce(pa);
+	if (!pa)
+		return NULL;
+
+	if (isl_from_pw_aff_data_init(&data, build, pa) < 0)
+		goto error;
+	set_none(&data);
+
+	if (isl_pw_aff_foreach_piece(pa, &ast_expr_from_pw_aff, &data) >= 0)
+		res = build_pieces(&data);
+
+	isl_pw_aff_free(pa);
+	isl_from_pw_aff_data_clear(&data);
+	return res;
+error:
+	isl_pw_aff_free(pa);
+	isl_from_pw_aff_data_clear(&data);
+	return NULL;
+}
+
+/* Construct an isl_ast_expr that evaluates "pa".
+ * The result is simplified in terms of build->domain.
+ *
+ * The domain of "pa" lives in the external schedule space.
+ */
+__isl_give isl_ast_expr *isl_ast_build_expr_from_pw_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa)
+{
+	isl_ast_expr *expr;
+
+	if (isl_ast_build_need_schedule_map(build)) {
+		isl_multi_aff *ma;
+		ma = isl_ast_build_get_schedule_map_multi_aff(build);
+		pa = isl_pw_aff_pullback_multi_aff(pa, ma);
+	}
+	expr = isl_ast_build_expr_from_pw_aff_internal(build, pa);
+	return expr;
+}
+
+/* Set the ids of the input dimensions of "mpa" to the iterator ids
+ * of "build".
+ *
+ * The domain of "mpa" is assumed to live in the internal schedule domain.
+ */
+static __isl_give isl_multi_pw_aff *set_iterator_names(
+	__isl_keep isl_ast_build *build, __isl_take isl_multi_pw_aff *mpa)
+{
+	int i, n;
+
+	n = isl_multi_pw_aff_dim(mpa, isl_dim_in);
+	for (i = 0; i < n; ++i) {
+		isl_id *id;
+
+		id = isl_ast_build_get_iterator_id(build, i);
+		mpa = isl_multi_pw_aff_set_dim_id(mpa, isl_dim_in, i, id);
+	}
+
+	return mpa;
+}
+
+/* Construct an isl_ast_expr of type "type" with as first argument "arg0" and
+ * the remaining arguments derived from "mpa".
+ * That is, construct a call or access expression that calls/accesses "arg0"
+ * with arguments/indices specified by "mpa".
+ */
+static __isl_give isl_ast_expr *isl_ast_build_with_arguments(
+	__isl_keep isl_ast_build *build, enum isl_ast_op_type type,
+	__isl_take isl_ast_expr *arg0, __isl_take isl_multi_pw_aff *mpa)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_ast_expr *expr;
+
+	ctx = isl_ast_build_get_ctx(build);
+
+	n = isl_multi_pw_aff_dim(mpa, isl_dim_out);
+	expr = isl_ast_expr_alloc_op(ctx, type, 1 + n);
+	expr = isl_ast_expr_set_op_arg(expr, 0, arg0);
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+		isl_ast_expr *arg;
+
+		pa = isl_multi_pw_aff_get_pw_aff(mpa, i);
+		arg = isl_ast_build_expr_from_pw_aff_internal(build, pa);
+		expr = isl_ast_expr_set_op_arg(expr, 1 + i, arg);
+	}
+
+	isl_multi_pw_aff_free(mpa);
+	return expr;
+}
+
+static __isl_give isl_ast_expr *isl_ast_build_from_multi_pw_aff_internal(
+	__isl_keep isl_ast_build *build, enum isl_ast_op_type type,
+	__isl_take isl_multi_pw_aff *mpa);
+
+/* Construct an isl_ast_expr that accesses the member specified by "mpa".
+ * The range of "mpa" is assumed to be wrapped relation.
+ * The domain of this wrapped relation specifies the structure being
+ * accessed, while the range of this wrapped relation spacifies the
+ * member of the structure being accessed.
+ *
+ * The domain of "mpa" is assumed to live in the internal schedule domain.
+ */
+static __isl_give isl_ast_expr *isl_ast_build_from_multi_pw_aff_member(
+	__isl_keep isl_ast_build *build, __isl_take isl_multi_pw_aff *mpa)
+{
+	isl_id *id;
+	isl_multi_pw_aff *domain;
+	isl_ast_expr *domain_expr, *expr;
+	enum isl_ast_op_type type = isl_ast_op_access;
+
+	domain = isl_multi_pw_aff_copy(mpa);
+	domain = isl_multi_pw_aff_range_factor_domain(domain);
+	domain_expr = isl_ast_build_from_multi_pw_aff_internal(build,
+								type, domain);
+	mpa = isl_multi_pw_aff_range_factor_range(mpa);
+	if (!isl_multi_pw_aff_has_tuple_id(mpa, isl_dim_out))
+		isl_die(isl_ast_build_get_ctx(build), isl_error_invalid,
+			"missing field name", goto error);
+	id = isl_multi_pw_aff_get_tuple_id(mpa, isl_dim_out);
+	expr = isl_ast_expr_from_id(id);
+	expr = isl_ast_expr_alloc_binary(isl_ast_op_member, domain_expr, expr);
+	return isl_ast_build_with_arguments(build, type, expr, mpa);
+error:
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Construct an isl_ast_expr of type "type" that calls or accesses
+ * the element specified by "mpa".
+ * The first argument is obtained from the output tuple name.
+ * The remaining arguments are given by the piecewise affine expressions.
+ *
+ * If the range of "mpa" is a mapped relation, then we assume it
+ * represents an access to a member of a structure.
+ *
+ * The domain of "mpa" is assumed to live in the internal schedule domain.
+ */
+static __isl_give isl_ast_expr *isl_ast_build_from_multi_pw_aff_internal(
+	__isl_keep isl_ast_build *build, enum isl_ast_op_type type,
+	__isl_take isl_multi_pw_aff *mpa)
+{
+	isl_ctx *ctx;
+	isl_id *id;
+	isl_ast_expr *expr;
+
+	if (!mpa)
+		goto error;
+
+	if (type == isl_ast_op_access &&
+	    isl_multi_pw_aff_range_is_wrapping(mpa))
+		return isl_ast_build_from_multi_pw_aff_member(build, mpa);
+
+	mpa = set_iterator_names(build, mpa);
+	if (!build || !mpa)
+		goto error;
+
+	ctx = isl_ast_build_get_ctx(build);
+
+	if (isl_multi_pw_aff_has_tuple_id(mpa, isl_dim_out))
+		id = isl_multi_pw_aff_get_tuple_id(mpa, isl_dim_out);
+	else
+		id = isl_id_alloc(ctx, "", NULL);
+
+	expr = isl_ast_expr_from_id(id);
+	return isl_ast_build_with_arguments(build, type, expr, mpa);
+error:
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Construct an isl_ast_expr of type "type" that calls or accesses
+ * the element specified by "pma".
+ * The first argument is obtained from the output tuple name.
+ * The remaining arguments are given by the piecewise affine expressions.
+ *
+ * The domain of "pma" is assumed to live in the internal schedule domain.
+ */
+static __isl_give isl_ast_expr *isl_ast_build_from_pw_multi_aff_internal(
+	__isl_keep isl_ast_build *build, enum isl_ast_op_type type,
+	__isl_take isl_pw_multi_aff *pma)
+{
+	isl_multi_pw_aff *mpa;
+
+	mpa = isl_multi_pw_aff_from_pw_multi_aff(pma);
+	return isl_ast_build_from_multi_pw_aff_internal(build, type, mpa);
+}
+
+/* Construct an isl_ast_expr of type "type" that calls or accesses
+ * the element specified by "mpa".
+ * The first argument is obtained from the output tuple name.
+ * The remaining arguments are given by the piecewise affine expressions.
+ *
+ * The domain of "mpa" is assumed to live in the external schedule domain.
+ */
+static __isl_give isl_ast_expr *isl_ast_build_from_multi_pw_aff(
+	__isl_keep isl_ast_build *build, enum isl_ast_op_type type,
+	__isl_take isl_multi_pw_aff *mpa)
+{
+	int is_domain;
+	isl_ast_expr *expr;
+	isl_space *space_build, *space_mpa;
+
+	space_build = isl_ast_build_get_space(build, 0);
+	space_mpa = isl_multi_pw_aff_get_space(mpa);
+	is_domain = isl_space_tuple_is_equal(space_build, isl_dim_set,
+					space_mpa, isl_dim_in);
+	isl_space_free(space_build);
+	isl_space_free(space_mpa);
+	if (is_domain < 0)
+		goto error;
+	if (!is_domain)
+		isl_die(isl_ast_build_get_ctx(build), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	if (isl_ast_build_need_schedule_map(build)) {
+		isl_multi_aff *ma;
+		ma = isl_ast_build_get_schedule_map_multi_aff(build);
+		mpa = isl_multi_pw_aff_pullback_multi_aff(mpa, ma);
+	}
+
+	expr = isl_ast_build_from_multi_pw_aff_internal(build, type, mpa);
+	return expr;
+error:
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Construct an isl_ast_expr that calls the domain element specified by "mpa".
+ * The name of the function is obtained from the output tuple name.
+ * The arguments are given by the piecewise affine expressions.
+ *
+ * The domain of "mpa" is assumed to live in the external schedule domain.
+ */
+__isl_give isl_ast_expr *isl_ast_build_call_from_multi_pw_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_multi_pw_aff *mpa)
+{
+	return isl_ast_build_from_multi_pw_aff(build, isl_ast_op_call, mpa);
+}
+
+/* Construct an isl_ast_expr that accesses the array element specified by "mpa".
+ * The name of the array is obtained from the output tuple name.
+ * The index expressions are given by the piecewise affine expressions.
+ *
+ * The domain of "mpa" is assumed to live in the external schedule domain.
+ */
+__isl_give isl_ast_expr *isl_ast_build_access_from_multi_pw_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_multi_pw_aff *mpa)
+{
+	return isl_ast_build_from_multi_pw_aff(build, isl_ast_op_access, mpa);
+}
+
+/* Construct an isl_ast_expr of type "type" that calls or accesses
+ * the element specified by "pma".
+ * The first argument is obtained from the output tuple name.
+ * The remaining arguments are given by the piecewise affine expressions.
+ *
+ * The domain of "pma" is assumed to live in the external schedule domain.
+ */
+static __isl_give isl_ast_expr *isl_ast_build_from_pw_multi_aff(
+	__isl_keep isl_ast_build *build, enum isl_ast_op_type type,
+	__isl_take isl_pw_multi_aff *pma)
+{
+	isl_multi_pw_aff *mpa;
+
+	mpa = isl_multi_pw_aff_from_pw_multi_aff(pma);
+	return isl_ast_build_from_multi_pw_aff(build, type, mpa);
+}
+
+/* Construct an isl_ast_expr that calls the domain element specified by "pma".
+ * The name of the function is obtained from the output tuple name.
+ * The arguments are given by the piecewise affine expressions.
+ *
+ * The domain of "pma" is assumed to live in the external schedule domain.
+ */
+__isl_give isl_ast_expr *isl_ast_build_call_from_pw_multi_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma)
+{
+	return isl_ast_build_from_pw_multi_aff(build, isl_ast_op_call, pma);
+}
+
+/* Construct an isl_ast_expr that accesses the array element specified by "pma".
+ * The name of the array is obtained from the output tuple name.
+ * The index expressions are given by the piecewise affine expressions.
+ *
+ * The domain of "pma" is assumed to live in the external schedule domain.
+ */
+__isl_give isl_ast_expr *isl_ast_build_access_from_pw_multi_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma)
+{
+	return isl_ast_build_from_pw_multi_aff(build, isl_ast_op_access, pma);
+}
+
+/* Construct an isl_ast_expr that calls the domain element
+ * specified by "executed".
+ *
+ * "executed" is assumed to be single-valued, with a domain that lives
+ * in the internal schedule space.
+ */
+__isl_give isl_ast_node *isl_ast_build_call_from_executed(
+	__isl_keep isl_ast_build *build, __isl_take isl_map *executed)
+{
+	isl_pw_multi_aff *iteration;
+	isl_ast_expr *expr;
+
+	iteration = isl_pw_multi_aff_from_map(executed);
+	iteration = isl_ast_build_compute_gist_pw_multi_aff(build, iteration);
+	iteration = isl_pw_multi_aff_intersect_domain(iteration,
+					isl_ast_build_get_domain(build));
+	expr = isl_ast_build_from_pw_multi_aff_internal(build, isl_ast_op_call,
+							iteration);
+	return isl_ast_node_alloc_user(expr);
+}
diff --git a/final/lib/External/isl/isl_ast_build_expr.h b/final/lib/External/isl/isl_ast_build_expr.h
new file mode 100644
index 0000000..362f2bf
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_build_expr.h
@@ -0,0 +1,22 @@
+#ifndef ISL_AST_BUILD_EXPR_PRIVATE_H
+#define ISL_AST_BUILD_EXPR_PRIVATE_H
+
+#include <isl/ast.h>
+#include <isl/ast_build.h>
+
+__isl_give isl_ast_expr *isl_ast_build_expr_from_basic_set(
+	 __isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset);
+__isl_give isl_ast_expr *isl_ast_build_expr_from_set_internal(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *set);
+
+__isl_give isl_ast_expr *isl_ast_build_expr_from_pw_aff_internal(
+	__isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa);
+__isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff,
+	__isl_keep isl_ast_build *build);
+__isl_give isl_ast_expr *isl_ast_expr_set_op_arg(__isl_take isl_ast_expr *expr,
+	int pos, __isl_take isl_ast_expr *arg);
+
+__isl_give isl_ast_node *isl_ast_build_call_from_executed(
+	__isl_keep isl_ast_build *build, __isl_take isl_map *executed);
+
+#endif
diff --git a/final/lib/External/isl/isl_ast_build_private.h b/final/lib/External/isl/isl_ast_build_private.h
new file mode 100644
index 0000000..ae638c7
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_build_private.h
@@ -0,0 +1,327 @@
+#ifndef ISL_AST_BUILD_PRIVATE_H
+#define ISL_AST_BUILD_PRIVATE_H
+
+#include <isl/aff.h>
+#include <isl/ast.h>
+#include <isl/ast_build.h>
+#include <isl/set.h>
+#include <isl/list.h>
+#include <isl/schedule_node.h>
+
+/* An isl_ast_build represents the context in which AST is being
+ * generated.  That is, it (mostly) contains information about outer
+ * loops that can be used to simplify inner loops.
+ *
+ * "domain" represents constraints on the internal schedule domain,
+ * corresponding to the context of the AST generation and the constraints
+ * implied by the loops that have already been generated.
+ * When an isl_ast_build is first created, outside any AST generation,
+ * the domain is typically a parameter set.  It is only when a AST
+ * generation phase is initiated that the domain of the isl_ast_build
+ * is changed to refer to the internal schedule domain.
+ * The domain then lives in a space of the form
+ *
+ *	S
+ *
+ *  or
+ *
+ *	[O -> S]
+ *
+ * O represents the loops generated in outer AST generations.
+ * S represents the loops (both generated and to be generated)
+ * of the current AST generation.
+ * Both include eliminated loops.
+ * "domain" is expected not to have any unknown divs because
+ * it is used as the context argument in a call to isl_basic_set_gist
+ * in isl_ast_build_compute_gist_basic_set.
+ *
+ * "depth" is equal to the number of loops that have already
+ * been generated (including those in outer AST generations).
+ * "outer_pos" is equal to the number of loops in outer AST generations.
+ *
+ * "generated" is a superset of "domain" corresponding to those
+ * constraints that were either given by the user or that have
+ * effectively been generated (as bounds on a for loop).
+ *
+ * "pending" is a superset of "domain" corresponding to the constraints
+ * that still need to be generated (as guards), but that may end up
+ * not getting generated if they are implied by any constraints
+ * enforced by inner loops.
+ *
+ * "strides" contains the stride of each loop.  The number of elements
+ * is equal to the number of dimensions in "domain".
+ * "offsets" constains the offsets of strided loops.  If s is the stride
+ * for a given dimension and f is the corresponding offset, then the
+ * dimension takes on values
+ *
+ *	f + s a
+ *
+ * with a an integer.  For non-strided loops, the offset is zero.
+ *
+ * "iterators" contains the loop iterators of both generated and
+ * to be generated loops.  The number of elements is at least as
+ * large as the dimension of the internal schedule domain.  The
+ * number may be larger, in which case the additional ids can be
+ * used in a nested AST generation should the schedule be non-injective.
+ *
+ * "values" lives in the space
+ *
+ *	[O -> S] -> [O -> S]		(or S -> S)
+ *
+ * and expresses (if possible) loop iterators in terms of parameters
+ * and outer loop iterators.  If the value of a given loop iterator
+ * cannot be expressed as an affine expression (either because the iterator
+ * attains multiple values or because the single value is a piecewise
+ * affine expression), then it is expressed in "values" as being equal
+ * to itself.
+ *
+ * "value" is the value of the loop iterator at the current depth.
+ * It is NULL if it has not been computed yet or if the value of the
+ * given loop iterator cannot be expressed as a piecewise affine expression
+ * (because the iterator attains multiple values).
+ *
+ * "schedule_map" maps the internal schedule domain to the external schedule
+ * domain.  It may be NULL if it hasn't been computed yet.
+ * See isl_ast_build_get_schedule_map_multi_aff.
+ *
+ * "internal2input" maps the internal schedule domain to the original
+ * input schedule domain.  In case of a schedule tree input, the original
+ * input schedule domain consist of the flat product of all outer
+ * band node spaces, including the current band node.
+ * It may be NULL if there no longer is such a uniform mapping
+ * (because different iterations have been rescheduled differently).
+ *
+ * "options" contains the AST build options in case we are generating
+ * an AST from a flat schedule map.  When creating an AST from a schedule
+ * tree, this field is ignored.
+ *
+ * The "create_leaf" callback is called for every leaf in the generated AST.
+ * The callback is responsible for creating the node to be placed at those
+ * leaves.  If this callback is not set, then isl will generated user
+ * nodes with call expressions corresponding to an element of the domain.
+ *
+ * The "at_each_domain" callback is called on every node created to represent
+ * an element of the domain.  Each of these nodes is a user node
+ * with as expression a call expression.
+ *
+ * The "before_each_for" callback is called on each for node before
+ * its children have been created.
+ *
+ * The "after_each_for" callback is called on each for node after
+ * its children have been created.
+ *
+ * The "before_each_mark" callback is called before we handle the subtree
+ * of an isl_schedule_node_mark node.
+ *
+ * The "after_each_mark" callback is called after we have handled the subtree
+ * of an isl_schedule_node_mark node.
+ *
+ * "executed" contains the inverse schedule at this point
+ * of the AST generation.
+ * It is currently only used in isl_ast_build_get_schedule, which is
+ * in turn only used by user code from within a callback.
+ * The value is set right before we may be calling such a callback.
+ *
+ * "single_valued" is set if the current inverse schedule (which may or may
+ * not be stored in "executed") is known to be single valued, specifically
+ * an inverse schedule that was not (appeared not to be) single valued
+ * is extended to a single valued inverse schedule.  This is mainly used
+ * to avoid an infinite recursion when we fail to detect later on that
+ * the extended inverse schedule is single valued.
+ *
+ * "node" points to the current band node in case we are generating
+ * an AST from a schedule tree.  It may be NULL if we are not generating
+ * an AST from a schedule tree or if we are not inside a band node.
+ *
+ * "loop_type" originally constains loop AST generation types for
+ * the "n" members of "node" and it is updated (along with "n") when
+ * a schedule dimension is inserted.
+ * It is NULL if "node" is NULL.
+ *
+ * "isolated" is the piece of the schedule domain isolated by the isolate
+ * option on the current band.  This set may be NULL if we have not checked
+ * for the isolate option yet.
+ */
+struct isl_ast_build {
+	int ref;
+
+	int outer_pos;
+	int depth;
+
+	isl_id_list *iterators;
+
+	isl_set *domain;
+	isl_set *generated;
+	isl_set *pending;
+	isl_multi_aff *values;
+
+	isl_pw_aff *value;
+
+	isl_vec *strides;
+	isl_multi_aff *offsets;
+
+	isl_multi_aff *schedule_map;
+	isl_multi_aff *internal2input;
+
+	isl_union_map *options;
+
+	__isl_give isl_ast_node *(*at_each_domain)(
+		__isl_take isl_ast_node *node,
+		__isl_keep isl_ast_build *build, void *user);
+	void *at_each_domain_user;
+
+	__isl_give isl_id *(*before_each_for)(
+		__isl_keep isl_ast_build *context, void *user);
+	void *before_each_for_user;
+	__isl_give isl_ast_node *(*after_each_for)(
+		__isl_take isl_ast_node *node,
+		__isl_keep isl_ast_build *context, void *user);
+	void *after_each_for_user;
+
+	isl_stat (*before_each_mark)(__isl_keep isl_id *mark,
+		__isl_keep isl_ast_build *build, void *user);
+	void *before_each_mark_user;
+	__isl_give isl_ast_node *(*after_each_mark)(
+		__isl_take isl_ast_node *node,
+		__isl_keep isl_ast_build *context, void *user);
+	void *after_each_mark_user;
+
+	__isl_give isl_ast_node *(*create_leaf)(
+		__isl_take isl_ast_build *build, void *user);
+	void *create_leaf_user;
+
+	isl_union_map *executed;
+	int single_valued;
+
+	isl_schedule_node *node;
+	int n;
+	enum isl_ast_loop_type *loop_type;
+	isl_set *isolated;
+};
+
+__isl_give isl_ast_build *isl_ast_build_clear_local_info(
+	__isl_take isl_ast_build *build);
+__isl_give isl_ast_build *isl_ast_build_increase_depth(
+	__isl_take isl_ast_build *build);
+int isl_ast_build_get_depth(__isl_keep isl_ast_build *build);
+unsigned isl_ast_build_dim(__isl_keep isl_ast_build *build,
+	enum isl_dim_type type);
+__isl_give isl_space *isl_ast_build_get_space(
+	__isl_keep isl_ast_build *build, int internal);
+__isl_give isl_ast_build *isl_ast_build_align_params(
+	__isl_take isl_ast_build *build, __isl_take isl_space *model);
+__isl_give isl_ast_build *isl_ast_build_cow(
+	__isl_take isl_ast_build *build);
+__isl_give isl_ast_build *isl_ast_build_insert_dim(
+	__isl_take isl_ast_build *build, int pos);
+__isl_give isl_ast_build *isl_ast_build_scale_down(
+	__isl_take isl_ast_build *build, __isl_take isl_val *m,
+	__isl_take isl_union_map *umap);
+__isl_give isl_ast_build *isl_ast_build_product(
+	__isl_take isl_ast_build *build, __isl_take isl_space *embedding);
+__isl_give isl_ast_build *isl_ast_build_set_loop_bounds(
+	__isl_take isl_ast_build *build, __isl_take isl_basic_set *bounds);
+__isl_give isl_ast_build *isl_ast_build_set_pending_generated(
+	__isl_take isl_ast_build *build, __isl_take isl_basic_set *bounds);
+__isl_give isl_ast_build *isl_ast_build_detect_strides(
+	__isl_take isl_ast_build *build, __isl_take isl_set *set);
+__isl_give isl_ast_build *isl_ast_build_include_stride(
+	__isl_take isl_ast_build *build);
+__isl_give isl_ast_build *isl_ast_build_set_executed(
+	__isl_take isl_ast_build *build,
+	__isl_take isl_union_map *executed);
+__isl_give isl_ast_build *isl_ast_build_set_single_valued(
+	__isl_take isl_ast_build *build, int sv);
+__isl_give isl_multi_aff *isl_ast_build_get_internal2input(
+	__isl_keep isl_ast_build *build);
+__isl_give isl_set *isl_ast_build_get_domain(
+	__isl_keep isl_ast_build *build);
+__isl_give isl_set *isl_ast_build_get_pending(
+	__isl_keep isl_ast_build *build);
+__isl_give isl_set *isl_ast_build_get_generated(
+	__isl_keep isl_ast_build *build);
+__isl_give isl_ast_build *isl_ast_build_restrict_generated(
+	__isl_take isl_ast_build *build, __isl_take isl_set *set);
+__isl_give isl_ast_build *isl_ast_build_replace_pending_by_guard(
+	__isl_take isl_ast_build *build, __isl_take isl_set *guard);
+__isl_give int isl_ast_build_need_schedule_map(
+	__isl_keep isl_ast_build *build);
+__isl_give isl_multi_aff *isl_ast_build_get_schedule_map_multi_aff(
+	__isl_keep isl_ast_build *build);
+__isl_give isl_map *isl_ast_build_get_schedule_map(
+	__isl_keep isl_ast_build *build);
+int isl_ast_build_has_affine_value(__isl_keep isl_ast_build *build, int pos);
+int isl_ast_build_has_value(__isl_keep isl_ast_build *build);
+__isl_give isl_id *isl_ast_build_get_iterator_id(
+	__isl_keep isl_ast_build *build, int pos);
+
+int isl_ast_build_has_schedule_node(__isl_keep isl_ast_build *build);
+__isl_give isl_schedule_node *isl_ast_build_get_schedule_node(
+	__isl_keep isl_ast_build *build);
+__isl_give isl_ast_build *isl_ast_build_set_schedule_node(
+	__isl_take isl_ast_build *build,
+	__isl_take isl_schedule_node *node);
+__isl_give isl_ast_build *isl_ast_build_reset_schedule_node(
+	__isl_take isl_ast_build *build);
+
+__isl_give isl_ast_build *isl_ast_build_extract_isolated(
+	__isl_take isl_ast_build *build);
+int isl_ast_build_has_isolated(__isl_keep isl_ast_build *build);
+__isl_give isl_set *isl_ast_build_get_isolated(
+	__isl_keep isl_ast_build *build);
+
+__isl_give isl_basic_set *isl_ast_build_specialize_basic_set(
+	__isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_ast_build_compute_gist_basic_set(
+	__isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset);
+__isl_give isl_set *isl_ast_build_specialize(__isl_keep isl_ast_build *build,
+	__isl_take isl_set *set);
+__isl_give isl_set *isl_ast_build_compute_gist(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *set);
+__isl_give isl_map *isl_ast_build_compute_gist_map_domain(
+	__isl_keep isl_ast_build *build, __isl_take isl_map *map);
+__isl_give isl_aff *isl_ast_build_compute_gist_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_aff *aff);
+__isl_give isl_pw_aff *isl_ast_build_compute_gist_pw_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa);
+__isl_give isl_pw_multi_aff *isl_ast_build_compute_gist_pw_multi_aff(
+	__isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma);
+
+__isl_give isl_union_map *isl_ast_build_substitute_values_union_map_domain(
+	__isl_keep isl_ast_build *build, __isl_take isl_union_map *umap);
+
+int isl_ast_build_aff_is_nonneg(__isl_keep isl_ast_build *build,
+	__isl_keep isl_aff *aff);
+
+isl_bool isl_ast_build_has_stride(__isl_keep isl_ast_build *build, int pos);
+__isl_give isl_aff *isl_ast_build_get_offset(__isl_keep isl_ast_build *build,
+	int pos);
+__isl_give isl_val *isl_ast_build_get_stride(__isl_keep isl_ast_build *build,
+	int pos);
+__isl_give isl_set *isl_ast_build_get_stride_constraint(
+	__isl_keep isl_ast_build *build);
+__isl_give isl_multi_aff *isl_ast_build_get_stride_expansion(
+	__isl_keep isl_ast_build *build);
+
+void isl_ast_build_dump(__isl_keep isl_ast_build *build);
+
+__isl_give isl_set *isl_ast_build_get_option_domain(
+	__isl_keep isl_ast_build *build, enum isl_ast_loop_type type);
+__isl_give isl_map *isl_ast_build_get_separation_class(
+	__isl_keep isl_ast_build *build);
+__isl_give isl_set *isl_ast_build_eliminate(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *domain);
+__isl_give isl_set *isl_ast_build_eliminate_inner(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *set);
+__isl_give isl_set *isl_ast_build_eliminate_divs(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *set);
+
+enum isl_ast_loop_type isl_ast_build_get_loop_type(
+	__isl_keep isl_ast_build *build, int isolated);
+
+__isl_give isl_map *isl_ast_build_map_to_iterator(
+	__isl_keep isl_ast_build *build, __isl_take isl_set *set);
+
+int isl_ast_build_options_involve_depth(__isl_keep isl_ast_build *build);
+
+#endif
diff --git a/final/lib/External/isl/isl_ast_codegen.c b/final/lib/External/isl/isl_ast_codegen.c
new file mode 100644
index 0000000..c56d4d5
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_codegen.c
@@ -0,0 +1,5750 @@
+/*
+ * Copyright 2012-2014 Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <limits.h>
+#include <isl/aff.h>
+#include <isl/constraint.h>
+#include <isl/set.h>
+#include <isl/ilp.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl/schedule_node.h>
+#include <isl_sort.h>
+#include <isl_tarjan.h>
+#include <isl_ast_private.h>
+#include <isl_ast_build_expr.h>
+#include <isl_ast_build_private.h>
+#include <isl_ast_graft_private.h>
+
+/* Data used in generate_domain.
+ *
+ * "build" is the input build.
+ * "list" collects the results.
+ */
+struct isl_generate_domain_data {
+	isl_ast_build *build;
+
+	isl_ast_graft_list *list;
+};
+
+static __isl_give isl_ast_graft_list *generate_next_level(
+	__isl_take isl_union_map *executed,
+	__isl_take isl_ast_build *build);
+static __isl_give isl_ast_graft_list *generate_code(
+	__isl_take isl_union_map *executed, __isl_take isl_ast_build *build,
+	int internal);
+
+/* Generate an AST for a single domain based on
+ * the (non single valued) inverse schedule "executed".
+ *
+ * We extend the schedule with the iteration domain
+ * and continue generating through a call to generate_code.
+ *
+ * In particular, if executed has the form
+ *
+ *	S -> D
+ *
+ * then we continue generating code on
+ *
+ *	[S -> D] -> D
+ *
+ * The extended inverse schedule is clearly single valued
+ * ensuring that the nested generate_code will not reach this function,
+ * but will instead create calls to all elements of D that need
+ * to be executed from the current schedule domain.
+ */
+static isl_stat generate_non_single_valued(__isl_take isl_map *executed,
+	struct isl_generate_domain_data *data)
+{
+	isl_map *identity;
+	isl_ast_build *build;
+	isl_ast_graft_list *list;
+
+	build = isl_ast_build_copy(data->build);
+
+	identity = isl_set_identity(isl_map_range(isl_map_copy(executed)));
+	executed = isl_map_domain_product(executed, identity);
+	build = isl_ast_build_set_single_valued(build, 1);
+
+	list = generate_code(isl_union_map_from_map(executed), build, 1);
+
+	data->list = isl_ast_graft_list_concat(data->list, list);
+
+	return isl_stat_ok;
+}
+
+/* Call the at_each_domain callback, if requested by the user,
+ * after recording the current inverse schedule in the build.
+ */
+static __isl_give isl_ast_graft *at_each_domain(__isl_take isl_ast_graft *graft,
+	__isl_keep isl_map *executed, __isl_keep isl_ast_build *build)
+{
+	if (!graft || !build)
+		return isl_ast_graft_free(graft);
+	if (!build->at_each_domain)
+		return graft;
+
+	build = isl_ast_build_copy(build);
+	build = isl_ast_build_set_executed(build,
+			isl_union_map_from_map(isl_map_copy(executed)));
+	if (!build)
+		return isl_ast_graft_free(graft);
+
+	graft->node = build->at_each_domain(graft->node,
+					build, build->at_each_domain_user);
+	isl_ast_build_free(build);
+
+	if (!graft->node)
+		graft = isl_ast_graft_free(graft);
+
+	return graft;
+}
+
+/* Generate a call expression for the single executed
+ * domain element "map" and put a guard around it based its (simplified)
+ * domain.  "executed" is the original inverse schedule from which "map"
+ * has been derived.  In particular, "map" is either identical to "executed"
+ * or it is the result of gisting "executed" with respect to the build domain.
+ * "executed" is only used if there is an at_each_domain callback.
+ *
+ * At this stage, any pending constraints in the build can no longer
+ * be simplified with respect to any enforced constraints since
+ * the call node does not have any enforced constraints.
+ * Since all pending constraints not covered by any enforced constraints
+ * will be added as a guard to the graft in create_node_scaled,
+ * even in the eliminated case, the pending constraints
+ * can be considered to have been generated by outer constructs.
+ *
+ * If the user has set an at_each_domain callback, it is called
+ * on the constructed call expression node.
+ */
+static isl_stat add_domain(__isl_take isl_map *executed,
+	__isl_take isl_map *map, struct isl_generate_domain_data *data)
+{
+	isl_ast_build *build;
+	isl_ast_graft *graft;
+	isl_ast_graft_list *list;
+	isl_set *guard, *pending;
+
+	build = isl_ast_build_copy(data->build);
+	pending = isl_ast_build_get_pending(build);
+	build = isl_ast_build_replace_pending_by_guard(build, pending);
+
+	guard = isl_map_domain(isl_map_copy(map));
+	guard = isl_set_compute_divs(guard);
+	guard = isl_set_coalesce(guard);
+	guard = isl_set_gist(guard, isl_ast_build_get_generated(build));
+	guard = isl_ast_build_specialize(build, guard);
+
+	graft = isl_ast_graft_alloc_domain(map, build);
+	graft = at_each_domain(graft, executed, build);
+	isl_ast_build_free(build);
+	isl_map_free(executed);
+	graft = isl_ast_graft_add_guard(graft, guard, data->build);
+
+	list = isl_ast_graft_list_from_ast_graft(graft);
+	data->list = isl_ast_graft_list_concat(data->list, list);
+
+	return isl_stat_ok;
+}
+
+/* Generate an AST for a single domain based on
+ * the inverse schedule "executed" and add it to data->list.
+ *
+ * If there is more than one domain element associated to the current
+ * schedule "time", then we need to continue the generation process
+ * in generate_non_single_valued.
+ * Note that the inverse schedule being single-valued may depend
+ * on constraints that are only available in the original context
+ * domain specified by the user.  We therefore first introduce
+ * some of the constraints of data->build->domain.  In particular,
+ * we intersect with a single-disjunct approximation of this set.
+ * We perform this approximation to avoid further splitting up
+ * the executed relation, possibly introducing a disjunctive guard
+ * on the statement.
+ *
+ * On the other hand, we only perform the test after having taken the gist
+ * of the domain as the resulting map is the one from which the call
+ * expression is constructed.  Using this map to construct the call
+ * expression usually yields simpler results in cases where the original
+ * map is not obviously single-valued.
+ * If the original map is obviously single-valued, then the gist
+ * operation is skipped.
+ *
+ * Because we perform the single-valuedness test on the gisted map,
+ * we may in rare cases fail to recognize that the inverse schedule
+ * is single-valued.  This becomes problematic if this happens
+ * from the recursive call through generate_non_single_valued
+ * as we would then end up in an infinite recursion.
+ * We therefore check if we are inside a call to generate_non_single_valued
+ * and revert to the ungisted map if the gisted map turns out not to be
+ * single-valued.
+ *
+ * Otherwise, call add_domain to generate a call expression (with guard) and
+ * to call the at_each_domain callback, if any.
+ */
+static isl_stat generate_domain(__isl_take isl_map *executed, void *user)
+{
+	struct isl_generate_domain_data *data = user;
+	isl_set *domain;
+	isl_map *map = NULL;
+	int empty, sv;
+
+	domain = isl_ast_build_get_domain(data->build);
+	domain = isl_set_from_basic_set(isl_set_simple_hull(domain));
+	executed = isl_map_intersect_domain(executed, domain);
+	empty = isl_map_is_empty(executed);
+	if (empty < 0)
+		goto error;
+	if (empty) {
+		isl_map_free(executed);
+		return isl_stat_ok;
+	}
+
+	sv = isl_map_plain_is_single_valued(executed);
+	if (sv < 0)
+		goto error;
+	if (sv)
+		return add_domain(executed, isl_map_copy(executed), data);
+
+	executed = isl_map_coalesce(executed);
+	map = isl_map_copy(executed);
+	map = isl_ast_build_compute_gist_map_domain(data->build, map);
+	sv = isl_map_is_single_valued(map);
+	if (sv < 0)
+		goto error;
+	if (!sv) {
+		isl_map_free(map);
+		if (data->build->single_valued)
+			map = isl_map_copy(executed);
+		else
+			return generate_non_single_valued(executed, data);
+	}
+
+	return add_domain(executed, map, data);
+error:
+	isl_map_free(map);
+	isl_map_free(executed);
+	return isl_stat_error;
+}
+
+/* Call build->create_leaf to a create "leaf" node in the AST,
+ * encapsulate the result in an isl_ast_graft and return the result
+ * as a 1-element list.
+ *
+ * Note that the node returned by the user may be an entire tree.
+ *
+ * Since the node itself cannot enforce any constraints, we turn
+ * all pending constraints into guards and add them to the resulting
+ * graft to ensure that they will be generated.
+ *
+ * Before we pass control to the user, we first clear some information
+ * from the build that is (presumbably) only meaningful
+ * for the current code generation.
+ * This includes the create_leaf callback itself, so we make a copy
+ * of the build first.
+ */
+static __isl_give isl_ast_graft_list *call_create_leaf(
+	__isl_take isl_union_map *executed, __isl_take isl_ast_build *build)
+{
+	isl_set *guard;
+	isl_ast_node *node;
+	isl_ast_graft *graft;
+	isl_ast_build *user_build;
+
+	guard = isl_ast_build_get_pending(build);
+	user_build = isl_ast_build_copy(build);
+	user_build = isl_ast_build_replace_pending_by_guard(user_build,
+							isl_set_copy(guard));
+	user_build = isl_ast_build_set_executed(user_build, executed);
+	user_build = isl_ast_build_clear_local_info(user_build);
+	if (!user_build)
+		node = NULL;
+	else
+		node = build->create_leaf(user_build, build->create_leaf_user);
+	graft = isl_ast_graft_alloc(node, build);
+	graft = isl_ast_graft_add_guard(graft, guard, build);
+	isl_ast_build_free(build);
+	return isl_ast_graft_list_from_ast_graft(graft);
+}
+
+static __isl_give isl_ast_graft_list *build_ast_from_child(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *executed);
+
+/* Generate an AST after having handled the complete schedule
+ * of this call to the code generator or the complete band
+ * if we are generating an AST from a schedule tree.
+ *
+ * If we are inside a band node, then move on to the child of the band.
+ *
+ * If the user has specified a create_leaf callback, control
+ * is passed to the user in call_create_leaf.
+ *
+ * Otherwise, we generate one or more calls for each individual
+ * domain in generate_domain.
+ */
+static __isl_give isl_ast_graft_list *generate_inner_level(
+	__isl_take isl_union_map *executed, __isl_take isl_ast_build *build)
+{
+	isl_ctx *ctx;
+	struct isl_generate_domain_data data = { build };
+
+	if (!build || !executed)
+		goto error;
+
+	if (isl_ast_build_has_schedule_node(build)) {
+		isl_schedule_node *node;
+		node = isl_ast_build_get_schedule_node(build);
+		build = isl_ast_build_reset_schedule_node(build);
+		return build_ast_from_child(build, node, executed);
+	}
+
+	if (build->create_leaf)
+		return call_create_leaf(executed, build);
+
+	ctx = isl_union_map_get_ctx(executed);
+	data.list = isl_ast_graft_list_alloc(ctx, 0);
+	if (isl_union_map_foreach_map(executed, &generate_domain, &data) < 0)
+		data.list = isl_ast_graft_list_free(data.list);
+
+	if (0)
+error:		data.list = NULL;
+	isl_ast_build_free(build);
+	isl_union_map_free(executed);
+	return data.list;
+}
+
+/* Call the before_each_for callback, if requested by the user.
+ */
+static __isl_give isl_ast_node *before_each_for(__isl_take isl_ast_node *node,
+	__isl_keep isl_ast_build *build)
+{
+	isl_id *id;
+
+	if (!node || !build)
+		return isl_ast_node_free(node);
+	if (!build->before_each_for)
+		return node;
+	id = build->before_each_for(build, build->before_each_for_user);
+	node = isl_ast_node_set_annotation(node, id);
+	return node;
+}
+
+/* Call the after_each_for callback, if requested by the user.
+ */
+static __isl_give isl_ast_graft *after_each_for(__isl_take isl_ast_graft *graft,
+	__isl_keep isl_ast_build *build)
+{
+	if (!graft || !build)
+		return isl_ast_graft_free(graft);
+	if (!build->after_each_for)
+		return graft;
+	graft->node = build->after_each_for(graft->node, build,
+						build->after_each_for_user);
+	if (!graft->node)
+		return isl_ast_graft_free(graft);
+	return graft;
+}
+
+/* Plug in all the know values of the current and outer dimensions
+ * in the domain of "executed".  In principle, we only need to plug
+ * in the known value of the current dimension since the values of
+ * outer dimensions have been plugged in already.
+ * However, it turns out to be easier to just plug in all known values.
+ */
+static __isl_give isl_union_map *plug_in_values(
+	__isl_take isl_union_map *executed, __isl_keep isl_ast_build *build)
+{
+	return isl_ast_build_substitute_values_union_map_domain(build,
+								    executed);
+}
+
+/* Check if the constraint "c" is a lower bound on dimension "pos",
+ * an upper bound, or independent of dimension "pos".
+ */
+static int constraint_type(isl_constraint *c, int pos)
+{
+	if (isl_constraint_is_lower_bound(c, isl_dim_set, pos))
+		return 1;
+	if (isl_constraint_is_upper_bound(c, isl_dim_set, pos))
+		return 2;
+	return 0;
+}
+
+/* Compare the types of the constraints "a" and "b",
+ * resulting in constraints that are independent of "depth"
+ * to be sorted before the lower bounds on "depth", which in
+ * turn are sorted before the upper bounds on "depth".
+ */
+static int cmp_constraint(__isl_keep isl_constraint *a,
+	__isl_keep isl_constraint *b, void *user)
+{
+	int *depth = user;
+	int t1 = constraint_type(a, *depth);
+	int t2 = constraint_type(b, *depth);
+
+	return t1 - t2;
+}
+
+/* Extract a lower bound on dimension "pos" from constraint "c".
+ *
+ * If the constraint is of the form
+ *
+ *	a x + f(...) >= 0
+ *
+ * then we essentially return
+ *
+ *	l = ceil(-f(...)/a)
+ *
+ * However, if the current dimension is strided, then we need to make
+ * sure that the lower bound we construct is of the form
+ *
+ *	f + s a
+ *
+ * with f the offset and s the stride.
+ * We therefore compute
+ *
+ *	f + s * ceil((l - f)/s)
+ */
+static __isl_give isl_aff *lower_bound(__isl_keep isl_constraint *c,
+	int pos, __isl_keep isl_ast_build *build)
+{
+	isl_aff *aff;
+
+	aff = isl_constraint_get_bound(c, isl_dim_set, pos);
+	aff = isl_aff_ceil(aff);
+
+	if (isl_ast_build_has_stride(build, pos)) {
+		isl_aff *offset;
+		isl_val *stride;
+
+		offset = isl_ast_build_get_offset(build, pos);
+		stride = isl_ast_build_get_stride(build, pos);
+
+		aff = isl_aff_sub(aff, isl_aff_copy(offset));
+		aff = isl_aff_scale_down_val(aff, isl_val_copy(stride));
+		aff = isl_aff_ceil(aff);
+		aff = isl_aff_scale_val(aff, stride);
+		aff = isl_aff_add(aff, offset);
+	}
+
+	aff = isl_ast_build_compute_gist_aff(build, aff);
+
+	return aff;
+}
+
+/* Return the exact lower bound (or upper bound if "upper" is set)
+ * of "domain" as a piecewise affine expression.
+ *
+ * If we are computing a lower bound (of a strided dimension), then
+ * we need to make sure it is of the form
+ *
+ *	f + s a
+ *
+ * where f is the offset and s is the stride.
+ * We therefore need to include the stride constraint before computing
+ * the minimum.
+ */
+static __isl_give isl_pw_aff *exact_bound(__isl_keep isl_set *domain,
+	__isl_keep isl_ast_build *build, int upper)
+{
+	isl_set *stride;
+	isl_map *it_map;
+	isl_pw_aff *pa;
+	isl_pw_multi_aff *pma;
+
+	domain = isl_set_copy(domain);
+	if (!upper) {
+		stride = isl_ast_build_get_stride_constraint(build);
+		domain = isl_set_intersect(domain, stride);
+	}
+	it_map = isl_ast_build_map_to_iterator(build, domain);
+	if (upper)
+		pma = isl_map_lexmax_pw_multi_aff(it_map);
+	else
+		pma = isl_map_lexmin_pw_multi_aff(it_map);
+	pa = isl_pw_multi_aff_get_pw_aff(pma, 0);
+	isl_pw_multi_aff_free(pma);
+	pa = isl_ast_build_compute_gist_pw_aff(build, pa);
+	pa = isl_pw_aff_coalesce(pa);
+
+	return pa;
+}
+
+/* Callback for sorting the isl_pw_aff_list passed to reduce_list and
+ * remove_redundant_lower_bounds.
+ */
+static int reduce_list_cmp(__isl_keep isl_pw_aff *a, __isl_keep isl_pw_aff *b,
+	void *user)
+{
+	return isl_pw_aff_plain_cmp(a, b);
+}
+
+/* Given a list of lower bounds "list", remove those that are redundant
+ * with respect to the other bounds in "list" and the domain of "build".
+ *
+ * We first sort the bounds in the same way as they would be sorted
+ * by set_for_node_expressions so that we can try and remove the last
+ * bounds first.
+ *
+ * For a lower bound to be effective, there needs to be at least
+ * one domain element for which it is larger than all other lower bounds.
+ * For each lower bound we therefore intersect the domain with
+ * the conditions that it is larger than all other bounds and
+ * check whether the result is empty.  If so, the bound can be removed.
+ */
+static __isl_give isl_pw_aff_list *remove_redundant_lower_bounds(
+	__isl_take isl_pw_aff_list *list, __isl_keep isl_ast_build *build)
+{
+	int i, j, n;
+	isl_set *domain;
+
+	list = isl_pw_aff_list_sort(list, &reduce_list_cmp, NULL);
+	if (!list)
+		return NULL;
+
+	n = isl_pw_aff_list_n_pw_aff(list);
+	if (n <= 1)
+		return list;
+
+	domain = isl_ast_build_get_domain(build);
+
+	for (i = n - 1; i >= 0; --i) {
+		isl_pw_aff *pa_i;
+		isl_set *domain_i;
+		int empty;
+
+		domain_i = isl_set_copy(domain);
+		pa_i = isl_pw_aff_list_get_pw_aff(list, i);
+
+		for (j = 0; j < n; ++j) {
+			isl_pw_aff *pa_j;
+			isl_set *better;
+
+			if (j == i)
+				continue;
+
+			pa_j = isl_pw_aff_list_get_pw_aff(list, j);
+			better = isl_pw_aff_gt_set(isl_pw_aff_copy(pa_i), pa_j);
+			domain_i = isl_set_intersect(domain_i, better);
+		}
+
+		empty = isl_set_is_empty(domain_i);
+
+		isl_set_free(domain_i);
+		isl_pw_aff_free(pa_i);
+
+		if (empty < 0)
+			goto error;
+		if (!empty)
+			continue;
+		list = isl_pw_aff_list_drop(list, i, 1);
+		n--;
+	}
+
+	isl_set_free(domain);
+
+	return list;
+error:
+	isl_set_free(domain);
+	return isl_pw_aff_list_free(list);
+}
+
+/* Extract a lower bound on dimension "pos" from each constraint
+ * in "constraints" and return the list of lower bounds.
+ * If "constraints" has zero elements, then we extract a lower bound
+ * from "domain" instead.
+ *
+ * If the current dimension is strided, then the lower bound
+ * is adjusted by lower_bound to match the stride information.
+ * This modification may make one or more lower bounds redundant
+ * with respect to the other lower bounds.  We therefore check
+ * for this condition and remove the redundant lower bounds.
+ */
+static __isl_give isl_pw_aff_list *lower_bounds(
+	__isl_keep isl_constraint_list *constraints, int pos,
+	__isl_keep isl_set *domain, __isl_keep isl_ast_build *build)
+{
+	isl_ctx *ctx;
+	isl_pw_aff_list *list;
+	int i, n;
+
+	if (!build)
+		return NULL;
+
+	n = isl_constraint_list_n_constraint(constraints);
+	if (n == 0) {
+		isl_pw_aff *pa;
+		pa = exact_bound(domain, build, 0);
+		return isl_pw_aff_list_from_pw_aff(pa);
+	}
+
+	ctx = isl_ast_build_get_ctx(build);
+	list = isl_pw_aff_list_alloc(ctx,n);
+
+	for (i = 0; i < n; ++i) {
+		isl_aff *aff;
+		isl_constraint *c;
+
+		c = isl_constraint_list_get_constraint(constraints, i);
+		aff = lower_bound(c, pos, build);
+		isl_constraint_free(c);
+		list = isl_pw_aff_list_add(list, isl_pw_aff_from_aff(aff));
+	}
+
+	if (isl_ast_build_has_stride(build, pos))
+		list = remove_redundant_lower_bounds(list, build);
+
+	return list;
+}
+
+/* Extract an upper bound on dimension "pos" from each constraint
+ * in "constraints" and return the list of upper bounds.
+ * If "constraints" has zero elements, then we extract an upper bound
+ * from "domain" instead.
+ */
+static __isl_give isl_pw_aff_list *upper_bounds(
+	__isl_keep isl_constraint_list *constraints, int pos,
+	__isl_keep isl_set *domain, __isl_keep isl_ast_build *build)
+{
+	isl_ctx *ctx;
+	isl_pw_aff_list *list;
+	int i, n;
+
+	n = isl_constraint_list_n_constraint(constraints);
+	if (n == 0) {
+		isl_pw_aff *pa;
+		pa = exact_bound(domain, build, 1);
+		return isl_pw_aff_list_from_pw_aff(pa);
+	}
+
+	ctx = isl_ast_build_get_ctx(build);
+	list = isl_pw_aff_list_alloc(ctx,n);
+
+	for (i = 0; i < n; ++i) {
+		isl_aff *aff;
+		isl_constraint *c;
+
+		c = isl_constraint_list_get_constraint(constraints, i);
+		aff = isl_constraint_get_bound(c, isl_dim_set, pos);
+		isl_constraint_free(c);
+		aff = isl_aff_floor(aff);
+		list = isl_pw_aff_list_add(list, isl_pw_aff_from_aff(aff));
+	}
+
+	return list;
+}
+
+/* Return an isl_ast_expr that performs the reduction of type "type"
+ * on AST expressions corresponding to the elements in "list".
+ *
+ * The list is assumed to contain at least one element.
+ * If the list contains exactly one element, then the returned isl_ast_expr
+ * simply computes that affine expression.
+ * If the list contains more than one element, then we sort it
+ * using a fairly abitrary but hopefully reasonably stable order.
+ */
+static __isl_give isl_ast_expr *reduce_list(enum isl_ast_op_type type,
+	__isl_keep isl_pw_aff_list *list, __isl_keep isl_ast_build *build)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_ast_expr *expr;
+
+	if (!list)
+		return NULL;
+
+	n = isl_pw_aff_list_n_pw_aff(list);
+
+	if (n == 1)
+		return isl_ast_build_expr_from_pw_aff_internal(build,
+				isl_pw_aff_list_get_pw_aff(list, 0));
+
+	ctx = isl_pw_aff_list_get_ctx(list);
+	expr = isl_ast_expr_alloc_op(ctx, type, n);
+	if (!expr)
+		return NULL;
+
+	list = isl_pw_aff_list_copy(list);
+	list = isl_pw_aff_list_sort(list, &reduce_list_cmp, NULL);
+	if (!list)
+		return isl_ast_expr_free(expr);
+
+	for (i = 0; i < n; ++i) {
+		isl_ast_expr *expr_i;
+
+		expr_i = isl_ast_build_expr_from_pw_aff_internal(build,
+				isl_pw_aff_list_get_pw_aff(list, i));
+		if (!expr_i)
+			goto error;
+		expr->u.op.args[i] = expr_i;
+	}
+
+	isl_pw_aff_list_free(list);
+	return expr;
+error:
+	isl_pw_aff_list_free(list);
+	isl_ast_expr_free(expr);
+	return NULL;
+}
+
+/* Add guards implied by the "generated constraints",
+ * but not (necessarily) enforced by the generated AST to "guard".
+ * In particular, if there is any stride constraints,
+ * then add the guard implied by those constraints.
+ * If we have generated a degenerate loop, then add the guard
+ * implied by "bounds" on the outer dimensions, i.e., the guard
+ * that ensures that the single value actually exists.
+ * Since there may also be guards implied by a combination
+ * of these constraints, we first combine them before
+ * deriving the implied constraints.
+ */
+static __isl_give isl_set *add_implied_guards(__isl_take isl_set *guard,
+	int degenerate, __isl_keep isl_basic_set *bounds,
+	__isl_keep isl_ast_build *build)
+{
+	int depth, has_stride;
+	isl_space *space;
+	isl_set *dom, *set;
+
+	depth = isl_ast_build_get_depth(build);
+	has_stride = isl_ast_build_has_stride(build, depth);
+	if (!has_stride && !degenerate)
+		return guard;
+
+	space = isl_basic_set_get_space(bounds);
+	dom = isl_set_universe(space);
+
+	if (degenerate) {
+		bounds = isl_basic_set_copy(bounds);
+		bounds = isl_basic_set_drop_constraints_not_involving_dims(
+					bounds, isl_dim_set, depth, 1);
+		set = isl_set_from_basic_set(bounds);
+		dom = isl_set_intersect(dom, set);
+	}
+
+	if (has_stride) {
+		set = isl_ast_build_get_stride_constraint(build);
+		dom = isl_set_intersect(dom, set);
+	}
+
+	dom = isl_set_eliminate(dom, isl_dim_set, depth, 1);
+	dom = isl_ast_build_compute_gist(build, dom);
+	guard = isl_set_intersect(guard, dom);
+
+	return guard;
+}
+
+/* Update "graft" based on "sub_build" for the degenerate case.
+ *
+ * "build" is the build in which graft->node was created
+ * "sub_build" contains information about the current level itself,
+ * including the single value attained.
+ *
+ * We set the initialization part of the for loop to the single
+ * value attained by the current dimension.
+ * The increment and condition are not strictly needed as the are known
+ * to be "1" and "iterator <= value" respectively.
+ */
+static __isl_give isl_ast_graft *refine_degenerate(
+	__isl_take isl_ast_graft *graft, __isl_keep isl_ast_build *build,
+	__isl_keep isl_ast_build *sub_build)
+{
+	isl_pw_aff *value;
+
+	if (!graft || !sub_build)
+		return isl_ast_graft_free(graft);
+
+	value = isl_pw_aff_copy(sub_build->value);
+
+	graft->node->u.f.init = isl_ast_build_expr_from_pw_aff_internal(build,
+						value);
+	if (!graft->node->u.f.init)
+		return isl_ast_graft_free(graft);
+
+	return graft;
+}
+
+/* Return the intersection of constraints in "list" as a set.
+ */
+static __isl_give isl_set *intersect_constraints(
+	__isl_keep isl_constraint_list *list)
+{
+	int i, n;
+	isl_basic_set *bset;
+
+	n = isl_constraint_list_n_constraint(list);
+	if (n < 1)
+		isl_die(isl_constraint_list_get_ctx(list), isl_error_internal,
+			"expecting at least one constraint", return NULL);
+
+	bset = isl_basic_set_from_constraint(
+				isl_constraint_list_get_constraint(list, 0));
+	for (i = 1; i < n; ++i) {
+		isl_basic_set *bset_i;
+
+		bset_i = isl_basic_set_from_constraint(
+				isl_constraint_list_get_constraint(list, i));
+		bset = isl_basic_set_intersect(bset, bset_i);
+	}
+
+	return isl_set_from_basic_set(bset);
+}
+
+/* Compute the constraints on the outer dimensions enforced by
+ * graft->node and add those constraints to graft->enforced,
+ * in case the upper bound is expressed as a set "upper".
+ *
+ * In particular, if l(...) is a lower bound in "lower", and
+ *
+ *	-a i + f(...) >= 0		or	a i <= f(...)
+ *
+ * is an upper bound ocnstraint on the current dimension i,
+ * then the for loop enforces the constraint
+ *
+ *	-a l(...) + f(...) >= 0		or	a l(...) <= f(...)
+ *
+ * We therefore simply take each lower bound in turn, plug it into
+ * the upper bounds and compute the intersection over all lower bounds.
+ *
+ * If a lower bound is a rational expression, then
+ * isl_basic_set_preimage_multi_aff will force this rational
+ * expression to have only integer values.  However, the loop
+ * itself does not enforce this integrality constraint.  We therefore
+ * use the ceil of the lower bounds instead of the lower bounds themselves.
+ * Other constraints will make sure that the for loop is only executed
+ * when each of the lower bounds attains an integral value.
+ * In particular, potentially rational values only occur in
+ * lower_bound if the offset is a (seemingly) rational expression,
+ * but then outer conditions will make sure that this rational expression
+ * only attains integer values.
+ */
+static __isl_give isl_ast_graft *set_enforced_from_set(
+	__isl_take isl_ast_graft *graft,
+	__isl_keep isl_pw_aff_list *lower, int pos, __isl_keep isl_set *upper)
+{
+	isl_space *space;
+	isl_basic_set *enforced;
+	isl_pw_multi_aff *pma;
+	int i, n;
+
+	if (!graft || !lower)
+		return isl_ast_graft_free(graft);
+
+	space = isl_set_get_space(upper);
+	enforced = isl_basic_set_universe(isl_space_copy(space));
+
+	space = isl_space_map_from_set(space);
+	pma = isl_pw_multi_aff_identity(space);
+
+	n = isl_pw_aff_list_n_pw_aff(lower);
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+		isl_set *enforced_i;
+		isl_basic_set *hull;
+		isl_pw_multi_aff *pma_i;
+
+		pa = isl_pw_aff_list_get_pw_aff(lower, i);
+		pa = isl_pw_aff_ceil(pa);
+		pma_i = isl_pw_multi_aff_copy(pma);
+		pma_i = isl_pw_multi_aff_set_pw_aff(pma_i, pos, pa);
+		enforced_i = isl_set_copy(upper);
+		enforced_i = isl_set_preimage_pw_multi_aff(enforced_i, pma_i);
+		hull = isl_set_simple_hull(enforced_i);
+		enforced = isl_basic_set_intersect(enforced, hull);
+	}
+
+	isl_pw_multi_aff_free(pma);
+
+	graft = isl_ast_graft_enforce(graft, enforced);
+
+	return graft;
+}
+
+/* Compute the constraints on the outer dimensions enforced by
+ * graft->node and add those constraints to graft->enforced,
+ * in case the upper bound is expressed as
+ * a list of affine expressions "upper".
+ *
+ * The enforced condition is that each lower bound expression is less
+ * than or equal to each upper bound expression.
+ */
+static __isl_give isl_ast_graft *set_enforced_from_list(
+	__isl_take isl_ast_graft *graft,
+	__isl_keep isl_pw_aff_list *lower, __isl_keep isl_pw_aff_list *upper)
+{
+	isl_set *cond;
+	isl_basic_set *enforced;
+
+	lower = isl_pw_aff_list_copy(lower);
+	upper = isl_pw_aff_list_copy(upper);
+	cond = isl_pw_aff_list_le_set(lower, upper);
+	enforced = isl_set_simple_hull(cond);
+	graft = isl_ast_graft_enforce(graft, enforced);
+
+	return graft;
+}
+
+/* Does "aff" have a negative constant term?
+ */
+static isl_stat aff_constant_is_negative(__isl_take isl_set *set,
+	__isl_take isl_aff *aff, void *user)
+{
+	int *neg = user;
+	isl_val *v;
+
+	v = isl_aff_get_constant_val(aff);
+	*neg = isl_val_is_neg(v);
+	isl_val_free(v);
+	isl_set_free(set);
+	isl_aff_free(aff);
+
+	return *neg ? isl_stat_ok : isl_stat_error;
+}
+
+/* Does "pa" have a negative constant term over its entire domain?
+ */
+static isl_stat pw_aff_constant_is_negative(__isl_take isl_pw_aff *pa,
+	void *user)
+{
+	isl_stat r;
+	int *neg = user;
+
+	r = isl_pw_aff_foreach_piece(pa, &aff_constant_is_negative, user);
+	isl_pw_aff_free(pa);
+
+	return (*neg && r >= 0) ? isl_stat_ok : isl_stat_error;
+}
+
+/* Does each element in "list" have a negative constant term?
+ *
+ * The callback terminates the iteration as soon an element has been
+ * found that does not have a negative constant term.
+ */
+static int list_constant_is_negative(__isl_keep isl_pw_aff_list *list)
+{
+	int neg = 1;
+
+	if (isl_pw_aff_list_foreach(list,
+				&pw_aff_constant_is_negative, &neg) < 0 && neg)
+		return -1;
+
+	return neg;
+}
+
+/* Add 1 to each of the elements in "list", where each of these elements
+ * is defined over the internal schedule space of "build".
+ */
+static __isl_give isl_pw_aff_list *list_add_one(
+	__isl_take isl_pw_aff_list *list, __isl_keep isl_ast_build *build)
+{
+	int i, n;
+	isl_space *space;
+	isl_aff *aff;
+	isl_pw_aff *one;
+
+	space = isl_ast_build_get_space(build, 1);
+	aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+	aff = isl_aff_add_constant_si(aff, 1);
+	one = isl_pw_aff_from_aff(aff);
+
+	n = isl_pw_aff_list_n_pw_aff(list);
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+		pa = isl_pw_aff_list_get_pw_aff(list, i);
+		pa = isl_pw_aff_add(pa, isl_pw_aff_copy(one));
+		list = isl_pw_aff_list_set_pw_aff(list, i, pa);
+	}
+
+	isl_pw_aff_free(one);
+
+	return list;
+}
+
+/* Set the condition part of the for node graft->node in case
+ * the upper bound is represented as a list of piecewise affine expressions.
+ *
+ * In particular, set the condition to
+ *
+ *	iterator <= min(list of upper bounds)
+ *
+ * If each of the upper bounds has a negative constant term, then
+ * set the condition to
+ *
+ *	iterator < min(list of (upper bound + 1)s)
+ *
+ */
+static __isl_give isl_ast_graft *set_for_cond_from_list(
+	__isl_take isl_ast_graft *graft, __isl_keep isl_pw_aff_list *list,
+	__isl_keep isl_ast_build *build)
+{
+	int neg;
+	isl_ast_expr *bound, *iterator, *cond;
+	enum isl_ast_op_type type = isl_ast_op_le;
+
+	if (!graft || !list)
+		return isl_ast_graft_free(graft);
+
+	neg = list_constant_is_negative(list);
+	if (neg < 0)
+		return isl_ast_graft_free(graft);
+	list = isl_pw_aff_list_copy(list);
+	if (neg) {
+		list = list_add_one(list, build);
+		type = isl_ast_op_lt;
+	}
+
+	bound = reduce_list(isl_ast_op_min, list, build);
+	iterator = isl_ast_expr_copy(graft->node->u.f.iterator);
+	cond = isl_ast_expr_alloc_binary(type, iterator, bound);
+	graft->node->u.f.cond = cond;
+
+	isl_pw_aff_list_free(list);
+	if (!graft->node->u.f.cond)
+		return isl_ast_graft_free(graft);
+	return graft;
+}
+
+/* Set the condition part of the for node graft->node in case
+ * the upper bound is represented as a set.
+ */
+static __isl_give isl_ast_graft *set_for_cond_from_set(
+	__isl_take isl_ast_graft *graft, __isl_keep isl_set *set,
+	__isl_keep isl_ast_build *build)
+{
+	isl_ast_expr *cond;
+
+	if (!graft)
+		return NULL;
+
+	cond = isl_ast_build_expr_from_set_internal(build, isl_set_copy(set));
+	graft->node->u.f.cond = cond;
+	if (!graft->node->u.f.cond)
+		return isl_ast_graft_free(graft);
+	return graft;
+}
+
+/* Construct an isl_ast_expr for the increment (i.e., stride) of
+ * the current dimension.
+ */
+static __isl_give isl_ast_expr *for_inc(__isl_keep isl_ast_build *build)
+{
+	int depth;
+	isl_val *v;
+	isl_ctx *ctx;
+
+	if (!build)
+		return NULL;
+	ctx = isl_ast_build_get_ctx(build);
+	depth = isl_ast_build_get_depth(build);
+
+	if (!isl_ast_build_has_stride(build, depth))
+		return isl_ast_expr_alloc_int_si(ctx, 1);
+
+	v = isl_ast_build_get_stride(build, depth);
+	return isl_ast_expr_from_val(v);
+}
+
+/* Should we express the loop condition as
+ *
+ *	iterator <= min(list of upper bounds)
+ *
+ * or as a conjunction of constraints?
+ *
+ * The first is constructed from a list of upper bounds.
+ * The second is constructed from a set.
+ *
+ * If there are no upper bounds in "constraints", then this could mean
+ * that "domain" simply doesn't have an upper bound or that we didn't
+ * pick any upper bound.  In the first case, we want to generate the
+ * loop condition as a(n empty) conjunction of constraints
+ * In the second case, we will compute
+ * a single upper bound from "domain" and so we use the list form.
+ *
+ * If there are upper bounds in "constraints",
+ * then we use the list form iff the atomic_upper_bound option is set.
+ */
+static int use_upper_bound_list(isl_ctx *ctx, int n_upper,
+	__isl_keep isl_set *domain, int depth)
+{
+	if (n_upper > 0)
+		return isl_options_get_ast_build_atomic_upper_bound(ctx);
+	else
+		return isl_set_dim_has_upper_bound(domain, isl_dim_set, depth);
+}
+
+/* Fill in the expressions of the for node in graft->node.
+ *
+ * In particular,
+ * - set the initialization part of the loop to the maximum of the lower bounds
+ * - extract the increment from the stride of the current dimension
+ * - construct the for condition either based on a list of upper bounds
+ *	or on a set of upper bound constraints.
+ */
+static __isl_give isl_ast_graft *set_for_node_expressions(
+	__isl_take isl_ast_graft *graft, __isl_keep isl_pw_aff_list *lower,
+	int use_list, __isl_keep isl_pw_aff_list *upper_list,
+	__isl_keep isl_set *upper_set, __isl_keep isl_ast_build *build)
+{
+	isl_ast_node *node;
+
+	if (!graft)
+		return NULL;
+
+	build = isl_ast_build_copy(build);
+
+	node = graft->node;
+	node->u.f.init = reduce_list(isl_ast_op_max, lower, build);
+	node->u.f.inc = for_inc(build);
+
+	if (!node->u.f.init || !node->u.f.inc)
+		graft = isl_ast_graft_free(graft);
+
+	if (use_list)
+		graft = set_for_cond_from_list(graft, upper_list, build);
+	else
+		graft = set_for_cond_from_set(graft, upper_set, build);
+
+	isl_ast_build_free(build);
+
+	return graft;
+}
+
+/* Update "graft" based on "bounds" and "domain" for the generic,
+ * non-degenerate, case.
+ *
+ * "c_lower" and "c_upper" contain the lower and upper bounds
+ * that the loop node should express.
+ * "domain" is the subset of the intersection of the constraints
+ * for which some code is executed.
+ *
+ * There may be zero lower bounds or zero upper bounds in "constraints"
+ * in case the list of constraints was created
+ * based on the atomic option or based on separation with explicit bounds.
+ * In that case, we use "domain" to derive lower and/or upper bounds.
+ *
+ * We first compute a list of one or more lower bounds.
+ *
+ * Then we decide if we want to express the condition as
+ *
+ *	iterator <= min(list of upper bounds)
+ *
+ * or as a conjunction of constraints.
+ *
+ * The set of enforced constraints is then computed either based on
+ * a list of upper bounds or on a set of upper bound constraints.
+ * We do not compute any enforced constraints if we were forced
+ * to compute a lower or upper bound using exact_bound.  The domains
+ * of the resulting expressions may imply some bounds on outer dimensions
+ * that we do not want to appear in the enforced constraints since
+ * they are not actually enforced by the corresponding code.
+ *
+ * Finally, we fill in the expressions of the for node.
+ */
+static __isl_give isl_ast_graft *refine_generic_bounds(
+	__isl_take isl_ast_graft *graft,
+	__isl_take isl_constraint_list *c_lower,
+	__isl_take isl_constraint_list *c_upper,
+	__isl_keep isl_set *domain, __isl_keep isl_ast_build *build)
+{
+	int depth;
+	isl_ctx *ctx;
+	isl_pw_aff_list *lower;
+	int use_list;
+	isl_set *upper_set = NULL;
+	isl_pw_aff_list *upper_list = NULL;
+	int n_lower, n_upper;
+
+	if (!graft || !c_lower || !c_upper || !build)
+		goto error;
+
+	depth = isl_ast_build_get_depth(build);
+	ctx = isl_ast_graft_get_ctx(graft);
+
+	n_lower = isl_constraint_list_n_constraint(c_lower);
+	n_upper = isl_constraint_list_n_constraint(c_upper);
+
+	use_list = use_upper_bound_list(ctx, n_upper, domain, depth);
+
+	lower = lower_bounds(c_lower, depth, domain, build);
+
+	if (use_list)
+		upper_list = upper_bounds(c_upper, depth, domain, build);
+	else if (n_upper > 0)
+		upper_set = intersect_constraints(c_upper);
+	else
+		upper_set = isl_set_universe(isl_set_get_space(domain));
+
+	if (n_lower == 0 || n_upper == 0)
+		;
+	else if (use_list)
+		graft = set_enforced_from_list(graft, lower, upper_list);
+	else
+		graft = set_enforced_from_set(graft, lower, depth, upper_set);
+
+	graft = set_for_node_expressions(graft, lower, use_list, upper_list,
+					upper_set, build);
+
+	isl_pw_aff_list_free(lower);
+	isl_pw_aff_list_free(upper_list);
+	isl_set_free(upper_set);
+	isl_constraint_list_free(c_lower);
+	isl_constraint_list_free(c_upper);
+
+	return graft;
+error:
+	isl_constraint_list_free(c_lower);
+	isl_constraint_list_free(c_upper);
+	return isl_ast_graft_free(graft);
+}
+
+/* Internal data structure used inside count_constraints to keep
+ * track of the number of constraints that are independent of dimension "pos",
+ * the lower bounds in "pos" and the upper bounds in "pos".
+ */
+struct isl_ast_count_constraints_data {
+	int pos;
+
+	int n_indep;
+	int n_lower;
+	int n_upper;
+};
+
+/* Increment data->n_indep, data->lower or data->upper depending
+ * on whether "c" is independenct of dimensions data->pos,
+ * a lower bound or an upper bound.
+ */
+static isl_stat count_constraints(__isl_take isl_constraint *c, void *user)
+{
+	struct isl_ast_count_constraints_data *data = user;
+
+	if (isl_constraint_is_lower_bound(c, isl_dim_set, data->pos))
+		data->n_lower++;
+	else if (isl_constraint_is_upper_bound(c, isl_dim_set, data->pos))
+		data->n_upper++;
+	else
+		data->n_indep++;
+
+	isl_constraint_free(c);
+
+	return isl_stat_ok;
+}
+
+/* Update "graft" based on "bounds" and "domain" for the generic,
+ * non-degenerate, case.
+ *
+ * "list" respresent the list of bounds that need to be encoded by
+ * the for loop.  Only the constraints that involve the iterator
+ * are relevant here.  The other constraints are taken care of by
+ * the caller and are included in the generated constraints of "build".
+ * "domain" is the subset of the intersection of the constraints
+ * for which some code is executed.
+ * "build" is the build in which graft->node was created.
+ *
+ * We separate lower bounds, upper bounds and constraints that
+ * are independent of the loop iterator.
+ *
+ * The actual for loop bounds are generated in refine_generic_bounds.
+ */
+static __isl_give isl_ast_graft *refine_generic_split(
+	__isl_take isl_ast_graft *graft, __isl_take isl_constraint_list *list,
+	__isl_keep isl_set *domain, __isl_keep isl_ast_build *build)
+{
+	struct isl_ast_count_constraints_data data;
+	isl_constraint_list *lower;
+	isl_constraint_list *upper;
+
+	if (!list)
+		return isl_ast_graft_free(graft);
+
+	data.pos = isl_ast_build_get_depth(build);
+
+	list = isl_constraint_list_sort(list, &cmp_constraint, &data.pos);
+	if (!list)
+		return isl_ast_graft_free(graft);
+
+	data.n_indep = data.n_lower = data.n_upper = 0;
+	if (isl_constraint_list_foreach(list, &count_constraints, &data) < 0) {
+		isl_constraint_list_free(list);
+		return isl_ast_graft_free(graft);
+	}
+
+	lower = isl_constraint_list_drop(list, 0, data.n_indep);
+	upper = isl_constraint_list_copy(lower);
+	lower = isl_constraint_list_drop(lower, data.n_lower, data.n_upper);
+	upper = isl_constraint_list_drop(upper, 0, data.n_lower);
+
+	return refine_generic_bounds(graft, lower, upper, domain, build);
+}
+
+/* Update "graft" based on "bounds" and "domain" for the generic,
+ * non-degenerate, case.
+ *
+ * "bounds" respresent the bounds that need to be encoded by
+ * the for loop (or a guard around the for loop).
+ * "domain" is the subset of "bounds" for which some code is executed.
+ * "build" is the build in which graft->node was created.
+ *
+ * We break up "bounds" into a list of constraints and continue with
+ * refine_generic_split.
+ */
+static __isl_give isl_ast_graft *refine_generic(
+	__isl_take isl_ast_graft *graft,
+	__isl_keep isl_basic_set *bounds, __isl_keep isl_set *domain,
+	__isl_keep isl_ast_build *build)
+{
+	isl_constraint_list *list;
+
+	if (!build || !graft)
+		return isl_ast_graft_free(graft);
+
+	list = isl_basic_set_get_constraint_list(bounds);
+
+	graft = refine_generic_split(graft, list, domain, build);
+
+	return graft;
+}
+
+/* Create a for node for the current level.
+ *
+ * Mark the for node degenerate if "degenerate" is set.
+ */
+static __isl_give isl_ast_node *create_for(__isl_keep isl_ast_build *build,
+	int degenerate)
+{
+	int depth;
+	isl_id *id;
+	isl_ast_node *node;
+
+	if (!build)
+		return NULL;
+
+	depth = isl_ast_build_get_depth(build);
+	id = isl_ast_build_get_iterator_id(build, depth);
+	node = isl_ast_node_alloc_for(id);
+	if (degenerate)
+		node = isl_ast_node_for_mark_degenerate(node);
+
+	return node;
+}
+
+/* If the ast_build_exploit_nested_bounds option is set, then return
+ * the constraints enforced by all elements in "list".
+ * Otherwise, return the universe.
+ */
+static __isl_give isl_basic_set *extract_shared_enforced(
+	__isl_keep isl_ast_graft_list *list, __isl_keep isl_ast_build *build)
+{
+	isl_ctx *ctx;
+	isl_space *space;
+
+	if (!list)
+		return NULL;
+
+	ctx = isl_ast_graft_list_get_ctx(list);
+	if (isl_options_get_ast_build_exploit_nested_bounds(ctx))
+		return isl_ast_graft_list_extract_shared_enforced(list, build);
+
+	space = isl_ast_build_get_space(build, 1);
+	return isl_basic_set_universe(space);
+}
+
+/* Return the pending constraints of "build" that are not already taken
+ * care of (by a combination of "enforced" and the generated constraints
+ * of "build").
+ */
+static __isl_give isl_set *extract_pending(__isl_keep isl_ast_build *build,
+	__isl_keep isl_basic_set *enforced)
+{
+	isl_set *guard, *context;
+
+	guard = isl_ast_build_get_pending(build);
+	context = isl_set_from_basic_set(isl_basic_set_copy(enforced));
+	context = isl_set_intersect(context,
+					isl_ast_build_get_generated(build));
+	return isl_set_gist(guard, context);
+}
+
+/* Create an AST node for the current dimension based on
+ * the schedule domain "bounds" and return the node encapsulated
+ * in an isl_ast_graft.
+ *
+ * "executed" is the current inverse schedule, taking into account
+ * the bounds in "bounds"
+ * "domain" is the domain of "executed", with inner dimensions projected out.
+ * It may be a strict subset of "bounds" in case "bounds" was created
+ * based on the atomic option or based on separation with explicit bounds.
+ *
+ * "domain" may satisfy additional equalities that result
+ * from intersecting "executed" with "bounds" in add_node.
+ * It may also satisfy some global constraints that were dropped out because
+ * we performed separation with explicit bounds.
+ * The very first step is then to copy these constraints to "bounds".
+ *
+ * Since we may be calling before_each_for and after_each_for
+ * callbacks, we record the current inverse schedule in the build.
+ *
+ * We consider three builds,
+ * "build" is the one in which the current level is created,
+ * "body_build" is the build in which the next level is created,
+ * "sub_build" is essentially the same as "body_build", except that
+ * the depth has not been increased yet.
+ *
+ * "build" already contains information (in strides and offsets)
+ * about the strides at the current level, but this information is not
+ * reflected in the build->domain.
+ * We first add this information and the "bounds" to the sub_build->domain.
+ * isl_ast_build_set_loop_bounds adds the stride information and
+ * checks whether the current dimension attains
+ * only a single value and whether this single value can be represented using
+ * a single affine expression.
+ * In the first case, the current level is considered "degenerate".
+ * In the second, sub-case, the current level is considered "eliminated".
+ * Eliminated levels don't need to be reflected in the AST since we can
+ * simply plug in the affine expression.  For degenerate, but non-eliminated,
+ * levels, we do introduce a for node, but mark is as degenerate so that
+ * it can be printed as an assignment of the single value to the loop
+ * "iterator".
+ *
+ * If the current level is eliminated, we explicitly plug in the value
+ * for the current level found by isl_ast_build_set_loop_bounds in the
+ * inverse schedule.  This ensures that if we are working on a slice
+ * of the domain based on information available in the inverse schedule
+ * and the build domain, that then this information is also reflected
+ * in the inverse schedule.  This operation also eliminates the current
+ * dimension from the inverse schedule making sure no inner dimensions depend
+ * on the current dimension.  Otherwise, we create a for node, marking
+ * it degenerate if appropriate.  The initial for node is still incomplete
+ * and will be completed in either refine_degenerate or refine_generic.
+ *
+ * We then generate a sequence of grafts for the next level,
+ * create a surrounding graft for the current level and insert
+ * the for node we created (if the current level is not eliminated).
+ * Before creating a graft for the current level, we first extract
+ * hoistable constraints from the child guards and combine them
+ * with the pending constraints in the build.  These constraints
+ * are used to simplify the child guards and then added to the guard
+ * of the current graft to ensure that they will be generated.
+ * If the hoisted guard is a disjunction, then we use it directly
+ * to gist the guards on the children before intersect it with the
+ * pending constraints.  We do so because this disjunction is typically
+ * identical to the guards on the children such that these guards
+ * can be effectively removed completely.  After the intersection,
+ * the gist operation would have a harder time figuring this out.
+ *
+ * Finally, we set the bounds of the for loop in either
+ * refine_degenerate or refine_generic.
+ * We do so in a context where the pending constraints of the build
+ * have been replaced by the guard of the current graft.
+ */
+static __isl_give isl_ast_graft *create_node_scaled(
+	__isl_take isl_union_map *executed,
+	__isl_take isl_basic_set *bounds, __isl_take isl_set *domain,
+	__isl_take isl_ast_build *build)
+{
+	int depth;
+	int degenerate, eliminated;
+	isl_basic_set *hull;
+	isl_basic_set *enforced;
+	isl_set *guard, *hoisted;
+	isl_ast_node *node = NULL;
+	isl_ast_graft *graft;
+	isl_ast_graft_list *children;
+	isl_ast_build *sub_build;
+	isl_ast_build *body_build;
+
+	domain = isl_ast_build_eliminate_divs(build, domain);
+	domain = isl_set_detect_equalities(domain);
+	hull = isl_set_unshifted_simple_hull(isl_set_copy(domain));
+	bounds = isl_basic_set_intersect(bounds, hull);
+	build = isl_ast_build_set_executed(build, isl_union_map_copy(executed));
+
+	depth = isl_ast_build_get_depth(build);
+	sub_build = isl_ast_build_copy(build);
+	bounds = isl_basic_set_remove_redundancies(bounds);
+	bounds = isl_ast_build_specialize_basic_set(sub_build, bounds);
+	sub_build = isl_ast_build_set_loop_bounds(sub_build,
+						isl_basic_set_copy(bounds));
+	degenerate = isl_ast_build_has_value(sub_build);
+	eliminated = isl_ast_build_has_affine_value(sub_build, depth);
+	if (degenerate < 0 || eliminated < 0)
+		executed = isl_union_map_free(executed);
+	if (!degenerate)
+		bounds = isl_ast_build_compute_gist_basic_set(build, bounds);
+	sub_build = isl_ast_build_set_pending_generated(sub_build,
+						isl_basic_set_copy(bounds));
+	if (eliminated)
+		executed = plug_in_values(executed, sub_build);
+	else
+		node = create_for(build, degenerate);
+
+	body_build = isl_ast_build_copy(sub_build);
+	body_build = isl_ast_build_increase_depth(body_build);
+	if (!eliminated)
+		node = before_each_for(node, body_build);
+	children = generate_next_level(executed,
+				    isl_ast_build_copy(body_build));
+
+	enforced = extract_shared_enforced(children, build);
+	guard = extract_pending(sub_build, enforced);
+	hoisted = isl_ast_graft_list_extract_hoistable_guard(children, build);
+	if (isl_set_n_basic_set(hoisted) > 1)
+		children = isl_ast_graft_list_gist_guards(children,
+						    isl_set_copy(hoisted));
+	guard = isl_set_intersect(guard, hoisted);
+	if (!eliminated)
+		guard = add_implied_guards(guard, degenerate, bounds, build);
+
+	graft = isl_ast_graft_alloc_from_children(children,
+			    isl_set_copy(guard), enforced, build, sub_build);
+
+	if (!eliminated) {
+		isl_ast_build *for_build;
+
+		graft = isl_ast_graft_insert_for(graft, node);
+		for_build = isl_ast_build_copy(build);
+		for_build = isl_ast_build_replace_pending_by_guard(for_build,
+							isl_set_copy(guard));
+		if (degenerate)
+			graft = refine_degenerate(graft, for_build, sub_build);
+		else
+			graft = refine_generic(graft, bounds,
+					domain, for_build);
+		isl_ast_build_free(for_build);
+	}
+	isl_set_free(guard);
+	if (!eliminated)
+		graft = after_each_for(graft, body_build);
+
+	isl_ast_build_free(body_build);
+	isl_ast_build_free(sub_build);
+	isl_ast_build_free(build);
+	isl_basic_set_free(bounds);
+	isl_set_free(domain);
+
+	return graft;
+}
+
+/* Internal data structure for checking if all constraints involving
+ * the input dimension "depth" are such that the other coefficients
+ * are multiples of "m", reducing "m" if they are not.
+ * If "m" is reduced all the way down to "1", then the check has failed
+ * and we break out of the iteration.
+ */
+struct isl_check_scaled_data {
+	int depth;
+	isl_val *m;
+};
+
+/* If constraint "c" involves the input dimension data->depth,
+ * then make sure that all the other coefficients are multiples of data->m,
+ * reducing data->m if needed.
+ * Break out of the iteration if data->m has become equal to "1".
+ */
+static isl_stat constraint_check_scaled(__isl_take isl_constraint *c,
+	void *user)
+{
+	struct isl_check_scaled_data *data = user;
+	int i, j, n;
+	enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_out,
+				    isl_dim_div };
+
+	if (!isl_constraint_involves_dims(c, isl_dim_in, data->depth, 1)) {
+		isl_constraint_free(c);
+		return isl_stat_ok;
+	}
+
+	for (i = 0; i < 4; ++i) {
+		n = isl_constraint_dim(c, t[i]);
+		for (j = 0; j < n; ++j) {
+			isl_val *d;
+
+			if (t[i] == isl_dim_in && j == data->depth)
+				continue;
+			if (!isl_constraint_involves_dims(c, t[i], j, 1))
+				continue;
+			d = isl_constraint_get_coefficient_val(c, t[i], j);
+			data->m = isl_val_gcd(data->m, d);
+			if (isl_val_is_one(data->m))
+				break;
+		}
+		if (j < n)
+			break;
+	}
+
+	isl_constraint_free(c);
+
+	return i < 4 ? isl_stat_error : isl_stat_ok;
+}
+
+/* For each constraint of "bmap" that involves the input dimension data->depth,
+ * make sure that all the other coefficients are multiples of data->m,
+ * reducing data->m if needed.
+ * Break out of the iteration if data->m has become equal to "1".
+ */
+static isl_stat basic_map_check_scaled(__isl_take isl_basic_map *bmap,
+	void *user)
+{
+	isl_stat r;
+
+	r = isl_basic_map_foreach_constraint(bmap,
+						&constraint_check_scaled, user);
+	isl_basic_map_free(bmap);
+
+	return r;
+}
+
+/* For each constraint of "map" that involves the input dimension data->depth,
+ * make sure that all the other coefficients are multiples of data->m,
+ * reducing data->m if needed.
+ * Break out of the iteration if data->m has become equal to "1".
+ */
+static isl_stat map_check_scaled(__isl_take isl_map *map, void *user)
+{
+	isl_stat r;
+
+	r = isl_map_foreach_basic_map(map, &basic_map_check_scaled, user);
+	isl_map_free(map);
+
+	return r;
+}
+
+/* Create an AST node for the current dimension based on
+ * the schedule domain "bounds" and return the node encapsulated
+ * in an isl_ast_graft.
+ *
+ * "executed" is the current inverse schedule, taking into account
+ * the bounds in "bounds"
+ * "domain" is the domain of "executed", with inner dimensions projected out.
+ *
+ *
+ * Before moving on to the actual AST node construction in create_node_scaled,
+ * we first check if the current dimension is strided and if we can scale
+ * down this stride.  Note that we only do this if the ast_build_scale_strides
+ * option is set.
+ *
+ * In particular, let the current dimension take on values
+ *
+ *	f + s a
+ *
+ * with a an integer.  We check if we can find an integer m that (obviously)
+ * divides both f and s.
+ *
+ * If so, we check if the current dimension only appears in constraints
+ * where the coefficients of the other variables are multiples of m.
+ * We perform this extra check to avoid the risk of introducing
+ * divisions by scaling down the current dimension.
+ *
+ * If so, we scale the current dimension down by a factor of m.
+ * That is, we plug in
+ *
+ *	i = m i'							(1)
+ *
+ * Note that in principle we could always scale down strided loops
+ * by plugging in
+ *
+ *	i = f + s i'
+ *
+ * but this may result in i' taking on larger values than the original i,
+ * due to the shift by "f".
+ * By constrast, the scaling in (1) can only reduce the (absolute) value "i".
+ */
+static __isl_give isl_ast_graft *create_node(__isl_take isl_union_map *executed,
+	__isl_take isl_basic_set *bounds, __isl_take isl_set *domain,
+	__isl_take isl_ast_build *build)
+{
+	struct isl_check_scaled_data data;
+	isl_ctx *ctx;
+	isl_aff *offset;
+	isl_val *d;
+
+	ctx = isl_ast_build_get_ctx(build);
+	if (!isl_options_get_ast_build_scale_strides(ctx))
+		return create_node_scaled(executed, bounds, domain, build);
+
+	data.depth = isl_ast_build_get_depth(build);
+	if (!isl_ast_build_has_stride(build, data.depth))
+		return create_node_scaled(executed, bounds, domain, build);
+
+	offset = isl_ast_build_get_offset(build, data.depth);
+	data.m = isl_ast_build_get_stride(build, data.depth);
+	if (!data.m)
+		offset = isl_aff_free(offset);
+	offset = isl_aff_scale_down_val(offset, isl_val_copy(data.m));
+	d = isl_aff_get_denominator_val(offset);
+	if (!d)
+		executed = isl_union_map_free(executed);
+
+	if (executed && isl_val_is_divisible_by(data.m, d))
+		data.m = isl_val_div(data.m, d);
+	else {
+		data.m = isl_val_set_si(data.m, 1);
+		isl_val_free(d);
+	}
+
+	if (!isl_val_is_one(data.m)) {
+		if (isl_union_map_foreach_map(executed, &map_check_scaled,
+						&data) < 0 &&
+		    !isl_val_is_one(data.m))
+			executed = isl_union_map_free(executed);
+	}
+
+	if (!isl_val_is_one(data.m)) {
+		isl_space *space;
+		isl_multi_aff *ma;
+		isl_aff *aff;
+		isl_map *map;
+		isl_union_map *umap;
+
+		space = isl_ast_build_get_space(build, 1);
+		space = isl_space_map_from_set(space);
+		ma = isl_multi_aff_identity(space);
+		aff = isl_multi_aff_get_aff(ma, data.depth);
+		aff = isl_aff_scale_val(aff, isl_val_copy(data.m));
+		ma = isl_multi_aff_set_aff(ma, data.depth, aff);
+
+		bounds = isl_basic_set_preimage_multi_aff(bounds,
+						isl_multi_aff_copy(ma));
+		domain = isl_set_preimage_multi_aff(domain,
+						isl_multi_aff_copy(ma));
+		map = isl_map_reverse(isl_map_from_multi_aff(ma));
+		umap = isl_union_map_from_map(map);
+		executed = isl_union_map_apply_domain(executed,
+						isl_union_map_copy(umap));
+		build = isl_ast_build_scale_down(build, isl_val_copy(data.m),
+						umap);
+	}
+	isl_aff_free(offset);
+	isl_val_free(data.m);
+
+	return create_node_scaled(executed, bounds, domain, build);
+}
+
+/* Add the basic set to the list that "user" points to.
+ */
+static isl_stat collect_basic_set(__isl_take isl_basic_set *bset, void *user)
+{
+	isl_basic_set_list **list = user;
+
+	*list = isl_basic_set_list_add(*list, bset);
+
+	return isl_stat_ok;
+}
+
+/* Extract the basic sets of "set" and collect them in an isl_basic_set_list.
+ */
+static __isl_give isl_basic_set_list *isl_basic_set_list_from_set(
+	__isl_take isl_set *set)
+{
+	int n;
+	isl_ctx *ctx;
+	isl_basic_set_list *list;
+
+	if (!set)
+		return NULL;
+
+	ctx = isl_set_get_ctx(set);
+
+	n = isl_set_n_basic_set(set);
+	list = isl_basic_set_list_alloc(ctx, n);
+	if (isl_set_foreach_basic_set(set, &collect_basic_set, &list) < 0)
+		list = isl_basic_set_list_free(list);
+
+	isl_set_free(set);
+	return list;
+}
+
+/* Generate code for the schedule domain "bounds"
+ * and add the result to "list".
+ *
+ * We mainly detect strides here and check if the bounds do not
+ * conflict with the current build domain
+ * and then pass over control to create_node.
+ *
+ * "bounds" reflects the bounds on the current dimension and possibly
+ * some extra conditions on outer dimensions.
+ * It does not, however, include any divs involving the current dimension,
+ * so it does not capture any stride constraints.
+ * We therefore need to compute that part of the schedule domain that
+ * intersects with "bounds" and derive the strides from the result.
+ */
+static __isl_give isl_ast_graft_list *add_node(
+	__isl_take isl_ast_graft_list *list, __isl_take isl_union_map *executed,
+	__isl_take isl_basic_set *bounds, __isl_take isl_ast_build *build)
+{
+	isl_ast_graft *graft;
+	isl_set *domain = NULL;
+	isl_union_set *uset;
+	int empty, disjoint;
+
+	uset = isl_union_set_from_basic_set(isl_basic_set_copy(bounds));
+	executed = isl_union_map_intersect_domain(executed, uset);
+	empty = isl_union_map_is_empty(executed);
+	if (empty < 0)
+		goto error;
+	if (empty)
+		goto done;
+
+	uset = isl_union_map_domain(isl_union_map_copy(executed));
+	domain = isl_set_from_union_set(uset);
+	domain = isl_ast_build_specialize(build, domain);
+
+	domain = isl_set_compute_divs(domain);
+	domain = isl_ast_build_eliminate_inner(build, domain);
+	disjoint = isl_set_is_disjoint(domain, build->domain);
+	if (disjoint < 0)
+		goto error;
+	if (disjoint)
+		goto done;
+
+	build = isl_ast_build_detect_strides(build, isl_set_copy(domain));
+
+	graft = create_node(executed, bounds, domain,
+				isl_ast_build_copy(build));
+	list = isl_ast_graft_list_add(list, graft);
+	isl_ast_build_free(build);
+	return list;
+error:
+	list = isl_ast_graft_list_free(list);
+done:
+	isl_set_free(domain);
+	isl_basic_set_free(bounds);
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+	return list;
+}
+
+/* Does any element of i follow or coincide with any element of j
+ * at the current depth for equal values of the outer dimensions?
+ */
+static isl_bool domain_follows_at_depth(__isl_keep isl_basic_set *i,
+	__isl_keep isl_basic_set *j, void *user)
+{
+	int depth = *(int *) user;
+	isl_basic_map *test;
+	isl_bool empty;
+	int l;
+
+	test = isl_basic_map_from_domain_and_range(isl_basic_set_copy(i),
+						    isl_basic_set_copy(j));
+	for (l = 0; l < depth; ++l)
+		test = isl_basic_map_equate(test, isl_dim_in, l,
+						isl_dim_out, l);
+	test = isl_basic_map_order_ge(test, isl_dim_in, depth,
+					isl_dim_out, depth);
+	empty = isl_basic_map_is_empty(test);
+	isl_basic_map_free(test);
+
+	return empty < 0 ? isl_bool_error : !empty;
+}
+
+/* Split up each element of "list" into a part that is related to "bset"
+ * according to "gt" and a part that is not.
+ * Return a list that consist of "bset" and all the pieces.
+ */
+static __isl_give isl_basic_set_list *add_split_on(
+	__isl_take isl_basic_set_list *list, __isl_take isl_basic_set *bset,
+	__isl_keep isl_basic_map *gt)
+{
+	int i, n;
+	isl_basic_set_list *res;
+
+	if (!list)
+		bset = isl_basic_set_free(bset);
+
+	gt = isl_basic_map_copy(gt);
+	gt = isl_basic_map_intersect_domain(gt, isl_basic_set_copy(bset));
+	n = isl_basic_set_list_n_basic_set(list);
+	res = isl_basic_set_list_from_basic_set(bset);
+	for (i = 0; res && i < n; ++i) {
+		isl_basic_set *bset;
+		isl_set *set1, *set2;
+		isl_basic_map *bmap;
+		int empty;
+
+		bset = isl_basic_set_list_get_basic_set(list, i);
+		bmap = isl_basic_map_copy(gt);
+		bmap = isl_basic_map_intersect_range(bmap, bset);
+		bset = isl_basic_map_range(bmap);
+		empty = isl_basic_set_is_empty(bset);
+		if (empty < 0)
+			res = isl_basic_set_list_free(res);
+		if (empty)  {
+			isl_basic_set_free(bset);
+			bset = isl_basic_set_list_get_basic_set(list, i);
+			res = isl_basic_set_list_add(res, bset);
+			continue;
+		}
+
+		res = isl_basic_set_list_add(res, isl_basic_set_copy(bset));
+		set1 = isl_set_from_basic_set(bset);
+		bset = isl_basic_set_list_get_basic_set(list, i);
+		set2 = isl_set_from_basic_set(bset);
+		set1 = isl_set_subtract(set2, set1);
+		set1 = isl_set_make_disjoint(set1);
+
+		res = isl_basic_set_list_concat(res,
+					    isl_basic_set_list_from_set(set1));
+	}
+	isl_basic_map_free(gt);
+	isl_basic_set_list_free(list);
+	return res;
+}
+
+static __isl_give isl_ast_graft_list *generate_sorted_domains(
+	__isl_keep isl_basic_set_list *domain_list,
+	__isl_keep isl_union_map *executed,
+	__isl_keep isl_ast_build *build);
+
+/* Internal data structure for add_nodes.
+ *
+ * "executed" and "build" are extra arguments to be passed to add_node.
+ * "list" collects the results.
+ */
+struct isl_add_nodes_data {
+	isl_union_map *executed;
+	isl_ast_build *build;
+
+	isl_ast_graft_list *list;
+};
+
+/* Generate code for the schedule domains in "scc"
+ * and add the results to "list".
+ *
+ * The domains in "scc" form a strongly connected component in the ordering.
+ * If the number of domains in "scc" is larger than 1, then this means
+ * that we cannot determine a valid ordering for the domains in the component.
+ * This should be fairly rare because the individual domains
+ * have been made disjoint first.
+ * The problem is that the domains may be integrally disjoint but not
+ * rationally disjoint.  For example, we may have domains
+ *
+ *	{ [i,i] : 0 <= i <= 1 }		and	{ [i,1-i] : 0 <= i <= 1 }
+ *
+ * These two domains have an empty intersection, but their rational
+ * relaxations do intersect.  It is impossible to order these domains
+ * in the second dimension because the first should be ordered before
+ * the second for outer dimension equal to 0, while it should be ordered
+ * after for outer dimension equal to 1.
+ *
+ * This may happen in particular in case of unrolling since the domain
+ * of each slice is replaced by its simple hull.
+ *
+ * For each basic set i in "scc" and for each of the following basic sets j,
+ * we split off that part of the basic set i that shares the outer dimensions
+ * with j and lies before j in the current dimension.
+ * We collect all the pieces in a new list that replaces "scc".
+ *
+ * While the elements in "scc" should be disjoint, we double-check
+ * this property to avoid running into an infinite recursion in case
+ * they intersect due to some internal error.
+ */
+static isl_stat add_nodes(__isl_take isl_basic_set_list *scc, void *user)
+{
+	struct isl_add_nodes_data *data = user;
+	int i, n, depth;
+	isl_basic_set *bset, *first;
+	isl_basic_set_list *list;
+	isl_space *space;
+	isl_basic_map *gt;
+
+	n = isl_basic_set_list_n_basic_set(scc);
+	bset = isl_basic_set_list_get_basic_set(scc, 0);
+	if (n == 1) {
+		isl_basic_set_list_free(scc);
+		data->list = add_node(data->list,
+				isl_union_map_copy(data->executed), bset,
+				isl_ast_build_copy(data->build));
+		return data->list ? isl_stat_ok : isl_stat_error;
+	}
+
+	depth = isl_ast_build_get_depth(data->build);
+	space = isl_basic_set_get_space(bset);
+	space = isl_space_map_from_set(space);
+	gt = isl_basic_map_universe(space);
+	for (i = 0; i < depth; ++i)
+		gt = isl_basic_map_equate(gt, isl_dim_in, i, isl_dim_out, i);
+	gt = isl_basic_map_order_gt(gt, isl_dim_in, depth, isl_dim_out, depth);
+
+	first = isl_basic_set_copy(bset);
+	list = isl_basic_set_list_from_basic_set(bset);
+	for (i = 1; i < n; ++i) {
+		int disjoint;
+
+		bset = isl_basic_set_list_get_basic_set(scc, i);
+
+		disjoint = isl_basic_set_is_disjoint(bset, first);
+		if (disjoint < 0)
+			list = isl_basic_set_list_free(list);
+		else if (!disjoint)
+			isl_die(isl_basic_set_list_get_ctx(scc),
+				isl_error_internal,
+				"basic sets in scc are assumed to be disjoint",
+				list = isl_basic_set_list_free(list));
+
+		list = add_split_on(list, bset, gt);
+	}
+	isl_basic_set_free(first);
+	isl_basic_map_free(gt);
+	isl_basic_set_list_free(scc);
+	scc = list;
+	data->list = isl_ast_graft_list_concat(data->list,
+		    generate_sorted_domains(scc, data->executed, data->build));
+	isl_basic_set_list_free(scc);
+
+	return data->list ? isl_stat_ok : isl_stat_error;
+}
+
+/* Sort the domains in "domain_list" according to the execution order
+ * at the current depth (for equal values of the outer dimensions),
+ * generate code for each of them, collecting the results in a list.
+ * If no code is generated (because the intersection of the inverse schedule
+ * with the domains turns out to be empty), then an empty list is returned.
+ *
+ * The caller is responsible for ensuring that the basic sets in "domain_list"
+ * are pair-wise disjoint.  It can, however, in principle happen that
+ * two basic sets should be ordered one way for one value of the outer
+ * dimensions and the other way for some other value of the outer dimensions.
+ * We therefore play safe and look for strongly connected components.
+ * The function add_nodes takes care of handling non-trivial components.
+ */
+static __isl_give isl_ast_graft_list *generate_sorted_domains(
+	__isl_keep isl_basic_set_list *domain_list,
+	__isl_keep isl_union_map *executed, __isl_keep isl_ast_build *build)
+{
+	isl_ctx *ctx;
+	struct isl_add_nodes_data data;
+	int depth;
+	int n;
+
+	if (!domain_list)
+		return NULL;
+
+	ctx = isl_basic_set_list_get_ctx(domain_list);
+	n = isl_basic_set_list_n_basic_set(domain_list);
+	data.list = isl_ast_graft_list_alloc(ctx, n);
+	if (n == 0)
+		return data.list;
+	if (n == 1)
+		return add_node(data.list, isl_union_map_copy(executed),
+			isl_basic_set_list_get_basic_set(domain_list, 0),
+			isl_ast_build_copy(build));
+
+	depth = isl_ast_build_get_depth(build);
+	data.executed = executed;
+	data.build = build;
+	if (isl_basic_set_list_foreach_scc(domain_list,
+					&domain_follows_at_depth, &depth,
+					&add_nodes, &data) < 0)
+		data.list = isl_ast_graft_list_free(data.list);
+
+	return data.list;
+}
+
+/* Do i and j share any values for the outer dimensions?
+ */
+static isl_bool shared_outer(__isl_keep isl_basic_set *i,
+	__isl_keep isl_basic_set *j, void *user)
+{
+	int depth = *(int *) user;
+	isl_basic_map *test;
+	isl_bool empty;
+	int l;
+
+	test = isl_basic_map_from_domain_and_range(isl_basic_set_copy(i),
+						    isl_basic_set_copy(j));
+	for (l = 0; l < depth; ++l)
+		test = isl_basic_map_equate(test, isl_dim_in, l,
+						isl_dim_out, l);
+	empty = isl_basic_map_is_empty(test);
+	isl_basic_map_free(test);
+
+	return empty < 0 ? isl_bool_error : !empty;
+}
+
+/* Internal data structure for generate_sorted_domains_wrap.
+ *
+ * "n" is the total number of basic sets
+ * "executed" and "build" are extra arguments to be passed
+ *	to generate_sorted_domains.
+ *
+ * "single" is set to 1 by generate_sorted_domains_wrap if there
+ * is only a single component.
+ * "list" collects the results.
+ */
+struct isl_ast_generate_parallel_domains_data {
+	int n;
+	isl_union_map *executed;
+	isl_ast_build *build;
+
+	int single;
+	isl_ast_graft_list *list;
+};
+
+/* Call generate_sorted_domains on "scc", fuse the result into a list
+ * with either zero or one graft and collect the these single element
+ * lists into data->list.
+ *
+ * If there is only one component, i.e., if the number of basic sets
+ * in the current component is equal to the total number of basic sets,
+ * then data->single is set to 1 and the result of generate_sorted_domains
+ * is not fused.
+ */
+static isl_stat generate_sorted_domains_wrap(__isl_take isl_basic_set_list *scc,
+	void *user)
+{
+	struct isl_ast_generate_parallel_domains_data *data = user;
+	isl_ast_graft_list *list;
+
+	list = generate_sorted_domains(scc, data->executed, data->build);
+	data->single = isl_basic_set_list_n_basic_set(scc) == data->n;
+	if (!data->single)
+		list = isl_ast_graft_list_fuse(list, data->build);
+	if (!data->list)
+		data->list = list;
+	else
+		data->list = isl_ast_graft_list_concat(data->list, list);
+
+	isl_basic_set_list_free(scc);
+	if (!data->list)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Look for any (weakly connected) components in the "domain_list"
+ * of domains that share some values of the outer dimensions.
+ * That is, domains in different components do not share any values
+ * of the outer dimensions.  This means that these components
+ * can be freely reordered.
+ * Within each of the components, we sort the domains according
+ * to the execution order at the current depth.
+ *
+ * If there is more than one component, then generate_sorted_domains_wrap
+ * fuses the result of each call to generate_sorted_domains
+ * into a list with either zero or one graft and collects these (at most)
+ * single element lists into a bigger list. This means that the elements of the
+ * final list can be freely reordered.  In particular, we sort them
+ * according to an arbitrary but fixed ordering to ease merging of
+ * graft lists from different components.
+ */
+static __isl_give isl_ast_graft_list *generate_parallel_domains(
+	__isl_keep isl_basic_set_list *domain_list,
+	__isl_keep isl_union_map *executed, __isl_keep isl_ast_build *build)
+{
+	int depth;
+	struct isl_ast_generate_parallel_domains_data data;
+
+	if (!domain_list)
+		return NULL;
+
+	data.n = isl_basic_set_list_n_basic_set(domain_list);
+	if (data.n <= 1)
+		return generate_sorted_domains(domain_list, executed, build);
+
+	depth = isl_ast_build_get_depth(build);
+	data.list = NULL;
+	data.executed = executed;
+	data.build = build;
+	data.single = 0;
+	if (isl_basic_set_list_foreach_scc(domain_list, &shared_outer, &depth,
+					    &generate_sorted_domains_wrap,
+					    &data) < 0)
+		data.list = isl_ast_graft_list_free(data.list);
+
+	if (!data.single)
+		data.list = isl_ast_graft_list_sort_guard(data.list);
+
+	return data.list;
+}
+
+/* Internal data for separate_domain.
+ *
+ * "explicit" is set if we only want to use explicit bounds.
+ *
+ * "domain" collects the separated domains.
+ */
+struct isl_separate_domain_data {
+	isl_ast_build *build;
+	int explicit;
+	isl_set *domain;
+};
+
+/* Extract implicit bounds on the current dimension for the executed "map".
+ *
+ * The domain of "map" may involve inner dimensions, so we
+ * need to eliminate them.
+ */
+static __isl_give isl_set *implicit_bounds(__isl_take isl_map *map,
+	__isl_keep isl_ast_build *build)
+{
+	isl_set *domain;
+
+	domain = isl_map_domain(map);
+	domain = isl_ast_build_eliminate(build, domain);
+
+	return domain;
+}
+
+/* Extract explicit bounds on the current dimension for the executed "map".
+ *
+ * Rather than eliminating the inner dimensions as in implicit_bounds,
+ * we simply drop any constraints involving those inner dimensions.
+ * The idea is that most bounds that are implied by constraints on the
+ * inner dimensions will be enforced by for loops and not by explicit guards.
+ * There is then no need to separate along those bounds.
+ */
+static __isl_give isl_set *explicit_bounds(__isl_take isl_map *map,
+	__isl_keep isl_ast_build *build)
+{
+	isl_set *domain;
+	int depth, dim;
+
+	dim = isl_map_dim(map, isl_dim_out);
+	map = isl_map_drop_constraints_involving_dims(map, isl_dim_out, 0, dim);
+
+	domain = isl_map_domain(map);
+	depth = isl_ast_build_get_depth(build);
+	dim = isl_set_dim(domain, isl_dim_set);
+	domain = isl_set_detect_equalities(domain);
+	domain = isl_set_drop_constraints_involving_dims(domain,
+				isl_dim_set, depth + 1, dim - (depth + 1));
+	domain = isl_set_remove_divs_involving_dims(domain,
+				isl_dim_set, depth, 1);
+	domain = isl_set_remove_unknown_divs(domain);
+
+	return domain;
+}
+
+/* Split data->domain into pieces that intersect with the range of "map"
+ * and pieces that do not intersect with the range of "map"
+ * and then add that part of the range of "map" that does not intersect
+ * with data->domain.
+ */
+static isl_stat separate_domain(__isl_take isl_map *map, void *user)
+{
+	struct isl_separate_domain_data *data = user;
+	isl_set *domain;
+	isl_set *d1, *d2;
+
+	if (data->explicit)
+		domain = explicit_bounds(map, data->build);
+	else
+		domain = implicit_bounds(map, data->build);
+
+	domain = isl_set_coalesce(domain);
+	domain = isl_set_make_disjoint(domain);
+	d1 = isl_set_subtract(isl_set_copy(domain), isl_set_copy(data->domain));
+	d2 = isl_set_subtract(isl_set_copy(data->domain), isl_set_copy(domain));
+	data->domain = isl_set_intersect(data->domain, domain);
+	data->domain = isl_set_union(data->domain, d1);
+	data->domain = isl_set_union(data->domain, d2);
+
+	return isl_stat_ok;
+}
+
+/* Separate the schedule domains of "executed".
+ *
+ * That is, break up the domain of "executed" into basic sets,
+ * such that for each basic set S, every element in S is associated with
+ * the same domain spaces.
+ *
+ * "space" is the (single) domain space of "executed".
+ */
+static __isl_give isl_set *separate_schedule_domains(
+	__isl_take isl_space *space, __isl_take isl_union_map *executed,
+	__isl_keep isl_ast_build *build)
+{
+	struct isl_separate_domain_data data = { build };
+	isl_ctx *ctx;
+
+	ctx = isl_ast_build_get_ctx(build);
+	data.explicit = isl_options_get_ast_build_separation_bounds(ctx) ==
+				    ISL_AST_BUILD_SEPARATION_BOUNDS_EXPLICIT;
+	data.domain = isl_set_empty(space);
+	if (isl_union_map_foreach_map(executed, &separate_domain, &data) < 0)
+		data.domain = isl_set_free(data.domain);
+
+	isl_union_map_free(executed);
+	return data.domain;
+}
+
+/* Temporary data used during the search for a lower bound for unrolling.
+ *
+ * "build" is the build in which the unrolling will be performed
+ * "domain" is the original set for which to find a lower bound
+ * "depth" is the dimension for which to find a lower boudn
+ * "expansion" is the expansion that needs to be applied to "domain"
+ * in the unrolling that will be performed
+ *
+ * "lower" is the best lower bound found so far.  It is NULL if we have not
+ * found any yet.
+ * "n" is the corresponding size.  If lower is NULL, then the value of n
+ * is undefined.
+ * "n_div" is the maximal number of integer divisions in the first
+ * unrolled iteration (after expansion).  It is set to -1 if it hasn't
+ * been computed yet.
+ */
+struct isl_find_unroll_data {
+	isl_ast_build *build;
+	isl_set *domain;
+	int depth;
+	isl_basic_map *expansion;
+
+	isl_aff *lower;
+	int *n;
+	int n_div;
+};
+
+/* Return the constraint
+ *
+ *	i_"depth" = aff + offset
+ */
+static __isl_give isl_constraint *at_offset(int depth, __isl_keep isl_aff *aff,
+	int offset)
+{
+	aff = isl_aff_copy(aff);
+	aff = isl_aff_add_coefficient_si(aff, isl_dim_in, depth, -1);
+	aff = isl_aff_add_constant_si(aff, offset);
+	return isl_equality_from_aff(aff);
+}
+
+/* Update *user to the number of integer divsions in the first element
+ * of "ma", if it is larger than the current value.
+ */
+static isl_stat update_n_div(__isl_take isl_set *set,
+	__isl_take isl_multi_aff *ma, void *user)
+{
+	isl_aff *aff;
+	int *n = user;
+	int n_div;
+
+	aff = isl_multi_aff_get_aff(ma, 0);
+	n_div = isl_aff_dim(aff, isl_dim_div);
+	isl_aff_free(aff);
+	isl_multi_aff_free(ma);
+	isl_set_free(set);
+
+	if (n_div > *n)
+		*n = n_div;
+
+	return aff ? isl_stat_ok : isl_stat_error;
+}
+
+/* Get the number of integer divisions in the expression for the iterator
+ * value at the first slice in the unrolling based on lower bound "lower",
+ * taking into account the expansion that needs to be performed on this slice.
+ */
+static int get_expanded_n_div(struct isl_find_unroll_data *data,
+	__isl_keep isl_aff *lower)
+{
+	isl_constraint *c;
+	isl_set *set;
+	isl_map *it_map, *expansion;
+	isl_pw_multi_aff *pma;
+	int n;
+
+	c = at_offset(data->depth, lower, 0);
+	set = isl_set_copy(data->domain);
+	set = isl_set_add_constraint(set, c);
+	expansion = isl_map_from_basic_map(isl_basic_map_copy(data->expansion));
+	set = isl_set_apply(set, expansion);
+	it_map = isl_ast_build_map_to_iterator(data->build, set);
+	pma = isl_pw_multi_aff_from_map(it_map);
+	n = 0;
+	if (isl_pw_multi_aff_foreach_piece(pma, &update_n_div, &n) < 0)
+		n = -1;
+	isl_pw_multi_aff_free(pma);
+
+	return n;
+}
+
+/* Is the lower bound "lower" with corresponding iteration count "n"
+ * better than the one stored in "data"?
+ * If there is no upper bound on the iteration count ("n" is infinity) or
+ * if the count is too large, then we cannot use this lower bound.
+ * Otherwise, if there was no previous lower bound or
+ * if the iteration count of the new lower bound is smaller than
+ * the iteration count of the previous lower bound, then we consider
+ * the new lower bound to be better.
+ * If the iteration count is the same, then compare the number
+ * of integer divisions that would be needed to express
+ * the iterator value at the first slice in the unrolling
+ * according to the lower bound.  If we end up computing this
+ * number, then store the lowest value in data->n_div.
+ */
+static int is_better_lower_bound(struct isl_find_unroll_data *data,
+	__isl_keep isl_aff *lower, __isl_keep isl_val *n)
+{
+	int cmp;
+	int n_div;
+
+	if (!n)
+		return -1;
+	if (isl_val_is_infty(n))
+		return 0;
+	if (isl_val_cmp_si(n, INT_MAX) > 0)
+		return 0;
+	if (!data->lower)
+		return 1;
+	cmp = isl_val_cmp_si(n, *data->n);
+	if (cmp < 0)
+		return 1;
+	if (cmp > 0)
+		return 0;
+	if (data->n_div < 0)
+		data->n_div = get_expanded_n_div(data, data->lower);
+	if (data->n_div < 0)
+		return -1;
+	if (data->n_div == 0)
+		return 0;
+	n_div = get_expanded_n_div(data, lower);
+	if (n_div < 0)
+		return -1;
+	if (n_div >= data->n_div)
+		return 0;
+	data->n_div = n_div;
+
+	return 1;
+}
+
+/* Check if we can use "c" as a lower bound and if it is better than
+ * any previously found lower bound.
+ *
+ * If "c" does not involve the dimension at the current depth,
+ * then we cannot use it.
+ * Otherwise, let "c" be of the form
+ *
+ *	i >= f(j)/a
+ *
+ * We compute the maximal value of
+ *
+ *	-ceil(f(j)/a)) + i + 1
+ *
+ * over the domain.  If there is such a value "n", then we know
+ *
+ *	-ceil(f(j)/a)) + i + 1 <= n
+ *
+ * or
+ *
+ *	i < ceil(f(j)/a)) + n
+ *
+ * meaning that we can use ceil(f(j)/a)) as a lower bound for unrolling.
+ * We just need to check if we have found any lower bound before and
+ * if the new lower bound is better (smaller n or fewer integer divisions)
+ * than the previously found lower bounds.
+ */
+static isl_stat update_unrolling_lower_bound(struct isl_find_unroll_data *data,
+	__isl_keep isl_constraint *c)
+{
+	isl_aff *aff, *lower;
+	isl_val *max;
+	int better;
+
+	if (!isl_constraint_is_lower_bound(c, isl_dim_set, data->depth))
+		return isl_stat_ok;
+
+	lower = isl_constraint_get_bound(c, isl_dim_set, data->depth);
+	lower = isl_aff_ceil(lower);
+	aff = isl_aff_copy(lower);
+	aff = isl_aff_neg(aff);
+	aff = isl_aff_add_coefficient_si(aff, isl_dim_in, data->depth, 1);
+	aff = isl_aff_add_constant_si(aff, 1);
+	max = isl_set_max_val(data->domain, aff);
+	isl_aff_free(aff);
+
+	better = is_better_lower_bound(data, lower, max);
+	if (better < 0 || !better) {
+		isl_val_free(max);
+		isl_aff_free(lower);
+		return better < 0 ? isl_stat_error : isl_stat_ok;
+	}
+
+	isl_aff_free(data->lower);
+	data->lower = lower;
+	*data->n = isl_val_get_num_si(max);
+	isl_val_free(max);
+
+	return isl_stat_ok;
+}
+
+/* Check if we can use "c" as a lower bound and if it is better than
+ * any previously found lower bound.
+ */
+static isl_stat constraint_find_unroll(__isl_take isl_constraint *c, void *user)
+{
+	struct isl_find_unroll_data *data;
+	isl_stat r;
+
+	data = (struct isl_find_unroll_data *) user;
+	r = update_unrolling_lower_bound(data, c);
+	isl_constraint_free(c);
+
+	return r;
+}
+
+/* Look for a lower bound l(i) on the dimension at "depth"
+ * and a size n such that "domain" is a subset of
+ *
+ *	{ [i] : l(i) <= i_d < l(i) + n }
+ *
+ * where d is "depth" and l(i) depends only on earlier dimensions.
+ * Furthermore, try and find a lower bound such that n is as small as possible.
+ * In particular, "n" needs to be finite.
+ * "build" is the build in which the unrolling will be performed.
+ * "expansion" is the expansion that needs to be applied to "domain"
+ * in the unrolling that will be performed.
+ *
+ * Inner dimensions have been eliminated from "domain" by the caller.
+ *
+ * We first construct a collection of lower bounds on the input set
+ * by computing its simple hull.  We then iterate through them,
+ * discarding those that we cannot use (either because they do not
+ * involve the dimension at "depth" or because they have no corresponding
+ * upper bound, meaning that "n" would be unbounded) and pick out the
+ * best from the remaining ones.
+ *
+ * If we cannot find a suitable lower bound, then we consider that
+ * to be an error.
+ */
+static __isl_give isl_aff *find_unroll_lower_bound(
+	__isl_keep isl_ast_build *build, __isl_keep isl_set *domain,
+	int depth, __isl_keep isl_basic_map *expansion, int *n)
+{
+	struct isl_find_unroll_data data =
+			{ build, domain, depth, expansion, NULL, n, -1 };
+	isl_basic_set *hull;
+
+	hull = isl_set_simple_hull(isl_set_copy(domain));
+
+	if (isl_basic_set_foreach_constraint(hull,
+					    &constraint_find_unroll, &data) < 0)
+		goto error;
+
+	isl_basic_set_free(hull);
+
+	if (!data.lower)
+		isl_die(isl_set_get_ctx(domain), isl_error_invalid,
+			"cannot find lower bound for unrolling", return NULL);
+
+	return data.lower;
+error:
+	isl_basic_set_free(hull);
+	return isl_aff_free(data.lower);
+}
+
+/* Call "fn" on each iteration of the current dimension of "domain".
+ * If "init" is not NULL, then it is called with the number of
+ * iterations before any call to "fn".
+ * Return -1 on failure.
+ *
+ * Since we are going to be iterating over the individual values,
+ * we first check if there are any strides on the current dimension.
+ * If there is, we rewrite the current dimension i as
+ *
+ *		i = stride i' + offset
+ *
+ * and then iterate over individual values of i' instead.
+ *
+ * We then look for a lower bound on i' and a size such that the domain
+ * is a subset of
+ *
+ *	{ [j,i'] : l(j) <= i' < l(j) + n }
+ *
+ * and then take slices of the domain at values of i'
+ * between l(j) and l(j) + n - 1.
+ *
+ * We compute the unshifted simple hull of each slice to ensure that
+ * we have a single basic set per offset.  The slicing constraint
+ * may get simplified away before the unshifted simple hull is taken
+ * and may therefore in some rare cases disappear from the result.
+ * We therefore explicitly add the constraint back after computing
+ * the unshifted simple hull to ensure that the basic sets
+ * remain disjoint.  The constraints that are dropped by taking the hull
+ * will be taken into account at the next level, as in the case of the
+ * atomic option.
+ *
+ * Finally, we map i' back to i and call "fn".
+ */
+static int foreach_iteration(__isl_take isl_set *domain,
+	__isl_keep isl_ast_build *build, int (*init)(int n, void *user),
+	int (*fn)(__isl_take isl_basic_set *bset, void *user), void *user)
+{
+	int i, n;
+	int empty;
+	int depth;
+	isl_multi_aff *expansion;
+	isl_basic_map *bmap;
+	isl_aff *lower = NULL;
+	isl_ast_build *stride_build;
+
+	depth = isl_ast_build_get_depth(build);
+
+	domain = isl_ast_build_eliminate_inner(build, domain);
+	domain = isl_set_intersect(domain, isl_ast_build_get_domain(build));
+	stride_build = isl_ast_build_copy(build);
+	stride_build = isl_ast_build_detect_strides(stride_build,
+							isl_set_copy(domain));
+	expansion = isl_ast_build_get_stride_expansion(stride_build);
+
+	domain = isl_set_preimage_multi_aff(domain,
+					    isl_multi_aff_copy(expansion));
+	domain = isl_ast_build_eliminate_divs(stride_build, domain);
+	isl_ast_build_free(stride_build);
+
+	bmap = isl_basic_map_from_multi_aff(expansion);
+
+	empty = isl_set_is_empty(domain);
+	if (empty < 0) {
+		n = -1;
+	} else if (empty) {
+		n = 0;
+	} else {
+		lower = find_unroll_lower_bound(build, domain, depth, bmap, &n);
+		if (!lower)
+			n = -1;
+	}
+	if (n >= 0 && init && init(n, user) < 0)
+		n = -1;
+	for (i = 0; i < n; ++i) {
+		isl_set *set;
+		isl_basic_set *bset;
+		isl_constraint *slice;
+
+		slice = at_offset(depth, lower, i);
+		set = isl_set_copy(domain);
+		set = isl_set_add_constraint(set, isl_constraint_copy(slice));
+		bset = isl_set_unshifted_simple_hull(set);
+		bset = isl_basic_set_add_constraint(bset, slice);
+		bset = isl_basic_set_apply(bset, isl_basic_map_copy(bmap));
+
+		if (fn(bset, user) < 0)
+			break;
+	}
+
+	isl_aff_free(lower);
+	isl_set_free(domain);
+	isl_basic_map_free(bmap);
+
+	return n < 0 || i < n ? -1 : 0;
+}
+
+/* Data structure for storing the results and the intermediate objects
+ * of compute_domains.
+ *
+ * "list" is the main result of the function and contains a list
+ * of disjoint basic sets for which code should be generated.
+ *
+ * "executed" and "build" are inputs to compute_domains.
+ * "schedule_domain" is the domain of "executed".
+ *
+ * "option" constains the domains at the current depth that should by
+ * atomic, separated or unrolled.  These domains are as specified by
+ * the user, except that inner dimensions have been eliminated and
+ * that they have been made pair-wise disjoint.
+ *
+ * "sep_class" contains the user-specified split into separation classes
+ * specialized to the current depth.
+ * "done" contains the union of the separation domains that have already
+ * been handled.
+ */
+struct isl_codegen_domains {
+	isl_basic_set_list *list;
+
+	isl_union_map *executed;
+	isl_ast_build *build;
+	isl_set *schedule_domain;
+
+	isl_set *option[4];
+
+	isl_map *sep_class;
+	isl_set *done;
+};
+
+/* Internal data structure for do_unroll.
+ *
+ * "domains" stores the results of compute_domains.
+ * "class_domain" is the original class domain passed to do_unroll.
+ * "unroll_domain" collects the unrolled iterations.
+ */
+struct isl_ast_unroll_data {
+	struct isl_codegen_domains *domains;
+	isl_set *class_domain;
+	isl_set *unroll_domain;
+};
+
+/* Given an iteration of an unrolled domain represented by "bset",
+ * add it to data->domains->list.
+ * Since we may have dropped some constraints, we intersect with
+ * the class domain again to ensure that each element in the list
+ * is disjoint from the other class domains.
+ */
+static int do_unroll_iteration(__isl_take isl_basic_set *bset, void *user)
+{
+	struct isl_ast_unroll_data *data = user;
+	isl_set *set;
+	isl_basic_set_list *list;
+
+	set = isl_set_from_basic_set(bset);
+	data->unroll_domain = isl_set_union(data->unroll_domain,
+					    isl_set_copy(set));
+	set = isl_set_intersect(set, isl_set_copy(data->class_domain));
+	set = isl_set_make_disjoint(set);
+	list = isl_basic_set_list_from_set(set);
+	data->domains->list = isl_basic_set_list_concat(data->domains->list,
+							list);
+
+	return 0;
+}
+
+/* Extend domains->list with a list of basic sets, one for each value
+ * of the current dimension in "domain" and remove the corresponding
+ * sets from the class domain.  Return the updated class domain.
+ * The divs that involve the current dimension have not been projected out
+ * from this domain.
+ *
+ * We call foreach_iteration to iterate over the individual values and
+ * in do_unroll_iteration we collect the individual basic sets in
+ * domains->list and their union in data->unroll_domain, which is then
+ * used to update the class domain.
+ */
+static __isl_give isl_set *do_unroll(struct isl_codegen_domains *domains,
+	__isl_take isl_set *domain, __isl_take isl_set *class_domain)
+{
+	struct isl_ast_unroll_data data;
+
+	if (!domain)
+		return isl_set_free(class_domain);
+	if (!class_domain)
+		return isl_set_free(domain);
+
+	data.domains = domains;
+	data.class_domain = class_domain;
+	data.unroll_domain = isl_set_empty(isl_set_get_space(domain));
+
+	if (foreach_iteration(domain, domains->build, NULL,
+				&do_unroll_iteration, &data) < 0)
+		data.unroll_domain = isl_set_free(data.unroll_domain);
+
+	class_domain = isl_set_subtract(class_domain, data.unroll_domain);
+
+	return class_domain;
+}
+
+/* Add domains to domains->list for each individual value of the current
+ * dimension, for that part of the schedule domain that lies in the
+ * intersection of the option domain and the class domain.
+ * Remove the corresponding sets from the class domain and
+ * return the updated class domain.
+ *
+ * We first break up the unroll option domain into individual pieces
+ * and then handle each of them separately.  The unroll option domain
+ * has been made disjoint in compute_domains_init_options,
+ *
+ * Note that we actively want to combine different pieces of the
+ * schedule domain that have the same value at the current dimension.
+ * We therefore need to break up the unroll option domain before
+ * intersecting with class and schedule domain, hoping that the
+ * unroll option domain specified by the user is relatively simple.
+ */
+static __isl_give isl_set *compute_unroll_domains(
+	struct isl_codegen_domains *domains, __isl_take isl_set *class_domain)
+{
+	isl_set *unroll_domain;
+	isl_basic_set_list *unroll_list;
+	int i, n;
+	int empty;
+
+	empty = isl_set_is_empty(domains->option[isl_ast_loop_unroll]);
+	if (empty < 0)
+		return isl_set_free(class_domain);
+	if (empty)
+		return class_domain;
+
+	unroll_domain = isl_set_copy(domains->option[isl_ast_loop_unroll]);
+	unroll_list = isl_basic_set_list_from_set(unroll_domain);
+
+	n = isl_basic_set_list_n_basic_set(unroll_list);
+	for (i = 0; i < n; ++i) {
+		isl_basic_set *bset;
+
+		bset = isl_basic_set_list_get_basic_set(unroll_list, i);
+		unroll_domain = isl_set_from_basic_set(bset);
+		unroll_domain = isl_set_intersect(unroll_domain,
+						    isl_set_copy(class_domain));
+		unroll_domain = isl_set_intersect(unroll_domain,
+					isl_set_copy(domains->schedule_domain));
+
+		empty = isl_set_is_empty(unroll_domain);
+		if (empty >= 0 && empty) {
+			isl_set_free(unroll_domain);
+			continue;
+		}
+
+		class_domain = do_unroll(domains, unroll_domain, class_domain);
+	}
+
+	isl_basic_set_list_free(unroll_list);
+
+	return class_domain;
+}
+
+/* Try and construct a single basic set that includes the intersection of
+ * the schedule domain, the atomic option domain and the class domain.
+ * Add the resulting basic set(s) to domains->list and remove them
+ * from class_domain.  Return the updated class domain.
+ *
+ * We construct a single domain rather than trying to combine
+ * the schedule domains of individual domains because we are working
+ * within a single component so that non-overlapping schedule domains
+ * should already have been separated.
+ * We do however need to make sure that this single domains is a subset
+ * of the class domain so that it would not intersect with any other
+ * class domains.  This means that we may end up splitting up the atomic
+ * domain in case separation classes are being used.
+ *
+ * "domain" is the intersection of the schedule domain and the class domain,
+ * with inner dimensions projected out.
+ */
+static __isl_give isl_set *compute_atomic_domain(
+	struct isl_codegen_domains *domains, __isl_take isl_set *class_domain)
+{
+	isl_basic_set *bset;
+	isl_basic_set_list *list;
+	isl_set *domain, *atomic_domain;
+	int empty;
+
+	domain = isl_set_copy(domains->option[isl_ast_loop_atomic]);
+	domain = isl_set_intersect(domain, isl_set_copy(class_domain));
+	domain = isl_set_intersect(domain,
+				isl_set_copy(domains->schedule_domain));
+	empty = isl_set_is_empty(domain);
+	if (empty < 0)
+		class_domain = isl_set_free(class_domain);
+	if (empty) {
+		isl_set_free(domain);
+		return class_domain;
+	}
+
+	domain = isl_ast_build_eliminate(domains->build, domain);
+	domain = isl_set_coalesce(domain);
+	bset = isl_set_unshifted_simple_hull(domain);
+	domain = isl_set_from_basic_set(bset);
+	atomic_domain = isl_set_copy(domain);
+	domain = isl_set_intersect(domain, isl_set_copy(class_domain));
+	class_domain = isl_set_subtract(class_domain, atomic_domain);
+	domain = isl_set_make_disjoint(domain);
+	list = isl_basic_set_list_from_set(domain);
+	domains->list = isl_basic_set_list_concat(domains->list, list);
+
+	return class_domain;
+}
+
+/* Split up the schedule domain into uniform basic sets,
+ * in the sense that each element in a basic set is associated to
+ * elements of the same domains, and add the result to domains->list.
+ * Do this for that part of the schedule domain that lies in the
+ * intersection of "class_domain" and the separate option domain.
+ *
+ * "class_domain" may or may not include the constraints
+ * of the schedule domain, but this does not make a difference
+ * since we are going to intersect it with the domain of the inverse schedule.
+ * If it includes schedule domain constraints, then they may involve
+ * inner dimensions, but we will eliminate them in separation_domain.
+ */
+static int compute_separate_domain(struct isl_codegen_domains *domains,
+	__isl_keep isl_set *class_domain)
+{
+	isl_space *space;
+	isl_set *domain;
+	isl_union_map *executed;
+	isl_basic_set_list *list;
+	int empty;
+
+	domain = isl_set_copy(domains->option[isl_ast_loop_separate]);
+	domain = isl_set_intersect(domain, isl_set_copy(class_domain));
+	executed = isl_union_map_copy(domains->executed);
+	executed = isl_union_map_intersect_domain(executed,
+				    isl_union_set_from_set(domain));
+	empty = isl_union_map_is_empty(executed);
+	if (empty < 0 || empty) {
+		isl_union_map_free(executed);
+		return empty < 0 ? -1 : 0;
+	}
+
+	space = isl_set_get_space(class_domain);
+	domain = separate_schedule_domains(space, executed, domains->build);
+
+	list = isl_basic_set_list_from_set(domain);
+	domains->list = isl_basic_set_list_concat(domains->list, list);
+
+	return 0;
+}
+
+/* Split up the domain at the current depth into disjoint
+ * basic sets for which code should be generated separately
+ * for the given separation class domain.
+ *
+ * If any separation classes have been defined, then "class_domain"
+ * is the domain of the current class and does not refer to inner dimensions.
+ * Otherwise, "class_domain" is the universe domain.
+ *
+ * We first make sure that the class domain is disjoint from
+ * previously considered class domains.
+ *
+ * The separate domains can be computed directly from the "class_domain".
+ *
+ * The unroll, atomic and remainder domains need the constraints
+ * from the schedule domain.
+ *
+ * For unrolling, the actual schedule domain is needed (with divs that
+ * may refer to the current dimension) so that stride detection can be
+ * performed.
+ *
+ * For atomic and remainder domains, inner dimensions and divs involving
+ * the current dimensions should be eliminated.
+ * In case we are working within a separation class, we need to intersect
+ * the result with the current "class_domain" to ensure that the domains
+ * are disjoint from those generated from other class domains.
+ *
+ * The domain that has been made atomic may be larger than specified
+ * by the user since it needs to be representable as a single basic set.
+ * This possibly larger domain is removed from class_domain by
+ * compute_atomic_domain.  It is computed first so that the extended domain
+ * would not overlap with any domains computed before.
+ * Similary, the unrolled domains may have some constraints removed and
+ * may therefore also be larger than specified by the user.
+ *
+ * If anything is left after handling separate, unroll and atomic,
+ * we split it up into basic sets and append the basic sets to domains->list.
+ */
+static isl_stat compute_partial_domains(struct isl_codegen_domains *domains,
+	__isl_take isl_set *class_domain)
+{
+	isl_basic_set_list *list;
+	isl_set *domain;
+
+	class_domain = isl_set_subtract(class_domain,
+					isl_set_copy(domains->done));
+	domains->done = isl_set_union(domains->done,
+					isl_set_copy(class_domain));
+
+	class_domain = compute_atomic_domain(domains, class_domain);
+	class_domain = compute_unroll_domains(domains, class_domain);
+
+	domain = isl_set_copy(class_domain);
+
+	if (compute_separate_domain(domains, domain) < 0)
+		goto error;
+	domain = isl_set_subtract(domain,
+			isl_set_copy(domains->option[isl_ast_loop_separate]));
+
+	domain = isl_set_intersect(domain,
+				isl_set_copy(domains->schedule_domain));
+
+	domain = isl_ast_build_eliminate(domains->build, domain);
+	domain = isl_set_intersect(domain, isl_set_copy(class_domain));
+
+	domain = isl_set_coalesce(domain);
+	domain = isl_set_make_disjoint(domain);
+
+	list = isl_basic_set_list_from_set(domain);
+	domains->list = isl_basic_set_list_concat(domains->list, list);
+
+	isl_set_free(class_domain);
+
+	return isl_stat_ok;
+error:
+	isl_set_free(domain);
+	isl_set_free(class_domain);
+	return isl_stat_error;
+}
+
+/* Split up the domain at the current depth into disjoint
+ * basic sets for which code should be generated separately
+ * for the separation class identified by "pnt".
+ *
+ * We extract the corresponding class domain from domains->sep_class,
+ * eliminate inner dimensions and pass control to compute_partial_domains.
+ */
+static isl_stat compute_class_domains(__isl_take isl_point *pnt, void *user)
+{
+	struct isl_codegen_domains *domains = user;
+	isl_set *class_set;
+	isl_set *domain;
+	int disjoint;
+
+	class_set = isl_set_from_point(pnt);
+	domain = isl_map_domain(isl_map_intersect_range(
+				isl_map_copy(domains->sep_class), class_set));
+	domain = isl_ast_build_compute_gist(domains->build, domain);
+	domain = isl_ast_build_eliminate(domains->build, domain);
+
+	disjoint = isl_set_plain_is_disjoint(domain, domains->schedule_domain);
+	if (disjoint < 0)
+		return isl_stat_error;
+	if (disjoint) {
+		isl_set_free(domain);
+		return isl_stat_ok;
+	}
+
+	return compute_partial_domains(domains, domain);
+}
+
+/* Extract the domains at the current depth that should be atomic,
+ * separated or unrolled and store them in option.
+ *
+ * The domains specified by the user might overlap, so we make
+ * them disjoint by subtracting earlier domains from later domains.
+ */
+static void compute_domains_init_options(isl_set *option[4],
+	__isl_keep isl_ast_build *build)
+{
+	enum isl_ast_loop_type type, type2;
+	isl_set *unroll;
+
+	for (type = isl_ast_loop_atomic;
+	    type <= isl_ast_loop_separate; ++type) {
+		option[type] = isl_ast_build_get_option_domain(build, type);
+		for (type2 = isl_ast_loop_atomic; type2 < type; ++type2)
+			option[type] = isl_set_subtract(option[type],
+						isl_set_copy(option[type2]));
+	}
+
+	unroll = option[isl_ast_loop_unroll];
+	unroll = isl_set_coalesce(unroll);
+	unroll = isl_set_make_disjoint(unroll);
+	option[isl_ast_loop_unroll] = unroll;
+}
+
+/* Split up the domain at the current depth into disjoint
+ * basic sets for which code should be generated separately,
+ * based on the user-specified options.
+ * Return the list of disjoint basic sets.
+ *
+ * There are three kinds of domains that we need to keep track of.
+ * - the "schedule domain" is the domain of "executed"
+ * - the "class domain" is the domain corresponding to the currrent
+ *	separation class
+ * - the "option domain" is the domain corresponding to one of the options
+ *	atomic, unroll or separate
+ *
+ * We first consider the individial values of the separation classes
+ * and split up the domain for each of them separately.
+ * Finally, we consider the remainder.  If no separation classes were
+ * specified, then we call compute_partial_domains with the universe
+ * "class_domain".  Otherwise, we take the "schedule_domain" as "class_domain",
+ * with inner dimensions removed.  We do this because we want to
+ * avoid computing the complement of the class domains (i.e., the difference
+ * between the universe and domains->done).
+ */
+static __isl_give isl_basic_set_list *compute_domains(
+	__isl_keep isl_union_map *executed, __isl_keep isl_ast_build *build)
+{
+	struct isl_codegen_domains domains;
+	isl_ctx *ctx;
+	isl_set *domain;
+	isl_union_set *schedule_domain;
+	isl_set *classes;
+	isl_space *space;
+	int n_param;
+	enum isl_ast_loop_type type;
+	int empty;
+
+	if (!executed)
+		return NULL;
+
+	ctx = isl_union_map_get_ctx(executed);
+	domains.list = isl_basic_set_list_alloc(ctx, 0);
+
+	schedule_domain = isl_union_map_domain(isl_union_map_copy(executed));
+	domain = isl_set_from_union_set(schedule_domain);
+
+	compute_domains_init_options(domains.option, build);
+
+	domains.sep_class = isl_ast_build_get_separation_class(build);
+	classes = isl_map_range(isl_map_copy(domains.sep_class));
+	n_param = isl_set_dim(classes, isl_dim_param);
+	classes = isl_set_project_out(classes, isl_dim_param, 0, n_param);
+
+	space = isl_set_get_space(domain);
+	domains.build = build;
+	domains.schedule_domain = isl_set_copy(domain);
+	domains.executed = executed;
+	domains.done = isl_set_empty(space);
+
+	if (isl_set_foreach_point(classes, &compute_class_domains, &domains) < 0)
+		domains.list = isl_basic_set_list_free(domains.list);
+	isl_set_free(classes);
+
+	empty = isl_set_is_empty(domains.done);
+	if (empty < 0) {
+		domains.list = isl_basic_set_list_free(domains.list);
+		domain = isl_set_free(domain);
+	} else if (empty) {
+		isl_set_free(domain);
+		domain = isl_set_universe(isl_set_get_space(domains.done));
+	} else {
+		domain = isl_ast_build_eliminate(build, domain);
+	}
+	if (compute_partial_domains(&domains, domain) < 0)
+		domains.list = isl_basic_set_list_free(domains.list);
+
+	isl_set_free(domains.schedule_domain);
+	isl_set_free(domains.done);
+	isl_map_free(domains.sep_class);
+	for (type = isl_ast_loop_atomic; type <= isl_ast_loop_separate; ++type)
+		isl_set_free(domains.option[type]);
+
+	return domains.list;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a union map.
+ *
+ * We first split up the domain at the current depth into disjoint
+ * basic sets based on the user-specified options.
+ * Then we generated code for each of them and concatenate the results.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_flat(
+	__isl_take isl_union_map *executed, __isl_take isl_ast_build *build)
+{
+	isl_basic_set_list *domain_list;
+	isl_ast_graft_list *list = NULL;
+
+	domain_list = compute_domains(executed, build);
+	list = generate_parallel_domains(domain_list, executed, build);
+
+	isl_basic_set_list_free(domain_list);
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+
+	return list;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a schedule tree
+ * and the separate option was specified.
+ *
+ * We perform separation on the domain of "executed" and then generate
+ * an AST for each of the resulting disjoint basic sets.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_tree_separate(
+	__isl_take isl_union_map *executed, __isl_take isl_ast_build *build)
+{
+	isl_space *space;
+	isl_set *domain;
+	isl_basic_set_list *domain_list;
+	isl_ast_graft_list *list;
+
+	space = isl_ast_build_get_space(build, 1);
+	domain = separate_schedule_domains(space,
+					isl_union_map_copy(executed), build);
+	domain_list = isl_basic_set_list_from_set(domain);
+
+	list = generate_parallel_domains(domain_list, executed, build);
+
+	isl_basic_set_list_free(domain_list);
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+
+	return list;
+}
+
+/* Internal data structure for generate_shifted_component_tree_unroll.
+ *
+ * "executed" and "build" are inputs to generate_shifted_component_tree_unroll.
+ * "list" collects the constructs grafts.
+ */
+struct isl_ast_unroll_tree_data {
+	isl_union_map *executed;
+	isl_ast_build *build;
+	isl_ast_graft_list *list;
+};
+
+/* Initialize data->list to a list of "n" elements.
+ */
+static int init_unroll_tree(int n, void *user)
+{
+	struct isl_ast_unroll_tree_data *data = user;
+	isl_ctx *ctx;
+
+	ctx = isl_ast_build_get_ctx(data->build);
+	data->list = isl_ast_graft_list_alloc(ctx, n);
+
+	return 0;
+}
+
+/* Given an iteration of an unrolled domain represented by "bset",
+ * generate the corresponding AST and add the result to data->list.
+ */
+static int do_unroll_tree_iteration(__isl_take isl_basic_set *bset, void *user)
+{
+	struct isl_ast_unroll_tree_data *data = user;
+
+	data->list = add_node(data->list, isl_union_map_copy(data->executed),
+				bset, isl_ast_build_copy(data->build));
+
+	return 0;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a schedule tree
+ * and the unroll option was specified.
+ *
+ * We call foreach_iteration to iterate over the individual values and
+ * construct and collect the corresponding grafts in do_unroll_tree_iteration.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_tree_unroll(
+	__isl_take isl_union_map *executed, __isl_take isl_set *domain,
+	__isl_take isl_ast_build *build)
+{
+	struct isl_ast_unroll_tree_data data = { executed, build, NULL };
+
+	if (foreach_iteration(domain, build, &init_unroll_tree,
+				&do_unroll_tree_iteration, &data) < 0)
+		data.list = isl_ast_graft_list_free(data.list);
+
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+
+	return data.list;
+}
+
+/* Does "domain" involve a disjunction that is purely based on
+ * constraints involving only outer dimension?
+ *
+ * In particular, is there a disjunction such that the constraints
+ * involving the current and later dimensions are the same over
+ * all the disjuncts?
+ */
+static isl_bool has_pure_outer_disjunction(__isl_keep isl_set *domain,
+	__isl_keep isl_ast_build *build)
+{
+	isl_basic_set *hull;
+	isl_set *shared, *inner;
+	isl_bool equal;
+	int depth, dim;
+
+	if (isl_set_n_basic_set(domain) <= 1)
+		return isl_bool_false;
+
+	inner = isl_set_copy(domain);
+	depth = isl_ast_build_get_depth(build);
+	dim = isl_set_dim(inner, isl_dim_set);
+	inner = isl_set_drop_constraints_not_involving_dims(inner,
+					    isl_dim_set, depth, dim - depth);
+	hull = isl_set_plain_unshifted_simple_hull(isl_set_copy(inner));
+	shared = isl_set_from_basic_set(hull);
+	equal = isl_set_plain_is_equal(inner, shared);
+	isl_set_free(inner);
+	isl_set_free(shared);
+
+	return equal;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a schedule tree.
+ * In particular, handle the base case where there is either no isolated
+ * set or we are within the isolated set (in which case "isolated" is set)
+ * or the iterations that precede or follow the isolated set.
+ *
+ * The schedule domain is broken up or combined into basic sets
+ * according to the AST generation option specified in the current
+ * schedule node, which may be either atomic, separate, unroll or
+ * unspecified.  If the option is unspecified, then we currently simply
+ * split the schedule domain into disjoint basic sets.
+ *
+ * In case the separate option is specified, the AST generation is
+ * handled by generate_shifted_component_tree_separate.
+ * In the other cases, we need the global schedule domain.
+ * In the unroll case, the AST generation is then handled by
+ * generate_shifted_component_tree_unroll which needs the actual
+ * schedule domain (with divs that may refer to the current dimension)
+ * so that stride detection can be performed.
+ * In the atomic or unspecified case, inner dimensions and divs involving
+ * the current dimensions should be eliminated.
+ * The result is then either combined into a single basic set or
+ * split up into disjoint basic sets.
+ * Finally an AST is generated for each basic set and the results are
+ * concatenated.
+ *
+ * If the schedule domain involves a disjunction that is purely based on
+ * constraints involving only outer dimension, then it is treated as
+ * if atomic was specified.  This ensures that only a single loop
+ * is generated instead of a sequence of identical loops with
+ * different guards.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_tree_base(
+	__isl_take isl_union_map *executed, __isl_take isl_ast_build *build,
+	int isolated)
+{
+	isl_bool outer_disjunction;
+	isl_union_set *schedule_domain;
+	isl_set *domain;
+	isl_basic_set_list *domain_list;
+	isl_ast_graft_list *list;
+	enum isl_ast_loop_type type;
+
+	type = isl_ast_build_get_loop_type(build, isolated);
+	if (type < 0)
+		goto error;
+
+	if (type == isl_ast_loop_separate)
+		return generate_shifted_component_tree_separate(executed,
+								build);
+
+	schedule_domain = isl_union_map_domain(isl_union_map_copy(executed));
+	domain = isl_set_from_union_set(schedule_domain);
+
+	if (type == isl_ast_loop_unroll)
+		return generate_shifted_component_tree_unroll(executed, domain,
+								build);
+
+	domain = isl_ast_build_eliminate(build, domain);
+	domain = isl_set_coalesce(domain);
+
+	outer_disjunction = has_pure_outer_disjunction(domain, build);
+	if (outer_disjunction < 0)
+		domain = isl_set_free(domain);
+
+	if (outer_disjunction || type == isl_ast_loop_atomic) {
+		isl_basic_set *hull;
+		hull = isl_set_unshifted_simple_hull(domain);
+		domain_list = isl_basic_set_list_from_basic_set(hull);
+	} else {
+		domain = isl_set_make_disjoint(domain);
+		domain_list = isl_basic_set_list_from_set(domain);
+	}
+
+	list = generate_parallel_domains(domain_list, executed, build);
+
+	isl_basic_set_list_free(domain_list);
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+
+	return list;
+error:
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+	return NULL;
+}
+
+/* Extract out the disjunction imposed by "domain" on the outer
+ * schedule dimensions.
+ *
+ * In particular, remove all inner dimensions from "domain" (including
+ * the current dimension) and then remove the constraints that are shared
+ * by all disjuncts in the result.
+ */
+static __isl_give isl_set *extract_disjunction(__isl_take isl_set *domain,
+	__isl_keep isl_ast_build *build)
+{
+	isl_set *hull;
+	int depth, dim;
+
+	domain = isl_ast_build_specialize(build, domain);
+	depth = isl_ast_build_get_depth(build);
+	dim = isl_set_dim(domain, isl_dim_set);
+	domain = isl_set_eliminate(domain, isl_dim_set, depth, dim - depth);
+	domain = isl_set_remove_unknown_divs(domain);
+	hull = isl_set_copy(domain);
+	hull = isl_set_from_basic_set(isl_set_unshifted_simple_hull(hull));
+	domain = isl_set_gist(domain, hull);
+
+	return domain;
+}
+
+/* Add "guard" to the grafts in "list".
+ * "build" is the outer AST build, while "sub_build" includes "guard"
+ * in its generated domain.
+ *
+ * First combine the grafts into a single graft and then add the guard.
+ * If the list is empty, or if some error occurred, then simply return
+ * the list.
+ */
+static __isl_give isl_ast_graft_list *list_add_guard(
+	__isl_take isl_ast_graft_list *list, __isl_keep isl_set *guard,
+	__isl_keep isl_ast_build *build, __isl_keep isl_ast_build *sub_build)
+{
+	isl_ast_graft *graft;
+
+	list = isl_ast_graft_list_fuse(list, sub_build);
+
+	if (isl_ast_graft_list_n_ast_graft(list) != 1)
+		return list;
+
+	graft = isl_ast_graft_list_get_ast_graft(list, 0);
+	graft = isl_ast_graft_add_guard(graft, isl_set_copy(guard), build);
+	list = isl_ast_graft_list_set_ast_graft(list, 0, graft);
+
+	return list;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a schedule tree.
+ * In particular, do so for the specified subset of the schedule domain.
+ *
+ * If we are outside of the isolated part, then "domain" may include
+ * a disjunction.  Explicitly generate this disjunction at this point
+ * instead of relying on the disjunction getting hoisted back up
+ * to this level.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_tree_part(
+	__isl_keep isl_union_map *executed, __isl_take isl_set *domain,
+	__isl_keep isl_ast_build *build, int isolated)
+{
+	isl_union_set *uset;
+	isl_ast_graft_list *list;
+	isl_ast_build *sub_build;
+	int empty;
+
+	uset = isl_union_set_from_set(isl_set_copy(domain));
+	executed = isl_union_map_copy(executed);
+	executed = isl_union_map_intersect_domain(executed, uset);
+	empty = isl_union_map_is_empty(executed);
+	if (empty < 0)
+		goto error;
+	if (empty) {
+		isl_ctx *ctx;
+		isl_union_map_free(executed);
+		isl_set_free(domain);
+		ctx = isl_ast_build_get_ctx(build);
+		return isl_ast_graft_list_alloc(ctx, 0);
+	}
+
+	sub_build = isl_ast_build_copy(build);
+	if (!isolated) {
+		domain = extract_disjunction(domain, build);
+		sub_build = isl_ast_build_restrict_generated(sub_build,
+							isl_set_copy(domain));
+	}
+	list = generate_shifted_component_tree_base(executed,
+				isl_ast_build_copy(sub_build), isolated);
+	if (!isolated)
+		list = list_add_guard(list, domain, build, sub_build);
+	isl_ast_build_free(sub_build);
+	isl_set_free(domain);
+	return list;
+error:
+	isl_union_map_free(executed);
+	isl_set_free(domain);
+	return NULL;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a schedule tree.
+ * In particular, do so for the specified sequence of subsets
+ * of the schedule domain, "before", "isolated", "after" and "other",
+ * where only the "isolated" part is considered to be isolated.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_parts(
+	__isl_take isl_union_map *executed, __isl_take isl_set *before,
+	__isl_take isl_set *isolated, __isl_take isl_set *after,
+	__isl_take isl_set *other, __isl_take isl_ast_build *build)
+{
+	isl_ast_graft_list *list, *res;
+
+	res = generate_shifted_component_tree_part(executed, before, build, 0);
+	list = generate_shifted_component_tree_part(executed, isolated,
+						    build, 1);
+	res = isl_ast_graft_list_concat(res, list);
+	list = generate_shifted_component_tree_part(executed, after, build, 0);
+	res = isl_ast_graft_list_concat(res, list);
+	list = generate_shifted_component_tree_part(executed, other, build, 0);
+	res = isl_ast_graft_list_concat(res, list);
+
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+
+	return res;
+}
+
+/* Does "set" intersect "first", but not "second"?
+ */
+static isl_bool only_intersects_first(__isl_keep isl_set *set,
+	__isl_keep isl_set *first, __isl_keep isl_set *second)
+{
+	isl_bool disjoint;
+
+	disjoint = isl_set_is_disjoint(set, first);
+	if (disjoint < 0)
+		return isl_bool_error;
+	if (disjoint)
+		return isl_bool_false;
+
+	return isl_set_is_disjoint(set, second);
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a schedule tree.
+ * In particular, do so in case of isolation where there is
+ * only an "isolated" part and an "after" part.
+ * "dead1" and "dead2" are freed by this function in order to simplify
+ * the caller.
+ *
+ * The "before" and "other" parts are set to empty sets.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_only_after(
+	__isl_take isl_union_map *executed, __isl_take isl_set *isolated,
+	__isl_take isl_set *after, __isl_take isl_ast_build *build,
+	__isl_take isl_set *dead1, __isl_take isl_set *dead2)
+{
+	isl_set *empty;
+
+	empty = isl_set_empty(isl_set_get_space(after));
+	isl_set_free(dead1);
+	isl_set_free(dead2);
+	return generate_shifted_component_parts(executed, isl_set_copy(empty),
+						isolated, after, empty, build);
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied, in case the schedule was specified as a schedule tree.
+ *
+ * We first check if the user has specified an isolated schedule domain
+ * and that we are not already outside of this isolated schedule domain.
+ * If so, we break up the schedule domain into iterations that
+ * precede the isolated domain, the isolated domain itself,
+ * the iterations that follow the isolated domain and
+ * the remaining iterations (those that are incomparable
+ * to the isolated domain).
+ * We generate an AST for each piece and concatenate the results.
+ *
+ * In the special case where at least one element of the schedule
+ * domain that does not belong to the isolated domain needs
+ * to be scheduled after this isolated domain, but none of those
+ * elements need to be scheduled before, break up the schedule domain
+ * in only two parts, the isolated domain, and a part that will be
+ * scheduled after the isolated domain.
+ *
+ * If no isolated set has been specified, then we generate an
+ * AST for the entire inverse schedule.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_tree(
+	__isl_take isl_union_map *executed, __isl_take isl_ast_build *build)
+{
+	int i, depth;
+	int empty, has_isolate;
+	isl_space *space;
+	isl_union_set *schedule_domain;
+	isl_set *domain;
+	isl_basic_set *hull;
+	isl_set *isolated, *before, *after, *test;
+	isl_map *gt, *lt;
+	isl_bool pure;
+
+	build = isl_ast_build_extract_isolated(build);
+	has_isolate = isl_ast_build_has_isolated(build);
+	if (has_isolate < 0)
+		executed = isl_union_map_free(executed);
+	else if (!has_isolate)
+		return generate_shifted_component_tree_base(executed, build, 0);
+
+	schedule_domain = isl_union_map_domain(isl_union_map_copy(executed));
+	domain = isl_set_from_union_set(schedule_domain);
+
+	isolated = isl_ast_build_get_isolated(build);
+	isolated = isl_set_intersect(isolated, isl_set_copy(domain));
+	test = isl_ast_build_specialize(build, isl_set_copy(isolated));
+	empty = isl_set_is_empty(test);
+	isl_set_free(test);
+	if (empty < 0)
+		goto error;
+	if (empty) {
+		isl_set_free(isolated);
+		isl_set_free(domain);
+		return generate_shifted_component_tree_base(executed, build, 0);
+	}
+	isolated = isl_ast_build_eliminate(build, isolated);
+	hull = isl_set_unshifted_simple_hull(isolated);
+	isolated = isl_set_from_basic_set(hull);
+
+	depth = isl_ast_build_get_depth(build);
+	space = isl_space_map_from_set(isl_set_get_space(isolated));
+	gt = isl_map_universe(space);
+	for (i = 0; i < depth; ++i)
+		gt = isl_map_equate(gt, isl_dim_in, i, isl_dim_out, i);
+	gt = isl_map_order_gt(gt, isl_dim_in, depth, isl_dim_out, depth);
+	lt = isl_map_reverse(isl_map_copy(gt));
+	before = isl_set_apply(isl_set_copy(isolated), gt);
+	after = isl_set_apply(isl_set_copy(isolated), lt);
+
+	domain = isl_set_subtract(domain, isl_set_copy(isolated));
+	pure = only_intersects_first(domain, after, before);
+	if (pure < 0)
+		executed = isl_union_map_free(executed);
+	else if (pure)
+		return generate_shifted_component_only_after(executed, isolated,
+						domain, build, before, after);
+	domain = isl_set_subtract(domain, isl_set_copy(before));
+	domain = isl_set_subtract(domain, isl_set_copy(after));
+	after = isl_set_subtract(after, isl_set_copy(isolated));
+	after = isl_set_subtract(after, isl_set_copy(before));
+	before = isl_set_subtract(before, isl_set_copy(isolated));
+
+	return generate_shifted_component_parts(executed, before, isolated,
+						after, domain, build);
+error:
+	isl_set_free(domain);
+	isl_set_free(isolated);
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+	return NULL;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied.
+ *
+ * Call generate_shifted_component_tree or generate_shifted_component_flat
+ * depending on whether the schedule was specified as a schedule tree.
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component(
+	__isl_take isl_union_map *executed, __isl_take isl_ast_build *build)
+{
+	if (isl_ast_build_has_schedule_node(build))
+		return generate_shifted_component_tree(executed, build);
+	else
+		return generate_shifted_component_flat(executed, build);
+}
+
+struct isl_set_map_pair {
+	isl_set *set;
+	isl_map *map;
+};
+
+/* Given an array "domain" of isl_set_map_pairs and an array "order"
+ * of indices into the "domain" array,
+ * return the union of the "map" fields of the elements
+ * indexed by the first "n" elements of "order".
+ */
+static __isl_give isl_union_map *construct_component_executed(
+	struct isl_set_map_pair *domain, int *order, int n)
+{
+	int i;
+	isl_map *map;
+	isl_union_map *executed;
+
+	map = isl_map_copy(domain[order[0]].map);
+	executed = isl_union_map_from_map(map);
+	for (i = 1; i < n; ++i) {
+		map = isl_map_copy(domain[order[i]].map);
+		executed = isl_union_map_add_map(executed, map);
+	}
+
+	return executed;
+}
+
+/* Generate code for a single component, after shifting (if any)
+ * has been applied.
+ *
+ * The component inverse schedule is specified as the "map" fields
+ * of the elements of "domain" indexed by the first "n" elements of "order".
+ */
+static __isl_give isl_ast_graft_list *generate_shifted_component_from_list(
+	struct isl_set_map_pair *domain, int *order, int n,
+	__isl_take isl_ast_build *build)
+{
+	isl_union_map *executed;
+
+	executed = construct_component_executed(domain, order, n);
+	return generate_shifted_component(executed, build);
+}
+
+/* Does set dimension "pos" of "set" have an obviously fixed value?
+ */
+static int dim_is_fixed(__isl_keep isl_set *set, int pos)
+{
+	int fixed;
+	isl_val *v;
+
+	v = isl_set_plain_get_val_if_fixed(set, isl_dim_set, pos);
+	if (!v)
+		return -1;
+	fixed = !isl_val_is_nan(v);
+	isl_val_free(v);
+
+	return fixed;
+}
+
+/* Given an array "domain" of isl_set_map_pairs and an array "order"
+ * of indices into the "domain" array,
+ * do all (except for at most one) of the "set" field of the elements
+ * indexed by the first "n" elements of "order" have a fixed value
+ * at position "depth"?
+ */
+static int at_most_one_non_fixed(struct isl_set_map_pair *domain,
+	int *order, int n, int depth)
+{
+	int i;
+	int non_fixed = -1;
+
+	for (i = 0; i < n; ++i) {
+		int f;
+
+		f = dim_is_fixed(domain[order[i]].set, depth);
+		if (f < 0)
+			return -1;
+		if (f)
+			continue;
+		if (non_fixed >= 0)
+			return 0;
+		non_fixed = i;
+	}
+
+	return 1;
+}
+
+/* Given an array "domain" of isl_set_map_pairs and an array "order"
+ * of indices into the "domain" array,
+ * eliminate the inner dimensions from the "set" field of the elements
+ * indexed by the first "n" elements of "order", provided the current
+ * dimension does not have a fixed value.
+ *
+ * Return the index of the first element in "order" with a corresponding
+ * "set" field that does not have an (obviously) fixed value.
+ */
+static int eliminate_non_fixed(struct isl_set_map_pair *domain,
+	int *order, int n, int depth, __isl_keep isl_ast_build *build)
+{
+	int i;
+	int base = -1;
+
+	for (i = n - 1; i >= 0; --i) {
+		int f;
+		f = dim_is_fixed(domain[order[i]].set, depth);
+		if (f < 0)
+			return -1;
+		if (f)
+			continue;
+		domain[order[i]].set = isl_ast_build_eliminate_inner(build,
+							domain[order[i]].set);
+		base = i;
+	}
+
+	return base;
+}
+
+/* Given an array "domain" of isl_set_map_pairs and an array "order"
+ * of indices into the "domain" array,
+ * find the element of "domain" (amongst those indexed by the first "n"
+ * elements of "order") with the "set" field that has the smallest
+ * value for the current iterator.
+ *
+ * Note that the domain with the smallest value may depend on the parameters
+ * and/or outer loop dimension.  Since the result of this function is only
+ * used as heuristic, we only make a reasonable attempt at finding the best
+ * domain, one that should work in case a single domain provides the smallest
+ * value for the current dimension over all values of the parameters
+ * and outer dimensions.
+ *
+ * In particular, we compute the smallest value of the first domain
+ * and replace it by that of any later domain if that later domain
+ * has a smallest value that is smaller for at least some value
+ * of the parameters and outer dimensions.
+ */
+static int first_offset(struct isl_set_map_pair *domain, int *order, int n,
+	__isl_keep isl_ast_build *build)
+{
+	int i;
+	isl_map *min_first;
+	int first = 0;
+
+	min_first = isl_ast_build_map_to_iterator(build,
+					isl_set_copy(domain[order[0]].set));
+	min_first = isl_map_lexmin(min_first);
+
+	for (i = 1; i < n; ++i) {
+		isl_map *min, *test;
+		int empty;
+
+		min = isl_ast_build_map_to_iterator(build,
+					isl_set_copy(domain[order[i]].set));
+		min = isl_map_lexmin(min);
+		test = isl_map_copy(min);
+		test = isl_map_apply_domain(isl_map_copy(min_first), test);
+		test = isl_map_order_lt(test, isl_dim_in, 0, isl_dim_out, 0);
+		empty = isl_map_is_empty(test);
+		isl_map_free(test);
+		if (empty >= 0 && !empty) {
+			isl_map_free(min_first);
+			first = i;
+			min_first = min;
+		} else
+			isl_map_free(min);
+
+		if (empty < 0)
+			break;
+	}
+
+	isl_map_free(min_first);
+
+	return i < n ? -1 : first;
+}
+
+/* Construct a shifted inverse schedule based on the original inverse schedule,
+ * the stride and the offset.
+ *
+ * The original inverse schedule is specified as the "map" fields
+ * of the elements of "domain" indexed by the first "n" elements of "order".
+ *
+ * "stride" and "offset" are such that the difference
+ * between the values of the current dimension of domain "i"
+ * and the values of the current dimension for some reference domain are
+ * equal to
+ *
+ *	stride * integer + offset[i]
+ *
+ * Moreover, 0 <= offset[i] < stride.
+ *
+ * For each domain, we create a map
+ *
+ *	{ [..., j, ...] -> [..., j - offset[i], offset[i], ....] }
+ *
+ * where j refers to the current dimension and the other dimensions are
+ * unchanged, and apply this map to the original schedule domain.
+ *
+ * For example, for the original schedule
+ *
+ *	{ A[i] -> [2i]: 0 <= i < 10; B[i] -> [2i+1] : 0 <= i < 10 }
+ *
+ * and assuming the offset is 0 for the A domain and 1 for the B domain,
+ * we apply the mapping
+ *
+ *	{ [j] -> [j, 0] }
+ *
+ * to the schedule of the "A" domain and the mapping
+ *
+ *	{ [j - 1] -> [j, 1] }
+ *
+ * to the schedule of the "B" domain.
+ *
+ *
+ * Note that after the transformation, the differences between pairs
+ * of values of the current dimension over all domains are multiples
+ * of stride and that we have therefore exposed the stride.
+ *
+ *
+ * To see that the mapping preserves the lexicographic order,
+ * first note that each of the individual maps above preserves the order.
+ * If the value of the current iterator is j1 in one domain and j2 in another,
+ * then if j1 = j2, we know that the same map is applied to both domains
+ * and the order is preserved.
+ * Otherwise, let us assume, without loss of generality, that j1 < j2.
+ * If c1 >= c2 (with c1 and c2 the corresponding offsets), then
+ *
+ *	j1 - c1 < j2 - c2
+ *
+ * and the order is preserved.
+ * If c1 < c2, then we know
+ *
+ *	0 <= c2 - c1 < s
+ *
+ * We also have
+ *
+ *	j2 - j1 = n * s + r
+ *
+ * with n >= 0 and 0 <= r < s.
+ * In other words, r = c2 - c1.
+ * If n > 0, then
+ *
+ *	j1 - c1 < j2 - c2
+ *
+ * If n = 0, then
+ *
+ *	j1 - c1 = j2 - c2
+ *
+ * and so
+ *
+ *	(j1 - c1, c1) << (j2 - c2, c2)
+ *
+ * with "<<" the lexicographic order, proving that the order is preserved
+ * in all cases.
+ */
+static __isl_give isl_union_map *contruct_shifted_executed(
+	struct isl_set_map_pair *domain, int *order, int n,
+	__isl_keep isl_val *stride, __isl_keep isl_multi_val *offset,
+	__isl_take isl_ast_build *build)
+{
+	int i;
+	isl_union_map *executed;
+	isl_space *space;
+	isl_map *map;
+	int depth;
+	isl_constraint *c;
+
+	depth = isl_ast_build_get_depth(build);
+	space = isl_ast_build_get_space(build, 1);
+	executed = isl_union_map_empty(isl_space_copy(space));
+	space = isl_space_map_from_set(space);
+	map = isl_map_identity(isl_space_copy(space));
+	map = isl_map_eliminate(map, isl_dim_out, depth, 1);
+	map = isl_map_insert_dims(map, isl_dim_out, depth + 1, 1);
+	space = isl_space_insert_dims(space, isl_dim_out, depth + 1, 1);
+
+	c = isl_constraint_alloc_equality(isl_local_space_from_space(space));
+	c = isl_constraint_set_coefficient_si(c, isl_dim_in, depth, 1);
+	c = isl_constraint_set_coefficient_si(c, isl_dim_out, depth, -1);
+
+	for (i = 0; i < n; ++i) {
+		isl_map *map_i;
+		isl_val *v;
+
+		v = isl_multi_val_get_val(offset, i);
+		if (!v)
+			break;
+		map_i = isl_map_copy(map);
+		map_i = isl_map_fix_val(map_i, isl_dim_out, depth + 1,
+					isl_val_copy(v));
+		v = isl_val_neg(v);
+		c = isl_constraint_set_constant_val(c, v);
+		map_i = isl_map_add_constraint(map_i, isl_constraint_copy(c));
+
+		map_i = isl_map_apply_domain(isl_map_copy(domain[order[i]].map),
+						map_i);
+		executed = isl_union_map_add_map(executed, map_i);
+	}
+
+	isl_constraint_free(c);
+	isl_map_free(map);
+
+	if (i < n)
+		executed = isl_union_map_free(executed);
+
+	return executed;
+}
+
+/* Generate code for a single component, after exposing the stride,
+ * given that the schedule domain is "shifted strided".
+ *
+ * The component inverse schedule is specified as the "map" fields
+ * of the elements of "domain" indexed by the first "n" elements of "order".
+ *
+ * The schedule domain being "shifted strided" means that the differences
+ * between the values of the current dimension of domain "i"
+ * and the values of the current dimension for some reference domain are
+ * equal to
+ *
+ *	stride * integer + offset[i]
+ *
+ * We first look for the domain with the "smallest" value for the current
+ * dimension and adjust the offsets such that the offset of the "smallest"
+ * domain is equal to zero.  The other offsets are reduced modulo stride.
+ *
+ * Based on this information, we construct a new inverse schedule in
+ * contruct_shifted_executed that exposes the stride.
+ * Since this involves the introduction of a new schedule dimension,
+ * the build needs to be changed accodingly.
+ * After computing the AST, the newly introduced dimension needs
+ * to be removed again from the list of grafts.  We do this by plugging
+ * in a mapping that represents the new schedule domain in terms of the
+ * old schedule domain.
+ */
+static __isl_give isl_ast_graft_list *generate_shift_component(
+	struct isl_set_map_pair *domain, int *order, int n,
+	__isl_keep isl_val *stride, __isl_keep isl_multi_val *offset,
+	__isl_take isl_ast_build *build)
+{
+	isl_ast_graft_list *list;
+	int first;
+	int depth;
+	isl_val *val;
+	isl_multi_val *mv;
+	isl_space *space;
+	isl_multi_aff *ma, *zero;
+	isl_union_map *executed;
+
+	depth = isl_ast_build_get_depth(build);
+
+	first = first_offset(domain, order, n, build);
+	if (first < 0)
+		goto error;
+
+	mv = isl_multi_val_copy(offset);
+	val = isl_multi_val_get_val(offset, first);
+	val = isl_val_neg(val);
+	mv = isl_multi_val_add_val(mv, val);
+	mv = isl_multi_val_mod_val(mv, isl_val_copy(stride));
+
+	executed = contruct_shifted_executed(domain, order, n, stride, mv,
+						build);
+	space = isl_ast_build_get_space(build, 1);
+	space = isl_space_map_from_set(space);
+	ma = isl_multi_aff_identity(isl_space_copy(space));
+	space = isl_space_from_domain(isl_space_domain(space));
+	space = isl_space_add_dims(space, isl_dim_out, 1);
+	zero = isl_multi_aff_zero(space);
+	ma = isl_multi_aff_range_splice(ma, depth + 1, zero);
+	build = isl_ast_build_insert_dim(build, depth + 1);
+	list = generate_shifted_component(executed, build);
+
+	list = isl_ast_graft_list_preimage_multi_aff(list, ma);
+
+	isl_multi_val_free(mv);
+
+	return list;
+error:
+	isl_ast_build_free(build);
+	return NULL;
+}
+
+/* Does any node in the schedule tree rooted at the current schedule node
+ * of "build" depend on outer schedule nodes?
+ */
+static int has_anchored_subtree(__isl_keep isl_ast_build *build)
+{
+	isl_schedule_node *node;
+	int dependent = 0;
+
+	node = isl_ast_build_get_schedule_node(build);
+	dependent = isl_schedule_node_is_subtree_anchored(node);
+	isl_schedule_node_free(node);
+
+	return dependent;
+}
+
+/* Generate code for a single component.
+ *
+ * The component inverse schedule is specified as the "map" fields
+ * of the elements of "domain" indexed by the first "n" elements of "order".
+ *
+ * This function may modify the "set" fields of "domain".
+ *
+ * Before proceeding with the actual code generation for the component,
+ * we first check if there are any "shifted" strides, meaning that
+ * the schedule domains of the individual domains are all strided,
+ * but that they have different offsets, resulting in the union
+ * of schedule domains not being strided anymore.
+ *
+ * The simplest example is the schedule
+ *
+ *	{ A[i] -> [2i]: 0 <= i < 10; B[i] -> [2i+1] : 0 <= i < 10 }
+ *
+ * Both schedule domains are strided, but their union is not.
+ * This function detects such cases and then rewrites the schedule to
+ *
+ *	{ A[i] -> [2i, 0]: 0 <= i < 10; B[i] -> [2i, 1] : 0 <= i < 10 }
+ *
+ * In the new schedule, the schedule domains have the same offset (modulo
+ * the stride), ensuring that the union of schedule domains is also strided.
+ *
+ *
+ * If there is only a single domain in the component, then there is
+ * nothing to do.   Similarly, if the current schedule dimension has
+ * a fixed value for almost all domains then there is nothing to be done.
+ * In particular, we need at least two domains where the current schedule
+ * dimension does not have a fixed value.
+ * Finally, in case of a schedule map input,
+ * if any of the options refer to the current schedule dimension,
+ * then we bail out as well.  It would be possible to reformulate the options
+ * in terms of the new schedule domain, but that would introduce constraints
+ * that separate the domains in the options and that is something we would
+ * like to avoid.
+ * In the case of a schedule tree input, we bail out if any of
+ * the descendants of the current schedule node refer to outer
+ * schedule nodes in any way.
+ *
+ *
+ * To see if there is any shifted stride, we look at the differences
+ * between the values of the current dimension in pairs of domains
+ * for equal values of outer dimensions.  These differences should be
+ * of the form
+ *
+ *	m x + r
+ *
+ * with "m" the stride and "r" a constant.  Note that we cannot perform
+ * this analysis on individual domains as the lower bound in each domain
+ * may depend on parameters or outer dimensions and so the current dimension
+ * itself may not have a fixed remainder on division by the stride.
+ *
+ * In particular, we compare the first domain that does not have an
+ * obviously fixed value for the current dimension to itself and all
+ * other domains and collect the offsets and the gcd of the strides.
+ * If the gcd becomes one, then we failed to find shifted strides.
+ * If the gcd is zero, then the differences were all fixed, meaning
+ * that some domains had non-obviously fixed values for the current dimension.
+ * If all the offsets are the same (for those domains that do not have
+ * an obviously fixed value for the current dimension), then we do not
+ * apply the transformation.
+ * If none of the domains were skipped, then there is nothing to do.
+ * If some of them were skipped, then if we apply separation, the schedule
+ * domain should get split in pieces with a (non-shifted) stride.
+ *
+ * Otherwise, we apply a shift to expose the stride in
+ * generate_shift_component.
+ */
+static __isl_give isl_ast_graft_list *generate_component(
+	struct isl_set_map_pair *domain, int *order, int n,
+	__isl_take isl_ast_build *build)
+{
+	int i, d;
+	int depth;
+	isl_ctx *ctx;
+	isl_map *map;
+	isl_set *deltas;
+	isl_val *gcd = NULL;
+	isl_multi_val *mv;
+	int fixed, skip;
+	int base;
+	isl_ast_graft_list *list;
+	int res = 0;
+
+	depth = isl_ast_build_get_depth(build);
+
+	skip = n == 1;
+	if (skip >= 0 && !skip)
+		skip = at_most_one_non_fixed(domain, order, n, depth);
+	if (skip >= 0 && !skip) {
+		if (isl_ast_build_has_schedule_node(build))
+			skip = has_anchored_subtree(build);
+		else
+			skip = isl_ast_build_options_involve_depth(build);
+	}
+	if (skip < 0)
+		goto error;
+	if (skip)
+		return generate_shifted_component_from_list(domain,
+							    order, n, build);
+
+	base = eliminate_non_fixed(domain, order, n, depth, build);
+	if (base < 0)
+		goto error;
+
+	ctx = isl_ast_build_get_ctx(build);
+
+	mv = isl_multi_val_zero(isl_space_set_alloc(ctx, 0, n));
+
+	fixed = 1;
+	for (i = 0; i < n; ++i) {
+		isl_val *r, *m;
+
+		map = isl_map_from_domain_and_range(
+					isl_set_copy(domain[order[base]].set),
+					isl_set_copy(domain[order[i]].set));
+		for (d = 0; d < depth; ++d)
+			map = isl_map_equate(map, isl_dim_in, d,
+						    isl_dim_out, d);
+		deltas = isl_map_deltas(map);
+		res = isl_set_dim_residue_class_val(deltas, depth, &m, &r);
+		isl_set_free(deltas);
+		if (res < 0)
+			break;
+
+		if (i == 0)
+			gcd = m;
+		else
+			gcd = isl_val_gcd(gcd, m);
+		if (isl_val_is_one(gcd)) {
+			isl_val_free(r);
+			break;
+		}
+		mv = isl_multi_val_set_val(mv, i, r);
+
+		res = dim_is_fixed(domain[order[i]].set, depth);
+		if (res < 0)
+			break;
+		if (res)
+			continue;
+
+		if (fixed && i > base) {
+			isl_val *a, *b;
+			a = isl_multi_val_get_val(mv, i);
+			b = isl_multi_val_get_val(mv, base);
+			if (isl_val_ne(a, b))
+				fixed = 0;
+			isl_val_free(a);
+			isl_val_free(b);
+		}
+	}
+
+	if (res < 0 || !gcd) {
+		isl_ast_build_free(build);
+		list = NULL;
+	} else if (i < n || fixed || isl_val_is_zero(gcd)) {
+		list = generate_shifted_component_from_list(domain,
+							    order, n, build);
+	} else {
+		list = generate_shift_component(domain, order, n, gcd, mv,
+						build);
+	}
+
+	isl_val_free(gcd);
+	isl_multi_val_free(mv);
+
+	return list;
+error:
+	isl_ast_build_free(build);
+	return NULL;
+}
+
+/* Store both "map" itself and its domain in the
+ * structure pointed to by *next and advance to the next array element.
+ */
+static isl_stat extract_domain(__isl_take isl_map *map, void *user)
+{
+	struct isl_set_map_pair **next = user;
+
+	(*next)->map = isl_map_copy(map);
+	(*next)->set = isl_map_domain(map);
+	(*next)++;
+
+	return isl_stat_ok;
+}
+
+static int after_in_tree(__isl_keep isl_union_map *umap,
+	__isl_keep isl_schedule_node *node);
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the child of "node"?
+ */
+static int after_in_child(__isl_keep isl_union_map *umap,
+	__isl_keep isl_schedule_node *node)
+{
+	isl_schedule_node *child;
+	int after;
+
+	child = isl_schedule_node_get_child(node, 0);
+	after = after_in_tree(umap, child);
+	isl_schedule_node_free(child);
+
+	return after;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the band node "node"?
+ *
+ * We first check if any domain element is scheduled after any
+ * of the corresponding image elements by the band node itself.
+ * If not, we restrict "map" to those pairs of element that
+ * are scheduled together by the band node and continue with
+ * the child of the band node.
+ * If there are no such pairs then the map passed to after_in_child
+ * will be empty causing it to return 0.
+ */
+static int after_in_band(__isl_keep isl_union_map *umap,
+	__isl_keep isl_schedule_node *node)
+{
+	isl_multi_union_pw_aff *mupa;
+	isl_union_map *partial, *test, *gt, *universe, *umap1, *umap2;
+	isl_union_set *domain, *range;
+	isl_space *space;
+	int empty;
+	int after;
+
+	if (isl_schedule_node_band_n_member(node) == 0)
+		return after_in_child(umap, node);
+
+	mupa = isl_schedule_node_band_get_partial_schedule(node);
+	space = isl_multi_union_pw_aff_get_space(mupa);
+	partial = isl_union_map_from_multi_union_pw_aff(mupa);
+	test = isl_union_map_copy(umap);
+	test = isl_union_map_apply_domain(test, isl_union_map_copy(partial));
+	test = isl_union_map_apply_range(test, isl_union_map_copy(partial));
+	gt = isl_union_map_from_map(isl_map_lex_gt(space));
+	test = isl_union_map_intersect(test, gt);
+	empty = isl_union_map_is_empty(test);
+	isl_union_map_free(test);
+
+	if (empty < 0 || !empty) {
+		isl_union_map_free(partial);
+		return empty < 0 ? -1 : 1;
+	}
+
+	universe = isl_union_map_universe(isl_union_map_copy(umap));
+	domain = isl_union_map_domain(isl_union_map_copy(universe));
+	range = isl_union_map_range(universe);
+	umap1 = isl_union_map_copy(partial);
+	umap1 = isl_union_map_intersect_domain(umap1, domain);
+	umap2 = isl_union_map_intersect_domain(partial, range);
+	test = isl_union_map_apply_range(umap1, isl_union_map_reverse(umap2));
+	test = isl_union_map_intersect(test, isl_union_map_copy(umap));
+	after = after_in_child(test, node);
+	isl_union_map_free(test);
+	return after;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the context node "node"?
+ *
+ * The context constraints apply to the schedule domain,
+ * so we cannot apply them directly to "umap", which contains
+ * pairs of statement instances.  Instead, we add them
+ * to the range of the prefix schedule for both domain and
+ * range of "umap".
+ */
+static int after_in_context(__isl_keep isl_union_map *umap,
+	__isl_keep isl_schedule_node *node)
+{
+	isl_union_map *prefix, *universe, *umap1, *umap2;
+	isl_union_set *domain, *range;
+	isl_set *context;
+	int after;
+
+	umap = isl_union_map_copy(umap);
+	context = isl_schedule_node_context_get_context(node);
+	prefix = isl_schedule_node_get_prefix_schedule_union_map(node);
+	universe = isl_union_map_universe(isl_union_map_copy(umap));
+	domain = isl_union_map_domain(isl_union_map_copy(universe));
+	range = isl_union_map_range(universe);
+	umap1 = isl_union_map_copy(prefix);
+	umap1 = isl_union_map_intersect_domain(umap1, domain);
+	umap2 = isl_union_map_intersect_domain(prefix, range);
+	umap1 = isl_union_map_intersect_range(umap1,
+					    isl_union_set_from_set(context));
+	umap1 = isl_union_map_apply_range(umap1, isl_union_map_reverse(umap2));
+	umap = isl_union_map_intersect(umap, umap1);
+
+	after = after_in_child(umap, node);
+
+	isl_union_map_free(umap);
+
+	return after;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the expansion node "node"?
+ *
+ * We apply the expansion to domain and range of "umap" and
+ * continue with its child.
+ */
+static int after_in_expansion(__isl_keep isl_union_map *umap,
+	__isl_keep isl_schedule_node *node)
+{
+	isl_union_map *expansion;
+	int after;
+
+	expansion = isl_schedule_node_expansion_get_expansion(node);
+	umap = isl_union_map_copy(umap);
+	umap = isl_union_map_apply_domain(umap, isl_union_map_copy(expansion));
+	umap = isl_union_map_apply_range(umap, expansion);
+
+	after = after_in_child(umap, node);
+
+	isl_union_map_free(umap);
+
+	return after;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the extension node "node"?
+ *
+ * Since the extension node may add statement instances before or
+ * after the pairs of statement instances in "umap", we return 1
+ * to ensure that these pairs are not broken up.
+ */
+static int after_in_extension(__isl_keep isl_union_map *umap,
+	__isl_keep isl_schedule_node *node)
+{
+	return 1;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the filter node "node"?
+ *
+ * We intersect domain and range of "umap" with the filter and
+ * continue with its child.
+ */
+static int after_in_filter(__isl_keep isl_union_map *umap,
+	__isl_keep isl_schedule_node *node)
+{
+	isl_union_set *filter;
+	int after;
+
+	umap = isl_union_map_copy(umap);
+	filter = isl_schedule_node_filter_get_filter(node);
+	umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(filter));
+	umap = isl_union_map_intersect_range(umap, filter);
+
+	after = after_in_child(umap, node);
+
+	isl_union_map_free(umap);
+
+	return after;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the set node "node"?
+ *
+ * This is only the case if this condition holds in any
+ * of the (filter) children of the set node.
+ * In particular, if the domain and the range of "umap"
+ * are contained in different children, then the condition
+ * does not hold.
+ */
+static int after_in_set(__isl_keep isl_union_map *umap,
+	__isl_keep isl_schedule_node *node)
+{
+	int i, n;
+
+	n = isl_schedule_node_n_children(node);
+	for (i = 0; i < n; ++i) {
+		isl_schedule_node *child;
+		int after;
+
+		child = isl_schedule_node_get_child(node, i);
+		after = after_in_tree(umap, child);
+		isl_schedule_node_free(child);
+
+		if (after < 0 || after)
+			return after;
+	}
+
+	return 0;
+}
+
+/* Return the filter of child "i" of "node".
+ */
+static __isl_give isl_union_set *child_filter(
+	__isl_keep isl_schedule_node *node, int i)
+{
+	isl_schedule_node *child;
+	isl_union_set *filter;
+
+	child = isl_schedule_node_get_child(node, i);
+	filter = isl_schedule_node_filter_get_filter(child);
+	isl_schedule_node_free(child);
+
+	return filter;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at
+ * the sequence node "node"?
+ *
+ * This happens in particular if any domain element is
+ * contained in a later child than one containing a range element or
+ * if the condition holds within a given child in the sequence.
+ * The later part of the condition is checked by after_in_set.
+ */
+static int after_in_sequence(__isl_keep isl_union_map *umap,
+	__isl_keep isl_schedule_node *node)
+{
+	int i, j, n;
+	isl_union_map *umap_i;
+	int empty, after = 0;
+
+	n = isl_schedule_node_n_children(node);
+	for (i = 1; i < n; ++i) {
+		isl_union_set *filter_i;
+
+		umap_i = isl_union_map_copy(umap);
+		filter_i = child_filter(node, i);
+		umap_i = isl_union_map_intersect_domain(umap_i, filter_i);
+		empty = isl_union_map_is_empty(umap_i);
+		if (empty < 0)
+			goto error;
+		if (empty) {
+			isl_union_map_free(umap_i);
+			continue;
+		}
+
+		for (j = 0; j < i; ++j) {
+			isl_union_set *filter_j;
+			isl_union_map *umap_ij;
+
+			umap_ij = isl_union_map_copy(umap_i);
+			filter_j = child_filter(node, j);
+			umap_ij = isl_union_map_intersect_range(umap_ij,
+								filter_j);
+			empty = isl_union_map_is_empty(umap_ij);
+			isl_union_map_free(umap_ij);
+
+			if (empty < 0)
+				goto error;
+			if (!empty)
+				after = 1;
+			if (after)
+				break;
+		}
+
+		isl_union_map_free(umap_i);
+		if (after)
+			break;
+	}
+
+	if (after < 0 || after)
+		return after;
+
+	return after_in_set(umap, node);
+error:
+	isl_union_map_free(umap_i);
+	return -1;
+}
+
+/* Is any domain element of "umap" scheduled after any of
+ * the corresponding image elements by the tree rooted at "node"?
+ *
+ * If "umap" is empty, then clearly there is no such element.
+ * Otherwise, consider the different types of nodes separately.
+ */
+static int after_in_tree(__isl_keep isl_union_map *umap,
+	__isl_keep isl_schedule_node *node)
+{
+	int empty;
+	enum isl_schedule_node_type type;
+
+	empty = isl_union_map_is_empty(umap);
+	if (empty < 0)
+		return -1;
+	if (empty)
+		return 0;
+	if (!node)
+		return -1;
+
+	type = isl_schedule_node_get_type(node);
+	switch (type) {
+	case isl_schedule_node_error:
+		return -1;
+	case isl_schedule_node_leaf:
+		return 0;
+	case isl_schedule_node_band:
+		return after_in_band(umap, node);
+	case isl_schedule_node_domain:
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_internal,
+			"unexpected internal domain node", return -1);
+	case isl_schedule_node_context:
+		return after_in_context(umap, node);
+	case isl_schedule_node_expansion:
+		return after_in_expansion(umap, node);
+	case isl_schedule_node_extension:
+		return after_in_extension(umap, node);
+	case isl_schedule_node_filter:
+		return after_in_filter(umap, node);
+	case isl_schedule_node_guard:
+	case isl_schedule_node_mark:
+		return after_in_child(umap, node);
+	case isl_schedule_node_set:
+		return after_in_set(umap, node);
+	case isl_schedule_node_sequence:
+		return after_in_sequence(umap, node);
+	}
+
+	return 1;
+}
+
+/* Is any domain element of "map1" scheduled after any domain
+ * element of "map2" by the subtree underneath the current band node,
+ * while at the same time being scheduled together by the current
+ * band node, i.e., by "map1" and "map2?
+ *
+ * If the child of the current band node is a leaf, then
+ * no element can be scheduled after any other element.
+ *
+ * Otherwise, we construct a relation between domain elements
+ * of "map1" and domain elements of "map2" that are scheduled
+ * together and then check if the subtree underneath the current
+ * band node determines their relative order.
+ */
+static int after_in_subtree(__isl_keep isl_ast_build *build,
+	__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	isl_schedule_node *node;
+	isl_map *map;
+	isl_union_map *umap;
+	int after;
+
+	node = isl_ast_build_get_schedule_node(build);
+	if (!node)
+		return -1;
+	node = isl_schedule_node_child(node, 0);
+	if (isl_schedule_node_get_type(node) == isl_schedule_node_leaf) {
+		isl_schedule_node_free(node);
+		return 0;
+	}
+	map = isl_map_copy(map2);
+	map = isl_map_apply_domain(map, isl_map_copy(map1));
+	umap = isl_union_map_from_map(map);
+	after = after_in_tree(umap, node);
+	isl_union_map_free(umap);
+	isl_schedule_node_free(node);
+	return after;
+}
+
+/* Internal data for any_scheduled_after.
+ *
+ * "build" is the build in which the AST is constructed.
+ * "depth" is the number of loops that have already been generated
+ * "group_coscheduled" is a local copy of options->ast_build_group_coscheduled
+ * "domain" is an array of set-map pairs corresponding to the different
+ * iteration domains.  The set is the schedule domain, i.e., the domain
+ * of the inverse schedule, while the map is the inverse schedule itself.
+ */
+struct isl_any_scheduled_after_data {
+	isl_ast_build *build;
+	int depth;
+	int group_coscheduled;
+	struct isl_set_map_pair *domain;
+};
+
+/* Is any element of domain "i" scheduled after any element of domain "j"
+ * (for a common iteration of the first data->depth loops)?
+ *
+ * data->domain[i].set contains the domain of the inverse schedule
+ * for domain "i", i.e., elements in the schedule domain.
+ *
+ * If we are inside a band of a schedule tree and there is a pair
+ * of elements in the two domains that is schedule together by
+ * the current band, then we check if any element of "i" may be schedule
+ * after element of "j" by the descendants of the band node.
+ *
+ * If data->group_coscheduled is set, then we also return 1 if there
+ * is any pair of elements in the two domains that are scheduled together.
+ */
+static isl_bool any_scheduled_after(int i, int j, void *user)
+{
+	struct isl_any_scheduled_after_data *data = user;
+	int dim = isl_set_dim(data->domain[i].set, isl_dim_set);
+	int pos;
+
+	for (pos = data->depth; pos < dim; ++pos) {
+		int follows;
+
+		follows = isl_set_follows_at(data->domain[i].set,
+						data->domain[j].set, pos);
+
+		if (follows < -1)
+			return isl_bool_error;
+		if (follows > 0)
+			return isl_bool_true;
+		if (follows < 0)
+			return isl_bool_false;
+	}
+
+	if (isl_ast_build_has_schedule_node(data->build)) {
+		int after;
+
+		after = after_in_subtree(data->build, data->domain[i].map,
+					    data->domain[j].map);
+		if (after < 0 || after)
+			return after;
+	}
+
+	return data->group_coscheduled;
+}
+
+/* Look for independent components at the current depth and generate code
+ * for each component separately.  The resulting lists of grafts are
+ * merged in an attempt to combine grafts with identical guards.
+ *
+ * Code for two domains can be generated separately if all the elements
+ * of one domain are scheduled before (or together with) all the elements
+ * of the other domain.  We therefore consider the graph with as nodes
+ * the domains and an edge between two nodes if any element of the first
+ * node is scheduled after any element of the second node.
+ * If the ast_build_group_coscheduled is set, then we also add an edge if
+ * there is any pair of elements in the two domains that are scheduled
+ * together.
+ * Code is then generated (by generate_component)
+ * for each of the strongly connected components in this graph
+ * in their topological order.
+ *
+ * Since the test is performed on the domain of the inverse schedules of
+ * the different domains, we precompute these domains and store
+ * them in data.domain.
+ */
+static __isl_give isl_ast_graft_list *generate_components(
+	__isl_take isl_union_map *executed, __isl_take isl_ast_build *build)
+{
+	int i;
+	isl_ctx *ctx = isl_ast_build_get_ctx(build);
+	int n = isl_union_map_n_map(executed);
+	struct isl_any_scheduled_after_data data;
+	struct isl_set_map_pair *next;
+	struct isl_tarjan_graph *g = NULL;
+	isl_ast_graft_list *list = NULL;
+	int n_domain = 0;
+
+	data.domain = isl_calloc_array(ctx, struct isl_set_map_pair, n);
+	if (!data.domain)
+		goto error;
+	n_domain = n;
+
+	next = data.domain;
+	if (isl_union_map_foreach_map(executed, &extract_domain, &next) < 0)
+		goto error;
+
+	if (!build)
+		goto error;
+	data.build = build;
+	data.depth = isl_ast_build_get_depth(build);
+	data.group_coscheduled = isl_options_get_ast_build_group_coscheduled(ctx);
+	g = isl_tarjan_graph_init(ctx, n, &any_scheduled_after, &data);
+	if (!g)
+		goto error;
+
+	list = isl_ast_graft_list_alloc(ctx, 0);
+
+	i = 0;
+	while (list && n) {
+		isl_ast_graft_list *list_c;
+		int first = i;
+
+		if (g->order[i] == -1)
+			isl_die(ctx, isl_error_internal, "cannot happen",
+				goto error);
+		++i; --n;
+		while (g->order[i] != -1) {
+			++i; --n;
+		}
+
+		list_c = generate_component(data.domain,
+					    g->order + first, i - first,
+					    isl_ast_build_copy(build));
+		list = isl_ast_graft_list_merge(list, list_c, build);
+
+		++i;
+	}
+
+	if (0)
+error:		list = isl_ast_graft_list_free(list);
+	isl_tarjan_graph_free(g);
+	for (i = 0; i < n_domain; ++i) {
+		isl_map_free(data.domain[i].map);
+		isl_set_free(data.domain[i].set);
+	}
+	free(data.domain);
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+
+	return list;
+}
+
+/* Generate code for the next level (and all inner levels).
+ *
+ * If "executed" is empty, i.e., no code needs to be generated,
+ * then we return an empty list.
+ *
+ * If we have already generated code for all loop levels, then we pass
+ * control to generate_inner_level.
+ *
+ * If "executed" lives in a single space, i.e., if code needs to be
+ * generated for a single domain, then there can only be a single
+ * component and we go directly to generate_shifted_component.
+ * Otherwise, we call generate_components to detect the components
+ * and to call generate_component on each of them separately.
+ */
+static __isl_give isl_ast_graft_list *generate_next_level(
+	__isl_take isl_union_map *executed, __isl_take isl_ast_build *build)
+{
+	int depth;
+
+	if (!build || !executed)
+		goto error;
+
+	if (isl_union_map_is_empty(executed)) {
+		isl_ctx *ctx = isl_ast_build_get_ctx(build);
+		isl_union_map_free(executed);
+		isl_ast_build_free(build);
+		return isl_ast_graft_list_alloc(ctx, 0);
+	}
+
+	depth = isl_ast_build_get_depth(build);
+	if (depth >= isl_ast_build_dim(build, isl_dim_set))
+		return generate_inner_level(executed, build);
+
+	if (isl_union_map_n_map(executed) == 1)
+		return generate_shifted_component(executed, build);
+
+	return generate_components(executed, build);
+error:
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+	return NULL;
+}
+
+/* Internal data structure used by isl_ast_build_node_from_schedule_map.
+ * internal, executed and build are the inputs to generate_code.
+ * list collects the output.
+ */
+struct isl_generate_code_data {
+	int internal;
+	isl_union_map *executed;
+	isl_ast_build *build;
+
+	isl_ast_graft_list *list;
+};
+
+/* Given an inverse schedule in terms of the external build schedule, i.e.,
+ *
+ *	[E -> S] -> D
+ *
+ * with E the external build schedule and S the additional schedule "space",
+ * reformulate the inverse schedule in terms of the internal schedule domain,
+ * i.e., return
+ *
+ *	[I -> S] -> D
+ *
+ * We first obtain a mapping
+ *
+ *	I -> E
+ *
+ * take the inverse and the product with S -> S, resulting in
+ *
+ *	[I -> S] -> [E -> S]
+ *
+ * Applying the map to the input produces the desired result.
+ */
+static __isl_give isl_union_map *internal_executed(
+	__isl_take isl_union_map *executed, __isl_keep isl_space *space,
+	__isl_keep isl_ast_build *build)
+{
+	isl_map *id, *proj;
+
+	proj = isl_ast_build_get_schedule_map(build);
+	proj = isl_map_reverse(proj);
+	space = isl_space_map_from_set(isl_space_copy(space));
+	id = isl_map_identity(space);
+	proj = isl_map_product(proj, id);
+	executed = isl_union_map_apply_domain(executed,
+						isl_union_map_from_map(proj));
+	return executed;
+}
+
+/* Generate an AST that visits the elements in the range of data->executed
+ * in the relative order specified by the corresponding domain element(s)
+ * for those domain elements that belong to "set".
+ * Add the result to data->list.
+ *
+ * The caller ensures that "set" is a universe domain.
+ * "space" is the space of the additional part of the schedule.
+ * It is equal to the space of "set" if build->domain is parametric.
+ * Otherwise, it is equal to the range of the wrapped space of "set".
+ *
+ * If the build space is not parametric and
+ * if isl_ast_build_node_from_schedule_map
+ * was called from an outside user (data->internal not set), then
+ * the (inverse) schedule refers to the external build domain and needs to
+ * be transformed to refer to the internal build domain.
+ *
+ * If the build space is parametric, then we add some of the parameter
+ * constraints to the executed relation.  Adding these constraints
+ * allows for an earlier detection of conflicts in some cases.
+ * However, we do not want to divide the executed relation into
+ * more disjuncts than necessary.  We therefore approximate
+ * the constraints on the parameters by a single disjunct set.
+ *
+ * The build is extended to include the additional part of the schedule.
+ * If the original build space was not parametric, then the options
+ * in data->build refer only to the additional part of the schedule
+ * and they need to be adjusted to refer to the complete AST build
+ * domain.
+ *
+ * After having adjusted inverse schedule and build, we start generating
+ * code with the outer loop of the current code generation
+ * in generate_next_level.
+ *
+ * If the original build space was not parametric, we undo the embedding
+ * on the resulting isl_ast_node_list so that it can be used within
+ * the outer AST build.
+ */
+static isl_stat generate_code_in_space(struct isl_generate_code_data *data,
+	__isl_take isl_set *set, __isl_take isl_space *space)
+{
+	isl_union_map *executed;
+	isl_ast_build *build;
+	isl_ast_graft_list *list;
+	int embed;
+
+	executed = isl_union_map_copy(data->executed);
+	executed = isl_union_map_intersect_domain(executed,
+						 isl_union_set_from_set(set));
+
+	embed = !isl_set_is_params(data->build->domain);
+	if (embed && !data->internal)
+		executed = internal_executed(executed, space, data->build);
+	if (!embed) {
+		isl_set *domain;
+		domain = isl_ast_build_get_domain(data->build);
+		domain = isl_set_from_basic_set(isl_set_simple_hull(domain));
+		executed = isl_union_map_intersect_params(executed, domain);
+	}
+
+	build = isl_ast_build_copy(data->build);
+	build = isl_ast_build_product(build, space);
+
+	list = generate_next_level(executed, build);
+
+	list = isl_ast_graft_list_unembed(list, embed);
+
+	data->list = isl_ast_graft_list_concat(data->list, list);
+
+	return isl_stat_ok;
+}
+
+/* Generate an AST that visits the elements in the range of data->executed
+ * in the relative order specified by the corresponding domain element(s)
+ * for those domain elements that belong to "set".
+ * Add the result to data->list.
+ *
+ * The caller ensures that "set" is a universe domain.
+ *
+ * If the build space S is not parametric, then the space of "set"
+ * need to be a wrapped relation with S as domain.  That is, it needs
+ * to be of the form
+ *
+ *	[S -> T]
+ *
+ * Check this property and pass control to generate_code_in_space
+ * passing along T.
+ * If the build space is not parametric, then T is the space of "set".
+ */
+static isl_stat generate_code_set(__isl_take isl_set *set, void *user)
+{
+	struct isl_generate_code_data *data = user;
+	isl_space *space, *build_space;
+	int is_domain;
+
+	space = isl_set_get_space(set);
+
+	if (isl_set_is_params(data->build->domain))
+		return generate_code_in_space(data, set, space);
+
+	build_space = isl_ast_build_get_space(data->build, data->internal);
+	space = isl_space_unwrap(space);
+	is_domain = isl_space_is_domain(build_space, space);
+	isl_space_free(build_space);
+	space = isl_space_range(space);
+
+	if (is_domain < 0)
+		goto error;
+	if (!is_domain)
+		isl_die(isl_set_get_ctx(set), isl_error_invalid,
+			"invalid nested schedule space", goto error);
+
+	return generate_code_in_space(data, set, space);
+error:
+	isl_set_free(set);
+	isl_space_free(space);
+	return isl_stat_error;
+}
+
+/* Generate an AST that visits the elements in the range of "executed"
+ * in the relative order specified by the corresponding domain element(s).
+ *
+ * "build" is an isl_ast_build that has either been constructed by
+ * isl_ast_build_from_context or passed to a callback set by
+ * isl_ast_build_set_create_leaf.
+ * In the first case, the space of the isl_ast_build is typically
+ * a parametric space, although this is currently not enforced.
+ * In the second case, the space is never a parametric space.
+ * If the space S is not parametric, then the domain space(s) of "executed"
+ * need to be wrapped relations with S as domain.
+ *
+ * If the domain of "executed" consists of several spaces, then an AST
+ * is generated for each of them (in arbitrary order) and the results
+ * are concatenated.
+ *
+ * If "internal" is set, then the domain "S" above refers to the internal
+ * schedule domain representation.  Otherwise, it refers to the external
+ * representation, as returned by isl_ast_build_get_schedule_space.
+ *
+ * We essentially run over all the spaces in the domain of "executed"
+ * and call generate_code_set on each of them.
+ */
+static __isl_give isl_ast_graft_list *generate_code(
+	__isl_take isl_union_map *executed, __isl_take isl_ast_build *build,
+	int internal)
+{
+	isl_ctx *ctx;
+	struct isl_generate_code_data data = { 0 };
+	isl_space *space;
+	isl_union_set *schedule_domain;
+	isl_union_map *universe;
+
+	if (!build)
+		goto error;
+	space = isl_ast_build_get_space(build, 1);
+	space = isl_space_align_params(space,
+				    isl_union_map_get_space(executed));
+	space = isl_space_align_params(space,
+				    isl_union_map_get_space(build->options));
+	build = isl_ast_build_align_params(build, isl_space_copy(space));
+	executed = isl_union_map_align_params(executed, space);
+	if (!executed || !build)
+		goto error;
+
+	ctx = isl_ast_build_get_ctx(build);
+
+	data.internal = internal;
+	data.executed = executed;
+	data.build = build;
+	data.list = isl_ast_graft_list_alloc(ctx, 0);
+
+	universe = isl_union_map_universe(isl_union_map_copy(executed));
+	schedule_domain = isl_union_map_domain(universe);
+	if (isl_union_set_foreach_set(schedule_domain, &generate_code_set,
+					&data) < 0)
+		data.list = isl_ast_graft_list_free(data.list);
+
+	isl_union_set_free(schedule_domain);
+	isl_union_map_free(executed);
+
+	isl_ast_build_free(build);
+	return data.list;
+error:
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+	return NULL;
+}
+
+/* Generate an AST that visits the elements in the domain of "schedule"
+ * in the relative order specified by the corresponding image element(s).
+ *
+ * "build" is an isl_ast_build that has either been constructed by
+ * isl_ast_build_from_context or passed to a callback set by
+ * isl_ast_build_set_create_leaf.
+ * In the first case, the space of the isl_ast_build is typically
+ * a parametric space, although this is currently not enforced.
+ * In the second case, the space is never a parametric space.
+ * If the space S is not parametric, then the range space(s) of "schedule"
+ * need to be wrapped relations with S as domain.
+ *
+ * If the range of "schedule" consists of several spaces, then an AST
+ * is generated for each of them (in arbitrary order) and the results
+ * are concatenated.
+ *
+ * We first initialize the local copies of the relevant options.
+ * We do this here rather than when the isl_ast_build is created
+ * because the options may have changed between the construction
+ * of the isl_ast_build and the call to isl_generate_code.
+ *
+ * The main computation is performed on an inverse schedule (with
+ * the schedule domain in the domain and the elements to be executed
+ * in the range) called "executed".
+ */
+__isl_give isl_ast_node *isl_ast_build_node_from_schedule_map(
+	__isl_keep isl_ast_build *build, __isl_take isl_union_map *schedule)
+{
+	isl_ast_graft_list *list;
+	isl_ast_node *node;
+	isl_union_map *executed;
+
+	build = isl_ast_build_copy(build);
+	build = isl_ast_build_set_single_valued(build, 0);
+	schedule = isl_union_map_coalesce(schedule);
+	schedule = isl_union_map_remove_redundancies(schedule);
+	executed = isl_union_map_reverse(schedule);
+	list = generate_code(executed, isl_ast_build_copy(build), 0);
+	node = isl_ast_node_from_graft_list(list, build);
+	isl_ast_build_free(build);
+
+	return node;
+}
+
+/* The old name for isl_ast_build_node_from_schedule_map.
+ * It is being kept for backward compatibility, but
+ * it will be removed in the future.
+ */
+__isl_give isl_ast_node *isl_ast_build_ast_from_schedule(
+	__isl_keep isl_ast_build *build, __isl_take isl_union_map *schedule)
+{
+	return isl_ast_build_node_from_schedule_map(build, schedule);
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the band node "node" and its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * If the band is empty, we continue with its descendants.
+ * Otherwise, we extend the build and the inverse schedule with
+ * the additional space/partial schedule and continue generating
+ * an AST in generate_next_level.
+ * As soon as we have extended the inverse schedule with the additional
+ * partial schedule, we look for equalities that may exists between
+ * the old and the new part.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_band(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *executed)
+{
+	isl_space *space;
+	isl_multi_union_pw_aff *extra;
+	isl_union_map *extra_umap;
+	isl_ast_graft_list *list;
+	unsigned n1, n2;
+
+	if (!build || !node || !executed)
+		goto error;
+
+	if (isl_schedule_node_band_n_member(node) == 0)
+		return build_ast_from_child(build, node, executed);
+
+	extra = isl_schedule_node_band_get_partial_schedule(node);
+	extra = isl_multi_union_pw_aff_align_params(extra,
+				isl_ast_build_get_space(build, 1));
+	space = isl_multi_union_pw_aff_get_space(extra);
+
+	extra_umap = isl_union_map_from_multi_union_pw_aff(extra);
+	extra_umap = isl_union_map_reverse(extra_umap);
+
+	executed = isl_union_map_domain_product(executed, extra_umap);
+	executed = isl_union_map_detect_equalities(executed);
+
+	n1 = isl_ast_build_dim(build, isl_dim_param);
+	build = isl_ast_build_product(build, space);
+	n2 = isl_ast_build_dim(build, isl_dim_param);
+	if (n2 > n1)
+		isl_die(isl_ast_build_get_ctx(build), isl_error_invalid,
+			"band node is not allowed to introduce new parameters",
+			build = isl_ast_build_free(build));
+	build = isl_ast_build_set_schedule_node(build, node);
+
+	list = generate_next_level(executed, build);
+
+	list = isl_ast_graft_list_unembed(list, 1);
+
+	return list;
+error:
+	isl_schedule_node_free(node);
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+	return NULL;
+}
+
+/* Hoist a list of grafts (in practice containing a single graft)
+ * from "sub_build" (which includes extra context information)
+ * to "build".
+ *
+ * In particular, project out all additional parameters introduced
+ * by the context node from the enforced constraints and the guard
+ * of the single graft.
+ */
+static __isl_give isl_ast_graft_list *hoist_out_of_context(
+	__isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build,
+	__isl_keep isl_ast_build *sub_build)
+{
+	isl_ast_graft *graft;
+	isl_basic_set *enforced;
+	isl_set *guard;
+	unsigned n_param, extra_param;
+
+	if (!build || !sub_build)
+		return isl_ast_graft_list_free(list);
+
+	n_param = isl_ast_build_dim(build, isl_dim_param);
+	extra_param = isl_ast_build_dim(sub_build, isl_dim_param);
+
+	if (extra_param == n_param)
+		return list;
+
+	extra_param -= n_param;
+	enforced = isl_ast_graft_list_extract_shared_enforced(list, sub_build);
+	enforced = isl_basic_set_project_out(enforced, isl_dim_param,
+							n_param, extra_param);
+	enforced = isl_basic_set_remove_unknown_divs(enforced);
+	guard = isl_ast_graft_list_extract_hoistable_guard(list, sub_build);
+	guard = isl_set_remove_divs_involving_dims(guard, isl_dim_param,
+							n_param, extra_param);
+	guard = isl_set_project_out(guard, isl_dim_param, n_param, extra_param);
+	guard = isl_set_compute_divs(guard);
+	graft = isl_ast_graft_alloc_from_children(list, guard, enforced,
+							build, sub_build);
+	list = isl_ast_graft_list_from_ast_graft(graft);
+
+	return list;
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the context node "node"
+ * and its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * The context node may introduce additional parameters as well as
+ * constraints on the outer schedule dimenions or original parameters.
+ *
+ * We add the extra parameters to a new build and the context
+ * constraints to both the build and (as a single disjunct)
+ * to the domain of "executed".  Since the context constraints
+ * are specified in terms of the input schedule, we first need
+ * to map them to the internal schedule domain.
+ *
+ * After constructing the AST from the descendants of "node",
+ * we combine the list of grafts into a single graft within
+ * the new build, in order to be able to exploit the additional
+ * context constraints during this combination.
+ *
+ * Additionally, if the current node is the outermost node in
+ * the schedule tree (apart from the root domain node), we generate
+ * all pending guards, again to be able to exploit the additional
+ * context constraints.  We currently do not do this for internal
+ * context nodes since we may still want to hoist conditions
+ * to outer AST nodes.
+ *
+ * If the context node introduced any new parameters, then they
+ * are removed from the set of enforced constraints and guard
+ * in hoist_out_of_context.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_context(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *executed)
+{
+	isl_set *context;
+	isl_space *space;
+	isl_multi_aff *internal2input;
+	isl_ast_build *sub_build;
+	isl_ast_graft_list *list;
+	int n, depth;
+
+	depth = isl_schedule_node_get_tree_depth(node);
+	space = isl_ast_build_get_space(build, 1);
+	context = isl_schedule_node_context_get_context(node);
+	context = isl_set_align_params(context, space);
+	sub_build = isl_ast_build_copy(build);
+	space = isl_set_get_space(context);
+	sub_build = isl_ast_build_align_params(sub_build, space);
+	internal2input = isl_ast_build_get_internal2input(sub_build);
+	context = isl_set_preimage_multi_aff(context, internal2input);
+	sub_build = isl_ast_build_restrict_generated(sub_build,
+					isl_set_copy(context));
+	context = isl_set_from_basic_set(isl_set_simple_hull(context));
+	executed = isl_union_map_intersect_domain(executed,
+					isl_union_set_from_set(context));
+
+	list = build_ast_from_child(isl_ast_build_copy(sub_build),
+						node, executed);
+	n = isl_ast_graft_list_n_ast_graft(list);
+	if (n < 0)
+		list = isl_ast_graft_list_free(list);
+
+	list = isl_ast_graft_list_fuse(list, sub_build);
+	if (depth == 1)
+		list = isl_ast_graft_list_insert_pending_guard_nodes(list,
+								sub_build);
+	if (n >= 1)
+		list = hoist_out_of_context(list, build, sub_build);
+
+	isl_ast_build_free(build);
+	isl_ast_build_free(sub_build);
+
+	return list;
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the expansion node "node" and
+ * its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * We expand the domain elements by the expansion and
+ * continue with the descendants of the node.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_expansion(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *executed)
+{
+	isl_union_map *expansion;
+	unsigned n1, n2;
+
+	expansion = isl_schedule_node_expansion_get_expansion(node);
+	expansion = isl_union_map_align_params(expansion,
+				isl_union_map_get_space(executed));
+
+	n1 = isl_union_map_dim(executed, isl_dim_param);
+	executed = isl_union_map_apply_range(executed, expansion);
+	n2 = isl_union_map_dim(executed, isl_dim_param);
+	if (n2 > n1)
+		isl_die(isl_ast_build_get_ctx(build), isl_error_invalid,
+			"expansion node is not allowed to introduce "
+			"new parameters", goto error);
+
+	return build_ast_from_child(build, node, executed);
+error:
+	isl_ast_build_free(build);
+	isl_schedule_node_free(node);
+	isl_union_map_free(executed);
+	return NULL;
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the extension node "node" and
+ * its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * Extend the inverse schedule with the extension applied to current
+ * set of generated constraints.  Since the extension if formulated
+ * in terms of the input schedule, it first needs to be transformed
+ * to refer to the internal schedule.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_extension(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *executed)
+{
+	isl_union_set *schedule_domain;
+	isl_union_map *extension;
+	isl_set *set;
+
+	set = isl_ast_build_get_generated(build);
+	set = isl_set_from_basic_set(isl_set_simple_hull(set));
+	schedule_domain = isl_union_set_from_set(set);
+
+	extension = isl_schedule_node_extension_get_extension(node);
+
+	extension = isl_union_map_preimage_domain_multi_aff(extension,
+			isl_multi_aff_copy(build->internal2input));
+	extension = isl_union_map_intersect_domain(extension, schedule_domain);
+	extension = isl_ast_build_substitute_values_union_map_domain(build,
+								    extension);
+	executed = isl_union_map_union(executed, extension);
+
+	return build_ast_from_child(build, node, executed);
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the filter node "node" and
+ * its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * We simply intersect the iteration domain (i.e., the range of "executed")
+ * with the filter and continue with the descendants of the node,
+ * unless the resulting inverse schedule is empty, in which
+ * case we return an empty list.
+ *
+ * If the result of the intersection is equal to the original "executed"
+ * relation, then keep the original representation since the intersection
+ * may have unnecessarily broken up the relation into a greater number
+ * of disjuncts.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_filter(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *executed)
+{
+	isl_ctx *ctx;
+	isl_union_set *filter;
+	isl_union_map *orig;
+	isl_ast_graft_list *list;
+	int empty;
+	isl_bool unchanged;
+	unsigned n1, n2;
+
+	orig = isl_union_map_copy(executed);
+	if (!build || !node || !executed)
+		goto error;
+
+	filter = isl_schedule_node_filter_get_filter(node);
+	filter = isl_union_set_align_params(filter,
+				isl_union_map_get_space(executed));
+	n1 = isl_union_map_dim(executed, isl_dim_param);
+	executed = isl_union_map_intersect_range(executed, filter);
+	n2 = isl_union_map_dim(executed, isl_dim_param);
+	if (n2 > n1)
+		isl_die(isl_ast_build_get_ctx(build), isl_error_invalid,
+			"filter node is not allowed to introduce "
+			"new parameters", goto error);
+
+	unchanged = isl_union_map_is_subset(orig, executed);
+	empty = isl_union_map_is_empty(executed);
+	if (unchanged < 0 || empty < 0)
+		goto error;
+	if (unchanged) {
+		isl_union_map_free(executed);
+		return build_ast_from_child(build, node, orig);
+	}
+	isl_union_map_free(orig);
+	if (!empty)
+		return build_ast_from_child(build, node, executed);
+
+	ctx = isl_ast_build_get_ctx(build);
+	list = isl_ast_graft_list_alloc(ctx, 0);
+	isl_ast_build_free(build);
+	isl_schedule_node_free(node);
+	isl_union_map_free(executed);
+	return list;
+error:
+	isl_ast_build_free(build);
+	isl_schedule_node_free(node);
+	isl_union_map_free(executed);
+	isl_union_map_free(orig);
+	return NULL;
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the guard node "node" and
+ * its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * Ensure that the associated guard is enforced by the outer AST
+ * constructs by adding it to the guard of the graft.
+ * Since we know that we will enforce the guard, we can also include it
+ * in the generated constraints used to construct an AST for
+ * the descendant nodes.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_guard(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *executed)
+{
+	isl_space *space;
+	isl_set *guard, *hoisted;
+	isl_basic_set *enforced;
+	isl_ast_build *sub_build;
+	isl_ast_graft *graft;
+	isl_ast_graft_list *list;
+	unsigned n1, n2;
+
+	space = isl_ast_build_get_space(build, 1);
+	guard = isl_schedule_node_guard_get_guard(node);
+	n1 = isl_space_dim(space, isl_dim_param);
+	guard = isl_set_align_params(guard, space);
+	n2 = isl_set_dim(guard, isl_dim_param);
+	if (n2 > n1)
+		isl_die(isl_ast_build_get_ctx(build), isl_error_invalid,
+			"guard node is not allowed to introduce "
+			"new parameters", guard = isl_set_free(guard));
+	guard = isl_set_preimage_multi_aff(guard,
+			isl_multi_aff_copy(build->internal2input));
+	guard = isl_ast_build_specialize(build, guard);
+	guard = isl_set_gist(guard, isl_set_copy(build->generated));
+
+	sub_build = isl_ast_build_copy(build);
+	sub_build = isl_ast_build_restrict_generated(sub_build,
+							isl_set_copy(guard));
+
+	list = build_ast_from_child(isl_ast_build_copy(sub_build),
+							node, executed);
+
+	hoisted = isl_ast_graft_list_extract_hoistable_guard(list, sub_build);
+	if (isl_set_n_basic_set(hoisted) > 1)
+		list = isl_ast_graft_list_gist_guards(list,
+						    isl_set_copy(hoisted));
+	guard = isl_set_intersect(guard, hoisted);
+	enforced = extract_shared_enforced(list, build);
+	graft = isl_ast_graft_alloc_from_children(list, guard, enforced,
+						    build, sub_build);
+
+	isl_ast_build_free(sub_build);
+	isl_ast_build_free(build);
+	return isl_ast_graft_list_from_ast_graft(graft);
+}
+
+/* Call the before_each_mark callback, if requested by the user.
+ *
+ * Return 0 on success and -1 on error.
+ *
+ * The caller is responsible for recording the current inverse schedule
+ * in "build".
+ */
+static isl_stat before_each_mark(__isl_keep isl_id *mark,
+	__isl_keep isl_ast_build *build)
+{
+	if (!build)
+		return isl_stat_error;
+	if (!build->before_each_mark)
+		return isl_stat_ok;
+	return build->before_each_mark(mark, build,
+					build->before_each_mark_user);
+}
+
+/* Call the after_each_mark callback, if requested by the user.
+ *
+ * The caller is responsible for recording the current inverse schedule
+ * in "build".
+ */
+static __isl_give isl_ast_graft *after_each_mark(
+	__isl_take isl_ast_graft *graft, __isl_keep isl_ast_build *build)
+{
+	if (!graft || !build)
+		return isl_ast_graft_free(graft);
+	if (!build->after_each_mark)
+		return graft;
+	graft->node = build->after_each_mark(graft->node, build,
+						build->after_each_mark_user);
+	if (!graft->node)
+		return isl_ast_graft_free(graft);
+	return graft;
+}
+
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the mark node "node" and
+ * its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+
+ * Since we may be calling before_each_mark and after_each_mark
+ * callbacks, we record the current inverse schedule in the build.
+ *
+ * We generate an AST for the child of the mark node, combine
+ * the graft list into a single graft and then insert the mark
+ * in the AST of that single graft.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_mark(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *executed)
+{
+	isl_id *mark;
+	isl_ast_graft *graft;
+	isl_ast_graft_list *list;
+	int n;
+
+	build = isl_ast_build_set_executed(build, isl_union_map_copy(executed));
+
+	mark = isl_schedule_node_mark_get_id(node);
+	if (before_each_mark(mark, build) < 0)
+		node = isl_schedule_node_free(node);
+
+	list = build_ast_from_child(isl_ast_build_copy(build), node, executed);
+	list = isl_ast_graft_list_fuse(list, build);
+	n = isl_ast_graft_list_n_ast_graft(list);
+	if (n < 0)
+		list = isl_ast_graft_list_free(list);
+	if (n == 0) {
+		isl_id_free(mark);
+	} else {
+		graft = isl_ast_graft_list_get_ast_graft(list, 0);
+		graft = isl_ast_graft_insert_mark(graft, mark);
+		graft = after_each_mark(graft, build);
+		list = isl_ast_graft_list_set_ast_graft(list, 0, graft);
+	}
+	isl_ast_build_free(build);
+
+	return list;
+}
+
+static __isl_give isl_ast_graft_list *build_ast_from_schedule_node(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *executed);
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the sequence (or set) node "node" and
+ * its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * We simply generate an AST for each of the children and concatenate
+ * the results.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_sequence(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *executed)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_ast_graft_list *list;
+
+	ctx = isl_ast_build_get_ctx(build);
+	list = isl_ast_graft_list_alloc(ctx, 0);
+
+	n = isl_schedule_node_n_children(node);
+	for (i = 0; i < n; ++i) {
+		isl_schedule_node *child;
+		isl_ast_graft_list *list_i;
+
+		child = isl_schedule_node_get_child(node, i);
+		list_i = build_ast_from_schedule_node(isl_ast_build_copy(build),
+					child, isl_union_map_copy(executed));
+		list = isl_ast_graft_list_concat(list, list_i);
+	}
+	isl_ast_build_free(build);
+	isl_schedule_node_free(node);
+	isl_union_map_free(executed);
+
+	return list;
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the node "node" and its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * If the node is a leaf, then we pass control to generate_inner_level.
+ * Note that the current build does not refer to any band node, so
+ * that generate_inner_level will not try to visit the child of
+ * the leaf node.
+ *
+ * The other node types are handled in separate functions.
+ * Set nodes are currently treated in the same way as sequence nodes.
+ * The children of a set node may be executed in any order,
+ * including the order of the children.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_schedule_node(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *executed)
+{
+	enum isl_schedule_node_type type;
+
+	type = isl_schedule_node_get_type(node);
+
+	switch (type) {
+	case isl_schedule_node_error:
+		goto error;
+	case isl_schedule_node_leaf:
+		isl_schedule_node_free(node);
+		return generate_inner_level(executed, build);
+	case isl_schedule_node_band:
+		return build_ast_from_band(build, node, executed);
+	case isl_schedule_node_context:
+		return build_ast_from_context(build, node, executed);
+	case isl_schedule_node_domain:
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_unsupported,
+			"unexpected internal domain node", goto error);
+	case isl_schedule_node_expansion:
+		return build_ast_from_expansion(build, node, executed);
+	case isl_schedule_node_extension:
+		return build_ast_from_extension(build, node, executed);
+	case isl_schedule_node_filter:
+		return build_ast_from_filter(build, node, executed);
+	case isl_schedule_node_guard:
+		return build_ast_from_guard(build, node, executed);
+	case isl_schedule_node_mark:
+		return build_ast_from_mark(build, node, executed);
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		return build_ast_from_sequence(build, node, executed);
+	}
+
+	isl_die(isl_ast_build_get_ctx(build), isl_error_internal,
+		"unhandled type", goto error);
+error:
+	isl_union_map_free(executed);
+	isl_schedule_node_free(node);
+	isl_ast_build_free(build);
+
+	return NULL;
+}
+
+/* Generate an AST that visits the elements in the domain of "executed"
+ * in the relative order specified by the (single) child of "node" and
+ * its descendants.
+ *
+ * The relation "executed" maps the outer generated loop iterators
+ * to the domain elements executed by those iterations.
+ *
+ * This function is never called on a leaf, set or sequence node,
+ * so the node always has exactly one child.
+ */
+static __isl_give isl_ast_graft_list *build_ast_from_child(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *executed)
+{
+	node = isl_schedule_node_child(node, 0);
+	return build_ast_from_schedule_node(build, node, executed);
+}
+
+/* Generate an AST that visits the elements in the domain of the domain
+ * node "node" in the relative order specified by its descendants.
+ *
+ * An initial inverse schedule is created that maps a zero-dimensional
+ * schedule space to the node domain.
+ * The input "build" is assumed to have a parametric domain and
+ * is replaced by the same zero-dimensional schedule space.
+ *
+ * We also add some of the parameter constraints in the build domain
+ * to the executed relation.  Adding these constraints
+ * allows for an earlier detection of conflicts in some cases.
+ * However, we do not want to divide the executed relation into
+ * more disjuncts than necessary.  We therefore approximate
+ * the constraints on the parameters by a single disjunct set.
+ */
+static __isl_give isl_ast_node *build_ast_from_domain(
+	__isl_take isl_ast_build *build, __isl_take isl_schedule_node *node)
+{
+	isl_ctx *ctx;
+	isl_union_set *domain, *schedule_domain;
+	isl_union_map *executed;
+	isl_space *space;
+	isl_set *set;
+	isl_ast_graft_list *list;
+	isl_ast_node *ast;
+	int is_params;
+
+	if (!build)
+		goto error;
+
+	ctx = isl_ast_build_get_ctx(build);
+	space = isl_ast_build_get_space(build, 1);
+	is_params = isl_space_is_params(space);
+	isl_space_free(space);
+	if (is_params < 0)
+		goto error;
+	if (!is_params)
+		isl_die(ctx, isl_error_unsupported,
+			"expecting parametric initial context", goto error);
+
+	domain = isl_schedule_node_domain_get_domain(node);
+	domain = isl_union_set_coalesce(domain);
+
+	space = isl_union_set_get_space(domain);
+	space = isl_space_set_from_params(space);
+	build = isl_ast_build_product(build, space);
+
+	set = isl_ast_build_get_domain(build);
+	set = isl_set_from_basic_set(isl_set_simple_hull(set));
+	schedule_domain = isl_union_set_from_set(set);
+
+	executed = isl_union_map_from_domain_and_range(schedule_domain, domain);
+	list = build_ast_from_child(isl_ast_build_copy(build), node, executed);
+	ast = isl_ast_node_from_graft_list(list, build);
+	isl_ast_build_free(build);
+
+	return ast;
+error:
+	isl_schedule_node_free(node);
+	isl_ast_build_free(build);
+	return NULL;
+}
+
+/* Generate an AST that visits the elements in the domain of "schedule"
+ * in the relative order specified by the schedule tree.
+ *
+ * "build" is an isl_ast_build that has been created using
+ * isl_ast_build_alloc or isl_ast_build_from_context based
+ * on a parametric set.
+ *
+ * The construction starts at the root node of the schedule,
+ * which is assumed to be a domain node.
+ */
+__isl_give isl_ast_node *isl_ast_build_node_from_schedule(
+	__isl_keep isl_ast_build *build, __isl_take isl_schedule *schedule)
+{
+	isl_ctx *ctx;
+	isl_schedule_node *node;
+
+	if (!build || !schedule)
+		goto error;
+
+	ctx = isl_ast_build_get_ctx(build);
+
+	node = isl_schedule_get_root(schedule);
+	isl_schedule_free(schedule);
+
+	build = isl_ast_build_copy(build);
+	build = isl_ast_build_set_single_valued(build, 0);
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_domain)
+		isl_die(ctx, isl_error_unsupported,
+			"expecting root domain node",
+			build = isl_ast_build_free(build));
+	return build_ast_from_domain(build, node);
+error:
+	isl_schedule_free(schedule);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_ast_graft.c b/final/lib/External/isl/isl_ast_graft.c
new file mode 100644
index 0000000..6d90dd2
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_graft.c
@@ -0,0 +1,1296 @@
+/*
+ * Copyright 2012      Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <isl_ast_private.h>
+#include <isl_ast_build_expr.h>
+#include <isl_ast_build_private.h>
+#include <isl_ast_graft_private.h>
+
+static __isl_give isl_ast_graft *isl_ast_graft_copy(
+	__isl_keep isl_ast_graft *graft);
+
+#undef BASE
+#define BASE ast_graft
+
+#include <isl_list_templ.c>
+
+#undef BASE
+#define BASE ast_graft
+#include <print_templ.c>
+
+isl_ctx *isl_ast_graft_get_ctx(__isl_keep isl_ast_graft *graft)
+{
+	if (!graft)
+		return NULL;
+	return isl_basic_set_get_ctx(graft->enforced);
+}
+
+__isl_give isl_ast_node *isl_ast_graft_get_node(
+	__isl_keep isl_ast_graft *graft)
+{
+	return graft ? isl_ast_node_copy(graft->node) : NULL;
+}
+
+/* Create a graft for "node" with no guards and no enforced conditions.
+ */
+__isl_give isl_ast_graft *isl_ast_graft_alloc(
+	__isl_take isl_ast_node *node, __isl_keep isl_ast_build *build)
+{
+	isl_ctx *ctx;
+	isl_space *space;
+	isl_ast_graft *graft;
+
+	if (!node)
+		return NULL;
+
+	ctx = isl_ast_node_get_ctx(node);
+	graft = isl_calloc_type(ctx, isl_ast_graft);
+	if (!graft)
+		goto error;
+
+	space = isl_ast_build_get_space(build, 1);
+
+	graft->ref = 1;
+	graft->node = node;
+	graft->guard = isl_set_universe(isl_space_copy(space));
+	graft->enforced = isl_basic_set_universe(space);
+
+	if (!graft->guard || !graft->enforced)
+		return isl_ast_graft_free(graft);
+
+	return graft;
+error:
+	isl_ast_node_free(node);
+	return NULL;
+}
+
+/* Create a graft with no guards and no enforced conditions
+ * encapsulating a call to the domain element specified by "executed".
+ * "executed" is assumed to be single-valued.
+ */
+__isl_give isl_ast_graft *isl_ast_graft_alloc_domain(
+	__isl_take isl_map *executed, __isl_keep isl_ast_build *build)
+{
+	isl_ast_node *node;
+
+	node = isl_ast_build_call_from_executed(build, executed);
+
+	return isl_ast_graft_alloc(node, build);
+}
+
+static __isl_give isl_ast_graft *isl_ast_graft_copy(
+	__isl_keep isl_ast_graft *graft)
+{
+	if (!graft)
+		return NULL;
+
+	graft->ref++;
+	return graft;
+}
+
+/* Do all the grafts in "list" have the same guard and is this guard
+ * independent of the current depth?
+ */
+static int equal_independent_guards(__isl_keep isl_ast_graft_list *list,
+	__isl_keep isl_ast_build *build)
+{
+	int i, n;
+	int depth;
+	isl_ast_graft *graft_0;
+	int equal = 1;
+	int skip;
+
+	graft_0 = isl_ast_graft_list_get_ast_graft(list, 0);
+	if (!graft_0)
+		return -1;
+
+	depth = isl_ast_build_get_depth(build);
+	if (isl_set_dim(graft_0->guard, isl_dim_set) <= depth)
+		skip = 0;
+	else
+		skip = isl_set_involves_dims(graft_0->guard,
+						isl_dim_set, depth, 1);
+	if (skip < 0 || skip) {
+		isl_ast_graft_free(graft_0);
+		return skip < 0 ? -1 : 0;
+	}
+
+	n = isl_ast_graft_list_n_ast_graft(list);
+	for (i = 1; i < n; ++i) {
+		isl_ast_graft *graft;
+		graft = isl_ast_graft_list_get_ast_graft(list, i);
+		if (!graft)
+			equal = -1;
+		else
+			equal = isl_set_is_equal(graft_0->guard, graft->guard);
+		isl_ast_graft_free(graft);
+		if (equal < 0 || !equal)
+			break;
+	}
+
+	isl_ast_graft_free(graft_0);
+
+	return equal;
+}
+
+/* Hoist "guard" out of the current level (given by "build").
+ *
+ * In particular, eliminate the dimension corresponding to the current depth.
+ */
+static __isl_give isl_set *hoist_guard(__isl_take isl_set *guard,
+	__isl_keep isl_ast_build *build)
+{
+	int depth;
+
+	depth = isl_ast_build_get_depth(build);
+	if (depth < isl_set_dim(guard, isl_dim_set)) {
+		guard = isl_set_remove_divs_involving_dims(guard,
+						isl_dim_set, depth, 1);
+		guard = isl_set_eliminate(guard, isl_dim_set, depth, 1);
+		guard = isl_set_compute_divs(guard);
+	}
+
+	return guard;
+}
+
+/* Extract a common guard from the grafts in "list" that can be hoisted
+ * out of the current level.  If no such guard can be found, then return
+ * a universal set.
+ *
+ * If all the grafts in the list have the same guard and if this guard
+ * is independent of the current level, then it can be hoisted out.
+ * If there is only one graft in the list and if its guard
+ * depends on the current level, then we eliminate this level and
+ * return the result.
+ *
+ * Otherwise, we return the unshifted simple hull of the guards.
+ * In order to be able to hoist as many constraints as possible,
+ * but at the same time avoid hoisting constraints that did not
+ * appear in the guards in the first place, we intersect the guards
+ * with all the information that is available (i.e., the domain
+ * from the build and the enforced constraints of the graft) and
+ * compute the unshifted hull of the result using only constraints
+ * from the original guards.
+ * In particular, intersecting the guards with other known information
+ * allows us to hoist guards that are only explicit is some of
+ * the grafts and implicit in the others.
+ *
+ * The special case for equal guards is needed in case those guards
+ * are non-convex.  Taking the simple hull would remove information
+ * and would not allow for these guards to be hoisted completely.
+ */
+__isl_give isl_set *isl_ast_graft_list_extract_hoistable_guard(
+	__isl_keep isl_ast_graft_list *list, __isl_keep isl_ast_build *build)
+{
+	int i, n;
+	int equal;
+	isl_ctx *ctx;
+	isl_set *guard;
+	isl_set_list *set_list;
+	isl_basic_set *hull;
+
+	if (!list || !build)
+		return NULL;
+
+	n = isl_ast_graft_list_n_ast_graft(list);
+	if (n == 0)
+		return isl_set_universe(isl_ast_build_get_space(build, 1));
+
+	equal = equal_independent_guards(list, build);
+	if (equal < 0)
+		return NULL;
+
+	if (equal || n == 1) {
+		isl_ast_graft *graft_0;
+
+		graft_0 = isl_ast_graft_list_get_ast_graft(list, 0);
+		if (!graft_0)
+			return NULL;
+		guard = isl_set_copy(graft_0->guard);
+		if (!equal)
+			guard = hoist_guard(guard, build);
+		isl_ast_graft_free(graft_0);
+		return guard;
+	}
+
+	ctx = isl_ast_build_get_ctx(build);
+	set_list = isl_set_list_alloc(ctx, n);
+	guard = isl_set_empty(isl_ast_build_get_space(build, 1));
+	for (i = 0; i < n; ++i) {
+		isl_ast_graft *graft;
+		isl_basic_set *enforced;
+		isl_set *guard_i;
+
+		graft = isl_ast_graft_list_get_ast_graft(list, i);
+		enforced = isl_ast_graft_get_enforced(graft);
+		guard_i = isl_set_copy(graft->guard);
+		isl_ast_graft_free(graft);
+		set_list = isl_set_list_add(set_list, isl_set_copy(guard_i));
+		guard_i = isl_set_intersect(guard_i,
+					    isl_set_from_basic_set(enforced));
+		guard_i = isl_set_intersect(guard_i,
+					    isl_ast_build_get_domain(build));
+		guard = isl_set_union(guard, guard_i);
+	}
+	hull = isl_set_unshifted_simple_hull_from_set_list(guard, set_list);
+	guard = isl_set_from_basic_set(hull);
+	return hoist_guard(guard, build);
+}
+
+/* Internal data structure used inside insert_if.
+ *
+ * list is the list of guarded nodes created by each call to insert_if.
+ * node is the original node that is guarded by insert_if.
+ * build is the build in which the AST is constructed.
+ */
+struct isl_insert_if_data {
+	isl_ast_node_list *list;
+	isl_ast_node *node;
+	isl_ast_build *build;
+};
+
+static isl_stat insert_if(__isl_take isl_basic_set *bset, void *user);
+
+/* Insert an if node around "node" testing the condition encoded
+ * in guard "guard".
+ *
+ * If the user does not want any disjunctions in the if conditions
+ * and if "guard" does involve a disjunction, then we make the different
+ * disjuncts disjoint and insert an if node corresponding to each disjunct
+ * around a copy of "node".  The result is then a block node containing
+ * this sequence of guarded copies of "node".
+ */
+static __isl_give isl_ast_node *ast_node_insert_if(
+	__isl_take isl_ast_node *node, __isl_take isl_set *guard,
+	__isl_keep isl_ast_build *build)
+{
+	struct isl_insert_if_data data;
+	isl_ctx *ctx;
+
+	ctx = isl_ast_build_get_ctx(build);
+	if (isl_options_get_ast_build_allow_or(ctx) ||
+	    isl_set_n_basic_set(guard) <= 1) {
+		isl_ast_node *if_node;
+		isl_ast_expr *expr;
+
+		expr = isl_ast_build_expr_from_set_internal(build, guard);
+
+		if_node = isl_ast_node_alloc_if(expr);
+		return isl_ast_node_if_set_then(if_node, node);
+	}
+
+	guard = isl_set_make_disjoint(guard);
+
+	data.list = isl_ast_node_list_alloc(ctx, 0);
+	data.node = node;
+	data.build = build;
+	if (isl_set_foreach_basic_set(guard, &insert_if, &data) < 0)
+		data.list = isl_ast_node_list_free(data.list);
+
+	isl_set_free(guard);
+	isl_ast_node_free(data.node);
+	return isl_ast_node_alloc_block(data.list);
+}
+
+/* Insert an if node around a copy of "data->node" testing the condition
+ * encoded in guard "bset" and add the result to data->list.
+ */
+static isl_stat insert_if(__isl_take isl_basic_set *bset, void *user)
+{
+	struct isl_insert_if_data *data = user;
+	isl_ast_node *node;
+	isl_set *set;
+
+	set = isl_set_from_basic_set(bset);
+	node = isl_ast_node_copy(data->node);
+	node = ast_node_insert_if(node, set, data->build);
+	data->list = isl_ast_node_list_add(data->list, node);
+
+	return isl_stat_ok;
+}
+
+/* Insert an if node around graft->node testing the condition encoded
+ * in guard "guard", assuming guard involves any conditions.
+ */
+static __isl_give isl_ast_graft *insert_if_node(
+	__isl_take isl_ast_graft *graft, __isl_take isl_set *guard,
+	__isl_keep isl_ast_build *build)
+{
+	int univ;
+
+	if (!graft)
+		goto error;
+
+	univ = isl_set_plain_is_universe(guard);
+	if (univ < 0)
+		goto error;
+	if (univ) {
+		isl_set_free(guard);
+		return graft;
+	}
+
+	build = isl_ast_build_copy(build);
+	graft->node = ast_node_insert_if(graft->node, guard, build);
+	isl_ast_build_free(build);
+
+	if (!graft->node)
+		return isl_ast_graft_free(graft);
+
+	return graft;
+error:
+	isl_set_free(guard);
+	return isl_ast_graft_free(graft);
+}
+
+/* Insert an if node around graft->node testing the condition encoded
+ * in graft->guard, assuming graft->guard involves any conditions.
+ */
+static __isl_give isl_ast_graft *insert_pending_guard_node(
+	__isl_take isl_ast_graft *graft, __isl_keep isl_ast_build *build)
+{
+	if (!graft)
+		return NULL;
+
+	return insert_if_node(graft, isl_set_copy(graft->guard), build);
+}
+
+/* Replace graft->enforced by "enforced".
+ */
+__isl_give isl_ast_graft *isl_ast_graft_set_enforced(
+	__isl_take isl_ast_graft *graft, __isl_take isl_basic_set *enforced)
+{
+	if (!graft || !enforced)
+		goto error;
+
+	isl_basic_set_free(graft->enforced);
+	graft->enforced = enforced;
+
+	return graft;
+error:
+	isl_basic_set_free(enforced);
+	return isl_ast_graft_free(graft);
+}
+
+/* Update "enforced" such that it only involves constraints that are
+ * also enforced by "graft".
+ */
+static __isl_give isl_basic_set *update_enforced(
+	__isl_take isl_basic_set *enforced, __isl_keep isl_ast_graft *graft,
+	int depth)
+{
+	isl_basic_set *enforced_g;
+
+	enforced_g = isl_ast_graft_get_enforced(graft);
+	if (depth < isl_basic_set_dim(enforced_g, isl_dim_set))
+		enforced_g = isl_basic_set_eliminate(enforced_g,
+							isl_dim_set, depth, 1);
+	enforced_g = isl_basic_set_remove_unknown_divs(enforced_g);
+	enforced_g = isl_basic_set_align_params(enforced_g,
+				isl_basic_set_get_space(enforced));
+	enforced = isl_basic_set_align_params(enforced,
+				isl_basic_set_get_space(enforced_g));
+	enforced = isl_set_simple_hull(isl_basic_set_union(enforced,
+						enforced_g));
+
+	return enforced;
+}
+
+/* Extend the node at *body with node.
+ *
+ * If body points to the else branch, then *body may still be NULL.
+ * If so, we simply attach node to this else branch.
+ * Otherwise, we attach a list containing the statements already
+ * attached at *body followed by node.
+ */
+static void extend_body(__isl_keep isl_ast_node **body,
+	__isl_take isl_ast_node *node)
+{
+	isl_ast_node_list *list;
+
+	if  (!*body) {
+		*body = node;
+		return;
+	}
+
+	if ((*body)->type == isl_ast_node_block) {
+		list = isl_ast_node_block_get_children(*body);
+		isl_ast_node_free(*body);
+	} else
+		list = isl_ast_node_list_from_ast_node(*body);
+	list = isl_ast_node_list_add(list, node);
+	*body = isl_ast_node_alloc_block(list);
+}
+
+/* Merge "graft" into the last graft of "list".
+ * body points to the then or else branch of an if node in that last graft.
+ *
+ * We attach graft->node to this branch and update the enforced
+ * set of the last graft of "list" to take into account the enforced
+ * set of "graft".
+ */
+static __isl_give isl_ast_graft_list *graft_extend_body(
+	__isl_take isl_ast_graft_list *list,
+	__isl_keep isl_ast_node **body, __isl_take isl_ast_graft *graft,
+	__isl_keep isl_ast_build *build)
+{
+	int n;
+	int depth;
+	isl_ast_graft *last;
+	isl_space *space;
+	isl_basic_set *enforced;
+
+	if (!list || !graft)
+		goto error;
+	extend_body(body, isl_ast_node_copy(graft->node));
+	if (!*body)
+		goto error;
+
+	n = isl_ast_graft_list_n_ast_graft(list);
+	last = isl_ast_graft_list_get_ast_graft(list, n - 1);
+
+	depth = isl_ast_build_get_depth(build);
+	space = isl_ast_build_get_space(build, 1);
+	enforced = isl_basic_set_empty(space);
+	enforced = update_enforced(enforced, last, depth);
+	enforced = update_enforced(enforced, graft, depth);
+	last = isl_ast_graft_set_enforced(last, enforced);
+
+	list = isl_ast_graft_list_set_ast_graft(list, n - 1, last);
+	isl_ast_graft_free(graft);
+	return list;
+error:
+	isl_ast_graft_free(graft);
+	return isl_ast_graft_list_free(list);
+}
+
+/* Merge "graft" into the last graft of "list", attaching graft->node
+ * to the then branch of "last_if".
+ */
+static __isl_give isl_ast_graft_list *extend_then(
+	__isl_take isl_ast_graft_list *list,
+	__isl_keep isl_ast_node *last_if, __isl_take isl_ast_graft *graft,
+	__isl_keep isl_ast_build *build)
+{
+	return graft_extend_body(list, &last_if->u.i.then, graft, build);
+}
+
+/* Merge "graft" into the last graft of "list", attaching graft->node
+ * to the else branch of "last_if".
+ */
+static __isl_give isl_ast_graft_list *extend_else(
+	__isl_take isl_ast_graft_list *list,
+	__isl_keep isl_ast_node *last_if, __isl_take isl_ast_graft *graft,
+	__isl_keep isl_ast_build *build)
+{
+	return graft_extend_body(list, &last_if->u.i.else_node, graft, build);
+}
+
+/* This data structure keeps track of an if node.
+ *
+ * "node" is the actual if-node
+ * "guard" is the original, non-simplified guard of the node
+ * "complement" is the complement of "guard" in the context of outer if nodes
+ */
+struct isl_if_node {
+	isl_ast_node *node;
+	isl_set *guard;
+	isl_set *complement;
+};
+
+/* Given a list of "n" if nodes, clear those starting at "first"
+ * and return "first" (i.e., the updated size of the array).
+ */
+static int clear_if_nodes(struct isl_if_node *if_node, int first, int n)
+{
+	int i;
+
+	for (i = first; i < n; ++i) {
+		isl_set_free(if_node[i].guard);
+		isl_set_free(if_node[i].complement);
+	}
+
+	return first;
+}
+
+/* For each graft in "list",
+ * insert an if node around graft->node testing the condition encoded
+ * in graft->guard, assuming graft->guard involves any conditions.
+ *
+ * We keep track of a list of generated if nodes that can be extended
+ * without changing the order of the elements in "list".
+ * If the guard of a graft is a subset of either the guard or its complement
+ * of one of those if nodes, then the node
+ * of the new graft is inserted into the then or else branch of the last graft
+ * and the current graft is discarded.
+ * The guard of the node is then simplified based on the conditions
+ * enforced at that then or else branch.
+ * Otherwise, the current graft is appended to the list.
+ *
+ * We only construct else branches if allowed by the user.
+ */
+static __isl_give isl_ast_graft_list *insert_pending_guard_nodes(
+	__isl_take isl_ast_graft_list *list,
+	__isl_keep isl_ast_build *build)
+{
+	int i, j, n, n_if;
+	int allow_else;
+	isl_ctx *ctx;
+	isl_ast_graft_list *res;
+	struct isl_if_node *if_node = NULL;
+
+	if (!build || !list)
+		return isl_ast_graft_list_free(list);
+
+	ctx = isl_ast_build_get_ctx(build);
+	n = isl_ast_graft_list_n_ast_graft(list);
+
+	allow_else = isl_options_get_ast_build_allow_else(ctx);
+
+	n_if = 0;
+	if (n > 1) {
+		if_node = isl_alloc_array(ctx, struct isl_if_node, n - 1);
+		if (!if_node)
+			return isl_ast_graft_list_free(list);
+	}
+
+	res = isl_ast_graft_list_alloc(ctx, n);
+
+	for (i = 0; i < n; ++i) {
+		isl_set *guard;
+		isl_ast_graft *graft;
+		int subset, found_then, found_else;
+		isl_ast_node *node;
+
+		graft = isl_ast_graft_list_get_ast_graft(list, i);
+		if (!graft)
+			break;
+		subset = 0;
+		found_then = found_else = -1;
+		if (n_if > 0) {
+			isl_set *test;
+			test = isl_set_copy(graft->guard);
+			test = isl_set_intersect(test,
+						isl_set_copy(build->domain));
+			for (j = n_if - 1; j >= 0; --j) {
+				subset = isl_set_is_subset(test,
+							if_node[j].guard);
+				if (subset < 0 || subset) {
+					found_then = j;
+					break;
+				}
+				if (!allow_else)
+					continue;
+				subset = isl_set_is_subset(test,
+							if_node[j].complement);
+				if (subset < 0 || subset) {
+					found_else = j;
+					break;
+				}
+			}
+			n_if = clear_if_nodes(if_node, j + 1, n_if);
+			isl_set_free(test);
+		}
+		if (subset < 0) {
+			graft = isl_ast_graft_free(graft);
+			break;
+		}
+
+		guard = isl_set_copy(graft->guard);
+		if (found_then >= 0)
+			graft->guard = isl_set_gist(graft->guard,
+				isl_set_copy(if_node[found_then].guard));
+		else if (found_else >= 0)
+			graft->guard = isl_set_gist(graft->guard,
+				isl_set_copy(if_node[found_else].complement));
+
+		node = graft->node;
+		if (!graft->guard)
+			graft = isl_ast_graft_free(graft);
+		graft = insert_pending_guard_node(graft, build);
+		if (graft && graft->node != node && i != n - 1) {
+			isl_set *set;
+			if_node[n_if].node = graft->node;
+			if_node[n_if].guard = guard;
+			if (found_then >= 0)
+				set = if_node[found_then].guard;
+			else if (found_else >= 0)
+				set = if_node[found_else].complement;
+			else
+				set = build->domain;
+			set = isl_set_copy(set);
+			set = isl_set_subtract(set, isl_set_copy(guard));
+			if_node[n_if].complement = set;
+			n_if++;
+		} else
+			isl_set_free(guard);
+		if (!graft)
+			break;
+
+		if (found_then >= 0)
+			res = extend_then(res, if_node[found_then].node,
+						graft, build);
+		else if (found_else >= 0)
+			res = extend_else(res, if_node[found_else].node,
+						graft, build);
+		else
+			res = isl_ast_graft_list_add(res, graft);
+	}
+	if (i < n)
+		res = isl_ast_graft_list_free(res);
+
+	isl_ast_graft_list_free(list);
+	clear_if_nodes(if_node, 0, n_if);
+	free(if_node);
+	return res;
+}
+
+/* For each graft in "list",
+ * insert an if node around graft->node testing the condition encoded
+ * in graft->guard, assuming graft->guard involves any conditions.
+ * Subsequently remove the guards from the grafts.
+ */
+__isl_give isl_ast_graft_list *isl_ast_graft_list_insert_pending_guard_nodes(
+	__isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build)
+{
+	int i, n;
+	isl_set *universe;
+
+	list = insert_pending_guard_nodes(list, build);
+	if (!list)
+		return NULL;
+
+	universe = isl_set_universe(isl_ast_build_get_space(build, 1));
+	n = isl_ast_graft_list_n_ast_graft(list);
+	for (i = 0; i < n; ++i) {
+		isl_ast_graft *graft;
+
+		graft = isl_ast_graft_list_get_ast_graft(list, i);
+		if (!graft)
+			break;
+		isl_set_free(graft->guard);
+		graft->guard = isl_set_copy(universe);
+		if (!graft->guard)
+			graft = isl_ast_graft_free(graft);
+		list = isl_ast_graft_list_set_ast_graft(list, i, graft);
+	}
+	isl_set_free(universe);
+	if (i < n)
+		return isl_ast_graft_list_free(list);
+
+	return list;
+}
+
+/* Collect the nodes contained in the grafts in "list" in a node list.
+ */
+static __isl_give isl_ast_node_list *extract_node_list(
+	__isl_keep isl_ast_graft_list *list)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_ast_node_list *node_list;
+
+	if (!list)
+		return NULL;
+	ctx = isl_ast_graft_list_get_ctx(list);
+	n = isl_ast_graft_list_n_ast_graft(list);
+	node_list = isl_ast_node_list_alloc(ctx, n);
+	for (i = 0; i < n; ++i) {
+		isl_ast_node *node;
+		isl_ast_graft *graft;
+
+		graft = isl_ast_graft_list_get_ast_graft(list, i);
+		node = isl_ast_graft_get_node(graft);
+		node_list = isl_ast_node_list_add(node_list, node);
+		isl_ast_graft_free(graft);
+	}
+
+	return node_list;
+}
+
+/* Look for shared enforced constraints by all the elements in "list"
+ * on outer loops (with respect to the current depth) and return the result.
+ *
+ * If there are no elements in "list", then return the empty set.
+ */
+__isl_give isl_basic_set *isl_ast_graft_list_extract_shared_enforced(
+	__isl_keep isl_ast_graft_list *list,
+	__isl_keep isl_ast_build *build)
+{
+	int i, n;
+	int depth;
+	isl_space *space;
+	isl_basic_set *enforced;
+
+	if (!list)
+		return NULL;
+
+	space = isl_ast_build_get_space(build, 1);
+	enforced = isl_basic_set_empty(space);
+
+	depth = isl_ast_build_get_depth(build);
+	n = isl_ast_graft_list_n_ast_graft(list);
+	for (i = 0; i < n; ++i) {
+		isl_ast_graft *graft;
+
+		graft = isl_ast_graft_list_get_ast_graft(list, i);
+		enforced = update_enforced(enforced, graft, depth);
+		isl_ast_graft_free(graft);
+	}
+
+	return enforced;
+}
+
+/* Record "guard" in "graft" so that it will be enforced somewhere
+ * up the tree.  If the graft already has a guard, then it may be partially
+ * redundant in combination with the new guard and in the context
+ * the generated constraints of "build".  In fact, the new guard
+ * may in itself have some redundant constraints.
+ * We therefore (re)compute the gist of the intersection
+ * and coalesce the result.
+ */
+static __isl_give isl_ast_graft *store_guard(__isl_take isl_ast_graft *graft,
+	__isl_take isl_set *guard, __isl_keep isl_ast_build *build)
+{
+	int is_universe;
+
+	if (!graft)
+		goto error;
+
+	is_universe = isl_set_plain_is_universe(guard);
+	if (is_universe < 0)
+		goto error;
+	if (is_universe) {
+		isl_set_free(guard);
+		return graft;
+	}
+
+	graft->guard = isl_set_intersect(graft->guard, guard);
+	graft->guard = isl_set_gist(graft->guard,
+				    isl_ast_build_get_generated(build));
+	graft->guard = isl_set_coalesce(graft->guard);
+	if (!graft->guard)
+		return isl_ast_graft_free(graft);
+
+	return graft;
+error:
+	isl_set_free(guard);
+	return isl_ast_graft_free(graft);
+}
+
+/* For each graft in "list", replace its guard with the gist with
+ * respect to "context".
+ */
+static __isl_give isl_ast_graft_list *gist_guards(
+	__isl_take isl_ast_graft_list *list, __isl_keep isl_set *context)
+{
+	int i, n;
+
+	if (!list)
+		return NULL;
+
+	n = isl_ast_graft_list_n_ast_graft(list);
+	for (i = 0; i < n; ++i) {
+		isl_ast_graft *graft;
+
+		graft = isl_ast_graft_list_get_ast_graft(list, i);
+		if (!graft)
+			break;
+		graft->guard = isl_set_gist(graft->guard,
+						isl_set_copy(context));
+		if (!graft->guard)
+			graft = isl_ast_graft_free(graft);
+		list = isl_ast_graft_list_set_ast_graft(list, i, graft);
+	}
+	if (i < n)
+		return isl_ast_graft_list_free(list);
+
+	return list;
+}
+
+/* For each graft in "list", replace its guard with the gist with
+ * respect to "context".
+ */
+__isl_give isl_ast_graft_list *isl_ast_graft_list_gist_guards(
+	__isl_take isl_ast_graft_list *list, __isl_take isl_set *context)
+{
+	list = gist_guards(list, context);
+	isl_set_free(context);
+
+	return list;
+}
+
+/* Allocate a graft in "build" based on the list of grafts in "sub_build".
+ * "guard" and "enforced" are the guard and enforced constraints
+ * of the allocated graft.  The guard is used to simplify the guards
+ * of the elements in "list".
+ *
+ * The node is initialized to either a block containing the nodes of "children"
+ * or, if there is only a single child, the node of that child.
+ * If the current level requires a for node, it should be inserted by
+ * a subsequent call to isl_ast_graft_insert_for.
+ */
+__isl_give isl_ast_graft *isl_ast_graft_alloc_from_children(
+	__isl_take isl_ast_graft_list *list, __isl_take isl_set *guard,
+	__isl_take isl_basic_set *enforced, __isl_keep isl_ast_build *build,
+	__isl_keep isl_ast_build *sub_build)
+{
+	isl_ast_build *guard_build;
+	isl_ast_node *node;
+	isl_ast_node_list *node_list;
+	isl_ast_graft *graft;
+
+	guard_build = isl_ast_build_copy(sub_build);
+	guard_build = isl_ast_build_replace_pending_by_guard(guard_build,
+						isl_set_copy(guard));
+	list = gist_guards(list, guard);
+	list = insert_pending_guard_nodes(list, guard_build);
+	isl_ast_build_free(guard_build);
+
+	node_list = extract_node_list(list);
+	node = isl_ast_node_from_ast_node_list(node_list);
+	isl_ast_graft_list_free(list);
+
+	graft = isl_ast_graft_alloc(node, build);
+	graft = store_guard(graft, guard, build);
+	graft = isl_ast_graft_enforce(graft, enforced);
+
+	return graft;
+}
+
+/* Combine the grafts in the list into a single graft.
+ *
+ * The guard is initialized to the shared guard of the list elements (if any),
+ * provided it does not depend on the current dimension.
+ * The guards in the elements are then simplified with respect to the
+ * hoisted guard and materialized as if nodes around the contained AST nodes
+ * in the context of "sub_build".
+ *
+ * The enforced set is initialized to the simple hull of the enforced sets
+ * of the elements, provided the ast_build_exploit_nested_bounds option is set
+ * or the new graft will be used at the same level.
+ *
+ * The node is initialized to either a block containing the nodes of "list"
+ * or, if there is only a single element, the node of that element.
+ */
+static __isl_give isl_ast_graft *ast_graft_list_fuse(
+	__isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build)
+{
+	isl_ast_graft *graft;
+	isl_basic_set *enforced;
+	isl_set *guard;
+
+	if (!list)
+		return NULL;
+
+	enforced = isl_ast_graft_list_extract_shared_enforced(list, build);
+	guard = isl_ast_graft_list_extract_hoistable_guard(list, build);
+	graft = isl_ast_graft_alloc_from_children(list, guard, enforced,
+						    build, build);
+
+	return graft;
+}
+
+/* Combine the grafts in the list into a single graft.
+ * Return a list containing this single graft.
+ * If the original list is empty, then return an empty list.
+ */
+__isl_give isl_ast_graft_list *isl_ast_graft_list_fuse(
+	__isl_take isl_ast_graft_list *list,
+	__isl_keep isl_ast_build *build)
+{
+	isl_ast_graft *graft;
+
+	if (!list)
+		return NULL;
+	if (isl_ast_graft_list_n_ast_graft(list) <= 1)
+		return list;
+	graft = ast_graft_list_fuse(list, build);
+	return isl_ast_graft_list_from_ast_graft(graft);
+}
+
+/* Combine the two grafts into a single graft.
+ * Return a list containing this single graft.
+ */
+static __isl_give isl_ast_graft *isl_ast_graft_fuse(
+	__isl_take isl_ast_graft *graft1, __isl_take isl_ast_graft *graft2,
+	__isl_keep isl_ast_build *build)
+{
+	isl_ctx *ctx;
+	isl_ast_graft_list *list;
+
+	ctx = isl_ast_build_get_ctx(build);
+
+	list = isl_ast_graft_list_alloc(ctx, 2);
+	list = isl_ast_graft_list_add(list, graft1);
+	list = isl_ast_graft_list_add(list, graft2);
+
+	return ast_graft_list_fuse(list, build);
+}
+
+/* Insert a for node enclosing the current graft->node.
+ */
+__isl_give isl_ast_graft *isl_ast_graft_insert_for(
+	__isl_take isl_ast_graft *graft, __isl_take isl_ast_node *node)
+{
+	if (!graft)
+		goto error;
+
+	graft->node = isl_ast_node_for_set_body(node, graft->node);
+	if (!graft->node)
+		return isl_ast_graft_free(graft);
+
+	return graft;
+error:
+	isl_ast_node_free(node);
+	isl_ast_graft_free(graft);
+	return NULL;
+}
+
+/* Insert a mark governing the current graft->node.
+ */
+__isl_give isl_ast_graft *isl_ast_graft_insert_mark(
+	__isl_take isl_ast_graft *graft, __isl_take isl_id *mark)
+{
+	if (!graft)
+		goto error;
+
+	graft->node = isl_ast_node_alloc_mark(mark, graft->node);
+	if (!graft->node)
+		return isl_ast_graft_free(graft);
+
+	return graft;
+error:
+	isl_id_free(mark);
+	isl_ast_graft_free(graft);
+	return NULL;
+}
+
+/* Represent the graft list as an AST node.
+ * This operation drops the information about guards in the grafts, so
+ * if there are any pending guards, then they are materialized as if nodes.
+ */
+__isl_give isl_ast_node *isl_ast_node_from_graft_list(
+	__isl_take isl_ast_graft_list *list,
+	__isl_keep isl_ast_build *build)
+{
+	isl_ast_node_list *node_list;
+
+	list = insert_pending_guard_nodes(list, build);
+	node_list = extract_node_list(list);
+	isl_ast_graft_list_free(list);
+
+	return isl_ast_node_from_ast_node_list(node_list);
+}
+
+void *isl_ast_graft_free(__isl_take isl_ast_graft *graft)
+{
+	if (!graft)
+		return NULL;
+
+	if (--graft->ref > 0)
+		return NULL;
+
+	isl_ast_node_free(graft->node);
+	isl_set_free(graft->guard);
+	isl_basic_set_free(graft->enforced);
+	free(graft);
+
+	return NULL;
+}
+
+/* Record that the grafted tree enforces
+ * "enforced" by intersecting graft->enforced with "enforced".
+ */
+__isl_give isl_ast_graft *isl_ast_graft_enforce(
+	__isl_take isl_ast_graft *graft, __isl_take isl_basic_set *enforced)
+{
+	if (!graft || !enforced)
+		goto error;
+
+	enforced = isl_basic_set_align_params(enforced,
+				isl_basic_set_get_space(graft->enforced));
+	graft->enforced = isl_basic_set_align_params(graft->enforced,
+				isl_basic_set_get_space(enforced));
+	graft->enforced = isl_basic_set_intersect(graft->enforced, enforced);
+	if (!graft->enforced)
+		return isl_ast_graft_free(graft);
+
+	return graft;
+error:
+	isl_basic_set_free(enforced);
+	return isl_ast_graft_free(graft);
+}
+
+__isl_give isl_basic_set *isl_ast_graft_get_enforced(
+	__isl_keep isl_ast_graft *graft)
+{
+	return graft ? isl_basic_set_copy(graft->enforced) : NULL;
+}
+
+__isl_give isl_set *isl_ast_graft_get_guard(__isl_keep isl_ast_graft *graft)
+{
+	return graft ? isl_set_copy(graft->guard) : NULL;
+}
+
+/* Record that "guard" needs to be inserted in "graft".
+ */
+__isl_give isl_ast_graft *isl_ast_graft_add_guard(
+	__isl_take isl_ast_graft *graft,
+	__isl_take isl_set *guard, __isl_keep isl_ast_build *build)
+{
+	return store_guard(graft, guard, build);
+}
+
+/* Reformulate the "graft", which was generated in the context
+ * of an inner code generation, in terms of the outer code generation
+ * AST build.
+ *
+ * If "product" is set, then the domain of the inner code generation build is
+ *
+ *	[O -> S]
+ *
+ * with O the domain of the outer code generation build.
+ * We essentially need to project out S.
+ *
+ * If "product" is not set, then we need to project the domains onto
+ * their parameter spaces.
+ */
+__isl_give isl_ast_graft *isl_ast_graft_unembed(__isl_take isl_ast_graft *graft,
+	int product)
+{
+	isl_basic_set *enforced;
+
+	if (!graft)
+		return NULL;
+
+	if (product) {
+		enforced = graft->enforced;
+		enforced = isl_basic_map_domain(isl_basic_set_unwrap(enforced));
+		graft->enforced = enforced;
+		graft->guard = isl_map_domain(isl_set_unwrap(graft->guard));
+	} else {
+		graft->enforced = isl_basic_set_params(graft->enforced);
+		graft->guard = isl_set_params(graft->guard);
+	}
+	graft->guard = isl_set_compute_divs(graft->guard);
+
+	if (!graft->enforced || !graft->guard)
+		return isl_ast_graft_free(graft);
+
+	return graft;
+}
+
+/* Reformulate the grafts in "list", which were generated in the context
+ * of an inner code generation, in terms of the outer code generation
+ * AST build.
+ */
+__isl_give isl_ast_graft_list *isl_ast_graft_list_unembed(
+	__isl_take isl_ast_graft_list *list, int product)
+{
+	int i, n;
+
+	n = isl_ast_graft_list_n_ast_graft(list);
+	for (i = 0; i < n; ++i) {
+		isl_ast_graft *graft;
+
+		graft = isl_ast_graft_list_get_ast_graft(list, i);
+		graft = isl_ast_graft_unembed(graft, product);
+		list = isl_ast_graft_list_set_ast_graft(list, i, graft);
+	}
+
+	return list;
+}
+
+/* Compute the preimage of "graft" under the function represented by "ma".
+ * In other words, plug in "ma" in "enforced" and "guard" fields of "graft".
+ */
+__isl_give isl_ast_graft *isl_ast_graft_preimage_multi_aff(
+	__isl_take isl_ast_graft *graft, __isl_take isl_multi_aff *ma)
+{
+	isl_basic_set *enforced;
+
+	if (!graft)
+		return NULL;
+
+	enforced = graft->enforced;
+	graft->enforced = isl_basic_set_preimage_multi_aff(enforced,
+						isl_multi_aff_copy(ma));
+	graft->guard = isl_set_preimage_multi_aff(graft->guard, ma);
+
+	if (!graft->enforced || !graft->guard)
+		return isl_ast_graft_free(graft);
+
+	return graft;
+}
+
+/* Compute the preimage of all the grafts in "list" under
+ * the function represented by "ma".
+ */
+__isl_give isl_ast_graft_list *isl_ast_graft_list_preimage_multi_aff(
+	__isl_take isl_ast_graft_list *list, __isl_take isl_multi_aff *ma)
+{
+	int i, n;
+
+	n = isl_ast_graft_list_n_ast_graft(list);
+	for (i = 0; i < n; ++i) {
+		isl_ast_graft *graft;
+
+		graft = isl_ast_graft_list_get_ast_graft(list, i);
+		graft = isl_ast_graft_preimage_multi_aff(graft,
+						    isl_multi_aff_copy(ma));
+		list = isl_ast_graft_list_set_ast_graft(list, i, graft);
+	}
+
+	isl_multi_aff_free(ma);
+	return list;
+}
+
+/* Compare two grafts based on their guards.
+ */
+static int cmp_graft(__isl_keep isl_ast_graft *a, __isl_keep isl_ast_graft *b,
+	void *user)
+{
+	return isl_set_plain_cmp(a->guard, b->guard);
+}
+
+/* Order the elements in "list" based on their guards.
+ */
+__isl_give isl_ast_graft_list *isl_ast_graft_list_sort_guard(
+	__isl_take isl_ast_graft_list *list)
+{
+	return isl_ast_graft_list_sort(list, &cmp_graft, NULL);
+}
+
+/* Merge the given two lists into a single list of grafts,
+ * merging grafts with the same guard into a single graft.
+ *
+ * "list2" has been sorted using isl_ast_graft_list_sort.
+ * "list1" may be the result of a previous call to isl_ast_graft_list_merge
+ * and may therefore not be completely sorted.
+ *
+ * The elements in "list2" need to be executed after those in "list1",
+ * but if the guard of a graft in "list2" is disjoint from the guards
+ * of some final elements in "list1", then it can be moved up to before
+ * those final elements.
+ *
+ * In particular, we look at each element g of "list2" in turn
+ * and move it up beyond elements of "list1" that would be sorted
+ * after g as long as each of these elements has a guard that is disjoint
+ * from that of g.
+ *
+ * We do not allow the second or any later element of "list2" to be moved
+ * before a previous elements of "list2" even if the reason that
+ * that element didn't move up further was that its guard was not disjoint
+ * from that of the previous element in "list1".
+ */
+__isl_give isl_ast_graft_list *isl_ast_graft_list_merge(
+	__isl_take isl_ast_graft_list *list1,
+	__isl_take isl_ast_graft_list *list2,
+	__isl_keep isl_ast_build *build)
+{
+	int i, j, first;
+
+	if (!list1 || !list2 || !build)
+		goto error;
+	if (list2->n == 0) {
+		isl_ast_graft_list_free(list2);
+		return list1;
+	}
+	if (list1->n == 0) {
+		isl_ast_graft_list_free(list1);
+		return list2;
+	}
+
+	first = 0;
+	for (i = 0; i < list2->n; ++i) {
+		isl_ast_graft *graft;
+		graft = isl_ast_graft_list_get_ast_graft(list2, i);
+		if (!graft)
+			break;
+
+		for (j = list1->n; j >= 0; --j) {
+			int cmp, disjoint;
+			isl_ast_graft *graft_j;
+
+			if (j == first)
+				cmp = -1;
+			else
+				cmp = isl_set_plain_cmp(list1->p[j - 1]->guard,
+							graft->guard);
+			if (cmp > 0) {
+				disjoint = isl_set_is_disjoint(graft->guard,
+							list1->p[j - 1]->guard);
+				if (disjoint < 0) {
+					list1 = isl_ast_graft_list_free(list1);
+					break;
+				}
+				if (!disjoint)
+					cmp = -1;
+			}
+			if (cmp > 0)
+				continue;
+			if (cmp < 0) {
+				list1 = isl_ast_graft_list_insert(list1, j,
+								graft);
+				break;
+			}
+
+			--j;
+
+			graft_j = isl_ast_graft_list_get_ast_graft(list1, j);
+			graft_j = isl_ast_graft_fuse(graft_j, graft, build);
+			list1 = isl_ast_graft_list_set_ast_graft(list1, j,
+								graft_j);
+			break;
+		}
+
+		if (j < 0)
+			isl_die(isl_ast_build_get_ctx(build),
+				isl_error_internal,
+				"element failed to get inserted", break);
+
+		first = j + 1;
+		if (!list1)
+			break;
+	}
+	if (i < list2->n)
+		list1 = isl_ast_graft_list_free(list1);
+	isl_ast_graft_list_free(list2);
+
+	return list1;
+error:
+	isl_ast_graft_list_free(list1);
+	isl_ast_graft_list_free(list2);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_ast_graft(__isl_take isl_printer *p,
+	__isl_keep isl_ast_graft *graft)
+{
+	if (!p)
+		return NULL;
+	if (!graft)
+		return isl_printer_free(p);
+
+	p = isl_printer_print_str(p, "(");
+	p = isl_printer_print_str(p, "guard: ");
+	p = isl_printer_print_set(p, graft->guard);
+	p = isl_printer_print_str(p, ", ");
+	p = isl_printer_print_str(p, "enforced: ");
+	p = isl_printer_print_basic_set(p, graft->enforced);
+	p = isl_printer_print_str(p, ", ");
+	p = isl_printer_print_str(p, "node: ");
+	p = isl_printer_print_ast_node(p, graft->node);
+	p = isl_printer_print_str(p, ")");
+
+	return p;
+}
diff --git a/final/lib/External/isl/isl_ast_graft_private.h b/final/lib/External/isl/isl_ast_graft_private.h
new file mode 100644
index 0000000..400b9a8
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_graft_private.h
@@ -0,0 +1,102 @@
+#ifndef ISL_AST_GRAFT_PRIVATE_H
+#define ISL_AST_GRAFT_PRIVATE_H
+
+#include <isl/ast.h>
+#include <isl/set.h>
+#include <isl/list.h>
+#include <isl/printer.h>
+
+struct isl_ast_graft;
+typedef struct isl_ast_graft isl_ast_graft;
+
+/* Representation of part of an AST ("node") with some additional polyhedral
+ * information about the tree.
+ *
+ * "guard" contains conditions that should still be enforced by
+ * some ancestor of the current tree.  In particular, the already
+ * generated tree assumes that these conditions hold, but may not
+ * have enforced them itself.
+ * The guard should not contain any unknown divs as it will be used
+ * to generate an if condition.
+ *
+ * "enforced" expresses constraints that are already enforced by the for
+ * nodes in the current tree and that therefore do not need to be enforced
+ * by any ancestor.
+ * The constraints only involve outer loop iterators.
+ */
+struct isl_ast_graft {
+	int ref;
+
+	isl_ast_node *node;
+
+	isl_set *guard;
+	isl_basic_set *enforced;
+};
+
+ISL_DECLARE_LIST(ast_graft)
+
+#undef EL
+#define EL isl_ast_graft
+
+#include <isl_list_templ.h>
+
+isl_ctx *isl_ast_graft_get_ctx(__isl_keep isl_ast_graft *graft);
+
+__isl_give isl_ast_graft *isl_ast_graft_alloc(
+	__isl_take isl_ast_node *node, __isl_keep isl_ast_build *build);
+__isl_give isl_ast_graft *isl_ast_graft_alloc_from_children(
+	__isl_take isl_ast_graft_list *list, __isl_take isl_set *guard,
+	__isl_take isl_basic_set *enforced, __isl_keep isl_ast_build *build,
+	__isl_keep isl_ast_build *sub_build);
+__isl_give isl_ast_graft_list *isl_ast_graft_list_fuse(
+	__isl_take isl_ast_graft_list *children,
+	__isl_keep isl_ast_build *build);
+__isl_give isl_ast_graft *isl_ast_graft_alloc_domain(
+	__isl_take isl_map *schedule, __isl_keep isl_ast_build *build);
+void *isl_ast_graft_free(__isl_take isl_ast_graft *graft);
+__isl_give isl_ast_graft_list *isl_ast_graft_list_sort_guard(
+	__isl_take isl_ast_graft_list *list);
+
+__isl_give isl_ast_graft_list *isl_ast_graft_list_merge(
+	__isl_take isl_ast_graft_list *list1,
+	__isl_take isl_ast_graft_list *list2,
+	__isl_keep isl_ast_build *build);
+
+__isl_give isl_ast_node *isl_ast_graft_get_node(
+	__isl_keep isl_ast_graft *graft);
+__isl_give isl_basic_set *isl_ast_graft_get_enforced(
+	__isl_keep isl_ast_graft *graft);
+__isl_give isl_set *isl_ast_graft_get_guard(__isl_keep isl_ast_graft *graft);
+
+__isl_give isl_ast_graft *isl_ast_graft_insert_for(
+	__isl_take isl_ast_graft *graft, __isl_take isl_ast_node *node);
+__isl_give isl_ast_graft *isl_ast_graft_add_guard(
+	__isl_take isl_ast_graft *graft,
+	__isl_take isl_set *guard, __isl_keep isl_ast_build *build);
+__isl_give isl_ast_graft *isl_ast_graft_enforce(
+	__isl_take isl_ast_graft *graft, __isl_take isl_basic_set *enforced);
+
+__isl_give isl_ast_graft *isl_ast_graft_insert_mark(
+	__isl_take isl_ast_graft *graft, __isl_take isl_id *mark);
+
+__isl_give isl_ast_graft_list *isl_ast_graft_list_unembed(
+	__isl_take isl_ast_graft_list *list, int product);
+__isl_give isl_ast_graft_list *isl_ast_graft_list_preimage_multi_aff(
+	__isl_take isl_ast_graft_list *list, __isl_take isl_multi_aff *ma);
+__isl_give isl_ast_graft_list *isl_ast_graft_list_insert_pending_guard_nodes(
+	__isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build);
+
+__isl_give isl_ast_node *isl_ast_node_from_graft_list(
+	__isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build);
+
+__isl_give isl_basic_set *isl_ast_graft_list_extract_shared_enforced(
+	__isl_keep isl_ast_graft_list *list, __isl_keep isl_ast_build *build);
+__isl_give isl_set *isl_ast_graft_list_extract_hoistable_guard(
+	__isl_keep isl_ast_graft_list *list, __isl_keep isl_ast_build *build);
+__isl_give isl_ast_graft_list *isl_ast_graft_list_gist_guards(
+	__isl_take isl_ast_graft_list *list, __isl_take isl_set *context);
+
+__isl_give isl_printer *isl_printer_print_ast_graft(__isl_take isl_printer *p,
+	__isl_keep isl_ast_graft *graft);
+
+#endif
diff --git a/final/lib/External/isl/isl_ast_int.c b/final/lib/External/isl/isl_ast_int.c
new file mode 100644
index 0000000..178c38c
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_int.c
@@ -0,0 +1,13 @@
+#include <isl/deprecated/ast_int.h>
+#include <isl/deprecated/val_int.h>
+#include <isl_ast_private.h>
+
+int isl_ast_expr_get_int(__isl_keep isl_ast_expr *expr, isl_int *v)
+{
+	if (!expr)
+		return -1;
+	if (expr->type != isl_ast_expr_int)
+		isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid,
+			"expression not an int", return -1);
+	return isl_val_get_num_isl_int(expr->u.v, v);
+}
diff --git a/final/lib/External/isl/isl_ast_private.h b/final/lib/External/isl/isl_ast_private.h
new file mode 100644
index 0000000..9470019
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_private.h
@@ -0,0 +1,121 @@
+#ifndef ISL_AST_PRIVATE_H
+#define ISL_AST_PRIVATE_H
+
+#include <isl/aff.h>
+#include <isl/ast.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/vec.h>
+#include <isl/list.h>
+
+/* An expression is either an integer, an identifier or an operation
+ * with zero or more arguments.
+ */
+struct isl_ast_expr {
+	int ref;
+
+	isl_ctx *ctx;
+
+	enum isl_ast_expr_type type;
+
+	union {
+		isl_val *v;
+		isl_id *id;
+		struct {
+			enum isl_ast_op_type op;
+			unsigned n_arg;
+			isl_ast_expr **args;
+		} op;
+	} u;
+};
+
+#undef EL
+#define EL isl_ast_expr
+
+#include <isl_list_templ.h>
+
+__isl_give isl_ast_expr *isl_ast_expr_alloc_int_si(isl_ctx *ctx, int i);
+__isl_give isl_ast_expr *isl_ast_expr_alloc_op(isl_ctx *ctx,
+	enum isl_ast_op_type op, int n_arg);
+__isl_give isl_ast_expr *isl_ast_expr_alloc_binary(enum isl_ast_op_type type,
+	__isl_take isl_ast_expr *expr1, __isl_take isl_ast_expr *expr2);
+
+#undef EL
+#define EL isl_ast_node
+
+#include <isl_list_templ.h>
+
+/* A node is either a block, an if, a for, a user node or a mark node.
+ * "else_node" is NULL if the if node does not have an else branch.
+ * "cond" and "inc" are NULL for degenerate for nodes.
+ * In case of a mark node, "mark" is the mark and "node" is the marked node.
+ */
+struct isl_ast_node {
+	int ref;
+
+	isl_ctx *ctx;
+	enum isl_ast_node_type type;
+
+	union {
+		struct {
+			isl_ast_node_list *children;
+		} b;
+		struct {
+			isl_ast_expr *guard;
+			isl_ast_node *then;
+			isl_ast_node *else_node;
+		} i;
+		struct {
+			unsigned degenerate : 1;
+			isl_ast_expr *iterator;
+			isl_ast_expr *init;
+			isl_ast_expr *cond;
+			isl_ast_expr *inc;
+			isl_ast_node *body;
+		} f;
+		struct {
+			isl_ast_expr *expr;
+		} e;
+		struct {
+			isl_id *mark;
+			isl_ast_node *node;
+		} m;
+	} u;
+
+	isl_id *annotation;
+};
+
+__isl_give isl_ast_node *isl_ast_node_alloc_for(__isl_take isl_id *id);
+__isl_give isl_ast_node *isl_ast_node_for_mark_degenerate(
+	__isl_take isl_ast_node *node);
+__isl_give isl_ast_node *isl_ast_node_alloc_if(__isl_take isl_ast_expr *guard);
+__isl_give isl_ast_node *isl_ast_node_alloc_block(
+	__isl_take isl_ast_node_list *list);
+__isl_give isl_ast_node *isl_ast_node_alloc_mark(__isl_take isl_id *id,
+	__isl_take isl_ast_node *node);
+__isl_give isl_ast_node *isl_ast_node_from_ast_node_list(
+	__isl_take isl_ast_node_list *list);
+__isl_give isl_ast_node *isl_ast_node_for_set_body(
+	__isl_take isl_ast_node *node, __isl_take isl_ast_node *body);
+__isl_give isl_ast_node *isl_ast_node_if_set_then(
+	__isl_take isl_ast_node *node, __isl_take isl_ast_node *child);
+
+struct isl_ast_print_options {
+	int ref;
+	isl_ctx *ctx;
+
+	__isl_give isl_printer *(*print_for)(__isl_take isl_printer *p,
+		__isl_take isl_ast_print_options *options,
+		__isl_keep isl_ast_node *node, void *user);
+	void *print_for_user;
+	__isl_give isl_printer *(*print_user)(__isl_take isl_printer *p,
+		__isl_take isl_ast_print_options *options,
+		__isl_keep isl_ast_node *node, void *user);
+	void *print_user_user;
+};
+
+__isl_give isl_printer *isl_ast_node_list_print(
+	__isl_keep isl_ast_node_list *list, __isl_take isl_printer *p,
+	__isl_keep isl_ast_print_options *options);
+
+#endif
diff --git a/final/lib/External/isl/isl_band.c b/final/lib/External/isl/isl_band.c
new file mode 100644
index 0000000..43569d6
--- /dev/null
+++ b/final/lib/External/isl/isl_band.c
@@ -0,0 +1,727 @@
+/*
+ * Copyright 2011      INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_band_private.h>
+#include <isl_schedule_private.h>
+
+#undef BASE
+#define BASE band
+
+#include <isl_list_templ.c>
+
+isl_ctx *isl_band_get_ctx(__isl_keep isl_band *band)
+{
+	return band ? isl_union_pw_multi_aff_get_ctx(band->pma) : NULL;
+}
+
+__isl_give isl_band *isl_band_alloc(isl_ctx *ctx)
+{
+	isl_band *band;
+
+	band = isl_calloc_type(ctx, isl_band);
+	if (!band)
+		return NULL;
+
+	band->ref = 1;
+
+	return band;
+}
+
+/* Create a duplicate of the given band.  The duplicate refers
+ * to the same schedule and parent as the input, but does not
+ * increment their reference counts.
+ */
+__isl_give isl_band *isl_band_dup(__isl_keep isl_band *band)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_band *dup;
+
+	if (!band)
+		return NULL;
+
+	ctx = isl_band_get_ctx(band);
+	dup = isl_band_alloc(ctx);
+	if (!dup)
+		return NULL;
+
+	dup->n = band->n;
+	dup->coincident = isl_alloc_array(ctx, int, band->n);
+	if (band->n && !dup->coincident)
+		goto error;
+
+	for (i = 0; i < band->n; ++i)
+		dup->coincident[i] = band->coincident[i];
+
+	dup->pma = isl_union_pw_multi_aff_copy(band->pma);
+	dup->schedule = band->schedule;
+	dup->parent = band->parent;
+
+	if (!dup->pma)
+		goto error;
+
+	return dup;
+error:
+	isl_band_free(dup);
+	return NULL;
+}
+
+/* We not only increment the reference count of the band,
+ * but also that of the schedule that contains this band.
+ * This ensures that the schedule won't disappear while there
+ * is still a reference to the band outside of the schedule.
+ * There is no need to increment the reference count of the parent
+ * band as the parent band is part of the same schedule.
+ */
+__isl_give isl_band *isl_band_copy(__isl_keep isl_band *band)
+{
+	if (!band)
+		return NULL;
+
+	band->ref++;
+	band->schedule->ref++;
+	return band;
+}
+
+/* If this is not the last reference to the band (the one from within the
+ * schedule), then we also need to decrement the reference count of the
+ * containing schedule as it was incremented in isl_band_copy.
+ */
+__isl_null isl_band *isl_band_free(__isl_take isl_band *band)
+{
+	if (!band)
+		return NULL;
+
+	if (--band->ref > 0) {
+		isl_schedule_free(band->schedule);
+		return NULL;
+	}
+
+	isl_union_pw_multi_aff_free(band->pma);
+	isl_band_list_free(band->children);
+	free(band->coincident);
+	free(band);
+
+	return NULL;
+}
+
+int isl_band_has_children(__isl_keep isl_band *band)
+{
+	if (!band)
+		return -1;
+
+	return band->children != NULL;
+}
+
+__isl_give isl_band_list *isl_band_get_children(
+	__isl_keep isl_band *band)
+{
+	if (!band)
+		return NULL;
+	if (!band->children)
+		isl_die(isl_band_get_ctx(band), isl_error_invalid,
+			"band has no children", return NULL);
+	return isl_band_list_dup(band->children);
+}
+
+int isl_band_n_member(__isl_keep isl_band *band)
+{
+	return band ? band->n : 0;
+}
+
+/* Is the given scheduling dimension coincident within the band and
+ * with respect to the coincidence constraints.
+ */
+int isl_band_member_is_coincident(__isl_keep isl_band *band, int pos)
+{
+	if (!band)
+		return -1;
+
+	if (pos < 0 || pos >= band->n)
+		isl_die(isl_band_get_ctx(band), isl_error_invalid,
+			"invalid member position", return -1);
+
+	return band->coincident[pos];
+}
+
+/* Return the schedule that leads up to this band.
+ */
+__isl_give isl_union_map *isl_band_get_prefix_schedule(
+	__isl_keep isl_band *band)
+{
+	isl_union_set *domain;
+	isl_union_pw_multi_aff *prefix;
+	isl_band *a;
+
+	if (!band)
+		return NULL;
+
+	prefix = isl_union_pw_multi_aff_copy(band->pma);
+	domain = isl_union_pw_multi_aff_domain(prefix);
+	prefix = isl_union_pw_multi_aff_from_domain(domain);
+
+	for (a = band->parent; a; a = a->parent) {
+		isl_union_pw_multi_aff *partial;
+
+		partial = isl_union_pw_multi_aff_copy(a->pma);
+		prefix = isl_union_pw_multi_aff_flat_range_product(partial,
+								   prefix);
+	}
+
+	return isl_union_map_from_union_pw_multi_aff(prefix);
+}
+
+/* Return the schedule of the band in isolation.
+ */
+__isl_give isl_union_pw_multi_aff *
+isl_band_get_partial_schedule_union_pw_multi_aff(__isl_keep isl_band *band)
+{
+	return band ? isl_union_pw_multi_aff_copy(band->pma) : NULL;
+}
+
+/* Return the schedule of the band in isolation.
+ */
+__isl_give isl_union_map *isl_band_get_partial_schedule(
+	__isl_keep isl_band *band)
+{
+	isl_union_pw_multi_aff *sched;
+
+	sched = isl_band_get_partial_schedule_union_pw_multi_aff(band);
+	return isl_union_map_from_union_pw_multi_aff(sched);
+}
+
+__isl_give isl_union_pw_multi_aff *
+isl_band_get_suffix_schedule_union_pw_multi_aff(__isl_keep isl_band *band);
+
+/* Return the schedule for the given band list.
+ * For each band in the list, the schedule is composed of the partial
+ * and suffix schedules of that band.
+ */
+__isl_give isl_union_pw_multi_aff *
+isl_band_list_get_suffix_schedule_union_pw_multi_aff(
+	__isl_keep isl_band_list *list)
+{
+	isl_ctx *ctx;
+	int i, n;
+	isl_space *space;
+	isl_union_pw_multi_aff *suffix;
+
+	if (!list)
+		return NULL;
+
+	ctx = isl_band_list_get_ctx(list);
+	space = isl_space_alloc(ctx, 0, 0, 0);
+	suffix = isl_union_pw_multi_aff_empty(space);
+	n = isl_band_list_n_band(list);
+	for (i = 0; i < n; ++i) {
+		isl_band *el;
+		isl_union_pw_multi_aff *partial;
+		isl_union_pw_multi_aff *suffix_i;
+
+		el = isl_band_list_get_band(list, i);
+		partial = isl_band_get_partial_schedule_union_pw_multi_aff(el);
+		suffix_i = isl_band_get_suffix_schedule_union_pw_multi_aff(el);
+		suffix_i = isl_union_pw_multi_aff_flat_range_product(
+				partial, suffix_i);
+		suffix = isl_union_pw_multi_aff_union_add(suffix, suffix_i);
+
+		isl_band_free(el);
+	}
+
+	return suffix;
+}
+
+/* Return the schedule for the given band list.
+ * For each band in the list, the schedule is composed of the partial
+ * and suffix schedules of that band.
+ */
+__isl_give isl_union_map *isl_band_list_get_suffix_schedule(
+	__isl_keep isl_band_list *list)
+{
+	isl_union_pw_multi_aff *suffix;
+
+	suffix = isl_band_list_get_suffix_schedule_union_pw_multi_aff(list);
+	return isl_union_map_from_union_pw_multi_aff(suffix);
+}
+
+/* Return the schedule for the forest underneath the given band.
+ */
+__isl_give isl_union_pw_multi_aff *
+isl_band_get_suffix_schedule_union_pw_multi_aff(__isl_keep isl_band *band)
+{
+	isl_union_pw_multi_aff *suffix;
+
+	if (!band)
+		return NULL;
+
+	if (!isl_band_has_children(band)) {
+		isl_union_set *domain;
+
+		suffix = isl_union_pw_multi_aff_copy(band->pma);
+		domain = isl_union_pw_multi_aff_domain(suffix);
+		suffix = isl_union_pw_multi_aff_from_domain(domain);
+	} else {
+		isl_band_list *list;
+
+		list = isl_band_get_children(band);
+		suffix =
+		    isl_band_list_get_suffix_schedule_union_pw_multi_aff(list);
+		isl_band_list_free(list);
+	}
+
+	return suffix;
+}
+
+/* Return the schedule for the forest underneath the given band.
+ */
+__isl_give isl_union_map *isl_band_get_suffix_schedule(
+	__isl_keep isl_band *band)
+{
+	isl_union_pw_multi_aff *suffix;
+
+	suffix = isl_band_get_suffix_schedule_union_pw_multi_aff(band);
+	return isl_union_map_from_union_pw_multi_aff(suffix);
+}
+
+/* Call "fn" on each band (recursively) in the list
+ * in depth-first post-order.
+ */
+int isl_band_list_foreach_band(__isl_keep isl_band_list *list,
+	int (*fn)(__isl_keep isl_band *band, void *user), void *user)
+{
+	int i, n;
+
+	if (!list)
+		return -1;
+
+	n = isl_band_list_n_band(list);
+	for (i = 0; i < n; ++i) {
+		isl_band *band;
+		int r = 0;
+
+		band = isl_band_list_get_band(list, i);
+		if (isl_band_has_children(band)) {
+			isl_band_list *children;
+
+			children = isl_band_get_children(band);
+			r = isl_band_list_foreach_band(children, fn, user);
+			isl_band_list_free(children);
+		}
+
+		if (!band)
+			r = -1;
+		if (r == 0)
+			r = fn(band, user);
+
+		isl_band_free(band);
+		if (r)
+			return r;
+	}
+
+	return 0;
+}
+
+/* Internal data used during the construction of the schedule
+ * for the tile loops.
+ *
+ * sizes contains the tile sizes
+ * scale is set if the tile loops should be scaled
+ * tiled collects the result for a single statement
+ * res collects the result for all statements
+ */
+struct isl_band_tile_data {
+	isl_multi_val *sizes;
+	isl_union_pw_multi_aff *res;
+	isl_pw_multi_aff *tiled;
+	int scale;
+};
+
+/* Given part of the schedule of a band, construct the corresponding
+ * schedule for the tile loops based on the tile sizes in data->sizes
+ * and add the result to data->tiled.
+ *
+ * If data->scale is set, then dimension i of the schedule will be
+ * of the form
+ *
+ *	m_i * floor(s_i(x) / m_i)
+ *
+ * where s_i(x) refers to the original schedule and m_i is the tile size.
+ * If data->scale is not set, then dimension i of the schedule will be
+ * of the form
+ *
+ *	floor(s_i(x) / m_i)
+ *
+ */
+static isl_stat multi_aff_tile(__isl_take isl_set *set,
+	__isl_take isl_multi_aff *ma, void *user)
+{
+	struct isl_band_tile_data *data = user;
+	isl_pw_multi_aff *pma;
+	int i, n;
+	isl_val *v;
+
+	n = isl_multi_aff_dim(ma, isl_dim_out);
+
+	for (i = 0; i < n; ++i) {
+		isl_aff *aff;
+
+		aff = isl_multi_aff_get_aff(ma, i);
+		v = isl_multi_val_get_val(data->sizes, i);
+
+		aff = isl_aff_scale_down_val(aff, isl_val_copy(v));
+		aff = isl_aff_floor(aff);
+		if (data->scale)
+			aff = isl_aff_scale_val(aff, isl_val_copy(v));
+		isl_val_free(v);
+
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+
+	pma = isl_pw_multi_aff_alloc(set, ma);
+	data->tiled = isl_pw_multi_aff_union_add(data->tiled, pma);
+
+	return isl_stat_ok;
+}
+
+/* Given part of the schedule of a band, construct the corresponding
+ * schedule for the tile loops based on the tile sizes in data->sizes
+ * and add the result to data->res.
+ */
+static isl_stat pw_multi_aff_tile(__isl_take isl_pw_multi_aff *pma, void *user)
+{
+	struct isl_band_tile_data *data = user;
+
+	data->tiled = isl_pw_multi_aff_empty(isl_pw_multi_aff_get_space(pma));
+
+	if (isl_pw_multi_aff_foreach_piece(pma, &multi_aff_tile, data) < 0)
+		goto error;
+
+	isl_pw_multi_aff_free(pma);
+	data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res,
+								data->tiled);
+
+	return isl_stat_ok;
+error:
+	isl_pw_multi_aff_free(pma);
+	isl_pw_multi_aff_free(data->tiled);
+	return isl_stat_error;
+}
+
+/* Given the schedule of a band, construct the corresponding
+ * schedule for the tile loops based on the given tile sizes
+ * and return the result.
+ */
+static isl_union_pw_multi_aff *isl_union_pw_multi_aff_tile(
+	__isl_take isl_union_pw_multi_aff *sched,
+	__isl_keep isl_multi_val *sizes)
+{
+	isl_ctx *ctx;
+	isl_space *space;
+	struct isl_band_tile_data data = { sizes };
+
+	ctx = isl_multi_val_get_ctx(sizes);
+
+	space = isl_union_pw_multi_aff_get_space(sched);
+	data.res = isl_union_pw_multi_aff_empty(space);
+	data.scale = isl_options_get_tile_scale_tile_loops(ctx);
+
+	if (isl_union_pw_multi_aff_foreach_pw_multi_aff(sched,
+						&pw_multi_aff_tile, &data) < 0)
+		goto error;
+
+	isl_union_pw_multi_aff_free(sched);
+	return data.res;
+error:
+	isl_union_pw_multi_aff_free(sched);
+	isl_union_pw_multi_aff_free(data.res);
+	return NULL;
+}
+
+/* Extract the range space from "pma" and store it in *user.
+ * All entries are expected to have the same range space, so we can
+ * stop after extracting the range space from the first entry.
+ */
+static isl_stat extract_range_space(__isl_take isl_pw_multi_aff *pma,
+	void *user)
+{
+	isl_space **space = user;
+
+	*space = isl_space_range(isl_pw_multi_aff_get_space(pma));
+	isl_pw_multi_aff_free(pma);
+
+	return isl_stat_error;
+}
+
+/* Extract the range space of "band".  All entries in band->pma should
+ * have the same range space.  Furthermore, band->pma should have at least
+ * one entry.
+ */
+static __isl_give isl_space *band_get_range_space(__isl_keep isl_band *band)
+{
+	isl_space *space;
+
+	if (!band)
+		return NULL;
+
+	space = NULL;
+	isl_union_pw_multi_aff_foreach_pw_multi_aff(band->pma,
+						&extract_range_space, &space);
+
+	return space;
+}
+
+/* Construct and return an isl_multi_val in the given space, with as entries
+ * the first elements of "v", padded with ones if the size of "v" is smaller
+ * than the dimension of "space".
+ */
+static __isl_give isl_multi_val *multi_val_from_vec(__isl_take isl_space *space,
+	__isl_take isl_vec *v)
+{
+	isl_ctx *ctx;
+	isl_multi_val *mv;
+	int i, n, size;
+
+	if (!space || !v)
+		goto error;
+
+	ctx = isl_space_get_ctx(space);
+	mv = isl_multi_val_zero(space);
+	n = isl_multi_val_dim(mv, isl_dim_set);
+	size = isl_vec_size(v);
+	if (n < size)
+		size = n;
+
+	for (i = 0; i < size; ++i) {
+		isl_val *val = isl_vec_get_element_val(v, i);
+		mv = isl_multi_val_set_val(mv, i, val);
+	}
+	for (i = size; i < n; ++i)
+		mv = isl_multi_val_set_val(mv, i, isl_val_one(ctx));
+
+	isl_vec_free(v);
+	return mv;
+error:
+	isl_space_free(space);
+	isl_vec_free(v);
+	return NULL;
+}
+
+/* Tile the given band using the specified tile sizes.
+ * The given band is modified to refer to the tile loops and
+ * a child band is created to refer to the point loops.
+ * The children of this point loop band are the children
+ * of the original band.
+ *
+ * If the scale tile loops option is set, then the tile loops
+ * are scaled by the tile sizes.  If the shift point loops option is set,
+ * then the point loops are shifted to start at zero.
+ * In particular, these options affect the tile and point loop schedules
+ * as follows
+ *
+ *	scale	shift	original	tile		point
+ *
+ *	0	0	i		floor(i/s)	i
+ *	1	0	i		s * floor(i/s)	i
+ *	0	1	i		floor(i/s)	i - s * floor(i/s)
+ *	1	1	i		s * floor(i/s)	i - s * floor(i/s)
+ */
+int isl_band_tile(__isl_keep isl_band *band, __isl_take isl_vec *sizes)
+{
+	isl_ctx *ctx;
+	isl_band *child;
+	isl_band_list *list = NULL;
+	isl_union_pw_multi_aff *sched = NULL, *child_sched = NULL;
+	isl_space *space;
+	isl_multi_val *mv_sizes;
+
+	if (!band || !sizes)
+		goto error;
+
+	ctx = isl_vec_get_ctx(sizes);
+	child = isl_band_dup(band);
+	list = isl_band_list_alloc(ctx, 1);
+	list = isl_band_list_add(list, child);
+	if (!list)
+		goto error;
+
+	space = band_get_range_space(band);
+	mv_sizes = multi_val_from_vec(space, isl_vec_copy(sizes));
+	sched = isl_union_pw_multi_aff_copy(band->pma);
+	sched = isl_union_pw_multi_aff_tile(sched, mv_sizes);
+
+	child_sched = isl_union_pw_multi_aff_copy(child->pma);
+	if (isl_options_get_tile_shift_point_loops(ctx)) {
+		isl_union_pw_multi_aff *scaled;
+		scaled = isl_union_pw_multi_aff_copy(sched);
+		if (!isl_options_get_tile_scale_tile_loops(ctx))
+			scaled = isl_union_pw_multi_aff_scale_multi_val(scaled,
+						isl_multi_val_copy(mv_sizes));
+		child_sched = isl_union_pw_multi_aff_sub(child_sched, scaled);
+	}
+	isl_multi_val_free(mv_sizes);
+	if (!sched || !child_sched)
+		goto error;
+
+	child->children = band->children;
+	band->children = list;
+	child->parent = band;
+	isl_union_pw_multi_aff_free(band->pma);
+	band->pma = sched;
+	isl_union_pw_multi_aff_free(child->pma);
+	child->pma = child_sched;
+
+	isl_vec_free(sizes);
+	return 0;
+error:
+	isl_union_pw_multi_aff_free(sched);
+	isl_union_pw_multi_aff_free(child_sched);
+	isl_band_list_free(list);
+	isl_vec_free(sizes);
+	return -1;
+}
+
+/* Internal data structure used inside isl_union_pw_multi_aff_drop.
+ *
+ * "pos" is the position of the first dimension to drop.
+ * "n" is the number of dimensions to drop.
+ * "res" accumulates the result.
+ */
+struct isl_union_pw_multi_aff_drop_data {
+	int pos;
+	int n;
+	isl_union_pw_multi_aff *res;
+};
+
+/* Drop the data->n output dimensions starting at data->pos from "pma"
+ * and add the result to data->res.
+ */
+static isl_stat pw_multi_aff_drop(__isl_take isl_pw_multi_aff *pma, void *user)
+{
+	struct isl_union_pw_multi_aff_drop_data *data = user;
+
+	pma = isl_pw_multi_aff_drop_dims(pma, isl_dim_out, data->pos, data->n);
+
+	data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma);
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Drop the "n" output dimensions starting at "pos" from "sched".
+ */
+static isl_union_pw_multi_aff *isl_union_pw_multi_aff_drop(
+	__isl_take isl_union_pw_multi_aff *sched, int pos, int n)
+{
+	isl_space *space;
+	struct isl_union_pw_multi_aff_drop_data data = { pos, n };
+
+	space = isl_union_pw_multi_aff_get_space(sched);
+	data.res = isl_union_pw_multi_aff_empty(space);
+
+	if (isl_union_pw_multi_aff_foreach_pw_multi_aff(sched,
+						&pw_multi_aff_drop, &data) < 0)
+		data.res = isl_union_pw_multi_aff_free(data.res);
+
+	isl_union_pw_multi_aff_free(sched);
+	return data.res;
+}
+
+/* Drop the "n" dimensions starting at "pos" from "band".
+ */
+static int isl_band_drop(__isl_keep isl_band *band, int pos, int n)
+{
+	int i;
+	isl_union_pw_multi_aff *sched;
+
+	if (!band)
+		return -1;
+	if (n == 0)
+		return 0;
+
+	sched = isl_union_pw_multi_aff_copy(band->pma);
+	sched = isl_union_pw_multi_aff_drop(sched, pos, n);
+	if (!sched)
+		return -1;
+
+	isl_union_pw_multi_aff_free(band->pma);
+	band->pma = sched;
+
+	for (i = pos + n; i < band->n; ++i)
+		band->coincident[i - n] = band->coincident[i];
+
+	band->n -= n;
+
+	return 0;
+}
+
+/* Split the given band into two nested bands, one with the first "pos"
+ * dimensions of "band" and one with the remaining band->n - pos dimensions.
+ */
+int isl_band_split(__isl_keep isl_band *band, int pos)
+{
+	isl_ctx *ctx;
+	isl_band *child;
+	isl_band_list *list;
+
+	if (!band)
+		return -1;
+
+	ctx = isl_band_get_ctx(band);
+
+	if (pos < 0 || pos > band->n)
+		isl_die(ctx, isl_error_invalid, "position out of bounds",
+			return -1);
+
+	child = isl_band_dup(band);
+	if (isl_band_drop(child, 0, pos) < 0)
+		child = isl_band_free(child);
+	list = isl_band_list_alloc(ctx, 1);
+	list = isl_band_list_add(list, child);
+	if (!list)
+		return -1;
+
+	if (isl_band_drop(band, pos, band->n - pos) < 0) {
+		isl_band_list_free(list);
+		return -1;
+	}
+
+	child->children = band->children;
+	band->children = list;
+	child->parent = band;
+
+	return 0;
+}
+
+__isl_give isl_printer *isl_printer_print_band(__isl_take isl_printer *p,
+	__isl_keep isl_band *band)
+{
+	isl_union_map *prefix, *partial, *suffix;
+
+	prefix = isl_band_get_prefix_schedule(band);
+	partial = isl_band_get_partial_schedule(band);
+	suffix = isl_band_get_suffix_schedule(band);
+
+	p = isl_printer_print_str(p, "(");
+	p = isl_printer_print_union_map(p, prefix);
+	p = isl_printer_print_str(p, ",");
+	p = isl_printer_print_union_map(p, partial);
+	p = isl_printer_print_str(p, ",");
+	p = isl_printer_print_union_map(p, suffix);
+	p = isl_printer_print_str(p, ")");
+
+	isl_union_map_free(prefix);
+	isl_union_map_free(partial);
+	isl_union_map_free(suffix);
+
+	return p;
+}
diff --git a/final/lib/External/isl/isl_band_private.h b/final/lib/External/isl/isl_band_private.h
new file mode 100644
index 0000000..8b9c0b7
--- /dev/null
+++ b/final/lib/External/isl/isl_band_private.h
@@ -0,0 +1,47 @@
+#ifndef ISL_BAND_PRIVATE_H
+#define ISL_BAND_PRIVATE_H
+
+#include <isl/aff.h>
+#include <isl/band.h>
+#include <isl/list.h>
+#include <isl/schedule.h>
+
+/* Information about a band within a schedule.
+ *
+ * n is the number of scheduling dimensions within the band.
+ * coincident is an array of length n, indicating whether a scheduling dimension
+ *	satisfies the coincidence constraints in the sense that
+ *	the corresponding dependence distances are zero.
+ * pma is the partial schedule corresponding to this band.
+ * schedule is the schedule that contains this band.
+ * parent is the parent of this band (or NULL if the band is a root).
+ * children are the children of this band (or NULL if the band is a leaf).
+ *
+ * To avoid circular dependences in the reference counting,
+ * the schedule and parent pointers are not reference counted.
+ * isl_band_copy increments the reference count of schedule to ensure
+ * that outside references to the band keep the schedule alive.
+ */
+struct isl_band {
+	int ref;
+
+	int n;
+	int *coincident;
+
+	isl_union_pw_multi_aff *pma;
+	isl_schedule *schedule;
+	isl_band *parent;
+	isl_band_list *children;
+};
+
+#undef EL
+#define EL isl_band
+
+#include <isl_list_templ.h>
+
+__isl_give isl_band *isl_band_alloc(isl_ctx *ctx);
+
+__isl_give isl_union_map *isl_band_list_get_suffix_schedule(
+	__isl_keep isl_band_list *list);
+
+#endif
diff --git a/final/lib/External/isl/isl_basis_reduction.h b/final/lib/External/isl/isl_basis_reduction.h
new file mode 100644
index 0000000..2517c2f
--- /dev/null
+++ b/final/lib/External/isl/isl_basis_reduction.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_BASIS_REDUCTION_H
+#define ISL_BASIS_REDUCTION_H
+
+#include <isl/set.h>
+#include <isl_mat_private.h>
+#include "isl_tab.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_tab *isl_tab_compute_reduced_basis(struct isl_tab *tab);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/isl_bernstein.c b/final/lib/External/isl/isl_bernstein.c
new file mode 100644
index 0000000..3036e8f
--- /dev/null
+++ b/final/lib/External/isl/isl_bernstein.c
@@ -0,0 +1,558 @@
+/*
+ * Copyright 2006-2007 Universiteit Leiden
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science,
+ * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands
+ * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A,
+ * B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/set.h>
+#include <isl_seq.h>
+#include <isl_morph.h>
+#include <isl_factorization.h>
+#include <isl_vertices_private.h>
+#include <isl_polynomial_private.h>
+#include <isl_options_private.h>
+#include <isl_vec_private.h>
+#include <isl_bernstein.h>
+
+struct bernstein_data {
+	enum isl_fold type;
+	isl_qpolynomial *poly;
+	int check_tight;
+
+	isl_cell *cell;
+
+	isl_qpolynomial_fold *fold;
+	isl_qpolynomial_fold *fold_tight;
+	isl_pw_qpolynomial_fold *pwf;
+	isl_pw_qpolynomial_fold *pwf_tight;
+};
+
+static int vertex_is_integral(__isl_keep isl_basic_set *vertex)
+{
+	unsigned nvar;
+	unsigned nparam;
+	int i;
+
+	nvar = isl_basic_set_dim(vertex, isl_dim_set);
+	nparam = isl_basic_set_dim(vertex, isl_dim_param);
+	for (i = 0; i < nvar; ++i) {
+		int r = nvar - 1 - i;
+		if (!isl_int_is_one(vertex->eq[r][1 + nparam + i]) &&
+		    !isl_int_is_negone(vertex->eq[r][1 + nparam + i]))
+			return 0;
+	}
+
+	return 1;
+}
+
+static __isl_give isl_qpolynomial *vertex_coordinate(
+	__isl_keep isl_basic_set *vertex, int i, __isl_take isl_space *dim)
+{
+	unsigned nvar;
+	unsigned nparam;
+	int r;
+	isl_int denom;
+	isl_qpolynomial *v;
+
+	nvar = isl_basic_set_dim(vertex, isl_dim_set);
+	nparam = isl_basic_set_dim(vertex, isl_dim_param);
+	r = nvar - 1 - i;
+
+	isl_int_init(denom);
+	isl_int_set(denom, vertex->eq[r][1 + nparam + i]);
+	isl_assert(vertex->ctx, !isl_int_is_zero(denom), goto error);
+
+	if (isl_int_is_pos(denom))
+		isl_seq_neg(vertex->eq[r], vertex->eq[r],
+				1 + isl_basic_set_total_dim(vertex));
+	else
+		isl_int_neg(denom, denom);
+
+	v = isl_qpolynomial_from_affine(dim, vertex->eq[r], denom);
+	isl_int_clear(denom);
+
+	return v;
+error:
+	isl_space_free(dim);
+	isl_int_clear(denom);
+	return NULL;
+}
+
+/* Check whether the bound associated to the selection "k" is tight,
+ * which is the case if we select exactly one vertex and if that vertex
+ * is integral for all values of the parameters.
+ */
+static int is_tight(int *k, int n, int d, isl_cell *cell)
+{
+	int i;
+
+	for (i = 0; i < n; ++i) {
+		int v;
+		if (k[i] != d) {
+			if (k[i])
+				return 0;
+			continue;
+		}
+		v = cell->ids[n - 1 - i];
+		return vertex_is_integral(cell->vertices->v[v].vertex);
+	}
+
+	return 0;
+}
+
+static void add_fold(__isl_take isl_qpolynomial *b, __isl_keep isl_set *dom,
+	int *k, int n, int d, struct bernstein_data *data)
+{
+	isl_qpolynomial_fold *fold;
+
+	fold = isl_qpolynomial_fold_alloc(data->type, b);
+
+	if (data->check_tight && is_tight(k, n, d, data->cell))
+		data->fold_tight = isl_qpolynomial_fold_fold_on_domain(dom,
+							data->fold_tight, fold);
+	else
+		data->fold = isl_qpolynomial_fold_fold_on_domain(dom,
+							data->fold, fold);
+}
+
+/* Extract the coefficients of the Bernstein base polynomials and store
+ * them in data->fold and data->fold_tight.
+ *
+ * In particular, the coefficient of each monomial
+ * of multi-degree (k[0], k[1], ..., k[n-1]) is divided by the corresponding
+ * multinomial coefficient d!/k[0]! k[1]! ... k[n-1]!
+ *
+ * c[i] contains the coefficient of the selected powers of the first i+1 vars.
+ * multinom[i] contains the partial multinomial coefficient.
+ */
+static void extract_coefficients(isl_qpolynomial *poly,
+	__isl_keep isl_set *dom, struct bernstein_data *data)
+{
+	int i;
+	int d;
+	int n;
+	isl_ctx *ctx;
+	isl_qpolynomial **c = NULL;
+	int *k = NULL;
+	int *left = NULL;
+	isl_vec *multinom = NULL;
+
+	if (!poly)
+		return;
+
+	ctx = isl_qpolynomial_get_ctx(poly);
+	n = isl_qpolynomial_dim(poly, isl_dim_in);
+	d = isl_qpolynomial_degree(poly);
+	isl_assert(ctx, n >= 2, return);
+
+	c = isl_calloc_array(ctx, isl_qpolynomial *, n);
+	k = isl_alloc_array(ctx, int, n);
+	left = isl_alloc_array(ctx, int, n);
+	multinom = isl_vec_alloc(ctx, n);
+	if (!c || !k || !left || !multinom)
+		goto error;
+
+	isl_int_set_si(multinom->el[0], 1);
+	for (k[0] = d; k[0] >= 0; --k[0]) {
+		int i = 1;
+		isl_qpolynomial_free(c[0]);
+		c[0] = isl_qpolynomial_coeff(poly, isl_dim_in, n - 1, k[0]);
+		left[0] = d - k[0];
+		k[1] = -1;
+		isl_int_set(multinom->el[1], multinom->el[0]);
+		while (i > 0) {
+			if (i == n - 1) {
+				int j;
+				isl_space *dim;
+				isl_qpolynomial *b;
+				isl_qpolynomial *f;
+				for (j = 2; j <= left[i - 1]; ++j)
+					isl_int_divexact_ui(multinom->el[i],
+						multinom->el[i], j);
+				b = isl_qpolynomial_coeff(c[i - 1], isl_dim_in,
+					n - 1 - i, left[i - 1]);
+				b = isl_qpolynomial_project_domain_on_params(b);
+				dim = isl_qpolynomial_get_domain_space(b);
+				f = isl_qpolynomial_rat_cst_on_domain(dim, ctx->one,
+					multinom->el[i]);
+				b = isl_qpolynomial_mul(b, f);
+				k[n - 1] = left[n - 2];
+				add_fold(b, dom, k, n, d, data);
+				--i;
+				continue;
+			}
+			if (k[i] >= left[i - 1]) {
+				--i;
+				continue;
+			}
+			++k[i];
+			if (k[i])
+				isl_int_divexact_ui(multinom->el[i],
+					multinom->el[i], k[i]);
+			isl_qpolynomial_free(c[i]);
+			c[i] = isl_qpolynomial_coeff(c[i - 1], isl_dim_in,
+					n - 1 - i, k[i]);
+			left[i] = left[i - 1] - k[i];
+			k[i + 1] = -1;
+			isl_int_set(multinom->el[i + 1], multinom->el[i]);
+			++i;
+		}
+		isl_int_mul_ui(multinom->el[0], multinom->el[0], k[0]);
+	}
+
+	for (i = 0; i < n; ++i)
+		isl_qpolynomial_free(c[i]);
+
+	isl_vec_free(multinom);
+	free(left);
+	free(k);
+	free(c);
+	return;
+error:
+	isl_vec_free(multinom);
+	free(left);
+	free(k);
+	if (c)
+		for (i = 0; i < n; ++i)
+			isl_qpolynomial_free(c[i]);
+	free(c);
+	return;
+}
+
+/* Perform bernstein expansion on the parametric vertices that are active
+ * on "cell".
+ *
+ * data->poly has been homogenized in the calling function.
+ *
+ * We plug in the barycentric coordinates for the set variables
+ *
+ *		\vec x = \sum_i \alpha_i v_i(\vec p)
+ *
+ * and the constant "1 = \sum_i \alpha_i" for the homogeneous dimension.
+ * Next, we extract the coefficients of the Bernstein base polynomials.
+ */
+static isl_stat bernstein_coefficients_cell(__isl_take isl_cell *cell,
+	void *user)
+{
+	int i, j;
+	struct bernstein_data *data = (struct bernstein_data *)user;
+	isl_space *dim_param;
+	isl_space *dim_dst;
+	isl_qpolynomial *poly = data->poly;
+	unsigned nvar;
+	int n_vertices;
+	isl_qpolynomial **subs;
+	isl_pw_qpolynomial_fold *pwf;
+	isl_set *dom;
+	isl_ctx *ctx;
+
+	if (!poly)
+		goto error;
+
+	nvar = isl_qpolynomial_dim(poly, isl_dim_in) - 1;
+	n_vertices = cell->n_vertices;
+
+	ctx = isl_qpolynomial_get_ctx(poly);
+	if (n_vertices > nvar + 1 && ctx->opt->bernstein_triangulate)
+		return isl_cell_foreach_simplex(cell,
+					    &bernstein_coefficients_cell, user);
+
+	subs = isl_alloc_array(ctx, isl_qpolynomial *, 1 + nvar);
+	if (!subs)
+		goto error;
+
+	dim_param = isl_basic_set_get_space(cell->dom);
+	dim_dst = isl_qpolynomial_get_domain_space(poly);
+	dim_dst = isl_space_add_dims(dim_dst, isl_dim_set, n_vertices);
+
+	for (i = 0; i < 1 + nvar; ++i)
+		subs[i] = isl_qpolynomial_zero_on_domain(isl_space_copy(dim_dst));
+
+	for (i = 0; i < n_vertices; ++i) {
+		isl_qpolynomial *c;
+		c = isl_qpolynomial_var_on_domain(isl_space_copy(dim_dst), isl_dim_set,
+					1 + nvar + i);
+		for (j = 0; j < nvar; ++j) {
+			int k = cell->ids[i];
+			isl_qpolynomial *v;
+			v = vertex_coordinate(cell->vertices->v[k].vertex, j,
+						isl_space_copy(dim_param));
+			v = isl_qpolynomial_add_dims(v, isl_dim_in,
+							1 + nvar + n_vertices);
+			v = isl_qpolynomial_mul(v, isl_qpolynomial_copy(c));
+			subs[1 + j] = isl_qpolynomial_add(subs[1 + j], v);
+		}
+		subs[0] = isl_qpolynomial_add(subs[0], c);
+	}
+	isl_space_free(dim_dst);
+
+	poly = isl_qpolynomial_copy(poly);
+
+	poly = isl_qpolynomial_add_dims(poly, isl_dim_in, n_vertices);
+	poly = isl_qpolynomial_substitute(poly, isl_dim_in, 0, 1 + nvar, subs);
+	poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, 0, 1 + nvar);
+
+	data->cell = cell;
+	dom = isl_set_from_basic_set(isl_basic_set_copy(cell->dom));
+	data->fold = isl_qpolynomial_fold_empty(data->type, isl_space_copy(dim_param));
+	data->fold_tight = isl_qpolynomial_fold_empty(data->type, dim_param);
+	extract_coefficients(poly, dom, data);
+
+	pwf = isl_pw_qpolynomial_fold_alloc(data->type, isl_set_copy(dom),
+					    data->fold);
+	data->pwf = isl_pw_qpolynomial_fold_fold(data->pwf, pwf);
+	pwf = isl_pw_qpolynomial_fold_alloc(data->type, dom, data->fold_tight);
+	data->pwf_tight = isl_pw_qpolynomial_fold_fold(data->pwf_tight, pwf);
+
+	isl_qpolynomial_free(poly);
+	isl_cell_free(cell);
+	for (i = 0; i < 1 + nvar; ++i)
+		isl_qpolynomial_free(subs[i]);
+	free(subs);
+	return isl_stat_ok;
+error:
+	isl_cell_free(cell);
+	return isl_stat_error;
+}
+
+/* Base case of applying bernstein expansion.
+ *
+ * We compute the chamber decomposition of the parametric polytope "bset"
+ * and then perform bernstein expansion on the parametric vertices
+ * that are active on each chamber.
+ */
+static __isl_give isl_pw_qpolynomial_fold *bernstein_coefficients_base(
+	__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct bernstein_data *data, int *tight)
+{
+	unsigned nvar;
+	isl_space *dim;
+	isl_pw_qpolynomial_fold *pwf;
+	isl_vertices *vertices;
+	int covers;
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+	if (nvar == 0) {
+		isl_set *dom;
+		isl_qpolynomial_fold *fold;
+
+		fold = isl_qpolynomial_fold_alloc(data->type, poly);
+		dom = isl_set_from_basic_set(bset);
+		if (tight)
+			*tight = 1;
+		pwf = isl_pw_qpolynomial_fold_alloc(data->type, dom, fold);
+		return isl_pw_qpolynomial_fold_project_domain_on_params(pwf);
+	}
+
+	if (isl_qpolynomial_is_zero(poly)) {
+		isl_set *dom;
+		isl_qpolynomial_fold *fold;
+		fold = isl_qpolynomial_fold_alloc(data->type, poly);
+		dom = isl_set_from_basic_set(bset);
+		pwf = isl_pw_qpolynomial_fold_alloc(data->type, dom, fold);
+		if (tight)
+			*tight = 1;
+		return isl_pw_qpolynomial_fold_project_domain_on_params(pwf);
+	}
+
+	dim = isl_basic_set_get_space(bset);
+	dim = isl_space_params(dim);
+	dim = isl_space_from_domain(dim);
+	dim = isl_space_add_dims(dim, isl_dim_set, 1);
+	data->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(dim), data->type);
+	data->pwf_tight = isl_pw_qpolynomial_fold_zero(dim, data->type);
+	data->poly = isl_qpolynomial_homogenize(isl_qpolynomial_copy(poly));
+	vertices = isl_basic_set_compute_vertices(bset);
+	if (isl_vertices_foreach_disjoint_cell(vertices,
+					&bernstein_coefficients_cell, data) < 0)
+		data->pwf = isl_pw_qpolynomial_fold_free(data->pwf);
+	isl_vertices_free(vertices);
+	isl_qpolynomial_free(data->poly);
+
+	isl_basic_set_free(bset);
+	isl_qpolynomial_free(poly);
+
+	covers = isl_pw_qpolynomial_fold_covers(data->pwf_tight, data->pwf);
+	if (covers < 0)
+		goto error;
+
+	if (tight)
+		*tight = covers;
+
+	if (covers) {
+		isl_pw_qpolynomial_fold_free(data->pwf);
+		return data->pwf_tight;
+	}
+
+	data->pwf = isl_pw_qpolynomial_fold_fold(data->pwf, data->pwf_tight);
+
+	return data->pwf;
+error:
+	isl_pw_qpolynomial_fold_free(data->pwf_tight);
+	isl_pw_qpolynomial_fold_free(data->pwf);
+	return NULL;
+}
+
+/* Apply bernstein expansion recursively by working in on len[i]
+ * set variables at a time, with i ranging from n_group - 1 to 0.
+ */
+static __isl_give isl_pw_qpolynomial_fold *bernstein_coefficients_recursive(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	int n_group, int *len, struct bernstein_data *data, int *tight)
+{
+	int i;
+	unsigned nparam;
+	unsigned nvar;
+	isl_pw_qpolynomial_fold *pwf;
+
+	if (!pwqp)
+		return NULL;
+
+	nparam = isl_pw_qpolynomial_dim(pwqp, isl_dim_param);
+	nvar = isl_pw_qpolynomial_dim(pwqp, isl_dim_in);
+
+	pwqp = isl_pw_qpolynomial_move_dims(pwqp, isl_dim_param, nparam,
+					isl_dim_in, 0, nvar - len[n_group - 1]);
+	pwf = isl_pw_qpolynomial_bound(pwqp, data->type, tight);
+
+	for (i = n_group - 2; i >= 0; --i) {
+		nparam = isl_pw_qpolynomial_fold_dim(pwf, isl_dim_param);
+		pwf = isl_pw_qpolynomial_fold_move_dims(pwf, isl_dim_in, 0,
+				isl_dim_param, nparam - len[i], len[i]);
+		if (tight && !*tight)
+			tight = NULL;
+		pwf = isl_pw_qpolynomial_fold_bound(pwf, tight);
+	}
+
+	return pwf;
+}
+
+static __isl_give isl_pw_qpolynomial_fold *bernstein_coefficients_factors(
+	__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct bernstein_data *data, int *tight)
+{
+	isl_factorizer *f;
+	isl_set *set;
+	isl_pw_qpolynomial *pwqp;
+	isl_pw_qpolynomial_fold *pwf;
+
+	f = isl_basic_set_factorizer(bset);
+	if (!f)
+		goto error;
+	if (f->n_group == 0) {
+		isl_factorizer_free(f);
+		return  bernstein_coefficients_base(bset, poly, data, tight);
+	}
+
+	set = isl_set_from_basic_set(bset);
+	pwqp = isl_pw_qpolynomial_alloc(set, poly);
+	pwqp = isl_pw_qpolynomial_morph_domain(pwqp, isl_morph_copy(f->morph));
+
+	pwf = bernstein_coefficients_recursive(pwqp, f->n_group, f->len, data,
+						tight);
+
+	isl_factorizer_free(f);
+
+	return pwf;
+error:
+	isl_basic_set_free(bset);
+	isl_qpolynomial_free(poly);
+	return NULL;
+}
+
+static __isl_give isl_pw_qpolynomial_fold *bernstein_coefficients_full_recursive(
+	__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct bernstein_data *data, int *tight)
+{
+	int i;
+	int *len;
+	unsigned nvar;
+	isl_pw_qpolynomial_fold *pwf;
+	isl_set *set;
+	isl_pw_qpolynomial *pwqp;
+
+	if (!bset || !poly)
+		goto error;
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+	
+	len = isl_alloc_array(bset->ctx, int, nvar);
+	if (nvar && !len)
+		goto error;
+
+	for (i = 0; i < nvar; ++i)
+		len[i] = 1;
+
+	set = isl_set_from_basic_set(bset);
+	pwqp = isl_pw_qpolynomial_alloc(set, poly);
+
+	pwf = bernstein_coefficients_recursive(pwqp, nvar, len, data, tight);
+
+	free(len);
+
+	return pwf;
+error:
+	isl_basic_set_free(bset);
+	isl_qpolynomial_free(poly);
+	return NULL;
+}
+
+/* Compute a bound on the polynomial defined over the parametric polytope
+ * using bernstein expansion and store the result
+ * in bound->pwf and bound->pwf_tight.
+ *
+ * If bernstein_recurse is set to ISL_BERNSTEIN_FACTORS, we check if
+ * the polytope can be factorized and apply bernstein expansion recursively
+ * on the factors.
+ * If bernstein_recurse is set to ISL_BERNSTEIN_INTERVALS, we apply
+ * bernstein expansion recursively on each dimension.
+ * Otherwise, we apply bernstein expansion on the entire polytope.
+ */
+isl_stat isl_qpolynomial_bound_on_domain_bernstein(
+	__isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *poly,
+	struct isl_bound *bound)
+{
+	struct bernstein_data data;
+	isl_pw_qpolynomial_fold *pwf;
+	unsigned nvar;
+	int tight = 0;
+	int *tp = bound->check_tight ? &tight : NULL;
+
+	if (!bset || !poly)
+		goto error;
+
+	data.type = bound->type;
+	data.check_tight = bound->check_tight;
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+	if (bset->ctx->opt->bernstein_recurse & ISL_BERNSTEIN_FACTORS)
+		pwf = bernstein_coefficients_factors(bset, poly, &data, tp);
+	else if (nvar > 1 &&
+	    (bset->ctx->opt->bernstein_recurse & ISL_BERNSTEIN_INTERVALS))
+		pwf = bernstein_coefficients_full_recursive(bset, poly, &data, tp);
+	else
+		pwf = bernstein_coefficients_base(bset, poly, &data, tp);
+
+	if (tight)
+		bound->pwf_tight = isl_pw_qpolynomial_fold_fold(bound->pwf_tight, pwf);
+	else
+		bound->pwf = isl_pw_qpolynomial_fold_fold(bound->pwf, pwf);
+
+	return isl_stat_ok;
+error:
+	isl_basic_set_free(bset);
+	isl_qpolynomial_free(poly);
+	return isl_stat_error;
+}
diff --git a/final/lib/External/isl/isl_bernstein.h b/final/lib/External/isl/isl_bernstein.h
new file mode 100644
index 0000000..ca11df4
--- /dev/null
+++ b/final/lib/External/isl/isl_bernstein.h
@@ -0,0 +1,5 @@
+#include <isl_bound.h>
+
+isl_stat isl_qpolynomial_bound_on_domain_bernstein(
+	__isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *poly,
+	struct isl_bound *bound);
diff --git a/final/lib/External/isl/isl_blk.c b/final/lib/External/isl/isl_blk.c
new file mode 100644
index 0000000..0b03ecf
--- /dev/null
+++ b/final/lib/External/isl/isl_blk.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_blk.h>
+#include <isl_ctx_private.h>
+
+/* The maximal number of cache misses before first element is evicted */
+#define ISL_BLK_MAX_MISS	100
+
+struct isl_blk isl_blk_empty()
+{
+	struct isl_blk block;
+	block.size = 0;
+	block.data = NULL;
+	return block;
+}
+
+static int isl_blk_is_empty(struct isl_blk block)
+{
+	return block.size == 0 && block.data == NULL;
+}
+
+static struct isl_blk isl_blk_error()
+{
+	struct isl_blk block;
+	block.size = -1;
+	block.data = NULL;
+	return block;
+}
+
+int isl_blk_is_error(struct isl_blk block)
+{
+	return block.size == -1 && block.data == NULL;
+}
+
+static void isl_blk_free_force(struct isl_ctx *ctx, struct isl_blk block)
+{
+	int i;
+
+	for (i = 0; i < block.size; ++i)
+		isl_int_clear(block.data[i]);
+	free(block.data);
+}
+
+static struct isl_blk extend(struct isl_ctx *ctx, struct isl_blk block,
+				size_t new_n)
+{
+	int i;
+	isl_int *p;
+
+	if (block.size >= new_n)
+		return block;
+
+	p = isl_realloc_array(ctx, block.data, isl_int, new_n);
+	if (!p) {
+		isl_blk_free_force(ctx, block);
+		return isl_blk_error();
+	}
+	block.data = p;
+
+	for (i = block.size; i < new_n; ++i)
+		isl_int_init(block.data[i]);
+	block.size = new_n;
+
+	return block;
+}
+
+struct isl_blk isl_blk_alloc(struct isl_ctx *ctx, size_t n)
+{
+	int i;
+	struct isl_blk block;
+
+	block = isl_blk_empty();
+	if (n && ctx->n_cached) {
+		int best = 0;
+		for (i = 1; ctx->cache[best].size != n && i < ctx->n_cached; ++i) {
+			if (ctx->cache[best].size < n) {
+				if (ctx->cache[i].size > ctx->cache[best].size)
+					best = i;
+			} else if (ctx->cache[i].size >= n &&
+				   ctx->cache[i].size < ctx->cache[best].size)
+					best = i;
+		}
+		if (ctx->cache[best].size < 2 * n + 100) {
+			block = ctx->cache[best];
+			if (--ctx->n_cached != best)
+				ctx->cache[best] = ctx->cache[ctx->n_cached];
+			if (best == 0)
+				ctx->n_miss = 0;
+		} else if (ctx->n_miss++ >= ISL_BLK_MAX_MISS) {
+			isl_blk_free_force(ctx, ctx->cache[0]);
+			if (--ctx->n_cached != 0)
+				ctx->cache[0] = ctx->cache[ctx->n_cached];
+			ctx->n_miss = 0;
+		}
+	}
+
+	return extend(ctx, block, n);
+}
+
+struct isl_blk isl_blk_extend(struct isl_ctx *ctx, struct isl_blk block,
+				size_t new_n)
+{
+	if (isl_blk_is_empty(block))
+		return isl_blk_alloc(ctx, new_n);
+
+	return extend(ctx, block, new_n);
+}
+
+void isl_blk_free(struct isl_ctx *ctx, struct isl_blk block)
+{
+	if (isl_blk_is_empty(block) || isl_blk_is_error(block))
+		return;
+
+	if (ctx->n_cached < ISL_BLK_CACHE_SIZE)
+		ctx->cache[ctx->n_cached++] = block;
+	else
+		isl_blk_free_force(ctx, block);
+}
+
+void isl_blk_clear_cache(struct isl_ctx *ctx)
+{
+	int i;
+
+	for (i = 0; i < ctx->n_cached; ++i)
+		isl_blk_free_force(ctx, ctx->cache[i]);
+	ctx->n_cached = 0;
+}
diff --git a/final/lib/External/isl/isl_blk.h b/final/lib/External/isl/isl_blk.h
new file mode 100644
index 0000000..7756e01
--- /dev/null
+++ b/final/lib/External/isl/isl_blk.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_BLK_H
+#define ISL_BLK_H
+
+#include <isl_int.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_blk {
+	size_t size;
+	isl_int *data;
+};
+
+#define ISL_BLK_CACHE_SIZE	20
+
+struct isl_ctx;
+
+struct isl_blk isl_blk_alloc(struct isl_ctx *ctx, size_t n);
+struct isl_blk isl_blk_empty(void);
+int isl_blk_is_error(struct isl_blk block);
+struct isl_blk isl_blk_extend(struct isl_ctx *ctx, struct isl_blk block,
+				size_t new_n);
+void isl_blk_free(struct isl_ctx *ctx, struct isl_blk block);
+void isl_blk_clear_cache(struct isl_ctx *ctx);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/isl_bound.c b/final/lib/External/isl/isl_bound.c
new file mode 100644
index 0000000..d4177f4
--- /dev/null
+++ b/final/lib/External/isl/isl_bound.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France 
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_bound.h>
+#include <isl_bernstein.h>
+#include <isl_range.h>
+#include <isl_polynomial_private.h>
+#include <isl_options_private.h>
+
+/* Compute a bound on the polynomial defined over the parametric polytope
+ * using either range propagation or bernstein expansion and
+ * store the result in bound->pwf and bound->pwf_tight.
+ * Since bernstein expansion requires bounded domains, we apply
+ * range propagation on unbounded domains.  Otherwise, we respect the choice
+ * of the user.
+ */
+static isl_stat compressed_guarded_poly_bound(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, void *user)
+{
+	struct isl_bound *bound = (struct isl_bound *)user;
+	int bounded;
+
+	if (!bset || !poly)
+		goto error;
+
+	if (bset->ctx->opt->bound == ISL_BOUND_RANGE)
+		return isl_qpolynomial_bound_on_domain_range(bset, poly, bound);
+
+	bounded = isl_basic_set_is_bounded(bset);
+	if (bounded < 0)
+		goto error;
+	if (bounded)
+		return isl_qpolynomial_bound_on_domain_bernstein(bset, poly, bound);
+	else
+		return isl_qpolynomial_bound_on_domain_range(bset, poly, bound);
+error:
+	isl_basic_set_free(bset);
+	isl_qpolynomial_free(poly);
+	return -1;
+}
+
+static isl_stat unwrapped_guarded_poly_bound(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, void *user)
+{
+	struct isl_bound *bound = (struct isl_bound *)user;
+	isl_pw_qpolynomial_fold *top_pwf;
+	isl_pw_qpolynomial_fold *top_pwf_tight;
+	isl_space *dim;
+	isl_morph *morph;
+	isl_stat r;
+
+	bset = isl_basic_set_detect_equalities(bset);
+
+	if (!bset)
+		goto error;
+
+	if (bset->n_eq == 0)
+		return compressed_guarded_poly_bound(bset, poly, user);
+
+	morph = isl_basic_set_full_compression(bset);
+
+	bset = isl_morph_basic_set(isl_morph_copy(morph), bset);
+	poly = isl_qpolynomial_morph_domain(poly, isl_morph_copy(morph));
+
+	dim = isl_morph_get_ran_space(morph);
+	dim = isl_space_params(dim);
+
+	top_pwf = bound->pwf;
+	top_pwf_tight = bound->pwf_tight;
+
+	dim = isl_space_from_domain(dim);
+	dim = isl_space_add_dims(dim, isl_dim_out, 1);
+	bound->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(dim),
+						  bound->type);
+	bound->pwf_tight = isl_pw_qpolynomial_fold_zero(dim, bound->type);
+
+	r = compressed_guarded_poly_bound(bset, poly, user);
+
+	morph = isl_morph_dom_params(morph);
+	morph = isl_morph_ran_params(morph);
+	morph = isl_morph_inverse(morph);
+
+	bound->pwf = isl_pw_qpolynomial_fold_morph_domain(bound->pwf,
+							isl_morph_copy(morph));
+	bound->pwf_tight = isl_pw_qpolynomial_fold_morph_domain(
+						bound->pwf_tight, morph);
+
+	bound->pwf = isl_pw_qpolynomial_fold_fold(top_pwf, bound->pwf);
+	bound->pwf_tight = isl_pw_qpolynomial_fold_fold(top_pwf_tight,
+							bound->pwf_tight);
+
+	return r;
+error:
+	isl_basic_set_free(bset);
+	isl_qpolynomial_free(poly);
+	return isl_stat_error;
+}
+
+static isl_stat guarded_poly_bound(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, void *user)
+{
+	struct isl_bound *bound = (struct isl_bound *)user;
+	isl_space *dim;
+	isl_pw_qpolynomial_fold *top_pwf;
+	isl_pw_qpolynomial_fold *top_pwf_tight;
+	int nparam;
+	int n_in;
+	isl_stat r;
+
+	if (!bound->wrapping)
+		return unwrapped_guarded_poly_bound(bset, poly, user);
+
+	nparam = isl_space_dim(bound->dim, isl_dim_param);
+	n_in = isl_space_dim(bound->dim, isl_dim_in);
+
+	bset = isl_basic_set_move_dims(bset, isl_dim_param, nparam,
+					isl_dim_set, 0, n_in);
+	poly = isl_qpolynomial_move_dims(poly, isl_dim_param, nparam,
+					isl_dim_in, 0, n_in);
+
+	dim = isl_basic_set_get_space(bset);
+	dim = isl_space_params(dim);
+
+	top_pwf = bound->pwf;
+	top_pwf_tight = bound->pwf_tight;
+
+	dim = isl_space_from_domain(dim);
+	dim = isl_space_add_dims(dim, isl_dim_out, 1);
+	bound->pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(dim),
+						  bound->type);
+	bound->pwf_tight = isl_pw_qpolynomial_fold_zero(dim, bound->type);
+
+	r = unwrapped_guarded_poly_bound(bset, poly, user);
+
+	bound->pwf = isl_pw_qpolynomial_fold_reset_space(bound->pwf,
+						    isl_space_copy(bound->dim));
+	bound->pwf_tight = isl_pw_qpolynomial_fold_reset_space(bound->pwf_tight,
+						    isl_space_copy(bound->dim));
+
+	bound->pwf = isl_pw_qpolynomial_fold_fold(top_pwf, bound->pwf);
+	bound->pwf_tight = isl_pw_qpolynomial_fold_fold(top_pwf_tight,
+							bound->pwf_tight);
+
+	return r;
+}
+
+static isl_stat guarded_qp(__isl_take isl_qpolynomial *qp, void *user)
+{
+	struct isl_bound *bound = (struct isl_bound *)user;
+	isl_stat r;
+
+	r = isl_qpolynomial_as_polynomial_on_domain(qp, bound->bset,
+						    &guarded_poly_bound, user);
+	isl_qpolynomial_free(qp);
+	return r;
+}
+
+static isl_stat basic_guarded_fold(__isl_take isl_basic_set *bset, void *user)
+{
+	struct isl_bound *bound = (struct isl_bound *)user;
+	isl_stat r;
+
+	bound->bset = bset;
+	r = isl_qpolynomial_fold_foreach_qpolynomial(bound->fold,
+							&guarded_qp, user);
+	isl_basic_set_free(bset);
+	return r;
+}
+
+static isl_stat guarded_fold(__isl_take isl_set *set,
+	__isl_take isl_qpolynomial_fold *fold, void *user)
+{
+	struct isl_bound *bound = (struct isl_bound *)user;
+
+	if (!set || !fold)
+		goto error;
+
+	set = isl_set_make_disjoint(set);
+
+	bound->fold = fold;
+	bound->type = isl_qpolynomial_fold_get_type(fold);
+
+	if (isl_set_foreach_basic_set(set, &basic_guarded_fold, bound) < 0)
+		goto error;
+
+	isl_set_free(set);
+	isl_qpolynomial_fold_free(fold);
+
+	return isl_stat_ok;
+error:
+	isl_set_free(set);
+	isl_qpolynomial_fold_free(fold);
+	return isl_stat_error;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_bound(
+	__isl_take isl_pw_qpolynomial_fold *pwf, int *tight)
+{
+	unsigned nvar;
+	struct isl_bound bound;
+	int covers;
+
+	if (!pwf)
+		return NULL;
+
+	bound.dim = isl_pw_qpolynomial_fold_get_domain_space(pwf);
+
+	bound.wrapping = isl_space_is_wrapping(bound.dim);
+	if (bound.wrapping)
+		bound.dim = isl_space_unwrap(bound.dim);
+	nvar = isl_space_dim(bound.dim, isl_dim_out);
+	bound.dim = isl_space_domain(bound.dim);
+	bound.dim = isl_space_from_domain(bound.dim);
+	bound.dim = isl_space_add_dims(bound.dim, isl_dim_out, 1);
+
+	if (nvar == 0) {
+		if (tight)
+			*tight = 1;
+		return isl_pw_qpolynomial_fold_reset_space(pwf, bound.dim);
+	}
+
+	if (isl_pw_qpolynomial_fold_is_zero(pwf)) {
+		enum isl_fold type = pwf->type;
+		isl_pw_qpolynomial_fold_free(pwf);
+		if (tight)
+			*tight = 1;
+		return isl_pw_qpolynomial_fold_zero(bound.dim, type);
+	}
+
+	bound.pwf = isl_pw_qpolynomial_fold_zero(isl_space_copy(bound.dim),
+							pwf->type);
+	bound.pwf_tight = isl_pw_qpolynomial_fold_zero(isl_space_copy(bound.dim),
+							pwf->type);
+	bound.check_tight = !!tight;
+
+	if (isl_pw_qpolynomial_fold_foreach_lifted_piece(pwf,
+							guarded_fold, &bound) < 0)
+		goto error;
+
+	covers = isl_pw_qpolynomial_fold_covers(bound.pwf_tight, bound.pwf);
+	if (covers < 0)
+		goto error;
+
+	if (tight)
+		*tight = covers;
+
+	isl_space_free(bound.dim);
+	isl_pw_qpolynomial_fold_free(pwf);
+
+	if (covers) {
+		isl_pw_qpolynomial_fold_free(bound.pwf);
+		return bound.pwf_tight;
+	}
+
+	bound.pwf = isl_pw_qpolynomial_fold_fold(bound.pwf, bound.pwf_tight);
+
+	return bound.pwf;
+error:
+	isl_pw_qpolynomial_fold_free(bound.pwf_tight);
+	isl_pw_qpolynomial_fold_free(bound.pwf);
+	isl_pw_qpolynomial_fold_free(pwf);
+	isl_space_free(bound.dim);
+	return NULL;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_bound(
+	__isl_take isl_pw_qpolynomial *pwqp, enum isl_fold type, int *tight)
+{
+	isl_pw_qpolynomial_fold *pwf;
+
+	pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(type, pwqp);
+	return isl_pw_qpolynomial_fold_bound(pwf, tight);
+}
+
+struct isl_union_bound_data {
+	enum isl_fold type;
+	int tight;
+	isl_union_pw_qpolynomial_fold *res;
+};
+
+static isl_stat bound_pw(__isl_take isl_pw_qpolynomial *pwqp, void *user)
+{
+	struct isl_union_bound_data *data = user;
+	isl_pw_qpolynomial_fold *pwf;
+
+	pwf = isl_pw_qpolynomial_bound(pwqp, data->type,
+					data->tight ? &data->tight : NULL);
+	data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
+								data->res, pwf);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_bound(
+	__isl_take isl_union_pw_qpolynomial *upwqp,
+	enum isl_fold type, int *tight)
+{
+	isl_space *dim;
+	struct isl_union_bound_data data = { type, 1, NULL };
+
+	if (!upwqp)
+		return NULL;
+
+	if (!tight)
+		data.tight = 0;
+
+	dim = isl_union_pw_qpolynomial_get_space(upwqp);
+	data.res = isl_union_pw_qpolynomial_fold_zero(dim, type);
+	if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp,
+						    &bound_pw, &data) < 0)
+		goto error;
+
+	isl_union_pw_qpolynomial_free(upwqp);
+	if (tight)
+		*tight = data.tight;
+
+	return data.res;
+error:
+	isl_union_pw_qpolynomial_free(upwqp);
+	isl_union_pw_qpolynomial_fold_free(data.res);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_bound.h b/final/lib/External/isl/isl_bound.h
new file mode 100644
index 0000000..1a9d390
--- /dev/null
+++ b/final/lib/External/isl/isl_bound.h
@@ -0,0 +1,20 @@
+#ifndef ISL_BOUND_H
+#define ISL_BOUND_H
+
+#include <isl/polynomial.h>
+
+struct isl_bound {
+	/* input */
+	int check_tight;
+	int wrapping;
+	enum isl_fold type;
+	isl_space *dim;
+	isl_basic_set *bset;
+	isl_qpolynomial_fold *fold;
+
+	/* output */
+	isl_pw_qpolynomial_fold *pwf;
+	isl_pw_qpolynomial_fold *pwf_tight;
+};
+
+#endif
diff --git a/final/lib/External/isl/isl_coalesce.c b/final/lib/External/isl/isl_coalesce.c
new file mode 100644
index 0000000..476f815
--- /dev/null
+++ b/final/lib/External/isl/isl_coalesce.c
@@ -0,0 +1,3822 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ * Copyright 2016      INRIA Paris
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12,
+ * CS 42112, 75589 Paris Cedex 12, France
+ */
+
+#include <isl_ctx_private.h>
+#include "isl_map_private.h"
+#include <isl_seq.h>
+#include <isl/options.h>
+#include "isl_tab.h"
+#include <isl_mat_private.h>
+#include <isl_local_space_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl_aff_private.h>
+#include <isl_equalities.h>
+#include <isl_constraint_private.h>
+
+#include <set_to_map.c>
+#include <set_from_map.c>
+
+#define STATUS_ERROR		-1
+#define STATUS_REDUNDANT	 1
+#define STATUS_VALID	 	 2
+#define STATUS_SEPARATE	 	 3
+#define STATUS_CUT	 	 4
+#define STATUS_ADJ_EQ	 	 5
+#define STATUS_ADJ_INEQ	 	 6
+
+static int status_in(isl_int *ineq, struct isl_tab *tab)
+{
+	enum isl_ineq_type type = isl_tab_ineq_type(tab, ineq);
+	switch (type) {
+	default:
+	case isl_ineq_error:		return STATUS_ERROR;
+	case isl_ineq_redundant:	return STATUS_VALID;
+	case isl_ineq_separate:		return STATUS_SEPARATE;
+	case isl_ineq_cut:		return STATUS_CUT;
+	case isl_ineq_adj_eq:		return STATUS_ADJ_EQ;
+	case isl_ineq_adj_ineq:		return STATUS_ADJ_INEQ;
+	}
+}
+
+/* Compute the position of the equalities of basic map "bmap_i"
+ * with respect to the basic map represented by "tab_j".
+ * The resulting array has twice as many entries as the number
+ * of equalities corresponding to the two inequalities to which
+ * each equality corresponds.
+ */
+static int *eq_status_in(__isl_keep isl_basic_map *bmap_i,
+	struct isl_tab *tab_j)
+{
+	int k, l;
+	int *eq = isl_calloc_array(bmap_i->ctx, int, 2 * bmap_i->n_eq);
+	unsigned dim;
+
+	if (!eq)
+		return NULL;
+
+	dim = isl_basic_map_total_dim(bmap_i);
+	for (k = 0; k < bmap_i->n_eq; ++k) {
+		for (l = 0; l < 2; ++l) {
+			isl_seq_neg(bmap_i->eq[k], bmap_i->eq[k], 1+dim);
+			eq[2 * k + l] = status_in(bmap_i->eq[k], tab_j);
+			if (eq[2 * k + l] == STATUS_ERROR)
+				goto error;
+		}
+	}
+
+	return eq;
+error:
+	free(eq);
+	return NULL;
+}
+
+/* Compute the position of the inequalities of basic map "bmap_i"
+ * (also represented by "tab_i", if not NULL) with respect to the basic map
+ * represented by "tab_j".
+ */
+static int *ineq_status_in(__isl_keep isl_basic_map *bmap_i,
+	struct isl_tab *tab_i, struct isl_tab *tab_j)
+{
+	int k;
+	unsigned n_eq = bmap_i->n_eq;
+	int *ineq = isl_calloc_array(bmap_i->ctx, int, bmap_i->n_ineq);
+
+	if (!ineq)
+		return NULL;
+
+	for (k = 0; k < bmap_i->n_ineq; ++k) {
+		if (tab_i && isl_tab_is_redundant(tab_i, n_eq + k)) {
+			ineq[k] = STATUS_REDUNDANT;
+			continue;
+		}
+		ineq[k] = status_in(bmap_i->ineq[k], tab_j);
+		if (ineq[k] == STATUS_ERROR)
+			goto error;
+		if (ineq[k] == STATUS_SEPARATE)
+			break;
+	}
+
+	return ineq;
+error:
+	free(ineq);
+	return NULL;
+}
+
+static int any(int *con, unsigned len, int status)
+{
+	int i;
+
+	for (i = 0; i < len ; ++i)
+		if (con[i] == status)
+			return 1;
+	return 0;
+}
+
+/* Return the first position of "status" in the list "con" of length "len".
+ * Return -1 if there is no such entry.
+ */
+static int find(int *con, unsigned len, int status)
+{
+	int i;
+
+	for (i = 0; i < len ; ++i)
+		if (con[i] == status)
+			return i;
+	return -1;
+}
+
+static int count(int *con, unsigned len, int status)
+{
+	int i;
+	int c = 0;
+
+	for (i = 0; i < len ; ++i)
+		if (con[i] == status)
+			c++;
+	return c;
+}
+
+static int all(int *con, unsigned len, int status)
+{
+	int i;
+
+	for (i = 0; i < len ; ++i) {
+		if (con[i] == STATUS_REDUNDANT)
+			continue;
+		if (con[i] != status)
+			return 0;
+	}
+	return 1;
+}
+
+/* Internal information associated to a basic map in a map
+ * that is to be coalesced by isl_map_coalesce.
+ *
+ * "bmap" is the basic map itself (or NULL if "removed" is set)
+ * "tab" is the corresponding tableau (or NULL if "removed" is set)
+ * "hull_hash" identifies the affine space in which "bmap" lives.
+ * "removed" is set if this basic map has been removed from the map
+ * "simplify" is set if this basic map may have some unknown integer
+ * divisions that were not present in the input basic maps.  The basic
+ * map should then be simplified such that we may be able to find
+ * a definition among the constraints.
+ *
+ * "eq" and "ineq" are only set if we are currently trying to coalesce
+ * this basic map with another basic map, in which case they represent
+ * the position of the inequalities of this basic map with respect to
+ * the other basic map.  The number of elements in the "eq" array
+ * is twice the number of equalities in the "bmap", corresponding
+ * to the two inequalities that make up each equality.
+ */
+struct isl_coalesce_info {
+	isl_basic_map *bmap;
+	struct isl_tab *tab;
+	uint32_t hull_hash;
+	int removed;
+	int simplify;
+	int *eq;
+	int *ineq;
+};
+
+/* Are all non-redundant constraints of the basic map represented by "info"
+ * either valid or cut constraints with respect to the other basic map?
+ */
+static int all_valid_or_cut(struct isl_coalesce_info *info)
+{
+	int i;
+
+	for (i = 0; i < 2 * info->bmap->n_eq; ++i) {
+		if (info->eq[i] == STATUS_REDUNDANT)
+			continue;
+		if (info->eq[i] == STATUS_VALID)
+			continue;
+		if (info->eq[i] == STATUS_CUT)
+			continue;
+		return 0;
+	}
+
+	for (i = 0; i < info->bmap->n_ineq; ++i) {
+		if (info->ineq[i] == STATUS_REDUNDANT)
+			continue;
+		if (info->ineq[i] == STATUS_VALID)
+			continue;
+		if (info->ineq[i] == STATUS_CUT)
+			continue;
+		return 0;
+	}
+
+	return 1;
+}
+
+/* Compute the hash of the (apparent) affine hull of info->bmap (with
+ * the existentially quantified variables removed) and store it
+ * in info->hash.
+ */
+static int coalesce_info_set_hull_hash(struct isl_coalesce_info *info)
+{
+	isl_basic_map *hull;
+	unsigned n_div;
+
+	hull = isl_basic_map_copy(info->bmap);
+	hull = isl_basic_map_plain_affine_hull(hull);
+	n_div = isl_basic_map_dim(hull, isl_dim_div);
+	hull = isl_basic_map_drop_constraints_involving_dims(hull,
+							isl_dim_div, 0, n_div);
+	info->hull_hash = isl_basic_map_get_hash(hull);
+	isl_basic_map_free(hull);
+
+	return hull ? 0 : -1;
+}
+
+/* Free all the allocated memory in an array
+ * of "n" isl_coalesce_info elements.
+ */
+static void clear_coalesce_info(int n, struct isl_coalesce_info *info)
+{
+	int i;
+
+	if (!info)
+		return;
+
+	for (i = 0; i < n; ++i) {
+		isl_basic_map_free(info[i].bmap);
+		isl_tab_free(info[i].tab);
+	}
+
+	free(info);
+}
+
+/* Drop the basic map represented by "info".
+ * That is, clear the memory associated to the entry and
+ * mark it as having been removed.
+ */
+static void drop(struct isl_coalesce_info *info)
+{
+	info->bmap = isl_basic_map_free(info->bmap);
+	isl_tab_free(info->tab);
+	info->tab = NULL;
+	info->removed = 1;
+}
+
+/* Exchange the information in "info1" with that in "info2".
+ */
+static void exchange(struct isl_coalesce_info *info1,
+	struct isl_coalesce_info *info2)
+{
+	struct isl_coalesce_info info;
+
+	info = *info1;
+	*info1 = *info2;
+	*info2 = info;
+}
+
+/* This type represents the kind of change that has been performed
+ * while trying to coalesce two basic maps.
+ *
+ * isl_change_none: nothing was changed
+ * isl_change_drop_first: the first basic map was removed
+ * isl_change_drop_second: the second basic map was removed
+ * isl_change_fuse: the two basic maps were replaced by a new basic map.
+ */
+enum isl_change {
+	isl_change_error = -1,
+	isl_change_none = 0,
+	isl_change_drop_first,
+	isl_change_drop_second,
+	isl_change_fuse,
+};
+
+/* Update "change" based on an interchange of the first and the second
+ * basic map.  That is, interchange isl_change_drop_first and
+ * isl_change_drop_second.
+ */
+static enum isl_change invert_change(enum isl_change change)
+{
+	switch (change) {
+	case isl_change_error:
+		return isl_change_error;
+	case isl_change_none:
+		return isl_change_none;
+	case isl_change_drop_first:
+		return isl_change_drop_second;
+	case isl_change_drop_second:
+		return isl_change_drop_first;
+	case isl_change_fuse:
+		return isl_change_fuse;
+	}
+
+	return isl_change_error;
+}
+
+/* Add the valid constraints of the basic map represented by "info"
+ * to "bmap".  "len" is the size of the constraints.
+ * If only one of the pair of inequalities that make up an equality
+ * is valid, then add that inequality.
+ */
+static __isl_give isl_basic_map *add_valid_constraints(
+	__isl_take isl_basic_map *bmap, struct isl_coalesce_info *info,
+	unsigned len)
+{
+	int k, l;
+
+	if (!bmap)
+		return NULL;
+
+	for (k = 0; k < info->bmap->n_eq; ++k) {
+		if (info->eq[2 * k] == STATUS_VALID &&
+		    info->eq[2 * k + 1] == STATUS_VALID) {
+			l = isl_basic_map_alloc_equality(bmap);
+			if (l < 0)
+				return isl_basic_map_free(bmap);
+			isl_seq_cpy(bmap->eq[l], info->bmap->eq[k], len);
+		} else if (info->eq[2 * k] == STATUS_VALID) {
+			l = isl_basic_map_alloc_inequality(bmap);
+			if (l < 0)
+				return isl_basic_map_free(bmap);
+			isl_seq_neg(bmap->ineq[l], info->bmap->eq[k], len);
+		} else if (info->eq[2 * k + 1] == STATUS_VALID) {
+			l = isl_basic_map_alloc_inequality(bmap);
+			if (l < 0)
+				return isl_basic_map_free(bmap);
+			isl_seq_cpy(bmap->ineq[l], info->bmap->eq[k], len);
+		}
+	}
+
+	for (k = 0; k < info->bmap->n_ineq; ++k) {
+		if (info->ineq[k] != STATUS_VALID)
+			continue;
+		l = isl_basic_map_alloc_inequality(bmap);
+		if (l < 0)
+			return isl_basic_map_free(bmap);
+		isl_seq_cpy(bmap->ineq[l], info->bmap->ineq[k], len);
+	}
+
+	return bmap;
+}
+
+/* Is "bmap" defined by a number of (non-redundant) constraints that
+ * is greater than the number of constraints of basic maps i and j combined?
+ * Equalities are counted as two inequalities.
+ */
+static int number_of_constraints_increases(int i, int j,
+	struct isl_coalesce_info *info,
+	__isl_keep isl_basic_map *bmap, struct isl_tab *tab)
+{
+	int k, n_old, n_new;
+
+	n_old = 2 * info[i].bmap->n_eq + info[i].bmap->n_ineq;
+	n_old += 2 * info[j].bmap->n_eq + info[j].bmap->n_ineq;
+
+	n_new = 2 * bmap->n_eq;
+	for (k = 0; k < bmap->n_ineq; ++k)
+		if (!isl_tab_is_redundant(tab, bmap->n_eq + k))
+			++n_new;
+
+	return n_new > n_old;
+}
+
+/* Replace the pair of basic maps i and j by the basic map bounded
+ * by the valid constraints in both basic maps and the constraints
+ * in extra (if not NULL).
+ * Place the fused basic map in the position that is the smallest of i and j.
+ *
+ * If "detect_equalities" is set, then look for equalities encoded
+ * as pairs of inequalities.
+ * If "check_number" is set, then the original basic maps are only
+ * replaced if the total number of constraints does not increase.
+ * While the number of integer divisions in the two basic maps
+ * is assumed to be the same, the actual definitions may be different.
+ * We only copy the definition from one of the basic map if it is
+ * the same as that of the other basic map.  Otherwise, we mark
+ * the integer division as unknown and simplify the basic map
+ * in an attempt to recover the integer division definition.
+ */
+static enum isl_change fuse(int i, int j, struct isl_coalesce_info *info,
+	__isl_keep isl_mat *extra, int detect_equalities, int check_number)
+{
+	int k, l;
+	struct isl_basic_map *fused = NULL;
+	struct isl_tab *fused_tab = NULL;
+	unsigned total = isl_basic_map_total_dim(info[i].bmap);
+	unsigned extra_rows = extra ? extra->n_row : 0;
+	unsigned n_eq, n_ineq;
+	int simplify = 0;
+
+	if (j < i)
+		return fuse(j, i, info, extra, detect_equalities, check_number);
+
+	n_eq = info[i].bmap->n_eq + info[j].bmap->n_eq;
+	n_ineq = info[i].bmap->n_ineq + info[j].bmap->n_ineq;
+	fused = isl_basic_map_alloc_space(isl_space_copy(info[i].bmap->dim),
+		    info[i].bmap->n_div, n_eq, n_eq + n_ineq + extra_rows);
+	fused = add_valid_constraints(fused, &info[i], 1 + total);
+	fused = add_valid_constraints(fused, &info[j], 1 + total);
+	if (!fused)
+		goto error;
+	if (ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_RATIONAL) &&
+	    ISL_F_ISSET(info[j].bmap, ISL_BASIC_MAP_RATIONAL))
+		ISL_F_SET(fused, ISL_BASIC_MAP_RATIONAL);
+
+	for (k = 0; k < info[i].bmap->n_div; ++k) {
+		int l = isl_basic_map_alloc_div(fused);
+		if (l < 0)
+			goto error;
+		if (isl_seq_eq(info[i].bmap->div[k], info[j].bmap->div[k],
+				1 + 1 + total)) {
+			isl_seq_cpy(fused->div[l], info[i].bmap->div[k],
+				1 + 1 + total);
+		} else {
+			isl_int_set_si(fused->div[l][0], 0);
+			simplify = 1;
+		}
+	}
+
+	for (k = 0; k < extra_rows; ++k) {
+		l = isl_basic_map_alloc_inequality(fused);
+		if (l < 0)
+			goto error;
+		isl_seq_cpy(fused->ineq[l], extra->row[k], 1 + total);
+	}
+
+	if (detect_equalities)
+		fused = isl_basic_map_detect_inequality_pairs(fused, NULL);
+	fused = isl_basic_map_gauss(fused, NULL);
+	if (simplify || info[j].simplify) {
+		fused = isl_basic_map_simplify(fused);
+		info[i].simplify = 0;
+	}
+	fused = isl_basic_map_finalize(fused);
+
+	fused_tab = isl_tab_from_basic_map(fused, 0);
+	if (isl_tab_detect_redundant(fused_tab) < 0)
+		goto error;
+
+	if (check_number &&
+	    number_of_constraints_increases(i, j, info, fused, fused_tab)) {
+		isl_tab_free(fused_tab);
+		isl_basic_map_free(fused);
+		return isl_change_none;
+	}
+
+	isl_basic_map_free(info[i].bmap);
+	info[i].bmap = fused;
+	isl_tab_free(info[i].tab);
+	info[i].tab = fused_tab;
+	drop(&info[j]);
+
+	return isl_change_fuse;
+error:
+	isl_tab_free(fused_tab);
+	isl_basic_map_free(fused);
+	return isl_change_error;
+}
+
+/* Given a pair of basic maps i and j such that all constraints are either
+ * "valid" or "cut", check if the facets corresponding to the "cut"
+ * constraints of i lie entirely within basic map j.
+ * If so, replace the pair by the basic map consisting of the valid
+ * constraints in both basic maps.
+ * Checking whether the facet lies entirely within basic map j
+ * is performed by checking whether the constraints of basic map j
+ * are valid for the facet.  These tests are performed on a rational
+ * tableau to avoid the theoretical possibility that a constraint
+ * that was considered to be a cut constraint for the entire basic map i
+ * happens to be considered to be a valid constraint for the facet,
+ * even though it cuts off the same rational points.
+ *
+ * To see that we are not introducing any extra points, call the
+ * two basic maps A and B and the resulting map U and let x
+ * be an element of U \setminus ( A \cup B ).
+ * A line connecting x with an element of A \cup B meets a facet F
+ * of either A or B.  Assume it is a facet of B and let c_1 be
+ * the corresponding facet constraint.  We have c_1(x) < 0 and
+ * so c_1 is a cut constraint.  This implies that there is some
+ * (possibly rational) point x' satisfying the constraints of A
+ * and the opposite of c_1 as otherwise c_1 would have been marked
+ * valid for A.  The line connecting x and x' meets a facet of A
+ * in a (possibly rational) point that also violates c_1, but this
+ * is impossible since all cut constraints of B are valid for all
+ * cut facets of A.
+ * In case F is a facet of A rather than B, then we can apply the
+ * above reasoning to find a facet of B separating x from A \cup B first.
+ */
+static enum isl_change check_facets(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	int k, l;
+	struct isl_tab_undo *snap, *snap2;
+	unsigned n_eq = info[i].bmap->n_eq;
+
+	snap = isl_tab_snap(info[i].tab);
+	if (isl_tab_mark_rational(info[i].tab) < 0)
+		return isl_change_error;
+	snap2 = isl_tab_snap(info[i].tab);
+
+	for (k = 0; k < info[i].bmap->n_ineq; ++k) {
+		if (info[i].ineq[k] != STATUS_CUT)
+			continue;
+		if (isl_tab_select_facet(info[i].tab, n_eq + k) < 0)
+			return isl_change_error;
+		for (l = 0; l < info[j].bmap->n_ineq; ++l) {
+			int stat;
+			if (info[j].ineq[l] != STATUS_CUT)
+				continue;
+			stat = status_in(info[j].bmap->ineq[l], info[i].tab);
+			if (stat < 0)
+				return isl_change_error;
+			if (stat != STATUS_VALID)
+				break;
+		}
+		if (isl_tab_rollback(info[i].tab, snap2) < 0)
+			return isl_change_error;
+		if (l < info[j].bmap->n_ineq)
+			break;
+	}
+
+	if (k < info[i].bmap->n_ineq) {
+		if (isl_tab_rollback(info[i].tab, snap) < 0)
+			return isl_change_error;
+		return isl_change_none;
+	}
+	return fuse(i, j, info, NULL, 0, 0);
+}
+
+/* Check if info->bmap contains the basic map represented
+ * by the tableau "tab".
+ * For each equality, we check both the constraint itself
+ * (as an inequality) and its negation.  Make sure the
+ * equality is returned to its original state before returning.
+ */
+static isl_bool contains(struct isl_coalesce_info *info, struct isl_tab *tab)
+{
+	int k;
+	unsigned dim;
+	isl_basic_map *bmap = info->bmap;
+
+	dim = isl_basic_map_total_dim(bmap);
+	for (k = 0; k < bmap->n_eq; ++k) {
+		int stat;
+		isl_seq_neg(bmap->eq[k], bmap->eq[k], 1 + dim);
+		stat = status_in(bmap->eq[k], tab);
+		isl_seq_neg(bmap->eq[k], bmap->eq[k], 1 + dim);
+		if (stat < 0)
+			return isl_bool_error;
+		if (stat != STATUS_VALID)
+			return isl_bool_false;
+		stat = status_in(bmap->eq[k], tab);
+		if (stat < 0)
+			return isl_bool_error;
+		if (stat != STATUS_VALID)
+			return isl_bool_false;
+	}
+
+	for (k = 0; k < bmap->n_ineq; ++k) {
+		int stat;
+		if (info->ineq[k] == STATUS_REDUNDANT)
+			continue;
+		stat = status_in(bmap->ineq[k], tab);
+		if (stat < 0)
+			return isl_bool_error;
+		if (stat != STATUS_VALID)
+			return isl_bool_false;
+	}
+	return isl_bool_true;
+}
+
+/* Basic map "i" has an inequality (say "k") that is adjacent
+ * to some inequality of basic map "j".  All the other inequalities
+ * are valid for "j".
+ * Check if basic map "j" forms an extension of basic map "i".
+ *
+ * Note that this function is only called if some of the equalities or
+ * inequalities of basic map "j" do cut basic map "i".  The function is
+ * correct even if there are no such cut constraints, but in that case
+ * the additional checks performed by this function are overkill.
+ *
+ * In particular, we replace constraint k, say f >= 0, by constraint
+ * f <= -1, add the inequalities of "j" that are valid for "i"
+ * and check if the result is a subset of basic map "j".
+ * To improve the chances of the subset relation being detected,
+ * any variable that only attains a single integer value
+ * in the tableau of "i" is first fixed to that value.
+ * If the result is a subset, then we know that this result is exactly equal
+ * to basic map "j" since all its constraints are valid for basic map "j".
+ * By combining the valid constraints of "i" (all equalities and all
+ * inequalities except "k") and the valid constraints of "j" we therefore
+ * obtain a basic map that is equal to their union.
+ * In this case, there is no need to perform a rollback of the tableau
+ * since it is going to be destroyed in fuse().
+ *
+ *
+ *	|\__			|\__
+ *	|   \__			|   \__
+ *	|      \_	=>	|      \__
+ *	|_______| _		|_________\
+ *
+ *
+ *	|\			|\
+ *	| \			| \
+ *	|  \			|  \
+ *	|  |			|   \
+ *	|  ||\		=>      |    \
+ *	|  || \			|     \
+ *	|  ||  |		|      |
+ *	|__||_/			|_____/
+ */
+static enum isl_change is_adj_ineq_extension(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	int k;
+	struct isl_tab_undo *snap;
+	unsigned n_eq = info[i].bmap->n_eq;
+	unsigned total = isl_basic_map_total_dim(info[i].bmap);
+	isl_stat r;
+	isl_bool super;
+
+	if (isl_tab_extend_cons(info[i].tab, 1 + info[j].bmap->n_ineq) < 0)
+		return isl_change_error;
+
+	k = find(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_INEQ);
+	if (k < 0)
+		isl_die(isl_basic_map_get_ctx(info[i].bmap), isl_error_internal,
+			"info[i].ineq should have exactly one STATUS_ADJ_INEQ",
+			return isl_change_error);
+
+	snap = isl_tab_snap(info[i].tab);
+
+	if (isl_tab_unrestrict(info[i].tab, n_eq + k) < 0)
+		return isl_change_error;
+
+	isl_seq_neg(info[i].bmap->ineq[k], info[i].bmap->ineq[k], 1 + total);
+	isl_int_sub_ui(info[i].bmap->ineq[k][0], info[i].bmap->ineq[k][0], 1);
+	r = isl_tab_add_ineq(info[i].tab, info[i].bmap->ineq[k]);
+	isl_seq_neg(info[i].bmap->ineq[k], info[i].bmap->ineq[k], 1 + total);
+	isl_int_sub_ui(info[i].bmap->ineq[k][0], info[i].bmap->ineq[k][0], 1);
+	if (r < 0)
+		return isl_change_error;
+
+	for (k = 0; k < info[j].bmap->n_ineq; ++k) {
+		if (info[j].ineq[k] != STATUS_VALID)
+			continue;
+		if (isl_tab_add_ineq(info[i].tab, info[j].bmap->ineq[k]) < 0)
+			return isl_change_error;
+	}
+	if (isl_tab_detect_constants(info[i].tab) < 0)
+		return isl_change_error;
+
+	super = contains(&info[j], info[i].tab);
+	if (super < 0)
+		return isl_change_error;
+	if (super)
+		return fuse(i, j, info, NULL, 0, 0);
+
+	if (isl_tab_rollback(info[i].tab, snap) < 0)
+		return isl_change_error;
+
+	return isl_change_none;
+}
+
+
+/* Both basic maps have at least one inequality with and adjacent
+ * (but opposite) inequality in the other basic map.
+ * Check that there are no cut constraints and that there is only
+ * a single pair of adjacent inequalities.
+ * If so, we can replace the pair by a single basic map described
+ * by all but the pair of adjacent inequalities.
+ * Any additional points introduced lie strictly between the two
+ * adjacent hyperplanes and can therefore be integral.
+ *
+ *        ____			  _____
+ *       /    ||\		 /     \
+ *      /     || \		/       \
+ *      \     ||  \	=>	\        \
+ *       \    ||  /		 \       /
+ *        \___||_/		  \_____/
+ *
+ * The test for a single pair of adjancent inequalities is important
+ * for avoiding the combination of two basic maps like the following
+ *
+ *       /|
+ *      / |
+ *     /__|
+ *         _____
+ *         |   |
+ *         |   |
+ *         |___|
+ *
+ * If there are some cut constraints on one side, then we may
+ * still be able to fuse the two basic maps, but we need to perform
+ * some additional checks in is_adj_ineq_extension.
+ */
+static enum isl_change check_adj_ineq(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	int count_i, count_j;
+	int cut_i, cut_j;
+
+	count_i = count(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_INEQ);
+	count_j = count(info[j].ineq, info[j].bmap->n_ineq, STATUS_ADJ_INEQ);
+
+	if (count_i != 1 && count_j != 1)
+		return isl_change_none;
+
+	cut_i = any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_CUT) ||
+		any(info[i].ineq, info[i].bmap->n_ineq, STATUS_CUT);
+	cut_j = any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_CUT) ||
+		any(info[j].ineq, info[j].bmap->n_ineq, STATUS_CUT);
+
+	if (!cut_i && !cut_j && count_i == 1 && count_j == 1)
+		return fuse(i, j, info, NULL, 0, 0);
+
+	if (count_i == 1 && !cut_i)
+		return is_adj_ineq_extension(i, j, info);
+
+	if (count_j == 1 && !cut_j)
+		return is_adj_ineq_extension(j, i, info);
+
+	return isl_change_none;
+}
+
+/* Given an affine transformation matrix "T", does row "row" represent
+ * anything other than a unit vector (possibly shifted by a constant)
+ * that is not involved in any of the other rows?
+ *
+ * That is, if a constraint involves the variable corresponding to
+ * the row, then could its preimage by "T" have any coefficients
+ * that are different from those in the original constraint?
+ */
+static int not_unique_unit_row(__isl_keep isl_mat *T, int row)
+{
+	int i, j;
+	int len = T->n_col - 1;
+
+	i = isl_seq_first_non_zero(T->row[row] + 1, len);
+	if (i < 0)
+		return 1;
+	if (!isl_int_is_one(T->row[row][1 + i]) &&
+	    !isl_int_is_negone(T->row[row][1 + i]))
+		return 1;
+
+	j = isl_seq_first_non_zero(T->row[row] + 1 + i + 1, len - (i + 1));
+	if (j >= 0)
+		return 1;
+
+	for (j = 1; j < T->n_row; ++j) {
+		if (j == row)
+			continue;
+		if (!isl_int_is_zero(T->row[j][1 + i]))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Does inequality constraint "ineq" of "bmap" involve any of
+ * the variables marked in "affected"?
+ * "total" is the total number of variables, i.e., the number
+ * of entries in "affected".
+ */
+static isl_bool is_affected(__isl_keep isl_basic_map *bmap, int ineq,
+	int *affected, int total)
+{
+	int i;
+
+	for (i = 0; i < total; ++i) {
+		if (!affected[i])
+			continue;
+		if (!isl_int_is_zero(bmap->ineq[ineq][1 + i]))
+			return isl_bool_true;
+	}
+
+	return isl_bool_false;
+}
+
+/* Given the compressed version of inequality constraint "ineq"
+ * of info->bmap in "v", check if the constraint can be tightened,
+ * where the compression is based on an equality constraint valid
+ * for info->tab.
+ * If so, add the tightened version of the inequality constraint
+ * to info->tab.  "v" may be modified by this function.
+ *
+ * That is, if the compressed constraint is of the form
+ *
+ *	m f() + c >= 0
+ *
+ * with 0 < c < m, then it is equivalent to
+ *
+ *	f() >= 0
+ *
+ * This means that c can also be subtracted from the original,
+ * uncompressed constraint without affecting the integer points
+ * in info->tab.  Add this tightened constraint as an extra row
+ * to info->tab to make this information explicitly available.
+ */
+static __isl_give isl_vec *try_tightening(struct isl_coalesce_info *info,
+	int ineq, __isl_take isl_vec *v)
+{
+	isl_ctx *ctx;
+	isl_stat r;
+
+	if (!v)
+		return NULL;
+
+	ctx = isl_vec_get_ctx(v);
+	isl_seq_gcd(v->el + 1, v->size - 1, &ctx->normalize_gcd);
+	if (isl_int_is_zero(ctx->normalize_gcd) ||
+	    isl_int_is_one(ctx->normalize_gcd)) {
+		return v;
+	}
+
+	v = isl_vec_cow(v);
+	if (!v)
+		return NULL;
+
+	isl_int_fdiv_r(v->el[0], v->el[0], ctx->normalize_gcd);
+	if (isl_int_is_zero(v->el[0]))
+		return v;
+
+	if (isl_tab_extend_cons(info->tab, 1) < 0)
+		return isl_vec_free(v);
+
+	isl_int_sub(info->bmap->ineq[ineq][0],
+		    info->bmap->ineq[ineq][0], v->el[0]);
+	r = isl_tab_add_ineq(info->tab, info->bmap->ineq[ineq]);
+	isl_int_add(info->bmap->ineq[ineq][0],
+		    info->bmap->ineq[ineq][0], v->el[0]);
+
+	if (r < 0)
+		return isl_vec_free(v);
+
+	return v;
+}
+
+/* Tighten the (non-redundant) constraints on the facet represented
+ * by info->tab.
+ * In particular, on input, info->tab represents the result
+ * of relaxing the "n" inequality constraints of info->bmap in "relaxed"
+ * by one, i.e., replacing f_i >= 0 by f_i + 1 >= 0, and then
+ * replacing the one at index "l" by the corresponding equality,
+ * i.e., f_k + 1 = 0, with k = relaxed[l].
+ *
+ * Compute a variable compression from the equality constraint f_k + 1 = 0
+ * and use it to tighten the other constraints of info->bmap
+ * (that is, all constraints that have not been relaxed),
+ * updating info->tab (and leaving info->bmap untouched).
+ * The compression handles essentially two cases, one where a variable
+ * is assigned a fixed value and can therefore be eliminated, and one
+ * where one variable is a shifted multiple of some other variable and
+ * can therefore be replaced by that multiple.
+ * Gaussian elimination would also work for the first case, but for
+ * the second case, the effectiveness would depend on the order
+ * of the variables.
+ * After compression, some of the constraints may have coefficients
+ * with a common divisor.  If this divisor does not divide the constant
+ * term, then the constraint can be tightened.
+ * The tightening is performed on the tableau info->tab by introducing
+ * extra (temporary) constraints.
+ *
+ * Only constraints that are possibly affected by the compression are
+ * considered.  In particular, if the constraint only involves variables
+ * that are directly mapped to a distinct set of other variables, then
+ * no common divisor can be introduced and no tightening can occur.
+ *
+ * It is important to only consider the non-redundant constraints
+ * since the facet constraint has been relaxed prior to the call
+ * to this function, meaning that the constraints that were redundant
+ * prior to the relaxation may no longer be redundant.
+ * These constraints will be ignored in the fused result, so
+ * the fusion detection should not exploit them.
+ */
+static isl_stat tighten_on_relaxed_facet(struct isl_coalesce_info *info,
+	int n, int *relaxed, int l)
+{
+	unsigned total;
+	isl_ctx *ctx;
+	isl_vec *v = NULL;
+	isl_mat *T;
+	int i;
+	int k;
+	int *affected;
+
+	k = relaxed[l];
+	ctx = isl_basic_map_get_ctx(info->bmap);
+	total = isl_basic_map_total_dim(info->bmap);
+	isl_int_add_ui(info->bmap->ineq[k][0], info->bmap->ineq[k][0], 1);
+	T = isl_mat_sub_alloc6(ctx, info->bmap->ineq, k, 1, 0, 1 + total);
+	T = isl_mat_variable_compression(T, NULL);
+	isl_int_sub_ui(info->bmap->ineq[k][0], info->bmap->ineq[k][0], 1);
+	if (!T)
+		return isl_stat_error;
+	if (T->n_col == 0) {
+		isl_mat_free(T);
+		return isl_stat_ok;
+	}
+
+	affected = isl_alloc_array(ctx, int, total);
+	if (!affected)
+		goto error;
+
+	for (i = 0; i < total; ++i)
+		affected[i] = not_unique_unit_row(T, 1 + i);
+
+	for (i = 0; i < info->bmap->n_ineq; ++i) {
+		isl_bool handle;
+		if (any(relaxed, n, i))
+			continue;
+		if (info->ineq[i] == STATUS_REDUNDANT)
+			continue;
+		handle = is_affected(info->bmap, i, affected, total);
+		if (handle < 0)
+			goto error;
+		if (!handle)
+			continue;
+		v = isl_vec_alloc(ctx, 1 + total);
+		if (!v)
+			goto error;
+		isl_seq_cpy(v->el, info->bmap->ineq[i], 1 + total);
+		v = isl_vec_mat_product(v, isl_mat_copy(T));
+		v = try_tightening(info, i, v);
+		isl_vec_free(v);
+		if (!v)
+			goto error;
+	}
+
+	isl_mat_free(T);
+	free(affected);
+	return isl_stat_ok;
+error:
+	isl_mat_free(T);
+	free(affected);
+	return isl_stat_error;
+}
+
+/* Replace the basic maps "i" and "j" by an extension of "i"
+ * along the "n" inequality constraints in "relax" by one.
+ * The tableau info[i].tab has already been extended.
+ * Extend info[i].bmap accordingly by relaxing all constraints in "relax"
+ * by one.
+ * Each integer division that does not have exactly the same
+ * definition in "i" and "j" is marked unknown and the basic map
+ * is scheduled to be simplified in an attempt to recover
+ * the integer division definition.
+ * Place the extension in the position that is the smallest of i and j.
+ */
+static enum isl_change extend(int i, int j, int n, int *relax,
+	struct isl_coalesce_info *info)
+{
+	int l;
+	unsigned total;
+
+	info[i].bmap = isl_basic_map_cow(info[i].bmap);
+	if (!info[i].bmap)
+		return isl_change_error;
+	total = isl_basic_map_total_dim(info[i].bmap);
+	for (l = 0; l < info[i].bmap->n_div; ++l)
+		if (!isl_seq_eq(info[i].bmap->div[l],
+				info[j].bmap->div[l], 1 + 1 + total)) {
+			isl_int_set_si(info[i].bmap->div[l][0], 0);
+			info[i].simplify = 1;
+		}
+	for (l = 0; l < n; ++l)
+		isl_int_add_ui(info[i].bmap->ineq[relax[l]][0],
+				info[i].bmap->ineq[relax[l]][0], 1);
+	ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_FINAL);
+	drop(&info[j]);
+	if (j < i)
+		exchange(&info[i], &info[j]);
+	return isl_change_fuse;
+}
+
+/* Basic map "i" has "n" inequality constraints (collected in "relax")
+ * that are such that they include basic map "j" if they are relaxed
+ * by one.  All the other inequalities are valid for "j".
+ * Check if basic map "j" forms an extension of basic map "i".
+ *
+ * In particular, relax the constraints in "relax", compute the corresponding
+ * facets one by one and check whether each of these is included
+ * in the other basic map.
+ * Before testing for inclusion, the constraints on each facet
+ * are tightened to increase the chance of an inclusion being detected.
+ * (Adding the valid constraints of "j" to the tableau of "i", as is done
+ * in is_adj_ineq_extension, may further increase those chances, but this
+ * is not currently done.)
+ * If each facet is included, we know that relaxing the constraints extends
+ * the basic map with exactly the other basic map (we already know that this
+ * other basic map is included in the extension, because all other
+ * inequality constraints are valid of "j") and we can replace the
+ * two basic maps by this extension.
+ *
+ * If any of the relaxed constraints turn out to be redundant, then bail out.
+ * isl_tab_select_facet refuses to handle such constraints.  It may be
+ * possible to handle them anyway by making a distinction between
+ * redundant constraints with a corresponding facet that still intersects
+ * the set (allowing isl_tab_select_facet to handle them) and
+ * those where the facet does not intersect the set (which can be ignored
+ * because the empty facet is trivially included in the other disjunct).
+ * However, relaxed constraints that turn out to be redundant should
+ * be fairly rare and no such instance has been reported where
+ * coalescing would be successful.
+ *        ____			  _____
+ *       /    || 		 /     |
+ *      /     ||  		/      |
+ *      \     ||   	=>	\      |
+ *       \    ||		 \     |
+ *        \___||		  \____|
+ *
+ *
+ *	 \			|\
+ *	|\\			| \
+ *	| \\			|  \
+ *	|  |		=>	|  /
+ *	| /			| /
+ *	|/			|/
+ */
+static enum isl_change is_relaxed_extension(int i, int j, int n, int *relax,
+	struct isl_coalesce_info *info)
+{
+	int l;
+	isl_bool super;
+	struct isl_tab_undo *snap, *snap2;
+	unsigned n_eq = info[i].bmap->n_eq;
+
+	for (l = 0; l < n; ++l)
+		if (isl_tab_is_equality(info[i].tab, n_eq + relax[l]))
+			return isl_change_none;
+
+	snap = isl_tab_snap(info[i].tab);
+	for (l = 0; l < n; ++l)
+		if (isl_tab_relax(info[i].tab, n_eq + relax[l]) < 0)
+			return isl_change_error;
+	for (l = 0; l < n; ++l) {
+		if (!isl_tab_is_redundant(info[i].tab, n_eq + relax[l]))
+			continue;
+		if (isl_tab_rollback(info[i].tab, snap) < 0)
+			return isl_change_error;
+		return isl_change_none;
+	}
+	snap2 = isl_tab_snap(info[i].tab);
+	for (l = 0; l < n; ++l) {
+		if (isl_tab_rollback(info[i].tab, snap2) < 0)
+			return isl_change_error;
+		if (isl_tab_select_facet(info[i].tab, n_eq + relax[l]) < 0)
+			return isl_change_error;
+		if (tighten_on_relaxed_facet(&info[i], n, relax, l) < 0)
+			return isl_change_error;
+		super = contains(&info[j], info[i].tab);
+		if (super < 0)
+			return isl_change_error;
+		if (super)
+			continue;
+		if (isl_tab_rollback(info[i].tab, snap) < 0)
+			return isl_change_error;
+		return isl_change_none;
+	}
+
+	if (isl_tab_rollback(info[i].tab, snap2) < 0)
+		return isl_change_error;
+	return extend(i, j, n, relax, info);
+}
+
+/* Data structure that keeps track of the wrapping constraints
+ * and of information to bound the coefficients of those constraints.
+ *
+ * bound is set if we want to apply a bound on the coefficients
+ * mat contains the wrapping constraints
+ * max is the bound on the coefficients (if bound is set)
+ */
+struct isl_wraps {
+	int bound;
+	isl_mat *mat;
+	isl_int max;
+};
+
+/* Update wraps->max to be greater than or equal to the coefficients
+ * in the equalities and inequalities of info->bmap that can be removed
+ * if we end up applying wrapping.
+ */
+static isl_stat wraps_update_max(struct isl_wraps *wraps,
+	struct isl_coalesce_info *info)
+{
+	int k;
+	isl_int max_k;
+	unsigned total = isl_basic_map_total_dim(info->bmap);
+
+	isl_int_init(max_k);
+
+	for (k = 0; k < info->bmap->n_eq; ++k) {
+		if (info->eq[2 * k] == STATUS_VALID &&
+		    info->eq[2 * k + 1] == STATUS_VALID)
+			continue;
+		isl_seq_abs_max(info->bmap->eq[k] + 1, total, &max_k);
+		if (isl_int_abs_gt(max_k, wraps->max))
+			isl_int_set(wraps->max, max_k);
+	}
+
+	for (k = 0; k < info->bmap->n_ineq; ++k) {
+		if (info->ineq[k] == STATUS_VALID ||
+		    info->ineq[k] == STATUS_REDUNDANT)
+			continue;
+		isl_seq_abs_max(info->bmap->ineq[k] + 1, total, &max_k);
+		if (isl_int_abs_gt(max_k, wraps->max))
+			isl_int_set(wraps->max, max_k);
+	}
+
+	isl_int_clear(max_k);
+
+	return isl_stat_ok;
+}
+
+/* Initialize the isl_wraps data structure.
+ * If we want to bound the coefficients of the wrapping constraints,
+ * we set wraps->max to the largest coefficient
+ * in the equalities and inequalities that can be removed if we end up
+ * applying wrapping.
+ */
+static isl_stat wraps_init(struct isl_wraps *wraps, __isl_take isl_mat *mat,
+	struct isl_coalesce_info *info, int i, int j)
+{
+	isl_ctx *ctx;
+
+	wraps->bound = 0;
+	wraps->mat = mat;
+	if (!mat)
+		return isl_stat_error;
+	ctx = isl_mat_get_ctx(mat);
+	wraps->bound = isl_options_get_coalesce_bounded_wrapping(ctx);
+	if (!wraps->bound)
+		return isl_stat_ok;
+	isl_int_init(wraps->max);
+	isl_int_set_si(wraps->max, 0);
+	if (wraps_update_max(wraps, &info[i]) < 0)
+		return isl_stat_error;
+	if (wraps_update_max(wraps, &info[j]) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Free the contents of the isl_wraps data structure.
+ */
+static void wraps_free(struct isl_wraps *wraps)
+{
+	isl_mat_free(wraps->mat);
+	if (wraps->bound)
+		isl_int_clear(wraps->max);
+}
+
+/* Is the wrapping constraint in row "row" allowed?
+ *
+ * If wraps->bound is set, we check that none of the coefficients
+ * is greater than wraps->max.
+ */
+static int allow_wrap(struct isl_wraps *wraps, int row)
+{
+	int i;
+
+	if (!wraps->bound)
+		return 1;
+
+	for (i = 1; i < wraps->mat->n_col; ++i)
+		if (isl_int_abs_gt(wraps->mat->row[row][i], wraps->max))
+			return 0;
+
+	return 1;
+}
+
+/* Wrap "ineq" (or its opposite if "negate" is set) around "bound"
+ * to include "set" and add the result in position "w" of "wraps".
+ * "len" is the total number of coefficients in "bound" and "ineq".
+ * Return 1 on success, 0 on failure and -1 on error.
+ * Wrapping can fail if the result of wrapping is equal to "bound"
+ * or if we want to bound the sizes of the coefficients and
+ * the wrapped constraint does not satisfy this bound.
+ */
+static int add_wrap(struct isl_wraps *wraps, int w, isl_int *bound,
+	isl_int *ineq, unsigned len, __isl_keep isl_set *set, int negate)
+{
+	isl_seq_cpy(wraps->mat->row[w], bound, len);
+	if (negate) {
+		isl_seq_neg(wraps->mat->row[w + 1], ineq, len);
+		ineq = wraps->mat->row[w + 1];
+	}
+	if (!isl_set_wrap_facet(set, wraps->mat->row[w], ineq))
+		return -1;
+	if (isl_seq_eq(wraps->mat->row[w], bound, len))
+		return 0;
+	if (!allow_wrap(wraps, w))
+		return 0;
+	return 1;
+}
+
+/* For each constraint in info->bmap that is not redundant (as determined
+ * by info->tab) and that is not a valid constraint for the other basic map,
+ * wrap the constraint around "bound" such that it includes the whole
+ * set "set" and append the resulting constraint to "wraps".
+ * Note that the constraints that are valid for the other basic map
+ * will be added to the combined basic map by default, so there is
+ * no need to wrap them.
+ * The caller wrap_in_facets even relies on this function not wrapping
+ * any constraints that are already valid.
+ * "wraps" is assumed to have been pre-allocated to the appropriate size.
+ * wraps->n_row is the number of actual wrapped constraints that have
+ * been added.
+ * If any of the wrapping problems results in a constraint that is
+ * identical to "bound", then this means that "set" is unbounded in such
+ * way that no wrapping is possible.  If this happens then wraps->n_row
+ * is reset to zero.
+ * Similarly, if we want to bound the coefficients of the wrapping
+ * constraints and a newly added wrapping constraint does not
+ * satisfy the bound, then wraps->n_row is also reset to zero.
+ */
+static isl_stat add_wraps(struct isl_wraps *wraps,
+	struct isl_coalesce_info *info, isl_int *bound, __isl_keep isl_set *set)
+{
+	int l, m;
+	int w;
+	int added;
+	isl_basic_map *bmap = info->bmap;
+	unsigned len = 1 + isl_basic_map_total_dim(bmap);
+
+	w = wraps->mat->n_row;
+
+	for (l = 0; l < bmap->n_ineq; ++l) {
+		if (info->ineq[l] == STATUS_VALID ||
+		    info->ineq[l] == STATUS_REDUNDANT)
+			continue;
+		if (isl_seq_is_neg(bound, bmap->ineq[l], len))
+			continue;
+		if (isl_seq_eq(bound, bmap->ineq[l], len))
+			continue;
+		if (isl_tab_is_redundant(info->tab, bmap->n_eq + l))
+			continue;
+
+		added = add_wrap(wraps, w, bound, bmap->ineq[l], len, set, 0);
+		if (added < 0)
+			return isl_stat_error;
+		if (!added)
+			goto unbounded;
+		++w;
+	}
+	for (l = 0; l < bmap->n_eq; ++l) {
+		if (isl_seq_is_neg(bound, bmap->eq[l], len))
+			continue;
+		if (isl_seq_eq(bound, bmap->eq[l], len))
+			continue;
+
+		for (m = 0; m < 2; ++m) {
+			if (info->eq[2 * l + m] == STATUS_VALID)
+				continue;
+			added = add_wrap(wraps, w, bound, bmap->eq[l], len,
+					set, !m);
+			if (added < 0)
+				return isl_stat_error;
+			if (!added)
+				goto unbounded;
+			++w;
+		}
+	}
+
+	wraps->mat->n_row = w;
+	return isl_stat_ok;
+unbounded:
+	wraps->mat->n_row = 0;
+	return isl_stat_ok;
+}
+
+/* Check if the constraints in "wraps" from "first" until the last
+ * are all valid for the basic set represented by "tab".
+ * If not, wraps->n_row is set to zero.
+ */
+static int check_wraps(__isl_keep isl_mat *wraps, int first,
+	struct isl_tab *tab)
+{
+	int i;
+
+	for (i = first; i < wraps->n_row; ++i) {
+		enum isl_ineq_type type;
+		type = isl_tab_ineq_type(tab, wraps->row[i]);
+		if (type == isl_ineq_error)
+			return -1;
+		if (type == isl_ineq_redundant)
+			continue;
+		wraps->n_row = 0;
+		return 0;
+	}
+
+	return 0;
+}
+
+/* Return a set that corresponds to the non-redundant constraints
+ * (as recorded in tab) of bmap.
+ *
+ * It's important to remove the redundant constraints as some
+ * of the other constraints may have been modified after the
+ * constraints were marked redundant.
+ * In particular, a constraint may have been relaxed.
+ * Redundant constraints are ignored when a constraint is relaxed
+ * and should therefore continue to be ignored ever after.
+ * Otherwise, the relaxation might be thwarted by some of
+ * these constraints.
+ *
+ * Update the underlying set to ensure that the dimension doesn't change.
+ * Otherwise the integer divisions could get dropped if the tab
+ * turns out to be empty.
+ */
+static __isl_give isl_set *set_from_updated_bmap(__isl_keep isl_basic_map *bmap,
+	struct isl_tab *tab)
+{
+	isl_basic_set *bset;
+
+	bmap = isl_basic_map_copy(bmap);
+	bset = isl_basic_map_underlying_set(bmap);
+	bset = isl_basic_set_cow(bset);
+	bset = isl_basic_set_update_from_tab(bset, tab);
+	return isl_set_from_basic_set(bset);
+}
+
+/* Wrap the constraints of info->bmap that bound the facet defined
+ * by inequality "k" around (the opposite of) this inequality to
+ * include "set".  "bound" may be used to store the negated inequality.
+ * Since the wrapped constraints are not guaranteed to contain the whole
+ * of info->bmap, we check them in check_wraps.
+ * If any of the wrapped constraints turn out to be invalid, then
+ * check_wraps will reset wrap->n_row to zero.
+ */
+static isl_stat add_wraps_around_facet(struct isl_wraps *wraps,
+	struct isl_coalesce_info *info, int k, isl_int *bound,
+	__isl_keep isl_set *set)
+{
+	struct isl_tab_undo *snap;
+	int n;
+	unsigned total = isl_basic_map_total_dim(info->bmap);
+
+	snap = isl_tab_snap(info->tab);
+
+	if (isl_tab_select_facet(info->tab, info->bmap->n_eq + k) < 0)
+		return isl_stat_error;
+	if (isl_tab_detect_redundant(info->tab) < 0)
+		return isl_stat_error;
+
+	isl_seq_neg(bound, info->bmap->ineq[k], 1 + total);
+
+	n = wraps->mat->n_row;
+	if (add_wraps(wraps, info, bound, set) < 0)
+		return isl_stat_error;
+
+	if (isl_tab_rollback(info->tab, snap) < 0)
+		return isl_stat_error;
+	if (check_wraps(wraps->mat, n, info->tab) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Given a basic set i with a constraint k that is adjacent to
+ * basic set j, check if we can wrap
+ * both the facet corresponding to k (if "wrap_facet" is set) and basic map j
+ * (always) around their ridges to include the other set.
+ * If so, replace the pair of basic sets by their union.
+ *
+ * All constraints of i (except k) are assumed to be valid or
+ * cut constraints for j.
+ * Wrapping the cut constraints to include basic map j may result
+ * in constraints that are no longer valid of basic map i
+ * we have to check that the resulting wrapping constraints are valid for i.
+ * If "wrap_facet" is not set, then all constraints of i (except k)
+ * are assumed to be valid for j.
+ *        ____			  _____
+ *       /    | 		 /     \
+ *      /     ||  		/      |
+ *      \     ||   	=>	\      |
+ *       \    ||		 \     |
+ *        \___||		  \____|
+ *
+ */
+static enum isl_change can_wrap_in_facet(int i, int j, int k,
+	struct isl_coalesce_info *info, int wrap_facet)
+{
+	enum isl_change change = isl_change_none;
+	struct isl_wraps wraps;
+	isl_ctx *ctx;
+	isl_mat *mat;
+	struct isl_set *set_i = NULL;
+	struct isl_set *set_j = NULL;
+	struct isl_vec *bound = NULL;
+	unsigned total = isl_basic_map_total_dim(info[i].bmap);
+
+	set_i = set_from_updated_bmap(info[i].bmap, info[i].tab);
+	set_j = set_from_updated_bmap(info[j].bmap, info[j].tab);
+	ctx = isl_basic_map_get_ctx(info[i].bmap);
+	mat = isl_mat_alloc(ctx, 2 * (info[i].bmap->n_eq + info[j].bmap->n_eq) +
+				    info[i].bmap->n_ineq + info[j].bmap->n_ineq,
+				    1 + total);
+	if (wraps_init(&wraps, mat, info, i, j) < 0)
+		goto error;
+	bound = isl_vec_alloc(ctx, 1 + total);
+	if (!set_i || !set_j || !bound)
+		goto error;
+
+	isl_seq_cpy(bound->el, info[i].bmap->ineq[k], 1 + total);
+	isl_int_add_ui(bound->el[0], bound->el[0], 1);
+
+	isl_seq_cpy(wraps.mat->row[0], bound->el, 1 + total);
+	wraps.mat->n_row = 1;
+
+	if (add_wraps(&wraps, &info[j], bound->el, set_i) < 0)
+		goto error;
+	if (!wraps.mat->n_row)
+		goto unbounded;
+
+	if (wrap_facet) {
+		if (add_wraps_around_facet(&wraps, &info[i], k,
+					    bound->el, set_j) < 0)
+			goto error;
+		if (!wraps.mat->n_row)
+			goto unbounded;
+	}
+
+	change = fuse(i, j, info, wraps.mat, 0, 0);
+
+unbounded:
+	wraps_free(&wraps);
+
+	isl_set_free(set_i);
+	isl_set_free(set_j);
+
+	isl_vec_free(bound);
+
+	return change;
+error:
+	wraps_free(&wraps);
+	isl_vec_free(bound);
+	isl_set_free(set_i);
+	isl_set_free(set_j);
+	return isl_change_error;
+}
+
+/* Given a cut constraint t(x) >= 0 of basic map i, stored in row "w"
+ * of wrap.mat, replace it by its relaxed version t(x) + 1 >= 0, and
+ * add wrapping constraints to wrap.mat for all constraints
+ * of basic map j that bound the part of basic map j that sticks out
+ * of the cut constraint.
+ * "set_i" is the underlying set of basic map i.
+ * If any wrapping fails, then wraps->mat.n_row is reset to zero.
+ *
+ * In particular, we first intersect basic map j with t(x) + 1 = 0.
+ * If the result is empty, then t(x) >= 0 was actually a valid constraint
+ * (with respect to the integer points), so we add t(x) >= 0 instead.
+ * Otherwise, we wrap the constraints of basic map j that are not
+ * redundant in this intersection and that are not already valid
+ * for basic map i over basic map i.
+ * Note that it is sufficient to wrap the constraints to include
+ * basic map i, because we will only wrap the constraints that do
+ * not include basic map i already.  The wrapped constraint will
+ * therefore be more relaxed compared to the original constraint.
+ * Since the original constraint is valid for basic map j, so is
+ * the wrapped constraint.
+ */
+static isl_stat wrap_in_facet(struct isl_wraps *wraps, int w,
+	struct isl_coalesce_info *info_j, __isl_keep isl_set *set_i,
+	struct isl_tab_undo *snap)
+{
+	isl_int_add_ui(wraps->mat->row[w][0], wraps->mat->row[w][0], 1);
+	if (isl_tab_add_eq(info_j->tab, wraps->mat->row[w]) < 0)
+		return isl_stat_error;
+	if (isl_tab_detect_redundant(info_j->tab) < 0)
+		return isl_stat_error;
+
+	if (info_j->tab->empty)
+		isl_int_sub_ui(wraps->mat->row[w][0], wraps->mat->row[w][0], 1);
+	else if (add_wraps(wraps, info_j, wraps->mat->row[w], set_i) < 0)
+		return isl_stat_error;
+
+	if (isl_tab_rollback(info_j->tab, snap) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Given a pair of basic maps i and j such that j sticks out
+ * of i at n cut constraints, each time by at most one,
+ * try to compute wrapping constraints and replace the two
+ * basic maps by a single basic map.
+ * The other constraints of i are assumed to be valid for j.
+ * "set_i" is the underlying set of basic map i.
+ * "wraps" has been initialized to be of the right size.
+ *
+ * For each cut constraint t(x) >= 0 of i, we add the relaxed version
+ * t(x) + 1 >= 0, along with wrapping constraints for all constraints
+ * of basic map j that bound the part of basic map j that sticks out
+ * of the cut constraint.
+ *
+ * If any wrapping fails, i.e., if we cannot wrap to touch
+ * the union, then we give up.
+ * Otherwise, the pair of basic maps is replaced by their union.
+ */
+static enum isl_change try_wrap_in_facets(int i, int j,
+	struct isl_coalesce_info *info, struct isl_wraps *wraps,
+	__isl_keep isl_set *set_i)
+{
+	int k, l, w;
+	unsigned total;
+	struct isl_tab_undo *snap;
+
+	total = isl_basic_map_total_dim(info[i].bmap);
+
+	snap = isl_tab_snap(info[j].tab);
+
+	wraps->mat->n_row = 0;
+
+	for (k = 0; k < info[i].bmap->n_eq; ++k) {
+		for (l = 0; l < 2; ++l) {
+			if (info[i].eq[2 * k + l] != STATUS_CUT)
+				continue;
+			w = wraps->mat->n_row++;
+			if (l == 0)
+				isl_seq_neg(wraps->mat->row[w],
+					    info[i].bmap->eq[k], 1 + total);
+			else
+				isl_seq_cpy(wraps->mat->row[w],
+					    info[i].bmap->eq[k], 1 + total);
+			if (wrap_in_facet(wraps, w, &info[j], set_i, snap) < 0)
+				return isl_change_error;
+
+			if (!wraps->mat->n_row)
+				return isl_change_none;
+		}
+	}
+
+	for (k = 0; k < info[i].bmap->n_ineq; ++k) {
+		if (info[i].ineq[k] != STATUS_CUT)
+			continue;
+		w = wraps->mat->n_row++;
+		isl_seq_cpy(wraps->mat->row[w],
+			    info[i].bmap->ineq[k], 1 + total);
+		if (wrap_in_facet(wraps, w, &info[j], set_i, snap) < 0)
+			return isl_change_error;
+
+		if (!wraps->mat->n_row)
+			return isl_change_none;
+	}
+
+	return fuse(i, j, info, wraps->mat, 0, 1);
+}
+
+/* Given a pair of basic maps i and j such that j sticks out
+ * of i at n cut constraints, each time by at most one,
+ * try to compute wrapping constraints and replace the two
+ * basic maps by a single basic map.
+ * The other constraints of i are assumed to be valid for j.
+ *
+ * The core computation is performed by try_wrap_in_facets.
+ * This function simply extracts an underlying set representation
+ * of basic map i and initializes the data structure for keeping
+ * track of wrapping constraints.
+ */
+static enum isl_change wrap_in_facets(int i, int j, int n,
+	struct isl_coalesce_info *info)
+{
+	enum isl_change change = isl_change_none;
+	struct isl_wraps wraps;
+	isl_ctx *ctx;
+	isl_mat *mat;
+	isl_set *set_i = NULL;
+	unsigned total = isl_basic_map_total_dim(info[i].bmap);
+	int max_wrap;
+
+	if (isl_tab_extend_cons(info[j].tab, 1) < 0)
+		return isl_change_error;
+
+	max_wrap = 1 + 2 * info[j].bmap->n_eq + info[j].bmap->n_ineq;
+	max_wrap *= n;
+
+	set_i = set_from_updated_bmap(info[i].bmap, info[i].tab);
+	ctx = isl_basic_map_get_ctx(info[i].bmap);
+	mat = isl_mat_alloc(ctx, max_wrap, 1 + total);
+	if (wraps_init(&wraps, mat, info, i, j) < 0)
+		goto error;
+	if (!set_i)
+		goto error;
+
+	change = try_wrap_in_facets(i, j, info, &wraps, set_i);
+
+	wraps_free(&wraps);
+	isl_set_free(set_i);
+
+	return change;
+error:
+	wraps_free(&wraps);
+	isl_set_free(set_i);
+	return isl_change_error;
+}
+
+/* Return the effect of inequality "ineq" on the tableau "tab",
+ * after relaxing the constant term of "ineq" by one.
+ */
+static enum isl_ineq_type type_of_relaxed(struct isl_tab *tab, isl_int *ineq)
+{
+	enum isl_ineq_type type;
+
+	isl_int_add_ui(ineq[0], ineq[0], 1);
+	type = isl_tab_ineq_type(tab, ineq);
+	isl_int_sub_ui(ineq[0], ineq[0], 1);
+
+	return type;
+}
+
+/* Given two basic sets i and j,
+ * check if relaxing all the cut constraints of i by one turns
+ * them into valid constraint for j and check if we can wrap in
+ * the bits that are sticking out.
+ * If so, replace the pair by their union.
+ *
+ * We first check if all relaxed cut inequalities of i are valid for j
+ * and then try to wrap in the intersections of the relaxed cut inequalities
+ * with j.
+ *
+ * During this wrapping, we consider the points of j that lie at a distance
+ * of exactly 1 from i.  In particular, we ignore the points that lie in
+ * between this lower-dimensional space and the basic map i.
+ * We can therefore only apply this to integer maps.
+ *        ____			  _____
+ *       / ___|_		 /     \
+ *      / |    |  		/      |
+ *      \ |    |   	=>	\      |
+ *       \|____|		 \     |
+ *        \___| 		  \____/
+ *
+ *	 _____			 ______
+ *	| ____|_		|      \
+ *	| |     |		|       |
+ *	| |	|	=>	|       |
+ *	|_|     |		|       |
+ *	  |_____|		 \______|
+ *
+ *	 _______
+ *	|       |
+ *	|  |\   |
+ *	|  | \  |
+ *	|  |  \ |
+ *	|  |   \|
+ *	|  |    \
+ *	|  |_____\
+ *	|       |
+ *	|_______|
+ *
+ * Wrapping can fail if the result of wrapping one of the facets
+ * around its edges does not produce any new facet constraint.
+ * In particular, this happens when we try to wrap in unbounded sets.
+ *
+ *	 _______________________________________________________________________
+ *	|
+ *	|  ___
+ *	| |   |
+ *	|_|   |_________________________________________________________________
+ *	  |___|
+ *
+ * The following is not an acceptable result of coalescing the above two
+ * sets as it includes extra integer points.
+ *	 _______________________________________________________________________
+ *	|
+ *	|     
+ *	|      
+ *	|
+ *	 \______________________________________________________________________
+ */
+static enum isl_change can_wrap_in_set(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	int k, l;
+	int n;
+	unsigned total;
+
+	if (ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_RATIONAL) ||
+	    ISL_F_ISSET(info[j].bmap, ISL_BASIC_MAP_RATIONAL))
+		return isl_change_none;
+
+	n = count(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_CUT);
+	n += count(info[i].ineq, info[i].bmap->n_ineq, STATUS_CUT);
+	if (n == 0)
+		return isl_change_none;
+
+	total = isl_basic_map_total_dim(info[i].bmap);
+	for (k = 0; k < info[i].bmap->n_eq; ++k) {
+		for (l = 0; l < 2; ++l) {
+			enum isl_ineq_type type;
+
+			if (info[i].eq[2 * k + l] != STATUS_CUT)
+				continue;
+
+			if (l == 0)
+				isl_seq_neg(info[i].bmap->eq[k],
+					    info[i].bmap->eq[k], 1 + total);
+			type = type_of_relaxed(info[j].tab,
+					    info[i].bmap->eq[k]);
+			if (l == 0)
+				isl_seq_neg(info[i].bmap->eq[k],
+					    info[i].bmap->eq[k], 1 + total);
+			if (type == isl_ineq_error)
+				return isl_change_error;
+			if (type != isl_ineq_redundant)
+				return isl_change_none;
+		}
+	}
+
+	for (k = 0; k < info[i].bmap->n_ineq; ++k) {
+		enum isl_ineq_type type;
+
+		if (info[i].ineq[k] != STATUS_CUT)
+			continue;
+
+		type = type_of_relaxed(info[j].tab, info[i].bmap->ineq[k]);
+		if (type == isl_ineq_error)
+			return isl_change_error;
+		if (type != isl_ineq_redundant)
+			return isl_change_none;
+	}
+
+	return wrap_in_facets(i, j, n, info);
+}
+
+/* Check if either i or j has only cut constraints that can
+ * be used to wrap in (a facet of) the other basic set.
+ * if so, replace the pair by their union.
+ */
+static enum isl_change check_wrap(int i, int j, struct isl_coalesce_info *info)
+{
+	enum isl_change change = isl_change_none;
+
+	change = can_wrap_in_set(i, j, info);
+	if (change != isl_change_none)
+		return change;
+
+	change = can_wrap_in_set(j, i, info);
+	return change;
+}
+
+/* Check if all inequality constraints of "i" that cut "j" cease
+ * to be cut constraints if they are relaxed by one.
+ * If so, collect the cut constraints in "list".
+ * The caller is responsible for allocating "list".
+ */
+static isl_bool all_cut_by_one(int i, int j, struct isl_coalesce_info *info,
+	int *list)
+{
+	int l, n;
+
+	n = 0;
+	for (l = 0; l < info[i].bmap->n_ineq; ++l) {
+		enum isl_ineq_type type;
+
+		if (info[i].ineq[l] != STATUS_CUT)
+			continue;
+		type = type_of_relaxed(info[j].tab, info[i].bmap->ineq[l]);
+		if (type == isl_ineq_error)
+			return isl_bool_error;
+		if (type != isl_ineq_redundant)
+			return isl_bool_false;
+		list[n++] = l;
+	}
+
+	return isl_bool_true;
+}
+
+/* Given two basic maps such that "j" has at least one equality constraint
+ * that is adjacent to an inequality constraint of "i" and such that "i" has
+ * exactly one inequality constraint that is adjacent to an equality
+ * constraint of "j", check whether "i" can be extended to include "j" or
+ * whether "j" can be wrapped into "i".
+ * All remaining constraints of "i" and "j" are assumed to be valid
+ * or cut constraints of the other basic map.
+ * However, none of the equality constraints of "i" are cut constraints.
+ *
+ * If "i" has any "cut" inequality constraints, then check if relaxing
+ * each of them by one is sufficient for them to become valid.
+ * If so, check if the inequality constraint adjacent to an equality
+ * constraint of "j" along with all these cut constraints
+ * can be relaxed by one to contain exactly "j".
+ * Otherwise, or if this fails, check if "j" can be wrapped into "i".
+ */
+static enum isl_change check_single_adj_eq(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	enum isl_change change = isl_change_none;
+	int k;
+	int n_cut;
+	int *relax;
+	isl_ctx *ctx;
+	isl_bool try_relax;
+
+	n_cut = count(info[i].ineq, info[i].bmap->n_ineq, STATUS_CUT);
+
+	k = find(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_EQ);
+
+	if (n_cut > 0) {
+		ctx = isl_basic_map_get_ctx(info[i].bmap);
+		relax = isl_calloc_array(ctx, int, 1 + n_cut);
+		if (!relax)
+			return isl_change_error;
+		relax[0] = k;
+		try_relax = all_cut_by_one(i, j, info, relax + 1);
+		if (try_relax < 0)
+			change = isl_change_error;
+	} else {
+		try_relax = isl_bool_true;
+		relax = &k;
+	}
+	if (try_relax && change == isl_change_none)
+		change = is_relaxed_extension(i, j, 1 + n_cut, relax, info);
+	if (n_cut > 0)
+		free(relax);
+	if (change != isl_change_none)
+		return change;
+
+	change = can_wrap_in_facet(i, j, k, info, n_cut > 0);
+
+	return change;
+}
+
+/* At least one of the basic maps has an equality that is adjacent
+ * to inequality.  Make sure that only one of the basic maps has
+ * such an equality and that the other basic map has exactly one
+ * inequality adjacent to an equality.
+ * If the other basic map does not have such an inequality, then
+ * check if all its constraints are either valid or cut constraints
+ * and, if so, try wrapping in the first map into the second.
+ * Otherwise, try to extend one basic map with the other or
+ * wrap one basic map in the other.
+ */
+static enum isl_change check_adj_eq(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ADJ_INEQ) &&
+	    any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_ADJ_INEQ))
+		/* ADJ EQ TOO MANY */
+		return isl_change_none;
+
+	if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ADJ_INEQ))
+		return check_adj_eq(j, i, info);
+
+	/* j has an equality adjacent to an inequality in i */
+
+	if (count(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_EQ) != 1) {
+		if (all_valid_or_cut(&info[i]))
+			return can_wrap_in_set(i, j, info);
+		return isl_change_none;
+	}
+	if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_CUT))
+		return isl_change_none;
+	if (any(info[j].ineq, info[j].bmap->n_ineq, STATUS_ADJ_EQ) ||
+	    any(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_INEQ) ||
+	    any(info[j].ineq, info[j].bmap->n_ineq, STATUS_ADJ_INEQ))
+		/* ADJ EQ TOO MANY */
+		return isl_change_none;
+
+	return check_single_adj_eq(i, j, info);
+}
+
+/* The two basic maps lie on adjacent hyperplanes.  In particular,
+ * basic map "i" has an equality that lies parallel to basic map "j".
+ * Check if we can wrap the facets around the parallel hyperplanes
+ * to include the other set.
+ *
+ * We perform basically the same operations as can_wrap_in_facet,
+ * except that we don't need to select a facet of one of the sets.
+ *				_
+ *	\\			\\
+ *	 \\		=>	 \\
+ *	  \			  \|
+ *
+ * If there is more than one equality of "i" adjacent to an equality of "j",
+ * then the result will satisfy one or more equalities that are a linear
+ * combination of these equalities.  These will be encoded as pairs
+ * of inequalities in the wrapping constraints and need to be made
+ * explicit.
+ */
+static enum isl_change check_eq_adj_eq(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	int k;
+	enum isl_change change = isl_change_none;
+	int detect_equalities = 0;
+	struct isl_wraps wraps;
+	isl_ctx *ctx;
+	isl_mat *mat;
+	struct isl_set *set_i = NULL;
+	struct isl_set *set_j = NULL;
+	struct isl_vec *bound = NULL;
+	unsigned total = isl_basic_map_total_dim(info[i].bmap);
+
+	if (count(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ADJ_EQ) != 1)
+		detect_equalities = 1;
+
+	k = find(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ADJ_EQ);
+
+	set_i = set_from_updated_bmap(info[i].bmap, info[i].tab);
+	set_j = set_from_updated_bmap(info[j].bmap, info[j].tab);
+	ctx = isl_basic_map_get_ctx(info[i].bmap);
+	mat = isl_mat_alloc(ctx, 2 * (info[i].bmap->n_eq + info[j].bmap->n_eq) +
+				    info[i].bmap->n_ineq + info[j].bmap->n_ineq,
+				    1 + total);
+	if (wraps_init(&wraps, mat, info, i, j) < 0)
+		goto error;
+	bound = isl_vec_alloc(ctx, 1 + total);
+	if (!set_i || !set_j || !bound)
+		goto error;
+
+	if (k % 2 == 0)
+		isl_seq_neg(bound->el, info[i].bmap->eq[k / 2], 1 + total);
+	else
+		isl_seq_cpy(bound->el, info[i].bmap->eq[k / 2], 1 + total);
+	isl_int_add_ui(bound->el[0], bound->el[0], 1);
+
+	isl_seq_cpy(wraps.mat->row[0], bound->el, 1 + total);
+	wraps.mat->n_row = 1;
+
+	if (add_wraps(&wraps, &info[j], bound->el, set_i) < 0)
+		goto error;
+	if (!wraps.mat->n_row)
+		goto unbounded;
+
+	isl_int_sub_ui(bound->el[0], bound->el[0], 1);
+	isl_seq_neg(bound->el, bound->el, 1 + total);
+
+	isl_seq_cpy(wraps.mat->row[wraps.mat->n_row], bound->el, 1 + total);
+	wraps.mat->n_row++;
+
+	if (add_wraps(&wraps, &info[i], bound->el, set_j) < 0)
+		goto error;
+	if (!wraps.mat->n_row)
+		goto unbounded;
+
+	change = fuse(i, j, info, wraps.mat, detect_equalities, 0);
+
+	if (0) {
+error:		change = isl_change_error;
+	}
+unbounded:
+
+	wraps_free(&wraps);
+	isl_set_free(set_i);
+	isl_set_free(set_j);
+	isl_vec_free(bound);
+
+	return change;
+}
+
+/* Initialize the "eq" and "ineq" fields of "info".
+ */
+static void init_status(struct isl_coalesce_info *info)
+{
+	info->eq = info->ineq = NULL;
+}
+
+/* Set info->eq to the positions of the equalities of info->bmap
+ * with respect to the basic map represented by "tab".
+ * If info->eq has already been computed, then do not compute it again.
+ */
+static void set_eq_status_in(struct isl_coalesce_info *info,
+	struct isl_tab *tab)
+{
+	if (info->eq)
+		return;
+	info->eq = eq_status_in(info->bmap, tab);
+}
+
+/* Set info->ineq to the positions of the inequalities of info->bmap
+ * with respect to the basic map represented by "tab".
+ * If info->ineq has already been computed, then do not compute it again.
+ */
+static void set_ineq_status_in(struct isl_coalesce_info *info,
+	struct isl_tab *tab)
+{
+	if (info->ineq)
+		return;
+	info->ineq = ineq_status_in(info->bmap, info->tab, tab);
+}
+
+/* Free the memory allocated by the "eq" and "ineq" fields of "info".
+ * This function assumes that init_status has been called on "info" first,
+ * after which the "eq" and "ineq" fields may or may not have been
+ * assigned a newly allocated array.
+ */
+static void clear_status(struct isl_coalesce_info *info)
+{
+	free(info->eq);
+	free(info->ineq);
+}
+
+/* Are all inequality constraints of the basic map represented by "info"
+ * valid for the other basic map, except for a single constraint
+ * that is adjacent to an inequality constraint of the other basic map?
+ */
+static int all_ineq_valid_or_single_adj_ineq(struct isl_coalesce_info *info)
+{
+	int i;
+	int k = -1;
+
+	for (i = 0; i < info->bmap->n_ineq; ++i) {
+		if (info->ineq[i] == STATUS_REDUNDANT)
+			continue;
+		if (info->ineq[i] == STATUS_VALID)
+			continue;
+		if (info->ineq[i] != STATUS_ADJ_INEQ)
+			return 0;
+		if (k != -1)
+			return 0;
+		k = i;
+	}
+
+	return k != -1;
+}
+
+/* Basic map "i" has one or more equality constraints that separate it
+ * from basic map "j".  Check if it happens to be an extension
+ * of basic map "j".
+ * In particular, check that all constraints of "j" are valid for "i",
+ * except for one inequality constraint that is adjacent
+ * to an inequality constraints of "i".
+ * If so, check for "i" being an extension of "j" by calling
+ * is_adj_ineq_extension.
+ *
+ * Clean up the memory allocated for keeping track of the status
+ * of the constraints before returning.
+ */
+static enum isl_change separating_equality(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	enum isl_change change = isl_change_none;
+
+	if (all(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_VALID) &&
+	    all_ineq_valid_or_single_adj_ineq(&info[j]))
+		change = is_adj_ineq_extension(j, i, info);
+
+	clear_status(&info[i]);
+	clear_status(&info[j]);
+	return change;
+}
+
+/* Check if the union of the given pair of basic maps
+ * can be represented by a single basic map.
+ * If so, replace the pair by the single basic map and return
+ * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
+ * Otherwise, return isl_change_none.
+ * The two basic maps are assumed to live in the same local space.
+ * The "eq" and "ineq" fields of info[i] and info[j] are assumed
+ * to have been initialized by the caller, either to NULL or
+ * to valid information.
+ *
+ * We first check the effect of each constraint of one basic map
+ * on the other basic map.
+ * The constraint may be
+ *	redundant	the constraint is redundant in its own
+ *			basic map and should be ignore and removed
+ *			in the end
+ *	valid		all (integer) points of the other basic map
+ *			satisfy the constraint
+ *	separate	no (integer) point of the other basic map
+ *			satisfies the constraint
+ *	cut		some but not all points of the other basic map
+ *			satisfy the constraint
+ *	adj_eq		the given constraint is adjacent (on the outside)
+ *			to an equality of the other basic map
+ *	adj_ineq	the given constraint is adjacent (on the outside)
+ *			to an inequality of the other basic map
+ *
+ * We consider seven cases in which we can replace the pair by a single
+ * basic map.  We ignore all "redundant" constraints.
+ *
+ *	1. all constraints of one basic map are valid
+ *		=> the other basic map is a subset and can be removed
+ *
+ *	2. all constraints of both basic maps are either "valid" or "cut"
+ *	   and the facets corresponding to the "cut" constraints
+ *	   of one of the basic maps lies entirely inside the other basic map
+ *		=> the pair can be replaced by a basic map consisting
+ *		   of the valid constraints in both basic maps
+ *
+ *	3. there is a single pair of adjacent inequalities
+ *	   (all other constraints are "valid")
+ *		=> the pair can be replaced by a basic map consisting
+ *		   of the valid constraints in both basic maps
+ *
+ *	4. one basic map has a single adjacent inequality, while the other
+ *	   constraints are "valid".  The other basic map has some
+ *	   "cut" constraints, but replacing the adjacent inequality by
+ *	   its opposite and adding the valid constraints of the other
+ *	   basic map results in a subset of the other basic map
+ *		=> the pair can be replaced by a basic map consisting
+ *		   of the valid constraints in both basic maps
+ *
+ *	5. there is a single adjacent pair of an inequality and an equality,
+ *	   the other constraints of the basic map containing the inequality are
+ *	   "valid".  Moreover, if the inequality the basic map is relaxed
+ *	   and then turned into an equality, then resulting facet lies
+ *	   entirely inside the other basic map
+ *		=> the pair can be replaced by the basic map containing
+ *		   the inequality, with the inequality relaxed.
+ *
+ *	6. there is a single adjacent pair of an inequality and an equality,
+ *	   the other constraints of the basic map containing the inequality are
+ *	   "valid".  Moreover, the facets corresponding to both
+ *	   the inequality and the equality can be wrapped around their
+ *	   ridges to include the other basic map
+ *		=> the pair can be replaced by a basic map consisting
+ *		   of the valid constraints in both basic maps together
+ *		   with all wrapping constraints
+ *
+ *	7. one of the basic maps extends beyond the other by at most one.
+ *	   Moreover, the facets corresponding to the cut constraints and
+ *	   the pieces of the other basic map at offset one from these cut
+ *	   constraints can be wrapped around their ridges to include
+ *	   the union of the two basic maps
+ *		=> the pair can be replaced by a basic map consisting
+ *		   of the valid constraints in both basic maps together
+ *		   with all wrapping constraints
+ *
+ *	8. the two basic maps live in adjacent hyperplanes.  In principle
+ *	   such sets can always be combined through wrapping, but we impose
+ *	   that there is only one such pair, to avoid overeager coalescing.
+ *
+ * Throughout the computation, we maintain a collection of tableaus
+ * corresponding to the basic maps.  When the basic maps are dropped
+ * or combined, the tableaus are modified accordingly.
+ */
+static enum isl_change coalesce_local_pair_reuse(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	enum isl_change change = isl_change_none;
+
+	set_ineq_status_in(&info[i], info[j].tab);
+	if (info[i].bmap->n_ineq && !info[i].ineq)
+		goto error;
+	if (any(info[i].ineq, info[i].bmap->n_ineq, STATUS_ERROR))
+		goto error;
+	if (any(info[i].ineq, info[i].bmap->n_ineq, STATUS_SEPARATE))
+		goto done;
+
+	set_ineq_status_in(&info[j], info[i].tab);
+	if (info[j].bmap->n_ineq && !info[j].ineq)
+		goto error;
+	if (any(info[j].ineq, info[j].bmap->n_ineq, STATUS_ERROR))
+		goto error;
+	if (any(info[j].ineq, info[j].bmap->n_ineq, STATUS_SEPARATE))
+		goto done;
+
+	set_eq_status_in(&info[i], info[j].tab);
+	if (info[i].bmap->n_eq && !info[i].eq)
+		goto error;
+	if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ERROR))
+		goto error;
+
+	set_eq_status_in(&info[j], info[i].tab);
+	if (info[j].bmap->n_eq && !info[j].eq)
+		goto error;
+	if (any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_ERROR))
+		goto error;
+
+	if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_SEPARATE))
+		return separating_equality(i, j, info);
+	if (any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_SEPARATE))
+		return separating_equality(j, i, info);
+
+	if (all(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_VALID) &&
+	    all(info[i].ineq, info[i].bmap->n_ineq, STATUS_VALID)) {
+		drop(&info[j]);
+		change = isl_change_drop_second;
+	} else if (all(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_VALID) &&
+		   all(info[j].ineq, info[j].bmap->n_ineq, STATUS_VALID)) {
+		drop(&info[i]);
+		change = isl_change_drop_first;
+	} else if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ADJ_EQ)) {
+		change = check_eq_adj_eq(i, j, info);
+	} else if (any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_ADJ_EQ)) {
+		change = check_eq_adj_eq(j, i, info);
+	} else if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_ADJ_INEQ) ||
+		   any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_ADJ_INEQ)) {
+		change = check_adj_eq(i, j, info);
+	} else if (any(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_EQ) ||
+		   any(info[j].ineq, info[j].bmap->n_ineq, STATUS_ADJ_EQ)) {
+		/* Can't happen */
+		/* BAD ADJ INEQ */
+	} else if (any(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_INEQ) ||
+		   any(info[j].ineq, info[j].bmap->n_ineq, STATUS_ADJ_INEQ)) {
+		change = check_adj_ineq(i, j, info);
+	} else {
+		if (!any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_CUT) &&
+		    !any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_CUT))
+			change = check_facets(i, j, info);
+		if (change == isl_change_none)
+			change = check_wrap(i, j, info);
+	}
+
+done:
+	clear_status(&info[i]);
+	clear_status(&info[j]);
+	return change;
+error:
+	clear_status(&info[i]);
+	clear_status(&info[j]);
+	return isl_change_error;
+}
+
+/* Check if the union of the given pair of basic maps
+ * can be represented by a single basic map.
+ * If so, replace the pair by the single basic map and return
+ * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
+ * Otherwise, return isl_change_none.
+ * The two basic maps are assumed to live in the same local space.
+ */
+static enum isl_change coalesce_local_pair(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	init_status(&info[i]);
+	init_status(&info[j]);
+	return coalesce_local_pair_reuse(i, j, info);
+}
+
+/* Shift the integer division at position "div" of the basic map
+ * represented by "info" by "shift".
+ *
+ * That is, if the integer division has the form
+ *
+ *	floor(f(x)/d)
+ *
+ * then replace it by
+ *
+ *	floor((f(x) + shift * d)/d) - shift
+ */
+static isl_stat shift_div(struct isl_coalesce_info *info, int div,
+	isl_int shift)
+{
+	unsigned total;
+
+	info->bmap = isl_basic_map_shift_div(info->bmap, div, 0, shift);
+	if (!info->bmap)
+		return isl_stat_error;
+
+	total = isl_basic_map_dim(info->bmap, isl_dim_all);
+	total -= isl_basic_map_dim(info->bmap, isl_dim_div);
+	if (isl_tab_shift_var(info->tab, total + div, shift) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* If the integer division at position "div" is defined by an equality,
+ * i.e., a stride constraint, then change the integer division expression
+ * to have a constant term equal to zero.
+ *
+ * Let the equality constraint be
+ *
+ *	c + f + m a = 0
+ *
+ * The integer division expression is then of the form
+ *
+ *	a = floor((-f - c')/m)
+ *
+ * The integer division is first shifted by t = floor(c/m),
+ * turning the equality constraint into
+ *
+ *	c - m floor(c/m) + f + m a' = 0
+ *
+ * i.e.,
+ *
+ *	(c mod m) + f + m a' = 0
+ *
+ * That is,
+ *
+ *	a' = (-f - (c mod m))/m = floor((-f)/m)
+ *
+ * because a' is an integer and 0 <= (c mod m) < m.
+ * The constant term of a' can therefore be zeroed out.
+ */
+static isl_stat normalize_stride_div(struct isl_coalesce_info *info, int div)
+{
+	isl_bool defined;
+	isl_stat r;
+	isl_constraint *c;
+	isl_int shift, stride;
+
+	defined = isl_basic_map_has_defining_equality(info->bmap, isl_dim_div,
+							div, &c);
+	if (defined < 0)
+		return isl_stat_error;
+	if (!defined)
+		return isl_stat_ok;
+	if (!c)
+		return isl_stat_error;
+	isl_int_init(shift);
+	isl_int_init(stride);
+	isl_constraint_get_constant(c, &shift);
+	isl_constraint_get_coefficient(c, isl_dim_div, div, &stride);
+	isl_int_fdiv_q(shift, shift, stride);
+	r = shift_div(info, div, shift);
+	isl_int_clear(stride);
+	isl_int_clear(shift);
+	isl_constraint_free(c);
+	if (r < 0)
+		return isl_stat_error;
+	info->bmap = isl_basic_map_set_div_expr_constant_num_si_inplace(
+							    info->bmap, div, 0);
+	if (!info->bmap)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* The basic maps represented by "info1" and "info2" are known
+ * to have the same number of integer divisions.
+ * Check if pairs of integer divisions are equal to each other
+ * despite the fact that they differ by a rational constant.
+ *
+ * In particular, look for any pair of integer divisions that
+ * only differ in their constant terms.
+ * If either of these integer divisions is defined
+ * by stride constraints, then modify it to have a zero constant term.
+ * If both are defined by stride constraints then in the end they will have
+ * the same (zero) constant term.
+ */
+static isl_stat harmonize_stride_divs(struct isl_coalesce_info *info1,
+	struct isl_coalesce_info *info2)
+{
+	int i, n;
+
+	n = isl_basic_map_dim(info1->bmap, isl_dim_div);
+	for (i = 0; i < n; ++i) {
+		isl_bool known, harmonize;
+
+		known = isl_basic_map_div_is_known(info1->bmap, i);
+		if (known >= 0 && known)
+			known = isl_basic_map_div_is_known(info2->bmap, i);
+		if (known < 0)
+			return isl_stat_error;
+		if (!known)
+			continue;
+		harmonize = isl_basic_map_equal_div_expr_except_constant(
+					    info1->bmap, i, info2->bmap, i);
+		if (harmonize < 0)
+			return isl_stat_error;
+		if (!harmonize)
+			continue;
+		if (normalize_stride_div(info1, i) < 0)
+			return isl_stat_error;
+		if (normalize_stride_div(info2, i) < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* If "shift" is an integer constant, then shift the integer division
+ * at position "div" of the basic map represented by "info" by "shift".
+ * If "shift" is not an integer constant, then do nothing.
+ * If "shift" is equal to zero, then no shift needs to be performed either.
+ *
+ * That is, if the integer division has the form
+ *
+ *	floor(f(x)/d)
+ *
+ * then replace it by
+ *
+ *	floor((f(x) + shift * d)/d) - shift
+ */
+static isl_stat shift_if_cst_int(struct isl_coalesce_info *info, int div,
+	__isl_keep isl_aff *shift)
+{
+	isl_bool cst;
+	isl_stat r;
+	isl_int d;
+	isl_val *c;
+
+	cst = isl_aff_is_cst(shift);
+	if (cst < 0 || !cst)
+		return cst < 0 ? isl_stat_error : isl_stat_ok;
+
+	c = isl_aff_get_constant_val(shift);
+	cst = isl_val_is_int(c);
+	if (cst >= 0 && cst)
+		cst = isl_bool_not(isl_val_is_zero(c));
+	if (cst < 0 || !cst) {
+		isl_val_free(c);
+		return cst < 0 ? isl_stat_error : isl_stat_ok;
+	}
+
+	isl_int_init(d);
+	r = isl_val_get_num_isl_int(c, &d);
+	if (r >= 0)
+		r = shift_div(info, div, d);
+	isl_int_clear(d);
+
+	isl_val_free(c);
+
+	return r;
+}
+
+/* Check if some of the divs in the basic map represented by "info1"
+ * are shifts of the corresponding divs in the basic map represented
+ * by "info2", taking into account the equality constraints "eq1" of "info1"
+ * and "eq2" of "info2".  If so, align them with those of "info2".
+ * "info1" and "info2" are assumed to have the same number
+ * of integer divisions.
+ *
+ * An integer division is considered to be a shift of another integer
+ * division if, after simplification with respect to the equality
+ * constraints of the other basic map, one is equal to the other
+ * plus a constant.
+ *
+ * In particular, for each pair of integer divisions, if both are known,
+ * have the same denominator and are not already equal to each other,
+ * simplify each with respect to the equality constraints
+ * of the other basic map.  If the difference is an integer constant,
+ * then move this difference outside.
+ * That is, if, after simplification, one integer division is of the form
+ *
+ *	floor((f(x) + c_1)/d)
+ *
+ * while the other is of the form
+ *
+ *	floor((f(x) + c_2)/d)
+ *
+ * and n = (c_2 - c_1)/d is an integer, then replace the first
+ * integer division by
+ *
+ *	floor((f_1(x) + c_1 + n * d)/d) - n,
+ *
+ * where floor((f_1(x) + c_1 + n * d)/d) = floor((f2(x) + c_2)/d)
+ * after simplification with respect to the equality constraints.
+ */
+static isl_stat harmonize_divs_with_hulls(struct isl_coalesce_info *info1,
+	struct isl_coalesce_info *info2, __isl_keep isl_basic_set *eq1,
+	__isl_keep isl_basic_set *eq2)
+{
+	int i;
+	int total;
+	isl_local_space *ls1, *ls2;
+
+	total = isl_basic_map_total_dim(info1->bmap);
+	ls1 = isl_local_space_wrap(isl_basic_map_get_local_space(info1->bmap));
+	ls2 = isl_local_space_wrap(isl_basic_map_get_local_space(info2->bmap));
+	for (i = 0; i < info1->bmap->n_div; ++i) {
+		isl_stat r;
+		isl_aff *div1, *div2;
+
+		if (!isl_local_space_div_is_known(ls1, i) ||
+		    !isl_local_space_div_is_known(ls2, i))
+			continue;
+		if (isl_int_ne(info1->bmap->div[i][0], info2->bmap->div[i][0]))
+			continue;
+		if (isl_seq_eq(info1->bmap->div[i] + 1,
+				info2->bmap->div[i] + 1, 1 + total))
+			continue;
+		div1 = isl_local_space_get_div(ls1, i);
+		div2 = isl_local_space_get_div(ls2, i);
+		div1 = isl_aff_substitute_equalities(div1,
+						    isl_basic_set_copy(eq2));
+		div2 = isl_aff_substitute_equalities(div2,
+						    isl_basic_set_copy(eq1));
+		div2 = isl_aff_sub(div2, div1);
+		r = shift_if_cst_int(info1, i, div2);
+		isl_aff_free(div2);
+		if (r < 0)
+			break;
+	}
+	isl_local_space_free(ls1);
+	isl_local_space_free(ls2);
+
+	if (i < info1->bmap->n_div)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Check if some of the divs in the basic map represented by "info1"
+ * are shifts of the corresponding divs in the basic map represented
+ * by "info2".  If so, align them with those of "info2".
+ * Only do this if "info1" and "info2" have the same number
+ * of integer divisions.
+ *
+ * An integer division is considered to be a shift of another integer
+ * division if, after simplification with respect to the equality
+ * constraints of the other basic map, one is equal to the other
+ * plus a constant.
+ *
+ * First check if pairs of integer divisions are equal to each other
+ * despite the fact that they differ by a rational constant.
+ * If so, try and arrange for them to have the same constant term.
+ *
+ * Then, extract the equality constraints and continue with
+ * harmonize_divs_with_hulls.
+ *
+ * If the equality constraints of both basic maps are the same,
+ * then there is no need to perform any shifting since
+ * the coefficients of the integer divisions should have been
+ * reduced in the same way.
+ */
+static isl_stat harmonize_divs(struct isl_coalesce_info *info1,
+	struct isl_coalesce_info *info2)
+{
+	isl_bool equal;
+	isl_basic_map *bmap1, *bmap2;
+	isl_basic_set *eq1, *eq2;
+	isl_stat r;
+
+	if (!info1->bmap || !info2->bmap)
+		return isl_stat_error;
+
+	if (info1->bmap->n_div != info2->bmap->n_div)
+		return isl_stat_ok;
+	if (info1->bmap->n_div == 0)
+		return isl_stat_ok;
+
+	if (harmonize_stride_divs(info1, info2) < 0)
+		return isl_stat_error;
+
+	bmap1 = isl_basic_map_copy(info1->bmap);
+	bmap2 = isl_basic_map_copy(info2->bmap);
+	eq1 = isl_basic_map_wrap(isl_basic_map_plain_affine_hull(bmap1));
+	eq2 = isl_basic_map_wrap(isl_basic_map_plain_affine_hull(bmap2));
+	equal = isl_basic_set_plain_is_equal(eq1, eq2);
+	if (equal < 0)
+		r = isl_stat_error;
+	else if (equal)
+		r = isl_stat_ok;
+	else
+		r = harmonize_divs_with_hulls(info1, info2, eq1, eq2);
+	isl_basic_set_free(eq1);
+	isl_basic_set_free(eq2);
+
+	return r;
+}
+
+/* Do the two basic maps live in the same local space, i.e.,
+ * do they have the same (known) divs?
+ * If either basic map has any unknown divs, then we can only assume
+ * that they do not live in the same local space.
+ */
+static isl_bool same_divs(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	int i;
+	isl_bool known;
+	int total;
+
+	if (!bmap1 || !bmap2)
+		return isl_bool_error;
+	if (bmap1->n_div != bmap2->n_div)
+		return isl_bool_false;
+
+	if (bmap1->n_div == 0)
+		return isl_bool_true;
+
+	known = isl_basic_map_divs_known(bmap1);
+	if (known < 0 || !known)
+		return known;
+	known = isl_basic_map_divs_known(bmap2);
+	if (known < 0 || !known)
+		return known;
+
+	total = isl_basic_map_total_dim(bmap1);
+	for (i = 0; i < bmap1->n_div; ++i)
+		if (!isl_seq_eq(bmap1->div[i], bmap2->div[i], 2 + total))
+			return 0;
+
+	return 1;
+}
+
+/* Assuming that "tab" contains the equality constraints and
+ * the initial inequality constraints of "bmap", copy the remaining
+ * inequality constraints of "bmap" to "Tab".
+ */
+static isl_stat copy_ineq(struct isl_tab *tab, __isl_keep isl_basic_map *bmap)
+{
+	int i, n_ineq;
+
+	if (!bmap)
+		return isl_stat_error;
+
+	n_ineq = tab->n_con - tab->n_eq;
+	for (i = n_ineq; i < bmap->n_ineq; ++i)
+		if (isl_tab_add_ineq(tab, bmap->ineq[i]) < 0)
+			return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Description of an integer division that is added
+ * during an expansion.
+ * "pos" is the position of the corresponding variable.
+ * "cst" indicates whether this integer division has a fixed value.
+ * "val" contains the fixed value, if the value is fixed.
+ */
+struct isl_expanded {
+	int pos;
+	isl_bool cst;
+	isl_int val;
+};
+
+/* For each of the "n" integer division variables "expanded",
+ * if the variable has a fixed value, then add two inequality
+ * constraints expressing the fixed value.
+ * Otherwise, add the corresponding div constraints.
+ * The caller is responsible for removing the div constraints
+ * that it added for all these "n" integer divisions.
+ *
+ * The div constraints and the pair of inequality constraints
+ * forcing the fixed value cannot both be added for a given variable
+ * as the combination may render some of the original constraints redundant.
+ * These would then be ignored during the coalescing detection,
+ * while they could remain in the fused result.
+ *
+ * The two added inequality constraints are
+ *
+ *	-a + v >= 0
+ *	a - v >= 0
+ *
+ * with "a" the variable and "v" its fixed value.
+ * The facet corresponding to one of these two constraints is selected
+ * in the tableau to ensure that the pair of inequality constraints
+ * is treated as an equality constraint.
+ *
+ * The information in info->ineq is thrown away because it was
+ * computed in terms of div constraints, while some of those
+ * have now been replaced by these pairs of inequality constraints.
+ */
+static isl_stat fix_constant_divs(struct isl_coalesce_info *info,
+	int n, struct isl_expanded *expanded)
+{
+	unsigned o_div;
+	int i;
+	isl_vec *ineq;
+
+	o_div = isl_basic_map_offset(info->bmap, isl_dim_div) - 1;
+	ineq = isl_vec_alloc(isl_tab_get_ctx(info->tab), 1 + info->tab->n_var);
+	if (!ineq)
+		return isl_stat_error;
+	isl_seq_clr(ineq->el + 1, info->tab->n_var);
+
+	for (i = 0; i < n; ++i) {
+		if (!expanded[i].cst) {
+			info->bmap = isl_basic_map_extend_constraints(
+						info->bmap, 0, 2);
+			if (isl_basic_map_add_div_constraints(info->bmap,
+						expanded[i].pos - o_div) < 0)
+				break;
+		} else {
+			isl_int_set_si(ineq->el[1 + expanded[i].pos], -1);
+			isl_int_set(ineq->el[0], expanded[i].val);
+			info->bmap = isl_basic_map_add_ineq(info->bmap,
+								ineq->el);
+			isl_int_set_si(ineq->el[1 + expanded[i].pos], 1);
+			isl_int_neg(ineq->el[0], expanded[i].val);
+			info->bmap = isl_basic_map_add_ineq(info->bmap,
+								ineq->el);
+			isl_int_set_si(ineq->el[1 + expanded[i].pos], 0);
+		}
+		if (copy_ineq(info->tab, info->bmap) < 0)
+			break;
+		if (expanded[i].cst &&
+		    isl_tab_select_facet(info->tab, info->tab->n_con - 1) < 0)
+			break;
+	}
+
+	isl_vec_free(ineq);
+
+	clear_status(info);
+	init_status(info);
+
+	return i < n ? isl_stat_error : isl_stat_ok;
+}
+
+/* Insert the "n" integer division variables "expanded"
+ * into info->tab and info->bmap and
+ * update info->ineq with respect to the redundant constraints
+ * in the resulting tableau.
+ * "bmap" contains the result of this insertion in info->bmap,
+ * while info->bmap is the original version
+ * of "bmap", i.e., the one that corresponds to the current
+ * state of info->tab.  The number of constraints in info->bmap
+ * is assumed to be the same as the number of constraints
+ * in info->tab.  This is required to be able to detect
+ * the extra constraints in "bmap".
+ *
+ * In particular, introduce extra variables corresponding
+ * to the extra integer divisions and add the div constraints
+ * that were added to "bmap" after info->tab was created
+ * from info->bmap.
+ * Furthermore, check if these extra integer divisions happen
+ * to attain a fixed integer value in info->tab.
+ * If so, replace the corresponding div constraints by pairs
+ * of inequality constraints that fix these
+ * integer divisions to their single integer values.
+ * Replace info->bmap by "bmap" to match the changes to info->tab.
+ * info->ineq was computed without a tableau and therefore
+ * does not take into account the redundant constraints
+ * in the tableau.  Mark them here.
+ * There is no need to check the newly added div constraints
+ * since they cannot be redundant.
+ * The redundancy check is not performed when constants have been discovered
+ * since info->ineq is completely thrown away in this case.
+ */
+static isl_stat tab_insert_divs(struct isl_coalesce_info *info,
+	int n, struct isl_expanded *expanded, __isl_take isl_basic_map *bmap)
+{
+	int i, n_ineq;
+	unsigned n_eq;
+	struct isl_tab_undo *snap;
+	int any;
+
+	if (!bmap)
+		return isl_stat_error;
+	if (info->bmap->n_eq + info->bmap->n_ineq != info->tab->n_con)
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_internal,
+			"original tableau does not correspond "
+			"to original basic map", goto error);
+
+	if (isl_tab_extend_vars(info->tab, n) < 0)
+		goto error;
+	if (isl_tab_extend_cons(info->tab, 2 * n) < 0)
+		goto error;
+
+	for (i = 0; i < n; ++i) {
+		if (isl_tab_insert_var(info->tab, expanded[i].pos) < 0)
+			goto error;
+	}
+
+	snap = isl_tab_snap(info->tab);
+
+	n_ineq = info->tab->n_con - info->tab->n_eq;
+	if (copy_ineq(info->tab, bmap) < 0)
+		goto error;
+
+	isl_basic_map_free(info->bmap);
+	info->bmap = bmap;
+
+	any = 0;
+	for (i = 0; i < n; ++i) {
+		expanded[i].cst = isl_tab_is_constant(info->tab,
+					    expanded[i].pos, &expanded[i].val);
+		if (expanded[i].cst < 0)
+			return isl_stat_error;
+		if (expanded[i].cst)
+			any = 1;
+	}
+
+	if (any) {
+		if (isl_tab_rollback(info->tab, snap) < 0)
+			return isl_stat_error;
+		info->bmap = isl_basic_map_cow(info->bmap);
+		if (isl_basic_map_free_inequality(info->bmap, 2 * n) < 0)
+			return isl_stat_error;
+
+		return fix_constant_divs(info, n, expanded);
+	}
+
+	n_eq = info->bmap->n_eq;
+	for (i = 0; i < n_ineq; ++i) {
+		if (isl_tab_is_redundant(info->tab, n_eq + i))
+			info->ineq[i] = STATUS_REDUNDANT;
+	}
+
+	return isl_stat_ok;
+error:
+	isl_basic_map_free(bmap);
+	return isl_stat_error;
+}
+
+/* Expand info->tab and info->bmap in the same way "bmap" was expanded
+ * in isl_basic_map_expand_divs using the expansion "exp" and
+ * update info->ineq with respect to the redundant constraints
+ * in the resulting tableau. info->bmap is the original version
+ * of "bmap", i.e., the one that corresponds to the current
+ * state of info->tab.  The number of constraints in info->bmap
+ * is assumed to be the same as the number of constraints
+ * in info->tab.  This is required to be able to detect
+ * the extra constraints in "bmap".
+ *
+ * Extract the positions where extra local variables are introduced
+ * from "exp" and call tab_insert_divs.
+ */
+static isl_stat expand_tab(struct isl_coalesce_info *info, int *exp,
+	__isl_take isl_basic_map *bmap)
+{
+	isl_ctx *ctx;
+	struct isl_expanded *expanded;
+	int i, j, k, n;
+	int extra_var;
+	unsigned total, pos, n_div;
+	isl_stat r;
+
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	pos = total - n_div;
+	extra_var = total - info->tab->n_var;
+	n = n_div - extra_var;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	expanded = isl_calloc_array(ctx, struct isl_expanded, extra_var);
+	if (extra_var && !expanded)
+		goto error;
+
+	i = 0;
+	k = 0;
+	for (j = 0; j < n_div; ++j) {
+		if (i < n && exp[i] == j) {
+			++i;
+			continue;
+		}
+		expanded[k++].pos = pos + j;
+	}
+
+	for (k = 0; k < extra_var; ++k)
+		isl_int_init(expanded[k].val);
+
+	r = tab_insert_divs(info, extra_var, expanded, bmap);
+
+	for (k = 0; k < extra_var; ++k)
+		isl_int_clear(expanded[k].val);
+	free(expanded);
+
+	return r;
+error:
+	isl_basic_map_free(bmap);
+	return isl_stat_error;
+}
+
+/* Check if the union of the basic maps represented by info[i] and info[j]
+ * can be represented by a single basic map,
+ * after expanding the divs of info[i] to match those of info[j].
+ * If so, replace the pair by the single basic map and return
+ * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
+ * Otherwise, return isl_change_none.
+ *
+ * The caller has already checked for info[j] being a subset of info[i].
+ * If some of the divs of info[j] are unknown, then the expanded info[i]
+ * will not have the corresponding div constraints.  The other patterns
+ * therefore cannot apply.  Skip the computation in this case.
+ *
+ * The expansion is performed using the divs "div" and expansion "exp"
+ * computed by the caller.
+ * info[i].bmap has already been expanded and the result is passed in
+ * as "bmap".
+ * The "eq" and "ineq" fields of info[i] reflect the status of
+ * the constraints of the expanded "bmap" with respect to info[j].tab.
+ * However, inequality constraints that are redundant in info[i].tab
+ * have not yet been marked as such because no tableau was available.
+ *
+ * Replace info[i].bmap by "bmap" and expand info[i].tab as well,
+ * updating info[i].ineq with respect to the redundant constraints.
+ * Then try and coalesce the expanded info[i] with info[j],
+ * reusing the information in info[i].eq and info[i].ineq.
+ * If this does not result in any coalescing or if it results in info[j]
+ * getting dropped (which should not happen in practice, since the case
+ * of info[j] being a subset of info[i] has already been checked by
+ * the caller), then revert info[i] to its original state.
+ */
+static enum isl_change coalesce_expand_tab_divs(__isl_take isl_basic_map *bmap,
+	int i, int j, struct isl_coalesce_info *info, __isl_keep isl_mat *div,
+	int *exp)
+{
+	isl_bool known;
+	isl_basic_map *bmap_i;
+	struct isl_tab_undo *snap;
+	enum isl_change change = isl_change_none;
+
+	known = isl_basic_map_divs_known(info[j].bmap);
+	if (known < 0 || !known) {
+		clear_status(&info[i]);
+		isl_basic_map_free(bmap);
+		return known < 0 ? isl_change_error : isl_change_none;
+	}
+
+	bmap_i = isl_basic_map_copy(info[i].bmap);
+	snap = isl_tab_snap(info[i].tab);
+	if (expand_tab(&info[i], exp, bmap) < 0)
+		change = isl_change_error;
+
+	init_status(&info[j]);
+	if (change == isl_change_none)
+		change = coalesce_local_pair_reuse(i, j, info);
+	else
+		clear_status(&info[i]);
+	if (change != isl_change_none && change != isl_change_drop_second) {
+		isl_basic_map_free(bmap_i);
+	} else {
+		isl_basic_map_free(info[i].bmap);
+		info[i].bmap = bmap_i;
+
+		if (isl_tab_rollback(info[i].tab, snap) < 0)
+			change = isl_change_error;
+	}
+
+	return change;
+}
+
+/* Check if the union of "bmap" and the basic map represented by info[j]
+ * can be represented by a single basic map,
+ * after expanding the divs of "bmap" to match those of info[j].
+ * If so, replace the pair by the single basic map and return
+ * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
+ * Otherwise, return isl_change_none.
+ *
+ * In particular, check if the expanded "bmap" contains the basic map
+ * represented by the tableau info[j].tab.
+ * The expansion is performed using the divs "div" and expansion "exp"
+ * computed by the caller.
+ * Then we check if all constraints of the expanded "bmap" are valid for
+ * info[j].tab.
+ *
+ * If "i" is not equal to -1, then "bmap" is equal to info[i].bmap.
+ * In this case, the positions of the constraints of info[i].bmap
+ * with respect to the basic map represented by info[j] are stored
+ * in info[i].
+ *
+ * If the expanded "bmap" does not contain the basic map
+ * represented by the tableau info[j].tab and if "i" is not -1,
+ * i.e., if the original "bmap" is info[i].bmap, then expand info[i].tab
+ * as well and check if that results in coalescing.
+ */
+static enum isl_change coalesce_with_expanded_divs(
+	__isl_keep isl_basic_map *bmap, int i, int j,
+	struct isl_coalesce_info *info, __isl_keep isl_mat *div, int *exp)
+{
+	enum isl_change change = isl_change_none;
+	struct isl_coalesce_info info_local, *info_i;
+
+	info_i = i >= 0 ? &info[i] : &info_local;
+	init_status(info_i);
+	bmap = isl_basic_map_copy(bmap);
+	bmap = isl_basic_map_expand_divs(bmap, isl_mat_copy(div), exp);
+	bmap = isl_basic_map_mark_final(bmap);
+
+	if (!bmap)
+		goto error;
+
+	info_i->eq = eq_status_in(bmap, info[j].tab);
+	if (bmap->n_eq && !info_i->eq)
+		goto error;
+	if (any(info_i->eq, 2 * bmap->n_eq, STATUS_ERROR))
+		goto error;
+	if (any(info_i->eq, 2 * bmap->n_eq, STATUS_SEPARATE))
+		goto done;
+
+	info_i->ineq = ineq_status_in(bmap, NULL, info[j].tab);
+	if (bmap->n_ineq && !info_i->ineq)
+		goto error;
+	if (any(info_i->ineq, bmap->n_ineq, STATUS_ERROR))
+		goto error;
+	if (any(info_i->ineq, bmap->n_ineq, STATUS_SEPARATE))
+		goto done;
+
+	if (all(info_i->eq, 2 * bmap->n_eq, STATUS_VALID) &&
+	    all(info_i->ineq, bmap->n_ineq, STATUS_VALID)) {
+		drop(&info[j]);
+		change = isl_change_drop_second;
+	}
+
+	if (change == isl_change_none && i != -1)
+		return coalesce_expand_tab_divs(bmap, i, j, info, div, exp);
+
+done:
+	isl_basic_map_free(bmap);
+	clear_status(info_i);
+	return change;
+error:
+	isl_basic_map_free(bmap);
+	clear_status(info_i);
+	return isl_change_error;
+}
+
+/* Check if the union of "bmap_i" and the basic map represented by info[j]
+ * can be represented by a single basic map,
+ * after aligning the divs of "bmap_i" to match those of info[j].
+ * If so, replace the pair by the single basic map and return
+ * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
+ * Otherwise, return isl_change_none.
+ *
+ * In particular, check if "bmap_i" contains the basic map represented by
+ * info[j] after aligning the divs of "bmap_i" to those of info[j].
+ * Note that this can only succeed if the number of divs of "bmap_i"
+ * is smaller than (or equal to) the number of divs of info[j].
+ *
+ * We first check if the divs of "bmap_i" are all known and form a subset
+ * of those of info[j].bmap.  If so, we pass control over to
+ * coalesce_with_expanded_divs.
+ *
+ * If "i" is not equal to -1, then "bmap" is equal to info[i].bmap.
+ */
+static enum isl_change coalesce_after_aligning_divs(
+	__isl_keep isl_basic_map *bmap_i, int i, int j,
+	struct isl_coalesce_info *info)
+{
+	int known;
+	isl_mat *div_i, *div_j, *div;
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_ctx *ctx;
+	enum isl_change change;
+
+	known = isl_basic_map_divs_known(bmap_i);
+	if (known < 0 || !known)
+		return known;
+
+	ctx = isl_basic_map_get_ctx(bmap_i);
+
+	div_i = isl_basic_map_get_divs(bmap_i);
+	div_j = isl_basic_map_get_divs(info[j].bmap);
+
+	if (!div_i || !div_j)
+		goto error;
+
+	exp1 = isl_alloc_array(ctx, int, div_i->n_row);
+	exp2 = isl_alloc_array(ctx, int, div_j->n_row);
+	if ((div_i->n_row && !exp1) || (div_j->n_row && !exp2))
+		goto error;
+
+	div = isl_merge_divs(div_i, div_j, exp1, exp2);
+	if (!div)
+		goto error;
+
+	if (div->n_row == div_j->n_row)
+		change = coalesce_with_expanded_divs(bmap_i,
+							i, j, info, div, exp1);
+	else
+		change = isl_change_none;
+
+	isl_mat_free(div);
+
+	isl_mat_free(div_i);
+	isl_mat_free(div_j);
+
+	free(exp2);
+	free(exp1);
+
+	return change;
+error:
+	isl_mat_free(div_i);
+	isl_mat_free(div_j);
+	free(exp1);
+	free(exp2);
+	return isl_change_error;
+}
+
+/* Check if basic map "j" is a subset of basic map "i" after
+ * exploiting the extra equalities of "j" to simplify the divs of "i".
+ * If so, remove basic map "j" and return isl_change_drop_second.
+ *
+ * If "j" does not have any equalities or if they are the same
+ * as those of "i", then we cannot exploit them to simplify the divs.
+ * Similarly, if there are no divs in "i", then they cannot be simplified.
+ * If, on the other hand, the affine hulls of "i" and "j" do not intersect,
+ * then "j" cannot be a subset of "i".
+ *
+ * Otherwise, we intersect "i" with the affine hull of "j" and then
+ * check if "j" is a subset of the result after aligning the divs.
+ * If so, then "j" is definitely a subset of "i" and can be removed.
+ * Note that if after intersection with the affine hull of "j".
+ * "i" still has more divs than "j", then there is no way we can
+ * align the divs of "i" to those of "j".
+ */
+static enum isl_change coalesce_subset_with_equalities(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	isl_basic_map *hull_i, *hull_j, *bmap_i;
+	int equal, empty;
+	enum isl_change change;
+
+	if (info[j].bmap->n_eq == 0)
+		return isl_change_none;
+	if (info[i].bmap->n_div == 0)
+		return isl_change_none;
+
+	hull_i = isl_basic_map_copy(info[i].bmap);
+	hull_i = isl_basic_map_plain_affine_hull(hull_i);
+	hull_j = isl_basic_map_copy(info[j].bmap);
+	hull_j = isl_basic_map_plain_affine_hull(hull_j);
+
+	hull_j = isl_basic_map_intersect(hull_j, isl_basic_map_copy(hull_i));
+	equal = isl_basic_map_plain_is_equal(hull_i, hull_j);
+	empty = isl_basic_map_plain_is_empty(hull_j);
+	isl_basic_map_free(hull_i);
+
+	if (equal < 0 || equal || empty < 0 || empty) {
+		isl_basic_map_free(hull_j);
+		if (equal < 0 || empty < 0)
+			return isl_change_error;
+		return isl_change_none;
+	}
+
+	bmap_i = isl_basic_map_copy(info[i].bmap);
+	bmap_i = isl_basic_map_intersect(bmap_i, hull_j);
+	if (!bmap_i)
+		return isl_change_error;
+
+	if (bmap_i->n_div > info[j].bmap->n_div) {
+		isl_basic_map_free(bmap_i);
+		return isl_change_none;
+	}
+
+	change = coalesce_after_aligning_divs(bmap_i, -1, j, info);
+
+	isl_basic_map_free(bmap_i);
+
+	return change;
+}
+
+/* Check if the union of and the basic maps represented by info[i] and info[j]
+ * can be represented by a single basic map, by aligning or equating
+ * their integer divisions.
+ * If so, replace the pair by the single basic map and return
+ * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
+ * Otherwise, return isl_change_none.
+ *
+ * Note that we only perform any test if the number of divs is different
+ * in the two basic maps.  In case the number of divs is the same,
+ * we have already established that the divs are different
+ * in the two basic maps.
+ * In particular, if the number of divs of basic map i is smaller than
+ * the number of divs of basic map j, then we check if j is a subset of i
+ * and vice versa.
+ */
+static enum isl_change coalesce_divs(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	enum isl_change change = isl_change_none;
+
+	if (info[i].bmap->n_div < info[j].bmap->n_div)
+		change = coalesce_after_aligning_divs(info[i].bmap, i, j, info);
+	if (change != isl_change_none)
+		return change;
+
+	if (info[j].bmap->n_div < info[i].bmap->n_div)
+		change = coalesce_after_aligning_divs(info[j].bmap, j, i, info);
+	if (change != isl_change_none)
+		return invert_change(change);
+
+	change = coalesce_subset_with_equalities(i, j, info);
+	if (change != isl_change_none)
+		return change;
+
+	change = coalesce_subset_with_equalities(j, i, info);
+	if (change != isl_change_none)
+		return invert_change(change);
+
+	return isl_change_none;
+}
+
+/* Does "bmap" involve any divs that themselves refer to divs?
+ */
+static isl_bool has_nested_div(__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	unsigned total;
+	unsigned n_div;
+
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	total -= n_div;
+
+	for (i = 0; i < n_div; ++i)
+		if (isl_seq_first_non_zero(bmap->div[i] + 2 + total,
+					    n_div) != -1)
+			return isl_bool_true;
+
+	return isl_bool_false;
+}
+
+/* Return a list of affine expressions, one for each integer division
+ * in "bmap_i".  For each integer division that also appears in "bmap_j",
+ * the affine expression is set to NaN.  The number of NaNs in the list
+ * is equal to the number of integer divisions in "bmap_j".
+ * For the other integer divisions of "bmap_i", the corresponding
+ * element in the list is a purely affine expression equal to the integer
+ * division in "hull".
+ * If no such list can be constructed, then the number of elements
+ * in the returned list is smaller than the number of integer divisions
+ * in "bmap_i".
+ */
+static __isl_give isl_aff_list *set_up_substitutions(
+	__isl_keep isl_basic_map *bmap_i, __isl_keep isl_basic_map *bmap_j,
+	__isl_take isl_basic_map *hull)
+{
+	unsigned n_div_i, n_div_j, total;
+	isl_ctx *ctx;
+	isl_local_space *ls;
+	isl_basic_set *wrap_hull;
+	isl_aff *aff_nan;
+	isl_aff_list *list;
+	int i, j;
+
+	if (!hull)
+		return NULL;
+
+	ctx = isl_basic_map_get_ctx(hull);
+
+	n_div_i = isl_basic_map_dim(bmap_i, isl_dim_div);
+	n_div_j = isl_basic_map_dim(bmap_j, isl_dim_div);
+	total = isl_basic_map_total_dim(bmap_i) - n_div_i;
+
+	ls = isl_basic_map_get_local_space(bmap_i);
+	ls = isl_local_space_wrap(ls);
+	wrap_hull = isl_basic_map_wrap(hull);
+
+	aff_nan = isl_aff_nan_on_domain(isl_local_space_copy(ls));
+	list = isl_aff_list_alloc(ctx, n_div_i);
+
+	j = 0;
+	for (i = 0; i < n_div_i; ++i) {
+		isl_aff *aff;
+
+		if (j < n_div_j &&
+		    isl_basic_map_equal_div_expr_part(bmap_i, i, bmap_j, j,
+						    0, 2 + total)) {
+			++j;
+			list = isl_aff_list_add(list, isl_aff_copy(aff_nan));
+			continue;
+		}
+		if (n_div_i - i <= n_div_j - j)
+			break;
+
+		aff = isl_local_space_get_div(ls, i);
+		aff = isl_aff_substitute_equalities(aff,
+						isl_basic_set_copy(wrap_hull));
+		aff = isl_aff_floor(aff);
+		if (!aff)
+			goto error;
+		if (isl_aff_dim(aff, isl_dim_div) != 0) {
+			isl_aff_free(aff);
+			break;
+		}
+
+		list = isl_aff_list_add(list, aff);
+	}
+
+	isl_aff_free(aff_nan);
+	isl_local_space_free(ls);
+	isl_basic_set_free(wrap_hull);
+
+	return list;
+error:
+	isl_aff_free(aff_nan);
+	isl_local_space_free(ls);
+	isl_basic_set_free(wrap_hull);
+	isl_aff_list_free(list);
+	return NULL;
+}
+
+/* Add variables to info->bmap and info->tab corresponding to the elements
+ * in "list" that are not set to NaN.
+ * "extra_var" is the number of these elements.
+ * "dim" is the offset in the variables of "tab" where we should
+ * start considering the elements in "list".
+ * When this function returns, the total number of variables in "tab"
+ * is equal to "dim" plus the number of elements in "list".
+ *
+ * The newly added existentially quantified variables are not given
+ * an explicit representation because the corresponding div constraints
+ * do not appear in info->bmap.  These constraints are not added
+ * to info->bmap because for internal consistency, they would need to
+ * be added to info->tab as well, where they could combine with the equality
+ * that is added later to result in constraints that do not hold
+ * in the original input.
+ */
+static isl_stat add_sub_vars(struct isl_coalesce_info *info,
+	__isl_keep isl_aff_list *list, int dim, int extra_var)
+{
+	int i, j, n, d;
+	isl_space *space;
+
+	space = isl_basic_map_get_space(info->bmap);
+	info->bmap = isl_basic_map_cow(info->bmap);
+	info->bmap = isl_basic_map_extend_space(info->bmap, space,
+						extra_var, 0, 0);
+	if (!info->bmap)
+		return isl_stat_error;
+	n = isl_aff_list_n_aff(list);
+	for (i = 0; i < n; ++i) {
+		int is_nan;
+		isl_aff *aff;
+
+		aff = isl_aff_list_get_aff(list, i);
+		is_nan = isl_aff_is_nan(aff);
+		isl_aff_free(aff);
+		if (is_nan < 0)
+			return isl_stat_error;
+		if (is_nan)
+			continue;
+
+		if (isl_tab_insert_var(info->tab, dim + i) < 0)
+			return isl_stat_error;
+		d = isl_basic_map_alloc_div(info->bmap);
+		if (d < 0)
+			return isl_stat_error;
+		info->bmap = isl_basic_map_mark_div_unknown(info->bmap, d);
+		if (!info->bmap)
+			return isl_stat_error;
+		for (j = d; j > i; --j)
+			isl_basic_map_swap_div(info->bmap, j - 1, j);
+	}
+
+	return isl_stat_ok;
+}
+
+/* For each element in "list" that is not set to NaN, fix the corresponding
+ * variable in "tab" to the purely affine expression defined by the element.
+ * "dim" is the offset in the variables of "tab" where we should
+ * start considering the elements in "list".
+ *
+ * This function assumes that a sufficient number of rows and
+ * elements in the constraint array are available in the tableau.
+ */
+static int add_sub_equalities(struct isl_tab *tab,
+	__isl_keep isl_aff_list *list, int dim)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_vec *sub;
+	isl_aff *aff;
+
+	n = isl_aff_list_n_aff(list);
+
+	ctx = isl_tab_get_ctx(tab);
+	sub = isl_vec_alloc(ctx, 1 + dim + n);
+	if (!sub)
+		return -1;
+	isl_seq_clr(sub->el + 1 + dim, n);
+
+	for (i = 0; i < n; ++i) {
+		aff = isl_aff_list_get_aff(list, i);
+		if (!aff)
+			goto error;
+		if (isl_aff_is_nan(aff)) {
+			isl_aff_free(aff);
+			continue;
+		}
+		isl_seq_cpy(sub->el, aff->v->el + 1, 1 + dim);
+		isl_int_neg(sub->el[1 + dim + i], aff->v->el[0]);
+		if (isl_tab_add_eq(tab, sub->el) < 0)
+			goto error;
+		isl_int_set_si(sub->el[1 + dim + i], 0);
+		isl_aff_free(aff);
+	}
+
+	isl_vec_free(sub);
+	return 0;
+error:
+	isl_aff_free(aff);
+	isl_vec_free(sub);
+	return -1;
+}
+
+/* Add variables to info->tab and info->bmap corresponding to the elements
+ * in "list" that are not set to NaN.  The value of the added variable
+ * in info->tab is fixed to the purely affine expression defined by the element.
+ * "dim" is the offset in the variables of info->tab where we should
+ * start considering the elements in "list".
+ * When this function returns, the total number of variables in info->tab
+ * is equal to "dim" plus the number of elements in "list".
+ */
+static int add_subs(struct isl_coalesce_info *info,
+	__isl_keep isl_aff_list *list, int dim)
+{
+	int extra_var;
+	int n;
+
+	if (!list)
+		return -1;
+
+	n = isl_aff_list_n_aff(list);
+	extra_var = n - (info->tab->n_var - dim);
+
+	if (isl_tab_extend_vars(info->tab, extra_var) < 0)
+		return -1;
+	if (isl_tab_extend_cons(info->tab, 2 * extra_var) < 0)
+		return -1;
+	if (add_sub_vars(info, list, dim, extra_var) < 0)
+		return -1;
+
+	return add_sub_equalities(info->tab, list, dim);
+}
+
+/* Coalesce basic map "j" into basic map "i" after adding the extra integer
+ * divisions in "i" but not in "j" to basic map "j", with values
+ * specified by "list".  The total number of elements in "list"
+ * is equal to the number of integer divisions in "i", while the number
+ * of NaN elements in the list is equal to the number of integer divisions
+ * in "j".
+ *
+ * If no coalescing can be performed, then we need to revert basic map "j"
+ * to its original state.  We do the same if basic map "i" gets dropped
+ * during the coalescing, even though this should not happen in practice
+ * since we have already checked for "j" being a subset of "i"
+ * before we reach this stage.
+ */
+static enum isl_change coalesce_with_subs(int i, int j,
+	struct isl_coalesce_info *info, __isl_keep isl_aff_list *list)
+{
+	isl_basic_map *bmap_j;
+	struct isl_tab_undo *snap;
+	unsigned dim;
+	enum isl_change change;
+
+	bmap_j = isl_basic_map_copy(info[j].bmap);
+	snap = isl_tab_snap(info[j].tab);
+
+	dim = isl_basic_map_dim(bmap_j, isl_dim_all);
+	dim -= isl_basic_map_dim(bmap_j, isl_dim_div);
+	if (add_subs(&info[j], list, dim) < 0)
+		goto error;
+
+	change = coalesce_local_pair(i, j, info);
+	if (change != isl_change_none && change != isl_change_drop_first) {
+		isl_basic_map_free(bmap_j);
+	} else {
+		isl_basic_map_free(info[j].bmap);
+		info[j].bmap = bmap_j;
+
+		if (isl_tab_rollback(info[j].tab, snap) < 0)
+			return isl_change_error;
+	}
+
+	return change;
+error:
+	isl_basic_map_free(bmap_j);
+	return isl_change_error;
+}
+
+/* Check if we can coalesce basic map "j" into basic map "i" after copying
+ * those extra integer divisions in "i" that can be simplified away
+ * using the extra equalities in "j".
+ * All divs are assumed to be known and not contain any nested divs.
+ *
+ * We first check if there are any extra equalities in "j" that we
+ * can exploit.  Then we check if every integer division in "i"
+ * either already appears in "j" or can be simplified using the
+ * extra equalities to a purely affine expression.
+ * If these tests succeed, then we try to coalesce the two basic maps
+ * by introducing extra dimensions in "j" corresponding to
+ * the extra integer divsisions "i" fixed to the corresponding
+ * purely affine expression.
+ */
+static enum isl_change check_coalesce_into_eq(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	unsigned n_div_i, n_div_j;
+	isl_basic_map *hull_i, *hull_j;
+	int equal, empty;
+	isl_aff_list *list;
+	enum isl_change change;
+
+	n_div_i = isl_basic_map_dim(info[i].bmap, isl_dim_div);
+	n_div_j = isl_basic_map_dim(info[j].bmap, isl_dim_div);
+	if (n_div_i <= n_div_j)
+		return isl_change_none;
+	if (info[j].bmap->n_eq == 0)
+		return isl_change_none;
+
+	hull_i = isl_basic_map_copy(info[i].bmap);
+	hull_i = isl_basic_map_plain_affine_hull(hull_i);
+	hull_j = isl_basic_map_copy(info[j].bmap);
+	hull_j = isl_basic_map_plain_affine_hull(hull_j);
+
+	hull_j = isl_basic_map_intersect(hull_j, isl_basic_map_copy(hull_i));
+	equal = isl_basic_map_plain_is_equal(hull_i, hull_j);
+	empty = isl_basic_map_plain_is_empty(hull_j);
+	isl_basic_map_free(hull_i);
+
+	if (equal < 0 || empty < 0)
+		goto error;
+	if (equal || empty) {
+		isl_basic_map_free(hull_j);
+		return isl_change_none;
+	}
+
+	list = set_up_substitutions(info[i].bmap, info[j].bmap, hull_j);
+	if (!list)
+		return isl_change_error;
+	if (isl_aff_list_n_aff(list) < n_div_i)
+		change = isl_change_none;
+	else
+		change = coalesce_with_subs(i, j, info, list);
+
+	isl_aff_list_free(list);
+
+	return change;
+error:
+	isl_basic_map_free(hull_j);
+	return isl_change_error;
+}
+
+/* Check if we can coalesce basic maps "i" and "j" after copying
+ * those extra integer divisions in one of the basic maps that can
+ * be simplified away using the extra equalities in the other basic map.
+ * We require all divs to be known in both basic maps.
+ * Furthermore, to simplify the comparison of div expressions,
+ * we do not allow any nested integer divisions.
+ */
+static enum isl_change check_coalesce_eq(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	isl_bool known, nested;
+	enum isl_change change;
+
+	known = isl_basic_map_divs_known(info[i].bmap);
+	if (known < 0 || !known)
+		return known < 0 ? isl_change_error : isl_change_none;
+	known = isl_basic_map_divs_known(info[j].bmap);
+	if (known < 0 || !known)
+		return known < 0 ? isl_change_error : isl_change_none;
+	nested = has_nested_div(info[i].bmap);
+	if (nested < 0 || nested)
+		return nested < 0 ? isl_change_error : isl_change_none;
+	nested = has_nested_div(info[j].bmap);
+	if (nested < 0 || nested)
+		return nested < 0 ? isl_change_error : isl_change_none;
+
+	change = check_coalesce_into_eq(i, j, info);
+	if (change != isl_change_none)
+		return change;
+	change = check_coalesce_into_eq(j, i, info);
+	if (change != isl_change_none)
+		return invert_change(change);
+
+	return isl_change_none;
+}
+
+/* Check if the union of the given pair of basic maps
+ * can be represented by a single basic map.
+ * If so, replace the pair by the single basic map and return
+ * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
+ * Otherwise, return isl_change_none.
+ *
+ * We first check if the two basic maps live in the same local space,
+ * after aligning the divs that differ by only an integer constant.
+ * If so, we do the complete check.  Otherwise, we check if they have
+ * the same number of integer divisions and can be coalesced, if one is
+ * an obvious subset of the other or if the extra integer divisions
+ * of one basic map can be simplified away using the extra equalities
+ * of the other basic map.
+ */
+static enum isl_change coalesce_pair(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	isl_bool same;
+	enum isl_change change;
+
+	if (harmonize_divs(&info[i], &info[j]) < 0)
+		return isl_change_error;
+	same = same_divs(info[i].bmap, info[j].bmap);
+	if (same < 0)
+		return isl_change_error;
+	if (same)
+		return coalesce_local_pair(i, j, info);
+
+	if (info[i].bmap->n_div == info[j].bmap->n_div) {
+		change = coalesce_local_pair(i, j, info);
+		if (change != isl_change_none)
+			return change;
+	}
+
+	change = coalesce_divs(i, j, info);
+	if (change != isl_change_none)
+		return change;
+
+	return check_coalesce_eq(i, j, info);
+}
+
+/* Return the maximum of "a" and "b".
+ */
+static int isl_max(int a, int b)
+{
+	return a > b ? a : b;
+}
+
+/* Pairwise coalesce the basic maps in the range [start1, end1[ of "info"
+ * with those in the range [start2, end2[, skipping basic maps
+ * that have been removed (either before or within this function).
+ *
+ * For each basic map i in the first range, we check if it can be coalesced
+ * with respect to any previously considered basic map j in the second range.
+ * If i gets dropped (because it was a subset of some j), then
+ * we can move on to the next basic map.
+ * If j gets dropped, we need to continue checking against the other
+ * previously considered basic maps.
+ * If the two basic maps got fused, then we recheck the fused basic map
+ * against the previously considered basic maps, starting at i + 1
+ * (even if start2 is greater than i + 1).
+ */
+static int coalesce_range(isl_ctx *ctx, struct isl_coalesce_info *info,
+	int start1, int end1, int start2, int end2)
+{
+	int i, j;
+
+	for (i = end1 - 1; i >= start1; --i) {
+		if (info[i].removed)
+			continue;
+		for (j = isl_max(i + 1, start2); j < end2; ++j) {
+			enum isl_change changed;
+
+			if (info[j].removed)
+				continue;
+			if (info[i].removed)
+				isl_die(ctx, isl_error_internal,
+					"basic map unexpectedly removed",
+					return -1);
+			changed = coalesce_pair(i, j, info);
+			switch (changed) {
+			case isl_change_error:
+				return -1;
+			case isl_change_none:
+			case isl_change_drop_second:
+				continue;
+			case isl_change_drop_first:
+				j = end2;
+				break;
+			case isl_change_fuse:
+				j = i;
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* Pairwise coalesce the basic maps described by the "n" elements of "info".
+ *
+ * We consider groups of basic maps that live in the same apparent
+ * affine hull and we first coalesce within such a group before we
+ * coalesce the elements in the group with elements of previously
+ * considered groups.  If a fuse happens during the second phase,
+ * then we also reconsider the elements within the group.
+ */
+static int coalesce(isl_ctx *ctx, int n, struct isl_coalesce_info *info)
+{
+	int start, end;
+
+	for (end = n; end > 0; end = start) {
+		start = end - 1;
+		while (start >= 1 &&
+		    info[start - 1].hull_hash == info[start].hull_hash)
+			start--;
+		if (coalesce_range(ctx, info, start, end, start, end) < 0)
+			return -1;
+		if (coalesce_range(ctx, info, start, end, end, n) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Update the basic maps in "map" based on the information in "info".
+ * In particular, remove the basic maps that have been marked removed and
+ * update the others based on the information in the corresponding tableau.
+ * Since we detected implicit equalities without calling
+ * isl_basic_map_gauss, we need to do it now.
+ * Also call isl_basic_map_simplify if we may have lost the definition
+ * of one or more integer divisions.
+ */
+static __isl_give isl_map *update_basic_maps(__isl_take isl_map *map,
+	int n, struct isl_coalesce_info *info)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	for (i = n - 1; i >= 0; --i) {
+		if (info[i].removed) {
+			isl_basic_map_free(map->p[i]);
+			if (i != map->n - 1)
+				map->p[i] = map->p[map->n - 1];
+			map->n--;
+			continue;
+		}
+
+		info[i].bmap = isl_basic_map_update_from_tab(info[i].bmap,
+							info[i].tab);
+		info[i].bmap = isl_basic_map_gauss(info[i].bmap, NULL);
+		if (info[i].simplify)
+			info[i].bmap = isl_basic_map_simplify(info[i].bmap);
+		info[i].bmap = isl_basic_map_finalize(info[i].bmap);
+		if (!info[i].bmap)
+			return isl_map_free(map);
+		ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_NO_IMPLICIT);
+		ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+		isl_basic_map_free(map->p[i]);
+		map->p[i] = info[i].bmap;
+		info[i].bmap = NULL;
+	}
+
+	return map;
+}
+
+/* For each pair of basic maps in the map, check if the union of the two
+ * can be represented by a single basic map.
+ * If so, replace the pair by the single basic map and start over.
+ *
+ * We factor out any (hidden) common factor from the constraint
+ * coefficients to improve the detection of adjacent constraints.
+ *
+ * Since we are constructing the tableaus of the basic maps anyway,
+ * we exploit them to detect implicit equalities and redundant constraints.
+ * This also helps the coalescing as it can ignore the redundant constraints.
+ * In order to avoid confusion, we make all implicit equalities explicit
+ * in the basic maps.  We don't call isl_basic_map_gauss, though,
+ * as that may affect the number of constraints.
+ * This means that we have to call isl_basic_map_gauss at the end
+ * of the computation (in update_basic_maps) to ensure that
+ * the basic maps are not left in an unexpected state.
+ * For each basic map, we also compute the hash of the apparent affine hull
+ * for use in coalesce.
+ */
+__isl_give isl_map *isl_map_coalesce(__isl_take isl_map *map)
+{
+	int i;
+	unsigned n;
+	isl_ctx *ctx;
+	struct isl_coalesce_info *info = NULL;
+
+	map = isl_map_remove_empty_parts(map);
+	if (!map)
+		return NULL;
+
+	if (map->n <= 1)
+		return map;
+
+	ctx = isl_map_get_ctx(map);
+	map = isl_map_sort_divs(map);
+	map = isl_map_cow(map);
+
+	if (!map)
+		return NULL;
+
+	n = map->n;
+
+	info = isl_calloc_array(map->ctx, struct isl_coalesce_info, n);
+	if (!info)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_reduce_coefficients(map->p[i]);
+		if (!map->p[i])
+			goto error;
+		info[i].bmap = isl_basic_map_copy(map->p[i]);
+		info[i].tab = isl_tab_from_basic_map(info[i].bmap, 0);
+		if (!info[i].tab)
+			goto error;
+		if (!ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_NO_IMPLICIT))
+			if (isl_tab_detect_implicit_equalities(info[i].tab) < 0)
+				goto error;
+		info[i].bmap = isl_tab_make_equalities_explicit(info[i].tab,
+								info[i].bmap);
+		if (!info[i].bmap)
+			goto error;
+		if (!ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_NO_REDUNDANT))
+			if (isl_tab_detect_redundant(info[i].tab) < 0)
+				goto error;
+		if (coalesce_info_set_hull_hash(&info[i]) < 0)
+			goto error;
+	}
+	for (i = map->n - 1; i >= 0; --i)
+		if (info[i].tab->empty)
+			drop(&info[i]);
+
+	if (coalesce(ctx, n, info) < 0)
+		goto error;
+
+	map = update_basic_maps(map, n, info);
+
+	clear_coalesce_info(n, info);
+
+	return map;
+error:
+	clear_coalesce_info(n, info);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* For each pair of basic sets in the set, check if the union of the two
+ * can be represented by a single basic set.
+ * If so, replace the pair by the single basic set and start over.
+ */
+struct isl_set *isl_set_coalesce(struct isl_set *set)
+{
+	return set_from_map(isl_map_coalesce(set_to_map(set)));
+}
diff --git a/final/lib/External/isl/isl_config.h.in b/final/lib/External/isl/isl_config.h.in
new file mode 100644
index 0000000..27b6f94
--- /dev/null
+++ b/final/lib/External/isl/isl_config.h.in
@@ -0,0 +1,217 @@
+/* isl_config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if HeaderSearchOptions::AddPath takes 4 arguments */
+#undef ADDPATH_TAKES_4_ARGUMENTS
+
+/* Clang installation prefix */
+#undef CLANG_PREFIX
+
+/* Define if CompilerInstance::createDiagnostics takes argc and argv */
+#undef CREATEDIAGNOSTICS_TAKES_ARG
+
+/* Define if CompilerInstance::createPreprocessor takes TranslationUnitKind */
+#undef CREATEPREPROCESSOR_TAKES_TUKIND
+
+/* Define if TargetInfo::CreateTargetInfo takes pointer */
+#undef CREATETARGETINFO_TAKES_POINTER
+
+/* Define if TargetInfo::CreateTargetInfo takes shared_ptr */
+#undef CREATETARGETINFO_TAKES_SHARED_PTR
+
+/* Define if Driver constructor takes default image name */
+#undef DRIVER_CTOR_TAKES_DEFAULTIMAGENAME
+
+/* Define to Diagnostic for older versions of clang */
+#undef DiagnosticsEngine
+
+/* most gcc compilers know a function __attribute__((__warn_unused_result__))
+   */
+#undef GCC_WARN_UNUSED_RESULT
+
+/* Define if llvm/ADT/OwningPtr.h exists */
+#undef HAVE_ADT_OWNINGPTR_H
+
+/* Define if clang/Basic/DiagnosticOptions.h exists */
+#undef HAVE_BASIC_DIAGNOSTICOPTIONS_H
+
+/* define if the compiler supports basic C++11 syntax */
+#undef HAVE_CXX11
+
+/* Define if Driver constructor takes CXXIsProduction argument */
+#undef HAVE_CXXISPRODUCTION
+
+/* Define to 1 if you have the declaration of `ffs', and to 0 if you don't. */
+#undef HAVE_DECL_FFS
+
+/* Define to 1 if you have the declaration of `mp_get_memory_functions', and
+   to 0 if you don't. */
+#undef HAVE_DECL_MP_GET_MEMORY_FUNCTIONS
+
+/* Define to 1 if you have the declaration of `snprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_SNPRINTF
+
+/* Define to 1 if you have the declaration of `strcasecmp', and to 0 if you
+   don't. */
+#undef HAVE_DECL_STRCASECMP
+
+/* Define to 1 if you have the declaration of `strncasecmp', and to 0 if you
+   don't. */
+#undef HAVE_DECL_STRNCASECMP
+
+/* Define to 1 if you have the declaration of `_BitScanForward', and to 0 if
+   you don't. */
+#undef HAVE_DECL__BITSCANFORWARD
+
+/* Define to 1 if you have the declaration of `_snprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL__SNPRINTF
+
+/* Define to 1 if you have the declaration of `_stricmp', and to 0 if you
+   don't. */
+#undef HAVE_DECL__STRICMP
+
+/* Define to 1 if you have the declaration of `_strnicmp', and to 0 if you
+   don't. */
+#undef HAVE_DECL__STRNICMP
+
+/* Define to 1 if you have the declaration of `__builtin_ffs', and to 0 if you
+   don't. */
+#undef HAVE_DECL___BUILTIN_FFS
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define if Driver constructor takes IsProduction argument */
+#undef HAVE_ISPRODUCTION
+
+/* Define if clang/Lex/PreprocessorOptions.h exists */
+#undef HAVE_LEX_PREPROCESSOROPTIONS_H
+
+/* Define to 1 if you have the `gmp' library (-lgmp). */
+#undef HAVE_LIBGMP
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if SourceManager has a setMainFileID method */
+#undef HAVE_SETMAINFILEID
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* define if your compiler has __attribute__ */
+#undef HAVE___ATTRIBUTE__
+
+/* Return type of HandleTopLevelDeclReturn */
+#undef HandleTopLevelDeclContinue
+
+/* Return type of HandleTopLevelDeclReturn */
+#undef HandleTopLevelDeclReturn
+
+/* Define to InputKind::C for newer versions of clang */
+#undef IK_C
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Defined if CompilerInstance::setInvocation takes a shared_ptr */
+#undef SETINVOCATION_TAKES_SHARED_PTR
+
+/* Define if CompilerInvocation::setLangDefaults takes 5 arguments */
+#undef SETLANGDEFAULTS_TAKES_5_ARGUMENTS
+
+/* The size of `char', as computed by sizeof. */
+#undef SIZEOF_CHAR
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of `void*', as computed by sizeof. */
+#undef SIZEOF_VOIDP
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if Driver::BuildCompilation takes ArrayRef */
+#undef USE_ARRAYREF
+
+/* use gmp to implement isl_int */
+#undef USE_GMP_FOR_MP
+
+/* use imath to implement isl_int */
+#undef USE_IMATH_FOR_MP
+
+/* Use small integer optimization */
+#undef USE_SMALL_INT_OPT
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to getParamType for newer versions of clang */
+#undef getArgType
+
+/* Define to getHostTriple for older versions of clang */
+#undef getDefaultTargetTriple
+
+/* Define to getInstantiationLineNumber for older versions of clang */
+#undef getExpansionLineNumber
+
+/* Define to getNumParams for newer versions of clang */
+#undef getNumArgs
+
+/* Define to getResultType for older versions of clang */
+#undef getReturnType
+
+/* Define to InitializeBuiltins for older versions of clang */
+#undef initializeBuiltins
+
+#include <isl_config_post.h>
diff --git a/final/lib/External/isl/isl_config_post.h b/final/lib/External/isl/isl_config_post.h
new file mode 100644
index 0000000..39373af
--- /dev/null
+++ b/final/lib/External/isl/isl_config_post.h
@@ -0,0 +1,38 @@
+#ifndef HAVE___ATTRIBUTE__
+#define __attribute__(x)
+#endif
+
+#if HAVE_DECL_FFS
+#include <strings.h>
+#endif
+
+#if (HAVE_DECL_FFS==0) && (HAVE_DECL___BUILTIN_FFS==1)
+#define ffs __builtin_ffs
+#endif
+
+#if !HAVE_DECL_FFS && !HAVE_DECL___BUILTIN_FFS && HAVE_DECL__BITSCANFORWARD
+int isl_ffs(int i);
+#define ffs isl_ffs
+#endif
+
+#if HAVE_DECL_STRCASECMP || HAVE_DECL_STRNCASECMP
+#include <strings.h>
+#endif
+
+#if !HAVE_DECL_STRCASECMP && HAVE_DECL__STRICMP
+#define strcasecmp _stricmp
+#endif
+
+#if !HAVE_DECL_STRNCASECMP && HAVE_DECL__STRNICMP
+#define strncasecmp _strnicmp
+#endif
+
+#if !HAVE_DECL_SNPRINTF && HAVE_DECL__SNPRINTF
+#define snprintf _snprintf
+#endif
+
+#ifdef GCC_WARN_UNUSED_RESULT
+#define WARN_UNUSED	GCC_WARN_UNUSED_RESULT
+#else
+#define WARN_UNUSED
+#endif
diff --git a/final/lib/External/isl/isl_constraint.c b/final/lib/External/isl/isl_constraint.c
new file mode 100644
index 0000000..92a6bb8
--- /dev/null
+++ b/final/lib/External/isl/isl_constraint.c
@@ -0,0 +1,1395 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ */
+
+#include <isl_map_private.h>
+#include <isl_constraint_private.h>
+#include <isl_space_private.h>
+#include <isl_seq.h>
+#include <isl_aff_private.h>
+#include <isl_local_space_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl/deprecated/constraint_int.h>
+
+#include <bset_to_bmap.c>
+#include <bset_from_bmap.c>
+
+#undef BASE
+#define BASE constraint
+
+#include <isl_list_templ.c>
+
+isl_ctx *isl_constraint_get_ctx(__isl_keep isl_constraint *c)
+{
+	return c ? isl_local_space_get_ctx(c->ls) : NULL;
+}
+
+static unsigned n(struct isl_constraint *c, enum isl_dim_type type)
+{
+	return isl_local_space_dim(c->ls, type);
+}
+
+static unsigned offset(struct isl_constraint *c, enum isl_dim_type type)
+{
+	return isl_local_space_offset(c->ls, type);
+}
+
+static unsigned basic_map_offset(__isl_keep isl_basic_map *bmap,
+							enum isl_dim_type type)
+{
+	return type == isl_dim_div ? 1 + isl_space_dim(bmap->dim, isl_dim_all)
+				   : 1 + isl_space_offset(bmap->dim, type);
+}
+
+static unsigned basic_set_offset(struct isl_basic_set *bset,
+							enum isl_dim_type type)
+{
+	isl_space *dim = bset->dim;
+	switch (type) {
+	case isl_dim_param:	return 1;
+	case isl_dim_in:	return 1 + dim->nparam;
+	case isl_dim_out:	return 1 + dim->nparam + dim->n_in;
+	case isl_dim_div:	return 1 + dim->nparam + dim->n_in + dim->n_out;
+	default:		return 0;
+	}
+}
+
+__isl_give isl_constraint *isl_constraint_alloc_vec(int eq,
+	__isl_take isl_local_space *ls, __isl_take isl_vec *v)
+{
+	isl_constraint *constraint;
+
+	if (!ls || !v)
+		goto error;
+
+	constraint = isl_alloc_type(isl_vec_get_ctx(v), isl_constraint);
+	if (!constraint)
+		goto error;
+
+	constraint->ref = 1;
+	constraint->eq = eq;
+	constraint->ls = ls;
+	constraint->v = v;
+
+	return constraint;
+error:
+	isl_local_space_free(ls);
+	isl_vec_free(v);
+	return NULL;
+}
+
+__isl_give isl_constraint *isl_constraint_alloc(int eq,
+	__isl_take isl_local_space *ls)
+{
+	isl_ctx *ctx;
+	isl_vec *v;
+
+	if (!ls)
+		return NULL;
+
+	ctx = isl_local_space_get_ctx(ls);
+	v = isl_vec_alloc(ctx, 1 + isl_local_space_dim(ls, isl_dim_all));
+	v = isl_vec_clr(v);
+	return isl_constraint_alloc_vec(eq, ls, v);
+}
+
+struct isl_constraint *isl_basic_map_constraint(struct isl_basic_map *bmap,
+	isl_int **line)
+{
+	int eq;
+	isl_ctx *ctx;
+	isl_vec *v;
+	isl_local_space *ls = NULL;
+	isl_constraint *constraint;
+
+	if (!bmap || !line)
+		goto error;
+
+	eq = line >= bmap->eq;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	ls = isl_basic_map_get_local_space(bmap);
+	v = isl_vec_alloc(ctx, 1 + isl_local_space_dim(ls, isl_dim_all));
+	if (!v)
+		goto error;
+	isl_seq_cpy(v->el, line[0], v->size);
+	constraint = isl_constraint_alloc_vec(eq, ls, v);
+
+	isl_basic_map_free(bmap);
+	return constraint;
+error:
+	isl_local_space_free(ls);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_constraint *isl_basic_set_constraint(struct isl_basic_set *bset,
+	isl_int **line)
+{
+	return isl_basic_map_constraint(bset_to_bmap(bset), line);
+}
+
+__isl_give isl_constraint *isl_constraint_alloc_equality(
+	__isl_take isl_local_space *ls)
+{
+	return isl_constraint_alloc(1, ls);
+}
+
+__isl_give isl_constraint *isl_constraint_alloc_inequality(
+	__isl_take isl_local_space *ls)
+{
+	return isl_constraint_alloc(0, ls);
+}
+
+struct isl_constraint *isl_constraint_dup(struct isl_constraint *c)
+{
+	if (!c)
+		return NULL;
+
+	return isl_constraint_alloc_vec(c->eq, isl_local_space_copy(c->ls),
+						isl_vec_copy(c->v));
+}
+
+struct isl_constraint *isl_constraint_cow(struct isl_constraint *c)
+{
+	if (!c)
+		return NULL;
+
+	if (c->ref == 1)
+		return c;
+	c->ref--;
+	return isl_constraint_dup(c);
+}
+
+struct isl_constraint *isl_constraint_copy(struct isl_constraint *constraint)
+{
+	if (!constraint)
+		return NULL;
+
+	constraint->ref++;
+	return constraint;
+}
+
+__isl_null isl_constraint *isl_constraint_free(__isl_take isl_constraint *c)
+{
+	if (!c)
+		return NULL;
+
+	if (--c->ref > 0)
+		return NULL;
+
+	isl_local_space_free(c->ls);
+	isl_vec_free(c->v);
+	free(c);
+
+	return NULL;
+}
+
+/* Return the number of constraints in "bmap", i.e., the
+ * number of times isl_basic_map_foreach_constraint will
+ * call the callback.
+ */
+int isl_basic_map_n_constraint(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+
+	return bmap->n_eq + bmap->n_ineq;
+}
+
+/* Return the number of constraints in "bset", i.e., the
+ * number of times isl_basic_set_foreach_constraint will
+ * call the callback.
+ */
+int isl_basic_set_n_constraint(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_n_constraint(bset);
+}
+
+isl_stat isl_basic_map_foreach_constraint(__isl_keep isl_basic_map *bmap,
+	isl_stat (*fn)(__isl_take isl_constraint *c, void *user), void *user)
+{
+	int i;
+	struct isl_constraint *c;
+
+	if (!bmap)
+		return isl_stat_error;
+
+	isl_assert(bmap->ctx, ISL_F_ISSET(bmap, ISL_BASIC_MAP_FINAL),
+			return isl_stat_error);
+
+	for (i = 0; i < bmap->n_eq; ++i) {
+		c = isl_basic_map_constraint(isl_basic_map_copy(bmap),
+						&bmap->eq[i]);
+		if (!c)
+			return isl_stat_error;
+		if (fn(c, user) < 0)
+			return isl_stat_error;
+	}
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		c = isl_basic_map_constraint(isl_basic_map_copy(bmap),
+						&bmap->ineq[i]);
+		if (!c)
+			return isl_stat_error;
+		if (fn(c, user) < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+isl_stat isl_basic_set_foreach_constraint(__isl_keep isl_basic_set *bset,
+	isl_stat (*fn)(__isl_take isl_constraint *c, void *user), void *user)
+{
+	return isl_basic_map_foreach_constraint(bset_to_bmap(bset), fn, user);
+}
+
+/* Add the constraint to the list that "user" points to, if it is not
+ * a div constraint.
+ */
+static isl_stat collect_constraint(__isl_take isl_constraint *constraint,
+	void *user)
+{
+	isl_constraint_list **list = user;
+
+	if (isl_constraint_is_div_constraint(constraint))
+		isl_constraint_free(constraint);
+	else
+		*list = isl_constraint_list_add(*list, constraint);
+
+	return isl_stat_ok;
+}
+
+/* Return a list of constraints that, when combined, are equivalent
+ * to "bmap".  The input is required to have only known divs.
+ *
+ * There is no need to include the div constraints as they are
+ * implied by the div expressions.
+ */
+__isl_give isl_constraint_list *isl_basic_map_get_constraint_list(
+	__isl_keep isl_basic_map *bmap)
+{
+	int n;
+	int known;
+	isl_ctx *ctx;
+	isl_constraint_list *list;
+
+	known = isl_basic_map_divs_known(bmap);
+	if (known < 0)
+		return NULL;
+	ctx = isl_basic_map_get_ctx(bmap);
+	if (!known)
+		isl_die(ctx, isl_error_invalid,
+			"input involves unknown divs", return NULL);
+
+	n = isl_basic_map_n_constraint(bmap);
+	list = isl_constraint_list_alloc(ctx, n);
+	if (isl_basic_map_foreach_constraint(bmap,
+					    &collect_constraint, &list) < 0)
+		list = isl_constraint_list_free(list);
+
+	return list;
+}
+
+/* Return a list of constraints that, when combined, are equivalent
+ * to "bset".  The input is required to have only known divs.
+ */
+__isl_give isl_constraint_list *isl_basic_set_get_constraint_list(
+	__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_get_constraint_list(bset);
+}
+
+int isl_constraint_is_equal(struct isl_constraint *constraint1,
+	struct isl_constraint *constraint2)
+{
+	int equal;
+
+	if (!constraint1 || !constraint2)
+		return 0;
+	if (constraint1->eq != constraint2->eq)
+		return 0;
+	equal = isl_local_space_is_equal(constraint1->ls, constraint2->ls);
+	if (equal < 0 || !equal)
+		return equal;
+	return isl_vec_is_equal(constraint1->v, constraint2->v);
+}
+
+struct isl_basic_map *isl_basic_map_add_constraint(
+	struct isl_basic_map *bmap, struct isl_constraint *constraint)
+{
+	isl_ctx *ctx;
+	isl_space *dim;
+	int equal_space;
+
+	if (!bmap || !constraint)
+		goto error;
+
+	ctx = isl_constraint_get_ctx(constraint);
+	dim = isl_constraint_get_space(constraint);
+	equal_space = isl_space_is_equal(bmap->dim, dim);
+	isl_space_free(dim);
+	isl_assert(ctx, equal_space, goto error);
+
+	bmap = isl_basic_map_intersect(bmap,
+				isl_basic_map_from_constraint(constraint));
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_constraint_free(constraint);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_add_constraint(
+	struct isl_basic_set *bset, struct isl_constraint *constraint)
+{
+	return bset_from_bmap(isl_basic_map_add_constraint(bset_to_bmap(bset),
+							    constraint));
+}
+
+__isl_give isl_map *isl_map_add_constraint(__isl_take isl_map *map,
+	__isl_take isl_constraint *constraint)
+{
+	isl_basic_map *bmap;
+
+	bmap = isl_basic_map_from_constraint(constraint);
+	map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+	return map;
+}
+
+__isl_give isl_set *isl_set_add_constraint(__isl_take isl_set *set,
+	__isl_take isl_constraint *constraint)
+{
+	return isl_map_add_constraint(set, constraint);
+}
+
+__isl_give isl_space *isl_constraint_get_space(
+	__isl_keep isl_constraint *constraint)
+{
+	return constraint ? isl_local_space_get_space(constraint->ls) : NULL;
+}
+
+__isl_give isl_local_space *isl_constraint_get_local_space(
+	__isl_keep isl_constraint *constraint)
+{
+	return constraint ? isl_local_space_copy(constraint->ls) : NULL;
+}
+
+int isl_constraint_dim(struct isl_constraint *constraint,
+	enum isl_dim_type type)
+{
+	if (!constraint)
+		return -1;
+	return n(constraint, type);
+}
+
+isl_bool isl_constraint_involves_dims(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	isl_ctx *ctx;
+	int *active = NULL;
+	isl_bool involves = isl_bool_false;
+
+	if (!constraint)
+		return isl_bool_error;
+	if (n == 0)
+		return isl_bool_false;
+
+	ctx = isl_constraint_get_ctx(constraint);
+	if (first + n > isl_constraint_dim(constraint, type))
+		isl_die(ctx, isl_error_invalid,
+			"range out of bounds", return isl_bool_error);
+
+	active = isl_local_space_get_active(constraint->ls,
+					    constraint->v->el + 1);
+	if (!active)
+		goto error;
+
+	first += isl_local_space_offset(constraint->ls, type) - 1;
+	for (i = 0; i < n; ++i)
+		if (active[first + i]) {
+			involves = isl_bool_true;
+			break;
+		}
+
+	free(active);
+
+	return involves;
+error:
+	free(active);
+	return isl_bool_error;
+}
+
+/* Does the given constraint represent a lower bound on the given
+ * dimension?
+ */
+isl_bool isl_constraint_is_lower_bound(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!constraint)
+		return isl_bool_error;
+
+	if (pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+			"position out of bounds", return isl_bool_error);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	return isl_int_is_pos(constraint->v->el[pos]);
+}
+
+/* Does the given constraint represent an upper bound on the given
+ * dimension?
+ */
+isl_bool isl_constraint_is_upper_bound(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!constraint)
+		return isl_bool_error;
+
+	if (pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+			"position out of bounds", return isl_bool_error);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	return isl_int_is_neg(constraint->v->el[pos]);
+}
+
+const char *isl_constraint_get_dim_name(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, unsigned pos)
+{
+	return constraint ?
+	    isl_local_space_get_dim_name(constraint->ls, type, pos) : NULL;
+}
+
+void isl_constraint_get_constant(__isl_keep isl_constraint *constraint,
+	isl_int *v)
+{
+	if (!constraint)
+		return;
+	isl_int_set(*v, constraint->v->el[0]);
+}
+
+/* Return the constant term of "constraint".
+ */
+__isl_give isl_val *isl_constraint_get_constant_val(
+	__isl_keep isl_constraint *constraint)
+{
+	isl_ctx *ctx;
+
+	if (!constraint)
+		return NULL;
+
+	ctx = isl_constraint_get_ctx(constraint);
+	return isl_val_int_from_isl_int(ctx, constraint->v->el[0]);
+}
+
+void isl_constraint_get_coefficient(struct isl_constraint *constraint,
+	enum isl_dim_type type, int pos, isl_int *v)
+{
+	if (!constraint)
+		return;
+
+	if (pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(constraint->v->ctx, isl_error_invalid,
+			"position out of bounds", return);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	isl_int_set(*v, constraint->v->el[pos]);
+}
+
+/* Return the coefficient of the variable of type "type" at position "pos"
+ * of "constraint".
+ */
+__isl_give isl_val *isl_constraint_get_coefficient_val(
+	__isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos)
+{
+	isl_ctx *ctx;
+
+	if (!constraint)
+		return NULL;
+
+	ctx = isl_constraint_get_ctx(constraint);
+	if (pos < 0 || pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(ctx, isl_error_invalid,
+			"position out of bounds", return NULL);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	return isl_val_int_from_isl_int(ctx, constraint->v->el[pos]);
+}
+
+__isl_give isl_aff *isl_constraint_get_div(__isl_keep isl_constraint *constraint,
+	int pos)
+{
+	if (!constraint)
+		return NULL;
+
+	return isl_local_space_get_div(constraint->ls, pos);
+}
+
+__isl_give isl_constraint *isl_constraint_set_constant(
+	__isl_take isl_constraint *constraint, isl_int v)
+{
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	constraint->v = isl_vec_cow(constraint->v);
+	if (!constraint->v)
+		return isl_constraint_free(constraint);
+
+	isl_int_set(constraint->v->el[0], v);
+	return constraint;
+}
+
+/* Replace the constant term of "constraint" by "v".
+ */
+__isl_give isl_constraint *isl_constraint_set_constant_val(
+	__isl_take isl_constraint *constraint, __isl_take isl_val *v)
+{
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint || !v)
+		goto error;
+	if (!isl_val_is_int(v))
+		isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+			"expecting integer value", goto error);
+	constraint->v = isl_vec_set_element_val(constraint->v, 0, v);
+	if (!constraint->v)
+		constraint = isl_constraint_free(constraint);
+	return constraint;
+error:
+	isl_val_free(v);
+	return isl_constraint_free(constraint);
+}
+
+__isl_give isl_constraint *isl_constraint_set_constant_si(
+	__isl_take isl_constraint *constraint, int v)
+{
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	constraint->v = isl_vec_cow(constraint->v);
+	if (!constraint->v)
+		return isl_constraint_free(constraint);
+
+	isl_int_set_si(constraint->v->el[0], v);
+	return constraint;
+}
+
+__isl_give isl_constraint *isl_constraint_set_coefficient(
+	__isl_take isl_constraint *constraint,
+	enum isl_dim_type type, int pos, isl_int v)
+{
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	if (pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(constraint->v->ctx, isl_error_invalid,
+			"position out of bounds",
+			return isl_constraint_free(constraint));
+
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	constraint->v = isl_vec_cow(constraint->v);
+	if (!constraint->v)
+		return isl_constraint_free(constraint);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	isl_int_set(constraint->v->el[pos], v);
+
+	return constraint;
+}
+
+/* Replace the coefficient of the variable of type "type" at position "pos"
+ * of "constraint" by "v".
+ */
+__isl_give isl_constraint *isl_constraint_set_coefficient_val(
+	__isl_take isl_constraint *constraint,
+	enum isl_dim_type type, int pos, __isl_take isl_val *v)
+{
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint || !v)
+		goto error;
+	if (!isl_val_is_int(v))
+		isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+			"expecting integer value", goto error);
+
+	if (pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+			"position out of bounds", goto error);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	constraint->v = isl_vec_set_element_val(constraint->v, pos, v);
+	if (!constraint->v)
+		constraint = isl_constraint_free(constraint);
+	return constraint;
+error:
+	isl_val_free(v);
+	return isl_constraint_free(constraint);
+}
+
+__isl_give isl_constraint *isl_constraint_set_coefficient_si(
+	__isl_take isl_constraint *constraint,
+	enum isl_dim_type type, int pos, int v)
+{
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	if (pos >= isl_local_space_dim(constraint->ls, type))
+		isl_die(constraint->v->ctx, isl_error_invalid,
+			"position out of bounds",
+			return isl_constraint_free(constraint));
+
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	constraint->v = isl_vec_cow(constraint->v);
+	if (!constraint->v)
+		return isl_constraint_free(constraint);
+
+	pos += isl_local_space_offset(constraint->ls, type);
+	isl_int_set_si(constraint->v->el[pos], v);
+
+	return constraint;
+}
+
+struct isl_constraint *isl_constraint_negate(struct isl_constraint *constraint)
+{
+	isl_ctx *ctx;
+
+	constraint = isl_constraint_cow(constraint);
+	if (!constraint)
+		return NULL;
+
+	ctx = isl_constraint_get_ctx(constraint);
+	if (isl_constraint_is_equality(constraint))
+		isl_die(ctx, isl_error_invalid, "cannot negate equality",
+			return isl_constraint_free(constraint));
+	constraint->v = isl_vec_neg(constraint->v);
+	constraint->v = isl_vec_cow(constraint->v);
+	if (!constraint->v)
+		return isl_constraint_free(constraint);
+	isl_int_sub_ui(constraint->v->el[0], constraint->v->el[0], 1);
+	return constraint;
+}
+
+isl_bool isl_constraint_is_equality(struct isl_constraint *constraint)
+{
+	if (!constraint)
+		return isl_bool_error;
+	return constraint->eq;
+}
+
+int isl_constraint_is_div_constraint(__isl_keep isl_constraint *constraint)
+{
+	int i;
+	int n_div;
+
+	if (!constraint)
+		return -1;
+	if (isl_constraint_is_equality(constraint))
+		return 0;
+	n_div = isl_constraint_dim(constraint, isl_dim_div);
+	for (i = 0; i < n_div; ++i) {
+		isl_bool is_div;
+		is_div = isl_local_space_is_div_constraint(constraint->ls,
+							constraint->v->el, i);
+		if (is_div < 0 || is_div)
+			return is_div;
+	}
+
+	return 0;
+}
+
+/* We manually set ISL_BASIC_SET_FINAL instead of calling
+ * isl_basic_map_finalize because we want to keep the position
+ * of the divs and we therefore do not want to throw away redundant divs.
+ * This is arguably a bit fragile.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_constraint(
+	__isl_take isl_constraint *constraint)
+{
+	int k;
+	isl_local_space *ls;
+	struct isl_basic_map *bmap;
+	isl_int *c;
+	unsigned total;
+
+	if (!constraint)
+		return NULL;
+
+	ls = isl_local_space_copy(constraint->ls);
+	bmap = isl_basic_map_from_local_space(ls);
+	bmap = isl_basic_map_extend_constraints(bmap, 1, 1);
+	if (isl_constraint_is_equality(constraint)) {
+		k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			goto error;
+		c = bmap->eq[k];
+	}
+	else {
+		k = isl_basic_map_alloc_inequality(bmap);
+		if (k < 0)
+			goto error;
+		c = bmap->ineq[k];
+	}
+	total = isl_basic_map_total_dim(bmap);
+	isl_seq_cpy(c, constraint->v->el, 1 + total);
+	isl_constraint_free(constraint);
+	if (bmap)
+		ISL_F_SET(bmap, ISL_BASIC_SET_FINAL);
+	return bmap;
+error:
+	isl_constraint_free(constraint);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_from_constraint(
+	__isl_take isl_constraint *constraint)
+{
+	if (!constraint)
+		return NULL;
+
+	if (isl_constraint_dim(constraint, isl_dim_in) != 0)
+		isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid,
+			"not a set constraint", goto error);
+	return bset_from_bmap(isl_basic_map_from_constraint(constraint));
+error:
+	isl_constraint_free(constraint);
+	return NULL;
+}
+
+/* Is the variable of "type" at position "pos" of "bmap" defined
+ * in terms of earlier dimensions through an equality?
+ *
+ * If so, and if c is not NULL, then return a copy of this equality in *c.
+ */
+isl_bool isl_basic_map_has_defining_equality(
+	__isl_keep isl_basic_map *bmap, enum isl_dim_type type, int pos,
+	__isl_give isl_constraint **c)
+{
+	int i;
+	unsigned offset;
+	unsigned total;
+
+	if (!bmap)
+		return isl_bool_error;
+	offset = basic_map_offset(bmap, type);
+	total = isl_basic_map_total_dim(bmap);
+	if (pos >= isl_basic_map_dim(bmap, type))
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"invalid position", return isl_bool_error);
+	for (i = 0; i < bmap->n_eq; ++i) {
+		if (isl_int_is_zero(bmap->eq[i][offset + pos]) ||
+		    isl_seq_first_non_zero(bmap->eq[i]+offset+pos+1,
+					   1+total-offset-pos-1) != -1)
+			continue;
+		if (c)
+			*c = isl_basic_map_constraint(isl_basic_map_copy(bmap),
+								&bmap->eq[i]);
+		return isl_bool_true;
+	}
+	return isl_bool_false;
+}
+
+/* Is the variable of "type" at position "pos" of "bset" defined
+ * in terms of earlier dimensions through an equality?
+ *
+ * If so, and if c is not NULL, then return a copy of this equality in *c.
+ */
+isl_bool isl_basic_set_has_defining_equality(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type type, int pos,
+	__isl_give isl_constraint **c)
+{
+	return isl_basic_map_has_defining_equality(bset_to_bmap(bset),
+						    type, pos, c);
+}
+
+isl_bool isl_basic_set_has_defining_inequalities(
+	struct isl_basic_set *bset, enum isl_dim_type type, int pos,
+	struct isl_constraint **lower,
+	struct isl_constraint **upper)
+{
+	int i, j;
+	unsigned offset;
+	unsigned total;
+	isl_int m;
+	isl_int **lower_line, **upper_line;
+
+	if (!bset)
+		return isl_bool_error;
+	offset = basic_set_offset(bset, type);
+	total = isl_basic_set_total_dim(bset);
+	if (pos >= isl_basic_set_dim(bset, type))
+		isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid,
+			"invalid position", return isl_bool_error);
+	isl_int_init(m);
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (isl_int_is_zero(bset->ineq[i][offset + pos]))
+			continue;
+		if (isl_int_is_one(bset->ineq[i][offset + pos]))
+			continue;
+		if (isl_int_is_negone(bset->ineq[i][offset + pos]))
+			continue;
+		if (isl_seq_first_non_zero(bset->ineq[i]+offset+pos+1,
+						1+total-offset-pos-1) != -1)
+			continue;
+		for (j = i + 1; j < bset->n_ineq; ++j) {
+			if (!isl_seq_is_neg(bset->ineq[i]+1, bset->ineq[j]+1,
+					    total))
+				continue;
+			isl_int_add(m, bset->ineq[i][0], bset->ineq[j][0]);
+			if (isl_int_abs_ge(m, bset->ineq[i][offset+pos]))
+				continue;
+
+			if (isl_int_is_pos(bset->ineq[i][offset+pos])) {
+				lower_line = &bset->ineq[i];
+				upper_line = &bset->ineq[j];
+			} else {
+				lower_line = &bset->ineq[j];
+				upper_line = &bset->ineq[i];
+			}
+			*lower = isl_basic_set_constraint(
+					isl_basic_set_copy(bset), lower_line);
+			*upper = isl_basic_set_constraint(
+					isl_basic_set_copy(bset), upper_line);
+			isl_int_clear(m);
+			return isl_bool_true;
+		}
+	}
+	*lower = NULL;
+	*upper = NULL;
+	isl_int_clear(m);
+	return isl_bool_false;
+}
+
+/* Given two constraints "a" and "b" on the variable at position "abs_pos"
+ * (in "a" and "b"), add a constraint to "bset" that ensures that the
+ * bound implied by "a" is (strictly) larger than the bound implied by "b".
+ *
+ * If both constraints imply lower bounds, then this means that "a" is
+ * active in the result.
+ * If both constraints imply upper bounds, then this means that "b" is
+ * active in the result.
+ */
+static __isl_give isl_basic_set *add_larger_bound_constraint(
+	__isl_take isl_basic_set *bset, isl_int *a, isl_int *b,
+	unsigned abs_pos, int strict)
+{
+	int k;
+	isl_int t;
+	unsigned total;
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+
+	total = isl_basic_set_dim(bset, isl_dim_all);
+
+	isl_int_init(t);
+	isl_int_neg(t, b[1 + abs_pos]);
+
+	isl_seq_combine(bset->ineq[k], t, a, a[1 + abs_pos], b, 1 + abs_pos);
+	isl_seq_combine(bset->ineq[k] + 1 + abs_pos,
+		t, a + 1 + abs_pos + 1, a[1 + abs_pos], b + 1 + abs_pos + 1,
+		total - abs_pos);
+
+	if (strict)
+		isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1);
+
+	isl_int_clear(t);
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Add constraints to "context" that ensure that "u" is the smallest
+ * (and therefore active) upper bound on "abs_pos" in "bset" and return
+ * the resulting basic set.
+ */
+static __isl_give isl_basic_set *set_smallest_upper_bound(
+	__isl_keep isl_basic_set *context,
+	__isl_keep isl_basic_set *bset, unsigned abs_pos, int n_upper, int u)
+{
+	int j;
+
+	context = isl_basic_set_copy(context);
+	context = isl_basic_set_cow(context);
+
+	context = isl_basic_set_extend_constraints(context, 0, n_upper - 1);
+
+	for (j = 0; j < bset->n_ineq; ++j) {
+		if (j == u)
+			continue;
+		if (!isl_int_is_neg(bset->ineq[j][1 + abs_pos]))
+			continue;
+		context = add_larger_bound_constraint(context,
+			bset->ineq[j], bset->ineq[u], abs_pos, j > u);
+	}
+
+	context = isl_basic_set_simplify(context);
+	context = isl_basic_set_finalize(context);
+
+	return context;
+}
+
+/* Add constraints to "context" that ensure that "u" is the largest
+ * (and therefore active) upper bound on "abs_pos" in "bset" and return
+ * the resulting basic set.
+ */
+static __isl_give isl_basic_set *set_largest_lower_bound(
+	__isl_keep isl_basic_set *context,
+	__isl_keep isl_basic_set *bset, unsigned abs_pos, int n_lower, int l)
+{
+	int j;
+
+	context = isl_basic_set_copy(context);
+	context = isl_basic_set_cow(context);
+
+	context = isl_basic_set_extend_constraints(context, 0, n_lower - 1);
+
+	for (j = 0; j < bset->n_ineq; ++j) {
+		if (j == l)
+			continue;
+		if (!isl_int_is_pos(bset->ineq[j][1 + abs_pos]))
+			continue;
+		context = add_larger_bound_constraint(context,
+			bset->ineq[l], bset->ineq[j], abs_pos, j > l);
+	}
+
+	context = isl_basic_set_simplify(context);
+	context = isl_basic_set_finalize(context);
+
+	return context;
+}
+
+static isl_stat foreach_upper_bound(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned abs_pos,
+	__isl_take isl_basic_set *context, int n_upper,
+	isl_stat (*fn)(__isl_take isl_constraint *lower,
+		  __isl_take isl_constraint *upper,
+		  __isl_take isl_basic_set *bset, void *user), void *user)
+{
+	isl_basic_set *context_i;
+	isl_constraint *upper = NULL;
+	int i;
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (isl_int_is_zero(bset->ineq[i][1 + abs_pos]))
+			continue;
+
+		context_i = set_smallest_upper_bound(context, bset,
+							abs_pos, n_upper, i);
+		if (isl_basic_set_is_empty(context_i)) {
+			isl_basic_set_free(context_i);
+			continue;
+		}
+		upper = isl_basic_set_constraint(isl_basic_set_copy(bset),
+						&bset->ineq[i]);
+		if (!upper || !context_i)
+			goto error;
+		if (fn(NULL, upper, context_i, user) < 0)
+			break;
+	}
+
+	isl_basic_set_free(context);
+
+	if (i < bset->n_ineq)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+error:
+	isl_constraint_free(upper);
+	isl_basic_set_free(context_i);
+	isl_basic_set_free(context);
+	return isl_stat_error;
+}
+
+static isl_stat foreach_lower_bound(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned abs_pos,
+	__isl_take isl_basic_set *context, int n_lower,
+	isl_stat (*fn)(__isl_take isl_constraint *lower,
+		  __isl_take isl_constraint *upper,
+		  __isl_take isl_basic_set *bset, void *user), void *user)
+{
+	isl_basic_set *context_i;
+	isl_constraint *lower = NULL;
+	int i;
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (isl_int_is_zero(bset->ineq[i][1 + abs_pos]))
+			continue;
+
+		context_i = set_largest_lower_bound(context, bset,
+							abs_pos, n_lower, i);
+		if (isl_basic_set_is_empty(context_i)) {
+			isl_basic_set_free(context_i);
+			continue;
+		}
+		lower = isl_basic_set_constraint(isl_basic_set_copy(bset),
+						&bset->ineq[i]);
+		if (!lower || !context_i)
+			goto error;
+		if (fn(lower, NULL, context_i, user) < 0)
+			break;
+	}
+
+	isl_basic_set_free(context);
+
+	if (i < bset->n_ineq)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+error:
+	isl_constraint_free(lower);
+	isl_basic_set_free(context_i);
+	isl_basic_set_free(context);
+	return isl_stat_error;
+}
+
+static isl_stat foreach_bound_pair(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned abs_pos,
+	__isl_take isl_basic_set *context, int n_lower, int n_upper,
+	isl_stat (*fn)(__isl_take isl_constraint *lower,
+		  __isl_take isl_constraint *upper,
+		  __isl_take isl_basic_set *bset, void *user), void *user)
+{
+	isl_basic_set *context_i, *context_j;
+	isl_constraint *lower = NULL;
+	isl_constraint *upper = NULL;
+	int i, j;
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (!isl_int_is_pos(bset->ineq[i][1 + abs_pos]))
+			continue;
+
+		context_i = set_largest_lower_bound(context, bset,
+							abs_pos, n_lower, i);
+		if (isl_basic_set_is_empty(context_i)) {
+			isl_basic_set_free(context_i);
+			continue;
+		}
+
+		for (j = 0; j < bset->n_ineq; ++j) {
+			if (!isl_int_is_neg(bset->ineq[j][1 + abs_pos]))
+				continue;
+
+			context_j = set_smallest_upper_bound(context_i, bset,
+							    abs_pos, n_upper, j);
+			context_j = isl_basic_set_extend_constraints(context_j,
+									0, 1);
+			context_j = add_larger_bound_constraint(context_j,
+				bset->ineq[i], bset->ineq[j], abs_pos, 0);
+			context_j = isl_basic_set_simplify(context_j);
+			context_j = isl_basic_set_finalize(context_j);
+			if (isl_basic_set_is_empty(context_j)) {
+				isl_basic_set_free(context_j);
+				continue;
+			}
+			lower = isl_basic_set_constraint(isl_basic_set_copy(bset),
+							&bset->ineq[i]);
+			upper = isl_basic_set_constraint(isl_basic_set_copy(bset),
+							&bset->ineq[j]);
+			if (!lower || !upper || !context_j)
+				goto error;
+			if (fn(lower, upper, context_j, user) < 0)
+				break;
+		}
+
+		isl_basic_set_free(context_i);
+
+		if (j < bset->n_ineq)
+			break;
+	}
+
+	isl_basic_set_free(context);
+
+	if (i < bset->n_ineq)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+error:
+	isl_constraint_free(lower);
+	isl_constraint_free(upper);
+	isl_basic_set_free(context_i);
+	isl_basic_set_free(context_j);
+	isl_basic_set_free(context);
+	return isl_stat_error;
+}
+
+/* For each pair of lower and upper bounds on the variable "pos"
+ * of type "type", call "fn" with these lower and upper bounds and the
+ * set of constraints on the remaining variables where these bounds
+ * are active, i.e., (stricly) larger/smaller than the other lower/upper bounds.
+ *
+ * If the designated variable is equal to an affine combination of the
+ * other variables then fn is called with both lower and upper
+ * set to the corresponding equality.
+ *
+ * If there is no lower (or upper) bound, then NULL is passed
+ * as the corresponding bound.
+ *
+ * We first check if the variable is involved in any equality.
+ * If not, we count the number of lower and upper bounds and
+ * act accordingly.
+ */
+isl_stat isl_basic_set_foreach_bound_pair(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos,
+	isl_stat (*fn)(__isl_take isl_constraint *lower,
+		  __isl_take isl_constraint *upper,
+		  __isl_take isl_basic_set *bset, void *user), void *user)
+{
+	int i;
+	isl_constraint *lower = NULL;
+	isl_constraint *upper = NULL;
+	isl_basic_set *context = NULL;
+	unsigned abs_pos;
+	int n_lower, n_upper;
+
+	if (!bset)
+		return isl_stat_error;
+	isl_assert(bset->ctx, pos < isl_basic_set_dim(bset, type),
+		return isl_stat_error);
+	isl_assert(bset->ctx, type == isl_dim_param || type == isl_dim_set,
+		return isl_stat_error);
+
+	abs_pos = pos;
+	if (type == isl_dim_set)
+		abs_pos += isl_basic_set_dim(bset, isl_dim_param);
+
+	for (i = 0; i < bset->n_eq; ++i) {
+		if (isl_int_is_zero(bset->eq[i][1 + abs_pos]))
+			continue;
+
+		lower = isl_basic_set_constraint(isl_basic_set_copy(bset),
+						&bset->eq[i]);
+		upper = isl_constraint_copy(lower);
+		context = isl_basic_set_remove_dims(isl_basic_set_copy(bset),
+					type, pos, 1);
+		if (!lower || !upper || !context)
+			goto error;
+		return fn(lower, upper, context, user);
+	}
+
+	n_lower = 0;
+	n_upper = 0;
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (isl_int_is_pos(bset->ineq[i][1 + abs_pos]))
+			n_lower++;
+		else if (isl_int_is_neg(bset->ineq[i][1 + abs_pos]))
+			n_upper++;
+	}
+
+	context = isl_basic_set_copy(bset);
+	context = isl_basic_set_cow(context);
+	if (!context)
+		goto error;
+	for (i = context->n_ineq - 1; i >= 0; --i)
+		if (!isl_int_is_zero(context->ineq[i][1 + abs_pos]))
+			isl_basic_set_drop_inequality(context, i);
+
+	context = isl_basic_set_drop(context, type, pos, 1);
+	if (!n_lower && !n_upper)
+		return fn(NULL, NULL, context, user);
+	if (!n_lower)
+		return foreach_upper_bound(bset, type, abs_pos, context, n_upper,
+						fn, user);
+	if (!n_upper)
+		return foreach_lower_bound(bset, type, abs_pos, context, n_lower,
+						fn, user);
+	return foreach_bound_pair(bset, type, abs_pos, context, n_lower, n_upper,
+					fn, user);
+error:
+	isl_constraint_free(lower);
+	isl_constraint_free(upper);
+	isl_basic_set_free(context);
+	return -1;
+}
+
+__isl_give isl_aff *isl_constraint_get_bound(
+	__isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos)
+{
+	isl_aff *aff;
+	isl_ctx *ctx;
+
+	if (!constraint)
+		return NULL;
+	ctx = isl_constraint_get_ctx(constraint);
+	if (pos >= isl_constraint_dim(constraint, type))
+		isl_die(ctx, isl_error_invalid,
+			"index out of bounds", return NULL);
+	if (isl_constraint_dim(constraint, isl_dim_in) != 0)
+		isl_die(ctx, isl_error_invalid,
+			"not a set constraint", return NULL);
+
+	pos += offset(constraint, type);
+	if (isl_int_is_zero(constraint->v->el[pos]))
+		isl_die(ctx, isl_error_invalid,
+			"constraint does not define a bound on given dimension",
+			return NULL);
+
+	aff = isl_aff_alloc(isl_local_space_copy(constraint->ls));
+	if (!aff)
+		return NULL;
+
+	if (isl_int_is_neg(constraint->v->el[pos]))
+		isl_seq_cpy(aff->v->el + 1, constraint->v->el, aff->v->size - 1);
+	else
+		isl_seq_neg(aff->v->el + 1, constraint->v->el, aff->v->size - 1);
+	isl_int_set_si(aff->v->el[1 + pos], 0);
+	isl_int_abs(aff->v->el[0], constraint->v->el[pos]);
+
+	return aff;
+}
+
+/* For an inequality constraint
+ *
+ *	f >= 0
+ *
+ * or an equality constraint
+ *
+ *	f = 0
+ *
+ * return the affine expression f.
+ */
+__isl_give isl_aff *isl_constraint_get_aff(
+	__isl_keep isl_constraint *constraint)
+{
+	isl_aff *aff;
+
+	if (!constraint)
+		return NULL;
+
+	aff = isl_aff_alloc(isl_local_space_copy(constraint->ls));
+	if (!aff)
+		return NULL;
+
+	isl_seq_cpy(aff->v->el + 1, constraint->v->el, aff->v->size - 1);
+	isl_int_set_si(aff->v->el[0], 1);
+
+	return aff;
+}
+
+/* Construct an inequality (eq = 0) or equality (eq = 1) constraint from "aff".
+ * In particular, construct aff >= 0 or aff = 0.
+ *
+ * The denominator of "aff" can be ignored.
+ */
+static __isl_give isl_constraint *isl_constraint_alloc_aff(int eq,
+	__isl_take isl_aff *aff)
+{
+	isl_local_space *ls;
+	isl_vec *v;
+
+	if (!aff)
+		return NULL;
+	ls = isl_aff_get_domain_local_space(aff);
+	v = isl_vec_drop_els(isl_vec_copy(aff->v), 0, 1);
+	isl_aff_free(aff);
+
+	return isl_constraint_alloc_vec(eq, ls, v);
+}
+
+/* Construct an equality constraint equating the given affine expression
+ * to zero.
+ */
+__isl_give isl_constraint *isl_equality_from_aff(__isl_take isl_aff *aff)
+{
+	return isl_constraint_alloc_aff(1, aff);
+}
+
+/* Construct an inequality constraint enforcing the given affine expression
+ * to be non-negative.
+ */
+__isl_give isl_constraint *isl_inequality_from_aff(__isl_take isl_aff *aff)
+{
+	return isl_constraint_alloc_aff(0, aff);
+}
+
+/* Compare two isl_constraints.
+ *
+ * Return -1 if "c1" is "smaller" than "c2", 1 if "c1" is "greater"
+ * than "c2" and 0 if they are equal.
+ *
+ * The order is fairly arbitrary.  We do consider constraints that only involve
+ * earlier dimensions as "smaller".
+ */
+int isl_constraint_plain_cmp(__isl_keep isl_constraint *c1,
+	__isl_keep isl_constraint *c2)
+{
+	int cmp;
+	int last1, last2;
+
+	if (c1 == c2)
+		return 0;
+	if (!c1)
+		return -1;
+	if (!c2)
+		return 1;
+	cmp = isl_local_space_cmp(c1->ls, c2->ls);
+	if (cmp != 0)
+		return cmp;
+
+	last1 = isl_seq_last_non_zero(c1->v->el + 1, c1->v->size - 1);
+	last2 = isl_seq_last_non_zero(c2->v->el + 1, c1->v->size - 1);
+	if (last1 != last2)
+		return last1 - last2;
+
+	return isl_seq_cmp(c1->v->el, c2->v->el, c1->v->size);
+}
+
+/* Compare two constraints based on their final (non-zero) coefficients.
+ * In particular, the constraint that involves later variables or
+ * that has a larger coefficient for a shared latest variable
+ * is considered "greater" than the other constraint.
+ *
+ * Return -1 if "c1" is "smaller" than "c2", 1 if "c1" is "greater"
+ * than "c2" and 0 if they are equal.
+ *
+ * If the constraints live in different local spaces, then we cannot
+ * really compare the constraints so we compare the local spaces instead.
+ */
+int isl_constraint_cmp_last_non_zero(__isl_keep isl_constraint *c1,
+	__isl_keep isl_constraint *c2)
+{
+	int cmp;
+	int last1, last2;
+
+	if (c1 == c2)
+		return 0;
+	if (!c1)
+		return -1;
+	if (!c2)
+		return 1;
+	cmp = isl_local_space_cmp(c1->ls, c2->ls);
+	if (cmp != 0)
+		return cmp;
+
+	last1 = isl_seq_last_non_zero(c1->v->el + 1, c1->v->size - 1);
+	last2 = isl_seq_last_non_zero(c2->v->el + 1, c1->v->size - 1);
+	if (last1 != last2)
+		return last1 - last2;
+	if (last1 == -1)
+		return 0;
+	return isl_int_abs_cmp(c1->v->el[1 + last1], c2->v->el[1 + last2]);
+}
diff --git a/final/lib/External/isl/isl_constraint_private.h b/final/lib/External/isl/isl_constraint_private.h
new file mode 100644
index 0000000..26a8630
--- /dev/null
+++ b/final/lib/External/isl/isl_constraint_private.h
@@ -0,0 +1,34 @@
+#ifndef ISL_CONSTRAINT_PRIVATE_H
+#define ISL_CONSTRAINT_PRIVATE_H
+
+#include <isl/constraint.h>
+#include <isl/local_space.h>
+#include <isl/vec.h>
+
+struct isl_constraint {
+	int ref;
+
+	int eq;
+	isl_local_space	*ls;
+	isl_vec		*v;
+};
+
+#undef EL
+#define EL isl_constraint
+
+#include <isl_list_templ.h>
+
+struct isl_constraint *isl_basic_set_constraint(struct isl_basic_set *bset,
+	isl_int **line);
+
+void isl_constraint_get_constant(__isl_keep isl_constraint *constraint,
+	isl_int *v);
+void isl_constraint_get_coefficient(__isl_keep isl_constraint *constraint,
+	enum isl_dim_type type, int pos, isl_int *v);
+__isl_give isl_constraint *isl_constraint_set_constant(
+	__isl_take isl_constraint *constraint, isl_int v);
+__isl_give isl_constraint *isl_constraint_set_coefficient(
+	__isl_take isl_constraint *constraint,
+	enum isl_dim_type type, int pos, isl_int v);
+
+#endif
diff --git a/final/lib/External/isl/isl_convex_hull.c b/final/lib/External/isl/isl_convex_hull.c
new file mode 100644
index 0000000..bedee1b
--- /dev/null
+++ b/final/lib/External/isl/isl_convex_hull.c
@@ -0,0 +1,3063 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2014      INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_lp_private.h>
+#include <isl/map.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl/set.h>
+#include <isl_seq.h>
+#include <isl_options_private.h>
+#include "isl_equalities.h"
+#include "isl_tab.h"
+#include <isl_sort.h>
+
+#include <bset_to_bmap.c>
+#include <bset_from_bmap.c>
+#include <set_to_map.c>
+
+static __isl_give isl_basic_set *uset_convex_hull_wrap_bounded(
+	__isl_take isl_set *set);
+
+/* Remove redundant
+ * constraints.  If the minimal value along the normal of a constraint
+ * is the same if the constraint is removed, then the constraint is redundant.
+ *
+ * Since some constraints may be mutually redundant, sort the constraints
+ * first such that constraints that involve existentially quantified
+ * variables are considered for removal before those that do not.
+ * The sorting is also needed for the use in map_simple_hull.
+ *
+ * Note that isl_tab_detect_implicit_equalities may also end up
+ * marking some constraints as redundant.  Make sure the constraints
+ * are preserved and undo those marking such that isl_tab_detect_redundant
+ * can consider the constraints in the sorted order.
+ *
+ * Alternatively, we could have intersected the basic map with the
+ * corresponding equality and then checked if the dimension was that
+ * of a facet.
+ */
+__isl_give isl_basic_map *isl_basic_map_remove_redundancies(
+	__isl_take isl_basic_map *bmap)
+{
+	struct isl_tab *tab;
+
+	if (!bmap)
+		return NULL;
+
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+		return bmap;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NO_REDUNDANT))
+		return bmap;
+	if (bmap->n_ineq <= 1)
+		return bmap;
+
+	bmap = isl_basic_map_sort_constraints(bmap);
+	tab = isl_tab_from_basic_map(bmap, 0);
+	if (!tab)
+		goto error;
+	tab->preserve = 1;
+	if (isl_tab_detect_implicit_equalities(tab) < 0)
+		goto error;
+	if (isl_tab_restore_redundant(tab) < 0)
+		goto error;
+	tab->preserve = 0;
+	if (isl_tab_detect_redundant(tab) < 0)
+		goto error;
+	bmap = isl_basic_map_update_from_tab(bmap, tab);
+	isl_tab_free(tab);
+	if (!bmap)
+		return NULL;
+	ISL_F_SET(bmap, ISL_BASIC_MAP_NO_IMPLICIT);
+	ISL_F_SET(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+	return bmap;
+error:
+	isl_tab_free(tab);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_remove_redundancies(
+	__isl_take isl_basic_set *bset)
+{
+	return bset_from_bmap(
+		isl_basic_map_remove_redundancies(bset_to_bmap(bset)));
+}
+
+/* Remove redundant constraints in each of the basic maps.
+ */
+__isl_give isl_map *isl_map_remove_redundancies(__isl_take isl_map *map)
+{
+	return isl_map_inline_foreach_basic_map(map,
+					    &isl_basic_map_remove_redundancies);
+}
+
+__isl_give isl_set *isl_set_remove_redundancies(__isl_take isl_set *set)
+{
+	return isl_map_remove_redundancies(set);
+}
+
+/* Check if the set set is bound in the direction of the affine
+ * constraint c and if so, set the constant term such that the
+ * resulting constraint is a bounding constraint for the set.
+ */
+static int uset_is_bound(__isl_keep isl_set *set, isl_int *c, unsigned len)
+{
+	int first;
+	int j;
+	isl_int opt;
+	isl_int opt_denom;
+
+	isl_int_init(opt);
+	isl_int_init(opt_denom);
+	first = 1;
+	for (j = 0; j < set->n; ++j) {
+		enum isl_lp_result res;
+
+		if (ISL_F_ISSET(set->p[j], ISL_BASIC_SET_EMPTY))
+			continue;
+
+		res = isl_basic_set_solve_lp(set->p[j],
+				0, c, set->ctx->one, &opt, &opt_denom, NULL);
+		if (res == isl_lp_unbounded)
+			break;
+		if (res == isl_lp_error)
+			goto error;
+		if (res == isl_lp_empty) {
+			set->p[j] = isl_basic_set_set_to_empty(set->p[j]);
+			if (!set->p[j])
+				goto error;
+			continue;
+		}
+		if (first || isl_int_is_neg(opt)) {
+			if (!isl_int_is_one(opt_denom))
+				isl_seq_scale(c, c, opt_denom, len);
+			isl_int_sub(c[0], c[0], opt);
+		}
+		first = 0;
+	}
+	isl_int_clear(opt);
+	isl_int_clear(opt_denom);
+	return j >= set->n;
+error:
+	isl_int_clear(opt);
+	isl_int_clear(opt_denom);
+	return -1;
+}
+
+static struct isl_basic_set *isl_basic_set_add_equality(
+	struct isl_basic_set *bset, isl_int *c)
+{
+	int i;
+	unsigned dim;
+
+	if (!bset)
+		return NULL;
+
+	if (ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY))
+		return bset;
+
+	isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
+	isl_assert(bset->ctx, bset->n_div == 0, goto error);
+	dim = isl_basic_set_n_dim(bset);
+	bset = isl_basic_set_cow(bset);
+	bset = isl_basic_set_extend(bset, 0, dim, 0, 1, 0);
+	i = isl_basic_set_alloc_equality(bset);
+	if (i < 0)
+		goto error;
+	isl_seq_cpy(bset->eq[i], c, 1 + dim);
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+static __isl_give isl_set *isl_set_add_basic_set_equality(
+	__isl_take isl_set *set, isl_int *c)
+{
+	int i;
+
+	set = isl_set_cow(set);
+	if (!set)
+		return NULL;
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_add_equality(set->p[i], c);
+		if (!set->p[i])
+			goto error;
+	}
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Given a union of basic sets, construct the constraints for wrapping
+ * a facet around one of its ridges.
+ * In particular, if each of n the d-dimensional basic sets i in "set"
+ * contains the origin, satisfies the constraints x_1 >= 0 and x_2 >= 0
+ * and is defined by the constraints
+ *				    [ 1 ]
+ *				A_i [ x ]  >= 0
+ *
+ * then the resulting set is of dimension n*(1+d) and has as constraints
+ *
+ *				    [ a_i ]
+ *				A_i [ x_i ] >= 0
+ *
+ *				      a_i   >= 0
+ *
+ *			\sum_i x_{i,1} = 1
+ */
+static __isl_give isl_basic_set *wrap_constraints(__isl_keep isl_set *set)
+{
+	struct isl_basic_set *lp;
+	unsigned n_eq;
+	unsigned n_ineq;
+	int i, j, k;
+	unsigned dim, lp_dim;
+
+	if (!set)
+		return NULL;
+
+	dim = 1 + isl_set_n_dim(set);
+	n_eq = 1;
+	n_ineq = set->n;
+	for (i = 0; i < set->n; ++i) {
+		n_eq += set->p[i]->n_eq;
+		n_ineq += set->p[i]->n_ineq;
+	}
+	lp = isl_basic_set_alloc(set->ctx, 0, dim * set->n, 0, n_eq, n_ineq);
+	lp = isl_basic_set_set_rational(lp);
+	if (!lp)
+		return NULL;
+	lp_dim = isl_basic_set_n_dim(lp);
+	k = isl_basic_set_alloc_equality(lp);
+	isl_int_set_si(lp->eq[k][0], -1);
+	for (i = 0; i < set->n; ++i) {
+		isl_int_set_si(lp->eq[k][1+dim*i], 0);
+		isl_int_set_si(lp->eq[k][1+dim*i+1], 1);
+		isl_seq_clr(lp->eq[k]+1+dim*i+2, dim-2);
+	}
+	for (i = 0; i < set->n; ++i) {
+		k = isl_basic_set_alloc_inequality(lp);
+		isl_seq_clr(lp->ineq[k], 1+lp_dim);
+		isl_int_set_si(lp->ineq[k][1+dim*i], 1);
+
+		for (j = 0; j < set->p[i]->n_eq; ++j) {
+			k = isl_basic_set_alloc_equality(lp);
+			isl_seq_clr(lp->eq[k], 1+dim*i);
+			isl_seq_cpy(lp->eq[k]+1+dim*i, set->p[i]->eq[j], dim);
+			isl_seq_clr(lp->eq[k]+1+dim*(i+1), dim*(set->n-i-1));
+		}
+
+		for (j = 0; j < set->p[i]->n_ineq; ++j) {
+			k = isl_basic_set_alloc_inequality(lp);
+			isl_seq_clr(lp->ineq[k], 1+dim*i);
+			isl_seq_cpy(lp->ineq[k]+1+dim*i, set->p[i]->ineq[j], dim);
+			isl_seq_clr(lp->ineq[k]+1+dim*(i+1), dim*(set->n-i-1));
+		}
+	}
+	return lp;
+}
+
+/* Given a facet "facet" of the convex hull of "set" and a facet "ridge"
+ * of that facet, compute the other facet of the convex hull that contains
+ * the ridge.
+ *
+ * We first transform the set such that the facet constraint becomes
+ *
+ *			x_1 >= 0
+ *
+ * I.e., the facet lies in
+ *
+ *			x_1 = 0
+ *
+ * and on that facet, the constraint that defines the ridge is
+ *
+ *			x_2 >= 0
+ *
+ * (This transformation is not strictly needed, all that is needed is
+ * that the ridge contains the origin.)
+ *
+ * Since the ridge contains the origin, the cone of the convex hull
+ * will be of the form
+ *
+ *			x_1 >= 0
+ *			x_2 >= a x_1
+ *
+ * with this second constraint defining the new facet.
+ * The constant a is obtained by settting x_1 in the cone of the
+ * convex hull to 1 and minimizing x_2.
+ * Now, each element in the cone of the convex hull is the sum
+ * of elements in the cones of the basic sets.
+ * If a_i is the dilation factor of basic set i, then the problem
+ * we need to solve is
+ *
+ *			min \sum_i x_{i,2}
+ *			st
+ *				\sum_i x_{i,1} = 1
+ *				    a_i   >= 0
+ *				  [ a_i ]
+ *				A [ x_i ] >= 0
+ *
+ * with
+ *				    [  1  ]
+ *				A_i [ x_i ] >= 0
+ *
+ * the constraints of each (transformed) basic set.
+ * If a = n/d, then the constraint defining the new facet (in the transformed
+ * space) is
+ *
+ *			-n x_1 + d x_2 >= 0
+ *
+ * In the original space, we need to take the same combination of the
+ * corresponding constraints "facet" and "ridge".
+ *
+ * If a = -infty = "-1/0", then we just return the original facet constraint.
+ * This means that the facet is unbounded, but has a bounded intersection
+ * with the union of sets.
+ */
+isl_int *isl_set_wrap_facet(__isl_keep isl_set *set,
+	isl_int *facet, isl_int *ridge)
+{
+	int i;
+	isl_ctx *ctx;
+	struct isl_mat *T = NULL;
+	struct isl_basic_set *lp = NULL;
+	struct isl_vec *obj;
+	enum isl_lp_result res;
+	isl_int num, den;
+	unsigned dim;
+
+	if (!set)
+		return NULL;
+	ctx = set->ctx;
+	set = isl_set_copy(set);
+	set = isl_set_set_rational(set);
+
+	dim = 1 + isl_set_n_dim(set);
+	T = isl_mat_alloc(ctx, 3, dim);
+	if (!T)
+		goto error;
+	isl_int_set_si(T->row[0][0], 1);
+	isl_seq_clr(T->row[0]+1, dim - 1);
+	isl_seq_cpy(T->row[1], facet, dim);
+	isl_seq_cpy(T->row[2], ridge, dim);
+	T = isl_mat_right_inverse(T);
+	set = isl_set_preimage(set, T);
+	T = NULL;
+	if (!set)
+		goto error;
+	lp = wrap_constraints(set);
+	obj = isl_vec_alloc(ctx, 1 + dim*set->n);
+	if (!obj)
+		goto error;
+	isl_int_set_si(obj->block.data[0], 0);
+	for (i = 0; i < set->n; ++i) {
+		isl_seq_clr(obj->block.data + 1 + dim*i, 2);
+		isl_int_set_si(obj->block.data[1 + dim*i+2], 1);
+		isl_seq_clr(obj->block.data + 1 + dim*i+3, dim-3);
+	}
+	isl_int_init(num);
+	isl_int_init(den);
+	res = isl_basic_set_solve_lp(lp, 0,
+			    obj->block.data, ctx->one, &num, &den, NULL);
+	if (res == isl_lp_ok) {
+		isl_int_neg(num, num);
+		isl_seq_combine(facet, num, facet, den, ridge, dim);
+		isl_seq_normalize(ctx, facet, dim);
+	}
+	isl_int_clear(num);
+	isl_int_clear(den);
+	isl_vec_free(obj);
+	isl_basic_set_free(lp);
+	isl_set_free(set);
+	if (res == isl_lp_error)
+		return NULL;
+	isl_assert(ctx, res == isl_lp_ok || res == isl_lp_unbounded, 
+		   return NULL);
+	return facet;
+error:
+	isl_basic_set_free(lp);
+	isl_mat_free(T);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Compute the constraint of a facet of "set".
+ *
+ * We first compute the intersection with a bounding constraint
+ * that is orthogonal to one of the coordinate axes.
+ * If the affine hull of this intersection has only one equality,
+ * we have found a facet.
+ * Otherwise, we wrap the current bounding constraint around
+ * one of the equalities of the face (one that is not equal to
+ * the current bounding constraint).
+ * This process continues until we have found a facet.
+ * The dimension of the intersection increases by at least
+ * one on each iteration, so termination is guaranteed.
+ */
+static __isl_give isl_mat *initial_facet_constraint(__isl_keep isl_set *set)
+{
+	struct isl_set *slice = NULL;
+	struct isl_basic_set *face = NULL;
+	int i;
+	unsigned dim = isl_set_n_dim(set);
+	int is_bound;
+	isl_mat *bounds = NULL;
+
+	isl_assert(set->ctx, set->n > 0, goto error);
+	bounds = isl_mat_alloc(set->ctx, 1, 1 + dim);
+	if (!bounds)
+		return NULL;
+
+	isl_seq_clr(bounds->row[0], dim);
+	isl_int_set_si(bounds->row[0][1 + dim - 1], 1);
+	is_bound = uset_is_bound(set, bounds->row[0], 1 + dim);
+	if (is_bound < 0)
+		goto error;
+	isl_assert(set->ctx, is_bound, goto error);
+	isl_seq_normalize(set->ctx, bounds->row[0], 1 + dim);
+	bounds->n_row = 1;
+
+	for (;;) {
+		slice = isl_set_copy(set);
+		slice = isl_set_add_basic_set_equality(slice, bounds->row[0]);
+		face = isl_set_affine_hull(slice);
+		if (!face)
+			goto error;
+		if (face->n_eq == 1) {
+			isl_basic_set_free(face);
+			break;
+		}
+		for (i = 0; i < face->n_eq; ++i)
+			if (!isl_seq_eq(bounds->row[0], face->eq[i], 1 + dim) &&
+			    !isl_seq_is_neg(bounds->row[0],
+						face->eq[i], 1 + dim))
+				break;
+		isl_assert(set->ctx, i < face->n_eq, goto error);
+		if (!isl_set_wrap_facet(set, bounds->row[0], face->eq[i]))
+			goto error;
+		isl_seq_normalize(set->ctx, bounds->row[0], bounds->n_col);
+		isl_basic_set_free(face);
+	}
+
+	return bounds;
+error:
+	isl_basic_set_free(face);
+	isl_mat_free(bounds);
+	return NULL;
+}
+
+/* Given the bounding constraint "c" of a facet of the convex hull of "set",
+ * compute a hyperplane description of the facet, i.e., compute the facets
+ * of the facet.
+ *
+ * We compute an affine transformation that transforms the constraint
+ *
+ *			  [ 1 ]
+ *			c [ x ] = 0
+ *
+ * to the constraint
+ *
+ *			   z_1  = 0
+ *
+ * by computing the right inverse U of a matrix that starts with the rows
+ *
+ *			[ 1 0 ]
+ *			[  c  ]
+ *
+ * Then
+ *			[ 1 ]     [ 1 ]
+ *			[ x ] = U [ z ]
+ * and
+ *			[ 1 ]     [ 1 ]
+ *			[ z ] = Q [ x ]
+ *
+ * with Q = U^{-1}
+ * Since z_1 is zero, we can drop this variable as well as the corresponding
+ * column of U to obtain
+ *
+ *			[ 1 ]      [ 1  ]
+ *			[ x ] = U' [ z' ]
+ * and
+ *			[ 1  ]      [ 1 ]
+ *			[ z' ] = Q' [ x ]
+ *
+ * with Q' equal to Q, but without the corresponding row.
+ * After computing the facets of the facet in the z' space,
+ * we convert them back to the x space through Q.
+ */
+static __isl_give isl_basic_set *compute_facet(__isl_keep isl_set *set,
+	isl_int *c)
+{
+	struct isl_mat *m, *U, *Q;
+	struct isl_basic_set *facet = NULL;
+	struct isl_ctx *ctx;
+	unsigned dim;
+
+	ctx = set->ctx;
+	set = isl_set_copy(set);
+	dim = isl_set_n_dim(set);
+	m = isl_mat_alloc(set->ctx, 2, 1 + dim);
+	if (!m)
+		goto error;
+	isl_int_set_si(m->row[0][0], 1);
+	isl_seq_clr(m->row[0]+1, dim);
+	isl_seq_cpy(m->row[1], c, 1+dim);
+	U = isl_mat_right_inverse(m);
+	Q = isl_mat_right_inverse(isl_mat_copy(U));
+	U = isl_mat_drop_cols(U, 1, 1);
+	Q = isl_mat_drop_rows(Q, 1, 1);
+	set = isl_set_preimage(set, U);
+	facet = uset_convex_hull_wrap_bounded(set);
+	facet = isl_basic_set_preimage(facet, Q);
+	if (facet && facet->n_eq != 0)
+		isl_die(ctx, isl_error_internal, "unexpected equality",
+			return isl_basic_set_free(facet));
+	return facet;
+error:
+	isl_basic_set_free(facet);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Given an initial facet constraint, compute the remaining facets.
+ * We do this by running through all facets found so far and computing
+ * the adjacent facets through wrapping, adding those facets that we
+ * hadn't already found before.
+ *
+ * For each facet we have found so far, we first compute its facets
+ * in the resulting convex hull.  That is, we compute the ridges
+ * of the resulting convex hull contained in the facet.
+ * We also compute the corresponding facet in the current approximation
+ * of the convex hull.  There is no need to wrap around the ridges
+ * in this facet since that would result in a facet that is already
+ * present in the current approximation.
+ *
+ * This function can still be significantly optimized by checking which of
+ * the facets of the basic sets are also facets of the convex hull and
+ * using all the facets so far to help in constructing the facets of the
+ * facets
+ * and/or
+ * using the technique in section "3.1 Ridge Generation" of
+ * "Extended Convex Hull" by Fukuda et al.
+ */
+static __isl_give isl_basic_set *extend(__isl_take isl_basic_set *hull,
+	__isl_keep isl_set *set)
+{
+	int i, j, f;
+	int k;
+	struct isl_basic_set *facet = NULL;
+	struct isl_basic_set *hull_facet = NULL;
+	unsigned dim;
+
+	if (!hull)
+		return NULL;
+
+	isl_assert(set->ctx, set->n > 0, goto error);
+
+	dim = isl_set_n_dim(set);
+
+	for (i = 0; i < hull->n_ineq; ++i) {
+		facet = compute_facet(set, hull->ineq[i]);
+		facet = isl_basic_set_add_equality(facet, hull->ineq[i]);
+		facet = isl_basic_set_gauss(facet, NULL);
+		facet = isl_basic_set_normalize_constraints(facet);
+		hull_facet = isl_basic_set_copy(hull);
+		hull_facet = isl_basic_set_add_equality(hull_facet, hull->ineq[i]);
+		hull_facet = isl_basic_set_gauss(hull_facet, NULL);
+		hull_facet = isl_basic_set_normalize_constraints(hull_facet);
+		if (!facet || !hull_facet)
+			goto error;
+		hull = isl_basic_set_cow(hull);
+		hull = isl_basic_set_extend_space(hull,
+			isl_space_copy(hull->dim), 0, 0, facet->n_ineq);
+		if (!hull)
+			goto error;
+		for (j = 0; j < facet->n_ineq; ++j) {
+			for (f = 0; f < hull_facet->n_ineq; ++f)
+				if (isl_seq_eq(facet->ineq[j],
+						hull_facet->ineq[f], 1 + dim))
+					break;
+			if (f < hull_facet->n_ineq)
+				continue;
+			k = isl_basic_set_alloc_inequality(hull);
+			if (k < 0)
+				goto error;
+			isl_seq_cpy(hull->ineq[k], hull->ineq[i], 1+dim);
+			if (!isl_set_wrap_facet(set, hull->ineq[k], facet->ineq[j]))
+				goto error;
+		}
+		isl_basic_set_free(hull_facet);
+		isl_basic_set_free(facet);
+	}
+	hull = isl_basic_set_simplify(hull);
+	hull = isl_basic_set_finalize(hull);
+	return hull;
+error:
+	isl_basic_set_free(hull_facet);
+	isl_basic_set_free(facet);
+	isl_basic_set_free(hull);
+	return NULL;
+}
+
+/* Special case for computing the convex hull of a one dimensional set.
+ * We simply collect the lower and upper bounds of each basic set
+ * and the biggest of those.
+ */
+static __isl_give isl_basic_set *convex_hull_1d(__isl_take isl_set *set)
+{
+	struct isl_mat *c = NULL;
+	isl_int *lower = NULL;
+	isl_int *upper = NULL;
+	int i, j, k;
+	isl_int a, b;
+	struct isl_basic_set *hull;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_simplify(set->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+	set = isl_set_remove_empty_parts(set);
+	if (!set)
+		goto error;
+	isl_assert(set->ctx, set->n > 0, goto error);
+	c = isl_mat_alloc(set->ctx, 2, 2);
+	if (!c)
+		goto error;
+
+	if (set->p[0]->n_eq > 0) {
+		isl_assert(set->ctx, set->p[0]->n_eq == 1, goto error);
+		lower = c->row[0];
+		upper = c->row[1];
+		if (isl_int_is_pos(set->p[0]->eq[0][1])) {
+			isl_seq_cpy(lower, set->p[0]->eq[0], 2);
+			isl_seq_neg(upper, set->p[0]->eq[0], 2);
+		} else {
+			isl_seq_neg(lower, set->p[0]->eq[0], 2);
+			isl_seq_cpy(upper, set->p[0]->eq[0], 2);
+		}
+	} else {
+		for (j = 0; j < set->p[0]->n_ineq; ++j) {
+			if (isl_int_is_pos(set->p[0]->ineq[j][1])) {
+				lower = c->row[0];
+				isl_seq_cpy(lower, set->p[0]->ineq[j], 2);
+			} else {
+				upper = c->row[1];
+				isl_seq_cpy(upper, set->p[0]->ineq[j], 2);
+			}
+		}
+	}
+
+	isl_int_init(a);
+	isl_int_init(b);
+	for (i = 0; i < set->n; ++i) {
+		struct isl_basic_set *bset = set->p[i];
+		int has_lower = 0;
+		int has_upper = 0;
+
+		for (j = 0; j < bset->n_eq; ++j) {
+			has_lower = 1;
+			has_upper = 1;
+			if (lower) {
+				isl_int_mul(a, lower[0], bset->eq[j][1]);
+				isl_int_mul(b, lower[1], bset->eq[j][0]);
+				if (isl_int_lt(a, b) && isl_int_is_pos(bset->eq[j][1]))
+					isl_seq_cpy(lower, bset->eq[j], 2);
+				if (isl_int_gt(a, b) && isl_int_is_neg(bset->eq[j][1]))
+					isl_seq_neg(lower, bset->eq[j], 2);
+			}
+			if (upper) {
+				isl_int_mul(a, upper[0], bset->eq[j][1]);
+				isl_int_mul(b, upper[1], bset->eq[j][0]);
+				if (isl_int_lt(a, b) && isl_int_is_pos(bset->eq[j][1]))
+					isl_seq_neg(upper, bset->eq[j], 2);
+				if (isl_int_gt(a, b) && isl_int_is_neg(bset->eq[j][1]))
+					isl_seq_cpy(upper, bset->eq[j], 2);
+			}
+		}
+		for (j = 0; j < bset->n_ineq; ++j) {
+			if (isl_int_is_pos(bset->ineq[j][1]))
+				has_lower = 1;
+			if (isl_int_is_neg(bset->ineq[j][1]))
+				has_upper = 1;
+			if (lower && isl_int_is_pos(bset->ineq[j][1])) {
+				isl_int_mul(a, lower[0], bset->ineq[j][1]);
+				isl_int_mul(b, lower[1], bset->ineq[j][0]);
+				if (isl_int_lt(a, b))
+					isl_seq_cpy(lower, bset->ineq[j], 2);
+			}
+			if (upper && isl_int_is_neg(bset->ineq[j][1])) {
+				isl_int_mul(a, upper[0], bset->ineq[j][1]);
+				isl_int_mul(b, upper[1], bset->ineq[j][0]);
+				if (isl_int_gt(a, b))
+					isl_seq_cpy(upper, bset->ineq[j], 2);
+			}
+		}
+		if (!has_lower)
+			lower = NULL;
+		if (!has_upper)
+			upper = NULL;
+	}
+	isl_int_clear(a);
+	isl_int_clear(b);
+
+	hull = isl_basic_set_alloc(set->ctx, 0, 1, 0, 0, 2);
+	hull = isl_basic_set_set_rational(hull);
+	if (!hull)
+		goto error;
+	if (lower) {
+		k = isl_basic_set_alloc_inequality(hull);
+		isl_seq_cpy(hull->ineq[k], lower, 2);
+	}
+	if (upper) {
+		k = isl_basic_set_alloc_inequality(hull);
+		isl_seq_cpy(hull->ineq[k], upper, 2);
+	}
+	hull = isl_basic_set_finalize(hull);
+	isl_set_free(set);
+	isl_mat_free(c);
+	return hull;
+error:
+	isl_set_free(set);
+	isl_mat_free(c);
+	return NULL;
+}
+
+static __isl_give isl_basic_set *convex_hull_0d(__isl_take isl_set *set)
+{
+	struct isl_basic_set *convex_hull;
+
+	if (!set)
+		return NULL;
+
+	if (isl_set_is_empty(set))
+		convex_hull = isl_basic_set_empty(isl_space_copy(set->dim));
+	else
+		convex_hull = isl_basic_set_universe(isl_space_copy(set->dim));
+	isl_set_free(set);
+	return convex_hull;
+}
+
+/* Compute the convex hull of a pair of basic sets without any parameters or
+ * integer divisions using Fourier-Motzkin elimination.
+ * The convex hull is the set of all points that can be written as
+ * the sum of points from both basic sets (in homogeneous coordinates).
+ * We set up the constraints in a space with dimensions for each of
+ * the three sets and then project out the dimensions corresponding
+ * to the two original basic sets, retaining only those corresponding
+ * to the convex hull.
+ */
+static __isl_give isl_basic_set *convex_hull_pair_elim(
+	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+	int i, j, k;
+	struct isl_basic_set *bset[2];
+	struct isl_basic_set *hull = NULL;
+	unsigned dim;
+
+	if (!bset1 || !bset2)
+		goto error;
+
+	dim = isl_basic_set_n_dim(bset1);
+	hull = isl_basic_set_alloc(bset1->ctx, 0, 2 + 3 * dim, 0,
+				1 + dim + bset1->n_eq + bset2->n_eq,
+				2 + bset1->n_ineq + bset2->n_ineq);
+	bset[0] = bset1;
+	bset[1] = bset2;
+	for (i = 0; i < 2; ++i) {
+		for (j = 0; j < bset[i]->n_eq; ++j) {
+			k = isl_basic_set_alloc_equality(hull);
+			if (k < 0)
+				goto error;
+			isl_seq_clr(hull->eq[k], (i+1) * (1+dim));
+			isl_seq_clr(hull->eq[k]+(i+2)*(1+dim), (1-i)*(1+dim));
+			isl_seq_cpy(hull->eq[k]+(i+1)*(1+dim), bset[i]->eq[j],
+					1+dim);
+		}
+		for (j = 0; j < bset[i]->n_ineq; ++j) {
+			k = isl_basic_set_alloc_inequality(hull);
+			if (k < 0)
+				goto error;
+			isl_seq_clr(hull->ineq[k], (i+1) * (1+dim));
+			isl_seq_clr(hull->ineq[k]+(i+2)*(1+dim), (1-i)*(1+dim));
+			isl_seq_cpy(hull->ineq[k]+(i+1)*(1+dim),
+					bset[i]->ineq[j], 1+dim);
+		}
+		k = isl_basic_set_alloc_inequality(hull);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(hull->ineq[k], 1+2+3*dim);
+		isl_int_set_si(hull->ineq[k][(i+1)*(1+dim)], 1);
+	}
+	for (j = 0; j < 1+dim; ++j) {
+		k = isl_basic_set_alloc_equality(hull);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(hull->eq[k], 1+2+3*dim);
+		isl_int_set_si(hull->eq[k][j], -1);
+		isl_int_set_si(hull->eq[k][1+dim+j], 1);
+		isl_int_set_si(hull->eq[k][2*(1+dim)+j], 1);
+	}
+	hull = isl_basic_set_set_rational(hull);
+	hull = isl_basic_set_remove_dims(hull, isl_dim_set, dim, 2*(1+dim));
+	hull = isl_basic_set_remove_redundancies(hull);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return hull;
+error:
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	isl_basic_set_free(hull);
+	return NULL;
+}
+
+/* Is the set bounded for each value of the parameters?
+ */
+isl_bool isl_basic_set_is_bounded(__isl_keep isl_basic_set *bset)
+{
+	struct isl_tab *tab;
+	isl_bool bounded;
+
+	if (!bset)
+		return isl_bool_error;
+	if (isl_basic_set_plain_is_empty(bset))
+		return isl_bool_true;
+
+	tab = isl_tab_from_recession_cone(bset, 1);
+	bounded = isl_tab_cone_is_bounded(tab);
+	isl_tab_free(tab);
+	return bounded;
+}
+
+/* Is the image bounded for each value of the parameters and
+ * the domain variables?
+ */
+isl_bool isl_basic_map_image_is_bounded(__isl_keep isl_basic_map *bmap)
+{
+	unsigned nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	unsigned n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	isl_bool bounded;
+
+	bmap = isl_basic_map_copy(bmap);
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_move_dims(bmap, isl_dim_param, nparam,
+					isl_dim_in, 0, n_in);
+	bounded = isl_basic_set_is_bounded(bset_from_bmap(bmap));
+	isl_basic_map_free(bmap);
+
+	return bounded;
+}
+
+/* Is the set bounded for each value of the parameters?
+ */
+isl_bool isl_set_is_bounded(__isl_keep isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return isl_bool_error;
+
+	for (i = 0; i < set->n; ++i) {
+		isl_bool bounded = isl_basic_set_is_bounded(set->p[i]);
+		if (!bounded || bounded < 0)
+			return bounded;
+	}
+	return isl_bool_true;
+}
+
+/* Compute the lineality space of the convex hull of bset1 and bset2.
+ *
+ * We first compute the intersection of the recession cone of bset1
+ * with the negative of the recession cone of bset2 and then compute
+ * the linear hull of the resulting cone.
+ */
+static __isl_give isl_basic_set *induced_lineality_space(
+	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+	int i, k;
+	struct isl_basic_set *lin = NULL;
+	unsigned dim;
+
+	if (!bset1 || !bset2)
+		goto error;
+
+	dim = isl_basic_set_total_dim(bset1);
+	lin = isl_basic_set_alloc_space(isl_basic_set_get_space(bset1), 0,
+					bset1->n_eq + bset2->n_eq,
+					bset1->n_ineq + bset2->n_ineq);
+	lin = isl_basic_set_set_rational(lin);
+	if (!lin)
+		goto error;
+	for (i = 0; i < bset1->n_eq; ++i) {
+		k = isl_basic_set_alloc_equality(lin);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(lin->eq[k][0], 0);
+		isl_seq_cpy(lin->eq[k] + 1, bset1->eq[i] + 1, dim);
+	}
+	for (i = 0; i < bset1->n_ineq; ++i) {
+		k = isl_basic_set_alloc_inequality(lin);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(lin->ineq[k][0], 0);
+		isl_seq_cpy(lin->ineq[k] + 1, bset1->ineq[i] + 1, dim);
+	}
+	for (i = 0; i < bset2->n_eq; ++i) {
+		k = isl_basic_set_alloc_equality(lin);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(lin->eq[k][0], 0);
+		isl_seq_neg(lin->eq[k] + 1, bset2->eq[i] + 1, dim);
+	}
+	for (i = 0; i < bset2->n_ineq; ++i) {
+		k = isl_basic_set_alloc_inequality(lin);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(lin->ineq[k][0], 0);
+		isl_seq_neg(lin->ineq[k] + 1, bset2->ineq[i] + 1, dim);
+	}
+
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return isl_basic_set_affine_hull(lin);
+error:
+	isl_basic_set_free(lin);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return NULL;
+}
+
+static __isl_give isl_basic_set *uset_convex_hull(__isl_take isl_set *set);
+
+/* Given a set and a linear space "lin" of dimension n > 0,
+ * project the linear space from the set, compute the convex hull
+ * and then map the set back to the original space.
+ *
+ * Let
+ *
+ *	M x = 0
+ *
+ * describe the linear space.  We first compute the Hermite normal
+ * form H = M U of M = H Q, to obtain
+ *
+ *	H Q x = 0
+ *
+ * The last n rows of H will be zero, so the last n variables of x' = Q x
+ * are the one we want to project out.  We do this by transforming each
+ * basic set A x >= b to A U x' >= b and then removing the last n dimensions.
+ * After computing the convex hull in x'_1, i.e., A' x'_1 >= b',
+ * we transform the hull back to the original space as A' Q_1 x >= b',
+ * with Q_1 all but the last n rows of Q.
+ */
+static __isl_give isl_basic_set *modulo_lineality(__isl_take isl_set *set,
+	__isl_take isl_basic_set *lin)
+{
+	unsigned total = isl_basic_set_total_dim(lin);
+	unsigned lin_dim;
+	struct isl_basic_set *hull;
+	struct isl_mat *M, *U, *Q;
+
+	if (!set || !lin)
+		goto error;
+	lin_dim = total - lin->n_eq;
+	M = isl_mat_sub_alloc6(set->ctx, lin->eq, 0, lin->n_eq, 1, total);
+	M = isl_mat_left_hermite(M, 0, &U, &Q);
+	if (!M)
+		goto error;
+	isl_mat_free(M);
+	isl_basic_set_free(lin);
+
+	Q = isl_mat_drop_rows(Q, Q->n_row - lin_dim, lin_dim);
+
+	U = isl_mat_lin_to_aff(U);
+	Q = isl_mat_lin_to_aff(Q);
+
+	set = isl_set_preimage(set, U);
+	set = isl_set_remove_dims(set, isl_dim_set, total - lin_dim, lin_dim);
+	hull = uset_convex_hull(set);
+	hull = isl_basic_set_preimage(hull, Q);
+
+	return hull;
+error:
+	isl_basic_set_free(lin);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Given two polyhedra with as constraints h_{ij} x >= 0 in homegeneous space,
+ * set up an LP for solving
+ *
+ *	\sum_j \alpha_{1j} h_{1j} = \sum_j \alpha_{2j} h_{2j}
+ *
+ * \alpha{i0} corresponds to the (implicit) positivity constraint 1 >= 0
+ * The next \alpha{ij} correspond to the equalities and come in pairs.
+ * The final \alpha{ij} correspond to the inequalities.
+ */
+static __isl_give isl_basic_set *valid_direction_lp(
+	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+	isl_space *dim;
+	struct isl_basic_set *lp;
+	unsigned d;
+	int n;
+	int i, j, k;
+
+	if (!bset1 || !bset2)
+		goto error;
+	d = 1 + isl_basic_set_total_dim(bset1);
+	n = 2 +
+	    2 * bset1->n_eq + bset1->n_ineq + 2 * bset2->n_eq + bset2->n_ineq;
+	dim = isl_space_set_alloc(bset1->ctx, 0, n);
+	lp = isl_basic_set_alloc_space(dim, 0, d, n);
+	if (!lp)
+		goto error;
+	for (i = 0; i < n; ++i) {
+		k = isl_basic_set_alloc_inequality(lp);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(lp->ineq[k] + 1, n);
+		isl_int_set_si(lp->ineq[k][0], -1);
+		isl_int_set_si(lp->ineq[k][1 + i], 1);
+	}
+	for (i = 0; i < d; ++i) {
+		k = isl_basic_set_alloc_equality(lp);
+		if (k < 0)
+			goto error;
+		n = 0;
+		isl_int_set_si(lp->eq[k][n], 0); n++;
+		/* positivity constraint 1 >= 0 */
+		isl_int_set_si(lp->eq[k][n], i == 0); n++;
+		for (j = 0; j < bset1->n_eq; ++j) {
+			isl_int_set(lp->eq[k][n], bset1->eq[j][i]); n++;
+			isl_int_neg(lp->eq[k][n], bset1->eq[j][i]); n++;
+		}
+		for (j = 0; j < bset1->n_ineq; ++j) {
+			isl_int_set(lp->eq[k][n], bset1->ineq[j][i]); n++;
+		}
+		/* positivity constraint 1 >= 0 */
+		isl_int_set_si(lp->eq[k][n], -(i == 0)); n++;
+		for (j = 0; j < bset2->n_eq; ++j) {
+			isl_int_neg(lp->eq[k][n], bset2->eq[j][i]); n++;
+			isl_int_set(lp->eq[k][n], bset2->eq[j][i]); n++;
+		}
+		for (j = 0; j < bset2->n_ineq; ++j) {
+			isl_int_neg(lp->eq[k][n], bset2->ineq[j][i]); n++;
+		}
+	}
+	lp = isl_basic_set_gauss(lp, NULL);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return lp;
+error:
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return NULL;
+}
+
+/* Compute a vector s in the homogeneous space such that <s, r> > 0
+ * for all rays in the homogeneous space of the two cones that correspond
+ * to the input polyhedra bset1 and bset2.
+ *
+ * We compute s as a vector that satisfies
+ *
+ *	s = \sum_j \alpha_{ij} h_{ij}	for i = 1,2			(*)
+ *
+ * with h_{ij} the normals of the facets of polyhedron i
+ * (including the "positivity constraint" 1 >= 0) and \alpha_{ij}
+ * strictly positive numbers.  For simplicity we impose \alpha_{ij} >= 1.
+ * We first set up an LP with as variables the \alpha{ij}.
+ * In this formulation, for each polyhedron i,
+ * the first constraint is the positivity constraint, followed by pairs
+ * of variables for the equalities, followed by variables for the inequalities.
+ * We then simply pick a feasible solution and compute s using (*).
+ *
+ * Note that we simply pick any valid direction and make no attempt
+ * to pick a "good" or even the "best" valid direction.
+ */
+static __isl_give isl_vec *valid_direction(
+	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+	struct isl_basic_set *lp;
+	struct isl_tab *tab;
+	struct isl_vec *sample = NULL;
+	struct isl_vec *dir;
+	unsigned d;
+	int i;
+	int n;
+
+	if (!bset1 || !bset2)
+		goto error;
+	lp = valid_direction_lp(isl_basic_set_copy(bset1),
+				isl_basic_set_copy(bset2));
+	tab = isl_tab_from_basic_set(lp, 0);
+	sample = isl_tab_get_sample_value(tab);
+	isl_tab_free(tab);
+	isl_basic_set_free(lp);
+	if (!sample)
+		goto error;
+	d = isl_basic_set_total_dim(bset1);
+	dir = isl_vec_alloc(bset1->ctx, 1 + d);
+	if (!dir)
+		goto error;
+	isl_seq_clr(dir->block.data + 1, dir->size - 1);
+	n = 1;
+	/* positivity constraint 1 >= 0 */
+	isl_int_set(dir->block.data[0], sample->block.data[n]); n++;
+	for (i = 0; i < bset1->n_eq; ++i) {
+		isl_int_sub(sample->block.data[n],
+			    sample->block.data[n], sample->block.data[n+1]);
+		isl_seq_combine(dir->block.data,
+				bset1->ctx->one, dir->block.data,
+				sample->block.data[n], bset1->eq[i], 1 + d);
+
+		n += 2;
+	}
+	for (i = 0; i < bset1->n_ineq; ++i)
+		isl_seq_combine(dir->block.data,
+				bset1->ctx->one, dir->block.data,
+				sample->block.data[n++], bset1->ineq[i], 1 + d);
+	isl_vec_free(sample);
+	isl_seq_normalize(bset1->ctx, dir->el, dir->size);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return dir;
+error:
+	isl_vec_free(sample);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return NULL;
+}
+
+/* Given a polyhedron b_i + A_i x >= 0 and a map T = S^{-1},
+ * compute b_i' + A_i' x' >= 0, with
+ *
+ *	[ b_i A_i ]        [ y' ]		              [ y' ]
+ *	[  1   0  ] S^{-1} [ x' ] >= 0	or	[ b_i' A_i' ] [ x' ] >= 0
+ *
+ * In particular, add the "positivity constraint" and then perform
+ * the mapping.
+ */
+static __isl_give isl_basic_set *homogeneous_map(__isl_take isl_basic_set *bset,
+	__isl_take isl_mat *T)
+{
+	int k;
+
+	if (!bset)
+		goto error;
+	bset = isl_basic_set_extend_constraints(bset, 0, 1);
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(bset->ineq[k] + 1, isl_basic_set_total_dim(bset));
+	isl_int_set_si(bset->ineq[k][0], 1);
+	bset = isl_basic_set_preimage(bset, T);
+	return bset;
+error:
+	isl_mat_free(T);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Compute the convex hull of a pair of basic sets without any parameters or
+ * integer divisions, where the convex hull is known to be pointed,
+ * but the basic sets may be unbounded.
+ *
+ * We turn this problem into the computation of a convex hull of a pair
+ * _bounded_ polyhedra by "changing the direction of the homogeneous
+ * dimension".  This idea is due to Matthias Koeppe.
+ *
+ * Consider the cones in homogeneous space that correspond to the
+ * input polyhedra.  The rays of these cones are also rays of the
+ * polyhedra if the coordinate that corresponds to the homogeneous
+ * dimension is zero.  That is, if the inner product of the rays
+ * with the homogeneous direction is zero.
+ * The cones in the homogeneous space can also be considered to
+ * correspond to other pairs of polyhedra by chosing a different
+ * homogeneous direction.  To ensure that both of these polyhedra
+ * are bounded, we need to make sure that all rays of the cones
+ * correspond to vertices and not to rays.
+ * Let s be a direction such that <s, r> > 0 for all rays r of both cones.
+ * Then using s as a homogeneous direction, we obtain a pair of polytopes.
+ * The vector s is computed in valid_direction.
+ *
+ * Note that we need to consider _all_ rays of the cones and not just
+ * the rays that correspond to rays in the polyhedra.  If we were to
+ * only consider those rays and turn them into vertices, then we
+ * may inadvertently turn some vertices into rays.
+ *
+ * The standard homogeneous direction is the unit vector in the 0th coordinate.
+ * We therefore transform the two polyhedra such that the selected
+ * direction is mapped onto this standard direction and then proceed
+ * with the normal computation.
+ * Let S be a non-singular square matrix with s as its first row,
+ * then we want to map the polyhedra to the space
+ *
+ *	[ y' ]     [ y ]		[ y ]          [ y' ]
+ *	[ x' ] = S [ x ]	i.e.,	[ x ] = S^{-1} [ x' ]
+ *
+ * We take S to be the unimodular completion of s to limit the growth
+ * of the coefficients in the following computations.
+ *
+ * Let b_i + A_i x >= 0 be the constraints of polyhedron i.
+ * We first move to the homogeneous dimension
+ *
+ *	b_i y + A_i x >= 0		[ b_i A_i ] [ y ]    [ 0 ]
+ *	    y         >= 0	or	[  1   0  ] [ x ] >= [ 0 ]
+ *
+ * Then we change directoin
+ *
+ *	[ b_i A_i ]        [ y' ]		              [ y' ]
+ *	[  1   0  ] S^{-1} [ x' ] >= 0	or	[ b_i' A_i' ] [ x' ] >= 0
+ *
+ * Then we compute the convex hull of the polytopes b_i' + A_i' x' >= 0
+ * resulting in b' + A' x' >= 0, which we then convert back
+ *
+ *	            [ y ]		        [ y ]
+ *	[ b' A' ] S [ x ] >= 0	or	[ b A ] [ x ] >= 0
+ *
+ * The polyhedron b + A x >= 0 is then the convex hull of the input polyhedra.
+ */
+static __isl_give isl_basic_set *convex_hull_pair_pointed(
+	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+	struct isl_ctx *ctx = NULL;
+	struct isl_vec *dir = NULL;
+	struct isl_mat *T = NULL;
+	struct isl_mat *T2 = NULL;
+	struct isl_basic_set *hull;
+	struct isl_set *set;
+
+	if (!bset1 || !bset2)
+		goto error;
+	ctx = isl_basic_set_get_ctx(bset1);
+	dir = valid_direction(isl_basic_set_copy(bset1),
+				isl_basic_set_copy(bset2));
+	if (!dir)
+		goto error;
+	T = isl_mat_alloc(ctx, dir->size, dir->size);
+	if (!T)
+		goto error;
+	isl_seq_cpy(T->row[0], dir->block.data, dir->size);
+	T = isl_mat_unimodular_complete(T, 1);
+	T2 = isl_mat_right_inverse(isl_mat_copy(T));
+
+	bset1 = homogeneous_map(bset1, isl_mat_copy(T2));
+	bset2 = homogeneous_map(bset2, T2);
+	set = isl_set_alloc_space(isl_basic_set_get_space(bset1), 2, 0);
+	set = isl_set_add_basic_set(set, bset1);
+	set = isl_set_add_basic_set(set, bset2);
+	hull = uset_convex_hull(set);
+	hull = isl_basic_set_preimage(hull, T);
+	 
+	isl_vec_free(dir);
+
+	return hull;
+error:
+	isl_vec_free(dir);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return NULL;
+}
+
+static __isl_give isl_basic_set *uset_convex_hull_wrap(__isl_take isl_set *set);
+static __isl_give isl_basic_set *modulo_affine_hull(
+	__isl_take isl_set *set, __isl_take isl_basic_set *affine_hull);
+
+/* Compute the convex hull of a pair of basic sets without any parameters or
+ * integer divisions.
+ *
+ * This function is called from uset_convex_hull_unbounded, which
+ * means that the complete convex hull is unbounded.  Some pairs
+ * of basic sets may still be bounded, though.
+ * They may even lie inside a lower dimensional space, in which
+ * case they need to be handled inside their affine hull since
+ * the main algorithm assumes that the result is full-dimensional.
+ *
+ * If the convex hull of the two basic sets would have a non-trivial
+ * lineality space, we first project out this lineality space.
+ */
+static __isl_give isl_basic_set *convex_hull_pair(
+	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+	isl_basic_set *lin, *aff;
+	int bounded1, bounded2;
+
+	if (bset1->ctx->opt->convex == ISL_CONVEX_HULL_FM)
+		return convex_hull_pair_elim(bset1, bset2);
+
+	aff = isl_set_affine_hull(isl_basic_set_union(isl_basic_set_copy(bset1),
+						    isl_basic_set_copy(bset2)));
+	if (!aff)
+		goto error;
+	if (aff->n_eq != 0) 
+		return modulo_affine_hull(isl_basic_set_union(bset1, bset2), aff);
+	isl_basic_set_free(aff);
+
+	bounded1 = isl_basic_set_is_bounded(bset1);
+	bounded2 = isl_basic_set_is_bounded(bset2);
+
+	if (bounded1 < 0 || bounded2 < 0)
+		goto error;
+
+	if (bounded1 && bounded2)
+		return uset_convex_hull_wrap(isl_basic_set_union(bset1, bset2));
+
+	if (bounded1 || bounded2)
+		return convex_hull_pair_pointed(bset1, bset2);
+
+	lin = induced_lineality_space(isl_basic_set_copy(bset1),
+				      isl_basic_set_copy(bset2));
+	if (!lin)
+		goto error;
+	if (isl_basic_set_plain_is_universe(lin)) {
+		isl_basic_set_free(bset1);
+		isl_basic_set_free(bset2);
+		return lin;
+	}
+	if (lin->n_eq < isl_basic_set_total_dim(lin)) {
+		struct isl_set *set;
+		set = isl_set_alloc_space(isl_basic_set_get_space(bset1), 2, 0);
+		set = isl_set_add_basic_set(set, bset1);
+		set = isl_set_add_basic_set(set, bset2);
+		return modulo_lineality(set, lin);
+	}
+	isl_basic_set_free(lin);
+
+	return convex_hull_pair_pointed(bset1, bset2);
+error:
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	return NULL;
+}
+
+/* Compute the lineality space of a basic set.
+ * We basically just drop the constants and turn every inequality
+ * into an equality.
+ * Any explicit representations of local variables are removed
+ * because they may no longer be valid representations
+ * in the lineality space.
+ */
+__isl_give isl_basic_set *isl_basic_set_lineality_space(
+	__isl_take isl_basic_set *bset)
+{
+	int i, k;
+	struct isl_basic_set *lin = NULL;
+	unsigned n_div, dim;
+
+	if (!bset)
+		goto error;
+	n_div = isl_basic_set_dim(bset, isl_dim_div);
+	dim = isl_basic_set_total_dim(bset);
+
+	lin = isl_basic_set_alloc_space(isl_basic_set_get_space(bset),
+					n_div, dim, 0);
+	for (i = 0; i < n_div; ++i)
+		if (isl_basic_set_alloc_div(lin) < 0)
+			goto error;
+	if (!lin)
+		goto error;
+	for (i = 0; i < bset->n_eq; ++i) {
+		k = isl_basic_set_alloc_equality(lin);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(lin->eq[k][0], 0);
+		isl_seq_cpy(lin->eq[k] + 1, bset->eq[i] + 1, dim);
+	}
+	lin = isl_basic_set_gauss(lin, NULL);
+	if (!lin)
+		goto error;
+	for (i = 0; i < bset->n_ineq && lin->n_eq < dim; ++i) {
+		k = isl_basic_set_alloc_equality(lin);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(lin->eq[k][0], 0);
+		isl_seq_cpy(lin->eq[k] + 1, bset->ineq[i] + 1, dim);
+		lin = isl_basic_set_gauss(lin, NULL);
+		if (!lin)
+			goto error;
+	}
+	isl_basic_set_free(bset);
+	return lin;
+error:
+	isl_basic_set_free(lin);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Compute the (linear) hull of the lineality spaces of the basic sets in the
+ * set "set".
+ */
+__isl_give isl_basic_set *isl_set_combined_lineality_space(
+	__isl_take isl_set *set)
+{
+	int i;
+	struct isl_set *lin = NULL;
+
+	if (!set)
+		return NULL;
+	if (set->n == 0) {
+		isl_space *space = isl_set_get_space(set);
+		isl_set_free(set);
+		return isl_basic_set_empty(space);
+	}
+
+	lin = isl_set_alloc_space(isl_set_get_space(set), set->n, 0);
+	for (i = 0; i < set->n; ++i)
+		lin = isl_set_add_basic_set(lin,
+		    isl_basic_set_lineality_space(isl_basic_set_copy(set->p[i])));
+	isl_set_free(set);
+	return isl_set_affine_hull(lin);
+}
+
+/* Compute the convex hull of a set without any parameters or
+ * integer divisions.
+ * In each step, we combined two basic sets until only one
+ * basic set is left.
+ * The input basic sets are assumed not to have a non-trivial
+ * lineality space.  If any of the intermediate results has
+ * a non-trivial lineality space, it is projected out.
+ */
+static __isl_give isl_basic_set *uset_convex_hull_unbounded(
+	__isl_take isl_set *set)
+{
+	isl_basic_set_list *list;
+
+	list = isl_set_get_basic_set_list(set);
+	isl_set_free(set);
+
+	while (list) {
+		int n;
+		struct isl_basic_set *t;
+		isl_basic_set *bset1, *bset2;
+
+		n = isl_basic_set_list_n_basic_set(list);
+		if (n < 2)
+			isl_die(isl_basic_set_list_get_ctx(list),
+				isl_error_internal,
+				"expecting at least two elements", goto error);
+		bset1 = isl_basic_set_list_get_basic_set(list, n - 1);
+		bset2 = isl_basic_set_list_get_basic_set(list, n - 2);
+		bset1 = convex_hull_pair(bset1, bset2);
+		if (n == 2) {
+			isl_basic_set_list_free(list);
+			return bset1;
+		}
+		bset1 = isl_basic_set_underlying_set(bset1);
+		list = isl_basic_set_list_drop(list, n - 2, 2);
+		list = isl_basic_set_list_add(list, bset1);
+
+		t = isl_basic_set_list_get_basic_set(list, n - 2);
+		t = isl_basic_set_lineality_space(t);
+		if (!t)
+			goto error;
+		if (isl_basic_set_plain_is_universe(t)) {
+			isl_basic_set_list_free(list);
+			return t;
+		}
+		if (t->n_eq < isl_basic_set_total_dim(t)) {
+			set = isl_basic_set_list_union(list);
+			return modulo_lineality(set, t);
+		}
+		isl_basic_set_free(t);
+	}
+
+	return NULL;
+error:
+	isl_basic_set_list_free(list);
+	return NULL;
+}
+
+/* Compute an initial hull for wrapping containing a single initial
+ * facet.
+ * This function assumes that the given set is bounded.
+ */
+static __isl_give isl_basic_set *initial_hull(__isl_take isl_basic_set *hull,
+	__isl_keep isl_set *set)
+{
+	struct isl_mat *bounds = NULL;
+	unsigned dim;
+	int k;
+
+	if (!hull)
+		goto error;
+	bounds = initial_facet_constraint(set);
+	if (!bounds)
+		goto error;
+	k = isl_basic_set_alloc_inequality(hull);
+	if (k < 0)
+		goto error;
+	dim = isl_set_n_dim(set);
+	isl_assert(set->ctx, 1 + dim == bounds->n_col, goto error);
+	isl_seq_cpy(hull->ineq[k], bounds->row[0], bounds->n_col);
+	isl_mat_free(bounds);
+
+	return hull;
+error:
+	isl_basic_set_free(hull);
+	isl_mat_free(bounds);
+	return NULL;
+}
+
+struct max_constraint {
+	struct isl_mat *c;
+	int	 	count;
+	int		ineq;
+};
+
+static int max_constraint_equal(const void *entry, const void *val)
+{
+	struct max_constraint *a = (struct max_constraint *)entry;
+	isl_int *b = (isl_int *)val;
+
+	return isl_seq_eq(a->c->row[0] + 1, b, a->c->n_col - 1);
+}
+
+static void update_constraint(struct isl_ctx *ctx, struct isl_hash_table *table,
+	isl_int *con, unsigned len, int n, int ineq)
+{
+	struct isl_hash_table_entry *entry;
+	struct max_constraint *c;
+	uint32_t c_hash;
+
+	c_hash = isl_seq_get_hash(con + 1, len);
+	entry = isl_hash_table_find(ctx, table, c_hash, max_constraint_equal,
+			con + 1, 0);
+	if (!entry)
+		return;
+	c = entry->data;
+	if (c->count < n) {
+		isl_hash_table_remove(ctx, table, entry);
+		return;
+	}
+	c->count++;
+	if (isl_int_gt(c->c->row[0][0], con[0]))
+		return;
+	if (isl_int_eq(c->c->row[0][0], con[0])) {
+		if (ineq)
+			c->ineq = ineq;
+		return;
+	}
+	c->c = isl_mat_cow(c->c);
+	isl_int_set(c->c->row[0][0], con[0]);
+	c->ineq = ineq;
+}
+
+/* Check whether the constraint hash table "table" constains the constraint
+ * "con".
+ */
+static int has_constraint(struct isl_ctx *ctx, struct isl_hash_table *table,
+	isl_int *con, unsigned len, int n)
+{
+	struct isl_hash_table_entry *entry;
+	struct max_constraint *c;
+	uint32_t c_hash;
+
+	c_hash = isl_seq_get_hash(con + 1, len);
+	entry = isl_hash_table_find(ctx, table, c_hash, max_constraint_equal,
+			con + 1, 0);
+	if (!entry)
+		return 0;
+	c = entry->data;
+	if (c->count < n)
+		return 0;
+	return isl_int_eq(c->c->row[0][0], con[0]);
+}
+
+/* Check for inequality constraints of a basic set without equalities
+ * such that the same or more stringent copies of the constraint appear
+ * in all of the basic sets.  Such constraints are necessarily facet
+ * constraints of the convex hull.
+ *
+ * If the resulting basic set is by chance identical to one of
+ * the basic sets in "set", then we know that this basic set contains
+ * all other basic sets and is therefore the convex hull of set.
+ * In this case we set *is_hull to 1.
+ */
+static __isl_give isl_basic_set *common_constraints(
+	__isl_take isl_basic_set *hull, __isl_keep isl_set *set, int *is_hull)
+{
+	int i, j, s, n;
+	int min_constraints;
+	int best;
+	struct max_constraint *constraints = NULL;
+	struct isl_hash_table *table = NULL;
+	unsigned total;
+
+	*is_hull = 0;
+
+	for (i = 0; i < set->n; ++i)
+		if (set->p[i]->n_eq == 0)
+			break;
+	if (i >= set->n)
+		return hull;
+	min_constraints = set->p[i]->n_ineq;
+	best = i;
+	for (i = best + 1; i < set->n; ++i) {
+		if (set->p[i]->n_eq != 0)
+			continue;
+		if (set->p[i]->n_ineq >= min_constraints)
+			continue;
+		min_constraints = set->p[i]->n_ineq;
+		best = i;
+	}
+	constraints = isl_calloc_array(hull->ctx, struct max_constraint,
+					min_constraints);
+	if (!constraints)
+		return hull;
+	table = isl_alloc_type(hull->ctx, struct isl_hash_table);
+	if (isl_hash_table_init(hull->ctx, table, min_constraints))
+		goto error;
+
+	total = isl_space_dim(set->dim, isl_dim_all);
+	for (i = 0; i < set->p[best]->n_ineq; ++i) {
+		constraints[i].c = isl_mat_sub_alloc6(hull->ctx,
+			set->p[best]->ineq + i, 0, 1, 0, 1 + total);
+		if (!constraints[i].c)
+			goto error;
+		constraints[i].ineq = 1;
+	}
+	for (i = 0; i < min_constraints; ++i) {
+		struct isl_hash_table_entry *entry;
+		uint32_t c_hash;
+		c_hash = isl_seq_get_hash(constraints[i].c->row[0] + 1, total);
+		entry = isl_hash_table_find(hull->ctx, table, c_hash,
+			max_constraint_equal, constraints[i].c->row[0] + 1, 1);
+		if (!entry)
+			goto error;
+		isl_assert(hull->ctx, !entry->data, goto error);
+		entry->data = &constraints[i];
+	}
+
+	n = 0;
+	for (s = 0; s < set->n; ++s) {
+		if (s == best)
+			continue;
+
+		for (i = 0; i < set->p[s]->n_eq; ++i) {
+			isl_int *eq = set->p[s]->eq[i];
+			for (j = 0; j < 2; ++j) {
+				isl_seq_neg(eq, eq, 1 + total);
+				update_constraint(hull->ctx, table,
+							    eq, total, n, 0);
+			}
+		}
+		for (i = 0; i < set->p[s]->n_ineq; ++i) {
+			isl_int *ineq = set->p[s]->ineq[i];
+			update_constraint(hull->ctx, table, ineq, total, n,
+				set->p[s]->n_eq == 0);
+		}
+		++n;
+	}
+
+	for (i = 0; i < min_constraints; ++i) {
+		if (constraints[i].count < n)
+			continue;
+		if (!constraints[i].ineq)
+			continue;
+		j = isl_basic_set_alloc_inequality(hull);
+		if (j < 0)
+			goto error;
+		isl_seq_cpy(hull->ineq[j], constraints[i].c->row[0], 1 + total);
+	}
+
+	for (s = 0; s < set->n; ++s) {
+		if (set->p[s]->n_eq)
+			continue;
+		if (set->p[s]->n_ineq != hull->n_ineq)
+			continue;
+		for (i = 0; i < set->p[s]->n_ineq; ++i) {
+			isl_int *ineq = set->p[s]->ineq[i];
+			if (!has_constraint(hull->ctx, table, ineq, total, n))
+				break;
+		}
+		if (i == set->p[s]->n_ineq)
+			*is_hull = 1;
+	}
+
+	isl_hash_table_clear(table);
+	for (i = 0; i < min_constraints; ++i)
+		isl_mat_free(constraints[i].c);
+	free(constraints);
+	free(table);
+	return hull;
+error:
+	isl_hash_table_clear(table);
+	free(table);
+	if (constraints)
+		for (i = 0; i < min_constraints; ++i)
+			isl_mat_free(constraints[i].c);
+	free(constraints);
+	return hull;
+}
+
+/* Create a template for the convex hull of "set" and fill it up
+ * obvious facet constraints, if any.  If the result happens to
+ * be the convex hull of "set" then *is_hull is set to 1.
+ */
+static __isl_give isl_basic_set *proto_hull(__isl_keep isl_set *set,
+	int *is_hull)
+{
+	struct isl_basic_set *hull;
+	unsigned n_ineq;
+	int i;
+
+	n_ineq = 1;
+	for (i = 0; i < set->n; ++i) {
+		n_ineq += set->p[i]->n_eq;
+		n_ineq += set->p[i]->n_ineq;
+	}
+	hull = isl_basic_set_alloc_space(isl_space_copy(set->dim), 0, 0, n_ineq);
+	hull = isl_basic_set_set_rational(hull);
+	if (!hull)
+		return NULL;
+	return common_constraints(hull, set, is_hull);
+}
+
+static __isl_give isl_basic_set *uset_convex_hull_wrap(__isl_take isl_set *set)
+{
+	struct isl_basic_set *hull;
+	int is_hull;
+
+	hull = proto_hull(set, &is_hull);
+	if (hull && !is_hull) {
+		if (hull->n_ineq == 0)
+			hull = initial_hull(hull, set);
+		hull = extend(hull, set);
+	}
+	isl_set_free(set);
+
+	return hull;
+}
+
+/* Compute the convex hull of a set without any parameters or
+ * integer divisions.  Depending on whether the set is bounded,
+ * we pass control to the wrapping based convex hull or
+ * the Fourier-Motzkin elimination based convex hull.
+ * We also handle a few special cases before checking the boundedness.
+ */
+static __isl_give isl_basic_set *uset_convex_hull(__isl_take isl_set *set)
+{
+	isl_bool bounded;
+	struct isl_basic_set *convex_hull = NULL;
+	struct isl_basic_set *lin;
+
+	if (isl_set_n_dim(set) == 0)
+		return convex_hull_0d(set);
+
+	set = isl_set_coalesce(set);
+	set = isl_set_set_rational(set);
+
+	if (!set)
+		return NULL;
+	if (set->n == 1) {
+		convex_hull = isl_basic_set_copy(set->p[0]);
+		isl_set_free(set);
+		return convex_hull;
+	}
+	if (isl_set_n_dim(set) == 1)
+		return convex_hull_1d(set);
+
+	bounded = isl_set_is_bounded(set);
+	if (bounded < 0)
+		goto error;
+	if (bounded && set->ctx->opt->convex == ISL_CONVEX_HULL_WRAP)
+		return uset_convex_hull_wrap(set);
+
+	lin = isl_set_combined_lineality_space(isl_set_copy(set));
+	if (!lin)
+		goto error;
+	if (isl_basic_set_plain_is_universe(lin)) {
+		isl_set_free(set);
+		return lin;
+	}
+	if (lin->n_eq < isl_basic_set_total_dim(lin))
+		return modulo_lineality(set, lin);
+	isl_basic_set_free(lin);
+
+	return uset_convex_hull_unbounded(set);
+error:
+	isl_set_free(set);
+	isl_basic_set_free(convex_hull);
+	return NULL;
+}
+
+/* This is the core procedure, where "set" is a "pure" set, i.e.,
+ * without parameters or divs and where the convex hull of set is
+ * known to be full-dimensional.
+ */
+static __isl_give isl_basic_set *uset_convex_hull_wrap_bounded(
+	__isl_take isl_set *set)
+{
+	struct isl_basic_set *convex_hull = NULL;
+
+	if (!set)
+		goto error;
+
+	if (isl_set_n_dim(set) == 0) {
+		convex_hull = isl_basic_set_universe(isl_space_copy(set->dim));
+		isl_set_free(set);
+		convex_hull = isl_basic_set_set_rational(convex_hull);
+		return convex_hull;
+	}
+
+	set = isl_set_set_rational(set);
+	set = isl_set_coalesce(set);
+	if (!set)
+		goto error;
+	if (set->n == 1) {
+		convex_hull = isl_basic_set_copy(set->p[0]);
+		isl_set_free(set);
+		convex_hull = isl_basic_map_remove_redundancies(convex_hull);
+		return convex_hull;
+	}
+	if (isl_set_n_dim(set) == 1)
+		return convex_hull_1d(set);
+
+	return uset_convex_hull_wrap(set);
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Compute the convex hull of set "set" with affine hull "affine_hull",
+ * We first remove the equalities (transforming the set), compute the
+ * convex hull of the transformed set and then add the equalities back
+ * (after performing the inverse transformation.
+ */
+static __isl_give isl_basic_set *modulo_affine_hull(
+	__isl_take isl_set *set, __isl_take isl_basic_set *affine_hull)
+{
+	struct isl_mat *T;
+	struct isl_mat *T2;
+	struct isl_basic_set *dummy;
+	struct isl_basic_set *convex_hull;
+
+	dummy = isl_basic_set_remove_equalities(
+			isl_basic_set_copy(affine_hull), &T, &T2);
+	if (!dummy)
+		goto error;
+	isl_basic_set_free(dummy);
+	set = isl_set_preimage(set, T);
+	convex_hull = uset_convex_hull(set);
+	convex_hull = isl_basic_set_preimage(convex_hull, T2);
+	convex_hull = isl_basic_set_intersect(convex_hull, affine_hull);
+	return convex_hull;
+error:
+	isl_mat_free(T);
+	isl_mat_free(T2);
+	isl_basic_set_free(affine_hull);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Return an empty basic map living in the same space as "map".
+ */
+static __isl_give isl_basic_map *replace_map_by_empty_basic_map(
+	__isl_take isl_map *map)
+{
+	isl_space *space;
+
+	space = isl_map_get_space(map);
+	isl_map_free(map);
+	return isl_basic_map_empty(space);
+}
+
+/* Compute the convex hull of a map.
+ *
+ * The implementation was inspired by "Extended Convex Hull" by Fukuda et al.,
+ * specifically, the wrapping of facets to obtain new facets.
+ */
+__isl_give isl_basic_map *isl_map_convex_hull(__isl_take isl_map *map)
+{
+	struct isl_basic_set *bset;
+	struct isl_basic_map *model = NULL;
+	struct isl_basic_set *affine_hull = NULL;
+	struct isl_basic_map *convex_hull = NULL;
+	struct isl_set *set = NULL;
+
+	map = isl_map_detect_equalities(map);
+	map = isl_map_align_divs_internal(map);
+	if (!map)
+		goto error;
+
+	if (map->n == 0)
+		return replace_map_by_empty_basic_map(map);
+
+	model = isl_basic_map_copy(map->p[0]);
+	set = isl_map_underlying_set(map);
+	if (!set)
+		goto error;
+
+	affine_hull = isl_set_affine_hull(isl_set_copy(set));
+	if (!affine_hull)
+		goto error;
+	if (affine_hull->n_eq != 0)
+		bset = modulo_affine_hull(set, affine_hull);
+	else {
+		isl_basic_set_free(affine_hull);
+		bset = uset_convex_hull(set);
+	}
+
+	convex_hull = isl_basic_map_overlying_set(bset, model);
+	if (!convex_hull)
+		return NULL;
+
+	ISL_F_SET(convex_hull, ISL_BASIC_MAP_NO_IMPLICIT);
+	ISL_F_SET(convex_hull, ISL_BASIC_MAP_ALL_EQUALITIES);
+	ISL_F_CLR(convex_hull, ISL_BASIC_MAP_RATIONAL);
+	return convex_hull;
+error:
+	isl_set_free(set);
+	isl_basic_map_free(model);
+	return NULL;
+}
+
+struct isl_basic_set *isl_set_convex_hull(struct isl_set *set)
+{
+	return bset_from_bmap(isl_map_convex_hull(set_to_map(set)));
+}
+
+__isl_give isl_basic_map *isl_map_polyhedral_hull(__isl_take isl_map *map)
+{
+	isl_basic_map *hull;
+
+	hull = isl_map_convex_hull(map);
+	return isl_basic_map_remove_divs(hull);
+}
+
+__isl_give isl_basic_set *isl_set_polyhedral_hull(__isl_take isl_set *set)
+{
+	return bset_from_bmap(isl_map_polyhedral_hull(set_to_map(set)));
+}
+
+struct sh_data_entry {
+	struct isl_hash_table	*table;
+	struct isl_tab		*tab;
+};
+
+/* Holds the data needed during the simple hull computation.
+ * In particular,
+ *	n		the number of basic sets in the original set
+ *	hull_table	a hash table of already computed constraints
+ *			in the simple hull
+ *	p		for each basic set,
+ *		table		a hash table of the constraints
+ *		tab		the tableau corresponding to the basic set
+ */
+struct sh_data {
+	struct isl_ctx		*ctx;
+	unsigned		n;
+	struct isl_hash_table	*hull_table;
+	struct sh_data_entry	p[1];
+};
+
+static void sh_data_free(struct sh_data *data)
+{
+	int i;
+
+	if (!data)
+		return;
+	isl_hash_table_free(data->ctx, data->hull_table);
+	for (i = 0; i < data->n; ++i) {
+		isl_hash_table_free(data->ctx, data->p[i].table);
+		isl_tab_free(data->p[i].tab);
+	}
+	free(data);
+}
+
+struct ineq_cmp_data {
+	unsigned	len;
+	isl_int		*p;
+};
+
+static int has_ineq(const void *entry, const void *val)
+{
+	isl_int *row = (isl_int *)entry;
+	struct ineq_cmp_data *v = (struct ineq_cmp_data *)val;
+
+	return isl_seq_eq(row + 1, v->p + 1, v->len) ||
+	       isl_seq_is_neg(row + 1, v->p + 1, v->len);
+}
+
+static int hash_ineq(struct isl_ctx *ctx, struct isl_hash_table *table,
+			isl_int *ineq, unsigned len)
+{
+	uint32_t c_hash;
+	struct ineq_cmp_data v;
+	struct isl_hash_table_entry *entry;
+
+	v.len = len;
+	v.p = ineq;
+	c_hash = isl_seq_get_hash(ineq + 1, len);
+	entry = isl_hash_table_find(ctx, table, c_hash, has_ineq, &v, 1);
+	if (!entry)
+		return - 1;
+	entry->data = ineq;
+	return 0;
+}
+
+/* Fill hash table "table" with the constraints of "bset".
+ * Equalities are added as two inequalities.
+ * The value in the hash table is a pointer to the (in)equality of "bset".
+ */
+static int hash_basic_set(struct isl_hash_table *table,
+	__isl_keep isl_basic_set *bset)
+{
+	int i, j;
+	unsigned dim = isl_basic_set_total_dim(bset);
+
+	for (i = 0; i < bset->n_eq; ++i) {
+		for (j = 0; j < 2; ++j) {
+			isl_seq_neg(bset->eq[i], bset->eq[i], 1 + dim);
+			if (hash_ineq(bset->ctx, table, bset->eq[i], dim) < 0)
+				return -1;
+		}
+	}
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (hash_ineq(bset->ctx, table, bset->ineq[i], dim) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+static struct sh_data *sh_data_alloc(__isl_keep isl_set *set, unsigned n_ineq)
+{
+	struct sh_data *data;
+	int i;
+
+	data = isl_calloc(set->ctx, struct sh_data,
+		sizeof(struct sh_data) +
+		(set->n - 1) * sizeof(struct sh_data_entry));
+	if (!data)
+		return NULL;
+	data->ctx = set->ctx;
+	data->n = set->n;
+	data->hull_table = isl_hash_table_alloc(set->ctx, n_ineq);
+	if (!data->hull_table)
+		goto error;
+	for (i = 0; i < set->n; ++i) {
+		data->p[i].table = isl_hash_table_alloc(set->ctx,
+				    2 * set->p[i]->n_eq + set->p[i]->n_ineq);
+		if (!data->p[i].table)
+			goto error;
+		if (hash_basic_set(data->p[i].table, set->p[i]) < 0)
+			goto error;
+	}
+	return data;
+error:
+	sh_data_free(data);
+	return NULL;
+}
+
+/* Check if inequality "ineq" is a bound for basic set "j" or if
+ * it can be relaxed (by increasing the constant term) to become
+ * a bound for that basic set.  In the latter case, the constant
+ * term is updated.
+ * Relaxation of the constant term is only allowed if "shift" is set.
+ *
+ * Return 1 if "ineq" is a bound
+ *	  0 if "ineq" may attain arbitrarily small values on basic set "j"
+ *	 -1 if some error occurred
+ */
+static int is_bound(struct sh_data *data, __isl_keep isl_set *set, int j,
+	isl_int *ineq, int shift)
+{
+	enum isl_lp_result res;
+	isl_int opt;
+
+	if (!data->p[j].tab) {
+		data->p[j].tab = isl_tab_from_basic_set(set->p[j], 0);
+		if (!data->p[j].tab)
+			return -1;
+	}
+
+	isl_int_init(opt);
+
+	res = isl_tab_min(data->p[j].tab, ineq, data->ctx->one,
+				&opt, NULL, 0);
+	if (res == isl_lp_ok && isl_int_is_neg(opt)) {
+		if (shift)
+			isl_int_sub(ineq[0], ineq[0], opt);
+		else
+			res = isl_lp_unbounded;
+	}
+
+	isl_int_clear(opt);
+
+	return (res == isl_lp_ok || res == isl_lp_empty) ? 1 :
+	       res == isl_lp_unbounded ? 0 : -1;
+}
+
+/* Set the constant term of "ineq" to the maximum of those of the constraints
+ * in the basic sets of "set" following "i" that are parallel to "ineq".
+ * That is, if any of the basic sets of "set" following "i" have a more
+ * relaxed copy of "ineq", then replace "ineq" by the most relaxed copy.
+ * "c_hash" is the hash value of the linear part of "ineq".
+ * "v" has been set up for use by has_ineq.
+ *
+ * Note that the two inequality constraints corresponding to an equality are
+ * represented by the same inequality constraint in data->p[j].table
+ * (but with different hash values).  This means the constraint (or at
+ * least its constant term) may need to be temporarily negated to get
+ * the actually hashed constraint.
+ */
+static void set_max_constant_term(struct sh_data *data, __isl_keep isl_set *set,
+	int i, isl_int *ineq, uint32_t c_hash, struct ineq_cmp_data *v)
+{
+	int j;
+	isl_ctx *ctx;
+	struct isl_hash_table_entry *entry;
+
+	ctx = isl_set_get_ctx(set);
+	for (j = i + 1; j < set->n; ++j) {
+		int neg;
+		isl_int *ineq_j;
+
+		entry = isl_hash_table_find(ctx, data->p[j].table,
+						c_hash, &has_ineq, v, 0);
+		if (!entry)
+			continue;
+
+		ineq_j = entry->data;
+		neg = isl_seq_is_neg(ineq_j + 1, ineq + 1, v->len);
+		if (neg)
+			isl_int_neg(ineq_j[0], ineq_j[0]);
+		if (isl_int_gt(ineq_j[0], ineq[0]))
+			isl_int_set(ineq[0], ineq_j[0]);
+		if (neg)
+			isl_int_neg(ineq_j[0], ineq_j[0]);
+	}
+}
+
+/* Check if inequality "ineq" from basic set "i" is or can be relaxed to
+ * become a bound on the whole set.  If so, add the (relaxed) inequality
+ * to "hull".  Relaxation is only allowed if "shift" is set.
+ *
+ * We first check if "hull" already contains a translate of the inequality.
+ * If so, we are done.
+ * Then, we check if any of the previous basic sets contains a translate
+ * of the inequality.  If so, then we have already considered this
+ * inequality and we are done.
+ * Otherwise, for each basic set other than "i", we check if the inequality
+ * is a bound on the basic set, but first replace the constant term
+ * by the maximal value of any translate of the inequality in any
+ * of the following basic sets.
+ * For previous basic sets, we know that they do not contain a translate
+ * of the inequality, so we directly call is_bound.
+ * For following basic sets, we first check if a translate of the
+ * inequality appears in its description.  If so, the constant term
+ * of the inequality has already been updated with respect to this
+ * translate and the inequality is therefore known to be a bound
+ * of this basic set.
+ */
+static __isl_give isl_basic_set *add_bound(__isl_take isl_basic_set *hull,
+	struct sh_data *data, __isl_keep isl_set *set, int i, isl_int *ineq,
+	int shift)
+{
+	uint32_t c_hash;
+	struct ineq_cmp_data v;
+	struct isl_hash_table_entry *entry;
+	int j, k;
+
+	if (!hull)
+		return NULL;
+
+	v.len = isl_basic_set_total_dim(hull);
+	v.p = ineq;
+	c_hash = isl_seq_get_hash(ineq + 1, v.len);
+
+	entry = isl_hash_table_find(hull->ctx, data->hull_table, c_hash,
+					has_ineq, &v, 0);
+	if (entry)
+		return hull;
+
+	for (j = 0; j < i; ++j) {
+		entry = isl_hash_table_find(hull->ctx, data->p[j].table,
+						c_hash, has_ineq, &v, 0);
+		if (entry)
+			break;
+	}
+	if (j < i)
+		return hull;
+
+	k = isl_basic_set_alloc_inequality(hull);
+	if (k < 0)
+		goto error;
+	isl_seq_cpy(hull->ineq[k], ineq, 1 + v.len);
+
+	set_max_constant_term(data, set, i, hull->ineq[k], c_hash, &v);
+	for (j = 0; j < i; ++j) {
+		int bound;
+		bound = is_bound(data, set, j, hull->ineq[k], shift);
+		if (bound < 0)
+			goto error;
+		if (!bound)
+			break;
+	}
+	if (j < i) {
+		isl_basic_set_free_inequality(hull, 1);
+		return hull;
+	}
+
+	for (j = i + 1; j < set->n; ++j) {
+		int bound;
+		entry = isl_hash_table_find(hull->ctx, data->p[j].table,
+						c_hash, has_ineq, &v, 0);
+		if (entry)
+			continue;
+		bound = is_bound(data, set, j, hull->ineq[k], shift);
+		if (bound < 0)
+			goto error;
+		if (!bound)
+			break;
+	}
+	if (j < set->n) {
+		isl_basic_set_free_inequality(hull, 1);
+		return hull;
+	}
+
+	entry = isl_hash_table_find(hull->ctx, data->hull_table, c_hash,
+					has_ineq, &v, 1);
+	if (!entry)
+		goto error;
+	entry->data = hull->ineq[k];
+
+	return hull;
+error:
+	isl_basic_set_free(hull);
+	return NULL;
+}
+
+/* Check if any inequality from basic set "i" is or can be relaxed to
+ * become a bound on the whole set.  If so, add the (relaxed) inequality
+ * to "hull".  Relaxation is only allowed if "shift" is set.
+ */
+static __isl_give isl_basic_set *add_bounds(__isl_take isl_basic_set *bset,
+	struct sh_data *data, __isl_keep isl_set *set, int i, int shift)
+{
+	int j, k;
+	unsigned dim = isl_basic_set_total_dim(bset);
+
+	for (j = 0; j < set->p[i]->n_eq; ++j) {
+		for (k = 0; k < 2; ++k) {
+			isl_seq_neg(set->p[i]->eq[j], set->p[i]->eq[j], 1+dim);
+			bset = add_bound(bset, data, set, i, set->p[i]->eq[j],
+					    shift);
+		}
+	}
+	for (j = 0; j < set->p[i]->n_ineq; ++j)
+		bset = add_bound(bset, data, set, i, set->p[i]->ineq[j], shift);
+	return bset;
+}
+
+/* Compute a superset of the convex hull of set that is described
+ * by only (translates of) the constraints in the constituents of set.
+ * Translation is only allowed if "shift" is set.
+ */
+static __isl_give isl_basic_set *uset_simple_hull(__isl_take isl_set *set,
+	int shift)
+{
+	struct sh_data *data = NULL;
+	struct isl_basic_set *hull = NULL;
+	unsigned n_ineq;
+	int i;
+
+	if (!set)
+		return NULL;
+
+	n_ineq = 0;
+	for (i = 0; i < set->n; ++i) {
+		if (!set->p[i])
+			goto error;
+		n_ineq += 2 * set->p[i]->n_eq + set->p[i]->n_ineq;
+	}
+
+	hull = isl_basic_set_alloc_space(isl_space_copy(set->dim), 0, 0, n_ineq);
+	if (!hull)
+		goto error;
+
+	data = sh_data_alloc(set, n_ineq);
+	if (!data)
+		goto error;
+
+	for (i = 0; i < set->n; ++i)
+		hull = add_bounds(hull, data, set, i, shift);
+
+	sh_data_free(data);
+	isl_set_free(set);
+
+	return hull;
+error:
+	sh_data_free(data);
+	isl_basic_set_free(hull);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Compute a superset of the convex hull of map that is described
+ * by only (translates of) the constraints in the constituents of map.
+ * Handle trivial cases where map is NULL or contains at most one disjunct.
+ */
+static __isl_give isl_basic_map *map_simple_hull_trivial(
+	__isl_take isl_map *map)
+{
+	isl_basic_map *hull;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return replace_map_by_empty_basic_map(map);
+
+	hull = isl_basic_map_copy(map->p[0]);
+	isl_map_free(map);
+	return hull;
+}
+
+/* Return a copy of the simple hull cached inside "map".
+ * "shift" determines whether to return the cached unshifted or shifted
+ * simple hull.
+ */
+static __isl_give isl_basic_map *cached_simple_hull(__isl_take isl_map *map,
+	int shift)
+{
+	isl_basic_map *hull;
+
+	hull = isl_basic_map_copy(map->cached_simple_hull[shift]);
+	isl_map_free(map);
+
+	return hull;
+}
+
+/* Compute a superset of the convex hull of map that is described
+ * by only (translates of) the constraints in the constituents of map.
+ * Translation is only allowed if "shift" is set.
+ *
+ * The constraints are sorted while removing redundant constraints
+ * in order to indicate a preference of which constraints should
+ * be preserved.  In particular, pairs of constraints that are
+ * sorted together are preferred to either both be preserved
+ * or both be removed.  The sorting is performed inside
+ * isl_basic_map_remove_redundancies.
+ *
+ * The result of the computation is stored in map->cached_simple_hull[shift]
+ * such that it can be reused in subsequent calls.  The cache is cleared
+ * whenever the map is modified (in isl_map_cow).
+ * Note that the results need to be stored in the input map for there
+ * to be any chance that they may get reused.  In particular, they
+ * are stored in a copy of the input map that is saved before
+ * the integer division alignment.
+ */
+static __isl_give isl_basic_map *map_simple_hull(__isl_take isl_map *map,
+	int shift)
+{
+	struct isl_set *set = NULL;
+	struct isl_basic_map *model = NULL;
+	struct isl_basic_map *hull;
+	struct isl_basic_map *affine_hull;
+	struct isl_basic_set *bset = NULL;
+	isl_map *input;
+
+	if (!map || map->n <= 1)
+		return map_simple_hull_trivial(map);
+
+	if (map->cached_simple_hull[shift])
+		return cached_simple_hull(map, shift);
+
+	map = isl_map_detect_equalities(map);
+	if (!map || map->n <= 1)
+		return map_simple_hull_trivial(map);
+	affine_hull = isl_map_affine_hull(isl_map_copy(map));
+	input = isl_map_copy(map);
+	map = isl_map_align_divs_internal(map);
+	model = map ? isl_basic_map_copy(map->p[0]) : NULL;
+
+	set = isl_map_underlying_set(map);
+
+	bset = uset_simple_hull(set, shift);
+
+	hull = isl_basic_map_overlying_set(bset, model);
+
+	hull = isl_basic_map_intersect(hull, affine_hull);
+	hull = isl_basic_map_remove_redundancies(hull);
+
+	if (hull) {
+		ISL_F_SET(hull, ISL_BASIC_MAP_NO_IMPLICIT);
+		ISL_F_SET(hull, ISL_BASIC_MAP_ALL_EQUALITIES);
+	}
+
+	hull = isl_basic_map_finalize(hull);
+	if (input)
+		input->cached_simple_hull[shift] = isl_basic_map_copy(hull);
+	isl_map_free(input);
+
+	return hull;
+}
+
+/* Compute a superset of the convex hull of map that is described
+ * by only translates of the constraints in the constituents of map.
+ */
+__isl_give isl_basic_map *isl_map_simple_hull(__isl_take isl_map *map)
+{
+	return map_simple_hull(map, 1);
+}
+
+struct isl_basic_set *isl_set_simple_hull(struct isl_set *set)
+{
+	return bset_from_bmap(isl_map_simple_hull(set_to_map(set)));
+}
+
+/* Compute a superset of the convex hull of map that is described
+ * by only the constraints in the constituents of map.
+ */
+__isl_give isl_basic_map *isl_map_unshifted_simple_hull(
+	__isl_take isl_map *map)
+{
+	return map_simple_hull(map, 0);
+}
+
+__isl_give isl_basic_set *isl_set_unshifted_simple_hull(
+	__isl_take isl_set *set)
+{
+	return isl_map_unshifted_simple_hull(set);
+}
+
+/* Drop all inequalities from "bmap1" that do not also appear in "bmap2".
+ * A constraint that appears with different constant terms
+ * in "bmap1" and "bmap2" is also kept, with the least restrictive
+ * (i.e., greatest) constant term.
+ * "bmap1" and "bmap2" are assumed to have the same (known)
+ * integer divisions.
+ * The constraints of both "bmap1" and "bmap2" are assumed
+ * to have been sorted using isl_basic_map_sort_constraints.
+ *
+ * Run through the inequality constraints of "bmap1" and "bmap2"
+ * in sorted order.
+ * Each constraint of "bmap1" without a matching constraint in "bmap2"
+ * is removed.
+ * If a match is found, the constraint is kept.  If needed, the constant
+ * term of the constraint is adjusted.
+ */
+static __isl_give isl_basic_map *select_shared_inequalities(
+	__isl_take isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2)
+{
+	int i1, i2;
+
+	bmap1 = isl_basic_map_cow(bmap1);
+	if (!bmap1 || !bmap2)
+		return isl_basic_map_free(bmap1);
+
+	i1 = bmap1->n_ineq - 1;
+	i2 = bmap2->n_ineq - 1;
+	while (bmap1 && i1 >= 0 && i2 >= 0) {
+		int cmp;
+
+		cmp = isl_basic_map_constraint_cmp(bmap1, bmap1->ineq[i1],
+							bmap2->ineq[i2]);
+		if (cmp < 0) {
+			--i2;
+			continue;
+		}
+		if (cmp > 0) {
+			if (isl_basic_map_drop_inequality(bmap1, i1) < 0)
+				bmap1 = isl_basic_map_free(bmap1);
+			--i1;
+			continue;
+		}
+		if (isl_int_lt(bmap1->ineq[i1][0], bmap2->ineq[i2][0]))
+			isl_int_set(bmap1->ineq[i1][0], bmap2->ineq[i2][0]);
+		--i1;
+		--i2;
+	}
+	for (; i1 >= 0; --i1)
+		if (isl_basic_map_drop_inequality(bmap1, i1) < 0)
+			bmap1 = isl_basic_map_free(bmap1);
+
+	return bmap1;
+}
+
+/* Drop all equalities from "bmap1" that do not also appear in "bmap2".
+ * "bmap1" and "bmap2" are assumed to have the same (known)
+ * integer divisions.
+ *
+ * Run through the equality constraints of "bmap1" and "bmap2".
+ * Each constraint of "bmap1" without a matching constraint in "bmap2"
+ * is removed.
+ */
+static __isl_give isl_basic_map *select_shared_equalities(
+	__isl_take isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2)
+{
+	int i1, i2;
+	unsigned total;
+
+	bmap1 = isl_basic_map_cow(bmap1);
+	if (!bmap1 || !bmap2)
+		return isl_basic_map_free(bmap1);
+
+	total = isl_basic_map_total_dim(bmap1);
+
+	i1 = bmap1->n_eq - 1;
+	i2 = bmap2->n_eq - 1;
+	while (bmap1 && i1 >= 0 && i2 >= 0) {
+		int last1, last2;
+
+		last1 = isl_seq_last_non_zero(bmap1->eq[i1] + 1, total);
+		last2 = isl_seq_last_non_zero(bmap2->eq[i2] + 1, total);
+		if (last1 > last2) {
+			--i2;
+			continue;
+		}
+		if (last1 < last2) {
+			if (isl_basic_map_drop_equality(bmap1, i1) < 0)
+				bmap1 = isl_basic_map_free(bmap1);
+			--i1;
+			continue;
+		}
+		if (!isl_seq_eq(bmap1->eq[i1], bmap2->eq[i2], 1 + total)) {
+			if (isl_basic_map_drop_equality(bmap1, i1) < 0)
+				bmap1 = isl_basic_map_free(bmap1);
+		}
+		--i1;
+		--i2;
+	}
+	for (; i1 >= 0; --i1)
+		if (isl_basic_map_drop_equality(bmap1, i1) < 0)
+			bmap1 = isl_basic_map_free(bmap1);
+
+	return bmap1;
+}
+
+/* Compute a superset of "bmap1" and "bmap2" that is described
+ * by only the constraints that appear in both "bmap1" and "bmap2".
+ *
+ * First drop constraints that involve unknown integer divisions
+ * since it is not trivial to check whether two such integer divisions
+ * in different basic maps are the same.
+ * Then align the remaining (known) divs and sort the constraints.
+ * Finally drop all inequalities and equalities from "bmap1" that
+ * do not also appear in "bmap2".
+ */
+__isl_give isl_basic_map *isl_basic_map_plain_unshifted_simple_hull(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+	bmap1 = isl_basic_map_drop_constraint_involving_unknown_divs(bmap1);
+	bmap2 = isl_basic_map_drop_constraint_involving_unknown_divs(bmap2);
+	bmap2 = isl_basic_map_align_divs(bmap2, bmap1);
+	bmap1 = isl_basic_map_align_divs(bmap1, bmap2);
+	bmap1 = isl_basic_map_gauss(bmap1, NULL);
+	bmap2 = isl_basic_map_gauss(bmap2, NULL);
+	bmap1 = isl_basic_map_sort_constraints(bmap1);
+	bmap2 = isl_basic_map_sort_constraints(bmap2);
+
+	bmap1 = select_shared_inequalities(bmap1, bmap2);
+	bmap1 = select_shared_equalities(bmap1, bmap2);
+
+	isl_basic_map_free(bmap2);
+	bmap1 = isl_basic_map_finalize(bmap1);
+	return bmap1;
+}
+
+/* Compute a superset of the convex hull of "map" that is described
+ * by only the constraints in the constituents of "map".
+ * In particular, the result is composed of constraints that appear
+ * in each of the basic maps of "map"
+ *
+ * Constraints that involve unknown integer divisions are dropped
+ * since it is not trivial to check whether two such integer divisions
+ * in different basic maps are the same.
+ *
+ * The hull is initialized from the first basic map and then
+ * updated with respect to the other basic maps in turn.
+ */
+__isl_give isl_basic_map *isl_map_plain_unshifted_simple_hull(
+	__isl_take isl_map *map)
+{
+	int i;
+	isl_basic_map *hull;
+
+	if (!map)
+		return NULL;
+	if (map->n <= 1)
+		return map_simple_hull_trivial(map);
+	map = isl_map_drop_constraint_involving_unknown_divs(map);
+	hull = isl_basic_map_copy(map->p[0]);
+	for (i = 1; i < map->n; ++i) {
+		isl_basic_map *bmap_i;
+
+		bmap_i = isl_basic_map_copy(map->p[i]);
+		hull = isl_basic_map_plain_unshifted_simple_hull(hull, bmap_i);
+	}
+
+	isl_map_free(map);
+	return hull;
+}
+
+/* Compute a superset of the convex hull of "set" that is described
+ * by only the constraints in the constituents of "set".
+ * In particular, the result is composed of constraints that appear
+ * in each of the basic sets of "set"
+ */
+__isl_give isl_basic_set *isl_set_plain_unshifted_simple_hull(
+	__isl_take isl_set *set)
+{
+	return isl_map_plain_unshifted_simple_hull(set);
+}
+
+/* Check if "ineq" is a bound on "set" and, if so, add it to "hull".
+ *
+ * For each basic set in "set", we first check if the basic set
+ * contains a translate of "ineq".  If this translate is more relaxed,
+ * then we assume that "ineq" is not a bound on this basic set.
+ * Otherwise, we know that it is a bound.
+ * If the basic set does not contain a translate of "ineq", then
+ * we call is_bound to perform the test.
+ */
+static __isl_give isl_basic_set *add_bound_from_constraint(
+	__isl_take isl_basic_set *hull, struct sh_data *data,
+	__isl_keep isl_set *set, isl_int *ineq)
+{
+	int i, k;
+	isl_ctx *ctx;
+	uint32_t c_hash;
+	struct ineq_cmp_data v;
+
+	if (!hull || !set)
+		return isl_basic_set_free(hull);
+
+	v.len = isl_basic_set_total_dim(hull);
+	v.p = ineq;
+	c_hash = isl_seq_get_hash(ineq + 1, v.len);
+
+	ctx = isl_basic_set_get_ctx(hull);
+	for (i = 0; i < set->n; ++i) {
+		int bound;
+		struct isl_hash_table_entry *entry;
+
+		entry = isl_hash_table_find(ctx, data->p[i].table,
+						c_hash, &has_ineq, &v, 0);
+		if (entry) {
+			isl_int *ineq_i = entry->data;
+			int neg, more_relaxed;
+
+			neg = isl_seq_is_neg(ineq_i + 1, ineq + 1, v.len);
+			if (neg)
+				isl_int_neg(ineq_i[0], ineq_i[0]);
+			more_relaxed = isl_int_gt(ineq_i[0], ineq[0]);
+			if (neg)
+				isl_int_neg(ineq_i[0], ineq_i[0]);
+			if (more_relaxed)
+				break;
+			else
+				continue;
+		}
+		bound = is_bound(data, set, i, ineq, 0);
+		if (bound < 0)
+			return isl_basic_set_free(hull);
+		if (!bound)
+			break;
+	}
+	if (i < set->n)
+		return hull;
+
+	k = isl_basic_set_alloc_inequality(hull);
+	if (k < 0)
+		return isl_basic_set_free(hull);
+	isl_seq_cpy(hull->ineq[k], ineq, 1 + v.len);
+
+	return hull;
+}
+
+/* Compute a superset of the convex hull of "set" that is described
+ * by only some of the "n_ineq" constraints in the list "ineq", where "set"
+ * has no parameters or integer divisions.
+ *
+ * The inequalities in "ineq" are assumed to have been sorted such
+ * that constraints with the same linear part appear together and
+ * that among constraints with the same linear part, those with
+ * smaller constant term appear first.
+ *
+ * We reuse the same data structure that is used by uset_simple_hull,
+ * but we do not need the hull table since we will not consider the
+ * same constraint more than once.  We therefore allocate it with zero size.
+ *
+ * We run through the constraints and try to add them one by one,
+ * skipping identical constraints.  If we have added a constraint and
+ * the next constraint is a more relaxed translate, then we skip this
+ * next constraint as well.
+ */
+static __isl_give isl_basic_set *uset_unshifted_simple_hull_from_constraints(
+	__isl_take isl_set *set, int n_ineq, isl_int **ineq)
+{
+	int i;
+	int last_added = 0;
+	struct sh_data *data = NULL;
+	isl_basic_set *hull = NULL;
+	unsigned dim;
+
+	hull = isl_basic_set_alloc_space(isl_set_get_space(set), 0, 0, n_ineq);
+	if (!hull)
+		goto error;
+
+	data = sh_data_alloc(set, 0);
+	if (!data)
+		goto error;
+
+	dim = isl_set_dim(set, isl_dim_set);
+	for (i = 0; i < n_ineq; ++i) {
+		int hull_n_ineq = hull->n_ineq;
+		int parallel;
+
+		parallel = i > 0 && isl_seq_eq(ineq[i - 1] + 1, ineq[i] + 1,
+						dim);
+		if (parallel &&
+		    (last_added || isl_int_eq(ineq[i - 1][0], ineq[i][0])))
+			continue;
+		hull = add_bound_from_constraint(hull, data, set, ineq[i]);
+		if (!hull)
+			goto error;
+		last_added = hull->n_ineq > hull_n_ineq;
+	}
+
+	sh_data_free(data);
+	isl_set_free(set);
+	return hull;
+error:
+	sh_data_free(data);
+	isl_set_free(set);
+	isl_basic_set_free(hull);
+	return NULL;
+}
+
+/* Collect pointers to all the inequalities in the elements of "list"
+ * in "ineq".  For equalities, store both a pointer to the equality and
+ * a pointer to its opposite, which is first copied to "mat".
+ * "ineq" and "mat" are assumed to have been preallocated to the right size
+ * (the number of inequalities + 2 times the number of equalites and
+ * the number of equalities, respectively).
+ */
+static __isl_give isl_mat *collect_inequalities(__isl_take isl_mat *mat,
+	__isl_keep isl_basic_set_list *list, isl_int **ineq)
+{
+	int i, j, n, n_eq, n_ineq;
+
+	if (!mat)
+		return NULL;
+
+	n_eq = 0;
+	n_ineq = 0;
+	n = isl_basic_set_list_n_basic_set(list);
+	for (i = 0; i < n; ++i) {
+		isl_basic_set *bset;
+		bset = isl_basic_set_list_get_basic_set(list, i);
+		if (!bset)
+			return isl_mat_free(mat);
+		for (j = 0; j < bset->n_eq; ++j) {
+			ineq[n_ineq++] = mat->row[n_eq];
+			ineq[n_ineq++] = bset->eq[j];
+			isl_seq_neg(mat->row[n_eq++], bset->eq[j], mat->n_col);
+		}
+		for (j = 0; j < bset->n_ineq; ++j)
+			ineq[n_ineq++] = bset->ineq[j];
+		isl_basic_set_free(bset);
+	}
+
+	return mat;
+}
+
+/* Comparison routine for use as an isl_sort callback.
+ *
+ * Constraints with the same linear part are sorted together and
+ * among constraints with the same linear part, those with smaller
+ * constant term are sorted first.
+ */
+static int cmp_ineq(const void *a, const void *b, void *arg)
+{
+	unsigned dim = *(unsigned *) arg;
+	isl_int * const *ineq1 = a;
+	isl_int * const *ineq2 = b;
+	int cmp;
+
+	cmp = isl_seq_cmp((*ineq1) + 1, (*ineq2) + 1, dim);
+	if (cmp != 0)
+		return cmp;
+	return isl_int_cmp((*ineq1)[0], (*ineq2)[0]);
+}
+
+/* Compute a superset of the convex hull of "set" that is described
+ * by only constraints in the elements of "list", where "set" has
+ * no parameters or integer divisions.
+ *
+ * We collect all the constraints in those elements and then
+ * sort the constraints such that constraints with the same linear part
+ * are sorted together and that those with smaller constant term are
+ * sorted first.
+ */
+static __isl_give isl_basic_set *uset_unshifted_simple_hull_from_basic_set_list(
+	__isl_take isl_set *set, __isl_take isl_basic_set_list *list)
+{
+	int i, n, n_eq, n_ineq;
+	unsigned dim;
+	isl_ctx *ctx;
+	isl_mat *mat = NULL;
+	isl_int **ineq = NULL;
+	isl_basic_set *hull;
+
+	if (!set)
+		goto error;
+	ctx = isl_set_get_ctx(set);
+
+	n_eq = 0;
+	n_ineq = 0;
+	n = isl_basic_set_list_n_basic_set(list);
+	for (i = 0; i < n; ++i) {
+		isl_basic_set *bset;
+		bset = isl_basic_set_list_get_basic_set(list, i);
+		if (!bset)
+			goto error;
+		n_eq += bset->n_eq;
+		n_ineq += 2 * bset->n_eq + bset->n_ineq;
+		isl_basic_set_free(bset);
+	}
+
+	ineq = isl_alloc_array(ctx, isl_int *, n_ineq);
+	if (n_ineq > 0 && !ineq)
+		goto error;
+
+	dim = isl_set_dim(set, isl_dim_set);
+	mat = isl_mat_alloc(ctx, n_eq, 1 + dim);
+	mat = collect_inequalities(mat, list, ineq);
+	if (!mat)
+		goto error;
+
+	if (isl_sort(ineq, n_ineq, sizeof(ineq[0]), &cmp_ineq, &dim) < 0)
+		goto error;
+
+	hull = uset_unshifted_simple_hull_from_constraints(set, n_ineq, ineq);
+
+	isl_mat_free(mat);
+	free(ineq);
+	isl_basic_set_list_free(list);
+	return hull;
+error:
+	isl_mat_free(mat);
+	free(ineq);
+	isl_set_free(set);
+	isl_basic_set_list_free(list);
+	return NULL;
+}
+
+/* Compute a superset of the convex hull of "map" that is described
+ * by only constraints in the elements of "list".
+ *
+ * If the list is empty, then we can only describe the universe set.
+ * If the input map is empty, then all constraints are valid, so
+ * we return the intersection of the elements in "list".
+ *
+ * Otherwise, we align all divs and temporarily treat them
+ * as regular variables, computing the unshifted simple hull in
+ * uset_unshifted_simple_hull_from_basic_set_list.
+ */
+static __isl_give isl_basic_map *map_unshifted_simple_hull_from_basic_map_list(
+	__isl_take isl_map *map, __isl_take isl_basic_map_list *list)
+{
+	isl_basic_map *model;
+	isl_basic_map *hull;
+	isl_set *set;
+	isl_basic_set_list *bset_list;
+
+	if (!map || !list)
+		goto error;
+
+	if (isl_basic_map_list_n_basic_map(list) == 0) {
+		isl_space *space;
+
+		space = isl_map_get_space(map);
+		isl_map_free(map);
+		isl_basic_map_list_free(list);
+		return isl_basic_map_universe(space);
+	}
+	if (isl_map_plain_is_empty(map)) {
+		isl_map_free(map);
+		return isl_basic_map_list_intersect(list);
+	}
+
+	map = isl_map_align_divs_to_basic_map_list(map, list);
+	if (!map)
+		goto error;
+	list = isl_basic_map_list_align_divs_to_basic_map(list, map->p[0]);
+
+	model = isl_basic_map_list_get_basic_map(list, 0);
+
+	set = isl_map_underlying_set(map);
+	bset_list = isl_basic_map_list_underlying_set(list);
+
+	hull = uset_unshifted_simple_hull_from_basic_set_list(set, bset_list);
+	hull = isl_basic_map_overlying_set(hull, model);
+
+	return hull;
+error:
+	isl_map_free(map);
+	isl_basic_map_list_free(list);
+	return NULL;
+}
+
+/* Return a sequence of the basic maps that make up the maps in "list".
+ */
+static __isl_give isl_basic_map_list *collect_basic_maps(
+	__isl_take isl_map_list *list)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_basic_map_list *bmap_list;
+
+	if (!list)
+		return NULL;
+	n = isl_map_list_n_map(list);
+	ctx = isl_map_list_get_ctx(list);
+	bmap_list = isl_basic_map_list_alloc(ctx, 0);
+
+	for (i = 0; i < n; ++i) {
+		isl_map *map;
+		isl_basic_map_list *list_i;
+
+		map = isl_map_list_get_map(list, i);
+		map = isl_map_compute_divs(map);
+		list_i = isl_map_get_basic_map_list(map);
+		isl_map_free(map);
+		bmap_list = isl_basic_map_list_concat(bmap_list, list_i);
+	}
+
+	isl_map_list_free(list);
+	return bmap_list;
+}
+
+/* Compute a superset of the convex hull of "map" that is described
+ * by only constraints in the elements of "list".
+ *
+ * If "map" is the universe, then the convex hull (and therefore
+ * any superset of the convexhull) is the universe as well.
+ *
+ * Otherwise, we collect all the basic maps in the map list and
+ * continue with map_unshifted_simple_hull_from_basic_map_list.
+ */
+__isl_give isl_basic_map *isl_map_unshifted_simple_hull_from_map_list(
+	__isl_take isl_map *map, __isl_take isl_map_list *list)
+{
+	isl_basic_map_list *bmap_list;
+	int is_universe;
+
+	is_universe = isl_map_plain_is_universe(map);
+	if (is_universe < 0)
+		map = isl_map_free(map);
+	if (is_universe < 0 || is_universe) {
+		isl_map_list_free(list);
+		return isl_map_unshifted_simple_hull(map);
+	}
+
+	bmap_list = collect_basic_maps(list);
+	return map_unshifted_simple_hull_from_basic_map_list(map, bmap_list);
+}
+
+/* Compute a superset of the convex hull of "set" that is described
+ * by only constraints in the elements of "list".
+ */
+__isl_give isl_basic_set *isl_set_unshifted_simple_hull_from_set_list(
+	__isl_take isl_set *set, __isl_take isl_set_list *list)
+{
+	return isl_map_unshifted_simple_hull_from_map_list(set, list);
+}
+
+/* Given a set "set", return parametric bounds on the dimension "dim".
+ */
+static struct isl_basic_set *set_bounds(struct isl_set *set, int dim)
+{
+	unsigned set_dim = isl_set_dim(set, isl_dim_set);
+	set = isl_set_copy(set);
+	set = isl_set_eliminate_dims(set, dim + 1, set_dim - (dim + 1));
+	set = isl_set_eliminate_dims(set, 0, dim);
+	return isl_set_convex_hull(set);
+}
+
+/* Computes a "simple hull" and then check if each dimension in the
+ * resulting hull is bounded by a symbolic constant.  If not, the
+ * hull is intersected with the corresponding bounds on the whole set.
+ */
+__isl_give isl_basic_set *isl_set_bounded_simple_hull(__isl_take isl_set *set)
+{
+	int i, j;
+	struct isl_basic_set *hull;
+	unsigned nparam, left;
+	int removed_divs = 0;
+
+	hull = isl_set_simple_hull(isl_set_copy(set));
+	if (!hull)
+		goto error;
+
+	nparam = isl_basic_set_dim(hull, isl_dim_param);
+	for (i = 0; i < isl_basic_set_dim(hull, isl_dim_set); ++i) {
+		int lower = 0, upper = 0;
+		struct isl_basic_set *bounds;
+
+		left = isl_basic_set_total_dim(hull) - nparam - i - 1;
+		for (j = 0; j < hull->n_eq; ++j) {
+			if (isl_int_is_zero(hull->eq[j][1 + nparam + i]))
+				continue;
+			if (isl_seq_first_non_zero(hull->eq[j]+1+nparam+i+1,
+						    left) == -1)
+				break;
+		}
+		if (j < hull->n_eq)
+			continue;
+
+		for (j = 0; j < hull->n_ineq; ++j) {
+			if (isl_int_is_zero(hull->ineq[j][1 + nparam + i]))
+				continue;
+			if (isl_seq_first_non_zero(hull->ineq[j]+1+nparam+i+1,
+						    left) != -1 ||
+			    isl_seq_first_non_zero(hull->ineq[j]+1+nparam,
+						    i) != -1)
+				continue;
+			if (isl_int_is_pos(hull->ineq[j][1 + nparam + i]))
+				lower = 1;
+			else
+				upper = 1;
+			if (lower && upper)
+				break;
+		}
+
+		if (lower && upper)
+			continue;
+
+		if (!removed_divs) {
+			set = isl_set_remove_divs(set);
+			if (!set)
+				goto error;
+			removed_divs = 1;
+		}
+		bounds = set_bounds(set, i);
+		hull = isl_basic_set_intersect(hull, bounds);
+		if (!hull)
+			goto error;
+	}
+
+	isl_set_free(set);
+	return hull;
+error:
+	isl_set_free(set);
+	isl_basic_set_free(hull);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_ctx.c b/final/lib/External/isl/isl_ctx.c
new file mode 100644
index 0000000..002863e
--- /dev/null
+++ b/final/lib/External/isl/isl_ctx.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_ctx_private.h>
+#include <isl/vec.h>
+#include <isl_options_private.h>
+
+#define __isl_calloc(type,size)		((type *)calloc(1, size))
+#define __isl_calloc_type(type)		__isl_calloc(type,sizeof(type))
+
+/* Return the negation of "b", where the negation of isl_bool_error
+ * is isl_bool_error again.
+ */
+isl_bool isl_bool_not(isl_bool b)
+{
+	return b < 0 ? isl_bool_error : !b;
+}
+
+/* Check that the result of an allocation ("p") is not NULL and
+ * complain if it is.
+ * The only exception is when allocation size ("size") is equal to zero.
+ */
+static void *check_non_null(isl_ctx *ctx, void *p, size_t size)
+{
+	if (p || size == 0)
+		return p;
+	isl_die(ctx, isl_error_alloc, "allocation failure", return NULL);
+}
+
+/* Prepare for performing the next "operation" in the context.
+ * Return 0 if we are allowed to perform this operation and
+ * return -1 if we should abort the computation.
+ *
+ * In particular, we should stop if the user has explicitly aborted
+ * the computation or if the maximal number of operations has been exceeded.
+ */
+int isl_ctx_next_operation(isl_ctx *ctx)
+{
+	if (!ctx)
+		return -1;
+	if (ctx->abort) {
+		isl_ctx_set_error(ctx, isl_error_abort);
+		return -1;
+	}
+	if (ctx->max_operations && ctx->operations >= ctx->max_operations)
+		isl_die(ctx, isl_error_quota,
+			"maximal number of operations exceeded", return -1);
+	ctx->operations++;
+	return 0;
+}
+
+/* Call malloc and complain if it fails.
+ * If ctx is NULL, then return NULL.
+ */
+void *isl_malloc_or_die(isl_ctx *ctx, size_t size)
+{
+	if (isl_ctx_next_operation(ctx) < 0)
+		return NULL;
+	return ctx ? check_non_null(ctx, malloc(size), size) : NULL;
+}
+
+/* Call calloc and complain if it fails.
+ * If ctx is NULL, then return NULL.
+ */
+void *isl_calloc_or_die(isl_ctx *ctx, size_t nmemb, size_t size)
+{
+	if (isl_ctx_next_operation(ctx) < 0)
+		return NULL;
+	return ctx ? check_non_null(ctx, calloc(nmemb, size), nmemb) : NULL;
+}
+
+/* Call realloc and complain if it fails.
+ * If ctx is NULL, then return NULL.
+ */
+void *isl_realloc_or_die(isl_ctx *ctx, void *ptr, size_t size)
+{
+	if (isl_ctx_next_operation(ctx) < 0)
+		return NULL;
+	return ctx ? check_non_null(ctx, realloc(ptr, size), size) : NULL;
+}
+
+void isl_handle_error(isl_ctx *ctx, enum isl_error error, const char *msg,
+	const char *file, int line)
+{
+	if (!ctx)
+		return;
+
+	isl_ctx_set_error(ctx, error);
+
+	switch (ctx->opt->on_error) {
+	case ISL_ON_ERROR_WARN:
+		fprintf(stderr, "%s:%d: %s\n", file, line, msg);
+		return;
+	case ISL_ON_ERROR_CONTINUE:
+		return;
+	case ISL_ON_ERROR_ABORT:
+		fprintf(stderr, "%s:%d: %s\n", file, line, msg);
+		abort();
+		return;
+	}
+}
+
+static struct isl_options *find_nested_options(struct isl_args *args,
+	void *opt, struct isl_args *wanted)
+{
+	int i;
+	struct isl_options *options;
+
+	if (args == wanted)
+		return opt;
+
+	for (i = 0; args->args[i].type != isl_arg_end; ++i) {
+		struct isl_arg *arg = &args->args[i];
+		void *child;
+
+		if (arg->type != isl_arg_child)
+			continue;
+
+		if (arg->offset == (size_t) -1)
+			child = opt;
+		else
+			child = *(void **)(((char *)opt) + arg->offset);
+
+		options = find_nested_options(arg->u.child.child,
+						child, wanted);
+		if (options)
+			return options;
+	}
+
+	return NULL;
+}
+
+static struct isl_options *find_nested_isl_options(struct isl_args *args,
+	void *opt)
+{
+	return find_nested_options(args, opt, &isl_options_args);
+}
+
+void *isl_ctx_peek_options(isl_ctx *ctx, struct isl_args *args)
+{
+	if (!ctx)
+		return NULL;
+	if (args == &isl_options_args)
+		return ctx->opt;
+	return find_nested_options(ctx->user_args, ctx->user_opt, args);
+}
+
+isl_ctx *isl_ctx_alloc_with_options(struct isl_args *args, void *user_opt)
+{
+	struct isl_ctx *ctx = NULL;
+	struct isl_options *opt = NULL;
+	int opt_allocated = 0;
+
+	if (!user_opt)
+		return NULL;
+
+	opt = find_nested_isl_options(args, user_opt);
+	if (!opt) {
+		opt = isl_options_new_with_defaults();
+		if (!opt)
+			goto error;
+		opt_allocated = 1;
+	}
+
+	ctx = __isl_calloc_type(struct isl_ctx);
+	if (!ctx)
+		goto error;
+
+	if (isl_hash_table_init(ctx, &ctx->id_table, 0))
+		goto error;
+
+	ctx->stats = isl_calloc_type(ctx, struct isl_stats);
+	if (!ctx->stats)
+		goto error;
+
+	ctx->user_args = args;
+	ctx->user_opt = user_opt;
+	ctx->opt_allocated = opt_allocated;
+	ctx->opt = opt;
+	ctx->ref = 0;
+
+	isl_int_init(ctx->zero);
+	isl_int_set_si(ctx->zero, 0);
+
+	isl_int_init(ctx->one);
+	isl_int_set_si(ctx->one, 1);
+
+	isl_int_init(ctx->two);
+	isl_int_set_si(ctx->two, 2);
+
+	isl_int_init(ctx->negone);
+	isl_int_set_si(ctx->negone, -1);
+
+	isl_int_init(ctx->normalize_gcd);
+
+	ctx->n_cached = 0;
+	ctx->n_miss = 0;
+
+	ctx->error = isl_error_none;
+
+	ctx->operations = 0;
+	isl_ctx_set_max_operations(ctx, ctx->opt->max_operations);
+
+	return ctx;
+error:
+	isl_args_free(args, user_opt);
+	if (opt_allocated)
+		isl_options_free(opt);
+	free(ctx);
+	return NULL;
+}
+
+struct isl_ctx *isl_ctx_alloc()
+{
+	struct isl_options *opt;
+
+	opt = isl_options_new_with_defaults();
+
+	return isl_ctx_alloc_with_options(&isl_options_args, opt);
+}
+
+void isl_ctx_ref(struct isl_ctx *ctx)
+{
+	ctx->ref++;
+}
+
+void isl_ctx_deref(struct isl_ctx *ctx)
+{
+	isl_assert(ctx, ctx->ref > 0, return);
+	ctx->ref--;
+}
+
+/* Print statistics on usage.
+ */
+static void print_stats(isl_ctx *ctx)
+{
+	fprintf(stderr, "operations: %lu\n", ctx->operations);
+}
+
+void isl_ctx_free(struct isl_ctx *ctx)
+{
+	if (!ctx)
+		return;
+	if (ctx->ref != 0)
+		isl_die(ctx, isl_error_invalid,
+			"isl_ctx freed, but some objects still reference it",
+			return);
+
+	if (ctx->opt->print_stats)
+		print_stats(ctx);
+
+	isl_hash_table_clear(&ctx->id_table);
+	isl_blk_clear_cache(ctx);
+	isl_int_clear(ctx->zero);
+	isl_int_clear(ctx->one);
+	isl_int_clear(ctx->two);
+	isl_int_clear(ctx->negone);
+	isl_int_clear(ctx->normalize_gcd);
+	isl_args_free(ctx->user_args, ctx->user_opt);
+	if (ctx->opt_allocated)
+		isl_options_free(ctx->opt);
+	free(ctx->stats);
+	free(ctx);
+}
+
+struct isl_options *isl_ctx_options(isl_ctx *ctx)
+{
+	if (!ctx)
+		return NULL;
+	return ctx->opt;
+}
+
+enum isl_error isl_ctx_last_error(isl_ctx *ctx)
+{
+	return ctx->error;
+}
+
+void isl_ctx_reset_error(isl_ctx *ctx)
+{
+	ctx->error = isl_error_none;
+}
+
+void isl_ctx_set_error(isl_ctx *ctx, enum isl_error error)
+{
+	if (ctx)
+		ctx->error = error;
+}
+
+void isl_ctx_abort(isl_ctx *ctx)
+{
+	if (ctx)
+		ctx->abort = 1;
+}
+
+void isl_ctx_resume(isl_ctx *ctx)
+{
+	if (ctx)
+		ctx->abort = 0;
+}
+
+int isl_ctx_aborted(isl_ctx *ctx)
+{
+	return ctx ? ctx->abort : -1;
+}
+
+int isl_ctx_parse_options(isl_ctx *ctx, int argc, char **argv, unsigned flags)
+{
+	if (!ctx)
+		return -1;
+	return isl_args_parse(ctx->user_args, argc, argv, ctx->user_opt, flags);
+}
+
+/* Set the maximal number of iterations of "ctx" to "max_operations".
+ */
+void isl_ctx_set_max_operations(isl_ctx *ctx, unsigned long max_operations)
+{
+	if (!ctx)
+		return;
+	ctx->max_operations = max_operations;
+}
+
+/* Return the maximal number of iterations of "ctx".
+ */
+unsigned long isl_ctx_get_max_operations(isl_ctx *ctx)
+{
+	return ctx ? ctx->max_operations : 0;
+}
+
+/* Reset the number of operations performed by "ctx".
+ */
+void isl_ctx_reset_operations(isl_ctx *ctx)
+{
+	if (!ctx)
+		return;
+	ctx->operations = 0;
+}
diff --git a/final/lib/External/isl/isl_ctx_private.h b/final/lib/External/isl/isl_ctx_private.h
new file mode 100644
index 0000000..b4bb2a5
--- /dev/null
+++ b/final/lib/External/isl/isl_ctx_private.h
@@ -0,0 +1,34 @@
+#include <isl/ctx.h>
+#include <isl_blk.h>
+
+struct isl_ctx {
+	int			ref;
+
+	struct isl_stats	*stats;
+
+	int			 opt_allocated;
+	struct isl_options	*opt;
+	void			*user_opt;
+	struct isl_args		*user_args;
+
+	isl_int			zero;
+	isl_int			one;
+	isl_int			two;
+	isl_int			negone;
+
+	isl_int			normalize_gcd;
+
+	int			n_cached;
+	int			n_miss;
+	struct isl_blk		cache[ISL_BLK_CACHE_SIZE];
+	struct isl_hash_table	id_table;
+
+	enum isl_error		error;
+
+	int			abort;
+
+	unsigned long		operations;
+	unsigned long		max_operations;
+};
+
+int isl_ctx_next_operation(isl_ctx *ctx);
diff --git a/final/lib/External/isl/isl_deprecated.c b/final/lib/External/isl/isl_deprecated.c
new file mode 100644
index 0000000..6c21f7d
--- /dev/null
+++ b/final/lib/External/isl/isl_deprecated.c
@@ -0,0 +1,25 @@
+#include <isl/constraint.h>
+#include <isl/set.h>
+
+/* This function was never documented and has been replaced by
+ * isl_basic_set_add_dims.
+ */
+__isl_give isl_basic_set *isl_basic_set_add(__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned n)
+{
+	return isl_basic_set_add_dims(bset, type, n);
+}
+
+/* This function was replaced by isl_constraint_alloc_equality.
+ */
+__isl_give isl_constraint *isl_equality_alloc(__isl_take isl_local_space *ls)
+{
+	return isl_constraint_alloc_equality(ls);
+}
+
+/* This function was replaced by isl_constraint_alloc_inequality.
+ */
+__isl_give isl_constraint *isl_inequality_alloc(__isl_take isl_local_space *ls)
+{
+	return isl_constraint_alloc_inequality(ls);
+}
diff --git a/final/lib/External/isl/isl_dim_map.c b/final/lib/External/isl/isl_dim_map.c
new file mode 100644
index 0000000..cc104c6
--- /dev/null
+++ b/final/lib/External/isl/isl_dim_map.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010-2011 INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ */
+
+#include <isl_map_private.h>
+#include <isl_space_private.h>
+#include <isl_dim_map.h>
+#include <isl_reordering.h>
+
+struct isl_dim_map_entry {
+	int pos;
+	int sgn;
+};
+
+/* Maps dst positions to src positions */
+struct isl_dim_map {
+	unsigned len;
+	struct isl_dim_map_entry m[1];
+};
+
+__isl_give isl_dim_map *isl_dim_map_alloc(isl_ctx *ctx, unsigned len)
+{
+	int i;
+	struct isl_dim_map *dim_map;
+	dim_map = isl_alloc(ctx, struct isl_dim_map,
+	    sizeof(struct isl_dim_map) + len * sizeof(struct isl_dim_map_entry));
+	if (!dim_map)
+		return NULL;
+	dim_map->len = 1 + len;
+	dim_map->m[0].pos = 0;
+	dim_map->m[0].sgn = 1;
+	for (i = 0; i < len; ++i)
+		dim_map->m[1 + i].sgn = 0;
+	return dim_map;
+}
+
+void isl_dim_map_range(__isl_keep isl_dim_map *dim_map,
+	unsigned dst_pos, int dst_stride, unsigned src_pos, int src_stride,
+	unsigned n, int sign)
+{
+	int i;
+
+	if (!dim_map)
+		return;
+
+	for (i = 0; i < n; ++i) {
+		unsigned d = 1 + dst_pos + dst_stride * i;
+		unsigned s = 1 + src_pos + src_stride * i;
+		dim_map->m[d].pos = s;
+		dim_map->m[d].sgn = sign;
+	}
+}
+
+void isl_dim_map_dim_range(__isl_keep isl_dim_map *dim_map,
+	__isl_keep isl_space *dim, enum isl_dim_type type,
+	unsigned first, unsigned n, unsigned dst_pos)
+{
+	int i;
+	unsigned src_pos;
+
+	if (!dim_map || !dim)
+		return;
+	
+	src_pos = 1 + isl_space_offset(dim, type);
+	for (i = 0; i < n; ++i) {
+		dim_map->m[1 + dst_pos + i].pos = src_pos + first + i;
+		dim_map->m[1 + dst_pos + i].sgn = 1;
+	}
+}
+
+void isl_dim_map_dim(__isl_keep isl_dim_map *dim_map, __isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned dst_pos)
+{
+	isl_dim_map_dim_range(dim_map, dim, type,
+			      0, isl_space_dim(dim, type), dst_pos);
+}
+
+void isl_dim_map_div(__isl_keep isl_dim_map *dim_map,
+	__isl_keep isl_basic_map *bmap, unsigned dst_pos)
+{
+	int i;
+	unsigned src_pos;
+
+	if (!dim_map || !bmap)
+		return;
+	
+	src_pos = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+	for (i = 0; i < bmap->n_div; ++i) {
+		dim_map->m[1 + dst_pos + i].pos = src_pos + i;
+		dim_map->m[1 + dst_pos + i].sgn = 1;
+	}
+}
+
+void isl_dim_map_dump(struct isl_dim_map *dim_map)
+{
+	int i;
+
+	for (i = 0; i < dim_map->len; ++i)
+		fprintf(stderr, "%d -> %d * %d; ", i,
+			dim_map->m[i].sgn, dim_map->m[i].pos);
+	fprintf(stderr, "\n");
+}
+
+static void copy_constraint_dim_map(isl_int *dst, isl_int *src,
+					struct isl_dim_map *dim_map)
+{
+	int i;
+
+	for (i = 0; i < dim_map->len; ++i) {
+		if (dim_map->m[i].sgn == 0)
+			isl_int_set_si(dst[i], 0);
+		else if (dim_map->m[i].sgn > 0)
+			isl_int_set(dst[i], src[dim_map->m[i].pos]);
+		else
+			isl_int_neg(dst[i], src[dim_map->m[i].pos]);
+	}
+}
+
+static void copy_div_dim_map(isl_int *dst, isl_int *src,
+					struct isl_dim_map *dim_map)
+{
+	isl_int_set(dst[0], src[0]);
+	copy_constraint_dim_map(dst+1, src+1, dim_map);
+}
+
+__isl_give isl_basic_map *isl_basic_map_add_constraints_dim_map(
+	__isl_take isl_basic_map *dst, __isl_take isl_basic_map *src,
+	__isl_take isl_dim_map *dim_map)
+{
+	int i;
+
+	if (!src || !dst || !dim_map)
+		goto error;
+
+	for (i = 0; i < src->n_eq; ++i) {
+		int i1 = isl_basic_map_alloc_equality(dst);
+		if (i1 < 0)
+			goto error;
+		copy_constraint_dim_map(dst->eq[i1], src->eq[i], dim_map);
+	}
+
+	for (i = 0; i < src->n_ineq; ++i) {
+		int i1 = isl_basic_map_alloc_inequality(dst);
+		if (i1 < 0)
+			goto error;
+		copy_constraint_dim_map(dst->ineq[i1], src->ineq[i], dim_map);
+	}
+
+	for (i = 0; i < src->n_div; ++i) {
+		int i1 = isl_basic_map_alloc_div(dst);
+		if (i1 < 0)
+			goto error;
+		copy_div_dim_map(dst->div[i1], src->div[i], dim_map);
+	}
+
+	free(dim_map);
+	isl_basic_map_free(src);
+
+	return dst;
+error:
+	free(dim_map);
+	isl_basic_map_free(src);
+	isl_basic_map_free(dst);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_constraints_dim_map(
+	__isl_take isl_basic_set *dst, __isl_take isl_basic_set *src,
+	__isl_take isl_dim_map *dim_map)
+{
+	return isl_basic_map_add_constraints_dim_map(dst, src, dim_map);
+}
+
+/* Extend the given dim_map with mappings for the divs in bmap.
+ */
+__isl_give isl_dim_map *isl_dim_map_extend(__isl_keep isl_dim_map *dim_map,
+	__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	struct isl_dim_map *res;
+	int offset;
+
+	if (!dim_map)
+		return NULL;
+
+	offset = isl_basic_map_offset(bmap, isl_dim_div);
+
+	res = isl_dim_map_alloc(bmap->ctx, dim_map->len - 1 + bmap->n_div);
+	if (!res)
+		return NULL;
+
+	for (i = 0; i < dim_map->len; ++i)
+		res->m[i] = dim_map->m[i];
+	for (i = 0; i < bmap->n_div; ++i) {
+		res->m[dim_map->len + i].pos = offset + i;
+		res->m[dim_map->len + i].sgn = 1;
+	}
+
+	return res;
+}
+
+/* Extract a dim_map from a reordering.
+ * We essentially need to reverse the mapping, and add an offset
+ * of 1 for the constant term.
+ */
+__isl_give isl_dim_map *isl_dim_map_from_reordering(
+	__isl_keep isl_reordering *exp)
+{
+	int i;
+	isl_ctx *ctx;
+	struct isl_dim_map *dim_map;
+
+	if (!exp)
+		return NULL;
+
+	ctx = isl_space_get_ctx(exp->dim);
+	dim_map = isl_dim_map_alloc(ctx, isl_space_dim(exp->dim, isl_dim_all));
+	if (!dim_map)
+		return NULL;
+
+	for (i = 0; i < exp->len; ++i) {
+		dim_map->m[1 + exp->pos[i]].pos = 1 + i;
+		dim_map->m[1 + exp->pos[i]].sgn = 1;
+	}
+
+	return dim_map;
+}
diff --git a/final/lib/External/isl/isl_dim_map.h b/final/lib/External/isl/isl_dim_map.h
new file mode 100644
index 0000000..0c39b49
--- /dev/null
+++ b/final/lib/External/isl/isl_dim_map.h
@@ -0,0 +1,36 @@
+#ifndef ISL_DIM_MAP_H
+#define ISL_DIM_MAP_H
+
+#include <isl/ctx.h>
+#include <isl/space.h>
+#include <isl/map.h>
+#include <isl_reordering.h>
+
+struct isl_dim_map;
+typedef struct isl_dim_map isl_dim_map;
+
+__isl_give isl_dim_map *isl_dim_map_alloc(isl_ctx *ctx, unsigned len);
+void isl_dim_map_range(__isl_keep isl_dim_map *dim_map,
+	unsigned dst_pos, int dst_stride, unsigned src_pos, int src_stride,
+	unsigned n, int sign);
+void isl_dim_map_dim_range(__isl_keep isl_dim_map *dim_map,
+	isl_space *dim, enum isl_dim_type type,
+	unsigned first, unsigned n, unsigned dst_pos);
+void isl_dim_map_dim(__isl_keep isl_dim_map *dim_map, __isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned dst_pos);
+void isl_dim_map_div(__isl_keep isl_dim_map *dim_map,
+	__isl_keep isl_basic_map *bmap, unsigned dst_pos);
+__isl_give isl_basic_set *isl_basic_set_add_constraints_dim_map(
+	__isl_take isl_basic_set *dst, __isl_take isl_basic_set *src,
+	__isl_take isl_dim_map *dim_map);
+__isl_give isl_basic_map *isl_basic_map_add_constraints_dim_map(
+	__isl_take isl_basic_map *dst, __isl_take isl_basic_map *src,
+	__isl_take isl_dim_map *dim_map);
+
+__isl_give isl_dim_map *isl_dim_map_extend(__isl_keep isl_dim_map *dim_map,
+	__isl_keep isl_basic_map *bmap);
+
+__isl_give isl_dim_map *isl_dim_map_from_reordering(
+	__isl_keep isl_reordering *exp);
+
+#endif
diff --git a/final/lib/External/isl/isl_equalities.c b/final/lib/External/isl/isl_equalities.c
new file mode 100644
index 0000000..0501cd9
--- /dev/null
+++ b/final/lib/External/isl/isl_equalities.c
@@ -0,0 +1,896 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ */
+
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl_seq.h>
+#include "isl_map_private.h"
+#include "isl_equalities.h"
+#include <isl_val_private.h>
+
+/* Given a set of modulo constraints
+ *
+ *		c + A y = 0 mod d
+ *
+ * this function computes a particular solution y_0
+ *
+ * The input is given as a matrix B = [ c A ] and a vector d.
+ *
+ * The output is matrix containing the solution y_0 or
+ * a zero-column matrix if the constraints admit no integer solution.
+ *
+ * The given set of constrains is equivalent to
+ *
+ *		c + A y = -D x
+ *
+ * with D = diag d and x a fresh set of variables.
+ * Reducing both c and A modulo d does not change the
+ * value of y in the solution and may lead to smaller coefficients.
+ * Let M = [ D A ] and [ H 0 ] = M U, the Hermite normal form of M.
+ * Then
+ *		  [ x ]
+ *		M [ y ] = - c
+ * and so
+ *		               [ x ]
+ *		[ H 0 ] U^{-1} [ y ] = - c
+ * Let
+ *		[ A ]          [ x ]
+ *		[ B ] = U^{-1} [ y ]
+ * then
+ *		H A + 0 B = -c
+ *
+ * so B may be chosen arbitrarily, e.g., B = 0, and then
+ *
+ *		       [ x ] = [ -c ]
+ *		U^{-1} [ y ] = [  0 ]
+ * or
+ *		[ x ]     [ -c ]
+ *		[ y ] = U [  0 ]
+ * specifically,
+ *
+ *		y = U_{2,1} (-c)
+ *
+ * If any of the coordinates of this y are non-integer
+ * then the constraints admit no integer solution and
+ * a zero-column matrix is returned.
+ */
+static struct isl_mat *particular_solution(struct isl_mat *B, struct isl_vec *d)
+{
+	int i, j;
+	struct isl_mat *M = NULL;
+	struct isl_mat *C = NULL;
+	struct isl_mat *U = NULL;
+	struct isl_mat *H = NULL;
+	struct isl_mat *cst = NULL;
+	struct isl_mat *T = NULL;
+
+	M = isl_mat_alloc(B->ctx, B->n_row, B->n_row + B->n_col - 1);
+	C = isl_mat_alloc(B->ctx, 1 + B->n_row, 1);
+	if (!M || !C)
+		goto error;
+	isl_int_set_si(C->row[0][0], 1);
+	for (i = 0; i < B->n_row; ++i) {
+		isl_seq_clr(M->row[i], B->n_row);
+		isl_int_set(M->row[i][i], d->block.data[i]);
+		isl_int_neg(C->row[1 + i][0], B->row[i][0]);
+		isl_int_fdiv_r(C->row[1+i][0], C->row[1+i][0], M->row[i][i]);
+		for (j = 0; j < B->n_col - 1; ++j)
+			isl_int_fdiv_r(M->row[i][B->n_row + j],
+					B->row[i][1 + j], M->row[i][i]);
+	}
+	M = isl_mat_left_hermite(M, 0, &U, NULL);
+	if (!M || !U)
+		goto error;
+	H = isl_mat_sub_alloc(M, 0, B->n_row, 0, B->n_row);
+	H = isl_mat_lin_to_aff(H);
+	C = isl_mat_inverse_product(H, C);
+	if (!C)
+		goto error;
+	for (i = 0; i < B->n_row; ++i) {
+		if (!isl_int_is_divisible_by(C->row[1+i][0], C->row[0][0]))
+			break;
+		isl_int_divexact(C->row[1+i][0], C->row[1+i][0], C->row[0][0]);
+	}
+	if (i < B->n_row)
+		cst = isl_mat_alloc(B->ctx, B->n_row, 0);
+	else
+		cst = isl_mat_sub_alloc(C, 1, B->n_row, 0, 1);
+	T = isl_mat_sub_alloc(U, B->n_row, B->n_col - 1, 0, B->n_row);
+	cst = isl_mat_product(T, cst);
+	isl_mat_free(M);
+	isl_mat_free(C);
+	isl_mat_free(U);
+	return cst;
+error:
+	isl_mat_free(M);
+	isl_mat_free(C);
+	isl_mat_free(U);
+	return NULL;
+}
+
+/* Compute and return the matrix
+ *
+ *		U_1^{-1} diag(d_1, 1, ..., 1)
+ *
+ * with U_1 the unimodular completion of the first (and only) row of B.
+ * The columns of this matrix generate the lattice that satisfies
+ * the single (linear) modulo constraint.
+ */
+static struct isl_mat *parameter_compression_1(
+			struct isl_mat *B, struct isl_vec *d)
+{
+	struct isl_mat *U;
+
+	U = isl_mat_alloc(B->ctx, B->n_col - 1, B->n_col - 1);
+	if (!U)
+		return NULL;
+	isl_seq_cpy(U->row[0], B->row[0] + 1, B->n_col - 1);
+	U = isl_mat_unimodular_complete(U, 1);
+	U = isl_mat_right_inverse(U);
+	if (!U)
+		return NULL;
+	isl_mat_col_mul(U, 0, d->block.data[0], 0);
+	U = isl_mat_lin_to_aff(U);
+	return U;
+}
+
+/* Compute a common lattice of solutions to the linear modulo
+ * constraints specified by B and d.
+ * See also the documentation of isl_mat_parameter_compression.
+ * We put the matrix
+ * 
+ *		A = [ L_1^{-T} L_2^{-T} ... L_k^{-T} ]
+ *
+ * on a common denominator.  This denominator D is the lcm of modulos d.
+ * Since L_i = U_i^{-1} diag(d_i, 1, ... 1), we have
+ * L_i^{-T} = U_i^T diag(d_i, 1, ... 1)^{-T} = U_i^T diag(1/d_i, 1, ..., 1).
+ * Putting this on the common denominator, we have
+ * D * L_i^{-T} = U_i^T diag(D/d_i, D, ..., D).
+ */
+static struct isl_mat *parameter_compression_multi(
+			struct isl_mat *B, struct isl_vec *d)
+{
+	int i, j, k;
+	isl_int D;
+	struct isl_mat *A = NULL, *U = NULL;
+	struct isl_mat *T;
+	unsigned size;
+
+	isl_int_init(D);
+
+	isl_vec_lcm(d, &D);
+
+	size = B->n_col - 1;
+	A = isl_mat_alloc(B->ctx, size, B->n_row * size);
+	U = isl_mat_alloc(B->ctx, size, size);
+	if (!U || !A)
+		goto error;
+	for (i = 0; i < B->n_row; ++i) {
+		isl_seq_cpy(U->row[0], B->row[i] + 1, size);
+		U = isl_mat_unimodular_complete(U, 1);
+		if (!U)
+			goto error;
+		isl_int_divexact(D, D, d->block.data[i]);
+		for (k = 0; k < U->n_col; ++k)
+			isl_int_mul(A->row[k][i*size+0], D, U->row[0][k]);
+		isl_int_mul(D, D, d->block.data[i]);
+		for (j = 1; j < U->n_row; ++j)
+			for (k = 0; k < U->n_col; ++k)
+				isl_int_mul(A->row[k][i*size+j],
+						D, U->row[j][k]);
+	}
+	A = isl_mat_left_hermite(A, 0, NULL, NULL);
+	T = isl_mat_sub_alloc(A, 0, A->n_row, 0, A->n_row);
+	T = isl_mat_lin_to_aff(T);
+	if (!T)
+		goto error;
+	isl_int_set(T->row[0][0], D);
+	T = isl_mat_right_inverse(T);
+	if (!T)
+		goto error;
+	isl_assert(T->ctx, isl_int_is_one(T->row[0][0]), goto error);
+	T = isl_mat_transpose(T);
+	isl_mat_free(A);
+	isl_mat_free(U);
+
+	isl_int_clear(D);
+	return T;
+error:
+	isl_mat_free(A);
+	isl_mat_free(U);
+	isl_int_clear(D);
+	return NULL;
+}
+
+/* Given a set of modulo constraints
+ *
+ *		c + A y = 0 mod d
+ *
+ * this function returns an affine transformation T,
+ *
+ *		y = T y'
+ *
+ * that bijectively maps the integer vectors y' to integer
+ * vectors y that satisfy the modulo constraints.
+ *
+ * This function is inspired by Section 2.5.3
+ * of B. Meister, "Stating and Manipulating Periodicity in the Polytope
+ * Model.  Applications to Program Analysis and Optimization".
+ * However, the implementation only follows the algorithm of that
+ * section for computing a particular solution and not for computing
+ * a general homogeneous solution.  The latter is incomplete and
+ * may remove some valid solutions.
+ * Instead, we use an adaptation of the algorithm in Section 7 of
+ * B. Meister, S. Verdoolaege, "Polynomial Approximations in the Polytope
+ * Model: Bringing the Power of Quasi-Polynomials to the Masses".
+ *
+ * The input is given as a matrix B = [ c A ] and a vector d.
+ * Each element of the vector d corresponds to a row in B.
+ * The output is a lower triangular matrix.
+ * If no integer vector y satisfies the given constraints then
+ * a matrix with zero columns is returned.
+ *
+ * We first compute a particular solution y_0 to the given set of
+ * modulo constraints in particular_solution.  If no such solution
+ * exists, then we return a zero-columned transformation matrix.
+ * Otherwise, we compute the generic solution to
+ *
+ *		A y = 0 mod d
+ *
+ * That is we want to compute G such that
+ *
+ *		y = G y''
+ *
+ * with y'' integer, describes the set of solutions.
+ *
+ * We first remove the common factors of each row.
+ * In particular if gcd(A_i,d_i) != 1, then we divide the whole
+ * row i (including d_i) by this common factor.  If afterwards gcd(A_i) != 1,
+ * then we divide this row of A by the common factor, unless gcd(A_i) = 0.
+ * In the later case, we simply drop the row (in both A and d).
+ *
+ * If there are no rows left in A, then G is the identity matrix. Otherwise,
+ * for each row i, we now determine the lattice of integer vectors
+ * that satisfies this row.  Let U_i be the unimodular extension of the
+ * row A_i.  This unimodular extension exists because gcd(A_i) = 1.
+ * The first component of
+ *
+ *		y' = U_i y
+ *
+ * needs to be a multiple of d_i.  Let y' = diag(d_i, 1, ..., 1) y''.
+ * Then,
+ *
+ *		y = U_i^{-1} diag(d_i, 1, ..., 1) y''
+ *
+ * for arbitrary integer vectors y''.  That is, y belongs to the lattice
+ * generated by the columns of L_i = U_i^{-1} diag(d_i, 1, ..., 1).
+ * If there is only one row, then G = L_1.
+ *
+ * If there is more than one row left, we need to compute the intersection
+ * of the lattices.  That is, we need to compute an L such that
+ *
+ *		L = L_i L_i'	for all i
+ *
+ * with L_i' some integer matrices.  Let A be constructed as follows
+ *
+ *		A = [ L_1^{-T} L_2^{-T} ... L_k^{-T} ]
+ *
+ * and computed the Hermite Normal Form of A = [ H 0 ] U
+ * Then,
+ *
+ *		L_i^{-T} = H U_{1,i}
+ *
+ * or
+ *
+ *		H^{-T} = L_i U_{1,i}^T
+ *
+ * In other words G = L = H^{-T}.
+ * To ensure that G is lower triangular, we compute and use its Hermite
+ * normal form.
+ *
+ * The affine transformation matrix returned is then
+ *
+ *		[  1   0  ]
+ *		[ y_0  G  ]
+ *
+ * as any y = y_0 + G y' with y' integer is a solution to the original
+ * modulo constraints.
+ */
+__isl_give isl_mat *isl_mat_parameter_compression(__isl_take isl_mat *B,
+	__isl_take isl_vec *d)
+{
+	int i;
+	struct isl_mat *cst = NULL;
+	struct isl_mat *T = NULL;
+	isl_int D;
+
+	if (!B || !d)
+		goto error;
+	isl_assert(B->ctx, B->n_row == d->size, goto error);
+	cst = particular_solution(B, d);
+	if (!cst)
+		goto error;
+	if (cst->n_col == 0) {
+		T = isl_mat_alloc(B->ctx, B->n_col, 0);
+		isl_mat_free(cst);
+		isl_mat_free(B);
+		isl_vec_free(d);
+		return T;
+	}
+	isl_int_init(D);
+	/* Replace a*g*row = 0 mod g*m by row = 0 mod m */
+	for (i = 0; i < B->n_row; ++i) {
+		isl_seq_gcd(B->row[i] + 1, B->n_col - 1, &D);
+		if (isl_int_is_one(D))
+			continue;
+		if (isl_int_is_zero(D)) {
+			B = isl_mat_drop_rows(B, i, 1);
+			d = isl_vec_cow(d);
+			if (!B || !d)
+				goto error2;
+			isl_seq_cpy(d->block.data+i, d->block.data+i+1,
+							d->size - (i+1));
+			d->size--;
+			i--;
+			continue;
+		}
+		B = isl_mat_cow(B);
+		if (!B)
+			goto error2;
+		isl_seq_scale_down(B->row[i] + 1, B->row[i] + 1, D, B->n_col-1);
+		isl_int_gcd(D, D, d->block.data[i]);
+		d = isl_vec_cow(d);
+		if (!d)
+			goto error2;
+		isl_int_divexact(d->block.data[i], d->block.data[i], D);
+	}
+	isl_int_clear(D);
+	if (B->n_row == 0)
+		T = isl_mat_identity(B->ctx, B->n_col);
+	else if (B->n_row == 1)
+		T = parameter_compression_1(B, d);
+	else
+		T = parameter_compression_multi(B, d);
+	T = isl_mat_left_hermite(T, 0, NULL, NULL);
+	if (!T)
+		goto error;
+	isl_mat_sub_copy(T->ctx, T->row + 1, cst->row, cst->n_row, 0, 0, 1);
+	isl_mat_free(cst);
+	isl_mat_free(B);
+	isl_vec_free(d);
+	return T;
+error2:
+	isl_int_clear(D);
+error:
+	isl_mat_free(cst);
+	isl_mat_free(B);
+	isl_vec_free(d);
+	return NULL;
+}
+
+/* Given a set of equalities
+ *
+ *		B(y) + A x = 0						(*)
+ *
+ * compute and return an affine transformation T,
+ *
+ *		y = T y'
+ *
+ * that bijectively maps the integer vectors y' to integer
+ * vectors y that satisfy the modulo constraints for some value of x.
+ *
+ * Let [H 0] be the Hermite Normal Form of A, i.e.,
+ *
+ *		A = [H 0] Q
+ *
+ * Then y is a solution of (*) iff
+ *
+ *		H^-1 B(y) (= - [I 0] Q x)
+ *
+ * is an integer vector.  Let d be the common denominator of H^-1.
+ * We impose
+ *
+ *		d H^-1 B(y) = 0 mod d
+ *
+ * and compute the solution using isl_mat_parameter_compression.
+ */
+__isl_give isl_mat *isl_mat_parameter_compression_ext(__isl_take isl_mat *B,
+	__isl_take isl_mat *A)
+{
+	isl_ctx *ctx;
+	isl_vec *d;
+	int n_row, n_col;
+
+	if (!A)
+		return isl_mat_free(B);
+
+	ctx = isl_mat_get_ctx(A);
+	n_row = A->n_row;
+	n_col = A->n_col;
+	A = isl_mat_left_hermite(A, 0, NULL, NULL);
+	A = isl_mat_drop_cols(A, n_row, n_col - n_row);
+	A = isl_mat_lin_to_aff(A);
+	A = isl_mat_right_inverse(A);
+	d = isl_vec_alloc(ctx, n_row);
+	if (A)
+		d = isl_vec_set(d, A->row[0][0]);
+	A = isl_mat_drop_rows(A, 0, 1);
+	A = isl_mat_drop_cols(A, 0, 1);
+	B = isl_mat_product(A, B);
+
+	return isl_mat_parameter_compression(B, d);
+}
+
+/* Return a compression matrix that indicates that there are no solutions
+ * to the original constraints.  In particular, return a zero-column
+ * matrix with 1 + dim rows.  If "T2" is not NULL, then assign *T2
+ * the inverse of this matrix.  *T2 may already have been assigned
+ * matrix, so free it first.
+ * "free1", "free2" and "free3" are temporary matrices that are
+ * not useful when an empty compression is returned.  They are
+ * simply freed.
+ */
+static __isl_give isl_mat *empty_compression(isl_ctx *ctx, unsigned dim,
+	__isl_give isl_mat **T2, __isl_take isl_mat *free1,
+	__isl_take isl_mat *free2, __isl_take isl_mat *free3)
+{
+	isl_mat_free(free1);
+	isl_mat_free(free2);
+	isl_mat_free(free3);
+	if (T2) {
+		isl_mat_free(*T2);
+		*T2 = isl_mat_alloc(ctx, 0, 1 + dim);
+	}
+	return isl_mat_alloc(ctx, 1 + dim, 0);
+}
+
+/* Given a matrix that maps a (possibly) parametric domain to
+ * a parametric domain, add in rows that map the "nparam" parameters onto
+ * themselves.
+ */
+static __isl_give isl_mat *insert_parameter_rows(__isl_take isl_mat *mat,
+	unsigned nparam)
+{
+	int i;
+
+	if (nparam == 0)
+		return mat;
+	if (!mat)
+		return NULL;
+
+	mat = isl_mat_insert_rows(mat, 1, nparam);
+	if (!mat)
+		return NULL;
+
+	for (i = 0; i < nparam; ++i) {
+		isl_seq_clr(mat->row[1 + i], mat->n_col);
+		isl_int_set(mat->row[1 + i][1 + i], mat->row[0][0]);
+	}
+
+	return mat;
+}
+
+/* Given a set of equalities
+ *
+ *		-C(y) + M x = 0
+ *
+ * this function computes a unimodular transformation from a lower-dimensional
+ * space to the original space that bijectively maps the integer points x'
+ * in the lower-dimensional space to the integer points x in the original
+ * space that satisfy the equalities.
+ *
+ * The input is given as a matrix B = [ -C M ] and the output is a
+ * matrix that maps [1 x'] to [1 x].
+ * The number of equality constraints in B is assumed to be smaller than
+ * or equal to the number of variables x.
+ * "first" is the position of the first x variable.
+ * The preceding variables are considered to be y-variables.
+ * If T2 is not NULL, then *T2 is set to a matrix mapping [1 x] to [1 x'].
+ *
+ * First compute the (left) Hermite normal form of M,
+ *
+ *		M [U1 U2] = M U = H = [H1 0]
+ * or
+ *		              M = H Q = [H1 0] [Q1]
+ *                                             [Q2]
+ *
+ * with U, Q unimodular, Q = U^{-1} (and H lower triangular).
+ * Define the transformed variables as
+ *
+ *		x = [U1 U2] [ x1' ] = [U1 U2] [Q1] x
+ *		            [ x2' ]           [Q2]
+ *
+ * The equalities then become
+ *
+ *		-C(y) + H1 x1' = 0   or   x1' = H1^{-1} C(y) = C'(y)
+ *
+ * If the denominator of the constant term does not divide the
+ * the common denominator of the coefficients of y, then every
+ * integer point is mapped to a non-integer point and then the original set
+ * has no integer solutions (since the x' are a unimodular transformation
+ * of the x).  In this case, a zero-column matrix is returned.
+ * Otherwise, the transformation is given by
+ *
+ *		x = U1 H1^{-1} C(y) + U2 x2'
+ *
+ * The inverse transformation is simply
+ *
+ *		x2' = Q2 x
+ */
+__isl_give isl_mat *isl_mat_final_variable_compression(__isl_take isl_mat *B,
+	int first, __isl_give isl_mat **T2)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_mat *H = NULL, *C, *H1, *U = NULL, *U1, *U2;
+	unsigned dim;
+
+	if (T2)
+		*T2 = NULL;
+	if (!B)
+		goto error;
+
+	ctx = isl_mat_get_ctx(B);
+	dim = B->n_col - 1;
+	n = dim - first;
+	if (n < B->n_row)
+		isl_die(ctx, isl_error_invalid, "too many equality constraints",
+			goto error);
+	H = isl_mat_sub_alloc(B, 0, B->n_row, 1 + first, n);
+	H = isl_mat_left_hermite(H, 0, &U, T2);
+	if (!H || !U || (T2 && !*T2))
+		goto error;
+	if (T2) {
+		*T2 = isl_mat_drop_rows(*T2, 0, B->n_row);
+		*T2 = isl_mat_diagonal(isl_mat_identity(ctx, 1 + first), *T2);
+		if (!*T2)
+			goto error;
+	}
+	C = isl_mat_alloc(ctx, 1 + B->n_row, 1 + first);
+	if (!C)
+		goto error;
+	isl_int_set_si(C->row[0][0], 1);
+	isl_seq_clr(C->row[0] + 1, first);
+	isl_mat_sub_neg(ctx, C->row + 1, B->row, B->n_row, 0, 0, 1 + first);
+	H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
+	H1 = isl_mat_lin_to_aff(H1);
+	C = isl_mat_inverse_product(H1, C);
+	if (!C)
+		goto error;
+	isl_mat_free(H);
+	if (!isl_int_is_one(C->row[0][0])) {
+		isl_int g;
+
+		isl_int_init(g);
+		for (i = 0; i < B->n_row; ++i) {
+			isl_seq_gcd(C->row[1 + i] + 1, first, &g);
+			isl_int_gcd(g, g, C->row[0][0]);
+			if (!isl_int_is_divisible_by(C->row[1 + i][0], g))
+				break;
+		}
+		isl_int_clear(g);
+
+		if (i < B->n_row)
+			return empty_compression(ctx, dim, T2, B, C, U);
+		C = isl_mat_normalize(C);
+	}
+	U1 = isl_mat_sub_alloc(U, 0, U->n_row, 0, B->n_row);
+	U1 = isl_mat_lin_to_aff(U1);
+	U2 = isl_mat_sub_alloc(U, 0, U->n_row, B->n_row, U->n_row - B->n_row);
+	U2 = isl_mat_lin_to_aff(U2);
+	isl_mat_free(U);
+	C = isl_mat_product(U1, C);
+	C = isl_mat_aff_direct_sum(C, U2);
+	C = insert_parameter_rows(C, first);
+
+	isl_mat_free(B);
+
+	return C;
+error:
+	isl_mat_free(B);
+	isl_mat_free(H);
+	isl_mat_free(U);
+	if (T2) {
+		isl_mat_free(*T2);
+		*T2 = NULL;
+	}
+	return NULL;
+}
+
+/* Given a set of equalities
+ *
+ *		M x - c = 0
+ *
+ * this function computes a unimodular transformation from a lower-dimensional
+ * space to the original space that bijectively maps the integer points x'
+ * in the lower-dimensional space to the integer points x in the original
+ * space that satisfy the equalities.
+ *
+ * The input is given as a matrix B = [ -c M ] and the output is a
+ * matrix that maps [1 x'] to [1 x].
+ * The number of equality constraints in B is assumed to be smaller than
+ * or equal to the number of variables x.
+ * If T2 is not NULL, then *T2 is set to a matrix mapping [1 x] to [1 x'].
+ */
+__isl_give isl_mat *isl_mat_variable_compression(__isl_take isl_mat *B,
+	__isl_give isl_mat **T2)
+{
+	return isl_mat_final_variable_compression(B, 0, T2);
+}
+
+/* Return "bset" and set *T and *T2 to the identity transformation
+ * on "bset" (provided T and T2 are not NULL).
+ */
+static __isl_give isl_basic_set *return_with_identity(
+	__isl_take isl_basic_set *bset, __isl_give isl_mat **T,
+	__isl_give isl_mat **T2)
+{
+	unsigned dim;
+	isl_mat *id;
+
+	if (!bset)
+		return NULL;
+	if (!T && !T2)
+		return bset;
+
+	dim = isl_basic_set_dim(bset, isl_dim_set);
+	id = isl_mat_identity(isl_basic_map_get_ctx(bset), 1 + dim);
+	if (T)
+		*T = isl_mat_copy(id);
+	if (T2)
+		*T2 = isl_mat_copy(id);
+	isl_mat_free(id);
+
+	return bset;
+}
+
+/* Use the n equalities of bset to unimodularly transform the
+ * variables x such that n transformed variables x1' have a constant value
+ * and rewrite the constraints of bset in terms of the remaining
+ * transformed variables x2'.  The matrix pointed to by T maps
+ * the new variables x2' back to the original variables x, while T2
+ * maps the original variables to the new variables.
+ */
+static struct isl_basic_set *compress_variables(
+	struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2)
+{
+	struct isl_mat *B, *TC;
+	unsigned dim;
+
+	if (T)
+		*T = NULL;
+	if (T2)
+		*T2 = NULL;
+	if (!bset)
+		goto error;
+	isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
+	isl_assert(bset->ctx, bset->n_div == 0, goto error);
+	dim = isl_basic_set_n_dim(bset);
+	isl_assert(bset->ctx, bset->n_eq <= dim, goto error);
+	if (bset->n_eq == 0)
+		return return_with_identity(bset, T, T2);
+
+	B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq, 0, 1 + dim);
+	TC = isl_mat_variable_compression(B, T2);
+	if (!TC)
+		goto error;
+	if (TC->n_col == 0) {
+		isl_mat_free(TC);
+		if (T2) {
+			isl_mat_free(*T2);
+			*T2 = NULL;
+		}
+		bset = isl_basic_set_set_to_empty(bset);
+		return return_with_identity(bset, T, T2);
+	}
+
+	bset = isl_basic_set_preimage(bset, T ? isl_mat_copy(TC) : TC);
+	if (T)
+		*T = TC;
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_remove_equalities(
+	struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2)
+{
+	if (T)
+		*T = NULL;
+	if (T2)
+		*T2 = NULL;
+	if (!bset)
+		return NULL;
+	isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0, goto error);
+	bset = isl_basic_set_gauss(bset, NULL);
+	if (ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY))
+		return return_with_identity(bset, T, T2);
+	bset = compress_variables(bset, T, T2);
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	*T = NULL;
+	return NULL;
+}
+
+/* Check if dimension dim belongs to a residue class
+ *		i_dim \equiv r mod m
+ * with m != 1 and if so return m in *modulo and r in *residue.
+ * As a special case, when i_dim has a fixed value v, then
+ * *modulo is set to 0 and *residue to v.
+ *
+ * If i_dim does not belong to such a residue class, then *modulo
+ * is set to 1 and *residue is set to 0.
+ */
+isl_stat isl_basic_set_dim_residue_class(__isl_keep isl_basic_set *bset,
+	int pos, isl_int *modulo, isl_int *residue)
+{
+	isl_bool fixed;
+	struct isl_ctx *ctx;
+	struct isl_mat *H = NULL, *U = NULL, *C, *H1, *U1;
+	unsigned total;
+	unsigned nparam;
+
+	if (!bset || !modulo || !residue)
+		return isl_stat_error;
+
+	fixed = isl_basic_set_plain_dim_is_fixed(bset, pos, residue);
+	if (fixed < 0)
+		return isl_stat_error;
+	if (fixed) {
+		isl_int_set_si(*modulo, 0);
+		return isl_stat_ok;
+	}
+
+	ctx = isl_basic_set_get_ctx(bset);
+	total = isl_basic_set_total_dim(bset);
+	nparam = isl_basic_set_n_param(bset);
+	H = isl_mat_sub_alloc6(ctx, bset->eq, 0, bset->n_eq, 1, total);
+	H = isl_mat_left_hermite(H, 0, &U, NULL);
+	if (!H)
+		return isl_stat_error;
+
+	isl_seq_gcd(U->row[nparam + pos]+bset->n_eq,
+			total-bset->n_eq, modulo);
+	if (isl_int_is_zero(*modulo))
+		isl_int_set_si(*modulo, 1);
+	if (isl_int_is_one(*modulo)) {
+		isl_int_set_si(*residue, 0);
+		isl_mat_free(H);
+		isl_mat_free(U);
+		return isl_stat_ok;
+	}
+
+	C = isl_mat_alloc(ctx, 1 + bset->n_eq, 1);
+	if (!C)
+		goto error;
+	isl_int_set_si(C->row[0][0], 1);
+	isl_mat_sub_neg(ctx, C->row + 1, bset->eq, bset->n_eq, 0, 0, 1);
+	H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
+	H1 = isl_mat_lin_to_aff(H1);
+	C = isl_mat_inverse_product(H1, C);
+	isl_mat_free(H);
+	U1 = isl_mat_sub_alloc(U, nparam+pos, 1, 0, bset->n_eq);
+	U1 = isl_mat_lin_to_aff(U1);
+	isl_mat_free(U);
+	C = isl_mat_product(U1, C);
+	if (!C)
+		return isl_stat_error;
+	if (!isl_int_is_divisible_by(C->row[1][0], C->row[0][0])) {
+		bset = isl_basic_set_copy(bset);
+		bset = isl_basic_set_set_to_empty(bset);
+		isl_basic_set_free(bset);
+		isl_int_set_si(*modulo, 1);
+		isl_int_set_si(*residue, 0);
+		return isl_stat_ok;
+	}
+	isl_int_divexact(*residue, C->row[1][0], C->row[0][0]);
+	isl_int_fdiv_r(*residue, *residue, *modulo);
+	isl_mat_free(C);
+	return isl_stat_ok;
+error:
+	isl_mat_free(H);
+	isl_mat_free(U);
+	return isl_stat_error;
+}
+
+/* Check if dimension dim belongs to a residue class
+ *		i_dim \equiv r mod m
+ * with m != 1 and if so return m in *modulo and r in *residue.
+ * As a special case, when i_dim has a fixed value v, then
+ * *modulo is set to 0 and *residue to v.
+ *
+ * If i_dim does not belong to such a residue class, then *modulo
+ * is set to 1 and *residue is set to 0.
+ */
+isl_stat isl_set_dim_residue_class(__isl_keep isl_set *set,
+	int pos, isl_int *modulo, isl_int *residue)
+{
+	isl_int m;
+	isl_int r;
+	int i;
+
+	if (!set || !modulo || !residue)
+		return isl_stat_error;
+
+	if (set->n == 0) {
+		isl_int_set_si(*modulo, 0);
+		isl_int_set_si(*residue, 0);
+		return isl_stat_ok;
+	}
+
+	if (isl_basic_set_dim_residue_class(set->p[0], pos, modulo, residue)<0)
+		return isl_stat_error;
+
+	if (set->n == 1)
+		return isl_stat_ok;
+
+	if (isl_int_is_one(*modulo))
+		return isl_stat_ok;
+
+	isl_int_init(m);
+	isl_int_init(r);
+
+	for (i = 1; i < set->n; ++i) {
+		if (isl_basic_set_dim_residue_class(set->p[i], pos, &m, &r) < 0)
+			goto error;
+		isl_int_gcd(*modulo, *modulo, m);
+		isl_int_sub(m, *residue, r);
+		isl_int_gcd(*modulo, *modulo, m);
+		if (!isl_int_is_zero(*modulo))
+			isl_int_fdiv_r(*residue, *residue, *modulo);
+		if (isl_int_is_one(*modulo))
+			break;
+	}
+
+	isl_int_clear(m);
+	isl_int_clear(r);
+
+	return isl_stat_ok;
+error:
+	isl_int_clear(m);
+	isl_int_clear(r);
+	return isl_stat_error;
+}
+
+/* Check if dimension "dim" belongs to a residue class
+ *		i_dim \equiv r mod m
+ * with m != 1 and if so return m in *modulo and r in *residue.
+ * As a special case, when i_dim has a fixed value v, then
+ * *modulo is set to 0 and *residue to v.
+ *
+ * If i_dim does not belong to such a residue class, then *modulo
+ * is set to 1 and *residue is set to 0.
+ */
+isl_stat isl_set_dim_residue_class_val(__isl_keep isl_set *set,
+	int pos, __isl_give isl_val **modulo, __isl_give isl_val **residue)
+{
+	*modulo = NULL;
+	*residue = NULL;
+	if (!set)
+		return isl_stat_error;
+	*modulo = isl_val_alloc(isl_set_get_ctx(set));
+	*residue = isl_val_alloc(isl_set_get_ctx(set));
+	if (!*modulo || !*residue)
+		goto error;
+	if (isl_set_dim_residue_class(set, pos,
+					&(*modulo)->n, &(*residue)->n) < 0)
+		goto error;
+	isl_int_set_si((*modulo)->d, 1);
+	isl_int_set_si((*residue)->d, 1);
+	return isl_stat_ok;
+error:
+	isl_val_free(*modulo);
+	isl_val_free(*residue);
+	return isl_stat_error;
+}
diff --git a/final/lib/External/isl/isl_equalities.h b/final/lib/External/isl/isl_equalities.h
new file mode 100644
index 0000000..0de8347
--- /dev/null
+++ b/final/lib/External/isl/isl_equalities.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_EQUALITIES_H
+#define ISL_EQUALITIES_H
+
+#include <isl/set.h>
+#include <isl/mat.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_mat *isl_mat_final_variable_compression(__isl_take isl_mat *B,
+	int first, __isl_give isl_mat **T2);
+__isl_give isl_mat *isl_mat_variable_compression(__isl_take isl_mat *B,
+	__isl_give isl_mat **T2);
+__isl_give isl_mat *isl_mat_parameter_compression(__isl_take isl_mat *B,
+	__isl_take isl_vec *d);
+__isl_give isl_mat *isl_mat_parameter_compression_ext(__isl_take isl_mat *B,
+	__isl_take isl_mat *A);
+struct isl_basic_set *isl_basic_set_remove_equalities(
+	struct isl_basic_set *bset, struct isl_mat **T, struct isl_mat **T2);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/isl_factorization.c b/final/lib/External/isl/isl_factorization.c
new file mode 100644
index 0000000..f692cdb
--- /dev/null
+++ b/final/lib/External/isl/isl_factorization.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2005-2007 Universiteit Leiden
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science,
+ * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands
+ * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A,
+ * B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ */
+
+#include <isl_map_private.h>
+#include <isl_factorization.h>
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+
+static __isl_give isl_factorizer *isl_factorizer_alloc(
+	__isl_take isl_morph *morph, int n_group)
+{
+	isl_factorizer *f = NULL;
+	int *len = NULL;
+
+	if (!morph)
+		return NULL;
+
+	if (n_group > 0) {
+		len = isl_alloc_array(morph->dom->ctx, int, n_group);
+		if (!len)
+			goto error;
+	}
+
+	f = isl_alloc_type(morph->dom->ctx, struct isl_factorizer);
+	if (!f)
+		goto error;
+
+	f->morph = morph;
+	f->n_group = n_group;
+	f->len = len;
+
+	return f;
+error:
+	free(len);
+	isl_morph_free(morph);
+	return NULL;
+}
+
+void isl_factorizer_free(__isl_take isl_factorizer *f)
+{
+	if (!f)
+		return;
+
+	isl_morph_free(f->morph);
+	free(f->len);
+	free(f);
+}
+
+void isl_factorizer_dump(__isl_take isl_factorizer *f)
+{
+	int i;
+
+	if (!f)
+		return;
+
+	isl_morph_print_internal(f->morph, stderr);
+	fprintf(stderr, "[");
+	for (i = 0; i < f->n_group; ++i) {
+		if (i)
+			fprintf(stderr, ", ");
+		fprintf(stderr, "%d", f->len[i]);
+	}
+	fprintf(stderr, "]\n");
+}
+
+__isl_give isl_factorizer *isl_factorizer_identity(__isl_keep isl_basic_set *bset)
+{
+	return isl_factorizer_alloc(isl_morph_identity(bset), 0);
+}
+
+__isl_give isl_factorizer *isl_factorizer_groups(__isl_keep isl_basic_set *bset,
+	__isl_take isl_mat *Q, __isl_take isl_mat *U, int n, int *len)
+{
+	int i;
+	unsigned nvar;
+	unsigned ovar;
+	isl_space *dim;
+	isl_basic_set *dom;
+	isl_basic_set *ran;
+	isl_morph *morph;
+	isl_factorizer *f;
+	isl_mat *id;
+
+	if (!bset || !Q || !U)
+		goto error;
+
+	ovar = 1 + isl_space_offset(bset->dim, isl_dim_set);
+	id = isl_mat_identity(bset->ctx, ovar);
+	Q = isl_mat_diagonal(isl_mat_copy(id), Q);
+	U = isl_mat_diagonal(id, U);
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+	dim = isl_basic_set_get_space(bset);
+	dom = isl_basic_set_universe(isl_space_copy(dim));
+	dim = isl_space_drop_dims(dim, isl_dim_set, 0, nvar);
+	dim = isl_space_add_dims(dim, isl_dim_set, nvar);
+	ran = isl_basic_set_universe(dim);
+	morph = isl_morph_alloc(dom, ran, Q, U);
+	f = isl_factorizer_alloc(morph, n);
+	if (!f)
+		return NULL;
+	for (i = 0; i < n; ++i)
+		f->len[i] = len[i];
+	return f;
+error:
+	isl_mat_free(Q);
+	isl_mat_free(U);
+	return NULL;
+}
+
+struct isl_factor_groups {
+	int *pos;		/* for each column: row position of pivot */
+	int *group;		/* group to which a column belongs */
+	int *cnt;		/* number of columns in the group */
+	int *rowgroup;		/* group to which a constraint belongs */
+};
+
+/* Initialize isl_factor_groups structure: find pivot row positions,
+ * each column initially belongs to its own group and the groups
+ * of the constraints are still unknown.
+ */
+static int init_groups(struct isl_factor_groups *g, __isl_keep isl_mat *H)
+{
+	int i, j;
+
+	if (!H)
+		return -1;
+
+	g->pos = isl_alloc_array(H->ctx, int, H->n_col);
+	g->group = isl_alloc_array(H->ctx, int, H->n_col);
+	g->cnt = isl_alloc_array(H->ctx, int, H->n_col);
+	g->rowgroup = isl_alloc_array(H->ctx, int, H->n_row);
+
+	if (!g->pos || !g->group || !g->cnt || !g->rowgroup)
+		return -1;
+
+	for (i = 0; i < H->n_row; ++i)
+		g->rowgroup[i] = -1;
+	for (i = 0, j = 0; i < H->n_col; ++i) {
+		for ( ; j < H->n_row; ++j)
+			if (!isl_int_is_zero(H->row[j][i]))
+				break;
+		g->pos[i] = j;
+	}
+	for (i = 0; i < H->n_col; ++i) {
+		g->group[i] = i;
+		g->cnt[i] = 1;
+	}
+
+	return 0;
+}
+
+/* Update group[k] to the group column k belongs to.
+ * When merging two groups, only the group of the current
+ * group leader is changed.  Here we change the group of
+ * the other members to also point to the group that the
+ * old group leader now points to.
+ */
+static void update_group(struct isl_factor_groups *g, int k)
+{
+	int p = g->group[k];
+	while (g->cnt[p] == 0)
+		p = g->group[p];
+	g->group[k] = p;
+}
+
+/* Merge group i with all groups of the subsequent columns
+ * with non-zero coefficients in row j of H.
+ * (The previous columns are all zero; otherwise we would have handled
+ * the row before.)
+ */
+static int update_group_i_with_row_j(struct isl_factor_groups *g, int i, int j,
+	__isl_keep isl_mat *H)
+{
+	int k;
+
+	g->rowgroup[j] = g->group[i];
+	for (k = i + 1; k < H->n_col && j >= g->pos[k]; ++k) {
+		update_group(g, k);
+		update_group(g, i);
+		if (g->group[k] != g->group[i] &&
+		    !isl_int_is_zero(H->row[j][k])) {
+			isl_assert(H->ctx, g->cnt[g->group[k]] != 0, return -1);
+			isl_assert(H->ctx, g->cnt[g->group[i]] != 0, return -1);
+			if (g->group[i] < g->group[k]) {
+				g->cnt[g->group[i]] += g->cnt[g->group[k]];
+				g->cnt[g->group[k]] = 0;
+				g->group[g->group[k]] = g->group[i];
+			} else {
+				g->cnt[g->group[k]] += g->cnt[g->group[i]];
+				g->cnt[g->group[i]] = 0;
+				g->group[g->group[i]] = g->group[k];
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* Update the group information based on the constraint matrix.
+ */
+static int update_groups(struct isl_factor_groups *g, __isl_keep isl_mat *H)
+{
+	int i, j;
+
+	for (i = 0; i < H->n_col && g->cnt[0] < H->n_col; ++i) {
+		if (g->pos[i] == H->n_row)
+			continue; /* A line direction */
+		if (g->rowgroup[g->pos[i]] == -1)
+			g->rowgroup[g->pos[i]] = i;
+		for (j = g->pos[i] + 1; j < H->n_row; ++j) {
+			if (isl_int_is_zero(H->row[j][i]))
+				continue;
+			if (g->rowgroup[j] != -1)
+				continue;
+			if (update_group_i_with_row_j(g, i, j, H) < 0)
+				return -1;
+		}
+	}
+	for (i = 1; i < H->n_col; ++i)
+		update_group(g, i);
+
+	return 0;
+}
+
+static void clear_groups(struct isl_factor_groups *g)
+{
+	if (!g)
+		return;
+	free(g->pos);
+	free(g->group);
+	free(g->cnt);
+	free(g->rowgroup);
+}
+
+/* Determine if the set variables of the basic set can be factorized and
+ * return the results in an isl_factorizer.
+ *
+ * The algorithm works by first computing the Hermite normal form
+ * and then grouping columns linked by one or more constraints together,
+ * where a constraints "links" two or more columns if the constraint
+ * has nonzero coefficients in the columns.
+ */
+__isl_give isl_factorizer *isl_basic_set_factorizer(
+	__isl_keep isl_basic_set *bset)
+{
+	int i, j, n, done;
+	isl_mat *H, *U, *Q;
+	unsigned nvar;
+	struct isl_factor_groups g = { 0 };
+	isl_factorizer *f;
+
+	if (!bset)
+		return NULL;
+
+	isl_assert(bset->ctx, isl_basic_set_dim(bset, isl_dim_div) == 0,
+		return NULL);
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+	if (nvar <= 1)
+		return isl_factorizer_identity(bset);
+
+	H = isl_mat_alloc(bset->ctx, bset->n_eq + bset->n_ineq, nvar);
+	if (!H)
+		return NULL;
+	isl_mat_sub_copy(bset->ctx, H->row, bset->eq, bset->n_eq,
+		0, 1 + isl_space_offset(bset->dim, isl_dim_set), nvar);
+	isl_mat_sub_copy(bset->ctx, H->row + bset->n_eq, bset->ineq, bset->n_ineq,
+		0, 1 + isl_space_offset(bset->dim, isl_dim_set), nvar);
+	H = isl_mat_left_hermite(H, 0, &U, &Q);
+
+	if (init_groups(&g, H) < 0)
+		goto error;
+	if (update_groups(&g, H) < 0)
+		goto error;
+
+	if (g.cnt[0] == nvar) {
+		isl_mat_free(H);
+		isl_mat_free(U);
+		isl_mat_free(Q);
+		clear_groups(&g);
+
+		return isl_factorizer_identity(bset);
+	}
+
+	done = 0;
+	n = 0;
+	while (done != nvar) {
+		int group = g.group[done];
+		for (i = 1; i < g.cnt[group]; ++i) {
+			if (g.group[done + i] == group)
+				continue;
+			for (j = done + g.cnt[group]; j < nvar; ++j)
+				if (g.group[j] == group)
+					break;
+			if (j == nvar)
+				isl_die(bset->ctx, isl_error_internal,
+					"internal error", goto error);
+			g.group[j] = g.group[done + i];
+			Q = isl_mat_swap_rows(Q, done + i, j);
+			U = isl_mat_swap_cols(U, done + i, j);
+		}
+		done += g.cnt[group];
+		g.pos[n++] = g.cnt[group];
+	}
+
+	f = isl_factorizer_groups(bset, Q, U, n, g.pos);
+
+	isl_mat_free(H);
+	clear_groups(&g);
+
+	return f;
+error:
+	isl_mat_free(H);
+	isl_mat_free(U);
+	isl_mat_free(Q);
+	clear_groups(&g);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_factorization.h b/final/lib/External/isl/isl_factorization.h
new file mode 100644
index 0000000..4d769d9
--- /dev/null
+++ b/final/lib/External/isl/isl_factorization.h
@@ -0,0 +1,34 @@
+#ifndef ISL_FACTORIZATION_H
+#define ISL_FACTORIZATION_H
+
+#include <isl/set.h>
+#include <isl_morph.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Data for factorizing a particular basic set.
+ * After applying "morph" to the basic set, there are "n_group"
+ * groups of consecutive set variables, each of length "len[i]",
+ * with 0 <= i < n_group.
+ * If no factorization is possible, then "n_group" is set to 0.
+ */
+struct isl_factorizer {
+	isl_morph	*morph;
+	int		n_group;
+	int		*len;
+};
+typedef struct isl_factorizer isl_factorizer;
+
+__isl_give isl_factorizer *isl_basic_set_factorizer(
+	__isl_keep isl_basic_set *bset);
+
+void isl_factorizer_free(__isl_take isl_factorizer *f);
+void isl_factorizer_dump(__isl_take isl_factorizer *f);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/isl_farkas.c b/final/lib/External/isl/isl_farkas.c
new file mode 100644
index 0000000..cb45a63
--- /dev/null
+++ b/final/lib/External/isl/isl_farkas.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France 
+ */
+
+#include <isl_map_private.h>
+#include <isl/set.h>
+#include <isl_space_private.h>
+#include <isl_seq.h>
+
+/*
+ * Let C be a cone and define
+ *
+ *	C' := { y | forall x in C : y x >= 0 }
+ *
+ * C' contains the coefficients of all linear constraints
+ * that are valid for C.
+ * Furthermore, C'' = C.
+ *
+ * If C is defined as { x | A x >= 0 }
+ * then any element in C' must be a non-negative combination
+ * of the rows of A, i.e., y = t A with t >= 0.  That is,
+ *
+ *	C' = { y | exists t >= 0 : y = t A }
+ *
+ * If any of the rows in A actually represents an equality, then
+ * also negative combinations of this row are allowed and so the
+ * non-negativity constraint on the corresponding element of t
+ * can be dropped.
+ *
+ * A polyhedron P = { x | b + A x >= 0 } can be represented
+ * in homogeneous coordinates by the cone
+ * C = { [z,x] | b z + A x >= and z >= 0 }
+ * The valid linear constraints on C correspond to the valid affine
+ * constraints on P.
+ * This is essentially Farkas' lemma.
+ *
+ * Since
+ *				  [ 1 0 ]
+ *		[ w y ] = [t_0 t] [ b A ]
+ *
+ * we have
+ *
+ *	C' = { w, y | exists t_0, t >= 0 : y = t A and w = t_0 + t b }
+ * or
+ *
+ *	C' = { w, y | exists t >= 0 : y = t A and w - t b >= 0 }
+ *
+ * In practice, we introduce an extra variable (w), shifting all
+ * other variables to the right, and an extra inequality
+ * (w - t b >= 0) corresponding to the positivity constraint on
+ * the homogeneous coordinate.
+ *
+ * When going back from coefficients to solutions, we immediately
+ * plug in 1 for z, which corresponds to shifting all variables
+ * to the left, with the leftmost ending up in the constant position.
+ */
+
+/* Add the given prefix to all named isl_dim_set dimensions in "dim".
+ */
+static __isl_give isl_space *isl_space_prefix(__isl_take isl_space *dim,
+	const char *prefix)
+{
+	int i;
+	isl_ctx *ctx;
+	unsigned nvar;
+	size_t prefix_len = strlen(prefix);
+
+	if (!dim)
+		return NULL;
+
+	ctx = isl_space_get_ctx(dim);
+	nvar = isl_space_dim(dim, isl_dim_set);
+
+	for (i = 0; i < nvar; ++i) {
+		const char *name;
+		char *prefix_name;
+
+		name = isl_space_get_dim_name(dim, isl_dim_set, i);
+		if (!name)
+			continue;
+
+		prefix_name = isl_alloc_array(ctx, char,
+					      prefix_len + strlen(name) + 1);
+		if (!prefix_name)
+			goto error;
+		memcpy(prefix_name, prefix, prefix_len);
+		strcpy(prefix_name + prefix_len, name);
+
+		dim = isl_space_set_dim_name(dim, isl_dim_set, i, prefix_name);
+		free(prefix_name);
+	}
+
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Given a dimension specification of the solutions space, construct
+ * a dimension specification for the space of coefficients.
+ *
+ * In particular transform
+ *
+ *	[params] -> { S }
+ *
+ * to
+ *
+ *	{ coefficients[[cst, params] -> S] }
+ *
+ * and prefix each dimension name with "c_".
+ */
+static __isl_give isl_space *isl_space_coefficients(__isl_take isl_space *dim)
+{
+	isl_space *dim_param;
+	unsigned nvar;
+	unsigned nparam;
+
+	nvar = isl_space_dim(dim, isl_dim_set);
+	nparam = isl_space_dim(dim, isl_dim_param);
+	dim_param = isl_space_copy(dim);
+	dim_param = isl_space_drop_dims(dim_param, isl_dim_set, 0, nvar);
+	dim_param = isl_space_move_dims(dim_param, isl_dim_set, 0,
+				 isl_dim_param, 0, nparam);
+	dim_param = isl_space_prefix(dim_param, "c_");
+	dim_param = isl_space_insert_dims(dim_param, isl_dim_set, 0, 1);
+	dim_param = isl_space_set_dim_name(dim_param, isl_dim_set, 0, "c_cst");
+	dim = isl_space_drop_dims(dim, isl_dim_param, 0, nparam);
+	dim = isl_space_prefix(dim, "c_");
+	dim = isl_space_join(isl_space_from_domain(dim_param),
+			   isl_space_from_range(dim));
+	dim = isl_space_wrap(dim);
+	dim = isl_space_set_tuple_name(dim, isl_dim_set, "coefficients");
+
+	return dim;
+}
+
+/* Drop the given prefix from all named dimensions of type "type" in "dim".
+ */
+static __isl_give isl_space *isl_space_unprefix(__isl_take isl_space *dim,
+	enum isl_dim_type type, const char *prefix)
+{
+	int i;
+	unsigned n;
+	size_t prefix_len = strlen(prefix);
+
+	n = isl_space_dim(dim, type);
+
+	for (i = 0; i < n; ++i) {
+		const char *name;
+
+		name = isl_space_get_dim_name(dim, type, i);
+		if (!name)
+			continue;
+		if (strncmp(name, prefix, prefix_len))
+			continue;
+
+		dim = isl_space_set_dim_name(dim, type, i, name + prefix_len);
+	}
+
+	return dim;
+}
+
+/* Given a dimension specification of the space of coefficients, construct
+ * a dimension specification for the space of solutions.
+ *
+ * In particular transform
+ *
+ *	{ coefficients[[cst, params] -> S] }
+ *
+ * to
+ *
+ *	[params] -> { S }
+ *
+ * and drop the "c_" prefix from the dimension names.
+ */
+static __isl_give isl_space *isl_space_solutions(__isl_take isl_space *dim)
+{
+	unsigned nparam;
+
+	dim = isl_space_unwrap(dim);
+	dim = isl_space_drop_dims(dim, isl_dim_in, 0, 1);
+	dim = isl_space_unprefix(dim, isl_dim_in, "c_");
+	dim = isl_space_unprefix(dim, isl_dim_out, "c_");
+	nparam = isl_space_dim(dim, isl_dim_in);
+	dim = isl_space_move_dims(dim, isl_dim_param, 0, isl_dim_in, 0, nparam);
+	dim = isl_space_range(dim);
+
+	return dim;
+}
+
+/* Return the rational universe basic set in the given space.
+ */
+static __isl_give isl_basic_set *rational_universe(__isl_take isl_space *space)
+{
+	isl_basic_set *bset;
+
+	bset = isl_basic_set_universe(space);
+	bset = isl_basic_set_set_rational(bset);
+
+	return bset;
+}
+
+/* Compute the dual of "bset" by applying Farkas' lemma.
+ * As explained above, we add an extra dimension to represent
+ * the coefficient of the constant term when going from solutions
+ * to coefficients (shift == 1) and we drop the extra dimension when going
+ * in the opposite direction (shift == -1).  "dim" is the space in which
+ * the dual should be created.
+ *
+ * If "bset" is (obviously) empty, then the way this emptiness
+ * is represented by the constraints does not allow for the application
+ * of the standard farkas algorithm.  We therefore handle this case
+ * specifically and return the universe basic set.
+ */
+static __isl_give isl_basic_set *farkas(__isl_take isl_space *space,
+	__isl_take isl_basic_set *bset, int shift)
+{
+	int i, j, k;
+	isl_basic_set *dual = NULL;
+	unsigned total;
+
+	if (isl_basic_set_plain_is_empty(bset)) {
+		isl_basic_set_free(bset);
+		return rational_universe(space);
+	}
+
+	total = isl_basic_set_total_dim(bset);
+
+	dual = isl_basic_set_alloc_space(space, bset->n_eq + bset->n_ineq,
+					total, bset->n_ineq + (shift > 0));
+	dual = isl_basic_set_set_rational(dual);
+
+	for (i = 0; i < bset->n_eq + bset->n_ineq; ++i) {
+		k = isl_basic_set_alloc_div(dual);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(dual->div[k][0], 0);
+	}
+
+	for (i = 0; i < total; ++i) {
+		k = isl_basic_set_alloc_equality(dual);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(dual->eq[k], 1 + shift + total);
+		isl_int_set_si(dual->eq[k][1 + shift + i], -1);
+		for (j = 0; j < bset->n_eq; ++j)
+			isl_int_set(dual->eq[k][1 + shift + total + j],
+				    bset->eq[j][1 + i]);
+		for (j = 0; j < bset->n_ineq; ++j)
+			isl_int_set(dual->eq[k][1 + shift + total + bset->n_eq + j],
+				    bset->ineq[j][1 + i]);
+	}
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		k = isl_basic_set_alloc_inequality(dual);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(dual->ineq[k],
+			    1 + shift + total + bset->n_eq + bset->n_ineq);
+		isl_int_set_si(dual->ineq[k][1 + shift + total + bset->n_eq + i], 1);
+	}
+
+	if (shift > 0) {
+		k = isl_basic_set_alloc_inequality(dual);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(dual->ineq[k], 2 + total);
+		isl_int_set_si(dual->ineq[k][1], 1);
+		for (j = 0; j < bset->n_eq; ++j)
+			isl_int_neg(dual->ineq[k][2 + total + j],
+				    bset->eq[j][0]);
+		for (j = 0; j < bset->n_ineq; ++j)
+			isl_int_neg(dual->ineq[k][2 + total + bset->n_eq + j],
+				    bset->ineq[j][0]);
+	}
+
+	dual = isl_basic_set_remove_divs(dual);
+	dual = isl_basic_set_simplify(dual);
+	dual = isl_basic_set_finalize(dual);
+
+	isl_basic_set_free(bset);
+	return dual;
+error:
+	isl_basic_set_free(bset);
+	isl_basic_set_free(dual);
+	return NULL;
+}
+
+/* Construct a basic set containing the tuples of coefficients of all
+ * valid affine constraints on the given basic set.
+ */
+__isl_give isl_basic_set *isl_basic_set_coefficients(
+	__isl_take isl_basic_set *bset)
+{
+	isl_space *dim;
+
+	if (!bset)
+		return NULL;
+	if (bset->n_div)
+		isl_die(bset->ctx, isl_error_invalid,
+			"input set not allowed to have local variables",
+			goto error);
+
+	dim = isl_basic_set_get_space(bset);
+	dim = isl_space_coefficients(dim);
+
+	return farkas(dim, bset, 1);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Construct a basic set containing the elements that satisfy all
+ * affine constraints whose coefficient tuples are
+ * contained in the given basic set.
+ */
+__isl_give isl_basic_set *isl_basic_set_solutions(
+	__isl_take isl_basic_set *bset)
+{
+	isl_space *dim;
+
+	if (!bset)
+		return NULL;
+	if (bset->n_div)
+		isl_die(bset->ctx, isl_error_invalid,
+			"input set not allowed to have local variables",
+			goto error);
+
+	dim = isl_basic_set_get_space(bset);
+	dim = isl_space_solutions(dim);
+
+	return farkas(dim, bset, -1);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Construct a basic set containing the tuples of coefficients of all
+ * valid affine constraints on the given set.
+ */
+__isl_give isl_basic_set *isl_set_coefficients(__isl_take isl_set *set)
+{
+	int i;
+	isl_basic_set *coeff;
+
+	if (!set)
+		return NULL;
+	if (set->n == 0) {
+		isl_space *space = isl_set_get_space(set);
+		space = isl_space_coefficients(space);
+		isl_set_free(set);
+		return rational_universe(space);
+	}
+
+	coeff = isl_basic_set_coefficients(isl_basic_set_copy(set->p[0]));
+
+	for (i = 1; i < set->n; ++i) {
+		isl_basic_set *bset, *coeff_i;
+		bset = isl_basic_set_copy(set->p[i]);
+		coeff_i = isl_basic_set_coefficients(bset);
+		coeff = isl_basic_set_intersect(coeff, coeff_i);
+	}
+
+	isl_set_free(set);
+	return coeff;
+}
+
+/* Wrapper around isl_basic_set_coefficients for use
+ * as a isl_basic_set_list_map callback.
+ */
+static __isl_give isl_basic_set *coefficients_wrap(
+	__isl_take isl_basic_set *bset, void *user)
+{
+	return isl_basic_set_coefficients(bset);
+}
+
+/* Replace the elements of "list" by the result of applying
+ * isl_basic_set_coefficients to them.
+ */
+__isl_give isl_basic_set_list *isl_basic_set_list_coefficients(
+	__isl_take isl_basic_set_list *list)
+{
+	return isl_basic_set_list_map(list, &coefficients_wrap, NULL);
+}
+
+/* Construct a basic set containing the elements that satisfy all
+ * affine constraints whose coefficient tuples are
+ * contained in the given set.
+ */
+__isl_give isl_basic_set *isl_set_solutions(__isl_take isl_set *set)
+{
+	int i;
+	isl_basic_set *sol;
+
+	if (!set)
+		return NULL;
+	if (set->n == 0) {
+		isl_space *space = isl_set_get_space(set);
+		space = isl_space_solutions(space);
+		isl_set_free(set);
+		return rational_universe(space);
+	}
+
+	sol = isl_basic_set_solutions(isl_basic_set_copy(set->p[0]));
+
+	for (i = 1; i < set->n; ++i) {
+		isl_basic_set *bset, *sol_i;
+		bset = isl_basic_set_copy(set->p[i]);
+		sol_i = isl_basic_set_solutions(bset);
+		sol = isl_basic_set_intersect(sol, sol_i);
+	}
+
+	isl_set_free(set);
+	return sol;
+}
diff --git a/final/lib/External/isl/isl_ffs.c b/final/lib/External/isl/isl_ffs.c
new file mode 100644
index 0000000..c1ee928
--- /dev/null
+++ b/final/lib/External/isl/isl_ffs.c
@@ -0,0 +1,24 @@
+#include <isl_config.h>
+
+#if !HAVE_DECL_FFS && !HAVE_DECL___BUILTIN_FFS && HAVE_DECL__BITSCANFORWARD
+#include <intrin.h>
+
+/* Implementation of ffs in terms of _BitScanForward.
+ *
+ * ffs returns the position of the least significant bit set in i,
+ * with the least significant bit is position 1, or 0 if not bits are set.
+ *
+ * _BitScanForward returns 1 if mask is non-zero and sets index
+ * to the position of the least significant bit set in i,
+ * with the least significant bit is position 0.
+ */
+int isl_ffs(int i)
+{
+	unsigned char non_zero;
+	unsigned long index, mask = i;
+
+	non_zero = _BitScanForward(&index, mask);
+
+	return non_zero ? 1 + index : 0;
+}
+#endif
diff --git a/final/lib/External/isl/isl_flow.c b/final/lib/External/isl/isl_flow.c
new file mode 100644
index 0000000..37a29b0
--- /dev/null
+++ b/final/lib/External/isl/isl_flow.c
@@ -0,0 +1,3307 @@
+/*
+ * Copyright 2005-2007 Universiteit Leiden
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012      Universiteit Leiden
+ * Copyright 2014      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science,
+ * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands
+ * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A,
+ * B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl/flow.h>
+#include <isl/schedule_node.h>
+#include <isl_sort.h>
+#include <isl/stream.h>
+
+enum isl_restriction_type {
+	isl_restriction_type_empty,
+	isl_restriction_type_none,
+	isl_restriction_type_input,
+	isl_restriction_type_output
+};
+
+struct isl_restriction {
+	enum isl_restriction_type type;
+
+	isl_set *source;
+	isl_set *sink;
+};
+
+/* Create a restriction of the given type.
+ */
+static __isl_give isl_restriction *isl_restriction_alloc(
+	__isl_take isl_map *source_map, enum isl_restriction_type type)
+{
+	isl_ctx *ctx;
+	isl_restriction *restr;
+
+	if (!source_map)
+		return NULL;
+
+	ctx = isl_map_get_ctx(source_map);
+	restr = isl_calloc_type(ctx, struct isl_restriction);
+	if (!restr)
+		goto error;
+
+	restr->type = type;
+
+	isl_map_free(source_map);
+	return restr;
+error:
+	isl_map_free(source_map);
+	return NULL;
+}
+
+/* Create a restriction that doesn't restrict anything.
+ */
+__isl_give isl_restriction *isl_restriction_none(__isl_take isl_map *source_map)
+{
+	return isl_restriction_alloc(source_map, isl_restriction_type_none);
+}
+
+/* Create a restriction that removes everything.
+ */
+__isl_give isl_restriction *isl_restriction_empty(
+	__isl_take isl_map *source_map)
+{
+	return isl_restriction_alloc(source_map, isl_restriction_type_empty);
+}
+
+/* Create a restriction on the input of the maximization problem
+ * based on the given source and sink restrictions.
+ */
+__isl_give isl_restriction *isl_restriction_input(
+	__isl_take isl_set *source_restr, __isl_take isl_set *sink_restr)
+{
+	isl_ctx *ctx;
+	isl_restriction *restr;
+
+	if (!source_restr || !sink_restr)
+		goto error;
+
+	ctx = isl_set_get_ctx(source_restr);
+	restr = isl_calloc_type(ctx, struct isl_restriction);
+	if (!restr)
+		goto error;
+
+	restr->type = isl_restriction_type_input;
+	restr->source = source_restr;
+	restr->sink = sink_restr;
+
+	return restr;
+error:
+	isl_set_free(source_restr);
+	isl_set_free(sink_restr);
+	return NULL;
+}
+
+/* Create a restriction on the output of the maximization problem
+ * based on the given source restriction.
+ */
+__isl_give isl_restriction *isl_restriction_output(
+	__isl_take isl_set *source_restr)
+{
+	isl_ctx *ctx;
+	isl_restriction *restr;
+
+	if (!source_restr)
+		return NULL;
+
+	ctx = isl_set_get_ctx(source_restr);
+	restr = isl_calloc_type(ctx, struct isl_restriction);
+	if (!restr)
+		goto error;
+
+	restr->type = isl_restriction_type_output;
+	restr->source = source_restr;
+
+	return restr;
+error:
+	isl_set_free(source_restr);
+	return NULL;
+}
+
+__isl_null isl_restriction *isl_restriction_free(
+	__isl_take isl_restriction *restr)
+{
+	if (!restr)
+		return NULL;
+
+	isl_set_free(restr->source);
+	isl_set_free(restr->sink);
+	free(restr);
+	return NULL;
+}
+
+isl_ctx *isl_restriction_get_ctx(__isl_keep isl_restriction *restr)
+{
+	return restr ? isl_set_get_ctx(restr->source) : NULL;
+}
+
+/* A private structure to keep track of a mapping together with
+ * a user-specified identifier and a boolean indicating whether
+ * the map represents a must or may access/dependence.
+ */
+struct isl_labeled_map {
+	struct isl_map	*map;
+	void		*data;
+	int		must;
+};
+
+typedef int (*isl_access_coscheduled)(void *first, void *second);
+
+/* A structure containing the input for dependence analysis:
+ * - a sink
+ * - n_must + n_may (<= max_source) sources
+ * - a function for determining the relative order of sources and sink
+ * - an optional function "coscheduled" for determining whether sources
+ *   may be coscheduled.  If "coscheduled" is NULL, then the sources
+ *   are assumed not to be coscheduled.
+ * The must sources are placed before the may sources.
+ *
+ * domain_map is an auxiliary map that maps the sink access relation
+ * to the domain of this access relation.
+ * This field is only needed when restrict_fn is set and
+ * the field itself is set by isl_access_info_compute_flow.
+ *
+ * restrict_fn is a callback that (if not NULL) will be called
+ * right before any lexicographical maximization.
+ */
+struct isl_access_info {
+	isl_map				*domain_map;
+	struct isl_labeled_map		sink;
+	isl_access_level_before		level_before;
+	isl_access_coscheduled		coscheduled;
+
+	isl_access_restrict		restrict_fn;
+	void				*restrict_user;
+
+	int		    		max_source;
+	int		    		n_must;
+	int		    		n_may;
+	struct isl_labeled_map		source[1];
+};
+
+/* A structure containing the output of dependence analysis:
+ * - n_source dependences
+ * - a wrapped subset of the sink for which definitely no source could be found
+ * - a wrapped subset of the sink for which possibly no source could be found
+ */
+struct isl_flow {
+	isl_set			*must_no_source;
+	isl_set			*may_no_source;
+	int			n_source;
+	struct isl_labeled_map	*dep;
+};
+
+/* Construct an isl_access_info structure and fill it up with
+ * the given data.  The number of sources is set to 0.
+ */
+__isl_give isl_access_info *isl_access_info_alloc(__isl_take isl_map *sink,
+	void *sink_user, isl_access_level_before fn, int max_source)
+{
+	isl_ctx *ctx;
+	struct isl_access_info *acc;
+
+	if (!sink)
+		return NULL;
+
+	ctx = isl_map_get_ctx(sink);
+	isl_assert(ctx, max_source >= 0, goto error);
+
+	acc = isl_calloc(ctx, struct isl_access_info,
+			sizeof(struct isl_access_info) +
+			(max_source - 1) * sizeof(struct isl_labeled_map));
+	if (!acc)
+		goto error;
+
+	acc->sink.map = sink;
+	acc->sink.data = sink_user;
+	acc->level_before = fn;
+	acc->max_source = max_source;
+	acc->n_must = 0;
+	acc->n_may = 0;
+
+	return acc;
+error:
+	isl_map_free(sink);
+	return NULL;
+}
+
+/* Free the given isl_access_info structure.
+ */
+__isl_null isl_access_info *isl_access_info_free(
+	__isl_take isl_access_info *acc)
+{
+	int i;
+
+	if (!acc)
+		return NULL;
+	isl_map_free(acc->domain_map);
+	isl_map_free(acc->sink.map);
+	for (i = 0; i < acc->n_must + acc->n_may; ++i)
+		isl_map_free(acc->source[i].map);
+	free(acc);
+	return NULL;
+}
+
+isl_ctx *isl_access_info_get_ctx(__isl_keep isl_access_info *acc)
+{
+	return acc ? isl_map_get_ctx(acc->sink.map) : NULL;
+}
+
+__isl_give isl_access_info *isl_access_info_set_restrict(
+	__isl_take isl_access_info *acc, isl_access_restrict fn, void *user)
+{
+	if (!acc)
+		return NULL;
+	acc->restrict_fn = fn;
+	acc->restrict_user = user;
+	return acc;
+}
+
+/* Add another source to an isl_access_info structure, making
+ * sure the "must" sources are placed before the "may" sources.
+ * This function may be called at most max_source times on a
+ * given isl_access_info structure, with max_source as specified
+ * in the call to isl_access_info_alloc that constructed the structure.
+ */
+__isl_give isl_access_info *isl_access_info_add_source(
+	__isl_take isl_access_info *acc, __isl_take isl_map *source,
+	int must, void *source_user)
+{
+	isl_ctx *ctx;
+
+	if (!acc)
+		goto error;
+	ctx = isl_map_get_ctx(acc->sink.map);
+	isl_assert(ctx, acc->n_must + acc->n_may < acc->max_source, goto error);
+	
+	if (must) {
+		if (acc->n_may)
+			acc->source[acc->n_must + acc->n_may] =
+				acc->source[acc->n_must];
+		acc->source[acc->n_must].map = source;
+		acc->source[acc->n_must].data = source_user;
+		acc->source[acc->n_must].must = 1;
+		acc->n_must++;
+	} else {
+		acc->source[acc->n_must + acc->n_may].map = source;
+		acc->source[acc->n_must + acc->n_may].data = source_user;
+		acc->source[acc->n_must + acc->n_may].must = 0;
+		acc->n_may++;
+	}
+
+	return acc;
+error:
+	isl_map_free(source);
+	isl_access_info_free(acc);
+	return NULL;
+}
+
+/* A helper struct carrying the isl_access_info and an error condition.
+ */
+struct access_sort_info {
+	isl_access_info *access_info;
+	int error;
+};
+
+/* Return -n, 0 or n (with n a positive value), depending on whether
+ * the source access identified by p1 should be sorted before, together
+ * or after that identified by p2.
+ *
+ * If p1 appears before p2, then it should be sorted first.
+ * For more generic initial schedules, it is possible that neither
+ * p1 nor p2 appears before the other, or at least not in any obvious way.
+ * We therefore also check if p2 appears before p1, in which case p2
+ * should be sorted first.
+ * If not, we try to order the two statements based on the description
+ * of the iteration domains.  This results in an arbitrary, but fairly
+ * stable ordering.
+ *
+ * In case of an error, sort_info.error is set to true and all elements are
+ * reported to be equal.
+ */
+static int access_sort_cmp(const void *p1, const void *p2, void *user)
+{
+	struct access_sort_info *sort_info = user;
+	isl_access_info *acc = sort_info->access_info;
+
+	if (sort_info->error)
+		return 0;
+
+	const struct isl_labeled_map *i1, *i2;
+	int level1, level2;
+	uint32_t h1, h2;
+	i1 = (const struct isl_labeled_map *) p1;
+	i2 = (const struct isl_labeled_map *) p2;
+
+	level1 = acc->level_before(i1->data, i2->data);
+	if (level1 < 0)
+		goto error;
+	if (level1 % 2)
+		return -1;
+
+	level2 = acc->level_before(i2->data, i1->data);
+	if (level2 < 0)
+		goto error;
+	if (level2 % 2)
+		return 1;
+
+	h1 = isl_map_get_hash(i1->map);
+	h2 = isl_map_get_hash(i2->map);
+	return h1 > h2 ? 1 : h1 < h2 ? -1 : 0;
+error:
+	sort_info->error = 1;
+	return 0;
+}
+
+/* Sort the must source accesses in their textual order.
+ */
+static __isl_give isl_access_info *isl_access_info_sort_sources(
+	__isl_take isl_access_info *acc)
+{
+	struct access_sort_info sort_info;
+
+	sort_info.access_info = acc;
+	sort_info.error = 0;
+
+	if (!acc)
+		return NULL;
+	if (acc->n_must <= 1)
+		return acc;
+
+	if (isl_sort(acc->source, acc->n_must, sizeof(struct isl_labeled_map),
+		    access_sort_cmp, &sort_info) < 0)
+		return isl_access_info_free(acc);
+	if (sort_info.error)
+		return isl_access_info_free(acc);
+
+	return acc;
+}
+
+/* Align the parameters of the two spaces if needed and then call
+ * isl_space_join.
+ */
+static __isl_give isl_space *space_align_and_join(__isl_take isl_space *left,
+	__isl_take isl_space *right)
+{
+	isl_bool equal_params;
+
+	equal_params = isl_space_has_equal_params(left, right);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params)
+		return isl_space_join(left, right);
+
+	left = isl_space_align_params(left, isl_space_copy(right));
+	right = isl_space_align_params(right, isl_space_copy(left));
+	return isl_space_join(left, right);
+error:
+	isl_space_free(left);
+	isl_space_free(right);
+	return NULL;
+}
+
+/* Initialize an empty isl_flow structure corresponding to a given
+ * isl_access_info structure.
+ * For each must access, two dependences are created (initialized
+ * to the empty relation), one for the resulting must dependences
+ * and one for the resulting may dependences.  May accesses can
+ * only lead to may dependences, so only one dependence is created
+ * for each of them.
+ * This function is private as isl_flow structures are only supposed
+ * to be created by isl_access_info_compute_flow.
+ */
+static __isl_give isl_flow *isl_flow_alloc(__isl_keep isl_access_info *acc)
+{
+	int i, n;
+	struct isl_ctx *ctx;
+	struct isl_flow *dep;
+
+	if (!acc)
+		return NULL;
+
+	ctx = isl_map_get_ctx(acc->sink.map);
+	dep = isl_calloc_type(ctx, struct isl_flow);
+	if (!dep)
+		return NULL;
+
+	n = 2 * acc->n_must + acc->n_may;
+	dep->dep = isl_calloc_array(ctx, struct isl_labeled_map, n);
+	if (n && !dep->dep)
+		goto error;
+
+	dep->n_source = n;
+	for (i = 0; i < acc->n_must; ++i) {
+		isl_space *dim;
+		dim = space_align_and_join(
+			isl_map_get_space(acc->source[i].map),
+			isl_space_reverse(isl_map_get_space(acc->sink.map)));
+		dep->dep[2 * i].map = isl_map_empty(dim);
+		dep->dep[2 * i + 1].map = isl_map_copy(dep->dep[2 * i].map);
+		dep->dep[2 * i].data = acc->source[i].data;
+		dep->dep[2 * i + 1].data = acc->source[i].data;
+		dep->dep[2 * i].must = 1;
+		dep->dep[2 * i + 1].must = 0;
+		if (!dep->dep[2 * i].map || !dep->dep[2 * i + 1].map)
+			goto error;
+	}
+	for (i = acc->n_must; i < acc->n_must + acc->n_may; ++i) {
+		isl_space *dim;
+		dim = space_align_and_join(
+			isl_map_get_space(acc->source[i].map),
+			isl_space_reverse(isl_map_get_space(acc->sink.map)));
+		dep->dep[acc->n_must + i].map = isl_map_empty(dim);
+		dep->dep[acc->n_must + i].data = acc->source[i].data;
+		dep->dep[acc->n_must + i].must = 0;
+		if (!dep->dep[acc->n_must + i].map)
+			goto error;
+	}
+
+	return dep;
+error:
+	isl_flow_free(dep);
+	return NULL;
+}
+
+/* Iterate over all sources and for each resulting flow dependence
+ * that is not empty, call the user specfied function.
+ * The second argument in this function call identifies the source,
+ * while the third argument correspond to the final argument of
+ * the isl_flow_foreach call.
+ */
+isl_stat isl_flow_foreach(__isl_keep isl_flow *deps,
+	isl_stat (*fn)(__isl_take isl_map *dep, int must, void *dep_user,
+		void *user),
+	void *user)
+{
+	int i;
+
+	if (!deps)
+		return isl_stat_error;
+
+	for (i = 0; i < deps->n_source; ++i) {
+		if (isl_map_plain_is_empty(deps->dep[i].map))
+			continue;
+		if (fn(isl_map_copy(deps->dep[i].map), deps->dep[i].must,
+				deps->dep[i].data, user) < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Return a copy of the subset of the sink for which no source could be found.
+ */
+__isl_give isl_map *isl_flow_get_no_source(__isl_keep isl_flow *deps, int must)
+{
+	if (!deps)
+		return NULL;
+	
+	if (must)
+		return isl_set_unwrap(isl_set_copy(deps->must_no_source));
+	else
+		return isl_set_unwrap(isl_set_copy(deps->may_no_source));
+}
+
+void isl_flow_free(__isl_take isl_flow *deps)
+{
+	int i;
+
+	if (!deps)
+		return;
+	isl_set_free(deps->must_no_source);
+	isl_set_free(deps->may_no_source);
+	if (deps->dep) {
+		for (i = 0; i < deps->n_source; ++i)
+			isl_map_free(deps->dep[i].map);
+		free(deps->dep);
+	}
+	free(deps);
+}
+
+isl_ctx *isl_flow_get_ctx(__isl_keep isl_flow *deps)
+{
+	return deps ? isl_set_get_ctx(deps->must_no_source) : NULL;
+}
+
+/* Return a map that enforces that the domain iteration occurs after
+ * the range iteration at the given level.
+ * If level is odd, then the domain iteration should occur after
+ * the target iteration in their shared level/2 outermost loops.
+ * In this case we simply need to enforce that these outermost
+ * loop iterations are the same.
+ * If level is even, then the loop iterator of the domain should
+ * be greater than the loop iterator of the range at the last
+ * of the level/2 shared loops, i.e., loop level/2 - 1.
+ */
+static __isl_give isl_map *after_at_level(__isl_take isl_space *dim, int level)
+{
+	struct isl_basic_map *bmap;
+
+	if (level % 2)
+		bmap = isl_basic_map_equal(dim, level/2);
+	else
+		bmap = isl_basic_map_more_at(dim, level/2 - 1);
+
+	return isl_map_from_basic_map(bmap);
+}
+
+/* Compute the partial lexicographic maximum of "dep" on domain "sink",
+ * but first check if the user has set acc->restrict_fn and if so
+ * update either the input or the output of the maximization problem
+ * with respect to the resulting restriction.
+ *
+ * Since the user expects a mapping from sink iterations to source iterations,
+ * whereas the domain of "dep" is a wrapped map, mapping sink iterations
+ * to accessed array elements, we first need to project out the accessed
+ * sink array elements by applying acc->domain_map.
+ * Similarly, the sink restriction specified by the user needs to be
+ * converted back to the wrapped map.
+ */
+static __isl_give isl_map *restricted_partial_lexmax(
+	__isl_keep isl_access_info *acc, __isl_take isl_map *dep,
+	int source, __isl_take isl_set *sink, __isl_give isl_set **empty)
+{
+	isl_map *source_map;
+	isl_restriction *restr;
+	isl_set *sink_domain;
+	isl_set *sink_restr;
+	isl_map *res;
+
+	if (!acc->restrict_fn)
+		return isl_map_partial_lexmax(dep, sink, empty);
+
+	source_map = isl_map_copy(dep);
+	source_map = isl_map_apply_domain(source_map,
+					    isl_map_copy(acc->domain_map));
+	sink_domain = isl_set_copy(sink);
+	sink_domain = isl_set_apply(sink_domain, isl_map_copy(acc->domain_map));
+	restr = acc->restrict_fn(source_map, sink_domain,
+				acc->source[source].data, acc->restrict_user);
+	isl_set_free(sink_domain);
+	isl_map_free(source_map);
+
+	if (!restr)
+		goto error;
+	if (restr->type == isl_restriction_type_input) {
+		dep = isl_map_intersect_range(dep, isl_set_copy(restr->source));
+		sink_restr = isl_set_copy(restr->sink);
+		sink_restr = isl_set_apply(sink_restr,
+				isl_map_reverse(isl_map_copy(acc->domain_map)));
+		sink = isl_set_intersect(sink, sink_restr);
+	} else if (restr->type == isl_restriction_type_empty) {
+		isl_space *space = isl_map_get_space(dep);
+		isl_map_free(dep);
+		dep = isl_map_empty(space);
+	}
+
+	res = isl_map_partial_lexmax(dep, sink, empty);
+
+	if (restr->type == isl_restriction_type_output)
+		res = isl_map_intersect_range(res, isl_set_copy(restr->source));
+
+	isl_restriction_free(restr);
+	return res;
+error:
+	isl_map_free(dep);
+	isl_set_free(sink);
+	*empty = NULL;
+	return NULL;
+}
+
+/* Compute the last iteration of must source j that precedes the sink
+ * at the given level for sink iterations in set_C.
+ * The subset of set_C for which no such iteration can be found is returned
+ * in *empty.
+ */
+static struct isl_map *last_source(struct isl_access_info *acc, 
+				    struct isl_set *set_C,
+				    int j, int level, struct isl_set **empty)
+{
+	struct isl_map *read_map;
+	struct isl_map *write_map;
+	struct isl_map *dep_map;
+	struct isl_map *after;
+	struct isl_map *result;
+
+	read_map = isl_map_copy(acc->sink.map);
+	write_map = isl_map_copy(acc->source[j].map);
+	write_map = isl_map_reverse(write_map);
+	dep_map = isl_map_apply_range(read_map, write_map);
+	after = after_at_level(isl_map_get_space(dep_map), level);
+	dep_map = isl_map_intersect(dep_map, after);
+	result = restricted_partial_lexmax(acc, dep_map, j, set_C, empty);
+	result = isl_map_reverse(result);
+
+	return result;
+}
+
+/* For a given mapping between iterations of must source j and iterations
+ * of the sink, compute the last iteration of must source k preceding
+ * the sink at level before_level for any of the sink iterations,
+ * but following the corresponding iteration of must source j at level
+ * after_level.
+ */
+static struct isl_map *last_later_source(struct isl_access_info *acc,
+					 struct isl_map *old_map,
+					 int j, int before_level,
+					 int k, int after_level,
+					 struct isl_set **empty)
+{
+	isl_space *dim;
+	struct isl_set *set_C;
+	struct isl_map *read_map;
+	struct isl_map *write_map;
+	struct isl_map *dep_map;
+	struct isl_map *after_write;
+	struct isl_map *before_read;
+	struct isl_map *result;
+
+	set_C = isl_map_range(isl_map_copy(old_map));
+	read_map = isl_map_copy(acc->sink.map);
+	write_map = isl_map_copy(acc->source[k].map);
+
+	write_map = isl_map_reverse(write_map);
+	dep_map = isl_map_apply_range(read_map, write_map);
+	dim = space_align_and_join(isl_map_get_space(acc->source[k].map),
+		    isl_space_reverse(isl_map_get_space(acc->source[j].map)));
+	after_write = after_at_level(dim, after_level);
+	after_write = isl_map_apply_range(after_write, old_map);
+	after_write = isl_map_reverse(after_write);
+	dep_map = isl_map_intersect(dep_map, after_write);
+	before_read = after_at_level(isl_map_get_space(dep_map), before_level);
+	dep_map = isl_map_intersect(dep_map, before_read);
+	result = restricted_partial_lexmax(acc, dep_map, k, set_C, empty);
+	result = isl_map_reverse(result);
+
+	return result;
+}
+
+/* Given a shared_level between two accesses, return 1 if the
+ * the first can precede the second at the requested target_level.
+ * If the target level is odd, i.e., refers to a statement level
+ * dimension, then first needs to precede second at the requested
+ * level, i.e., shared_level must be equal to target_level.
+ * If the target level is odd, then the two loops should share
+ * at least the requested number of outer loops.
+ */
+static int can_precede_at_level(int shared_level, int target_level)
+{
+	if (shared_level < target_level)
+		return 0;
+	if ((target_level % 2) && shared_level > target_level)
+		return 0;
+	return 1;
+}
+
+/* Given a possible flow dependence temp_rel[j] between source j and the sink
+ * at level sink_level, remove those elements for which
+ * there is an iteration of another source k < j that is closer to the sink.
+ * The flow dependences temp_rel[k] are updated with the improved sources.
+ * Any improved source needs to precede the sink at the same level
+ * and needs to follow source j at the same or a deeper level.
+ * The lower this level, the later the execution date of source k.
+ * We therefore consider lower levels first.
+ *
+ * If temp_rel[j] is empty, then there can be no improvement and
+ * we return immediately.
+ *
+ * This function returns isl_stat_ok in case it was executed successfully and
+ * isl_stat_error in case of errors during the execution of this function.
+ */
+static isl_stat intermediate_sources(__isl_keep isl_access_info *acc,
+	struct isl_map **temp_rel, int j, int sink_level)
+{
+	int k, level;
+	int depth = 2 * isl_map_dim(acc->source[j].map, isl_dim_in) + 1;
+
+	if (isl_map_plain_is_empty(temp_rel[j]))
+		return isl_stat_ok;
+
+	for (k = j - 1; k >= 0; --k) {
+		int plevel, plevel2;
+		plevel = acc->level_before(acc->source[k].data, acc->sink.data);
+		if (plevel < 0)
+			return isl_stat_error;
+		if (!can_precede_at_level(plevel, sink_level))
+			continue;
+
+		plevel2 = acc->level_before(acc->source[j].data,
+						acc->source[k].data);
+		if (plevel2 < 0)
+			return isl_stat_error;
+
+		for (level = sink_level; level <= depth; ++level) {
+			struct isl_map *T;
+			struct isl_set *trest;
+			struct isl_map *copy;
+
+			if (!can_precede_at_level(plevel2, level))
+				continue;
+
+			copy = isl_map_copy(temp_rel[j]);
+			T = last_later_source(acc, copy, j, sink_level, k,
+					      level, &trest);
+			if (isl_map_plain_is_empty(T)) {
+				isl_set_free(trest);
+				isl_map_free(T);
+				continue;
+			}
+			temp_rel[j] = isl_map_intersect_range(temp_rel[j], trest);
+			temp_rel[k] = isl_map_union_disjoint(temp_rel[k], T);
+		}
+	}
+
+	return isl_stat_ok;
+}
+
+/* Compute all iterations of may source j that precedes the sink at the given
+ * level for sink iterations in set_C.
+ */
+static __isl_give isl_map *all_sources(__isl_keep isl_access_info *acc,
+				    __isl_take isl_set *set_C, int j, int level)
+{
+	isl_map *read_map;
+	isl_map *write_map;
+	isl_map *dep_map;
+	isl_map *after;
+
+	read_map = isl_map_copy(acc->sink.map);
+	read_map = isl_map_intersect_domain(read_map, set_C);
+	write_map = isl_map_copy(acc->source[acc->n_must + j].map);
+	write_map = isl_map_reverse(write_map);
+	dep_map = isl_map_apply_range(read_map, write_map);
+	after = after_at_level(isl_map_get_space(dep_map), level);
+	dep_map = isl_map_intersect(dep_map, after);
+
+	return isl_map_reverse(dep_map);
+}
+
+/* For a given mapping between iterations of must source k and iterations
+ * of the sink, compute all iterations of may source j preceding
+ * the sink at level before_level for any of the sink iterations,
+ * but following the corresponding iteration of must source k at level
+ * after_level.
+ */
+static __isl_give isl_map *all_later_sources(__isl_keep isl_access_info *acc,
+	__isl_take isl_map *old_map,
+	int j, int before_level, int k, int after_level)
+{
+	isl_space *dim;
+	isl_set *set_C;
+	isl_map *read_map;
+	isl_map *write_map;
+	isl_map *dep_map;
+	isl_map *after_write;
+	isl_map *before_read;
+
+	set_C = isl_map_range(isl_map_copy(old_map));
+	read_map = isl_map_copy(acc->sink.map);
+	read_map = isl_map_intersect_domain(read_map, set_C);
+	write_map = isl_map_copy(acc->source[acc->n_must + j].map);
+
+	write_map = isl_map_reverse(write_map);
+	dep_map = isl_map_apply_range(read_map, write_map);
+	dim = isl_space_join(isl_map_get_space(acc->source[acc->n_must + j].map),
+		    isl_space_reverse(isl_map_get_space(acc->source[k].map)));
+	after_write = after_at_level(dim, after_level);
+	after_write = isl_map_apply_range(after_write, old_map);
+	after_write = isl_map_reverse(after_write);
+	dep_map = isl_map_intersect(dep_map, after_write);
+	before_read = after_at_level(isl_map_get_space(dep_map), before_level);
+	dep_map = isl_map_intersect(dep_map, before_read);
+	return isl_map_reverse(dep_map);
+}
+
+/* Given the must and may dependence relations for the must accesses
+ * for level sink_level, check if there are any accesses of may access j
+ * that occur in between and return their union.
+ * If some of these accesses are intermediate with respect to
+ * (previously thought to be) must dependences, then these
+ * must dependences are turned into may dependences.
+ */
+static __isl_give isl_map *all_intermediate_sources(
+	__isl_keep isl_access_info *acc, __isl_take isl_map *map,
+	struct isl_map **must_rel, struct isl_map **may_rel,
+	int j, int sink_level)
+{
+	int k, level;
+	int depth = 2 * isl_map_dim(acc->source[acc->n_must + j].map,
+					isl_dim_in) + 1;
+
+	for (k = 0; k < acc->n_must; ++k) {
+		int plevel;
+
+		if (isl_map_plain_is_empty(may_rel[k]) &&
+		    isl_map_plain_is_empty(must_rel[k]))
+			continue;
+
+		plevel = acc->level_before(acc->source[k].data,
+					acc->source[acc->n_must + j].data);
+		if (plevel < 0)
+			return isl_map_free(map);
+
+		for (level = sink_level; level <= depth; ++level) {
+			isl_map *T;
+			isl_map *copy;
+			isl_set *ran;
+
+			if (!can_precede_at_level(plevel, level))
+				continue;
+
+			copy = isl_map_copy(may_rel[k]);
+			T = all_later_sources(acc, copy, j, sink_level, k, level);
+			map = isl_map_union(map, T);
+
+			copy = isl_map_copy(must_rel[k]);
+			T = all_later_sources(acc, copy, j, sink_level, k, level);
+			ran = isl_map_range(isl_map_copy(T));
+			map = isl_map_union(map, T);
+			may_rel[k] = isl_map_union_disjoint(may_rel[k],
+			    isl_map_intersect_range(isl_map_copy(must_rel[k]),
+						    isl_set_copy(ran)));
+			T = isl_map_from_domain_and_range(
+			    isl_set_universe(
+				isl_space_domain(isl_map_get_space(must_rel[k]))),
+			    ran);
+			must_rel[k] = isl_map_subtract(must_rel[k], T);
+		}
+	}
+
+	return map;
+}
+
+/* Given a dependence relation "old_map" between a must-source and the sink,
+ * return a subset of the dependences, augmented with instances
+ * of the source at position "pos" in "acc" that are coscheduled
+ * with the must-source and that access the same element.
+ * That is, if the input lives in a space T -> K, then the output
+ * lives in the space [T -> S] -> K, with S the space of source "pos", and
+ * the domain factor of the domain product is a subset of the input.
+ * The sources are considered to be coscheduled if they have the same values
+ * for the initial "depth" coordinates.
+ *
+ * First construct a dependence relation S -> K and a mapping
+ * between coscheduled sources T -> S.
+ * The second is combined with the original dependence relation T -> K
+ * to form a relation in T -> [S -> K], which is subsequently
+ * uncurried to [T -> S] -> K.
+ * This result is then intersected with the dependence relation S -> K
+ * to form the output.
+ *
+ * In case a negative depth is given, NULL is returned to indicate an error.
+ */
+static __isl_give isl_map *coscheduled_source(__isl_keep isl_access_info *acc,
+	__isl_keep isl_map *old_map, int pos, int depth)
+{
+	isl_space *space;
+	isl_set *set_C;
+	isl_map *read_map;
+	isl_map *write_map;
+	isl_map *dep_map;
+	isl_map *equal;
+	isl_map *map;
+
+	if (depth < 0)
+		return NULL;
+
+	set_C = isl_map_range(isl_map_copy(old_map));
+	read_map = isl_map_copy(acc->sink.map);
+	read_map = isl_map_intersect_domain(read_map, set_C);
+	write_map = isl_map_copy(acc->source[pos].map);
+	dep_map = isl_map_domain_product(write_map, read_map);
+	dep_map = isl_set_unwrap(isl_map_domain(dep_map));
+	space = isl_space_join(isl_map_get_space(old_map),
+				isl_space_reverse(isl_map_get_space(dep_map)));
+	equal = isl_map_from_basic_map(isl_basic_map_equal(space, depth));
+	map = isl_map_range_product(equal, isl_map_copy(old_map));
+	map = isl_map_uncurry(map);
+	map = isl_map_intersect_domain_factor_range(map, dep_map);
+
+	return map;
+}
+
+/* After the dependences derived from a must-source have been computed
+ * at a certain level, check if any of the sources of the must-dependences
+ * may be coscheduled with other sources.
+ * If they are any such sources, then there is no way of determining
+ * which of the sources actually comes last and the must-dependences
+ * need to be turned into may-dependences, while dependences from
+ * the other sources need to be added to the may-dependences as well.
+ * "acc" describes the sources and a callback for checking whether
+ * two sources may be coscheduled.  If acc->coscheduled is NULL then
+ * the sources are assumed not to be coscheduled.
+ * "must_rel" and "may_rel" describe the must and may-dependence relations
+ * computed at the current level for the must-sources.  Some of the dependences
+ * may be moved from "must_rel" to "may_rel".
+ * "flow" contains all dependences computed so far (apart from those
+ * in "must_rel" and "may_rel") and may be updated with additional
+ * dependences derived from may-sources.
+ *
+ * In particular, consider all the must-sources with a non-empty
+ * dependence relation in "must_rel".  They are considered in reverse
+ * order because that is the order in which they are considered in the caller.
+ * If any of the must-sources are coscheduled, then the last one
+ * is the one that will have a corresponding dependence relation.
+ * For each must-source i, consider both all the previous must-sources
+ * and all the may-sources.  If any of those may be coscheduled with
+ * must-source i, then compute the coscheduled instances that access
+ * the same memory elements.  The result is a relation [T -> S] -> K.
+ * The projection onto T -> K is a subset of the must-dependence relation
+ * that needs to be turned into may-dependences.
+ * The projection onto S -> K needs to be added to the may-dependences
+ * of source S.
+ * Since a given must-source instance may be coscheduled with several
+ * other source instances, the dependences that need to be turned
+ * into may-dependences are first collected and only actually removed
+ * from the must-dependences after all other sources have been considered.
+ */
+static __isl_give isl_flow *handle_coscheduled(__isl_keep isl_access_info *acc,
+	__isl_keep isl_map **must_rel, __isl_keep isl_map **may_rel,
+	__isl_take isl_flow *flow)
+{
+	int i, j;
+
+	if (!acc->coscheduled)
+		return flow;
+	for (i = acc->n_must - 1; i >= 0; --i) {
+		isl_map *move;
+
+		if (isl_map_plain_is_empty(must_rel[i]))
+			continue;
+		move = isl_map_empty(isl_map_get_space(must_rel[i]));
+		for (j = i - 1; j >= 0; --j) {
+			int depth;
+			isl_map *map, *factor;
+
+			if (!acc->coscheduled(acc->source[i].data,
+						acc->source[j].data))
+				continue;
+			depth = acc->level_before(acc->source[i].data,
+						acc->source[j].data) / 2;
+			map = coscheduled_source(acc, must_rel[i], j, depth);
+			factor = isl_map_domain_factor_range(isl_map_copy(map));
+			may_rel[j] = isl_map_union(may_rel[j], factor);
+			map = isl_map_domain_factor_domain(map);
+			move = isl_map_union(move, map);
+		}
+		for (j = 0; j < acc->n_may; ++j) {
+			int depth, pos;
+			isl_map *map, *factor;
+
+			pos = acc->n_must + j;
+			if (!acc->coscheduled(acc->source[i].data,
+						acc->source[pos].data))
+				continue;
+			depth = acc->level_before(acc->source[i].data,
+						acc->source[pos].data) / 2;
+			map = coscheduled_source(acc, must_rel[i], pos, depth);
+			factor = isl_map_domain_factor_range(isl_map_copy(map));
+			pos = 2 * acc->n_must + j;
+			flow->dep[pos].map = isl_map_union(flow->dep[pos].map,
+							    factor);
+			map = isl_map_domain_factor_domain(map);
+			move = isl_map_union(move, map);
+		}
+		must_rel[i] = isl_map_subtract(must_rel[i], isl_map_copy(move));
+		may_rel[i] = isl_map_union(may_rel[i], move);
+	}
+
+	return flow;
+}
+
+/* Compute dependences for the case where all accesses are "may"
+ * accesses, which boils down to computing memory based dependences.
+ * The generic algorithm would also work in this case, but it would
+ * be overkill to use it.
+ */
+static __isl_give isl_flow *compute_mem_based_dependences(
+	__isl_keep isl_access_info *acc)
+{
+	int i;
+	isl_set *mustdo;
+	isl_set *maydo;
+	isl_flow *res;
+
+	res = isl_flow_alloc(acc);
+	if (!res)
+		return NULL;
+
+	mustdo = isl_map_domain(isl_map_copy(acc->sink.map));
+	maydo = isl_set_copy(mustdo);
+
+	for (i = 0; i < acc->n_may; ++i) {
+		int plevel;
+		int is_before;
+		isl_space *dim;
+		isl_map *before;
+		isl_map *dep;
+
+		plevel = acc->level_before(acc->source[i].data, acc->sink.data);
+		if (plevel < 0)
+			goto error;
+
+		is_before = plevel & 1;
+		plevel >>= 1;
+
+		dim = isl_map_get_space(res->dep[i].map);
+		if (is_before)
+			before = isl_map_lex_le_first(dim, plevel);
+		else
+			before = isl_map_lex_lt_first(dim, plevel);
+		dep = isl_map_apply_range(isl_map_copy(acc->source[i].map),
+			isl_map_reverse(isl_map_copy(acc->sink.map)));
+		dep = isl_map_intersect(dep, before);
+		mustdo = isl_set_subtract(mustdo,
+					    isl_map_range(isl_map_copy(dep)));
+		res->dep[i].map = isl_map_union(res->dep[i].map, dep);
+	}
+
+	res->may_no_source = isl_set_subtract(maydo, isl_set_copy(mustdo));
+	res->must_no_source = mustdo;
+
+	return res;
+error:
+	isl_set_free(mustdo);
+	isl_set_free(maydo);
+	isl_flow_free(res);
+	return NULL;
+}
+
+/* Compute dependences for the case where there is at least one
+ * "must" access.
+ *
+ * The core algorithm considers all levels in which a source may precede
+ * the sink, where a level may either be a statement level or a loop level.
+ * The outermost statement level is 1, the first loop level is 2, etc...
+ * The algorithm basically does the following:
+ * for all levels l of the read access from innermost to outermost
+ *	for all sources w that may precede the sink access at that level
+ *	    compute the last iteration of the source that precedes the sink access
+ *					    at that level
+ *	    add result to possible last accesses at level l of source w
+ *	    for all sources w2 that we haven't considered yet at this level that may
+ *					    also precede the sink access
+ *		for all levels l2 of w from l to innermost
+ *		    for all possible last accesses dep of w at l
+ *			compute last iteration of w2 between the source and sink
+ *								of dep
+ *			add result to possible last accesses at level l of write w2
+ *			and replace possible last accesses dep by the remainder
+ *
+ *
+ * The above algorithm is applied to the must access.  During the course
+ * of the algorithm, we keep track of sink iterations that still
+ * need to be considered.  These iterations are split into those that
+ * haven't been matched to any source access (mustdo) and those that have only
+ * been matched to may accesses (maydo).
+ * At the end of each level, must-sources and may-sources that are coscheduled
+ * with the sources of the must-dependences at that level are considered.
+ * If any coscheduled instances are found, then corresponding may-dependences
+ * are added and the original must-dependences are turned into may-dependences.
+ * Afterwards, the may accesses that occur after must-dependence sources
+ * are considered.
+ * In particular, we consider may accesses that precede the remaining
+ * sink iterations, moving elements from mustdo to maydo when appropriate,
+ * and may accesses that occur between a must source and a sink of any 
+ * dependences found at the current level, turning must dependences into
+ * may dependences when appropriate.
+ * 
+ */
+static __isl_give isl_flow *compute_val_based_dependences(
+	__isl_keep isl_access_info *acc)
+{
+	isl_ctx *ctx;
+	isl_flow *res;
+	isl_set *mustdo = NULL;
+	isl_set *maydo = NULL;
+	int level, j;
+	int depth;
+	isl_map **must_rel = NULL;
+	isl_map **may_rel = NULL;
+
+	if (!acc)
+		return NULL;
+
+	res = isl_flow_alloc(acc);
+	if (!res)
+		goto error;
+	ctx = isl_map_get_ctx(acc->sink.map);
+
+	depth = 2 * isl_map_dim(acc->sink.map, isl_dim_in) + 1;
+	mustdo = isl_map_domain(isl_map_copy(acc->sink.map));
+	maydo = isl_set_empty(isl_set_get_space(mustdo));
+	if (!mustdo || !maydo)
+		goto error;
+	if (isl_set_plain_is_empty(mustdo))
+		goto done;
+
+	must_rel = isl_calloc_array(ctx, struct isl_map *, acc->n_must);
+	may_rel = isl_calloc_array(ctx, struct isl_map *, acc->n_must);
+	if (!must_rel || !may_rel)
+		goto error;
+
+	for (level = depth; level >= 1; --level) {
+		for (j = acc->n_must-1; j >=0; --j) {
+			isl_space *space;
+			space = isl_map_get_space(res->dep[2 * j].map);
+			must_rel[j] = isl_map_empty(space);
+			may_rel[j] = isl_map_copy(must_rel[j]);
+		}
+
+		for (j = acc->n_must - 1; j >= 0; --j) {
+			struct isl_map *T;
+			struct isl_set *rest;
+			int plevel;
+
+			plevel = acc->level_before(acc->source[j].data,
+						     acc->sink.data);
+			if (plevel < 0)
+				goto error;
+			if (!can_precede_at_level(plevel, level))
+				continue;
+
+			T = last_source(acc, mustdo, j, level, &rest);
+			must_rel[j] = isl_map_union_disjoint(must_rel[j], T);
+			mustdo = rest;
+
+			if (intermediate_sources(acc, must_rel, j, level) < 0)
+				goto error;
+
+			T = last_source(acc, maydo, j, level, &rest);
+			may_rel[j] = isl_map_union_disjoint(may_rel[j], T);
+			maydo = rest;
+
+			if (intermediate_sources(acc, may_rel, j, level) < 0)
+				goto error;
+
+			if (isl_set_plain_is_empty(mustdo) &&
+			    isl_set_plain_is_empty(maydo))
+				break;
+		}
+		for (j = j - 1; j >= 0; --j) {
+			int plevel;
+
+			plevel = acc->level_before(acc->source[j].data,
+						     acc->sink.data);
+			if (plevel < 0)
+				goto error;
+			if (!can_precede_at_level(plevel, level))
+				continue;
+
+			if (intermediate_sources(acc, must_rel, j, level) < 0)
+				goto error;
+			if (intermediate_sources(acc, may_rel, j, level) < 0)
+				goto error;
+		}
+
+		handle_coscheduled(acc, must_rel, may_rel, res);
+
+		for (j = 0; j < acc->n_may; ++j) {
+			int plevel;
+			isl_map *T;
+			isl_set *ran;
+
+			plevel = acc->level_before(acc->source[acc->n_must + j].data,
+						     acc->sink.data);
+			if (plevel < 0)
+				goto error;
+			if (!can_precede_at_level(plevel, level))
+				continue;
+
+			T = all_sources(acc, isl_set_copy(maydo), j, level);
+			res->dep[2 * acc->n_must + j].map =
+			    isl_map_union(res->dep[2 * acc->n_must + j].map, T);
+			T = all_sources(acc, isl_set_copy(mustdo), j, level);
+			ran = isl_map_range(isl_map_copy(T));
+			res->dep[2 * acc->n_must + j].map =
+			    isl_map_union(res->dep[2 * acc->n_must + j].map, T);
+			mustdo = isl_set_subtract(mustdo, isl_set_copy(ran));
+			maydo = isl_set_union_disjoint(maydo, ran);
+
+			T = res->dep[2 * acc->n_must + j].map;
+			T = all_intermediate_sources(acc, T, must_rel, may_rel,
+							j, level);
+			res->dep[2 * acc->n_must + j].map = T;
+		}
+
+		for (j = acc->n_must - 1; j >= 0; --j) {
+			res->dep[2 * j].map =
+				isl_map_union_disjoint(res->dep[2 * j].map,
+							     must_rel[j]);
+			res->dep[2 * j + 1].map =
+				isl_map_union_disjoint(res->dep[2 * j + 1].map,
+							     may_rel[j]);
+		}
+
+		if (isl_set_plain_is_empty(mustdo) &&
+		    isl_set_plain_is_empty(maydo))
+			break;
+	}
+
+	free(must_rel);
+	free(may_rel);
+done:
+	res->must_no_source = mustdo;
+	res->may_no_source = maydo;
+	return res;
+error:
+	if (must_rel)
+		for (j = 0; j < acc->n_must; ++j)
+			isl_map_free(must_rel[j]);
+	if (may_rel)
+		for (j = 0; j < acc->n_must; ++j)
+			isl_map_free(may_rel[j]);
+	isl_flow_free(res);
+	isl_set_free(mustdo);
+	isl_set_free(maydo);
+	free(must_rel);
+	free(may_rel);
+	return NULL;
+}
+
+/* Given a "sink" access, a list of n "source" accesses,
+ * compute for each iteration of the sink access
+ * and for each element accessed by that iteration,
+ * the source access in the list that last accessed the
+ * element accessed by the sink access before this sink access.
+ * Each access is given as a map from the loop iterators
+ * to the array indices.
+ * The result is a list of n relations between source and sink
+ * iterations and a subset of the domain of the sink access,
+ * corresponding to those iterations that access an element
+ * not previously accessed.
+ *
+ * To deal with multi-valued sink access relations, the sink iteration
+ * domain is first extended with dimensions that correspond to the data
+ * space.  However, these extra dimensions are not projected out again.
+ * It is up to the caller to decide whether these dimensions should be kept.
+ */
+static __isl_give isl_flow *access_info_compute_flow_core(
+	__isl_take isl_access_info *acc)
+{
+	struct isl_flow *res = NULL;
+
+	if (!acc)
+		return NULL;
+
+	acc->sink.map = isl_map_range_map(acc->sink.map);
+	if (!acc->sink.map)
+		goto error;
+
+	if (acc->n_must == 0)
+		res = compute_mem_based_dependences(acc);
+	else {
+		acc = isl_access_info_sort_sources(acc);
+		res = compute_val_based_dependences(acc);
+	}
+	acc = isl_access_info_free(acc);
+	if (!res)
+		return NULL;
+	if (!res->must_no_source || !res->may_no_source)
+		goto error;
+	return res;
+error:
+	isl_access_info_free(acc);
+	isl_flow_free(res);
+	return NULL;
+}
+
+/* Given a "sink" access, a list of n "source" accesses,
+ * compute for each iteration of the sink access
+ * and for each element accessed by that iteration,
+ * the source access in the list that last accessed the
+ * element accessed by the sink access before this sink access.
+ * Each access is given as a map from the loop iterators
+ * to the array indices.
+ * The result is a list of n relations between source and sink
+ * iterations and a subset of the domain of the sink access,
+ * corresponding to those iterations that access an element
+ * not previously accessed.
+ *
+ * To deal with multi-valued sink access relations,
+ * access_info_compute_flow_core extends the sink iteration domain
+ * with dimensions that correspond to the data space.  These extra dimensions
+ * are projected out from the result of access_info_compute_flow_core.
+ */
+__isl_give isl_flow *isl_access_info_compute_flow(__isl_take isl_access_info *acc)
+{
+	int j;
+	struct isl_flow *res;
+
+	if (!acc)
+		return NULL;
+
+	acc->domain_map = isl_map_domain_map(isl_map_copy(acc->sink.map));
+	res = access_info_compute_flow_core(acc);
+	if (!res)
+		return NULL;
+
+	for (j = 0; j < res->n_source; ++j) {
+		res->dep[j].map = isl_map_range_factor_domain(res->dep[j].map);
+		if (!res->dep[j].map)
+			goto error;
+	}
+
+	return res;
+error:
+	isl_flow_free(res);
+	return NULL;
+}
+
+
+/* Keep track of some information about a schedule for a given
+ * access.  In particular, keep track of which dimensions
+ * have a constant value and of the actual constant values.
+ */
+struct isl_sched_info {
+	int *is_cst;
+	isl_vec *cst;
+};
+
+static void sched_info_free(__isl_take struct isl_sched_info *info)
+{
+	if (!info)
+		return;
+	isl_vec_free(info->cst);
+	free(info->is_cst);
+	free(info);
+}
+
+/* Extract information on the constant dimensions of the schedule
+ * for a given access.  The "map" is of the form
+ *
+ *	[S -> D] -> A
+ *
+ * with S the schedule domain, D the iteration domain and A the data domain.
+ */
+static __isl_give struct isl_sched_info *sched_info_alloc(
+	__isl_keep isl_map *map)
+{
+	isl_ctx *ctx;
+	isl_space *dim;
+	struct isl_sched_info *info;
+	int i, n;
+
+	if (!map)
+		return NULL;
+
+	dim = isl_space_unwrap(isl_space_domain(isl_map_get_space(map)));
+	if (!dim)
+		return NULL;
+	n = isl_space_dim(dim, isl_dim_in);
+	isl_space_free(dim);
+
+	ctx = isl_map_get_ctx(map);
+	info = isl_alloc_type(ctx, struct isl_sched_info);
+	if (!info)
+		return NULL;
+	info->is_cst = isl_alloc_array(ctx, int, n);
+	info->cst = isl_vec_alloc(ctx, n);
+	if (n && (!info->is_cst || !info->cst))
+		goto error;
+
+	for (i = 0; i < n; ++i) {
+		isl_val *v;
+
+		v = isl_map_plain_get_val_if_fixed(map, isl_dim_in, i);
+		if (!v)
+			goto error;
+		info->is_cst[i] = !isl_val_is_nan(v);
+		if (info->is_cst[i])
+			info->cst = isl_vec_set_element_val(info->cst, i, v);
+		else
+			isl_val_free(v);
+	}
+
+	return info;
+error:
+	sched_info_free(info);
+	return NULL;
+}
+
+/* The different types of access relations that isl_union_access_info
+ * keeps track of.
+
+ * "isl_access_sink" represents the sink accesses.
+ * "isl_access_must_source" represents the definite source accesses.
+ * "isl_access_may_source" represents the possible source accesses.
+ * "isl_access_kill" represents the kills.
+ *
+ * isl_access_sink is sometimes treated differently and
+ * should therefore appear first.
+ */
+enum isl_access_type {
+	isl_access_sink,
+	isl_access_must_source,
+	isl_access_may_source,
+	isl_access_kill,
+	isl_access_end
+};
+
+/* This structure represents the input for a dependence analysis computation.
+ *
+ * "access" contains the access relations.
+ *
+ * "schedule" or "schedule_map" represents the execution order.
+ * Exactly one of these fields should be NULL.  The other field
+ * determines the execution order.
+ *
+ * The domains of these four maps refer to the same iteration spaces(s).
+ * The ranges of the first three maps also refer to the same data space(s).
+ *
+ * After a call to isl_union_access_info_introduce_schedule,
+ * the "schedule_map" field no longer contains useful information.
+ */
+struct isl_union_access_info {
+	isl_union_map *access[isl_access_end];
+
+	isl_schedule *schedule;
+	isl_union_map *schedule_map;
+};
+
+/* Free "access" and return NULL.
+ */
+__isl_null isl_union_access_info *isl_union_access_info_free(
+	__isl_take isl_union_access_info *access)
+{
+	enum isl_access_type i;
+
+	if (!access)
+		return NULL;
+
+	for (i = isl_access_sink; i < isl_access_end; ++i)
+		isl_union_map_free(access->access[i]);
+	isl_schedule_free(access->schedule);
+	isl_union_map_free(access->schedule_map);
+	free(access);
+
+	return NULL;
+}
+
+/* Return the isl_ctx to which "access" belongs.
+ */
+isl_ctx *isl_union_access_info_get_ctx(__isl_keep isl_union_access_info *access)
+{
+	if (!access)
+		return NULL;
+	return isl_union_map_get_ctx(access->access[isl_access_sink]);
+}
+
+/* Construct an empty (invalid) isl_union_access_info object.
+ * The caller is responsible for setting the sink access relation and
+ * initializing all the other fields, e.g., by calling
+ * isl_union_access_info_init.
+ */
+static __isl_give isl_union_access_info *isl_union_access_info_alloc(
+	isl_ctx *ctx)
+{
+	return isl_calloc_type(ctx, isl_union_access_info);
+}
+
+/* Initialize all the fields of "info", except the sink access relation,
+ * which is assumed to have been set by the caller.
+ *
+ * By default, we use the schedule field of the isl_union_access_info,
+ * but this may be overridden by a call
+ * to isl_union_access_info_set_schedule_map.
+ */
+static __isl_give isl_union_access_info *isl_union_access_info_init(
+	__isl_take isl_union_access_info *info)
+{
+	isl_space *space;
+	isl_union_map *empty;
+	enum isl_access_type i;
+
+	if (!info)
+		return NULL;
+	if (!info->access[isl_access_sink])
+		return isl_union_access_info_free(info);
+
+	space = isl_union_map_get_space(info->access[isl_access_sink]);
+	empty = isl_union_map_empty(isl_space_copy(space));
+	for (i = isl_access_sink + 1; i < isl_access_end; ++i)
+		if (!info->access[i])
+			info->access[i] = isl_union_map_copy(empty);
+	isl_union_map_free(empty);
+	if (!info->schedule && !info->schedule_map)
+		info->schedule = isl_schedule_empty(isl_space_copy(space));
+	isl_space_free(space);
+
+	for (i = isl_access_sink + 1; i < isl_access_end; ++i)
+		if (!info->access[i])
+			return isl_union_access_info_free(info);
+	if (!info->schedule && !info->schedule_map)
+		return isl_union_access_info_free(info);
+
+	return info;
+}
+
+/* Create a new isl_union_access_info with the given sink accesses and
+ * and no other accesses or schedule information.
+ */
+__isl_give isl_union_access_info *isl_union_access_info_from_sink(
+	__isl_take isl_union_map *sink)
+{
+	isl_ctx *ctx;
+	isl_union_access_info *access;
+
+	if (!sink)
+		return NULL;
+	ctx = isl_union_map_get_ctx(sink);
+	access = isl_union_access_info_alloc(ctx);
+	if (!access)
+		goto error;
+	access->access[isl_access_sink] = sink;
+	return isl_union_access_info_init(access);
+error:
+	isl_union_map_free(sink);
+	return NULL;
+}
+
+/* Replace the access relation of type "type" of "info" by "access".
+ */
+static __isl_give isl_union_access_info *isl_union_access_info_set(
+	__isl_take isl_union_access_info *info,
+	enum isl_access_type type, __isl_take isl_union_map *access)
+{
+	if (!info || !access)
+		goto error;
+
+	isl_union_map_free(info->access[type]);
+	info->access[type] = access;
+
+	return info;
+error:
+	isl_union_access_info_free(info);
+	isl_union_map_free(access);
+	return NULL;
+}
+
+/* Replace the definite source accesses of "access" by "must_source".
+ */
+__isl_give isl_union_access_info *isl_union_access_info_set_must_source(
+	__isl_take isl_union_access_info *access,
+	__isl_take isl_union_map *must_source)
+{
+	return isl_union_access_info_set(access, isl_access_must_source,
+					must_source);
+}
+
+/* Replace the possible source accesses of "access" by "may_source".
+ */
+__isl_give isl_union_access_info *isl_union_access_info_set_may_source(
+	__isl_take isl_union_access_info *access,
+	__isl_take isl_union_map *may_source)
+{
+	return isl_union_access_info_set(access, isl_access_may_source,
+					may_source);
+}
+
+/* Replace the kills of "info" by "kill".
+ */
+__isl_give isl_union_access_info *isl_union_access_info_set_kill(
+	__isl_take isl_union_access_info *info, __isl_take isl_union_map *kill)
+{
+	return isl_union_access_info_set(info, isl_access_kill, kill);
+}
+
+/* Return the access relation of type "type" of "info".
+ */
+static __isl_give isl_union_map *isl_union_access_info_get(
+	__isl_keep isl_union_access_info *info, enum isl_access_type type)
+{
+	if (!info)
+		return NULL;
+	return isl_union_map_copy(info->access[type]);
+}
+
+/* Return the definite source accesses of "info".
+ */
+__isl_give isl_union_map *isl_union_access_info_get_must_source(
+	__isl_keep isl_union_access_info *info)
+{
+	return isl_union_access_info_get(info, isl_access_must_source);
+}
+
+/* Return the possible source accesses of "info".
+ */
+__isl_give isl_union_map *isl_union_access_info_get_may_source(
+	__isl_keep isl_union_access_info *info)
+{
+	return isl_union_access_info_get(info, isl_access_may_source);
+}
+
+/* Return the kills of "info".
+ */
+__isl_give isl_union_map *isl_union_access_info_get_kill(
+	__isl_keep isl_union_access_info *info)
+{
+	return isl_union_access_info_get(info, isl_access_kill);
+}
+
+/* Does "info" specify any kills?
+ */
+static isl_bool isl_union_access_has_kill(
+	__isl_keep isl_union_access_info *info)
+{
+	isl_bool empty;
+
+	if (!info)
+		return isl_bool_error;
+	empty = isl_union_map_is_empty(info->access[isl_access_kill]);
+	return isl_bool_not(empty);
+}
+
+/* Replace the schedule of "access" by "schedule".
+ * Also free the schedule_map in case it was set last.
+ */
+__isl_give isl_union_access_info *isl_union_access_info_set_schedule(
+	__isl_take isl_union_access_info *access,
+	__isl_take isl_schedule *schedule)
+{
+	if (!access || !schedule)
+		goto error;
+
+	access->schedule_map = isl_union_map_free(access->schedule_map);
+	isl_schedule_free(access->schedule);
+	access->schedule = schedule;
+
+	return access;
+error:
+	isl_union_access_info_free(access);
+	isl_schedule_free(schedule);
+	return NULL;
+}
+
+/* Replace the schedule map of "access" by "schedule_map".
+ * Also free the schedule in case it was set last.
+ */
+__isl_give isl_union_access_info *isl_union_access_info_set_schedule_map(
+	__isl_take isl_union_access_info *access,
+	__isl_take isl_union_map *schedule_map)
+{
+	if (!access || !schedule_map)
+		goto error;
+
+	isl_union_map_free(access->schedule_map);
+	access->schedule = isl_schedule_free(access->schedule);
+	access->schedule_map = schedule_map;
+
+	return access;
+error:
+	isl_union_access_info_free(access);
+	isl_union_map_free(schedule_map);
+	return NULL;
+}
+
+__isl_give isl_union_access_info *isl_union_access_info_copy(
+	__isl_keep isl_union_access_info *access)
+{
+	isl_union_access_info *copy;
+	enum isl_access_type i;
+
+	if (!access)
+		return NULL;
+	copy = isl_union_access_info_from_sink(
+		    isl_union_map_copy(access->access[isl_access_sink]));
+	for (i = isl_access_sink + 1; i < isl_access_end; ++i)
+		copy = isl_union_access_info_set(copy, i,
+					isl_union_map_copy(access->access[i]));
+	if (access->schedule)
+		copy = isl_union_access_info_set_schedule(copy,
+				isl_schedule_copy(access->schedule));
+	else
+		copy = isl_union_access_info_set_schedule_map(copy,
+				isl_union_map_copy(access->schedule_map));
+
+	return copy;
+}
+
+/* Print a key-value pair of a YAML mapping to "p",
+ * with key "name" and value "umap".
+ */
+static __isl_give isl_printer *print_union_map_field(__isl_take isl_printer *p,
+	const char *name, __isl_keep isl_union_map *umap)
+{
+	p = isl_printer_print_str(p, name);
+	p = isl_printer_yaml_next(p);
+	p = isl_printer_print_str(p, "\"");
+	p = isl_printer_print_union_map(p, umap);
+	p = isl_printer_print_str(p, "\"");
+	p = isl_printer_yaml_next(p);
+
+	return p;
+}
+
+/* An enumeration of the various keys that may appear in a YAML mapping
+ * of an isl_union_access_info object.
+ * The keys for the access relation types are assumed to have the same values
+ * as the access relation types in isl_access_type.
+ */
+enum isl_ai_key {
+	isl_ai_key_error = -1,
+	isl_ai_key_sink = isl_access_sink,
+	isl_ai_key_must_source = isl_access_must_source,
+	isl_ai_key_may_source = isl_access_may_source,
+	isl_ai_key_kill = isl_access_kill,
+	isl_ai_key_schedule_map,
+	isl_ai_key_schedule,
+	isl_ai_key_end
+};
+
+/* Textual representations of the YAML keys for an isl_union_access_info
+ * object.
+ */
+static char *key_str[] = {
+	[isl_ai_key_sink] = "sink",
+	[isl_ai_key_must_source] = "must_source",
+	[isl_ai_key_may_source] = "may_source",
+	[isl_ai_key_kill] = "kill",
+	[isl_ai_key_schedule_map] = "schedule_map",
+	[isl_ai_key_schedule] = "schedule",
+};
+
+/* Print a key-value pair corresponding to the access relation of type "type"
+ * of a YAML mapping of "info" to "p".
+ *
+ * The sink access relation is always printed, but any other access relation
+ * is only printed if it is non-empty.
+ */
+static __isl_give isl_printer *print_access_field(__isl_take isl_printer *p,
+	__isl_keep isl_union_access_info *info, enum isl_access_type type)
+{
+	if (type != isl_access_sink) {
+		isl_bool empty;
+
+		empty = isl_union_map_is_empty(info->access[type]);
+		if (empty < 0)
+			return isl_printer_free(p);
+		if (empty)
+			return p;
+	}
+	return print_union_map_field(p, key_str[type], info->access[type]);
+}
+
+/* Print the information contained in "access" to "p".
+ * The information is printed as a YAML document.
+ */
+__isl_give isl_printer *isl_printer_print_union_access_info(
+	__isl_take isl_printer *p, __isl_keep isl_union_access_info *access)
+{
+	enum isl_access_type i;
+
+	if (!access)
+		return isl_printer_free(p);
+
+	p = isl_printer_yaml_start_mapping(p);
+	for (i = isl_access_sink; i < isl_access_end; ++i)
+		p = print_access_field(p, access, i);
+	if (access->schedule) {
+		p = isl_printer_print_str(p, key_str[isl_ai_key_schedule]);
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_schedule(p, access->schedule);
+		p = isl_printer_yaml_next(p);
+	} else {
+		p = print_union_map_field(p, key_str[isl_ai_key_schedule_map],
+						access->schedule_map);
+	}
+	p = isl_printer_yaml_end_mapping(p);
+
+	return p;
+}
+
+/* Return a string representation of the information in "access".
+ * The information is printed in flow format.
+ */
+__isl_give char *isl_union_access_info_to_str(
+	__isl_keep isl_union_access_info *access)
+{
+	isl_printer *p;
+	char *s;
+
+	if (!access)
+		return NULL;
+
+	p = isl_printer_to_str(isl_union_access_info_get_ctx(access));
+	p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
+	p = isl_printer_print_union_access_info(p, access);
+	s = isl_printer_get_str(p);
+	isl_printer_free(p);
+
+	return s;
+}
+
+#undef KEY
+#define KEY enum isl_ai_key
+#undef KEY_ERROR
+#define KEY_ERROR isl_ai_key_error
+#undef KEY_END
+#define KEY_END isl_ai_key_end
+#include "extract_key.c"
+
+#undef BASE
+#define BASE union_map
+#include "read_in_string_templ.c"
+
+/* Read an isl_union_access_info object from "s".
+ *
+ * Start off with an empty (invalid) isl_union_access_info object and
+ * then fill up the fields based on the input.
+ * The input needs to contain at least a description of the sink
+ * access relation as well as some form of schedule.
+ * The other access relations are set to empty relations
+ * by isl_union_access_info_init if they are not specified in the input.
+ */
+__isl_give isl_union_access_info *isl_stream_read_union_access_info(
+	isl_stream *s)
+{
+	isl_ctx *ctx;
+	isl_union_access_info *info;
+	int more;
+	int sink_set = 0;
+	int schedule_set = 0;
+
+	if (isl_stream_yaml_read_start_mapping(s))
+		return NULL;
+
+	ctx = isl_stream_get_ctx(s);
+	info = isl_union_access_info_alloc(ctx);
+	while ((more = isl_stream_yaml_next(s)) > 0) {
+		enum isl_ai_key key;
+		isl_union_map *access, *schedule_map;
+		isl_schedule *schedule;
+
+		key = get_key(s);
+		if (isl_stream_yaml_next(s) < 0)
+			return isl_union_access_info_free(info);
+		switch (key) {
+		case isl_ai_key_end:
+		case isl_ai_key_error:
+			return isl_union_access_info_free(info);
+		case isl_ai_key_sink:
+			sink_set = 1;
+		case isl_ai_key_must_source:
+		case isl_ai_key_may_source:
+		case isl_ai_key_kill:
+			access = read_union_map(s);
+			info = isl_union_access_info_set(info, key, access);
+			if (!info)
+				return NULL;
+			break;
+		case isl_ai_key_schedule_map:
+			schedule_set = 1;
+			schedule_map = read_union_map(s);
+			info = isl_union_access_info_set_schedule_map(info,
+								schedule_map);
+			if (!info)
+				return NULL;
+			break;
+		case isl_ai_key_schedule:
+			schedule_set = 1;
+			schedule = isl_stream_read_schedule(s);
+			info = isl_union_access_info_set_schedule(info,
+								schedule);
+			if (!info)
+				return NULL;
+			break;
+		}
+	}
+	if (more < 0)
+		return isl_union_access_info_free(info);
+
+	if (isl_stream_yaml_read_end_mapping(s) < 0) {
+		isl_stream_error(s, NULL, "unexpected extra elements");
+		return isl_union_access_info_free(info);
+	}
+
+	if (!sink_set) {
+		isl_stream_error(s, NULL, "no sink specified");
+		return isl_union_access_info_free(info);
+	}
+
+	if (!schedule_set) {
+		isl_stream_error(s, NULL, "no schedule specified");
+		return isl_union_access_info_free(info);
+	}
+
+	return isl_union_access_info_init(info);
+}
+
+/* Read an isl_union_access_info object from the file "input".
+ */
+__isl_give isl_union_access_info *isl_union_access_info_read_from_file(
+	isl_ctx *ctx, FILE *input)
+{
+	isl_stream *s;
+	isl_union_access_info *access;
+
+	s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	access = isl_stream_read_union_access_info(s);
+	isl_stream_free(s);
+
+	return access;
+}
+
+/* Update the fields of "access" such that they all have the same parameters,
+ * keeping in mind that the schedule_map field may be NULL and ignoring
+ * the schedule field.
+ */
+static __isl_give isl_union_access_info *isl_union_access_info_align_params(
+	__isl_take isl_union_access_info *access)
+{
+	isl_space *space;
+	enum isl_access_type i;
+
+	if (!access)
+		return NULL;
+
+	space = isl_union_map_get_space(access->access[isl_access_sink]);
+	for (i = isl_access_sink + 1; i < isl_access_end; ++i)
+		space = isl_space_align_params(space,
+				isl_union_map_get_space(access->access[i]));
+	if (access->schedule_map)
+		space = isl_space_align_params(space,
+				isl_union_map_get_space(access->schedule_map));
+	for (i = isl_access_sink; i < isl_access_end; ++i)
+		access->access[i] =
+			isl_union_map_align_params(access->access[i],
+							isl_space_copy(space));
+	if (!access->schedule_map) {
+		isl_space_free(space);
+	} else {
+		access->schedule_map =
+		    isl_union_map_align_params(access->schedule_map, space);
+		if (!access->schedule_map)
+			return isl_union_access_info_free(access);
+	}
+
+	for (i = isl_access_sink; i < isl_access_end; ++i)
+		if (!access->access[i])
+			return isl_union_access_info_free(access);
+
+	return access;
+}
+
+/* Prepend the schedule dimensions to the iteration domains.
+ *
+ * That is, if the schedule is of the form
+ *
+ *	D -> S
+ *
+ * while the access relations are of the form
+ *
+ *	D -> A
+ *
+ * then the updated access relations are of the form
+ *
+ *	[S -> D] -> A
+ *
+ * The schedule map is also replaced by the map
+ *
+ *	[S -> D] -> D
+ *
+ * that is used during the internal computation.
+ * Neither the original schedule map nor this updated schedule map
+ * are used after the call to this function.
+ */
+static __isl_give isl_union_access_info *
+isl_union_access_info_introduce_schedule(
+	__isl_take isl_union_access_info *access)
+{
+	isl_union_map *sm;
+	enum isl_access_type i;
+
+	if (!access)
+		return NULL;
+
+	sm = isl_union_map_reverse(access->schedule_map);
+	sm = isl_union_map_range_map(sm);
+	for (i = isl_access_sink; i < isl_access_end; ++i)
+		access->access[i] =
+			isl_union_map_apply_range(isl_union_map_copy(sm),
+						access->access[i]);
+	access->schedule_map = sm;
+
+	for (i = isl_access_sink; i < isl_access_end; ++i)
+		if (!access->access[i])
+			return isl_union_access_info_free(access);
+	if (!access->schedule_map)
+		return isl_union_access_info_free(access);
+
+	return access;
+}
+
+/* This structure represents the result of a dependence analysis computation.
+ *
+ * "must_dep" represents the full definite dependences
+ * "may_dep" represents the full non-definite dependences.
+ * Both are of the form
+ *
+ *	[Source] -> [[Sink -> Data]]
+ *
+ * (after the schedule dimensions have been projected out).
+ * "must_no_source" represents the subset of the sink accesses for which
+ * definitely no source was found.
+ * "may_no_source" represents the subset of the sink accesses for which
+ * possibly, but not definitely, no source was found.
+ */
+struct isl_union_flow {
+	isl_union_map *must_dep;
+	isl_union_map *may_dep;
+	isl_union_map *must_no_source;
+	isl_union_map *may_no_source;
+};
+
+/* Return the isl_ctx to which "flow" belongs.
+ */
+isl_ctx *isl_union_flow_get_ctx(__isl_keep isl_union_flow *flow)
+{
+	return flow ? isl_union_map_get_ctx(flow->must_dep) : NULL;
+}
+
+/* Free "flow" and return NULL.
+ */
+__isl_null isl_union_flow *isl_union_flow_free(__isl_take isl_union_flow *flow)
+{
+	if (!flow)
+		return NULL;
+	isl_union_map_free(flow->must_dep);
+	isl_union_map_free(flow->may_dep);
+	isl_union_map_free(flow->must_no_source);
+	isl_union_map_free(flow->may_no_source);
+	free(flow);
+	return NULL;
+}
+
+void isl_union_flow_dump(__isl_keep isl_union_flow *flow)
+{
+	if (!flow)
+		return;
+
+	fprintf(stderr, "must dependences: ");
+	isl_union_map_dump(flow->must_dep);
+	fprintf(stderr, "may dependences: ");
+	isl_union_map_dump(flow->may_dep);
+	fprintf(stderr, "must no source: ");
+	isl_union_map_dump(flow->must_no_source);
+	fprintf(stderr, "may no source: ");
+	isl_union_map_dump(flow->may_no_source);
+}
+
+/* Return the full definite dependences in "flow", with accessed elements.
+ */
+__isl_give isl_union_map *isl_union_flow_get_full_must_dependence(
+	__isl_keep isl_union_flow *flow)
+{
+	if (!flow)
+		return NULL;
+	return isl_union_map_copy(flow->must_dep);
+}
+
+/* Return the full possible dependences in "flow", including the definite
+ * dependences, with accessed elements.
+ */
+__isl_give isl_union_map *isl_union_flow_get_full_may_dependence(
+	__isl_keep isl_union_flow *flow)
+{
+	if (!flow)
+		return NULL;
+	return isl_union_map_union(isl_union_map_copy(flow->must_dep),
+				    isl_union_map_copy(flow->may_dep));
+}
+
+/* Return the definite dependences in "flow", without the accessed elements.
+ */
+__isl_give isl_union_map *isl_union_flow_get_must_dependence(
+	__isl_keep isl_union_flow *flow)
+{
+	isl_union_map *dep;
+
+	if (!flow)
+		return NULL;
+	dep = isl_union_map_copy(flow->must_dep);
+	return isl_union_map_range_factor_domain(dep);
+}
+
+/* Return the possible dependences in "flow", including the definite
+ * dependences, without the accessed elements.
+ */
+__isl_give isl_union_map *isl_union_flow_get_may_dependence(
+	__isl_keep isl_union_flow *flow)
+{
+	isl_union_map *dep;
+
+	if (!flow)
+		return NULL;
+	dep = isl_union_map_union(isl_union_map_copy(flow->must_dep),
+				    isl_union_map_copy(flow->may_dep));
+	return isl_union_map_range_factor_domain(dep);
+}
+
+/* Return the non-definite dependences in "flow".
+ */
+static __isl_give isl_union_map *isl_union_flow_get_non_must_dependence(
+	__isl_keep isl_union_flow *flow)
+{
+	if (!flow)
+		return NULL;
+	return isl_union_map_copy(flow->may_dep);
+}
+
+/* Return the subset of the sink accesses for which definitely
+ * no source was found.
+ */
+__isl_give isl_union_map *isl_union_flow_get_must_no_source(
+	__isl_keep isl_union_flow *flow)
+{
+	if (!flow)
+		return NULL;
+	return isl_union_map_copy(flow->must_no_source);
+}
+
+/* Return the subset of the sink accesses for which possibly
+ * no source was found, including those for which definitely
+ * no source was found.
+ */
+__isl_give isl_union_map *isl_union_flow_get_may_no_source(
+	__isl_keep isl_union_flow *flow)
+{
+	if (!flow)
+		return NULL;
+	return isl_union_map_union(isl_union_map_copy(flow->must_no_source),
+				    isl_union_map_copy(flow->may_no_source));
+}
+
+/* Return the subset of the sink accesses for which possibly, but not
+ * definitely, no source was found.
+ */
+static __isl_give isl_union_map *isl_union_flow_get_non_must_no_source(
+	__isl_keep isl_union_flow *flow)
+{
+	if (!flow)
+		return NULL;
+	return isl_union_map_copy(flow->may_no_source);
+}
+
+/* Create a new isl_union_flow object, initialized with empty
+ * dependence relations and sink subsets.
+ */
+static __isl_give isl_union_flow *isl_union_flow_alloc(
+	__isl_take isl_space *space)
+{
+	isl_ctx *ctx;
+	isl_union_map *empty;
+	isl_union_flow *flow;
+
+	if (!space)
+		return NULL;
+	ctx = isl_space_get_ctx(space);
+	flow = isl_alloc_type(ctx, isl_union_flow);
+	if (!flow)
+		goto error;
+
+	empty = isl_union_map_empty(space);
+	flow->must_dep = isl_union_map_copy(empty);
+	flow->may_dep = isl_union_map_copy(empty);
+	flow->must_no_source = isl_union_map_copy(empty);
+	flow->may_no_source = empty;
+
+	if (!flow->must_dep || !flow->may_dep ||
+	    !flow->must_no_source || !flow->may_no_source)
+		return isl_union_flow_free(flow);
+
+	return flow;
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Copy this isl_union_flow object.
+ */
+__isl_give isl_union_flow *isl_union_flow_copy(__isl_keep isl_union_flow *flow)
+{
+	isl_union_flow *copy;
+
+	if (!flow)
+		return NULL;
+
+	copy = isl_union_flow_alloc(isl_union_map_get_space(flow->must_dep));
+
+	if (!copy)
+		return NULL;
+
+	copy->must_dep = isl_union_map_union(copy->must_dep,
+		isl_union_map_copy(flow->must_dep));
+	copy->may_dep = isl_union_map_union(copy->may_dep,
+		isl_union_map_copy(flow->may_dep));
+	copy->must_no_source = isl_union_map_union(copy->must_no_source,
+		isl_union_map_copy(flow->must_no_source));
+	copy->may_no_source = isl_union_map_union(copy->may_no_source,
+		isl_union_map_copy(flow->may_no_source));
+
+	if (!copy->must_dep || !copy->may_dep ||
+	    !copy->must_no_source || !copy->may_no_source)
+		return isl_union_flow_free(copy);
+
+	return copy;
+}
+
+/* Drop the schedule dimensions from the iteration domains in "flow".
+ * In particular, the schedule dimensions have been prepended
+ * to the iteration domains prior to the dependence analysis by
+ * replacing the iteration domain D, by the wrapped map [S -> D].
+ * Replace these wrapped maps by the original D.
+ *
+ * In particular, the dependences computed by access_info_compute_flow_core
+ * are of the form
+ *
+ *	[S -> D] -> [[S' -> D'] -> A]
+ *
+ * The schedule dimensions are projected out by first currying the range,
+ * resulting in
+ *
+ *	[S -> D] -> [S' -> [D' -> A]]
+ *
+ * and then computing the factor range
+ *
+ *	D -> [D' -> A]
+ */
+static __isl_give isl_union_flow *isl_union_flow_drop_schedule(
+	__isl_take isl_union_flow *flow)
+{
+	if (!flow)
+		return NULL;
+
+	flow->must_dep = isl_union_map_range_curry(flow->must_dep);
+	flow->must_dep = isl_union_map_factor_range(flow->must_dep);
+	flow->may_dep = isl_union_map_range_curry(flow->may_dep);
+	flow->may_dep = isl_union_map_factor_range(flow->may_dep);
+	flow->must_no_source =
+		isl_union_map_domain_factor_range(flow->must_no_source);
+	flow->may_no_source =
+		isl_union_map_domain_factor_range(flow->may_no_source);
+
+	if (!flow->must_dep || !flow->may_dep ||
+	    !flow->must_no_source || !flow->may_no_source)
+		return isl_union_flow_free(flow);
+
+	return flow;
+}
+
+struct isl_compute_flow_data {
+	isl_union_map *must_source;
+	isl_union_map *may_source;
+	isl_union_flow *flow;
+
+	int count;
+	int must;
+	isl_space *dim;
+	struct isl_sched_info *sink_info;
+	struct isl_sched_info **source_info;
+	isl_access_info *accesses;
+};
+
+static isl_stat count_matching_array(__isl_take isl_map *map, void *user)
+{
+	int eq;
+	isl_space *dim;
+	struct isl_compute_flow_data *data;
+
+	data = (struct isl_compute_flow_data *)user;
+
+	dim = isl_space_range(isl_map_get_space(map));
+
+	eq = isl_space_is_equal(dim, data->dim);
+
+	isl_space_free(dim);
+	isl_map_free(map);
+
+	if (eq < 0)
+		return isl_stat_error;
+	if (eq)
+		data->count++;
+
+	return isl_stat_ok;
+}
+
+static isl_stat collect_matching_array(__isl_take isl_map *map, void *user)
+{
+	int eq;
+	isl_space *dim;
+	struct isl_sched_info *info;
+	struct isl_compute_flow_data *data;
+
+	data = (struct isl_compute_flow_data *)user;
+
+	dim = isl_space_range(isl_map_get_space(map));
+
+	eq = isl_space_is_equal(dim, data->dim);
+
+	isl_space_free(dim);
+
+	if (eq < 0)
+		goto error;
+	if (!eq) {
+		isl_map_free(map);
+		return isl_stat_ok;
+	}
+
+	info = sched_info_alloc(map);
+	data->source_info[data->count] = info;
+
+	data->accesses = isl_access_info_add_source(data->accesses,
+						    map, data->must, info);
+
+	data->count++;
+
+	return isl_stat_ok;
+error:
+	isl_map_free(map);
+	return isl_stat_error;
+}
+
+/* Determine the shared nesting level and the "textual order" of
+ * the given accesses.
+ *
+ * We first determine the minimal schedule dimension for both accesses.
+ *
+ * If among those dimensions, we can find one where both have a fixed
+ * value and if moreover those values are different, then the previous
+ * dimension is the last shared nesting level and the textual order
+ * is determined based on the order of the fixed values.
+ * If no such fixed values can be found, then we set the shared
+ * nesting level to the minimal schedule dimension, with no textual ordering.
+ */
+static int before(void *first, void *second)
+{
+	struct isl_sched_info *info1 = first;
+	struct isl_sched_info *info2 = second;
+	int n1, n2;
+	int i;
+
+	n1 = isl_vec_size(info1->cst);
+	n2 = isl_vec_size(info2->cst);
+
+	if (n2 < n1)
+		n1 = n2;
+
+	for (i = 0; i < n1; ++i) {
+		int r;
+		int cmp;
+
+		if (!info1->is_cst[i])
+			continue;
+		if (!info2->is_cst[i])
+			continue;
+		cmp = isl_vec_cmp_element(info1->cst, info2->cst, i);
+		if (cmp == 0)
+			continue;
+
+		r = 2 * i + (cmp < 0);
+
+		return r;
+	}
+
+	return 2 * n1;
+}
+
+/* Check if the given two accesses may be coscheduled.
+ * If so, return 1.  Otherwise return 0.
+ *
+ * Two accesses may only be coscheduled if the fixed schedule
+ * coordinates have the same values.
+ */
+static int coscheduled(void *first, void *second)
+{
+	struct isl_sched_info *info1 = first;
+	struct isl_sched_info *info2 = second;
+	int n1, n2;
+	int i;
+
+	n1 = isl_vec_size(info1->cst);
+	n2 = isl_vec_size(info2->cst);
+
+	if (n2 < n1)
+		n1 = n2;
+
+	for (i = 0; i < n1; ++i) {
+		int cmp;
+
+		if (!info1->is_cst[i])
+			continue;
+		if (!info2->is_cst[i])
+			continue;
+		cmp = isl_vec_cmp_element(info1->cst, info2->cst, i);
+		if (cmp != 0)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Given a sink access, look for all the source accesses that access
+ * the same array and perform dataflow analysis on them using
+ * isl_access_info_compute_flow_core.
+ */
+static isl_stat compute_flow(__isl_take isl_map *map, void *user)
+{
+	int i;
+	isl_ctx *ctx;
+	struct isl_compute_flow_data *data;
+	isl_flow *flow;
+	isl_union_flow *df;
+
+	data = (struct isl_compute_flow_data *)user;
+	df = data->flow;
+
+	ctx = isl_map_get_ctx(map);
+
+	data->accesses = NULL;
+	data->sink_info = NULL;
+	data->source_info = NULL;
+	data->count = 0;
+	data->dim = isl_space_range(isl_map_get_space(map));
+
+	if (isl_union_map_foreach_map(data->must_source,
+					&count_matching_array, data) < 0)
+		goto error;
+	if (isl_union_map_foreach_map(data->may_source,
+					&count_matching_array, data) < 0)
+		goto error;
+
+	data->sink_info = sched_info_alloc(map);
+	data->source_info = isl_calloc_array(ctx, struct isl_sched_info *,
+					     data->count);
+
+	data->accesses = isl_access_info_alloc(isl_map_copy(map),
+				data->sink_info, &before, data->count);
+	if (!data->sink_info || (data->count && !data->source_info) ||
+	    !data->accesses)
+		goto error;
+	data->accesses->coscheduled = &coscheduled;
+	data->count = 0;
+	data->must = 1;
+	if (isl_union_map_foreach_map(data->must_source,
+					&collect_matching_array, data) < 0)
+		goto error;
+	data->must = 0;
+	if (isl_union_map_foreach_map(data->may_source,
+					&collect_matching_array, data) < 0)
+		goto error;
+
+	flow = access_info_compute_flow_core(data->accesses);
+	data->accesses = NULL;
+
+	if (!flow)
+		goto error;
+
+	df->must_no_source = isl_union_map_union(df->must_no_source,
+		    isl_union_map_from_map(isl_flow_get_no_source(flow, 1)));
+	df->may_no_source = isl_union_map_union(df->may_no_source,
+		    isl_union_map_from_map(isl_flow_get_no_source(flow, 0)));
+
+	for (i = 0; i < flow->n_source; ++i) {
+		isl_union_map *dep;
+		dep = isl_union_map_from_map(isl_map_copy(flow->dep[i].map));
+		if (flow->dep[i].must)
+			df->must_dep = isl_union_map_union(df->must_dep, dep);
+		else
+			df->may_dep = isl_union_map_union(df->may_dep, dep);
+	}
+
+	isl_flow_free(flow);
+
+	sched_info_free(data->sink_info);
+	if (data->source_info) {
+		for (i = 0; i < data->count; ++i)
+			sched_info_free(data->source_info[i]);
+		free(data->source_info);
+	}
+	isl_space_free(data->dim);
+	isl_map_free(map);
+
+	return isl_stat_ok;
+error:
+	isl_access_info_free(data->accesses);
+	sched_info_free(data->sink_info);
+	if (data->source_info) {
+		for (i = 0; i < data->count; ++i)
+			sched_info_free(data->source_info[i]);
+		free(data->source_info);
+	}
+	isl_space_free(data->dim);
+	isl_map_free(map);
+
+	return isl_stat_error;
+}
+
+/* Add the kills of "info" to the must-sources.
+ */
+static __isl_give isl_union_access_info *
+isl_union_access_info_add_kill_to_must_source(
+	__isl_take isl_union_access_info *info)
+{
+	isl_union_map *must, *kill;
+
+	must = isl_union_access_info_get_must_source(info);
+	kill = isl_union_access_info_get_kill(info);
+	must = isl_union_map_union(must, kill);
+	return isl_union_access_info_set_must_source(info, must);
+}
+
+/* Drop dependences from "flow" that purely originate from kills.
+ * That is, only keep those dependences that originate from
+ * the original must-sources "must" and/or the original may-sources "may".
+ * In particular, "must" contains the must-sources from before
+ * the kills were added and "may" contains the may-source from before
+ * the kills were removed.
+ *
+ * The dependences are of the form
+ *
+ *	Source -> [Sink -> Data]
+ *
+ * Only those dependences are kept where the Source -> Data part
+ * is a subset of the original may-sources or must-sources.
+ * Of those, only the must-dependences that intersect with the must-sources
+ * remain must-dependences.
+ * If there is some overlap between the may-sources and the must-sources,
+ * then the may-dependences and must-dependences may also overlap.
+ * This should be fine since the may-dependences are only kept
+ * disjoint from the must-dependences for the isl_union_map_compute_flow
+ * interface.  This interface does not support kills, so it will
+ * not end up calling this function.
+ */
+static __isl_give isl_union_flow *isl_union_flow_drop_kill_source(
+	__isl_take isl_union_flow *flow, __isl_take isl_union_map *must,
+	__isl_take isl_union_map *may)
+{
+	isl_union_map *move;
+
+	if (!flow)
+		goto error;
+	move = isl_union_map_copy(flow->must_dep);
+	move = isl_union_map_intersect_range_factor_range(move,
+				isl_union_map_copy(may));
+	may = isl_union_map_union(may, isl_union_map_copy(must));
+	flow->may_dep = isl_union_map_intersect_range_factor_range(
+				flow->may_dep, may);
+	flow->must_dep = isl_union_map_intersect_range_factor_range(
+				flow->must_dep, must);
+	flow->may_dep = isl_union_map_union(flow->may_dep, move);
+	if (!flow->must_dep || !flow->may_dep)
+		return isl_union_flow_free(flow);
+
+	return flow;
+error:
+	isl_union_map_free(must);
+	isl_union_map_free(may);
+	return NULL;
+}
+
+/* Remove the must accesses from the may accesses.
+ *
+ * A must access always trumps a may access, so there is no need
+ * for a must access to also be considered as a may access.  Doing so
+ * would only cost extra computations only to find out that
+ * the duplicated may access does not make any difference.
+ */
+static __isl_give isl_union_access_info *isl_union_access_info_normalize(
+	__isl_take isl_union_access_info *access)
+{
+	if (!access)
+		return NULL;
+	access->access[isl_access_may_source] =
+		isl_union_map_subtract(access->access[isl_access_may_source],
+		    isl_union_map_copy(access->access[isl_access_must_source]));
+	if (!access->access[isl_access_may_source])
+		return isl_union_access_info_free(access);
+
+	return access;
+}
+
+/* Given a description of the "sink" accesses, the "source" accesses and
+ * a schedule, compute for each instance of a sink access
+ * and for each element accessed by that instance,
+ * the possible or definite source accesses that last accessed the
+ * element accessed by the sink access before this sink access
+ * in the sense that there is no intermediate definite source access.
+ *
+ * The must_no_source and may_no_source elements of the result
+ * are subsets of access->sink.  The elements must_dep and may_dep
+ * map domain elements of access->{may,must)_source to
+ * domain elements of access->sink.
+ *
+ * This function is used when only the schedule map representation
+ * is available.
+ *
+ * We first prepend the schedule dimensions to the domain
+ * of the accesses so that we can easily compare their relative order.
+ * Then we consider each sink access individually in compute_flow.
+ */
+static __isl_give isl_union_flow *compute_flow_union_map(
+	__isl_take isl_union_access_info *access)
+{
+	struct isl_compute_flow_data data;
+	isl_union_map *sink;
+
+	access = isl_union_access_info_align_params(access);
+	access = isl_union_access_info_introduce_schedule(access);
+	if (!access)
+		return NULL;
+
+	data.must_source = access->access[isl_access_must_source];
+	data.may_source = access->access[isl_access_may_source];
+
+	sink = access->access[isl_access_sink];
+	data.flow = isl_union_flow_alloc(isl_union_map_get_space(sink));
+
+	if (isl_union_map_foreach_map(sink, &compute_flow, &data) < 0)
+		goto error;
+
+	data.flow = isl_union_flow_drop_schedule(data.flow);
+
+	isl_union_access_info_free(access);
+	return data.flow;
+error:
+	isl_union_access_info_free(access);
+	isl_union_flow_free(data.flow);
+	return NULL;
+}
+
+/* A schedule access relation.
+ *
+ * The access relation "access" is of the form [S -> D] -> A,
+ * where S corresponds to the prefix schedule at "node".
+ * "must" is only relevant for source accesses and indicates
+ * whether the access is a must source or a may source.
+ */
+struct isl_scheduled_access {
+	isl_map *access;
+	int must;
+	isl_schedule_node *node;
+};
+
+/* Data structure for keeping track of individual scheduled sink and source
+ * accesses when computing dependence analysis based on a schedule tree.
+ *
+ * "n_sink" is the number of used entries in "sink"
+ * "n_source" is the number of used entries in "source"
+ *
+ * "set_sink", "must" and "node" are only used inside collect_sink_source,
+ * to keep track of the current node and
+ * of what extract_sink_source needs to do.
+ */
+struct isl_compute_flow_schedule_data {
+	isl_union_access_info *access;
+
+	int n_sink;
+	int n_source;
+
+	struct isl_scheduled_access *sink;
+	struct isl_scheduled_access *source;
+
+	int set_sink;
+	int must;
+	isl_schedule_node *node;
+};
+
+/* Align the parameters of all sinks with all sources.
+ *
+ * If there are no sinks or no sources, then no alignment is needed.
+ */
+static void isl_compute_flow_schedule_data_align_params(
+	struct isl_compute_flow_schedule_data *data)
+{
+	int i;
+	isl_space *space;
+
+	if (data->n_sink == 0 || data->n_source == 0)
+		return;
+
+	space = isl_map_get_space(data->sink[0].access);
+
+	for (i = 1; i < data->n_sink; ++i)
+		space = isl_space_align_params(space,
+				isl_map_get_space(data->sink[i].access));
+	for (i = 0; i < data->n_source; ++i)
+		space = isl_space_align_params(space,
+				isl_map_get_space(data->source[i].access));
+
+	for (i = 0; i < data->n_sink; ++i)
+		data->sink[i].access =
+			isl_map_align_params(data->sink[i].access,
+							isl_space_copy(space));
+	for (i = 0; i < data->n_source; ++i)
+		data->source[i].access =
+			isl_map_align_params(data->source[i].access,
+							isl_space_copy(space));
+
+	isl_space_free(space);
+}
+
+/* Free all the memory referenced from "data".
+ * Do not free "data" itself as it may be allocated on the stack.
+ */
+static void isl_compute_flow_schedule_data_clear(
+	struct isl_compute_flow_schedule_data *data)
+{
+	int i;
+
+	if (!data->sink)
+		return;
+
+	for (i = 0; i < data->n_sink; ++i) {
+		isl_map_free(data->sink[i].access);
+		isl_schedule_node_free(data->sink[i].node);
+	}
+
+	for (i = 0; i < data->n_source; ++i) {
+		isl_map_free(data->source[i].access);
+		isl_schedule_node_free(data->source[i].node);
+	}
+
+	free(data->sink);
+}
+
+/* isl_schedule_foreach_schedule_node_top_down callback for counting
+ * (an upper bound on) the number of sinks and sources.
+ *
+ * Sinks and sources are only extracted at leaves of the tree,
+ * so we skip the node if it is not a leaf.
+ * Otherwise we increment data->n_sink and data->n_source with
+ * the number of spaces in the sink and source access domains
+ * that reach this node.
+ */
+static isl_bool count_sink_source(__isl_keep isl_schedule_node *node,
+	void *user)
+{
+	struct isl_compute_flow_schedule_data *data = user;
+	isl_union_set *domain;
+	isl_union_map *umap;
+	isl_bool r = isl_bool_false;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_leaf)
+		return isl_bool_true;
+
+	domain = isl_schedule_node_get_universe_domain(node);
+
+	umap = isl_union_map_copy(data->access->access[isl_access_sink]);
+	umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(domain));
+	data->n_sink += isl_union_map_n_map(umap);
+	isl_union_map_free(umap);
+	if (!umap)
+		r = isl_bool_error;
+
+	umap = isl_union_map_copy(data->access->access[isl_access_must_source]);
+	umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(domain));
+	data->n_source += isl_union_map_n_map(umap);
+	isl_union_map_free(umap);
+	if (!umap)
+		r = isl_bool_error;
+
+	umap = isl_union_map_copy(data->access->access[isl_access_may_source]);
+	umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(domain));
+	data->n_source += isl_union_map_n_map(umap);
+	isl_union_map_free(umap);
+	if (!umap)
+		r = isl_bool_error;
+
+	isl_union_set_free(domain);
+
+	return r;
+}
+
+/* Add a single scheduled sink or source (depending on data->set_sink)
+ * with scheduled access relation "map", must property data->must and
+ * schedule node data->node to the list of sinks or sources.
+ */
+static isl_stat extract_sink_source(__isl_take isl_map *map, void *user)
+{
+	struct isl_compute_flow_schedule_data *data = user;
+	struct isl_scheduled_access *access;
+
+	if (data->set_sink)
+		access = data->sink + data->n_sink++;
+	else
+		access = data->source + data->n_source++;
+
+	access->access = map;
+	access->must = data->must;
+	access->node = isl_schedule_node_copy(data->node);
+
+	return isl_stat_ok;
+}
+
+/* isl_schedule_foreach_schedule_node_top_down callback for collecting
+ * individual scheduled source and sink accesses (taking into account
+ * the domain of the schedule).
+ *
+ * We only collect accesses at the leaves of the schedule tree.
+ * We prepend the schedule dimensions at the leaf to the iteration
+ * domains of the source and sink accesses and then extract
+ * the individual accesses (per space).
+ *
+ * In particular, if the prefix schedule at the node is of the form
+ *
+ *	D -> S
+ *
+ * while the access relations are of the form
+ *
+ *	D -> A
+ *
+ * then the updated access relations are of the form
+ *
+ *	[S -> D] -> A
+ *
+ * Note that S consists of a single space such that introducing S
+ * in the access relations does not increase the number of spaces.
+ */
+static isl_bool collect_sink_source(__isl_keep isl_schedule_node *node,
+	void *user)
+{
+	struct isl_compute_flow_schedule_data *data = user;
+	isl_union_map *prefix;
+	isl_union_map *umap;
+	isl_bool r = isl_bool_false;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_leaf)
+		return isl_bool_true;
+
+	data->node = node;
+
+	prefix = isl_schedule_node_get_prefix_schedule_relation(node);
+	prefix = isl_union_map_reverse(prefix);
+	prefix = isl_union_map_range_map(prefix);
+
+	data->set_sink = 1;
+	umap = isl_union_map_copy(data->access->access[isl_access_sink]);
+	umap = isl_union_map_apply_range(isl_union_map_copy(prefix), umap);
+	if (isl_union_map_foreach_map(umap, &extract_sink_source, data) < 0)
+		r = isl_bool_error;
+	isl_union_map_free(umap);
+
+	data->set_sink = 0;
+	data->must = 1;
+	umap = isl_union_map_copy(data->access->access[isl_access_must_source]);
+	umap = isl_union_map_apply_range(isl_union_map_copy(prefix), umap);
+	if (isl_union_map_foreach_map(umap, &extract_sink_source, data) < 0)
+		r = isl_bool_error;
+	isl_union_map_free(umap);
+
+	data->set_sink = 0;
+	data->must = 0;
+	umap = isl_union_map_copy(data->access->access[isl_access_may_source]);
+	umap = isl_union_map_apply_range(isl_union_map_copy(prefix), umap);
+	if (isl_union_map_foreach_map(umap, &extract_sink_source, data) < 0)
+		r = isl_bool_error;
+	isl_union_map_free(umap);
+
+	isl_union_map_free(prefix);
+
+	return r;
+}
+
+/* isl_access_info_compute_flow callback for determining whether
+ * the shared nesting level and the ordering within that level
+ * for two scheduled accesses for use in compute_single_flow.
+ *
+ * The tokens passed to this function refer to the leaves
+ * in the schedule tree where the accesses take place.
+ *
+ * If n is the shared number of loops, then we need to return
+ * "2 * n + 1" if "first" precedes "second" inside the innermost
+ * shared loop and "2 * n" otherwise.
+ *
+ * The innermost shared ancestor may be the leaves themselves
+ * if the accesses take place in the same leaf.  Otherwise,
+ * it is either a set node or a sequence node.  Only in the case
+ * of a sequence node do we consider one access to precede the other.
+ */
+static int before_node(void *first, void *second)
+{
+	isl_schedule_node *node1 = first;
+	isl_schedule_node *node2 = second;
+	isl_schedule_node *shared;
+	int depth;
+	int before = 0;
+
+	shared = isl_schedule_node_get_shared_ancestor(node1, node2);
+	if (!shared)
+		return -1;
+
+	depth = isl_schedule_node_get_schedule_depth(shared);
+	if (isl_schedule_node_get_type(shared) == isl_schedule_node_sequence) {
+		int pos1, pos2;
+
+		pos1 = isl_schedule_node_get_ancestor_child_position(node1,
+								    shared);
+		pos2 = isl_schedule_node_get_ancestor_child_position(node2,
+								    shared);
+		before = pos1 < pos2;
+	}
+
+	isl_schedule_node_free(shared);
+
+	return 2 * depth + before;
+}
+
+/* Check if the given two accesses may be coscheduled.
+ * If so, return 1.  Otherwise return 0.
+ *
+ * Two accesses may only be coscheduled if they appear in the same leaf.
+ */
+static int coscheduled_node(void *first, void *second)
+{
+	isl_schedule_node *node1 = first;
+	isl_schedule_node *node2 = second;
+
+	return node1 == node2;
+}
+
+/* Add the scheduled sources from "data" that access
+ * the same data space as "sink" to "access".
+ */
+static __isl_give isl_access_info *add_matching_sources(
+	__isl_take isl_access_info *access, struct isl_scheduled_access *sink,
+	struct isl_compute_flow_schedule_data *data)
+{
+	int i;
+	isl_space *space;
+
+	space = isl_space_range(isl_map_get_space(sink->access));
+	for (i = 0; i < data->n_source; ++i) {
+		struct isl_scheduled_access *source;
+		isl_space *source_space;
+		int eq;
+
+		source = &data->source[i];
+		source_space = isl_map_get_space(source->access);
+		source_space = isl_space_range(source_space);
+		eq = isl_space_is_equal(space, source_space);
+		isl_space_free(source_space);
+
+		if (!eq)
+			continue;
+		if (eq < 0)
+			goto error;
+
+		access = isl_access_info_add_source(access,
+		    isl_map_copy(source->access), source->must, source->node);
+	}
+
+	isl_space_free(space);
+	return access;
+error:
+	isl_space_free(space);
+	isl_access_info_free(access);
+	return NULL;
+}
+
+/* Given a scheduled sink access relation "sink", compute the corresponding
+ * dependences on the sources in "data" and add the computed dependences
+ * to "uf".
+ *
+ * The dependences computed by access_info_compute_flow_core are of the form
+ *
+ *	[S -> I] -> [[S' -> I'] -> A]
+ *
+ * The schedule dimensions are projected out by first currying the range,
+ * resulting in
+ *
+ *	[S -> I] -> [S' -> [I' -> A]]
+ *
+ * and then computing the factor range
+ *
+ *	I -> [I' -> A]
+ */
+static __isl_give isl_union_flow *compute_single_flow(
+	__isl_take isl_union_flow *uf, struct isl_scheduled_access *sink,
+	struct isl_compute_flow_schedule_data *data)
+{
+	int i;
+	isl_access_info *access;
+	isl_flow *flow;
+	isl_map *map;
+
+	if (!uf)
+		return NULL;
+
+	access = isl_access_info_alloc(isl_map_copy(sink->access), sink->node,
+					&before_node, data->n_source);
+	if (access)
+		access->coscheduled = &coscheduled_node;
+	access = add_matching_sources(access, sink, data);
+
+	flow = access_info_compute_flow_core(access);
+	if (!flow)
+		return isl_union_flow_free(uf);
+
+	map = isl_map_domain_factor_range(isl_flow_get_no_source(flow, 1));
+	uf->must_no_source = isl_union_map_union(uf->must_no_source,
+						isl_union_map_from_map(map));
+	map = isl_map_domain_factor_range(isl_flow_get_no_source(flow, 0));
+	uf->may_no_source = isl_union_map_union(uf->may_no_source,
+						isl_union_map_from_map(map));
+
+	for (i = 0; i < flow->n_source; ++i) {
+		isl_union_map *dep;
+
+		map = isl_map_range_curry(isl_map_copy(flow->dep[i].map));
+		map = isl_map_factor_range(map);
+		dep = isl_union_map_from_map(map);
+		if (flow->dep[i].must)
+			uf->must_dep = isl_union_map_union(uf->must_dep, dep);
+		else
+			uf->may_dep = isl_union_map_union(uf->may_dep, dep);
+	}
+
+	isl_flow_free(flow);
+
+	return uf;
+}
+
+/* Given a description of the "sink" accesses, the "source" accesses and
+ * a schedule, compute for each instance of a sink access
+ * and for each element accessed by that instance,
+ * the possible or definite source accesses that last accessed the
+ * element accessed by the sink access before this sink access
+ * in the sense that there is no intermediate definite source access.
+ * Only consider dependences between statement instances that belong
+ * to the domain of the schedule.
+ *
+ * The must_no_source and may_no_source elements of the result
+ * are subsets of access->sink.  The elements must_dep and may_dep
+ * map domain elements of access->{may,must)_source to
+ * domain elements of access->sink.
+ *
+ * This function is used when a schedule tree representation
+ * is available.
+ *
+ * We extract the individual scheduled source and sink access relations
+ * (taking into account the domain of the schedule) and
+ * then compute dependences for each scheduled sink individually.
+ */
+static __isl_give isl_union_flow *compute_flow_schedule(
+	__isl_take isl_union_access_info *access)
+{
+	struct isl_compute_flow_schedule_data data = { access };
+	int i, n;
+	isl_ctx *ctx;
+	isl_space *space;
+	isl_union_flow *flow;
+
+	ctx = isl_union_access_info_get_ctx(access);
+
+	data.n_sink = 0;
+	data.n_source = 0;
+	if (isl_schedule_foreach_schedule_node_top_down(access->schedule,
+						&count_sink_source, &data) < 0)
+		goto error;
+
+	n = data.n_sink + data.n_source;
+	data.sink = isl_calloc_array(ctx, struct isl_scheduled_access, n);
+	if (n && !data.sink)
+		goto error;
+	data.source = data.sink + data.n_sink;
+
+	data.n_sink = 0;
+	data.n_source = 0;
+	if (isl_schedule_foreach_schedule_node_top_down(access->schedule,
+					    &collect_sink_source, &data) < 0)
+		goto error;
+
+	space = isl_union_map_get_space(access->access[isl_access_sink]);
+	flow = isl_union_flow_alloc(space);
+
+	isl_compute_flow_schedule_data_align_params(&data);
+
+	for (i = 0; i < data.n_sink; ++i)
+		flow = compute_single_flow(flow, &data.sink[i], &data);
+
+	isl_compute_flow_schedule_data_clear(&data);
+
+	isl_union_access_info_free(access);
+	return flow;
+error:
+	isl_union_access_info_free(access);
+	isl_compute_flow_schedule_data_clear(&data);
+	return NULL;
+}
+
+/* Given a description of the "sink" accesses, the "source" accesses and
+ * a schedule, compute for each instance of a sink access
+ * and for each element accessed by that instance,
+ * the possible or definite source accesses that last accessed the
+ * element accessed by the sink access before this sink access
+ * in the sense that there is no intermediate definite source access.
+ *
+ * The must_no_source and may_no_source elements of the result
+ * are subsets of access->sink.  The elements must_dep and may_dep
+ * map domain elements of access->{may,must)_source to
+ * domain elements of access->sink.
+ *
+ * If any kills have been specified, then they are treated as
+ * must-sources internally.  Any dependence that purely derives
+ * from an original kill is removed from the output.
+ *
+ * We check whether the schedule is available as a schedule tree
+ * or a schedule map and call the corresponding function to perform
+ * the analysis.
+ */
+__isl_give isl_union_flow *isl_union_access_info_compute_flow(
+	__isl_take isl_union_access_info *access)
+{
+	isl_bool has_kill;
+	isl_union_map *must = NULL, *may = NULL;
+	isl_union_flow *flow;
+
+	has_kill = isl_union_access_has_kill(access);
+	if (has_kill < 0)
+		goto error;
+	if (has_kill) {
+		must = isl_union_access_info_get_must_source(access);
+		may = isl_union_access_info_get_may_source(access);
+	}
+	access = isl_union_access_info_add_kill_to_must_source(access);
+	access = isl_union_access_info_normalize(access);
+	if (!access)
+		goto error;
+	if (access->schedule)
+		flow = compute_flow_schedule(access);
+	else
+		flow = compute_flow_union_map(access);
+	if (has_kill)
+		flow = isl_union_flow_drop_kill_source(flow, must, may);
+	return flow;
+error:
+	isl_union_access_info_free(access);
+	isl_union_map_free(must);
+	isl_union_map_free(may);
+	return NULL;
+}
+
+/* Print the information contained in "flow" to "p".
+ * The information is printed as a YAML document.
+ */
+__isl_give isl_printer *isl_printer_print_union_flow(
+	__isl_take isl_printer *p, __isl_keep isl_union_flow *flow)
+{
+	isl_union_map *umap;
+
+	if (!flow)
+		return isl_printer_free(p);
+
+	p = isl_printer_yaml_start_mapping(p);
+	umap = isl_union_flow_get_full_must_dependence(flow);
+	p = print_union_map_field(p, "must_dependence", umap);
+	isl_union_map_free(umap);
+	umap = isl_union_flow_get_full_may_dependence(flow);
+	p = print_union_map_field(p, "may_dependence", umap);
+	isl_union_map_free(umap);
+	p = print_union_map_field(p, "must_no_source", flow->must_no_source);
+	umap = isl_union_flow_get_may_no_source(flow);
+	p = print_union_map_field(p, "may_no_source", umap);
+	isl_union_map_free(umap);
+	p = isl_printer_yaml_end_mapping(p);
+
+	return p;
+}
+
+/* Return a string representation of the information in "flow".
+ * The information is printed in flow format.
+ */
+__isl_give char *isl_union_flow_to_str(__isl_keep isl_union_flow *flow)
+{
+	isl_printer *p;
+	char *s;
+
+	if (!flow)
+		return NULL;
+
+	p = isl_printer_to_str(isl_union_flow_get_ctx(flow));
+	p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
+	p = isl_printer_print_union_flow(p, flow);
+	s = isl_printer_get_str(p);
+	isl_printer_free(p);
+
+	return s;
+}
+
+/* Given a collection of "sink" and "source" accesses,
+ * compute for each iteration of a sink access
+ * and for each element accessed by that iteration,
+ * the source access in the list that last accessed the
+ * element accessed by the sink access before this sink access.
+ * Each access is given as a map from the loop iterators
+ * to the array indices.
+ * The result is a relations between source and sink
+ * iterations and a subset of the domain of the sink accesses,
+ * corresponding to those iterations that access an element
+ * not previously accessed.
+ *
+ * We collect the inputs in an isl_union_access_info object,
+ * call isl_union_access_info_compute_flow and extract
+ * the outputs from the result.
+ */
+int isl_union_map_compute_flow(__isl_take isl_union_map *sink,
+	__isl_take isl_union_map *must_source,
+	__isl_take isl_union_map *may_source,
+	__isl_take isl_union_map *schedule,
+	__isl_give isl_union_map **must_dep, __isl_give isl_union_map **may_dep,
+	__isl_give isl_union_map **must_no_source,
+	__isl_give isl_union_map **may_no_source)
+{
+	isl_union_access_info *access;
+	isl_union_flow *flow;
+
+	access = isl_union_access_info_from_sink(sink);
+	access = isl_union_access_info_set_must_source(access, must_source);
+	access = isl_union_access_info_set_may_source(access, may_source);
+	access = isl_union_access_info_set_schedule_map(access, schedule);
+	flow = isl_union_access_info_compute_flow(access);
+
+	if (must_dep)
+		*must_dep = isl_union_flow_get_must_dependence(flow);
+	if (may_dep)
+		*may_dep = isl_union_flow_get_non_must_dependence(flow);
+	if (must_no_source)
+		*must_no_source = isl_union_flow_get_must_no_source(flow);
+	if (may_no_source)
+		*may_no_source = isl_union_flow_get_non_must_no_source(flow);
+
+	isl_union_flow_free(flow);
+
+	if ((must_dep && !*must_dep) || (may_dep && !*may_dep) ||
+	    (must_no_source && !*must_no_source) ||
+	    (may_no_source && !*may_no_source))
+		goto error;
+
+	return 0;
+error:
+	if (must_dep)
+		*must_dep = isl_union_map_free(*must_dep);
+	if (may_dep)
+		*may_dep = isl_union_map_free(*may_dep);
+	if (must_no_source)
+		*must_no_source = isl_union_map_free(*must_no_source);
+	if (may_no_source)
+		*may_no_source = isl_union_map_free(*may_no_source);
+	return -1;
+}
diff --git a/final/lib/External/isl/isl_fold.c b/final/lib/External/isl/isl_fold.c
new file mode 100644
index 0000000..1ba8815
--- /dev/null
+++ b/final/lib/External/isl/isl_fold.c
@@ -0,0 +1,1795 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France 
+ */
+
+#define ISL_DIM_H
+#include <isl_map_private.h>
+#include <isl_union_map_private.h>
+#include <isl_polynomial_private.h>
+#include <isl_point_private.h>
+#include <isl_space_private.h>
+#include <isl_lp_private.h>
+#include <isl_seq.h>
+#include <isl_mat_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl_config.h>
+#include <isl/deprecated/polynomial_int.h>
+
+enum isl_fold isl_fold_type_negate(enum isl_fold type)
+{
+	switch (type) {
+	case isl_fold_min:
+		return isl_fold_max;
+	case isl_fold_max:
+		return isl_fold_min;
+	case isl_fold_list:
+		return isl_fold_list;
+	}
+
+	isl_die(NULL, isl_error_internal, "unhandled isl_fold type", abort());
+}
+
+static __isl_give isl_qpolynomial_fold *qpolynomial_fold_alloc(
+	enum isl_fold type, __isl_take isl_space *dim, int n)
+{
+	isl_qpolynomial_fold *fold;
+
+	if (!dim)
+		goto error;
+
+	isl_assert(dim->ctx, n >= 0, goto error);
+	fold = isl_calloc(dim->ctx, struct isl_qpolynomial_fold,
+			sizeof(struct isl_qpolynomial_fold) +
+			(n - 1) * sizeof(struct isl_qpolynomial *));
+	if (!fold)
+		goto error;
+
+	fold->ref = 1;
+	fold->size = n;
+	fold->n = 0;
+	fold->type = type;
+	fold->dim = dim;
+
+	return fold;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+isl_ctx *isl_qpolynomial_fold_get_ctx(__isl_keep isl_qpolynomial_fold *fold)
+{
+	return fold ? fold->dim->ctx : NULL;
+}
+
+__isl_give isl_space *isl_qpolynomial_fold_get_domain_space(
+	__isl_keep isl_qpolynomial_fold *fold)
+{
+	return fold ? isl_space_copy(fold->dim) : NULL;
+}
+
+__isl_give isl_space *isl_qpolynomial_fold_get_space(
+	__isl_keep isl_qpolynomial_fold *fold)
+{
+	isl_space *space;
+	if (!fold)
+		return NULL;
+	space = isl_space_copy(fold->dim);
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, 1);
+	return space;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim)
+{
+	int i;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold || !dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_reset_domain_space(fold->qp[i],
+							isl_space_copy(dim));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_space_free(fold->dim);
+	fold->dim = dim;
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Reset the space of "fold".  This function is called from isl_pw_templ.c
+ * and doesn't know if the space of an element object is represented
+ * directly or through its domain.  It therefore passes along both.
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_space_and_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space,
+	__isl_take isl_space *domain)
+{
+	isl_space_free(space);
+	return isl_qpolynomial_fold_reset_domain_space(fold, domain);
+}
+
+int isl_qpolynomial_fold_involves_dims(__isl_keep isl_qpolynomial_fold *fold,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!fold)
+		return -1;
+	if (fold->n == 0 || n == 0)
+		return 0;
+
+	for (i = 0; i < fold->n; ++i) {
+		int involves = isl_qpolynomial_involves_dims(fold->qp[i],
+							    type, first, n);
+		if (involves < 0 || involves)
+			return involves;
+	}
+	return 0;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_set_dim_name(
+	__isl_take isl_qpolynomial_fold *fold,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	int i;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+	fold->dim = isl_space_set_dim_name(fold->dim, type, pos, s);
+	if (!fold->dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_set_dim_name(fold->qp[i],
+							    type, pos, s);
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+/* Given a dimension type for an isl_qpolynomial_fold,
+ * return the corresponding type for the domain.
+ */
+static enum isl_dim_type domain_type(enum isl_dim_type type)
+{
+	if (type == isl_dim_in)
+		return isl_dim_set;
+	return type;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_drop_dims(
+	__isl_take isl_qpolynomial_fold *fold,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	enum isl_dim_type set_type;
+
+	if (!fold)
+		return NULL;
+	if (n == 0)
+		return fold;
+
+	set_type = domain_type(type);
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+	fold->dim = isl_space_drop_dims(fold->dim, set_type, first, n);
+	if (!fold->dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_drop_dims(fold->qp[i],
+							    type, first, n);
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_insert_dims(
+	__isl_take isl_qpolynomial_fold *fold,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!fold)
+		return NULL;
+	if (n == 0 && !isl_space_is_named_or_nested(fold->dim, type))
+		return fold;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+	fold->dim = isl_space_insert_dims(fold->dim, type, first, n);
+	if (!fold->dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_insert_dims(fold->qp[i],
+							    type, first, n);
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+/* Determine the sign of the constant quasipolynomial "qp".
+ *
+ * Return
+ *	-1 if qp <= 0
+ *	 1 if qp >= 0
+ *	 0 if unknown
+ *
+ * For qp == 0, we can return either -1 or 1.  In practice, we return 1.
+ * For qp == NaN, the sign is undefined, so we return 0.
+ */
+static int isl_qpolynomial_cst_sign(__isl_keep isl_qpolynomial *qp)
+{
+	struct isl_upoly_cst *cst;
+
+	if (isl_qpolynomial_is_nan(qp))
+		return 0;
+
+	cst = isl_upoly_as_cst(qp->upoly);
+	if (!cst)
+		return 0;
+
+	return isl_int_sgn(cst->n) < 0 ? -1 : 1;
+}
+
+static int isl_qpolynomial_aff_sign(__isl_keep isl_set *set,
+	__isl_keep isl_qpolynomial *qp)
+{
+	enum isl_lp_result res;
+	isl_vec *aff;
+	isl_int opt;
+	int sgn = 0;
+
+	aff = isl_qpolynomial_extract_affine(qp);
+	if (!aff)
+		return 0;
+
+	isl_int_init(opt);
+
+	res = isl_set_solve_lp(set, 0, aff->el + 1, aff->el[0],
+				&opt, NULL, NULL);
+	if (res == isl_lp_error)
+		goto done;
+	if (res == isl_lp_empty ||
+	    (res == isl_lp_ok && !isl_int_is_neg(opt))) {
+		sgn = 1;
+		goto done;
+	}
+
+	res = isl_set_solve_lp(set, 1, aff->el + 1, aff->el[0],
+				&opt, NULL, NULL);
+	if (res == isl_lp_ok && !isl_int_is_pos(opt))
+		sgn = -1;
+
+done:
+	isl_int_clear(opt);
+	isl_vec_free(aff);
+	return sgn;
+}
+
+/* Determine, if possible, the sign of the quasipolynomial "qp" on
+ * the domain "set".
+ *
+ * If qp is a constant, then the problem is trivial.
+ * If qp is linear, then we check if the minimum of the corresponding
+ * affine constraint is non-negative or if the maximum is non-positive.
+ *
+ * Otherwise, we check if the outermost variable "v" has a lower bound "l"
+ * in "set".  If so, we write qp(v,v') as
+ *
+ *	q(v,v') * (v - l) + r(v')
+ *
+ * if q(v,v') and r(v') have the same known sign, then the original
+ * quasipolynomial has the same sign as well.
+ *
+ * Return
+ *	-1 if qp <= 0
+ *	 1 if qp >= 0
+ *	 0 if unknown
+ */
+static int isl_qpolynomial_sign(__isl_keep isl_set *set,
+	__isl_keep isl_qpolynomial *qp)
+{
+	int d;
+	int i;
+	int is;
+	struct isl_upoly_rec *rec;
+	isl_vec *v;
+	isl_int l;
+	enum isl_lp_result res;
+	int sgn = 0;
+
+	is = isl_qpolynomial_is_cst(qp, NULL, NULL);
+	if (is < 0)
+		return 0;
+	if (is)
+		return isl_qpolynomial_cst_sign(qp);
+
+	is = isl_qpolynomial_is_affine(qp);
+	if (is < 0)
+		return 0;
+	if (is)
+		return isl_qpolynomial_aff_sign(set, qp);
+
+	if (qp->div->n_row > 0)
+		return 0;
+
+	rec = isl_upoly_as_rec(qp->upoly);
+	if (!rec)
+		return 0;
+
+	d = isl_space_dim(qp->dim, isl_dim_all);
+	v = isl_vec_alloc(set->ctx, 2 + d);
+	if (!v)
+		return 0;
+
+	isl_seq_clr(v->el + 1, 1 + d);
+	isl_int_set_si(v->el[0], 1);
+	isl_int_set_si(v->el[2 + qp->upoly->var], 1);
+
+	isl_int_init(l);
+
+	res = isl_set_solve_lp(set, 0, v->el + 1, v->el[0], &l, NULL, NULL);
+	if (res == isl_lp_ok) {
+		isl_qpolynomial *min;
+		isl_qpolynomial *base;
+		isl_qpolynomial *r, *q;
+		isl_qpolynomial *t;
+
+		min = isl_qpolynomial_cst_on_domain(isl_space_copy(qp->dim), l);
+		base = isl_qpolynomial_var_pow_on_domain(isl_space_copy(qp->dim),
+						qp->upoly->var, 1);
+
+		r = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0,
+					  isl_upoly_copy(rec->p[rec->n - 1]));
+		q = isl_qpolynomial_copy(r);
+
+		for (i = rec->n - 2; i >= 0; --i) {
+			r = isl_qpolynomial_mul(r, isl_qpolynomial_copy(min));
+			t = isl_qpolynomial_alloc(isl_space_copy(qp->dim), 0,
+						  isl_upoly_copy(rec->p[i]));
+			r = isl_qpolynomial_add(r, t);
+			if (i == 0)
+				break;
+			q = isl_qpolynomial_mul(q, isl_qpolynomial_copy(base));
+			q = isl_qpolynomial_add(q, isl_qpolynomial_copy(r));
+		}
+
+		if (isl_qpolynomial_is_zero(q))
+			sgn = isl_qpolynomial_sign(set, r);
+		else if (isl_qpolynomial_is_zero(r))
+			sgn = isl_qpolynomial_sign(set, q);
+		else {
+			int sgn_q, sgn_r;
+			sgn_r = isl_qpolynomial_sign(set, r);
+			sgn_q = isl_qpolynomial_sign(set, q);
+			if (sgn_r == sgn_q)
+				sgn = sgn_r;
+		}
+
+		isl_qpolynomial_free(min);
+		isl_qpolynomial_free(base);
+		isl_qpolynomial_free(q);
+		isl_qpolynomial_free(r);
+	}
+
+	isl_int_clear(l);
+
+	isl_vec_free(v);
+
+	return sgn;
+}
+
+/* Combine "fold1" and "fold2" into a single reduction, eliminating
+ * those elements of one reduction that are already covered by the other
+ * reduction on "set".
+ *
+ * If "fold1" or "fold2" is an empty reduction, then return
+ * the other reduction.
+ * If "fold1" or "fold2" is a NaN, then return this NaN.
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain(
+	__isl_keep isl_set *set,
+	__isl_take isl_qpolynomial_fold *fold1,
+	__isl_take isl_qpolynomial_fold *fold2)
+{
+	int i, j;
+	int n1;
+	struct isl_qpolynomial_fold *res = NULL;
+	int better;
+
+	if (!fold1 || !fold2)
+		goto error;
+
+	isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error);
+	isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim),
+			goto error);
+
+	better = fold1->type == isl_fold_max ? -1 : 1;
+
+	if (isl_qpolynomial_fold_is_empty(fold1) ||
+	    isl_qpolynomial_fold_is_nan(fold2)) {
+		isl_qpolynomial_fold_free(fold1);
+		return fold2;
+	}
+
+	if (isl_qpolynomial_fold_is_empty(fold2) ||
+	    isl_qpolynomial_fold_is_nan(fold1)) {
+		isl_qpolynomial_fold_free(fold2);
+		return fold1;
+	}
+
+	res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim),
+					fold1->n + fold2->n);
+	if (!res)
+		goto error;
+
+	for (i = 0; i < fold1->n; ++i) {
+		res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]);
+		if (!res->qp[res->n])
+			goto error;
+		res->n++;
+	}
+	n1 = res->n;
+
+	for (i = 0; i < fold2->n; ++i) {
+		for (j = n1 - 1; j >= 0; --j) {
+			isl_qpolynomial *d;
+			int sgn, equal;
+			equal = isl_qpolynomial_plain_is_equal(res->qp[j],
+								fold2->qp[i]);
+			if (equal < 0)
+				goto error;
+			if (equal)
+				break;
+			d = isl_qpolynomial_sub(
+				isl_qpolynomial_copy(res->qp[j]),
+				isl_qpolynomial_copy(fold2->qp[i]));
+			sgn = isl_qpolynomial_sign(set, d);
+			isl_qpolynomial_free(d);
+			if (sgn == 0)
+				continue;
+			if (sgn != better)
+				break;
+			isl_qpolynomial_free(res->qp[j]);
+			if (j != n1 - 1)
+				res->qp[j] = res->qp[n1 - 1];
+			n1--;
+			if (n1 != res->n - 1)
+				res->qp[n1] = res->qp[res->n - 1];
+			res->n--;
+		}
+		if (j >= 0)
+			continue;
+		res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]);
+		if (!res->qp[res->n])
+			goto error;
+		res->n++;
+	}
+
+	isl_qpolynomial_fold_free(fold1);
+	isl_qpolynomial_fold_free(fold2);
+
+	return res;
+error:
+	isl_qpolynomial_fold_free(res);
+	isl_qpolynomial_fold_free(fold1);
+	isl_qpolynomial_fold_free(fold2);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_qpolynomial(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_qpolynomial *qp)
+{
+	int i;
+
+	if (!fold || !qp)
+		goto error;
+
+	if (isl_qpolynomial_is_zero(qp)) {
+		isl_qpolynomial_free(qp);
+		return fold;
+	}
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_add(fold->qp[i],
+						isl_qpolynomial_copy(qp));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_qpolynomial_free(qp);
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain(
+	__isl_keep isl_set *dom,
+	__isl_take isl_qpolynomial_fold *fold1,
+	__isl_take isl_qpolynomial_fold *fold2)
+{
+	int i;
+	isl_qpolynomial_fold *res = NULL;
+
+	if (!fold1 || !fold2)
+		goto error;
+
+	if (isl_qpolynomial_fold_is_empty(fold1)) {
+		isl_qpolynomial_fold_free(fold1);
+		return fold2;
+	}
+
+	if (isl_qpolynomial_fold_is_empty(fold2)) {
+		isl_qpolynomial_fold_free(fold2);
+		return fold1;
+	}
+
+	if (fold1->n == 1 && fold2->n != 1)
+		return isl_qpolynomial_fold_add_on_domain(dom, fold2, fold1);
+
+	if (fold2->n == 1) {
+		res = isl_qpolynomial_fold_add_qpolynomial(fold1,
+					isl_qpolynomial_copy(fold2->qp[0]));
+		isl_qpolynomial_fold_free(fold2);
+		return res;
+	}
+
+	res = isl_qpolynomial_fold_add_qpolynomial(
+				isl_qpolynomial_fold_copy(fold1),
+				isl_qpolynomial_copy(fold2->qp[0]));
+
+	for (i = 1; i < fold2->n; ++i) {
+		isl_qpolynomial_fold *res_i;
+		res_i = isl_qpolynomial_fold_add_qpolynomial(
+					isl_qpolynomial_fold_copy(fold1),
+					isl_qpolynomial_copy(fold2->qp[i]));
+		res = isl_qpolynomial_fold_fold_on_domain(dom, res, res_i);
+	}
+
+	isl_qpolynomial_fold_free(fold1);
+	isl_qpolynomial_fold_free(fold2);
+	return res;
+error:
+	isl_qpolynomial_fold_free(res);
+	isl_qpolynomial_fold_free(fold1);
+	isl_qpolynomial_fold_free(fold2);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq)
+{
+	int i;
+
+	if (!fold || !eq)
+		goto error;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_substitute_equalities(fold->qp[i],
+							isl_basic_set_copy(eq));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_basic_set_free(eq);
+	return fold;
+error:
+	isl_basic_set_free(eq);
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
+{
+	int i;
+
+	if (!fold || !context)
+		goto error;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_gist(fold->qp[i],
+							isl_set_copy(context));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_set_free(context);
+	return fold;
+error:
+	isl_set_free(context);
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist_params(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context)
+{
+	isl_space *space = isl_qpolynomial_fold_get_domain_space(fold);
+	isl_set *dom_context = isl_set_universe(space);
+	dom_context = isl_set_intersect_params(dom_context, context);
+	return isl_qpolynomial_fold_gist(fold, dom_context);
+}
+
+#define isl_qpolynomial_fold_involves_nan isl_qpolynomial_fold_is_nan
+
+#define HAS_TYPE
+
+#undef PW
+#define PW isl_pw_qpolynomial_fold
+#undef EL
+#define EL isl_qpolynomial_fold
+#undef EL_IS_ZERO
+#define EL_IS_ZERO is_empty
+#undef ZERO
+#define ZERO zero
+#undef IS_ZERO
+#define IS_ZERO is_zero
+#undef FIELD
+#define FIELD fold
+#undef DEFAULT_IS_ZERO
+#define DEFAULT_IS_ZERO 1
+
+#define NO_NEG
+#define NO_SUB
+#define NO_PULLBACK
+
+#include <isl_pw_templ.c>
+
+#undef UNION
+#define UNION isl_union_pw_qpolynomial_fold
+#undef PART
+#define PART isl_pw_qpolynomial_fold
+#undef PARTS
+#define PARTS pw_qpolynomial_fold
+
+#define NO_SUB
+
+#include <isl_union_single.c>
+#include <isl_union_eval.c>
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_empty(enum isl_fold type,
+	__isl_take isl_space *dim)
+{
+	return qpolynomial_fold_alloc(type, dim, 0);
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_alloc(
+	enum isl_fold type, __isl_take isl_qpolynomial *qp)
+{
+	isl_qpolynomial_fold *fold;
+
+	if (!qp)
+		return NULL;
+
+	fold = qpolynomial_fold_alloc(type, isl_space_copy(qp->dim), 1);
+	if (!fold)
+		goto error;
+
+	fold->qp[0] = qp;
+	fold->n++;
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_copy(
+	__isl_keep isl_qpolynomial_fold *fold)
+{
+	if (!fold)
+		return NULL;
+
+	fold->ref++;
+	return fold;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup(
+	__isl_keep isl_qpolynomial_fold *fold)
+{
+	int i;
+	isl_qpolynomial_fold *dup;
+
+	if (!fold)
+		return NULL;
+	dup = qpolynomial_fold_alloc(fold->type,
+					isl_space_copy(fold->dim), fold->n);
+	if (!dup)
+		return NULL;
+	
+	dup->n = fold->n;
+	for (i = 0; i < fold->n; ++i) {
+		dup->qp[i] = isl_qpolynomial_copy(fold->qp[i]);
+		if (!dup->qp[i])
+			goto error;
+	}
+
+	return dup;
+error:
+	isl_qpolynomial_fold_free(dup);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow(
+	__isl_take isl_qpolynomial_fold *fold)
+{
+	if (!fold)
+		return NULL;
+
+	if (fold->ref == 1)
+		return fold;
+	fold->ref--;
+	return isl_qpolynomial_fold_dup(fold);
+}
+
+void isl_qpolynomial_fold_free(__isl_take isl_qpolynomial_fold *fold)
+{
+	int i;
+
+	if (!fold)
+		return;
+	if (--fold->ref > 0)
+		return;
+
+	for (i = 0; i < fold->n; ++i)
+		isl_qpolynomial_free(fold->qp[i]);
+	isl_space_free(fold->dim);
+	free(fold);
+}
+
+int isl_qpolynomial_fold_is_empty(__isl_keep isl_qpolynomial_fold *fold)
+{
+	if (!fold)
+		return -1;
+
+	return fold->n == 0;
+}
+
+/* Does "fold" represent max(NaN) or min(NaN)?
+ */
+isl_bool isl_qpolynomial_fold_is_nan(__isl_keep isl_qpolynomial_fold *fold)
+{
+	if (!fold)
+		return isl_bool_error;
+	if (fold->n != 1)
+		return isl_bool_false;
+	return isl_qpolynomial_is_nan(fold->qp[0]);
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold(
+	__isl_take isl_qpolynomial_fold *fold1,
+	__isl_take isl_qpolynomial_fold *fold2)
+{
+	int i;
+	struct isl_qpolynomial_fold *res = NULL;
+
+	if (!fold1 || !fold2)
+		goto error;
+
+	isl_assert(fold1->dim->ctx, fold1->type == fold2->type, goto error);
+	isl_assert(fold1->dim->ctx, isl_space_is_equal(fold1->dim, fold2->dim),
+			goto error);
+
+	if (isl_qpolynomial_fold_is_empty(fold1)) {
+		isl_qpolynomial_fold_free(fold1);
+		return fold2;
+	}
+
+	if (isl_qpolynomial_fold_is_empty(fold2)) {
+		isl_qpolynomial_fold_free(fold2);
+		return fold1;
+	}
+
+	res = qpolynomial_fold_alloc(fold1->type, isl_space_copy(fold1->dim),
+					fold1->n + fold2->n);
+	if (!res)
+		goto error;
+
+	for (i = 0; i < fold1->n; ++i) {
+		res->qp[res->n] = isl_qpolynomial_copy(fold1->qp[i]);
+		if (!res->qp[res->n])
+			goto error;
+		res->n++;
+	}
+
+	for (i = 0; i < fold2->n; ++i) {
+		res->qp[res->n] = isl_qpolynomial_copy(fold2->qp[i]);
+		if (!res->qp[res->n])
+			goto error;
+		res->n++;
+	}
+
+	isl_qpolynomial_fold_free(fold1);
+	isl_qpolynomial_fold_free(fold2);
+
+	return res;
+error:
+	isl_qpolynomial_fold_free(res);
+	isl_qpolynomial_fold_free(fold1);
+	isl_qpolynomial_fold_free(fold2);
+	return NULL;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_fold(
+	__isl_take isl_pw_qpolynomial_fold *pw1,
+	__isl_take isl_pw_qpolynomial_fold *pw2)
+{
+	int i, j, n;
+	struct isl_pw_qpolynomial_fold *res;
+	isl_set *set;
+
+	if (!pw1 || !pw2)
+		goto error;
+
+	isl_assert(pw1->dim->ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
+
+	if (isl_pw_qpolynomial_fold_is_zero(pw1)) {
+		isl_pw_qpolynomial_fold_free(pw1);
+		return pw2;
+	}
+
+	if (isl_pw_qpolynomial_fold_is_zero(pw2)) {
+		isl_pw_qpolynomial_fold_free(pw2);
+		return pw1;
+	}
+
+	if (pw1->type != pw2->type)
+		isl_die(pw1->dim->ctx, isl_error_invalid,
+			"fold types don't match", goto error);
+
+	n = (pw1->n + 1) * (pw2->n + 1);
+	res = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pw1->dim),
+						pw1->type, n);
+
+	for (i = 0; i < pw1->n; ++i) {
+		set = isl_set_copy(pw1->p[i].set);
+		for (j = 0; j < pw2->n; ++j) {
+			struct isl_set *common;
+			isl_qpolynomial_fold *sum;
+			set = isl_set_subtract(set,
+					isl_set_copy(pw2->p[j].set));
+			common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
+						isl_set_copy(pw2->p[j].set));
+			if (isl_set_plain_is_empty(common)) {
+				isl_set_free(common);
+				continue;
+			}
+
+			sum = isl_qpolynomial_fold_fold_on_domain(common,
+			       isl_qpolynomial_fold_copy(pw1->p[i].fold),
+			       isl_qpolynomial_fold_copy(pw2->p[j].fold));
+
+			res = isl_pw_qpolynomial_fold_add_piece(res, common, sum);
+		}
+		res = isl_pw_qpolynomial_fold_add_piece(res, set,
+			isl_qpolynomial_fold_copy(pw1->p[i].fold));
+	}
+
+	for (j = 0; j < pw2->n; ++j) {
+		set = isl_set_copy(pw2->p[j].set);
+		for (i = 0; i < pw1->n; ++i)
+			set = isl_set_subtract(set, isl_set_copy(pw1->p[i].set));
+		res = isl_pw_qpolynomial_fold_add_piece(res, set,
+				    isl_qpolynomial_fold_copy(pw2->p[j].fold));
+	}
+
+	isl_pw_qpolynomial_fold_free(pw1);
+	isl_pw_qpolynomial_fold_free(pw2);
+
+	return res;
+error:
+	isl_pw_qpolynomial_fold_free(pw1);
+	isl_pw_qpolynomial_fold_free(pw2);
+	return NULL;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
+	__isl_take isl_union_pw_qpolynomial_fold *u,
+	__isl_take isl_pw_qpolynomial_fold *part)
+{
+	struct isl_hash_table_entry *entry;
+
+	u = isl_union_pw_qpolynomial_fold_cow(u);
+
+	if (!part || !u)
+		goto error;
+	if (isl_space_check_equal_params(part->dim, u->space) < 0)
+		goto error;
+
+	entry = isl_union_pw_qpolynomial_fold_find_part_entry(u, part->dim, 1);
+	if (!entry)
+		goto error;
+
+	if (!entry->data)
+		entry->data = part;
+	else {
+		entry->data = isl_pw_qpolynomial_fold_fold(entry->data,
+					    isl_pw_qpolynomial_fold_copy(part));
+		if (!entry->data)
+			goto error;
+		isl_pw_qpolynomial_fold_free(part);
+	}
+
+	return u;
+error:
+	isl_pw_qpolynomial_fold_free(part);
+	isl_union_pw_qpolynomial_fold_free(u);
+	return NULL;
+}
+
+static isl_stat fold_part(__isl_take isl_pw_qpolynomial_fold *part, void *user)
+{
+	isl_union_pw_qpolynomial_fold **u;
+	u = (isl_union_pw_qpolynomial_fold **)user;
+
+	*u = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(*u, part);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_fold(
+	__isl_take isl_union_pw_qpolynomial_fold *u1,
+	__isl_take isl_union_pw_qpolynomial_fold *u2)
+{
+	u1 = isl_union_pw_qpolynomial_fold_cow(u1);
+
+	if (!u1 || !u2)
+		goto error;
+
+	if (isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(u2,
+							&fold_part, &u1) < 0)
+		goto error;
+
+	isl_union_pw_qpolynomial_fold_free(u2);
+
+	return u1;
+error:
+	isl_union_pw_qpolynomial_fold_free(u1);
+	isl_union_pw_qpolynomial_fold_free(u2);
+	return NULL;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_from_pw_qpolynomial(
+	enum isl_fold type, __isl_take isl_pw_qpolynomial *pwqp)
+{
+	int i;
+	isl_pw_qpolynomial_fold *pwf;
+
+	if (!pwqp)
+		return NULL;
+	
+	pwf = isl_pw_qpolynomial_fold_alloc_size(isl_space_copy(pwqp->dim),
+						type, pwqp->n);
+
+	for (i = 0; i < pwqp->n; ++i)
+		pwf = isl_pw_qpolynomial_fold_add_piece(pwf,
+			isl_set_copy(pwqp->p[i].set),
+			isl_qpolynomial_fold_alloc(type,
+				isl_qpolynomial_copy(pwqp->p[i].qp)));
+
+	isl_pw_qpolynomial_free(pwqp);
+
+	return pwf;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_add(
+	__isl_take isl_pw_qpolynomial_fold *pwf1,
+	__isl_take isl_pw_qpolynomial_fold *pwf2)
+{
+	return isl_pw_qpolynomial_fold_union_add_(pwf1, pwf2);
+}
+
+/* Compare two quasi-polynomial reductions.
+ *
+ * Return -1 if "fold1" is "smaller" than "fold2", 1 if "fold1" is "greater"
+ * than "fold2" and 0 if they are equal.
+ */
+int isl_qpolynomial_fold_plain_cmp(__isl_keep isl_qpolynomial_fold *fold1,
+	__isl_keep isl_qpolynomial_fold *fold2)
+{
+	int i;
+
+	if (fold1 == fold2)
+		return 0;
+	if (!fold1)
+		return -1;
+	if (!fold2)
+		return 1;
+
+	if (fold1->n != fold2->n)
+		return fold1->n - fold2->n;
+
+	for (i = 0; i < fold1->n; ++i) {
+		int cmp;
+
+		cmp = isl_qpolynomial_plain_cmp(fold1->qp[i], fold2->qp[i]);
+		if (cmp != 0)
+			return cmp;
+	}
+
+	return 0;
+}
+
+int isl_qpolynomial_fold_plain_is_equal(__isl_keep isl_qpolynomial_fold *fold1,
+	__isl_keep isl_qpolynomial_fold *fold2)
+{
+	int i;
+
+	if (!fold1 || !fold2)
+		return -1;
+
+	if (fold1->n != fold2->n)
+		return 0;
+
+	/* We probably want to sort the qps first... */
+	for (i = 0; i < fold1->n; ++i) {
+		int eq = isl_qpolynomial_plain_is_equal(fold1->qp[i], fold2->qp[i]);
+		if (eq < 0 || !eq)
+			return eq;
+	}
+
+	return 1;
+}
+
+__isl_give isl_val *isl_qpolynomial_fold_eval(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_point *pnt)
+{
+	isl_ctx *ctx;
+	isl_val *v;
+
+	if (!fold || !pnt)
+		goto error;
+	ctx = isl_point_get_ctx(pnt);
+	isl_assert(pnt->dim->ctx, isl_space_is_equal(pnt->dim, fold->dim), goto error);
+	isl_assert(pnt->dim->ctx,
+		fold->type == isl_fold_max || fold->type == isl_fold_min,
+		goto error);
+
+	if (fold->n == 0)
+		v = isl_val_zero(ctx);
+	else {
+		int i;
+		v = isl_qpolynomial_eval(isl_qpolynomial_copy(fold->qp[0]),
+						isl_point_copy(pnt));
+		for (i = 1; i < fold->n; ++i) {
+			isl_val *v_i;
+			v_i = isl_qpolynomial_eval(
+					    isl_qpolynomial_copy(fold->qp[i]),
+					    isl_point_copy(pnt));
+			if (fold->type == isl_fold_max)
+				v = isl_val_max(v, v_i);
+			else
+				v = isl_val_min(v, v_i);
+		}
+	}
+	isl_qpolynomial_fold_free(fold);
+	isl_point_free(pnt);
+
+	return v;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_point_free(pnt);
+	return NULL;
+}
+
+size_t isl_pw_qpolynomial_fold_size(__isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+	int i;
+	size_t n = 0;
+
+	for (i = 0; i < pwf->n; ++i)
+		n += pwf->p[i].fold->n;
+
+	return n;
+}
+
+__isl_give isl_val *isl_qpolynomial_fold_opt_on_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *set, int max)
+{
+	int i;
+	isl_val *opt;
+
+	if (!set || !fold)
+		goto error;
+
+	if (fold->n == 0) {
+		opt = isl_val_zero(isl_set_get_ctx(set));
+		isl_set_free(set);
+		isl_qpolynomial_fold_free(fold);
+		return opt;
+	}
+
+	opt = isl_qpolynomial_opt_on_domain(isl_qpolynomial_copy(fold->qp[0]),
+						isl_set_copy(set), max);
+	for (i = 1; i < fold->n; ++i) {
+		isl_val *opt_i;
+		opt_i = isl_qpolynomial_opt_on_domain(
+				isl_qpolynomial_copy(fold->qp[i]),
+				isl_set_copy(set), max);
+		if (max)
+			opt = isl_val_max(opt, opt_i);
+		else
+			opt = isl_val_min(opt, opt_i);
+	}
+
+	isl_set_free(set);
+	isl_qpolynomial_fold_free(fold);
+
+	return opt;
+error:
+	isl_set_free(set);
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+/* Check whether for each quasi-polynomial in "fold2" there is
+ * a quasi-polynomial in "fold1" that dominates it on "set".
+ */
+static int qpolynomial_fold_covers_on_domain(__isl_keep isl_set *set,
+	__isl_keep isl_qpolynomial_fold *fold1,
+	__isl_keep isl_qpolynomial_fold *fold2)
+{
+	int i, j;
+	int covers;
+
+	if (!set || !fold1 || !fold2)
+		return -1;
+
+	covers = fold1->type == isl_fold_max ? 1 : -1;
+
+	for (i = 0; i < fold2->n; ++i) {
+		for (j = 0; j < fold1->n; ++j) {
+			isl_qpolynomial *d;
+			int sgn;
+
+			d = isl_qpolynomial_sub(
+				isl_qpolynomial_copy(fold1->qp[j]),
+				isl_qpolynomial_copy(fold2->qp[i]));
+			sgn = isl_qpolynomial_sign(set, d);
+			isl_qpolynomial_free(d);
+			if (sgn == covers)
+				break;
+		}
+		if (j >= fold1->n)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Check whether "pwf1" dominated "pwf2", i.e., the domain of "pwf1" contains
+ * that of "pwf2" and on each cell, the corresponding fold from pwf1 dominates
+ * that of pwf2.
+ */
+int isl_pw_qpolynomial_fold_covers(__isl_keep isl_pw_qpolynomial_fold *pwf1,
+	__isl_keep isl_pw_qpolynomial_fold *pwf2)
+{
+	int i, j;
+	isl_set *dom1, *dom2;
+	int is_subset;
+
+	if (!pwf1 || !pwf2)
+		return -1;
+
+	if (pwf2->n == 0)
+		return 1;
+	if (pwf1->n == 0)
+		return 0;
+
+	dom1 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf1));
+	dom2 = isl_pw_qpolynomial_fold_domain(isl_pw_qpolynomial_fold_copy(pwf2));
+	is_subset = isl_set_is_subset(dom2, dom1);
+	isl_set_free(dom1);
+	isl_set_free(dom2);
+
+	if (is_subset < 0 || !is_subset)
+		return is_subset;
+
+	for (i = 0; i < pwf2->n; ++i) {
+		for (j = 0; j < pwf1->n; ++j) {
+			int is_empty;
+			isl_set *common;
+			int covers;
+
+			common = isl_set_intersect(isl_set_copy(pwf1->p[j].set),
+						   isl_set_copy(pwf2->p[i].set));
+			is_empty = isl_set_is_empty(common);
+			if (is_empty < 0 || is_empty) {
+				isl_set_free(common);
+				if (is_empty < 0)
+					return -1;
+				continue;
+			}
+			covers = qpolynomial_fold_covers_on_domain(common,
+					pwf1->p[j].fold, pwf2->p[i].fold);
+			isl_set_free(common);
+			if (covers < 0 || !covers)
+				return covers;
+		}
+	}
+
+	return 1;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph)
+{
+	int i;
+	isl_ctx *ctx;
+
+	if (!fold || !morph)
+		goto error;
+
+	ctx = fold->dim->ctx;
+	isl_assert(ctx, isl_space_is_equal(fold->dim, morph->dom->dim), goto error);
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		goto error;
+
+	isl_space_free(fold->dim);
+	fold->dim = isl_space_copy(morph->ran->dim);
+	if (!fold->dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_morph_domain(fold->qp[i],
+						isl_morph_copy(morph));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_morph_free(morph);
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_morph_free(morph);
+	return NULL;
+}
+
+enum isl_fold isl_qpolynomial_fold_get_type(__isl_keep isl_qpolynomial_fold *fold)
+{
+	if (!fold)
+		return isl_fold_list;
+	return fold->type;
+}
+
+enum isl_fold isl_union_pw_qpolynomial_fold_get_type(
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf)
+{
+	if (!upwf)
+		return isl_fold_list;
+	return upwf->type;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim)
+{
+	int i;
+
+	if (!fold || !dim)
+		goto error;
+
+	if (isl_space_is_equal(fold->dim, dim)) {
+		isl_space_free(dim);
+		return fold;
+	}
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		goto error;
+
+	isl_space_free(fold->dim);
+	fold->dim = isl_space_copy(dim);
+	if (!fold->dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_lift(fold->qp[i],
+						isl_space_copy(dim));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_space_free(dim);
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_space_free(dim);
+	return NULL;
+}
+
+isl_stat isl_qpolynomial_fold_foreach_qpolynomial(
+	__isl_keep isl_qpolynomial_fold *fold,
+	isl_stat (*fn)(__isl_take isl_qpolynomial *qp, void *user), void *user)
+{
+	int i;
+
+	if (!fold)
+		return isl_stat_error;
+
+	for (i = 0; i < fold->n; ++i)
+		if (fn(isl_qpolynomial_copy(fold->qp[i]), user) < 0)
+			return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_move_dims(
+	__isl_take isl_qpolynomial_fold *fold,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	int i;
+	enum isl_dim_type set_src_type, set_dst_type;
+
+	if (n == 0)
+		return fold;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+
+	set_src_type = domain_type(src_type);
+	set_dst_type = domain_type(dst_type);
+
+	fold->dim = isl_space_move_dims(fold->dim, set_dst_type, dst_pos,
+						set_src_type, src_pos, n);
+	if (!fold->dim)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_move_dims(fold->qp[i],
+				dst_type, dst_pos, src_type, src_pos, n);
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+/* For each 0 <= i < "n", replace variable "first" + i of type "type"
+ * in fold->qp[k] by subs[i].
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute(
+	__isl_take isl_qpolynomial_fold *fold,
+	enum isl_dim_type type, unsigned first, unsigned n,
+	__isl_keep isl_qpolynomial **subs)
+{
+	int i;
+
+	if (n == 0)
+		return fold;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_substitute(fold->qp[i],
+				type, first, n, subs);
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+static isl_stat add_pwqp(__isl_take isl_pw_qpolynomial *pwqp, void *user)
+{
+	isl_pw_qpolynomial_fold *pwf;
+	isl_union_pw_qpolynomial_fold **upwf;
+	struct isl_hash_table_entry *entry;
+
+	upwf = (isl_union_pw_qpolynomial_fold **)user;
+
+	entry = isl_union_pw_qpolynomial_fold_find_part_entry(*upwf,
+			 pwqp->dim, 1);
+	if (!entry)
+		goto error;
+
+	pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial((*upwf)->type, pwqp);
+	if (!entry->data)
+		entry->data = pwf;
+	else {
+		entry->data = isl_pw_qpolynomial_fold_add(entry->data, pwf);
+		if (!entry->data)
+			return isl_stat_error;
+		if (isl_pw_qpolynomial_fold_is_zero(entry->data))
+			*upwf = isl_union_pw_qpolynomial_fold_remove_part_entry(
+								*upwf, entry);
+	}
+
+	return isl_stat_ok;
+error:
+	isl_pw_qpolynomial_free(pwqp);
+	return isl_stat_error;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf,
+	__isl_take isl_union_pw_qpolynomial *upwqp)
+{
+	upwf = isl_union_pw_qpolynomial_fold_align_params(upwf,
+				isl_union_pw_qpolynomial_get_space(upwqp));
+	upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
+				isl_union_pw_qpolynomial_fold_get_space(upwf));
+
+	upwf = isl_union_pw_qpolynomial_fold_cow(upwf);
+	if (!upwf || !upwqp)
+		goto error;
+
+	if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &add_pwqp,
+							 &upwf) < 0)
+		goto error;
+
+	isl_union_pw_qpolynomial_free(upwqp);
+
+	return upwf;
+error:
+	isl_union_pw_qpolynomial_fold_free(upwf);
+	isl_union_pw_qpolynomial_free(upwqp);
+	return NULL;
+}
+
+static isl_bool join_compatible(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	isl_bool m;
+	m = isl_space_has_equal_params(space1, space2);
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(space1, isl_dim_out,
+					space2, isl_dim_in);
+}
+
+/* Compute the intersection of the range of the map and the domain
+ * of the piecewise quasipolynomial reduction and then compute a bound
+ * on the associated quasipolynomial reduction over all elements
+ * in this intersection.
+ *
+ * We first introduce some unconstrained dimensions in the
+ * piecewise quasipolynomial, intersect the resulting domain
+ * with the wrapped map and the compute the sum.
+ */
+__isl_give isl_pw_qpolynomial_fold *isl_map_apply_pw_qpolynomial_fold(
+	__isl_take isl_map *map, __isl_take isl_pw_qpolynomial_fold *pwf,
+	int *tight)
+{
+	isl_ctx *ctx;
+	isl_set *dom;
+	isl_space *map_dim;
+	isl_space *pwf_dim;
+	unsigned n_in;
+	isl_bool ok;
+
+	ctx = isl_map_get_ctx(map);
+	if (!ctx)
+		goto error;
+
+	map_dim = isl_map_get_space(map);
+	pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf);
+	ok = join_compatible(map_dim, pwf_dim);
+	isl_space_free(map_dim);
+	isl_space_free(pwf_dim);
+	if (ok < 0)
+		goto error;
+	if (!ok)
+		isl_die(ctx, isl_error_invalid, "incompatible dimensions",
+			goto error);
+
+	n_in = isl_map_dim(map, isl_dim_in);
+	pwf = isl_pw_qpolynomial_fold_insert_dims(pwf, isl_dim_in, 0, n_in);
+
+	dom = isl_map_wrap(map);
+	pwf = isl_pw_qpolynomial_fold_reset_domain_space(pwf,
+						isl_set_get_space(dom));
+
+	pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, dom);
+	pwf = isl_pw_qpolynomial_fold_bound(pwf, tight);
+	
+	return pwf;
+error:
+	isl_map_free(map);
+	isl_pw_qpolynomial_fold_free(pwf);
+	return NULL;
+}
+
+__isl_give isl_pw_qpolynomial_fold *isl_set_apply_pw_qpolynomial_fold(
+	__isl_take isl_set *set, __isl_take isl_pw_qpolynomial_fold *pwf,
+	int *tight)
+{
+	return isl_map_apply_pw_qpolynomial_fold(set, pwf, tight);
+}
+
+struct isl_apply_fold_data {
+	isl_union_pw_qpolynomial_fold *upwf;
+	isl_union_pw_qpolynomial_fold *res;
+	isl_map *map;
+	int tight;
+};
+
+static isl_stat pw_qpolynomial_fold_apply(
+	__isl_take isl_pw_qpolynomial_fold *pwf, void *user)
+{
+	isl_space *map_dim;
+	isl_space *pwf_dim;
+	struct isl_apply_fold_data *data = user;
+	isl_bool ok;
+
+	map_dim = isl_map_get_space(data->map);
+	pwf_dim = isl_pw_qpolynomial_fold_get_space(pwf);
+	ok = join_compatible(map_dim, pwf_dim);
+	isl_space_free(map_dim);
+	isl_space_free(pwf_dim);
+
+	if (ok < 0)
+		return isl_stat_error;
+	if (ok) {
+		pwf = isl_map_apply_pw_qpolynomial_fold(isl_map_copy(data->map),
+				    pwf, data->tight ? &data->tight : NULL);
+		data->res = isl_union_pw_qpolynomial_fold_fold_pw_qpolynomial_fold(
+							data->res, pwf);
+	} else
+		isl_pw_qpolynomial_fold_free(pwf);
+
+	return isl_stat_ok;
+}
+
+static isl_stat map_apply(__isl_take isl_map *map, void *user)
+{
+	struct isl_apply_fold_data *data = user;
+	isl_stat r;
+
+	data->map = map;
+	r = isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(
+				data->upwf, &pw_qpolynomial_fold_apply, data);
+
+	isl_map_free(map);
+	return r;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_map_apply_union_pw_qpolynomial_fold(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight)
+{
+	isl_space *dim;
+	enum isl_fold type;
+	struct isl_apply_fold_data data;
+
+	upwf = isl_union_pw_qpolynomial_fold_align_params(upwf,
+				isl_union_map_get_space(umap));
+	umap = isl_union_map_align_params(umap,
+				isl_union_pw_qpolynomial_fold_get_space(upwf));
+
+	data.upwf = upwf;
+	data.tight = tight ? 1 : 0;
+	dim = isl_union_pw_qpolynomial_fold_get_space(upwf);
+	type = isl_union_pw_qpolynomial_fold_get_type(upwf);
+	data.res = isl_union_pw_qpolynomial_fold_zero(dim, type);
+	if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
+		goto error;
+
+	isl_union_map_free(umap);
+	isl_union_pw_qpolynomial_fold_free(upwf);
+
+	if (tight)
+		*tight = data.tight;
+
+	return data.res;
+error:
+	isl_union_map_free(umap);
+	isl_union_pw_qpolynomial_fold_free(upwf);
+	isl_union_pw_qpolynomial_fold_free(data.res);
+	return NULL;
+}
+
+__isl_give isl_union_pw_qpolynomial_fold *isl_union_set_apply_union_pw_qpolynomial_fold(
+	__isl_take isl_union_set *uset,
+	__isl_take isl_union_pw_qpolynomial_fold *upwf, int *tight)
+{
+	return isl_union_map_apply_union_pw_qpolynomial_fold(uset, upwf, tight);
+}
+
+/* Reorder the dimension of "fold" according to the given reordering.
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r)
+{
+	int i;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold || !r)
+		goto error;
+
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_realign_domain(fold->qp[i],
+						    isl_reordering_copy(r));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	fold = isl_qpolynomial_fold_reset_domain_space(fold,
+						    isl_space_copy(r->dim));
+
+	isl_reordering_free(r);
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	isl_reordering_free(r);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int(
+	__isl_take isl_qpolynomial_fold *fold, isl_int v)
+{
+	int i;
+
+	if (isl_int_is_one(v))
+		return fold;
+	if (fold && isl_int_is_zero(v)) {
+		isl_qpolynomial_fold *zero;
+		isl_space *dim = isl_space_copy(fold->dim);
+		zero = isl_qpolynomial_fold_empty(fold->type, dim);
+		isl_qpolynomial_fold_free(fold);
+		return zero;
+	}
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+
+	if (isl_int_is_neg(v))
+		fold->type = isl_fold_type_negate(fold->type);
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_mul_isl_int(fold->qp[i], v);
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	return fold;
+error:
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale(
+	__isl_take isl_qpolynomial_fold *fold, isl_int v)
+{
+	return isl_qpolynomial_fold_mul_isl_int(fold, v);
+}
+
+/* Multiply "fold" by "v".
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_val(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
+{
+	int i;
+
+	if (!fold || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return fold;
+	}
+	if (isl_val_is_zero(v)) {
+		isl_qpolynomial_fold *zero;
+		isl_space *space = isl_qpolynomial_fold_get_domain_space(fold);
+		zero = isl_qpolynomial_fold_empty(fold->type, space);
+		isl_qpolynomial_fold_free(fold);
+		isl_val_free(v);
+		return zero;
+	}
+	if (!isl_val_is_rat(v))
+		isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid,
+			"expecting rational factor", goto error);
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		goto error;
+
+	if (isl_val_is_neg(v))
+		fold->type = isl_fold_type_negate(fold->type);
+	for (i = 0; i < fold->n; ++i) {
+		fold->qp[i] = isl_qpolynomial_scale_val(fold->qp[i],
+							isl_val_copy(v));
+		if (!fold->qp[i])
+			goto error;
+	}
+
+	isl_val_free(v);
+	return fold;
+error:
+	isl_val_free(v);
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
+
+/* Divide "fold" by "v".
+ */
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_scale_down_val(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_val *v)
+{
+	if (!fold || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return fold;
+	}
+	if (!isl_val_is_rat(v))
+		isl_die(isl_qpolynomial_fold_get_ctx(fold), isl_error_invalid,
+			"expecting rational factor", goto error);
+	if (isl_val_is_zero(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"cannot scale down by zero", goto error);
+
+	return isl_qpolynomial_fold_scale_val(fold, isl_val_inv(v));
+error:
+	isl_val_free(v);
+	isl_qpolynomial_fold_free(fold);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_gmp.c b/final/lib/External/isl/isl_gmp.c
new file mode 100644
index 0000000..d488fd2
--- /dev/null
+++ b/final/lib/External/isl/isl_gmp.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_int.h>
+
+uint32_t isl_gmp_hash(mpz_t v, uint32_t hash)
+{
+	int sa = v[0]._mp_size;
+	int abs_sa = sa < 0 ? -sa : sa;
+	unsigned char *data = (unsigned char *)v[0]._mp_d;
+	unsigned char *end = data + abs_sa * sizeof(v[0]._mp_d[0]);
+
+	if (sa < 0)
+		isl_hash_byte(hash, 0xFF);
+	for (; data < end; ++data)
+		isl_hash_byte(hash, *data);
+	return hash;
+}
diff --git a/final/lib/External/isl/isl_hash.c b/final/lib/External/isl/isl_hash.c
new file mode 100644
index 0000000..ca25d0d
--- /dev/null
+++ b/final/lib/External/isl/isl_hash.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <stdlib.h>
+#include <isl_hash_private.h>
+#include <isl/ctx.h>
+#include "isl_config.h"
+
+uint32_t isl_hash_string(uint32_t hash, const char *s)
+{
+	for (; *s; s++)
+		isl_hash_byte(hash, *s);
+	return hash;
+}
+
+uint32_t isl_hash_mem(uint32_t hash, const void *p, size_t len)
+{
+	int i;
+	const char *s = p;
+	for (i = 0; i < len; ++i)
+		isl_hash_byte(hash, s[i]);
+	return hash;
+}
+
+static unsigned int round_up(unsigned int v)
+{
+	int old_v = v;
+
+	while (v) {
+		old_v = v;
+		v ^= v & -v;
+	}
+	return old_v << 1;
+}
+
+int isl_hash_table_init(struct isl_ctx *ctx, struct isl_hash_table *table,
+			int min_size)
+{
+	size_t size;
+
+	if (!table)
+		return -1;
+
+	if (min_size < 2)
+		min_size = 2;
+	table->bits = ffs(round_up(4 * (min_size + 1) / 3 - 1)) - 1;
+	table->n = 0;
+
+	size = 1 << table->bits;
+	table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry,
+					  size);
+	if (!table->entries)
+		return -1;
+
+	return 0;
+}
+
+/* Dummy comparison function that always returns false.
+ */
+static int no(const void *entry, const void *val)
+{
+	return 0;
+}
+
+/* Extend "table" to twice its size.
+ * Return 0 on success and -1 on error.
+ *
+ * We reuse isl_hash_table_find to create entries in the extended table.
+ * Since all entries in the original table are assumed to be different,
+ * there is no need to compare them against each other.
+ */
+static int grow_table(struct isl_ctx *ctx, struct isl_hash_table *table)
+{
+	int n;
+	size_t old_size, size;
+	struct isl_hash_table_entry *entries;
+	uint32_t h;
+
+	entries = table->entries;
+	old_size = 1 << table->bits;
+	size = 2 * old_size;
+	table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry,
+					  size);
+	if (!table->entries) {
+		table->entries = entries;
+		return -1;
+	}
+
+	n = table->n;
+	table->n = 0;
+	table->bits++;
+
+	for (h = 0; h < old_size; ++h) {
+		struct isl_hash_table_entry *entry;
+
+		if (!entries[h].data)
+			continue;
+
+		entry = isl_hash_table_find(ctx, table, entries[h].hash,
+					    &no, NULL, 1);
+		if (!entry) {
+			table->bits--;
+			free(table->entries);
+			table->entries = entries;
+			table->n = n;
+			return -1;
+		}
+
+		*entry = entries[h];
+	}
+
+	free(entries);
+
+	return 0;
+}
+
+struct isl_hash_table *isl_hash_table_alloc(struct isl_ctx *ctx, int min_size)
+{
+	struct isl_hash_table *table = NULL;
+
+	table = isl_alloc_type(ctx, struct isl_hash_table);
+	if (isl_hash_table_init(ctx, table, min_size))
+		goto error;
+	return table;
+error:
+	isl_hash_table_free(ctx, table);
+	return NULL;
+}
+
+void isl_hash_table_clear(struct isl_hash_table *table)
+{
+	if (!table)
+		return;
+	free(table->entries);
+}
+
+void isl_hash_table_free(struct isl_ctx *ctx, struct isl_hash_table *table)
+{
+	if (!table)
+		return;
+	isl_hash_table_clear(table);
+	free(table);
+}
+
+/* A dummy entry that can be used to make a distinction between
+ * a missing entry and an error condition.
+ * It is used by isl_union_*_find_part_entry.
+ */
+static struct isl_hash_table_entry none = { 0, NULL };
+struct isl_hash_table_entry *isl_hash_table_entry_none = &none;
+
+struct isl_hash_table_entry *isl_hash_table_find(struct isl_ctx *ctx,
+				struct isl_hash_table *table,
+				uint32_t key_hash,
+				int (*eq)(const void *entry, const void *val),
+				const void *val, int reserve)
+{
+	size_t size;
+	uint32_t h, key_bits;
+
+	key_bits = isl_hash_bits(key_hash, table->bits);
+	size = 1 << table->bits;
+	for (h = key_bits; table->entries[h].data; h = (h+1) % size)
+		if (table->entries[h].hash == key_hash &&
+		    eq(table->entries[h].data, val))
+			return &table->entries[h];
+
+	if (!reserve)
+		return NULL;
+
+	if (4 * table->n >= 3 * size) {
+		if (grow_table(ctx, table) < 0)
+			return NULL;
+		return isl_hash_table_find(ctx, table, key_hash, eq, val, 1);
+	}
+
+	table->n++;
+	table->entries[h].hash = key_hash;
+
+	return &table->entries[h];
+}
+
+isl_stat isl_hash_table_foreach(isl_ctx *ctx, struct isl_hash_table *table,
+	isl_stat (*fn)(void **entry, void *user), void *user)
+{
+	size_t size;
+	uint32_t h;
+
+	if (!table->entries)
+		return isl_stat_error;
+
+	size = 1 << table->bits;
+	for (h = 0; h < size; ++ h)
+		if (table->entries[h].data &&
+		    fn(&table->entries[h].data, user) < 0)
+			return isl_stat_error;
+	
+	return isl_stat_ok;
+}
+
+void isl_hash_table_remove(struct isl_ctx *ctx,
+				struct isl_hash_table *table,
+				struct isl_hash_table_entry *entry)
+{
+	int h, h2;
+	size_t size;
+
+	if (!table || !entry)
+		return;
+
+	size = 1 << table->bits;
+	h = entry - table->entries;
+	isl_assert(ctx, h >= 0 && h < size, return);
+
+	for (h2 = h+1; table->entries[h2 % size].data; h2++) {
+		uint32_t bits = isl_hash_bits(table->entries[h2 % size].hash,
+						table->bits);
+		uint32_t offset = (size + bits - (h+1)) % size;
+		if (offset <= h2 - (h+1))
+			continue;
+		*entry = table->entries[h2 % size];
+		h = h2;
+		entry = &table->entries[h % size];
+	}
+
+	entry->hash = 0;
+	entry->data = NULL;
+	table->n--;
+}
diff --git a/final/lib/External/isl/isl_hash_private.h b/final/lib/External/isl/isl_hash_private.h
new file mode 100644
index 0000000..c6b272a
--- /dev/null
+++ b/final/lib/External/isl/isl_hash_private.h
@@ -0,0 +1,8 @@
+#ifndef ISL_HASH_PRIVATE
+#define ISL_HASH_PRIVATE
+
+#include <isl/hash.h>
+
+extern struct isl_hash_table_entry *isl_hash_table_entry_none;
+
+#endif
diff --git a/final/lib/External/isl/isl_hide_deprecated.h b/final/lib/External/isl/isl_hide_deprecated.h
new file mode 100644
index 0000000..344a368
--- /dev/null
+++ b/final/lib/External/isl/isl_hide_deprecated.h
@@ -0,0 +1,52 @@
+#define isl_aff_get_constant	isl_gmp_aff_get_constant
+#define isl_aff_get_coefficient	isl_gmp_aff_get_coefficient
+#define isl_aff_get_denominator	isl_gmp_aff_get_denominator
+#define isl_aff_set_constant	isl_gmp_aff_set_constant
+#define isl_aff_set_coefficient	isl_gmp_aff_set_coefficient
+#define isl_aff_set_denominator	isl_gmp_aff_set_denominator
+#define isl_aff_add_constant	isl_gmp_aff_add_constant
+#define isl_aff_add_constant_num	isl_gmp_aff_add_constant_num
+#define isl_aff_add_coefficient	isl_gmp_aff_add_coefficient
+#define isl_aff_mod	isl_gmp_aff_mod
+#define isl_aff_scale	isl_gmp_aff_scale
+#define isl_aff_scale_down	isl_gmp_aff_scale_down
+#define isl_pw_aff_mod	isl_gmp_pw_aff_mod
+#define isl_pw_aff_scale	isl_gmp_pw_aff_scale
+#define isl_pw_aff_scale_down	isl_gmp_pw_aff_scale_down
+#define isl_multi_aff_scale	isl_gmp_multi_aff_scale
+#define isl_ast_expr_get_int	isl_gmp_ast_expr_get_int
+#define isl_constraint_get_constant	isl_gmp_constraint_get_constant
+#define isl_constraint_get_coefficient	isl_gmp_constraint_get_coefficient
+#define isl_constraint_set_constant	isl_gmp_constraint_set_constant
+#define isl_constraint_set_coefficient	isl_gmp_constraint_set_coefficient
+#define isl_basic_set_max	isl_gmp_basic_set_max
+#define isl_set_min	isl_gmp_set_min
+#define isl_set_max	isl_gmp_set_max
+#define isl_gmp_hash	isl_gmp_gmp_hash
+#define isl_basic_map_plain_is_fixed	isl_gmp_basic_map_plain_is_fixed
+#define isl_map_fix	isl_gmp_map_fix
+#define isl_map_plain_is_fixed	isl_gmp_map_plain_is_fixed
+#define isl_map_fixed_power	isl_gmp_map_fixed_power
+#define isl_mat_get_element	isl_gmp_mat_get_element
+#define isl_mat_set_element	isl_gmp_mat_set_element
+#define isl_point_get_coordinate	isl_gmp_point_get_coordinate
+#define isl_point_set_coordinate	isl_gmp_point_set_coordinate
+#define isl_qpolynomial_rat_cst_on_domain	isl_gmp_qpolynomial_rat_cst_on_domain
+#define isl_qpolynomial_is_cst	isl_gmp_qpolynomial_is_cst
+#define isl_qpolynomial_scale	isl_gmp_qpolynomial_scale
+#define isl_term_get_num	isl_gmp_term_get_num
+#define isl_term_get_den	isl_gmp_term_get_den
+#define isl_qpolynomial_fold_scale	isl_gmp_qpolynomial_fold_scale
+#define isl_pw_qpolynomial_fold_fix_dim	isl_gmp_pw_qpolynomial_fold_fix_dim
+#define isl_basic_set_fix	isl_gmp_basic_set_fix
+#define isl_set_lower_bound	isl_gmp_set_lower_bound
+#define isl_set_upper_bound	isl_gmp_set_upper_bound
+#define isl_set_fix	isl_gmp_set_fix
+#define isl_set_plain_is_fixed	isl_gmp_set_plain_is_fixed
+#define isl_union_map_fixed_power	isl_gmp_union_map_fixed_power
+#define isl_val_int_from_isl_int	isl_gmp_val_int_from_isl_int
+#define isl_val_get_num_isl_int	isl_gmp_val_get_num_isl_int
+#define isl_vec_get_element	isl_gmp_vec_get_element
+#define isl_vec_set_element	isl_gmp_vec_set_element
+#define isl_vec_set	isl_gmp_vec_set
+#define isl_vec_fdiv_r	isl_gmp_vec_fdiv_r
diff --git a/final/lib/External/isl/isl_id.c b/final/lib/External/isl/isl_id.c
new file mode 100644
index 0000000..d5c7c71
--- /dev/null
+++ b/final/lib/External/isl/isl_id.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <string.h>
+#include <isl_ctx_private.h>
+#include <isl_id_private.h>
+
+#undef BASE
+#define BASE id
+
+#include <isl_list_templ.c>
+
+/* A special, static isl_id to use as domains (and ranges)
+ * of sets and parameters domains.
+ * The user should never get a hold on this isl_id.
+ */
+isl_id isl_id_none = {
+	.ref = -1,
+	.ctx = NULL,
+	.name = "#none",
+	.user = NULL
+};
+
+isl_ctx *isl_id_get_ctx(__isl_keep isl_id *id)
+{
+	return id ? id->ctx : NULL;
+}
+
+void *isl_id_get_user(__isl_keep isl_id *id)
+{
+	return id ? id->user : NULL;
+}
+
+const char *isl_id_get_name(__isl_keep isl_id *id)
+{
+	return id ? id->name : NULL;
+}
+
+static __isl_give isl_id *id_alloc(isl_ctx *ctx, const char *name, void *user)
+{
+	const char *copy = name ? strdup(name) : NULL;
+	isl_id *id;
+
+	if (name && !copy)
+		return NULL;
+	id = isl_calloc_type(ctx, struct isl_id);
+	if (!id)
+		goto error;
+
+	id->ctx = ctx;
+	isl_ctx_ref(id->ctx);
+	id->ref = 1;
+	id->name = copy;
+	id->user = user;
+
+	id->hash = isl_hash_init();
+	if (name)
+		id->hash = isl_hash_string(id->hash, name);
+	else
+		id->hash = isl_hash_builtin(id->hash, user);
+
+	return id;
+error:
+	free((char *)copy);
+	return NULL;
+}
+
+uint32_t isl_id_get_hash(__isl_keep isl_id *id)
+{
+	return id ? id->hash : 0;
+}
+
+struct isl_name_and_user {
+	const char *name;
+	void *user;
+};
+
+static int isl_id_has_name_and_user(const void *entry, const void *val)
+{
+	isl_id *id = (isl_id *)entry;
+	struct isl_name_and_user *nu = (struct isl_name_and_user *) val;
+
+	if (id->user != nu->user)
+		return 0;
+	if (id->name == nu->name)
+		return 1;
+	if (!id->name || !nu->name)
+		return 0;
+
+	return !strcmp(id->name, nu->name);
+}
+
+__isl_give isl_id *isl_id_alloc(isl_ctx *ctx, const char *name, void *user)
+{
+	struct isl_hash_table_entry *entry;
+	uint32_t id_hash;
+	struct isl_name_and_user nu = { name, user };
+
+	if (!ctx)
+		return NULL;
+
+	id_hash = isl_hash_init();
+	if (name)
+		id_hash = isl_hash_string(id_hash, name);
+	else
+		id_hash = isl_hash_builtin(id_hash, user);
+	entry = isl_hash_table_find(ctx, &ctx->id_table, id_hash,
+					isl_id_has_name_and_user, &nu, 1);
+	if (!entry)
+		return NULL;
+	if (entry->data)
+		return isl_id_copy(entry->data);
+	entry->data = id_alloc(ctx, name, user);
+	if (!entry->data)
+		ctx->id_table.n--;
+	return entry->data;
+}
+
+/* If the id has a negative refcount, then it is a static isl_id
+ * which should not be changed.
+ */
+__isl_give isl_id *isl_id_copy(isl_id *id)
+{
+	if (!id)
+		return NULL;
+
+	if (id->ref < 0)
+		return id;
+
+	id->ref++;
+	return id;
+}
+
+/* Compare two isl_ids.
+ *
+ * The order is fairly arbitrary.  We do keep the comparison of
+ * the user pointers as a last resort since these pointer values
+ * may not be stable across different systems or even different runs.
+ */
+int isl_id_cmp(__isl_keep isl_id *id1, __isl_keep isl_id *id2)
+{
+	if (id1 == id2)
+		return 0;
+	if (!id1)
+		return -1;
+	if (!id2)
+		return 1;
+	if (!id1->name != !id2->name)
+		return !id1->name - !id2->name;
+	if (id1->name) {
+		int cmp = strcmp(id1->name, id2->name);
+		if (cmp != 0)
+			return cmp;
+	}
+	if (id1->user < id2->user)
+		return -1;
+	else
+		return 1;
+}
+
+static int isl_id_eq(const void *entry, const void *name)
+{
+	return entry == name;
+}
+
+uint32_t isl_hash_id(uint32_t hash, __isl_keep isl_id *id)
+{
+	if (id)
+		isl_hash_hash(hash, id->hash);
+
+	return hash;
+}
+
+/* Replace the free_user callback by "free_user".
+ */
+__isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id,
+	void (*free_user)(void *user))
+{
+	if (!id)
+		return NULL;
+
+	id->free_user = free_user;
+
+	return id;
+}
+
+/* If the id has a negative refcount, then it is a static isl_id
+ * and should not be freed.
+ */
+__isl_null isl_id *isl_id_free(__isl_take isl_id *id)
+{
+	struct isl_hash_table_entry *entry;
+
+	if (!id)
+		return NULL;
+
+	if (id->ref < 0)
+		return NULL;
+
+	if (--id->ref > 0)
+		return NULL;
+
+	entry = isl_hash_table_find(id->ctx, &id->ctx->id_table, id->hash,
+					isl_id_eq, id, 0);
+	if (!entry)
+		isl_die(id->ctx, isl_error_unknown,
+			"unable to find id", (void)0);
+	else
+		isl_hash_table_remove(id->ctx, &id->ctx->id_table, entry);
+
+	if (id->free_user)
+		id->free_user(id->user);
+
+	free((char *)id->name);
+	isl_ctx_deref(id->ctx);
+	free(id);
+
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_id(__isl_take isl_printer *p,
+	__isl_keep isl_id *id)
+{
+	if (!id)
+		goto error;
+
+	if (id->name)
+		p = isl_printer_print_str(p, id->name);
+	if (id->user) {
+		char buffer[50];
+		snprintf(buffer, sizeof(buffer), "@%p", id->user);
+		p = isl_printer_print_str(p, buffer);
+	}
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_id_private.h b/final/lib/External/isl/isl_id_private.h
new file mode 100644
index 0000000..1d903c8
--- /dev/null
+++ b/final/lib/External/isl/isl_id_private.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_ID_PRIVATE_H
+#define ISL_ID_PRIVATE_H
+
+#include <isl/id.h>
+
+/* Represent a name and/or user pointer.
+ *
+ * If "free_user" is set, then it will be called on "user" when
+ * the last instance of the isl_id is freed.
+ */
+struct isl_id {
+	int ref;
+	isl_ctx *ctx;
+
+	const char *name;
+	void *user;
+	uint32_t hash;
+
+	__isl_give void (*free_user)(void *user);
+};
+
+#undef EL
+#define EL isl_id
+
+#include <isl_list_templ.h>
+
+uint32_t isl_hash_id(uint32_t hash, __isl_keep isl_id *id);
+int isl_id_cmp(__isl_keep isl_id *id1, __isl_keep isl_id *id2);
+
+extern isl_id isl_id_none;
+
+#endif
diff --git a/final/lib/External/isl/isl_id_to_ast_expr.c b/final/lib/External/isl/isl_id_to_ast_expr.c
new file mode 100644
index 0000000..e088565
--- /dev/null
+++ b/final/lib/External/isl/isl_id_to_ast_expr.c
@@ -0,0 +1,15 @@
+#include <isl/id_to_ast_expr.h>
+#include <isl/ast.h>
+
+#define isl_id_is_equal(id1,id2)	id1 == id2
+
+#define ISL_KEY		isl_id
+#define ISL_VAL		isl_ast_expr
+#define ISL_HMAP_SUFFIX	id_to_ast_expr
+#define ISL_HMAP	isl_id_to_ast_expr
+#define ISL_KEY_IS_EQUAL	isl_id_is_equal
+#define ISL_VAL_IS_EQUAL	isl_ast_expr_is_equal
+#define ISL_KEY_PRINT		isl_printer_print_id
+#define ISL_VAL_PRINT		isl_printer_print_ast_expr
+
+#include <isl/hmap_templ.c>
diff --git a/final/lib/External/isl/isl_id_to_id.c b/final/lib/External/isl/isl_id_to_id.c
new file mode 100644
index 0000000..dba2cf3
--- /dev/null
+++ b/final/lib/External/isl/isl_id_to_id.c
@@ -0,0 +1,14 @@
+#include <isl/id_to_id.h>
+
+#define isl_id_is_equal(id1,id2)	id1 == id2
+
+#define ISL_KEY		isl_id
+#define ISL_VAL		isl_id
+#define ISL_HMAP_SUFFIX	id_to_id
+#define ISL_HMAP	isl_id_to_id
+#define ISL_KEY_IS_EQUAL	isl_id_is_equal
+#define ISL_VAL_IS_EQUAL	isl_id_is_equal
+#define ISL_KEY_PRINT		isl_printer_print_id
+#define ISL_VAL_PRINT		isl_printer_print_id
+
+#include <isl/hmap_templ.c>
diff --git a/final/lib/External/isl/isl_id_to_pw_aff.c b/final/lib/External/isl/isl_id_to_pw_aff.c
new file mode 100644
index 0000000..6ea6fea
--- /dev/null
+++ b/final/lib/External/isl/isl_id_to_pw_aff.c
@@ -0,0 +1,15 @@
+#include <isl/id_to_pw_aff.h>
+#include <isl/aff.h>
+
+#define isl_id_is_equal(id1,id2)	id1 == id2
+
+#define ISL_KEY		isl_id
+#define ISL_VAL		isl_pw_aff
+#define ISL_HMAP_SUFFIX	id_to_pw_aff
+#define ISL_HMAP	isl_id_to_pw_aff
+#define ISL_KEY_IS_EQUAL	isl_id_is_equal
+#define ISL_VAL_IS_EQUAL	isl_pw_aff_plain_is_equal
+#define ISL_KEY_PRINT		isl_printer_print_id
+#define ISL_VAL_PRINT		isl_printer_print_pw_aff
+
+#include <isl/hmap_templ.c>
diff --git a/final/lib/External/isl/isl_ilp.c b/final/lib/External/isl/isl_ilp.c
new file mode 100644
index 0000000..eee294e
--- /dev/null
+++ b/final/lib/External/isl/isl_ilp.c
@@ -0,0 +1,837 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/ilp.h>
+#include <isl/union_set.h>
+#include "isl_sample.h"
+#include <isl_seq.h>
+#include "isl_equalities.h"
+#include <isl_aff_private.h>
+#include <isl_local_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl_lp_private.h>
+#include <isl_ilp_private.h>
+#include <isl/deprecated/ilp_int.h>
+
+/* Given a basic set "bset", construct a basic set U such that for
+ * each element x in U, the whole unit box positioned at x is inside
+ * the given basic set.
+ * Note that U may not contain all points that satisfy this property.
+ *
+ * We simply add the sum of all negative coefficients to the constant
+ * term.  This ensures that if x satisfies the resulting constraints,
+ * then x plus any sum of unit vectors satisfies the original constraints.
+ */
+static __isl_give isl_basic_set *unit_box_base_points(
+	__isl_take isl_basic_set *bset)
+{
+	int i, j, k;
+	struct isl_basic_set *unit_box = NULL;
+	unsigned total;
+
+	if (!bset)
+		goto error;
+
+	if (bset->n_eq != 0) {
+		isl_space *space = isl_basic_set_get_space(bset);
+		isl_basic_set_free(bset);
+		return isl_basic_set_empty(space);
+	}
+
+	total = isl_basic_set_total_dim(bset);
+	unit_box = isl_basic_set_alloc_space(isl_basic_set_get_space(bset),
+					0, 0, bset->n_ineq);
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		k = isl_basic_set_alloc_inequality(unit_box);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(unit_box->ineq[k], bset->ineq[i], 1 + total);
+		for (j = 0; j < total; ++j) {
+			if (isl_int_is_nonneg(unit_box->ineq[k][1 + j]))
+				continue;
+			isl_int_add(unit_box->ineq[k][0],
+				unit_box->ineq[k][0], unit_box->ineq[k][1 + j]);
+		}
+	}
+
+	isl_basic_set_free(bset);
+	return unit_box;
+error:
+	isl_basic_set_free(bset);
+	isl_basic_set_free(unit_box);
+	return NULL;
+}
+
+/* Find an integer point in "bset", preferably one that is
+ * close to minimizing "f".
+ *
+ * We first check if we can easily put unit boxes inside bset.
+ * If so, we take the best base point of any of the unit boxes we can find
+ * and round it up to the nearest integer.
+ * If not, we simply pick any integer point in "bset".
+ */
+static __isl_give isl_vec *initial_solution(__isl_keep isl_basic_set *bset,
+	isl_int *f)
+{
+	enum isl_lp_result res;
+	struct isl_basic_set *unit_box;
+	struct isl_vec *sol;
+
+	unit_box = unit_box_base_points(isl_basic_set_copy(bset));
+
+	res = isl_basic_set_solve_lp(unit_box, 0, f, bset->ctx->one,
+					NULL, NULL, &sol);
+	if (res == isl_lp_ok) {
+		isl_basic_set_free(unit_box);
+		return isl_vec_ceil(sol);
+	}
+
+	isl_basic_set_free(unit_box);
+
+	return isl_basic_set_sample_vec(isl_basic_set_copy(bset));
+}
+
+/* Restrict "bset" to those points with values for f in the interval [l, u].
+ */
+static __isl_give isl_basic_set *add_bounds(__isl_take isl_basic_set *bset,
+	isl_int *f, isl_int l, isl_int u)
+{
+	int k;
+	unsigned total;
+
+	total = isl_basic_set_total_dim(bset);
+	bset = isl_basic_set_extend_constraints(bset, 0, 2);
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_seq_cpy(bset->ineq[k], f, 1 + total);
+	isl_int_sub(bset->ineq[k][0], bset->ineq[k][0], l);
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_seq_neg(bset->ineq[k], f, 1 + total);
+	isl_int_add(bset->ineq[k][0], bset->ineq[k][0], u);
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Find an integer point in "bset" that minimizes f (in any) such that
+ * the value of f lies inside the interval [l, u].
+ * Return this integer point if it can be found.
+ * Otherwise, return sol.
+ *
+ * We perform a number of steps until l > u.
+ * In each step, we look for an integer point with value in either
+ * the whole interval [l, u] or half of the interval [l, l+floor(u-l-1/2)].
+ * The choice depends on whether we have found an integer point in the
+ * previous step.  If so, we look for the next point in half of the remaining
+ * interval.
+ * If we find a point, the current solution is updated and u is set
+ * to its value minus 1.
+ * If no point can be found, we update l to the upper bound of the interval
+ * we checked (u or l+floor(u-l-1/2)) plus 1.
+ */
+static __isl_give isl_vec *solve_ilp_search(__isl_keep isl_basic_set *bset,
+	isl_int *f, isl_int *opt, __isl_take isl_vec *sol, isl_int l, isl_int u)
+{
+	isl_int tmp;
+	int divide = 1;
+
+	isl_int_init(tmp);
+
+	while (isl_int_le(l, u)) {
+		struct isl_basic_set *slice;
+		struct isl_vec *sample;
+
+		if (!divide)
+			isl_int_set(tmp, u);
+		else {
+			isl_int_sub(tmp, u, l);
+			isl_int_fdiv_q_ui(tmp, tmp, 2);
+			isl_int_add(tmp, tmp, l);
+		}
+		slice = add_bounds(isl_basic_set_copy(bset), f, l, tmp);
+		sample = isl_basic_set_sample_vec(slice);
+		if (!sample) {
+			isl_vec_free(sol);
+			sol = NULL;
+			break;
+		}
+		if (sample->size > 0) {
+			isl_vec_free(sol);
+			sol = sample;
+			isl_seq_inner_product(f, sol->el, sol->size, opt);
+			isl_int_sub_ui(u, *opt, 1);
+			divide = 1;
+		} else {
+			isl_vec_free(sample);
+			if (!divide)
+				break;
+			isl_int_add_ui(l, tmp, 1);
+			divide = 0;
+		}
+	}
+
+	isl_int_clear(tmp);
+
+	return sol;
+}
+
+/* Find an integer point in "bset" that minimizes f (if any).
+ * If sol_p is not NULL then the integer point is returned in *sol_p.
+ * The optimal value of f is returned in *opt.
+ *
+ * The algorithm maintains a currently best solution and an interval [l, u]
+ * of values of f for which integer solutions could potentially still be found.
+ * The initial value of the best solution so far is any solution.
+ * The initial value of l is minimal value of f over the rationals
+ * (rounded up to the nearest integer).
+ * The initial value of u is the value of f at the initial solution minus 1.
+ *
+ * We then call solve_ilp_search to perform a binary search on the interval.
+ */
+static enum isl_lp_result solve_ilp(__isl_keep isl_basic_set *bset,
+	isl_int *f, isl_int *opt, __isl_give isl_vec **sol_p)
+{
+	enum isl_lp_result res;
+	isl_int l, u;
+	struct isl_vec *sol;
+
+	res = isl_basic_set_solve_lp(bset, 0, f, bset->ctx->one,
+					opt, NULL, &sol);
+	if (res == isl_lp_ok && isl_int_is_one(sol->el[0])) {
+		if (sol_p)
+			*sol_p = sol;
+		else
+			isl_vec_free(sol);
+		return isl_lp_ok;
+	}
+	isl_vec_free(sol);
+	if (res == isl_lp_error || res == isl_lp_empty)
+		return res;
+
+	sol = initial_solution(bset, f);
+	if (!sol)
+		return isl_lp_error;
+	if (sol->size == 0) {
+		isl_vec_free(sol);
+		return isl_lp_empty;
+	}
+	if (res == isl_lp_unbounded) {
+		isl_vec_free(sol);
+		return isl_lp_unbounded;
+	}
+
+	isl_int_init(l);
+	isl_int_init(u);
+
+	isl_int_set(l, *opt);
+
+	isl_seq_inner_product(f, sol->el, sol->size, opt);
+	isl_int_sub_ui(u, *opt, 1);
+
+	sol = solve_ilp_search(bset, f, opt, sol, l, u);
+	if (!sol)
+		res = isl_lp_error;
+
+	isl_int_clear(l);
+	isl_int_clear(u);
+
+	if (sol_p)
+		*sol_p = sol;
+	else
+		isl_vec_free(sol);
+
+	return res;
+}
+
+static enum isl_lp_result solve_ilp_with_eq(__isl_keep isl_basic_set *bset,
+	int max, isl_int *f, isl_int *opt, __isl_give isl_vec **sol_p)
+{
+	unsigned dim;
+	enum isl_lp_result res;
+	struct isl_mat *T = NULL;
+	struct isl_vec *v;
+
+	bset = isl_basic_set_copy(bset);
+	dim = isl_basic_set_total_dim(bset);
+	v = isl_vec_alloc(bset->ctx, 1 + dim);
+	if (!v)
+		goto error;
+	isl_seq_cpy(v->el, f, 1 + dim);
+	bset = isl_basic_set_remove_equalities(bset, &T, NULL);
+	v = isl_vec_mat_product(v, isl_mat_copy(T));
+	if (!v)
+		goto error;
+	res = isl_basic_set_solve_ilp(bset, max, v->el, opt, sol_p);
+	isl_vec_free(v);
+	if (res == isl_lp_ok && sol_p) {
+		*sol_p = isl_mat_vec_product(T, *sol_p);
+		if (!*sol_p)
+			res = isl_lp_error;
+	} else
+		isl_mat_free(T);
+	isl_basic_set_free(bset);
+	return res;
+error:
+	isl_mat_free(T);
+	isl_basic_set_free(bset);
+	return isl_lp_error;
+}
+
+/* Find an integer point in "bset" that minimizes (or maximizes if max is set)
+ * f (if any).
+ * If sol_p is not NULL then the integer point is returned in *sol_p.
+ * The optimal value of f is returned in *opt.
+ *
+ * If there is any equality among the points in "bset", then we first
+ * project it out.  Otherwise, we continue with solve_ilp above.
+ */
+enum isl_lp_result isl_basic_set_solve_ilp(__isl_keep isl_basic_set *bset,
+	int max, isl_int *f, isl_int *opt, __isl_give isl_vec **sol_p)
+{
+	unsigned dim;
+	enum isl_lp_result res;
+
+	if (!bset)
+		return isl_lp_error;
+	if (sol_p)
+		*sol_p = NULL;
+
+	isl_assert(bset->ctx, isl_basic_set_n_param(bset) == 0,
+		return isl_lp_error);
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return isl_lp_empty;
+
+	if (bset->n_eq)
+		return solve_ilp_with_eq(bset, max, f, opt, sol_p);
+
+	dim = isl_basic_set_total_dim(bset);
+
+	if (max)
+		isl_seq_neg(f, f, 1 + dim);
+
+	res = solve_ilp(bset, f, opt, sol_p);
+
+	if (max) {
+		isl_seq_neg(f, f, 1 + dim);
+		isl_int_neg(*opt, *opt);
+	}
+
+	return res;
+}
+
+static enum isl_lp_result basic_set_opt(__isl_keep isl_basic_set *bset, int max,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	enum isl_lp_result res;
+
+	if (!obj)
+		return isl_lp_error;
+	bset = isl_basic_set_copy(bset);
+	bset = isl_basic_set_underlying_set(bset);
+	res = isl_basic_set_solve_ilp(bset, max, obj->v->el + 1, opt, NULL);
+	isl_basic_set_free(bset);
+	return res;
+}
+
+static __isl_give isl_mat *extract_divs(__isl_keep isl_basic_set *bset)
+{
+	int i;
+	isl_ctx *ctx = isl_basic_set_get_ctx(bset);
+	isl_mat *div;
+
+	div = isl_mat_alloc(ctx, bset->n_div,
+			    1 + 1 + isl_basic_set_total_dim(bset));
+	if (!div)
+		return NULL;
+
+	for (i = 0; i < bset->n_div; ++i)
+		isl_seq_cpy(div->row[i], bset->div[i], div->n_col);
+
+	return div;
+}
+
+enum isl_lp_result isl_basic_set_opt(__isl_keep isl_basic_set *bset, int max,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_ctx *ctx;
+	isl_mat *bset_div = NULL;
+	isl_mat *div = NULL;
+	enum isl_lp_result res;
+	int bset_n_div, obj_n_div;
+
+	if (!bset || !obj)
+		return isl_lp_error;
+
+	ctx = isl_aff_get_ctx(obj);
+	if (!isl_space_is_equal(bset->dim, obj->ls->dim))
+		isl_die(ctx, isl_error_invalid,
+			"spaces don't match", return isl_lp_error);
+	if (!isl_int_is_one(obj->v->el[0]))
+		isl_die(ctx, isl_error_unsupported,
+			"expecting integer affine expression",
+			return isl_lp_error);
+
+	bset_n_div = isl_basic_set_dim(bset, isl_dim_div);
+	obj_n_div = isl_aff_dim(obj, isl_dim_div);
+	if (bset_n_div == 0 && obj_n_div == 0)
+		return basic_set_opt(bset, max, obj, opt);
+
+	bset = isl_basic_set_copy(bset);
+	obj = isl_aff_copy(obj);
+
+	bset_div = extract_divs(bset);
+	exp1 = isl_alloc_array(ctx, int, bset_n_div);
+	exp2 = isl_alloc_array(ctx, int, obj_n_div);
+	if (!bset_div || (bset_n_div && !exp1) || (obj_n_div && !exp2))
+		goto error;
+
+	div = isl_merge_divs(bset_div, obj->ls->div, exp1, exp2);
+
+	bset = isl_basic_set_expand_divs(bset, isl_mat_copy(div), exp1);
+	obj = isl_aff_expand_divs(obj, isl_mat_copy(div), exp2);
+
+	res = basic_set_opt(bset, max, obj, opt);
+
+	isl_mat_free(bset_div);
+	isl_mat_free(div);
+	free(exp1);
+	free(exp2);
+	isl_basic_set_free(bset);
+	isl_aff_free(obj);
+
+	return res;
+error:
+	isl_mat_free(div);
+	isl_mat_free(bset_div);
+	free(exp1);
+	free(exp2);
+	isl_basic_set_free(bset);
+	isl_aff_free(obj);
+	return isl_lp_error;
+}
+
+/* Compute the minimum (maximum if max is set) of the integer affine
+ * expression obj over the points in set and put the result in *opt.
+ *
+ * The parameters are assumed to have been aligned.
+ */
+static enum isl_lp_result isl_set_opt_aligned(__isl_keep isl_set *set, int max,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	int i;
+	enum isl_lp_result res;
+	int empty = 1;
+	isl_int opt_i;
+
+	if (!set || !obj)
+		return isl_lp_error;
+	if (set->n == 0)
+		return isl_lp_empty;
+
+	res = isl_basic_set_opt(set->p[0], max, obj, opt);
+	if (res == isl_lp_error || res == isl_lp_unbounded)
+		return res;
+	if (set->n == 1)
+		return res;
+	if (res == isl_lp_ok)
+		empty = 0;
+
+	isl_int_init(opt_i);
+	for (i = 1; i < set->n; ++i) {
+		res = isl_basic_set_opt(set->p[i], max, obj, &opt_i);
+		if (res == isl_lp_error || res == isl_lp_unbounded) {
+			isl_int_clear(opt_i);
+			return res;
+		}
+		if (res == isl_lp_empty)
+			continue;
+		empty = 0;
+		if (max ? isl_int_gt(opt_i, *opt) : isl_int_lt(opt_i, *opt))
+			isl_int_set(*opt, opt_i);
+	}
+	isl_int_clear(opt_i);
+
+	return empty ? isl_lp_empty : isl_lp_ok;
+}
+
+/* Compute the minimum (maximum if max is set) of the integer affine
+ * expression obj over the points in set and put the result in *opt.
+ */
+enum isl_lp_result isl_set_opt(__isl_keep isl_set *set, int max,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	enum isl_lp_result res;
+	isl_bool aligned;
+
+	if (!set || !obj)
+		return isl_lp_error;
+
+	aligned = isl_set_space_has_equal_params(set, obj->ls->dim);
+	if (aligned < 0)
+		return isl_lp_error;
+	if (aligned)
+		return isl_set_opt_aligned(set, max, obj, opt);
+
+	set = isl_set_copy(set);
+	obj = isl_aff_copy(obj);
+	set = isl_set_align_params(set, isl_aff_get_domain_space(obj));
+	obj = isl_aff_align_params(obj, isl_set_get_space(set));
+
+	res = isl_set_opt_aligned(set, max, obj, opt);
+
+	isl_set_free(set);
+	isl_aff_free(obj);
+
+	return res;
+}
+
+enum isl_lp_result isl_basic_set_max(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	return isl_basic_set_opt(bset, 1, obj, opt);
+}
+
+enum isl_lp_result isl_set_max(__isl_keep isl_set *set,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	return isl_set_opt(set, 1, obj, opt);
+}
+
+enum isl_lp_result isl_set_min(__isl_keep isl_set *set,
+	__isl_keep isl_aff *obj, isl_int *opt)
+{
+	return isl_set_opt(set, 0, obj, opt);
+}
+
+/* Convert the result of a function that returns an isl_lp_result
+ * to an isl_val.  The numerator of "v" is set to the optimal value
+ * if lp_res is isl_lp_ok.  "max" is set if a maximum was computed.
+ *
+ * Return "v" with denominator set to 1 if lp_res is isl_lp_ok.
+ * Return NULL on error.
+ * Return a NaN if lp_res is isl_lp_empty.
+ * Return infinity or negative infinity if lp_res is isl_lp_unbounded,
+ * depending on "max".
+ */
+static __isl_give isl_val *convert_lp_result(enum isl_lp_result lp_res,
+	__isl_take isl_val *v, int max)
+{
+	isl_ctx *ctx;
+
+	if (lp_res == isl_lp_ok) {
+		isl_int_set_si(v->d, 1);
+		return isl_val_normalize(v);
+	}
+	ctx = isl_val_get_ctx(v);
+	isl_val_free(v);
+	if (lp_res == isl_lp_error)
+		return NULL;
+	if (lp_res == isl_lp_empty)
+		return isl_val_nan(ctx);
+	if (max)
+		return isl_val_infty(ctx);
+	else
+		return isl_val_neginfty(ctx);
+}
+
+/* Return the minimum (maximum if max is set) of the integer affine
+ * expression "obj" over the points in "bset".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ *
+ * Call isl_basic_set_opt and translate the results.
+ */
+__isl_give isl_val *isl_basic_set_opt_val(__isl_keep isl_basic_set *bset,
+	int max, __isl_keep isl_aff *obj)
+{
+	isl_ctx *ctx;
+	isl_val *res;
+	enum isl_lp_result lp_res;
+
+	if (!bset || !obj)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(obj);
+	res = isl_val_alloc(ctx);
+	if (!res)
+		return NULL;
+	lp_res = isl_basic_set_opt(bset, max, obj, &res->n);
+	return convert_lp_result(lp_res, res, max);
+}
+
+/* Return the maximum of the integer affine
+ * expression "obj" over the points in "bset".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_basic_set_max_val(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_aff *obj)
+{
+	return isl_basic_set_opt_val(bset, 1, obj);
+}
+
+/* Return the minimum (maximum if max is set) of the integer affine
+ * expression "obj" over the points in "set".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "set" is empty.
+ *
+ * Call isl_set_opt and translate the results.
+ */
+__isl_give isl_val *isl_set_opt_val(__isl_keep isl_set *set, int max,
+	__isl_keep isl_aff *obj)
+{
+	isl_ctx *ctx;
+	isl_val *res;
+	enum isl_lp_result lp_res;
+
+	if (!set || !obj)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(obj);
+	res = isl_val_alloc(ctx);
+	if (!res)
+		return NULL;
+	lp_res = isl_set_opt(set, max, obj, &res->n);
+	return convert_lp_result(lp_res, res, max);
+}
+
+/* Return the minimum of the integer affine
+ * expression "obj" over the points in "set".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "set" is empty.
+ */
+__isl_give isl_val *isl_set_min_val(__isl_keep isl_set *set,
+	__isl_keep isl_aff *obj)
+{
+	return isl_set_opt_val(set, 0, obj);
+}
+
+/* Return the maximum of the integer affine
+ * expression "obj" over the points in "set".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "set" is empty.
+ */
+__isl_give isl_val *isl_set_max_val(__isl_keep isl_set *set,
+	__isl_keep isl_aff *obj)
+{
+	return isl_set_opt_val(set, 1, obj);
+}
+
+/* Return the optimum (min or max depending on "max") of "v1" and "v2",
+ * where either may be NaN, signifying an uninitialized value.
+ * That is, if either is NaN, then return the other one.
+ */
+static __isl_give isl_val *val_opt(__isl_take isl_val *v1,
+	__isl_take isl_val *v2, int max)
+{
+	if (!v1 || !v2)
+		goto error;
+	if (isl_val_is_nan(v1)) {
+		isl_val_free(v1);
+		return v2;
+	}
+	if (isl_val_is_nan(v2)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (max)
+		return isl_val_max(v1, v2);
+	else
+		return isl_val_min(v1, v2);
+error:
+	isl_val_free(v1);
+	isl_val_free(v2);
+	return NULL;
+}
+
+/* Internal data structure for isl_set_opt_pw_aff.
+ *
+ * "max" is set if the maximum should be computed.
+ * "set" is the set over which the optimum should be computed.
+ * "res" contains the current optimum and is initialized to NaN.
+ */
+struct isl_set_opt_data {
+	int max;
+	isl_set *set;
+
+	isl_val *res;
+};
+
+/* Update the optimum in data->res with respect to the affine function
+ * "aff" defined over "set".
+ */
+static isl_stat piece_opt(__isl_take isl_set *set, __isl_take isl_aff *aff,
+	void *user)
+{
+	struct isl_set_opt_data *data = user;
+	isl_val *opt;
+
+	set = isl_set_intersect(set, isl_set_copy(data->set));
+	opt = isl_set_opt_val(set, data->max, aff);
+	isl_set_free(set);
+	isl_aff_free(aff);
+
+	data->res = val_opt(data->res, opt, data->max);
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Return the minimum (maximum if "max" is set) of the integer piecewise affine
+ * expression "obj" over the points in "set".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if the intersection of "set" with the domain of "obj" is empty.
+ *
+ * Initialize the result to NaN and then update it for each of the pieces
+ * in "obj".
+ */
+static __isl_give isl_val *isl_set_opt_pw_aff(__isl_keep isl_set *set, int max,
+	__isl_keep isl_pw_aff *obj)
+{
+	struct isl_set_opt_data data = { max, set };
+
+	data.res = isl_val_nan(isl_set_get_ctx(set));
+	if (isl_pw_aff_foreach_piece(obj, &piece_opt, &data) < 0)
+		return isl_val_free(data.res);
+
+	return data.res;
+}
+
+/* Internal data structure for isl_union_set_opt_union_pw_aff.
+ *
+ * "max" is set if the maximum should be computed.
+ * "obj" is the objective function that needs to be optimized.
+ * "res" contains the current optimum and is initialized to NaN.
+ */
+struct isl_union_set_opt_data {
+	int max;
+	isl_union_pw_aff *obj;
+
+	isl_val *res;
+};
+
+/* Update the optimum in data->res with the optimum over "set".
+ * Do so by first extracting the matching objective function
+ * from data->obj.
+ */
+static isl_stat set_opt(__isl_take isl_set *set, void *user)
+{
+	struct isl_union_set_opt_data *data = user;
+	isl_space *space;
+	isl_pw_aff *pa;
+	isl_val *opt;
+
+	space = isl_set_get_space(set);
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, 1);
+	pa = isl_union_pw_aff_extract_pw_aff(data->obj, space);
+	opt = isl_set_opt_pw_aff(set, data->max, pa);
+	isl_pw_aff_free(pa);
+	isl_set_free(set);
+
+	data->res = val_opt(data->res, opt, data->max);
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Return the minimum (maximum if "max" is set) of the integer piecewise affine
+ * expression "obj" over the points in "uset".
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if the intersection of "uset" with the domain of "obj" is empty.
+ *
+ * Initialize the result to NaN and then update it for each of the sets
+ * in "uset".
+ */
+static __isl_give isl_val *isl_union_set_opt_union_pw_aff(
+	__isl_keep isl_union_set *uset, int max,
+	__isl_keep isl_union_pw_aff *obj)
+{
+	struct isl_union_set_opt_data data = { max, obj };
+
+	data.res = isl_val_nan(isl_union_set_get_ctx(uset));
+	if (isl_union_set_foreach_set(uset, &set_opt, &data) < 0)
+		return isl_val_free(data.res);
+
+	return data.res;
+}
+
+/* Return a list of minima (maxima if "max" is set) over the points in "uset"
+ * for each of the expressions in "obj".
+ *
+ * An element in the list is infinity or negative infinity if the optimal
+ * value of the corresponding expression is unbounded and
+ * NaN if the intersection of "uset" with the domain of the expression
+ * is empty.
+ *
+ * Iterate over all the expressions in "obj" and collect the results.
+ */
+static __isl_give isl_multi_val *isl_union_set_opt_multi_union_pw_aff(
+	__isl_keep isl_union_set *uset, int max,
+	__isl_keep isl_multi_union_pw_aff *obj)
+{
+	int i, n;
+	isl_multi_val *mv;
+
+	if (!uset || !obj)
+		return NULL;
+
+	n = isl_multi_union_pw_aff_dim(obj, isl_dim_set);
+	mv = isl_multi_val_zero(isl_multi_union_pw_aff_get_space(obj));
+
+	for (i = 0; i < n; ++i) {
+		isl_val *v;
+		isl_union_pw_aff *upa;
+
+		upa = isl_multi_union_pw_aff_get_union_pw_aff(obj, i);
+		v = isl_union_set_opt_union_pw_aff(uset, max, upa);
+		isl_union_pw_aff_free(upa);
+		mv = isl_multi_val_set_val(mv, i, v);
+	}
+
+	return mv;
+}
+
+/* Return a list of minima over the points in "uset"
+ * for each of the expressions in "obj".
+ *
+ * An element in the list is infinity or negative infinity if the optimal
+ * value of the corresponding expression is unbounded and
+ * NaN if the intersection of "uset" with the domain of the expression
+ * is empty.
+ */
+__isl_give isl_multi_val *isl_union_set_min_multi_union_pw_aff(
+	__isl_keep isl_union_set *uset, __isl_keep isl_multi_union_pw_aff *obj)
+{
+	return isl_union_set_opt_multi_union_pw_aff(uset, 0, obj);
+}
diff --git a/final/lib/External/isl/isl_ilp_private.h b/final/lib/External/isl/isl_ilp_private.h
new file mode 100644
index 0000000..932b2c3
--- /dev/null
+++ b/final/lib/External/isl/isl_ilp_private.h
@@ -0,0 +1,11 @@
+#ifndef ISL_ILP_PRIVATE_H
+#define ISL_ILP_PRIVATE_H
+
+#include <isl_int.h>
+#include <isl/lp.h>
+#include <isl/set.h>
+
+enum isl_lp_result isl_basic_set_solve_ilp(__isl_keep isl_basic_set *bset,
+	int max, isl_int *f, isl_int *opt, __isl_give isl_vec **sol_p);
+
+#endif
diff --git a/final/lib/External/isl/isl_imath.c b/final/lib/External/isl/isl_imath.c
new file mode 100644
index 0000000..d870f14
--- /dev/null
+++ b/final/lib/External/isl/isl_imath.c
@@ -0,0 +1,83 @@
+#include <isl_int.h>
+
+uint32_t isl_imath_hash(mp_int v, uint32_t hash)
+{
+	unsigned const char *data = (unsigned char *)v->digits;
+	unsigned const char *end = data + v->used * sizeof(v->digits[0]);
+
+	if (v->sign == 1)
+		isl_hash_byte(hash, 0xFF);
+	for (; data < end; ++data)
+		isl_hash_byte(hash, *data);
+	return hash;
+}
+
+/* Try a standard conversion that fits into a long.
+ */
+int isl_imath_fits_slong_p(mp_int op)
+{
+	long out;
+	mp_result res = mp_int_to_int(op, &out);
+	return res == MP_OK;
+}
+
+/* Try a standard conversion that fits into an unsigned long.
+ */
+int isl_imath_fits_ulong_p(mp_int op)
+{
+	unsigned long out;
+	mp_result res = mp_int_to_uint(op, &out);
+	return res == MP_OK;
+}
+
+void isl_imath_addmul_ui(mp_int rop, mp_int op1, unsigned long op2)
+{
+	mpz_t temp;
+	mp_int_init(&temp);
+
+	mp_int_set_uvalue(&temp, op2);
+	mp_int_mul(op1, &temp, &temp);
+	mp_int_add(rop, &temp, rop);
+
+	mp_int_clear(&temp);
+}
+
+void isl_imath_submul_ui(mp_int rop, mp_int op1, unsigned long op2)
+{
+	mpz_t temp;
+	mp_int_init(&temp);
+
+	mp_int_set_uvalue(&temp, op2);
+	mp_int_mul(op1, &temp, &temp);
+	mp_int_sub(rop, &temp, rop);
+
+	mp_int_clear(&temp);
+}
+
+/* Compute the division of lhs by a rhs of type unsigned long, rounding towards
+ * positive infinity (Ceil).
+ */
+void isl_imath_cdiv_q_ui(mp_int rop, mp_int lhs, unsigned long rhs)
+{
+	mpz_t temp;
+	mp_int_init(&temp);
+
+	mp_int_set_uvalue(&temp, rhs);
+	impz_cdiv_q(rop, lhs, &temp);
+
+	mp_int_clear(&temp);
+}
+
+/* Compute the division of lhs by a rhs of type unsigned long, rounding towards
+ * negative infinity (Floor).
+ */
+void isl_imath_fdiv_q_ui(mp_int rop, mp_int lhs, unsigned long rhs)
+{
+	mpz_t temp;
+	mp_int_init(&temp);
+
+	mp_int_set_uvalue(&temp, rhs);
+	impz_fdiv_q(rop, lhs, &temp);
+
+	mp_int_clear(&temp);
+}
diff --git a/final/lib/External/isl/isl_imath.h b/final/lib/External/isl/isl_imath.h
new file mode 100644
index 0000000..9efbe31
--- /dev/null
+++ b/final/lib/External/isl/isl_imath.h
@@ -0,0 +1,10 @@
+#include <imath.h>
+#include <gmp_compat.h>
+
+uint32_t isl_imath_hash(mp_int v, uint32_t hash);
+int isl_imath_fits_ulong_p(mp_int op);
+int isl_imath_fits_slong_p(mp_int op);
+void isl_imath_addmul_ui(mp_int rop, mp_int op1, unsigned long op2);
+void isl_imath_submul_ui(mp_int rop, mp_int op1, unsigned long op2);
+void isl_imath_cdiv_q_ui(mp_int rop, mp_int op1, unsigned long op2);
+void isl_imath_fdiv_q_ui(mp_int rop, mp_int op1, unsigned long op2);
diff --git a/final/lib/External/isl/isl_input.c b/final/lib/External/isl/isl_input.c
new file mode 100644
index 0000000..e122053
--- /dev/null
+++ b/final/lib/External/isl/isl_input.c
@@ -0,0 +1,4050 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/set.h>
+#include <isl_seq.h>
+#include <isl_stream_private.h>
+#include <isl/obj.h>
+#include "isl_polynomial_private.h"
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl_mat_private.h>
+#include <isl_aff_private.h>
+#include <isl_vec_private.h>
+#include <isl/list.h>
+#include <isl_val_private.h>
+
+struct variable {
+	char    	    	*name;
+	int	     		 pos;
+	struct variable		*next;
+};
+
+struct vars {
+	struct isl_ctx	*ctx;
+	int		 n;
+	struct variable	*v;
+};
+
+static struct vars *vars_new(struct isl_ctx *ctx)
+{
+	struct vars *v;
+	v = isl_alloc_type(ctx, struct vars);
+	if (!v)
+		return NULL;
+	v->ctx = ctx;
+	v->n = 0;
+	v->v = NULL;
+	return v;
+}
+
+static void variable_free(struct variable *var)
+{
+	while (var) {
+		struct variable *next = var->next;
+		free(var->name);
+		free(var);
+		var = next;
+	}
+}
+
+static void vars_free(struct vars *v)
+{
+	if (!v)
+		return;
+	variable_free(v->v);
+	free(v);
+}
+
+static void vars_drop(struct vars *v, int n)
+{
+	struct variable *var;
+
+	if (!v || !v->v)
+		return;
+
+	v->n -= n;
+
+	var = v->v;
+	while (--n >= 0) {
+		struct variable *next = var->next;
+		free(var->name);
+		free(var);
+		var = next;
+	}
+	v->v = var;
+}
+
+static struct variable *variable_new(struct vars *v, const char *name, int len,
+				int pos)
+{
+	struct variable *var;
+	var = isl_calloc_type(v->ctx, struct variable);
+	if (!var)
+		goto error;
+	var->name = strdup(name);
+	var->name[len] = '\0';
+	var->pos = pos;
+	var->next = v->v;
+	return var;
+error:
+	variable_free(v->v);
+	return NULL;
+}
+
+static int vars_pos(struct vars *v, const char *s, int len)
+{
+	int pos;
+	struct variable *q;
+
+	if (len == -1)
+		len = strlen(s);
+	for (q = v->v; q; q = q->next) {
+		if (strncmp(q->name, s, len) == 0 && q->name[len] == '\0')
+			break;
+	}
+	if (q)
+		pos = q->pos;
+	else {
+		pos = v->n;
+		v->v = variable_new(v, s, len, v->n);
+		if (!v->v)
+			return -1;
+		v->n++;
+	}
+	return pos;
+}
+
+static int vars_add_anon(struct vars *v)
+{
+	v->v = variable_new(v, "", 0, v->n);
+
+	if (!v->v)
+		return -1;
+	v->n++;
+
+	return 0;
+}
+
+/* Obtain next token, with some preprocessing.
+ * In particular, evaluate expressions of the form x^y,
+ * with x and y values.
+ */
+static struct isl_token *next_token(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok, *tok2;
+
+	tok = isl_stream_next_token(s);
+	if (!tok || tok->type != ISL_TOKEN_VALUE)
+		return tok;
+	if (!isl_stream_eat_if_available(s, '^'))
+		return tok;
+	tok2 = isl_stream_next_token(s);
+	if (!tok2 || tok2->type != ISL_TOKEN_VALUE) {
+		isl_stream_error(s, tok2, "expecting constant value");
+		goto error;
+	}
+
+	isl_int_pow_ui(tok->u.v, tok->u.v, isl_int_get_ui(tok2->u.v));
+
+	isl_token_free(tok2);
+	return tok;
+error:
+	isl_token_free(tok);
+	isl_token_free(tok2);
+	return NULL;
+}
+
+/* Read an isl_val from "s".
+ *
+ * The following token sequences are recognized
+ *
+ *	"infty"		->	infty
+ *	"-" "infty"	->	-infty
+ *	"NaN"		->	NaN
+ *	n "/" d		->	n/d
+ *	v		->	v
+ *
+ * where n, d and v are integer constants.
+ */
+__isl_give isl_val *isl_stream_read_val(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok = NULL;
+	struct isl_token *tok2 = NULL;
+	isl_val *val;
+
+	tok = next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		goto error;
+	}
+	if (tok->type == ISL_TOKEN_INFTY) {
+		isl_token_free(tok);
+		return isl_val_infty(s->ctx);
+	}
+	if (tok->type == '-' &&
+	    isl_stream_eat_if_available(s, ISL_TOKEN_INFTY)) {
+		isl_token_free(tok);
+		return isl_val_neginfty(s->ctx);
+	}
+	if (tok->type == ISL_TOKEN_NAN) {
+		isl_token_free(tok);
+		return isl_val_nan(s->ctx);
+	}
+	if (tok->type != ISL_TOKEN_VALUE) {
+		isl_stream_error(s, tok, "expecting value");
+		goto error;
+	}
+
+	if (isl_stream_eat_if_available(s, '/')) {
+		tok2 = next_token(s);
+		if (!tok2) {
+			isl_stream_error(s, NULL, "unexpected EOF");
+			goto error;
+		}
+		if (tok2->type != ISL_TOKEN_VALUE) {
+			isl_stream_error(s, tok2, "expecting value");
+			goto error;
+		}
+		val = isl_val_rat_from_isl_int(s->ctx, tok->u.v, tok2->u.v);
+		val = isl_val_normalize(val);
+	} else {
+		val = isl_val_int_from_isl_int(s->ctx, tok->u.v);
+	}
+
+	isl_token_free(tok);
+	isl_token_free(tok2);
+	return val;
+error:
+	isl_token_free(tok);
+	isl_token_free(tok2);
+	return NULL;
+}
+
+/* Read an isl_val from "str".
+ */
+struct isl_val *isl_val_read_from_str(struct isl_ctx *ctx,
+	const char *str)
+{
+	isl_val *val;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	val = isl_stream_read_val(s);
+	isl_stream_free(s);
+	return val;
+}
+
+static int accept_cst_factor(__isl_keep isl_stream *s, isl_int *f)
+{
+	struct isl_token *tok;
+
+	tok = next_token(s);
+	if (!tok || tok->type != ISL_TOKEN_VALUE) {
+		isl_stream_error(s, tok, "expecting constant value");
+		goto error;
+	}
+
+	isl_int_mul(*f, *f, tok->u.v);
+
+	isl_token_free(tok);
+
+	if (isl_stream_eat_if_available(s, '*'))
+		return accept_cst_factor(s, f);
+
+	return 0;
+error:
+	isl_token_free(tok);
+	return -1;
+}
+
+/* Given an affine expression aff, return an affine expression
+ * for aff % d, with d the next token on the stream, which is
+ * assumed to be a constant.
+ *
+ * We introduce an integer division q = [aff/d] and the result
+ * is set to aff - d q.
+ */
+static __isl_give isl_pw_aff *affine_mod(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_pw_aff *aff)
+{
+	struct isl_token *tok;
+	isl_pw_aff *q;
+
+	tok = next_token(s);
+	if (!tok || tok->type != ISL_TOKEN_VALUE) {
+		isl_stream_error(s, tok, "expecting constant value");
+		goto error;
+	}
+
+	q = isl_pw_aff_copy(aff);
+	q = isl_pw_aff_scale_down(q, tok->u.v);
+	q = isl_pw_aff_floor(q);
+	q = isl_pw_aff_scale(q, tok->u.v);
+
+	aff = isl_pw_aff_sub(aff, q);
+
+	isl_token_free(tok);
+	return aff;
+error:
+	isl_pw_aff_free(aff);
+	isl_token_free(tok);
+	return NULL;
+}
+
+static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s,
+	__isl_take isl_space *space, struct vars *v);
+static __isl_give isl_pw_aff_list *accept_affine_list(__isl_keep isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v);
+
+static __isl_give isl_pw_aff *accept_minmax(__isl_keep isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v)
+{
+	struct isl_token *tok;
+	isl_pw_aff_list *list = NULL;
+	int min;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		goto error;
+	min = tok->type == ISL_TOKEN_MIN;
+	isl_token_free(tok);
+
+	if (isl_stream_eat(s, '('))
+		goto error;
+
+	list = accept_affine_list(s, isl_space_copy(dim), v);
+	if (!list)
+		goto error;
+
+	if (isl_stream_eat(s, ')'))
+		goto error;
+
+	isl_space_free(dim);
+	return min ? isl_pw_aff_list_min(list) : isl_pw_aff_list_max(list);
+error:
+	isl_space_free(dim);
+	isl_pw_aff_list_free(list);
+	return NULL;
+}
+
+/* Is "tok" the start of an integer division?
+ */
+static int is_start_of_div(struct isl_token *tok)
+{
+	if (!tok)
+		return 0;
+	if (tok->type == '[')
+		return 1;
+	if (tok->type == ISL_TOKEN_FLOOR)
+		return 1;
+	if (tok->type == ISL_TOKEN_CEIL)
+		return 1;
+	if (tok->type == ISL_TOKEN_FLOORD)
+		return 1;
+	if (tok->type == ISL_TOKEN_CEILD)
+		return 1;
+	return 0;
+}
+
+/* Read an integer division from "s" and return it as an isl_pw_aff.
+ *
+ * The integer division can be of the form
+ *
+ *	[<affine expression>]
+ *	floor(<affine expression>)
+ *	ceil(<affine expression>)
+ *	floord(<affine expression>,<denominator>)
+ *	ceild(<affine expression>,<denominator>)
+ */
+static __isl_give isl_pw_aff *accept_div(__isl_keep isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v)
+{
+	struct isl_token *tok;
+	int f = 0;
+	int c = 0;
+	int extra = 0;
+	isl_pw_aff *pwaff = NULL;
+
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_FLOORD))
+		extra = f = 1;
+	else if (isl_stream_eat_if_available(s, ISL_TOKEN_CEILD))
+		extra = c = 1;
+	else if (isl_stream_eat_if_available(s, ISL_TOKEN_FLOOR))
+		f = 1;
+	else if (isl_stream_eat_if_available(s, ISL_TOKEN_CEIL))
+		c = 1;
+	if (f || c) {
+		if (isl_stream_eat(s, '('))
+			goto error;
+	} else {
+		if (isl_stream_eat(s, '['))
+			goto error;
+	}
+
+	pwaff = accept_affine(s, isl_space_copy(dim), v);
+
+	if (extra) {
+		if (isl_stream_eat(s, ','))
+			goto error;
+
+		tok = next_token(s);
+		if (!tok)
+			goto error;
+		if (tok->type != ISL_TOKEN_VALUE) {
+			isl_stream_error(s, tok, "expected denominator");
+			isl_stream_push_token(s, tok);
+			goto error;
+		}
+		pwaff = isl_pw_aff_scale_down(pwaff,  tok->u.v);
+		isl_token_free(tok);
+	}
+
+	if (c)
+		pwaff = isl_pw_aff_ceil(pwaff);
+	else
+		pwaff = isl_pw_aff_floor(pwaff);
+
+	if (f || c) {
+		if (isl_stream_eat(s, ')'))
+			goto error;
+	} else {
+		if (isl_stream_eat(s, ']'))
+			goto error;
+	}
+
+	isl_space_free(dim);
+	return pwaff;
+error:
+	isl_space_free(dim);
+	isl_pw_aff_free(pwaff);
+	return NULL;
+}
+
+static __isl_give isl_pw_aff *accept_affine_factor(__isl_keep isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v)
+{
+	struct isl_token *tok = NULL;
+	isl_pw_aff *res = NULL;
+
+	tok = next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		goto error;
+	}
+
+	if (tok->type == ISL_TOKEN_AFF) {
+		res = isl_pw_aff_copy(tok->u.pwaff);
+		isl_token_free(tok);
+	} else if (tok->type == ISL_TOKEN_IDENT) {
+		int n = v->n;
+		int pos = vars_pos(v, tok->u.s, -1);
+		isl_aff *aff;
+
+		if (pos < 0)
+			goto error;
+		if (pos >= n) {
+			vars_drop(v, v->n - n);
+			isl_stream_error(s, tok, "unknown identifier");
+			goto error;
+		}
+
+		aff = isl_aff_zero_on_domain(isl_local_space_from_space(isl_space_copy(dim)));
+		if (!aff)
+			goto error;
+		isl_int_set_si(aff->v->el[2 + pos], 1);
+		res = isl_pw_aff_from_aff(aff);
+		isl_token_free(tok);
+	} else if (tok->type == ISL_TOKEN_VALUE) {
+		if (isl_stream_eat_if_available(s, '*')) {
+			res = accept_affine_factor(s, isl_space_copy(dim), v);
+			res = isl_pw_aff_scale(res, tok->u.v);
+		} else {
+			isl_local_space *ls;
+			isl_aff *aff;
+			ls = isl_local_space_from_space(isl_space_copy(dim));
+			aff = isl_aff_zero_on_domain(ls);
+			aff = isl_aff_add_constant(aff, tok->u.v);
+			res = isl_pw_aff_from_aff(aff);
+		}
+		isl_token_free(tok);
+	} else if (tok->type == '(') {
+		isl_token_free(tok);
+		tok = NULL;
+		res = accept_affine(s, isl_space_copy(dim), v);
+		if (!res)
+			goto error;
+		if (isl_stream_eat(s, ')'))
+			goto error;
+	} else if (is_start_of_div(tok)) {
+		isl_stream_push_token(s, tok);
+		tok = NULL;
+		res = accept_div(s, isl_space_copy(dim), v);
+	} else if (tok->type == ISL_TOKEN_MIN || tok->type == ISL_TOKEN_MAX) {
+		isl_stream_push_token(s, tok);
+		tok = NULL;
+		res = accept_minmax(s, isl_space_copy(dim), v);
+	} else {
+		isl_stream_error(s, tok, "expecting factor");
+		goto error;
+	}
+	if (isl_stream_eat_if_available(s, '%') ||
+	    isl_stream_eat_if_available(s, ISL_TOKEN_MOD)) {
+		isl_space_free(dim);
+		return affine_mod(s, v, res);
+	}
+	if (isl_stream_eat_if_available(s, '*')) {
+		isl_int f;
+		isl_int_init(f);
+		isl_int_set_si(f, 1);
+		if (accept_cst_factor(s, &f) < 0) {
+			isl_int_clear(f);
+			goto error2;
+		}
+		res = isl_pw_aff_scale(res, f);
+		isl_int_clear(f);
+	}
+	if (isl_stream_eat_if_available(s, '/')) {
+		isl_int f;
+		isl_int_init(f);
+		isl_int_set_si(f, 1);
+		if (accept_cst_factor(s, &f) < 0) {
+			isl_int_clear(f);
+			goto error2;
+		}
+		res = isl_pw_aff_scale_down(res, f);
+		isl_int_clear(f);
+	}
+
+	isl_space_free(dim);
+	return res;
+error:
+	isl_token_free(tok);
+error2:
+	isl_pw_aff_free(res);
+	isl_space_free(dim);
+	return NULL;
+}
+
+static __isl_give isl_pw_aff *add_cst(__isl_take isl_pw_aff *pwaff, isl_int v)
+{
+	isl_aff *aff;
+	isl_space *space;
+
+	space = isl_pw_aff_get_domain_space(pwaff);
+	aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+	aff = isl_aff_add_constant(aff, v);
+
+	return isl_pw_aff_add(pwaff, isl_pw_aff_from_aff(aff));
+}
+
+/* Return a piecewise affine expression defined on the specified domain
+ * that represents NaN.
+ */
+static __isl_give isl_pw_aff *nan_on_domain(__isl_keep isl_space *space)
+{
+	isl_local_space *ls;
+
+	ls = isl_local_space_from_space(isl_space_copy(space));
+	return isl_pw_aff_nan_on_domain(ls);
+}
+
+static __isl_give isl_pw_aff *accept_affine(__isl_keep isl_stream *s,
+	__isl_take isl_space *space, struct vars *v)
+{
+	struct isl_token *tok = NULL;
+	isl_local_space *ls;
+	isl_pw_aff *res;
+	int sign = 1;
+
+	ls = isl_local_space_from_space(isl_space_copy(space));
+	res = isl_pw_aff_from_aff(isl_aff_zero_on_domain(ls));
+	if (!res)
+		goto error;
+
+	for (;;) {
+		tok = next_token(s);
+		if (!tok) {
+			isl_stream_error(s, NULL, "unexpected EOF");
+			goto error;
+		}
+		if (tok->type == '-') {
+			sign = -sign;
+			isl_token_free(tok);
+			continue;
+		}
+		if (tok->type == '(' || is_start_of_div(tok) ||
+		    tok->type == ISL_TOKEN_MIN || tok->type == ISL_TOKEN_MAX ||
+		    tok->type == ISL_TOKEN_IDENT ||
+		    tok->type == ISL_TOKEN_AFF) {
+			isl_pw_aff *term;
+			isl_stream_push_token(s, tok);
+			tok = NULL;
+			term = accept_affine_factor(s,
+						    isl_space_copy(space), v);
+			if (sign < 0)
+				res = isl_pw_aff_sub(res, term);
+			else
+				res = isl_pw_aff_add(res, term);
+			if (!res)
+				goto error;
+			sign = 1;
+		} else if (tok->type == ISL_TOKEN_VALUE) {
+			if (sign < 0)
+				isl_int_neg(tok->u.v, tok->u.v);
+			if (isl_stream_eat_if_available(s, '*') ||
+			    isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) {
+				isl_pw_aff *term;
+				term = accept_affine_factor(s,
+						    isl_space_copy(space), v);
+				term = isl_pw_aff_scale(term, tok->u.v);
+				res = isl_pw_aff_add(res, term);
+				if (!res)
+					goto error;
+			} else {
+				res = add_cst(res, tok->u.v);
+			}
+			sign = 1;
+		} else if (tok->type == ISL_TOKEN_NAN) {
+			res = isl_pw_aff_add(res, nan_on_domain(space));
+		} else {
+			isl_stream_error(s, tok, "unexpected isl_token");
+			isl_stream_push_token(s, tok);
+			isl_pw_aff_free(res);
+			isl_space_free(space);
+			return NULL;
+		}
+		isl_token_free(tok);
+
+		tok = next_token(s);
+		if (tok && tok->type == '-') {
+			sign = -sign;
+			isl_token_free(tok);
+		} else if (tok && tok->type == '+') {
+			/* nothing */
+			isl_token_free(tok);
+		} else if (tok && tok->type == ISL_TOKEN_VALUE &&
+			   isl_int_is_neg(tok->u.v)) {
+			isl_stream_push_token(s, tok);
+		} else {
+			if (tok)
+				isl_stream_push_token(s, tok);
+			break;
+		}
+	}
+
+	isl_space_free(space);
+	return res;
+error:
+	isl_space_free(space);
+	isl_token_free(tok);
+	isl_pw_aff_free(res);
+	return NULL;
+}
+
+/* Is "type" the type of a comparison operator between lists
+ * of affine expressions?
+ */
+static int is_list_comparator_type(int type)
+{
+	switch (type) {
+	case ISL_TOKEN_LEX_LT:
+	case ISL_TOKEN_LEX_GT:
+	case ISL_TOKEN_LEX_LE:
+	case ISL_TOKEN_LEX_GE:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int is_comparator(struct isl_token *tok)
+{
+	if (!tok)
+		return 0;
+	if (is_list_comparator_type(tok->type))
+		return 1;
+
+	switch (tok->type) {
+	case ISL_TOKEN_LT:
+	case ISL_TOKEN_GT:
+	case ISL_TOKEN_LE:
+	case ISL_TOKEN_GE:
+	case ISL_TOKEN_NE:
+	case '=':
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static __isl_give isl_map *read_formula(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational);
+static __isl_give isl_pw_aff *accept_extended_affine(__isl_keep isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v, int rational);
+
+/* Accept a ternary operator, given the first argument.
+ */
+static __isl_give isl_pw_aff *accept_ternary(__isl_keep isl_stream *s,
+	__isl_take isl_map *cond, struct vars *v, int rational)
+{
+	isl_space *dim;
+	isl_pw_aff *pwaff1 = NULL, *pwaff2 = NULL, *pa_cond;
+
+	if (!cond)
+		return NULL;
+
+	if (isl_stream_eat(s, '?'))
+		goto error;
+
+	dim = isl_space_wrap(isl_map_get_space(cond));
+	pwaff1 = accept_extended_affine(s, dim, v, rational);
+	if (!pwaff1)
+		goto error;
+
+	if (isl_stream_eat(s, ':'))
+		goto error;
+
+	dim = isl_pw_aff_get_domain_space(pwaff1);
+	pwaff2 = accept_extended_affine(s, dim, v, rational);
+	if (!pwaff1)
+		goto error;
+
+	pa_cond = isl_set_indicator_function(isl_map_wrap(cond));
+	return isl_pw_aff_cond(pa_cond, pwaff1, pwaff2);
+error:
+	isl_map_free(cond);
+	isl_pw_aff_free(pwaff1);
+	isl_pw_aff_free(pwaff2);
+	return NULL;
+}
+
+/* Set *line and *col to those of the next token, if any.
+ */
+static void set_current_line_col(__isl_keep isl_stream *s, int *line, int *col)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return;
+
+	*line = tok->line;
+	*col = tok->col;
+	isl_stream_push_token(s, tok);
+}
+
+/* Push a token encapsulating "pa" onto "s", with the given
+ * line and column.
+ */
+static int push_aff(__isl_keep isl_stream *s, int line, int col,
+	__isl_take isl_pw_aff *pa)
+{
+	struct isl_token *tok;
+
+	tok = isl_token_new(s->ctx, line, col, 0);
+	if (!tok)
+		goto error;
+	tok->type = ISL_TOKEN_AFF;
+	tok->u.pwaff = pa;
+	isl_stream_push_token(s, tok);
+
+	return 0;
+error:
+	isl_pw_aff_free(pa);
+	return -1;
+}
+
+/* Accept an affine expression that may involve ternary operators.
+ * We first read an affine expression.
+ * If it is not followed by a comparison operator, we simply return it.
+ * Otherwise, we assume the affine expression is part of the first
+ * argument of a ternary operator and try to parse that.
+ */
+static __isl_give isl_pw_aff *accept_extended_affine(__isl_keep isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v, int rational)
+{
+	isl_space *space;
+	isl_map *cond;
+	isl_pw_aff *pwaff;
+	struct isl_token *tok;
+	int line = -1, col = -1;
+	int is_comp;
+
+	set_current_line_col(s, &line, &col);
+
+	pwaff = accept_affine(s, dim, v);
+	if (rational)
+		pwaff = isl_pw_aff_set_rational(pwaff);
+	if (!pwaff)
+		return NULL;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return isl_pw_aff_free(pwaff);
+
+	is_comp = is_comparator(tok);
+	isl_stream_push_token(s, tok);
+	if (!is_comp)
+		return pwaff;
+
+	space = isl_pw_aff_get_domain_space(pwaff);
+	cond = isl_map_universe(isl_space_unwrap(space));
+
+	if (push_aff(s, line, col, pwaff) < 0)
+		cond = isl_map_free(cond);
+	if (!cond)
+		return NULL;
+
+	cond = read_formula(s, v, cond, rational);
+
+	return accept_ternary(s, cond, v, rational);
+}
+
+static __isl_give isl_map *read_var_def(__isl_keep isl_stream *s,
+	__isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
+	int rational)
+{
+	isl_pw_aff *def;
+	int pos;
+	isl_map *def_map;
+
+	if (type == isl_dim_param)
+		pos = isl_map_dim(map, isl_dim_param);
+	else {
+		pos = isl_map_dim(map, isl_dim_in);
+		if (type == isl_dim_out)
+			pos += isl_map_dim(map, isl_dim_out);
+		type = isl_dim_in;
+	}
+	--pos;
+
+	def = accept_extended_affine(s, isl_space_wrap(isl_map_get_space(map)),
+					v, rational);
+	def_map = isl_map_from_pw_aff(def);
+	def_map = isl_map_equate(def_map, type, pos, isl_dim_out, 0);
+	def_map = isl_set_unwrap(isl_map_domain(def_map));
+
+	map = isl_map_intersect(map, def_map);
+
+	return map;
+}
+
+static __isl_give isl_pw_aff_list *accept_affine_list(__isl_keep isl_stream *s,
+	__isl_take isl_space *dim, struct vars *v)
+{
+	isl_pw_aff *pwaff;
+	isl_pw_aff_list *list;
+	struct isl_token *tok = NULL;
+
+	pwaff = accept_affine(s, isl_space_copy(dim), v);
+	list = isl_pw_aff_list_from_pw_aff(pwaff);
+	if (!list)
+		goto error;
+
+	for (;;) {
+		tok = isl_stream_next_token(s);
+		if (!tok) {
+			isl_stream_error(s, NULL, "unexpected EOF");
+			goto error;
+		}
+		if (tok->type != ',') {
+			isl_stream_push_token(s, tok);
+			break;
+		}
+		isl_token_free(tok);
+
+		pwaff = accept_affine(s, isl_space_copy(dim), v);
+		list = isl_pw_aff_list_concat(list,
+				isl_pw_aff_list_from_pw_aff(pwaff));
+		if (!list)
+			goto error;
+	}
+
+	isl_space_free(dim);
+	return list;
+error:
+	isl_space_free(dim);
+	isl_pw_aff_list_free(list);
+	return NULL;
+}
+
+static __isl_give isl_map *read_defined_var_list(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	struct isl_token *tok;
+
+	while ((tok = isl_stream_next_token(s)) != NULL) {
+		int p;
+		int n = v->n;
+
+		if (tok->type != ISL_TOKEN_IDENT)
+			break;
+
+		p = vars_pos(v, tok->u.s, -1);
+		if (p < 0)
+			goto error;
+		if (p < n) {
+			isl_stream_error(s, tok, "expecting unique identifier");
+			goto error;
+		}
+
+		map = isl_map_add_dims(map, isl_dim_out, 1);
+
+		isl_token_free(tok);
+		tok = isl_stream_next_token(s);
+		if (tok && tok->type == '=') {
+			isl_token_free(tok);
+			map = read_var_def(s, map, isl_dim_out, v, rational);
+			tok = isl_stream_next_token(s);
+		}
+
+		if (!tok || tok->type != ',')
+			break;
+
+		isl_token_free(tok);
+	}
+	if (tok)
+		isl_stream_push_token(s, tok);
+
+	return map;
+error:
+	isl_token_free(tok);
+	isl_map_free(map);
+	return NULL;
+}
+
+static int next_is_tuple(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+	int is_tuple;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	if (tok->type == '[') {
+		isl_stream_push_token(s, tok);
+		return 1;
+	}
+	if (tok->type != ISL_TOKEN_IDENT && !tok->is_keyword) {
+		isl_stream_push_token(s, tok);
+		return 0;
+	}
+
+	is_tuple = isl_stream_next_token_is(s, '[');
+
+	isl_stream_push_token(s, tok);
+
+	return is_tuple;
+}
+
+/* Is "pa" an expression in term of earlier dimensions?
+ * The alternative is that the dimension is defined to be equal to itself,
+ * meaning that it has a universe domain and an expression that depends
+ * on itself.  "i" is the position of the expression in a sequence
+ * of "n" expressions.  The final dimensions of "pa" correspond to
+ * these "n" expressions.
+ */
+static int pw_aff_is_expr(__isl_keep isl_pw_aff *pa, int i, int n)
+{
+	isl_aff *aff;
+
+	if (!pa)
+		return -1;
+	if (pa->n != 1)
+		return 1;
+	if (!isl_set_plain_is_universe(pa->p[0].set))
+		return 1;
+
+	aff = pa->p[0].aff;
+	if (isl_int_is_zero(aff->v->el[aff->v->size - n + i]))
+		return 1;
+	return 0;
+}
+
+/* Does the tuple contain any dimensions that are defined
+ * in terms of earlier dimensions?
+ */
+static int tuple_has_expr(__isl_keep isl_multi_pw_aff *tuple)
+{
+	int i, n;
+	int has_expr = 0;
+	isl_pw_aff *pa;
+
+	if (!tuple)
+		return -1;
+	n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
+	for (i = 0; i < n; ++i) {
+		pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
+		has_expr = pw_aff_is_expr(pa, i, n);
+		isl_pw_aff_free(pa);
+		if (has_expr < 0 || has_expr)
+			break;
+	}
+
+	return has_expr;
+}
+
+/* Set the name of dimension "pos" in "space" to "name".
+ * During printing, we add primes if the same name appears more than once
+ * to distinguish the occurrences.  Here, we remove those primes from "name"
+ * before setting the name of the dimension.
+ */
+static __isl_give isl_space *space_set_dim_name(__isl_take isl_space *space,
+	int pos, char *name)
+{
+	char *prime;
+
+	if (!name)
+		return space;
+
+	prime = strchr(name, '\'');
+	if (prime)
+		*prime = '\0';
+	space = isl_space_set_dim_name(space, isl_dim_out, pos, name);
+	if (prime)
+		*prime = '\'';
+
+	return space;
+}
+
+/* Accept a piecewise affine expression.
+ *
+ * At the outer level, the piecewise affine expression may be of the form
+ *
+ *	aff1 : condition1; aff2 : conditions2; ...
+ *
+ * or simply
+ *
+ *	aff
+ *
+ * each of the affine expressions may in turn include ternary operators.
+ *
+ * There may be parentheses around some subexpression of "aff1"
+ * around "aff1" itself, around "aff1 : condition1" and/or
+ * around the entire piecewise affine expression.
+ * We therefore remove the opening parenthesis (if any) from the stream
+ * in case the closing parenthesis follows the colon, but if the closing
+ * parenthesis is the first thing in the stream after the parsed affine
+ * expression, we push the parsed expression onto the stream and parse
+ * again in case the parentheses enclose some subexpression of "aff1".
+ */
+static __isl_give isl_pw_aff *accept_piecewise_affine(__isl_keep isl_stream *s,
+	__isl_take isl_space *space, struct vars *v, int rational)
+{
+	isl_pw_aff *res;
+	isl_space *res_space;
+
+	res_space = isl_space_from_domain(isl_space_copy(space));
+	res_space = isl_space_add_dims(res_space, isl_dim_out, 1);
+	res = isl_pw_aff_empty(res_space);
+	do {
+		isl_pw_aff *pa;
+		int seen_paren;
+		int line = -1, col = -1;
+
+		set_current_line_col(s, &line, &col);
+		seen_paren = isl_stream_eat_if_available(s, '(');
+		if (seen_paren)
+			pa = accept_piecewise_affine(s, isl_space_copy(space),
+							v, rational);
+		else
+			pa = accept_extended_affine(s, isl_space_copy(space),
+							v, rational);
+		if (seen_paren && isl_stream_eat_if_available(s, ')')) {
+			seen_paren = 0;
+			if (push_aff(s, line, col, pa) < 0)
+				goto error;
+			pa = accept_extended_affine(s, isl_space_copy(space),
+							v, rational);
+		}
+		if (isl_stream_eat_if_available(s, ':')) {
+			isl_space *dom_space;
+			isl_set *dom;
+
+			dom_space = isl_pw_aff_get_domain_space(pa);
+			dom = isl_set_universe(dom_space);
+			dom = read_formula(s, v, dom, rational);
+			pa = isl_pw_aff_intersect_domain(pa, dom);
+		}
+
+		res = isl_pw_aff_union_add(res, pa);
+
+		if (seen_paren && isl_stream_eat(s, ')'))
+			goto error;
+	} while (isl_stream_eat_if_available(s, ';'));
+
+	isl_space_free(space);
+
+	return res;
+error:
+	isl_space_free(space);
+	return isl_pw_aff_free(res);
+}
+
+/* Read an affine expression from "s" for use in read_tuple.
+ *
+ * accept_extended_affine requires a wrapped space as input.
+ * read_tuple on the other hand expects each isl_pw_aff
+ * to have an anonymous space.  We therefore adjust the space
+ * of the isl_pw_aff before returning it.
+ */
+static __isl_give isl_pw_aff *read_tuple_var_def(__isl_keep isl_stream *s,
+	struct vars *v, int rational)
+{
+	isl_space *space;
+	isl_pw_aff *def;
+
+	space = isl_space_wrap(isl_space_alloc(s->ctx, 0, v->n, 0));
+
+	def = accept_piecewise_affine(s, space, v, rational);
+
+	space = isl_space_set_alloc(s->ctx, 0, v->n);
+	def = isl_pw_aff_reset_domain_space(def, space);
+
+	return def;
+}
+
+/* Read a list of tuple elements by calling "read_el" on each of them and
+ * return a space with the same number of set dimensions derived from
+ * the parameter space "space" and possibly updated by "read_el".
+ * The elements in the list are separated by either "," or "][".
+ * If "comma" is set then only "," is allowed.
+ */
+static __isl_give isl_space *read_tuple_list(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_space *space, int rational, int comma,
+	__isl_give isl_space *(*read_el)(__isl_keep isl_stream *s,
+		struct vars *v, __isl_take isl_space *space, int rational,
+		void *user),
+	void *user)
+{
+	if (!space)
+		return NULL;
+
+	space = isl_space_set_from_params(space);
+
+	if (isl_stream_next_token_is(s, ']'))
+		return space;
+
+	for (;;) {
+		struct isl_token *tok;
+
+		space = isl_space_add_dims(space, isl_dim_set, 1);
+
+		space = read_el(s, v, space, rational, user);
+		if (!space)
+			return NULL;
+
+		tok = isl_stream_next_token(s);
+		if (!comma && tok && tok->type == ']' &&
+		    isl_stream_next_token_is(s, '[')) {
+			isl_token_free(tok);
+			tok = isl_stream_next_token(s);
+		} else if (!tok || tok->type != ',') {
+			if (tok)
+				isl_stream_push_token(s, tok);
+			break;
+		}
+
+		isl_token_free(tok);
+	}
+
+	return space;
+}
+
+/* Read a tuple space from "s" derived from the parameter space "space".
+ * Call "read_el" on each element in the tuples.
+ */
+static __isl_give isl_space *read_tuple_space(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_space *space, int rational, int comma,
+	__isl_give isl_space *(*read_el)(__isl_keep isl_stream *s,
+		struct vars *v, __isl_take isl_space *space, int rational,
+		void *user),
+	void *user)
+{
+	struct isl_token *tok;
+	char *name = NULL;
+	isl_space *res = NULL;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		goto error;
+	if (tok->type == ISL_TOKEN_IDENT || tok->is_keyword) {
+		name = strdup(tok->u.s);
+		isl_token_free(tok);
+		if (!name)
+			goto error;
+	} else
+		isl_stream_push_token(s, tok);
+	if (isl_stream_eat(s, '['))
+		goto error;
+	if (next_is_tuple(s)) {
+		isl_space *out;
+		res = read_tuple_space(s, v, isl_space_copy(space),
+					rational, comma, read_el, user);
+		if (isl_stream_eat(s, ISL_TOKEN_TO))
+			goto error;
+		out = read_tuple_space(s, v, isl_space_copy(space),
+					rational, comma, read_el, user);
+		res = isl_space_product(res, out);
+	} else
+		res = read_tuple_list(s, v, isl_space_copy(space),
+					rational, comma, read_el, user);
+	if (isl_stream_eat(s, ']'))
+		goto error;
+
+	if (name) {
+		res = isl_space_set_tuple_name(res, isl_dim_set, name);
+		free(name);
+	}
+
+	isl_space_free(space);
+	return res;
+error:
+	free(name);
+	isl_space_free(res);
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Construct an isl_pw_aff defined on a space with v->n variables
+ * that is equal to the last of those variables.
+ */
+static __isl_give isl_pw_aff *identity_tuple_el(struct vars *v)
+{
+	isl_space *space;
+	isl_aff *aff;
+
+	space = isl_space_set_alloc(v->ctx, 0, v->n);
+	aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+	aff = isl_aff_add_coefficient_si(aff, isl_dim_in, v->n - 1, 1);
+	return isl_pw_aff_from_aff(aff);
+}
+
+/* This function is called for each element in a tuple inside read_tuple.
+ * Add a new variable to "v" and construct a corresponding isl_pw_aff defined
+ * over a space containing all variables in "v" defined so far.
+ * The isl_pw_aff expresses the new variable in terms of earlier variables
+ * if a definition is provided.  Otherwise, it is represented as being
+ * equal to itself.
+ * Add the isl_pw_aff to *list.
+ * If the new variable was named, then adjust "space" accordingly and
+ * return the updated space.
+ */
+static __isl_give isl_space *read_tuple_pw_aff_el(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_space *space, int rational, void *user)
+{
+	isl_pw_aff_list **list = (isl_pw_aff_list **) user;
+	isl_pw_aff *pa;
+	struct isl_token *tok;
+	int new_name = 0;
+
+	tok = next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return isl_space_free(space);
+	}
+
+	if (tok->type == ISL_TOKEN_IDENT) {
+		int n = v->n;
+		int p = vars_pos(v, tok->u.s, -1);
+		if (p < 0)
+			goto error;
+		new_name = p >= n;
+	}
+
+	if (tok->type == '*') {
+		if (vars_add_anon(v) < 0)
+			goto error;
+		isl_token_free(tok);
+		pa = identity_tuple_el(v);
+	} else if (new_name) {
+		int pos = isl_space_dim(space, isl_dim_out) - 1;
+		space = space_set_dim_name(space, pos, v->v->name);
+		isl_token_free(tok);
+		if (isl_stream_eat_if_available(s, '='))
+			pa = read_tuple_var_def(s, v, rational);
+		else
+			pa = identity_tuple_el(v);
+	} else {
+		isl_stream_push_token(s, tok);
+		tok = NULL;
+		if (vars_add_anon(v) < 0)
+			goto error;
+		pa = read_tuple_var_def(s, v, rational);
+	}
+
+	*list = isl_pw_aff_list_add(*list, pa);
+	if (!*list)
+		return isl_space_free(space);
+
+	return space;
+error:
+	isl_token_free(tok);
+	return isl_space_free(space);
+}
+
+/* Read a tuple and represent it as an isl_multi_pw_aff.
+ * The range space of the isl_multi_pw_aff is the space of the tuple.
+ * The domain space is an anonymous space
+ * with a dimension for each variable in the set of variables in "v",
+ * including the variables in the range.
+ * If a given dimension is not defined in terms of earlier dimensions in
+ * the input, then the corresponding isl_pw_aff is set equal to one time
+ * the variable corresponding to the dimension being defined.
+ *
+ * The elements in the tuple are collected in a list by read_tuple_pw_aff_el.
+ * Each element in this list is defined over a space representing
+ * the variables defined so far.  We need to adjust the earlier
+ * elements to have as many variables in the domain as the final
+ * element in the list.
+ */
+static __isl_give isl_multi_pw_aff *read_tuple(__isl_keep isl_stream *s,
+	struct vars *v, int rational, int comma)
+{
+	int i, n;
+	isl_space *space;
+	isl_pw_aff_list *list;
+
+	space = isl_space_params_alloc(v->ctx, 0);
+	list = isl_pw_aff_list_alloc(s->ctx, 0);
+	space = read_tuple_space(s, v, space, rational, comma,
+				&read_tuple_pw_aff_el, &list);
+	n = isl_space_dim(space, isl_dim_set);
+	for (i = 0; i + 1 < n; ++i) {
+		isl_pw_aff *pa;
+
+		pa = isl_pw_aff_list_get_pw_aff(list, i);
+		pa = isl_pw_aff_add_dims(pa, isl_dim_in, n - (i + 1));
+		list = isl_pw_aff_list_set_pw_aff(list, i, pa);
+	}
+
+	space = isl_space_from_range(space);
+	space = isl_space_add_dims(space, isl_dim_in, v->n);
+	return isl_multi_pw_aff_from_pw_aff_list(space, list);
+}
+
+/* Add the tuple represented by the isl_multi_pw_aff "tuple" to "map".
+ * We first create the appropriate space in "map" based on the range
+ * space of this isl_multi_pw_aff.  Then, we add equalities based
+ * on the affine expressions.  These live in an anonymous space,
+ * however, so we first need to reset the space to that of "map".
+ */
+static __isl_give isl_map *map_from_tuple(__isl_take isl_multi_pw_aff *tuple,
+	__isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
+	int rational)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_space *space = NULL;
+
+	if (!map || !tuple)
+		goto error;
+	ctx = isl_multi_pw_aff_get_ctx(tuple);
+	n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
+	space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
+	if (!space)
+		goto error;
+
+	if (type == isl_dim_param) {
+		if (isl_space_has_tuple_name(space, isl_dim_set) ||
+		    isl_space_is_wrapping(space)) {
+			isl_die(ctx, isl_error_invalid,
+				"parameter tuples cannot be named or nested",
+				goto error);
+		}
+		map = isl_map_add_dims(map, type, n);
+		for (i = 0; i < n; ++i) {
+			isl_id *id;
+			if (!isl_space_has_dim_name(space, isl_dim_set, i))
+				isl_die(ctx, isl_error_invalid,
+					"parameters must be named",
+					goto error);
+			id = isl_space_get_dim_id(space, isl_dim_set, i);
+			map = isl_map_set_dim_id(map, isl_dim_param, i, id);
+		}
+	} else if (type == isl_dim_in) {
+		isl_set *set;
+
+		set = isl_set_universe(isl_space_copy(space));
+		if (rational)
+			set = isl_set_set_rational(set);
+		set = isl_set_intersect_params(set, isl_map_params(map));
+		map = isl_map_from_domain(set);
+	} else {
+		isl_set *set;
+
+		set = isl_set_universe(isl_space_copy(space));
+		if (rational)
+			set = isl_set_set_rational(set);
+		map = isl_map_from_domain_and_range(isl_map_domain(map), set);
+	}
+
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+		isl_space *space;
+		isl_aff *aff;
+		isl_set *set;
+		isl_map *map_i;
+
+		pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
+		space = isl_pw_aff_get_domain_space(pa);
+		aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+		aff = isl_aff_add_coefficient_si(aff,
+						isl_dim_in, v->n - n + i, -1);
+		pa = isl_pw_aff_add(pa, isl_pw_aff_from_aff(aff));
+		if (rational)
+			pa = isl_pw_aff_set_rational(pa);
+		set = isl_pw_aff_zero_set(pa);
+		map_i = isl_map_from_range(set);
+		map_i = isl_map_reset_space(map_i, isl_map_get_space(map));
+		map = isl_map_intersect(map, map_i);
+	}
+
+	isl_space_free(space);
+	isl_multi_pw_aff_free(tuple);
+	return map;
+error:
+	isl_space_free(space);
+	isl_multi_pw_aff_free(tuple);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Read a tuple from "s" and add it to "map".
+ * The tuple is initially represented as an isl_multi_pw_aff and
+ * then added to "map".
+ */
+static __isl_give isl_map *read_map_tuple(__isl_keep isl_stream *s,
+	__isl_take isl_map *map, enum isl_dim_type type, struct vars *v,
+	int rational, int comma)
+{
+	isl_multi_pw_aff *tuple;
+
+	tuple = read_tuple(s, v, rational, comma);
+	if (!tuple)
+		return isl_map_free(map);
+
+	return map_from_tuple(tuple, map, type, v, rational);
+}
+
+/* Given two equal-length lists of piecewise affine expression with the space
+ * of "set" as domain, construct a set in the same space that expresses
+ * that "left" and "right" satisfy the comparison "type".
+ *
+ * A space is constructed of the same dimension as the number of elements
+ * in the two lists.  The comparison is then expressed in a map from
+ * this space to itself and wrapped into a set.  Finally the two lists
+ * of piecewise affine expressions are plugged into this set.
+ *
+ * Let S be the space of "set" and T the constructed space.
+ * The lists are first changed into two isl_multi_pw_affs in S -> T and
+ * then combined into an isl_multi_pw_aff in S -> [T -> T],
+ * while the comparison is first expressed in T -> T, then [T -> T]
+ * and finally in S.
+ */
+static __isl_give isl_set *list_cmp(__isl_keep isl_set *set, int type,
+	__isl_take isl_pw_aff_list *left, __isl_take isl_pw_aff_list *right)
+{
+	isl_space *space;
+	int n;
+	isl_multi_pw_aff *mpa1, *mpa2;
+
+	if (!set || !left || !right)
+		goto error;
+
+	space = isl_set_get_space(set);
+	n = isl_pw_aff_list_n_pw_aff(left);
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, n);
+	mpa1 = isl_multi_pw_aff_from_pw_aff_list(isl_space_copy(space), left);
+	mpa2 = isl_multi_pw_aff_from_pw_aff_list(isl_space_copy(space), right);
+	mpa1 = isl_multi_pw_aff_range_product(mpa1, mpa2);
+
+	space = isl_space_range(space);
+	switch (type) {
+	case ISL_TOKEN_LEX_LT:
+		set = isl_map_wrap(isl_map_lex_lt(space));
+		break;
+	case ISL_TOKEN_LEX_GT:
+		set = isl_map_wrap(isl_map_lex_gt(space));
+		break;
+	case ISL_TOKEN_LEX_LE:
+		set = isl_map_wrap(isl_map_lex_le(space));
+		break;
+	case ISL_TOKEN_LEX_GE:
+		set = isl_map_wrap(isl_map_lex_ge(space));
+		break;
+	default:
+		isl_multi_pw_aff_free(mpa1);
+		isl_space_free(space);
+		isl_die(isl_set_get_ctx(set), isl_error_internal,
+			"unhandled list comparison type", return NULL);
+	}
+	set = isl_set_preimage_multi_pw_aff(set, mpa1);
+	return set;
+error:
+	isl_pw_aff_list_free(left);
+	isl_pw_aff_list_free(right);
+	return NULL;
+}
+
+/* Construct constraints of the form
+ *
+ *	a op b
+ *
+ * where a is an element in "left", op is an operator of type "type" and
+ * b is an element in "right", add the constraints to "set" and return
+ * the result.
+ * "rational" is set if the constraints should be treated as
+ * a rational constraints.
+ *
+ * If "type" is the type of a comparison operator between lists
+ * of affine expressions, then a single (compound) constraint
+ * is constructed by list_cmp instead.
+ */
+static __isl_give isl_set *construct_constraints(
+	__isl_take isl_set *set, int type,
+	__isl_keep isl_pw_aff_list *left, __isl_keep isl_pw_aff_list *right,
+	int rational)
+{
+	isl_set *cond;
+
+	left = isl_pw_aff_list_copy(left);
+	right = isl_pw_aff_list_copy(right);
+	if (rational) {
+		left = isl_pw_aff_list_set_rational(left);
+		right = isl_pw_aff_list_set_rational(right);
+	}
+	if (is_list_comparator_type(type))
+		cond = list_cmp(set, type, left, right);
+	else if (type == ISL_TOKEN_LE)
+		cond = isl_pw_aff_list_le_set(left, right);
+	else if (type == ISL_TOKEN_GE)
+		cond = isl_pw_aff_list_ge_set(left, right);
+	else if (type == ISL_TOKEN_LT)
+		cond = isl_pw_aff_list_lt_set(left, right);
+	else if (type == ISL_TOKEN_GT)
+		cond = isl_pw_aff_list_gt_set(left, right);
+	else if (type == ISL_TOKEN_NE)
+		cond = isl_pw_aff_list_ne_set(left, right);
+	else
+		cond = isl_pw_aff_list_eq_set(left, right);
+
+	return isl_set_intersect(set, cond);
+}
+
+/* Read a constraint from "s", add it to "map" and return the result.
+ * "v" contains a description of the identifiers parsed so far.
+ * "rational" is set if the constraint should be treated as
+ * a rational constraint.
+ * The constraint read from "s" may be applied to multiple pairs
+ * of affine expressions and may be chained.
+ * In particular, a list of affine expressions is read, followed
+ * by a comparison operator and another list of affine expressions.
+ * The comparison operator is then applied to each pair of elements
+ * in the two lists and the results are added to "map".
+ * However, if the operator expects two lists of affine expressions,
+ * then it is applied directly to those lists and the two lists
+ * are required to have the same length.
+ * If the next token is another comparison operator, then another
+ * list of affine expressions is read and the process repeats.
+ *
+ * The processing is performed on a wrapped copy of "map" because
+ * an affine expression cannot have a binary relation as domain.
+ */
+static __isl_give isl_map *add_constraint(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	struct isl_token *tok;
+	int type;
+	isl_pw_aff_list *list1 = NULL, *list2 = NULL;
+	int n1, n2;
+	isl_set *set;
+
+	set = isl_map_wrap(map);
+	list1 = accept_affine_list(s, isl_set_get_space(set), v);
+	if (!list1)
+		goto error;
+	tok = isl_stream_next_token(s);
+	if (!is_comparator(tok)) {
+		isl_stream_error(s, tok, "missing operator");
+		if (tok)
+			isl_stream_push_token(s, tok);
+		goto error;
+	}
+	type = tok->type;
+	isl_token_free(tok);
+	for (;;) {
+		list2 = accept_affine_list(s, isl_set_get_space(set), v);
+		if (!list2)
+			goto error;
+		n1 = isl_pw_aff_list_n_pw_aff(list1);
+		n2 = isl_pw_aff_list_n_pw_aff(list2);
+		if (is_list_comparator_type(type) && n1 != n2) {
+			isl_stream_error(s, NULL,
+					"list arguments not of same size");
+			goto error;
+		}
+
+		set = construct_constraints(set, type, list1, list2, rational);
+		isl_pw_aff_list_free(list1);
+		list1 = list2;
+
+		tok = isl_stream_next_token(s);
+		if (!is_comparator(tok)) {
+			if (tok)
+				isl_stream_push_token(s, tok);
+			break;
+		}
+		type = tok->type;
+		isl_token_free(tok);
+	}
+	isl_pw_aff_list_free(list1);
+
+	return isl_set_unwrap(set);
+error:
+	isl_pw_aff_list_free(list1);
+	isl_pw_aff_list_free(list2);
+	isl_set_free(set);
+	return NULL;
+}
+
+static __isl_give isl_map *read_exists(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	int n = v->n;
+	int seen_paren = isl_stream_eat_if_available(s, '(');
+
+	map = isl_map_from_domain(isl_map_wrap(map));
+	map = read_defined_var_list(s, v, map, rational);
+
+	if (isl_stream_eat(s, ':'))
+		goto error;
+
+	map = read_formula(s, v, map, rational);
+	map = isl_set_unwrap(isl_map_domain(map));
+
+	vars_drop(v, v->n - n);
+	if (seen_paren && isl_stream_eat(s, ')'))
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Parse an expression between parentheses and push the result
+ * back on the stream.
+ *
+ * The parsed expression may be either an affine expression
+ * or a condition.  The first type is pushed onto the stream
+ * as an isl_pw_aff, while the second is pushed as an isl_map.
+ *
+ * If the initial token indicates the start of a condition,
+ * we parse it as such.
+ * Otherwise, we first parse an affine expression and push
+ * that onto the stream.  If the affine expression covers the
+ * entire expression between parentheses, we return.
+ * Otherwise, we assume that the affine expression is the
+ * start of a condition and continue parsing.
+ */
+static int resolve_paren_expr(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	struct isl_token *tok, *tok2;
+	int line, col;
+	isl_pw_aff *pwaff;
+
+	tok = isl_stream_next_token(s);
+	if (!tok || tok->type != '(')
+		goto error;
+
+	if (isl_stream_next_token_is(s, '('))
+		if (resolve_paren_expr(s, v, isl_map_copy(map), rational))
+			goto error;
+
+	if (isl_stream_next_token_is(s, ISL_TOKEN_EXISTS) ||
+	    isl_stream_next_token_is(s, ISL_TOKEN_NOT) ||
+	    isl_stream_next_token_is(s, ISL_TOKEN_TRUE) ||
+	    isl_stream_next_token_is(s, ISL_TOKEN_FALSE) ||
+	    isl_stream_next_token_is(s, ISL_TOKEN_MAP)) {
+		map = read_formula(s, v, map, rational);
+		if (isl_stream_eat(s, ')'))
+			goto error;
+		tok->type = ISL_TOKEN_MAP;
+		tok->u.map = map;
+		isl_stream_push_token(s, tok);
+		return 0;
+	}
+
+	tok2 = isl_stream_next_token(s);
+	if (!tok2)
+		goto error;
+	line = tok2->line;
+	col = tok2->col;
+	isl_stream_push_token(s, tok2);
+
+	pwaff = accept_affine(s, isl_space_wrap(isl_map_get_space(map)), v);
+	if (!pwaff)
+		goto error;
+
+	tok2 = isl_token_new(s->ctx, line, col, 0);
+	if (!tok2)
+		goto error2;
+	tok2->type = ISL_TOKEN_AFF;
+	tok2->u.pwaff = pwaff;
+
+	if (isl_stream_eat_if_available(s, ')')) {
+		isl_stream_push_token(s, tok2);
+		isl_token_free(tok);
+		isl_map_free(map);
+		return 0;
+	}
+
+	isl_stream_push_token(s, tok2);
+
+	map = read_formula(s, v, map, rational);
+	if (isl_stream_eat(s, ')'))
+		goto error;
+
+	tok->type = ISL_TOKEN_MAP;
+	tok->u.map = map;
+	isl_stream_push_token(s, tok);
+
+	return 0;
+error2:
+	isl_pw_aff_free(pwaff);
+error:
+	isl_token_free(tok);
+	isl_map_free(map);
+	return -1;
+}
+
+static __isl_give isl_map *read_conjunct(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	if (isl_stream_next_token_is(s, '('))
+		if (resolve_paren_expr(s, v, isl_map_copy(map), rational))
+			goto error;
+
+	if (isl_stream_next_token_is(s, ISL_TOKEN_MAP)) {
+		struct isl_token *tok;
+		tok = isl_stream_next_token(s);
+		if (!tok)
+			goto error;
+		isl_map_free(map);
+		map = isl_map_copy(tok->u.map);
+		isl_token_free(tok);
+		return map;
+	}
+
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_EXISTS))
+		return read_exists(s, v, map, rational);
+
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_TRUE))
+		return map;
+
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_FALSE)) {
+		isl_space *dim = isl_map_get_space(map);
+		isl_map_free(map);
+		return isl_map_empty(dim);
+	}
+		
+	return add_constraint(s, v, map, rational);
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+static __isl_give isl_map *read_conjuncts(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	isl_map *res;
+	int negate;
+
+	negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
+	res = read_conjunct(s, v, isl_map_copy(map), rational);
+	if (negate)
+		res = isl_map_subtract(isl_map_copy(map), res);
+
+	while (res && isl_stream_eat_if_available(s, ISL_TOKEN_AND)) {
+		isl_map *res_i;
+
+		negate = isl_stream_eat_if_available(s, ISL_TOKEN_NOT);
+		res_i = read_conjunct(s, v, isl_map_copy(map), rational);
+		if (negate)
+			res = isl_map_subtract(res, res_i);
+		else
+			res = isl_map_intersect(res, res_i);
+	}
+
+	isl_map_free(map);
+	return res;
+}
+
+static struct isl_map *read_disjuncts(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	isl_map *res;
+
+	if (isl_stream_next_token_is(s, '}'))
+		return map;
+
+	res = read_conjuncts(s, v, isl_map_copy(map), rational);
+	while (isl_stream_eat_if_available(s, ISL_TOKEN_OR)) {
+		isl_map *res_i;
+
+		res_i = read_conjuncts(s, v, isl_map_copy(map), rational);
+		res = isl_map_union(res, res_i);
+	}
+
+	isl_map_free(map);
+	return res;
+}
+
+/* Read a first order formula from "s", add the corresponding
+ * constraints to "map" and return the result.
+ *
+ * In particular, read a formula of the form
+ *
+ *	a
+ *
+ * or
+ *
+ *	a implies b
+ *
+ * where a and b are disjunctions.
+ *
+ * In the first case, map is replaced by
+ *
+ *	map \cap { [..] : a }
+ *
+ * In the second case, it is replaced by
+ *
+ *	(map \setminus { [..] : a}) \cup (map \cap { [..] : b })
+ */
+static __isl_give isl_map *read_formula(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_map *map, int rational)
+{
+	isl_map *res;
+
+	res = read_disjuncts(s, v, isl_map_copy(map), rational);
+
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_IMPLIES)) {
+		isl_map *res2;
+
+		res = isl_map_subtract(isl_map_copy(map), res);
+		res2 = read_disjuncts(s, v, map, rational);
+		res = isl_map_union(res, res2);
+	} else
+		isl_map_free(map);
+
+	return res;
+}
+
+static int polylib_pos_to_isl_pos(__isl_keep isl_basic_map *bmap, int pos)
+{
+	if (pos < isl_basic_map_dim(bmap, isl_dim_out))
+		return 1 + isl_basic_map_dim(bmap, isl_dim_param) +
+			   isl_basic_map_dim(bmap, isl_dim_in) + pos;
+	pos -= isl_basic_map_dim(bmap, isl_dim_out);
+
+	if (pos < isl_basic_map_dim(bmap, isl_dim_in))
+		return 1 + isl_basic_map_dim(bmap, isl_dim_param) + pos;
+	pos -= isl_basic_map_dim(bmap, isl_dim_in);
+
+	if (pos < isl_basic_map_dim(bmap, isl_dim_div))
+		return 1 + isl_basic_map_dim(bmap, isl_dim_param) +
+			   isl_basic_map_dim(bmap, isl_dim_in) +
+			   isl_basic_map_dim(bmap, isl_dim_out) + pos;
+	pos -= isl_basic_map_dim(bmap, isl_dim_div);
+
+	if (pos < isl_basic_map_dim(bmap, isl_dim_param))
+		return 1 + pos;
+
+	return 0;
+}
+
+static __isl_give isl_basic_map *basic_map_read_polylib_constraint(
+	__isl_keep isl_stream *s, __isl_take isl_basic_map *bmap)
+{
+	int j;
+	struct isl_token *tok;
+	int type;
+	int k;
+	isl_int *c;
+
+	if (!bmap)
+		return NULL;
+
+	tok = isl_stream_next_token(s);
+	if (!tok || tok->type != ISL_TOKEN_VALUE) {
+		isl_stream_error(s, tok, "expecting coefficient");
+		if (tok)
+			isl_stream_push_token(s, tok);
+		goto error;
+	}
+	if (!tok->on_new_line) {
+		isl_stream_error(s, tok, "coefficient should appear on new line");
+		isl_stream_push_token(s, tok);
+		goto error;
+	}
+
+	type = isl_int_get_si(tok->u.v);
+	isl_token_free(tok);
+
+	isl_assert(s->ctx, type == 0 || type == 1, goto error);
+	if (type == 0) {
+		k = isl_basic_map_alloc_equality(bmap);
+		c = bmap->eq[k];
+	} else {
+		k = isl_basic_map_alloc_inequality(bmap);
+		c = bmap->ineq[k];
+	}
+	if (k < 0)
+		goto error;
+
+	for (j = 0; j < 1 + isl_basic_map_total_dim(bmap); ++j) {
+		int pos;
+		tok = isl_stream_next_token(s);
+		if (!tok || tok->type != ISL_TOKEN_VALUE) {
+			isl_stream_error(s, tok, "expecting coefficient");
+			if (tok)
+				isl_stream_push_token(s, tok);
+			goto error;
+		}
+		if (tok->on_new_line) {
+			isl_stream_error(s, tok,
+				"coefficient should not appear on new line");
+			isl_stream_push_token(s, tok);
+			goto error;
+		}
+		pos = polylib_pos_to_isl_pos(bmap, j);
+		isl_int_set(c[pos], tok->u.v);
+		isl_token_free(tok);
+	}
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+static __isl_give isl_basic_map *basic_map_read_polylib(
+	__isl_keep isl_stream *s)
+{
+	int i;
+	struct isl_token *tok;
+	struct isl_token *tok2;
+	int n_row, n_col;
+	int on_new_line;
+	unsigned in = 0, out, local = 0;
+	struct isl_basic_map *bmap = NULL;
+	int nparam = 0;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	tok2 = isl_stream_next_token(s);
+	if (!tok2) {
+		isl_token_free(tok);
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	if (tok->type != ISL_TOKEN_VALUE || tok2->type != ISL_TOKEN_VALUE) {
+		isl_stream_push_token(s, tok2);
+		isl_stream_push_token(s, tok);
+		isl_stream_error(s, NULL,
+				 "expecting constraint matrix dimensions");
+		return NULL;
+	}
+	n_row = isl_int_get_si(tok->u.v);
+	n_col = isl_int_get_si(tok2->u.v);
+	on_new_line = tok2->on_new_line;
+	isl_token_free(tok2);
+	isl_token_free(tok);
+	isl_assert(s->ctx, !on_new_line, return NULL);
+	isl_assert(s->ctx, n_row >= 0, return NULL);
+	isl_assert(s->ctx, n_col >= 2 + nparam, return NULL);
+	tok = isl_stream_next_token_on_same_line(s);
+	if (tok) {
+		if (tok->type != ISL_TOKEN_VALUE) {
+			isl_stream_error(s, tok,
+				    "expecting number of output dimensions");
+			isl_stream_push_token(s, tok);
+			goto error;
+		}
+		out = isl_int_get_si(tok->u.v);
+		isl_token_free(tok);
+
+		tok = isl_stream_next_token_on_same_line(s);
+		if (!tok || tok->type != ISL_TOKEN_VALUE) {
+			isl_stream_error(s, tok,
+				    "expecting number of input dimensions");
+			if (tok)
+				isl_stream_push_token(s, tok);
+			goto error;
+		}
+		in = isl_int_get_si(tok->u.v);
+		isl_token_free(tok);
+
+		tok = isl_stream_next_token_on_same_line(s);
+		if (!tok || tok->type != ISL_TOKEN_VALUE) {
+			isl_stream_error(s, tok,
+				    "expecting number of existentials");
+			if (tok)
+				isl_stream_push_token(s, tok);
+			goto error;
+		}
+		local = isl_int_get_si(tok->u.v);
+		isl_token_free(tok);
+
+		tok = isl_stream_next_token_on_same_line(s);
+		if (!tok || tok->type != ISL_TOKEN_VALUE) {
+			isl_stream_error(s, tok,
+				    "expecting number of parameters");
+			if (tok)
+				isl_stream_push_token(s, tok);
+			goto error;
+		}
+		nparam = isl_int_get_si(tok->u.v);
+		isl_token_free(tok);
+		if (n_col != 1 + out + in + local + nparam + 1) {
+			isl_stream_error(s, NULL,
+				    "dimensions don't match");
+			goto error;
+		}
+	} else
+		out = n_col - 2 - nparam;
+	bmap = isl_basic_map_alloc(s->ctx, nparam, in, out, local, n_row, n_row);
+	if (!bmap)
+		return NULL;
+
+	for (i = 0; i < local; ++i) {
+		int k = isl_basic_map_alloc_div(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bmap->div[k], 1 + 1 + nparam + in + out + local);
+	}
+
+	for (i = 0; i < n_row; ++i)
+		bmap = basic_map_read_polylib_constraint(s, bmap);
+
+	tok = isl_stream_next_token_on_same_line(s);
+	if (tok) {
+		isl_stream_error(s, tok, "unexpected extra token on line");
+		isl_stream_push_token(s, tok);
+		goto error;
+	}
+
+	bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+static struct isl_map *map_read_polylib(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+	struct isl_token *tok2;
+	int i, n;
+	struct isl_map *map;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	tok2 = isl_stream_next_token_on_same_line(s);
+	if (tok2 && tok2->type == ISL_TOKEN_VALUE) {
+		isl_stream_push_token(s, tok2);
+		isl_stream_push_token(s, tok);
+		return isl_map_from_basic_map(basic_map_read_polylib(s));
+	}
+	if (tok2) {
+		isl_stream_error(s, tok2, "unexpected token");
+		isl_stream_push_token(s, tok2);
+		isl_stream_push_token(s, tok);
+		return NULL;
+	}
+	n = isl_int_get_si(tok->u.v);
+	isl_token_free(tok);
+
+	isl_assert(s->ctx, n >= 1, return NULL);
+
+	map = isl_map_from_basic_map(basic_map_read_polylib(s));
+
+	for (i = 1; map && i < n; ++i)
+		map = isl_map_union(map,
+			isl_map_from_basic_map(basic_map_read_polylib(s)));
+
+	return map;
+}
+
+static int optional_power(__isl_keep isl_stream *s)
+{
+	int pow;
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 1;
+	if (tok->type != '^') {
+		isl_stream_push_token(s, tok);
+		return 1;
+	}
+	isl_token_free(tok);
+	tok = isl_stream_next_token(s);
+	if (!tok || tok->type != ISL_TOKEN_VALUE) {
+		isl_stream_error(s, tok, "expecting exponent");
+		if (tok)
+			isl_stream_push_token(s, tok);
+		return 1;
+	}
+	pow = isl_int_get_si(tok->u.v);
+	isl_token_free(tok);
+	return pow;
+}
+
+static __isl_give isl_pw_qpolynomial *read_term(__isl_keep isl_stream *s,
+	__isl_keep isl_map *map, struct vars *v);
+
+static __isl_give isl_pw_qpolynomial *read_factor(__isl_keep isl_stream *s,
+	__isl_keep isl_map *map, struct vars *v)
+{
+	isl_pw_qpolynomial *pwqp;
+	struct isl_token *tok;
+
+	tok = next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	if (tok->type == '(') {
+		int pow;
+
+		isl_token_free(tok);
+		pwqp = read_term(s, map, v);
+		if (!pwqp)
+			return NULL;
+		if (isl_stream_eat(s, ')'))
+			goto error;
+		pow = optional_power(s);
+		pwqp = isl_pw_qpolynomial_pow(pwqp, pow);
+	} else if (tok->type == ISL_TOKEN_VALUE) {
+		struct isl_token *tok2;
+		isl_qpolynomial *qp;
+
+		tok2 = isl_stream_next_token(s);
+		if (tok2 && tok2->type == '/') {
+			isl_token_free(tok2);
+			tok2 = next_token(s);
+			if (!tok2 || tok2->type != ISL_TOKEN_VALUE) {
+				isl_stream_error(s, tok2, "expected denominator");
+				isl_token_free(tok);
+				isl_token_free(tok2);
+				return NULL;
+			}
+			qp = isl_qpolynomial_rat_cst_on_domain(isl_map_get_space(map),
+						    tok->u.v, tok2->u.v);
+			isl_token_free(tok2);
+		} else {
+			isl_stream_push_token(s, tok2);
+			qp = isl_qpolynomial_cst_on_domain(isl_map_get_space(map),
+						tok->u.v);
+		}
+		isl_token_free(tok);
+		pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
+	} else if (tok->type == ISL_TOKEN_INFTY) {
+		isl_qpolynomial *qp;
+		isl_token_free(tok);
+		qp = isl_qpolynomial_infty_on_domain(isl_map_get_space(map));
+		pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
+	} else if (tok->type == ISL_TOKEN_NAN) {
+		isl_qpolynomial *qp;
+		isl_token_free(tok);
+		qp = isl_qpolynomial_nan_on_domain(isl_map_get_space(map));
+		pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
+	} else if (tok->type == ISL_TOKEN_IDENT) {
+		int n = v->n;
+		int pos = vars_pos(v, tok->u.s, -1);
+		int pow;
+		isl_qpolynomial *qp;
+		if (pos < 0) {
+			isl_token_free(tok);
+			return NULL;
+		}
+		if (pos >= n) {
+			vars_drop(v, v->n - n);
+			isl_stream_error(s, tok, "unknown identifier");
+			isl_token_free(tok);
+			return NULL;
+		}
+		isl_token_free(tok);
+		pow = optional_power(s);
+		qp = isl_qpolynomial_var_pow_on_domain(isl_map_get_space(map), pos, pow);
+		pwqp = isl_pw_qpolynomial_from_qpolynomial(qp);
+	} else if (is_start_of_div(tok)) {
+		isl_pw_aff *pwaff;
+		int pow;
+
+		isl_stream_push_token(s, tok);
+		pwaff = accept_div(s, isl_map_get_space(map), v);
+		pow = optional_power(s);
+		pwqp = isl_pw_qpolynomial_from_pw_aff(pwaff);
+		pwqp = isl_pw_qpolynomial_pow(pwqp, pow);
+	} else if (tok->type == '-') {
+		isl_token_free(tok);
+		pwqp = read_factor(s, map, v);
+		pwqp = isl_pw_qpolynomial_neg(pwqp);
+	} else {
+		isl_stream_error(s, tok, "unexpected isl_token");
+		isl_stream_push_token(s, tok);
+		return NULL;
+	}
+
+	if (isl_stream_eat_if_available(s, '*') ||
+	    isl_stream_next_token_is(s, ISL_TOKEN_IDENT)) {
+		isl_pw_qpolynomial *pwqp2;
+
+		pwqp2 = read_factor(s, map, v);
+		pwqp = isl_pw_qpolynomial_mul(pwqp, pwqp2);
+	}
+
+	return pwqp;
+error:
+	isl_pw_qpolynomial_free(pwqp);
+	return NULL;
+}
+
+static __isl_give isl_pw_qpolynomial *read_term(__isl_keep isl_stream *s,
+	__isl_keep isl_map *map, struct vars *v)
+{
+	struct isl_token *tok;
+	isl_pw_qpolynomial *pwqp;
+
+	pwqp = read_factor(s, map, v);
+
+	for (;;) {
+		tok = next_token(s);
+		if (!tok)
+			return pwqp;
+
+		if (tok->type == '+') {
+			isl_pw_qpolynomial *pwqp2;
+
+			isl_token_free(tok);
+			pwqp2 = read_factor(s, map, v);
+			pwqp = isl_pw_qpolynomial_add(pwqp, pwqp2);
+		} else if (tok->type == '-') {
+			isl_pw_qpolynomial *pwqp2;
+
+			isl_token_free(tok);
+			pwqp2 = read_factor(s, map, v);
+			pwqp = isl_pw_qpolynomial_sub(pwqp, pwqp2);
+		} else if (tok->type == ISL_TOKEN_VALUE &&
+			    isl_int_is_neg(tok->u.v)) {
+			isl_pw_qpolynomial *pwqp2;
+
+			isl_stream_push_token(s, tok);
+			pwqp2 = read_factor(s, map, v);
+			pwqp = isl_pw_qpolynomial_add(pwqp, pwqp2);
+		} else {
+			isl_stream_push_token(s, tok);
+			break;
+		}
+	}
+
+	return pwqp;
+}
+
+static __isl_give isl_map *read_optional_formula(__isl_keep isl_stream *s,
+	__isl_take isl_map *map, struct vars *v, int rational)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		goto error;
+	}
+	if (tok->type == ':' ||
+	    (tok->type == ISL_TOKEN_OR && !strcmp(tok->u.s, "|"))) {
+		isl_token_free(tok);
+		map = read_formula(s, v, map, rational);
+	} else
+		isl_stream_push_token(s, tok);
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+static struct isl_obj obj_read_poly(__isl_keep isl_stream *s,
+	__isl_take isl_map *map, struct vars *v, int n)
+{
+	struct isl_obj obj = { isl_obj_pw_qpolynomial, NULL };
+	isl_pw_qpolynomial *pwqp;
+	struct isl_set *set;
+
+	pwqp = read_term(s, map, v);
+	map = read_optional_formula(s, map, v, 0);
+	set = isl_map_range(map);
+
+	pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, set);
+
+	vars_drop(v, v->n - n);
+
+	obj.v = pwqp;
+	return obj;
+}
+
+static struct isl_obj obj_read_poly_or_fold(__isl_keep isl_stream *s,
+	__isl_take isl_set *set, struct vars *v, int n)
+{
+	struct isl_obj obj = { isl_obj_pw_qpolynomial_fold, NULL };
+	isl_pw_qpolynomial *pwqp;
+	isl_pw_qpolynomial_fold *pwf = NULL;
+
+	if (!isl_stream_eat_if_available(s, ISL_TOKEN_MAX))
+		return obj_read_poly(s, set, v, n);
+
+	if (isl_stream_eat(s, '('))
+		goto error;
+
+	pwqp = read_term(s, set, v);
+	pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(isl_fold_max, pwqp);
+
+	while (isl_stream_eat_if_available(s, ',')) {
+		isl_pw_qpolynomial_fold *pwf_i;
+		pwqp = read_term(s, set, v);
+		pwf_i = isl_pw_qpolynomial_fold_from_pw_qpolynomial(isl_fold_max,
+									pwqp);
+		pwf = isl_pw_qpolynomial_fold_fold(pwf, pwf_i);
+	}
+
+	if (isl_stream_eat(s, ')'))
+		goto error;
+
+	set = read_optional_formula(s, set, v, 0);
+	pwf = isl_pw_qpolynomial_fold_intersect_domain(pwf, set);
+
+	vars_drop(v, v->n - n);
+
+	obj.v = pwf;
+	return obj;
+error:
+	isl_set_free(set);
+	isl_pw_qpolynomial_fold_free(pwf);
+	obj.type = isl_obj_none;
+	return obj;
+}
+
+static int is_rational(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	if (tok->type == ISL_TOKEN_RAT && isl_stream_next_token_is(s, ':')) {
+		isl_token_free(tok);
+		isl_stream_eat(s, ':');
+		return 1;
+	}
+
+	isl_stream_push_token(s, tok);
+
+	return 0;
+}
+
+static struct isl_obj obj_read_body(__isl_keep isl_stream *s,
+	__isl_take isl_map *map, struct vars *v)
+{
+	struct isl_token *tok;
+	struct isl_obj obj = { isl_obj_set, NULL };
+	int n = v->n;
+	int rational;
+
+	rational = is_rational(s);
+	if (rational)
+		map = isl_map_set_rational(map);
+
+	if (isl_stream_next_token_is(s, ':')) {
+		obj.type = isl_obj_set;
+		obj.v = read_optional_formula(s, map, v, rational);
+		return obj;
+	}
+
+	if (!next_is_tuple(s))
+		return obj_read_poly_or_fold(s, map, v, n);
+
+	map = read_map_tuple(s, map, isl_dim_in, v, rational, 0);
+	if (!map)
+		goto error;
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		goto error;
+	if (tok->type == ISL_TOKEN_TO) {
+		obj.type = isl_obj_map;
+		isl_token_free(tok);
+		if (!next_is_tuple(s)) {
+			isl_set *set = isl_map_domain(map);
+			return obj_read_poly_or_fold(s, set, v, n);
+		}
+		map = read_map_tuple(s, map, isl_dim_out, v, rational, 0);
+		if (!map)
+			goto error;
+	} else {
+		map = isl_map_domain(map);
+		isl_stream_push_token(s, tok);
+	}
+
+	map = read_optional_formula(s, map, v, rational);
+
+	vars_drop(v, v->n - n);
+
+	obj.v = map;
+	return obj;
+error:
+	isl_map_free(map);
+	obj.type = isl_obj_none;
+	return obj;
+}
+
+static struct isl_obj to_union(isl_ctx *ctx, struct isl_obj obj)
+{
+	if (obj.type == isl_obj_map) {
+		obj.v = isl_union_map_from_map(obj.v);
+		obj.type = isl_obj_union_map;
+	} else if (obj.type == isl_obj_set) {
+		obj.v = isl_union_set_from_set(obj.v);
+		obj.type = isl_obj_union_set;
+	} else if (obj.type == isl_obj_pw_qpolynomial) {
+		obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v);
+		obj.type = isl_obj_union_pw_qpolynomial;
+	} else if (obj.type == isl_obj_pw_qpolynomial_fold) {
+		obj.v = isl_union_pw_qpolynomial_fold_from_pw_qpolynomial_fold(obj.v);
+		obj.type = isl_obj_union_pw_qpolynomial_fold;
+	} else
+		isl_assert(ctx, 0, goto error);
+	return obj;
+error:
+	obj.type->free(obj.v);
+	obj.type = isl_obj_none;
+	return obj;
+}
+
+static struct isl_obj obj_add(__isl_keep isl_stream *s,
+	struct isl_obj obj1, struct isl_obj obj2)
+{
+	if (obj1.type == isl_obj_set && obj2.type == isl_obj_union_set)
+		obj1 = to_union(s->ctx, obj1);
+	if (obj1.type == isl_obj_union_set && obj2.type == isl_obj_set)
+		obj2 = to_union(s->ctx, obj2);
+	if (obj1.type == isl_obj_map && obj2.type == isl_obj_union_map)
+		obj1 = to_union(s->ctx, obj1);
+	if (obj1.type == isl_obj_union_map && obj2.type == isl_obj_map)
+		obj2 = to_union(s->ctx, obj2);
+	if (obj1.type == isl_obj_pw_qpolynomial &&
+	    obj2.type == isl_obj_union_pw_qpolynomial)
+		obj1 = to_union(s->ctx, obj1);
+	if (obj1.type == isl_obj_union_pw_qpolynomial &&
+	    obj2.type == isl_obj_pw_qpolynomial)
+		obj2 = to_union(s->ctx, obj2);
+	if (obj1.type == isl_obj_pw_qpolynomial_fold &&
+	    obj2.type == isl_obj_union_pw_qpolynomial_fold)
+		obj1 = to_union(s->ctx, obj1);
+	if (obj1.type == isl_obj_union_pw_qpolynomial_fold &&
+	    obj2.type == isl_obj_pw_qpolynomial_fold)
+		obj2 = to_union(s->ctx, obj2);
+	if (obj1.type != obj2.type) {
+		isl_stream_error(s, NULL,
+				"attempt to combine incompatible objects");
+		goto error;
+	}
+	if (!obj1.type->add)
+		isl_die(s->ctx, isl_error_internal,
+			"combination not supported on object type", goto error);
+	if (obj1.type == isl_obj_map && !isl_map_has_equal_space(obj1.v, obj2.v)) {
+		obj1 = to_union(s->ctx, obj1);
+		obj2 = to_union(s->ctx, obj2);
+	}
+	if (obj1.type == isl_obj_set && !isl_set_has_equal_space(obj1.v, obj2.v)) {
+		obj1 = to_union(s->ctx, obj1);
+		obj2 = to_union(s->ctx, obj2);
+	}
+	if (obj1.type == isl_obj_pw_qpolynomial &&
+	    !isl_pw_qpolynomial_has_equal_space(obj1.v, obj2.v)) {
+		obj1 = to_union(s->ctx, obj1);
+		obj2 = to_union(s->ctx, obj2);
+	}
+	if (obj1.type == isl_obj_pw_qpolynomial_fold &&
+	    !isl_pw_qpolynomial_fold_has_equal_space(obj1.v, obj2.v)) {
+		obj1 = to_union(s->ctx, obj1);
+		obj2 = to_union(s->ctx, obj2);
+	}
+	obj1.v = obj1.type->add(obj1.v, obj2.v);
+	return obj1;
+error:
+	obj1.type->free(obj1.v);
+	obj2.type->free(obj2.v);
+	obj1.type = isl_obj_none;
+	obj1.v = NULL;
+	return obj1;
+}
+
+/* Are the first two tokens on "s", "domain" (either as a string
+ * or as an identifier) followed by ":"?
+ */
+static int next_is_domain_colon(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+	char *name;
+	int res;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	if (tok->type != ISL_TOKEN_IDENT && tok->type != ISL_TOKEN_STRING) {
+		isl_stream_push_token(s, tok);
+		return 0;
+	}
+
+	name = isl_token_get_str(s->ctx, tok);
+	res = !strcmp(name, "domain") && isl_stream_next_token_is(s, ':');
+	free(name);
+
+	isl_stream_push_token(s, tok);
+
+	return res;
+}
+
+/* Do the first tokens on "s" look like a schedule?
+ *
+ * The root of a schedule is always a domain node, so the first thing
+ * we expect in the stream is a domain key, i.e., "domain" followed
+ * by ":".  If the schedule was printed in YAML flow style, then
+ * we additionally expect a "{" to open the outer mapping.
+ */
+static int next_is_schedule(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+	int is_schedule;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	if (tok->type != '{') {
+		isl_stream_push_token(s, tok);
+		return next_is_domain_colon(s);
+	}
+
+	is_schedule = next_is_domain_colon(s);
+	isl_stream_push_token(s, tok);
+
+	return is_schedule;
+}
+
+/* Read an isl_schedule from "s" and store it in an isl_obj.
+ */
+static struct isl_obj schedule_read(__isl_keep isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj.type = isl_obj_schedule;
+	obj.v = isl_stream_read_schedule(s);
+
+	return obj;
+}
+
+static struct isl_obj obj_read(__isl_keep isl_stream *s)
+{
+	isl_map *map = NULL;
+	struct isl_token *tok;
+	struct vars *v = NULL;
+	struct isl_obj obj = { isl_obj_set, NULL };
+
+	if (next_is_schedule(s))
+		return schedule_read(s);
+
+	tok = next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		goto error;
+	}
+	if (tok->type == ISL_TOKEN_VALUE) {
+		struct isl_token *tok2;
+		struct isl_map *map;
+
+		tok2 = isl_stream_next_token(s);
+		if (!tok2 || tok2->type != ISL_TOKEN_VALUE ||
+		    isl_int_is_neg(tok2->u.v)) {
+			if (tok2)
+				isl_stream_push_token(s, tok2);
+			obj.type = isl_obj_val;
+			obj.v = isl_val_int_from_isl_int(s->ctx, tok->u.v);
+			isl_token_free(tok);
+			return obj;
+		}
+		isl_stream_push_token(s, tok2);
+		isl_stream_push_token(s, tok);
+		map = map_read_polylib(s);
+		if (!map)
+			goto error;
+		if (isl_map_may_be_set(map))
+			obj.v = isl_map_range(map);
+		else {
+			obj.type = isl_obj_map;
+			obj.v = map;
+		}
+		return obj;
+	}
+	v = vars_new(s->ctx);
+	if (!v) {
+		isl_stream_push_token(s, tok);
+		goto error;
+	}
+	map = isl_map_universe(isl_space_params_alloc(s->ctx, 0));
+	if (tok->type == '[') {
+		isl_stream_push_token(s, tok);
+		map = read_map_tuple(s, map, isl_dim_param, v, 0, 0);
+		if (!map)
+			goto error;
+		tok = isl_stream_next_token(s);
+		if (!tok || tok->type != ISL_TOKEN_TO) {
+			isl_stream_error(s, tok, "expecting '->'");
+			if (tok)
+				isl_stream_push_token(s, tok);
+			goto error;
+		}
+		isl_token_free(tok);
+		tok = isl_stream_next_token(s);
+	}
+	if (!tok || tok->type != '{') {
+		isl_stream_error(s, tok, "expecting '{'");
+		if (tok)
+			isl_stream_push_token(s, tok);
+		goto error;
+	}
+	isl_token_free(tok);
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		;
+	else if (tok->type == ISL_TOKEN_IDENT && !strcmp(tok->u.s, "Sym")) {
+		isl_token_free(tok);
+		if (isl_stream_eat(s, '='))
+			goto error;
+		map = read_map_tuple(s, map, isl_dim_param, v, 0, 1);
+		if (!map)
+			goto error;
+	} else if (tok->type == '}') {
+		obj.type = isl_obj_union_set;
+		obj.v = isl_union_set_empty(isl_map_get_space(map));
+		isl_token_free(tok);
+		goto done;
+	} else
+		isl_stream_push_token(s, tok);
+
+	for (;;) {
+		struct isl_obj o;
+		tok = NULL;
+		o = obj_read_body(s, isl_map_copy(map), v);
+		if (o.type == isl_obj_none || !o.v)
+			goto error;
+		if (!obj.v)
+			obj = o;
+		else {
+			obj = obj_add(s, obj, o);
+			if (obj.type == isl_obj_none || !obj.v)
+				goto error;
+		}
+		tok = isl_stream_next_token(s);
+		if (!tok || tok->type != ';')
+			break;
+		isl_token_free(tok);
+		if (isl_stream_next_token_is(s, '}')) {
+			tok = isl_stream_next_token(s);
+			break;
+		}
+	}
+
+	if (tok && tok->type == '}') {
+		isl_token_free(tok);
+	} else {
+		isl_stream_error(s, tok, "unexpected isl_token");
+		if (tok)
+			isl_token_free(tok);
+		goto error;
+	}
+done:
+	vars_free(v);
+	isl_map_free(map);
+
+	return obj;
+error:
+	isl_map_free(map);
+	obj.type->free(obj.v);
+	if (v)
+		vars_free(v);
+	obj.v = NULL;
+	return obj;
+}
+
+struct isl_obj isl_stream_read_obj(__isl_keep isl_stream *s)
+{
+	return obj_read(s);
+}
+
+__isl_give isl_map *isl_stream_read_map(__isl_keep isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (obj.v)
+		isl_assert(s->ctx, obj.type == isl_obj_map ||
+				   obj.type == isl_obj_set, goto error);
+	
+	if (obj.type == isl_obj_set)
+		obj.v = isl_map_from_range(obj.v);
+
+	return obj.v;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+__isl_give isl_set *isl_stream_read_set(__isl_keep isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (obj.v) {
+		if (obj.type == isl_obj_map && isl_map_may_be_set(obj.v)) {
+			obj.v = isl_map_range(obj.v);
+			obj.type = isl_obj_set;
+		}
+		isl_assert(s->ctx, obj.type == isl_obj_set, goto error);
+	}
+
+	return obj.v;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+__isl_give isl_union_map *isl_stream_read_union_map(__isl_keep isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (obj.type == isl_obj_map) {
+		obj.type = isl_obj_union_map;
+		obj.v = isl_union_map_from_map(obj.v);
+	}
+	if (obj.type == isl_obj_set) {
+		obj.type = isl_obj_union_set;
+		obj.v = isl_union_set_from_set(obj.v);
+	}
+	if (obj.v && obj.type == isl_obj_union_set &&
+	    isl_union_set_is_empty(obj.v))
+		obj.type = isl_obj_union_map;
+	if (obj.v && obj.type != isl_obj_union_map)
+		isl_die(s->ctx, isl_error_invalid, "invalid input", goto error);
+
+	return obj.v;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+__isl_give isl_union_set *isl_stream_read_union_set(__isl_keep isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (obj.type == isl_obj_set) {
+		obj.type = isl_obj_union_set;
+		obj.v = isl_union_set_from_set(obj.v);
+	}
+	if (obj.v)
+		isl_assert(s->ctx, obj.type == isl_obj_union_set, goto error);
+
+	return obj.v;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+static __isl_give isl_basic_map *basic_map_read(__isl_keep isl_stream *s)
+{
+	struct isl_obj obj;
+	struct isl_map *map;
+	struct isl_basic_map *bmap;
+
+	obj = obj_read(s);
+	if (obj.v && (obj.type != isl_obj_map && obj.type != isl_obj_set))
+		isl_die(s->ctx, isl_error_invalid, "not a (basic) set or map",
+			goto error);
+	map = obj.v;
+	if (!map)
+		return NULL;
+
+	if (map->n > 1)
+		isl_die(s->ctx, isl_error_invalid,
+			"set or map description involves "
+			"more than one disjunct", goto error);
+
+	if (map->n == 0)
+		bmap = isl_basic_map_empty(isl_map_get_space(map));
+	else
+		bmap = isl_basic_map_copy(map->p[0]);
+
+	isl_map_free(map);
+
+	return bmap;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+static __isl_give isl_basic_set *basic_set_read(__isl_keep isl_stream *s)
+{
+	isl_basic_map *bmap;
+	bmap = basic_map_read(s);
+	if (!bmap)
+		return NULL;
+	if (!isl_basic_map_may_be_set(bmap))
+		isl_die(s->ctx, isl_error_invalid,
+			"input is not a set", goto error);
+	return isl_basic_map_range(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_read_from_file(isl_ctx *ctx,
+	FILE *input)
+{
+	struct isl_basic_map *bmap;
+	isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	bmap = basic_map_read(s);
+	isl_stream_free(s);
+	return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_read_from_file(isl_ctx *ctx,
+	FILE *input)
+{
+	isl_basic_set *bset;
+	isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	bset = basic_set_read(s);
+	isl_stream_free(s);
+	return bset;
+}
+
+struct isl_basic_map *isl_basic_map_read_from_str(struct isl_ctx *ctx,
+	const char *str)
+{
+	struct isl_basic_map *bmap;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	bmap = basic_map_read(s);
+	isl_stream_free(s);
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_read_from_str(struct isl_ctx *ctx,
+	const char *str)
+{
+	isl_basic_set *bset;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	bset = basic_set_read(s);
+	isl_stream_free(s);
+	return bset;
+}
+
+__isl_give isl_map *isl_map_read_from_file(struct isl_ctx *ctx,
+	FILE *input)
+{
+	struct isl_map *map;
+	isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	map = isl_stream_read_map(s);
+	isl_stream_free(s);
+	return map;
+}
+
+__isl_give isl_map *isl_map_read_from_str(struct isl_ctx *ctx,
+	const char *str)
+{
+	struct isl_map *map;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	map = isl_stream_read_map(s);
+	isl_stream_free(s);
+	return map;
+}
+
+__isl_give isl_set *isl_set_read_from_file(struct isl_ctx *ctx,
+	FILE *input)
+{
+	isl_set *set;
+	isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	set = isl_stream_read_set(s);
+	isl_stream_free(s);
+	return set;
+}
+
+struct isl_set *isl_set_read_from_str(struct isl_ctx *ctx,
+	const char *str)
+{
+	isl_set *set;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	set = isl_stream_read_set(s);
+	isl_stream_free(s);
+	return set;
+}
+
+__isl_give isl_union_map *isl_union_map_read_from_file(isl_ctx *ctx,
+	FILE *input)
+{
+	isl_union_map *umap;
+	isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	umap = isl_stream_read_union_map(s);
+	isl_stream_free(s);
+	return umap;
+}
+
+__isl_give isl_union_map *isl_union_map_read_from_str(struct isl_ctx *ctx,
+		const char *str)
+{
+	isl_union_map *umap;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	umap = isl_stream_read_union_map(s);
+	isl_stream_free(s);
+	return umap;
+}
+
+__isl_give isl_union_set *isl_union_set_read_from_file(isl_ctx *ctx,
+	FILE *input)
+{
+	isl_union_set *uset;
+	isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	uset = isl_stream_read_union_set(s);
+	isl_stream_free(s);
+	return uset;
+}
+
+__isl_give isl_union_set *isl_union_set_read_from_str(struct isl_ctx *ctx,
+		const char *str)
+{
+	isl_union_set *uset;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	uset = isl_stream_read_union_set(s);
+	isl_stream_free(s);
+	return uset;
+}
+
+static __isl_give isl_vec *isl_vec_read_polylib(__isl_keep isl_stream *s)
+{
+	struct isl_vec *vec = NULL;
+	struct isl_token *tok;
+	unsigned size;
+	int j;
+
+	tok = isl_stream_next_token(s);
+	if (!tok || tok->type != ISL_TOKEN_VALUE) {
+		isl_stream_error(s, tok, "expecting vector length");
+		goto error;
+	}
+
+	size = isl_int_get_si(tok->u.v);
+	isl_token_free(tok);
+
+	vec = isl_vec_alloc(s->ctx, size);
+
+	for (j = 0; j < size; ++j) {
+		tok = isl_stream_next_token(s);
+		if (!tok || tok->type != ISL_TOKEN_VALUE) {
+			isl_stream_error(s, tok, "expecting constant value");
+			goto error;
+		}
+		isl_int_set(vec->el[j], tok->u.v);
+		isl_token_free(tok);
+	}
+
+	return vec;
+error:
+	isl_token_free(tok);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+static __isl_give isl_vec *vec_read(__isl_keep isl_stream *s)
+{
+	return isl_vec_read_polylib(s);
+}
+
+__isl_give isl_vec *isl_vec_read_from_file(isl_ctx *ctx, FILE *input)
+{
+	isl_vec *v;
+	isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	v = vec_read(s);
+	isl_stream_free(s);
+	return v;
+}
+
+__isl_give isl_pw_qpolynomial *isl_stream_read_pw_qpolynomial(
+	__isl_keep isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (obj.v)
+		isl_assert(s->ctx, obj.type == isl_obj_pw_qpolynomial,
+			   goto error);
+
+	return obj.v;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_str(isl_ctx *ctx,
+		const char *str)
+{
+	isl_pw_qpolynomial *pwqp;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	pwqp = isl_stream_read_pw_qpolynomial(s);
+	isl_stream_free(s);
+	return pwqp;
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_read_from_file(isl_ctx *ctx,
+		FILE *input)
+{
+	isl_pw_qpolynomial *pwqp;
+	isl_stream *s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	pwqp = isl_stream_read_pw_qpolynomial(s);
+	isl_stream_free(s);
+	return pwqp;
+}
+
+/* Is the next token an identifer not in "v"?
+ */
+static int next_is_fresh_ident(__isl_keep isl_stream *s, struct vars *v)
+{
+	int n = v->n;
+	int fresh;
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	fresh = tok->type == ISL_TOKEN_IDENT && vars_pos(v, tok->u.s, -1) >= n;
+	isl_stream_push_token(s, tok);
+
+	vars_drop(v, v->n - n);
+
+	return fresh;
+}
+
+/* First read the domain of the affine expression, which may be
+ * a parameter space or a set.
+ * The tricky part is that we don't know if the domain is a set or not,
+ * so when we are trying to read the domain, we may actually be reading
+ * the affine expression itself (defined on a parameter domains)
+ * If the tuple we are reading is named, we assume it's the domain.
+ * Also, if inside the tuple, the first thing we find is a nested tuple
+ * or a new identifier, we again assume it's the domain.
+ * Finally, if the tuple is empty, then it must be the domain
+ * since it does not contain an affine expression.
+ * Otherwise, we assume we are reading an affine expression.
+ */
+static __isl_give isl_set *read_aff_domain(__isl_keep isl_stream *s,
+	__isl_take isl_set *dom, struct vars *v)
+{
+	struct isl_token *tok, *tok2;
+	int is_empty;
+
+	tok = isl_stream_next_token(s);
+	if (tok && (tok->type == ISL_TOKEN_IDENT || tok->is_keyword)) {
+		isl_stream_push_token(s, tok);
+		return read_map_tuple(s, dom, isl_dim_set, v, 1, 0);
+	}
+	if (!tok || tok->type != '[') {
+		isl_stream_error(s, tok, "expecting '['");
+		goto error;
+	}
+	tok2 = isl_stream_next_token(s);
+	is_empty = tok2 && tok2->type == ']';
+	if (tok2)
+		isl_stream_push_token(s, tok2);
+	if (is_empty || next_is_tuple(s) || next_is_fresh_ident(s, v)) {
+		isl_stream_push_token(s, tok);
+		dom = read_map_tuple(s, dom, isl_dim_set, v, 1, 0);
+	} else
+		isl_stream_push_token(s, tok);
+
+	return dom;
+error:
+	if (tok)
+		isl_stream_push_token(s, tok);
+	isl_set_free(dom);
+	return NULL;
+}
+
+/* Read an affine expression from "s".
+ */
+__isl_give isl_aff *isl_stream_read_aff(__isl_keep isl_stream *s)
+{
+	isl_aff *aff;
+	isl_multi_aff *ma;
+
+	ma = isl_stream_read_multi_aff(s);
+	if (!ma)
+		return NULL;
+	if (isl_multi_aff_dim(ma, isl_dim_out) != 1)
+		isl_die(s->ctx, isl_error_invalid,
+			"expecting single affine expression",
+			goto error);
+
+	aff = isl_multi_aff_get_aff(ma, 0);
+	isl_multi_aff_free(ma);
+	return aff;
+error:
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+/* Read a piecewise affine expression from "s" with domain (space) "dom".
+ */
+static __isl_give isl_pw_aff *read_pw_aff_with_dom(__isl_keep isl_stream *s,
+	__isl_take isl_set *dom, struct vars *v)
+{
+	isl_pw_aff *pwaff = NULL;
+
+	if (!isl_set_is_params(dom) && isl_stream_eat(s, ISL_TOKEN_TO))
+		goto error;
+
+	if (isl_stream_eat(s, '['))
+		goto error;
+
+	pwaff = accept_affine(s, isl_set_get_space(dom), v);
+
+	if (isl_stream_eat(s, ']'))
+		goto error;
+
+	dom = read_optional_formula(s, dom, v, 0);
+	pwaff = isl_pw_aff_intersect_domain(pwaff, dom);
+
+	return pwaff;
+error:
+	isl_set_free(dom);
+	isl_pw_aff_free(pwaff);
+	return NULL;
+}
+
+__isl_give isl_pw_aff *isl_stream_read_pw_aff(__isl_keep isl_stream *s)
+{
+	struct vars *v;
+	isl_set *dom = NULL;
+	isl_set *aff_dom;
+	isl_pw_aff *pa = NULL;
+	int n;
+
+	v = vars_new(s->ctx);
+	if (!v)
+		return NULL;
+
+	dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
+	if (next_is_tuple(s)) {
+		dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
+		if (isl_stream_eat(s, ISL_TOKEN_TO))
+			goto error;
+	}
+	if (isl_stream_eat(s, '{'))
+		goto error;
+
+	n = v->n;
+	aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
+	pa = read_pw_aff_with_dom(s, aff_dom, v);
+	vars_drop(v, v->n - n);
+
+	while (isl_stream_eat_if_available(s, ';')) {
+		isl_pw_aff *pa_i;
+
+		n = v->n;
+		aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
+		pa_i = read_pw_aff_with_dom(s, aff_dom, v);
+		vars_drop(v, v->n - n);
+
+		pa = isl_pw_aff_union_add(pa, pa_i);
+	}
+
+	if (isl_stream_eat(s, '}'))
+		goto error;
+
+	vars_free(v);
+	isl_set_free(dom);
+	return pa;
+error:
+	vars_free(v);
+	isl_set_free(dom);
+	isl_pw_aff_free(pa);
+	return NULL;
+}
+
+__isl_give isl_aff *isl_aff_read_from_str(isl_ctx *ctx, const char *str)
+{
+	isl_aff *aff;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	aff = isl_stream_read_aff(s);
+	isl_stream_free(s);
+	return aff;
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str)
+{
+	isl_pw_aff *pa;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	pa = isl_stream_read_pw_aff(s);
+	isl_stream_free(s);
+	return pa;
+}
+
+/* Extract an isl_multi_pw_aff with domain space "dom_space"
+ * from a tuple "tuple" read by read_tuple.
+ *
+ * Note that the function read_tuple accepts tuples where some output or
+ * set dimensions are defined in terms of other output or set dimensions
+ * since this function is also used to read maps.  As a special case,
+ * read_tuple also accept dimensions that are defined in terms of themselves
+ * (i.e., that are not defined).
+ * These cases are not allowed when extracting an isl_multi_pw_aff so check
+ * that the definitions of the output/set dimensions do not involve any
+ * output/set dimensions.
+ * Finally, drop the output dimensions from the domain of the result
+ * of read_tuple (which is of the form [input, output] -> [output],
+ * with anonymous domain) and reset the space.
+ */
+static __isl_give isl_multi_pw_aff *extract_mpa_from_tuple(
+	__isl_take isl_space *dom_space, __isl_keep isl_multi_pw_aff *tuple)
+{
+	int dim, i, n;
+	isl_space *space;
+	isl_multi_pw_aff *mpa;
+
+	n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
+	dim = isl_space_dim(dom_space, isl_dim_all);
+	space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
+	space = isl_space_align_params(space, isl_space_copy(dom_space));
+	if (!isl_space_is_params(dom_space))
+		space = isl_space_map_from_domain_and_range(
+				isl_space_copy(dom_space), space);
+	isl_space_free(dom_space);
+	mpa = isl_multi_pw_aff_alloc(space);
+
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+		pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
+		if (!pa)
+			return isl_multi_pw_aff_free(mpa);
+		if (isl_pw_aff_involves_dims(pa, isl_dim_in, dim, i + 1)) {
+			isl_ctx *ctx = isl_pw_aff_get_ctx(pa);
+			isl_pw_aff_free(pa);
+			isl_die(ctx, isl_error_invalid,
+				"not an affine expression",
+				return isl_multi_pw_aff_free(mpa));
+		}
+		pa = isl_pw_aff_drop_dims(pa, isl_dim_in, dim, n);
+		space = isl_multi_pw_aff_get_domain_space(mpa);
+		pa = isl_pw_aff_reset_domain_space(pa, space);
+		mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);
+	}
+
+	return mpa;
+}
+
+/* Read a tuple of affine expressions, together with optional constraints
+ * on the domain from "s".  "dom" represents the initial constraints
+ * on the domain.
+ *
+ * The isl_multi_aff may live in either a set or a map space.
+ * First read the first tuple and check if it is followed by a "->".
+ * If so, convert the tuple into the domain of the isl_multi_pw_aff and
+ * read in the next tuple.  This tuple (or the first tuple if it was
+ * not followed by a "->") is then converted into an isl_multi_pw_aff
+ * through a call to extract_mpa_from_tuple.
+ * The result is converted to an isl_pw_multi_aff and
+ * its domain is intersected with the domain.
+ */
+static __isl_give isl_pw_multi_aff *read_conditional_multi_aff(
+	__isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v)
+{
+	isl_multi_pw_aff *tuple;
+	isl_multi_pw_aff *mpa;
+	isl_pw_multi_aff *pma;
+	int n = v->n;
+
+	tuple = read_tuple(s, v, 0, 0);
+	if (!tuple)
+		goto error;
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
+		isl_map *map = map_from_tuple(tuple, dom, isl_dim_in, v, 0);
+		dom = isl_map_domain(map);
+		tuple = read_tuple(s, v, 0, 0);
+		if (!tuple)
+			goto error;
+	}
+
+	dom = read_optional_formula(s, dom, v, 0);
+
+	vars_drop(v, v->n - n);
+
+	mpa = extract_mpa_from_tuple(isl_set_get_space(dom), tuple);
+	isl_multi_pw_aff_free(tuple);
+	pma = isl_pw_multi_aff_from_multi_pw_aff(mpa);
+	pma = isl_pw_multi_aff_intersect_domain(pma, dom);
+
+	return pma;
+error:
+	isl_set_free(dom);
+	return NULL;
+}
+
+/* Read an isl_pw_multi_aff from "s".
+ *
+ * In particular, first read the parameters and then read a sequence
+ * of one or more tuples of affine expressions with optional conditions and
+ * add them up.
+ */
+__isl_give isl_pw_multi_aff *isl_stream_read_pw_multi_aff(
+	__isl_keep isl_stream *s)
+{
+	struct vars *v;
+	isl_set *dom;
+	isl_pw_multi_aff *pma = NULL;
+
+	v = vars_new(s->ctx);
+	if (!v)
+		return NULL;
+
+	dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
+	if (next_is_tuple(s)) {
+		dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
+		if (isl_stream_eat(s, ISL_TOKEN_TO))
+			goto error;
+	}
+	if (isl_stream_eat(s, '{'))
+		goto error;
+
+	pma = read_conditional_multi_aff(s, isl_set_copy(dom), v);
+
+	while (isl_stream_eat_if_available(s, ';')) {
+		isl_pw_multi_aff *pma2;
+
+		pma2 = read_conditional_multi_aff(s, isl_set_copy(dom), v);
+		pma = isl_pw_multi_aff_union_add(pma, pma2);
+		if (!pma)
+			goto error;
+	}
+
+	if (isl_stream_eat(s, '}'))
+		goto error;
+
+	isl_set_free(dom);
+	vars_free(v);
+	return pma;
+error:
+	isl_pw_multi_aff_free(pma);
+	isl_set_free(dom);
+	vars_free(v);
+	return NULL;
+}
+
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_read_from_str(isl_ctx *ctx,
+	const char *str)
+{
+	isl_pw_multi_aff *pma;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	pma = isl_stream_read_pw_multi_aff(s);
+	isl_stream_free(s);
+	return pma;
+}
+
+/* Read an isl_union_pw_multi_aff from "s".
+ * We currently read a generic object and if it turns out to be a set or
+ * a map, we convert that to an isl_union_pw_multi_aff.
+ * It would be more efficient if we were to construct
+ * the isl_union_pw_multi_aff directly.
+ */
+__isl_give isl_union_pw_multi_aff *isl_stream_read_union_pw_multi_aff(
+	__isl_keep isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (!obj.v)
+		return NULL;
+
+	if (obj.type == isl_obj_map || obj.type == isl_obj_set)
+		obj = to_union(s->ctx, obj);
+	if (obj.type == isl_obj_union_map)
+		return isl_union_pw_multi_aff_from_union_map(obj.v);
+	if (obj.type == isl_obj_union_set)
+		return isl_union_pw_multi_aff_from_union_set(obj.v);
+
+	obj.type->free(obj.v);
+	isl_die(s->ctx, isl_error_invalid, "unexpected object type",
+		return NULL);
+}
+
+/* Read an isl_union_pw_multi_aff from "str".
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_read_from_str(
+	isl_ctx *ctx, const char *str)
+{
+	isl_union_pw_multi_aff *upma;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	upma = isl_stream_read_union_pw_multi_aff(s);
+	isl_stream_free(s);
+	return upma;
+}
+
+/* Assuming "pa" represents a single affine expression defined on a universe
+ * domain, extract this affine expression.
+ */
+static __isl_give isl_aff *aff_from_pw_aff(__isl_take isl_pw_aff *pa)
+{
+	isl_aff *aff;
+
+	if (!pa)
+		return NULL;
+	if (pa->n != 1)
+		isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
+			"expecting single affine expression",
+			goto error);
+	if (!isl_set_plain_is_universe(pa->p[0].set))
+		isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
+			"expecting universe domain",
+			goto error);
+
+	aff = isl_aff_copy(pa->p[0].aff);
+	isl_pw_aff_free(pa);
+	return aff;
+error:
+	isl_pw_aff_free(pa);
+	return NULL;
+}
+
+/* This function is called for each element in a tuple inside
+ * isl_stream_read_multi_val.
+ * Read an isl_val from "s" and add it to *list.
+ */
+static __isl_give isl_space *read_val_el(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_space *space, int rational, void *user)
+{
+	isl_val_list **list = (isl_val_list **) user;
+	isl_val *val;
+
+	val = isl_stream_read_val(s);
+	*list = isl_val_list_add(*list, val);
+	if (!*list)
+		return isl_space_free(space);
+
+	return space;
+}
+
+/* Read an isl_multi_val from "s".
+ *
+ * We first read a tuple space, collecting the element values in a list.
+ * Then we create an isl_multi_val from the space and the isl_val_list.
+ */
+__isl_give isl_multi_val *isl_stream_read_multi_val(__isl_keep isl_stream *s)
+{
+	struct vars *v;
+	isl_set *dom = NULL;
+	isl_space *space;
+	isl_multi_val *mv = NULL;
+	isl_val_list *list;
+
+	v = vars_new(s->ctx);
+	if (!v)
+		return NULL;
+
+	dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
+	if (next_is_tuple(s)) {
+		dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
+		if (isl_stream_eat(s, ISL_TOKEN_TO))
+			goto error;
+	}
+	if (!isl_set_plain_is_universe(dom))
+		isl_die(s->ctx, isl_error_invalid,
+			"expecting universe parameter domain", goto error);
+	if (isl_stream_eat(s, '{'))
+		goto error;
+
+	space = isl_set_get_space(dom);
+
+	list = isl_val_list_alloc(s->ctx, 0);
+	space = read_tuple_space(s, v, space, 1, 0, &read_val_el, &list);
+	mv = isl_multi_val_from_val_list(space, list);
+
+	if (isl_stream_eat(s, '}'))
+		goto error;
+
+	vars_free(v);
+	isl_set_free(dom);
+	return mv;
+error:
+	vars_free(v);
+	isl_set_free(dom);
+	isl_multi_val_free(mv);
+	return NULL;
+}
+
+/* Read an isl_multi_val from "str".
+ */
+__isl_give isl_multi_val *isl_multi_val_read_from_str(isl_ctx *ctx,
+	const char *str)
+{
+	isl_multi_val *mv;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	mv = isl_stream_read_multi_val(s);
+	isl_stream_free(s);
+	return mv;
+}
+
+/* Read a multi-affine expression from "s".
+ * If the multi-affine expression has a domain, then the tuple
+ * representing this domain cannot involve any affine expressions.
+ * The tuple representing the actual expressions needs to consist
+ * of only affine expressions.  Moreover, these expressions can
+ * only depend on parameters and input dimensions and not on other
+ * output dimensions.
+ */
+__isl_give isl_multi_aff *isl_stream_read_multi_aff(__isl_keep isl_stream *s)
+{
+	struct vars *v;
+	isl_set *dom = NULL;
+	isl_multi_pw_aff *tuple = NULL;
+	int dim, i, n;
+	isl_space *space, *dom_space;
+	isl_multi_aff *ma = NULL;
+
+	v = vars_new(s->ctx);
+	if (!v)
+		return NULL;
+
+	dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
+	if (next_is_tuple(s)) {
+		dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
+		if (isl_stream_eat(s, ISL_TOKEN_TO))
+			goto error;
+	}
+	if (!isl_set_plain_is_universe(dom))
+		isl_die(s->ctx, isl_error_invalid,
+			"expecting universe parameter domain", goto error);
+	if (isl_stream_eat(s, '{'))
+		goto error;
+
+	tuple = read_tuple(s, v, 0, 0);
+	if (!tuple)
+		goto error;
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
+		isl_set *set;
+		isl_space *space;
+		int has_expr;
+
+		has_expr = tuple_has_expr(tuple);
+		if (has_expr < 0)
+			goto error;
+		if (has_expr)
+			isl_die(s->ctx, isl_error_invalid,
+				"expecting universe domain", goto error);
+		space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
+		set = isl_set_universe(space);
+		dom = isl_set_intersect_params(set, dom);
+		isl_multi_pw_aff_free(tuple);
+		tuple = read_tuple(s, v, 0, 0);
+		if (!tuple)
+			goto error;
+	}
+
+	if (isl_stream_eat(s, '}'))
+		goto error;
+
+	n = isl_multi_pw_aff_dim(tuple, isl_dim_out);
+	dim = isl_set_dim(dom, isl_dim_all);
+	dom_space = isl_set_get_space(dom);
+	space = isl_space_range(isl_multi_pw_aff_get_space(tuple));
+	space = isl_space_align_params(space, isl_space_copy(dom_space));
+	if (!isl_space_is_params(dom_space))
+		space = isl_space_map_from_domain_and_range(
+				isl_space_copy(dom_space), space);
+	isl_space_free(dom_space);
+	ma = isl_multi_aff_alloc(space);
+
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+		isl_aff *aff;
+		pa = isl_multi_pw_aff_get_pw_aff(tuple, i);
+		aff = aff_from_pw_aff(pa);
+		if (!aff)
+			goto error;
+		if (isl_aff_involves_dims(aff, isl_dim_in, dim, i + 1)) {
+			isl_aff_free(aff);
+			isl_die(s->ctx, isl_error_invalid,
+				"not an affine expression", goto error);
+		}
+		aff = isl_aff_drop_dims(aff, isl_dim_in, dim, n);
+		space = isl_multi_aff_get_domain_space(ma);
+		aff = isl_aff_reset_domain_space(aff, space);
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+
+	isl_multi_pw_aff_free(tuple);
+	vars_free(v);
+	isl_set_free(dom);
+	return ma;
+error:
+	isl_multi_pw_aff_free(tuple);
+	vars_free(v);
+	isl_set_free(dom);
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+__isl_give isl_multi_aff *isl_multi_aff_read_from_str(isl_ctx *ctx,
+	const char *str)
+{
+	isl_multi_aff *maff;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	maff = isl_stream_read_multi_aff(s);
+	isl_stream_free(s);
+	return maff;
+}
+
+/* Read an isl_multi_pw_aff from "s".
+ *
+ * The input format is similar to that of map, except that any conditions
+ * on the domains should be specified inside the tuple since each
+ * piecewise affine expression may have a different domain.
+ *
+ * Since we do not know in advance if the isl_multi_pw_aff lives
+ * in a set or a map space, we first read the first tuple and check
+ * if it is followed by a "->".  If so, we convert the tuple into
+ * the domain of the isl_multi_pw_aff and read in the next tuple.
+ * This tuple (or the first tuple if it was not followed by a "->")
+ * is then converted into the isl_multi_pw_aff through a call
+ * to extract_mpa_from_tuple and the domain of the result
+ * is intersected with the domain.
+ */
+__isl_give isl_multi_pw_aff *isl_stream_read_multi_pw_aff(
+	__isl_keep isl_stream *s)
+{
+	struct vars *v;
+	isl_set *dom = NULL;
+	isl_multi_pw_aff *tuple = NULL;
+	isl_multi_pw_aff *mpa = NULL;
+
+	v = vars_new(s->ctx);
+	if (!v)
+		return NULL;
+
+	dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
+	if (next_is_tuple(s)) {
+		dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
+		if (isl_stream_eat(s, ISL_TOKEN_TO))
+			goto error;
+	}
+	if (isl_stream_eat(s, '{'))
+		goto error;
+
+	tuple = read_tuple(s, v, 0, 0);
+	if (!tuple)
+		goto error;
+	if (isl_stream_eat_if_available(s, ISL_TOKEN_TO)) {
+		isl_map *map = map_from_tuple(tuple, dom, isl_dim_in, v, 0);
+		dom = isl_map_domain(map);
+		tuple = read_tuple(s, v, 0, 0);
+		if (!tuple)
+			goto error;
+	}
+
+	if (isl_stream_eat(s, '}'))
+		goto error;
+
+	mpa = extract_mpa_from_tuple(isl_set_get_space(dom), tuple);
+
+	isl_multi_pw_aff_free(tuple);
+	vars_free(v);
+	mpa = isl_multi_pw_aff_intersect_domain(mpa, dom);
+	return mpa;
+error:
+	isl_multi_pw_aff_free(tuple);
+	vars_free(v);
+	isl_set_free(dom);
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Read an isl_multi_pw_aff from "str".
+ */
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(isl_ctx *ctx,
+	const char *str)
+{
+	isl_multi_pw_aff *mpa;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	mpa = isl_stream_read_multi_pw_aff(s);
+	isl_stream_free(s);
+	return mpa;
+}
+
+/* Read the body of an isl_union_pw_aff from "s" with parameter domain "dom".
+ */
+static __isl_give isl_union_pw_aff *read_union_pw_aff_with_dom(
+	__isl_keep isl_stream *s, __isl_take isl_set *dom, struct vars *v)
+{
+	isl_pw_aff *pa;
+	isl_union_pw_aff *upa = NULL;
+	isl_set *aff_dom;
+	int n;
+
+	n = v->n;
+	aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
+	pa = read_pw_aff_with_dom(s, aff_dom, v);
+	vars_drop(v, v->n - n);
+
+	upa = isl_union_pw_aff_from_pw_aff(pa);
+
+	while (isl_stream_eat_if_available(s, ';')) {
+		isl_pw_aff *pa_i;
+		isl_union_pw_aff *upa_i;
+
+		n = v->n;
+		aff_dom = read_aff_domain(s, isl_set_copy(dom), v);
+		pa_i = read_pw_aff_with_dom(s, aff_dom, v);
+		vars_drop(v, v->n - n);
+
+		upa_i = isl_union_pw_aff_from_pw_aff(pa_i);
+		upa = isl_union_pw_aff_union_add(upa, upa_i);
+	}
+
+	isl_set_free(dom);
+	return upa;
+}
+
+/* Read an isl_union_pw_aff from "s".
+ *
+ * First check if there are any paramters, then read in the opening brace
+ * and use read_union_pw_aff_with_dom to read in the body of
+ * the isl_union_pw_aff.  Finally, read the closing brace.
+ */
+__isl_give isl_union_pw_aff *isl_stream_read_union_pw_aff(
+	__isl_keep isl_stream *s)
+{
+	struct vars *v;
+	isl_set *dom;
+	isl_union_pw_aff *upa = NULL;
+
+	v = vars_new(s->ctx);
+	if (!v)
+		return NULL;
+
+	dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
+	if (next_is_tuple(s)) {
+		dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
+		if (isl_stream_eat(s, ISL_TOKEN_TO))
+			goto error;
+	}
+	if (isl_stream_eat(s, '{'))
+		goto error;
+
+	upa = read_union_pw_aff_with_dom(s, isl_set_copy(dom), v);
+
+	if (isl_stream_eat(s, '}'))
+		goto error;
+
+	vars_free(v);
+	isl_set_free(dom);
+	return upa;
+error:
+	vars_free(v);
+	isl_set_free(dom);
+	isl_union_pw_aff_free(upa);
+	return NULL;
+}
+
+/* Read an isl_union_pw_aff from "str".
+ */
+__isl_give isl_union_pw_aff *isl_union_pw_aff_read_from_str(isl_ctx *ctx,
+	const char *str)
+{
+	isl_union_pw_aff *upa;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	upa = isl_stream_read_union_pw_aff(s);
+	isl_stream_free(s);
+	return upa;
+}
+
+/* This function is called for each element in a tuple inside
+ * isl_stream_read_multi_union_pw_aff.
+ *
+ * Read a '{', the union piecewise affine expression body and a '}' and
+ * add the isl_union_pw_aff to *list.
+ */
+static __isl_give isl_space *read_union_pw_aff_el(__isl_keep isl_stream *s,
+	struct vars *v, __isl_take isl_space *space, int rational, void *user)
+{
+	isl_set *dom;
+	isl_union_pw_aff *upa;
+	isl_union_pw_aff_list **list = (isl_union_pw_aff_list **) user;
+
+	dom = isl_set_universe(isl_space_params(isl_space_copy(space)));
+	if (isl_stream_eat(s, '{'))
+		goto error;
+	upa = read_union_pw_aff_with_dom(s, dom, v);
+	*list = isl_union_pw_aff_list_add(*list, upa);
+	if (isl_stream_eat(s, '}'))
+		return isl_space_free(space);
+	if (!*list)
+		return isl_space_free(space);
+	return space;
+error:
+	isl_set_free(dom);
+	return isl_space_free(space);
+}
+
+/* Do the next tokens in "s" correspond to an empty tuple?
+ * In particular, does the stream start with a '[', followed by a ']',
+ * not followed by a "->"?
+ */
+static int next_is_empty_tuple(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok, *tok2, *tok3;
+	int is_empty_tuple = 0;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	if (tok->type != '[') {
+		isl_stream_push_token(s, tok);
+		return 0;
+	}
+
+	tok2 = isl_stream_next_token(s);
+	if (tok2 && tok2->type == ']') {
+		tok3 = isl_stream_next_token(s);
+		is_empty_tuple = !tok || tok->type != ISL_TOKEN_TO;
+		if (tok3)
+			isl_stream_push_token(s, tok3);
+	}
+	if (tok2)
+		isl_stream_push_token(s, tok2);
+	isl_stream_push_token(s, tok);
+
+	return is_empty_tuple;
+}
+
+/* Do the next tokens in "s" correspond to a tuple of parameters?
+ * In particular, does the stream start with a '[' that is not
+ * followed by a '{' or a nested tuple?
+ */
+static int next_is_param_tuple(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok, *tok2;
+	int is_tuple;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	if (tok->type != '[' || next_is_tuple(s)) {
+		isl_stream_push_token(s, tok);
+		return 0;
+	}
+
+	tok2 = isl_stream_next_token(s);
+	is_tuple = tok2 && tok2->type != '{';
+	if (tok2)
+		isl_stream_push_token(s, tok2);
+	isl_stream_push_token(s, tok);
+
+	return is_tuple;
+}
+
+/* Read an isl_multi_union_pw_aff from "s".
+ *
+ * The input has the form
+ *
+ *	[{ [..] : ... ; [..] : ... }, { [..] : ... ; [..] : ... }]
+ *
+ * or
+ *
+ *	[..] -> [{ [..] : ... ; [..] : ... }, { [..] : ... ; [..] : ... }]
+ *
+ * We first check for the special case of an empty tuple "[]".
+ * Then we check if there are any parameters.
+ * Finally, we read the tuple, collecting the individual isl_union_pw_aff
+ * elements in a list and construct the result from the tuple space and
+ * the list.
+ */
+__isl_give isl_multi_union_pw_aff *isl_stream_read_multi_union_pw_aff(
+	__isl_keep isl_stream *s)
+{
+	struct vars *v;
+	isl_set *dom = NULL;
+	isl_space *space;
+	isl_multi_union_pw_aff *mupa = NULL;
+	isl_union_pw_aff_list *list;
+
+	if (next_is_empty_tuple(s)) {
+		if (isl_stream_eat(s, '['))
+			return NULL;
+		if (isl_stream_eat(s, ']'))
+			return NULL;
+		space = isl_space_set_alloc(s->ctx, 0, 0);
+		return isl_multi_union_pw_aff_zero(space);
+	}
+
+	v = vars_new(s->ctx);
+	if (!v)
+		return NULL;
+
+	dom = isl_set_universe(isl_space_params_alloc(s->ctx, 0));
+	if (next_is_param_tuple(s)) {
+		dom = read_map_tuple(s, dom, isl_dim_param, v, 1, 0);
+		if (isl_stream_eat(s, ISL_TOKEN_TO))
+			goto error;
+	}
+	space = isl_set_get_space(dom);
+	isl_set_free(dom);
+	list = isl_union_pw_aff_list_alloc(s->ctx, 0);
+	space = read_tuple_space(s, v, space, 1, 0,
+				&read_union_pw_aff_el, &list);
+	mupa = isl_multi_union_pw_aff_from_union_pw_aff_list(space, list);
+
+	vars_free(v);
+
+	return mupa;
+error:
+	vars_free(v);
+	isl_set_free(dom);
+	isl_multi_union_pw_aff_free(mupa);
+	return NULL;
+}
+
+/* Read an isl_multi_union_pw_aff from "str".
+ */
+__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_read_from_str(
+	isl_ctx *ctx, const char *str)
+{
+	isl_multi_union_pw_aff *mupa;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	mupa = isl_stream_read_multi_union_pw_aff(s);
+	isl_stream_free(s);
+	return mupa;
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_stream_read_union_pw_qpolynomial(
+	__isl_keep isl_stream *s)
+{
+	struct isl_obj obj;
+
+	obj = obj_read(s);
+	if (obj.type == isl_obj_pw_qpolynomial) {
+		obj.type = isl_obj_union_pw_qpolynomial;
+		obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v);
+	}
+	if (obj.v)
+		isl_assert(s->ctx, obj.type == isl_obj_union_pw_qpolynomial,
+			   goto error);
+
+	return obj.v;
+error:
+	obj.type->free(obj.v);
+	return NULL;
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_read_from_str(
+	isl_ctx *ctx, const char *str)
+{
+	isl_union_pw_qpolynomial *upwqp;
+	isl_stream *s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	upwqp = isl_stream_read_union_pw_qpolynomial(s);
+	isl_stream_free(s);
+	return upwqp;
+}
diff --git a/final/lib/External/isl/isl_int.h b/final/lib/External/isl/isl_int.h
new file mode 100644
index 0000000..07be2ba
--- /dev/null
+++ b/final/lib/External/isl/isl_int.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_INT_H
+#define ISL_INT_H
+#define ISL_DEPRECATED_INT_H
+
+#include <isl/hash.h>
+#include <isl/printer.h>
+#include <string.h>
+#include <isl_config.h>
+
+#ifdef USE_GMP_FOR_MP
+#include <isl_int_gmp.h>
+#endif
+
+#ifdef USE_IMATH_FOR_MP
+#ifdef USE_SMALL_INT_OPT
+#include <isl_int_sioimath.h>
+#else /* USE_SMALL_INT_OPT */
+#include <isl_int_imath.h>
+#endif /* USE_SMALL_INT_OPT */
+#endif /* USE_IMATH_FOR_MP */
+
+#define isl_int_is_zero(i)	(isl_int_sgn(i) == 0)
+#define isl_int_is_one(i)	(isl_int_cmp_si(i,1) == 0)
+#define isl_int_is_negone(i)	(isl_int_cmp_si(i,-1) == 0)
+#define isl_int_is_pos(i)	(isl_int_sgn(i) > 0)
+#define isl_int_is_neg(i)	(isl_int_sgn(i) < 0)
+#define isl_int_is_nonpos(i)	(isl_int_sgn(i) <= 0)
+#define isl_int_is_nonneg(i)	(isl_int_sgn(i) >= 0)
+
+#ifndef USE_SMALL_INT_OPT
+#define isl_int_print(out,i,width)					\
+	do {								\
+		char *s;						\
+		s = isl_int_get_str(i);					\
+		fprintf(out, "%*s", width, s);				\
+		isl_int_free_str(s);                                        \
+	} while (0)
+#endif /* USE_SMALL_INT_OPT */
+
+__isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p,
+	isl_int i);
+
+#endif /* ISL_INT_H */
diff --git a/final/lib/External/isl/isl_int_gmp.h b/final/lib/External/isl/isl_int_gmp.h
new file mode 100644
index 0000000..3a35e26
--- /dev/null
+++ b/final/lib/External/isl/isl_int_gmp.h
@@ -0,0 +1,89 @@
+#ifndef ISL_INT_GMP_H
+#define ISL_INT_GMP_H
+
+#include <gmp.h>
+
+/* isl_int is the basic integer type, implemented with GMP's mpz_t.  In the
+ * future, different types such as long long or cln::cl_I will be supported.
+ */
+typedef mpz_t	isl_int;
+
+#define isl_int_init(i)		mpz_init(i)
+#define isl_int_clear(i)	mpz_clear(i)
+
+#define isl_int_set(r,i)	mpz_set(r,i)
+#define isl_int_set_si(r,i)	mpz_set_si(r,i)
+#define isl_int_set_ui(r,i)	mpz_set_ui(r,i)
+#define isl_int_fits_slong(r)	mpz_fits_slong_p(r)
+#define isl_int_get_si(r)	mpz_get_si(r)
+#define isl_int_fits_ulong(r)	mpz_fits_ulong_p(r)
+#define isl_int_get_ui(r)	mpz_get_ui(r)
+#define isl_int_get_d(r)	mpz_get_d(r)
+#define isl_int_get_str(r)	mpz_get_str(0, 10, r)
+#define isl_int_abs(r,i)	mpz_abs(r,i)
+#define isl_int_neg(r,i)	mpz_neg(r,i)
+#define isl_int_swap(i,j)	mpz_swap(i,j)
+#define isl_int_swap_or_set(i,j)	mpz_swap(i,j)
+#define isl_int_add_ui(r,i,j)	mpz_add_ui(r,i,j)
+#define isl_int_sub_ui(r,i,j)	mpz_sub_ui(r,i,j)
+
+#define isl_int_add(r,i,j)	mpz_add(r,i,j)
+#define isl_int_sub(r,i,j)	mpz_sub(r,i,j)
+#define isl_int_mul(r,i,j)	mpz_mul(r,i,j)
+#define isl_int_mul_2exp(r,i,j)	mpz_mul_2exp(r,i,j)
+#define isl_int_mul_si(r,i,j)	mpz_mul_si(r,i,j)
+#define isl_int_mul_ui(r,i,j)	mpz_mul_ui(r,i,j)
+#define isl_int_pow_ui(r,i,j)	mpz_pow_ui(r,i,j)
+#define isl_int_addmul(r,i,j)	mpz_addmul(r,i,j)
+#define isl_int_addmul_ui(r,i,j)	mpz_addmul_ui(r,i,j)
+#define isl_int_submul(r,i,j)	mpz_submul(r,i,j)
+#define isl_int_submul_ui(r,i,j)	mpz_submul_ui(r,i,j)
+
+#define isl_int_gcd(r,i,j)	mpz_gcd(r,i,j)
+#define isl_int_lcm(r,i,j)	mpz_lcm(r,i,j)
+#define isl_int_divexact(r,i,j)	mpz_divexact(r,i,j)
+#define isl_int_divexact_ui(r,i,j)	mpz_divexact_ui(r,i,j)
+#define isl_int_tdiv_q(r,i,j)	mpz_tdiv_q(r,i,j)
+#define isl_int_cdiv_q(r,i,j)	mpz_cdiv_q(r,i,j)
+#define isl_int_cdiv_q_ui(r,i,j)	mpz_cdiv_q_ui(r,i,j)
+#define isl_int_fdiv_q(r,i,j)	mpz_fdiv_q(r,i,j)
+#define isl_int_fdiv_r(r,i,j)	mpz_fdiv_r(r,i,j)
+#define isl_int_fdiv_q_ui(r,i,j)	mpz_fdiv_q_ui(r,i,j)
+
+#define isl_int_read(r,s)	mpz_set_str(r,s,10)
+#define isl_int_sgn(i)		mpz_sgn(i)
+#define isl_int_cmp(i,j)	mpz_cmp(i,j)
+#define isl_int_cmp_si(i,si)	mpz_cmp_si(i,si)
+#define isl_int_eq(i,j)		(mpz_cmp(i,j) == 0)
+#define isl_int_ne(i,j)		(mpz_cmp(i,j) != 0)
+#define isl_int_lt(i,j)		(mpz_cmp(i,j) < 0)
+#define isl_int_le(i,j)		(mpz_cmp(i,j) <= 0)
+#define isl_int_gt(i,j)		(mpz_cmp(i,j) > 0)
+#define isl_int_ge(i,j)		(mpz_cmp(i,j) >= 0)
+#define isl_int_abs_cmp(i,j)	mpz_cmpabs(i,j)
+#define isl_int_abs_eq(i,j)	(mpz_cmpabs(i,j) == 0)
+#define isl_int_abs_ne(i,j)	(mpz_cmpabs(i,j) != 0)
+#define isl_int_abs_lt(i,j)	(mpz_cmpabs(i,j) < 0)
+#define isl_int_abs_gt(i,j)	(mpz_cmpabs(i,j) > 0)
+#define isl_int_abs_ge(i,j)	(mpz_cmpabs(i,j) >= 0)
+#define isl_int_is_divisible_by(i,j)	mpz_divisible_p(i,j)
+
+uint32_t isl_gmp_hash(mpz_t v, uint32_t hash);
+#define isl_int_hash(v,h)	isl_gmp_hash(v,h)
+
+#ifndef mp_get_memory_functions
+void mp_get_memory_functions(
+		void *(**alloc_func_ptr) (size_t),
+		void *(**realloc_func_ptr) (void *, size_t, size_t),
+		void (**free_func_ptr) (void *, size_t));
+#endif
+
+typedef void (*isl_int_print_mp_free_t)(void *, size_t);
+#define isl_int_free_str(s)					\
+	do {								\
+		isl_int_print_mp_free_t mp_free;			\
+		mp_get_memory_functions(NULL, NULL, &mp_free);		\
+		(*mp_free)(s, strlen(s) + 1);				\
+	} while (0)
+
+#endif /* ISL_INT_GMP_H */
diff --git a/final/lib/External/isl/isl_int_imath.h b/final/lib/External/isl/isl_int_imath.h
new file mode 100644
index 0000000..73d6379
--- /dev/null
+++ b/final/lib/External/isl/isl_int_imath.h
@@ -0,0 +1,77 @@
+#ifndef ISL_INT_IMATH_H
+#define ISL_INT_IMATH_H
+
+#include "isl_hide_deprecated.h"
+
+#include <isl_imath.h>
+
+/* isl_int is the basic integer type, implemented with imath's mp_int. */
+typedef mp_int isl_int;
+
+#define isl_int_init(i)		i = mp_int_alloc()
+#define isl_int_clear(i)	mp_int_free(i)
+
+#define isl_int_set(r,i)	impz_set(r,i)
+#define isl_int_set_si(r,i)	impz_set_si(r,i)
+#define isl_int_set_ui(r,i)	impz_set_ui(r,i)
+#define isl_int_fits_slong(r)	isl_imath_fits_slong_p(r)
+#define isl_int_get_si(r)	impz_get_si(r)
+#define isl_int_fits_ulong(r)	isl_imath_fits_ulong_p(r)
+#define isl_int_get_ui(r)	impz_get_ui(r)
+#define isl_int_get_d(r)	impz_get_si(r)
+#define isl_int_get_str(r)	impz_get_str(0, 10, r)
+#define isl_int_abs(r,i)	impz_abs(r,i)
+#define isl_int_neg(r,i)	impz_neg(r,i)
+#define isl_int_swap(i,j)	impz_swap(i,j)
+#define isl_int_swap_or_set(i,j)	impz_swap(i,j)
+#define isl_int_add_ui(r,i,j)	impz_add_ui(r,i,j)
+#define isl_int_sub_ui(r,i,j)	impz_sub_ui(r,i,j)
+
+#define isl_int_add(r,i,j)	impz_add(r,i,j)
+#define isl_int_sub(r,i,j)	impz_sub(r,i,j)
+#define isl_int_mul(r,i,j)	impz_mul(r,i,j)
+#define isl_int_mul_2exp(r,i,j)	impz_mul_2exp(r,i,j)
+#define isl_int_mul_si(r,i,j)	mp_int_mul_value(i,j,r)
+#define isl_int_mul_ui(r,i,j)	impz_mul_ui(r,i,j)
+#define isl_int_pow_ui(r,i,j)	impz_pow_ui(r,i,j)
+#define isl_int_addmul(r,i,j)	impz_addmul(r,i,j)
+#define isl_int_addmul_ui(r,i,j)	isl_imath_addmul_ui(r,i,j)
+#define isl_int_submul(r,i,j)	impz_submul(r,i,j)
+#define isl_int_submul_ui(r,i,j)	isl_imath_submul_ui(r,i,j)
+
+#define isl_int_gcd(r,i,j)	impz_gcd(r,i,j)
+#define isl_int_lcm(r,i,j)	impz_lcm(r,i,j)
+#define isl_int_divexact(r,i,j)	impz_divexact(r,i,j)
+#define isl_int_divexact_ui(r,i,j)	impz_divexact_ui(r,i,j)
+#define isl_int_tdiv_q(r,i,j)	impz_tdiv_q(r,i,j)
+#define isl_int_cdiv_q(r,i,j)	impz_cdiv_q(r,i,j)
+#define isl_int_cdiv_q_ui(r,i,j)	isl_imath_cdiv_q_ui(r,i,j)
+#define isl_int_fdiv_q(r,i,j)	impz_fdiv_q(r,i,j)
+#define isl_int_fdiv_r(r,i,j)	impz_fdiv_r(r,i,j)
+#define isl_int_fdiv_q_ui(r,i,j)	isl_imath_fdiv_q_ui(r,i,j)
+
+#define isl_int_read(r,s)	impz_set_str(r,s,10)
+#define isl_int_sgn(i)		impz_sgn(i)
+#define isl_int_cmp(i,j)	impz_cmp(i,j)
+#define isl_int_cmp_si(i,si)	impz_cmp_si(i,si)
+#define isl_int_eq(i,j)		(impz_cmp(i,j) == 0)
+#define isl_int_ne(i,j)		(impz_cmp(i,j) != 0)
+#define isl_int_lt(i,j)		(impz_cmp(i,j) < 0)
+#define isl_int_le(i,j)		(impz_cmp(i,j) <= 0)
+#define isl_int_gt(i,j)		(impz_cmp(i,j) > 0)
+#define isl_int_ge(i,j)		(impz_cmp(i,j) >= 0)
+#define isl_int_abs_cmp(i,j)	impz_cmpabs(i,j)
+#define isl_int_abs_eq(i,j)	(impz_cmpabs(i,j) == 0)
+#define isl_int_abs_ne(i,j)	(impz_cmpabs(i,j) != 0)
+#define isl_int_abs_lt(i,j)	(impz_cmpabs(i,j) < 0)
+#define isl_int_abs_gt(i,j)	(impz_cmpabs(i,j) > 0)
+#define isl_int_abs_ge(i,j)	(impz_cmpabs(i,j) >= 0)
+#define isl_int_is_divisible_by(i,j)	impz_divisible_p(i,j)
+
+uint32_t isl_imath_hash(mp_int v, uint32_t hash);
+#define isl_int_hash(v,h)	isl_imath_hash(v,h)
+
+typedef void (*isl_int_print_mp_free_t)(void *, size_t);
+#define isl_int_free_str(s)	free(s)
+
+#endif /* ISL_INT_IMATH_H */
diff --git a/final/lib/External/isl/isl_int_sioimath.c b/final/lib/External/isl/isl_int_sioimath.c
new file mode 100644
index 0000000..1702862
--- /dev/null
+++ b/final/lib/External/isl/isl_int_sioimath.c
@@ -0,0 +1,223 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <isl_int.h>
+
+extern int isl_sioimath_decode(isl_sioimath val, int32_t *small, mp_int *big);
+extern int isl_sioimath_decode_big(isl_sioimath val, mp_int *big);
+extern int isl_sioimath_decode_small(isl_sioimath val, int32_t *small);
+
+extern isl_sioimath isl_sioimath_encode_small(int32_t val);
+extern isl_sioimath isl_sioimath_encode_big(mp_int val);
+extern int isl_sioimath_is_small(isl_sioimath val);
+extern int isl_sioimath_is_big(isl_sioimath val);
+extern int32_t isl_sioimath_get_small(isl_sioimath val);
+extern mp_int isl_sioimath_get_big(isl_sioimath val);
+
+extern void isl_siomath_uint32_to_digits(uint32_t num, mp_digit *digits,
+	mp_size *used);
+extern void isl_siomath_ulong_to_digits(unsigned long num, mp_digit *digits,
+	mp_size *used);
+extern void isl_siomath_uint64_to_digits(uint64_t num, mp_digit *digits,
+	mp_size *used);
+
+extern mp_int isl_sioimath_bigarg_src(isl_sioimath arg,
+	isl_sioimath_scratchspace_t *scratch);
+extern mp_int isl_sioimath_siarg_src(signed long arg,
+	isl_sioimath_scratchspace_t *scratch);
+extern mp_int isl_sioimath_si64arg_src(int64_t arg,
+	isl_sioimath_scratchspace_t *scratch);
+extern mp_int isl_sioimath_uiarg_src(unsigned long arg,
+	isl_sioimath_scratchspace_t *scratch);
+extern mp_int isl_sioimath_reinit_big(isl_sioimath_ptr ptr);
+extern void isl_sioimath_set_small(isl_sioimath_ptr ptr, int32_t val);
+extern void isl_sioimath_set_int32(isl_sioimath_ptr ptr, int32_t val);
+extern void isl_sioimath_set_int64(isl_sioimath_ptr ptr, int64_t val);
+extern void isl_sioimath_promote(isl_sioimath_ptr dst);
+extern void isl_sioimath_try_demote(isl_sioimath_ptr dst);
+
+extern void isl_sioimath_init(isl_sioimath_ptr dst);
+extern void isl_sioimath_clear(isl_sioimath_ptr dst);
+extern void isl_sioimath_set(isl_sioimath_ptr dst, isl_sioimath_src val);
+extern void isl_sioimath_set_si(isl_sioimath_ptr dst, long val);
+extern void isl_sioimath_set_ui(isl_sioimath_ptr dst, unsigned long val);
+extern int isl_sioimath_fits_slong(isl_sioimath_src val);
+extern long isl_sioimath_get_si(isl_sioimath_src val);
+extern int isl_sioimath_fits_ulong(isl_sioimath_src val);
+extern unsigned long isl_sioimath_get_ui(isl_sioimath_src val);
+extern double isl_sioimath_get_d(isl_sioimath_src val);
+extern char *isl_sioimath_get_str(isl_sioimath_src val);
+extern void isl_sioimath_abs(isl_sioimath_ptr dst, isl_sioimath_src arg);
+extern void isl_sioimath_neg(isl_sioimath_ptr dst, isl_sioimath_src arg);
+extern void isl_sioimath_swap(isl_sioimath_ptr lhs, isl_sioimath_ptr rhs);
+extern void isl_sioimath_add_ui(isl_sioimath_ptr dst, isl_sioimath lhs,
+	unsigned long rhs);
+extern void isl_sioimath_sub_ui(isl_sioimath_ptr dst, isl_sioimath lhs,
+	unsigned long rhs);
+
+extern void isl_sioimath_add(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs);
+extern void isl_sioimath_sub(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs);
+extern void isl_sioimath_mul(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs);
+extern void isl_sioimath_mul_2exp(isl_sioimath_ptr dst, isl_sioimath lhs,
+	unsigned long rhs);
+extern void isl_sioimath_mul_si(isl_sioimath_ptr dst, isl_sioimath lhs,
+	signed long rhs);
+extern void isl_sioimath_mul_ui(isl_sioimath_ptr dst, isl_sioimath lhs,
+	unsigned long rhs);
+extern void isl_sioimath_pow_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	unsigned long rhs);
+extern void isl_sioimath_addmul(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs);
+extern void isl_sioimath_addmul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	unsigned long rhs);
+extern void isl_sioimath_submul(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs);
+extern void isl_sioimath_submul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	unsigned long rhs);
+
+/* Implements the Euclidean algorithm to compute the greatest common divisor of
+ * two values in small representation.
+ */
+static uint32_t isl_sioimath_smallgcd(int32_t lhs, int32_t rhs)
+{
+	uint32_t dividend, divisor, remainder;
+
+	dividend = labs(lhs);
+	divisor = labs(rhs);
+	while (divisor) {
+		remainder = dividend % divisor;
+		dividend = divisor;
+		divisor = remainder;
+	}
+
+	return dividend;
+}
+
+/* Compute the greatest common divisor.
+ *
+ * Per GMP convention, gcd(0,0)==0 and otherwise always positive.
+ */
+void isl_sioimath_gcd(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs)
+{
+	int32_t lhssmall, rhssmall;
+	uint32_t smallgcd;
+	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
+
+	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
+	    isl_sioimath_decode_small(rhs, &rhssmall)) {
+		smallgcd = isl_sioimath_smallgcd(lhssmall, rhssmall);
+		isl_sioimath_set_small(dst, smallgcd);
+		return;
+	}
+
+	impz_gcd(isl_sioimath_reinit_big(dst),
+	    isl_sioimath_bigarg_src(lhs, &scratchlhs),
+	    isl_sioimath_bigarg_src(rhs, &scratchrhs));
+	isl_sioimath_try_demote(dst);
+}
+
+/* Compute the lowest common multiple of two numbers.
+ */
+void isl_sioimath_lcm(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs)
+{
+	int32_t lhssmall, rhssmall;
+	uint32_t smallgcd;
+	uint64_t multiple;
+	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
+
+	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
+	    isl_sioimath_decode_small(rhs, &rhssmall)) {
+		if (lhssmall == 0 || rhssmall == 0) {
+			isl_sioimath_set_small(dst, 0);
+			return;
+		}
+		smallgcd = isl_sioimath_smallgcd(lhssmall, rhssmall);
+		multiple = (uint64_t) abs(lhssmall) * (uint64_t) abs(rhssmall);
+		isl_sioimath_set_int64(dst, multiple / smallgcd);
+		return;
+	}
+
+	impz_lcm(isl_sioimath_reinit_big(dst),
+	    isl_sioimath_bigarg_src(lhs, &scratchlhs),
+	    isl_sioimath_bigarg_src(rhs, &scratchrhs));
+	isl_sioimath_try_demote(dst);
+}
+
+extern void isl_sioimath_tdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs);
+extern void isl_sioimath_tdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	unsigned long rhs);
+extern void isl_sioimath_cdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs);
+extern void isl_sioimath_cdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	unsigned long rhs);
+extern void isl_sioimath_fdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs);
+extern void isl_sioimath_fdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	unsigned long rhs);
+extern void isl_sioimath_fdiv_r(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs);
+
+/* Parse a number from a string.
+ * If it has less than 10 characters then it will fit into the small
+ * representation (i.e. strlen("2147483647")). Otherwise, let IMath parse it.
+ */
+void isl_sioimath_read(isl_sioimath_ptr dst, const char *str)
+{
+	int32_t small;
+
+	if (strlen(str) < 10) {
+		small = strtol(str, NULL, 10);
+		isl_sioimath_set_small(dst, small);
+		return;
+	}
+
+	mp_int_read_string(isl_sioimath_reinit_big(dst), 10, str);
+	isl_sioimath_try_demote(dst);
+}
+
+extern int isl_sioimath_sgn(isl_sioimath_src arg);
+extern int isl_sioimath_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs);
+extern int isl_sioimath_cmp_si(isl_sioimath_src lhs, signed long rhs);
+extern int isl_sioimath_abs_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs);
+extern int isl_sioimath_is_divisible_by(isl_sioimath_src lhs,
+	isl_sioimath_src rhs);
+
+extern uint32_t isl_sioimath_hash(isl_sioimath_src arg, uint32_t hash);
+extern size_t isl_sioimath_sizeinbase(isl_sioimath_src arg, int base);
+extern void isl_sioimath_print(FILE *out, isl_sioimath_src i, int width);
+
+/* Print an isl_int to FILE*. Adds space padding to the left until at least
+ * width characters are printed.
+ */
+void isl_sioimath_print(FILE *out, isl_sioimath_src i, int width)
+{
+	size_t len;
+	int32_t small;
+	mp_int big;
+	char *buf;
+
+	if (isl_sioimath_decode_small(i, &small)) {
+		fprintf(out, "%*" PRIi32, width, small);
+		return;
+	}
+
+	big = isl_sioimath_get_big(i);
+	len = mp_int_string_len(big, 10);
+	buf = malloc(len);
+	mp_int_to_string(big, 10, buf, len);
+	fprintf(out, "%*s", width, buf);
+	free(buf);
+}
+
+/* Print a number to stdout. Meant for debugging.
+ */
+void isl_sioimath_dump(isl_sioimath_src arg)
+{
+	isl_sioimath_print(stdout, arg, 0);
+}
diff --git a/final/lib/External/isl/isl_int_sioimath.h b/final/lib/External/isl/isl_int_sioimath.h
new file mode 100644
index 0000000..a2112cd
--- /dev/null
+++ b/final/lib/External/isl/isl_int_sioimath.h
@@ -0,0 +1,1254 @@
+/*
+ * Copyright 2015 INRIA Paris-Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Michael Kruse, INRIA Paris-Rocquencourt,
+ * Domaine de Voluceau, Rocquenqourt, B.P. 105,
+ * 78153 Le Chesnay Cedex France
+ */
+#ifndef ISL_INT_SIOIMATH_H
+#define ISL_INT_SIOIMATH_H
+
+#include <inttypes.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <isl_imath.h>
+#include <isl/hash.h>
+
+#define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
+
+/* Visual Studio before VS2015 does not support the inline keyword when
+ * compiling in C mode because it was introduced in C99 which it does not
+ * officially support.  Instead, it has a proprietary extension using __inline.
+ */
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define inline __inline
+#endif
+
+/* The type to represent integers optimized for small values. It is either a
+ * pointer to an mp_int ( = mpz_t*; big representation) or an int32_t (small
+ * represenation) with a discriminator at the least significant bit. In big
+ * representation it will be always zero because of heap alignment. It is set
+ * to 1 for small representation and use the 32 most significant bits for the
+ * int32_t.
+ *
+ * Structure on 64 bit machines, with 8-byte aligment (3 bits):
+ *
+ * Big representation:
+ * MSB                                                          LSB
+ * |------------------------------------------------------------000
+ * |                            mpz_t*                            |
+ * |                           != NULL                            |
+ *
+ * Small representation:
+ * MSB                           32                             LSB
+ * |------------------------------|00000000000000000000000000000001
+ * |          int32_t             |
+ * |  2147483647 ... -2147483647  |
+ *                                                                ^
+ *                                                                |
+ *                                                        discriminator bit
+ *
+ * On 32 bit machines isl_sioimath type is blown up to 8 bytes, i.e.
+ * isl_sioimath is guaranteed to be at least 8 bytes. This is to ensure the
+ * int32_t can be hidden in that type without data loss. In the future we might
+ * optimize this to use 31 hidden bits in a 32 bit pointer. We may also use 63
+ * bits on 64 bit machines, but this comes with the cost of additional overflow
+ * checks because there is no standardized 128 bit integer we could expand to.
+ *
+ * We use native integer types and avoid union structures to avoid assumptions
+ * on the machine's endianness.
+ *
+ * This implementation makes the following assumptions:
+ * - long can represent any int32_t
+ * - mp_small is signed long
+ * - mp_usmall is unsigned long
+ * - adresses returned by malloc are aligned to 2-byte boundaries (leastmost
+ *   bit is zero)
+ */
+#if UINT64_MAX > UINTPTR_MAX
+typedef uint64_t isl_sioimath;
+#else
+typedef uintptr_t isl_sioimath;
+#endif
+
+/* The negation of the smallest possible number in int32_t, INT32_MIN
+ * (0x80000000u, -2147483648), cannot be represented in an int32_t, therefore
+ * every operation that may produce this value needs to special-case it.
+ * The operations are:
+ * abs(INT32_MIN)
+ * -INT32_MIN   (negation)
+ * -1 * INT32_MIN (multiplication)
+ * INT32_MIN/-1 (any division: divexact, fdiv, cdiv, tdiv)
+ * To avoid checking these cases, we exclude INT32_MIN from small
+ * representation.
+ */
+#define ISL_SIOIMATH_SMALL_MIN (-INT32_MAX)
+
+/* Largest possible number in small representation */
+#define ISL_SIOIMATH_SMALL_MAX INT32_MAX
+
+/* Used for function parameters the function modifies. */
+typedef isl_sioimath *isl_sioimath_ptr;
+
+/* Used for function parameters that are read-only. */
+typedef isl_sioimath isl_sioimath_src;
+
+/* Return whether the argument is stored in small representation.
+ */
+inline int isl_sioimath_is_small(isl_sioimath val)
+{
+	return val & 0x00000001;
+}
+
+/* Return whether the argument is stored in big representation.
+ */
+inline int isl_sioimath_is_big(isl_sioimath val)
+{
+	return !isl_sioimath_is_small(val);
+}
+
+/* Get the number of an isl_int in small representation. Result is undefined if
+ * val is not stored in that format.
+ */
+inline int32_t isl_sioimath_get_small(isl_sioimath val)
+{
+	return val >> 32;
+}
+
+/* Get the number of an in isl_int in big representation. Result is undefined if
+ * val is not stored in that format.
+ */
+inline mp_int isl_sioimath_get_big(isl_sioimath val)
+{
+	return (mp_int)(uintptr_t) val;
+}
+
+/* Return 1 if val is stored in small representation and store its value to
+ * small. We rely on the compiler to optimize the isl_sioimath_get_small such
+ * that the shift is moved into the branch that executes in case of small
+ * representation. If there is no such branch, then a single shift is still
+ * cheaper than introducing branching code.
+ */
+inline int isl_sioimath_decode_small(isl_sioimath val, int32_t *small)
+{
+	*small = isl_sioimath_get_small(val);
+	return isl_sioimath_is_small(val);
+}
+
+/* Return 1 if val is stored in big representation and store its value to big.
+ */
+inline int isl_sioimath_decode_big(isl_sioimath val, mp_int *big)
+{
+	*big = isl_sioimath_get_big(val);
+	return isl_sioimath_is_big(val);
+}
+
+/* Encode a small representation into an isl_int.
+ */
+inline isl_sioimath isl_sioimath_encode_small(int32_t val)
+{
+	return ((isl_sioimath) val) << 32 | 0x00000001;
+}
+
+/* Encode a big representation.
+ */
+inline isl_sioimath isl_sioimath_encode_big(mp_int val)
+{
+	return (isl_sioimath)(uintptr_t) val;
+}
+
+/* A common situation is to call an IMath function with at least one argument
+ * that is currently in small representation or an integer parameter, i.e. a big
+ * representation of the same number is required. Promoting the original
+ * argument comes with multiple problems, such as modifying a read-only
+ * argument, the responsibility of deallocation and the execution cost. Instead,
+ * we make a copy by 'faking' the IMath internal structure.
+ *
+ * We reserve the maximum number of required digits on the stack to avoid heap
+ * allocations.
+ *
+ * mp_digit can be uint32_t or uint16_t. This code must work for little and big
+ * endian digits. The structure for an uint64_t argument and 32-bit mp_digits is
+ * sketched below.
+ *
+ * |----------------------------|
+ *            uint64_t
+ *
+ * |-------------||-------------|
+ *    mp_digit        mp_digit
+ *    digits[1]       digits[0]
+ * Most sig digit  Least sig digit
+ */
+typedef struct {
+	mpz_t big;
+	mp_digit digits[(sizeof(uintmax_t) + sizeof(mp_digit) - 1) /
+	                sizeof(mp_digit)];
+} isl_sioimath_scratchspace_t;
+
+/* Convert a native integer to IMath's digit representation. A native integer
+ * might be big- or little endian, but IMath always stores the least significant
+ * digit in the lowest array indices.  memcpy therefore is not possible.
+ *
+ * We also have to consider that long and mp_digit can be of different sizes,
+ * depending on the compiler (LP64, LLP64) and IMath's USE_64BIT_WORDS. This
+ * macro should work for all of them.
+ *
+ * "used" is set to the number of written digits. It must be minimal (IMath
+ * checks zeroness using the used field), but always at least one.  Also note
+ * that the result of num>>(sizeof(num)*CHAR_BIT) is undefined.
+ */
+#define ISL_SIOIMATH_TO_DIGITS(num, digits, used)                              \
+	do {                                                                   \
+		int i = 0;                                                     \
+		do {                                                           \
+			(digits)[i] =                                          \
+			    ((num) >> (sizeof(mp_digit) * CHAR_BIT * i));      \
+			i += 1;                                                \
+			if (i >= (sizeof(num) + sizeof(mp_digit) - 1) /        \
+			             sizeof(mp_digit))                         \
+				break;                                         \
+			if (((num) >> (sizeof(mp_digit) * CHAR_BIT * i)) == 0) \
+				break;                                         \
+		} while (1);                                                   \
+		(used) = i;                                                    \
+	} while (0)
+
+inline void isl_siomath_uint32_to_digits(uint32_t num, mp_digit *digits,
+	mp_size *used)
+{
+	ISL_SIOIMATH_TO_DIGITS(num, digits, *used);
+}
+
+inline void isl_siomath_ulong_to_digits(unsigned long num, mp_digit *digits,
+	mp_size *used)
+{
+	ISL_SIOIMATH_TO_DIGITS(num, digits, *used);
+}
+
+inline void isl_siomath_uint64_to_digits(uint64_t num, mp_digit *digits,
+	mp_size *used)
+{
+	ISL_SIOIMATH_TO_DIGITS(num, digits, *used);
+}
+
+/* Get the IMath representation of an isl_int without modifying it.
+ * For the case it is not in big representation yet, pass some scratch space we
+ * can use to store the big representation in.
+ * In order to avoid requiring init and free on the scratch space, we directly
+ * modify the internal representation.
+ *
+ * The name derives from its indented use: getting the big representation of an
+ * input (src) argument.
+ */
+inline mp_int isl_sioimath_bigarg_src(isl_sioimath arg,
+	isl_sioimath_scratchspace_t *scratch)
+{
+	mp_int big;
+	int32_t small;
+	uint32_t num;
+
+	if (isl_sioimath_decode_big(arg, &big))
+		return big;
+
+	small = isl_sioimath_get_small(arg);
+	scratch->big.digits = scratch->digits;
+	scratch->big.alloc = ARRAY_SIZE(scratch->digits);
+	if (small >= 0) {
+		scratch->big.sign = MP_ZPOS;
+		num = small;
+	} else {
+		scratch->big.sign = MP_NEG;
+		num = -small;
+	}
+
+	isl_siomath_uint32_to_digits(num, scratch->digits, &scratch->big.used);
+	return &scratch->big;
+}
+
+/* Create a temporary IMath mp_int for a signed long.
+ */
+inline mp_int isl_sioimath_siarg_src(signed long arg,
+	isl_sioimath_scratchspace_t *scratch)
+{
+	unsigned long num;
+
+	scratch->big.digits = scratch->digits;
+	scratch->big.alloc = ARRAY_SIZE(scratch->digits);
+	if (arg >= 0) {
+		scratch->big.sign = MP_ZPOS;
+		num = arg;
+	} else {
+		scratch->big.sign = MP_NEG;
+		num = (arg == LONG_MIN) ? ((unsigned long) LONG_MAX) + 1 : -arg;
+	}
+
+	isl_siomath_ulong_to_digits(num, scratch->digits, &scratch->big.used);
+	return &scratch->big;
+}
+
+/* Create a temporary IMath mp_int for an int64_t.
+ */
+inline mp_int isl_sioimath_si64arg_src(int64_t arg,
+	isl_sioimath_scratchspace_t *scratch)
+{
+	uint64_t num;
+
+	scratch->big.digits = scratch->digits;
+	scratch->big.alloc = ARRAY_SIZE(scratch->digits);
+	if (arg >= 0) {
+		scratch->big.sign = MP_ZPOS;
+		num = arg;
+	} else {
+		scratch->big.sign = MP_NEG;
+		num = (arg == INT64_MIN) ? ((uint64_t) INT64_MAX) + 1 : -arg;
+	}
+
+	isl_siomath_uint64_to_digits(num, scratch->digits, &scratch->big.used);
+	return &scratch->big;
+}
+
+/* Create a temporary IMath mp_int for an unsigned long.
+ */
+inline mp_int isl_sioimath_uiarg_src(unsigned long arg,
+	isl_sioimath_scratchspace_t *scratch)
+{
+	scratch->big.digits = scratch->digits;
+	scratch->big.alloc = ARRAY_SIZE(scratch->digits);
+	scratch->big.sign = MP_ZPOS;
+
+	isl_siomath_ulong_to_digits(arg, scratch->digits, &scratch->big.used);
+	return &scratch->big;
+}
+
+/* Ensure big representation. Does not preserve the current number.
+ * Callers may use the fact that the value _is_ preserved if the presentation
+ * was big before.
+ */
+inline mp_int isl_sioimath_reinit_big(isl_sioimath_ptr ptr)
+{
+	if (isl_sioimath_is_small(*ptr))
+		*ptr = isl_sioimath_encode_big(mp_int_alloc());
+	return isl_sioimath_get_big(*ptr);
+}
+
+/* Set ptr to a number in small representation.
+ */
+inline void isl_sioimath_set_small(isl_sioimath_ptr ptr, int32_t val)
+{
+	if (isl_sioimath_is_big(*ptr))
+		mp_int_free(isl_sioimath_get_big(*ptr));
+	*ptr = isl_sioimath_encode_small(val);
+}
+
+/* Set ptr to val, choosing small representation if possible.
+ */
+inline void isl_sioimath_set_int32(isl_sioimath_ptr ptr, int32_t val)
+{
+	if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) {
+		isl_sioimath_set_small(ptr, val);
+		return;
+	}
+
+	mp_int_init_value(isl_sioimath_reinit_big(ptr), val);
+}
+
+/* Assign an int64_t number using small representation if possible.
+ */
+inline void isl_sioimath_set_int64(isl_sioimath_ptr ptr, int64_t val)
+{
+	if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) {
+		isl_sioimath_set_small(ptr, val);
+		return;
+	}
+
+	isl_sioimath_scratchspace_t scratch;
+	mp_int_copy(isl_sioimath_si64arg_src(val, &scratch),
+	    isl_sioimath_reinit_big(ptr));
+}
+
+/* Convert to big representation while preserving the current number.
+ */
+inline void isl_sioimath_promote(isl_sioimath_ptr dst)
+{
+	int32_t small;
+
+	if (isl_sioimath_is_big(*dst))
+		return;
+
+	small = isl_sioimath_get_small(*dst);
+	mp_int_set_value(isl_sioimath_reinit_big(dst), small);
+}
+
+/* Convert to small representation while preserving the current number. Does
+ * nothing if dst doesn't fit small representation.
+ */
+inline void isl_sioimath_try_demote(isl_sioimath_ptr dst)
+{
+	mp_small small;
+
+	if (isl_sioimath_is_small(*dst))
+		return;
+
+	if (mp_int_to_int(isl_sioimath_get_big(*dst), &small) != MP_OK)
+		return;
+
+	if (ISL_SIOIMATH_SMALL_MIN <= small && small <= ISL_SIOIMATH_SMALL_MAX)
+		isl_sioimath_set_small(dst, small);
+}
+
+/* Initialize an isl_int. The implicit value is 0 in small representation.
+ */
+inline void isl_sioimath_init(isl_sioimath_ptr dst)
+{
+	*dst = isl_sioimath_encode_small(0);
+}
+
+/* Free the resources taken by an isl_int.
+ */
+inline void isl_sioimath_clear(isl_sioimath_ptr dst)
+{
+	if (isl_sioimath_is_small(*dst))
+		return;
+
+	mp_int_free(isl_sioimath_get_big(*dst));
+}
+
+/* Copy the value of one isl_int to another.
+ */
+inline void isl_sioimath_set(isl_sioimath_ptr dst, isl_sioimath_src val)
+{
+	if (isl_sioimath_is_small(val)) {
+		isl_sioimath_set_small(dst, isl_sioimath_get_small(val));
+		return;
+	}
+
+	mp_int_copy(isl_sioimath_get_big(val), isl_sioimath_reinit_big(dst));
+}
+
+/* Store a signed long into an isl_int.
+ */
+inline void isl_sioimath_set_si(isl_sioimath_ptr dst, long val)
+{
+	if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) {
+		isl_sioimath_set_small(dst, val);
+		return;
+	}
+
+	mp_int_set_value(isl_sioimath_reinit_big(dst), val);
+}
+
+/* Store an unsigned long into an isl_int.
+ */
+inline void isl_sioimath_set_ui(isl_sioimath_ptr dst, unsigned long val)
+{
+	if (val <= ISL_SIOIMATH_SMALL_MAX) {
+		isl_sioimath_set_small(dst, val);
+		return;
+	}
+
+	mp_int_set_uvalue(isl_sioimath_reinit_big(dst), val);
+}
+
+/* Return whether a number can be represented by a signed long.
+ */
+inline int isl_sioimath_fits_slong(isl_sioimath_src val)
+{
+	mp_small dummy;
+
+	if (isl_sioimath_is_small(val))
+		return 1;
+
+	return mp_int_to_int(isl_sioimath_get_big(val), &dummy) == MP_OK;
+}
+
+/* Return a number as signed long. Result is undefined if the number cannot be
+ * represented as long.
+ */
+inline long isl_sioimath_get_si(isl_sioimath_src val)
+{
+	mp_small result;
+
+	if (isl_sioimath_is_small(val))
+		return isl_sioimath_get_small(val);
+
+	mp_int_to_int(isl_sioimath_get_big(val), &result);
+	return result;
+}
+
+/* Return whether a number can be represented as unsigned long.
+ */
+inline int isl_sioimath_fits_ulong(isl_sioimath_src val)
+{
+	mp_usmall dummy;
+
+	if (isl_sioimath_is_small(val))
+		return isl_sioimath_get_small(val) >= 0;
+
+	return mp_int_to_uint(isl_sioimath_get_big(val), &dummy) == MP_OK;
+}
+
+/* Return a number as unsigned long. Result is undefined if the number cannot be
+ * represented as unsigned long.
+ */
+inline unsigned long isl_sioimath_get_ui(isl_sioimath_src val)
+{
+	mp_usmall result;
+
+	if (isl_sioimath_is_small(val))
+		return isl_sioimath_get_small(val);
+
+	mp_int_to_uint(isl_sioimath_get_big(val), &result);
+	return result;
+}
+
+/* Return a number as floating point value.
+ */
+inline double isl_sioimath_get_d(isl_sioimath_src val)
+{
+	mp_int big;
+	double result = 0;
+	int i;
+
+	if (isl_sioimath_is_small(val))
+		return isl_sioimath_get_small(val);
+
+	big = isl_sioimath_get_big(val);
+	for (i = 0; i < big->used; ++i)
+		result = result * (double) ((uintmax_t) MP_DIGIT_MAX + 1) +
+		         (double) big->digits[i];
+
+	if (big->sign == MP_NEG)
+		result = -result;
+
+	return result;
+}
+
+/* Format a number as decimal string.
+ *
+ * The largest possible string from small representation is 12 characters
+ * ("-2147483647").
+ */
+inline char *isl_sioimath_get_str(isl_sioimath_src val)
+{
+	char *result;
+
+	if (isl_sioimath_is_small(val)) {
+		result = malloc(12);
+		snprintf(result, 12, "%" PRIi32, isl_sioimath_get_small(val));
+		return result;
+	}
+
+	return impz_get_str(NULL, 10, isl_sioimath_get_big(val));
+}
+
+/* Return the absolute value.
+ */
+inline void isl_sioimath_abs(isl_sioimath_ptr dst, isl_sioimath_src arg)
+{
+	if (isl_sioimath_is_small(arg)) {
+		isl_sioimath_set_small(dst, labs(isl_sioimath_get_small(arg)));
+		return;
+	}
+
+	mp_int_abs(isl_sioimath_get_big(arg), isl_sioimath_reinit_big(dst));
+}
+
+/* Return the negation of a number.
+ */
+inline void isl_sioimath_neg(isl_sioimath_ptr dst, isl_sioimath_src arg)
+{
+	if (isl_sioimath_is_small(arg)) {
+		isl_sioimath_set_small(dst, -isl_sioimath_get_small(arg));
+		return;
+	}
+
+	mp_int_neg(isl_sioimath_get_big(arg), isl_sioimath_reinit_big(dst));
+}
+
+/* Swap two isl_ints.
+ *
+ * isl_sioimath can be copied bytewise; nothing depends on its address. It can
+ * also be stored in a CPU register.
+ */
+inline void isl_sioimath_swap(isl_sioimath_ptr lhs, isl_sioimath_ptr rhs)
+{
+	isl_sioimath tmp = *lhs;
+	*lhs = *rhs;
+	*rhs = tmp;
+}
+
+/* Add an unsigned long to the number.
+ *
+ * On LP64 unsigned long exceeds the range of an int64_t, therefore we check in
+ * advance whether small representation possibly overflows.
+ */
+inline void isl_sioimath_add_ui(isl_sioimath_ptr dst, isl_sioimath lhs,
+	unsigned long rhs)
+{
+	int32_t smalllhs;
+	isl_sioimath_scratchspace_t lhsscratch;
+
+	if (isl_sioimath_decode_small(lhs, &smalllhs) &&
+	    (rhs <= (uint64_t) INT64_MAX - (uint64_t) ISL_SIOIMATH_SMALL_MAX)) {
+		isl_sioimath_set_int64(dst, (int64_t) smalllhs + rhs);
+		return;
+	}
+
+	impz_add_ui(isl_sioimath_reinit_big(dst),
+	    isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs);
+	isl_sioimath_try_demote(dst);
+}
+
+/* Subtract an unsigned long.
+ *
+ * On LP64 unsigned long exceeds the range of an int64_t.  If
+ * ISL_SIOIMATH_SMALL_MIN-rhs>=INT64_MIN we can do the calculation using int64_t
+ * without risking an overflow.
+ */
+inline void isl_sioimath_sub_ui(isl_sioimath_ptr dst, isl_sioimath lhs,
+				unsigned long rhs)
+{
+	int32_t smalllhs;
+	isl_sioimath_scratchspace_t lhsscratch;
+
+	if (isl_sioimath_decode_small(lhs, &smalllhs) &&
+	    (rhs < (uint64_t) INT64_MIN - (uint64_t) ISL_SIOIMATH_SMALL_MIN)) {
+		isl_sioimath_set_int64(dst, (int64_t) smalllhs - rhs);
+		return;
+	}
+
+	impz_sub_ui(isl_sioimath_reinit_big(dst),
+	    isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs);
+	isl_sioimath_try_demote(dst);
+}
+
+/* Sum of two isl_ints.
+ */
+inline void isl_sioimath_add(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs)
+{
+	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
+	int32_t smalllhs, smallrhs;
+
+	if (isl_sioimath_decode_small(lhs, &smalllhs) &&
+	    isl_sioimath_decode_small(rhs, &smallrhs)) {
+		isl_sioimath_set_int64(
+		    dst, (int64_t) smalllhs + (int64_t) smallrhs);
+		return;
+	}
+
+	mp_int_add(isl_sioimath_bigarg_src(lhs, &scratchlhs),
+	    isl_sioimath_bigarg_src(rhs, &scratchrhs),
+	    isl_sioimath_reinit_big(dst));
+	isl_sioimath_try_demote(dst);
+}
+
+/* Subtract two isl_ints.
+ */
+inline void isl_sioimath_sub(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs)
+{
+	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
+	int32_t smalllhs, smallrhs;
+
+	if (isl_sioimath_decode_small(lhs, &smalllhs) &&
+	    isl_sioimath_decode_small(rhs, &smallrhs)) {
+		isl_sioimath_set_int64(
+		    dst, (int64_t) smalllhs - (int64_t) smallrhs);
+		return;
+	}
+
+	mp_int_sub(isl_sioimath_bigarg_src(lhs, &scratchlhs),
+	    isl_sioimath_bigarg_src(rhs, &scratchrhs),
+	    isl_sioimath_reinit_big(dst));
+	isl_sioimath_try_demote(dst);
+}
+
+/* Multiply two isl_ints.
+ */
+inline void isl_sioimath_mul(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs)
+{
+	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
+	int32_t smalllhs, smallrhs;
+
+	if (isl_sioimath_decode_small(lhs, &smalllhs) &&
+	    isl_sioimath_decode_small(rhs, &smallrhs)) {
+		isl_sioimath_set_int64(
+		    dst, (int64_t) smalllhs * (int64_t) smallrhs);
+		return;
+	}
+
+	mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs),
+	    isl_sioimath_bigarg_src(rhs, &scratchrhs),
+	    isl_sioimath_reinit_big(dst));
+	isl_sioimath_try_demote(dst);
+}
+
+/* Shift lhs by rhs bits to the left and store the result in dst. Effectively,
+ * this operation computes 'lhs * 2^rhs'.
+ */
+inline void isl_sioimath_mul_2exp(isl_sioimath_ptr dst, isl_sioimath lhs,
+	unsigned long rhs)
+{
+	isl_sioimath_scratchspace_t scratchlhs;
+	int32_t smalllhs;
+
+	if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs <= 32ul)) {
+		isl_sioimath_set_int64(dst, ((int64_t) smalllhs) << rhs);
+		return;
+	}
+
+	mp_int_mul_pow2(isl_sioimath_bigarg_src(lhs, &scratchlhs), rhs,
+	    isl_sioimath_reinit_big(dst));
+}
+
+/* Multiply an isl_int and a signed long.
+ */
+inline void isl_sioimath_mul_si(isl_sioimath_ptr dst, isl_sioimath lhs,
+	signed long rhs)
+{
+	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
+	int32_t smalllhs;
+
+	if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs > LONG_MIN) &&
+	    (labs(rhs) <= UINT32_MAX)) {
+		isl_sioimath_set_int64(dst, (int64_t) smalllhs * (int64_t) rhs);
+		return;
+	}
+
+	mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs),
+	    isl_sioimath_siarg_src(rhs, &scratchrhs),
+	    isl_sioimath_reinit_big(dst));
+	isl_sioimath_try_demote(dst);
+}
+
+/* Multiply an isl_int and an unsigned long.
+ */
+inline void isl_sioimath_mul_ui(isl_sioimath_ptr dst, isl_sioimath lhs,
+	unsigned long rhs)
+{
+	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
+	int32_t smalllhs;
+
+	if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs <= UINT32_MAX)) {
+		isl_sioimath_set_int64(dst, (int64_t) smalllhs * (int64_t) rhs);
+		return;
+	}
+
+	mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs),
+	    isl_sioimath_uiarg_src(rhs, &scratchrhs),
+	    isl_sioimath_reinit_big(dst));
+	isl_sioimath_try_demote(dst);
+}
+
+/* Compute the power of an isl_int to an unsigned long.
+ * Always let IMath do it; the result is unlikely to be small except in some
+ * special cases.
+ * Note: 0^0 == 1
+ */
+inline void isl_sioimath_pow_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	unsigned long rhs)
+{
+	isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
+	int32_t smalllhs;
+
+	switch (rhs) {
+	case 0:
+		isl_sioimath_set_small(dst, 1);
+		return;
+	case 1:
+		isl_sioimath_set(dst, lhs);
+		return;
+	case 2:
+		isl_sioimath_mul(dst, lhs, lhs);
+		return;
+	}
+
+	if (isl_sioimath_decode_small(lhs, &smalllhs)) {
+		switch (smalllhs) {
+		case 0:
+			isl_sioimath_set_small(dst, 0);
+			return;
+		case 1:
+			isl_sioimath_set_small(dst, 1);
+			return;
+		case 2:
+			isl_sioimath_set_small(dst, 1);
+			isl_sioimath_mul_2exp(dst, *dst, rhs);
+			return;
+		default:
+			if ((MP_SMALL_MIN <= rhs) && (rhs <= MP_SMALL_MAX)) {
+				mp_int_expt_value(smalllhs, rhs,
+				    isl_sioimath_reinit_big(dst));
+				isl_sioimath_try_demote(dst);
+				return;
+			}
+		}
+	}
+
+	mp_int_expt_full(isl_sioimath_bigarg_src(lhs, &scratchlhs),
+	    isl_sioimath_uiarg_src(rhs, &scratchrhs),
+	    isl_sioimath_reinit_big(dst));
+	isl_sioimath_try_demote(dst);
+}
+
+/* Fused multiply-add.
+ */
+inline void isl_sioimath_addmul(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs)
+{
+	isl_sioimath tmp;
+	isl_sioimath_init(&tmp);
+	isl_sioimath_mul(&tmp, lhs, rhs);
+	isl_sioimath_add(dst, *dst, tmp);
+	isl_sioimath_clear(&tmp);
+}
+
+/* Fused multiply-add with an unsigned long.
+ */
+inline void isl_sioimath_addmul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	unsigned long rhs)
+{
+	isl_sioimath tmp;
+	isl_sioimath_init(&tmp);
+	isl_sioimath_mul_ui(&tmp, lhs, rhs);
+	isl_sioimath_add(dst, *dst, tmp);
+	isl_sioimath_clear(&tmp);
+}
+
+/* Fused multiply-subtract.
+ */
+inline void isl_sioimath_submul(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs)
+{
+	isl_sioimath tmp;
+	isl_sioimath_init(&tmp);
+	isl_sioimath_mul(&tmp, lhs, rhs);
+	isl_sioimath_sub(dst, *dst, tmp);
+	isl_sioimath_clear(&tmp);
+}
+
+/* Fused multiply-add with an unsigned long.
+ */
+inline void isl_sioimath_submul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	unsigned long rhs)
+{
+	isl_sioimath tmp;
+	isl_sioimath_init(&tmp);
+	isl_sioimath_mul_ui(&tmp, lhs, rhs);
+	isl_sioimath_sub(dst, *dst, tmp);
+	isl_sioimath_clear(&tmp);
+}
+
+void isl_sioimath_gcd(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+		      isl_sioimath_src rhs);
+void isl_sioimath_lcm(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+		      isl_sioimath_src rhs);
+
+/* Divide lhs by rhs, rounding to zero (Truncate).
+ */
+inline void isl_sioimath_tdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs)
+{
+	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
+	int32_t lhssmall, rhssmall;
+
+	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
+	    isl_sioimath_decode_small(rhs, &rhssmall)) {
+		isl_sioimath_set_small(dst, lhssmall / rhssmall);
+		return;
+	}
+
+	mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch),
+	    isl_sioimath_bigarg_src(rhs, &rhsscratch),
+	    isl_sioimath_reinit_big(dst), NULL);
+	isl_sioimath_try_demote(dst);
+	return;
+}
+
+/* Divide lhs by an unsigned long rhs, rounding to zero (Truncate).
+ */
+inline void isl_sioimath_tdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	unsigned long rhs)
+{
+	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
+	int32_t lhssmall;
+
+	if (isl_sioimath_is_small(lhs) && (rhs <= (unsigned long) INT32_MAX)) {
+		lhssmall = isl_sioimath_get_small(lhs);
+		isl_sioimath_set_small(dst, lhssmall / (int32_t) rhs);
+		return;
+	}
+
+	if (rhs <= MP_SMALL_MAX) {
+		mp_int_div_value(isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs,
+		    isl_sioimath_reinit_big(dst), NULL);
+		isl_sioimath_try_demote(dst);
+		return;
+	}
+
+	mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch),
+	    isl_sioimath_uiarg_src(rhs, &rhsscratch),
+	    isl_sioimath_reinit_big(dst), NULL);
+	isl_sioimath_try_demote(dst);
+}
+
+/* Divide lhs by rhs, rounding to positive infinity (Ceil).
+ */
+inline void isl_sioimath_cdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs)
+{
+	int32_t lhssmall, rhssmall;
+	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
+	int32_t q;
+
+	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
+	    isl_sioimath_decode_small(rhs, &rhssmall)) {
+		if ((lhssmall >= 0) && (rhssmall >= 0))
+			q = ((int64_t) lhssmall + (int64_t) rhssmall - 1) /
+			    rhssmall;
+		else if ((lhssmall < 0) && (rhssmall < 0))
+			q = ((int64_t) lhssmall + (int64_t) rhssmall + 1) /
+			    rhssmall;
+		else
+			q = lhssmall / rhssmall;
+		isl_sioimath_set_small(dst, q);
+		return;
+	}
+
+	impz_cdiv_q(isl_sioimath_reinit_big(dst),
+	    isl_sioimath_bigarg_src(lhs, &lhsscratch),
+	    isl_sioimath_bigarg_src(rhs, &rhsscratch));
+	isl_sioimath_try_demote(dst);
+}
+
+/* Compute the division of lhs by a rhs of type unsigned long, rounding towards
+ * positive infinity (Ceil).
+ */
+inline void isl_sioimath_cdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	unsigned long rhs)
+{
+	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
+	int32_t lhssmall, q;
+
+	if (isl_sioimath_decode_small(lhs, &lhssmall) && (rhs <= INT32_MAX)) {
+		if (lhssmall >= 0)
+			q = ((int64_t) lhssmall + ((int64_t) rhs - 1)) /
+			    (int64_t) rhs;
+		else
+			q = lhssmall / (int32_t) rhs;
+		isl_sioimath_set_small(dst, q);
+		return;
+	}
+
+	impz_cdiv_q(isl_sioimath_reinit_big(dst),
+	    isl_sioimath_bigarg_src(lhs, &lhsscratch),
+	    isl_sioimath_uiarg_src(rhs, &rhsscratch));
+	isl_sioimath_try_demote(dst);
+}
+
+/* Divide lhs by rhs, rounding to negative infinity (Floor).
+ */
+inline void isl_sioimath_fdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs)
+{
+	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
+	int32_t lhssmall, rhssmall;
+	int32_t q;
+
+	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
+	    isl_sioimath_decode_small(rhs, &rhssmall)) {
+		if ((lhssmall < 0) && (rhssmall >= 0))
+			q = ((int64_t) lhssmall - ((int64_t) rhssmall - 1)) /
+			    rhssmall;
+		else if ((lhssmall >= 0) && (rhssmall < 0))
+			q = ((int64_t) lhssmall - ((int64_t) rhssmall + 1)) /
+			    rhssmall;
+		else
+			q = lhssmall / rhssmall;
+		isl_sioimath_set_small(dst, q);
+		return;
+	}
+
+	impz_fdiv_q(isl_sioimath_reinit_big(dst),
+	    isl_sioimath_bigarg_src(lhs, &lhsscratch),
+	    isl_sioimath_bigarg_src(rhs, &rhsscratch));
+	isl_sioimath_try_demote(dst);
+}
+
+/* Compute the division of lhs by a rhs of type unsigned long, rounding towards
+ * negative infinity (Floor).
+ */
+inline void isl_sioimath_fdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	unsigned long rhs)
+{
+	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
+	int32_t lhssmall, q;
+
+	if (isl_sioimath_decode_small(lhs, &lhssmall) && (rhs <= INT32_MAX)) {
+		if (lhssmall >= 0)
+			q = (uint32_t) lhssmall / rhs;
+		else
+			q = ((int64_t) lhssmall - ((int64_t) rhs - 1)) /
+			    (int64_t) rhs;
+		isl_sioimath_set_small(dst, q);
+		return;
+	}
+
+	impz_fdiv_q(isl_sioimath_reinit_big(dst),
+	    isl_sioimath_bigarg_src(lhs, &lhsscratch),
+	    isl_sioimath_uiarg_src(rhs, &rhsscratch));
+	isl_sioimath_try_demote(dst);
+}
+
+/* Get the remainder of: lhs divided by rhs rounded towards negative infinite
+ * (Floor).
+ */
+inline void isl_sioimath_fdiv_r(isl_sioimath_ptr dst, isl_sioimath_src lhs,
+	isl_sioimath_src rhs)
+{
+	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
+	int64_t lhssmall, rhssmall;
+	int32_t r;
+
+	if (isl_sioimath_is_small(lhs) && isl_sioimath_is_small(rhs)) {
+		lhssmall = isl_sioimath_get_small(lhs);
+		rhssmall = isl_sioimath_get_small(rhs);
+		r = (rhssmall + lhssmall % rhssmall) % rhssmall;
+		isl_sioimath_set_small(dst, r);
+		return;
+	}
+
+	impz_fdiv_r(isl_sioimath_reinit_big(dst),
+	    isl_sioimath_bigarg_src(lhs, &lhsscratch),
+	    isl_sioimath_bigarg_src(rhs, &rhsscratch));
+	isl_sioimath_try_demote(dst);
+}
+
+void isl_sioimath_read(isl_sioimath_ptr dst, const char *str);
+
+/* Return:
+ *   +1 for a positive number
+ *   -1 for a negative number
+ *    0 if the number is zero
+ */
+inline int isl_sioimath_sgn(isl_sioimath_src arg)
+{
+	int32_t small;
+
+	if (isl_sioimath_decode_small(arg, &small))
+		return (small > 0) - (small < 0);
+
+	return mp_int_compare_zero(isl_sioimath_get_big(arg));
+}
+
+/* Return:
+ *   +1 if lhs > rhs
+ *   -1 if lhs < rhs
+ *    0 if lhs = rhs
+ */
+inline int isl_sioimath_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs)
+{
+	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
+	int32_t lhssmall, rhssmall;
+
+	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
+	    isl_sioimath_decode_small(rhs, &rhssmall))
+		return (lhssmall > rhssmall) - (lhssmall < rhssmall);
+
+	if (isl_sioimath_decode_small(rhs, &rhssmall))
+		return mp_int_compare_value(
+		    isl_sioimath_bigarg_src(lhs, &lhsscratch), rhssmall);
+
+	if (isl_sioimath_decode_small(lhs, &lhssmall))
+		return -mp_int_compare_value(
+		           isl_sioimath_bigarg_src(rhs, &rhsscratch), lhssmall);
+
+	return mp_int_compare(
+	    isl_sioimath_get_big(lhs), isl_sioimath_get_big(rhs));
+}
+
+/* As isl_sioimath_cmp, but with signed long rhs.
+ */
+inline int isl_sioimath_cmp_si(isl_sioimath_src lhs, signed long rhs)
+{
+	int32_t lhssmall;
+
+	if (isl_sioimath_decode_small(lhs, &lhssmall))
+		return (lhssmall > rhs) - (lhssmall < rhs);
+
+	return mp_int_compare_value(isl_sioimath_get_big(lhs), rhs);
+}
+
+/* Return:
+ *   +1 if |lhs| > |rhs|
+ *   -1 if |lhs| < |rhs|
+ *    0 if |lhs| = |rhs|
+ */
+inline int isl_sioimath_abs_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs)
+{
+	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
+	int32_t lhssmall, rhssmall;
+
+	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
+	    isl_sioimath_decode_small(rhs, &rhssmall)) {
+		lhssmall = labs(lhssmall);
+		rhssmall = labs(rhssmall);
+		return (lhssmall > rhssmall) - (lhssmall < rhssmall);
+	}
+
+	return mp_int_compare_unsigned(
+	    isl_sioimath_bigarg_src(lhs, &lhsscratch),
+	    isl_sioimath_bigarg_src(rhs, &rhsscratch));
+}
+
+/* Return whether lhs is divisible by rhs.
+ * In particular, can rhs be multiplied by some integer to result in lhs?
+ * If rhs is zero, then this means lhs has to be zero too.
+ */
+inline int isl_sioimath_is_divisible_by(isl_sioimath_src lhs,
+					isl_sioimath_src rhs)
+{
+	isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
+	int32_t lhssmall, rhssmall;
+	mpz_t rem;
+	int cmp;
+
+	if (isl_sioimath_sgn(rhs) == 0)
+		return isl_sioimath_sgn(lhs) == 0;
+
+	if (isl_sioimath_decode_small(lhs, &lhssmall) &&
+	    isl_sioimath_decode_small(rhs, &rhssmall))
+		return lhssmall % rhssmall == 0;
+
+	if (isl_sioimath_decode_small(rhs, &rhssmall))
+		return mp_int_divisible_value(
+		    isl_sioimath_bigarg_src(lhs, &lhsscratch), rhssmall);
+
+	mp_int_init(&rem);
+	mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch),
+	    isl_sioimath_bigarg_src(rhs, &rhsscratch), NULL, &rem);
+	cmp = mp_int_compare_zero(&rem);
+	mp_int_clear(&rem);
+	return cmp == 0;
+}
+
+/* Return a hash code of an isl_sioimath.
+ * The hash code for a number in small and big representation must be identical
+ * on the same machine because small representation if not obligatory if fits.
+ */
+inline uint32_t isl_sioimath_hash(isl_sioimath_src arg, uint32_t hash)
+{
+	int32_t small;
+	int i;
+	uint32_t num;
+	mp_digit digits[(sizeof(uint32_t) + sizeof(mp_digit) - 1) /
+	                sizeof(mp_digit)];
+	mp_size used;
+	const unsigned char *digitdata = (const unsigned char *) &digits;
+
+	if (isl_sioimath_decode_small(arg, &small)) {
+		if (small < 0)
+			isl_hash_byte(hash, 0xFF);
+		num = labs(small);
+
+		isl_siomath_uint32_to_digits(num, digits, &used);
+		for (i = 0; i < used * sizeof(mp_digit); i += 1)
+			isl_hash_byte(hash, digitdata[i]);
+		return hash;
+	}
+
+	return isl_imath_hash(isl_sioimath_get_big(arg), hash);
+}
+
+/* Return the number of digits in a number of the given base or more, i.e. the
+ * string length without sign and null terminator.
+ *
+ * Current implementation for small representation returns the maximal number
+ * of binary digits in that representation, which can be much larger than the
+ * smallest possible solution.
+ */
+inline size_t isl_sioimath_sizeinbase(isl_sioimath_src arg, int base)
+{
+	int32_t small;
+
+	if (isl_sioimath_decode_small(arg, &small))
+		return sizeof(int32_t) * CHAR_BIT - 1;
+
+	return impz_sizeinbase(isl_sioimath_get_big(arg), base);
+}
+
+void isl_sioimath_print(FILE *out, isl_sioimath_src i, int width);
+void isl_sioimath_dump(isl_sioimath_src arg);
+
+typedef isl_sioimath isl_int[1];
+#define isl_int_init(i)			isl_sioimath_init((i))
+#define isl_int_clear(i)		isl_sioimath_clear((i))
+
+#define isl_int_set(r, i)		isl_sioimath_set((r), *(i))
+#define isl_int_set_si(r, i)		isl_sioimath_set_si((r), i)
+#define isl_int_set_ui(r, i)		isl_sioimath_set_ui((r), i)
+#define isl_int_fits_slong(r)		isl_sioimath_fits_slong(*(r))
+#define isl_int_get_si(r)		isl_sioimath_get_si(*(r))
+#define isl_int_fits_ulong(r)		isl_sioimath_fits_ulong(*(r))
+#define isl_int_get_ui(r)		isl_sioimath_get_ui(*(r))
+#define isl_int_get_d(r)		isl_sioimath_get_d(*(r))
+#define isl_int_get_str(r)		isl_sioimath_get_str(*(r))
+#define isl_int_abs(r, i)		isl_sioimath_abs((r), *(i))
+#define isl_int_neg(r, i)		isl_sioimath_neg((r), *(i))
+#define isl_int_swap(i, j)		isl_sioimath_swap((i), (j))
+#define isl_int_swap_or_set(i, j)	isl_sioimath_swap((i), (j))
+#define isl_int_add_ui(r, i, j)		isl_sioimath_add_ui((r), *(i), j)
+#define isl_int_sub_ui(r, i, j)		isl_sioimath_sub_ui((r), *(i), j)
+
+#define isl_int_add(r, i, j)		isl_sioimath_add((r), *(i), *(j))
+#define isl_int_sub(r, i, j)		isl_sioimath_sub((r), *(i), *(j))
+#define isl_int_mul(r, i, j)		isl_sioimath_mul((r), *(i), *(j))
+#define isl_int_mul_2exp(r, i, j)	isl_sioimath_mul_2exp((r), *(i), j)
+#define isl_int_mul_si(r, i, j)		isl_sioimath_mul_si((r), *(i), j)
+#define isl_int_mul_ui(r, i, j)		isl_sioimath_mul_ui((r), *(i), j)
+#define isl_int_pow_ui(r, i, j)		isl_sioimath_pow_ui((r), *(i), j)
+#define isl_int_addmul(r, i, j)		isl_sioimath_addmul((r), *(i), *(j))
+#define isl_int_addmul_ui(r, i, j)	isl_sioimath_addmul_ui((r), *(i), j)
+#define isl_int_submul(r, i, j)		isl_sioimath_submul((r), *(i), *(j))
+#define isl_int_submul_ui(r, i, j)	isl_sioimath_submul_ui((r), *(i), j)
+
+#define isl_int_gcd(r, i, j)		isl_sioimath_gcd((r), *(i), *(j))
+#define isl_int_lcm(r, i, j)		isl_sioimath_lcm((r), *(i), *(j))
+#define isl_int_divexact(r, i, j)	isl_sioimath_tdiv_q((r), *(i), *(j))
+#define isl_int_divexact_ui(r, i, j)	isl_sioimath_tdiv_q_ui((r), *(i), j)
+#define isl_int_tdiv_q(r, i, j)		isl_sioimath_tdiv_q((r), *(i), *(j))
+#define isl_int_cdiv_q(r, i, j)		isl_sioimath_cdiv_q((r), *(i), *(j))
+#define isl_int_cdiv_q_ui(r, i, j)	isl_sioimath_cdiv_q_ui((r), *(i), j)
+#define isl_int_fdiv_q(r, i, j)		isl_sioimath_fdiv_q((r), *(i), *(j))
+#define isl_int_fdiv_r(r, i, j)		isl_sioimath_fdiv_r((r), *(i), *(j))
+#define isl_int_fdiv_q_ui(r, i, j)	isl_sioimath_fdiv_q_ui((r), *(i), j)
+
+#define isl_int_read(r, s)		isl_sioimath_read((r), s)
+#define isl_int_sgn(i)			isl_sioimath_sgn(*(i))
+#define isl_int_cmp(i, j)		isl_sioimath_cmp(*(i), *(j))
+#define isl_int_cmp_si(i, si)		isl_sioimath_cmp_si(*(i), si)
+#define isl_int_eq(i, j)		(isl_sioimath_cmp(*(i), *(j)) == 0)
+#define isl_int_ne(i, j)		(isl_sioimath_cmp(*(i), *(j)) != 0)
+#define isl_int_lt(i, j)		(isl_sioimath_cmp(*(i), *(j)) < 0)
+#define isl_int_le(i, j)		(isl_sioimath_cmp(*(i), *(j)) <= 0)
+#define isl_int_gt(i, j)		(isl_sioimath_cmp(*(i), *(j)) > 0)
+#define isl_int_ge(i, j)		(isl_sioimath_cmp(*(i), *(j)) >= 0)
+#define isl_int_abs_cmp(i, j)		isl_sioimath_abs_cmp(*(i), *(j))
+#define isl_int_abs_eq(i, j)		(isl_sioimath_abs_cmp(*(i), *(j)) == 0)
+#define isl_int_abs_ne(i, j)		(isl_sioimath_abs_cmp(*(i), *(j)) != 0)
+#define isl_int_abs_lt(i, j)		(isl_sioimath_abs_cmp(*(i), *(j)) < 0)
+#define isl_int_abs_gt(i, j)		(isl_sioimath_abs_cmp(*(i), *(j)) > 0)
+#define isl_int_abs_ge(i, j)		(isl_sioimath_abs_cmp(*(i), *(j)) >= 0)
+#define isl_int_is_divisible_by(i, j)	isl_sioimath_is_divisible_by(*(i), *(j))
+
+#define isl_int_hash(v, h)		isl_sioimath_hash(*(v), h)
+#define isl_int_free_str(s)		free(s)
+#define isl_int_print(out, i, width)	isl_sioimath_print(out, *(i), width)
+
+#endif /* ISL_INT_SIOIMATH_H */
diff --git a/final/lib/External/isl/isl_list_templ.c b/final/lib/External/isl/isl_list_templ.c
new file mode 100644
index 0000000..7d0c544
--- /dev/null
+++ b/final/lib/External/isl/isl_list_templ.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2011      INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ * Copyright 2017      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl_sort.h>
+#include <isl_tarjan.h>
+
+#define xCAT(A,B) A ## B
+#define CAT(A,B) xCAT(A,B)
+#undef EL
+#define EL CAT(isl_,BASE)
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xLIST(EL) EL ## _list
+#define LIST(EL) xLIST(EL)
+#define xS(TYPE,NAME) struct TYPE ## _ ## NAME
+#define S(TYPE,NAME) xS(TYPE,NAME)
+
+isl_ctx *FN(LIST(EL),get_ctx)(__isl_keep LIST(EL) *list)
+{
+	return list ? list->ctx : NULL;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),alloc)(isl_ctx *ctx, int n)
+{
+	LIST(EL) *list;
+
+	if (n < 0)
+		isl_die(ctx, isl_error_invalid,
+			"cannot create list of negative length",
+			return NULL);
+	list = isl_alloc(ctx, LIST(EL),
+			 sizeof(LIST(EL)) + (n - 1) * sizeof(struct EL *));
+	if (!list)
+		return NULL;
+
+	list->ctx = ctx;
+	isl_ctx_ref(ctx);
+	list->ref = 1;
+	list->size = n;
+	list->n = 0;
+	return list;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),copy)(__isl_keep LIST(EL) *list)
+{
+	if (!list)
+		return NULL;
+
+	list->ref++;
+	return list;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),dup)(__isl_keep LIST(EL) *list)
+{
+	int i;
+	LIST(EL) *dup;
+
+	if (!list)
+		return NULL;
+
+	dup = FN(LIST(EL),alloc)(FN(LIST(EL),get_ctx)(list), list->n);
+	if (!dup)
+		return NULL;
+	for (i = 0; i < list->n; ++i)
+		dup = FN(LIST(EL),add)(dup, FN(EL,copy)(list->p[i]));
+	return dup;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),cow)(__isl_take LIST(EL) *list)
+{
+	if (!list)
+		return NULL;
+
+	if (list->ref == 1)
+		return list;
+	list->ref--;
+	return FN(LIST(EL),dup)(list);
+}
+
+/* Make sure "list" has room for at least "n" more pieces.
+ * Always return a list with a single reference.
+ *
+ * If there is only one reference to list, we extend it in place.
+ * Otherwise, we create a new LIST(EL) and copy the elements.
+ */
+static __isl_give LIST(EL) *FN(LIST(EL),grow)(__isl_take LIST(EL) *list, int n)
+{
+	isl_ctx *ctx;
+	int i, new_size;
+	LIST(EL) *res;
+
+	if (!list)
+		return NULL;
+	if (list->ref == 1 && list->n + n <= list->size)
+		return list;
+
+	ctx = FN(LIST(EL),get_ctx)(list);
+	new_size = ((list->n + n + 1) * 3) / 2;
+	if (list->ref == 1) {
+		res = isl_realloc(ctx, list, LIST(EL),
+			    sizeof(LIST(EL)) + (new_size - 1) * sizeof(EL *));
+		if (!res)
+			return FN(LIST(EL),free)(list);
+		res->size = new_size;
+		return res;
+	}
+
+	if (list->n + n <= list->size && list->size < new_size)
+		new_size = list->size;
+
+	res = FN(LIST(EL),alloc)(ctx, new_size);
+	if (!res)
+		return FN(LIST(EL),free)(list);
+
+	for (i = 0; i < list->n; ++i)
+		res = FN(LIST(EL),add)(res, FN(EL,copy)(list->p[i]));
+
+	FN(LIST(EL),free)(list);
+	return res;
+}
+
+/* Check that "index" is a valid position in "list".
+ */
+static isl_stat FN(LIST(EL),check_index)(__isl_keep LIST(EL) *list, int index)
+{
+	if (!list)
+		return isl_stat_error;
+	if (index < 0 || index >= list->n)
+		isl_die(FN(LIST(EL),get_ctx)(list), isl_error_invalid,
+			"index out of bounds", return isl_stat_error);
+	return isl_stat_ok;
+}
+
+__isl_give LIST(EL) *FN(LIST(EL),add)(__isl_take LIST(EL) *list,
+	__isl_take struct EL *el)
+{
+	list = FN(LIST(EL),grow)(list, 1);
+	if (!list || !el)
+		goto error;
+	list->p[list->n] = el;
+	list->n++;
+	return list;
+error:
+	FN(EL,free)(el);
+	FN(LIST(EL),free)(list);
+	return NULL;
+}
+
+/* Remove the "n" elements starting at "first" from "list".
+ */
+__isl_give LIST(EL) *FN(LIST(EL),drop)(__isl_take LIST(EL) *list,
+	unsigned first, unsigned n)
+{
+	int i;
+
+	if (!list)
+		return NULL;
+	if (first + n > list->n || first + n < first)
+		isl_die(list->ctx, isl_error_invalid,
+			"index out of bounds", return FN(LIST(EL),free)(list));
+	if (n == 0)
+		return list;
+	list = FN(LIST(EL),cow)(list);
+	if (!list)
+		return NULL;
+	for (i = 0; i < n; ++i)
+		FN(EL,free)(list->p[first + i]);
+	for (i = first; i + n < list->n; ++i)
+		list->p[i] = list->p[i + n];
+	list->n -= n;
+	return list;
+}
+
+/* Insert "el" at position "pos" in "list".
+ *
+ * If there is only one reference to "list" and if it already has space
+ * for one extra element, we insert it directly into "list".
+ * Otherwise, we create a new list consisting of "el" and copied
+ * elements from "list".
+ */
+__isl_give LIST(EL) *FN(LIST(EL),insert)(__isl_take LIST(EL) *list,
+	unsigned pos, __isl_take struct EL *el)
+{
+	int i;
+	isl_ctx *ctx;
+	LIST(EL) *res;
+
+	if (!list || !el)
+		goto error;
+	ctx = FN(LIST(EL),get_ctx)(list);
+	if (pos > list->n)
+		isl_die(ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+
+	if (list->ref == 1 && list->size > list->n) {
+		for (i = list->n; i > pos; --i)
+			list->p[i] = list->p[i - 1];
+		list->n++;
+		list->p[pos] = el;
+		return list;
+	}
+
+	res = FN(LIST(EL),alloc)(ctx, list->n + 1);
+	for (i = 0; i < pos; ++i)
+		res = FN(LIST(EL),add)(res, FN(EL,copy)(list->p[i]));
+	res = FN(LIST(EL),add)(res, el);
+	for (i = pos; i < list->n; ++i)
+		res = FN(LIST(EL),add)(res, FN(EL,copy)(list->p[i]));
+	FN(LIST(EL),free)(list);
+
+	return res;
+error:
+	FN(EL,free)(el);
+	FN(LIST(EL),free)(list);
+	return NULL;
+}
+
+__isl_null LIST(EL) *FN(LIST(EL),free)(__isl_take LIST(EL) *list)
+{
+	int i;
+
+	if (!list)
+		return NULL;
+
+	if (--list->ref > 0)
+		return NULL;
+
+	isl_ctx_deref(list->ctx);
+	for (i = 0; i < list->n; ++i)
+		FN(EL,free)(list->p[i]);
+	free(list);
+
+	return NULL;
+}
+
+int FN(FN(LIST(EL),n),BASE)(__isl_keep LIST(EL) *list)
+{
+	return list ? list->n : 0;
+}
+
+__isl_give EL *FN(FN(LIST(EL),get),BASE)(__isl_keep LIST(EL) *list, int index)
+{
+	if (FN(LIST(EL),check_index)(list, index) < 0)
+		return NULL;
+	return FN(EL,copy)(list->p[index]);
+}
+
+/* Replace the element at position "index" in "list" by "el".
+ */
+__isl_give LIST(EL) *FN(FN(LIST(EL),set),BASE)(__isl_take LIST(EL) *list,
+	int index, __isl_take EL *el)
+{
+	if (!list || !el)
+		goto error;
+	if (FN(LIST(EL),check_index)(list, index) < 0)
+		goto error;
+	if (list->p[index] == el) {
+		FN(EL,free)(el);
+		return list;
+	}
+	list = FN(LIST(EL),cow)(list);
+	if (!list)
+		goto error;
+	FN(EL,free)(list->p[index]);
+	list->p[index] = el;
+	return list;
+error:
+	FN(EL,free)(el);
+	FN(LIST(EL),free)(list);
+	return NULL;
+}
+
+/* Return the element at position "index" of "list".
+ * This may be either a copy or the element itself
+ * if there is only one reference to "list".
+ * This allows the element to be modified inplace
+ * if both the list and the element have only a single reference.
+ * The caller is not allowed to modify "list" between
+ * this call to isl_list_*_take_* and a subsequent call
+ * to isl_list_*_restore_*.
+ * The only exception is that isl_list_*_free can be called instead.
+ */
+static __isl_give EL *FN(FN(LIST(EL),take),BASE)(__isl_keep LIST(EL) *list,
+	int index)
+{
+	EL *el;
+
+	if (FN(LIST(EL),check_index)(list, index) < 0)
+		return NULL;
+	if (list->ref != 1)
+		return FN(FN(LIST(EL),get),BASE)(list, index);
+	el = list->p[index];
+	list->p[index] = NULL;
+	return el;
+}
+
+/* Set the element at position "index" of "list" to "el",
+ * where the position may be empty due to a previous call
+ * to isl_list_*_take_*.
+ */
+static __isl_give LIST(EL) *FN(FN(LIST(EL),restore),BASE)(
+	__isl_take LIST(EL) *list, int index, __isl_take EL *el)
+{
+	return FN(FN(LIST(EL),set),BASE)(list, index, el);
+}
+
+isl_stat FN(LIST(EL),foreach)(__isl_keep LIST(EL) *list,
+	isl_stat (*fn)(__isl_take EL *el, void *user), void *user)
+{
+	int i;
+
+	if (!list)
+		return isl_stat_error;
+
+	for (i = 0; i < list->n; ++i) {
+		EL *el = FN(EL,copy)(list->p[i]);
+		if (!el)
+			return isl_stat_error;
+		if (fn(el, user) < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Replace each element in "list" by the result of calling "fn"
+ * on the element.
+ */
+__isl_give LIST(EL) *FN(LIST(EL),map)(__isl_keep LIST(EL) *list,
+	__isl_give EL *(*fn)(__isl_take EL *el, void *user), void *user)
+{
+	int i, n;
+
+	if (!list)
+		return NULL;
+
+	n = list->n;
+	for (i = 0; i < n; ++i) {
+		EL *el = FN(FN(LIST(EL),take),BASE)(list, i);
+		if (!el)
+			return FN(LIST(EL),free)(list);
+		el = fn(el, user);
+		list = FN(FN(LIST(EL),restore),BASE)(list, i, el);
+	}
+
+	return list;
+}
+
+/* Internal data structure for isl_*_list_sort.
+ *
+ * "cmp" is the original comparison function.
+ * "user" is a user provided pointer that should be passed to "cmp".
+ */
+S(LIST(EL),sort_data) {
+	int (*cmp)(__isl_keep EL *a, __isl_keep EL *b, void *user);
+	void *user;
+};
+
+/* Compare two entries of an isl_*_list based on the user provided
+ * comparison function on pairs of isl_* objects.
+ */
+static int FN(LIST(EL),cmp)(const void *a, const void *b, void *user)
+{
+	S(LIST(EL),sort_data) *data = user;
+	EL * const *el1 = a;
+	EL * const *el2 = b;
+
+	return data->cmp(*el1, *el2, data->user);
+}
+
+/* Sort the elements of "list" in ascending order according to
+ * comparison function "cmp".
+ */
+__isl_give LIST(EL) *FN(LIST(EL),sort)(__isl_take LIST(EL) *list,
+	int (*cmp)(__isl_keep EL *a, __isl_keep EL *b, void *user), void *user)
+{
+	S(LIST(EL),sort_data) data = { cmp, user };
+
+	if (!list)
+		return NULL;
+	if (list->n <= 1)
+		return list;
+	list = FN(LIST(EL),cow)(list);
+	if (!list)
+		return NULL;
+
+	if (isl_sort(list->p, list->n, sizeof(list->p[0]),
+			&FN(LIST(EL),cmp), &data) < 0)
+		return FN(LIST(EL),free)(list);
+
+	return list;
+}
+
+/* Internal data structure for isl_*_list_foreach_scc.
+ *
+ * "list" is the original list.
+ * "follows" is the user provided callback that defines the edges of the graph.
+ */
+S(LIST(EL),foreach_scc_data) {
+	LIST(EL) *list;
+	isl_bool (*follows)(__isl_keep EL *a, __isl_keep EL *b, void *user);
+	void *follows_user;
+};
+
+/* Does element i of data->list follow element j?
+ *
+ * Use the user provided callback to find out.
+ */
+static isl_bool FN(LIST(EL),follows)(int i, int j, void *user)
+{
+	S(LIST(EL),foreach_scc_data) *data = user;
+
+	return data->follows(data->list->p[i], data->list->p[j],
+				data->follows_user);
+}
+
+/* Call "fn" on the sublist of "list" that consists of the elements
+ * with indices specified by the "n" elements of "pos".
+ */
+static isl_stat FN(LIST(EL),call_on_scc)(__isl_keep LIST(EL) *list, int *pos,
+	int n, isl_stat (*fn)(__isl_take LIST(EL) *scc, void *user), void *user)
+{
+	int i;
+	isl_ctx *ctx;
+	LIST(EL) *slice;
+
+	ctx = FN(LIST(EL),get_ctx)(list);
+	slice = FN(LIST(EL),alloc)(ctx, n);
+	for (i = 0; i < n; ++i) {
+		EL *el;
+
+		el = FN(EL,copy)(list->p[pos[i]]);
+		slice = FN(LIST(EL),add)(slice, el);
+	}
+
+	return fn(slice, user);
+}
+
+/* Call "fn" on each of the strongly connected components (SCCs) of
+ * the graph with as vertices the elements of "list" and
+ * a directed edge from node b to node a iff follows(a, b)
+ * returns 1.  follows should return -1 on error.
+ *
+ * If SCC a contains a node i that follows a node j in another SCC b
+ * (i.e., follows(i, j, user) returns 1), then fn will be called on SCC a
+ * after being called on SCC b.
+ *
+ * We simply call isl_tarjan_graph_init, extract the SCCs from the result and
+ * call fn on each of them.
+ */
+isl_stat FN(LIST(EL),foreach_scc)(__isl_keep LIST(EL) *list,
+	isl_bool (*follows)(__isl_keep EL *a, __isl_keep EL *b, void *user),
+	void *follows_user,
+	isl_stat (*fn)(__isl_take LIST(EL) *scc, void *user), void *fn_user)
+{
+	S(LIST(EL),foreach_scc_data) data = { list, follows, follows_user };
+	int i, n;
+	isl_ctx *ctx;
+	struct isl_tarjan_graph *g;
+
+	if (!list)
+		return isl_stat_error;
+	if (list->n == 0)
+		return isl_stat_ok;
+	if (list->n == 1)
+		return fn(FN(LIST(EL),copy)(list), fn_user);
+
+	ctx = FN(LIST(EL),get_ctx)(list);
+	n = list->n;
+	g = isl_tarjan_graph_init(ctx, n, &FN(LIST(EL),follows), &data);
+	if (!g)
+		return isl_stat_error;
+
+	i = 0;
+	do {
+		int first;
+
+		if (g->order[i] == -1)
+			isl_die(ctx, isl_error_internal, "cannot happen",
+				break);
+		first = i;
+		while (g->order[i] != -1) {
+			++i; --n;
+		}
+		if (first == 0 && n == 0) {
+			isl_tarjan_graph_free(g);
+			return fn(FN(LIST(EL),copy)(list), fn_user);
+		}
+		if (FN(LIST(EL),call_on_scc)(list, g->order + first, i - first,
+					    fn, fn_user) < 0)
+			break;
+		++i;
+	} while (n);
+
+	isl_tarjan_graph_free(g);
+
+	return n > 0 ? isl_stat_error : isl_stat_ok;
+}
+
+__isl_give LIST(EL) *FN(FN(LIST(EL),from),BASE)(__isl_take EL *el)
+{
+	isl_ctx *ctx;
+	LIST(EL) *list;
+
+	if (!el)
+		return NULL;
+	ctx = FN(EL,get_ctx)(el);
+	list = FN(LIST(EL),alloc)(ctx, 1);
+	if (!list)
+		goto error;
+	list = FN(LIST(EL),add)(list, el);
+	return list;
+error:
+	FN(EL,free)(el);
+	return NULL;
+}
+
+/* Append the elements of "list2" to "list1", where "list1" is known
+ * to have only a single reference and enough room to hold
+ * the extra elements.
+ */
+static __isl_give LIST(EL) *FN(LIST(EL),concat_inplace)(
+	__isl_take LIST(EL) *list1, __isl_take LIST(EL) *list2)
+{
+	int i;
+
+	for (i = 0; i < list2->n; ++i)
+		list1 = FN(LIST(EL),add)(list1, FN(EL,copy)(list2->p[i]));
+	FN(LIST(EL),free)(list2);
+	return list1;
+}
+
+/* Concatenate "list1" and "list2".
+ * If "list1" has only one reference and has enough room
+ * for the elements of "list2", the add the elements to "list1" itself.
+ * Otherwise, create a new list to store the result.
+ */
+__isl_give LIST(EL) *FN(LIST(EL),concat)(__isl_take LIST(EL) *list1,
+	__isl_take LIST(EL) *list2)
+{
+	int i;
+	isl_ctx *ctx;
+	LIST(EL) *res;
+
+	if (!list1 || !list2)
+		goto error;
+
+	if (list1->ref == 1 && list1->n + list2->n <= list1->size)
+		return FN(LIST(EL),concat_inplace)(list1, list2);
+
+	ctx = FN(LIST(EL),get_ctx)(list1);
+	res = FN(LIST(EL),alloc)(ctx, list1->n + list2->n);
+	for (i = 0; i < list1->n; ++i)
+		res = FN(LIST(EL),add)(res, FN(EL,copy)(list1->p[i]));
+	for (i = 0; i < list2->n; ++i)
+		res = FN(LIST(EL),add)(res, FN(EL,copy)(list2->p[i]));
+
+	FN(LIST(EL),free)(list1);
+	FN(LIST(EL),free)(list2);
+	return res;
+error:
+	FN(LIST(EL),free)(list1);
+	FN(LIST(EL),free)(list2);
+	return NULL;
+}
+
+__isl_give isl_printer *CAT(isl_printer_print_,LIST(BASE))(
+	__isl_take isl_printer *p, __isl_keep LIST(EL) *list)
+{
+	int i;
+
+	if (!p || !list)
+		goto error;
+	p = isl_printer_print_str(p, "(");
+	for (i = 0; i < list->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, ",");
+		p = CAT(isl_printer_print_,BASE)(p, list->p[i]);
+	}
+	p = isl_printer_print_str(p, ")");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+void FN(LIST(EL),dump)(__isl_keep LIST(EL) *list)
+{
+	isl_printer *printer;
+
+	if (!list)
+		return;
+
+	printer = isl_printer_to_file(FN(LIST(EL),get_ctx)(list), stderr);
+	printer = CAT(isl_printer_print_,LIST(BASE))(printer, list);
+	printer = isl_printer_end_line(printer);
+
+	isl_printer_free(printer);
+}
diff --git a/final/lib/External/isl/isl_list_templ.h b/final/lib/External/isl/isl_list_templ.h
new file mode 100644
index 0000000..893f9d9
--- /dev/null
+++ b/final/lib/External/isl/isl_list_templ.h
@@ -0,0 +1,16 @@
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xLIST(EL) EL ## _list
+#define LIST(EL) xLIST(EL)
+
+struct LIST(EL) {
+	int ref;
+	isl_ctx *ctx;
+
+	int n;
+
+	size_t size;
+	struct EL *p[1];
+};
+
+__isl_give LIST(EL) *FN(LIST(EL),dup)(__isl_keep LIST(EL) *list);
diff --git a/final/lib/External/isl/isl_local.c b/final/lib/External/isl/isl_local.c
new file mode 100644
index 0000000..c8240b9
--- /dev/null
+++ b/final/lib/External/isl/isl_local.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2014      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_mat_private.h>
+#include <isl_seq.h>
+
+/* Given a matrix "div" representing local variables,
+ * is the variable at position "pos" marked as not having
+ * an explicit representation?
+ * Note that even if this variable is not marked in this way and therefore
+ * does have an explicit representation, this representation may still
+ * depend (indirectly) on other local variables that do not
+ * have an explicit representation.
+ */
+isl_bool isl_local_div_is_marked_unknown(__isl_keep isl_mat *div, int pos)
+{
+	if (!div)
+		return isl_bool_error;
+	if (pos < 0 || pos >= div->n_row)
+		isl_die(isl_mat_get_ctx(div), isl_error_invalid,
+			"position out of bounds", return isl_bool_error);
+	return isl_int_is_zero(div->row[pos][0]);
+}
+
+/* Given a matrix "div" representing local variables,
+ * does the variable at position "pos" have a complete explicit representation?
+ * Having a complete explicit representation requires not only
+ * an explicit representation, but also that all local variables
+ * that appear in this explicit representation in turn have
+ * a complete explicit representation.
+ */
+isl_bool isl_local_div_is_known(__isl_keep isl_mat *div, int pos)
+{
+	isl_bool marked;
+	int i, n, off;
+
+	if (!div)
+		return isl_bool_error;
+	if (pos < 0 || pos >= div->n_row)
+		isl_die(isl_mat_get_ctx(div), isl_error_invalid,
+			"position out of bounds", return isl_bool_error);
+
+	marked = isl_local_div_is_marked_unknown(div, pos);
+	if (marked < 0 || marked)
+		return isl_bool_not(marked);
+
+	n = isl_mat_rows(div);
+	off = isl_mat_cols(div) - n;
+
+	for (i = n - 1; i >= 0; --i) {
+		isl_bool known;
+
+		if (isl_int_is_zero(div->row[pos][off + i]))
+			continue;
+		known = isl_local_div_is_known(div, i);
+		if (known < 0 || !known)
+			return known;
+	}
+
+	return isl_bool_true;
+}
+
+/* Compare two matrices representing local variables, defined over
+ * the same space.
+ *
+ * Return -1 if "div1" is "smaller" than "div2", 1 if "div1" is "greater"
+ * than "div2" and 0 if they are equal.
+ *
+ * The order is fairly arbitrary.  We do "prefer" divs that only involve
+ * earlier dimensions in the sense that we consider matrices where
+ * the first differing div involves earlier dimensions to be smaller.
+ */
+int isl_local_cmp(__isl_keep isl_mat *div1, __isl_keep isl_mat *div2)
+{
+	int i;
+	int cmp;
+	isl_bool unknown1, unknown2;
+	int last1, last2;
+	int n_col;
+
+	if (div1 == div2)
+		return 0;
+	if (!div1)
+		return -1;
+	if (!div2)
+		return 1;
+
+	if (div1->n_row != div2->n_row)
+		return div1->n_row - div2->n_row;
+
+	n_col = isl_mat_cols(div1);
+	for (i = 0; i < div1->n_row; ++i) {
+		unknown1 = isl_local_div_is_marked_unknown(div1, i);
+		unknown2 = isl_local_div_is_marked_unknown(div2, i);
+		if (unknown1 && unknown2)
+			continue;
+		if (unknown1)
+			return 1;
+		if (unknown2)
+			return -1;
+		last1 = isl_seq_last_non_zero(div1->row[i] + 1, n_col - 1);
+		last2 = isl_seq_last_non_zero(div2->row[i] + 1, n_col - 1);
+		if (last1 != last2)
+			return last1 - last2;
+		cmp = isl_seq_cmp(div1->row[i], div2->row[i], n_col);
+		if (cmp != 0)
+			return cmp;
+	}
+
+	return 0;
+}
diff --git a/final/lib/External/isl/isl_local.h b/final/lib/External/isl/isl_local.h
new file mode 100644
index 0000000..0970509
--- /dev/null
+++ b/final/lib/External/isl/isl_local.h
@@ -0,0 +1,10 @@
+#ifndef ISL_LOCAL_H
+#define ISL_LOCAL_H
+
+#include <isl/mat.h>
+
+isl_bool isl_local_div_is_marked_unknown(__isl_keep isl_mat *div, int pos);
+isl_bool isl_local_div_is_known(__isl_keep isl_mat *div, int pos);
+int isl_local_cmp(__isl_keep isl_mat *div1, __isl_keep isl_mat *div2);
+
+#endif
diff --git a/final/lib/External/isl/isl_local_space.c b/final/lib/External/isl/isl_local_space.c
new file mode 100644
index 0000000..58ce847
--- /dev/null
+++ b/final/lib/External/isl/isl_local_space.c
@@ -0,0 +1,1451 @@
+/*
+ * Copyright 2011      INRIA Saclay
+ * Copyright 2012-2014 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_local_space_private.h>
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_aff_private.h>
+#include <isl_vec_private.h>
+#include <isl_seq.h>
+#include <isl_local.h>
+
+isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls)
+{
+	return ls ? ls->dim->ctx : NULL;
+}
+
+/* Return a hash value that digests "ls".
+ */
+uint32_t isl_local_space_get_hash(__isl_keep isl_local_space *ls)
+{
+	uint32_t hash, space_hash, div_hash;
+
+	if (!ls)
+		return 0;
+
+	hash = isl_hash_init();
+	space_hash = isl_space_get_hash(ls->dim);
+	isl_hash_hash(hash, space_hash);
+	div_hash = isl_mat_get_hash(ls->div);
+	isl_hash_hash(hash, div_hash);
+
+	return hash;
+}
+
+__isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim,
+	__isl_take isl_mat *div)
+{
+	isl_ctx *ctx;
+	isl_local_space *ls = NULL;
+
+	if (!dim || !div)
+		goto error;
+
+	ctx = isl_space_get_ctx(dim);
+	ls = isl_calloc_type(ctx, struct isl_local_space);
+	if (!ls)
+		goto error;
+
+	ls->ref = 1;
+	ls->dim = dim;
+	ls->div = div;
+
+	return ls;
+error:
+	isl_mat_free(div);
+	isl_space_free(dim);
+	isl_local_space_free(ls);
+	return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim,
+	unsigned n_div)
+{
+	isl_ctx *ctx;
+	isl_mat *div;
+	unsigned total;
+
+	if (!dim)
+		return NULL;
+
+	total = isl_space_dim(dim, isl_dim_all);
+
+	ctx = isl_space_get_ctx(dim);
+	div = isl_mat_alloc(ctx, n_div, 1 + 1 + total + n_div);
+	return isl_local_space_alloc_div(dim, div);
+}
+
+__isl_give isl_local_space *isl_local_space_from_space(__isl_take isl_space *dim)
+{
+	return isl_local_space_alloc(dim, 0);
+}
+
+__isl_give isl_local_space *isl_local_space_copy(__isl_keep isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	ls->ref++;
+	return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_dup(__isl_keep isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	return isl_local_space_alloc_div(isl_space_copy(ls->dim),
+					 isl_mat_copy(ls->div));
+
+}
+
+__isl_give isl_local_space *isl_local_space_cow(__isl_take isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	if (ls->ref == 1)
+		return ls;
+	ls->ref--;
+	return isl_local_space_dup(ls);
+}
+
+__isl_null isl_local_space *isl_local_space_free(
+	__isl_take isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	if (--ls->ref > 0)
+		return NULL;
+
+	isl_space_free(ls->dim);
+	isl_mat_free(ls->div);
+
+	free(ls);
+
+	return NULL;
+}
+
+/* Is the local space that of a parameter domain?
+ */
+isl_bool isl_local_space_is_params(__isl_keep isl_local_space *ls)
+{
+	if (!ls)
+		return isl_bool_error;
+	return isl_space_is_params(ls->dim);
+}
+
+/* Is the local space that of a set?
+ */
+isl_bool isl_local_space_is_set(__isl_keep isl_local_space *ls)
+{
+	return ls ? isl_space_is_set(ls->dim) : isl_bool_error;
+}
+
+/* Do "ls1" and "ls2" have the same space?
+ */
+isl_bool isl_local_space_has_equal_space(__isl_keep isl_local_space *ls1,
+	__isl_keep isl_local_space *ls2)
+{
+	if (!ls1 || !ls2)
+		return isl_bool_error;
+
+	return isl_space_is_equal(ls1->dim, ls2->dim);
+}
+
+/* Return true if the two local spaces are identical, with identical
+ * expressions for the integer divisions.
+ */
+isl_bool isl_local_space_is_equal(__isl_keep isl_local_space *ls1,
+	__isl_keep isl_local_space *ls2)
+{
+	isl_bool equal;
+
+	equal = isl_local_space_has_equal_space(ls1, ls2);
+	if (equal < 0 || !equal)
+		return equal;
+
+	if (!isl_local_space_divs_known(ls1))
+		return isl_bool_false;
+	if (!isl_local_space_divs_known(ls2))
+		return isl_bool_false;
+
+	return isl_mat_is_equal(ls1->div, ls2->div);
+}
+
+/* Compare two isl_local_spaces.
+ *
+ * Return -1 if "ls1" is "smaller" than "ls2", 1 if "ls1" is "greater"
+ * than "ls2" and 0 if they are equal.
+ */
+int isl_local_space_cmp(__isl_keep isl_local_space *ls1,
+	__isl_keep isl_local_space *ls2)
+{
+	int cmp;
+
+	if (ls1 == ls2)
+		return 0;
+	if (!ls1)
+		return -1;
+	if (!ls2)
+		return 1;
+
+	cmp = isl_space_cmp(ls1->dim, ls2->dim);
+	if (cmp != 0)
+		return cmp;
+
+	return isl_local_cmp(ls1->div, ls2->div);
+}
+
+int isl_local_space_dim(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type)
+{
+	if (!ls)
+		return 0;
+	if (type == isl_dim_div)
+		return ls->div->n_row;
+	if (type == isl_dim_all)
+		return isl_space_dim(ls->dim, isl_dim_all) + ls->div->n_row;
+	return isl_space_dim(ls->dim, type);
+}
+
+unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type)
+{
+	isl_space *dim;
+
+	if (!ls)
+		return 0;
+
+	dim = ls->dim;
+	switch (type) {
+	case isl_dim_cst:	return 0;
+	case isl_dim_param:	return 1;
+	case isl_dim_in:	return 1 + dim->nparam;
+	case isl_dim_out:	return 1 + dim->nparam + dim->n_in;
+	case isl_dim_div:	return 1 + dim->nparam + dim->n_in + dim->n_out;
+	default:		return 0;
+	}
+}
+
+/* Return the position of the dimension of the given type and name
+ * in "ls".
+ * Return -1 if no such dimension can be found.
+ */
+int isl_local_space_find_dim_by_name(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, const char *name)
+{
+	if (!ls)
+		return -1;
+	if (type == isl_dim_div)
+		return -1;
+	return isl_space_find_dim_by_name(ls->dim, type, name);
+}
+
+/* Does the given dimension have a name?
+ */
+isl_bool isl_local_space_has_dim_name(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos)
+{
+	return ls ? isl_space_has_dim_name(ls->dim, type, pos) : isl_bool_error;
+}
+
+const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos)
+{
+	return ls ? isl_space_get_dim_name(ls->dim, type, pos) : NULL;
+}
+
+isl_bool isl_local_space_has_dim_id(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos)
+{
+	return ls ? isl_space_has_dim_id(ls->dim, type, pos) : isl_bool_error;
+}
+
+__isl_give isl_id *isl_local_space_get_dim_id(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos)
+{
+	return ls ? isl_space_get_dim_id(ls->dim, type, pos) : NULL;
+}
+
+/* Return the argument of the integer division at position "pos" in "ls".
+ * All local variables in "ls" are known to have a (complete) explicit
+ * representation.
+ */
+static __isl_give isl_aff *extract_div(__isl_keep isl_local_space *ls, int pos)
+{
+	isl_aff *aff;
+
+	aff = isl_aff_alloc(isl_local_space_copy(ls));
+	if (!aff)
+		return NULL;
+	isl_seq_cpy(aff->v->el, ls->div->row[pos], aff->v->size);
+	return aff;
+}
+
+/* Return the argument of the integer division at position "pos" in "ls".
+ * The integer division at that position is known to have a complete
+ * explicit representation, but some of the others do not.
+ * Remove them first because the domain of an isl_aff
+ * is not allowed to have unknown local variables.
+ */
+static __isl_give isl_aff *drop_unknown_divs_and_extract_div(
+	__isl_keep isl_local_space *ls, int pos)
+{
+	int i, n;
+	isl_bool unknown;
+	isl_aff *aff;
+
+	ls = isl_local_space_copy(ls);
+	n = isl_local_space_dim(ls, isl_dim_div);
+	for (i = n - 1; i >= 0; --i) {
+		unknown = isl_local_space_div_is_marked_unknown(ls, i);
+		if (unknown < 0)
+			ls = isl_local_space_free(ls);
+		else if (!unknown)
+			continue;
+		ls = isl_local_space_drop_dims(ls, isl_dim_div, i, 1);
+		if (pos > i)
+			--pos;
+	}
+	aff = extract_div(ls, pos);
+	isl_local_space_free(ls);
+	return aff;
+}
+
+/* Return the argument of the integer division at position "pos" in "ls".
+ * The integer division is assumed to have a complete explicit
+ * representation.  If some of the other integer divisions
+ * do not have an explicit representation, then they need
+ * to be removed first because the domain of an isl_aff
+ * is not allowed to have unknown local variables.
+ */
+__isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls,
+	int pos)
+{
+	isl_bool known;
+
+	if (!ls)
+		return NULL;
+
+	if (pos < 0 || pos >= ls->div->n_row)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"index out of bounds", return NULL);
+
+	known = isl_local_space_div_is_known(ls, pos);
+	if (known < 0)
+		return NULL;
+	if (!known)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"expression of div unknown", return NULL);
+	if (!isl_local_space_is_set(ls))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"cannot represent divs of map spaces", return NULL);
+
+	known = isl_local_space_divs_known(ls);
+	if (known < 0)
+		return NULL;
+	if (known)
+		return extract_div(ls, pos);
+	else
+		return drop_unknown_divs_and_extract_div(ls, pos);
+}
+
+__isl_give isl_space *isl_local_space_get_space(__isl_keep isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	return isl_space_copy(ls->dim);
+}
+
+/* Replace the identifier of the tuple of type "type" by "id".
+ */
+__isl_give isl_local_space *isl_local_space_set_tuple_id(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, __isl_take isl_id *id)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		goto error;
+	ls->dim = isl_space_set_tuple_id(ls->dim, type, id);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+	return ls;
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_set_dim_name(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+	ls->dim = isl_space_set_dim_name(ls->dim, type, pos, s);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_set_dim_id(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		goto error;
+	ls->dim = isl_space_set_dim_id(ls->dim, type, pos, id);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+
+	return ls;
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_reset_space(
+	__isl_take isl_local_space *ls, __isl_take isl_space *dim)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls || !dim)
+		goto error;
+
+	isl_space_free(ls->dim);
+	ls->dim = dim;
+
+	return ls;
+error:
+	isl_local_space_free(ls);
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Reorder the columns of the given div definitions according to the
+ * given reordering.
+ * The order of the divs themselves is assumed not to change.
+ */
+static __isl_give isl_mat *reorder_divs(__isl_take isl_mat *div,
+	__isl_take isl_reordering *r)
+{
+	int i, j;
+	isl_mat *mat;
+	int extra;
+
+	if (!div || !r)
+		goto error;
+
+	extra = isl_space_dim(r->dim, isl_dim_all) + div->n_row - r->len;
+	mat = isl_mat_alloc(div->ctx, div->n_row, div->n_col + extra);
+	if (!mat)
+		goto error;
+
+	for (i = 0; i < div->n_row; ++i) {
+		isl_seq_cpy(mat->row[i], div->row[i], 2);
+		isl_seq_clr(mat->row[i] + 2, mat->n_col - 2);
+		for (j = 0; j < r->len; ++j)
+			isl_int_set(mat->row[i][2 + r->pos[j]],
+				    div->row[i][2 + j]);
+	}
+
+	isl_reordering_free(r);
+	isl_mat_free(div);
+	return mat;
+error:
+	isl_reordering_free(r);
+	isl_mat_free(div);
+	return NULL;
+}
+
+/* Reorder the dimensions of "ls" according to the given reordering.
+ * The reordering r is assumed to have been extended with the local
+ * variables, leaving them in the same order.
+ */
+__isl_give isl_local_space *isl_local_space_realign(
+	__isl_take isl_local_space *ls, __isl_take isl_reordering *r)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls || !r)
+		goto error;
+
+	ls->div = reorder_divs(ls->div, isl_reordering_copy(r));
+	if (!ls->div)
+		goto error;
+
+	ls = isl_local_space_reset_space(ls, isl_space_copy(r->dim));
+
+	isl_reordering_free(r);
+	return ls;
+error:
+	isl_local_space_free(ls);
+	isl_reordering_free(r);
+	return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_add_div(
+	__isl_take isl_local_space *ls, __isl_take isl_vec *div)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls || !div)
+		goto error;
+
+	if (ls->div->n_col != div->size)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"incompatible dimensions", goto error);
+
+	ls->div = isl_mat_add_zero_cols(ls->div, 1);
+	ls->div = isl_mat_add_rows(ls->div, 1);
+	if (!ls->div)
+		goto error;
+
+	isl_seq_cpy(ls->div->row[ls->div->n_row - 1], div->el, div->size);
+	isl_int_set_si(ls->div->row[ls->div->n_row - 1][div->size], 0);
+
+	isl_vec_free(div);
+	return ls;
+error:
+	isl_local_space_free(ls);
+	isl_vec_free(div);
+	return NULL;
+}
+
+__isl_give isl_local_space *isl_local_space_replace_divs(
+	__isl_take isl_local_space *ls, __isl_take isl_mat *div)
+{
+	ls = isl_local_space_cow(ls);
+
+	if (!ls || !div)
+		goto error;
+
+	isl_mat_free(ls->div);
+	ls->div = div;
+	return ls;
+error:
+	isl_mat_free(div);
+	isl_local_space_free(ls);
+	return NULL;
+}
+
+/* Copy row "s" of "src" to row "d" of "dst", applying the expansion
+ * defined by "exp".
+ */
+static void expand_row(__isl_keep isl_mat *dst, int d,
+	__isl_keep isl_mat *src, int s, int *exp)
+{
+	int i;
+	unsigned c = src->n_col - src->n_row;
+
+	isl_seq_cpy(dst->row[d], src->row[s], c);
+	isl_seq_clr(dst->row[d] + c, dst->n_col - c);
+
+	for (i = 0; i < s; ++i)
+		isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
+}
+
+/* Compare (known) divs.
+ * Return non-zero if at least one of the two divs is unknown.
+ * In particular, if both divs are unknown, we respect their
+ * current order.  Otherwise, we sort the known div after the unknown
+ * div only if the known div depends on the unknown div.
+ */
+static int cmp_row(isl_int *row_i, isl_int *row_j, int i, int j,
+	unsigned n_row, unsigned n_col)
+{
+	int li, lj;
+	int unknown_i, unknown_j;
+
+	unknown_i = isl_int_is_zero(row_i[0]);
+	unknown_j = isl_int_is_zero(row_j[0]);
+
+	if (unknown_i && unknown_j)
+		return i - j;
+
+	if (unknown_i)
+		li = n_col - n_row + i;
+	else
+		li = isl_seq_last_non_zero(row_i, n_col);
+	if (unknown_j)
+		lj = n_col - n_row + j;
+	else
+		lj = isl_seq_last_non_zero(row_j, n_col);
+
+	if (li != lj)
+		return li - lj;
+
+	return isl_seq_cmp(row_i, row_j, n_col);
+}
+
+/* Call cmp_row for divs in a matrix.
+ */
+int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j)
+{
+	return cmp_row(div->row[i], div->row[j], i, j, div->n_row, div->n_col);
+}
+
+/* Call cmp_row for divs in a basic map.
+ */
+static int bmap_cmp_row(__isl_keep isl_basic_map *bmap, int i, int j,
+	unsigned total)
+{
+	return cmp_row(bmap->div[i], bmap->div[j], i, j, bmap->n_div, total);
+}
+
+/* Sort the divs in "bmap".
+ *
+ * We first make sure divs are placed after divs on which they depend.
+ * Then we perform a simple insertion sort based on the same ordering
+ * that is used in isl_merge_divs.
+ */
+__isl_give isl_basic_map *isl_basic_map_sort_divs(
+	__isl_take isl_basic_map *bmap)
+{
+	int i, j;
+	unsigned total;
+
+	bmap = isl_basic_map_order_divs(bmap);
+	if (!bmap)
+		return NULL;
+	if (bmap->n_div <= 1)
+		return bmap;
+
+	total = 2 + isl_basic_map_total_dim(bmap);
+	for (i = 1; i < bmap->n_div; ++i) {
+		for (j = i - 1; j >= 0; --j) {
+			if (bmap_cmp_row(bmap, j, j + 1, total) <= 0)
+				break;
+			isl_basic_map_swap_div(bmap, j, j + 1);
+		}
+	}
+
+	return bmap;
+}
+
+/* Sort the divs in the basic maps of "map".
+ */
+__isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map)
+{
+	return isl_map_inline_foreach_basic_map(map, &isl_basic_map_sort_divs);
+}
+
+/* Combine the two lists of divs into a single list.
+ * For each row i in div1, exp1[i] is set to the position of the corresponding
+ * row in the result.  Similarly for div2 and exp2.
+ * This function guarantees
+ *	exp1[i] >= i
+ *	exp1[i+1] > exp1[i]
+ * For optimal merging, the two input list should have been sorted.
+ */
+__isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
+	__isl_keep isl_mat *div2, int *exp1, int *exp2)
+{
+	int i, j, k;
+	isl_mat *div = NULL;
+	unsigned d;
+
+	if (!div1 || !div2)
+		return NULL;
+
+	d = div1->n_col - div1->n_row;
+	div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
+				d + div1->n_row + div2->n_row);
+	if (!div)
+		return NULL;
+
+	for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
+		int cmp;
+
+		expand_row(div, k, div1, i, exp1);
+		expand_row(div, k + 1, div2, j, exp2);
+
+		cmp = isl_mat_cmp_div(div, k, k + 1);
+		if (cmp == 0) {
+			exp1[i++] = k;
+			exp2[j++] = k;
+		} else if (cmp < 0) {
+			exp1[i++] = k;
+		} else {
+			exp2[j++] = k;
+			isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
+		}
+	}
+	for (; i < div1->n_row; ++i, ++k) {
+		expand_row(div, k, div1, i, exp1);
+		exp1[i] = k;
+	}
+	for (; j < div2->n_row; ++j, ++k) {
+		expand_row(div, k, div2, j, exp2);
+		exp2[j] = k;
+	}
+
+	div->n_row = k;
+	div->n_col = d + k;
+
+	return div;
+}
+
+/* Swap divs "a" and "b" in "ls".
+ */
+__isl_give isl_local_space *isl_local_space_swap_div(
+	__isl_take isl_local_space *ls, int a, int b)
+{
+	int offset;
+
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+	if (a < 0 || a >= ls->div->n_row || b < 0 || b >= ls->div->n_row)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"index out of bounds", return isl_local_space_free(ls));
+	offset = ls->div->n_col - ls->div->n_row;
+	ls->div = isl_mat_swap_cols(ls->div, offset + a, offset + b);
+	ls->div = isl_mat_swap_rows(ls->div, a, b);
+	if (!ls->div)
+		return isl_local_space_free(ls);
+	return ls;
+}
+
+/* Construct a local space that contains all the divs in either
+ * "ls1" or "ls2".
+ */
+__isl_give isl_local_space *isl_local_space_intersect(
+	__isl_take isl_local_space *ls1, __isl_take isl_local_space *ls2)
+{
+	isl_ctx *ctx;
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_mat *div = NULL;
+	isl_bool equal;
+
+	if (!ls1 || !ls2)
+		goto error;
+
+	ctx = isl_local_space_get_ctx(ls1);
+	if (!isl_space_is_equal(ls1->dim, ls2->dim))
+		isl_die(ctx, isl_error_invalid,
+			"spaces should be identical", goto error);
+
+	if (ls2->div->n_row == 0) {
+		isl_local_space_free(ls2);
+		return ls1;
+	}
+
+	if (ls1->div->n_row == 0) {
+		isl_local_space_free(ls1);
+		return ls2;
+	}
+
+	exp1 = isl_alloc_array(ctx, int, ls1->div->n_row);
+	exp2 = isl_alloc_array(ctx, int, ls2->div->n_row);
+	if (!exp1 || !exp2)
+		goto error;
+
+	div = isl_merge_divs(ls1->div, ls2->div, exp1, exp2);
+	if (!div)
+		goto error;
+
+	equal = isl_mat_is_equal(ls1->div, div);
+	if (equal < 0)
+		goto error;
+	if (!equal)
+		ls1 = isl_local_space_cow(ls1);
+	if (!ls1)
+		goto error;
+
+	free(exp1);
+	free(exp2);
+	isl_local_space_free(ls2);
+	isl_mat_free(ls1->div);
+	ls1->div = div;
+
+	return ls1;
+error:
+	free(exp1);
+	free(exp2);
+	isl_mat_free(div);
+	isl_local_space_free(ls1);
+	isl_local_space_free(ls2);
+	return NULL;
+}
+
+/* Is the local variable "div" of "ls" marked as not having
+ * an explicit representation?
+ * Note that even if this variable is not marked in this way and therefore
+ * does have an explicit representation, this representation may still
+ * depend (indirectly) on other local variables that do not
+ * have an explicit representation.
+ */
+isl_bool isl_local_space_div_is_marked_unknown(__isl_keep isl_local_space *ls,
+	int div)
+{
+	if (!ls)
+		return isl_bool_error;
+	return isl_local_div_is_marked_unknown(ls->div, div);
+}
+
+/* Does "ls" have a complete explicit representation for div "div"?
+ */
+isl_bool isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div)
+{
+	if (!ls)
+		return isl_bool_error;
+	return isl_local_div_is_known(ls->div, div);
+}
+
+/* Does "ls" have an explicit representation for all local variables?
+ */
+isl_bool isl_local_space_divs_known(__isl_keep isl_local_space *ls)
+{
+	int i;
+
+	if (!ls)
+		return isl_bool_error;
+
+	for (i = 0; i < ls->div->n_row; ++i) {
+		isl_bool unknown = isl_local_space_div_is_marked_unknown(ls, i);
+		if (unknown < 0 || unknown)
+			return isl_bool_not(unknown);
+	}
+
+	return isl_bool_true;
+}
+
+__isl_give isl_local_space *isl_local_space_domain(
+	__isl_take isl_local_space *ls)
+{
+	ls = isl_local_space_drop_dims(ls, isl_dim_out,
+					0, isl_local_space_dim(ls, isl_dim_out));
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+	ls->dim = isl_space_domain(ls->dim);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+	return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_range(
+	__isl_take isl_local_space *ls)
+{
+	ls = isl_local_space_drop_dims(ls, isl_dim_in,
+					0, isl_local_space_dim(ls, isl_dim_in));
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	ls->dim = isl_space_range(ls->dim);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+	return ls;
+}
+
+/* Construct a local space for a map that has the given local
+ * space as domain and that has a zero-dimensional range.
+ */
+__isl_give isl_local_space *isl_local_space_from_domain(
+	__isl_take isl_local_space *ls)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+	ls->dim = isl_space_from_domain(ls->dim);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+	return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_add_dims(
+	__isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n)
+{
+	int pos;
+
+	if (!ls)
+		return NULL;
+	pos = isl_local_space_dim(ls, type);
+	return isl_local_space_insert_dims(ls, type, pos, n);
+}
+
+/* Remove common factor of non-constant terms and denominator.
+ */
+static void normalize_div(__isl_keep isl_local_space *ls, int div)
+{
+	isl_ctx *ctx = ls->div->ctx;
+	unsigned total = ls->div->n_col - 2;
+
+	isl_seq_gcd(ls->div->row[div] + 2, total, &ctx->normalize_gcd);
+	isl_int_gcd(ctx->normalize_gcd,
+		    ctx->normalize_gcd, ls->div->row[div][0]);
+	if (isl_int_is_one(ctx->normalize_gcd))
+		return;
+
+	isl_seq_scale_down(ls->div->row[div] + 2, ls->div->row[div] + 2,
+			    ctx->normalize_gcd, total);
+	isl_int_divexact(ls->div->row[div][0], ls->div->row[div][0],
+			    ctx->normalize_gcd);
+	isl_int_fdiv_q(ls->div->row[div][1], ls->div->row[div][1],
+			    ctx->normalize_gcd);
+}
+
+/* Exploit the equalities in "eq" to simplify the expressions of
+ * the integer divisions in "ls".
+ * The integer divisions in "ls" are assumed to appear as regular
+ * dimensions in "eq".
+ */
+__isl_give isl_local_space *isl_local_space_substitute_equalities(
+	__isl_take isl_local_space *ls, __isl_take isl_basic_set *eq)
+{
+	int i, j, k;
+	unsigned total;
+	unsigned n_div;
+
+	if (!ls || !eq)
+		goto error;
+
+	total = isl_space_dim(eq->dim, isl_dim_all);
+	if (isl_local_space_dim(ls, isl_dim_all) != total)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"spaces don't match", goto error);
+	total++;
+	n_div = eq->n_div;
+	for (i = 0; i < eq->n_eq; ++i) {
+		j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
+		if (j < 0 || j == 0 || j >= total)
+			continue;
+
+		for (k = 0; k < ls->div->n_row; ++k) {
+			if (isl_int_is_zero(ls->div->row[k][1 + j]))
+				continue;
+			ls = isl_local_space_cow(ls);
+			if (!ls)
+				goto error;
+			ls->div = isl_mat_cow(ls->div);
+			if (!ls->div)
+				goto error;
+			isl_seq_elim(ls->div->row[k] + 1, eq->eq[i], j, total,
+					&ls->div->row[k][0]);
+			normalize_div(ls, k);
+		}
+	}
+
+	isl_basic_set_free(eq);
+	return ls;
+error:
+	isl_basic_set_free(eq);
+	isl_local_space_free(ls);
+	return NULL;
+}
+
+/* Plug in the affine expressions "subs" of length "subs_len" (including
+ * the denominator and the constant term) into the variable at position "pos"
+ * of the "n" div expressions starting at "first".
+ *
+ * Let i be the dimension to replace and let "subs" be of the form
+ *
+ *	f/d
+ *
+ * Any integer division starting at "first" with a non-zero coefficient for i,
+ *
+ *	floor((a i + g)/m)
+ *
+ * is replaced by
+ *
+ *	floor((a f + d g)/(m d))
+ */
+__isl_give isl_local_space *isl_local_space_substitute_seq(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len,
+	int first, int n)
+{
+	int i;
+	isl_int v;
+
+	if (n == 0)
+		return ls;
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+	ls->div = isl_mat_cow(ls->div);
+	if (!ls->div)
+		return isl_local_space_free(ls);
+
+	if (first + n > ls->div->n_row)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"index out of bounds", return isl_local_space_free(ls));
+
+	pos += isl_local_space_offset(ls, type);
+
+	isl_int_init(v);
+	for (i = first; i < first + n; ++i) {
+		if (isl_int_is_zero(ls->div->row[i][1 + pos]))
+			continue;
+		isl_seq_substitute(ls->div->row[i], pos, subs,
+			ls->div->n_col, subs_len, v);
+		normalize_div(ls, i);
+	}
+	isl_int_clear(v);
+
+	return ls;
+}
+
+/* Plug in "subs" for dimension "type", "pos" in the integer divisions
+ * of "ls".
+ *
+ * Let i be the dimension to replace and let "subs" be of the form
+ *
+ *	f/d
+ *
+ * Any integer division with a non-zero coefficient for i,
+ *
+ *	floor((a i + g)/m)
+ *
+ * is replaced by
+ *
+ *	floor((a f + d g)/(m d))
+ */
+__isl_give isl_local_space *isl_local_space_substitute(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls || !subs)
+		return isl_local_space_free(ls);
+
+	if (!isl_space_is_equal(ls->dim, subs->ls->dim))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"spaces don't match", return isl_local_space_free(ls));
+	if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
+			"cannot handle divs yet",
+			return isl_local_space_free(ls));
+
+	return isl_local_space_substitute_seq(ls, type, pos, subs->v->el,
+					    subs->v->size, 0, ls->div->n_row);
+}
+
+isl_bool isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type)
+{
+	if (!ls)
+		return isl_bool_error;
+	return isl_space_is_named_or_nested(ls->dim, type);
+}
+
+__isl_give isl_local_space *isl_local_space_drop_dims(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	isl_ctx *ctx;
+
+	if (!ls)
+		return NULL;
+	if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
+		return ls;
+
+	ctx = isl_local_space_get_ctx(ls);
+	if (first + n > isl_local_space_dim(ls, type))
+		isl_die(ctx, isl_error_invalid, "range out of bounds",
+			return isl_local_space_free(ls));
+
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	if (type == isl_dim_div) {
+		ls->div = isl_mat_drop_rows(ls->div, first, n);
+	} else {
+		ls->dim = isl_space_drop_dims(ls->dim, type, first, n);
+		if (!ls->dim)
+			return isl_local_space_free(ls);
+	}
+
+	first += 1 + isl_local_space_offset(ls, type);
+	ls->div = isl_mat_drop_cols(ls->div, first, n);
+	if (!ls->div)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+__isl_give isl_local_space *isl_local_space_insert_dims(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	isl_ctx *ctx;
+
+	if (!ls)
+		return NULL;
+	if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
+		return ls;
+
+	ctx = isl_local_space_get_ctx(ls);
+	if (first > isl_local_space_dim(ls, type))
+		isl_die(ctx, isl_error_invalid, "position out of bounds",
+			return isl_local_space_free(ls));
+
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	if (type == isl_dim_div) {
+		ls->div = isl_mat_insert_zero_rows(ls->div, first, n);
+	} else {
+		ls->dim = isl_space_insert_dims(ls->dim, type, first, n);
+		if (!ls->dim)
+			return isl_local_space_free(ls);
+	}
+
+	first += 1 + isl_local_space_offset(ls, type);
+	ls->div = isl_mat_insert_zero_cols(ls->div, first, n);
+	if (!ls->div)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+/* Check if the constraints pointed to by "constraint" is a div
+ * constraint corresponding to div "div" in "ls".
+ *
+ * That is, if div = floor(f/m), then check if the constraint is
+ *
+ *		f - m d >= 0
+ * or
+ *		-(f-(m-1)) + m d >= 0
+ */
+isl_bool isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls,
+	isl_int *constraint, unsigned div)
+{
+	unsigned pos;
+
+	if (!ls)
+		return isl_bool_error;
+
+	if (isl_int_is_zero(ls->div->row[div][0]))
+		return isl_bool_false;
+
+	pos = isl_local_space_offset(ls, isl_dim_div) + div;
+
+	if (isl_int_eq(constraint[pos], ls->div->row[div][0])) {
+		int neg;
+		isl_int_sub(ls->div->row[div][1],
+				ls->div->row[div][1], ls->div->row[div][0]);
+		isl_int_add_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
+		neg = isl_seq_is_neg(constraint, ls->div->row[div]+1, pos);
+		isl_int_sub_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
+		isl_int_add(ls->div->row[div][1],
+				ls->div->row[div][1], ls->div->row[div][0]);
+		if (!neg)
+			return isl_bool_false;
+		if (isl_seq_first_non_zero(constraint+pos+1,
+					    ls->div->n_row-div-1) != -1)
+			return isl_bool_false;
+	} else if (isl_int_abs_eq(constraint[pos], ls->div->row[div][0])) {
+		if (!isl_seq_eq(constraint, ls->div->row[div]+1, pos))
+			return isl_bool_false;
+		if (isl_seq_first_non_zero(constraint+pos+1,
+					    ls->div->n_row-div-1) != -1)
+			return isl_bool_false;
+	} else
+		return isl_bool_false;
+
+	return isl_bool_true;
+}
+
+/*
+ * Set active[i] to 1 if the dimension at position i is involved
+ * in the linear expression l.
+ */
+int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l)
+{
+	int i, j;
+	isl_ctx *ctx;
+	int *active = NULL;
+	unsigned total;
+	unsigned offset;
+
+	ctx = isl_local_space_get_ctx(ls);
+	total = isl_local_space_dim(ls, isl_dim_all);
+	active = isl_calloc_array(ctx, int, total);
+	if (total && !active)
+		return NULL;
+
+	for (i = 0; i < total; ++i)
+		active[i] = !isl_int_is_zero(l[i]);
+
+	offset = isl_local_space_offset(ls, isl_dim_div) - 1;
+	for (i = ls->div->n_row - 1; i >= 0; --i) {
+		if (!active[offset + i])
+			continue;
+		for (j = 0; j < total; ++j)
+			active[j] |= !isl_int_is_zero(ls->div->row[i][2 + j]);
+	}
+
+	return active;
+}
+
+/* Given a local space "ls" of a set, create a local space
+ * for the lift of the set.  In particular, the result
+ * is of the form [dim -> local[..]], with ls->div->n_row variables in the
+ * range of the wrapped map.
+ */
+__isl_give isl_local_space *isl_local_space_lift(
+	__isl_take isl_local_space *ls)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	ls->dim = isl_space_lift(ls->dim, ls->div->n_row);
+	ls->div = isl_mat_drop_rows(ls->div, 0, ls->div->n_row);
+	if (!ls->dim || !ls->div)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+/* Construct a basic map that maps a set living in local space "ls"
+ * to the corresponding lifted local space.
+ */
+__isl_give isl_basic_map *isl_local_space_lifting(
+	__isl_take isl_local_space *ls)
+{
+	isl_basic_map *lifting;
+	isl_basic_set *bset;
+
+	if (!ls)
+		return NULL;
+	if (!isl_local_space_is_set(ls))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"lifting only defined on set spaces", goto error);
+
+	bset = isl_basic_set_from_local_space(ls);
+	lifting = isl_basic_set_unwrap(isl_basic_set_lift(bset));
+	lifting = isl_basic_map_domain_map(lifting);
+	lifting = isl_basic_map_reverse(lifting);
+
+	return lifting;
+error:
+	isl_local_space_free(ls);
+	return NULL;
+}
+
+/* Compute the preimage of "ls" under the function represented by "ma".
+ * In other words, plug in "ma" in "ls".  The result is a local space
+ * that is part of the domain space of "ma".
+ *
+ * If the divs in "ls" are represented as
+ *
+ *	floor((a_i(p) + b_i x + c_i(divs))/n_i)
+ *
+ * and ma is represented by
+ *
+ *	x = D(p) + F(y) + G(divs')
+ *
+ * then the resulting divs are
+ *
+ *	floor((a_i(p) + b_i D(p) + b_i F(y) + B_i G(divs') + c_i(divs))/n_i)
+ *
+ * We first copy over the divs from "ma" and then
+ * we add the modified divs from "ls".
+ */
+__isl_give isl_local_space *isl_local_space_preimage_multi_aff(
+	__isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma)
+{
+	int i;
+	isl_space *space;
+	isl_local_space *res = NULL;
+	int n_div_ls, n_div_ma;
+	isl_int f, c1, c2, g;
+
+	ma = isl_multi_aff_align_divs(ma);
+	if (!ls || !ma)
+		goto error;
+	if (!isl_space_is_range_internal(ls->dim, ma->space))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	n_div_ls = isl_local_space_dim(ls, isl_dim_div);
+	n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0;
+
+	space = isl_space_domain(isl_multi_aff_get_space(ma));
+	res = isl_local_space_alloc(space, n_div_ma + n_div_ls);
+	if (!res)
+		goto error;
+
+	if (n_div_ma) {
+		isl_mat_free(res->div);
+		res->div = isl_mat_copy(ma->p[0]->ls->div);
+		res->div = isl_mat_add_zero_cols(res->div, n_div_ls);
+		res->div = isl_mat_add_rows(res->div, n_div_ls);
+		if (!res->div)
+			goto error;
+	}
+
+	isl_int_init(f);
+	isl_int_init(c1);
+	isl_int_init(c2);
+	isl_int_init(g);
+
+	for (i = 0; i < ls->div->n_row; ++i) {
+		if (isl_int_is_zero(ls->div->row[i][0])) {
+			isl_int_set_si(res->div->row[n_div_ma + i][0], 0);
+			continue;
+		}
+		isl_seq_preimage(res->div->row[n_div_ma + i], ls->div->row[i],
+				ma, 0, 0, n_div_ma, n_div_ls, f, c1, c2, g, 1);
+		normalize_div(res, n_div_ma + i);
+	}
+
+	isl_int_clear(f);
+	isl_int_clear(c1);
+	isl_int_clear(c2);
+	isl_int_clear(g);
+
+	isl_local_space_free(ls);
+	isl_multi_aff_free(ma);
+	return res;
+error:
+	isl_local_space_free(ls);
+	isl_multi_aff_free(ma);
+	isl_local_space_free(res);
+	return NULL;
+}
+
+/* Move the "n" dimensions of "src_type" starting at "src_pos" of "ls"
+ * to dimensions of "dst_type" at "dst_pos".
+ *
+ * Moving to/from local dimensions is not allowed.
+ * We currently assume that the dimension type changes.
+ */
+__isl_give isl_local_space *isl_local_space_move_dims(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	unsigned g_dst_pos;
+	unsigned g_src_pos;
+
+	if (!ls)
+		return NULL;
+	if (n == 0 &&
+	    !isl_local_space_is_named_or_nested(ls, src_type) &&
+	    !isl_local_space_is_named_or_nested(ls, dst_type))
+		return ls;
+
+	if (src_pos + n > isl_local_space_dim(ls, src_type))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"range out of bounds", return isl_local_space_free(ls));
+	if (dst_pos > isl_local_space_dim(ls, dst_type))
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"position out of bounds",
+			return isl_local_space_free(ls));
+	if (src_type == isl_dim_div)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"cannot move divs", return isl_local_space_free(ls));
+	if (dst_type == isl_dim_div)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"cannot move to divs", return isl_local_space_free(ls));
+	if (dst_type == src_type && dst_pos == src_pos)
+		return ls;
+	if (dst_type == src_type)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
+			"moving dims within the same type not supported",
+			return isl_local_space_free(ls));
+
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	g_src_pos = 1 + isl_local_space_offset(ls, src_type) + src_pos;
+	g_dst_pos = 1 + isl_local_space_offset(ls, dst_type) + dst_pos;
+	if (dst_type > src_type)
+		g_dst_pos -= n;
+	ls->div = isl_mat_move_cols(ls->div, g_dst_pos, g_src_pos, n);
+	if (!ls->div)
+		return isl_local_space_free(ls);
+	ls->dim = isl_space_move_dims(ls->dim, dst_type, dst_pos,
+					src_type, src_pos, n);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+/* Remove any internal structure of the domain of "ls".
+ * If there is any such internal structure in the input,
+ * then the name of the corresponding space is also removed.
+ */
+__isl_give isl_local_space *isl_local_space_flatten_domain(
+	__isl_take isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	if (!ls->dim->nested[0])
+		return ls;
+
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	ls->dim = isl_space_flatten_domain(ls->dim);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+/* Remove any internal structure of the range of "ls".
+ * If there is any such internal structure in the input,
+ * then the name of the corresponding space is also removed.
+ */
+__isl_give isl_local_space *isl_local_space_flatten_range(
+	__isl_take isl_local_space *ls)
+{
+	if (!ls)
+		return NULL;
+
+	if (!ls->dim->nested[1])
+		return ls;
+
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	ls->dim = isl_space_flatten_range(ls->dim);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
+
+/* Given the local space "ls" of a map, return the local space of a set
+ * that lives in a space that wraps the space of "ls" and that has
+ * the same divs.
+ */
+__isl_give isl_local_space *isl_local_space_wrap(__isl_take isl_local_space *ls)
+{
+	ls = isl_local_space_cow(ls);
+	if (!ls)
+		return NULL;
+
+	ls->dim = isl_space_wrap(ls->dim);
+	if (!ls->dim)
+		return isl_local_space_free(ls);
+
+	return ls;
+}
diff --git a/final/lib/External/isl/isl_local_space_private.h b/final/lib/External/isl/isl_local_space_private.h
new file mode 100644
index 0000000..a1bdb1b
--- /dev/null
+++ b/final/lib/External/isl/isl_local_space_private.h
@@ -0,0 +1,82 @@
+#ifndef ISL_LOCAL_SPACE_PRIVATE_H
+#define ISL_LOCAL_SPACE_PRIVATE_H
+
+#include <isl/mat.h>
+#include <isl/set.h>
+#include <isl/local_space.h>
+
+struct isl_local_space {
+	int ref;
+
+	isl_space *dim;
+	isl_mat *div;
+};
+
+uint32_t isl_local_space_get_hash(__isl_keep isl_local_space *ls);
+
+__isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim,
+	unsigned n_div);
+__isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim,
+	__isl_take isl_mat *div);
+
+__isl_give isl_local_space *isl_local_space_swap_div(
+	__isl_take isl_local_space *ls, int a, int b);
+__isl_give isl_local_space *isl_local_space_add_div(
+	__isl_take isl_local_space *ls, __isl_take isl_vec *div);
+
+int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j);
+__isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
+	__isl_keep isl_mat *div2, int *exp1, int *exp2);
+
+unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type);
+
+__isl_give isl_local_space *isl_local_space_replace_divs(
+	__isl_take isl_local_space *ls, __isl_take isl_mat *div);
+isl_bool isl_local_space_div_is_marked_unknown(__isl_keep isl_local_space *ls,
+	int div);
+isl_bool isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div);
+isl_bool isl_local_space_divs_known(__isl_keep isl_local_space *ls);
+
+__isl_give isl_local_space *isl_local_space_substitute_equalities(
+	__isl_take isl_local_space *ls, __isl_take isl_basic_set *eq);
+
+isl_bool isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type);
+
+isl_bool isl_local_space_has_equal_space(__isl_keep isl_local_space *ls1,
+	__isl_keep isl_local_space *ls2);
+
+__isl_give isl_local_space *isl_local_space_reset_space(
+	__isl_take isl_local_space *ls, __isl_take isl_space *dim);
+__isl_give isl_local_space *isl_local_space_realign(
+	__isl_take isl_local_space *ls, __isl_take isl_reordering *r);
+
+isl_bool isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls,
+	isl_int *constraint, unsigned div);
+
+int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l);
+
+__isl_give isl_local_space *isl_local_space_substitute_seq(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len,
+	int first, int n);
+__isl_give isl_local_space *isl_local_space_substitute(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs);
+
+__isl_give isl_local_space *isl_local_space_lift(
+	__isl_take isl_local_space *ls);
+
+__isl_give isl_local_space *isl_local_space_preimage_multi_aff(
+	__isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma);
+
+__isl_give isl_local_space *isl_local_space_move_dims(
+	__isl_take isl_local_space *ls,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n);
+
+int isl_local_space_cmp(__isl_keep isl_local_space *ls1,
+	__isl_keep isl_local_space *ls2);
+
+#endif
diff --git a/final/lib/External/isl/isl_lp.c b/final/lib/External/isl/isl_lp.c
new file mode 100644
index 0000000..0c2f5ff
--- /dev/null
+++ b/final/lib/External/isl/isl_lp.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/lp.h>
+#include <isl_seq.h>
+#include "isl_tab.h"
+#include <isl_options_private.h>
+#include <isl_local_space_private.h>
+#include <isl_aff_private.h>
+#include <isl_mat_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+
+#include <bset_to_bmap.c>
+#include <set_to_map.c>
+
+enum isl_lp_result isl_tab_solve_lp(__isl_keep isl_basic_map *bmap,
+	int maximize, isl_int *f, isl_int denom, isl_int *opt,
+	isl_int *opt_denom, __isl_give isl_vec **sol)
+{
+	struct isl_tab *tab;
+	enum isl_lp_result res;
+	unsigned dim = isl_basic_map_total_dim(bmap);
+
+	if (maximize)
+		isl_seq_neg(f, f, 1 + dim);
+
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	tab = isl_tab_from_basic_map(bmap, 0);
+	res = isl_tab_min(tab, f, denom, opt, opt_denom, 0);
+	if (res == isl_lp_ok && sol) {
+		*sol = isl_tab_get_sample_value(tab);
+		if (!*sol)
+			res = isl_lp_error;
+	}
+	isl_tab_free(tab);
+
+	if (maximize)
+		isl_seq_neg(f, f, 1 + dim);
+	if (maximize && opt)
+		isl_int_neg(*opt, *opt);
+
+	return res;
+}
+
+/* Given a basic map "bmap" and an affine combination of the variables "f"
+ * with denominator "denom", set *opt / *opt_denom to the minimal
+ * (or maximal if "maximize" is true) value attained by f/d over "bmap",
+ * assuming the basic map is not empty and the expression cannot attain
+ * arbitrarily small (or large) values.
+ * If opt_denom is NULL, then *opt is rounded up (or down)
+ * to the nearest integer.
+ * The return value reflects the nature of the result (empty, unbounded,
+ * minimal or maximal value returned in *opt).
+ */
+enum isl_lp_result isl_basic_map_solve_lp(__isl_keep isl_basic_map *bmap,
+	int max, isl_int *f, isl_int d, isl_int *opt, isl_int *opt_denom,
+	__isl_give isl_vec **sol)
+{
+	if (sol)
+		*sol = NULL;
+
+	if (!bmap)
+		return isl_lp_error;
+
+	return isl_tab_solve_lp(bmap, max, f, d, opt, opt_denom, sol);
+}
+
+enum isl_lp_result isl_basic_set_solve_lp(struct isl_basic_set *bset, int max,
+				      isl_int *f, isl_int d, isl_int *opt,
+				      isl_int *opt_denom,
+				      struct isl_vec **sol)
+{
+	return isl_basic_map_solve_lp(bset_to_bmap(bset), max,
+					f, d, opt, opt_denom, sol);
+}
+
+enum isl_lp_result isl_map_solve_lp(__isl_keep isl_map *map, int max,
+				      isl_int *f, isl_int d, isl_int *opt,
+				      isl_int *opt_denom,
+				      struct isl_vec **sol)
+{
+	int i;
+	isl_int o;
+	isl_int t;
+	isl_int opt_i;
+	isl_int opt_denom_i;
+	enum isl_lp_result res;
+	int max_div;
+	isl_vec *v = NULL;
+
+	if (!map)
+		return isl_lp_error;
+	if (map->n == 0)
+		return isl_lp_empty;
+
+	max_div = 0;
+	for (i = 0; i < map->n; ++i)
+		if (map->p[i]->n_div > max_div)
+			max_div = map->p[i]->n_div;
+	if (max_div > 0) {
+		unsigned total = isl_space_dim(map->dim, isl_dim_all);
+		v = isl_vec_alloc(map->ctx, 1 + total + max_div);
+		if (!v)
+			return isl_lp_error;
+		isl_seq_cpy(v->el, f, 1 + total);
+		isl_seq_clr(v->el + 1 + total, max_div);
+		f = v->el;
+	}
+
+	if (!opt && map->n > 1 && sol) {
+		isl_int_init(o);
+		opt = &o;
+	}
+	if (map->n > 0)
+		isl_int_init(opt_i);
+	if (map->n > 0 && opt_denom) {
+		isl_int_init(opt_denom_i);
+		isl_int_init(t);
+	}
+
+	res = isl_basic_map_solve_lp(map->p[0], max, f, d,
+					opt, opt_denom, sol);
+	if (res == isl_lp_error || res == isl_lp_unbounded)
+		goto done;
+
+	if (sol)
+		*sol = NULL;
+
+	for (i = 1; i < map->n; ++i) {
+		isl_vec *sol_i = NULL;
+		enum isl_lp_result res_i;
+		int better;
+
+		res_i = isl_basic_map_solve_lp(map->p[i], max, f, d,
+					    &opt_i,
+					    opt_denom ? &opt_denom_i : NULL,
+					    sol ? &sol_i : NULL);
+		if (res_i == isl_lp_error || res_i == isl_lp_unbounded) {
+			res = res_i;
+			goto done;
+		}
+		if (res_i == isl_lp_empty)
+			continue;
+		if (res == isl_lp_empty) {
+			better = 1;
+		} else if (!opt_denom) {
+			if (max)
+				better = isl_int_gt(opt_i, *opt);
+			else
+				better = isl_int_lt(opt_i, *opt);
+		} else {
+			isl_int_mul(t, opt_i, *opt_denom);
+			isl_int_submul(t, *opt, opt_denom_i);
+			if (max)
+				better = isl_int_is_pos(t);
+			else
+				better = isl_int_is_neg(t);
+		}
+		if (better) {
+			res = res_i;
+			if (opt)
+				isl_int_set(*opt, opt_i);
+			if (opt_denom)
+				isl_int_set(*opt_denom, opt_denom_i);
+			if (sol) {
+				isl_vec_free(*sol);
+				*sol = sol_i;
+			}
+		} else
+			isl_vec_free(sol_i);
+	}
+
+done:
+	isl_vec_free(v);
+	if (map->n > 0 && opt_denom) {
+		isl_int_clear(opt_denom_i);
+		isl_int_clear(t);
+	}
+	if (map->n > 0)
+		isl_int_clear(opt_i);
+	if (opt == &o)
+		isl_int_clear(o);
+	return res;
+}
+
+enum isl_lp_result isl_set_solve_lp(__isl_keep isl_set *set, int max,
+				      isl_int *f, isl_int d, isl_int *opt,
+				      isl_int *opt_denom,
+				      struct isl_vec **sol)
+{
+	return isl_map_solve_lp(set_to_map(set), max,
+					f, d, opt, opt_denom, sol);
+}
+
+/* Return the optimal (rational) value of "obj" over "bset", assuming
+ * that "obj" and "bset" have aligned parameters and divs.
+ * If "max" is set, then the maximal value is computed.
+ * Otherwise, the minimal value is computed.
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ *
+ * Call isl_basic_set_solve_lp and translate the results.
+ */
+static __isl_give isl_val *basic_set_opt_lp(
+	__isl_keep isl_basic_set *bset, int max, __isl_keep isl_aff *obj)
+{
+	isl_ctx *ctx;
+	isl_val *res;
+	enum isl_lp_result lp_res;
+
+	if (!bset || !obj)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(obj);
+	res = isl_val_alloc(ctx);
+	if (!res)
+		return NULL;
+	lp_res = isl_basic_set_solve_lp(bset, max, obj->v->el + 1,
+					obj->v->el[0], &res->n, &res->d, NULL);
+	if (lp_res == isl_lp_ok)
+		return isl_val_normalize(res);
+	isl_val_free(res);
+	if (lp_res == isl_lp_error)
+		return NULL;
+	if (lp_res == isl_lp_empty)
+		return isl_val_nan(ctx);
+	if (max)
+		return isl_val_infty(ctx);
+	else
+		return isl_val_neginfty(ctx);
+}
+
+/* Return the optimal (rational) value of "obj" over "bset", assuming
+ * that "obj" and "bset" have aligned parameters.
+ * If "max" is set, then the maximal value is computed.
+ * Otherwise, the minimal value is computed.
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ *
+ * Align the divs of "bset" and "obj" and call basic_set_opt_lp.
+ */
+static __isl_give isl_val *isl_basic_set_opt_lp_val_aligned(
+	__isl_keep isl_basic_set *bset, int max, __isl_keep isl_aff *obj)
+{
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_ctx *ctx;
+	isl_mat *bset_div = NULL;
+	isl_mat *div = NULL;
+	isl_val *res;
+	int bset_n_div, obj_n_div;
+
+	if (!bset || !obj)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(obj);
+	if (!isl_space_is_equal(bset->dim, obj->ls->dim))
+		isl_die(ctx, isl_error_invalid,
+			"spaces don't match", return NULL);
+
+	bset_n_div = isl_basic_set_dim(bset, isl_dim_div);
+	obj_n_div = isl_aff_dim(obj, isl_dim_div);
+	if (bset_n_div == 0 && obj_n_div == 0)
+		return basic_set_opt_lp(bset, max, obj);
+
+	bset = isl_basic_set_copy(bset);
+	obj = isl_aff_copy(obj);
+
+	bset_div = isl_basic_set_get_divs(bset);
+	exp1 = isl_alloc_array(ctx, int, bset_n_div);
+	exp2 = isl_alloc_array(ctx, int, obj_n_div);
+	if (!bset_div || (bset_n_div && !exp1) || (obj_n_div && !exp2))
+		goto error;
+
+	div = isl_merge_divs(bset_div, obj->ls->div, exp1, exp2);
+
+	bset = isl_basic_set_expand_divs(bset, isl_mat_copy(div), exp1);
+	obj = isl_aff_expand_divs(obj, isl_mat_copy(div), exp2);
+
+	res = basic_set_opt_lp(bset, max, obj);
+
+	isl_mat_free(bset_div);
+	isl_mat_free(div);
+	free(exp1);
+	free(exp2);
+	isl_basic_set_free(bset);
+	isl_aff_free(obj);
+
+	return res;
+error:
+	isl_mat_free(div);
+	isl_mat_free(bset_div);
+	free(exp1);
+	free(exp2);
+	isl_basic_set_free(bset);
+	isl_aff_free(obj);
+	return NULL;
+}
+
+/* Return the optimal (rational) value of "obj" over "bset".
+ * If "max" is set, then the maximal value is computed.
+ * Otherwise, the minimal value is computed.
+ *
+ * Return infinity or negative infinity if the optimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+static __isl_give isl_val *isl_basic_set_opt_lp_val(
+	__isl_keep isl_basic_set *bset, int max, __isl_keep isl_aff *obj)
+{
+	isl_bool equal;
+	isl_val *res;
+
+	if (!bset || !obj)
+		return NULL;
+
+	equal = isl_basic_set_space_has_equal_params(bset, obj->ls->dim);
+	if (equal < 0)
+		return NULL;
+	if (equal)
+		return isl_basic_set_opt_lp_val_aligned(bset, max, obj);
+
+	bset = isl_basic_set_copy(bset);
+	obj = isl_aff_copy(obj);
+	bset = isl_basic_set_align_params(bset, isl_aff_get_domain_space(obj));
+	obj = isl_aff_align_params(obj, isl_basic_set_get_space(bset));
+
+	res = isl_basic_set_opt_lp_val_aligned(bset, max, obj);
+
+	isl_basic_set_free(bset);
+	isl_aff_free(obj);
+
+	return res;
+}
+
+/* Return the minimal (rational) value of "obj" over "bset".
+ *
+ * Return negative infinity if the minimal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_basic_set_min_lp_val(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_aff *obj)
+{
+	return isl_basic_set_opt_lp_val(bset, 0, obj);
+}
+
+/* Return the maximal (rational) value of "obj" over "bset".
+ *
+ * Return infinity if the maximal value is unbounded and
+ * NaN if "bset" is empty.
+ */
+__isl_give isl_val *isl_basic_set_max_lp_val(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_aff *obj)
+{
+	return isl_basic_set_opt_lp_val(bset, 1, obj);
+}
diff --git a/final/lib/External/isl/isl_lp_private.h b/final/lib/External/isl/isl_lp_private.h
new file mode 100644
index 0000000..ddc44c1
--- /dev/null
+++ b/final/lib/External/isl/isl_lp_private.h
@@ -0,0 +1,21 @@
+#ifndef ISL_LP_PRIVATE_H
+#define ISL_LP_PRIVATE_H
+
+#include <isl_int.h>
+#include <isl/lp.h>
+#include <isl/vec.h>
+
+enum isl_lp_result isl_basic_map_solve_lp(__isl_keep isl_basic_map *bmap,
+	int max, isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+	__isl_give isl_vec **sol);
+enum isl_lp_result isl_basic_set_solve_lp(__isl_keep isl_basic_set *bset,
+	int max, isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+	__isl_give isl_vec **sol);
+enum isl_lp_result isl_map_solve_lp(__isl_keep isl_map *map, int max,
+	isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+	__isl_give isl_vec **sol);
+enum isl_lp_result isl_set_solve_lp(__isl_keep isl_set *set, int max,
+	isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+	__isl_give isl_vec **sol);
+
+#endif
diff --git a/final/lib/External/isl/isl_map.c b/final/lib/External/isl/isl_map.c
new file mode 100644
index 0000000..cb3b376
--- /dev/null
+++ b/final/lib/External/isl/isl_map.c
@@ -0,0 +1,13650 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012-2014 Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ * Copyright 2016      INRIA Paris
+ * Copyright 2016      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12,
+ * CS 42112, 75589 Paris Cedex 12, France
+ */
+
+#include <string.h>
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_blk.h>
+#include <isl/constraint.h>
+#include "isl_space_private.h"
+#include "isl_equalities.h"
+#include <isl_lp_private.h>
+#include <isl_seq.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl_reordering.h>
+#include "isl_sample.h"
+#include <isl_sort.h>
+#include "isl_tab.h"
+#include <isl/vec.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl_dim_map.h>
+#include <isl_local_space_private.h>
+#include <isl_aff_private.h>
+#include <isl_options_private.h>
+#include <isl_morph.h>
+#include <isl_val_private.h>
+#include <isl/deprecated/map_int.h>
+#include <isl/deprecated/set_int.h>
+
+#include <bset_to_bmap.c>
+#include <bset_from_bmap.c>
+#include <set_to_map.c>
+#include <set_from_map.c>
+
+static unsigned n(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	switch (type) {
+	case isl_dim_param:	return dim->nparam;
+	case isl_dim_in:	return dim->n_in;
+	case isl_dim_out:	return dim->n_out;
+	case isl_dim_all:	return dim->nparam + dim->n_in + dim->n_out;
+	default:		return 0;
+	}
+}
+
+static unsigned pos(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	switch (type) {
+	case isl_dim_param:	return 1;
+	case isl_dim_in:	return 1 + dim->nparam;
+	case isl_dim_out:	return 1 + dim->nparam + dim->n_in;
+	default:		return 0;
+	}
+}
+
+unsigned isl_basic_map_dim(__isl_keep isl_basic_map *bmap,
+				enum isl_dim_type type)
+{
+	if (!bmap)
+		return 0;
+	switch (type) {
+	case isl_dim_cst:	return 1;
+	case isl_dim_param:
+	case isl_dim_in:
+	case isl_dim_out:	return isl_space_dim(bmap->dim, type);
+	case isl_dim_div:	return bmap->n_div;
+	case isl_dim_all:	return isl_basic_map_total_dim(bmap);
+	default:		return 0;
+	}
+}
+
+/* Return the space of "map".
+ */
+__isl_keep isl_space *isl_map_peek_space(__isl_keep const isl_map *map)
+{
+	return map ? map->dim : NULL;
+}
+
+unsigned isl_map_dim(__isl_keep isl_map *map, enum isl_dim_type type)
+{
+	return map ? n(map->dim, type) : 0;
+}
+
+unsigned isl_set_dim(__isl_keep isl_set *set, enum isl_dim_type type)
+{
+	return set ? n(set->dim, type) : 0;
+}
+
+unsigned isl_basic_map_offset(struct isl_basic_map *bmap,
+					enum isl_dim_type type)
+{
+	isl_space *space;
+
+	if (!bmap)
+		return 0;
+
+	space = bmap->dim;
+	switch (type) {
+	case isl_dim_cst:	return 0;
+	case isl_dim_param:	return 1;
+	case isl_dim_in:	return 1 + space->nparam;
+	case isl_dim_out:	return 1 + space->nparam + space->n_in;
+	case isl_dim_div:	return 1 + space->nparam + space->n_in +
+								space->n_out;
+	default:		return 0;
+	}
+}
+
+unsigned isl_basic_set_offset(__isl_keep isl_basic_set *bset,
+					enum isl_dim_type type)
+{
+	return isl_basic_map_offset(bset, type);
+}
+
+static unsigned map_offset(__isl_keep isl_map *map, enum isl_dim_type type)
+{
+	return pos(map->dim, type);
+}
+
+unsigned isl_basic_set_dim(__isl_keep isl_basic_set *bset,
+				enum isl_dim_type type)
+{
+	return isl_basic_map_dim(bset, type);
+}
+
+unsigned isl_basic_set_n_dim(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_set_dim(bset, isl_dim_set);
+}
+
+unsigned isl_basic_set_n_param(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_set_dim(bset, isl_dim_param);
+}
+
+unsigned isl_basic_set_total_dim(__isl_keep const isl_basic_set *bset)
+{
+	if (!bset)
+		return 0;
+	return isl_space_dim(bset->dim, isl_dim_all) + bset->n_div;
+}
+
+unsigned isl_set_n_dim(__isl_keep isl_set *set)
+{
+	return isl_set_dim(set, isl_dim_set);
+}
+
+unsigned isl_set_n_param(__isl_keep isl_set *set)
+{
+	return isl_set_dim(set, isl_dim_param);
+}
+
+unsigned isl_basic_map_n_in(__isl_keep const isl_basic_map *bmap)
+{
+	return bmap ? bmap->dim->n_in : 0;
+}
+
+unsigned isl_basic_map_n_out(__isl_keep const isl_basic_map *bmap)
+{
+	return bmap ? bmap->dim->n_out : 0;
+}
+
+unsigned isl_basic_map_n_param(__isl_keep const isl_basic_map *bmap)
+{
+	return bmap ? bmap->dim->nparam : 0;
+}
+
+unsigned isl_basic_map_n_div(__isl_keep const isl_basic_map *bmap)
+{
+	return bmap ? bmap->n_div : 0;
+}
+
+unsigned isl_basic_map_total_dim(__isl_keep const isl_basic_map *bmap)
+{
+	return bmap ? isl_space_dim(bmap->dim, isl_dim_all) + bmap->n_div : 0;
+}
+
+unsigned isl_map_n_in(__isl_keep const isl_map *map)
+{
+	return map ? map->dim->n_in : 0;
+}
+
+unsigned isl_map_n_out(__isl_keep const isl_map *map)
+{
+	return map ? map->dim->n_out : 0;
+}
+
+unsigned isl_map_n_param(__isl_keep const isl_map *map)
+{
+	return map ? map->dim->nparam : 0;
+}
+
+/* Return the number of equality constraints in the description of "bmap".
+ * Return -1 on error.
+ */
+int isl_basic_map_n_equality(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	return bmap->n_eq;
+}
+
+/* Return the number of equality constraints in the description of "bset".
+ * Return -1 on error.
+ */
+int isl_basic_set_n_equality(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_n_equality(bset_to_bmap(bset));
+}
+
+/* Return the number of inequality constraints in the description of "bmap".
+ * Return -1 on error.
+ */
+int isl_basic_map_n_inequality(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	return bmap->n_ineq;
+}
+
+/* Return the number of inequality constraints in the description of "bset".
+ * Return -1 on error.
+ */
+int isl_basic_set_n_inequality(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_n_inequality(bset_to_bmap(bset));
+}
+
+/* Do "bmap1" and "bmap2" have the same parameters?
+ */
+static isl_bool isl_basic_map_has_equal_params(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	isl_space *space1, *space2;
+
+	space1 = isl_basic_map_peek_space(bmap1);
+	space2 = isl_basic_map_peek_space(bmap2);
+	return isl_space_has_equal_params(space1, space2);
+}
+
+/* Do "map1" and "map2" have the same parameters?
+ */
+isl_bool isl_map_has_equal_params(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2)
+{
+	isl_space *space1, *space2;
+
+	space1 = isl_map_peek_space(map1);
+	space2 = isl_map_peek_space(map2);
+	return isl_space_has_equal_params(space1, space2);
+}
+
+/* Do "map" and "set" have the same parameters?
+ */
+static isl_bool isl_map_set_has_equal_params(__isl_keep isl_map *map,
+	__isl_keep isl_set *set)
+{
+	return isl_map_has_equal_params(map, set_to_map(set));
+}
+
+isl_bool isl_map_compatible_domain(__isl_keep isl_map *map,
+	__isl_keep isl_set *set)
+{
+	isl_bool m;
+	if (!map || !set)
+		return isl_bool_error;
+	m = isl_map_has_equal_params(map, set_to_map(set));
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(map->dim, isl_dim_in,
+					set->dim, isl_dim_set);
+}
+
+isl_bool isl_basic_map_compatible_domain(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_basic_set *bset)
+{
+	isl_bool m;
+	if (!bmap || !bset)
+		return isl_bool_error;
+	m = isl_basic_map_has_equal_params(bmap, bset_to_bmap(bset));
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(bmap->dim, isl_dim_in,
+					bset->dim, isl_dim_set);
+}
+
+isl_bool isl_map_compatible_range(__isl_keep isl_map *map,
+	__isl_keep isl_set *set)
+{
+	isl_bool m;
+	if (!map || !set)
+		return isl_bool_error;
+	m = isl_map_has_equal_params(map, set_to_map(set));
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(map->dim, isl_dim_out,
+					set->dim, isl_dim_set);
+}
+
+isl_bool isl_basic_map_compatible_range(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_basic_set *bset)
+{
+	isl_bool m;
+	if (!bmap || !bset)
+		return isl_bool_error;
+	m = isl_basic_map_has_equal_params(bmap, bset_to_bmap(bset));
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(bmap->dim, isl_dim_out,
+					bset->dim, isl_dim_set);
+}
+
+isl_ctx *isl_basic_map_get_ctx(__isl_keep isl_basic_map *bmap)
+{
+	return bmap ? bmap->ctx : NULL;
+}
+
+isl_ctx *isl_basic_set_get_ctx(__isl_keep isl_basic_set *bset)
+{
+	return bset ? bset->ctx : NULL;
+}
+
+isl_ctx *isl_map_get_ctx(__isl_keep isl_map *map)
+{
+	return map ? map->ctx : NULL;
+}
+
+isl_ctx *isl_set_get_ctx(__isl_keep isl_set *set)
+{
+	return set ? set->ctx : NULL;
+}
+
+/* Return the space of "bmap".
+ */
+__isl_keep isl_space *isl_basic_map_peek_space(
+	__isl_keep const isl_basic_map *bmap)
+{
+	return bmap ? bmap->dim : NULL;
+}
+
+/* Return the space of "bset".
+ */
+__isl_keep isl_space *isl_basic_set_peek_space(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_peek_space(bset_to_bmap(bset));
+}
+
+__isl_give isl_space *isl_basic_map_get_space(__isl_keep isl_basic_map *bmap)
+{
+	return isl_space_copy(isl_basic_map_peek_space(bmap));
+}
+
+__isl_give isl_space *isl_basic_set_get_space(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_get_space(bset_to_bmap(bset));
+}
+
+/* Extract the divs in "bmap" as a matrix.
+ */
+__isl_give isl_mat *isl_basic_map_get_divs(__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_mat *div;
+	unsigned total;
+	unsigned cols;
+
+	if (!bmap)
+		return NULL;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+	cols = 1 + 1 + total + bmap->n_div;
+	div = isl_mat_alloc(ctx, bmap->n_div, cols);
+	if (!div)
+		return NULL;
+
+	for (i = 0; i < bmap->n_div; ++i)
+		isl_seq_cpy(div->row[i], bmap->div[i], cols);
+
+	return div;
+}
+
+/* Extract the divs in "bset" as a matrix.
+ */
+__isl_give isl_mat *isl_basic_set_get_divs(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_get_divs(bset);
+}
+
+__isl_give isl_local_space *isl_basic_map_get_local_space(
+	__isl_keep isl_basic_map *bmap)
+{
+	isl_mat *div;
+
+	if (!bmap)
+		return NULL;
+
+	div = isl_basic_map_get_divs(bmap);
+	return isl_local_space_alloc_div(isl_space_copy(bmap->dim), div);
+}
+
+__isl_give isl_local_space *isl_basic_set_get_local_space(
+	__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_get_local_space(bset);
+}
+
+/* For each known div d = floor(f/m), add the constraints
+ *
+ *		f - m d >= 0
+ *		-(f-(m-1)) + m d >= 0
+ *
+ * Do not finalize the result.
+ */
+static __isl_give isl_basic_map *add_known_div_constraints(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+	unsigned n_div;
+
+	if (!bmap)
+		return NULL;
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	if (n_div == 0)
+		return bmap;
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_extend_constraints(bmap, 0, 2 * n_div);
+	if (!bmap)
+		return NULL;
+	for (i = 0; i < n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (isl_basic_map_add_div_constraints(bmap, i) < 0)
+			return isl_basic_map_free(bmap);
+	}
+
+	return bmap;
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_local_space(
+	__isl_take isl_local_space *ls)
+{
+	int i;
+	int n_div;
+	isl_basic_map *bmap;
+
+	if (!ls)
+		return NULL;
+
+	n_div = isl_local_space_dim(ls, isl_dim_div);
+	bmap = isl_basic_map_alloc_space(isl_local_space_get_space(ls),
+					n_div, 0, 2 * n_div);
+
+	for (i = 0; i < n_div; ++i)
+		if (isl_basic_map_alloc_div(bmap) < 0)
+			goto error;
+
+	for (i = 0; i < n_div; ++i)
+		isl_seq_cpy(bmap->div[i], ls->div->row[i], ls->div->n_col);
+	bmap = add_known_div_constraints(bmap);
+					
+	isl_local_space_free(ls);
+	return bmap;
+error:
+	isl_local_space_free(ls);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_from_local_space(
+	__isl_take isl_local_space *ls)
+{
+	return isl_basic_map_from_local_space(ls);
+}
+
+__isl_give isl_space *isl_map_get_space(__isl_keep isl_map *map)
+{
+	return isl_space_copy(isl_map_peek_space(map));
+}
+
+__isl_give isl_space *isl_set_get_space(__isl_keep isl_set *set)
+{
+	if (!set)
+		return NULL;
+	return isl_space_copy(set->dim);
+}
+
+__isl_give isl_basic_map *isl_basic_map_set_tuple_name(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type, const char *s)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	bmap->dim = isl_space_set_tuple_name(bmap->dim, type, s);
+	if (!bmap->dim)
+		goto error;
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_set_tuple_name(
+	__isl_take isl_basic_set *bset, const char *s)
+{
+	return isl_basic_map_set_tuple_name(bset, isl_dim_set, s);
+}
+
+const char *isl_basic_map_get_tuple_name(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type)
+{
+	return bmap ? isl_space_get_tuple_name(bmap->dim, type) : NULL;
+}
+
+__isl_give isl_map *isl_map_set_tuple_name(__isl_take isl_map *map,
+	enum isl_dim_type type, const char *s)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_set_tuple_name(map->dim, type, s);
+	if (!map->dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_set_tuple_name(map->p[i], type, s);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Replace the identifier of the tuple of type "type" by "id".
+ */
+__isl_give isl_basic_map *isl_basic_map_set_tuple_id(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, __isl_take isl_id *id)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		goto error;
+	bmap->dim = isl_space_set_tuple_id(bmap->dim, type, id);
+	if (!bmap->dim)
+		return isl_basic_map_free(bmap);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+/* Replace the identifier of the tuple by "id".
+ */
+__isl_give isl_basic_set *isl_basic_set_set_tuple_id(
+	__isl_take isl_basic_set *bset, __isl_take isl_id *id)
+{
+	return isl_basic_map_set_tuple_id(bset, isl_dim_set, id);
+}
+
+/* Does the input or output tuple have a name?
+ */
+isl_bool isl_map_has_tuple_name(__isl_keep isl_map *map, enum isl_dim_type type)
+{
+	return map ? isl_space_has_tuple_name(map->dim, type) : isl_bool_error;
+}
+
+const char *isl_map_get_tuple_name(__isl_keep isl_map *map,
+	enum isl_dim_type type)
+{
+	return map ? isl_space_get_tuple_name(map->dim, type) : NULL;
+}
+
+__isl_give isl_set *isl_set_set_tuple_name(__isl_take isl_set *set,
+	const char *s)
+{
+	return set_from_map(isl_map_set_tuple_name(set_to_map(set),
+						isl_dim_set, s));
+}
+
+__isl_give isl_map *isl_map_set_tuple_id(__isl_take isl_map *map,
+	enum isl_dim_type type, __isl_take isl_id *id)
+{
+	map = isl_map_cow(map);
+	if (!map)
+		goto error;
+
+	map->dim = isl_space_set_tuple_id(map->dim, type, id);
+
+	return isl_map_reset_space(map, isl_space_copy(map->dim));
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_set_tuple_id(__isl_take isl_set *set,
+	__isl_take isl_id *id)
+{
+	return isl_map_set_tuple_id(set, isl_dim_set, id);
+}
+
+__isl_give isl_map *isl_map_reset_tuple_id(__isl_take isl_map *map,
+	enum isl_dim_type type)
+{
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_reset_tuple_id(map->dim, type);
+
+	return isl_map_reset_space(map, isl_space_copy(map->dim));
+}
+
+__isl_give isl_set *isl_set_reset_tuple_id(__isl_take isl_set *set)
+{
+	return isl_map_reset_tuple_id(set, isl_dim_set);
+}
+
+isl_bool isl_map_has_tuple_id(__isl_keep isl_map *map, enum isl_dim_type type)
+{
+	return map ? isl_space_has_tuple_id(map->dim, type) : isl_bool_error;
+}
+
+__isl_give isl_id *isl_map_get_tuple_id(__isl_keep isl_map *map,
+	enum isl_dim_type type)
+{
+	return map ? isl_space_get_tuple_id(map->dim, type) : NULL;
+}
+
+isl_bool isl_set_has_tuple_id(__isl_keep isl_set *set)
+{
+	return isl_map_has_tuple_id(set, isl_dim_set);
+}
+
+__isl_give isl_id *isl_set_get_tuple_id(__isl_keep isl_set *set)
+{
+	return isl_map_get_tuple_id(set, isl_dim_set);
+}
+
+/* Does the set tuple have a name?
+ */
+isl_bool isl_set_has_tuple_name(__isl_keep isl_set *set)
+{
+	if (!set)
+		return isl_bool_error;
+	return isl_space_has_tuple_name(set->dim, isl_dim_set);
+}
+
+
+const char *isl_basic_set_get_tuple_name(__isl_keep isl_basic_set *bset)
+{
+	return bset ? isl_space_get_tuple_name(bset->dim, isl_dim_set) : NULL;
+}
+
+const char *isl_set_get_tuple_name(__isl_keep isl_set *set)
+{
+	return set ? isl_space_get_tuple_name(set->dim, isl_dim_set) : NULL;
+}
+
+const char *isl_basic_map_get_dim_name(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos)
+{
+	return bmap ? isl_space_get_dim_name(bmap->dim, type, pos) : NULL;
+}
+
+const char *isl_basic_set_get_dim_name(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos)
+{
+	return bset ? isl_space_get_dim_name(bset->dim, type, pos) : NULL;
+}
+
+/* Does the given dimension have a name?
+ */
+isl_bool isl_map_has_dim_name(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!map)
+		return isl_bool_error;
+	return isl_space_has_dim_name(map->dim, type, pos);
+}
+
+const char *isl_map_get_dim_name(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	return map ? isl_space_get_dim_name(map->dim, type, pos) : NULL;
+}
+
+const char *isl_set_get_dim_name(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return set ? isl_space_get_dim_name(set->dim, type, pos) : NULL;
+}
+
+/* Does the given dimension have a name?
+ */
+isl_bool isl_set_has_dim_name(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!set)
+		return isl_bool_error;
+	return isl_space_has_dim_name(set->dim, type, pos);
+}
+
+__isl_give isl_basic_map *isl_basic_map_set_dim_name(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	bmap->dim = isl_space_set_dim_name(bmap->dim, type, pos, s);
+	if (!bmap->dim)
+		goto error;
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_set_dim_name(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_set_dim_name(map->dim, type, pos, s);
+	if (!map->dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_set_dim_name(map->p[i], type, pos, s);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_set_dim_name(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	return bset_from_bmap(isl_basic_map_set_dim_name(bset_to_bmap(bset),
+							type, pos, s));
+}
+
+__isl_give isl_set *isl_set_set_dim_name(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	return set_from_map(isl_map_set_dim_name(set_to_map(set),
+							type, pos, s));
+}
+
+isl_bool isl_basic_map_has_dim_id(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!bmap)
+		return isl_bool_error;
+	return isl_space_has_dim_id(bmap->dim, type, pos);
+}
+
+__isl_give isl_id *isl_basic_set_get_dim_id(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos)
+{
+	return bset ? isl_space_get_dim_id(bset->dim, type, pos) : NULL;
+}
+
+isl_bool isl_map_has_dim_id(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	return map ? isl_space_has_dim_id(map->dim, type, pos) : isl_bool_error;
+}
+
+__isl_give isl_id *isl_map_get_dim_id(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	return map ? isl_space_get_dim_id(map->dim, type, pos) : NULL;
+}
+
+isl_bool isl_set_has_dim_id(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_map_has_dim_id(set, type, pos);
+}
+
+__isl_give isl_id *isl_set_get_dim_id(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_map_get_dim_id(set, type, pos);
+}
+
+__isl_give isl_map *isl_map_set_dim_id(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	map = isl_map_cow(map);
+	if (!map)
+		goto error;
+
+	map->dim = isl_space_set_dim_id(map->dim, type, pos, id);
+
+	return isl_map_reset_space(map, isl_space_copy(map->dim));
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_set_dim_id(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	return isl_map_set_dim_id(set, type, pos, id);
+}
+
+int isl_map_find_dim_by_id(__isl_keep isl_map *map, enum isl_dim_type type,
+	__isl_keep isl_id *id)
+{
+	if (!map)
+		return -1;
+	return isl_space_find_dim_by_id(map->dim, type, id);
+}
+
+int isl_set_find_dim_by_id(__isl_keep isl_set *set, enum isl_dim_type type,
+	__isl_keep isl_id *id)
+{
+	return isl_map_find_dim_by_id(set, type, id);
+}
+
+/* Return the position of the dimension of the given type and name
+ * in "bmap".
+ * Return -1 if no such dimension can be found.
+ */
+int isl_basic_map_find_dim_by_name(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, const char *name)
+{
+	if (!bmap)
+		return -1;
+	return isl_space_find_dim_by_name(bmap->dim, type, name);
+}
+
+int isl_map_find_dim_by_name(__isl_keep isl_map *map, enum isl_dim_type type,
+	const char *name)
+{
+	if (!map)
+		return -1;
+	return isl_space_find_dim_by_name(map->dim, type, name);
+}
+
+int isl_set_find_dim_by_name(__isl_keep isl_set *set, enum isl_dim_type type,
+	const char *name)
+{
+	return isl_map_find_dim_by_name(set, type, name);
+}
+
+/* Check whether equality i of bset is a pure stride constraint
+ * on a single dimension, i.e., of the form
+ *
+ *	v = k e
+ *
+ * with k a constant and e an existentially quantified variable.
+ */
+isl_bool isl_basic_set_eq_is_stride(__isl_keep isl_basic_set *bset, int i)
+{
+	unsigned nparam;
+	unsigned d;
+	unsigned n_div;
+	int pos1;
+	int pos2;
+
+	if (!bset)
+		return isl_bool_error;
+
+	if (!isl_int_is_zero(bset->eq[i][0]))
+		return isl_bool_false;
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	d = isl_basic_set_dim(bset, isl_dim_set);
+	n_div = isl_basic_set_dim(bset, isl_dim_div);
+
+	if (isl_seq_first_non_zero(bset->eq[i] + 1, nparam) != -1)
+		return isl_bool_false;
+	pos1 = isl_seq_first_non_zero(bset->eq[i] + 1 + nparam, d);
+	if (pos1 == -1)
+		return isl_bool_false;
+	if (isl_seq_first_non_zero(bset->eq[i] + 1 + nparam + pos1 + 1,
+					d - pos1 - 1) != -1)
+		return isl_bool_false;
+
+	pos2 = isl_seq_first_non_zero(bset->eq[i] + 1 + nparam + d, n_div);
+	if (pos2 == -1)
+		return isl_bool_false;
+	if (isl_seq_first_non_zero(bset->eq[i] + 1 + nparam + d  + pos2 + 1,
+				   n_div - pos2 - 1) != -1)
+		return isl_bool_false;
+	if (!isl_int_is_one(bset->eq[i][1 + nparam + pos1]) &&
+	    !isl_int_is_negone(bset->eq[i][1 + nparam + pos1]))
+		return isl_bool_false;
+
+	return isl_bool_true;
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the space of "map".
+ */
+__isl_give isl_map *isl_map_reset_user(__isl_take isl_map *map)
+{
+	isl_space *space;
+
+	space = isl_map_get_space(map);
+	space = isl_space_reset_user(space);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the space of "set".
+ */
+__isl_give isl_set *isl_set_reset_user(__isl_take isl_set *set)
+{
+	return isl_map_reset_user(set);
+}
+
+isl_bool isl_basic_map_is_rational(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return isl_bool_error;
+	return ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+}
+
+/* Has "map" been marked as a rational map?
+ * In particular, have all basic maps in "map" been marked this way?
+ * An empty map is not considered to be rational.
+ * Maps where only some of the basic maps are marked rational
+ * are not allowed.
+ */
+isl_bool isl_map_is_rational(__isl_keep isl_map *map)
+{
+	int i;
+	isl_bool rational;
+
+	if (!map)
+		return isl_bool_error;
+	if (map->n == 0)
+		return isl_bool_false;
+	rational = isl_basic_map_is_rational(map->p[0]);
+	if (rational < 0)
+		return rational;
+	for (i = 1; i < map->n; ++i) {
+		isl_bool rational_i;
+
+		rational_i = isl_basic_map_is_rational(map->p[i]);
+		if (rational_i < 0)
+			return rational_i;
+		if (rational != rational_i)
+			isl_die(isl_map_get_ctx(map), isl_error_unsupported,
+				"mixed rational and integer basic maps "
+				"not supported", return isl_bool_error);
+	}
+
+	return rational;
+}
+
+/* Has "set" been marked as a rational set?
+ * In particular, have all basic set in "set" been marked this way?
+ * An empty set is not considered to be rational.
+ * Sets where only some of the basic sets are marked rational
+ * are not allowed.
+ */
+isl_bool isl_set_is_rational(__isl_keep isl_set *set)
+{
+	return isl_map_is_rational(set);
+}
+
+int isl_basic_set_is_rational(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_is_rational(bset);
+}
+
+/* Does "bmap" contain any rational points?
+ *
+ * If "bmap" has an equality for each dimension, equating the dimension
+ * to an integer constant, then it has no rational points, even if it
+ * is marked as rational.
+ */
+isl_bool isl_basic_map_has_rational(__isl_keep isl_basic_map *bmap)
+{
+	isl_bool has_rational = isl_bool_true;
+	unsigned total;
+
+	if (!bmap)
+		return isl_bool_error;
+	if (isl_basic_map_plain_is_empty(bmap))
+		return isl_bool_false;
+	if (!isl_basic_map_is_rational(bmap))
+		return isl_bool_false;
+	bmap = isl_basic_map_copy(bmap);
+	bmap = isl_basic_map_implicit_equalities(bmap);
+	if (!bmap)
+		return isl_bool_error;
+	total = isl_basic_map_total_dim(bmap);
+	if (bmap->n_eq == total) {
+		int i, j;
+		for (i = 0; i < bmap->n_eq; ++i) {
+			j = isl_seq_first_non_zero(bmap->eq[i] + 1, total);
+			if (j < 0)
+				break;
+			if (!isl_int_is_one(bmap->eq[i][1 + j]) &&
+			    !isl_int_is_negone(bmap->eq[i][1 + j]))
+				break;
+			j = isl_seq_first_non_zero(bmap->eq[i] + 1 + j + 1,
+						    total - j - 1);
+			if (j >= 0)
+				break;
+		}
+		if (i == bmap->n_eq)
+			has_rational = isl_bool_false;
+	}
+	isl_basic_map_free(bmap);
+
+	return has_rational;
+}
+
+/* Does "map" contain any rational points?
+ */
+isl_bool isl_map_has_rational(__isl_keep isl_map *map)
+{
+	int i;
+	isl_bool has_rational;
+
+	if (!map)
+		return isl_bool_error;
+	for (i = 0; i < map->n; ++i) {
+		has_rational = isl_basic_map_has_rational(map->p[i]);
+		if (has_rational < 0 || has_rational)
+			return has_rational;
+	}
+	return isl_bool_false;
+}
+
+/* Does "set" contain any rational points?
+ */
+isl_bool isl_set_has_rational(__isl_keep isl_set *set)
+{
+	return isl_map_has_rational(set);
+}
+
+/* Is this basic set a parameter domain?
+ */
+isl_bool isl_basic_set_is_params(__isl_keep isl_basic_set *bset)
+{
+	if (!bset)
+		return isl_bool_error;
+	return isl_space_is_params(bset->dim);
+}
+
+/* Is this set a parameter domain?
+ */
+isl_bool isl_set_is_params(__isl_keep isl_set *set)
+{
+	if (!set)
+		return isl_bool_error;
+	return isl_space_is_params(set->dim);
+}
+
+/* Is this map actually a parameter domain?
+ * Users should never call this function.  Outside of isl,
+ * a map can never be a parameter domain.
+ */
+isl_bool isl_map_is_params(__isl_keep isl_map *map)
+{
+	if (!map)
+		return isl_bool_error;
+	return isl_space_is_params(map->dim);
+}
+
+static struct isl_basic_map *basic_map_init(struct isl_ctx *ctx,
+		struct isl_basic_map *bmap, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	int i;
+	size_t row_size = 1 + isl_space_dim(bmap->dim, isl_dim_all) + extra;
+
+	bmap->ctx = ctx;
+	isl_ctx_ref(ctx);
+
+	bmap->block = isl_blk_alloc(ctx, (n_ineq + n_eq) * row_size);
+	if (isl_blk_is_error(bmap->block))
+		goto error;
+
+	bmap->ineq = isl_alloc_array(ctx, isl_int *, n_ineq + n_eq);
+	if ((n_ineq + n_eq) && !bmap->ineq)
+		goto error;
+
+	if (extra == 0) {
+		bmap->block2 = isl_blk_empty();
+		bmap->div = NULL;
+	} else {
+		bmap->block2 = isl_blk_alloc(ctx, extra * (1 + row_size));
+		if (isl_blk_is_error(bmap->block2))
+			goto error;
+
+		bmap->div = isl_alloc_array(ctx, isl_int *, extra);
+		if (!bmap->div)
+			goto error;
+	}
+
+	for (i = 0; i < n_ineq + n_eq; ++i)
+		bmap->ineq[i] = bmap->block.data + i * row_size;
+
+	for (i = 0; i < extra; ++i)
+		bmap->div[i] = bmap->block2.data + i * (1 + row_size);
+
+	bmap->ref = 1;
+	bmap->flags = 0;
+	bmap->c_size = n_eq + n_ineq;
+	bmap->eq = bmap->ineq + n_ineq;
+	bmap->extra = extra;
+	bmap->n_eq = 0;
+	bmap->n_ineq = 0;
+	bmap->n_div = 0;
+	bmap->sample = NULL;
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_alloc(struct isl_ctx *ctx,
+		unsigned nparam, unsigned dim, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	struct isl_basic_map *bmap;
+	isl_space *space;
+
+	space = isl_space_set_alloc(ctx, nparam, dim);
+	if (!space)
+		return NULL;
+
+	bmap = isl_basic_map_alloc_space(space, extra, n_eq, n_ineq);
+	return bset_from_bmap(bmap);
+}
+
+__isl_give isl_basic_set *isl_basic_set_alloc_space(__isl_take isl_space *dim,
+		unsigned extra, unsigned n_eq, unsigned n_ineq)
+{
+	struct isl_basic_map *bmap;
+	if (!dim)
+		return NULL;
+	isl_assert(dim->ctx, dim->n_in == 0, goto error);
+	bmap = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq);
+	return bset_from_bmap(bmap);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_alloc_space(__isl_take isl_space *dim,
+		unsigned extra, unsigned n_eq, unsigned n_ineq)
+{
+	struct isl_basic_map *bmap;
+
+	if (!dim)
+		return NULL;
+	bmap = isl_calloc_type(dim->ctx, struct isl_basic_map);
+	if (!bmap)
+		goto error;
+	bmap->dim = dim;
+
+	return basic_map_init(dim->ctx, bmap, extra, n_eq, n_ineq);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_alloc(struct isl_ctx *ctx,
+		unsigned nparam, unsigned in, unsigned out, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	struct isl_basic_map *bmap;
+	isl_space *dim;
+
+	dim = isl_space_alloc(ctx, nparam, in, out);
+	if (!dim)
+		return NULL;
+
+	bmap = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq);
+	return bmap;
+}
+
+static void dup_constraints(
+		struct isl_basic_map *dst, struct isl_basic_map *src)
+{
+	int i;
+	unsigned total = isl_basic_map_total_dim(src);
+
+	for (i = 0; i < src->n_eq; ++i) {
+		int j = isl_basic_map_alloc_equality(dst);
+		isl_seq_cpy(dst->eq[j], src->eq[i], 1+total);
+	}
+
+	for (i = 0; i < src->n_ineq; ++i) {
+		int j = isl_basic_map_alloc_inequality(dst);
+		isl_seq_cpy(dst->ineq[j], src->ineq[i], 1+total);
+	}
+
+	for (i = 0; i < src->n_div; ++i) {
+		int j = isl_basic_map_alloc_div(dst);
+		isl_seq_cpy(dst->div[j], src->div[i], 1+1+total);
+	}
+	ISL_F_SET(dst, ISL_BASIC_SET_FINAL);
+}
+
+__isl_give isl_basic_map *isl_basic_map_dup(__isl_keep isl_basic_map *bmap)
+{
+	struct isl_basic_map *dup;
+
+	if (!bmap)
+		return NULL;
+	dup = isl_basic_map_alloc_space(isl_space_copy(bmap->dim),
+			bmap->n_div, bmap->n_eq, bmap->n_ineq);
+	if (!dup)
+		return NULL;
+	dup_constraints(dup, bmap);
+	dup->flags = bmap->flags;
+	dup->sample = isl_vec_copy(bmap->sample);
+	return dup;
+}
+
+struct isl_basic_set *isl_basic_set_dup(struct isl_basic_set *bset)
+{
+	struct isl_basic_map *dup;
+
+	dup = isl_basic_map_dup(bset_to_bmap(bset));
+	return bset_from_bmap(dup);
+}
+
+__isl_give isl_basic_set *isl_basic_set_copy(__isl_keep isl_basic_set *bset)
+{
+	if (!bset)
+		return NULL;
+
+	if (ISL_F_ISSET(bset, ISL_BASIC_SET_FINAL)) {
+		bset->ref++;
+		return bset;
+	}
+	return isl_basic_set_dup(bset);
+}
+
+__isl_give isl_set *isl_set_copy(__isl_keep isl_set *set)
+{
+	if (!set)
+		return NULL;
+
+	set->ref++;
+	return set;
+}
+
+__isl_give isl_basic_map *isl_basic_map_copy(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_SET_FINAL)) {
+		bmap->ref++;
+		return bmap;
+	}
+	bmap = isl_basic_map_dup(bmap);
+	if (bmap)
+		ISL_F_SET(bmap, ISL_BASIC_SET_FINAL);
+	return bmap;
+}
+
+__isl_give isl_map *isl_map_copy(__isl_keep isl_map *map)
+{
+	if (!map)
+		return NULL;
+
+	map->ref++;
+	return map;
+}
+
+__isl_null isl_basic_map *isl_basic_map_free(__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (--bmap->ref > 0)
+		return NULL;
+
+	isl_ctx_deref(bmap->ctx);
+	free(bmap->div);
+	isl_blk_free(bmap->ctx, bmap->block2);
+	free(bmap->ineq);
+	isl_blk_free(bmap->ctx, bmap->block);
+	isl_vec_free(bmap->sample);
+	isl_space_free(bmap->dim);
+	free(bmap);
+
+	return NULL;
+}
+
+__isl_null isl_basic_set *isl_basic_set_free(__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_free(bset_to_bmap(bset));
+}
+
+static int room_for_con(struct isl_basic_map *bmap, unsigned n)
+{
+	return bmap->n_eq + bmap->n_ineq + n <= bmap->c_size;
+}
+
+/* Check that "map" has only named parameters, reporting an error
+ * if it does not.
+ */
+isl_stat isl_map_check_named_params(__isl_keep isl_map *map)
+{
+	return isl_space_check_named_params(isl_map_peek_space(map));
+}
+
+/* Check that "bmap1" and "bmap2" have the same parameters,
+ * reporting an error if they do not.
+ */
+static isl_stat isl_basic_map_check_equal_params(
+	__isl_keep isl_basic_map *bmap1, __isl_keep isl_basic_map *bmap2)
+{
+	isl_bool match;
+
+	match = isl_basic_map_has_equal_params(bmap1, bmap2);
+	if (match < 0)
+		return isl_stat_error;
+	if (!match)
+		isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+			"parameters don't match", return isl_stat_error);
+	return isl_stat_ok;
+}
+
+__isl_give isl_map *isl_map_align_params_map_map_and(
+	__isl_take isl_map *map1, __isl_take isl_map *map2,
+	__isl_give isl_map *(*fn)(__isl_take isl_map *map1,
+				    __isl_take isl_map *map2))
+{
+	if (!map1 || !map2)
+		goto error;
+	if (isl_map_has_equal_params(map1, map2))
+		return fn(map1, map2);
+	if (isl_map_check_named_params(map1) < 0)
+		goto error;
+	if (isl_map_check_named_params(map2) < 0)
+		goto error;
+	map1 = isl_map_align_params(map1, isl_map_get_space(map2));
+	map2 = isl_map_align_params(map2, isl_map_get_space(map1));
+	return fn(map1, map2);
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+isl_bool isl_map_align_params_map_map_and_test(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2,
+	isl_bool (*fn)(__isl_keep isl_map *map1, __isl_keep isl_map *map2))
+{
+	isl_bool r;
+
+	if (!map1 || !map2)
+		return isl_bool_error;
+	if (isl_map_has_equal_params(map1, map2))
+		return fn(map1, map2);
+	if (isl_map_check_named_params(map1) < 0)
+		return isl_bool_error;
+	if (isl_map_check_named_params(map2) < 0)
+		return isl_bool_error;
+	map1 = isl_map_copy(map1);
+	map2 = isl_map_copy(map2);
+	map1 = isl_map_align_params(map1, isl_map_get_space(map2));
+	map2 = isl_map_align_params(map2, isl_map_get_space(map1));
+	r = fn(map1, map2);
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return r;
+}
+
+int isl_basic_map_alloc_equality(struct isl_basic_map *bmap)
+{
+	struct isl_ctx *ctx;
+	if (!bmap)
+		return -1;
+	ctx = bmap->ctx;
+	isl_assert(ctx, room_for_con(bmap, 1), return -1);
+	isl_assert(ctx, (bmap->eq - bmap->ineq) + bmap->n_eq <= bmap->c_size,
+			return -1);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_IMPLICIT);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+	if ((bmap->eq - bmap->ineq) + bmap->n_eq == bmap->c_size) {
+		isl_int *t;
+		int j = isl_basic_map_alloc_inequality(bmap);
+		if (j < 0)
+			return -1;
+		t = bmap->ineq[j];
+		bmap->ineq[j] = bmap->ineq[bmap->n_ineq - 1];
+		bmap->ineq[bmap->n_ineq - 1] = bmap->eq[-1];
+		bmap->eq[-1] = t;
+		bmap->n_eq++;
+		bmap->n_ineq--;
+		bmap->eq--;
+		return 0;
+	}
+	isl_seq_clr(bmap->eq[bmap->n_eq] + 1 + isl_basic_map_total_dim(bmap),
+		      bmap->extra - bmap->n_div);
+	return bmap->n_eq++;
+}
+
+int isl_basic_set_alloc_equality(struct isl_basic_set *bset)
+{
+	return isl_basic_map_alloc_equality(bset_to_bmap(bset));
+}
+
+int isl_basic_map_free_equality(struct isl_basic_map *bmap, unsigned n)
+{
+	if (!bmap)
+		return -1;
+	isl_assert(bmap->ctx, n <= bmap->n_eq, return -1);
+	bmap->n_eq -= n;
+	return 0;
+}
+
+int isl_basic_set_free_equality(struct isl_basic_set *bset, unsigned n)
+{
+	return isl_basic_map_free_equality(bset_to_bmap(bset), n);
+}
+
+int isl_basic_map_drop_equality(struct isl_basic_map *bmap, unsigned pos)
+{
+	isl_int *t;
+	if (!bmap)
+		return -1;
+	isl_assert(bmap->ctx, pos < bmap->n_eq, return -1);
+
+	if (pos != bmap->n_eq - 1) {
+		t = bmap->eq[pos];
+		bmap->eq[pos] = bmap->eq[bmap->n_eq - 1];
+		bmap->eq[bmap->n_eq - 1] = t;
+	}
+	bmap->n_eq--;
+	return 0;
+}
+
+/* Turn inequality "pos" of "bmap" into an equality.
+ *
+ * In particular, we move the inequality in front of the equalities
+ * and move the last inequality in the position of the moved inequality.
+ * Note that isl_tab_make_equalities_explicit depends on this particular
+ * change in the ordering of the constraints.
+ */
+void isl_basic_map_inequality_to_equality(
+		struct isl_basic_map *bmap, unsigned pos)
+{
+	isl_int *t;
+
+	t = bmap->ineq[pos];
+	bmap->ineq[pos] = bmap->ineq[bmap->n_ineq - 1];
+	bmap->ineq[bmap->n_ineq - 1] = bmap->eq[-1];
+	bmap->eq[-1] = t;
+	bmap->n_eq++;
+	bmap->n_ineq--;
+	bmap->eq--;
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES);
+}
+
+static int room_for_ineq(struct isl_basic_map *bmap, unsigned n)
+{
+	return bmap->n_ineq + n <= bmap->eq - bmap->ineq;
+}
+
+int isl_basic_map_alloc_inequality(__isl_keep isl_basic_map *bmap)
+{
+	struct isl_ctx *ctx;
+	if (!bmap)
+		return -1;
+	ctx = bmap->ctx;
+	isl_assert(ctx, room_for_ineq(bmap, 1), return -1);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_IMPLICIT);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_ALL_EQUALITIES);
+	isl_seq_clr(bmap->ineq[bmap->n_ineq] +
+		      1 + isl_basic_map_total_dim(bmap),
+		      bmap->extra - bmap->n_div);
+	return bmap->n_ineq++;
+}
+
+int isl_basic_set_alloc_inequality(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_alloc_inequality(bset_to_bmap(bset));
+}
+
+int isl_basic_map_free_inequality(struct isl_basic_map *bmap, unsigned n)
+{
+	if (!bmap)
+		return -1;
+	isl_assert(bmap->ctx, n <= bmap->n_ineq, return -1);
+	bmap->n_ineq -= n;
+	return 0;
+}
+
+int isl_basic_set_free_inequality(struct isl_basic_set *bset, unsigned n)
+{
+	return isl_basic_map_free_inequality(bset_to_bmap(bset), n);
+}
+
+int isl_basic_map_drop_inequality(struct isl_basic_map *bmap, unsigned pos)
+{
+	isl_int *t;
+	if (!bmap)
+		return -1;
+	isl_assert(bmap->ctx, pos < bmap->n_ineq, return -1);
+
+	if (pos != bmap->n_ineq - 1) {
+		t = bmap->ineq[pos];
+		bmap->ineq[pos] = bmap->ineq[bmap->n_ineq - 1];
+		bmap->ineq[bmap->n_ineq - 1] = t;
+		ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	}
+	bmap->n_ineq--;
+	return 0;
+}
+
+int isl_basic_set_drop_inequality(struct isl_basic_set *bset, unsigned pos)
+{
+	return isl_basic_map_drop_inequality(bset_to_bmap(bset), pos);
+}
+
+__isl_give isl_basic_map *isl_basic_map_add_eq(__isl_take isl_basic_map *bmap,
+	isl_int *eq)
+{
+	int k;
+
+	bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
+	if (!bmap)
+		return NULL;
+	k = isl_basic_map_alloc_equality(bmap);
+	if (k < 0)
+		goto error;
+	isl_seq_cpy(bmap->eq[k], eq, 1 + isl_basic_map_total_dim(bmap));
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_eq(__isl_take isl_basic_set *bset,
+	isl_int *eq)
+{
+	return bset_from_bmap(isl_basic_map_add_eq(bset_to_bmap(bset), eq));
+}
+
+__isl_give isl_basic_map *isl_basic_map_add_ineq(__isl_take isl_basic_map *bmap,
+	isl_int *ineq)
+{
+	int k;
+
+	bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+	if (!bmap)
+		return NULL;
+	k = isl_basic_map_alloc_inequality(bmap);
+	if (k < 0)
+		goto error;
+	isl_seq_cpy(bmap->ineq[k], ineq, 1 + isl_basic_map_total_dim(bmap));
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_ineq(__isl_take isl_basic_set *bset,
+	isl_int *ineq)
+{
+	return bset_from_bmap(isl_basic_map_add_ineq(bset_to_bmap(bset), ineq));
+}
+
+int isl_basic_map_alloc_div(struct isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	isl_assert(bmap->ctx, bmap->n_div < bmap->extra, return -1);
+	isl_seq_clr(bmap->div[bmap->n_div] +
+		      1 + 1 + isl_basic_map_total_dim(bmap),
+		      bmap->extra - bmap->n_div);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+	return bmap->n_div++;
+}
+
+int isl_basic_set_alloc_div(struct isl_basic_set *bset)
+{
+	return isl_basic_map_alloc_div(bset_to_bmap(bset));
+}
+
+/* Check that there are "n" dimensions of type "type" starting at "first"
+ * in "bmap".
+ */
+static isl_stat isl_basic_map_check_range(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	unsigned dim;
+
+	if (!bmap)
+		return isl_stat_error;
+	dim = isl_basic_map_dim(bmap, type);
+	if (first + n > dim || first + n < first)
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"position or range out of bounds",
+			return isl_stat_error);
+	return isl_stat_ok;
+}
+
+/* Insert an extra integer division, prescribed by "div", to "bmap"
+ * at (integer division) position "pos".
+ *
+ * The integer division is first added at the end and then moved
+ * into the right position.
+ */
+__isl_give isl_basic_map *isl_basic_map_insert_div(
+	__isl_take isl_basic_map *bmap, int pos, __isl_keep isl_vec *div)
+{
+	int i, k;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap || !div)
+		return isl_basic_map_free(bmap);
+
+	if (div->size != 1 + 1 + isl_basic_map_dim(bmap, isl_dim_all))
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"unexpected size", return isl_basic_map_free(bmap));
+	if (isl_basic_map_check_range(bmap, isl_dim_div, pos, 0) < 0)
+		return isl_basic_map_free(bmap);
+
+	bmap = isl_basic_map_extend_space(bmap,
+					isl_basic_map_get_space(bmap), 1, 0, 2);
+	k = isl_basic_map_alloc_div(bmap);
+	if (k < 0)
+		return isl_basic_map_free(bmap);
+	isl_seq_cpy(bmap->div[k], div->el, div->size);
+	isl_int_set_si(bmap->div[k][div->size], 0);
+
+	for (i = k; i > pos; --i)
+		isl_basic_map_swap_div(bmap, i, i - 1);
+
+	return bmap;
+}
+
+isl_stat isl_basic_map_free_div(struct isl_basic_map *bmap, unsigned n)
+{
+	if (!bmap)
+		return isl_stat_error;
+	isl_assert(bmap->ctx, n <= bmap->n_div, return isl_stat_error);
+	bmap->n_div -= n;
+	return isl_stat_ok;
+}
+
+/* Copy constraint from src to dst, putting the vars of src at offset
+ * dim_off in dst and the divs of src at offset div_off in dst.
+ * If both sets are actually map, then dim_off applies to the input
+ * variables.
+ */
+static void copy_constraint(struct isl_basic_map *dst_map, isl_int *dst,
+			    struct isl_basic_map *src_map, isl_int *src,
+			    unsigned in_off, unsigned out_off, unsigned div_off)
+{
+	unsigned src_nparam = isl_basic_map_dim(src_map, isl_dim_param);
+	unsigned dst_nparam = isl_basic_map_dim(dst_map, isl_dim_param);
+	unsigned src_in = isl_basic_map_dim(src_map, isl_dim_in);
+	unsigned dst_in = isl_basic_map_dim(dst_map, isl_dim_in);
+	unsigned src_out = isl_basic_map_dim(src_map, isl_dim_out);
+	unsigned dst_out = isl_basic_map_dim(dst_map, isl_dim_out);
+	isl_int_set(dst[0], src[0]);
+	isl_seq_cpy(dst+1, src+1, isl_min(dst_nparam, src_nparam));
+	if (dst_nparam > src_nparam)
+		isl_seq_clr(dst+1+src_nparam,
+				dst_nparam - src_nparam);
+	isl_seq_clr(dst+1+dst_nparam, in_off);
+	isl_seq_cpy(dst+1+dst_nparam+in_off,
+		    src+1+src_nparam,
+		    isl_min(dst_in-in_off, src_in));
+	if (dst_in-in_off > src_in)
+		isl_seq_clr(dst+1+dst_nparam+in_off+src_in,
+				dst_in - in_off - src_in);
+	isl_seq_clr(dst+1+dst_nparam+dst_in, out_off);
+	isl_seq_cpy(dst+1+dst_nparam+dst_in+out_off,
+		    src+1+src_nparam+src_in,
+		    isl_min(dst_out-out_off, src_out));
+	if (dst_out-out_off > src_out)
+		isl_seq_clr(dst+1+dst_nparam+dst_in+out_off+src_out,
+				dst_out - out_off - src_out);
+	isl_seq_clr(dst+1+dst_nparam+dst_in+dst_out, div_off);
+	isl_seq_cpy(dst+1+dst_nparam+dst_in+dst_out+div_off,
+		    src+1+src_nparam+src_in+src_out,
+		    isl_min(dst_map->extra-div_off, src_map->n_div));
+	if (dst_map->n_div-div_off > src_map->n_div)
+		isl_seq_clr(dst+1+dst_nparam+dst_in+dst_out+
+				div_off+src_map->n_div,
+				dst_map->n_div - div_off - src_map->n_div);
+}
+
+static void copy_div(struct isl_basic_map *dst_map, isl_int *dst,
+		     struct isl_basic_map *src_map, isl_int *src,
+		     unsigned in_off, unsigned out_off, unsigned div_off)
+{
+	isl_int_set(dst[0], src[0]);
+	copy_constraint(dst_map, dst+1, src_map, src+1, in_off, out_off, div_off);
+}
+
+static __isl_give isl_basic_map *add_constraints(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2,
+	unsigned i_pos, unsigned o_pos)
+{
+	int i;
+	unsigned div_off;
+
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	div_off = bmap1->n_div;
+
+	for (i = 0; i < bmap2->n_eq; ++i) {
+		int i1 = isl_basic_map_alloc_equality(bmap1);
+		if (i1 < 0)
+			goto error;
+		copy_constraint(bmap1, bmap1->eq[i1], bmap2, bmap2->eq[i],
+				i_pos, o_pos, div_off);
+	}
+
+	for (i = 0; i < bmap2->n_ineq; ++i) {
+		int i1 = isl_basic_map_alloc_inequality(bmap1);
+		if (i1 < 0)
+			goto error;
+		copy_constraint(bmap1, bmap1->ineq[i1], bmap2, bmap2->ineq[i],
+				i_pos, o_pos, div_off);
+	}
+
+	for (i = 0; i < bmap2->n_div; ++i) {
+		int i1 = isl_basic_map_alloc_div(bmap1);
+		if (i1 < 0)
+			goto error;
+		copy_div(bmap1, bmap1->div[i1], bmap2, bmap2->div[i],
+			 i_pos, o_pos, div_off);
+	}
+
+	isl_basic_map_free(bmap2);
+
+	return bmap1;
+
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_add_constraints(struct isl_basic_set *bset1,
+		struct isl_basic_set *bset2, unsigned pos)
+{
+	return bset_from_bmap(add_constraints(bset_to_bmap(bset1),
+						bset_to_bmap(bset2), 0, pos));
+}
+
+__isl_give isl_basic_map *isl_basic_map_extend_space(
+	__isl_take isl_basic_map *base, __isl_take isl_space *dim,
+	unsigned extra, unsigned n_eq, unsigned n_ineq)
+{
+	struct isl_basic_map *ext;
+	unsigned flags;
+	int dims_ok;
+
+	if (!dim)
+		goto error;
+
+	if (!base)
+		goto error;
+
+	dims_ok = isl_space_is_equal(base->dim, dim) &&
+		  base->extra >= base->n_div + extra;
+
+	if (dims_ok && room_for_con(base, n_eq + n_ineq) &&
+		       room_for_ineq(base, n_ineq)) {
+		isl_space_free(dim);
+		return base;
+	}
+
+	isl_assert(base->ctx, base->dim->nparam <= dim->nparam, goto error);
+	isl_assert(base->ctx, base->dim->n_in <= dim->n_in, goto error);
+	isl_assert(base->ctx, base->dim->n_out <= dim->n_out, goto error);
+	extra += base->extra;
+	n_eq += base->n_eq;
+	n_ineq += base->n_ineq;
+
+	ext = isl_basic_map_alloc_space(dim, extra, n_eq, n_ineq);
+	dim = NULL;
+	if (!ext)
+		goto error;
+
+	if (dims_ok)
+		ext->sample = isl_vec_copy(base->sample);
+	flags = base->flags;
+	ext = add_constraints(ext, base, 0, 0);
+	if (ext) {
+		ext->flags = flags;
+		ISL_F_CLR(ext, ISL_BASIC_SET_FINAL);
+	}
+
+	return ext;
+
+error:
+	isl_space_free(dim);
+	isl_basic_map_free(base);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_extend_space(
+	__isl_take isl_basic_set *base,
+		__isl_take isl_space *dim, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	return bset_from_bmap(isl_basic_map_extend_space(bset_to_bmap(base),
+						    dim, extra, n_eq, n_ineq));
+}
+
+struct isl_basic_map *isl_basic_map_extend_constraints(
+		struct isl_basic_map *base, unsigned n_eq, unsigned n_ineq)
+{
+	if (!base)
+		return NULL;
+	return isl_basic_map_extend_space(base, isl_space_copy(base->dim),
+					0, n_eq, n_ineq);
+}
+
+struct isl_basic_map *isl_basic_map_extend(struct isl_basic_map *base,
+		unsigned nparam, unsigned n_in, unsigned n_out, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	struct isl_basic_map *bmap;
+	isl_space *dim;
+
+	if (!base)
+		return NULL;
+	dim = isl_space_alloc(base->ctx, nparam, n_in, n_out);
+	if (!dim)
+		goto error;
+
+	bmap = isl_basic_map_extend_space(base, dim, extra, n_eq, n_ineq);
+	return bmap;
+error:
+	isl_basic_map_free(base);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_extend(struct isl_basic_set *base,
+		unsigned nparam, unsigned dim, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	return bset_from_bmap(isl_basic_map_extend(bset_to_bmap(base),
+					nparam, 0, dim, extra, n_eq, n_ineq));
+}
+
+struct isl_basic_set *isl_basic_set_extend_constraints(
+		struct isl_basic_set *base, unsigned n_eq, unsigned n_ineq)
+{
+	isl_basic_map *bmap = bset_to_bmap(base);
+	bmap = isl_basic_map_extend_constraints(bmap, n_eq, n_ineq);
+	return bset_from_bmap(bmap);
+}
+
+__isl_give isl_basic_set *isl_basic_set_cow(__isl_take isl_basic_set *bset)
+{
+	return bset_from_bmap(isl_basic_map_cow(bset_to_bmap(bset)));
+}
+
+__isl_give isl_basic_map *isl_basic_map_cow(__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (bmap->ref > 1) {
+		bmap->ref--;
+		bmap = isl_basic_map_dup(bmap);
+	}
+	if (bmap) {
+		ISL_F_CLR(bmap, ISL_BASIC_SET_FINAL);
+		ISL_F_CLR(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS);
+	}
+	return bmap;
+}
+
+/* Clear all cached information in "map", either because it is about
+ * to be modified or because it is being freed.
+ * Always return the same pointer that is passed in.
+ * This is needed for the use in isl_map_free.
+ */
+static __isl_give isl_map *clear_caches(__isl_take isl_map *map)
+{
+	isl_basic_map_free(map->cached_simple_hull[0]);
+	isl_basic_map_free(map->cached_simple_hull[1]);
+	map->cached_simple_hull[0] = NULL;
+	map->cached_simple_hull[1] = NULL;
+	return map;
+}
+
+__isl_give isl_set *isl_set_cow(__isl_take isl_set *set)
+{
+	return isl_map_cow(set);
+}
+
+/* Return an isl_map that is equal to "map" and that has only
+ * a single reference.
+ *
+ * If the original input already has only one reference, then
+ * simply return it, but clear all cached information, since
+ * it may be rendered invalid by the operations that will be
+ * performed on the result.
+ *
+ * Otherwise, create a duplicate (without any cached information).
+ */
+__isl_give isl_map *isl_map_cow(__isl_take isl_map *map)
+{
+	if (!map)
+		return NULL;
+
+	if (map->ref == 1)
+		return clear_caches(map);
+	map->ref--;
+	return isl_map_dup(map);
+}
+
+static void swap_vars(struct isl_blk blk, isl_int *a,
+			unsigned a_len, unsigned b_len)
+{
+	isl_seq_cpy(blk.data, a+a_len, b_len);
+	isl_seq_cpy(blk.data+b_len, a, a_len);
+	isl_seq_cpy(a, blk.data, b_len+a_len);
+}
+
+static __isl_give isl_basic_map *isl_basic_map_swap_vars(
+	__isl_take isl_basic_map *bmap, unsigned pos, unsigned n1, unsigned n2)
+{
+	int i;
+	struct isl_blk blk;
+
+	if (!bmap)
+		goto error;
+
+	isl_assert(bmap->ctx,
+		pos + n1 + n2 <= 1 + isl_basic_map_total_dim(bmap), goto error);
+
+	if (n1 == 0 || n2 == 0)
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	blk = isl_blk_alloc(bmap->ctx, n1 + n2);
+	if (isl_blk_is_error(blk))
+		goto error;
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		swap_vars(blk,
+			  bmap->eq[i] + pos, n1, n2);
+
+	for (i = 0; i < bmap->n_ineq; ++i)
+		swap_vars(blk,
+			  bmap->ineq[i] + pos, n1, n2);
+
+	for (i = 0; i < bmap->n_div; ++i)
+		swap_vars(blk,
+			  bmap->div[i]+1 + pos, n1, n2);
+
+	isl_blk_free(bmap->ctx, blk);
+
+	ISL_F_CLR(bmap, ISL_BASIC_SET_NORMALIZED);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_set_to_empty(
+	__isl_take isl_basic_map *bmap)
+{
+	int i = 0;
+	unsigned total;
+	if (!bmap)
+		goto error;
+	total = isl_basic_map_total_dim(bmap);
+	if (isl_basic_map_free_div(bmap, bmap->n_div) < 0)
+		return isl_basic_map_free(bmap);
+	isl_basic_map_free_inequality(bmap, bmap->n_ineq);
+	if (bmap->n_eq > 0)
+		isl_basic_map_free_equality(bmap, bmap->n_eq-1);
+	else {
+		i = isl_basic_map_alloc_equality(bmap);
+		if (i < 0)
+			goto error;
+	}
+	isl_int_set_si(bmap->eq[i][0], 1);
+	isl_seq_clr(bmap->eq[i]+1, total);
+	ISL_F_SET(bmap, ISL_BASIC_MAP_EMPTY);
+	isl_vec_free(bmap->sample);
+	bmap->sample = NULL;
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_set_to_empty(
+	__isl_take isl_basic_set *bset)
+{
+	return bset_from_bmap(isl_basic_map_set_to_empty(bset_to_bmap(bset)));
+}
+
+__isl_give isl_basic_map *isl_basic_map_set_rational(
+	__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	ISL_F_SET(bmap, ISL_BASIC_MAP_RATIONAL);
+
+	return isl_basic_map_finalize(bmap);
+}
+
+__isl_give isl_basic_set *isl_basic_set_set_rational(
+	__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_set_rational(bset);
+}
+
+__isl_give isl_basic_set *isl_basic_set_set_integral(
+	__isl_take isl_basic_set *bset)
+{
+	if (!bset)
+		return NULL;
+
+	if (!ISL_F_ISSET(bset, ISL_BASIC_MAP_RATIONAL))
+		return bset;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		return NULL;
+
+	ISL_F_CLR(bset, ISL_BASIC_MAP_RATIONAL);
+
+	return isl_basic_set_finalize(bset);
+}
+
+__isl_give isl_map *isl_map_set_rational(__isl_take isl_map *map)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_set_rational(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_set_rational(__isl_take isl_set *set)
+{
+	return isl_map_set_rational(set);
+}
+
+/* Swap divs "a" and "b" in "bmap" (without modifying any of the constraints
+ * of "bmap").
+ */
+static void swap_div(__isl_keep isl_basic_map *bmap, int a, int b)
+{
+	isl_int *t = bmap->div[a];
+	bmap->div[a] = bmap->div[b];
+	bmap->div[b] = t;
+}
+
+/* Swap divs "a" and "b" in "bmap" and adjust the constraints and
+ * div definitions accordingly.
+ */
+void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b)
+{
+	int i;
+	unsigned off = isl_space_dim(bmap->dim, isl_dim_all);
+
+	swap_div(bmap, a, b);
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		isl_int_swap(bmap->eq[i][1+off+a], bmap->eq[i][1+off+b]);
+
+	for (i = 0; i < bmap->n_ineq; ++i)
+		isl_int_swap(bmap->ineq[i][1+off+a], bmap->ineq[i][1+off+b]);
+
+	for (i = 0; i < bmap->n_div; ++i)
+		isl_int_swap(bmap->div[i][1+1+off+a], bmap->div[i][1+1+off+b]);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+}
+
+/* Swap divs "a" and "b" in "bset" and adjust the constraints and
+ * div definitions accordingly.
+ */
+void isl_basic_set_swap_div(__isl_keep isl_basic_set *bset, int a, int b)
+{
+	isl_basic_map_swap_div(bset, a, b);
+}
+
+static void constraint_drop_vars(isl_int *c, unsigned n, unsigned rem)
+{
+	isl_seq_cpy(c, c + n, rem);
+	isl_seq_clr(c + rem, n);
+}
+
+/* Drop n dimensions starting at first.
+ *
+ * In principle, this frees up some extra variables as the number
+ * of columns remains constant, but we would have to extend
+ * the div array too as the number of rows in this array is assumed
+ * to be equal to extra.
+ */
+__isl_give isl_basic_set *isl_basic_set_drop_dims(
+	__isl_take isl_basic_set *bset, unsigned first, unsigned n)
+{
+	return isl_basic_map_drop(bset_to_bmap(bset), isl_dim_set, first, n);
+}
+
+/* Move "n" divs starting at "first" to the end of the list of divs.
+ */
+static struct isl_basic_map *move_divs_last(struct isl_basic_map *bmap,
+	unsigned first, unsigned n)
+{
+	isl_int **div;
+	int i;
+
+	if (first + n == bmap->n_div)
+		return bmap;
+
+	div = isl_alloc_array(bmap->ctx, isl_int *, n);
+	if (!div)
+		goto error;
+	for (i = 0; i < n; ++i)
+		div[i] = bmap->div[first + i];
+	for (i = 0; i < bmap->n_div - first - n; ++i)
+		bmap->div[first + i] = bmap->div[first + n + i];
+	for (i = 0; i < n; ++i)
+		bmap->div[bmap->n_div - n + i] = div[i];
+	free(div);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Drop "n" dimensions of type "type" starting at "first".
+ *
+ * In principle, this frees up some extra variables as the number
+ * of columns remains constant, but we would have to extend
+ * the div array too as the number of rows in this array is assumed
+ * to be equal to extra.
+ */
+__isl_give isl_basic_map *isl_basic_map_drop(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	unsigned dim;
+	unsigned offset;
+	unsigned left;
+
+	if (!bmap)
+		goto error;
+
+	dim = isl_basic_map_dim(bmap, type);
+	isl_assert(bmap->ctx, first + n <= dim, goto error);
+
+	if (n == 0 && !isl_space_is_named_or_nested(bmap->dim, type))
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	offset = isl_basic_map_offset(bmap, type) + first;
+	left = isl_basic_map_total_dim(bmap) - (offset - 1) - n;
+	for (i = 0; i < bmap->n_eq; ++i)
+		constraint_drop_vars(bmap->eq[i]+offset, n, left);
+
+	for (i = 0; i < bmap->n_ineq; ++i)
+		constraint_drop_vars(bmap->ineq[i]+offset, n, left);
+
+	for (i = 0; i < bmap->n_div; ++i)
+		constraint_drop_vars(bmap->div[i]+1+offset, n, left);
+
+	if (type == isl_dim_div) {
+		bmap = move_divs_last(bmap, first, n);
+		if (!bmap)
+			goto error;
+		if (isl_basic_map_free_div(bmap, n) < 0)
+			return isl_basic_map_free(bmap);
+	} else
+		bmap->dim = isl_space_drop_dims(bmap->dim, type, first, n);
+	if (!bmap->dim)
+		goto error;
+
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_drop(__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return bset_from_bmap(isl_basic_map_drop(bset_to_bmap(bset),
+							type, first, n));
+}
+
+__isl_give isl_map *isl_map_drop(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!map)
+		goto error;
+
+	isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error);
+
+	if (n == 0 && !isl_space_is_named_or_nested(map->dim, type))
+		return map;
+	map = isl_map_cow(map);
+	if (!map)
+		goto error;
+	map->dim = isl_space_drop_dims(map->dim, type, first, n);
+	if (!map->dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_drop(map->p[i], type, first, n);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_drop(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return set_from_map(isl_map_drop(set_to_map(set), type, first, n));
+}
+
+/*
+ * We don't cow, as the div is assumed to be redundant.
+ */
+__isl_give isl_basic_map *isl_basic_map_drop_div(
+	__isl_take isl_basic_map *bmap, unsigned div)
+{
+	int i;
+	unsigned pos;
+
+	if (!bmap)
+		goto error;
+
+	pos = 1 + isl_space_dim(bmap->dim, isl_dim_all) + div;
+
+	isl_assert(bmap->ctx, div < bmap->n_div, goto error);
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		constraint_drop_vars(bmap->eq[i]+pos, 1, bmap->extra-div-1);
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		if (!isl_int_is_zero(bmap->ineq[i][pos])) {
+			isl_basic_map_drop_inequality(bmap, i);
+			--i;
+			continue;
+		}
+		constraint_drop_vars(bmap->ineq[i]+pos, 1, bmap->extra-div-1);
+	}
+
+	for (i = 0; i < bmap->n_div; ++i)
+		constraint_drop_vars(bmap->div[i]+1+pos, 1, bmap->extra-div-1);
+
+	if (div != bmap->n_div - 1) {
+		int j;
+		isl_int *t = bmap->div[div];
+
+		for (j = div; j < bmap->n_div - 1; ++j)
+			bmap->div[j] = bmap->div[j+1];
+
+		bmap->div[bmap->n_div - 1] = t;
+	}
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	if (isl_basic_map_free_div(bmap, 1) < 0)
+		return isl_basic_map_free(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Eliminate the specified n dimensions starting at first from the
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
+ */
+__isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	if (n == 0)
+		return map;
+
+	if (first + n > isl_map_dim(map, type) || first + n < first)
+		isl_die(map->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_eliminate(map->p[i], type, first, n);
+		if (!map->p[i])
+			goto error;
+	}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Eliminate the specified n dimensions starting at first from the
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
+ */
+__isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return set_from_map(isl_map_eliminate(set_to_map(set), type, first, n));
+}
+
+/* Eliminate the specified n dimensions starting at first from the
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
+ */
+__isl_give isl_set *isl_set_eliminate_dims(__isl_take isl_set *set,
+	unsigned first, unsigned n)
+{
+	return isl_set_eliminate(set, isl_dim_set, first, n);
+}
+
+__isl_give isl_basic_map *isl_basic_map_remove_divs(
+	__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+	bmap = isl_basic_map_eliminate_vars(bmap,
+			    isl_space_dim(bmap->dim, isl_dim_all), bmap->n_div);
+	if (!bmap)
+		return NULL;
+	bmap->n_div = 0;
+	return isl_basic_map_finalize(bmap);
+}
+
+__isl_give isl_basic_set *isl_basic_set_remove_divs(
+	__isl_take isl_basic_set *bset)
+{
+	return bset_from_bmap(isl_basic_map_remove_divs(bset_to_bmap(bset)));
+}
+
+__isl_give isl_map *isl_map_remove_divs(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+	
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_remove_divs(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_remove_divs(__isl_take isl_set *set)
+{
+	return isl_map_remove_divs(set);
+}
+
+__isl_give isl_basic_map *isl_basic_map_remove_dims(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type,
+	unsigned first, unsigned n)
+{
+	if (isl_basic_map_check_range(bmap, type, first, n) < 0)
+		return isl_basic_map_free(bmap);
+	if (n == 0 && !isl_space_is_named_or_nested(bmap->dim, type))
+		return bmap;
+	bmap = isl_basic_map_eliminate_vars(bmap,
+			isl_basic_map_offset(bmap, type) - 1 + first, n);
+	if (!bmap)
+		return bmap;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY) && type == isl_dim_div)
+		return bmap;
+	bmap = isl_basic_map_drop(bmap, type, first, n);
+	return bmap;
+}
+
+/* Return true if the definition of the given div (recursively) involves
+ * any of the given variables.
+ */
+static isl_bool div_involves_vars(__isl_keep isl_basic_map *bmap, int div,
+	unsigned first, unsigned n)
+{
+	int i;
+	unsigned div_offset = isl_basic_map_offset(bmap, isl_dim_div);
+
+	if (isl_int_is_zero(bmap->div[div][0]))
+		return isl_bool_false;
+	if (isl_seq_first_non_zero(bmap->div[div] + 1 + first, n) >= 0)
+		return isl_bool_true;
+
+	for (i = bmap->n_div - 1; i >= 0; --i) {
+		isl_bool involves;
+
+		if (isl_int_is_zero(bmap->div[div][1 + div_offset + i]))
+			continue;
+		involves = div_involves_vars(bmap, i, first, n);
+		if (involves < 0 || involves)
+			return involves;
+	}
+
+	return isl_bool_false;
+}
+
+/* Try and add a lower and/or upper bound on "div" to "bmap"
+ * based on inequality "i".
+ * "total" is the total number of variables (excluding the divs).
+ * "v" is a temporary object that can be used during the calculations.
+ * If "lb" is set, then a lower bound should be constructed.
+ * If "ub" is set, then an upper bound should be constructed.
+ *
+ * The calling function has already checked that the inequality does not
+ * reference "div", but we still need to check that the inequality is
+ * of the right form.  We'll consider the case where we want to construct
+ * a lower bound.  The construction of upper bounds is similar.
+ *
+ * Let "div" be of the form
+ *
+ *	q = floor((a + f(x))/d)
+ *
+ * We essentially check if constraint "i" is of the form
+ *
+ *	b + f(x) >= 0
+ *
+ * so that we can use it to derive a lower bound on "div".
+ * However, we allow a slightly more general form
+ *
+ *	b + g(x) >= 0
+ *
+ * with the condition that the coefficients of g(x) - f(x) are all
+ * divisible by d.
+ * Rewriting this constraint as
+ *
+ *	0 >= -b - g(x)
+ *
+ * adding a + f(x) to both sides and dividing by d, we obtain
+ *
+ *	(a + f(x))/d >= (a-b)/d + (f(x)-g(x))/d
+ *
+ * Taking the floor on both sides, we obtain
+ *
+ *	q >= floor((a-b)/d) + (f(x)-g(x))/d
+ *
+ * or
+ *
+ *	(g(x)-f(x))/d + ceil((b-a)/d) + q >= 0
+ *
+ * In the case of an upper bound, we construct the constraint
+ *
+ *	(g(x)+f(x))/d + floor((b+a)/d) - q >= 0
+ *
+ */
+static __isl_give isl_basic_map *insert_bounds_on_div_from_ineq(
+	__isl_take isl_basic_map *bmap, int div, int i,
+	unsigned total, isl_int v, int lb, int ub)
+{
+	int j;
+
+	for (j = 0; (lb || ub) && j < total + bmap->n_div; ++j) {
+		if (lb) {
+			isl_int_sub(v, bmap->ineq[i][1 + j],
+					bmap->div[div][1 + 1 + j]);
+			lb = isl_int_is_divisible_by(v, bmap->div[div][0]);
+		}
+		if (ub) {
+			isl_int_add(v, bmap->ineq[i][1 + j],
+					bmap->div[div][1 + 1 + j]);
+			ub = isl_int_is_divisible_by(v, bmap->div[div][0]);
+		}
+	}
+	if (!lb && !ub)
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_extend_constraints(bmap, 0, lb + ub);
+	if (lb) {
+		int k = isl_basic_map_alloc_inequality(bmap);
+		if (k < 0)
+			goto error;
+		for (j = 0; j < 1 + total + bmap->n_div; ++j) {
+			isl_int_sub(bmap->ineq[k][j], bmap->ineq[i][j],
+					bmap->div[div][1 + j]);
+			isl_int_cdiv_q(bmap->ineq[k][j],
+					bmap->ineq[k][j], bmap->div[div][0]);
+		}
+		isl_int_set_si(bmap->ineq[k][1 + total + div], 1);
+	}
+	if (ub) {
+		int k = isl_basic_map_alloc_inequality(bmap);
+		if (k < 0)
+			goto error;
+		for (j = 0; j < 1 + total + bmap->n_div; ++j) {
+			isl_int_add(bmap->ineq[k][j], bmap->ineq[i][j],
+					bmap->div[div][1 + j]);
+			isl_int_fdiv_q(bmap->ineq[k][j],
+					bmap->ineq[k][j], bmap->div[div][0]);
+		}
+		isl_int_set_si(bmap->ineq[k][1 + total + div], -1);
+	}
+
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* This function is called right before "div" is eliminated from "bmap"
+ * using Fourier-Motzkin.
+ * Look through the constraints of "bmap" for constraints on the argument
+ * of the integer division and use them to construct constraints on the
+ * integer division itself.  These constraints can then be combined
+ * during the Fourier-Motzkin elimination.
+ * Note that it is only useful to introduce lower bounds on "div"
+ * if "bmap" already contains upper bounds on "div" as the newly
+ * introduce lower bounds can then be combined with the pre-existing
+ * upper bounds.  Similarly for upper bounds.
+ * We therefore first check if "bmap" contains any lower and/or upper bounds
+ * on "div".
+ *
+ * It is interesting to note that the introduction of these constraints
+ * can indeed lead to more accurate results, even when compared to
+ * deriving constraints on the argument of "div" from constraints on "div".
+ * Consider, for example, the set
+ *
+ *	{ [i,j,k] : 3 + i + 2j >= 0 and 2 * [(i+2j)/4] <= k }
+ *
+ * The second constraint can be rewritten as
+ *
+ *	2 * [(-i-2j+3)/4] + k >= 0
+ *
+ * from which we can derive
+ *
+ *	-i - 2j + 3 >= -2k
+ *
+ * or
+ *
+ *	i + 2j <= 3 + 2k
+ *
+ * Combined with the first constraint, we obtain
+ *
+ *	-3 <= 3 + 2k	or	k >= -3
+ *
+ * If, on the other hand we derive a constraint on [(i+2j)/4] from
+ * the first constraint, we obtain
+ *
+ *	[(i + 2j)/4] >= [-3/4] = -1
+ *
+ * Combining this constraint with the second constraint, we obtain
+ *
+ *	k >= -2
+ */
+static __isl_give isl_basic_map *insert_bounds_on_div(
+	__isl_take isl_basic_map *bmap, int div)
+{
+	int i;
+	int check_lb, check_ub;
+	isl_int v;
+	unsigned total;
+
+	if (!bmap)
+		return NULL;
+
+	if (isl_int_is_zero(bmap->div[div][0]))
+		return bmap;
+
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+
+	check_lb = 0;
+	check_ub = 0;
+	for (i = 0; (!check_lb || !check_ub) && i < bmap->n_ineq; ++i) {
+		int s = isl_int_sgn(bmap->ineq[i][1 + total + div]);
+		if (s > 0)
+			check_ub = 1;
+		if (s < 0)
+			check_lb = 1;
+	}
+
+	if (!check_lb && !check_ub)
+		return bmap;
+
+	isl_int_init(v);
+
+	for (i = 0; bmap && i < bmap->n_ineq; ++i) {
+		if (!isl_int_is_zero(bmap->ineq[i][1 + total + div]))
+			continue;
+
+		bmap = insert_bounds_on_div_from_ineq(bmap, div, i, total, v,
+							check_lb, check_ub);
+	}
+
+	isl_int_clear(v);
+
+	return bmap;
+}
+
+/* Remove all divs (recursively) involving any of the given dimensions
+ * in their definitions.
+ */
+__isl_give isl_basic_map *isl_basic_map_remove_divs_involving_dims(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (isl_basic_map_check_range(bmap, type, first, n) < 0)
+		return isl_basic_map_free(bmap);
+	first += isl_basic_map_offset(bmap, type);
+
+	for (i = bmap->n_div - 1; i >= 0; --i) {
+		isl_bool involves;
+
+		involves = div_involves_vars(bmap, i, first, n);
+		if (involves < 0)
+			return isl_basic_map_free(bmap);
+		if (!involves)
+			continue;
+		bmap = insert_bounds_on_div(bmap, i);
+		bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, i, 1);
+		if (!bmap)
+			return NULL;
+		i = bmap->n_div;
+	}
+
+	return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_remove_divs_involving_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_basic_map_remove_divs_involving_dims(bset, type, first, n);
+}
+
+__isl_give isl_map *isl_map_remove_divs_involving_dims(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_remove_divs_involving_dims(map->p[i],
+								type, first, n);
+		if (!map->p[i])
+			goto error;
+	}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_remove_divs_involving_dims(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return set_from_map(isl_map_remove_divs_involving_dims(set_to_map(set),
+							      type, first, n));
+}
+
+/* Does the description of "bmap" depend on the specified dimensions?
+ * We also check whether the dimensions appear in any of the div definitions.
+ * In principle there is no need for this check.  If the dimensions appear
+ * in a div definition, they also appear in the defining constraints of that
+ * div.
+ */
+isl_bool isl_basic_map_involves_dims(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (isl_basic_map_check_range(bmap, type, first, n) < 0)
+		return isl_bool_error;
+
+	first += isl_basic_map_offset(bmap, type);
+	for (i = 0; i < bmap->n_eq; ++i)
+		if (isl_seq_first_non_zero(bmap->eq[i] + first, n) >= 0)
+			return isl_bool_true;
+	for (i = 0; i < bmap->n_ineq; ++i)
+		if (isl_seq_first_non_zero(bmap->ineq[i] + first, n) >= 0)
+			return isl_bool_true;
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (isl_seq_first_non_zero(bmap->div[i] + 1 + first, n) >= 0)
+			return isl_bool_true;
+	}
+
+	return isl_bool_false;
+}
+
+isl_bool isl_map_involves_dims(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!map)
+		return isl_bool_error;
+
+	if (first + n > isl_map_dim(map, type))
+		isl_die(map->ctx, isl_error_invalid,
+			"index out of bounds", return isl_bool_error);
+
+	for (i = 0; i < map->n; ++i) {
+		isl_bool involves = isl_basic_map_involves_dims(map->p[i],
+							    type, first, n);
+		if (involves < 0 || involves)
+			return involves;
+	}
+
+	return isl_bool_false;
+}
+
+isl_bool isl_basic_set_involves_dims(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_basic_map_involves_dims(bset, type, first, n);
+}
+
+isl_bool isl_set_involves_dims(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_map_involves_dims(set, type, first, n);
+}
+
+/* Drop all constraints in bmap that involve any of the dimensions
+ * first to first+n-1.
+ */
+static __isl_give isl_basic_map *isl_basic_map_drop_constraints_involving(
+	__isl_take isl_basic_map *bmap, unsigned first, unsigned n)
+{
+	int i;
+
+	if (n == 0)
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+
+	if (!bmap)
+		return NULL;
+
+	for (i = bmap->n_eq - 1; i >= 0; --i) {
+		if (isl_seq_first_non_zero(bmap->eq[i] + 1 + first, n) == -1)
+			continue;
+		isl_basic_map_drop_equality(bmap, i);
+	}
+
+	for (i = bmap->n_ineq - 1; i >= 0; --i) {
+		if (isl_seq_first_non_zero(bmap->ineq[i] + 1 + first, n) == -1)
+			continue;
+		isl_basic_map_drop_inequality(bmap, i);
+	}
+
+	bmap = isl_basic_map_add_known_div_constraints(bmap);
+	return bmap;
+}
+
+/* Drop all constraints in bset that involve any of the dimensions
+ * first to first+n-1.
+ */
+__isl_give isl_basic_set *isl_basic_set_drop_constraints_involving(
+	__isl_take isl_basic_set *bset, unsigned first, unsigned n)
+{
+	return isl_basic_map_drop_constraints_involving(bset, first, n);
+}
+
+/* Drop all constraints in bmap that do not involve any of the dimensions
+ * first to first + n - 1 of the given type.
+ */
+__isl_give isl_basic_map *isl_basic_map_drop_constraints_not_involving_dims(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (n == 0) {
+		isl_space *space = isl_basic_map_get_space(bmap);
+		isl_basic_map_free(bmap);
+		return isl_basic_map_universe(space);
+	}
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	if (isl_basic_map_check_range(bmap, type, first, n) < 0)
+		return isl_basic_map_free(bmap);
+
+	first += isl_basic_map_offset(bmap, type) - 1;
+
+	for (i = bmap->n_eq - 1; i >= 0; --i) {
+		if (isl_seq_first_non_zero(bmap->eq[i] + 1 + first, n) != -1)
+			continue;
+		isl_basic_map_drop_equality(bmap, i);
+	}
+
+	for (i = bmap->n_ineq - 1; i >= 0; --i) {
+		if (isl_seq_first_non_zero(bmap->ineq[i] + 1 + first, n) != -1)
+			continue;
+		isl_basic_map_drop_inequality(bmap, i);
+	}
+
+	bmap = isl_basic_map_add_known_div_constraints(bmap);
+	return bmap;
+}
+
+/* Drop all constraints in bset that do not involve any of the dimensions
+ * first to first + n - 1 of the given type.
+ */
+__isl_give isl_basic_set *isl_basic_set_drop_constraints_not_involving_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_basic_map_drop_constraints_not_involving_dims(bset,
+							    type, first, n);
+}
+
+/* Drop all constraints in bmap that involve any of the dimensions
+ * first to first + n - 1 of the given type.
+ */
+__isl_give isl_basic_map *isl_basic_map_drop_constraints_involving_dims(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	if (!bmap)
+		return NULL;
+	if (n == 0)
+		return bmap;
+
+	if (isl_basic_map_check_range(bmap, type, first, n) < 0)
+		return isl_basic_map_free(bmap);
+
+	bmap = isl_basic_map_remove_divs_involving_dims(bmap, type, first, n);
+	first += isl_basic_map_offset(bmap, type) - 1;
+	return isl_basic_map_drop_constraints_involving(bmap, first, n);
+}
+
+/* Drop all constraints in bset that involve any of the dimensions
+ * first to first + n - 1 of the given type.
+ */
+__isl_give isl_basic_set *isl_basic_set_drop_constraints_involving_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_basic_map_drop_constraints_involving_dims(bset,
+							    type, first, n);
+}
+
+/* Drop constraints from "map" by applying "drop" to each basic map.
+ */
+static __isl_give isl_map *drop_constraints(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n,
+	__isl_give isl_basic_map *(*drop)(__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned first, unsigned n))
+{
+	int i;
+	unsigned dim;
+
+	if (!map)
+		return NULL;
+
+	dim = isl_map_dim(map, type);
+	if (first + n > dim || first + n < first)
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"index out of bounds", return isl_map_free(map));
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = drop(map->p[i], type, first, n);
+		if (!map->p[i])
+			return isl_map_free(map);
+	}
+
+	if (map->n > 1)
+		ISL_F_CLR(map, ISL_MAP_DISJOINT);
+
+	return map;
+}
+
+/* Drop all constraints in map that involve any of the dimensions
+ * first to first + n - 1 of the given type.
+ */
+__isl_give isl_map *isl_map_drop_constraints_involving_dims(
+	__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	if (n == 0)
+		return map;
+	return drop_constraints(map, type, first, n,
+				&isl_basic_map_drop_constraints_involving_dims);
+}
+
+/* Drop all constraints in "map" that do not involve any of the dimensions
+ * first to first + n - 1 of the given type.
+ */
+__isl_give isl_map *isl_map_drop_constraints_not_involving_dims(
+	__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	if (n == 0) {
+		isl_space *space = isl_map_get_space(map);
+		isl_map_free(map);
+		return isl_map_universe(space);
+	}
+	return drop_constraints(map, type, first, n,
+			    &isl_basic_map_drop_constraints_not_involving_dims);
+}
+
+/* Drop all constraints in set that involve any of the dimensions
+ * first to first + n - 1 of the given type.
+ */
+__isl_give isl_set *isl_set_drop_constraints_involving_dims(
+	__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_map_drop_constraints_involving_dims(set, type, first, n);
+}
+
+/* Drop all constraints in "set" that do not involve any of the dimensions
+ * first to first + n - 1 of the given type.
+ */
+__isl_give isl_set *isl_set_drop_constraints_not_involving_dims(
+	__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_map_drop_constraints_not_involving_dims(set, type, first, n);
+}
+
+/* Does local variable "div" of "bmap" have a complete explicit representation?
+ * Having a complete explicit representation requires not only
+ * an explicit representation, but also that all local variables
+ * that appear in this explicit representation in turn have
+ * a complete explicit representation.
+ */
+isl_bool isl_basic_map_div_is_known(__isl_keep isl_basic_map *bmap, int div)
+{
+	int i;
+	unsigned div_offset = isl_basic_map_offset(bmap, isl_dim_div);
+	isl_bool marked;
+
+	marked = isl_basic_map_div_is_marked_unknown(bmap, div);
+	if (marked < 0 || marked)
+		return isl_bool_not(marked);
+
+	for (i = bmap->n_div - 1; i >= 0; --i) {
+		isl_bool known;
+
+		if (isl_int_is_zero(bmap->div[div][1 + div_offset + i]))
+			continue;
+		known = isl_basic_map_div_is_known(bmap, i);
+		if (known < 0 || !known)
+			return known;
+	}
+
+	return isl_bool_true;
+}
+
+/* Remove all divs that are unknown or defined in terms of unknown divs.
+ */
+__isl_give isl_basic_map *isl_basic_map_remove_unknown_divs(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+
+	if (!bmap)
+		return NULL;
+
+	for (i = bmap->n_div - 1; i >= 0; --i) {
+		if (isl_basic_map_div_is_known(bmap, i))
+			continue;
+		bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, i, 1);
+		if (!bmap)
+			return NULL;
+		i = bmap->n_div;
+	}
+
+	return bmap;
+}
+
+/* Remove all divs that are unknown or defined in terms of unknown divs.
+ */
+__isl_give isl_basic_set *isl_basic_set_remove_unknown_divs(
+	__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_remove_unknown_divs(bset);
+}
+
+__isl_give isl_map *isl_map_remove_unknown_divs(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_remove_unknown_divs(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_remove_unknown_divs(__isl_take isl_set *set)
+{
+	return set_from_map(isl_map_remove_unknown_divs(set_to_map(set)));
+}
+
+__isl_give isl_basic_set *isl_basic_set_remove_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	isl_basic_map *bmap = bset_to_bmap(bset);
+	bmap = isl_basic_map_remove_dims(bmap, type, first, n);
+	return bset_from_bmap(bmap);
+}
+
+__isl_give isl_map *isl_map_remove_dims(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (n == 0)
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+	isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error);
+	
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_eliminate_vars(map->p[i],
+			isl_basic_map_offset(map->p[i], type) - 1 + first, n);
+		if (!map->p[i])
+			goto error;
+	}
+	map = isl_map_drop(map, type, first, n);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_remove_dims(__isl_take isl_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return set_from_map(isl_map_remove_dims(set_to_map(bset),
+						type, first, n));
+}
+
+/* Project out n inputs starting at first using Fourier-Motzkin */
+struct isl_map *isl_map_remove_inputs(struct isl_map *map,
+	unsigned first, unsigned n)
+{
+	return isl_map_remove_dims(map, isl_dim_in, first, n);
+}
+
+static void dump_term(struct isl_basic_map *bmap,
+			isl_int c, int pos, FILE *out)
+{
+	const char *name;
+	unsigned in = isl_basic_map_dim(bmap, isl_dim_in);
+	unsigned dim = in + isl_basic_map_dim(bmap, isl_dim_out);
+	unsigned nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	if (!pos)
+		isl_int_print(out, c, 0);
+	else {
+		if (!isl_int_is_one(c))
+			isl_int_print(out, c, 0);
+		if (pos < 1 + nparam) {
+			name = isl_space_get_dim_name(bmap->dim,
+						isl_dim_param, pos - 1);
+			if (name)
+				fprintf(out, "%s", name);
+			else
+				fprintf(out, "p%d", pos - 1);
+		} else if (pos < 1 + nparam + in)
+			fprintf(out, "i%d", pos - 1 - nparam);
+		else if (pos < 1 + nparam + dim)
+			fprintf(out, "o%d", pos - 1 - nparam - in);
+		else
+			fprintf(out, "e%d", pos - 1 - nparam - dim);
+	}
+}
+
+static void dump_constraint_sign(struct isl_basic_map *bmap, isl_int *c,
+				int sign, FILE *out)
+{
+	int i;
+	int first;
+	unsigned len = 1 + isl_basic_map_total_dim(bmap);
+	isl_int v;
+
+	isl_int_init(v);
+	for (i = 0, first = 1; i < len; ++i) {
+		if (isl_int_sgn(c[i]) * sign <= 0)
+			continue;
+		if (!first)
+			fprintf(out, " + ");
+		first = 0;
+		isl_int_abs(v, c[i]);
+		dump_term(bmap, v, i, out);
+	}
+	isl_int_clear(v);
+	if (first)
+		fprintf(out, "0");
+}
+
+static void dump_constraint(struct isl_basic_map *bmap, isl_int *c,
+				const char *op, FILE *out, int indent)
+{
+	int i;
+
+	fprintf(out, "%*s", indent, "");
+
+	dump_constraint_sign(bmap, c, 1, out);
+	fprintf(out, " %s ", op);
+	dump_constraint_sign(bmap, c, -1, out);
+
+	fprintf(out, "\n");
+
+	for (i = bmap->n_div; i < bmap->extra; ++i) {
+		if (isl_int_is_zero(c[1+isl_space_dim(bmap->dim, isl_dim_all)+i]))
+			continue;
+		fprintf(out, "%*s", indent, "");
+		fprintf(out, "ERROR: unused div coefficient not zero\n");
+		abort();
+	}
+}
+
+static void dump_constraints(struct isl_basic_map *bmap,
+				isl_int **c, unsigned n,
+				const char *op, FILE *out, int indent)
+{
+	int i;
+
+	for (i = 0; i < n; ++i)
+		dump_constraint(bmap, c[i], op, out, indent);
+}
+
+static void dump_affine(struct isl_basic_map *bmap, isl_int *exp, FILE *out)
+{
+	int j;
+	int first = 1;
+	unsigned total = isl_basic_map_total_dim(bmap);
+
+	for (j = 0; j < 1 + total; ++j) {
+		if (isl_int_is_zero(exp[j]))
+			continue;
+		if (!first && isl_int_is_pos(exp[j]))
+			fprintf(out, "+");
+		dump_term(bmap, exp[j], j, out);
+		first = 0;
+	}
+}
+
+static void dump(struct isl_basic_map *bmap, FILE *out, int indent)
+{
+	int i;
+
+	dump_constraints(bmap, bmap->eq, bmap->n_eq, "=", out, indent);
+	dump_constraints(bmap, bmap->ineq, bmap->n_ineq, ">=", out, indent);
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		fprintf(out, "%*s", indent, "");
+		fprintf(out, "e%d = [(", i);
+		dump_affine(bmap, bmap->div[i]+1, out);
+		fprintf(out, ")/");
+		isl_int_print(out, bmap->div[i][0], 0);
+		fprintf(out, "]\n");
+	}
+}
+
+void isl_basic_set_print_internal(struct isl_basic_set *bset,
+	FILE *out, int indent)
+{
+	if (!bset) {
+		fprintf(out, "null basic set\n");
+		return;
+	}
+
+	fprintf(out, "%*s", indent, "");
+	fprintf(out, "ref: %d, nparam: %d, dim: %d, extra: %d, flags: %x\n",
+			bset->ref, bset->dim->nparam, bset->dim->n_out,
+			bset->extra, bset->flags);
+	dump(bset_to_bmap(bset), out, indent);
+}
+
+void isl_basic_map_print_internal(struct isl_basic_map *bmap,
+	FILE *out, int indent)
+{
+	if (!bmap) {
+		fprintf(out, "null basic map\n");
+		return;
+	}
+
+	fprintf(out, "%*s", indent, "");
+	fprintf(out, "ref: %d, nparam: %d, in: %d, out: %d, extra: %d, "
+			"flags: %x, n_name: %d\n",
+		bmap->ref,
+		bmap->dim->nparam, bmap->dim->n_in, bmap->dim->n_out,
+		bmap->extra, bmap->flags, bmap->dim->n_id);
+	dump(bmap, out, indent);
+}
+
+int isl_inequality_negate(struct isl_basic_map *bmap, unsigned pos)
+{
+	unsigned total;
+	if (!bmap)
+		return -1;
+	total = isl_basic_map_total_dim(bmap);
+	isl_assert(bmap->ctx, pos < bmap->n_ineq, return -1);
+	isl_seq_neg(bmap->ineq[pos], bmap->ineq[pos], 1 + total);
+	isl_int_sub_ui(bmap->ineq[pos][0], bmap->ineq[pos][0], 1);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	return 0;
+}
+
+__isl_give isl_set *isl_set_alloc_space(__isl_take isl_space *space, int n,
+	unsigned flags)
+{
+	if (!space)
+		return NULL;
+	if (isl_space_dim(space, isl_dim_in) != 0)
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"set cannot have input dimensions", goto error);
+	return isl_map_alloc_space(space, n, flags);
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Make sure "map" has room for at least "n" more basic maps.
+ */
+__isl_give isl_map *isl_map_grow(__isl_take isl_map *map, int n)
+{
+	int i;
+	struct isl_map *grown = NULL;
+
+	if (!map)
+		return NULL;
+	isl_assert(map->ctx, n >= 0, goto error);
+	if (map->n + n <= map->size)
+		return map;
+	grown = isl_map_alloc_space(isl_map_get_space(map), map->n + n, map->flags);
+	if (!grown)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		grown->p[i] = isl_basic_map_copy(map->p[i]);
+		if (!grown->p[i])
+			goto error;
+		grown->n++;
+	}
+	isl_map_free(map);
+	return grown;
+error:
+	isl_map_free(grown);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Make sure "set" has room for at least "n" more basic sets.
+ */
+struct isl_set *isl_set_grow(struct isl_set *set, int n)
+{
+	return set_from_map(isl_map_grow(set_to_map(set), n));
+}
+
+__isl_give isl_set *isl_set_from_basic_set(__isl_take isl_basic_set *bset)
+{
+	return isl_map_from_basic_map(bset);
+}
+
+__isl_give isl_map *isl_map_from_basic_map(__isl_take isl_basic_map *bmap)
+{
+	struct isl_map *map;
+
+	if (!bmap)
+		return NULL;
+
+	map = isl_map_alloc_space(isl_space_copy(bmap->dim), 1, ISL_MAP_DISJOINT);
+	return isl_map_add_basic_map(map, bmap);
+}
+
+__isl_give isl_set *isl_set_add_basic_set(__isl_take isl_set *set,
+						__isl_take isl_basic_set *bset)
+{
+	return set_from_map(isl_map_add_basic_map(set_to_map(set),
+						bset_to_bmap(bset)));
+}
+
+__isl_null isl_set *isl_set_free(__isl_take isl_set *set)
+{
+	return isl_map_free(set);
+}
+
+void isl_set_print_internal(struct isl_set *set, FILE *out, int indent)
+{
+	int i;
+
+	if (!set) {
+		fprintf(out, "null set\n");
+		return;
+	}
+
+	fprintf(out, "%*s", indent, "");
+	fprintf(out, "ref: %d, n: %d, nparam: %d, dim: %d, flags: %x\n",
+			set->ref, set->n, set->dim->nparam, set->dim->n_out,
+			set->flags);
+	for (i = 0; i < set->n; ++i) {
+		fprintf(out, "%*s", indent, "");
+		fprintf(out, "basic set %d:\n", i);
+		isl_basic_set_print_internal(set->p[i], out, indent+4);
+	}
+}
+
+void isl_map_print_internal(struct isl_map *map, FILE *out, int indent)
+{
+	int i;
+
+	if (!map) {
+		fprintf(out, "null map\n");
+		return;
+	}
+
+	fprintf(out, "%*s", indent, "");
+	fprintf(out, "ref: %d, n: %d, nparam: %d, in: %d, out: %d, "
+		     "flags: %x, n_name: %d\n",
+			map->ref, map->n, map->dim->nparam, map->dim->n_in,
+			map->dim->n_out, map->flags, map->dim->n_id);
+	for (i = 0; i < map->n; ++i) {
+		fprintf(out, "%*s", indent, "");
+		fprintf(out, "basic map %d:\n", i);
+		isl_basic_map_print_internal(map->p[i], out, indent+4);
+	}
+}
+
+__isl_give isl_basic_map *isl_basic_map_intersect_domain(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *bset)
+{
+	struct isl_basic_map *bmap_domain;
+
+	if (isl_basic_map_check_equal_params(bmap, bset_to_bmap(bset)) < 0)
+		goto error;
+
+	if (isl_space_dim(bset->dim, isl_dim_set) != 0)
+		isl_assert(bset->ctx,
+		    isl_basic_map_compatible_domain(bmap, bset), goto error);
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		goto error;
+	bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+			bset->n_div, bset->n_eq, bset->n_ineq);
+	bmap_domain = isl_basic_map_from_domain(bset);
+	bmap = add_constraints(bmap, bmap_domain, 0, 0);
+
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Check that the space of "bset" is the same as that of the range of "bmap".
+ */
+static isl_stat isl_basic_map_check_compatible_range(
+	__isl_keep isl_basic_map *bmap, __isl_keep isl_basic_set *bset)
+{
+	isl_bool ok;
+
+	ok = isl_basic_map_compatible_range(bmap, bset);
+	if (ok < 0)
+		return isl_stat_error;
+	if (!ok)
+		isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid,
+			"incompatible spaces", return isl_stat_error);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_basic_map *isl_basic_map_intersect_range(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *bset)
+{
+	struct isl_basic_map *bmap_range;
+
+	if (isl_basic_map_check_equal_params(bmap, bset_to_bmap(bset)) < 0)
+		goto error;
+
+	if (isl_space_dim(bset->dim, isl_dim_set) != 0 &&
+	    isl_basic_map_check_compatible_range(bmap, bset) < 0)
+		goto error;
+
+	if (isl_basic_set_plain_is_universe(bset)) {
+		isl_basic_set_free(bset);
+		return bmap;
+	}
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		goto error;
+	bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+			bset->n_div, bset->n_eq, bset->n_ineq);
+	bmap_range = bset_to_bmap(bset);
+	bmap = add_constraints(bmap, bmap_range, 0, 0);
+
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+isl_bool isl_basic_map_contains(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_vec *vec)
+{
+	int i;
+	unsigned total;
+	isl_int s;
+
+	if (!bmap || !vec)
+		return isl_bool_error;
+
+	total = 1 + isl_basic_map_total_dim(bmap);
+	if (total != vec->size)
+		return isl_bool_false;
+
+	isl_int_init(s);
+
+	for (i = 0; i < bmap->n_eq; ++i) {
+		isl_seq_inner_product(vec->el, bmap->eq[i], total, &s);
+		if (!isl_int_is_zero(s)) {
+			isl_int_clear(s);
+			return isl_bool_false;
+		}
+	}
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		isl_seq_inner_product(vec->el, bmap->ineq[i], total, &s);
+		if (isl_int_is_neg(s)) {
+			isl_int_clear(s);
+			return isl_bool_false;
+		}
+	}
+
+	isl_int_clear(s);
+
+	return isl_bool_true;
+}
+
+isl_bool isl_basic_set_contains(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_vec *vec)
+{
+	return isl_basic_map_contains(bset_to_bmap(bset), vec);
+}
+
+__isl_give isl_basic_map *isl_basic_map_intersect(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+	struct isl_vec *sample = NULL;
+
+	if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0)
+		goto error;
+	if (isl_space_dim(bmap1->dim, isl_dim_all) ==
+				isl_space_dim(bmap1->dim, isl_dim_param) &&
+	    isl_space_dim(bmap2->dim, isl_dim_all) !=
+				isl_space_dim(bmap2->dim, isl_dim_param))
+		return isl_basic_map_intersect(bmap2, bmap1);
+
+	if (isl_space_dim(bmap2->dim, isl_dim_all) !=
+					isl_space_dim(bmap2->dim, isl_dim_param))
+		isl_assert(bmap1->ctx,
+			    isl_space_is_equal(bmap1->dim, bmap2->dim), goto error);
+
+	if (isl_basic_map_plain_is_empty(bmap1)) {
+		isl_basic_map_free(bmap2);
+		return bmap1;
+	}
+	if (isl_basic_map_plain_is_empty(bmap2)) {
+		isl_basic_map_free(bmap1);
+		return bmap2;
+	}
+
+	if (bmap1->sample &&
+	    isl_basic_map_contains(bmap1, bmap1->sample) > 0 &&
+	    isl_basic_map_contains(bmap2, bmap1->sample) > 0)
+		sample = isl_vec_copy(bmap1->sample);
+	else if (bmap2->sample &&
+	    isl_basic_map_contains(bmap1, bmap2->sample) > 0 &&
+	    isl_basic_map_contains(bmap2, bmap2->sample) > 0)
+		sample = isl_vec_copy(bmap2->sample);
+
+	bmap1 = isl_basic_map_cow(bmap1);
+	if (!bmap1)
+		goto error;
+	bmap1 = isl_basic_map_extend_space(bmap1, isl_space_copy(bmap1->dim),
+			bmap2->n_div, bmap2->n_eq, bmap2->n_ineq);
+	bmap1 = add_constraints(bmap1, bmap2, 0, 0);
+
+	if (!bmap1)
+		isl_vec_free(sample);
+	else if (sample) {
+		isl_vec_free(bmap1->sample);
+		bmap1->sample = sample;
+	}
+
+	bmap1 = isl_basic_map_simplify(bmap1);
+	return isl_basic_map_finalize(bmap1);
+error:
+	if (sample)
+		isl_vec_free(sample);
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_intersect(
+		struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+	return bset_from_bmap(isl_basic_map_intersect(bset_to_bmap(bset1),
+							bset_to_bmap(bset2)));
+}
+
+__isl_give isl_basic_set *isl_basic_set_intersect_params(
+	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+	return isl_basic_set_intersect(bset1, bset2);
+}
+
+/* Special case of isl_map_intersect, where both map1 and map2
+ * are convex, without any divs and such that either map1 or map2
+ * contains a single constraint.  This constraint is then simply
+ * added to the other map.
+ */
+static __isl_give isl_map *map_intersect_add_constraint(
+	__isl_take isl_map *map1, __isl_take isl_map *map2)
+{
+	isl_assert(map1->ctx, map1->n == 1, goto error);
+	isl_assert(map2->ctx, map1->n == 1, goto error);
+	isl_assert(map1->ctx, map1->p[0]->n_div == 0, goto error);
+	isl_assert(map2->ctx, map1->p[0]->n_div == 0, goto error);
+
+	if (map2->p[0]->n_eq + map2->p[0]->n_ineq != 1)
+		return isl_map_intersect(map2, map1);
+
+	map1 = isl_map_cow(map1);
+	if (!map1)
+		goto error;
+	if (isl_map_plain_is_empty(map1)) {
+		isl_map_free(map2);
+		return map1;
+	}
+	map1->p[0] = isl_basic_map_cow(map1->p[0]);
+	if (map2->p[0]->n_eq == 1)
+		map1->p[0] = isl_basic_map_add_eq(map1->p[0], map2->p[0]->eq[0]);
+	else
+		map1->p[0] = isl_basic_map_add_ineq(map1->p[0],
+							map2->p[0]->ineq[0]);
+
+	map1->p[0] = isl_basic_map_simplify(map1->p[0]);
+	map1->p[0] = isl_basic_map_finalize(map1->p[0]);
+	if (!map1->p[0])
+		goto error;
+
+	if (isl_basic_map_plain_is_empty(map1->p[0])) {
+		isl_basic_map_free(map1->p[0]);
+		map1->n = 0;
+	}
+
+	isl_map_free(map2);
+
+	return map1;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+/* map2 may be either a parameter domain or a map living in the same
+ * space as map1.
+ */
+static __isl_give isl_map *map_intersect_internal(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	unsigned flags = 0;
+	isl_map *result;
+	int i, j;
+
+	if (!map1 || !map2)
+		goto error;
+
+	if ((isl_map_plain_is_empty(map1) ||
+	     isl_map_plain_is_universe(map2)) &&
+	    isl_space_is_equal(map1->dim, map2->dim)) {
+		isl_map_free(map2);
+		return map1;
+	}
+	if ((isl_map_plain_is_empty(map2) ||
+	     isl_map_plain_is_universe(map1)) &&
+	    isl_space_is_equal(map1->dim, map2->dim)) {
+		isl_map_free(map1);
+		return map2;
+	}
+
+	if (map1->n == 1 && map2->n == 1 &&
+	    map1->p[0]->n_div == 0 && map2->p[0]->n_div == 0 &&
+	    isl_space_is_equal(map1->dim, map2->dim) &&
+	    (map1->p[0]->n_eq + map1->p[0]->n_ineq == 1 ||
+	     map2->p[0]->n_eq + map2->p[0]->n_ineq == 1))
+		return map_intersect_add_constraint(map1, map2);
+
+	if (isl_space_dim(map2->dim, isl_dim_all) !=
+				isl_space_dim(map2->dim, isl_dim_param))
+		isl_assert(map1->ctx,
+			    isl_space_is_equal(map1->dim, map2->dim), goto error);
+
+	if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) &&
+	    ISL_F_ISSET(map2, ISL_MAP_DISJOINT))
+		ISL_FL_SET(flags, ISL_MAP_DISJOINT);
+
+	result = isl_map_alloc_space(isl_space_copy(map1->dim),
+				map1->n * map2->n, flags);
+	if (!result)
+		goto error;
+	for (i = 0; i < map1->n; ++i)
+		for (j = 0; j < map2->n; ++j) {
+			struct isl_basic_map *part;
+			part = isl_basic_map_intersect(
+				    isl_basic_map_copy(map1->p[i]),
+				    isl_basic_map_copy(map2->p[j]));
+			if (isl_basic_map_is_empty(part) < 0)
+				part = isl_basic_map_free(part);
+			result = isl_map_add_basic_map(result, part);
+			if (!result)
+				goto error;
+		}
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return result;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+static __isl_give isl_map *map_intersect(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	if (!map1 || !map2)
+		goto error;
+	if (!isl_space_is_equal(map1->dim, map2->dim))
+		isl_die(isl_map_get_ctx(map1), isl_error_invalid,
+			"spaces don't match", goto error);
+	return map_intersect_internal(map1, map2);
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_intersect(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_intersect);
+}
+
+struct isl_set *isl_set_intersect(struct isl_set *set1, struct isl_set *set2)
+{
+	return set_from_map(isl_map_intersect(set_to_map(set1),
+					      set_to_map(set2)));
+}
+
+/* map_intersect_internal accepts intersections
+ * with parameter domains, so we can just call that function.
+ */
+static __isl_give isl_map *map_intersect_params(__isl_take isl_map *map,
+		__isl_take isl_set *params)
+{
+	return map_intersect_internal(map, params);
+}
+
+__isl_give isl_map *isl_map_intersect_params(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_intersect_params);
+}
+
+__isl_give isl_set *isl_set_intersect_params(__isl_take isl_set *set,
+		__isl_take isl_set *params)
+{
+	return isl_map_intersect_params(set, params);
+}
+
+__isl_give isl_basic_map *isl_basic_map_reverse(__isl_take isl_basic_map *bmap)
+{
+	isl_space *space;
+	unsigned pos, n1, n2;
+
+	if (!bmap)
+		return NULL;
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	space = isl_space_reverse(isl_space_copy(bmap->dim));
+	pos = isl_basic_map_offset(bmap, isl_dim_in);
+	n1 = isl_basic_map_dim(bmap, isl_dim_in);
+	n2 = isl_basic_map_dim(bmap, isl_dim_out);
+	bmap = isl_basic_map_swap_vars(bmap, pos, n1, n2);
+	return isl_basic_map_reset_space(bmap, space);
+}
+
+static __isl_give isl_basic_map *basic_map_space_reset(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type)
+{
+	isl_space *space;
+
+	if (!bmap)
+		return NULL;
+	if (!isl_space_is_named_or_nested(bmap->dim, type))
+		return bmap;
+
+	space = isl_basic_map_get_space(bmap);
+	space = isl_space_reset(space, type);
+	bmap = isl_basic_map_reset_space(bmap, space);
+	return bmap;
+}
+
+__isl_give isl_basic_map *isl_basic_map_insert_dims(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type,
+	unsigned pos, unsigned n)
+{
+	isl_bool rational;
+	isl_space *res_dim;
+	struct isl_basic_map *res;
+	struct isl_dim_map *dim_map;
+	unsigned total, off;
+	enum isl_dim_type t;
+
+	if (n == 0)
+		return basic_map_space_reset(bmap, type);
+
+	if (!bmap)
+		return NULL;
+
+	res_dim = isl_space_insert_dims(isl_basic_map_get_space(bmap), type, pos, n);
+
+	total = isl_basic_map_total_dim(bmap) + n;
+	dim_map = isl_dim_map_alloc(bmap->ctx, total);
+	off = 0;
+	for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+		if (t != type) {
+			isl_dim_map_dim(dim_map, bmap->dim, t, off);
+		} else {
+			unsigned size = isl_basic_map_dim(bmap, t);
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+						0, pos, off);
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+						pos, size - pos, off + pos + n);
+		}
+		off += isl_space_dim(res_dim, t);
+	}
+	isl_dim_map_div(dim_map, bmap, off);
+
+	res = isl_basic_map_alloc_space(res_dim,
+			bmap->n_div, bmap->n_eq, bmap->n_ineq);
+	rational = isl_basic_map_is_rational(bmap);
+	if (rational < 0)
+		res = isl_basic_map_free(res);
+	if (rational)
+		res = isl_basic_map_set_rational(res);
+	if (isl_basic_map_plain_is_empty(bmap)) {
+		isl_basic_map_free(bmap);
+		free(dim_map);
+		return isl_basic_map_set_to_empty(res);
+	}
+	res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+	return isl_basic_map_finalize(res);
+}
+
+__isl_give isl_basic_set *isl_basic_set_insert_dims(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, unsigned n)
+{
+	return isl_basic_map_insert_dims(bset, type, pos, n);
+}
+
+__isl_give isl_basic_map *isl_basic_map_add_dims(__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned n)
+{
+	if (!bmap)
+		return NULL;
+	return isl_basic_map_insert_dims(bmap, type,
+					isl_basic_map_dim(bmap, type), n);
+}
+
+__isl_give isl_basic_set *isl_basic_set_add_dims(__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned n)
+{
+	if (!bset)
+		return NULL;
+	isl_assert(bset->ctx, type != isl_dim_in, goto error);
+	return isl_basic_map_add_dims(bset, type, n);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+static __isl_give isl_map *map_space_reset(__isl_take isl_map *map,
+	enum isl_dim_type type)
+{
+	isl_space *space;
+
+	if (!map || !isl_space_is_named_or_nested(map->dim, type))
+		return map;
+
+	space = isl_map_get_space(map);
+	space = isl_space_reset(space, type);
+	map = isl_map_reset_space(map, space);
+	return map;
+}
+
+__isl_give isl_map *isl_map_insert_dims(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, unsigned n)
+{
+	int i;
+
+	if (n == 0)
+		return map_space_reset(map, type);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_insert_dims(map->dim, type, pos, n);
+	if (!map->dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_insert_dims(map->p[i], type, pos, n);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_insert_dims(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, unsigned n)
+{
+	return isl_map_insert_dims(set, type, pos, n);
+}
+
+__isl_give isl_map *isl_map_add_dims(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned n)
+{
+	if (!map)
+		return NULL;
+	return isl_map_insert_dims(map, type, isl_map_dim(map, type), n);
+}
+
+__isl_give isl_set *isl_set_add_dims(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned n)
+{
+	if (!set)
+		return NULL;
+	isl_assert(set->ctx, type != isl_dim_in, goto error);
+	return set_from_map(isl_map_add_dims(set_to_map(set), type, n));
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_move_dims(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	struct isl_dim_map *dim_map;
+	struct isl_basic_map *res;
+	enum isl_dim_type t;
+	unsigned total, off;
+
+	if (!bmap)
+		return NULL;
+	if (n == 0) {
+		bmap = isl_basic_map_reset(bmap, src_type);
+		bmap = isl_basic_map_reset(bmap, dst_type);
+		return bmap;
+	}
+
+	if (isl_basic_map_check_range(bmap, src_type, src_pos, n) < 0)
+		return isl_basic_map_free(bmap);
+
+	if (dst_type == src_type && dst_pos == src_pos)
+		return bmap;
+
+	isl_assert(bmap->ctx, dst_type != src_type, goto error);
+
+	if (pos(bmap->dim, dst_type) + dst_pos ==
+	    pos(bmap->dim, src_type) + src_pos +
+					    ((src_type < dst_type) ? n : 0)) {
+		bmap = isl_basic_map_cow(bmap);
+		if (!bmap)
+			return NULL;
+
+		bmap->dim = isl_space_move_dims(bmap->dim, dst_type, dst_pos,
+						src_type, src_pos, n);
+		if (!bmap->dim)
+			goto error;
+
+		bmap = isl_basic_map_finalize(bmap);
+
+		return bmap;
+	}
+
+	total = isl_basic_map_total_dim(bmap);
+	dim_map = isl_dim_map_alloc(bmap->ctx, total);
+
+	off = 0;
+	for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+		unsigned size = isl_space_dim(bmap->dim, t);
+		if (t == dst_type) {
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					    0, dst_pos, off);
+			off += dst_pos;
+			isl_dim_map_dim_range(dim_map, bmap->dim, src_type,
+					    src_pos, n, off);
+			off += n;
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					    dst_pos, size - dst_pos, off);
+			off += size - dst_pos;
+		} else if (t == src_type) {
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					    0, src_pos, off);
+			off += src_pos;
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					src_pos + n, size - src_pos - n, off);
+			off += size - src_pos - n;
+		} else {
+			isl_dim_map_dim(dim_map, bmap->dim, t, off);
+			off += size;
+		}
+	}
+	isl_dim_map_div(dim_map, bmap, off);
+
+	res = isl_basic_map_alloc_space(isl_basic_map_get_space(bmap),
+			bmap->n_div, bmap->n_eq, bmap->n_ineq);
+	bmap = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+	if (!bmap)
+		goto error;
+
+	bmap->dim = isl_space_move_dims(bmap->dim, dst_type, dst_pos,
+					src_type, src_pos, n);
+	if (!bmap->dim)
+		goto error;
+
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_move_dims(__isl_take isl_basic_set *bset,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	isl_basic_map *bmap = bset_to_bmap(bset);
+	bmap = isl_basic_map_move_dims(bmap, dst_type, dst_pos,
+					src_type, src_pos, n);
+	return bset_from_bmap(bmap);
+}
+
+__isl_give isl_set *isl_set_move_dims(__isl_take isl_set *set,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	if (!set)
+		return NULL;
+	isl_assert(set->ctx, dst_type != isl_dim_in, goto error);
+	return set_from_map(isl_map_move_dims(set_to_map(set),
+				    dst_type, dst_pos, src_type, src_pos, n));
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_move_dims(__isl_take isl_map *map,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	if (n == 0) {
+		map = isl_map_reset(map, src_type);
+		map = isl_map_reset(map, dst_type);
+		return map;
+	}
+
+	isl_assert(map->ctx, src_pos + n <= isl_map_dim(map, src_type),
+		goto error);
+
+	if (dst_type == src_type && dst_pos == src_pos)
+		return map;
+
+	isl_assert(map->ctx, dst_type != src_type, goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_move_dims(map->dim, dst_type, dst_pos, src_type, src_pos, n);
+	if (!map->dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_move_dims(map->p[i],
+						dst_type, dst_pos,
+						src_type, src_pos, n);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Move the specified dimensions to the last columns right before
+ * the divs.  Don't change the dimension specification of bmap.
+ * That's the responsibility of the caller.
+ */
+static __isl_give isl_basic_map *move_last(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	struct isl_dim_map *dim_map;
+	struct isl_basic_map *res;
+	enum isl_dim_type t;
+	unsigned total, off;
+
+	if (!bmap)
+		return NULL;
+	if (pos(bmap->dim, type) + first + n ==
+				1 + isl_space_dim(bmap->dim, isl_dim_all))
+		return bmap;
+
+	total = isl_basic_map_total_dim(bmap);
+	dim_map = isl_dim_map_alloc(bmap->ctx, total);
+
+	off = 0;
+	for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+		unsigned size = isl_space_dim(bmap->dim, t);
+		if (t == type) {
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					    0, first, off);
+			off += first;
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					    first, n, total - bmap->n_div - n);
+			isl_dim_map_dim_range(dim_map, bmap->dim, t,
+					    first + n, size - (first + n), off);
+			off += size - (first + n);
+		} else {
+			isl_dim_map_dim(dim_map, bmap->dim, t, off);
+			off += size;
+		}
+	}
+	isl_dim_map_div(dim_map, bmap, off + n);
+
+	res = isl_basic_map_alloc_space(isl_basic_map_get_space(bmap),
+			bmap->n_div, bmap->n_eq, bmap->n_ineq);
+	res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+	return res;
+}
+
+/* Insert "n" rows in the divs of "bmap".
+ *
+ * The number of columns is not changed, which means that the last
+ * dimensions of "bmap" are being reintepreted as the new divs.
+ * The space of "bmap" is not adjusted, however, which means
+ * that "bmap" is left in an inconsistent state.  Removing "n" dimensions
+ * from the space of "bmap" is the responsibility of the caller.
+ */
+static __isl_give isl_basic_map *insert_div_rows(__isl_take isl_basic_map *bmap,
+	int n)
+{
+	int i;
+	size_t row_size;
+	isl_int **new_div;
+	isl_int *old;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	row_size = 1 + isl_space_dim(bmap->dim, isl_dim_all) + bmap->extra;
+	old = bmap->block2.data;
+	bmap->block2 = isl_blk_extend(bmap->ctx, bmap->block2,
+					(bmap->extra + n) * (1 + row_size));
+	if (!bmap->block2.data)
+		return isl_basic_map_free(bmap);
+	new_div = isl_alloc_array(bmap->ctx, isl_int *, bmap->extra + n);
+	if (!new_div)
+		return isl_basic_map_free(bmap);
+	for (i = 0; i < n; ++i) {
+		new_div[i] = bmap->block2.data +
+				(bmap->extra + i) * (1 + row_size);
+		isl_seq_clr(new_div[i], 1 + row_size);
+	}
+	for (i = 0; i < bmap->extra; ++i)
+		new_div[n + i] = bmap->block2.data + (bmap->div[i] - old);
+	free(bmap->div);
+	bmap->div = new_div;
+	bmap->n_div += n;
+	bmap->extra += n;
+
+	return bmap;
+}
+
+/* Drop constraints from "bmap" that only involve the variables
+ * of "type" in the range [first, first + n] that are not related
+ * to any of the variables outside that interval.
+ * These constraints cannot influence the values for the variables
+ * outside the interval, except in case they cause "bmap" to be empty.
+ * Only drop the constraints if "bmap" is known to be non-empty.
+ */
+static __isl_give isl_basic_map *drop_irrelevant_constraints(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type,
+	unsigned first, unsigned n)
+{
+	int i;
+	int *groups;
+	unsigned dim, n_div;
+	isl_bool non_empty;
+
+	non_empty = isl_basic_map_plain_is_non_empty(bmap);
+	if (non_empty < 0)
+		return isl_basic_map_free(bmap);
+	if (!non_empty)
+		return bmap;
+
+	dim = isl_basic_map_dim(bmap, isl_dim_all);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	groups = isl_calloc_array(isl_basic_map_get_ctx(bmap), int, dim);
+	if (!groups)
+		return isl_basic_map_free(bmap);
+	first += isl_basic_map_offset(bmap, type) - 1;
+	for (i = 0; i < first; ++i)
+		groups[i] = -1;
+	for (i = first + n; i < dim - n_div; ++i)
+		groups[i] = -1;
+
+	bmap = isl_basic_map_drop_unrelated_constraints(bmap, groups);
+
+	return bmap;
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ *
+ * If a subset of the projected out variables are unrelated
+ * to any of the variables that remain, then the constraints
+ * involving this subset are simply dropped first.
+ */
+__isl_give isl_basic_map *isl_basic_map_project_out(
+		__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned first, unsigned n)
+{
+	isl_bool empty;
+
+	if (n == 0)
+		return basic_map_space_reset(bmap, type);
+	if (type == isl_dim_div)
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"cannot project out existentially quantified variables",
+			return isl_basic_map_free(bmap));
+
+	empty = isl_basic_map_plain_is_empty(bmap);
+	if (empty < 0)
+		return isl_basic_map_free(bmap);
+	if (empty)
+		bmap = isl_basic_map_set_to_empty(bmap);
+
+	bmap = drop_irrelevant_constraints(bmap, type, first, n);
+	if (!bmap)
+		return NULL;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+		return isl_basic_map_remove_dims(bmap, type, first, n);
+
+	if (isl_basic_map_check_range(bmap, type, first, n) < 0)
+		return isl_basic_map_free(bmap);
+
+	bmap = move_last(bmap, type, first, n);
+	bmap = isl_basic_map_cow(bmap);
+	bmap = insert_div_rows(bmap, n);
+	if (!bmap)
+		return NULL;
+
+	bmap->dim = isl_space_drop_dims(bmap->dim, type, first, n);
+	if (!bmap->dim)
+		goto error;
+	bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_drop_redundant_divs(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+struct isl_basic_set *isl_basic_set_project_out(struct isl_basic_set *bset,
+		enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return bset_from_bmap(isl_basic_map_project_out(bset_to_bmap(bset),
+							type, first, n));
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+__isl_give isl_map *isl_map_project_out(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (n == 0)
+		return map_space_reset(map, type);
+
+	isl_assert(map->ctx, first + n <= isl_map_dim(map, type), goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_drop_dims(map->dim, type, first, n);
+	if (!map->dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_project_out(map->p[i], type, first, n);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+__isl_give isl_set *isl_set_project_out(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return set_from_map(isl_map_project_out(set_to_map(set),
+						type, first, n));
+}
+
+/* Return a map that projects the elements in "set" onto their
+ * "n" set dimensions starting at "first".
+ * "type" should be equal to isl_dim_set.
+ */
+__isl_give isl_map *isl_set_project_onto_map(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	int dim;
+	isl_map *map;
+
+	if (!set)
+		return NULL;
+	if (type != isl_dim_set)
+		isl_die(isl_set_get_ctx(set), isl_error_invalid,
+			"only set dimensions can be projected out", goto error);
+	dim = isl_set_dim(set, isl_dim_set);
+	if (first + n > dim || first + n < first)
+		isl_die(isl_set_get_ctx(set), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	map = isl_map_from_domain(set);
+	map = isl_map_add_dims(map, isl_dim_out, n);
+	for (i = 0; i < n; ++i)
+		map = isl_map_equate(map, isl_dim_in, first + i,
+					isl_dim_out, i);
+	return map;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+static struct isl_basic_map *add_divs(struct isl_basic_map *bmap, unsigned n)
+{
+	int i, j;
+
+	for (i = 0; i < n; ++i) {
+		j = isl_basic_map_alloc_div(bmap);
+		if (j < 0)
+			goto error;
+		isl_seq_clr(bmap->div[j], 1+1+isl_basic_map_total_dim(bmap));
+	}
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_apply_range(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	isl_space *dim_result = NULL;
+	struct isl_basic_map *bmap;
+	unsigned n_in, n_out, n, nparam, total, pos;
+	struct isl_dim_map *dim_map1, *dim_map2;
+
+	if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0)
+		goto error;
+	if (!isl_space_tuple_is_equal(bmap1->dim, isl_dim_out,
+				    bmap2->dim, isl_dim_in))
+		isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	dim_result = isl_space_join(isl_space_copy(bmap1->dim),
+				  isl_space_copy(bmap2->dim));
+
+	n_in = isl_basic_map_dim(bmap1, isl_dim_in);
+	n_out = isl_basic_map_dim(bmap2, isl_dim_out);
+	n = isl_basic_map_dim(bmap1, isl_dim_out);
+	nparam = isl_basic_map_dim(bmap1, isl_dim_param);
+
+	total = nparam + n_in + n_out + bmap1->n_div + bmap2->n_div + n;
+	dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+	dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += n_in);
+	isl_dim_map_div(dim_map1, bmap1, pos += n_out);
+	isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += bmap2->n_div);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos);
+
+	bmap = isl_basic_map_alloc_space(dim_result,
+			bmap1->n_div + bmap2->n_div + n,
+			bmap1->n_eq + bmap2->n_eq,
+			bmap1->n_ineq + bmap2->n_ineq);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+	bmap = add_divs(bmap, n);
+	bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_drop_redundant_divs(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_apply(
+		struct isl_basic_set *bset, struct isl_basic_map *bmap)
+{
+	if (!bset || !bmap)
+		goto error;
+
+	isl_assert(bset->ctx, isl_basic_map_compatible_domain(bmap, bset),
+		    goto error);
+
+	return bset_from_bmap(isl_basic_map_apply_range(bset_to_bmap(bset),
+							bmap));
+error:
+	isl_basic_set_free(bset);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_apply_domain(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0)
+		goto error;
+	if (!isl_space_tuple_is_equal(bmap1->dim, isl_dim_in,
+					bmap2->dim, isl_dim_in))
+		isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	bmap1 = isl_basic_map_reverse(bmap1);
+	bmap1 = isl_basic_map_apply_range(bmap1, bmap2);
+	return isl_basic_map_reverse(bmap1);
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+/* Given two basic maps A -> f(A) and B -> g(B), construct a basic map
+ * A \cap B -> f(A) + f(B)
+ */
+__isl_give isl_basic_map *isl_basic_map_sum(__isl_take isl_basic_map *bmap1,
+	__isl_take isl_basic_map *bmap2)
+{
+	unsigned n_in, n_out, nparam, total, pos;
+	struct isl_basic_map *bmap = NULL;
+	struct isl_dim_map *dim_map1, *dim_map2;
+	int i;
+
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim),
+		goto error);
+
+	nparam = isl_basic_map_dim(bmap1, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap1, isl_dim_in);
+	n_out = isl_basic_map_dim(bmap1, isl_dim_out);
+
+	total = nparam + n_in + n_out + bmap1->n_div + bmap2->n_div + 2 * n_out;
+	dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+	dim_map2 = isl_dim_map_alloc(bmap2->ctx, total);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos);
+	isl_dim_map_div(dim_map1, bmap1, pos += n_in + n_out);
+	isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += bmap2->n_div);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += n_out);
+
+	bmap = isl_basic_map_alloc_space(isl_space_copy(bmap1->dim),
+			bmap1->n_div + bmap2->n_div + 2 * n_out,
+			bmap1->n_eq + bmap2->n_eq + n_out,
+			bmap1->n_ineq + bmap2->n_ineq);
+	for (i = 0; i < n_out; ++i) {
+		int j = isl_basic_map_alloc_equality(bmap);
+		if (j < 0)
+			goto error;
+		isl_seq_clr(bmap->eq[j], 1+total);
+		isl_int_set_si(bmap->eq[j][1+nparam+n_in+i], -1);
+		isl_int_set_si(bmap->eq[j][1+pos+i], 1);
+		isl_int_set_si(bmap->eq[j][1+pos-n_out+i], 1);
+	}
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+	bmap = add_divs(bmap, 2 * n_out);
+
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+/* Given two maps A -> f(A) and B -> g(B), construct a map
+ * A \cap B -> f(A) + f(B)
+ */
+__isl_give isl_map *isl_map_sum(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	struct isl_map *result;
+	int i, j;
+
+	if (!map1 || !map2)
+		goto error;
+
+	isl_assert(map1->ctx, isl_space_is_equal(map1->dim, map2->dim), goto error);
+
+	result = isl_map_alloc_space(isl_space_copy(map1->dim),
+				map1->n * map2->n, 0);
+	if (!result)
+		goto error;
+	for (i = 0; i < map1->n; ++i)
+		for (j = 0; j < map2->n; ++j) {
+			struct isl_basic_map *part;
+			part = isl_basic_map_sum(
+				    isl_basic_map_copy(map1->p[i]),
+				    isl_basic_map_copy(map2->p[j]));
+			if (isl_basic_map_is_empty(part))
+				isl_basic_map_free(part);
+			else
+				result = isl_map_add_basic_map(result, part);
+			if (!result)
+				goto error;
+		}
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return result;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_sum(__isl_take isl_set *set1,
+	__isl_take isl_set *set2)
+{
+	return set_from_map(isl_map_sum(set_to_map(set1), set_to_map(set2)));
+}
+
+/* Given a basic map A -> f(A), construct A -> -f(A).
+ */
+__isl_give isl_basic_map *isl_basic_map_neg(__isl_take isl_basic_map *bmap)
+{
+	int i, j;
+	unsigned off, n;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	n = isl_basic_map_dim(bmap, isl_dim_out);
+	off = isl_basic_map_offset(bmap, isl_dim_out);
+	for (i = 0; i < bmap->n_eq; ++i)
+		for (j = 0; j < n; ++j)
+			isl_int_neg(bmap->eq[i][off+j], bmap->eq[i][off+j]);
+	for (i = 0; i < bmap->n_ineq; ++i)
+		for (j = 0; j < n; ++j)
+			isl_int_neg(bmap->ineq[i][off+j], bmap->ineq[i][off+j]);
+	for (i = 0; i < bmap->n_div; ++i)
+		for (j = 0; j < n; ++j)
+			isl_int_neg(bmap->div[i][1+off+j], bmap->div[i][1+off+j]);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	return isl_basic_map_finalize(bmap);
+}
+
+__isl_give isl_basic_set *isl_basic_set_neg(__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_neg(bset);
+}
+
+/* Given a map A -> f(A), construct A -> -f(A).
+ */
+__isl_give isl_map *isl_map_neg(__isl_take isl_map *map)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_neg(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_neg(__isl_take isl_set *set)
+{
+	return set_from_map(isl_map_neg(set_to_map(set)));
+}
+
+/* Given a basic map A -> f(A) and an integer d, construct a basic map
+ * A -> floor(f(A)/d).
+ */
+__isl_give isl_basic_map *isl_basic_map_floordiv(__isl_take isl_basic_map *bmap,
+		isl_int d)
+{
+	unsigned n_in, n_out, nparam, total, pos;
+	struct isl_basic_map *result = NULL;
+	struct isl_dim_map *dim_map;
+	int i;
+
+	if (!bmap)
+		return NULL;
+
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+
+	total = nparam + n_in + n_out + bmap->n_div + n_out;
+	dim_map = isl_dim_map_alloc(bmap->ctx, total);
+	isl_dim_map_dim(dim_map, bmap->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map, bmap->dim, isl_dim_in, pos += nparam);
+	isl_dim_map_div(dim_map, bmap, pos += n_in + n_out);
+	isl_dim_map_dim(dim_map, bmap->dim, isl_dim_out, pos += bmap->n_div);
+
+	result = isl_basic_map_alloc_space(isl_space_copy(bmap->dim),
+			bmap->n_div + n_out,
+			bmap->n_eq, bmap->n_ineq + 2 * n_out);
+	result = isl_basic_map_add_constraints_dim_map(result, bmap, dim_map);
+	result = add_divs(result, n_out);
+	for (i = 0; i < n_out; ++i) {
+		int j;
+		j = isl_basic_map_alloc_inequality(result);
+		if (j < 0)
+			goto error;
+		isl_seq_clr(result->ineq[j], 1+total);
+		isl_int_neg(result->ineq[j][1+nparam+n_in+i], d);
+		isl_int_set_si(result->ineq[j][1+pos+i], 1);
+		j = isl_basic_map_alloc_inequality(result);
+		if (j < 0)
+			goto error;
+		isl_seq_clr(result->ineq[j], 1+total);
+		isl_int_set(result->ineq[j][1+nparam+n_in+i], d);
+		isl_int_set_si(result->ineq[j][1+pos+i], -1);
+		isl_int_sub_ui(result->ineq[j][0], d, 1);
+	}
+
+	result = isl_basic_map_simplify(result);
+	return isl_basic_map_finalize(result);
+error:
+	isl_basic_map_free(result);
+	return NULL;
+}
+
+/* Given a map A -> f(A) and an integer d, construct a map
+ * A -> floor(f(A)/d).
+ */
+__isl_give isl_map *isl_map_floordiv(__isl_take isl_map *map, isl_int d)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	ISL_F_CLR(map, ISL_MAP_DISJOINT);
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_floordiv(map->p[i], d);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Given a map A -> f(A) and an integer d, construct a map
+ * A -> floor(f(A)/d).
+ */
+__isl_give isl_map *isl_map_floordiv_val(__isl_take isl_map *map,
+	__isl_take isl_val *d)
+{
+	if (!map || !d)
+		goto error;
+	if (!isl_val_is_int(d))
+		isl_die(isl_val_get_ctx(d), isl_error_invalid,
+			"expecting integer denominator", goto error);
+	map = isl_map_floordiv(map, d->n);
+	isl_val_free(d);
+	return map;
+error:
+	isl_map_free(map);
+	isl_val_free(d);
+	return NULL;
+}
+
+static __isl_give isl_basic_map *var_equal(__isl_take isl_basic_map *bmap,
+	unsigned pos)
+{
+	int i;
+	unsigned nparam;
+	unsigned n_in;
+
+	i = isl_basic_map_alloc_equality(bmap);
+	if (i < 0)
+		goto error;
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->eq[i][1+nparam+pos], -1);
+	isl_int_set_si(bmap->eq[i][1+nparam+n_in+pos], 1);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Add a constraint to "bmap" expressing i_pos < o_pos
+ */
+static __isl_give isl_basic_map *var_less(__isl_take isl_basic_map *bmap,
+	unsigned pos)
+{
+	int i;
+	unsigned nparam;
+	unsigned n_in;
+
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		goto error;
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->ineq[i][0], -1);
+	isl_int_set_si(bmap->ineq[i][1+nparam+pos], -1);
+	isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], 1);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Add a constraint to "bmap" expressing i_pos <= o_pos
+ */
+static __isl_give isl_basic_map *var_less_or_equal(
+	__isl_take isl_basic_map *bmap, unsigned pos)
+{
+	int i;
+	unsigned nparam;
+	unsigned n_in;
+
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		goto error;
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->ineq[i][1+nparam+pos], -1);
+	isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], 1);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Add a constraint to "bmap" expressing i_pos > o_pos
+ */
+static __isl_give isl_basic_map *var_more(__isl_take isl_basic_map *bmap,
+	unsigned pos)
+{
+	int i;
+	unsigned nparam;
+	unsigned n_in;
+
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		goto error;
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->ineq[i][0], -1);
+	isl_int_set_si(bmap->ineq[i][1+nparam+pos], 1);
+	isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], -1);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Add a constraint to "bmap" expressing i_pos >= o_pos
+ */
+static __isl_give isl_basic_map *var_more_or_equal(
+	__isl_take isl_basic_map *bmap, unsigned pos)
+{
+	int i;
+	unsigned nparam;
+	unsigned n_in;
+
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		goto error;
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->ineq[i][1+nparam+pos], 1);
+	isl_int_set_si(bmap->ineq[i][1+nparam+n_in+pos], -1);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_equal(
+	__isl_take isl_space *dim, unsigned n_equal)
+{
+	int i;
+	struct isl_basic_map *bmap;
+	bmap = isl_basic_map_alloc_space(dim, 0, n_equal, 0);
+	if (!bmap)
+		return NULL;
+	for (i = 0; i < n_equal && bmap; ++i)
+		bmap = var_equal(bmap, i);
+	return isl_basic_map_finalize(bmap);
+}
+
+/* Return a relation on of dimension "dim" expressing i_[0..pos] << o_[0..pos]
+ */
+__isl_give isl_basic_map *isl_basic_map_less_at(__isl_take isl_space *dim,
+	unsigned pos)
+{
+	int i;
+	struct isl_basic_map *bmap;
+	bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
+	if (!bmap)
+		return NULL;
+	for (i = 0; i < pos && bmap; ++i)
+		bmap = var_equal(bmap, i);
+	if (bmap)
+		bmap = var_less(bmap, pos);
+	return isl_basic_map_finalize(bmap);
+}
+
+/* Return a relation on "dim" expressing i_[0..pos] <<= o_[0..pos]
+ */
+__isl_give isl_basic_map *isl_basic_map_less_or_equal_at(
+	__isl_take isl_space *dim, unsigned pos)
+{
+	int i;
+	isl_basic_map *bmap;
+
+	bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
+	for (i = 0; i < pos; ++i)
+		bmap = var_equal(bmap, i);
+	bmap = var_less_or_equal(bmap, pos);
+	return isl_basic_map_finalize(bmap);
+}
+
+/* Return a relation on "dim" expressing i_pos > o_pos
+ */
+__isl_give isl_basic_map *isl_basic_map_more_at(__isl_take isl_space *dim,
+	unsigned pos)
+{
+	int i;
+	struct isl_basic_map *bmap;
+	bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
+	if (!bmap)
+		return NULL;
+	for (i = 0; i < pos && bmap; ++i)
+		bmap = var_equal(bmap, i);
+	if (bmap)
+		bmap = var_more(bmap, pos);
+	return isl_basic_map_finalize(bmap);
+}
+
+/* Return a relation on "dim" expressing i_[0..pos] >>= o_[0..pos]
+ */
+__isl_give isl_basic_map *isl_basic_map_more_or_equal_at(
+	__isl_take isl_space *dim, unsigned pos)
+{
+	int i;
+	isl_basic_map *bmap;
+
+	bmap = isl_basic_map_alloc_space(dim, 0, pos, 1);
+	for (i = 0; i < pos; ++i)
+		bmap = var_equal(bmap, i);
+	bmap = var_more_or_equal(bmap, pos);
+	return isl_basic_map_finalize(bmap);
+}
+
+static __isl_give isl_map *map_lex_lte_first(__isl_take isl_space *dims,
+	unsigned n, int equal)
+{
+	struct isl_map *map;
+	int i;
+
+	if (n == 0 && equal)
+		return isl_map_universe(dims);
+
+	map = isl_map_alloc_space(isl_space_copy(dims), n, ISL_MAP_DISJOINT);
+
+	for (i = 0; i + 1 < n; ++i)
+		map = isl_map_add_basic_map(map,
+				  isl_basic_map_less_at(isl_space_copy(dims), i));
+	if (n > 0) {
+		if (equal)
+			map = isl_map_add_basic_map(map,
+			      isl_basic_map_less_or_equal_at(dims, n - 1));
+		else
+			map = isl_map_add_basic_map(map,
+			      isl_basic_map_less_at(dims, n - 1));
+	} else
+		isl_space_free(dims);
+
+	return map;
+}
+
+static __isl_give isl_map *map_lex_lte(__isl_take isl_space *dims, int equal)
+{
+	if (!dims)
+		return NULL;
+	return map_lex_lte_first(dims, dims->n_out, equal);
+}
+
+__isl_give isl_map *isl_map_lex_lt_first(__isl_take isl_space *dim, unsigned n)
+{
+	return map_lex_lte_first(dim, n, 0);
+}
+
+__isl_give isl_map *isl_map_lex_le_first(__isl_take isl_space *dim, unsigned n)
+{
+	return map_lex_lte_first(dim, n, 1);
+}
+
+__isl_give isl_map *isl_map_lex_lt(__isl_take isl_space *set_dim)
+{
+	return map_lex_lte(isl_space_map_from_set(set_dim), 0);
+}
+
+__isl_give isl_map *isl_map_lex_le(__isl_take isl_space *set_dim)
+{
+	return map_lex_lte(isl_space_map_from_set(set_dim), 1);
+}
+
+static __isl_give isl_map *map_lex_gte_first(__isl_take isl_space *dims,
+	unsigned n, int equal)
+{
+	struct isl_map *map;
+	int i;
+
+	if (n == 0 && equal)
+		return isl_map_universe(dims);
+
+	map = isl_map_alloc_space(isl_space_copy(dims), n, ISL_MAP_DISJOINT);
+
+	for (i = 0; i + 1 < n; ++i)
+		map = isl_map_add_basic_map(map,
+				  isl_basic_map_more_at(isl_space_copy(dims), i));
+	if (n > 0) {
+		if (equal)
+			map = isl_map_add_basic_map(map,
+			      isl_basic_map_more_or_equal_at(dims, n - 1));
+		else
+			map = isl_map_add_basic_map(map,
+			      isl_basic_map_more_at(dims, n - 1));
+	} else
+		isl_space_free(dims);
+
+	return map;
+}
+
+static __isl_give isl_map *map_lex_gte(__isl_take isl_space *dims, int equal)
+{
+	if (!dims)
+		return NULL;
+	return map_lex_gte_first(dims, dims->n_out, equal);
+}
+
+__isl_give isl_map *isl_map_lex_gt_first(__isl_take isl_space *dim, unsigned n)
+{
+	return map_lex_gte_first(dim, n, 0);
+}
+
+__isl_give isl_map *isl_map_lex_ge_first(__isl_take isl_space *dim, unsigned n)
+{
+	return map_lex_gte_first(dim, n, 1);
+}
+
+__isl_give isl_map *isl_map_lex_gt(__isl_take isl_space *set_dim)
+{
+	return map_lex_gte(isl_space_map_from_set(set_dim), 0);
+}
+
+__isl_give isl_map *isl_map_lex_ge(__isl_take isl_space *set_dim)
+{
+	return map_lex_gte(isl_space_map_from_set(set_dim), 1);
+}
+
+__isl_give isl_map *isl_set_lex_le_set(__isl_take isl_set *set1,
+	__isl_take isl_set *set2)
+{
+	isl_map *map;
+	map = isl_map_lex_le(isl_set_get_space(set1));
+	map = isl_map_intersect_domain(map, set1);
+	map = isl_map_intersect_range(map, set2);
+	return map;
+}
+
+__isl_give isl_map *isl_set_lex_lt_set(__isl_take isl_set *set1,
+	__isl_take isl_set *set2)
+{
+	isl_map *map;
+	map = isl_map_lex_lt(isl_set_get_space(set1));
+	map = isl_map_intersect_domain(map, set1);
+	map = isl_map_intersect_range(map, set2);
+	return map;
+}
+
+__isl_give isl_map *isl_set_lex_ge_set(__isl_take isl_set *set1,
+	__isl_take isl_set *set2)
+{
+	isl_map *map;
+	map = isl_map_lex_ge(isl_set_get_space(set1));
+	map = isl_map_intersect_domain(map, set1);
+	map = isl_map_intersect_range(map, set2);
+	return map;
+}
+
+__isl_give isl_map *isl_set_lex_gt_set(__isl_take isl_set *set1,
+	__isl_take isl_set *set2)
+{
+	isl_map *map;
+	map = isl_map_lex_gt(isl_set_get_space(set1));
+	map = isl_map_intersect_domain(map, set1);
+	map = isl_map_intersect_range(map, set2);
+	return map;
+}
+
+__isl_give isl_map *isl_map_lex_le_map(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *map;
+	map = isl_map_lex_le(isl_space_range(isl_map_get_space(map1)));
+	map = isl_map_apply_domain(map, isl_map_reverse(map1));
+	map = isl_map_apply_range(map, isl_map_reverse(map2));
+	return map;
+}
+
+__isl_give isl_map *isl_map_lex_lt_map(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *map;
+	map = isl_map_lex_lt(isl_space_range(isl_map_get_space(map1)));
+	map = isl_map_apply_domain(map, isl_map_reverse(map1));
+	map = isl_map_apply_range(map, isl_map_reverse(map2));
+	return map;
+}
+
+__isl_give isl_map *isl_map_lex_ge_map(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *map;
+	map = isl_map_lex_ge(isl_space_range(isl_map_get_space(map1)));
+	map = isl_map_apply_domain(map, isl_map_reverse(map1));
+	map = isl_map_apply_range(map, isl_map_reverse(map2));
+	return map;
+}
+
+__isl_give isl_map *isl_map_lex_gt_map(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *map;
+	map = isl_map_lex_gt(isl_space_range(isl_map_get_space(map1)));
+	map = isl_map_apply_domain(map, isl_map_reverse(map1));
+	map = isl_map_apply_range(map, isl_map_reverse(map2));
+	return map;
+}
+
+/* For a div d = floor(f/m), add the constraint
+ *
+ *		f - m d >= 0
+ */
+static isl_stat add_upper_div_constraint(__isl_keep isl_basic_map *bmap,
+	unsigned pos, isl_int *div)
+{
+	int i;
+	unsigned total = isl_basic_map_total_dim(bmap);
+
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		return isl_stat_error;
+	isl_seq_cpy(bmap->ineq[i], div + 1, 1 + total);
+	isl_int_neg(bmap->ineq[i][1 + pos], div[0]);
+
+	return isl_stat_ok;
+}
+
+/* For a div d = floor(f/m), add the constraint
+ *
+ *		-(f-(m-1)) + m d >= 0
+ */
+static isl_stat add_lower_div_constraint(__isl_keep isl_basic_map *bmap,
+	unsigned pos, isl_int *div)
+{
+	int i;
+	unsigned total = isl_basic_map_total_dim(bmap);
+
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		return isl_stat_error;
+	isl_seq_neg(bmap->ineq[i], div + 1, 1 + total);
+	isl_int_set(bmap->ineq[i][1 + pos], div[0]);
+	isl_int_add(bmap->ineq[i][0], bmap->ineq[i][0], bmap->ineq[i][1 + pos]);
+	isl_int_sub_ui(bmap->ineq[i][0], bmap->ineq[i][0], 1);
+
+	return isl_stat_ok;
+}
+
+/* For a div d = floor(f/m), add the constraints
+ *
+ *		f - m d >= 0
+ *		-(f-(m-1)) + m d >= 0
+ *
+ * Note that the second constraint is the negation of
+ *
+ *		f - m d >= m
+ */
+int isl_basic_map_add_div_constraints_var(__isl_keep isl_basic_map *bmap,
+	unsigned pos, isl_int *div)
+{
+	if (add_upper_div_constraint(bmap, pos, div) < 0)
+		return -1;
+	if (add_lower_div_constraint(bmap, pos, div) < 0)
+		return -1;
+	return 0;
+}
+
+int isl_basic_set_add_div_constraints_var(__isl_keep isl_basic_set *bset,
+	unsigned pos, isl_int *div)
+{
+	return isl_basic_map_add_div_constraints_var(bset_to_bmap(bset),
+							pos, div);
+}
+
+int isl_basic_map_add_div_constraints(struct isl_basic_map *bmap, unsigned div)
+{
+	unsigned total = isl_basic_map_total_dim(bmap);
+	unsigned div_pos = total - bmap->n_div + div;
+
+	return isl_basic_map_add_div_constraints_var(bmap, div_pos,
+							bmap->div[div]);
+}
+
+/* For each known div d = floor(f/m), add the constraints
+ *
+ *		f - m d >= 0
+ *		-(f-(m-1)) + m d >= 0
+ *
+ * Remove duplicate constraints in case of some these div constraints
+ * already appear in "bmap".
+ */
+__isl_give isl_basic_map *isl_basic_map_add_known_div_constraints(
+	__isl_take isl_basic_map *bmap)
+{
+	unsigned n_div;
+
+	if (!bmap)
+		return NULL;
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	if (n_div == 0)
+		return bmap;
+
+	bmap = add_known_div_constraints(bmap);
+	bmap = isl_basic_map_remove_duplicate_constraints(bmap, NULL, 0);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+}
+
+/* Add the div constraint of sign "sign" for div "div" of "bmap".
+ *
+ * In particular, if this div is of the form d = floor(f/m),
+ * then add the constraint
+ *
+ *		f - m d >= 0
+ *
+ * if sign < 0 or the constraint
+ *
+ *		-(f-(m-1)) + m d >= 0
+ *
+ * if sign > 0.
+ */
+int isl_basic_map_add_div_constraint(__isl_keep isl_basic_map *bmap,
+	unsigned div, int sign)
+{
+	unsigned total;
+	unsigned div_pos;
+
+	if (!bmap)
+		return -1;
+
+	total = isl_basic_map_total_dim(bmap);
+	div_pos = total - bmap->n_div + div;
+
+	if (sign < 0)
+		return add_upper_div_constraint(bmap, div_pos, bmap->div[div]);
+	else
+		return add_lower_div_constraint(bmap, div_pos, bmap->div[div]);
+}
+
+__isl_give isl_basic_set *isl_basic_map_underlying_set(
+	__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		goto error;
+	if (bmap->dim->nparam == 0 && bmap->dim->n_in == 0 &&
+	    bmap->n_div == 0 &&
+	    !isl_space_is_named_or_nested(bmap->dim, isl_dim_in) &&
+	    !isl_space_is_named_or_nested(bmap->dim, isl_dim_out))
+		return bset_from_bmap(bmap);
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		goto error;
+	bmap->dim = isl_space_underlying(bmap->dim, bmap->n_div);
+	if (!bmap->dim)
+		goto error;
+	bmap->extra -= bmap->n_div;
+	bmap->n_div = 0;
+	bmap = isl_basic_map_finalize(bmap);
+	return bset_from_bmap(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_underlying_set(
+		__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_underlying_set(bset_to_bmap(bset));
+}
+
+/* Replace each element in "list" by the result of applying
+ * isl_basic_map_underlying_set to the element.
+ */
+__isl_give isl_basic_set_list *isl_basic_map_list_underlying_set(
+	__isl_take isl_basic_map_list *list)
+{
+	int i, n;
+
+	if (!list)
+		return NULL;
+
+	n = isl_basic_map_list_n_basic_map(list);
+	for (i = 0; i < n; ++i) {
+		isl_basic_map *bmap;
+		isl_basic_set *bset;
+
+		bmap = isl_basic_map_list_get_basic_map(list, i);
+		bset = isl_basic_set_underlying_set(bmap);
+		list = isl_basic_set_list_set_basic_set(list, i, bset);
+	}
+
+	return list;
+}
+
+__isl_give isl_basic_map *isl_basic_map_overlying_set(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_map *like)
+{
+	struct isl_basic_map *bmap;
+	struct isl_ctx *ctx;
+	unsigned total;
+	int i;
+
+	if (!bset || !like)
+		goto error;
+	ctx = bset->ctx;
+	isl_assert(ctx, bset->n_div == 0, goto error);
+	isl_assert(ctx, isl_basic_set_n_param(bset) == 0, goto error);
+	isl_assert(ctx, bset->dim->n_out == isl_basic_map_total_dim(like),
+			goto error);
+	if (like->n_div == 0) {
+		isl_space *space = isl_basic_map_get_space(like);
+		isl_basic_map_free(like);
+		return isl_basic_map_reset_space(bset, space);
+	}
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		goto error;
+	total = bset->dim->n_out + bset->extra;
+	bmap = bset_to_bmap(bset);
+	isl_space_free(bmap->dim);
+	bmap->dim = isl_space_copy(like->dim);
+	if (!bmap->dim)
+		goto error;
+	bmap->n_div = like->n_div;
+	bmap->extra += like->n_div;
+	if (bmap->extra) {
+		unsigned ltotal;
+		isl_int **div;
+		ltotal = total - bmap->extra + like->extra;
+		if (ltotal > total)
+			ltotal = total;
+		bmap->block2 = isl_blk_extend(ctx, bmap->block2,
+					bmap->extra * (1 + 1 + total));
+		if (isl_blk_is_error(bmap->block2))
+			goto error;
+		div = isl_realloc_array(ctx, bmap->div, isl_int *, bmap->extra);
+		if (!div)
+			goto error;
+		bmap->div = div;
+		for (i = 0; i < bmap->extra; ++i)
+			bmap->div[i] = bmap->block2.data + i * (1 + 1 + total);
+		for (i = 0; i < like->n_div; ++i) {
+			isl_seq_cpy(bmap->div[i], like->div[i], 1 + 1 + ltotal);
+			isl_seq_clr(bmap->div[i]+1+1+ltotal, total - ltotal);
+		}
+		bmap = isl_basic_map_add_known_div_constraints(bmap);
+	}
+	isl_basic_map_free(like);
+	bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_basic_map_free(like);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_from_underlying_set(
+	struct isl_basic_set *bset, struct isl_basic_set *like)
+{
+	return bset_from_bmap(isl_basic_map_overlying_set(bset,
+							bset_to_bmap(like)));
+}
+
+__isl_give isl_set *isl_map_underlying_set(__isl_take isl_map *map)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+	map->dim = isl_space_cow(map->dim);
+	if (!map->dim)
+		goto error;
+
+	for (i = 1; i < map->n; ++i)
+		isl_assert(map->ctx, map->p[0]->n_div == map->p[i]->n_div,
+				goto error);
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = bset_to_bmap(
+				isl_basic_map_underlying_set(map->p[i]));
+		if (!map->p[i])
+			goto error;
+	}
+	if (map->n == 0)
+		map->dim = isl_space_underlying(map->dim, 0);
+	else {
+		isl_space_free(map->dim);
+		map->dim = isl_space_copy(map->p[0]->dim);
+	}
+	if (!map->dim)
+		goto error;
+	return set_from_map(map);
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Replace the space of "bmap" by "space".
+ *
+ * If the space of "bmap" is identical to "space" (including the identifiers
+ * of the input and output dimensions), then simply return the original input.
+ */
+__isl_give isl_basic_map *isl_basic_map_reset_space(
+	__isl_take isl_basic_map *bmap, __isl_take isl_space *space)
+{
+	isl_bool equal;
+	isl_space *bmap_space;
+
+	bmap_space = isl_basic_map_peek_space(bmap);
+	equal = isl_space_is_equal(bmap_space, space);
+	if (equal >= 0 && equal)
+		equal = isl_space_has_equal_ids(bmap_space, space);
+	if (equal < 0)
+		goto error;
+	if (equal) {
+		isl_space_free(space);
+		return bmap;
+	}
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap || !space)
+		goto error;
+
+	isl_space_free(bmap->dim);
+	bmap->dim = space;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_space_free(space);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_reset_space(
+	__isl_take isl_basic_set *bset, __isl_take isl_space *dim)
+{
+	return bset_from_bmap(isl_basic_map_reset_space(bset_to_bmap(bset),
+							dim));
+}
+
+__isl_give isl_map *isl_map_reset_space(__isl_take isl_map *map,
+	__isl_take isl_space *dim)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map || !dim)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_reset_space(map->p[i],
+						    isl_space_copy(dim));
+		if (!map->p[i])
+			goto error;
+	}
+	isl_space_free(map->dim);
+	map->dim = dim;
+
+	return map;
+error:
+	isl_map_free(map);
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_reset_space(__isl_take isl_set *set,
+	__isl_take isl_space *dim)
+{
+	return set_from_map(isl_map_reset_space(set_to_map(set), dim));
+}
+
+/* Compute the parameter domain of the given basic set.
+ */
+__isl_give isl_basic_set *isl_basic_set_params(__isl_take isl_basic_set *bset)
+{
+	isl_bool is_params;
+	isl_space *space;
+	unsigned n;
+
+	is_params = isl_basic_set_is_params(bset);
+	if (is_params < 0)
+		return isl_basic_set_free(bset);
+	if (is_params)
+		return bset;
+
+	n = isl_basic_set_dim(bset, isl_dim_set);
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 0, n);
+	space = isl_basic_set_get_space(bset);
+	space = isl_space_params(space);
+	bset = isl_basic_set_reset_space(bset, space);
+	return bset;
+}
+
+/* Construct a zero-dimensional basic set with the given parameter domain.
+ */
+__isl_give isl_basic_set *isl_basic_set_from_params(
+	__isl_take isl_basic_set *bset)
+{
+	isl_space *space;
+	space = isl_basic_set_get_space(bset);
+	space = isl_space_set_from_params(space);
+	bset = isl_basic_set_reset_space(bset, space);
+	return bset;
+}
+
+/* Compute the parameter domain of the given set.
+ */
+__isl_give isl_set *isl_set_params(__isl_take isl_set *set)
+{
+	isl_space *space;
+	unsigned n;
+
+	if (isl_set_is_params(set))
+		return set;
+
+	n = isl_set_dim(set, isl_dim_set);
+	set = isl_set_project_out(set, isl_dim_set, 0, n);
+	space = isl_set_get_space(set);
+	space = isl_space_params(space);
+	set = isl_set_reset_space(set, space);
+	return set;
+}
+
+/* Construct a zero-dimensional set with the given parameter domain.
+ */
+__isl_give isl_set *isl_set_from_params(__isl_take isl_set *set)
+{
+	isl_space *space;
+	space = isl_set_get_space(set);
+	space = isl_space_set_from_params(space);
+	set = isl_set_reset_space(set, space);
+	return set;
+}
+
+/* Compute the parameter domain of the given map.
+ */
+__isl_give isl_set *isl_map_params(__isl_take isl_map *map)
+{
+	isl_space *space;
+	unsigned n;
+
+	n = isl_map_dim(map, isl_dim_in);
+	map = isl_map_project_out(map, isl_dim_in, 0, n);
+	n = isl_map_dim(map, isl_dim_out);
+	map = isl_map_project_out(map, isl_dim_out, 0, n);
+	space = isl_map_get_space(map);
+	space = isl_space_params(space);
+	map = isl_map_reset_space(map, space);
+	return map;
+}
+
+struct isl_basic_set *isl_basic_map_domain(struct isl_basic_map *bmap)
+{
+	isl_space *space;
+	unsigned n_out;
+
+	if (!bmap)
+		return NULL;
+	space = isl_space_domain(isl_basic_map_get_space(bmap));
+
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	bmap = isl_basic_map_project_out(bmap, isl_dim_out, 0, n_out);
+
+	return isl_basic_map_reset_space(bmap, space);
+}
+
+isl_bool isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return isl_bool_error;
+	return isl_space_may_be_set(bmap->dim);
+}
+
+/* Is this basic map actually a set?
+ * Users should never call this function.  Outside of isl,
+ * the type should indicate whether something is a set or a map.
+ */
+isl_bool isl_basic_map_is_set(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return isl_bool_error;
+	return isl_space_is_set(bmap->dim);
+}
+
+struct isl_basic_set *isl_basic_map_range(struct isl_basic_map *bmap)
+{
+	isl_bool is_set;
+
+	is_set = isl_basic_map_is_set(bmap);
+	if (is_set < 0)
+		goto error;
+	if (is_set)
+		return bmap;
+	return isl_basic_map_domain(isl_basic_map_reverse(bmap));
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_domain_map(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+	isl_space *dim;
+	isl_basic_map *domain;
+	int nparam, n_in, n_out;
+
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+
+	dim = isl_space_from_range(isl_space_domain(isl_basic_map_get_space(bmap)));
+	domain = isl_basic_map_universe(dim);
+
+	bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
+	bmap = isl_basic_map_apply_range(bmap, domain);
+	bmap = isl_basic_map_extend_constraints(bmap, n_in, 0);
+
+	for (i = 0; i < n_in; ++i)
+		bmap = isl_basic_map_equate(bmap, isl_dim_in, i,
+						    isl_dim_out, i);
+
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	return isl_basic_map_finalize(bmap);
+}
+
+__isl_give isl_basic_map *isl_basic_map_range_map(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+	isl_space *dim;
+	isl_basic_map *range;
+	int nparam, n_in, n_out;
+
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+
+	dim = isl_space_from_range(isl_space_range(isl_basic_map_get_space(bmap)));
+	range = isl_basic_map_universe(dim);
+
+	bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
+	bmap = isl_basic_map_apply_range(bmap, range);
+	bmap = isl_basic_map_extend_constraints(bmap, n_out, 0);
+
+	for (i = 0; i < n_out; ++i)
+		bmap = isl_basic_map_equate(bmap, isl_dim_in, n_in + i,
+						    isl_dim_out, i);
+
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	return isl_basic_map_finalize(bmap);
+}
+
+int isl_map_may_be_set(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+	return isl_space_may_be_set(map->dim);
+}
+
+/* Is this map actually a set?
+ * Users should never call this function.  Outside of isl,
+ * the type should indicate whether something is a set or a map.
+ */
+isl_bool isl_map_is_set(__isl_keep isl_map *map)
+{
+	if (!map)
+		return isl_bool_error;
+	return isl_space_is_set(map->dim);
+}
+
+__isl_give isl_set *isl_map_range(__isl_take isl_map *map)
+{
+	int i;
+	isl_bool is_set;
+	struct isl_set *set;
+
+	is_set = isl_map_is_set(map);
+	if (is_set < 0)
+		goto error;
+	if (is_set)
+		return set_from_map(map);
+
+	map = isl_map_cow(map);
+	if (!map)
+		goto error;
+
+	set = set_from_map(map);
+	set->dim = isl_space_range(set->dim);
+	if (!set->dim)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		set->p[i] = isl_basic_map_range(map->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+	ISL_F_CLR(set, ISL_MAP_DISJOINT);
+	ISL_F_CLR(set, ISL_SET_NORMALIZED);
+	return set;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_domain_map(__isl_take isl_map *map)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_domain_map(map->dim);
+	if (!map->dim)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_domain_map(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_DISJOINT);
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_range_map(__isl_take isl_map *map)
+{
+	int i;
+	isl_space *range_dim;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	range_dim = isl_space_range(isl_map_get_space(map));
+	range_dim = isl_space_from_range(range_dim);
+	map->dim = isl_space_from_domain(isl_space_wrap(map->dim));
+	map->dim = isl_space_join(map->dim, range_dim);
+	if (!map->dim)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_range_map(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_DISJOINT);
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Given a wrapped map of the form A[B -> C],
+ * return the map A[B -> C] -> B.
+ */
+__isl_give isl_map *isl_set_wrapped_domain_map(__isl_take isl_set *set)
+{
+	isl_id *id;
+	isl_map *map;
+
+	if (!set)
+		return NULL;
+	if (!isl_set_has_tuple_id(set))
+		return isl_map_domain_map(isl_set_unwrap(set));
+
+	id = isl_set_get_tuple_id(set);
+	map = isl_map_domain_map(isl_set_unwrap(set));
+	map = isl_map_set_tuple_id(map, isl_dim_in, id);
+
+	return map;
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_domain(
+	__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_reverse(isl_basic_map_from_range(bset));
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_range(
+	__isl_take isl_basic_set *bset)
+{
+	isl_space *space;
+	space = isl_basic_set_get_space(bset);
+	space = isl_space_from_range(space);
+	bset = isl_basic_set_reset_space(bset, space);
+	return bset_to_bmap(bset);
+}
+
+/* Create a relation with the given set as range.
+ * The domain of the created relation is a zero-dimensional
+ * flat anonymous space.
+ */
+__isl_give isl_map *isl_map_from_range(__isl_take isl_set *set)
+{
+	isl_space *space;
+	space = isl_set_get_space(set);
+	space = isl_space_from_range(space);
+	set = isl_set_reset_space(set, space);
+	return set_to_map(set);
+}
+
+/* Create a relation with the given set as domain.
+ * The range of the created relation is a zero-dimensional
+ * flat anonymous space.
+ */
+__isl_give isl_map *isl_map_from_domain(__isl_take isl_set *set)
+{
+	return isl_map_reverse(isl_map_from_range(set));
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_domain_and_range(
+	__isl_take isl_basic_set *domain, __isl_take isl_basic_set *range)
+{
+	return isl_basic_map_apply_range(isl_basic_map_reverse(domain), range);
+}
+
+__isl_give isl_map *isl_map_from_domain_and_range(__isl_take isl_set *domain,
+	__isl_take isl_set *range)
+{
+	return isl_map_apply_range(isl_map_reverse(domain), range);
+}
+
+/* Return a newly allocated isl_map with given space and flags and
+ * room for "n" basic maps.
+ * Make sure that all cached information is cleared.
+ */
+__isl_give isl_map *isl_map_alloc_space(__isl_take isl_space *space, int n,
+	unsigned flags)
+{
+	struct isl_map *map;
+
+	if (!space)
+		return NULL;
+	if (n < 0)
+		isl_die(space->ctx, isl_error_internal,
+			"negative number of basic maps", goto error);
+	map = isl_calloc(space->ctx, struct isl_map,
+			sizeof(struct isl_map) +
+			(n - 1) * sizeof(struct isl_basic_map *));
+	if (!map)
+		goto error;
+
+	map->ctx = space->ctx;
+	isl_ctx_ref(map->ctx);
+	map->ref = 1;
+	map->size = n;
+	map->n = 0;
+	map->dim = space;
+	map->flags = flags;
+	return map;
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_empty(__isl_take isl_space *dim)
+{
+	struct isl_basic_map *bmap;
+	bmap = isl_basic_map_alloc_space(dim, 0, 1, 0);
+	bmap = isl_basic_map_set_to_empty(bmap);
+	return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_empty(__isl_take isl_space *dim)
+{
+	struct isl_basic_set *bset;
+	bset = isl_basic_set_alloc_space(dim, 0, 1, 0);
+	bset = isl_basic_set_set_to_empty(bset);
+	return bset;
+}
+
+__isl_give isl_basic_map *isl_basic_map_universe(__isl_take isl_space *dim)
+{
+	struct isl_basic_map *bmap;
+	bmap = isl_basic_map_alloc_space(dim, 0, 0, 0);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_universe(__isl_take isl_space *dim)
+{
+	struct isl_basic_set *bset;
+	bset = isl_basic_set_alloc_space(dim, 0, 0, 0);
+	bset = isl_basic_set_finalize(bset);
+	return bset;
+}
+
+__isl_give isl_basic_map *isl_basic_map_nat_universe(__isl_take isl_space *dim)
+{
+	int i;
+	unsigned total = isl_space_dim(dim, isl_dim_all);
+	isl_basic_map *bmap;
+
+	bmap= isl_basic_map_alloc_space(dim, 0, 0, total);
+	for (i = 0; i < total; ++i) {
+		int k = isl_basic_map_alloc_inequality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bmap->ineq[k], 1 + total);
+		isl_int_set_si(bmap->ineq[k][1 + i], 1);
+	}
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_nat_universe(__isl_take isl_space *dim)
+{
+	return isl_basic_map_nat_universe(dim);
+}
+
+__isl_give isl_map *isl_map_nat_universe(__isl_take isl_space *dim)
+{
+	return isl_map_from_basic_map(isl_basic_map_nat_universe(dim));
+}
+
+__isl_give isl_set *isl_set_nat_universe(__isl_take isl_space *dim)
+{
+	return isl_map_nat_universe(dim);
+}
+
+__isl_give isl_map *isl_map_empty(__isl_take isl_space *dim)
+{
+	return isl_map_alloc_space(dim, 0, ISL_MAP_DISJOINT);
+}
+
+__isl_give isl_set *isl_set_empty(__isl_take isl_space *dim)
+{
+	return isl_set_alloc_space(dim, 0, ISL_MAP_DISJOINT);
+}
+
+__isl_give isl_map *isl_map_universe(__isl_take isl_space *dim)
+{
+	struct isl_map *map;
+	if (!dim)
+		return NULL;
+	map = isl_map_alloc_space(isl_space_copy(dim), 1, ISL_MAP_DISJOINT);
+	map = isl_map_add_basic_map(map, isl_basic_map_universe(dim));
+	return map;
+}
+
+__isl_give isl_set *isl_set_universe(__isl_take isl_space *dim)
+{
+	struct isl_set *set;
+	if (!dim)
+		return NULL;
+	set = isl_set_alloc_space(isl_space_copy(dim), 1, ISL_MAP_DISJOINT);
+	set = isl_set_add_basic_set(set, isl_basic_set_universe(dim));
+	return set;
+}
+
+struct isl_map *isl_map_dup(struct isl_map *map)
+{
+	int i;
+	struct isl_map *dup;
+
+	if (!map)
+		return NULL;
+	dup = isl_map_alloc_space(isl_space_copy(map->dim), map->n, map->flags);
+	for (i = 0; i < map->n; ++i)
+		dup = isl_map_add_basic_map(dup, isl_basic_map_copy(map->p[i]));
+	return dup;
+}
+
+__isl_give isl_map *isl_map_add_basic_map(__isl_take isl_map *map,
+						__isl_take isl_basic_map *bmap)
+{
+	if (!bmap || !map)
+		goto error;
+	if (isl_basic_map_plain_is_empty(bmap)) {
+		isl_basic_map_free(bmap);
+		return map;
+	}
+	isl_assert(map->ctx, isl_space_is_equal(map->dim, bmap->dim), goto error);
+	isl_assert(map->ctx, map->n < map->size, goto error);
+	map->p[map->n] = bmap;
+	map->n++;
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	if (map)
+		isl_map_free(map);
+	if (bmap)
+		isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_null isl_map *isl_map_free(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (--map->ref > 0)
+		return NULL;
+
+	clear_caches(map);
+	isl_ctx_deref(map->ctx);
+	for (i = 0; i < map->n; ++i)
+		isl_basic_map_free(map->p[i]);
+	isl_space_free(map->dim);
+	free(map);
+
+	return NULL;
+}
+
+static struct isl_basic_map *isl_basic_map_fix_pos_si(
+	struct isl_basic_map *bmap, unsigned pos, int value)
+{
+	int j;
+
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
+	j = isl_basic_map_alloc_equality(bmap);
+	if (j < 0)
+		goto error;
+	isl_seq_clr(bmap->eq[j] + 1, isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->eq[j][pos], -1);
+	isl_int_set_si(bmap->eq[j][0], value);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+static __isl_give isl_basic_map *isl_basic_map_fix_pos(
+	__isl_take isl_basic_map *bmap, unsigned pos, isl_int value)
+{
+	int j;
+
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
+	j = isl_basic_map_alloc_equality(bmap);
+	if (j < 0)
+		goto error;
+	isl_seq_clr(bmap->eq[j] + 1, isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->eq[j][pos], -1);
+	isl_int_set(bmap->eq[j][0], value);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_fix_si(__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos, int value)
+{
+	if (isl_basic_map_check_range(bmap, type, pos, 1) < 0)
+		return isl_basic_map_free(bmap);
+	return isl_basic_map_fix_pos_si(bmap,
+		isl_basic_map_offset(bmap, type) + pos, value);
+}
+
+__isl_give isl_basic_map *isl_basic_map_fix(__isl_take isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	if (isl_basic_map_check_range(bmap, type, pos, 1) < 0)
+		return isl_basic_map_free(bmap);
+	return isl_basic_map_fix_pos(bmap,
+		isl_basic_map_offset(bmap, type) + pos, value);
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "bmap"
+ * to be equal to "v".
+ */
+__isl_give isl_basic_map *isl_basic_map_fix_val(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+	if (!bmap || !v)
+		goto error;
+	if (!isl_val_is_int(v))
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"expecting integer value", goto error);
+	if (isl_basic_map_check_range(bmap, type, pos, 1) < 0)
+		goto error;
+	pos += isl_basic_map_offset(bmap, type);
+	bmap = isl_basic_map_fix_pos(bmap, pos, v->n);
+	isl_val_free(v);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_val_free(v);
+	return NULL;
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "bset"
+ * to be equal to "v".
+ */
+__isl_give isl_basic_set *isl_basic_set_fix_val(__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+	return isl_basic_map_fix_val(bset, type, pos, v);
+}
+
+struct isl_basic_set *isl_basic_set_fix_si(struct isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos, int value)
+{
+	return bset_from_bmap(isl_basic_map_fix_si(bset_to_bmap(bset),
+						    type, pos, value));
+}
+
+__isl_give isl_basic_set *isl_basic_set_fix(__isl_take isl_basic_set *bset,
+		enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	return bset_from_bmap(isl_basic_map_fix(bset_to_bmap(bset),
+						    type, pos, value));
+}
+
+struct isl_basic_map *isl_basic_map_fix_input_si(struct isl_basic_map *bmap,
+		unsigned input, int value)
+{
+	return isl_basic_map_fix_si(bmap, isl_dim_in, input, value);
+}
+
+struct isl_basic_set *isl_basic_set_fix_dim_si(struct isl_basic_set *bset,
+		unsigned dim, int value)
+{
+	return bset_from_bmap(isl_basic_map_fix_si(bset_to_bmap(bset),
+					isl_dim_set, dim, value));
+}
+
+static int remove_if_empty(__isl_keep isl_map *map, int i)
+{
+	int empty = isl_basic_map_plain_is_empty(map->p[i]);
+
+	if (empty < 0)
+		return -1;
+	if (!empty)
+		return 0;
+
+	isl_basic_map_free(map->p[i]);
+	if (i != map->n - 1) {
+		ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+		map->p[i] = map->p[map->n - 1];
+	}
+	map->n--;
+
+	return 0;
+}
+
+/* Perform "fn" on each basic map of "map", where we may not be holding
+ * the only reference to "map".
+ * In particular, "fn" should be a semantics preserving operation
+ * that we want to apply to all copies of "map".  We therefore need
+ * to be careful not to modify "map" in a way that breaks "map"
+ * in case anything goes wrong.
+ */
+__isl_give isl_map *isl_map_inline_foreach_basic_map(__isl_take isl_map *map,
+	__isl_give isl_basic_map *(*fn)(__isl_take isl_basic_map *bmap))
+{
+	struct isl_basic_map *bmap;
+	int i;
+
+	if (!map)
+		return NULL;
+
+	for (i = map->n - 1; i >= 0; --i) {
+		bmap = isl_basic_map_copy(map->p[i]);
+		bmap = fn(bmap);
+		if (!bmap)
+			goto error;
+		isl_basic_map_free(map->p[i]);
+		map->p[i] = bmap;
+		if (remove_if_empty(map, i) < 0)
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_fix_si(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, int value)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error);
+	for (i = map->n - 1; i >= 0; --i) {
+		map->p[i] = isl_basic_map_fix_si(map->p[i], type, pos, value);
+		if (remove_if_empty(map, i) < 0)
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_fix_si(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, int value)
+{
+	return set_from_map(isl_map_fix_si(set_to_map(set), type, pos, value));
+}
+
+__isl_give isl_map *isl_map_fix(__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error);
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_fix(map->p[i], type, pos, value);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_fix(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	return set_from_map(isl_map_fix(set_to_map(set), type, pos, value));
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "map"
+ * to be equal to "v".
+ */
+__isl_give isl_map *isl_map_fix_val(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map || !v)
+		goto error;
+
+	if (!isl_val_is_int(v))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"expecting integer value", goto error);
+	if (pos >= isl_map_dim(map, type))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"index out of bounds", goto error);
+	for (i = map->n - 1; i >= 0; --i) {
+		map->p[i] = isl_basic_map_fix_val(map->p[i], type, pos,
+							isl_val_copy(v));
+		if (remove_if_empty(map, i) < 0)
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	isl_val_free(v);
+	return map;
+error:
+	isl_map_free(map);
+	isl_val_free(v);
+	return NULL;
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "set"
+ * to be equal to "v".
+ */
+__isl_give isl_set *isl_set_fix_val(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+	return isl_map_fix_val(set, type, pos, v);
+}
+
+struct isl_map *isl_map_fix_input_si(struct isl_map *map,
+		unsigned input, int value)
+{
+	return isl_map_fix_si(map, isl_dim_in, input, value);
+}
+
+struct isl_set *isl_set_fix_dim_si(struct isl_set *set, unsigned dim, int value)
+{
+	return set_from_map(isl_map_fix_si(set_to_map(set),
+						isl_dim_set, dim, value));
+}
+
+static __isl_give isl_basic_map *basic_map_bound_si(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, int value, int upper)
+{
+	int j;
+
+	if (isl_basic_map_check_range(bmap, type, pos, 1) < 0)
+		return isl_basic_map_free(bmap);
+	pos += isl_basic_map_offset(bmap, type);
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+	j = isl_basic_map_alloc_inequality(bmap);
+	if (j < 0)
+		goto error;
+	isl_seq_clr(bmap->ineq[j], 1 + isl_basic_map_total_dim(bmap));
+	if (upper) {
+		isl_int_set_si(bmap->ineq[j][pos], -1);
+		isl_int_set_si(bmap->ineq[j][0], value);
+	} else {
+		isl_int_set_si(bmap->ineq[j][pos], 1);
+		isl_int_set_si(bmap->ineq[j][0], -value);
+	}
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_lower_bound_si(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, int value)
+{
+	return basic_map_bound_si(bmap, type, pos, value, 0);
+}
+
+/* Constrain the values of the given dimension to be no greater than "value".
+ */
+__isl_give isl_basic_map *isl_basic_map_upper_bound_si(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, int value)
+{
+	return basic_map_bound_si(bmap, type, pos, value, 1);
+}
+
+static __isl_give isl_map *map_bound_si(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, int value, int upper)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	isl_assert(map->ctx, pos < isl_map_dim(map, type), goto error);
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = basic_map_bound_si(map->p[i],
+						 type, pos, value, upper);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_lower_bound_si(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, int value)
+{
+	return map_bound_si(map, type, pos, value, 0);
+}
+
+__isl_give isl_map *isl_map_upper_bound_si(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, int value)
+{
+	return map_bound_si(map, type, pos, value, 1);
+}
+
+__isl_give isl_set *isl_set_lower_bound_si(__isl_take isl_set *set,
+		enum isl_dim_type type, unsigned pos, int value)
+{
+	return set_from_map(isl_map_lower_bound_si(set_to_map(set),
+							type, pos, value));
+}
+
+__isl_give isl_set *isl_set_upper_bound_si(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, int value)
+{
+	return isl_map_upper_bound_si(set, type, pos, value);
+}
+
+/* Bound the given variable of "bmap" from below (or above is "upper"
+ * is set) to "value".
+ */
+static __isl_give isl_basic_map *basic_map_bound(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, isl_int value, int upper)
+{
+	int j;
+
+	if (isl_basic_map_check_range(bmap, type, pos, 1) < 0)
+		return isl_basic_map_free(bmap);
+	pos += isl_basic_map_offset(bmap, type);
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+	j = isl_basic_map_alloc_inequality(bmap);
+	if (j < 0)
+		goto error;
+	isl_seq_clr(bmap->ineq[j], 1 + isl_basic_map_total_dim(bmap));
+	if (upper) {
+		isl_int_set_si(bmap->ineq[j][pos], -1);
+		isl_int_set(bmap->ineq[j][0], value);
+	} else {
+		isl_int_set_si(bmap->ineq[j][pos], 1);
+		isl_int_neg(bmap->ineq[j][0], value);
+	}
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Bound the given variable of "map" from below (or above is "upper"
+ * is set) to "value".
+ */
+static __isl_give isl_map *map_bound(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int value, int upper)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	if (pos >= isl_map_dim(map, type))
+		isl_die(map->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+	for (i = map->n - 1; i >= 0; --i) {
+		map->p[i] = basic_map_bound(map->p[i], type, pos, value, upper);
+		if (remove_if_empty(map, i) < 0)
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_lower_bound(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	return map_bound(map, type, pos, value, 0);
+}
+
+__isl_give isl_map *isl_map_upper_bound(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	return map_bound(map, type, pos, value, 1);
+}
+
+__isl_give isl_set *isl_set_lower_bound(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	return isl_map_lower_bound(set, type, pos, value);
+}
+
+__isl_give isl_set *isl_set_upper_bound(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, isl_int value)
+{
+	return isl_map_upper_bound(set, type, pos, value);
+}
+
+/* Force the values of the variable at position "pos" of type "type" of "set"
+ * to be no smaller than "value".
+ */
+__isl_give isl_set *isl_set_lower_bound_val(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *value)
+{
+	if (!value)
+		goto error;
+	if (!isl_val_is_int(value))
+		isl_die(isl_set_get_ctx(set), isl_error_invalid,
+			"expecting integer value", goto error);
+	set = isl_set_lower_bound(set, type, pos, value->n);
+	isl_val_free(value);
+	return set;
+error:
+	isl_val_free(value);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Force the values of the variable at position "pos" of type "type" of "set"
+ * to be no greater than "value".
+ */
+__isl_give isl_set *isl_set_upper_bound_val(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *value)
+{
+	if (!value)
+		goto error;
+	if (!isl_val_is_int(value))
+		isl_die(isl_set_get_ctx(set), isl_error_invalid,
+			"expecting integer value", goto error);
+	set = isl_set_upper_bound(set, type, pos, value->n);
+	isl_val_free(value);
+	return set;
+error:
+	isl_val_free(value);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Bound the given variable of "bset" from below (or above is "upper"
+ * is set) to "value".
+ */
+static __isl_give isl_basic_set *isl_basic_set_bound(
+	__isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos,
+	isl_int value, int upper)
+{
+	return bset_from_bmap(basic_map_bound(bset_to_bmap(bset),
+						type, pos, value, upper));
+}
+
+/* Bound the given variable of "bset" from below (or above is "upper"
+ * is set) to "value".
+ */
+static __isl_give isl_basic_set *isl_basic_set_bound_val(
+	__isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos,
+	__isl_take isl_val *value, int upper)
+{
+	if (!value)
+		goto error;
+	if (!isl_val_is_int(value))
+		isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid,
+			"expecting integer value", goto error);
+	bset = isl_basic_set_bound(bset, type, pos, value->n, upper);
+	isl_val_free(value);
+	return bset;
+error:
+	isl_val_free(value);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Bound the given variable of "bset" from below to "value".
+ */
+__isl_give isl_basic_set *isl_basic_set_lower_bound_val(
+	__isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos,
+	__isl_take isl_val *value)
+{
+	return isl_basic_set_bound_val(bset, type, pos, value, 0);
+}
+
+/* Bound the given variable of "bset" from above to "value".
+ */
+__isl_give isl_basic_set *isl_basic_set_upper_bound_val(
+	__isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned pos,
+	__isl_take isl_val *value)
+{
+	return isl_basic_set_bound_val(bset, type, pos, value, 1);
+}
+
+__isl_give isl_map *isl_map_reverse(__isl_take isl_map *map)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	map->dim = isl_space_reverse(map->dim);
+	if (!map->dim)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_reverse(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+#undef TYPE
+#define TYPE	isl_pw_multi_aff
+#undef SUFFIX
+#define SUFFIX	_pw_multi_aff
+#undef EMPTY
+#define EMPTY	isl_pw_multi_aff_empty
+#undef ADD
+#define ADD	isl_pw_multi_aff_union_add
+#include "isl_map_lexopt_templ.c"
+
+/* Given a map "map", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in dom,
+ * in the form of an isl_pw_multi_aff.
+ * If "empty" is not NULL, then set *empty to those elements in dom that
+ * do not have an image element.
+ * If "flags" includes ISL_OPT_FULL, then "dom" is NULL and the optimum
+ * should be computed over the domain of "map".  "empty" is also NULL
+ * in this case.
+ *
+ * We first compute the lexicographically minimal or maximal element
+ * in the first basic map.  This results in a partial solution "res"
+ * and a subset "todo" of dom that still need to be handled.
+ * We then consider each of the remaining maps in "map" and successively
+ * update both "res" and "todo".
+ * If "empty" is NULL, then the todo sets are not needed and therefore
+ * also not computed.
+ */
+static __isl_give isl_pw_multi_aff *isl_map_partial_lexopt_aligned_pw_multi_aff(
+	__isl_take isl_map *map, __isl_take isl_set *dom,
+	__isl_give isl_set **empty, unsigned flags)
+{
+	int i;
+	int full;
+	isl_pw_multi_aff *res;
+	isl_set *todo;
+
+	full = ISL_FL_ISSET(flags, ISL_OPT_FULL);
+	if (!map || (!full && !dom))
+		goto error;
+
+	if (isl_map_plain_is_empty(map)) {
+		if (empty)
+			*empty = dom;
+		else
+			isl_set_free(dom);
+		return isl_pw_multi_aff_from_map(map);
+	}
+
+	res = basic_map_partial_lexopt_pw_multi_aff(
+					    isl_basic_map_copy(map->p[0]),
+					    isl_set_copy(dom), empty, flags);
+
+	if (empty)
+		todo = *empty;
+	for (i = 1; i < map->n; ++i) {
+		isl_pw_multi_aff *res_i;
+
+		res_i = basic_map_partial_lexopt_pw_multi_aff(
+					    isl_basic_map_copy(map->p[i]),
+					    isl_set_copy(dom), empty, flags);
+
+		if (ISL_FL_ISSET(flags, ISL_OPT_MAX))
+			res = isl_pw_multi_aff_union_lexmax(res, res_i);
+		else
+			res = isl_pw_multi_aff_union_lexmin(res, res_i);
+
+		if (empty)
+			todo = isl_set_intersect(todo, *empty);
+	}
+
+	isl_set_free(dom);
+	isl_map_free(map);
+
+	if (empty)
+		*empty = todo;
+
+	return res;
+error:
+	if (empty)
+		*empty = NULL;
+	isl_set_free(dom);
+	isl_map_free(map);
+	return NULL;
+}
+
+#undef TYPE
+#define TYPE	isl_map
+#undef SUFFIX
+#define SUFFIX
+#undef EMPTY
+#define EMPTY	isl_map_empty
+#undef ADD
+#define ADD	isl_map_union_disjoint
+#include "isl_map_lexopt_templ.c"
+
+/* Given a map "map", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in "dom",
+ * in the form of an isl_map.
+ * If "empty" is not NULL, then set *empty to those elements in "dom" that
+ * do not have an image element.
+ * If "flags" includes ISL_OPT_FULL, then "dom" is NULL and the optimum
+ * should be computed over the domain of "map".  "empty" is also NULL
+ * in this case.
+ *
+ * If the input consists of more than one disjunct, then first
+ * compute the desired result in the form of an isl_pw_multi_aff and
+ * then convert that into an isl_map.
+ *
+ * This function used to have an explicit implementation in terms
+ * of isl_maps, but it would continually intersect the domains of
+ * partial results with the complement of the domain of the next
+ * partial solution, potentially leading to an explosion in the number
+ * of disjuncts if there are several disjuncts in the input.
+ * An even earlier implementation of this function would look for
+ * better results in the domain of the partial result and for extra
+ * results in the complement of this domain, which would lead to
+ * even more splintering.
+ */
+static __isl_give isl_map *isl_map_partial_lexopt_aligned(
+	__isl_take isl_map *map, __isl_take isl_set *dom,
+	__isl_give isl_set **empty, unsigned flags)
+{
+	int full;
+	struct isl_map *res;
+	isl_pw_multi_aff *pma;
+
+	full = ISL_FL_ISSET(flags, ISL_OPT_FULL);
+	if (!map || (!full && !dom))
+		goto error;
+
+	if (isl_map_plain_is_empty(map)) {
+		if (empty)
+			*empty = dom;
+		else
+			isl_set_free(dom);
+		return map;
+	}
+
+	if (map->n == 1) {
+		res = basic_map_partial_lexopt(isl_basic_map_copy(map->p[0]),
+						dom, empty, flags);
+		isl_map_free(map);
+		return res;
+	}
+
+	pma = isl_map_partial_lexopt_aligned_pw_multi_aff(map, dom, empty,
+							flags);
+	return isl_map_from_pw_multi_aff(pma);
+error:
+	if (empty)
+		*empty = NULL;
+	isl_set_free(dom);
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_partial_lexmax(
+		__isl_take isl_map *map, __isl_take isl_set *dom,
+		__isl_give isl_set **empty)
+{
+	return isl_map_partial_lexopt(map, dom, empty, ISL_OPT_MAX);
+}
+
+__isl_give isl_map *isl_map_partial_lexmin(
+		__isl_take isl_map *map, __isl_take isl_set *dom,
+		__isl_give isl_set **empty)
+{
+	return isl_map_partial_lexopt(map, dom, empty, 0);
+}
+
+__isl_give isl_set *isl_set_partial_lexmin(
+		__isl_take isl_set *set, __isl_take isl_set *dom,
+		__isl_give isl_set **empty)
+{
+	return set_from_map(isl_map_partial_lexmin(set_to_map(set),
+						    dom, empty));
+}
+
+__isl_give isl_set *isl_set_partial_lexmax(
+		__isl_take isl_set *set, __isl_take isl_set *dom,
+		__isl_give isl_set **empty)
+{
+	return set_from_map(isl_map_partial_lexmax(set_to_map(set),
+						    dom, empty));
+}
+
+/* Compute the lexicographic minimum (or maximum if "flags" includes
+ * ISL_OPT_MAX) of "bset" over its parametric domain.
+ */
+__isl_give isl_set *isl_basic_set_lexopt(__isl_take isl_basic_set *bset,
+	unsigned flags)
+{
+	return isl_basic_map_lexopt(bset, flags);
+}
+
+__isl_give isl_map *isl_basic_map_lexmax(__isl_take isl_basic_map *bmap)
+{
+	return isl_basic_map_lexopt(bmap, ISL_OPT_MAX);
+}
+
+__isl_give isl_set *isl_basic_set_lexmin(__isl_take isl_basic_set *bset)
+{
+	return set_from_map(isl_basic_map_lexmin(bset_to_bmap(bset)));
+}
+
+__isl_give isl_set *isl_basic_set_lexmax(__isl_take isl_basic_set *bset)
+{
+	return set_from_map(isl_basic_map_lexmax(bset_to_bmap(bset)));
+}
+
+/* Compute the lexicographic minimum of "bset" over its parametric domain
+ * for the purpose of quantifier elimination.
+ * That is, find an explicit representation for all the existentially
+ * quantified variables in "bset" by computing their lexicographic
+ * minimum.
+ */
+static __isl_give isl_set *isl_basic_set_lexmin_compute_divs(
+	__isl_take isl_basic_set *bset)
+{
+	return isl_basic_set_lexopt(bset, ISL_OPT_QE);
+}
+
+/* Extract the first and only affine expression from list
+ * and then add it to *pwaff with the given dom.
+ * This domain is known to be disjoint from other domains
+ * because of the way isl_basic_map_foreach_lexmax works.
+ */
+static isl_stat update_dim_opt(__isl_take isl_basic_set *dom,
+	__isl_take isl_aff_list *list, void *user)
+{
+	isl_ctx *ctx = isl_basic_set_get_ctx(dom);
+	isl_aff *aff;
+	isl_pw_aff **pwaff = user;
+	isl_pw_aff *pwaff_i;
+
+	if (!list)
+		goto error;
+	if (isl_aff_list_n_aff(list) != 1)
+		isl_die(ctx, isl_error_internal,
+			"expecting single element list", goto error);
+
+	aff = isl_aff_list_get_aff(list, 0);
+	pwaff_i = isl_pw_aff_alloc(isl_set_from_basic_set(dom), aff);
+
+	*pwaff = isl_pw_aff_add_disjoint(*pwaff, pwaff_i);
+
+	isl_aff_list_free(list);
+
+	return isl_stat_ok;
+error:
+	isl_basic_set_free(dom);
+	isl_aff_list_free(list);
+	return isl_stat_error;
+}
+
+/* Given a basic map with one output dimension, compute the minimum or
+ * maximum of that dimension as an isl_pw_aff.
+ *
+ * The isl_pw_aff is constructed by having isl_basic_map_foreach_lexopt
+ * call update_dim_opt on each leaf of the result.
+ */
+static __isl_give isl_pw_aff *basic_map_dim_opt(__isl_keep isl_basic_map *bmap,
+	int max)
+{
+	isl_space *dim = isl_basic_map_get_space(bmap);
+	isl_pw_aff *pwaff;
+	isl_stat r;
+
+	dim = isl_space_from_domain(isl_space_domain(dim));
+	dim = isl_space_add_dims(dim, isl_dim_out, 1);
+	pwaff = isl_pw_aff_empty(dim);
+
+	r = isl_basic_map_foreach_lexopt(bmap, max, &update_dim_opt, &pwaff);
+	if (r < 0)
+		return isl_pw_aff_free(pwaff);
+
+	return pwaff;
+}
+
+/* Compute the minimum or maximum of the given output dimension
+ * as a function of the parameters and the input dimensions,
+ * but independently of the other output dimensions.
+ *
+ * We first project out the other output dimension and then compute
+ * the "lexicographic" maximum in each basic map, combining the results
+ * using isl_pw_aff_union_max.
+ */
+static __isl_give isl_pw_aff *map_dim_opt(__isl_take isl_map *map, int pos,
+	int max)
+{
+	int i;
+	isl_pw_aff *pwaff;
+	unsigned n_out;
+
+	n_out = isl_map_dim(map, isl_dim_out);
+	map = isl_map_project_out(map, isl_dim_out, pos + 1, n_out - (pos + 1));
+	map = isl_map_project_out(map, isl_dim_out, 0, pos);
+	if (!map)
+		return NULL;
+
+	if (map->n == 0) {
+		isl_space *dim = isl_map_get_space(map);
+		isl_map_free(map);
+		return isl_pw_aff_empty(dim);
+	}
+
+	pwaff = basic_map_dim_opt(map->p[0], max);
+	for (i = 1; i < map->n; ++i) {
+		isl_pw_aff *pwaff_i;
+
+		pwaff_i = basic_map_dim_opt(map->p[i], max);
+		pwaff = isl_pw_aff_union_opt(pwaff, pwaff_i, max);
+	}
+
+	isl_map_free(map);
+
+	return pwaff;
+}
+
+/* Compute the minimum of the given output dimension as a function of the
+ * parameters and input dimensions, but independently of
+ * the other output dimensions.
+ */
+__isl_give isl_pw_aff *isl_map_dim_min(__isl_take isl_map *map, int pos)
+{
+	return map_dim_opt(map, pos, 0);
+}
+
+/* Compute the maximum of the given output dimension as a function of the
+ * parameters and input dimensions, but independently of
+ * the other output dimensions.
+ */
+__isl_give isl_pw_aff *isl_map_dim_max(__isl_take isl_map *map, int pos)
+{
+	return map_dim_opt(map, pos, 1);
+}
+
+/* Compute the minimum or maximum of the given set dimension
+ * as a function of the parameters,
+ * but independently of the other set dimensions.
+ */
+static __isl_give isl_pw_aff *set_dim_opt(__isl_take isl_set *set, int pos,
+	int max)
+{
+	return map_dim_opt(set, pos, max);
+}
+
+/* Compute the maximum of the given set dimension as a function of the
+ * parameters, but independently of the other set dimensions.
+ */
+__isl_give isl_pw_aff *isl_set_dim_max(__isl_take isl_set *set, int pos)
+{
+	return set_dim_opt(set, pos, 1);
+}
+
+/* Compute the minimum of the given set dimension as a function of the
+ * parameters, but independently of the other set dimensions.
+ */
+__isl_give isl_pw_aff *isl_set_dim_min(__isl_take isl_set *set, int pos)
+{
+	return set_dim_opt(set, pos, 0);
+}
+
+/* Apply a preimage specified by "mat" on the parameters of "bset".
+ * bset is assumed to have only parameters and divs.
+ */
+static __isl_give isl_basic_set *basic_set_parameter_preimage(
+	__isl_take isl_basic_set *bset, __isl_take isl_mat *mat)
+{
+	unsigned nparam;
+
+	if (!bset || !mat)
+		goto error;
+
+	bset->dim = isl_space_cow(bset->dim);
+	if (!bset->dim)
+		goto error;
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+
+	isl_assert(bset->ctx, mat->n_row == 1 + nparam, goto error);
+
+	bset->dim->nparam = 0;
+	bset->dim->n_out = nparam;
+	bset = isl_basic_set_preimage(bset, mat);
+	if (bset) {
+		bset->dim->nparam = bset->dim->n_out;
+		bset->dim->n_out = 0;
+	}
+	return bset;
+error:
+	isl_mat_free(mat);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Apply a preimage specified by "mat" on the parameters of "set".
+ * set is assumed to have only parameters and divs.
+ */
+static __isl_give isl_set *set_parameter_preimage(__isl_take isl_set *set,
+	__isl_take isl_mat *mat)
+{
+	isl_space *space;
+	unsigned nparam;
+
+	if (!set || !mat)
+		goto error;
+
+	nparam = isl_set_dim(set, isl_dim_param);
+
+	if (mat->n_row != 1 + nparam)
+		isl_die(isl_set_get_ctx(set), isl_error_internal,
+			"unexpected number of rows", goto error);
+
+	space = isl_set_get_space(set);
+	space = isl_space_move_dims(space, isl_dim_set, 0,
+				    isl_dim_param, 0, nparam);
+	set = isl_set_reset_space(set, space);
+	set = isl_set_preimage(set, mat);
+	nparam = isl_set_dim(set, isl_dim_out);
+	space = isl_set_get_space(set);
+	space = isl_space_move_dims(space, isl_dim_param, 0,
+				    isl_dim_out, 0, nparam);
+	set = isl_set_reset_space(set, space);
+	return set;
+error:
+	isl_mat_free(mat);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Intersect the basic set "bset" with the affine space specified by the
+ * equalities in "eq".
+ */
+static __isl_give isl_basic_set *basic_set_append_equalities(
+	__isl_take isl_basic_set *bset, __isl_take isl_mat *eq)
+{
+	int i, k;
+	unsigned len;
+
+	if (!bset || !eq)
+		goto error;
+
+	bset = isl_basic_set_extend_space(bset, isl_space_copy(bset->dim), 0,
+					eq->n_row, 0);
+	if (!bset)
+		goto error;
+
+	len = 1 + isl_space_dim(bset->dim, isl_dim_all) + bset->extra;
+	for (i = 0; i < eq->n_row; ++i) {
+		k = isl_basic_set_alloc_equality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bset->eq[k], eq->row[i], eq->n_col);
+		isl_seq_clr(bset->eq[k] + eq->n_col, len - eq->n_col);
+	}
+	isl_mat_free(eq);
+
+	bset = isl_basic_set_gauss(bset, NULL);
+	bset = isl_basic_set_finalize(bset);
+
+	return bset;
+error:
+	isl_mat_free(eq);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Intersect the set "set" with the affine space specified by the
+ * equalities in "eq".
+ */
+static struct isl_set *set_append_equalities(struct isl_set *set,
+	struct isl_mat *eq)
+{
+	int i;
+
+	if (!set || !eq)
+		goto error;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = basic_set_append_equalities(set->p[i],
+					isl_mat_copy(eq));
+		if (!set->p[i])
+			goto error;
+	}
+	isl_mat_free(eq);
+	return set;
+error:
+	isl_mat_free(eq);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Given a basic set "bset" that only involves parameters and existentially
+ * quantified variables, return the index of the first equality
+ * that only involves parameters.  If there is no such equality then
+ * return bset->n_eq.
+ *
+ * This function assumes that isl_basic_set_gauss has been called on "bset".
+ */
+static int first_parameter_equality(__isl_keep isl_basic_set *bset)
+{
+	int i, j;
+	unsigned nparam, n_div;
+
+	if (!bset)
+		return -1;
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	n_div = isl_basic_set_dim(bset, isl_dim_div);
+
+	for (i = 0, j = n_div - 1; i < bset->n_eq && j >= 0; --j) {
+		if (!isl_int_is_zero(bset->eq[i][1 + nparam + j]))
+			++i;
+	}
+
+	return i;
+}
+
+/* Compute an explicit representation for the existentially quantified
+ * variables in "bset" by computing the "minimal value" of the set
+ * variables.  Since there are no set variables, the computation of
+ * the minimal value essentially computes an explicit representation
+ * of the non-empty part(s) of "bset".
+ *
+ * The input only involves parameters and existentially quantified variables.
+ * All equalities among parameters have been removed.
+ *
+ * Since the existentially quantified variables in the result are in general
+ * going to be different from those in the input, we first replace
+ * them by the minimal number of variables based on their equalities.
+ * This should simplify the parametric integer programming.
+ */
+static __isl_give isl_set *base_compute_divs(__isl_take isl_basic_set *bset)
+{
+	isl_morph *morph1, *morph2;
+	isl_set *set;
+	unsigned n;
+
+	if (!bset)
+		return NULL;
+	if (bset->n_eq == 0)
+		return isl_basic_set_lexmin_compute_divs(bset);
+
+	morph1 = isl_basic_set_parameter_compression(bset);
+	bset = isl_morph_basic_set(isl_morph_copy(morph1), bset);
+	bset = isl_basic_set_lift(bset);
+	morph2 = isl_basic_set_variable_compression(bset, isl_dim_set);
+	bset = isl_morph_basic_set(morph2, bset);
+	n = isl_basic_set_dim(bset, isl_dim_set);
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 0, n);
+
+	set = isl_basic_set_lexmin_compute_divs(bset);
+
+	set = isl_morph_set(isl_morph_inverse(morph1), set);
+
+	return set;
+}
+
+/* Project the given basic set onto its parameter domain, possibly introducing
+ * new, explicit, existential variables in the constraints.
+ * The input has parameters and (possibly implicit) existential variables.
+ * The output has the same parameters, but only
+ * explicit existentially quantified variables.
+ *
+ * The actual projection is performed by pip, but pip doesn't seem
+ * to like equalities very much, so we first remove the equalities
+ * among the parameters by performing a variable compression on
+ * the parameters.  Afterward, an inverse transformation is performed
+ * and the equalities among the parameters are inserted back in.
+ *
+ * The variable compression on the parameters may uncover additional
+ * equalities that were only implicit before.  We therefore check
+ * if there are any new parameter equalities in the result and
+ * if so recurse.  The removal of parameter equalities is required
+ * for the parameter compression performed by base_compute_divs.
+ */
+static struct isl_set *parameter_compute_divs(struct isl_basic_set *bset)
+{
+	int i;
+	struct isl_mat *eq;
+	struct isl_mat *T, *T2;
+	struct isl_set *set;
+	unsigned nparam;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		return NULL;
+
+	if (bset->n_eq == 0)
+		return base_compute_divs(bset);
+
+	bset = isl_basic_set_gauss(bset, NULL);
+	if (!bset)
+		return NULL;
+	if (isl_basic_set_plain_is_empty(bset))
+		return isl_set_from_basic_set(bset);
+
+	i = first_parameter_equality(bset);
+	if (i == bset->n_eq)
+		return base_compute_divs(bset);
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	eq = isl_mat_sub_alloc6(bset->ctx, bset->eq, i, bset->n_eq - i,
+		0, 1 + nparam);
+	eq = isl_mat_cow(eq);
+	T = isl_mat_variable_compression(isl_mat_copy(eq), &T2);
+	if (T && T->n_col == 0) {
+		isl_mat_free(T);
+		isl_mat_free(T2);
+		isl_mat_free(eq);
+		bset = isl_basic_set_set_to_empty(bset);
+		return isl_set_from_basic_set(bset);
+	}
+	bset = basic_set_parameter_preimage(bset, T);
+
+	i = first_parameter_equality(bset);
+	if (!bset)
+		set = NULL;
+	else if (i == bset->n_eq)
+		set = base_compute_divs(bset);
+	else
+		set = parameter_compute_divs(bset);
+	set = set_parameter_preimage(set, T2);
+	set = set_append_equalities(set, eq);
+	return set;
+}
+
+/* Insert the divs from "ls" before those of "bmap".
+ *
+ * The number of columns is not changed, which means that the last
+ * dimensions of "bmap" are being reintepreted as the divs from "ls".
+ * The caller is responsible for removing the same number of dimensions
+ * from the space of "bmap".
+ */
+static __isl_give isl_basic_map *insert_divs_from_local_space(
+	__isl_take isl_basic_map *bmap, __isl_keep isl_local_space *ls)
+{
+	int i;
+	int n_div;
+	int old_n_div;
+
+	n_div = isl_local_space_dim(ls, isl_dim_div);
+	if (n_div == 0)
+		return bmap;
+
+	old_n_div = bmap->n_div;
+	bmap = insert_div_rows(bmap, n_div);
+	if (!bmap)
+		return NULL;
+
+	for (i = 0; i < n_div; ++i) {
+		isl_seq_cpy(bmap->div[i], ls->div->row[i], ls->div->n_col);
+		isl_seq_clr(bmap->div[i] + ls->div->n_col, old_n_div);
+	}
+
+	return bmap;
+}
+
+/* Replace the space of "bmap" by the space and divs of "ls".
+ *
+ * If "ls" has any divs, then we simplify the result since we may
+ * have discovered some additional equalities that could simplify
+ * the div expressions.
+ */
+static __isl_give isl_basic_map *basic_replace_space_by_local_space(
+	__isl_take isl_basic_map *bmap, __isl_take isl_local_space *ls)
+{
+	int n_div;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap || !ls)
+		goto error;
+
+	n_div = isl_local_space_dim(ls, isl_dim_div);
+	bmap = insert_divs_from_local_space(bmap, ls);
+	if (!bmap)
+		goto error;
+
+	isl_space_free(bmap->dim);
+	bmap->dim = isl_local_space_get_space(ls);
+	if (!bmap->dim)
+		goto error;
+
+	isl_local_space_free(ls);
+	if (n_div > 0)
+		bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_local_space_free(ls);
+	return NULL;
+}
+
+/* Replace the space of "map" by the space and divs of "ls".
+ */
+static __isl_give isl_map *replace_space_by_local_space(__isl_take isl_map *map,
+	__isl_take isl_local_space *ls)
+{
+	int i;
+
+	map = isl_map_cow(map);
+	if (!map || !ls)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = basic_replace_space_by_local_space(map->p[i],
+						    isl_local_space_copy(ls));
+		if (!map->p[i])
+			goto error;
+	}
+	isl_space_free(map->dim);
+	map->dim = isl_local_space_get_space(ls);
+	if (!map->dim)
+		goto error;
+
+	isl_local_space_free(ls);
+	return map;
+error:
+	isl_local_space_free(ls);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Compute an explicit representation for the existentially
+ * quantified variables for which do not know any explicit representation yet.
+ *
+ * We first sort the existentially quantified variables so that the
+ * existentially quantified variables for which we already have an explicit
+ * representation are placed before those for which we do not.
+ * The input dimensions, the output dimensions and the existentially
+ * quantified variables for which we already have an explicit
+ * representation are then turned into parameters.
+ * compute_divs returns a map with the same parameters and
+ * no input or output dimensions and the dimension specification
+ * is reset to that of the input, including the existentially quantified
+ * variables for which we already had an explicit representation.
+ */
+static struct isl_map *compute_divs(struct isl_basic_map *bmap)
+{
+	struct isl_basic_set *bset;
+	struct isl_set *set;
+	struct isl_map *map;
+	isl_space *dim;
+	isl_local_space *ls;
+	unsigned	 nparam;
+	unsigned	 n_in;
+	unsigned	 n_out;
+	int n_known;
+	int i;
+
+	bmap = isl_basic_map_sort_divs(bmap);
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	n_known = isl_basic_map_first_unknown_div(bmap);
+	if (n_known < 0)
+		return isl_map_from_basic_map(isl_basic_map_free(bmap));
+
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	dim = isl_space_set_alloc(bmap->ctx,
+				    nparam + n_in + n_out + n_known, 0);
+	if (!dim)
+		goto error;
+
+	ls = isl_basic_map_get_local_space(bmap);
+	ls = isl_local_space_drop_dims(ls, isl_dim_div,
+					n_known, bmap->n_div - n_known);
+	if (n_known > 0) {
+		for (i = n_known; i < bmap->n_div; ++i)
+			swap_div(bmap, i - n_known, i);
+		bmap->n_div -= n_known;
+		bmap->extra -= n_known;
+	}
+	bmap = isl_basic_map_reset_space(bmap, dim);
+	bset = bset_from_bmap(bmap);
+
+	set = parameter_compute_divs(bset);
+	map = set_to_map(set);
+	map = replace_space_by_local_space(map, ls);
+
+	return map;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Remove the explicit representation of local variable "div",
+ * if there is any.
+ */
+__isl_give isl_basic_map *isl_basic_map_mark_div_unknown(
+	__isl_take isl_basic_map *bmap, int div)
+{
+	isl_bool unknown;
+
+	unknown = isl_basic_map_div_is_marked_unknown(bmap, div);
+	if (unknown < 0)
+		return isl_basic_map_free(bmap);
+	if (unknown)
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	isl_int_set_si(bmap->div[div][0], 0);
+	return bmap;
+}
+
+/* Is local variable "div" of "bmap" marked as not having an explicit
+ * representation?
+ * Note that even if "div" is not marked in this way and therefore
+ * has an explicit representation, this representation may still
+ * depend (indirectly) on other local variables that do not
+ * have an explicit representation.
+ */
+isl_bool isl_basic_map_div_is_marked_unknown(__isl_keep isl_basic_map *bmap,
+	int div)
+{
+	if (isl_basic_map_check_range(bmap, isl_dim_div, div, 1) < 0)
+		return isl_bool_error;
+	return isl_int_is_zero(bmap->div[div][0]);
+}
+
+/* Return the position of the first local variable that does not
+ * have an explicit representation.
+ * Return the total number of local variables if they all have
+ * an explicit representation.
+ * Return -1 on error.
+ */
+int isl_basic_map_first_unknown_div(__isl_keep isl_basic_map *bmap)
+{
+	int i;
+
+	if (!bmap)
+		return -1;
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (!isl_basic_map_div_is_known(bmap, i))
+			return i;
+	}
+	return bmap->n_div;
+}
+
+/* Return the position of the first local variable that does not
+ * have an explicit representation.
+ * Return the total number of local variables if they all have
+ * an explicit representation.
+ * Return -1 on error.
+ */
+int isl_basic_set_first_unknown_div(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_first_unknown_div(bset);
+}
+
+/* Does "bmap" have an explicit representation for all local variables?
+ */
+isl_bool isl_basic_map_divs_known(__isl_keep isl_basic_map *bmap)
+{
+	int first, n;
+
+	n = isl_basic_map_dim(bmap, isl_dim_div);
+	first = isl_basic_map_first_unknown_div(bmap);
+	if (first < 0)
+		return isl_bool_error;
+	return first == n;
+}
+
+/* Do all basic maps in "map" have an explicit representation
+ * for all local variables?
+ */
+isl_bool isl_map_divs_known(__isl_keep isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return isl_bool_error;
+
+	for (i = 0; i < map->n; ++i) {
+		int known = isl_basic_map_divs_known(map->p[i]);
+		if (known <= 0)
+			return known;
+	}
+
+	return isl_bool_true;
+}
+
+/* If bmap contains any unknown divs, then compute explicit
+ * expressions for them.  However, this computation may be
+ * quite expensive, so first try to remove divs that aren't
+ * strictly needed.
+ */
+__isl_give isl_map *isl_basic_map_compute_divs(__isl_take isl_basic_map *bmap)
+{
+	int known;
+	struct isl_map *map;
+
+	known = isl_basic_map_divs_known(bmap);
+	if (known < 0)
+		goto error;
+	if (known)
+		return isl_map_from_basic_map(bmap);
+
+	bmap = isl_basic_map_drop_redundant_divs(bmap);
+
+	known = isl_basic_map_divs_known(bmap);
+	if (known < 0)
+		goto error;
+	if (known)
+		return isl_map_from_basic_map(bmap);
+
+	map = compute_divs(bmap);
+	return map;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_compute_divs(__isl_take isl_map *map)
+{
+	int i;
+	int known;
+	struct isl_map *res;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return map;
+
+	known = isl_map_divs_known(map);
+	if (known < 0) {
+		isl_map_free(map);
+		return NULL;
+	}
+	if (known)
+		return map;
+
+	res = isl_basic_map_compute_divs(isl_basic_map_copy(map->p[0]));
+	for (i = 1 ; i < map->n; ++i) {
+		struct isl_map *r2;
+		r2 = isl_basic_map_compute_divs(isl_basic_map_copy(map->p[i]));
+		if (ISL_F_ISSET(map, ISL_MAP_DISJOINT))
+			res = isl_map_union_disjoint(res, r2);
+		else
+			res = isl_map_union(res, r2);
+	}
+	isl_map_free(map);
+
+	return res;
+}
+
+__isl_give isl_set *isl_basic_set_compute_divs(__isl_take isl_basic_set *bset)
+{
+	return set_from_map(isl_basic_map_compute_divs(bset_to_bmap(bset)));
+}
+
+struct isl_set *isl_set_compute_divs(struct isl_set *set)
+{
+	return set_from_map(isl_map_compute_divs(set_to_map(set)));
+}
+
+__isl_give isl_set *isl_map_domain(__isl_take isl_map *map)
+{
+	int i;
+	struct isl_set *set;
+
+	if (!map)
+		goto error;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	set = set_from_map(map);
+	set->dim = isl_space_domain(set->dim);
+	if (!set->dim)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		set->p[i] = isl_basic_map_domain(map->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+	ISL_F_CLR(set, ISL_MAP_DISJOINT);
+	ISL_F_CLR(set, ISL_SET_NORMALIZED);
+	return set;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Return the union of "map1" and "map2", where we assume for now that
+ * "map1" and "map2" are disjoint.  Note that the basic maps inside
+ * "map1" or "map2" may not be disjoint from each other.
+ * Also note that this function is also called from isl_map_union,
+ * which takes care of handling the situation where "map1" and "map2"
+ * may not be disjoint.
+ *
+ * If one of the inputs is empty, we can simply return the other input.
+ * Similarly, if one of the inputs is universal, then it is equal to the union.
+ */
+static __isl_give isl_map *map_union_disjoint(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	int i;
+	unsigned flags = 0;
+	struct isl_map *map = NULL;
+	int is_universe;
+
+	if (!map1 || !map2)
+		goto error;
+
+	if (!isl_space_is_equal(map1->dim, map2->dim))
+		isl_die(isl_map_get_ctx(map1), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	if (map1->n == 0) {
+		isl_map_free(map1);
+		return map2;
+	}
+	if (map2->n == 0) {
+		isl_map_free(map2);
+		return map1;
+	}
+
+	is_universe = isl_map_plain_is_universe(map1);
+	if (is_universe < 0)
+		goto error;
+	if (is_universe) {
+		isl_map_free(map2);
+		return map1;
+	}
+
+	is_universe = isl_map_plain_is_universe(map2);
+	if (is_universe < 0)
+		goto error;
+	if (is_universe) {
+		isl_map_free(map1);
+		return map2;
+	}
+
+	if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) &&
+	    ISL_F_ISSET(map2, ISL_MAP_DISJOINT))
+		ISL_FL_SET(flags, ISL_MAP_DISJOINT);
+
+	map = isl_map_alloc_space(isl_space_copy(map1->dim),
+				map1->n + map2->n, flags);
+	if (!map)
+		goto error;
+	for (i = 0; i < map1->n; ++i) {
+		map = isl_map_add_basic_map(map,
+				  isl_basic_map_copy(map1->p[i]));
+		if (!map)
+			goto error;
+	}
+	for (i = 0; i < map2->n; ++i) {
+		map = isl_map_add_basic_map(map,
+				  isl_basic_map_copy(map2->p[i]));
+		if (!map)
+			goto error;
+	}
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return map;
+error:
+	isl_map_free(map);
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+/* Return the union of "map1" and "map2", where "map1" and "map2" are
+ * guaranteed to be disjoint by the caller.
+ *
+ * Note that this functions is called from within isl_map_make_disjoint,
+ * so we have to be careful not to touch the constraints of the inputs
+ * in any way.
+ */
+__isl_give isl_map *isl_map_union_disjoint(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_union_disjoint);
+}
+
+/* Return the union of "map1" and "map2", where "map1" and "map2" may
+ * not be disjoint.  The parameters are assumed to have been aligned.
+ *
+ * We currently simply call map_union_disjoint, the internal operation
+ * of which does not really depend on the inputs being disjoint.
+ * If the result contains more than one basic map, then we clear
+ * the disjoint flag since the result may contain basic maps from
+ * both inputs and these are not guaranteed to be disjoint.
+ *
+ * As a special case, if "map1" and "map2" are obviously equal,
+ * then we simply return "map1".
+ */
+static __isl_give isl_map *map_union_aligned(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	int equal;
+
+	if (!map1 || !map2)
+		goto error;
+
+	equal = isl_map_plain_is_equal(map1, map2);
+	if (equal < 0)
+		goto error;
+	if (equal) {
+		isl_map_free(map2);
+		return map1;
+	}
+
+	map1 = map_union_disjoint(map1, map2);
+	if (!map1)
+		return NULL;
+	if (map1->n > 1)
+		ISL_F_CLR(map1, ISL_MAP_DISJOINT);
+	return map1;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+/* Return the union of "map1" and "map2", where "map1" and "map2" may
+ * not be disjoint.
+ */
+__isl_give isl_map *isl_map_union(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_union_aligned);
+}
+
+__isl_give isl_set *isl_set_union_disjoint(
+	__isl_take isl_set *set1, __isl_take isl_set *set2)
+{
+	return set_from_map(isl_map_union_disjoint(set_to_map(set1),
+						    set_to_map(set2)));
+}
+
+struct isl_set *isl_set_union(struct isl_set *set1, struct isl_set *set2)
+{
+	return set_from_map(isl_map_union(set_to_map(set1), set_to_map(set2)));
+}
+
+/* Apply "fn" to pairs of elements from "map" and "set" and collect
+ * the results.
+ *
+ * "map" and "set" are assumed to be compatible and non-NULL.
+ */
+static __isl_give isl_map *map_intersect_set(__isl_take isl_map *map,
+	__isl_take isl_set *set,
+	__isl_give isl_basic_map *fn(__isl_take isl_basic_map *bmap,
+		__isl_take isl_basic_set *bset))
+{
+	unsigned flags = 0;
+	struct isl_map *result;
+	int i, j;
+
+	if (isl_set_plain_is_universe(set)) {
+		isl_set_free(set);
+		return map;
+	}
+
+	if (ISL_F_ISSET(map, ISL_MAP_DISJOINT) &&
+	    ISL_F_ISSET(set, ISL_MAP_DISJOINT))
+		ISL_FL_SET(flags, ISL_MAP_DISJOINT);
+
+	result = isl_map_alloc_space(isl_space_copy(map->dim),
+					map->n * set->n, flags);
+	for (i = 0; result && i < map->n; ++i)
+		for (j = 0; j < set->n; ++j) {
+			result = isl_map_add_basic_map(result,
+					fn(isl_basic_map_copy(map->p[i]),
+					    isl_basic_set_copy(set->p[j])));
+			if (!result)
+				break;
+		}
+
+	isl_map_free(map);
+	isl_set_free(set);
+	return result;
+}
+
+static __isl_give isl_map *map_intersect_range(__isl_take isl_map *map,
+	__isl_take isl_set *set)
+{
+	isl_bool ok;
+
+	ok = isl_map_compatible_range(map, set);
+	if (ok < 0)
+		goto error;
+	if (!ok)
+		isl_die(set->ctx, isl_error_invalid,
+			"incompatible spaces", goto error);
+
+	return map_intersect_set(map, set, &isl_basic_map_intersect_range);
+error:
+	isl_map_free(map);
+	isl_set_free(set);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_intersect_range(__isl_take isl_map *map,
+	__isl_take isl_set *set)
+{
+	return isl_map_align_params_map_map_and(map, set, &map_intersect_range);
+}
+
+static __isl_give isl_map *map_intersect_domain(__isl_take isl_map *map,
+	__isl_take isl_set *set)
+{
+	isl_bool ok;
+
+	ok = isl_map_compatible_domain(map, set);
+	if (ok < 0)
+		goto error;
+	if (!ok)
+		isl_die(set->ctx, isl_error_invalid,
+			"incompatible spaces", goto error);
+
+	return map_intersect_set(map, set, &isl_basic_map_intersect_domain);
+error:
+	isl_map_free(map);
+	isl_set_free(set);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_intersect_domain(__isl_take isl_map *map,
+	__isl_take isl_set *set)
+{
+	return isl_map_align_params_map_map_and(map, set,
+						&map_intersect_domain);
+}
+
+/* Given a map "map" in a space [A -> B] -> C and a map "factor"
+ * in the space B -> C, return the intersection.
+ * The parameters are assumed to have been aligned.
+ *
+ * The map "factor" is first extended to a map living in the space
+ * [A -> B] -> C and then a regular intersection is computed.
+ */
+static __isl_give isl_map *map_intersect_domain_factor_range(
+	__isl_take isl_map *map, __isl_take isl_map *factor)
+{
+	isl_space *space;
+	isl_map *ext_factor;
+
+	space = isl_space_domain_factor_domain(isl_map_get_space(map));
+	ext_factor = isl_map_universe(space);
+	ext_factor = isl_map_domain_product(ext_factor, factor);
+	return map_intersect(map, ext_factor);
+}
+
+/* Given a map "map" in a space [A -> B] -> C and a map "factor"
+ * in the space B -> C, return the intersection.
+ */
+__isl_give isl_map *isl_map_intersect_domain_factor_range(
+	__isl_take isl_map *map, __isl_take isl_map *factor)
+{
+	return isl_map_align_params_map_map_and(map, factor,
+					    &map_intersect_domain_factor_range);
+}
+
+/* Given a map "map" in a space A -> [B -> C] and a map "factor"
+ * in the space A -> C, return the intersection.
+ *
+ * The map "factor" is first extended to a map living in the space
+ * A -> [B -> C] and then a regular intersection is computed.
+ */
+static __isl_give isl_map *map_intersect_range_factor_range(
+	__isl_take isl_map *map, __isl_take isl_map *factor)
+{
+	isl_space *space;
+	isl_map *ext_factor;
+
+	space = isl_space_range_factor_domain(isl_map_get_space(map));
+	ext_factor = isl_map_universe(space);
+	ext_factor = isl_map_range_product(ext_factor, factor);
+	return isl_map_intersect(map, ext_factor);
+}
+
+/* Given a map "map" in a space A -> [B -> C] and a map "factor"
+ * in the space A -> C, return the intersection.
+ */
+__isl_give isl_map *isl_map_intersect_range_factor_range(
+	__isl_take isl_map *map, __isl_take isl_map *factor)
+{
+	return isl_map_align_params_map_map_and(map, factor,
+					    &map_intersect_range_factor_range);
+}
+
+static __isl_give isl_map *map_apply_domain(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	if (!map1 || !map2)
+		goto error;
+	map1 = isl_map_reverse(map1);
+	map1 = isl_map_apply_range(map1, map2);
+	return isl_map_reverse(map1);
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_apply_domain(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_apply_domain);
+}
+
+static __isl_give isl_map *map_apply_range(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_space *dim_result;
+	struct isl_map *result;
+	int i, j;
+
+	if (!map1 || !map2)
+		goto error;
+
+	dim_result = isl_space_join(isl_space_copy(map1->dim),
+				  isl_space_copy(map2->dim));
+
+	result = isl_map_alloc_space(dim_result, map1->n * map2->n, 0);
+	if (!result)
+		goto error;
+	for (i = 0; i < map1->n; ++i)
+		for (j = 0; j < map2->n; ++j) {
+			result = isl_map_add_basic_map(result,
+			    isl_basic_map_apply_range(
+				isl_basic_map_copy(map1->p[i]),
+				isl_basic_map_copy(map2->p[j])));
+			if (!result)
+				goto error;
+		}
+	isl_map_free(map1);
+	isl_map_free(map2);
+	if (result && result->n <= 1)
+		ISL_F_SET(result, ISL_MAP_DISJOINT);
+	return result;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_apply_range(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_apply_range);
+}
+
+/*
+ * returns range - domain
+ */
+__isl_give isl_basic_set *isl_basic_map_deltas(__isl_take isl_basic_map *bmap)
+{
+	isl_space *target_space;
+	struct isl_basic_set *bset;
+	unsigned dim;
+	unsigned nparam;
+	int i;
+
+	if (!bmap)
+		goto error;
+	isl_assert(bmap->ctx, isl_space_tuple_is_equal(bmap->dim, isl_dim_in,
+						  bmap->dim, isl_dim_out),
+		   goto error);
+	target_space = isl_space_domain(isl_basic_map_get_space(bmap));
+	dim = isl_basic_map_dim(bmap, isl_dim_in);
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	bmap = isl_basic_map_from_range(isl_basic_map_wrap(bmap));
+	bmap = isl_basic_map_add_dims(bmap, isl_dim_in, dim);
+	bmap = isl_basic_map_extend_constraints(bmap, dim, 0);
+	for (i = 0; i < dim; ++i) {
+		int j = isl_basic_map_alloc_equality(bmap);
+		if (j < 0) {
+			bmap = isl_basic_map_free(bmap);
+			break;
+		}
+		isl_seq_clr(bmap->eq[j], 1 + isl_basic_map_total_dim(bmap));
+		isl_int_set_si(bmap->eq[j][1+nparam+i], 1);
+		isl_int_set_si(bmap->eq[j][1+nparam+dim+i], 1);
+		isl_int_set_si(bmap->eq[j][1+nparam+2*dim+i], -1);
+	}
+	bset = isl_basic_map_domain(bmap);
+	bset = isl_basic_set_reset_space(bset, target_space);
+	return bset;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/*
+ * returns range - domain
+ */
+__isl_give isl_set *isl_map_deltas(__isl_take isl_map *map)
+{
+	int i;
+	isl_space *dim;
+	struct isl_set *result;
+
+	if (!map)
+		return NULL;
+
+	isl_assert(map->ctx, isl_space_tuple_is_equal(map->dim, isl_dim_in,
+						 map->dim, isl_dim_out),
+		   goto error);
+	dim = isl_map_get_space(map);
+	dim = isl_space_domain(dim);
+	result = isl_set_alloc_space(dim, map->n, 0);
+	if (!result)
+		goto error;
+	for (i = 0; i < map->n; ++i)
+		result = isl_set_add_basic_set(result,
+			  isl_basic_map_deltas(isl_basic_map_copy(map->p[i])));
+	isl_map_free(map);
+	return result;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/*
+ * returns [domain -> range] -> range - domain
+ */
+__isl_give isl_basic_map *isl_basic_map_deltas_map(
+	__isl_take isl_basic_map *bmap)
+{
+	int i, k;
+	isl_space *dim;
+	isl_basic_map *domain;
+	int nparam, n;
+	unsigned total;
+
+	if (!isl_space_tuple_is_equal(bmap->dim, isl_dim_in,
+					bmap->dim, isl_dim_out))
+		isl_die(bmap->ctx, isl_error_invalid,
+			"domain and range don't match", goto error);
+
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n = isl_basic_map_dim(bmap, isl_dim_in);
+
+	dim = isl_space_from_range(isl_space_domain(isl_basic_map_get_space(bmap)));
+	domain = isl_basic_map_universe(dim);
+
+	bmap = isl_basic_map_from_domain(isl_basic_map_wrap(bmap));
+	bmap = isl_basic_map_apply_range(bmap, domain);
+	bmap = isl_basic_map_extend_constraints(bmap, n, 0);
+
+	total = isl_basic_map_total_dim(bmap);
+
+	for (i = 0; i < n; ++i) {
+		k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bmap->eq[k], 1 + total);
+		isl_int_set_si(bmap->eq[k][1 + nparam + i], 1);
+		isl_int_set_si(bmap->eq[k][1 + nparam + n + i], -1);
+		isl_int_set_si(bmap->eq[k][1 + nparam + n + n + i], 1);
+	}
+
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/*
+ * returns [domain -> range] -> range - domain
+ */
+__isl_give isl_map *isl_map_deltas_map(__isl_take isl_map *map)
+{
+	int i;
+	isl_space *domain_dim;
+
+	if (!map)
+		return NULL;
+
+	if (!isl_space_tuple_is_equal(map->dim, isl_dim_in,
+					map->dim, isl_dim_out))
+		isl_die(map->ctx, isl_error_invalid,
+			"domain and range don't match", goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	domain_dim = isl_space_from_range(isl_space_domain(isl_map_get_space(map)));
+	map->dim = isl_space_from_domain(isl_space_wrap(map->dim));
+	map->dim = isl_space_join(map->dim, domain_dim);
+	if (!map->dim)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_deltas_map(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+static __isl_give isl_basic_map *basic_map_identity(__isl_take isl_space *dims)
+{
+	struct isl_basic_map *bmap;
+	unsigned nparam;
+	unsigned dim;
+	int i;
+
+	if (!dims)
+		return NULL;
+
+	nparam = dims->nparam;
+	dim = dims->n_out;
+	bmap = isl_basic_map_alloc_space(dims, 0, dim, 0);
+	if (!bmap)
+		goto error;
+
+	for (i = 0; i < dim; ++i) {
+		int j = isl_basic_map_alloc_equality(bmap);
+		if (j < 0)
+			goto error;
+		isl_seq_clr(bmap->eq[j], 1 + isl_basic_map_total_dim(bmap));
+		isl_int_set_si(bmap->eq[j][1+nparam+i], 1);
+		isl_int_set_si(bmap->eq[j][1+nparam+dim+i], -1);
+	}
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_identity(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	if (dim->n_in != dim->n_out)
+		isl_die(dim->ctx, isl_error_invalid,
+			"number of input and output dimensions needs to be "
+			"the same", goto error);
+	return basic_map_identity(dim);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_identity(__isl_take isl_space *dim)
+{
+	return isl_map_from_basic_map(isl_basic_map_identity(dim));
+}
+
+__isl_give isl_map *isl_set_identity(__isl_take isl_set *set)
+{
+	isl_space *dim = isl_set_get_space(set);
+	isl_map *id;
+	id = isl_map_identity(isl_space_map_from_set(dim));
+	return isl_map_intersect_range(id, set);
+}
+
+/* Construct a basic set with all set dimensions having only non-negative
+ * values.
+ */
+__isl_give isl_basic_set *isl_basic_set_positive_orthant(
+	__isl_take isl_space *space)
+{
+	int i;
+	unsigned nparam;
+	unsigned dim;
+	struct isl_basic_set *bset;
+
+	if (!space)
+		return NULL;
+	nparam = space->nparam;
+	dim = space->n_out;
+	bset = isl_basic_set_alloc_space(space, 0, 0, dim);
+	if (!bset)
+		return NULL;
+	for (i = 0; i < dim; ++i) {
+		int k = isl_basic_set_alloc_inequality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bset->ineq[k], 1 + isl_basic_set_total_dim(bset));
+		isl_int_set_si(bset->ineq[k][1 + nparam + i], 1);
+	}
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Construct the half-space x_pos >= 0.
+ */
+static __isl_give isl_basic_set *nonneg_halfspace(__isl_take isl_space *dim,
+	int pos)
+{
+	int k;
+	isl_basic_set *nonneg;
+
+	nonneg = isl_basic_set_alloc_space(dim, 0, 0, 1);
+	k = isl_basic_set_alloc_inequality(nonneg);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(nonneg->ineq[k], 1 + isl_basic_set_total_dim(nonneg));
+	isl_int_set_si(nonneg->ineq[k][pos], 1);
+
+	return isl_basic_set_finalize(nonneg);
+error:
+	isl_basic_set_free(nonneg);
+	return NULL;
+}
+
+/* Construct the half-space x_pos <= -1.
+ */
+static __isl_give isl_basic_set *neg_halfspace(__isl_take isl_space *dim, int pos)
+{
+	int k;
+	isl_basic_set *neg;
+
+	neg = isl_basic_set_alloc_space(dim, 0, 0, 1);
+	k = isl_basic_set_alloc_inequality(neg);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(neg->ineq[k], 1 + isl_basic_set_total_dim(neg));
+	isl_int_set_si(neg->ineq[k][0], -1);
+	isl_int_set_si(neg->ineq[k][pos], -1);
+
+	return isl_basic_set_finalize(neg);
+error:
+	isl_basic_set_free(neg);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_split_dims(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	unsigned offset;
+	isl_basic_set *nonneg;
+	isl_basic_set *neg;
+
+	if (!set)
+		return NULL;
+	if (n == 0)
+		return set;
+
+	isl_assert(set->ctx, first + n <= isl_set_dim(set, type), goto error);
+
+	offset = pos(set->dim, type);
+	for (i = 0; i < n; ++i) {
+		nonneg = nonneg_halfspace(isl_set_get_space(set),
+					  offset + first + i);
+		neg = neg_halfspace(isl_set_get_space(set), offset + first + i);
+
+		set = isl_set_intersect(set, isl_basic_set_union(nonneg, neg));
+	}
+
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+static isl_stat foreach_orthant(__isl_take isl_set *set, int *signs, int first,
+	int len,
+	isl_stat (*fn)(__isl_take isl_set *orthant, int *signs, void *user),
+	void *user)
+{
+	isl_set *half;
+
+	if (!set)
+		return isl_stat_error;
+	if (isl_set_plain_is_empty(set)) {
+		isl_set_free(set);
+		return isl_stat_ok;
+	}
+	if (first == len)
+		return fn(set, signs, user);
+
+	signs[first] = 1;
+	half = isl_set_from_basic_set(nonneg_halfspace(isl_set_get_space(set),
+							1 + first));
+	half = isl_set_intersect(half, isl_set_copy(set));
+	if (foreach_orthant(half, signs, first + 1, len, fn, user) < 0)
+		goto error;
+
+	signs[first] = -1;
+	half = isl_set_from_basic_set(neg_halfspace(isl_set_get_space(set),
+							1 + first));
+	half = isl_set_intersect(half, set);
+	return foreach_orthant(half, signs, first + 1, len, fn, user);
+error:
+	isl_set_free(set);
+	return isl_stat_error;
+}
+
+/* Call "fn" on the intersections of "set" with each of the orthants
+ * (except for obviously empty intersections).  The orthant is identified
+ * by the signs array, with each entry having value 1 or -1 according
+ * to the sign of the corresponding variable.
+ */
+isl_stat isl_set_foreach_orthant(__isl_keep isl_set *set,
+	isl_stat (*fn)(__isl_take isl_set *orthant, int *signs, void *user),
+	void *user)
+{
+	unsigned nparam;
+	unsigned nvar;
+	int *signs;
+	isl_stat r;
+
+	if (!set)
+		return isl_stat_error;
+	if (isl_set_plain_is_empty(set))
+		return isl_stat_ok;
+
+	nparam = isl_set_dim(set, isl_dim_param);
+	nvar = isl_set_dim(set, isl_dim_set);
+
+	signs = isl_alloc_array(set->ctx, int, nparam + nvar);
+
+	r = foreach_orthant(isl_set_copy(set), signs, 0, nparam + nvar,
+			    fn, user);
+
+	free(signs);
+
+	return r;
+}
+
+isl_bool isl_set_is_equal(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	return isl_map_is_equal(set_to_map(set1), set_to_map(set2));
+}
+
+isl_bool isl_basic_map_is_subset(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	int is_subset;
+	struct isl_map *map1;
+	struct isl_map *map2;
+
+	if (!bmap1 || !bmap2)
+		return isl_bool_error;
+
+	map1 = isl_map_from_basic_map(isl_basic_map_copy(bmap1));
+	map2 = isl_map_from_basic_map(isl_basic_map_copy(bmap2));
+
+	is_subset = isl_map_is_subset(map1, map2);
+
+	isl_map_free(map1);
+	isl_map_free(map2);
+
+	return is_subset;
+}
+
+isl_bool isl_basic_set_is_subset(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2)
+{
+	return isl_basic_map_is_subset(bset1, bset2);
+}
+
+isl_bool isl_basic_map_is_equal(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	isl_bool is_subset;
+
+	if (!bmap1 || !bmap2)
+		return isl_bool_error;
+	is_subset = isl_basic_map_is_subset(bmap1, bmap2);
+	if (is_subset != isl_bool_true)
+		return is_subset;
+	is_subset = isl_basic_map_is_subset(bmap2, bmap1);
+	return is_subset;
+}
+
+isl_bool isl_basic_set_is_equal(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2)
+{
+	return isl_basic_map_is_equal(
+		bset_to_bmap(bset1), bset_to_bmap(bset2));
+}
+
+isl_bool isl_map_is_empty(__isl_keep isl_map *map)
+{
+	int i;
+	int is_empty;
+
+	if (!map)
+		return isl_bool_error;
+	for (i = 0; i < map->n; ++i) {
+		is_empty = isl_basic_map_is_empty(map->p[i]);
+		if (is_empty < 0)
+			return isl_bool_error;
+		if (!is_empty)
+			return isl_bool_false;
+	}
+	return isl_bool_true;
+}
+
+isl_bool isl_map_plain_is_empty(__isl_keep isl_map *map)
+{
+	return map ? map->n == 0 : isl_bool_error;
+}
+
+isl_bool isl_set_plain_is_empty(__isl_keep isl_set *set)
+{
+	return set ? set->n == 0 : isl_bool_error;
+}
+
+isl_bool isl_set_is_empty(__isl_keep isl_set *set)
+{
+	return isl_map_is_empty(set_to_map(set));
+}
+
+isl_bool isl_map_has_equal_space(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2)
+{
+	if (!map1 || !map2)
+		return isl_bool_error;
+
+	return isl_space_is_equal(map1->dim, map2->dim);
+}
+
+isl_bool isl_set_has_equal_space(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2)
+{
+	if (!set1 || !set2)
+		return isl_bool_error;
+
+	return isl_space_is_equal(set1->dim, set2->dim);
+}
+
+static isl_bool map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	isl_bool is_subset;
+
+	if (!map1 || !map2)
+		return isl_bool_error;
+	is_subset = isl_map_is_subset(map1, map2);
+	if (is_subset != isl_bool_true)
+		return is_subset;
+	is_subset = isl_map_is_subset(map2, map1);
+	return is_subset;
+}
+
+/* Is "map1" equal to "map2"?
+ *
+ * First check if they are obviously equal.
+ * If not, then perform a more detailed analysis.
+ */
+isl_bool isl_map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	isl_bool equal;
+
+	equal = isl_map_plain_is_equal(map1, map2);
+	if (equal < 0 || equal)
+		return equal;
+	return isl_map_align_params_map_map_and_test(map1, map2, &map_is_equal);
+}
+
+isl_bool isl_basic_map_is_strict_subset(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	isl_bool is_subset;
+
+	if (!bmap1 || !bmap2)
+		return isl_bool_error;
+	is_subset = isl_basic_map_is_subset(bmap1, bmap2);
+	if (is_subset != isl_bool_true)
+		return is_subset;
+	is_subset = isl_basic_map_is_subset(bmap2, bmap1);
+	if (is_subset == isl_bool_error)
+		return is_subset;
+	return !is_subset;
+}
+
+isl_bool isl_map_is_strict_subset(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2)
+{
+	isl_bool is_subset;
+
+	if (!map1 || !map2)
+		return isl_bool_error;
+	is_subset = isl_map_is_subset(map1, map2);
+	if (is_subset != isl_bool_true)
+		return is_subset;
+	is_subset = isl_map_is_subset(map2, map1);
+	if (is_subset == isl_bool_error)
+		return is_subset;
+	return !is_subset;
+}
+
+isl_bool isl_set_is_strict_subset(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2)
+{
+	return isl_map_is_strict_subset(set_to_map(set1), set_to_map(set2));
+}
+
+/* Is "bmap" obviously equal to the universe with the same space?
+ *
+ * That is, does it not have any constraints?
+ */
+isl_bool isl_basic_map_plain_is_universe(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return isl_bool_error;
+	return bmap->n_eq == 0 && bmap->n_ineq == 0;
+}
+
+/* Is "bset" obviously equal to the universe with the same space?
+ */
+isl_bool isl_basic_set_plain_is_universe(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_plain_is_universe(bset);
+}
+
+/* If "c" does not involve any existentially quantified variables,
+ * then set *univ to false and abort
+ */
+static isl_stat involves_divs(__isl_take isl_constraint *c, void *user)
+{
+	isl_bool *univ = user;
+	unsigned n;
+
+	n = isl_constraint_dim(c, isl_dim_div);
+	*univ = isl_constraint_involves_dims(c, isl_dim_div, 0, n);
+	isl_constraint_free(c);
+	if (*univ < 0 || !*univ)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Is "bmap" equal to the universe with the same space?
+ *
+ * First check if it is obviously equal to the universe.
+ * If not and if there are any constraints not involving
+ * existentially quantified variables, then it is certainly
+ * not equal to the universe.
+ * Otherwise, check if the universe is a subset of "bmap".
+ */
+isl_bool isl_basic_map_is_universe(__isl_keep isl_basic_map *bmap)
+{
+	isl_bool univ;
+	isl_basic_map *test;
+
+	univ = isl_basic_map_plain_is_universe(bmap);
+	if (univ < 0 || univ)
+		return univ;
+	if (isl_basic_map_dim(bmap, isl_dim_div) == 0)
+		return isl_bool_false;
+	univ = isl_bool_true;
+	if (isl_basic_map_foreach_constraint(bmap, &involves_divs, &univ) < 0 &&
+	    univ)
+		return isl_bool_error;
+	if (univ < 0 || !univ)
+		return univ;
+	test = isl_basic_map_universe(isl_basic_map_get_space(bmap));
+	univ = isl_basic_map_is_subset(test, bmap);
+	isl_basic_map_free(test);
+	return univ;
+}
+
+/* Is "bset" equal to the universe with the same space?
+ */
+isl_bool isl_basic_set_is_universe(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_is_universe(bset);
+}
+
+isl_bool isl_map_plain_is_universe(__isl_keep isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return isl_bool_error;
+
+	for (i = 0; i < map->n; ++i) {
+		isl_bool r = isl_basic_map_plain_is_universe(map->p[i]);
+		if (r < 0 || r)
+			return r;
+	}
+
+	return isl_bool_false;
+}
+
+isl_bool isl_set_plain_is_universe(__isl_keep isl_set *set)
+{
+	return isl_map_plain_is_universe(set_to_map(set));
+}
+
+isl_bool isl_basic_map_is_empty(__isl_keep isl_basic_map *bmap)
+{
+	struct isl_basic_set *bset = NULL;
+	struct isl_vec *sample = NULL;
+	isl_bool empty, non_empty;
+
+	if (!bmap)
+		return isl_bool_error;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+		return isl_bool_true;
+
+	if (isl_basic_map_plain_is_universe(bmap))
+		return isl_bool_false;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) {
+		struct isl_basic_map *copy = isl_basic_map_copy(bmap);
+		copy = isl_basic_map_remove_redundancies(copy);
+		empty = isl_basic_map_plain_is_empty(copy);
+		isl_basic_map_free(copy);
+		return empty;
+	}
+
+	non_empty = isl_basic_map_plain_is_non_empty(bmap);
+	if (non_empty < 0)
+		return isl_bool_error;
+	if (non_empty)
+		return isl_bool_false;
+	isl_vec_free(bmap->sample);
+	bmap->sample = NULL;
+	bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap));
+	if (!bset)
+		return isl_bool_error;
+	sample = isl_basic_set_sample_vec(bset);
+	if (!sample)
+		return isl_bool_error;
+	empty = sample->size == 0;
+	isl_vec_free(bmap->sample);
+	bmap->sample = sample;
+	if (empty)
+		ISL_F_SET(bmap, ISL_BASIC_MAP_EMPTY);
+
+	return empty;
+}
+
+isl_bool isl_basic_map_plain_is_empty(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return isl_bool_error;
+	return ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY);
+}
+
+isl_bool isl_basic_set_plain_is_empty(__isl_keep isl_basic_set *bset)
+{
+	if (!bset)
+		return isl_bool_error;
+	return ISL_F_ISSET(bset, ISL_BASIC_SET_EMPTY);
+}
+
+/* Is "bmap" known to be non-empty?
+ *
+ * That is, is the cached sample still valid?
+ */
+isl_bool isl_basic_map_plain_is_non_empty(__isl_keep isl_basic_map *bmap)
+{
+	unsigned total;
+
+	if (!bmap)
+		return isl_bool_error;
+	if (!bmap->sample)
+		return isl_bool_false;
+	total = 1 + isl_basic_map_total_dim(bmap);
+	if (bmap->sample->size != total)
+		return isl_bool_false;
+	return isl_basic_map_contains(bmap, bmap->sample);
+}
+
+isl_bool isl_basic_set_is_empty(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_is_empty(bset_to_bmap(bset));
+}
+
+__isl_give isl_map *isl_basic_map_union(__isl_take isl_basic_map *bmap1,
+	__isl_take isl_basic_map *bmap2)
+{
+	struct isl_map *map;
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim), goto error);
+
+	map = isl_map_alloc_space(isl_space_copy(bmap1->dim), 2, 0);
+	if (!map)
+		goto error;
+	map = isl_map_add_basic_map(map, bmap1);
+	map = isl_map_add_basic_map(map, bmap2);
+	return map;
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+struct isl_set *isl_basic_set_union(
+		struct isl_basic_set *bset1, struct isl_basic_set *bset2)
+{
+	return set_from_map(isl_basic_map_union(bset_to_bmap(bset1),
+						bset_to_bmap(bset2)));
+}
+
+/* Order divs such that any div only depends on previous divs */
+__isl_give isl_basic_map *isl_basic_map_order_divs(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+	unsigned off;
+
+	if (!bmap)
+		return NULL;
+
+	off = isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		int pos;
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		pos = isl_seq_first_non_zero(bmap->div[i]+1+1+off+i,
+							    bmap->n_div-i);
+		if (pos == -1)
+			continue;
+		if (pos == 0)
+			isl_die(isl_basic_map_get_ctx(bmap), isl_error_internal,
+				"integer division depends on itself",
+				return isl_basic_map_free(bmap));
+		isl_basic_map_swap_div(bmap, i, i + pos);
+		--i;
+	}
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_order_divs(struct isl_basic_set *bset)
+{
+	return bset_from_bmap(isl_basic_map_order_divs(bset_to_bmap(bset)));
+}
+
+__isl_give isl_map *isl_map_order_divs(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return 0;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_order_divs(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Sort the local variables of "bset".
+ */
+__isl_give isl_basic_set *isl_basic_set_sort_divs(
+	__isl_take isl_basic_set *bset)
+{
+	return bset_from_bmap(isl_basic_map_sort_divs(bset_to_bmap(bset)));
+}
+
+/* Apply the expansion computed by isl_merge_divs.
+ * The expansion itself is given by "exp" while the resulting
+ * list of divs is given by "div".
+ *
+ * Move the integer divisions of "bmap" into the right position
+ * according to "exp" and then introduce the additional integer
+ * divisions, adding div constraints.
+ * The moving should be done first to avoid moving coefficients
+ * in the definitions of the extra integer divisions.
+ */
+__isl_give isl_basic_map *isl_basic_map_expand_divs(
+	__isl_take isl_basic_map *bmap, __isl_take isl_mat *div, int *exp)
+{
+	int i, j;
+	int n_div;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap || !div)
+		goto error;
+
+	if (div->n_row < bmap->n_div)
+		isl_die(isl_mat_get_ctx(div), isl_error_invalid,
+			"not an expansion", goto error);
+
+	n_div = bmap->n_div;
+	bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+					    div->n_row - n_div, 0,
+					    2 * (div->n_row - n_div));
+
+	for (i = n_div; i < div->n_row; ++i)
+		if (isl_basic_map_alloc_div(bmap) < 0)
+			goto error;
+
+	for (j = n_div - 1; j >= 0; --j) {
+		if (exp[j] == j)
+			break;
+		isl_basic_map_swap_div(bmap, j, exp[j]);
+	}
+	j = 0;
+	for (i = 0; i < div->n_row; ++i) {
+		if (j < n_div && exp[j] == i) {
+			j++;
+		} else {
+			isl_seq_cpy(bmap->div[i], div->row[i], div->n_col);
+			if (isl_basic_map_div_is_marked_unknown(bmap, i))
+				continue;
+			if (isl_basic_map_add_div_constraints(bmap, i) < 0)
+				goto error;
+		}
+	}
+
+	isl_mat_free(div);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_mat_free(div);
+	return NULL;
+}
+
+/* Apply the expansion computed by isl_merge_divs.
+ * The expansion itself is given by "exp" while the resulting
+ * list of divs is given by "div".
+ */
+__isl_give isl_basic_set *isl_basic_set_expand_divs(
+	__isl_take isl_basic_set *bset, __isl_take isl_mat *div, int *exp)
+{
+	return isl_basic_map_expand_divs(bset, div, exp);
+}
+
+/* Look for a div in dst that corresponds to the div "div" in src.
+ * The divs before "div" in src and dst are assumed to be the same.
+ * 
+ * Returns -1 if no corresponding div was found and the position
+ * of the corresponding div in dst otherwise.
+ */
+static int find_div(__isl_keep isl_basic_map *dst,
+	__isl_keep isl_basic_map *src, unsigned div)
+{
+	int i;
+
+	unsigned total = isl_space_dim(src->dim, isl_dim_all);
+
+	isl_assert(dst->ctx, div <= dst->n_div, return -1);
+	for (i = div; i < dst->n_div; ++i)
+		if (isl_seq_eq(dst->div[i], src->div[div], 1+1+total+div) &&
+		    isl_seq_first_non_zero(dst->div[i]+1+1+total+div,
+						dst->n_div - div) == -1)
+			return i;
+	return -1;
+}
+
+/* Align the divs of "dst" to those of "src", adding divs from "src"
+ * if needed.  That is, make sure that the first src->n_div divs
+ * of the result are equal to those of src.
+ *
+ * The result is not finalized as by design it will have redundant
+ * divs if any divs from "src" were copied.
+ */
+__isl_give isl_basic_map *isl_basic_map_align_divs(
+	__isl_take isl_basic_map *dst, __isl_keep isl_basic_map *src)
+{
+	int i;
+	int known, extended;
+	unsigned total;
+
+	if (!dst || !src)
+		return isl_basic_map_free(dst);
+
+	if (src->n_div == 0)
+		return dst;
+
+	known = isl_basic_map_divs_known(src);
+	if (known < 0)
+		return isl_basic_map_free(dst);
+	if (!known)
+		isl_die(isl_basic_map_get_ctx(src), isl_error_invalid,
+			"some src divs are unknown",
+			return isl_basic_map_free(dst));
+
+	src = isl_basic_map_order_divs(src);
+
+	extended = 0;
+	total = isl_space_dim(src->dim, isl_dim_all);
+	for (i = 0; i < src->n_div; ++i) {
+		int j = find_div(dst, src, i);
+		if (j < 0) {
+			if (!extended) {
+				int extra = src->n_div - i;
+				dst = isl_basic_map_cow(dst);
+				if (!dst)
+					return NULL;
+				dst = isl_basic_map_extend_space(dst,
+						isl_space_copy(dst->dim),
+						extra, 0, 2 * extra);
+				extended = 1;
+			}
+			j = isl_basic_map_alloc_div(dst);
+			if (j < 0)
+				return isl_basic_map_free(dst);
+			isl_seq_cpy(dst->div[j], src->div[i], 1+1+total+i);
+			isl_seq_clr(dst->div[j]+1+1+total+i, dst->n_div - i);
+			if (isl_basic_map_add_div_constraints(dst, j) < 0)
+				return isl_basic_map_free(dst);
+		}
+		if (j != i)
+			isl_basic_map_swap_div(dst, i, j);
+	}
+	return dst;
+}
+
+__isl_give isl_map *isl_map_align_divs_internal(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return map;
+	map = isl_map_compute_divs(map);
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 1; i < map->n; ++i)
+		map->p[0] = isl_basic_map_align_divs(map->p[0], map->p[i]);
+	for (i = 1; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_align_divs(map->p[i], map->p[0]);
+		if (!map->p[i])
+			return isl_map_free(map);
+	}
+
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+}
+
+__isl_give isl_map *isl_map_align_divs(__isl_take isl_map *map)
+{
+	return isl_map_align_divs_internal(map);
+}
+
+struct isl_set *isl_set_align_divs(struct isl_set *set)
+{
+	return set_from_map(isl_map_align_divs_internal(set_to_map(set)));
+}
+
+/* Align the divs of the basic maps in "map" to those
+ * of the basic maps in "list", as well as to the other basic maps in "map".
+ * The elements in "list" are assumed to have known divs.
+ */
+__isl_give isl_map *isl_map_align_divs_to_basic_map_list(
+	__isl_take isl_map *map, __isl_keep isl_basic_map_list *list)
+{
+	int i, n;
+
+	map = isl_map_compute_divs(map);
+	map = isl_map_cow(map);
+	if (!map || !list)
+		return isl_map_free(map);
+	if (map->n == 0)
+		return map;
+
+	n = isl_basic_map_list_n_basic_map(list);
+	for (i = 0; i < n; ++i) {
+		isl_basic_map *bmap;
+
+		bmap = isl_basic_map_list_get_basic_map(list, i);
+		map->p[0] = isl_basic_map_align_divs(map->p[0], bmap);
+		isl_basic_map_free(bmap);
+	}
+	if (!map->p[0])
+		return isl_map_free(map);
+
+	return isl_map_align_divs_internal(map);
+}
+
+/* Align the divs of each element of "list" to those of "bmap".
+ * Both "bmap" and the elements of "list" are assumed to have known divs.
+ */
+__isl_give isl_basic_map_list *isl_basic_map_list_align_divs_to_basic_map(
+	__isl_take isl_basic_map_list *list, __isl_keep isl_basic_map *bmap)
+{
+	int i, n;
+
+	if (!list || !bmap)
+		return isl_basic_map_list_free(list);
+
+	n = isl_basic_map_list_n_basic_map(list);
+	for (i = 0; i < n; ++i) {
+		isl_basic_map *bmap_i;
+
+		bmap_i = isl_basic_map_list_get_basic_map(list, i);
+		bmap_i = isl_basic_map_align_divs(bmap_i, bmap);
+		list = isl_basic_map_list_set_basic_map(list, i, bmap_i);
+	}
+
+	return list;
+}
+
+static __isl_give isl_set *set_apply( __isl_take isl_set *set,
+	__isl_take isl_map *map)
+{
+	isl_bool ok;
+
+	ok = isl_map_compatible_domain(map, set);
+	if (ok < 0)
+		goto error;
+	if (!ok)
+		isl_die(isl_set_get_ctx(set), isl_error_invalid,
+			"incompatible spaces", goto error);
+	map = isl_map_intersect_domain(map, set);
+	set = isl_map_range(map);
+	return set;
+error:
+	isl_set_free(set);
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_apply( __isl_take isl_set *set,
+	__isl_take isl_map *map)
+{
+	return isl_map_align_params_map_map_and(set, map, &set_apply);
+}
+
+/* There is no need to cow as removing empty parts doesn't change
+ * the meaning of the set.
+ */
+__isl_give isl_map *isl_map_remove_empty_parts(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	for (i = map->n - 1; i >= 0; --i)
+		remove_if_empty(map, i);
+
+	return map;
+}
+
+struct isl_set *isl_set_remove_empty_parts(struct isl_set *set)
+{
+	return set_from_map(isl_map_remove_empty_parts(set_to_map(set)));
+}
+
+/* Given two basic sets bset1 and bset2, compute the maximal difference
+ * between the values of dimension pos in bset1 and those in bset2
+ * for any common value of the parameters and dimensions preceding pos.
+ */
+static enum isl_lp_result basic_set_maximal_difference_at(
+	__isl_keep isl_basic_set *bset1, __isl_keep isl_basic_set *bset2,
+	int pos, isl_int *opt)
+{
+	isl_basic_map *bmap1;
+	isl_basic_map *bmap2;
+	struct isl_ctx *ctx;
+	struct isl_vec *obj;
+	unsigned total;
+	unsigned nparam;
+	unsigned dim1;
+	enum isl_lp_result res;
+
+	if (!bset1 || !bset2)
+		return isl_lp_error;
+
+	nparam = isl_basic_set_n_param(bset1);
+	dim1 = isl_basic_set_n_dim(bset1);
+
+	bmap1 = isl_basic_map_from_range(isl_basic_set_copy(bset1));
+	bmap2 = isl_basic_map_from_range(isl_basic_set_copy(bset2));
+	bmap1 = isl_basic_map_move_dims(bmap1, isl_dim_in, 0,
+					isl_dim_out, 0, pos);
+	bmap2 = isl_basic_map_move_dims(bmap2, isl_dim_in, 0,
+					isl_dim_out, 0, pos);
+	bmap1 = isl_basic_map_range_product(bmap1, bmap2);
+	if (!bmap1)
+		return isl_lp_error;
+
+	total = isl_basic_map_total_dim(bmap1);
+	ctx = bmap1->ctx;
+	obj = isl_vec_alloc(ctx, 1 + total);
+	if (!obj)
+		goto error;
+	isl_seq_clr(obj->block.data, 1 + total);
+	isl_int_set_si(obj->block.data[1+nparam+pos], 1);
+	isl_int_set_si(obj->block.data[1+nparam+pos+(dim1-pos)], -1);
+	res = isl_basic_map_solve_lp(bmap1, 1, obj->block.data, ctx->one,
+					opt, NULL, NULL);
+	isl_basic_map_free(bmap1);
+	isl_vec_free(obj);
+	return res;
+error:
+	isl_basic_map_free(bmap1);
+	return isl_lp_error;
+}
+
+/* Given two _disjoint_ basic sets bset1 and bset2, check whether
+ * for any common value of the parameters and dimensions preceding pos
+ * in both basic sets, the values of dimension pos in bset1 are
+ * smaller or larger than those in bset2.
+ *
+ * Returns
+ *	 1 if bset1 follows bset2
+ *	-1 if bset1 precedes bset2
+ *	 0 if bset1 and bset2 are incomparable
+ *	-2 if some error occurred.
+ */
+int isl_basic_set_compare_at(struct isl_basic_set *bset1,
+	struct isl_basic_set *bset2, int pos)
+{
+	isl_int opt;
+	enum isl_lp_result res;
+	int cmp;
+
+	isl_int_init(opt);
+
+	res = basic_set_maximal_difference_at(bset1, bset2, pos, &opt);
+
+	if (res == isl_lp_empty)
+		cmp = 0;
+	else if ((res == isl_lp_ok && isl_int_is_pos(opt)) ||
+		  res == isl_lp_unbounded)
+		cmp = 1;
+	else if (res == isl_lp_ok && isl_int_is_neg(opt))
+		cmp = -1;
+	else
+		cmp = -2;
+
+	isl_int_clear(opt);
+	return cmp;
+}
+
+/* Given two basic sets bset1 and bset2, check whether
+ * for any common value of the parameters and dimensions preceding pos
+ * there is a value of dimension pos in bset1 that is larger
+ * than a value of the same dimension in bset2.
+ *
+ * Return
+ *	 1 if there exists such a pair
+ *	 0 if there is no such pair, but there is a pair of equal values
+ *	-1 otherwise
+ *	-2 if some error occurred.
+ */
+int isl_basic_set_follows_at(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2, int pos)
+{
+	isl_int opt;
+	enum isl_lp_result res;
+	int cmp;
+
+	isl_int_init(opt);
+
+	res = basic_set_maximal_difference_at(bset1, bset2, pos, &opt);
+
+	if (res == isl_lp_empty)
+		cmp = -1;
+	else if ((res == isl_lp_ok && isl_int_is_pos(opt)) ||
+		  res == isl_lp_unbounded)
+		cmp = 1;
+	else if (res == isl_lp_ok && isl_int_is_neg(opt))
+		cmp = -1;
+	else if (res == isl_lp_ok)
+		cmp = 0;
+	else
+		cmp = -2;
+
+	isl_int_clear(opt);
+	return cmp;
+}
+
+/* Given two sets set1 and set2, check whether
+ * for any common value of the parameters and dimensions preceding pos
+ * there is a value of dimension pos in set1 that is larger
+ * than a value of the same dimension in set2.
+ *
+ * Return
+ *	 1 if there exists such a pair
+ *	 0 if there is no such pair, but there is a pair of equal values
+ *	-1 otherwise
+ *	-2 if some error occurred.
+ */
+int isl_set_follows_at(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2, int pos)
+{
+	int i, j;
+	int follows = -1;
+
+	if (!set1 || !set2)
+		return -2;
+
+	for (i = 0; i < set1->n; ++i)
+		for (j = 0; j < set2->n; ++j) {
+			int f;
+			f = isl_basic_set_follows_at(set1->p[i], set2->p[j], pos);
+			if (f == 1 || f == -2)
+				return f;
+			if (f > follows)
+				follows = f;
+		}
+
+	return follows;
+}
+
+static isl_bool isl_basic_map_plain_has_fixed_var(
+	__isl_keep isl_basic_map *bmap, unsigned pos, isl_int *val)
+{
+	int i;
+	int d;
+	unsigned total;
+
+	if (!bmap)
+		return isl_bool_error;
+	total = isl_basic_map_total_dim(bmap);
+	for (i = 0, d = total-1; i < bmap->n_eq && d+1 > pos; ++i) {
+		for (; d+1 > pos; --d)
+			if (!isl_int_is_zero(bmap->eq[i][1+d]))
+				break;
+		if (d != pos)
+			continue;
+		if (isl_seq_first_non_zero(bmap->eq[i]+1, d) != -1)
+			return isl_bool_false;
+		if (isl_seq_first_non_zero(bmap->eq[i]+1+d+1, total-d-1) != -1)
+			return isl_bool_false;
+		if (!isl_int_is_one(bmap->eq[i][1+d]))
+			return isl_bool_false;
+		if (val)
+			isl_int_neg(*val, bmap->eq[i][0]);
+		return isl_bool_true;
+	}
+	return isl_bool_false;
+}
+
+static isl_bool isl_map_plain_has_fixed_var(__isl_keep isl_map *map,
+	unsigned pos, isl_int *val)
+{
+	int i;
+	isl_int v;
+	isl_int tmp;
+	isl_bool fixed;
+
+	if (!map)
+		return isl_bool_error;
+	if (map->n == 0)
+		return isl_bool_false;
+	if (map->n == 1)
+		return isl_basic_map_plain_has_fixed_var(map->p[0], pos, val); 
+	isl_int_init(v);
+	isl_int_init(tmp);
+	fixed = isl_basic_map_plain_has_fixed_var(map->p[0], pos, &v); 
+	for (i = 1; fixed == isl_bool_true && i < map->n; ++i) {
+		fixed = isl_basic_map_plain_has_fixed_var(map->p[i], pos, &tmp); 
+		if (fixed == isl_bool_true && isl_int_ne(tmp, v))
+			fixed = isl_bool_false;
+	}
+	if (val)
+		isl_int_set(*val, v);
+	isl_int_clear(tmp);
+	isl_int_clear(v);
+	return fixed;
+}
+
+static isl_bool isl_basic_set_plain_has_fixed_var(
+	__isl_keep isl_basic_set *bset, unsigned pos, isl_int *val)
+{
+	return isl_basic_map_plain_has_fixed_var(bset_to_bmap(bset),
+						pos, val);
+}
+
+isl_bool isl_basic_map_plain_is_fixed(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+	if (isl_basic_map_check_range(bmap, type, pos, 1) < 0)
+		return isl_bool_error;
+	return isl_basic_map_plain_has_fixed_var(bmap,
+		isl_basic_map_offset(bmap, type) - 1 + pos, val);
+}
+
+/* If "bmap" obviously lies on a hyperplane where the given dimension
+ * has a fixed value, then return that value.
+ * Otherwise return NaN.
+ */
+__isl_give isl_val *isl_basic_map_plain_get_val_if_fixed(
+	__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos)
+{
+	isl_ctx *ctx;
+	isl_val *v;
+	isl_bool fixed;
+
+	if (!bmap)
+		return NULL;
+	ctx = isl_basic_map_get_ctx(bmap);
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+	fixed = isl_basic_map_plain_is_fixed(bmap, type, pos, &v->n);
+	if (fixed < 0)
+		return isl_val_free(v);
+	if (fixed) {
+		isl_int_set_si(v->d, 1);
+		return v;
+	}
+	isl_val_free(v);
+	return isl_val_nan(ctx);
+}
+
+isl_bool isl_map_plain_is_fixed(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+	if (pos >= isl_map_dim(map, type))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"position out of bounds", return isl_bool_error);
+	return isl_map_plain_has_fixed_var(map,
+		map_offset(map, type) - 1 + pos, val);
+}
+
+/* If "map" obviously lies on a hyperplane where the given dimension
+ * has a fixed value, then return that value.
+ * Otherwise return NaN.
+ */
+__isl_give isl_val *isl_map_plain_get_val_if_fixed(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	isl_ctx *ctx;
+	isl_val *v;
+	isl_bool fixed;
+
+	if (!map)
+		return NULL;
+	ctx = isl_map_get_ctx(map);
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+	fixed = isl_map_plain_is_fixed(map, type, pos, &v->n);
+	if (fixed < 0)
+		return isl_val_free(v);
+	if (fixed) {
+		isl_int_set_si(v->d, 1);
+		return v;
+	}
+	isl_val_free(v);
+	return isl_val_nan(ctx);
+}
+
+/* If "set" obviously lies on a hyperplane where the given dimension
+ * has a fixed value, then return that value.
+ * Otherwise return NaN.
+ */
+__isl_give isl_val *isl_set_plain_get_val_if_fixed(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_map_plain_get_val_if_fixed(set, type, pos);
+}
+
+isl_bool isl_set_plain_is_fixed(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+	return isl_map_plain_is_fixed(set, type, pos, val);
+}
+
+/* Check if dimension dim has fixed value and if so and if val is not NULL,
+ * then return this fixed value in *val.
+ */
+isl_bool isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset,
+	unsigned dim, isl_int *val)
+{
+	return isl_basic_set_plain_has_fixed_var(bset,
+					isl_basic_set_n_param(bset) + dim, val);
+}
+
+/* Return -1 if the constraint "c1" should be sorted before "c2"
+ * and 1 if it should be sorted after "c2".
+ * Return 0 if the two constraints are the same (up to the constant term).
+ *
+ * In particular, if a constraint involves later variables than another
+ * then it is sorted after this other constraint.
+ * uset_gist depends on constraints without existentially quantified
+ * variables sorting first.
+ *
+ * For constraints that have the same latest variable, those
+ * with the same coefficient for this latest variable (first in absolute value
+ * and then in actual value) are grouped together.
+ * This is useful for detecting pairs of constraints that can
+ * be chained in their printed representation.
+ *
+ * Finally, within a group, constraints are sorted according to
+ * their coefficients (excluding the constant term).
+ */
+static int sort_constraint_cmp(const void *p1, const void *p2, void *arg)
+{
+	isl_int **c1 = (isl_int **) p1;
+	isl_int **c2 = (isl_int **) p2;
+	int l1, l2;
+	unsigned size = *(unsigned *) arg;
+	int cmp;
+
+	l1 = isl_seq_last_non_zero(*c1 + 1, size);
+	l2 = isl_seq_last_non_zero(*c2 + 1, size);
+
+	if (l1 != l2)
+		return l1 - l2;
+
+	cmp = isl_int_abs_cmp((*c1)[1 + l1], (*c2)[1 + l1]);
+	if (cmp != 0)
+		return cmp;
+	cmp = isl_int_cmp((*c1)[1 + l1], (*c2)[1 + l1]);
+	if (cmp != 0)
+		return -cmp;
+
+	return isl_seq_cmp(*c1 + 1, *c2 + 1, size);
+}
+
+/* Return -1 if the constraint "c1" of "bmap" is sorted before "c2"
+ * by isl_basic_map_sort_constraints, 1 if it is sorted after "c2"
+ * and 0 if the two constraints are the same (up to the constant term).
+ */
+int isl_basic_map_constraint_cmp(__isl_keep isl_basic_map *bmap,
+	isl_int *c1, isl_int *c2)
+{
+	unsigned total;
+
+	if (!bmap)
+		return -2;
+	total = isl_basic_map_total_dim(bmap);
+	return sort_constraint_cmp(&c1, &c2, &total);
+}
+
+__isl_give isl_basic_map *isl_basic_map_sort_constraints(
+	__isl_take isl_basic_map *bmap)
+{
+	unsigned total;
+
+	if (!bmap)
+		return NULL;
+	if (bmap->n_ineq == 0)
+		return bmap;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NORMALIZED))
+		return bmap;
+	total = isl_basic_map_total_dim(bmap);
+	if (isl_sort(bmap->ineq, bmap->n_ineq, sizeof(isl_int *),
+		    &sort_constraint_cmp, &total) < 0)
+		return isl_basic_map_free(bmap);
+	return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_sort_constraints(
+	__isl_take isl_basic_set *bset)
+{
+	isl_basic_map *bmap = bset_to_bmap(bset);
+	return bset_from_bmap(isl_basic_map_sort_constraints(bmap));
+}
+
+__isl_give isl_basic_map *isl_basic_map_normalize(
+	__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NORMALIZED))
+		return bmap;
+	bmap = isl_basic_map_remove_redundancies(bmap);
+	bmap = isl_basic_map_sort_constraints(bmap);
+	if (bmap)
+		ISL_F_SET(bmap, ISL_BASIC_MAP_NORMALIZED);
+	return bmap;
+}
+int isl_basic_map_plain_cmp(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	int i, cmp;
+	unsigned total;
+	isl_space *space1, *space2;
+
+	if (!bmap1 || !bmap2)
+		return -1;
+
+	if (bmap1 == bmap2)
+		return 0;
+	space1 = isl_basic_map_peek_space(bmap1);
+	space2 = isl_basic_map_peek_space(bmap2);
+	cmp = isl_space_cmp(space1, space2);
+	if (cmp)
+		return cmp;
+	if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_RATIONAL) !=
+	    ISL_F_ISSET(bmap2, ISL_BASIC_MAP_RATIONAL))
+		return ISL_F_ISSET(bmap1, ISL_BASIC_MAP_RATIONAL) ? -1 : 1;
+	if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_EMPTY) &&
+	    ISL_F_ISSET(bmap2, ISL_BASIC_MAP_EMPTY))
+		return 0;
+	if (ISL_F_ISSET(bmap1, ISL_BASIC_MAP_EMPTY))
+		return 1;
+	if (ISL_F_ISSET(bmap2, ISL_BASIC_MAP_EMPTY))
+		return -1;
+	if (bmap1->n_eq != bmap2->n_eq)
+		return bmap1->n_eq - bmap2->n_eq;
+	if (bmap1->n_ineq != bmap2->n_ineq)
+		return bmap1->n_ineq - bmap2->n_ineq;
+	if (bmap1->n_div != bmap2->n_div)
+		return bmap1->n_div - bmap2->n_div;
+	total = isl_basic_map_total_dim(bmap1);
+	for (i = 0; i < bmap1->n_eq; ++i) {
+		cmp = isl_seq_cmp(bmap1->eq[i], bmap2->eq[i], 1+total);
+		if (cmp)
+			return cmp;
+	}
+	for (i = 0; i < bmap1->n_ineq; ++i) {
+		cmp = isl_seq_cmp(bmap1->ineq[i], bmap2->ineq[i], 1+total);
+		if (cmp)
+			return cmp;
+	}
+	for (i = 0; i < bmap1->n_div; ++i) {
+		cmp = isl_seq_cmp(bmap1->div[i], bmap2->div[i], 1+1+total);
+		if (cmp)
+			return cmp;
+	}
+	return 0;
+}
+
+int isl_basic_set_plain_cmp(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2)
+{
+	return isl_basic_map_plain_cmp(bset1, bset2);
+}
+
+int isl_set_plain_cmp(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	int i, cmp;
+
+	if (set1 == set2)
+		return 0;
+	if (set1->n != set2->n)
+		return set1->n - set2->n;
+
+	for (i = 0; i < set1->n; ++i) {
+		cmp = isl_basic_set_plain_cmp(set1->p[i], set2->p[i]);
+		if (cmp)
+			return cmp;
+	}
+
+	return 0;
+}
+
+isl_bool isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	if (!bmap1 || !bmap2)
+		return isl_bool_error;
+	return isl_basic_map_plain_cmp(bmap1, bmap2) == 0;
+}
+
+isl_bool isl_basic_set_plain_is_equal(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2)
+{
+	return isl_basic_map_plain_is_equal(bset_to_bmap(bset1),
+					    bset_to_bmap(bset2));
+}
+
+static int qsort_bmap_cmp(const void *p1, const void *p2)
+{
+	isl_basic_map *bmap1 = *(isl_basic_map **) p1;
+	isl_basic_map *bmap2 = *(isl_basic_map **) p2;
+
+	return isl_basic_map_plain_cmp(bmap1, bmap2);
+}
+
+/* Sort the basic maps of "map" and remove duplicate basic maps.
+ *
+ * While removing basic maps, we make sure that the basic maps remain
+ * sorted because isl_map_normalize expects the basic maps of the result
+ * to be sorted.
+ */
+static __isl_give isl_map *sort_and_remove_duplicates(__isl_take isl_map *map)
+{
+	int i, j;
+
+	map = isl_map_remove_empty_parts(map);
+	if (!map)
+		return NULL;
+	qsort(map->p, map->n, sizeof(struct isl_basic_map *), qsort_bmap_cmp);
+	for (i = map->n - 1; i >= 1; --i) {
+		if (!isl_basic_map_plain_is_equal(map->p[i - 1], map->p[i]))
+			continue;
+		isl_basic_map_free(map->p[i-1]);
+		for (j = i; j < map->n; ++j)
+			map->p[j - 1] = map->p[j];
+		map->n--;
+	}
+
+	return map;
+}
+
+/* Remove obvious duplicates among the basic maps of "map".
+ *
+ * Unlike isl_map_normalize, this function does not remove redundant
+ * constraints and only removes duplicates that have exactly the same
+ * constraints in the input.  It does sort the constraints and
+ * the basic maps to ease the detection of duplicates.
+ *
+ * If "map" has already been normalized or if the basic maps are
+ * disjoint, then there can be no duplicates.
+ */
+__isl_give isl_map *isl_map_remove_obvious_duplicates(__isl_take isl_map *map)
+{
+	int i;
+	isl_basic_map *bmap;
+
+	if (!map)
+		return NULL;
+	if (map->n <= 1)
+		return map;
+	if (ISL_F_ISSET(map, ISL_MAP_NORMALIZED | ISL_MAP_DISJOINT))
+		return map;
+	for (i = 0; i < map->n; ++i) {
+		bmap = isl_basic_map_copy(map->p[i]);
+		bmap = isl_basic_map_sort_constraints(bmap);
+		if (!bmap)
+			return isl_map_free(map);
+		isl_basic_map_free(map->p[i]);
+		map->p[i] = bmap;
+	}
+
+	map = sort_and_remove_duplicates(map);
+	return map;
+}
+
+/* We normalize in place, but if anything goes wrong we need
+ * to return NULL, so we need to make sure we don't change the
+ * meaning of any possible other copies of map.
+ */
+__isl_give isl_map *isl_map_normalize(__isl_take isl_map *map)
+{
+	int i;
+	struct isl_basic_map *bmap;
+
+	if (!map)
+		return NULL;
+	if (ISL_F_ISSET(map, ISL_MAP_NORMALIZED))
+		return map;
+	for (i = 0; i < map->n; ++i) {
+		bmap = isl_basic_map_normalize(isl_basic_map_copy(map->p[i]));
+		if (!bmap)
+			goto error;
+		isl_basic_map_free(map->p[i]);
+		map->p[i] = bmap;
+	}
+
+	map = sort_and_remove_duplicates(map);
+	if (map)
+		ISL_F_SET(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+struct isl_set *isl_set_normalize(struct isl_set *set)
+{
+	return set_from_map(isl_map_normalize(set_to_map(set)));
+}
+
+isl_bool isl_map_plain_is_equal(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2)
+{
+	int i;
+	isl_bool equal;
+
+	if (!map1 || !map2)
+		return isl_bool_error;
+
+	if (map1 == map2)
+		return isl_bool_true;
+	if (!isl_space_is_equal(map1->dim, map2->dim))
+		return isl_bool_false;
+
+	map1 = isl_map_copy(map1);
+	map2 = isl_map_copy(map2);
+	map1 = isl_map_normalize(map1);
+	map2 = isl_map_normalize(map2);
+	if (!map1 || !map2)
+		goto error;
+	equal = map1->n == map2->n;
+	for (i = 0; equal && i < map1->n; ++i) {
+		equal = isl_basic_map_plain_is_equal(map1->p[i], map2->p[i]);
+		if (equal < 0)
+			goto error;
+	}
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return equal;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return isl_bool_error;
+}
+
+isl_bool isl_set_plain_is_equal(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2)
+{
+	return isl_map_plain_is_equal(set_to_map(set1), set_to_map(set2));
+}
+
+/* Return the basic maps in "map" as a list.
+ */
+__isl_give isl_basic_map_list *isl_map_get_basic_map_list(
+	__isl_keep isl_map *map)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_basic_map_list *list;
+
+	if (!map)
+		return NULL;
+	ctx = isl_map_get_ctx(map);
+	list = isl_basic_map_list_alloc(ctx, map->n);
+
+	for (i = 0; i < map->n; ++i) {
+		isl_basic_map *bmap;
+
+		bmap = isl_basic_map_copy(map->p[i]);
+		list = isl_basic_map_list_add(list, bmap);
+	}
+
+	return list;
+}
+
+/* Return the intersection of the elements in the non-empty list "list".
+ * All elements are assumed to live in the same space.
+ */
+__isl_give isl_basic_map *isl_basic_map_list_intersect(
+	__isl_take isl_basic_map_list *list)
+{
+	int i, n;
+	isl_basic_map *bmap;
+
+	if (!list)
+		return NULL;
+	n = isl_basic_map_list_n_basic_map(list);
+	if (n < 1)
+		isl_die(isl_basic_map_list_get_ctx(list), isl_error_invalid,
+			"expecting non-empty list", goto error);
+
+	bmap = isl_basic_map_list_get_basic_map(list, 0);
+	for (i = 1; i < n; ++i) {
+		isl_basic_map *bmap_i;
+
+		bmap_i = isl_basic_map_list_get_basic_map(list, i);
+		bmap = isl_basic_map_intersect(bmap, bmap_i);
+	}
+
+	isl_basic_map_list_free(list);
+	return bmap;
+error:
+	isl_basic_map_list_free(list);
+	return NULL;
+}
+
+/* Return the intersection of the elements in the non-empty list "list".
+ * All elements are assumed to live in the same space.
+ */
+__isl_give isl_basic_set *isl_basic_set_list_intersect(
+	__isl_take isl_basic_set_list *list)
+{
+	return isl_basic_map_list_intersect(list);
+}
+
+/* Return the union of the elements of "list".
+ * The list is required to have at least one element.
+ */
+__isl_give isl_set *isl_basic_set_list_union(
+	__isl_take isl_basic_set_list *list)
+{
+	int i, n;
+	isl_space *space;
+	isl_basic_set *bset;
+	isl_set *set;
+
+	if (!list)
+		return NULL;
+	n = isl_basic_set_list_n_basic_set(list);
+	if (n < 1)
+		isl_die(isl_basic_set_list_get_ctx(list), isl_error_invalid,
+			"expecting non-empty list", goto error);
+
+	bset = isl_basic_set_list_get_basic_set(list, 0);
+	space = isl_basic_set_get_space(bset);
+	isl_basic_set_free(bset);
+
+	set = isl_set_alloc_space(space, n, 0);
+	for (i = 0; i < n; ++i) {
+		bset = isl_basic_set_list_get_basic_set(list, i);
+		set = isl_set_add_basic_set(set, bset);
+	}
+
+	isl_basic_set_list_free(list);
+	return set;
+error:
+	isl_basic_set_list_free(list);
+	return NULL;
+}
+
+/* Return the union of the elements in the non-empty list "list".
+ * All elements are assumed to live in the same space.
+ */
+__isl_give isl_set *isl_set_list_union(__isl_take isl_set_list *list)
+{
+	int i, n;
+	isl_set *set;
+
+	if (!list)
+		return NULL;
+	n = isl_set_list_n_set(list);
+	if (n < 1)
+		isl_die(isl_set_list_get_ctx(list), isl_error_invalid,
+			"expecting non-empty list", goto error);
+
+	set = isl_set_list_get_set(list, 0);
+	for (i = 1; i < n; ++i) {
+		isl_set *set_i;
+
+		set_i = isl_set_list_get_set(list, i);
+		set = isl_set_union(set, set_i);
+	}
+
+	isl_set_list_free(list);
+	return set;
+error:
+	isl_set_list_free(list);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+	isl_space *dim_result = NULL;
+	struct isl_basic_map *bmap;
+	unsigned in1, in2, out1, out2, nparam, total, pos;
+	struct isl_dim_map *dim_map1, *dim_map2;
+
+	if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0)
+		goto error;
+	dim_result = isl_space_product(isl_space_copy(bmap1->dim),
+						   isl_space_copy(bmap2->dim));
+
+	in1 = isl_basic_map_dim(bmap1, isl_dim_in);
+	in2 = isl_basic_map_dim(bmap2, isl_dim_in);
+	out1 = isl_basic_map_dim(bmap1, isl_dim_out);
+	out2 = isl_basic_map_dim(bmap2, isl_dim_out);
+	nparam = isl_basic_map_dim(bmap1, isl_dim_param);
+
+	total = nparam + in1 + in2 + out1 + out2 + bmap1->n_div + bmap2->n_div;
+	dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+	dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos += in1);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in2);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += out1);
+	isl_dim_map_div(dim_map1, bmap1, pos += out2);
+	isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+
+	bmap = isl_basic_map_alloc_space(dim_result,
+			bmap1->n_div + bmap2->n_div,
+			bmap1->n_eq + bmap2->n_eq,
+			bmap1->n_ineq + bmap2->n_ineq);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flat_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+	isl_basic_map *prod;
+
+	prod = isl_basic_map_product(bmap1, bmap2);
+	prod = isl_basic_map_flatten(prod);
+	return prod;
+}
+
+__isl_give isl_basic_set *isl_basic_set_flat_product(
+	__isl_take isl_basic_set *bset1, __isl_take isl_basic_set *bset2)
+{
+	return isl_basic_map_flat_range_product(bset1, bset2);
+}
+
+__isl_give isl_basic_map *isl_basic_map_domain_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+	isl_space *space_result = NULL;
+	isl_basic_map *bmap;
+	unsigned in1, in2, out, nparam, total, pos;
+	struct isl_dim_map *dim_map1, *dim_map2;
+
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	space_result = isl_space_domain_product(isl_space_copy(bmap1->dim),
+						isl_space_copy(bmap2->dim));
+
+	in1 = isl_basic_map_dim(bmap1, isl_dim_in);
+	in2 = isl_basic_map_dim(bmap2, isl_dim_in);
+	out = isl_basic_map_dim(bmap1, isl_dim_out);
+	nparam = isl_basic_map_dim(bmap1, isl_dim_param);
+
+	total = nparam + in1 + in2 + out + bmap1->n_div + bmap2->n_div;
+	dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+	dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos += in1);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in2);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos);
+	isl_dim_map_div(dim_map1, bmap1, pos += out);
+	isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+
+	bmap = isl_basic_map_alloc_space(space_result,
+			bmap1->n_div + bmap2->n_div,
+			bmap1->n_eq + bmap2->n_eq,
+			bmap1->n_ineq + bmap2->n_ineq);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_range_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+	isl_bool rational;
+	isl_space *dim_result = NULL;
+	isl_basic_map *bmap;
+	unsigned in, out1, out2, nparam, total, pos;
+	struct isl_dim_map *dim_map1, *dim_map2;
+
+	rational = isl_basic_map_is_rational(bmap1);
+	if (rational >= 0 && rational)
+		rational = isl_basic_map_is_rational(bmap2);
+	if (!bmap1 || !bmap2 || rational < 0)
+		goto error;
+
+	if (isl_basic_map_check_equal_params(bmap1, bmap2) < 0)
+		goto error;
+
+	dim_result = isl_space_range_product(isl_space_copy(bmap1->dim),
+					   isl_space_copy(bmap2->dim));
+
+	in = isl_basic_map_dim(bmap1, isl_dim_in);
+	out1 = isl_basic_map_dim(bmap1, isl_dim_out);
+	out2 = isl_basic_map_dim(bmap2, isl_dim_out);
+	nparam = isl_basic_map_dim(bmap1, isl_dim_param);
+
+	total = nparam + in + out1 + out2 + bmap1->n_div + bmap2->n_div;
+	dim_map1 = isl_dim_map_alloc(bmap1->ctx, total);
+	dim_map2 = isl_dim_map_alloc(bmap1->ctx, total);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_param, pos = 0);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_in, pos += nparam);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_in, pos);
+	isl_dim_map_dim(dim_map1, bmap1->dim, isl_dim_out, pos += in);
+	isl_dim_map_dim(dim_map2, bmap2->dim, isl_dim_out, pos += out1);
+	isl_dim_map_div(dim_map1, bmap1, pos += out2);
+	isl_dim_map_div(dim_map2, bmap2, pos += bmap1->n_div);
+
+	bmap = isl_basic_map_alloc_space(dim_result,
+			bmap1->n_div + bmap2->n_div,
+			bmap1->n_eq + bmap2->n_eq,
+			bmap1->n_ineq + bmap2->n_ineq);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap1, dim_map1);
+	bmap = isl_basic_map_add_constraints_dim_map(bmap, bmap2, dim_map2);
+	if (rational)
+		bmap = isl_basic_map_set_rational(bmap);
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flat_range_product(
+	__isl_take isl_basic_map *bmap1, __isl_take isl_basic_map *bmap2)
+{
+	isl_basic_map *prod;
+
+	prod = isl_basic_map_range_product(bmap1, bmap2);
+	prod = isl_basic_map_flatten_range(prod);
+	return prod;
+}
+
+/* Apply "basic_map_product" to each pair of basic maps in "map1" and "map2"
+ * and collect the results.
+ * The result live in the space obtained by calling "space_product"
+ * on the spaces of "map1" and "map2".
+ * If "remove_duplicates" is set then the result may contain duplicates
+ * (even if the inputs do not) and so we try and remove the obvious
+ * duplicates.
+ */
+static __isl_give isl_map *map_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2,
+	__isl_give isl_space *(*space_product)(__isl_take isl_space *left,
+					   __isl_take isl_space *right),
+	__isl_give isl_basic_map *(*basic_map_product)(
+		__isl_take isl_basic_map *left,
+		__isl_take isl_basic_map *right),
+	int remove_duplicates)
+{
+	unsigned flags = 0;
+	struct isl_map *result;
+	int i, j;
+	isl_bool m;
+
+	m = isl_map_has_equal_params(map1, map2);
+	if (m < 0)
+		goto error;
+	if (!m)
+		isl_die(isl_map_get_ctx(map1), isl_error_invalid,
+			"parameters don't match", goto error);
+
+	if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT) &&
+	    ISL_F_ISSET(map2, ISL_MAP_DISJOINT))
+		ISL_FL_SET(flags, ISL_MAP_DISJOINT);
+
+	result = isl_map_alloc_space(space_product(isl_space_copy(map1->dim),
+					       isl_space_copy(map2->dim)),
+				map1->n * map2->n, flags);
+	if (!result)
+		goto error;
+	for (i = 0; i < map1->n; ++i)
+		for (j = 0; j < map2->n; ++j) {
+			struct isl_basic_map *part;
+			part = basic_map_product(isl_basic_map_copy(map1->p[i]),
+						 isl_basic_map_copy(map2->p[j]));
+			if (isl_basic_map_is_empty(part))
+				isl_basic_map_free(part);
+			else
+				result = isl_map_add_basic_map(result, part);
+			if (!result)
+				goto error;
+		}
+	if (remove_duplicates)
+		result = isl_map_remove_obvious_duplicates(result);
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return result;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+/* Given two maps A -> B and C -> D, construct a map [A -> C] -> [B -> D]
+ */
+static __isl_give isl_map *map_product_aligned(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return map_product(map1, map2, &isl_space_product,
+			&isl_basic_map_product, 0);
+}
+
+__isl_give isl_map *isl_map_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_product_aligned);
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B, D)
+ */
+__isl_give isl_map *isl_map_flat_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *prod;
+
+	prod = isl_map_product(map1, map2);
+	prod = isl_map_flatten(prod);
+	return prod;
+}
+
+/* Given two set A and B, construct its Cartesian product A x B.
+ */
+struct isl_set *isl_set_product(struct isl_set *set1, struct isl_set *set2)
+{
+	return isl_map_range_product(set1, set2);
+}
+
+__isl_give isl_set *isl_set_flat_product(__isl_take isl_set *set1,
+	__isl_take isl_set *set2)
+{
+	return isl_map_flat_range_product(set1, set2);
+}
+
+/* Given two maps A -> B and C -> D, construct a map [A -> C] -> (B * D)
+ */
+static __isl_give isl_map *map_domain_product_aligned(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return map_product(map1, map2, &isl_space_domain_product,
+				&isl_basic_map_domain_product, 1);
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A * C) -> [B -> D]
+ */
+static __isl_give isl_map *map_range_product_aligned(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return map_product(map1, map2, &isl_space_range_product,
+				&isl_basic_map_range_product, 1);
+}
+
+__isl_give isl_map *isl_map_domain_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2,
+						&map_domain_product_aligned);
+}
+
+__isl_give isl_map *isl_map_range_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2,
+						&map_range_product_aligned);
+}
+
+/* Given a map of the form [A -> B] -> [C -> D], return the map A -> C.
+ */
+__isl_give isl_map *isl_map_factor_domain(__isl_take isl_map *map)
+{
+	isl_space *space;
+	int total1, keep1, total2, keep2;
+
+	if (!map)
+		return NULL;
+	if (!isl_space_domain_is_wrapping(map->dim) ||
+	    !isl_space_range_is_wrapping(map->dim))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"not a product", return isl_map_free(map));
+
+	space = isl_map_get_space(map);
+	total1 = isl_space_dim(space, isl_dim_in);
+	total2 = isl_space_dim(space, isl_dim_out);
+	space = isl_space_factor_domain(space);
+	keep1 = isl_space_dim(space, isl_dim_in);
+	keep2 = isl_space_dim(space, isl_dim_out);
+	map = isl_map_project_out(map, isl_dim_in, keep1, total1 - keep1);
+	map = isl_map_project_out(map, isl_dim_out, keep2, total2 - keep2);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Given a map of the form [A -> B] -> [C -> D], return the map B -> D.
+ */
+__isl_give isl_map *isl_map_factor_range(__isl_take isl_map *map)
+{
+	isl_space *space;
+	int total1, keep1, total2, keep2;
+
+	if (!map)
+		return NULL;
+	if (!isl_space_domain_is_wrapping(map->dim) ||
+	    !isl_space_range_is_wrapping(map->dim))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"not a product", return isl_map_free(map));
+
+	space = isl_map_get_space(map);
+	total1 = isl_space_dim(space, isl_dim_in);
+	total2 = isl_space_dim(space, isl_dim_out);
+	space = isl_space_factor_range(space);
+	keep1 = isl_space_dim(space, isl_dim_in);
+	keep2 = isl_space_dim(space, isl_dim_out);
+	map = isl_map_project_out(map, isl_dim_in, 0, total1 - keep1);
+	map = isl_map_project_out(map, isl_dim_out, 0, total2 - keep2);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Given a map of the form [A -> B] -> C, return the map A -> C.
+ */
+__isl_give isl_map *isl_map_domain_factor_domain(__isl_take isl_map *map)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!map)
+		return NULL;
+	if (!isl_space_domain_is_wrapping(map->dim))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"domain is not a product", return isl_map_free(map));
+
+	space = isl_map_get_space(map);
+	total = isl_space_dim(space, isl_dim_in);
+	space = isl_space_domain_factor_domain(space);
+	keep = isl_space_dim(space, isl_dim_in);
+	map = isl_map_project_out(map, isl_dim_in, keep, total - keep);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Given a map of the form [A -> B] -> C, return the map B -> C.
+ */
+__isl_give isl_map *isl_map_domain_factor_range(__isl_take isl_map *map)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!map)
+		return NULL;
+	if (!isl_space_domain_is_wrapping(map->dim))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"domain is not a product", return isl_map_free(map));
+
+	space = isl_map_get_space(map);
+	total = isl_space_dim(space, isl_dim_in);
+	space = isl_space_domain_factor_range(space);
+	keep = isl_space_dim(space, isl_dim_in);
+	map = isl_map_project_out(map, isl_dim_in, 0, total - keep);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Given a map A -> [B -> C], extract the map A -> B.
+ */
+__isl_give isl_map *isl_map_range_factor_domain(__isl_take isl_map *map)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!map)
+		return NULL;
+	if (!isl_space_range_is_wrapping(map->dim))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"range is not a product", return isl_map_free(map));
+
+	space = isl_map_get_space(map);
+	total = isl_space_dim(space, isl_dim_out);
+	space = isl_space_range_factor_domain(space);
+	keep = isl_space_dim(space, isl_dim_out);
+	map = isl_map_project_out(map, isl_dim_out, keep, total - keep);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Given a map A -> [B -> C], extract the map A -> C.
+ */
+__isl_give isl_map *isl_map_range_factor_range(__isl_take isl_map *map)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!map)
+		return NULL;
+	if (!isl_space_range_is_wrapping(map->dim))
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"range is not a product", return isl_map_free(map));
+
+	space = isl_map_get_space(map);
+	total = isl_space_dim(space, isl_dim_out);
+	space = isl_space_range_factor_range(space);
+	keep = isl_space_dim(space, isl_dim_out);
+	map = isl_map_project_out(map, isl_dim_out, 0, total - keep);
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B * D)
+ */
+__isl_give isl_map *isl_map_flat_domain_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *prod;
+
+	prod = isl_map_domain_product(map1, map2);
+	prod = isl_map_flatten_domain(prod);
+	return prod;
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A * C) -> (B, D)
+ */
+__isl_give isl_map *isl_map_flat_range_product(__isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_map *prod;
+
+	prod = isl_map_range_product(map1, map2);
+	prod = isl_map_flatten_range(prod);
+	return prod;
+}
+
+uint32_t isl_basic_map_get_hash(__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	uint32_t hash = isl_hash_init();
+	unsigned total;
+
+	if (!bmap)
+		return 0;
+	bmap = isl_basic_map_copy(bmap);
+	bmap = isl_basic_map_normalize(bmap);
+	if (!bmap)
+		return 0;
+	total = isl_basic_map_total_dim(bmap);
+	isl_hash_byte(hash, bmap->n_eq & 0xFF);
+	for (i = 0; i < bmap->n_eq; ++i) {
+		uint32_t c_hash;
+		c_hash = isl_seq_get_hash(bmap->eq[i], 1 + total);
+		isl_hash_hash(hash, c_hash);
+	}
+	isl_hash_byte(hash, bmap->n_ineq & 0xFF);
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		uint32_t c_hash;
+		c_hash = isl_seq_get_hash(bmap->ineq[i], 1 + total);
+		isl_hash_hash(hash, c_hash);
+	}
+	isl_hash_byte(hash, bmap->n_div & 0xFF);
+	for (i = 0; i < bmap->n_div; ++i) {
+		uint32_t c_hash;
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		isl_hash_byte(hash, i & 0xFF);
+		c_hash = isl_seq_get_hash(bmap->div[i], 1 + 1 + total);
+		isl_hash_hash(hash, c_hash);
+	}
+	isl_basic_map_free(bmap);
+	return hash;
+}
+
+uint32_t isl_basic_set_get_hash(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_get_hash(bset_to_bmap(bset));
+}
+
+uint32_t isl_map_get_hash(__isl_keep isl_map *map)
+{
+	int i;
+	uint32_t hash;
+
+	if (!map)
+		return 0;
+	map = isl_map_copy(map);
+	map = isl_map_normalize(map);
+	if (!map)
+		return 0;
+
+	hash = isl_hash_init();
+	for (i = 0; i < map->n; ++i) {
+		uint32_t bmap_hash;
+		bmap_hash = isl_basic_map_get_hash(map->p[i]);
+		isl_hash_hash(hash, bmap_hash);
+	}
+		
+	isl_map_free(map);
+
+	return hash;
+}
+
+uint32_t isl_set_get_hash(__isl_keep isl_set *set)
+{
+	return isl_map_get_hash(set_to_map(set));
+}
+
+/* Return the number of basic maps in the (current) representation of "map".
+ */
+int isl_map_n_basic_map(__isl_keep isl_map *map)
+{
+	return map ? map->n : 0;
+}
+
+int isl_set_n_basic_set(__isl_keep isl_set *set)
+{
+	return set ? set->n : 0;
+}
+
+isl_stat isl_map_foreach_basic_map(__isl_keep isl_map *map,
+	isl_stat (*fn)(__isl_take isl_basic_map *bmap, void *user), void *user)
+{
+	int i;
+
+	if (!map)
+		return isl_stat_error;
+
+	for (i = 0; i < map->n; ++i)
+		if (fn(isl_basic_map_copy(map->p[i]), user) < 0)
+			return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+isl_stat isl_set_foreach_basic_set(__isl_keep isl_set *set,
+	isl_stat (*fn)(__isl_take isl_basic_set *bset, void *user), void *user)
+{
+	int i;
+
+	if (!set)
+		return isl_stat_error;
+
+	for (i = 0; i < set->n; ++i)
+		if (fn(isl_basic_set_copy(set->p[i]), user) < 0)
+			return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Return a list of basic sets, the union of which is equal to "set".
+ */
+__isl_give isl_basic_set_list *isl_set_get_basic_set_list(
+	__isl_keep isl_set *set)
+{
+	int i;
+	isl_basic_set_list *list;
+
+	if (!set)
+		return NULL;
+
+	list = isl_basic_set_list_alloc(isl_set_get_ctx(set), set->n);
+	for (i = 0; i < set->n; ++i) {
+		isl_basic_set *bset;
+
+		bset = isl_basic_set_copy(set->p[i]);
+		list = isl_basic_set_list_add(list, bset);
+	}
+
+	return list;
+}
+
+__isl_give isl_basic_set *isl_basic_set_lift(__isl_take isl_basic_set *bset)
+{
+	isl_space *dim;
+
+	if (!bset)
+		return NULL;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		return NULL;
+
+	dim = isl_basic_set_get_space(bset);
+	dim = isl_space_lift(dim, bset->n_div);
+	if (!dim)
+		goto error;
+	isl_space_free(bset->dim);
+	bset->dim = dim;
+	bset->extra -= bset->n_div;
+	bset->n_div = 0;
+
+	bset = isl_basic_set_finalize(bset);
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_lift(__isl_take isl_set *set)
+{
+	int i;
+	isl_space *dim;
+	unsigned n_div;
+
+	set = set_from_map(isl_map_align_divs_internal(set_to_map(set)));
+
+	if (!set)
+		return NULL;
+
+	set = isl_set_cow(set);
+	if (!set)
+		return NULL;
+
+	n_div = set->p[0]->n_div;
+	dim = isl_set_get_space(set);
+	dim = isl_space_lift(dim, n_div);
+	if (!dim)
+		goto error;
+	isl_space_free(set->dim);
+	set->dim = dim;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_lift(set->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+int isl_basic_set_size(__isl_keep isl_basic_set *bset)
+{
+	unsigned dim;
+	int size = 0;
+
+	if (!bset)
+		return -1;
+
+	dim = isl_basic_set_total_dim(bset);
+	size += bset->n_eq * (1 + dim);
+	size += bset->n_ineq * (1 + dim);
+	size += bset->n_div * (2 + dim);
+
+	return size;
+}
+
+int isl_set_size(__isl_keep isl_set *set)
+{
+	int i;
+	int size = 0;
+
+	if (!set)
+		return -1;
+
+	for (i = 0; i < set->n; ++i)
+		size += isl_basic_set_size(set->p[i]);
+
+	return size;
+}
+
+/* Check if there is any lower bound (if lower == 0) and/or upper
+ * bound (if upper == 0) on the specified dim.
+ */
+static isl_bool basic_map_dim_is_bounded(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, int lower, int upper)
+{
+	int i;
+
+	if (isl_basic_map_check_range(bmap, type, pos, 1) < 0)
+		return isl_bool_error;
+
+	pos += isl_basic_map_offset(bmap, type);
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (!isl_int_is_zero(bmap->div[i][1 + pos]))
+			return isl_bool_true;
+	}
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		if (!isl_int_is_zero(bmap->eq[i][pos]))
+			return isl_bool_true;
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		int sgn = isl_int_sgn(bmap->ineq[i][pos]);
+		if (sgn > 0)
+			lower = 1;
+		if (sgn < 0)
+			upper = 1;
+	}
+
+	return lower && upper;
+}
+
+isl_bool isl_basic_map_dim_is_bounded(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos)
+{
+	return basic_map_dim_is_bounded(bmap, type, pos, 0, 0);
+}
+
+isl_bool isl_basic_map_dim_has_lower_bound(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos)
+{
+	return basic_map_dim_is_bounded(bmap, type, pos, 0, 1);
+}
+
+isl_bool isl_basic_map_dim_has_upper_bound(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos)
+{
+	return basic_map_dim_is_bounded(bmap, type, pos, 1, 0);
+}
+
+isl_bool isl_map_dim_is_bounded(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	int i;
+
+	if (!map)
+		return isl_bool_error;
+
+	for (i = 0; i < map->n; ++i) {
+		isl_bool bounded;
+		bounded = isl_basic_map_dim_is_bounded(map->p[i], type, pos);
+		if (bounded < 0 || !bounded)
+			return bounded;
+	}
+
+	return isl_bool_true;
+}
+
+/* Return true if the specified dim is involved in both an upper bound
+ * and a lower bound.
+ */
+isl_bool isl_set_dim_is_bounded(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_map_dim_is_bounded(set_to_map(set), type, pos);
+}
+
+/* Does "map" have a bound (according to "fn") for any of its basic maps?
+ */
+static isl_bool has_any_bound(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos,
+	isl_bool (*fn)(__isl_keep isl_basic_map *bmap,
+		  enum isl_dim_type type, unsigned pos))
+{
+	int i;
+
+	if (!map)
+		return isl_bool_error;
+
+	for (i = 0; i < map->n; ++i) {
+		isl_bool bounded;
+		bounded = fn(map->p[i], type, pos);
+		if (bounded < 0 || bounded)
+			return bounded;
+	}
+
+	return isl_bool_false;
+}
+
+/* Return 1 if the specified dim is involved in any lower bound.
+ */
+isl_bool isl_set_dim_has_any_lower_bound(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return has_any_bound(set, type, pos,
+				&isl_basic_map_dim_has_lower_bound);
+}
+
+/* Return 1 if the specified dim is involved in any upper bound.
+ */
+isl_bool isl_set_dim_has_any_upper_bound(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return has_any_bound(set, type, pos,
+				&isl_basic_map_dim_has_upper_bound);
+}
+
+/* Does "map" have a bound (according to "fn") for all of its basic maps?
+ */
+static isl_bool has_bound(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos,
+	isl_bool (*fn)(__isl_keep isl_basic_map *bmap,
+		  enum isl_dim_type type, unsigned pos))
+{
+	int i;
+
+	if (!map)
+		return isl_bool_error;
+
+	for (i = 0; i < map->n; ++i) {
+		isl_bool bounded;
+		bounded = fn(map->p[i], type, pos);
+		if (bounded < 0 || !bounded)
+			return bounded;
+	}
+
+	return isl_bool_true;
+}
+
+/* Return 1 if the specified dim has a lower bound (in each of its basic sets).
+ */
+isl_bool isl_set_dim_has_lower_bound(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return has_bound(set, type, pos, &isl_basic_map_dim_has_lower_bound);
+}
+
+/* Return 1 if the specified dim has an upper bound (in each of its basic sets).
+ */
+isl_bool isl_set_dim_has_upper_bound(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return has_bound(set, type, pos, &isl_basic_map_dim_has_upper_bound);
+}
+
+/* For each of the "n" variables starting at "first", determine
+ * the sign of the variable and put the results in the first "n"
+ * elements of the array "signs".
+ * Sign
+ *	1 means that the variable is non-negative
+ *	-1 means that the variable is non-positive
+ *	0 means the variable attains both positive and negative values.
+ */
+isl_stat isl_basic_set_vars_get_sign(__isl_keep isl_basic_set *bset,
+	unsigned first, unsigned n, int *signs)
+{
+	isl_vec *bound = NULL;
+	struct isl_tab *tab = NULL;
+	struct isl_tab_undo *snap;
+	int i;
+
+	if (!bset || !signs)
+		return isl_stat_error;
+
+	bound = isl_vec_alloc(bset->ctx, 1 + isl_basic_set_total_dim(bset));
+	tab = isl_tab_from_basic_set(bset, 0);
+	if (!bound || !tab)
+		goto error;
+
+	isl_seq_clr(bound->el, bound->size);
+	isl_int_set_si(bound->el[0], -1);
+
+	snap = isl_tab_snap(tab);
+	for (i = 0; i < n; ++i) {
+		int empty;
+
+		isl_int_set_si(bound->el[1 + first + i], -1);
+		if (isl_tab_add_ineq(tab, bound->el) < 0)
+			goto error;
+		empty = tab->empty;
+		isl_int_set_si(bound->el[1 + first + i], 0);
+		if (isl_tab_rollback(tab, snap) < 0)
+			goto error;
+
+		if (empty) {
+			signs[i] = 1;
+			continue;
+		}
+
+		isl_int_set_si(bound->el[1 + first + i], 1);
+		if (isl_tab_add_ineq(tab, bound->el) < 0)
+			goto error;
+		empty = tab->empty;
+		isl_int_set_si(bound->el[1 + first + i], 0);
+		if (isl_tab_rollback(tab, snap) < 0)
+			goto error;
+
+		signs[i] = empty ? -1 : 0;
+	}
+
+	isl_tab_free(tab);
+	isl_vec_free(bound);
+	return isl_stat_ok;
+error:
+	isl_tab_free(tab);
+	isl_vec_free(bound);
+	return isl_stat_error;
+}
+
+isl_stat isl_basic_set_dims_get_sign(__isl_keep isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n, int *signs)
+{
+	if (!bset || !signs)
+		return isl_stat_error;
+	isl_assert(bset->ctx, first + n <= isl_basic_set_dim(bset, type),
+		return isl_stat_error);
+
+	first += pos(bset->dim, type) - 1;
+	return isl_basic_set_vars_get_sign(bset, first, n, signs);
+}
+
+/* Is it possible for the integer division "div" to depend (possibly
+ * indirectly) on any output dimensions?
+ *
+ * If the div is undefined, then we conservatively assume that it
+ * may depend on them.
+ * Otherwise, we check if it actually depends on them or on any integer
+ * divisions that may depend on them.
+ */
+static isl_bool div_may_involve_output(__isl_keep isl_basic_map *bmap, int div)
+{
+	int i;
+	unsigned n_out, o_out;
+	unsigned n_div, o_div;
+
+	if (isl_int_is_zero(bmap->div[div][0]))
+		return isl_bool_true;
+
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	o_out = isl_basic_map_offset(bmap, isl_dim_out);
+
+	if (isl_seq_first_non_zero(bmap->div[div] + 1 + o_out, n_out) != -1)
+		return isl_bool_true;
+
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	o_div = isl_basic_map_offset(bmap, isl_dim_div);
+
+	for (i = 0; i < n_div; ++i) {
+		isl_bool may_involve;
+
+		if (isl_int_is_zero(bmap->div[div][1 + o_div + i]))
+			continue;
+		may_involve = div_may_involve_output(bmap, i);
+		if (may_involve < 0 || may_involve)
+			return may_involve;
+	}
+
+	return isl_bool_false;
+}
+
+/* Return the first integer division of "bmap" in the range
+ * [first, first + n[ that may depend on any output dimensions and
+ * that has a non-zero coefficient in "c" (where the first coefficient
+ * in "c" corresponds to integer division "first").
+ */
+static int first_div_may_involve_output(__isl_keep isl_basic_map *bmap,
+	isl_int *c, int first, int n)
+{
+	int k;
+
+	if (!bmap)
+		return -1;
+
+	for (k = first; k < first + n; ++k) {
+		isl_bool may_involve;
+
+		if (isl_int_is_zero(c[k]))
+			continue;
+		may_involve = div_may_involve_output(bmap, k);
+		if (may_involve < 0)
+			return -1;
+		if (may_involve)
+			return k;
+	}
+
+	return first + n;
+}
+
+/* Look for a pair of inequality constraints in "bmap" of the form
+ *
+ *	-l + i >= 0		or		i >= l
+ * and
+ *	n + l - i >= 0		or		i <= l + n
+ *
+ * with n < "m" and i the output dimension at position "pos".
+ * (Note that n >= 0 as otherwise the two constraints would conflict.)
+ * Furthermore, "l" is only allowed to involve parameters, input dimensions
+ * and earlier output dimensions, as well as integer divisions that do
+ * not involve any of the output dimensions.
+ *
+ * Return the index of the first inequality constraint or bmap->n_ineq
+ * if no such pair can be found.
+ */
+static int find_modulo_constraint_pair(__isl_keep isl_basic_map *bmap,
+	int pos, isl_int m)
+{
+	int i, j;
+	isl_ctx *ctx;
+	unsigned total;
+	unsigned n_div, o_div;
+	unsigned n_out, o_out;
+	int less;
+
+	if (!bmap)
+		return -1;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	total = isl_basic_map_total_dim(bmap);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	o_out = isl_basic_map_offset(bmap, isl_dim_out);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	o_div = isl_basic_map_offset(bmap, isl_dim_div);
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		if (!isl_int_abs_eq(bmap->ineq[i][o_out + pos], ctx->one))
+			continue;
+		if (isl_seq_first_non_zero(bmap->ineq[i] + o_out + pos + 1,
+					n_out - (pos + 1)) != -1)
+			continue;
+		if (first_div_may_involve_output(bmap, bmap->ineq[i] + o_div,
+						0, n_div) < n_div)
+			continue;
+		for (j = i + 1; j < bmap->n_ineq; ++j) {
+			if (!isl_int_abs_eq(bmap->ineq[j][o_out + pos],
+					    ctx->one))
+				continue;
+			if (!isl_seq_is_neg(bmap->ineq[i] + 1,
+					    bmap->ineq[j] + 1, total))
+				continue;
+			break;
+		}
+		if (j >= bmap->n_ineq)
+			continue;
+		isl_int_add(bmap->ineq[i][0],
+			    bmap->ineq[i][0], bmap->ineq[j][0]);
+		less = isl_int_abs_lt(bmap->ineq[i][0], m);
+		isl_int_sub(bmap->ineq[i][0],
+			    bmap->ineq[i][0], bmap->ineq[j][0]);
+		if (!less)
+			continue;
+		if (isl_int_is_one(bmap->ineq[i][o_out + pos]))
+			return i;
+		else
+			return j;
+	}
+
+	return bmap->n_ineq;
+}
+
+/* Return the index of the equality of "bmap" that defines
+ * the output dimension "pos" in terms of earlier dimensions.
+ * The equality may also involve integer divisions, as long
+ * as those integer divisions are defined in terms of
+ * parameters or input dimensions.
+ * In this case, *div is set to the number of integer divisions and
+ * *ineq is set to the number of inequality constraints (provided
+ * div and ineq are not NULL).
+ *
+ * The equality may also involve a single integer division involving
+ * the output dimensions (typically only output dimension "pos") as
+ * long as the coefficient of output dimension "pos" is 1 or -1 and
+ * there is a pair of constraints i >= l and i <= l + n, with i referring
+ * to output dimension "pos", l an expression involving only earlier
+ * dimensions and n smaller than the coefficient of the integer division
+ * in the equality.  In this case, the output dimension can be defined
+ * in terms of a modulo expression that does not involve the integer division.
+ * *div is then set to this single integer division and
+ * *ineq is set to the index of constraint i >= l.
+ *
+ * Return bmap->n_eq if there is no such equality.
+ * Return -1 on error.
+ */
+int isl_basic_map_output_defining_equality(__isl_keep isl_basic_map *bmap,
+	int pos, int *div, int *ineq)
+{
+	int j, k, l;
+	unsigned n_out, o_out;
+	unsigned n_div, o_div;
+
+	if (!bmap)
+		return -1;
+
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	o_out = isl_basic_map_offset(bmap, isl_dim_out);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	o_div = isl_basic_map_offset(bmap, isl_dim_div);
+
+	if (ineq)
+		*ineq = bmap->n_ineq;
+	if (div)
+		*div = n_div;
+	for (j = 0; j < bmap->n_eq; ++j) {
+		if (isl_int_is_zero(bmap->eq[j][o_out + pos]))
+			continue;
+		if (isl_seq_first_non_zero(bmap->eq[j] + o_out + pos + 1,
+					n_out - (pos + 1)) != -1)
+			continue;
+		k = first_div_may_involve_output(bmap, bmap->eq[j] + o_div,
+						0, n_div);
+		if (k >= n_div)
+			return j;
+		if (!isl_int_is_one(bmap->eq[j][o_out + pos]) &&
+		    !isl_int_is_negone(bmap->eq[j][o_out + pos]))
+			continue;
+		if (first_div_may_involve_output(bmap, bmap->eq[j] + o_div,
+						k + 1, n_div - (k+1)) < n_div)
+			continue;
+		l = find_modulo_constraint_pair(bmap, pos,
+						bmap->eq[j][o_div + k]);
+		if (l < 0)
+			return -1;
+		if (l >= bmap->n_ineq)
+			continue;
+		if (div)
+			*div = k;
+		if (ineq)
+			*ineq = l;
+		return j;
+	}
+
+	return bmap->n_eq;
+}
+
+/* Check if the given basic map is obviously single-valued.
+ * In particular, for each output dimension, check that there is
+ * an equality that defines the output dimension in terms of
+ * earlier dimensions.
+ */
+isl_bool isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	unsigned n_out;
+
+	if (!bmap)
+		return isl_bool_error;
+
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+
+	for (i = 0; i < n_out; ++i) {
+		int eq;
+
+		eq = isl_basic_map_output_defining_equality(bmap, i,
+							    NULL, NULL);
+		if (eq < 0)
+			return isl_bool_error;
+		if (eq >= bmap->n_eq)
+			return isl_bool_false;
+	}
+
+	return isl_bool_true;
+}
+
+/* Check if the given basic map is single-valued.
+ * We simply compute
+ *
+ *	M \circ M^-1
+ *
+ * and check if the result is a subset of the identity mapping.
+ */
+isl_bool isl_basic_map_is_single_valued(__isl_keep isl_basic_map *bmap)
+{
+	isl_space *space;
+	isl_basic_map *test;
+	isl_basic_map *id;
+	isl_bool sv;
+
+	sv = isl_basic_map_plain_is_single_valued(bmap);
+	if (sv < 0 || sv)
+		return sv;
+
+	test = isl_basic_map_reverse(isl_basic_map_copy(bmap));
+	test = isl_basic_map_apply_range(test, isl_basic_map_copy(bmap));
+
+	space = isl_basic_map_get_space(bmap);
+	space = isl_space_map_from_set(isl_space_range(space));
+	id = isl_basic_map_identity(space);
+
+	sv = isl_basic_map_is_subset(test, id);
+
+	isl_basic_map_free(test);
+	isl_basic_map_free(id);
+
+	return sv;
+}
+
+/* Check if the given map is obviously single-valued.
+ */
+isl_bool isl_map_plain_is_single_valued(__isl_keep isl_map *map)
+{
+	if (!map)
+		return isl_bool_error;
+	if (map->n == 0)
+		return isl_bool_true;
+	if (map->n >= 2)
+		return isl_bool_false;
+
+	return isl_basic_map_plain_is_single_valued(map->p[0]);
+}
+
+/* Check if the given map is single-valued.
+ * We simply compute
+ *
+ *	M \circ M^-1
+ *
+ * and check if the result is a subset of the identity mapping.
+ */
+isl_bool isl_map_is_single_valued(__isl_keep isl_map *map)
+{
+	isl_space *dim;
+	isl_map *test;
+	isl_map *id;
+	isl_bool sv;
+
+	sv = isl_map_plain_is_single_valued(map);
+	if (sv < 0 || sv)
+		return sv;
+
+	test = isl_map_reverse(isl_map_copy(map));
+	test = isl_map_apply_range(test, isl_map_copy(map));
+
+	dim = isl_space_map_from_set(isl_space_range(isl_map_get_space(map)));
+	id = isl_map_identity(dim);
+
+	sv = isl_map_is_subset(test, id);
+
+	isl_map_free(test);
+	isl_map_free(id);
+
+	return sv;
+}
+
+isl_bool isl_map_is_injective(__isl_keep isl_map *map)
+{
+	isl_bool in;
+
+	map = isl_map_copy(map);
+	map = isl_map_reverse(map);
+	in = isl_map_is_single_valued(map);
+	isl_map_free(map);
+
+	return in;
+}
+
+/* Check if the given map is obviously injective.
+ */
+isl_bool isl_map_plain_is_injective(__isl_keep isl_map *map)
+{
+	isl_bool in;
+
+	map = isl_map_copy(map);
+	map = isl_map_reverse(map);
+	in = isl_map_plain_is_single_valued(map);
+	isl_map_free(map);
+
+	return in;
+}
+
+isl_bool isl_map_is_bijective(__isl_keep isl_map *map)
+{
+	isl_bool sv;
+
+	sv = isl_map_is_single_valued(map);
+	if (sv < 0 || !sv)
+		return sv;
+
+	return isl_map_is_injective(map);
+}
+
+isl_bool isl_set_is_singleton(__isl_keep isl_set *set)
+{
+	return isl_map_is_single_valued(set_to_map(set));
+}
+
+/* Does "map" only map elements to themselves?
+ *
+ * If the domain and range spaces are different, then "map"
+ * is considered not to be an identity relation, even if it is empty.
+ * Otherwise, construct the maximal identity relation and
+ * check whether "map" is a subset of this relation.
+ */
+isl_bool isl_map_is_identity(__isl_keep isl_map *map)
+{
+	isl_space *space;
+	isl_map *id;
+	isl_bool equal, is_identity;
+
+	space = isl_map_get_space(map);
+	equal = isl_space_tuple_is_equal(space, isl_dim_in, space, isl_dim_out);
+	isl_space_free(space);
+	if (equal < 0 || !equal)
+		return equal;
+
+	id = isl_map_identity(isl_map_get_space(map));
+	is_identity = isl_map_is_subset(map, id);
+	isl_map_free(id);
+
+	return is_identity;
+}
+
+int isl_map_is_translation(__isl_keep isl_map *map)
+{
+	int ok;
+	isl_set *delta;
+
+	delta = isl_map_deltas(isl_map_copy(map));
+	ok = isl_set_is_singleton(delta);
+	isl_set_free(delta);
+
+	return ok;
+}
+
+static int unique(isl_int *p, unsigned pos, unsigned len)
+{
+	if (isl_seq_first_non_zero(p, pos) != -1)
+		return 0;
+	if (isl_seq_first_non_zero(p + pos + 1, len - pos - 1) != -1)
+		return 0;
+	return 1;
+}
+
+isl_bool isl_basic_set_is_box(__isl_keep isl_basic_set *bset)
+{
+	int i, j;
+	unsigned nvar;
+	unsigned ovar;
+
+	if (!bset)
+		return isl_bool_error;
+
+	if (isl_basic_set_dim(bset, isl_dim_div) != 0)
+		return isl_bool_false;
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+	ovar = isl_space_offset(bset->dim, isl_dim_set);
+	for (j = 0; j < nvar; ++j) {
+		int lower = 0, upper = 0;
+		for (i = 0; i < bset->n_eq; ++i) {
+			if (isl_int_is_zero(bset->eq[i][1 + ovar + j]))
+				continue;
+			if (!unique(bset->eq[i] + 1 + ovar, j, nvar))
+				return isl_bool_false;
+			break;
+		}
+		if (i < bset->n_eq)
+			continue;
+		for (i = 0; i < bset->n_ineq; ++i) {
+			if (isl_int_is_zero(bset->ineq[i][1 + ovar + j]))
+				continue;
+			if (!unique(bset->ineq[i] + 1 + ovar, j, nvar))
+				return isl_bool_false;
+			if (isl_int_is_pos(bset->ineq[i][1 + ovar + j]))
+				lower = 1;
+			else
+				upper = 1;
+		}
+		if (!lower || !upper)
+			return isl_bool_false;
+	}
+
+	return isl_bool_true;
+}
+
+isl_bool isl_set_is_box(__isl_keep isl_set *set)
+{
+	if (!set)
+		return isl_bool_error;
+	if (set->n != 1)
+		return isl_bool_false;
+
+	return isl_basic_set_is_box(set->p[0]);
+}
+
+isl_bool isl_basic_set_is_wrapping(__isl_keep isl_basic_set *bset)
+{
+	if (!bset)
+		return isl_bool_error;
+	
+	return isl_space_is_wrapping(bset->dim);
+}
+
+isl_bool isl_set_is_wrapping(__isl_keep isl_set *set)
+{
+	if (!set)
+		return isl_bool_error;
+	
+	return isl_space_is_wrapping(set->dim);
+}
+
+/* Modify the space of "map" through a call to "change".
+ * If "can_change" is set (not NULL), then first call it to check
+ * if the modification is allowed, printing the error message "cannot_change"
+ * if it is not.
+ */
+static __isl_give isl_map *isl_map_change_space(__isl_take isl_map *map,
+	isl_bool (*can_change)(__isl_keep isl_map *map),
+	const char *cannot_change,
+	__isl_give isl_space *(*change)(__isl_take isl_space *space))
+{
+	isl_bool ok;
+	isl_space *space;
+
+	if (!map)
+		return NULL;
+
+	ok = can_change ? can_change(map) : isl_bool_true;
+	if (ok < 0)
+		return isl_map_free(map);
+	if (!ok)
+		isl_die(isl_map_get_ctx(map), isl_error_invalid, cannot_change,
+			return isl_map_free(map));
+
+	space = change(isl_map_get_space(map));
+	map = isl_map_reset_space(map, space);
+
+	return map;
+}
+
+/* Is the domain of "map" a wrapped relation?
+ */
+isl_bool isl_map_domain_is_wrapping(__isl_keep isl_map *map)
+{
+	if (!map)
+		return isl_bool_error;
+
+	return isl_space_domain_is_wrapping(map->dim);
+}
+
+/* Does "map" have a wrapped relation in both domain and range?
+ */
+isl_bool isl_map_is_product(__isl_keep isl_map *map)
+{
+	return isl_space_is_product(isl_map_peek_space(map));
+}
+
+/* Is the range of "map" a wrapped relation?
+ */
+isl_bool isl_map_range_is_wrapping(__isl_keep isl_map *map)
+{
+	if (!map)
+		return isl_bool_error;
+
+	return isl_space_range_is_wrapping(map->dim);
+}
+
+__isl_give isl_basic_set *isl_basic_map_wrap(__isl_take isl_basic_map *bmap)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	bmap->dim = isl_space_wrap(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bset_from_bmap(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Given a map A -> B, return the set (A -> B).
+ */
+__isl_give isl_set *isl_map_wrap(__isl_take isl_map *map)
+{
+	return isl_map_change_space(map, NULL, NULL, &isl_space_wrap);
+}
+
+__isl_give isl_basic_map *isl_basic_set_unwrap(__isl_take isl_basic_set *bset)
+{
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		return NULL;
+
+	bset->dim = isl_space_unwrap(bset->dim);
+	if (!bset->dim)
+		goto error;
+
+	bset = isl_basic_set_finalize(bset);
+
+	return bset_to_bmap(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Given a set (A -> B), return the map A -> B.
+ * Error out if "set" is not of the form (A -> B).
+ */
+__isl_give isl_map *isl_set_unwrap(__isl_take isl_set *set)
+{
+	return isl_map_change_space(set, &isl_set_is_wrapping,
+				    "not a wrapping set", &isl_space_unwrap);
+}
+
+__isl_give isl_basic_map *isl_basic_map_reset(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type)
+{
+	if (!bmap)
+		return NULL;
+
+	if (!isl_space_is_named_or_nested(bmap->dim, type))
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	bmap->dim = isl_space_reset(bmap->dim, type);
+	if (!bmap->dim)
+		goto error;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_reset(__isl_take isl_map *map,
+	enum isl_dim_type type)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!isl_space_is_named_or_nested(map->dim, type))
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_reset(map->p[i], type);
+		if (!map->p[i])
+			goto error;
+	}
+	map->dim = isl_space_reset(map->dim, type);
+	if (!map->dim)
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flatten(__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (!bmap->dim->nested[0] && !bmap->dim->nested[1])
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	bmap->dim = isl_space_flatten(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_flatten(__isl_take isl_basic_set *bset)
+{
+	return bset_from_bmap(isl_basic_map_flatten(bset_to_bmap(bset)));
+}
+
+__isl_give isl_basic_map *isl_basic_map_flatten_domain(
+	__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (!bmap->dim->nested[0])
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	bmap->dim = isl_space_flatten_domain(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_flatten_range(
+	__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+
+	if (!bmap->dim->nested[1])
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+
+	bmap->dim = isl_space_flatten_range(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Remove any internal structure from the spaces of domain and range of "map".
+ */
+__isl_give isl_map *isl_map_flatten(__isl_take isl_map *map)
+{
+	if (!map)
+		return NULL;
+
+	if (!map->dim->nested[0] && !map->dim->nested[1])
+		return map;
+
+	return isl_map_change_space(map, NULL, NULL, &isl_space_flatten);
+}
+
+__isl_give isl_set *isl_set_flatten(__isl_take isl_set *set)
+{
+	return set_from_map(isl_map_flatten(set_to_map(set)));
+}
+
+__isl_give isl_map *isl_set_flatten_map(__isl_take isl_set *set)
+{
+	isl_space *dim, *flat_dim;
+	isl_map *map;
+
+	dim = isl_set_get_space(set);
+	flat_dim = isl_space_flatten(isl_space_copy(dim));
+	map = isl_map_identity(isl_space_join(isl_space_reverse(dim), flat_dim));
+	map = isl_map_intersect_domain(map, set);
+
+	return map;
+}
+
+/* Remove any internal structure from the space of the domain of "map".
+ */
+__isl_give isl_map *isl_map_flatten_domain(__isl_take isl_map *map)
+{
+	if (!map)
+		return NULL;
+
+	if (!map->dim->nested[0])
+		return map;
+
+	return isl_map_change_space(map, NULL, NULL, &isl_space_flatten_domain);
+}
+
+/* Remove any internal structure from the space of the range of "map".
+ */
+__isl_give isl_map *isl_map_flatten_range(__isl_take isl_map *map)
+{
+	if (!map)
+		return NULL;
+
+	if (!map->dim->nested[1])
+		return map;
+
+	return isl_map_change_space(map, NULL, NULL, &isl_space_flatten_range);
+}
+
+/* Reorder the dimensions of "bmap" according to the given dim_map
+ * and set the dimension specification to "dim" and
+ * perform Gaussian elimination on the result.
+ */
+__isl_give isl_basic_map *isl_basic_map_realign(__isl_take isl_basic_map *bmap,
+	__isl_take isl_space *dim, __isl_take struct isl_dim_map *dim_map)
+{
+	isl_basic_map *res;
+	unsigned flags;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap || !dim || !dim_map)
+		goto error;
+
+	flags = bmap->flags;
+	ISL_FL_CLR(flags, ISL_BASIC_MAP_FINAL);
+	ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED);
+	ISL_FL_CLR(flags, ISL_BASIC_MAP_NORMALIZED_DIVS);
+	res = isl_basic_map_alloc_space(dim,
+			bmap->n_div, bmap->n_eq, bmap->n_ineq);
+	res = isl_basic_map_add_constraints_dim_map(res, bmap, dim_map);
+	if (res)
+		res->flags = flags;
+	res = isl_basic_map_gauss(res, NULL);
+	res = isl_basic_map_finalize(res);
+	return res;
+error:
+	free(dim_map);
+	isl_basic_map_free(bmap);
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Reorder the dimensions of "map" according to given reordering.
+ */
+__isl_give isl_map *isl_map_realign(__isl_take isl_map *map,
+	__isl_take isl_reordering *r)
+{
+	int i;
+	struct isl_dim_map *dim_map;
+
+	map = isl_map_cow(map);
+	dim_map = isl_dim_map_from_reordering(r);
+	if (!map || !r || !dim_map)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		struct isl_dim_map *dim_map_i;
+
+		dim_map_i = isl_dim_map_extend(dim_map, map->p[i]);
+
+		map->p[i] = isl_basic_map_realign(map->p[i],
+					    isl_space_copy(r->dim), dim_map_i);
+
+		if (!map->p[i])
+			goto error;
+	}
+
+	map = isl_map_reset_space(map, isl_space_copy(r->dim));
+
+	isl_reordering_free(r);
+	free(dim_map);
+	return map;
+error:
+	free(dim_map);
+	isl_map_free(map);
+	isl_reordering_free(r);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_realign(__isl_take isl_set *set,
+	__isl_take isl_reordering *r)
+{
+	return set_from_map(isl_map_realign(set_to_map(set), r));
+}
+
+__isl_give isl_map *isl_map_align_params(__isl_take isl_map *map,
+	__isl_take isl_space *model)
+{
+	isl_ctx *ctx;
+	isl_bool aligned;
+
+	if (!map || !model)
+		goto error;
+
+	ctx = isl_space_get_ctx(model);
+	if (!isl_space_has_named_params(model))
+		isl_die(ctx, isl_error_invalid,
+			"model has unnamed parameters", goto error);
+	if (isl_map_check_named_params(map) < 0)
+		goto error;
+	aligned = isl_map_space_has_equal_params(map, model);
+	if (aligned < 0)
+		goto error;
+	if (!aligned) {
+		isl_reordering *exp;
+
+		model = isl_space_drop_dims(model, isl_dim_in,
+					0, isl_space_dim(model, isl_dim_in));
+		model = isl_space_drop_dims(model, isl_dim_out,
+					0, isl_space_dim(model, isl_dim_out));
+		exp = isl_parameter_alignment_reordering(map->dim, model);
+		exp = isl_reordering_extend_space(exp, isl_map_get_space(map));
+		map = isl_map_realign(map, exp);
+	}
+
+	isl_space_free(model);
+	return map;
+error:
+	isl_space_free(model);
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_align_params(__isl_take isl_set *set,
+	__isl_take isl_space *model)
+{
+	return isl_map_align_params(set, model);
+}
+
+/* Align the parameters of "bmap" to those of "model", introducing
+ * additional parameters if needed.
+ */
+__isl_give isl_basic_map *isl_basic_map_align_params(
+	__isl_take isl_basic_map *bmap, __isl_take isl_space *model)
+{
+	isl_ctx *ctx;
+	isl_bool equal_params;
+
+	if (!bmap || !model)
+		goto error;
+
+	ctx = isl_space_get_ctx(model);
+	if (!isl_space_has_named_params(model))
+		isl_die(ctx, isl_error_invalid,
+			"model has unnamed parameters", goto error);
+	if (!isl_space_has_named_params(bmap->dim))
+		isl_die(ctx, isl_error_invalid,
+			"relation has unnamed parameters", goto error);
+	equal_params = isl_space_has_equal_params(bmap->dim, model);
+	if (equal_params < 0)
+		goto error;
+	if (!equal_params) {
+		isl_reordering *exp;
+		struct isl_dim_map *dim_map;
+
+		model = isl_space_drop_dims(model, isl_dim_in,
+					0, isl_space_dim(model, isl_dim_in));
+		model = isl_space_drop_dims(model, isl_dim_out,
+					0, isl_space_dim(model, isl_dim_out));
+		exp = isl_parameter_alignment_reordering(bmap->dim, model);
+		exp = isl_reordering_extend_space(exp,
+					isl_basic_map_get_space(bmap));
+		dim_map = isl_dim_map_from_reordering(exp);
+		bmap = isl_basic_map_realign(bmap,
+				    exp ? isl_space_copy(exp->dim) : NULL,
+				    isl_dim_map_extend(dim_map, bmap));
+		isl_reordering_free(exp);
+		free(dim_map);
+	}
+
+	isl_space_free(model);
+	return bmap;
+error:
+	isl_space_free(model);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Do "bset" and "space" have the same parameters?
+ */
+isl_bool isl_basic_set_space_has_equal_params(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_space *space)
+{
+	isl_space *bset_space;
+
+	bset_space = isl_basic_set_peek_space(bset);
+	return isl_space_has_equal_params(bset_space, space);
+}
+
+/* Do "map" and "space" have the same parameters?
+ */
+isl_bool isl_map_space_has_equal_params(__isl_keep isl_map *map,
+	__isl_keep isl_space *space)
+{
+	isl_space *map_space;
+
+	map_space = isl_map_peek_space(map);
+	return isl_space_has_equal_params(map_space, space);
+}
+
+/* Do "set" and "space" have the same parameters?
+ */
+isl_bool isl_set_space_has_equal_params(__isl_keep isl_set *set,
+	__isl_keep isl_space *space)
+{
+	return isl_map_space_has_equal_params(set_to_map(set), space);
+}
+
+/* Align the parameters of "bset" to those of "model", introducing
+ * additional parameters if needed.
+ */
+__isl_give isl_basic_set *isl_basic_set_align_params(
+	__isl_take isl_basic_set *bset, __isl_take isl_space *model)
+{
+	return isl_basic_map_align_params(bset, model);
+}
+
+__isl_give isl_mat *isl_basic_map_equalities_matrix(
+		__isl_keep isl_basic_map *bmap, enum isl_dim_type c1,
+		enum isl_dim_type c2, enum isl_dim_type c3,
+		enum isl_dim_type c4, enum isl_dim_type c5)
+{
+	enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 };
+	struct isl_mat *mat;
+	int i, j, k;
+	int pos;
+
+	if (!bmap)
+		return NULL;
+	mat = isl_mat_alloc(bmap->ctx, bmap->n_eq,
+				isl_basic_map_total_dim(bmap) + 1);
+	if (!mat)
+		return NULL;
+	for (i = 0; i < bmap->n_eq; ++i)
+		for (j = 0, pos = 0; j < 5; ++j) {
+			int off = isl_basic_map_offset(bmap, c[j]);
+			for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) {
+				isl_int_set(mat->row[i][pos],
+					    bmap->eq[i][off + k]);
+				++pos;
+			}
+		}
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_basic_map_inequalities_matrix(
+		__isl_keep isl_basic_map *bmap, enum isl_dim_type c1,
+		enum isl_dim_type c2, enum isl_dim_type c3,
+		enum isl_dim_type c4, enum isl_dim_type c5)
+{
+	enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 };
+	struct isl_mat *mat;
+	int i, j, k;
+	int pos;
+
+	if (!bmap)
+		return NULL;
+	mat = isl_mat_alloc(bmap->ctx, bmap->n_ineq,
+				isl_basic_map_total_dim(bmap) + 1);
+	if (!mat)
+		return NULL;
+	for (i = 0; i < bmap->n_ineq; ++i)
+		for (j = 0, pos = 0; j < 5; ++j) {
+			int off = isl_basic_map_offset(bmap, c[j]);
+			for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) {
+				isl_int_set(mat->row[i][pos],
+					    bmap->ineq[i][off + k]);
+				++pos;
+			}
+		}
+
+	return mat;
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_constraint_matrices(
+	__isl_take isl_space *dim,
+	__isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1,
+	enum isl_dim_type c2, enum isl_dim_type c3,
+	enum isl_dim_type c4, enum isl_dim_type c5)
+{
+	enum isl_dim_type c[5] = { c1, c2, c3, c4, c5 };
+	isl_basic_map *bmap;
+	unsigned total;
+	unsigned extra;
+	int i, j, k, l;
+	int pos;
+
+	if (!dim || !eq || !ineq)
+		goto error;
+
+	if (eq->n_col != ineq->n_col)
+		isl_die(dim->ctx, isl_error_invalid,
+			"equalities and inequalities matrices should have "
+			"same number of columns", goto error);
+
+	total = 1 + isl_space_dim(dim, isl_dim_all);
+
+	if (eq->n_col < total)
+		isl_die(dim->ctx, isl_error_invalid,
+			"number of columns too small", goto error);
+
+	extra = eq->n_col - total;
+
+	bmap = isl_basic_map_alloc_space(isl_space_copy(dim), extra,
+				       eq->n_row, ineq->n_row);
+	if (!bmap)
+		goto error;
+	for (i = 0; i < extra; ++i) {
+		k = isl_basic_map_alloc_div(bmap);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(bmap->div[k][0], 0);
+	}
+	for (i = 0; i < eq->n_row; ++i) {
+		l = isl_basic_map_alloc_equality(bmap);
+		if (l < 0)
+			goto error;
+		for (j = 0, pos = 0; j < 5; ++j) {
+			int off = isl_basic_map_offset(bmap, c[j]);
+			for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) {
+				isl_int_set(bmap->eq[l][off + k], 
+					    eq->row[i][pos]);
+				++pos;
+			}
+		}
+	}
+	for (i = 0; i < ineq->n_row; ++i) {
+		l = isl_basic_map_alloc_inequality(bmap);
+		if (l < 0)
+			goto error;
+		for (j = 0, pos = 0; j < 5; ++j) {
+			int off = isl_basic_map_offset(bmap, c[j]);
+			for (k = 0; k < isl_basic_map_dim(bmap, c[j]); ++k) {
+				isl_int_set(bmap->ineq[l][off + k], 
+					    ineq->row[i][pos]);
+				++pos;
+			}
+		}
+	}
+
+	isl_space_free(dim);
+	isl_mat_free(eq);
+	isl_mat_free(ineq);
+
+	bmap = isl_basic_map_simplify(bmap);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_space_free(dim);
+	isl_mat_free(eq);
+	isl_mat_free(ineq);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_basic_set_equalities_matrix(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type c1,
+	enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4)
+{
+	return isl_basic_map_equalities_matrix(bset_to_bmap(bset),
+						c1, c2, c3, c4, isl_dim_in);
+}
+
+__isl_give isl_mat *isl_basic_set_inequalities_matrix(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type c1,
+	enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4)
+{
+	return isl_basic_map_inequalities_matrix(bset_to_bmap(bset),
+						 c1, c2, c3, c4, isl_dim_in);
+}
+
+__isl_give isl_basic_set *isl_basic_set_from_constraint_matrices(
+	__isl_take isl_space *dim,
+	__isl_take isl_mat *eq, __isl_take isl_mat *ineq, enum isl_dim_type c1,
+	enum isl_dim_type c2, enum isl_dim_type c3, enum isl_dim_type c4)
+{
+	isl_basic_map *bmap;
+	bmap = isl_basic_map_from_constraint_matrices(dim, eq, ineq,
+						   c1, c2, c3, c4, isl_dim_in);
+	return bset_from_bmap(bmap);
+}
+
+isl_bool isl_basic_map_can_zip(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return isl_bool_error;
+	
+	return isl_space_can_zip(bmap->dim);
+}
+
+isl_bool isl_map_can_zip(__isl_keep isl_map *map)
+{
+	if (!map)
+		return isl_bool_error;
+	
+	return isl_space_can_zip(map->dim);
+}
+
+/* Given a basic map (A -> B) -> (C -> D), return the corresponding basic map
+ * (A -> C) -> (B -> D).
+ */
+__isl_give isl_basic_map *isl_basic_map_zip(__isl_take isl_basic_map *bmap)
+{
+	unsigned pos;
+	unsigned n1;
+	unsigned n2;
+
+	if (!bmap)
+		return NULL;
+
+	if (!isl_basic_map_can_zip(bmap))
+		isl_die(bmap->ctx, isl_error_invalid,
+			"basic map cannot be zipped", goto error);
+	pos = isl_basic_map_offset(bmap, isl_dim_in) +
+		isl_space_dim(bmap->dim->nested[0], isl_dim_in);
+	n1 = isl_space_dim(bmap->dim->nested[0], isl_dim_out);
+	n2 = isl_space_dim(bmap->dim->nested[1], isl_dim_in);
+	bmap = isl_basic_map_cow(bmap);
+	bmap = isl_basic_map_swap_vars(bmap, pos, n1, n2);
+	if (!bmap)
+		return NULL;
+	bmap->dim = isl_space_zip(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+	bmap = isl_basic_map_mark_final(bmap);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Given a map (A -> B) -> (C -> D), return the corresponding map
+ * (A -> C) -> (B -> D).
+ */
+__isl_give isl_map *isl_map_zip(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!isl_map_can_zip(map))
+		isl_die(map->ctx, isl_error_invalid, "map cannot be zipped",
+			goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_zip(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+
+	map->dim = isl_space_zip(map->dim);
+	if (!map->dim)
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Can we apply isl_basic_map_curry to "bmap"?
+ * That is, does it have a nested relation in its domain?
+ */
+isl_bool isl_basic_map_can_curry(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return isl_bool_error;
+
+	return isl_space_can_curry(bmap->dim);
+}
+
+/* Can we apply isl_map_curry to "map"?
+ * That is, does it have a nested relation in its domain?
+ */
+isl_bool isl_map_can_curry(__isl_keep isl_map *map)
+{
+	if (!map)
+		return isl_bool_error;
+
+	return isl_space_can_curry(map->dim);
+}
+
+/* Given a basic map (A -> B) -> C, return the corresponding basic map
+ * A -> (B -> C).
+ */
+__isl_give isl_basic_map *isl_basic_map_curry(__isl_take isl_basic_map *bmap)
+{
+
+	if (!bmap)
+		return NULL;
+
+	if (!isl_basic_map_can_curry(bmap))
+		isl_die(bmap->ctx, isl_error_invalid,
+			"basic map cannot be curried", goto error);
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	bmap->dim = isl_space_curry(bmap->dim);
+	if (!bmap->dim)
+		goto error;
+	bmap = isl_basic_map_mark_final(bmap);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Given a map (A -> B) -> C, return the corresponding map
+ * A -> (B -> C).
+ */
+__isl_give isl_map *isl_map_curry(__isl_take isl_map *map)
+{
+	return isl_map_change_space(map, &isl_map_can_curry,
+				    "map cannot be curried", &isl_space_curry);
+}
+
+/* Can isl_map_range_curry be applied to "map"?
+ * That is, does it have a nested relation in its range,
+ * the domain of which is itself a nested relation?
+ */
+isl_bool isl_map_can_range_curry(__isl_keep isl_map *map)
+{
+	if (!map)
+		return isl_bool_error;
+
+	return isl_space_can_range_curry(map->dim);
+}
+
+/* Given a map A -> ((B -> C) -> D), return the corresponding map
+ * A -> (B -> (C -> D)).
+ */
+__isl_give isl_map *isl_map_range_curry(__isl_take isl_map *map)
+{
+	return isl_map_change_space(map, &isl_map_can_range_curry,
+				    "map range cannot be curried",
+				    &isl_space_range_curry);
+}
+
+/* Can we apply isl_basic_map_uncurry to "bmap"?
+ * That is, does it have a nested relation in its domain?
+ */
+isl_bool isl_basic_map_can_uncurry(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return isl_bool_error;
+
+	return isl_space_can_uncurry(bmap->dim);
+}
+
+/* Can we apply isl_map_uncurry to "map"?
+ * That is, does it have a nested relation in its domain?
+ */
+isl_bool isl_map_can_uncurry(__isl_keep isl_map *map)
+{
+	if (!map)
+		return isl_bool_error;
+
+	return isl_space_can_uncurry(map->dim);
+}
+
+/* Given a basic map A -> (B -> C), return the corresponding basic map
+ * (A -> B) -> C.
+ */
+__isl_give isl_basic_map *isl_basic_map_uncurry(__isl_take isl_basic_map *bmap)
+{
+
+	if (!bmap)
+		return NULL;
+
+	if (!isl_basic_map_can_uncurry(bmap))
+		isl_die(bmap->ctx, isl_error_invalid,
+			"basic map cannot be uncurried",
+			return isl_basic_map_free(bmap));
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	bmap->dim = isl_space_uncurry(bmap->dim);
+	if (!bmap->dim)
+		return isl_basic_map_free(bmap);
+	bmap = isl_basic_map_mark_final(bmap);
+	return bmap;
+}
+
+/* Given a map A -> (B -> C), return the corresponding map
+ * (A -> B) -> C.
+ */
+__isl_give isl_map *isl_map_uncurry(__isl_take isl_map *map)
+{
+	return isl_map_change_space(map, &isl_map_can_uncurry,
+				"map cannot be uncurried", &isl_space_uncurry);
+}
+
+/* Construct a basic map mapping the domain of the affine expression
+ * to a one-dimensional range prescribed by the affine expression.
+ * If "rational" is set, then construct a rational basic map.
+ *
+ * A NaN affine expression cannot be converted to a basic map.
+ */
+static __isl_give isl_basic_map *isl_basic_map_from_aff2(
+	__isl_take isl_aff *aff, int rational)
+{
+	int k;
+	int pos;
+	isl_bool is_nan;
+	isl_local_space *ls;
+	isl_basic_map *bmap = NULL;
+
+	if (!aff)
+		return NULL;
+	is_nan = isl_aff_is_nan(aff);
+	if (is_nan < 0)
+		goto error;
+	if (is_nan)
+		isl_die(isl_aff_get_ctx(aff), isl_error_invalid,
+			"cannot convert NaN", goto error);
+
+	ls = isl_aff_get_local_space(aff);
+	bmap = isl_basic_map_from_local_space(ls);
+	bmap = isl_basic_map_extend_constraints(bmap, 1, 0);
+	k = isl_basic_map_alloc_equality(bmap);
+	if (k < 0)
+		goto error;
+
+	pos = isl_basic_map_offset(bmap, isl_dim_out);
+	isl_seq_cpy(bmap->eq[k], aff->v->el + 1, pos);
+	isl_int_neg(bmap->eq[k][pos], aff->v->el[0]);
+	isl_seq_cpy(bmap->eq[k] + pos + 1, aff->v->el + 1 + pos,
+		    aff->v->size - (pos + 1));
+
+	isl_aff_free(aff);
+	if (rational)
+		bmap = isl_basic_map_set_rational(bmap);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_aff_free(aff);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Construct a basic map mapping the domain of the affine expression
+ * to a one-dimensional range prescribed by the affine expression.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_aff(__isl_take isl_aff *aff)
+{
+	return isl_basic_map_from_aff2(aff, 0);
+}
+
+/* Construct a map mapping the domain of the affine expression
+ * to a one-dimensional range prescribed by the affine expression.
+ */
+__isl_give isl_map *isl_map_from_aff(__isl_take isl_aff *aff)
+{
+	isl_basic_map *bmap;
+
+	bmap = isl_basic_map_from_aff(aff);
+	return isl_map_from_basic_map(bmap);
+}
+
+/* Construct a basic map mapping the domain the multi-affine expression
+ * to its range, with each dimension in the range equated to the
+ * corresponding affine expression.
+ * If "rational" is set, then construct a rational basic map.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_multi_aff2(
+	__isl_take isl_multi_aff *maff, int rational)
+{
+	int i;
+	isl_space *space;
+	isl_basic_map *bmap;
+
+	if (!maff)
+		return NULL;
+
+	if (isl_space_dim(maff->space, isl_dim_out) != maff->n)
+		isl_die(isl_multi_aff_get_ctx(maff), isl_error_internal,
+			"invalid space", goto error);
+
+	space = isl_space_domain(isl_multi_aff_get_space(maff));
+	bmap = isl_basic_map_universe(isl_space_from_domain(space));
+	if (rational)
+		bmap = isl_basic_map_set_rational(bmap);
+
+	for (i = 0; i < maff->n; ++i) {
+		isl_aff *aff;
+		isl_basic_map *bmap_i;
+
+		aff = isl_aff_copy(maff->p[i]);
+		bmap_i = isl_basic_map_from_aff2(aff, rational);
+
+		bmap = isl_basic_map_flat_range_product(bmap, bmap_i);
+	}
+
+	bmap = isl_basic_map_reset_space(bmap, isl_multi_aff_get_space(maff));
+
+	isl_multi_aff_free(maff);
+	return bmap;
+error:
+	isl_multi_aff_free(maff);
+	return NULL;
+}
+
+/* Construct a basic map mapping the domain the multi-affine expression
+ * to its range, with each dimension in the range equated to the
+ * corresponding affine expression.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_multi_aff(
+	__isl_take isl_multi_aff *ma)
+{
+	return isl_basic_map_from_multi_aff2(ma, 0);
+}
+
+/* Construct a map mapping the domain the multi-affine expression
+ * to its range, with each dimension in the range equated to the
+ * corresponding affine expression.
+ */
+__isl_give isl_map *isl_map_from_multi_aff(__isl_take isl_multi_aff *maff)
+{
+	isl_basic_map *bmap;
+
+	bmap = isl_basic_map_from_multi_aff(maff);
+	return isl_map_from_basic_map(bmap);
+}
+
+/* Construct a basic map mapping a domain in the given space to
+ * to an n-dimensional range, with n the number of elements in the list,
+ * where each coordinate in the range is prescribed by the
+ * corresponding affine expression.
+ * The domains of all affine expressions in the list are assumed to match
+ * domain_dim.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_aff_list(
+	__isl_take isl_space *domain_dim, __isl_take isl_aff_list *list)
+{
+	int i;
+	isl_space *dim;
+	isl_basic_map *bmap;
+
+	if (!list)
+		return NULL;
+
+	dim = isl_space_from_domain(domain_dim);
+	bmap = isl_basic_map_universe(dim);
+
+	for (i = 0; i < list->n; ++i) {
+		isl_aff *aff;
+		isl_basic_map *bmap_i;
+
+		aff = isl_aff_copy(list->p[i]);
+		bmap_i = isl_basic_map_from_aff(aff);
+
+		bmap = isl_basic_map_flat_range_product(bmap, bmap_i);
+	}
+
+	isl_aff_list_free(list);
+	return bmap;
+}
+
+__isl_give isl_set *isl_set_equate(__isl_take isl_set *set,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	return isl_map_equate(set, type1, pos1, type2, pos2);
+}
+
+/* Construct a basic map where the given dimensions are equal to each other.
+ */
+static __isl_give isl_basic_map *equator(__isl_take isl_space *space,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *bmap = NULL;
+	int i;
+
+	if (!space)
+		return NULL;
+
+	if (pos1 >= isl_space_dim(space, type1))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"index out of bounds", goto error);
+	if (pos2 >= isl_space_dim(space, type2))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	if (type1 == type2 && pos1 == pos2)
+		return isl_basic_map_universe(space);
+
+	bmap = isl_basic_map_alloc_space(isl_space_copy(space), 0, 1, 0);
+	i = isl_basic_map_alloc_equality(bmap);
+	if (i < 0)
+		goto error;
+	isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap));
+	pos1 += isl_basic_map_offset(bmap, type1);
+	pos2 += isl_basic_map_offset(bmap, type2);
+	isl_int_set_si(bmap->eq[i][pos1], -1);
+	isl_int_set_si(bmap->eq[i][pos2], 1);
+	bmap = isl_basic_map_finalize(bmap);
+	isl_space_free(space);
+	return bmap;
+error:
+	isl_space_free(space);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Add a constraint imposing that the given two dimensions are equal.
+ */
+__isl_give isl_basic_map *isl_basic_map_equate(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *eq;
+
+	eq = equator(isl_basic_map_get_space(bmap), type1, pos1, type2, pos2);
+
+	bmap = isl_basic_map_intersect(bmap, eq);
+
+	return bmap;
+}
+
+/* Add a constraint imposing that the given two dimensions are equal.
+ */
+__isl_give isl_map *isl_map_equate(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *bmap;
+
+	bmap = equator(isl_map_get_space(map), type1, pos1, type2, pos2);
+
+	map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+	return map;
+}
+
+/* Add a constraint imposing that the given two dimensions have opposite values.
+ */
+__isl_give isl_map *isl_map_oppose(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *bmap = NULL;
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (pos1 >= isl_map_dim(map, type1))
+		isl_die(map->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+	if (pos2 >= isl_map_dim(map, type2))
+		isl_die(map->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+
+	bmap = isl_basic_map_alloc_space(isl_map_get_space(map), 0, 1, 0);
+	i = isl_basic_map_alloc_equality(bmap);
+	if (i < 0)
+		goto error;
+	isl_seq_clr(bmap->eq[i], 1 + isl_basic_map_total_dim(bmap));
+	pos1 += isl_basic_map_offset(bmap, type1);
+	pos2 += isl_basic_map_offset(bmap, type2);
+	isl_int_set_si(bmap->eq[i][pos1], 1);
+	isl_int_set_si(bmap->eq[i][pos2], 1);
+	bmap = isl_basic_map_finalize(bmap);
+
+	map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+	return map;
+error:
+	isl_basic_map_free(bmap);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Construct a constraint imposing that the value of the first dimension is
+ * greater than or equal to that of the second.
+ */
+static __isl_give isl_constraint *constraint_order_ge(
+	__isl_take isl_space *space, enum isl_dim_type type1, int pos1,
+	enum isl_dim_type type2, int pos2)
+{
+	isl_constraint *c;
+
+	if (!space)
+		return NULL;
+
+	c = isl_constraint_alloc_inequality(isl_local_space_from_space(space));
+
+	if (pos1 >= isl_constraint_dim(c, type1))
+		isl_die(isl_constraint_get_ctx(c), isl_error_invalid,
+			"index out of bounds", return isl_constraint_free(c));
+	if (pos2 >= isl_constraint_dim(c, type2))
+		isl_die(isl_constraint_get_ctx(c), isl_error_invalid,
+			"index out of bounds", return isl_constraint_free(c));
+
+	if (type1 == type2 && pos1 == pos2)
+		return c;
+
+	c = isl_constraint_set_coefficient_si(c, type1, pos1, 1);
+	c = isl_constraint_set_coefficient_si(c, type2, pos2, -1);
+
+	return c;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than or equal to that of the second.
+ */
+__isl_give isl_basic_map *isl_basic_map_order_ge(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_constraint *c;
+	isl_space *space;
+
+	if (type1 == type2 && pos1 == pos2)
+		return bmap;
+	space = isl_basic_map_get_space(bmap);
+	c = constraint_order_ge(space, type1, pos1, type2, pos2);
+	bmap = isl_basic_map_add_constraint(bmap, c);
+
+	return bmap;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than or equal to that of the second.
+ */
+__isl_give isl_map *isl_map_order_ge(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_constraint *c;
+	isl_space *space;
+
+	if (type1 == type2 && pos1 == pos2)
+		return map;
+	space = isl_map_get_space(map);
+	c = constraint_order_ge(space, type1, pos1, type2, pos2);
+	map = isl_map_add_constraint(map, c);
+
+	return map;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * less than or equal to that of the second.
+ */
+__isl_give isl_map *isl_map_order_le(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	return isl_map_order_ge(map, type2, pos2, type1, pos1);
+}
+
+/* Construct a basic map where the value of the first dimension is
+ * greater than that of the second.
+ */
+static __isl_give isl_basic_map *greator(__isl_take isl_space *space,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *bmap = NULL;
+	int i;
+
+	if (!space)
+		return NULL;
+
+	if (pos1 >= isl_space_dim(space, type1))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"index out of bounds", goto error);
+	if (pos2 >= isl_space_dim(space, type2))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	if (type1 == type2 && pos1 == pos2)
+		return isl_basic_map_empty(space);
+
+	bmap = isl_basic_map_alloc_space(space, 0, 0, 1);
+	i = isl_basic_map_alloc_inequality(bmap);
+	if (i < 0)
+		return isl_basic_map_free(bmap);
+	isl_seq_clr(bmap->ineq[i], 1 + isl_basic_map_total_dim(bmap));
+	pos1 += isl_basic_map_offset(bmap, type1);
+	pos2 += isl_basic_map_offset(bmap, type2);
+	isl_int_set_si(bmap->ineq[i][pos1], 1);
+	isl_int_set_si(bmap->ineq[i][pos2], -1);
+	isl_int_set_si(bmap->ineq[i][0], -1);
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_space_free(space);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than that of the second.
+ */
+__isl_give isl_basic_map *isl_basic_map_order_gt(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *gt;
+
+	gt = greator(isl_basic_map_get_space(bmap), type1, pos1, type2, pos2);
+
+	bmap = isl_basic_map_intersect(bmap, gt);
+
+	return bmap;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * greater than that of the second.
+ */
+__isl_give isl_map *isl_map_order_gt(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	isl_basic_map *bmap;
+
+	bmap = greator(isl_map_get_space(map), type1, pos1, type2, pos2);
+
+	map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+	return map;
+}
+
+/* Add a constraint imposing that the value of the first dimension is
+ * smaller than that of the second.
+ */
+__isl_give isl_map *isl_map_order_lt(__isl_take isl_map *map,
+	enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
+{
+	return isl_map_order_gt(map, type2, pos2, type1, pos1);
+}
+
+__isl_give isl_aff *isl_basic_map_get_div(__isl_keep isl_basic_map *bmap,
+	int pos)
+{
+	isl_aff *div;
+	isl_local_space *ls;
+
+	if (!bmap)
+		return NULL;
+
+	if (!isl_basic_map_divs_known(bmap))
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"some divs are unknown", return NULL);
+
+	ls = isl_basic_map_get_local_space(bmap);
+	div = isl_local_space_get_div(ls, pos);
+	isl_local_space_free(ls);
+
+	return div;
+}
+
+__isl_give isl_aff *isl_basic_set_get_div(__isl_keep isl_basic_set *bset,
+	int pos)
+{
+	return isl_basic_map_get_div(bset, pos);
+}
+
+/* Plug in "subs" for dimension "type", "pos" of "bset".
+ *
+ * Let i be the dimension to replace and let "subs" be of the form
+ *
+ *	f/d
+ *
+ * Any integer division with a non-zero coefficient for i,
+ *
+ *	floor((a i + g)/m)
+ *
+ * is replaced by
+ *
+ *	floor((a f + d g)/(m d))
+ *
+ * Constraints of the form
+ *
+ *	a i + g
+ *
+ * are replaced by
+ *
+ *	a f + d g
+ *
+ * We currently require that "subs" is an integral expression.
+ * Handling rational expressions may require us to add stride constraints
+ * as we do in isl_basic_set_preimage_multi_aff.
+ */
+__isl_give isl_basic_set *isl_basic_set_substitute(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
+{
+	int i;
+	isl_int v;
+	isl_ctx *ctx;
+
+	if (bset && isl_basic_set_plain_is_empty(bset))
+		return bset;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset || !subs)
+		goto error;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	if (!isl_space_is_equal(bset->dim, subs->ls->dim))
+		isl_die(ctx, isl_error_invalid,
+			"spaces don't match", goto error);
+	if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
+		isl_die(ctx, isl_error_unsupported,
+			"cannot handle divs yet", goto error);
+	if (!isl_int_is_one(subs->v->el[0]))
+		isl_die(ctx, isl_error_invalid,
+			"can only substitute integer expressions", goto error);
+
+	pos += isl_basic_set_offset(bset, type);
+
+	isl_int_init(v);
+
+	for (i = 0; i < bset->n_eq; ++i) {
+		if (isl_int_is_zero(bset->eq[i][pos]))
+			continue;
+		isl_int_set(v, bset->eq[i][pos]);
+		isl_int_set_si(bset->eq[i][pos], 0);
+		isl_seq_combine(bset->eq[i], subs->v->el[0], bset->eq[i],
+				v, subs->v->el + 1, subs->v->size - 1);
+	}
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (isl_int_is_zero(bset->ineq[i][pos]))
+			continue;
+		isl_int_set(v, bset->ineq[i][pos]);
+		isl_int_set_si(bset->ineq[i][pos], 0);
+		isl_seq_combine(bset->ineq[i], subs->v->el[0], bset->ineq[i],
+				v, subs->v->el + 1, subs->v->size - 1);
+	}
+
+	for (i = 0; i < bset->n_div; ++i) {
+		if (isl_int_is_zero(bset->div[i][1 + pos]))
+			continue;
+		isl_int_set(v, bset->div[i][1 + pos]);
+		isl_int_set_si(bset->div[i][1 + pos], 0);
+		isl_seq_combine(bset->div[i] + 1,
+				subs->v->el[0], bset->div[i] + 1,
+				v, subs->v->el + 1, subs->v->size - 1);
+		isl_int_mul(bset->div[i][0], bset->div[i][0], subs->v->el[0]);
+	}
+
+	isl_int_clear(v);
+
+	bset = isl_basic_set_simplify(bset);
+	return isl_basic_set_finalize(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Plug in "subs" for dimension "type", "pos" of "set".
+ */
+__isl_give isl_set *isl_set_substitute(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
+{
+	int i;
+
+	if (set && isl_set_plain_is_empty(set))
+		return set;
+
+	set = isl_set_cow(set);
+	if (!set || !subs)
+		goto error;
+
+	for (i = set->n - 1; i >= 0; --i) {
+		set->p[i] = isl_basic_set_substitute(set->p[i], type, pos, subs);
+		if (remove_if_empty(set, i) < 0)
+			goto error;
+	}
+
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Check if the range of "ma" is compatible with the domain or range
+ * (depending on "type") of "bmap".
+ */
+static isl_stat check_basic_map_compatible_range_multi_aff(
+	__isl_keep isl_basic_map *bmap, enum isl_dim_type type,
+	__isl_keep isl_multi_aff *ma)
+{
+	isl_bool m;
+	isl_space *ma_space;
+
+	ma_space = isl_multi_aff_get_space(ma);
+
+	m = isl_space_has_equal_params(bmap->dim, ma_space);
+	if (m < 0)
+		goto error;
+	if (!m)
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"parameters don't match", goto error);
+	m = isl_space_tuple_is_equal(bmap->dim, type, ma_space, isl_dim_out);
+	if (m < 0)
+		goto error;
+	if (!m)
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	isl_space_free(ma_space);
+	return isl_stat_ok;
+error:
+	isl_space_free(ma_space);
+	return isl_stat_error;
+}
+
+/* Copy the divs from "ma" to "bmap", adding zeros for the "n_before"
+ * coefficients before the transformed range of dimensions,
+ * the "n_after" coefficients after the transformed range of dimensions
+ * and the coefficients of the other divs in "bmap".
+ */
+static int set_ma_divs(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_multi_aff *ma, int n_before, int n_after, int n_div)
+{
+	int i;
+	int n_param;
+	int n_set;
+	isl_local_space *ls;
+
+	if (n_div == 0)
+		return 0;
+
+	ls = isl_aff_get_domain_local_space(ma->p[0]);
+	if (!ls)
+		return -1;
+
+	n_param = isl_local_space_dim(ls, isl_dim_param);
+	n_set = isl_local_space_dim(ls, isl_dim_set);
+	for (i = 0; i < n_div; ++i) {
+		int o_bmap = 0, o_ls = 0;
+
+		isl_seq_cpy(bmap->div[i], ls->div->row[i], 1 + 1 + n_param);
+		o_bmap += 1 + 1 + n_param;
+		o_ls += 1 + 1 + n_param;
+		isl_seq_clr(bmap->div[i] + o_bmap, n_before);
+		o_bmap += n_before;
+		isl_seq_cpy(bmap->div[i] + o_bmap,
+			    ls->div->row[i] + o_ls, n_set);
+		o_bmap += n_set;
+		o_ls += n_set;
+		isl_seq_clr(bmap->div[i] + o_bmap, n_after);
+		o_bmap += n_after;
+		isl_seq_cpy(bmap->div[i] + o_bmap,
+			    ls->div->row[i] + o_ls, n_div);
+		o_bmap += n_div;
+		o_ls += n_div;
+		isl_seq_clr(bmap->div[i] + o_bmap, bmap->n_div - n_div);
+		if (isl_basic_map_add_div_constraints(bmap, i) < 0)
+			goto error;
+	}
+
+	isl_local_space_free(ls);
+	return 0;
+error:
+	isl_local_space_free(ls);
+	return -1;
+}
+
+/* How many stride constraints does "ma" enforce?
+ * That is, how many of the affine expressions have a denominator
+ * different from one?
+ */
+static int multi_aff_strides(__isl_keep isl_multi_aff *ma)
+{
+	int i;
+	int strides = 0;
+
+	for (i = 0; i < ma->n; ++i)
+		if (!isl_int_is_one(ma->p[i]->v->el[0]))
+			strides++;
+
+	return strides;
+}
+
+/* For each affine expression in ma of the form
+ *
+ *	x_i = (f_i y + h_i)/m_i
+ *
+ * with m_i different from one, add a constraint to "bmap"
+ * of the form
+ *
+ *	f_i y + h_i = m_i alpha_i
+ *
+ * with alpha_i an additional existentially quantified variable.
+ *
+ * The input variables of "ma" correspond to a subset of the variables
+ * of "bmap".  There are "n_before" variables in "bmap" before this
+ * subset and "n_after" variables after this subset.
+ * The integer divisions of the affine expressions in "ma" are assumed
+ * to have been aligned.  There are "n_div_ma" of them and
+ * they appear first in "bmap", straight after the "n_after" variables.
+ */
+static __isl_give isl_basic_map *add_ma_strides(
+	__isl_take isl_basic_map *bmap, __isl_keep isl_multi_aff *ma,
+	int n_before, int n_after, int n_div_ma)
+{
+	int i, k;
+	int div;
+	int total;
+	int n_param;
+	int n_in;
+
+	total = isl_basic_map_total_dim(bmap);
+	n_param = isl_multi_aff_dim(ma, isl_dim_param);
+	n_in = isl_multi_aff_dim(ma, isl_dim_in);
+	for (i = 0; i < ma->n; ++i) {
+		int o_bmap = 0, o_ma = 1;
+
+		if (isl_int_is_one(ma->p[i]->v->el[0]))
+			continue;
+		div = isl_basic_map_alloc_div(bmap);
+		k = isl_basic_map_alloc_equality(bmap);
+		if (div < 0 || k < 0)
+			goto error;
+		isl_int_set_si(bmap->div[div][0], 0);
+		isl_seq_cpy(bmap->eq[k] + o_bmap,
+			    ma->p[i]->v->el + o_ma, 1 + n_param);
+		o_bmap += 1 + n_param;
+		o_ma += 1 + n_param;
+		isl_seq_clr(bmap->eq[k] + o_bmap, n_before);
+		o_bmap += n_before;
+		isl_seq_cpy(bmap->eq[k] + o_bmap,
+			    ma->p[i]->v->el + o_ma, n_in);
+		o_bmap += n_in;
+		o_ma += n_in;
+		isl_seq_clr(bmap->eq[k] + o_bmap, n_after);
+		o_bmap += n_after;
+		isl_seq_cpy(bmap->eq[k] + o_bmap,
+			    ma->p[i]->v->el + o_ma, n_div_ma);
+		o_bmap += n_div_ma;
+		o_ma += n_div_ma;
+		isl_seq_clr(bmap->eq[k] + o_bmap, 1 + total - o_bmap);
+		isl_int_neg(bmap->eq[k][1 + total], ma->p[i]->v->el[0]);
+		total++;
+	}
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Replace the domain or range space (depending on "type) of "space" by "set".
+ */
+static __isl_give isl_space *isl_space_set(__isl_take isl_space *space,
+	enum isl_dim_type type, __isl_take isl_space *set)
+{
+	if (type == isl_dim_in) {
+		space = isl_space_range(space);
+		space = isl_space_map_from_domain_and_range(set, space);
+	} else {
+		space = isl_space_domain(space);
+		space = isl_space_map_from_domain_and_range(space, set);
+	}
+
+	return space;
+}
+
+/* Compute the preimage of the domain or range (depending on "type")
+ * of "bmap" under the function represented by "ma".
+ * In other words, plug in "ma" in the domain or range of "bmap".
+ * The result is a basic map that lives in the same space as "bmap"
+ * except that the domain or range has been replaced by
+ * the domain space of "ma".
+ *
+ * If bmap is represented by
+ *
+ *	A(p) + S u + B x + T v + C(divs) >= 0,
+ *
+ * where u and x are input and output dimensions if type == isl_dim_out
+ * while x and v are input and output dimensions if type == isl_dim_in,
+ * and ma is represented by
+ *
+ *	x = D(p) + F(y) + G(divs')
+ *
+ * then the result is
+ *
+ *	A(p) + B D(p) + S u + B F(y) + T v + B G(divs') + C(divs) >= 0
+ *
+ * The divs in the input set are similarly adjusted.
+ * In particular
+ *
+ *	floor((a_i(p) + s u + b_i x + t v + c_i(divs))/n_i)
+ *
+ * becomes
+ *
+ *	floor((a_i(p) + b_i D(p) + s u + b_i F(y) + t v +
+ *		B_i G(divs') + c_i(divs))/n_i)
+ *
+ * If bmap is not a rational map and if F(y) involves any denominators
+ *
+ *	x_i = (f_i y + h_i)/m_i
+ *
+ * then additional constraints are added to ensure that we only
+ * map back integer points.  That is we enforce
+ *
+ *	f_i y + h_i = m_i alpha_i
+ *
+ * with alpha_i an additional existentially quantified variable.
+ *
+ * We first copy over the divs from "ma".
+ * Then we add the modified constraints and divs from "bmap".
+ * Finally, we add the stride constraints, if needed.
+ */
+__isl_give isl_basic_map *isl_basic_map_preimage_multi_aff(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type,
+	__isl_take isl_multi_aff *ma)
+{
+	int i, k;
+	isl_space *space;
+	isl_basic_map *res = NULL;
+	int n_before, n_after, n_div_bmap, n_div_ma;
+	isl_int f, c1, c2, g;
+	isl_bool rational;
+	int strides;
+
+	isl_int_init(f);
+	isl_int_init(c1);
+	isl_int_init(c2);
+	isl_int_init(g);
+
+	ma = isl_multi_aff_align_divs(ma);
+	if (!bmap || !ma)
+		goto error;
+	if (check_basic_map_compatible_range_multi_aff(bmap, type, ma) < 0)
+		goto error;
+
+	if (type == isl_dim_in) {
+		n_before = 0;
+		n_after = isl_basic_map_dim(bmap, isl_dim_out);
+	} else {
+		n_before = isl_basic_map_dim(bmap, isl_dim_in);
+		n_after = 0;
+	}
+	n_div_bmap = isl_basic_map_dim(bmap, isl_dim_div);
+	n_div_ma = ma->n ? isl_aff_dim(ma->p[0], isl_dim_div) : 0;
+
+	space = isl_multi_aff_get_domain_space(ma);
+	space = isl_space_set(isl_basic_map_get_space(bmap), type, space);
+	rational = isl_basic_map_is_rational(bmap);
+	strides = rational ? 0 : multi_aff_strides(ma);
+	res = isl_basic_map_alloc_space(space, n_div_ma + n_div_bmap + strides,
+			    bmap->n_eq + strides, bmap->n_ineq + 2 * n_div_ma);
+	if (rational)
+		res = isl_basic_map_set_rational(res);
+
+	for (i = 0; i < n_div_ma + n_div_bmap; ++i)
+		if (isl_basic_map_alloc_div(res) < 0)
+			goto error;
+
+	if (set_ma_divs(res, ma, n_before, n_after, n_div_ma) < 0)
+		goto error;
+
+	for (i = 0; i < bmap->n_eq; ++i) {
+		k = isl_basic_map_alloc_equality(res);
+		if (k < 0)
+			goto error;
+		isl_seq_preimage(res->eq[k], bmap->eq[i], ma, n_before,
+				n_after, n_div_ma, n_div_bmap, f, c1, c2, g, 0);
+	}
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		k = isl_basic_map_alloc_inequality(res);
+		if (k < 0)
+			goto error;
+		isl_seq_preimage(res->ineq[k], bmap->ineq[i], ma, n_before,
+				n_after, n_div_ma, n_div_bmap, f, c1, c2, g, 0);
+	}
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0])) {
+			isl_int_set_si(res->div[n_div_ma + i][0], 0);
+			continue;
+		}
+		isl_seq_preimage(res->div[n_div_ma + i], bmap->div[i], ma,
+				    n_before, n_after, n_div_ma, n_div_bmap,
+				    f, c1, c2, g, 1);
+	}
+
+	if (strides)
+		res = add_ma_strides(res, ma, n_before, n_after, n_div_ma);
+
+	isl_int_clear(f);
+	isl_int_clear(c1);
+	isl_int_clear(c2);
+	isl_int_clear(g);
+	isl_basic_map_free(bmap);
+	isl_multi_aff_free(ma);
+	res = isl_basic_map_simplify(res);
+	return isl_basic_map_finalize(res);
+error:
+	isl_int_clear(f);
+	isl_int_clear(c1);
+	isl_int_clear(c2);
+	isl_int_clear(g);
+	isl_basic_map_free(bmap);
+	isl_multi_aff_free(ma);
+	isl_basic_map_free(res);
+	return NULL;
+}
+
+/* Compute the preimage of "bset" under the function represented by "ma".
+ * In other words, plug in "ma" in "bset".  The result is a basic set
+ * that lives in the domain space of "ma".
+ */
+__isl_give isl_basic_set *isl_basic_set_preimage_multi_aff(
+	__isl_take isl_basic_set *bset, __isl_take isl_multi_aff *ma)
+{
+	return isl_basic_map_preimage_multi_aff(bset, isl_dim_set, ma);
+}
+
+/* Compute the preimage of the domain of "bmap" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the domain of "bmap".
+ * The result is a basic map that lives in the same space as "bmap"
+ * except that the domain has been replaced by the domain space of "ma".
+ */
+__isl_give isl_basic_map *isl_basic_map_preimage_domain_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma)
+{
+	return isl_basic_map_preimage_multi_aff(bmap, isl_dim_in, ma);
+}
+
+/* Compute the preimage of the range of "bmap" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the range of "bmap".
+ * The result is a basic map that lives in the same space as "bmap"
+ * except that the range has been replaced by the domain space of "ma".
+ */
+__isl_give isl_basic_map *isl_basic_map_preimage_range_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_multi_aff *ma)
+{
+	return isl_basic_map_preimage_multi_aff(bmap, isl_dim_out, ma);
+}
+
+/* Check if the range of "ma" is compatible with the domain or range
+ * (depending on "type") of "map".
+ * Return isl_stat_error if anything is wrong.
+ */
+static isl_stat check_map_compatible_range_multi_aff(
+	__isl_keep isl_map *map, enum isl_dim_type type,
+	__isl_keep isl_multi_aff *ma)
+{
+	isl_bool m;
+	isl_space *ma_space;
+
+	ma_space = isl_multi_aff_get_space(ma);
+	m = isl_space_tuple_is_equal(map->dim, type, ma_space, isl_dim_out);
+	isl_space_free(ma_space);
+	if (m < 0)
+		return isl_stat_error;
+	if (!m)
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"spaces don't match", return isl_stat_error);
+	return isl_stat_ok;
+}
+
+/* Compute the preimage of the domain or range (depending on "type")
+ * of "map" under the function represented by "ma".
+ * In other words, plug in "ma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the domain or range has been replaced by
+ * the domain space of "ma".
+ *
+ * The parameters are assumed to have been aligned.
+ */
+static __isl_give isl_map *map_preimage_multi_aff(__isl_take isl_map *map,
+	enum isl_dim_type type, __isl_take isl_multi_aff *ma)
+{
+	int i;
+	isl_space *space;
+
+	map = isl_map_cow(map);
+	ma = isl_multi_aff_align_divs(ma);
+	if (!map || !ma)
+		goto error;
+	if (check_map_compatible_range_multi_aff(map, type, ma) < 0)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_preimage_multi_aff(map->p[i], type,
+							isl_multi_aff_copy(ma));
+		if (!map->p[i])
+			goto error;
+	}
+
+	space = isl_multi_aff_get_domain_space(ma);
+	space = isl_space_set(isl_map_get_space(map), type, space);
+
+	isl_space_free(map->dim);
+	map->dim = space;
+	if (!map->dim)
+		goto error;
+
+	isl_multi_aff_free(ma);
+	if (map->n > 1)
+		ISL_F_CLR(map, ISL_MAP_DISJOINT);
+	ISL_F_CLR(map, ISL_SET_NORMALIZED);
+	return map;
+error:
+	isl_multi_aff_free(ma);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Compute the preimage of the domain or range (depending on "type")
+ * of "map" under the function represented by "ma".
+ * In other words, plug in "ma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the domain or range has been replaced by
+ * the domain space of "ma".
+ */
+__isl_give isl_map *isl_map_preimage_multi_aff(__isl_take isl_map *map,
+	enum isl_dim_type type, __isl_take isl_multi_aff *ma)
+{
+	isl_bool aligned;
+
+	if (!map || !ma)
+		goto error;
+
+	aligned = isl_map_space_has_equal_params(map, ma->space);
+	if (aligned < 0)
+		goto error;
+	if (aligned)
+		return map_preimage_multi_aff(map, type, ma);
+
+	if (isl_map_check_named_params(map) < 0)
+		goto error;
+	if (!isl_space_has_named_params(ma->space))
+		isl_die(map->ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	map = isl_map_align_params(map, isl_multi_aff_get_space(ma));
+	ma = isl_multi_aff_align_params(ma, isl_map_get_space(map));
+
+	return map_preimage_multi_aff(map, type, ma);
+error:
+	isl_multi_aff_free(ma);
+	return isl_map_free(map);
+}
+
+/* Compute the preimage of "set" under the function represented by "ma".
+ * In other words, plug in "ma" in "set".  The result is a set
+ * that lives in the domain space of "ma".
+ */
+__isl_give isl_set *isl_set_preimage_multi_aff(__isl_take isl_set *set,
+	__isl_take isl_multi_aff *ma)
+{
+	return isl_map_preimage_multi_aff(set, isl_dim_set, ma);
+}
+
+/* Compute the preimage of the domain of "map" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the domain of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the domain has been replaced by the domain space of "ma".
+ */
+__isl_give isl_map *isl_map_preimage_domain_multi_aff(__isl_take isl_map *map,
+	__isl_take isl_multi_aff *ma)
+{
+	return isl_map_preimage_multi_aff(map, isl_dim_in, ma);
+}
+
+/* Compute the preimage of the range of "map" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the range of "map".
+ * The result is a map that lives in the same space as "map"
+ * except that the range has been replaced by the domain space of "ma".
+ */
+__isl_give isl_map *isl_map_preimage_range_multi_aff(__isl_take isl_map *map,
+	__isl_take isl_multi_aff *ma)
+{
+	return isl_map_preimage_multi_aff(map, isl_dim_out, ma);
+}
+
+/* Compute the preimage of "map" under the function represented by "pma".
+ * In other words, plug in "pma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that the space of type "type" has been replaced by
+ * the domain space of "pma".
+ *
+ * The parameters of "map" and "pma" are assumed to have been aligned.
+ */
+static __isl_give isl_map *isl_map_preimage_pw_multi_aff_aligned(
+	__isl_take isl_map *map, enum isl_dim_type type,
+	__isl_take isl_pw_multi_aff *pma)
+{
+	int i;
+	isl_map *res;
+
+	if (!pma)
+		goto error;
+
+	if (pma->n == 0) {
+		isl_pw_multi_aff_free(pma);
+		res = isl_map_empty(isl_map_get_space(map));
+		isl_map_free(map);
+		return res;
+	}
+
+	res = isl_map_preimage_multi_aff(isl_map_copy(map), type,
+					isl_multi_aff_copy(pma->p[0].maff));
+	if (type == isl_dim_in)
+		res = isl_map_intersect_domain(res,
+						isl_map_copy(pma->p[0].set));
+	else
+		res = isl_map_intersect_range(res,
+						isl_map_copy(pma->p[0].set));
+
+	for (i = 1; i < pma->n; ++i) {
+		isl_map *res_i;
+
+		res_i = isl_map_preimage_multi_aff(isl_map_copy(map), type,
+					isl_multi_aff_copy(pma->p[i].maff));
+		if (type == isl_dim_in)
+			res_i = isl_map_intersect_domain(res_i,
+						isl_map_copy(pma->p[i].set));
+		else
+			res_i = isl_map_intersect_range(res_i,
+						isl_map_copy(pma->p[i].set));
+		res = isl_map_union(res, res_i);
+	}
+
+	isl_pw_multi_aff_free(pma);
+	isl_map_free(map);
+	return res;
+error:
+	isl_pw_multi_aff_free(pma);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Compute the preimage of "map" under the function represented by "pma".
+ * In other words, plug in "pma" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that the space of type "type" has been replaced by
+ * the domain space of "pma".
+ */
+__isl_give isl_map *isl_map_preimage_pw_multi_aff(__isl_take isl_map *map,
+	enum isl_dim_type type, __isl_take isl_pw_multi_aff *pma)
+{
+	isl_bool aligned;
+
+	if (!map || !pma)
+		goto error;
+
+	aligned = isl_map_space_has_equal_params(map, pma->dim);
+	if (aligned < 0)
+		goto error;
+	if (aligned)
+		return isl_map_preimage_pw_multi_aff_aligned(map, type, pma);
+
+	if (isl_map_check_named_params(map) < 0)
+		goto error;
+	if (!isl_space_has_named_params(pma->dim))
+		isl_die(map->ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	map = isl_map_align_params(map, isl_pw_multi_aff_get_space(pma));
+	pma = isl_pw_multi_aff_align_params(pma, isl_map_get_space(map));
+
+	return isl_map_preimage_pw_multi_aff_aligned(map, type, pma);
+error:
+	isl_pw_multi_aff_free(pma);
+	return isl_map_free(map);
+}
+
+/* Compute the preimage of "set" under the function represented by "pma".
+ * In other words, plug in "pma" in "set".  The result is a set
+ * that lives in the domain space of "pma".
+ */
+__isl_give isl_set *isl_set_preimage_pw_multi_aff(__isl_take isl_set *set,
+	__isl_take isl_pw_multi_aff *pma)
+{
+	return isl_map_preimage_pw_multi_aff(set, isl_dim_set, pma);
+}
+
+/* Compute the preimage of the domain of "map" under the function
+ * represented by "pma".
+ * In other words, plug in "pma" in the domain of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that domain space has been replaced by the domain space of "pma".
+ */
+__isl_give isl_map *isl_map_preimage_domain_pw_multi_aff(
+	__isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma)
+{
+	return isl_map_preimage_pw_multi_aff(map, isl_dim_in, pma);
+}
+
+/* Compute the preimage of the range of "map" under the function
+ * represented by "pma".
+ * In other words, plug in "pma" in the range of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that range space has been replaced by the domain space of "pma".
+ */
+__isl_give isl_map *isl_map_preimage_range_pw_multi_aff(
+	__isl_take isl_map *map, __isl_take isl_pw_multi_aff *pma)
+{
+	return isl_map_preimage_pw_multi_aff(map, isl_dim_out, pma);
+}
+
+/* Compute the preimage of "map" under the function represented by "mpa".
+ * In other words, plug in "mpa" in the domain or range of "map".
+ * The result is a map that lives in the same space as "map",
+ * except that the space of type "type" has been replaced by
+ * the domain space of "mpa".
+ *
+ * If the map does not involve any constraints that refer to the
+ * dimensions of the substituted space, then the only possible
+ * effect of "mpa" on the map is to map the space to a different space.
+ * We create a separate isl_multi_aff to effectuate this change
+ * in order to avoid spurious splitting of the map along the pieces
+ * of "mpa".
+ */
+__isl_give isl_map *isl_map_preimage_multi_pw_aff(__isl_take isl_map *map,
+	enum isl_dim_type type, __isl_take isl_multi_pw_aff *mpa)
+{
+	int n;
+	isl_pw_multi_aff *pma;
+
+	if (!map || !mpa)
+		goto error;
+
+	n = isl_map_dim(map, type);
+	if (!isl_map_involves_dims(map, type, 0, n)) {
+		isl_space *space;
+		isl_multi_aff *ma;
+
+		space = isl_multi_pw_aff_get_space(mpa);
+		isl_multi_pw_aff_free(mpa);
+		ma = isl_multi_aff_zero(space);
+		return isl_map_preimage_multi_aff(map, type, ma);
+	}
+
+	pma = isl_pw_multi_aff_from_multi_pw_aff(mpa);
+	return isl_map_preimage_pw_multi_aff(map, type, pma);
+error:
+	isl_map_free(map);
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Compute the preimage of "map" under the function represented by "mpa".
+ * In other words, plug in "mpa" in the domain "map".
+ * The result is a map that lives in the same space as "map",
+ * except that domain space has been replaced by the domain space of "mpa".
+ */
+__isl_give isl_map *isl_map_preimage_domain_multi_pw_aff(
+	__isl_take isl_map *map, __isl_take isl_multi_pw_aff *mpa)
+{
+	return isl_map_preimage_multi_pw_aff(map, isl_dim_in, mpa);
+}
+
+/* Compute the preimage of "set" by the function represented by "mpa".
+ * In other words, plug in "mpa" in "set".
+ */
+__isl_give isl_set *isl_set_preimage_multi_pw_aff(__isl_take isl_set *set,
+	__isl_take isl_multi_pw_aff *mpa)
+{
+	return isl_map_preimage_multi_pw_aff(set, isl_dim_set, mpa);
+}
+
+/* Return a copy of the equality constraints of "bset" as a matrix.
+ */
+__isl_give isl_mat *isl_basic_set_extract_equalities(
+	__isl_keep isl_basic_set *bset)
+{
+	isl_ctx *ctx;
+	unsigned total;
+
+	if (!bset)
+		return NULL;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	total = 1 + isl_basic_set_dim(bset, isl_dim_all);
+	return isl_mat_sub_alloc6(ctx, bset->eq, 0, bset->n_eq, 0, total);
+}
+
+/* Are the "n" "coefficients" starting at "first" of the integer division
+ * expressions at position "pos1" in "bmap1" and "pos2" in "bmap2" equal
+ * to each other?
+ * The "coefficient" at position 0 is the denominator.
+ * The "coefficient" at position 1 is the constant term.
+ */
+isl_bool isl_basic_map_equal_div_expr_part(__isl_keep isl_basic_map *bmap1,
+	int pos1, __isl_keep isl_basic_map *bmap2, int pos2,
+	unsigned first, unsigned n)
+{
+	if (isl_basic_map_check_range(bmap1, isl_dim_div, pos1, 1) < 0)
+		return isl_bool_error;
+	if (isl_basic_map_check_range(bmap2, isl_dim_div, pos2, 1) < 0)
+		return isl_bool_error;
+	return isl_seq_eq(bmap1->div[pos1] + first,
+			  bmap2->div[pos2] + first, n);
+}
+
+/* Are the integer division expressions at position "pos1" in "bmap1" and
+ * "pos2" in "bmap2" equal to each other, except that the constant terms
+ * are different?
+ */
+isl_bool isl_basic_map_equal_div_expr_except_constant(
+	__isl_keep isl_basic_map *bmap1, int pos1,
+	__isl_keep isl_basic_map *bmap2, int pos2)
+{
+	isl_bool equal;
+	unsigned total;
+
+	if (!bmap1 || !bmap2)
+		return isl_bool_error;
+	total = isl_basic_map_total_dim(bmap1);
+	if (total != isl_basic_map_total_dim(bmap2))
+		isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+			"incomparable div expressions", return isl_bool_error);
+	equal = isl_basic_map_equal_div_expr_part(bmap1, pos1, bmap2, pos2,
+						0, 1);
+	if (equal < 0 || !equal)
+		return equal;
+	equal = isl_basic_map_equal_div_expr_part(bmap1, pos1, bmap2, pos2,
+						1, 1);
+	if (equal < 0 || equal)
+		return isl_bool_not(equal);
+	return isl_basic_map_equal_div_expr_part(bmap1, pos1, bmap2, pos2,
+						2, total);
+}
+
+/* Replace the numerator of the constant term of the integer division
+ * expression at position "div" in "bmap" by "value".
+ * The caller guarantees that this does not change the meaning
+ * of the input.
+ */
+__isl_give isl_basic_map *isl_basic_map_set_div_expr_constant_num_si_inplace(
+	__isl_take isl_basic_map *bmap, int div, int value)
+{
+	if (isl_basic_map_check_range(bmap, isl_dim_div, div, 1) < 0)
+		return isl_basic_map_free(bmap);
+
+	isl_int_set_si(bmap->div[div][1], value);
+
+	return bmap;
+}
+
+/* Is the point "inner" internal to inequality constraint "ineq"
+ * of "bset"?
+ * The point is considered to be internal to the inequality constraint,
+ * if it strictly lies on the positive side of the inequality constraint,
+ * or if it lies on the constraint and the constraint is lexico-positive.
+ */
+static isl_bool is_internal(__isl_keep isl_vec *inner,
+	__isl_keep isl_basic_set *bset, int ineq)
+{
+	isl_ctx *ctx;
+	int pos;
+	unsigned total;
+
+	if (!inner || !bset)
+		return isl_bool_error;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	isl_seq_inner_product(inner->el, bset->ineq[ineq], inner->size,
+				&ctx->normalize_gcd);
+	if (!isl_int_is_zero(ctx->normalize_gcd))
+		return isl_int_is_nonneg(ctx->normalize_gcd);
+
+	total = isl_basic_set_dim(bset, isl_dim_all);
+	pos = isl_seq_first_non_zero(bset->ineq[ineq] + 1, total);
+	return isl_int_is_pos(bset->ineq[ineq][1 + pos]);
+}
+
+/* Tighten the inequality constraints of "bset" that are outward with respect
+ * to the point "vec".
+ * That is, tighten the constraints that are not satisfied by "vec".
+ *
+ * "vec" is a point internal to some superset S of "bset" that is used
+ * to make the subsets of S disjoint, by tightening one half of the constraints
+ * that separate two subsets.  In particular, the constraints of S
+ * are all satisfied by "vec" and should not be tightened.
+ * Of the internal constraints, those that have "vec" on the outside
+ * are tightened.  The shared facet is included in the adjacent subset
+ * with the opposite constraint.
+ * For constraints that saturate "vec", this criterion cannot be used
+ * to determine which of the two sides should be tightened.
+ * Instead, the sign of the first non-zero coefficient is used
+ * to make this choice.  Note that this second criterion is never used
+ * on the constraints of S since "vec" is interior to "S".
+ */
+__isl_give isl_basic_set *isl_basic_set_tighten_outward(
+	__isl_take isl_basic_set *bset, __isl_keep isl_vec *vec)
+{
+	int j;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		return NULL;
+	for (j = 0; j < bset->n_ineq; ++j) {
+		isl_bool internal;
+
+		internal = is_internal(vec, bset, j);
+		if (internal < 0)
+			return isl_basic_set_free(bset);
+		if (internal)
+			continue;
+		isl_int_sub_ui(bset->ineq[j][0], bset->ineq[j][0], 1);
+	}
+
+	return bset;
+}
+
+/* Replace the variables x of type "type" starting at "first" in "bmap"
+ * by x' with x = M x' with M the matrix trans.
+ * That is, replace the corresponding coefficients c by c M.
+ *
+ * The transformation matrix should be a square matrix.
+ */
+__isl_give isl_basic_map *isl_basic_map_transform_dims(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type, unsigned first,
+	__isl_take isl_mat *trans)
+{
+	unsigned pos;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap || !trans)
+		goto error;
+
+	if (trans->n_row != trans->n_col)
+		isl_die(trans->ctx, isl_error_invalid,
+			"expecting square transformation matrix", goto error);
+	if (first + trans->n_row > isl_basic_map_dim(bmap, type))
+		isl_die(trans->ctx, isl_error_invalid,
+			"oversized transformation matrix", goto error);
+
+	pos = isl_basic_map_offset(bmap, type) + first;
+
+	if (isl_mat_sub_transform(bmap->eq, bmap->n_eq, pos,
+			isl_mat_copy(trans)) < 0)
+		goto error;
+	if (isl_mat_sub_transform(bmap->ineq, bmap->n_ineq, pos,
+		      isl_mat_copy(trans)) < 0)
+		goto error;
+	if (isl_mat_sub_transform(bmap->div, bmap->n_div, 1 + pos,
+		      isl_mat_copy(trans)) < 0)
+		goto error;
+
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+
+	isl_mat_free(trans);
+	return bmap;
+error:
+	isl_mat_free(trans);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Replace the variables x of type "type" starting at "first" in "bset"
+ * by x' with x = M x' with M the matrix trans.
+ * That is, replace the corresponding coefficients c by c M.
+ *
+ * The transformation matrix should be a square matrix.
+ */
+__isl_give isl_basic_set *isl_basic_set_transform_dims(
+	__isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned first,
+	__isl_take isl_mat *trans)
+{
+	return isl_basic_map_transform_dims(bset, type, first, trans);
+}
diff --git a/final/lib/External/isl/isl_map_lexopt_templ.c b/final/lib/External/isl/isl_map_lexopt_templ.c
new file mode 100644
index 0000000..780a54f
--- /dev/null
+++ b/final/lib/External/isl/isl_map_lexopt_templ.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+/* Function for computing the lexicographic optimum of a map
+ * in the form of either an isl_map or an isl_pw_multi_aff.
+ */
+
+#define xSF(TYPE,SUFFIX) TYPE ## SUFFIX
+#define SF(TYPE,SUFFIX) xSF(TYPE,SUFFIX)
+
+/* Compute the lexicographic minimum (or maximum if "flags" includes
+ * ISL_OPT_MAX) of "bmap" over the domain "dom" and return the result.
+ * If "empty" is not NULL, then *empty is assigned a set that
+ * contains those parts of the domain where there is no solution.
+ * If "flags" includes ISL_OPT_FULL, then "dom" is NULL and the optimum
+ * should be computed over the domain of "bmap".  "empty" is also NULL
+ * in this case.
+ * If "bmap" is marked as rational (ISL_BASIC_MAP_RATIONAL),
+ * then the rational optimum is computed.  Otherwise, the integral optimum
+ * is computed.
+ */
+static __isl_give TYPE *SF(isl_basic_map_partial_lexopt,SUFFIX)(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, unsigned flags)
+{
+	return SF(isl_tab_basic_map_partial_lexopt,SUFFIX)(bmap, dom, empty,
+							    flags);
+}
+
+__isl_give TYPE *SF(isl_basic_map_partial_lexmax,SUFFIX)(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty)
+{
+	unsigned flags = ISL_OPT_MAX;
+	return SF(isl_basic_map_partial_lexopt,SUFFIX)(bmap, dom, empty, flags);
+}
+
+__isl_give TYPE *SF(isl_basic_map_partial_lexmin,SUFFIX)(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty)
+{
+	unsigned flags = 0;
+	return SF(isl_basic_map_partial_lexopt,SUFFIX)(bmap, dom, empty, flags);
+}
+
+__isl_give TYPE *SF(isl_basic_set_partial_lexmin,SUFFIX)(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty)
+{
+	return SF(isl_basic_map_partial_lexmin,SUFFIX)(bset, dom, empty);
+}
+
+__isl_give TYPE *SF(isl_basic_set_partial_lexmax,SUFFIX)(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty)
+{
+	return SF(isl_basic_map_partial_lexmax,SUFFIX)(bset, dom, empty);
+}
+
+/* Given a basic map "bmap", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in dom.
+ * If empty is not NULL, then set *empty to those elements in dom
+ * that do not have an image element.
+ * If "flags" includes ISL_OPT_FULL, then "dom" is NULL and the optimum
+ * should be computed over the domain of "bmap".  "empty" is also NULL
+ * in this case.
+ *
+ * We first make sure the basic sets in dom are disjoint and then
+ * simply collect the results over each of the basic sets separately.
+ * We could probably improve the efficiency a bit by moving the union
+ * domain down into the parametric integer programming.
+ *
+ * If a full optimum is being computed (i.e., "flags" includes ISL_OPT_FULL),
+ * then no domain is given and there is then also no need to consider
+ * the disjuncts of the domain.
+ */
+static __isl_give TYPE *SF(basic_map_partial_lexopt,SUFFIX)(
+	__isl_take isl_basic_map *bmap, __isl_take isl_set *dom,
+	__isl_give isl_set **empty, unsigned flags)
+{
+	int i;
+	TYPE *res;
+	isl_set *all_empty;
+
+	if (ISL_FL_ISSET(flags, ISL_OPT_FULL))
+		return SF(isl_basic_map_partial_lexopt,SUFFIX)(bmap, NULL,
+								empty, flags);
+
+	dom = isl_set_make_disjoint(dom);
+	if (!dom)
+		goto error;
+
+	if (isl_set_plain_is_empty(dom)) {
+		isl_space *space = isl_basic_map_get_space(bmap);
+		if (empty)
+			*empty = dom;
+		else
+			isl_set_free(dom);
+		isl_basic_map_free(bmap);
+		return EMPTY(space);
+	}
+
+	res = SF(isl_basic_map_partial_lexopt,SUFFIX)(isl_basic_map_copy(bmap),
+			isl_basic_set_copy(dom->p[0]), empty, flags);
+
+	if (empty)
+		all_empty = *empty;
+	for (i = 1; i < dom->n; ++i) {
+		TYPE *res_i;
+
+		res_i = SF(isl_basic_map_partial_lexopt,SUFFIX)(
+				isl_basic_map_copy(bmap),
+				isl_basic_set_copy(dom->p[i]), empty, flags);
+
+		res = ADD(res, res_i);
+		if (empty)
+			all_empty = isl_set_union_disjoint(all_empty, *empty);
+	}
+
+	if (empty)
+		*empty = all_empty;
+	isl_set_free(dom);
+	isl_basic_map_free(bmap);
+	return res;
+error:
+	if (empty)
+		*empty = NULL;
+	isl_set_free(dom);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Compute the lexicographic minimum (or maximum if "flags" includes
+ * ISL_OPT_MAX) of "bmap" over its domain.
+ */
+__isl_give TYPE *SF(isl_basic_map_lexopt,SUFFIX)(
+	__isl_take isl_basic_map *bmap, unsigned flags)
+{
+	ISL_FL_SET(flags, ISL_OPT_FULL);
+	return SF(isl_basic_map_partial_lexopt,SUFFIX)(bmap, NULL, NULL, flags);
+}
+
+__isl_give TYPE *SF(isl_basic_map_lexmin,SUFFIX)(__isl_take isl_basic_map *bmap)
+{
+	return SF(isl_basic_map_lexopt,SUFFIX)(bmap, 0);
+}
+
+static __isl_give TYPE *SF(isl_map_partial_lexopt_aligned,SUFFIX)(
+	__isl_take isl_map *map, __isl_take isl_set *dom,
+	__isl_give isl_set **empty, unsigned flags);
+/* This function is currently only used when TYPE is defined as isl_map. */
+static __isl_give TYPE *SF(isl_map_partial_lexopt,SUFFIX)(
+	__isl_take isl_map *map, __isl_take isl_set *dom,
+	__isl_give isl_set **empty, unsigned flags)
+	__attribute__ ((unused));
+
+/* Given a map "map", compute the lexicographically minimal
+ * (or maximal) image element for each domain element in dom.
+ * Set *empty to those elements in dom that do not have an image element.
+ *
+ * Align parameters if needed and then call isl_map_partial_lexopt_aligned.
+ */
+static __isl_give TYPE *SF(isl_map_partial_lexopt,SUFFIX)(
+	__isl_take isl_map *map, __isl_take isl_set *dom,
+	__isl_give isl_set **empty, unsigned flags)
+{
+	isl_bool aligned;
+
+	aligned = isl_map_set_has_equal_params(map, dom);
+	if (aligned < 0)
+		goto error;
+	if (aligned)
+		return SF(isl_map_partial_lexopt_aligned,SUFFIX)(map, dom,
+								empty, flags);
+	if (!isl_space_has_named_params(map->dim) ||
+	    !isl_space_has_named_params(dom->dim))
+		isl_die(map->ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	map = isl_map_align_params(map, isl_map_get_space(dom));
+	dom = isl_map_align_params(dom, isl_map_get_space(map));
+	return SF(isl_map_partial_lexopt_aligned,SUFFIX)(map, dom, empty,
+							flags);
+error:
+	if (empty)
+		*empty = NULL;
+	isl_set_free(dom);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Compute the lexicographic minimum (or maximum if "flags" includes
+ * ISL_OPT_MAX) of "map" over its domain.
+ */
+__isl_give TYPE *SF(isl_map_lexopt,SUFFIX)(__isl_take isl_map *map,
+	unsigned flags)
+{
+	ISL_FL_SET(flags, ISL_OPT_FULL);
+	return SF(isl_map_partial_lexopt_aligned,SUFFIX)(map, NULL, NULL,
+							flags);
+}
+
+__isl_give TYPE *SF(isl_map_lexmin,SUFFIX)(__isl_take isl_map *map)
+{
+	return SF(isl_map_lexopt,SUFFIX)(map, 0);
+}
+
+__isl_give TYPE *SF(isl_map_lexmax,SUFFIX)(__isl_take isl_map *map)
+{
+	return SF(isl_map_lexopt,SUFFIX)(map, ISL_OPT_MAX);
+}
+
+__isl_give TYPE *SF(isl_set_lexmin,SUFFIX)(__isl_take isl_set *set)
+{
+	return SF(isl_map_lexmin,SUFFIX)(set);
+}
+
+__isl_give TYPE *SF(isl_set_lexmax,SUFFIX)(__isl_take isl_set *set)
+{
+	return SF(isl_map_lexmax,SUFFIX)(set);
+}
diff --git a/final/lib/External/isl/isl_map_list.c b/final/lib/External/isl/isl_map_list.c
new file mode 100644
index 0000000..5e9305f
--- /dev/null
+++ b/final/lib/External/isl/isl_map_list.c
@@ -0,0 +1,32 @@
+#include <isl/map.h>
+#include <isl/union_map.h>
+
+#undef EL
+#define EL isl_basic_map
+
+#include <isl_list_templ.h>
+
+#undef BASE
+#define BASE basic_map
+
+#include <isl_list_templ.c>
+
+#undef EL
+#define EL isl_map
+
+#include <isl_list_templ.h>
+
+#undef BASE
+#define BASE map
+
+#include <isl_list_templ.c>
+
+#undef EL
+#define EL isl_union_map
+
+#include <isl_list_templ.h>
+
+#undef BASE
+#define BASE union_map
+
+#include <isl_list_templ.c>
diff --git a/final/lib/External/isl/isl_map_private.h b/final/lib/External/isl/isl_map_private.h
new file mode 100644
index 0000000..ba2937e
--- /dev/null
+++ b/final/lib/External/isl/isl_map_private.h
@@ -0,0 +1,557 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_MAP_PRIVATE_H
+#define ISL_MAP_PRIVATE_H
+
+#define isl_basic_set	isl_basic_map
+#define isl_maybe_isl_basic_set	isl_maybe_isl_basic_map
+#define isl_set		isl_map
+#define isl_basic_set_list	isl_basic_map_list
+#define isl_set_list	isl_map_list
+#include <isl/list.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl_reordering.h>
+#include <isl/vec.h>
+#include <isl/hash.h>
+#include <isl_blk.h>
+
+/* A "basic map" is a relation between two sets of variables,
+ * called the "in" and "out" variables.
+ * A "basic set" is a basic map with a zero-dimensional
+ * domain.
+ *
+ * It is implemented as a set with two extra fields:
+ * n_in is the number of in variables
+ * n_out is the number of out variables
+ * n_in + n_out should be equal to set.dim
+ */
+struct isl_basic_map {
+	int ref;
+#define ISL_BASIC_MAP_FINAL		(1 << 0)
+#define ISL_BASIC_MAP_EMPTY		(1 << 1)
+#define ISL_BASIC_MAP_NO_IMPLICIT	(1 << 2)
+#define ISL_BASIC_MAP_NO_REDUNDANT	(1 << 3)
+#define ISL_BASIC_MAP_RATIONAL		(1 << 4)
+#define ISL_BASIC_MAP_NORMALIZED	(1 << 5)
+#define ISL_BASIC_MAP_NORMALIZED_DIVS	(1 << 6)
+#define ISL_BASIC_MAP_ALL_EQUALITIES	(1 << 7)
+#define ISL_BASIC_MAP_REDUCED_COEFFICIENTS	(1 << 8)
+#define ISL_BASIC_SET_FINAL		(1 << 0)
+#define ISL_BASIC_SET_EMPTY		(1 << 1)
+#define ISL_BASIC_SET_NO_IMPLICIT	(1 << 2)
+#define ISL_BASIC_SET_NO_REDUNDANT	(1 << 3)
+#define ISL_BASIC_SET_RATIONAL		(1 << 4)
+#define ISL_BASIC_SET_NORMALIZED	(1 << 5)
+#define ISL_BASIC_SET_NORMALIZED_DIVS	(1 << 6)
+#define ISL_BASIC_SET_ALL_EQUALITIES	(1 << 7)
+#define ISL_BASIC_SET_REDUCED_COEFFICIENTS	(1 << 8)
+	unsigned flags;
+
+	struct isl_ctx *ctx;
+
+	isl_space *dim;
+	unsigned extra;
+
+	unsigned n_eq;
+	unsigned n_ineq;
+
+	size_t c_size;
+	isl_int **eq;
+	isl_int **ineq;
+
+	unsigned n_div;
+
+	isl_int **div;
+
+	struct isl_vec *sample;
+
+	struct isl_blk block;
+	struct isl_blk block2;
+};
+
+#undef EL
+#define EL isl_basic_set
+
+#include <isl_list_templ.h>
+
+/* A "map" is a (possibly disjoint) union of basic maps.
+ * A "set" is a (possibly disjoint) union of basic sets.
+ *
+ * Currently, the isl_set structure is identical to the isl_map structure
+ * and the library depends on this correspondence internally.
+ * However, users should not depend on this correspondence.
+ *
+ * "cached_simple_hull" contains copies of the unshifted and shifted
+ * simple hulls, if they have already been computed.  Otherwise,
+ * the entries are NULL.
+ */
+struct isl_map {
+	int ref;
+#define ISL_MAP_DISJOINT		(1 << 0)
+#define ISL_MAP_NORMALIZED		(1 << 1)
+#define ISL_SET_DISJOINT		(1 << 0)
+#define ISL_SET_NORMALIZED		(1 << 1)
+	unsigned flags;
+	isl_basic_map *cached_simple_hull[2];
+
+	struct isl_ctx *ctx;
+
+	isl_space *dim;
+
+	int n;
+
+	size_t size;
+	struct isl_basic_map *p[1];
+};
+
+#undef EL
+#define EL isl_set
+
+#include <isl_list_templ.h>
+
+__isl_give isl_basic_set *isl_basic_set_alloc(isl_ctx *ctx,
+	unsigned nparam, unsigned dim, unsigned extra,
+	unsigned n_eq, unsigned n_ineq);
+__isl_give isl_basic_set *isl_basic_set_extend(__isl_take isl_basic_set *base,
+	unsigned nparam, unsigned dim, unsigned extra,
+	unsigned n_eq, unsigned n_ineq);
+__isl_give isl_basic_set *isl_basic_set_extend_constraints(
+	__isl_take isl_basic_set *base, unsigned n_eq, unsigned n_ineq);
+__isl_give isl_basic_set *isl_basic_set_finalize(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_basic_set_dup(__isl_keep isl_basic_set *bset);
+__isl_give isl_basic_set *isl_basic_set_simplify(
+	__isl_take isl_basic_set *bset);
+
+__isl_give isl_basic_map *isl_basic_map_alloc(isl_ctx *ctx,
+	unsigned nparam, unsigned in, unsigned out, unsigned extra,
+	unsigned n_eq, unsigned n_ineq);
+__isl_give isl_basic_map *isl_basic_map_mark_final(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_map *isl_basic_map_finalize(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_map *isl_basic_map_extend(__isl_take isl_basic_map *base,
+	unsigned nparam, unsigned n_in, unsigned n_out, unsigned extra,
+	unsigned n_eq, unsigned n_ineq);
+__isl_give isl_basic_map *isl_basic_map_extend_constraints(
+	__isl_take isl_basic_map *base, unsigned n_eq, unsigned n_ineq);
+__isl_give isl_basic_map *isl_basic_map_simplify(
+	__isl_take isl_basic_map *bmap);
+
+__isl_give isl_set *isl_set_add_basic_set(__isl_take isl_set *set,
+	__isl_take isl_basic_set *bset);
+
+__isl_give isl_map *isl_map_add_basic_map(__isl_take isl_map *map,
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_dup(__isl_keep isl_map *map);
+
+__isl_give isl_basic_set *isl_basic_set_from_underlying_set(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *like);
+
+__isl_give isl_map *isl_map_realign(__isl_take isl_map *map,
+	__isl_take isl_reordering *r);
+__isl_give isl_set *isl_set_realign(__isl_take isl_set *set,
+	__isl_take isl_reordering *r);
+
+__isl_give isl_basic_map *isl_basic_map_reset(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type);
+__isl_give isl_map *isl_map_reset(__isl_take isl_map *map,
+	enum isl_dim_type type);
+
+__isl_keep isl_space *isl_basic_map_peek_space(
+	__isl_keep const isl_basic_map *bmap);
+__isl_keep isl_space *isl_basic_set_peek_space(__isl_keep isl_basic_set *bset);
+
+__isl_give isl_basic_set *isl_basic_set_reset_space(
+	__isl_take isl_basic_set *bset, __isl_take isl_space *dim);
+__isl_give isl_basic_map *isl_basic_map_reset_space(
+	__isl_take isl_basic_map *bmap, __isl_take isl_space *dim);
+__isl_give isl_map *isl_map_reset_space(__isl_take isl_map *map,
+	__isl_take isl_space *dim);
+
+unsigned isl_basic_map_offset(struct isl_basic_map *bmap,
+					enum isl_dim_type type);
+unsigned isl_basic_set_offset(__isl_keep isl_basic_set *bset,
+					enum isl_dim_type type);
+
+isl_bool isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap);
+int isl_map_may_be_set(__isl_keep isl_map *map);
+isl_bool isl_map_compatible_domain(__isl_keep isl_map *map,
+	__isl_keep isl_set *set);
+isl_bool isl_basic_map_compatible_domain(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_basic_set *bset);
+isl_bool isl_basic_map_compatible_range(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_basic_set *bset);
+
+__isl_give isl_basic_map *isl_basic_map_extend_space(
+	__isl_take isl_basic_map *base, __isl_take isl_space *dim,
+	unsigned extra, unsigned n_eq, unsigned n_ineq);
+__isl_give isl_basic_set *isl_basic_set_extend_space(
+	__isl_take isl_basic_set *base,
+		__isl_take isl_space *dim, unsigned extra,
+		unsigned n_eq, unsigned n_ineq);
+struct isl_basic_set *isl_basic_set_add_constraints(struct isl_basic_set *bset1,
+		struct isl_basic_set *bset2, unsigned pos);
+
+__isl_give isl_map *isl_map_grow(__isl_take isl_map *map, int n);
+struct isl_set *isl_set_grow(struct isl_set *set, int n);
+
+isl_bool isl_basic_set_contains(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_vec *vec);
+isl_bool isl_basic_map_contains(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_vec *vec);
+
+__isl_give isl_basic_set *isl_basic_set_alloc_space(__isl_take isl_space *dim,
+		unsigned extra, unsigned n_eq, unsigned n_ineq);
+__isl_give isl_set *isl_set_alloc_space(__isl_take isl_space *dim, int n,
+	unsigned flags);
+__isl_give isl_basic_map *isl_basic_map_alloc_space(__isl_take isl_space *dim,
+		unsigned extra, unsigned n_eq, unsigned n_ineq);
+__isl_give isl_map *isl_map_alloc_space(__isl_take isl_space *dim, int n,
+	unsigned flags);
+
+int isl_basic_map_alloc_equality(struct isl_basic_map *bmap);
+int isl_basic_set_alloc_equality(struct isl_basic_set *bset);
+int isl_basic_set_free_inequality(struct isl_basic_set *bset, unsigned n);
+int isl_basic_map_free_equality(struct isl_basic_map *bmap, unsigned n);
+int isl_basic_set_free_equality(struct isl_basic_set *bset, unsigned n);
+int isl_basic_set_alloc_inequality(__isl_keep isl_basic_set *bset);
+int isl_basic_map_alloc_inequality(__isl_keep isl_basic_map *bmap);
+int isl_basic_map_free_inequality(struct isl_basic_map *bmap, unsigned n);
+int isl_basic_map_alloc_div(struct isl_basic_map *bmap);
+__isl_give isl_basic_map *isl_basic_map_insert_div(
+	__isl_take isl_basic_map *bmap, int pos, __isl_keep isl_vec *div);
+int isl_basic_set_alloc_div(struct isl_basic_set *bset);
+isl_stat isl_basic_map_free_div(struct isl_basic_map *bmap, unsigned n);
+__isl_give isl_basic_map *isl_basic_map_drop_div(
+	__isl_take isl_basic_map *bmap, unsigned div);
+void isl_basic_map_inequality_to_equality(
+		struct isl_basic_map *bmap, unsigned pos);
+int isl_basic_map_drop_equality(struct isl_basic_map *bmap, unsigned pos);
+int isl_basic_set_drop_inequality(struct isl_basic_set *bset, unsigned pos);
+int isl_basic_map_drop_inequality(struct isl_basic_map *bmap, unsigned pos);
+__isl_give isl_basic_set *isl_basic_set_add_eq(__isl_take isl_basic_set *bset,
+	isl_int *eq);
+__isl_give isl_basic_map *isl_basic_map_add_eq(__isl_take isl_basic_map *bmap,
+	isl_int *eq);
+__isl_give isl_basic_set *isl_basic_set_add_ineq(__isl_take isl_basic_set *bset,
+	isl_int *ineq);
+__isl_give isl_basic_map *isl_basic_map_add_ineq(__isl_take isl_basic_map *bmap,
+	isl_int *ineq);
+
+__isl_give isl_basic_set *isl_basic_set_tighten_outward(
+	__isl_take isl_basic_set *bset, __isl_keep isl_vec *vec);
+
+int isl_inequality_negate(struct isl_basic_map *bmap, unsigned pos);
+
+__isl_give isl_basic_set *isl_basic_set_cow(__isl_take isl_basic_set *bset);
+__isl_give isl_basic_map *isl_basic_map_cow(__isl_take isl_basic_map *bmap);
+__isl_give isl_set *isl_set_cow(__isl_take isl_set *set);
+__isl_give isl_map *isl_map_cow(__isl_take isl_map *map);
+
+uint32_t isl_basic_map_get_hash(__isl_keep isl_basic_map *bmap);
+
+__isl_give isl_set *isl_basic_set_list_union(
+	__isl_take isl_basic_set_list *list);
+
+__isl_give isl_basic_map *isl_basic_map_set_to_empty(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_set *isl_basic_set_set_to_empty(
+	__isl_take isl_basic_set *bset);
+struct isl_basic_set *isl_basic_set_order_divs(struct isl_basic_set *bset);
+void isl_basic_map_swap_div(struct isl_basic_map *bmap, int a, int b);
+void isl_basic_set_swap_div(struct isl_basic_set *bset, int a, int b);
+__isl_give isl_basic_map *isl_basic_map_order_divs(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_order_divs(__isl_take isl_map *map);
+__isl_give isl_basic_map *isl_basic_map_align_divs(
+	__isl_take isl_basic_map *dst, __isl_keep isl_basic_map *src);
+__isl_give isl_map *isl_map_align_divs_to_basic_map_list(
+	__isl_take isl_map *map, __isl_keep isl_basic_map_list *list);
+__isl_give isl_basic_map_list *isl_basic_map_list_align_divs_to_basic_map(
+	__isl_take isl_basic_map_list *list, __isl_keep isl_basic_map *bmap);
+__isl_give isl_map *isl_map_align_divs_internal(__isl_take isl_map *map);
+__isl_give isl_basic_set *isl_basic_set_sort_divs(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_basic_map *isl_basic_map_sort_divs(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map);
+__isl_give isl_basic_map *isl_basic_map_gauss(__isl_take isl_basic_map *bmap,
+	int *progress);
+__isl_give isl_basic_set *isl_basic_set_gauss(
+	__isl_take isl_basic_set *bset, int *progress);
+int isl_basic_map_constraint_cmp(__isl_keep isl_basic_map *bmap,
+	isl_int *c1, isl_int *c2);
+__isl_give isl_basic_map *isl_basic_map_sort_constraints(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_set *isl_basic_set_sort_constraints(
+	__isl_take isl_basic_set *bset);
+int isl_basic_map_plain_cmp(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2);
+isl_bool isl_basic_map_plain_is_equal(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2);
+__isl_give isl_basic_map *isl_basic_map_normalize_constraints(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_set *isl_basic_set_normalize_constraints(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_basic_map *isl_basic_map_implicit_equalities(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_set *isl_basic_map_underlying_set(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_set *isl_basic_set_underlying_set(
+		__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set_list *isl_basic_map_list_underlying_set(
+	__isl_take isl_basic_map_list *list);
+__isl_give isl_set *isl_map_underlying_set(__isl_take isl_map *map);
+__isl_give isl_basic_map *isl_basic_map_overlying_set(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_map *like);
+__isl_give isl_basic_map *isl_basic_map_drop_constraint_involving_unknown_divs(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_drop_constraint_involving_unknown_divs(
+	__isl_take isl_map *map);
+__isl_give isl_basic_set *isl_basic_set_drop_constraints_involving(
+	__isl_take isl_basic_set *bset, unsigned first, unsigned n);
+__isl_give isl_basic_set *isl_basic_set_drop(__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_basic_map *isl_basic_map_drop(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_set *isl_set_drop(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_basic_set *isl_basic_set_drop_dims(
+	__isl_take isl_basic_set *bset, unsigned first, unsigned n);
+__isl_give isl_map *isl_map_drop(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_basic_map *isl_basic_map_drop_unrelated_constraints(
+	__isl_take isl_basic_map *bmap, __isl_take int *group);
+
+__isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints(
+	__isl_take isl_basic_map *bmap, int *progress, int detect_divs);
+__isl_give isl_basic_map *isl_basic_map_detect_inequality_pairs(
+	__isl_take isl_basic_map *bmap, int *progress);
+
+__isl_give isl_map *isl_map_remove_empty_parts(__isl_take isl_map *map);
+struct isl_set *isl_set_remove_empty_parts(struct isl_set *set);
+__isl_give isl_map *isl_map_remove_obvious_duplicates(__isl_take isl_map *map);
+
+struct isl_set *isl_set_normalize(struct isl_set *set);
+
+struct isl_set *isl_set_drop_vars(
+		struct isl_set *set, unsigned first, unsigned n);
+
+__isl_give isl_basic_map *isl_basic_map_eliminate_vars(
+	__isl_take isl_basic_map *bmap, unsigned pos, unsigned n);
+struct isl_basic_set *isl_basic_set_eliminate_vars(
+	struct isl_basic_set *bset, unsigned pos, unsigned n);
+
+__isl_give isl_map *isl_map_eliminate(__isl_take isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_set *isl_set_eliminate(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+int isl_basic_map_add_div_constraint(__isl_keep isl_basic_map *bmap,
+	unsigned div, int sign);
+int isl_basic_map_add_div_constraints(struct isl_basic_map *bmap, unsigned div);
+__isl_give isl_basic_map *isl_basic_map_add_known_div_constraints(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_basic_map *isl_basic_map_drop_redundant_divs(
+	__isl_take isl_basic_map *bmap);
+
+__isl_give isl_basic_set *isl_basic_set_recession_cone(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_basic_set_lineality_space(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_set_combined_lineality_space(
+	__isl_take isl_set *set);
+
+__isl_give isl_basic_set *isl_basic_set_set_integral(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_basic_set *isl_basic_set_set_rational(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_set *isl_set_set_rational(__isl_take isl_set *set);
+__isl_give isl_basic_map *isl_basic_map_set_rational(
+	__isl_take isl_basic_map *bmap);
+__isl_give isl_map *isl_map_set_rational(__isl_take isl_map *map);
+
+isl_bool isl_map_is_rational(__isl_keep isl_map *map);
+isl_bool isl_set_is_rational(__isl_keep isl_set *set);
+
+isl_bool isl_map_has_rational(__isl_keep isl_map *map);
+isl_bool isl_set_has_rational(__isl_keep isl_set *set);
+
+__isl_give isl_basic_map *isl_basic_map_from_multi_aff2(
+	__isl_take isl_multi_aff *maff, int rational);
+
+struct isl_mat;
+
+__isl_give isl_basic_set *isl_basic_set_preimage(
+	__isl_take isl_basic_set *bset, __isl_take isl_mat *mat);
+__isl_give isl_set *isl_set_preimage(
+	__isl_take isl_set *set, __isl_take isl_mat *mat);
+
+__isl_give isl_basic_map *isl_basic_map_transform_dims(
+	__isl_take isl_basic_map *bmap, enum isl_dim_type type, unsigned first,
+	__isl_take isl_mat *trans);
+__isl_give isl_basic_set *isl_basic_set_transform_dims(
+	__isl_take isl_basic_set *bset, enum isl_dim_type type, unsigned first,
+	__isl_take isl_mat *trans);
+
+isl_int *isl_set_wrap_facet(__isl_keep isl_set *set,
+	isl_int *facet, isl_int *ridge);
+
+isl_bool isl_basic_map_contains_point(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_point *point);
+isl_bool isl_set_contains_point(__isl_keep isl_set *set,
+	__isl_keep isl_point *point);
+
+isl_stat isl_basic_set_vars_get_sign(__isl_keep isl_basic_set *bset,
+	unsigned first, unsigned n, int *signs);
+isl_stat isl_set_foreach_orthant(__isl_keep isl_set *set,
+	isl_stat (*fn)(__isl_take isl_set *orthant, int *signs, void *user),
+	void *user);
+
+isl_bool isl_basic_set_eq_is_stride(__isl_keep isl_basic_set *bset, int i);
+
+int isl_basic_map_add_div_constraints_var(__isl_keep isl_basic_map *bmap,
+	unsigned pos, isl_int *div);
+int isl_basic_set_add_div_constraints_var(__isl_keep isl_basic_set *bset,
+	unsigned pos, isl_int *div);
+isl_bool isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap,
+	isl_int *constraint, unsigned div);
+isl_bool isl_basic_set_is_div_constraint(__isl_keep isl_basic_set *bset,
+	isl_int *constraint, unsigned div);
+
+__isl_give isl_basic_set *isl_basic_set_from_local_space(
+	__isl_take isl_local_space *ls);
+__isl_give isl_basic_map *isl_basic_map_from_local_space(
+	__isl_take isl_local_space *ls);
+__isl_give isl_basic_set *isl_basic_set_expand_divs(
+	__isl_take isl_basic_set *bset, __isl_take isl_mat *div, int *exp);
+__isl_give isl_basic_map *isl_basic_map_expand_divs(
+	__isl_take isl_basic_set *bmap, __isl_take isl_mat *div, int *exp);
+
+int isl_basic_set_n_equality(__isl_keep isl_basic_set *bset);
+int isl_basic_map_n_equality(__isl_keep isl_basic_map *bmap);
+int isl_basic_set_n_inequality(__isl_keep isl_basic_set *bset);
+int isl_basic_map_n_inequality(__isl_keep isl_basic_map *bmap);
+
+__isl_give isl_basic_map *isl_basic_map_mark_div_unknown(
+	__isl_take isl_basic_map *bmap, int div);
+isl_bool isl_basic_map_div_is_marked_unknown(__isl_keep isl_basic_map *bmap,
+	int div);
+isl_bool isl_basic_map_div_is_known(__isl_keep isl_basic_map *bmap, int div);
+int isl_basic_set_first_unknown_div(__isl_keep isl_basic_set *bset);
+int isl_basic_map_first_unknown_div(__isl_keep isl_basic_map *bmap);
+isl_bool isl_basic_map_divs_known(__isl_keep isl_basic_map *bmap);
+isl_bool isl_map_divs_known(__isl_keep isl_map *map);
+__isl_give isl_mat *isl_basic_set_get_divs(__isl_keep isl_basic_set *bset);
+__isl_give isl_mat *isl_basic_map_get_divs(__isl_keep isl_basic_map *bmap);
+
+__isl_give isl_map *isl_map_inline_foreach_basic_map(__isl_take isl_map *map,
+	__isl_give isl_basic_map *(*fn)(__isl_take isl_basic_map *bmap));
+
+isl_stat isl_map_check_named_params(__isl_keep isl_map *map);
+
+isl_bool isl_map_has_equal_params(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2);
+isl_bool isl_basic_set_space_has_equal_params(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_space *space);
+isl_bool isl_set_space_has_equal_params(__isl_keep isl_set *set,
+	__isl_keep isl_space *space);
+isl_bool isl_map_space_has_equal_params(__isl_keep isl_map *map,
+	__isl_keep isl_space *space);
+
+__isl_give isl_map *isl_map_align_params_map_map_and(
+	__isl_take isl_map *map1, __isl_take isl_map *map2,
+	__isl_give isl_map *(*fn)(__isl_take isl_map *map1,
+				    __isl_take isl_map *map2));
+isl_bool isl_map_align_params_map_map_and_test(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2,
+	isl_bool (*fn)(__isl_keep isl_map *map1, __isl_keep isl_map *map2));
+
+isl_stat isl_basic_map_foreach_lexopt(__isl_keep isl_basic_map *bmap, int max,
+	isl_stat (*fn)(__isl_take isl_basic_set *dom,
+		__isl_take isl_aff_list *list, void *user),
+	void *user);
+
+__isl_give isl_set *isl_set_substitute(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs);
+
+__isl_give isl_set *isl_set_gist_params_basic_set(__isl_take isl_set *set,
+	__isl_take isl_basic_set *context);
+
+isl_bool isl_map_compatible_range(__isl_keep isl_map *map,
+	__isl_keep isl_set *set);
+
+isl_bool isl_basic_map_plain_is_non_empty(__isl_keep isl_basic_map *bmap);
+isl_bool isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap);
+
+isl_bool isl_map_is_set(__isl_keep isl_map *map);
+
+isl_bool isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset,
+	unsigned dim, isl_int *val);
+
+__isl_give isl_set *isl_set_plain_gist_basic_set(__isl_take isl_set *set,
+	__isl_take isl_basic_set *context);
+__isl_give isl_map *isl_map_plain_gist_basic_map(__isl_take isl_map *map,
+	__isl_take isl_basic_map *context);
+__isl_give isl_map *isl_map_plain_gist(__isl_take isl_map *map,
+	__isl_take isl_map *context);
+
+__isl_give isl_basic_set *isl_basic_set_plain_affine_hull(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_basic_map *isl_basic_map_plain_affine_hull(
+	__isl_take isl_basic_map *bmap);
+
+isl_stat isl_basic_set_dim_residue_class(__isl_keep isl_basic_set *bset,
+	int pos, isl_int *modulo, isl_int *residue);
+isl_stat isl_set_dim_residue_class(__isl_keep isl_set *set,
+	int pos, isl_int *modulo, isl_int *residue);
+
+__isl_give isl_basic_set *isl_basic_set_fix(__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned pos, isl_int value);
+__isl_give isl_basic_map *isl_basic_map_fix(__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, isl_int value);
+__isl_give isl_set *isl_set_fix(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, isl_int value);
+isl_bool isl_map_plain_is_fixed(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos, isl_int *val);
+
+int isl_basic_map_output_defining_equality(__isl_keep isl_basic_map *bmap,
+	int pos, int *div, int *ineq);
+
+__isl_give isl_basic_map *isl_basic_map_reduce_coefficients(
+	__isl_take isl_basic_map *bmap);
+
+__isl_give isl_basic_map *isl_basic_map_shift_div(
+	__isl_take isl_basic_map *bmap, int div, int pos, isl_int shift);
+
+__isl_give isl_basic_map_list *isl_map_get_basic_map_list(
+	__isl_keep isl_map *map);
+
+__isl_give isl_map *isl_map_fixed_power(__isl_take isl_map *map, isl_int exp);
+
+int isl_basic_set_count_upto(__isl_keep isl_basic_set *bset,
+	isl_int max, isl_int *count);
+int isl_set_count_upto(__isl_keep isl_set *set, isl_int max, isl_int *count);
+
+__isl_give isl_mat *isl_basic_set_extract_equalities(
+	__isl_keep isl_basic_set *bset);
+
+isl_bool isl_basic_map_equal_div_expr_part(__isl_keep isl_basic_map *bmap1,
+	int pos1, __isl_keep isl_basic_map *bmap2, int pos2,
+	unsigned first, unsigned n);
+isl_bool isl_basic_map_equal_div_expr_except_constant(
+	__isl_keep isl_basic_map *bmap1, int pos1,
+	__isl_keep isl_basic_map *bmap2, int pos2);
+__isl_give isl_basic_map *isl_basic_map_set_div_expr_constant_num_si_inplace(
+	__isl_take isl_basic_map *bmap, int div, int value);
+
+#endif
diff --git a/final/lib/External/isl/isl_map_simplify.c b/final/lib/External/isl/isl_map_simplify.c
new file mode 100644
index 0000000..06806d9
--- /dev/null
+++ b/final/lib/External/isl/isl_map_simplify.c
@@ -0,0 +1,5219 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2012-2013 Ecole Normale Superieure
+ * Copyright 2014-2015 INRIA Rocquencourt
+ * Copyright 2016      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include "isl_equalities.h"
+#include <isl/map.h>
+#include <isl_seq.h>
+#include "isl_tab.h"
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+
+#include <bset_to_bmap.c>
+#include <bset_from_bmap.c>
+#include <set_to_map.c>
+#include <set_from_map.c>
+
+static void swap_equality(struct isl_basic_map *bmap, int a, int b)
+{
+	isl_int *t = bmap->eq[a];
+	bmap->eq[a] = bmap->eq[b];
+	bmap->eq[b] = t;
+}
+
+static void swap_inequality(struct isl_basic_map *bmap, int a, int b)
+{
+	if (a != b) {
+		isl_int *t = bmap->ineq[a];
+		bmap->ineq[a] = bmap->ineq[b];
+		bmap->ineq[b] = t;
+	}
+}
+
+__isl_give isl_basic_map *isl_basic_map_normalize_constraints(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+	isl_int gcd;
+	unsigned total = isl_basic_map_total_dim(bmap);
+
+	if (!bmap)
+		return NULL;
+
+	isl_int_init(gcd);
+	for (i = bmap->n_eq - 1; i >= 0; --i) {
+		isl_seq_gcd(bmap->eq[i]+1, total, &gcd);
+		if (isl_int_is_zero(gcd)) {
+			if (!isl_int_is_zero(bmap->eq[i][0])) {
+				bmap = isl_basic_map_set_to_empty(bmap);
+				break;
+			}
+			isl_basic_map_drop_equality(bmap, i);
+			continue;
+		}
+		if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+			isl_int_gcd(gcd, gcd, bmap->eq[i][0]);
+		if (isl_int_is_one(gcd))
+			continue;
+		if (!isl_int_is_divisible_by(bmap->eq[i][0], gcd)) {
+			bmap = isl_basic_map_set_to_empty(bmap);
+			break;
+		}
+		isl_seq_scale_down(bmap->eq[i], bmap->eq[i], gcd, 1+total);
+	}
+
+	for (i = bmap->n_ineq - 1; i >= 0; --i) {
+		isl_seq_gcd(bmap->ineq[i]+1, total, &gcd);
+		if (isl_int_is_zero(gcd)) {
+			if (isl_int_is_neg(bmap->ineq[i][0])) {
+				bmap = isl_basic_map_set_to_empty(bmap);
+				break;
+			}
+			isl_basic_map_drop_inequality(bmap, i);
+			continue;
+		}
+		if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+			isl_int_gcd(gcd, gcd, bmap->ineq[i][0]);
+		if (isl_int_is_one(gcd))
+			continue;
+		isl_int_fdiv_q(bmap->ineq[i][0], bmap->ineq[i][0], gcd);
+		isl_seq_scale_down(bmap->ineq[i]+1, bmap->ineq[i]+1, gcd, total);
+	}
+	isl_int_clear(gcd);
+
+	return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_normalize_constraints(
+	__isl_take isl_basic_set *bset)
+{
+	isl_basic_map *bmap = bset_to_bmap(bset);
+	return bset_from_bmap(isl_basic_map_normalize_constraints(bmap));
+}
+
+/* Reduce the coefficient of the variable at position "pos"
+ * in integer division "div", such that it lies in the half-open
+ * interval (1/2,1/2], extracting any excess value from this integer division.
+ * "pos" is as determined by isl_basic_map_offset, i.e., pos == 0
+ * corresponds to the constant term.
+ *
+ * That is, the integer division is of the form
+ *
+ *	floor((... + (c * d + r) * x_pos + ...)/d)
+ *
+ * with -d < 2 * r <= d.
+ * Replace it by
+ *
+ *	floor((... + r * x_pos + ...)/d) + c * x_pos
+ *
+ * If 2 * ((c * d + r) % d) <= d, then c = floor((c * d + r)/d).
+ * Otherwise, c = floor((c * d + r)/d) + 1.
+ *
+ * This is the same normalization that is performed by isl_aff_floor.
+ */
+static __isl_give isl_basic_map *reduce_coefficient_in_div(
+	__isl_take isl_basic_map *bmap, int div, int pos)
+{
+	isl_int shift;
+	int add_one;
+
+	isl_int_init(shift);
+	isl_int_fdiv_r(shift, bmap->div[div][1 + pos], bmap->div[div][0]);
+	isl_int_mul_ui(shift, shift, 2);
+	add_one = isl_int_gt(shift, bmap->div[div][0]);
+	isl_int_fdiv_q(shift, bmap->div[div][1 + pos], bmap->div[div][0]);
+	if (add_one)
+		isl_int_add_ui(shift, shift, 1);
+	isl_int_neg(shift, shift);
+	bmap = isl_basic_map_shift_div(bmap, div, pos, shift);
+	isl_int_clear(shift);
+
+	return bmap;
+}
+
+/* Does the coefficient of the variable at position "pos"
+ * in integer division "div" need to be reduced?
+ * That is, does it lie outside the half-open interval (1/2,1/2]?
+ * The coefficient c/d lies outside this interval if abs(2 * c) >= d and
+ * 2 * c != d.
+ */
+static isl_bool needs_reduction(__isl_keep isl_basic_map *bmap, int div,
+	int pos)
+{
+	isl_bool r;
+
+	if (isl_int_is_zero(bmap->div[div][1 + pos]))
+		return isl_bool_false;
+
+	isl_int_mul_ui(bmap->div[div][1 + pos], bmap->div[div][1 + pos], 2);
+	r = isl_int_abs_ge(bmap->div[div][1 + pos], bmap->div[div][0]) &&
+	    !isl_int_eq(bmap->div[div][1 + pos], bmap->div[div][0]);
+	isl_int_divexact_ui(bmap->div[div][1 + pos],
+			    bmap->div[div][1 + pos], 2);
+
+	return r;
+}
+
+/* Reduce the coefficients (including the constant term) of
+ * integer division "div", if needed.
+ * In particular, make sure all coefficients lie in
+ * the half-open interval (1/2,1/2].
+ */
+static __isl_give isl_basic_map *reduce_div_coefficients_of_div(
+	__isl_take isl_basic_map *bmap, int div)
+{
+	int i;
+	unsigned total = 1 + isl_basic_map_total_dim(bmap);
+
+	for (i = 0; i < total; ++i) {
+		isl_bool reduce;
+
+		reduce = needs_reduction(bmap, div, i);
+		if (reduce < 0)
+			return isl_basic_map_free(bmap);
+		if (!reduce)
+			continue;
+		bmap = reduce_coefficient_in_div(bmap, div, i);
+		if (!bmap)
+			break;
+	}
+
+	return bmap;
+}
+
+/* Reduce the coefficients (including the constant term) of
+ * the known integer divisions, if needed
+ * In particular, make sure all coefficients lie in
+ * the half-open interval (1/2,1/2].
+ */
+static __isl_give isl_basic_map *reduce_div_coefficients(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+
+	if (!bmap)
+		return NULL;
+	if (bmap->n_div == 0)
+		return bmap;
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		bmap = reduce_div_coefficients_of_div(bmap, i);
+		if (!bmap)
+			break;
+	}
+
+	return bmap;
+}
+
+/* Remove any common factor in numerator and denominator of the div expression,
+ * not taking into account the constant term.
+ * That is, if the div is of the form
+ *
+ *	floor((a + m f(x))/(m d))
+ *
+ * then replace it by
+ *
+ *	floor((floor(a/m) + f(x))/d)
+ *
+ * The difference {a/m}/d in the argument satisfies 0 <= {a/m}/d < 1/d
+ * and can therefore not influence the result of the floor.
+ */
+static void normalize_div_expression(__isl_keep isl_basic_map *bmap, int div)
+{
+	unsigned total = isl_basic_map_total_dim(bmap);
+	isl_ctx *ctx = bmap->ctx;
+
+	if (isl_int_is_zero(bmap->div[div][0]))
+		return;
+	isl_seq_gcd(bmap->div[div] + 2, total, &ctx->normalize_gcd);
+	isl_int_gcd(ctx->normalize_gcd, ctx->normalize_gcd, bmap->div[div][0]);
+	if (isl_int_is_one(ctx->normalize_gcd))
+		return;
+	isl_int_fdiv_q(bmap->div[div][1], bmap->div[div][1],
+			ctx->normalize_gcd);
+	isl_int_divexact(bmap->div[div][0], bmap->div[div][0],
+			ctx->normalize_gcd);
+	isl_seq_scale_down(bmap->div[div] + 2, bmap->div[div] + 2,
+			ctx->normalize_gcd, total);
+}
+
+/* Remove any common factor in numerator and denominator of a div expression,
+ * not taking into account the constant term.
+ * That is, look for any div of the form
+ *
+ *	floor((a + m f(x))/(m d))
+ *
+ * and replace it by
+ *
+ *	floor((floor(a/m) + f(x))/d)
+ *
+ * The difference {a/m}/d in the argument satisfies 0 <= {a/m}/d < 1/d
+ * and can therefore not influence the result of the floor.
+ */
+static __isl_give isl_basic_map *normalize_div_expressions(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+
+	if (!bmap)
+		return NULL;
+	if (bmap->n_div == 0)
+		return bmap;
+
+	for (i = 0; i < bmap->n_div; ++i)
+		normalize_div_expression(bmap, i);
+
+	return bmap;
+}
+
+/* Assumes divs have been ordered if keep_divs is set.
+ */
+static void eliminate_var_using_equality(struct isl_basic_map *bmap,
+	unsigned pos, isl_int *eq, int keep_divs, int *progress)
+{
+	unsigned total;
+	unsigned space_total;
+	int k;
+	int last_div;
+
+	total = isl_basic_map_total_dim(bmap);
+	space_total = isl_space_dim(bmap->dim, isl_dim_all);
+	last_div = isl_seq_last_non_zero(eq + 1 + space_total, bmap->n_div);
+	for (k = 0; k < bmap->n_eq; ++k) {
+		if (bmap->eq[k] == eq)
+			continue;
+		if (isl_int_is_zero(bmap->eq[k][1+pos]))
+			continue;
+		if (progress)
+			*progress = 1;
+		isl_seq_elim(bmap->eq[k], eq, 1+pos, 1+total, NULL);
+		isl_seq_normalize(bmap->ctx, bmap->eq[k], 1 + total);
+	}
+
+	for (k = 0; k < bmap->n_ineq; ++k) {
+		if (isl_int_is_zero(bmap->ineq[k][1+pos]))
+			continue;
+		if (progress)
+			*progress = 1;
+		isl_seq_elim(bmap->ineq[k], eq, 1+pos, 1+total, NULL);
+		isl_seq_normalize(bmap->ctx, bmap->ineq[k], 1 + total);
+		ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	}
+
+	for (k = 0; k < bmap->n_div; ++k) {
+		if (isl_int_is_zero(bmap->div[k][0]))
+			continue;
+		if (isl_int_is_zero(bmap->div[k][1+1+pos]))
+			continue;
+		if (progress)
+			*progress = 1;
+		/* We need to be careful about circular definitions,
+		 * so for now we just remove the definition of div k
+		 * if the equality contains any divs.
+		 * If keep_divs is set, then the divs have been ordered
+		 * and we can keep the definition as long as the result
+		 * is still ordered.
+		 */
+		if (last_div == -1 || (keep_divs && last_div < k)) {
+			isl_seq_elim(bmap->div[k]+1, eq,
+					1+pos, 1+total, &bmap->div[k][0]);
+			normalize_div_expression(bmap, k);
+		} else
+			isl_seq_clr(bmap->div[k], 1 + total);
+		ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	}
+}
+
+/* Assumes divs have been ordered if keep_divs is set.
+ */
+static __isl_give isl_basic_map *eliminate_div(__isl_take isl_basic_map *bmap,
+	isl_int *eq, unsigned div, int keep_divs)
+{
+	unsigned pos = isl_space_dim(bmap->dim, isl_dim_all) + div;
+
+	eliminate_var_using_equality(bmap, pos, eq, keep_divs, NULL);
+
+	bmap = isl_basic_map_drop_div(bmap, div);
+
+	return bmap;
+}
+
+/* Check if elimination of div "div" using equality "eq" would not
+ * result in a div depending on a later div.
+ */
+static isl_bool ok_to_eliminate_div(__isl_keep isl_basic_map *bmap, isl_int *eq,
+	unsigned div)
+{
+	int k;
+	int last_div;
+	unsigned space_total = isl_space_dim(bmap->dim, isl_dim_all);
+	unsigned pos = space_total + div;
+
+	last_div = isl_seq_last_non_zero(eq + 1 + space_total, bmap->n_div);
+	if (last_div < 0 || last_div <= div)
+		return isl_bool_true;
+
+	for (k = 0; k <= last_div; ++k) {
+		if (isl_int_is_zero(bmap->div[k][0]))
+			continue;
+		if (!isl_int_is_zero(bmap->div[k][1 + 1 + pos]))
+			return isl_bool_false;
+	}
+
+	return isl_bool_true;
+}
+
+/* Eliminate divs based on equalities
+ */
+static __isl_give isl_basic_map *eliminate_divs_eq(
+	__isl_take isl_basic_map *bmap, int *progress)
+{
+	int d;
+	int i;
+	int modified = 0;
+	unsigned off;
+
+	bmap = isl_basic_map_order_divs(bmap);
+
+	if (!bmap)
+		return NULL;
+
+	off = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (d = bmap->n_div - 1; d >= 0 ; --d) {
+		for (i = 0; i < bmap->n_eq; ++i) {
+			isl_bool ok;
+
+			if (!isl_int_is_one(bmap->eq[i][off + d]) &&
+			    !isl_int_is_negone(bmap->eq[i][off + d]))
+				continue;
+			ok = ok_to_eliminate_div(bmap, bmap->eq[i], d);
+			if (ok < 0)
+				return isl_basic_map_free(bmap);
+			if (!ok)
+				continue;
+			modified = 1;
+			*progress = 1;
+			bmap = eliminate_div(bmap, bmap->eq[i], d, 1);
+			if (isl_basic_map_drop_equality(bmap, i) < 0)
+				return isl_basic_map_free(bmap);
+			break;
+		}
+	}
+	if (modified)
+		return eliminate_divs_eq(bmap, progress);
+	return bmap;
+}
+
+/* Eliminate divs based on inequalities
+ */
+static __isl_give isl_basic_map *eliminate_divs_ineq(
+	__isl_take isl_basic_map *bmap, int *progress)
+{
+	int d;
+	int i;
+	unsigned off;
+	struct isl_ctx *ctx;
+
+	if (!bmap)
+		return NULL;
+
+	ctx = bmap->ctx;
+	off = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (d = bmap->n_div - 1; d >= 0 ; --d) {
+		for (i = 0; i < bmap->n_eq; ++i)
+			if (!isl_int_is_zero(bmap->eq[i][off + d]))
+				break;
+		if (i < bmap->n_eq)
+			continue;
+		for (i = 0; i < bmap->n_ineq; ++i)
+			if (isl_int_abs_gt(bmap->ineq[i][off + d], ctx->one))
+				break;
+		if (i < bmap->n_ineq)
+			continue;
+		*progress = 1;
+		bmap = isl_basic_map_eliminate_vars(bmap, (off-1)+d, 1);
+		if (!bmap || ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+			break;
+		bmap = isl_basic_map_drop_div(bmap, d);
+		if (!bmap)
+			break;
+	}
+	return bmap;
+}
+
+/* Does the equality constraint at position "eq" in "bmap" involve
+ * any local variables in the range [first, first + n)
+ * that are not marked as having an explicit representation?
+ */
+static isl_bool bmap_eq_involves_unknown_divs(__isl_keep isl_basic_map *bmap,
+	int eq, unsigned first, unsigned n)
+{
+	unsigned o_div;
+	int i;
+
+	if (!bmap)
+		return isl_bool_error;
+
+	o_div = isl_basic_map_offset(bmap, isl_dim_div);
+	for (i = 0; i < n; ++i) {
+		isl_bool unknown;
+
+		if (isl_int_is_zero(bmap->eq[eq][o_div + first + i]))
+			continue;
+		unknown = isl_basic_map_div_is_marked_unknown(bmap, first + i);
+		if (unknown < 0)
+			return isl_bool_error;
+		if (unknown)
+			return isl_bool_true;
+	}
+
+	return isl_bool_false;
+}
+
+/* The last local variable involved in the equality constraint
+ * at position "eq" in "bmap" is the local variable at position "div".
+ * It can therefore be used to extract an explicit representation
+ * for that variable.
+ * Do so unless the local variable already has an explicit representation or
+ * the explicit representation would involve any other local variables
+ * that in turn do not have an explicit representation.
+ * An equality constraint involving local variables without an explicit
+ * representation can be used in isl_basic_map_drop_redundant_divs
+ * to separate out an independent local variable.  Introducing
+ * an explicit representation here would block this transformation,
+ * while the partial explicit representation in itself is not very useful.
+ * Set *progress if anything is changed.
+ *
+ * The equality constraint is of the form
+ *
+ *	f(x) + n e >= 0
+ *
+ * with n a positive number.  The explicit representation derived from
+ * this constraint is
+ *
+ *	floor((-f(x))/n)
+ */
+static __isl_give isl_basic_map *set_div_from_eq(__isl_take isl_basic_map *bmap,
+	int div, int eq, int *progress)
+{
+	unsigned total, o_div;
+	isl_bool involves;
+
+	if (!bmap)
+		return NULL;
+
+	if (!isl_int_is_zero(bmap->div[div][0]))
+		return bmap;
+
+	involves = bmap_eq_involves_unknown_divs(bmap, eq, 0, div);
+	if (involves < 0)
+		return isl_basic_map_free(bmap);
+	if (involves)
+		return bmap;
+
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	o_div = isl_basic_map_offset(bmap, isl_dim_div);
+	isl_seq_neg(bmap->div[div] + 1, bmap->eq[eq], 1 + total);
+	isl_int_set_si(bmap->div[div][1 + o_div + div], 0);
+	isl_int_set(bmap->div[div][0], bmap->eq[eq][o_div + div]);
+	if (progress)
+		*progress = 1;
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+
+	return bmap;
+}
+
+__isl_give isl_basic_map *isl_basic_map_gauss(__isl_take isl_basic_map *bmap,
+	int *progress)
+{
+	int k;
+	int done;
+	int last_var;
+	unsigned total_var;
+	unsigned total;
+
+	bmap = isl_basic_map_order_divs(bmap);
+
+	if (!bmap)
+		return NULL;
+
+	total = isl_basic_map_total_dim(bmap);
+	total_var = total - bmap->n_div;
+
+	last_var = total - 1;
+	for (done = 0; done < bmap->n_eq; ++done) {
+		for (; last_var >= 0; --last_var) {
+			for (k = done; k < bmap->n_eq; ++k)
+				if (!isl_int_is_zero(bmap->eq[k][1+last_var]))
+					break;
+			if (k < bmap->n_eq)
+				break;
+		}
+		if (last_var < 0)
+			break;
+		if (k != done)
+			swap_equality(bmap, k, done);
+		if (isl_int_is_neg(bmap->eq[done][1+last_var]))
+			isl_seq_neg(bmap->eq[done], bmap->eq[done], 1+total);
+
+		eliminate_var_using_equality(bmap, last_var, bmap->eq[done], 1,
+						progress);
+
+		if (last_var >= total_var)
+			bmap = set_div_from_eq(bmap, last_var - total_var,
+						done, progress);
+		if (!bmap)
+			return NULL;
+	}
+	if (done == bmap->n_eq)
+		return bmap;
+	for (k = done; k < bmap->n_eq; ++k) {
+		if (isl_int_is_zero(bmap->eq[k][0]))
+			continue;
+		return isl_basic_map_set_to_empty(bmap);
+	}
+	isl_basic_map_free_equality(bmap, bmap->n_eq-done);
+	return bmap;
+}
+
+__isl_give isl_basic_set *isl_basic_set_gauss(
+	__isl_take isl_basic_set *bset, int *progress)
+{
+	return bset_from_bmap(isl_basic_map_gauss(bset_to_bmap(bset),
+							progress));
+}
+
+
+static unsigned int round_up(unsigned int v)
+{
+	int old_v = v;
+
+	while (v) {
+		old_v = v;
+		v ^= v & -v;
+	}
+	return old_v << 1;
+}
+
+/* Hash table of inequalities in a basic map.
+ * "index" is an array of addresses of inequalities in the basic map, some
+ * of which are NULL.  The inequalities are hashed on the coefficients
+ * except the constant term.
+ * "size" is the number of elements in the array and is always a power of two
+ * "bits" is the number of bits need to represent an index into the array.
+ * "total" is the total dimension of the basic map.
+ */
+struct isl_constraint_index {
+	unsigned int size;
+	int bits;
+	isl_int ***index;
+	unsigned total;
+};
+
+/* Fill in the "ci" data structure for holding the inequalities of "bmap".
+ */
+static isl_stat create_constraint_index(struct isl_constraint_index *ci,
+	__isl_keep isl_basic_map *bmap)
+{
+	isl_ctx *ctx;
+
+	ci->index = NULL;
+	if (!bmap)
+		return isl_stat_error;
+	ci->total = isl_basic_set_total_dim(bmap);
+	if (bmap->n_ineq == 0)
+		return isl_stat_ok;
+	ci->size = round_up(4 * (bmap->n_ineq + 1) / 3 - 1);
+	ci->bits = ffs(ci->size) - 1;
+	ctx = isl_basic_map_get_ctx(bmap);
+	ci->index = isl_calloc_array(ctx, isl_int **, ci->size);
+	if (!ci->index)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Free the memory allocated by create_constraint_index.
+ */
+static void constraint_index_free(struct isl_constraint_index *ci)
+{
+	free(ci->index);
+}
+
+/* Return the position in ci->index that contains the address of
+ * an inequality that is equal to *ineq up to the constant term,
+ * provided this address is not identical to "ineq".
+ * If there is no such inequality, then return the position where
+ * such an inequality should be inserted.
+ */
+static int hash_index_ineq(struct isl_constraint_index *ci, isl_int **ineq)
+{
+	int h;
+	uint32_t hash = isl_seq_get_hash_bits((*ineq) + 1, ci->total, ci->bits);
+	for (h = hash; ci->index[h]; h = (h+1) % ci->size)
+		if (ineq != ci->index[h] &&
+		    isl_seq_eq((*ineq) + 1, ci->index[h][0]+1, ci->total))
+			break;
+	return h;
+}
+
+/* Return the position in ci->index that contains the address of
+ * an inequality that is equal to the k'th inequality of "bmap"
+ * up to the constant term, provided it does not point to the very
+ * same inequality.
+ * If there is no such inequality, then return the position where
+ * such an inequality should be inserted.
+ */
+static int hash_index(struct isl_constraint_index *ci,
+	__isl_keep isl_basic_map *bmap, int k)
+{
+	return hash_index_ineq(ci, &bmap->ineq[k]);
+}
+
+static int set_hash_index(struct isl_constraint_index *ci,
+	__isl_keep isl_basic_set *bset, int k)
+{
+	return hash_index(ci, bset, k);
+}
+
+/* Fill in the "ci" data structure with the inequalities of "bset".
+ */
+static isl_stat setup_constraint_index(struct isl_constraint_index *ci,
+	__isl_keep isl_basic_set *bset)
+{
+	int k, h;
+
+	if (create_constraint_index(ci, bset) < 0)
+		return isl_stat_error;
+
+	for (k = 0; k < bset->n_ineq; ++k) {
+		h = set_hash_index(ci, bset, k);
+		ci->index[h] = &bset->ineq[k];
+	}
+
+	return isl_stat_ok;
+}
+
+/* Is the inequality ineq (obviously) redundant with respect
+ * to the constraints in "ci"?
+ *
+ * Look for an inequality in "ci" with the same coefficients and then
+ * check if the contant term of "ineq" is greater than or equal
+ * to the constant term of that inequality.  If so, "ineq" is clearly
+ * redundant.
+ *
+ * Note that hash_index_ineq ignores a stored constraint if it has
+ * the same address as the passed inequality.  It is ok to pass
+ * the address of a local variable here since it will never be
+ * the same as the address of a constraint in "ci".
+ */
+static isl_bool constraint_index_is_redundant(struct isl_constraint_index *ci,
+	isl_int *ineq)
+{
+	int h;
+
+	h = hash_index_ineq(ci, &ineq);
+	if (!ci->index[h])
+		return isl_bool_false;
+	return isl_int_ge(ineq[0], (*ci->index[h])[0]);
+}
+
+/* If we can eliminate more than one div, then we need to make
+ * sure we do it from last div to first div, in order not to
+ * change the position of the other divs that still need to
+ * be removed.
+ */
+static __isl_give isl_basic_map *remove_duplicate_divs(
+	__isl_take isl_basic_map *bmap, int *progress)
+{
+	unsigned int size;
+	int *index;
+	int *elim_for;
+	int k, l, h;
+	int bits;
+	struct isl_blk eq;
+	unsigned total_var;
+	unsigned total;
+	struct isl_ctx *ctx;
+
+	bmap = isl_basic_map_order_divs(bmap);
+	if (!bmap || bmap->n_div <= 1)
+		return bmap;
+
+	total_var = isl_space_dim(bmap->dim, isl_dim_all);
+	total = total_var + bmap->n_div;
+
+	ctx = bmap->ctx;
+	for (k = bmap->n_div - 1; k >= 0; --k)
+		if (!isl_int_is_zero(bmap->div[k][0]))
+			break;
+	if (k <= 0)
+		return bmap;
+
+	size = round_up(4 * bmap->n_div / 3 - 1);
+	if (size == 0)
+		return bmap;
+	elim_for = isl_calloc_array(ctx, int, bmap->n_div);
+	bits = ffs(size) - 1;
+	index = isl_calloc_array(ctx, int, size);
+	if (!elim_for || !index)
+		goto out;
+	eq = isl_blk_alloc(ctx, 1+total);
+	if (isl_blk_is_error(eq))
+		goto out;
+
+	isl_seq_clr(eq.data, 1+total);
+	index[isl_seq_get_hash_bits(bmap->div[k], 2+total, bits)] = k + 1;
+	for (--k; k >= 0; --k) {
+		uint32_t hash;
+
+		if (isl_int_is_zero(bmap->div[k][0]))
+			continue;
+
+		hash = isl_seq_get_hash_bits(bmap->div[k], 2+total, bits);
+		for (h = hash; index[h]; h = (h+1) % size)
+			if (isl_seq_eq(bmap->div[k],
+				       bmap->div[index[h]-1], 2+total))
+				break;
+		if (index[h]) {
+			*progress = 1;
+			l = index[h] - 1;
+			elim_for[l] = k + 1;
+		}
+		index[h] = k+1;
+	}
+	for (l = bmap->n_div - 1; l >= 0; --l) {
+		if (!elim_for[l])
+			continue;
+		k = elim_for[l] - 1;
+		isl_int_set_si(eq.data[1+total_var+k], -1);
+		isl_int_set_si(eq.data[1+total_var+l], 1);
+		bmap = eliminate_div(bmap, eq.data, l, 1);
+		if (!bmap)
+			break;
+		isl_int_set_si(eq.data[1+total_var+k], 0);
+		isl_int_set_si(eq.data[1+total_var+l], 0);
+	}
+
+	isl_blk_free(ctx, eq);
+out:
+	free(index);
+	free(elim_for);
+	return bmap;
+}
+
+static int n_pure_div_eq(struct isl_basic_map *bmap)
+{
+	int i, j;
+	unsigned total;
+
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+	for (i = 0, j = bmap->n_div-1; i < bmap->n_eq; ++i) {
+		while (j >= 0 && isl_int_is_zero(bmap->eq[i][1 + total + j]))
+			--j;
+		if (j < 0)
+			break;
+		if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total, j) != -1)
+			return 0;
+	}
+	return i;
+}
+
+/* Normalize divs that appear in equalities.
+ *
+ * In particular, we assume that bmap contains some equalities
+ * of the form
+ *
+ *	a x = m * e_i
+ *
+ * and we want to replace the set of e_i by a minimal set and
+ * such that the new e_i have a canonical representation in terms
+ * of the vector x.
+ * If any of the equalities involves more than one divs, then
+ * we currently simply bail out.
+ *
+ * Let us first additionally assume that all equalities involve
+ * a div.  The equalities then express modulo constraints on the
+ * remaining variables and we can use "parameter compression"
+ * to find a minimal set of constraints.  The result is a transformation
+ *
+ *	x = T(x') = x_0 + G x'
+ *
+ * with G a lower-triangular matrix with all elements below the diagonal
+ * non-negative and smaller than the diagonal element on the same row.
+ * We first normalize x_0 by making the same property hold in the affine
+ * T matrix.
+ * The rows i of G with a 1 on the diagonal do not impose any modulo
+ * constraint and simply express x_i = x'_i.
+ * For each of the remaining rows i, we introduce a div and a corresponding
+ * equality.  In particular
+ *
+ *	g_ii e_j = x_i - g_i(x')
+ *
+ * where each x'_k is replaced either by x_k (if g_kk = 1) or the
+ * corresponding div (if g_kk != 1).
+ *
+ * If there are any equalities not involving any div, then we
+ * first apply a variable compression on the variables x:
+ *
+ *	x = C x''	x'' = C_2 x
+ *
+ * and perform the above parameter compression on A C instead of on A.
+ * The resulting compression is then of the form
+ *
+ *	x'' = T(x') = x_0 + G x'
+ *
+ * and in constructing the new divs and the corresponding equalities,
+ * we have to replace each x'', i.e., the x'_k with (g_kk = 1),
+ * by the corresponding row from C_2.
+ */
+static __isl_give isl_basic_map *normalize_divs(__isl_take isl_basic_map *bmap,
+	int *progress)
+{
+	int i, j, k;
+	int total;
+	int div_eq;
+	struct isl_mat *B;
+	struct isl_vec *d;
+	struct isl_mat *T = NULL;
+	struct isl_mat *C = NULL;
+	struct isl_mat *C2 = NULL;
+	isl_int v;
+	int *pos = NULL;
+	int dropped, needed;
+
+	if (!bmap)
+		return NULL;
+
+	if (bmap->n_div == 0)
+		return bmap;
+
+	if (bmap->n_eq == 0)
+		return bmap;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS))
+		return bmap;
+
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+	div_eq = n_pure_div_eq(bmap);
+	if (div_eq == 0)
+		return bmap;
+
+	if (div_eq < bmap->n_eq) {
+		B = isl_mat_sub_alloc6(bmap->ctx, bmap->eq, div_eq,
+					bmap->n_eq - div_eq, 0, 1 + total);
+		C = isl_mat_variable_compression(B, &C2);
+		if (!C || !C2)
+			goto error;
+		if (C->n_col == 0) {
+			bmap = isl_basic_map_set_to_empty(bmap);
+			isl_mat_free(C);
+			isl_mat_free(C2);
+			goto done;
+		}
+	}
+
+	d = isl_vec_alloc(bmap->ctx, div_eq);
+	if (!d)
+		goto error;
+	for (i = 0, j = bmap->n_div-1; i < div_eq; ++i) {
+		while (j >= 0 && isl_int_is_zero(bmap->eq[i][1 + total + j]))
+			--j;
+		isl_int_set(d->block.data[i], bmap->eq[i][1 + total + j]);
+	}
+	B = isl_mat_sub_alloc6(bmap->ctx, bmap->eq, 0, div_eq, 0, 1 + total);
+
+	if (C) {
+		B = isl_mat_product(B, C);
+		C = NULL;
+	}
+
+	T = isl_mat_parameter_compression(B, d);
+	if (!T)
+		goto error;
+	if (T->n_col == 0) {
+		bmap = isl_basic_map_set_to_empty(bmap);
+		isl_mat_free(C2);
+		isl_mat_free(T);
+		goto done;
+	}
+	isl_int_init(v);
+	for (i = 0; i < T->n_row - 1; ++i) {
+		isl_int_fdiv_q(v, T->row[1 + i][0], T->row[1 + i][1 + i]);
+		if (isl_int_is_zero(v))
+			continue;
+		isl_mat_col_submul(T, 0, v, 1 + i);
+	}
+	isl_int_clear(v);
+	pos = isl_alloc_array(bmap->ctx, int, T->n_row);
+	if (!pos)
+		goto error;
+	/* We have to be careful because dropping equalities may reorder them */
+	dropped = 0;
+	for (j = bmap->n_div - 1; j >= 0; --j) {
+		for (i = 0; i < bmap->n_eq; ++i)
+			if (!isl_int_is_zero(bmap->eq[i][1 + total + j]))
+				break;
+		if (i < bmap->n_eq) {
+			bmap = isl_basic_map_drop_div(bmap, j);
+			isl_basic_map_drop_equality(bmap, i);
+			++dropped;
+		}
+	}
+	pos[0] = 0;
+	needed = 0;
+	for (i = 1; i < T->n_row; ++i) {
+		if (isl_int_is_one(T->row[i][i]))
+			pos[i] = i;
+		else
+			needed++;
+	}
+	if (needed > dropped) {
+		bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+				needed, needed, 0);
+		if (!bmap)
+			goto error;
+	}
+	for (i = 1; i < T->n_row; ++i) {
+		if (isl_int_is_one(T->row[i][i]))
+			continue;
+		k = isl_basic_map_alloc_div(bmap);
+		pos[i] = 1 + total + k;
+		isl_seq_clr(bmap->div[k] + 1, 1 + total + bmap->n_div);
+		isl_int_set(bmap->div[k][0], T->row[i][i]);
+		if (C2)
+			isl_seq_cpy(bmap->div[k] + 1, C2->row[i], 1 + total);
+		else
+			isl_int_set_si(bmap->div[k][1 + i], 1);
+		for (j = 0; j < i; ++j) {
+			if (isl_int_is_zero(T->row[i][j]))
+				continue;
+			if (pos[j] < T->n_row && C2)
+				isl_seq_submul(bmap->div[k] + 1, T->row[i][j],
+						C2->row[pos[j]], 1 + total);
+			else
+				isl_int_neg(bmap->div[k][1 + pos[j]],
+								T->row[i][j]);
+		}
+		j = isl_basic_map_alloc_equality(bmap);
+		isl_seq_neg(bmap->eq[j], bmap->div[k]+1, 1+total+bmap->n_div);
+		isl_int_set(bmap->eq[j][pos[i]], bmap->div[k][0]);
+	}
+	free(pos);
+	isl_mat_free(C2);
+	isl_mat_free(T);
+
+	if (progress)
+		*progress = 1;
+done:
+	ISL_F_SET(bmap, ISL_BASIC_MAP_NORMALIZED_DIVS);
+
+	return bmap;
+error:
+	free(pos);
+	isl_mat_free(C);
+	isl_mat_free(C2);
+	isl_mat_free(T);
+	return bmap;
+}
+
+static __isl_give isl_basic_map *set_div_from_lower_bound(
+	__isl_take isl_basic_map *bmap, int div, int ineq)
+{
+	unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+	isl_seq_neg(bmap->div[div] + 1, bmap->ineq[ineq], total + bmap->n_div);
+	isl_int_set(bmap->div[div][0], bmap->ineq[ineq][total + div]);
+	isl_int_add(bmap->div[div][1], bmap->div[div][1], bmap->div[div][0]);
+	isl_int_sub_ui(bmap->div[div][1], bmap->div[div][1], 1);
+	isl_int_set_si(bmap->div[div][1 + total + div], 0);
+
+	return bmap;
+}
+
+/* Check whether it is ok to define a div based on an inequality.
+ * To avoid the introduction of circular definitions of divs, we
+ * do not allow such a definition if the resulting expression would refer to
+ * any other undefined divs or if any known div is defined in
+ * terms of the unknown div.
+ */
+static isl_bool ok_to_set_div_from_bound(__isl_keep isl_basic_map *bmap,
+	int div, int ineq)
+{
+	int j;
+	unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+	/* Not defined in terms of unknown divs */
+	for (j = 0; j < bmap->n_div; ++j) {
+		if (div == j)
+			continue;
+		if (isl_int_is_zero(bmap->ineq[ineq][total + j]))
+			continue;
+		if (isl_int_is_zero(bmap->div[j][0]))
+			return isl_bool_false;
+	}
+
+	/* No other div defined in terms of this one => avoid loops */
+	for (j = 0; j < bmap->n_div; ++j) {
+		if (div == j)
+			continue;
+		if (isl_int_is_zero(bmap->div[j][0]))
+			continue;
+		if (!isl_int_is_zero(bmap->div[j][1 + total + div]))
+			return isl_bool_false;
+	}
+
+	return isl_bool_true;
+}
+
+/* Would an expression for div "div" based on inequality "ineq" of "bmap"
+ * be a better expression than the current one?
+ *
+ * If we do not have any expression yet, then any expression would be better.
+ * Otherwise we check if the last variable involved in the inequality
+ * (disregarding the div that it would define) is in an earlier position
+ * than the last variable involved in the current div expression.
+ */
+static isl_bool better_div_constraint(__isl_keep isl_basic_map *bmap,
+	int div, int ineq)
+{
+	unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+	int last_div;
+	int last_ineq;
+
+	if (isl_int_is_zero(bmap->div[div][0]))
+		return isl_bool_true;
+
+	if (isl_seq_last_non_zero(bmap->ineq[ineq] + total + div + 1,
+				  bmap->n_div - (div + 1)) >= 0)
+		return isl_bool_false;
+
+	last_ineq = isl_seq_last_non_zero(bmap->ineq[ineq], total + div);
+	last_div = isl_seq_last_non_zero(bmap->div[div] + 1,
+					 total + bmap->n_div);
+
+	return last_ineq < last_div;
+}
+
+/* Given two constraints "k" and "l" that are opposite to each other,
+ * except for the constant term, check if we can use them
+ * to obtain an expression for one of the hitherto unknown divs or
+ * a "better" expression for a div for which we already have an expression.
+ * "sum" is the sum of the constant terms of the constraints.
+ * If this sum is strictly smaller than the coefficient of one
+ * of the divs, then this pair can be used define the div.
+ * To avoid the introduction of circular definitions of divs, we
+ * do not use the pair if the resulting expression would refer to
+ * any other undefined divs or if any known div is defined in
+ * terms of the unknown div.
+ */
+static __isl_give isl_basic_map *check_for_div_constraints(
+	__isl_take isl_basic_map *bmap, int k, int l, isl_int sum,
+	int *progress)
+{
+	int i;
+	unsigned total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		isl_bool set_div;
+
+		if (isl_int_is_zero(bmap->ineq[k][total + i]))
+			continue;
+		if (isl_int_abs_ge(sum, bmap->ineq[k][total + i]))
+			continue;
+		set_div = better_div_constraint(bmap, i, k);
+		if (set_div >= 0 && set_div)
+			set_div = ok_to_set_div_from_bound(bmap, i, k);
+		if (set_div < 0)
+			return isl_basic_map_free(bmap);
+		if (!set_div)
+			break;
+		if (isl_int_is_pos(bmap->ineq[k][total + i]))
+			bmap = set_div_from_lower_bound(bmap, i, k);
+		else
+			bmap = set_div_from_lower_bound(bmap, i, l);
+		if (progress)
+			*progress = 1;
+		break;
+	}
+	return bmap;
+}
+
+__isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints(
+	__isl_take isl_basic_map *bmap, int *progress, int detect_divs)
+{
+	struct isl_constraint_index ci;
+	int k, l, h;
+	unsigned total = isl_basic_map_total_dim(bmap);
+	isl_int sum;
+
+	if (!bmap || bmap->n_ineq <= 1)
+		return bmap;
+
+	if (create_constraint_index(&ci, bmap) < 0)
+		return bmap;
+
+	h = isl_seq_get_hash_bits(bmap->ineq[0] + 1, total, ci.bits);
+	ci.index[h] = &bmap->ineq[0];
+	for (k = 1; k < bmap->n_ineq; ++k) {
+		h = hash_index(&ci, bmap, k);
+		if (!ci.index[h]) {
+			ci.index[h] = &bmap->ineq[k];
+			continue;
+		}
+		if (progress)
+			*progress = 1;
+		l = ci.index[h] - &bmap->ineq[0];
+		if (isl_int_lt(bmap->ineq[k][0], bmap->ineq[l][0]))
+			swap_inequality(bmap, k, l);
+		isl_basic_map_drop_inequality(bmap, k);
+		--k;
+	}
+	isl_int_init(sum);
+	for (k = 0; k < bmap->n_ineq-1; ++k) {
+		isl_seq_neg(bmap->ineq[k]+1, bmap->ineq[k]+1, total);
+		h = hash_index(&ci, bmap, k);
+		isl_seq_neg(bmap->ineq[k]+1, bmap->ineq[k]+1, total);
+		if (!ci.index[h])
+			continue;
+		l = ci.index[h] - &bmap->ineq[0];
+		isl_int_add(sum, bmap->ineq[k][0], bmap->ineq[l][0]);
+		if (isl_int_is_pos(sum)) {
+			if (detect_divs)
+				bmap = check_for_div_constraints(bmap, k, l,
+								 sum, progress);
+			continue;
+		}
+		if (isl_int_is_zero(sum)) {
+			/* We need to break out of the loop after these
+			 * changes since the contents of the hash
+			 * will no longer be valid.
+			 * Plus, we probably we want to regauss first.
+			 */
+			if (progress)
+				*progress = 1;
+			isl_basic_map_drop_inequality(bmap, l);
+			isl_basic_map_inequality_to_equality(bmap, k);
+		} else
+			bmap = isl_basic_map_set_to_empty(bmap);
+		break;
+	}
+	isl_int_clear(sum);
+
+	constraint_index_free(&ci);
+	return bmap;
+}
+
+/* Detect all pairs of inequalities that form an equality.
+ *
+ * isl_basic_map_remove_duplicate_constraints detects at most one such pair.
+ * Call it repeatedly while it is making progress.
+ */
+__isl_give isl_basic_map *isl_basic_map_detect_inequality_pairs(
+	__isl_take isl_basic_map *bmap, int *progress)
+{
+	int duplicate;
+
+	do {
+		duplicate = 0;
+		bmap = isl_basic_map_remove_duplicate_constraints(bmap,
+								&duplicate, 0);
+		if (progress && duplicate)
+			*progress = 1;
+	} while (duplicate);
+
+	return bmap;
+}
+
+/* Eliminate knowns divs from constraints where they appear with
+ * a (positive or negative) unit coefficient.
+ *
+ * That is, replace
+ *
+ *	floor(e/m) + f >= 0
+ *
+ * by
+ *
+ *	e + m f >= 0
+ *
+ * and
+ *
+ *	-floor(e/m) + f >= 0
+ *
+ * by
+ *
+ *	-e + m f + m - 1 >= 0
+ *
+ * The first conversion is valid because floor(e/m) >= -f is equivalent
+ * to e/m >= -f because -f is an integral expression.
+ * The second conversion follows from the fact that
+ *
+ *	-floor(e/m) = ceil(-e/m) = floor((-e + m - 1)/m)
+ *
+ *
+ * Note that one of the div constraints may have been eliminated
+ * due to being redundant with respect to the constraint that is
+ * being modified by this function.  The modified constraint may
+ * no longer imply this div constraint, so we add it back to make
+ * sure we do not lose any information.
+ *
+ * We skip integral divs, i.e., those with denominator 1, as we would
+ * risk eliminating the div from the div constraints.  We do not need
+ * to handle those divs here anyway since the div constraints will turn
+ * out to form an equality and this equality can then be used to eliminate
+ * the div from all constraints.
+ */
+static __isl_give isl_basic_map *eliminate_unit_divs(
+	__isl_take isl_basic_map *bmap, int *progress)
+{
+	int i, j;
+	isl_ctx *ctx;
+	unsigned total;
+
+	if (!bmap)
+		return NULL;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	total = 1 + isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (isl_int_is_one(bmap->div[i][0]))
+			continue;
+		for (j = 0; j < bmap->n_ineq; ++j) {
+			int s;
+
+			if (!isl_int_is_one(bmap->ineq[j][total + i]) &&
+			    !isl_int_is_negone(bmap->ineq[j][total + i]))
+				continue;
+
+			*progress = 1;
+
+			s = isl_int_sgn(bmap->ineq[j][total + i]);
+			isl_int_set_si(bmap->ineq[j][total + i], 0);
+			if (s < 0)
+				isl_seq_combine(bmap->ineq[j],
+					ctx->negone, bmap->div[i] + 1,
+					bmap->div[i][0], bmap->ineq[j],
+					total + bmap->n_div);
+			else
+				isl_seq_combine(bmap->ineq[j],
+					ctx->one, bmap->div[i] + 1,
+					bmap->div[i][0], bmap->ineq[j],
+					total + bmap->n_div);
+			if (s < 0) {
+				isl_int_add(bmap->ineq[j][0],
+					bmap->ineq[j][0], bmap->div[i][0]);
+				isl_int_sub_ui(bmap->ineq[j][0],
+					bmap->ineq[j][0], 1);
+			}
+
+			bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+			if (isl_basic_map_add_div_constraint(bmap, i, s) < 0)
+				return isl_basic_map_free(bmap);
+		}
+	}
+
+	return bmap;
+}
+
+__isl_give isl_basic_map *isl_basic_map_simplify(__isl_take isl_basic_map *bmap)
+{
+	int progress = 1;
+	if (!bmap)
+		return NULL;
+	while (progress) {
+		isl_bool empty;
+
+		progress = 0;
+		empty = isl_basic_map_plain_is_empty(bmap);
+		if (empty < 0)
+			return isl_basic_map_free(bmap);
+		if (empty)
+			break;
+		bmap = isl_basic_map_normalize_constraints(bmap);
+		bmap = reduce_div_coefficients(bmap);
+		bmap = normalize_div_expressions(bmap);
+		bmap = remove_duplicate_divs(bmap, &progress);
+		bmap = eliminate_unit_divs(bmap, &progress);
+		bmap = eliminate_divs_eq(bmap, &progress);
+		bmap = eliminate_divs_ineq(bmap, &progress);
+		bmap = isl_basic_map_gauss(bmap, &progress);
+		/* requires equalities in normal form */
+		bmap = normalize_divs(bmap, &progress);
+		bmap = isl_basic_map_remove_duplicate_constraints(bmap,
+								&progress, 1);
+		if (bmap && progress)
+			ISL_F_CLR(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS);
+	}
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_simplify(struct isl_basic_set *bset)
+{
+	return bset_from_bmap(isl_basic_map_simplify(bset_to_bmap(bset)));
+}
+
+
+isl_bool isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap,
+	isl_int *constraint, unsigned div)
+{
+	unsigned pos;
+
+	if (!bmap)
+		return isl_bool_error;
+
+	pos = 1 + isl_space_dim(bmap->dim, isl_dim_all) + div;
+
+	if (isl_int_eq(constraint[pos], bmap->div[div][0])) {
+		int neg;
+		isl_int_sub(bmap->div[div][1],
+				bmap->div[div][1], bmap->div[div][0]);
+		isl_int_add_ui(bmap->div[div][1], bmap->div[div][1], 1);
+		neg = isl_seq_is_neg(constraint, bmap->div[div]+1, pos);
+		isl_int_sub_ui(bmap->div[div][1], bmap->div[div][1], 1);
+		isl_int_add(bmap->div[div][1],
+				bmap->div[div][1], bmap->div[div][0]);
+		if (!neg)
+			return isl_bool_false;
+		if (isl_seq_first_non_zero(constraint+pos+1,
+					    bmap->n_div-div-1) != -1)
+			return isl_bool_false;
+	} else if (isl_int_abs_eq(constraint[pos], bmap->div[div][0])) {
+		if (!isl_seq_eq(constraint, bmap->div[div]+1, pos))
+			return isl_bool_false;
+		if (isl_seq_first_non_zero(constraint+pos+1,
+					    bmap->n_div-div-1) != -1)
+			return isl_bool_false;
+	} else
+		return isl_bool_false;
+
+	return isl_bool_true;
+}
+
+isl_bool isl_basic_set_is_div_constraint(__isl_keep isl_basic_set *bset,
+	isl_int *constraint, unsigned div)
+{
+	return isl_basic_map_is_div_constraint(bset, constraint, div);
+}
+
+
+/* If the only constraints a div d=floor(f/m)
+ * appears in are its two defining constraints
+ *
+ *	f - m d >=0
+ *	-(f - (m - 1)) + m d >= 0
+ *
+ * then it can safely be removed.
+ */
+static isl_bool div_is_redundant(__isl_keep isl_basic_map *bmap, int div)
+{
+	int i;
+	unsigned pos = 1 + isl_space_dim(bmap->dim, isl_dim_all) + div;
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		if (!isl_int_is_zero(bmap->eq[i][pos]))
+			return isl_bool_false;
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		isl_bool red;
+
+		if (isl_int_is_zero(bmap->ineq[i][pos]))
+			continue;
+		red = isl_basic_map_is_div_constraint(bmap, bmap->ineq[i], div);
+		if (red < 0 || !red)
+			return red;
+	}
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (!isl_int_is_zero(bmap->div[i][1+pos]))
+			return isl_bool_false;
+	}
+
+	return isl_bool_true;
+}
+
+/*
+ * Remove divs that don't occur in any of the constraints or other divs.
+ * These can arise when dropping constraints from a basic map or
+ * when the divs of a basic map have been temporarily aligned
+ * with the divs of another basic map.
+ */
+static __isl_give isl_basic_map *remove_redundant_divs(
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+
+	if (!bmap)
+		return NULL;
+
+	for (i = bmap->n_div-1; i >= 0; --i) {
+		isl_bool redundant;
+
+		redundant = div_is_redundant(bmap, i);
+		if (redundant < 0)
+			return isl_basic_map_free(bmap);
+		if (!redundant)
+			continue;
+		bmap = isl_basic_map_drop_div(bmap, i);
+	}
+	return bmap;
+}
+
+/* Mark "bmap" as final, without checking for obviously redundant
+ * integer divisions.  This function should be used when "bmap"
+ * is known not to involve any such integer divisions.
+ */
+__isl_give isl_basic_map *isl_basic_map_mark_final(
+	__isl_take isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+	ISL_F_SET(bmap, ISL_BASIC_SET_FINAL);
+	return bmap;
+}
+
+/* Mark "bmap" as final, after removing obviously redundant integer divisions.
+ */
+__isl_give isl_basic_map *isl_basic_map_finalize(__isl_take isl_basic_map *bmap)
+{
+	bmap = remove_redundant_divs(bmap);
+	bmap = isl_basic_map_mark_final(bmap);
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_finalize(struct isl_basic_set *bset)
+{
+	return bset_from_bmap(isl_basic_map_finalize(bset_to_bmap(bset)));
+}
+
+/* Remove definition of any div that is defined in terms of the given variable.
+ * The div itself is not removed.  Functions such as
+ * eliminate_divs_ineq depend on the other divs remaining in place.
+ */
+static __isl_give isl_basic_map *remove_dependent_vars(
+	__isl_take isl_basic_map *bmap, int pos)
+{
+	int i;
+
+	if (!bmap)
+		return NULL;
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (isl_int_is_zero(bmap->div[i][1+1+pos]))
+			continue;
+		bmap = isl_basic_map_mark_div_unknown(bmap, i);
+		if (!bmap)
+			return NULL;
+	}
+	return bmap;
+}
+
+/* Eliminate the specified variables from the constraints using
+ * Fourier-Motzkin.  The variables themselves are not removed.
+ */
+__isl_give isl_basic_map *isl_basic_map_eliminate_vars(
+	__isl_take isl_basic_map *bmap, unsigned pos, unsigned n)
+{
+	int d;
+	int i, j, k;
+	unsigned total;
+	int need_gauss = 0;
+
+	if (n == 0)
+		return bmap;
+	if (!bmap)
+		return NULL;
+	total = isl_basic_map_total_dim(bmap);
+
+	bmap = isl_basic_map_cow(bmap);
+	for (d = pos + n - 1; d >= 0 && d >= pos; --d)
+		bmap = remove_dependent_vars(bmap, d);
+	if (!bmap)
+		return NULL;
+
+	for (d = pos + n - 1;
+	     d >= 0 && d >= total - bmap->n_div && d >= pos; --d)
+		isl_seq_clr(bmap->div[d-(total-bmap->n_div)], 2+total);
+	for (d = pos + n - 1; d >= 0 && d >= pos; --d) {
+		int n_lower, n_upper;
+		if (!bmap)
+			return NULL;
+		for (i = 0; i < bmap->n_eq; ++i) {
+			if (isl_int_is_zero(bmap->eq[i][1+d]))
+				continue;
+			eliminate_var_using_equality(bmap, d, bmap->eq[i], 0, NULL);
+			isl_basic_map_drop_equality(bmap, i);
+			need_gauss = 1;
+			break;
+		}
+		if (i < bmap->n_eq)
+			continue;
+		n_lower = 0;
+		n_upper = 0;
+		for (i = 0; i < bmap->n_ineq; ++i) {
+			if (isl_int_is_pos(bmap->ineq[i][1+d]))
+				n_lower++;
+			else if (isl_int_is_neg(bmap->ineq[i][1+d]))
+				n_upper++;
+		}
+		bmap = isl_basic_map_extend_constraints(bmap,
+				0, n_lower * n_upper);
+		if (!bmap)
+			goto error;
+		for (i = bmap->n_ineq - 1; i >= 0; --i) {
+			int last;
+			if (isl_int_is_zero(bmap->ineq[i][1+d]))
+				continue;
+			last = -1;
+			for (j = 0; j < i; ++j) {
+				if (isl_int_is_zero(bmap->ineq[j][1+d]))
+					continue;
+				last = j;
+				if (isl_int_sgn(bmap->ineq[i][1+d]) ==
+				    isl_int_sgn(bmap->ineq[j][1+d]))
+					continue;
+				k = isl_basic_map_alloc_inequality(bmap);
+				if (k < 0)
+					goto error;
+				isl_seq_cpy(bmap->ineq[k], bmap->ineq[i],
+						1+total);
+				isl_seq_elim(bmap->ineq[k], bmap->ineq[j],
+						1+d, 1+total, NULL);
+			}
+			isl_basic_map_drop_inequality(bmap, i);
+			i = last + 1;
+		}
+		if (n_lower > 0 && n_upper > 0) {
+			bmap = isl_basic_map_normalize_constraints(bmap);
+			bmap = isl_basic_map_remove_duplicate_constraints(bmap,
+								    NULL, 0);
+			bmap = isl_basic_map_gauss(bmap, NULL);
+			bmap = isl_basic_map_remove_redundancies(bmap);
+			need_gauss = 0;
+			if (!bmap)
+				goto error;
+			if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+				break;
+		}
+	}
+	ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+	if (need_gauss)
+		bmap = isl_basic_map_gauss(bmap, NULL);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_set *isl_basic_set_eliminate_vars(
+	struct isl_basic_set *bset, unsigned pos, unsigned n)
+{
+	return bset_from_bmap(isl_basic_map_eliminate_vars(bset_to_bmap(bset),
+								pos, n));
+}
+
+/* Eliminate the specified n dimensions starting at first from the
+ * constraints, without removing the dimensions from the space.
+ * If the set is rational, the dimensions are eliminated using Fourier-Motzkin.
+ * Otherwise, they are projected out and the original space is restored.
+ */
+__isl_give isl_basic_map *isl_basic_map_eliminate(
+	__isl_take isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	isl_space *space;
+
+	if (!bmap)
+		return NULL;
+	if (n == 0)
+		return bmap;
+
+	if (first + n > isl_basic_map_dim(bmap, type) || first + n < first)
+		isl_die(bmap->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL)) {
+		first += isl_basic_map_offset(bmap, type) - 1;
+		bmap = isl_basic_map_eliminate_vars(bmap, first, n);
+		return isl_basic_map_finalize(bmap);
+	}
+
+	space = isl_basic_map_get_space(bmap);
+	bmap = isl_basic_map_project_out(bmap, type, first, n);
+	bmap = isl_basic_map_insert_dims(bmap, type, first, n);
+	bmap = isl_basic_map_reset_space(bmap, space);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_eliminate(
+	__isl_take isl_basic_set *bset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_basic_map_eliminate(bset, type, first, n);
+}
+
+/* Remove all constraints from "bmap" that reference any unknown local
+ * variables (directly or indirectly).
+ *
+ * Dropping all constraints on a local variable will make it redundant,
+ * so it will get removed implicitly by
+ * isl_basic_map_drop_constraints_involving_dims.  Some other local
+ * variables may also end up becoming redundant if they only appear
+ * in constraints together with the unknown local variable.
+ * Therefore, start over after calling
+ * isl_basic_map_drop_constraints_involving_dims.
+ */
+__isl_give isl_basic_map *isl_basic_map_drop_constraint_involving_unknown_divs(
+	__isl_take isl_basic_map *bmap)
+{
+	isl_bool known;
+	int i, n_div, o_div;
+
+	known = isl_basic_map_divs_known(bmap);
+	if (known < 0)
+		return isl_basic_map_free(bmap);
+	if (known)
+		return bmap;
+
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	o_div = isl_basic_map_offset(bmap, isl_dim_div) - 1;
+
+	for (i = 0; i < n_div; ++i) {
+		known = isl_basic_map_div_is_known(bmap, i);
+		if (known < 0)
+			return isl_basic_map_free(bmap);
+		if (known)
+			continue;
+		bmap = remove_dependent_vars(bmap, o_div + i);
+		bmap = isl_basic_map_drop_constraints_involving_dims(bmap,
+							    isl_dim_div, i, 1);
+		if (!bmap)
+			return NULL;
+		n_div = isl_basic_map_dim(bmap, isl_dim_div);
+		i = -1;
+	}
+
+	return bmap;
+}
+
+/* Remove all constraints from "map" that reference any unknown local
+ * variables (directly or indirectly).
+ *
+ * Since constraints may get dropped from the basic maps,
+ * they may no longer be disjoint from each other.
+ */
+__isl_give isl_map *isl_map_drop_constraint_involving_unknown_divs(
+	__isl_take isl_map *map)
+{
+	int i;
+	isl_bool known;
+
+	known = isl_map_divs_known(map);
+	if (known < 0)
+		return isl_map_free(map);
+	if (known)
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] =
+		    isl_basic_map_drop_constraint_involving_unknown_divs(
+								    map->p[i]);
+		if (!map->p[i])
+			return isl_map_free(map);
+	}
+
+	if (map->n > 1)
+		ISL_F_CLR(map, ISL_MAP_DISJOINT);
+
+	return map;
+}
+
+/* Don't assume equalities are in order, because align_divs
+ * may have changed the order of the divs.
+ */
+static void compute_elimination_index(__isl_keep isl_basic_map *bmap, int *elim)
+{
+	int d, i;
+	unsigned total;
+
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+	for (d = 0; d < total; ++d)
+		elim[d] = -1;
+	for (i = 0; i < bmap->n_eq; ++i) {
+		for (d = total - 1; d >= 0; --d) {
+			if (isl_int_is_zero(bmap->eq[i][1+d]))
+				continue;
+			elim[d] = i;
+			break;
+		}
+	}
+}
+
+static void set_compute_elimination_index(__isl_keep isl_basic_set *bset,
+	int *elim)
+{
+	compute_elimination_index(bset_to_bmap(bset), elim);
+}
+
+static int reduced_using_equalities(isl_int *dst, isl_int *src,
+	__isl_keep isl_basic_map *bmap, int *elim)
+{
+	int d;
+	int copied = 0;
+	unsigned total;
+
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+	for (d = total - 1; d >= 0; --d) {
+		if (isl_int_is_zero(src[1+d]))
+			continue;
+		if (elim[d] == -1)
+			continue;
+		if (!copied) {
+			isl_seq_cpy(dst, src, 1 + total);
+			copied = 1;
+		}
+		isl_seq_elim(dst, bmap->eq[elim[d]], 1 + d, 1 + total, NULL);
+	}
+	return copied;
+}
+
+static int set_reduced_using_equalities(isl_int *dst, isl_int *src,
+	__isl_keep isl_basic_set *bset, int *elim)
+{
+	return reduced_using_equalities(dst, src,
+					bset_to_bmap(bset), elim);
+}
+
+static __isl_give isl_basic_set *isl_basic_set_reduce_using_equalities(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *context)
+{
+	int i;
+	int *elim;
+
+	if (!bset || !context)
+		goto error;
+
+	if (context->n_eq == 0) {
+		isl_basic_set_free(context);
+		return bset;
+	}
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		goto error;
+
+	elim = isl_alloc_array(bset->ctx, int, isl_basic_set_n_dim(bset));
+	if (!elim)
+		goto error;
+	set_compute_elimination_index(context, elim);
+	for (i = 0; i < bset->n_eq; ++i)
+		set_reduced_using_equalities(bset->eq[i], bset->eq[i],
+							context, elim);
+	for (i = 0; i < bset->n_ineq; ++i)
+		set_reduced_using_equalities(bset->ineq[i], bset->ineq[i],
+							context, elim);
+	isl_basic_set_free(context);
+	free(elim);
+	bset = isl_basic_set_simplify(bset);
+	bset = isl_basic_set_finalize(bset);
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	isl_basic_set_free(context);
+	return NULL;
+}
+
+/* For each inequality in "ineq" that is a shifted (more relaxed)
+ * copy of an inequality in "context", mark the corresponding entry
+ * in "row" with -1.
+ * If an inequality only has a non-negative constant term, then
+ * mark it as well.
+ */
+static isl_stat mark_shifted_constraints(__isl_keep isl_mat *ineq,
+	__isl_keep isl_basic_set *context, int *row)
+{
+	struct isl_constraint_index ci;
+	int n_ineq;
+	unsigned total;
+	int k;
+
+	if (!ineq || !context)
+		return isl_stat_error;
+	if (context->n_ineq == 0)
+		return isl_stat_ok;
+	if (setup_constraint_index(&ci, context) < 0)
+		return isl_stat_error;
+
+	n_ineq = isl_mat_rows(ineq);
+	total = isl_mat_cols(ineq) - 1;
+	for (k = 0; k < n_ineq; ++k) {
+		int l;
+		isl_bool redundant;
+
+		l = isl_seq_first_non_zero(ineq->row[k] + 1, total);
+		if (l < 0 && isl_int_is_nonneg(ineq->row[k][0])) {
+			row[k] = -1;
+			continue;
+		}
+		redundant = constraint_index_is_redundant(&ci, ineq->row[k]);
+		if (redundant < 0)
+			goto error;
+		if (!redundant)
+			continue;
+		row[k] = -1;
+	}
+	constraint_index_free(&ci);
+	return isl_stat_ok;
+error:
+	constraint_index_free(&ci);
+	return isl_stat_error;
+}
+
+static __isl_give isl_basic_set *remove_shifted_constraints(
+	__isl_take isl_basic_set *bset, __isl_keep isl_basic_set *context)
+{
+	struct isl_constraint_index ci;
+	int k;
+
+	if (!bset || !context)
+		return bset;
+
+	if (context->n_ineq == 0)
+		return bset;
+	if (setup_constraint_index(&ci, context) < 0)
+		return bset;
+
+	for (k = 0; k < bset->n_ineq; ++k) {
+		isl_bool redundant;
+
+		redundant = constraint_index_is_redundant(&ci, bset->ineq[k]);
+		if (redundant < 0)
+			goto error;
+		if (!redundant)
+			continue;
+		bset = isl_basic_set_cow(bset);
+		if (!bset)
+			goto error;
+		isl_basic_set_drop_inequality(bset, k);
+		--k;
+	}
+	constraint_index_free(&ci);
+	return bset;
+error:
+	constraint_index_free(&ci);
+	return bset;
+}
+
+/* Remove constraints from "bmap" that are identical to constraints
+ * in "context" or that are more relaxed (greater constant term).
+ *
+ * We perform the test for shifted copies on the pure constraints
+ * in remove_shifted_constraints.
+ */
+static __isl_give isl_basic_map *isl_basic_map_remove_shifted_constraints(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_map *context)
+{
+	isl_basic_set *bset, *bset_context;
+
+	if (!bmap || !context)
+		goto error;
+
+	if (bmap->n_ineq == 0 || context->n_ineq == 0) {
+		isl_basic_map_free(context);
+		return bmap;
+	}
+
+	context = isl_basic_map_align_divs(context, bmap);
+	bmap = isl_basic_map_align_divs(bmap, context);
+
+	bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap));
+	bset_context = isl_basic_map_underlying_set(context);
+	bset = remove_shifted_constraints(bset, bset_context);
+	isl_basic_set_free(bset_context);
+
+	bmap = isl_basic_map_overlying_set(bset, bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_basic_map_free(context);
+	return NULL;
+}
+
+/* Does the (linear part of a) constraint "c" involve any of the "len"
+ * "relevant" dimensions?
+ */
+static int is_related(isl_int *c, int len, int *relevant)
+{
+	int i;
+
+	for (i = 0; i < len; ++i) {
+		if (!relevant[i])
+			continue;
+		if (!isl_int_is_zero(c[i]))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Drop constraints from "bmap" that do not involve any of
+ * the dimensions marked "relevant".
+ */
+static __isl_give isl_basic_map *drop_unrelated_constraints(
+	__isl_take isl_basic_map *bmap, int *relevant)
+{
+	int i, dim;
+
+	dim = isl_basic_map_dim(bmap, isl_dim_all);
+	for (i = 0; i < dim; ++i)
+		if (!relevant[i])
+			break;
+	if (i >= dim)
+		return bmap;
+
+	for (i = bmap->n_eq - 1; i >= 0; --i)
+		if (!is_related(bmap->eq[i] + 1, dim, relevant)) {
+			bmap = isl_basic_map_cow(bmap);
+			if (isl_basic_map_drop_equality(bmap, i) < 0)
+				return isl_basic_map_free(bmap);
+		}
+
+	for (i = bmap->n_ineq - 1; i >= 0; --i)
+		if (!is_related(bmap->ineq[i] + 1, dim, relevant)) {
+			bmap = isl_basic_map_cow(bmap);
+			if (isl_basic_map_drop_inequality(bmap, i) < 0)
+				return isl_basic_map_free(bmap);
+		}
+
+	return bmap;
+}
+
+/* Update the groups in "group" based on the (linear part of a) constraint "c".
+ *
+ * In particular, for any variable involved in the constraint,
+ * find the actual group id from before and replace the group
+ * of the corresponding variable by the minimal group of all
+ * the variables involved in the constraint considered so far
+ * (if this minimum is smaller) or replace the minimum by this group
+ * (if the minimum is larger).
+ *
+ * At the end, all the variables in "c" will (indirectly) point
+ * to the minimal of the groups that they referred to originally.
+ */
+static void update_groups(int dim, int *group, isl_int *c)
+{
+	int j;
+	int min = dim;
+
+	for (j = 0; j < dim; ++j) {
+		if (isl_int_is_zero(c[j]))
+			continue;
+		while (group[j] >= 0 && group[group[j]] != group[j])
+			group[j] = group[group[j]];
+		if (group[j] == min)
+			continue;
+		if (group[j] < min) {
+			if (min >= 0 && min < dim)
+				group[min] = group[j];
+			min = group[j];
+		} else
+			group[group[j]] = min;
+	}
+}
+
+/* Allocate an array of groups of variables, one for each variable
+ * in "context", initialized to zero.
+ */
+static int *alloc_groups(__isl_keep isl_basic_set *context)
+{
+	isl_ctx *ctx;
+	int dim;
+
+	dim = isl_basic_set_dim(context, isl_dim_set);
+	ctx = isl_basic_set_get_ctx(context);
+	return isl_calloc_array(ctx, int, dim);
+}
+
+/* Drop constraints from "bmap" that only involve variables that are
+ * not related to any of the variables marked with a "-1" in "group".
+ *
+ * We construct groups of variables that collect variables that
+ * (indirectly) appear in some common constraint of "bmap".
+ * Each group is identified by the first variable in the group,
+ * except for the special group of variables that was already identified
+ * in the input as -1 (or are related to those variables).
+ * If group[i] is equal to i (or -1), then the group of i is i (or -1),
+ * otherwise the group of i is the group of group[i].
+ *
+ * We first initialize groups for the remaining variables.
+ * Then we iterate over the constraints of "bmap" and update the
+ * group of the variables in the constraint by the smallest group.
+ * Finally, we resolve indirect references to groups by running over
+ * the variables.
+ *
+ * After computing the groups, we drop constraints that do not involve
+ * any variables in the -1 group.
+ */
+__isl_give isl_basic_map *isl_basic_map_drop_unrelated_constraints(
+	__isl_take isl_basic_map *bmap, __isl_take int *group)
+{
+	int dim;
+	int i;
+	int last;
+
+	if (!bmap)
+		return NULL;
+
+	dim = isl_basic_map_dim(bmap, isl_dim_all);
+
+	last = -1;
+	for (i = 0; i < dim; ++i)
+		if (group[i] >= 0)
+			last = group[i] = i;
+	if (last < 0) {
+		free(group);
+		return bmap;
+	}
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		update_groups(dim, group, bmap->eq[i] + 1);
+	for (i = 0; i < bmap->n_ineq; ++i)
+		update_groups(dim, group, bmap->ineq[i] + 1);
+
+	for (i = 0; i < dim; ++i)
+		if (group[i] >= 0)
+			group[i] = group[group[i]];
+
+	for (i = 0; i < dim; ++i)
+		group[i] = group[i] == -1;
+
+	bmap = drop_unrelated_constraints(bmap, group);
+
+	free(group);
+	return bmap;
+}
+
+/* Drop constraints from "context" that are irrelevant for computing
+ * the gist of "bset".
+ *
+ * In particular, drop constraints in variables that are not related
+ * to any of the variables involved in the constraints of "bset"
+ * in the sense that there is no sequence of constraints that connects them.
+ *
+ * We first mark all variables that appear in "bset" as belonging
+ * to a "-1" group and then continue with group_and_drop_irrelevant_constraints.
+ */
+static __isl_give isl_basic_set *drop_irrelevant_constraints(
+	__isl_take isl_basic_set *context, __isl_keep isl_basic_set *bset)
+{
+	int *group;
+	int dim;
+	int i, j;
+
+	if (!context || !bset)
+		return isl_basic_set_free(context);
+
+	group = alloc_groups(context);
+
+	if (!group)
+		return isl_basic_set_free(context);
+
+	dim = isl_basic_set_dim(bset, isl_dim_set);
+	for (i = 0; i < dim; ++i) {
+		for (j = 0; j < bset->n_eq; ++j)
+			if (!isl_int_is_zero(bset->eq[j][1 + i]))
+				break;
+		if (j < bset->n_eq) {
+			group[i] = -1;
+			continue;
+		}
+		for (j = 0; j < bset->n_ineq; ++j)
+			if (!isl_int_is_zero(bset->ineq[j][1 + i]))
+				break;
+		if (j < bset->n_ineq)
+			group[i] = -1;
+	}
+
+	return isl_basic_map_drop_unrelated_constraints(context, group);
+}
+
+/* Drop constraints from "context" that are irrelevant for computing
+ * the gist of the inequalities "ineq".
+ * Inequalities in "ineq" for which the corresponding element of row
+ * is set to -1 have already been marked for removal and should be ignored.
+ *
+ * In particular, drop constraints in variables that are not related
+ * to any of the variables involved in "ineq"
+ * in the sense that there is no sequence of constraints that connects them.
+ *
+ * We first mark all variables that appear in "bset" as belonging
+ * to a "-1" group and then continue with group_and_drop_irrelevant_constraints.
+ */
+static __isl_give isl_basic_set *drop_irrelevant_constraints_marked(
+	__isl_take isl_basic_set *context, __isl_keep isl_mat *ineq, int *row)
+{
+	int *group;
+	int dim;
+	int i, j, n;
+
+	if (!context || !ineq)
+		return isl_basic_set_free(context);
+
+	group = alloc_groups(context);
+
+	if (!group)
+		return isl_basic_set_free(context);
+
+	dim = isl_basic_set_dim(context, isl_dim_set);
+	n = isl_mat_rows(ineq);
+	for (i = 0; i < dim; ++i) {
+		for (j = 0; j < n; ++j) {
+			if (row[j] < 0)
+				continue;
+			if (!isl_int_is_zero(ineq->row[j][1 + i]))
+				break;
+		}
+		if (j < n)
+			group[i] = -1;
+	}
+
+	return isl_basic_map_drop_unrelated_constraints(context, group);
+}
+
+/* Do all "n" entries of "row" contain a negative value?
+ */
+static int all_neg(int *row, int n)
+{
+	int i;
+
+	for (i = 0; i < n; ++i)
+		if (row[i] >= 0)
+			return 0;
+
+	return 1;
+}
+
+/* Update the inequalities in "bset" based on the information in "row"
+ * and "tab".
+ *
+ * In particular, the array "row" contains either -1, meaning that
+ * the corresponding inequality of "bset" is redundant, or the index
+ * of an inequality in "tab".
+ *
+ * If the row entry is -1, then drop the inequality.
+ * Otherwise, if the constraint is marked redundant in the tableau,
+ * then drop the inequality.  Similarly, if it is marked as an equality
+ * in the tableau, then turn the inequality into an equality and
+ * perform Gaussian elimination.
+ */
+static __isl_give isl_basic_set *update_ineq(__isl_take isl_basic_set *bset,
+	__isl_keep int *row, struct isl_tab *tab)
+{
+	int i;
+	unsigned n_ineq;
+	unsigned n_eq;
+	int found_equality = 0;
+
+	if (!bset)
+		return NULL;
+	if (tab && tab->empty)
+		return isl_basic_set_set_to_empty(bset);
+
+	n_ineq = bset->n_ineq;
+	for (i = n_ineq - 1; i >= 0; --i) {
+		if (row[i] < 0) {
+			if (isl_basic_set_drop_inequality(bset, i) < 0)
+				return isl_basic_set_free(bset);
+			continue;
+		}
+		if (!tab)
+			continue;
+		n_eq = tab->n_eq;
+		if (isl_tab_is_equality(tab, n_eq + row[i])) {
+			isl_basic_map_inequality_to_equality(bset, i);
+			found_equality = 1;
+		} else if (isl_tab_is_redundant(tab, n_eq + row[i])) {
+			if (isl_basic_set_drop_inequality(bset, i) < 0)
+				return isl_basic_set_free(bset);
+		}
+	}
+
+	if (found_equality)
+		bset = isl_basic_set_gauss(bset, NULL);
+	bset = isl_basic_set_finalize(bset);
+	return bset;
+}
+
+/* Update the inequalities in "bset" based on the information in "row"
+ * and "tab" and free all arguments (other than "bset").
+ */
+static __isl_give isl_basic_set *update_ineq_free(
+	__isl_take isl_basic_set *bset, __isl_take isl_mat *ineq,
+	__isl_take isl_basic_set *context, __isl_take int *row,
+	struct isl_tab *tab)
+{
+	isl_mat_free(ineq);
+	isl_basic_set_free(context);
+
+	bset = update_ineq(bset, row, tab);
+
+	free(row);
+	isl_tab_free(tab);
+	return bset;
+}
+
+/* Remove all information from bset that is redundant in the context
+ * of context.
+ * "ineq" contains the (possibly transformed) inequalities of "bset",
+ * in the same order.
+ * The (explicit) equalities of "bset" are assumed to have been taken
+ * into account by the transformation such that only the inequalities
+ * are relevant.
+ * "context" is assumed not to be empty.
+ *
+ * "row" keeps track of the constraint index of a "bset" inequality in "tab".
+ * A value of -1 means that the inequality is obviously redundant and may
+ * not even appear in  "tab".
+ *
+ * We first mark the inequalities of "bset"
+ * that are obviously redundant with respect to some inequality in "context".
+ * Then we remove those constraints from "context" that have become
+ * irrelevant for computing the gist of "bset".
+ * Note that this removal of constraints cannot be replaced by
+ * a factorization because factors in "bset" may still be connected
+ * to each other through constraints in "context".
+ *
+ * If there are any inequalities left, we construct a tableau for
+ * the context and then add the inequalities of "bset".
+ * Before adding these inequalities, we freeze all constraints such that
+ * they won't be considered redundant in terms of the constraints of "bset".
+ * Then we detect all redundant constraints (among the
+ * constraints that weren't frozen), first by checking for redundancy in the
+ * the tableau and then by checking if replacing a constraint by its negation
+ * would lead to an empty set.  This last step is fairly expensive
+ * and could be optimized by more reuse of the tableau.
+ * Finally, we update bset according to the results.
+ */
+static __isl_give isl_basic_set *uset_gist_full(__isl_take isl_basic_set *bset,
+	__isl_take isl_mat *ineq, __isl_take isl_basic_set *context)
+{
+	int i, r;
+	int *row = NULL;
+	isl_ctx *ctx;
+	isl_basic_set *combined = NULL;
+	struct isl_tab *tab = NULL;
+	unsigned n_eq, context_ineq;
+
+	if (!bset || !ineq || !context)
+		goto error;
+
+	if (bset->n_ineq == 0 || isl_basic_set_plain_is_universe(context)) {
+		isl_basic_set_free(context);
+		isl_mat_free(ineq);
+		return bset;
+	}
+
+	ctx = isl_basic_set_get_ctx(context);
+	row = isl_calloc_array(ctx, int, bset->n_ineq);
+	if (!row)
+		goto error;
+
+	if (mark_shifted_constraints(ineq, context, row) < 0)
+		goto error;
+	if (all_neg(row, bset->n_ineq))
+		return update_ineq_free(bset, ineq, context, row, NULL);
+
+	context = drop_irrelevant_constraints_marked(context, ineq, row);
+	if (!context)
+		goto error;
+	if (isl_basic_set_plain_is_universe(context))
+		return update_ineq_free(bset, ineq, context, row, NULL);
+
+	n_eq = context->n_eq;
+	context_ineq = context->n_ineq;
+	combined = isl_basic_set_cow(isl_basic_set_copy(context));
+	combined = isl_basic_set_extend_constraints(combined, 0, bset->n_ineq);
+	tab = isl_tab_from_basic_set(combined, 0);
+	for (i = 0; i < context_ineq; ++i)
+		if (isl_tab_freeze_constraint(tab, n_eq + i) < 0)
+			goto error;
+	if (isl_tab_extend_cons(tab, bset->n_ineq) < 0)
+		goto error;
+	r = context_ineq;
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (row[i] < 0)
+			continue;
+		combined = isl_basic_set_add_ineq(combined, ineq->row[i]);
+		if (isl_tab_add_ineq(tab, ineq->row[i]) < 0)
+			goto error;
+		row[i] = r++;
+	}
+	if (isl_tab_detect_implicit_equalities(tab) < 0)
+		goto error;
+	if (isl_tab_detect_redundant(tab) < 0)
+		goto error;
+	for (i = bset->n_ineq - 1; i >= 0; --i) {
+		isl_basic_set *test;
+		int is_empty;
+
+		if (row[i] < 0)
+			continue;
+		r = row[i];
+		if (tab->con[n_eq + r].is_redundant)
+			continue;
+		test = isl_basic_set_dup(combined);
+		if (isl_inequality_negate(test, r) < 0)
+			test = isl_basic_set_free(test);
+		test = isl_basic_set_update_from_tab(test, tab);
+		is_empty = isl_basic_set_is_empty(test);
+		isl_basic_set_free(test);
+		if (is_empty < 0)
+			goto error;
+		if (is_empty)
+			tab->con[n_eq + r].is_redundant = 1;
+	}
+	bset = update_ineq_free(bset, ineq, context, row, tab);
+	if (bset) {
+		ISL_F_SET(bset, ISL_BASIC_SET_NO_IMPLICIT);
+		ISL_F_SET(bset, ISL_BASIC_SET_NO_REDUNDANT);
+	}
+
+	isl_basic_set_free(combined);
+	return bset;
+error:
+	free(row);
+	isl_mat_free(ineq);
+	isl_tab_free(tab);
+	isl_basic_set_free(combined);
+	isl_basic_set_free(context);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Extract the inequalities of "bset" as an isl_mat.
+ */
+static __isl_give isl_mat *extract_ineq(__isl_keep isl_basic_set *bset)
+{
+	unsigned total;
+	isl_ctx *ctx;
+	isl_mat *ineq;
+
+	if (!bset)
+		return NULL;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	total = isl_basic_set_total_dim(bset);
+	ineq = isl_mat_sub_alloc6(ctx, bset->ineq, 0, bset->n_ineq,
+				    0, 1 + total);
+
+	return ineq;
+}
+
+/* Remove all information from "bset" that is redundant in the context
+ * of "context", for the case where both "bset" and "context" are
+ * full-dimensional.
+ */
+static __isl_give isl_basic_set *uset_gist_uncompressed(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *context)
+{
+	isl_mat *ineq;
+
+	ineq = extract_ineq(bset);
+	return uset_gist_full(bset, ineq, context);
+}
+
+/* Remove all information from "bset" that is redundant in the context
+ * of "context", for the case where the combined equalities of
+ * "bset" and "context" allow for a compression that can be obtained
+ * by preapplication of "T".
+ *
+ * "bset" itself is not transformed by "T".  Instead, the inequalities
+ * are extracted from "bset" and those are transformed by "T".
+ * uset_gist_full then determines which of the transformed inequalities
+ * are redundant with respect to the transformed "context" and removes
+ * the corresponding inequalities from "bset".
+ *
+ * After preapplying "T" to the inequalities, any common factor is
+ * removed from the coefficients.  If this results in a tightening
+ * of the constant term, then the same tightening is applied to
+ * the corresponding untransformed inequality in "bset".
+ * That is, if after plugging in T, a constraint f(x) >= 0 is of the form
+ *
+ *	g f'(x) + r >= 0
+ *
+ * with 0 <= r < g, then it is equivalent to
+ *
+ *	f'(x) >= 0
+ *
+ * This means that f(x) >= 0 is equivalent to f(x) - r >= 0 in the affine
+ * subspace compressed by T since the latter would be transformed to
+ *
+ *	g f'(x) >= 0
+ */
+static __isl_give isl_basic_set *uset_gist_compressed(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *context,
+	__isl_take isl_mat *T)
+{
+	isl_ctx *ctx;
+	isl_mat *ineq;
+	int i, n_row, n_col;
+	isl_int rem;
+
+	ineq = extract_ineq(bset);
+	ineq = isl_mat_product(ineq, isl_mat_copy(T));
+	context = isl_basic_set_preimage(context, T);
+
+	if (!ineq || !context)
+		goto error;
+	if (isl_basic_set_plain_is_empty(context)) {
+		isl_mat_free(ineq);
+		isl_basic_set_free(context);
+		return isl_basic_set_set_to_empty(bset);
+	}
+
+	ctx = isl_mat_get_ctx(ineq);
+	n_row = isl_mat_rows(ineq);
+	n_col = isl_mat_cols(ineq);
+	isl_int_init(rem);
+	for (i = 0; i < n_row; ++i) {
+		isl_seq_gcd(ineq->row[i] + 1, n_col - 1, &ctx->normalize_gcd);
+		if (isl_int_is_zero(ctx->normalize_gcd))
+			continue;
+		if (isl_int_is_one(ctx->normalize_gcd))
+			continue;
+		isl_seq_scale_down(ineq->row[i] + 1, ineq->row[i] + 1,
+				    ctx->normalize_gcd, n_col - 1);
+		isl_int_fdiv_r(rem, ineq->row[i][0], ctx->normalize_gcd);
+		isl_int_fdiv_q(ineq->row[i][0],
+				ineq->row[i][0], ctx->normalize_gcd);
+		if (isl_int_is_zero(rem))
+			continue;
+		bset = isl_basic_set_cow(bset);
+		if (!bset)
+			break;
+		isl_int_sub(bset->ineq[i][0], bset->ineq[i][0], rem);
+	}
+	isl_int_clear(rem);
+
+	return uset_gist_full(bset, ineq, context);
+error:
+	isl_mat_free(ineq);
+	isl_basic_set_free(context);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Project "bset" onto the variables that are involved in "template".
+ */
+static __isl_give isl_basic_set *project_onto_involved(
+	__isl_take isl_basic_set *bset, __isl_keep isl_basic_set *template)
+{
+	int i, n;
+
+	if (!bset || !template)
+		return isl_basic_set_free(bset);
+
+	n = isl_basic_set_dim(template, isl_dim_set);
+
+	for (i = 0; i < n; ++i) {
+		isl_bool involved;
+
+		involved = isl_basic_set_involves_dims(template,
+							isl_dim_set, i, 1);
+		if (involved < 0)
+			return isl_basic_set_free(bset);
+		if (involved)
+			continue;
+		bset = isl_basic_set_eliminate_vars(bset, i, 1);
+	}
+
+	return bset;
+}
+
+/* Remove all information from bset that is redundant in the context
+ * of context.  In particular, equalities that are linear combinations
+ * of those in context are removed.  Then the inequalities that are
+ * redundant in the context of the equalities and inequalities of
+ * context are removed.
+ *
+ * First of all, we drop those constraints from "context"
+ * that are irrelevant for computing the gist of "bset".
+ * Alternatively, we could factorize the intersection of "context" and "bset".
+ *
+ * We first compute the intersection of the integer affine hulls
+ * of "bset" and "context",
+ * compute the gist inside this intersection and then reduce
+ * the constraints with respect to the equalities of the context
+ * that only involve variables already involved in the input.
+ *
+ * If two constraints are mutually redundant, then uset_gist_full
+ * will remove the second of those constraints.  We therefore first
+ * sort the constraints so that constraints not involving existentially
+ * quantified variables are given precedence over those that do.
+ * We have to perform this sorting before the variable compression,
+ * because that may effect the order of the variables.
+ */
+static __isl_give isl_basic_set *uset_gist(__isl_take isl_basic_set *bset,
+	__isl_take isl_basic_set *context)
+{
+	isl_mat *eq;
+	isl_mat *T;
+	isl_basic_set *aff;
+	isl_basic_set *aff_context;
+	unsigned total;
+
+	if (!bset || !context)
+		goto error;
+
+	context = drop_irrelevant_constraints(context, bset);
+
+	bset = isl_basic_set_detect_equalities(bset);
+	aff = isl_basic_set_copy(bset);
+	aff = isl_basic_set_plain_affine_hull(aff);
+	context = isl_basic_set_detect_equalities(context);
+	aff_context = isl_basic_set_copy(context);
+	aff_context = isl_basic_set_plain_affine_hull(aff_context);
+	aff = isl_basic_set_intersect(aff, aff_context);
+	if (!aff)
+		goto error;
+	if (isl_basic_set_plain_is_empty(aff)) {
+		isl_basic_set_free(bset);
+		isl_basic_set_free(context);
+		return aff;
+	}
+	bset = isl_basic_set_sort_constraints(bset);
+	if (aff->n_eq == 0) {
+		isl_basic_set_free(aff);
+		return uset_gist_uncompressed(bset, context);
+	}
+	total = isl_basic_set_total_dim(bset);
+	eq = isl_mat_sub_alloc6(bset->ctx, aff->eq, 0, aff->n_eq, 0, 1 + total);
+	eq = isl_mat_cow(eq);
+	T = isl_mat_variable_compression(eq, NULL);
+	isl_basic_set_free(aff);
+	if (T && T->n_col == 0) {
+		isl_mat_free(T);
+		isl_basic_set_free(context);
+		return isl_basic_set_set_to_empty(bset);
+	}
+
+	aff_context = isl_basic_set_affine_hull(isl_basic_set_copy(context));
+	aff_context = project_onto_involved(aff_context, bset);
+
+	bset = uset_gist_compressed(bset, context, T);
+	bset = isl_basic_set_reduce_using_equalities(bset, aff_context);
+
+	if (bset) {
+		ISL_F_SET(bset, ISL_BASIC_SET_NO_IMPLICIT);
+		ISL_F_SET(bset, ISL_BASIC_SET_NO_REDUNDANT);
+	}
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	isl_basic_set_free(context);
+	return NULL;
+}
+
+/* Return the number of equality constraints in "bmap" that involve
+ * local variables.  This function assumes that Gaussian elimination
+ * has been applied to the equality constraints.
+ */
+static int n_div_eq(__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	int total, n_div;
+
+	if (!bmap)
+		return -1;
+
+	if (bmap->n_eq == 0)
+		return 0;
+
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	total -= n_div;
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total,
+					    n_div) == -1)
+			return i;
+
+	return bmap->n_eq;
+}
+
+/* Construct a basic map in "space" defined by the equality constraints in "eq".
+ * The constraints are assumed not to involve any local variables.
+ */
+static __isl_give isl_basic_map *basic_map_from_equalities(
+	__isl_take isl_space *space, __isl_take isl_mat *eq)
+{
+	int i, k;
+	isl_basic_map *bmap = NULL;
+
+	if (!space || !eq)
+		goto error;
+
+	if (1 + isl_space_dim(space, isl_dim_all) != eq->n_col)
+		isl_die(isl_space_get_ctx(space), isl_error_internal,
+			"unexpected number of columns", goto error);
+
+	bmap = isl_basic_map_alloc_space(isl_space_copy(space),
+					    0, eq->n_row, 0);
+	for (i = 0; i < eq->n_row; ++i) {
+		k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bmap->eq[k], eq->row[i], eq->n_col);
+	}
+
+	isl_space_free(space);
+	isl_mat_free(eq);
+	return bmap;
+error:
+	isl_space_free(space);
+	isl_mat_free(eq);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Construct and return a variable compression based on the equality
+ * constraints in "bmap1" and "bmap2" that do not involve the local variables.
+ * "n1" is the number of (initial) equality constraints in "bmap1"
+ * that do involve local variables.
+ * "n2" is the number of (initial) equality constraints in "bmap2"
+ * that do involve local variables.
+ * "total" is the total number of other variables.
+ * This function assumes that Gaussian elimination
+ * has been applied to the equality constraints in both "bmap1" and "bmap2"
+ * such that the equality constraints not involving local variables
+ * are those that start at "n1" or "n2".
+ *
+ * If either of "bmap1" and "bmap2" does not have such equality constraints,
+ * then simply compute the compression based on the equality constraints
+ * in the other basic map.
+ * Otherwise, combine the equality constraints from both into a new
+ * basic map such that Gaussian elimination can be applied to this combination
+ * and then construct a variable compression from the resulting
+ * equality constraints.
+ */
+static __isl_give isl_mat *combined_variable_compression(
+	__isl_keep isl_basic_map *bmap1, int n1,
+	__isl_keep isl_basic_map *bmap2, int n2, int total)
+{
+	isl_ctx *ctx;
+	isl_mat *E1, *E2, *V;
+	isl_basic_map *bmap;
+
+	ctx = isl_basic_map_get_ctx(bmap1);
+	if (bmap1->n_eq == n1) {
+		E2 = isl_mat_sub_alloc6(ctx, bmap2->eq,
+					n2, bmap2->n_eq - n2, 0, 1 + total);
+		return isl_mat_variable_compression(E2, NULL);
+	}
+	if (bmap2->n_eq == n2) {
+		E1 = isl_mat_sub_alloc6(ctx, bmap1->eq,
+					n1, bmap1->n_eq - n1, 0, 1 + total);
+		return isl_mat_variable_compression(E1, NULL);
+	}
+	E1 = isl_mat_sub_alloc6(ctx, bmap1->eq,
+				n1, bmap1->n_eq - n1, 0, 1 + total);
+	E2 = isl_mat_sub_alloc6(ctx, bmap2->eq,
+				n2, bmap2->n_eq - n2, 0, 1 + total);
+	E1 = isl_mat_concat(E1, E2);
+	bmap = basic_map_from_equalities(isl_basic_map_get_space(bmap1), E1);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	if (!bmap)
+		return NULL;
+	E1 = isl_mat_sub_alloc6(ctx, bmap->eq, 0, bmap->n_eq, 0, 1 + total);
+	V = isl_mat_variable_compression(E1, NULL);
+	isl_basic_map_free(bmap);
+
+	return V;
+}
+
+/* Extract the stride constraints from "bmap", compressed
+ * with respect to both the stride constraints in "context" and
+ * the remaining equality constraints in both "bmap" and "context".
+ * "bmap_n_eq" is the number of (initial) stride constraints in "bmap".
+ * "context_n_eq" is the number of (initial) stride constraints in "context".
+ *
+ * Let x be all variables in "bmap" (and "context") other than the local
+ * variables.  First compute a variable compression
+ *
+ *	x = V x'
+ *
+ * based on the non-stride equality constraints in "bmap" and "context".
+ * Consider the stride constraints of "context",
+ *
+ *	A(x) + B(y) = 0
+ *
+ * with y the local variables and plug in the variable compression,
+ * resulting in
+ *
+ *	A(V x') + B(y) = 0
+ *
+ * Use these constraints to compute a parameter compression on x'
+ *
+ *	x' = T x''
+ *
+ * Now consider the stride constraints of "bmap"
+ *
+ *	C(x) + D(y) = 0
+ *
+ * and plug in x = V*T x''.
+ * That is, return A = [C*V*T D].
+ */
+static __isl_give isl_mat *extract_compressed_stride_constraints(
+	__isl_keep isl_basic_map *bmap, int bmap_n_eq,
+	__isl_keep isl_basic_map *context, int context_n_eq)
+{
+	int total, n_div;
+	isl_ctx *ctx;
+	isl_mat *A, *B, *T, *V;
+
+	total = isl_basic_map_dim(context, isl_dim_all);
+	n_div = isl_basic_map_dim(context, isl_dim_div);
+	total -= n_div;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+
+	V = combined_variable_compression(bmap, bmap_n_eq,
+						context, context_n_eq, total);
+
+	A = isl_mat_sub_alloc6(ctx, context->eq, 0, context_n_eq, 0, 1 + total);
+	B = isl_mat_sub_alloc6(ctx, context->eq,
+				0, context_n_eq, 1 + total, n_div);
+	A = isl_mat_product(A, isl_mat_copy(V));
+	T = isl_mat_parameter_compression_ext(A, B);
+	T = isl_mat_product(V, T);
+
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	T = isl_mat_diagonal(T, isl_mat_identity(ctx, n_div));
+
+	A = isl_mat_sub_alloc6(ctx, bmap->eq,
+				0, bmap_n_eq, 0, 1 + total + n_div);
+	A = isl_mat_product(A, T);
+
+	return A;
+}
+
+/* Remove the prime factors from *g that have an exponent that
+ * is strictly smaller than the exponent in "c".
+ * All exponents in *g are known to be smaller than or equal
+ * to those in "c".
+ *
+ * That is, if *g is equal to
+ *
+ *	p_1^{e_1} p_2^{e_2} ... p_n^{e_n}
+ *
+ * and "c" is equal to
+ *
+ *	p_1^{f_1} p_2^{f_2} ... p_n^{f_n}
+ *
+ * then update *g to
+ *
+ *	p_1^{e_1 * (e_1 = f_1)} p_2^{e_2 * (e_2 = f_2)} ...
+ *		p_n^{e_n * (e_n = f_n)}
+ *
+ * If e_i = f_i, then c / *g does not have any p_i factors and therefore
+ * neither does the gcd of *g and c / *g.
+ * If e_i < f_i, then the gcd of *g and c / *g has a positive
+ * power min(e_i, s_i) of p_i with s_i = f_i - e_i among its factors.
+ * Dividing *g by this gcd therefore strictly reduces the exponent
+ * of the prime factors that need to be removed, while leaving the
+ * other prime factors untouched.
+ * Repeating this process until gcd(*g, c / *g) = 1 therefore
+ * removes all undesired factors, without removing any others.
+ */
+static void remove_incomplete_powers(isl_int *g, isl_int c)
+{
+	isl_int t;
+
+	isl_int_init(t);
+	for (;;) {
+		isl_int_divexact(t, c, *g);
+		isl_int_gcd(t, t, *g);
+		if (isl_int_is_one(t))
+			break;
+		isl_int_divexact(*g, *g, t);
+	}
+	isl_int_clear(t);
+}
+
+/* Reduce the "n" stride constraints in "bmap" based on a copy "A"
+ * of the same stride constraints in a compressed space that exploits
+ * all equalities in the context and the other equalities in "bmap".
+ *
+ * If the stride constraints of "bmap" are of the form
+ *
+ *	C(x) + D(y) = 0
+ *
+ * then A is of the form
+ *
+ *	B(x') + D(y) = 0
+ *
+ * If any of these constraints involves only a single local variable y,
+ * then the constraint appears as
+ *
+ *	f(x) + m y_i = 0
+ *
+ * in "bmap" and as
+ *
+ *	h(x') + m y_i = 0
+ *
+ * in "A".
+ *
+ * Let g be the gcd of m and the coefficients of h.
+ * Then, in particular, g is a divisor of the coefficients of h and
+ *
+ *	f(x) = h(x')
+ *
+ * is known to be a multiple of g.
+ * If some prime factor in m appears with the same exponent in g,
+ * then it can be removed from m because f(x) is already known
+ * to be a multiple of g and therefore in particular of this power
+ * of the prime factors.
+ * Prime factors that appear with a smaller exponent in g cannot
+ * be removed from m.
+ * Let g' be the divisor of g containing all prime factors that
+ * appear with the same exponent in m and g, then
+ *
+ *	f(x) + m y_i = 0
+ *
+ * can be replaced by
+ *
+ *	f(x) + m/g' y_i' = 0
+ *
+ * Note that (if g' != 1) this changes the explicit representation
+ * of y_i to that of y_i', so the integer division at position i
+ * is marked unknown and later recomputed by a call to
+ * isl_basic_map_gauss.
+ */
+static __isl_give isl_basic_map *reduce_stride_constraints(
+	__isl_take isl_basic_map *bmap, int n, __isl_keep isl_mat *A)
+{
+	int i;
+	int total, n_div;
+	int any = 0;
+	isl_int gcd;
+
+	if (!bmap || !A)
+		return isl_basic_map_free(bmap);
+
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	total -= n_div;
+
+	isl_int_init(gcd);
+	for (i = 0; i < n; ++i) {
+		int div;
+
+		div = isl_seq_first_non_zero(bmap->eq[i] + 1 + total, n_div);
+		if (div < 0)
+			isl_die(isl_basic_map_get_ctx(bmap), isl_error_internal,
+				"equality constraints modified unexpectedly",
+				goto error);
+		if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total + div + 1,
+						n_div - div - 1) != -1)
+			continue;
+		if (isl_mat_row_gcd(A, i, &gcd) < 0)
+			goto error;
+		if (isl_int_is_one(gcd))
+			continue;
+		remove_incomplete_powers(&gcd, bmap->eq[i][1 + total + div]);
+		if (isl_int_is_one(gcd))
+			continue;
+		isl_int_divexact(bmap->eq[i][1 + total + div],
+				bmap->eq[i][1 + total + div], gcd);
+		bmap = isl_basic_map_mark_div_unknown(bmap, div);
+		if (!bmap)
+			goto error;
+		any = 1;
+	}
+	isl_int_clear(gcd);
+
+	if (any)
+		bmap = isl_basic_map_gauss(bmap, NULL);
+
+	return bmap;
+error:
+	isl_int_clear(gcd);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Simplify the stride constraints in "bmap" based on
+ * the remaining equality constraints in "bmap" and all equality
+ * constraints in "context".
+ * Only do this if both "bmap" and "context" have stride constraints.
+ *
+ * First extract a copy of the stride constraints in "bmap" in a compressed
+ * space exploiting all the other equality constraints and then
+ * use this compressed copy to simplify the original stride constraints.
+ */
+static __isl_give isl_basic_map *gist_strides(__isl_take isl_basic_map *bmap,
+	__isl_keep isl_basic_map *context)
+{
+	int bmap_n_eq, context_n_eq;
+	isl_mat *A;
+
+	if (!bmap || !context)
+		return isl_basic_map_free(bmap);
+
+	bmap_n_eq = n_div_eq(bmap);
+	context_n_eq = n_div_eq(context);
+
+	if (bmap_n_eq < 0 || context_n_eq < 0)
+		return isl_basic_map_free(bmap);
+	if (bmap_n_eq == 0 || context_n_eq == 0)
+		return bmap;
+
+	A = extract_compressed_stride_constraints(bmap, bmap_n_eq,
+						    context, context_n_eq);
+	bmap = reduce_stride_constraints(bmap, bmap_n_eq, A);
+
+	isl_mat_free(A);
+
+	return bmap;
+}
+
+/* Return a basic map that has the same intersection with "context" as "bmap"
+ * and that is as "simple" as possible.
+ *
+ * The core computation is performed on the pure constraints.
+ * When we add back the meaning of the integer divisions, we need
+ * to (re)introduce the div constraints.  If we happen to have
+ * discovered that some of these integer divisions are equal to
+ * some affine combination of other variables, then these div
+ * constraints may end up getting simplified in terms of the equalities,
+ * resulting in extra inequalities on the other variables that
+ * may have been removed already or that may not even have been
+ * part of the input.  We try and remove those constraints of
+ * this form that are most obviously redundant with respect to
+ * the context.  We also remove those div constraints that are
+ * redundant with respect to the other constraints in the result.
+ *
+ * The stride constraints among the equality constraints in "bmap" are
+ * also simplified with respecting to the other equality constraints
+ * in "bmap" and with respect to all equality constraints in "context".
+ */
+__isl_give isl_basic_map *isl_basic_map_gist(__isl_take isl_basic_map *bmap,
+	__isl_take isl_basic_map *context)
+{
+	isl_basic_set *bset, *eq;
+	isl_basic_map *eq_bmap;
+	unsigned total, n_div, extra, n_eq, n_ineq;
+
+	if (!bmap || !context)
+		goto error;
+
+	if (isl_basic_map_plain_is_universe(bmap)) {
+		isl_basic_map_free(context);
+		return bmap;
+	}
+	if (isl_basic_map_plain_is_empty(context)) {
+		isl_space *space = isl_basic_map_get_space(bmap);
+		isl_basic_map_free(bmap);
+		isl_basic_map_free(context);
+		return isl_basic_map_universe(space);
+	}
+	if (isl_basic_map_plain_is_empty(bmap)) {
+		isl_basic_map_free(context);
+		return bmap;
+	}
+
+	bmap = isl_basic_map_remove_redundancies(bmap);
+	context = isl_basic_map_remove_redundancies(context);
+	if (!context)
+		goto error;
+
+	context = isl_basic_map_align_divs(context, bmap);
+	n_div = isl_basic_map_dim(context, isl_dim_div);
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	extra = n_div - isl_basic_map_dim(bmap, isl_dim_div);
+
+	bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap));
+	bset = isl_basic_set_add_dims(bset, isl_dim_set, extra);
+	bset = uset_gist(bset,
+		    isl_basic_map_underlying_set(isl_basic_map_copy(context)));
+	bset = isl_basic_set_project_out(bset, isl_dim_set, total, extra);
+
+	if (!bset || bset->n_eq == 0 || n_div == 0 ||
+	    isl_basic_set_plain_is_empty(bset)) {
+		isl_basic_map_free(context);
+		return isl_basic_map_overlying_set(bset, bmap);
+	}
+
+	n_eq = bset->n_eq;
+	n_ineq = bset->n_ineq;
+	eq = isl_basic_set_copy(bset);
+	eq = isl_basic_set_cow(eq);
+	if (isl_basic_set_free_inequality(eq, n_ineq) < 0)
+		eq = isl_basic_set_free(eq);
+	if (isl_basic_set_free_equality(bset, n_eq) < 0)
+		bset = isl_basic_set_free(bset);
+
+	eq_bmap = isl_basic_map_overlying_set(eq, isl_basic_map_copy(bmap));
+	eq_bmap = gist_strides(eq_bmap, context);
+	eq_bmap = isl_basic_map_remove_shifted_constraints(eq_bmap, context);
+	bmap = isl_basic_map_overlying_set(bset, bmap);
+	bmap = isl_basic_map_intersect(bmap, eq_bmap);
+	bmap = isl_basic_map_remove_redundancies(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_basic_map_free(context);
+	return NULL;
+}
+
+/*
+ * Assumes context has no implicit divs.
+ */
+__isl_give isl_map *isl_map_gist_basic_map(__isl_take isl_map *map,
+	__isl_take isl_basic_map *context)
+{
+	int i;
+
+	if (!map || !context)
+		goto error;
+
+	if (isl_basic_map_plain_is_empty(context)) {
+		isl_space *space = isl_map_get_space(map);
+		isl_map_free(map);
+		isl_basic_map_free(context);
+		return isl_map_universe(space);
+	}
+
+	context = isl_basic_map_remove_redundancies(context);
+	map = isl_map_cow(map);
+	if (!map || !context)
+		goto error;
+	isl_assert(map->ctx, isl_space_is_equal(map->dim, context->dim), goto error);
+	map = isl_map_compute_divs(map);
+	if (!map)
+		goto error;
+	for (i = map->n - 1; i >= 0; --i) {
+		map->p[i] = isl_basic_map_gist(map->p[i],
+						isl_basic_map_copy(context));
+		if (!map->p[i])
+			goto error;
+		if (isl_basic_map_plain_is_empty(map->p[i])) {
+			isl_basic_map_free(map->p[i]);
+			if (i != map->n - 1)
+				map->p[i] = map->p[map->n - 1];
+			map->n--;
+		}
+	}
+	isl_basic_map_free(context);
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	return map;
+error:
+	isl_map_free(map);
+	isl_basic_map_free(context);
+	return NULL;
+}
+
+/* Drop all inequalities from "bmap" that also appear in "context".
+ * "context" is assumed to have only known local variables and
+ * the initial local variables of "bmap" are assumed to be the same
+ * as those of "context".
+ * The constraints of both "bmap" and "context" are assumed
+ * to have been sorted using isl_basic_map_sort_constraints.
+ *
+ * Run through the inequality constraints of "bmap" and "context"
+ * in sorted order.
+ * If a constraint of "bmap" involves variables not in "context",
+ * then it cannot appear in "context".
+ * If a matching constraint is found, it is removed from "bmap".
+ */
+static __isl_give isl_basic_map *drop_inequalities(
+	__isl_take isl_basic_map *bmap, __isl_keep isl_basic_map *context)
+{
+	int i1, i2;
+	unsigned total, extra;
+
+	if (!bmap || !context)
+		return isl_basic_map_free(bmap);
+
+	total = isl_basic_map_total_dim(context);
+	extra = isl_basic_map_total_dim(bmap) - total;
+
+	i1 = bmap->n_ineq - 1;
+	i2 = context->n_ineq - 1;
+	while (bmap && i1 >= 0 && i2 >= 0) {
+		int cmp;
+
+		if (isl_seq_first_non_zero(bmap->ineq[i1] + 1 + total,
+					    extra) != -1) {
+			--i1;
+			continue;
+		}
+		cmp = isl_basic_map_constraint_cmp(context, bmap->ineq[i1],
+							context->ineq[i2]);
+		if (cmp < 0) {
+			--i2;
+			continue;
+		}
+		if (cmp > 0) {
+			--i1;
+			continue;
+		}
+		if (isl_int_eq(bmap->ineq[i1][0], context->ineq[i2][0])) {
+			bmap = isl_basic_map_cow(bmap);
+			if (isl_basic_map_drop_inequality(bmap, i1) < 0)
+				bmap = isl_basic_map_free(bmap);
+		}
+		--i1;
+		--i2;
+	}
+
+	return bmap;
+}
+
+/* Drop all equalities from "bmap" that also appear in "context".
+ * "context" is assumed to have only known local variables and
+ * the initial local variables of "bmap" are assumed to be the same
+ * as those of "context".
+ *
+ * Run through the equality constraints of "bmap" and "context"
+ * in sorted order.
+ * If a constraint of "bmap" involves variables not in "context",
+ * then it cannot appear in "context".
+ * If a matching constraint is found, it is removed from "bmap".
+ */
+static __isl_give isl_basic_map *drop_equalities(
+	__isl_take isl_basic_map *bmap, __isl_keep isl_basic_map *context)
+{
+	int i1, i2;
+	unsigned total, extra;
+
+	if (!bmap || !context)
+		return isl_basic_map_free(bmap);
+
+	total = isl_basic_map_total_dim(context);
+	extra = isl_basic_map_total_dim(bmap) - total;
+
+	i1 = bmap->n_eq - 1;
+	i2 = context->n_eq - 1;
+
+	while (bmap && i1 >= 0 && i2 >= 0) {
+		int last1, last2;
+
+		if (isl_seq_first_non_zero(bmap->eq[i1] + 1 + total,
+					    extra) != -1)
+			break;
+		last1 = isl_seq_last_non_zero(bmap->eq[i1] + 1, total);
+		last2 = isl_seq_last_non_zero(context->eq[i2] + 1, total);
+		if (last1 > last2) {
+			--i2;
+			continue;
+		}
+		if (last1 < last2) {
+			--i1;
+			continue;
+		}
+		if (isl_seq_eq(bmap->eq[i1], context->eq[i2], 1 + total)) {
+			bmap = isl_basic_map_cow(bmap);
+			if (isl_basic_map_drop_equality(bmap, i1) < 0)
+				bmap = isl_basic_map_free(bmap);
+		}
+		--i1;
+		--i2;
+	}
+
+	return bmap;
+}
+
+/* Remove the constraints in "context" from "bmap".
+ * "context" is assumed to have explicit representations
+ * for all local variables.
+ *
+ * First align the divs of "bmap" to those of "context" and
+ * sort the constraints.  Then drop all constraints from "bmap"
+ * that appear in "context".
+ */
+__isl_give isl_basic_map *isl_basic_map_plain_gist(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_map *context)
+{
+	isl_bool done, known;
+
+	done = isl_basic_map_plain_is_universe(context);
+	if (done == isl_bool_false)
+		done = isl_basic_map_plain_is_universe(bmap);
+	if (done == isl_bool_false)
+		done = isl_basic_map_plain_is_empty(context);
+	if (done == isl_bool_false)
+		done = isl_basic_map_plain_is_empty(bmap);
+	if (done < 0)
+		goto error;
+	if (done) {
+		isl_basic_map_free(context);
+		return bmap;
+	}
+	known = isl_basic_map_divs_known(context);
+	if (known < 0)
+		goto error;
+	if (!known)
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"context has unknown divs", goto error);
+
+	bmap = isl_basic_map_align_divs(bmap, context);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	bmap = isl_basic_map_sort_constraints(bmap);
+	context = isl_basic_map_sort_constraints(context);
+
+	bmap = drop_inequalities(bmap, context);
+	bmap = drop_equalities(bmap, context);
+
+	isl_basic_map_free(context);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_basic_map_free(context);
+	return NULL;
+}
+
+/* Replace "map" by the disjunct at position "pos" and free "context".
+ */
+static __isl_give isl_map *replace_by_disjunct(__isl_take isl_map *map,
+	int pos, __isl_take isl_basic_map *context)
+{
+	isl_basic_map *bmap;
+
+	bmap = isl_basic_map_copy(map->p[pos]);
+	isl_map_free(map);
+	isl_basic_map_free(context);
+	return isl_map_from_basic_map(bmap);
+}
+
+/* Remove the constraints in "context" from "map".
+ * If any of the disjuncts in the result turns out to be the universe,
+ * then return this universe.
+ * "context" is assumed to have explicit representations
+ * for all local variables.
+ */
+__isl_give isl_map *isl_map_plain_gist_basic_map(__isl_take isl_map *map,
+	__isl_take isl_basic_map *context)
+{
+	int i;
+	isl_bool univ, known;
+
+	univ = isl_basic_map_plain_is_universe(context);
+	if (univ < 0)
+		goto error;
+	if (univ) {
+		isl_basic_map_free(context);
+		return map;
+	}
+	known = isl_basic_map_divs_known(context);
+	if (known < 0)
+		goto error;
+	if (!known)
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"context has unknown divs", goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		goto error;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_plain_gist(map->p[i],
+						isl_basic_map_copy(context));
+		univ = isl_basic_map_plain_is_universe(map->p[i]);
+		if (univ < 0)
+			goto error;
+		if (univ && map->n > 1)
+			return replace_by_disjunct(map, i, context);
+	}
+
+	isl_basic_map_free(context);
+	ISL_F_CLR(map, ISL_MAP_NORMALIZED);
+	if (map->n > 1)
+		ISL_F_CLR(map, ISL_MAP_DISJOINT);
+	return map;
+error:
+	isl_map_free(map);
+	isl_basic_map_free(context);
+	return NULL;
+}
+
+/* Remove the constraints in "context" from "set".
+ * If any of the disjuncts in the result turns out to be the universe,
+ * then return this universe.
+ * "context" is assumed to have explicit representations
+ * for all local variables.
+ */
+__isl_give isl_set *isl_set_plain_gist_basic_set(__isl_take isl_set *set,
+	__isl_take isl_basic_set *context)
+{
+	return set_from_map(isl_map_plain_gist_basic_map(set_to_map(set),
+							bset_to_bmap(context)));
+}
+
+/* Remove the constraints in "context" from "map".
+ * If any of the disjuncts in the result turns out to be the universe,
+ * then return this universe.
+ * "context" is assumed to consist of a single disjunct and
+ * to have explicit representations for all local variables.
+ */
+__isl_give isl_map *isl_map_plain_gist(__isl_take isl_map *map,
+	__isl_take isl_map *context)
+{
+	isl_basic_map *hull;
+
+	hull = isl_map_unshifted_simple_hull(context);
+	return isl_map_plain_gist_basic_map(map, hull);
+}
+
+/* Replace "map" by a universe map in the same space and free "drop".
+ */
+static __isl_give isl_map *replace_by_universe(__isl_take isl_map *map,
+	__isl_take isl_map *drop)
+{
+	isl_map *res;
+
+	res = isl_map_universe(isl_map_get_space(map));
+	isl_map_free(map);
+	isl_map_free(drop);
+	return res;
+}
+
+/* Return a map that has the same intersection with "context" as "map"
+ * and that is as "simple" as possible.
+ *
+ * If "map" is already the universe, then we cannot make it any simpler.
+ * Similarly, if "context" is the universe, then we cannot exploit it
+ * to simplify "map"
+ * If "map" and "context" are identical to each other, then we can
+ * return the corresponding universe.
+ *
+ * If either "map" or "context" consists of multiple disjuncts,
+ * then check if "context" happens to be a subset of "map",
+ * in which case all constraints can be removed.
+ * In case of multiple disjuncts, the standard procedure
+ * may not be able to detect that all constraints can be removed.
+ *
+ * If none of these cases apply, we have to work a bit harder.
+ * During this computation, we make use of a single disjunct context,
+ * so if the original context consists of more than one disjunct
+ * then we need to approximate the context by a single disjunct set.
+ * Simply taking the simple hull may drop constraints that are
+ * only implicitly available in each disjunct.  We therefore also
+ * look for constraints among those defining "map" that are valid
+ * for the context.  These can then be used to simplify away
+ * the corresponding constraints in "map".
+ */
+static __isl_give isl_map *map_gist(__isl_take isl_map *map,
+	__isl_take isl_map *context)
+{
+	int equal;
+	int is_universe;
+	int single_disjunct_map, single_disjunct_context;
+	isl_bool subset;
+	isl_basic_map *hull;
+
+	is_universe = isl_map_plain_is_universe(map);
+	if (is_universe >= 0 && !is_universe)
+		is_universe = isl_map_plain_is_universe(context);
+	if (is_universe < 0)
+		goto error;
+	if (is_universe) {
+		isl_map_free(context);
+		return map;
+	}
+
+	equal = isl_map_plain_is_equal(map, context);
+	if (equal < 0)
+		goto error;
+	if (equal)
+		return replace_by_universe(map, context);
+
+	single_disjunct_map = isl_map_n_basic_map(map) == 1;
+	single_disjunct_context = isl_map_n_basic_map(context) == 1;
+	if (!single_disjunct_map || !single_disjunct_context) {
+		subset = isl_map_is_subset(context, map);
+		if (subset < 0)
+			goto error;
+		if (subset)
+			return replace_by_universe(map, context);
+	}
+
+	context = isl_map_compute_divs(context);
+	if (!context)
+		goto error;
+	if (single_disjunct_context) {
+		hull = isl_map_simple_hull(context);
+	} else {
+		isl_ctx *ctx;
+		isl_map_list *list;
+
+		ctx = isl_map_get_ctx(map);
+		list = isl_map_list_alloc(ctx, 2);
+		list = isl_map_list_add(list, isl_map_copy(context));
+		list = isl_map_list_add(list, isl_map_copy(map));
+		hull = isl_map_unshifted_simple_hull_from_map_list(context,
+								    list);
+	}
+	return isl_map_gist_basic_map(map, hull);
+error:
+	isl_map_free(map);
+	isl_map_free(context);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_gist(__isl_take isl_map *map,
+	__isl_take isl_map *context)
+{
+	return isl_map_align_params_map_map_and(map, context, &map_gist);
+}
+
+struct isl_basic_set *isl_basic_set_gist(struct isl_basic_set *bset,
+						struct isl_basic_set *context)
+{
+	return bset_from_bmap(isl_basic_map_gist(bset_to_bmap(bset),
+						bset_to_bmap(context)));
+}
+
+__isl_give isl_set *isl_set_gist_basic_set(__isl_take isl_set *set,
+	__isl_take isl_basic_set *context)
+{
+	return set_from_map(isl_map_gist_basic_map(set_to_map(set),
+					bset_to_bmap(context)));
+}
+
+__isl_give isl_set *isl_set_gist_params_basic_set(__isl_take isl_set *set,
+	__isl_take isl_basic_set *context)
+{
+	isl_space *space = isl_set_get_space(set);
+	isl_basic_set *dom_context = isl_basic_set_universe(space);
+	dom_context = isl_basic_set_intersect_params(dom_context, context);
+	return isl_set_gist_basic_set(set, dom_context);
+}
+
+__isl_give isl_set *isl_set_gist(__isl_take isl_set *set,
+	__isl_take isl_set *context)
+{
+	return set_from_map(isl_map_gist(set_to_map(set), set_to_map(context)));
+}
+
+/* Compute the gist of "bmap" with respect to the constraints "context"
+ * on the domain.
+ */
+__isl_give isl_basic_map *isl_basic_map_gist_domain(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *context)
+{
+	isl_space *space = isl_basic_map_get_space(bmap);
+	isl_basic_map *bmap_context = isl_basic_map_universe(space);
+
+	bmap_context = isl_basic_map_intersect_domain(bmap_context, context);
+	return isl_basic_map_gist(bmap, bmap_context);
+}
+
+__isl_give isl_map *isl_map_gist_domain(__isl_take isl_map *map,
+	__isl_take isl_set *context)
+{
+	isl_map *map_context = isl_map_universe(isl_map_get_space(map));
+	map_context = isl_map_intersect_domain(map_context, context);
+	return isl_map_gist(map, map_context);
+}
+
+__isl_give isl_map *isl_map_gist_range(__isl_take isl_map *map,
+	__isl_take isl_set *context)
+{
+	isl_map *map_context = isl_map_universe(isl_map_get_space(map));
+	map_context = isl_map_intersect_range(map_context, context);
+	return isl_map_gist(map, map_context);
+}
+
+__isl_give isl_map *isl_map_gist_params(__isl_take isl_map *map,
+	__isl_take isl_set *context)
+{
+	isl_map *map_context = isl_map_universe(isl_map_get_space(map));
+	map_context = isl_map_intersect_params(map_context, context);
+	return isl_map_gist(map, map_context);
+}
+
+__isl_give isl_set *isl_set_gist_params(__isl_take isl_set *set,
+	__isl_take isl_set *context)
+{
+	return isl_map_gist_params(set, context);
+}
+
+/* Quick check to see if two basic maps are disjoint.
+ * In particular, we reduce the equalities and inequalities of
+ * one basic map in the context of the equalities of the other
+ * basic map and check if we get a contradiction.
+ */
+isl_bool isl_basic_map_plain_is_disjoint(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	struct isl_vec *v = NULL;
+	int *elim = NULL;
+	unsigned total;
+	int i;
+
+	if (!bmap1 || !bmap2)
+		return isl_bool_error;
+	isl_assert(bmap1->ctx, isl_space_is_equal(bmap1->dim, bmap2->dim),
+			return isl_bool_error);
+	if (bmap1->n_div || bmap2->n_div)
+		return isl_bool_false;
+	if (!bmap1->n_eq && !bmap2->n_eq)
+		return isl_bool_false;
+
+	total = isl_space_dim(bmap1->dim, isl_dim_all);
+	if (total == 0)
+		return isl_bool_false;
+	v = isl_vec_alloc(bmap1->ctx, 1 + total);
+	if (!v)
+		goto error;
+	elim = isl_alloc_array(bmap1->ctx, int, total);
+	if (!elim)
+		goto error;
+	compute_elimination_index(bmap1, elim);
+	for (i = 0; i < bmap2->n_eq; ++i) {
+		int reduced;
+		reduced = reduced_using_equalities(v->block.data, bmap2->eq[i],
+							bmap1, elim);
+		if (reduced && !isl_int_is_zero(v->block.data[0]) &&
+		    isl_seq_first_non_zero(v->block.data + 1, total) == -1)
+			goto disjoint;
+	}
+	for (i = 0; i < bmap2->n_ineq; ++i) {
+		int reduced;
+		reduced = reduced_using_equalities(v->block.data,
+						bmap2->ineq[i], bmap1, elim);
+		if (reduced && isl_int_is_neg(v->block.data[0]) &&
+		    isl_seq_first_non_zero(v->block.data + 1, total) == -1)
+			goto disjoint;
+	}
+	compute_elimination_index(bmap2, elim);
+	for (i = 0; i < bmap1->n_ineq; ++i) {
+		int reduced;
+		reduced = reduced_using_equalities(v->block.data,
+						bmap1->ineq[i], bmap2, elim);
+		if (reduced && isl_int_is_neg(v->block.data[0]) &&
+		    isl_seq_first_non_zero(v->block.data + 1, total) == -1)
+			goto disjoint;
+	}
+	isl_vec_free(v);
+	free(elim);
+	return isl_bool_false;
+disjoint:
+	isl_vec_free(v);
+	free(elim);
+	return isl_bool_true;
+error:
+	isl_vec_free(v);
+	free(elim);
+	return isl_bool_error;
+}
+
+int isl_basic_set_plain_is_disjoint(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2)
+{
+	return isl_basic_map_plain_is_disjoint(bset_to_bmap(bset1),
+					      bset_to_bmap(bset2));
+}
+
+/* Does "test" hold for all pairs of basic maps in "map1" and "map2"?
+ */
+static isl_bool all_pairs(__isl_keep isl_map *map1, __isl_keep isl_map *map2,
+	isl_bool (*test)(__isl_keep isl_basic_map *bmap1,
+		__isl_keep isl_basic_map *bmap2))
+{
+	int i, j;
+
+	if (!map1 || !map2)
+		return isl_bool_error;
+
+	for (i = 0; i < map1->n; ++i) {
+		for (j = 0; j < map2->n; ++j) {
+			isl_bool d = test(map1->p[i], map2->p[j]);
+			if (d != isl_bool_true)
+				return d;
+		}
+	}
+
+	return isl_bool_true;
+}
+
+/* Are "map1" and "map2" obviously disjoint, based on information
+ * that can be derived without looking at the individual basic maps?
+ *
+ * In particular, if one of them is empty or if they live in different spaces
+ * (ignoring parameters), then they are clearly disjoint.
+ */
+static isl_bool isl_map_plain_is_disjoint_global(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2)
+{
+	isl_bool disjoint;
+	isl_bool match;
+
+	if (!map1 || !map2)
+		return isl_bool_error;
+
+	disjoint = isl_map_plain_is_empty(map1);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	disjoint = isl_map_plain_is_empty(map2);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	match = isl_space_tuple_is_equal(map1->dim, isl_dim_in,
+				map2->dim, isl_dim_in);
+	if (match < 0 || !match)
+		return match < 0 ? isl_bool_error : isl_bool_true;
+
+	match = isl_space_tuple_is_equal(map1->dim, isl_dim_out,
+				map2->dim, isl_dim_out);
+	if (match < 0 || !match)
+		return match < 0 ? isl_bool_error : isl_bool_true;
+
+	return isl_bool_false;
+}
+
+/* Are "map1" and "map2" obviously disjoint?
+ *
+ * If one of them is empty or if they live in different spaces (ignoring
+ * parameters), then they are clearly disjoint.
+ * This is checked by isl_map_plain_is_disjoint_global.
+ *
+ * If they have different parameters, then we skip any further tests.
+ *
+ * If they are obviously equal, but not obviously empty, then we will
+ * not be able to detect if they are disjoint.
+ *
+ * Otherwise we check if each basic map in "map1" is obviously disjoint
+ * from each basic map in "map2".
+ */
+isl_bool isl_map_plain_is_disjoint(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2)
+{
+	isl_bool disjoint;
+	isl_bool intersect;
+	isl_bool match;
+
+	disjoint = isl_map_plain_is_disjoint_global(map1, map2);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	match = isl_map_has_equal_params(map1, map2);
+	if (match < 0 || !match)
+		return match < 0 ? isl_bool_error : isl_bool_false;
+
+	intersect = isl_map_plain_is_equal(map1, map2);
+	if (intersect < 0 || intersect)
+		return intersect < 0 ? isl_bool_error : isl_bool_false;
+
+	return all_pairs(map1, map2, &isl_basic_map_plain_is_disjoint);
+}
+
+/* Are "map1" and "map2" disjoint?
+ * The parameters are assumed to have been aligned.
+ *
+ * In particular, check whether all pairs of basic maps are disjoint.
+ */
+static isl_bool isl_map_is_disjoint_aligned(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2)
+{
+	return all_pairs(map1, map2, &isl_basic_map_is_disjoint);
+}
+
+/* Are "map1" and "map2" disjoint?
+ *
+ * They are disjoint if they are "obviously disjoint" or if one of them
+ * is empty.  Otherwise, they are not disjoint if one of them is universal.
+ * If the two inputs are (obviously) equal and not empty, then they are
+ * not disjoint.
+ * If none of these cases apply, then check if all pairs of basic maps
+ * are disjoint after aligning the parameters.
+ */
+isl_bool isl_map_is_disjoint(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	isl_bool disjoint;
+	isl_bool intersect;
+
+	disjoint = isl_map_plain_is_disjoint_global(map1, map2);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	disjoint = isl_map_is_empty(map1);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	disjoint = isl_map_is_empty(map2);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	intersect = isl_map_plain_is_universe(map1);
+	if (intersect < 0 || intersect)
+		return intersect < 0 ? isl_bool_error : isl_bool_false;
+
+	intersect = isl_map_plain_is_universe(map2);
+	if (intersect < 0 || intersect)
+		return intersect < 0 ? isl_bool_error : isl_bool_false;
+
+	intersect = isl_map_plain_is_equal(map1, map2);
+	if (intersect < 0 || intersect)
+		return isl_bool_not(intersect);
+
+	return isl_map_align_params_map_map_and_test(map1, map2,
+						&isl_map_is_disjoint_aligned);
+}
+
+/* Are "bmap1" and "bmap2" disjoint?
+ *
+ * They are disjoint if they are "obviously disjoint" or if one of them
+ * is empty.  Otherwise, they are not disjoint if one of them is universal.
+ * If none of these cases apply, we compute the intersection and see if
+ * the result is empty.
+ */
+isl_bool isl_basic_map_is_disjoint(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	isl_bool disjoint;
+	isl_bool intersect;
+	isl_basic_map *test;
+
+	disjoint = isl_basic_map_plain_is_disjoint(bmap1, bmap2);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	disjoint = isl_basic_map_is_empty(bmap1);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	disjoint = isl_basic_map_is_empty(bmap2);
+	if (disjoint < 0 || disjoint)
+		return disjoint;
+
+	intersect = isl_basic_map_plain_is_universe(bmap1);
+	if (intersect < 0 || intersect)
+		return intersect < 0 ? isl_bool_error : isl_bool_false;
+
+	intersect = isl_basic_map_plain_is_universe(bmap2);
+	if (intersect < 0 || intersect)
+		return intersect < 0 ? isl_bool_error : isl_bool_false;
+
+	test = isl_basic_map_intersect(isl_basic_map_copy(bmap1),
+		isl_basic_map_copy(bmap2));
+	disjoint = isl_basic_map_is_empty(test);
+	isl_basic_map_free(test);
+
+	return disjoint;
+}
+
+/* Are "bset1" and "bset2" disjoint?
+ */
+isl_bool isl_basic_set_is_disjoint(__isl_keep isl_basic_set *bset1,
+	__isl_keep isl_basic_set *bset2)
+{
+	return isl_basic_map_is_disjoint(bset1, bset2);
+}
+
+isl_bool isl_set_plain_is_disjoint(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2)
+{
+	return isl_map_plain_is_disjoint(set_to_map(set1), set_to_map(set2));
+}
+
+/* Are "set1" and "set2" disjoint?
+ */
+isl_bool isl_set_is_disjoint(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	return isl_map_is_disjoint(set1, set2);
+}
+
+/* Is "v" equal to 0, 1 or -1?
+ */
+static int is_zero_or_one(isl_int v)
+{
+	return isl_int_is_zero(v) || isl_int_is_one(v) || isl_int_is_negone(v);
+}
+
+/* Check if we can combine a given div with lower bound l and upper
+ * bound u with some other div and if so return that other div.
+ * Otherwise return -1.
+ *
+ * We first check that
+ *	- the bounds are opposites of each other (except for the constant
+ *	  term)
+ *	- the bounds do not reference any other div
+ *	- no div is defined in terms of this div
+ *
+ * Let m be the size of the range allowed on the div by the bounds.
+ * That is, the bounds are of the form
+ *
+ *	e <= a <= e + m - 1
+ *
+ * with e some expression in the other variables.
+ * We look for another div b such that no third div is defined in terms
+ * of this second div b and such that in any constraint that contains
+ * a (except for the given lower and upper bound), also contains b
+ * with a coefficient that is m times that of b.
+ * That is, all constraints (except for the lower and upper bound)
+ * are of the form
+ *
+ *	e + f (a + m b) >= 0
+ *
+ * Furthermore, in the constraints that only contain b, the coefficient
+ * of b should be equal to 1 or -1.
+ * If so, we return b so that "a + m b" can be replaced by
+ * a single div "c = a + m b".
+ */
+static int div_find_coalesce(struct isl_basic_map *bmap, int *pairs,
+	unsigned div, unsigned l, unsigned u)
+{
+	int i, j;
+	unsigned dim;
+	int coalesce = -1;
+
+	if (bmap->n_div <= 1)
+		return -1;
+	dim = isl_space_dim(bmap->dim, isl_dim_all);
+	if (isl_seq_first_non_zero(bmap->ineq[l] + 1 + dim, div) != -1)
+		return -1;
+	if (isl_seq_first_non_zero(bmap->ineq[l] + 1 + dim + div + 1,
+				   bmap->n_div - div - 1) != -1)
+		return -1;
+	if (!isl_seq_is_neg(bmap->ineq[l] + 1, bmap->ineq[u] + 1,
+			    dim + bmap->n_div))
+		return -1;
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (!isl_int_is_zero(bmap->div[i][1 + 1 + dim + div]))
+			return -1;
+	}
+
+	isl_int_add(bmap->ineq[l][0], bmap->ineq[l][0], bmap->ineq[u][0]);
+	if (isl_int_is_neg(bmap->ineq[l][0])) {
+		isl_int_sub(bmap->ineq[l][0],
+			    bmap->ineq[l][0], bmap->ineq[u][0]);
+		bmap = isl_basic_map_copy(bmap);
+		bmap = isl_basic_map_set_to_empty(bmap);
+		isl_basic_map_free(bmap);
+		return -1;
+	}
+	isl_int_add_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1);
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (i == div)
+			continue;
+		if (!pairs[i])
+			continue;
+		for (j = 0; j < bmap->n_div; ++j) {
+			if (isl_int_is_zero(bmap->div[j][0]))
+				continue;
+			if (!isl_int_is_zero(bmap->div[j][1 + 1 + dim + i]))
+				break;
+		}
+		if (j < bmap->n_div)
+			continue;
+		for (j = 0; j < bmap->n_ineq; ++j) {
+			int valid;
+			if (j == l || j == u)
+				continue;
+			if (isl_int_is_zero(bmap->ineq[j][1 + dim + div])) {
+				if (is_zero_or_one(bmap->ineq[j][1 + dim + i]))
+					continue;
+				break;
+			}
+			if (isl_int_is_zero(bmap->ineq[j][1 + dim + i]))
+				break;
+			isl_int_mul(bmap->ineq[j][1 + dim + div],
+				    bmap->ineq[j][1 + dim + div],
+				    bmap->ineq[l][0]);
+			valid = isl_int_eq(bmap->ineq[j][1 + dim + div],
+					   bmap->ineq[j][1 + dim + i]);
+			isl_int_divexact(bmap->ineq[j][1 + dim + div],
+					 bmap->ineq[j][1 + dim + div],
+					 bmap->ineq[l][0]);
+			if (!valid)
+				break;
+		}
+		if (j < bmap->n_ineq)
+			continue;
+		coalesce = i;
+		break;
+	}
+	isl_int_sub_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1);
+	isl_int_sub(bmap->ineq[l][0], bmap->ineq[l][0], bmap->ineq[u][0]);
+	return coalesce;
+}
+
+/* Internal data structure used during the construction and/or evaluation of
+ * an inequality that ensures that a pair of bounds always allows
+ * for an integer value.
+ *
+ * "tab" is the tableau in which the inequality is evaluated.  It may
+ * be NULL until it is actually needed.
+ * "v" contains the inequality coefficients.
+ * "g", "fl" and "fu" are temporary scalars used during the construction and
+ * evaluation.
+ */
+struct test_ineq_data {
+	struct isl_tab *tab;
+	isl_vec *v;
+	isl_int g;
+	isl_int fl;
+	isl_int fu;
+};
+
+/* Free all the memory allocated by the fields of "data".
+ */
+static void test_ineq_data_clear(struct test_ineq_data *data)
+{
+	isl_tab_free(data->tab);
+	isl_vec_free(data->v);
+	isl_int_clear(data->g);
+	isl_int_clear(data->fl);
+	isl_int_clear(data->fu);
+}
+
+/* Is the inequality stored in data->v satisfied by "bmap"?
+ * That is, does it only attain non-negative values?
+ * data->tab is a tableau corresponding to "bmap".
+ */
+static isl_bool test_ineq_is_satisfied(__isl_keep isl_basic_map *bmap,
+	struct test_ineq_data *data)
+{
+	isl_ctx *ctx;
+	enum isl_lp_result res;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	if (!data->tab)
+		data->tab = isl_tab_from_basic_map(bmap, 0);
+	res = isl_tab_min(data->tab, data->v->el, ctx->one, &data->g, NULL, 0);
+	if (res == isl_lp_error)
+		return isl_bool_error;
+	return res == isl_lp_ok && isl_int_is_nonneg(data->g);
+}
+
+/* Given a lower and an upper bound on div i, do they always allow
+ * for an integer value of the given div?
+ * Determine this property by constructing an inequality
+ * such that the property is guaranteed when the inequality is nonnegative.
+ * The lower bound is inequality l, while the upper bound is inequality u.
+ * The constructed inequality is stored in data->v.
+ *
+ * Let the upper bound be
+ *
+ *	-n_u a + e_u >= 0
+ *
+ * and the lower bound
+ *
+ *	n_l a + e_l >= 0
+ *
+ * Let n_u = f_u g and n_l = f_l g, with g = gcd(n_u, n_l).
+ * We have
+ *
+ *	- f_u e_l <= f_u f_l g a <= f_l e_u
+ *
+ * Since all variables are integer valued, this is equivalent to
+ *
+ *	- f_u e_l - (f_u - 1) <= f_u f_l g a <= f_l e_u + (f_l - 1)
+ *
+ * If this interval is at least f_u f_l g, then it contains at least
+ * one integer value for a.
+ * That is, the test constraint is
+ *
+ *	f_l e_u + f_u e_l + f_l - 1 + f_u - 1 + 1 >= f_u f_l g
+ *
+ * or
+ *
+ *	f_l e_u + f_u e_l + f_l - 1 + f_u - 1 + 1 - f_u f_l g >= 0
+ *
+ * If the coefficients of f_l e_u + f_u e_l have a common divisor g',
+ * then the constraint can be scaled down by a factor g',
+ * with the constant term replaced by
+ * floor((f_l e_{u,0} + f_u e_{l,0} + f_l - 1 + f_u - 1 + 1 - f_u f_l g)/g').
+ * Note that the result of applying Fourier-Motzkin to this pair
+ * of constraints is
+ *
+ *	f_l e_u + f_u e_l >= 0
+ *
+ * If the constant term of the scaled down version of this constraint,
+ * i.e., floor((f_l e_{u,0} + f_u e_{l,0})/g') is equal to the constant
+ * term of the scaled down test constraint, then the test constraint
+ * is known to hold and no explicit evaluation is required.
+ * This is essentially the Omega test.
+ *
+ * If the test constraint consists of only a constant term, then
+ * it is sufficient to look at the sign of this constant term.
+ */
+static isl_bool int_between_bounds(__isl_keep isl_basic_map *bmap, int i,
+	int l, int u, struct test_ineq_data *data)
+{
+	unsigned offset, n_div;
+	offset = isl_basic_map_offset(bmap, isl_dim_div);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+
+	isl_int_gcd(data->g,
+		    bmap->ineq[l][offset + i], bmap->ineq[u][offset + i]);
+	isl_int_divexact(data->fl, bmap->ineq[l][offset + i], data->g);
+	isl_int_divexact(data->fu, bmap->ineq[u][offset + i], data->g);
+	isl_int_neg(data->fu, data->fu);
+	isl_seq_combine(data->v->el, data->fl, bmap->ineq[u],
+			data->fu, bmap->ineq[l], offset + n_div);
+	isl_int_mul(data->g, data->g, data->fl);
+	isl_int_mul(data->g, data->g, data->fu);
+	isl_int_sub(data->g, data->g, data->fl);
+	isl_int_sub(data->g, data->g, data->fu);
+	isl_int_add_ui(data->g, data->g, 1);
+	isl_int_sub(data->fl, data->v->el[0], data->g);
+
+	isl_seq_gcd(data->v->el + 1, offset - 1 + n_div, &data->g);
+	if (isl_int_is_zero(data->g))
+		return isl_int_is_nonneg(data->fl);
+	if (isl_int_is_one(data->g)) {
+		isl_int_set(data->v->el[0], data->fl);
+		return test_ineq_is_satisfied(bmap, data);
+	}
+	isl_int_fdiv_q(data->fl, data->fl, data->g);
+	isl_int_fdiv_q(data->v->el[0], data->v->el[0], data->g);
+	if (isl_int_eq(data->fl, data->v->el[0]))
+		return isl_bool_true;
+	isl_int_set(data->v->el[0], data->fl);
+	isl_seq_scale_down(data->v->el + 1, data->v->el + 1, data->g,
+			    offset - 1 + n_div);
+
+	return test_ineq_is_satisfied(bmap, data);
+}
+
+/* Remove more kinds of divs that are not strictly needed.
+ * In particular, if all pairs of lower and upper bounds on a div
+ * are such that they allow at least one integer value of the div,
+ * then we can eliminate the div using Fourier-Motzkin without
+ * introducing any spurious solutions.
+ *
+ * If at least one of the two constraints has a unit coefficient for the div,
+ * then the presence of such a value is guaranteed so there is no need to check.
+ * In particular, the value attained by the bound with unit coefficient
+ * can serve as this intermediate value.
+ */
+static __isl_give isl_basic_map *drop_more_redundant_divs(
+	__isl_take isl_basic_map *bmap, __isl_take int *pairs, int n)
+{
+	isl_ctx *ctx;
+	struct test_ineq_data data = { NULL, NULL };
+	unsigned off, n_div;
+	int remove = -1;
+
+	isl_int_init(data.g);
+	isl_int_init(data.fl);
+	isl_int_init(data.fu);
+
+	if (!bmap)
+		goto error;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	off = isl_basic_map_offset(bmap, isl_dim_div);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	data.v = isl_vec_alloc(ctx, off + n_div);
+	if (!data.v)
+		goto error;
+
+	while (n > 0) {
+		int i, l, u;
+		int best = -1;
+		isl_bool has_int;
+
+		for (i = 0; i < n_div; ++i) {
+			if (!pairs[i])
+				continue;
+			if (best >= 0 && pairs[best] <= pairs[i])
+				continue;
+			best = i;
+		}
+
+		i = best;
+		for (l = 0; l < bmap->n_ineq; ++l) {
+			if (!isl_int_is_pos(bmap->ineq[l][off + i]))
+				continue;
+			if (isl_int_is_one(bmap->ineq[l][off + i]))
+				continue;
+			for (u = 0; u < bmap->n_ineq; ++u) {
+				if (!isl_int_is_neg(bmap->ineq[u][off + i]))
+					continue;
+				if (isl_int_is_negone(bmap->ineq[u][off + i]))
+					continue;
+				has_int = int_between_bounds(bmap, i, l, u,
+								&data);
+				if (has_int < 0)
+					goto error;
+				if (data.tab && data.tab->empty)
+					break;
+				if (!has_int)
+					break;
+			}
+			if (u < bmap->n_ineq)
+				break;
+		}
+		if (data.tab && data.tab->empty) {
+			bmap = isl_basic_map_set_to_empty(bmap);
+			break;
+		}
+		if (l == bmap->n_ineq) {
+			remove = i;
+			break;
+		}
+		pairs[i] = 0;
+		--n;
+	}
+
+	test_ineq_data_clear(&data);
+
+	free(pairs);
+
+	if (remove < 0)
+		return bmap;
+
+	bmap = isl_basic_map_remove_dims(bmap, isl_dim_div, remove, 1);
+	return isl_basic_map_drop_redundant_divs(bmap);
+error:
+	free(pairs);
+	isl_basic_map_free(bmap);
+	test_ineq_data_clear(&data);
+	return NULL;
+}
+
+/* Given a pair of divs div1 and div2 such that, except for the lower bound l
+ * and the upper bound u, div1 always occurs together with div2 in the form
+ * (div1 + m div2), where m is the constant range on the variable div1
+ * allowed by l and u, replace the pair div1 and div2 by a single
+ * div that is equal to div1 + m div2.
+ *
+ * The new div will appear in the location that contains div2.
+ * We need to modify all constraints that contain
+ * div2 = (div - div1) / m
+ * The coefficient of div2 is known to be equal to 1 or -1.
+ * (If a constraint does not contain div2, it will also not contain div1.)
+ * If the constraint also contains div1, then we know they appear
+ * as f (div1 + m div2) and we can simply replace (div1 + m div2) by div,
+ * i.e., the coefficient of div is f.
+ *
+ * Otherwise, we first need to introduce div1 into the constraint.
+ * Let l be
+ *
+ *	div1 + f >=0
+ *
+ * and u
+ *
+ *	-div1 + f' >= 0
+ *
+ * A lower bound on div2
+ *
+ *	div2 + t >= 0
+ *
+ * can be replaced by
+ *
+ *	m div2 + div1 + m t + f >= 0
+ *
+ * An upper bound
+ *
+ *	-div2 + t >= 0
+ *
+ * can be replaced by
+ *
+ *	-(m div2 + div1) + m t + f' >= 0
+ *
+ * These constraint are those that we would obtain from eliminating
+ * div1 using Fourier-Motzkin.
+ *
+ * After all constraints have been modified, we drop the lower and upper
+ * bound and then drop div1.
+ * Since the new div is only placed in the same location that used
+ * to store div2, but otherwise has a different meaning, any possible
+ * explicit representation of the original div2 is removed.
+ */
+static __isl_give isl_basic_map *coalesce_divs(__isl_take isl_basic_map *bmap,
+	unsigned div1, unsigned div2, unsigned l, unsigned u)
+{
+	isl_ctx *ctx;
+	isl_int m;
+	unsigned dim, total;
+	int i;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+
+	dim = isl_space_dim(bmap->dim, isl_dim_all);
+	total = 1 + dim + bmap->n_div;
+
+	isl_int_init(m);
+	isl_int_add(m, bmap->ineq[l][0], bmap->ineq[u][0]);
+	isl_int_add_ui(m, m, 1);
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		if (i == l || i == u)
+			continue;
+		if (isl_int_is_zero(bmap->ineq[i][1 + dim + div2]))
+			continue;
+		if (isl_int_is_zero(bmap->ineq[i][1 + dim + div1])) {
+			if (isl_int_is_pos(bmap->ineq[i][1 + dim + div2]))
+				isl_seq_combine(bmap->ineq[i], m, bmap->ineq[i],
+						ctx->one, bmap->ineq[l], total);
+			else
+				isl_seq_combine(bmap->ineq[i], m, bmap->ineq[i],
+						ctx->one, bmap->ineq[u], total);
+		}
+		isl_int_set(bmap->ineq[i][1 + dim + div2],
+			    bmap->ineq[i][1 + dim + div1]);
+		isl_int_set_si(bmap->ineq[i][1 + dim + div1], 0);
+	}
+
+	isl_int_clear(m);
+	if (l > u) {
+		isl_basic_map_drop_inequality(bmap, l);
+		isl_basic_map_drop_inequality(bmap, u);
+	} else {
+		isl_basic_map_drop_inequality(bmap, u);
+		isl_basic_map_drop_inequality(bmap, l);
+	}
+	bmap = isl_basic_map_mark_div_unknown(bmap, div2);
+	bmap = isl_basic_map_drop_div(bmap, div1);
+	return bmap;
+}
+
+/* First check if we can coalesce any pair of divs and
+ * then continue with dropping more redundant divs.
+ *
+ * We loop over all pairs of lower and upper bounds on a div
+ * with coefficient 1 and -1, respectively, check if there
+ * is any other div "c" with which we can coalesce the div
+ * and if so, perform the coalescing.
+ */
+static __isl_give isl_basic_map *coalesce_or_drop_more_redundant_divs(
+	__isl_take isl_basic_map *bmap, int *pairs, int n)
+{
+	int i, l, u;
+	unsigned dim;
+
+	dim = isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (!pairs[i])
+			continue;
+		for (l = 0; l < bmap->n_ineq; ++l) {
+			if (!isl_int_is_one(bmap->ineq[l][1 + dim + i]))
+				continue;
+			for (u = 0; u < bmap->n_ineq; ++u) {
+				int c;
+
+				if (!isl_int_is_negone(bmap->ineq[u][1+dim+i]))
+					continue;
+				c = div_find_coalesce(bmap, pairs, i, l, u);
+				if (c < 0)
+					continue;
+				free(pairs);
+				bmap = coalesce_divs(bmap, i, c, l, u);
+				return isl_basic_map_drop_redundant_divs(bmap);
+			}
+		}
+	}
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) {
+		free(pairs);
+		return bmap;
+	}
+
+	return drop_more_redundant_divs(bmap, pairs, n);
+}
+
+/* Are the "n" coefficients starting at "first" of inequality constraints
+ * "i" and "j" of "bmap" equal to each other?
+ */
+static int is_parallel_part(__isl_keep isl_basic_map *bmap, int i, int j,
+	int first, int n)
+{
+	return isl_seq_eq(bmap->ineq[i] + first, bmap->ineq[j] + first, n);
+}
+
+/* Are the "n" coefficients starting at "first" of inequality constraints
+ * "i" and "j" of "bmap" opposite to each other?
+ */
+static int is_opposite_part(__isl_keep isl_basic_map *bmap, int i, int j,
+	int first, int n)
+{
+	return isl_seq_is_neg(bmap->ineq[i] + first, bmap->ineq[j] + first, n);
+}
+
+/* Are inequality constraints "i" and "j" of "bmap" opposite to each other,
+ * apart from the constant term?
+ */
+static isl_bool is_opposite(__isl_keep isl_basic_map *bmap, int i, int j)
+{
+	unsigned total;
+
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	return is_opposite_part(bmap, i, j, 1, total);
+}
+
+/* Are inequality constraints "i" and "j" of "bmap" equal to each other,
+ * apart from the constant term and the coefficient at position "pos"?
+ */
+static int is_parallel_except(__isl_keep isl_basic_map *bmap, int i, int j,
+	int pos)
+{
+	unsigned total;
+
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	return is_parallel_part(bmap, i, j, 1, pos - 1) &&
+		is_parallel_part(bmap, i, j, pos + 1, total - pos);
+}
+
+/* Are inequality constraints "i" and "j" of "bmap" opposite to each other,
+ * apart from the constant term and the coefficient at position "pos"?
+ */
+static int is_opposite_except(__isl_keep isl_basic_map *bmap, int i, int j,
+	int pos)
+{
+	unsigned total;
+
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	return is_opposite_part(bmap, i, j, 1, pos - 1) &&
+		is_opposite_part(bmap, i, j, pos + 1, total - pos);
+}
+
+/* Restart isl_basic_map_drop_redundant_divs after "bmap" has
+ * been modified, simplying it if "simplify" is set.
+ * Free the temporary data structure "pairs" that was associated
+ * to the old version of "bmap".
+ */
+static __isl_give isl_basic_map *drop_redundant_divs_again(
+	__isl_take isl_basic_map *bmap, __isl_take int *pairs, int simplify)
+{
+	if (simplify)
+		bmap = isl_basic_map_simplify(bmap);
+	free(pairs);
+	return isl_basic_map_drop_redundant_divs(bmap);
+}
+
+/* Is "div" the single unknown existentially quantified variable
+ * in inequality constraint "ineq" of "bmap"?
+ * "div" is known to have a non-zero coefficient in "ineq".
+ */
+static isl_bool single_unknown(__isl_keep isl_basic_map *bmap, int ineq,
+	int div)
+{
+	int i;
+	unsigned n_div, o_div;
+	isl_bool known;
+
+	known = isl_basic_map_div_is_known(bmap, div);
+	if (known < 0 || known)
+		return isl_bool_not(known);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	if (n_div == 1)
+		return isl_bool_true;
+	o_div = isl_basic_map_offset(bmap, isl_dim_div);
+	for (i = 0; i < n_div; ++i) {
+		isl_bool known;
+
+		if (i == div)
+			continue;
+		if (isl_int_is_zero(bmap->ineq[ineq][o_div + i]))
+			continue;
+		known = isl_basic_map_div_is_known(bmap, i);
+		if (known < 0 || !known)
+			return known;
+	}
+
+	return isl_bool_true;
+}
+
+/* Does integer division "div" have coefficient 1 in inequality constraint
+ * "ineq" of "map"?
+ */
+static isl_bool has_coef_one(__isl_keep isl_basic_map *bmap, int div, int ineq)
+{
+	unsigned o_div;
+
+	o_div = isl_basic_map_offset(bmap, isl_dim_div);
+	if (isl_int_is_one(bmap->ineq[ineq][o_div + div]))
+		return isl_bool_true;
+
+	return isl_bool_false;
+}
+
+/* Turn inequality constraint "ineq" of "bmap" into an equality and
+ * then try and drop redundant divs again,
+ * freeing the temporary data structure "pairs" that was associated
+ * to the old version of "bmap".
+ */
+static __isl_give isl_basic_map *set_eq_and_try_again(
+	__isl_take isl_basic_map *bmap, int ineq, __isl_take int *pairs)
+{
+	bmap = isl_basic_map_cow(bmap);
+	isl_basic_map_inequality_to_equality(bmap, ineq);
+	return drop_redundant_divs_again(bmap, pairs, 1);
+}
+
+/* Drop the integer division at position "div", along with the two
+ * inequality constraints "ineq1" and "ineq2" in which it appears
+ * from "bmap" and then try and drop redundant divs again,
+ * freeing the temporary data structure "pairs" that was associated
+ * to the old version of "bmap".
+ */
+static __isl_give isl_basic_map *drop_div_and_try_again(
+	__isl_take isl_basic_map *bmap, int div, int ineq1, int ineq2,
+	__isl_take int *pairs)
+{
+	if (ineq1 > ineq2) {
+		isl_basic_map_drop_inequality(bmap, ineq1);
+		isl_basic_map_drop_inequality(bmap, ineq2);
+	} else {
+		isl_basic_map_drop_inequality(bmap, ineq2);
+		isl_basic_map_drop_inequality(bmap, ineq1);
+	}
+	bmap = isl_basic_map_drop_div(bmap, div);
+	return drop_redundant_divs_again(bmap, pairs, 0);
+}
+
+/* Given two inequality constraints
+ *
+ *	f(x) + n d + c >= 0,		(ineq)
+ *
+ * with d the variable at position "pos", and
+ *
+ *	f(x) + c0 >= 0,			(lower)
+ *
+ * compute the maximal value of the lower bound ceil((-f(x) - c)/n)
+ * determined by the first constraint.
+ * That is, store
+ *
+ *	ceil((c0 - c)/n)
+ *
+ * in *l.
+ */
+static void lower_bound_from_parallel(__isl_keep isl_basic_map *bmap,
+	int ineq, int lower, int pos, isl_int *l)
+{
+	isl_int_neg(*l, bmap->ineq[ineq][0]);
+	isl_int_add(*l, *l, bmap->ineq[lower][0]);
+	isl_int_cdiv_q(*l, *l, bmap->ineq[ineq][pos]);
+}
+
+/* Given two inequality constraints
+ *
+ *	f(x) + n d + c >= 0,		(ineq)
+ *
+ * with d the variable at position "pos", and
+ *
+ *	-f(x) - c0 >= 0,		(upper)
+ *
+ * compute the minimal value of the lower bound ceil((-f(x) - c)/n)
+ * determined by the first constraint.
+ * That is, store
+ *
+ *	ceil((-c1 - c)/n)
+ *
+ * in *u.
+ */
+static void lower_bound_from_opposite(__isl_keep isl_basic_map *bmap,
+	int ineq, int upper, int pos, isl_int *u)
+{
+	isl_int_neg(*u, bmap->ineq[ineq][0]);
+	isl_int_sub(*u, *u, bmap->ineq[upper][0]);
+	isl_int_cdiv_q(*u, *u, bmap->ineq[ineq][pos]);
+}
+
+/* Given a lower bound constraint "ineq" on "div" in "bmap",
+ * does the corresponding lower bound have a fixed value in "bmap"?
+ *
+ * In particular, "ineq" is of the form
+ *
+ *	f(x) + n d + c >= 0
+ *
+ * with n > 0, c the constant term and
+ * d the existentially quantified variable "div".
+ * That is, the lower bound is
+ *
+ *	ceil((-f(x) - c)/n)
+ *
+ * Look for a pair of constraints
+ *
+ *	f(x) + c0 >= 0
+ *	-f(x) + c1 >= 0
+ *
+ * i.e., -c1 <= -f(x) <= c0, that fix ceil((-f(x) - c)/n) to a constant value.
+ * That is, check that
+ *
+ *	ceil((-c1 - c)/n) = ceil((c0 - c)/n)
+ *
+ * If so, return the index of inequality f(x) + c0 >= 0.
+ * Otherwise, return -1.
+ */
+static int lower_bound_is_cst(__isl_keep isl_basic_map *bmap, int div, int ineq)
+{
+	int i;
+	int lower = -1, upper = -1;
+	unsigned o_div;
+	isl_int l, u;
+	int equal;
+
+	o_div = isl_basic_map_offset(bmap, isl_dim_div);
+	for (i = 0; i < bmap->n_ineq && (lower < 0 || upper < 0); ++i) {
+		if (i == ineq)
+			continue;
+		if (!isl_int_is_zero(bmap->ineq[i][o_div + div]))
+			continue;
+		if (lower < 0 &&
+		    is_parallel_except(bmap, ineq, i, o_div + div)) {
+			lower = i;
+			continue;
+		}
+		if (upper < 0 &&
+		    is_opposite_except(bmap, ineq, i, o_div + div)) {
+			upper = i;
+		}
+	}
+
+	if (lower < 0 || upper < 0)
+		return -1;
+
+	isl_int_init(l);
+	isl_int_init(u);
+
+	lower_bound_from_parallel(bmap, ineq, lower, o_div + div, &l);
+	lower_bound_from_opposite(bmap, ineq, upper, o_div + div, &u);
+
+	equal = isl_int_eq(l, u);
+
+	isl_int_clear(l);
+	isl_int_clear(u);
+
+	return equal ? lower : -1;
+}
+
+/* Given a lower bound constraint "ineq" on the existentially quantified
+ * variable "div", such that the corresponding lower bound has
+ * a fixed value in "bmap", assign this fixed value to the variable and
+ * then try and drop redundant divs again,
+ * freeing the temporary data structure "pairs" that was associated
+ * to the old version of "bmap".
+ * "lower" determines the constant value for the lower bound.
+ *
+ * In particular, "ineq" is of the form
+ *
+ *	f(x) + n d + c >= 0,
+ *
+ * while "lower" is of the form
+ *
+ *	f(x) + c0 >= 0
+ *
+ * The lower bound is ceil((-f(x) - c)/n) and its constant value
+ * is ceil((c0 - c)/n).
+ */
+static __isl_give isl_basic_map *fix_cst_lower(__isl_take isl_basic_map *bmap,
+	int div, int ineq, int lower, int *pairs)
+{
+	isl_int c;
+	unsigned o_div;
+
+	isl_int_init(c);
+
+	o_div = isl_basic_map_offset(bmap, isl_dim_div);
+	lower_bound_from_parallel(bmap, ineq, lower, o_div + div, &c);
+	bmap = isl_basic_map_fix(bmap, isl_dim_div, div, c);
+	free(pairs);
+
+	isl_int_clear(c);
+
+	return isl_basic_map_drop_redundant_divs(bmap);
+}
+
+/* Remove divs that are not strictly needed based on the inequality
+ * constraints.
+ * In particular, if a div only occurs positively (or negatively)
+ * in constraints, then it can simply be dropped.
+ * Also, if a div occurs in only two constraints and if moreover
+ * those two constraints are opposite to each other, except for the constant
+ * term and if the sum of the constant terms is such that for any value
+ * of the other values, there is always at least one integer value of the
+ * div, i.e., if one plus this sum is greater than or equal to
+ * the (absolute value) of the coefficient of the div in the constraints,
+ * then we can also simply drop the div.
+ *
+ * If an existentially quantified variable does not have an explicit
+ * representation, appears in only a single lower bound that does not
+ * involve any other such existentially quantified variables and appears
+ * in this lower bound with coefficient 1,
+ * then fix the variable to the value of the lower bound.  That is,
+ * turn the inequality into an equality.
+ * If for any value of the other variables, there is any value
+ * for the existentially quantified variable satisfying the constraints,
+ * then this lower bound also satisfies the constraints.
+ * It is therefore safe to pick this lower bound.
+ *
+ * The same reasoning holds even if the coefficient is not one.
+ * However, fixing the variable to the value of the lower bound may
+ * in general introduce an extra integer division, in which case
+ * it may be better to pick another value.
+ * If this integer division has a known constant value, then plugging
+ * in this constant value removes the existentially quantified variable
+ * completely.  In particular, if the lower bound is of the form
+ * ceil((-f(x) - c)/n) and there are two constraints, f(x) + c0 >= 0 and
+ * -f(x) + c1 >= 0 such that ceil((-c1 - c)/n) = ceil((c0 - c)/n),
+ * then the existentially quantified variable can be assigned this
+ * shared value.
+ *
+ * We skip divs that appear in equalities or in the definition of other divs.
+ * Divs that appear in the definition of other divs usually occur in at least
+ * 4 constraints, but the constraints may have been simplified.
+ *
+ * If any divs are left after these simple checks then we move on
+ * to more complicated cases in drop_more_redundant_divs.
+ */
+static __isl_give isl_basic_map *isl_basic_map_drop_redundant_divs_ineq(
+	__isl_take isl_basic_map *bmap)
+{
+	int i, j;
+	unsigned off;
+	int *pairs = NULL;
+	int n = 0;
+
+	if (!bmap)
+		goto error;
+	if (bmap->n_div == 0)
+		return bmap;
+
+	off = isl_space_dim(bmap->dim, isl_dim_all);
+	pairs = isl_calloc_array(bmap->ctx, int, bmap->n_div);
+	if (!pairs)
+		goto error;
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		int pos, neg;
+		int last_pos, last_neg;
+		int redundant;
+		int defined;
+		isl_bool opp, set_div;
+
+		defined = !isl_int_is_zero(bmap->div[i][0]);
+		for (j = i; j < bmap->n_div; ++j)
+			if (!isl_int_is_zero(bmap->div[j][1 + 1 + off + i]))
+				break;
+		if (j < bmap->n_div)
+			continue;
+		for (j = 0; j < bmap->n_eq; ++j)
+			if (!isl_int_is_zero(bmap->eq[j][1 + off + i]))
+				break;
+		if (j < bmap->n_eq)
+			continue;
+		++n;
+		pos = neg = 0;
+		for (j = 0; j < bmap->n_ineq; ++j) {
+			if (isl_int_is_pos(bmap->ineq[j][1 + off + i])) {
+				last_pos = j;
+				++pos;
+			}
+			if (isl_int_is_neg(bmap->ineq[j][1 + off + i])) {
+				last_neg = j;
+				++neg;
+			}
+		}
+		pairs[i] = pos * neg;
+		if (pairs[i] == 0) {
+			for (j = bmap->n_ineq - 1; j >= 0; --j)
+				if (!isl_int_is_zero(bmap->ineq[j][1+off+i]))
+					isl_basic_map_drop_inequality(bmap, j);
+			bmap = isl_basic_map_drop_div(bmap, i);
+			return drop_redundant_divs_again(bmap, pairs, 0);
+		}
+		if (pairs[i] != 1)
+			opp = isl_bool_false;
+		else
+			opp = is_opposite(bmap, last_pos, last_neg);
+		if (opp < 0)
+			goto error;
+		if (!opp) {
+			int lower;
+			isl_bool single, one;
+
+			if (pos != 1)
+				continue;
+			single = single_unknown(bmap, last_pos, i);
+			if (single < 0)
+				goto error;
+			if (!single)
+				continue;
+			one = has_coef_one(bmap, i, last_pos);
+			if (one < 0)
+				goto error;
+			if (one)
+				return set_eq_and_try_again(bmap, last_pos,
+							    pairs);
+			lower = lower_bound_is_cst(bmap, i, last_pos);
+			if (lower >= 0)
+				return fix_cst_lower(bmap, i, last_pos, lower,
+						pairs);
+			continue;
+		}
+
+		isl_int_add(bmap->ineq[last_pos][0],
+			    bmap->ineq[last_pos][0], bmap->ineq[last_neg][0]);
+		isl_int_add_ui(bmap->ineq[last_pos][0],
+			       bmap->ineq[last_pos][0], 1);
+		redundant = isl_int_ge(bmap->ineq[last_pos][0],
+				bmap->ineq[last_pos][1+off+i]);
+		isl_int_sub_ui(bmap->ineq[last_pos][0],
+			       bmap->ineq[last_pos][0], 1);
+		isl_int_sub(bmap->ineq[last_pos][0],
+			    bmap->ineq[last_pos][0], bmap->ineq[last_neg][0]);
+		if (redundant)
+			return drop_div_and_try_again(bmap, i,
+						    last_pos, last_neg, pairs);
+		if (defined)
+			set_div = isl_bool_false;
+		else
+			set_div = ok_to_set_div_from_bound(bmap, i, last_pos);
+		if (set_div < 0)
+			return isl_basic_map_free(bmap);
+		if (set_div) {
+			bmap = set_div_from_lower_bound(bmap, i, last_pos);
+			return drop_redundant_divs_again(bmap, pairs, 1);
+		}
+		pairs[i] = 0;
+		--n;
+	}
+
+	if (n > 0)
+		return coalesce_or_drop_more_redundant_divs(bmap, pairs, n);
+
+	free(pairs);
+	return bmap;
+error:
+	free(pairs);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Consider the coefficients at "c" as a row vector and replace
+ * them with their product with "T".  "T" is assumed to be a square matrix.
+ */
+static isl_stat preimage(isl_int *c, __isl_keep isl_mat *T)
+{
+	int n;
+	isl_ctx *ctx;
+	isl_vec *v;
+
+	if (!T)
+		return isl_stat_error;
+	n = isl_mat_rows(T);
+	if (isl_seq_first_non_zero(c, n) == -1)
+		return isl_stat_ok;
+	ctx = isl_mat_get_ctx(T);
+	v = isl_vec_alloc(ctx, n);
+	if (!v)
+		return isl_stat_error;
+	isl_seq_swp_or_cpy(v->el, c, n);
+	v = isl_vec_mat_product(v, isl_mat_copy(T));
+	if (!v)
+		return isl_stat_error;
+	isl_seq_swp_or_cpy(c, v->el, n);
+	isl_vec_free(v);
+
+	return isl_stat_ok;
+}
+
+/* Plug in T for the variables in "bmap" starting at "pos".
+ * T is a linear unimodular matrix, i.e., without constant term.
+ */
+static __isl_give isl_basic_map *isl_basic_map_preimage_vars(
+	__isl_take isl_basic_map *bmap, unsigned pos, __isl_take isl_mat *T)
+{
+	int i;
+	unsigned n, total;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap || !T)
+		goto error;
+
+	n = isl_mat_cols(T);
+	if (n != isl_mat_rows(T))
+		isl_die(isl_mat_get_ctx(T), isl_error_invalid,
+			"expecting square matrix", goto error);
+
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	if (pos + n > total || pos + n < pos)
+		isl_die(isl_mat_get_ctx(T), isl_error_invalid,
+			"invalid range", goto error);
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		if (preimage(bmap->eq[i] + 1 + pos, T) < 0)
+			goto error;
+	for (i = 0; i < bmap->n_ineq; ++i)
+		if (preimage(bmap->ineq[i] + 1 + pos, T) < 0)
+			goto error;
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_basic_map_div_is_marked_unknown(bmap, i))
+			continue;
+		if (preimage(bmap->div[i] + 1 + 1 + pos, T) < 0)
+			goto error;
+	}
+
+	isl_mat_free(T);
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_mat_free(T);
+	return NULL;
+}
+
+/* Remove divs that are not strictly needed.
+ *
+ * First look for an equality constraint involving two or more
+ * existentially quantified variables without an explicit
+ * representation.  Replace the combination that appears
+ * in the equality constraint by a single existentially quantified
+ * variable such that the equality can be used to derive
+ * an explicit representation for the variable.
+ * If there are no more such equality constraints, then continue
+ * with isl_basic_map_drop_redundant_divs_ineq.
+ *
+ * In particular, if the equality constraint is of the form
+ *
+ *	f(x) + \sum_i c_i a_i = 0
+ *
+ * with a_i existentially quantified variable without explicit
+ * representation, then apply a transformation on the existentially
+ * quantified variables to turn the constraint into
+ *
+ *	f(x) + g a_1' = 0
+ *
+ * with g the gcd of the c_i.
+ * In order to easily identify which existentially quantified variables
+ * have a complete explicit representation, i.e., without being defined
+ * in terms of other existentially quantified variables without
+ * an explicit representation, the existentially quantified variables
+ * are first sorted.
+ *
+ * The variable transformation is computed by extending the row
+ * [c_1/g ... c_n/g] to a unimodular matrix, obtaining the transformation
+ *
+ *	[a_1']   [c_1/g ... c_n/g]   [ a_1 ]
+ *	[a_2']                       [ a_2 ]
+ *	 ...   =         U             ....
+ *	[a_n']            	     [ a_n ]
+ *
+ * with [c_1/g ... c_n/g] representing the first row of U.
+ * The inverse of U is then plugged into the original constraints.
+ * The call to isl_basic_map_simplify makes sure the explicit
+ * representation for a_1' is extracted from the equality constraint.
+ */
+__isl_give isl_basic_map *isl_basic_map_drop_redundant_divs(
+	__isl_take isl_basic_map *bmap)
+{
+	int first;
+	int i;
+	unsigned o_div, n_div;
+	int l;
+	isl_ctx *ctx;
+	isl_mat *T;
+
+	if (!bmap)
+		return NULL;
+	if (isl_basic_map_divs_known(bmap))
+		return isl_basic_map_drop_redundant_divs_ineq(bmap);
+	if (bmap->n_eq == 0)
+		return isl_basic_map_drop_redundant_divs_ineq(bmap);
+	bmap = isl_basic_map_sort_divs(bmap);
+	if (!bmap)
+		return NULL;
+
+	first = isl_basic_map_first_unknown_div(bmap);
+	if (first < 0)
+		return isl_basic_map_free(bmap);
+
+	o_div = isl_basic_map_offset(bmap, isl_dim_div);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+
+	for (i = 0; i < bmap->n_eq; ++i) {
+		l = isl_seq_first_non_zero(bmap->eq[i] + o_div + first,
+					    n_div - (first));
+		if (l < 0)
+			continue;
+		l += first;
+		if (isl_seq_first_non_zero(bmap->eq[i] + o_div + l + 1,
+					    n_div - (l + 1)) == -1)
+			continue;
+		break;
+	}
+	if (i >= bmap->n_eq)
+		return isl_basic_map_drop_redundant_divs_ineq(bmap);
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	T = isl_mat_alloc(ctx, n_div - l, n_div - l);
+	if (!T)
+		return isl_basic_map_free(bmap);
+	isl_seq_cpy(T->row[0], bmap->eq[i] + o_div + l, n_div - l);
+	T = isl_mat_normalize_row(T, 0);
+	T = isl_mat_unimodular_complete(T, 1);
+	T = isl_mat_right_inverse(T);
+
+	for (i = l; i < n_div; ++i)
+		bmap = isl_basic_map_mark_div_unknown(bmap, i);
+	bmap = isl_basic_map_preimage_vars(bmap, o_div - 1 + l, T);
+	bmap = isl_basic_map_simplify(bmap);
+
+	return isl_basic_map_drop_redundant_divs(bmap);
+}
+
+/* Does "bmap" satisfy any equality that involves more than 2 variables
+ * and/or has coefficients different from -1 and 1?
+ */
+static int has_multiple_var_equality(__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	unsigned total;
+
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+
+	for (i = 0; i < bmap->n_eq; ++i) {
+		int j, k;
+
+		j = isl_seq_first_non_zero(bmap->eq[i] + 1, total);
+		if (j < 0)
+			continue;
+		if (!isl_int_is_one(bmap->eq[i][1 + j]) &&
+		    !isl_int_is_negone(bmap->eq[i][1 + j]))
+			return 1;
+
+		j += 1;
+		k = isl_seq_first_non_zero(bmap->eq[i] + 1 + j, total - j);
+		if (k < 0)
+			continue;
+		j += k;
+		if (!isl_int_is_one(bmap->eq[i][1 + j]) &&
+		    !isl_int_is_negone(bmap->eq[i][1 + j]))
+			return 1;
+
+		j += 1;
+		k = isl_seq_first_non_zero(bmap->eq[i] + 1 + j, total - j);
+		if (k >= 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Remove any common factor g from the constraint coefficients in "v".
+ * The constant term is stored in the first position and is replaced
+ * by floor(c/g).  If any common factor is removed and if this results
+ * in a tightening of the constraint, then set *tightened.
+ */
+static __isl_give isl_vec *normalize_constraint(__isl_take isl_vec *v,
+	int *tightened)
+{
+	isl_ctx *ctx;
+
+	if (!v)
+		return NULL;
+	ctx = isl_vec_get_ctx(v);
+	isl_seq_gcd(v->el + 1, v->size - 1, &ctx->normalize_gcd);
+	if (isl_int_is_zero(ctx->normalize_gcd))
+		return v;
+	if (isl_int_is_one(ctx->normalize_gcd))
+		return v;
+	v = isl_vec_cow(v);
+	if (!v)
+		return NULL;
+	if (tightened && !isl_int_is_divisible_by(v->el[0], ctx->normalize_gcd))
+		*tightened = 1;
+	isl_int_fdiv_q(v->el[0], v->el[0], ctx->normalize_gcd);
+	isl_seq_scale_down(v->el + 1, v->el + 1, ctx->normalize_gcd,
+				v->size - 1);
+	return v;
+}
+
+/* If "bmap" is an integer set that satisfies any equality involving
+ * more than 2 variables and/or has coefficients different from -1 and 1,
+ * then use variable compression to reduce the coefficients by removing
+ * any (hidden) common factor.
+ * In particular, apply the variable compression to each constraint,
+ * factor out any common factor in the non-constant coefficients and
+ * then apply the inverse of the compression.
+ * At the end, we mark the basic map as having reduced constants.
+ * If this flag is still set on the next invocation of this function,
+ * then we skip the computation.
+ *
+ * Removing a common factor may result in a tightening of some of
+ * the constraints.  If this happens, then we may end up with two
+ * opposite inequalities that can be replaced by an equality.
+ * We therefore call isl_basic_map_detect_inequality_pairs,
+ * which checks for such pairs of inequalities as well as eliminate_divs_eq
+ * and isl_basic_map_gauss if such a pair was found.
+ *
+ * Note that this function may leave the result in an inconsistent state.
+ * In particular, the constraints may not be gaussed.
+ * Unfortunately, isl_map_coalesce actually depends on this inconsistent state
+ * for some of the test cases to pass successfully.
+ * Any potential modification of the representation is therefore only
+ * performed on a single copy of the basic map.
+ */
+__isl_give isl_basic_map *isl_basic_map_reduce_coefficients(
+	__isl_take isl_basic_map *bmap)
+{
+	unsigned total;
+	isl_ctx *ctx;
+	isl_vec *v;
+	isl_mat *eq, *T, *T2;
+	int i;
+	int tightened;
+
+	if (!bmap)
+		return NULL;
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS))
+		return bmap;
+	if (isl_basic_map_is_rational(bmap))
+		return bmap;
+	if (bmap->n_eq == 0)
+		return bmap;
+	if (!has_multiple_var_equality(bmap))
+		return bmap;
+
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	ctx = isl_basic_map_get_ctx(bmap);
+	v = isl_vec_alloc(ctx, 1 + total);
+	if (!v)
+		return isl_basic_map_free(bmap);
+
+	eq = isl_mat_sub_alloc6(ctx, bmap->eq, 0, bmap->n_eq, 0, 1 + total);
+	T = isl_mat_variable_compression(eq, &T2);
+	if (!T || !T2)
+		goto error;
+	if (T->n_col == 0) {
+		isl_mat_free(T);
+		isl_mat_free(T2);
+		isl_vec_free(v);
+		return isl_basic_map_set_to_empty(bmap);
+	}
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		goto error;
+
+	tightened = 0;
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		isl_seq_cpy(v->el, bmap->ineq[i], 1 + total);
+		v = isl_vec_mat_product(v, isl_mat_copy(T));
+		v = normalize_constraint(v, &tightened);
+		v = isl_vec_mat_product(v, isl_mat_copy(T2));
+		if (!v)
+			goto error;
+		isl_seq_cpy(bmap->ineq[i], v->el, 1 + total);
+	}
+
+	isl_mat_free(T);
+	isl_mat_free(T2);
+	isl_vec_free(v);
+
+	ISL_F_SET(bmap, ISL_BASIC_MAP_REDUCED_COEFFICIENTS);
+
+	if (tightened) {
+		int progress = 0;
+
+		bmap = isl_basic_map_detect_inequality_pairs(bmap, &progress);
+		if (progress) {
+			bmap = eliminate_divs_eq(bmap, &progress);
+			bmap = isl_basic_map_gauss(bmap, NULL);
+		}
+	}
+
+	return bmap;
+error:
+	isl_mat_free(T);
+	isl_mat_free(T2);
+	isl_vec_free(v);
+	return isl_basic_map_free(bmap);
+}
+
+/* Shift the integer division at position "div" of "bmap"
+ * by "shift" times the variable at position "pos".
+ * "pos" is as determined by isl_basic_map_offset, i.e., pos == 0
+ * corresponds to the constant term.
+ *
+ * That is, if the integer division has the form
+ *
+ *	floor(f(x)/d)
+ *
+ * then replace it by
+ *
+ *	floor((f(x) + shift * d * x_pos)/d) - shift * x_pos
+ */
+__isl_give isl_basic_map *isl_basic_map_shift_div(
+	__isl_take isl_basic_map *bmap, int div, int pos, isl_int shift)
+{
+	int i;
+	unsigned total;
+
+	if (isl_int_is_zero(shift))
+		return bmap;
+	if (!bmap)
+		return NULL;
+
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	total -= isl_basic_map_dim(bmap, isl_dim_div);
+
+	isl_int_addmul(bmap->div[div][1 + pos], shift, bmap->div[div][0]);
+
+	for (i = 0; i < bmap->n_eq; ++i) {
+		if (isl_int_is_zero(bmap->eq[i][1 + total + div]))
+			continue;
+		isl_int_submul(bmap->eq[i][pos],
+				shift, bmap->eq[i][1 + total + div]);
+	}
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		if (isl_int_is_zero(bmap->ineq[i][1 + total + div]))
+			continue;
+		isl_int_submul(bmap->ineq[i][pos],
+				shift, bmap->ineq[i][1 + total + div]);
+	}
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (isl_int_is_zero(bmap->div[i][1 + 1 + total + div]))
+			continue;
+		isl_int_submul(bmap->div[i][1 + pos],
+				shift, bmap->div[i][1 + 1 + total + div]);
+	}
+
+	return bmap;
+}
diff --git a/final/lib/External/isl/isl_map_subtract.c b/final/lib/External/isl/isl_map_subtract.c
new file mode 100644
index 0000000..df16ea9
--- /dev/null
+++ b/final/lib/External/isl/isl_map_subtract.c
@@ -0,0 +1,943 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_map_private.h>
+#include <isl_seq.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include "isl_tab.h"
+#include <isl_point_private.h>
+#include <isl_vec_private.h>
+
+#include <set_to_map.c>
+#include <set_from_map.c>
+
+/* Expand the constraint "c" into "v".  The initial "dim" dimensions
+ * are the same, but "v" may have more divs than "c" and the divs of "c"
+ * may appear in different positions in "v".
+ * The number of divs in "c" is given by "n_div" and the mapping
+ * of divs in "c" to divs in "v" is given by "div_map".
+ *
+ * Although it shouldn't happen in practice, it is theoretically
+ * possible that two or more divs in "c" are mapped to the same div in "v".
+ * These divs are then necessarily the same, so we simply add their
+ * coefficients.
+ */
+static void expand_constraint(isl_vec *v, unsigned dim,
+	isl_int *c, int *div_map, unsigned n_div)
+{
+	int i;
+
+	isl_seq_cpy(v->el, c, 1 + dim);
+	isl_seq_clr(v->el + 1 + dim, v->size - (1 + dim));
+
+	for (i = 0; i < n_div; ++i) {
+		int pos = 1 + dim + div_map[i];
+		isl_int_add(v->el[pos], v->el[pos], c[1 + dim + i]);
+	}
+}
+
+/* Add all constraints of bmap to tab.  The equalities of bmap
+ * are added as a pair of inequalities.
+ */
+static isl_stat tab_add_constraints(struct isl_tab *tab,
+	__isl_keep isl_basic_map *bmap, int *div_map)
+{
+	int i;
+	unsigned dim;
+	unsigned tab_total;
+	unsigned bmap_total;
+	isl_vec *v;
+
+	if (!tab || !bmap)
+		return isl_stat_error;
+
+	tab_total = isl_basic_map_total_dim(tab->bmap);
+	bmap_total = isl_basic_map_total_dim(bmap);
+	dim = isl_space_dim(tab->bmap->dim, isl_dim_all);
+
+	if (isl_tab_extend_cons(tab, 2 * bmap->n_eq + bmap->n_ineq) < 0)
+		return isl_stat_error;
+
+	v = isl_vec_alloc(bmap->ctx, 1 + tab_total);
+	if (!v)
+		return isl_stat_error;
+
+	for (i = 0; i < bmap->n_eq; ++i) {
+		expand_constraint(v, dim, bmap->eq[i], div_map, bmap->n_div);
+		if (isl_tab_add_ineq(tab, v->el) < 0)
+			goto error;
+		isl_seq_neg(bmap->eq[i], bmap->eq[i], 1 + bmap_total);
+		expand_constraint(v, dim, bmap->eq[i], div_map, bmap->n_div);
+		if (isl_tab_add_ineq(tab, v->el) < 0)
+			goto error;
+		isl_seq_neg(bmap->eq[i], bmap->eq[i], 1 + bmap_total);
+		if (tab->empty)
+			break;
+	}
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		expand_constraint(v, dim, bmap->ineq[i], div_map, bmap->n_div);
+		if (isl_tab_add_ineq(tab, v->el) < 0)
+			goto error;
+		if (tab->empty)
+			break;
+	}
+
+	isl_vec_free(v);
+	return isl_stat_ok;
+error:
+	isl_vec_free(v);
+	return isl_stat_error;
+}
+
+/* Add a specific constraint of bmap (or its opposite) to tab.
+ * The position of the constraint is specified by "c", where
+ * the equalities of bmap are counted twice, once for the inequality
+ * that is equal to the equality, and once for its negation.
+ *
+ * Each of these constraints has been added to "tab" before by
+ * tab_add_constraints (and later removed again), so there should
+ * already be a row available for the constraint.
+ */
+static isl_stat tab_add_constraint(struct isl_tab *tab,
+	__isl_keep isl_basic_map *bmap, int *div_map, int c, int oppose)
+{
+	unsigned dim;
+	unsigned tab_total;
+	unsigned bmap_total;
+	isl_vec *v;
+	isl_stat r;
+
+	if (!tab || !bmap)
+		return isl_stat_error;
+
+	tab_total = isl_basic_map_total_dim(tab->bmap);
+	bmap_total = isl_basic_map_total_dim(bmap);
+	dim = isl_space_dim(tab->bmap->dim, isl_dim_all);
+
+	v = isl_vec_alloc(bmap->ctx, 1 + tab_total);
+	if (!v)
+		return isl_stat_error;
+
+	if (c < 2 * bmap->n_eq) {
+		if ((c % 2) != oppose)
+			isl_seq_neg(bmap->eq[c/2], bmap->eq[c/2],
+					1 + bmap_total);
+		if (oppose)
+			isl_int_sub_ui(bmap->eq[c/2][0], bmap->eq[c/2][0], 1);
+		expand_constraint(v, dim, bmap->eq[c/2], div_map, bmap->n_div);
+		r = isl_tab_add_ineq(tab, v->el);
+		if (oppose)
+			isl_int_add_ui(bmap->eq[c/2][0], bmap->eq[c/2][0], 1);
+		if ((c % 2) != oppose)
+			isl_seq_neg(bmap->eq[c/2], bmap->eq[c/2],
+					1 + bmap_total);
+	} else {
+		c -= 2 * bmap->n_eq;
+		if (oppose) {
+			isl_seq_neg(bmap->ineq[c], bmap->ineq[c],
+					1 + bmap_total);
+			isl_int_sub_ui(bmap->ineq[c][0], bmap->ineq[c][0], 1);
+		}
+		expand_constraint(v, dim, bmap->ineq[c], div_map, bmap->n_div);
+		r = isl_tab_add_ineq(tab, v->el);
+		if (oppose) {
+			isl_int_add_ui(bmap->ineq[c][0], bmap->ineq[c][0], 1);
+			isl_seq_neg(bmap->ineq[c], bmap->ineq[c],
+					1 + bmap_total);
+		}
+	}
+
+	isl_vec_free(v);
+	return r;
+}
+
+static isl_stat tab_add_divs(struct isl_tab *tab,
+	__isl_keep isl_basic_map *bmap, int **div_map)
+{
+	int i, j;
+	struct isl_vec *vec;
+	unsigned total;
+	unsigned dim;
+
+	if (!bmap)
+		return isl_stat_error;
+	if (!bmap->n_div)
+		return isl_stat_ok;
+
+	if (!*div_map)
+		*div_map = isl_alloc_array(bmap->ctx, int, bmap->n_div);
+	if (!*div_map)
+		return isl_stat_error;
+
+	total = isl_basic_map_total_dim(tab->bmap);
+	dim = total - tab->bmap->n_div;
+	vec = isl_vec_alloc(bmap->ctx, 2 + total + bmap->n_div);
+	if (!vec)
+		return isl_stat_error;
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		isl_seq_cpy(vec->el, bmap->div[i], 2 + dim);
+		isl_seq_clr(vec->el + 2 + dim, tab->bmap->n_div);
+		for (j = 0; j < i; ++j)
+			isl_int_set(vec->el[2 + dim + (*div_map)[j]],
+					bmap->div[i][2 + dim + j]);
+		for (j = 0; j < tab->bmap->n_div; ++j)
+			if (isl_seq_eq(tab->bmap->div[j],
+					vec->el, 2 + dim + tab->bmap->n_div))
+				break;
+		(*div_map)[i] = j;
+		if (j == tab->bmap->n_div) {
+			vec->size = 2 + dim + tab->bmap->n_div;
+			if (isl_tab_add_div(tab, vec) < 0)
+				goto error;
+		}
+	}
+
+	isl_vec_free(vec);
+
+	return isl_stat_ok;
+error:
+	isl_vec_free(vec);
+
+	return isl_stat_error;
+}
+
+/* Freeze all constraints of tableau tab.
+ */
+static int tab_freeze_constraints(struct isl_tab *tab)
+{
+	int i;
+
+	for (i = 0; i < tab->n_con; ++i)
+		if (isl_tab_freeze_constraint(tab, i) < 0)
+			return -1;
+
+	return 0;
+}
+
+/* Check for redundant constraints starting at offset.
+ * Put the indices of the redundant constraints in index
+ * and return the number of redundant constraints.
+ */
+static int n_non_redundant(isl_ctx *ctx, struct isl_tab *tab,
+	int offset, int **index)
+{
+	int i, n;
+	int n_test = tab->n_con - offset;
+
+	if (isl_tab_detect_redundant(tab) < 0)
+		return -1;
+
+	if (n_test == 0)
+		return 0;
+	if (!*index)
+		*index = isl_alloc_array(ctx, int, n_test);
+	if (!*index)
+		return -1;
+
+	for (n = 0, i = 0; i < n_test; ++i) {
+		int r;
+		r = isl_tab_is_redundant(tab, offset + i);
+		if (r < 0)
+			return -1;
+		if (r)
+			continue;
+		(*index)[n++] = i;
+	}
+
+	return n;
+}
+
+/* basic_map_collect_diff calls add on each of the pieces of
+ * the set difference between bmap and map until the add method
+ * return a negative value.
+ */
+struct isl_diff_collector {
+	isl_stat (*add)(struct isl_diff_collector *dc,
+		    __isl_take isl_basic_map *bmap);
+};
+
+/* Compute the set difference between bmap and map and call
+ * dc->add on each of the piece until this function returns
+ * a negative value.
+ * Return 0 on success and -1 on error.  dc->add returning
+ * a negative value is treated as an error, but the calling
+ * function can interpret the results based on the state of dc.
+ *
+ * Assumes that map has known divs.
+ *
+ * The difference is computed by a backtracking algorithm.
+ * Each level corresponds to a basic map in "map".
+ * When a node in entered for the first time, we check
+ * if the corresonding basic map intersects the current piece
+ * of "bmap".  If not, we move to the next level.
+ * Otherwise, we split the current piece into as many
+ * pieces as there are non-redundant constraints of the current
+ * basic map in the intersection.  Each of these pieces is
+ * handled by a child of the current node.
+ * In particular, if there are n non-redundant constraints,
+ * then for each 0 <= i < n, a piece is cut off by adding
+ * constraints 0 <= j < i and adding the opposite of constraint i.
+ * If there are no non-redundant constraints, meaning that the current
+ * piece is a subset of the current basic map, then we simply backtrack.
+ *
+ * In the leaves, we check if the remaining piece has any integer points
+ * and if so, pass it along to dc->add.  As a special case, if nothing
+ * has been removed when we end up in a leaf, we simply pass along
+ * the original basic map.
+ */
+static isl_stat basic_map_collect_diff(__isl_take isl_basic_map *bmap,
+	__isl_take isl_map *map, struct isl_diff_collector *dc)
+{
+	int i;
+	int modified;
+	int level;
+	int init;
+	isl_bool empty;
+	isl_ctx *ctx;
+	struct isl_tab *tab = NULL;
+	struct isl_tab_undo **snap = NULL;
+	int *k = NULL;
+	int *n = NULL;
+	int **index = NULL;
+	int **div_map = NULL;
+
+	empty = isl_basic_map_is_empty(bmap);
+	if (empty) {
+		isl_basic_map_free(bmap);
+		isl_map_free(map);
+		return empty < 0 ? isl_stat_error : isl_stat_ok;
+	}
+
+	bmap = isl_basic_map_cow(bmap);
+	map = isl_map_cow(map);
+
+	if (!bmap || !map)
+		goto error;
+
+	ctx = map->ctx;
+	snap = isl_alloc_array(map->ctx, struct isl_tab_undo *, map->n);
+	k = isl_alloc_array(map->ctx, int, map->n);
+	n = isl_alloc_array(map->ctx, int, map->n);
+	index = isl_calloc_array(map->ctx, int *, map->n);
+	div_map = isl_calloc_array(map->ctx, int *, map->n);
+	if (!snap || !k || !n || !index || !div_map)
+		goto error;
+
+	bmap = isl_basic_map_order_divs(bmap);
+	map = isl_map_order_divs(map);
+
+	tab = isl_tab_from_basic_map(bmap, 1);
+	if (!tab)
+		goto error;
+
+	modified = 0;
+	level = 0;
+	init = 1;
+
+	while (level >= 0) {
+		if (level >= map->n) {
+			int empty;
+			struct isl_basic_map *bm;
+			if (!modified) {
+				if (dc->add(dc, isl_basic_map_copy(bmap)) < 0)
+					goto error;
+				break;
+			}
+			bm = isl_basic_map_copy(tab->bmap);
+			bm = isl_basic_map_cow(bm);
+			bm = isl_basic_map_update_from_tab(bm, tab);
+			bm = isl_basic_map_simplify(bm);
+			bm = isl_basic_map_finalize(bm);
+			empty = isl_basic_map_is_empty(bm);
+			if (empty)
+				isl_basic_map_free(bm);
+			else if (dc->add(dc, bm) < 0)
+				goto error;
+			if (empty < 0)
+				goto error;
+			level--;
+			init = 0;
+			continue;
+		}
+		if (init) {
+			int offset;
+			struct isl_tab_undo *snap2;
+			snap2 = isl_tab_snap(tab);
+			if (tab_add_divs(tab, map->p[level],
+					 &div_map[level]) < 0)
+				goto error;
+			offset = tab->n_con;
+			snap[level] = isl_tab_snap(tab);
+			if (tab_freeze_constraints(tab) < 0)
+				goto error;
+			if (tab_add_constraints(tab, map->p[level],
+						div_map[level]) < 0)
+				goto error;
+			k[level] = 0;
+			n[level] = 0;
+			if (tab->empty) {
+				if (isl_tab_rollback(tab, snap2) < 0)
+					goto error;
+				level++;
+				continue;
+			}
+			modified = 1;
+			n[level] = n_non_redundant(ctx, tab, offset,
+						    &index[level]);
+			if (n[level] < 0)
+				goto error;
+			if (n[level] == 0) {
+				level--;
+				init = 0;
+				continue;
+			}
+			if (isl_tab_rollback(tab, snap[level]) < 0)
+				goto error;
+			if (tab_add_constraint(tab, map->p[level],
+					div_map[level], index[level][0], 1) < 0)
+				goto error;
+			level++;
+			continue;
+		} else {
+			if (k[level] + 1 >= n[level]) {
+				level--;
+				continue;
+			}
+			if (isl_tab_rollback(tab, snap[level]) < 0)
+				goto error;
+			if (tab_add_constraint(tab, map->p[level],
+						div_map[level],
+						index[level][k[level]], 0) < 0)
+				goto error;
+			snap[level] = isl_tab_snap(tab);
+			k[level]++;
+			if (tab_add_constraint(tab, map->p[level],
+						div_map[level],
+						index[level][k[level]], 1) < 0)
+				goto error;
+			level++;
+			init = 1;
+			continue;
+		}
+	}
+
+	isl_tab_free(tab);
+	free(snap);
+	free(n);
+	free(k);
+	for (i = 0; index && i < map->n; ++i)
+		free(index[i]);
+	free(index);
+	for (i = 0; div_map && i < map->n; ++i)
+		free(div_map[i]);
+	free(div_map);
+
+	isl_basic_map_free(bmap);
+	isl_map_free(map);
+
+	return isl_stat_ok;
+error:
+	isl_tab_free(tab);
+	free(snap);
+	free(n);
+	free(k);
+	for (i = 0; index && i < map->n; ++i)
+		free(index[i]);
+	free(index);
+	for (i = 0; div_map && i < map->n; ++i)
+		free(div_map[i]);
+	free(div_map);
+	isl_basic_map_free(bmap);
+	isl_map_free(map);
+	return isl_stat_error;
+}
+
+/* A diff collector that actually collects all parts of the
+ * set difference in the field diff.
+ */
+struct isl_subtract_diff_collector {
+	struct isl_diff_collector dc;
+	struct isl_map *diff;
+};
+
+/* isl_subtract_diff_collector callback.
+ */
+static isl_stat basic_map_subtract_add(struct isl_diff_collector *dc,
+			    __isl_take isl_basic_map *bmap)
+{
+	struct isl_subtract_diff_collector *sdc;
+	sdc = (struct isl_subtract_diff_collector *)dc;
+
+	sdc->diff = isl_map_union_disjoint(sdc->diff,
+			isl_map_from_basic_map(bmap));
+
+	return sdc->diff ? isl_stat_ok : isl_stat_error;
+}
+
+/* Return the set difference between bmap and map.
+ */
+static __isl_give isl_map *basic_map_subtract(__isl_take isl_basic_map *bmap,
+	__isl_take isl_map *map)
+{
+	struct isl_subtract_diff_collector sdc;
+	sdc.dc.add = &basic_map_subtract_add;
+	sdc.diff = isl_map_empty(isl_basic_map_get_space(bmap));
+	if (basic_map_collect_diff(bmap, map, &sdc.dc) < 0) {
+		isl_map_free(sdc.diff);
+		sdc.diff = NULL;
+	}
+	return sdc.diff;
+}
+
+/* Return an empty map living in the same space as "map1" and "map2".
+ */
+static __isl_give isl_map *replace_pair_by_empty( __isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	isl_space *space;
+
+	space = isl_map_get_space(map1);
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return isl_map_empty(space);
+}
+
+/* Return the set difference between map1 and map2.
+ * (U_i A_i) \ (U_j B_j) is computed as U_i (A_i \ (U_j B_j))
+ *
+ * If "map1" and "map2" are obviously equal to each other,
+ * then return an empty map in the same space.
+ *
+ * If "map1" and "map2" are disjoint, then simply return "map1".
+ */
+static __isl_give isl_map *map_subtract( __isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	int i;
+	int equal, disjoint;
+	struct isl_map *diff;
+
+	if (!map1 || !map2)
+		goto error;
+
+	isl_assert(map1->ctx, isl_space_is_equal(map1->dim, map2->dim), goto error);
+
+	equal = isl_map_plain_is_equal(map1, map2);
+	if (equal < 0)
+		goto error;
+	if (equal)
+		return replace_pair_by_empty(map1, map2);
+
+	disjoint = isl_map_is_disjoint(map1, map2);
+	if (disjoint < 0)
+		goto error;
+	if (disjoint) {
+		isl_map_free(map2);
+		return map1;
+	}
+
+	map1 = isl_map_compute_divs(map1);
+	map2 = isl_map_compute_divs(map2);
+	if (!map1 || !map2)
+		goto error;
+
+	map1 = isl_map_remove_empty_parts(map1);
+	map2 = isl_map_remove_empty_parts(map2);
+
+	diff = isl_map_empty(isl_map_get_space(map1));
+	for (i = 0; i < map1->n; ++i) {
+		struct isl_map *d;
+		d = basic_map_subtract(isl_basic_map_copy(map1->p[i]),
+				       isl_map_copy(map2));
+		if (ISL_F_ISSET(map1, ISL_MAP_DISJOINT))
+			diff = isl_map_union_disjoint(diff, d);
+		else
+			diff = isl_map_union(diff, d);
+	}
+
+	isl_map_free(map1);
+	isl_map_free(map2);
+
+	return diff;
+error:
+	isl_map_free(map1);
+	isl_map_free(map2);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_subtract( __isl_take isl_map *map1,
+	__isl_take isl_map *map2)
+{
+	return isl_map_align_params_map_map_and(map1, map2, &map_subtract);
+}
+
+struct isl_set *isl_set_subtract(struct isl_set *set1, struct isl_set *set2)
+{
+	return set_from_map(isl_map_subtract(set_to_map(set1),
+					    set_to_map(set2)));
+}
+
+/* Remove the elements of "dom" from the domain of "map".
+ */
+static __isl_give isl_map *map_subtract_domain(__isl_take isl_map *map,
+	__isl_take isl_set *dom)
+{
+	isl_bool ok;
+	isl_map *ext_dom;
+
+	ok = isl_map_compatible_domain(map, dom);
+	if (ok < 0)
+		goto error;
+	if (!ok)
+		isl_die(isl_set_get_ctx(dom), isl_error_invalid,
+			"incompatible spaces", goto error);
+	
+	ext_dom = isl_map_universe(isl_map_get_space(map));
+	ext_dom = isl_map_intersect_domain(ext_dom, dom);
+	return isl_map_subtract(map, ext_dom);
+error:
+	isl_map_free(map);
+	isl_set_free(dom);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_subtract_domain(__isl_take isl_map *map,
+	__isl_take isl_set *dom)
+{
+	return isl_map_align_params_map_map_and(map, dom, &map_subtract_domain);
+}
+
+/* Remove the elements of "dom" from the range of "map".
+ */
+static __isl_give isl_map *map_subtract_range(__isl_take isl_map *map,
+	__isl_take isl_set *dom)
+{
+	isl_bool ok;
+	isl_map *ext_dom;
+
+	ok = isl_map_compatible_range(map, dom);
+	if (ok < 0)
+		goto error;
+	if (!ok)
+		isl_die(isl_set_get_ctx(dom), isl_error_invalid,
+			"incompatible spaces", goto error);
+	
+	ext_dom = isl_map_universe(isl_map_get_space(map));
+	ext_dom = isl_map_intersect_range(ext_dom, dom);
+	return isl_map_subtract(map, ext_dom);
+error:
+	isl_map_free(map);
+	isl_set_free(dom);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_subtract_range(__isl_take isl_map *map,
+	__isl_take isl_set *dom)
+{
+	return isl_map_align_params_map_map_and(map, dom, &map_subtract_range);
+}
+
+/* A diff collector that aborts as soon as its add function is called,
+ * setting empty to 0.
+ */
+struct isl_is_empty_diff_collector {
+	struct isl_diff_collector dc;
+	isl_bool empty;
+};
+
+/* isl_is_empty_diff_collector callback.
+ */
+static isl_stat basic_map_is_empty_add(struct isl_diff_collector *dc,
+			    __isl_take isl_basic_map *bmap)
+{
+	struct isl_is_empty_diff_collector *edc;
+	edc = (struct isl_is_empty_diff_collector *)dc;
+
+	edc->empty = 0;
+
+	isl_basic_map_free(bmap);
+	return isl_stat_error;
+}
+
+/* Check if bmap \ map is empty by computing this set difference
+ * and breaking off as soon as the difference is known to be non-empty.
+ */
+static isl_bool basic_map_diff_is_empty(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_map *map)
+{
+	isl_bool empty;
+	isl_stat r;
+	struct isl_is_empty_diff_collector edc;
+
+	empty = isl_basic_map_plain_is_empty(bmap);
+	if (empty)
+		return empty;
+
+	edc.dc.add = &basic_map_is_empty_add;
+	edc.empty = isl_bool_true;
+	r = basic_map_collect_diff(isl_basic_map_copy(bmap),
+				   isl_map_copy(map), &edc.dc);
+	if (!edc.empty)
+		return isl_bool_false;
+
+	return r < 0 ? isl_bool_error : isl_bool_true;
+}
+
+/* Check if map1 \ map2 is empty by checking if the set difference is empty
+ * for each of the basic maps in map1.
+ */
+static isl_bool map_diff_is_empty(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2)
+{
+	int i;
+	isl_bool is_empty = isl_bool_true;
+
+	if (!map1 || !map2)
+		return isl_bool_error;
+	
+	for (i = 0; i < map1->n; ++i) {
+		is_empty = basic_map_diff_is_empty(map1->p[i], map2);
+		if (is_empty < 0 || !is_empty)
+			 break;
+	}
+
+	return is_empty;
+}
+
+/* Return true if "bmap" contains a single element.
+ */
+isl_bool isl_basic_map_plain_is_singleton(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return isl_bool_error;
+	if (bmap->n_div)
+		return isl_bool_false;
+	if (bmap->n_ineq)
+		return isl_bool_false;
+	return bmap->n_eq == isl_basic_map_total_dim(bmap);
+}
+
+/* Return true if "map" contains a single element.
+ */
+isl_bool isl_map_plain_is_singleton(__isl_keep isl_map *map)
+{
+	if (!map)
+		return isl_bool_error;
+	if (map->n != 1)
+		return isl_bool_false;
+
+	return isl_basic_map_plain_is_singleton(map->p[0]);
+}
+
+/* Given a singleton basic map, extract the single element
+ * as an isl_point.
+ */
+static __isl_give isl_point *singleton_extract_point(
+	__isl_keep isl_basic_map *bmap)
+{
+	int j;
+	unsigned dim;
+	struct isl_vec *point;
+	isl_int m;
+
+	if (!bmap)
+		return NULL;
+
+	dim = isl_basic_map_total_dim(bmap);
+	isl_assert(bmap->ctx, bmap->n_eq == dim, return NULL);
+	point = isl_vec_alloc(bmap->ctx, 1 + dim);
+	if (!point)
+		return NULL;
+
+	isl_int_init(m);
+
+	isl_int_set_si(point->el[0], 1);
+	for (j = 0; j < bmap->n_eq; ++j) {
+		int i = dim - 1 - j;
+		isl_assert(bmap->ctx,
+		    isl_seq_first_non_zero(bmap->eq[j] + 1, i) == -1,
+		    goto error);
+		isl_assert(bmap->ctx,
+		    isl_int_is_one(bmap->eq[j][1 + i]) ||
+		    isl_int_is_negone(bmap->eq[j][1 + i]),
+		    goto error);
+		isl_assert(bmap->ctx,
+		    isl_seq_first_non_zero(bmap->eq[j]+1+i+1, dim-i-1) == -1,
+		    goto error);
+
+		isl_int_gcd(m, point->el[0], bmap->eq[j][1 + i]);
+		isl_int_divexact(m, bmap->eq[j][1 + i], m);
+		isl_int_abs(m, m);
+		isl_seq_scale(point->el, point->el, m, 1 + i);
+		isl_int_divexact(m, point->el[0], bmap->eq[j][1 + i]);
+		isl_int_neg(m, m);
+		isl_int_mul(point->el[1 + i], m, bmap->eq[j][0]);
+	}
+
+	isl_int_clear(m);
+	return isl_point_alloc(isl_basic_map_get_space(bmap), point);
+error:
+	isl_int_clear(m);
+	isl_vec_free(point);
+	return NULL;
+}
+
+/* Return isl_bool_true if the singleton map "map1" is a subset of "map2",
+ * i.e., if the single element of "map1" is also an element of "map2".
+ * Assumes "map2" has known divs.
+ */
+static isl_bool map_is_singleton_subset(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2)
+{
+	int i;
+	isl_bool is_subset = isl_bool_false;
+	struct isl_point *point;
+
+	if (!map1 || !map2)
+		return isl_bool_error;
+	if (map1->n != 1)
+		isl_die(isl_map_get_ctx(map1), isl_error_invalid,
+			"expecting single-disjunct input",
+			return isl_bool_error);
+
+	point = singleton_extract_point(map1->p[0]);
+	if (!point)
+		return isl_bool_error;
+
+	for (i = 0; i < map2->n; ++i) {
+		is_subset = isl_basic_map_contains_point(map2->p[i], point);
+		if (is_subset)
+			break;
+	}
+
+	isl_point_free(point);
+	return is_subset;
+}
+
+static isl_bool map_is_subset(__isl_keep isl_map *map1,
+	__isl_keep isl_map *map2)
+{
+	isl_bool is_subset = isl_bool_false;
+	isl_bool empty, single;
+	isl_bool rat1, rat2;
+
+	if (!map1 || !map2)
+		return isl_bool_error;
+
+	if (!isl_map_has_equal_space(map1, map2))
+		return isl_bool_false;
+
+	empty = isl_map_is_empty(map1);
+	if (empty < 0)
+		return isl_bool_error;
+	if (empty)
+		return isl_bool_true;
+
+	empty = isl_map_is_empty(map2);
+	if (empty < 0)
+		return isl_bool_error;
+	if (empty)
+		return isl_bool_false;
+
+	rat1 = isl_map_has_rational(map1);
+	rat2 = isl_map_has_rational(map2);
+	if (rat1 < 0 || rat2 < 0)
+		return isl_bool_error;
+	if (rat1 && !rat2)
+		return isl_bool_false;
+
+	if (isl_map_plain_is_universe(map2))
+		return isl_bool_true;
+
+	single = isl_map_plain_is_singleton(map1);
+	if (single < 0)
+		return isl_bool_error;
+	map2 = isl_map_compute_divs(isl_map_copy(map2));
+	if (single) {
+		is_subset = map_is_singleton_subset(map1, map2);
+		isl_map_free(map2);
+		return is_subset;
+	}
+	is_subset = map_diff_is_empty(map1, map2);
+	isl_map_free(map2);
+
+	return is_subset;
+}
+
+isl_bool isl_map_is_subset(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	return isl_map_align_params_map_map_and_test(map1, map2,
+							&map_is_subset);
+}
+
+isl_bool isl_set_is_subset(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	return isl_map_is_subset(set_to_map(set1), set_to_map(set2));
+}
+
+__isl_give isl_map *isl_map_make_disjoint(__isl_take isl_map *map)
+{
+	int i;
+	struct isl_subtract_diff_collector sdc;
+	sdc.dc.add = &basic_map_subtract_add;
+
+	if (!map)
+		return NULL;
+	if (ISL_F_ISSET(map, ISL_MAP_DISJOINT))
+		return map;
+	if (map->n <= 1)
+		return map;
+
+	map = isl_map_compute_divs(map);
+	map = isl_map_remove_empty_parts(map);
+
+	if (!map || map->n <= 1)
+		return map;
+
+	sdc.diff = isl_map_from_basic_map(isl_basic_map_copy(map->p[0]));
+
+	for (i = 1; i < map->n; ++i) {
+		struct isl_basic_map *bmap = isl_basic_map_copy(map->p[i]);
+		struct isl_map *copy = isl_map_copy(sdc.diff);
+		if (basic_map_collect_diff(bmap, copy, &sdc.dc) < 0) {
+			isl_map_free(sdc.diff);
+			sdc.diff = NULL;
+			break;
+		}
+	}
+
+	isl_map_free(map);
+
+	return sdc.diff;
+}
+
+__isl_give isl_set *isl_set_make_disjoint(__isl_take isl_set *set)
+{
+	return set_from_map(isl_map_make_disjoint(set_to_map(set)));
+}
+
+__isl_give isl_map *isl_map_complement(__isl_take isl_map *map)
+{
+	isl_map *universe;
+
+	if (!map)
+		return NULL;
+
+	universe = isl_map_universe(isl_map_get_space(map));
+
+	return isl_map_subtract(universe, map);
+}
+
+__isl_give isl_set *isl_set_complement(__isl_take isl_set *set)
+{
+	return isl_map_complement(set);
+}
diff --git a/final/lib/External/isl/isl_map_to_basic_set.c b/final/lib/External/isl/isl_map_to_basic_set.c
new file mode 100644
index 0000000..f0c8d50
--- /dev/null
+++ b/final/lib/External/isl/isl_map_to_basic_set.c
@@ -0,0 +1,14 @@
+#include <isl/map_to_basic_set.h>
+#include <isl/map.h>
+#include <isl/set.h>
+
+#define ISL_KEY		isl_map
+#define ISL_VAL		isl_basic_set
+#define ISL_HMAP_SUFFIX	map_to_basic_set
+#define ISL_HMAP	isl_map_to_basic_set
+#define ISL_KEY_IS_EQUAL	isl_map_plain_is_equal
+#define ISL_VAL_IS_EQUAL	isl_basic_set_plain_is_equal
+#define ISL_KEY_PRINT		isl_printer_print_map
+#define ISL_VAL_PRINT		isl_printer_print_basic_set
+
+#include <isl/hmap_templ.c>
diff --git a/final/lib/External/isl/isl_mat.c b/final/lib/External/isl/isl_mat.c
new file mode 100644
index 0000000..0e9666c
--- /dev/null
+++ b/final/lib/External/isl/isl_mat.c
@@ -0,0 +1,1954 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2014      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/space.h>
+#include <isl_seq.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl_space_private.h>
+#include <isl_val_private.h>
+#include <isl/deprecated/mat_int.h>
+
+isl_ctx *isl_mat_get_ctx(__isl_keep isl_mat *mat)
+{
+	return mat ? mat->ctx : NULL;
+}
+
+/* Return a hash value that digests "mat".
+ */
+uint32_t isl_mat_get_hash(__isl_keep isl_mat *mat)
+{
+	int i;
+	uint32_t hash;
+
+	if (!mat)
+		return 0;
+
+	hash = isl_hash_init();
+	isl_hash_byte(hash, mat->n_row & 0xFF);
+	isl_hash_byte(hash, mat->n_col & 0xFF);
+	for (i = 0; i < mat->n_row; ++i) {
+		uint32_t row_hash;
+
+		row_hash = isl_seq_get_hash(mat->row[i], mat->n_col);
+		isl_hash_hash(hash, row_hash);
+	}
+
+	return hash;
+}
+
+struct isl_mat *isl_mat_alloc(struct isl_ctx *ctx,
+	unsigned n_row, unsigned n_col)
+{
+	int i;
+	struct isl_mat *mat;
+
+	mat = isl_alloc_type(ctx, struct isl_mat);
+	if (!mat)
+		return NULL;
+
+	mat->row = NULL;
+	mat->block = isl_blk_alloc(ctx, n_row * n_col);
+	if (isl_blk_is_error(mat->block))
+		goto error;
+	mat->row = isl_alloc_array(ctx, isl_int *, n_row);
+	if (n_row && !mat->row)
+		goto error;
+
+	for (i = 0; i < n_row; ++i)
+		mat->row[i] = mat->block.data + i * n_col;
+
+	mat->ctx = ctx;
+	isl_ctx_ref(ctx);
+	mat->ref = 1;
+	mat->n_row = n_row;
+	mat->n_col = n_col;
+	mat->max_col = n_col;
+	mat->flags = 0;
+
+	return mat;
+error:
+	isl_blk_free(ctx, mat->block);
+	free(mat);
+	return NULL;
+}
+
+struct isl_mat *isl_mat_extend(struct isl_mat *mat,
+	unsigned n_row, unsigned n_col)
+{
+	int i;
+	isl_int *old;
+	isl_int **row;
+
+	if (!mat)
+		return NULL;
+
+	if (mat->max_col >= n_col && mat->n_row >= n_row) {
+		if (mat->n_col < n_col)
+			mat->n_col = n_col;
+		return mat;
+	}
+
+	if (mat->max_col < n_col) {
+		struct isl_mat *new_mat;
+
+		if (n_row < mat->n_row)
+			n_row = mat->n_row;
+		new_mat = isl_mat_alloc(mat->ctx, n_row, n_col);
+		if (!new_mat)
+			goto error;
+		for (i = 0; i < mat->n_row; ++i)
+			isl_seq_cpy(new_mat->row[i], mat->row[i], mat->n_col);
+		isl_mat_free(mat);
+		return new_mat;
+	}
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		goto error;
+
+	old = mat->block.data;
+	mat->block = isl_blk_extend(mat->ctx, mat->block, n_row * mat->max_col);
+	if (isl_blk_is_error(mat->block))
+		goto error;
+	row = isl_realloc_array(mat->ctx, mat->row, isl_int *, n_row);
+	if (n_row && !row)
+		goto error;
+	mat->row = row;
+
+	for (i = 0; i < mat->n_row; ++i)
+		mat->row[i] = mat->block.data + (mat->row[i] - old);
+	for (i = mat->n_row; i < n_row; ++i)
+		mat->row[i] = mat->block.data + i * mat->max_col;
+	mat->n_row = n_row;
+	if (mat->n_col < n_col)
+		mat->n_col = n_col;
+
+	return mat;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_sub_alloc6(isl_ctx *ctx, isl_int **row,
+	unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col)
+{
+	int i;
+	struct isl_mat *mat;
+
+	mat = isl_alloc_type(ctx, struct isl_mat);
+	if (!mat)
+		return NULL;
+	mat->row = isl_alloc_array(ctx, isl_int *, n_row);
+	if (n_row && !mat->row)
+		goto error;
+	for (i = 0; i < n_row; ++i)
+		mat->row[i] = row[first_row+i] + first_col;
+	mat->ctx = ctx;
+	isl_ctx_ref(ctx);
+	mat->ref = 1;
+	mat->n_row = n_row;
+	mat->n_col = n_col;
+	mat->block = isl_blk_empty();
+	mat->flags = ISL_MAT_BORROWED;
+	return mat;
+error:
+	free(mat);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_sub_alloc(__isl_keep isl_mat *mat,
+	unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col)
+{
+	if (!mat)
+		return NULL;
+	return isl_mat_sub_alloc6(mat->ctx, mat->row, first_row, n_row,
+				  first_col, n_col);
+}
+
+void isl_mat_sub_copy(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+	unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col)
+{
+	int i;
+
+	for (i = 0; i < n_row; ++i)
+		isl_seq_cpy(dst[i]+dst_col, src[i]+src_col, n_col);
+}
+
+void isl_mat_sub_neg(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+	unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col)
+{
+	int i;
+
+	for (i = 0; i < n_row; ++i)
+		isl_seq_neg(dst[i]+dst_col, src[i]+src_col, n_col);
+}
+
+__isl_give isl_mat *isl_mat_copy(__isl_keep isl_mat *mat)
+{
+	if (!mat)
+		return NULL;
+
+	mat->ref++;
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_dup(__isl_keep isl_mat *mat)
+{
+	int i;
+	struct isl_mat *mat2;
+
+	if (!mat)
+		return NULL;
+	mat2 = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col);
+	if (!mat2)
+		return NULL;
+	for (i = 0; i < mat->n_row; ++i)
+		isl_seq_cpy(mat2->row[i], mat->row[i], mat->n_col);
+	return mat2;
+}
+
+__isl_give isl_mat *isl_mat_cow(__isl_take isl_mat *mat)
+{
+	struct isl_mat *mat2;
+	if (!mat)
+		return NULL;
+
+	if (mat->ref == 1 && !ISL_F_ISSET(mat, ISL_MAT_BORROWED))
+		return mat;
+
+	mat2 = isl_mat_dup(mat);
+	isl_mat_free(mat);
+	return mat2;
+}
+
+__isl_null isl_mat *isl_mat_free(__isl_take isl_mat *mat)
+{
+	if (!mat)
+		return NULL;
+
+	if (--mat->ref > 0)
+		return NULL;
+
+	if (!ISL_F_ISSET(mat, ISL_MAT_BORROWED))
+		isl_blk_free(mat->ctx, mat->block);
+	isl_ctx_deref(mat->ctx);
+	free(mat->row);
+	free(mat);
+
+	return NULL;
+}
+
+int isl_mat_rows(__isl_keep isl_mat *mat)
+{
+	return mat ? mat->n_row : -1;
+}
+
+int isl_mat_cols(__isl_keep isl_mat *mat)
+{
+	return mat ? mat->n_col : -1;
+}
+
+/* Check that "col" is a valid column position for "mat".
+ */
+static isl_stat check_col(__isl_keep isl_mat *mat, int col)
+{
+	if (!mat)
+		return isl_stat_error;
+	if (col < 0 || col >= mat->n_col)
+		isl_die(isl_mat_get_ctx(mat), isl_error_invalid,
+			"column out of range", return isl_stat_error);
+	return isl_stat_ok;
+}
+
+/* Check that "row" is a valid row position for "mat".
+ */
+static isl_stat check_row(__isl_keep isl_mat *mat, int row)
+{
+	if (!mat)
+		return isl_stat_error;
+	if (row < 0 || row >= mat->n_row)
+		isl_die(isl_mat_get_ctx(mat), isl_error_invalid,
+			"row out of range", return isl_stat_error);
+	return isl_stat_ok;
+}
+
+int isl_mat_get_element(__isl_keep isl_mat *mat, int row, int col, isl_int *v)
+{
+	if (check_row(mat, row) < 0)
+		return -1;
+	if (check_col(mat, col) < 0)
+		return -1;
+	isl_int_set(*v, mat->row[row][col]);
+	return 0;
+}
+
+/* Extract the element at row "row", oolumn "col" of "mat".
+ */
+__isl_give isl_val *isl_mat_get_element_val(__isl_keep isl_mat *mat,
+	int row, int col)
+{
+	isl_ctx *ctx;
+
+	if (check_row(mat, row) < 0)
+		return NULL;
+	if (check_col(mat, col) < 0)
+		return NULL;
+	ctx = isl_mat_get_ctx(mat);
+	return isl_val_int_from_isl_int(ctx, mat->row[row][col]);
+}
+
+__isl_give isl_mat *isl_mat_set_element(__isl_take isl_mat *mat,
+	int row, int col, isl_int v)
+{
+	mat = isl_mat_cow(mat);
+	if (check_row(mat, row) < 0)
+		return isl_mat_free(mat);
+	if (check_col(mat, col) < 0)
+		return isl_mat_free(mat);
+	isl_int_set(mat->row[row][col], v);
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_set_element_si(__isl_take isl_mat *mat,
+	int row, int col, int v)
+{
+	mat = isl_mat_cow(mat);
+	if (check_row(mat, row) < 0)
+		return isl_mat_free(mat);
+	if (check_col(mat, col) < 0)
+		return isl_mat_free(mat);
+	isl_int_set_si(mat->row[row][col], v);
+	return mat;
+}
+
+/* Replace the element at row "row", column "col" of "mat" by "v".
+ */
+__isl_give isl_mat *isl_mat_set_element_val(__isl_take isl_mat *mat,
+	int row, int col, __isl_take isl_val *v)
+{
+	if (!v)
+		return isl_mat_free(mat);
+	if (!isl_val_is_int(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting integer value", goto error);
+	mat = isl_mat_set_element(mat, row, col, v->n);
+	isl_val_free(v);
+	return mat;
+error:
+	isl_val_free(v);
+	return isl_mat_free(mat);
+}
+
+__isl_give isl_mat *isl_mat_diag(isl_ctx *ctx, unsigned n_row, isl_int d)
+{
+	int i;
+	struct isl_mat *mat;
+
+	mat = isl_mat_alloc(ctx, n_row, n_row);
+	if (!mat)
+		return NULL;
+	for (i = 0; i < n_row; ++i) {
+		isl_seq_clr(mat->row[i], i);
+		isl_int_set(mat->row[i][i], d);
+		isl_seq_clr(mat->row[i]+i+1, n_row-(i+1));
+	}
+
+	return mat;
+}
+
+/* Create an "n_row" by "n_col" matrix with zero elements.
+ */
+__isl_give isl_mat *isl_mat_zero(isl_ctx *ctx, unsigned n_row, unsigned n_col)
+{
+	int i;
+	isl_mat *mat;
+
+	mat = isl_mat_alloc(ctx, n_row, n_col);
+	if (!mat)
+		return NULL;
+	for (i = 0; i < n_row; ++i)
+		isl_seq_clr(mat->row[i], n_col);
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_identity(isl_ctx *ctx, unsigned n_row)
+{
+	if (!ctx)
+		return NULL;
+	return isl_mat_diag(ctx, n_row, ctx->one);
+}
+
+/* Is "mat" a (possibly scaled) identity matrix?
+ */
+int isl_mat_is_scaled_identity(__isl_keep isl_mat *mat)
+{
+	int i;
+
+	if (!mat)
+		return -1;
+	if (mat->n_row != mat->n_col)
+		return 0;
+
+	for (i = 0; i < mat->n_row; ++i) {
+		if (isl_seq_first_non_zero(mat->row[i], i) != -1)
+			return 0;
+		if (isl_int_ne(mat->row[0][0], mat->row[i][i]))
+			return 0;
+		if (isl_seq_first_non_zero(mat->row[i] + i + 1,
+					    mat->n_col - (i + 1)) != -1)
+			return 0;
+	}
+
+	return 1;
+}
+
+__isl_give isl_vec *isl_mat_vec_product(__isl_take isl_mat *mat,
+	__isl_take isl_vec *vec)
+{
+	int i;
+	struct isl_vec *prod;
+
+	if (!mat || !vec)
+		goto error;
+
+	isl_assert(mat->ctx, mat->n_col == vec->size, goto error);
+
+	prod = isl_vec_alloc(mat->ctx, mat->n_row);
+	if (!prod)
+		goto error;
+
+	for (i = 0; i < prod->size; ++i)
+		isl_seq_inner_product(mat->row[i], vec->el, vec->size,
+					&prod->block.data[i]);
+	isl_mat_free(mat);
+	isl_vec_free(vec);
+	return prod;
+error:
+	isl_mat_free(mat);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+__isl_give isl_vec *isl_mat_vec_inverse_product(__isl_take isl_mat *mat,
+	__isl_take isl_vec *vec)
+{
+	struct isl_mat *vec_mat;
+	int i;
+
+	if (!mat || !vec)
+		goto error;
+	vec_mat = isl_mat_alloc(vec->ctx, vec->size, 1);
+	if (!vec_mat)
+		goto error;
+	for (i = 0; i < vec->size; ++i)
+		isl_int_set(vec_mat->row[i][0], vec->el[i]);
+	vec_mat = isl_mat_inverse_product(mat, vec_mat);
+	isl_vec_free(vec);
+	if (!vec_mat)
+		return NULL;
+	vec = isl_vec_alloc(vec_mat->ctx, vec_mat->n_row);
+	if (vec)
+		for (i = 0; i < vec->size; ++i)
+			isl_int_set(vec->el[i], vec_mat->row[i][0]);
+	isl_mat_free(vec_mat);
+	return vec;
+error:
+	isl_mat_free(mat);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+__isl_give isl_vec *isl_vec_mat_product(__isl_take isl_vec *vec,
+	__isl_take isl_mat *mat)
+{
+	int i, j;
+	struct isl_vec *prod;
+
+	if (!mat || !vec)
+		goto error;
+
+	isl_assert(mat->ctx, mat->n_row == vec->size, goto error);
+
+	prod = isl_vec_alloc(mat->ctx, mat->n_col);
+	if (!prod)
+		goto error;
+
+	for (i = 0; i < prod->size; ++i) {
+		isl_int_set_si(prod->el[i], 0);
+		for (j = 0; j < vec->size; ++j)
+			isl_int_addmul(prod->el[i], vec->el[j], mat->row[j][i]);
+	}
+	isl_mat_free(mat);
+	isl_vec_free(vec);
+	return prod;
+error:
+	isl_mat_free(mat);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_aff_direct_sum(__isl_take isl_mat *left,
+	__isl_take isl_mat *right)
+{
+	int i;
+	struct isl_mat *sum;
+
+	if (!left || !right)
+		goto error;
+
+	isl_assert(left->ctx, left->n_row == right->n_row, goto error);
+	isl_assert(left->ctx, left->n_row >= 1, goto error);
+	isl_assert(left->ctx, left->n_col >= 1, goto error);
+	isl_assert(left->ctx, right->n_col >= 1, goto error);
+	isl_assert(left->ctx,
+	    isl_seq_first_non_zero(left->row[0]+1, left->n_col-1) == -1,
+	    goto error);
+	isl_assert(left->ctx,
+	    isl_seq_first_non_zero(right->row[0]+1, right->n_col-1) == -1,
+	    goto error);
+
+	sum = isl_mat_alloc(left->ctx, left->n_row, left->n_col + right->n_col - 1);
+	if (!sum)
+		goto error;
+	isl_int_lcm(sum->row[0][0], left->row[0][0], right->row[0][0]);
+	isl_int_divexact(left->row[0][0], sum->row[0][0], left->row[0][0]);
+	isl_int_divexact(right->row[0][0], sum->row[0][0], right->row[0][0]);
+
+	isl_seq_clr(sum->row[0]+1, sum->n_col-1);
+	for (i = 1; i < sum->n_row; ++i) {
+		isl_int_mul(sum->row[i][0], left->row[0][0], left->row[i][0]);
+		isl_int_addmul(sum->row[i][0],
+				right->row[0][0], right->row[i][0]);
+		isl_seq_scale(sum->row[i]+1, left->row[i]+1, left->row[0][0],
+				left->n_col-1);
+		isl_seq_scale(sum->row[i]+left->n_col,
+				right->row[i]+1, right->row[0][0],
+				right->n_col-1);
+	}
+
+	isl_int_divexact(left->row[0][0], sum->row[0][0], left->row[0][0]);
+	isl_int_divexact(right->row[0][0], sum->row[0][0], right->row[0][0]);
+	isl_mat_free(left);
+	isl_mat_free(right);
+	return sum;
+error:
+	isl_mat_free(left);
+	isl_mat_free(right);
+	return NULL;
+}
+
+static void exchange(struct isl_mat *M, struct isl_mat **U,
+	struct isl_mat **Q, unsigned row, unsigned i, unsigned j)
+{
+	int r;
+	for (r = row; r < M->n_row; ++r)
+		isl_int_swap(M->row[r][i], M->row[r][j]);
+	if (U) {
+		for (r = 0; r < (*U)->n_row; ++r)
+			isl_int_swap((*U)->row[r][i], (*U)->row[r][j]);
+	}
+	if (Q)
+		isl_mat_swap_rows(*Q, i, j);
+}
+
+static void subtract(struct isl_mat *M, struct isl_mat **U,
+	struct isl_mat **Q, unsigned row, unsigned i, unsigned j, isl_int m)
+{
+	int r;
+	for (r = row; r < M->n_row; ++r)
+		isl_int_submul(M->row[r][j], m, M->row[r][i]);
+	if (U) {
+		for (r = 0; r < (*U)->n_row; ++r)
+			isl_int_submul((*U)->row[r][j], m, (*U)->row[r][i]);
+	}
+	if (Q) {
+		for (r = 0; r < (*Q)->n_col; ++r)
+			isl_int_addmul((*Q)->row[i][r], m, (*Q)->row[j][r]);
+	}
+}
+
+static void oppose(struct isl_mat *M, struct isl_mat **U,
+	struct isl_mat **Q, unsigned row, unsigned col)
+{
+	int r;
+	for (r = row; r < M->n_row; ++r)
+		isl_int_neg(M->row[r][col], M->row[r][col]);
+	if (U) {
+		for (r = 0; r < (*U)->n_row; ++r)
+			isl_int_neg((*U)->row[r][col], (*U)->row[r][col]);
+	}
+	if (Q)
+		isl_seq_neg((*Q)->row[col], (*Q)->row[col], (*Q)->n_col);
+}
+
+/* Given matrix M, compute
+ *
+ *		M U = H
+ *		M   = H Q
+ *
+ * with U and Q unimodular matrices and H a matrix in column echelon form
+ * such that on each echelon row the entries in the non-echelon column
+ * are non-negative (if neg == 0) or non-positive (if neg == 1)
+ * and strictly smaller (in absolute value) than the entries in the echelon
+ * column.
+ * If U or Q are NULL, then these matrices are not computed.
+ */
+__isl_give isl_mat *isl_mat_left_hermite(__isl_take isl_mat *M, int neg,
+	__isl_give isl_mat **U, __isl_give isl_mat **Q)
+{
+	isl_int c;
+	int row, col;
+
+	if (U)
+		*U = NULL;
+	if (Q)
+		*Q = NULL;
+	if (!M)
+		goto error;
+	M = isl_mat_cow(M);
+	if (!M)
+		goto error;
+	if (U) {
+		*U = isl_mat_identity(M->ctx, M->n_col);
+		if (!*U)
+			goto error;
+	}
+	if (Q) {
+		*Q = isl_mat_identity(M->ctx, M->n_col);
+		if (!*Q)
+			goto error;
+	}
+
+	col = 0;
+	isl_int_init(c);
+	for (row = 0; row < M->n_row; ++row) {
+		int first, i, off;
+		first = isl_seq_abs_min_non_zero(M->row[row]+col, M->n_col-col);
+		if (first == -1)
+			continue;
+		first += col;
+		if (first != col)
+			exchange(M, U, Q, row, first, col);
+		if (isl_int_is_neg(M->row[row][col]))
+			oppose(M, U, Q, row, col);
+		first = col+1;
+		while ((off = isl_seq_first_non_zero(M->row[row]+first,
+						       M->n_col-first)) != -1) {
+			first += off;
+			isl_int_fdiv_q(c, M->row[row][first], M->row[row][col]);
+			subtract(M, U, Q, row, col, first, c);
+			if (!isl_int_is_zero(M->row[row][first]))
+				exchange(M, U, Q, row, first, col);
+			else
+				++first;
+		}
+		for (i = 0; i < col; ++i) {
+			if (isl_int_is_zero(M->row[row][i]))
+				continue;
+			if (neg)
+				isl_int_cdiv_q(c, M->row[row][i], M->row[row][col]);
+			else
+				isl_int_fdiv_q(c, M->row[row][i], M->row[row][col]);
+			if (isl_int_is_zero(c))
+				continue;
+			subtract(M, U, Q, row, col, i, c);
+		}
+		++col;
+	}
+	isl_int_clear(c);
+
+	return M;
+error:
+	if (Q) {
+		isl_mat_free(*Q);
+		*Q = NULL;
+	}
+	if (U) {
+		isl_mat_free(*U);
+		*U = NULL;
+	}
+	isl_mat_free(M);
+	return NULL;
+}
+
+/* Use row "row" of "mat" to eliminate column "col" from all other rows.
+ */
+static __isl_give isl_mat *eliminate(__isl_take isl_mat *mat, int row, int col)
+{
+	int k, nr, nc;
+	isl_ctx *ctx;
+
+	if (!mat)
+		return NULL;
+
+	ctx = isl_mat_get_ctx(mat);
+	nr = isl_mat_rows(mat);
+	nc = isl_mat_cols(mat);
+
+	for (k = 0; k < nr; ++k) {
+		if (k == row)
+			continue;
+		if (isl_int_is_zero(mat->row[k][col]))
+			continue;
+		mat = isl_mat_cow(mat);
+		if (!mat)
+			return NULL;
+		isl_seq_elim(mat->row[k], mat->row[row], col, nc, NULL);
+		isl_seq_normalize(ctx, mat->row[k], nc);
+	}
+
+	return mat;
+}
+
+/* Perform Gaussian elimination on the rows of "mat", but start
+ * from the final row and the final column.
+ * Any zero rows that result from the elimination are removed.
+ *
+ * In particular, for each column from last to first,
+ * look for the last row with a non-zero coefficient in that column,
+ * move it last (but before other rows moved last in previous steps) and
+ * use it to eliminate the column from the other rows.
+ */
+__isl_give isl_mat *isl_mat_reverse_gauss(__isl_take isl_mat *mat)
+{
+	int k, row, last, nr, nc;
+
+	if (!mat)
+		return NULL;
+
+	nr = isl_mat_rows(mat);
+	nc = isl_mat_cols(mat);
+
+	last = nc - 1;
+	for (row = nr - 1; row >= 0; --row) {
+		for (; last >= 0; --last) {
+			for (k = row; k >= 0; --k)
+				if (!isl_int_is_zero(mat->row[k][last]))
+					break;
+			if (k >= 0)
+				break;
+		}
+		if (last < 0)
+			break;
+		if (k != row)
+			mat = isl_mat_swap_rows(mat, k, row);
+		if (!mat)
+			return NULL;
+		if (isl_int_is_neg(mat->row[row][last]))
+			mat = isl_mat_row_neg(mat, row);
+		mat = eliminate(mat, row, last);
+		if (!mat)
+			return NULL;
+	}
+	mat = isl_mat_drop_rows(mat, 0, row + 1);
+
+	return mat;
+}
+
+/* Negate the lexicographically negative rows of "mat" such that
+ * all rows in the result are lexicographically non-negative.
+ */
+__isl_give isl_mat *isl_mat_lexnonneg_rows(__isl_take isl_mat *mat)
+{
+	int i, nr, nc;
+
+	if (!mat)
+		return NULL;
+
+	nr = isl_mat_rows(mat);
+	nc = isl_mat_cols(mat);
+
+	for (i = 0; i < nr; ++i) {
+		int pos;
+
+		pos = isl_seq_first_non_zero(mat->row[i], nc);
+		if (pos < 0)
+			continue;
+		if (isl_int_is_nonneg(mat->row[i][pos]))
+			continue;
+		mat = isl_mat_row_neg(mat, i);
+		if (!mat)
+			return NULL;
+	}
+
+	return mat;
+}
+
+struct isl_mat *isl_mat_right_kernel(struct isl_mat *mat)
+{
+	int i, rank;
+	struct isl_mat *U = NULL;
+	struct isl_mat *K;
+
+	mat = isl_mat_left_hermite(mat, 0, &U, NULL);
+	if (!mat || !U)
+		goto error;
+
+	for (i = 0, rank = 0; rank < mat->n_col; ++rank) {
+		while (i < mat->n_row && isl_int_is_zero(mat->row[i][rank]))
+			++i;
+		if (i >= mat->n_row)
+			break;
+	}
+	K = isl_mat_alloc(U->ctx, U->n_row, U->n_col - rank);
+	if (!K)
+		goto error;
+	isl_mat_sub_copy(K->ctx, K->row, U->row, U->n_row, 0, rank, U->n_col-rank);
+	isl_mat_free(mat);
+	isl_mat_free(U);
+	return K;
+error:
+	isl_mat_free(mat);
+	isl_mat_free(U);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_lin_to_aff(__isl_take isl_mat *mat)
+{
+	int i;
+	struct isl_mat *mat2;
+
+	if (!mat)
+		return NULL;
+	mat2 = isl_mat_alloc(mat->ctx, 1+mat->n_row, 1+mat->n_col);
+	if (!mat2)
+		goto error;
+	isl_int_set_si(mat2->row[0][0], 1);
+	isl_seq_clr(mat2->row[0]+1, mat->n_col);
+	for (i = 0; i < mat->n_row; ++i) {
+		isl_int_set_si(mat2->row[1+i][0], 0);
+		isl_seq_cpy(mat2->row[1+i]+1, mat->row[i], mat->n_col);
+	}
+	isl_mat_free(mat);
+	return mat2;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+/* Given two matrices M1 and M2, return the block matrix
+ *
+ *	[ M1  0  ]
+ *	[ 0   M2 ]
+ */
+__isl_give isl_mat *isl_mat_diagonal(__isl_take isl_mat *mat1,
+	__isl_take isl_mat *mat2)
+{
+	int i;
+	isl_mat *mat;
+
+	if (!mat1 || !mat2)
+		goto error;
+
+	mat = isl_mat_alloc(mat1->ctx, mat1->n_row + mat2->n_row,
+				       mat1->n_col + mat2->n_col);
+	if (!mat)
+		goto error;
+	for (i = 0; i < mat1->n_row; ++i) {
+		isl_seq_cpy(mat->row[i], mat1->row[i], mat1->n_col);
+		isl_seq_clr(mat->row[i] + mat1->n_col, mat2->n_col);
+	}
+	for (i = 0; i < mat2->n_row; ++i) {
+		isl_seq_clr(mat->row[mat1->n_row + i], mat1->n_col);
+		isl_seq_cpy(mat->row[mat1->n_row + i] + mat1->n_col,
+						    mat2->row[i], mat2->n_col);
+	}
+	isl_mat_free(mat1);
+	isl_mat_free(mat2);
+	return mat;
+error:
+	isl_mat_free(mat1);
+	isl_mat_free(mat2);
+	return NULL;
+}
+
+static int row_first_non_zero(isl_int **row, unsigned n_row, unsigned col)
+{
+	int i;
+
+	for (i = 0; i < n_row; ++i)
+		if (!isl_int_is_zero(row[i][col]))
+			return i;
+	return -1;
+}
+
+static int row_abs_min_non_zero(isl_int **row, unsigned n_row, unsigned col)
+{
+	int i, min = row_first_non_zero(row, n_row, col);
+	if (min < 0)
+		return -1;
+	for (i = min + 1; i < n_row; ++i) {
+		if (isl_int_is_zero(row[i][col]))
+			continue;
+		if (isl_int_abs_lt(row[i][col], row[min][col]))
+			min = i;
+	}
+	return min;
+}
+
+static isl_stat inv_exchange(__isl_keep isl_mat **left,
+	__isl_keep isl_mat **right, unsigned i, unsigned j)
+{
+	*left = isl_mat_swap_rows(*left, i, j);
+	*right = isl_mat_swap_rows(*right, i, j);
+
+	if (!*left || !*right)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+static void inv_oppose(
+	struct isl_mat *left, struct isl_mat *right, unsigned row)
+{
+	isl_seq_neg(left->row[row]+row, left->row[row]+row, left->n_col-row);
+	isl_seq_neg(right->row[row], right->row[row], right->n_col);
+}
+
+static void inv_subtract(struct isl_mat *left, struct isl_mat *right,
+	unsigned row, unsigned i, isl_int m)
+{
+	isl_int_neg(m, m);
+	isl_seq_combine(left->row[i]+row,
+			left->ctx->one, left->row[i]+row,
+			m, left->row[row]+row,
+			left->n_col-row);
+	isl_seq_combine(right->row[i], right->ctx->one, right->row[i],
+			m, right->row[row], right->n_col);
+}
+
+/* Compute inv(left)*right
+ */
+__isl_give isl_mat *isl_mat_inverse_product(__isl_take isl_mat *left,
+	__isl_take isl_mat *right)
+{
+	int row;
+	isl_int a, b;
+
+	if (!left || !right)
+		goto error;
+
+	isl_assert(left->ctx, left->n_row == left->n_col, goto error);
+	isl_assert(left->ctx, left->n_row == right->n_row, goto error);
+
+	if (left->n_row == 0) {
+		isl_mat_free(left);
+		return right;
+	}
+
+	left = isl_mat_cow(left);
+	right = isl_mat_cow(right);
+	if (!left || !right)
+		goto error;
+
+	isl_int_init(a);
+	isl_int_init(b);
+	for (row = 0; row < left->n_row; ++row) {
+		int pivot, first, i, off;
+		pivot = row_abs_min_non_zero(left->row+row, left->n_row-row, row);
+		if (pivot < 0) {
+			isl_int_clear(a);
+			isl_int_clear(b);
+			isl_assert(left->ctx, pivot >= 0, goto error);
+		}
+		pivot += row;
+		if (pivot != row)
+			if (inv_exchange(&left, &right, pivot, row) < 0)
+				goto error;
+		if (isl_int_is_neg(left->row[row][row]))
+			inv_oppose(left, right, row);
+		first = row+1;
+		while ((off = row_first_non_zero(left->row+first,
+					left->n_row-first, row)) != -1) {
+			first += off;
+			isl_int_fdiv_q(a, left->row[first][row],
+					left->row[row][row]);
+			inv_subtract(left, right, row, first, a);
+			if (!isl_int_is_zero(left->row[first][row])) {
+				if (inv_exchange(&left, &right, row, first) < 0)
+					goto error;
+			} else {
+				++first;
+			}
+		}
+		for (i = 0; i < row; ++i) {
+			if (isl_int_is_zero(left->row[i][row]))
+				continue;
+			isl_int_gcd(a, left->row[row][row], left->row[i][row]);
+			isl_int_divexact(b, left->row[i][row], a);
+			isl_int_divexact(a, left->row[row][row], a);
+			isl_int_neg(b, b);
+			isl_seq_combine(left->row[i] + i,
+					a, left->row[i] + i,
+					b, left->row[row] + i,
+					left->n_col - i);
+			isl_seq_combine(right->row[i], a, right->row[i],
+					b, right->row[row], right->n_col);
+		}
+	}
+	isl_int_clear(b);
+
+	isl_int_set(a, left->row[0][0]);
+	for (row = 1; row < left->n_row; ++row)
+		isl_int_lcm(a, a, left->row[row][row]);
+	if (isl_int_is_zero(a)){
+		isl_int_clear(a);
+		isl_assert(left->ctx, 0, goto error);
+	}
+	for (row = 0; row < left->n_row; ++row) {
+		isl_int_divexact(left->row[row][row], a, left->row[row][row]);
+		if (isl_int_is_one(left->row[row][row]))
+			continue;
+		isl_seq_scale(right->row[row], right->row[row],
+				left->row[row][row], right->n_col);
+	}
+	isl_int_clear(a);
+
+	isl_mat_free(left);
+	return right;
+error:
+	isl_mat_free(left);
+	isl_mat_free(right);
+	return NULL;
+}
+
+void isl_mat_col_scale(struct isl_mat *mat, unsigned col, isl_int m)
+{
+	int i;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_int_mul(mat->row[i][col], mat->row[i][col], m);
+}
+
+void isl_mat_col_combine(struct isl_mat *mat, unsigned dst,
+	isl_int m1, unsigned src1, isl_int m2, unsigned src2)
+{
+	int i;
+	isl_int tmp;
+
+	isl_int_init(tmp);
+	for (i = 0; i < mat->n_row; ++i) {
+		isl_int_mul(tmp, m1, mat->row[i][src1]);
+		isl_int_addmul(tmp, m2, mat->row[i][src2]);
+		isl_int_set(mat->row[i][dst], tmp);
+	}
+	isl_int_clear(tmp);
+}
+
+__isl_give isl_mat *isl_mat_right_inverse(__isl_take isl_mat *mat)
+{
+	struct isl_mat *inv;
+	int row;
+	isl_int a, b;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	inv = isl_mat_identity(mat->ctx, mat->n_col);
+	inv = isl_mat_cow(inv);
+	if (!inv)
+		goto error;
+
+	isl_int_init(a);
+	isl_int_init(b);
+	for (row = 0; row < mat->n_row; ++row) {
+		int pivot, first, i, off;
+		pivot = isl_seq_abs_min_non_zero(mat->row[row]+row, mat->n_col-row);
+		if (pivot < 0) {
+			isl_int_clear(a);
+			isl_int_clear(b);
+			isl_assert(mat->ctx, pivot >= 0, goto error);
+		}
+		pivot += row;
+		if (pivot != row)
+			exchange(mat, &inv, NULL, row, pivot, row);
+		if (isl_int_is_neg(mat->row[row][row]))
+			oppose(mat, &inv, NULL, row, row);
+		first = row+1;
+		while ((off = isl_seq_first_non_zero(mat->row[row]+first,
+						    mat->n_col-first)) != -1) {
+			first += off;
+			isl_int_fdiv_q(a, mat->row[row][first],
+						    mat->row[row][row]);
+			subtract(mat, &inv, NULL, row, row, first, a);
+			if (!isl_int_is_zero(mat->row[row][first]))
+				exchange(mat, &inv, NULL, row, row, first);
+			else
+				++first;
+		}
+		for (i = 0; i < row; ++i) {
+			if (isl_int_is_zero(mat->row[row][i]))
+				continue;
+			isl_int_gcd(a, mat->row[row][row], mat->row[row][i]);
+			isl_int_divexact(b, mat->row[row][i], a);
+			isl_int_divexact(a, mat->row[row][row], a);
+			isl_int_neg(a, a);
+			isl_mat_col_combine(mat, i, a, i, b, row);
+			isl_mat_col_combine(inv, i, a, i, b, row);
+		}
+	}
+	isl_int_clear(b);
+
+	isl_int_set(a, mat->row[0][0]);
+	for (row = 1; row < mat->n_row; ++row)
+		isl_int_lcm(a, a, mat->row[row][row]);
+	if (isl_int_is_zero(a)){
+		isl_int_clear(a);
+		goto error;
+	}
+	for (row = 0; row < mat->n_row; ++row) {
+		isl_int_divexact(mat->row[row][row], a, mat->row[row][row]);
+		if (isl_int_is_one(mat->row[row][row]))
+			continue;
+		isl_mat_col_scale(inv, row, mat->row[row][row]);
+	}
+	isl_int_clear(a);
+
+	isl_mat_free(mat);
+
+	return inv;
+error:
+	isl_mat_free(mat);
+	isl_mat_free(inv);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_transpose(__isl_take isl_mat *mat)
+{
+	struct isl_mat *transpose = NULL;
+	int i, j;
+
+	if (!mat)
+		return NULL;
+
+	if (mat->n_col == mat->n_row) {
+		mat = isl_mat_cow(mat);
+		if (!mat)
+			return NULL;
+		for (i = 0; i < mat->n_row; ++i)
+			for (j = i + 1; j < mat->n_col; ++j)
+				isl_int_swap(mat->row[i][j], mat->row[j][i]);
+		return mat;
+	}
+	transpose = isl_mat_alloc(mat->ctx, mat->n_col, mat->n_row);
+	if (!transpose)
+		goto error;
+	for (i = 0; i < mat->n_row; ++i)
+		for (j = 0; j < mat->n_col; ++j)
+			isl_int_set(transpose->row[j][i], mat->row[i][j]);
+	isl_mat_free(mat);
+	return transpose;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_swap_cols(__isl_take isl_mat *mat,
+	unsigned i, unsigned j)
+{
+	int r;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+	isl_assert(mat->ctx, i < mat->n_col, goto error);
+	isl_assert(mat->ctx, j < mat->n_col, goto error);
+
+	for (r = 0; r < mat->n_row; ++r)
+		isl_int_swap(mat->row[r][i], mat->row[r][j]);
+	return mat;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_swap_rows(__isl_take isl_mat *mat,
+	unsigned i, unsigned j)
+{
+	isl_int *t;
+
+	if (!mat)
+		return NULL;
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+	t = mat->row[i];
+	mat->row[i] = mat->row[j];
+	mat->row[j] = t;
+	return mat;
+}
+
+/* Calculate the product of two matrices.
+ *
+ * This function is optimized for operand matrices that contain many zeros and
+ * skips multiplications where we know one of the operands is zero.
+ */
+__isl_give isl_mat *isl_mat_product(__isl_take isl_mat *left,
+	__isl_take isl_mat *right)
+{
+	int i, j, k;
+	struct isl_mat *prod;
+
+	if (!left || !right)
+		goto error;
+	isl_assert(left->ctx, left->n_col == right->n_row, goto error);
+	prod = isl_mat_alloc(left->ctx, left->n_row, right->n_col);
+	if (!prod)
+		goto error;
+	if (left->n_col == 0) {
+		for (i = 0; i < prod->n_row; ++i)
+			isl_seq_clr(prod->row[i], prod->n_col);
+		isl_mat_free(left);
+		isl_mat_free(right);
+		return prod;
+	}
+	for (i = 0; i < prod->n_row; ++i) {
+		for (j = 0; j < prod->n_col; ++j)
+			isl_int_mul(prod->row[i][j],
+				    left->row[i][0], right->row[0][j]);
+		for (k = 1; k < left->n_col; ++k) {
+			if (isl_int_is_zero(left->row[i][k]))
+				continue;
+			for (j = 0; j < prod->n_col; ++j)
+				isl_int_addmul(prod->row[i][j],
+					    left->row[i][k], right->row[k][j]);
+		}
+	}
+	isl_mat_free(left);
+	isl_mat_free(right);
+	return prod;
+error:
+	isl_mat_free(left);
+	isl_mat_free(right);
+	return NULL;
+}
+
+/* Replace the variables x in the rows q by x' given by x = M x',
+ * with M the matrix mat.
+ *
+ * If the number of new variables is greater than the original
+ * number of variables, then the rows q have already been
+ * preextended.  If the new number is smaller, then the coefficients
+ * of the divs, which are not changed, need to be shifted down.
+ * The row q may be the equalities, the inequalities or the
+ * div expressions.  In the latter case, has_div is true and
+ * we need to take into account the extra denominator column.
+ */
+static int preimage(struct isl_ctx *ctx, isl_int **q, unsigned n,
+	unsigned n_div, int has_div, struct isl_mat *mat)
+{
+	int i;
+	struct isl_mat *t;
+	int e;
+
+	if (mat->n_col >= mat->n_row)
+		e = 0;
+	else
+		e = mat->n_row - mat->n_col;
+	if (has_div)
+		for (i = 0; i < n; ++i)
+			isl_int_mul(q[i][0], q[i][0], mat->row[0][0]);
+	t = isl_mat_sub_alloc6(mat->ctx, q, 0, n, has_div, mat->n_row);
+	t = isl_mat_product(t, mat);
+	if (!t)
+		return -1;
+	for (i = 0; i < n; ++i) {
+		isl_seq_swp_or_cpy(q[i] + has_div, t->row[i], t->n_col);
+		isl_seq_cpy(q[i] + has_div + t->n_col,
+			    q[i] + has_div + t->n_col + e, n_div);
+		isl_seq_clr(q[i] + has_div + t->n_col + n_div, e);
+	}
+	isl_mat_free(t);
+	return 0;
+}
+
+/* Replace the variables x in bset by x' given by x = M x', with
+ * M the matrix mat.
+ *
+ * If there are fewer variables x' then there are x, then we perform
+ * the transformation in place, which means that, in principle,
+ * this frees up some extra variables as the number
+ * of columns remains constant, but we would have to extend
+ * the div array too as the number of rows in this array is assumed
+ * to be equal to extra.
+ */
+__isl_give isl_basic_set *isl_basic_set_preimage(
+	__isl_take isl_basic_set *bset, __isl_take isl_mat *mat)
+{
+	struct isl_ctx *ctx;
+
+	if (!bset || !mat)
+		goto error;
+
+	ctx = bset->ctx;
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		goto error;
+
+	isl_assert(ctx, bset->dim->nparam == 0, goto error);
+	isl_assert(ctx, 1+bset->dim->n_out == mat->n_row, goto error);
+	isl_assert(ctx, mat->n_col > 0, goto error);
+
+	if (mat->n_col > mat->n_row) {
+		bset = isl_basic_set_extend(bset, 0, mat->n_col-1, 0, 0, 0);
+		if (!bset)
+			goto error;
+	} else if (mat->n_col < mat->n_row) {
+		bset->dim = isl_space_cow(bset->dim);
+		if (!bset->dim)
+			goto error;
+		bset->dim->n_out -= mat->n_row - mat->n_col;
+	}
+
+	if (preimage(ctx, bset->eq, bset->n_eq, bset->n_div, 0,
+			isl_mat_copy(mat)) < 0)
+		goto error;
+
+	if (preimage(ctx, bset->ineq, bset->n_ineq, bset->n_div, 0,
+			isl_mat_copy(mat)) < 0)
+		goto error;
+
+	if (preimage(ctx, bset->div, bset->n_div, bset->n_div, 1, mat) < 0)
+		goto error2;
+
+	ISL_F_CLR(bset, ISL_BASIC_SET_NO_IMPLICIT);
+	ISL_F_CLR(bset, ISL_BASIC_SET_NO_REDUNDANT);
+	ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED);
+	ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED_DIVS);
+	ISL_F_CLR(bset, ISL_BASIC_SET_ALL_EQUALITIES);
+
+	bset = isl_basic_set_simplify(bset);
+	bset = isl_basic_set_finalize(bset);
+
+	return bset;
+error:
+	isl_mat_free(mat);
+error2:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_preimage(
+	__isl_take isl_set *set, __isl_take isl_mat *mat)
+{
+	int i;
+
+	set = isl_set_cow(set);
+	if (!set)
+		goto error;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_preimage(set->p[i],
+						    isl_mat_copy(mat));
+		if (!set->p[i])
+			goto error;
+	}
+	if (mat->n_col != mat->n_row) {
+		set->dim = isl_space_cow(set->dim);
+		if (!set->dim)
+			goto error;
+		set->dim->n_out += mat->n_col;
+		set->dim->n_out -= mat->n_row;
+	}
+	isl_mat_free(mat);
+	ISL_F_CLR(set, ISL_SET_NORMALIZED);
+	return set;
+error:
+	isl_set_free(set);
+	isl_mat_free(mat);
+	return NULL;
+}
+
+/* Replace the variables x starting at "first_col" in the rows "rows"
+ * of some coefficient matrix by x' with x = M x' with M the matrix mat.
+ * That is, replace the corresponding coefficients c by c M.
+ */
+isl_stat isl_mat_sub_transform(isl_int **row, unsigned n_row,
+	unsigned first_col, __isl_take isl_mat *mat)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_mat *t;
+
+	if (!mat)
+		return isl_stat_error;
+	ctx = isl_mat_get_ctx(mat);
+	t = isl_mat_sub_alloc6(ctx, row, 0, n_row, first_col, mat->n_row);
+	t = isl_mat_product(t, mat);
+	if (!t)
+		return isl_stat_error;
+	for (i = 0; i < n_row; ++i)
+		isl_seq_swp_or_cpy(row[i] + first_col, t->row[i], t->n_col);
+	isl_mat_free(t);
+	return isl_stat_ok;
+}
+
+void isl_mat_print_internal(__isl_keep isl_mat *mat, FILE *out, int indent)
+{
+	int i, j;
+
+	if (!mat) {
+		fprintf(out, "%*snull mat\n", indent, "");
+		return;
+	}
+
+	if (mat->n_row == 0)
+		fprintf(out, "%*s[]\n", indent, "");
+
+	for (i = 0; i < mat->n_row; ++i) {
+		if (!i)
+			fprintf(out, "%*s[[", indent, "");
+		else
+			fprintf(out, "%*s[", indent+1, "");
+		for (j = 0; j < mat->n_col; ++j) {
+			if (j)
+			    fprintf(out, ",");
+			isl_int_print(out, mat->row[i][j], 0);
+		}
+		if (i == mat->n_row-1)
+			fprintf(out, "]]\n");
+		else
+			fprintf(out, "]\n");
+	}
+}
+
+void isl_mat_dump(__isl_keep isl_mat *mat)
+{
+	isl_mat_print_internal(mat, stderr, 0);
+}
+
+__isl_give isl_mat *isl_mat_drop_cols(__isl_take isl_mat *mat,
+	unsigned col, unsigned n)
+{
+	int r;
+
+	if (n == 0)
+		return mat;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	if (col != mat->n_col-n) {
+		for (r = 0; r < mat->n_row; ++r)
+			isl_seq_cpy(mat->row[r]+col, mat->row[r]+col+n,
+					mat->n_col - col - n);
+	}
+	mat->n_col -= n;
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_drop_rows(__isl_take isl_mat *mat,
+	unsigned row, unsigned n)
+{
+	int r;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	for (r = row; r+n < mat->n_row; ++r)
+		mat->row[r] = mat->row[r+n];
+
+	mat->n_row -= n;
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_insert_cols(__isl_take isl_mat *mat,
+				unsigned col, unsigned n)
+{
+	isl_mat *ext;
+
+	if (!mat)
+		return NULL;
+	if (n == 0)
+		return mat;
+
+	ext = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col + n);
+	if (!ext)
+		goto error;
+
+	isl_mat_sub_copy(mat->ctx, ext->row, mat->row, mat->n_row, 0, 0, col);
+	isl_mat_sub_copy(mat->ctx, ext->row, mat->row, mat->n_row,
+				col + n, col, mat->n_col - col);
+
+	isl_mat_free(mat);
+	return ext;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_insert_zero_cols(__isl_take isl_mat *mat,
+	unsigned first, unsigned n)
+{
+	int i;
+
+	if (!mat)
+		return NULL;
+	mat = isl_mat_insert_cols(mat, first, n);
+	if (!mat)
+		return NULL;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_seq_clr(mat->row[i] + first, n);
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_add_zero_cols(__isl_take isl_mat *mat, unsigned n)
+{
+	if (!mat)
+		return NULL;
+
+	return isl_mat_insert_zero_cols(mat, mat->n_col, n);
+}
+
+__isl_give isl_mat *isl_mat_insert_rows(__isl_take isl_mat *mat,
+				unsigned row, unsigned n)
+{
+	isl_mat *ext;
+
+	if (!mat)
+		return NULL;
+	if (n == 0)
+		return mat;
+
+	ext = isl_mat_alloc(mat->ctx, mat->n_row + n, mat->n_col);
+	if (!ext)
+		goto error;
+
+	isl_mat_sub_copy(mat->ctx, ext->row, mat->row, row, 0, 0, mat->n_col);
+	isl_mat_sub_copy(mat->ctx, ext->row + row + n, mat->row + row,
+				mat->n_row - row, 0, 0, mat->n_col);
+
+	isl_mat_free(mat);
+	return ext;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_add_rows(__isl_take isl_mat *mat, unsigned n)
+{
+	if (!mat)
+		return NULL;
+
+	return isl_mat_insert_rows(mat, mat->n_row, n);
+}
+
+__isl_give isl_mat *isl_mat_insert_zero_rows(__isl_take isl_mat *mat,
+	unsigned row, unsigned n)
+{
+	int i;
+
+	mat = isl_mat_insert_rows(mat, row, n);
+	if (!mat)
+		return NULL;
+	
+	for (i = 0; i < n; ++i)
+		isl_seq_clr(mat->row[row + i], mat->n_col);
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_add_zero_rows(__isl_take isl_mat *mat, unsigned n)
+{
+	if (!mat)
+		return NULL;
+
+	return isl_mat_insert_zero_rows(mat, mat->n_row, n);
+}
+
+void isl_mat_col_submul(struct isl_mat *mat,
+			int dst_col, isl_int f, int src_col)
+{
+	int i;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_int_submul(mat->row[i][dst_col], f, mat->row[i][src_col]);
+}
+
+void isl_mat_col_add(__isl_keep isl_mat *mat, int dst_col, int src_col)
+{
+	int i;
+
+	if (!mat)
+		return;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_int_add(mat->row[i][dst_col],
+			    mat->row[i][dst_col], mat->row[i][src_col]);
+}
+
+void isl_mat_col_mul(struct isl_mat *mat, int dst_col, isl_int f, int src_col)
+{
+	int i;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_int_mul(mat->row[i][dst_col], f, mat->row[i][src_col]);
+}
+
+/* Add "f" times column "src_col" to column "dst_col" of "mat" and
+ * return the result.
+ */
+__isl_give isl_mat *isl_mat_col_addmul(__isl_take isl_mat *mat, int dst_col,
+	isl_int f, int src_col)
+{
+	int i;
+
+	if (check_col(mat, dst_col) < 0 || check_col(mat, src_col) < 0)
+		return isl_mat_free(mat);
+
+	for (i = 0; i < mat->n_row; ++i) {
+		if (isl_int_is_zero(mat->row[i][src_col]))
+			continue;
+		mat = isl_mat_cow(mat);
+		if (!mat)
+			return NULL;
+		isl_int_addmul(mat->row[i][dst_col], f, mat->row[i][src_col]);
+	}
+
+	return mat;
+}
+
+/* Negate column "col" of "mat" and return the result.
+ */
+__isl_give isl_mat *isl_mat_col_neg(__isl_take isl_mat *mat, int col)
+{
+	int i;
+
+	if (check_col(mat, col) < 0)
+		return isl_mat_free(mat);
+
+	for (i = 0; i < mat->n_row; ++i) {
+		if (isl_int_is_zero(mat->row[i][col]))
+			continue;
+		mat = isl_mat_cow(mat);
+		if (!mat)
+			return NULL;
+		isl_int_neg(mat->row[i][col], mat->row[i][col]);
+	}
+
+	return mat;
+}
+
+/* Negate row "row" of "mat" and return the result.
+ */
+__isl_give isl_mat *isl_mat_row_neg(__isl_take isl_mat *mat, int row)
+{
+	if (check_row(mat, row) < 0)
+		return isl_mat_free(mat);
+	if (isl_seq_first_non_zero(mat->row[row], mat->n_col) == -1)
+		return mat;
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+	isl_seq_neg(mat->row[row], mat->row[row], mat->n_col);
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_unimodular_complete(__isl_take isl_mat *M, int row)
+{
+	int r;
+	struct isl_mat *H = NULL, *Q = NULL;
+
+	if (!M)
+		return NULL;
+
+	isl_assert(M->ctx, M->n_row == M->n_col, goto error);
+	M->n_row = row;
+	H = isl_mat_left_hermite(isl_mat_copy(M), 0, NULL, &Q);
+	M->n_row = M->n_col;
+	if (!H)
+		goto error;
+	for (r = 0; r < row; ++r)
+		isl_assert(M->ctx, isl_int_is_one(H->row[r][r]), goto error);
+	for (r = row; r < M->n_row; ++r)
+		isl_seq_cpy(M->row[r], Q->row[r], M->n_col);
+	isl_mat_free(H);
+	isl_mat_free(Q);
+	return M;
+error:
+	isl_mat_free(H);
+	isl_mat_free(Q);
+	isl_mat_free(M);
+	return NULL;
+}
+
+__isl_give isl_mat *isl_mat_concat(__isl_take isl_mat *top,
+	__isl_take isl_mat *bot)
+{
+	struct isl_mat *mat;
+
+	if (!top || !bot)
+		goto error;
+
+	isl_assert(top->ctx, top->n_col == bot->n_col, goto error);
+	if (top->n_row == 0) {
+		isl_mat_free(top);
+		return bot;
+	}
+	if (bot->n_row == 0) {
+		isl_mat_free(bot);
+		return top;
+	}
+
+	mat = isl_mat_alloc(top->ctx, top->n_row + bot->n_row, top->n_col);
+	if (!mat)
+		goto error;
+	isl_mat_sub_copy(mat->ctx, mat->row, top->row, top->n_row,
+			 0, 0, mat->n_col);
+	isl_mat_sub_copy(mat->ctx, mat->row + top->n_row, bot->row, bot->n_row,
+			 0, 0, mat->n_col);
+	isl_mat_free(top);
+	isl_mat_free(bot);
+	return mat;
+error:
+	isl_mat_free(top);
+	isl_mat_free(bot);
+	return NULL;
+}
+
+isl_bool isl_mat_is_equal(__isl_keep isl_mat *mat1, __isl_keep isl_mat *mat2)
+{
+	int i;
+
+	if (!mat1 || !mat2)
+		return isl_bool_error;
+
+	if (mat1->n_row != mat2->n_row)
+		return isl_bool_false;
+
+	if (mat1->n_col != mat2->n_col)
+		return isl_bool_false;
+
+	for (i = 0; i < mat1->n_row; ++i)
+		if (!isl_seq_eq(mat1->row[i], mat2->row[i], mat1->n_col))
+			return isl_bool_false;
+
+	return isl_bool_true;
+}
+
+__isl_give isl_mat *isl_mat_from_row_vec(__isl_take isl_vec *vec)
+{
+	struct isl_mat *mat;
+
+	if (!vec)
+		return NULL;
+	mat = isl_mat_alloc(vec->ctx, 1, vec->size);
+	if (!mat)
+		goto error;
+
+	isl_seq_cpy(mat->row[0], vec->el, vec->size);
+
+	isl_vec_free(vec);
+	return mat;
+error:
+	isl_vec_free(vec);
+	return NULL;
+}
+
+/* Return a copy of row "row" of "mat" as an isl_vec.
+ */
+__isl_give isl_vec *isl_mat_get_row(__isl_keep isl_mat *mat, unsigned row)
+{
+	isl_vec *v;
+
+	if (!mat)
+		return NULL;
+	if (row >= mat->n_row)
+		isl_die(mat->ctx, isl_error_invalid, "row out of range",
+			return NULL);
+
+	v = isl_vec_alloc(isl_mat_get_ctx(mat), mat->n_col);
+	if (!v)
+		return NULL;
+	isl_seq_cpy(v->el, mat->row[row], mat->n_col);
+
+	return v;
+}
+
+__isl_give isl_mat *isl_mat_vec_concat(__isl_take isl_mat *top,
+	__isl_take isl_vec *bot)
+{
+	return isl_mat_concat(top, isl_mat_from_row_vec(bot));
+}
+
+__isl_give isl_mat *isl_mat_move_cols(__isl_take isl_mat *mat,
+	unsigned dst_col, unsigned src_col, unsigned n)
+{
+	isl_mat *res;
+
+	if (!mat)
+		return NULL;
+	if (n == 0 || dst_col == src_col)
+		return mat;
+
+	res = isl_mat_alloc(mat->ctx, mat->n_row, mat->n_col);
+	if (!res)
+		goto error;
+
+	if (dst_col < src_col) {
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 0, 0, dst_col);
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 dst_col, src_col, n);
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 dst_col + n, dst_col, src_col - dst_col);
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 src_col + n, src_col + n,
+				 res->n_col - src_col - n);
+	} else {
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 0, 0, src_col);
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 src_col, src_col + n, dst_col - src_col);
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 dst_col, src_col, n);
+		isl_mat_sub_copy(res->ctx, res->row, mat->row, mat->n_row,
+				 dst_col + n, dst_col + n,
+				 res->n_col - dst_col - n);
+	}
+	isl_mat_free(mat);
+
+	return res;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+/* Return the gcd of the elements in row "row" of "mat" in *gcd.
+ * Return isl_stat_ok on success and isl_stat_error on failure.
+ */
+isl_stat isl_mat_row_gcd(__isl_keep isl_mat *mat, int row, isl_int *gcd)
+{
+	if (check_row(mat, row) < 0)
+		return isl_stat_error;
+
+	isl_seq_gcd(mat->row[row], mat->n_col, gcd);
+
+	return isl_stat_ok;
+}
+
+void isl_mat_gcd(__isl_keep isl_mat *mat, isl_int *gcd)
+{
+	int i;
+	isl_int g;
+
+	isl_int_set_si(*gcd, 0);
+	if (!mat)
+		return;
+
+	isl_int_init(g);
+	for (i = 0; i < mat->n_row; ++i) {
+		isl_seq_gcd(mat->row[i], mat->n_col, &g);
+		isl_int_gcd(*gcd, *gcd, g);
+	}
+	isl_int_clear(g);
+}
+
+/* Return the result of scaling "mat" by a factor of "m".
+ */
+__isl_give isl_mat *isl_mat_scale(__isl_take isl_mat *mat, isl_int m)
+{
+	int i;
+
+	if (isl_int_is_one(m))
+		return mat;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_seq_scale(mat->row[i], mat->row[i], m, mat->n_col);
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_scale_down(__isl_take isl_mat *mat, isl_int m)
+{
+	int i;
+
+	if (isl_int_is_one(m))
+		return mat;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	for (i = 0; i < mat->n_row; ++i)
+		isl_seq_scale_down(mat->row[i], mat->row[i], m, mat->n_col);
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_scale_down_row(__isl_take isl_mat *mat, int row,
+	isl_int m)
+{
+	if (isl_int_is_one(m))
+		return mat;
+
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	isl_seq_scale_down(mat->row[row], mat->row[row], m, mat->n_col);
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_normalize(__isl_take isl_mat *mat)
+{
+	isl_int gcd;
+
+	if (!mat)
+		return NULL;
+
+	isl_int_init(gcd);
+	isl_mat_gcd(mat, &gcd);
+	mat = isl_mat_scale_down(mat, gcd);
+	isl_int_clear(gcd);
+
+	return mat;
+}
+
+__isl_give isl_mat *isl_mat_normalize_row(__isl_take isl_mat *mat, int row)
+{
+	mat = isl_mat_cow(mat);
+	if (!mat)
+		return NULL;
+
+	isl_seq_normalize(mat->ctx, mat->row[row], mat->n_col);
+
+	return mat;
+}
+
+/* Number of initial non-zero columns.
+ */
+int isl_mat_initial_non_zero_cols(__isl_keep isl_mat *mat)
+{
+	int i;
+
+	if (!mat)
+		return -1;
+
+	for (i = 0; i < mat->n_col; ++i)
+		if (row_first_non_zero(mat->row, mat->n_row, i) < 0)
+			break;
+
+	return i;
+}
diff --git a/final/lib/External/isl/isl_mat_private.h b/final/lib/External/isl/isl_mat_private.h
new file mode 100644
index 0000000..7733d81
--- /dev/null
+++ b/final/lib/External/isl/isl_mat_private.h
@@ -0,0 +1,62 @@
+#include <isl/mat.h>
+#include <isl_blk.h>
+
+struct isl_mat {
+	int ref;
+
+	struct isl_ctx *ctx;
+
+#define ISL_MAT_BORROWED		(1 << 0)
+	unsigned flags;
+
+	unsigned n_row;
+	unsigned n_col;
+
+	isl_int **row;
+
+	/* actual size of the rows in memory; n_col <= max_col */
+	unsigned max_col;
+
+	struct isl_blk block;
+};
+
+uint32_t isl_mat_get_hash(__isl_keep isl_mat *mat);
+
+__isl_give isl_mat *isl_mat_zero(isl_ctx *ctx, unsigned n_row, unsigned n_col);
+__isl_give isl_mat *isl_mat_sub_alloc(__isl_keep isl_mat *mat,
+	unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col);
+__isl_give isl_mat *isl_mat_sub_alloc6(isl_ctx *ctx, isl_int **row,
+	unsigned first_row, unsigned n_row, unsigned first_col, unsigned n_col);
+void isl_mat_sub_copy(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+	unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col);
+void isl_mat_sub_neg(struct isl_ctx *ctx, isl_int **dst, isl_int **src,
+	unsigned n_row, unsigned dst_col, unsigned src_col, unsigned n_col);
+isl_stat isl_mat_sub_transform(isl_int **row, unsigned n_row,
+	unsigned first_col, __isl_take isl_mat *mat);
+__isl_give isl_mat *isl_mat_diag(isl_ctx *ctx, unsigned n_row, isl_int d);
+
+__isl_give isl_mat *isl_mat_reverse_gauss(__isl_take isl_mat *mat);
+
+__isl_give isl_mat *isl_mat_scale(__isl_take isl_mat *mat, isl_int m);
+__isl_give isl_mat *isl_mat_scale_down_row(__isl_take isl_mat *mat, int row,
+	isl_int m);
+
+__isl_give isl_vec *isl_mat_get_row(__isl_keep isl_mat *mat, unsigned row);
+
+__isl_give isl_mat *isl_mat_lexnonneg_rows(__isl_take isl_mat *mat);
+
+int isl_mat_is_scaled_identity(__isl_keep isl_mat *mat);
+
+isl_stat isl_mat_row_gcd(__isl_keep isl_mat *mat, int row, isl_int *gcd);
+
+void isl_mat_col_mul(struct isl_mat *mat, int dst_col, isl_int f, int src_col);
+void isl_mat_col_submul(struct isl_mat *mat,
+			int dst_col, isl_int f, int src_col);
+__isl_give isl_mat *isl_mat_col_addmul(__isl_take isl_mat *mat, int dst_col,
+	isl_int f, int src_col);
+__isl_give isl_mat *isl_mat_col_neg(__isl_take isl_mat *mat, int col);
+__isl_give isl_mat *isl_mat_row_neg(__isl_take isl_mat *mat, int row);
+
+int isl_mat_get_element(__isl_keep isl_mat *mat, int row, int col, isl_int *v);
+__isl_give isl_mat *isl_mat_set_element(__isl_take isl_mat *mat,
+	int row, int col, isl_int v);
diff --git a/final/lib/External/isl/isl_maybe_map.h b/final/lib/External/isl/isl_maybe_map.h
new file mode 100644
index 0000000..460a89e
--- /dev/null
+++ b/final/lib/External/isl/isl_maybe_map.h
@@ -0,0 +1,10 @@
+#ifndef ISL_MAYBE_MAP_H
+#define ISL_MAYBE_MAP_H
+
+#include <isl/map_type.h>
+
+#define ISL_TYPE	isl_map
+#include <isl/maybe_templ.h>
+#undef ISL_TYPE
+
+#endif
diff --git a/final/lib/External/isl/isl_morph.c b/final/lib/External/isl/isl_morph.c
new file mode 100644
index 0000000..9b615f1
--- /dev/null
+++ b/final/lib/External/isl/isl_morph.c
@@ -0,0 +1,836 @@
+/*
+ * Copyright 2010-2011 INRIA Saclay
+ * Copyright 2014      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_map_private.h>
+#include <isl_aff_private.h>
+#include <isl_morph.h>
+#include <isl_seq.h>
+#include <isl_mat_private.h>
+#include <isl_space_private.h>
+#include <isl_equalities.h>
+#include <isl_id_private.h>
+
+isl_ctx *isl_morph_get_ctx(__isl_keep isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+	return isl_basic_set_get_ctx(morph->dom);
+}
+
+__isl_give isl_morph *isl_morph_alloc(
+	__isl_take isl_basic_set *dom, __isl_take isl_basic_set *ran,
+	__isl_take isl_mat *map, __isl_take isl_mat *inv)
+{
+	isl_morph *morph;
+
+	if (!dom || !ran || !map || !inv)
+		goto error;
+
+	morph = isl_alloc_type(dom->ctx, struct isl_morph);
+	if (!morph)
+		goto error;
+
+	morph->ref = 1;
+	morph->dom = dom;
+	morph->ran = ran;
+	morph->map = map;
+	morph->inv = inv;
+
+	return morph;
+error:
+	isl_basic_set_free(dom);
+	isl_basic_set_free(ran);
+	isl_mat_free(map);
+	isl_mat_free(inv);
+	return NULL;
+}
+
+__isl_give isl_morph *isl_morph_copy(__isl_keep isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+
+	morph->ref++;
+	return morph;
+}
+
+__isl_give isl_morph *isl_morph_dup(__isl_keep isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+
+	return isl_morph_alloc(isl_basic_set_copy(morph->dom),
+		isl_basic_set_copy(morph->ran),
+		isl_mat_copy(morph->map), isl_mat_copy(morph->inv));
+}
+
+__isl_give isl_morph *isl_morph_cow(__isl_take isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+
+	if (morph->ref == 1)
+		return morph;
+	morph->ref--;
+	return isl_morph_dup(morph);
+}
+
+__isl_null isl_morph *isl_morph_free(__isl_take isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+
+	if (--morph->ref > 0)
+		return NULL;
+
+	isl_basic_set_free(morph->dom);
+	isl_basic_set_free(morph->ran);
+	isl_mat_free(morph->map);
+	isl_mat_free(morph->inv);
+	free(morph);
+
+	return NULL;
+}
+
+/* Is "morph" an identity on the parameters?
+ */
+static int identity_on_parameters(__isl_keep isl_morph *morph)
+{
+	int is_identity;
+	unsigned nparam;
+	isl_mat *sub;
+
+	nparam = isl_morph_dom_dim(morph, isl_dim_param);
+	if (nparam != isl_morph_ran_dim(morph, isl_dim_param))
+		return 0;
+	if (nparam == 0)
+		return 1;
+	sub = isl_mat_sub_alloc(morph->map, 0, 1 + nparam, 0, 1 + nparam);
+	is_identity = isl_mat_is_scaled_identity(sub);
+	isl_mat_free(sub);
+
+	return is_identity;
+}
+
+/* Return an affine expression of the variables of the range of "morph"
+ * in terms of the parameters and the variables of the domain on "morph".
+ *
+ * In order for the space manipulations to make sense, we require
+ * that the parameters are not modified by "morph".
+ */
+__isl_give isl_multi_aff *isl_morph_get_var_multi_aff(
+	__isl_keep isl_morph *morph)
+{
+	isl_space *dom, *ran, *space;
+	isl_local_space *ls;
+	isl_multi_aff *ma;
+	unsigned nparam, nvar;
+	int i;
+	int is_identity;
+
+	if (!morph)
+		return NULL;
+
+	is_identity = identity_on_parameters(morph);
+	if (is_identity < 0)
+		return NULL;
+	if (!is_identity)
+		isl_die(isl_morph_get_ctx(morph), isl_error_invalid,
+			"cannot handle parameter compression", return NULL);
+
+	dom = isl_morph_get_dom_space(morph);
+	ls = isl_local_space_from_space(isl_space_copy(dom));
+	ran = isl_morph_get_ran_space(morph);
+	space = isl_space_map_from_domain_and_range(dom, ran);
+	ma = isl_multi_aff_zero(space);
+
+	nparam = isl_multi_aff_dim(ma, isl_dim_param);
+	nvar = isl_multi_aff_dim(ma, isl_dim_out);
+	for (i = 0; i < nvar; ++i) {
+		isl_val *val;
+		isl_vec *v;
+		isl_aff *aff;
+
+		v = isl_mat_get_row(morph->map, 1 + nparam + i);
+		v = isl_vec_insert_els(v, 0, 1);
+		val = isl_mat_get_element_val(morph->map, 0, 0);
+		v = isl_vec_set_element_val(v, 0, val);
+		aff = isl_aff_alloc_vec(isl_local_space_copy(ls), v);
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+
+	isl_local_space_free(ls);
+	return ma;
+}
+
+/* Return the domain space of "morph".
+ */
+__isl_give isl_space *isl_morph_get_dom_space(__isl_keep isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+
+	return isl_basic_set_get_space(morph->dom);
+}
+
+__isl_give isl_space *isl_morph_get_ran_space(__isl_keep isl_morph *morph)
+{
+	if (!morph)
+		return NULL;
+	
+	return isl_space_copy(morph->ran->dim);
+}
+
+unsigned isl_morph_dom_dim(__isl_keep isl_morph *morph, enum isl_dim_type type)
+{
+	if (!morph)
+		return 0;
+
+	return isl_basic_set_dim(morph->dom, type);
+}
+
+unsigned isl_morph_ran_dim(__isl_keep isl_morph *morph, enum isl_dim_type type)
+{
+	if (!morph)
+		return 0;
+
+	return isl_basic_set_dim(morph->ran, type);
+}
+
+__isl_give isl_morph *isl_morph_remove_dom_dims(__isl_take isl_morph *morph,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	unsigned dom_offset;
+
+	if (n == 0)
+		return morph;
+
+	morph = isl_morph_cow(morph);
+	if (!morph)
+		return NULL;
+
+	dom_offset = 1 + isl_space_offset(morph->dom->dim, type);
+
+	morph->dom = isl_basic_set_remove_dims(morph->dom, type, first, n);
+
+	morph->map = isl_mat_drop_cols(morph->map, dom_offset + first, n);
+
+	morph->inv = isl_mat_drop_rows(morph->inv, dom_offset + first, n);
+
+	if (morph->dom && morph->ran && morph->map && morph->inv)
+		return morph;
+
+	isl_morph_free(morph);
+	return NULL;
+}
+
+__isl_give isl_morph *isl_morph_remove_ran_dims(__isl_take isl_morph *morph,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	unsigned ran_offset;
+
+	if (n == 0)
+		return morph;
+
+	morph = isl_morph_cow(morph);
+	if (!morph)
+		return NULL;
+
+	ran_offset = 1 + isl_space_offset(morph->ran->dim, type);
+
+	morph->ran = isl_basic_set_remove_dims(morph->ran, type, first, n);
+
+	morph->map = isl_mat_drop_rows(morph->map, ran_offset + first, n);
+
+	morph->inv = isl_mat_drop_cols(morph->inv, ran_offset + first, n);
+
+	if (morph->dom && morph->ran && morph->map && morph->inv)
+		return morph;
+
+	isl_morph_free(morph);
+	return NULL;
+}
+
+/* Project domain of morph onto its parameter domain.
+ */
+__isl_give isl_morph *isl_morph_dom_params(__isl_take isl_morph *morph)
+{
+	unsigned n;
+
+	morph = isl_morph_cow(morph);
+	if (!morph)
+		return NULL;
+	n = isl_basic_set_dim(morph->dom, isl_dim_set);
+	morph = isl_morph_remove_dom_dims(morph, isl_dim_set, 0, n);
+	if (!morph)
+		return NULL;
+	morph->dom = isl_basic_set_params(morph->dom);
+	if (morph->dom)
+		return morph;
+
+	isl_morph_free(morph);
+	return NULL;
+}
+
+/* Project range of morph onto its parameter domain.
+ */
+__isl_give isl_morph *isl_morph_ran_params(__isl_take isl_morph *morph)
+{
+	unsigned n;
+
+	morph = isl_morph_cow(morph);
+	if (!morph)
+		return NULL;
+	n = isl_basic_set_dim(morph->ran, isl_dim_set);
+	morph = isl_morph_remove_ran_dims(morph, isl_dim_set, 0, n);
+	if (!morph)
+		return NULL;
+	morph->ran = isl_basic_set_params(morph->ran);
+	if (morph->ran)
+		return morph;
+
+	isl_morph_free(morph);
+	return NULL;
+}
+
+void isl_morph_print_internal(__isl_take isl_morph *morph, FILE *out)
+{
+	if (!morph)
+		return;
+
+	isl_basic_set_dump(morph->dom);
+	isl_basic_set_dump(morph->ran);
+	isl_mat_print_internal(morph->map, out, 4);
+	isl_mat_print_internal(morph->inv, out, 4);
+}
+
+void isl_morph_dump(__isl_take isl_morph *morph)
+{
+	isl_morph_print_internal(morph, stderr);
+}
+
+__isl_give isl_morph *isl_morph_identity(__isl_keep isl_basic_set *bset)
+{
+	isl_mat *id;
+	isl_basic_set *universe;
+	unsigned total;
+
+	if (!bset)
+		return NULL;
+
+	total = isl_basic_set_total_dim(bset);
+	id = isl_mat_identity(bset->ctx, 1 + total);
+	universe = isl_basic_set_universe(isl_space_copy(bset->dim));
+
+	return isl_morph_alloc(universe, isl_basic_set_copy(universe),
+		id, isl_mat_copy(id));
+}
+
+/* Create a(n identity) morphism between empty sets of the same dimension
+ * a "bset".
+ */
+__isl_give isl_morph *isl_morph_empty(__isl_keep isl_basic_set *bset)
+{
+	isl_mat *id;
+	isl_basic_set *empty;
+	unsigned total;
+
+	if (!bset)
+		return NULL;
+
+	total = isl_basic_set_total_dim(bset);
+	id = isl_mat_identity(bset->ctx, 1 + total);
+	empty = isl_basic_set_empty(isl_space_copy(bset->dim));
+
+	return isl_morph_alloc(empty, isl_basic_set_copy(empty),
+		id, isl_mat_copy(id));
+}
+
+/* Construct a basic set described by the "n" equalities of "bset" starting
+ * at "first".
+ */
+static __isl_give isl_basic_set *copy_equalities(__isl_keep isl_basic_set *bset,
+	unsigned first, unsigned n)
+{
+	int i, k;
+	isl_basic_set *eq;
+	unsigned total;
+
+	isl_assert(bset->ctx, bset->n_div == 0, return NULL);
+
+	total = isl_basic_set_total_dim(bset);
+	eq = isl_basic_set_alloc_space(isl_space_copy(bset->dim), 0, n, 0);
+	if (!eq)
+		return NULL;
+	for (i = 0; i < n; ++i) {
+		k = isl_basic_set_alloc_equality(eq);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(eq->eq[k], bset->eq[first + i], 1 + total);
+	}
+
+	return eq;
+error:
+	isl_basic_set_free(eq);
+	return NULL;
+}
+
+/* Given a basic set, exploit the equalities in the basic set to construct
+ * a morphism that maps the basic set to a lower-dimensional space
+ * with identifier "id".
+ * Specifically, the morphism reduces the number of dimensions of type "type".
+ *
+ * We first select the equalities of interest, that is those that involve
+ * variables of type "type" and no later variables.
+ * Denote those equalities as
+ *
+ *		-C(p) + M x = 0
+ *
+ * where C(p) depends on the parameters if type == isl_dim_set and
+ * is a constant if type == isl_dim_param.
+ *
+ * Use isl_mat_final_variable_compression to construct a compression
+ *
+ *	x = T x'
+ *
+ *	x' = Q x
+ *
+ * If T is a zero-column matrix, then the set of equality constraints
+ * do not admit a solution.  In this case, an empty morphism is returned.
+ *
+ * Both matrices are extended to map the full original space to the full
+ * compressed space.
+ */
+__isl_give isl_morph *isl_basic_set_variable_compression_with_id(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type type,
+	__isl_keep isl_id *id)
+{
+	unsigned otype;
+	unsigned ntype;
+	unsigned orest;
+	unsigned nrest;
+	int f_eq, n_eq;
+	isl_space *space;
+	isl_mat *E, *Q, *C;
+	isl_basic_set *dom, *ran;
+
+	if (!bset)
+		return NULL;
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return isl_morph_empty(bset);
+
+	isl_assert(bset->ctx, bset->n_div == 0, return NULL);
+
+	otype = 1 + isl_space_offset(bset->dim, type);
+	ntype = isl_basic_set_dim(bset, type);
+	orest = otype + ntype;
+	nrest = isl_basic_set_total_dim(bset) - (orest - 1);
+
+	for (f_eq = 0; f_eq < bset->n_eq; ++f_eq)
+		if (isl_seq_first_non_zero(bset->eq[f_eq] + orest, nrest) == -1)
+			break;
+	for (n_eq = 0; f_eq + n_eq < bset->n_eq; ++n_eq)
+		if (isl_seq_first_non_zero(bset->eq[f_eq + n_eq] + otype, ntype) == -1)
+			break;
+	if (n_eq == 0)
+		return isl_morph_identity(bset);
+
+	E = isl_mat_sub_alloc6(bset->ctx, bset->eq, f_eq, n_eq, 0, orest);
+	C = isl_mat_final_variable_compression(E, otype - 1, &Q);
+	if (!Q)
+		C = isl_mat_free(C);
+	if (C && C->n_col == 0) {
+		isl_mat_free(C);
+		isl_mat_free(Q);
+		return isl_morph_empty(bset);
+	}
+
+	Q = isl_mat_diagonal(Q, isl_mat_identity(bset->ctx, nrest));
+	C = isl_mat_diagonal(C, isl_mat_identity(bset->ctx, nrest));
+
+	space = isl_space_copy(bset->dim);
+	space = isl_space_drop_dims(space, type, 0, ntype);
+	space = isl_space_add_dims(space, type, ntype - n_eq);
+	space = isl_space_set_tuple_id(space, isl_dim_set, isl_id_copy(id));
+	ran = isl_basic_set_universe(space);
+	dom = copy_equalities(bset, f_eq, n_eq);
+
+	return isl_morph_alloc(dom, ran, Q, C);
+}
+
+/* Given a basic set, exploit the equalities in the basic set to construct
+ * a morphism that maps the basic set to a lower-dimensional space.
+ * Specifically, the morphism reduces the number of dimensions of type "type".
+ */
+__isl_give isl_morph *isl_basic_set_variable_compression(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type type)
+{
+	return isl_basic_set_variable_compression_with_id(bset, type,
+							&isl_id_none);
+}
+
+/* Construct a parameter compression for "bset".
+ * We basically just call isl_mat_parameter_compression with the right input
+ * and then extend the resulting matrix to include the variables.
+ *
+ * The implementation assumes that "bset" does not have any equalities
+ * that only involve the parameters and that isl_basic_set_gauss has
+ * been applied to "bset".
+ *
+ * Let the equalities be given as
+ *
+ *	B(p) + A x = 0.
+ *
+ * We use isl_mat_parameter_compression_ext to compute the compression
+ *
+ *	p = T p'.
+ */
+__isl_give isl_morph *isl_basic_set_parameter_compression(
+	__isl_keep isl_basic_set *bset)
+{
+	unsigned nparam;
+	unsigned nvar;
+	unsigned n_div;
+	int n_eq;
+	isl_mat *H, *B;
+	isl_mat *map, *inv;
+	isl_basic_set *dom, *ran;
+
+	if (!bset)
+		return NULL;
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return isl_morph_empty(bset);
+	if (bset->n_eq == 0)
+		return isl_morph_identity(bset);
+
+	n_eq = bset->n_eq;
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+	n_div = isl_basic_set_dim(bset, isl_dim_div);
+
+	if (isl_seq_first_non_zero(bset->eq[bset->n_eq - 1] + 1 + nparam,
+				    nvar + n_div) == -1)
+		isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid,
+			"input not allowed to have parameter equalities",
+			return NULL);
+	if (n_eq > nvar + n_div)
+		isl_die(isl_basic_set_get_ctx(bset), isl_error_invalid,
+			"input not gaussed", return NULL);
+
+	B = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, n_eq, 0, 1 + nparam);
+	H = isl_mat_sub_alloc6(bset->ctx, bset->eq,
+				0, n_eq, 1 + nparam, nvar + n_div);
+	inv = isl_mat_parameter_compression_ext(B, H);
+	inv = isl_mat_diagonal(inv, isl_mat_identity(bset->ctx, nvar));
+	map = isl_mat_right_inverse(isl_mat_copy(inv));
+
+	dom = isl_basic_set_universe(isl_space_copy(bset->dim));
+	ran = isl_basic_set_universe(isl_space_copy(bset->dim));
+
+	return isl_morph_alloc(dom, ran, map, inv);
+}
+
+/* Add stride constraints to "bset" based on the inverse mapping
+ * that was plugged in.  In particular, if morph maps x' to x,
+ * the the constraints of the original input
+ *
+ *	A x' + b >= 0
+ *
+ * have been rewritten to
+ *
+ *	A inv x + b >= 0
+ *
+ * However, this substitution may loose information on the integrality of x',
+ * so we need to impose that
+ *
+ *	inv x
+ *
+ * is integral.  If inv = B/d, this means that we need to impose that
+ *
+ *	B x = 0		mod d
+ *
+ * or
+ *
+ *	exists alpha in Z^m: B x = d alpha
+ *
+ * This function is similar to add_strides in isl_affine_hull.c
+ */
+static __isl_give isl_basic_set *add_strides(__isl_take isl_basic_set *bset,
+	__isl_keep isl_morph *morph)
+{
+	int i, div, k;
+	isl_int gcd;
+
+	if (isl_int_is_one(morph->inv->row[0][0]))
+		return bset;
+
+	isl_int_init(gcd);
+
+	for (i = 0; 1 + i < morph->inv->n_row; ++i) {
+		isl_seq_gcd(morph->inv->row[1 + i], morph->inv->n_col, &gcd);
+		if (isl_int_is_divisible_by(gcd, morph->inv->row[0][0]))
+			continue;
+		div = isl_basic_set_alloc_div(bset);
+		if (div < 0)
+			goto error;
+		isl_int_set_si(bset->div[div][0], 0);
+		k = isl_basic_set_alloc_equality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bset->eq[k], morph->inv->row[1 + i],
+			    morph->inv->n_col);
+		isl_seq_clr(bset->eq[k] + morph->inv->n_col, bset->n_div);
+		isl_int_set(bset->eq[k][morph->inv->n_col + div],
+			    morph->inv->row[0][0]);
+	}
+
+	isl_int_clear(gcd);
+
+	return bset;
+error:
+	isl_int_clear(gcd);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Apply the morphism to the basic set.
+ * We basically just compute the preimage of "bset" under the inverse mapping
+ * in morph, add in stride constraints and intersect with the range
+ * of the morphism.
+ */
+__isl_give isl_basic_set *isl_morph_basic_set(__isl_take isl_morph *morph,
+	__isl_take isl_basic_set *bset)
+{
+	isl_basic_set *res = NULL;
+	isl_mat *mat = NULL;
+	int i, k;
+	int max_stride;
+
+	if (!morph || !bset)
+		goto error;
+
+	isl_assert(bset->ctx, isl_space_is_equal(bset->dim, morph->dom->dim),
+		    goto error);
+
+	max_stride = morph->inv->n_row - 1;
+	if (isl_int_is_one(morph->inv->row[0][0]))
+		max_stride = 0;
+	res = isl_basic_set_alloc_space(isl_space_copy(morph->ran->dim),
+		bset->n_div + max_stride, bset->n_eq + max_stride, bset->n_ineq);
+
+	for (i = 0; i < bset->n_div; ++i)
+		if (isl_basic_set_alloc_div(res) < 0)
+			goto error;
+
+	mat = isl_mat_sub_alloc6(bset->ctx, bset->eq, 0, bset->n_eq,
+					0, morph->inv->n_row);
+	mat = isl_mat_product(mat, isl_mat_copy(morph->inv));
+	if (!mat)
+		goto error;
+	for (i = 0; i < bset->n_eq; ++i) {
+		k = isl_basic_set_alloc_equality(res);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(res->eq[k], mat->row[i], mat->n_col);
+		isl_seq_scale(res->eq[k] + mat->n_col, bset->eq[i] + mat->n_col,
+				morph->inv->row[0][0], bset->n_div);
+	}
+	isl_mat_free(mat);
+
+	mat = isl_mat_sub_alloc6(bset->ctx, bset->ineq, 0, bset->n_ineq,
+					0, morph->inv->n_row);
+	mat = isl_mat_product(mat, isl_mat_copy(morph->inv));
+	if (!mat)
+		goto error;
+	for (i = 0; i < bset->n_ineq; ++i) {
+		k = isl_basic_set_alloc_inequality(res);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(res->ineq[k], mat->row[i], mat->n_col);
+		isl_seq_scale(res->ineq[k] + mat->n_col,
+				bset->ineq[i] + mat->n_col,
+				morph->inv->row[0][0], bset->n_div);
+	}
+	isl_mat_free(mat);
+
+	mat = isl_mat_sub_alloc6(bset->ctx, bset->div, 0, bset->n_div,
+					1, morph->inv->n_row);
+	mat = isl_mat_product(mat, isl_mat_copy(morph->inv));
+	if (!mat)
+		goto error;
+	for (i = 0; i < bset->n_div; ++i) {
+		isl_int_mul(res->div[i][0],
+				morph->inv->row[0][0], bset->div[i][0]);
+		isl_seq_cpy(res->div[i] + 1, mat->row[i], mat->n_col);
+		isl_seq_scale(res->div[i] + 1 + mat->n_col,
+				bset->div[i] + 1 + mat->n_col,
+				morph->inv->row[0][0], bset->n_div);
+	}
+	isl_mat_free(mat);
+
+	res = add_strides(res, morph);
+
+	if (isl_basic_set_is_rational(bset))
+		res = isl_basic_set_set_rational(res);
+
+	res = isl_basic_set_simplify(res);
+	res = isl_basic_set_finalize(res);
+
+	res = isl_basic_set_intersect(res, isl_basic_set_copy(morph->ran));
+
+	isl_morph_free(morph);
+	isl_basic_set_free(bset);
+	return res;
+error:
+	isl_mat_free(mat);
+	isl_morph_free(morph);
+	isl_basic_set_free(bset);
+	isl_basic_set_free(res);
+	return NULL;
+}
+
+/* Apply the morphism to the set.
+ */
+__isl_give isl_set *isl_morph_set(__isl_take isl_morph *morph,
+	__isl_take isl_set *set)
+{
+	int i;
+
+	if (!morph || !set)
+		goto error;
+
+	isl_assert(set->ctx, isl_space_is_equal(set->dim, morph->dom->dim), goto error);
+
+	set = isl_set_cow(set);
+	if (!set)
+		goto error;
+
+	isl_space_free(set->dim);
+	set->dim = isl_space_copy(morph->ran->dim);
+	if (!set->dim)
+		goto error;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_morph_basic_set(isl_morph_copy(morph), set->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+
+	isl_morph_free(morph);
+
+	ISL_F_CLR(set, ISL_SET_NORMALIZED);
+
+	return set;
+error:
+	isl_set_free(set);
+	isl_morph_free(morph);
+	return NULL;
+}
+
+/* Construct a morphism that first does morph2 and then morph1.
+ */
+__isl_give isl_morph *isl_morph_compose(__isl_take isl_morph *morph1,
+	__isl_take isl_morph *morph2)
+{
+	isl_mat *map, *inv;
+	isl_basic_set *dom, *ran;
+
+	if (!morph1 || !morph2)
+		goto error;
+
+	map = isl_mat_product(isl_mat_copy(morph1->map), isl_mat_copy(morph2->map));
+	inv = isl_mat_product(isl_mat_copy(morph2->inv), isl_mat_copy(morph1->inv));
+	dom = isl_morph_basic_set(isl_morph_inverse(isl_morph_copy(morph2)),
+				  isl_basic_set_copy(morph1->dom));
+	dom = isl_basic_set_intersect(dom, isl_basic_set_copy(morph2->dom));
+	ran = isl_morph_basic_set(isl_morph_copy(morph1),
+				  isl_basic_set_copy(morph2->ran));
+	ran = isl_basic_set_intersect(ran, isl_basic_set_copy(morph1->ran));
+
+	isl_morph_free(morph1);
+	isl_morph_free(morph2);
+
+	return isl_morph_alloc(dom, ran, map, inv);
+error:
+	isl_morph_free(morph1);
+	isl_morph_free(morph2);
+	return NULL;
+}
+
+__isl_give isl_morph *isl_morph_inverse(__isl_take isl_morph *morph)
+{
+	isl_basic_set *bset;
+	isl_mat *mat;
+
+	morph = isl_morph_cow(morph);
+	if (!morph)
+		return NULL;
+
+	bset = morph->dom;
+	morph->dom = morph->ran;
+	morph->ran = bset;
+
+	mat = morph->map;
+	morph->map = morph->inv;
+	morph->inv = mat;
+
+	return morph;
+}
+
+/* We detect all the equalities first to avoid implicit equalities
+ * being discovered during the computations.  In particular,
+ * the compression on the variables could expose additional stride
+ * constraints on the parameters.  This would result in existentially
+ * quantified variables after applying the resulting morph, which
+ * in turn could break invariants of the calling functions.
+ */
+__isl_give isl_morph *isl_basic_set_full_compression(
+	__isl_keep isl_basic_set *bset)
+{
+	isl_morph *morph, *morph2;
+
+	bset = isl_basic_set_copy(bset);
+	bset = isl_basic_set_detect_equalities(bset);
+
+	morph = isl_basic_set_variable_compression(bset, isl_dim_param);
+	bset = isl_morph_basic_set(isl_morph_copy(morph), bset);
+
+	morph2 = isl_basic_set_parameter_compression(bset);
+	bset = isl_morph_basic_set(isl_morph_copy(morph2), bset);
+
+	morph = isl_morph_compose(morph2, morph);
+
+	morph2 = isl_basic_set_variable_compression(bset, isl_dim_set);
+	isl_basic_set_free(bset);
+
+	morph = isl_morph_compose(morph2, morph);
+
+	return morph;
+}
+
+__isl_give isl_vec *isl_morph_vec(__isl_take isl_morph *morph,
+	__isl_take isl_vec *vec)
+{
+	if (!morph)
+		goto error;
+
+	vec = isl_mat_vec_product(isl_mat_copy(morph->map), vec);
+
+	isl_morph_free(morph);
+	return vec;
+error:
+	isl_morph_free(morph);
+	isl_vec_free(vec);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_morph.h b/final/lib/External/isl/isl_morph.h
new file mode 100644
index 0000000..8ded753
--- /dev/null
+++ b/final/lib/External/isl/isl_morph.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France 
+ */
+
+#ifndef ISL_MORHP_H
+#define ISL_MORHP_H
+
+#include <stdio.h>
+#include <isl/space.h>
+#include <isl/mat.h>
+#include <isl/set.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* An isl_morph is a "morphism" on (basic) sets.
+ * "map" is an affine mapping from "dom" to "ran"
+ * and "inv" is the inverse mapping.
+ */
+struct isl_morph {
+	int ref;
+
+	isl_basic_set *dom;
+	isl_basic_set *ran;
+
+	isl_mat *map;
+	isl_mat *inv;
+};
+typedef struct isl_morph isl_morph;
+
+isl_ctx *isl_morph_get_ctx(__isl_keep isl_morph *morph);
+
+__isl_give isl_morph *isl_morph_alloc(
+	__isl_take isl_basic_set *dom, __isl_take isl_basic_set *ran,
+	__isl_take isl_mat *map, __isl_take isl_mat *inv);
+__isl_give isl_morph *isl_morph_copy(__isl_keep isl_morph *morph);
+__isl_give isl_morph *isl_morph_identity(__isl_keep isl_basic_set *bset);
+__isl_null isl_morph *isl_morph_free(__isl_take isl_morph *morph);
+
+__isl_give isl_space *isl_morph_get_dom_space(__isl_keep isl_morph *morph);
+__isl_give isl_space *isl_morph_get_ran_space(__isl_keep isl_morph *morph);
+__isl_give isl_multi_aff *isl_morph_get_var_multi_aff(
+	__isl_keep isl_morph *morph);
+unsigned isl_morph_dom_dim(__isl_keep isl_morph *morph, enum isl_dim_type type);
+unsigned isl_morph_ran_dim(__isl_keep isl_morph *morph, enum isl_dim_type type);
+
+__isl_give isl_morph *isl_morph_remove_dom_dims(__isl_take isl_morph *morph,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_morph *isl_morph_remove_ran_dims(__isl_take isl_morph *morph,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_morph *isl_morph_dom_params(__isl_take isl_morph *morph);
+__isl_give isl_morph *isl_morph_ran_params(__isl_take isl_morph *morph);
+
+__isl_give isl_morph *isl_morph_compose(__isl_take isl_morph *morph1,
+	__isl_take isl_morph *morph2);
+__isl_give isl_morph *isl_morph_inverse(__isl_take isl_morph *morph);
+
+void isl_morph_print_internal(__isl_take isl_morph *morph, FILE *out);
+void isl_morph_dump(__isl_take isl_morph *morph);
+
+__isl_give isl_morph *isl_basic_set_variable_compression(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type type);
+__isl_give isl_morph *isl_basic_set_variable_compression_with_id(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type type,
+	__isl_keep isl_id *id);
+__isl_give isl_morph *isl_basic_set_parameter_compression(
+	__isl_keep isl_basic_set *bset);
+__isl_give isl_morph *isl_basic_set_full_compression(
+	__isl_keep isl_basic_set *bset);
+
+__isl_give isl_basic_set *isl_morph_basic_set(__isl_take isl_morph *morph,
+	__isl_take isl_basic_set *bset);
+__isl_give isl_set *isl_morph_set(__isl_take isl_morph *morph,
+	__isl_take isl_set *set);
+__isl_give isl_vec *isl_morph_vec(__isl_take isl_morph *morph,
+	__isl_take isl_vec *vec);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/isl_multi_apply_set.c b/final/lib/External/isl/isl_multi_apply_set.c
new file mode 100644
index 0000000..df97878
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_apply_set.c
@@ -0,0 +1,7 @@
+#define APPLY_DOMBASE set
+#define APPLY_DOM isl_set
+
+#include <isl_multi_apply_templ.c>
+
+#undef APPLY_DOMBASE
+#undef APPLY_DOM
diff --git a/final/lib/External/isl/isl_multi_apply_templ.c b/final/lib/External/isl/isl_multi_apply_templ.c
new file mode 100644
index 0000000..44fcb9a
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_apply_templ.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2011      Sven Verdoolaege
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl_multi_macro.h>
+
+/* Transform the elements of "multi" by applying "fn" to them
+ * with extra argument "set".
+ *
+ * The parameters of "multi" and "set" are assumed to have been aligned.
+ */
+__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),apply_aligned),APPLY_DOMBASE)(
+	__isl_take MULTI(BASE) *multi, __isl_take APPLY_DOM *set,
+	__isl_give EL *(*fn)(EL *el, __isl_take APPLY_DOM *set))
+{
+	int i;
+
+	if (!multi || !set)
+		goto error;
+
+	if (multi->n == 0) {
+		FN(APPLY_DOM,free)(set);
+		return multi;
+	}
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		goto error;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = fn(multi->p[i], FN(APPLY_DOM,copy)(set));
+		if (!multi->p[i])
+			goto error;
+	}
+
+	FN(APPLY_DOM,free)(set);
+	return multi;
+error:
+	FN(APPLY_DOM,free)(set);
+	FN(MULTI(BASE),free)(multi);
+	return NULL;
+}
+
+/* Transform the elements of "multi" by applying "fn" to them
+ * with extra argument "set".
+ *
+ * Align the parameters if needed and call apply_set_aligned.
+ */
+static __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),apply),APPLY_DOMBASE)(
+	__isl_take MULTI(BASE) *multi, __isl_take APPLY_DOM *set,
+	__isl_give EL *(*fn)(EL *el, __isl_take APPLY_DOM *set))
+{
+	isl_bool aligned;
+	isl_ctx *ctx;
+
+	if (!multi || !set)
+		goto error;
+
+	aligned = FN(APPLY_DOM,space_has_equal_params)(set, multi->space);
+	if (aligned < 0)
+		goto error;
+	if (aligned)
+		return FN(FN(MULTI(BASE),apply_aligned),APPLY_DOMBASE)(multi,
+								    set, fn);
+	ctx = FN(MULTI(BASE),get_ctx)(multi);
+	if (!isl_space_has_named_params(multi->space) ||
+	    !isl_space_has_named_params(set->dim))
+		isl_die(ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	multi = FN(MULTI(BASE),align_params)(multi,
+						FN(APPLY_DOM,get_space)(set));
+	set = FN(APPLY_DOM,align_params)(set, FN(MULTI(BASE),get_space)(multi));
+	return FN(FN(MULTI(BASE),apply_aligned),APPLY_DOMBASE)(multi, set, fn);
+error:
+	FN(MULTI(BASE),free)(multi);
+	FN(APPLY_DOM,free)(set);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_multi_apply_union_set.c b/final/lib/External/isl/isl_multi_apply_union_set.c
new file mode 100644
index 0000000..d7c298a
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_apply_union_set.c
@@ -0,0 +1,7 @@
+#define APPLY_DOMBASE union_set
+#define APPLY_DOM isl_union_set
+
+#include <isl_multi_apply_templ.c>
+
+#undef APPLY_DOMBASE
+#undef APPLY_DOM
diff --git a/final/lib/External/isl/isl_multi_cmp.c b/final/lib/External/isl/isl_multi_cmp.c
new file mode 100644
index 0000000..a99d370
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_cmp.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege
+ */
+
+#include <isl_multi_macro.h>
+
+/* Compare two multi expressions.
+ *
+ * Return -1 if "multi1" is "smaller" than "multi2", 1 if "multi1" is "greater"
+ * than "multi2" and 0 if they are equal.
+ */
+int FN(MULTI(BASE),plain_cmp)(__isl_keep MULTI(BASE) *multi1,
+	__isl_keep MULTI(BASE) *multi2)
+{
+	int i;
+	int cmp;
+
+	if (multi1 == multi2)
+		return 0;
+	if (!multi1)
+		return -1;
+	if (!multi2)
+		return 1;
+
+	cmp = isl_space_cmp(multi1->space, multi2->space);
+	if (cmp != 0)
+		return cmp;
+
+	for (i = 0; i < multi1->n; ++i) {
+		cmp = FN(EL,plain_cmp)(multi1->p[i], multi2->p[i]);
+		if (cmp != 0)
+			return cmp;
+	}
+
+	return 0;
+}
diff --git a/final/lib/External/isl/isl_multi_coalesce.c b/final/lib/External/isl/isl_multi_coalesce.c
new file mode 100644
index 0000000..aef59e8
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_coalesce.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2013      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_multi_macro.h>
+
+/* Coalesce the elements of "multi".
+ *
+ * Note that such coalescing does not change the meaning of "multi"
+ * so there is no need to cow.  We do need to be careful not to
+ * destroy any other copies of "multi" in case of failure.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),coalesce)(__isl_take MULTI(BASE) *multi)
+{
+	int i;
+
+	if (!multi)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i) {
+		EL *el = FN(EL,copy)(multi->p[i]);
+		el = FN(EL,coalesce)(el);
+		if (!el)
+			return FN(MULTI(BASE),free)(multi);
+		FN(EL,free)(multi->p[i]);
+		multi->p[i] = el;
+	}
+
+	return multi;
+}
diff --git a/final/lib/External/isl/isl_multi_floor.c b/final/lib/External/isl/isl_multi_floor.c
new file mode 100644
index 0000000..d869e65
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_floor.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_multi_macro.h>
+
+/* Given f, return floor(f).
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),floor)(__isl_take MULTI(BASE) *multi)
+{
+	int i;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,floor)(multi->p[i]);
+		if (!multi->p[i])
+			return FN(MULTI(BASE),free)(multi);
+	}
+
+	return multi;
+}
diff --git a/final/lib/External/isl/isl_multi_gist.c b/final/lib/External/isl/isl_multi_gist.c
new file mode 100644
index 0000000..d43525f
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_gist.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2011      Sven Verdoolaege
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl_multi_macro.h>
+
+/* Compute the gist of "multi" with respect to the domain constraints
+ * of "context".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),gist)(__isl_take MULTI(BASE) *multi,
+	__isl_take DOM *context)
+{
+	return FN(FN(MULTI(BASE),apply),DOMBASE)(multi, context, &FN(EL,gist));
+}
+
+/* Compute the gist of "multi" with respect to the parameter constraints
+ * of "context".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),gist_params)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_set *context)
+{
+	return FN(MULTI(BASE),apply_set)(multi, context, &FN(EL,gist_params));
+}
diff --git a/final/lib/External/isl/isl_multi_hash.c b/final/lib/External/isl/isl_multi_hash.c
new file mode 100644
index 0000000..b4bb6c3
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_hash.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege
+ */
+
+#include <isl_multi_macro.h>
+#include <isl/hash.h>
+
+/* Return a hash value that digests "multi".
+ */
+uint32_t FN(MULTI(BASE),get_hash)(__isl_keep MULTI(BASE) *multi)
+{
+	int i;
+	uint32_t hash;
+
+	if (!multi)
+		return 0;
+
+	hash = isl_hash_init();
+	for (i = 0; i < multi->n; ++i) {
+		uint32_t el_hash;
+		el_hash = FN(EL,get_hash)(multi->p[i]);
+		isl_hash_hash(hash, el_hash);
+	}
+
+	return hash;
+}
diff --git a/final/lib/External/isl/isl_multi_intersect.c b/final/lib/External/isl/isl_multi_intersect.c
new file mode 100644
index 0000000..b934102
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_intersect.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2011      Sven Verdoolaege
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl_multi_macro.h>
+
+/* Intersect the domain of "multi" with "domain".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_domain)(
+	__isl_take MULTI(BASE) *multi, __isl_take DOM *domain)
+{
+	return FN(FN(MULTI(BASE),apply),DOMBASE)(multi, domain,
+					&FN(EL,intersect_domain));
+}
+
+/* Intersect the parameter domain of "multi" with "domain".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),intersect_params)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_set *domain)
+{
+	return FN(MULTI(BASE),apply_set)(multi, domain,
+					&FN(EL,intersect_params));
+}
diff --git a/final/lib/External/isl/isl_multi_macro.h b/final/lib/External/isl/isl_multi_macro.h
new file mode 100644
index 0000000..0200b4d
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_macro.h
@@ -0,0 +1,10 @@
+#define xCAT(A,B) A ## B
+#define CAT(A,B) xCAT(A,B)
+#undef EL
+#define EL CAT(isl_,BASE)
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xMULTI(BASE) isl_multi_ ## BASE
+#define MULTI(BASE) xMULTI(BASE)
+#undef DOM
+#define DOM CAT(isl_,DOMBASE)
diff --git a/final/lib/External/isl/isl_multi_templ.c b/final/lib/External/isl/isl_multi_templ.c
new file mode 100644
index 0000000..f2f2618
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_templ.c
@@ -0,0 +1,1514 @@
+/*
+ * Copyright 2011      Sven Verdoolaege
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl_space_private.h>
+#include <isl/set.h>
+#include <isl_reordering.h>
+
+#include <isl_multi_macro.h>
+
+#define MULTI_NAME(BASE) "isl_multi_" #BASE
+#define xLIST(EL) EL ## _list
+#define LIST(EL) xLIST(EL)
+
+isl_ctx *FN(MULTI(BASE),get_ctx)(__isl_keep MULTI(BASE) *multi)
+{
+	return multi ? isl_space_get_ctx(multi->space) : NULL;
+}
+
+__isl_give isl_space *FN(MULTI(BASE),get_space)(__isl_keep MULTI(BASE) *multi)
+{
+	return multi ? isl_space_copy(multi->space) : NULL;
+}
+
+/* Return the position of the dimension of the given type and name
+ * in "multi".
+ * Return -1 if no such dimension can be found.
+ */
+int FN(MULTI(BASE),find_dim_by_name)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type, const char *name)
+{
+	if (!multi)
+		return -1;
+	return isl_space_find_dim_by_name(multi->space, type, name);
+}
+
+__isl_give isl_space *FN(MULTI(BASE),get_domain_space)(
+	__isl_keep MULTI(BASE) *multi)
+{
+	return multi ? isl_space_domain(isl_space_copy(multi->space)) : NULL;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),alloc)(__isl_take isl_space *space)
+{
+	isl_ctx *ctx;
+	int n;
+	MULTI(BASE) *multi;
+
+	if (!space)
+		return NULL;
+
+	ctx = isl_space_get_ctx(space);
+	n = isl_space_dim(space, isl_dim_out);
+	multi = isl_calloc(ctx, MULTI(BASE),
+			 sizeof(MULTI(BASE)) + (n - 1) * sizeof(struct EL *));
+	if (!multi)
+		goto error;
+
+	multi->space = space;
+	multi->n = n;
+	multi->ref = 1;
+	return multi;
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),dup)(__isl_keep MULTI(BASE) *multi)
+{
+	int i;
+	MULTI(BASE) *dup;
+
+	if (!multi)
+		return NULL;
+
+	dup = FN(MULTI(BASE),alloc)(isl_space_copy(multi->space));
+	if (!dup)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i)
+		dup = FN(FN(MULTI(BASE),set),BASE)(dup, i,
+						    FN(EL,copy)(multi->p[i]));
+
+	return dup;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),cow)(__isl_take MULTI(BASE) *multi)
+{
+	if (!multi)
+		return NULL;
+
+	if (multi->ref == 1)
+		return multi;
+
+	multi->ref--;
+	return FN(MULTI(BASE),dup)(multi);
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),copy)(__isl_keep MULTI(BASE) *multi)
+{
+	if (!multi)
+		return NULL;
+
+	multi->ref++;
+	return multi;
+}
+
+__isl_null MULTI(BASE) *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi)
+{
+	int i;
+
+	if (!multi)
+		return NULL;
+
+	if (--multi->ref > 0)
+		return NULL;
+
+	isl_space_free(multi->space);
+	for (i = 0; i < multi->n; ++i)
+		FN(EL,free)(multi->p[i]);
+	free(multi);
+
+	return NULL;
+}
+
+#ifndef NO_DIMS
+/* Check whether "multi" has non-zero coefficients for any dimension
+ * in the given range or if any of these dimensions appear
+ * with non-zero coefficients in any of the integer divisions involved.
+ */
+isl_bool FN(MULTI(BASE),involves_dims)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!multi)
+		return isl_bool_error;
+	if (multi->n == 0 || n == 0)
+		return isl_bool_false;
+
+	for (i = 0; i < multi->n; ++i) {
+		isl_bool involves;
+
+		involves = FN(EL,involves_dims)(multi->p[i], type, first, n);
+		if (involves < 0 || involves)
+			return involves;
+	}
+
+	return isl_bool_false;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),insert_dims)(
+	__isl_take MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!multi)
+		return NULL;
+	if (type == isl_dim_out)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"cannot insert output/set dimensions",
+			return FN(MULTI(BASE),free)(multi));
+	if (n == 0 && !isl_space_is_named_or_nested(multi->space, type))
+		return multi;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	multi->space = isl_space_insert_dims(multi->space, type, first, n);
+	if (!multi->space)
+		return FN(MULTI(BASE),free)(multi);
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,insert_dims)(multi->p[i], type, first, n);
+		if (!multi->p[i])
+			return FN(MULTI(BASE),free)(multi);
+	}
+
+	return multi;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),add_dims)(__isl_take MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned n)
+{
+	unsigned pos;
+
+	pos = FN(MULTI(BASE),dim)(multi, type);
+
+	return FN(MULTI(BASE),insert_dims)(multi, type, pos, n);
+}
+#endif
+
+unsigned FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type)
+{
+	return multi ? isl_space_dim(multi->space, type) : 0;
+}
+
+/* Return the position of the first dimension of "type" with id "id".
+ * Return -1 if there is no such dimension.
+ */
+int FN(MULTI(BASE),find_dim_by_id)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type, __isl_keep isl_id *id)
+{
+	if (!multi)
+		return -1;
+	return isl_space_find_dim_by_id(multi->space, type, id);
+}
+
+/* Return the id of the given dimension.
+ */
+__isl_give isl_id *FN(MULTI(BASE),get_dim_id)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned pos)
+{
+	return multi ? isl_space_get_dim_id(multi->space, type, pos) : NULL;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_name)(
+	__isl_take MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	int i;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	multi->space = isl_space_set_dim_name(multi->space, type, pos, s);
+	if (!multi->space)
+		return FN(MULTI(BASE),free)(multi);
+
+	if (type == isl_dim_out)
+		return multi;
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,set_dim_name)(multi->p[i], type, pos, s);
+		if (!multi->p[i])
+			return FN(MULTI(BASE),free)(multi);
+	}
+
+	return multi;
+}
+
+const char *FN(MULTI(BASE),get_tuple_name)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type)
+{
+	return multi ? isl_space_get_tuple_name(multi->space, type) : NULL;
+}
+
+/* Does the specified tuple have an id?
+ */
+isl_bool FN(MULTI(BASE),has_tuple_id)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type)
+{
+	if (!multi)
+		return isl_bool_error;
+	return isl_space_has_tuple_id(multi->space, type);
+}
+
+/* Return the id of the specified tuple.
+ */
+__isl_give isl_id *FN(MULTI(BASE),get_tuple_id)(__isl_keep MULTI(BASE) *multi,
+	enum isl_dim_type type)
+{
+	return multi ? isl_space_get_tuple_id(multi->space, type) : NULL;
+}
+
+__isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi,
+	int pos)
+{
+	isl_ctx *ctx;
+
+	if (!multi)
+		return NULL;
+	ctx = FN(MULTI(BASE),get_ctx)(multi);
+	if (pos < 0 || pos >= multi->n)
+		isl_die(ctx, isl_error_invalid,
+			"index out of bounds", return NULL);
+	return FN(EL,copy)(multi->p[pos]);
+}
+
+__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)(
+	__isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
+{
+	isl_space *multi_space = NULL;
+	isl_space *el_space = NULL;
+	isl_bool match;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi || !el)
+		goto error;
+
+	multi_space = FN(MULTI(BASE),get_space)(multi);
+	match = FN(EL,matching_params)(el, multi_space);
+	if (match < 0)
+		goto error;
+	if (!match) {
+		multi = FN(MULTI(BASE),align_params)(multi,
+						    FN(EL,get_space)(el));
+		isl_space_free(multi_space);
+		multi_space = FN(MULTI(BASE),get_space)(multi);
+		el = FN(EL,align_params)(el, isl_space_copy(multi_space));
+	}
+	if (FN(EL,check_match_domain_space)(el, multi_space) < 0)
+		goto error;
+
+	if (pos < 0 || pos >= multi->n)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	FN(EL,free)(multi->p[pos]);
+	multi->p[pos] = el;
+
+	isl_space_free(multi_space);
+	isl_space_free(el_space);
+
+	return multi;
+error:
+	FN(MULTI(BASE),free)(multi);
+	FN(EL,free)(el);
+	isl_space_free(multi_space);
+	isl_space_free(el_space);
+	return NULL;
+}
+
+/* Reset the space of "multi".  This function is called from isl_pw_templ.c
+ * and doesn't know if the space of an element object is represented
+ * directly or through its domain.  It therefore passes along both,
+ * which we pass along to the element function since we don't how
+ * that is represented either.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space_and_domain)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_space *space,
+	__isl_take isl_space *domain)
+{
+	int i;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi || !space || !domain)
+		goto error;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,reset_domain_space)(multi->p[i],
+				 isl_space_copy(domain));
+		if (!multi->p[i])
+			goto error;
+	}
+	isl_space_free(domain);
+	isl_space_free(multi->space);
+	multi->space = space;
+
+	return multi;
+error:
+	isl_space_free(domain);
+	isl_space_free(space);
+	FN(MULTI(BASE),free)(multi);
+	return NULL;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_domain_space)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_space *domain)
+{
+	isl_space *space;
+
+	space = isl_space_extend_domain_with_range(isl_space_copy(domain),
+						isl_space_copy(multi->space));
+	return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_space *space)
+{
+	isl_space *domain;
+
+	domain = isl_space_domain(isl_space_copy(space));
+	return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
+}
+
+/* Set the id of the given dimension of "multi" to "id".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_id)(
+	__isl_take MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	isl_space *space;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi || !id)
+		goto error;
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	space = isl_space_set_dim_id(space, type, pos, id);
+
+	return FN(MULTI(BASE),reset_space)(multi, space);
+error:
+	isl_id_free(id);
+	FN(MULTI(BASE),free)(multi);
+	return NULL;
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_name)(
+	__isl_keep MULTI(BASE) *multi, enum isl_dim_type type,
+	const char *s)
+{
+	isl_space *space;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	space = isl_space_set_tuple_name(space, type, s);
+
+	return FN(MULTI(BASE),reset_space)(multi, space);
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_id)(
+	__isl_take MULTI(BASE) *multi, enum isl_dim_type type,
+	__isl_take isl_id *id)
+{
+	isl_space *space;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		goto error;
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	space = isl_space_set_tuple_id(space, type, id);
+
+	return FN(MULTI(BASE),reset_space)(multi, space);
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+/* Drop the id on the specified tuple.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_tuple_id)(
+	__isl_take MULTI(BASE) *multi, enum isl_dim_type type)
+{
+	isl_space *space;
+
+	if (!multi)
+		return NULL;
+	if (!FN(MULTI(BASE),has_tuple_id)(multi, type))
+		return multi;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	space = isl_space_reset_tuple_id(space, type);
+
+	return FN(MULTI(BASE),reset_space)(multi, space);
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the space of "multi".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_user)(
+	__isl_take MULTI(BASE) *multi)
+{
+	isl_space *space;
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	space = isl_space_reset_user(space);
+
+	return FN(MULTI(BASE),reset_space)(multi, space);
+}
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),realign_domain)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_reordering *exp)
+{
+	int i;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi || !exp)
+		goto error;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,realign_domain)(multi->p[i],
+						isl_reordering_copy(exp));
+		if (!multi->p[i])
+			goto error;
+	}
+
+	multi = FN(MULTI(BASE),reset_domain_space)(multi,
+						    isl_space_copy(exp->dim));
+
+	isl_reordering_free(exp);
+	return multi;
+error:
+	isl_reordering_free(exp);
+	FN(MULTI(BASE),free)(multi);
+	return NULL;
+}
+
+/* Align the parameters of "multi" to those of "model".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_space *model)
+{
+	isl_ctx *ctx;
+	isl_bool equal_params;
+	isl_reordering *exp;
+
+	if (!multi || !model)
+		goto error;
+
+	equal_params = isl_space_has_equal_params(multi->space, model);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params) {
+		isl_space_free(model);
+		return multi;
+	}
+
+	ctx = isl_space_get_ctx(model);
+	if (!isl_space_has_named_params(model))
+		isl_die(ctx, isl_error_invalid,
+			"model has unnamed parameters", goto error);
+	if (!isl_space_has_named_params(multi->space))
+		isl_die(ctx, isl_error_invalid,
+			"input has unnamed parameters", goto error);
+
+	model = isl_space_params(model);
+	exp = isl_parameter_alignment_reordering(multi->space, model);
+	exp = isl_reordering_extend_space(exp,
+				    FN(MULTI(BASE),get_domain_space)(multi));
+	multi = FN(MULTI(BASE),realign_domain)(multi, exp);
+
+	isl_space_free(model);
+	return multi;
+error:
+	isl_space_free(model);
+	FN(MULTI(BASE),free)(multi);
+	return NULL;
+}
+
+__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))(
+	__isl_take isl_space *space, __isl_take LIST(EL) *list)
+{
+	int i;
+	int n;
+	isl_ctx *ctx;
+	MULTI(BASE) *multi;
+
+	if (!space || !list)
+		goto error;
+
+	ctx = isl_space_get_ctx(space);
+	n = FN(FN(LIST(EL),n),BASE)(list);
+	if (n != isl_space_dim(space, isl_dim_out))
+		isl_die(ctx, isl_error_invalid,
+			"invalid number of elements in list", goto error);
+
+	multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
+	for (i = 0; i < n; ++i) {
+		multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
+					FN(FN(LIST(EL),get),BASE)(list, i));
+	}
+
+	isl_space_free(space);
+	FN(LIST(EL),free)(list);
+	return multi;
+error:
+	isl_space_free(space);
+	FN(LIST(EL),free)(list);
+	return NULL;
+}
+
+#ifndef NO_IDENTITY
+/* Create a multi expression in the given space that maps each
+ * input dimension to the corresponding output dimension.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),identity)(__isl_take isl_space *space)
+{
+	int i, n;
+	isl_local_space *ls;
+	MULTI(BASE) *multi;
+
+	if (!space)
+		return NULL;
+
+	if (isl_space_is_set(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"expecting map space", goto error);
+
+	n = isl_space_dim(space, isl_dim_out);
+	if (n != isl_space_dim(space, isl_dim_in))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"number of input and output dimensions needs to be "
+			"the same", goto error);
+
+	multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
+
+	if (!n) {
+		isl_space_free(space);
+		return multi;
+	}
+
+	space = isl_space_domain(space);
+	ls = isl_local_space_from_space(space);
+
+	for (i = 0; i < n; ++i) {
+		EL *el;
+		el = FN(EL,var_on_domain)(isl_local_space_copy(ls),
+						isl_dim_set, i);
+		multi = FN(FN(MULTI(BASE),set),BASE)(multi, i, el);
+	}
+
+	isl_local_space_free(ls);
+
+	return multi;
+error:
+	isl_space_free(space);
+	return NULL;
+}
+#endif
+
+#ifndef NO_ZERO
+/* Construct a multi expression in the given space with value zero in
+ * each of the output dimensions.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),zero)(__isl_take isl_space *space)
+{
+	int n;
+	MULTI(BASE) *multi;
+
+	if (!space)
+		return NULL;
+
+	n = isl_space_dim(space , isl_dim_out);
+	multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
+
+	if (!n)
+		isl_space_free(space);
+	else {
+		int i;
+		isl_local_space *ls;
+		EL *el;
+
+		space = isl_space_domain(space);
+		ls = isl_local_space_from_space(space);
+		el = FN(EL,zero_on_domain)(ls);
+
+		for (i = 0; i < n; ++i)
+			multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
+							    FN(EL,copy)(el));
+
+		FN(EL,free)(el);
+	}
+
+	return multi;
+}
+#endif
+
+#ifndef NO_FROM_BASE
+/* Create a multiple expression with a single output/set dimension
+ * equal to "el".
+ * For most multiple expression types, the base type has a single
+ * output/set dimension and the space of the result is therefore
+ * the same as the space of the input.
+ * In the case of isl_multi_union_pw_aff, however, the base type
+ * lives in a parameter space and we therefore need to add
+ * a single set dimension.
+ */
+__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),BASE)(__isl_take EL *el)
+{
+	isl_space *space;
+	MULTI(BASE) *multi;
+
+	space = FN(EL,get_space(el));
+	if (isl_space_is_params(space)) {
+		space = isl_space_set_from_params(space);
+		space = isl_space_add_dims(space, isl_dim_set, 1);
+	}
+	multi = FN(MULTI(BASE),alloc)(space);
+	multi = FN(FN(MULTI(BASE),set),BASE)(multi, 0, el);
+
+	return multi;
+}
+#endif
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)(
+	__isl_take MULTI(BASE) *multi,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	unsigned dim;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	dim = FN(MULTI(BASE),dim)(multi, type);
+	if (first + n > dim || first + n < first)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"index out of bounds",
+			return FN(MULTI(BASE),free)(multi));
+
+	multi->space = isl_space_drop_dims(multi->space, type, first, n);
+	if (!multi->space)
+		return FN(MULTI(BASE),free)(multi);
+
+	if (type == isl_dim_out) {
+		for (i = 0; i < n; ++i)
+			FN(EL,free)(multi->p[first + i]);
+		for (i = first; i + n < multi->n; ++i)
+			multi->p[i] = multi->p[i + n];
+		multi->n -= n;
+
+		return multi;
+	}
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,drop_dims)(multi->p[i], type, first, n);
+		if (!multi->p[i])
+			return FN(MULTI(BASE),free)(multi);
+	}
+
+	return multi;
+}
+
+/* Align the parameters of "multi1" and "multi2" (if needed) and call "fn".
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_multi_and)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
+	__isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi1,
+		__isl_take MULTI(BASE) *multi2))
+{
+	isl_ctx *ctx;
+	isl_bool equal_params;
+
+	if (!multi1 || !multi2)
+		goto error;
+	equal_params = isl_space_has_equal_params(multi1->space, multi2->space);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params)
+		return fn(multi1, multi2);
+	ctx = FN(MULTI(BASE),get_ctx)(multi1);
+	if (!isl_space_has_named_params(multi1->space) ||
+	    !isl_space_has_named_params(multi2->space))
+		isl_die(ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	multi1 = FN(MULTI(BASE),align_params)(multi1,
+					    FN(MULTI(BASE),get_space)(multi2));
+	multi2 = FN(MULTI(BASE),align_params)(multi2,
+					    FN(MULTI(BASE),get_space)(multi1));
+	return fn(multi1, multi2);
+error:
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return NULL;
+}
+
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) (A * C) -> [B -> D].
+ *
+ * The parameters are assumed to have been aligned.
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product_aligned)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+	int i, n1, n2;
+	EL *el;
+	isl_space *space;
+	MULTI(BASE) *res;
+
+	if (!multi1 || !multi2)
+		goto error;
+
+	space = isl_space_range_product(FN(MULTI(BASE),get_space)(multi1),
+					FN(MULTI(BASE),get_space)(multi2));
+	res = FN(MULTI(BASE),alloc)(space);
+
+	n1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
+	n2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
+
+	for (i = 0; i < n1; ++i) {
+		el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
+		res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
+	}
+
+	for (i = 0; i < n2; ++i) {
+		el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
+		res = FN(FN(MULTI(BASE),set),BASE)(res, n1 + i, el);
+	}
+
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return res;
+error:
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return NULL;
+}
+
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) (A * C) -> [B -> D].
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+	return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
+					&FN(MULTI(BASE),range_product_aligned));
+}
+
+/* Is the range of "multi" a wrapped relation?
+ */
+isl_bool FN(MULTI(BASE),range_is_wrapping)(__isl_keep MULTI(BASE) *multi)
+{
+	if (!multi)
+		return isl_bool_error;
+	return isl_space_range_is_wrapping(multi->space);
+}
+
+/* Given a function A -> [B -> C], extract the function A -> B.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_domain)(
+	__isl_take MULTI(BASE) *multi)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!multi)
+		return NULL;
+	if (!isl_space_range_is_wrapping(multi->space))
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"range is not a product",
+			return FN(MULTI(BASE),free)(multi));
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	total = isl_space_dim(space, isl_dim_out);
+	space = isl_space_range_factor_domain(space);
+	keep = isl_space_dim(space, isl_dim_out);
+	multi = FN(MULTI(BASE),drop_dims)(multi,
+					isl_dim_out, keep, total - keep);
+	multi = FN(MULTI(BASE),reset_space)(multi, space);
+
+	return multi;
+}
+
+/* Given a function A -> [B -> C], extract the function A -> C.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_range)(
+	__isl_take MULTI(BASE) *multi)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!multi)
+		return NULL;
+	if (!isl_space_range_is_wrapping(multi->space))
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"range is not a product",
+			return FN(MULTI(BASE),free)(multi));
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	total = isl_space_dim(space, isl_dim_out);
+	space = isl_space_range_factor_range(space);
+	keep = isl_space_dim(space, isl_dim_out);
+	multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
+	multi = FN(MULTI(BASE),reset_space)(multi, space);
+
+	return multi;
+}
+
+/* Given a function [B -> C], extract the function C.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),factor_range)(
+	__isl_take MULTI(BASE) *multi)
+{
+	isl_space *space;
+	int total, keep;
+
+	if (!multi)
+		return NULL;
+	if (!isl_space_is_wrapping(multi->space))
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"not a product", return FN(MULTI(BASE),free)(multi));
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	total = isl_space_dim(space, isl_dim_out);
+	space = isl_space_factor_range(space);
+	keep = isl_space_dim(space, isl_dim_out);
+	multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
+	multi = FN(MULTI(BASE),reset_space)(multi, space);
+
+	return multi;
+}
+
+#ifndef NO_PRODUCT
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) [A -> C] -> [B -> D].
+ *
+ * The parameters are assumed to have been aligned.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),product_aligned)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+	int i;
+	EL *el;
+	isl_space *space;
+	MULTI(BASE) *res;
+	int in1, in2, out1, out2;
+
+	in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in);
+	in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in);
+	out1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
+	out2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
+	space = isl_space_product(FN(MULTI(BASE),get_space)(multi1),
+				  FN(MULTI(BASE),get_space)(multi2));
+	res = FN(MULTI(BASE),alloc)(isl_space_copy(space));
+	space = isl_space_domain(space);
+
+	for (i = 0; i < out1; ++i) {
+		el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
+		el = FN(EL,insert_dims)(el, isl_dim_in, in1, in2);
+		el = FN(EL,reset_domain_space)(el, isl_space_copy(space));
+		res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
+	}
+
+	for (i = 0; i < out2; ++i) {
+		el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
+		el = FN(EL,insert_dims)(el, isl_dim_in, 0, in1);
+		el = FN(EL,reset_domain_space)(el, isl_space_copy(space));
+		res = FN(FN(MULTI(BASE),set),BASE)(res, out1 + i, el);
+	}
+
+	isl_space_free(space);
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return res;
+}
+
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) [A -> C] -> [B -> D].
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),product)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+	return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
+					&FN(MULTI(BASE),product_aligned));
+}
+#endif
+
+__isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)(
+	__isl_take MULTI(BASE) *multi)
+{
+	if (!multi)
+		return NULL;
+
+	if (!multi->space->nested[1])
+		return multi;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	multi->space = isl_space_flatten_range(multi->space);
+	if (!multi->space)
+		return FN(MULTI(BASE),free)(multi);
+
+	return multi;
+}
+
+/* Given two MULTI(BASE)s A -> B and C -> D,
+ * construct a MULTI(BASE) (A * C) -> (B, D).
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),flat_range_product)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+	MULTI(BASE) *multi;
+
+	multi = FN(MULTI(BASE),range_product)(multi1, multi2);
+	multi = FN(MULTI(BASE),flatten_range)(multi);
+	return multi;
+}
+
+/* Given two multi expressions, "multi1"
+ *
+ *	[A] -> [B1 B2]
+ *
+ * where B2 starts at position "pos", and "multi2"
+ *
+ *	[A] -> [D]
+ *
+ * return the multi expression
+ *
+ *	[A] -> [B1 D B2]
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),range_splice)(
+	__isl_take MULTI(BASE) *multi1, unsigned pos,
+	__isl_take MULTI(BASE) *multi2)
+{
+	MULTI(BASE) *res;
+	unsigned dim;
+
+	if (!multi1 || !multi2)
+		goto error;
+
+	dim = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
+	if (pos > dim)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	res = FN(MULTI(BASE),copy)(multi1);
+	res = FN(MULTI(BASE),drop_dims)(res, isl_dim_out, pos, dim - pos);
+	multi1 = FN(MULTI(BASE),drop_dims)(multi1, isl_dim_out, 0, pos);
+
+	res = FN(MULTI(BASE),flat_range_product)(res, multi2);
+	res = FN(MULTI(BASE),flat_range_product)(res, multi1);
+
+	return res;
+error:
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return NULL;
+}
+
+#ifndef NO_SPLICE
+/* Given two multi expressions, "multi1"
+ *
+ *	[A1 A2] -> [B1 B2]
+ *
+ * where A2 starts at position "in_pos" and B2 starts at position "out_pos",
+ * and "multi2"
+ *
+ *	[C] -> [D]
+ *
+ * return the multi expression
+ *
+ *	[A1 C A2] -> [B1 D B2]
+ *
+ * We first insert input dimensions to obtain
+ *
+ *	[A1 C A2] -> [B1 B2]
+ *
+ * and
+ *
+ *	[A1 C A2] -> [D]
+ *
+ * and then apply range_splice.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),splice)(
+	__isl_take MULTI(BASE) *multi1, unsigned in_pos, unsigned out_pos,
+	__isl_take MULTI(BASE) *multi2)
+{
+	unsigned n_in1;
+	unsigned n_in2;
+
+	if (!multi1 || !multi2)
+		goto error;
+
+	n_in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in);
+	if (in_pos > n_in1)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
+			"index out of bounds", goto error);
+
+	n_in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in);
+
+	multi1 = FN(MULTI(BASE),insert_dims)(multi1, isl_dim_in, in_pos, n_in2);
+	multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, n_in2,
+						n_in1 - in_pos);
+	multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, 0, in_pos);
+
+	return FN(MULTI(BASE),range_splice)(multi1, out_pos, multi2);
+error:
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return NULL;
+}
+#endif
+
+/* This function is currently only used from isl_aff.c
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
+	__isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
+	__attribute__ ((unused));
+
+/* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
+ * return the result.
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
+	__isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
+{
+	int i;
+	isl_ctx *ctx;
+
+	multi1 = FN(MULTI(BASE),cow)(multi1);
+	if (!multi1 || !multi2)
+		goto error;
+
+	ctx = FN(MULTI(BASE),get_ctx)(multi1);
+	if (!isl_space_is_equal(multi1->space, multi2->space))
+		isl_die(ctx, isl_error_invalid,
+			"spaces don't match", goto error);
+
+	for (i = 0; i < multi1->n; ++i) {
+		multi1->p[i] = fn(multi1->p[i], FN(EL,copy)(multi2->p[i]));
+		if (!multi1->p[i])
+			goto error;
+	}
+
+	FN(MULTI(BASE),free)(multi2);
+	return multi1;
+error:
+	FN(MULTI(BASE),free)(multi1);
+	FN(MULTI(BASE),free)(multi2);
+	return NULL;
+}
+
+/* Add "multi2" from "multi1" and return the result.
+ *
+ * The parameters of "multi1" and "multi2" are assumed to have been aligned.
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),add_aligned)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+	return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,add));
+}
+
+/* Add "multi2" from "multi1" and return the result.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),add)(__isl_take MULTI(BASE) *multi1,
+	__isl_take MULTI(BASE) *multi2)
+{
+	return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
+						&FN(MULTI(BASE),add_aligned));
+}
+
+/* Subtract "multi2" from "multi1" and return the result.
+ *
+ * The parameters of "multi1" and "multi2" are assumed to have been aligned.
+ */
+static __isl_give MULTI(BASE) *FN(MULTI(BASE),sub_aligned)(
+	__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
+{
+	return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,sub));
+}
+
+/* Subtract "multi2" from "multi1" and return the result.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),sub)(__isl_take MULTI(BASE) *multi1,
+	__isl_take MULTI(BASE) *multi2)
+{
+	return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
+						&FN(MULTI(BASE),sub_aligned));
+}
+
+/* Multiply the elements of "multi" by "v" and return the result.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val)(__isl_take MULTI(BASE) *multi,
+	__isl_take isl_val *v)
+{
+	int i;
+
+	if (!multi || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return multi;
+	}
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational factor", goto error);
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,scale_val)(multi->p[i], isl_val_copy(v));
+		if (!multi->p[i])
+			goto error;
+	}
+
+	isl_val_free(v);
+	return multi;
+error:
+	isl_val_free(v);
+	return FN(MULTI(BASE),free)(multi);
+}
+
+/* Divide the elements of "multi" by "v" and return the result.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_val)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_val *v)
+{
+	int i;
+
+	if (!multi || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return multi;
+	}
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational factor", goto error);
+	if (isl_val_is_zero(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"cannot scale down by zero", goto error);
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,scale_down_val)(multi->p[i],
+						    isl_val_copy(v));
+		if (!multi->p[i])
+			goto error;
+	}
+
+	isl_val_free(v);
+	return multi;
+error:
+	isl_val_free(v);
+	return FN(MULTI(BASE),free)(multi);
+}
+
+/* Multiply the elements of "multi" by the corresponding element of "mv"
+ * and return the result.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_multi_val)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
+{
+	int i;
+
+	if (!multi || !mv)
+		goto error;
+
+	if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
+					mv->space, isl_dim_set))
+		isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		goto error;
+
+	for (i = 0; i < multi->n; ++i) {
+		isl_val *v;
+
+		v = isl_multi_val_get_val(mv, i);
+		multi->p[i] = FN(EL,scale_val)(multi->p[i], v);
+		if (!multi->p[i])
+			goto error;
+	}
+
+	isl_multi_val_free(mv);
+	return multi;
+error:
+	isl_multi_val_free(mv);
+	return FN(MULTI(BASE),free)(multi);
+}
+
+/* Divide the elements of "multi" by the corresponding element of "mv"
+ * and return the result.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_multi_val)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
+{
+	int i;
+
+	if (!multi || !mv)
+		goto error;
+
+	if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
+					mv->space, isl_dim_set))
+		isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i) {
+		isl_val *v;
+
+		v = isl_multi_val_get_val(mv, i);
+		multi->p[i] = FN(EL,scale_down_val)(multi->p[i], v);
+		if (!multi->p[i])
+			goto error;
+	}
+
+	isl_multi_val_free(mv);
+	return multi;
+error:
+	isl_multi_val_free(mv);
+	return FN(MULTI(BASE),free)(multi);
+}
+
+/* Compute the residues of the elements of "multi" modulo
+ * the corresponding element of "mv" and return the result.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),mod_multi_val)(
+	__isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
+{
+	int i;
+
+	if (!multi || !mv)
+		goto error;
+
+	if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
+					mv->space, isl_dim_set))
+		isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
+			"spaces don't match", goto error);
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i) {
+		isl_val *v;
+
+		v = isl_multi_val_get_val(mv, i);
+		multi->p[i] = FN(EL,mod_val)(multi->p[i], v);
+		if (!multi->p[i])
+			goto error;
+	}
+
+	isl_multi_val_free(mv);
+	return multi;
+error:
+	isl_multi_val_free(mv);
+	return FN(MULTI(BASE),free)(multi);
+}
+
+#ifndef NO_MOVE_DIMS
+/* Move the "n" dimensions of "src_type" starting at "src_pos" of "multi"
+ * to dimensions of "dst_type" at "dst_pos".
+ *
+ * We only support moving input dimensions to parameters and vice versa.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),move_dims)(__isl_take MULTI(BASE) *multi,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	int i;
+
+	if (!multi)
+		return NULL;
+
+	if (n == 0 &&
+	    !isl_space_is_named_or_nested(multi->space, src_type) &&
+	    !isl_space_is_named_or_nested(multi->space, dst_type))
+		return multi;
+
+	if (dst_type == isl_dim_out || src_type == isl_dim_out)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"cannot move output/set dimension",
+			return FN(MULTI(BASE),free)(multi));
+	if (dst_type == isl_dim_div || src_type == isl_dim_div)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"cannot move divs",
+			return FN(MULTI(BASE),free)(multi));
+	if (src_pos + n > isl_space_dim(multi->space, src_type))
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"range out of bounds",
+			return FN(MULTI(BASE),free)(multi));
+	if (dst_type == src_type)
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_unsupported,
+			"moving dims within the same type not supported",
+			return FN(MULTI(BASE),free)(multi));
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	multi->space = isl_space_move_dims(multi->space, dst_type, dst_pos,
+						src_type, src_pos, n);
+	if (!multi->space)
+		return FN(MULTI(BASE),free)(multi);
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,move_dims)(multi->p[i], dst_type, dst_pos,
+						src_type, src_pos, n);
+		if (!multi->p[i])
+			return FN(MULTI(BASE),free)(multi);
+	}
+
+	return multi;
+}
+#endif
+
+/* Convert a multiple expression defined over a parameter domain
+ * into one that is defined over a zero-dimensional set.
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),from_range)(
+	__isl_take MULTI(BASE) *multi)
+{
+	isl_space *space;
+
+	if (!multi)
+		return NULL;
+	if (!isl_space_is_set(multi->space))
+		isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
+			"not living in a set space",
+			return FN(MULTI(BASE),free)(multi));
+
+	space = FN(MULTI(BASE),get_space)(multi);
+	space = isl_space_from_range(space);
+	multi = FN(MULTI(BASE),reset_space)(multi, space);
+
+	return multi;
+}
+
+/* Are "multi1" and "multi2" obviously equal?
+ */
+isl_bool FN(MULTI(BASE),plain_is_equal)(__isl_keep MULTI(BASE) *multi1,
+	__isl_keep MULTI(BASE) *multi2)
+{
+	int i;
+	isl_bool equal;
+
+	if (!multi1 || !multi2)
+		return isl_bool_error;
+	if (multi1->n != multi2->n)
+		return isl_bool_false;
+	equal = isl_space_is_equal(multi1->space, multi2->space);
+	if (equal < 0 || !equal)
+		return equal;
+
+	for (i = 0; i < multi1->n; ++i) {
+		equal = FN(EL,plain_is_equal)(multi1->p[i], multi2->p[i]);
+		if (equal < 0 || !equal)
+			return equal;
+	}
+
+	return isl_bool_true;
+}
+
+/* Does "multi" involve any NaNs?
+ */
+isl_bool FN(MULTI(BASE),involves_nan)(__isl_keep MULTI(BASE) *multi)
+{
+	int i;
+
+	if (!multi)
+		return isl_bool_error;
+	if (multi->n == 0)
+		return isl_bool_false;
+
+	for (i = 0; i < multi->n; ++i) {
+		isl_bool has_nan = FN(EL,involves_nan)(multi->p[i]);
+		if (has_nan < 0 || has_nan)
+			return has_nan;
+	}
+
+	return isl_bool_false;
+}
+
+#ifndef NO_DOMAIN
+/* Return the shared domain of the elements of "multi".
+ */
+__isl_give isl_set *FN(MULTI(BASE),domain)(__isl_take MULTI(BASE) *multi)
+{
+	int i;
+	isl_set *dom;
+
+	if (!multi)
+		return NULL;
+
+	dom = isl_set_universe(FN(MULTI(BASE),get_domain_space)(multi));
+	for (i = 0; i < multi->n; ++i) {
+		isl_set *dom_i;
+
+		dom_i = FN(EL,domain)(FN(FN(MULTI(BASE),get),BASE)(multi, i));
+		dom = isl_set_intersect(dom, dom_i);
+	}
+
+	FN(MULTI(BASE),free)(multi);
+	return dom;
+}
+#endif
+
+#ifndef NO_NEG
+/* Return the opposite of "multi".
+ */
+__isl_give MULTI(BASE) *FN(MULTI(BASE),neg)(__isl_take MULTI(BASE) *multi)
+{
+	int i;
+
+	multi = FN(MULTI(BASE),cow)(multi);
+	if (!multi)
+		return NULL;
+
+	for (i = 0; i < multi->n; ++i) {
+		multi->p[i] = FN(EL,neg)(multi->p[i]);
+		if (!multi->p[i])
+			return FN(MULTI(BASE),free)(multi);
+	}
+
+	return multi;
+}
+#endif
diff --git a/final/lib/External/isl/isl_multi_templ.h b/final/lib/External/isl/isl_multi_templ.h
new file mode 100644
index 0000000..8170892
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_templ.h
@@ -0,0 +1,13 @@
+#include <isl/space.h>
+
+#include <isl_multi_macro.h>
+
+struct MULTI(BASE) {
+	int ref;
+	isl_space *space;
+
+	int n;
+	EL *p[1];
+};
+
+__isl_give MULTI(BASE) *CAT(MULTI(BASE),_alloc)(__isl_take isl_space *space);
diff --git a/final/lib/External/isl/isl_obj.c b/final/lib/External/isl/isl_obj.c
new file mode 100644
index 0000000..e12035f
--- /dev/null
+++ b/final/lib/External/isl/isl_obj.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2014      Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <isl/aff.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl/polynomial.h>
+#include <isl/schedule.h>
+#include <isl/obj.h>
+
+static void *isl_obj_val_copy(void *v)
+{
+	return isl_val_copy((isl_val *)v);
+}
+
+static void isl_obj_val_free(void *v)
+{
+	isl_val_free((isl_val *)v);
+}
+
+static __isl_give isl_printer *isl_obj_val_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_val(p, (isl_val *)v);
+}
+
+static void *isl_obj_val_add(void *v1, void *v2)
+{
+	return isl_val_add((isl_val *) v1, (isl_val *) v2);
+}
+
+struct isl_obj_vtable isl_obj_val_vtable = {
+	isl_obj_val_copy,
+	isl_obj_val_add,
+	isl_obj_val_print,
+	isl_obj_val_free
+};
+
+static void *isl_obj_map_copy(void *v)
+{
+	return isl_map_copy((struct isl_map *)v);
+}
+
+static void isl_obj_map_free(void *v)
+{
+	isl_map_free((struct isl_map *)v);
+}
+
+static __isl_give isl_printer *isl_obj_map_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_map(p, (struct isl_map *)v);
+}
+
+static void *isl_obj_map_add(void *v1, void *v2)
+{
+	return isl_map_union((struct isl_map *)v1, (struct isl_map *)v2);
+}
+
+struct isl_obj_vtable isl_obj_map_vtable = {
+	isl_obj_map_copy,
+	isl_obj_map_add,
+	isl_obj_map_print,
+	isl_obj_map_free
+};
+
+static void *isl_obj_union_map_copy(void *v)
+{
+	return isl_union_map_copy((isl_union_map *)v);
+}
+
+static void isl_obj_union_map_free(void *v)
+{
+	isl_union_map_free((isl_union_map *)v);
+}
+
+static __isl_give isl_printer *isl_obj_union_map_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_union_map(p, (isl_union_map *)v);
+}
+
+static void *isl_obj_union_map_add(void *v1, void *v2)
+{
+	return isl_union_map_union((isl_union_map *)v1, (isl_union_map *)v2);
+}
+
+struct isl_obj_vtable isl_obj_union_map_vtable = {
+	isl_obj_union_map_copy,
+	isl_obj_union_map_add,
+	isl_obj_union_map_print,
+	isl_obj_union_map_free
+};
+
+static void *isl_obj_set_copy(void *v)
+{
+	return isl_set_copy((struct isl_set *)v);
+}
+
+static void isl_obj_set_free(void *v)
+{
+	isl_set_free((struct isl_set *)v);
+}
+
+static __isl_give isl_printer *isl_obj_set_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_set(p, (struct isl_set *)v);
+}
+
+static void *isl_obj_set_add(void *v1, void *v2)
+{
+	return isl_set_union((struct isl_set *)v1, (struct isl_set *)v2);
+}
+
+struct isl_obj_vtable isl_obj_set_vtable = {
+	isl_obj_set_copy,
+	isl_obj_set_add,
+	isl_obj_set_print,
+	isl_obj_set_free
+};
+
+static void *isl_obj_union_set_copy(void *v)
+{
+	return isl_union_set_copy((isl_union_set *)v);
+}
+
+static void isl_obj_union_set_free(void *v)
+{
+	isl_union_set_free((isl_union_set *)v);
+}
+
+static __isl_give isl_printer *isl_obj_union_set_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_union_set(p, (isl_union_set *)v);
+}
+
+static void *isl_obj_union_set_add(void *v1, void *v2)
+{
+	return isl_union_set_union((isl_union_set *)v1, (isl_union_set *)v2);
+}
+
+struct isl_obj_vtable isl_obj_union_set_vtable = {
+	isl_obj_union_set_copy,
+	isl_obj_union_set_add,
+	isl_obj_union_set_print,
+	isl_obj_union_set_free
+};
+
+static void *isl_obj_pw_multi_aff_copy(void *v)
+{
+	return isl_pw_multi_aff_copy((isl_pw_multi_aff *) v);
+}
+
+static void isl_obj_pw_multi_aff_free(void *v)
+{
+	isl_pw_multi_aff_free((isl_pw_multi_aff *) v);
+}
+
+static __isl_give isl_printer *isl_obj_pw_multi_aff_print(
+	__isl_take isl_printer *p, void *v)
+{
+	return isl_printer_print_pw_multi_aff(p, (isl_pw_multi_aff *) v);
+}
+
+static void *isl_obj_pw_multi_aff_add(void *v1, void *v2)
+{
+	return isl_pw_multi_aff_add((isl_pw_multi_aff *) v1,
+				    (isl_pw_multi_aff *) v2);
+}
+
+struct isl_obj_vtable isl_obj_pw_multi_aff_vtable = {
+	isl_obj_pw_multi_aff_copy,
+	isl_obj_pw_multi_aff_add,
+	isl_obj_pw_multi_aff_print,
+	isl_obj_pw_multi_aff_free
+};
+
+static void *isl_obj_none_copy(void *v)
+{
+	return v;
+}
+
+static void isl_obj_none_free(void *v)
+{
+}
+
+static __isl_give isl_printer *isl_obj_none_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return p;
+}
+
+static void *isl_obj_none_add(void *v1, void *v2)
+{
+	return NULL;
+}
+
+struct isl_obj_vtable isl_obj_none_vtable = {
+	isl_obj_none_copy,
+	isl_obj_none_add,
+	isl_obj_none_print,
+	isl_obj_none_free
+};
+
+static void *isl_obj_pw_qp_copy(void *v)
+{
+	return isl_pw_qpolynomial_copy((struct isl_pw_qpolynomial *)v);
+}
+
+static void isl_obj_pw_qp_free(void *v)
+{
+	isl_pw_qpolynomial_free((struct isl_pw_qpolynomial *)v);
+}
+
+static __isl_give isl_printer *isl_obj_pw_qp_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_pw_qpolynomial(p,
+						(struct isl_pw_qpolynomial *)v);
+}
+
+static void *isl_obj_pw_qp_add(void *v1, void *v2)
+{
+	return isl_pw_qpolynomial_add((struct isl_pw_qpolynomial *)v1,
+					(struct isl_pw_qpolynomial *)v2);
+}
+
+struct isl_obj_vtable isl_obj_pw_qpolynomial_vtable = {
+	isl_obj_pw_qp_copy,
+	isl_obj_pw_qp_add,
+	isl_obj_pw_qp_print,
+	isl_obj_pw_qp_free
+};
+
+static void *isl_obj_union_pw_qp_copy(void *v)
+{
+	return isl_union_pw_qpolynomial_copy((struct isl_union_pw_qpolynomial *)v);
+}
+
+static void isl_obj_union_pw_qp_free(void *v)
+{
+	isl_union_pw_qpolynomial_free((struct isl_union_pw_qpolynomial *)v);
+}
+
+static __isl_give isl_printer *isl_obj_union_pw_qp_print(
+	__isl_take isl_printer *p, void *v)
+{
+	return isl_printer_print_union_pw_qpolynomial(p,
+					(struct isl_union_pw_qpolynomial *)v);
+}
+
+static void *isl_obj_union_pw_qp_add(void *v1, void *v2)
+{
+	return isl_union_pw_qpolynomial_add(
+					(struct isl_union_pw_qpolynomial *)v1,
+					(struct isl_union_pw_qpolynomial *)v2);
+}
+
+struct isl_obj_vtable isl_obj_union_pw_qpolynomial_vtable = {
+	isl_obj_union_pw_qp_copy,
+	isl_obj_union_pw_qp_add,
+	isl_obj_union_pw_qp_print,
+	isl_obj_union_pw_qp_free
+};
+
+static void *isl_obj_pw_qpf_copy(void *v)
+{
+	return isl_pw_qpolynomial_fold_copy((struct isl_pw_qpolynomial_fold *)v);
+}
+
+static void isl_obj_pw_qpf_free(void *v)
+{
+	isl_pw_qpolynomial_fold_free((struct isl_pw_qpolynomial_fold *)v);
+}
+
+static __isl_give isl_printer *isl_obj_pw_qpf_print(__isl_take isl_printer *p,
+	void *v)
+{
+	return isl_printer_print_pw_qpolynomial_fold(p,
+					(struct isl_pw_qpolynomial_fold *)v);
+}
+
+static void *isl_obj_pw_qpf_add(void *v1, void *v2)
+{
+	return isl_pw_qpolynomial_fold_fold((struct isl_pw_qpolynomial_fold *)v1,
+					    (struct isl_pw_qpolynomial_fold *)v2);
+}
+
+struct isl_obj_vtable isl_obj_pw_qpolynomial_fold_vtable = {
+	isl_obj_pw_qpf_copy,
+	isl_obj_pw_qpf_add,
+	isl_obj_pw_qpf_print,
+	isl_obj_pw_qpf_free
+};
+
+static void *isl_obj_union_pw_qpf_copy(void *v)
+{
+	return isl_union_pw_qpolynomial_fold_copy((struct isl_union_pw_qpolynomial_fold *)v);
+}
+
+static void isl_obj_union_pw_qpf_free(void *v)
+{
+	isl_union_pw_qpolynomial_fold_free((struct isl_union_pw_qpolynomial_fold *)v);
+}
+
+static __isl_give isl_printer *isl_obj_union_pw_qpf_print(
+	__isl_take isl_printer *p, void *v)
+{
+	return isl_printer_print_union_pw_qpolynomial_fold(p,
+				    (struct isl_union_pw_qpolynomial_fold *)v);
+}
+
+static void *isl_obj_union_pw_qpf_add(void *v1, void *v2)
+{
+	return isl_union_pw_qpolynomial_fold_fold(
+				    (struct isl_union_pw_qpolynomial_fold *)v1,
+				    (struct isl_union_pw_qpolynomial_fold *)v2);
+}
+
+struct isl_obj_vtable isl_obj_union_pw_qpolynomial_fold_vtable = {
+	isl_obj_union_pw_qpf_copy,
+	isl_obj_union_pw_qpf_add,
+	isl_obj_union_pw_qpf_print,
+	isl_obj_union_pw_qpf_free
+};
+
+static void *isl_obj_schedule_copy(void *v)
+{
+	return isl_schedule_copy((isl_schedule *) v);
+}
+
+static void isl_obj_schedule_free(void *v)
+{
+	isl_schedule_free((isl_schedule *) v);
+}
+
+static __isl_give isl_printer *isl_obj_schedule_print(
+	__isl_take isl_printer *p, void *v)
+{
+	return isl_printer_print_schedule(p, (isl_schedule *) v);
+}
+
+struct isl_obj_vtable isl_obj_schedule_vtable = {
+	isl_obj_schedule_copy,
+	NULL,
+	isl_obj_schedule_print,
+	isl_obj_schedule_free
+};
diff --git a/final/lib/External/isl/isl_options.c b/final/lib/External/isl/isl_options.c
new file mode 100644
index 0000000..eb3dd02
--- /dev/null
+++ b/final/lib/External/isl/isl_options.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isl/ctx.h>
+#include <isl_options_private.h>
+#include <isl/ast_build.h>
+#include <isl/schedule.h>
+#include <isl/version.h>
+
+struct isl_arg_choice isl_pip_context_choice[] = {
+	{"gbr",		ISL_CONTEXT_GBR},
+	{"lexmin",	ISL_CONTEXT_LEXMIN},
+	{0}
+};
+
+struct isl_arg_choice isl_gbr_choice[] = {
+	{"never",	ISL_GBR_NEVER},
+	{"once",	ISL_GBR_ONCE},
+	{"always",	ISL_GBR_ALWAYS},
+	{0}
+};
+
+struct isl_arg_choice isl_closure_choice[] = {
+	{"isl",		ISL_CLOSURE_ISL},
+	{"box",		ISL_CLOSURE_BOX},
+	{0}
+};
+
+static struct isl_arg_choice bound[] = {
+	{"bernstein",	ISL_BOUND_BERNSTEIN},
+	{"range",	ISL_BOUND_RANGE},
+	{0}
+};
+
+static struct isl_arg_choice on_error[] = {
+	{"warn",	ISL_ON_ERROR_WARN},
+	{"continue",	ISL_ON_ERROR_CONTINUE},
+	{"abort",	ISL_ON_ERROR_ABORT},
+	{0}
+};
+
+static struct isl_arg_choice isl_schedule_algorithm_choice[] = {
+	{"isl",		ISL_SCHEDULE_ALGORITHM_ISL},
+	{"feautrier",   ISL_SCHEDULE_ALGORITHM_FEAUTRIER},
+	{0}
+};
+
+static struct isl_arg_flags bernstein_recurse[] = {
+	{"none",	ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS, 0},
+	{"factors",	ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS,
+			ISL_BERNSTEIN_FACTORS},
+	{"intervals",	ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS,
+			ISL_BERNSTEIN_INTERVALS},
+	{"full",	ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS,
+			ISL_BERNSTEIN_FACTORS | ISL_BERNSTEIN_INTERVALS},
+	{0}
+};
+
+static struct isl_arg_choice convex[] = {
+	{"wrap",	ISL_CONVEX_HULL_WRAP},
+	{"fm",		ISL_CONVEX_HULL_FM},
+	{0}
+};
+
+#define		ISL_SCHEDULE_FUSE_MAX			0
+#define		ISL_SCHEDULE_FUSE_MIN			1
+
+static struct isl_arg_choice fuse[] = {
+	{"max",		ISL_SCHEDULE_FUSE_MAX},
+	{"min",		ISL_SCHEDULE_FUSE_MIN},
+	{0}
+};
+
+/* Callback for setting the "schedule-fuse" option.
+ * This (now hidden) option tries to mimic an option that was
+ * replaced by the schedule-serialize-sccs option.
+ * Setting the old option to ISL_SCHEDULE_FUSE_MIN is now
+ * expressed by turning on the schedule-serialize-sccs option.
+ */
+static int set_fuse(void *opt, unsigned val)
+{
+	struct isl_options *options = opt;
+
+	options->schedule_serialize_sccs = (val == ISL_SCHEDULE_FUSE_MIN);
+
+	return 0;
+}
+
+static struct isl_arg_choice separation_bounds[] = {
+	{"explicit",	ISL_AST_BUILD_SEPARATION_BOUNDS_EXPLICIT},
+	{"implicit",	ISL_AST_BUILD_SEPARATION_BOUNDS_IMPLICIT},
+	{0}
+};
+
+static void print_version(void)
+{
+	printf("%s", isl_version());
+}
+
+ISL_ARGS_START(struct isl_options, isl_options_args)
+ISL_ARG_CHOICE(struct isl_options, context, 0, "context", \
+	isl_pip_context_choice,	ISL_CONTEXT_GBR,
+	"how to handle the pip context tableau")
+ISL_ARG_CHOICE(struct isl_options, gbr, 0, "gbr", \
+	isl_gbr_choice,	ISL_GBR_ALWAYS,
+	"how often to use generalized basis reduction")
+ISL_ARG_CHOICE(struct isl_options, closure, 0, "closure", \
+	isl_closure_choice,	ISL_CLOSURE_ISL,
+	"closure operation to use")
+ISL_ARG_BOOL(struct isl_options, gbr_only_first, 0, "gbr-only-first", 0,
+	"only perform basis reduction in first direction")
+ISL_ARG_CHOICE(struct isl_options, bound, 0, "bound", bound,
+	ISL_BOUND_BERNSTEIN, "algorithm to use for computing bounds")
+ISL_ARG_CHOICE(struct isl_options, on_error, 0, "on-error", on_error,
+	ISL_ON_ERROR_WARN, "how to react if an error is detected")
+ISL_ARG_FLAGS(struct isl_options, bernstein_recurse, 0,
+	"bernstein-recurse", bernstein_recurse, ISL_BERNSTEIN_FACTORS, NULL)
+ISL_ARG_BOOL(struct isl_options, bernstein_triangulate, 0,
+	"bernstein-triangulate", 1,
+	"triangulate domains during Bernstein expansion")
+ISL_ARG_BOOL(struct isl_options, pip_symmetry, 0, "pip-symmetry", 1,
+	"detect simple symmetries in PIP input")
+ISL_ARG_CHOICE(struct isl_options, convex, 0, "convex-hull", \
+	convex,	ISL_CONVEX_HULL_WRAP, "convex hull algorithm to use")
+ISL_ARG_BOOL(struct isl_options, coalesce_bounded_wrapping, 0,
+	"coalesce-bounded-wrapping", 1, "bound wrapping during coalescing")
+ISL_ARG_INT(struct isl_options, schedule_max_coefficient, 0,
+	"schedule-max-coefficient", "limit", -1, "Only consider schedules "
+	"where the coefficients of the variable and parameter dimensions "
+        "do not exceed <limit>. A value of -1 allows arbitrary coefficients.")
+ISL_ARG_INT(struct isl_options, schedule_max_constant_term, 0,
+	"schedule-max-constant-term", "limit", -1, "Only consider schedules "
+	"where the coefficients of the constant dimension do not exceed "
+	"<limit>. A value of -1 allows arbitrary coefficients.")
+ISL_ARG_BOOL(struct isl_options, schedule_parametric, 0,
+	"schedule-parametric", 1, "construct possibly parametric schedules")
+ISL_ARG_BOOL(struct isl_options, schedule_outer_coincidence, 0,
+	"schedule-outer-coincidence", 0,
+	"try to construct schedules where the outer member of each band "
+	"satisfies the coincidence constraints")
+ISL_ARG_BOOL(struct isl_options, schedule_maximize_band_depth, 0,
+	"schedule-maximize-band-depth", 0,
+	"maximize the number of scheduling dimensions in a band")
+ISL_ARG_BOOL(struct isl_options, schedule_maximize_coincidence, 0,
+	"schedule-maximize-coincidence", 0,
+	"maximize the number of coincident dimensions in a band")
+ISL_ARG_BOOL(struct isl_options, schedule_split_scaled, 0,
+	"schedule-split-scaled", 1,
+	"split non-tilable bands with scaled schedules")
+ISL_ARG_BOOL(struct isl_options, schedule_treat_coalescing, 0,
+	"schedule-treat-coalescing", 1,
+	"try and prevent or adjust schedules that perform loop coalescing")
+ISL_ARG_BOOL(struct isl_options, schedule_separate_components, 0,
+	"schedule-separate-components", 1,
+	"separate components in dependence graph")
+ISL_ARG_BOOL(struct isl_options, schedule_whole_component, 0,
+	"schedule-whole-component", 1,
+	"try and compute schedule for entire component first")
+ISL_ARG_CHOICE(struct isl_options, schedule_algorithm, 0,
+	"schedule-algorithm", isl_schedule_algorithm_choice,
+	ISL_SCHEDULE_ALGORITHM_ISL, "scheduling algorithm to use")
+ISL_ARG_BOOL(struct isl_options, schedule_carry_self_first, 0,
+	"schedule-carry-self-first", 1, "try and carry self-dependences first")
+ISL_ARG_BOOL(struct isl_options, schedule_serialize_sccs, 0,
+	"schedule-serialize-sccs", 0,
+	"serialize strongly connected components in dependence graph")
+ISL_ARG_PHANTOM_USER_CHOICE_F(0, "schedule-fuse", fuse, &set_fuse,
+	ISL_SCHEDULE_FUSE_MAX, "level of fusion during scheduling",
+	ISL_ARG_HIDDEN)
+ISL_ARG_BOOL(struct isl_options, tile_scale_tile_loops, 0,
+	"tile-scale-tile-loops", 1, "scale tile loops")
+ISL_ARG_BOOL(struct isl_options, tile_shift_point_loops, 0,
+	"tile-shift-point-loops", 1, "shift point loops to start at zero")
+ISL_ARG_STR(struct isl_options, ast_iterator_type, 0,
+	"ast-iterator-type", "type", "int",
+	"type used for iterators during printing of AST")
+ISL_ARG_BOOL(struct isl_options, ast_always_print_block, 0,
+	"ast-always-print-block", 0, "print for and if bodies as a block "
+	"regardless of the number of statements in the body")
+ISL_ARG_BOOL(struct isl_options, ast_print_macro_once, 0,
+	"ast-print-macro-once", 0, "only print macro definitions once")
+ISL_ARG_BOOL(struct isl_options, ast_build_atomic_upper_bound, 0,
+	"ast-build-atomic-upper-bound", 1, "generate atomic upper bounds")
+ISL_ARG_BOOL(struct isl_options, ast_build_prefer_pdiv, 0,
+	"ast-build-prefer-pdiv", 1, "prefer pdiv operation over fdiv")
+ISL_ARG_BOOL(struct isl_options, ast_build_detect_min_max, 0,
+	"ast-build-detect-min-max", 0, "detect min/max expressions")
+ISL_ARG_BOOL(struct isl_options, ast_build_exploit_nested_bounds, 0,
+	"ast-build-exploit-nested-bounds", 1,
+	"simplify conditions based on bounds of nested for loops")
+ISL_ARG_BOOL(struct isl_options, ast_build_group_coscheduled, 0,
+	"ast-build-group-coscheduled", 0,
+	"keep coscheduled domain elements together")
+ISL_ARG_CHOICE(struct isl_options, ast_build_separation_bounds, 0,
+	"ast-build-separation-bounds", separation_bounds,
+	ISL_AST_BUILD_SEPARATION_BOUNDS_EXPLICIT,
+	"bounds to use during separation")
+ISL_ARG_BOOL(struct isl_options, ast_build_scale_strides, 0,
+	"ast-build-scale-strides", 1,
+	"allow iterators of strided loops to be scaled down")
+ISL_ARG_BOOL(struct isl_options, ast_build_allow_else, 0,
+	"ast-build-allow-else", 1, "generate if statements with else branches")
+ISL_ARG_BOOL(struct isl_options, ast_build_allow_or, 0,
+	"ast-build-allow-or", 1, "generate if conditions with disjunctions")
+ISL_ARG_BOOL(struct isl_options, print_stats, 0, "print-stats", 0,
+	"print statistics for every isl_ctx")
+ISL_ARG_ULONG(struct isl_options, max_operations, 0,
+	"max-operations", 0, "default number of maximal operations per isl_ctx")
+ISL_ARG_VERSION(print_version)
+ISL_ARGS_END
+
+ISL_ARG_DEF(isl_options, struct isl_options, isl_options_args)
+
+ISL_ARG_CTX_DEF(isl_options, struct isl_options, isl_options_args)
+
+ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args, bound)
+ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args, bound)
+
+ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	on_error)
+ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	on_error)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	pip_symmetry)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	pip_symmetry)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	coalesce_bounded_wrapping)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	coalesce_bounded_wrapping)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	gbr_only_first)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	gbr_only_first)
+
+ISL_CTX_SET_INT_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_max_coefficient)
+ISL_CTX_GET_INT_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_max_coefficient)
+
+ISL_CTX_SET_INT_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_max_constant_term)
+ISL_CTX_GET_INT_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_max_constant_term)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_maximize_band_depth)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_maximize_band_depth)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_maximize_coincidence)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_maximize_coincidence)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_split_scaled)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_split_scaled)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_treat_coalescing)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_treat_coalescing)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_separate_components)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_separate_components)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_whole_component)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_whole_component)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_outer_coincidence)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_outer_coincidence)
+
+ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_algorithm)
+ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_algorithm)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_carry_self_first)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_carry_self_first)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_serialize_sccs)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	schedule_serialize_sccs)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	tile_scale_tile_loops)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	tile_scale_tile_loops)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	tile_shift_point_loops)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	tile_shift_point_loops)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_atomic_upper_bound)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_atomic_upper_bound)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_prefer_pdiv)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_prefer_pdiv)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_detect_min_max)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_detect_min_max)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_exploit_nested_bounds)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_exploit_nested_bounds)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_group_coscheduled)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_group_coscheduled)
+
+ISL_CTX_SET_STR_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_iterator_type)
+ISL_CTX_GET_STR_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_iterator_type)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_always_print_block)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_always_print_block)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_print_macro_once)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_print_macro_once)
+
+ISL_CTX_SET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_separation_bounds)
+ISL_CTX_GET_CHOICE_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_separation_bounds)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_scale_strides)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_scale_strides)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_allow_else)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_allow_else)
+
+ISL_CTX_SET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_allow_or)
+ISL_CTX_GET_BOOL_DEF(isl_options, struct isl_options, isl_options_args,
+	ast_build_allow_or)
diff --git a/final/lib/External/isl/isl_options_private.h b/final/lib/External/isl/isl_options_private.h
new file mode 100644
index 0000000..13f21a7
--- /dev/null
+++ b/final/lib/External/isl/isl_options_private.h
@@ -0,0 +1,73 @@
+#ifndef ISL_OPTIONS_PRIVATE_H
+#define ISL_OPTIONS_PRIVATE_H
+
+#include <isl/options.h>
+
+struct isl_options {
+	#define			ISL_CONTEXT_GBR		0
+	#define			ISL_CONTEXT_LEXMIN	1
+	unsigned		context;
+
+	#define			ISL_GBR_NEVER	0
+	#define			ISL_GBR_ONCE	1
+	#define			ISL_GBR_ALWAYS	2
+	unsigned		gbr;
+	unsigned		gbr_only_first;
+
+	#define			ISL_CLOSURE_ISL		0
+	#define			ISL_CLOSURE_BOX		1
+	unsigned		closure;
+
+	int			bound;
+	unsigned		on_error;
+
+	#define			ISL_BERNSTEIN_FACTORS	1
+	#define			ISL_BERNSTEIN_INTERVALS	2
+	int			bernstein_recurse;
+
+	int			bernstein_triangulate;
+
+	int			pip_symmetry;
+
+	#define			ISL_CONVEX_HULL_WRAP	0
+	#define			ISL_CONVEX_HULL_FM	1
+	int			convex;
+
+	int			coalesce_bounded_wrapping;
+
+	int			schedule_max_coefficient;
+	int			schedule_max_constant_term;
+	int			schedule_parametric;
+	int			schedule_outer_coincidence;
+	int			schedule_maximize_band_depth;
+	int			schedule_maximize_coincidence;
+	int			schedule_split_scaled;
+	int			schedule_treat_coalescing;
+	int			schedule_separate_components;
+	int			schedule_whole_component;
+	unsigned		schedule_algorithm;
+	int			schedule_carry_self_first;
+	int			schedule_serialize_sccs;
+
+	int			tile_scale_tile_loops;
+	int			tile_shift_point_loops;
+
+	char			*ast_iterator_type;
+	int			ast_always_print_block;
+	int			ast_print_macro_once;
+
+	int			ast_build_atomic_upper_bound;
+	int			ast_build_prefer_pdiv;
+	int			ast_build_detect_min_max;
+	int			ast_build_exploit_nested_bounds;
+	int			ast_build_group_coscheduled;
+	int			ast_build_separation_bounds;
+	int			ast_build_scale_strides;
+	int			ast_build_allow_else;
+	int			ast_build_allow_or;
+
+	int			print_stats;
+	unsigned long		max_operations;
+};
+
+#endif
diff --git a/final/lib/External/isl/isl_output.c b/final/lib/External/isl/isl_output.c
new file mode 100644
index 0000000..93442a9
--- /dev/null
+++ b/final/lib/External/isl/isl_output.c
@@ -0,0 +1,3148 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/set.h>
+#include <isl_seq.h>
+#include <isl_polynomial_private.h>
+#include <isl_printer_private.h>
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl/union_map.h>
+#include <isl/constraint.h>
+#include <isl_local_space_private.h>
+#include <isl_aff_private.h>
+#include <isl_val_private.h>
+#include <isl_constraint_private.h>
+#include <isl/ast_build.h>
+#include <isl_sort.h>
+#include <isl_output_private.h>
+
+#include <bset_to_bmap.c>
+#include <set_to_map.c>
+
+static const char *s_to[2] = { " -> ", " \\to " };
+static const char *s_and[2] = { " and ", " \\wedge " };
+static const char *s_or[2] = { " or ", " \\vee " };
+static const char *s_le[2] = { "<=", "\\le" };
+static const char *s_ge[2] = { ">=", "\\ge" };
+static const char *s_open_set[2] = { "{ ", "\\{\\, " };
+static const char *s_close_set[2] = { " }", " \\,\\}" };
+static const char *s_open_list[2] = { "[", "(" };
+static const char *s_close_list[2] = { "]", ")" };
+static const char *s_such_that[2] = { " : ", " \\mid " };
+static const char *s_open_exists[2] = { "exists (", "\\exists \\, " };
+static const char *s_close_exists[2] = { ")", "" };
+static const char *s_div_prefix[2] = { "e", "\\alpha_" };
+static const char *s_param_prefix[2] = { "p", "p_" };
+static const char *s_input_prefix[2] = { "i", "i_" };
+static const char *s_output_prefix[2] = { "o", "o_" };
+
+static __isl_give isl_printer *print_constraint_polylib(
+	struct isl_basic_map *bmap, int ineq, int n, __isl_take isl_printer *p)
+{
+	int i;
+	unsigned n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	unsigned n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	unsigned nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	isl_int *c = ineq ? bmap->ineq[n] : bmap->eq[n];
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_int(p, ineq);
+	for (i = 0; i < n_out; ++i) {
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_isl_int(p, c[1+nparam+n_in+i]);
+	}
+	for (i = 0; i < n_in; ++i) {
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_isl_int(p, c[1+nparam+i]);
+	}
+	for (i = 0; i < bmap->n_div; ++i) {
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_isl_int(p, c[1+nparam+n_in+n_out+i]);
+	}
+	for (i = 0; i < nparam; ++i) {
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_isl_int(p, c[1+i]);
+	}
+	p = isl_printer_print_str(p, " ");
+	p = isl_printer_print_isl_int(p, c[0]);
+	p = isl_printer_end_line(p);
+	return p;
+}
+
+static __isl_give isl_printer *print_constraints_polylib(
+	struct isl_basic_map *bmap, __isl_take isl_printer *p)
+{
+	int i;
+
+	p = isl_printer_set_isl_int_width(p, 5);
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		p = print_constraint_polylib(bmap, 0, i, p);
+	for (i = 0; i < bmap->n_ineq; ++i)
+		p = print_constraint_polylib(bmap, 1, i, p);
+
+	return p;
+}
+
+static __isl_give isl_printer *bset_print_constraints_polylib(
+	struct isl_basic_set *bset, __isl_take isl_printer *p)
+{
+	return print_constraints_polylib(bset_to_bmap(bset), p);
+}
+
+static __isl_give isl_printer *isl_basic_map_print_polylib(
+	__isl_keep isl_basic_map *bmap, __isl_take isl_printer *p, int ext)
+{
+	unsigned total = isl_basic_map_total_dim(bmap);
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_int(p, bmap->n_eq + bmap->n_ineq);
+	p = isl_printer_print_str(p, " ");
+	p = isl_printer_print_int(p, 1 + total + 1);
+	if (ext) {
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_int(p,
+				    isl_basic_map_dim(bmap, isl_dim_out));
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_int(p,
+				    isl_basic_map_dim(bmap, isl_dim_in));
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_int(p,
+				    isl_basic_map_dim(bmap, isl_dim_div));
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_int(p,
+				    isl_basic_map_dim(bmap, isl_dim_param));
+	}
+	p = isl_printer_end_line(p);
+	return print_constraints_polylib(bmap, p);
+}
+
+static __isl_give isl_printer *isl_basic_set_print_polylib(
+	__isl_keep isl_basic_set *bset, __isl_take isl_printer *p, int ext)
+{
+	return isl_basic_map_print_polylib(bset_to_bmap(bset), p, ext);
+}
+
+static __isl_give isl_printer *isl_map_print_polylib(__isl_keep isl_map *map,
+	__isl_take isl_printer *p, int ext)
+{
+	int i;
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_int(p, map->n);
+	p = isl_printer_end_line(p);
+	for (i = 0; i < map->n; ++i) {
+		p = isl_printer_start_line(p);
+		p = isl_printer_end_line(p);
+		p = isl_basic_map_print_polylib(map->p[i], p, ext);
+	}
+	return p;
+}
+
+static __isl_give isl_printer *isl_set_print_polylib(__isl_keep isl_set *set,
+	__isl_take isl_printer *p, int ext)
+{
+	return isl_map_print_polylib(set_to_map(set), p, ext);
+}
+
+static int count_same_name(__isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned pos, const char *name)
+{
+	enum isl_dim_type t;
+	unsigned p, s;
+	int count = 0;
+
+	for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) {
+		s = t == type ? pos : isl_space_dim(dim, t);
+		for (p = 0; p < s; ++p) {
+			const char *n = isl_space_get_dim_name(dim, t, p);
+			if (n && !strcmp(n, name))
+				count++;
+		}
+	}
+	return count;
+}
+
+/* Print the name of the variable of type "type" and position "pos"
+ * in "space" to "p".
+ */
+static __isl_give isl_printer *print_name(__isl_keep isl_space *space,
+	__isl_take isl_printer *p, enum isl_dim_type type, unsigned pos,
+	int latex)
+{
+	const char *name;
+	char buffer[20];
+	int primes;
+
+	name = type == isl_dim_div ? NULL
+				   : isl_space_get_dim_name(space, type, pos);
+
+	if (!name) {
+		const char *prefix;
+		if (type == isl_dim_param)
+			prefix = s_param_prefix[latex];
+		else if (type == isl_dim_div)
+			prefix = s_div_prefix[latex];
+		else if (isl_space_is_set(space) || type == isl_dim_in)
+			prefix = s_input_prefix[latex];
+		else
+			prefix = s_output_prefix[latex];
+		snprintf(buffer, sizeof(buffer), "%s%d", prefix, pos);
+		name = buffer;
+	}
+	primes = count_same_name(space, name == buffer ? isl_dim_div : type,
+				 pos, name);
+	p = isl_printer_print_str(p, name);
+	while (primes-- > 0)
+		p = isl_printer_print_str(p, "'");
+	return p;
+}
+
+static enum isl_dim_type pos2type(__isl_keep isl_space *dim, unsigned *pos)
+{
+	enum isl_dim_type type;
+	unsigned n_in = isl_space_dim(dim, isl_dim_in);
+	unsigned n_out = isl_space_dim(dim, isl_dim_out);
+	unsigned nparam = isl_space_dim(dim, isl_dim_param);
+
+	if (*pos < 1 + nparam) {
+		type = isl_dim_param;
+		*pos -= 1;
+	} else if (*pos < 1 + nparam + n_in) {
+		type = isl_dim_in;
+		*pos -= 1 + nparam;
+	} else if (*pos < 1 + nparam + n_in + n_out) {
+		type = isl_dim_out;
+		*pos -= 1 + nparam + n_in;
+	} else {
+		type = isl_dim_div;
+		*pos -= 1 + nparam + n_in + n_out;
+	}
+
+	return type;
+}
+
+/* Can the div expression of the integer division at position "row" of "div"
+ * be printed?
+ * In particular, are the div expressions available and does the selected
+ * variable have a known explicit representation?
+ * Furthermore, the Omega format does not allow any div expressions
+ * to be printed.
+ */
+static isl_bool can_print_div_expr(__isl_keep isl_printer *p,
+	__isl_keep isl_mat *div, int pos)
+{
+	if (p->output_format == ISL_FORMAT_OMEGA)
+		return isl_bool_false;
+	if (!div)
+		return isl_bool_false;
+	return !isl_int_is_zero(div->row[pos][0]);
+}
+
+static __isl_give isl_printer *print_div(__isl_keep isl_space *dim,
+	__isl_keep isl_mat *div, int pos, __isl_take isl_printer *p);
+
+static __isl_give isl_printer *print_term(__isl_keep isl_space *space,
+	__isl_keep isl_mat *div,
+	isl_int c, unsigned pos, __isl_take isl_printer *p, int latex)
+{
+	enum isl_dim_type type;
+	int print_div_def;
+
+	if (pos == 0)
+		return isl_printer_print_isl_int(p, c);
+
+	type = pos2type(space, &pos);
+	print_div_def = type == isl_dim_div && can_print_div_expr(p, div, pos);
+
+	if (isl_int_is_one(c))
+		;
+	else if (isl_int_is_negone(c))
+		p = isl_printer_print_str(p, "-");
+	else {
+		p = isl_printer_print_isl_int(p, c);
+		if (p->output_format == ISL_FORMAT_C || print_div_def)
+			p = isl_printer_print_str(p, "*");
+	}
+	if (print_div_def)
+		p = print_div(space, div, pos, p);
+	else
+		p = print_name(space, p, type, pos, latex);
+	return p;
+}
+
+static __isl_give isl_printer *print_affine_of_len(__isl_keep isl_space *dim,
+	__isl_keep isl_mat *div,
+	__isl_take isl_printer *p, isl_int *c, int len)
+{
+	int i;
+	int first;
+
+	for (i = 0, first = 1; i < len; ++i) {
+		int flip = 0;
+		if (isl_int_is_zero(c[i]))
+			continue;
+		if (!first) {
+			if (isl_int_is_neg(c[i])) {
+				flip = 1;
+				isl_int_neg(c[i], c[i]);
+				p = isl_printer_print_str(p, " - ");
+			} else 
+				p = isl_printer_print_str(p, " + ");
+		}
+		first = 0;
+		p = print_term(dim, div, c[i], i, p, 0);
+		if (flip)
+			isl_int_neg(c[i], c[i]);
+	}
+	if (first)
+		p = isl_printer_print_str(p, "0");
+	return p;
+}
+
+/* Print an affine expression "c" corresponding to a constraint in "bmap"
+ * to "p", with the variable names taken from "space" and
+ * the integer division definitions taken from "div".
+ */
+static __isl_give isl_printer *print_affine(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_space *space, __isl_keep isl_mat *div,
+	__isl_take isl_printer *p, isl_int *c)
+{
+	unsigned len = 1 + isl_basic_map_total_dim(bmap);
+	return print_affine_of_len(space, div, p, c, len);
+}
+
+/* offset is the offset of local_dim inside data->type of data->space.
+ */
+static __isl_give isl_printer *print_nested_var_list(__isl_take isl_printer *p,
+	__isl_keep isl_space *local_dim, enum isl_dim_type local_type,
+	struct isl_print_space_data *data, int offset)
+{
+	int i;
+
+	if (data->space != local_dim && local_type == isl_dim_out)
+		offset += local_dim->n_in;
+
+	for (i = 0; i < isl_space_dim(local_dim, local_type); ++i) {
+		if (i)
+			p = isl_printer_print_str(p, ", ");
+		if (data->print_dim)
+			p = data->print_dim(p, data, offset + i);
+		else
+			p = print_name(data->space, p, data->type, offset + i,
+					data->latex);
+	}
+	return p;
+}
+
+static __isl_give isl_printer *print_var_list(__isl_take isl_printer *p,
+	__isl_keep isl_space *space, enum isl_dim_type type)
+{
+	struct isl_print_space_data data = { .space = space, .type = type };
+
+	return print_nested_var_list(p, space, type, &data, 0);
+}
+
+static __isl_give isl_printer *print_nested_map_dim(__isl_take isl_printer *p,
+	__isl_keep isl_space *local_dim,
+	struct isl_print_space_data *data, int offset);
+
+static __isl_give isl_printer *print_nested_tuple(__isl_take isl_printer *p,
+	__isl_keep isl_space *local_dim, enum isl_dim_type local_type,
+	struct isl_print_space_data *data, int offset)
+{
+	const char *name = NULL;
+	unsigned n = isl_space_dim(local_dim, local_type);
+	if ((local_type == isl_dim_in || local_type == isl_dim_out)) {
+		name = isl_space_get_tuple_name(local_dim, local_type);
+		if (name) {
+			if (data->latex)
+				p = isl_printer_print_str(p, "\\mathrm{");
+			p = isl_printer_print_str(p, name);
+			if (data->latex)
+				p = isl_printer_print_str(p, "}");
+		}
+	}
+	if (!data->latex || n != 1 || name)
+		p = isl_printer_print_str(p, s_open_list[data->latex]);
+	if ((local_type == isl_dim_in || local_type == isl_dim_out) &&
+	    local_dim->nested[local_type - isl_dim_in]) {
+		if (data->space != local_dim && local_type == isl_dim_out)
+			offset += local_dim->n_in;
+		p = print_nested_map_dim(p,
+				local_dim->nested[local_type - isl_dim_in],
+				data, offset);
+	} else
+		p = print_nested_var_list(p, local_dim, local_type, data,
+					  offset);
+	if (!data->latex || n != 1 || name)
+		p = isl_printer_print_str(p, s_close_list[data->latex]);
+	return p;
+}
+
+static __isl_give isl_printer *print_tuple(__isl_keep isl_space *dim,
+	__isl_take isl_printer *p, enum isl_dim_type type,
+	struct isl_print_space_data *data)
+{
+	data->space = dim;
+	data->type = type;
+	return print_nested_tuple(p, dim, type, data, 0);
+}
+
+static __isl_give isl_printer *print_nested_map_dim(__isl_take isl_printer *p,
+	__isl_keep isl_space *local_dim,
+	struct isl_print_space_data *data, int offset)
+{
+	p = print_nested_tuple(p, local_dim, isl_dim_in, data, offset);
+	p = isl_printer_print_str(p, s_to[data->latex]);
+	p = print_nested_tuple(p, local_dim, isl_dim_out, data, offset);
+
+	return p;
+}
+
+__isl_give isl_printer *isl_print_space(__isl_keep isl_space *space,
+	__isl_take isl_printer *p, int rational,
+	struct isl_print_space_data *data)
+{
+	if (rational && !data->latex)
+		p = isl_printer_print_str(p, "rat: ");
+	if (isl_space_is_params(space))
+		;
+	else if (isl_space_is_set(space))
+		p = print_tuple(space, p, isl_dim_set, data);
+	else {
+		p = print_tuple(space, p, isl_dim_in, data);
+		p = isl_printer_print_str(p, s_to[data->latex]);
+		p = print_tuple(space, p, isl_dim_out, data);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_omega_parameters(__isl_keep isl_space *dim,
+	__isl_take isl_printer *p)
+{
+	if (isl_space_dim(dim, isl_dim_param) == 0)
+		return p;
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "symbolic ");
+	p = print_var_list(p, dim, isl_dim_param);
+	p = isl_printer_print_str(p, ";");
+	p = isl_printer_end_line(p);
+	return p;
+}
+
+/* Does the inequality constraint following "i" in "bmap"
+ * have an opposite value for the same last coefficient?
+ * "last" is the position of the last coefficient of inequality "i".
+ * If the next constraint is a div constraint, then it is ignored
+ * since div constraints are not printed.
+ */
+static int next_is_opposite(__isl_keep isl_basic_map *bmap, int i, int last)
+{
+	unsigned total = isl_basic_map_total_dim(bmap);
+	unsigned o_div = isl_basic_map_offset(bmap, isl_dim_div);
+
+	if (i + 1 >= bmap->n_ineq)
+		return 0;
+	if (isl_seq_last_non_zero(bmap->ineq[i + 1], 1 + total) != last)
+		return 0;
+	if (last >= o_div) {
+		isl_bool is_div;
+		is_div = isl_basic_map_is_div_constraint(bmap,
+					    bmap->ineq[i + 1], last - o_div);
+		if (is_div < 0)
+			return -1;
+		if (is_div)
+			return 0;
+	}
+	return isl_int_abs_eq(bmap->ineq[i][last], bmap->ineq[i + 1][last]) &&
+		!isl_int_eq(bmap->ineq[i][last], bmap->ineq[i + 1][last]);
+}
+
+/* Return a string representation of the operator used when
+ * printing a constraint where the LHS is greater than or equal to the LHS
+ * (sign > 0) or smaller than or equal to the LHS (sign < 0).
+ * If "strict" is set, then return the strict version of the comparison
+ * operator.
+ */
+static const char *constraint_op(int sign, int strict, int latex)
+{
+	if (strict)
+		return sign < 0 ? "<" : ">";
+	if (sign < 0)
+		return s_le[latex];
+	else
+		return s_ge[latex];
+}
+
+/* Print one side of a constraint "c" from "bmap" to "p", with
+ * the variable names taken from "space" and the integer division definitions
+ * taken from "div".
+ * "last" is the position of the last non-zero coefficient.
+ * Let c' be the result of zeroing out this coefficient, then
+ * the partial constraint
+ *
+ *	c' op
+ *
+ * is printed.
+ * "first_constraint" is set if this is the first constraint
+ * in the conjunction.
+ */
+static __isl_give isl_printer *print_half_constraint(
+	__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_space *space, __isl_keep isl_mat *div,
+	__isl_take isl_printer *p, isl_int *c, int last, const char *op,
+	int first_constraint, int latex)
+{
+	if (!first_constraint)
+		p = isl_printer_print_str(p, s_and[latex]);
+
+	isl_int_set_si(c[last], 0);
+	p = print_affine(bmap, space, div, p, c);
+
+	p = isl_printer_print_str(p, " ");
+	p = isl_printer_print_str(p, op);
+	p = isl_printer_print_str(p, " ");
+
+	return p;
+}
+
+/* Print a constraint "c" from "bmap" to "p", with the variable names
+ * taken from "space" and the integer division definitions taken from "div".
+ * "last" is the position of the last non-zero coefficient, which is
+ * moreover assumed to be negative.
+ * Let c' be the result of zeroing out this coefficient, then
+ * the constraint is printed in the form
+ *
+ *	-c[last] op c'
+ *
+ * "first_constraint" is set if this is the first constraint
+ * in the conjunction.
+ */
+static __isl_give isl_printer *print_constraint(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_space *space, __isl_keep isl_mat *div,
+	__isl_take isl_printer *p,
+	isl_int *c, int last, const char *op, int first_constraint, int latex)
+{
+	if (!first_constraint)
+		p = isl_printer_print_str(p, s_and[latex]);
+
+	isl_int_abs(c[last], c[last]);
+
+	p = print_term(space, div, c[last], last, p, latex);
+
+	p = isl_printer_print_str(p, " ");
+	p = isl_printer_print_str(p, op);
+	p = isl_printer_print_str(p, " ");
+
+	isl_int_set_si(c[last], 0);
+	p = print_affine(bmap, space, div, p, c);
+
+	return p;
+}
+
+/* Print the constraints of "bmap" to "p".
+ * The names of the variables are taken from "space" and
+ * the integer division definitions are taken from "div".
+ * Div constraints are only printed in "dump" mode.
+ * The constraints are sorted prior to printing (except in "dump" mode).
+ *
+ * If x is the last variable with a non-zero coefficient,
+ * then a lower bound
+ *
+ *	f - a x >= 0
+ *
+ * is printed as
+ *
+ *	a x <= f
+ *
+ * while an upper bound
+ *
+ *	f + a x >= 0
+ *
+ * is printed as
+ *
+ *	a x >= -f
+ *
+ * If the next constraint has an opposite sign for the same last coefficient,
+ * then it is printed as
+ *
+ *	f >= a x
+ *
+ * or
+ *
+ *	-f <= a x
+ *
+ * instead.  In fact, the "a x" part is not printed explicitly, but
+ * reused from the next constraint, which is therefore treated as
+ * a first constraint in the conjunction.
+ *
+ * If the constant term of "f" is -1, then "f" is replaced by "f + 1" and
+ * the comparison operator is replaced by the strict variant.
+ * Essentially, ">= 1" is replaced by "> 0".
+ */
+static __isl_give isl_printer *print_constraints(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_space *space, __isl_keep isl_mat *div,
+	__isl_take isl_printer *p, int latex)
+{
+	int i;
+	isl_vec *c = NULL;
+	int rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+	unsigned total = isl_basic_map_total_dim(bmap);
+	unsigned o_div = isl_basic_map_offset(bmap, isl_dim_div);
+	int first = 1;
+	int dump;
+
+	if (!p)
+		return NULL;
+	bmap = isl_basic_map_copy(bmap);
+	dump = p->dump;
+	if (!dump)
+		bmap = isl_basic_map_sort_constraints(bmap);
+	if (!bmap)
+		goto error;
+
+	c = isl_vec_alloc(bmap->ctx, 1 + total);
+	if (!c)
+		goto error;
+
+	for (i = bmap->n_eq - 1; i >= 0; --i) {
+		int l = isl_seq_last_non_zero(bmap->eq[i], 1 + total);
+		if (l < 0) {
+			if (i != bmap->n_eq - 1)
+				p = isl_printer_print_str(p, s_and[latex]);
+			p = isl_printer_print_str(p, "0 = 0");
+			continue;
+		}
+		if (isl_int_is_neg(bmap->eq[i][l]))
+			isl_seq_cpy(c->el, bmap->eq[i], 1 + total);
+		else
+			isl_seq_neg(c->el, bmap->eq[i], 1 + total);
+		p = print_constraint(bmap, space, div, p, c->el, l,
+				    "=", first, latex);
+		first = 0;
+	}
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		int l = isl_seq_last_non_zero(bmap->ineq[i], 1 + total);
+		int strict;
+		int s;
+		const char *op;
+		if (l < 0)
+			continue;
+		if (!dump && l >= o_div &&
+		    can_print_div_expr(p, div, l - o_div)) {
+			isl_bool is_div;
+			is_div = isl_basic_map_is_div_constraint(bmap,
+						    bmap->ineq[i], l - o_div);
+			if (is_div < 0)
+				goto error;
+			if (is_div)
+				continue;
+		}
+		s = isl_int_sgn(bmap->ineq[i][l]);
+		strict = !rational && isl_int_is_negone(bmap->ineq[i][0]);
+		if (s < 0)
+			isl_seq_cpy(c->el, bmap->ineq[i], 1 + total);
+		else
+			isl_seq_neg(c->el, bmap->ineq[i], 1 + total);
+		if (strict)
+			isl_int_set_si(c->el[0], 0);
+		if (!dump && next_is_opposite(bmap, i, l)) {
+			op = constraint_op(-s, strict, latex);
+			p = print_half_constraint(bmap, space, div, p, c->el, l,
+						op, first, latex);
+			first = 1;
+		} else {
+			op = constraint_op(s, strict, latex);
+			p = print_constraint(bmap, space, div, p, c->el, l,
+						op, first, latex);
+			first = 0;
+		}
+	}
+
+	isl_basic_map_free(bmap);
+	isl_vec_free(c);
+
+	return p;
+error:
+	isl_basic_map_free(bmap);
+	isl_vec_free(c);
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_div(__isl_keep isl_space *dim,
+	__isl_keep isl_mat *div, int pos, __isl_take isl_printer *p)
+{
+	int c;
+
+	if (!p || !div)
+		return isl_printer_free(p);
+
+	c = p->output_format == ISL_FORMAT_C;
+	p = isl_printer_print_str(p, c ? "floord(" : "floor((");
+	p = print_affine_of_len(dim, div, p,
+				div->row[pos] + 1, div->n_col - 1);
+	p = isl_printer_print_str(p, c ? ", " : ")/");
+	p = isl_printer_print_isl_int(p, div->row[pos][0]);
+	p = isl_printer_print_str(p, ")");
+	return p;
+}
+
+/* Print a comma separated list of div names, except those that have
+ * a definition that can be printed.
+ * If "print_defined_divs" is set, then those div names are printed
+ * as well, along with their definitions.
+ */
+static __isl_give isl_printer *print_div_list(__isl_take isl_printer *p,
+	__isl_keep isl_space *space, __isl_keep isl_mat *div, int latex,
+	int print_defined_divs)
+{
+	int i;
+	int first = 1;
+	unsigned n_div;
+
+	if (!p || !space || !div)
+		return isl_printer_free(p);
+
+	n_div = isl_mat_rows(div);
+
+	for (i = 0; i < n_div; ++i) {
+		if (!print_defined_divs && can_print_div_expr(p, div, i))
+			continue;
+		if (!first)
+			p = isl_printer_print_str(p, ", ");
+		p = print_name(space, p, isl_dim_div, i, latex);
+		first = 0;
+		if (!can_print_div_expr(p, div, i))
+			continue;
+		p = isl_printer_print_str(p, " = ");
+		p = print_div(space, div, i, p);
+	}
+
+	return p;
+}
+
+/* Does printing an object with local variables described by "div"
+ * require an "exists" clause?
+ * That is, are there any local variables without an explicit representation?
+ * An exists clause is also needed in "dump" mode because
+ * explicit div representations are not printed inline in that case.
+ */
+static isl_bool need_exists(__isl_keep isl_printer *p, __isl_keep isl_mat *div)
+{
+	int i, n;
+
+	if (!p || !div)
+		return isl_bool_error;
+	n = isl_mat_rows(div);
+	if (n == 0)
+		return isl_bool_false;
+	if (p->dump)
+		return isl_bool_true;
+	for (i = 0; i < n; ++i)
+		if (!can_print_div_expr(p, div, i))
+			return isl_bool_true;
+	return isl_bool_false;
+}
+
+/* Print the start of an exists clause, i.e.,
+ *
+ *	(exists variables:
+ *
+ * In dump mode, local variables with an explicit definition are printed
+ * as well because they will not be printed inline.
+ */
+static __isl_give isl_printer *open_exists(__isl_take isl_printer *p,
+	__isl_keep isl_space *space, __isl_keep isl_mat *div, int latex)
+{
+	int dump;
+
+	if (!p)
+		return NULL;
+
+	dump = p->dump;
+	p = isl_printer_print_str(p, s_open_exists[latex]);
+	p = print_div_list(p, space, div, latex, dump);
+	p = isl_printer_print_str(p, ": ");
+
+	return p;
+}
+
+/* Print the constraints of "bmap" to "p".
+ * The names of the variables are taken from "space".
+ * "latex" is set if the constraints should be printed in LaTeX format.
+ * Do not print inline explicit div representations in "dump" mode.
+ */
+static __isl_give isl_printer *print_disjunct(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_space *space, __isl_take isl_printer *p, int latex)
+{
+	int dump;
+	isl_mat *div;
+	isl_bool exists;
+
+	if (!p)
+		return NULL;
+	dump = p->dump;
+	div = isl_basic_map_get_divs(bmap);
+	exists = need_exists(p, div);
+	if (exists >= 0 && exists)
+		p = open_exists(p, space, div, latex);
+
+	if (dump)
+		div = isl_mat_free(div);
+	p = print_constraints(bmap, space, div, p, latex);
+	isl_mat_free(div);
+
+	if (exists >= 0 && exists)
+		p = isl_printer_print_str(p, s_close_exists[latex]);
+	return p;
+}
+
+/* Print a colon followed by the constraints of "bmap"
+ * to "p", provided there are any constraints.
+ * The names of the variables are taken from "space".
+ * "latex" is set if the constraints should be printed in LaTeX format.
+ */
+static __isl_give isl_printer *print_optional_disjunct(
+	__isl_keep isl_basic_map *bmap, __isl_keep isl_space *space,
+	__isl_take isl_printer *p, int latex)
+{
+	if (isl_basic_map_plain_is_universe(bmap))
+		return p;
+
+	p = isl_printer_print_str(p, ": ");
+	p = print_disjunct(bmap, space, p, latex);
+
+	return p;
+}
+
+static __isl_give isl_printer *basic_map_print_omega(
+	__isl_keep isl_basic_map *bmap, __isl_take isl_printer *p)
+{
+	p = isl_printer_print_str(p, "{ [");
+	p = print_var_list(p, bmap->dim, isl_dim_in);
+	p = isl_printer_print_str(p, "] -> [");
+	p = print_var_list(p, bmap->dim, isl_dim_out);
+	p = isl_printer_print_str(p, "] ");
+	p = print_optional_disjunct(bmap, bmap->dim, p, 0);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+static __isl_give isl_printer *basic_set_print_omega(
+	__isl_keep isl_basic_set *bset, __isl_take isl_printer *p)
+{
+	p = isl_printer_print_str(p, "{ [");
+	p = print_var_list(p, bset->dim, isl_dim_set);
+	p = isl_printer_print_str(p, "] ");
+	p = print_optional_disjunct(bset, bset->dim, p, 0);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+static __isl_give isl_printer *isl_map_print_omega(__isl_keep isl_map *map,
+	__isl_take isl_printer *p)
+{
+	int i;
+
+	for (i = 0; i < map->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, " union ");
+		p = basic_map_print_omega(map->p[i], p);
+	}
+	return p;
+}
+
+static __isl_give isl_printer *isl_set_print_omega(__isl_keep isl_set *set,
+	__isl_take isl_printer *p)
+{
+	int i;
+
+	for (i = 0; i < set->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, " union ");
+		p = basic_set_print_omega(set->p[i], p);
+	}
+	return p;
+}
+
+/* Print the list of parameters in "space", followed by an arrow, to "p",
+ * if there are any parameters.
+ */
+static __isl_give isl_printer *print_param_tuple(__isl_take isl_printer *p,
+	__isl_keep isl_space *space, struct isl_print_space_data *data)
+{
+	if (!p || !space)
+		return isl_printer_free(p);
+	if (isl_space_dim(space, isl_dim_param) == 0)
+		return p;
+
+	p = print_tuple(space, p, isl_dim_param, data);
+	p = isl_printer_print_str(p, s_to[data->latex]);
+
+	return p;
+}
+
+static __isl_give isl_printer *isl_basic_map_print_isl(
+	__isl_keep isl_basic_map *bmap, __isl_take isl_printer *p,
+	int latex)
+{
+	struct isl_print_space_data data = { .latex = latex };
+	int rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+
+	p = print_param_tuple(p, bmap->dim, &data);
+	p = isl_printer_print_str(p, "{ ");
+	p = isl_print_space(bmap->dim, p, rational, &data);
+	p = isl_printer_print_str(p, " : ");
+	p = print_disjunct(bmap, bmap->dim, p, latex);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+/* Print the disjuncts of a map (or set) "map" to "p".
+ * The names of the variables are taken from "space".
+ * "latex" is set if the constraints should be printed in LaTeX format.
+ */
+static __isl_give isl_printer *print_disjuncts_core(__isl_keep isl_map *map,
+	__isl_keep isl_space *space, __isl_take isl_printer *p, int latex)
+{
+	int i;
+
+	if (map->n == 0)
+		p = isl_printer_print_str(p, "1 = 0");
+	for (i = 0; i < map->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, s_or[latex]);
+		if (map->n > 1 && map->p[i]->n_eq + map->p[i]->n_ineq > 1)
+			p = isl_printer_print_str(p, "(");
+		p = print_disjunct(map->p[i], space, p, latex);
+		if (map->n > 1 && map->p[i]->n_eq + map->p[i]->n_ineq > 1)
+			p = isl_printer_print_str(p, ")");
+	}
+	return p;
+}
+
+/* Print the disjuncts of a map (or set) "map" to "p".
+ * The names of the variables are taken from "space".
+ * "hull" describes constraints shared by all disjuncts of "map".
+ * "latex" is set if the constraints should be printed in LaTeX format.
+ *
+ * Print the disjuncts as a conjunction of "hull" and
+ * the result of removing the constraints of "hull" from "map".
+ * If this result turns out to be the universe, then simply print "hull".
+ */
+static __isl_give isl_printer *print_disjuncts_in_hull(__isl_keep isl_map *map,
+	__isl_keep isl_space *space, __isl_take isl_basic_map *hull,
+	__isl_take isl_printer *p, int latex)
+{
+	isl_bool is_universe;
+
+	p = print_disjunct(hull, space, p, latex);
+	map = isl_map_plain_gist_basic_map(isl_map_copy(map), hull);
+	is_universe = isl_map_plain_is_universe(map);
+	if (is_universe < 0)
+		goto error;
+	if (!is_universe) {
+		p = isl_printer_print_str(p, s_and[latex]);
+		p = isl_printer_print_str(p, "(");
+		p = print_disjuncts_core(map, space, p, latex);
+		p = isl_printer_print_str(p, ")");
+	}
+	isl_map_free(map);
+
+	return p;
+error:
+	isl_map_free(map);
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print the disjuncts of a map (or set) "map" to "p".
+ * The names of the variables are taken from "space".
+ * "latex" is set if the constraints should be printed in LaTeX format.
+ *
+ * If there are at least two disjuncts and "dump" mode is not turned out,
+ * check for any shared constraints among all disjuncts.
+ * If there are any, then print them separately in print_disjuncts_in_hull.
+ */
+static __isl_give isl_printer *print_disjuncts(__isl_keep isl_map *map,
+	__isl_keep isl_space *space, __isl_take isl_printer *p, int latex)
+{
+	if (isl_map_plain_is_universe(map))
+		return p;
+
+	p = isl_printer_print_str(p, s_such_that[latex]);
+	if (!p)
+		return NULL;
+
+	if (!p->dump && map->n >= 2) {
+		isl_basic_map *hull;
+		isl_bool is_universe;
+
+		hull = isl_map_plain_unshifted_simple_hull(isl_map_copy(map));
+		is_universe = isl_basic_map_plain_is_universe(hull);
+		if (is_universe < 0)
+			p = isl_printer_free(p);
+		else if (!is_universe)
+			return print_disjuncts_in_hull(map, space, hull,
+							p, latex);
+		isl_basic_map_free(hull);
+	}
+
+	return print_disjuncts_core(map, space, p, latex);
+}
+
+/* Print the disjuncts of a map (or set).
+ * The names of the variables are taken from "space".
+ * "latex" is set if the constraints should be printed in LaTeX format.
+ *
+ * If the map turns out to be a universal parameter domain, then
+ * we need to print the colon.  Otherwise, the output looks identical
+ * to the empty set.
+ */
+static __isl_give isl_printer *print_disjuncts_map(__isl_keep isl_map *map,
+	__isl_keep isl_space *space, __isl_take isl_printer *p, int latex)
+{
+	if (isl_map_plain_is_universe(map) && isl_space_is_params(map->dim))
+		return isl_printer_print_str(p, s_such_that[latex]);
+	else
+		return print_disjuncts(map, space, p, latex);
+}
+
+struct isl_aff_split {
+	isl_basic_map *aff;
+	isl_map *map;
+};
+
+static void free_split(__isl_take struct isl_aff_split *split, int n)
+{
+	int i;
+
+	if (!split)
+		return;
+
+	for (i = 0; i < n; ++i) {
+		isl_basic_map_free(split[i].aff);
+		isl_map_free(split[i].map);
+	}
+
+	free(split);
+}
+
+static __isl_give isl_basic_map *get_aff(__isl_take isl_basic_map *bmap)
+{
+	int i, j;
+	unsigned nparam, n_in, n_out, total;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		return NULL;
+	if (isl_basic_map_free_inequality(bmap, bmap->n_ineq) < 0)
+		goto error;
+
+	nparam = isl_basic_map_dim(bmap, isl_dim_param);
+	n_in = isl_basic_map_dim(bmap, isl_dim_in);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+	for (i = bmap->n_eq - 1; i >= 0; --i) {
+		j = isl_seq_last_non_zero(bmap->eq[i] + 1, total);
+		if (j >= nparam && j < nparam + n_in + n_out &&
+		    (isl_int_is_one(bmap->eq[i][1 + j]) ||
+		     isl_int_is_negone(bmap->eq[i][1 + j])))
+			continue;
+		if (isl_basic_map_drop_equality(bmap, i) < 0)
+			goto error;
+	}
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+static int aff_split_cmp(const void *p1, const void *p2, void *user)
+{
+	const struct isl_aff_split *s1, *s2;
+	s1 = (const struct isl_aff_split *) p1;
+	s2 = (const struct isl_aff_split *) p2;
+
+	return isl_basic_map_plain_cmp(s1->aff, s2->aff);
+}
+
+static __isl_give isl_basic_map *drop_aff(__isl_take isl_basic_map *bmap,
+	__isl_keep isl_basic_map *aff)
+{
+	int i, j;
+	unsigned total;
+
+	if (!bmap || !aff)
+		goto error;
+
+	total = isl_space_dim(bmap->dim, isl_dim_all);
+
+	for (i = bmap->n_eq - 1; i >= 0; --i) {
+		if (isl_seq_first_non_zero(bmap->eq[i] + 1 + total,
+					    bmap->n_div) != -1)
+			continue;
+		for (j = 0; j < aff->n_eq; ++j) {
+			if (!isl_seq_eq(bmap->eq[i], aff->eq[j], 1 + total) &&
+			    !isl_seq_is_neg(bmap->eq[i], aff->eq[j], 1 + total))
+				continue;
+			if (isl_basic_map_drop_equality(bmap, i) < 0)
+				goto error;
+			break;
+		}
+	}
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+static __isl_give struct isl_aff_split *split_aff(__isl_keep isl_map *map)
+{
+	int i, n;
+	struct isl_aff_split *split;
+	isl_ctx *ctx;
+
+	ctx = isl_map_get_ctx(map);
+	split = isl_calloc_array(ctx, struct isl_aff_split, map->n);
+	if (!split)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		isl_basic_map *bmap;
+		split[i].aff = get_aff(isl_basic_map_copy(map->p[i]));
+		bmap = isl_basic_map_copy(map->p[i]);
+		bmap = isl_basic_map_cow(bmap);
+		bmap = drop_aff(bmap, split[i].aff);
+		split[i].map = isl_map_from_basic_map(bmap);
+		if (!split[i].aff || !split[i].map)
+			goto error;
+	}
+
+	if (isl_sort(split, map->n, sizeof(struct isl_aff_split),
+			&aff_split_cmp, NULL) < 0)
+		goto error;
+
+	n = map->n;
+	for (i = n - 1; i >= 1; --i) {
+		if (!isl_basic_map_plain_is_equal(split[i - 1].aff,
+						 split[i].aff))
+			continue;
+		isl_basic_map_free(split[i].aff);
+		split[i - 1].map = isl_map_union(split[i - 1].map,
+						 split[i].map);
+		if (i != n - 1)
+			split[i] = split[n - 1];
+		split[n - 1].aff = NULL;
+		split[n - 1].map = NULL;
+		--n;
+	}
+
+	return split;
+error:
+	free_split(split, map->n);
+	return NULL;
+}
+
+static int defining_equality(__isl_keep isl_basic_map *eq,
+	__isl_keep isl_space *dim, enum isl_dim_type type, int pos)
+{
+	int i;
+	unsigned total;
+
+	if (!eq)
+		return -1;
+
+	pos += isl_space_offset(dim, type);
+	total = isl_basic_map_total_dim(eq);
+
+	for (i = 0; i < eq->n_eq; ++i) {
+		if (isl_seq_last_non_zero(eq->eq[i] + 1, total) != pos)
+			continue;
+		if (isl_int_is_one(eq->eq[i][1 + pos]))
+			isl_seq_neg(eq->eq[i], eq->eq[i], 1 + total);
+		return i;
+	}
+
+	return -1;
+}
+
+/* Print dimension "pos" of data->space to "p".
+ *
+ * data->user is assumed to be an isl_basic_map keeping track of equalities.
+ *
+ * If the current dimension is defined by these equalities, then print
+ * the corresponding expression, assigned to the name of the dimension
+ * if there is any.  Otherwise, print the name of the dimension.
+ */
+static __isl_give isl_printer *print_dim_eq(__isl_take isl_printer *p,
+	struct isl_print_space_data *data, unsigned pos)
+{
+	isl_basic_map *eq = data->user;
+	int j;
+
+	j = defining_equality(eq, data->space, data->type, pos);
+	if (j >= 0) {
+		if (isl_space_has_dim_name(data->space, data->type, pos)) {
+			p = print_name(data->space, p, data->type, pos,
+					data->latex);
+			p = isl_printer_print_str(p, " = ");
+		}
+		pos += 1 + isl_space_offset(data->space, data->type);
+		p = print_affine_of_len(data->space, NULL, p, eq->eq[j], pos);
+	} else {
+		p = print_name(data->space, p, data->type, pos, data->latex);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_split_map(__isl_take isl_printer *p,
+	struct isl_aff_split *split, int n, __isl_keep isl_space *space)
+{
+	struct isl_print_space_data data = { 0 };
+	int i;
+	int rational;
+
+	data.print_dim = &print_dim_eq;
+	for (i = 0; i < n; ++i) {
+		if (!split[i].map)
+			break;
+		rational = split[i].map->n > 0 &&
+		    ISL_F_ISSET(split[i].map->p[0], ISL_BASIC_MAP_RATIONAL);
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		data.user = split[i].aff;
+		p = isl_print_space(space, p, rational, &data);
+		p = print_disjuncts_map(split[i].map, space, p, 0);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *isl_map_print_isl_body(__isl_keep isl_map *map,
+	__isl_take isl_printer *p)
+{
+	struct isl_print_space_data data = { 0 };
+	struct isl_aff_split *split = NULL;
+	int rational;
+
+	if (!p || !map)
+		return isl_printer_free(p);
+	if (!p->dump && map->n > 0)
+		split = split_aff(map);
+	if (split) {
+		p = print_split_map(p, split, map->n, map->dim);
+	} else {
+		rational = map->n > 0 &&
+		    ISL_F_ISSET(map->p[0], ISL_BASIC_MAP_RATIONAL);
+		p = isl_print_space(map->dim, p, rational, &data);
+		p = print_disjuncts_map(map, map->dim, p, 0);
+	}
+	free_split(split, map->n);
+	return p;
+}
+
+static __isl_give isl_printer *isl_map_print_isl(__isl_keep isl_map *map,
+	__isl_take isl_printer *p)
+{
+	struct isl_print_space_data data = { 0 };
+
+	p = print_param_tuple(p, map->dim, &data);
+	p = isl_printer_print_str(p, s_open_set[0]);
+	p = isl_map_print_isl_body(map, p);
+	p = isl_printer_print_str(p, s_close_set[0]);
+	return p;
+}
+
+static __isl_give isl_printer *print_latex_map(__isl_keep isl_map *map,
+	__isl_take isl_printer *p, __isl_keep isl_basic_map *aff)
+{
+	struct isl_print_space_data data = { 0 };
+
+	data.latex = 1;
+	p = print_param_tuple(p, map->dim, &data);
+	p = isl_printer_print_str(p, s_open_set[1]);
+	data.print_dim = &print_dim_eq;
+	data.user = aff;
+	p = isl_print_space(map->dim, p, 0, &data);
+	p = print_disjuncts_map(map, map->dim, p, 1);
+	p = isl_printer_print_str(p, s_close_set[1]);
+
+	return p;
+}
+
+static __isl_give isl_printer *isl_map_print_latex(__isl_keep isl_map *map,
+	__isl_take isl_printer *p)
+{
+	int i;
+	struct isl_aff_split *split = NULL;
+
+	if (map->n > 0)
+		split = split_aff(map);
+
+	if (!split)
+		return print_latex_map(map, p, NULL);
+
+	for (i = 0; i < map->n; ++i) {
+		if (!split[i].map)
+			break;
+		if (i)
+			p = isl_printer_print_str(p, " \\cup ");
+		p = print_latex_map(split[i].map, p, split[i].aff);
+	}
+
+	free_split(split, map->n);
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_basic_map(__isl_take isl_printer *p,
+	__isl_keep isl_basic_map *bmap)
+{
+	if (!p || !bmap)
+		goto error;
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_basic_map_print_isl(bmap, p, 0);
+	else if (p->output_format == ISL_FORMAT_OMEGA)
+		return basic_map_print_omega(bmap, p);
+	isl_assert(bmap->ctx, 0, goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_basic_set(__isl_take isl_printer *p,
+	__isl_keep isl_basic_set *bset)
+{
+	if (!p || !bset)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_basic_map_print_isl(bset, p, 0);
+	else if (p->output_format == ISL_FORMAT_POLYLIB)
+		return isl_basic_set_print_polylib(bset, p, 0);
+	else if (p->output_format == ISL_FORMAT_EXT_POLYLIB)
+		return isl_basic_set_print_polylib(bset, p, 1);
+	else if (p->output_format == ISL_FORMAT_POLYLIB_CONSTRAINTS)
+		return bset_print_constraints_polylib(bset, p);
+	else if (p->output_format == ISL_FORMAT_OMEGA)
+		return basic_set_print_omega(bset, p);
+	isl_assert(p->ctx, 0, goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_set(__isl_take isl_printer *p,
+	__isl_keep isl_set *set)
+{
+	if (!p || !set)
+		goto error;
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_map_print_isl(set_to_map(set), p);
+	else if (p->output_format == ISL_FORMAT_POLYLIB)
+		return isl_set_print_polylib(set, p, 0);
+	else if (p->output_format == ISL_FORMAT_EXT_POLYLIB)
+		return isl_set_print_polylib(set, p, 1);
+	else if (p->output_format == ISL_FORMAT_OMEGA)
+		return isl_set_print_omega(set, p);
+	else if (p->output_format == ISL_FORMAT_LATEX)
+		return isl_map_print_latex(set_to_map(set), p);
+	isl_assert(set->ctx, 0, goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_map(__isl_take isl_printer *p,
+	__isl_keep isl_map *map)
+{
+	if (!p || !map)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_map_print_isl(map, p);
+	else if (p->output_format == ISL_FORMAT_POLYLIB)
+		return isl_map_print_polylib(map, p, 0);
+	else if (p->output_format == ISL_FORMAT_EXT_POLYLIB)
+		return isl_map_print_polylib(map, p, 1);
+	else if (p->output_format == ISL_FORMAT_OMEGA)
+		return isl_map_print_omega(map, p);
+	else if (p->output_format == ISL_FORMAT_LATEX)
+		return isl_map_print_latex(map, p);
+	isl_assert(map->ctx, 0, goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+struct isl_union_print_data {
+	isl_printer *p;
+	int first;
+};
+
+static isl_stat print_map_body(__isl_take isl_map *map, void *user)
+{
+	struct isl_union_print_data *data;
+	data = (struct isl_union_print_data *)user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, "; ");
+	data->first = 0;
+
+	data->p = isl_map_print_isl_body(map, data->p);
+	isl_map_free(map);
+
+	return isl_stat_ok;
+}
+
+static __isl_give isl_printer *isl_union_map_print_isl(
+	__isl_keep isl_union_map *umap, __isl_take isl_printer *p)
+{
+	struct isl_union_print_data data;
+	struct isl_print_space_data space_data = { 0 };
+	isl_space *space;
+
+	space = isl_union_map_get_space(umap);
+	p = print_param_tuple(p, space, &space_data);
+	isl_space_free(space);
+	p = isl_printer_print_str(p, s_open_set[0]);
+	data.p = p;
+	data.first = 1;
+	isl_union_map_foreach_map(umap, &print_map_body, &data);
+	p = data.p;
+	p = isl_printer_print_str(p, s_close_set[0]);
+	return p;
+}
+
+static isl_stat print_latex_map_body(__isl_take isl_map *map, void *user)
+{
+	struct isl_union_print_data *data;
+	data = (struct isl_union_print_data *)user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, " \\cup ");
+	data->first = 0;
+
+	data->p = isl_map_print_latex(map, data->p);
+	isl_map_free(map);
+
+	return isl_stat_ok;
+}
+
+static __isl_give isl_printer *isl_union_map_print_latex(
+	__isl_keep isl_union_map *umap, __isl_take isl_printer *p)
+{
+	struct isl_union_print_data data = { p, 1 };
+	isl_union_map_foreach_map(umap, &print_latex_map_body, &data);
+	p = data.p;
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_union_map(__isl_take isl_printer *p,
+	__isl_keep isl_union_map *umap)
+{
+	if (!p || !umap)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_union_map_print_isl(umap, p);
+	if (p->output_format == ISL_FORMAT_LATEX)
+		return isl_union_map_print_latex(umap, p);
+
+	isl_die(p->ctx, isl_error_invalid,
+		"invalid output format for isl_union_map", goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_union_set(__isl_take isl_printer *p,
+	__isl_keep isl_union_set *uset)
+{
+	if (!p || !uset)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_union_map_print_isl((isl_union_map *)uset, p);
+	if (p->output_format == ISL_FORMAT_LATEX)
+		return isl_union_map_print_latex((isl_union_map *)uset, p);
+
+	isl_die(p->ctx, isl_error_invalid,
+		"invalid output format for isl_union_set", goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static int upoly_rec_n_non_zero(__isl_keep struct isl_upoly_rec *rec)
+{
+	int i;
+	int n;
+
+	for (i = 0, n = 0; i < rec->n; ++i)
+		if (!isl_upoly_is_zero(rec->p[i]))
+			++n;
+
+	return n;
+}
+
+static __isl_give isl_printer *upoly_print_cst(__isl_keep struct isl_upoly *up,
+	__isl_take isl_printer *p, int first)
+{
+	struct isl_upoly_cst *cst;
+	int neg;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		goto error;
+	neg = !first && isl_int_is_neg(cst->n);
+	if (!first)
+		p = isl_printer_print_str(p, neg ? " - " :  " + ");
+	if (neg)
+		isl_int_neg(cst->n, cst->n);
+	if (isl_int_is_zero(cst->d)) {
+		int sgn = isl_int_sgn(cst->n);
+		p = isl_printer_print_str(p, sgn < 0 ? "-infty" :
+					    sgn == 0 ? "NaN" : "infty");
+	} else
+		p = isl_printer_print_isl_int(p, cst->n);
+	if (neg)
+		isl_int_neg(cst->n, cst->n);
+	if (!isl_int_is_zero(cst->d) && !isl_int_is_one(cst->d)) {
+		p = isl_printer_print_str(p, "/");
+		p = isl_printer_print_isl_int(p, cst->d);
+	}
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_base(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_mat *div, int var)
+{
+	unsigned total;
+
+	total = isl_space_dim(dim, isl_dim_all);
+	if (var < total)
+		p = print_term(dim, NULL, dim->ctx->one, 1 + var, p, 0);
+	else
+		p = print_div(dim, div, var - total, p);
+	return p;
+}
+
+static __isl_give isl_printer *print_pow(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_mat *div, int var, int exp)
+{
+	p = print_base(p, dim, div, var);
+	if (exp == 1)
+		return p;
+	if (p->output_format == ISL_FORMAT_C) {
+		int i;
+		for (i = 1; i < exp; ++i) {
+			p = isl_printer_print_str(p, "*");
+			p = print_base(p, dim, div, var);
+		}
+	} else {
+		p = isl_printer_print_str(p, "^");
+		p = isl_printer_print_int(p, exp);
+	}
+	return p;
+}
+
+/* Print the polynomial "up" defined over the domain space "space" and
+ * local variables defined by "div" to "p".
+ */
+static __isl_give isl_printer *upoly_print(__isl_keep struct isl_upoly *up,
+	__isl_keep isl_space *space, __isl_keep isl_mat *div,
+	__isl_take isl_printer *p)
+{
+	int i, n, first, print_parens;
+	struct isl_upoly_rec *rec;
+
+	if (!p || !up || !space || !div)
+		goto error;
+
+	if (isl_upoly_is_cst(up))
+		return upoly_print_cst(up, p, 1);
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+	n = upoly_rec_n_non_zero(rec);
+	print_parens = n > 1;
+	if (print_parens)
+		p = isl_printer_print_str(p, "(");
+	for (i = 0, first = 1; i < rec->n; ++i) {
+		if (isl_upoly_is_zero(rec->p[i]))
+			continue;
+		if (isl_upoly_is_negone(rec->p[i])) {
+			if (!i)
+				p = isl_printer_print_str(p, "-1");
+			else if (first)
+				p = isl_printer_print_str(p, "-");
+			else
+				p = isl_printer_print_str(p, " - ");
+		} else if (isl_upoly_is_cst(rec->p[i]) &&
+				!isl_upoly_is_one(rec->p[i]))
+			p = upoly_print_cst(rec->p[i], p, first);
+		else {
+			if (!first)
+				p = isl_printer_print_str(p, " + ");
+			if (i == 0 || !isl_upoly_is_one(rec->p[i]))
+				p = upoly_print(rec->p[i], space, div, p);
+		}
+		first = 0;
+		if (i == 0)
+			continue;
+		if (!isl_upoly_is_one(rec->p[i]) &&
+		    !isl_upoly_is_negone(rec->p[i]))
+			p = isl_printer_print_str(p, " * ");
+		p = print_pow(p, space, div, rec->up.var, i);
+	}
+	if (print_parens)
+		p = isl_printer_print_str(p, ")");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_qpolynomial(__isl_take isl_printer *p,
+	__isl_keep isl_qpolynomial *qp)
+{
+	if (!p || !qp)
+		goto error;
+	p = upoly_print(qp->upoly, qp->dim, qp->div, p);
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_qpolynomial_isl(__isl_take isl_printer *p,
+	__isl_keep isl_qpolynomial *qp)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!p || !qp)
+		goto error;
+
+	p = print_param_tuple(p, qp->dim, &data);
+	p = isl_printer_print_str(p, "{ ");
+	if (!isl_space_is_params(qp->dim)) {
+		p = isl_print_space(qp->dim, p, 0, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = print_qpolynomial(p, qp);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print the quasi-polynomial "qp" to "p" in C format, with the variable names
+ * taken from the domain space "space".
+ */
+static __isl_give isl_printer *print_qpolynomial_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *space, __isl_keep isl_qpolynomial *qp)
+{
+	isl_int den;
+
+	isl_int_init(den);
+	isl_qpolynomial_get_den(qp, &den);
+	if (!isl_int_is_one(den)) {
+		isl_qpolynomial *f;
+		p = isl_printer_print_str(p, "(");
+		qp = isl_qpolynomial_copy(qp);
+		f = isl_qpolynomial_rat_cst_on_domain(isl_space_copy(qp->dim),
+						den, qp->dim->ctx->one);
+		qp = isl_qpolynomial_mul(qp, f);
+	}
+	if (qp)
+		p = upoly_print(qp->upoly, space, qp->div, p);
+	else
+		p = isl_printer_free(p);
+	if (!isl_int_is_one(den)) {
+		p = isl_printer_print_str(p, ")/");
+		p = isl_printer_print_isl_int(p, den);
+		isl_qpolynomial_free(qp);
+	}
+	isl_int_clear(den);
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_qpolynomial(
+	__isl_take isl_printer *p, __isl_keep isl_qpolynomial *qp)
+{
+	if (!p || !qp)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_qpolynomial_isl(p, qp);
+	else if (p->output_format == ISL_FORMAT_C)
+		return print_qpolynomial_c(p, qp->dim, qp);
+	else
+		isl_die(qp->dim->ctx, isl_error_unsupported,
+			"output format not supported for isl_qpolynomials",
+			goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+void isl_qpolynomial_print(__isl_keep isl_qpolynomial *qp, FILE *out,
+	unsigned output_format)
+{
+	isl_printer *p;
+
+	if  (!qp)
+		return;
+
+	isl_assert(qp->dim->ctx, output_format == ISL_FORMAT_ISL, return);
+	p = isl_printer_to_file(qp->dim->ctx, out);
+	p = isl_printer_print_qpolynomial(p, qp);
+	isl_printer_free(p);
+}
+
+static __isl_give isl_printer *qpolynomial_fold_print(
+	__isl_keep isl_qpolynomial_fold *fold, __isl_take isl_printer *p)
+{
+	int i;
+
+	if (fold->type == isl_fold_min)
+		p = isl_printer_print_str(p, "min");
+	else if (fold->type == isl_fold_max)
+		p = isl_printer_print_str(p, "max");
+	p = isl_printer_print_str(p, "(");
+	for (i = 0; i < fold->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, ", ");
+		p = print_qpolynomial(p, fold->qp[i]);
+	}
+	p = isl_printer_print_str(p, ")");
+	return p;
+}
+
+void isl_qpolynomial_fold_print(__isl_keep isl_qpolynomial_fold *fold,
+	FILE *out, unsigned output_format)
+{
+	isl_printer *p;
+
+	if (!fold)
+		return;
+
+	isl_assert(fold->dim->ctx, output_format == ISL_FORMAT_ISL, return);
+
+	p = isl_printer_to_file(fold->dim->ctx, out);
+	p = isl_printer_print_qpolynomial_fold(p, fold);
+
+	isl_printer_free(p);
+}
+
+static __isl_give isl_printer *isl_pwqp_print_isl_body(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp)
+{
+	struct isl_print_space_data data = { 0 };
+	int i = 0;
+
+	for (i = 0; i < pwqp->n; ++i) {
+		isl_space *space;
+
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		space = isl_qpolynomial_get_domain_space(pwqp->p[i].qp);
+		if (!isl_space_is_params(space)) {
+			p = isl_print_space(space, p, 0, &data);
+			p = isl_printer_print_str(p, " -> ");
+		}
+		p = print_qpolynomial(p, pwqp->p[i].qp);
+		p = print_disjuncts(set_to_map(pwqp->p[i].set), space, p, 0);
+		isl_space_free(space);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_pw_qpolynomial_isl(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!p || !pwqp)
+		goto error;
+
+	p = print_param_tuple(p, pwqp->dim, &data);
+	p = isl_printer_print_str(p, "{ ");
+	if (pwqp->n == 0) {
+		if (!isl_space_is_set(pwqp->dim)) {
+			p = print_tuple(pwqp->dim, p, isl_dim_in, &data);
+			p = isl_printer_print_str(p, " -> ");
+		}
+		p = isl_printer_print_str(p, "0");
+	}
+	p = isl_pwqp_print_isl_body(p, pwqp);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+void isl_pw_qpolynomial_print(__isl_keep isl_pw_qpolynomial *pwqp, FILE *out,
+	unsigned output_format)
+{
+	isl_printer *p;
+
+	if (!pwqp)
+		return;
+
+	p = isl_printer_to_file(pwqp->dim->ctx, out);
+	p = isl_printer_set_output_format(p, output_format);
+	p = isl_printer_print_pw_qpolynomial(p, pwqp);
+
+	isl_printer_free(p);
+}
+
+static __isl_give isl_printer *isl_pwf_print_isl_body(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+	struct isl_print_space_data data = { 0 };
+	int i = 0;
+
+	for (i = 0; i < pwf->n; ++i) {
+		isl_space *space;
+
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		space = isl_qpolynomial_fold_get_domain_space(pwf->p[i].fold);
+		if (!isl_space_is_params(space)) {
+			p = isl_print_space(space, p, 0, &data);
+			p = isl_printer_print_str(p, " -> ");
+		}
+		p = qpolynomial_fold_print(pwf->p[i].fold, p);
+		p = print_disjuncts(set_to_map(pwf->p[i].set), space, p, 0);
+		isl_space_free(space);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_pw_qpolynomial_fold_isl(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+	struct isl_print_space_data data = { 0 };
+
+	p = print_param_tuple(p, pwf->dim, &data);
+	p = isl_printer_print_str(p, "{ ");
+	if (pwf->n == 0) {
+		if (!isl_space_is_set(pwf->dim)) {
+			p = print_tuple(pwf->dim, p, isl_dim_in, &data);
+			p = isl_printer_print_str(p, " -> ");
+		}
+		p = isl_printer_print_str(p, "0");
+	}
+	p = isl_pwf_print_isl_body(p, pwf);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+static __isl_give isl_printer *print_affine_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_basic_set *bset, isl_int *c);
+
+static __isl_give isl_printer *print_name_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim,
+	__isl_keep isl_basic_set *bset, enum isl_dim_type type, unsigned pos)
+{
+	if (type == isl_dim_div) {
+		p = isl_printer_print_str(p, "floord(");
+		p = print_affine_c(p, dim, bset, bset->div[pos] + 1);
+		p = isl_printer_print_str(p, ", ");
+		p = isl_printer_print_isl_int(p, bset->div[pos][0]);
+		p = isl_printer_print_str(p, ")");
+	} else {
+		const char *name;
+
+		name = isl_space_get_dim_name(dim, type, pos);
+		if (!name)
+			name = "UNNAMED";
+		p = isl_printer_print_str(p, name);
+	}
+	return p;
+}
+
+static __isl_give isl_printer *print_term_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim,
+	__isl_keep isl_basic_set *bset, isl_int c, unsigned pos)
+{
+	enum isl_dim_type type;
+
+	if (pos == 0)
+		return isl_printer_print_isl_int(p, c);
+
+	if (isl_int_is_one(c))
+		;
+	else if (isl_int_is_negone(c))
+		p = isl_printer_print_str(p, "-");
+	else {
+		p = isl_printer_print_isl_int(p, c);
+		p = isl_printer_print_str(p, "*");
+	}
+	type = pos2type(dim, &pos);
+	p = print_name_c(p, dim, bset, type, pos);
+	return p;
+}
+
+static __isl_give isl_printer *print_partial_affine_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim,
+	__isl_keep isl_basic_set *bset, isl_int *c, unsigned len)
+{
+	int i;
+	int first;
+
+	for (i = 0, first = 1; i < len; ++i) {
+		int flip = 0;
+		if (isl_int_is_zero(c[i]))
+			continue;
+		if (!first) {
+			if (isl_int_is_neg(c[i])) {
+				flip = 1;
+				isl_int_neg(c[i], c[i]);
+				p = isl_printer_print_str(p, " - ");
+			} else 
+				p = isl_printer_print_str(p, " + ");
+		}
+		first = 0;
+		p = print_term_c(p, dim, bset, c[i], i);
+		if (flip)
+			isl_int_neg(c[i], c[i]);
+	}
+	if (first)
+		p = isl_printer_print_str(p, "0");
+	return p;
+}
+
+static __isl_give isl_printer *print_affine_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_basic_set *bset, isl_int *c)
+{
+	unsigned len = 1 + isl_basic_set_total_dim(bset);
+	return print_partial_affine_c(p, dim, bset, c, len);
+}
+
+/* We skip the constraint if it is implied by the div expression.
+ *
+ * *first indicates whether this is the first constraint in the conjunction and
+ * is updated if the constraint is actually printed.
+ */
+static __isl_give isl_printer *print_constraint_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim,
+	__isl_keep isl_basic_set *bset, isl_int *c, const char *op, int *first)
+{
+	unsigned o_div;
+	unsigned n_div;
+	int div;
+
+	o_div = isl_basic_set_offset(bset, isl_dim_div);
+	n_div = isl_basic_set_dim(bset, isl_dim_div);
+	div = isl_seq_last_non_zero(c + o_div, n_div);
+	if (div >= 0) {
+		isl_bool is_div = isl_basic_set_is_div_constraint(bset, c, div);
+		if (is_div < 0)
+			return isl_printer_free(p);
+		if (is_div)
+			return p;
+	}
+
+	if (!*first)
+		p = isl_printer_print_str(p, " && ");
+
+	p = print_affine_c(p, dim, bset, c);
+	p = isl_printer_print_str(p, " ");
+	p = isl_printer_print_str(p, op);
+	p = isl_printer_print_str(p, " 0");
+
+	*first = 0;
+
+	return p;
+}
+
+static __isl_give isl_printer *print_basic_set_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_basic_set *bset)
+{
+	int i, j;
+	int first = 1;
+	unsigned n_div = isl_basic_set_dim(bset, isl_dim_div);
+	unsigned total = isl_basic_set_total_dim(bset) - n_div;
+
+	for (i = 0; i < bset->n_eq; ++i) {
+		j = isl_seq_last_non_zero(bset->eq[i] + 1 + total, n_div);
+		if (j < 0)
+			p = print_constraint_c(p, dim, bset,
+						bset->eq[i], "==", &first);
+		else {
+			if (i)
+				p = isl_printer_print_str(p, " && ");
+			p = isl_printer_print_str(p, "(");
+			p = print_partial_affine_c(p, dim, bset, bset->eq[i],
+						   1 + total + j);
+			p = isl_printer_print_str(p, ") % ");
+			p = isl_printer_print_isl_int(p,
+						bset->eq[i][1 + total + j]);
+			p = isl_printer_print_str(p, " == 0");
+			first = 0;
+		}
+	}
+	for (i = 0; i < bset->n_ineq; ++i)
+		p = print_constraint_c(p, dim, bset, bset->ineq[i], ">=",
+					&first);
+	return p;
+}
+
+static __isl_give isl_printer *print_set_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __isl_keep isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return isl_printer_free(p);
+
+	if (set->n == 0)
+		p = isl_printer_print_str(p, "0");
+
+	for (i = 0; i < set->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, " || ");
+		if (set->n > 1)
+			p = isl_printer_print_str(p, "(");
+		p = print_basic_set_c(p, dim, set->p[i]);
+		if (set->n > 1)
+			p = isl_printer_print_str(p, ")");
+	}
+	return p;
+}
+
+/* Print the piecewise quasi-polynomial "pwqp" to "p" in C format.
+ */
+static __isl_give isl_printer *print_pw_qpolynomial_c(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp)
+{
+	int i;
+	isl_space *space;
+
+	space = isl_pw_qpolynomial_get_domain_space(pwqp);
+	if (pwqp->n == 1 && isl_set_plain_is_universe(pwqp->p[0].set)) {
+		p = print_qpolynomial_c(p, space, pwqp->p[0].qp);
+		isl_space_free(space);
+		return p;
+	}
+
+	for (i = 0; i < pwqp->n; ++i) {
+		p = isl_printer_print_str(p, "(");
+		p = print_set_c(p, space, pwqp->p[i].set);
+		p = isl_printer_print_str(p, ") ? (");
+		p = print_qpolynomial_c(p, space, pwqp->p[i].qp);
+		p = isl_printer_print_str(p, ") : ");
+	}
+
+	isl_space_free(space);
+	p = isl_printer_print_str(p, "0");
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_pw_qpolynomial(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp)
+{
+	if (!p || !pwqp)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_pw_qpolynomial_isl(p, pwqp);
+	else if (p->output_format == ISL_FORMAT_C)
+		return print_pw_qpolynomial_c(p, pwqp);
+	isl_assert(p->ctx, 0, goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static isl_stat print_pwqp_body(__isl_take isl_pw_qpolynomial *pwqp, void *user)
+{
+	struct isl_union_print_data *data;
+	data = (struct isl_union_print_data *)user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, "; ");
+	data->first = 0;
+
+	data->p = isl_pwqp_print_isl_body(data->p, pwqp);
+	isl_pw_qpolynomial_free(pwqp);
+
+	return isl_stat_ok;
+}
+
+static __isl_give isl_printer *print_union_pw_qpolynomial_isl(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_qpolynomial *upwqp)
+{
+	struct isl_union_print_data data;
+	struct isl_print_space_data space_data = { 0 };
+	isl_space *space;
+
+	space = isl_union_pw_qpolynomial_get_space(upwqp);
+	p = print_param_tuple(p, space, &space_data);
+	isl_space_free(space);
+	p = isl_printer_print_str(p, "{ ");
+	data.p = p;
+	data.first = 1;
+	isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp, &print_pwqp_body,
+							&data);
+	p = data.p;
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_union_pw_qpolynomial(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_qpolynomial *upwqp)
+{
+	if (!p || !upwqp)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_union_pw_qpolynomial_isl(p, upwqp);
+	isl_die(p->ctx, isl_error_invalid,
+		"invalid output format for isl_union_pw_qpolynomial",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print the quasi-polynomial reduction "fold" to "p" in C format,
+ * with the variable names taken from the domain space "space".
+ */
+static __isl_give isl_printer *print_qpolynomial_fold_c(
+	__isl_take isl_printer *p, __isl_keep isl_space *space,
+	__isl_keep isl_qpolynomial_fold *fold)
+{
+	int i;
+
+	for (i = 0; i < fold->n - 1; ++i)
+		if (fold->type == isl_fold_min)
+			p = isl_printer_print_str(p, "min(");
+		else if (fold->type == isl_fold_max)
+			p = isl_printer_print_str(p, "max(");
+
+	for (i = 0; i < fold->n; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, ", ");
+		p = print_qpolynomial_c(p, space, fold->qp[i]);
+		if (i)
+			p = isl_printer_print_str(p, ")");
+	}
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_qpolynomial_fold(
+	__isl_take isl_printer *p, __isl_keep isl_qpolynomial_fold *fold)
+{
+	if  (!p || !fold)
+		goto error;
+	if (p->output_format == ISL_FORMAT_ISL)
+		return qpolynomial_fold_print(fold, p);
+	else if (p->output_format == ISL_FORMAT_C)
+		return print_qpolynomial_fold_c(p, fold->dim, fold);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print the piecewise quasi-polynomial reduction "pwf" to "p" in C format.
+ */
+static __isl_give isl_printer *print_pw_qpolynomial_fold_c(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+	int i;
+	isl_space *space;
+
+	space = isl_pw_qpolynomial_fold_get_domain_space(pwf);
+	if (pwf->n == 1 && isl_set_plain_is_universe(pwf->p[0].set)) {
+		p = print_qpolynomial_fold_c(p, space, pwf->p[0].fold);
+		isl_space_free(space);
+		return p;
+	}
+
+	for (i = 0; i < pwf->n; ++i) {
+		p = isl_printer_print_str(p, "(");
+		p = print_set_c(p, space, pwf->p[i].set);
+		p = isl_printer_print_str(p, ") ? (");
+		p = print_qpolynomial_fold_c(p, space, pwf->p[i].fold);
+		p = isl_printer_print_str(p, ") : ");
+	}
+
+	isl_space_free(space);
+	p = isl_printer_print_str(p, "0");
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_pw_qpolynomial_fold(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+	if (!p || !pwf)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_pw_qpolynomial_fold_isl(p, pwf);
+	else if (p->output_format == ISL_FORMAT_C)
+		return print_pw_qpolynomial_fold_c(p, pwf);
+	isl_assert(p->ctx, 0, goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+void isl_pw_qpolynomial_fold_print(__isl_keep isl_pw_qpolynomial_fold *pwf,
+	FILE *out, unsigned output_format)
+{
+	isl_printer *p;
+
+	if (!pwf)
+		return;
+
+	p = isl_printer_to_file(pwf->dim->ctx, out);
+	p = isl_printer_set_output_format(p, output_format);
+	p = isl_printer_print_pw_qpolynomial_fold(p, pwf);
+
+	isl_printer_free(p);
+}
+
+static isl_stat print_pwf_body(__isl_take isl_pw_qpolynomial_fold *pwf,
+	void *user)
+{
+	struct isl_union_print_data *data;
+	data = (struct isl_union_print_data *)user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, "; ");
+	data->first = 0;
+
+	data->p = isl_pwf_print_isl_body(data->p, pwf);
+	isl_pw_qpolynomial_fold_free(pwf);
+
+	return isl_stat_ok;
+}
+
+static __isl_give isl_printer *print_union_pw_qpolynomial_fold_isl(
+	__isl_take isl_printer *p,
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf)
+{
+	struct isl_union_print_data data;
+	struct isl_print_space_data space_data = { 0 };
+	isl_space *space;
+
+	space = isl_union_pw_qpolynomial_fold_get_space(upwf);
+	p = print_param_tuple(p, space, &space_data);
+	isl_space_free(space);
+	p = isl_printer_print_str(p, "{ ");
+	data.p = p;
+	data.first = 1;
+	isl_union_pw_qpolynomial_fold_foreach_pw_qpolynomial_fold(upwf,
+							&print_pwf_body, &data);
+	p = data.p;
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_union_pw_qpolynomial_fold(
+	__isl_take isl_printer *p,
+	__isl_keep isl_union_pw_qpolynomial_fold *upwf)
+{
+	if (!p || !upwf)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_union_pw_qpolynomial_fold_isl(p, upwf);
+	isl_die(p->ctx, isl_error_invalid,
+		"invalid output format for isl_union_pw_qpolynomial_fold",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print the isl_constraint "c" to "p".
+ */
+__isl_give isl_printer *isl_printer_print_constraint(__isl_take isl_printer *p,
+	__isl_keep isl_constraint *c)
+{
+	struct isl_print_space_data data = { 0 };
+	isl_local_space *ls;
+	isl_space *space;
+	isl_bool exists;
+
+	if (!p || !c)
+		goto error;
+
+	ls = isl_constraint_get_local_space(c);
+	if (!ls)
+		return isl_printer_free(p);
+	space = isl_local_space_get_space(ls);
+	p = print_param_tuple(p, space, &data);
+	p = isl_printer_print_str(p, "{ ");
+	p = isl_print_space(space, p, 0, &data);
+	p = isl_printer_print_str(p, " : ");
+	exists = need_exists(p, ls->div);
+	if (exists < 0)
+		p = isl_printer_free(p);
+	if (exists >= 0 && exists)
+		p = open_exists(p, space, ls->div, 0);
+	p = print_affine_of_len(space, ls->div, p, c->v->el, c->v->size);
+	if (isl_constraint_is_equality(c))
+		p = isl_printer_print_str(p, " = 0");
+	else
+		p = isl_printer_print_str(p, " >= 0");
+	if (exists >= 0 && exists)
+		p = isl_printer_print_str(p, s_close_exists[0]);
+	p = isl_printer_print_str(p, " }");
+	isl_space_free(space);
+	isl_local_space_free(ls);
+
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *isl_printer_print_space_isl(
+	__isl_take isl_printer *p, __isl_keep isl_space *space)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!space)
+		goto error;
+
+	p = print_param_tuple(p, space, &data);
+
+	p = isl_printer_print_str(p, "{ ");
+	if (isl_space_is_params(space))
+		p = isl_printer_print_str(p, s_such_that[0]);
+	else
+		p = isl_print_space(space, p, 0, &data);
+	p = isl_printer_print_str(p, " }");
+
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_space(__isl_take isl_printer *p,
+	__isl_keep isl_space *space)
+{
+	if (!p || !space)
+		return isl_printer_free(p);
+	if (p->output_format == ISL_FORMAT_ISL)
+		return isl_printer_print_space_isl(p, space);
+	else if (p->output_format == ISL_FORMAT_OMEGA)
+		return print_omega_parameters(space, p);
+
+	isl_die(isl_space_get_ctx(space), isl_error_unsupported,
+		"output format not supported for space",
+		return isl_printer_free(p));
+}
+
+__isl_give isl_printer *isl_printer_print_local_space(__isl_take isl_printer *p,
+	__isl_keep isl_local_space *ls)
+{
+	struct isl_print_space_data data = { 0 };
+	unsigned n_div;
+
+	if (!ls)
+		goto error;
+
+	p = print_param_tuple(p, ls->dim, &data);
+	p = isl_printer_print_str(p, "{ ");
+	p = isl_print_space(ls->dim, p, 0, &data);
+	n_div = isl_local_space_dim(ls, isl_dim_div);
+	if (n_div > 0) {
+		p = isl_printer_print_str(p, " : ");
+		p = isl_printer_print_str(p, s_open_exists[0]);
+		p = print_div_list(p, ls->dim, ls->div, 0, 1);
+		p = isl_printer_print_str(p, s_close_exists[0]);
+	} else if (isl_space_is_params(ls->dim))
+		p = isl_printer_print_str(p, s_such_that[0]);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_aff_body(__isl_take isl_printer *p,
+	__isl_keep isl_aff *aff)
+{
+	unsigned total;
+
+	if (isl_aff_is_nan(aff))
+		return isl_printer_print_str(p, "NaN");
+
+	total = isl_local_space_dim(aff->ls, isl_dim_all);
+	p = isl_printer_print_str(p, "(");
+	p = print_affine_of_len(aff->ls->dim, aff->ls->div, p,
+				aff->v->el + 1, 1 + total);
+	if (isl_int_is_one(aff->v->el[0]))
+		p = isl_printer_print_str(p, ")");
+	else {
+		p = isl_printer_print_str(p, ")/");
+		p = isl_printer_print_isl_int(p, aff->v->el[0]);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_aff(__isl_take isl_printer *p,
+	__isl_keep isl_aff *aff)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (isl_space_is_params(aff->ls->dim))
+		;
+	else {
+		p = print_tuple(aff->ls->dim, p, isl_dim_set, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "[");
+	p = print_aff_body(p, aff);
+	p = isl_printer_print_str(p, "]");
+
+	return p;
+}
+
+static __isl_give isl_printer *print_aff_isl(__isl_take isl_printer *p,
+	__isl_keep isl_aff *aff)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!aff)
+		goto error;
+
+	p = print_param_tuple(p, aff->ls->dim, &data);
+	p = isl_printer_print_str(p, "{ ");
+	p = print_aff(p, aff);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print the body of an isl_pw_aff, i.e., a semicolon delimited
+ * sequence of affine expressions, each followed by constraints.
+ */
+static __isl_give isl_printer *print_pw_aff_body(
+	__isl_take isl_printer *p, __isl_keep isl_pw_aff *pa)
+{
+	int i;
+
+	if (!pa)
+		return isl_printer_free(p);
+
+	for (i = 0; i < pa->n; ++i) {
+		isl_space *space;
+
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		p = print_aff(p, pa->p[i].aff);
+		space = isl_aff_get_domain_space(pa->p[i].aff);
+		p = print_disjuncts(set_to_map(pa->p[i].set), space, p, 0);
+		isl_space_free(space);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_pw_aff_isl(__isl_take isl_printer *p,
+	__isl_keep isl_pw_aff *pwaff)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!pwaff)
+		goto error;
+
+	p = print_param_tuple(p, pwaff->dim, &data);
+	p = isl_printer_print_str(p, "{ ");
+	p = print_pw_aff_body(p, pwaff);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_ls_affine_c(__isl_take isl_printer *p,
+	__isl_keep isl_local_space *ls, isl_int *c);
+
+static __isl_give isl_printer *print_ls_name_c(__isl_take isl_printer *p,
+	__isl_keep isl_local_space *ls, enum isl_dim_type type, unsigned pos)
+{
+	if (type == isl_dim_div) {
+		p = isl_printer_print_str(p, "floord(");
+		p = print_ls_affine_c(p, ls, ls->div->row[pos] + 1);
+		p = isl_printer_print_str(p, ", ");
+		p = isl_printer_print_isl_int(p, ls->div->row[pos][0]);
+		p = isl_printer_print_str(p, ")");
+	} else {
+		const char *name;
+
+		name = isl_space_get_dim_name(ls->dim, type, pos);
+		if (!name)
+			name = "UNNAMED";
+		p = isl_printer_print_str(p, name);
+	}
+	return p;
+}
+
+static __isl_give isl_printer *print_ls_term_c(__isl_take isl_printer *p,
+	__isl_keep isl_local_space *ls, isl_int c, unsigned pos)
+{
+	enum isl_dim_type type;
+
+	if (pos == 0)
+		return isl_printer_print_isl_int(p, c);
+
+	if (isl_int_is_one(c))
+		;
+	else if (isl_int_is_negone(c))
+		p = isl_printer_print_str(p, "-");
+	else {
+		p = isl_printer_print_isl_int(p, c);
+		p = isl_printer_print_str(p, "*");
+	}
+	type = pos2type(ls->dim, &pos);
+	p = print_ls_name_c(p, ls, type, pos);
+	return p;
+}
+
+static __isl_give isl_printer *print_ls_partial_affine_c(
+	__isl_take isl_printer *p, __isl_keep isl_local_space *ls,
+	isl_int *c, unsigned len)
+{
+	int i;
+	int first;
+
+	for (i = 0, first = 1; i < len; ++i) {
+		int flip = 0;
+		if (isl_int_is_zero(c[i]))
+			continue;
+		if (!first) {
+			if (isl_int_is_neg(c[i])) {
+				flip = 1;
+				isl_int_neg(c[i], c[i]);
+				p = isl_printer_print_str(p, " - ");
+			} else 
+				p = isl_printer_print_str(p, " + ");
+		}
+		first = 0;
+		p = print_ls_term_c(p, ls, c[i], i);
+		if (flip)
+			isl_int_neg(c[i], c[i]);
+	}
+	if (first)
+		p = isl_printer_print_str(p, "0");
+	return p;
+}
+
+static __isl_give isl_printer *print_ls_affine_c(__isl_take isl_printer *p,
+	__isl_keep isl_local_space *ls, isl_int *c)
+{
+	unsigned len = 1 + isl_local_space_dim(ls, isl_dim_all);
+	return print_ls_partial_affine_c(p, ls, c, len);
+}
+
+static __isl_give isl_printer *print_aff_c(__isl_take isl_printer *p,
+	__isl_keep isl_aff *aff)
+{
+	unsigned total;
+
+	total = isl_local_space_dim(aff->ls, isl_dim_all);
+	if (!isl_int_is_one(aff->v->el[0]))
+		p = isl_printer_print_str(p, "(");
+	p = print_ls_partial_affine_c(p, aff->ls, aff->v->el + 1, 1 + total);
+	if (!isl_int_is_one(aff->v->el[0])) {
+		p = isl_printer_print_str(p, ")/");
+		p = isl_printer_print_isl_int(p, aff->v->el[0]);
+	}
+	return p;
+}
+
+/* In the C format, we cannot express that "pwaff" may be undefined
+ * on parts of the domain space.  We therefore assume that the expression
+ * will only be evaluated on its definition domain and compute the gist
+ * of each cell with respect to this domain.
+ */
+static __isl_give isl_printer *print_pw_aff_c(__isl_take isl_printer *p,
+	__isl_keep isl_pw_aff *pwaff)
+{
+	isl_set *domain;
+	isl_ast_build *build;
+	isl_ast_expr *expr;
+
+	if (pwaff->n < 1)
+		isl_die(p->ctx, isl_error_unsupported,
+			"cannot print empty isl_pw_aff in C format",
+			return isl_printer_free(p));
+
+	domain = isl_pw_aff_domain(isl_pw_aff_copy(pwaff));
+	build = isl_ast_build_from_context(domain);
+	expr = isl_ast_build_expr_from_pw_aff(build, isl_pw_aff_copy(pwaff));
+	p = isl_printer_print_ast_expr(p, expr);
+	isl_ast_expr_free(expr);
+	isl_ast_build_free(build);
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_aff(__isl_take isl_printer *p,
+	__isl_keep isl_aff *aff)
+{
+	if (!p || !aff)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_aff_isl(p, aff);
+	else if (p->output_format == ISL_FORMAT_C)
+		return print_aff_c(p, aff);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_pw_aff(__isl_take isl_printer *p,
+	__isl_keep isl_pw_aff *pwaff)
+{
+	if (!p || !pwaff)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_pw_aff_isl(p, pwaff);
+	else if (p->output_format == ISL_FORMAT_C)
+		return print_pw_aff_c(p, pwaff);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print "pa" in a sequence of isl_pw_affs delimited by semicolons.
+ * Each isl_pw_aff itself is also printed as semicolon delimited
+ * sequence of pieces.
+ * If data->first = 1, then this is the first in the sequence.
+ * Update data->first to tell the next element that it is not the first.
+ */
+static isl_stat print_pw_aff_body_wrap(__isl_take isl_pw_aff *pa,
+	void *user)
+{
+	struct isl_union_print_data *data;
+	data = (struct isl_union_print_data *) user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, "; ");
+	data->first = 0;
+
+	data->p = print_pw_aff_body(data->p, pa);
+	isl_pw_aff_free(pa);
+
+	return data->p ? isl_stat_ok : isl_stat_error;
+}
+
+/* Print the body of an isl_union_pw_aff, i.e., a semicolon delimited
+ * sequence of affine expressions, each followed by constraints,
+ * with the sequence enclosed in braces.
+ */
+static __isl_give isl_printer *print_union_pw_aff_body(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa)
+{
+	struct isl_union_print_data data = { p, 1 };
+
+	p = isl_printer_print_str(p, s_open_set[0]);
+	data.p = p;
+	if (isl_union_pw_aff_foreach_pw_aff(upa,
+					    &print_pw_aff_body_wrap, &data) < 0)
+		data.p = isl_printer_free(p);
+	p = data.p;
+	p = isl_printer_print_str(p, s_close_set[0]);
+
+	return p;
+}
+
+/* Print the isl_union_pw_aff "upa" to "p" in isl format.
+ *
+ * The individual isl_pw_affs are delimited by a semicolon.
+ */
+static __isl_give isl_printer *print_union_pw_aff_isl(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa)
+{
+	struct isl_print_space_data data = { 0 };
+	isl_space *space;
+
+	space = isl_union_pw_aff_get_space(upa);
+	p = print_param_tuple(p, space, &data);
+	isl_space_free(space);
+	p = print_union_pw_aff_body(p, upa);
+	return p;
+}
+
+/* Print the isl_union_pw_aff "upa" to "p".
+ *
+ * We currently only support an isl format.
+ */
+__isl_give isl_printer *isl_printer_print_union_pw_aff(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_aff *upa)
+{
+	if (!p || !upa)
+		return isl_printer_free(p);
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_union_pw_aff_isl(p, upa);
+	isl_die(isl_printer_get_ctx(p), isl_error_unsupported,
+		"unsupported output format", return isl_printer_free(p));
+}
+
+/* Print dimension "pos" of data->space to "p".
+ *
+ * data->user is assumed to be an isl_multi_aff.
+ *
+ * If the current dimension is an output dimension, then print
+ * the corresponding expression.  Otherwise, print the name of the dimension.
+ */
+static __isl_give isl_printer *print_dim_ma(__isl_take isl_printer *p,
+	struct isl_print_space_data *data, unsigned pos)
+{
+	isl_multi_aff *ma = data->user;
+
+	if (data->type == isl_dim_out)
+		p = print_aff_body(p, ma->p[pos]);
+	else
+		p = print_name(data->space, p, data->type, pos, data->latex);
+
+	return p;
+}
+
+static __isl_give isl_printer *print_multi_aff(__isl_take isl_printer *p,
+	__isl_keep isl_multi_aff *maff)
+{
+	struct isl_print_space_data data = { 0 };
+
+	data.print_dim = &print_dim_ma;
+	data.user = maff;
+	return isl_print_space(maff->space, p, 0, &data);
+}
+
+static __isl_give isl_printer *print_multi_aff_isl(__isl_take isl_printer *p,
+	__isl_keep isl_multi_aff *maff)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!maff)
+		goto error;
+
+	p = print_param_tuple(p, maff->space, &data);
+	p = isl_printer_print_str(p, "{ ");
+	p = print_multi_aff(p, maff);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_multi_aff(__isl_take isl_printer *p,
+	__isl_keep isl_multi_aff *maff)
+{
+	if (!p || !maff)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_multi_aff_isl(p, maff);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_pw_multi_aff_body(
+	__isl_take isl_printer *p, __isl_keep isl_pw_multi_aff *pma)
+{
+	int i;
+
+	if (!pma)
+		goto error;
+
+	for (i = 0; i < pma->n; ++i) {
+		isl_space *space;
+
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		p = print_multi_aff(p, pma->p[i].maff);
+		space = isl_multi_aff_get_domain_space(pma->p[i].maff);
+		p = print_disjuncts(set_to_map(pma->p[i].set), space, p, 0);
+		isl_space_free(space);
+	}
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *print_pw_multi_aff_isl(__isl_take isl_printer *p,
+	__isl_keep isl_pw_multi_aff *pma)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!pma)
+		goto error;
+
+	p = print_param_tuple(p, pma->dim, &data);
+	p = isl_printer_print_str(p, "{ ");
+	p = print_pw_multi_aff_body(p, pma);
+	p = isl_printer_print_str(p, " }");
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print the unnamed, single-dimensional piecewise multi affine expression "pma"
+ * to "p".
+ */
+static __isl_give isl_printer *print_unnamed_pw_multi_aff_c(
+	__isl_take isl_printer *p, __isl_keep isl_pw_multi_aff *pma)
+{
+	int i;
+	isl_space *space;
+
+	space = isl_pw_multi_aff_get_domain_space(pma);
+	for (i = 0; i < pma->n - 1; ++i) {
+		p = isl_printer_print_str(p, "(");
+		p = print_set_c(p, space, pma->p[i].set);
+		p = isl_printer_print_str(p, ") ? (");
+		p = print_aff_c(p, pma->p[i].maff->p[0]);
+		p = isl_printer_print_str(p, ") : ");
+	}
+	isl_space_free(space);
+
+	return print_aff_c(p, pma->p[pma->n - 1].maff->p[0]);
+}
+
+static __isl_give isl_printer *print_pw_multi_aff_c(__isl_take isl_printer *p,
+	__isl_keep isl_pw_multi_aff *pma)
+{
+	int n;
+	const char *name;
+
+	if (!pma)
+		goto error;
+	if (pma->n < 1)
+		isl_die(p->ctx, isl_error_unsupported,
+			"cannot print empty isl_pw_multi_aff in C format",
+			goto error);
+	name = isl_pw_multi_aff_get_tuple_name(pma, isl_dim_out);
+	if (!name && isl_pw_multi_aff_dim(pma, isl_dim_out) == 1)
+		return print_unnamed_pw_multi_aff_c(p, pma);
+	if (!name)
+		isl_die(p->ctx, isl_error_unsupported,
+			"cannot print unnamed isl_pw_multi_aff in C format",
+			goto error);
+
+	p = isl_printer_print_str(p, name);
+	n = isl_pw_multi_aff_dim(pma, isl_dim_out);
+	if (n != 0)
+		isl_die(p->ctx, isl_error_unsupported,
+			"not supported yet", goto error);
+
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_give isl_printer *isl_printer_print_pw_multi_aff(
+	__isl_take isl_printer *p, __isl_keep isl_pw_multi_aff *pma)
+{
+	if (!p || !pma)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_pw_multi_aff_isl(p, pma);
+	if (p->output_format == ISL_FORMAT_C)
+		return print_pw_multi_aff_c(p, pma);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static isl_stat print_pw_multi_aff_body_wrap(__isl_take isl_pw_multi_aff *pma,
+	void *user)
+{
+	struct isl_union_print_data *data;
+	data = (struct isl_union_print_data *) user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, "; ");
+	data->first = 0;
+
+	data->p = print_pw_multi_aff_body(data->p, pma);
+	isl_pw_multi_aff_free(pma);
+
+	return isl_stat_ok;
+}
+
+static __isl_give isl_printer *print_union_pw_multi_aff_isl(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma)
+{
+	struct isl_union_print_data data;
+	struct isl_print_space_data space_data = { 0 };
+	isl_space *space;
+
+	space = isl_union_pw_multi_aff_get_space(upma);
+	p = print_param_tuple(p, space, &space_data);
+	isl_space_free(space);
+	p = isl_printer_print_str(p, s_open_set[0]);
+	data.p = p;
+	data.first = 1;
+	isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
+					&print_pw_multi_aff_body_wrap, &data);
+	p = data.p;
+	p = isl_printer_print_str(p, s_close_set[0]);
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_union_pw_multi_aff(
+	__isl_take isl_printer *p, __isl_keep isl_union_pw_multi_aff *upma)
+{
+	if (!p || !upma)
+		goto error;
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_union_pw_multi_aff_isl(p, upma);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		goto error);
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print dimension "pos" of data->space to "p".
+ *
+ * data->user is assumed to be an isl_multi_pw_aff.
+ *
+ * If the current dimension is an output dimension, then print
+ * the corresponding piecewise affine expression.
+ * Otherwise, print the name of the dimension.
+ */
+static __isl_give isl_printer *print_dim_mpa(__isl_take isl_printer *p,
+	struct isl_print_space_data *data, unsigned pos)
+{
+	int i;
+	int need_parens;
+	isl_multi_pw_aff *mpa = data->user;
+	isl_pw_aff *pa;
+
+	if (data->type != isl_dim_out)
+		return print_name(data->space, p, data->type, pos, data->latex);
+
+	pa = mpa->p[pos];
+	if (pa->n == 0)
+		return isl_printer_print_str(p, "(0 : 1 = 0)");
+
+	need_parens = pa->n != 1 || !isl_set_plain_is_universe(pa->p[0].set);
+	if (need_parens)
+		p = isl_printer_print_str(p, "(");
+	for (i = 0; i < pa->n; ++i) {
+		isl_space *space;
+
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		p = print_aff_body(p, pa->p[i].aff);
+		space = isl_aff_get_domain_space(pa->p[i].aff);
+		p = print_disjuncts(pa->p[i].set, space, p, 0);
+		isl_space_free(space);
+	}
+	if (need_parens)
+		p = isl_printer_print_str(p, ")");
+
+	return p;
+}
+
+/* Print "mpa" to "p" in isl format.
+ */
+static __isl_give isl_printer *print_multi_pw_aff_isl(__isl_take isl_printer *p,
+	__isl_keep isl_multi_pw_aff *mpa)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!mpa)
+		return isl_printer_free(p);
+
+	p = print_param_tuple(p, mpa->space, &data);
+	p = isl_printer_print_str(p, "{ ");
+	data.print_dim = &print_dim_mpa;
+	data.user = mpa;
+	p = isl_print_space(mpa->space, p, 0, &data);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_multi_pw_aff(
+	__isl_take isl_printer *p, __isl_keep isl_multi_pw_aff *mpa)
+{
+	if (!p || !mpa)
+		return isl_printer_free(p);
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_multi_pw_aff_isl(p, mpa);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		return isl_printer_free(p));
+}
+
+/* Print dimension "pos" of data->space to "p".
+ *
+ * data->user is assumed to be an isl_multi_val.
+ *
+ * If the current dimension is an output dimension, then print
+ * the corresponding value.  Otherwise, print the name of the dimension.
+ */
+static __isl_give isl_printer *print_dim_mv(__isl_take isl_printer *p,
+	struct isl_print_space_data *data, unsigned pos)
+{
+	isl_multi_val *mv = data->user;
+
+	if (data->type == isl_dim_out)
+		return isl_printer_print_val(p, mv->p[pos]);
+	else
+		return print_name(data->space, p, data->type, pos, data->latex);
+}
+
+/* Print the isl_multi_val "mv" to "p" in isl format.
+ */
+static __isl_give isl_printer *print_multi_val_isl(__isl_take isl_printer *p,
+	__isl_keep isl_multi_val *mv)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!mv)
+		return isl_printer_free(p);
+
+	p = print_param_tuple(p, mv->space, &data);
+	p = isl_printer_print_str(p, "{ ");
+	data.print_dim = &print_dim_mv;
+	data.user = mv;
+	p = isl_print_space(mv->space, p, 0, &data);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
+
+/* Print the isl_multi_val "mv" to "p".
+ *
+ * Currently only supported in isl format.
+ */
+__isl_give isl_printer *isl_printer_print_multi_val(
+	__isl_take isl_printer *p, __isl_keep isl_multi_val *mv)
+{
+	if (!p || !mv)
+		return isl_printer_free(p);
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_multi_val_isl(p, mv);
+	isl_die(p->ctx, isl_error_unsupported, "unsupported output format",
+		return isl_printer_free(p));
+}
+
+/* Print dimension "pos" of data->space to "p".
+ *
+ * data->user is assumed to be an isl_multi_union_pw_aff.
+ *
+ * The current dimension is necessarily a set dimension, so
+ * we print the corresponding isl_union_pw_aff, including
+ * the braces.
+ */
+static __isl_give isl_printer *print_union_pw_aff_dim(__isl_take isl_printer *p,
+	struct isl_print_space_data *data, unsigned pos)
+{
+	isl_multi_union_pw_aff *mupa = data->user;
+	isl_union_pw_aff *upa;
+
+	upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, pos);
+	p = print_union_pw_aff_body(p, upa);
+	isl_union_pw_aff_free(upa);
+
+	return p;
+}
+
+/* Print the isl_multi_union_pw_aff "mupa" to "p" in isl format.
+ */
+static __isl_give isl_printer *print_multi_union_pw_aff_isl(
+	__isl_take isl_printer *p, __isl_keep isl_multi_union_pw_aff *mupa)
+{
+	struct isl_print_space_data data = { 0 };
+	isl_space *space;
+
+	space = isl_multi_union_pw_aff_get_space(mupa);
+	p = print_param_tuple(p, space, &data);
+
+	data.print_dim = &print_union_pw_aff_dim;
+	data.user = mupa;
+
+	p = isl_print_space(space, p, 0, &data);
+	isl_space_free(space);
+
+	return p;
+}
+
+/* Print the isl_multi_union_pw_aff "mupa" to "p" in isl format.
+ *
+ * We currently only support an isl format.
+ */
+__isl_give isl_printer *isl_printer_print_multi_union_pw_aff(
+	__isl_take isl_printer *p, __isl_keep isl_multi_union_pw_aff *mupa)
+{
+	if (!p || !mupa)
+		return isl_printer_free(p);
+
+	if (p->output_format == ISL_FORMAT_ISL)
+		return print_multi_union_pw_aff_isl(p, mupa);
+	isl_die(isl_printer_get_ctx(p), isl_error_unsupported,
+		"unsupported output format", return isl_printer_free(p));
+}
diff --git a/final/lib/External/isl/isl_output_private.h b/final/lib/External/isl/isl_output_private.h
new file mode 100644
index 0000000..2e4701d
--- /dev/null
+++ b/final/lib/External/isl/isl_output_private.h
@@ -0,0 +1,27 @@
+#include <isl/space.h>
+#include <isl/printer.h>
+
+/* Internal data structure for isl_print_space.
+ *
+ * latex is set if that is the output format.
+ * print_dim (if not NULL) is called on each dimension.
+ * user is set by the caller of print_space and may be used inside print_dim.
+ *
+ * space is the global space that is being printed.  This field is set by
+ *	print_space.
+ * type is the tuple of the global space that is currently being printed.
+ *	This field is set by print_space.
+ */
+struct isl_print_space_data {
+	int latex;
+	__isl_give isl_printer *(*print_dim)(__isl_take isl_printer *p,
+		struct isl_print_space_data *data, unsigned pos);
+	void *user;
+
+	isl_space *space;
+	enum isl_dim_type type;
+};
+
+__isl_give isl_printer *isl_print_space(__isl_keep isl_space *space,
+	__isl_take isl_printer *p, int rational,
+	struct isl_print_space_data *data);
diff --git a/final/lib/External/isl/isl_point.c b/final/lib/External/isl/isl_point.c
new file mode 100644
index 0000000..48534ed
--- /dev/null
+++ b/final/lib/External/isl/isl_point.c
@@ -0,0 +1,622 @@
+#include <isl_map_private.h>
+#include <isl_point_private.h>
+#include <isl/set.h>
+#include <isl/union_set.h>
+#include <isl_sample.h>
+#include <isl_scan.h>
+#include <isl_seq.h>
+#include <isl_space_private.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl_output_private.h>
+#include <isl/deprecated/point_int.h>
+
+#include <set_to_map.c>
+
+isl_ctx *isl_point_get_ctx(__isl_keep isl_point *pnt)
+{
+	return pnt ? isl_space_get_ctx(pnt->dim) : NULL;
+}
+
+__isl_give isl_space *isl_point_get_space(__isl_keep isl_point *pnt)
+{
+	return pnt ? isl_space_copy(pnt->dim) : NULL;
+}
+
+__isl_give isl_point *isl_point_alloc(__isl_take isl_space *dim,
+	__isl_take isl_vec *vec)
+{
+	struct isl_point *pnt;
+
+	if (!dim || !vec)
+		goto error;
+
+	if (vec->size > 1 + isl_space_dim(dim, isl_dim_all)) {
+		vec = isl_vec_cow(vec);
+		if (!vec)
+			goto error;
+		vec->size = 1 + isl_space_dim(dim, isl_dim_all);
+	}
+
+	pnt = isl_alloc_type(dim->ctx, struct isl_point);
+	if (!pnt)
+		goto error;
+
+	pnt->ref = 1;
+	pnt->dim = dim;
+	pnt->vec = vec;
+
+	return pnt;
+error:
+	isl_space_free(dim);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+__isl_give isl_point *isl_point_zero(__isl_take isl_space *dim)
+{
+	isl_vec *vec;
+
+	if (!dim)
+		return NULL;
+	vec = isl_vec_alloc(dim->ctx, 1 + isl_space_dim(dim, isl_dim_all));
+	if (!vec)
+		goto error;
+	isl_int_set_si(vec->el[0], 1);
+	isl_seq_clr(vec->el + 1, vec->size - 1);
+	return isl_point_alloc(dim, vec);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_point *isl_point_dup(__isl_keep isl_point *pnt)
+{
+	struct isl_point *pnt2;
+
+	if (!pnt)
+		return NULL;
+	pnt2 = isl_point_alloc(isl_space_copy(pnt->dim), isl_vec_copy(pnt->vec));
+	return pnt2;
+}
+
+__isl_give isl_point *isl_point_cow(__isl_take isl_point *pnt)
+{
+	struct isl_point *pnt2;
+	if (!pnt)
+		return NULL;
+
+	if (pnt->ref == 1)
+		return pnt;
+
+	pnt2 = isl_point_dup(pnt);
+	isl_point_free(pnt);
+	return pnt2;
+}
+
+__isl_give isl_point *isl_point_copy(__isl_keep isl_point *pnt)
+{
+	if (!pnt)
+		return NULL;
+
+	pnt->ref++;
+	return pnt;
+}
+
+__isl_null isl_point *isl_point_free(__isl_take isl_point *pnt)
+{
+	if (!pnt)
+		return NULL;
+
+	if (--pnt->ref > 0)
+		return NULL;
+
+	isl_space_free(pnt->dim);
+	isl_vec_free(pnt->vec);
+	free(pnt);
+	return NULL;
+}
+
+__isl_give isl_point *isl_point_void(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+
+	return isl_point_alloc(dim, isl_vec_alloc(dim->ctx, 0));
+}
+
+isl_bool isl_point_is_void(__isl_keep isl_point *pnt)
+{
+	if (!pnt)
+		return isl_bool_error;
+
+	return pnt->vec->size == 0;
+}
+
+int isl_point_get_coordinate(__isl_keep isl_point *pnt,
+	enum isl_dim_type type, int pos, isl_int *v)
+{
+	if (!pnt || isl_point_is_void(pnt))
+		return -1;
+
+	if (pos < 0 || pos >= isl_space_dim(pnt->dim, type))
+		isl_die(isl_point_get_ctx(pnt), isl_error_invalid,
+			"position out of bounds", return -1);
+
+	if (type == isl_dim_set)
+		pos += isl_space_dim(pnt->dim, isl_dim_param);
+	isl_int_set(*v, pnt->vec->el[1 + pos]);
+
+	return 0;
+}
+
+/* Return the value of coordinate "pos" of type "type" of "pnt".
+ */
+__isl_give isl_val *isl_point_get_coordinate_val(__isl_keep isl_point *pnt,
+	enum isl_dim_type type, int pos)
+{
+	isl_ctx *ctx;
+	isl_val *v;
+
+	if (!pnt)
+		return NULL;
+
+	ctx = isl_point_get_ctx(pnt);
+	if (isl_point_is_void(pnt))
+		isl_die(ctx, isl_error_invalid,
+			"void point does not have coordinates", return NULL);
+	if (pos < 0 || pos >= isl_space_dim(pnt->dim, type))
+		isl_die(ctx, isl_error_invalid,
+			"position out of bounds", return NULL);
+
+	if (type == isl_dim_set)
+		pos += isl_space_dim(pnt->dim, isl_dim_param);
+
+	v = isl_val_rat_from_isl_int(ctx, pnt->vec->el[1 + pos],
+						pnt->vec->el[0]);
+	return isl_val_normalize(v);
+}
+
+__isl_give isl_point *isl_point_set_coordinate(__isl_take isl_point *pnt,
+	enum isl_dim_type type, int pos, isl_int v)
+{
+	if (!pnt || isl_point_is_void(pnt))
+		return pnt;
+
+	pnt = isl_point_cow(pnt);
+	if (!pnt)
+		return NULL;
+	pnt->vec = isl_vec_cow(pnt->vec);
+	if (!pnt->vec)
+		goto error;
+
+	if (type == isl_dim_set)
+		pos += isl_space_dim(pnt->dim, isl_dim_param);
+
+	isl_int_set(pnt->vec->el[1 + pos], v);
+
+	return pnt;
+error:
+	isl_point_free(pnt);
+	return NULL;
+}
+
+/* Replace coordinate "pos" of type "type" of "pnt" by "v".
+ */
+__isl_give isl_point *isl_point_set_coordinate_val(__isl_take isl_point *pnt,
+	enum isl_dim_type type, int pos, __isl_take isl_val *v)
+{
+	if (!pnt || !v)
+		goto error;
+	if (isl_point_is_void(pnt))
+		isl_die(isl_point_get_ctx(pnt), isl_error_invalid,
+			"void point does not have coordinates", goto error);
+	if (pos < 0 || pos >= isl_space_dim(pnt->dim, type))
+		isl_die(isl_point_get_ctx(pnt), isl_error_invalid,
+			"position out of bounds", goto error);
+	if (!isl_val_is_rat(v))
+		isl_die(isl_point_get_ctx(pnt), isl_error_invalid,
+			"expecting rational value", goto error);
+
+	if (isl_int_eq(pnt->vec->el[1 + pos], v->n) &&
+	    isl_int_eq(pnt->vec->el[0], v->d)) {
+		isl_val_free(v);
+		return pnt;
+	}
+
+	pnt = isl_point_cow(pnt);
+	if (!pnt)
+		goto error;
+	pnt->vec = isl_vec_cow(pnt->vec);
+	if (!pnt->vec)
+		goto error;
+
+	if (isl_int_eq(pnt->vec->el[0], v->d)) {
+		isl_int_set(pnt->vec->el[1 + pos], v->n);
+	} else if (isl_int_is_one(v->d)) {
+		isl_int_mul(pnt->vec->el[1 + pos], pnt->vec->el[0], v->n);
+	} else {
+		isl_seq_scale(pnt->vec->el + 1,
+				pnt->vec->el + 1, v->d, pnt->vec->size - 1);
+		isl_int_mul(pnt->vec->el[1 + pos], pnt->vec->el[0], v->n);
+		isl_int_mul(pnt->vec->el[0], pnt->vec->el[0], v->d);
+		pnt->vec = isl_vec_normalize(pnt->vec);
+		if (!pnt->vec)
+			goto error;
+	}
+
+	isl_val_free(v);
+	return pnt;
+error:
+	isl_val_free(v);
+	isl_point_free(pnt);
+	return NULL;
+}
+
+__isl_give isl_point *isl_point_add_ui(__isl_take isl_point *pnt,
+	enum isl_dim_type type, int pos, unsigned val)
+{
+	if (!pnt || isl_point_is_void(pnt))
+		return pnt;
+
+	pnt = isl_point_cow(pnt);
+	if (!pnt)
+		return NULL;
+	pnt->vec = isl_vec_cow(pnt->vec);
+	if (!pnt->vec)
+		goto error;
+
+	if (type == isl_dim_set)
+		pos += isl_space_dim(pnt->dim, isl_dim_param);
+
+	isl_int_add_ui(pnt->vec->el[1 + pos], pnt->vec->el[1 + pos], val);
+
+	return pnt;
+error:
+	isl_point_free(pnt);
+	return NULL;
+}
+
+__isl_give isl_point *isl_point_sub_ui(__isl_take isl_point *pnt,
+	enum isl_dim_type type, int pos, unsigned val)
+{
+	if (!pnt || isl_point_is_void(pnt))
+		return pnt;
+
+	pnt = isl_point_cow(pnt);
+	if (!pnt)
+		return NULL;
+	pnt->vec = isl_vec_cow(pnt->vec);
+	if (!pnt->vec)
+		goto error;
+
+	if (type == isl_dim_set)
+		pos += isl_space_dim(pnt->dim, isl_dim_param);
+
+	isl_int_sub_ui(pnt->vec->el[1 + pos], pnt->vec->el[1 + pos], val);
+
+	return pnt;
+error:
+	isl_point_free(pnt);
+	return NULL;
+}
+
+struct isl_foreach_point {
+	struct isl_scan_callback callback;
+	isl_stat (*fn)(__isl_take isl_point *pnt, void *user);
+	void *user;
+	isl_space *dim;
+};
+
+static isl_stat foreach_point(struct isl_scan_callback *cb,
+	__isl_take isl_vec *sample)
+{
+	struct isl_foreach_point *fp = (struct isl_foreach_point *)cb;
+	isl_point *pnt;
+
+	pnt = isl_point_alloc(isl_space_copy(fp->dim), sample);
+
+	return fp->fn(pnt, fp->user);
+}
+
+isl_stat isl_set_foreach_point(__isl_keep isl_set *set,
+	isl_stat (*fn)(__isl_take isl_point *pnt, void *user), void *user)
+{
+	struct isl_foreach_point fp = { { &foreach_point }, fn, user };
+	int i;
+
+	if (!set)
+		return isl_stat_error;
+
+	fp.dim = isl_set_get_space(set);
+	if (!fp.dim)
+		return isl_stat_error;
+
+	set = isl_set_copy(set);
+	set = isl_set_cow(set);
+	set = isl_set_make_disjoint(set);
+	set = isl_set_compute_divs(set);
+	if (!set)
+		goto error;
+
+	for (i = 0; i < set->n; ++i)
+		if (isl_basic_set_scan(isl_basic_set_copy(set->p[i]),
+					&fp.callback) < 0)
+			goto error;
+
+	isl_set_free(set);
+	isl_space_free(fp.dim);
+
+	return isl_stat_ok;
+error:
+	isl_set_free(set);
+	isl_space_free(fp.dim);
+	return isl_stat_error;
+}
+
+/* Return 1 if "bmap" contains the point "point".
+ * "bmap" is assumed to have known divs.
+ * The point is first extended with the divs and then passed
+ * to basic_map_contains.
+ */
+isl_bool isl_basic_map_contains_point(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_point *point)
+{
+	int i;
+	struct isl_vec *vec;
+	unsigned dim;
+	isl_bool contains;
+
+	if (!bmap || !point)
+		return isl_bool_error;
+	isl_assert(bmap->ctx, isl_space_is_equal(bmap->dim, point->dim),
+		return isl_bool_error);
+	if (bmap->n_div == 0)
+		return isl_basic_map_contains(bmap, point->vec);
+
+	dim = isl_basic_map_total_dim(bmap) - bmap->n_div;
+	vec = isl_vec_alloc(bmap->ctx, 1 + dim + bmap->n_div);
+	if (!vec)
+		return isl_bool_error;
+
+	isl_seq_cpy(vec->el, point->vec->el, point->vec->size);
+	for (i = 0; i < bmap->n_div; ++i) {
+		isl_seq_inner_product(bmap->div[i] + 1, vec->el,
+					1 + dim + i, &vec->el[1+dim+i]);
+		isl_int_fdiv_q(vec->el[1+dim+i], vec->el[1+dim+i],
+				bmap->div[i][0]);
+	}
+
+	contains = isl_basic_map_contains(bmap, vec);
+
+	isl_vec_free(vec);
+	return contains;
+}
+
+isl_bool isl_map_contains_point(__isl_keep isl_map *map,
+	__isl_keep isl_point *point)
+{
+	int i;
+	isl_bool found = isl_bool_false;
+
+	if (!map || !point)
+		return isl_bool_error;
+
+	map = isl_map_copy(map);
+	map = isl_map_compute_divs(map);
+	if (!map)
+		return isl_bool_error;
+
+	for (i = 0; i < map->n; ++i) {
+		found = isl_basic_map_contains_point(map->p[i], point);
+		if (found < 0)
+			goto error;
+		if (found)
+			break;
+	}
+	isl_map_free(map);
+
+	return found;
+error:
+	isl_map_free(map);
+	return isl_bool_error;
+}
+
+isl_bool isl_set_contains_point(__isl_keep isl_set *set,
+	__isl_keep isl_point *point)
+{
+	return isl_map_contains_point(set_to_map(set), point);
+}
+
+__isl_give isl_basic_set *isl_basic_set_from_point(__isl_take isl_point *pnt)
+{
+	isl_basic_set *bset;
+	isl_basic_set *model;
+
+	if (!pnt)
+		return NULL;
+
+	model = isl_basic_set_empty(isl_space_copy(pnt->dim));
+	bset = isl_basic_set_from_vec(isl_vec_copy(pnt->vec));
+	bset = isl_basic_set_from_underlying_set(bset, model);
+	isl_point_free(pnt);
+
+	return bset;
+}
+
+__isl_give isl_set *isl_set_from_point(__isl_take isl_point *pnt)
+{
+	isl_basic_set *bset;
+	bset = isl_basic_set_from_point(pnt);
+	return isl_set_from_basic_set(bset);
+}
+
+/* Construct a union set, containing the single element "pnt".
+ * If "pnt" is void, then return an empty union set.
+ */
+__isl_give isl_union_set *isl_union_set_from_point(__isl_take isl_point *pnt)
+{
+	if (!pnt)
+		return NULL;
+	if (isl_point_is_void(pnt)) {
+		isl_space *space;
+
+		space = isl_point_get_space(pnt);
+		isl_point_free(pnt);
+		return isl_union_set_empty(space);
+	}
+
+	return isl_union_set_from_set(isl_set_from_point(pnt));
+}
+
+__isl_give isl_basic_set *isl_basic_set_box_from_points(
+	__isl_take isl_point *pnt1, __isl_take isl_point *pnt2)
+{
+	isl_basic_set *bset = NULL;
+	unsigned total;
+	int i;
+	int k;
+	isl_int t;
+
+	isl_int_init(t);
+
+	if (!pnt1 || !pnt2)
+		goto error;
+
+	isl_assert(pnt1->dim->ctx,
+			isl_space_is_equal(pnt1->dim, pnt2->dim), goto error);
+
+	if (isl_point_is_void(pnt1) && isl_point_is_void(pnt2)) {
+		isl_space *dim = isl_space_copy(pnt1->dim);
+		isl_point_free(pnt1);
+		isl_point_free(pnt2);
+		isl_int_clear(t);
+		return isl_basic_set_empty(dim);
+	}
+	if (isl_point_is_void(pnt1)) {
+		isl_point_free(pnt1);
+		isl_int_clear(t);
+		return isl_basic_set_from_point(pnt2);
+	}
+	if (isl_point_is_void(pnt2)) {
+		isl_point_free(pnt2);
+		isl_int_clear(t);
+		return isl_basic_set_from_point(pnt1);
+	}
+
+	total = isl_space_dim(pnt1->dim, isl_dim_all);
+	bset = isl_basic_set_alloc_space(isl_space_copy(pnt1->dim), 0, 0, 2 * total);
+
+	for (i = 0; i < total; ++i) {
+		isl_int_mul(t, pnt1->vec->el[1 + i], pnt2->vec->el[0]);
+		isl_int_submul(t, pnt2->vec->el[1 + i], pnt1->vec->el[0]);
+
+		k = isl_basic_set_alloc_inequality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bset->ineq[k] + 1, total);
+		if (isl_int_is_pos(t)) {
+			isl_int_set_si(bset->ineq[k][1 + i], -1);
+			isl_int_set(bset->ineq[k][0], pnt1->vec->el[1 + i]);
+		} else {
+			isl_int_set_si(bset->ineq[k][1 + i], 1);
+			isl_int_neg(bset->ineq[k][0], pnt1->vec->el[1 + i]);
+		}
+		isl_int_fdiv_q(bset->ineq[k][0], bset->ineq[k][0], pnt1->vec->el[0]);
+
+		k = isl_basic_set_alloc_inequality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bset->ineq[k] + 1, total);
+		if (isl_int_is_pos(t)) {
+			isl_int_set_si(bset->ineq[k][1 + i], 1);
+			isl_int_neg(bset->ineq[k][0], pnt2->vec->el[1 + i]);
+		} else {
+			isl_int_set_si(bset->ineq[k][1 + i], -1);
+			isl_int_set(bset->ineq[k][0], pnt2->vec->el[1 + i]);
+		}
+		isl_int_fdiv_q(bset->ineq[k][0], bset->ineq[k][0], pnt2->vec->el[0]);
+	}
+
+	bset = isl_basic_set_finalize(bset);
+
+	isl_point_free(pnt1);
+	isl_point_free(pnt2);
+
+	isl_int_clear(t);
+
+	return bset;
+error:
+	isl_point_free(pnt1);
+	isl_point_free(pnt2);
+	isl_int_clear(t);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_box_from_points(__isl_take isl_point *pnt1,
+	__isl_take isl_point *pnt2)
+{
+	isl_basic_set *bset;
+	bset = isl_basic_set_box_from_points(pnt1, pnt2);
+	return isl_set_from_basic_set(bset);
+}
+
+/* Print the coordinate at position "pos" of the point "pnt".
+ */
+static __isl_give isl_printer *print_coordinate(__isl_take isl_printer *p,
+	struct isl_print_space_data *data, unsigned pos)
+{
+	isl_point *pnt = data->user;
+
+	p = isl_printer_print_isl_int(p, pnt->vec->el[1 + pos]);
+	if (!isl_int_is_one(pnt->vec->el[0])) {
+		p = isl_printer_print_str(p, "/");
+		p = isl_printer_print_isl_int(p, pnt->vec->el[0]);
+	}
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_point(
+	__isl_take isl_printer *p, __isl_keep isl_point *pnt)
+{
+	struct isl_print_space_data data = { 0 };
+	int i;
+	unsigned nparam;
+
+	if (!pnt)
+		return p;
+	if (isl_point_is_void(pnt)) {
+		p = isl_printer_print_str(p, "void");
+		return p;
+	}
+
+	nparam = isl_space_dim(pnt->dim, isl_dim_param);
+	if (nparam > 0) {
+		p = isl_printer_print_str(p, "[");
+		for (i = 0; i < nparam; ++i) {
+			const char *name;
+			if (i)
+				p = isl_printer_print_str(p, ", ");
+			name = isl_space_get_dim_name(pnt->dim, isl_dim_param, i);
+			if (name) {
+				p = isl_printer_print_str(p, name);
+				p = isl_printer_print_str(p, " = ");
+			}
+			p = isl_printer_print_isl_int(p, pnt->vec->el[1 + i]);
+			if (!isl_int_is_one(pnt->vec->el[0])) {
+				p = isl_printer_print_str(p, "/");
+				p = isl_printer_print_isl_int(p, pnt->vec->el[0]);
+			}
+		}
+		p = isl_printer_print_str(p, "]");
+		p = isl_printer_print_str(p, " -> ");
+	}
+	data.print_dim = &print_coordinate;
+	data.user = pnt;
+	p = isl_printer_print_str(p, "{ ");
+	p = isl_print_space(pnt->dim, p, 0, &data);
+	p = isl_printer_print_str(p, " }");
+	return p;
+}
diff --git a/final/lib/External/isl/isl_point_private.h b/final/lib/External/isl/isl_point_private.h
new file mode 100644
index 0000000..305b81e
--- /dev/null
+++ b/final/lib/External/isl/isl_point_private.h
@@ -0,0 +1,12 @@
+#include <isl/space.h>
+#include <isl/point.h>
+#include <isl/vec.h>
+
+struct isl_point {
+	int		ref;
+	isl_space	*dim;
+	struct isl_vec	*vec;
+};
+
+__isl_give isl_point *isl_point_alloc(__isl_take isl_space *dim,
+	__isl_take isl_vec *vec);
diff --git a/final/lib/External/isl/isl_polynomial.c b/final/lib/External/isl/isl_polynomial.c
new file mode 100644
index 0000000..2f4ba43
--- /dev/null
+++ b/final/lib/External/isl/isl_polynomial.c
@@ -0,0 +1,5020 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France 
+ */
+
+#include <stdlib.h>
+#define ISL_DIM_H
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_factorization.h>
+#include <isl_lp_private.h>
+#include <isl_seq.h>
+#include <isl_union_map_private.h>
+#include <isl_constraint_private.h>
+#include <isl_polynomial_private.h>
+#include <isl_point_private.h>
+#include <isl_space_private.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl_range.h>
+#include <isl_local.h>
+#include <isl_local_space_private.h>
+#include <isl_aff_private.h>
+#include <isl_val_private.h>
+#include <isl_config.h>
+#include <isl/deprecated/polynomial_int.h>
+
+static unsigned pos(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	switch (type) {
+	case isl_dim_param:	return 0;
+	case isl_dim_in:	return dim->nparam;
+	case isl_dim_out:	return dim->nparam + dim->n_in;
+	default:		return 0;
+	}
+}
+
+int isl_upoly_is_cst(__isl_keep struct isl_upoly *up)
+{
+	if (!up)
+		return -1;
+
+	return up->var < 0;
+}
+
+__isl_keep struct isl_upoly_cst *isl_upoly_as_cst(__isl_keep struct isl_upoly *up)
+{
+	if (!up)
+		return NULL;
+
+	isl_assert(up->ctx, up->var < 0, return NULL);
+
+	return (struct isl_upoly_cst *)up;
+}
+
+__isl_keep struct isl_upoly_rec *isl_upoly_as_rec(__isl_keep struct isl_upoly *up)
+{
+	if (!up)
+		return NULL;
+
+	isl_assert(up->ctx, up->var >= 0, return NULL);
+
+	return (struct isl_upoly_rec *)up;
+}
+
+/* Compare two polynomials.
+ *
+ * Return -1 if "up1" is "smaller" than "up2", 1 if "up1" is "greater"
+ * than "up2" and 0 if they are equal.
+ */
+static int isl_upoly_plain_cmp(__isl_keep struct isl_upoly *up1,
+	__isl_keep struct isl_upoly *up2)
+{
+	int i;
+	struct isl_upoly_rec *rec1, *rec2;
+
+	if (up1 == up2)
+		return 0;
+	if (!up1)
+		return -1;
+	if (!up2)
+		return 1;
+	if (up1->var != up2->var)
+		return up1->var - up2->var;
+
+	if (isl_upoly_is_cst(up1)) {
+		struct isl_upoly_cst *cst1, *cst2;
+		int cmp;
+
+		cst1 = isl_upoly_as_cst(up1);
+		cst2 = isl_upoly_as_cst(up2);
+		if (!cst1 || !cst2)
+			return 0;
+		cmp = isl_int_cmp(cst1->n, cst2->n);
+		if (cmp != 0)
+			return cmp;
+		return isl_int_cmp(cst1->d, cst2->d);
+	}
+
+	rec1 = isl_upoly_as_rec(up1);
+	rec2 = isl_upoly_as_rec(up2);
+	if (!rec1 || !rec2)
+		return 0;
+
+	if (rec1->n != rec2->n)
+		return rec1->n - rec2->n;
+
+	for (i = 0; i < rec1->n; ++i) {
+		int cmp = isl_upoly_plain_cmp(rec1->p[i], rec2->p[i]);
+		if (cmp != 0)
+			return cmp;
+	}
+
+	return 0;
+}
+
+isl_bool isl_upoly_is_equal(__isl_keep struct isl_upoly *up1,
+	__isl_keep struct isl_upoly *up2)
+{
+	int i;
+	struct isl_upoly_rec *rec1, *rec2;
+
+	if (!up1 || !up2)
+		return isl_bool_error;
+	if (up1 == up2)
+		return isl_bool_true;
+	if (up1->var != up2->var)
+		return isl_bool_false;
+	if (isl_upoly_is_cst(up1)) {
+		struct isl_upoly_cst *cst1, *cst2;
+		cst1 = isl_upoly_as_cst(up1);
+		cst2 = isl_upoly_as_cst(up2);
+		if (!cst1 || !cst2)
+			return isl_bool_error;
+		return isl_int_eq(cst1->n, cst2->n) &&
+		       isl_int_eq(cst1->d, cst2->d);
+	}
+
+	rec1 = isl_upoly_as_rec(up1);
+	rec2 = isl_upoly_as_rec(up2);
+	if (!rec1 || !rec2)
+		return isl_bool_error;
+
+	if (rec1->n != rec2->n)
+		return isl_bool_false;
+
+	for (i = 0; i < rec1->n; ++i) {
+		isl_bool eq = isl_upoly_is_equal(rec1->p[i], rec2->p[i]);
+		if (eq < 0 || !eq)
+			return eq;
+	}
+
+	return isl_bool_true;
+}
+
+int isl_upoly_is_zero(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return -1;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return -1;
+
+	return isl_int_is_zero(cst->n) && isl_int_is_pos(cst->d);
+}
+
+int isl_upoly_sgn(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return 0;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return 0;
+
+	return isl_int_sgn(cst->n);
+}
+
+int isl_upoly_is_nan(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return -1;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return -1;
+
+	return isl_int_is_zero(cst->n) && isl_int_is_zero(cst->d);
+}
+
+int isl_upoly_is_infty(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return -1;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return -1;
+
+	return isl_int_is_pos(cst->n) && isl_int_is_zero(cst->d);
+}
+
+int isl_upoly_is_neginfty(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return -1;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return -1;
+
+	return isl_int_is_neg(cst->n) && isl_int_is_zero(cst->d);
+}
+
+int isl_upoly_is_one(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return -1;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return -1;
+
+	return isl_int_eq(cst->n, cst->d) && isl_int_is_pos(cst->d);
+}
+
+int isl_upoly_is_negone(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return -1;
+	if (!isl_upoly_is_cst(up))
+		return 0;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return -1;
+
+	return isl_int_is_negone(cst->n) && isl_int_is_one(cst->d);
+}
+
+__isl_give struct isl_upoly_cst *isl_upoly_cst_alloc(struct isl_ctx *ctx)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_alloc_type(ctx, struct isl_upoly_cst);
+	if (!cst)
+		return NULL;
+
+	cst->up.ref = 1;
+	cst->up.ctx = ctx;
+	isl_ctx_ref(ctx);
+	cst->up.var = -1;
+
+	isl_int_init(cst->n);
+	isl_int_init(cst->d);
+
+	return cst;
+}
+
+__isl_give struct isl_upoly *isl_upoly_zero(struct isl_ctx *ctx)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_cst_alloc(ctx);
+	if (!cst)
+		return NULL;
+
+	isl_int_set_si(cst->n, 0);
+	isl_int_set_si(cst->d, 1);
+
+	return &cst->up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_one(struct isl_ctx *ctx)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_cst_alloc(ctx);
+	if (!cst)
+		return NULL;
+
+	isl_int_set_si(cst->n, 1);
+	isl_int_set_si(cst->d, 1);
+
+	return &cst->up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_infty(struct isl_ctx *ctx)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_cst_alloc(ctx);
+	if (!cst)
+		return NULL;
+
+	isl_int_set_si(cst->n, 1);
+	isl_int_set_si(cst->d, 0);
+
+	return &cst->up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_neginfty(struct isl_ctx *ctx)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_cst_alloc(ctx);
+	if (!cst)
+		return NULL;
+
+	isl_int_set_si(cst->n, -1);
+	isl_int_set_si(cst->d, 0);
+
+	return &cst->up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_nan(struct isl_ctx *ctx)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_cst_alloc(ctx);
+	if (!cst)
+		return NULL;
+
+	isl_int_set_si(cst->n, 0);
+	isl_int_set_si(cst->d, 0);
+
+	return &cst->up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_rat_cst(struct isl_ctx *ctx,
+	isl_int n, isl_int d)
+{
+	struct isl_upoly_cst *cst;
+
+	cst = isl_upoly_cst_alloc(ctx);
+	if (!cst)
+		return NULL;
+
+	isl_int_set(cst->n, n);
+	isl_int_set(cst->d, d);
+
+	return &cst->up;
+}
+
+__isl_give struct isl_upoly_rec *isl_upoly_alloc_rec(struct isl_ctx *ctx,
+	int var, int size)
+{
+	struct isl_upoly_rec *rec;
+
+	isl_assert(ctx, var >= 0, return NULL);
+	isl_assert(ctx, size >= 0, return NULL);
+	rec = isl_calloc(ctx, struct isl_upoly_rec,
+			sizeof(struct isl_upoly_rec) +
+			size * sizeof(struct isl_upoly *));
+	if (!rec)
+		return NULL;
+
+	rec->up.ref = 1;
+	rec->up.ctx = ctx;
+	isl_ctx_ref(ctx);
+	rec->up.var = var;
+
+	rec->n = 0;
+	rec->size = size;
+
+	return rec;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_reset_domain_space(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_space *dim)
+{
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp || !dim)
+		goto error;
+
+	isl_space_free(qp->dim);
+	qp->dim = dim;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Reset the space of "qp".  This function is called from isl_pw_templ.c
+ * and doesn't know if the space of an element object is represented
+ * directly or through its domain.  It therefore passes along both.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_reset_space_and_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_space *space,
+	__isl_take isl_space *domain)
+{
+	isl_space_free(space);
+	return isl_qpolynomial_reset_domain_space(qp, domain);
+}
+
+isl_ctx *isl_qpolynomial_get_ctx(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? qp->dim->ctx : NULL;
+}
+
+__isl_give isl_space *isl_qpolynomial_get_domain_space(
+	__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_space_copy(qp->dim) : NULL;
+}
+
+__isl_give isl_space *isl_qpolynomial_get_space(__isl_keep isl_qpolynomial *qp)
+{
+	isl_space *space;
+	if (!qp)
+		return NULL;
+	space = isl_space_copy(qp->dim);
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, 1);
+	return space;
+}
+
+/* Return the number of variables of the given type in the domain of "qp".
+ */
+unsigned isl_qpolynomial_domain_dim(__isl_keep isl_qpolynomial *qp,
+	enum isl_dim_type type)
+{
+	if (!qp)
+		return 0;
+	if (type == isl_dim_div)
+		return qp->div->n_row;
+	if (type == isl_dim_all)
+		return isl_space_dim(qp->dim, isl_dim_all) +
+				    isl_qpolynomial_domain_dim(qp, isl_dim_div);
+	return isl_space_dim(qp->dim, type);
+}
+
+/* Externally, an isl_qpolynomial has a map space, but internally, the
+ * ls field corresponds to the domain of that space.
+ */
+unsigned isl_qpolynomial_dim(__isl_keep isl_qpolynomial *qp,
+	enum isl_dim_type type)
+{
+	if (!qp)
+		return 0;
+	if (type == isl_dim_out)
+		return 1;
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	return isl_qpolynomial_domain_dim(qp, type);
+}
+
+/* Return the offset of the first coefficient of type "type" in
+ * the domain of "qp".
+ */
+unsigned isl_qpolynomial_domain_offset(__isl_keep isl_qpolynomial *qp,
+	enum isl_dim_type type)
+{
+	if (!qp)
+		return 0;
+	switch (type) {
+	case isl_dim_cst:
+		return 0;
+	case isl_dim_param:
+	case isl_dim_set:
+		return 1 + isl_space_offset(qp->dim, type);
+	case isl_dim_div:
+		return 1 + isl_space_dim(qp->dim, isl_dim_all);
+	default:
+		return 0;
+	}
+}
+
+isl_bool isl_qpolynomial_is_zero(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_upoly_is_zero(qp->upoly) : isl_bool_error;
+}
+
+isl_bool isl_qpolynomial_is_one(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_upoly_is_one(qp->upoly) : isl_bool_error;
+}
+
+isl_bool isl_qpolynomial_is_nan(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_upoly_is_nan(qp->upoly) : isl_bool_error;
+}
+
+isl_bool isl_qpolynomial_is_infty(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_upoly_is_infty(qp->upoly) : isl_bool_error;
+}
+
+isl_bool isl_qpolynomial_is_neginfty(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_upoly_is_neginfty(qp->upoly) : isl_bool_error;
+}
+
+int isl_qpolynomial_sgn(__isl_keep isl_qpolynomial *qp)
+{
+	return qp ? isl_upoly_sgn(qp->upoly) : 0;
+}
+
+static void upoly_free_cst(__isl_take struct isl_upoly_cst *cst)
+{
+	isl_int_clear(cst->n);
+	isl_int_clear(cst->d);
+}
+
+static void upoly_free_rec(__isl_take struct isl_upoly_rec *rec)
+{
+	int i;
+
+	for (i = 0; i < rec->n; ++i)
+		isl_upoly_free(rec->p[i]);
+}
+
+__isl_give struct isl_upoly *isl_upoly_copy(__isl_keep struct isl_upoly *up)
+{
+	if (!up)
+		return NULL;
+
+	up->ref++;
+	return up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_dup_cst(__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+	struct isl_upoly_cst *dup;
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return NULL;
+
+	dup = isl_upoly_as_cst(isl_upoly_zero(up->ctx));
+	if (!dup)
+		return NULL;
+	isl_int_set(dup->n, cst->n);
+	isl_int_set(dup->d, cst->d);
+
+	return &dup->up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_dup_rec(__isl_keep struct isl_upoly *up)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+	struct isl_upoly_rec *dup;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		return NULL;
+
+	dup = isl_upoly_alloc_rec(up->ctx, up->var, rec->n);
+	if (!dup)
+		return NULL;
+
+	for (i = 0; i < rec->n; ++i) {
+		dup->p[i] = isl_upoly_copy(rec->p[i]);
+		if (!dup->p[i])
+			goto error;
+		dup->n++;
+	}
+
+	return &dup->up;
+error:
+	isl_upoly_free(&dup->up);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_dup(__isl_keep struct isl_upoly *up)
+{
+	if (!up)
+		return NULL;
+
+	if (isl_upoly_is_cst(up))
+		return isl_upoly_dup_cst(up);
+	else
+		return isl_upoly_dup_rec(up);
+}
+
+__isl_give struct isl_upoly *isl_upoly_cow(__isl_take struct isl_upoly *up)
+{
+	if (!up)
+		return NULL;
+
+	if (up->ref == 1)
+		return up;
+	up->ref--;
+	return isl_upoly_dup(up);
+}
+
+__isl_null struct isl_upoly *isl_upoly_free(__isl_take struct isl_upoly *up)
+{
+	if (!up)
+		return NULL;
+
+	if (--up->ref > 0)
+		return NULL;
+
+	if (up->var < 0)
+		upoly_free_cst((struct isl_upoly_cst *)up);
+	else
+		upoly_free_rec((struct isl_upoly_rec *)up);
+
+	isl_ctx_deref(up->ctx);
+	free(up);
+	return NULL;
+}
+
+static void isl_upoly_cst_reduce(__isl_keep struct isl_upoly_cst *cst)
+{
+	isl_int gcd;
+
+	isl_int_init(gcd);
+	isl_int_gcd(gcd, cst->n, cst->d);
+	if (!isl_int_is_zero(gcd) && !isl_int_is_one(gcd)) {
+		isl_int_divexact(cst->n, cst->n, gcd);
+		isl_int_divexact(cst->d, cst->d, gcd);
+	}
+	isl_int_clear(gcd);
+}
+
+__isl_give struct isl_upoly *isl_upoly_sum_cst(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2)
+{
+	struct isl_upoly_cst *cst1;
+	struct isl_upoly_cst *cst2;
+
+	up1 = isl_upoly_cow(up1);
+	if (!up1 || !up2)
+		goto error;
+
+	cst1 = isl_upoly_as_cst(up1);
+	cst2 = isl_upoly_as_cst(up2);
+
+	if (isl_int_eq(cst1->d, cst2->d))
+		isl_int_add(cst1->n, cst1->n, cst2->n);
+	else {
+		isl_int_mul(cst1->n, cst1->n, cst2->d);
+		isl_int_addmul(cst1->n, cst2->n, cst1->d);
+		isl_int_mul(cst1->d, cst1->d, cst2->d);
+	}
+
+	isl_upoly_cst_reduce(cst1);
+
+	isl_upoly_free(up2);
+	return up1;
+error:
+	isl_upoly_free(up1);
+	isl_upoly_free(up2);
+	return NULL;
+}
+
+static __isl_give struct isl_upoly *replace_by_zero(
+	__isl_take struct isl_upoly *up)
+{
+	struct isl_ctx *ctx;
+
+	if (!up)
+		return NULL;
+	ctx = up->ctx;
+	isl_upoly_free(up);
+	return isl_upoly_zero(ctx);
+}
+
+static __isl_give struct isl_upoly *replace_by_constant_term(
+	__isl_take struct isl_upoly *up)
+{
+	struct isl_upoly_rec *rec;
+	struct isl_upoly *cst;
+
+	if (!up)
+		return NULL;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+	cst = isl_upoly_copy(rec->p[0]);
+	isl_upoly_free(up);
+	return cst;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_sum(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2)
+{
+	int i;
+	struct isl_upoly_rec *rec1, *rec2;
+
+	if (!up1 || !up2)
+		goto error;
+
+	if (isl_upoly_is_nan(up1)) {
+		isl_upoly_free(up2);
+		return up1;
+	}
+
+	if (isl_upoly_is_nan(up2)) {
+		isl_upoly_free(up1);
+		return up2;
+	}
+
+	if (isl_upoly_is_zero(up1)) {
+		isl_upoly_free(up1);
+		return up2;
+	}
+
+	if (isl_upoly_is_zero(up2)) {
+		isl_upoly_free(up2);
+		return up1;
+	}
+
+	if (up1->var < up2->var)
+		return isl_upoly_sum(up2, up1);
+
+	if (up2->var < up1->var) {
+		struct isl_upoly_rec *rec;
+		if (isl_upoly_is_infty(up2) || isl_upoly_is_neginfty(up2)) {
+			isl_upoly_free(up1);
+			return up2;
+		}
+		up1 = isl_upoly_cow(up1);
+		rec = isl_upoly_as_rec(up1);
+		if (!rec)
+			goto error;
+		rec->p[0] = isl_upoly_sum(rec->p[0], up2);
+		if (rec->n == 1)
+			up1 = replace_by_constant_term(up1);
+		return up1;
+	}
+
+	if (isl_upoly_is_cst(up1))
+		return isl_upoly_sum_cst(up1, up2);
+
+	rec1 = isl_upoly_as_rec(up1);
+	rec2 = isl_upoly_as_rec(up2);
+	if (!rec1 || !rec2)
+		goto error;
+
+	if (rec1->n < rec2->n)
+		return isl_upoly_sum(up2, up1);
+
+	up1 = isl_upoly_cow(up1);
+	rec1 = isl_upoly_as_rec(up1);
+	if (!rec1)
+		goto error;
+
+	for (i = rec2->n - 1; i >= 0; --i) {
+		rec1->p[i] = isl_upoly_sum(rec1->p[i],
+					    isl_upoly_copy(rec2->p[i]));
+		if (!rec1->p[i])
+			goto error;
+		if (i == rec1->n - 1 && isl_upoly_is_zero(rec1->p[i])) {
+			isl_upoly_free(rec1->p[i]);
+			rec1->n--;
+		}
+	}
+
+	if (rec1->n == 0)
+		up1 = replace_by_zero(up1);
+	else if (rec1->n == 1)
+		up1 = replace_by_constant_term(up1);
+
+	isl_upoly_free(up2);
+
+	return up1;
+error:
+	isl_upoly_free(up1);
+	isl_upoly_free(up2);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_cst_add_isl_int(
+	__isl_take struct isl_upoly *up, isl_int v)
+{
+	struct isl_upoly_cst *cst;
+
+	up = isl_upoly_cow(up);
+	if (!up)
+		return NULL;
+
+	cst = isl_upoly_as_cst(up);
+
+	isl_int_addmul(cst->n, cst->d, v);
+
+	return up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_add_isl_int(
+	__isl_take struct isl_upoly *up, isl_int v)
+{
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return NULL;
+
+	if (isl_upoly_is_cst(up))
+		return isl_upoly_cst_add_isl_int(up, v);
+
+	up = isl_upoly_cow(up);
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	rec->p[0] = isl_upoly_add_isl_int(rec->p[0], v);
+	if (!rec->p[0])
+		goto error;
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_cst_mul_isl_int(
+	__isl_take struct isl_upoly *up, isl_int v)
+{
+	struct isl_upoly_cst *cst;
+
+	if (isl_upoly_is_zero(up))
+		return up;
+
+	up = isl_upoly_cow(up);
+	if (!up)
+		return NULL;
+
+	cst = isl_upoly_as_cst(up);
+
+	isl_int_mul(cst->n, cst->n, v);
+
+	return up;
+}
+
+__isl_give struct isl_upoly *isl_upoly_mul_isl_int(
+	__isl_take struct isl_upoly *up, isl_int v)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return NULL;
+
+	if (isl_upoly_is_cst(up))
+		return isl_upoly_cst_mul_isl_int(up, v);
+
+	up = isl_upoly_cow(up);
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		rec->p[i] = isl_upoly_mul_isl_int(rec->p[i], v);
+		if (!rec->p[i])
+			goto error;
+	}
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+/* Multiply the constant polynomial "up" by "v".
+ */
+static __isl_give struct isl_upoly *isl_upoly_cst_scale_val(
+	__isl_take struct isl_upoly *up, __isl_keep isl_val *v)
+{
+	struct isl_upoly_cst *cst;
+
+	if (isl_upoly_is_zero(up))
+		return up;
+
+	up = isl_upoly_cow(up);
+	if (!up)
+		return NULL;
+
+	cst = isl_upoly_as_cst(up);
+
+	isl_int_mul(cst->n, cst->n, v->n);
+	isl_int_mul(cst->d, cst->d, v->d);
+	isl_upoly_cst_reduce(cst);
+
+	return up;
+}
+
+/* Multiply the polynomial "up" by "v".
+ */
+static __isl_give struct isl_upoly *isl_upoly_scale_val(
+	__isl_take struct isl_upoly *up, __isl_keep isl_val *v)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return NULL;
+
+	if (isl_upoly_is_cst(up))
+		return isl_upoly_cst_scale_val(up, v);
+
+	up = isl_upoly_cow(up);
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		rec->p[i] = isl_upoly_scale_val(rec->p[i], v);
+		if (!rec->p[i])
+			goto error;
+	}
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_mul_cst(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2)
+{
+	struct isl_upoly_cst *cst1;
+	struct isl_upoly_cst *cst2;
+
+	up1 = isl_upoly_cow(up1);
+	if (!up1 || !up2)
+		goto error;
+
+	cst1 = isl_upoly_as_cst(up1);
+	cst2 = isl_upoly_as_cst(up2);
+
+	isl_int_mul(cst1->n, cst1->n, cst2->n);
+	isl_int_mul(cst1->d, cst1->d, cst2->d);
+
+	isl_upoly_cst_reduce(cst1);
+
+	isl_upoly_free(up2);
+	return up1;
+error:
+	isl_upoly_free(up1);
+	isl_upoly_free(up2);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_mul_rec(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2)
+{
+	struct isl_upoly_rec *rec1;
+	struct isl_upoly_rec *rec2;
+	struct isl_upoly_rec *res = NULL;
+	int i, j;
+	int size;
+
+	rec1 = isl_upoly_as_rec(up1);
+	rec2 = isl_upoly_as_rec(up2);
+	if (!rec1 || !rec2)
+		goto error;
+	size = rec1->n + rec2->n - 1;
+	res = isl_upoly_alloc_rec(up1->ctx, up1->var, size);
+	if (!res)
+		goto error;
+
+	for (i = 0; i < rec1->n; ++i) {
+		res->p[i] = isl_upoly_mul(isl_upoly_copy(rec2->p[0]),
+					    isl_upoly_copy(rec1->p[i]));
+		if (!res->p[i])
+			goto error;
+		res->n++;
+	}
+	for (; i < size; ++i) {
+		res->p[i] = isl_upoly_zero(up1->ctx);
+		if (!res->p[i])
+			goto error;
+		res->n++;
+	}
+	for (i = 0; i < rec1->n; ++i) {
+		for (j = 1; j < rec2->n; ++j) {
+			struct isl_upoly *up;
+			up = isl_upoly_mul(isl_upoly_copy(rec2->p[j]),
+					    isl_upoly_copy(rec1->p[i]));
+			res->p[i + j] = isl_upoly_sum(res->p[i + j], up);
+			if (!res->p[i + j])
+				goto error;
+		}
+	}
+
+	isl_upoly_free(up1);
+	isl_upoly_free(up2);
+
+	return &res->up;
+error:
+	isl_upoly_free(up1);
+	isl_upoly_free(up2);
+	isl_upoly_free(&res->up);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_mul(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2)
+{
+	if (!up1 || !up2)
+		goto error;
+
+	if (isl_upoly_is_nan(up1)) {
+		isl_upoly_free(up2);
+		return up1;
+	}
+
+	if (isl_upoly_is_nan(up2)) {
+		isl_upoly_free(up1);
+		return up2;
+	}
+
+	if (isl_upoly_is_zero(up1)) {
+		isl_upoly_free(up2);
+		return up1;
+	}
+
+	if (isl_upoly_is_zero(up2)) {
+		isl_upoly_free(up1);
+		return up2;
+	}
+
+	if (isl_upoly_is_one(up1)) {
+		isl_upoly_free(up1);
+		return up2;
+	}
+
+	if (isl_upoly_is_one(up2)) {
+		isl_upoly_free(up2);
+		return up1;
+	}
+
+	if (up1->var < up2->var)
+		return isl_upoly_mul(up2, up1);
+
+	if (up2->var < up1->var) {
+		int i;
+		struct isl_upoly_rec *rec;
+		if (isl_upoly_is_infty(up2) || isl_upoly_is_neginfty(up2)) {
+			isl_ctx *ctx = up1->ctx;
+			isl_upoly_free(up1);
+			isl_upoly_free(up2);
+			return isl_upoly_nan(ctx);
+		}
+		up1 = isl_upoly_cow(up1);
+		rec = isl_upoly_as_rec(up1);
+		if (!rec)
+			goto error;
+
+		for (i = 0; i < rec->n; ++i) {
+			rec->p[i] = isl_upoly_mul(rec->p[i],
+						    isl_upoly_copy(up2));
+			if (!rec->p[i])
+				goto error;
+		}
+		isl_upoly_free(up2);
+		return up1;
+	}
+
+	if (isl_upoly_is_cst(up1))
+		return isl_upoly_mul_cst(up1, up2);
+
+	return isl_upoly_mul_rec(up1, up2);
+error:
+	isl_upoly_free(up1);
+	isl_upoly_free(up2);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_pow(__isl_take struct isl_upoly *up,
+	unsigned power)
+{
+	struct isl_upoly *res;
+
+	if (!up)
+		return NULL;
+	if (power == 1)
+		return up;
+
+	if (power % 2)
+		res = isl_upoly_copy(up);
+	else
+		res = isl_upoly_one(up->ctx);
+
+	while (power >>= 1) {
+		up = isl_upoly_mul(up, isl_upoly_copy(up));
+		if (power % 2)
+			res = isl_upoly_mul(res, isl_upoly_copy(up));
+	}
+
+	isl_upoly_free(up);
+	return res;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_alloc(__isl_take isl_space *dim,
+	unsigned n_div, __isl_take struct isl_upoly *up)
+{
+	struct isl_qpolynomial *qp = NULL;
+	unsigned total;
+
+	if (!dim || !up)
+		goto error;
+
+	if (!isl_space_is_set(dim))
+		isl_die(isl_space_get_ctx(dim), isl_error_invalid,
+			"domain of polynomial should be a set", goto error);
+
+	total = isl_space_dim(dim, isl_dim_all);
+
+	qp = isl_calloc_type(dim->ctx, struct isl_qpolynomial);
+	if (!qp)
+		goto error;
+
+	qp->ref = 1;
+	qp->div = isl_mat_alloc(dim->ctx, n_div, 1 + 1 + total + n_div);
+	if (!qp->div)
+		goto error;
+
+	qp->dim = dim;
+	qp->upoly = up;
+
+	return qp;
+error:
+	isl_space_free(dim);
+	isl_upoly_free(up);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_copy(__isl_keep isl_qpolynomial *qp)
+{
+	if (!qp)
+		return NULL;
+
+	qp->ref++;
+	return qp;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_dup(__isl_keep isl_qpolynomial *qp)
+{
+	struct isl_qpolynomial *dup;
+
+	if (!qp)
+		return NULL;
+
+	dup = isl_qpolynomial_alloc(isl_space_copy(qp->dim), qp->div->n_row,
+				    isl_upoly_copy(qp->upoly));
+	if (!dup)
+		return NULL;
+	isl_mat_free(dup->div);
+	dup->div = isl_mat_copy(qp->div);
+	if (!dup->div)
+		goto error;
+
+	return dup;
+error:
+	isl_qpolynomial_free(dup);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_cow(__isl_take isl_qpolynomial *qp)
+{
+	if (!qp)
+		return NULL;
+
+	if (qp->ref == 1)
+		return qp;
+	qp->ref--;
+	return isl_qpolynomial_dup(qp);
+}
+
+__isl_null isl_qpolynomial *isl_qpolynomial_free(
+	__isl_take isl_qpolynomial *qp)
+{
+	if (!qp)
+		return NULL;
+
+	if (--qp->ref > 0)
+		return NULL;
+
+	isl_space_free(qp->dim);
+	isl_mat_free(qp->div);
+	isl_upoly_free(qp->upoly);
+
+	free(qp);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_var_pow(isl_ctx *ctx, int pos, int power)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+	struct isl_upoly_cst *cst;
+
+	rec = isl_upoly_alloc_rec(ctx, pos, 1 + power);
+	if (!rec)
+		return NULL;
+	for (i = 0; i < 1 + power; ++i) {
+		rec->p[i] = isl_upoly_zero(ctx);
+		if (!rec->p[i])
+			goto error;
+		rec->n++;
+	}
+	cst = isl_upoly_as_cst(rec->p[power]);
+	isl_int_set_si(cst->n, 1);
+
+	return &rec->up;
+error:
+	isl_upoly_free(&rec->up);
+	return NULL;
+}
+
+/* r array maps original positions to new positions.
+ */
+static __isl_give struct isl_upoly *reorder(__isl_take struct isl_upoly *up,
+	int *r)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+	struct isl_upoly *base;
+	struct isl_upoly *res;
+
+	if (isl_upoly_is_cst(up))
+		return up;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	isl_assert(up->ctx, rec->n >= 1, goto error);
+
+	base = isl_upoly_var_pow(up->ctx, r[up->var], 1);
+	res = reorder(isl_upoly_copy(rec->p[rec->n - 1]), r);
+
+	for (i = rec->n - 2; i >= 0; --i) {
+		res = isl_upoly_mul(res, isl_upoly_copy(base));
+		res = isl_upoly_sum(res, reorder(isl_upoly_copy(rec->p[i]), r));
+	}
+
+	isl_upoly_free(base);
+	isl_upoly_free(up);
+
+	return res;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+static isl_bool compatible_divs(__isl_keep isl_mat *div1,
+	__isl_keep isl_mat *div2)
+{
+	int n_row, n_col;
+	isl_bool equal;
+
+	isl_assert(div1->ctx, div1->n_row >= div2->n_row &&
+				div1->n_col >= div2->n_col,
+		    return isl_bool_error);
+
+	if (div1->n_row == div2->n_row)
+		return isl_mat_is_equal(div1, div2);
+
+	n_row = div1->n_row;
+	n_col = div1->n_col;
+	div1->n_row = div2->n_row;
+	div1->n_col = div2->n_col;
+
+	equal = isl_mat_is_equal(div1, div2);
+
+	div1->n_row = n_row;
+	div1->n_col = n_col;
+
+	return equal;
+}
+
+static int cmp_row(__isl_keep isl_mat *div, int i, int j)
+{
+	int li, lj;
+
+	li = isl_seq_last_non_zero(div->row[i], div->n_col);
+	lj = isl_seq_last_non_zero(div->row[j], div->n_col);
+
+	if (li != lj)
+		return li - lj;
+
+	return isl_seq_cmp(div->row[i], div->row[j], div->n_col);
+}
+
+struct isl_div_sort_info {
+	isl_mat	*div;
+	int	 row;
+};
+
+static int div_sort_cmp(const void *p1, const void *p2)
+{
+	const struct isl_div_sort_info *i1, *i2;
+	i1 = (const struct isl_div_sort_info *) p1;
+	i2 = (const struct isl_div_sort_info *) p2;
+
+	return cmp_row(i1->div, i1->row, i2->row);
+}
+
+/* Sort divs and remove duplicates.
+ */
+static __isl_give isl_qpolynomial *sort_divs(__isl_take isl_qpolynomial *qp)
+{
+	int i;
+	int skip;
+	int len;
+	struct isl_div_sort_info *array = NULL;
+	int *pos = NULL, *at = NULL;
+	int *reordering = NULL;
+	unsigned div_pos;
+
+	if (!qp)
+		return NULL;
+	if (qp->div->n_row <= 1)
+		return qp;
+
+	div_pos = isl_space_dim(qp->dim, isl_dim_all);
+
+	array = isl_alloc_array(qp->div->ctx, struct isl_div_sort_info,
+				qp->div->n_row);
+	pos = isl_alloc_array(qp->div->ctx, int, qp->div->n_row);
+	at = isl_alloc_array(qp->div->ctx, int, qp->div->n_row);
+	len = qp->div->n_col - 2;
+	reordering = isl_alloc_array(qp->div->ctx, int, len);
+	if (!array || !pos || !at || !reordering)
+		goto error;
+
+	for (i = 0; i < qp->div->n_row; ++i) {
+		array[i].div = qp->div;
+		array[i].row = i;
+		pos[i] = i;
+		at[i] = i;
+	}
+
+	qsort(array, qp->div->n_row, sizeof(struct isl_div_sort_info),
+		div_sort_cmp);
+
+	for (i = 0; i < div_pos; ++i)
+		reordering[i] = i;
+
+	for (i = 0; i < qp->div->n_row; ++i) {
+		if (pos[array[i].row] == i)
+			continue;
+		qp->div = isl_mat_swap_rows(qp->div, i, pos[array[i].row]);
+		pos[at[i]] = pos[array[i].row];
+		at[pos[array[i].row]] = at[i];
+		at[i] = array[i].row;
+		pos[array[i].row] = i;
+	}
+
+	skip = 0;
+	for (i = 0; i < len - div_pos; ++i) {
+		if (i > 0 &&
+		    isl_seq_eq(qp->div->row[i - skip - 1],
+			       qp->div->row[i - skip], qp->div->n_col)) {
+			qp->div = isl_mat_drop_rows(qp->div, i - skip, 1);
+			isl_mat_col_add(qp->div, 2 + div_pos + i - skip - 1,
+						 2 + div_pos + i - skip);
+			qp->div = isl_mat_drop_cols(qp->div,
+						    2 + div_pos + i - skip, 1);
+			skip++;
+		}
+		reordering[div_pos + array[i].row] = div_pos + i - skip;
+	}
+
+	qp->upoly = reorder(qp->upoly, reordering);
+
+	if (!qp->upoly || !qp->div)
+		goto error;
+
+	free(at);
+	free(pos);
+	free(array);
+	free(reordering);
+
+	return qp;
+error:
+	free(at);
+	free(pos);
+	free(array);
+	free(reordering);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+static __isl_give struct isl_upoly *expand(__isl_take struct isl_upoly *up,
+	int *exp, int first)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (isl_upoly_is_cst(up))
+		return up;
+
+	if (up->var < first)
+		return up;
+
+	if (exp[up->var - first] == up->var - first)
+		return up;
+
+	up = isl_upoly_cow(up);
+	if (!up)
+		goto error;
+
+	up->var = exp[up->var - first] + first;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		rec->p[i] = expand(rec->p[i], exp, first);
+		if (!rec->p[i])
+			goto error;
+	}
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+static __isl_give isl_qpolynomial *with_merged_divs(
+	__isl_give isl_qpolynomial *(*fn)(__isl_take isl_qpolynomial *qp1,
+					  __isl_take isl_qpolynomial *qp2),
+	__isl_take isl_qpolynomial *qp1, __isl_take isl_qpolynomial *qp2)
+{
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_mat *div = NULL;
+	int n_div1, n_div2;
+
+	qp1 = isl_qpolynomial_cow(qp1);
+	qp2 = isl_qpolynomial_cow(qp2);
+
+	if (!qp1 || !qp2)
+		goto error;
+
+	isl_assert(qp1->div->ctx, qp1->div->n_row >= qp2->div->n_row &&
+				qp1->div->n_col >= qp2->div->n_col, goto error);
+
+	n_div1 = qp1->div->n_row;
+	n_div2 = qp2->div->n_row;
+	exp1 = isl_alloc_array(qp1->div->ctx, int, n_div1);
+	exp2 = isl_alloc_array(qp2->div->ctx, int, n_div2);
+	if ((n_div1 && !exp1) || (n_div2 && !exp2))
+		goto error;
+
+	div = isl_merge_divs(qp1->div, qp2->div, exp1, exp2);
+	if (!div)
+		goto error;
+
+	isl_mat_free(qp1->div);
+	qp1->div = isl_mat_copy(div);
+	isl_mat_free(qp2->div);
+	qp2->div = isl_mat_copy(div);
+
+	qp1->upoly = expand(qp1->upoly, exp1, div->n_col - div->n_row - 2);
+	qp2->upoly = expand(qp2->upoly, exp2, div->n_col - div->n_row - 2);
+
+	if (!qp1->upoly || !qp2->upoly)
+		goto error;
+
+	isl_mat_free(div);
+	free(exp1);
+	free(exp2);
+
+	return fn(qp1, qp2);
+error:
+	isl_mat_free(div);
+	free(exp1);
+	free(exp2);
+	isl_qpolynomial_free(qp1);
+	isl_qpolynomial_free(qp2);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_add(__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2)
+{
+	isl_bool compatible;
+
+	qp1 = isl_qpolynomial_cow(qp1);
+
+	if (!qp1 || !qp2)
+		goto error;
+
+	if (qp1->div->n_row < qp2->div->n_row)
+		return isl_qpolynomial_add(qp2, qp1);
+
+	isl_assert(qp1->dim->ctx, isl_space_is_equal(qp1->dim, qp2->dim), goto error);
+	compatible = compatible_divs(qp1->div, qp2->div);
+	if (compatible < 0)
+		goto error;
+	if (!compatible)
+		return with_merged_divs(isl_qpolynomial_add, qp1, qp2);
+
+	qp1->upoly = isl_upoly_sum(qp1->upoly, isl_upoly_copy(qp2->upoly));
+	if (!qp1->upoly)
+		goto error;
+
+	isl_qpolynomial_free(qp2);
+
+	return qp1;
+error:
+	isl_qpolynomial_free(qp1);
+	isl_qpolynomial_free(qp2);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_add_on_domain(
+	__isl_keep isl_set *dom,
+	__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2)
+{
+	qp1 = isl_qpolynomial_add(qp1, qp2);
+	qp1 = isl_qpolynomial_gist(qp1, isl_set_copy(dom));
+	return qp1;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_sub(__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2)
+{
+	return isl_qpolynomial_add(qp1, isl_qpolynomial_neg(qp2));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_add_isl_int(
+	__isl_take isl_qpolynomial *qp, isl_int v)
+{
+	if (isl_int_is_zero(v))
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	qp->upoly = isl_upoly_add_isl_int(qp->upoly, v);
+	if (!qp->upoly)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_neg(__isl_take isl_qpolynomial *qp)
+{
+	if (!qp)
+		return NULL;
+
+	return isl_qpolynomial_mul_isl_int(qp, qp->dim->ctx->negone);
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_mul_isl_int(
+	__isl_take isl_qpolynomial *qp, isl_int v)
+{
+	if (isl_int_is_one(v))
+		return qp;
+
+	if (qp && isl_int_is_zero(v)) {
+		isl_qpolynomial *zero;
+		zero = isl_qpolynomial_zero_on_domain(isl_space_copy(qp->dim));
+		isl_qpolynomial_free(qp);
+		return zero;
+	}
+	
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	qp->upoly = isl_upoly_mul_isl_int(qp->upoly, v);
+	if (!qp->upoly)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_scale(
+	__isl_take isl_qpolynomial *qp, isl_int v)
+{
+	return isl_qpolynomial_mul_isl_int(qp, v);
+}
+
+/* Multiply "qp" by "v".
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_scale_val(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_val *v)
+{
+	if (!qp || !v)
+		goto error;
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_qpolynomial_get_ctx(qp), isl_error_invalid,
+			"expecting rational factor", goto error);
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return qp;
+	}
+
+	if (isl_val_is_zero(v)) {
+		isl_space *space;
+
+		space = isl_qpolynomial_get_domain_space(qp);
+		isl_qpolynomial_free(qp);
+		isl_val_free(v);
+		return isl_qpolynomial_zero_on_domain(space);
+	}
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		goto error;
+
+	qp->upoly = isl_upoly_scale_val(qp->upoly, v);
+	if (!qp->upoly)
+		qp = isl_qpolynomial_free(qp);
+
+	isl_val_free(v);
+	return qp;
+error:
+	isl_val_free(v);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+/* Divide "qp" by "v".
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_scale_down_val(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_val *v)
+{
+	if (!qp || !v)
+		goto error;
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_qpolynomial_get_ctx(qp), isl_error_invalid,
+			"expecting rational factor", goto error);
+	if (isl_val_is_zero(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"cannot scale down by zero", goto error);
+
+	return isl_qpolynomial_scale_val(qp, isl_val_inv(v));
+error:
+	isl_val_free(v);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_mul(__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2)
+{
+	isl_bool compatible;
+
+	qp1 = isl_qpolynomial_cow(qp1);
+
+	if (!qp1 || !qp2)
+		goto error;
+
+	if (qp1->div->n_row < qp2->div->n_row)
+		return isl_qpolynomial_mul(qp2, qp1);
+
+	isl_assert(qp1->dim->ctx, isl_space_is_equal(qp1->dim, qp2->dim), goto error);
+	compatible = compatible_divs(qp1->div, qp2->div);
+	if (compatible < 0)
+		goto error;
+	if (!compatible)
+		return with_merged_divs(isl_qpolynomial_mul, qp1, qp2);
+
+	qp1->upoly = isl_upoly_mul(qp1->upoly, isl_upoly_copy(qp2->upoly));
+	if (!qp1->upoly)
+		goto error;
+
+	isl_qpolynomial_free(qp2);
+
+	return qp1;
+error:
+	isl_qpolynomial_free(qp1);
+	isl_qpolynomial_free(qp2);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_pow(__isl_take isl_qpolynomial *qp,
+	unsigned power)
+{
+	qp = isl_qpolynomial_cow(qp);
+
+	if (!qp)
+		return NULL;
+
+	qp->upoly = isl_upoly_pow(qp->upoly, power);
+	if (!qp->upoly)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_pow(
+	__isl_take isl_pw_qpolynomial *pwqp, unsigned power)
+{
+	int i;
+
+	if (power == 1)
+		return pwqp;
+
+	pwqp = isl_pw_qpolynomial_cow(pwqp);
+	if (!pwqp)
+		return NULL;
+
+	for (i = 0; i < pwqp->n; ++i) {
+		pwqp->p[i].qp = isl_qpolynomial_pow(pwqp->p[i].qp, power);
+		if (!pwqp->p[i].qp)
+			return isl_pw_qpolynomial_free(pwqp);
+	}
+
+	return pwqp;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_zero_on_domain(
+	__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	return isl_qpolynomial_alloc(dim, 0, isl_upoly_zero(dim->ctx));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_one_on_domain(
+	__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	return isl_qpolynomial_alloc(dim, 0, isl_upoly_one(dim->ctx));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_infty_on_domain(
+	__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	return isl_qpolynomial_alloc(dim, 0, isl_upoly_infty(dim->ctx));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_neginfty_on_domain(
+	__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	return isl_qpolynomial_alloc(dim, 0, isl_upoly_neginfty(dim->ctx));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_nan_on_domain(
+	__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	return isl_qpolynomial_alloc(dim, 0, isl_upoly_nan(dim->ctx));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_cst_on_domain(
+	__isl_take isl_space *dim,
+	isl_int v)
+{
+	struct isl_qpolynomial *qp;
+	struct isl_upoly_cst *cst;
+
+	if (!dim)
+		return NULL;
+
+	qp = isl_qpolynomial_alloc(dim, 0, isl_upoly_zero(dim->ctx));
+	if (!qp)
+		return NULL;
+
+	cst = isl_upoly_as_cst(qp->upoly);
+	isl_int_set(cst->n, v);
+
+	return qp;
+}
+
+int isl_qpolynomial_is_cst(__isl_keep isl_qpolynomial *qp,
+	isl_int *n, isl_int *d)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!qp)
+		return -1;
+
+	if (!isl_upoly_is_cst(qp->upoly))
+		return 0;
+
+	cst = isl_upoly_as_cst(qp->upoly);
+	if (!cst)
+		return -1;
+
+	if (n)
+		isl_int_set(*n, cst->n);
+	if (d)
+		isl_int_set(*d, cst->d);
+
+	return 1;
+}
+
+/* Return the constant term of "up".
+ */
+static __isl_give isl_val *isl_upoly_get_constant_val(
+	__isl_keep struct isl_upoly *up)
+{
+	struct isl_upoly_cst *cst;
+
+	if (!up)
+		return NULL;
+
+	while (!isl_upoly_is_cst(up)) {
+		struct isl_upoly_rec *rec;
+
+		rec = isl_upoly_as_rec(up);
+		if (!rec)
+			return NULL;
+		up = rec->p[0];
+	}
+
+	cst = isl_upoly_as_cst(up);
+	if (!cst)
+		return NULL;
+	return isl_val_rat_from_isl_int(cst->up.ctx, cst->n, cst->d);
+}
+
+/* Return the constant term of "qp".
+ */
+__isl_give isl_val *isl_qpolynomial_get_constant_val(
+	__isl_keep isl_qpolynomial *qp)
+{
+	if (!qp)
+		return NULL;
+
+	return isl_upoly_get_constant_val(qp->upoly);
+}
+
+int isl_upoly_is_affine(__isl_keep struct isl_upoly *up)
+{
+	int is_cst;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return -1;
+
+	if (up->var < 0)
+		return 1;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		return -1;
+
+	if (rec->n > 2)
+		return 0;
+
+	isl_assert(up->ctx, rec->n > 1, return -1);
+
+	is_cst = isl_upoly_is_cst(rec->p[1]);
+	if (is_cst < 0)
+		return -1;
+	if (!is_cst)
+		return 0;
+
+	return isl_upoly_is_affine(rec->p[0]);
+}
+
+int isl_qpolynomial_is_affine(__isl_keep isl_qpolynomial *qp)
+{
+	if (!qp)
+		return -1;
+
+	if (qp->div->n_row > 0)
+		return 0;
+
+	return isl_upoly_is_affine(qp->upoly);
+}
+
+static void update_coeff(__isl_keep isl_vec *aff,
+	__isl_keep struct isl_upoly_cst *cst, int pos)
+{
+	isl_int gcd;
+	isl_int f;
+
+	if (isl_int_is_zero(cst->n))
+		return;
+
+	isl_int_init(gcd);
+	isl_int_init(f);
+	isl_int_gcd(gcd, cst->d, aff->el[0]);
+	isl_int_divexact(f, cst->d, gcd);
+	isl_int_divexact(gcd, aff->el[0], gcd);
+	isl_seq_scale(aff->el, aff->el, f, aff->size);
+	isl_int_mul(aff->el[1 + pos], gcd, cst->n);
+	isl_int_clear(gcd);
+	isl_int_clear(f);
+}
+
+int isl_upoly_update_affine(__isl_keep struct isl_upoly *up,
+	__isl_keep isl_vec *aff)
+{
+	struct isl_upoly_cst *cst;
+	struct isl_upoly_rec *rec;
+
+	if (!up || !aff)
+		return -1;
+
+	if (up->var < 0) {
+		struct isl_upoly_cst *cst;
+
+		cst = isl_upoly_as_cst(up);
+		if (!cst)
+			return -1;
+		update_coeff(aff, cst, 0);
+		return 0;
+	}
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		return -1;
+	isl_assert(up->ctx, rec->n == 2, return -1);
+
+	cst = isl_upoly_as_cst(rec->p[1]);
+	if (!cst)
+		return -1;
+	update_coeff(aff, cst, 1 + up->var);
+
+	return isl_upoly_update_affine(rec->p[0], aff);
+}
+
+__isl_give isl_vec *isl_qpolynomial_extract_affine(
+	__isl_keep isl_qpolynomial *qp)
+{
+	isl_vec *aff;
+	unsigned d;
+
+	if (!qp)
+		return NULL;
+
+	d = isl_space_dim(qp->dim, isl_dim_all);
+	aff = isl_vec_alloc(qp->div->ctx, 2 + d + qp->div->n_row);
+	if (!aff)
+		return NULL;
+
+	isl_seq_clr(aff->el + 1, 1 + d + qp->div->n_row);
+	isl_int_set_si(aff->el[0], 1);
+
+	if (isl_upoly_update_affine(qp->upoly, aff) < 0)
+		goto error;
+
+	return aff;
+error:
+	isl_vec_free(aff);
+	return NULL;
+}
+
+/* Compare two quasi-polynomials.
+ *
+ * Return -1 if "qp1" is "smaller" than "qp2", 1 if "qp1" is "greater"
+ * than "qp2" and 0 if they are equal.
+ */
+int isl_qpolynomial_plain_cmp(__isl_keep isl_qpolynomial *qp1,
+	__isl_keep isl_qpolynomial *qp2)
+{
+	int cmp;
+
+	if (qp1 == qp2)
+		return 0;
+	if (!qp1)
+		return -1;
+	if (!qp2)
+		return 1;
+
+	cmp = isl_space_cmp(qp1->dim, qp2->dim);
+	if (cmp != 0)
+		return cmp;
+
+	cmp = isl_local_cmp(qp1->div, qp2->div);
+	if (cmp != 0)
+		return cmp;
+
+	return isl_upoly_plain_cmp(qp1->upoly, qp2->upoly);
+}
+
+/* Is "qp1" obviously equal to "qp2"?
+ *
+ * NaN is not equal to anything, not even to another NaN.
+ */
+isl_bool isl_qpolynomial_plain_is_equal(__isl_keep isl_qpolynomial *qp1,
+	__isl_keep isl_qpolynomial *qp2)
+{
+	isl_bool equal;
+
+	if (!qp1 || !qp2)
+		return isl_bool_error;
+
+	if (isl_qpolynomial_is_nan(qp1) || isl_qpolynomial_is_nan(qp2))
+		return isl_bool_false;
+
+	equal = isl_space_is_equal(qp1->dim, qp2->dim);
+	if (equal < 0 || !equal)
+		return equal;
+
+	equal = isl_mat_is_equal(qp1->div, qp2->div);
+	if (equal < 0 || !equal)
+		return equal;
+
+	return isl_upoly_is_equal(qp1->upoly, qp2->upoly);
+}
+
+static void upoly_update_den(__isl_keep struct isl_upoly *up, isl_int *d)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (isl_upoly_is_cst(up)) {
+		struct isl_upoly_cst *cst;
+		cst = isl_upoly_as_cst(up);
+		if (!cst)
+			return;
+		isl_int_lcm(*d, *d, cst->d);
+		return;
+	}
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		return;
+
+	for (i = 0; i < rec->n; ++i)
+		upoly_update_den(rec->p[i], d);
+}
+
+void isl_qpolynomial_get_den(__isl_keep isl_qpolynomial *qp, isl_int *d)
+{
+	isl_int_set_si(*d, 1);
+	if (!qp)
+		return;
+	upoly_update_den(qp->upoly, d);
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_var_pow_on_domain(
+	__isl_take isl_space *dim, int pos, int power)
+{
+	struct isl_ctx *ctx;
+
+	if (!dim)
+		return NULL;
+
+	ctx = dim->ctx;
+
+	return isl_qpolynomial_alloc(dim, 0, isl_upoly_var_pow(ctx, pos, power));
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_var_on_domain(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!dim)
+		return NULL;
+
+	isl_assert(dim->ctx, isl_space_dim(dim, isl_dim_in) == 0, goto error);
+	isl_assert(dim->ctx, pos < isl_space_dim(dim, type), goto error);
+
+	if (type == isl_dim_set)
+		pos += isl_space_dim(dim, isl_dim_param);
+
+	return isl_qpolynomial_var_pow_on_domain(dim, pos, 1);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_subs(__isl_take struct isl_upoly *up,
+	unsigned first, unsigned n, __isl_keep struct isl_upoly **subs)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+	struct isl_upoly *base, *res;
+
+	if (!up)
+		return NULL;
+
+	if (isl_upoly_is_cst(up))
+		return up;
+
+	if (up->var < first)
+		return up;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	isl_assert(up->ctx, rec->n >= 1, goto error);
+
+	if (up->var >= first + n)
+		base = isl_upoly_var_pow(up->ctx, up->var, 1);
+	else
+		base = isl_upoly_copy(subs[up->var - first]);
+
+	res = isl_upoly_subs(isl_upoly_copy(rec->p[rec->n - 1]), first, n, subs);
+	for (i = rec->n - 2; i >= 0; --i) {
+		struct isl_upoly *t;
+		t = isl_upoly_subs(isl_upoly_copy(rec->p[i]), first, n, subs);
+		res = isl_upoly_mul(res, isl_upoly_copy(base));
+		res = isl_upoly_sum(res, t);
+	}
+
+	isl_upoly_free(base);
+	isl_upoly_free(up);
+				
+	return res;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}	
+
+__isl_give struct isl_upoly *isl_upoly_from_affine(isl_ctx *ctx, isl_int *f,
+	isl_int denom, unsigned len)
+{
+	int i;
+	struct isl_upoly *up;
+
+	isl_assert(ctx, len >= 1, return NULL);
+
+	up = isl_upoly_rat_cst(ctx, f[0], denom);
+	for (i = 0; i < len - 1; ++i) {
+		struct isl_upoly *t;
+		struct isl_upoly *c;
+
+		if (isl_int_is_zero(f[1 + i]))
+			continue;
+
+		c = isl_upoly_rat_cst(ctx, f[1 + i], denom);
+		t = isl_upoly_var_pow(ctx, i, 1);
+		t = isl_upoly_mul(c, t);
+		up = isl_upoly_sum(up, t);
+	}
+
+	return up;
+}
+
+/* Remove common factor of non-constant terms and denominator.
+ */
+static void normalize_div(__isl_keep isl_qpolynomial *qp, int div)
+{
+	isl_ctx *ctx = qp->div->ctx;
+	unsigned total = qp->div->n_col - 2;
+
+	isl_seq_gcd(qp->div->row[div] + 2, total, &ctx->normalize_gcd);
+	isl_int_gcd(ctx->normalize_gcd,
+		    ctx->normalize_gcd, qp->div->row[div][0]);
+	if (isl_int_is_one(ctx->normalize_gcd))
+		return;
+
+	isl_seq_scale_down(qp->div->row[div] + 2, qp->div->row[div] + 2,
+			    ctx->normalize_gcd, total);
+	isl_int_divexact(qp->div->row[div][0], qp->div->row[div][0],
+			    ctx->normalize_gcd);
+	isl_int_fdiv_q(qp->div->row[div][1], qp->div->row[div][1],
+			    ctx->normalize_gcd);
+}
+
+/* Replace the integer division identified by "div" by the polynomial "s".
+ * The integer division is assumed not to appear in the definition
+ * of any other integer divisions.
+ */
+static __isl_give isl_qpolynomial *substitute_div(
+	__isl_take isl_qpolynomial *qp,
+	int div, __isl_take struct isl_upoly *s)
+{
+	int i;
+	int total;
+	int *reordering;
+
+	if (!qp || !s)
+		goto error;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		goto error;
+
+	total = isl_space_dim(qp->dim, isl_dim_all);
+	qp->upoly = isl_upoly_subs(qp->upoly, total + div, 1, &s);
+	if (!qp->upoly)
+		goto error;
+
+	reordering = isl_alloc_array(qp->dim->ctx, int, total + qp->div->n_row);
+	if (!reordering)
+		goto error;
+	for (i = 0; i < total + div; ++i)
+		reordering[i] = i;
+	for (i = total + div + 1; i < total + qp->div->n_row; ++i)
+		reordering[i] = i - 1;
+	qp->div = isl_mat_drop_rows(qp->div, div, 1);
+	qp->div = isl_mat_drop_cols(qp->div, 2 + total + div, 1);
+	qp->upoly = reorder(qp->upoly, reordering);
+	free(reordering);
+
+	if (!qp->upoly || !qp->div)
+		goto error;
+
+	isl_upoly_free(s);
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_upoly_free(s);
+	return NULL;
+}
+
+/* Replace all integer divisions [e/d] that turn out to not actually be integer
+ * divisions because d is equal to 1 by their definition, i.e., e.
+ */
+static __isl_give isl_qpolynomial *substitute_non_divs(
+	__isl_take isl_qpolynomial *qp)
+{
+	int i, j;
+	int total;
+	struct isl_upoly *s;
+
+	if (!qp)
+		return NULL;
+
+	total = isl_space_dim(qp->dim, isl_dim_all);
+	for (i = 0; qp && i < qp->div->n_row; ++i) {
+		if (!isl_int_is_one(qp->div->row[i][0]))
+			continue;
+		for (j = i + 1; j < qp->div->n_row; ++j) {
+			if (isl_int_is_zero(qp->div->row[j][2 + total + i]))
+				continue;
+			isl_seq_combine(qp->div->row[j] + 1,
+				qp->div->ctx->one, qp->div->row[j] + 1,
+				qp->div->row[j][2 + total + i],
+				qp->div->row[i] + 1, 1 + total + i);
+			isl_int_set_si(qp->div->row[j][2 + total + i], 0);
+			normalize_div(qp, j);
+		}
+		s = isl_upoly_from_affine(qp->dim->ctx, qp->div->row[i] + 1,
+					qp->div->row[i][0], qp->div->n_col - 1);
+		qp = substitute_div(qp, i, s);
+		--i;
+	}
+
+	return qp;
+}
+
+/* Reduce the coefficients of div "div" to lie in the interval [0, d-1],
+ * with d the denominator.  When replacing the coefficient e of x by
+ * d * frac(e/d) = e - d * floor(e/d), we are subtracting d * floor(e/d) * x
+ * inside the division, so we need to add floor(e/d) * x outside.
+ * That is, we replace q by q' + floor(e/d) * x and we therefore need
+ * to adjust the coefficient of x in each later div that depends on the
+ * current div "div" and also in the affine expressions in the rows of "mat"
+ * (if they too depend on "div").
+ */
+static void reduce_div(__isl_keep isl_qpolynomial *qp, int div,
+	__isl_keep isl_mat **mat)
+{
+	int i, j;
+	isl_int v;
+	unsigned total = qp->div->n_col - qp->div->n_row - 2;
+
+	isl_int_init(v);
+	for (i = 0; i < 1 + total + div; ++i) {
+		if (isl_int_is_nonneg(qp->div->row[div][1 + i]) &&
+		    isl_int_lt(qp->div->row[div][1 + i], qp->div->row[div][0]))
+			continue;
+		isl_int_fdiv_q(v, qp->div->row[div][1 + i], qp->div->row[div][0]);
+		isl_int_fdiv_r(qp->div->row[div][1 + i],
+				qp->div->row[div][1 + i], qp->div->row[div][0]);
+		*mat = isl_mat_col_addmul(*mat, i, v, 1 + total + div);
+		for (j = div + 1; j < qp->div->n_row; ++j) {
+			if (isl_int_is_zero(qp->div->row[j][2 + total + div]))
+				continue;
+			isl_int_addmul(qp->div->row[j][1 + i],
+					v, qp->div->row[j][2 + total + div]);
+		}
+	}
+	isl_int_clear(v);
+}
+
+/* Check if the last non-zero coefficient is bigger that half of the
+ * denominator.  If so, we will invert the div to further reduce the number
+ * of distinct divs that may appear.
+ * If the last non-zero coefficient is exactly half the denominator,
+ * then we continue looking for earlier coefficients that are bigger
+ * than half the denominator.
+ */
+static int needs_invert(__isl_keep isl_mat *div, int row)
+{
+	int i;
+	int cmp;
+
+	for (i = div->n_col - 1; i >= 1; --i) {
+		if (isl_int_is_zero(div->row[row][i]))
+			continue;
+		isl_int_mul_ui(div->row[row][i], div->row[row][i], 2);
+		cmp = isl_int_cmp(div->row[row][i], div->row[row][0]);
+		isl_int_divexact_ui(div->row[row][i], div->row[row][i], 2);
+		if (cmp)
+			return cmp > 0;
+		if (i == 1)
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Replace div "div" q = [e/d] by -[(-e+(d-1))/d].
+ * We only invert the coefficients of e (and the coefficient of q in
+ * later divs and in the rows of "mat").  After calling this function, the
+ * coefficients of e should be reduced again.
+ */
+static void invert_div(__isl_keep isl_qpolynomial *qp, int div,
+	__isl_keep isl_mat **mat)
+{
+	unsigned total = qp->div->n_col - qp->div->n_row - 2;
+
+	isl_seq_neg(qp->div->row[div] + 1,
+		    qp->div->row[div] + 1, qp->div->n_col - 1);
+	isl_int_sub_ui(qp->div->row[div][1], qp->div->row[div][1], 1);
+	isl_int_add(qp->div->row[div][1],
+		    qp->div->row[div][1], qp->div->row[div][0]);
+	*mat = isl_mat_col_neg(*mat, 1 + total + div);
+	isl_mat_col_mul(qp->div, 2 + total + div,
+			qp->div->ctx->negone, 2 + total + div);
+}
+
+/* Reduce all divs of "qp" to have coefficients
+ * in the interval [0, d-1], with d the denominator and such that the
+ * last non-zero coefficient that is not equal to d/2 is smaller than d/2.
+ * The modifications to the integer divisions need to be reflected
+ * in the factors of the polynomial that refer to the original
+ * integer divisions.  To this end, the modifications are collected
+ * as a set of affine expressions and then plugged into the polynomial.
+ *
+ * After the reduction, some divs may have become redundant or identical,
+ * so we call substitute_non_divs and sort_divs.  If these functions
+ * eliminate divs or merge two or more divs into one, the coefficients
+ * of the enclosing divs may have to be reduced again, so we call
+ * ourselves recursively if the number of divs decreases.
+ */
+static __isl_give isl_qpolynomial *reduce_divs(__isl_take isl_qpolynomial *qp)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_mat *mat;
+	struct isl_upoly **s;
+	unsigned o_div, n_div, total;
+
+	if (!qp)
+		return NULL;
+
+	total = isl_qpolynomial_domain_dim(qp, isl_dim_all);
+	n_div = isl_qpolynomial_domain_dim(qp, isl_dim_div);
+	o_div = isl_qpolynomial_domain_offset(qp, isl_dim_div);
+	ctx = isl_qpolynomial_get_ctx(qp);
+	mat = isl_mat_zero(ctx, n_div, 1 + total);
+
+	for (i = 0; i < n_div; ++i)
+		mat = isl_mat_set_element_si(mat, i, o_div + i, 1);
+
+	for (i = 0; i < qp->div->n_row; ++i) {
+		normalize_div(qp, i);
+		reduce_div(qp, i, &mat);
+		if (needs_invert(qp->div, i)) {
+			invert_div(qp, i, &mat);
+			reduce_div(qp, i, &mat);
+		}
+	}
+	if (!mat)
+		goto error;
+
+	s = isl_alloc_array(ctx, struct isl_upoly *, n_div);
+	if (n_div && !s)
+		goto error;
+	for (i = 0; i < n_div; ++i)
+		s[i] = isl_upoly_from_affine(ctx, mat->row[i], ctx->one,
+					    1 + total);
+	qp->upoly = isl_upoly_subs(qp->upoly, o_div - 1, n_div, s);
+	for (i = 0; i < n_div; ++i)
+		isl_upoly_free(s[i]);
+	free(s);
+	if (!qp->upoly)
+		goto error;
+
+	isl_mat_free(mat);
+
+	qp = substitute_non_divs(qp);
+	qp = sort_divs(qp);
+	if (qp && isl_qpolynomial_domain_dim(qp, isl_dim_div) < n_div)
+		return reduce_divs(qp);
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_mat_free(mat);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_rat_cst_on_domain(
+	__isl_take isl_space *dim, const isl_int n, const isl_int d)
+{
+	struct isl_qpolynomial *qp;
+	struct isl_upoly_cst *cst;
+
+	if (!dim)
+		return NULL;
+
+	qp = isl_qpolynomial_alloc(dim, 0, isl_upoly_zero(dim->ctx));
+	if (!qp)
+		return NULL;
+
+	cst = isl_upoly_as_cst(qp->upoly);
+	isl_int_set(cst->n, n);
+	isl_int_set(cst->d, d);
+
+	return qp;
+}
+
+/* Return an isl_qpolynomial that is equal to "val" on domain space "domain".
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_val_on_domain(
+	__isl_take isl_space *domain, __isl_take isl_val *val)
+{
+	isl_qpolynomial *qp;
+	struct isl_upoly_cst *cst;
+
+	if (!domain || !val)
+		goto error;
+
+	qp = isl_qpolynomial_alloc(isl_space_copy(domain), 0,
+					isl_upoly_zero(domain->ctx));
+	if (!qp)
+		goto error;
+
+	cst = isl_upoly_as_cst(qp->upoly);
+	isl_int_set(cst->n, val->n);
+	isl_int_set(cst->d, val->d);
+
+	isl_space_free(domain);
+	isl_val_free(val);
+	return qp;
+error:
+	isl_space_free(domain);
+	isl_val_free(val);
+	return NULL;
+}
+
+static int up_set_active(__isl_keep struct isl_upoly *up, int *active, int d)
+{
+	struct isl_upoly_rec *rec;
+	int i;
+
+	if (!up)
+		return -1;
+
+	if (isl_upoly_is_cst(up))
+		return 0;
+
+	if (up->var < d)
+		active[up->var] = 1;
+
+	rec = isl_upoly_as_rec(up);
+	for (i = 0; i < rec->n; ++i)
+		if (up_set_active(rec->p[i], active, d) < 0)
+			return -1;
+
+	return 0;
+}
+
+static int set_active(__isl_keep isl_qpolynomial *qp, int *active)
+{
+	int i, j;
+	int d = isl_space_dim(qp->dim, isl_dim_all);
+
+	if (!qp || !active)
+		return -1;
+
+	for (i = 0; i < d; ++i)
+		for (j = 0; j < qp->div->n_row; ++j) {
+			if (isl_int_is_zero(qp->div->row[j][2 + i]))
+				continue;
+			active[i] = 1;
+			break;
+		}
+
+	return up_set_active(qp->upoly, active, d);
+}
+
+isl_bool isl_qpolynomial_involves_dims(__isl_keep isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	int *active = NULL;
+	isl_bool involves = isl_bool_false;
+
+	if (!qp)
+		return isl_bool_error;
+	if (n == 0)
+		return isl_bool_false;
+
+	isl_assert(qp->dim->ctx,
+		    first + n <= isl_qpolynomial_dim(qp, type),
+		    return isl_bool_error);
+	isl_assert(qp->dim->ctx, type == isl_dim_param ||
+				 type == isl_dim_in, return isl_bool_error);
+
+	active = isl_calloc_array(qp->dim->ctx, int,
+					isl_space_dim(qp->dim, isl_dim_all));
+	if (set_active(qp, active) < 0)
+		goto error;
+
+	if (type == isl_dim_in)
+		first += isl_space_dim(qp->dim, isl_dim_param);
+	for (i = 0; i < n; ++i)
+		if (active[first + i]) {
+			involves = isl_bool_true;
+			break;
+		}
+
+	free(active);
+
+	return involves;
+error:
+	free(active);
+	return isl_bool_error;
+}
+
+/* Remove divs that do not appear in the quasi-polynomial, nor in any
+ * of the divs that do appear in the quasi-polynomial.
+ */
+static __isl_give isl_qpolynomial *remove_redundant_divs(
+	__isl_take isl_qpolynomial *qp)
+{
+	int i, j;
+	int d;
+	int len;
+	int skip;
+	int *active = NULL;
+	int *reordering = NULL;
+	int redundant = 0;
+	int n_div;
+	isl_ctx *ctx;
+
+	if (!qp)
+		return NULL;
+	if (qp->div->n_row == 0)
+		return qp;
+
+	d = isl_space_dim(qp->dim, isl_dim_all);
+	len = qp->div->n_col - 2;
+	ctx = isl_qpolynomial_get_ctx(qp);
+	active = isl_calloc_array(ctx, int, len);
+	if (!active)
+		goto error;
+
+	if (up_set_active(qp->upoly, active, len) < 0)
+		goto error;
+
+	for (i = qp->div->n_row - 1; i >= 0; --i) {
+		if (!active[d + i]) {
+			redundant = 1;
+			continue;
+		}
+		for (j = 0; j < i; ++j) {
+			if (isl_int_is_zero(qp->div->row[i][2 + d + j]))
+				continue;
+			active[d + j] = 1;
+			break;
+		}
+	}
+
+	if (!redundant) {
+		free(active);
+		return qp;
+	}
+
+	reordering = isl_alloc_array(qp->div->ctx, int, len);
+	if (!reordering)
+		goto error;
+
+	for (i = 0; i < d; ++i)
+		reordering[i] = i;
+
+	skip = 0;
+	n_div = qp->div->n_row;
+	for (i = 0; i < n_div; ++i) {
+		if (!active[d + i]) {
+			qp->div = isl_mat_drop_rows(qp->div, i - skip, 1);
+			qp->div = isl_mat_drop_cols(qp->div,
+						    2 + d + i - skip, 1);
+			skip++;
+		}
+		reordering[d + i] = d + i - skip;
+	}
+
+	qp->upoly = reorder(qp->upoly, reordering);
+
+	if (!qp->upoly || !qp->div)
+		goto error;
+
+	free(active);
+	free(reordering);
+
+	return qp;
+error:
+	free(active);
+	free(reordering);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give struct isl_upoly *isl_upoly_drop(__isl_take struct isl_upoly *up,
+	unsigned first, unsigned n)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return NULL;
+	if (n == 0 || up->var < 0 || up->var < first)
+		return up;
+	if (up->var < first + n) {
+		up = replace_by_constant_term(up);
+		return isl_upoly_drop(up, first, n);
+	}
+	up = isl_upoly_cow(up);
+	if (!up)
+		return NULL;
+	up->var -= n;
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		rec->p[i] = isl_upoly_drop(rec->p[i], first, n);
+		if (!rec->p[i])
+			goto error;
+	}
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_set_dim_name(
+	__isl_take isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+	if (type == isl_dim_out)
+		isl_die(isl_qpolynomial_get_ctx(qp), isl_error_invalid,
+			"cannot set name of output/set dimension",
+			return isl_qpolynomial_free(qp));
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	qp->dim = isl_space_set_dim_name(qp->dim, type, pos, s);
+	if (!qp->dim)
+		goto error;
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_drop_dims(
+	__isl_take isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	if (!qp)
+		return NULL;
+	if (type == isl_dim_out)
+		isl_die(qp->dim->ctx, isl_error_invalid,
+			"cannot drop output/set dimension",
+			goto error);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	if (n == 0 && !isl_space_is_named_or_nested(qp->dim, type))
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	isl_assert(qp->dim->ctx, first + n <= isl_space_dim(qp->dim, type),
+			goto error);
+	isl_assert(qp->dim->ctx, type == isl_dim_param ||
+				 type == isl_dim_set, goto error);
+
+	qp->dim = isl_space_drop_dims(qp->dim, type, first, n);
+	if (!qp->dim)
+		goto error;
+
+	if (type == isl_dim_set)
+		first += isl_space_dim(qp->dim, isl_dim_param);
+
+	qp->div = isl_mat_drop_cols(qp->div, 2 + first, n);
+	if (!qp->div)
+		goto error;
+
+	qp->upoly = isl_upoly_drop(qp->upoly, first, n);
+	if (!qp->upoly)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+/* Project the domain of the quasi-polynomial onto its parameter space.
+ * The quasi-polynomial may not involve any of the domain dimensions.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_project_domain_on_params(
+	__isl_take isl_qpolynomial *qp)
+{
+	isl_space *space;
+	unsigned n;
+	int involves;
+
+	n = isl_qpolynomial_dim(qp, isl_dim_in);
+	involves = isl_qpolynomial_involves_dims(qp, isl_dim_in, 0, n);
+	if (involves < 0)
+		return isl_qpolynomial_free(qp);
+	if (involves)
+		isl_die(isl_qpolynomial_get_ctx(qp), isl_error_invalid,
+			"polynomial involves some of the domain dimensions",
+			return isl_qpolynomial_free(qp));
+	qp = isl_qpolynomial_drop_dims(qp, isl_dim_in, 0, n);
+	space = isl_qpolynomial_get_domain_space(qp);
+	space = isl_space_params(space);
+	qp = isl_qpolynomial_reset_domain_space(qp, space);
+	return qp;
+}
+
+static __isl_give isl_qpolynomial *isl_qpolynomial_substitute_equalities_lifted(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_basic_set *eq)
+{
+	int i, j, k;
+	isl_int denom;
+	unsigned total;
+	unsigned n_div;
+	struct isl_upoly *up;
+
+	if (!eq)
+		goto error;
+	if (eq->n_eq == 0) {
+		isl_basic_set_free(eq);
+		return qp;
+	}
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		goto error;
+	qp->div = isl_mat_cow(qp->div);
+	if (!qp->div)
+		goto error;
+
+	total = 1 + isl_space_dim(eq->dim, isl_dim_all);
+	n_div = eq->n_div;
+	isl_int_init(denom);
+	for (i = 0; i < eq->n_eq; ++i) {
+		j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
+		if (j < 0 || j == 0 || j >= total)
+			continue;
+
+		for (k = 0; k < qp->div->n_row; ++k) {
+			if (isl_int_is_zero(qp->div->row[k][1 + j]))
+				continue;
+			isl_seq_elim(qp->div->row[k] + 1, eq->eq[i], j, total,
+					&qp->div->row[k][0]);
+			normalize_div(qp, k);
+		}
+
+		if (isl_int_is_pos(eq->eq[i][j]))
+			isl_seq_neg(eq->eq[i], eq->eq[i], total);
+		isl_int_abs(denom, eq->eq[i][j]);
+		isl_int_set_si(eq->eq[i][j], 0);
+
+		up = isl_upoly_from_affine(qp->dim->ctx,
+						   eq->eq[i], denom, total);
+		qp->upoly = isl_upoly_subs(qp->upoly, j - 1, 1, &up);
+		isl_upoly_free(up);
+	}
+	isl_int_clear(denom);
+
+	if (!qp->upoly)
+		goto error;
+
+	isl_basic_set_free(eq);
+
+	qp = substitute_non_divs(qp);
+	qp = sort_divs(qp);
+
+	return qp;
+error:
+	isl_basic_set_free(eq);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+/* Exploit the equalities in "eq" to simplify the quasi-polynomial.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_substitute_equalities(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_basic_set *eq)
+{
+	if (!qp || !eq)
+		goto error;
+	if (qp->div->n_row > 0)
+		eq = isl_basic_set_add_dims(eq, isl_dim_set, qp->div->n_row);
+	return isl_qpolynomial_substitute_equalities_lifted(qp, eq);
+error:
+	isl_basic_set_free(eq);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+static __isl_give isl_basic_set *add_div_constraints(
+	__isl_take isl_basic_set *bset, __isl_take isl_mat *div)
+{
+	int i;
+	unsigned total;
+
+	if (!bset || !div)
+		goto error;
+
+	bset = isl_basic_set_extend_constraints(bset, 0, 2 * div->n_row);
+	if (!bset)
+		goto error;
+	total = isl_basic_set_total_dim(bset);
+	for (i = 0; i < div->n_row; ++i)
+		if (isl_basic_set_add_div_constraints_var(bset,
+				    total - div->n_row + i, div->row[i]) < 0)
+			goto error;
+
+	isl_mat_free(div);
+	return bset;
+error:
+	isl_mat_free(div);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Look for equalities among the variables shared by context and qp
+ * and the integer divisions of qp, if any.
+ * The equalities are then used to eliminate variables and/or integer
+ * divisions from qp.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_gist(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_set *context)
+{
+	isl_basic_set *aff;
+
+	if (!qp)
+		goto error;
+	if (qp->div->n_row > 0) {
+		isl_basic_set *bset;
+		context = isl_set_add_dims(context, isl_dim_set,
+					    qp->div->n_row);
+		bset = isl_basic_set_universe(isl_set_get_space(context));
+		bset = add_div_constraints(bset, isl_mat_copy(qp->div));
+		context = isl_set_intersect(context,
+					    isl_set_from_basic_set(bset));
+	}
+
+	aff = isl_set_affine_hull(context);
+	return isl_qpolynomial_substitute_equalities_lifted(qp, aff);
+error:
+	isl_qpolynomial_free(qp);
+	isl_set_free(context);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_gist_params(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_set *context)
+{
+	isl_space *space = isl_qpolynomial_get_domain_space(qp);
+	isl_set *dom_context = isl_set_universe(space);
+	dom_context = isl_set_intersect_params(dom_context, context);
+	return isl_qpolynomial_gist(qp, dom_context);
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_qpolynomial(
+	__isl_take isl_qpolynomial *qp)
+{
+	isl_set *dom;
+
+	if (!qp)
+		return NULL;
+	if (isl_qpolynomial_is_zero(qp)) {
+		isl_space *dim = isl_qpolynomial_get_space(qp);
+		isl_qpolynomial_free(qp);
+		return isl_pw_qpolynomial_zero(dim);
+	}
+
+	dom = isl_set_universe(isl_qpolynomial_get_domain_space(qp));
+	return isl_pw_qpolynomial_alloc(dom, qp);
+}
+
+#define isl_qpolynomial_involves_nan isl_qpolynomial_is_nan
+
+#undef PW
+#define PW isl_pw_qpolynomial
+#undef EL
+#define EL isl_qpolynomial
+#undef EL_IS_ZERO
+#define EL_IS_ZERO is_zero
+#undef ZERO
+#define ZERO zero
+#undef IS_ZERO
+#define IS_ZERO is_zero
+#undef FIELD
+#define FIELD qp
+#undef DEFAULT_IS_ZERO
+#define DEFAULT_IS_ZERO 1
+
+#define NO_PULLBACK
+
+#include <isl_pw_templ.c>
+
+#undef UNION
+#define UNION isl_union_pw_qpolynomial
+#undef PART
+#define PART isl_pw_qpolynomial
+#undef PARTS
+#define PARTS pw_qpolynomial
+
+#include <isl_union_single.c>
+#include <isl_union_eval.c>
+#include <isl_union_neg.c>
+
+int isl_pw_qpolynomial_is_one(__isl_keep isl_pw_qpolynomial *pwqp)
+{
+	if (!pwqp)
+		return -1;
+
+	if (pwqp->n != -1)
+		return 0;
+
+	if (!isl_set_plain_is_universe(pwqp->p[0].set))
+		return 0;
+
+	return isl_qpolynomial_is_one(pwqp->p[0].qp);
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add(
+	__isl_take isl_pw_qpolynomial *pwqp1,
+	__isl_take isl_pw_qpolynomial *pwqp2)
+{
+	return isl_pw_qpolynomial_union_add_(pwqp1, pwqp2);
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_mul(
+	__isl_take isl_pw_qpolynomial *pwqp1,
+	__isl_take isl_pw_qpolynomial *pwqp2)
+{
+	int i, j, n;
+	struct isl_pw_qpolynomial *res;
+
+	if (!pwqp1 || !pwqp2)
+		goto error;
+
+	isl_assert(pwqp1->dim->ctx, isl_space_is_equal(pwqp1->dim, pwqp2->dim),
+			goto error);
+
+	if (isl_pw_qpolynomial_is_zero(pwqp1)) {
+		isl_pw_qpolynomial_free(pwqp2);
+		return pwqp1;
+	}
+
+	if (isl_pw_qpolynomial_is_zero(pwqp2)) {
+		isl_pw_qpolynomial_free(pwqp1);
+		return pwqp2;
+	}
+
+	if (isl_pw_qpolynomial_is_one(pwqp1)) {
+		isl_pw_qpolynomial_free(pwqp1);
+		return pwqp2;
+	}
+
+	if (isl_pw_qpolynomial_is_one(pwqp2)) {
+		isl_pw_qpolynomial_free(pwqp2);
+		return pwqp1;
+	}
+
+	n = pwqp1->n * pwqp2->n;
+	res = isl_pw_qpolynomial_alloc_size(isl_space_copy(pwqp1->dim), n);
+
+	for (i = 0; i < pwqp1->n; ++i) {
+		for (j = 0; j < pwqp2->n; ++j) {
+			struct isl_set *common;
+			struct isl_qpolynomial *prod;
+			common = isl_set_intersect(isl_set_copy(pwqp1->p[i].set),
+						isl_set_copy(pwqp2->p[j].set));
+			if (isl_set_plain_is_empty(common)) {
+				isl_set_free(common);
+				continue;
+			}
+
+			prod = isl_qpolynomial_mul(
+				isl_qpolynomial_copy(pwqp1->p[i].qp),
+				isl_qpolynomial_copy(pwqp2->p[j].qp));
+
+			res = isl_pw_qpolynomial_add_piece(res, common, prod);
+		}
+	}
+
+	isl_pw_qpolynomial_free(pwqp1);
+	isl_pw_qpolynomial_free(pwqp2);
+
+	return res;
+error:
+	isl_pw_qpolynomial_free(pwqp1);
+	isl_pw_qpolynomial_free(pwqp2);
+	return NULL;
+}
+
+__isl_give isl_val *isl_upoly_eval(__isl_take struct isl_upoly *up,
+	__isl_take isl_vec *vec)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+	isl_val *res;
+	isl_val *base;
+
+	if (isl_upoly_is_cst(up)) {
+		isl_vec_free(vec);
+		res = isl_upoly_get_constant_val(up);
+		isl_upoly_free(up);
+		return res;
+	}
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	isl_assert(up->ctx, rec->n >= 1, goto error);
+
+	base = isl_val_rat_from_isl_int(up->ctx,
+					vec->el[1 + up->var], vec->el[0]);
+
+	res = isl_upoly_eval(isl_upoly_copy(rec->p[rec->n - 1]),
+				isl_vec_copy(vec));
+
+	for (i = rec->n - 2; i >= 0; --i) {
+		res = isl_val_mul(res, isl_val_copy(base));
+		res = isl_val_add(res,
+			    isl_upoly_eval(isl_upoly_copy(rec->p[i]),
+							    isl_vec_copy(vec)));
+	}
+
+	isl_val_free(base);
+	isl_upoly_free(up);
+	isl_vec_free(vec);
+	return res;
+error:
+	isl_upoly_free(up);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+/* Evaluate "qp" in the void point "pnt".
+ * In particular, return the value NaN.
+ */
+static __isl_give isl_val *eval_void(__isl_take isl_qpolynomial *qp,
+	__isl_take isl_point *pnt)
+{
+	isl_ctx *ctx;
+
+	ctx = isl_point_get_ctx(pnt);
+	isl_qpolynomial_free(qp);
+	isl_point_free(pnt);
+	return isl_val_nan(ctx);
+}
+
+__isl_give isl_val *isl_qpolynomial_eval(__isl_take isl_qpolynomial *qp,
+	__isl_take isl_point *pnt)
+{
+	isl_bool is_void;
+	isl_vec *ext;
+	isl_val *v;
+
+	if (!qp || !pnt)
+		goto error;
+	isl_assert(pnt->dim->ctx, isl_space_is_equal(pnt->dim, qp->dim), goto error);
+	is_void = isl_point_is_void(pnt);
+	if (is_void < 0)
+		goto error;
+	if (is_void)
+		return eval_void(qp, pnt);
+
+	if (qp->div->n_row == 0)
+		ext = isl_vec_copy(pnt->vec);
+	else {
+		int i;
+		unsigned dim = isl_space_dim(qp->dim, isl_dim_all);
+		ext = isl_vec_alloc(qp->dim->ctx, 1 + dim + qp->div->n_row);
+		if (!ext)
+			goto error;
+
+		isl_seq_cpy(ext->el, pnt->vec->el, pnt->vec->size);
+		for (i = 0; i < qp->div->n_row; ++i) {
+			isl_seq_inner_product(qp->div->row[i] + 1, ext->el,
+						1 + dim + i, &ext->el[1+dim+i]);
+			isl_int_fdiv_q(ext->el[1+dim+i], ext->el[1+dim+i],
+					qp->div->row[i][0]);
+		}
+	}
+
+	v = isl_upoly_eval(isl_upoly_copy(qp->upoly), ext);
+
+	isl_qpolynomial_free(qp);
+	isl_point_free(pnt);
+
+	return v;
+error:
+	isl_qpolynomial_free(qp);
+	isl_point_free(pnt);
+	return NULL;
+}
+
+int isl_upoly_cmp(__isl_keep struct isl_upoly_cst *cst1,
+	__isl_keep struct isl_upoly_cst *cst2)
+{
+	int cmp;
+	isl_int t;
+	isl_int_init(t);
+	isl_int_mul(t, cst1->n, cst2->d);
+	isl_int_submul(t, cst2->n, cst1->d);
+	cmp = isl_int_sgn(t);
+	isl_int_clear(t);
+	return cmp;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_insert_dims(
+	__isl_take isl_qpolynomial *qp, enum isl_dim_type type,
+	unsigned first, unsigned n)
+{
+	unsigned total;
+	unsigned g_pos;
+	int *exp;
+
+	if (!qp)
+		return NULL;
+	if (type == isl_dim_out)
+		isl_die(qp->div->ctx, isl_error_invalid,
+			"cannot insert output/set dimensions",
+			goto error);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+	if (n == 0 && !isl_space_is_named_or_nested(qp->dim, type))
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	isl_assert(qp->div->ctx, first <= isl_space_dim(qp->dim, type),
+		    goto error);
+
+	g_pos = pos(qp->dim, type) + first;
+
+	qp->div = isl_mat_insert_zero_cols(qp->div, 2 + g_pos, n);
+	if (!qp->div)
+		goto error;
+
+	total = qp->div->n_col - 2;
+	if (total > g_pos) {
+		int i;
+		exp = isl_alloc_array(qp->div->ctx, int, total - g_pos);
+		if (!exp)
+			goto error;
+		for (i = 0; i < total - g_pos; ++i)
+			exp[i] = i + n;
+		qp->upoly = expand(qp->upoly, exp, g_pos);
+		free(exp);
+		if (!qp->upoly)
+			goto error;
+	}
+
+	qp->dim = isl_space_insert_dims(qp->dim, type, first, n);
+	if (!qp->dim)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_add_dims(
+	__isl_take isl_qpolynomial *qp, enum isl_dim_type type, unsigned n)
+{
+	unsigned pos;
+
+	pos = isl_qpolynomial_dim(qp, type);
+
+	return isl_qpolynomial_insert_dims(qp, type, pos, n);
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_dims(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type type, unsigned n)
+{
+	unsigned pos;
+
+	pos = isl_pw_qpolynomial_dim(pwqp, type);
+
+	return isl_pw_qpolynomial_insert_dims(pwqp, type, pos, n);
+}
+
+static int *reordering_move(isl_ctx *ctx,
+	unsigned len, unsigned dst, unsigned src, unsigned n)
+{
+	int i;
+	int *reordering;
+
+	reordering = isl_alloc_array(ctx, int, len);
+	if (!reordering)
+		return NULL;
+
+	if (dst <= src) {
+		for (i = 0; i < dst; ++i)
+			reordering[i] = i;
+		for (i = 0; i < n; ++i)
+			reordering[src + i] = dst + i;
+		for (i = 0; i < src - dst; ++i)
+			reordering[dst + i] = dst + n + i;
+		for (i = 0; i < len - src - n; ++i)
+			reordering[src + n + i] = src + n + i;
+	} else {
+		for (i = 0; i < src; ++i)
+			reordering[i] = i;
+		for (i = 0; i < n; ++i)
+			reordering[src + i] = dst + i;
+		for (i = 0; i < dst - src; ++i)
+			reordering[src + n + i] = src + i;
+		for (i = 0; i < len - dst - n; ++i)
+			reordering[dst + n + i] = dst + n + i;
+	}
+
+	return reordering;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_move_dims(
+	__isl_take isl_qpolynomial *qp,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	unsigned g_dst_pos;
+	unsigned g_src_pos;
+	int *reordering;
+
+	if (!qp)
+		return NULL;
+
+	if (dst_type == isl_dim_out || src_type == isl_dim_out)
+		isl_die(qp->dim->ctx, isl_error_invalid,
+			"cannot move output/set dimension",
+			goto error);
+	if (dst_type == isl_dim_in)
+		dst_type = isl_dim_set;
+	if (src_type == isl_dim_in)
+		src_type = isl_dim_set;
+
+	if (n == 0 &&
+	    !isl_space_is_named_or_nested(qp->dim, src_type) &&
+	    !isl_space_is_named_or_nested(qp->dim, dst_type))
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	isl_assert(qp->dim->ctx, src_pos + n <= isl_space_dim(qp->dim, src_type),
+		goto error);
+
+	g_dst_pos = pos(qp->dim, dst_type) + dst_pos;
+	g_src_pos = pos(qp->dim, src_type) + src_pos;
+	if (dst_type > src_type)
+		g_dst_pos -= n;
+
+	qp->div = isl_mat_move_cols(qp->div, 2 + g_dst_pos, 2 + g_src_pos, n);
+	if (!qp->div)
+		goto error;
+	qp = sort_divs(qp);
+	if (!qp)
+		goto error;
+
+	reordering = reordering_move(qp->dim->ctx,
+				qp->div->n_col - 2, g_dst_pos, g_src_pos, n);
+	if (!reordering)
+		goto error;
+
+	qp->upoly = reorder(qp->upoly, reordering);
+	free(reordering);
+	if (!qp->upoly)
+		goto error;
+
+	qp->dim = isl_space_move_dims(qp->dim, dst_type, dst_pos, src_type, src_pos, n);
+	if (!qp->dim)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_from_affine(__isl_take isl_space *dim,
+	isl_int *f, isl_int denom)
+{
+	struct isl_upoly *up;
+
+	dim = isl_space_domain(dim);
+	if (!dim)
+		return NULL;
+
+	up = isl_upoly_from_affine(dim->ctx, f, denom,
+					1 + isl_space_dim(dim, isl_dim_all));
+
+	return isl_qpolynomial_alloc(dim, 0, up);
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_from_aff(__isl_take isl_aff *aff)
+{
+	isl_ctx *ctx;
+	struct isl_upoly *up;
+	isl_qpolynomial *qp;
+
+	if (!aff)
+		return NULL;
+
+	ctx = isl_aff_get_ctx(aff);
+	up = isl_upoly_from_affine(ctx, aff->v->el + 1, aff->v->el[0],
+				    aff->v->size - 1);
+
+	qp = isl_qpolynomial_alloc(isl_aff_get_domain_space(aff),
+				    aff->ls->div->n_row, up);
+	if (!qp)
+		goto error;
+
+	isl_mat_free(qp->div);
+	qp->div = isl_mat_copy(aff->ls->div);
+	qp->div = isl_mat_cow(qp->div);
+	if (!qp->div)
+		goto error;
+
+	isl_aff_free(aff);
+	qp = reduce_divs(qp);
+	qp = remove_redundant_divs(qp);
+	return qp;
+error:
+	isl_aff_free(aff);
+	return isl_qpolynomial_free(qp);
+}
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_from_pw_aff(
+	__isl_take isl_pw_aff *pwaff)
+{
+	int i;
+	isl_pw_qpolynomial *pwqp;
+
+	if (!pwaff)
+		return NULL;
+
+	pwqp = isl_pw_qpolynomial_alloc_size(isl_pw_aff_get_space(pwaff),
+						pwaff->n);
+
+	for (i = 0; i < pwaff->n; ++i) {
+		isl_set *dom;
+		isl_qpolynomial *qp;
+
+		dom = isl_set_copy(pwaff->p[i].set);
+		qp = isl_qpolynomial_from_aff(isl_aff_copy(pwaff->p[i].aff));
+		pwqp = isl_pw_qpolynomial_add_piece(pwqp,  dom, qp);
+	}
+
+	isl_pw_aff_free(pwaff);
+	return pwqp;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_from_constraint(
+	__isl_take isl_constraint *c, enum isl_dim_type type, unsigned pos)
+{
+	isl_aff *aff;
+
+	aff = isl_constraint_get_bound(c, type, pos);
+	isl_constraint_free(c);
+	return isl_qpolynomial_from_aff(aff);
+}
+
+/* For each 0 <= i < "n", replace variable "first" + i of type "type"
+ * in "qp" by subs[i].
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_substitute(
+	__isl_take isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned first, unsigned n,
+	__isl_keep isl_qpolynomial **subs)
+{
+	int i;
+	struct isl_upoly **ups;
+
+	if (n == 0)
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	if (type == isl_dim_out)
+		isl_die(qp->dim->ctx, isl_error_invalid,
+			"cannot substitute output/set dimension",
+			goto error);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	for (i = 0; i < n; ++i)
+		if (!subs[i])
+			goto error;
+
+	isl_assert(qp->dim->ctx, first + n <= isl_space_dim(qp->dim, type),
+			goto error);
+
+	for (i = 0; i < n; ++i)
+		isl_assert(qp->dim->ctx, isl_space_is_equal(qp->dim, subs[i]->dim),
+				goto error);
+
+	isl_assert(qp->dim->ctx, qp->div->n_row == 0, goto error);
+	for (i = 0; i < n; ++i)
+		isl_assert(qp->dim->ctx, subs[i]->div->n_row == 0, goto error);
+
+	first += pos(qp->dim, type);
+
+	ups = isl_alloc_array(qp->dim->ctx, struct isl_upoly *, n);
+	if (!ups)
+		goto error;
+	for (i = 0; i < n; ++i)
+		ups[i] = subs[i]->upoly;
+
+	qp->upoly = isl_upoly_subs(qp->upoly, first, n, ups);
+
+	free(ups);
+
+	if (!qp->upoly)
+		goto error;
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+/* Extend "bset" with extra set dimensions for each integer division
+ * in "qp" and then call "fn" with the extended bset and the polynomial
+ * that results from replacing each of the integer divisions by the
+ * corresponding extra set dimension.
+ */
+isl_stat isl_qpolynomial_as_polynomial_on_domain(__isl_keep isl_qpolynomial *qp,
+	__isl_keep isl_basic_set *bset,
+	isl_stat (*fn)(__isl_take isl_basic_set *bset,
+		  __isl_take isl_qpolynomial *poly, void *user), void *user)
+{
+	isl_space *dim;
+	isl_mat *div;
+	isl_qpolynomial *poly;
+
+	if (!qp || !bset)
+		return isl_stat_error;
+	if (qp->div->n_row == 0)
+		return fn(isl_basic_set_copy(bset), isl_qpolynomial_copy(qp),
+			  user);
+
+	div = isl_mat_copy(qp->div);
+	dim = isl_space_copy(qp->dim);
+	dim = isl_space_add_dims(dim, isl_dim_set, qp->div->n_row);
+	poly = isl_qpolynomial_alloc(dim, 0, isl_upoly_copy(qp->upoly));
+	bset = isl_basic_set_copy(bset);
+	bset = isl_basic_set_add_dims(bset, isl_dim_set, qp->div->n_row);
+	bset = add_div_constraints(bset, div);
+
+	return fn(bset, poly, user);
+}
+
+/* Return total degree in variables first (inclusive) up to last (exclusive).
+ */
+int isl_upoly_degree(__isl_keep struct isl_upoly *up, int first, int last)
+{
+	int deg = -1;
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return -2;
+	if (isl_upoly_is_zero(up))
+		return -1;
+	if (isl_upoly_is_cst(up) || up->var < first)
+		return 0;
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		return -2;
+
+	for (i = 0; i < rec->n; ++i) {
+		int d;
+
+		if (isl_upoly_is_zero(rec->p[i]))
+			continue;
+		d = isl_upoly_degree(rec->p[i], first, last);
+		if (up->var < last)
+			d += i;
+		if (d > deg)
+			deg = d;
+	}
+
+	return deg;
+}
+
+/* Return total degree in set variables.
+ */
+int isl_qpolynomial_degree(__isl_keep isl_qpolynomial *poly)
+{
+	unsigned ovar;
+	unsigned nvar;
+
+	if (!poly)
+		return -2;
+
+	ovar = isl_space_offset(poly->dim, isl_dim_set);
+	nvar = isl_space_dim(poly->dim, isl_dim_set);
+	return isl_upoly_degree(poly->upoly, ovar, ovar + nvar);
+}
+
+__isl_give struct isl_upoly *isl_upoly_coeff(__isl_keep struct isl_upoly *up,
+	unsigned pos, int deg)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return NULL;
+
+	if (isl_upoly_is_cst(up) || up->var < pos) {
+		if (deg == 0)
+			return isl_upoly_copy(up);
+		else
+			return isl_upoly_zero(up->ctx);
+	}
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		return NULL;
+
+	if (up->var == pos) {
+		if (deg < rec->n)
+			return isl_upoly_copy(rec->p[deg]);
+		else
+			return isl_upoly_zero(up->ctx);
+	}
+
+	up = isl_upoly_copy(up);
+	up = isl_upoly_cow(up);
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		struct isl_upoly *t;
+		t = isl_upoly_coeff(rec->p[i], pos, deg);
+		if (!t)
+			goto error;
+		isl_upoly_free(rec->p[i]);
+		rec->p[i] = t;
+	}
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+/* Return coefficient of power "deg" of variable "t_pos" of type "type".
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_coeff(
+	__isl_keep isl_qpolynomial *qp,
+	enum isl_dim_type type, unsigned t_pos, int deg)
+{
+	unsigned g_pos;
+	struct isl_upoly *up;
+	isl_qpolynomial *c;
+
+	if (!qp)
+		return NULL;
+
+	if (type == isl_dim_out)
+		isl_die(qp->div->ctx, isl_error_invalid,
+			"output/set dimension does not have a coefficient",
+			return NULL);
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	isl_assert(qp->div->ctx, t_pos < isl_space_dim(qp->dim, type),
+			return NULL);
+
+	g_pos = pos(qp->dim, type) + t_pos;
+	up = isl_upoly_coeff(qp->upoly, g_pos, deg);
+
+	c = isl_qpolynomial_alloc(isl_space_copy(qp->dim), qp->div->n_row, up);
+	if (!c)
+		return NULL;
+	isl_mat_free(c->div);
+	c->div = isl_mat_copy(qp->div);
+	if (!c->div)
+		goto error;
+	return c;
+error:
+	isl_qpolynomial_free(c);
+	return NULL;
+}
+
+/* Homogenize the polynomial in the variables first (inclusive) up to
+ * last (exclusive) by inserting powers of variable first.
+ * Variable first is assumed not to appear in the input.
+ */
+__isl_give struct isl_upoly *isl_upoly_homogenize(
+	__isl_take struct isl_upoly *up, int deg, int target,
+	int first, int last)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up)
+		return NULL;
+	if (isl_upoly_is_zero(up))
+		return up;
+	if (deg == target)
+		return up;
+	if (isl_upoly_is_cst(up) || up->var < first) {
+		struct isl_upoly *hom;
+
+		hom = isl_upoly_var_pow(up->ctx, first, target - deg);
+		if (!hom)
+			goto error;
+		rec = isl_upoly_as_rec(hom);
+		rec->p[target - deg] = isl_upoly_mul(rec->p[target - deg], up);
+
+		return hom;
+	}
+
+	up = isl_upoly_cow(up);
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		if (isl_upoly_is_zero(rec->p[i]))
+			continue;
+		rec->p[i] = isl_upoly_homogenize(rec->p[i],
+				up->var < last ? deg + i : i, target,
+				first, last);
+		if (!rec->p[i])
+			goto error;
+	}
+
+	return up;
+error:
+	isl_upoly_free(up);
+	return NULL;
+}
+
+/* Homogenize the polynomial in the set variables by introducing
+ * powers of an extra set variable at position 0.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_homogenize(
+	__isl_take isl_qpolynomial *poly)
+{
+	unsigned ovar;
+	unsigned nvar;
+	int deg = isl_qpolynomial_degree(poly);
+
+	if (deg < -1)
+		goto error;
+
+	poly = isl_qpolynomial_insert_dims(poly, isl_dim_in, 0, 1);
+	poly = isl_qpolynomial_cow(poly);
+	if (!poly)
+		goto error;
+
+	ovar = isl_space_offset(poly->dim, isl_dim_set);
+	nvar = isl_space_dim(poly->dim, isl_dim_set);
+	poly->upoly = isl_upoly_homogenize(poly->upoly, 0, deg,
+						ovar, ovar + nvar);
+	if (!poly->upoly)
+		goto error;
+
+	return poly;
+error:
+	isl_qpolynomial_free(poly);
+	return NULL;
+}
+
+__isl_give isl_term *isl_term_alloc(__isl_take isl_space *dim,
+	__isl_take isl_mat *div)
+{
+	isl_term *term;
+	int n;
+
+	if (!dim || !div)
+		goto error;
+
+	n = isl_space_dim(dim, isl_dim_all) + div->n_row;
+
+	term = isl_calloc(dim->ctx, struct isl_term,
+			sizeof(struct isl_term) + (n - 1) * sizeof(int));
+	if (!term)
+		goto error;
+
+	term->ref = 1;
+	term->dim = dim;
+	term->div = div;
+	isl_int_init(term->n);
+	isl_int_init(term->d);
+	
+	return term;
+error:
+	isl_space_free(dim);
+	isl_mat_free(div);
+	return NULL;
+}
+
+__isl_give isl_term *isl_term_copy(__isl_keep isl_term *term)
+{
+	if (!term)
+		return NULL;
+
+	term->ref++;
+	return term;
+}
+
+__isl_give isl_term *isl_term_dup(__isl_keep isl_term *term)
+{
+	int i;
+	isl_term *dup;
+	unsigned total;
+
+	if (!term)
+		return NULL;
+
+	total = isl_space_dim(term->dim, isl_dim_all) + term->div->n_row;
+
+	dup = isl_term_alloc(isl_space_copy(term->dim), isl_mat_copy(term->div));
+	if (!dup)
+		return NULL;
+
+	isl_int_set(dup->n, term->n);
+	isl_int_set(dup->d, term->d);
+
+	for (i = 0; i < total; ++i)
+		dup->pow[i] = term->pow[i];
+
+	return dup;
+}
+
+__isl_give isl_term *isl_term_cow(__isl_take isl_term *term)
+{
+	if (!term)
+		return NULL;
+
+	if (term->ref == 1)
+		return term;
+	term->ref--;
+	return isl_term_dup(term);
+}
+
+void isl_term_free(__isl_take isl_term *term)
+{
+	if (!term)
+		return;
+
+	if (--term->ref > 0)
+		return;
+
+	isl_space_free(term->dim);
+	isl_mat_free(term->div);
+	isl_int_clear(term->n);
+	isl_int_clear(term->d);
+	free(term);
+}
+
+unsigned isl_term_dim(__isl_keep isl_term *term, enum isl_dim_type type)
+{
+	if (!term)
+		return 0;
+
+	switch (type) {
+	case isl_dim_param:
+	case isl_dim_in:
+	case isl_dim_out:	return isl_space_dim(term->dim, type);
+	case isl_dim_div:	return term->div->n_row;
+	case isl_dim_all:	return isl_space_dim(term->dim, isl_dim_all) +
+								term->div->n_row;
+	default:		return 0;
+	}
+}
+
+isl_ctx *isl_term_get_ctx(__isl_keep isl_term *term)
+{
+	return term ? term->dim->ctx : NULL;
+}
+
+void isl_term_get_num(__isl_keep isl_term *term, isl_int *n)
+{
+	if (!term)
+		return;
+	isl_int_set(*n, term->n);
+}
+
+void isl_term_get_den(__isl_keep isl_term *term, isl_int *d)
+{
+	if (!term)
+		return;
+	isl_int_set(*d, term->d);
+}
+
+/* Return the coefficient of the term "term".
+ */
+__isl_give isl_val *isl_term_get_coefficient_val(__isl_keep isl_term *term)
+{
+	if (!term)
+		return NULL;
+
+	return isl_val_rat_from_isl_int(isl_term_get_ctx(term),
+					term->n, term->d);
+}
+
+int isl_term_get_exp(__isl_keep isl_term *term,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!term)
+		return -1;
+
+	isl_assert(term->dim->ctx, pos < isl_term_dim(term, type), return -1);
+
+	if (type >= isl_dim_set)
+		pos += isl_space_dim(term->dim, isl_dim_param);
+	if (type >= isl_dim_div)
+		pos += isl_space_dim(term->dim, isl_dim_set);
+
+	return term->pow[pos];
+}
+
+__isl_give isl_aff *isl_term_get_div(__isl_keep isl_term *term, unsigned pos)
+{
+	isl_local_space *ls;
+	isl_aff *aff;
+
+	if (!term)
+		return NULL;
+
+	isl_assert(term->dim->ctx, pos < isl_term_dim(term, isl_dim_div),
+			return NULL);
+
+	ls = isl_local_space_alloc_div(isl_space_copy(term->dim),
+					isl_mat_copy(term->div));
+	aff = isl_aff_alloc(ls);
+	if (!aff)
+		return NULL;
+
+	isl_seq_cpy(aff->v->el, term->div->row[pos], aff->v->size);
+
+	aff = isl_aff_normalize(aff);
+
+	return aff;
+}
+
+__isl_give isl_term *isl_upoly_foreach_term(__isl_keep struct isl_upoly *up,
+	isl_stat (*fn)(__isl_take isl_term *term, void *user),
+	__isl_take isl_term *term, void *user)
+{
+	int i;
+	struct isl_upoly_rec *rec;
+
+	if (!up || !term)
+		goto error;
+
+	if (isl_upoly_is_zero(up))
+		return term;
+
+	isl_assert(up->ctx, !isl_upoly_is_nan(up), goto error);
+	isl_assert(up->ctx, !isl_upoly_is_infty(up), goto error);
+	isl_assert(up->ctx, !isl_upoly_is_neginfty(up), goto error);
+
+	if (isl_upoly_is_cst(up)) {
+		struct isl_upoly_cst *cst;
+		cst = isl_upoly_as_cst(up);
+		if (!cst)
+			goto error;
+		term = isl_term_cow(term);
+		if (!term)
+			goto error;
+		isl_int_set(term->n, cst->n);
+		isl_int_set(term->d, cst->d);
+		if (fn(isl_term_copy(term), user) < 0)
+			goto error;
+		return term;
+	}
+
+	rec = isl_upoly_as_rec(up);
+	if (!rec)
+		goto error;
+
+	for (i = 0; i < rec->n; ++i) {
+		term = isl_term_cow(term);
+		if (!term)
+			goto error;
+		term->pow[up->var] = i;
+		term = isl_upoly_foreach_term(rec->p[i], fn, term, user);
+		if (!term)
+			goto error;
+	}
+	term->pow[up->var] = 0;
+
+	return term;
+error:
+	isl_term_free(term);
+	return NULL;
+}
+
+isl_stat isl_qpolynomial_foreach_term(__isl_keep isl_qpolynomial *qp,
+	isl_stat (*fn)(__isl_take isl_term *term, void *user), void *user)
+{
+	isl_term *term;
+
+	if (!qp)
+		return isl_stat_error;
+
+	term = isl_term_alloc(isl_space_copy(qp->dim), isl_mat_copy(qp->div));
+	if (!term)
+		return isl_stat_error;
+
+	term = isl_upoly_foreach_term(qp->upoly, fn, term, user);
+
+	isl_term_free(term);
+
+	return term ? isl_stat_ok : isl_stat_error;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_from_term(__isl_take isl_term *term)
+{
+	struct isl_upoly *up;
+	isl_qpolynomial *qp;
+	int i, n;
+
+	if (!term)
+		return NULL;
+
+	n = isl_space_dim(term->dim, isl_dim_all) + term->div->n_row;
+
+	up = isl_upoly_rat_cst(term->dim->ctx, term->n, term->d);
+	for (i = 0; i < n; ++i) {
+		if (!term->pow[i])
+			continue;
+		up = isl_upoly_mul(up,
+			isl_upoly_var_pow(term->dim->ctx, i, term->pow[i]));
+	}
+
+	qp = isl_qpolynomial_alloc(isl_space_copy(term->dim), term->div->n_row, up);
+	if (!qp)
+		goto error;
+	isl_mat_free(qp->div);
+	qp->div = isl_mat_copy(term->div);
+	if (!qp->div)
+		goto error;
+
+	isl_term_free(term);
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_term_free(term);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_lift(__isl_take isl_qpolynomial *qp,
+	__isl_take isl_space *dim)
+{
+	int i;
+	int extra;
+	unsigned total;
+
+	if (!qp || !dim)
+		goto error;
+
+	if (isl_space_is_equal(qp->dim, dim)) {
+		isl_space_free(dim);
+		return qp;
+	}
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		goto error;
+
+	extra = isl_space_dim(dim, isl_dim_set) -
+			isl_space_dim(qp->dim, isl_dim_set);
+	total = isl_space_dim(qp->dim, isl_dim_all);
+	if (qp->div->n_row) {
+		int *exp;
+
+		exp = isl_alloc_array(qp->div->ctx, int, qp->div->n_row);
+		if (!exp)
+			goto error;
+		for (i = 0; i < qp->div->n_row; ++i)
+			exp[i] = extra + i;
+		qp->upoly = expand(qp->upoly, exp, total);
+		free(exp);
+		if (!qp->upoly)
+			goto error;
+	}
+	qp->div = isl_mat_insert_cols(qp->div, 2 + total, extra);
+	if (!qp->div)
+		goto error;
+	for (i = 0; i < qp->div->n_row; ++i)
+		isl_seq_clr(qp->div->row[i] + 2 + total, extra);
+
+	isl_space_free(qp->dim);
+	qp->dim = dim;
+
+	return qp;
+error:
+	isl_space_free(dim);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+/* For each parameter or variable that does not appear in qp,
+ * first eliminate the variable from all constraints and then set it to zero.
+ */
+static __isl_give isl_set *fix_inactive(__isl_take isl_set *set,
+	__isl_keep isl_qpolynomial *qp)
+{
+	int *active = NULL;
+	int i;
+	int d;
+	unsigned nparam;
+	unsigned nvar;
+
+	if (!set || !qp)
+		goto error;
+
+	d = isl_space_dim(set->dim, isl_dim_all);
+	active = isl_calloc_array(set->ctx, int, d);
+	if (set_active(qp, active) < 0)
+		goto error;
+
+	for (i = 0; i < d; ++i)
+		if (!active[i])
+			break;
+
+	if (i == d) {
+		free(active);
+		return set;
+	}
+
+	nparam = isl_space_dim(set->dim, isl_dim_param);
+	nvar = isl_space_dim(set->dim, isl_dim_set);
+	for (i = 0; i < nparam; ++i) {
+		if (active[i])
+			continue;
+		set = isl_set_eliminate(set, isl_dim_param, i, 1);
+		set = isl_set_fix_si(set, isl_dim_param, i, 0);
+	}
+	for (i = 0; i < nvar; ++i) {
+		if (active[nparam + i])
+			continue;
+		set = isl_set_eliminate(set, isl_dim_set, i, 1);
+		set = isl_set_fix_si(set, isl_dim_set, i, 0);
+	}
+
+	free(active);
+
+	return set;
+error:
+	free(active);
+	isl_set_free(set);
+	return NULL;
+}
+
+struct isl_opt_data {
+	isl_qpolynomial *qp;
+	int first;
+	isl_val *opt;
+	int max;
+};
+
+static isl_stat opt_fn(__isl_take isl_point *pnt, void *user)
+{
+	struct isl_opt_data *data = (struct isl_opt_data *)user;
+	isl_val *val;
+
+	val = isl_qpolynomial_eval(isl_qpolynomial_copy(data->qp), pnt);
+	if (data->first) {
+		data->first = 0;
+		data->opt = val;
+	} else if (data->max) {
+		data->opt = isl_val_max(data->opt, val);
+	} else {
+		data->opt = isl_val_min(data->opt, val);
+	}
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_val *isl_qpolynomial_opt_on_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_set *set, int max)
+{
+	struct isl_opt_data data = { NULL, 1, NULL, max };
+
+	if (!set || !qp)
+		goto error;
+
+	if (isl_upoly_is_cst(qp->upoly)) {
+		isl_set_free(set);
+		data.opt = isl_qpolynomial_get_constant_val(qp);
+		isl_qpolynomial_free(qp);
+		return data.opt;
+	}
+
+	set = fix_inactive(set, qp);
+
+	data.qp = qp;
+	if (isl_set_foreach_point(set, opt_fn, &data) < 0)
+		goto error;
+
+	if (data.first)
+		data.opt = isl_val_zero(isl_set_get_ctx(set));
+
+	isl_set_free(set);
+	isl_qpolynomial_free(qp);
+	return data.opt;
+error:
+	isl_set_free(set);
+	isl_qpolynomial_free(qp);
+	isl_val_free(data.opt);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_morph_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_morph *morph)
+{
+	int i;
+	int n_sub;
+	isl_ctx *ctx;
+	struct isl_upoly **subs;
+	isl_mat *mat, *diag;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp || !morph)
+		goto error;
+
+	ctx = qp->dim->ctx;
+	isl_assert(ctx, isl_space_is_equal(qp->dim, morph->dom->dim), goto error);
+
+	n_sub = morph->inv->n_row - 1;
+	if (morph->inv->n_row != morph->inv->n_col)
+		n_sub += qp->div->n_row;
+	subs = isl_calloc_array(ctx, struct isl_upoly *, n_sub);
+	if (n_sub && !subs)
+		goto error;
+
+	for (i = 0; 1 + i < morph->inv->n_row; ++i)
+		subs[i] = isl_upoly_from_affine(ctx, morph->inv->row[1 + i],
+					morph->inv->row[0][0], morph->inv->n_col);
+	if (morph->inv->n_row != morph->inv->n_col)
+		for (i = 0; i < qp->div->n_row; ++i)
+			subs[morph->inv->n_row - 1 + i] =
+			    isl_upoly_var_pow(ctx, morph->inv->n_col - 1 + i, 1);
+
+	qp->upoly = isl_upoly_subs(qp->upoly, 0, n_sub, subs);
+
+	for (i = 0; i < n_sub; ++i)
+		isl_upoly_free(subs[i]);
+	free(subs);
+
+	diag = isl_mat_diag(ctx, 1, morph->inv->row[0][0]);
+	mat = isl_mat_diagonal(diag, isl_mat_copy(morph->inv));
+	diag = isl_mat_diag(ctx, qp->div->n_row, morph->inv->row[0][0]);
+	mat = isl_mat_diagonal(mat, diag);
+	qp->div = isl_mat_product(qp->div, mat);
+	isl_space_free(qp->dim);
+	qp->dim = isl_space_copy(morph->ran->dim);
+
+	if (!qp->upoly || !qp->div || !qp->dim)
+		goto error;
+
+	isl_morph_free(morph);
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_morph_free(morph);
+	return NULL;
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_mul(
+	__isl_take isl_union_pw_qpolynomial *upwqp1,
+	__isl_take isl_union_pw_qpolynomial *upwqp2)
+{
+	return isl_union_pw_qpolynomial_match_bin_op(upwqp1, upwqp2,
+						&isl_pw_qpolynomial_mul);
+}
+
+/* Reorder the columns of the given div definitions according to the
+ * given reordering.
+ */
+static __isl_give isl_mat *reorder_divs(__isl_take isl_mat *div,
+	__isl_take isl_reordering *r)
+{
+	int i, j;
+	isl_mat *mat;
+	int extra;
+
+	if (!div || !r)
+		goto error;
+
+	extra = isl_space_dim(r->dim, isl_dim_all) + div->n_row - r->len;
+	mat = isl_mat_alloc(div->ctx, div->n_row, div->n_col + extra);
+	if (!mat)
+		goto error;
+
+	for (i = 0; i < div->n_row; ++i) {
+		isl_seq_cpy(mat->row[i], div->row[i], 2);
+		isl_seq_clr(mat->row[i] + 2, mat->n_col - 2);
+		for (j = 0; j < r->len; ++j)
+			isl_int_set(mat->row[i][2 + r->pos[j]],
+				    div->row[i][2 + j]);
+	}
+
+	isl_reordering_free(r);
+	isl_mat_free(div);
+	return mat;
+error:
+	isl_reordering_free(r);
+	isl_mat_free(div);
+	return NULL;
+}
+
+/* Reorder the dimension of "qp" according to the given reordering.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_realign_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_reordering *r)
+{
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		goto error;
+
+	r = isl_reordering_extend(r, qp->div->n_row);
+	if (!r)
+		goto error;
+
+	qp->div = reorder_divs(qp->div, isl_reordering_copy(r));
+	if (!qp->div)
+		goto error;
+
+	qp->upoly = reorder(qp->upoly, r->pos);
+	if (!qp->upoly)
+		goto error;
+
+	qp = isl_qpolynomial_reset_domain_space(qp, isl_space_copy(r->dim));
+
+	isl_reordering_free(r);
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_reordering_free(r);
+	return NULL;
+}
+
+__isl_give isl_qpolynomial *isl_qpolynomial_align_params(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_space *model)
+{
+	isl_bool equal_params;
+
+	if (!qp || !model)
+		goto error;
+
+	equal_params = isl_space_has_equal_params(qp->dim, model);
+	if (equal_params < 0)
+		goto error;
+	if (!equal_params) {
+		isl_reordering *exp;
+
+		model = isl_space_drop_dims(model, isl_dim_in,
+					0, isl_space_dim(model, isl_dim_in));
+		model = isl_space_drop_dims(model, isl_dim_out,
+					0, isl_space_dim(model, isl_dim_out));
+		exp = isl_parameter_alignment_reordering(qp->dim, model);
+		exp = isl_reordering_extend_space(exp,
+					isl_qpolynomial_get_domain_space(qp));
+		qp = isl_qpolynomial_realign_domain(qp, exp);
+	}
+
+	isl_space_free(model);
+	return qp;
+error:
+	isl_space_free(model);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+struct isl_split_periods_data {
+	int max_periods;
+	isl_pw_qpolynomial *res;
+};
+
+/* Create a slice where the integer division "div" has the fixed value "v".
+ * In particular, if "div" refers to floor(f/m), then create a slice
+ *
+ *	m v <= f <= m v + (m - 1)
+ *
+ * or
+ *
+ *	f - m v >= 0
+ *	-f + m v + (m - 1) >= 0
+ */
+static __isl_give isl_set *set_div_slice(__isl_take isl_space *dim,
+	__isl_keep isl_qpolynomial *qp, int div, isl_int v)
+{
+	int total;
+	isl_basic_set *bset = NULL;
+	int k;
+
+	if (!dim || !qp)
+		goto error;
+
+	total = isl_space_dim(dim, isl_dim_all);
+	bset = isl_basic_set_alloc_space(isl_space_copy(dim), 0, 0, 2);
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_seq_cpy(bset->ineq[k], qp->div->row[div] + 1, 1 + total);
+	isl_int_submul(bset->ineq[k][0], v, qp->div->row[div][0]);
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_seq_neg(bset->ineq[k], qp->div->row[div] + 1, 1 + total);
+	isl_int_addmul(bset->ineq[k][0], v, qp->div->row[div][0]);
+	isl_int_add(bset->ineq[k][0], bset->ineq[k][0], qp->div->row[div][0]);
+	isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1);
+
+	isl_space_free(dim);
+	return isl_set_from_basic_set(bset);
+error:
+	isl_basic_set_free(bset);
+	isl_space_free(dim);
+	return NULL;
+}
+
+static isl_stat split_periods(__isl_take isl_set *set,
+	__isl_take isl_qpolynomial *qp, void *user);
+
+/* Create a slice of the domain "set" such that integer division "div"
+ * has the fixed value "v" and add the results to data->res,
+ * replacing the integer division by "v" in "qp".
+ */
+static isl_stat set_div(__isl_take isl_set *set,
+	__isl_take isl_qpolynomial *qp, int div, isl_int v,
+	struct isl_split_periods_data *data)
+{
+	int i;
+	int total;
+	isl_set *slice;
+	struct isl_upoly *cst;
+
+	slice = set_div_slice(isl_set_get_space(set), qp, div, v);
+	set = isl_set_intersect(set, slice);
+
+	if (!qp)
+		goto error;
+
+	total = isl_space_dim(qp->dim, isl_dim_all);
+
+	for (i = div + 1; i < qp->div->n_row; ++i) {
+		if (isl_int_is_zero(qp->div->row[i][2 + total + div]))
+			continue;
+		isl_int_addmul(qp->div->row[i][1],
+				qp->div->row[i][2 + total + div], v);
+		isl_int_set_si(qp->div->row[i][2 + total + div], 0);
+	}
+
+	cst = isl_upoly_rat_cst(qp->dim->ctx, v, qp->dim->ctx->one);
+	qp = substitute_div(qp, div, cst);
+
+	return split_periods(set, qp, data);
+error:
+	isl_set_free(set);
+	isl_qpolynomial_free(qp);
+	return -1;
+}
+
+/* Split the domain "set" such that integer division "div"
+ * has a fixed value (ranging from "min" to "max") on each slice
+ * and add the results to data->res.
+ */
+static isl_stat split_div(__isl_take isl_set *set,
+	__isl_take isl_qpolynomial *qp, int div, isl_int min, isl_int max,
+	struct isl_split_periods_data *data)
+{
+	for (; isl_int_le(min, max); isl_int_add_ui(min, min, 1)) {
+		isl_set *set_i = isl_set_copy(set);
+		isl_qpolynomial *qp_i = isl_qpolynomial_copy(qp);
+
+		if (set_div(set_i, qp_i, div, min, data) < 0)
+			goto error;
+	}
+	isl_set_free(set);
+	isl_qpolynomial_free(qp);
+	return isl_stat_ok;
+error:
+	isl_set_free(set);
+	isl_qpolynomial_free(qp);
+	return isl_stat_error;
+}
+
+/* If "qp" refers to any integer division
+ * that can only attain "max_periods" distinct values on "set"
+ * then split the domain along those distinct values.
+ * Add the results (or the original if no splitting occurs)
+ * to data->res.
+ */
+static isl_stat split_periods(__isl_take isl_set *set,
+	__isl_take isl_qpolynomial *qp, void *user)
+{
+	int i;
+	isl_pw_qpolynomial *pwqp;
+	struct isl_split_periods_data *data;
+	isl_int min, max;
+	int total;
+	isl_stat r = isl_stat_ok;
+
+	data = (struct isl_split_periods_data *)user;
+
+	if (!set || !qp)
+		goto error;
+
+	if (qp->div->n_row == 0) {
+		pwqp = isl_pw_qpolynomial_alloc(set, qp);
+		data->res = isl_pw_qpolynomial_add_disjoint(data->res, pwqp);
+		return isl_stat_ok;
+	}
+
+	isl_int_init(min);
+	isl_int_init(max);
+	total = isl_space_dim(qp->dim, isl_dim_all);
+	for (i = 0; i < qp->div->n_row; ++i) {
+		enum isl_lp_result lp_res;
+
+		if (isl_seq_first_non_zero(qp->div->row[i] + 2 + total,
+						qp->div->n_row) != -1)
+			continue;
+
+		lp_res = isl_set_solve_lp(set, 0, qp->div->row[i] + 1,
+					  set->ctx->one, &min, NULL, NULL);
+		if (lp_res == isl_lp_error)
+			goto error2;
+		if (lp_res == isl_lp_unbounded || lp_res == isl_lp_empty)
+			continue;
+		isl_int_fdiv_q(min, min, qp->div->row[i][0]);
+
+		lp_res = isl_set_solve_lp(set, 1, qp->div->row[i] + 1,
+					  set->ctx->one, &max, NULL, NULL);
+		if (lp_res == isl_lp_error)
+			goto error2;
+		if (lp_res == isl_lp_unbounded || lp_res == isl_lp_empty)
+			continue;
+		isl_int_fdiv_q(max, max, qp->div->row[i][0]);
+
+		isl_int_sub(max, max, min);
+		if (isl_int_cmp_si(max, data->max_periods) < 0) {
+			isl_int_add(max, max, min);
+			break;
+		}
+	}
+
+	if (i < qp->div->n_row) {
+		r = split_div(set, qp, i, min, max, data);
+	} else {
+		pwqp = isl_pw_qpolynomial_alloc(set, qp);
+		data->res = isl_pw_qpolynomial_add_disjoint(data->res, pwqp);
+	}
+
+	isl_int_clear(max);
+	isl_int_clear(min);
+
+	return r;
+error2:
+	isl_int_clear(max);
+	isl_int_clear(min);
+error:
+	isl_set_free(set);
+	isl_qpolynomial_free(qp);
+	return isl_stat_error;
+}
+
+/* If any quasi-polynomial in pwqp refers to any integer division
+ * that can only attain "max_periods" distinct values on its domain
+ * then split the domain along those distinct values.
+ */
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_split_periods(
+	__isl_take isl_pw_qpolynomial *pwqp, int max_periods)
+{
+	struct isl_split_periods_data data;
+
+	data.max_periods = max_periods;
+	data.res = isl_pw_qpolynomial_zero(isl_pw_qpolynomial_get_space(pwqp));
+
+	if (isl_pw_qpolynomial_foreach_piece(pwqp, &split_periods, &data) < 0)
+		goto error;
+
+	isl_pw_qpolynomial_free(pwqp);
+
+	return data.res;
+error:
+	isl_pw_qpolynomial_free(data.res);
+	isl_pw_qpolynomial_free(pwqp);
+	return NULL;
+}
+
+/* Construct a piecewise quasipolynomial that is constant on the given
+ * domain.  In particular, it is
+ *	0	if cst == 0
+ *	1	if cst == 1
+ *  infinity	if cst == -1
+ *
+ * If cst == -1, then explicitly check whether the domain is empty and,
+ * if so, return 0 instead.
+ */
+static __isl_give isl_pw_qpolynomial *constant_on_domain(
+	__isl_take isl_basic_set *bset, int cst)
+{
+	isl_space *dim;
+	isl_qpolynomial *qp;
+
+	if (cst < 0 && isl_basic_set_is_empty(bset) == isl_bool_true)
+		cst = 0;
+	if (!bset)
+		return NULL;
+
+	bset = isl_basic_set_params(bset);
+	dim = isl_basic_set_get_space(bset);
+	if (cst < 0)
+		qp = isl_qpolynomial_infty_on_domain(dim);
+	else if (cst == 0)
+		qp = isl_qpolynomial_zero_on_domain(dim);
+	else
+		qp = isl_qpolynomial_one_on_domain(dim);
+	return isl_pw_qpolynomial_alloc(isl_set_from_basic_set(bset), qp);
+}
+
+/* Factor bset, call fn on each of the factors and return the product.
+ *
+ * If no factors can be found, simply call fn on the input.
+ * Otherwise, construct the factors based on the factorizer,
+ * call fn on each factor and compute the product.
+ */
+static __isl_give isl_pw_qpolynomial *compressed_multiplicative_call(
+	__isl_take isl_basic_set *bset,
+	__isl_give isl_pw_qpolynomial *(*fn)(__isl_take isl_basic_set *bset))
+{
+	int i, n;
+	isl_space *space;
+	isl_set *set;
+	isl_factorizer *f;
+	isl_qpolynomial *qp;
+	isl_pw_qpolynomial *pwqp;
+	unsigned nparam;
+	unsigned nvar;
+
+	f = isl_basic_set_factorizer(bset);
+	if (!f)
+		goto error;
+	if (f->n_group == 0) {
+		isl_factorizer_free(f);
+		return fn(bset);
+	}
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+	space = isl_basic_set_get_space(bset);
+	space = isl_space_params(space);
+	set = isl_set_universe(isl_space_copy(space));
+	qp = isl_qpolynomial_one_on_domain(space);
+	pwqp = isl_pw_qpolynomial_alloc(set, qp);
+
+	bset = isl_morph_basic_set(isl_morph_copy(f->morph), bset);
+
+	for (i = 0, n = 0; i < f->n_group; ++i) {
+		isl_basic_set *bset_i;
+		isl_pw_qpolynomial *pwqp_i;
+
+		bset_i = isl_basic_set_copy(bset);
+		bset_i = isl_basic_set_drop_constraints_involving(bset_i,
+			    nparam + n + f->len[i], nvar - n - f->len[i]);
+		bset_i = isl_basic_set_drop_constraints_involving(bset_i,
+			    nparam, n);
+		bset_i = isl_basic_set_drop(bset_i, isl_dim_set,
+			    n + f->len[i], nvar - n - f->len[i]);
+		bset_i = isl_basic_set_drop(bset_i, isl_dim_set, 0, n);
+
+		pwqp_i = fn(bset_i);
+		pwqp = isl_pw_qpolynomial_mul(pwqp, pwqp_i);
+
+		n += f->len[i];
+	}
+
+	isl_basic_set_free(bset);
+	isl_factorizer_free(f);
+
+	return pwqp;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Factor bset, call fn on each of the factors and return the product.
+ * The function is assumed to evaluate to zero on empty domains,
+ * to one on zero-dimensional domains and to infinity on unbounded domains
+ * and will not be called explicitly on zero-dimensional or unbounded domains.
+ *
+ * We first check for some special cases and remove all equalities.
+ * Then we hand over control to compressed_multiplicative_call.
+ */
+__isl_give isl_pw_qpolynomial *isl_basic_set_multiplicative_call(
+	__isl_take isl_basic_set *bset,
+	__isl_give isl_pw_qpolynomial *(*fn)(__isl_take isl_basic_set *bset))
+{
+	isl_bool bounded;
+	isl_morph *morph;
+	isl_pw_qpolynomial *pwqp;
+
+	if (!bset)
+		return NULL;
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return constant_on_domain(bset, 0);
+
+	if (isl_basic_set_dim(bset, isl_dim_set) == 0)
+		return constant_on_domain(bset, 1);
+
+	bounded = isl_basic_set_is_bounded(bset);
+	if (bounded < 0)
+		goto error;
+	if (!bounded)
+		return constant_on_domain(bset, -1);
+
+	if (bset->n_eq == 0)
+		return compressed_multiplicative_call(bset, fn);
+
+	morph = isl_basic_set_full_compression(bset);
+	bset = isl_morph_basic_set(isl_morph_copy(morph), bset);
+
+	pwqp = compressed_multiplicative_call(bset, fn);
+
+	morph = isl_morph_dom_params(morph);
+	morph = isl_morph_ran_params(morph);
+	morph = isl_morph_inverse(morph);
+
+	pwqp = isl_pw_qpolynomial_morph_domain(pwqp, morph);
+
+	return pwqp;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Drop all floors in "qp", turning each integer division [a/m] into
+ * a rational division a/m.  If "down" is set, then the integer division
+ * is replaced by (a-(m-1))/m instead.
+ */
+static __isl_give isl_qpolynomial *qp_drop_floors(
+	__isl_take isl_qpolynomial *qp, int down)
+{
+	int i;
+	struct isl_upoly *s;
+
+	if (!qp)
+		return NULL;
+	if (qp->div->n_row == 0)
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+
+	for (i = qp->div->n_row - 1; i >= 0; --i) {
+		if (down) {
+			isl_int_sub(qp->div->row[i][1],
+				    qp->div->row[i][1], qp->div->row[i][0]);
+			isl_int_add_ui(qp->div->row[i][1],
+				       qp->div->row[i][1], 1);
+		}
+		s = isl_upoly_from_affine(qp->dim->ctx, qp->div->row[i] + 1,
+					qp->div->row[i][0], qp->div->n_col - 1);
+		qp = substitute_div(qp, i, s);
+		if (!qp)
+			return NULL;
+	}
+
+	return qp;
+}
+
+/* Drop all floors in "pwqp", turning each integer division [a/m] into
+ * a rational division a/m.
+ */
+static __isl_give isl_pw_qpolynomial *pwqp_drop_floors(
+	__isl_take isl_pw_qpolynomial *pwqp)
+{
+	int i;
+
+	if (!pwqp)
+		return NULL;
+
+	if (isl_pw_qpolynomial_is_zero(pwqp))
+		return pwqp;
+
+	pwqp = isl_pw_qpolynomial_cow(pwqp);
+	if (!pwqp)
+		return NULL;
+
+	for (i = 0; i < pwqp->n; ++i) {
+		pwqp->p[i].qp = qp_drop_floors(pwqp->p[i].qp, 0);
+		if (!pwqp->p[i].qp)
+			goto error;
+	}
+
+	return pwqp;
+error:
+	isl_pw_qpolynomial_free(pwqp);
+	return NULL;
+}
+
+/* Adjust all the integer divisions in "qp" such that they are at least
+ * one over the given orthant (identified by "signs").  This ensures
+ * that they will still be non-negative even after subtracting (m-1)/m.
+ *
+ * In particular, f is replaced by f' + v, changing f = [a/m]
+ * to f' = [(a - m v)/m].
+ * If the constant term k in a is smaller than m,
+ * the constant term of v is set to floor(k/m) - 1.
+ * For any other term, if the coefficient c and the variable x have
+ * the same sign, then no changes are needed.
+ * Otherwise, if the variable is positive (and c is negative),
+ * then the coefficient of x in v is set to floor(c/m).
+ * If the variable is negative (and c is positive),
+ * then the coefficient of x in v is set to ceil(c/m).
+ */
+static __isl_give isl_qpolynomial *make_divs_pos(__isl_take isl_qpolynomial *qp,
+	int *signs)
+{
+	int i, j;
+	int total;
+	isl_vec *v = NULL;
+	struct isl_upoly *s;
+
+	qp = isl_qpolynomial_cow(qp);
+	if (!qp)
+		return NULL;
+	qp->div = isl_mat_cow(qp->div);
+	if (!qp->div)
+		goto error;
+
+	total = isl_space_dim(qp->dim, isl_dim_all);
+	v = isl_vec_alloc(qp->div->ctx, qp->div->n_col - 1);
+
+	for (i = 0; i < qp->div->n_row; ++i) {
+		isl_int *row = qp->div->row[i];
+		v = isl_vec_clr(v);
+		if (!v)
+			goto error;
+		if (isl_int_lt(row[1], row[0])) {
+			isl_int_fdiv_q(v->el[0], row[1], row[0]);
+			isl_int_sub_ui(v->el[0], v->el[0], 1);
+			isl_int_submul(row[1], row[0], v->el[0]);
+		}
+		for (j = 0; j < total; ++j) {
+			if (isl_int_sgn(row[2 + j]) * signs[j] >= 0)
+				continue;
+			if (signs[j] < 0)
+				isl_int_cdiv_q(v->el[1 + j], row[2 + j], row[0]);
+			else
+				isl_int_fdiv_q(v->el[1 + j], row[2 + j], row[0]);
+			isl_int_submul(row[2 + j], row[0], v->el[1 + j]);
+		}
+		for (j = 0; j < i; ++j) {
+			if (isl_int_sgn(row[2 + total + j]) >= 0)
+				continue;
+			isl_int_fdiv_q(v->el[1 + total + j],
+					row[2 + total + j], row[0]);
+			isl_int_submul(row[2 + total + j],
+					row[0], v->el[1 + total + j]);
+		}
+		for (j = i + 1; j < qp->div->n_row; ++j) {
+			if (isl_int_is_zero(qp->div->row[j][2 + total + i]))
+				continue;
+			isl_seq_combine(qp->div->row[j] + 1,
+				qp->div->ctx->one, qp->div->row[j] + 1,
+				qp->div->row[j][2 + total + i], v->el, v->size);
+		}
+		isl_int_set_si(v->el[1 + total + i], 1);
+		s = isl_upoly_from_affine(qp->dim->ctx, v->el,
+					qp->div->ctx->one, v->size);
+		qp->upoly = isl_upoly_subs(qp->upoly, total + i, 1, &s);
+		isl_upoly_free(s);
+		if (!qp->upoly)
+			goto error;
+	}
+
+	isl_vec_free(v);
+	return qp;
+error:
+	isl_vec_free(v);
+	isl_qpolynomial_free(qp);
+	return NULL;
+}
+
+struct isl_to_poly_data {
+	int sign;
+	isl_pw_qpolynomial *res;
+	isl_qpolynomial *qp;
+};
+
+/* Appoximate data->qp by a polynomial on the orthant identified by "signs".
+ * We first make all integer divisions positive and then split the
+ * quasipolynomials into terms with sign data->sign (the direction
+ * of the requested approximation) and terms with the opposite sign.
+ * In the first set of terms, each integer division [a/m] is
+ * overapproximated by a/m, while in the second it is underapproximated
+ * by (a-(m-1))/m.
+ */
+static isl_stat to_polynomial_on_orthant(__isl_take isl_set *orthant,
+	int *signs, void *user)
+{
+	struct isl_to_poly_data *data = user;
+	isl_pw_qpolynomial *t;
+	isl_qpolynomial *qp, *up, *down;
+
+	qp = isl_qpolynomial_copy(data->qp);
+	qp = make_divs_pos(qp, signs);
+
+	up = isl_qpolynomial_terms_of_sign(qp, signs, data->sign);
+	up = qp_drop_floors(up, 0);
+	down = isl_qpolynomial_terms_of_sign(qp, signs, -data->sign);
+	down = qp_drop_floors(down, 1);
+
+	isl_qpolynomial_free(qp);
+	qp = isl_qpolynomial_add(up, down);
+
+	t = isl_pw_qpolynomial_alloc(orthant, qp);
+	data->res = isl_pw_qpolynomial_add_disjoint(data->res, t);
+
+	return isl_stat_ok;
+}
+
+/* Approximate each quasipolynomial by a polynomial.  If "sign" is positive,
+ * the polynomial will be an overapproximation.  If "sign" is negative,
+ * it will be an underapproximation.  If "sign" is zero, the approximation
+ * will lie somewhere in between.
+ *
+ * In particular, is sign == 0, we simply drop the floors, turning
+ * the integer divisions into rational divisions.
+ * Otherwise, we split the domains into orthants, make all integer divisions
+ * positive and then approximate each [a/m] by either a/m or (a-(m-1))/m,
+ * depending on the requested sign and the sign of the term in which
+ * the integer division appears.
+ */
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_to_polynomial(
+	__isl_take isl_pw_qpolynomial *pwqp, int sign)
+{
+	int i;
+	struct isl_to_poly_data data;
+
+	if (sign == 0)
+		return pwqp_drop_floors(pwqp);
+
+	if (!pwqp)
+		return NULL;
+
+	data.sign = sign;
+	data.res = isl_pw_qpolynomial_zero(isl_pw_qpolynomial_get_space(pwqp));
+
+	for (i = 0; i < pwqp->n; ++i) {
+		if (pwqp->p[i].qp->div->n_row == 0) {
+			isl_pw_qpolynomial *t;
+			t = isl_pw_qpolynomial_alloc(
+					isl_set_copy(pwqp->p[i].set),
+					isl_qpolynomial_copy(pwqp->p[i].qp));
+			data.res = isl_pw_qpolynomial_add_disjoint(data.res, t);
+			continue;
+		}
+		data.qp = pwqp->p[i].qp;
+		if (isl_set_foreach_orthant(pwqp->p[i].set,
+					&to_polynomial_on_orthant, &data) < 0)
+			goto error;
+	}
+
+	isl_pw_qpolynomial_free(pwqp);
+
+	return data.res;
+error:
+	isl_pw_qpolynomial_free(pwqp);
+	isl_pw_qpolynomial_free(data.res);
+	return NULL;
+}
+
+static __isl_give isl_pw_qpolynomial *poly_entry(
+	__isl_take isl_pw_qpolynomial *pwqp, void *user)
+{
+	int *sign = user;
+
+	return isl_pw_qpolynomial_to_polynomial(pwqp, *sign);
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_to_polynomial(
+	__isl_take isl_union_pw_qpolynomial *upwqp, int sign)
+{
+	return isl_union_pw_qpolynomial_transform_inplace(upwqp,
+				   &poly_entry, &sign);
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_qpolynomial(
+	__isl_take isl_qpolynomial *qp)
+{
+	int i, k;
+	isl_space *dim;
+	isl_vec *aff = NULL;
+	isl_basic_map *bmap = NULL;
+	unsigned pos;
+	unsigned n_div;
+
+	if (!qp)
+		return NULL;
+	if (!isl_upoly_is_affine(qp->upoly))
+		isl_die(qp->dim->ctx, isl_error_invalid,
+			"input quasi-polynomial not affine", goto error);
+	aff = isl_qpolynomial_extract_affine(qp);
+	if (!aff)
+		goto error;
+	dim = isl_qpolynomial_get_space(qp);
+	pos = 1 + isl_space_offset(dim, isl_dim_out);
+	n_div = qp->div->n_row;
+	bmap = isl_basic_map_alloc_space(dim, n_div, 1, 2 * n_div);
+
+	for (i = 0; i < n_div; ++i) {
+		k = isl_basic_map_alloc_div(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bmap->div[k], qp->div->row[i], qp->div->n_col);
+		isl_int_set_si(bmap->div[k][qp->div->n_col], 0);
+		if (isl_basic_map_add_div_constraints(bmap, k) < 0)
+			goto error;
+	}
+	k = isl_basic_map_alloc_equality(bmap);
+	if (k < 0)
+		goto error;
+	isl_int_neg(bmap->eq[k][pos], aff->el[0]);
+	isl_seq_cpy(bmap->eq[k], aff->el + 1, pos);
+	isl_seq_cpy(bmap->eq[k] + pos + 1, aff->el + 1 + pos, n_div);
+
+	isl_vec_free(aff);
+	isl_qpolynomial_free(qp);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_vec_free(aff);
+	isl_qpolynomial_free(qp);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_polynomial_private.h b/final/lib/External/isl/isl_polynomial_private.h
new file mode 100644
index 0000000..b615b24
--- /dev/null
+++ b/final/lib/External/isl/isl_polynomial_private.h
@@ -0,0 +1,262 @@
+#include <stdio.h>
+#include <isl_int.h>
+#include <isl/map.h>
+#include <isl/mat.h>
+#include <isl_morph.h>
+#include <isl/polynomial.h>
+#include <isl_reordering.h>
+
+struct isl_upoly {
+	int ref;
+	struct isl_ctx *ctx;
+
+	int var;
+};
+
+struct isl_upoly_cst {
+	struct isl_upoly up;
+	isl_int n;
+	isl_int d;
+};
+
+struct isl_upoly_rec {
+	struct isl_upoly up;
+	int n;
+
+	size_t size;
+	struct isl_upoly *p[];
+};
+
+/* dim represents the domain space.
+ */
+struct isl_qpolynomial {
+	int ref;
+
+	isl_space *dim;
+	struct isl_mat *div;
+	struct isl_upoly *upoly;
+};
+
+struct isl_term {
+	int ref;
+
+	isl_int n;
+	isl_int d;
+
+	isl_space *dim;
+	struct isl_mat *div;
+
+	int pow[1];
+};
+
+struct isl_pw_qpolynomial_piece {
+	struct isl_set *set;
+	struct isl_qpolynomial *qp;
+};
+
+struct isl_pw_qpolynomial {
+	int ref;
+
+	isl_space *dim;
+
+	int n;
+
+	size_t size;
+	struct isl_pw_qpolynomial_piece p[1];
+};
+
+/* dim represents the domain space.
+ */
+struct isl_qpolynomial_fold {
+	int ref;
+
+	enum isl_fold type;
+	isl_space *dim;
+
+	int n;
+
+	size_t size;
+	struct isl_qpolynomial *qp[1];
+};
+
+struct isl_pw_qpolynomial_fold_piece {
+	struct isl_set *set;
+	struct isl_qpolynomial_fold *fold;
+};
+
+struct isl_pw_qpolynomial_fold {
+	int ref;
+
+	enum isl_fold type;
+	isl_space *dim;
+
+	int n;
+
+	size_t size;
+	struct isl_pw_qpolynomial_fold_piece p[1];
+};
+
+void isl_term_get_num(__isl_keep isl_term *term, isl_int *n);
+
+__isl_give struct isl_upoly *isl_upoly_zero(struct isl_ctx *ctx);
+__isl_give struct isl_upoly *isl_upoly_copy(__isl_keep struct isl_upoly *up);
+__isl_give struct isl_upoly *isl_upoly_cow(__isl_take struct isl_upoly *up);
+__isl_give struct isl_upoly *isl_upoly_dup(__isl_keep struct isl_upoly *up);
+__isl_null struct isl_upoly *isl_upoly_free(__isl_take struct isl_upoly *up);
+__isl_give struct isl_upoly *isl_upoly_mul(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2);
+
+int isl_upoly_is_cst(__isl_keep struct isl_upoly *up);
+int isl_upoly_is_zero(__isl_keep struct isl_upoly *up);
+int isl_upoly_is_one(__isl_keep struct isl_upoly *up);
+int isl_upoly_is_negone(__isl_keep struct isl_upoly *up);
+__isl_keep struct isl_upoly_cst *isl_upoly_as_cst(__isl_keep struct isl_upoly *up);
+__isl_keep struct isl_upoly_rec *isl_upoly_as_rec(__isl_keep struct isl_upoly *up);
+
+__isl_give struct isl_upoly *isl_upoly_sum(__isl_take struct isl_upoly *up1,
+	__isl_take struct isl_upoly *up2);
+__isl_give struct isl_upoly *isl_upoly_mul_isl_int(
+	__isl_take struct isl_upoly *up, isl_int v);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_alloc(__isl_take isl_space *dim,
+	unsigned n_div, __isl_take struct isl_upoly *up);
+__isl_give isl_qpolynomial *isl_qpolynomial_cow(__isl_take isl_qpolynomial *qp);
+__isl_give isl_qpolynomial *isl_qpolynomial_dup(__isl_keep isl_qpolynomial *qp);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_cst_on_domain(__isl_take isl_space *dim,
+	isl_int v);
+__isl_give isl_qpolynomial *isl_qpolynomial_rat_cst_on_domain(
+	__isl_take isl_space *space, const isl_int n, const isl_int d);
+__isl_give isl_qpolynomial *isl_qpolynomial_var_pow_on_domain(__isl_take isl_space *dim,
+	int pos, int power);
+isl_bool isl_qpolynomial_is_one(__isl_keep isl_qpolynomial *qp);
+int isl_qpolynomial_is_affine(__isl_keep isl_qpolynomial *qp);
+int isl_qpolynomial_is_cst(__isl_keep isl_qpolynomial *qp,
+	isl_int *n, isl_int *d);
+
+unsigned isl_qpolynomial_domain_offset(__isl_keep isl_qpolynomial *qp,
+	enum isl_dim_type type);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_add_on_domain(
+	__isl_keep isl_set *dom,
+	__isl_take isl_qpolynomial *qp1,
+	__isl_take isl_qpolynomial *qp2);
+
+int isl_qpolynomial_plain_cmp(__isl_keep isl_qpolynomial *qp1,
+	__isl_keep isl_qpolynomial *qp2);
+
+int isl_qpolynomial_degree(__isl_keep isl_qpolynomial *poly);
+__isl_give isl_qpolynomial *isl_qpolynomial_coeff(
+	__isl_keep isl_qpolynomial *poly,
+	enum isl_dim_type type, unsigned pos, int deg);
+
+__isl_give isl_vec *isl_qpolynomial_extract_affine(
+	__isl_keep isl_qpolynomial *qp);
+__isl_give isl_qpolynomial *isl_qpolynomial_from_affine(__isl_take isl_space *dim,
+	isl_int *f, isl_int denom);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_cow(
+	__isl_take isl_pw_qpolynomial *pwqp);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_add_piece(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	__isl_take isl_set *set, __isl_take isl_qpolynomial *qp);
+int isl_pw_qpolynomial_is_one(__isl_keep isl_pw_qpolynomial *pwqp);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_project_out(
+	__isl_take isl_pw_qpolynomial *pwqp,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+__isl_give isl_val *isl_qpolynomial_opt_on_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_set *set, int max);
+
+enum isl_fold isl_fold_type_negate(enum isl_fold type);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_cow(
+	__isl_take isl_qpolynomial_fold *fold);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_dup(
+	__isl_keep isl_qpolynomial_fold *fold);
+
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_cow(
+	__isl_take isl_pw_qpolynomial_fold *pwf);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_add_on_domain(
+	__isl_keep isl_set *set,
+	__isl_take isl_qpolynomial_fold *fold1,
+	__isl_take isl_qpolynomial_fold *fold2);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_fold_on_domain(
+	__isl_keep isl_set *set,
+	__isl_take isl_qpolynomial_fold *fold1,
+	__isl_take isl_qpolynomial_fold *fold2);
+
+int isl_qpolynomial_fold_plain_cmp(__isl_keep isl_qpolynomial_fold *fold1,
+	__isl_keep isl_qpolynomial_fold *fold2);
+
+__isl_give isl_val *isl_qpolynomial_fold_opt_on_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *set, int max);
+
+int isl_pw_qpolynomial_fold_covers(__isl_keep isl_pw_qpolynomial_fold *pwf1,
+	__isl_keep isl_pw_qpolynomial_fold *pwf2);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_morph_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_morph *morph);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_morph_domain(
+	__isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_morph *morph);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_morph_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_morph *morph);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_morph_domain(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_morph *morph);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_lift(__isl_take isl_qpolynomial *qp,
+	__isl_take isl_space *dim);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_lift(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_substitute_equalities(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_basic_set *eq);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_substitute_equalities(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_basic_set *eq);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_gist(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_set *context);
+
+__isl_give isl_qpolynomial *isl_qpolynomial_realign_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_reordering *r);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_realign_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_reordering *r);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_realign_domain(
+	__isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_reordering *r);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_realign_domain(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_reordering *r);
+
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_reset_space(
+	__isl_take isl_pw_qpolynomial *pwqp, __isl_take isl_space *space);
+__isl_give isl_qpolynomial *isl_qpolynomial_reset_domain_space(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_space *dim);
+__isl_give isl_qpolynomial *isl_qpolynomial_reset_space_and_domain(
+	__isl_take isl_qpolynomial *qp, __isl_take isl_space *space,
+	__isl_take isl_space *domain);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_domain_space(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *dim);
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_reset_space_and_domain(
+	__isl_take isl_qpolynomial_fold *fold, __isl_take isl_space *space,
+	__isl_take isl_space *domain);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_reset_domain_space(
+	__isl_take isl_pw_qpolynomial_fold *pwf, __isl_take isl_space *dim);
+
+void isl_qpolynomial_get_den(__isl_keep isl_qpolynomial *qp, isl_int *d);
+__isl_give isl_qpolynomial *isl_qpolynomial_add_isl_int(
+	__isl_take isl_qpolynomial *qp, isl_int v);
+__isl_give isl_qpolynomial *isl_qpolynomial_mul_isl_int(
+	__isl_take isl_qpolynomial *qp, isl_int v);
+__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_mul_isl_int(
+	__isl_take isl_pw_qpolynomial *pwqp, isl_int v);
+
+__isl_give isl_qpolynomial_fold *isl_qpolynomial_fold_mul_isl_int(
+	__isl_take isl_qpolynomial_fold *fold, isl_int v);
+__isl_give isl_pw_qpolynomial_fold *isl_pw_qpolynomial_fold_mul_isl_int(
+	__isl_take isl_pw_qpolynomial_fold *pwf, isl_int v);
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_mul_isl_int(
+	__isl_take isl_union_pw_qpolynomial *upwqp, isl_int v);
+__isl_give isl_union_pw_qpolynomial_fold *
+isl_union_pw_qpolynomial_fold_mul_isl_int(
+	__isl_take isl_union_pw_qpolynomial_fold *upwf, isl_int v);
diff --git a/final/lib/External/isl/isl_power_templ.c b/final/lib/External/isl/isl_power_templ.c
new file mode 100644
index 0000000..65253bd
--- /dev/null
+++ b/final/lib/External/isl/isl_power_templ.c
@@ -0,0 +1,81 @@
+#include <isl_val_private.h>
+
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+
+/* Compute the given non-zero power of "map" and return the result.
+ * If the exponent "exp" is negative, then the -exp th power of the inverse
+ * relation is computed.
+ */
+__isl_give TYPE *FN(TYPE,fixed_power)(__isl_take TYPE *map, isl_int exp)
+{
+	isl_ctx *ctx;
+	TYPE *res = NULL;
+	isl_int r;
+
+	if (!map)
+		return NULL;
+
+	ctx = FN(TYPE,get_ctx)(map);
+	if (isl_int_is_zero(exp))
+		isl_die(ctx, isl_error_invalid,
+			"expecting non-zero exponent", goto error);
+
+	if (isl_int_is_neg(exp)) {
+		isl_int_neg(exp, exp);
+		map = FN(TYPE,reverse)(map);
+		return FN(TYPE,fixed_power)(map, exp);
+	}
+
+	isl_int_init(r);
+	for (;;) {
+		isl_int_fdiv_r(r, exp, ctx->two);
+
+		if (!isl_int_is_zero(r)) {
+			if (!res)
+				res = FN(TYPE,copy)(map);
+			else {
+				res = FN(TYPE,apply_range)(res,
+							  FN(TYPE,copy)(map));
+				res = FN(TYPE,coalesce)(res);
+			}
+			if (!res)
+				break;
+		}
+
+		isl_int_fdiv_q(exp, exp, ctx->two);
+		if (isl_int_is_zero(exp))
+			break;
+
+		map = FN(TYPE,apply_range)(map, FN(TYPE,copy)(map));
+		map = FN(TYPE,coalesce)(map);
+	}
+	isl_int_clear(r);
+
+	FN(TYPE,free)(map);
+	return res;
+error:
+	FN(TYPE,free)(map);
+	return NULL;
+}
+
+/* Compute the given non-zero power of "map" and return the result.
+ * If the exponent "exp" is negative, then the -exp th power of the inverse
+ * relation is computed.
+ */
+__isl_give TYPE *FN(TYPE,fixed_power_val)(__isl_take TYPE *map,
+	__isl_take isl_val *exp)
+{
+	if (!map || !exp)
+		goto error;
+	if (!isl_val_is_int(exp))
+		isl_die(FN(TYPE,get_ctx)(map), isl_error_invalid,
+			"expecting integer exponent", goto error);
+	map = FN(TYPE,fixed_power)(map, exp->n);
+	isl_val_free(exp);
+	return map;
+error:
+	FN(TYPE,free)(map);
+	isl_val_free(exp);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_printer.c b/final/lib/External/isl/isl_printer.c
new file mode 100644
index 0000000..05860da
--- /dev/null
+++ b/final/lib/External/isl/isl_printer.c
@@ -0,0 +1,848 @@
+#include <string.h>
+#include <isl_int.h>
+#include <isl_printer_private.h>
+
+static __isl_give isl_printer *file_start_line(__isl_take isl_printer *p)
+{
+	fprintf(p->file, "%s%*s%s", p->indent_prefix ? p->indent_prefix : "",
+				    p->indent, "", p->prefix ? p->prefix : "");
+	return p;
+}
+
+static __isl_give isl_printer *file_end_line(__isl_take isl_printer *p)
+{
+	fprintf(p->file, "%s\n", p->suffix ? p->suffix : "");
+	return p;
+}
+
+static __isl_give isl_printer *file_flush(__isl_take isl_printer *p)
+{
+	fflush(p->file);
+	return p;
+}
+
+static __isl_give isl_printer *file_print_str(__isl_take isl_printer *p,
+	const char *s)
+{
+	fprintf(p->file, "%s", s);
+	return p;
+}
+
+static __isl_give isl_printer *file_print_double(__isl_take isl_printer *p,
+	double d)
+{
+	fprintf(p->file, "%g", d);
+	return p;
+}
+
+static __isl_give isl_printer *file_print_int(__isl_take isl_printer *p, int i)
+{
+	fprintf(p->file, "%d", i);
+	return p;
+}
+
+static __isl_give isl_printer *file_print_isl_int(__isl_take isl_printer *p, isl_int i)
+{
+	isl_int_print(p->file, i, p->width);
+	return p;
+}
+
+static int grow_buf(__isl_keep isl_printer *p, int extra)
+{
+	int new_size;
+	char *new_buf;
+
+	if (p->buf_size == 0)
+		return -1;
+
+	new_size = ((p->buf_n + extra + 1) * 3) / 2;
+	new_buf = isl_realloc_array(p->ctx, p->buf, char, new_size);
+	if (!new_buf) {
+		p->buf_size = 0;
+		return -1;
+	}
+	p->buf = new_buf;
+	p->buf_size = new_size;
+
+	return 0;
+}
+
+static __isl_give isl_printer *str_print(__isl_take isl_printer *p,
+	const char *s, int len)
+{
+	if (p->buf_n + len + 1 >= p->buf_size && grow_buf(p, len))
+		goto error;
+	memcpy(p->buf + p->buf_n, s, len);
+	p->buf_n += len;
+
+	p->buf[p->buf_n] = '\0';
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *str_print_indent(__isl_take isl_printer *p,
+	int indent)
+{
+	int i;
+
+	if (p->buf_n + indent + 1 >= p->buf_size && grow_buf(p, indent))
+		goto error;
+	for (i = 0; i < indent; ++i)
+		p->buf[p->buf_n++] = ' ';
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *str_start_line(__isl_take isl_printer *p)
+{
+	if (p->indent_prefix)
+		p = str_print(p, p->indent_prefix, strlen(p->indent_prefix));
+	p = str_print_indent(p, p->indent);
+	if (p->prefix)
+		p = str_print(p, p->prefix, strlen(p->prefix));
+	return p;
+}
+
+static __isl_give isl_printer *str_end_line(__isl_take isl_printer *p)
+{
+	if (p->suffix)
+		p = str_print(p, p->suffix, strlen(p->suffix));
+	p = str_print(p, "\n", strlen("\n"));
+	return p;
+}
+
+static __isl_give isl_printer *str_flush(__isl_take isl_printer *p)
+{
+	p->buf_n = 0;
+	p->buf[p->buf_n] = '\0';
+	return p;
+}
+
+static __isl_give isl_printer *str_print_str(__isl_take isl_printer *p,
+	const char *s)
+{
+	return str_print(p, s, strlen(s));
+}
+
+static __isl_give isl_printer *str_print_double(__isl_take isl_printer *p,
+	double d)
+{
+	int left = p->buf_size - p->buf_n;
+	int need = snprintf(p->buf + p->buf_n, left, "%g", d);
+	if (need >= left) {
+		if (grow_buf(p, need))
+			goto error;
+		left = p->buf_size - p->buf_n;
+		need = snprintf(p->buf + p->buf_n, left, "%g", d);
+	}
+	p->buf_n += need;
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *str_print_int(__isl_take isl_printer *p, int i)
+{
+	int left = p->buf_size - p->buf_n;
+	int need = snprintf(p->buf + p->buf_n, left, "%d", i);
+	if (need >= left) {
+		if (grow_buf(p, need))
+			goto error;
+		left = p->buf_size - p->buf_n;
+		need = snprintf(p->buf + p->buf_n, left, "%d", i);
+	}
+	p->buf_n += need;
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+static __isl_give isl_printer *str_print_isl_int(__isl_take isl_printer *p,
+	isl_int i)
+{
+	char *s;
+	int len;
+
+	s = isl_int_get_str(i);
+	len = strlen(s);
+	if (len < p->width)
+		p = str_print_indent(p, p->width - len);
+	p = str_print(p, s, len);
+	isl_int_free_str(s);
+	return p;
+}
+
+struct isl_printer_ops {
+	__isl_give isl_printer *(*start_line)(__isl_take isl_printer *p);
+	__isl_give isl_printer *(*end_line)(__isl_take isl_printer *p);
+	__isl_give isl_printer *(*print_double)(__isl_take isl_printer *p,
+		double d);
+	__isl_give isl_printer *(*print_int)(__isl_take isl_printer *p, int i);
+	__isl_give isl_printer *(*print_isl_int)(__isl_take isl_printer *p,
+						isl_int i);
+	__isl_give isl_printer *(*print_str)(__isl_take isl_printer *p,
+						const char *s);
+	__isl_give isl_printer *(*flush)(__isl_take isl_printer *p);
+};
+
+static struct isl_printer_ops file_ops = {
+	file_start_line,
+	file_end_line,
+	file_print_double,
+	file_print_int,
+	file_print_isl_int,
+	file_print_str,
+	file_flush
+};
+
+static struct isl_printer_ops str_ops = {
+	str_start_line,
+	str_end_line,
+	str_print_double,
+	str_print_int,
+	str_print_isl_int,
+	str_print_str,
+	str_flush
+};
+
+__isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file)
+{
+	struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
+	if (!p)
+		return NULL;
+	p->ctx = ctx;
+	isl_ctx_ref(p->ctx);
+	p->ops = &file_ops;
+	p->file = file;
+	p->buf = NULL;
+	p->buf_n = 0;
+	p->buf_size = 0;
+	p->indent = 0;
+	p->output_format = ISL_FORMAT_ISL;
+	p->indent_prefix = NULL;
+	p->prefix = NULL;
+	p->suffix = NULL;
+	p->width = 0;
+	p->yaml_style = ISL_YAML_STYLE_FLOW;
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx)
+{
+	struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
+	if (!p)
+		return NULL;
+	p->ctx = ctx;
+	isl_ctx_ref(p->ctx);
+	p->ops = &str_ops;
+	p->file = NULL;
+	p->buf = isl_alloc_array(ctx, char, 256);
+	if (!p->buf)
+		goto error;
+	p->buf_n = 0;
+	p->buf[0] = '\0';
+	p->buf_size = 256;
+	p->indent = 0;
+	p->output_format = ISL_FORMAT_ISL;
+	p->indent_prefix = NULL;
+	p->prefix = NULL;
+	p->suffix = NULL;
+	p->width = 0;
+	p->yaml_style = ISL_YAML_STYLE_FLOW;
+
+	return p;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+__isl_null isl_printer *isl_printer_free(__isl_take isl_printer *p)
+{
+	if (!p)
+		return NULL;
+	free(p->buf);
+	free(p->indent_prefix);
+	free(p->prefix);
+	free(p->suffix);
+	free(p->yaml_state);
+	isl_id_to_id_free(p->notes);
+	isl_ctx_deref(p->ctx);
+	free(p);
+
+	return NULL;
+}
+
+isl_ctx *isl_printer_get_ctx(__isl_keep isl_printer *printer)
+{
+	return printer ? printer->ctx : NULL;
+}
+
+FILE *isl_printer_get_file(__isl_keep isl_printer *printer)
+{
+	if (!printer)
+		return NULL;
+	if (!printer->file)
+		isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
+			"not a file printer", return NULL);
+	return printer->file;
+}
+
+__isl_give isl_printer *isl_printer_set_isl_int_width(__isl_take isl_printer *p,
+	int width)
+{
+	if (!p)
+		return NULL;
+
+	p->width = width;
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_set_indent(__isl_take isl_printer *p,
+	int indent)
+{
+	if (!p)
+		return NULL;
+
+	p->indent = indent;
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_indent(__isl_take isl_printer *p,
+	int indent)
+{
+	if (!p)
+		return NULL;
+
+	p->indent += indent;
+	if (p->indent < 0)
+		p->indent = 0;
+
+	return p;
+}
+
+/* Replace the indent prefix of "p" by "prefix".
+ */
+__isl_give isl_printer *isl_printer_set_indent_prefix(__isl_take isl_printer *p,
+	const char *prefix)
+{
+	if (!p)
+		return NULL;
+
+	free(p->indent_prefix);
+	p->indent_prefix = prefix ? strdup(prefix) : NULL;
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_set_prefix(__isl_take isl_printer *p,
+	const char *prefix)
+{
+	if (!p)
+		return NULL;
+
+	free(p->prefix);
+	p->prefix = prefix ? strdup(prefix) : NULL;
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_set_suffix(__isl_take isl_printer *p,
+	const char *suffix)
+{
+	if (!p)
+		return NULL;
+
+	free(p->suffix);
+	p->suffix = suffix ? strdup(suffix) : NULL;
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_set_output_format(__isl_take isl_printer *p,
+	int output_format)
+{
+	if (!p)
+		return NULL;
+
+	p->output_format = output_format;
+
+	return p;
+}
+
+int isl_printer_get_output_format(__isl_keep isl_printer *p)
+{
+	if (!p)
+		return -1;
+	return p->output_format;
+}
+
+/* Does "p" have a note with identifier "id"?
+ */
+isl_bool isl_printer_has_note(__isl_keep isl_printer *p,
+	__isl_keep isl_id *id)
+{
+	if (!p || !id)
+		return isl_bool_error;
+	if (!p->notes)
+		return isl_bool_false;
+	return isl_id_to_id_has(p->notes, id);
+}
+
+/* Retrieve the note identified by "id" from "p".
+ * The note is assumed to exist.
+ */
+__isl_give isl_id *isl_printer_get_note(__isl_keep isl_printer *p,
+	__isl_take isl_id *id)
+{
+	isl_bool has_note;
+
+	has_note = isl_printer_has_note(p, id);
+	if (has_note < 0)
+		goto error;
+	if (!has_note)
+		isl_die(isl_printer_get_ctx(p), isl_error_invalid,
+			"no such note", goto error);
+
+	return isl_id_to_id_get(p->notes, id);
+error:
+	isl_id_free(id);
+	return NULL;
+}
+
+/* Associate "note" to the identifier "id" in "p",
+ * replacing the previous note associated to the identifier, if any.
+ */
+__isl_give isl_printer *isl_printer_set_note(__isl_take isl_printer *p,
+	__isl_take isl_id *id, __isl_take isl_id *note)
+{
+	if (!p || !id || !note)
+		goto error;
+	if (!p->notes) {
+		p->notes = isl_id_to_id_alloc(isl_printer_get_ctx(p), 1);
+		if (!p->notes)
+			goto error;
+	}
+	p->notes = isl_id_to_id_set(p->notes, id, note);
+	if (!p->notes)
+		return isl_printer_free(p);
+	return p;
+error:
+	isl_printer_free(p);
+	isl_id_free(id);
+	isl_id_free(note);
+	return NULL;
+}
+
+/* Keep track of whether the printing to "p" is being performed from
+ * an isl_*_dump function as specified by "dump".
+ */
+__isl_give isl_printer *isl_printer_set_dump(__isl_take isl_printer *p,
+	int dump)
+{
+	if (!p)
+		return NULL;
+
+	p->dump = dump;
+
+	return p;
+}
+
+/* Set the YAML style of "p" to "yaml_style" and return the updated printer.
+ */
+__isl_give isl_printer *isl_printer_set_yaml_style(__isl_take isl_printer *p,
+	int yaml_style)
+{
+	if (!p)
+		return NULL;
+
+	p->yaml_style = yaml_style;
+
+	return p;
+}
+
+/* Return the YAML style of "p" or -1 on error.
+ */
+int isl_printer_get_yaml_style(__isl_keep isl_printer *p)
+{
+	if (!p)
+		return -1;
+	return p->yaml_style;
+}
+
+/* Push "state" onto the stack of currently active YAML elements and
+ * return the updated printer.
+ */
+static __isl_give isl_printer *push_state(__isl_take isl_printer *p,
+	enum isl_yaml_state state)
+{
+	if (!p)
+		return NULL;
+
+	if (p->yaml_size < p->yaml_depth + 1) {
+		enum isl_yaml_state *state;
+		state = isl_realloc_array(p->ctx, p->yaml_state,
+					enum isl_yaml_state, p->yaml_depth + 1);
+		if (!state)
+			return isl_printer_free(p);
+		p->yaml_state = state;
+		p->yaml_size = p->yaml_depth + 1;
+	}
+
+	p->yaml_state[p->yaml_depth] = state;
+	p->yaml_depth++;
+
+	return p;
+}
+
+/* Remove the innermost active YAML element from the stack and
+ * return the updated printer.
+ */
+static __isl_give isl_printer *pop_state(__isl_take isl_printer *p)
+{
+	if (!p)
+		return NULL;
+	p->yaml_depth--;
+	return p;
+}
+
+/* Set the state of the innermost active YAML element to "state" and
+ * return the updated printer.
+ */
+static __isl_give isl_printer *update_state(__isl_take isl_printer *p,
+	enum isl_yaml_state state)
+{
+	if (!p)
+		return NULL;
+	if (p->yaml_depth < 1)
+		isl_die(isl_printer_get_ctx(p), isl_error_invalid,
+			"not in YAML construct", return isl_printer_free(p));
+
+	p->yaml_state[p->yaml_depth - 1] = state;
+
+	return p;
+}
+
+/* Return the state of the innermost active YAML element.
+ * Return isl_yaml_none if we are not inside any YAML element.
+ */
+static enum isl_yaml_state current_state(__isl_keep isl_printer *p)
+{
+	if (!p)
+		return isl_yaml_none;
+	if (p->yaml_depth < 1)
+		return isl_yaml_none;
+	return p->yaml_state[p->yaml_depth - 1];
+}
+
+/* If we are printing a YAML document and we are at the start of an element,
+ * print whatever is needed before we can print the actual element and
+ * keep track of the fact that we are now printing the element.
+ * If "eol" is set, then whatever we print is going to be the last
+ * thing that gets printed on this line.
+ *
+ * If we are about the print the first key of a mapping, then nothing
+ * extra needs to be printed.  For any other key, however, we need
+ * to either move to the next line (in block format) or print a comma
+ * (in flow format).
+ * Before printing a value in a mapping, we need to print a colon.
+ *
+ * For sequences, in flow format, we only need to print a comma
+ * for each element except the first.
+ * In block format, before the first element in the sequence,
+ * we move to a new line, print a dash and increase the indentation.
+ * Before any other element, we print a dash on a new line,
+ * temporarily moving the indentation back.
+ */
+static __isl_give isl_printer *enter_state(__isl_take isl_printer *p,
+	int eol)
+{
+	enum isl_yaml_state state;
+
+	if (!p)
+		return NULL;
+
+	state = current_state(p);
+	if (state == isl_yaml_mapping_val_start) {
+		if (eol)
+			p = p->ops->print_str(p, ":");
+		else
+			p = p->ops->print_str(p, ": ");
+		p = update_state(p, isl_yaml_mapping_val);
+	} else if (state == isl_yaml_mapping_first_key_start) {
+		p = update_state(p, isl_yaml_mapping_key);
+	} else if (state == isl_yaml_mapping_key_start) {
+		if (p->yaml_style == ISL_YAML_STYLE_FLOW)
+			p = p->ops->print_str(p, ", ");
+		else {
+			p = p->ops->end_line(p);
+			p = p->ops->start_line(p);
+		}
+		p = update_state(p, isl_yaml_mapping_key);
+	} else if (state == isl_yaml_sequence_first_start) {
+		if (p->yaml_style != ISL_YAML_STYLE_FLOW) {
+			p = p->ops->end_line(p);
+			p = p->ops->start_line(p);
+			p = p->ops->print_str(p, "- ");
+			p = isl_printer_indent(p, 2);
+		}
+		p = update_state(p, isl_yaml_sequence);
+	} else if (state == isl_yaml_sequence_start) {
+		if (p->yaml_style == ISL_YAML_STYLE_FLOW)
+			p = p->ops->print_str(p, ", ");
+		else {
+			p = p->ops->end_line(p);
+			p = isl_printer_indent(p, -2);
+			p = p->ops->start_line(p);
+			p = p->ops->print_str(p, "- ");
+			p = isl_printer_indent(p, 2);
+		}
+		p = update_state(p, isl_yaml_sequence);
+	}
+
+	return p;
+}
+
+__isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p,
+	const char *s)
+{
+	if (!p)
+		return NULL;
+	if (!s)
+		return isl_printer_free(p);
+	p = enter_state(p, 0);
+	if (!p)
+		return NULL;
+	return p->ops->print_str(p, s);
+}
+
+__isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p,
+	double d)
+{
+	p = enter_state(p, 0);
+	if (!p)
+		return NULL;
+
+	return p->ops->print_double(p, d);
+}
+
+__isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i)
+{
+	p = enter_state(p, 0);
+	if (!p)
+		return NULL;
+
+	return p->ops->print_int(p, i);
+}
+
+__isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p,
+	isl_int i)
+{
+	p = enter_state(p, 0);
+	if (!p)
+		return NULL;
+
+	return p->ops->print_isl_int(p, i);
+}
+
+__isl_give isl_printer *isl_printer_start_line(__isl_take isl_printer *p)
+{
+	if (!p)
+		return NULL;
+
+	return p->ops->start_line(p);
+}
+
+__isl_give isl_printer *isl_printer_end_line(__isl_take isl_printer *p)
+{
+	if (!p)
+		return NULL;
+
+	return p->ops->end_line(p);
+}
+
+/* Return a copy of the string constructed by the string printer "printer".
+ */
+__isl_give char *isl_printer_get_str(__isl_keep isl_printer *printer)
+{
+	if (!printer)
+		return NULL;
+	if (printer->ops != &str_ops)
+		isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
+			"isl_printer_get_str can only be called on a string "
+			"printer", return NULL);
+	if (!printer->buf)
+		return NULL;
+	return strdup(printer->buf);
+}
+
+__isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p)
+{
+	if (!p)
+		return NULL;
+
+	return p->ops->flush(p);
+}
+
+/* Start a YAML mapping and push a new state to reflect that we
+ * are about to print the first key in a mapping.
+ *
+ * In flow style, print the opening brace.
+ * In block style, move to the next line with an increased indentation,
+ * except if this is the outer mapping or if we are inside a sequence
+ * (in which case we have already increased the indentation and we want
+ * to print the first key on the same line as the dash).
+ */
+__isl_give isl_printer *isl_printer_yaml_start_mapping(
+	__isl_take isl_printer *p)
+{
+	enum isl_yaml_state state;
+
+	if (!p)
+		return NULL;
+	p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK);
+	if (!p)
+		return NULL;
+	state = current_state(p);
+	if (p->yaml_style == ISL_YAML_STYLE_FLOW)
+		p = p->ops->print_str(p, "{ ");
+	else if (state != isl_yaml_none && state != isl_yaml_sequence) {
+		p = p->ops->end_line(p);
+		p = isl_printer_indent(p, 2);
+		p = p->ops->start_line(p);
+	}
+	p = push_state(p, isl_yaml_mapping_first_key_start);
+	return p;
+}
+
+/* Finish a YAML mapping and pop it from the state stack.
+ *
+ * In flow style, print the closing brace.
+ *
+ * In block style, first check if we are still in the
+ * isl_yaml_mapping_first_key_start state.  If so, we have not printed
+ * anything yet, so print "{}" to indicate an empty mapping.
+ * If we increased the indentation in isl_printer_yaml_start_mapping,
+ * then decrease it again.
+ * If this is the outer mapping then print a newline.
+ */
+__isl_give isl_printer *isl_printer_yaml_end_mapping(
+	__isl_take isl_printer *p)
+{
+	enum isl_yaml_state state;
+
+	state = current_state(p);
+	p = pop_state(p);
+	if (!p)
+		return NULL;
+	if (p->yaml_style == ISL_YAML_STYLE_FLOW)
+		return p->ops->print_str(p, " }");
+	if (state == isl_yaml_mapping_first_key_start)
+		p = p->ops->print_str(p, "{}");
+	if (!p)
+		return NULL;
+	state = current_state(p);
+	if (state != isl_yaml_none && state != isl_yaml_sequence)
+		p = isl_printer_indent(p, -2);
+	if (state == isl_yaml_none)
+		p = p->ops->end_line(p);
+	return p;
+}
+
+/* Start a YAML sequence and push a new state to reflect that we
+ * are about to print the first element in a sequence.
+ *
+ * In flow style, print the opening bracket.
+ */
+__isl_give isl_printer *isl_printer_yaml_start_sequence(
+	__isl_take isl_printer *p)
+{
+	if (!p)
+		return NULL;
+	p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK);
+	p = push_state(p, isl_yaml_sequence_first_start);
+	if (!p)
+		return NULL;
+	if (p->yaml_style == ISL_YAML_STYLE_FLOW)
+		p = p->ops->print_str(p, "[ ");
+	return p;
+}
+
+/* Finish a YAML sequence and pop it from the state stack.
+ *
+ * In flow style, print the closing bracket.
+ *
+ * In block style, check if we are still in the
+ * isl_yaml_sequence_first_start state.  If so, we have not printed
+ * anything yet, so print "[]" or " []" to indicate an empty sequence.
+ * We print the extra space when we instructed enter_state not
+ * to print a space at the end of the line.
+ * Otherwise, undo the increase in indentation performed by
+ * enter_state when moving away from the isl_yaml_sequence_first_start
+ * state.
+ * If this is the outer sequence then print a newline.
+ */
+__isl_give isl_printer *isl_printer_yaml_end_sequence(
+	__isl_take isl_printer *p)
+{
+	enum isl_yaml_state state, up;
+
+	state = current_state(p);
+	p = pop_state(p);
+	if (!p)
+		return NULL;
+	if (p->yaml_style == ISL_YAML_STYLE_FLOW)
+		return p->ops->print_str(p, " ]");
+	up = current_state(p);
+	if (state == isl_yaml_sequence_first_start) {
+		if (up == isl_yaml_mapping_val)
+			p = p->ops->print_str(p, " []");
+		else
+			p = p->ops->print_str(p, "[]");
+	} else {
+		p = isl_printer_indent(p, -2);
+	}
+	if (!p)
+		return NULL;
+	state = current_state(p);
+	if (state == isl_yaml_none)
+		p = p->ops->end_line(p);
+	return p;
+}
+
+/* Mark the fact that the current element is finished and that
+ * the next output belongs to the next element.
+ * In particular, if we are printing a key, then prepare for
+ * printing the subsequent value.  If we are printing a value,
+ * prepare for printing the next key.  If we are printing an
+ * element in a sequence, prepare for printing the next element.
+ */
+__isl_give isl_printer *isl_printer_yaml_next(__isl_take isl_printer *p)
+{
+	enum isl_yaml_state state;
+
+	if (!p)
+		return NULL;
+	if (p->yaml_depth < 1)
+		isl_die(isl_printer_get_ctx(p), isl_error_invalid,
+			"not in YAML construct", return isl_printer_free(p));
+
+	state = current_state(p);
+	if (state == isl_yaml_mapping_key)
+		state = isl_yaml_mapping_val_start;
+	else if (state == isl_yaml_mapping_val)
+		state = isl_yaml_mapping_key_start;
+	else if (state == isl_yaml_sequence)
+		state = isl_yaml_sequence_start;
+	p = update_state(p, state);
+
+	return p;
+}
diff --git a/final/lib/External/isl/isl_printer_private.h b/final/lib/External/isl/isl_printer_private.h
new file mode 100644
index 0000000..6b852e8
--- /dev/null
+++ b/final/lib/External/isl/isl_printer_private.h
@@ -0,0 +1,52 @@
+#ifndef ISL_PRINTER_PRIVATE_H
+#define ISL_PRINTER_PRIVATE_H
+
+#include <isl/printer.h>
+#include <isl_yaml.h>
+#include <isl/id_to_id.h>
+
+struct isl_printer_ops;
+
+/* A printer to a file or a string.
+ *
+ * "dump" is set if the printing is performed from an isl_*_dump function.
+ *
+ * yaml_style is the YAML style in which the next elements should
+ * be printed and may be either ISL_YAML_STYLE_BLOCK or ISL_YAML_STYLE_FLOW,
+ * with ISL_YAML_STYLE_FLOW being the default.
+ * yaml_state keeps track of the currently active YAML elements.
+ * yaml_size is the size of this arrays, while yaml_depth
+ * is the number of elements currently in use.
+ * yaml_state may be NULL if no YAML printing is being performed.
+ *
+ * notes keeps track of arbitrary notes as a mapping between
+ * name identifiers and note identifiers.  It may be NULL
+ * if there are no notes yet.
+ */
+struct isl_printer {
+	struct isl_ctx	*ctx;
+	struct isl_printer_ops *ops;
+	FILE        	*file;
+	int		buf_n;
+	int		buf_size;
+	char		*buf;
+	int		indent;
+	int		output_format;
+	int		dump;
+	char		*indent_prefix;
+	char		*prefix;
+	char		*suffix;
+	int		width;
+
+	int			yaml_style;
+	int			yaml_depth;
+	int			yaml_size;
+	enum isl_yaml_state	*yaml_state;
+
+	isl_id_to_id	*notes;
+};
+
+__isl_give isl_printer *isl_printer_set_dump(__isl_take isl_printer *p,
+	int dump);
+
+#endif
diff --git a/final/lib/External/isl/isl_pw_hash.c b/final/lib/External/isl/isl_pw_hash.c
new file mode 100644
index 0000000..4d121c0
--- /dev/null
+++ b/final/lib/External/isl/isl_pw_hash.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege
+ */
+
+#include <isl_pw_macro.h>
+#include <isl/hash.h>
+
+/* Return a hash value that digests "pw".
+ */
+uint32_t FN(PW,get_hash)(__isl_keep PW *pw)
+{
+	int i;
+	uint32_t hash;
+
+	if (!pw)
+		return 0;
+
+	hash = isl_hash_init();
+	for (i = 0; i < pw->n; ++i) {
+		uint32_t set_hash, el_hash;
+
+		set_hash = isl_set_get_hash(pw->p[i].set);
+		isl_hash_hash(hash, set_hash);
+		el_hash = FN(EL,get_hash)(pw->p[i].FIELD);
+		isl_hash_hash(hash, el_hash);
+	}
+
+	return hash;
+}
diff --git a/final/lib/External/isl/isl_pw_macro.h b/final/lib/External/isl/isl_pw_macro.h
new file mode 100644
index 0000000..f445df6
--- /dev/null
+++ b/final/lib/External/isl/isl_pw_macro.h
@@ -0,0 +1,4 @@
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xS(TYPE,NAME) struct TYPE ## _ ## NAME
+#define S(TYPE,NAME) xS(TYPE,NAME)
diff --git a/final/lib/External/isl/isl_pw_templ.c b/final/lib/External/isl/isl_pw_templ.c
new file mode 100644
index 0000000..124ff34
--- /dev/null
+++ b/final/lib/External/isl/isl_pw_templ.c
@@ -0,0 +1,2217 @@
+/*
+ * Copyright 2010-2011 INRIA Saclay
+ * Copyright 2011      Sven Verdoolaege
+ * Copyright 2012-2014 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl/aff.h>
+#include <isl_sort.h>
+#include <isl_val_private.h>
+
+#include <isl_pw_macro.h>
+
+#ifdef HAS_TYPE
+__isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *dim,
+	enum isl_fold type, int n)
+#else
+__isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *dim, int n)
+#endif
+{
+	isl_ctx *ctx;
+	struct PW *pw;
+
+	if (!dim)
+		return NULL;
+	ctx = isl_space_get_ctx(dim);
+	isl_assert(ctx, n >= 0, goto error);
+	pw = isl_alloc(ctx, struct PW,
+			sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
+	if (!pw)
+		goto error;
+
+	pw->ref = 1;
+#ifdef HAS_TYPE
+	pw->type = type;
+#endif
+	pw->size = n;
+	pw->n = 0;
+	pw->dim = dim;
+	return pw;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+#ifdef HAS_TYPE
+__isl_give PW *FN(PW,ZERO)(__isl_take isl_space *dim, enum isl_fold type)
+{
+	return FN(PW,alloc_size)(dim, type, 0);
+}
+#else
+__isl_give PW *FN(PW,ZERO)(__isl_take isl_space *dim)
+{
+	return FN(PW,alloc_size)(dim, 0);
+}
+#endif
+
+__isl_give PW *FN(PW,add_piece)(__isl_take PW *pw,
+	__isl_take isl_set *set, __isl_take EL *el)
+{
+	isl_ctx *ctx;
+	isl_space *el_dim = NULL;
+
+	if (!pw || !set || !el)
+		goto error;
+
+	if (isl_set_plain_is_empty(set) || FN(EL,EL_IS_ZERO)(el)) {
+		isl_set_free(set);
+		FN(EL,free)(el);
+		return pw;
+	}
+
+	ctx = isl_set_get_ctx(set);
+#ifdef HAS_TYPE
+	if (pw->type != el->type)
+		isl_die(ctx, isl_error_invalid, "fold types don't match",
+			goto error);
+#endif
+	el_dim = FN(EL,get_space(el));
+	isl_assert(ctx, isl_space_is_equal(pw->dim, el_dim), goto error);
+	isl_assert(ctx, pw->n < pw->size, goto error);
+
+	pw->p[pw->n].set = set;
+	pw->p[pw->n].FIELD = el;
+	pw->n++;
+	
+	isl_space_free(el_dim);
+	return pw;
+error:
+	isl_space_free(el_dim);
+	FN(PW,free)(pw);
+	isl_set_free(set);
+	FN(EL,free)(el);
+	return NULL;
+}
+
+#ifdef HAS_TYPE
+__isl_give PW *FN(PW,alloc)(enum isl_fold type,
+	__isl_take isl_set *set, __isl_take EL *el)
+#else
+__isl_give PW *FN(PW,alloc)(__isl_take isl_set *set, __isl_take EL *el)
+#endif
+{
+	PW *pw;
+
+	if (!set || !el)
+		goto error;
+
+#ifdef HAS_TYPE
+	pw = FN(PW,alloc_size)(FN(EL,get_space)(el), type, 1);
+#else
+	pw = FN(PW,alloc_size)(FN(EL,get_space)(el), 1);
+#endif
+
+	return FN(PW,add_piece)(pw, set, el);
+error:
+	isl_set_free(set);
+	FN(EL,free)(el);
+	return NULL;
+}
+
+__isl_give PW *FN(PW,dup)(__isl_keep PW *pw)
+{
+	int i;
+	PW *dup;
+
+	if (!pw)
+		return NULL;
+
+#ifdef HAS_TYPE
+	dup = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, pw->n);
+#else
+	dup = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->n);
+#endif
+	if (!dup)
+		return NULL;
+
+	for (i = 0; i < pw->n; ++i)
+		dup = FN(PW,add_piece)(dup, isl_set_copy(pw->p[i].set),
+					    FN(EL,copy)(pw->p[i].FIELD));
+
+	return dup;
+}
+
+__isl_give PW *FN(PW,cow)(__isl_take PW *pw)
+{
+	if (!pw)
+		return NULL;
+
+	if (pw->ref == 1)
+		return pw;
+	pw->ref--;
+	return FN(PW,dup)(pw);
+}
+
+__isl_give PW *FN(PW,copy)(__isl_keep PW *pw)
+{
+	if (!pw)
+		return NULL;
+
+	pw->ref++;
+	return pw;
+}
+
+__isl_null PW *FN(PW,free)(__isl_take PW *pw)
+{
+	int i;
+
+	if (!pw)
+		return NULL;
+	if (--pw->ref > 0)
+		return NULL;
+
+	for (i = 0; i < pw->n; ++i) {
+		isl_set_free(pw->p[i].set);
+		FN(EL,free)(pw->p[i].FIELD);
+	}
+	isl_space_free(pw->dim);
+	free(pw);
+
+	return NULL;
+}
+
+const char *FN(PW,get_dim_name)(__isl_keep PW *pw, enum isl_dim_type type,
+	unsigned pos)
+{
+	return pw ? isl_space_get_dim_name(pw->dim, type, pos) : NULL;
+}
+
+isl_bool FN(PW,has_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
+	unsigned pos)
+{
+	return pw ? isl_space_has_dim_id(pw->dim, type, pos) : isl_bool_error;
+}
+
+__isl_give isl_id *FN(PW,get_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
+	unsigned pos)
+{
+	return pw ? isl_space_get_dim_id(pw->dim, type, pos) : NULL;
+}
+
+isl_bool FN(PW,has_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
+{
+	return pw ? isl_space_has_tuple_name(pw->dim, type) : isl_bool_error;
+}
+
+const char *FN(PW,get_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
+{
+	return pw ? isl_space_get_tuple_name(pw->dim, type) : NULL;
+}
+
+isl_bool FN(PW,has_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
+{
+	return pw ? isl_space_has_tuple_id(pw->dim, type) : isl_bool_error;
+}
+
+__isl_give isl_id *FN(PW,get_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
+{
+	return pw ? isl_space_get_tuple_id(pw->dim, type) : NULL;
+}
+
+isl_bool FN(PW,IS_ZERO)(__isl_keep PW *pw)
+{
+	if (!pw)
+		return isl_bool_error;
+
+	return pw->n == 0;
+}
+
+#ifndef NO_REALIGN
+__isl_give PW *FN(PW,realign_domain)(__isl_take PW *pw,
+	__isl_take isl_reordering *exp)
+{
+	int i;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw || !exp)
+		goto error;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_realign(pw->p[i].set,
+						    isl_reordering_copy(exp));
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,realign_domain)(pw->p[i].FIELD,
+						    isl_reordering_copy(exp));
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	pw = FN(PW,reset_domain_space)(pw, isl_space_copy(exp->dim));
+
+	isl_reordering_free(exp);
+	return pw;
+error:
+	isl_reordering_free(exp);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+/* Align the parameters of "pw" to those of "model".
+ */
+__isl_give PW *FN(PW,align_params)(__isl_take PW *pw, __isl_take isl_space *model)
+{
+	isl_ctx *ctx;
+	isl_bool equal_params;
+
+	if (!pw || !model)
+		goto error;
+
+	ctx = isl_space_get_ctx(model);
+	if (!isl_space_has_named_params(model))
+		isl_die(ctx, isl_error_invalid,
+			"model has unnamed parameters", goto error);
+	if (!isl_space_has_named_params(pw->dim))
+		isl_die(ctx, isl_error_invalid,
+			"input has unnamed parameters", goto error);
+	equal_params = isl_space_has_equal_params(pw->dim, model);
+	if (equal_params < 0)
+		goto error;
+	if (!equal_params) {
+		isl_reordering *exp;
+
+		model = isl_space_drop_dims(model, isl_dim_in,
+					0, isl_space_dim(model, isl_dim_in));
+		model = isl_space_drop_dims(model, isl_dim_out,
+					0, isl_space_dim(model, isl_dim_out));
+		exp = isl_parameter_alignment_reordering(pw->dim, model);
+		exp = isl_reordering_extend_space(exp,
+					FN(PW,get_domain_space)(pw));
+		pw = FN(PW,realign_domain)(pw, exp);
+	}
+
+	isl_space_free(model);
+	return pw;
+error:
+	isl_space_free(model);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+static __isl_give PW *FN(PW,align_params_pw_pw_and)(__isl_take PW *pw1,
+	__isl_take PW *pw2,
+	__isl_give PW *(*fn)(__isl_take PW *pw1, __isl_take PW *pw2))
+{
+	isl_ctx *ctx;
+	isl_bool equal_params;
+
+	if (!pw1 || !pw2)
+		goto error;
+	equal_params = isl_space_has_equal_params(pw1->dim, pw2->dim);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params)
+		return fn(pw1, pw2);
+	ctx = FN(PW,get_ctx)(pw1);
+	if (!isl_space_has_named_params(pw1->dim) ||
+	    !isl_space_has_named_params(pw2->dim))
+		isl_die(ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	pw1 = FN(PW,align_params)(pw1, FN(PW,get_space)(pw2));
+	pw2 = FN(PW,align_params)(pw2, FN(PW,get_space)(pw1));
+	return fn(pw1, pw2);
+error:
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return NULL;
+}
+
+static __isl_give PW *FN(PW,align_params_pw_set_and)(__isl_take PW *pw,
+	__isl_take isl_set *set,
+	__isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_set *set))
+{
+	isl_ctx *ctx;
+	isl_bool aligned;
+
+	if (!pw || !set)
+		goto error;
+	aligned = isl_set_space_has_equal_params(set, pw->dim);
+	if (aligned < 0)
+		goto error;
+	if (aligned)
+		return fn(pw, set);
+	ctx = FN(PW,get_ctx)(pw);
+	if (!isl_space_has_named_params(pw->dim) ||
+	    !isl_space_has_named_params(set->dim))
+		isl_die(ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	pw = FN(PW,align_params)(pw, isl_set_get_space(set));
+	set = isl_set_align_params(set, FN(PW,get_space)(pw));
+	return fn(pw, set);
+error:
+	FN(PW,free)(pw);
+	isl_set_free(set);
+	return NULL;
+}
+#endif
+
+static __isl_give PW *FN(PW,union_add_aligned)(__isl_take PW *pw1,
+	__isl_take PW *pw2)
+{
+	int i, j, n;
+	struct PW *res;
+	isl_ctx *ctx;
+	isl_set *set;
+
+	if (!pw1 || !pw2)
+		goto error;
+
+	ctx = isl_space_get_ctx(pw1->dim);
+#ifdef HAS_TYPE
+	if (pw1->type != pw2->type)
+		isl_die(ctx, isl_error_invalid,
+			"fold types don't match", goto error);
+#endif
+	isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
+
+	if (FN(PW,IS_ZERO)(pw1)) {
+		FN(PW,free)(pw1);
+		return pw2;
+	}
+
+	if (FN(PW,IS_ZERO)(pw2)) {
+		FN(PW,free)(pw2);
+		return pw1;
+	}
+
+	n = (pw1->n + 1) * (pw2->n + 1);
+#ifdef HAS_TYPE
+	res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), pw1->type, n);
+#else
+	res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), n);
+#endif
+
+	for (i = 0; i < pw1->n; ++i) {
+		set = isl_set_copy(pw1->p[i].set);
+		for (j = 0; j < pw2->n; ++j) {
+			struct isl_set *common;
+			EL *sum;
+			common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
+						isl_set_copy(pw2->p[j].set));
+			if (isl_set_plain_is_empty(common)) {
+				isl_set_free(common);
+				continue;
+			}
+			set = isl_set_subtract(set,
+					isl_set_copy(pw2->p[j].set));
+
+			sum = FN(EL,add_on_domain)(common,
+						   FN(EL,copy)(pw1->p[i].FIELD),
+						   FN(EL,copy)(pw2->p[j].FIELD));
+
+			res = FN(PW,add_piece)(res, common, sum);
+		}
+		res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw1->p[i].FIELD));
+	}
+
+	for (j = 0; j < pw2->n; ++j) {
+		set = isl_set_copy(pw2->p[j].set);
+		for (i = 0; i < pw1->n; ++i)
+			set = isl_set_subtract(set,
+					isl_set_copy(pw1->p[i].set));
+		res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw2->p[j].FIELD));
+	}
+
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+
+	return res;
+error:
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return NULL;
+}
+
+/* Private version of "union_add".  For isl_pw_qpolynomial and
+ * isl_pw_qpolynomial_fold, we prefer to simply call it "add".
+ */
+static __isl_give PW *FN(PW,union_add_)(__isl_take PW *pw1, __isl_take PW *pw2)
+{
+	return FN(PW,align_params_pw_pw_and)(pw1, pw2,
+						&FN(PW,union_add_aligned));
+}
+
+/* Make sure "pw" has room for at least "n" more pieces.
+ *
+ * If there is only one reference to pw, we extend it in place.
+ * Otherwise, we create a new PW and copy the pieces.
+ */
+static __isl_give PW *FN(PW,grow)(__isl_take PW *pw, int n)
+{
+	int i;
+	isl_ctx *ctx;
+	PW *res;
+
+	if (!pw)
+		return NULL;
+	if (pw->n + n <= pw->size)
+		return pw;
+	ctx = FN(PW,get_ctx)(pw);
+	n += pw->n;
+	if (pw->ref == 1) {
+		res = isl_realloc(ctx, pw, struct PW,
+			    sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
+		if (!res)
+			return FN(PW,free)(pw);
+		res->size = n;
+		return res;
+	}
+#ifdef HAS_TYPE
+	res = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, n);
+#else
+	res = FN(PW,alloc_size)(isl_space_copy(pw->dim), n);
+#endif
+	if (!res)
+		return FN(PW,free)(pw);
+	for (i = 0; i < pw->n; ++i)
+		res = FN(PW,add_piece)(res, isl_set_copy(pw->p[i].set),
+					    FN(EL,copy)(pw->p[i].FIELD));
+	FN(PW,free)(pw);
+	return res;
+}
+
+static __isl_give PW *FN(PW,add_disjoint_aligned)(__isl_take PW *pw1,
+	__isl_take PW *pw2)
+{
+	int i;
+	isl_ctx *ctx;
+
+	if (!pw1 || !pw2)
+		goto error;
+
+	if (pw1->size < pw1->n + pw2->n && pw1->n < pw2->n)
+		return FN(PW,add_disjoint_aligned)(pw2, pw1);
+
+	ctx = isl_space_get_ctx(pw1->dim);
+#ifdef HAS_TYPE
+	if (pw1->type != pw2->type)
+		isl_die(ctx, isl_error_invalid,
+			"fold types don't match", goto error);
+#endif
+	isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
+
+	if (FN(PW,IS_ZERO)(pw1)) {
+		FN(PW,free)(pw1);
+		return pw2;
+	}
+
+	if (FN(PW,IS_ZERO)(pw2)) {
+		FN(PW,free)(pw2);
+		return pw1;
+	}
+
+	pw1 = FN(PW,grow)(pw1, pw2->n);
+	if (!pw1)
+		goto error;
+
+	for (i = 0; i < pw2->n; ++i)
+		pw1 = FN(PW,add_piece)(pw1,
+				isl_set_copy(pw2->p[i].set),
+				FN(EL,copy)(pw2->p[i].FIELD));
+
+	FN(PW,free)(pw2);
+
+	return pw1;
+error:
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return NULL;
+}
+
+__isl_give PW *FN(PW,add_disjoint)(__isl_take PW *pw1, __isl_take PW *pw2)
+{
+	return FN(PW,align_params_pw_pw_and)(pw1, pw2,
+						&FN(PW,add_disjoint_aligned));
+}
+
+/* This function is currently only used from isl_aff.c
+ */
+static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
+	__isl_take PW *pw2, __isl_take isl_space *space,
+	__isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
+	__attribute__ ((unused));
+
+/* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
+ * The result of "fn" (and therefore also of this function) lives in "space".
+ */
+static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
+	__isl_take PW *pw2, __isl_take isl_space *space,
+	__isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
+{
+	int i, j, n;
+	PW *res = NULL;
+
+	if (!pw1 || !pw2)
+		goto error;
+
+	n = pw1->n * pw2->n;
+#ifdef HAS_TYPE
+	res = FN(PW,alloc_size)(isl_space_copy(space), pw1->type, n);
+#else
+	res = FN(PW,alloc_size)(isl_space_copy(space), n);
+#endif
+
+	for (i = 0; i < pw1->n; ++i) {
+		for (j = 0; j < pw2->n; ++j) {
+			isl_set *common;
+			EL *res_ij;
+			int empty;
+
+			common = isl_set_intersect(
+					isl_set_copy(pw1->p[i].set),
+					isl_set_copy(pw2->p[j].set));
+			empty = isl_set_plain_is_empty(common);
+			if (empty < 0 || empty) {
+				isl_set_free(common);
+				if (empty < 0)
+					goto error;
+				continue;
+			}
+
+			res_ij = fn(FN(EL,copy)(pw1->p[i].FIELD),
+				    FN(EL,copy)(pw2->p[j].FIELD));
+			res_ij = FN(EL,gist)(res_ij, isl_set_copy(common));
+
+			res = FN(PW,add_piece)(res, common, res_ij);
+		}
+	}
+
+	isl_space_free(space);
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return res;
+error:
+	isl_space_free(space);
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	FN(PW,free)(res);
+	return NULL;
+}
+
+/* This function is currently only used from isl_aff.c
+ */
+static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
+	__isl_take PW *pw2,
+	__isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
+	__attribute__ ((unused));
+
+/* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
+ * The result of "fn" is assumed to live in the same space as "pw1" and "pw2".
+ */
+static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
+	__isl_take PW *pw2,
+	__isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
+{
+	isl_space *space;
+
+	if (!pw1 || !pw2)
+		goto error;
+
+	space = isl_space_copy(pw1->dim);
+	return FN(PW,on_shared_domain_in)(pw1, pw2, space, fn);
+error:
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return NULL;
+}
+
+#ifndef NO_NEG
+__isl_give PW *FN(PW,neg)(__isl_take PW *pw)
+{
+	int i;
+
+	if (!pw)
+		return NULL;
+
+	if (FN(PW,IS_ZERO)(pw))
+		return pw;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].FIELD = FN(EL,neg)(pw->p[i].FIELD);
+		if (!pw->p[i].FIELD)
+			return FN(PW,free)(pw);
+	}
+
+	return pw;
+}
+#endif
+
+#ifndef NO_SUB
+__isl_give PW *FN(PW,sub)(__isl_take PW *pw1, __isl_take PW *pw2)
+{
+	return FN(PW,add)(pw1, FN(PW,neg)(pw2));
+}
+#endif
+
+#ifndef NO_EVAL
+__isl_give isl_val *FN(PW,eval)(__isl_take PW *pw, __isl_take isl_point *pnt)
+{
+	int i;
+	int found = 0;
+	isl_ctx *ctx;
+	isl_space *pnt_dim = NULL;
+	isl_val *v;
+
+	if (!pw || !pnt)
+		goto error;
+	ctx = isl_point_get_ctx(pnt);
+	pnt_dim = isl_point_get_space(pnt);
+	isl_assert(ctx, isl_space_is_domain_internal(pnt_dim, pw->dim),
+		    goto error);
+
+	for (i = 0; i < pw->n; ++i) {
+		found = isl_set_contains_point(pw->p[i].set, pnt);
+		if (found < 0)
+			goto error;
+		if (found)
+			break;
+	}
+	if (found)
+		v = FN(EL,eval)(FN(EL,copy)(pw->p[i].FIELD),
+					    isl_point_copy(pnt));
+	else
+		v = isl_val_zero(ctx);
+	FN(PW,free)(pw);
+	isl_space_free(pnt_dim);
+	isl_point_free(pnt);
+	return v;
+error:
+	FN(PW,free)(pw);
+	isl_space_free(pnt_dim);
+	isl_point_free(pnt);
+	return NULL;
+}
+#endif
+
+/* Return the parameter domain of "pw".
+ */
+__isl_give isl_set *FN(PW,params)(__isl_take PW *pw)
+{
+	return isl_set_params(FN(PW,domain)(pw));
+}
+
+__isl_give isl_set *FN(PW,domain)(__isl_take PW *pw)
+{
+	int i;
+	isl_set *dom;
+
+	if (!pw)
+		return NULL;
+
+	dom = isl_set_empty(FN(PW,get_domain_space)(pw));
+	for (i = 0; i < pw->n; ++i)
+		dom = isl_set_union_disjoint(dom, isl_set_copy(pw->p[i].set));
+
+	FN(PW,free)(pw);
+
+	return dom;
+}
+
+/* Exploit the equalities in the domain of piece "i" of "pw"
+ * to simplify the associated function.
+ * If the domain of piece "i" is empty, then remove it entirely,
+ * replacing it with the final piece.
+ */
+static int FN(PW,exploit_equalities_and_remove_if_empty)(__isl_keep PW *pw,
+	int i)
+{
+	isl_basic_set *aff;
+	int empty = isl_set_plain_is_empty(pw->p[i].set);
+
+	if (empty < 0)
+		return -1;
+	if (empty) {
+		isl_set_free(pw->p[i].set);
+		FN(EL,free)(pw->p[i].FIELD);
+		if (i != pw->n - 1)
+			pw->p[i] = pw->p[pw->n - 1];
+		pw->n--;
+
+		return 0;
+	}
+
+	aff = isl_set_affine_hull(isl_set_copy(pw->p[i].set));
+	pw->p[i].FIELD = FN(EL,substitute_equalities)(pw->p[i].FIELD, aff);
+	if (!pw->p[i].FIELD)
+		return -1;
+
+	return 0;
+}
+
+/* Convert a piecewise expression defined over a parameter domain
+ * into one that is defined over a zero-dimensional set.
+ */
+__isl_give PW *FN(PW,from_range)(__isl_take PW *pw)
+{
+	isl_space *space;
+
+	if (!pw)
+		return NULL;
+	if (!isl_space_is_set(pw->dim))
+		isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
+			"not living in a set space", return FN(PW,free)(pw));
+
+	space = FN(PW,get_space)(pw);
+	space = isl_space_from_range(space);
+	pw = FN(PW,reset_space)(pw, space);
+
+	return pw;
+}
+
+/* Fix the value of the given parameter or domain dimension of "pw"
+ * to be equal to "value".
+ */
+__isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type,
+	unsigned pos, int value)
+{
+	int i;
+
+	if (!pw)
+		return NULL;
+
+	if (type == isl_dim_out)
+		isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
+			"cannot fix output dimension", return FN(PW,free)(pw));
+
+	if (pw->n == 0)
+		return pw;
+
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return FN(PW,free)(pw);
+
+	for (i = pw->n - 1; i >= 0; --i) {
+		pw->p[i].set = isl_set_fix_si(pw->p[i].set, type, pos, value);
+		if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
+			return FN(PW,free)(pw);
+	}
+
+	return pw;
+}
+
+/* Restrict the domain of "pw" by combining each cell
+ * with "set" through a call to "fn", where "fn" may be
+ * isl_set_intersect, isl_set_intersect_params or isl_set_subtract.
+ */
+static __isl_give PW *FN(PW,restrict_domain_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *set,
+	__isl_give isl_set *(*fn)(__isl_take isl_set *set1,
+				    __isl_take isl_set *set2))
+{
+	int i;
+
+	if (!pw || !set)
+		goto error;
+
+	if (pw->n == 0) {
+		isl_set_free(set);
+		return pw;
+	}
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+
+	for (i = pw->n - 1; i >= 0; --i) {
+		pw->p[i].set = fn(pw->p[i].set, isl_set_copy(set));
+		if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
+			goto error;
+	}
+	
+	isl_set_free(set);
+	return pw;
+error:
+	isl_set_free(set);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+static __isl_give PW *FN(PW,intersect_domain_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *set)
+{
+	return FN(PW,restrict_domain_aligned)(pw, set, &isl_set_intersect);
+}
+
+__isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw,
+	__isl_take isl_set *context)
+{
+	return FN(PW,align_params_pw_set_and)(pw, context,
+					&FN(PW,intersect_domain_aligned));
+}
+
+static __isl_give PW *FN(PW,intersect_params_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *set)
+{
+	return FN(PW,restrict_domain_aligned)(pw, set,
+					&isl_set_intersect_params);
+}
+
+/* Intersect the domain of "pw" with the parameter domain "context".
+ */
+__isl_give PW *FN(PW,intersect_params)(__isl_take PW *pw,
+	__isl_take isl_set *context)
+{
+	return FN(PW,align_params_pw_set_and)(pw, context,
+					&FN(PW,intersect_params_aligned));
+}
+
+/* Subtract "domain' from the domain of "pw", assuming their
+ * parameters have been aligned.
+ */
+static __isl_give PW *FN(PW,subtract_domain_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *domain)
+{
+	return FN(PW,restrict_domain_aligned)(pw, domain, &isl_set_subtract);
+}
+
+/* Subtract "domain' from the domain of "pw".
+ */
+__isl_give PW *FN(PW,subtract_domain)(__isl_take PW *pw,
+	__isl_take isl_set *domain)
+{
+	return FN(PW,align_params_pw_set_and)(pw, domain,
+					&FN(PW,subtract_domain_aligned));
+}
+
+/* Compute the gist of "pw" with respect to the domain constraints
+ * of "context" for the case where the domain of the last element
+ * of "pw" is equal to "context".
+ * Call "fn_el" to compute the gist of this element, replace
+ * its domain by the universe and drop all other elements
+ * as their domains are necessarily disjoint from "context".
+ */
+static __isl_give PW *FN(PW,gist_last)(__isl_take PW *pw,
+	__isl_take isl_set *context,
+	__isl_give EL *(*fn_el)(__isl_take EL *el, __isl_take isl_set *set))
+{
+	int i;
+	isl_space *space;
+
+	for (i = 0; i < pw->n - 1; ++i) {
+		isl_set_free(pw->p[i].set);
+		FN(EL,free)(pw->p[i].FIELD);
+	}
+	pw->p[0].FIELD = pw->p[pw->n - 1].FIELD;
+	pw->p[0].set = pw->p[pw->n - 1].set;
+	pw->n = 1;
+
+	space = isl_set_get_space(context);
+	pw->p[0].FIELD = fn_el(pw->p[0].FIELD, context);
+	context = isl_set_universe(space);
+	isl_set_free(pw->p[0].set);
+	pw->p[0].set = context;
+
+	if (!pw->p[0].FIELD || !pw->p[0].set)
+		return FN(PW,free)(pw);
+
+	return pw;
+}
+
+/* Compute the gist of "pw" with respect to the domain constraints
+ * of "context".  Call "fn_el" to compute the gist of the elements
+ * and "fn_dom" to compute the gist of the domains.
+ *
+ * If the piecewise expression is empty or the context is the universe,
+ * then nothing can be simplified.
+ */
+static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *context,
+	__isl_give EL *(*fn_el)(__isl_take EL *el,
+				    __isl_take isl_set *set),
+	__isl_give isl_set *(*fn_dom)(__isl_take isl_set *set,
+				    __isl_take isl_basic_set *bset))
+{
+	int i;
+	int is_universe;
+	isl_bool aligned;
+	isl_basic_set *hull = NULL;
+
+	if (!pw || !context)
+		goto error;
+
+	if (pw->n == 0) {
+		isl_set_free(context);
+		return pw;
+	}
+
+	is_universe = isl_set_plain_is_universe(context);
+	if (is_universe < 0)
+		goto error;
+	if (is_universe) {
+		isl_set_free(context);
+		return pw;
+	}
+
+	aligned = isl_set_space_has_equal_params(context, pw->dim);
+	if (aligned < 0)
+		goto error;
+	if (!aligned) {
+		pw = FN(PW,align_params)(pw, isl_set_get_space(context));
+		context = isl_set_align_params(context, FN(PW,get_space)(pw));
+	}
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+
+	if (pw->n == 1) {
+		int equal;
+
+		equal = isl_set_plain_is_equal(pw->p[0].set, context);
+		if (equal < 0)
+			goto error;
+		if (equal)
+			return FN(PW,gist_last)(pw, context, fn_el);
+	}
+
+	context = isl_set_compute_divs(context);
+	hull = isl_set_simple_hull(isl_set_copy(context));
+
+	for (i = pw->n - 1; i >= 0; --i) {
+		isl_set *set_i;
+		int empty;
+
+		if (i == pw->n - 1) {
+			int equal;
+			equal = isl_set_plain_is_equal(pw->p[i].set, context);
+			if (equal < 0)
+				goto error;
+			if (equal) {
+				isl_basic_set_free(hull);
+				return FN(PW,gist_last)(pw, context, fn_el);
+			}
+		}
+		set_i = isl_set_intersect(isl_set_copy(pw->p[i].set),
+						 isl_set_copy(context));
+		empty = isl_set_plain_is_empty(set_i);
+		pw->p[i].FIELD = fn_el(pw->p[i].FIELD, set_i);
+		pw->p[i].set = fn_dom(pw->p[i].set, isl_basic_set_copy(hull));
+		if (empty < 0 || !pw->p[i].FIELD || !pw->p[i].set)
+			goto error;
+		if (empty) {
+			isl_set_free(pw->p[i].set);
+			FN(EL,free)(pw->p[i].FIELD);
+			if (i != pw->n - 1)
+				pw->p[i] = pw->p[pw->n - 1];
+			pw->n--;
+		}
+	}
+
+	isl_basic_set_free(hull);
+	isl_set_free(context);
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	isl_basic_set_free(hull);
+	isl_set_free(context);
+	return NULL;
+}
+
+static __isl_give PW *FN(PW,gist_domain_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *set)
+{
+	return FN(PW,gist_aligned)(pw, set, &FN(EL,gist),
+					&isl_set_gist_basic_set);
+}
+
+__isl_give PW *FN(PW,gist)(__isl_take PW *pw, __isl_take isl_set *context)
+{
+	return FN(PW,align_params_pw_set_and)(pw, context,
+						&FN(PW,gist_domain_aligned));
+}
+
+static __isl_give PW *FN(PW,gist_params_aligned)(__isl_take PW *pw,
+	__isl_take isl_set *set)
+{
+	return FN(PW,gist_aligned)(pw, set, &FN(EL,gist_params),
+					&isl_set_gist_params_basic_set);
+}
+
+__isl_give PW *FN(PW,gist_params)(__isl_take PW *pw,
+	__isl_take isl_set *context)
+{
+	return FN(PW,align_params_pw_set_and)(pw, context,
+						&FN(PW,gist_params_aligned));
+}
+
+/* Return -1 if the piece "p1" should be sorted before "p2"
+ * and 1 if it should be sorted after "p2".
+ * Return 0 if they do not need to be sorted in a specific order.
+ *
+ * The two pieces are compared on the basis of their function value expressions.
+ */
+static int FN(PW,sort_field_cmp)(const void *p1, const void *p2, void *arg)
+{
+	struct FN(PW,piece) const *pc1 = p1;
+	struct FN(PW,piece) const *pc2 = p2;
+
+	return FN(EL,plain_cmp)(pc1->FIELD, pc2->FIELD);
+}
+
+/* Sort the pieces of "pw" according to their function value
+ * expressions and then combine pairs of adjacent pieces with
+ * the same such expression.
+ *
+ * The sorting is performed in place because it does not
+ * change the meaning of "pw", but care needs to be
+ * taken not to change any possible other copies of "pw"
+ * in case anything goes wrong.
+ */
+__isl_give PW *FN(PW,sort)(__isl_take PW *pw)
+{
+	int i, j;
+	isl_set *set;
+
+	if (!pw)
+		return NULL;
+	if (pw->n <= 1)
+		return pw;
+	if (isl_sort(pw->p, pw->n, sizeof(pw->p[0]),
+		    &FN(PW,sort_field_cmp), NULL) < 0)
+		return FN(PW,free)(pw);
+	for (i = pw->n - 1; i >= 1; --i) {
+		if (!FN(EL,plain_is_equal)(pw->p[i - 1].FIELD, pw->p[i].FIELD))
+			continue;
+		set = isl_set_union(isl_set_copy(pw->p[i - 1].set),
+				    isl_set_copy(pw->p[i].set));
+		if (!set)
+			return FN(PW,free)(pw);
+		isl_set_free(pw->p[i].set);
+		FN(EL,free)(pw->p[i].FIELD);
+		isl_set_free(pw->p[i - 1].set);
+		pw->p[i - 1].set = set;
+		for (j = i + 1; j < pw->n; ++j)
+			pw->p[j - 1] = pw->p[j];
+		pw->n--;
+	}
+
+	return pw;
+}
+
+/* Coalesce the domains of "pw".
+ *
+ * Prior to the actual coalescing, first sort the pieces such that
+ * pieces with the same function value expression are combined
+ * into a single piece, the combined domain of which can then
+ * be coalesced.
+ */
+__isl_give PW *FN(PW,coalesce)(__isl_take PW *pw)
+{
+	int i;
+
+	pw = FN(PW,sort)(pw);
+	if (!pw)
+		return NULL;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_coalesce(pw->p[i].set);
+		if (!pw->p[i].set)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+isl_ctx *FN(PW,get_ctx)(__isl_keep PW *pw)
+{
+	return pw ? isl_space_get_ctx(pw->dim) : NULL;
+}
+
+#ifndef NO_INVOLVES_DIMS
+isl_bool FN(PW,involves_dims)(__isl_keep PW *pw, enum isl_dim_type type,
+	unsigned first, unsigned n)
+{
+	int i;
+	enum isl_dim_type set_type;
+
+	if (!pw)
+		return isl_bool_error;
+	if (pw->n == 0 || n == 0)
+		return isl_bool_false;
+
+	set_type = type == isl_dim_in ? isl_dim_set : type;
+
+	for (i = 0; i < pw->n; ++i) {
+		isl_bool involves = FN(EL,involves_dims)(pw->p[i].FIELD,
+							type, first, n);
+		if (involves < 0 || involves)
+			return involves;
+		involves = isl_set_involves_dims(pw->p[i].set,
+							set_type, first, n);
+		if (involves < 0 || involves)
+			return involves;
+	}
+	return isl_bool_false;
+}
+#endif
+
+__isl_give PW *FN(PW,set_dim_name)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	int i;
+	enum isl_dim_type set_type;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+
+	set_type = type == isl_dim_in ? isl_dim_set : type;
+
+	pw->dim = isl_space_set_dim_name(pw->dim, type, pos, s);
+	if (!pw->dim)
+		goto error;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_set_dim_name(pw->p[i].set,
+							set_type, pos, s);
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,set_dim_name)(pw->p[i].FIELD, type, pos, s);
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+#ifndef NO_DROP_DIMS
+__isl_give PW *FN(PW,drop_dims)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	enum isl_dim_type set_type;
+
+	if (!pw)
+		return NULL;
+	if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
+		return pw;
+
+	set_type = type == isl_dim_in ? isl_dim_set : type;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+	pw->dim = isl_space_drop_dims(pw->dim, type, first, n);
+	if (!pw->dim)
+		goto error;
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n);
+		if (!pw->p[i].FIELD)
+			goto error;
+		if (type == isl_dim_out)
+			continue;
+		pw->p[i].set = isl_set_drop(pw->p[i].set, set_type, first, n);
+		if (!pw->p[i].set)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+/* This function is very similar to drop_dims.
+ * The only difference is that the cells may still involve
+ * the specified dimensions.  They are removed using
+ * isl_set_project_out instead of isl_set_drop.
+ */
+__isl_give PW *FN(PW,project_out)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+	enum isl_dim_type set_type;
+
+	if (!pw)
+		return NULL;
+	if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
+		return pw;
+
+	set_type = type == isl_dim_in ? isl_dim_set : type;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+	pw->dim = isl_space_drop_dims(pw->dim, type, first, n);
+	if (!pw->dim)
+		goto error;
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_project_out(pw->p[i].set,
+							set_type, first, n);
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n);
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+/* Project the domain of pw onto its parameter space.
+ */
+__isl_give PW *FN(PW,project_domain_on_params)(__isl_take PW *pw)
+{
+	isl_space *space;
+	unsigned n;
+
+	n = FN(PW,dim)(pw, isl_dim_in);
+	pw = FN(PW,project_out)(pw, isl_dim_in, 0, n);
+	space = FN(PW,get_domain_space)(pw);
+	space = isl_space_params(space);
+	pw = FN(PW,reset_domain_space)(pw, space);
+	return pw;
+}
+#endif
+
+#ifndef NO_INSERT_DIMS
+__isl_give PW *FN(PW,insert_dims)(__isl_take PW *pw, enum isl_dim_type type,
+	unsigned first, unsigned n)
+{
+	int i;
+	enum isl_dim_type set_type;
+
+	if (!pw)
+		return NULL;
+	if (n == 0 && !isl_space_is_named_or_nested(pw->dim, type))
+		return pw;
+
+	set_type = type == isl_dim_in ? isl_dim_set : type;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+
+	pw->dim = isl_space_insert_dims(pw->dim, type, first, n);
+	if (!pw->dim)
+		goto error;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_insert_dims(pw->p[i].set,
+							    set_type, first, n);
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,insert_dims)(pw->p[i].FIELD,
+								type, first, n);
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+#endif
+
+__isl_give PW *FN(PW,fix_dim)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned pos, isl_int v)
+{
+	int i;
+
+	if (!pw)
+		return NULL;
+
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_fix(pw->p[i].set, type, pos, v);
+		if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
+			return FN(PW,free)(pw);
+	}
+
+	return pw;
+}
+
+/* Fix the value of the variable at position "pos" of type "type" of "pw"
+ * to be equal to "v".
+ */
+__isl_give PW *FN(PW,fix_val)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
+{
+	if (!v)
+		return FN(PW,free)(pw);
+	if (!isl_val_is_int(v))
+		isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
+			"expecting integer value", goto error);
+
+	pw = FN(PW,fix_dim)(pw, type, pos, v->n);
+	isl_val_free(v);
+
+	return pw;
+error:
+	isl_val_free(v);
+	return FN(PW,free)(pw);
+}
+
+unsigned FN(PW,dim)(__isl_keep PW *pw, enum isl_dim_type type)
+{
+	return pw ? isl_space_dim(pw->dim, type) : 0;
+}
+
+__isl_give PW *FN(PW,split_dims)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!pw)
+		return NULL;
+	if (n == 0)
+		return pw;
+
+	if (type == isl_dim_in)
+		type = isl_dim_set;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+	if (!pw->dim)
+		goto error;
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_split_dims(pw->p[i].set, type, first, n);
+		if (!pw->p[i].set)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+#ifndef NO_OPT
+/* Compute the maximal value attained by the piecewise quasipolynomial
+ * on its domain or zero if the domain is empty.
+ * In the worst case, the domain is scanned completely,
+ * so the domain is assumed to be bounded.
+ */
+__isl_give isl_val *FN(PW,opt)(__isl_take PW *pw, int max)
+{
+	int i;
+	isl_val *opt;
+
+	if (!pw)
+		return NULL;
+
+	if (pw->n == 0) {
+		opt = isl_val_zero(FN(PW,get_ctx)(pw));
+		FN(PW,free)(pw);
+		return opt;
+	}
+
+	opt = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[0].FIELD),
+					isl_set_copy(pw->p[0].set), max);
+	for (i = 1; i < pw->n; ++i) {
+		isl_val *opt_i;
+		opt_i = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[i].FIELD),
+						isl_set_copy(pw->p[i].set), max);
+		if (max)
+			opt = isl_val_max(opt, opt_i);
+		else
+			opt = isl_val_min(opt, opt_i);
+	}
+
+	FN(PW,free)(pw);
+	return opt;
+}
+
+__isl_give isl_val *FN(PW,max)(__isl_take PW *pw)
+{
+	return FN(PW,opt)(pw, 1);
+}
+
+__isl_give isl_val *FN(PW,min)(__isl_take PW *pw)
+{
+	return FN(PW,opt)(pw, 0);
+}
+#endif
+
+__isl_give isl_space *FN(PW,get_space)(__isl_keep PW *pw)
+{
+	return pw ? isl_space_copy(pw->dim) : NULL;
+}
+
+__isl_give isl_space *FN(PW,get_domain_space)(__isl_keep PW *pw)
+{
+	return pw ? isl_space_domain(isl_space_copy(pw->dim)) : NULL;
+}
+
+/* Return the position of the dimension of the given type and name
+ * in "pw".
+ * Return -1 if no such dimension can be found.
+ */
+int FN(PW,find_dim_by_name)(__isl_keep PW *pw,
+	enum isl_dim_type type, const char *name)
+{
+	if (!pw)
+		return -1;
+	return isl_space_find_dim_by_name(pw->dim, type, name);
+}
+
+#ifndef NO_RESET_DIM
+/* Reset the space of "pw".  Since we don't know if the elements
+ * represent the spaces themselves or their domains, we pass along
+ * both when we call their reset_space_and_domain.
+ */
+static __isl_give PW *FN(PW,reset_space_and_domain)(__isl_take PW *pw,
+	__isl_take isl_space *space, __isl_take isl_space *domain)
+{
+	int i;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw || !space || !domain)
+		goto error;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_reset_space(pw->p[i].set,
+						 isl_space_copy(domain));
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,reset_space_and_domain)(pw->p[i].FIELD,
+			      isl_space_copy(space), isl_space_copy(domain));
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	isl_space_free(domain);
+
+	isl_space_free(pw->dim);
+	pw->dim = space;
+
+	return pw;
+error:
+	isl_space_free(domain);
+	isl_space_free(space);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+__isl_give PW *FN(PW,reset_domain_space)(__isl_take PW *pw,
+	__isl_take isl_space *domain)
+{
+	isl_space *space;
+
+	space = isl_space_extend_domain_with_range(isl_space_copy(domain),
+						   FN(PW,get_space)(pw));
+	return FN(PW,reset_space_and_domain)(pw, space, domain);
+}
+
+__isl_give PW *FN(PW,reset_space)(__isl_take PW *pw, __isl_take isl_space *dim)
+{
+	isl_space *domain;
+
+	domain = isl_space_domain(isl_space_copy(dim));
+	return FN(PW,reset_space_and_domain)(pw, dim, domain);
+}
+
+__isl_give PW *FN(PW,set_tuple_id)(__isl_take PW *pw, enum isl_dim_type type,
+	__isl_take isl_id *id)
+{
+	isl_space *space;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+
+	space = FN(PW,get_space)(pw);
+	space = isl_space_set_tuple_id(space, type, id);
+
+	return FN(PW,reset_space)(pw, space);
+error:
+	isl_id_free(id);
+	return FN(PW,free)(pw);
+}
+
+/* Drop the id on the specified tuple.
+ */
+__isl_give PW *FN(PW,reset_tuple_id)(__isl_take PW *pw, enum isl_dim_type type)
+{
+	isl_space *space;
+
+	if (!pw)
+		return NULL;
+	if (!FN(PW,has_tuple_id)(pw, type))
+		return pw;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+
+	space = FN(PW,get_space)(pw);
+	space = isl_space_reset_tuple_id(space, type);
+
+	return FN(PW,reset_space)(pw, space);
+}
+
+__isl_give PW *FN(PW,set_dim_id)(__isl_take PW *pw,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+	pw->dim = isl_space_set_dim_id(pw->dim, type, pos, id);
+	return FN(PW,reset_space)(pw, isl_space_copy(pw->dim));
+error:
+	isl_id_free(id);
+	return FN(PW,free)(pw);
+}
+#endif
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the space of "pw".
+ */
+__isl_give PW *FN(PW,reset_user)(__isl_take PW *pw)
+{
+	isl_space *space;
+
+	space = FN(PW,get_space)(pw);
+	space = isl_space_reset_user(space);
+
+	return FN(PW,reset_space)(pw, space);
+}
+
+isl_bool FN(PW,has_equal_space)(__isl_keep PW *pw1, __isl_keep PW *pw2)
+{
+	if (!pw1 || !pw2)
+		return isl_bool_error;
+
+	return isl_space_is_equal(pw1->dim, pw2->dim);
+}
+
+#ifndef NO_MORPH
+__isl_give PW *FN(PW,morph_domain)(__isl_take PW *pw,
+	__isl_take isl_morph *morph)
+{
+	int i;
+	isl_ctx *ctx;
+
+	if (!pw || !morph)
+		goto error;
+
+	ctx = isl_space_get_ctx(pw->dim);
+	isl_assert(ctx, isl_space_is_domain_internal(morph->dom->dim, pw->dim),
+		goto error);
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+	pw->dim = isl_space_extend_domain_with_range(
+			isl_space_copy(morph->ran->dim), pw->dim);
+	if (!pw->dim)
+		goto error;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_morph_set(isl_morph_copy(morph), pw->p[i].set);
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,morph_domain)(pw->p[i].FIELD,
+						isl_morph_copy(morph));
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	isl_morph_free(morph);
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	isl_morph_free(morph);
+	return NULL;
+}
+#endif
+
+int FN(PW,n_piece)(__isl_keep PW *pw)
+{
+	return pw ? pw->n : 0;
+}
+
+isl_stat FN(PW,foreach_piece)(__isl_keep PW *pw,
+	isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el, void *user),
+	void *user)
+{
+	int i;
+
+	if (!pw)
+		return isl_stat_error;
+
+	for (i = 0; i < pw->n; ++i)
+		if (fn(isl_set_copy(pw->p[i].set),
+				FN(EL,copy)(pw->p[i].FIELD), user) < 0)
+			return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+#ifndef NO_LIFT
+static isl_bool any_divs(__isl_keep isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return isl_bool_error;
+
+	for (i = 0; i < set->n; ++i)
+		if (set->p[i]->n_div > 0)
+			return isl_bool_true;
+
+	return isl_bool_false;
+}
+
+static isl_stat foreach_lifted_subset(__isl_take isl_set *set,
+	__isl_take EL *el,
+	isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el,
+		void *user), void *user)
+{
+	int i;
+
+	if (!set || !el)
+		goto error;
+
+	for (i = 0; i < set->n; ++i) {
+		isl_set *lift;
+		EL *copy;
+
+		lift = isl_set_from_basic_set(isl_basic_set_copy(set->p[i]));
+		lift = isl_set_lift(lift);
+
+		copy = FN(EL,copy)(el);
+		copy = FN(EL,lift)(copy, isl_set_get_space(lift));
+
+		if (fn(lift, copy, user) < 0)
+			goto error;
+	}
+
+	isl_set_free(set);
+	FN(EL,free)(el);
+
+	return isl_stat_ok;
+error:
+	isl_set_free(set);
+	FN(EL,free)(el);
+	return isl_stat_error;
+}
+
+isl_stat FN(PW,foreach_lifted_piece)(__isl_keep PW *pw,
+	isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el,
+		    void *user), void *user)
+{
+	int i;
+
+	if (!pw)
+		return isl_stat_error;
+
+	for (i = 0; i < pw->n; ++i) {
+		isl_bool any;
+		isl_set *set;
+		EL *el;
+
+		any = any_divs(pw->p[i].set);
+		if (any < 0)
+			return isl_stat_error;
+		set = isl_set_copy(pw->p[i].set);
+		el = FN(EL,copy)(pw->p[i].FIELD);
+		if (!any) {
+			if (fn(set, el, user) < 0)
+				return isl_stat_error;
+			continue;
+		}
+		if (foreach_lifted_subset(set, el, fn, user) < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+#endif
+
+#ifndef NO_MOVE_DIMS
+__isl_give PW *FN(PW,move_dims)(__isl_take PW *pw,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	int i;
+
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+
+	pw->dim = isl_space_move_dims(pw->dim, dst_type, dst_pos, src_type, src_pos, n);
+	if (!pw->dim)
+		goto error;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].FIELD = FN(EL,move_dims)(pw->p[i].FIELD,
+					dst_type, dst_pos, src_type, src_pos, n);
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	if (dst_type == isl_dim_in)
+		dst_type = isl_dim_set;
+	if (src_type == isl_dim_in)
+		src_type = isl_dim_set;
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_move_dims(pw->p[i].set,
+						dst_type, dst_pos,
+						src_type, src_pos, n);
+		if (!pw->p[i].set)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+#endif
+
+__isl_give PW *FN(PW,mul_isl_int)(__isl_take PW *pw, isl_int v)
+{
+	int i;
+
+	if (isl_int_is_one(v))
+		return pw;
+	if (pw && DEFAULT_IS_ZERO && isl_int_is_zero(v)) {
+		PW *zero;
+		isl_space *dim = FN(PW,get_space)(pw);
+#ifdef HAS_TYPE
+		zero = FN(PW,ZERO)(dim, pw->type);
+#else
+		zero = FN(PW,ZERO)(dim);
+#endif
+		FN(PW,free)(pw);
+		return zero;
+	}
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		return NULL;
+	if (pw->n == 0)
+		return pw;
+
+#ifdef HAS_TYPE
+	if (isl_int_is_neg(v))
+		pw->type = isl_fold_type_negate(pw->type);
+#endif
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].FIELD = FN(EL,scale)(pw->p[i].FIELD, v);
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	return pw;
+error:
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+/* Multiply the pieces of "pw" by "v" and return the result.
+ */
+__isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v)
+{
+	int i;
+
+	if (!pw || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return pw;
+	}
+	if (pw && DEFAULT_IS_ZERO && isl_val_is_zero(v)) {
+		PW *zero;
+		isl_space *space = FN(PW,get_space)(pw);
+#ifdef HAS_TYPE
+		zero = FN(PW,ZERO)(space, pw->type);
+#else
+		zero = FN(PW,ZERO)(space);
+#endif
+		FN(PW,free)(pw);
+		isl_val_free(v);
+		return zero;
+	}
+	if (pw->n == 0) {
+		isl_val_free(v);
+		return pw;
+	}
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+
+#ifdef HAS_TYPE
+	if (isl_val_is_neg(v))
+		pw->type = isl_fold_type_negate(pw->type);
+#endif
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].FIELD = FN(EL,scale_val)(pw->p[i].FIELD,
+						    isl_val_copy(v));
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	isl_val_free(v);
+	return pw;
+error:
+	isl_val_free(v);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+/* Divide the pieces of "pw" by "v" and return the result.
+ */
+__isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v)
+{
+	int i;
+
+	if (!pw || !v)
+		goto error;
+
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return pw;
+	}
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational factor", goto error);
+	if (isl_val_is_zero(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"cannot scale down by zero", goto error);
+
+	if (pw->n == 0) {
+		isl_val_free(v);
+		return pw;
+	}
+	pw = FN(PW,cow)(pw);
+	if (!pw)
+		goto error;
+
+#ifdef HAS_TYPE
+	if (isl_val_is_neg(v))
+		pw->type = isl_fold_type_negate(pw->type);
+#endif
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].FIELD = FN(EL,scale_down_val)(pw->p[i].FIELD,
+						    isl_val_copy(v));
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	isl_val_free(v);
+	return pw;
+error:
+	isl_val_free(v);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+__isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v)
+{
+	return FN(PW,mul_isl_int)(pw, v);
+}
+
+/* Apply some normalization to "pw".
+ * In particular, sort the pieces according to their function value
+ * expressions, combining pairs of adjacent pieces with
+ * the same such expression, and then normalize the domains of the pieces.
+ *
+ * We normalize in place, but if anything goes wrong we need
+ * to return NULL, so we need to make sure we don't change the
+ * meaning of any possible other copies of "pw".
+ */
+__isl_give PW *FN(PW,normalize)(__isl_take PW *pw)
+{
+	int i;
+	isl_set *set;
+
+	pw = FN(PW,sort)(pw);
+	if (!pw)
+		return NULL;
+	for (i = 0; i < pw->n; ++i) {
+		set = isl_set_normalize(isl_set_copy(pw->p[i].set));
+		if (!set)
+			return FN(PW,free)(pw);
+		isl_set_free(pw->p[i].set);
+		pw->p[i].set = set;
+	}
+
+	return pw;
+}
+
+/* Is pw1 obviously equal to pw2?
+ * That is, do they have obviously identical cells and obviously identical
+ * elements on each cell?
+ *
+ * If "pw1" or "pw2" contain any NaNs, then they are considered
+ * not to be the same.  A NaN is not equal to anything, not even
+ * to another NaN.
+ */
+isl_bool FN(PW,plain_is_equal)(__isl_keep PW *pw1, __isl_keep PW *pw2)
+{
+	int i;
+	isl_bool equal, has_nan;
+
+	if (!pw1 || !pw2)
+		return isl_bool_error;
+
+	has_nan = FN(PW,involves_nan)(pw1);
+	if (has_nan >= 0 && !has_nan)
+		has_nan = FN(PW,involves_nan)(pw2);
+	if (has_nan < 0 || has_nan)
+		return isl_bool_not(has_nan);
+
+	if (pw1 == pw2)
+		return isl_bool_true;
+	if (!isl_space_is_equal(pw1->dim, pw2->dim))
+		return isl_bool_false;
+
+	pw1 = FN(PW,copy)(pw1);
+	pw2 = FN(PW,copy)(pw2);
+	pw1 = FN(PW,normalize)(pw1);
+	pw2 = FN(PW,normalize)(pw2);
+	if (!pw1 || !pw2)
+		goto error;
+
+	equal = pw1->n == pw2->n;
+	for (i = 0; equal && i < pw1->n; ++i) {
+		equal = isl_set_plain_is_equal(pw1->p[i].set, pw2->p[i].set);
+		if (equal < 0)
+			goto error;
+		if (!equal)
+			break;
+		equal = FN(EL,plain_is_equal)(pw1->p[i].FIELD, pw2->p[i].FIELD);
+		if (equal < 0)
+			goto error;
+	}
+
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return equal;
+error:
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return isl_bool_error;
+}
+
+/* Does "pw" involve any NaNs?
+ */
+isl_bool FN(PW,involves_nan)(__isl_keep PW *pw)
+{
+	int i;
+
+	if (!pw)
+		return isl_bool_error;
+	if (pw->n == 0)
+		return isl_bool_false;
+
+	for (i = 0; i < pw->n; ++i) {
+		isl_bool has_nan = FN(EL,involves_nan)(pw->p[i].FIELD);
+		if (has_nan < 0 || has_nan)
+			return has_nan;
+	}
+
+	return isl_bool_false;
+}
+
+#ifndef NO_PULLBACK
+static __isl_give PW *FN(PW,align_params_pw_multi_aff_and)(__isl_take PW *pw,
+	__isl_take isl_multi_aff *ma,
+	__isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_multi_aff *ma))
+{
+	isl_ctx *ctx;
+	isl_bool equal_params;
+	isl_space *ma_space;
+
+	ma_space = isl_multi_aff_get_space(ma);
+	if (!pw || !ma || !ma_space)
+		goto error;
+	equal_params = isl_space_has_equal_params(pw->dim, ma_space);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params) {
+		isl_space_free(ma_space);
+		return fn(pw, ma);
+	}
+	ctx = FN(PW,get_ctx)(pw);
+	if (!isl_space_has_named_params(pw->dim) ||
+	    !isl_space_has_named_params(ma_space))
+		isl_die(ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	pw = FN(PW,align_params)(pw, ma_space);
+	ma = isl_multi_aff_align_params(ma, FN(PW,get_space)(pw));
+	return fn(pw, ma);
+error:
+	isl_space_free(ma_space);
+	FN(PW,free)(pw);
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+static __isl_give PW *FN(PW,align_params_pw_pw_multi_aff_and)(__isl_take PW *pw,
+	__isl_take isl_pw_multi_aff *pma,
+	__isl_give PW *(*fn)(__isl_take PW *pw,
+		__isl_take isl_pw_multi_aff *ma))
+{
+	isl_ctx *ctx;
+	isl_bool equal_params;
+	isl_space *pma_space;
+
+	pma_space = isl_pw_multi_aff_get_space(pma);
+	if (!pw || !pma || !pma_space)
+		goto error;
+	equal_params = isl_space_has_equal_params(pw->dim, pma_space);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params) {
+		isl_space_free(pma_space);
+		return fn(pw, pma);
+	}
+	ctx = FN(PW,get_ctx)(pw);
+	if (!isl_space_has_named_params(pw->dim) ||
+	    !isl_space_has_named_params(pma_space))
+		isl_die(ctx, isl_error_invalid,
+			"unaligned unnamed parameters", goto error);
+	pw = FN(PW,align_params)(pw, pma_space);
+	pma = isl_pw_multi_aff_align_params(pma, FN(PW,get_space)(pw));
+	return fn(pw, pma);
+error:
+	isl_space_free(pma_space);
+	FN(PW,free)(pw);
+	isl_pw_multi_aff_free(pma);
+	return NULL;
+}
+
+/* Compute the pullback of "pw" by the function represented by "ma".
+ * In other words, plug in "ma" in "pw".
+ */
+static __isl_give PW *FN(PW,pullback_multi_aff_aligned)(__isl_take PW *pw,
+	__isl_take isl_multi_aff *ma)
+{
+	int i;
+	isl_space *space = NULL;
+
+	ma = isl_multi_aff_align_divs(ma);
+	pw = FN(PW,cow)(pw);
+	if (!pw || !ma)
+		goto error;
+
+	space = isl_space_join(isl_multi_aff_get_space(ma),
+				FN(PW,get_space)(pw));
+
+	for (i = 0; i < pw->n; ++i) {
+		pw->p[i].set = isl_set_preimage_multi_aff(pw->p[i].set,
+						    isl_multi_aff_copy(ma));
+		if (!pw->p[i].set)
+			goto error;
+		pw->p[i].FIELD = FN(EL,pullback_multi_aff)(pw->p[i].FIELD,
+						    isl_multi_aff_copy(ma));
+		if (!pw->p[i].FIELD)
+			goto error;
+	}
+
+	pw = FN(PW,reset_space)(pw, space);
+	isl_multi_aff_free(ma);
+	return pw;
+error:
+	isl_space_free(space);
+	isl_multi_aff_free(ma);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+__isl_give PW *FN(PW,pullback_multi_aff)(__isl_take PW *pw,
+	__isl_take isl_multi_aff *ma)
+{
+	return FN(PW,align_params_pw_multi_aff_and)(pw, ma,
+					&FN(PW,pullback_multi_aff_aligned));
+}
+
+/* Compute the pullback of "pw" by the function represented by "pma".
+ * In other words, plug in "pma" in "pw".
+ */
+static __isl_give PW *FN(PW,pullback_pw_multi_aff_aligned)(__isl_take PW *pw,
+	__isl_take isl_pw_multi_aff *pma)
+{
+	int i;
+	PW *res;
+
+	if (!pma)
+		goto error;
+
+	if (pma->n == 0) {
+		isl_space *space;
+		space = isl_space_join(isl_pw_multi_aff_get_space(pma),
+					FN(PW,get_space)(pw));
+		isl_pw_multi_aff_free(pma);
+		res = FN(PW,empty)(space);
+		FN(PW,free)(pw);
+		return res;
+	}
+
+	res = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
+					isl_multi_aff_copy(pma->p[0].maff));
+	res = FN(PW,intersect_domain)(res, isl_set_copy(pma->p[0].set));
+
+	for (i = 1; i < pma->n; ++i) {
+		PW *res_i;
+
+		res_i = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
+					isl_multi_aff_copy(pma->p[i].maff));
+		res_i = FN(PW,intersect_domain)(res_i,
+					isl_set_copy(pma->p[i].set));
+		res = FN(PW,add_disjoint)(res, res_i);
+	}
+
+	isl_pw_multi_aff_free(pma);
+	FN(PW,free)(pw);
+	return res;
+error:
+	isl_pw_multi_aff_free(pma);
+	FN(PW,free)(pw);
+	return NULL;
+}
+
+__isl_give PW *FN(PW,pullback_pw_multi_aff)(__isl_take PW *pw,
+	__isl_take isl_pw_multi_aff *pma)
+{
+	return FN(PW,align_params_pw_pw_multi_aff_and)(pw, pma,
+					&FN(PW,pullback_pw_multi_aff_aligned));
+}
+#endif
diff --git a/final/lib/External/isl/isl_pw_union_opt.c b/final/lib/External/isl/isl_pw_union_opt.c
new file mode 100644
index 0000000..c10126a
--- /dev/null
+++ b/final/lib/External/isl/isl_pw_union_opt.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2011      INRIA Saclay
+ * Copyright 2012      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_pw_macro.h>
+
+/* Given a function "cmp" that returns the set of elements where
+ * "el1" is "better" than "el2", return this set.
+ */
+static __isl_give isl_set *FN(PW,better)(__isl_keep EL *el1, __isl_keep EL *el2,
+	__isl_give isl_set *(*cmp)(__isl_take EL *el1, __isl_take EL *el2))
+{
+	return cmp(FN(EL,copy)(el1), FN(EL,copy)(el2));
+}
+
+/* Return a list containing the domains of the pieces of "pw".
+ */
+static __isl_give isl_set_list *FN(PW,extract_domains)(__isl_keep PW *pw)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_set_list *list;
+
+	if (!pw)
+		return NULL;
+	ctx = FN(PW,get_ctx)(pw);
+	list = isl_set_list_alloc(ctx, pw->n);
+	for (i = 0; i < pw->n; ++i)
+		list = isl_set_list_add(list, isl_set_copy(pw->p[i].set));
+
+	return list;
+}
+
+/* Given sets B ("set"), C ("better") and A' ("out"), return
+ *
+ *	(B \cap C) \cup ((B \setminus C) \setminus A')
+ */
+static __isl_give isl_set *FN(PW,better_or_out)(__isl_take isl_set *set,
+	__isl_take isl_set *better, __isl_take isl_set *out)
+{
+	isl_set *set_better, *set_out;
+
+	set_better = isl_set_intersect(isl_set_copy(set), isl_set_copy(better));
+	set_out = isl_set_subtract(isl_set_subtract(set, better), out);
+
+	return isl_set_union(set_better, set_out);
+}
+
+/* Given sets A ("set"), C ("better") and B' ("out"), return
+ *
+ *	(A \setminus C) \cup ((A \cap C) \setminus B')
+ */
+static __isl_give isl_set *FN(PW,worse_or_out)(__isl_take isl_set *set,
+	__isl_take isl_set *better, __isl_take isl_set *out)
+{
+	isl_set *set_worse, *set_out;
+
+	set_worse = isl_set_subtract(isl_set_copy(set), isl_set_copy(better));
+	set_out = isl_set_subtract(isl_set_intersect(set, better), out);
+
+	return isl_set_union(set_worse, set_out);
+}
+
+/* Given two piecewise expressions "pw1" and "pw2", replace their domains
+ * by the sets in "list1" and "list2" and combine the results into
+ * a single piecewise expression.
+ * The pieces of "pw1" and "pw2" are assumed to have been sorted
+ * according to the function value expressions.
+ * The pieces of the result are also sorted in this way.
+ *
+ * Run through the pieces of "pw1" and "pw2" in order until they
+ * have both been exhausted, picking the piece from "pw1" or "pw2"
+ * depending on which should come first, together with the corresponding
+ * domain from "list1" or "list2".  In cases where the next pieces
+ * in both "pw1" and "pw2" have the same function value expression,
+ * construct only a single piece in the result with as domain
+ * the union of the domains in "list1" and "list2".
+ */
+static __isl_give PW *FN(PW,merge)(__isl_take PW *pw1, __isl_take PW *pw2,
+	__isl_take isl_set_list *list1, __isl_take isl_set_list *list2)
+{
+	int i, j;
+	PW *res;
+
+	if (!pw1 || !pw2)
+		goto error;
+
+	res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), pw1->n + pw2->n);
+
+	i = 0; j = 0;
+	while (i < pw1->n || j < pw2->n) {
+		int cmp;
+		isl_set *set;
+		EL *el;
+
+		if (i < pw1->n && j < pw2->n)
+			cmp = FN(EL,plain_cmp)(pw1->p[i].FIELD,
+						pw2->p[j].FIELD);
+		else
+			cmp = i < pw1->n ? -1 : 1;
+
+		if (cmp < 0) {
+			set = isl_set_list_get_set(list1, i);
+			el = FN(EL,copy)(pw1->p[i].FIELD);
+			++i;
+		} else if (cmp > 0) {
+			set = isl_set_list_get_set(list2, j);
+			el = FN(EL,copy)(pw2->p[j].FIELD);
+			++j;
+		} else {
+			set = isl_set_union(isl_set_list_get_set(list1, i),
+					    isl_set_list_get_set(list2, j));
+			el = FN(EL,copy)(pw1->p[i].FIELD);
+			++i;
+			++j;
+		}
+		res = FN(PW,add_piece)(res, set, el);
+	}
+
+	isl_set_list_free(list1);
+	isl_set_list_free(list2);
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return res;
+error:
+	isl_set_list_free(list1);
+	isl_set_list_free(list2);
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	return NULL;
+}
+
+/* Given a function "cmp" that returns the set of elements where
+ * "el1" is "better" than "el2", return a piecewise
+ * expression defined on the union of the definition domains
+ * of "pw1" and "pw2" that maps to the "best" of "pw1" and
+ * "pw2" on each cell.  If only one of the two input functions
+ * is defined on a given cell, then it is considered the best.
+ *
+ * Run through all pairs of pieces in "pw1" and "pw2".
+ * If the domains of these pieces intersect, then the intersection
+ * needs to be distributed over the two pieces based on "cmp".
+ * Let C be the set where the piece from "pw2" is better (according to "cmp")
+ * than the piece from "pw1".  Let A be the domain of the piece from "pw1" and
+ * B the domain of the piece from "pw2".
+ *
+ * The elements in C need to be removed from A, except for those parts
+ * that lie outside of B.  That is,
+ *
+ *	A <- (A \setminus C) \cup ((A \cap C) \setminus B')
+ *
+ * Conversely, the elements in B need to be restricted to C, except
+ * for those parts that lie outside of A.  That is
+ *
+ *	B <- (B \cap C) \cup ((B \setminus C) \setminus A')
+ *
+ * Since all pairs of pieces are considered, the domains are updated
+ * several times.  A and B refer to these updated domains
+ * (kept track of in "list1" and "list2"), while A' and B' refer
+ * to the original domains of the pieces.  It is safe to use these
+ * original domains because the difference between, say, A' and A is
+ * the domains of pw2-pieces that have been removed before and
+ * those domains are disjoint from B.  A' is used instead of A
+ * because the continued updating of A may result in this domain
+ * getting broken up into more disjuncts.
+ *
+ * After the updated domains have been computed, the result is constructed
+ * from "pw1", "pw2", "list1" and "list2".  If there are any pieces
+ * in "pw1" and "pw2" with the same function value expression, then
+ * they are combined into a single piece in the result.
+ * In order to be able to do this efficiently, the pieces of "pw1" and
+ * "pw2" are first sorted according to their function value expressions.
+ */
+static __isl_give PW *FN(PW,union_opt_cmp)(
+	__isl_take PW *pw1, __isl_take PW *pw2,
+	__isl_give isl_set *(*cmp)(__isl_take EL *el1, __isl_take EL *el2))
+{
+	int i, j;
+	PW *res = NULL;
+	isl_ctx *ctx;
+	isl_set *set = NULL;
+	isl_set_list *list1 = NULL, *list2 = NULL;
+
+	if (!pw1 || !pw2)
+		goto error;
+
+	ctx = isl_space_get_ctx(pw1->dim);
+	if (!isl_space_is_equal(pw1->dim, pw2->dim))
+		isl_die(ctx, isl_error_invalid,
+			"arguments should live in the same space", goto error);
+
+	if (FN(PW,is_empty)(pw1)) {
+		FN(PW,free)(pw1);
+		return pw2;
+	}
+
+	if (FN(PW,is_empty)(pw2)) {
+		FN(PW,free)(pw2);
+		return pw1;
+	}
+
+	pw1 = FN(PW,sort)(pw1);
+	pw2 = FN(PW,sort)(pw2);
+	if (!pw1 || !pw2)
+		goto error;
+
+	list1 = FN(PW,extract_domains)(pw1);
+	list2 = FN(PW,extract_domains)(pw2);
+
+	for (i = 0; i < pw1->n; ++i) {
+		for (j = 0; j < pw2->n; ++j) {
+			isl_bool disjoint;
+			isl_set *better, *set_i, *set_j;
+
+			disjoint = isl_set_is_disjoint(pw1->p[i].set,
+							pw2->p[j].set);
+			if (disjoint < 0)
+				goto error;
+			if (disjoint)
+				continue;
+			better = FN(PW,better)(pw2->p[j].FIELD,
+						pw1->p[i].FIELD, cmp);
+			set_i = isl_set_list_get_set(list1, i);
+			set_j = isl_set_copy(pw2->p[j].set);
+			set_i = FN(PW,worse_or_out)(set_i,
+						isl_set_copy(better), set_j);
+			list1 = isl_set_list_set_set(list1, i, set_i);
+			set_i = isl_set_copy(pw1->p[i].set);
+			set_j = isl_set_list_get_set(list2, j);
+			set_j = FN(PW,better_or_out)(set_j, better, set_i);
+			list2 = isl_set_list_set_set(list2, j, set_j);
+		}
+	}
+
+	res = FN(PW,merge)(pw1, pw2, list1, list2);
+
+	return res;
+error:
+	isl_set_list_free(list1);
+	isl_set_list_free(list2);
+	FN(PW,free)(pw1);
+	FN(PW,free)(pw2);
+	isl_set_free(set);
+	return FN(PW,free)(res);
+}
diff --git a/final/lib/External/isl/isl_range.c b/final/lib/External/isl/isl_range.c
new file mode 100644
index 0000000..d63ce58
--- /dev/null
+++ b/final/lib/External/isl/isl_range.c
@@ -0,0 +1,540 @@
+#include <isl_ctx_private.h>
+#include <isl_constraint_private.h>
+#include <isl/set.h>
+#include <isl_polynomial_private.h>
+#include <isl_morph.h>
+#include <isl_range.h>
+
+struct range_data {
+	struct isl_bound	*bound;
+	int 		    	*signs;
+	int			sign;
+	int			test_monotonicity;
+	int		    	monotonicity;
+	int			tight;
+	isl_qpolynomial	    	*poly;
+	isl_pw_qpolynomial_fold *pwf;
+	isl_pw_qpolynomial_fold *pwf_tight;
+};
+
+static isl_stat propagate_on_domain(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct range_data *data);
+
+/* Check whether the polynomial "poly" has sign "sign" over "bset",
+ * i.e., if sign == 1, check that the lower bound on the polynomial
+ * is non-negative and if sign == -1, check that the upper bound on
+ * the polynomial is non-positive.
+ */
+static int has_sign(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_qpolynomial *poly, int sign, int *signs)
+{
+	struct range_data data_m;
+	unsigned nparam;
+	isl_space *dim;
+	isl_val *opt;
+	int r;
+	enum isl_fold type;
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+
+	bset = isl_basic_set_copy(bset);
+	poly = isl_qpolynomial_copy(poly);
+
+	bset = isl_basic_set_move_dims(bset, isl_dim_set, 0,
+					isl_dim_param, 0, nparam);
+	poly = isl_qpolynomial_move_dims(poly, isl_dim_in, 0,
+					isl_dim_param, 0, nparam);
+
+	dim = isl_qpolynomial_get_space(poly);
+	dim = isl_space_params(dim);
+	dim = isl_space_from_domain(dim);
+	dim = isl_space_add_dims(dim, isl_dim_out, 1);
+
+	data_m.test_monotonicity = 0;
+	data_m.signs = signs;
+	data_m.sign = -sign;
+	type = data_m.sign < 0 ? isl_fold_min : isl_fold_max;
+	data_m.pwf = isl_pw_qpolynomial_fold_zero(dim, type);
+	data_m.tight = 0;
+	data_m.pwf_tight = NULL;
+
+	if (propagate_on_domain(bset, poly, &data_m) < 0)
+		goto error;
+
+	if (sign > 0)
+		opt = isl_pw_qpolynomial_fold_min(data_m.pwf);
+	else
+		opt = isl_pw_qpolynomial_fold_max(data_m.pwf);
+
+	if (!opt)
+		r = -1;
+	else if (isl_val_is_nan(opt) ||
+		 isl_val_is_infty(opt) ||
+		 isl_val_is_neginfty(opt))
+		r = 0;
+	else
+		r = sign * isl_val_sgn(opt) >= 0;
+
+	isl_val_free(opt);
+
+	return r;
+error:
+	isl_pw_qpolynomial_fold_free(data_m.pwf);
+	return -1;
+}
+
+/* Return  1 if poly is monotonically increasing in the last set variable,
+ *        -1 if poly is monotonically decreasing in the last set variable,
+ *	   0 if no conclusion,
+ *	  -2 on error.
+ *
+ * We simply check the sign of p(x+1)-p(x)
+ */
+static int monotonicity(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_qpolynomial *poly, struct range_data *data)
+{
+	isl_ctx *ctx;
+	isl_space *dim;
+	isl_qpolynomial *sub = NULL;
+	isl_qpolynomial *diff = NULL;
+	int result = 0;
+	int s;
+	unsigned nvar;
+
+	ctx = isl_qpolynomial_get_ctx(poly);
+	dim = isl_qpolynomial_get_domain_space(poly);
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+	sub = isl_qpolynomial_var_on_domain(isl_space_copy(dim), isl_dim_set, nvar - 1);
+	sub = isl_qpolynomial_add(sub,
+		isl_qpolynomial_rat_cst_on_domain(dim, ctx->one, ctx->one));
+
+	diff = isl_qpolynomial_substitute(isl_qpolynomial_copy(poly),
+			isl_dim_in, nvar - 1, 1, &sub);
+	diff = isl_qpolynomial_sub(diff, isl_qpolynomial_copy(poly));
+
+	s = has_sign(bset, diff, 1, data->signs);
+	if (s < 0)
+		goto error;
+	if (s)
+		result = 1;
+	else {
+		s = has_sign(bset, diff, -1, data->signs);
+		if (s < 0)
+			goto error;
+		if (s)
+			result = -1;
+	}
+
+	isl_qpolynomial_free(diff);
+	isl_qpolynomial_free(sub);
+
+	return result;
+error:
+	isl_qpolynomial_free(diff);
+	isl_qpolynomial_free(sub);
+	return -2;
+}
+
+/* Return a positive ("sign" > 0) or negative ("sign" < 0) infinite polynomial
+ * with domain space "space".
+ */
+static __isl_give isl_qpolynomial *signed_infty(__isl_take isl_space *space,
+	int sign)
+{
+	if (sign > 0)
+		return isl_qpolynomial_infty_on_domain(space);
+	else
+		return isl_qpolynomial_neginfty_on_domain(space);
+}
+
+static __isl_give isl_qpolynomial *bound2poly(__isl_take isl_constraint *bound,
+	__isl_take isl_space *space, unsigned pos, int sign)
+{
+	if (!bound)
+		return signed_infty(space, sign);
+	isl_space_free(space);
+	return isl_qpolynomial_from_constraint(bound, isl_dim_set, pos);
+}
+
+static int bound_is_integer(__isl_take isl_constraint *bound, unsigned pos)
+{
+	isl_int c;
+	int is_int;
+
+	if (!bound)
+		return 1;
+
+	isl_int_init(c);
+	isl_constraint_get_coefficient(bound, isl_dim_set, pos, &c);
+	is_int = isl_int_is_one(c) || isl_int_is_negone(c);
+	isl_int_clear(c);
+
+	return is_int;
+}
+
+struct isl_fixed_sign_data {
+	int		*signs;
+	int		sign;
+	isl_qpolynomial	*poly;
+};
+
+/* Add term "term" to data->poly if it has sign data->sign.
+ * The sign is determined based on the signs of the parameters
+ * and variables in data->signs.  The integer divisions, if
+ * any, are assumed to be non-negative.
+ */
+static isl_stat collect_fixed_sign_terms(__isl_take isl_term *term, void *user)
+{
+	struct isl_fixed_sign_data *data = (struct isl_fixed_sign_data *)user;
+	isl_int n;
+	int i;
+	int sign;
+	unsigned nparam;
+	unsigned nvar;
+
+	if (!term)
+		return isl_stat_error;
+
+	nparam = isl_term_dim(term, isl_dim_param);
+	nvar = isl_term_dim(term, isl_dim_set);
+
+	isl_int_init(n);
+
+	isl_term_get_num(term, &n);
+
+	sign = isl_int_sgn(n);
+	for (i = 0; i < nparam; ++i) {
+		if (data->signs[i] > 0)
+			continue;
+		if (isl_term_get_exp(term, isl_dim_param, i) % 2)
+			sign = -sign;
+	}
+	for (i = 0; i < nvar; ++i) {
+		if (data->signs[nparam + i] > 0)
+			continue;
+		if (isl_term_get_exp(term, isl_dim_set, i) % 2)
+			sign = -sign;
+	}
+
+	if (sign == data->sign) {
+		isl_qpolynomial *t = isl_qpolynomial_from_term(term);
+
+		data->poly = isl_qpolynomial_add(data->poly, t);
+	} else
+		isl_term_free(term);
+
+	isl_int_clear(n);
+
+	return isl_stat_ok;
+}
+
+/* Construct and return a polynomial that consists of the terms
+ * in "poly" that have sign "sign".  The integer divisions, if
+ * any, are assumed to be non-negative.
+ */
+__isl_give isl_qpolynomial *isl_qpolynomial_terms_of_sign(
+	__isl_keep isl_qpolynomial *poly, int *signs, int sign)
+{
+	isl_space *space;
+	struct isl_fixed_sign_data data = { signs, sign };
+
+	space = isl_qpolynomial_get_domain_space(poly);
+	data.poly = isl_qpolynomial_zero_on_domain(space);
+
+	if (isl_qpolynomial_foreach_term(poly, collect_fixed_sign_terms, &data) < 0)
+		goto error;
+
+	return data.poly;
+error:
+	isl_qpolynomial_free(data.poly);
+	return NULL;
+}
+
+/* Helper function to add a guarded polynomial to either pwf_tight or pwf,
+ * depending on whether the result has been determined to be tight.
+ */
+static isl_stat add_guarded_poly(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct range_data *data)
+{
+	enum isl_fold type = data->sign < 0 ? isl_fold_min : isl_fold_max;
+	isl_set *set;
+	isl_qpolynomial_fold *fold;
+	isl_pw_qpolynomial_fold *pwf;
+
+	bset = isl_basic_set_params(bset);
+	poly = isl_qpolynomial_project_domain_on_params(poly);
+
+	fold = isl_qpolynomial_fold_alloc(type, poly);
+	set = isl_set_from_basic_set(bset);
+	pwf = isl_pw_qpolynomial_fold_alloc(type, set, fold);
+	if (data->tight)
+		data->pwf_tight = isl_pw_qpolynomial_fold_fold(
+						data->pwf_tight, pwf);
+	else
+		data->pwf = isl_pw_qpolynomial_fold_fold(data->pwf, pwf);
+
+	return isl_stat_ok;
+}
+
+/* Plug in "sub" for the variable at position "pos" in "poly".
+ *
+ * If "sub" is an infinite polynomial and if the variable actually
+ * appears in "poly", then calling isl_qpolynomial_substitute
+ * to perform the substitution may result in a NaN result.
+ * In such cases, return positive or negative infinity instead,
+ * depending on whether an upper bound or a lower bound is being computed,
+ * and mark the result as not being tight.
+ */
+static __isl_give isl_qpolynomial *plug_in_at_pos(
+	__isl_take isl_qpolynomial *poly, int pos,
+	__isl_take isl_qpolynomial *sub, struct range_data *data)
+{
+	isl_bool involves, infty;
+
+	involves = isl_qpolynomial_involves_dims(poly, isl_dim_in, pos, 1);
+	if (involves < 0)
+		goto error;
+	if (!involves) {
+		isl_qpolynomial_free(sub);
+		return poly;
+	}
+
+	infty = isl_qpolynomial_is_infty(sub);
+	if (infty >= 0 && !infty)
+		infty = isl_qpolynomial_is_neginfty(sub);
+	if (infty < 0)
+		goto error;
+	if (infty) {
+		isl_space *space = isl_qpolynomial_get_domain_space(poly);
+		data->tight = 0;
+		isl_qpolynomial_free(poly);
+		isl_qpolynomial_free(sub);
+		return signed_infty(space, data->sign);
+	}
+
+	poly = isl_qpolynomial_substitute(poly, isl_dim_in, pos, 1, &sub);
+	isl_qpolynomial_free(sub);
+
+	return poly;
+error:
+	isl_qpolynomial_free(poly);
+	isl_qpolynomial_free(sub);
+	return NULL;
+}
+
+/* Given a lower and upper bound on the final variable and constraints
+ * on the remaining variables where these bounds are active,
+ * eliminate the variable from data->poly based on these bounds.
+ * If the polynomial has been determined to be monotonic
+ * in the variable, then simply plug in the appropriate bound.
+ * If the current polynomial is tight and if this bound is integer,
+ * then the result is still tight.  In all other cases, the results
+ * may not be tight.
+ * Otherwise, plug in the largest bound (in absolute value) in
+ * the positive terms (if an upper bound is wanted) or the negative terms
+ * (if a lower bounded is wanted) and the other bound in the other terms.
+ *
+ * If all variables have been eliminated, then record the result.
+ * Ohterwise, recurse on the next variable.
+ */
+static isl_stat propagate_on_bound_pair(__isl_take isl_constraint *lower,
+	__isl_take isl_constraint *upper, __isl_take isl_basic_set *bset,
+	void *user)
+{
+	struct range_data *data = (struct range_data *)user;
+	int save_tight = data->tight;
+	isl_qpolynomial *poly;
+	isl_stat r;
+	unsigned nvar;
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+	if (data->monotonicity) {
+		isl_qpolynomial *sub;
+		isl_space *dim = isl_qpolynomial_get_domain_space(data->poly);
+		if (data->monotonicity * data->sign > 0) {
+			if (data->tight)
+				data->tight = bound_is_integer(upper, nvar);
+			sub = bound2poly(upper, dim, nvar, 1);
+			isl_constraint_free(lower);
+		} else {
+			if (data->tight)
+				data->tight = bound_is_integer(lower, nvar);
+			sub = bound2poly(lower, dim, nvar, -1);
+			isl_constraint_free(upper);
+		}
+		poly = isl_qpolynomial_copy(data->poly);
+		poly = plug_in_at_pos(poly, nvar, sub, data);
+		poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, nvar, 1);
+	} else {
+		isl_qpolynomial *l, *u;
+		isl_qpolynomial *pos, *neg;
+		isl_space *dim = isl_qpolynomial_get_domain_space(data->poly);
+		unsigned nparam = isl_basic_set_dim(bset, isl_dim_param);
+		int sign = data->sign * data->signs[nparam + nvar];
+
+		data->tight = 0;
+
+		u = bound2poly(upper, isl_space_copy(dim), nvar, 1);
+		l = bound2poly(lower, dim, nvar, -1);
+
+		pos = isl_qpolynomial_terms_of_sign(data->poly, data->signs, sign);
+		neg = isl_qpolynomial_terms_of_sign(data->poly, data->signs, -sign);
+
+		pos = plug_in_at_pos(pos, nvar, u, data);
+		neg = plug_in_at_pos(neg, nvar, l, data);
+
+		poly = isl_qpolynomial_add(pos, neg);
+		poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, nvar, 1);
+	}
+
+	if (isl_basic_set_dim(bset, isl_dim_set) == 0)
+		r = add_guarded_poly(bset, poly, data);
+	else
+		r = propagate_on_domain(bset, poly, data);
+
+	data->tight = save_tight;
+
+	return r;
+}
+
+/* Recursively perform range propagation on the polynomial "poly"
+ * defined over the basic set "bset" and collect the results in "data".
+ */
+static isl_stat propagate_on_domain(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct range_data *data)
+{
+	isl_ctx *ctx;
+	isl_qpolynomial *save_poly = data->poly;
+	int save_monotonicity = data->monotonicity;
+	unsigned d;
+
+	if (!bset || !poly)
+		goto error;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	d = isl_basic_set_dim(bset, isl_dim_set);
+	isl_assert(ctx, d >= 1, goto error);
+
+	if (isl_qpolynomial_is_cst(poly, NULL, NULL)) {
+		bset = isl_basic_set_project_out(bset, isl_dim_set, 0, d);
+		poly = isl_qpolynomial_drop_dims(poly, isl_dim_in, 0, d);
+		return add_guarded_poly(bset, poly, data);
+	}
+
+	if (data->test_monotonicity)
+		data->monotonicity = monotonicity(bset, poly, data);
+	else
+		data->monotonicity = 0;
+	if (data->monotonicity < -1)
+		goto error;
+
+	data->poly = poly;
+	if (isl_basic_set_foreach_bound_pair(bset, isl_dim_set, d - 1,
+					    &propagate_on_bound_pair, data) < 0)
+		goto error;
+
+	isl_basic_set_free(bset);
+	isl_qpolynomial_free(poly);
+	data->monotonicity = save_monotonicity;
+	data->poly = save_poly;
+
+	return isl_stat_ok;
+error:
+	isl_basic_set_free(bset);
+	isl_qpolynomial_free(poly);
+	data->monotonicity = save_monotonicity;
+	data->poly = save_poly;
+	return isl_stat_error;
+}
+
+static isl_stat basic_guarded_poly_bound(__isl_take isl_basic_set *bset,
+	void *user)
+{
+	struct range_data *data = (struct range_data *)user;
+	isl_ctx *ctx;
+	unsigned nparam = isl_basic_set_dim(bset, isl_dim_param);
+	unsigned dim = isl_basic_set_dim(bset, isl_dim_set);
+	isl_stat r;
+
+	data->signs = NULL;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	data->signs = isl_alloc_array(ctx, int,
+					isl_basic_set_dim(bset, isl_dim_all));
+
+	if (isl_basic_set_dims_get_sign(bset, isl_dim_set, 0, dim,
+					data->signs + nparam) < 0)
+		goto error;
+	if (isl_basic_set_dims_get_sign(bset, isl_dim_param, 0, nparam,
+					data->signs) < 0)
+		goto error;
+
+	r = propagate_on_domain(bset, isl_qpolynomial_copy(data->poly), data);
+
+	free(data->signs);
+
+	return r;
+error:
+	free(data->signs);
+	isl_basic_set_free(bset);
+	return isl_stat_error;
+}
+
+static isl_stat qpolynomial_bound_on_domain_range(
+	__isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *poly,
+	struct range_data *data)
+{
+	unsigned nparam = isl_basic_set_dim(bset, isl_dim_param);
+	unsigned nvar = isl_basic_set_dim(bset, isl_dim_set);
+	isl_set *set = NULL;
+
+	if (!bset)
+		goto error;
+
+	if (nvar == 0)
+		return add_guarded_poly(bset, poly, data);
+
+	set = isl_set_from_basic_set(bset);
+	set = isl_set_split_dims(set, isl_dim_param, 0, nparam);
+	set = isl_set_split_dims(set, isl_dim_set, 0, nvar);
+
+	data->poly = poly;
+
+	data->test_monotonicity = 1;
+	if (isl_set_foreach_basic_set(set, &basic_guarded_poly_bound, data) < 0)
+		goto error;
+
+	isl_set_free(set);
+	isl_qpolynomial_free(poly);
+
+	return isl_stat_ok;
+error:
+	isl_set_free(set);
+	isl_qpolynomial_free(poly);
+	return isl_stat_error;
+}
+
+isl_stat isl_qpolynomial_bound_on_domain_range(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct isl_bound *bound)
+{
+	struct range_data data;
+	isl_stat r;
+
+	data.pwf = bound->pwf;
+	data.pwf_tight = bound->pwf_tight;
+	data.tight = bound->check_tight;
+	if (bound->type == isl_fold_min)
+		data.sign = -1;
+	else
+		data.sign = 1;
+
+	r = qpolynomial_bound_on_domain_range(bset, poly, &data);
+
+	bound->pwf = data.pwf;
+	bound->pwf_tight = data.pwf_tight;
+
+	return r;
+}
diff --git a/final/lib/External/isl/isl_range.h b/final/lib/External/isl/isl_range.h
new file mode 100644
index 0000000..6a5dd4a
--- /dev/null
+++ b/final/lib/External/isl/isl_range.h
@@ -0,0 +1,6 @@
+#include <isl_bound.h>
+
+isl_stat isl_qpolynomial_bound_on_domain_range(__isl_take isl_basic_set *bset,
+	__isl_take isl_qpolynomial *poly, struct isl_bound *bound);
+__isl_give isl_qpolynomial *isl_qpolynomial_terms_of_sign(
+	__isl_keep isl_qpolynomial *poly, int *signs, int sign);
diff --git a/final/lib/External/isl/isl_reordering.c b/final/lib/External/isl/isl_reordering.c
new file mode 100644
index 0000000..ca9c973
--- /dev/null
+++ b/final/lib/External/isl/isl_reordering.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_space_private.h>
+#include <isl_reordering.h>
+
+__isl_give isl_reordering *isl_reordering_alloc(isl_ctx *ctx, int len)
+{
+	isl_reordering *exp;
+
+	exp = isl_alloc(ctx, struct isl_reordering,
+			sizeof(struct isl_reordering) + (len - 1) * sizeof(int));
+	if (!exp)
+		return NULL;
+
+	exp->ref = 1;
+	exp->len = len;
+	exp->dim = NULL;
+
+	return exp;
+}
+
+__isl_give isl_reordering *isl_reordering_copy(__isl_keep isl_reordering *exp)
+{
+	if (!exp)
+		return NULL;
+
+	exp->ref++;
+	return exp;
+}
+
+__isl_give isl_reordering *isl_reordering_dup(__isl_keep isl_reordering *r)
+{
+	int i;
+	isl_reordering *dup;
+
+	if (!r)
+		return NULL;
+
+	dup = isl_reordering_alloc(r->dim->ctx, r->len);
+	if (!dup)
+		return NULL;
+
+	dup->dim = isl_space_copy(r->dim);
+	if (!dup->dim)
+		return isl_reordering_free(dup);
+	for (i = 0; i < dup->len; ++i)
+		dup->pos[i] = r->pos[i];
+
+	return dup;
+}
+
+__isl_give isl_reordering *isl_reordering_cow(__isl_take isl_reordering *r)
+{
+	if (!r)
+		return NULL;
+
+	if (r->ref == 1)
+		return r;
+	r->ref--;
+	return isl_reordering_dup(r);
+}
+
+void *isl_reordering_free(__isl_take isl_reordering *exp)
+{
+	if (!exp)
+		return NULL;
+
+	if (--exp->ref > 0)
+		return NULL;
+
+	isl_space_free(exp->dim);
+	free(exp);
+	return NULL;
+}
+
+/* Construct a reordering that maps the parameters of "alignee"
+ * to the corresponding parameters in a new dimension specification
+ * that has the parameters of "aligner" first, followed by
+ * any remaining parameters of "alignee" that do not occur in "aligner".
+ */
+__isl_give isl_reordering *isl_parameter_alignment_reordering(
+	__isl_keep isl_space *alignee, __isl_keep isl_space *aligner)
+{
+	int i, j;
+	isl_reordering *exp;
+
+	if (!alignee || !aligner)
+		return NULL;
+
+	exp = isl_reordering_alloc(alignee->ctx, alignee->nparam);
+	if (!exp)
+		return NULL;
+
+	exp->dim = isl_space_copy(aligner);
+
+	for (i = 0; i < alignee->nparam; ++i) {
+		isl_id *id_i;
+		id_i = isl_space_get_dim_id(alignee, isl_dim_param, i);
+		if (!id_i)
+			isl_die(alignee->ctx, isl_error_invalid,
+				"cannot align unnamed parameters", goto error);
+		for (j = 0; j < aligner->nparam; ++j) {
+			isl_id *id_j;
+			id_j = isl_space_get_dim_id(aligner, isl_dim_param, j);
+			isl_id_free(id_j);
+			if (id_i == id_j)
+				break;
+		}
+		if (j < aligner->nparam) {
+			exp->pos[i] = j;
+			isl_id_free(id_i);
+		} else {
+			int pos;
+			pos = isl_space_dim(exp->dim, isl_dim_param);
+			exp->dim = isl_space_add_dims(exp->dim, isl_dim_param, 1);
+			exp->dim = isl_space_set_dim_id(exp->dim,
+						isl_dim_param, pos, id_i);
+			exp->pos[i] = pos;
+		}
+	}
+
+	if (!exp->dim)
+		return isl_reordering_free(exp);
+	return exp;
+error:
+	isl_reordering_free(exp);
+	return NULL;
+}
+
+__isl_give isl_reordering *isl_reordering_extend(__isl_take isl_reordering *exp,
+	unsigned extra)
+{
+	int i;
+	isl_reordering *res;
+	int offset;
+
+	if (!exp)
+		return NULL;
+	if (extra == 0)
+		return exp;
+
+	offset = isl_space_dim(exp->dim, isl_dim_all) - exp->len;
+	res = isl_reordering_alloc(exp->dim->ctx, exp->len + extra);
+	if (!res)
+		goto error;
+	res->dim = isl_space_copy(exp->dim);
+	for (i = 0; i < exp->len; ++i)
+		res->pos[i] = exp->pos[i];
+	for (i = exp->len; i < res->len; ++i)
+		res->pos[i] = offset + i;
+
+	isl_reordering_free(exp);
+
+	return res;
+error:
+	isl_reordering_free(exp);
+	return NULL;
+}
+
+__isl_give isl_reordering *isl_reordering_extend_space(
+	__isl_take isl_reordering *exp, __isl_take isl_space *dim)
+{
+	isl_reordering *res;
+
+	if (!exp || !dim)
+		goto error;
+
+	res = isl_reordering_extend(isl_reordering_copy(exp),
+				    isl_space_dim(dim, isl_dim_all) - exp->len);
+	res = isl_reordering_cow(res);
+	if (!res)
+		goto error;
+	isl_space_free(res->dim);
+	res->dim = isl_space_replace(dim, isl_dim_param, exp->dim);
+
+	isl_reordering_free(exp);
+
+	if (!res->dim)
+		return isl_reordering_free(res);
+
+	return res;
+error:
+	isl_reordering_free(exp);
+	isl_space_free(dim);
+	return NULL;
+}
+
+void isl_reordering_dump(__isl_keep isl_reordering *exp)
+{
+	int i;
+
+	isl_space_dump(exp->dim);
+	for (i = 0; i < exp->len; ++i)
+		fprintf(stderr, "%d -> %d; ", i, exp->pos[i]);
+	fprintf(stderr, "\n");
+}
diff --git a/final/lib/External/isl/isl_reordering.h b/final/lib/External/isl/isl_reordering.h
new file mode 100644
index 0000000..ac5b6fa
--- /dev/null
+++ b/final/lib/External/isl/isl_reordering.h
@@ -0,0 +1,31 @@
+#ifndef ISL_REORDERING_H
+#define ISL_REORDERING_H
+
+#include <isl/space.h>
+
+/* pos maps original dimensions to new dimensions.
+ * The final dimension is given by dim.
+ * The number of dimensions (i.e., the range of values) in the result
+ * may be larger than the number of dimensions in the input.
+ * In particular, the possible values of the entries in pos ranges from 0 to
+ * the total dimension of dim - 1, unless isl_reordering_extend
+ * has been called.
+ */
+struct isl_reordering {
+	int ref;
+	isl_space *dim;
+	unsigned len;
+	int pos[1];
+};
+typedef struct isl_reordering isl_reordering;
+
+__isl_give isl_reordering *isl_parameter_alignment_reordering(
+	__isl_keep isl_space *alignee, __isl_keep isl_space *aligner);
+__isl_give isl_reordering *isl_reordering_copy(__isl_keep isl_reordering *exp);
+void *isl_reordering_free(__isl_take isl_reordering *exp);
+__isl_give isl_reordering *isl_reordering_extend_space(
+	__isl_take isl_reordering *exp, __isl_take isl_space *dim);
+__isl_give isl_reordering *isl_reordering_extend(__isl_take isl_reordering *exp,
+	unsigned extra);
+
+#endif
diff --git a/final/lib/External/isl/isl_sample.c b/final/lib/External/isl/isl_sample.c
new file mode 100644
index 0000000..058d689
--- /dev/null
+++ b/final/lib/External/isl/isl_sample.c
@@ -0,0 +1,1308 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include "isl_sample.h"
+#include <isl/vec.h>
+#include <isl/mat.h>
+#include <isl_seq.h>
+#include "isl_equalities.h"
+#include "isl_tab.h"
+#include "isl_basis_reduction.h"
+#include <isl_factorization.h>
+#include <isl_point_private.h>
+#include <isl_options_private.h>
+#include <isl_vec_private.h>
+
+#include <bset_from_bmap.c>
+#include <set_to_map.c>
+
+static __isl_give isl_vec *empty_sample(__isl_take isl_basic_set *bset)
+{
+	struct isl_vec *vec;
+
+	vec = isl_vec_alloc(bset->ctx, 0);
+	isl_basic_set_free(bset);
+	return vec;
+}
+
+/* Construct a zero sample of the same dimension as bset.
+ * As a special case, if bset is zero-dimensional, this
+ * function creates a zero-dimensional sample point.
+ */
+static __isl_give isl_vec *zero_sample(__isl_take isl_basic_set *bset)
+{
+	unsigned dim;
+	struct isl_vec *sample;
+
+	dim = isl_basic_set_total_dim(bset);
+	sample = isl_vec_alloc(bset->ctx, 1 + dim);
+	if (sample) {
+		isl_int_set_si(sample->el[0], 1);
+		isl_seq_clr(sample->el + 1, dim);
+	}
+	isl_basic_set_free(bset);
+	return sample;
+}
+
+static __isl_give isl_vec *interval_sample(__isl_take isl_basic_set *bset)
+{
+	int i;
+	isl_int t;
+	struct isl_vec *sample;
+
+	bset = isl_basic_set_simplify(bset);
+	if (!bset)
+		return NULL;
+	if (isl_basic_set_plain_is_empty(bset))
+		return empty_sample(bset);
+	if (bset->n_eq == 0 && bset->n_ineq == 0)
+		return zero_sample(bset);
+
+	sample = isl_vec_alloc(bset->ctx, 2);
+	if (!sample)
+		goto error;
+	if (!bset)
+		return NULL;
+	isl_int_set_si(sample->block.data[0], 1);
+
+	if (bset->n_eq > 0) {
+		isl_assert(bset->ctx, bset->n_eq == 1, goto error);
+		isl_assert(bset->ctx, bset->n_ineq == 0, goto error);
+		if (isl_int_is_one(bset->eq[0][1]))
+			isl_int_neg(sample->el[1], bset->eq[0][0]);
+		else {
+			isl_assert(bset->ctx, isl_int_is_negone(bset->eq[0][1]),
+				   goto error);
+			isl_int_set(sample->el[1], bset->eq[0][0]);
+		}
+		isl_basic_set_free(bset);
+		return sample;
+	}
+
+	isl_int_init(t);
+	if (isl_int_is_one(bset->ineq[0][1]))
+		isl_int_neg(sample->block.data[1], bset->ineq[0][0]);
+	else
+		isl_int_set(sample->block.data[1], bset->ineq[0][0]);
+	for (i = 1; i < bset->n_ineq; ++i) {
+		isl_seq_inner_product(sample->block.data,
+					bset->ineq[i], 2, &t);
+		if (isl_int_is_neg(t))
+			break;
+	}
+	isl_int_clear(t);
+	if (i < bset->n_ineq) {
+		isl_vec_free(sample);
+		return empty_sample(bset);
+	}
+
+	isl_basic_set_free(bset);
+	return sample;
+error:
+	isl_basic_set_free(bset);
+	isl_vec_free(sample);
+	return NULL;
+}
+
+/* Find a sample integer point, if any, in bset, which is known
+ * to have equalities.  If bset contains no integer points, then
+ * return a zero-length vector.
+ * We simply remove the known equalities, compute a sample
+ * in the resulting bset, using the specified recurse function,
+ * and then transform the sample back to the original space.
+ */
+static __isl_give isl_vec *sample_eq(__isl_take isl_basic_set *bset,
+	__isl_give isl_vec *(*recurse)(__isl_take isl_basic_set *))
+{
+	struct isl_mat *T;
+	struct isl_vec *sample;
+
+	if (!bset)
+		return NULL;
+
+	bset = isl_basic_set_remove_equalities(bset, &T, NULL);
+	sample = recurse(bset);
+	if (!sample || sample->size == 0)
+		isl_mat_free(T);
+	else
+		sample = isl_mat_vec_product(T, sample);
+	return sample;
+}
+
+/* Return a matrix containing the equalities of the tableau
+ * in constraint form.  The tableau is assumed to have
+ * an associated bset that has been kept up-to-date.
+ */
+static struct isl_mat *tab_equalities(struct isl_tab *tab)
+{
+	int i, j;
+	int n_eq;
+	struct isl_mat *eq;
+	struct isl_basic_set *bset;
+
+	if (!tab)
+		return NULL;
+
+	bset = isl_tab_peek_bset(tab);
+	isl_assert(tab->mat->ctx, bset, return NULL);
+
+	n_eq = tab->n_var - tab->n_col + tab->n_dead;
+	if (tab->empty || n_eq == 0)
+		return isl_mat_alloc(tab->mat->ctx, 0, tab->n_var);
+	if (n_eq == tab->n_var)
+		return isl_mat_identity(tab->mat->ctx, tab->n_var);
+
+	eq = isl_mat_alloc(tab->mat->ctx, n_eq, tab->n_var);
+	if (!eq)
+		return NULL;
+	for (i = 0, j = 0; i < tab->n_con; ++i) {
+		if (tab->con[i].is_row)
+			continue;
+		if (tab->con[i].index >= 0 && tab->con[i].index >= tab->n_dead)
+			continue;
+		if (i < bset->n_eq)
+			isl_seq_cpy(eq->row[j], bset->eq[i] + 1, tab->n_var);
+		else
+			isl_seq_cpy(eq->row[j],
+				    bset->ineq[i - bset->n_eq] + 1, tab->n_var);
+		++j;
+	}
+	isl_assert(bset->ctx, j == n_eq, goto error);
+	return eq;
+error:
+	isl_mat_free(eq);
+	return NULL;
+}
+
+/* Compute and return an initial basis for the bounded tableau "tab".
+ *
+ * If the tableau is either full-dimensional or zero-dimensional,
+ * the we simply return an identity matrix.
+ * Otherwise, we construct a basis whose first directions correspond
+ * to equalities.
+ */
+static struct isl_mat *initial_basis(struct isl_tab *tab)
+{
+	int n_eq;
+	struct isl_mat *eq;
+	struct isl_mat *Q;
+
+	tab->n_unbounded = 0;
+	tab->n_zero = n_eq = tab->n_var - tab->n_col + tab->n_dead;
+	if (tab->empty || n_eq == 0 || n_eq == tab->n_var)
+		return isl_mat_identity(tab->mat->ctx, 1 + tab->n_var);
+
+	eq = tab_equalities(tab);
+	eq = isl_mat_left_hermite(eq, 0, NULL, &Q);
+	if (!eq)
+		return NULL;
+	isl_mat_free(eq);
+
+	Q = isl_mat_lin_to_aff(Q);
+	return Q;
+}
+
+/* Compute the minimum of the current ("level") basis row over "tab"
+ * and store the result in position "level" of "min".
+ *
+ * This function assumes that at least one more row and at least
+ * one more element in the constraint array are available in the tableau.
+ */
+static enum isl_lp_result compute_min(isl_ctx *ctx, struct isl_tab *tab,
+	__isl_keep isl_vec *min, int level)
+{
+	return isl_tab_min(tab, tab->basis->row[1 + level],
+			    ctx->one, &min->el[level], NULL, 0);
+}
+
+/* Compute the maximum of the current ("level") basis row over "tab"
+ * and store the result in position "level" of "max".
+ *
+ * This function assumes that at least one more row and at least
+ * one more element in the constraint array are available in the tableau.
+ */
+static enum isl_lp_result compute_max(isl_ctx *ctx, struct isl_tab *tab,
+	__isl_keep isl_vec *max, int level)
+{
+	enum isl_lp_result res;
+	unsigned dim = tab->n_var;
+
+	isl_seq_neg(tab->basis->row[1 + level] + 1,
+		    tab->basis->row[1 + level] + 1, dim);
+	res = isl_tab_min(tab, tab->basis->row[1 + level],
+		    ctx->one, &max->el[level], NULL, 0);
+	isl_seq_neg(tab->basis->row[1 + level] + 1,
+		    tab->basis->row[1 + level] + 1, dim);
+	isl_int_neg(max->el[level], max->el[level]);
+
+	return res;
+}
+
+/* Perform a greedy search for an integer point in the set represented
+ * by "tab", given that the minimal rational value (rounded up to the
+ * nearest integer) at "level" is smaller than the maximal rational
+ * value (rounded down to the nearest integer).
+ *
+ * Return 1 if we have found an integer point (if tab->n_unbounded > 0
+ * then we may have only found integer values for the bounded dimensions
+ * and it is the responsibility of the caller to extend this solution
+ * to the unbounded dimensions).
+ * Return 0 if greedy search did not result in a solution.
+ * Return -1 if some error occurred.
+ *
+ * We assign a value half-way between the minimum and the maximum
+ * to the current dimension and check if the minimal value of the
+ * next dimension is still smaller than (or equal) to the maximal value.
+ * We continue this process until either
+ * - the minimal value (rounded up) is greater than the maximal value
+ *	(rounded down).  In this case, greedy search has failed.
+ * - we have exhausted all bounded dimensions, meaning that we have
+ *	found a solution.
+ * - the sample value of the tableau is integral.
+ * - some error has occurred.
+ */
+static int greedy_search(isl_ctx *ctx, struct isl_tab *tab,
+	__isl_keep isl_vec *min, __isl_keep isl_vec *max, int level)
+{
+	struct isl_tab_undo *snap;
+	enum isl_lp_result res;
+
+	snap = isl_tab_snap(tab);
+
+	do {
+		isl_int_add(tab->basis->row[1 + level][0],
+			    min->el[level], max->el[level]);
+		isl_int_fdiv_q_ui(tab->basis->row[1 + level][0],
+			    tab->basis->row[1 + level][0], 2);
+		isl_int_neg(tab->basis->row[1 + level][0],
+			    tab->basis->row[1 + level][0]);
+		if (isl_tab_add_valid_eq(tab, tab->basis->row[1 + level]) < 0)
+			return -1;
+		isl_int_set_si(tab->basis->row[1 + level][0], 0);
+
+		if (++level >= tab->n_var - tab->n_unbounded)
+			return 1;
+		if (isl_tab_sample_is_integer(tab))
+			return 1;
+
+		res = compute_min(ctx, tab, min, level);
+		if (res == isl_lp_error)
+			return -1;
+		if (res != isl_lp_ok)
+			isl_die(ctx, isl_error_internal,
+				"expecting bounded rational solution",
+				return -1);
+		res = compute_max(ctx, tab, max, level);
+		if (res == isl_lp_error)
+			return -1;
+		if (res != isl_lp_ok)
+			isl_die(ctx, isl_error_internal,
+				"expecting bounded rational solution",
+				return -1);
+	} while (isl_int_le(min->el[level], max->el[level]));
+
+	if (isl_tab_rollback(tab, snap) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Given a tableau representing a set, find and return
+ * an integer point in the set, if there is any.
+ *
+ * We perform a depth first search
+ * for an integer point, by scanning all possible values in the range
+ * attained by a basis vector, where an initial basis may have been set
+ * by the calling function.  Otherwise an initial basis that exploits
+ * the equalities in the tableau is created.
+ * tab->n_zero is currently ignored and is clobbered by this function.
+ *
+ * The tableau is allowed to have unbounded direction, but then
+ * the calling function needs to set an initial basis, with the
+ * unbounded directions last and with tab->n_unbounded set
+ * to the number of unbounded directions.
+ * Furthermore, the calling functions needs to add shifted copies
+ * of all constraints involving unbounded directions to ensure
+ * that any feasible rational value in these directions can be rounded
+ * up to yield a feasible integer value.
+ * In particular, let B define the given basis x' = B x
+ * and let T be the inverse of B, i.e., X = T x'.
+ * Let a x + c >= 0 be a constraint of the set represented by the tableau,
+ * or a T x' + c >= 0 in terms of the given basis.  Assume that
+ * the bounded directions have an integer value, then we can safely
+ * round up the values for the unbounded directions if we make sure
+ * that x' not only satisfies the original constraint, but also
+ * the constraint "a T x' + c + s >= 0" with s the sum of all
+ * negative values in the last n_unbounded entries of "a T".
+ * The calling function therefore needs to add the constraint
+ * a x + c + s >= 0.  The current function then scans the first
+ * directions for an integer value and once those have been found,
+ * it can compute "T ceil(B x)" to yield an integer point in the set.
+ * Note that during the search, the first rows of B may be changed
+ * by a basis reduction, but the last n_unbounded rows of B remain
+ * unaltered and are also not mixed into the first rows.
+ *
+ * The search is implemented iteratively.  "level" identifies the current
+ * basis vector.  "init" is true if we want the first value at the current
+ * level and false if we want the next value.
+ *
+ * At the start of each level, we first check if we can find a solution
+ * using greedy search.  If not, we continue with the exhaustive search.
+ *
+ * The initial basis is the identity matrix.  If the range in some direction
+ * contains more than one integer value, we perform basis reduction based
+ * on the value of ctx->opt->gbr
+ *	- ISL_GBR_NEVER:	never perform basis reduction
+ *	- ISL_GBR_ONCE:		only perform basis reduction the first
+ *				time such a range is encountered
+ *	- ISL_GBR_ALWAYS:	always perform basis reduction when
+ *				such a range is encountered
+ *
+ * When ctx->opt->gbr is set to ISL_GBR_ALWAYS, then we allow the basis
+ * reduction computation to return early.  That is, as soon as it
+ * finds a reasonable first direction.
+ */ 
+struct isl_vec *isl_tab_sample(struct isl_tab *tab)
+{
+	unsigned dim;
+	unsigned gbr;
+	struct isl_ctx *ctx;
+	struct isl_vec *sample;
+	struct isl_vec *min;
+	struct isl_vec *max;
+	enum isl_lp_result res;
+	int level;
+	int init;
+	int reduced;
+	struct isl_tab_undo **snap;
+
+	if (!tab)
+		return NULL;
+	if (tab->empty)
+		return isl_vec_alloc(tab->mat->ctx, 0);
+
+	if (!tab->basis)
+		tab->basis = initial_basis(tab);
+	if (!tab->basis)
+		return NULL;
+	isl_assert(tab->mat->ctx, tab->basis->n_row == tab->n_var + 1,
+		    return NULL);
+	isl_assert(tab->mat->ctx, tab->basis->n_col == tab->n_var + 1,
+		    return NULL);
+
+	ctx = tab->mat->ctx;
+	dim = tab->n_var;
+	gbr = ctx->opt->gbr;
+
+	if (tab->n_unbounded == tab->n_var) {
+		sample = isl_tab_get_sample_value(tab);
+		sample = isl_mat_vec_product(isl_mat_copy(tab->basis), sample);
+		sample = isl_vec_ceil(sample);
+		sample = isl_mat_vec_inverse_product(isl_mat_copy(tab->basis),
+							sample);
+		return sample;
+	}
+
+	if (isl_tab_extend_cons(tab, dim + 1) < 0)
+		return NULL;
+
+	min = isl_vec_alloc(ctx, dim);
+	max = isl_vec_alloc(ctx, dim);
+	snap = isl_alloc_array(ctx, struct isl_tab_undo *, dim);
+
+	if (!min || !max || !snap)
+		goto error;
+
+	level = 0;
+	init = 1;
+	reduced = 0;
+
+	while (level >= 0) {
+		if (init) {
+			int choice;
+
+			res = compute_min(ctx, tab, min, level);
+			if (res == isl_lp_error)
+				goto error;
+			if (res != isl_lp_ok)
+				isl_die(ctx, isl_error_internal,
+					"expecting bounded rational solution",
+					goto error);
+			if (isl_tab_sample_is_integer(tab))
+				break;
+			res = compute_max(ctx, tab, max, level);
+			if (res == isl_lp_error)
+				goto error;
+			if (res != isl_lp_ok)
+				isl_die(ctx, isl_error_internal,
+					"expecting bounded rational solution",
+					goto error);
+			if (isl_tab_sample_is_integer(tab))
+				break;
+			choice = isl_int_lt(min->el[level], max->el[level]);
+			if (choice) {
+				int g;
+				g = greedy_search(ctx, tab, min, max, level);
+				if (g < 0)
+					goto error;
+				if (g)
+					break;
+			}
+			if (!reduced && choice &&
+			    ctx->opt->gbr != ISL_GBR_NEVER) {
+				unsigned gbr_only_first;
+				if (ctx->opt->gbr == ISL_GBR_ONCE)
+					ctx->opt->gbr = ISL_GBR_NEVER;
+				tab->n_zero = level;
+				gbr_only_first = ctx->opt->gbr_only_first;
+				ctx->opt->gbr_only_first =
+					ctx->opt->gbr == ISL_GBR_ALWAYS;
+				tab = isl_tab_compute_reduced_basis(tab);
+				ctx->opt->gbr_only_first = gbr_only_first;
+				if (!tab || !tab->basis)
+					goto error;
+				reduced = 1;
+				continue;
+			}
+			reduced = 0;
+			snap[level] = isl_tab_snap(tab);
+		} else
+			isl_int_add_ui(min->el[level], min->el[level], 1);
+
+		if (isl_int_gt(min->el[level], max->el[level])) {
+			level--;
+			init = 0;
+			if (level >= 0)
+				if (isl_tab_rollback(tab, snap[level]) < 0)
+					goto error;
+			continue;
+		}
+		isl_int_neg(tab->basis->row[1 + level][0], min->el[level]);
+		if (isl_tab_add_valid_eq(tab, tab->basis->row[1 + level]) < 0)
+			goto error;
+		isl_int_set_si(tab->basis->row[1 + level][0], 0);
+		if (level + tab->n_unbounded < dim - 1) {
+			++level;
+			init = 1;
+			continue;
+		}
+		break;
+	}
+
+	if (level >= 0) {
+		sample = isl_tab_get_sample_value(tab);
+		if (!sample)
+			goto error;
+		if (tab->n_unbounded && !isl_int_is_one(sample->el[0])) {
+			sample = isl_mat_vec_product(isl_mat_copy(tab->basis),
+						     sample);
+			sample = isl_vec_ceil(sample);
+			sample = isl_mat_vec_inverse_product(
+					isl_mat_copy(tab->basis), sample);
+		}
+	} else
+		sample = isl_vec_alloc(ctx, 0);
+
+	ctx->opt->gbr = gbr;
+	isl_vec_free(min);
+	isl_vec_free(max);
+	free(snap);
+	return sample;
+error:
+	ctx->opt->gbr = gbr;
+	isl_vec_free(min);
+	isl_vec_free(max);
+	free(snap);
+	return NULL;
+}
+
+static __isl_give isl_vec *sample_bounded(__isl_take isl_basic_set *bset);
+
+/* Compute a sample point of the given basic set, based on the given,
+ * non-trivial factorization.
+ */
+static __isl_give isl_vec *factored_sample(__isl_take isl_basic_set *bset,
+	__isl_take isl_factorizer *f)
+{
+	int i, n;
+	isl_vec *sample = NULL;
+	isl_ctx *ctx;
+	unsigned nparam;
+	unsigned nvar;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	if (!ctx)
+		goto error;
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+	sample = isl_vec_alloc(ctx, 1 + isl_basic_set_total_dim(bset));
+	if (!sample)
+		goto error;
+	isl_int_set_si(sample->el[0], 1);
+
+	bset = isl_morph_basic_set(isl_morph_copy(f->morph), bset);
+
+	for (i = 0, n = 0; i < f->n_group; ++i) {
+		isl_basic_set *bset_i;
+		isl_vec *sample_i;
+
+		bset_i = isl_basic_set_copy(bset);
+		bset_i = isl_basic_set_drop_constraints_involving(bset_i,
+			    nparam + n + f->len[i], nvar - n - f->len[i]);
+		bset_i = isl_basic_set_drop_constraints_involving(bset_i,
+			    nparam, n);
+		bset_i = isl_basic_set_drop(bset_i, isl_dim_set,
+			    n + f->len[i], nvar - n - f->len[i]);
+		bset_i = isl_basic_set_drop(bset_i, isl_dim_set, 0, n);
+
+		sample_i = sample_bounded(bset_i);
+		if (!sample_i)
+			goto error;
+		if (sample_i->size == 0) {
+			isl_basic_set_free(bset);
+			isl_factorizer_free(f);
+			isl_vec_free(sample);
+			return sample_i;
+		}
+		isl_seq_cpy(sample->el + 1 + nparam + n,
+			    sample_i->el + 1, f->len[i]);
+		isl_vec_free(sample_i);
+
+		n += f->len[i];
+	}
+
+	f->morph = isl_morph_inverse(f->morph);
+	sample = isl_morph_vec(isl_morph_copy(f->morph), sample);
+
+	isl_basic_set_free(bset);
+	isl_factorizer_free(f);
+	return sample;
+error:
+	isl_basic_set_free(bset);
+	isl_factorizer_free(f);
+	isl_vec_free(sample);
+	return NULL;
+}
+
+/* Given a basic set that is known to be bounded, find and return
+ * an integer point in the basic set, if there is any.
+ *
+ * After handling some trivial cases, we construct a tableau
+ * and then use isl_tab_sample to find a sample, passing it
+ * the identity matrix as initial basis.
+ */ 
+static __isl_give isl_vec *sample_bounded(__isl_take isl_basic_set *bset)
+{
+	unsigned dim;
+	struct isl_vec *sample;
+	struct isl_tab *tab = NULL;
+	isl_factorizer *f;
+
+	if (!bset)
+		return NULL;
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return empty_sample(bset);
+
+	dim = isl_basic_set_total_dim(bset);
+	if (dim == 0)
+		return zero_sample(bset);
+	if (dim == 1)
+		return interval_sample(bset);
+	if (bset->n_eq > 0)
+		return sample_eq(bset, sample_bounded);
+
+	f = isl_basic_set_factorizer(bset);
+	if (!f)
+		goto error;
+	if (f->n_group != 0)
+		return factored_sample(bset, f);
+	isl_factorizer_free(f);
+
+	tab = isl_tab_from_basic_set(bset, 1);
+	if (tab && tab->empty) {
+		isl_tab_free(tab);
+		ISL_F_SET(bset, ISL_BASIC_SET_EMPTY);
+		sample = isl_vec_alloc(isl_basic_set_get_ctx(bset), 0);
+		isl_basic_set_free(bset);
+		return sample;
+	}
+
+	if (!ISL_F_ISSET(bset, ISL_BASIC_SET_NO_IMPLICIT))
+		if (isl_tab_detect_implicit_equalities(tab) < 0)
+			goto error;
+
+	sample = isl_tab_sample(tab);
+	if (!sample)
+		goto error;
+
+	if (sample->size > 0) {
+		isl_vec_free(bset->sample);
+		bset->sample = isl_vec_copy(sample);
+	}
+
+	isl_basic_set_free(bset);
+	isl_tab_free(tab);
+	return sample;
+error:
+	isl_basic_set_free(bset);
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Given a basic set "bset" and a value "sample" for the first coordinates
+ * of bset, plug in these values and drop the corresponding coordinates.
+ *
+ * We do this by computing the preimage of the transformation
+ *
+ *	     [ 1 0 ]
+ *	x =  [ s 0 ] x'
+ *	     [ 0 I ]
+ *
+ * where [1 s] is the sample value and I is the identity matrix of the
+ * appropriate dimension.
+ */
+static __isl_give isl_basic_set *plug_in(__isl_take isl_basic_set *bset,
+	__isl_take isl_vec *sample)
+{
+	int i;
+	unsigned total;
+	struct isl_mat *T;
+
+	if (!bset || !sample)
+		goto error;
+
+	total = isl_basic_set_total_dim(bset);
+	T = isl_mat_alloc(bset->ctx, 1 + total, 1 + total - (sample->size - 1));
+	if (!T)
+		goto error;
+
+	for (i = 0; i < sample->size; ++i) {
+		isl_int_set(T->row[i][0], sample->el[i]);
+		isl_seq_clr(T->row[i] + 1, T->n_col - 1);
+	}
+	for (i = 0; i < T->n_col - 1; ++i) {
+		isl_seq_clr(T->row[sample->size + i], T->n_col);
+		isl_int_set_si(T->row[sample->size + i][1 + i], 1);
+	}
+	isl_vec_free(sample);
+
+	bset = isl_basic_set_preimage(bset, T);
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	isl_vec_free(sample);
+	return NULL;
+}
+
+/* Given a basic set "bset", return any (possibly non-integer) point
+ * in the basic set.
+ */
+static __isl_give isl_vec *rational_sample(__isl_take isl_basic_set *bset)
+{
+	struct isl_tab *tab;
+	struct isl_vec *sample;
+
+	if (!bset)
+		return NULL;
+
+	tab = isl_tab_from_basic_set(bset, 0);
+	sample = isl_tab_get_sample_value(tab);
+	isl_tab_free(tab);
+
+	isl_basic_set_free(bset);
+
+	return sample;
+}
+
+/* Given a linear cone "cone" and a rational point "vec",
+ * construct a polyhedron with shifted copies of the constraints in "cone",
+ * i.e., a polyhedron with "cone" as its recession cone, such that each
+ * point x in this polyhedron is such that the unit box positioned at x
+ * lies entirely inside the affine cone 'vec + cone'.
+ * Any rational point in this polyhedron may therefore be rounded up
+ * to yield an integer point that lies inside said affine cone.
+ *
+ * Denote the constraints of cone by "<a_i, x> >= 0" and the rational
+ * point "vec" by v/d.
+ * Let b_i = <a_i, v>.  Then the affine cone 'vec + cone' is given
+ * by <a_i, x> - b/d >= 0.
+ * The polyhedron <a_i, x> - ceil{b/d} >= 0 is a subset of this affine cone.
+ * We prefer this polyhedron over the actual affine cone because it doesn't
+ * require a scaling of the constraints.
+ * If each of the vertices of the unit cube positioned at x lies inside
+ * this polyhedron, then the whole unit cube at x lies inside the affine cone.
+ * We therefore impose that x' = x + \sum e_i, for any selection of unit
+ * vectors lies inside the polyhedron, i.e.,
+ *
+ *	<a_i, x'> - ceil{b/d} = <a_i, x> + sum a_i - ceil{b/d} >= 0
+ *
+ * The most stringent of these constraints is the one that selects
+ * all negative a_i, so the polyhedron we are looking for has constraints
+ *
+ *	<a_i, x> + sum_{a_i < 0} a_i - ceil{b/d} >= 0
+ *
+ * Note that if cone were known to have only non-negative rays
+ * (which can be accomplished by a unimodular transformation),
+ * then we would only have to check the points x' = x + e_i
+ * and we only have to add the smallest negative a_i (if any)
+ * instead of the sum of all negative a_i.
+ */
+static __isl_give isl_basic_set *shift_cone(__isl_take isl_basic_set *cone,
+	__isl_take isl_vec *vec)
+{
+	int i, j, k;
+	unsigned total;
+
+	struct isl_basic_set *shift = NULL;
+
+	if (!cone || !vec)
+		goto error;
+
+	isl_assert(cone->ctx, cone->n_eq == 0, goto error);
+
+	total = isl_basic_set_total_dim(cone);
+
+	shift = isl_basic_set_alloc_space(isl_basic_set_get_space(cone),
+					0, 0, cone->n_ineq);
+
+	for (i = 0; i < cone->n_ineq; ++i) {
+		k = isl_basic_set_alloc_inequality(shift);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(shift->ineq[k] + 1, cone->ineq[i] + 1, total);
+		isl_seq_inner_product(shift->ineq[k] + 1, vec->el + 1, total,
+				      &shift->ineq[k][0]);
+		isl_int_cdiv_q(shift->ineq[k][0],
+			       shift->ineq[k][0], vec->el[0]);
+		isl_int_neg(shift->ineq[k][0], shift->ineq[k][0]);
+		for (j = 0; j < total; ++j) {
+			if (isl_int_is_nonneg(shift->ineq[k][1 + j]))
+				continue;
+			isl_int_add(shift->ineq[k][0],
+				    shift->ineq[k][0], shift->ineq[k][1 + j]);
+		}
+	}
+
+	isl_basic_set_free(cone);
+	isl_vec_free(vec);
+
+	return isl_basic_set_finalize(shift);
+error:
+	isl_basic_set_free(shift);
+	isl_basic_set_free(cone);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+/* Given a rational point vec in a (transformed) basic set,
+ * such that cone is the recession cone of the original basic set,
+ * "round up" the rational point to an integer point.
+ *
+ * We first check if the rational point just happens to be integer.
+ * If not, we transform the cone in the same way as the basic set,
+ * pick a point x in this cone shifted to the rational point such that
+ * the whole unit cube at x is also inside this affine cone.
+ * Then we simply round up the coordinates of x and return the
+ * resulting integer point.
+ */
+static __isl_give isl_vec *round_up_in_cone(__isl_take isl_vec *vec,
+	__isl_take isl_basic_set *cone, __isl_take isl_mat *U)
+{
+	unsigned total;
+
+	if (!vec || !cone || !U)
+		goto error;
+
+	isl_assert(vec->ctx, vec->size != 0, goto error);
+	if (isl_int_is_one(vec->el[0])) {
+		isl_mat_free(U);
+		isl_basic_set_free(cone);
+		return vec;
+	}
+
+	total = isl_basic_set_total_dim(cone);
+	cone = isl_basic_set_preimage(cone, U);
+	cone = isl_basic_set_remove_dims(cone, isl_dim_set,
+					 0, total - (vec->size - 1));
+
+	cone = shift_cone(cone, vec);
+
+	vec = rational_sample(cone);
+	vec = isl_vec_ceil(vec);
+	return vec;
+error:
+	isl_mat_free(U);
+	isl_vec_free(vec);
+	isl_basic_set_free(cone);
+	return NULL;
+}
+
+/* Concatenate two integer vectors, i.e., two vectors with denominator
+ * (stored in element 0) equal to 1.
+ */
+static __isl_give isl_vec *vec_concat(__isl_take isl_vec *vec1,
+	__isl_take isl_vec *vec2)
+{
+	struct isl_vec *vec;
+
+	if (!vec1 || !vec2)
+		goto error;
+	isl_assert(vec1->ctx, vec1->size > 0, goto error);
+	isl_assert(vec2->ctx, vec2->size > 0, goto error);
+	isl_assert(vec1->ctx, isl_int_is_one(vec1->el[0]), goto error);
+	isl_assert(vec2->ctx, isl_int_is_one(vec2->el[0]), goto error);
+
+	vec = isl_vec_alloc(vec1->ctx, vec1->size + vec2->size - 1);
+	if (!vec)
+		goto error;
+
+	isl_seq_cpy(vec->el, vec1->el, vec1->size);
+	isl_seq_cpy(vec->el + vec1->size, vec2->el + 1, vec2->size - 1);
+
+	isl_vec_free(vec1);
+	isl_vec_free(vec2);
+
+	return vec;
+error:
+	isl_vec_free(vec1);
+	isl_vec_free(vec2);
+	return NULL;
+}
+
+/* Give a basic set "bset" with recession cone "cone", compute and
+ * return an integer point in bset, if any.
+ *
+ * If the recession cone is full-dimensional, then we know that
+ * bset contains an infinite number of integer points and it is
+ * fairly easy to pick one of them.
+ * If the recession cone is not full-dimensional, then we first
+ * transform bset such that the bounded directions appear as
+ * the first dimensions of the transformed basic set.
+ * We do this by using a unimodular transformation that transforms
+ * the equalities in the recession cone to equalities on the first
+ * dimensions.
+ *
+ * The transformed set is then projected onto its bounded dimensions.
+ * Note that to compute this projection, we can simply drop all constraints
+ * involving any of the unbounded dimensions since these constraints
+ * cannot be combined to produce a constraint on the bounded dimensions.
+ * To see this, assume that there is such a combination of constraints
+ * that produces a constraint on the bounded dimensions.  This means
+ * that some combination of the unbounded dimensions has both an upper
+ * bound and a lower bound in terms of the bounded dimensions, but then
+ * this combination would be a bounded direction too and would have been
+ * transformed into a bounded dimensions.
+ *
+ * We then compute a sample value in the bounded dimensions.
+ * If no such value can be found, then the original set did not contain
+ * any integer points and we are done.
+ * Otherwise, we plug in the value we found in the bounded dimensions,
+ * project out these bounded dimensions and end up with a set with
+ * a full-dimensional recession cone.
+ * A sample point in this set is computed by "rounding up" any
+ * rational point in the set.
+ *
+ * The sample points in the bounded and unbounded dimensions are
+ * then combined into a single sample point and transformed back
+ * to the original space.
+ */
+__isl_give isl_vec *isl_basic_set_sample_with_cone(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *cone)
+{
+	unsigned total;
+	unsigned cone_dim;
+	struct isl_mat *M, *U;
+	struct isl_vec *sample;
+	struct isl_vec *cone_sample;
+	struct isl_ctx *ctx;
+	struct isl_basic_set *bounded;
+
+	if (!bset || !cone)
+		goto error;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	total = isl_basic_set_total_dim(cone);
+	cone_dim = total - cone->n_eq;
+
+	M = isl_mat_sub_alloc6(ctx, cone->eq, 0, cone->n_eq, 1, total);
+	M = isl_mat_left_hermite(M, 0, &U, NULL);
+	if (!M)
+		goto error;
+	isl_mat_free(M);
+
+	U = isl_mat_lin_to_aff(U);
+	bset = isl_basic_set_preimage(bset, isl_mat_copy(U));
+
+	bounded = isl_basic_set_copy(bset);
+	bounded = isl_basic_set_drop_constraints_involving(bounded,
+						   total - cone_dim, cone_dim);
+	bounded = isl_basic_set_drop_dims(bounded, total - cone_dim, cone_dim);
+	sample = sample_bounded(bounded);
+	if (!sample || sample->size == 0) {
+		isl_basic_set_free(bset);
+		isl_basic_set_free(cone);
+		isl_mat_free(U);
+		return sample;
+	}
+	bset = plug_in(bset, isl_vec_copy(sample));
+	cone_sample = rational_sample(bset);
+	cone_sample = round_up_in_cone(cone_sample, cone, isl_mat_copy(U));
+	sample = vec_concat(sample, cone_sample);
+	sample = isl_mat_vec_product(U, sample);
+	return sample;
+error:
+	isl_basic_set_free(cone);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+static void vec_sum_of_neg(struct isl_vec *v, isl_int *s)
+{
+	int i;
+
+	isl_int_set_si(*s, 0);
+
+	for (i = 0; i < v->size; ++i)
+		if (isl_int_is_neg(v->el[i]))
+			isl_int_add(*s, *s, v->el[i]);
+}
+
+/* Given a tableau "tab", a tableau "tab_cone" that corresponds
+ * to the recession cone and the inverse of a new basis U = inv(B),
+ * with the unbounded directions in B last,
+ * add constraints to "tab" that ensure any rational value
+ * in the unbounded directions can be rounded up to an integer value.
+ *
+ * The new basis is given by x' = B x, i.e., x = U x'.
+ * For any rational value of the last tab->n_unbounded coordinates
+ * in the update tableau, the value that is obtained by rounding
+ * up this value should be contained in the original tableau.
+ * For any constraint "a x + c >= 0", we therefore need to add
+ * a constraint "a x + c + s >= 0", with s the sum of all negative
+ * entries in the last elements of "a U".
+ *
+ * Since we are not interested in the first entries of any of the "a U",
+ * we first drop the columns of U that correpond to bounded directions.
+ */
+static int tab_shift_cone(struct isl_tab *tab,
+	struct isl_tab *tab_cone, struct isl_mat *U)
+{
+	int i;
+	isl_int v;
+	struct isl_basic_set *bset = NULL;
+
+	if (tab && tab->n_unbounded == 0) {
+		isl_mat_free(U);
+		return 0;
+	}
+	isl_int_init(v);
+	if (!tab || !tab_cone || !U)
+		goto error;
+	bset = isl_tab_peek_bset(tab_cone);
+	U = isl_mat_drop_cols(U, 0, tab->n_var - tab->n_unbounded);
+	for (i = 0; i < bset->n_ineq; ++i) {
+		int ok;
+		struct isl_vec *row = NULL;
+		if (isl_tab_is_equality(tab_cone, tab_cone->n_eq + i))
+			continue;
+		row = isl_vec_alloc(bset->ctx, tab_cone->n_var);
+		if (!row)
+			goto error;
+		isl_seq_cpy(row->el, bset->ineq[i] + 1, tab_cone->n_var);
+		row = isl_vec_mat_product(row, isl_mat_copy(U));
+		if (!row)
+			goto error;
+		vec_sum_of_neg(row, &v);
+		isl_vec_free(row);
+		if (isl_int_is_zero(v))
+			continue;
+		if (isl_tab_extend_cons(tab, 1) < 0)
+			goto error;
+		isl_int_add(bset->ineq[i][0], bset->ineq[i][0], v);
+		ok = isl_tab_add_ineq(tab, bset->ineq[i]) >= 0;
+		isl_int_sub(bset->ineq[i][0], bset->ineq[i][0], v);
+		if (!ok)
+			goto error;
+	}
+
+	isl_mat_free(U);
+	isl_int_clear(v);
+	return 0;
+error:
+	isl_mat_free(U);
+	isl_int_clear(v);
+	return -1;
+}
+
+/* Compute and return an initial basis for the possibly
+ * unbounded tableau "tab".  "tab_cone" is a tableau
+ * for the corresponding recession cone.
+ * Additionally, add constraints to "tab" that ensure
+ * that any rational value for the unbounded directions
+ * can be rounded up to an integer value.
+ *
+ * If the tableau is bounded, i.e., if the recession cone
+ * is zero-dimensional, then we just use inital_basis.
+ * Otherwise, we construct a basis whose first directions
+ * correspond to equalities, followed by bounded directions,
+ * i.e., equalities in the recession cone.
+ * The remaining directions are then unbounded.
+ */
+int isl_tab_set_initial_basis_with_cone(struct isl_tab *tab,
+	struct isl_tab *tab_cone)
+{
+	struct isl_mat *eq;
+	struct isl_mat *cone_eq;
+	struct isl_mat *U, *Q;
+
+	if (!tab || !tab_cone)
+		return -1;
+
+	if (tab_cone->n_col == tab_cone->n_dead) {
+		tab->basis = initial_basis(tab);
+		return tab->basis ? 0 : -1;
+	}
+
+	eq = tab_equalities(tab);
+	if (!eq)
+		return -1;
+	tab->n_zero = eq->n_row;
+	cone_eq = tab_equalities(tab_cone);
+	eq = isl_mat_concat(eq, cone_eq);
+	if (!eq)
+		return -1;
+	tab->n_unbounded = tab->n_var - (eq->n_row - tab->n_zero);
+	eq = isl_mat_left_hermite(eq, 0, &U, &Q);
+	if (!eq)
+		return -1;
+	isl_mat_free(eq);
+	tab->basis = isl_mat_lin_to_aff(Q);
+	if (tab_shift_cone(tab, tab_cone, U) < 0)
+		return -1;
+	if (!tab->basis)
+		return -1;
+	return 0;
+}
+
+/* Compute and return a sample point in bset using generalized basis
+ * reduction.  We first check if the input set has a non-trivial
+ * recession cone.  If so, we perform some extra preprocessing in
+ * sample_with_cone.  Otherwise, we directly perform generalized basis
+ * reduction.
+ */
+static __isl_give isl_vec *gbr_sample(__isl_take isl_basic_set *bset)
+{
+	unsigned dim;
+	struct isl_basic_set *cone;
+
+	dim = isl_basic_set_total_dim(bset);
+
+	cone = isl_basic_set_recession_cone(isl_basic_set_copy(bset));
+	if (!cone)
+		goto error;
+
+	if (cone->n_eq < dim)
+		return isl_basic_set_sample_with_cone(bset, cone);
+
+	isl_basic_set_free(cone);
+	return sample_bounded(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+static __isl_give isl_vec *basic_set_sample(__isl_take isl_basic_set *bset,
+	int bounded)
+{
+	struct isl_ctx *ctx;
+	unsigned dim;
+	if (!bset)
+		return NULL;
+
+	ctx = bset->ctx;
+	if (isl_basic_set_plain_is_empty(bset))
+		return empty_sample(bset);
+
+	dim = isl_basic_set_n_dim(bset);
+	isl_assert(ctx, isl_basic_set_n_param(bset) == 0, goto error);
+	isl_assert(ctx, bset->n_div == 0, goto error);
+
+	if (bset->sample && bset->sample->size == 1 + dim) {
+		int contains = isl_basic_set_contains(bset, bset->sample);
+		if (contains < 0)
+			goto error;
+		if (contains) {
+			struct isl_vec *sample = isl_vec_copy(bset->sample);
+			isl_basic_set_free(bset);
+			return sample;
+		}
+	}
+	isl_vec_free(bset->sample);
+	bset->sample = NULL;
+
+	if (bset->n_eq > 0)
+		return sample_eq(bset, bounded ? isl_basic_set_sample_bounded
+					       : isl_basic_set_sample_vec);
+	if (dim == 0)
+		return zero_sample(bset);
+	if (dim == 1)
+		return interval_sample(bset);
+
+	return bounded ? sample_bounded(bset) : gbr_sample(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+__isl_give isl_vec *isl_basic_set_sample_vec(__isl_take isl_basic_set *bset)
+{
+	return basic_set_sample(bset, 0);
+}
+
+/* Compute an integer sample in "bset", where the caller guarantees
+ * that "bset" is bounded.
+ */
+__isl_give isl_vec *isl_basic_set_sample_bounded(__isl_take isl_basic_set *bset)
+{
+	return basic_set_sample(bset, 1);
+}
+
+__isl_give isl_basic_set *isl_basic_set_from_vec(__isl_take isl_vec *vec)
+{
+	int i;
+	int k;
+	struct isl_basic_set *bset = NULL;
+	struct isl_ctx *ctx;
+	unsigned dim;
+
+	if (!vec)
+		return NULL;
+	ctx = vec->ctx;
+	isl_assert(ctx, vec->size != 0, goto error);
+
+	bset = isl_basic_set_alloc(ctx, 0, vec->size - 1, 0, vec->size - 1, 0);
+	if (!bset)
+		goto error;
+	dim = isl_basic_set_n_dim(bset);
+	for (i = dim - 1; i >= 0; --i) {
+		k = isl_basic_set_alloc_equality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bset->eq[k], 1 + dim);
+		isl_int_neg(bset->eq[k][0], vec->el[1 + i]);
+		isl_int_set(bset->eq[k][1 + i], vec->el[0]);
+	}
+	bset->sample = vec;
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	isl_vec_free(vec);
+	return NULL;
+}
+
+__isl_give isl_basic_map *isl_basic_map_sample(__isl_take isl_basic_map *bmap)
+{
+	struct isl_basic_set *bset;
+	struct isl_vec *sample_vec;
+
+	bset = isl_basic_map_underlying_set(isl_basic_map_copy(bmap));
+	sample_vec = isl_basic_set_sample_vec(bset);
+	if (!sample_vec)
+		goto error;
+	if (sample_vec->size == 0) {
+		isl_vec_free(sample_vec);
+		return isl_basic_map_set_to_empty(bmap);
+	}
+	isl_vec_free(bmap->sample);
+	bmap->sample = isl_vec_copy(sample_vec);
+	bset = isl_basic_set_from_vec(sample_vec);
+	return isl_basic_map_overlying_set(bset, bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_sample(__isl_take isl_basic_set *bset)
+{
+	return isl_basic_map_sample(bset);
+}
+
+__isl_give isl_basic_map *isl_map_sample(__isl_take isl_map *map)
+{
+	int i;
+	isl_basic_map *sample = NULL;
+
+	if (!map)
+		goto error;
+
+	for (i = 0; i < map->n; ++i) {
+		sample = isl_basic_map_sample(isl_basic_map_copy(map->p[i]));
+		if (!sample)
+			goto error;
+		if (!ISL_F_ISSET(sample, ISL_BASIC_MAP_EMPTY))
+			break;
+		isl_basic_map_free(sample);
+	}
+	if (i == map->n)
+		sample = isl_basic_map_empty(isl_map_get_space(map));
+	isl_map_free(map);
+	return sample;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_set_sample(__isl_take isl_set *set)
+{
+	return bset_from_bmap(isl_map_sample(set_to_map(set)));
+}
+
+__isl_give isl_point *isl_basic_set_sample_point(__isl_take isl_basic_set *bset)
+{
+	isl_vec *vec;
+	isl_space *dim;
+
+	dim = isl_basic_set_get_space(bset);
+	bset = isl_basic_set_underlying_set(bset);
+	vec = isl_basic_set_sample_vec(bset);
+
+	return isl_point_alloc(dim, vec);
+}
+
+__isl_give isl_point *isl_set_sample_point(__isl_take isl_set *set)
+{
+	int i;
+	isl_point *pnt;
+
+	if (!set)
+		return NULL;
+
+	for (i = 0; i < set->n; ++i) {
+		pnt = isl_basic_set_sample_point(isl_basic_set_copy(set->p[i]));
+		if (!pnt)
+			goto error;
+		if (!isl_point_is_void(pnt))
+			break;
+		isl_point_free(pnt);
+	}
+	if (i == set->n)
+		pnt = isl_point_void(isl_set_get_space(set));
+
+	isl_set_free(set);
+	return pnt;
+error:
+	isl_set_free(set);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_sample.h b/final/lib/External/isl/isl_sample.h
new file mode 100644
index 0000000..1357946
--- /dev/null
+++ b/final/lib/External/isl/isl_sample.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_SAMPLE_H
+#define ISL_SAMPLE_H
+
+#include <isl/set.h>
+#include <isl_tab.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+__isl_give isl_vec *isl_basic_set_sample_vec(__isl_take isl_basic_set *bset);
+__isl_give isl_vec *isl_basic_set_sample_bounded(
+	__isl_take isl_basic_set *bset);
+__isl_give isl_vec *isl_basic_set_sample_with_cone(
+	__isl_take isl_basic_set *bset, __isl_take isl_basic_set *cone);
+
+__isl_give isl_basic_set *isl_basic_set_from_vec(__isl_take isl_vec *vec);
+
+int isl_tab_set_initial_basis_with_cone(struct isl_tab *tab,
+	struct isl_tab *tab_cone);
+struct isl_vec *isl_tab_sample(struct isl_tab *tab);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/isl_scan.c b/final/lib/External/isl/isl_scan.c
new file mode 100644
index 0000000..fea42f1
--- /dev/null
+++ b/final/lib/External/isl/isl_scan.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include "isl_basis_reduction.h"
+#include "isl_scan.h"
+#include <isl_seq.h>
+#include "isl_tab.h"
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+
+struct isl_counter {
+	struct isl_scan_callback callback;
+	isl_int count;
+	isl_int max;
+};
+
+static isl_stat increment_counter(struct isl_scan_callback *cb,
+	__isl_take isl_vec *sample)
+{
+	struct isl_counter *cnt = (struct isl_counter *)cb;
+
+	isl_int_add_ui(cnt->count, cnt->count, 1);
+
+	isl_vec_free(sample);
+
+	if (isl_int_is_zero(cnt->max) || isl_int_lt(cnt->count, cnt->max))
+		return isl_stat_ok;
+	return isl_stat_error;
+}
+
+static int increment_range(struct isl_scan_callback *cb, isl_int min, isl_int max)
+{
+	struct isl_counter *cnt = (struct isl_counter *)cb;
+
+	isl_int_add(cnt->count, cnt->count, max);
+	isl_int_sub(cnt->count, cnt->count, min);
+	isl_int_add_ui(cnt->count, cnt->count, 1);
+
+	if (isl_int_is_zero(cnt->max) || isl_int_lt(cnt->count, cnt->max))
+		return 0;
+	isl_int_set(cnt->count, cnt->max);
+	return -1;
+}
+
+/* Call callback->add with the current sample value of the tableau "tab".
+ */
+static int add_solution(struct isl_tab *tab, struct isl_scan_callback *callback)
+{
+	struct isl_vec *sample;
+
+	if (!tab)
+		return -1;
+	sample = isl_tab_get_sample_value(tab);
+	if (!sample)
+		return -1;
+
+	return callback->add(callback, sample);
+}
+
+static isl_stat scan_0D(__isl_take isl_basic_set *bset,
+	struct isl_scan_callback *callback)
+{
+	struct isl_vec *sample;
+
+	sample = isl_vec_alloc(bset->ctx, 1);
+	isl_basic_set_free(bset);
+
+	if (!sample)
+		return isl_stat_error;
+
+	isl_int_set_si(sample->el[0], 1);
+
+	return callback->add(callback, sample);
+}
+
+/* Look for all integer points in "bset", which is assumed to be bounded,
+ * and call callback->add on each of them.
+ *
+ * We first compute a reduced basis for the set and then scan
+ * the set in the directions of this basis.
+ * We basically perform a depth first search, where in each level i
+ * we compute the range in the i-th basis vector direction, given
+ * fixed values in the directions of the previous basis vector.
+ * We then add an equality to the tableau fixing the value in the
+ * direction of the current basis vector to each value in the range
+ * in turn and then continue to the next level.
+ *
+ * The search is implemented iteratively.  "level" identifies the current
+ * basis vector.  "init" is true if we want the first value at the current
+ * level and false if we want the next value.
+ * Solutions are added in the leaves of the search tree, i.e., after
+ * we have fixed a value in each direction of the basis.
+ */
+isl_stat isl_basic_set_scan(__isl_take isl_basic_set *bset,
+	struct isl_scan_callback *callback)
+{
+	unsigned dim;
+	struct isl_mat *B = NULL;
+	struct isl_tab *tab = NULL;
+	struct isl_vec *min;
+	struct isl_vec *max;
+	struct isl_tab_undo **snap;
+	int level;
+	int init;
+	enum isl_lp_result res;
+
+	if (!bset)
+		return isl_stat_error;
+
+	dim = isl_basic_set_total_dim(bset);
+	if (dim == 0)
+		return scan_0D(bset, callback);
+
+	min = isl_vec_alloc(bset->ctx, dim);
+	max = isl_vec_alloc(bset->ctx, dim);
+	snap = isl_alloc_array(bset->ctx, struct isl_tab_undo *, dim);
+
+	if (!min || !max || !snap)
+		goto error;
+
+	tab = isl_tab_from_basic_set(bset, 0);
+	if (!tab)
+		goto error;
+	if (isl_tab_extend_cons(tab, dim + 1) < 0)
+		goto error;
+
+	tab->basis = isl_mat_identity(bset->ctx, 1 + dim);
+	if (1)
+		tab = isl_tab_compute_reduced_basis(tab);
+	if (!tab)
+		goto error;
+	B = isl_mat_copy(tab->basis);
+	if (!B)
+		goto error;
+
+	level = 0;
+	init = 1;
+
+	while (level >= 0) {
+		int empty = 0;
+		if (init) {
+			res = isl_tab_min(tab, B->row[1 + level],
+				    bset->ctx->one, &min->el[level], NULL, 0);
+			if (res == isl_lp_empty)
+				empty = 1;
+			if (res == isl_lp_error || res == isl_lp_unbounded)
+				goto error;
+			isl_seq_neg(B->row[1 + level] + 1,
+				    B->row[1 + level] + 1, dim);
+			res = isl_tab_min(tab, B->row[1 + level],
+				    bset->ctx->one, &max->el[level], NULL, 0);
+			isl_seq_neg(B->row[1 + level] + 1,
+				    B->row[1 + level] + 1, dim);
+			isl_int_neg(max->el[level], max->el[level]);
+			if (res == isl_lp_empty)
+				empty = 1;
+			if (res == isl_lp_error || res == isl_lp_unbounded)
+				goto error;
+			snap[level] = isl_tab_snap(tab);
+		} else
+			isl_int_add_ui(min->el[level], min->el[level], 1);
+
+		if (empty || isl_int_gt(min->el[level], max->el[level])) {
+			level--;
+			init = 0;
+			if (level >= 0)
+				if (isl_tab_rollback(tab, snap[level]) < 0)
+					goto error;
+			continue;
+		}
+		if (level == dim - 1 && callback->add == increment_counter) {
+			if (increment_range(callback,
+					    min->el[level], max->el[level]))
+				goto error;
+			level--;
+			init = 0;
+			if (level >= 0)
+				if (isl_tab_rollback(tab, snap[level]) < 0)
+					goto error;
+			continue;
+		}
+		isl_int_neg(B->row[1 + level][0], min->el[level]);
+		if (isl_tab_add_valid_eq(tab, B->row[1 + level]) < 0)
+			goto error;
+		isl_int_set_si(B->row[1 + level][0], 0);
+		if (level < dim - 1) {
+			++level;
+			init = 1;
+			continue;
+		}
+		if (add_solution(tab, callback) < 0)
+			goto error;
+		init = 0;
+		if (isl_tab_rollback(tab, snap[level]) < 0)
+			goto error;
+	}
+
+	isl_tab_free(tab);
+	free(snap);
+	isl_vec_free(min);
+	isl_vec_free(max);
+	isl_basic_set_free(bset);
+	isl_mat_free(B);
+	return isl_stat_ok;
+error:
+	isl_tab_free(tab);
+	free(snap);
+	isl_vec_free(min);
+	isl_vec_free(max);
+	isl_basic_set_free(bset);
+	isl_mat_free(B);
+	return isl_stat_error;
+}
+
+isl_stat isl_set_scan(__isl_take isl_set *set,
+	struct isl_scan_callback *callback)
+{
+	int i;
+
+	if (!set || !callback)
+		goto error;
+
+	set = isl_set_cow(set);
+	set = isl_set_make_disjoint(set);
+	set = isl_set_compute_divs(set);
+	if (!set)
+		goto error;
+
+	for (i = 0; i < set->n; ++i)
+		if (isl_basic_set_scan(isl_basic_set_copy(set->p[i]),
+					callback) < 0)
+			goto error;
+
+	isl_set_free(set);
+	return isl_stat_ok;
+error:
+	isl_set_free(set);
+	return isl_stat_error;
+}
+
+int isl_basic_set_count_upto(__isl_keep isl_basic_set *bset,
+	isl_int max, isl_int *count)
+{
+	struct isl_counter cnt = { { &increment_counter } };
+
+	if (!bset)
+		return -1;
+
+	isl_int_init(cnt.count);
+	isl_int_init(cnt.max);
+
+	isl_int_set_si(cnt.count, 0);
+	isl_int_set(cnt.max, max);
+	if (isl_basic_set_scan(isl_basic_set_copy(bset), &cnt.callback) < 0 &&
+	    isl_int_lt(cnt.count, cnt.max))
+		goto error;
+
+	isl_int_set(*count, cnt.count);
+	isl_int_clear(cnt.max);
+	isl_int_clear(cnt.count);
+
+	return 0;
+error:
+	isl_int_clear(cnt.count);
+	return -1;
+}
+
+int isl_set_count_upto(__isl_keep isl_set *set, isl_int max, isl_int *count)
+{
+	struct isl_counter cnt = { { &increment_counter } };
+
+	if (!set)
+		return -1;
+
+	isl_int_init(cnt.count);
+	isl_int_init(cnt.max);
+
+	isl_int_set_si(cnt.count, 0);
+	isl_int_set(cnt.max, max);
+	if (isl_set_scan(isl_set_copy(set), &cnt.callback) < 0 &&
+	    isl_int_lt(cnt.count, cnt.max))
+		goto error;
+
+	isl_int_set(*count, cnt.count);
+	isl_int_clear(cnt.max);
+	isl_int_clear(cnt.count);
+
+	return 0;
+error:
+	isl_int_clear(cnt.count);
+	return -1;
+}
+
+int isl_set_count(__isl_keep isl_set *set, isl_int *count)
+{
+	if (!set)
+		return -1;
+	return isl_set_count_upto(set, set->ctx->zero, count);
+}
+
+/* Count the total number of elements in "set" (in an inefficient way) and
+ * return the result.
+ */
+__isl_give isl_val *isl_set_count_val(__isl_keep isl_set *set)
+{
+	isl_val *v;
+
+	if (!set)
+		return NULL;
+	v = isl_val_zero(isl_set_get_ctx(set));
+	v = isl_val_cow(v);
+	if (!v)
+		return NULL;
+	if (isl_set_count(set, &v->n) < 0)
+		v = isl_val_free(v);
+	return v;
+}
diff --git a/final/lib/External/isl/isl_scan.h b/final/lib/External/isl/isl_scan.h
new file mode 100644
index 0000000..f2a5100
--- /dev/null
+++ b/final/lib/External/isl/isl_scan.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_SCAN_H
+#define ISL_SCAN_H
+
+#include <isl/set.h>
+#include <isl/vec.h>
+
+struct isl_scan_callback {
+	isl_stat (*add)(struct isl_scan_callback *cb,
+		__isl_take isl_vec *sample);
+};
+
+isl_stat isl_basic_set_scan(__isl_take isl_basic_set *bset,
+	struct isl_scan_callback *callback);
+isl_stat isl_set_scan(__isl_take isl_set *set,
+	struct isl_scan_callback *callback);
+
+#endif
diff --git a/final/lib/External/isl/isl_schedule.c b/final/lib/External/isl/isl_schedule.c
new file mode 100644
index 0000000..90d8d5d
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule.c
@@ -0,0 +1,1155 @@
+/*
+ * Copyright 2011      INRIA Saclay
+ * Copyright 2012-2014 Ecole Normale Superieure
+ * Copyright 2016      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl/ctx.h>
+#include <isl_aff_private.h>
+#include <isl/map.h>
+#include <isl/set.h>
+#include <isl/schedule.h>
+#include <isl/schedule_node.h>
+#include <isl_sort.h>
+#include <isl_schedule_private.h>
+#include <isl_schedule_tree.h>
+#include <isl_schedule_node_private.h>
+#include <isl_band_private.h>
+
+/* Return a schedule encapsulating the given schedule tree.
+ *
+ * We currently only allow schedule trees with a domain or extension as root.
+ *
+ * The leaf field is initialized as a leaf node so that it can be
+ * used to represent leaves in the constructed schedule.
+ * The reference count is set to -1 since the isl_schedule_tree
+ * should never be freed.  It is up to the (internal) users of
+ * these leaves to ensure that they are only used while the schedule
+ * is still alive.
+ */
+__isl_give isl_schedule *isl_schedule_from_schedule_tree(isl_ctx *ctx,
+	__isl_take isl_schedule_tree *tree)
+{
+	enum isl_schedule_node_type type;
+	isl_schedule *schedule;
+
+	if (!tree)
+		return NULL;
+	type = isl_schedule_tree_get_type(tree);
+	if (type != isl_schedule_node_domain &&
+	    type != isl_schedule_node_extension)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported,
+			"root of schedule tree should be a domain or extension",
+			goto error);
+
+	schedule = isl_calloc_type(ctx, isl_schedule);
+	if (!schedule)
+		goto error;
+
+	schedule->ref = 1;
+	schedule->root = tree;
+	schedule->leaf = isl_schedule_tree_leaf(ctx);
+
+	if (!schedule->leaf)
+		return isl_schedule_free(schedule);
+	return schedule;
+error:
+	isl_schedule_tree_free(tree);
+	return NULL;
+}
+
+/* Return a pointer to a schedule with as single node
+ * a domain node with the given domain.
+ */
+__isl_give isl_schedule *isl_schedule_from_domain(
+	__isl_take isl_union_set *domain)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+
+	ctx = isl_union_set_get_ctx(domain);
+	tree = isl_schedule_tree_from_domain(domain);
+	return isl_schedule_from_schedule_tree(ctx, tree);
+}
+
+/* Return a pointer to a schedule with as single node
+ * a domain node with an empty domain.
+ */
+__isl_give isl_schedule *isl_schedule_empty(__isl_take isl_space *space)
+{
+	return isl_schedule_from_domain(isl_union_set_empty(space));
+}
+
+/* Return a new reference to "sched".
+ */
+__isl_give isl_schedule *isl_schedule_copy(__isl_keep isl_schedule *sched)
+{
+	if (!sched)
+		return NULL;
+
+	sched->ref++;
+	return sched;
+}
+
+/* Return an isl_schedule that is equal to "schedule" and that has only
+ * a single reference.
+ *
+ * We only need and support this function when the schedule is represented
+ * as a schedule tree.
+ */
+__isl_give isl_schedule *isl_schedule_cow(__isl_take isl_schedule *schedule)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+
+	if (!schedule)
+		return NULL;
+	if (schedule->ref == 1)
+		return schedule;
+
+	ctx = isl_schedule_get_ctx(schedule);
+	if (!schedule->root)
+		isl_die(ctx, isl_error_internal,
+			"only for schedule tree based schedules",
+			return isl_schedule_free(schedule));
+	schedule->ref--;
+	tree = isl_schedule_tree_copy(schedule->root);
+	return isl_schedule_from_schedule_tree(ctx, tree);
+}
+
+__isl_null isl_schedule *isl_schedule_free(__isl_take isl_schedule *sched)
+{
+	if (!sched)
+		return NULL;
+
+	if (--sched->ref > 0)
+		return NULL;
+
+	isl_band_list_free(sched->band_forest);
+	isl_schedule_tree_free(sched->root);
+	isl_schedule_tree_free(sched->leaf);
+	free(sched);
+	return NULL;
+}
+
+/* Replace the root of "schedule" by "tree".
+ */
+__isl_give isl_schedule *isl_schedule_set_root(
+	__isl_take isl_schedule *schedule, __isl_take isl_schedule_tree *tree)
+{
+	if (!schedule || !tree)
+		goto error;
+	if (schedule->root == tree) {
+		isl_schedule_tree_free(tree);
+		return schedule;
+	}
+
+	schedule = isl_schedule_cow(schedule);
+	if (!schedule)
+		goto error;
+	isl_schedule_tree_free(schedule->root);
+	schedule->root = tree;
+
+	return schedule;
+error:
+	isl_schedule_free(schedule);
+	isl_schedule_tree_free(tree);
+	return NULL;
+}
+
+isl_ctx *isl_schedule_get_ctx(__isl_keep isl_schedule *schedule)
+{
+	return schedule ? isl_schedule_tree_get_ctx(schedule->leaf) : NULL;
+}
+
+/* Return a pointer to the leaf of "schedule".
+ */
+__isl_keep isl_schedule_tree *isl_schedule_peek_leaf(
+	__isl_keep isl_schedule *schedule)
+{
+	return schedule ? schedule->leaf : NULL;
+}
+
+/* Are "schedule1" and "schedule2" obviously equal to each other?
+ */
+isl_bool isl_schedule_plain_is_equal(__isl_keep isl_schedule *schedule1,
+	__isl_keep isl_schedule *schedule2)
+{
+	if (!schedule1 || !schedule2)
+		return isl_bool_error;
+	if (schedule1 == schedule2)
+		return isl_bool_true;
+	return isl_schedule_tree_plain_is_equal(schedule1->root,
+						schedule2->root);
+}
+
+/* Return the (parameter) space of the schedule, i.e., the space
+ * of the root domain.
+ */
+__isl_give isl_space *isl_schedule_get_space(
+	__isl_keep isl_schedule *schedule)
+{
+	enum isl_schedule_node_type type;
+	isl_space *space;
+	isl_union_set *domain;
+
+	if (!schedule)
+		return NULL;
+	if (!schedule->root)
+		isl_die(isl_schedule_get_ctx(schedule), isl_error_invalid,
+			"schedule tree representation not available",
+			return NULL);
+	type = isl_schedule_tree_get_type(schedule->root);
+	if (type != isl_schedule_node_domain)
+		isl_die(isl_schedule_get_ctx(schedule), isl_error_internal,
+			"root node not a domain node", return NULL);
+
+	domain = isl_schedule_tree_domain_get_domain(schedule->root);
+	space = isl_union_set_get_space(domain);
+	isl_union_set_free(domain);
+
+	return space;
+}
+
+/* Return a pointer to the root of "schedule".
+ */
+__isl_give isl_schedule_node *isl_schedule_get_root(
+	__isl_keep isl_schedule *schedule)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+	isl_schedule_tree_list *ancestors;
+
+	if (!schedule)
+		return NULL;
+
+	if (!schedule->root)
+		isl_die(isl_schedule_get_ctx(schedule), isl_error_invalid,
+			"schedule tree representation not available",
+			return NULL);
+
+	ctx = isl_schedule_get_ctx(schedule);
+	tree = isl_schedule_tree_copy(schedule->root);
+	schedule = isl_schedule_copy(schedule);
+	ancestors = isl_schedule_tree_list_alloc(ctx, 0);
+	return isl_schedule_node_alloc(schedule, tree, ancestors, NULL);
+}
+
+/* Set max_out to the maximal number of output dimensions over
+ * all maps.
+ */
+static isl_stat update_max_out(__isl_take isl_map *map, void *user)
+{
+	int *max_out = user;
+	int n_out = isl_map_dim(map, isl_dim_out);
+
+	if (n_out > *max_out)
+		*max_out = n_out;
+
+	isl_map_free(map);
+	return isl_stat_ok;
+}
+
+/* Internal data structure for map_pad_range.
+ *
+ * "max_out" is the maximal schedule dimension.
+ * "res" collects the results.
+ */
+struct isl_pad_schedule_map_data {
+	int max_out;
+	isl_union_map *res;
+};
+
+/* Pad the range of the given map with zeros to data->max_out and
+ * then add the result to data->res.
+ */
+static isl_stat map_pad_range(__isl_take isl_map *map, void *user)
+{
+	struct isl_pad_schedule_map_data *data = user;
+	int i;
+	int n_out = isl_map_dim(map, isl_dim_out);
+
+	map = isl_map_add_dims(map, isl_dim_out, data->max_out - n_out);
+	for (i = n_out; i < data->max_out; ++i)
+		map = isl_map_fix_si(map, isl_dim_out, i, 0);
+
+	data->res = isl_union_map_add_map(data->res, map);
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Pad the ranges of the maps in the union map with zeros such they all have
+ * the same dimension.
+ */
+static __isl_give isl_union_map *pad_schedule_map(
+	__isl_take isl_union_map *umap)
+{
+	struct isl_pad_schedule_map_data data;
+
+	if (!umap)
+		return NULL;
+	if (isl_union_map_n_map(umap) <= 1)
+		return umap;
+
+	data.max_out = 0;
+	if (isl_union_map_foreach_map(umap, &update_max_out, &data.max_out) < 0)
+		return isl_union_map_free(umap);
+
+	data.res = isl_union_map_empty(isl_union_map_get_space(umap));
+	if (isl_union_map_foreach_map(umap, &map_pad_range, &data) < 0)
+		data.res = isl_union_map_free(data.res);
+
+	isl_union_map_free(umap);
+	return data.res;
+}
+
+/* Return the domain of the root domain node of "schedule".
+ */
+__isl_give isl_union_set *isl_schedule_get_domain(
+	__isl_keep isl_schedule *schedule)
+{
+	if (!schedule)
+		return NULL;
+	if (!schedule->root)
+		isl_die(isl_schedule_get_ctx(schedule), isl_error_invalid,
+			"schedule tree representation not available",
+			return NULL);
+	return isl_schedule_tree_domain_get_domain(schedule->root);
+}
+
+/* Traverse all nodes of "sched" in depth first preorder.
+ *
+ * If "fn" returns -1 on any of the nodes, then the traversal is aborted.
+ * If "fn" returns 0 on any of the nodes, then the subtree rooted
+ * at that node is skipped.
+ *
+ * Return 0 on success and -1 on failure.
+ */
+isl_stat isl_schedule_foreach_schedule_node_top_down(
+	__isl_keep isl_schedule *sched,
+	isl_bool (*fn)(__isl_keep isl_schedule_node *node, void *user),
+	void *user)
+{
+	isl_schedule_node *node;
+	isl_stat r;
+
+	if (!sched)
+		return isl_stat_error;
+
+	node = isl_schedule_get_root(sched);
+	r = isl_schedule_node_foreach_descendant_top_down(node, fn, user);
+	isl_schedule_node_free(node);
+
+	return r;
+}
+
+/* Traverse the node of "sched" in depth first postorder,
+ * allowing the user to modify the visited node.
+ * The traversal continues from the node returned by the callback function.
+ * It is the responsibility of the user to ensure that this does not
+ * lead to an infinite loop.  It is safest to always return a pointer
+ * to the same position (same ancestors and child positions) as the input node.
+ */
+__isl_give isl_schedule *isl_schedule_map_schedule_node_bottom_up(
+	__isl_take isl_schedule *schedule,
+	__isl_give isl_schedule_node *(*fn)(
+		__isl_take isl_schedule_node *node, void *user), void *user)
+{
+	isl_schedule_node *node;
+
+	node = isl_schedule_get_root(schedule);
+	isl_schedule_free(schedule);
+
+	node = isl_schedule_node_map_descendant_bottom_up(node, fn, user);
+	schedule = isl_schedule_node_get_schedule(node);
+	isl_schedule_node_free(node);
+
+	return schedule;
+}
+
+/* Wrapper around isl_schedule_node_reset_user for use as
+ * an isl_schedule_map_schedule_node_bottom_up callback.
+ */
+static __isl_give isl_schedule_node *reset_user(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	return isl_schedule_node_reset_user(node);
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * in the schedule "schedule".
+ */
+__isl_give isl_schedule *isl_schedule_reset_user(
+	__isl_take isl_schedule *schedule)
+{
+	return isl_schedule_map_schedule_node_bottom_up(schedule, &reset_user,
+							NULL);
+}
+
+/* Wrapper around isl_schedule_node_align_params for use as
+ * an isl_schedule_map_schedule_node_bottom_up callback.
+ */
+static __isl_give isl_schedule_node *align_params(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	isl_space *space = user;
+
+	return isl_schedule_node_align_params(node, isl_space_copy(space));
+}
+
+/* Align the parameters of all nodes in schedule "schedule"
+ * to those of "space".
+ */
+__isl_give isl_schedule *isl_schedule_align_params(
+	__isl_take isl_schedule *schedule, __isl_take isl_space *space)
+{
+	schedule = isl_schedule_map_schedule_node_bottom_up(schedule,
+						    &align_params, space);
+	isl_space_free(space);
+	return schedule;
+}
+
+/* Wrapper around isl_schedule_node_pullback_union_pw_multi_aff for use as
+ * an isl_schedule_map_schedule_node_bottom_up callback.
+ */
+static __isl_give isl_schedule_node *pullback_upma(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	isl_union_pw_multi_aff *upma = user;
+
+	return isl_schedule_node_pullback_union_pw_multi_aff(node,
+					isl_union_pw_multi_aff_copy(upma));
+}
+
+/* Compute the pullback of "schedule" by the function represented by "upma".
+ * In other words, plug in "upma" in the iteration domains of "schedule".
+ *
+ * The schedule tree is not allowed to contain any expansion nodes.
+ */
+__isl_give isl_schedule *isl_schedule_pullback_union_pw_multi_aff(
+	__isl_take isl_schedule *schedule,
+	__isl_take isl_union_pw_multi_aff *upma)
+{
+	schedule = isl_schedule_map_schedule_node_bottom_up(schedule,
+						&pullback_upma, upma);
+	isl_union_pw_multi_aff_free(upma);
+	return schedule;
+}
+
+/* Expand the schedule "schedule" by extending all leaves
+ * with an expansion node with as subtree the tree of "expansion".
+ * The expansion of the expansion node is determined by "contraction"
+ * and the domain of "expansion".  That is, the domain of "expansion"
+ * is contracted according to "contraction".
+ *
+ * Call isl_schedule_node_expand after extracting the required
+ * information from "expansion".
+ */
+__isl_give isl_schedule *isl_schedule_expand(__isl_take isl_schedule *schedule,
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_schedule *expansion)
+{
+	isl_union_set *domain;
+	isl_schedule_node *node;
+	isl_schedule_tree *tree;
+
+	domain = isl_schedule_get_domain(expansion);
+
+	node = isl_schedule_get_root(expansion);
+	node = isl_schedule_node_child(node, 0);
+	tree = isl_schedule_node_get_tree(node);
+	isl_schedule_node_free(node);
+	isl_schedule_free(expansion);
+
+	node = isl_schedule_get_root(schedule);
+	isl_schedule_free(schedule);
+	node = isl_schedule_node_expand(node, contraction, domain, tree);
+	schedule = isl_schedule_node_get_schedule(node);
+	isl_schedule_node_free(node);
+
+	return schedule;
+}
+
+/* Intersect the domain of the schedule "schedule" with "domain".
+ * The root of "schedule" is required to be a domain node.
+ */
+__isl_give isl_schedule *isl_schedule_intersect_domain(
+	__isl_take isl_schedule *schedule, __isl_take isl_union_set *domain)
+{
+	enum isl_schedule_node_type root_type;
+	isl_schedule_node *node;
+
+	if (!schedule || !domain)
+		goto error;
+
+	root_type = isl_schedule_tree_get_type(schedule->root);
+	if (root_type != isl_schedule_node_domain)
+		isl_die(isl_schedule_get_ctx(schedule), isl_error_invalid,
+			"root node must be a domain node", goto error);
+
+	node = isl_schedule_get_root(schedule);
+	isl_schedule_free(schedule);
+	node = isl_schedule_node_domain_intersect_domain(node, domain);
+	schedule = isl_schedule_node_get_schedule(node);
+	isl_schedule_node_free(node);
+
+	return schedule;
+error:
+	isl_schedule_free(schedule);
+	isl_union_set_free(domain);
+	return NULL;
+}
+
+/* Replace the domain of the schedule "schedule" with the gist
+ * of the original domain with respect to the parameter domain "context".
+ */
+__isl_give isl_schedule *isl_schedule_gist_domain_params(
+	__isl_take isl_schedule *schedule, __isl_take isl_set *context)
+{
+	enum isl_schedule_node_type root_type;
+	isl_schedule_node *node;
+
+	if (!schedule || !context)
+		goto error;
+
+	root_type = isl_schedule_tree_get_type(schedule->root);
+	if (root_type != isl_schedule_node_domain)
+		isl_die(isl_schedule_get_ctx(schedule), isl_error_invalid,
+			"root node must be a domain node", goto error);
+
+	node = isl_schedule_get_root(schedule);
+	isl_schedule_free(schedule);
+	node = isl_schedule_node_domain_gist_params(node, context);
+	schedule = isl_schedule_node_get_schedule(node);
+	isl_schedule_node_free(node);
+
+	return schedule;
+error:
+	isl_schedule_free(schedule);
+	isl_set_free(context);
+	return NULL;
+}
+
+/* Return an isl_union_map representation of the schedule.
+ * If we still have access to the schedule tree, then we return
+ * an isl_union_map corresponding to the subtree schedule of the child
+ * of the root domain node.  That is, we do not intersect the domain
+ * of the returned isl_union_map with the domain constraints.
+ * Otherwise, we must have removed it because we created a band forest.
+ * If so, we extract the isl_union_map from the forest.
+ * This reconstructed schedule map
+ * then needs to be padded with zeros to unify the schedule space
+ * since the result of isl_band_list_get_suffix_schedule may not have
+ * a unified schedule space.
+ */
+__isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched)
+{
+	enum isl_schedule_node_type type;
+	isl_schedule_node *node;
+	isl_union_map *umap;
+
+	if (!sched)
+		return NULL;
+
+	if (sched->root) {
+		type = isl_schedule_tree_get_type(sched->root);
+		if (type != isl_schedule_node_domain)
+			isl_die(isl_schedule_get_ctx(sched), isl_error_internal,
+				"root node not a domain node", return NULL);
+
+		node = isl_schedule_get_root(sched);
+		node = isl_schedule_node_child(node, 0);
+		umap = isl_schedule_node_get_subtree_schedule_union_map(node);
+		isl_schedule_node_free(node);
+
+		return umap;
+	}
+
+	umap = isl_band_list_get_suffix_schedule(sched->band_forest);
+	return pad_schedule_map(umap);
+}
+
+static __isl_give isl_band_list *construct_band_list(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *domain,
+	__isl_keep isl_band *parent);
+
+/* Construct an isl_band structure from the given schedule tree node,
+ * which may be either a band node or a leaf node.
+ * In the latter case, construct a zero-dimensional band.
+ * "domain" is the universe set of the domain elements that reach "node".
+ * "parent" is the parent isl_band of the isl_band constructed
+ * by this function.
+ *
+ * In case of a band node, we copy the properties (except tilability,
+ * which is implicit in an isl_band) to the isl_band.
+ * We assume that the band node is not zero-dimensional.
+ * If the child of the band node is not a leaf node,
+ * then we extract the children of the isl_band from this child.
+ */
+static __isl_give isl_band *construct_band(__isl_take isl_schedule_node *node,
+	__isl_take isl_union_set *domain, __isl_keep isl_band *parent)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_band *band = NULL;
+	isl_multi_union_pw_aff *mupa;
+
+	if (!node || !domain)
+		goto error;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	band = isl_band_alloc(ctx);
+	if (!band)
+		goto error;
+
+	band->schedule = node->schedule;
+	band->parent = parent;
+
+	if (isl_schedule_node_get_type(node) == isl_schedule_node_leaf) {
+		band->n = 0;
+		band->pma = isl_union_pw_multi_aff_from_domain(domain);
+		isl_schedule_node_free(node);
+		return band;
+	}
+
+	band->n = isl_schedule_node_band_n_member(node);
+	if (band->n == 0)
+		isl_die(ctx, isl_error_unsupported,
+			"zero-dimensional band nodes not supported",
+			goto error);
+	band->coincident = isl_alloc_array(ctx, int, band->n);
+	if (band->n && !band->coincident)
+		goto error;
+	for (i = 0; i < band->n; ++i)
+		band->coincident[i] =
+			isl_schedule_node_band_member_get_coincident(node, i);
+	mupa = isl_schedule_node_band_get_partial_schedule(node);
+	band->pma = isl_union_pw_multi_aff_from_multi_union_pw_aff(mupa);
+	if (!band->pma)
+		goto error;
+
+	node = isl_schedule_node_child(node, 0);
+	if (isl_schedule_node_get_type(node) == isl_schedule_node_leaf) {
+		isl_schedule_node_free(node);
+		isl_union_set_free(domain);
+		return band;
+	}
+
+	band->children = construct_band_list(node, domain, band);
+	if (!band->children)
+		return isl_band_free(band);
+
+	return band;
+error:
+	isl_union_set_free(domain);
+	isl_schedule_node_free(node);
+	isl_band_free(band);
+	return NULL;
+}
+
+/* Construct a list of isl_band structures from the children of "node".
+ * "node" itself is a sequence or set node, so that each of the child nodes
+ * is a filter node and the list returned by node_construct_band_list
+ * consists of a single element.
+ * "domain" is the universe set of the domain elements that reach "node".
+ * "parent" is the parent isl_band of the isl_band structures constructed
+ * by this function.
+ */
+static __isl_give isl_band_list *construct_band_list_from_children(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *domain,
+	__isl_keep isl_band *parent)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_band_list *list;
+
+	n = isl_schedule_node_n_children(node);
+
+	ctx = isl_schedule_node_get_ctx(node);
+	list = isl_band_list_alloc(ctx, 0);
+	for (i = 0; i < n; ++i) {
+		isl_schedule_node *child;
+		isl_band_list *list_i;
+
+		child = isl_schedule_node_get_child(node, i);
+		list_i = construct_band_list(child, isl_union_set_copy(domain),
+						parent);
+		list = isl_band_list_concat(list, list_i);
+	}
+
+	isl_union_set_free(domain);
+	isl_schedule_node_free(node);
+
+	return list;
+}
+
+/* Construct an isl_band structure from the given sequence node
+ * (or set node that is treated as a sequence node).
+ * A single-dimensional band is created with as schedule for each of
+ * filters of the children, the corresponding child position.
+ * "domain" is the universe set of the domain elements that reach "node".
+ * "parent" is the parent isl_band of the isl_band constructed
+ * by this function.
+ */
+static __isl_give isl_band_list *construct_band_list_sequence(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *domain,
+	__isl_keep isl_band *parent)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_band *band = NULL;
+	isl_space *space;
+	isl_union_pw_multi_aff *upma;
+
+	if (!node || !domain)
+		goto error;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	band = isl_band_alloc(ctx);
+	if (!band)
+		goto error;
+
+	band->schedule = node->schedule;
+	band->parent = parent;
+	band->n = 1;
+	band->coincident = isl_calloc_array(ctx, int, band->n);
+	if (!band->coincident)
+		goto error;
+
+	n = isl_schedule_node_n_children(node);
+	space = isl_union_set_get_space(domain);
+	upma = isl_union_pw_multi_aff_empty(isl_space_copy(space));
+
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, 1);
+
+	for (i = 0; i < n; ++i) {
+		isl_schedule_node *child;
+		isl_union_set *filter;
+		isl_val *v;
+		isl_val_list *vl;
+		isl_multi_val *mv;
+		isl_union_pw_multi_aff *upma_i;
+
+		child = isl_schedule_node_get_child(node, i);
+		filter = isl_schedule_node_filter_get_filter(child);
+		isl_schedule_node_free(child);
+		filter = isl_union_set_intersect(filter,
+						isl_union_set_copy(domain));
+		v = isl_val_int_from_si(ctx, i);
+		vl = isl_val_list_from_val(v);
+		mv = isl_multi_val_from_val_list(isl_space_copy(space), vl);
+		upma_i = isl_union_pw_multi_aff_multi_val_on_domain(filter, mv);
+		upma = isl_union_pw_multi_aff_union_add(upma, upma_i);
+	}
+
+	isl_space_free(space);
+
+	band->pma = upma;
+	if (!band->pma)
+		goto error;
+
+	band->children = construct_band_list_from_children(node, domain, band);
+	if (!band->children)
+		band = isl_band_free(band);
+	return isl_band_list_from_band(band);
+error:
+	isl_union_set_free(domain);
+	isl_schedule_node_free(node);
+	isl_band_free(band);
+	return NULL;
+}
+
+/* Construct a list of isl_band structures from "node" depending
+ * on the type of "node".
+ * "domain" is the universe set of the domain elements that reach "node".
+ * "parent" is the parent isl_band of the isl_band structures constructed
+ * by this function.
+ *
+ * If schedule_separate_components is set then set nodes are treated
+ * as sequence nodes.  Otherwise, we directly extract an (implicitly
+ * parallel) list of isl_band structures.
+ *
+ * If "node" is a filter, then "domain" is updated by the filter.
+ */
+static __isl_give isl_band_list *construct_band_list(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *domain,
+	__isl_keep isl_band *parent)
+{
+	enum isl_schedule_node_type type;
+	isl_ctx *ctx;
+	isl_band *band;
+	isl_band_list *list;
+	isl_union_set *filter;
+
+	if (!node || !domain)
+		goto error;
+
+	type = isl_schedule_node_get_type(node);
+	switch (type) {
+	case isl_schedule_node_error:
+		goto error;
+	case isl_schedule_node_context:
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_unsupported,
+			"context nodes not supported", goto error);
+	case isl_schedule_node_domain:
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"internal domain nodes not allowed", goto error);
+	case isl_schedule_node_expansion:
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_unsupported,
+			"expansion nodes not supported", goto error);
+	case isl_schedule_node_extension:
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_unsupported,
+			"extension nodes not supported", goto error);
+	case isl_schedule_node_filter:
+		filter = isl_schedule_node_filter_get_filter(node);
+		domain = isl_union_set_intersect(domain, filter);
+		node = isl_schedule_node_child(node, 0);
+		return construct_band_list(node, domain, parent);
+	case isl_schedule_node_guard:
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_unsupported,
+			"guard nodes not supported", goto error);
+	case isl_schedule_node_mark:
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_unsupported,
+			"mark nodes not supported", goto error);
+	case isl_schedule_node_set:
+		ctx = isl_schedule_node_get_ctx(node);
+		if (isl_options_get_schedule_separate_components(ctx))
+			return construct_band_list_sequence(node, domain,
+							    parent);
+		else
+			return construct_band_list_from_children(node, domain,
+							    parent);
+	case isl_schedule_node_sequence:
+		return construct_band_list_sequence(node, domain, parent);
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_band:
+		band = construct_band(node, domain, parent);
+		list = isl_band_list_from_band(band);
+		break;
+	}
+
+	return list;
+error:
+	isl_union_set_free(domain);
+	isl_schedule_node_free(node);
+	return NULL;
+}
+
+/* Return the roots of a band forest representation of the schedule.
+ * The band forest is constructed from the schedule tree,
+ * but once such a band forest is
+ * constructed, we forget about the original schedule tree since
+ * the user may modify the schedule through the band forest.
+ */
+__isl_give isl_band_list *isl_schedule_get_band_forest(
+	__isl_keep isl_schedule *schedule)
+{
+	isl_schedule_node *node;
+	isl_union_set *domain;
+
+	if (!schedule)
+		return NULL;
+	if (schedule->root) {
+		node = isl_schedule_get_root(schedule);
+		domain = isl_schedule_node_domain_get_domain(node);
+		domain = isl_union_set_universe(domain);
+		node = isl_schedule_node_child(node, 0);
+
+		schedule->band_forest = construct_band_list(node, domain, NULL);
+		schedule->root = isl_schedule_tree_free(schedule->root);
+	}
+	return isl_band_list_dup(schedule->band_forest);
+}
+
+/* Call "fn" on each band in the schedule in depth-first post-order.
+ */
+int isl_schedule_foreach_band(__isl_keep isl_schedule *sched,
+	int (*fn)(__isl_keep isl_band *band, void *user), void *user)
+{
+	int r;
+	isl_band_list *forest;
+
+	if (!sched)
+		return -1;
+
+	forest = isl_schedule_get_band_forest(sched);
+	r = isl_band_list_foreach_band(forest, fn, user);
+	isl_band_list_free(forest);
+
+	return r;
+}
+
+static __isl_give isl_printer *print_band_list(__isl_take isl_printer *p,
+	__isl_keep isl_band_list *list);
+
+static __isl_give isl_printer *print_band(__isl_take isl_printer *p,
+	__isl_keep isl_band *band)
+{
+	isl_band_list *children;
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_union_pw_multi_aff(p, band->pma);
+	p = isl_printer_end_line(p);
+
+	if (!isl_band_has_children(band))
+		return p;
+
+	children = isl_band_get_children(band);
+
+	p = isl_printer_indent(p, 4);
+	p = print_band_list(p, children);
+	p = isl_printer_indent(p, -4);
+
+	isl_band_list_free(children);
+
+	return p;
+}
+
+static __isl_give isl_printer *print_band_list(__isl_take isl_printer *p,
+	__isl_keep isl_band_list *list)
+{
+	int i, n;
+
+	n = isl_band_list_n_band(list);
+	for (i = 0; i < n; ++i) {
+		isl_band *band;
+		band = isl_band_list_get_band(list, i);
+		p = print_band(p, band);
+		isl_band_free(band);
+	}
+
+	return p;
+}
+
+/* Insert a band node with partial schedule "partial" between the domain
+ * root node of "schedule" and its single child.
+ * Return a pointer to the updated schedule.
+ *
+ * If any of the nodes in the tree depend on the set of outer band nodes
+ * then we refuse to insert the band node.
+ */
+__isl_give isl_schedule *isl_schedule_insert_partial_schedule(
+	__isl_take isl_schedule *schedule,
+	__isl_take isl_multi_union_pw_aff *partial)
+{
+	isl_schedule_node *node;
+	int anchored;
+
+	node = isl_schedule_get_root(schedule);
+	isl_schedule_free(schedule);
+	if (!node)
+		goto error;
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_domain)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_internal,
+			"root node not a domain node", goto error);
+
+	node = isl_schedule_node_child(node, 0);
+	anchored = isl_schedule_node_is_subtree_anchored(node);
+	if (anchored < 0)
+		goto error;
+	if (anchored)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot insert band node in anchored subtree",
+			goto error);
+	node = isl_schedule_node_insert_partial_schedule(node, partial);
+
+	schedule = isl_schedule_node_get_schedule(node);
+	isl_schedule_node_free(node);
+
+	return schedule;
+error:
+	isl_schedule_node_free(node);
+	isl_multi_union_pw_aff_free(partial);
+	return NULL;
+}
+
+/* Insert a context node with constraints "context" between the domain
+ * root node of "schedule" and its single child.
+ * Return a pointer to the updated schedule.
+ */
+__isl_give isl_schedule *isl_schedule_insert_context(
+	__isl_take isl_schedule *schedule, __isl_take isl_set *context)
+{
+	isl_schedule_node *node;
+
+	node = isl_schedule_get_root(schedule);
+	isl_schedule_free(schedule);
+	node = isl_schedule_node_child(node, 0);
+	node = isl_schedule_node_insert_context(node, context);
+	schedule = isl_schedule_node_get_schedule(node);
+	isl_schedule_node_free(node);
+
+	return schedule;
+}
+
+/* Insert a guard node with constraints "guard" between the domain
+ * root node of "schedule" and its single child.
+ * Return a pointer to the updated schedule.
+ */
+__isl_give isl_schedule *isl_schedule_insert_guard(
+	__isl_take isl_schedule *schedule, __isl_take isl_set *guard)
+{
+	isl_schedule_node *node;
+
+	node = isl_schedule_get_root(schedule);
+	isl_schedule_free(schedule);
+	node = isl_schedule_node_child(node, 0);
+	node = isl_schedule_node_insert_guard(node, guard);
+	schedule = isl_schedule_node_get_schedule(node);
+	isl_schedule_node_free(node);
+
+	return schedule;
+}
+
+/* Return a tree with as top-level node a filter corresponding to "filter" and
+ * as child, the (single) child of "tree".
+ * However, if this single child is of type "type", then the filter is inserted
+ * in the children of this single child instead.
+ */
+static __isl_give isl_schedule_tree *insert_filter_in_child_of_type(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter,
+	enum isl_schedule_node_type type)
+{
+	if (!isl_schedule_tree_has_children(tree)) {
+		isl_schedule_tree_free(tree);
+		return isl_schedule_tree_from_filter(filter);
+	} else {
+		tree = isl_schedule_tree_child(tree, 0);
+	}
+
+	if (isl_schedule_tree_get_type(tree) == type)
+		tree = isl_schedule_tree_children_insert_filter(tree, filter);
+	else
+		tree = isl_schedule_tree_insert_filter(tree, filter);
+
+	return tree;
+}
+
+/* Construct a schedule that combines the schedules "schedule1" and "schedule2"
+ * with a top-level node (underneath the domain node) of type "type",
+ * either isl_schedule_node_sequence or isl_schedule_node_set.
+ * The domains of the two schedules are assumed to be disjoint.
+ *
+ * The new schedule has as domain the union of the domains of the two
+ * schedules.  The child of the domain node is a node of type "type"
+ * with two filters corresponding to the domains of the input schedules.
+ * If one (or both) of the top-level nodes of the two schedules is itself
+ * of type "type", then the filter is pushed into the children of that
+ * node and the sequence of set is flattened.
+ */
+__isl_give isl_schedule *isl_schedule_pair(enum isl_schedule_node_type type,
+	__isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2)
+{
+	int disjoint;
+	isl_ctx *ctx;
+	enum isl_schedule_node_type root_type;
+	isl_schedule_tree *tree1, *tree2;
+	isl_union_set *filter1, *filter2, *domain;
+
+	if (!schedule1 || !schedule2)
+		goto error;
+
+	root_type = isl_schedule_tree_get_type(schedule1->root);
+	if (root_type != isl_schedule_node_domain)
+		isl_die(isl_schedule_get_ctx(schedule1), isl_error_internal,
+			"root node not a domain node", goto error);
+	root_type = isl_schedule_tree_get_type(schedule2->root);
+	if (root_type != isl_schedule_node_domain)
+		isl_die(isl_schedule_get_ctx(schedule1), isl_error_internal,
+			"root node not a domain node", goto error);
+
+	ctx = isl_schedule_get_ctx(schedule1);
+	tree1 = isl_schedule_tree_copy(schedule1->root);
+	filter1 = isl_schedule_tree_domain_get_domain(tree1);
+	tree2 = isl_schedule_tree_copy(schedule2->root);
+	filter2 = isl_schedule_tree_domain_get_domain(tree2);
+
+	isl_schedule_free(schedule1);
+	isl_schedule_free(schedule2);
+
+	disjoint = isl_union_set_is_disjoint(filter1, filter2);
+	if (disjoint < 0)
+		filter1 = isl_union_set_free(filter1);
+	if (!disjoint)
+		isl_die(ctx, isl_error_invalid,
+			"schedule domains not disjoint",
+			filter1 = isl_union_set_free(filter1));
+
+	domain = isl_union_set_union(isl_union_set_copy(filter1),
+				    isl_union_set_copy(filter2));
+	filter1 = isl_union_set_gist(filter1, isl_union_set_copy(domain));
+	filter2 = isl_union_set_gist(filter2, isl_union_set_copy(domain));
+
+	tree1 = insert_filter_in_child_of_type(tree1, filter1, type);
+	tree2 = insert_filter_in_child_of_type(tree2, filter2, type);
+
+	tree1 = isl_schedule_tree_from_pair(type, tree1, tree2);
+	tree1 = isl_schedule_tree_insert_domain(tree1, domain);
+
+	return isl_schedule_from_schedule_tree(ctx, tree1);
+error:
+	isl_schedule_free(schedule1);
+	isl_schedule_free(schedule2);
+	return NULL;
+}
+
+/* Construct a schedule that combines the schedules "schedule1" and "schedule2"
+ * through a sequence node.
+ * The domains of the input schedules are assumed to be disjoint.
+ */
+__isl_give isl_schedule *isl_schedule_sequence(
+	__isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2)
+{
+	return isl_schedule_pair(isl_schedule_node_sequence,
+				schedule1, schedule2);
+}
+
+/* Construct a schedule that combines the schedules "schedule1" and "schedule2"
+ * through a set node.
+ * The domains of the input schedules are assumed to be disjoint.
+ */
+__isl_give isl_schedule *isl_schedule_set(
+	__isl_take isl_schedule *schedule1, __isl_take isl_schedule *schedule2)
+{
+	return isl_schedule_pair(isl_schedule_node_set, schedule1, schedule2);
+}
+
+/* Print "schedule" to "p".
+ *
+ * If "schedule" was created from a schedule tree, then we print
+ * the schedule tree representation.  Otherwise, we print
+ * the band forest representation.
+ */
+__isl_give isl_printer *isl_printer_print_schedule(__isl_take isl_printer *p,
+	__isl_keep isl_schedule *schedule)
+{
+	isl_band_list *forest;
+
+	if (!schedule)
+		return isl_printer_free(p);
+
+	if (schedule->root)
+		return isl_printer_print_schedule_tree(p, schedule->root);
+
+	forest = isl_schedule_get_band_forest(schedule);
+
+	p = print_band_list(p, forest);
+
+	isl_band_list_free(forest);
+
+	return p;
+}
+
+#undef BASE
+#define BASE schedule
+#include <print_templ_yaml.c>
diff --git a/final/lib/External/isl/isl_schedule_band.c b/final/lib/External/isl/isl_schedule_band.c
new file mode 100644
index 0000000..ed20961
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_band.c
@@ -0,0 +1,1299 @@
+/*
+ * Copyright 2013-2014 Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <string.h>
+#include <isl/map.h>
+#include <isl/schedule_node.h>
+#include <isl_schedule_band.h>
+#include <isl_schedule_private.h>
+
+isl_ctx *isl_schedule_band_get_ctx(__isl_keep isl_schedule_band *band)
+{
+	return band ? isl_multi_union_pw_aff_get_ctx(band->mupa) : NULL;
+}
+
+/* Return a new uninitialized isl_schedule_band.
+ */
+static __isl_give isl_schedule_band *isl_schedule_band_alloc(isl_ctx *ctx)
+{
+	isl_schedule_band *band;
+
+	band = isl_calloc_type(ctx, isl_schedule_band);
+	if (!band)
+		return NULL;
+
+	band->ref = 1;
+
+	return band;
+}
+
+/* Return a new isl_schedule_band with partial schedule "mupa".
+ * First replace "mupa" by its greatest integer part to ensure
+ * that the schedule is always integral.
+ * The band is not marked permutable, the dimensions are not
+ * marked coincident and the AST build options are empty.
+ * Since there are no build options, the node is not anchored.
+ */
+__isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff(
+	__isl_take isl_multi_union_pw_aff *mupa)
+{
+	isl_ctx *ctx;
+	isl_schedule_band *band;
+	isl_space *space;
+
+	mupa = isl_multi_union_pw_aff_floor(mupa);
+	if (!mupa)
+		return NULL;
+	ctx = isl_multi_union_pw_aff_get_ctx(mupa);
+	band = isl_schedule_band_alloc(ctx);
+	if (!band)
+		goto error;
+
+	band->n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
+	band->coincident = isl_calloc_array(ctx, int, band->n);
+	band->mupa = mupa;
+	space = isl_space_params_alloc(ctx, 0);
+	band->ast_build_options = isl_union_set_empty(space);
+	band->anchored = 0;
+
+	if ((band->n && !band->coincident) || !band->ast_build_options)
+		return isl_schedule_band_free(band);
+
+	return band;
+error:
+	isl_multi_union_pw_aff_free(mupa);
+	return NULL;
+}
+
+/* Create a duplicate of the given isl_schedule_band.
+ */
+__isl_give isl_schedule_band *isl_schedule_band_dup(
+	__isl_keep isl_schedule_band *band)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_schedule_band *dup;
+
+	if (!band)
+		return NULL;
+
+	ctx = isl_schedule_band_get_ctx(band);
+	dup = isl_schedule_band_alloc(ctx);
+	if (!dup)
+		return NULL;
+
+	dup->n = band->n;
+	dup->coincident = isl_alloc_array(ctx, int, band->n);
+	if (band->n && !dup->coincident)
+		return isl_schedule_band_free(dup);
+
+	for (i = 0; i < band->n; ++i)
+		dup->coincident[i] = band->coincident[i];
+	dup->permutable = band->permutable;
+
+	dup->mupa = isl_multi_union_pw_aff_copy(band->mupa);
+	dup->ast_build_options = isl_union_set_copy(band->ast_build_options);
+	if (!dup->mupa || !dup->ast_build_options)
+		return isl_schedule_band_free(dup);
+
+	if (band->loop_type) {
+		dup->loop_type = isl_alloc_array(ctx,
+					    enum isl_ast_loop_type, band->n);
+		if (band->n && !dup->loop_type)
+			return isl_schedule_band_free(dup);
+		for (i = 0; i < band->n; ++i)
+			dup->loop_type[i] = band->loop_type[i];
+	}
+	if (band->isolate_loop_type) {
+		dup->isolate_loop_type = isl_alloc_array(ctx,
+					    enum isl_ast_loop_type, band->n);
+		if (band->n && !dup->isolate_loop_type)
+			return isl_schedule_band_free(dup);
+		for (i = 0; i < band->n; ++i)
+			dup->isolate_loop_type[i] = band->isolate_loop_type[i];
+	}
+
+	return dup;
+}
+
+/* Return an isl_schedule_band that is equal to "band" and that has only
+ * a single reference.
+ */
+__isl_give isl_schedule_band *isl_schedule_band_cow(
+	__isl_take isl_schedule_band *band)
+{
+	if (!band)
+		return NULL;
+
+	if (band->ref == 1)
+		return band;
+	band->ref--;
+	return isl_schedule_band_dup(band);
+}
+
+/* Return a new reference to "band".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_copy(
+	__isl_keep isl_schedule_band *band)
+{
+	if (!band)
+		return NULL;
+
+	band->ref++;
+	return band;
+}
+
+/* Free a reference to "band" and return NULL.
+ */
+__isl_null isl_schedule_band *isl_schedule_band_free(
+	__isl_take isl_schedule_band *band)
+{
+	if (!band)
+		return NULL;
+
+	if (--band->ref > 0)
+		return NULL;
+
+	isl_multi_union_pw_aff_free(band->mupa);
+	isl_union_set_free(band->ast_build_options);
+	free(band->loop_type);
+	free(band->isolate_loop_type);
+	free(band->coincident);
+	free(band);
+
+	return NULL;
+}
+
+/* Are "band1" and "band2" obviously equal?
+ */
+isl_bool isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1,
+	__isl_keep isl_schedule_band *band2)
+{
+	int i;
+	isl_bool equal;
+
+	if (!band1 || !band2)
+		return isl_bool_error;
+	if (band1 == band2)
+		return isl_bool_true;
+
+	if (band1->n != band2->n)
+		return isl_bool_false;
+	for (i = 0; i < band1->n; ++i)
+		if (band1->coincident[i] != band2->coincident[i])
+			return isl_bool_false;
+	if (band1->permutable != band2->permutable)
+		return isl_bool_false;
+
+	equal = isl_multi_union_pw_aff_plain_is_equal(band1->mupa, band2->mupa);
+	if (equal < 0 || !equal)
+		return equal;
+
+	if (!band1->loop_type != !band2->loop_type)
+		return isl_bool_false;
+	if (band1->loop_type)
+		for (i = 0; i < band1->n; ++i)
+			if (band1->loop_type[i] != band2->loop_type[i])
+				return isl_bool_false;
+
+	if (!band1->isolate_loop_type != !band2->isolate_loop_type)
+		return isl_bool_false;
+	if (band1->isolate_loop_type)
+		for (i = 0; i < band1->n; ++i)
+			if (band1->isolate_loop_type[i] !=
+						band2->isolate_loop_type[i])
+				return isl_bool_false;
+
+	return isl_union_set_is_equal(band1->ast_build_options,
+					band2->ast_build_options);
+}
+
+/* Return the number of scheduling dimensions in the band.
+ */
+int isl_schedule_band_n_member(__isl_keep isl_schedule_band *band)
+{
+	return band ? band->n : 0;
+}
+
+/* Is the given scheduling dimension coincident within the band and
+ * with respect to the coincidence constraints?
+ */
+isl_bool isl_schedule_band_member_get_coincident(
+	__isl_keep isl_schedule_band *band, int pos)
+{
+	if (!band)
+		return isl_bool_error;
+
+	if (pos < 0 || pos >= band->n)
+		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
+			"invalid member position", return isl_bool_error);
+
+	return band->coincident[pos];
+}
+
+/* Mark the given scheduling dimension as being coincident or not
+ * according to "coincident".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_member_set_coincident(
+	__isl_take isl_schedule_band *band, int pos, int coincident)
+{
+	if (!band)
+		return NULL;
+	if (isl_schedule_band_member_get_coincident(band, pos) == coincident)
+		return band;
+	band = isl_schedule_band_cow(band);
+	if (!band)
+		return NULL;
+
+	if (pos < 0 || pos >= band->n)
+		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
+			"invalid member position",
+			return isl_schedule_band_free(band));
+
+	band->coincident[pos] = coincident;
+
+	return band;
+}
+
+/* Is the schedule band mark permutable?
+ */
+isl_bool isl_schedule_band_get_permutable(__isl_keep isl_schedule_band *band)
+{
+	if (!band)
+		return isl_bool_error;
+	return band->permutable;
+}
+
+/* Mark the schedule band permutable or not according to "permutable"?
+ */
+__isl_give isl_schedule_band *isl_schedule_band_set_permutable(
+	__isl_take isl_schedule_band *band, int permutable)
+{
+	if (!band)
+		return NULL;
+	if (band->permutable == permutable)
+		return band;
+	band = isl_schedule_band_cow(band);
+	if (!band)
+		return NULL;
+
+	band->permutable = permutable;
+
+	return band;
+}
+
+/* Is the band node "node" anchored?  That is, does it reference
+ * the outer band nodes?
+ */
+int isl_schedule_band_is_anchored(__isl_keep isl_schedule_band *band)
+{
+	return band ? band->anchored : -1;
+}
+
+/* Return the schedule space of the band.
+ */
+__isl_give isl_space *isl_schedule_band_get_space(
+	__isl_keep isl_schedule_band *band)
+{
+	if (!band)
+		return NULL;
+	return isl_multi_union_pw_aff_get_space(band->mupa);
+}
+
+/* Intersect the domain of the band schedule of "band" with "domain".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_intersect_domain(
+	__isl_take isl_schedule_band *band, __isl_take isl_union_set *domain)
+{
+	band = isl_schedule_band_cow(band);
+	if (!band || !domain)
+		goto error;
+
+	band->mupa = isl_multi_union_pw_aff_intersect_domain(band->mupa,
+								domain);
+	if (!band->mupa)
+		return isl_schedule_band_free(band);
+
+	return band;
+error:
+	isl_schedule_band_free(band);
+	isl_union_set_free(domain);
+	return NULL;
+}
+
+/* Return the schedule of the band in isolation.
+ */
+__isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule(
+	__isl_keep isl_schedule_band *band)
+{
+	return band ? isl_multi_union_pw_aff_copy(band->mupa) : NULL;
+}
+
+/* Replace the schedule of "band" by "schedule".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_set_partial_schedule(
+	__isl_take isl_schedule_band *band,
+	__isl_take isl_multi_union_pw_aff *schedule)
+{
+	band = isl_schedule_band_cow(band);
+	if (!band || !schedule)
+		goto error;
+
+	isl_multi_union_pw_aff_free(band->mupa);
+	band->mupa = schedule;
+
+	return band;
+error:
+	isl_schedule_band_free(band);
+	isl_multi_union_pw_aff_free(schedule);
+	return NULL;
+}
+
+/* Return the loop AST generation type for the band member of "band"
+ * at position "pos".
+ */
+enum isl_ast_loop_type isl_schedule_band_member_get_ast_loop_type(
+	__isl_keep isl_schedule_band *band, int pos)
+{
+	if (!band)
+		return isl_ast_loop_error;
+
+	if (pos < 0 || pos >= band->n)
+		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
+			"invalid member position", return -1);
+
+	if (!band->loop_type)
+		return isl_ast_loop_default;
+
+	return band->loop_type[pos];
+}
+
+/* Set the loop AST generation type for the band member of "band"
+ * at position "pos" to "type".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_member_set_ast_loop_type(
+	__isl_take isl_schedule_band *band, int pos,
+	enum isl_ast_loop_type type)
+{
+	if (!band)
+		return NULL;
+	if (isl_schedule_band_member_get_ast_loop_type(band, pos) == type)
+		return band;
+
+	if (pos < 0 || pos >= band->n)
+		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
+			"invalid member position",
+			return isl_schedule_band_free(band));
+
+	band = isl_schedule_band_cow(band);
+	if (!band)
+		return isl_schedule_band_free(band);
+
+	if (!band->loop_type) {
+		isl_ctx *ctx;
+
+		ctx = isl_schedule_band_get_ctx(band);
+		band->loop_type = isl_calloc_array(ctx,
+					    enum isl_ast_loop_type, band->n);
+		if (band->n && !band->loop_type)
+			return isl_schedule_band_free(band);
+	}
+
+	band->loop_type[pos] = type;
+
+	return band;
+}
+
+/* Return the loop AST generation type for the band member of "band"
+ * at position "pos" for the part that has been isolated by the isolate option.
+ */
+enum isl_ast_loop_type isl_schedule_band_member_get_isolate_ast_loop_type(
+	__isl_keep isl_schedule_band *band, int pos)
+{
+	if (!band)
+		return isl_ast_loop_error;
+
+	if (pos < 0 || pos >= band->n)
+		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
+			"invalid member position", return -1);
+
+	if (!band->isolate_loop_type)
+		return isl_ast_loop_default;
+
+	return band->isolate_loop_type[pos];
+}
+
+/* Set the loop AST generation type for the band member of "band"
+ * at position "pos" to "type" for the part that has been isolated
+ * by the isolate option.
+ */
+__isl_give isl_schedule_band *
+isl_schedule_band_member_set_isolate_ast_loop_type(
+	__isl_take isl_schedule_band *band, int pos,
+	enum isl_ast_loop_type type)
+{
+	if (!band)
+		return NULL;
+	if (isl_schedule_band_member_get_isolate_ast_loop_type(band, pos) ==
+									type)
+		return band;
+
+	if (pos < 0 || pos >= band->n)
+		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
+			"invalid member position",
+			return isl_schedule_band_free(band));
+
+	band = isl_schedule_band_cow(band);
+	if (!band)
+		return isl_schedule_band_free(band);
+
+	if (!band->isolate_loop_type) {
+		isl_ctx *ctx;
+
+		ctx = isl_schedule_band_get_ctx(band);
+		band->isolate_loop_type = isl_calloc_array(ctx,
+					    enum isl_ast_loop_type, band->n);
+		if (band->n && !band->isolate_loop_type)
+			return isl_schedule_band_free(band);
+	}
+
+	band->isolate_loop_type[pos] = type;
+
+	return band;
+}
+
+static const char *option_str[] = {
+	[isl_ast_loop_atomic] = "atomic",
+	[isl_ast_loop_unroll] = "unroll",
+	[isl_ast_loop_separate] = "separate"
+};
+
+/* Given a parameter space "space", extend it to a set space
+ *
+ *	{ type[x] }
+ *
+ * or
+ *
+ *	{ [isolate[] -> type[x]] }
+ *
+ * depending on whether "isolate" is set.
+ * These can be used to encode loop AST generation options of the given type.
+ */
+static __isl_give isl_space *loop_type_space(__isl_take isl_space *space,
+	enum isl_ast_loop_type type, int isolate)
+{
+	const char *name;
+
+	name = option_str[type];
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, 1);
+	space = isl_space_set_tuple_name(space, isl_dim_set, name);
+	if (!isolate)
+		return space;
+	space = isl_space_from_range(space);
+	space = isl_space_set_tuple_name(space, isl_dim_in, "isolate");
+	space = isl_space_wrap(space);
+
+	return space;
+}
+
+/* Add encodings of the "n" loop AST generation options "type" to "options".
+ * If "isolate" is set, then these options refer to the isolated part.
+ *
+ * In particular, for each sequence of consecutive identical types "t",
+ * different from the default, add an option
+ *
+ *	{ t[x] : first <= x <= last }
+ *
+ * or
+ *
+ *	{ [isolate[] -> t[x]] : first <= x <= last }
+ */
+static __isl_give isl_union_set *add_loop_types(
+	__isl_take isl_union_set *options, int n, enum isl_ast_loop_type *type,
+	int isolate)
+{
+	int i;
+
+	if (!type)
+		return options;
+	if (!options)
+		return NULL;
+
+	for (i = 0; i < n; ++i) {
+		int first;
+		isl_space *space;
+		isl_set *option;
+
+		if (type[i] == isl_ast_loop_default)
+			continue;
+
+		first = i;
+		while (i + 1 < n && type[i + 1] == type[i])
+			++i;
+
+		space = isl_union_set_get_space(options);
+		space = loop_type_space(space, type[i], isolate);
+		option = isl_set_universe(space);
+		option = isl_set_lower_bound_si(option, isl_dim_set, 0, first);
+		option = isl_set_upper_bound_si(option, isl_dim_set, 0, i);
+		options = isl_union_set_add_set(options, option);
+	}
+
+	return options;
+}
+
+/* Return the AST build options associated to "band".
+ */
+__isl_give isl_union_set *isl_schedule_band_get_ast_build_options(
+	__isl_keep isl_schedule_band *band)
+{
+	isl_union_set *options;
+
+	if (!band)
+		return NULL;
+
+	options = isl_union_set_copy(band->ast_build_options);
+	options = add_loop_types(options, band->n, band->loop_type, 0);
+	options = add_loop_types(options, band->n, band->isolate_loop_type, 1);
+
+	return options;
+}
+
+/* Does "uset" contain any set that satisfies "is"?
+ * "is" is assumed to set its integer argument to 1 if it is satisfied.
+ */
+static int has_any(__isl_keep isl_union_set *uset,
+	isl_stat (*is)(__isl_take isl_set *set, void *user))
+{
+	int found = 0;
+
+	if (isl_union_set_foreach_set(uset, is, &found) < 0 && !found)
+		return -1;
+
+	return found;
+}
+
+/* Does "set" live in a space of the form
+ *
+ *	isolate[[...] -> [...]]
+ *
+ * ?
+ *
+ * If so, set *found and abort the search.
+ */
+static isl_stat is_isolate(__isl_take isl_set *set, void *user)
+{
+	int *found = user;
+
+	if (isl_set_has_tuple_name(set)) {
+		const char *name;
+		name = isl_set_get_tuple_name(set);
+		if (isl_set_is_wrapping(set) && !strcmp(name, "isolate"))
+			*found = 1;
+	}
+	isl_set_free(set);
+
+	return *found ? isl_stat_error : isl_stat_ok;
+}
+
+/* Does "options" include an option of the ofrm
+ *
+ *	isolate[[...] -> [...]]
+ *
+ * ?
+ */
+static int has_isolate_option(__isl_keep isl_union_set *options)
+{
+	return has_any(options, &is_isolate);
+}
+
+/* Does "set" encode a loop AST generation option?
+ */
+static isl_stat is_loop_type_option(__isl_take isl_set *set, void *user)
+{
+	int *found = user;
+
+	if (isl_set_dim(set, isl_dim_set) == 1 &&
+	    isl_set_has_tuple_name(set)) {
+		const char *name;
+		enum isl_ast_loop_type type;
+		name = isl_set_get_tuple_name(set);
+		for (type = isl_ast_loop_atomic;
+		    type <= isl_ast_loop_separate; ++type) {
+			if (strcmp(name, option_str[type]))
+				continue;
+			*found = 1;
+			break;
+		}
+	}
+	isl_set_free(set);
+
+	return *found ? isl_stat_error : isl_stat_ok;
+}
+
+/* Does "set" encode a loop AST generation option for the isolated part?
+ * That is, is of the form
+ *
+ *	{ [isolate[] -> t[x]] }
+ *
+ * with t equal to "atomic", "unroll" or "separate"?
+ */
+static isl_stat is_isolate_loop_type_option(__isl_take isl_set *set, void *user)
+{
+	int *found = user;
+	const char *name;
+	enum isl_ast_loop_type type;
+	isl_map *map;
+
+	if (!isl_set_is_wrapping(set)) {
+		isl_set_free(set);
+		return isl_stat_ok;
+	}
+	map = isl_set_unwrap(set);
+	if (!isl_map_has_tuple_name(map, isl_dim_in) ||
+	    !isl_map_has_tuple_name(map, isl_dim_out)) {
+		isl_map_free(map);
+		return isl_stat_ok;
+	}
+	name = isl_map_get_tuple_name(map, isl_dim_in);
+	if (!strcmp(name, "isolate")) {
+		name = isl_map_get_tuple_name(map, isl_dim_out);
+		for (type = isl_ast_loop_atomic;
+		    type <= isl_ast_loop_separate; ++type) {
+			if (strcmp(name, option_str[type]))
+				continue;
+			*found = 1;
+			break;
+		}
+	}
+	isl_map_free(map);
+
+	return *found ? isl_stat_error : isl_stat_ok;
+}
+
+/* Does "options" encode any loop AST generation options
+ * for the isolated part?
+ */
+static int has_isolate_loop_type_options(__isl_keep isl_union_set *options)
+{
+	return has_any(options, &is_isolate_loop_type_option);
+}
+
+/* Does "options" encode any loop AST generation options?
+ */
+static int has_loop_type_options(__isl_keep isl_union_set *options)
+{
+	return has_any(options, &is_loop_type_option);
+}
+
+/* Extract the loop AST generation type for the band member
+ * at position "pos" from "options".
+ * If "isolate" is set, then extract the loop types for the isolated part.
+ */
+static enum isl_ast_loop_type extract_loop_type(
+	__isl_keep isl_union_set *options, int pos, int isolate)
+{
+	isl_ctx *ctx;
+	enum isl_ast_loop_type type, res = isl_ast_loop_default;
+
+	ctx = isl_union_set_get_ctx(options);
+	for (type = isl_ast_loop_atomic;
+	    type <= isl_ast_loop_separate; ++type) {
+		isl_space *space;
+		isl_set *option;
+		int empty;
+
+		space = isl_union_set_get_space(options);
+		space = loop_type_space(space, type, isolate);
+		option = isl_union_set_extract_set(options, space);
+		option = isl_set_fix_si(option, isl_dim_set, 0, pos);
+		empty = isl_set_is_empty(option);
+		isl_set_free(option);
+
+		if (empty < 0)
+			return isl_ast_loop_error;
+		if (empty)
+			continue;
+		if (res != isl_ast_loop_default)
+			isl_die(ctx, isl_error_invalid,
+				"conflicting loop type options",
+				return isl_ast_loop_error);
+		res = type;
+	}
+
+	return res;
+}
+
+/* Extract the loop AST generation types for the members of "band"
+ * from "options" and store them in band->loop_type.
+ * Return -1 on error.
+ */
+static int extract_loop_types(__isl_keep isl_schedule_band *band,
+	__isl_keep isl_union_set *options)
+{
+	int i;
+
+	if (!band->loop_type) {
+		isl_ctx *ctx = isl_schedule_band_get_ctx(band);
+		band->loop_type = isl_alloc_array(ctx,
+					    enum isl_ast_loop_type, band->n);
+		if (band->n && !band->loop_type)
+			return -1;
+	}
+	for (i = 0; i < band->n; ++i) {
+		band->loop_type[i] = extract_loop_type(options, i, 0);
+		if (band->loop_type[i] == isl_ast_loop_error)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Extract the loop AST generation types for the members of "band"
+ * from "options" for the isolated part and
+ * store them in band->isolate_loop_type.
+ * Return -1 on error.
+ */
+static int extract_isolate_loop_types(__isl_keep isl_schedule_band *band,
+	__isl_keep isl_union_set *options)
+{
+	int i;
+
+	if (!band->isolate_loop_type) {
+		isl_ctx *ctx = isl_schedule_band_get_ctx(band);
+		band->isolate_loop_type = isl_alloc_array(ctx,
+					    enum isl_ast_loop_type, band->n);
+		if (band->n && !band->isolate_loop_type)
+			return -1;
+	}
+	for (i = 0; i < band->n; ++i) {
+		band->isolate_loop_type[i] = extract_loop_type(options, i, 1);
+		if (band->isolate_loop_type[i] == isl_ast_loop_error)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Construct universe sets of the spaces that encode loop AST generation
+ * types (for the isolated part if "isolate" is set).  That is, construct
+ *
+ *	{ atomic[x]; separate[x]; unroll[x] }
+ *
+ * or
+ *
+ *	{ [isolate[] -> atomic[x]]; [isolate[] -> separate[x]];
+ *	  [isolate[] -> unroll[x]] }
+ */
+static __isl_give isl_union_set *loop_types(__isl_take isl_space *space,
+	int isolate)
+{
+	enum isl_ast_loop_type type;
+	isl_union_set *types;
+
+	types = isl_union_set_empty(space);
+	for (type = isl_ast_loop_atomic;
+	    type <= isl_ast_loop_separate; ++type) {
+		isl_set *set;
+
+		space = isl_union_set_get_space(types);
+		space = loop_type_space(space, type, isolate);
+		set = isl_set_universe(space);
+		types = isl_union_set_add_set(types, set);
+	}
+
+	return types;
+}
+
+/* Remove all elements from spaces that encode loop AST generation types
+ * from "options".
+ */
+static __isl_give isl_union_set *clear_loop_types(
+	__isl_take isl_union_set *options)
+{
+	isl_union_set *types;
+
+	types = loop_types(isl_union_set_get_space(options), 0);
+	options = isl_union_set_subtract(options, types);
+
+	return options;
+}
+
+/* Remove all elements from spaces that encode loop AST generation types
+ * for the isolated part from "options".
+ */
+static __isl_give isl_union_set *clear_isolate_loop_types(
+	__isl_take isl_union_set *options)
+{
+	isl_union_set *types;
+
+	types = loop_types(isl_union_set_get_space(options), 1);
+	options = isl_union_set_subtract(options, types);
+
+	return options;
+}
+
+/* Replace the AST build options associated to "band" by "options".
+ * If there are any loop AST generation type options, then they
+ * are extracted and stored in band->loop_type.  Otherwise,
+ * band->loop_type is removed to indicate that the default applies
+ * to all members.  Similarly for the loop AST generation type options
+ * for the isolated part, which are stored in band->isolate_loop_type.
+ * The remaining options are stored in band->ast_build_options.
+ *
+ * Set anchored if the options include an isolate option since the
+ * domain of the wrapped map references the outer band node schedules.
+ */
+__isl_give isl_schedule_band *isl_schedule_band_set_ast_build_options(
+	__isl_take isl_schedule_band *band, __isl_take isl_union_set *options)
+{
+	int has_isolate, has_loop_type, has_isolate_loop_type;
+
+	band = isl_schedule_band_cow(band);
+	if (!band || !options)
+		goto error;
+	has_isolate = has_isolate_option(options);
+	if (has_isolate < 0)
+		goto error;
+	has_loop_type = has_loop_type_options(options);
+	if (has_loop_type < 0)
+		goto error;
+	has_isolate_loop_type = has_isolate_loop_type_options(options);
+	if (has_isolate_loop_type < 0)
+		goto error;
+
+	if (!has_loop_type) {
+		free(band->loop_type);
+		band->loop_type = NULL;
+	} else {
+		if (extract_loop_types(band, options) < 0)
+			goto error;
+		options = clear_loop_types(options);
+		if (!options)
+			goto error;
+	}
+
+	if (!has_isolate_loop_type) {
+		free(band->isolate_loop_type);
+		band->isolate_loop_type = NULL;
+	} else {
+		if (extract_isolate_loop_types(band, options) < 0)
+			goto error;
+		options = clear_isolate_loop_types(options);
+		if (!options)
+			goto error;
+	}
+
+	isl_union_set_free(band->ast_build_options);
+	band->ast_build_options = options;
+	band->anchored = has_isolate;
+
+	return band;
+error:
+	isl_schedule_band_free(band);
+	isl_union_set_free(options);
+	return NULL;
+}
+
+/* Return the "isolate" option associated to "band", assuming
+ * it at appears at schedule depth "depth".
+ *
+ * The isolate option is of the form
+ *
+ *	isolate[[flattened outer bands] -> band]
+ */
+__isl_give isl_set *isl_schedule_band_get_ast_isolate_option(
+	__isl_keep isl_schedule_band *band, int depth)
+{
+	isl_space *space;
+	isl_set *isolate;
+
+	if (!band)
+		return NULL;
+
+	space = isl_schedule_band_get_space(band);
+	space = isl_space_from_range(space);
+	space = isl_space_add_dims(space, isl_dim_in, depth);
+	space = isl_space_wrap(space);
+	space = isl_space_set_tuple_name(space, isl_dim_set, "isolate");
+
+	isolate = isl_union_set_extract_set(band->ast_build_options, space);
+
+	return isolate;
+}
+
+/* Replace the option "drop" in the AST build options by "add".
+ * That is, remove "drop" and add "add".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_replace_ast_build_option(
+	__isl_take isl_schedule_band *band, __isl_take isl_set *drop,
+	__isl_take isl_set *add)
+{
+	isl_union_set *options;
+
+	band = isl_schedule_band_cow(band);
+	if (!band)
+		goto error;
+
+	options = band->ast_build_options;
+	options = isl_union_set_subtract(options, isl_union_set_from_set(drop));
+	options = isl_union_set_union(options, isl_union_set_from_set(add));
+	band->ast_build_options = options;
+
+	if (!band->ast_build_options)
+		return isl_schedule_band_free(band);
+
+	return band;
+error:
+	isl_schedule_band_free(band);
+	isl_set_free(drop);
+	isl_set_free(add);
+	return NULL;
+}
+
+/* Multiply the partial schedule of "band" with the factors in "mv".
+ * Replace the result by its greatest integer part to ensure
+ * that the schedule is always integral.
+ */
+__isl_give isl_schedule_band *isl_schedule_band_scale(
+	__isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv)
+{
+	band = isl_schedule_band_cow(band);
+	if (!band || !mv)
+		goto error;
+	band->mupa = isl_multi_union_pw_aff_scale_multi_val(band->mupa, mv);
+	band->mupa = isl_multi_union_pw_aff_floor(band->mupa);
+	if (!band->mupa)
+		return isl_schedule_band_free(band);
+	return band;
+error:
+	isl_schedule_band_free(band);
+	isl_multi_val_free(mv);
+	return NULL;
+}
+
+/* Divide the partial schedule of "band" by the factors in "mv".
+ * Replace the result by its greatest integer part to ensure
+ * that the schedule is always integral.
+ */
+__isl_give isl_schedule_band *isl_schedule_band_scale_down(
+	__isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv)
+{
+	band = isl_schedule_band_cow(band);
+	if (!band || !mv)
+		goto error;
+	band->mupa = isl_multi_union_pw_aff_scale_down_multi_val(band->mupa,
+								mv);
+	band->mupa = isl_multi_union_pw_aff_floor(band->mupa);
+	if (!band->mupa)
+		return isl_schedule_band_free(band);
+	return band;
+error:
+	isl_schedule_band_free(band);
+	isl_multi_val_free(mv);
+	return NULL;
+}
+
+/* Reduce the partial schedule of "band" modulo the factors in "mv".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_mod(
+	__isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv)
+{
+	band = isl_schedule_band_cow(band);
+	if (!band || !mv)
+		goto error;
+	band->mupa = isl_multi_union_pw_aff_mod_multi_val(band->mupa, mv);
+	if (!band->mupa)
+		return isl_schedule_band_free(band);
+	return band;
+error:
+	isl_schedule_band_free(band);
+	isl_multi_val_free(mv);
+	return NULL;
+}
+
+/* Shift the partial schedule of "band" by "shift" after checking
+ * that the domain of the partial schedule would not be affected
+ * by this shift.
+ */
+__isl_give isl_schedule_band *isl_schedule_band_shift(
+	__isl_take isl_schedule_band *band,
+	__isl_take isl_multi_union_pw_aff *shift)
+{
+	isl_union_set *dom1, *dom2;
+	isl_bool subset;
+
+	band = isl_schedule_band_cow(band);
+	if (!band || !shift)
+		goto error;
+	dom1 = isl_multi_union_pw_aff_domain(
+				isl_multi_union_pw_aff_copy(band->mupa));
+	dom2 = isl_multi_union_pw_aff_domain(
+				isl_multi_union_pw_aff_copy(shift));
+	subset = isl_union_set_is_subset(dom1, dom2);
+	isl_union_set_free(dom1);
+	isl_union_set_free(dom2);
+	if (subset < 0)
+		goto error;
+	if (!subset)
+		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
+			"domain of shift needs to include domain of "
+			"partial schedule", goto error);
+	band->mupa = isl_multi_union_pw_aff_add(band->mupa, shift);
+	if (!band->mupa)
+		return isl_schedule_band_free(band);
+	return band;
+error:
+	isl_schedule_band_free(band);
+	isl_multi_union_pw_aff_free(shift);
+	return NULL;
+}
+
+/* Given the schedule of a band, construct the corresponding
+ * schedule for the tile loops based on the given tile sizes
+ * and return the result.
+ *
+ * If the scale tile loops options is set, then the tile loops
+ * are scaled by the tile sizes.
+ *
+ * That is replace each schedule dimension "i" by either
+ * "floor(i/s)" or "s * floor(i/s)".
+ */
+static isl_multi_union_pw_aff *isl_multi_union_pw_aff_tile(
+	__isl_take isl_multi_union_pw_aff *sched,
+	__isl_take isl_multi_val *sizes)
+{
+	isl_ctx *ctx;
+	int i, n;
+	isl_val *v;
+	int scale;
+
+	ctx = isl_multi_val_get_ctx(sizes);
+	scale = isl_options_get_tile_scale_tile_loops(ctx);
+
+	n = isl_multi_union_pw_aff_dim(sched, isl_dim_set);
+	for (i = 0; i < n; ++i) {
+		isl_union_pw_aff *upa;
+
+		upa = isl_multi_union_pw_aff_get_union_pw_aff(sched, i);
+		v = isl_multi_val_get_val(sizes, i);
+
+		upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(v));
+		upa = isl_union_pw_aff_floor(upa);
+		if (scale)
+			upa = isl_union_pw_aff_scale_val(upa, isl_val_copy(v));
+		isl_val_free(v);
+
+		sched = isl_multi_union_pw_aff_set_union_pw_aff(sched, i, upa);
+	}
+
+	isl_multi_val_free(sizes);
+	return sched;
+}
+
+/* Replace "band" by a band corresponding to the tile loops of a tiling
+ * with the given tile sizes.
+ */
+__isl_give isl_schedule_band *isl_schedule_band_tile(
+	__isl_take isl_schedule_band *band, __isl_take isl_multi_val *sizes)
+{
+	band = isl_schedule_band_cow(band);
+	if (!band || !sizes)
+		goto error;
+	band->mupa = isl_multi_union_pw_aff_tile(band->mupa, sizes);
+	if (!band->mupa)
+		return isl_schedule_band_free(band);
+	return band;
+error:
+	isl_schedule_band_free(band);
+	isl_multi_val_free(sizes);
+	return NULL;
+}
+
+/* Replace "band" by a band corresponding to the point loops of a tiling
+ * with the given tile sizes.
+ * "tile" is the corresponding tile loop band.
+ *
+ * If the shift point loops option is set, then the point loops
+ * are shifted to start at zero.  That is, each schedule dimension "i"
+ * is replaced by "i - s * floor(i/s)".
+ * The expression "floor(i/s)" (or "s * floor(i/s)") is extracted from
+ * the tile band.
+ *
+ * Otherwise, the band is left untouched.
+ */
+__isl_give isl_schedule_band *isl_schedule_band_point(
+	__isl_take isl_schedule_band *band, __isl_keep isl_schedule_band *tile,
+	__isl_take isl_multi_val *sizes)
+{
+	isl_ctx *ctx;
+	isl_multi_union_pw_aff *scaled;
+
+	if (!band || !sizes)
+		goto error;
+
+	ctx = isl_schedule_band_get_ctx(band);
+	if (!isl_options_get_tile_shift_point_loops(ctx)) {
+		isl_multi_val_free(sizes);
+		return band;
+	}
+	band = isl_schedule_band_cow(band);
+	if (!band)
+		goto error;
+
+	scaled = isl_schedule_band_get_partial_schedule(tile);
+	if (!isl_options_get_tile_scale_tile_loops(ctx))
+		scaled = isl_multi_union_pw_aff_scale_multi_val(scaled, sizes);
+	else
+		isl_multi_val_free(sizes);
+	band->mupa = isl_multi_union_pw_aff_sub(band->mupa, scaled);
+	if (!band->mupa)
+		return isl_schedule_band_free(band);
+	return band;
+error:
+	isl_schedule_band_free(band);
+	isl_multi_val_free(sizes);
+	return NULL;
+}
+
+/* Drop the "n" dimensions starting at "pos" from "band".
+ *
+ * We apply the transformation even if "n" is zero to ensure consistent
+ * behavior with respect to changes in the schedule space.
+ *
+ * The caller is responsible for updating the isolate option.
+ */
+__isl_give isl_schedule_band *isl_schedule_band_drop(
+	__isl_take isl_schedule_band *band, int pos, int n)
+{
+	int i;
+
+	if (pos < 0 || n < 0 || pos + n > band->n)
+		isl_die(isl_schedule_band_get_ctx(band), isl_error_internal,
+			"range out of bounds",
+			return isl_schedule_band_free(band));
+
+	band = isl_schedule_band_cow(band);
+	if (!band)
+		return NULL;
+
+	band->mupa = isl_multi_union_pw_aff_drop_dims(band->mupa,
+							isl_dim_set, pos, n);
+	if (!band->mupa)
+		return isl_schedule_band_free(band);
+
+	for (i = pos + n; i < band->n; ++i)
+		band->coincident[i - n] = band->coincident[i];
+	if (band->loop_type)
+		for (i = pos + n; i < band->n; ++i)
+			band->loop_type[i - n] = band->loop_type[i];
+	if (band->isolate_loop_type)
+		for (i = pos + n; i < band->n; ++i)
+			band->isolate_loop_type[i - n] =
+						    band->isolate_loop_type[i];
+
+	band->n -= n;
+
+	return band;
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * in "band".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_reset_user(
+	__isl_take isl_schedule_band *band)
+{
+	band = isl_schedule_band_cow(band);
+	if (!band)
+		return NULL;
+
+	band->mupa = isl_multi_union_pw_aff_reset_user(band->mupa);
+	band->ast_build_options =
+		isl_union_set_reset_user(band->ast_build_options);
+	if (!band->mupa || !band->ast_build_options)
+		return isl_schedule_band_free(band);
+
+	return band;
+}
+
+/* Align the parameters of "band" to those of "space".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_align_params(
+	__isl_take isl_schedule_band *band, __isl_take isl_space *space)
+{
+	band = isl_schedule_band_cow(band);
+	if (!band || !space)
+		goto error;
+
+	band->mupa = isl_multi_union_pw_aff_align_params(band->mupa,
+						isl_space_copy(space));
+	band->ast_build_options =
+		isl_union_set_align_params(band->ast_build_options, space);
+	if (!band->mupa || !band->ast_build_options)
+		return isl_schedule_band_free(band);
+
+	return band;
+error:
+	isl_space_free(space);
+	isl_schedule_band_free(band);
+	return NULL;
+}
+
+/* Compute the pullback of "band" by the function represented by "upma".
+ * In other words, plug in "upma" in the iteration domains of "band".
+ */
+__isl_give isl_schedule_band *isl_schedule_band_pullback_union_pw_multi_aff(
+	__isl_take isl_schedule_band *band,
+	__isl_take isl_union_pw_multi_aff *upma)
+{
+	band = isl_schedule_band_cow(band);
+	if (!band || !upma)
+		goto error;
+
+	band->mupa =
+		isl_multi_union_pw_aff_pullback_union_pw_multi_aff(band->mupa,
+									upma);
+	if (!band->mupa)
+		return isl_schedule_band_free(band);
+
+	return band;
+error:
+	isl_union_pw_multi_aff_free(upma);
+	isl_schedule_band_free(band);
+	return NULL;
+}
+
+/* Compute the gist of "band" with respect to "context".
+ * In particular, compute the gist of the associated partial schedule.
+ */
+__isl_give isl_schedule_band *isl_schedule_band_gist(
+	__isl_take isl_schedule_band *band, __isl_take isl_union_set *context)
+{
+	if (!band || !context)
+		goto error;
+	if (band->n == 0) {
+		isl_union_set_free(context);
+		return band;
+	}
+	band = isl_schedule_band_cow(band);
+	if (!band)
+		goto error;
+	band->mupa = isl_multi_union_pw_aff_gist(band->mupa, context);
+	if (!band->mupa)
+		return isl_schedule_band_free(band);
+	return band;
+error:
+	isl_union_set_free(context);
+	isl_schedule_band_free(band);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_schedule_band.h b/final/lib/External/isl/isl_schedule_band.h
new file mode 100644
index 0000000..dcf16eb
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_band.h
@@ -0,0 +1,125 @@
+#ifndef ISL_SCHEDULE_BAND_H
+#define ISL_SCHEDULE_BAND_H
+
+#include <isl/aff.h>
+#include <isl/ast_type.h>
+#include <isl/union_map.h>
+
+/* Information about a band within a schedule.
+ *
+ * n is the number of scheduling dimensions within the band.
+ * coincident is an array of length n, indicating whether a scheduling dimension
+ *	satisfies the coincidence constraints in the sense that
+ *	the corresponding dependence distances are zero.
+ * permutable is set if the band is permutable.
+ * mupa is the partial schedule corresponding to this band.  The dimension
+ *	of mupa is equal to n.
+ * loop_type contains the loop AST generation types for the members
+ * in the band.  It may be NULL, if all members are
+ * of type isl_ast_loop_default.
+ * isolate_loop_type contains the loop AST generation types for the members
+ * in the band for the isolated part.  It may be NULL, if all members are
+ * of type isl_ast_loop_default.
+ * ast_build_options are the remaining AST build options associated
+ * to the band.
+ * anchored is set if the node depends on its position in the schedule tree.
+ *	In particular, it is set if the AST build options include
+ *	an isolate option.
+ */
+struct isl_schedule_band {
+	int ref;
+
+	int n;
+	int *coincident;
+	int permutable;
+
+	isl_multi_union_pw_aff *mupa;
+
+	int anchored;
+	isl_union_set *ast_build_options;
+	enum isl_ast_loop_type *loop_type;
+	enum isl_ast_loop_type *isolate_loop_type;
+};
+typedef struct isl_schedule_band isl_schedule_band;
+
+__isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff(
+	__isl_take isl_multi_union_pw_aff *mupa);
+__isl_give isl_schedule_band *isl_schedule_band_copy(
+	__isl_keep isl_schedule_band *band);
+__isl_null isl_schedule_band *isl_schedule_band_free(
+	__isl_take isl_schedule_band *band);
+
+isl_ctx *isl_schedule_band_get_ctx(__isl_keep isl_schedule_band *band);
+
+isl_bool isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1,
+	__isl_keep isl_schedule_band *band2);
+
+int isl_schedule_band_is_anchored(__isl_keep isl_schedule_band *band);
+
+__isl_give isl_space *isl_schedule_band_get_space(
+	__isl_keep isl_schedule_band *band);
+__isl_give isl_schedule_band *isl_schedule_band_intersect_domain(
+	__isl_take isl_schedule_band *band, __isl_take isl_union_set *domain);
+__isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule(
+	__isl_keep isl_schedule_band *band);
+__isl_give isl_schedule_band *isl_schedule_band_set_partial_schedule(
+	__isl_take isl_schedule_band *band,
+	__isl_take isl_multi_union_pw_aff *schedule);
+enum isl_ast_loop_type isl_schedule_band_member_get_ast_loop_type(
+	__isl_keep isl_schedule_band *band, int pos);
+__isl_give isl_schedule_band *isl_schedule_band_member_set_ast_loop_type(
+	__isl_take isl_schedule_band *band, int pos,
+	enum isl_ast_loop_type type);
+enum isl_ast_loop_type isl_schedule_band_member_get_isolate_ast_loop_type(
+	__isl_keep isl_schedule_band *band, int pos);
+__isl_give isl_schedule_band *
+isl_schedule_band_member_set_isolate_ast_loop_type(
+	__isl_take isl_schedule_band *band, int pos,
+	enum isl_ast_loop_type type);
+__isl_give isl_union_set *isl_schedule_band_get_ast_build_options(
+	__isl_keep isl_schedule_band *band);
+__isl_give isl_schedule_band *isl_schedule_band_set_ast_build_options(
+	__isl_take isl_schedule_band *band, __isl_take isl_union_set *options);
+__isl_give isl_set *isl_schedule_band_get_ast_isolate_option(
+	__isl_keep isl_schedule_band *band, int depth);
+__isl_give isl_schedule_band *isl_schedule_band_replace_ast_build_option(
+	__isl_take isl_schedule_band *band, __isl_take isl_set *drop,
+	__isl_take isl_set *add);
+
+int isl_schedule_band_n_member(__isl_keep isl_schedule_band *band);
+isl_bool isl_schedule_band_member_get_coincident(
+	__isl_keep isl_schedule_band *band, int pos);
+__isl_give isl_schedule_band *isl_schedule_band_member_set_coincident(
+	__isl_take isl_schedule_band *band, int pos, int coincident);
+isl_bool isl_schedule_band_get_permutable(__isl_keep isl_schedule_band *band);
+__isl_give isl_schedule_band *isl_schedule_band_set_permutable(
+	__isl_take isl_schedule_band *band, int permutable);
+
+__isl_give isl_schedule_band *isl_schedule_band_scale(
+	__isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv);
+__isl_give isl_schedule_band *isl_schedule_band_scale_down(
+	__isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv);
+__isl_give isl_schedule_band *isl_schedule_band_mod(
+	__isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv);
+__isl_give isl_schedule_band *isl_schedule_band_tile(
+	__isl_take isl_schedule_band *band, __isl_take isl_multi_val *sizes);
+__isl_give isl_schedule_band *isl_schedule_band_point(
+	__isl_take isl_schedule_band *band, __isl_keep isl_schedule_band *tile,
+	__isl_take isl_multi_val *sizes);
+__isl_give isl_schedule_band *isl_schedule_band_shift(
+	__isl_take isl_schedule_band *band,
+	__isl_take isl_multi_union_pw_aff *shift);
+__isl_give isl_schedule_band *isl_schedule_band_drop(
+	__isl_take isl_schedule_band *band, int pos, int n);
+__isl_give isl_schedule_band *isl_schedule_band_gist(
+	__isl_take isl_schedule_band *band, __isl_take isl_union_set *context);
+
+__isl_give isl_schedule_band *isl_schedule_band_reset_user(
+	__isl_take isl_schedule_band *band);
+__isl_give isl_schedule_band *isl_schedule_band_align_params(
+	__isl_take isl_schedule_band *band, __isl_take isl_space *space);
+__isl_give isl_schedule_band *isl_schedule_band_pullback_union_pw_multi_aff(
+	__isl_take isl_schedule_band *band,
+	__isl_take isl_union_pw_multi_aff *upma);
+
+#endif
diff --git a/final/lib/External/isl/isl_schedule_constraints.c b/final/lib/External/isl/isl_schedule_constraints.c
new file mode 100644
index 0000000..af7ca29
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_constraints.c
@@ -0,0 +1,725 @@
+/*
+ * Copyright 2012      Ecole Normale Superieure
+ * Copyright 2015-2016 Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_schedule_constraints.h>
+#include <isl/schedule.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl/stream.h>
+
+/* The constraints that need to be satisfied by a schedule on "domain".
+ *
+ * "context" specifies extra constraints on the parameters.
+ *
+ * "validity" constraints map domain elements i to domain elements
+ * that should be scheduled after i.  (Hard constraint)
+ * "proximity" constraints map domain elements i to domains elements
+ * that should be scheduled as early as possible after i (or before i).
+ * (Soft constraint)
+ *
+ * "condition" and "conditional_validity" constraints map possibly "tagged"
+ * domain elements i -> s to "tagged" domain elements j -> t.
+ * The elements of the "conditional_validity" constraints, but without the
+ * tags (i.e., the elements i -> j) are treated as validity constraints,
+ * except that during the construction of a tilable band,
+ * the elements of the "conditional_validity" constraints may be violated
+ * provided that all adjacent elements of the "condition" constraints
+ * are local within the band.
+ * A dependence is local within a band if domain and range are mapped
+ * to the same schedule point by the band.
+ */
+struct isl_schedule_constraints {
+	isl_union_set *domain;
+	isl_set *context;
+
+	isl_union_map *constraint[isl_edge_last + 1];
+};
+
+__isl_give isl_schedule_constraints *isl_schedule_constraints_copy(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	isl_ctx *ctx;
+	isl_schedule_constraints *sc_copy;
+	enum isl_edge_type i;
+
+	ctx = isl_union_set_get_ctx(sc->domain);
+	sc_copy = isl_calloc_type(ctx, struct isl_schedule_constraints);
+	if (!sc_copy)
+		return NULL;
+
+	sc_copy->domain = isl_union_set_copy(sc->domain);
+	sc_copy->context = isl_set_copy(sc->context);
+	if (!sc_copy->domain || !sc_copy->context)
+		return isl_schedule_constraints_free(sc_copy);
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		sc_copy->constraint[i] = isl_union_map_copy(sc->constraint[i]);
+		if (!sc_copy->constraint[i])
+			return isl_schedule_constraints_free(sc_copy);
+	}
+
+	return sc_copy;
+}
+
+/* Construct an empty (invalid) isl_schedule_constraints object.
+ * The caller is responsible for setting the domain and initializing
+ * all the other fields, e.g., by calling isl_schedule_constraints_init.
+ */
+static __isl_give isl_schedule_constraints *isl_schedule_constraints_alloc(
+	isl_ctx *ctx)
+{
+	return isl_calloc_type(ctx, struct isl_schedule_constraints);
+}
+
+/* Initialize all the fields of "sc", except domain, which is assumed
+ * to have been set by the caller.
+ */
+static __isl_give isl_schedule_constraints *isl_schedule_constraints_init(
+	__isl_take isl_schedule_constraints *sc)
+{
+	isl_space *space;
+	isl_union_map *empty;
+	enum isl_edge_type i;
+
+	if (!sc)
+		return NULL;
+	if (!sc->domain)
+		return isl_schedule_constraints_free(sc);
+	space = isl_union_set_get_space(sc->domain);
+	if (!sc->context)
+		sc->context = isl_set_universe(isl_space_copy(space));
+	empty = isl_union_map_empty(space);
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		if (sc->constraint[i])
+			continue;
+		sc->constraint[i] = isl_union_map_copy(empty);
+		if (!sc->constraint[i])
+			sc->domain = isl_union_set_free(sc->domain);
+	}
+	isl_union_map_free(empty);
+
+	if (!sc->domain || !sc->context)
+		return isl_schedule_constraints_free(sc);
+
+	return sc;
+}
+
+/* Construct an isl_schedule_constraints object for computing a schedule
+ * on "domain".  The initial object does not impose any constraints.
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_on_domain(
+	__isl_take isl_union_set *domain)
+{
+	isl_ctx *ctx;
+	isl_schedule_constraints *sc;
+
+	if (!domain)
+		return NULL;
+
+	ctx = isl_union_set_get_ctx(domain);
+	sc = isl_schedule_constraints_alloc(ctx);
+	if (!sc)
+		goto error;
+
+	sc->domain = domain;
+	return isl_schedule_constraints_init(sc);
+error:
+	isl_union_set_free(domain);
+	return NULL;
+}
+
+/* Replace the domain of "sc" by "domain".
+ */
+static __isl_give isl_schedule_constraints *isl_schedule_constraints_set_domain(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_set *domain)
+{
+	if (!sc || !domain)
+		goto error;
+
+	isl_union_set_free(sc->domain);
+	sc->domain = domain;
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_union_set_free(domain);
+	return NULL;
+}
+
+/* Replace the context of "sc" by "context".
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_set_context(
+	__isl_take isl_schedule_constraints *sc, __isl_take isl_set *context)
+{
+	if (!sc || !context)
+		goto error;
+
+	isl_set_free(sc->context);
+	sc->context = context;
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_set_free(context);
+	return NULL;
+}
+
+/* Replace the constraints of type "type" in "sc" by "c".
+ */
+static __isl_give isl_schedule_constraints *isl_schedule_constraints_set(
+	__isl_take isl_schedule_constraints *sc, enum isl_edge_type type,
+	__isl_take isl_union_map *c)
+{
+	if (!sc || !c)
+		goto error;
+
+	isl_union_map_free(sc->constraint[type]);
+	sc->constraint[type] = c;
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_union_map_free(c);
+	return NULL;
+}
+
+/* Replace the validity constraints of "sc" by "validity".
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_set_validity(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *validity)
+{
+	return isl_schedule_constraints_set(sc, isl_edge_validity, validity);
+}
+
+/* Replace the coincidence constraints of "sc" by "coincidence".
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_set_coincidence(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *coincidence)
+{
+	return isl_schedule_constraints_set(sc, isl_edge_coincidence,
+						coincidence);
+}
+
+/* Replace the proximity constraints of "sc" by "proximity".
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_set_proximity(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *proximity)
+{
+	return isl_schedule_constraints_set(sc, isl_edge_proximity, proximity);
+}
+
+/* Replace the conditional validity constraints of "sc" by "condition"
+ * and "validity".
+ */
+__isl_give isl_schedule_constraints *
+isl_schedule_constraints_set_conditional_validity(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *condition,
+	__isl_take isl_union_map *validity)
+{
+	sc = isl_schedule_constraints_set(sc, isl_edge_condition, condition);
+	sc = isl_schedule_constraints_set(sc, isl_edge_conditional_validity,
+						validity);
+	return sc;
+}
+
+__isl_null isl_schedule_constraints *isl_schedule_constraints_free(
+	__isl_take isl_schedule_constraints *sc)
+{
+	enum isl_edge_type i;
+
+	if (!sc)
+		return NULL;
+
+	isl_union_set_free(sc->domain);
+	isl_set_free(sc->context);
+	for (i = isl_edge_first; i <= isl_edge_last; ++i)
+		isl_union_map_free(sc->constraint[i]);
+
+	free(sc);
+
+	return NULL;
+}
+
+isl_ctx *isl_schedule_constraints_get_ctx(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	return sc ? isl_union_set_get_ctx(sc->domain) : NULL;
+}
+
+/* Return the domain of "sc".
+ */
+__isl_give isl_union_set *isl_schedule_constraints_get_domain(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	if (!sc)
+		return NULL;
+
+	return isl_union_set_copy(sc->domain);
+}
+
+/* Return the context of "sc".
+ */
+__isl_give isl_set *isl_schedule_constraints_get_context(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	if (!sc)
+		return NULL;
+
+	return isl_set_copy(sc->context);
+}
+
+/* Return the constraints of type "type" in "sc".
+ */
+__isl_give isl_union_map *isl_schedule_constraints_get(
+	__isl_keep isl_schedule_constraints *sc, enum isl_edge_type type)
+{
+	if (!sc)
+		return NULL;
+
+	return isl_union_map_copy(sc->constraint[type]);
+}
+
+/* Return the validity constraints of "sc".
+ */
+__isl_give isl_union_map *isl_schedule_constraints_get_validity(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	return isl_schedule_constraints_get(sc, isl_edge_validity);
+}
+
+/* Return the coincidence constraints of "sc".
+ */
+__isl_give isl_union_map *isl_schedule_constraints_get_coincidence(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	return isl_schedule_constraints_get(sc, isl_edge_coincidence);
+}
+
+/* Return the proximity constraints of "sc".
+ */
+__isl_give isl_union_map *isl_schedule_constraints_get_proximity(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	return isl_schedule_constraints_get(sc, isl_edge_proximity);
+}
+
+/* Return the conditional validity constraints of "sc".
+ */
+__isl_give isl_union_map *isl_schedule_constraints_get_conditional_validity(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	return isl_schedule_constraints_get(sc, isl_edge_conditional_validity);
+}
+
+/* Return the conditions for the conditional validity constraints of "sc".
+ */
+__isl_give isl_union_map *
+isl_schedule_constraints_get_conditional_validity_condition(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	return isl_schedule_constraints_get(sc, isl_edge_condition);
+}
+
+/* Add "c" to the constraints of type "type" in "sc".
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_add(
+	__isl_take isl_schedule_constraints *sc, enum isl_edge_type type,
+	__isl_take isl_union_map *c)
+{
+	if (!sc || !c)
+		goto error;
+
+	c = isl_union_map_union(sc->constraint[type], c);
+	sc->constraint[type] = c;
+	if (!c)
+		return isl_schedule_constraints_free(sc);
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_union_map_free(c);
+	return NULL;
+}
+
+/* Can a schedule constraint of type "type" be tagged?
+ */
+static int may_be_tagged(enum isl_edge_type type)
+{
+	if (type == isl_edge_condition || type == isl_edge_conditional_validity)
+		return 1;
+	return 0;
+}
+
+/* Apply "umap" to the domains of the wrapped relations
+ * inside the domain and range of "c".
+ *
+ * That is, for each map of the form
+ *
+ *	[D -> S] -> [E -> T]
+ *
+ * in "c", apply "umap" to D and E.
+ *
+ * D is exposed by currying the relation to
+ *
+ *	D -> [S -> [E -> T]]
+ *
+ * E is exposed by doing the same to the inverse of "c".
+ */
+static __isl_give isl_union_map *apply_factor_domain(
+	__isl_take isl_union_map *c, __isl_keep isl_union_map *umap)
+{
+	c = isl_union_map_curry(c);
+	c = isl_union_map_apply_domain(c, isl_union_map_copy(umap));
+	c = isl_union_map_uncurry(c);
+
+	c = isl_union_map_reverse(c);
+	c = isl_union_map_curry(c);
+	c = isl_union_map_apply_domain(c, isl_union_map_copy(umap));
+	c = isl_union_map_uncurry(c);
+	c = isl_union_map_reverse(c);
+
+	return c;
+}
+
+/* Apply "umap" to domain and range of "c".
+ * If "tag" is set, then "c" may contain tags and then "umap"
+ * needs to be applied to the domains of the wrapped relations
+ * inside the domain and range of "c".
+ */
+static __isl_give isl_union_map *apply(__isl_take isl_union_map *c,
+	__isl_keep isl_union_map *umap, int tag)
+{
+	isl_union_map *t;
+
+	if (tag)
+		t = isl_union_map_copy(c);
+	c = isl_union_map_apply_domain(c, isl_union_map_copy(umap));
+	c = isl_union_map_apply_range(c, isl_union_map_copy(umap));
+	if (!tag)
+		return c;
+	t = apply_factor_domain(t, umap);
+	c = isl_union_map_union(c, t);
+	return c;
+}
+
+/* Apply "umap" to the domain of the schedule constraints "sc".
+ *
+ * The two sides of the various schedule constraints are adjusted
+ * accordingly.
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_apply(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_take isl_union_map *umap)
+{
+	enum isl_edge_type i;
+
+	if (!sc || !umap)
+		goto error;
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		int tag = may_be_tagged(i);
+
+		sc->constraint[i] = apply(sc->constraint[i], umap, tag);
+		if (!sc->constraint[i])
+			goto error;
+	}
+	sc->domain = isl_union_set_apply(sc->domain, umap);
+	if (!sc->domain)
+		return isl_schedule_constraints_free(sc);
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_union_map_free(umap);
+	return NULL;
+}
+
+/* An enumeration of the various keys that may appear in a YAML mapping
+ * of an isl_schedule_constraints object.
+ * The keys for the edge types are assumed to have the same values
+ * as the edge types in isl_edge_type.
+ */
+enum isl_sc_key {
+	isl_sc_key_error = -1,
+	isl_sc_key_validity = isl_edge_validity,
+	isl_sc_key_coincidence = isl_edge_coincidence,
+	isl_sc_key_condition = isl_edge_condition,
+	isl_sc_key_conditional_validity = isl_edge_conditional_validity,
+	isl_sc_key_proximity = isl_edge_proximity,
+	isl_sc_key_domain,
+	isl_sc_key_context,
+	isl_sc_key_end
+};
+
+/* Textual representations of the YAML keys for an isl_schedule_constraints
+ * object.
+ */
+static char *key_str[] = {
+	[isl_sc_key_validity] = "validity",
+	[isl_sc_key_coincidence] = "coincidence",
+	[isl_sc_key_condition] = "condition",
+	[isl_sc_key_conditional_validity] = "conditional_validity",
+	[isl_sc_key_proximity] = "proximity",
+	[isl_sc_key_domain] = "domain",
+	[isl_sc_key_context] = "context",
+};
+
+/* Print a key, value pair for the edge of type "type" in "sc" to "p".
+ */
+static __isl_give isl_printer *print_constraint(__isl_take isl_printer *p,
+	__isl_keep isl_schedule_constraints *sc, enum isl_edge_type type)
+{
+	p = isl_printer_print_str(p, key_str[type]);
+	p = isl_printer_yaml_next(p);
+	p = isl_printer_print_union_map(p, sc->constraint[type]);
+	p = isl_printer_yaml_next(p);
+
+	return p;
+}
+
+/* Print "sc" to "p"
+ *
+ * In particular, print the isl_schedule_constraints object as a YAML document.
+ */
+__isl_give isl_printer *isl_printer_print_schedule_constraints(
+	__isl_take isl_printer *p, __isl_keep isl_schedule_constraints *sc)
+{
+	if (!sc)
+		return isl_printer_free(p);
+
+	p = isl_printer_yaml_start_mapping(p);
+	p = isl_printer_print_str(p, key_str[isl_sc_key_domain]);
+	p = isl_printer_yaml_next(p);
+	p = isl_printer_print_union_set(p, sc->domain);
+	p = isl_printer_yaml_next(p);
+	p = isl_printer_print_str(p, key_str[isl_sc_key_context]);
+	p = isl_printer_yaml_next(p);
+	p = isl_printer_print_set(p, sc->context);
+	p = isl_printer_yaml_next(p);
+	p = print_constraint(p, sc, isl_edge_validity);
+	p = print_constraint(p, sc, isl_edge_proximity);
+	p = print_constraint(p, sc, isl_edge_coincidence);
+	p = print_constraint(p, sc, isl_edge_condition);
+	p = print_constraint(p, sc, isl_edge_conditional_validity);
+	p = isl_printer_yaml_end_mapping(p);
+
+	return p;
+}
+
+#undef BASE
+#define BASE schedule_constraints
+#include <print_templ_yaml.c>
+
+#undef KEY
+#define KEY enum isl_sc_key
+#undef KEY_ERROR
+#define KEY_ERROR isl_sc_key_error
+#undef KEY_END
+#define KEY_END isl_sc_key_end
+#include "extract_key.c"
+
+#undef BASE
+#define BASE set
+#include "read_in_string_templ.c"
+
+#undef BASE
+#define BASE union_set
+#include "read_in_string_templ.c"
+
+#undef BASE
+#define BASE union_map
+#include "read_in_string_templ.c"
+
+/* Read an isl_schedule_constraints object from "s".
+ *
+ * Start off with an empty (invalid) isl_schedule_constraints object and
+ * then fill up the fields based on the input.
+ * The input needs to contain at least a description of the domain.
+ * The other fields are set to defaults by isl_schedule_constraints_init
+ * if they are not specified in the input.
+ */
+__isl_give isl_schedule_constraints *isl_stream_read_schedule_constraints(
+	isl_stream *s)
+{
+	isl_ctx *ctx;
+	isl_schedule_constraints *sc;
+	int more;
+	int domain_set = 0;
+
+	if (isl_stream_yaml_read_start_mapping(s))
+		return NULL;
+
+	ctx = isl_stream_get_ctx(s);
+	sc = isl_schedule_constraints_alloc(ctx);
+	while ((more = isl_stream_yaml_next(s)) > 0) {
+		enum isl_sc_key key;
+		isl_set *context;
+		isl_union_set *domain;
+		isl_union_map *constraints;
+
+		key = get_key(s);
+		if (isl_stream_yaml_next(s) < 0)
+			return isl_schedule_constraints_free(sc);
+		switch (key) {
+		case isl_sc_key_end:
+		case isl_sc_key_error:
+			return isl_schedule_constraints_free(sc);
+		case isl_sc_key_domain:
+			domain_set = 1;
+			domain = read_union_set(s);
+			sc = isl_schedule_constraints_set_domain(sc, domain);
+			if (!sc)
+				return NULL;
+			break;
+		case isl_sc_key_context:
+			context = read_set(s);
+			sc = isl_schedule_constraints_set_context(sc, context);
+			if (!sc)
+				return NULL;
+			break;
+		default:
+			constraints = read_union_map(s);
+			sc = isl_schedule_constraints_set(sc, key, constraints);
+			if (!sc)
+				return NULL;
+			break;
+		}
+	}
+	if (more < 0)
+		return isl_schedule_constraints_free(sc);
+
+	if (isl_stream_yaml_read_end_mapping(s) < 0) {
+		isl_stream_error(s, NULL, "unexpected extra elements");
+		return isl_schedule_constraints_free(sc);
+	}
+
+	if (!domain_set) {
+		isl_stream_error(s, NULL, "no domain specified");
+		return isl_schedule_constraints_free(sc);
+	}
+
+	return isl_schedule_constraints_init(sc);
+}
+
+/* Read an isl_schedule_constraints object from the file "input".
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_file(
+	isl_ctx *ctx, FILE *input)
+{
+	struct isl_stream *s;
+	isl_schedule_constraints *sc;
+
+	s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	sc = isl_stream_read_schedule_constraints(s);
+	isl_stream_free(s);
+
+	return sc;
+}
+
+/* Read an isl_schedule_constraints object from the string "str".
+ */
+__isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_str(
+	isl_ctx *ctx, const char *str)
+{
+	struct isl_stream *s;
+	isl_schedule_constraints *sc;
+
+	s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	sc = isl_stream_read_schedule_constraints(s);
+	isl_stream_free(s);
+
+	return sc;
+}
+
+/* Align the parameters of the fields of "sc".
+ */
+__isl_give isl_schedule_constraints *
+isl_schedule_constraints_align_params(__isl_take isl_schedule_constraints *sc)
+{
+	isl_space *space;
+	enum isl_edge_type i;
+
+	if (!sc)
+		return NULL;
+
+	space = isl_union_set_get_space(sc->domain);
+	space = isl_space_align_params(space, isl_set_get_space(sc->context));
+	for (i = isl_edge_first; i <= isl_edge_last; ++i)
+		space = isl_space_align_params(space,
+				    isl_union_map_get_space(sc->constraint[i]));
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		sc->constraint[i] = isl_union_map_align_params(
+				    sc->constraint[i], isl_space_copy(space));
+		if (!sc->constraint[i])
+			space = isl_space_free(space);
+	}
+	sc->context = isl_set_align_params(sc->context, isl_space_copy(space));
+	sc->domain = isl_union_set_align_params(sc->domain, space);
+	if (!sc->context || !sc->domain)
+		return isl_schedule_constraints_free(sc);
+
+	return sc;
+}
+
+/* Add the number of basic maps in "map" to *n.
+ */
+static isl_stat add_n_basic_map(__isl_take isl_map *map, void *user)
+{
+	int *n = user;
+
+	*n += isl_map_n_basic_map(map);
+	isl_map_free(map);
+
+	return isl_stat_ok;
+}
+
+/* Return the total number of isl_basic_maps in the constraints of "sc".
+ * Return -1 on error.
+ */
+int isl_schedule_constraints_n_basic_map(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	enum isl_edge_type i;
+	int n = 0;
+
+	if (!sc)
+		return -1;
+	for (i = isl_edge_first; i <= isl_edge_last; ++i)
+		if (isl_union_map_foreach_map(sc->constraint[i],
+						&add_n_basic_map, &n) < 0)
+			return -1;
+
+	return n;
+}
+
+/* Return the total number of isl_maps in the constraints of "sc".
+ */
+int isl_schedule_constraints_n_map(__isl_keep isl_schedule_constraints *sc)
+{
+	enum isl_edge_type i;
+	int n = 0;
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i)
+		n += isl_union_map_n_map(sc->constraint[i]);
+
+	return n;
+}
diff --git a/final/lib/External/isl/isl_schedule_constraints.h b/final/lib/External/isl/isl_schedule_constraints.h
new file mode 100644
index 0000000..a50ec62
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_constraints.h
@@ -0,0 +1,30 @@
+#ifndef ISL_SCHEDULE_CONSTRAINTS_H
+#define ISL_SCHEDULE_CONSTRAINTS_H
+
+#include <isl/schedule.h>
+
+enum isl_edge_type {
+	isl_edge_validity = 0,
+	isl_edge_first = isl_edge_validity,
+	isl_edge_coincidence,
+	isl_edge_condition,
+	isl_edge_conditional_validity,
+	isl_edge_proximity,
+	isl_edge_last = isl_edge_proximity,
+	isl_edge_local
+};
+
+__isl_give isl_schedule_constraints *
+isl_schedule_constraints_align_params(__isl_take isl_schedule_constraints *sc);
+
+__isl_give isl_union_map *isl_schedule_constraints_get(
+	__isl_keep isl_schedule_constraints *sc, enum isl_edge_type type);
+__isl_give isl_schedule_constraints *isl_schedule_constraints_add(
+	__isl_take isl_schedule_constraints *sc, enum isl_edge_type type,
+	__isl_take isl_union_map *c);
+
+int isl_schedule_constraints_n_basic_map(
+	__isl_keep isl_schedule_constraints *sc);
+int isl_schedule_constraints_n_map(__isl_keep isl_schedule_constraints *sc);
+
+#endif
diff --git a/final/lib/External/isl/isl_schedule_node.c b/final/lib/External/isl/isl_schedule_node.c
new file mode 100644
index 0000000..3a53dfe
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_node.c
@@ -0,0 +1,4713 @@
+/*
+ * Copyright 2013-2014 Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ * Copyright 2016      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <isl/set.h>
+#include <isl_schedule_band.h>
+#include <isl_schedule_private.h>
+#include <isl_schedule_node_private.h>
+
+/* Create a new schedule node in the given schedule, point at the given
+ * tree with given ancestors and child positions.
+ * "child_pos" may be NULL if there are no ancestors.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_alloc(
+	__isl_take isl_schedule *schedule, __isl_take isl_schedule_tree *tree,
+	__isl_take isl_schedule_tree_list *ancestors, int *child_pos)
+{
+	isl_ctx *ctx;
+	isl_schedule_node *node;
+	int i, n;
+
+	if (!schedule || !tree || !ancestors)
+		goto error;
+	n = isl_schedule_tree_list_n_schedule_tree(ancestors);
+	if (n > 0 && !child_pos)
+		goto error;
+	ctx = isl_schedule_get_ctx(schedule);
+	node = isl_calloc_type(ctx, isl_schedule_node);
+	if (!node)
+		goto error;
+	node->ref = 1;
+	node->schedule = schedule;
+	node->tree = tree;
+	node->ancestors = ancestors;
+	node->child_pos = isl_alloc_array(ctx, int, n);
+	if (n && !node->child_pos)
+		return isl_schedule_node_free(node);
+	for (i = 0; i < n; ++i)
+		node->child_pos[i] = child_pos[i];
+
+	return node;
+error:
+	isl_schedule_free(schedule);
+	isl_schedule_tree_free(tree);
+	isl_schedule_tree_list_free(ancestors);
+	return NULL;
+}
+
+/* Return a pointer to the root of a schedule tree with as single
+ * node a domain node with the given domain.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_from_domain(
+	__isl_take isl_union_set *domain)
+{
+	isl_schedule *schedule;
+	isl_schedule_node *node;
+
+	schedule = isl_schedule_from_domain(domain);
+	node = isl_schedule_get_root(schedule);
+	isl_schedule_free(schedule);
+
+	return node;
+}
+
+/* Return a pointer to the root of a schedule tree with as single
+ * node a extension node with the given extension.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_from_extension(
+	__isl_take isl_union_map *extension)
+{
+	isl_ctx *ctx;
+	isl_schedule *schedule;
+	isl_schedule_tree *tree;
+	isl_schedule_node *node;
+
+	if (!extension)
+		return NULL;
+
+	ctx = isl_union_map_get_ctx(extension);
+	tree = isl_schedule_tree_from_extension(extension);
+	schedule = isl_schedule_from_schedule_tree(ctx, tree);
+	node = isl_schedule_get_root(schedule);
+	isl_schedule_free(schedule);
+
+	return node;
+}
+
+/* Return the isl_ctx to which "node" belongs.
+ */
+isl_ctx *isl_schedule_node_get_ctx(__isl_keep isl_schedule_node *node)
+{
+	return node ? isl_schedule_get_ctx(node->schedule) : NULL;
+}
+
+/* Return a pointer to the leaf of the schedule into which "node" points.
+ */
+__isl_keep isl_schedule_tree *isl_schedule_node_peek_leaf(
+	__isl_keep isl_schedule_node *node)
+{
+	return node ? isl_schedule_peek_leaf(node->schedule) : NULL;
+}
+
+/* Return a copy of the leaf of the schedule into which "node" points.
+ */
+__isl_give isl_schedule_tree *isl_schedule_node_get_leaf(
+	__isl_keep isl_schedule_node *node)
+{
+	return isl_schedule_tree_copy(isl_schedule_node_peek_leaf(node));
+}
+
+/* Return the type of the node or isl_schedule_node_error on error.
+ */
+enum isl_schedule_node_type isl_schedule_node_get_type(
+	__isl_keep isl_schedule_node *node)
+{
+	return node ? isl_schedule_tree_get_type(node->tree)
+		    : isl_schedule_node_error;
+}
+
+/* Return the type of the parent of "node" or isl_schedule_node_error on error.
+ */
+enum isl_schedule_node_type isl_schedule_node_get_parent_type(
+	__isl_keep isl_schedule_node *node)
+{
+	int pos;
+	int has_parent;
+	isl_schedule_tree *parent;
+	enum isl_schedule_node_type type;
+
+	if (!node)
+		return isl_schedule_node_error;
+	has_parent = isl_schedule_node_has_parent(node);
+	if (has_parent < 0)
+		return isl_schedule_node_error;
+	if (!has_parent)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"node has no parent", return isl_schedule_node_error);
+
+	pos = isl_schedule_tree_list_n_schedule_tree(node->ancestors) - 1;
+	parent = isl_schedule_tree_list_get_schedule_tree(node->ancestors, pos);
+	type = isl_schedule_tree_get_type(parent);
+	isl_schedule_tree_free(parent);
+
+	return type;
+}
+
+/* Return a copy of the subtree that this node points to.
+ */
+__isl_give isl_schedule_tree *isl_schedule_node_get_tree(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_tree_copy(node->tree);
+}
+
+/* Return a copy of the schedule into which "node" points.
+ */
+__isl_give isl_schedule *isl_schedule_node_get_schedule(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+	return isl_schedule_copy(node->schedule);
+}
+
+/* Return a fresh copy of "node".
+ */
+__isl_take isl_schedule_node *isl_schedule_node_dup(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_node_alloc(isl_schedule_copy(node->schedule),
+				isl_schedule_tree_copy(node->tree),
+				isl_schedule_tree_list_copy(node->ancestors),
+				node->child_pos);
+}
+
+/* Return an isl_schedule_node that is equal to "node" and that has only
+ * a single reference.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_cow(
+	__isl_take isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	if (node->ref == 1)
+		return node;
+	node->ref--;
+	return isl_schedule_node_dup(node);
+}
+
+/* Return a new reference to "node".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_copy(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	node->ref++;
+	return node;
+}
+
+/* Free "node" and return NULL.
+ */
+__isl_null isl_schedule_node *isl_schedule_node_free(
+	__isl_take isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+	if (--node->ref > 0)
+		return NULL;
+
+	isl_schedule_tree_list_free(node->ancestors);
+	free(node->child_pos);
+	isl_schedule_tree_free(node->tree);
+	isl_schedule_free(node->schedule);
+	free(node);
+
+	return NULL;
+}
+
+/* Do "node1" and "node2" point to the same position in the same
+ * schedule?
+ */
+isl_bool isl_schedule_node_is_equal(__isl_keep isl_schedule_node *node1,
+	__isl_keep isl_schedule_node *node2)
+{
+	int i, n1, n2;
+
+	if (!node1 || !node2)
+		return isl_bool_error;
+	if (node1 == node2)
+		return isl_bool_true;
+	if (node1->schedule != node2->schedule)
+		return isl_bool_false;
+
+	n1 = isl_schedule_node_get_tree_depth(node1);
+	n2 = isl_schedule_node_get_tree_depth(node2);
+	if (n1 != n2)
+		return isl_bool_false;
+	for (i = 0; i < n1; ++i)
+		if (node1->child_pos[i] != node2->child_pos[i])
+			return isl_bool_false;
+
+	return isl_bool_true;
+}
+
+/* Return the number of outer schedule dimensions of "node"
+ * in its schedule tree.
+ *
+ * Return -1 on error.
+ */
+int isl_schedule_node_get_schedule_depth(__isl_keep isl_schedule_node *node)
+{
+	int i, n;
+	int depth = 0;
+
+	if (!node)
+		return -1;
+
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	for (i = n - 1; i >= 0; --i) {
+		isl_schedule_tree *tree;
+
+		tree = isl_schedule_tree_list_get_schedule_tree(
+						    node->ancestors, i);
+		if (!tree)
+			return -1;
+		if (tree->type == isl_schedule_node_band)
+			depth += isl_schedule_tree_band_n_member(tree);
+		isl_schedule_tree_free(tree);
+	}
+
+	return depth;
+}
+
+/* Internal data structure for
+ * isl_schedule_node_get_prefix_schedule_union_pw_multi_aff
+ *
+ * "initialized" is set if the filter field has been initialized.
+ * If "universe_domain" is not set, then the collected filter is intersected
+ * with the the domain of the root domain node.
+ * "universe_filter" is set if we are only collecting the universes of filters
+ * "collect_prefix" is set if we are collecting prefixes.
+ * "filter" collects all outer filters and is NULL until "initialized" is set.
+ * "prefix" collects all outer band partial schedules (if "collect_prefix"
+ * is set).  If it is used, then it is initialized by the caller
+ * of collect_filter_prefix to a zero-dimensional function.
+ */
+struct isl_schedule_node_get_filter_prefix_data {
+	int initialized;
+	int universe_domain;
+	int universe_filter;
+	int collect_prefix;
+	isl_union_set *filter;
+	isl_multi_union_pw_aff *prefix;
+};
+
+static int collect_filter_prefix(__isl_keep isl_schedule_tree_list *list,
+	int n, struct isl_schedule_node_get_filter_prefix_data *data);
+
+/* Update the filter and prefix information in "data" based on the first "n"
+ * elements in "list" and the expansion tree root "tree".
+ *
+ * We first collect the information from the elements in "list",
+ * initializing the filter based on the domain of the expansion.
+ * Then we map the results to the expanded space and combined them
+ * with the results already in "data".
+ */
+static int collect_filter_prefix_expansion(__isl_take isl_schedule_tree *tree,
+	__isl_keep isl_schedule_tree_list *list, int n,
+	struct isl_schedule_node_get_filter_prefix_data *data)
+{
+	struct isl_schedule_node_get_filter_prefix_data contracted;
+	isl_union_pw_multi_aff *c;
+	isl_union_map *exp, *universe;
+	isl_union_set *filter;
+
+	c = isl_schedule_tree_expansion_get_contraction(tree);
+	exp = isl_schedule_tree_expansion_get_expansion(tree);
+
+	contracted.initialized = 1;
+	contracted.universe_domain = data->universe_domain;
+	contracted.universe_filter = data->universe_filter;
+	contracted.collect_prefix = data->collect_prefix;
+	universe = isl_union_map_universe(isl_union_map_copy(exp));
+	filter = isl_union_map_domain(universe);
+	if (data->collect_prefix) {
+		isl_space *space = isl_union_set_get_space(filter);
+		space = isl_space_set_from_params(space);
+		contracted.prefix = isl_multi_union_pw_aff_zero(space);
+	}
+	contracted.filter = filter;
+
+	if (collect_filter_prefix(list, n, &contracted) < 0)
+		contracted.filter = isl_union_set_free(contracted.filter);
+	if (data->collect_prefix) {
+		isl_multi_union_pw_aff *prefix;
+
+		prefix = contracted.prefix;
+		prefix =
+		    isl_multi_union_pw_aff_pullback_union_pw_multi_aff(prefix,
+						isl_union_pw_multi_aff_copy(c));
+		data->prefix = isl_multi_union_pw_aff_flat_range_product(
+						prefix, data->prefix);
+	}
+	filter = contracted.filter;
+	if (data->universe_domain)
+		filter = isl_union_set_preimage_union_pw_multi_aff(filter,
+						isl_union_pw_multi_aff_copy(c));
+	else
+		filter = isl_union_set_apply(filter, isl_union_map_copy(exp));
+	if (!data->initialized)
+		data->filter = filter;
+	else
+		data->filter = isl_union_set_intersect(filter, data->filter);
+	data->initialized = 1;
+
+	isl_union_pw_multi_aff_free(c);
+	isl_union_map_free(exp);
+	isl_schedule_tree_free(tree);
+
+	return 0;
+}
+
+/* Update the filter information in "data" based on the first "n"
+ * elements in "list" and the extension tree root "tree", in case
+ * data->universe_domain is set and data->collect_prefix is not.
+ *
+ * We collect the universe domain of the elements in "list" and
+ * add it to the universe range of the extension (intersected
+ * with the already collected filter, if any).
+ */
+static int collect_universe_domain_extension(__isl_take isl_schedule_tree *tree,
+	__isl_keep isl_schedule_tree_list *list, int n,
+	struct isl_schedule_node_get_filter_prefix_data *data)
+{
+	struct isl_schedule_node_get_filter_prefix_data data_outer;
+	isl_union_map *extension;
+	isl_union_set *filter;
+
+	data_outer.initialized = 0;
+	data_outer.universe_domain = 1;
+	data_outer.universe_filter = data->universe_filter;
+	data_outer.collect_prefix = 0;
+	data_outer.filter = NULL;
+	data_outer.prefix = NULL;
+
+	if (collect_filter_prefix(list, n, &data_outer) < 0)
+		data_outer.filter = isl_union_set_free(data_outer.filter);
+
+	extension = isl_schedule_tree_extension_get_extension(tree);
+	extension = isl_union_map_universe(extension);
+	filter = isl_union_map_range(extension);
+	if (data_outer.initialized)
+		filter = isl_union_set_union(filter, data_outer.filter);
+	if (data->initialized)
+		filter = isl_union_set_intersect(filter, data->filter);
+
+	data->filter = filter;
+
+	isl_schedule_tree_free(tree);
+
+	return 0;
+}
+
+/* Update "data" based on the tree node "tree" in case "data" has
+ * not been initialized yet.
+ *
+ * Return 0 on success and -1 on error.
+ *
+ * If "tree" is a filter, then we set data->filter to this filter
+ * (or its universe).
+ * If "tree" is a domain, then this means we have reached the root
+ * of the schedule tree without being able to extract any information.
+ * We therefore initialize data->filter to the universe of the domain,
+ * or the domain itself if data->universe_domain is not set.
+ * If "tree" is a band with at least one member, then we set data->filter
+ * to the universe of the schedule domain and replace the zero-dimensional
+ * data->prefix by the band schedule (if data->collect_prefix is set).
+ */
+static int collect_filter_prefix_init(__isl_keep isl_schedule_tree *tree,
+	struct isl_schedule_node_get_filter_prefix_data *data)
+{
+	enum isl_schedule_node_type type;
+	isl_multi_union_pw_aff *mupa;
+	isl_union_set *filter;
+
+	type = isl_schedule_tree_get_type(tree);
+	switch (type) {
+	case isl_schedule_node_error:
+		return -1;
+	case isl_schedule_node_expansion:
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"should be handled by caller", return -1);
+	case isl_schedule_node_extension:
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"cannot handle extension nodes", return -1);
+	case isl_schedule_node_context:
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_guard:
+	case isl_schedule_node_mark:
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		return 0;
+	case isl_schedule_node_domain:
+		filter = isl_schedule_tree_domain_get_domain(tree);
+		if (data->universe_domain)
+			filter = isl_union_set_universe(filter);
+		data->filter = filter;
+		break;
+	case isl_schedule_node_band:
+		if (isl_schedule_tree_band_n_member(tree) == 0)
+			return 0;
+		mupa = isl_schedule_tree_band_get_partial_schedule(tree);
+		if (data->collect_prefix) {
+			isl_multi_union_pw_aff_free(data->prefix);
+			mupa = isl_multi_union_pw_aff_reset_tuple_id(mupa,
+								isl_dim_set);
+			data->prefix = isl_multi_union_pw_aff_copy(mupa);
+		}
+		filter = isl_multi_union_pw_aff_domain(mupa);
+		filter = isl_union_set_universe(filter);
+		data->filter = filter;
+		break;
+	case isl_schedule_node_filter:
+		filter = isl_schedule_tree_filter_get_filter(tree);
+		if (data->universe_filter)
+			filter = isl_union_set_universe(filter);
+		data->filter = filter;
+		break;
+	}
+
+	if ((data->collect_prefix && !data->prefix) || !data->filter)
+		return -1;
+
+	data->initialized = 1;
+
+	return 0;
+}
+
+/* Update "data" based on the tree node "tree" in case "data" has
+ * already been initialized.
+ *
+ * Return 0 on success and -1 on error.
+ *
+ * If "tree" is a domain and data->universe_domain is not set, then
+ * intersect data->filter with the domain.
+ * If "tree" is a filter, then we intersect data->filter with this filter
+ * (or its universe).
+ * If "tree" is a band with at least one member and data->collect_prefix
+ * is set, then we extend data->prefix with the band schedule.
+ * If "tree" is an extension, then we make sure that we are not collecting
+ * information on any extended domain elements.
+ */
+static int collect_filter_prefix_update(__isl_keep isl_schedule_tree *tree,
+	struct isl_schedule_node_get_filter_prefix_data *data)
+{
+	enum isl_schedule_node_type type;
+	isl_multi_union_pw_aff *mupa;
+	isl_union_set *filter;
+	isl_union_map *extension;
+	int empty;
+
+	type = isl_schedule_tree_get_type(tree);
+	switch (type) {
+	case isl_schedule_node_error:
+		return -1;
+	case isl_schedule_node_expansion:
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"should be handled by caller", return -1);
+	case isl_schedule_node_extension:
+		extension = isl_schedule_tree_extension_get_extension(tree);
+		extension = isl_union_map_intersect_range(extension,
+					isl_union_set_copy(data->filter));
+		empty = isl_union_map_is_empty(extension);
+		isl_union_map_free(extension);
+		if (empty < 0)
+			return -1;
+		if (empty)
+			break;
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"cannot handle extension nodes", return -1);
+	case isl_schedule_node_context:
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_guard:
+	case isl_schedule_node_mark:
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		break;
+	case isl_schedule_node_domain:
+		if (data->universe_domain)
+			break;
+		filter = isl_schedule_tree_domain_get_domain(tree);
+		data->filter = isl_union_set_intersect(data->filter, filter);
+		break;
+	case isl_schedule_node_band:
+		if (isl_schedule_tree_band_n_member(tree) == 0)
+			break;
+		if (!data->collect_prefix)
+			break;
+		mupa = isl_schedule_tree_band_get_partial_schedule(tree);
+		data->prefix = isl_multi_union_pw_aff_flat_range_product(mupa,
+								data->prefix);
+		if (!data->prefix)
+			return -1;
+		break;
+	case isl_schedule_node_filter:
+		filter = isl_schedule_tree_filter_get_filter(tree);
+		if (data->universe_filter)
+			filter = isl_union_set_universe(filter);
+		data->filter = isl_union_set_intersect(data->filter, filter);
+		if (!data->filter)
+			return -1;
+		break;
+	}
+
+	return 0;
+}
+
+/* Collect filter and/or prefix information from the first "n"
+ * elements in "list" (which represent the ancestors of a node).
+ * Store the results in "data".
+ *
+ * Extension nodes are only supported if they do not affect the outcome,
+ * i.e., if we are collecting information on non-extended domain elements,
+ * or if we are collecting the universe domain (without prefix).
+ *
+ * Return 0 on success and -1 on error.
+ *
+ * We traverse the list from innermost ancestor (last element)
+ * to outermost ancestor (first element), calling collect_filter_prefix_init
+ * on each node as long as we have not been able to extract any information
+ * yet and collect_filter_prefix_update afterwards.
+ * If we come across an expansion node, then we interrupt the traversal
+ * and call collect_filter_prefix_expansion to restart the traversal
+ * over the remaining ancestors and to combine the results with those
+ * that have already been collected.
+ * If we come across an extension node and we are only computing
+ * the universe domain, then we interrupt the traversal and call
+ * collect_universe_domain_extension to restart the traversal
+ * over the remaining ancestors and to combine the results with those
+ * that have already been collected.
+ * On successful return, data->initialized will be set since the outermost
+ * ancestor is a domain node, which always results in an initialization.
+ */
+static int collect_filter_prefix(__isl_keep isl_schedule_tree_list *list,
+	int n, struct isl_schedule_node_get_filter_prefix_data *data)
+{
+	int i;
+
+	if (!list)
+		return -1;
+
+	for (i = n - 1; i >= 0; --i) {
+		isl_schedule_tree *tree;
+		enum isl_schedule_node_type type;
+		int r;
+
+		tree = isl_schedule_tree_list_get_schedule_tree(list, i);
+		if (!tree)
+			return -1;
+		type = isl_schedule_tree_get_type(tree);
+		if (type == isl_schedule_node_expansion)
+			return collect_filter_prefix_expansion(tree, list, i,
+								data);
+		if (type == isl_schedule_node_extension &&
+		    data->universe_domain && !data->collect_prefix)
+			return collect_universe_domain_extension(tree, list, i,
+								data);
+		if (!data->initialized)
+			r = collect_filter_prefix_init(tree, data);
+		else
+			r = collect_filter_prefix_update(tree, data);
+		isl_schedule_tree_free(tree);
+		if (r < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Return the concatenation of the partial schedules of all outer band
+ * nodes of "node" interesected with all outer filters
+ * as an isl_multi_union_pw_aff.
+ * None of the ancestors of "node" may be an extension node, unless
+ * there is also a filter ancestor that filters out all the extended
+ * domain elements.
+ *
+ * If "node" is pointing at the root of the schedule tree, then
+ * there are no domain elements reaching the current node, so
+ * we return an empty result.
+ *
+ * We collect all the filters and partial schedules in collect_filter_prefix
+ * and intersect the domain of the combined schedule with the combined filter.
+ */
+__isl_give isl_multi_union_pw_aff *
+isl_schedule_node_get_prefix_schedule_multi_union_pw_aff(
+	__isl_keep isl_schedule_node *node)
+{
+	int n;
+	isl_space *space;
+	struct isl_schedule_node_get_filter_prefix_data data;
+
+	if (!node)
+		return NULL;
+
+	space = isl_schedule_get_space(node->schedule);
+	space = isl_space_set_from_params(space);
+	if (node->tree == node->schedule->root)
+		return isl_multi_union_pw_aff_zero(space);
+
+	data.initialized = 0;
+	data.universe_domain = 1;
+	data.universe_filter = 0;
+	data.collect_prefix = 1;
+	data.filter = NULL;
+	data.prefix = isl_multi_union_pw_aff_zero(space);
+
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	if (collect_filter_prefix(node->ancestors, n, &data) < 0)
+		data.prefix = isl_multi_union_pw_aff_free(data.prefix);
+
+	data.prefix = isl_multi_union_pw_aff_intersect_domain(data.prefix,
+								data.filter);
+
+	return data.prefix;
+}
+
+/* Return the concatenation of the partial schedules of all outer band
+ * nodes of "node" interesected with all outer filters
+ * as an isl_union_pw_multi_aff.
+ * None of the ancestors of "node" may be an extension node, unless
+ * there is also a filter ancestor that filters out all the extended
+ * domain elements.
+ *
+ * If "node" is pointing at the root of the schedule tree, then
+ * there are no domain elements reaching the current node, so
+ * we return an empty result.
+ *
+ * We collect all the filters and partial schedules in collect_filter_prefix.
+ * The partial schedules are collected as an isl_multi_union_pw_aff.
+ * If this isl_multi_union_pw_aff is zero-dimensional, then it does not
+ * contain any domain information, so we construct the isl_union_pw_multi_aff
+ * result as a zero-dimensional function on the collected filter.
+ * Otherwise, we convert the isl_multi_union_pw_aff to
+ * an isl_multi_union_pw_aff and intersect the domain with the filter.
+ */
+__isl_give isl_union_pw_multi_aff *
+isl_schedule_node_get_prefix_schedule_union_pw_multi_aff(
+	__isl_keep isl_schedule_node *node)
+{
+	int n;
+	isl_space *space;
+	isl_union_pw_multi_aff *prefix;
+	struct isl_schedule_node_get_filter_prefix_data data;
+
+	if (!node)
+		return NULL;
+
+	space = isl_schedule_get_space(node->schedule);
+	if (node->tree == node->schedule->root)
+		return isl_union_pw_multi_aff_empty(space);
+
+	space = isl_space_set_from_params(space);
+	data.initialized = 0;
+	data.universe_domain = 1;
+	data.universe_filter = 0;
+	data.collect_prefix = 1;
+	data.filter = NULL;
+	data.prefix = isl_multi_union_pw_aff_zero(space);
+
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	if (collect_filter_prefix(node->ancestors, n, &data) < 0)
+		data.prefix = isl_multi_union_pw_aff_free(data.prefix);
+
+	if (data.prefix &&
+	    isl_multi_union_pw_aff_dim(data.prefix, isl_dim_set) == 0) {
+		isl_multi_union_pw_aff_free(data.prefix);
+		prefix = isl_union_pw_multi_aff_from_domain(data.filter);
+	} else {
+		prefix =
+		    isl_union_pw_multi_aff_from_multi_union_pw_aff(data.prefix);
+		prefix = isl_union_pw_multi_aff_intersect_domain(prefix,
+								data.filter);
+	}
+
+	return prefix;
+}
+
+/* Return the concatenation of the partial schedules of all outer band
+ * nodes of "node" interesected with all outer filters
+ * as an isl_union_map.
+ */
+__isl_give isl_union_map *isl_schedule_node_get_prefix_schedule_union_map(
+	__isl_keep isl_schedule_node *node)
+{
+	isl_union_pw_multi_aff *upma;
+
+	upma = isl_schedule_node_get_prefix_schedule_union_pw_multi_aff(node);
+	return isl_union_map_from_union_pw_multi_aff(upma);
+}
+
+/* Return the concatenation of the partial schedules of all outer band
+ * nodes of "node" intersected with all outer domain constraints.
+ * None of the ancestors of "node" may be an extension node, unless
+ * there is also a filter ancestor that filters out all the extended
+ * domain elements.
+ *
+ * Essentially, this function intersects the domain of the output
+ * of isl_schedule_node_get_prefix_schedule_union_map with the output
+ * of isl_schedule_node_get_domain, except that it only traverses
+ * the ancestors of "node" once.
+ */
+__isl_give isl_union_map *isl_schedule_node_get_prefix_schedule_relation(
+	__isl_keep isl_schedule_node *node)
+{
+	int n;
+	isl_space *space;
+	isl_union_map *prefix;
+	struct isl_schedule_node_get_filter_prefix_data data;
+
+	if (!node)
+		return NULL;
+
+	space = isl_schedule_get_space(node->schedule);
+	if (node->tree == node->schedule->root)
+		return isl_union_map_empty(space);
+
+	space = isl_space_set_from_params(space);
+	data.initialized = 0;
+	data.universe_domain = 0;
+	data.universe_filter = 0;
+	data.collect_prefix = 1;
+	data.filter = NULL;
+	data.prefix = isl_multi_union_pw_aff_zero(space);
+
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	if (collect_filter_prefix(node->ancestors, n, &data) < 0)
+		data.prefix = isl_multi_union_pw_aff_free(data.prefix);
+
+	if (data.prefix &&
+	    isl_multi_union_pw_aff_dim(data.prefix, isl_dim_set) == 0) {
+		isl_multi_union_pw_aff_free(data.prefix);
+		prefix = isl_union_map_from_domain(data.filter);
+	} else {
+		prefix = isl_union_map_from_multi_union_pw_aff(data.prefix);
+		prefix = isl_union_map_intersect_domain(prefix, data.filter);
+	}
+
+	return prefix;
+}
+
+/* Return the domain elements that reach "node".
+ *
+ * If "node" is pointing at the root of the schedule tree, then
+ * there are no domain elements reaching the current node, so
+ * we return an empty result.
+ * None of the ancestors of "node" may be an extension node, unless
+ * there is also a filter ancestor that filters out all the extended
+ * domain elements.
+ *
+ * Otherwise, we collect all filters reaching the node,
+ * intersected with the root domain in collect_filter_prefix.
+ */
+__isl_give isl_union_set *isl_schedule_node_get_domain(
+	__isl_keep isl_schedule_node *node)
+{
+	int n;
+	struct isl_schedule_node_get_filter_prefix_data data;
+
+	if (!node)
+		return NULL;
+
+	if (node->tree == node->schedule->root) {
+		isl_space *space;
+
+		space = isl_schedule_get_space(node->schedule);
+		return isl_union_set_empty(space);
+	}
+
+	data.initialized = 0;
+	data.universe_domain = 0;
+	data.universe_filter = 0;
+	data.collect_prefix = 0;
+	data.filter = NULL;
+	data.prefix = NULL;
+
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	if (collect_filter_prefix(node->ancestors, n, &data) < 0)
+		data.filter = isl_union_set_free(data.filter);
+
+	return data.filter;
+}
+
+/* Return the union of universe sets of the domain elements that reach "node".
+ *
+ * If "node" is pointing at the root of the schedule tree, then
+ * there are no domain elements reaching the current node, so
+ * we return an empty result.
+ *
+ * Otherwise, we collect the universes of all filters reaching the node
+ * in collect_filter_prefix.
+ */
+__isl_give isl_union_set *isl_schedule_node_get_universe_domain(
+	__isl_keep isl_schedule_node *node)
+{
+	int n;
+	struct isl_schedule_node_get_filter_prefix_data data;
+
+	if (!node)
+		return NULL;
+
+	if (node->tree == node->schedule->root) {
+		isl_space *space;
+
+		space = isl_schedule_get_space(node->schedule);
+		return isl_union_set_empty(space);
+	}
+
+	data.initialized = 0;
+	data.universe_domain = 1;
+	data.universe_filter = 1;
+	data.collect_prefix = 0;
+	data.filter = NULL;
+	data.prefix = NULL;
+
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	if (collect_filter_prefix(node->ancestors, n, &data) < 0)
+		data.filter = isl_union_set_free(data.filter);
+
+	return data.filter;
+}
+
+/* Return the subtree schedule of "node".
+ *
+ * Since isl_schedule_tree_get_subtree_schedule_union_map does not handle
+ * trees that do not contain any schedule information, we first
+ * move down to the first relevant descendant and handle leaves ourselves.
+ *
+ * If the subtree rooted at "node" contains any expansion nodes, then
+ * the returned subtree schedule is formulated in terms of the expanded
+ * domains.
+ * The subtree is not allowed to contain any extension nodes.
+ */
+__isl_give isl_union_map *isl_schedule_node_get_subtree_schedule_union_map(
+	__isl_keep isl_schedule_node *node)
+{
+	isl_schedule_tree *tree, *leaf;
+	isl_union_map *umap;
+
+	tree = isl_schedule_node_get_tree(node);
+	leaf = isl_schedule_node_peek_leaf(node);
+	tree = isl_schedule_tree_first_schedule_descendant(tree, leaf);
+	if (!tree)
+		return NULL;
+	if (tree == leaf) {
+		isl_union_set *domain;
+		domain = isl_schedule_node_get_universe_domain(node);
+		isl_schedule_tree_free(tree);
+		return isl_union_map_from_domain(domain);
+	}
+
+	umap = isl_schedule_tree_get_subtree_schedule_union_map(tree);
+	isl_schedule_tree_free(tree);
+	return umap;
+}
+
+/* Return the number of ancestors of "node" in its schedule tree.
+ */
+int isl_schedule_node_get_tree_depth(__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return -1;
+	return isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+}
+
+/* Does "node" have a parent?
+ *
+ * That is, does it point to any node of the schedule other than the root?
+ */
+isl_bool isl_schedule_node_has_parent(__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return isl_bool_error;
+	if (!node->ancestors)
+		return isl_bool_error;
+
+	return isl_schedule_tree_list_n_schedule_tree(node->ancestors) != 0;
+}
+
+/* Return the position of "node" among the children of its parent.
+ */
+int isl_schedule_node_get_child_position(__isl_keep isl_schedule_node *node)
+{
+	int n;
+	int has_parent;
+
+	if (!node)
+		return -1;
+	has_parent = isl_schedule_node_has_parent(node);
+	if (has_parent < 0)
+		return -1;
+	if (!has_parent)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"node has no parent", return -1);
+
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	return node->child_pos[n - 1];
+}
+
+/* Does the parent (if any) of "node" have any children with a smaller child
+ * position than this one?
+ */
+isl_bool isl_schedule_node_has_previous_sibling(
+	__isl_keep isl_schedule_node *node)
+{
+	int n;
+	isl_bool has_parent;
+
+	if (!node)
+		return isl_bool_error;
+	has_parent = isl_schedule_node_has_parent(node);
+	if (has_parent < 0 || !has_parent)
+		return has_parent;
+
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+
+	return node->child_pos[n - 1] > 0;
+}
+
+/* Does the parent (if any) of "node" have any children with a greater child
+ * position than this one?
+ */
+isl_bool isl_schedule_node_has_next_sibling(__isl_keep isl_schedule_node *node)
+{
+	int n, n_child;
+	isl_bool has_parent;
+	isl_schedule_tree *tree;
+
+	if (!node)
+		return isl_bool_error;
+	has_parent = isl_schedule_node_has_parent(node);
+	if (has_parent < 0 || !has_parent)
+		return has_parent;
+
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors, n - 1);
+	if (!tree)
+		return isl_bool_error;
+	n_child = isl_schedule_tree_list_n_schedule_tree(tree->children);
+	isl_schedule_tree_free(tree);
+
+	return node->child_pos[n - 1] + 1 < n_child;
+}
+
+/* Does "node" have any children?
+ *
+ * Any node other than the leaf nodes is considered to have at least
+ * one child, even if the corresponding isl_schedule_tree does not
+ * have any children.
+ */
+isl_bool isl_schedule_node_has_children(__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return isl_bool_error;
+	return !isl_schedule_tree_is_leaf(node->tree);
+}
+
+/* Return the number of children of "node"?
+ *
+ * Any node other than the leaf nodes is considered to have at least
+ * one child, even if the corresponding isl_schedule_tree does not
+ * have any children.  That is, the number of children of "node" is
+ * only zero if its tree is the explicit empty tree.  Otherwise,
+ * if the isl_schedule_tree has any children, then it is equal
+ * to the number of children of "node".  If it has zero children,
+ * then "node" still has a leaf node as child.
+ */
+int isl_schedule_node_n_children(__isl_keep isl_schedule_node *node)
+{
+	int n;
+
+	if (!node)
+		return -1;
+
+	if (isl_schedule_tree_is_leaf(node->tree))
+		return 0;
+
+	n = isl_schedule_tree_n_children(node->tree);
+	if (n == 0)
+		return 1;
+
+	return n;
+}
+
+/* Move the "node" pointer to the ancestor of the given generation
+ * of the node it currently points to, where generation 0 is the node
+ * itself and generation 1 is its parent.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_ancestor(
+	__isl_take isl_schedule_node *node, int generation)
+{
+	int n;
+	isl_schedule_tree *tree;
+
+	if (!node)
+		return NULL;
+	if (generation == 0)
+		return node;
+	n = isl_schedule_node_get_tree_depth(node);
+	if (n < 0)
+		return isl_schedule_node_free(node);
+	if (generation < 0 || generation > n)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"generation out of bounds",
+			return isl_schedule_node_free(node));
+	node = isl_schedule_node_cow(node);
+	if (!node)
+		return NULL;
+
+	tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors,
+							n - generation);
+	isl_schedule_tree_free(node->tree);
+	node->tree = tree;
+	node->ancestors = isl_schedule_tree_list_drop(node->ancestors,
+						    n - generation, generation);
+	if (!node->ancestors || !node->tree)
+		return isl_schedule_node_free(node);
+
+	return node;
+}
+
+/* Move the "node" pointer to the parent of the node it currently points to.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_parent(
+	__isl_take isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+	if (!isl_schedule_node_has_parent(node))
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"node has no parent",
+			return isl_schedule_node_free(node));
+	return isl_schedule_node_ancestor(node, 1);
+}
+
+/* Move the "node" pointer to the root of its schedule tree.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_root(
+	__isl_take isl_schedule_node *node)
+{
+	int n;
+
+	if (!node)
+		return NULL;
+	n = isl_schedule_node_get_tree_depth(node);
+	if (n < 0)
+		return isl_schedule_node_free(node);
+	return isl_schedule_node_ancestor(node, n);
+}
+
+/* Move the "node" pointer to the child at position "pos" of the node
+ * it currently points to.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_child(
+	__isl_take isl_schedule_node *node, int pos)
+{
+	int n;
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+	int *child_pos;
+
+	node = isl_schedule_node_cow(node);
+	if (!node)
+		return NULL;
+	if (!isl_schedule_node_has_children(node))
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"node has no children",
+			return isl_schedule_node_free(node));
+
+	ctx = isl_schedule_node_get_ctx(node);
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	child_pos = isl_realloc_array(ctx, node->child_pos, int, n + 1);
+	if (!child_pos)
+		return isl_schedule_node_free(node);
+	node->child_pos = child_pos;
+	node->child_pos[n] = pos;
+
+	node->ancestors = isl_schedule_tree_list_add(node->ancestors,
+				isl_schedule_tree_copy(node->tree));
+	tree = node->tree;
+	if (isl_schedule_tree_has_children(tree))
+		tree = isl_schedule_tree_get_child(tree, pos);
+	else
+		tree = isl_schedule_node_get_leaf(node);
+	isl_schedule_tree_free(node->tree);
+	node->tree = tree;
+
+	if (!node->tree || !node->ancestors)
+		return isl_schedule_node_free(node);
+
+	return node;
+}
+
+/* Move the "node" pointer to the first child of the node
+ * it currently points to.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_first_child(
+	__isl_take isl_schedule_node *node)
+{
+	return isl_schedule_node_child(node, 0);
+}
+
+/* Move the "node" pointer to the child of this node's parent in
+ * the previous child position.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_previous_sibling(
+	__isl_take isl_schedule_node *node)
+{
+	int n;
+	isl_schedule_tree *parent, *tree;
+
+	node = isl_schedule_node_cow(node);
+	if (!node)
+		return NULL;
+	if (!isl_schedule_node_has_previous_sibling(node))
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"node has no previous sibling",
+			return isl_schedule_node_free(node));
+
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	parent = isl_schedule_tree_list_get_schedule_tree(node->ancestors,
+									n - 1);
+	if (!parent)
+		return isl_schedule_node_free(node);
+	node->child_pos[n - 1]--;
+	tree = isl_schedule_tree_list_get_schedule_tree(parent->children,
+							node->child_pos[n - 1]);
+	isl_schedule_tree_free(parent);
+	if (!tree)
+		return isl_schedule_node_free(node);
+	isl_schedule_tree_free(node->tree);
+	node->tree = tree;
+
+	return node;
+}
+
+/* Move the "node" pointer to the child of this node's parent in
+ * the next child position.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_next_sibling(
+	__isl_take isl_schedule_node *node)
+{
+	int n;
+	isl_schedule_tree *parent, *tree;
+
+	node = isl_schedule_node_cow(node);
+	if (!node)
+		return NULL;
+	if (!isl_schedule_node_has_next_sibling(node))
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"node has no next sibling",
+			return isl_schedule_node_free(node));
+
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	parent = isl_schedule_tree_list_get_schedule_tree(node->ancestors,
+									n - 1);
+	if (!parent)
+		return isl_schedule_node_free(node);
+	node->child_pos[n - 1]++;
+	tree = isl_schedule_tree_list_get_schedule_tree(parent->children,
+							node->child_pos[n - 1]);
+	isl_schedule_tree_free(parent);
+	if (!tree)
+		return isl_schedule_node_free(node);
+	isl_schedule_tree_free(node->tree);
+	node->tree = tree;
+
+	return node;
+}
+
+/* Return a copy to the child at position "pos" of "node".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_get_child(
+	__isl_keep isl_schedule_node *node, int pos)
+{
+	return isl_schedule_node_child(isl_schedule_node_copy(node), pos);
+}
+
+/* Traverse the descendant of "node" in depth-first order, including
+ * "node" itself.  Call "enter" whenever a node is entered and "leave"
+ * whenever a node is left.  The callback "enter" is responsible
+ * for moving to the deepest initial subtree of its argument that
+ * should be traversed.
+ */
+static __isl_give isl_schedule_node *traverse(
+	__isl_take isl_schedule_node *node,
+	__isl_give isl_schedule_node *(*enter)(
+		__isl_take isl_schedule_node *node, void *user),
+	__isl_give isl_schedule_node *(*leave)(
+		__isl_take isl_schedule_node *node, void *user),
+	void *user)
+{
+	int depth;
+
+	if (!node)
+		return NULL;
+
+	depth = isl_schedule_node_get_tree_depth(node);
+	do {
+		node = enter(node, user);
+		node = leave(node, user);
+		while (node && isl_schedule_node_get_tree_depth(node) > depth &&
+				!isl_schedule_node_has_next_sibling(node)) {
+			node = isl_schedule_node_parent(node);
+			node = leave(node, user);
+		}
+		if (node && isl_schedule_node_get_tree_depth(node) > depth)
+			node = isl_schedule_node_next_sibling(node);
+	} while (node && isl_schedule_node_get_tree_depth(node) > depth);
+
+	return node;
+}
+
+/* Internal data structure for isl_schedule_node_foreach_descendant_top_down.
+ *
+ * "fn" is the user-specified callback function.
+ * "user" is the user-specified argument for the callback.
+ */
+struct isl_schedule_node_preorder_data {
+	isl_bool (*fn)(__isl_keep isl_schedule_node *node, void *user);
+	void *user;
+};
+
+/* Callback for "traverse" to enter a node and to move
+ * to the deepest initial subtree that should be traversed
+ * for use in a preorder visit.
+ *
+ * If the user callback returns a negative value, then we abort
+ * the traversal.  If this callback returns zero, then we skip
+ * the subtree rooted at the current node.  Otherwise, we move
+ * down to the first child and repeat the process until a leaf
+ * is reached.
+ */
+static __isl_give isl_schedule_node *preorder_enter(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	struct isl_schedule_node_preorder_data *data = user;
+
+	if (!node)
+		return NULL;
+
+	do {
+		isl_bool r;
+
+		r = data->fn(node, data->user);
+		if (r < 0)
+			return isl_schedule_node_free(node);
+		if (r == isl_bool_false)
+			return node;
+	} while (isl_schedule_node_has_children(node) &&
+		(node = isl_schedule_node_first_child(node)) != NULL);
+
+	return node;
+}
+
+/* Callback for "traverse" to leave a node
+ * for use in a preorder visit.
+ * Since we already visited the node when we entered it,
+ * we do not need to do anything here.
+ */
+static __isl_give isl_schedule_node *preorder_leave(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	return node;
+}
+
+/* Traverse the descendants of "node" (including the node itself)
+ * in depth first preorder.
+ *
+ * If "fn" returns -1 on any of the nodes, then the traversal is aborted.
+ * If "fn" returns 0 on any of the nodes, then the subtree rooted
+ * at that node is skipped.
+ *
+ * Return 0 on success and -1 on failure.
+ */
+isl_stat isl_schedule_node_foreach_descendant_top_down(
+	__isl_keep isl_schedule_node *node,
+	isl_bool (*fn)(__isl_keep isl_schedule_node *node, void *user),
+	void *user)
+{
+	struct isl_schedule_node_preorder_data data = { fn, user };
+
+	node = isl_schedule_node_copy(node);
+	node = traverse(node, &preorder_enter, &preorder_leave, &data);
+	isl_schedule_node_free(node);
+
+	return node ? isl_stat_ok : isl_stat_error;
+}
+
+/* Internal data structure for isl_schedule_node_map_descendant_bottom_up.
+ *
+ * "fn" is the user-specified callback function.
+ * "user" is the user-specified argument for the callback.
+ */
+struct isl_schedule_node_postorder_data {
+	__isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node,
+		void *user);
+	void *user;
+};
+
+/* Callback for "traverse" to enter a node and to move
+ * to the deepest initial subtree that should be traversed
+ * for use in a postorder visit.
+ *
+ * Since we are performing a postorder visit, we only need
+ * to move to the deepest initial leaf here.
+ */
+static __isl_give isl_schedule_node *postorder_enter(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	while (node && isl_schedule_node_has_children(node))
+		node = isl_schedule_node_first_child(node);
+
+	return node;
+}
+
+/* Callback for "traverse" to leave a node
+ * for use in a postorder visit.
+ *
+ * Since we are performing a postorder visit, we need
+ * to call the user callback here.
+ */
+static __isl_give isl_schedule_node *postorder_leave(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	struct isl_schedule_node_postorder_data *data = user;
+
+	return data->fn(node, data->user);
+}
+
+/* Traverse the descendants of "node" (including the node itself)
+ * in depth first postorder, allowing the user to modify the visited node.
+ * The traversal continues from the node returned by the callback function.
+ * It is the responsibility of the user to ensure that this does not
+ * lead to an infinite loop.  It is safest to always return a pointer
+ * to the same position (same ancestors and child positions) as the input node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_map_descendant_bottom_up(
+	__isl_take isl_schedule_node *node,
+	__isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node,
+		void *user), void *user)
+{
+	struct isl_schedule_node_postorder_data data = { fn, user };
+
+	return traverse(node, &postorder_enter, &postorder_leave, &data);
+}
+
+/* Traverse the ancestors of "node" from the root down to and including
+ * the parent of "node", calling "fn" on each of them.
+ *
+ * If "fn" returns -1 on any of the nodes, then the traversal is aborted.
+ *
+ * Return 0 on success and -1 on failure.
+ */
+isl_stat isl_schedule_node_foreach_ancestor_top_down(
+	__isl_keep isl_schedule_node *node,
+	isl_stat (*fn)(__isl_keep isl_schedule_node *node, void *user),
+	void *user)
+{
+	int i, n;
+
+	if (!node)
+		return isl_stat_error;
+
+	n = isl_schedule_node_get_tree_depth(node);
+	for (i = 0; i < n; ++i) {
+		isl_schedule_node *ancestor;
+		isl_stat r;
+
+		ancestor = isl_schedule_node_copy(node);
+		ancestor = isl_schedule_node_ancestor(ancestor, n - i);
+		r = fn(ancestor, user);
+		isl_schedule_node_free(ancestor);
+		if (r < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Is any node in the subtree rooted at "node" anchored?
+ * That is, do any of these nodes reference the outer band nodes?
+ */
+isl_bool isl_schedule_node_is_subtree_anchored(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return isl_bool_error;
+	return isl_schedule_tree_is_subtree_anchored(node->tree);
+}
+
+/* Return the number of members in the given band node.
+ */
+unsigned isl_schedule_node_band_n_member(__isl_keep isl_schedule_node *node)
+{
+	return node ? isl_schedule_tree_band_n_member(node->tree) : 0;
+}
+
+/* Is the band member at position "pos" of the band node "node"
+ * marked coincident?
+ */
+isl_bool isl_schedule_node_band_member_get_coincident(
+	__isl_keep isl_schedule_node *node, int pos)
+{
+	if (!node)
+		return isl_bool_error;
+	return isl_schedule_tree_band_member_get_coincident(node->tree, pos);
+}
+
+/* Mark the band member at position "pos" the band node "node"
+ * as being coincident or not according to "coincident".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_member_set_coincident(
+	__isl_take isl_schedule_node *node, int pos, int coincident)
+{
+	int c;
+	isl_schedule_tree *tree;
+
+	if (!node)
+		return NULL;
+	c = isl_schedule_node_band_member_get_coincident(node, pos);
+	if (c == coincident)
+		return node;
+
+	tree = isl_schedule_tree_copy(node->tree);
+	tree = isl_schedule_tree_band_member_set_coincident(tree, pos,
+							    coincident);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+}
+
+/* Is the band node "node" marked permutable?
+ */
+isl_bool isl_schedule_node_band_get_permutable(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return isl_bool_error;
+
+	return isl_schedule_tree_band_get_permutable(node->tree);
+}
+
+/* Mark the band node "node" permutable or not according to "permutable"?
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_set_permutable(
+	__isl_take isl_schedule_node *node, int permutable)
+{
+	isl_schedule_tree *tree;
+
+	if (!node)
+		return NULL;
+	if (isl_schedule_node_band_get_permutable(node) == permutable)
+		return node;
+
+	tree = isl_schedule_tree_copy(node->tree);
+	tree = isl_schedule_tree_band_set_permutable(tree, permutable);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+}
+
+/* Return the schedule space of the band node.
+ */
+__isl_give isl_space *isl_schedule_node_band_get_space(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_tree_band_get_space(node->tree);
+}
+
+/* Return the schedule of the band node in isolation.
+ */
+__isl_give isl_multi_union_pw_aff *isl_schedule_node_band_get_partial_schedule(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_tree_band_get_partial_schedule(node->tree);
+}
+
+/* Return the schedule of the band node in isolation in the form of
+ * an isl_union_map.
+ *
+ * If the band does not have any members, then we construct a universe map
+ * with the universe of the domain elements reaching the node as domain.
+ * Otherwise, we extract an isl_multi_union_pw_aff representation and
+ * convert that to an isl_union_map.
+ */
+__isl_give isl_union_map *isl_schedule_node_band_get_partial_schedule_union_map(
+	__isl_keep isl_schedule_node *node)
+{
+	isl_multi_union_pw_aff *mupa;
+
+	if (!node)
+		return NULL;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_band)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"not a band node", return NULL);
+	if (isl_schedule_node_band_n_member(node) == 0) {
+		isl_union_set *domain;
+
+		domain = isl_schedule_node_get_universe_domain(node);
+		return isl_union_map_from_domain(domain);
+	}
+
+	mupa = isl_schedule_node_band_get_partial_schedule(node);
+	return isl_union_map_from_multi_union_pw_aff(mupa);
+}
+
+/* Return the loop AST generation type for the band member of band node "node"
+ * at position "pos".
+ */
+enum isl_ast_loop_type isl_schedule_node_band_member_get_ast_loop_type(
+	__isl_keep isl_schedule_node *node, int pos)
+{
+	if (!node)
+		return isl_ast_loop_error;
+
+	return isl_schedule_tree_band_member_get_ast_loop_type(node->tree, pos);
+}
+
+/* Set the loop AST generation type for the band member of band node "node"
+ * at position "pos" to "type".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_member_set_ast_loop_type(
+	__isl_take isl_schedule_node *node, int pos,
+	enum isl_ast_loop_type type)
+{
+	isl_schedule_tree *tree;
+
+	if (!node)
+		return NULL;
+
+	tree = isl_schedule_tree_copy(node->tree);
+	tree = isl_schedule_tree_band_member_set_ast_loop_type(tree, pos, type);
+	return isl_schedule_node_graft_tree(node, tree);
+}
+
+/* Return the loop AST generation type for the band member of band node "node"
+ * at position "pos" for the isolated part.
+ */
+enum isl_ast_loop_type isl_schedule_node_band_member_get_isolate_ast_loop_type(
+	__isl_keep isl_schedule_node *node, int pos)
+{
+	if (!node)
+		return isl_ast_loop_error;
+
+	return isl_schedule_tree_band_member_get_isolate_ast_loop_type(
+							    node->tree, pos);
+}
+
+/* Set the loop AST generation type for the band member of band node "node"
+ * at position "pos" for the isolated part to "type".
+ */
+__isl_give isl_schedule_node *
+isl_schedule_node_band_member_set_isolate_ast_loop_type(
+	__isl_take isl_schedule_node *node, int pos,
+	enum isl_ast_loop_type type)
+{
+	isl_schedule_tree *tree;
+
+	if (!node)
+		return NULL;
+
+	tree = isl_schedule_tree_copy(node->tree);
+	tree = isl_schedule_tree_band_member_set_isolate_ast_loop_type(tree,
+								    pos, type);
+	return isl_schedule_node_graft_tree(node, tree);
+}
+
+/* Return the AST build options associated to band node "node".
+ */
+__isl_give isl_union_set *isl_schedule_node_band_get_ast_build_options(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_tree_band_get_ast_build_options(node->tree);
+}
+
+/* Replace the AST build options associated to band node "node" by "options".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_set_ast_build_options(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *options)
+{
+	isl_schedule_tree *tree;
+
+	if (!node || !options)
+		goto error;
+
+	tree = isl_schedule_tree_copy(node->tree);
+	tree = isl_schedule_tree_band_set_ast_build_options(tree, options);
+	return isl_schedule_node_graft_tree(node, tree);
+error:
+	isl_schedule_node_free(node);
+	isl_union_set_free(options);
+	return NULL;
+}
+
+/* Return the "isolate" option associated to band node "node".
+ */
+__isl_give isl_set *isl_schedule_node_band_get_ast_isolate_option(
+	__isl_keep isl_schedule_node *node)
+{
+	int depth;
+
+	if (!node)
+		return NULL;
+
+	depth = isl_schedule_node_get_schedule_depth(node);
+	return isl_schedule_tree_band_get_ast_isolate_option(node->tree, depth);
+}
+
+/* Make sure that that spaces of "node" and "mv" are the same.
+ * Return -1 on error, reporting the error to the user.
+ */
+static int check_space_multi_val(__isl_keep isl_schedule_node *node,
+	__isl_keep isl_multi_val *mv)
+{
+	isl_space *node_space, *mv_space;
+	int equal;
+
+	node_space = isl_schedule_node_band_get_space(node);
+	mv_space = isl_multi_val_get_space(mv);
+	equal = isl_space_tuple_is_equal(node_space, isl_dim_set,
+					mv_space, isl_dim_set);
+	isl_space_free(mv_space);
+	isl_space_free(node_space);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"spaces don't match", return -1);
+
+	return 0;
+}
+
+/* Multiply the partial schedule of the band node "node"
+ * with the factors in "mv".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_scale(
+	__isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv)
+{
+	isl_schedule_tree *tree;
+	int anchored;
+
+	if (!node || !mv)
+		goto error;
+	if (check_space_multi_val(node, mv) < 0)
+		goto error;
+	anchored = isl_schedule_node_is_subtree_anchored(node);
+	if (anchored < 0)
+		goto error;
+	if (anchored)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot scale band node with anchored subtree",
+			goto error);
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_band_scale(tree, mv);
+	return isl_schedule_node_graft_tree(node, tree);
+error:
+	isl_multi_val_free(mv);
+	isl_schedule_node_free(node);
+	return NULL;
+}
+
+/* Divide the partial schedule of the band node "node"
+ * by the factors in "mv".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_scale_down(
+	__isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv)
+{
+	isl_schedule_tree *tree;
+	int anchored;
+
+	if (!node || !mv)
+		goto error;
+	if (check_space_multi_val(node, mv) < 0)
+		goto error;
+	anchored = isl_schedule_node_is_subtree_anchored(node);
+	if (anchored < 0)
+		goto error;
+	if (anchored)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot scale down band node with anchored subtree",
+			goto error);
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_band_scale_down(tree, mv);
+	return isl_schedule_node_graft_tree(node, tree);
+error:
+	isl_multi_val_free(mv);
+	isl_schedule_node_free(node);
+	return NULL;
+}
+
+/* Reduce the partial schedule of the band node "node"
+ * modulo the factors in "mv".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_mod(
+	__isl_take isl_schedule_node *node, __isl_take isl_multi_val *mv)
+{
+	isl_schedule_tree *tree;
+	isl_bool anchored;
+
+	if (!node || !mv)
+		goto error;
+	if (check_space_multi_val(node, mv) < 0)
+		goto error;
+	anchored = isl_schedule_node_is_subtree_anchored(node);
+	if (anchored < 0)
+		goto error;
+	if (anchored)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot perform mod on band node with anchored subtree",
+			goto error);
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_band_mod(tree, mv);
+	return isl_schedule_node_graft_tree(node, tree);
+error:
+	isl_multi_val_free(mv);
+	isl_schedule_node_free(node);
+	return NULL;
+}
+
+/* Make sure that that spaces of "node" and "mupa" are the same.
+ * Return isl_stat_error on error, reporting the error to the user.
+ */
+static isl_stat check_space_multi_union_pw_aff(
+	__isl_keep isl_schedule_node *node,
+	__isl_keep isl_multi_union_pw_aff *mupa)
+{
+	isl_space *node_space, *mupa_space;
+	isl_bool equal;
+
+	node_space = isl_schedule_node_band_get_space(node);
+	mupa_space = isl_multi_union_pw_aff_get_space(mupa);
+	equal = isl_space_tuple_is_equal(node_space, isl_dim_set,
+					mupa_space, isl_dim_set);
+	isl_space_free(mupa_space);
+	isl_space_free(node_space);
+	if (equal < 0)
+		return isl_stat_error;
+	if (!equal)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"spaces don't match", return isl_stat_error);
+
+	return isl_stat_ok;
+}
+
+/* Shift the partial schedule of the band node "node" by "shift".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_shift(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_multi_union_pw_aff *shift)
+{
+	isl_schedule_tree *tree;
+	int anchored;
+
+	if (!node || !shift)
+		goto error;
+	if (check_space_multi_union_pw_aff(node, shift) < 0)
+		goto error;
+	anchored = isl_schedule_node_is_subtree_anchored(node);
+	if (anchored < 0)
+		goto error;
+	if (anchored)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot shift band node with anchored subtree",
+			goto error);
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_band_shift(tree, shift);
+	return isl_schedule_node_graft_tree(node, tree);
+error:
+	isl_multi_union_pw_aff_free(shift);
+	isl_schedule_node_free(node);
+	return NULL;
+}
+
+/* Tile "node" with tile sizes "sizes".
+ *
+ * The current node is replaced by two nested nodes corresponding
+ * to the tile dimensions and the point dimensions.
+ *
+ * Return a pointer to the outer (tile) node.
+ *
+ * If any of the descendants of "node" depend on the set of outer band nodes,
+ * then we refuse to tile the node.
+ *
+ * If the scale tile loops option is set, then the tile loops
+ * are scaled by the tile sizes.  If the shift point loops option is set,
+ * then the point loops are shifted to start at zero.
+ * In particular, these options affect the tile and point loop schedules
+ * as follows
+ *
+ *	scale	shift	original	tile		point
+ *
+ *	0	0	i		floor(i/s)	i
+ *	1	0	i		s * floor(i/s)	i
+ *	0	1	i		floor(i/s)	i - s * floor(i/s)
+ *	1	1	i		s * floor(i/s)	i - s * floor(i/s)
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_tile(
+	__isl_take isl_schedule_node *node, __isl_take isl_multi_val *sizes)
+{
+	isl_schedule_tree *tree;
+	int anchored;
+
+	if (!node || !sizes)
+		goto error;
+	anchored = isl_schedule_node_is_subtree_anchored(node);
+	if (anchored < 0)
+		goto error;
+	if (anchored)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot tile band node with anchored subtree",
+			goto error);
+
+	if (check_space_multi_val(node, sizes) < 0)
+		goto error;
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_band_tile(tree, sizes);
+	return isl_schedule_node_graft_tree(node, tree);
+error:
+	isl_multi_val_free(sizes);
+	isl_schedule_node_free(node);
+	return NULL;
+}
+
+/* Move the band node "node" down to all the leaves in the subtree
+ * rooted at "node".
+ * Return a pointer to the node in the resulting tree that is in the same
+ * position as the node pointed to by "node" in the original tree.
+ *
+ * If the node only has a leaf child, then nothing needs to be done.
+ * Otherwise, the child of the node is removed and the result is
+ * appended to all the leaves in the subtree rooted at the original child.
+ * Since the node is moved to the leaves, it needs to be expanded
+ * according to the expansion, if any, defined by that subtree.
+ * In the end, the original node is replaced by the result of
+ * attaching copies of the expanded node to the leaves.
+ *
+ * If any of the nodes in the subtree rooted at "node" depend on
+ * the set of outer band nodes then we refuse to sink the band node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_sink(
+	__isl_take isl_schedule_node *node)
+{
+	enum isl_schedule_node_type type;
+	isl_schedule_tree *tree, *child;
+	isl_union_pw_multi_aff *contraction;
+	int anchored;
+
+	if (!node)
+		return NULL;
+
+	type = isl_schedule_node_get_type(node);
+	if (type != isl_schedule_node_band)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"not a band node", return isl_schedule_node_free(node));
+	anchored = isl_schedule_node_is_subtree_anchored(node);
+	if (anchored < 0)
+		return isl_schedule_node_free(node);
+	if (anchored)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot sink band node in anchored subtree",
+			return isl_schedule_node_free(node));
+	if (isl_schedule_tree_n_children(node->tree) == 0)
+		return node;
+
+	contraction = isl_schedule_node_get_subtree_contraction(node);
+
+	tree = isl_schedule_node_get_tree(node);
+	child = isl_schedule_tree_get_child(tree, 0);
+	tree = isl_schedule_tree_reset_children(tree);
+	tree = isl_schedule_tree_pullback_union_pw_multi_aff(tree, contraction);
+	tree = isl_schedule_tree_append_to_leaves(child, tree);
+
+	return isl_schedule_node_graft_tree(node, tree);
+}
+
+/* Split "node" into two nested band nodes, one with the first "pos"
+ * dimensions and one with the remaining dimensions.
+ * The schedules of the two band nodes live in anonymous spaces.
+ * The loop AST generation type options and the isolate option
+ * are split over the the two band nodes.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_split(
+	__isl_take isl_schedule_node *node, int pos)
+{
+	int depth;
+	isl_schedule_tree *tree;
+
+	depth = isl_schedule_node_get_schedule_depth(node);
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_band_split(tree, pos, depth);
+	return isl_schedule_node_graft_tree(node, tree);
+}
+
+/* Return the context of the context node "node".
+ */
+__isl_give isl_set *isl_schedule_node_context_get_context(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_tree_context_get_context(node->tree);
+}
+
+/* Return the domain of the domain node "node".
+ */
+__isl_give isl_union_set *isl_schedule_node_domain_get_domain(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_tree_domain_get_domain(node->tree);
+}
+
+/* Return the expansion map of expansion node "node".
+ */
+__isl_give isl_union_map *isl_schedule_node_expansion_get_expansion(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_tree_expansion_get_expansion(node->tree);
+}
+
+/* Return the contraction of expansion node "node".
+ */
+__isl_give isl_union_pw_multi_aff *isl_schedule_node_expansion_get_contraction(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_tree_expansion_get_contraction(node->tree);
+}
+
+/* Replace the contraction and the expansion of the expansion node "node"
+ * by "contraction" and "expansion".
+ */
+__isl_give isl_schedule_node *
+isl_schedule_node_expansion_set_contraction_and_expansion(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_union_map *expansion)
+{
+	isl_schedule_tree *tree;
+
+	if (!node || !contraction || !expansion)
+		goto error;
+
+	tree = isl_schedule_tree_copy(node->tree);
+	tree = isl_schedule_tree_expansion_set_contraction_and_expansion(tree,
+							contraction, expansion);
+	return isl_schedule_node_graft_tree(node, tree);
+error:
+	isl_schedule_node_free(node);
+	isl_union_pw_multi_aff_free(contraction);
+	isl_union_map_free(expansion);
+	return NULL;
+}
+
+/* Return the extension of the extension node "node".
+ */
+__isl_give isl_union_map *isl_schedule_node_extension_get_extension(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_tree_extension_get_extension(node->tree);
+}
+
+/* Replace the extension of extension node "node" by "extension".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_extension_set_extension(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_map *extension)
+{
+	isl_schedule_tree *tree;
+
+	if (!node || !extension)
+		goto error;
+
+	tree = isl_schedule_tree_copy(node->tree);
+	tree = isl_schedule_tree_extension_set_extension(tree, extension);
+	return isl_schedule_node_graft_tree(node, tree);
+error:
+	isl_schedule_node_free(node);
+	isl_union_map_free(extension);
+	return NULL;
+}
+
+/* Return the filter of the filter node "node".
+ */
+__isl_give isl_union_set *isl_schedule_node_filter_get_filter(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_tree_filter_get_filter(node->tree);
+}
+
+/* Replace the filter of filter node "node" by "filter".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_filter_set_filter(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *filter)
+{
+	isl_schedule_tree *tree;
+
+	if (!node || !filter)
+		goto error;
+
+	tree = isl_schedule_tree_copy(node->tree);
+	tree = isl_schedule_tree_filter_set_filter(tree, filter);
+	return isl_schedule_node_graft_tree(node, tree);
+error:
+	isl_schedule_node_free(node);
+	isl_union_set_free(filter);
+	return NULL;
+}
+
+/* Intersect the filter of filter node "node" with "filter".
+ *
+ * If the filter of the node is already a subset of "filter",
+ * then leave the node unchanged.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_filter_intersect_filter(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *filter)
+{
+	isl_union_set *node_filter = NULL;
+	isl_bool subset;
+
+	if (!node || !filter)
+		goto error;
+
+	node_filter = isl_schedule_node_filter_get_filter(node);
+	subset = isl_union_set_is_subset(node_filter, filter);
+	if (subset < 0)
+		goto error;
+	if (subset) {
+		isl_union_set_free(node_filter);
+		isl_union_set_free(filter);
+		return node;
+	}
+	node_filter = isl_union_set_intersect(node_filter, filter);
+	node = isl_schedule_node_filter_set_filter(node, node_filter);
+	return node;
+error:
+	isl_schedule_node_free(node);
+	isl_union_set_free(node_filter);
+	isl_union_set_free(filter);
+	return NULL;
+}
+
+/* Return the guard of the guard node "node".
+ */
+__isl_give isl_set *isl_schedule_node_guard_get_guard(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_tree_guard_get_guard(node->tree);
+}
+
+/* Return the mark identifier of the mark node "node".
+ */
+__isl_give isl_id *isl_schedule_node_mark_get_id(
+	__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return NULL;
+
+	return isl_schedule_tree_mark_get_id(node->tree);
+}
+
+/* Replace the child at position "pos" of the sequence node "node"
+ * by the children of sequence root node of "tree".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_sequence_splice(
+	__isl_take isl_schedule_node *node, int pos,
+	__isl_take isl_schedule_tree *tree)
+{
+	isl_schedule_tree *node_tree;
+
+	if (!node || !tree)
+		goto error;
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"not a sequence node", goto error);
+	if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"not a sequence node", goto error);
+	node_tree = isl_schedule_node_get_tree(node);
+	node_tree = isl_schedule_tree_sequence_splice(node_tree, pos, tree);
+	node = isl_schedule_node_graft_tree(node, node_tree);
+
+	return node;
+error:
+	isl_schedule_node_free(node);
+	isl_schedule_tree_free(tree);
+	return NULL;
+}
+
+/* Given a sequence node "node", with a child at position "pos" that
+ * is also a sequence node, attach the children of that node directly
+ * as children of "node" at that position, replacing the original child.
+ *
+ * The filters of these children are intersected with the filter
+ * of the child at position "pos".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_sequence_splice_child(
+	__isl_take isl_schedule_node *node, int pos)
+{
+	int i, n;
+	isl_union_set *filter;
+	isl_schedule_node *child;
+	isl_schedule_tree *tree;
+
+	if (!node)
+		return NULL;
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"not a sequence node",
+			return isl_schedule_node_free(node));
+	node = isl_schedule_node_child(node, pos);
+	node = isl_schedule_node_child(node, 0);
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"not a sequence node",
+			return isl_schedule_node_free(node));
+	child = isl_schedule_node_copy(node);
+	node = isl_schedule_node_parent(node);
+	filter = isl_schedule_node_filter_get_filter(node);
+	n = isl_schedule_node_n_children(child);
+	for (i = 0; i < n; ++i) {
+		child = isl_schedule_node_child(child, i);
+		child = isl_schedule_node_filter_intersect_filter(child,
+						isl_union_set_copy(filter));
+		child = isl_schedule_node_parent(child);
+	}
+	isl_union_set_free(filter);
+	tree = isl_schedule_node_get_tree(child);
+	isl_schedule_node_free(child);
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_sequence_splice(node, pos, tree);
+
+	return node;
+}
+
+/* Update the ancestors of "node" to point to the tree that "node"
+ * now points to.
+ * That is, replace the child in the original parent that corresponds
+ * to the current tree position by node->tree and continue updating
+ * the ancestors in the same way until the root is reached.
+ *
+ * If "fn" is not NULL, then it is called on each ancestor as we move up
+ * the tree so that it can modify the ancestor before it is added
+ * to the list of ancestors of the modified node.
+ * The additional "pos" argument records the position
+ * of the "tree" argument in the original schedule tree.
+ *
+ * If "node" originally points to a leaf of the schedule tree, then make sure
+ * that in the end it points to a leaf in the updated schedule tree.
+ */
+static __isl_give isl_schedule_node *update_ancestors(
+	__isl_take isl_schedule_node *node,
+	__isl_give isl_schedule_tree *(*fn)(__isl_take isl_schedule_tree *tree,
+		__isl_keep isl_schedule_node *pos, void *user), void *user)
+{
+	int i, n;
+	int is_leaf;
+	isl_schedule_tree *tree;
+	isl_schedule_node *pos = NULL;
+
+	if (fn)
+		pos = isl_schedule_node_copy(node);
+
+	node = isl_schedule_node_cow(node);
+	if (!node)
+		return isl_schedule_node_free(pos);
+
+	n = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	tree = isl_schedule_tree_copy(node->tree);
+
+	for (i = n - 1; i >= 0; --i) {
+		isl_schedule_tree *parent;
+
+		parent = isl_schedule_tree_list_get_schedule_tree(
+						    node->ancestors, i);
+		parent = isl_schedule_tree_replace_child(parent,
+						    node->child_pos[i], tree);
+		if (fn) {
+			pos = isl_schedule_node_parent(pos);
+			parent = fn(parent, pos, user);
+		}
+		node->ancestors = isl_schedule_tree_list_set_schedule_tree(
+			    node->ancestors, i, isl_schedule_tree_copy(parent));
+
+		tree = parent;
+	}
+
+	if (fn)
+		isl_schedule_node_free(pos);
+
+	is_leaf = isl_schedule_tree_is_leaf(node->tree);
+	node->schedule = isl_schedule_set_root(node->schedule, tree);
+	if (is_leaf) {
+		isl_schedule_tree_free(node->tree);
+		node->tree = isl_schedule_node_get_leaf(node);
+	}
+
+	if (!node->schedule || !node->ancestors)
+		return isl_schedule_node_free(node);
+
+	return node;
+}
+
+/* Replace the subtree that "pos" points to by "tree", updating
+ * the ancestors to maintain a consistent state.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_graft_tree(
+	__isl_take isl_schedule_node *pos, __isl_take isl_schedule_tree *tree)
+{
+	if (!tree || !pos)
+		goto error;
+	if (pos->tree == tree) {
+		isl_schedule_tree_free(tree);
+		return pos;
+	}
+
+	pos = isl_schedule_node_cow(pos);
+	if (!pos)
+		goto error;
+
+	isl_schedule_tree_free(pos->tree);
+	pos->tree = tree;
+
+	return update_ancestors(pos, NULL, NULL);
+error:
+	isl_schedule_node_free(pos);
+	isl_schedule_tree_free(tree);
+	return NULL;
+}
+
+/* Make sure we can insert a node between "node" and its parent.
+ * Return -1 on error, reporting the reason why we cannot insert a node.
+ */
+static int check_insert(__isl_keep isl_schedule_node *node)
+{
+	int has_parent;
+	enum isl_schedule_node_type type;
+
+	has_parent = isl_schedule_node_has_parent(node);
+	if (has_parent < 0)
+		return -1;
+	if (!has_parent)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot insert node outside of root", return -1);
+
+	type = isl_schedule_node_get_parent_type(node);
+	if (type == isl_schedule_node_error)
+		return -1;
+	if (type == isl_schedule_node_set || type == isl_schedule_node_sequence)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot insert node between set or sequence node "
+			"and its filter children", return -1);
+
+	return 0;
+}
+
+/* Insert a band node with partial schedule "mupa" between "node" and
+ * its parent.
+ * Return a pointer to the new band node.
+ *
+ * If any of the nodes in the subtree rooted at "node" depend on
+ * the set of outer band nodes then we refuse to insert the band node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_insert_partial_schedule(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_multi_union_pw_aff *mupa)
+{
+	int anchored;
+	isl_schedule_band *band;
+	isl_schedule_tree *tree;
+
+	if (check_insert(node) < 0)
+		node = isl_schedule_node_free(node);
+	anchored = isl_schedule_node_is_subtree_anchored(node);
+	if (anchored < 0)
+		goto error;
+	if (anchored)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot insert band node in anchored subtree",
+			goto error);
+
+	tree = isl_schedule_node_get_tree(node);
+	band = isl_schedule_band_from_multi_union_pw_aff(mupa);
+	tree = isl_schedule_tree_insert_band(tree, band);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+error:
+	isl_schedule_node_free(node);
+	isl_multi_union_pw_aff_free(mupa);
+	return NULL;
+}
+
+/* Insert a context node with context "context" between "node" and its parent.
+ * Return a pointer to the new context node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_insert_context(
+	__isl_take isl_schedule_node *node, __isl_take isl_set *context)
+{
+	isl_schedule_tree *tree;
+
+	if (check_insert(node) < 0)
+		node = isl_schedule_node_free(node);
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_insert_context(tree, context);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+}
+
+/* Insert an expansion node with the given "contraction" and "expansion"
+ * between "node" and its parent.
+ * Return a pointer to the new expansion node.
+ *
+ * Typically the domain and range spaces of the expansion are different.
+ * This means that only one of them can refer to the current domain space
+ * in a consistent tree.  It is up to the caller to ensure that the tree
+ * returns to a consistent state.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_insert_expansion(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_union_map *expansion)
+{
+	isl_schedule_tree *tree;
+
+	if (check_insert(node) < 0)
+		node = isl_schedule_node_free(node);
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_insert_expansion(tree, contraction, expansion);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+}
+
+/* Insert an extension node with extension "extension" between "node" and
+ * its parent.
+ * Return a pointer to the new extension node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_insert_extension(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *extension)
+{
+	isl_schedule_tree *tree;
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_insert_extension(tree, extension);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+}
+
+/* Insert a filter node with filter "filter" between "node" and its parent.
+ * Return a pointer to the new filter node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_insert_filter(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *filter)
+{
+	isl_schedule_tree *tree;
+
+	if (check_insert(node) < 0)
+		node = isl_schedule_node_free(node);
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_insert_filter(tree, filter);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+}
+
+/* Insert a guard node with guard "guard" between "node" and its parent.
+ * Return a pointer to the new guard node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_insert_guard(
+	__isl_take isl_schedule_node *node, __isl_take isl_set *guard)
+{
+	isl_schedule_tree *tree;
+
+	if (check_insert(node) < 0)
+		node = isl_schedule_node_free(node);
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_insert_guard(tree, guard);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+}
+
+/* Insert a mark node with mark identifier "mark" between "node" and
+ * its parent.
+ * Return a pointer to the new mark node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_insert_mark(
+	__isl_take isl_schedule_node *node, __isl_take isl_id *mark)
+{
+	isl_schedule_tree *tree;
+
+	if (check_insert(node) < 0)
+		node = isl_schedule_node_free(node);
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_insert_mark(tree, mark);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+}
+
+/* Attach the current subtree of "node" to a sequence of filter tree nodes
+ * with filters described by "filters", attach this sequence
+ * of filter tree nodes as children to a new tree of type "type" and
+ * replace the original subtree of "node" by this new tree.
+ * Each copy of the original subtree is simplified with respect
+ * to the corresponding filter.
+ */
+static __isl_give isl_schedule_node *isl_schedule_node_insert_children(
+	__isl_take isl_schedule_node *node,
+	enum isl_schedule_node_type type,
+	__isl_take isl_union_set_list *filters)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+	isl_schedule_tree_list *list;
+
+	if (check_insert(node) < 0)
+		node = isl_schedule_node_free(node);
+
+	if (!node || !filters)
+		goto error;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	n = isl_union_set_list_n_union_set(filters);
+	list = isl_schedule_tree_list_alloc(ctx, n);
+	for (i = 0; i < n; ++i) {
+		isl_schedule_node *node_i;
+		isl_schedule_tree *tree;
+		isl_union_set *filter;
+
+		filter = isl_union_set_list_get_union_set(filters, i);
+		node_i = isl_schedule_node_copy(node);
+		node_i = isl_schedule_node_gist(node_i,
+						isl_union_set_copy(filter));
+		tree = isl_schedule_node_get_tree(node_i);
+		isl_schedule_node_free(node_i);
+		tree = isl_schedule_tree_insert_filter(tree, filter);
+		list = isl_schedule_tree_list_add(list, tree);
+	}
+	tree = isl_schedule_tree_from_children(type, list);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	isl_union_set_list_free(filters);
+	return node;
+error:
+	isl_union_set_list_free(filters);
+	isl_schedule_node_free(node);
+	return NULL;
+}
+
+/* Insert a sequence node with child filters "filters" between "node" and
+ * its parent.  That is, the tree that "node" points to is attached
+ * to each of the child nodes of the filter nodes.
+ * Return a pointer to the new sequence node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_insert_sequence(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_set_list *filters)
+{
+	return isl_schedule_node_insert_children(node,
+					isl_schedule_node_sequence, filters);
+}
+
+/* Insert a set node with child filters "filters" between "node" and
+ * its parent.  That is, the tree that "node" points to is attached
+ * to each of the child nodes of the filter nodes.
+ * Return a pointer to the new set node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_insert_set(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_set_list *filters)
+{
+	return isl_schedule_node_insert_children(node,
+					isl_schedule_node_set, filters);
+}
+
+/* Remove "node" from its schedule tree and return a pointer
+ * to the leaf at the same position in the updated schedule tree.
+ *
+ * It is not allowed to remove the root of a schedule tree or
+ * a child of a set or sequence node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_cut(
+	__isl_take isl_schedule_node *node)
+{
+	isl_schedule_tree *leaf;
+	enum isl_schedule_node_type parent_type;
+
+	if (!node)
+		return NULL;
+	if (!isl_schedule_node_has_parent(node))
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot cut root", return isl_schedule_node_free(node));
+
+	parent_type = isl_schedule_node_get_parent_type(node);
+	if (parent_type == isl_schedule_node_set ||
+	    parent_type == isl_schedule_node_sequence)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot cut child of set or sequence",
+			return isl_schedule_node_free(node));
+
+	leaf = isl_schedule_node_get_leaf(node);
+	return isl_schedule_node_graft_tree(node, leaf);
+}
+
+/* Remove a single node from the schedule tree, attaching the child
+ * of "node" directly to its parent.
+ * Return a pointer to this former child or to the leaf the position
+ * of the original node if there was no child.
+ * It is not allowed to remove the root of a schedule tree,
+ * a set or sequence node, a child of a set or sequence node or
+ * a band node with an anchored subtree.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_delete(
+	__isl_take isl_schedule_node *node)
+{
+	int n;
+	isl_schedule_tree *tree;
+	enum isl_schedule_node_type type;
+
+	if (!node)
+		return NULL;
+
+	if (isl_schedule_node_get_tree_depth(node) == 0)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot delete root node",
+			return isl_schedule_node_free(node));
+	n = isl_schedule_node_n_children(node);
+	if (n != 1)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"can only delete node with a single child",
+			return isl_schedule_node_free(node));
+	type = isl_schedule_node_get_parent_type(node);
+	if (type == isl_schedule_node_sequence || type == isl_schedule_node_set)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"cannot delete child of set or sequence",
+			return isl_schedule_node_free(node));
+	if (isl_schedule_node_get_type(node) == isl_schedule_node_band) {
+		int anchored;
+
+		anchored = isl_schedule_node_is_subtree_anchored(node);
+		if (anchored < 0)
+			return isl_schedule_node_free(node);
+		if (anchored)
+			isl_die(isl_schedule_node_get_ctx(node),
+				isl_error_invalid,
+				"cannot delete band node with anchored subtree",
+				return isl_schedule_node_free(node));
+	}
+
+	tree = isl_schedule_node_get_tree(node);
+	if (!tree || isl_schedule_tree_has_children(tree)) {
+		tree = isl_schedule_tree_child(tree, 0);
+	} else {
+		isl_schedule_tree_free(tree);
+		tree = isl_schedule_node_get_leaf(node);
+	}
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+}
+
+/* Internal data structure for the group_ancestor callback.
+ *
+ * If "finished" is set, then we no longer need to modify
+ * any further ancestors.
+ *
+ * "contraction" and "expansion" represent the expansion
+ * that reflects the grouping.
+ *
+ * "domain" contains the domain elements that reach the position
+ * where the grouping is performed.  That is, it is the range
+ * of the resulting expansion.
+ * "domain_universe" is the universe of "domain".
+ * "group" is the set of group elements, i.e., the domain
+ * of the resulting expansion.
+ * "group_universe" is the universe of "group".
+ *
+ * "sched" is the schedule for the group elements, in pratice
+ * an identity mapping on "group_universe".
+ * "dim" is the dimension of "sched".
+ */
+struct isl_schedule_group_data {
+	int finished;
+
+	isl_union_map *expansion;
+	isl_union_pw_multi_aff *contraction;
+
+	isl_union_set *domain;
+	isl_union_set *domain_universe;
+	isl_union_set *group;
+	isl_union_set *group_universe;
+
+	int dim;
+	isl_multi_aff *sched;
+};
+
+/* Is domain covered by data->domain within data->domain_universe?
+ */
+static int locally_covered_by_domain(__isl_keep isl_union_set *domain,
+	struct isl_schedule_group_data *data)
+{
+	int is_subset;
+	isl_union_set *test;
+
+	test = isl_union_set_copy(domain);
+	test = isl_union_set_intersect(test,
+			    isl_union_set_copy(data->domain_universe));
+	is_subset = isl_union_set_is_subset(test, data->domain);
+	isl_union_set_free(test);
+
+	return is_subset;
+}
+
+/* Update the band tree root "tree" to refer to the group instances
+ * in data->group rather than the original domain elements in data->domain.
+ * "pos" is the position in the original schedule tree where the modified
+ * "tree" will be attached.
+ *
+ * Add the part of the identity schedule on the group instances data->sched
+ * that corresponds to this band node to the band schedule.
+ * If the domain elements that reach the node and that are part
+ * of data->domain_universe are all elements of data->domain (and therefore
+ * replaced by the group instances) then this data->domain_universe
+ * is removed from the domain of the band schedule.
+ */
+static __isl_give isl_schedule_tree *group_band(
+	__isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_node *pos,
+	struct isl_schedule_group_data *data)
+{
+	isl_union_set *domain;
+	isl_multi_aff *ma;
+	isl_multi_union_pw_aff *mupa, *partial;
+	int is_covered;
+	int depth, n, has_id;
+
+	domain = isl_schedule_node_get_domain(pos);
+	is_covered = locally_covered_by_domain(domain, data);
+	if (is_covered >= 0 && is_covered) {
+		domain = isl_union_set_universe(domain);
+		domain = isl_union_set_subtract(domain,
+			    isl_union_set_copy(data->domain_universe));
+		tree = isl_schedule_tree_band_intersect_domain(tree, domain);
+	} else
+		isl_union_set_free(domain);
+	if (is_covered < 0)
+		return isl_schedule_tree_free(tree);
+	depth = isl_schedule_node_get_schedule_depth(pos);
+	n = isl_schedule_tree_band_n_member(tree);
+	ma = isl_multi_aff_copy(data->sched);
+	ma = isl_multi_aff_drop_dims(ma, isl_dim_out, 0, depth);
+	ma = isl_multi_aff_drop_dims(ma, isl_dim_out, n, data->dim - depth - n);
+	mupa = isl_multi_union_pw_aff_from_multi_aff(ma);
+	partial = isl_schedule_tree_band_get_partial_schedule(tree);
+	has_id = isl_multi_union_pw_aff_has_tuple_id(partial, isl_dim_set);
+	if (has_id < 0) {
+		partial = isl_multi_union_pw_aff_free(partial);
+	} else if (has_id) {
+		isl_id *id;
+		id = isl_multi_union_pw_aff_get_tuple_id(partial, isl_dim_set);
+		mupa = isl_multi_union_pw_aff_set_tuple_id(mupa,
+							    isl_dim_set, id);
+	}
+	partial = isl_multi_union_pw_aff_union_add(partial, mupa);
+	tree = isl_schedule_tree_band_set_partial_schedule(tree, partial);
+
+	return tree;
+}
+
+/* Drop the parameters in "uset" that are not also in "space".
+ * "n" is the number of parameters in "space".
+ */
+static __isl_give isl_union_set *union_set_drop_extra_params(
+	__isl_take isl_union_set *uset, __isl_keep isl_space *space, int n)
+{
+	int n2;
+
+	uset = isl_union_set_align_params(uset, isl_space_copy(space));
+	n2 = isl_union_set_dim(uset, isl_dim_param);
+	uset = isl_union_set_project_out(uset, isl_dim_param, n, n2 - n);
+
+	return uset;
+}
+
+/* Update the context tree root "tree" to refer to the group instances
+ * in data->group rather than the original domain elements in data->domain.
+ * "pos" is the position in the original schedule tree where the modified
+ * "tree" will be attached.
+ *
+ * We do not actually need to update "tree" since a context node only
+ * refers to the schedule space.  However, we may need to update "data"
+ * to not refer to any parameters introduced by the context node.
+ */
+static __isl_give isl_schedule_tree *group_context(
+	__isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_node *pos,
+	struct isl_schedule_group_data *data)
+{
+	isl_space *space;
+	isl_union_set *domain;
+	int n1, n2;
+	int involves;
+
+	if (isl_schedule_node_get_tree_depth(pos) == 1)
+		return tree;
+
+	domain = isl_schedule_node_get_universe_domain(pos);
+	space = isl_union_set_get_space(domain);
+	isl_union_set_free(domain);
+
+	n1 = isl_space_dim(space, isl_dim_param);
+	data->expansion = isl_union_map_align_params(data->expansion, space);
+	n2 = isl_union_map_dim(data->expansion, isl_dim_param);
+
+	if (!data->expansion)
+		return isl_schedule_tree_free(tree);
+	if (n1 == n2)
+		return tree;
+
+	involves = isl_union_map_involves_dims(data->expansion,
+				isl_dim_param, n1, n2 - n1);
+	if (involves < 0)
+		return isl_schedule_tree_free(tree);
+	if (involves)
+		isl_die(isl_schedule_node_get_ctx(pos), isl_error_invalid,
+			"grouping cannot only refer to global parameters",
+			return isl_schedule_tree_free(tree));
+
+	data->expansion = isl_union_map_project_out(data->expansion,
+				isl_dim_param, n1, n2 - n1);
+	space = isl_union_map_get_space(data->expansion);
+
+	data->contraction = isl_union_pw_multi_aff_align_params(
+				data->contraction, isl_space_copy(space));
+	n2 = isl_union_pw_multi_aff_dim(data->contraction, isl_dim_param);
+	data->contraction = isl_union_pw_multi_aff_drop_dims(data->contraction,
+				isl_dim_param, n1, n2 - n1);
+
+	data->domain = union_set_drop_extra_params(data->domain, space, n1);
+	data->domain_universe =
+		union_set_drop_extra_params(data->domain_universe, space, n1);
+	data->group = union_set_drop_extra_params(data->group, space, n1);
+	data->group_universe =
+		union_set_drop_extra_params(data->group_universe, space, n1);
+
+	data->sched = isl_multi_aff_align_params(data->sched,
+				isl_space_copy(space));
+	n2 = isl_multi_aff_dim(data->sched, isl_dim_param);
+	data->sched = isl_multi_aff_drop_dims(data->sched,
+				isl_dim_param, n1, n2 - n1);
+
+	isl_space_free(space);
+
+	return tree;
+}
+
+/* Update the domain tree root "tree" to refer to the group instances
+ * in data->group rather than the original domain elements in data->domain.
+ * "pos" is the position in the original schedule tree where the modified
+ * "tree" will be attached.
+ *
+ * We first double-check that all grouped domain elements are actually
+ * part of the root domain and then replace those elements by the group
+ * instances.
+ */
+static __isl_give isl_schedule_tree *group_domain(
+	__isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_node *pos,
+	struct isl_schedule_group_data *data)
+{
+	isl_union_set *domain;
+	int is_subset;
+
+	domain = isl_schedule_tree_domain_get_domain(tree);
+	is_subset = isl_union_set_is_subset(data->domain, domain);
+	isl_union_set_free(domain);
+	if (is_subset < 0)
+		return isl_schedule_tree_free(tree);
+	if (!is_subset)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"grouped domain should be part of outer domain",
+			return isl_schedule_tree_free(tree));
+	domain = isl_schedule_tree_domain_get_domain(tree);
+	domain = isl_union_set_subtract(domain,
+				isl_union_set_copy(data->domain));
+	domain = isl_union_set_union(domain, isl_union_set_copy(data->group));
+	tree = isl_schedule_tree_domain_set_domain(tree, domain);
+
+	return tree;
+}
+
+/* Update the expansion tree root "tree" to refer to the group instances
+ * in data->group rather than the original domain elements in data->domain.
+ * "pos" is the position in the original schedule tree where the modified
+ * "tree" will be attached.
+ *
+ * Let G_1 -> D_1 be the expansion of "tree" and G_2 -> D_2 the newly
+ * introduced expansion in a descendant of "tree".
+ * We first double-check that D_2 is a subset of D_1.
+ * Then we remove D_2 from the range of G_1 -> D_1 and add the mapping
+ * G_1 -> D_1 . D_2 -> G_2.
+ * Simmilarly, we restrict the domain of the contraction to the universe
+ * of the range of the updated expansion and add G_2 -> D_2 . D_1 -> G_1,
+ * attempting to remove the domain constraints of this additional part.
+ */
+static __isl_give isl_schedule_tree *group_expansion(
+	__isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_node *pos,
+	struct isl_schedule_group_data *data)
+{
+	isl_union_set *domain;
+	isl_union_map *expansion, *umap;
+	isl_union_pw_multi_aff *contraction, *upma;
+	int is_subset;
+
+	expansion = isl_schedule_tree_expansion_get_expansion(tree);
+	domain = isl_union_map_range(expansion);
+	is_subset = isl_union_set_is_subset(data->domain, domain);
+	isl_union_set_free(domain);
+	if (is_subset < 0)
+		return isl_schedule_tree_free(tree);
+	if (!is_subset)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"grouped domain should be part "
+			"of outer expansion domain",
+			return isl_schedule_tree_free(tree));
+	expansion = isl_schedule_tree_expansion_get_expansion(tree);
+	umap = isl_union_map_from_union_pw_multi_aff(
+			isl_union_pw_multi_aff_copy(data->contraction));
+	umap = isl_union_map_apply_range(expansion, umap);
+	expansion = isl_schedule_tree_expansion_get_expansion(tree);
+	expansion = isl_union_map_subtract_range(expansion,
+				isl_union_set_copy(data->domain));
+	expansion = isl_union_map_union(expansion, umap);
+	umap = isl_union_map_universe(isl_union_map_copy(expansion));
+	domain = isl_union_map_range(umap);
+	contraction = isl_schedule_tree_expansion_get_contraction(tree);
+	umap = isl_union_map_from_union_pw_multi_aff(contraction);
+	umap = isl_union_map_apply_range(isl_union_map_copy(data->expansion),
+					umap);
+	upma = isl_union_pw_multi_aff_from_union_map(umap);
+	contraction = isl_schedule_tree_expansion_get_contraction(tree);
+	contraction = isl_union_pw_multi_aff_intersect_domain(contraction,
+								domain);
+	domain = isl_union_pw_multi_aff_domain(
+				isl_union_pw_multi_aff_copy(upma));
+	upma = isl_union_pw_multi_aff_gist(upma, domain);
+	contraction = isl_union_pw_multi_aff_union_add(contraction, upma);
+	tree = isl_schedule_tree_expansion_set_contraction_and_expansion(tree,
+							contraction, expansion);
+
+	return tree;
+}
+
+/* Update the tree root "tree" to refer to the group instances
+ * in data->group rather than the original domain elements in data->domain.
+ * "pos" is the position in the original schedule tree where the modified
+ * "tree" will be attached.
+ *
+ * If we have come across a domain or expansion node before (data->finished
+ * is set), then we no longer need perform any modifications.
+ *
+ * If "tree" is a filter, then we add data->group_universe to the filter.
+ * We also remove data->domain_universe from the filter if all the domain
+ * elements in this universe that reach the filter node are part of
+ * the elements that are being grouped by data->expansion.
+ * If "tree" is a band, domain or expansion, then it is handled
+ * in a separate function.
+ */
+static __isl_give isl_schedule_tree *group_ancestor(
+	__isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_node *pos,
+	void *user)
+{
+	struct isl_schedule_group_data *data = user;
+	isl_union_set *domain;
+	int is_covered;
+
+	if (!tree || !pos)
+		return isl_schedule_tree_free(tree);
+
+	if (data->finished)
+		return tree;
+
+	switch (isl_schedule_tree_get_type(tree)) {
+	case isl_schedule_node_error:
+		return isl_schedule_tree_free(tree);
+	case isl_schedule_node_extension:
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported,
+			"grouping not allowed in extended tree",
+			return isl_schedule_tree_free(tree));
+	case isl_schedule_node_band:
+		tree = group_band(tree, pos, data);
+		break;
+	case isl_schedule_node_context:
+		tree = group_context(tree, pos, data);
+		break;
+	case isl_schedule_node_domain:
+		tree = group_domain(tree, pos, data);
+		data->finished = 1;
+		break;
+	case isl_schedule_node_filter:
+		domain = isl_schedule_node_get_domain(pos);
+		is_covered = locally_covered_by_domain(domain, data);
+		isl_union_set_free(domain);
+		if (is_covered < 0)
+			return isl_schedule_tree_free(tree);
+		domain = isl_schedule_tree_filter_get_filter(tree);
+		if (is_covered)
+			domain = isl_union_set_subtract(domain,
+				    isl_union_set_copy(data->domain_universe));
+		domain = isl_union_set_union(domain,
+				    isl_union_set_copy(data->group_universe));
+		tree = isl_schedule_tree_filter_set_filter(tree, domain);
+		break;
+	case isl_schedule_node_expansion:
+		tree = group_expansion(tree, pos, data);
+		data->finished = 1;
+		break;
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_guard:
+	case isl_schedule_node_mark:
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		break;
+	}
+
+	return tree;
+}
+
+/* Group the domain elements that reach "node" into instances
+ * of a single statement with identifier "group_id".
+ * In particular, group the domain elements according to their
+ * prefix schedule.
+ *
+ * That is, introduce an expansion node with as contraction
+ * the prefix schedule (with the target space replaced by "group_id")
+ * and as expansion the inverse of this contraction (with its range
+ * intersected with the domain elements that reach "node").
+ * The outer nodes are then modified to refer to the group instances
+ * instead of the original domain elements.
+ *
+ * No instance of "group_id" is allowed to reach "node" prior
+ * to the grouping.
+ * No ancestor of "node" is allowed to be an extension node.
+ *
+ * Return a pointer to original node in tree, i.e., the child
+ * of the newly introduced expansion node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_group(
+	__isl_take isl_schedule_node *node, __isl_take isl_id *group_id)
+{
+	struct isl_schedule_group_data data = { 0 };
+	isl_space *space;
+	isl_union_set *domain;
+	isl_union_pw_multi_aff *contraction;
+	isl_union_map *expansion;
+	int disjoint;
+
+	if (!node || !group_id)
+		goto error;
+	if (check_insert(node) < 0)
+		goto error;
+
+	domain = isl_schedule_node_get_domain(node);
+	data.domain = isl_union_set_copy(domain);
+	data.domain_universe = isl_union_set_copy(domain);
+	data.domain_universe = isl_union_set_universe(data.domain_universe);
+
+	data.dim = isl_schedule_node_get_schedule_depth(node);
+	if (data.dim == 0) {
+		isl_ctx *ctx;
+		isl_set *set;
+		isl_union_set *group;
+		isl_union_map *univ;
+
+		ctx = isl_schedule_node_get_ctx(node);
+		space = isl_space_set_alloc(ctx, 0, 0);
+		space = isl_space_set_tuple_id(space, isl_dim_set, group_id);
+		set = isl_set_universe(isl_space_copy(space));
+		group = isl_union_set_from_set(set);
+		expansion = isl_union_map_from_domain_and_range(domain, group);
+		univ = isl_union_map_universe(isl_union_map_copy(expansion));
+		contraction = isl_union_pw_multi_aff_from_union_map(univ);
+		expansion = isl_union_map_reverse(expansion);
+	} else {
+		isl_multi_union_pw_aff *prefix;
+		isl_union_set *univ;
+
+		prefix =
+		isl_schedule_node_get_prefix_schedule_multi_union_pw_aff(node);
+		prefix = isl_multi_union_pw_aff_set_tuple_id(prefix,
+							isl_dim_set, group_id);
+		space = isl_multi_union_pw_aff_get_space(prefix);
+		contraction = isl_union_pw_multi_aff_from_multi_union_pw_aff(
+							prefix);
+		univ = isl_union_set_universe(isl_union_set_copy(domain));
+		contraction =
+		    isl_union_pw_multi_aff_intersect_domain(contraction, univ);
+		expansion = isl_union_map_from_union_pw_multi_aff(
+				    isl_union_pw_multi_aff_copy(contraction));
+		expansion = isl_union_map_reverse(expansion);
+		expansion = isl_union_map_intersect_range(expansion, domain);
+	}
+	space = isl_space_map_from_set(space);
+	data.sched = isl_multi_aff_identity(space);
+	data.group = isl_union_map_domain(isl_union_map_copy(expansion));
+	data.group = isl_union_set_coalesce(data.group);
+	data.group_universe = isl_union_set_copy(data.group);
+	data.group_universe = isl_union_set_universe(data.group_universe);
+	data.expansion = isl_union_map_copy(expansion);
+	data.contraction = isl_union_pw_multi_aff_copy(contraction);
+	node = isl_schedule_node_insert_expansion(node, contraction, expansion);
+
+	disjoint = isl_union_set_is_disjoint(data.domain_universe,
+					    data.group_universe);
+
+	node = update_ancestors(node, &group_ancestor, &data);
+
+	isl_union_set_free(data.domain);
+	isl_union_set_free(data.domain_universe);
+	isl_union_set_free(data.group);
+	isl_union_set_free(data.group_universe);
+	isl_multi_aff_free(data.sched);
+	isl_union_map_free(data.expansion);
+	isl_union_pw_multi_aff_free(data.contraction);
+
+	node = isl_schedule_node_child(node, 0);
+
+	if (!node || disjoint < 0)
+		return isl_schedule_node_free(node);
+	if (!disjoint)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"group instances already reach node",
+			return isl_schedule_node_free(node));
+
+	return node;
+error:
+	isl_schedule_node_free(node);
+	isl_id_free(group_id);
+	return NULL;
+}
+
+/* Compute the gist of the given band node with respect to "context".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_gist(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *context)
+{
+	isl_schedule_tree *tree;
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_band_gist(tree, context);
+	return isl_schedule_node_graft_tree(node, tree);
+}
+
+/* Internal data structure for isl_schedule_node_gist.
+ * "n_expansion" is the number of outer expansion nodes
+ * with respect to the current position
+ * "filters" contains an element for each outer filter, expansion or
+ * extension node with respect to the current position, each representing
+ * the intersection of the previous element and the filter on the filter node
+ * or the expansion/extension of the previous element.
+ * The first element in the original context passed to isl_schedule_node_gist.
+ */
+struct isl_node_gist_data {
+	int n_expansion;
+	isl_union_set_list *filters;
+};
+
+/* Enter the expansion node "node" during a isl_schedule_node_gist traversal.
+ *
+ * In particular, add an extra element to data->filters containing
+ * the expansion of the previous element and replace the expansion
+ * and contraction on "node" by the gist with respect to these filters.
+ * Also keep track of the fact that we have entered another expansion.
+ */
+static __isl_give isl_schedule_node *gist_enter_expansion(
+	__isl_take isl_schedule_node *node, struct isl_node_gist_data *data)
+{
+	int n;
+	isl_union_set *inner;
+	isl_union_map *expansion;
+	isl_union_pw_multi_aff *contraction;
+
+	data->n_expansion++;
+
+	n = isl_union_set_list_n_union_set(data->filters);
+	inner = isl_union_set_list_get_union_set(data->filters, n - 1);
+	expansion = isl_schedule_node_expansion_get_expansion(node);
+	inner = isl_union_set_apply(inner, expansion);
+
+	contraction = isl_schedule_node_expansion_get_contraction(node);
+	contraction = isl_union_pw_multi_aff_gist(contraction,
+						isl_union_set_copy(inner));
+
+	data->filters = isl_union_set_list_add(data->filters, inner);
+
+	inner = isl_union_set_list_get_union_set(data->filters, n - 1);
+	expansion = isl_schedule_node_expansion_get_expansion(node);
+	expansion = isl_union_map_gist_domain(expansion, inner);
+	node = isl_schedule_node_expansion_set_contraction_and_expansion(node,
+						contraction, expansion);
+
+	return node;
+}
+
+/* Leave the expansion node "node" during a isl_schedule_node_gist traversal.
+ *
+ * In particular, remove the element in data->filters that was added by
+ * gist_enter_expansion and decrement the number of outer expansions.
+ *
+ * The expansion has already been simplified in gist_enter_expansion.
+ * If this simplification results in an identity expansion, then
+ * it is removed here.
+ */
+static __isl_give isl_schedule_node *gist_leave_expansion(
+	__isl_take isl_schedule_node *node, struct isl_node_gist_data *data)
+{
+	int n;
+	isl_bool identity;
+	isl_union_map *expansion;
+
+	expansion = isl_schedule_node_expansion_get_expansion(node);
+	identity = isl_union_map_is_identity(expansion);
+	isl_union_map_free(expansion);
+
+	if (identity < 0)
+		node = isl_schedule_node_free(node);
+	else if (identity)
+		node = isl_schedule_node_delete(node);
+
+	n = isl_union_set_list_n_union_set(data->filters);
+	data->filters = isl_union_set_list_drop(data->filters, n - 1, 1);
+
+	data->n_expansion--;
+
+	return node;
+}
+
+/* Enter the extension node "node" during a isl_schedule_node_gist traversal.
+ *
+ * In particular, add an extra element to data->filters containing
+ * the union of the previous element with the additional domain elements
+ * introduced by the extension.
+ */
+static __isl_give isl_schedule_node *gist_enter_extension(
+	__isl_take isl_schedule_node *node, struct isl_node_gist_data *data)
+{
+	int n;
+	isl_union_set *inner, *extra;
+	isl_union_map *extension;
+
+	n = isl_union_set_list_n_union_set(data->filters);
+	inner = isl_union_set_list_get_union_set(data->filters, n - 1);
+	extension = isl_schedule_node_extension_get_extension(node);
+	extra = isl_union_map_range(extension);
+	inner = isl_union_set_union(inner, extra);
+
+	data->filters = isl_union_set_list_add(data->filters, inner);
+
+	return node;
+}
+
+/* Can we finish gisting at this node?
+ * That is, is the filter on the current filter node a subset of
+ * the original context passed to isl_schedule_node_gist?
+ * If we have gone through any expansions, then we cannot perform
+ * this test since the current domain elements are incomparable
+ * to the domain elements in the original context.
+ */
+static int gist_done(__isl_keep isl_schedule_node *node,
+	struct isl_node_gist_data *data)
+{
+	isl_union_set *filter, *outer;
+	int subset;
+
+	if (data->n_expansion != 0)
+		return 0;
+
+	filter = isl_schedule_node_filter_get_filter(node);
+	outer = isl_union_set_list_get_union_set(data->filters, 0);
+	subset = isl_union_set_is_subset(filter, outer);
+	isl_union_set_free(outer);
+	isl_union_set_free(filter);
+
+	return subset;
+}
+
+/* Callback for "traverse" to enter a node and to move
+ * to the deepest initial subtree that should be traversed
+ * by isl_schedule_node_gist.
+ *
+ * The "filters" list is extended by one element each time
+ * we come across a filter node by the result of intersecting
+ * the last element in the list with the filter on the filter node.
+ *
+ * If the filter on the current filter node is a subset of
+ * the original context passed to isl_schedule_node_gist,
+ * then there is no need to go into its subtree since it cannot
+ * be further simplified by the context.  The "filters" list is
+ * still extended for consistency, but the actual value of the
+ * added element is immaterial since it will not be used.
+ *
+ * Otherwise, the filter on the current filter node is replaced by
+ * the gist of the original filter with respect to the intersection
+ * of the original context with the intermediate filters.
+ *
+ * If the new element in the "filters" list is empty, then no elements
+ * can reach the descendants of the current filter node.  The subtree
+ * underneath the filter node is therefore removed.
+ *
+ * Each expansion node we come across is handled by
+ * gist_enter_expansion.
+ *
+ * Each extension node we come across is handled by
+ * gist_enter_extension.
+ */
+static __isl_give isl_schedule_node *gist_enter(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	struct isl_node_gist_data *data = user;
+
+	do {
+		isl_union_set *filter, *inner;
+		int done, empty;
+		int n;
+
+		switch (isl_schedule_node_get_type(node)) {
+		case isl_schedule_node_error:
+			return isl_schedule_node_free(node);
+		case isl_schedule_node_expansion:
+			node = gist_enter_expansion(node, data);
+			continue;
+		case isl_schedule_node_extension:
+			node = gist_enter_extension(node, data);
+			continue;
+		case isl_schedule_node_band:
+		case isl_schedule_node_context:
+		case isl_schedule_node_domain:
+		case isl_schedule_node_guard:
+		case isl_schedule_node_leaf:
+		case isl_schedule_node_mark:
+		case isl_schedule_node_sequence:
+		case isl_schedule_node_set:
+			continue;
+		case isl_schedule_node_filter:
+			break;
+		}
+		done = gist_done(node, data);
+		filter = isl_schedule_node_filter_get_filter(node);
+		if (done < 0 || done) {
+			data->filters = isl_union_set_list_add(data->filters,
+								filter);
+			if (done < 0)
+				return isl_schedule_node_free(node);
+			return node;
+		}
+		n = isl_union_set_list_n_union_set(data->filters);
+		inner = isl_union_set_list_get_union_set(data->filters, n - 1);
+		filter = isl_union_set_gist(filter, isl_union_set_copy(inner));
+		node = isl_schedule_node_filter_set_filter(node,
+						isl_union_set_copy(filter));
+		filter = isl_union_set_intersect(filter, inner);
+		empty = isl_union_set_is_empty(filter);
+		data->filters = isl_union_set_list_add(data->filters, filter);
+		if (empty < 0)
+			return isl_schedule_node_free(node);
+		if (!empty)
+			continue;
+		node = isl_schedule_node_child(node, 0);
+		node = isl_schedule_node_cut(node);
+		node = isl_schedule_node_parent(node);
+		return node;
+	} while (isl_schedule_node_has_children(node) &&
+		(node = isl_schedule_node_first_child(node)) != NULL);
+
+	return node;
+}
+
+/* Callback for "traverse" to leave a node for isl_schedule_node_gist.
+ *
+ * In particular, if the current node is a filter node, then we remove
+ * the element on the "filters" list that was added when we entered
+ * the node.  There is no need to compute any gist here, since we
+ * already did that when we entered the node.
+ *
+ * Expansion nodes are handled by gist_leave_expansion.
+ *
+ * If the current node is an extension, then remove the element
+ * in data->filters that was added by gist_enter_extension.
+ *
+ * If the current node is a band node, then we compute the gist of
+ * the band node with respect to the intersection of the original context
+ * and the intermediate filters.
+ *
+ * If the current node is a sequence or set node, then some of
+ * the filter children may have become empty and so they are removed.
+ * If only one child is left, then the set or sequence node along with
+ * the single remaining child filter is removed.  The filter can be
+ * removed because the filters on a sequence or set node are supposed
+ * to partition the incoming domain instances.
+ * In principle, it should then be impossible for there to be zero
+ * remaining children, but should this happen, we replace the entire
+ * subtree with an empty filter.
+ */
+static __isl_give isl_schedule_node *gist_leave(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	struct isl_node_gist_data *data = user;
+	isl_schedule_tree *tree;
+	int i, n;
+	isl_union_set *filter;
+
+	switch (isl_schedule_node_get_type(node)) {
+	case isl_schedule_node_error:
+		return isl_schedule_node_free(node);
+	case isl_schedule_node_expansion:
+		node = gist_leave_expansion(node, data);
+		break;
+	case isl_schedule_node_extension:
+	case isl_schedule_node_filter:
+		n = isl_union_set_list_n_union_set(data->filters);
+		data->filters = isl_union_set_list_drop(data->filters,
+							n - 1, 1);
+		break;
+	case isl_schedule_node_band:
+		n = isl_union_set_list_n_union_set(data->filters);
+		filter = isl_union_set_list_get_union_set(data->filters, n - 1);
+		node = isl_schedule_node_band_gist(node, filter);
+		break;
+	case isl_schedule_node_set:
+	case isl_schedule_node_sequence:
+		tree = isl_schedule_node_get_tree(node);
+		n = isl_schedule_tree_n_children(tree);
+		for (i = n - 1; i >= 0; --i) {
+			isl_schedule_tree *child;
+			isl_union_set *filter;
+			int empty;
+
+			child = isl_schedule_tree_get_child(tree, i);
+			filter = isl_schedule_tree_filter_get_filter(child);
+			empty = isl_union_set_is_empty(filter);
+			isl_union_set_free(filter);
+			isl_schedule_tree_free(child);
+			if (empty < 0)
+				tree = isl_schedule_tree_free(tree);
+			else if (empty)
+				tree = isl_schedule_tree_drop_child(tree, i);
+		}
+		n = isl_schedule_tree_n_children(tree);
+		node = isl_schedule_node_graft_tree(node, tree);
+		if (n == 1) {
+			node = isl_schedule_node_delete(node);
+			node = isl_schedule_node_delete(node);
+		} else if (n == 0) {
+			isl_space *space;
+
+			filter =
+			    isl_union_set_list_get_union_set(data->filters, 0);
+			space = isl_union_set_get_space(filter);
+			isl_union_set_free(filter);
+			filter = isl_union_set_empty(space);
+			node = isl_schedule_node_cut(node);
+			node = isl_schedule_node_insert_filter(node, filter);
+		}
+		break;
+	case isl_schedule_node_context:
+	case isl_schedule_node_domain:
+	case isl_schedule_node_guard:
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_mark:
+		break;
+	}
+
+	return node;
+}
+
+/* Compute the gist of the subtree at "node" with respect to
+ * the reaching domain elements in "context".
+ * In particular, compute the gist of all band and filter nodes
+ * in the subtree with respect to "context".  Children of set or sequence
+ * nodes that end up with an empty filter are removed completely.
+ *
+ * We keep track of the intersection of "context" with all outer filters
+ * of the current node within the subtree in the final element of "filters".
+ * Initially, this list contains the single element "context" and it is
+ * extended or shortened each time we enter or leave a filter node.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_gist(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *context)
+{
+	struct isl_node_gist_data data;
+
+	data.n_expansion = 0;
+	data.filters = isl_union_set_list_from_union_set(context);
+	node = traverse(node, &gist_enter, &gist_leave, &data);
+	isl_union_set_list_free(data.filters);
+	return node;
+}
+
+/* Intersect the domain of domain node "node" with "domain".
+ *
+ * If the domain of "node" is already a subset of "domain",
+ * then nothing needs to be changed.
+ *
+ * Otherwise, we replace the domain of the domain node by the intersection
+ * and simplify the subtree rooted at "node" with respect to this intersection.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_domain_intersect_domain(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *domain)
+{
+	isl_schedule_tree *tree;
+	isl_union_set *uset;
+	int is_subset;
+
+	if (!node || !domain)
+		goto error;
+
+	uset = isl_schedule_tree_domain_get_domain(node->tree);
+	is_subset = isl_union_set_is_subset(uset, domain);
+	isl_union_set_free(uset);
+	if (is_subset < 0)
+		goto error;
+	if (is_subset) {
+		isl_union_set_free(domain);
+		return node;
+	}
+
+	tree = isl_schedule_tree_copy(node->tree);
+	uset = isl_schedule_tree_domain_get_domain(tree);
+	uset = isl_union_set_intersect(uset, domain);
+	tree = isl_schedule_tree_domain_set_domain(tree,
+						    isl_union_set_copy(uset));
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	node = isl_schedule_node_child(node, 0);
+	node = isl_schedule_node_gist(node, uset);
+	node = isl_schedule_node_parent(node);
+
+	return node;
+error:
+	isl_schedule_node_free(node);
+	isl_union_set_free(domain);
+	return NULL;
+}
+
+/* Replace the domain of domain node "node" with the gist
+ * of the original domain with respect to the parameter domain "context".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_domain_gist_params(
+	__isl_take isl_schedule_node *node, __isl_take isl_set *context)
+{
+	isl_union_set *domain;
+	isl_schedule_tree *tree;
+
+	if (!node || !context)
+		goto error;
+
+	tree = isl_schedule_tree_copy(node->tree);
+	domain = isl_schedule_tree_domain_get_domain(node->tree);
+	domain = isl_union_set_gist_params(domain, context);
+	tree = isl_schedule_tree_domain_set_domain(tree, domain);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+error:
+	isl_schedule_node_free(node);
+	isl_set_free(context);
+	return NULL;
+}
+
+/* Internal data structure for isl_schedule_node_get_subtree_expansion.
+ * "expansions" contains a list of accumulated expansions
+ * for each outer expansion, set or sequence node.  The first element
+ * in the list is an identity mapping on the reaching domain elements.
+ * "res" collects the results.
+ */
+struct isl_subtree_expansion_data {
+	isl_union_map_list *expansions;
+	isl_union_map *res;
+};
+
+/* Callback for "traverse" to enter a node and to move
+ * to the deepest initial subtree that should be traversed
+ * by isl_schedule_node_get_subtree_expansion.
+ *
+ * Whenever we come across an expansion node, the last element
+ * of data->expansions is combined with the expansion
+ * on the expansion node.
+ *
+ * Whenever we come across a filter node that is the child
+ * of a set or sequence node, data->expansions is extended
+ * with a new element that restricts the previous element
+ * to the elements selected by the filter.
+ * The previous element can then be reused while backtracking.
+ */
+static __isl_give isl_schedule_node *subtree_expansion_enter(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	struct isl_subtree_expansion_data *data = user;
+
+	do {
+		enum isl_schedule_node_type type;
+		isl_union_set *filter;
+		isl_union_map *inner, *expansion;
+		int n;
+
+		switch (isl_schedule_node_get_type(node)) {
+		case isl_schedule_node_error:
+			return isl_schedule_node_free(node);
+		case isl_schedule_node_filter:
+			type = isl_schedule_node_get_parent_type(node);
+			if (type != isl_schedule_node_set &&
+			    type != isl_schedule_node_sequence)
+				break;
+			filter = isl_schedule_node_filter_get_filter(node);
+			n = isl_union_map_list_n_union_map(data->expansions);
+			inner =
+			    isl_union_map_list_get_union_map(data->expansions,
+								n - 1);
+			inner = isl_union_map_intersect_range(inner, filter);
+			data->expansions =
+			    isl_union_map_list_add(data->expansions, inner);
+			break;
+		case isl_schedule_node_expansion:
+			n = isl_union_map_list_n_union_map(data->expansions);
+			expansion =
+				isl_schedule_node_expansion_get_expansion(node);
+			inner =
+			    isl_union_map_list_get_union_map(data->expansions,
+								n - 1);
+			inner = isl_union_map_apply_range(inner, expansion);
+			data->expansions =
+			    isl_union_map_list_set_union_map(data->expansions,
+								n - 1, inner);
+			break;
+		case isl_schedule_node_band:
+		case isl_schedule_node_context:
+		case isl_schedule_node_domain:
+		case isl_schedule_node_extension:
+		case isl_schedule_node_guard:
+		case isl_schedule_node_leaf:
+		case isl_schedule_node_mark:
+		case isl_schedule_node_sequence:
+		case isl_schedule_node_set:
+			break;
+		}
+	} while (isl_schedule_node_has_children(node) &&
+		(node = isl_schedule_node_first_child(node)) != NULL);
+
+	return node;
+}
+
+/* Callback for "traverse" to leave a node for
+ * isl_schedule_node_get_subtree_expansion.
+ *
+ * If we come across a filter node that is the child
+ * of a set or sequence node, then we remove the element
+ * of data->expansions that was added in subtree_expansion_enter.
+ *
+ * If we reach a leaf node, then the accumulated expansion is
+ * added to data->res.
+ */
+static __isl_give isl_schedule_node *subtree_expansion_leave(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	struct isl_subtree_expansion_data *data = user;
+	int n;
+	isl_union_map *inner;
+	enum isl_schedule_node_type type;
+
+	switch (isl_schedule_node_get_type(node)) {
+	case isl_schedule_node_error:
+		return isl_schedule_node_free(node);
+	case isl_schedule_node_filter:
+		type = isl_schedule_node_get_parent_type(node);
+		if (type != isl_schedule_node_set &&
+		    type != isl_schedule_node_sequence)
+			break;
+		n = isl_union_map_list_n_union_map(data->expansions);
+		data->expansions = isl_union_map_list_drop(data->expansions,
+							n - 1, 1);
+		break;
+	case isl_schedule_node_leaf:
+		n = isl_union_map_list_n_union_map(data->expansions);
+		inner = isl_union_map_list_get_union_map(data->expansions,
+							n - 1);
+		data->res = isl_union_map_union(data->res, inner);
+		break;
+	case isl_schedule_node_band:
+	case isl_schedule_node_context:
+	case isl_schedule_node_domain:
+	case isl_schedule_node_expansion:
+	case isl_schedule_node_extension:
+	case isl_schedule_node_guard:
+	case isl_schedule_node_mark:
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		break;
+	}
+
+	return node;
+}
+
+/* Return a mapping from the domain elements that reach "node"
+ * to the corresponding domain elements in the leaves of the subtree
+ * rooted at "node" obtained by composing the intermediate expansions.
+ *
+ * We start out with an identity mapping between the domain elements
+ * that reach "node" and compose it with all the expansions
+ * on a path from "node" to a leaf while traversing the subtree.
+ * Within the children of an a sequence or set node, the
+ * accumulated expansion is restricted to the elements selected
+ * by the filter child.
+ */
+__isl_give isl_union_map *isl_schedule_node_get_subtree_expansion(
+	__isl_keep isl_schedule_node *node)
+{
+	struct isl_subtree_expansion_data data;
+	isl_space *space;
+	isl_union_set *domain;
+	isl_union_map *expansion;
+
+	if (!node)
+		return NULL;
+
+	domain = isl_schedule_node_get_universe_domain(node);
+	space = isl_union_set_get_space(domain);
+	expansion = isl_union_set_identity(domain);
+	data.res = isl_union_map_empty(space);
+	data.expansions = isl_union_map_list_from_union_map(expansion);
+
+	node = isl_schedule_node_copy(node);
+	node = traverse(node, &subtree_expansion_enter,
+			&subtree_expansion_leave, &data);
+	if (!node)
+		data.res = isl_union_map_free(data.res);
+	isl_schedule_node_free(node);
+
+	isl_union_map_list_free(data.expansions);
+
+	return data.res;
+}
+
+/* Internal data structure for isl_schedule_node_get_subtree_contraction.
+ * "contractions" contains a list of accumulated contractions
+ * for each outer expansion, set or sequence node.  The first element
+ * in the list is an identity mapping on the reaching domain elements.
+ * "res" collects the results.
+ */
+struct isl_subtree_contraction_data {
+	isl_union_pw_multi_aff_list *contractions;
+	isl_union_pw_multi_aff *res;
+};
+
+/* Callback for "traverse" to enter a node and to move
+ * to the deepest initial subtree that should be traversed
+ * by isl_schedule_node_get_subtree_contraction.
+ *
+ * Whenever we come across an expansion node, the last element
+ * of data->contractions is combined with the contraction
+ * on the expansion node.
+ *
+ * Whenever we come across a filter node that is the child
+ * of a set or sequence node, data->contractions is extended
+ * with a new element that restricts the previous element
+ * to the elements selected by the filter.
+ * The previous element can then be reused while backtracking.
+ */
+static __isl_give isl_schedule_node *subtree_contraction_enter(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	struct isl_subtree_contraction_data *data = user;
+
+	do {
+		enum isl_schedule_node_type type;
+		isl_union_set *filter;
+		isl_union_pw_multi_aff *inner, *contraction;
+		int n;
+
+		switch (isl_schedule_node_get_type(node)) {
+		case isl_schedule_node_error:
+			return isl_schedule_node_free(node);
+		case isl_schedule_node_filter:
+			type = isl_schedule_node_get_parent_type(node);
+			if (type != isl_schedule_node_set &&
+			    type != isl_schedule_node_sequence)
+				break;
+			filter = isl_schedule_node_filter_get_filter(node);
+			n = isl_union_pw_multi_aff_list_n_union_pw_multi_aff(
+						data->contractions);
+			inner =
+			    isl_union_pw_multi_aff_list_get_union_pw_multi_aff(
+						data->contractions, n - 1);
+			inner = isl_union_pw_multi_aff_intersect_domain(inner,
+								filter);
+			data->contractions =
+			    isl_union_pw_multi_aff_list_add(data->contractions,
+								inner);
+			break;
+		case isl_schedule_node_expansion:
+			n = isl_union_pw_multi_aff_list_n_union_pw_multi_aff(
+						data->contractions);
+			contraction =
+			    isl_schedule_node_expansion_get_contraction(node);
+			inner =
+			    isl_union_pw_multi_aff_list_get_union_pw_multi_aff(
+						data->contractions, n - 1);
+			inner =
+			    isl_union_pw_multi_aff_pullback_union_pw_multi_aff(
+						inner, contraction);
+			data->contractions =
+			    isl_union_pw_multi_aff_list_set_union_pw_multi_aff(
+					data->contractions, n - 1, inner);
+			break;
+		case isl_schedule_node_band:
+		case isl_schedule_node_context:
+		case isl_schedule_node_domain:
+		case isl_schedule_node_extension:
+		case isl_schedule_node_guard:
+		case isl_schedule_node_leaf:
+		case isl_schedule_node_mark:
+		case isl_schedule_node_sequence:
+		case isl_schedule_node_set:
+			break;
+		}
+	} while (isl_schedule_node_has_children(node) &&
+		(node = isl_schedule_node_first_child(node)) != NULL);
+
+	return node;
+}
+
+/* Callback for "traverse" to leave a node for
+ * isl_schedule_node_get_subtree_contraction.
+ *
+ * If we come across a filter node that is the child
+ * of a set or sequence node, then we remove the element
+ * of data->contractions that was added in subtree_contraction_enter.
+ *
+ * If we reach a leaf node, then the accumulated contraction is
+ * added to data->res.
+ */
+static __isl_give isl_schedule_node *subtree_contraction_leave(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	struct isl_subtree_contraction_data *data = user;
+	int n;
+	isl_union_pw_multi_aff *inner;
+	enum isl_schedule_node_type type;
+
+	switch (isl_schedule_node_get_type(node)) {
+	case isl_schedule_node_error:
+		return isl_schedule_node_free(node);
+	case isl_schedule_node_filter:
+		type = isl_schedule_node_get_parent_type(node);
+		if (type != isl_schedule_node_set &&
+		    type != isl_schedule_node_sequence)
+			break;
+		n = isl_union_pw_multi_aff_list_n_union_pw_multi_aff(
+						data->contractions);
+		data->contractions =
+			isl_union_pw_multi_aff_list_drop(data->contractions,
+							n - 1, 1);
+		break;
+	case isl_schedule_node_leaf:
+		n = isl_union_pw_multi_aff_list_n_union_pw_multi_aff(
+						data->contractions);
+		inner = isl_union_pw_multi_aff_list_get_union_pw_multi_aff(
+						data->contractions, n - 1);
+		data->res = isl_union_pw_multi_aff_union_add(data->res, inner);
+		break;
+	case isl_schedule_node_band:
+	case isl_schedule_node_context:
+	case isl_schedule_node_domain:
+	case isl_schedule_node_expansion:
+	case isl_schedule_node_extension:
+	case isl_schedule_node_guard:
+	case isl_schedule_node_mark:
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		break;
+	}
+
+	return node;
+}
+
+/* Return a mapping from the domain elements in the leaves of the subtree
+ * rooted at "node" to the corresponding domain elements that reach "node"
+ * obtained by composing the intermediate contractions.
+ *
+ * We start out with an identity mapping between the domain elements
+ * that reach "node" and compose it with all the contractions
+ * on a path from "node" to a leaf while traversing the subtree.
+ * Within the children of an a sequence or set node, the
+ * accumulated contraction is restricted to the elements selected
+ * by the filter child.
+ */
+__isl_give isl_union_pw_multi_aff *isl_schedule_node_get_subtree_contraction(
+	__isl_keep isl_schedule_node *node)
+{
+	struct isl_subtree_contraction_data data;
+	isl_space *space;
+	isl_union_set *domain;
+	isl_union_pw_multi_aff *contraction;
+
+	if (!node)
+		return NULL;
+
+	domain = isl_schedule_node_get_universe_domain(node);
+	space = isl_union_set_get_space(domain);
+	contraction = isl_union_set_identity_union_pw_multi_aff(domain);
+	data.res = isl_union_pw_multi_aff_empty(space);
+	data.contractions =
+	    isl_union_pw_multi_aff_list_from_union_pw_multi_aff(contraction);
+
+	node = isl_schedule_node_copy(node);
+	node = traverse(node, &subtree_contraction_enter,
+			&subtree_contraction_leave, &data);
+	if (!node)
+		data.res = isl_union_pw_multi_aff_free(data.res);
+	isl_schedule_node_free(node);
+
+	isl_union_pw_multi_aff_list_free(data.contractions);
+
+	return data.res;
+}
+
+/* Do the nearest "n" ancestors of "node" have the types given in "types"
+ * (starting at the parent of "node")?
+ */
+static int has_ancestors(__isl_keep isl_schedule_node *node,
+	int n, enum isl_schedule_node_type *types)
+{
+	int i, n_ancestor;
+
+	if (!node)
+		return -1;
+
+	n_ancestor = isl_schedule_tree_list_n_schedule_tree(node->ancestors);
+	if (n_ancestor < n)
+		return 0;
+
+	for (i = 0; i < n; ++i) {
+		isl_schedule_tree *tree;
+		int correct_type;
+
+		tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors,
+							    n_ancestor - 1 - i);
+		if (!tree)
+			return -1;
+		correct_type = isl_schedule_tree_get_type(tree) == types[i];
+		isl_schedule_tree_free(tree);
+		if (!correct_type)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Given a node "node" that appears in an extension (i.e., it is the child
+ * of a filter in a sequence inside an extension node), are the spaces
+ * of the extension specified by "extension" disjoint from those
+ * of both the original extension and the domain elements that reach
+ * that original extension?
+ */
+static int is_disjoint_extension(__isl_keep isl_schedule_node *node,
+	__isl_keep isl_union_map *extension)
+{
+	isl_union_map *old;
+	isl_union_set *domain;
+	int empty;
+
+	node = isl_schedule_node_copy(node);
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_parent(node);
+	old = isl_schedule_node_extension_get_extension(node);
+	domain = isl_schedule_node_get_universe_domain(node);
+	isl_schedule_node_free(node);
+	old = isl_union_map_universe(old);
+	domain = isl_union_set_union(domain, isl_union_map_range(old));
+	extension = isl_union_map_copy(extension);
+	extension = isl_union_map_intersect_range(extension, domain);
+	empty = isl_union_map_is_empty(extension);
+	isl_union_map_free(extension);
+
+	return empty;
+}
+
+/* Given a node "node" that is governed by an extension node, extend
+ * that extension node with "extension".
+ *
+ * In particular, "node" is the child of a filter in a sequence that
+ * is in turn a child of an extension node.  Extend that extension node
+ * with "extension".
+ *
+ * Return a pointer to the parent of the original node (i.e., a filter).
+ */
+static __isl_give isl_schedule_node *extend_extension(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_map *extension)
+{
+	int pos;
+	int disjoint;
+	isl_union_map *node_extension;
+
+	node = isl_schedule_node_parent(node);
+	pos = isl_schedule_node_get_child_position(node);
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_parent(node);
+	node_extension = isl_schedule_node_extension_get_extension(node);
+	disjoint = isl_union_map_is_disjoint(extension, node_extension);
+	extension = isl_union_map_union(extension, node_extension);
+	node = isl_schedule_node_extension_set_extension(node, extension);
+	node = isl_schedule_node_child(node, 0);
+	node = isl_schedule_node_child(node, pos);
+
+	if (disjoint < 0)
+		return isl_schedule_node_free(node);
+	if (!node)
+		return NULL;
+	if (!disjoint)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"extension domain should be disjoint from earlier "
+			"extensions", return isl_schedule_node_free(node));
+
+	return node;
+}
+
+/* Return the universe of "uset" if this universe is disjoint from "ref".
+ * Otherwise, return "uset".
+ *
+ * Also check if "uset" itself is disjoint from "ref", reporting
+ * an error if it is not.
+ */
+static __isl_give isl_union_set *replace_by_universe_if_disjoint(
+	__isl_take isl_union_set *uset, __isl_keep isl_union_set *ref)
+{
+	int disjoint;
+	isl_union_set *universe;
+
+	disjoint = isl_union_set_is_disjoint(uset, ref);
+	if (disjoint < 0)
+		return isl_union_set_free(uset);
+	if (!disjoint)
+		isl_die(isl_union_set_get_ctx(uset), isl_error_invalid,
+			"extension domain should be disjoint from "
+			"current domain", return isl_union_set_free(uset));
+
+	universe = isl_union_set_universe(isl_union_set_copy(uset));
+	disjoint = isl_union_set_is_disjoint(universe, ref);
+	if (disjoint >= 0 && disjoint) {
+		isl_union_set_free(uset);
+		return universe;
+	}
+	isl_union_set_free(universe);
+
+	if (disjoint < 0)
+		return isl_union_set_free(uset);
+	return uset;
+}
+
+/* Insert an extension node on top of "node" with extension "extension".
+ * In addition, insert a filter that separates node from the extension
+ * between the extension node and "node".
+ * Return a pointer to the inserted filter node.
+ *
+ * If "node" already appears in an extension (i.e., if it is the child
+ * of a filter in a sequence inside an extension node), then extend that
+ * extension with "extension" instead.
+ * In this case, a pointer to the original filter node is returned.
+ * Note that if some of the elements in the new extension live in the
+ * same space as those of the original extension or the domain elements
+ * reaching the original extension, then we insert a new extension anyway.
+ * Otherwise, we would have to adjust the filters in the sequence child
+ * of the extension to ensure that the elements in the new extension
+ * are filtered out.
+ */
+static __isl_give isl_schedule_node *insert_extension(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_map *extension)
+{
+	enum isl_schedule_node_type ancestors[] =
+		{ isl_schedule_node_filter, isl_schedule_node_sequence,
+		  isl_schedule_node_extension };
+	isl_union_set *domain;
+	isl_union_set *filter;
+	int in_ext;
+
+	in_ext = has_ancestors(node, 3, ancestors);
+	if (in_ext < 0)
+		goto error;
+	if (in_ext) {
+		int disjoint;
+
+		disjoint = is_disjoint_extension(node, extension);
+		if (disjoint < 0)
+			goto error;
+		if (disjoint)
+			return extend_extension(node, extension);
+	}
+
+	filter = isl_schedule_node_get_domain(node);
+	domain = isl_union_map_range(isl_union_map_copy(extension));
+	filter = replace_by_universe_if_disjoint(filter, domain);
+	isl_union_set_free(domain);
+
+	node = isl_schedule_node_insert_filter(node, filter);
+	node = isl_schedule_node_insert_extension(node, extension);
+	node = isl_schedule_node_child(node, 0);
+	return node;
+error:
+	isl_schedule_node_free(node);
+	isl_union_map_free(extension);
+	return NULL;
+}
+
+/* Replace the subtree that "node" points to by "tree" (which has
+ * a sequence root with two children), except if the parent of "node"
+ * is a sequence as well, in which case "tree" is spliced at the position
+ * of "node" in its parent.
+ * Return a pointer to the child of the "tree_pos" (filter) child of "tree"
+ * in the updated schedule tree.
+ */
+static __isl_give isl_schedule_node *graft_or_splice(
+	__isl_take isl_schedule_node *node, __isl_take isl_schedule_tree *tree,
+	int tree_pos)
+{
+	int pos;
+
+	if (isl_schedule_node_get_parent_type(node) ==
+	    isl_schedule_node_sequence) {
+		pos = isl_schedule_node_get_child_position(node);
+		node = isl_schedule_node_parent(node);
+		node = isl_schedule_node_sequence_splice(node, pos, tree);
+	} else {
+		pos = 0;
+		node = isl_schedule_node_graft_tree(node, tree);
+	}
+	node = isl_schedule_node_child(node, pos + tree_pos);
+	node = isl_schedule_node_child(node, 0);
+
+	return node;
+}
+
+/* Insert a node "graft" into the schedule tree of "node" such that it
+ * is executed before (if "before" is set) or after (if "before" is not set)
+ * the node that "node" points to.
+ * The root of "graft" is an extension node.
+ * Return a pointer to the node that "node" pointed to.
+ *
+ * We first insert an extension node on top of "node" (or extend
+ * the extension node if there already is one), with a filter on "node"
+ * separating it from the extension.
+ * We then insert a filter in the graft to separate it from the original
+ * domain elements and combine the original and new tree in a sequence.
+ * If we have extended an extension node, then the children of this
+ * sequence are spliced in the sequence of the extended extension
+ * at the position where "node" appears in the original extension.
+ * Otherwise, the sequence pair is attached to the new extension node.
+ */
+static __isl_give isl_schedule_node *graft_extension(
+	__isl_take isl_schedule_node *node, __isl_take isl_schedule_node *graft,
+	int before)
+{
+	isl_union_map *extension;
+	isl_union_set *graft_domain;
+	isl_union_set *node_domain;
+	isl_schedule_tree *tree, *tree_graft;
+
+	extension = isl_schedule_node_extension_get_extension(graft);
+	graft_domain = isl_union_map_range(isl_union_map_copy(extension));
+	node_domain = isl_schedule_node_get_universe_domain(node);
+	node = insert_extension(node, extension);
+
+	graft_domain = replace_by_universe_if_disjoint(graft_domain,
+							node_domain);
+	isl_union_set_free(node_domain);
+
+	tree = isl_schedule_node_get_tree(node);
+	if (!isl_schedule_node_has_children(graft)) {
+		tree_graft = isl_schedule_tree_from_filter(graft_domain);
+	} else {
+		graft = isl_schedule_node_child(graft, 0);
+		tree_graft = isl_schedule_node_get_tree(graft);
+		tree_graft = isl_schedule_tree_insert_filter(tree_graft,
+								graft_domain);
+	}
+	if (before)
+		tree = isl_schedule_tree_sequence_pair(tree_graft, tree);
+	else
+		tree = isl_schedule_tree_sequence_pair(tree, tree_graft);
+	node = graft_or_splice(node, tree, before);
+
+	isl_schedule_node_free(graft);
+
+	return node;
+}
+
+/* Replace the root domain node of "node" by an extension node suitable
+ * for insertion at "pos".
+ * That is, create an extension node that maps the outer band nodes
+ * at "pos" to the domain of the root node of "node" and attach
+ * the child of this root node to the extension node.
+ */
+static __isl_give isl_schedule_node *extension_from_domain(
+	__isl_take isl_schedule_node *node, __isl_keep isl_schedule_node *pos)
+{
+	isl_union_set *universe;
+	isl_union_set *domain;
+	isl_union_map *ext;
+	int depth;
+	int anchored;
+	isl_space *space;
+	isl_schedule_node *res;
+	isl_schedule_tree *tree;
+
+	anchored = isl_schedule_node_is_subtree_anchored(node);
+	if (anchored < 0)
+		return isl_schedule_node_free(node);
+	if (anchored)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_unsupported,
+			"cannot graft anchored tree with domain root",
+			return isl_schedule_node_free(node));
+
+	depth = isl_schedule_node_get_schedule_depth(pos);
+	domain = isl_schedule_node_domain_get_domain(node);
+	space = isl_union_set_get_space(domain);
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, depth);
+	universe = isl_union_set_from_set(isl_set_universe(space));
+	ext = isl_union_map_from_domain_and_range(universe, domain);
+	res = isl_schedule_node_from_extension(ext);
+	node = isl_schedule_node_child(node, 0);
+	if (!node)
+		return isl_schedule_node_free(res);
+	if (!isl_schedule_tree_is_leaf(node->tree)) {
+		tree = isl_schedule_node_get_tree(node);
+		res = isl_schedule_node_child(res, 0);
+		res = isl_schedule_node_graft_tree(res, tree);
+		res = isl_schedule_node_parent(res);
+	}
+	isl_schedule_node_free(node);
+
+	return res;
+}
+
+/* Insert a node "graft" into the schedule tree of "node" such that it
+ * is executed before (if "before" is set) or after (if "before" is not set)
+ * the node that "node" points to.
+ * The root of "graft" may be either a domain or an extension node.
+ * In the latter case, the domain of the extension needs to correspond
+ * to the outer band nodes of "node".
+ * The elements of the domain or the range of the extension may not
+ * intersect with the domain elements that reach "node".
+ * The schedule tree of "graft" may not be anchored.
+ *
+ * The schedule tree of "node" is modified to include an extension node
+ * corresponding to the root node of "graft" as a child of the original
+ * parent of "node".  The original node that "node" points to and the
+ * child of the root node of "graft" are attached to this extension node
+ * through a sequence, with appropriate filters and with the child
+ * of "graft" appearing before or after the original "node".
+ *
+ * If "node" already appears inside a sequence that is the child of
+ * an extension node and if the spaces of the new domain elements
+ * do not overlap with those of the original domain elements,
+ * then that extension node is extended with the new extension
+ * rather than introducing a new segment of extension and sequence nodes.
+ *
+ * Return a pointer to the same node in the modified tree that
+ * "node" pointed to in the original tree.
+ */
+static __isl_give isl_schedule_node *isl_schedule_node_graft_before_or_after(
+	__isl_take isl_schedule_node *node, __isl_take isl_schedule_node *graft,
+	int before)
+{
+	if (!node || !graft)
+		goto error;
+	if (check_insert(node) < 0)
+		goto error;
+
+	if (isl_schedule_node_get_type(graft) == isl_schedule_node_domain)
+		graft = extension_from_domain(graft, node);
+
+	if (isl_schedule_node_get_type(graft) != isl_schedule_node_extension)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"expecting domain or extension as root of graft",
+			goto error);
+
+	return graft_extension(node, graft, before);
+error:
+	isl_schedule_node_free(node);
+	isl_schedule_node_free(graft);
+	return NULL;
+}
+
+/* Insert a node "graft" into the schedule tree of "node" such that it
+ * is executed before the node that "node" points to.
+ * The root of "graft" may be either a domain or an extension node.
+ * In the latter case, the domain of the extension needs to correspond
+ * to the outer band nodes of "node".
+ * The elements of the domain or the range of the extension may not
+ * intersect with the domain elements that reach "node".
+ * The schedule tree of "graft" may not be anchored.
+ *
+ * Return a pointer to the same node in the modified tree that
+ * "node" pointed to in the original tree.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_graft_before(
+	__isl_take isl_schedule_node *node, __isl_take isl_schedule_node *graft)
+{
+	return isl_schedule_node_graft_before_or_after(node, graft, 1);
+}
+
+/* Insert a node "graft" into the schedule tree of "node" such that it
+ * is executed after the node that "node" points to.
+ * The root of "graft" may be either a domain or an extension node.
+ * In the latter case, the domain of the extension needs to correspond
+ * to the outer band nodes of "node".
+ * The elements of the domain or the range of the extension may not
+ * intersect with the domain elements that reach "node".
+ * The schedule tree of "graft" may not be anchored.
+ *
+ * Return a pointer to the same node in the modified tree that
+ * "node" pointed to in the original tree.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_graft_after(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_schedule_node *graft)
+{
+	return isl_schedule_node_graft_before_or_after(node, graft, 0);
+}
+
+/* Split the domain elements that reach "node" into those that satisfy
+ * "filter" and those that do not.  Arrange for the first subset to be
+ * executed before or after the second subset, depending on the value
+ * of "before".
+ * Return a pointer to the tree corresponding to the second subset,
+ * except when this subset is empty in which case the original pointer
+ * is returned.
+ * If both subsets are non-empty, then a sequence node is introduced
+ * to impose the order.  If the grandparent of the original node was
+ * itself a sequence, then the original child is replaced by two children
+ * in this sequence instead.
+ * The children in the sequence are copies of the original subtree,
+ * simplified with respect to their filters.
+ */
+static __isl_give isl_schedule_node *isl_schedule_node_order_before_or_after(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *filter,
+	int before)
+{
+	enum isl_schedule_node_type ancestors[] =
+		{ isl_schedule_node_filter, isl_schedule_node_sequence };
+	isl_union_set *node_domain, *node_filter = NULL, *parent_filter;
+	isl_schedule_node *node2;
+	isl_schedule_tree *tree1, *tree2;
+	int empty1, empty2;
+	int in_seq;
+
+	if (!node || !filter)
+		goto error;
+	if (check_insert(node) < 0)
+		goto error;
+
+	in_seq = has_ancestors(node, 2, ancestors);
+	if (in_seq < 0)
+		goto error;
+	node_domain = isl_schedule_node_get_domain(node);
+	filter = isl_union_set_gist(filter, isl_union_set_copy(node_domain));
+	node_filter = isl_union_set_copy(node_domain);
+	node_filter = isl_union_set_subtract(node_filter,
+						isl_union_set_copy(filter));
+	node_filter = isl_union_set_gist(node_filter, node_domain);
+	empty1 = isl_union_set_is_empty(filter);
+	empty2 = isl_union_set_is_empty(node_filter);
+	if (empty1 < 0 || empty2 < 0)
+		goto error;
+	if (empty1 || empty2) {
+		isl_union_set_free(filter);
+		isl_union_set_free(node_filter);
+		return node;
+	}
+
+	if (in_seq) {
+		node = isl_schedule_node_parent(node);
+		parent_filter = isl_schedule_node_filter_get_filter(node);
+		node_filter = isl_union_set_intersect(node_filter,
+					    isl_union_set_copy(parent_filter));
+		filter = isl_union_set_intersect(filter, parent_filter);
+	}
+
+	node2 = isl_schedule_node_copy(node);
+	node = isl_schedule_node_gist(node, isl_union_set_copy(node_filter));
+	node2 = isl_schedule_node_gist(node2, isl_union_set_copy(filter));
+	tree1 = isl_schedule_node_get_tree(node);
+	tree2 = isl_schedule_node_get_tree(node2);
+	tree1 = isl_schedule_tree_insert_filter(tree1, node_filter);
+	tree2 = isl_schedule_tree_insert_filter(tree2, filter);
+	isl_schedule_node_free(node2);
+
+	if (before) {
+		tree1 = isl_schedule_tree_sequence_pair(tree2, tree1);
+		node = graft_or_splice(node, tree1, 1);
+	} else {
+		tree1 = isl_schedule_tree_sequence_pair(tree1, tree2);
+		node = graft_or_splice(node, tree1, 0);
+	}
+
+	return node;
+error:
+	isl_schedule_node_free(node);
+	isl_union_set_free(filter);
+	isl_union_set_free(node_filter);
+	return NULL;
+}
+
+/* Split the domain elements that reach "node" into those that satisfy
+ * "filter" and those that do not.  Arrange for the first subset to be
+ * executed before the second subset.
+ * Return a pointer to the tree corresponding to the second subset,
+ * except when this subset is empty in which case the original pointer
+ * is returned.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_order_before(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *filter)
+{
+	return isl_schedule_node_order_before_or_after(node, filter, 1);
+}
+
+/* Split the domain elements that reach "node" into those that satisfy
+ * "filter" and those that do not.  Arrange for the first subset to be
+ * executed after the second subset.
+ * Return a pointer to the tree corresponding to the second subset,
+ * except when this subset is empty in which case the original pointer
+ * is returned.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_order_after(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *filter)
+{
+	return isl_schedule_node_order_before_or_after(node, filter, 0);
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * in the schedule node "node".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_reset_user(
+	__isl_take isl_schedule_node *node)
+{
+	isl_schedule_tree *tree;
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_reset_user(tree);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+}
+
+/* Align the parameters of the schedule node "node" to those of "space".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_align_params(
+	__isl_take isl_schedule_node *node, __isl_take isl_space *space)
+{
+	isl_schedule_tree *tree;
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_align_params(tree, space);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+}
+
+/* Compute the pullback of schedule node "node"
+ * by the function represented by "upma".
+ * In other words, plug in "upma" in the iteration domains
+ * of schedule node "node".
+ * We currently do not handle expansion nodes.
+ *
+ * Note that this is only a helper function for
+ * isl_schedule_pullback_union_pw_multi_aff.  In order to maintain consistency,
+ * this function should not be called on a single node without also
+ * calling it on all the other nodes.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_pullback_union_pw_multi_aff(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_pw_multi_aff *upma)
+{
+	isl_schedule_tree *tree;
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_pullback_union_pw_multi_aff(tree, upma);
+	node = isl_schedule_node_graft_tree(node, tree);
+
+	return node;
+}
+
+/* Internal data structure for isl_schedule_node_expand.
+ * "tree" is the tree that needs to be plugged in in all the leaves.
+ * "domain" is the set of domain elements in the original leaves
+ * to which the tree applies.
+ */
+struct isl_schedule_expand_data {
+	isl_schedule_tree *tree;
+	isl_union_set *domain;
+};
+
+/* If "node" is a leaf, then plug in data->tree, simplifying it
+ * within its new context.
+ *
+ * If there are any domain elements at the leaf where the tree
+ * should not be plugged in (i.e., there are elements not in data->domain)
+ * then first extend the tree to only apply to the elements in data->domain
+ * by constructing a set node that selects data->tree for elements
+ * in data->domain and a leaf for the other elements.
+ */
+static __isl_give isl_schedule_node *expand(__isl_take isl_schedule_node *node,
+	void *user)
+{
+	struct isl_schedule_expand_data *data = user;
+	isl_schedule_tree *tree, *leaf;
+	isl_union_set *domain, *left;
+	isl_bool empty;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_leaf)
+		return node;
+
+	domain = isl_schedule_node_get_domain(node);
+	tree = isl_schedule_tree_copy(data->tree);
+
+	left = isl_union_set_copy(domain);
+	left = isl_union_set_subtract(left, isl_union_set_copy(data->domain));
+	empty = isl_union_set_is_empty(left);
+	if (empty >= 0 && !empty) {
+		leaf = isl_schedule_node_get_leaf(node);
+		leaf = isl_schedule_tree_insert_filter(leaf, left);
+		left = isl_union_set_copy(data->domain);
+		tree = isl_schedule_tree_insert_filter(tree, left);
+		tree = isl_schedule_tree_set_pair(tree, leaf);
+	} else {
+		if (empty < 0)
+			node = isl_schedule_node_free(node);
+		isl_union_set_free(left);
+	}
+
+	node = isl_schedule_node_graft_tree(node, tree);
+	node = isl_schedule_node_gist(node, domain);
+
+	return node;
+}
+
+/* Expand the tree rooted at "node" by extending all leaves
+ * with an expansion node with as child "tree".
+ * The expansion is determined by "contraction" and "domain".
+ * That is, the elements of "domain" are contracted according
+ * to "contraction".  The expansion relation is then the inverse
+ * of "contraction" with its range intersected with "domain".
+ *
+ * Insert the appropriate expansion node on top of "tree" and
+ * then plug in the result in all leaves of "node".
+ */
+__isl_give isl_schedule_node *isl_schedule_node_expand(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_union_set *domain,
+	__isl_take isl_schedule_tree *tree)
+{
+	struct isl_schedule_expand_data data;
+	isl_union_map *expansion;
+	isl_union_pw_multi_aff *copy;
+
+	if (!node || !contraction || !tree)
+		node = isl_schedule_node_free(node);
+
+	copy = isl_union_pw_multi_aff_copy(contraction);
+	expansion = isl_union_map_from_union_pw_multi_aff(copy);
+	expansion = isl_union_map_reverse(expansion);
+	expansion = isl_union_map_intersect_range(expansion, domain);
+	data.domain = isl_union_map_domain(isl_union_map_copy(expansion));
+
+	tree = isl_schedule_tree_insert_expansion(tree, contraction, expansion);
+	data.tree = tree;
+
+	node = isl_schedule_node_map_descendant_bottom_up(node, &expand, &data);
+	isl_union_set_free(data.domain);
+	isl_schedule_tree_free(data.tree);
+	return node;
+}
+
+/* Return the position of the subtree containing "node" among the children
+ * of "ancestor".  "node" is assumed to be a descendant of "ancestor".
+ * In particular, both nodes should point to the same schedule tree.
+ *
+ * Return -1 on error.
+ */
+int isl_schedule_node_get_ancestor_child_position(
+	__isl_keep isl_schedule_node *node,
+	__isl_keep isl_schedule_node *ancestor)
+{
+	int n1, n2;
+	isl_schedule_tree *tree;
+
+	if (!node || !ancestor)
+		return -1;
+
+	if (node->schedule != ancestor->schedule)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"not a descendant", return -1);
+
+	n1 = isl_schedule_node_get_tree_depth(ancestor);
+	n2 = isl_schedule_node_get_tree_depth(node);
+
+	if (n1 >= n2)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"not a descendant", return -1);
+	tree = isl_schedule_tree_list_get_schedule_tree(node->ancestors, n1);
+	isl_schedule_tree_free(tree);
+	if (tree != ancestor->tree)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"not a descendant", return -1);
+
+	return node->child_pos[n1];
+}
+
+/* Given two nodes that point to the same schedule tree, return their
+ * closest shared ancestor.
+ *
+ * Since the two nodes point to the same schedule, they share at least
+ * one ancestor, the root of the schedule.  We move down from the root
+ * to the first ancestor where the respective children have a different
+ * child position.  This is the requested ancestor.
+ * If there is no ancestor where the children have a different position,
+ * then one node is an ancestor of the other and then this node is
+ * the requested ancestor.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_get_shared_ancestor(
+	__isl_keep isl_schedule_node *node1,
+	__isl_keep isl_schedule_node *node2)
+{
+	int i, n1, n2;
+
+	if (!node1 || !node2)
+		return NULL;
+	if (node1->schedule != node2->schedule)
+		isl_die(isl_schedule_node_get_ctx(node1), isl_error_invalid,
+			"not part of same schedule", return NULL);
+	n1 = isl_schedule_node_get_tree_depth(node1);
+	n2 = isl_schedule_node_get_tree_depth(node2);
+	if (n2 < n1)
+		return isl_schedule_node_get_shared_ancestor(node2, node1);
+	if (n1 == 0)
+		return isl_schedule_node_copy(node1);
+	if (isl_schedule_node_is_equal(node1, node2))
+		return isl_schedule_node_copy(node1);
+
+	for (i = 0; i < n1; ++i)
+		if (node1->child_pos[i] != node2->child_pos[i])
+			break;
+
+	node1 = isl_schedule_node_copy(node1);
+	return isl_schedule_node_ancestor(node1, n1 - i);
+}
+
+/* Print "node" to "p".
+ */
+__isl_give isl_printer *isl_printer_print_schedule_node(
+	__isl_take isl_printer *p, __isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return isl_printer_free(p);
+	return isl_printer_print_schedule_tree_mark(p, node->schedule->root,
+			isl_schedule_tree_list_n_schedule_tree(node->ancestors),
+			node->child_pos);
+}
+
+void isl_schedule_node_dump(__isl_keep isl_schedule_node *node)
+{
+	isl_ctx *ctx;
+	isl_printer *printer;
+
+	if (!node)
+		return;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	printer = isl_printer_to_file(ctx, stderr);
+	printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK);
+	printer = isl_printer_print_schedule_node(printer, node);
+
+	isl_printer_free(printer);
+}
+
+/* Return a string representation of "node".
+ * Print the schedule node in block format as it would otherwise
+ * look identical to the entire schedule.
+ */
+__isl_give char *isl_schedule_node_to_str(__isl_keep isl_schedule_node *node)
+{
+	isl_printer *printer;
+	char *s;
+
+	if (!node)
+		return NULL;
+
+	printer = isl_printer_to_str(isl_schedule_node_get_ctx(node));
+	printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK);
+	printer = isl_printer_print_schedule_node(printer, node);
+	s = isl_printer_get_str(printer);
+	isl_printer_free(printer);
+
+	return s;
+}
diff --git a/final/lib/External/isl/isl_schedule_node_private.h b/final/lib/External/isl/isl_schedule_node_private.h
new file mode 100644
index 0000000..c4ad6ef
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_node_private.h
@@ -0,0 +1,68 @@
+#ifndef ISL_SCHEDLUE_NODE_PRIVATE_H
+#define ISL_SCHEDLUE_NODE_PRIVATE_H
+
+#include <isl/schedule_node.h>
+#include <isl_schedule_band.h>
+#include <isl_schedule_tree.h>
+
+/* An isl_schedule_node points to a particular location in a schedule tree.
+ *
+ * "schedule" is the schedule that the node is pointing to.
+ * "ancestors" is a list of the n ancestors of the node
+ * that is being pointed to.
+ * The first ancestor is the root of "schedule", while the last ancestor
+ * is the parent of the specified location.
+ * "child_pos" is an array of child positions of the same length as "ancestors",
+ * where ancestor i (i > 0) appears in child_pos[i - 1] of ancestor i - 1 and
+ * "tree" appears in child_pos[n - 1] of ancestor n - 1.
+ * "tree" is the subtree at the specified location.
+ *
+ * Note that the same isl_schedule_tree object may appear several times
+ * in a schedule tree and therefore does not uniquely identify a position
+ * in the schedule tree.
+ */
+struct isl_schedule_node {
+	int ref;
+
+	isl_schedule *schedule;
+	isl_schedule_tree_list *ancestors;
+	int *child_pos;
+	isl_schedule_tree *tree;
+};
+
+__isl_give isl_schedule_node *isl_schedule_node_alloc(
+	__isl_take isl_schedule *schedule, __isl_take isl_schedule_tree *tree,
+	__isl_take isl_schedule_tree_list *ancestors, int *child_pos);
+__isl_give isl_schedule_node *isl_schedule_node_graft_tree(
+	__isl_take isl_schedule_node *pos, __isl_take isl_schedule_tree *tree);
+
+__isl_give isl_schedule_tree *isl_schedule_node_get_tree(
+	__isl_keep isl_schedule_node *node);
+
+__isl_give isl_schedule_node *isl_schedule_node_pullback_union_pw_multi_aff(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_pw_multi_aff *upma);
+
+__isl_give isl_schedule_node *isl_schedule_node_expand(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_union_set *domain,
+	__isl_take isl_schedule_tree *tree);
+
+__isl_give isl_schedule_node *isl_schedule_node_gist(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *context);
+
+__isl_give isl_schedule_node *isl_schedule_node_domain_intersect_domain(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *domain);
+__isl_give isl_schedule_node *isl_schedule_node_domain_gist_params(
+	__isl_take isl_schedule_node *node, __isl_take isl_set *context);
+
+__isl_give isl_schedule_node *isl_schedule_node_insert_expansion(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_union_map *expansion);
+__isl_give isl_schedule_node *isl_schedule_node_insert_extension(
+	__isl_take isl_schedule_node *node,
+	__isl_take isl_union_map *extension);
+
+#endif
diff --git a/final/lib/External/isl/isl_schedule_private.h b/final/lib/External/isl/isl_schedule_private.h
new file mode 100644
index 0000000..9ae4047
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_private.h
@@ -0,0 +1,41 @@
+#ifndef ISL_SCHEDLUE_PRIVATE_H
+#define ISL_SCHEDLUE_PRIVATE_H
+
+#include <isl/aff.h>
+#include <isl/schedule.h>
+#include <isl_schedule_tree.h>
+
+/* A complete schedule tree.
+ *
+ * band_forest points to a band forest representation of the schedule
+ * and may be NULL if the forest hasn't been created yet.
+ *
+ * "root" is the root of the schedule tree and may be NULL if we
+ * have created a band forest corresponding to the schedule.
+ *
+ * "leaf" may be used to represent a leaf of the schedule.
+ * It should not appear as a child to any other isl_schedule_tree objects,
+ * but an isl_schedule_node may have "leaf" as its tree if it refers to
+ * a leaf of this schedule tree.
+ */
+struct isl_schedule {
+	int ref;
+
+	isl_band_list *band_forest;
+	isl_schedule_tree *root;
+
+	struct isl_schedule_tree *leaf;
+};
+
+__isl_give isl_schedule *isl_schedule_from_schedule_tree(isl_ctx *ctx,
+	__isl_take isl_schedule_tree *tree);
+__isl_give isl_schedule *isl_schedule_set_root(
+	__isl_take isl_schedule *schedule, __isl_take isl_schedule_tree *tree);
+__isl_give isl_space *isl_schedule_get_space(
+	__isl_keep isl_schedule *schedule);
+__isl_give isl_union_set *isl_schedule_get_domain(
+	__isl_keep isl_schedule *schedule);
+__isl_keep isl_schedule_tree *isl_schedule_peek_leaf(
+	__isl_keep isl_schedule *schedule);
+
+#endif
diff --git a/final/lib/External/isl/isl_schedule_read.c b/final/lib/External/isl/isl_schedule_read.c
new file mode 100644
index 0000000..e3ea8c5
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_read.c
@@ -0,0 +1,775 @@
+#include <isl/schedule.h>
+#include <isl/stream.h>
+#include <isl_schedule_private.h>
+#include <isl_schedule_tree.h>
+
+/* An enumeration of the various keys that may appear in a YAML mapping
+ * of a schedule.
+ */
+enum isl_schedule_key {
+	isl_schedule_key_error = -1,
+	isl_schedule_key_child,
+	isl_schedule_key_coincident,
+	isl_schedule_key_context,
+	isl_schedule_key_contraction,
+	isl_schedule_key_domain,
+	isl_schedule_key_expansion,
+	isl_schedule_key_extension,
+	isl_schedule_key_filter,
+	isl_schedule_key_guard,
+	isl_schedule_key_leaf,
+	isl_schedule_key_mark,
+	isl_schedule_key_options,
+	isl_schedule_key_permutable,
+	isl_schedule_key_schedule,
+	isl_schedule_key_sequence,
+	isl_schedule_key_set,
+	isl_schedule_key_end
+};
+
+/* Textual representations of the YAML keys for an isl_schedule object.
+ */
+static char *key_str[] = {
+	[isl_schedule_key_child] = "child",
+	[isl_schedule_key_coincident] = "coincident",
+	[isl_schedule_key_context] = "context",
+	[isl_schedule_key_contraction] = "contraction",
+	[isl_schedule_key_domain] = "domain",
+	[isl_schedule_key_expansion] = "expansion",
+	[isl_schedule_key_extension] = "extension",
+	[isl_schedule_key_filter] = "filter",
+	[isl_schedule_key_guard] = "guard",
+	[isl_schedule_key_leaf] = "leaf",
+	[isl_schedule_key_mark] = "mark",
+	[isl_schedule_key_options] = "options",
+	[isl_schedule_key_permutable] = "permutable",
+	[isl_schedule_key_schedule] = "schedule",
+	[isl_schedule_key_sequence] = "sequence",
+	[isl_schedule_key_set] = "set",
+};
+
+#undef KEY
+#define KEY enum isl_schedule_key
+#undef KEY_ERROR
+#define KEY_ERROR isl_schedule_key_error
+#undef KEY_END
+#define KEY_END isl_schedule_key_end
+#include "extract_key.c"
+
+static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree(
+	__isl_keep isl_stream *s);
+
+/* Read a subtree with context root node from "s".
+ */
+static __isl_give isl_schedule_tree *read_context(__isl_keep isl_stream *s)
+{
+	isl_set *context = NULL;
+	isl_schedule_tree *tree;
+	isl_ctx *ctx;
+	struct isl_token *tok;
+	enum isl_schedule_key key;
+	char *str;
+	int more;
+
+	ctx = isl_stream_get_ctx(s);
+
+	key = get_key(s);
+
+	if (isl_stream_yaml_next(s) < 0)
+		return NULL;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	str = isl_token_get_str(ctx, tok);
+	context = isl_set_read_from_str(ctx, str);
+	free(str);
+	isl_token_free(tok);
+
+	more = isl_stream_yaml_next(s);
+	if (more < 0)
+		goto error;
+	if (!more) {
+		tree = isl_schedule_tree_from_context(context);
+	} else {
+		key = get_key(s);
+		if (key != isl_schedule_key_child)
+			isl_die(ctx, isl_error_invalid, "expecting child",
+				goto error);
+		if (isl_stream_yaml_next(s) < 0)
+			goto error;
+		tree = isl_stream_read_schedule_tree(s);
+		tree = isl_schedule_tree_insert_context(tree, context);
+	}
+
+	return tree;
+error:
+	isl_set_free(context);
+	return NULL;
+}
+
+/* Read a subtree with domain root node from "s".
+ */
+static __isl_give isl_schedule_tree *read_domain(__isl_keep isl_stream *s)
+{
+	isl_union_set *domain = NULL;
+	isl_schedule_tree *tree;
+	isl_ctx *ctx;
+	struct isl_token *tok;
+	enum isl_schedule_key key;
+	char *str;
+	int more;
+
+	ctx = isl_stream_get_ctx(s);
+
+	key = get_key(s);
+
+	if (isl_stream_yaml_next(s) < 0)
+		return NULL;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	str = isl_token_get_str(ctx, tok);
+	domain = isl_union_set_read_from_str(ctx, str);
+	free(str);
+	isl_token_free(tok);
+
+	more = isl_stream_yaml_next(s);
+	if (more < 0)
+		goto error;
+	if (!more) {
+		tree = isl_schedule_tree_from_domain(domain);
+	} else {
+		key = get_key(s);
+		if (key != isl_schedule_key_child)
+			isl_die(ctx, isl_error_invalid, "expecting child",
+				goto error);
+		if (isl_stream_yaml_next(s) < 0)
+			goto error;
+		tree = isl_stream_read_schedule_tree(s);
+		tree = isl_schedule_tree_insert_domain(tree, domain);
+	}
+
+	return tree;
+error:
+	isl_union_set_free(domain);
+	return NULL;
+}
+
+/* Read a subtree with expansion root node from "s".
+ */
+static __isl_give isl_schedule_tree *read_expansion(isl_stream *s)
+{
+	isl_ctx *ctx;
+	isl_union_pw_multi_aff *contraction = NULL;
+	isl_union_map *expansion = NULL;
+	isl_schedule_tree *tree = NULL;
+	int more;
+
+	ctx = isl_stream_get_ctx(s);
+
+	do {
+		struct isl_token *tok;
+		enum isl_schedule_key key;
+		char *str;
+
+		key = get_key(s);
+		if (isl_stream_yaml_next(s) < 0)
+			goto error;
+
+		switch (key) {
+		case isl_schedule_key_contraction:
+			isl_union_pw_multi_aff_free(contraction);
+			tok = isl_stream_next_token(s);
+			str = isl_token_get_str(ctx, tok);
+			contraction = isl_union_pw_multi_aff_read_from_str(ctx,
+									str);
+			free(str);
+			isl_token_free(tok);
+			if (!contraction)
+				goto error;
+			break;
+		case isl_schedule_key_expansion:
+			isl_union_map_free(expansion);
+			tok = isl_stream_next_token(s);
+			str = isl_token_get_str(ctx, tok);
+			expansion = isl_union_map_read_from_str(ctx, str);
+			free(str);
+			isl_token_free(tok);
+			if (!expansion)
+				goto error;
+			break;
+		case isl_schedule_key_child:
+			isl_schedule_tree_free(tree);
+			tree = isl_stream_read_schedule_tree(s);
+			if (!tree)
+				goto error;
+			break;
+		default:
+			isl_die(ctx, isl_error_invalid, "unexpected key",
+				goto error);
+		}
+	} while ((more = isl_stream_yaml_next(s)) > 0);
+
+	if (more < 0)
+		goto error;
+
+	if (!contraction)
+		isl_die(ctx, isl_error_invalid, "missing contraction",
+			goto error);
+	if (!expansion)
+		isl_die(ctx, isl_error_invalid, "missing expansion",
+			goto error);
+
+	if (!tree)
+		return isl_schedule_tree_from_expansion(contraction, expansion);
+	return isl_schedule_tree_insert_expansion(tree, contraction, expansion);
+error:
+	isl_schedule_tree_free(tree);
+	isl_union_pw_multi_aff_free(contraction);
+	isl_union_map_free(expansion);
+	return NULL;
+}
+
+/* Read a subtree with extension root node from "s".
+ */
+static __isl_give isl_schedule_tree *read_extension(isl_stream *s)
+{
+	isl_union_map *extension = NULL;
+	isl_schedule_tree *tree;
+	isl_ctx *ctx;
+	struct isl_token *tok;
+	enum isl_schedule_key key;
+	char *str;
+	int more;
+
+	ctx = isl_stream_get_ctx(s);
+
+	key = get_key(s);
+
+	if (isl_stream_yaml_next(s) < 0)
+		return NULL;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	str = isl_token_get_str(ctx, tok);
+	extension = isl_union_map_read_from_str(ctx, str);
+	free(str);
+	isl_token_free(tok);
+
+	more = isl_stream_yaml_next(s);
+	if (more < 0)
+		goto error;
+	if (!more) {
+		tree = isl_schedule_tree_from_extension(extension);
+	} else {
+		key = get_key(s);
+		if (key != isl_schedule_key_child)
+			isl_die(ctx, isl_error_invalid, "expecting child",
+				goto error);
+		if (isl_stream_yaml_next(s) < 0)
+			goto error;
+		tree = isl_stream_read_schedule_tree(s);
+		tree = isl_schedule_tree_insert_extension(tree, extension);
+	}
+
+	return tree;
+error:
+	isl_union_map_free(extension);
+	return NULL;
+}
+
+/* Read a subtree with filter root node from "s".
+ */
+static __isl_give isl_schedule_tree *read_filter(__isl_keep isl_stream *s)
+{
+	isl_union_set *filter = NULL;
+	isl_schedule_tree *tree;
+	isl_ctx *ctx;
+	struct isl_token *tok;
+	enum isl_schedule_key key;
+	char *str;
+	int more;
+
+	ctx = isl_stream_get_ctx(s);
+
+	key = get_key(s);
+
+	if (isl_stream_yaml_next(s) < 0)
+		return NULL;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	str = isl_token_get_str(ctx, tok);
+	filter = isl_union_set_read_from_str(ctx, str);
+	free(str);
+	isl_token_free(tok);
+
+	more = isl_stream_yaml_next(s);
+	if (more < 0)
+		goto error;
+	if (!more) {
+		tree = isl_schedule_tree_from_filter(filter);
+	} else {
+		key = get_key(s);
+		if (key != isl_schedule_key_child)
+			isl_die(ctx, isl_error_invalid, "expecting child",
+				goto error);
+		if (isl_stream_yaml_next(s) < 0)
+			goto error;
+		tree = isl_stream_read_schedule_tree(s);
+		tree = isl_schedule_tree_insert_filter(tree, filter);
+	}
+
+	return tree;
+error:
+	isl_union_set_free(filter);
+	return NULL;
+}
+
+/* Read a subtree with guard root node from "s".
+ */
+static __isl_give isl_schedule_tree *read_guard(isl_stream *s)
+{
+	isl_set *guard = NULL;
+	isl_schedule_tree *tree;
+	isl_ctx *ctx;
+	struct isl_token *tok;
+	enum isl_schedule_key key;
+	char *str;
+	int more;
+
+	ctx = isl_stream_get_ctx(s);
+
+	key = get_key(s);
+
+	if (isl_stream_yaml_next(s) < 0)
+		return NULL;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	str = isl_token_get_str(ctx, tok);
+	guard = isl_set_read_from_str(ctx, str);
+	free(str);
+	isl_token_free(tok);
+
+	more = isl_stream_yaml_next(s);
+	if (more < 0)
+		goto error;
+	if (!more) {
+		tree = isl_schedule_tree_from_guard(guard);
+	} else {
+		key = get_key(s);
+		if (key != isl_schedule_key_child)
+			isl_die(ctx, isl_error_invalid, "expecting child",
+				goto error);
+		if (isl_stream_yaml_next(s) < 0)
+			goto error;
+		tree = isl_stream_read_schedule_tree(s);
+		tree = isl_schedule_tree_insert_guard(tree, guard);
+	}
+
+	return tree;
+error:
+	isl_set_free(guard);
+	return NULL;
+}
+
+/* Read a subtree with mark root node from "s".
+ */
+static __isl_give isl_schedule_tree *read_mark(isl_stream *s)
+{
+	isl_id *mark;
+	isl_schedule_tree *tree;
+	isl_ctx *ctx;
+	struct isl_token *tok;
+	enum isl_schedule_key key;
+	char *str;
+	int more;
+
+	ctx = isl_stream_get_ctx(s);
+
+	key = get_key(s);
+
+	if (isl_stream_yaml_next(s) < 0)
+		return NULL;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		isl_stream_error(s, NULL, "unexpected EOF");
+		return NULL;
+	}
+	str = isl_token_get_str(ctx, tok);
+	mark = isl_id_alloc(ctx, str, NULL);
+	free(str);
+	isl_token_free(tok);
+
+	more = isl_stream_yaml_next(s);
+	if (more < 0)
+		goto error;
+	if (!more) {
+		isl_die(ctx, isl_error_invalid, "expecting child",
+			goto error);
+	} else {
+		key = get_key(s);
+		if (key != isl_schedule_key_child)
+			isl_die(ctx, isl_error_invalid, "expecting child",
+				goto error);
+		if (isl_stream_yaml_next(s) < 0)
+			goto error;
+		tree = isl_stream_read_schedule_tree(s);
+		tree = isl_schedule_tree_insert_mark(tree, mark);
+	}
+
+	return tree;
+error:
+	isl_id_free(mark);
+	return NULL;
+}
+
+/* Read a sequence of integers from "s" (representing the coincident
+ * property of a band node).
+ */
+static __isl_give isl_val_list *read_coincident(__isl_keep isl_stream *s)
+{
+	isl_ctx *ctx;
+	isl_val_list *list;
+	int more;
+
+	ctx = isl_stream_get_ctx(s);
+
+	if (isl_stream_yaml_read_start_sequence(s) < 0)
+		return NULL;
+
+	list = isl_val_list_alloc(ctx, 0);
+	while  ((more = isl_stream_yaml_next(s)) > 0) {
+		isl_val *val;
+
+		val = isl_stream_read_val(s);
+		list = isl_val_list_add(list, val);
+	}
+
+	if (more < 0 || isl_stream_yaml_read_end_sequence(s))
+		list = isl_val_list_free(list);
+
+	return list;
+}
+
+/* Set the (initial) coincident properties of "band" according to
+ * the (initial) elements of "coincident".
+ */
+static __isl_give isl_schedule_band *set_coincident(
+	__isl_take isl_schedule_band *band, __isl_take isl_val_list *coincident)
+{
+	int i;
+	int n, m;
+
+	n = isl_schedule_band_n_member(band);
+	m = isl_val_list_n_val(coincident);
+
+	for (i = 0; i < n && i < m; ++i) {
+		isl_val *v;
+
+		v = isl_val_list_get_val(coincident, i);
+		if (!v)
+			band = isl_schedule_band_free(band);
+		band = isl_schedule_band_member_set_coincident(band, i,
+							!isl_val_is_zero(v));
+		isl_val_free(v);
+	}
+	isl_val_list_free(coincident);
+	return band;
+}
+
+/* Read a subtree with band root node from "s".
+ */
+static __isl_give isl_schedule_tree *read_band(isl_stream *s)
+{
+	isl_multi_union_pw_aff *schedule = NULL;
+	isl_schedule_tree *tree = NULL;
+	isl_val_list *coincident = NULL;
+	isl_union_set *options = NULL;
+	isl_ctx *ctx;
+	isl_schedule_band *band;
+	int permutable = 0;
+	int more;
+
+	ctx = isl_stream_get_ctx(s);
+
+	do {
+		struct isl_token *tok;
+		enum isl_schedule_key key;
+		char *str;
+		isl_val *v;
+
+		key = get_key(s);
+		if (isl_stream_yaml_next(s) < 0)
+			goto error;
+
+		switch (key) {
+		case isl_schedule_key_schedule:
+			schedule = isl_multi_union_pw_aff_free(schedule);
+			tok = isl_stream_next_token(s);
+			if (!tok) {
+				isl_stream_error(s, NULL, "unexpected EOF");
+				goto error;
+			}
+			str = isl_token_get_str(ctx, tok);
+			schedule = isl_multi_union_pw_aff_read_from_str(ctx,
+									str);
+			free(str);
+			isl_token_free(tok);
+			if (!schedule)
+				goto error;
+			break;
+		case isl_schedule_key_coincident:
+			coincident = read_coincident(s);
+			if (!coincident)
+				goto error;
+			break;
+		case isl_schedule_key_permutable:
+			v = isl_stream_read_val(s);
+			permutable = !isl_val_is_zero(v);
+			isl_val_free(v);
+			break;
+		case isl_schedule_key_options:
+			isl_union_set_free(options);
+			tok = isl_stream_next_token(s);
+			str = isl_token_get_str(ctx, tok);
+			options = isl_union_set_read_from_str(ctx, str);
+			free(str);
+			isl_token_free(tok);
+			if (!options)
+				goto error;
+			break;
+		case isl_schedule_key_child:
+			isl_schedule_tree_free(tree);
+			tree = isl_stream_read_schedule_tree(s);
+			if (!tree)
+				goto error;
+			break;
+		default:
+			isl_die(ctx, isl_error_invalid, "unexpected key",
+				goto error);
+		}
+	} while ((more = isl_stream_yaml_next(s)) > 0);
+
+	if (more < 0)
+		goto error;
+
+	if (!schedule)
+		isl_die(ctx, isl_error_invalid, "missing schedule", goto error);
+
+	band = isl_schedule_band_from_multi_union_pw_aff(schedule);
+	band = isl_schedule_band_set_permutable(band, permutable);
+	if (coincident)
+		band = set_coincident(band, coincident);
+	if (options)
+		band = isl_schedule_band_set_ast_build_options(band, options);
+	if (tree)
+		tree = isl_schedule_tree_insert_band(tree, band);
+	else
+		tree = isl_schedule_tree_from_band(band);
+
+	return tree;
+error:
+	isl_val_list_free(coincident);
+	isl_union_set_free(options);
+	isl_schedule_tree_free(tree);
+	isl_multi_union_pw_aff_free(schedule);
+	return NULL;
+}
+
+/* Read a subtree with root node of type "type" from "s".
+ * The node is represented by a sequence of children.
+ */
+static __isl_give isl_schedule_tree *read_children(isl_stream *s,
+	enum isl_schedule_node_type type)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree_list *list;
+	int more;
+
+	ctx = isl_stream_get_ctx(s);
+
+	isl_token_free(isl_stream_next_token(s));
+
+	if (isl_stream_yaml_next(s) < 0)
+		return NULL;
+
+	if (isl_stream_yaml_read_start_sequence(s))
+		return NULL;
+
+	list = isl_schedule_tree_list_alloc(ctx, 0);
+	while ((more = isl_stream_yaml_next(s)) > 0) {
+		isl_schedule_tree *tree;
+
+		tree = isl_stream_read_schedule_tree(s);
+		list = isl_schedule_tree_list_add(list, tree);
+	}
+
+	if (more < 0 || isl_stream_yaml_read_end_sequence(s))
+		list = isl_schedule_tree_list_free(list);
+
+	return isl_schedule_tree_from_children(type, list);
+}
+
+/* Read a subtree with sequence root node from "s".
+ */
+static __isl_give isl_schedule_tree *read_sequence(isl_stream *s)
+{
+	return read_children(s, isl_schedule_node_sequence);
+}
+
+/* Read a subtree with set root node from "s".
+ */
+static __isl_give isl_schedule_tree *read_set(isl_stream *s)
+{
+	return read_children(s, isl_schedule_node_set);
+}
+
+/* Read a schedule (sub)tree from "s".
+ *
+ * We first determine the type of the root node based on the first
+ * mapping key and then hand over to a function tailored to reading
+ * nodes of this type.
+ */
+static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree(
+	struct isl_stream *s)
+{
+	enum isl_schedule_key key;
+	struct isl_token *tok;
+	isl_schedule_tree *tree = NULL;
+	int more;
+
+	if (isl_stream_yaml_read_start_mapping(s))
+		return NULL;
+	more = isl_stream_yaml_next(s);
+	if (more < 0)
+		return NULL;
+	if (!more) {
+		isl_stream_error(s, NULL, "missing key");
+		return NULL;
+	}
+
+	tok = isl_stream_next_token(s);
+	key = extract_key(s, tok);
+	isl_stream_push_token(s, tok);
+	if (key < 0)
+		return NULL;
+	switch (key) {
+	case isl_schedule_key_context:
+		tree = read_context(s);
+		break;
+	case isl_schedule_key_domain:
+		tree = read_domain(s);
+		break;
+	case isl_schedule_key_contraction:
+	case isl_schedule_key_expansion:
+		tree = read_expansion(s);
+		break;
+	case isl_schedule_key_extension:
+		tree = read_extension(s);
+		break;
+	case isl_schedule_key_filter:
+		tree = read_filter(s);
+		break;
+	case isl_schedule_key_guard:
+		tree = read_guard(s);
+		break;
+	case isl_schedule_key_leaf:
+		isl_token_free(isl_stream_next_token(s));
+		tree = isl_schedule_tree_leaf(isl_stream_get_ctx(s));
+		break;
+	case isl_schedule_key_mark:
+		tree = read_mark(s);
+		break;
+	case isl_schedule_key_sequence:
+		tree = read_sequence(s);
+		break;
+	case isl_schedule_key_set:
+		tree = read_set(s);
+		break;
+	case isl_schedule_key_schedule:
+	case isl_schedule_key_coincident:
+	case isl_schedule_key_options:
+	case isl_schedule_key_permutable:
+		tree = read_band(s);
+		break;
+	case isl_schedule_key_child:
+		isl_die(isl_stream_get_ctx(s), isl_error_unsupported,
+			"cannot identity node type", return NULL);
+	case isl_schedule_key_end:
+	case isl_schedule_key_error:
+		return NULL;
+	}
+
+	if (isl_stream_yaml_read_end_mapping(s) < 0) {
+		isl_stream_error(s, NULL, "unexpected extra elements");
+		return isl_schedule_tree_free(tree);
+	}
+
+	return tree;
+}
+
+/* Read an isl_schedule from "s".
+ */
+__isl_give isl_schedule *isl_stream_read_schedule(isl_stream *s)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+
+	if (!s)
+		return NULL;
+
+	ctx = isl_stream_get_ctx(s);
+	tree = isl_stream_read_schedule_tree(s);
+	return isl_schedule_from_schedule_tree(ctx, tree);
+}
+
+/* Read an isl_schedule from "input".
+ */
+__isl_give isl_schedule *isl_schedule_read_from_file(isl_ctx *ctx, FILE *input)
+{
+	struct isl_stream *s;
+	isl_schedule *schedule;
+
+	s = isl_stream_new_file(ctx, input);
+	if (!s)
+		return NULL;
+	schedule = isl_stream_read_schedule(s);
+	isl_stream_free(s);
+
+	return schedule;
+}
+
+/* Read an isl_schedule from "str".
+ */
+__isl_give isl_schedule *isl_schedule_read_from_str(isl_ctx *ctx,
+	const char *str)
+{
+	struct isl_stream *s;
+	isl_schedule *schedule;
+
+	s = isl_stream_new_str(ctx, str);
+	if (!s)
+		return NULL;
+	schedule = isl_stream_read_schedule(s);
+	isl_stream_free(s);
+
+	return schedule;
+}
diff --git a/final/lib/External/isl/isl_schedule_tree.c b/final/lib/External/isl/isl_schedule_tree.c
new file mode 100644
index 0000000..6dbadfc
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_tree.c
@@ -0,0 +1,2856 @@
+/*
+ * Copyright 2013-2014 Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ * Copyright 2016      INRIA Paris
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12,
+ * CS 42112, 75589 Paris Cedex 12, France
+ */
+
+#include <isl/map.h>
+#include <isl_schedule_band.h>
+#include <isl_schedule_private.h>
+
+#undef EL
+#define EL isl_schedule_tree
+
+#include <isl_list_templ.h>
+
+#undef BASE
+#define BASE schedule_tree
+
+#include <isl_list_templ.c>
+
+/* Is "tree" the leaf of a schedule tree?
+ */
+int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree)
+{
+	return isl_schedule_tree_get_type(tree) == isl_schedule_node_leaf;
+}
+
+/* Create a new schedule tree of type "type".
+ * The caller is responsible for filling in the type specific fields and
+ * the children.
+ *
+ * By default, the single node tree does not have any anchored nodes.
+ * The caller is responsible for updating the anchored field if needed.
+ */
+static __isl_give isl_schedule_tree *isl_schedule_tree_alloc(isl_ctx *ctx,
+	enum isl_schedule_node_type type)
+{
+	isl_schedule_tree *tree;
+
+	if (type == isl_schedule_node_error)
+		return NULL;
+
+	tree = isl_calloc_type(ctx, isl_schedule_tree);
+	if (!tree)
+		return NULL;
+
+	tree->ref = 1;
+	tree->ctx = ctx;
+	isl_ctx_ref(ctx);
+	tree->type = type;
+	tree->anchored = 0;
+
+	return tree;
+}
+
+/* Return a fresh copy of "tree".
+ */
+__isl_take isl_schedule_tree *isl_schedule_tree_dup(
+	__isl_keep isl_schedule_tree *tree)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *dup;
+
+	if (!tree)
+		return NULL;
+
+	ctx = isl_schedule_tree_get_ctx(tree);
+	dup = isl_schedule_tree_alloc(ctx, tree->type);
+	if (!dup)
+		return NULL;
+
+	switch (tree->type) {
+	case isl_schedule_node_error:
+		isl_die(ctx, isl_error_internal,
+			"allocation should have failed",
+			return isl_schedule_tree_free(dup));
+	case isl_schedule_node_band:
+		dup->band = isl_schedule_band_copy(tree->band);
+		if (!dup->band)
+			return isl_schedule_tree_free(dup);
+		break;
+	case isl_schedule_node_context:
+		dup->context = isl_set_copy(tree->context);
+		if (!dup->context)
+			return isl_schedule_tree_free(dup);
+		break;
+	case isl_schedule_node_domain:
+		dup->domain = isl_union_set_copy(tree->domain);
+		if (!dup->domain)
+			return isl_schedule_tree_free(dup);
+		break;
+	case isl_schedule_node_expansion:
+		dup->contraction =
+			isl_union_pw_multi_aff_copy(tree->contraction);
+		dup->expansion = isl_union_map_copy(tree->expansion);
+		if (!dup->contraction || !dup->expansion)
+			return isl_schedule_tree_free(dup);
+		break;
+	case isl_schedule_node_extension:
+		dup->extension = isl_union_map_copy(tree->extension);
+		if (!dup->extension)
+			return isl_schedule_tree_free(dup);
+		break;
+	case isl_schedule_node_filter:
+		dup->filter = isl_union_set_copy(tree->filter);
+		if (!dup->filter)
+			return isl_schedule_tree_free(dup);
+		break;
+	case isl_schedule_node_guard:
+		dup->guard = isl_set_copy(tree->guard);
+		if (!dup->guard)
+			return isl_schedule_tree_free(dup);
+		break;
+	case isl_schedule_node_mark:
+		dup->mark = isl_id_copy(tree->mark);
+		if (!dup->mark)
+			return isl_schedule_tree_free(dup);
+		break;
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		break;
+	}
+
+	if (tree->children) {
+		dup->children = isl_schedule_tree_list_copy(tree->children);
+		if (!dup->children)
+			return isl_schedule_tree_free(dup);
+	}
+	dup->anchored = tree->anchored;
+
+	return dup;
+}
+
+/* Return an isl_schedule_tree that is equal to "tree" and that has only
+ * a single reference.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_cow(
+	__isl_take isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->ref == 1)
+		return tree;
+	tree->ref--;
+	return isl_schedule_tree_dup(tree);
+}
+
+/* Return a new reference to "tree".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_copy(
+	__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	tree->ref++;
+	return tree;
+}
+
+/* Free "tree" and return NULL.
+ */
+__isl_null isl_schedule_tree *isl_schedule_tree_free(
+	__isl_take isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+	if (--tree->ref > 0)
+		return NULL;
+
+	switch (tree->type) {
+	case isl_schedule_node_band:
+		isl_schedule_band_free(tree->band);
+		break;
+	case isl_schedule_node_context:
+		isl_set_free(tree->context);
+		break;
+	case isl_schedule_node_domain:
+		isl_union_set_free(tree->domain);
+		break;
+	case isl_schedule_node_expansion:
+		isl_union_pw_multi_aff_free(tree->contraction);
+		isl_union_map_free(tree->expansion);
+		break;
+	case isl_schedule_node_extension:
+		isl_union_map_free(tree->extension);
+		break;
+	case isl_schedule_node_filter:
+		isl_union_set_free(tree->filter);
+		break;
+	case isl_schedule_node_guard:
+		isl_set_free(tree->guard);
+		break;
+	case isl_schedule_node_mark:
+		isl_id_free(tree->mark);
+		break;
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+	case isl_schedule_node_error:
+	case isl_schedule_node_leaf:
+		break;
+	}
+	isl_schedule_tree_list_free(tree->children);
+	isl_ctx_deref(tree->ctx);
+	free(tree);
+
+	return NULL;
+}
+
+/* Create and return a new leaf schedule tree.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx)
+{
+	return isl_schedule_tree_alloc(ctx, isl_schedule_node_leaf);
+}
+
+/* Create a new band schedule tree referring to "band"
+ * with no children.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_from_band(
+	__isl_take isl_schedule_band *band)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+
+	if (!band)
+		return NULL;
+
+	ctx = isl_schedule_band_get_ctx(band);
+	tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_band);
+	if (!tree)
+		goto error;
+
+	tree->band = band;
+	tree->anchored = isl_schedule_band_is_anchored(band);
+
+	return tree;
+error:
+	isl_schedule_band_free(band);
+	return NULL;
+}
+
+/* Create a new context schedule tree with the given context and no children.
+ * Since the context references the outer schedule dimension,
+ * the tree is anchored.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_from_context(
+	__isl_take isl_set *context)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+
+	if (!context)
+		return NULL;
+
+	ctx = isl_set_get_ctx(context);
+	tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_context);
+	if (!tree)
+		goto error;
+
+	tree->context = context;
+	tree->anchored = 1;
+
+	return tree;
+error:
+	isl_set_free(context);
+	return NULL;
+}
+
+/* Create a new domain schedule tree with the given domain and no children.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_from_domain(
+	__isl_take isl_union_set *domain)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+
+	if (!domain)
+		return NULL;
+
+	ctx = isl_union_set_get_ctx(domain);
+	tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_domain);
+	if (!tree)
+		goto error;
+
+	tree->domain = domain;
+
+	return tree;
+error:
+	isl_union_set_free(domain);
+	return NULL;
+}
+
+/* Create a new expansion schedule tree with the given contraction and
+ * expansion and no children.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_from_expansion(
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_union_map *expansion)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+
+	if (!contraction || !expansion)
+		goto error;
+
+	ctx = isl_union_map_get_ctx(expansion);
+	tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_expansion);
+	if (!tree)
+		goto error;
+
+	tree->contraction = contraction;
+	tree->expansion = expansion;
+
+	return tree;
+error:
+	isl_union_pw_multi_aff_free(contraction);
+	isl_union_map_free(expansion);
+	return NULL;
+}
+
+/* Create a new extension schedule tree with the given extension and
+ * no children.
+ * Since the domain of the extension refers to the outer schedule dimension,
+ * the tree is anchored.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_from_extension(
+	__isl_take isl_union_map *extension)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+
+	if (!extension)
+		return NULL;
+
+	ctx = isl_union_map_get_ctx(extension);
+	tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_extension);
+	if (!tree)
+		goto error;
+
+	tree->extension = extension;
+	tree->anchored = 1;
+
+	return tree;
+error:
+	isl_union_map_free(extension);
+	return NULL;
+}
+
+/* Create a new filter schedule tree with the given filter and no children.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_from_filter(
+	__isl_take isl_union_set *filter)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+
+	if (!filter)
+		return NULL;
+
+	ctx = isl_union_set_get_ctx(filter);
+	tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_filter);
+	if (!tree)
+		goto error;
+
+	tree->filter = filter;
+
+	return tree;
+error:
+	isl_union_set_free(filter);
+	return NULL;
+}
+
+/* Create a new guard schedule tree with the given guard and no children.
+ * Since the guard references the outer schedule dimension,
+ * the tree is anchored.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_from_guard(
+	__isl_take isl_set *guard)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+
+	if (!guard)
+		return NULL;
+
+	ctx = isl_set_get_ctx(guard);
+	tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_guard);
+	if (!tree)
+		goto error;
+
+	tree->guard = guard;
+	tree->anchored = 1;
+
+	return tree;
+error:
+	isl_set_free(guard);
+	return NULL;
+}
+
+/* Create a new mark schedule tree with the given mark identifier and
+ * no children.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_from_mark(
+	__isl_take isl_id *mark)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+
+	if (!mark)
+		return NULL;
+
+	ctx = isl_id_get_ctx(mark);
+	tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_mark);
+	if (!tree)
+		goto error;
+
+	tree->mark = mark;
+
+	return tree;
+error:
+	isl_id_free(mark);
+	return NULL;
+}
+
+/* Does "tree" have any node that depends on its position
+ * in the complete schedule tree?
+ */
+isl_bool isl_schedule_tree_is_subtree_anchored(
+	__isl_keep isl_schedule_tree *tree)
+{
+	return tree ? tree->anchored : isl_bool_error;
+}
+
+/* Does the root node of "tree" depend on its position in the complete
+ * schedule tree?
+ * Band nodes may be anchored depending on the associated AST build options.
+ * Context, extension and guard nodes are always anchored.
+ */
+int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return -1;
+
+	switch (isl_schedule_tree_get_type(tree)) {
+	case isl_schedule_node_error:
+		return -1;
+	case isl_schedule_node_band:
+		return isl_schedule_band_is_anchored(tree->band);
+	case isl_schedule_node_context:
+	case isl_schedule_node_extension:
+	case isl_schedule_node_guard:
+		return 1;
+	case isl_schedule_node_domain:
+	case isl_schedule_node_expansion:
+	case isl_schedule_node_filter:
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_mark:
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		return 0;
+	}
+
+	isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+		"unhandled case", return -1);
+}
+
+/* Update the anchored field of "tree" based on whether the root node
+ * itself in anchored and the anchored fields of the children.
+ *
+ * This function should be called whenever the children of a tree node
+ * are changed or the anchoredness of the tree root itself changes.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_update_anchored(
+	__isl_take isl_schedule_tree *tree)
+{
+	int i, n;
+	int anchored;
+
+	if (!tree)
+		return NULL;
+
+	anchored = isl_schedule_tree_is_anchored(tree);
+	if (anchored < 0)
+		return isl_schedule_tree_free(tree);
+
+	n = isl_schedule_tree_list_n_schedule_tree(tree->children);
+	for (i = 0; !anchored && i < n; ++i) {
+		isl_schedule_tree *child;
+
+		child = isl_schedule_tree_get_child(tree, i);
+		if (!child)
+			return isl_schedule_tree_free(tree);
+		anchored = child->anchored;
+		isl_schedule_tree_free(child);
+	}
+
+	if (anchored == tree->anchored)
+		return tree;
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		return NULL;
+	tree->anchored = anchored;
+	return tree;
+}
+
+/* Create a new tree of the given type (isl_schedule_node_sequence or
+ * isl_schedule_node_set) with the given children.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_from_children(
+	enum isl_schedule_node_type type,
+	__isl_take isl_schedule_tree_list *list)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree *tree;
+
+	if (!list)
+		return NULL;
+
+	ctx = isl_schedule_tree_list_get_ctx(list);
+	tree = isl_schedule_tree_alloc(ctx, type);
+	if (!tree)
+		goto error;
+
+	tree->children = list;
+	tree = isl_schedule_tree_update_anchored(tree);
+
+	return tree;
+error:
+	isl_schedule_tree_list_free(list);
+	return NULL;
+}
+
+/* Construct a tree with a root node of type "type" and as children
+ * "tree1" and "tree2".
+ * If the root of one (or both) of the input trees is itself of type "type",
+ * then the tree is replaced by its children.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_from_pair(
+	enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1,
+	__isl_take isl_schedule_tree *tree2)
+{
+	isl_ctx *ctx;
+	isl_schedule_tree_list *list;
+
+	if (!tree1 || !tree2)
+		goto error;
+
+	ctx = isl_schedule_tree_get_ctx(tree1);
+	if (isl_schedule_tree_get_type(tree1) == type) {
+		list = isl_schedule_tree_list_copy(tree1->children);
+		isl_schedule_tree_free(tree1);
+	} else {
+		list = isl_schedule_tree_list_alloc(ctx, 2);
+		list = isl_schedule_tree_list_add(list, tree1);
+	}
+	if (isl_schedule_tree_get_type(tree2) == type) {
+		isl_schedule_tree_list *children;
+
+		children = isl_schedule_tree_list_copy(tree2->children);
+		list = isl_schedule_tree_list_concat(list, children);
+		isl_schedule_tree_free(tree2);
+	} else {
+		list = isl_schedule_tree_list_add(list, tree2);
+	}
+
+	return isl_schedule_tree_from_children(type, list);
+error:
+	isl_schedule_tree_free(tree1);
+	isl_schedule_tree_free(tree2);
+	return NULL;
+}
+
+/* Construct a tree with a sequence root node and as children
+ * "tree1" and "tree2".
+ * If the root of one (or both) of the input trees is itself a sequence,
+ * then the tree is replaced by its children.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_sequence_pair(
+	__isl_take isl_schedule_tree *tree1,
+	__isl_take isl_schedule_tree *tree2)
+{
+	return isl_schedule_tree_from_pair(isl_schedule_node_sequence,
+						tree1, tree2);
+}
+
+/* Construct a tree with a set root node and as children
+ * "tree1" and "tree2".
+ * If the root of one (or both) of the input trees is itself a set,
+ * then the tree is replaced by its children.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_set_pair(
+	__isl_take isl_schedule_tree *tree1,
+	__isl_take isl_schedule_tree *tree2)
+{
+	return isl_schedule_tree_from_pair(isl_schedule_node_set, tree1, tree2);
+}
+
+/* Return the isl_ctx to which "tree" belongs.
+ */
+isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree)
+{
+	return tree ? tree->ctx : NULL;
+}
+
+/* Return the type of the root of the tree or isl_schedule_node_error
+ * on error.
+ */
+enum isl_schedule_node_type isl_schedule_tree_get_type(
+	__isl_keep isl_schedule_tree *tree)
+{
+	return tree ? tree->type : isl_schedule_node_error;
+}
+
+/* Are "tree1" and "tree2" obviously equal to each other?
+ */
+isl_bool isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
+	__isl_keep isl_schedule_tree *tree2)
+{
+	isl_bool equal;
+	int i, n;
+
+	if (!tree1 || !tree2)
+		return isl_bool_error;
+	if (tree1 == tree2)
+		return isl_bool_true;
+	if (tree1->type != tree2->type)
+		return isl_bool_false;
+
+	switch (tree1->type) {
+	case isl_schedule_node_band:
+		equal = isl_schedule_band_plain_is_equal(tree1->band,
+							tree2->band);
+		break;
+	case isl_schedule_node_context:
+		equal = isl_set_is_equal(tree1->context, tree2->context);
+		break;
+	case isl_schedule_node_domain:
+		equal = isl_union_set_is_equal(tree1->domain, tree2->domain);
+		break;
+	case isl_schedule_node_expansion:
+		equal = isl_union_map_is_equal(tree1->expansion,
+						tree2->expansion);
+		if (equal >= 0 && equal)
+			equal = isl_union_pw_multi_aff_plain_is_equal(
+				    tree1->contraction, tree2->contraction);
+		break;
+	case isl_schedule_node_extension:
+		equal = isl_union_map_is_equal(tree1->extension,
+						tree2->extension);
+		break;
+	case isl_schedule_node_filter:
+		equal = isl_union_set_is_equal(tree1->filter, tree2->filter);
+		break;
+	case isl_schedule_node_guard:
+		equal = isl_set_is_equal(tree1->guard, tree2->guard);
+		break;
+	case isl_schedule_node_mark:
+		equal = tree1->mark == tree2->mark;
+		break;
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		equal = isl_bool_true;
+		break;
+	case isl_schedule_node_error:
+		equal = isl_bool_error;
+		break;
+	}
+
+	if (equal < 0 || !equal)
+		return equal;
+
+	n = isl_schedule_tree_n_children(tree1);
+	if (n != isl_schedule_tree_n_children(tree2))
+		return isl_bool_false;
+	for (i = 0; i < n; ++i) {
+		isl_schedule_tree *child1, *child2;
+
+		child1 = isl_schedule_tree_get_child(tree1, i);
+		child2 = isl_schedule_tree_get_child(tree2, i);
+		equal = isl_schedule_tree_plain_is_equal(child1, child2);
+		isl_schedule_tree_free(child1);
+		isl_schedule_tree_free(child2);
+
+		if (equal < 0 || !equal)
+			return equal;
+	}
+
+	return isl_bool_true;
+}
+
+/* Does "tree" have any children, other than an implicit leaf.
+ */
+int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return -1;
+
+	return tree->children != NULL;
+}
+
+/* Return the number of children of "tree", excluding implicit leaves.
+ */
+int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return -1;
+
+	return isl_schedule_tree_list_n_schedule_tree(tree->children);
+}
+
+/* Return a copy of the (explicit) child at position "pos" of "tree".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_get_child(
+	__isl_keep isl_schedule_tree *tree, int pos)
+{
+	if (!tree)
+		return NULL;
+	if (!tree->children)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"schedule tree has no explicit children", return NULL);
+	return isl_schedule_tree_list_get_schedule_tree(tree->children, pos);
+}
+
+/* Return a copy of the (explicit) child at position "pos" of "tree" and
+ * free "tree".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_child(
+	__isl_take isl_schedule_tree *tree, int pos)
+{
+	isl_schedule_tree *child;
+
+	child = isl_schedule_tree_get_child(tree, pos);
+	isl_schedule_tree_free(tree);
+	return child;
+}
+
+/* Remove all (explicit) children from "tree".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_reset_children(
+	__isl_take isl_schedule_tree *tree)
+{
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		return NULL;
+	tree->children = isl_schedule_tree_list_free(tree->children);
+	return tree;
+}
+
+/* Remove the child at position "pos" from the children of "tree".
+ * If there was only one child to begin with, then remove all children.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_drop_child(
+	__isl_take isl_schedule_tree *tree, int pos)
+{
+	int n;
+
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		return NULL;
+
+	if (!isl_schedule_tree_has_children(tree))
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"tree does not have any explicit children",
+			return isl_schedule_tree_free(tree));
+	n = isl_schedule_tree_list_n_schedule_tree(tree->children);
+	if (pos < 0 || pos >= n)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"position out of bounds",
+			return isl_schedule_tree_free(tree));
+	if (n == 1)
+		return isl_schedule_tree_reset_children(tree);
+
+	tree->children = isl_schedule_tree_list_drop(tree->children, pos, 1);
+	if (!tree->children)
+		return isl_schedule_tree_free(tree);
+
+	return tree;
+}
+
+/* Replace the child at position "pos" of "tree" by "child".
+ *
+ * If the new child is a leaf, then it is not explicitly
+ * recorded in the list of children.  Instead, the list of children
+ * (which is assumed to have only one element) is removed.
+ * Note that the children of set and sequence nodes are always
+ * filters, so they cannot be replaced by empty trees.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_replace_child(
+	__isl_take isl_schedule_tree *tree, int pos,
+	__isl_take isl_schedule_tree *child)
+{
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree || !child)
+		goto error;
+
+	if (isl_schedule_tree_is_leaf(child)) {
+		isl_schedule_tree_free(child);
+		if (!tree->children && pos == 0)
+			return tree;
+		if (isl_schedule_tree_n_children(tree) != 1)
+			isl_die(isl_schedule_tree_get_ctx(tree),
+				isl_error_internal,
+				"can only replace single child by leaf",
+				goto error);
+		return isl_schedule_tree_reset_children(tree);
+	}
+
+	if (!tree->children && pos == 0)
+		tree->children =
+			isl_schedule_tree_list_from_schedule_tree(child);
+	else
+		tree->children = isl_schedule_tree_list_set_schedule_tree(
+				tree->children, pos, child);
+
+	if (!tree->children)
+		return isl_schedule_tree_free(tree);
+	tree = isl_schedule_tree_update_anchored(tree);
+
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_schedule_tree_free(child);
+	return NULL;
+}
+
+/* Replace the (explicit) children of "tree" by "children"?
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_set_children(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_schedule_tree_list *children)
+{
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree || !children)
+		goto error;
+	isl_schedule_tree_list_free(tree->children);
+	tree->children = children;
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_schedule_tree_list_free(children);
+	return NULL;
+}
+
+/* Create a new band schedule tree referring to "band"
+ * with "tree" as single child.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_band(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band)
+{
+	isl_schedule_tree *res;
+
+	res = isl_schedule_tree_from_band(band);
+	return isl_schedule_tree_replace_child(res, 0, tree);
+}
+
+/* Create a new context schedule tree with the given context and
+ * with "tree" as single child.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_context(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_set *context)
+{
+	isl_schedule_tree *res;
+
+	res = isl_schedule_tree_from_context(context);
+	return isl_schedule_tree_replace_child(res, 0, tree);
+}
+
+/* Create a new domain schedule tree with the given domain and
+ * with "tree" as single child.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_domain(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
+{
+	isl_schedule_tree *res;
+
+	res = isl_schedule_tree_from_domain(domain);
+	return isl_schedule_tree_replace_child(res, 0, tree);
+}
+
+/* Create a new expansion schedule tree with the given contraction and
+ * expansion and with "tree" as single child.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_union_map *expansion)
+{
+	isl_schedule_tree *res;
+
+	res = isl_schedule_tree_from_expansion(contraction, expansion);
+	return isl_schedule_tree_replace_child(res, 0, tree);
+}
+
+/* Create a new extension schedule tree with the given extension and
+ * with "tree" as single child.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_extension(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
+{
+	isl_schedule_tree *res;
+
+	res = isl_schedule_tree_from_extension(extension);
+	return isl_schedule_tree_replace_child(res, 0, tree);
+}
+
+/* Create a new filter schedule tree with the given filter and single child.
+ *
+ * If the root of "tree" is itself a filter node, then the two
+ * filter nodes are merged into one node.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_filter(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
+{
+	isl_schedule_tree *res;
+
+	if (isl_schedule_tree_get_type(tree) == isl_schedule_node_filter) {
+		isl_union_set *tree_filter;
+
+		tree_filter = isl_schedule_tree_filter_get_filter(tree);
+		tree_filter = isl_union_set_intersect(tree_filter, filter);
+		tree = isl_schedule_tree_filter_set_filter(tree, tree_filter);
+		return tree;
+	}
+
+	res = isl_schedule_tree_from_filter(filter);
+	return isl_schedule_tree_replace_child(res, 0, tree);
+}
+
+/* Insert a filter node with filter set "filter"
+ * in each of the children of "tree".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
+{
+	int i, n;
+
+	if (!tree || !filter)
+		goto error;
+
+	n = isl_schedule_tree_n_children(tree);
+	for (i = 0; i < n; ++i) {
+		isl_schedule_tree *child;
+
+		child = isl_schedule_tree_get_child(tree, i);
+		child = isl_schedule_tree_insert_filter(child,
+						    isl_union_set_copy(filter));
+		tree = isl_schedule_tree_replace_child(tree, i, child);
+	}
+
+	isl_union_set_free(filter);
+	return tree;
+error:
+	isl_union_set_free(filter);
+	isl_schedule_tree_free(tree);
+	return NULL;
+}
+
+/* Create a new guard schedule tree with the given guard and
+ * with "tree" as single child.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_guard(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_set *guard)
+{
+	isl_schedule_tree *res;
+
+	res = isl_schedule_tree_from_guard(guard);
+	return isl_schedule_tree_replace_child(res, 0, tree);
+}
+
+/* Create a new mark schedule tree with the given mark identifier and
+ * single child.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_mark(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_id *mark)
+{
+	isl_schedule_tree *res;
+
+	res = isl_schedule_tree_from_mark(mark);
+	return isl_schedule_tree_replace_child(res, 0, tree);
+}
+
+/* Return the number of members in the band tree root.
+ */
+unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return 0;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return 0);
+
+	return isl_schedule_band_n_member(tree->band);
+}
+
+/* Is the band member at position "pos" of the band tree root
+ * marked coincident?
+ */
+isl_bool isl_schedule_tree_band_member_get_coincident(
+	__isl_keep isl_schedule_tree *tree, int pos)
+{
+	if (!tree)
+		return isl_bool_error;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return isl_bool_error);
+
+	return isl_schedule_band_member_get_coincident(tree->band, pos);
+}
+
+/* Mark the given band member as being coincident or not
+ * according to "coincident".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident(
+	__isl_take isl_schedule_tree *tree, int pos, int coincident)
+{
+	if (!tree)
+		return NULL;
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return isl_schedule_tree_free(tree));
+	if (isl_schedule_tree_band_member_get_coincident(tree, pos) ==
+								    coincident)
+		return tree;
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		return NULL;
+
+	tree->band = isl_schedule_band_member_set_coincident(tree->band, pos,
+							coincident);
+	if (!tree->band)
+		return isl_schedule_tree_free(tree);
+	return tree;
+}
+
+/* Is the band tree root marked permutable?
+ */
+isl_bool isl_schedule_tree_band_get_permutable(
+	__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return isl_bool_error;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return isl_bool_error);
+
+	return isl_schedule_band_get_permutable(tree->band);
+}
+
+/* Mark the band tree root permutable or not according to "permutable"?
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable(
+	__isl_take isl_schedule_tree *tree, int permutable)
+{
+	if (!tree)
+		return NULL;
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return isl_schedule_tree_free(tree));
+	if (isl_schedule_tree_band_get_permutable(tree) == permutable)
+		return tree;
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		return NULL;
+
+	tree->band = isl_schedule_band_set_permutable(tree->band, permutable);
+	if (!tree->band)
+		return isl_schedule_tree_free(tree);
+	return tree;
+}
+
+/* Return the schedule space of the band tree root.
+ */
+__isl_give isl_space *isl_schedule_tree_band_get_space(
+	__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return NULL);
+
+	return isl_schedule_band_get_space(tree->band);
+}
+
+/* Intersect the domain of the band schedule of the band tree root
+ * with "domain".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
+{
+	if (!tree || !domain)
+		goto error;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", goto error);
+
+	tree->band = isl_schedule_band_intersect_domain(tree->band, domain);
+	if (!tree->band)
+		return isl_schedule_tree_free(tree);
+
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_union_set_free(domain);
+	return NULL;
+}
+
+/* Return the schedule of the band tree root in isolation.
+ */
+__isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule(
+	__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return NULL);
+
+	return isl_schedule_band_get_partial_schedule(tree->band);
+}
+
+/* Replace the schedule of the band tree root by "schedule".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_multi_union_pw_aff *schedule)
+{
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree || !schedule)
+		goto error;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return NULL);
+	tree->band = isl_schedule_band_set_partial_schedule(tree->band,
+								schedule);
+
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_multi_union_pw_aff_free(schedule);
+	return NULL;
+}
+
+/* Return the loop AST generation type for the band member
+ * of the band tree root at position "pos".
+ */
+enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type(
+	__isl_keep isl_schedule_tree *tree, int pos)
+{
+	if (!tree)
+		return isl_ast_loop_error;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return isl_ast_loop_error);
+
+	return isl_schedule_band_member_get_ast_loop_type(tree->band, pos);
+}
+
+/* Set the loop AST generation type for the band member of the band tree root
+ * at position "pos" to "type".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type(
+	__isl_take isl_schedule_tree *tree, int pos,
+	enum isl_ast_loop_type type)
+{
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return isl_schedule_tree_free(tree));
+
+	tree->band = isl_schedule_band_member_set_ast_loop_type(tree->band,
+								pos, type);
+	if (!tree->band)
+		return isl_schedule_tree_free(tree);
+
+	return tree;
+}
+
+/* Return the loop AST generation type for the band member
+ * of the band tree root at position "pos" for the isolated part.
+ */
+enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type(
+	__isl_keep isl_schedule_tree *tree, int pos)
+{
+	if (!tree)
+		return isl_ast_loop_error;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return isl_ast_loop_error);
+
+	return isl_schedule_band_member_get_isolate_ast_loop_type(tree->band,
+									pos);
+}
+
+/* Set the loop AST generation type for the band member of the band tree root
+ * at position "pos" for the isolated part to "type".
+ */
+__isl_give isl_schedule_tree *
+isl_schedule_tree_band_member_set_isolate_ast_loop_type(
+	__isl_take isl_schedule_tree *tree, int pos,
+	enum isl_ast_loop_type type)
+{
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return isl_schedule_tree_free(tree));
+
+	tree->band = isl_schedule_band_member_set_isolate_ast_loop_type(
+							tree->band, pos, type);
+	if (!tree->band)
+		return isl_schedule_tree_free(tree);
+
+	return tree;
+}
+
+/* Return the AST build options associated to the band tree root.
+ */
+__isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options(
+	__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return NULL);
+
+	return isl_schedule_band_get_ast_build_options(tree->band);
+}
+
+/* Replace the AST build options associated to band tree root by "options".
+ * Updated the anchored field if the anchoredness of the root node itself
+ * changes.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options)
+{
+	int was_anchored;
+
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree || !options)
+		goto error;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", goto error);
+
+	was_anchored = isl_schedule_tree_is_anchored(tree);
+	tree->band = isl_schedule_band_set_ast_build_options(tree->band,
+								options);
+	if (!tree->band)
+		return isl_schedule_tree_free(tree);
+	if (isl_schedule_tree_is_anchored(tree) != was_anchored)
+		tree = isl_schedule_tree_update_anchored(tree);
+
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_union_set_free(options);
+	return NULL;
+}
+
+/* Return the "isolate" option associated to the band tree root of "tree",
+ * which is assumed to appear at schedule depth "depth".
+ */
+__isl_give isl_set *isl_schedule_tree_band_get_ast_isolate_option(
+	__isl_keep isl_schedule_tree *tree, int depth)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return NULL);
+
+	return isl_schedule_band_get_ast_isolate_option(tree->band, depth);
+}
+
+/* Return the context of the context tree root.
+ */
+__isl_give isl_set *isl_schedule_tree_context_get_context(
+	__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_context)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a context node", return NULL);
+
+	return isl_set_copy(tree->context);
+}
+
+/* Return the domain of the domain tree root.
+ */
+__isl_give isl_union_set *isl_schedule_tree_domain_get_domain(
+	__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_domain)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a domain node", return NULL);
+
+	return isl_union_set_copy(tree->domain);
+}
+
+/* Replace the domain of domain tree root "tree" by "domain".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
+{
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree || !domain)
+		goto error;
+
+	if (tree->type != isl_schedule_node_domain)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a domain node", goto error);
+
+	isl_union_set_free(tree->domain);
+	tree->domain = domain;
+
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_union_set_free(domain);
+	return NULL;
+}
+
+/* Return the contraction of the expansion tree root.
+ */
+__isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction(
+	__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_expansion)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not an expansion node", return NULL);
+
+	return isl_union_pw_multi_aff_copy(tree->contraction);
+}
+
+/* Return the expansion of the expansion tree root.
+ */
+__isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion(
+	__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_expansion)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not an expansion node", return NULL);
+
+	return isl_union_map_copy(tree->expansion);
+}
+
+/* Replace the contraction and the expansion of the expansion tree root "tree"
+ * by "contraction" and "expansion".
+ */
+__isl_give isl_schedule_tree *
+isl_schedule_tree_expansion_set_contraction_and_expansion(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_union_map *expansion)
+{
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree || !contraction || !expansion)
+		goto error;
+
+	if (tree->type != isl_schedule_node_expansion)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not an expansion node", return NULL);
+
+	isl_union_pw_multi_aff_free(tree->contraction);
+	tree->contraction = contraction;
+	isl_union_map_free(tree->expansion);
+	tree->expansion = expansion;
+
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_union_pw_multi_aff_free(contraction);
+	isl_union_map_free(expansion);
+	return NULL;
+}
+
+/* Return the extension of the extension tree root.
+ */
+__isl_give isl_union_map *isl_schedule_tree_extension_get_extension(
+	__isl_take isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_extension)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not an extension node", return NULL);
+
+	return isl_union_map_copy(tree->extension);
+}
+
+/* Replace the extension of extension tree root "tree" by "extension".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_extension_set_extension(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
+{
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree || !extension)
+		goto error;
+
+	if (tree->type != isl_schedule_node_extension)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not an extension node", return NULL);
+	isl_union_map_free(tree->extension);
+	tree->extension = extension;
+
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_union_map_free(extension);
+	return NULL;
+}
+
+/* Return the filter of the filter tree root.
+ */
+__isl_give isl_union_set *isl_schedule_tree_filter_get_filter(
+	__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_filter)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a filter node", return NULL);
+
+	return isl_union_set_copy(tree->filter);
+}
+
+/* Replace the filter of the filter tree root by "filter".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
+{
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree || !filter)
+		goto error;
+
+	if (tree->type != isl_schedule_node_filter)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a filter node", return NULL);
+
+	isl_union_set_free(tree->filter);
+	tree->filter = filter;
+
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_union_set_free(filter);
+	return NULL;
+}
+
+/* Return the guard of the guard tree root.
+ */
+__isl_give isl_set *isl_schedule_tree_guard_get_guard(
+	__isl_take isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_guard)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a guard node", return NULL);
+
+	return isl_set_copy(tree->guard);
+}
+
+/* Return the mark identifier of the mark tree root "tree".
+ */
+__isl_give isl_id *isl_schedule_tree_mark_get_id(
+	__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->type != isl_schedule_node_mark)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a mark node", return NULL);
+
+	return isl_id_copy(tree->mark);
+}
+
+/* Set dim to the range dimension of "map" and abort the search.
+ */
+static isl_stat set_range_dim(__isl_take isl_map *map, void *user)
+{
+	int *dim = user;
+
+	*dim = isl_map_dim(map, isl_dim_out);
+	isl_map_free(map);
+
+	return isl_stat_error;
+}
+
+/* Return the dimension of the range of "umap".
+ * "umap" is assumed not to be empty and
+ * all maps inside "umap" are assumed to have the same range.
+ *
+ * We extract the range dimension from the first map in "umap".
+ */
+static int range_dim(__isl_keep isl_union_map *umap)
+{
+	int dim = -1;
+
+	if (!umap)
+		return -1;
+	if (isl_union_map_n_map(umap) == 0)
+		isl_die(isl_union_map_get_ctx(umap), isl_error_internal,
+			"unexpected empty input", return -1);
+
+	isl_union_map_foreach_map(umap, &set_range_dim, &dim);
+
+	return dim;
+}
+
+/* Append an "extra" number of zeros to the range of "umap" and
+ * return the result.
+ */
+static __isl_give isl_union_map *append_range(__isl_take isl_union_map *umap,
+	int extra)
+{
+	isl_union_set *dom;
+	isl_space *space;
+	isl_multi_val *mv;
+	isl_union_pw_multi_aff *suffix;
+	isl_union_map *universe;
+	isl_union_map *suffix_umap;
+
+	universe = isl_union_map_universe(isl_union_map_copy(umap));
+	dom = isl_union_map_domain(universe);
+	space = isl_union_set_get_space(dom);
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, extra);
+	mv = isl_multi_val_zero(space);
+
+	suffix = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv);
+	suffix_umap = isl_union_map_from_union_pw_multi_aff(suffix);
+	umap = isl_union_map_flat_range_product(umap, suffix_umap);
+
+	return umap;
+}
+
+/* Should we skip the root of "tree" while looking for the first
+ * descendant with schedule information?
+ * That is, is it impossible to derive any information about
+ * the iteration domain from this node?
+ *
+ * We do not want to skip leaf or error nodes because there is
+ * no point in looking any deeper from these nodes.
+ * We can only extract partial iteration domain information
+ * from an extension node, but extension nodes are not supported
+ * by the caller and it will error out on them.
+ */
+static int domain_less(__isl_keep isl_schedule_tree *tree)
+{
+	enum isl_schedule_node_type type;
+
+	type = isl_schedule_tree_get_type(tree);
+	switch (type) {
+	case isl_schedule_node_band:
+		return isl_schedule_tree_band_n_member(tree) == 0;
+	case isl_schedule_node_context:
+	case isl_schedule_node_guard:
+	case isl_schedule_node_mark:
+		return 1;
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_error:
+	case isl_schedule_node_domain:
+	case isl_schedule_node_expansion:
+	case isl_schedule_node_extension:
+	case isl_schedule_node_filter:
+	case isl_schedule_node_set:
+	case isl_schedule_node_sequence:
+		return 0;
+	}
+
+	isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+		"unhandled case", return 0);
+}
+
+/* Move down to the first descendant of "tree" that contains any schedule
+ * information or return "leaf" if there is no such descendant.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant(
+	__isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf)
+{
+	while (domain_less(tree)) {
+		if (!isl_schedule_tree_has_children(tree)) {
+			isl_schedule_tree_free(tree);
+			return isl_schedule_tree_copy(leaf);
+		}
+		tree = isl_schedule_tree_child(tree, 0);
+	}
+
+	return tree;
+}
+
+static __isl_give isl_union_map *subtree_schedule_extend(
+	__isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer);
+
+/* Extend the schedule map "outer" with the subtree schedule
+ * of the (single) child of "tree", if any.
+ *
+ * If "tree" does not have any descendants (apart from those that
+ * do not carry any schedule information), then we simply return "outer".
+ * Otherwise, we extend the schedule map "outer" with the subtree schedule
+ * of the single child.
+ */
+static __isl_give isl_union_map *subtree_schedule_extend_child(
+	__isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
+{
+	isl_schedule_tree *child;
+	isl_union_map *res;
+
+	if (!tree)
+		return isl_union_map_free(outer);
+	if (!isl_schedule_tree_has_children(tree))
+		return outer;
+	child = isl_schedule_tree_get_child(tree, 0);
+	if (!child)
+		return isl_union_map_free(outer);
+	res = subtree_schedule_extend(child, outer);
+	isl_schedule_tree_free(child);
+	return res;
+}
+
+/* Extract the parameter space from one of the children of "tree",
+ * which are assumed to be filters.
+ */
+static __isl_give isl_space *extract_space_from_filter_child(
+	__isl_keep isl_schedule_tree *tree)
+{
+	isl_space *space;
+	isl_union_set *dom;
+	isl_schedule_tree *child;
+
+	child = isl_schedule_tree_list_get_schedule_tree(tree->children, 0);
+	dom = isl_schedule_tree_filter_get_filter(child);
+	space = isl_union_set_get_space(dom);
+	isl_union_set_free(dom);
+	isl_schedule_tree_free(child);
+
+	return space;
+}
+
+/* Extend the schedule map "outer" with the subtree schedule
+ * of a set or sequence node.
+ *
+ * The schedule for the set or sequence node itself is composed of
+ * pieces of the form
+ *
+ *	filter -> []
+ *
+ * or
+ *
+ *	filter -> [index]
+ *
+ * The first form is used if there is only a single child or
+ * if the current node is a set node and the schedule_separate_components
+ * option is not set.
+ *
+ * Each of the pieces above is extended with the subtree schedule of
+ * the child of the corresponding filter, if any, padded with zeros
+ * to ensure that all pieces have the same range dimension.
+ */
+static __isl_give isl_union_map *subtree_schedule_extend_from_children(
+	__isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
+{
+	int i, n;
+	int dim;
+	int separate;
+	isl_ctx *ctx;
+	isl_val *v = NULL;
+	isl_multi_val *mv;
+	isl_space *space;
+	isl_union_map *umap;
+
+	if (!tree)
+		return NULL;
+
+	ctx = isl_schedule_tree_get_ctx(tree);
+	if (!tree->children)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"missing children", return NULL);
+	n = isl_schedule_tree_list_n_schedule_tree(tree->children);
+	if (n == 0)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"missing children", return NULL);
+
+	separate = n > 1 && (tree->type == isl_schedule_node_sequence ||
+			    isl_options_get_schedule_separate_components(ctx));
+
+	space = extract_space_from_filter_child(tree);
+
+	umap = isl_union_map_empty(isl_space_copy(space));
+	space = isl_space_set_from_params(space);
+	if (separate) {
+		space = isl_space_add_dims(space, isl_dim_set, 1);
+		v = isl_val_zero(ctx);
+	}
+	mv = isl_multi_val_zero(space);
+
+	dim = isl_multi_val_dim(mv, isl_dim_set);
+	for (i = 0; i < n; ++i) {
+		isl_union_pw_multi_aff *upma;
+		isl_union_map *umap_i;
+		isl_union_set *dom;
+		isl_schedule_tree *child;
+		int dim_i;
+		int empty;
+
+		child = isl_schedule_tree_list_get_schedule_tree(
+							tree->children, i);
+		dom = isl_schedule_tree_filter_get_filter(child);
+
+		if (separate) {
+			mv = isl_multi_val_set_val(mv, 0, isl_val_copy(v));
+			v = isl_val_add_ui(v, 1);
+		}
+		upma = isl_union_pw_multi_aff_multi_val_on_domain(dom,
+							isl_multi_val_copy(mv));
+		umap_i = isl_union_map_from_union_pw_multi_aff(upma);
+		umap_i = isl_union_map_flat_range_product(
+					    isl_union_map_copy(outer), umap_i);
+		umap_i = subtree_schedule_extend_child(child, umap_i);
+		isl_schedule_tree_free(child);
+
+		empty = isl_union_map_is_empty(umap_i);
+		if (empty < 0)
+			umap_i = isl_union_map_free(umap_i);
+		else if (empty) {
+			isl_union_map_free(umap_i);
+			continue;
+		}
+
+		dim_i = range_dim(umap_i);
+		if (dim_i < 0) {
+			umap = isl_union_map_free(umap);
+		} else if (dim < dim_i) {
+			umap = append_range(umap, dim_i - dim);
+			dim = dim_i;
+		} else if (dim_i < dim) {
+			umap_i = append_range(umap_i, dim - dim_i);
+		}
+		umap = isl_union_map_union(umap, umap_i);
+	}
+
+	isl_val_free(v);
+	isl_multi_val_free(mv);
+	isl_union_map_free(outer);
+
+	return umap;
+}
+
+/* Extend the schedule map "outer" with the subtree schedule of "tree".
+ *
+ * If the root of the tree is a set or a sequence, then we extend
+ * the schedule map in subtree_schedule_extend_from_children.
+ * Otherwise, we extend the schedule map with the partial schedule
+ * corresponding to the root of the tree and then continue with
+ * the single child of this root.
+ * In the special case of an expansion, the schedule map is "extended"
+ * by applying the expansion to the domain of the schedule map.
+ */
+static __isl_give isl_union_map *subtree_schedule_extend(
+	__isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
+{
+	isl_multi_union_pw_aff *mupa;
+	isl_union_map *umap;
+	isl_union_set *domain;
+
+	if (!tree)
+		return NULL;
+
+	switch (tree->type) {
+	case isl_schedule_node_error:
+		return isl_union_map_free(outer);
+	case isl_schedule_node_extension:
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"cannot construct subtree schedule of tree "
+			"with extension nodes",
+			return isl_union_map_free(outer));
+	case isl_schedule_node_context:
+	case isl_schedule_node_guard:
+	case isl_schedule_node_mark:
+		return subtree_schedule_extend_child(tree, outer);
+	case isl_schedule_node_band:
+		if (isl_schedule_tree_band_n_member(tree) == 0)
+			return subtree_schedule_extend_child(tree, outer);
+		mupa = isl_schedule_band_get_partial_schedule(tree->band);
+		umap = isl_union_map_from_multi_union_pw_aff(mupa);
+		outer = isl_union_map_flat_range_product(outer, umap);
+		umap = subtree_schedule_extend_child(tree, outer);
+		break;
+	case isl_schedule_node_domain:
+		domain = isl_schedule_tree_domain_get_domain(tree);
+		umap = isl_union_map_from_domain(domain);
+		outer = isl_union_map_flat_range_product(outer, umap);
+		umap = subtree_schedule_extend_child(tree, outer);
+		break;
+	case isl_schedule_node_expansion:
+		umap = isl_schedule_tree_expansion_get_expansion(tree);
+		outer = isl_union_map_apply_domain(outer, umap);
+		umap = subtree_schedule_extend_child(tree, outer);
+		break;
+	case isl_schedule_node_filter:
+		domain = isl_schedule_tree_filter_get_filter(tree);
+		umap = isl_union_map_from_domain(domain);
+		outer = isl_union_map_flat_range_product(outer, umap);
+		umap = subtree_schedule_extend_child(tree, outer);
+		break;
+	case isl_schedule_node_leaf:
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"leaf node should be handled by caller", return NULL);
+	case isl_schedule_node_set:
+	case isl_schedule_node_sequence:
+		umap = subtree_schedule_extend_from_children(tree, outer);
+		break;
+	}
+
+	return umap;
+}
+
+static __isl_give isl_union_set *initial_domain(
+	__isl_keep isl_schedule_tree *tree);
+
+/* Extract a universe domain from the children of the tree root "tree",
+ * which is a set or sequence, meaning that its children are filters.
+ * In particular, return the union of the universes of the filters.
+ */
+static __isl_give isl_union_set *initial_domain_from_children(
+	__isl_keep isl_schedule_tree *tree)
+{
+	int i, n;
+	isl_space *space;
+	isl_union_set *domain;
+
+	if (!tree->children)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"missing children", return NULL);
+	n = isl_schedule_tree_list_n_schedule_tree(tree->children);
+	if (n == 0)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"missing children", return NULL);
+
+	space = extract_space_from_filter_child(tree);
+	domain = isl_union_set_empty(space);
+
+	for (i = 0; i < n; ++i) {
+		isl_schedule_tree *child;
+		isl_union_set *domain_i;
+
+		child = isl_schedule_tree_get_child(tree, i);
+		domain_i = initial_domain(child);
+		domain = isl_union_set_union(domain, domain_i);
+		isl_schedule_tree_free(child);
+	}
+
+	return domain;
+}
+
+/* Extract a universe domain from the tree root "tree".
+ * The caller is responsible for making sure that this node
+ * would not be skipped by isl_schedule_tree_first_schedule_descendant
+ * and that it is not a leaf node.
+ */
+static __isl_give isl_union_set *initial_domain(
+	__isl_keep isl_schedule_tree *tree)
+{
+	isl_multi_union_pw_aff *mupa;
+	isl_union_set *domain;
+	isl_union_map *exp;
+
+	if (!tree)
+		return NULL;
+
+	switch (tree->type) {
+	case isl_schedule_node_error:
+		return NULL;
+	case isl_schedule_node_context:
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"context node should be handled by caller",
+			return NULL);
+	case isl_schedule_node_guard:
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"guard node should be handled by caller",
+			return NULL);
+	case isl_schedule_node_mark:
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"mark node should be handled by caller",
+			return NULL);
+	case isl_schedule_node_extension:
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"cannot construct subtree schedule of tree "
+			"with extension nodes", return NULL);
+	case isl_schedule_node_band:
+		if (isl_schedule_tree_band_n_member(tree) == 0)
+			isl_die(isl_schedule_tree_get_ctx(tree),
+				isl_error_internal,
+				"0D band should be handled by caller",
+				return NULL);
+		mupa = isl_schedule_band_get_partial_schedule(tree->band);
+		domain = isl_multi_union_pw_aff_domain(mupa);
+		domain = isl_union_set_universe(domain);
+		break;
+	case isl_schedule_node_domain:
+		domain = isl_schedule_tree_domain_get_domain(tree);
+		domain = isl_union_set_universe(domain);
+		break;
+	case isl_schedule_node_expansion:
+		exp = isl_schedule_tree_expansion_get_expansion(tree);
+		exp = isl_union_map_universe(exp);
+		domain = isl_union_map_domain(exp);
+		break;
+	case isl_schedule_node_filter:
+		domain = isl_schedule_tree_filter_get_filter(tree);
+		domain = isl_union_set_universe(domain);
+		break;
+	case isl_schedule_node_leaf:
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"leaf node should be handled by caller", return NULL);
+	case isl_schedule_node_set:
+	case isl_schedule_node_sequence:
+		domain = initial_domain_from_children(tree);
+		break;
+	}
+
+	return domain;
+}
+
+/* Return the subtree schedule of a node that contains some schedule
+ * information, i.e., a node that would not be skipped by
+ * isl_schedule_tree_first_schedule_descendant and that is not a leaf.
+ *
+ * If the tree contains any expansions, then the returned subtree
+ * schedule is formulated in terms of the expanded domains.
+ * The tree is not allowed to contain any extension nodes.
+ *
+ * We start with an initial zero-dimensional subtree schedule based
+ * on the domain information in the root node and then extend it
+ * based on the schedule information in the root node and its descendants.
+ */
+__isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map(
+	__isl_keep isl_schedule_tree *tree)
+{
+	isl_union_set *domain;
+	isl_union_map *umap;
+
+	domain = initial_domain(tree);
+	umap = isl_union_map_from_domain(domain);
+	return subtree_schedule_extend(tree, umap);
+}
+
+/* Multiply the partial schedule of the band root node of "tree"
+ * with the factors in "mv".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_scale(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
+{
+	if (!tree || !mv)
+		goto error;
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", goto error);
+
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		goto error;
+
+	tree->band = isl_schedule_band_scale(tree->band, mv);
+	if (!tree->band)
+		return isl_schedule_tree_free(tree);
+
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_multi_val_free(mv);
+	return NULL;
+}
+
+/* Divide the partial schedule of the band root node of "tree"
+ * by the factors in "mv".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
+{
+	if (!tree || !mv)
+		goto error;
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", goto error);
+
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		goto error;
+
+	tree->band = isl_schedule_band_scale_down(tree->band, mv);
+	if (!tree->band)
+		return isl_schedule_tree_free(tree);
+
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_multi_val_free(mv);
+	return NULL;
+}
+
+/* Reduce the partial schedule of the band root node of "tree"
+ * modulo the factors in "mv".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_mod(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
+{
+	if (!tree || !mv)
+		goto error;
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", goto error);
+
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		goto error;
+
+	tree->band = isl_schedule_band_mod(tree->band, mv);
+	if (!tree->band)
+		return isl_schedule_tree_free(tree);
+
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_multi_val_free(mv);
+	return NULL;
+}
+
+/* Shift the partial schedule of the band root node of "tree" by "shift".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_shift(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_multi_union_pw_aff *shift)
+{
+	if (!tree || !shift)
+		goto error;
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", goto error);
+
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		goto error;
+
+	tree->band = isl_schedule_band_shift(tree->band, shift);
+	if (!tree->band)
+		return isl_schedule_tree_free(tree);
+
+	return tree;
+error:
+	isl_schedule_tree_free(tree);
+	isl_multi_union_pw_aff_free(shift);
+	return NULL;
+}
+
+/* Given two trees with sequence roots, replace the child at position
+ * "pos" of "tree" with the children of "child".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_sequence_splice(
+	__isl_take isl_schedule_tree *tree, int pos,
+	__isl_take isl_schedule_tree *child)
+{
+	int n;
+	isl_schedule_tree_list *list1, *list2;
+
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree || !child)
+		goto error;
+	if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a sequence node", goto error);
+	n = isl_schedule_tree_n_children(tree);
+	if (pos < 0 || pos >= n)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"position out of bounds", goto error);
+	if (isl_schedule_tree_get_type(child) != isl_schedule_node_sequence)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a sequence node", goto error);
+
+	list1 = isl_schedule_tree_list_copy(tree->children);
+	list1 = isl_schedule_tree_list_drop(list1, pos, n - pos);
+	list2 = isl_schedule_tree_list_copy(tree->children);
+	list2 = isl_schedule_tree_list_drop(list2, 0, pos + 1);
+	list1 = isl_schedule_tree_list_concat(list1,
+				isl_schedule_tree_list_copy(child->children));
+	list1 = isl_schedule_tree_list_concat(list1, list2);
+
+	isl_schedule_tree_free(tree);
+	isl_schedule_tree_free(child);
+	return isl_schedule_tree_from_children(isl_schedule_node_sequence,
+						list1);
+error:
+	isl_schedule_tree_free(tree);
+	isl_schedule_tree_free(child);
+	return NULL;
+}
+
+/* Tile the band root node of "tree" with tile sizes "sizes".
+ *
+ * We duplicate the band node, change the schedule of one of them
+ * to the tile schedule and the other to the point schedule and then
+ * attach the point band as a child to the tile band.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_tile(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes)
+{
+	isl_schedule_tree *child = NULL;
+
+	if (!tree || !sizes)
+		goto error;
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", goto error);
+
+	child = isl_schedule_tree_copy(tree);
+	tree = isl_schedule_tree_cow(tree);
+	child = isl_schedule_tree_cow(child);
+	if (!tree || !child)
+		goto error;
+
+	tree->band = isl_schedule_band_tile(tree->band,
+					    isl_multi_val_copy(sizes));
+	if (!tree->band)
+		goto error;
+	child->band = isl_schedule_band_point(child->band, tree->band, sizes);
+	if (!child->band)
+		child = isl_schedule_tree_free(child);
+
+	tree = isl_schedule_tree_replace_child(tree, 0, child);
+
+	return tree;
+error:
+	isl_schedule_tree_free(child);
+	isl_schedule_tree_free(tree);
+	isl_multi_val_free(sizes);
+	return NULL;
+}
+
+/* Given an isolate AST generation option "isolate" for a band of size pos + n,
+ * return the corresponding option for a band covering the first "pos"
+ * members.
+ *
+ * The input isolate option is of the form
+ *
+ *	isolate[[flattened outer bands] -> [pos; n]]
+ *
+ * The output isolate option is of the form
+ *
+ *	isolate[[flattened outer bands] -> [pos]]
+ */
+static __isl_give isl_set *isolate_initial(__isl_keep isl_set *isolate,
+	int pos, int n)
+{
+	isl_id *id;
+	isl_map *map;
+
+	isolate = isl_set_copy(isolate);
+	id = isl_set_get_tuple_id(isolate);
+	map = isl_set_unwrap(isolate);
+	map = isl_map_project_out(map, isl_dim_out, pos, n);
+	isolate = isl_map_wrap(map);
+	isolate = isl_set_set_tuple_id(isolate, id);
+
+	return isolate;
+}
+
+/* Given an isolate AST generation option "isolate" for a band of size pos + n,
+ * return the corresponding option for a band covering the final "n"
+ * members within a band covering the first "pos" members.
+ *
+ * The input isolate option is of the form
+ *
+ *	isolate[[flattened outer bands] -> [pos; n]]
+ *
+ * The output isolate option is of the form
+ *
+ *	isolate[[flattened outer bands; pos] -> [n]]
+ *
+ *
+ * The range is first split into
+ *
+ *	isolate[[flattened outer bands] -> [[pos] -> [n]]]
+ *
+ * and then the first pos members are moved to the domain
+ *
+ *	isolate[[[flattened outer bands] -> [pos]] -> [n]]
+ *
+ * after which the domain is flattened to obtain the desired output.
+ */
+static __isl_give isl_set *isolate_final(__isl_keep isl_set *isolate,
+	int pos, int n)
+{
+	isl_id *id;
+	isl_space *space;
+	isl_multi_aff *ma1, *ma2;
+	isl_map *map;
+
+	isolate = isl_set_copy(isolate);
+	id = isl_set_get_tuple_id(isolate);
+	map = isl_set_unwrap(isolate);
+	space = isl_space_range(isl_map_get_space(map));
+	ma1 = isl_multi_aff_project_out_map(isl_space_copy(space),
+						   isl_dim_set, pos, n);
+	ma2 = isl_multi_aff_project_out_map(space, isl_dim_set, 0, pos);
+	ma1 = isl_multi_aff_range_product(ma1, ma2);
+	map = isl_map_apply_range(map, isl_map_from_multi_aff(ma1));
+	map = isl_map_uncurry(map);
+	map = isl_map_flatten_domain(map);
+	isolate = isl_map_wrap(map);
+	isolate = isl_set_set_tuple_id(isolate, id);
+
+	return isolate;
+}
+
+/* Split the band root node of "tree" into two nested band nodes,
+ * one with the first "pos" dimensions and
+ * one with the remaining dimensions.
+ * The tree is itself positioned at schedule depth "depth".
+ *
+ * The loop AST generation type options and the isolate option
+ * are split over the the two band nodes.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_split(
+	__isl_take isl_schedule_tree *tree, int pos, int depth)
+{
+	int n;
+	isl_set *isolate, *tree_isolate, *child_isolate;
+	isl_schedule_tree *child;
+
+	if (!tree)
+		return NULL;
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", return isl_schedule_tree_free(tree));
+
+	n = isl_schedule_tree_band_n_member(tree);
+	if (pos < 0 || pos > n)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"position out of bounds",
+			return isl_schedule_tree_free(tree));
+
+	child = isl_schedule_tree_copy(tree);
+	tree = isl_schedule_tree_cow(tree);
+	child = isl_schedule_tree_cow(child);
+	if (!tree || !child)
+		goto error;
+
+	isolate = isl_schedule_tree_band_get_ast_isolate_option(tree, depth);
+	tree_isolate = isolate_initial(isolate, pos, n - pos);
+	child_isolate = isolate_final(isolate, pos, n - pos);
+	child->band = isl_schedule_band_drop(child->band, 0, pos);
+	child->band = isl_schedule_band_replace_ast_build_option(child->band,
+					isl_set_copy(isolate), child_isolate);
+	tree->band = isl_schedule_band_drop(tree->band, pos, n - pos);
+	tree->band = isl_schedule_band_replace_ast_build_option(tree->band,
+					isl_set_copy(isolate), tree_isolate);
+	isl_set_free(isolate);
+	if (!child->band || !tree->band)
+		goto error;
+
+	tree = isl_schedule_tree_replace_child(tree, 0, child);
+
+	return tree;
+error:
+	isl_schedule_tree_free(child);
+	isl_schedule_tree_free(tree);
+	return NULL;
+}
+
+/* Attach "tree2" at each of the leaves of "tree1".
+ *
+ * If "tree1" does not have any explicit children, then make "tree2"
+ * its single child.  Otherwise, attach "tree2" to the leaves of
+ * each of the children of "tree1".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves(
+	__isl_take isl_schedule_tree *tree1,
+	__isl_take isl_schedule_tree *tree2)
+{
+	int i, n;
+
+	if (!tree1 || !tree2)
+		goto error;
+	n = isl_schedule_tree_n_children(tree1);
+	if (n == 0) {
+		isl_schedule_tree_list *list;
+		list = isl_schedule_tree_list_from_schedule_tree(tree2);
+		tree1 = isl_schedule_tree_set_children(tree1, list);
+		return tree1;
+	}
+	for (i = 0; i < n; ++i) {
+		isl_schedule_tree *child;
+
+		child = isl_schedule_tree_get_child(tree1, i);
+		child = isl_schedule_tree_append_to_leaves(child,
+					isl_schedule_tree_copy(tree2));
+		tree1 = isl_schedule_tree_replace_child(tree1, i, child);
+	}
+
+	isl_schedule_tree_free(tree2);
+	return tree1;
+error:
+	isl_schedule_tree_free(tree1);
+	isl_schedule_tree_free(tree2);
+	return NULL;
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * in the root of "tree".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
+	__isl_take isl_schedule_tree *tree)
+{
+	if (isl_schedule_tree_is_leaf(tree))
+		return tree;
+
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		return NULL;
+
+	switch (tree->type) {
+	case isl_schedule_node_error:
+		return isl_schedule_tree_free(tree);
+	case isl_schedule_node_band:
+		tree->band = isl_schedule_band_reset_user(tree->band);
+		if (!tree->band)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_context:
+		tree->context = isl_set_reset_user(tree->context);
+		if (!tree->context)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_domain:
+		tree->domain = isl_union_set_reset_user(tree->domain);
+		if (!tree->domain)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_expansion:
+		tree->contraction =
+			isl_union_pw_multi_aff_reset_user(tree->contraction);
+		tree->expansion = isl_union_map_reset_user(tree->expansion);
+		if (!tree->contraction || !tree->expansion)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_extension:
+		tree->extension = isl_union_map_reset_user(tree->extension);
+		if (!tree->extension)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_filter:
+		tree->filter = isl_union_set_reset_user(tree->filter);
+		if (!tree->filter)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_guard:
+		tree->guard = isl_set_reset_user(tree->guard);
+		if (!tree->guard)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_mark:
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		break;
+	}
+
+	return tree;
+}
+
+/* Align the parameters of the root of "tree" to those of "space".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_align_params(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_space *space)
+{
+	if (!space)
+		goto error;
+
+	if (isl_schedule_tree_is_leaf(tree)) {
+		isl_space_free(space);
+		return tree;
+	}
+
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		goto error;
+
+	switch (tree->type) {
+	case isl_schedule_node_error:
+		goto error;
+	case isl_schedule_node_band:
+		tree->band = isl_schedule_band_align_params(tree->band, space);
+		if (!tree->band)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_context:
+		tree->context = isl_set_align_params(tree->context, space);
+		if (!tree->context)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_domain:
+		tree->domain = isl_union_set_align_params(tree->domain, space);
+		if (!tree->domain)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_expansion:
+		tree->contraction =
+			isl_union_pw_multi_aff_align_params(tree->contraction,
+							isl_space_copy(space));
+		tree->expansion = isl_union_map_align_params(tree->expansion,
+								space);
+		if (!tree->contraction || !tree->expansion)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_extension:
+		tree->extension = isl_union_map_align_params(tree->extension,
+								space);
+		if (!tree->extension)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_filter:
+		tree->filter = isl_union_set_align_params(tree->filter, space);
+		if (!tree->filter)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_guard:
+		tree->guard = isl_set_align_params(tree->guard, space);
+		if (!tree->guard)
+			return isl_schedule_tree_free(tree);
+		break;
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_mark:
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		isl_space_free(space);
+		break;
+	}
+
+	return tree;
+error:
+	isl_space_free(space);
+	isl_schedule_tree_free(tree);
+	return NULL;
+}
+
+/* Does "tree" involve the iteration domain?
+ * That is, does it need to be modified
+ * by isl_schedule_tree_pullback_union_pw_multi_aff?
+ */
+static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return -1;
+
+	switch (tree->type) {
+	case isl_schedule_node_error:
+		return -1;
+	case isl_schedule_node_band:
+	case isl_schedule_node_domain:
+	case isl_schedule_node_expansion:
+	case isl_schedule_node_extension:
+	case isl_schedule_node_filter:
+		return 1;
+	case isl_schedule_node_context:
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_guard:
+	case isl_schedule_node_mark:
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		return 0;
+	}
+
+	isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+		"unhandled case", return -1);
+}
+
+/* Compute the pullback of the root node of "tree" by the function
+ * represented by "upma".
+ * In other words, plug in "upma" in the iteration domains of
+ * the root node of "tree".
+ * We currently do not handle expansion nodes.
+ *
+ * We first check if the root node involves any iteration domains.
+ * If so, we handle the specific cases.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_union_pw_multi_aff *upma)
+{
+	int involves;
+
+	if (!tree || !upma)
+		goto error;
+
+	involves = involves_iteration_domain(tree);
+	if (involves < 0)
+		goto error;
+	if (!involves) {
+		isl_union_pw_multi_aff_free(upma);
+		return tree;
+	}
+
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		goto error;
+
+	if (tree->type == isl_schedule_node_band) {
+		tree->band = isl_schedule_band_pullback_union_pw_multi_aff(
+							    tree->band, upma);
+		if (!tree->band)
+			return isl_schedule_tree_free(tree);
+	} else if (tree->type == isl_schedule_node_domain) {
+		tree->domain =
+			isl_union_set_preimage_union_pw_multi_aff(tree->domain,
+									upma);
+		if (!tree->domain)
+			return isl_schedule_tree_free(tree);
+	} else if (tree->type == isl_schedule_node_expansion) {
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported,
+			"cannot pullback expansion node", goto error);
+	} else if (tree->type == isl_schedule_node_extension) {
+		tree->extension =
+			isl_union_map_preimage_range_union_pw_multi_aff(
+			    tree->extension, upma);
+		if (!tree->extension)
+			return isl_schedule_tree_free(tree);
+	} else if (tree->type == isl_schedule_node_filter) {
+		tree->filter =
+			isl_union_set_preimage_union_pw_multi_aff(tree->filter,
+									upma);
+		if (!tree->filter)
+			return isl_schedule_tree_free(tree);
+	}
+
+	return tree;
+error:
+	isl_union_pw_multi_aff_free(upma);
+	isl_schedule_tree_free(tree);
+	return NULL;
+}
+
+/* Compute the gist of the band tree root with respect to "context".
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_gist(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context)
+{
+	if (!tree)
+		return NULL;
+	if (tree->type != isl_schedule_node_band)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
+			"not a band node", goto error);
+	tree = isl_schedule_tree_cow(tree);
+	if (!tree)
+		goto error;
+
+	tree->band = isl_schedule_band_gist(tree->band, context);
+	if (!tree->band)
+		return isl_schedule_tree_free(tree);
+	return tree;
+error:
+	isl_union_set_free(context);
+	isl_schedule_tree_free(tree);
+	return NULL;
+}
+
+/* Are any members in "band" marked coincident?
+ */
+static int any_coincident(__isl_keep isl_schedule_band *band)
+{
+	int i, n;
+
+	n = isl_schedule_band_n_member(band);
+	for (i = 0; i < n; ++i)
+		if (isl_schedule_band_member_get_coincident(band, i))
+			return 1;
+
+	return 0;
+}
+
+/* Print the band node "band" to "p".
+ *
+ * The permutable and coincident properties are only printed if they
+ * are different from the defaults.
+ * The coincident property is always printed in YAML flow style.
+ */
+static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p,
+	__isl_keep isl_schedule_band *band)
+{
+	isl_union_set *options;
+	int empty;
+
+	p = isl_printer_print_str(p, "schedule");
+	p = isl_printer_yaml_next(p);
+	p = isl_printer_print_str(p, "\"");
+	p = isl_printer_print_multi_union_pw_aff(p, band->mupa);
+	p = isl_printer_print_str(p, "\"");
+	if (isl_schedule_band_get_permutable(band)) {
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "permutable");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_int(p, 1);
+	}
+	if (any_coincident(band)) {
+		int i, n;
+		int style;
+
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "coincident");
+		p = isl_printer_yaml_next(p);
+		style = isl_printer_get_yaml_style(p);
+		p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
+		p = isl_printer_yaml_start_sequence(p);
+		n = isl_schedule_band_n_member(band);
+		for (i = 0; i < n; ++i) {
+			p = isl_printer_print_int(p,
+			    isl_schedule_band_member_get_coincident(band, i));
+			p = isl_printer_yaml_next(p);
+		}
+		p = isl_printer_yaml_end_sequence(p);
+		p = isl_printer_set_yaml_style(p, style);
+	}
+	options = isl_schedule_band_get_ast_build_options(band);
+	empty = isl_union_set_is_empty(options);
+	if (empty < 0)
+		p = isl_printer_free(p);
+	if (!empty) {
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "options");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "\"");
+		p = isl_printer_print_union_set(p, options);
+		p = isl_printer_print_str(p, "\"");
+	}
+	isl_union_set_free(options);
+
+	return p;
+}
+
+/* Print "tree" to "p".
+ *
+ * If "n_ancestor" is non-negative, then "child_pos" contains the child
+ * positions of a descendant of the current node that should be marked
+ * (by the comment "YOU ARE HERE").  In particular, if "n_ancestor"
+ * is zero, then the current node should be marked.
+ * The marking is only printed in YAML block format.
+ *
+ * Implicit leaf nodes are not printed, except if they correspond
+ * to the node that should be marked.
+ */
+__isl_give isl_printer *isl_printer_print_schedule_tree_mark(
+	__isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree,
+	int n_ancestor, int *child_pos)
+{
+	int i, n;
+	int sequence = 0;
+	int block;
+
+	block = isl_printer_get_yaml_style(p) == ISL_YAML_STYLE_BLOCK;
+
+	p = isl_printer_yaml_start_mapping(p);
+	if (n_ancestor == 0 && block) {
+		p = isl_printer_print_str(p, "# YOU ARE HERE");
+		p = isl_printer_end_line(p);
+		p = isl_printer_start_line(p);
+	}
+	switch (tree->type) {
+	case isl_schedule_node_error:
+		p = isl_printer_print_str(p, "ERROR");
+		break;
+	case isl_schedule_node_leaf:
+		p = isl_printer_print_str(p, "leaf");
+		break;
+	case isl_schedule_node_sequence:
+		p = isl_printer_print_str(p, "sequence");
+		sequence = 1;
+		break;
+	case isl_schedule_node_set:
+		p = isl_printer_print_str(p, "set");
+		sequence = 1;
+		break;
+	case isl_schedule_node_context:
+		p = isl_printer_print_str(p, "context");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "\"");
+		p = isl_printer_print_set(p, tree->context);
+		p = isl_printer_print_str(p, "\"");
+		break;
+	case isl_schedule_node_domain:
+		p = isl_printer_print_str(p, "domain");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "\"");
+		p = isl_printer_print_union_set(p, tree->domain);
+		p = isl_printer_print_str(p, "\"");
+		break;
+	case isl_schedule_node_expansion:
+		p = isl_printer_print_str(p, "contraction");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "\"");
+		p = isl_printer_print_union_pw_multi_aff(p, tree->contraction);
+		p = isl_printer_print_str(p, "\"");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "expansion");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "\"");
+		p = isl_printer_print_union_map(p, tree->expansion);
+		p = isl_printer_print_str(p, "\"");
+		break;
+	case isl_schedule_node_extension:
+		p = isl_printer_print_str(p, "extension");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "\"");
+		p = isl_printer_print_union_map(p, tree->extension);
+		p = isl_printer_print_str(p, "\"");
+		break;
+	case isl_schedule_node_filter:
+		p = isl_printer_print_str(p, "filter");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "\"");
+		p = isl_printer_print_union_set(p, tree->filter);
+		p = isl_printer_print_str(p, "\"");
+		break;
+	case isl_schedule_node_guard:
+		p = isl_printer_print_str(p, "guard");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "\"");
+		p = isl_printer_print_set(p, tree->guard);
+		p = isl_printer_print_str(p, "\"");
+		break;
+	case isl_schedule_node_mark:
+		p = isl_printer_print_str(p, "mark");
+		p = isl_printer_yaml_next(p);
+		p = isl_printer_print_str(p, "\"");
+		p = isl_printer_print_str(p, isl_id_get_name(tree->mark));
+		p = isl_printer_print_str(p, "\"");
+		break;
+	case isl_schedule_node_band:
+		p = print_tree_band(p, tree->band);
+		break;
+	}
+	p = isl_printer_yaml_next(p);
+
+	if (!tree->children) {
+		if (n_ancestor > 0 && block) {
+			isl_schedule_tree *leaf;
+
+			p = isl_printer_print_str(p, "child");
+			p = isl_printer_yaml_next(p);
+			leaf = isl_schedule_tree_leaf(isl_printer_get_ctx(p));
+			p = isl_printer_print_schedule_tree_mark(p,
+					leaf, 0, NULL);
+			isl_schedule_tree_free(leaf);
+			p = isl_printer_yaml_next(p);
+		}
+		return isl_printer_yaml_end_mapping(p);
+	}
+
+	if (sequence) {
+		p = isl_printer_yaml_start_sequence(p);
+	} else {
+		p = isl_printer_print_str(p, "child");
+		p = isl_printer_yaml_next(p);
+	}
+
+	n = isl_schedule_tree_list_n_schedule_tree(tree->children);
+	for (i = 0; i < n; ++i) {
+		isl_schedule_tree *t;
+
+		t = isl_schedule_tree_get_child(tree, i);
+		if (n_ancestor > 0 && child_pos[0] == i)
+			p = isl_printer_print_schedule_tree_mark(p, t,
+						n_ancestor - 1, child_pos + 1);
+		else
+			p = isl_printer_print_schedule_tree_mark(p, t,
+						-1, NULL);
+		isl_schedule_tree_free(t);
+
+		p = isl_printer_yaml_next(p);
+	}
+
+	if (sequence)
+		p = isl_printer_yaml_end_sequence(p);
+	p = isl_printer_yaml_end_mapping(p);
+
+	return p;
+}
+
+/* Print "tree" to "p".
+ */
+__isl_give isl_printer *isl_printer_print_schedule_tree(
+	__isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree)
+{
+	return isl_printer_print_schedule_tree_mark(p, tree, -1, NULL);
+}
+
+void isl_schedule_tree_dump(__isl_keep isl_schedule_tree *tree)
+{
+	isl_ctx *ctx;
+	isl_printer *printer;
+
+	if (!tree)
+		return;
+
+	ctx = isl_schedule_tree_get_ctx(tree);
+	printer = isl_printer_to_file(ctx, stderr);
+	printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK);
+	printer = isl_printer_print_schedule_tree(printer, tree);
+
+	isl_printer_free(printer);
+}
diff --git a/final/lib/External/isl/isl_schedule_tree.h b/final/lib/External/isl/isl_schedule_tree.h
new file mode 100644
index 0000000..9bb32c4
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_tree.h
@@ -0,0 +1,266 @@
+#ifndef ISL_SCHEDLUE_TREE_H
+#define ISL_SCHEDLUE_TREE_H
+
+#include <isl_schedule_band.h>
+#include <isl/schedule.h>
+#include <isl/set.h>
+#include <isl/union_set.h>
+
+struct isl_schedule_tree;
+typedef struct isl_schedule_tree isl_schedule_tree;
+
+ISL_DECLARE_LIST(schedule_tree)
+
+/* A schedule (sub)tree.
+ *
+ * The leaves of a tree are not explicitly represented inside
+ * the isl_schedule_tree, except when the tree consists of only a leaf.
+ *
+ * The "band" field is valid when type is isl_schedule_node_band.
+ * The "context" field is valid when type is isl_schedule_node_context
+ * and represents constraints on the flat product of the outer band nodes,
+ * possibly introducing additional parameters.
+ * The "domain" field is valid when type is isl_schedule_node_domain
+ * and introduces the statement instances scheduled by the tree.
+ *
+ * The "contraction" and "expansion" fields are valid when type
+ * is isl_schedule_node_expansion.
+ * "expansion" expands the reaching domain elements to one or more
+ * domain elements for the subtree.
+ * "contraction" maps these elements back to the corresponding
+ * reaching domain element.  It does not involve any domain constraints.
+ *
+ * The "extension" field is valid when the is isl_schedule_node_extension
+ * maps outer schedule dimenions (the flat product of the outer band nodes)
+ * to additional iteration domains.
+ *
+ * The "filter" field is valid when type is isl_schedule_node_filter
+ * and represents the statement instances selected by the node.
+ *
+ * The "guard" field is valid when type is isl_schedule_node_guard
+ * and represents constraints on the flat product of the outer band nodes
+ * that need to be enforced by the outer nodes in the generated AST.
+ *
+ * The "mark" field is valid when type is isl_schedule_node_mark and
+ * identifies the mark.
+ *
+ * The "children" field is valid for all types except
+ * isl_schedule_node_leaf.  This field is NULL if there are
+ * no children (except for the implicit leaves).
+ *
+ * anchored is set if the node or any of its descendants depends
+ * on its position in the schedule tree.
+ */
+struct isl_schedule_tree {
+	int ref;
+	isl_ctx *ctx;
+	int anchored;
+	enum isl_schedule_node_type type;
+	union {
+		isl_schedule_band *band;
+		isl_set *context;
+		isl_union_set *domain;
+		struct {
+			isl_union_pw_multi_aff *contraction;
+			isl_union_map *expansion;
+		};
+		isl_union_map *extension;
+		isl_union_set *filter;
+		isl_set *guard;
+		isl_id *mark;
+	};
+	isl_schedule_tree_list *children;
+};
+
+isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree);
+enum isl_schedule_node_type isl_schedule_tree_get_type(
+	__isl_keep isl_schedule_tree *tree);
+
+__isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx);
+int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree);
+
+isl_bool isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
+	__isl_keep isl_schedule_tree *tree2);
+
+__isl_give isl_schedule_tree *isl_schedule_tree_copy(
+	__isl_keep isl_schedule_tree *tree);
+__isl_null isl_schedule_tree *isl_schedule_tree_free(
+	__isl_take isl_schedule_tree *tree);
+
+__isl_give isl_schedule_tree *isl_schedule_tree_from_band(
+	__isl_take isl_schedule_band *band);
+__isl_give isl_schedule_tree *isl_schedule_tree_from_context(
+	__isl_take isl_set *context);
+__isl_give isl_schedule_tree *isl_schedule_tree_from_domain(
+	__isl_take isl_union_set *domain);
+__isl_give isl_schedule_tree *isl_schedule_tree_from_expansion(
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_union_map *expansion);
+__isl_give isl_schedule_tree *isl_schedule_tree_from_extension(
+	__isl_take isl_union_map *extension);
+__isl_give isl_schedule_tree *isl_schedule_tree_from_filter(
+	__isl_take isl_union_set *filter);
+__isl_give isl_schedule_tree *isl_schedule_tree_from_guard(
+	__isl_take isl_set *guard);
+__isl_give isl_schedule_tree *isl_schedule_tree_from_children(
+	enum isl_schedule_node_type type,
+	__isl_take isl_schedule_tree_list *list);
+__isl_give isl_schedule_tree *isl_schedule_tree_from_pair(
+	enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1,
+	__isl_take isl_schedule_tree *tree2);
+__isl_give isl_schedule_tree *isl_schedule_tree_sequence_pair(
+	__isl_take isl_schedule_tree *tree1,
+	__isl_take isl_schedule_tree *tree2);
+__isl_give isl_schedule_tree *isl_schedule_tree_set_pair(
+	__isl_take isl_schedule_tree *tree1,
+	__isl_take isl_schedule_tree *tree2);
+
+isl_bool isl_schedule_tree_is_subtree_anchored(
+	__isl_keep isl_schedule_tree *tree);
+
+__isl_give isl_space *isl_schedule_tree_band_get_space(
+	__isl_keep isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain);
+__isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule(
+	__isl_keep isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_multi_union_pw_aff *schedule);
+enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type(
+	__isl_keep isl_schedule_tree *tree, int pos);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type(
+	__isl_take isl_schedule_tree *tree, int pos,
+	enum isl_ast_loop_type type);
+enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type(
+	__isl_keep isl_schedule_tree *tree, int pos);
+__isl_give isl_schedule_tree *
+isl_schedule_tree_band_member_set_isolate_ast_loop_type(
+	__isl_take isl_schedule_tree *tree, int pos,
+	enum isl_ast_loop_type type);
+__isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options(
+	__isl_keep isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options);
+__isl_give isl_set *isl_schedule_tree_band_get_ast_isolate_option(
+	__isl_keep isl_schedule_tree *tree, int depth);
+__isl_give isl_set *isl_schedule_tree_context_get_context(
+	__isl_keep isl_schedule_tree *tree);
+__isl_give isl_union_set *isl_schedule_tree_domain_get_domain(
+	__isl_keep isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain);
+__isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction(
+	__isl_keep isl_schedule_tree *tree);
+__isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion(
+	__isl_keep isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *
+isl_schedule_tree_expansion_set_contraction_and_expansion(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_union_map *expansion);
+__isl_give isl_union_map *isl_schedule_tree_extension_get_extension(
+	__isl_keep isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *isl_schedule_tree_extension_set_extension(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_union_map *extension);
+__isl_give isl_union_set *isl_schedule_tree_filter_get_filter(
+	__isl_keep isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter);
+__isl_give isl_set *isl_schedule_tree_guard_get_guard(
+	__isl_keep isl_schedule_tree *tree);
+__isl_give isl_id *isl_schedule_tree_mark_get_id(
+	__isl_keep isl_schedule_tree *tree);
+
+__isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant(
+	__isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf);
+__isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map(
+	__isl_keep isl_schedule_tree *tree);
+
+unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree);
+
+isl_bool isl_schedule_tree_band_member_get_coincident(
+	__isl_keep isl_schedule_tree *tree, int pos);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident(
+	__isl_take isl_schedule_tree *tree, int pos, int coincident);
+isl_bool isl_schedule_tree_band_get_permutable(
+	__isl_keep isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable(
+	__isl_take isl_schedule_tree *tree, int permutable);
+
+int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree);
+int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *isl_schedule_tree_get_child(
+	__isl_keep isl_schedule_tree *tree, int pos);
+
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_band(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band);
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_context(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_set *context);
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_domain(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain);
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_union_pw_multi_aff *contraction,
+	__isl_take isl_union_map *expansion);
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_extension(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_union_map *extension);
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_filter(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter);
+__isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter);
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_guard(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_set *guard);
+__isl_give isl_schedule_tree *isl_schedule_tree_insert_mark(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_id *mark);
+
+__isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves(
+	__isl_take isl_schedule_tree *tree1,
+	__isl_take isl_schedule_tree *tree2);
+
+__isl_give isl_schedule_tree *isl_schedule_tree_band_scale(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_mod(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_tile(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_shift(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_multi_union_pw_aff *shift);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_split(
+	__isl_take isl_schedule_tree *tree, int pos, int depth);
+__isl_give isl_schedule_tree *isl_schedule_tree_band_gist(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context);
+
+__isl_give isl_schedule_tree *isl_schedule_tree_child(
+	__isl_take isl_schedule_tree *tree, int pos);
+__isl_give isl_schedule_tree *isl_schedule_tree_reset_children(
+	__isl_take isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *isl_schedule_tree_drop_child(
+	__isl_take isl_schedule_tree *tree, int pos);
+__isl_give isl_schedule_tree *isl_schedule_tree_replace_child(
+	__isl_take isl_schedule_tree *tree, int pos,
+	__isl_take isl_schedule_tree *new_child);
+__isl_give isl_schedule_tree *isl_schedule_tree_sequence_splice(
+	__isl_take isl_schedule_tree *tree, int pos,
+	__isl_take isl_schedule_tree *child);
+
+__isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
+	__isl_take isl_schedule_tree *tree);
+__isl_give isl_schedule_tree *isl_schedule_tree_align_params(
+	__isl_take isl_schedule_tree *tree, __isl_take isl_space *space);
+__isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff(
+	__isl_take isl_schedule_tree *tree,
+	__isl_take isl_union_pw_multi_aff *upma);
+
+__isl_give isl_printer *isl_printer_print_schedule_tree(
+	__isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree);
+__isl_give isl_printer *isl_printer_print_schedule_tree_mark(
+	__isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree,
+	int n_ancestor, int *child_pos);
+
+#endif
diff --git a/final/lib/External/isl/isl_scheduler.c b/final/lib/External/isl/isl_scheduler.c
new file mode 100644
index 0000000..9a93c30
--- /dev/null
+++ b/final/lib/External/isl/isl_scheduler.c
@@ -0,0 +1,7305 @@
+/*
+ * Copyright 2011      INRIA Saclay
+ * Copyright 2012-2014 Ecole Normale Superieure
+ * Copyright 2015-2016 Sven Verdoolaege
+ * Copyright 2016      INRIA Paris
+ * Copyright 2017      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12,
+ * CS 42112, 75589 Paris Cedex 12, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_space_private.h>
+#include <isl_aff_private.h>
+#include <isl/hash.h>
+#include <isl/constraint.h>
+#include <isl/schedule.h>
+#include <isl_schedule_constraints.h>
+#include <isl/schedule_node.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl/set.h>
+#include <isl_union_set_private.h>
+#include <isl_seq.h>
+#include <isl_tab.h>
+#include <isl_dim_map.h>
+#include <isl/map_to_basic_set.h>
+#include <isl_sort.h>
+#include <isl_options_private.h>
+#include <isl_tarjan.h>
+#include <isl_morph.h>
+#include <isl/ilp.h>
+#include <isl_val_private.h>
+
+/*
+ * The scheduling algorithm implemented in this file was inspired by
+ * Bondhugula et al., "Automatic Transformations for Communication-Minimized
+ * Parallelization and Locality Optimization in the Polyhedral Model".
+ */
+
+
+/* Internal information about a node that is used during the construction
+ * of a schedule.
+ * space represents the original space in which the domain lives;
+ *	that is, the space is not affected by compression
+ * sched is a matrix representation of the schedule being constructed
+ *	for this node; if compressed is set, then this schedule is
+ *	defined over the compressed domain space
+ * sched_map is an isl_map representation of the same (partial) schedule
+ *	sched_map may be NULL; if compressed is set, then this map
+ *	is defined over the uncompressed domain space
+ * rank is the number of linearly independent rows in the linear part
+ *	of sched
+ * the rows of "vmap" represent a change of basis for the node
+ *	variables; the first rank rows span the linear part of
+ *	the schedule rows; the remaining rows are linearly independent
+ * the rows of "indep" represent linear combinations of the schedule
+ * coefficients that are non-zero when the schedule coefficients are
+ * linearly independent of previously computed schedule rows.
+ * start is the first variable in the LP problem in the sequences that
+ *	represents the schedule coefficients of this node
+ * nvar is the dimension of the domain
+ * nparam is the number of parameters or 0 if we are not constructing
+ *	a parametric schedule
+ *
+ * If compressed is set, then hull represents the constraints
+ * that were used to derive the compression, while compress and
+ * decompress map the original space to the compressed space and
+ * vice versa.
+ *
+ * scc is the index of SCC (or WCC) this node belongs to
+ *
+ * "cluster" is only used inside extract_clusters and identifies
+ * the cluster of SCCs that the node belongs to.
+ *
+ * coincident contains a boolean for each of the rows of the schedule,
+ * indicating whether the corresponding scheduling dimension satisfies
+ * the coincidence constraints in the sense that the corresponding
+ * dependence distances are zero.
+ *
+ * If the schedule_treat_coalescing option is set, then
+ * "sizes" contains the sizes of the (compressed) instance set
+ * in each direction.  If there is no fixed size in a given direction,
+ * then the corresponding size value is set to infinity.
+ * If the schedule_treat_coalescing option or the schedule_max_coefficient
+ * option is set, then "max" contains the maximal values for
+ * schedule coefficients of the (compressed) variables.  If no bound
+ * needs to be imposed on a particular variable, then the corresponding
+ * value is negative.
+ * If not NULL, then "bounds" contains a non-parametric set
+ * in the compressed space that is bounded by the size in each direction.
+ */
+struct isl_sched_node {
+	isl_space *space;
+	int	compressed;
+	isl_set	*hull;
+	isl_multi_aff *compress;
+	isl_multi_aff *decompress;
+	isl_mat *sched;
+	isl_map *sched_map;
+	int	 rank;
+	isl_mat *indep;
+	isl_mat *vmap;
+	int	 start;
+	int	 nvar;
+	int	 nparam;
+
+	int	 scc;
+	int	 cluster;
+
+	int	*coincident;
+
+	isl_multi_val *sizes;
+	isl_basic_set *bounds;
+	isl_vec *max;
+};
+
+static int node_has_tuples(const void *entry, const void *val)
+{
+	struct isl_sched_node *node = (struct isl_sched_node *)entry;
+	isl_space *space = (isl_space *) val;
+
+	return isl_space_has_equal_tuples(node->space, space);
+}
+
+static int node_scc_exactly(struct isl_sched_node *node, int scc)
+{
+	return node->scc == scc;
+}
+
+static int node_scc_at_most(struct isl_sched_node *node, int scc)
+{
+	return node->scc <= scc;
+}
+
+static int node_scc_at_least(struct isl_sched_node *node, int scc)
+{
+	return node->scc >= scc;
+}
+
+/* An edge in the dependence graph.  An edge may be used to
+ * ensure validity of the generated schedule, to minimize the dependence
+ * distance or both
+ *
+ * map is the dependence relation, with i -> j in the map if j depends on i
+ * tagged_condition and tagged_validity contain the union of all tagged
+ *	condition or conditional validity dependence relations that
+ *	specialize the dependence relation "map"; that is,
+ *	if (i -> a) -> (j -> b) is an element of "tagged_condition"
+ *	or "tagged_validity", then i -> j is an element of "map".
+ *	If these fields are NULL, then they represent the empty relation.
+ * src is the source node
+ * dst is the sink node
+ *
+ * types is a bit vector containing the types of this edge.
+ * validity is set if the edge is used to ensure correctness
+ * coincidence is used to enforce zero dependence distances
+ * proximity is set if the edge is used to minimize dependence distances
+ * condition is set if the edge represents a condition
+ *	for a conditional validity schedule constraint
+ * local can only be set for condition edges and indicates that
+ *	the dependence distance over the edge should be zero
+ * conditional_validity is set if the edge is used to conditionally
+ *	ensure correctness
+ *
+ * For validity edges, start and end mark the sequence of inequality
+ * constraints in the LP problem that encode the validity constraint
+ * corresponding to this edge.
+ *
+ * During clustering, an edge may be marked "no_merge" if it should
+ * not be used to merge clusters.
+ * The weight is also only used during clustering and it is
+ * an indication of how many schedule dimensions on either side
+ * of the schedule constraints can be aligned.
+ * If the weight is negative, then this means that this edge was postponed
+ * by has_bounded_distances or any_no_merge.  The original weight can
+ * be retrieved by adding 1 + graph->max_weight, with "graph"
+ * the graph containing this edge.
+ */
+struct isl_sched_edge {
+	isl_map *map;
+	isl_union_map *tagged_condition;
+	isl_union_map *tagged_validity;
+
+	struct isl_sched_node *src;
+	struct isl_sched_node *dst;
+
+	unsigned types;
+
+	int start;
+	int end;
+
+	int no_merge;
+	int weight;
+};
+
+/* Is "edge" marked as being of type "type"?
+ */
+static int is_type(struct isl_sched_edge *edge, enum isl_edge_type type)
+{
+	return ISL_FL_ISSET(edge->types, 1 << type);
+}
+
+/* Mark "edge" as being of type "type".
+ */
+static void set_type(struct isl_sched_edge *edge, enum isl_edge_type type)
+{
+	ISL_FL_SET(edge->types, 1 << type);
+}
+
+/* No longer mark "edge" as being of type "type"?
+ */
+static void clear_type(struct isl_sched_edge *edge, enum isl_edge_type type)
+{
+	ISL_FL_CLR(edge->types, 1 << type);
+}
+
+/* Is "edge" marked as a validity edge?
+ */
+static int is_validity(struct isl_sched_edge *edge)
+{
+	return is_type(edge, isl_edge_validity);
+}
+
+/* Mark "edge" as a validity edge.
+ */
+static void set_validity(struct isl_sched_edge *edge)
+{
+	set_type(edge, isl_edge_validity);
+}
+
+/* Is "edge" marked as a proximity edge?
+ */
+static int is_proximity(struct isl_sched_edge *edge)
+{
+	return is_type(edge, isl_edge_proximity);
+}
+
+/* Is "edge" marked as a local edge?
+ */
+static int is_local(struct isl_sched_edge *edge)
+{
+	return is_type(edge, isl_edge_local);
+}
+
+/* Mark "edge" as a local edge.
+ */
+static void set_local(struct isl_sched_edge *edge)
+{
+	set_type(edge, isl_edge_local);
+}
+
+/* No longer mark "edge" as a local edge.
+ */
+static void clear_local(struct isl_sched_edge *edge)
+{
+	clear_type(edge, isl_edge_local);
+}
+
+/* Is "edge" marked as a coincidence edge?
+ */
+static int is_coincidence(struct isl_sched_edge *edge)
+{
+	return is_type(edge, isl_edge_coincidence);
+}
+
+/* Is "edge" marked as a condition edge?
+ */
+static int is_condition(struct isl_sched_edge *edge)
+{
+	return is_type(edge, isl_edge_condition);
+}
+
+/* Is "edge" marked as a conditional validity edge?
+ */
+static int is_conditional_validity(struct isl_sched_edge *edge)
+{
+	return is_type(edge, isl_edge_conditional_validity);
+}
+
+/* Internal information about the dependence graph used during
+ * the construction of the schedule.
+ *
+ * intra_hmap is a cache, mapping dependence relations to their dual,
+ *	for dependences from a node to itself, possibly without
+ *	coefficients for the parameters
+ * intra_hmap_param is a cache, mapping dependence relations to their dual,
+ *	for dependences from a node to itself, including coefficients
+ *	for the parameters
+ * inter_hmap is a cache, mapping dependence relations to their dual,
+ *	for dependences between distinct nodes
+ * if compression is involved then the key for these maps
+ * is the original, uncompressed dependence relation, while
+ * the value is the dual of the compressed dependence relation.
+ *
+ * n is the number of nodes
+ * node is the list of nodes
+ * maxvar is the maximal number of variables over all nodes
+ * max_row is the allocated number of rows in the schedule
+ * n_row is the current (maximal) number of linearly independent
+ *	rows in the node schedules
+ * n_total_row is the current number of rows in the node schedules
+ * band_start is the starting row in the node schedules of the current band
+ * root is set to the the original dependence graph from which this graph
+ *	is derived through splitting.  If this graph is not the result of
+ *	splitting, then the root field points to the graph itself.
+ *
+ * sorted contains a list of node indices sorted according to the
+ *	SCC to which a node belongs
+ *
+ * n_edge is the number of edges
+ * edge is the list of edges
+ * max_edge contains the maximal number of edges of each type;
+ *	in particular, it contains the number of edges in the inital graph.
+ * edge_table contains pointers into the edge array, hashed on the source
+ *	and sink spaces; there is one such table for each type;
+ *	a given edge may be referenced from more than one table
+ *	if the corresponding relation appears in more than one of the
+ *	sets of dependences; however, for each type there is only
+ *	a single edge between a given pair of source and sink space
+ *	in the entire graph
+ *
+ * node_table contains pointers into the node array, hashed on the space tuples
+ *
+ * region contains a list of variable sequences that should be non-trivial
+ *
+ * lp contains the (I)LP problem used to obtain new schedule rows
+ *
+ * src_scc and dst_scc are the source and sink SCCs of an edge with
+ *	conflicting constraints
+ *
+ * scc represents the number of components
+ * weak is set if the components are weakly connected
+ *
+ * max_weight is used during clustering and represents the maximal
+ * weight of the relevant proximity edges.
+ */
+struct isl_sched_graph {
+	isl_map_to_basic_set *intra_hmap;
+	isl_map_to_basic_set *intra_hmap_param;
+	isl_map_to_basic_set *inter_hmap;
+
+	struct isl_sched_node *node;
+	int n;
+	int maxvar;
+	int max_row;
+	int n_row;
+
+	int *sorted;
+
+	int n_total_row;
+	int band_start;
+
+	struct isl_sched_graph *root;
+
+	struct isl_sched_edge *edge;
+	int n_edge;
+	int max_edge[isl_edge_last + 1];
+	struct isl_hash_table *edge_table[isl_edge_last + 1];
+
+	struct isl_hash_table *node_table;
+	struct isl_trivial_region *region;
+
+	isl_basic_set *lp;
+
+	int src_scc;
+	int dst_scc;
+
+	int scc;
+	int weak;
+
+	int max_weight;
+};
+
+/* Initialize node_table based on the list of nodes.
+ */
+static int graph_init_table(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i;
+
+	graph->node_table = isl_hash_table_alloc(ctx, graph->n);
+	if (!graph->node_table)
+		return -1;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_hash_table_entry *entry;
+		uint32_t hash;
+
+		hash = isl_space_get_tuple_hash(graph->node[i].space);
+		entry = isl_hash_table_find(ctx, graph->node_table, hash,
+					    &node_has_tuples,
+					    graph->node[i].space, 1);
+		if (!entry)
+			return -1;
+		entry->data = &graph->node[i];
+	}
+
+	return 0;
+}
+
+/* Return a pointer to the node that lives within the given space,
+ * or NULL if there is no such node.
+ */
+static struct isl_sched_node *graph_find_node(isl_ctx *ctx,
+	struct isl_sched_graph *graph, __isl_keep isl_space *space)
+{
+	struct isl_hash_table_entry *entry;
+	uint32_t hash;
+
+	hash = isl_space_get_tuple_hash(space);
+	entry = isl_hash_table_find(ctx, graph->node_table, hash,
+				    &node_has_tuples, space, 0);
+
+	return entry ? entry->data : NULL;
+}
+
+/* Is "node" a node in "graph"?
+ */
+static int is_node(struct isl_sched_graph *graph,
+	struct isl_sched_node *node)
+{
+	return node && node >= &graph->node[0] && node < &graph->node[graph->n];
+}
+
+static int edge_has_src_and_dst(const void *entry, const void *val)
+{
+	const struct isl_sched_edge *edge = entry;
+	const struct isl_sched_edge *temp = val;
+
+	return edge->src == temp->src && edge->dst == temp->dst;
+}
+
+/* Add the given edge to graph->edge_table[type].
+ */
+static isl_stat graph_edge_table_add(isl_ctx *ctx,
+	struct isl_sched_graph *graph, enum isl_edge_type type,
+	struct isl_sched_edge *edge)
+{
+	struct isl_hash_table_entry *entry;
+	uint32_t hash;
+
+	hash = isl_hash_init();
+	hash = isl_hash_builtin(hash, edge->src);
+	hash = isl_hash_builtin(hash, edge->dst);
+	entry = isl_hash_table_find(ctx, graph->edge_table[type], hash,
+				    &edge_has_src_and_dst, edge, 1);
+	if (!entry)
+		return isl_stat_error;
+	entry->data = edge;
+
+	return isl_stat_ok;
+}
+
+/* Allocate the edge_tables based on the maximal number of edges of
+ * each type.
+ */
+static int graph_init_edge_tables(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i;
+
+	for (i = 0; i <= isl_edge_last; ++i) {
+		graph->edge_table[i] = isl_hash_table_alloc(ctx,
+							    graph->max_edge[i]);
+		if (!graph->edge_table[i])
+			return -1;
+	}
+
+	return 0;
+}
+
+/* If graph->edge_table[type] contains an edge from the given source
+ * to the given destination, then return the hash table entry of this edge.
+ * Otherwise, return NULL.
+ */
+static struct isl_hash_table_entry *graph_find_edge_entry(
+	struct isl_sched_graph *graph,
+	enum isl_edge_type type,
+	struct isl_sched_node *src, struct isl_sched_node *dst)
+{
+	isl_ctx *ctx = isl_space_get_ctx(src->space);
+	uint32_t hash;
+	struct isl_sched_edge temp = { .src = src, .dst = dst };
+
+	hash = isl_hash_init();
+	hash = isl_hash_builtin(hash, temp.src);
+	hash = isl_hash_builtin(hash, temp.dst);
+	return isl_hash_table_find(ctx, graph->edge_table[type], hash,
+				    &edge_has_src_and_dst, &temp, 0);
+}
+
+
+/* If graph->edge_table[type] contains an edge from the given source
+ * to the given destination, then return this edge.
+ * Otherwise, return NULL.
+ */
+static struct isl_sched_edge *graph_find_edge(struct isl_sched_graph *graph,
+	enum isl_edge_type type,
+	struct isl_sched_node *src, struct isl_sched_node *dst)
+{
+	struct isl_hash_table_entry *entry;
+
+	entry = graph_find_edge_entry(graph, type, src, dst);
+	if (!entry)
+		return NULL;
+
+	return entry->data;
+}
+
+/* Check whether the dependence graph has an edge of the given type
+ * between the given two nodes.
+ */
+static isl_bool graph_has_edge(struct isl_sched_graph *graph,
+	enum isl_edge_type type,
+	struct isl_sched_node *src, struct isl_sched_node *dst)
+{
+	struct isl_sched_edge *edge;
+	isl_bool empty;
+
+	edge = graph_find_edge(graph, type, src, dst);
+	if (!edge)
+		return 0;
+
+	empty = isl_map_plain_is_empty(edge->map);
+	if (empty < 0)
+		return isl_bool_error;
+
+	return !empty;
+}
+
+/* Look for any edge with the same src, dst and map fields as "model".
+ *
+ * Return the matching edge if one can be found.
+ * Return "model" if no matching edge is found.
+ * Return NULL on error.
+ */
+static struct isl_sched_edge *graph_find_matching_edge(
+	struct isl_sched_graph *graph, struct isl_sched_edge *model)
+{
+	enum isl_edge_type i;
+	struct isl_sched_edge *edge;
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		int is_equal;
+
+		edge = graph_find_edge(graph, i, model->src, model->dst);
+		if (!edge)
+			continue;
+		is_equal = isl_map_plain_is_equal(model->map, edge->map);
+		if (is_equal < 0)
+			return NULL;
+		if (is_equal)
+			return edge;
+	}
+
+	return model;
+}
+
+/* Remove the given edge from all the edge_tables that refer to it.
+ */
+static void graph_remove_edge(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge)
+{
+	isl_ctx *ctx = isl_map_get_ctx(edge->map);
+	enum isl_edge_type i;
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		struct isl_hash_table_entry *entry;
+
+		entry = graph_find_edge_entry(graph, i, edge->src, edge->dst);
+		if (!entry)
+			continue;
+		if (entry->data != edge)
+			continue;
+		isl_hash_table_remove(ctx, graph->edge_table[i], entry);
+	}
+}
+
+/* Check whether the dependence graph has any edge
+ * between the given two nodes.
+ */
+static isl_bool graph_has_any_edge(struct isl_sched_graph *graph,
+	struct isl_sched_node *src, struct isl_sched_node *dst)
+{
+	enum isl_edge_type i;
+	isl_bool r;
+
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		r = graph_has_edge(graph, i, src, dst);
+		if (r < 0 || r)
+			return r;
+	}
+
+	return r;
+}
+
+/* Check whether the dependence graph has a validity edge
+ * between the given two nodes.
+ *
+ * Conditional validity edges are essentially validity edges that
+ * can be ignored if the corresponding condition edges are iteration private.
+ * Here, we are only checking for the presence of validity
+ * edges, so we need to consider the conditional validity edges too.
+ * In particular, this function is used during the detection
+ * of strongly connected components and we cannot ignore
+ * conditional validity edges during this detection.
+ */
+static isl_bool graph_has_validity_edge(struct isl_sched_graph *graph,
+	struct isl_sched_node *src, struct isl_sched_node *dst)
+{
+	isl_bool r;
+
+	r = graph_has_edge(graph, isl_edge_validity, src, dst);
+	if (r < 0 || r)
+		return r;
+
+	return graph_has_edge(graph, isl_edge_conditional_validity, src, dst);
+}
+
+static int graph_alloc(isl_ctx *ctx, struct isl_sched_graph *graph,
+	int n_node, int n_edge)
+{
+	int i;
+
+	graph->n = n_node;
+	graph->n_edge = n_edge;
+	graph->node = isl_calloc_array(ctx, struct isl_sched_node, graph->n);
+	graph->sorted = isl_calloc_array(ctx, int, graph->n);
+	graph->region = isl_alloc_array(ctx,
+					struct isl_trivial_region, graph->n);
+	graph->edge = isl_calloc_array(ctx,
+					struct isl_sched_edge, graph->n_edge);
+
+	graph->intra_hmap = isl_map_to_basic_set_alloc(ctx, 2 * n_edge);
+	graph->intra_hmap_param = isl_map_to_basic_set_alloc(ctx, 2 * n_edge);
+	graph->inter_hmap = isl_map_to_basic_set_alloc(ctx, 2 * n_edge);
+
+	if (!graph->node || !graph->region || (graph->n_edge && !graph->edge) ||
+	    !graph->sorted)
+		return -1;
+
+	for(i = 0; i < graph->n; ++i)
+		graph->sorted[i] = i;
+
+	return 0;
+}
+
+static void graph_free(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i;
+
+	isl_map_to_basic_set_free(graph->intra_hmap);
+	isl_map_to_basic_set_free(graph->intra_hmap_param);
+	isl_map_to_basic_set_free(graph->inter_hmap);
+
+	if (graph->node)
+		for (i = 0; i < graph->n; ++i) {
+			isl_space_free(graph->node[i].space);
+			isl_set_free(graph->node[i].hull);
+			isl_multi_aff_free(graph->node[i].compress);
+			isl_multi_aff_free(graph->node[i].decompress);
+			isl_mat_free(graph->node[i].sched);
+			isl_map_free(graph->node[i].sched_map);
+			isl_mat_free(graph->node[i].indep);
+			isl_mat_free(graph->node[i].vmap);
+			if (graph->root == graph)
+				free(graph->node[i].coincident);
+			isl_multi_val_free(graph->node[i].sizes);
+			isl_basic_set_free(graph->node[i].bounds);
+			isl_vec_free(graph->node[i].max);
+		}
+	free(graph->node);
+	free(graph->sorted);
+	if (graph->edge)
+		for (i = 0; i < graph->n_edge; ++i) {
+			isl_map_free(graph->edge[i].map);
+			isl_union_map_free(graph->edge[i].tagged_condition);
+			isl_union_map_free(graph->edge[i].tagged_validity);
+		}
+	free(graph->edge);
+	free(graph->region);
+	for (i = 0; i <= isl_edge_last; ++i)
+		isl_hash_table_free(ctx, graph->edge_table[i]);
+	isl_hash_table_free(ctx, graph->node_table);
+	isl_basic_set_free(graph->lp);
+}
+
+/* For each "set" on which this function is called, increment
+ * graph->n by one and update graph->maxvar.
+ */
+static isl_stat init_n_maxvar(__isl_take isl_set *set, void *user)
+{
+	struct isl_sched_graph *graph = user;
+	int nvar = isl_set_dim(set, isl_dim_set);
+
+	graph->n++;
+	if (nvar > graph->maxvar)
+		graph->maxvar = nvar;
+
+	isl_set_free(set);
+
+	return isl_stat_ok;
+}
+
+/* Compute the number of rows that should be allocated for the schedule.
+ * In particular, we need one row for each variable or one row
+ * for each basic map in the dependences.
+ * Note that it is practically impossible to exhaust both
+ * the number of dependences and the number of variables.
+ */
+static isl_stat compute_max_row(struct isl_sched_graph *graph,
+	__isl_keep isl_schedule_constraints *sc)
+{
+	int n_edge;
+	isl_stat r;
+	isl_union_set *domain;
+
+	graph->n = 0;
+	graph->maxvar = 0;
+	domain = isl_schedule_constraints_get_domain(sc);
+	r = isl_union_set_foreach_set(domain, &init_n_maxvar, graph);
+	isl_union_set_free(domain);
+	if (r < 0)
+		return isl_stat_error;
+	n_edge = isl_schedule_constraints_n_basic_map(sc);
+	if (n_edge < 0)
+		return isl_stat_error;
+	graph->max_row = n_edge + graph->maxvar;
+
+	return isl_stat_ok;
+}
+
+/* Does "bset" have any defining equalities for its set variables?
+ */
+static isl_bool has_any_defining_equality(__isl_keep isl_basic_set *bset)
+{
+	int i, n;
+
+	if (!bset)
+		return isl_bool_error;
+
+	n = isl_basic_set_dim(bset, isl_dim_set);
+	for (i = 0; i < n; ++i) {
+		isl_bool has;
+
+		has = isl_basic_set_has_defining_equality(bset, isl_dim_set, i,
+							NULL);
+		if (has < 0 || has)
+			return has;
+	}
+
+	return isl_bool_false;
+}
+
+/* Set the entries of node->max to the value of the schedule_max_coefficient
+ * option, if set.
+ */
+static isl_stat set_max_coefficient(isl_ctx *ctx, struct isl_sched_node *node)
+{
+	int max;
+
+	max = isl_options_get_schedule_max_coefficient(ctx);
+	if (max == -1)
+		return isl_stat_ok;
+
+	node->max = isl_vec_alloc(ctx, node->nvar);
+	node->max = isl_vec_set_si(node->max, max);
+	if (!node->max)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Set the entries of node->max to the minimum of the schedule_max_coefficient
+ * option (if set) and half of the minimum of the sizes in the other
+ * dimensions.  Round up when computing the half such that
+ * if the minimum of the sizes is one, half of the size is taken to be one
+ * rather than zero.
+ * If the global minimum is unbounded (i.e., if both
+ * the schedule_max_coefficient is not set and the sizes in the other
+ * dimensions are unbounded), then store a negative value.
+ * If the schedule coefficient is close to the size of the instance set
+ * in another dimension, then the schedule may represent a loop
+ * coalescing transformation (especially if the coefficient
+ * in that other dimension is one).  Forcing the coefficient to be
+ * smaller than or equal to half the minimal size should avoid this
+ * situation.
+ */
+static isl_stat compute_max_coefficient(isl_ctx *ctx,
+	struct isl_sched_node *node)
+{
+	int max;
+	int i, j;
+	isl_vec *v;
+
+	max = isl_options_get_schedule_max_coefficient(ctx);
+	v = isl_vec_alloc(ctx, node->nvar);
+	if (!v)
+		return isl_stat_error;
+
+	for (i = 0; i < node->nvar; ++i) {
+		isl_int_set_si(v->el[i], max);
+		isl_int_mul_si(v->el[i], v->el[i], 2);
+	}
+
+	for (i = 0; i < node->nvar; ++i) {
+		isl_val *size;
+
+		size = isl_multi_val_get_val(node->sizes, i);
+		if (!size)
+			goto error;
+		if (!isl_val_is_int(size)) {
+			isl_val_free(size);
+			continue;
+		}
+		for (j = 0; j < node->nvar; ++j) {
+			if (j == i)
+				continue;
+			if (isl_int_is_neg(v->el[j]) ||
+			    isl_int_gt(v->el[j], size->n))
+				isl_int_set(v->el[j], size->n);
+		}
+		isl_val_free(size);
+	}
+
+	for (i = 0; i < node->nvar; ++i)
+		isl_int_cdiv_q_ui(v->el[i], v->el[i], 2);
+
+	node->max = v;
+	return isl_stat_ok;
+error:
+	isl_vec_free(v);
+	return isl_stat_error;
+}
+
+/* Compute and return the size of "set" in dimension "dim".
+ * The size is taken to be the difference in values for that variable
+ * for fixed values of the other variables.
+ * In particular, the variable is first isolated from the other variables
+ * in the range of a map
+ *
+ *	[i_0, ..., i_dim-1, i_dim+1, ...] -> [i_dim]
+ *
+ * and then duplicated
+ *
+ *	[i_0, ..., i_dim-1, i_dim+1, ...] -> [[i_dim] -> [i_dim']]
+ *
+ * The shared variables are then projected out and the maximal value
+ * of i_dim' - i_dim is computed.
+ */
+static __isl_give isl_val *compute_size(__isl_take isl_set *set, int dim)
+{
+	isl_map *map;
+	isl_local_space *ls;
+	isl_aff *obj;
+	isl_val *v;
+
+	map = isl_set_project_onto_map(set, isl_dim_set, dim, 1);
+	map = isl_map_project_out(map, isl_dim_in, dim, 1);
+	map = isl_map_range_product(map, isl_map_copy(map));
+	map = isl_set_unwrap(isl_map_range(map));
+	set = isl_map_deltas(map);
+	ls = isl_local_space_from_space(isl_set_get_space(set));
+	obj = isl_aff_var_on_domain(ls, isl_dim_set, 0);
+	v = isl_set_max_val(set, obj);
+	isl_aff_free(obj);
+	isl_set_free(set);
+
+	return v;
+}
+
+/* Compute the size of the instance set "set" of "node", after compression,
+ * as well as bounds on the corresponding coefficients, if needed.
+ *
+ * The sizes are needed when the schedule_treat_coalescing option is set.
+ * The bounds are needed when the schedule_treat_coalescing option or
+ * the schedule_max_coefficient option is set.
+ *
+ * If the schedule_treat_coalescing option is not set, then at most
+ * the bounds need to be set and this is done in set_max_coefficient.
+ * Otherwise, compress the domain if needed, compute the size
+ * in each direction and store the results in node->size.
+ * Finally, set the bounds on the coefficients based on the sizes
+ * and the schedule_max_coefficient option in compute_max_coefficient.
+ */
+static isl_stat compute_sizes_and_max(isl_ctx *ctx, struct isl_sched_node *node,
+	__isl_take isl_set *set)
+{
+	int j, n;
+	isl_multi_val *mv;
+
+	if (!isl_options_get_schedule_treat_coalescing(ctx)) {
+		isl_set_free(set);
+		return set_max_coefficient(ctx, node);
+	}
+
+	if (node->compressed)
+		set = isl_set_preimage_multi_aff(set,
+					isl_multi_aff_copy(node->decompress));
+	mv = isl_multi_val_zero(isl_set_get_space(set));
+	n = isl_set_dim(set, isl_dim_set);
+	for (j = 0; j < n; ++j) {
+		isl_val *v;
+
+		v = compute_size(isl_set_copy(set), j);
+		mv = isl_multi_val_set_val(mv, j, v);
+	}
+	node->sizes = mv;
+	isl_set_free(set);
+	if (!node->sizes)
+		return isl_stat_error;
+	return compute_max_coefficient(ctx, node);
+}
+
+/* Add a new node to the graph representing the given instance set.
+ * "nvar" is the (possibly compressed) number of variables and
+ * may be smaller than then number of set variables in "set"
+ * if "compressed" is set.
+ * If "compressed" is set, then "hull" represents the constraints
+ * that were used to derive the compression, while "compress" and
+ * "decompress" map the original space to the compressed space and
+ * vice versa.
+ * If "compressed" is not set, then "hull", "compress" and "decompress"
+ * should be NULL.
+ *
+ * Compute the size of the instance set and bounds on the coefficients,
+ * if needed.
+ */
+static isl_stat add_node(struct isl_sched_graph *graph,
+	__isl_take isl_set *set, int nvar, int compressed,
+	__isl_take isl_set *hull, __isl_take isl_multi_aff *compress,
+	__isl_take isl_multi_aff *decompress)
+{
+	int nparam;
+	isl_ctx *ctx;
+	isl_mat *sched;
+	isl_space *space;
+	int *coincident;
+	struct isl_sched_node *node;
+
+	if (!set)
+		return isl_stat_error;
+
+	ctx = isl_set_get_ctx(set);
+	nparam = isl_set_dim(set, isl_dim_param);
+	if (!ctx->opt->schedule_parametric)
+		nparam = 0;
+	sched = isl_mat_alloc(ctx, 0, 1 + nparam + nvar);
+	node = &graph->node[graph->n];
+	graph->n++;
+	space = isl_set_get_space(set);
+	node->space = space;
+	node->nvar = nvar;
+	node->nparam = nparam;
+	node->sched = sched;
+	node->sched_map = NULL;
+	coincident = isl_calloc_array(ctx, int, graph->max_row);
+	node->coincident = coincident;
+	node->compressed = compressed;
+	node->hull = hull;
+	node->compress = compress;
+	node->decompress = decompress;
+	if (compute_sizes_and_max(ctx, node, set) < 0)
+		return isl_stat_error;
+
+	if (!space || !sched || (graph->max_row && !coincident))
+		return isl_stat_error;
+	if (compressed && (!hull || !compress || !decompress))
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Construct an identifier for node "node", which will represent "set".
+ * The name of the identifier is either "compressed" or
+ * "compressed_<name>", with <name> the name of the space of "set".
+ * The user pointer of the identifier points to "node".
+ */
+static __isl_give isl_id *construct_compressed_id(__isl_keep isl_set *set,
+	struct isl_sched_node *node)
+{
+	isl_bool has_name;
+	isl_ctx *ctx;
+	isl_id *id;
+	isl_printer *p;
+	const char *name;
+	char *id_name;
+
+	has_name = isl_set_has_tuple_name(set);
+	if (has_name < 0)
+		return NULL;
+
+	ctx = isl_set_get_ctx(set);
+	if (!has_name)
+		return isl_id_alloc(ctx, "compressed", node);
+
+	p = isl_printer_to_str(ctx);
+	name = isl_set_get_tuple_name(set);
+	p = isl_printer_print_str(p, "compressed_");
+	p = isl_printer_print_str(p, name);
+	id_name = isl_printer_get_str(p);
+	isl_printer_free(p);
+
+	id = isl_id_alloc(ctx, id_name, node);
+	free(id_name);
+
+	return id;
+}
+
+/* Add a new node to the graph representing the given set.
+ *
+ * If any of the set variables is defined by an equality, then
+ * we perform variable compression such that we can perform
+ * the scheduling on the compressed domain.
+ * In this case, an identifier is used that references the new node
+ * such that each compressed space is unique and
+ * such that the node can be recovered from the compressed space.
+ */
+static isl_stat extract_node(__isl_take isl_set *set, void *user)
+{
+	int nvar;
+	isl_bool has_equality;
+	isl_id *id;
+	isl_basic_set *hull;
+	isl_set *hull_set;
+	isl_morph *morph;
+	isl_multi_aff *compress, *decompress;
+	struct isl_sched_graph *graph = user;
+
+	hull = isl_set_affine_hull(isl_set_copy(set));
+	hull = isl_basic_set_remove_divs(hull);
+	nvar = isl_set_dim(set, isl_dim_set);
+	has_equality = has_any_defining_equality(hull);
+
+	if (has_equality < 0)
+		goto error;
+	if (!has_equality) {
+		isl_basic_set_free(hull);
+		return add_node(graph, set, nvar, 0, NULL, NULL, NULL);
+	}
+
+	id = construct_compressed_id(set, &graph->node[graph->n]);
+	morph = isl_basic_set_variable_compression_with_id(hull,
+							    isl_dim_set, id);
+	isl_id_free(id);
+	nvar = isl_morph_ran_dim(morph, isl_dim_set);
+	compress = isl_morph_get_var_multi_aff(morph);
+	morph = isl_morph_inverse(morph);
+	decompress = isl_morph_get_var_multi_aff(morph);
+	isl_morph_free(morph);
+
+	hull_set = isl_set_from_basic_set(hull);
+	return add_node(graph, set, nvar, 1, hull_set, compress, decompress);
+error:
+	isl_basic_set_free(hull);
+	isl_set_free(set);
+	return isl_stat_error;
+}
+
+struct isl_extract_edge_data {
+	enum isl_edge_type type;
+	struct isl_sched_graph *graph;
+};
+
+/* Merge edge2 into edge1, freeing the contents of edge2.
+ * Return 0 on success and -1 on failure.
+ *
+ * edge1 and edge2 are assumed to have the same value for the map field.
+ */
+static int merge_edge(struct isl_sched_edge *edge1,
+	struct isl_sched_edge *edge2)
+{
+	edge1->types |= edge2->types;
+	isl_map_free(edge2->map);
+
+	if (is_condition(edge2)) {
+		if (!edge1->tagged_condition)
+			edge1->tagged_condition = edge2->tagged_condition;
+		else
+			edge1->tagged_condition =
+				isl_union_map_union(edge1->tagged_condition,
+						    edge2->tagged_condition);
+	}
+
+	if (is_conditional_validity(edge2)) {
+		if (!edge1->tagged_validity)
+			edge1->tagged_validity = edge2->tagged_validity;
+		else
+			edge1->tagged_validity =
+				isl_union_map_union(edge1->tagged_validity,
+						    edge2->tagged_validity);
+	}
+
+	if (is_condition(edge2) && !edge1->tagged_condition)
+		return -1;
+	if (is_conditional_validity(edge2) && !edge1->tagged_validity)
+		return -1;
+
+	return 0;
+}
+
+/* Insert dummy tags in domain and range of "map".
+ *
+ * In particular, if "map" is of the form
+ *
+ *	A -> B
+ *
+ * then return
+ *
+ *	[A -> dummy_tag] -> [B -> dummy_tag]
+ *
+ * where the dummy_tags are identical and equal to any dummy tags
+ * introduced by any other call to this function.
+ */
+static __isl_give isl_map *insert_dummy_tags(__isl_take isl_map *map)
+{
+	static char dummy;
+	isl_ctx *ctx;
+	isl_id *id;
+	isl_space *space;
+	isl_set *domain, *range;
+
+	ctx = isl_map_get_ctx(map);
+
+	id = isl_id_alloc(ctx, NULL, &dummy);
+	space = isl_space_params(isl_map_get_space(map));
+	space = isl_space_set_from_params(space);
+	space = isl_space_set_tuple_id(space, isl_dim_set, id);
+	space = isl_space_map_from_set(space);
+
+	domain = isl_map_wrap(map);
+	range = isl_map_wrap(isl_map_universe(space));
+	map = isl_map_from_domain_and_range(domain, range);
+	map = isl_map_zip(map);
+
+	return map;
+}
+
+/* Given that at least one of "src" or "dst" is compressed, return
+ * a map between the spaces of these nodes restricted to the affine
+ * hull that was used in the compression.
+ */
+static __isl_give isl_map *extract_hull(struct isl_sched_node *src,
+	struct isl_sched_node *dst)
+{
+	isl_set *dom, *ran;
+
+	if (src->compressed)
+		dom = isl_set_copy(src->hull);
+	else
+		dom = isl_set_universe(isl_space_copy(src->space));
+	if (dst->compressed)
+		ran = isl_set_copy(dst->hull);
+	else
+		ran = isl_set_universe(isl_space_copy(dst->space));
+
+	return isl_map_from_domain_and_range(dom, ran);
+}
+
+/* Intersect the domains of the nested relations in domain and range
+ * of "tagged" with "map".
+ */
+static __isl_give isl_map *map_intersect_domains(__isl_take isl_map *tagged,
+	__isl_keep isl_map *map)
+{
+	isl_set *set;
+
+	tagged = isl_map_zip(tagged);
+	set = isl_map_wrap(isl_map_copy(map));
+	tagged = isl_map_intersect_domain(tagged, set);
+	tagged = isl_map_zip(tagged);
+	return tagged;
+}
+
+/* Return a pointer to the node that lives in the domain space of "map"
+ * or NULL if there is no such node.
+ */
+static struct isl_sched_node *find_domain_node(isl_ctx *ctx,
+	struct isl_sched_graph *graph, __isl_keep isl_map *map)
+{
+	struct isl_sched_node *node;
+	isl_space *space;
+
+	space = isl_space_domain(isl_map_get_space(map));
+	node = graph_find_node(ctx, graph, space);
+	isl_space_free(space);
+
+	return node;
+}
+
+/* Return a pointer to the node that lives in the range space of "map"
+ * or NULL if there is no such node.
+ */
+static struct isl_sched_node *find_range_node(isl_ctx *ctx,
+	struct isl_sched_graph *graph, __isl_keep isl_map *map)
+{
+	struct isl_sched_node *node;
+	isl_space *space;
+
+	space = isl_space_range(isl_map_get_space(map));
+	node = graph_find_node(ctx, graph, space);
+	isl_space_free(space);
+
+	return node;
+}
+
+/* Add a new edge to the graph based on the given map
+ * and add it to data->graph->edge_table[data->type].
+ * If a dependence relation of a given type happens to be identical
+ * to one of the dependence relations of a type that was added before,
+ * then we don't create a new edge, but instead mark the original edge
+ * as also representing a dependence of the current type.
+ *
+ * Edges of type isl_edge_condition or isl_edge_conditional_validity
+ * may be specified as "tagged" dependence relations.  That is, "map"
+ * may contain elements (i -> a) -> (j -> b), where i -> j denotes
+ * the dependence on iterations and a and b are tags.
+ * edge->map is set to the relation containing the elements i -> j,
+ * while edge->tagged_condition and edge->tagged_validity contain
+ * the union of all the "map" relations
+ * for which extract_edge is called that result in the same edge->map.
+ *
+ * If the source or the destination node is compressed, then
+ * intersect both "map" and "tagged" with the constraints that
+ * were used to construct the compression.
+ * This ensures that there are no schedule constraints defined
+ * outside of these domains, while the scheduler no longer has
+ * any control over those outside parts.
+ */
+static isl_stat extract_edge(__isl_take isl_map *map, void *user)
+{
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	struct isl_extract_edge_data *data = user;
+	struct isl_sched_graph *graph = data->graph;
+	struct isl_sched_node *src, *dst;
+	struct isl_sched_edge *edge;
+	isl_map *tagged = NULL;
+
+	if (data->type == isl_edge_condition ||
+	    data->type == isl_edge_conditional_validity) {
+		if (isl_map_can_zip(map)) {
+			tagged = isl_map_copy(map);
+			map = isl_set_unwrap(isl_map_domain(isl_map_zip(map)));
+		} else {
+			tagged = insert_dummy_tags(isl_map_copy(map));
+		}
+	}
+
+	src = find_domain_node(ctx, graph, map);
+	dst = find_range_node(ctx, graph, map);
+
+	if (!src || !dst) {
+		isl_map_free(map);
+		isl_map_free(tagged);
+		return isl_stat_ok;
+	}
+
+	if (src->compressed || dst->compressed) {
+		isl_map *hull;
+		hull = extract_hull(src, dst);
+		if (tagged)
+			tagged = map_intersect_domains(tagged, hull);
+		map = isl_map_intersect(map, hull);
+	}
+
+	graph->edge[graph->n_edge].src = src;
+	graph->edge[graph->n_edge].dst = dst;
+	graph->edge[graph->n_edge].map = map;
+	graph->edge[graph->n_edge].types = 0;
+	graph->edge[graph->n_edge].tagged_condition = NULL;
+	graph->edge[graph->n_edge].tagged_validity = NULL;
+	set_type(&graph->edge[graph->n_edge], data->type);
+	if (data->type == isl_edge_condition)
+		graph->edge[graph->n_edge].tagged_condition =
+					isl_union_map_from_map(tagged);
+	if (data->type == isl_edge_conditional_validity)
+		graph->edge[graph->n_edge].tagged_validity =
+					isl_union_map_from_map(tagged);
+
+	edge = graph_find_matching_edge(graph, &graph->edge[graph->n_edge]);
+	if (!edge) {
+		graph->n_edge++;
+		return isl_stat_error;
+	}
+	if (edge == &graph->edge[graph->n_edge])
+		return graph_edge_table_add(ctx, graph, data->type,
+				    &graph->edge[graph->n_edge++]);
+
+	if (merge_edge(edge, &graph->edge[graph->n_edge]) < 0)
+		return -1;
+
+	return graph_edge_table_add(ctx, graph, data->type, edge);
+}
+
+/* Initialize the schedule graph "graph" from the schedule constraints "sc".
+ *
+ * The context is included in the domain before the nodes of
+ * the graphs are extracted in order to be able to exploit
+ * any possible additional equalities.
+ * Note that this intersection is only performed locally here.
+ */
+static isl_stat graph_init(struct isl_sched_graph *graph,
+	__isl_keep isl_schedule_constraints *sc)
+{
+	isl_ctx *ctx;
+	isl_union_set *domain;
+	isl_union_map *c;
+	struct isl_extract_edge_data data;
+	enum isl_edge_type i;
+	isl_stat r;
+
+	if (!sc)
+		return isl_stat_error;
+
+	ctx = isl_schedule_constraints_get_ctx(sc);
+
+	domain = isl_schedule_constraints_get_domain(sc);
+	graph->n = isl_union_set_n_set(domain);
+	isl_union_set_free(domain);
+
+	if (graph_alloc(ctx, graph, graph->n,
+	    isl_schedule_constraints_n_map(sc)) < 0)
+		return isl_stat_error;
+
+	if (compute_max_row(graph, sc) < 0)
+		return isl_stat_error;
+	graph->root = graph;
+	graph->n = 0;
+	domain = isl_schedule_constraints_get_domain(sc);
+	domain = isl_union_set_intersect_params(domain,
+				    isl_schedule_constraints_get_context(sc));
+	r = isl_union_set_foreach_set(domain, &extract_node, graph);
+	isl_union_set_free(domain);
+	if (r < 0)
+		return isl_stat_error;
+	if (graph_init_table(ctx, graph) < 0)
+		return isl_stat_error;
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		c = isl_schedule_constraints_get(sc, i);
+		graph->max_edge[i] = isl_union_map_n_map(c);
+		isl_union_map_free(c);
+		if (!c)
+			return isl_stat_error;
+	}
+	if (graph_init_edge_tables(ctx, graph) < 0)
+		return isl_stat_error;
+	graph->n_edge = 0;
+	data.graph = graph;
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		isl_stat r;
+
+		data.type = i;
+		c = isl_schedule_constraints_get(sc, i);
+		r = isl_union_map_foreach_map(c, &extract_edge, &data);
+		isl_union_map_free(c);
+		if (r < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Check whether there is any dependence from node[j] to node[i]
+ * or from node[i] to node[j].
+ */
+static isl_bool node_follows_weak(int i, int j, void *user)
+{
+	isl_bool f;
+	struct isl_sched_graph *graph = user;
+
+	f = graph_has_any_edge(graph, &graph->node[j], &graph->node[i]);
+	if (f < 0 || f)
+		return f;
+	return graph_has_any_edge(graph, &graph->node[i], &graph->node[j]);
+}
+
+/* Check whether there is a (conditional) validity dependence from node[j]
+ * to node[i], forcing node[i] to follow node[j].
+ */
+static isl_bool node_follows_strong(int i, int j, void *user)
+{
+	struct isl_sched_graph *graph = user;
+
+	return graph_has_validity_edge(graph, &graph->node[j], &graph->node[i]);
+}
+
+/* Use Tarjan's algorithm for computing the strongly connected components
+ * in the dependence graph only considering those edges defined by "follows".
+ */
+static int detect_ccs(isl_ctx *ctx, struct isl_sched_graph *graph,
+	isl_bool (*follows)(int i, int j, void *user))
+{
+	int i, n;
+	struct isl_tarjan_graph *g = NULL;
+
+	g = isl_tarjan_graph_init(ctx, graph->n, follows, graph);
+	if (!g)
+		return -1;
+
+	graph->scc = 0;
+	i = 0;
+	n = graph->n;
+	while (n) {
+		while (g->order[i] != -1) {
+			graph->node[g->order[i]].scc = graph->scc;
+			--n;
+			++i;
+		}
+		++i;
+		graph->scc++;
+	}
+
+	isl_tarjan_graph_free(g);
+
+	return 0;
+}
+
+/* Apply Tarjan's algorithm to detect the strongly connected components
+ * in the dependence graph.
+ * Only consider the (conditional) validity dependences and clear "weak".
+ */
+static int detect_sccs(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	graph->weak = 0;
+	return detect_ccs(ctx, graph, &node_follows_strong);
+}
+
+/* Apply Tarjan's algorithm to detect the (weakly) connected components
+ * in the dependence graph.
+ * Consider all dependences and set "weak".
+ */
+static int detect_wccs(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	graph->weak = 1;
+	return detect_ccs(ctx, graph, &node_follows_weak);
+}
+
+static int cmp_scc(const void *a, const void *b, void *data)
+{
+	struct isl_sched_graph *graph = data;
+	const int *i1 = a;
+	const int *i2 = b;
+
+	return graph->node[*i1].scc - graph->node[*i2].scc;
+}
+
+/* Sort the elements of graph->sorted according to the corresponding SCCs.
+ */
+static int sort_sccs(struct isl_sched_graph *graph)
+{
+	return isl_sort(graph->sorted, graph->n, sizeof(int), &cmp_scc, graph);
+}
+
+/* Return a non-parametric set in the compressed space of "node" that is
+ * bounded by the size in each direction
+ *
+ *	{ [x] : -S_i <= x_i <= S_i }
+ *
+ * If S_i is infinity in direction i, then there are no constraints
+ * in that direction.
+ *
+ * Cache the result in node->bounds.
+ */
+static __isl_give isl_basic_set *get_size_bounds(struct isl_sched_node *node)
+{
+	isl_space *space;
+	isl_basic_set *bounds;
+	int i;
+	unsigned nparam;
+
+	if (node->bounds)
+		return isl_basic_set_copy(node->bounds);
+
+	if (node->compressed)
+		space = isl_multi_aff_get_domain_space(node->decompress);
+	else
+		space = isl_space_copy(node->space);
+	nparam = isl_space_dim(space, isl_dim_param);
+	space = isl_space_drop_dims(space, isl_dim_param, 0, nparam);
+	bounds = isl_basic_set_universe(space);
+
+	for (i = 0; i < node->nvar; ++i) {
+		isl_val *size;
+
+		size = isl_multi_val_get_val(node->sizes, i);
+		if (!size)
+			return isl_basic_set_free(bounds);
+		if (!isl_val_is_int(size)) {
+			isl_val_free(size);
+			continue;
+		}
+		bounds = isl_basic_set_upper_bound_val(bounds, isl_dim_set, i,
+							isl_val_copy(size));
+		bounds = isl_basic_set_lower_bound_val(bounds, isl_dim_set, i,
+							isl_val_neg(size));
+	}
+
+	node->bounds = isl_basic_set_copy(bounds);
+	return bounds;
+}
+
+/* Drop some constraints from "delta" that could be exploited
+ * to construct loop coalescing schedules.
+ * In particular, drop those constraint that bound the difference
+ * to the size of the domain.
+ * First project out the parameters to improve the effectiveness.
+ */
+static __isl_give isl_set *drop_coalescing_constraints(
+	__isl_take isl_set *delta, struct isl_sched_node *node)
+{
+	unsigned nparam;
+	isl_basic_set *bounds;
+
+	bounds = get_size_bounds(node);
+
+	nparam = isl_set_dim(delta, isl_dim_param);
+	delta = isl_set_project_out(delta, isl_dim_param, 0, nparam);
+	delta = isl_set_remove_divs(delta);
+	delta = isl_set_plain_gist_basic_set(delta, bounds);
+	return delta;
+}
+
+/* Given a dependence relation R from "node" to itself,
+ * construct the set of coefficients of valid constraints for elements
+ * in that dependence relation.
+ * In particular, the result contains tuples of coefficients
+ * c_0, c_n, c_x such that
+ *
+ *	c_0 + c_n n + c_x y - c_x x >= 0 for each (x,y) in R
+ *
+ * or, equivalently,
+ *
+ *	c_0 + c_n n + c_x d >= 0 for each d in delta R = { y - x | (x,y) in R }
+ *
+ * We choose here to compute the dual of delta R.
+ * Alternatively, we could have computed the dual of R, resulting
+ * in a set of tuples c_0, c_n, c_x, c_y, and then
+ * plugged in (c_0, c_n, c_x, -c_x).
+ *
+ * If "need_param" is set, then the resulting coefficients effectively
+ * include coefficients for the parameters c_n.  Otherwise, they may
+ * have been projected out already.
+ * Since the constraints may be different for these two cases,
+ * they are stored in separate caches.
+ * In particular, if no parameter coefficients are required and
+ * the schedule_treat_coalescing option is set, then the parameters
+ * are projected out and some constraints that could be exploited
+ * to construct coalescing schedules are removed before the dual
+ * is computed.
+ *
+ * If "node" has been compressed, then the dependence relation
+ * is also compressed before the set of coefficients is computed.
+ */
+static __isl_give isl_basic_set *intra_coefficients(
+	struct isl_sched_graph *graph, struct isl_sched_node *node,
+	__isl_take isl_map *map, int need_param)
+{
+	isl_ctx *ctx;
+	isl_set *delta;
+	isl_map *key;
+	isl_basic_set *coef;
+	isl_maybe_isl_basic_set m;
+	isl_map_to_basic_set **hmap = &graph->intra_hmap;
+	int treat;
+
+	if (!map)
+		return NULL;
+
+	ctx = isl_map_get_ctx(map);
+	treat = !need_param && isl_options_get_schedule_treat_coalescing(ctx);
+	if (!treat)
+		hmap = &graph->intra_hmap_param;
+	m = isl_map_to_basic_set_try_get(*hmap, map);
+	if (m.valid < 0 || m.valid) {
+		isl_map_free(map);
+		return m.value;
+	}
+
+	key = isl_map_copy(map);
+	if (node->compressed) {
+		map = isl_map_preimage_domain_multi_aff(map,
+				    isl_multi_aff_copy(node->decompress));
+		map = isl_map_preimage_range_multi_aff(map,
+				    isl_multi_aff_copy(node->decompress));
+	}
+	delta = isl_map_deltas(map);
+	if (treat)
+		delta = drop_coalescing_constraints(delta, node);
+	delta = isl_set_remove_divs(delta);
+	coef = isl_set_coefficients(delta);
+	*hmap = isl_map_to_basic_set_set(*hmap, key, isl_basic_set_copy(coef));
+
+	return coef;
+}
+
+/* Given a dependence relation R, construct the set of coefficients
+ * of valid constraints for elements in that dependence relation.
+ * In particular, the result contains tuples of coefficients
+ * c_0, c_n, c_x, c_y such that
+ *
+ *	c_0 + c_n n + c_x x + c_y y >= 0 for each (x,y) in R
+ *
+ * If the source or destination nodes of "edge" have been compressed,
+ * then the dependence relation is also compressed before
+ * the set of coefficients is computed.
+ */
+static __isl_give isl_basic_set *inter_coefficients(
+	struct isl_sched_graph *graph, struct isl_sched_edge *edge,
+	__isl_take isl_map *map)
+{
+	isl_set *set;
+	isl_map *key;
+	isl_basic_set *coef;
+	isl_maybe_isl_basic_set m;
+
+	m = isl_map_to_basic_set_try_get(graph->inter_hmap, map);
+	if (m.valid < 0 || m.valid) {
+		isl_map_free(map);
+		return m.value;
+	}
+
+	key = isl_map_copy(map);
+	if (edge->src->compressed)
+		map = isl_map_preimage_domain_multi_aff(map,
+				    isl_multi_aff_copy(edge->src->decompress));
+	if (edge->dst->compressed)
+		map = isl_map_preimage_range_multi_aff(map,
+				    isl_multi_aff_copy(edge->dst->decompress));
+	set = isl_map_wrap(isl_map_remove_divs(map));
+	coef = isl_set_coefficients(set);
+	graph->inter_hmap = isl_map_to_basic_set_set(graph->inter_hmap, key,
+					isl_basic_set_copy(coef));
+
+	return coef;
+}
+
+/* Return the position of the coefficients of the variables in
+ * the coefficients constraints "coef".
+ *
+ * The space of "coef" is of the form
+ *
+ *	{ coefficients[[cst, params] -> S] }
+ *
+ * Return the position of S.
+ */
+static int coef_var_offset(__isl_keep isl_basic_set *coef)
+{
+	int offset;
+	isl_space *space;
+
+	space = isl_space_unwrap(isl_basic_set_get_space(coef));
+	offset = isl_space_dim(space, isl_dim_in);
+	isl_space_free(space);
+
+	return offset;
+}
+
+/* Return the offset of the coefficient of the constant term of "node"
+ * within the (I)LP.
+ *
+ * Within each node, the coefficients have the following order:
+ *	- positive and negative parts of c_i_x
+ *	- c_i_n (if parametric)
+ *	- c_i_0
+ */
+static int node_cst_coef_offset(struct isl_sched_node *node)
+{
+	return node->start + 2 * node->nvar + node->nparam;
+}
+
+/* Return the offset of the coefficients of the parameters of "node"
+ * within the (I)LP.
+ *
+ * Within each node, the coefficients have the following order:
+ *	- positive and negative parts of c_i_x
+ *	- c_i_n (if parametric)
+ *	- c_i_0
+ */
+static int node_par_coef_offset(struct isl_sched_node *node)
+{
+	return node->start + 2 * node->nvar;
+}
+
+/* Return the offset of the coefficients of the variables of "node"
+ * within the (I)LP.
+ *
+ * Within each node, the coefficients have the following order:
+ *	- positive and negative parts of c_i_x
+ *	- c_i_n (if parametric)
+ *	- c_i_0
+ */
+static int node_var_coef_offset(struct isl_sched_node *node)
+{
+	return node->start;
+}
+
+/* Return the position of the pair of variables encoding
+ * coefficient "i" of "node".
+ *
+ * The order of these variable pairs is the opposite of
+ * that of the coefficients, with 2 variables per coefficient.
+ */
+static int node_var_coef_pos(struct isl_sched_node *node, int i)
+{
+	return node_var_coef_offset(node) + 2 * (node->nvar - 1 - i);
+}
+
+/* Construct an isl_dim_map for mapping constraints on coefficients
+ * for "node" to the corresponding positions in graph->lp.
+ * "offset" is the offset of the coefficients for the variables
+ * in the input constraints.
+ * "s" is the sign of the mapping.
+ *
+ * The input constraints are given in terms of the coefficients
+ * (c_0, c_x) or (c_0, c_n, c_x).
+ * The mapping produced by this function essentially plugs in
+ * (0, c_i_x^+ - c_i_x^-) if s = 1 and
+ * (0, -c_i_x^+ + c_i_x^-) if s = -1 or
+ * (0, 0, c_i_x^+ - c_i_x^-) if s = 1 and
+ * (0, 0, -c_i_x^+ + c_i_x^-) if s = -1.
+ * In graph->lp, the c_i_x^- appear before their c_i_x^+ counterpart.
+ * Furthermore, the order of these pairs is the opposite of that
+ * of the corresponding coefficients.
+ *
+ * The caller can extend the mapping to also map the other coefficients
+ * (and therefore not plug in 0).
+ */
+static __isl_give isl_dim_map *intra_dim_map(isl_ctx *ctx,
+	struct isl_sched_graph *graph, struct isl_sched_node *node,
+	int offset, int s)
+{
+	int pos;
+	unsigned total;
+	isl_dim_map *dim_map;
+
+	if (!node)
+		return NULL;
+
+	total = isl_basic_set_total_dim(graph->lp);
+	pos = node_var_coef_pos(node, 0);
+	dim_map = isl_dim_map_alloc(ctx, total);
+	isl_dim_map_range(dim_map, pos, -2, offset, 1, node->nvar, -s);
+	isl_dim_map_range(dim_map, pos + 1, -2, offset, 1, node->nvar, s);
+
+	return dim_map;
+}
+
+/* Construct an isl_dim_map for mapping constraints on coefficients
+ * for "src" (node i) and "dst" (node j) to the corresponding positions
+ * in graph->lp.
+ * "offset" is the offset of the coefficients for the variables of "src"
+ * in the input constraints.
+ * "s" is the sign of the mapping.
+ *
+ * The input constraints are given in terms of the coefficients
+ * (c_0, c_n, c_x, c_y).
+ * The mapping produced by this function essentially plugs in
+ * (c_j_0 - c_i_0, c_j_n - c_i_n,
+ *  -(c_i_x^+ - c_i_x^-), c_j_x^+ - c_j_x^-) if s = 1 and
+ * (-c_j_0 + c_i_0, -c_j_n + c_i_n,
+ *  c_i_x^+ - c_i_x^-, -(c_j_x^+ - c_j_x^-)) if s = -1.
+ * In graph->lp, the c_*^- appear before their c_*^+ counterpart.
+ * Furthermore, the order of these pairs is the opposite of that
+ * of the corresponding coefficients.
+ *
+ * The caller can further extend the mapping.
+ */
+static __isl_give isl_dim_map *inter_dim_map(isl_ctx *ctx,
+	struct isl_sched_graph *graph, struct isl_sched_node *src,
+	struct isl_sched_node *dst, int offset, int s)
+{
+	int pos;
+	unsigned total;
+	isl_dim_map *dim_map;
+
+	if (!src || !dst)
+		return NULL;
+
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+
+	pos = node_cst_coef_offset(dst);
+	isl_dim_map_range(dim_map, pos, 0, 0, 0, 1, s);
+	pos = node_par_coef_offset(dst);
+	isl_dim_map_range(dim_map, pos, 1, 1, 1, dst->nparam, s);
+	pos = node_var_coef_pos(dst, 0);
+	isl_dim_map_range(dim_map, pos, -2, offset + src->nvar, 1,
+			  dst->nvar, -s);
+	isl_dim_map_range(dim_map, pos + 1, -2, offset + src->nvar, 1,
+			  dst->nvar, s);
+
+	pos = node_cst_coef_offset(src);
+	isl_dim_map_range(dim_map, pos, 0, 0, 0, 1, -s);
+	pos = node_par_coef_offset(src);
+	isl_dim_map_range(dim_map, pos, 1, 1, 1, src->nparam, -s);
+	pos = node_var_coef_pos(src, 0);
+	isl_dim_map_range(dim_map, pos, -2, offset, 1, src->nvar, s);
+	isl_dim_map_range(dim_map, pos + 1, -2, offset, 1, src->nvar, -s);
+
+	return dim_map;
+}
+
+/* Add the constraints from "src" to "dst" using "dim_map",
+ * after making sure there is enough room in "dst" for the extra constraints.
+ */
+static __isl_give isl_basic_set *add_constraints_dim_map(
+	__isl_take isl_basic_set *dst, __isl_take isl_basic_set *src,
+	__isl_take isl_dim_map *dim_map)
+{
+	int n_eq, n_ineq;
+
+	n_eq = isl_basic_set_n_equality(src);
+	n_ineq = isl_basic_set_n_inequality(src);
+	dst = isl_basic_set_extend_constraints(dst, n_eq, n_ineq);
+	dst = isl_basic_set_add_constraints_dim_map(dst, src, dim_map);
+	return dst;
+}
+
+/* Add constraints to graph->lp that force validity for the given
+ * dependence from a node i to itself.
+ * That is, add constraints that enforce
+ *
+ *	(c_i_0 + c_i_n n + c_i_x y) - (c_i_0 + c_i_n n + c_i_x x)
+ *	= c_i_x (y - x) >= 0
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_x)
+ * of valid constraints for (y - x) and then plug in (0, c_i_x^+ - c_i_x^-),
+ * where c_i_x = c_i_x^+ - c_i_x^-, with c_i_x^+ and c_i_x^- non-negative.
+ * In graph->lp, the c_i_x^- appear before their c_i_x^+ counterpart.
+ * Note that the result of intra_coefficients may also contain
+ * parameter coefficients c_n, in which case 0 is plugged in for them as well.
+ */
+static isl_stat add_intra_validity_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge)
+{
+	int offset;
+	isl_map *map = isl_map_copy(edge->map);
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *node = edge->src;
+
+	coef = intra_coefficients(graph, node, map, 0);
+
+	offset = coef_var_offset(coef);
+
+	if (!coef)
+		return isl_stat_error;
+
+	dim_map = intra_dim_map(ctx, graph, node, offset, 1);
+	graph->lp = add_constraints_dim_map(graph->lp, coef, dim_map);
+
+	return isl_stat_ok;
+}
+
+/* Add constraints to graph->lp that force validity for the given
+ * dependence from node i to node j.
+ * That is, add constraints that enforce
+ *
+ *	(c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x) >= 0
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x, c_y)
+ * of valid constraints for R and then plug in
+ * (c_j_0 - c_i_0, c_j_n - c_i_n, -(c_i_x^+ - c_i_x^-), c_j_x^+ - c_j_x^-),
+ * where c_* = c_*^+ - c_*^-, with c_*^+ and c_*^- non-negative.
+ * In graph->lp, the c_*^- appear before their c_*^+ counterpart.
+ */
+static isl_stat add_inter_validity_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge)
+{
+	int offset;
+	isl_map *map;
+	isl_ctx *ctx;
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *src = edge->src;
+	struct isl_sched_node *dst = edge->dst;
+
+	if (!graph->lp)
+		return isl_stat_error;
+
+	map = isl_map_copy(edge->map);
+	ctx = isl_map_get_ctx(map);
+	coef = inter_coefficients(graph, edge, map);
+
+	offset = coef_var_offset(coef);
+
+	if (!coef)
+		return isl_stat_error;
+
+	dim_map = inter_dim_map(ctx, graph, src, dst, offset, 1);
+
+	edge->start = graph->lp->n_ineq;
+	graph->lp = add_constraints_dim_map(graph->lp, coef, dim_map);
+	if (!graph->lp)
+		return isl_stat_error;
+	edge->end = graph->lp->n_ineq;
+
+	return isl_stat_ok;
+}
+
+/* Add constraints to graph->lp that bound the dependence distance for the given
+ * dependence from a node i to itself.
+ * If s = 1, we add the constraint
+ *
+ *	c_i_x (y - x) <= m_0 + m_n n
+ *
+ * or
+ *
+ *	-c_i_x (y - x) + m_0 + m_n n >= 0
+ *
+ * for each (x,y) in R.
+ * If s = -1, we add the constraint
+ *
+ *	-c_i_x (y - x) <= m_0 + m_n n
+ *
+ * or
+ *
+ *	c_i_x (y - x) + m_0 + m_n n >= 0
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x)
+ * of valid constraints for (y - x) and then plug in (m_0, m_n, -s * c_i_x),
+ * with each coefficient (except m_0) represented as a pair of non-negative
+ * coefficients.
+ *
+ *
+ * If "local" is set, then we add constraints
+ *
+ *	c_i_x (y - x) <= 0
+ *
+ * or
+ *
+ *	-c_i_x (y - x) <= 0
+ *
+ * instead, forcing the dependence distance to be (less than or) equal to 0.
+ * That is, we plug in (0, 0, -s * c_i_x),
+ * intra_coefficients is not required to have c_n in its result when
+ * "local" is set.  If they are missing, then (0, -s * c_i_x) is plugged in.
+ * Note that dependences marked local are treated as validity constraints
+ * by add_all_validity_constraints and therefore also have
+ * their distances bounded by 0 from below.
+ */
+static isl_stat add_intra_proximity_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge, int s, int local)
+{
+	int offset;
+	unsigned nparam;
+	isl_map *map = isl_map_copy(edge->map);
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *node = edge->src;
+
+	coef = intra_coefficients(graph, node, map, !local);
+
+	offset = coef_var_offset(coef);
+
+	if (!coef)
+		return isl_stat_error;
+
+	nparam = isl_space_dim(node->space, isl_dim_param);
+	dim_map = intra_dim_map(ctx, graph, node, offset, -s);
+
+	if (!local) {
+		isl_dim_map_range(dim_map, 1, 0, 0, 0, 1, 1);
+		isl_dim_map_range(dim_map, 4, 2, 1, 1, nparam, -1);
+		isl_dim_map_range(dim_map, 5, 2, 1, 1, nparam, 1);
+	}
+	graph->lp = add_constraints_dim_map(graph->lp, coef, dim_map);
+
+	return isl_stat_ok;
+}
+
+/* Add constraints to graph->lp that bound the dependence distance for the given
+ * dependence from node i to node j.
+ * If s = 1, we add the constraint
+ *
+ *	(c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x)
+ *		<= m_0 + m_n n
+ *
+ * or
+ *
+ *	-(c_j_0 + c_j_n n + c_j_x y) + (c_i_0 + c_i_n n + c_i_x x) +
+ *		m_0 + m_n n >= 0
+ *
+ * for each (x,y) in R.
+ * If s = -1, we add the constraint
+ *
+ *	-((c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x))
+ *		<= m_0 + m_n n
+ *
+ * or
+ *
+ *	(c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x) +
+ *		m_0 + m_n n >= 0
+ *
+ * for each (x,y) in R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x, c_y)
+ * of valid constraints for R and then plug in
+ * (m_0 - s*c_j_0 + s*c_i_0, m_n - s*c_j_n + s*c_i_n,
+ *  s*c_i_x, -s*c_j_x)
+ * with each coefficient (except m_0, c_*_0 and c_*_n)
+ * represented as a pair of non-negative coefficients.
+ *
+ *
+ * If "local" is set (and s = 1), then we add constraints
+ *
+ *	(c_j_0 + c_j_n n + c_j_x y) - (c_i_0 + c_i_n n + c_i_x x) <= 0
+ *
+ * or
+ *
+ *	-((c_j_0 + c_j_n n + c_j_x y) + (c_i_0 + c_i_n n + c_i_x x)) >= 0
+ *
+ * instead, forcing the dependence distance to be (less than or) equal to 0.
+ * That is, we plug in
+ * (-s*c_j_0 + s*c_i_0, -s*c_j_n + s*c_i_n, s*c_i_x, -s*c_j_x).
+ * Note that dependences marked local are treated as validity constraints
+ * by add_all_validity_constraints and therefore also have
+ * their distances bounded by 0 from below.
+ */
+static isl_stat add_inter_proximity_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge, int s, int local)
+{
+	int offset;
+	unsigned nparam;
+	isl_map *map = isl_map_copy(edge->map);
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *src = edge->src;
+	struct isl_sched_node *dst = edge->dst;
+
+	coef = inter_coefficients(graph, edge, map);
+
+	offset = coef_var_offset(coef);
+
+	if (!coef)
+		return isl_stat_error;
+
+	nparam = isl_space_dim(src->space, isl_dim_param);
+	dim_map = inter_dim_map(ctx, graph, src, dst, offset, -s);
+
+	if (!local) {
+		isl_dim_map_range(dim_map, 1, 0, 0, 0, 1, 1);
+		isl_dim_map_range(dim_map, 4, 2, 1, 1, nparam, -1);
+		isl_dim_map_range(dim_map, 5, 2, 1, 1, nparam, 1);
+	}
+
+	graph->lp = add_constraints_dim_map(graph->lp, coef, dim_map);
+
+	return isl_stat_ok;
+}
+
+/* Should the distance over "edge" be forced to zero?
+ * That is, is it marked as a local edge?
+ * If "use_coincidence" is set, then coincidence edges are treated
+ * as local edges.
+ */
+static int force_zero(struct isl_sched_edge *edge, int use_coincidence)
+{
+	return is_local(edge) || (use_coincidence && is_coincidence(edge));
+}
+
+/* Add all validity constraints to graph->lp.
+ *
+ * An edge that is forced to be local needs to have its dependence
+ * distances equal to zero.  We take care of bounding them by 0 from below
+ * here.  add_all_proximity_constraints takes care of bounding them by 0
+ * from above.
+ *
+ * If "use_coincidence" is set, then we treat coincidence edges as local edges.
+ * Otherwise, we ignore them.
+ */
+static int add_all_validity_constraints(struct isl_sched_graph *graph,
+	int use_coincidence)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge = &graph->edge[i];
+		int zero;
+
+		zero = force_zero(edge, use_coincidence);
+		if (!is_validity(edge) && !zero)
+			continue;
+		if (edge->src != edge->dst)
+			continue;
+		if (add_intra_validity_constraints(graph, edge) < 0)
+			return -1;
+	}
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge = &graph->edge[i];
+		int zero;
+
+		zero = force_zero(edge, use_coincidence);
+		if (!is_validity(edge) && !zero)
+			continue;
+		if (edge->src == edge->dst)
+			continue;
+		if (add_inter_validity_constraints(graph, edge) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Add constraints to graph->lp that bound the dependence distance
+ * for all dependence relations.
+ * If a given proximity dependence is identical to a validity
+ * dependence, then the dependence distance is already bounded
+ * from below (by zero), so we only need to bound the distance
+ * from above.  (This includes the case of "local" dependences
+ * which are treated as validity dependence by add_all_validity_constraints.)
+ * Otherwise, we need to bound the distance both from above and from below.
+ *
+ * If "use_coincidence" is set, then we treat coincidence edges as local edges.
+ * Otherwise, we ignore them.
+ */
+static int add_all_proximity_constraints(struct isl_sched_graph *graph,
+	int use_coincidence)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge = &graph->edge[i];
+		int zero;
+
+		zero = force_zero(edge, use_coincidence);
+		if (!is_proximity(edge) && !zero)
+			continue;
+		if (edge->src == edge->dst &&
+		    add_intra_proximity_constraints(graph, edge, 1, zero) < 0)
+			return -1;
+		if (edge->src != edge->dst &&
+		    add_inter_proximity_constraints(graph, edge, 1, zero) < 0)
+			return -1;
+		if (is_validity(edge) || zero)
+			continue;
+		if (edge->src == edge->dst &&
+		    add_intra_proximity_constraints(graph, edge, -1, 0) < 0)
+			return -1;
+		if (edge->src != edge->dst &&
+		    add_inter_proximity_constraints(graph, edge, -1, 0) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Normalize the rows of "indep" such that all rows are lexicographically
+ * positive and such that each row contains as many final zeros as possible,
+ * given the choice for the previous rows.
+ * Do this by performing elementary row operations.
+ */
+static __isl_give isl_mat *normalize_independent(__isl_take isl_mat *indep)
+{
+	indep = isl_mat_reverse_gauss(indep);
+	indep = isl_mat_lexnonneg_rows(indep);
+	return indep;
+}
+
+/* Compute a basis for the rows in the linear part of the schedule
+ * and extend this basis to a full basis.  The remaining rows
+ * can then be used to force linear independence from the rows
+ * in the schedule.
+ *
+ * In particular, given the schedule rows S, we compute
+ *
+ *	S   = H Q
+ *	S U = H
+ *
+ * with H the Hermite normal form of S.  That is, all but the
+ * first rank columns of H are zero and so each row in S is
+ * a linear combination of the first rank rows of Q.
+ * The matrix Q can be used as a variable transformation
+ * that isolates the directions of S in the first rank rows.
+ * Transposing S U = H yields
+ *
+ *	U^T S^T = H^T
+ *
+ * with all but the first rank rows of H^T zero.
+ * The last rows of U^T are therefore linear combinations
+ * of schedule coefficients that are all zero on schedule
+ * coefficients that are linearly dependent on the rows of S.
+ * At least one of these combinations is non-zero on
+ * linearly independent schedule coefficients.
+ * The rows are normalized to involve as few of the last
+ * coefficients as possible and to have a positive initial value.
+ */
+static int node_update_vmap(struct isl_sched_node *node)
+{
+	isl_mat *H, *U, *Q;
+	int n_row = isl_mat_rows(node->sched);
+
+	H = isl_mat_sub_alloc(node->sched, 0, n_row,
+			      1 + node->nparam, node->nvar);
+
+	H = isl_mat_left_hermite(H, 0, &U, &Q);
+	isl_mat_free(node->indep);
+	isl_mat_free(node->vmap);
+	node->vmap = Q;
+	node->indep = isl_mat_transpose(U);
+	node->rank = isl_mat_initial_non_zero_cols(H);
+	node->indep = isl_mat_drop_rows(node->indep, 0, node->rank);
+	node->indep = normalize_independent(node->indep);
+	isl_mat_free(H);
+
+	if (!node->indep || !node->vmap || node->rank < 0)
+		return -1;
+	return 0;
+}
+
+/* Is "edge" marked as a validity or a conditional validity edge?
+ */
+static int is_any_validity(struct isl_sched_edge *edge)
+{
+	return is_validity(edge) || is_conditional_validity(edge);
+}
+
+/* How many times should we count the constraints in "edge"?
+ *
+ * We count as follows
+ * validity		-> 1 (>= 0)
+ * validity+proximity	-> 2 (>= 0 and upper bound)
+ * proximity		-> 2 (lower and upper bound)
+ * local(+any)		-> 2 (>= 0 and <= 0)
+ *
+ * If an edge is only marked conditional_validity then it counts
+ * as zero since it is only checked afterwards.
+ *
+ * If "use_coincidence" is set, then we treat coincidence edges as local edges.
+ * Otherwise, we ignore them.
+ */
+static int edge_multiplicity(struct isl_sched_edge *edge, int use_coincidence)
+{
+	if (is_proximity(edge) || force_zero(edge, use_coincidence))
+		return 2;
+	if (is_validity(edge))
+		return 1;
+	return 0;
+}
+
+/* How many times should the constraints in "edge" be counted
+ * as a parametric intra-node constraint?
+ *
+ * Only proximity edges that are not forced zero need
+ * coefficient constraints that include coefficients for parameters.
+ * If the edge is also a validity edge, then only
+ * an upper bound is introduced.  Otherwise, both lower and upper bounds
+ * are introduced.
+ */
+static int parametric_intra_edge_multiplicity(struct isl_sched_edge *edge,
+	int use_coincidence)
+{
+	if (edge->src != edge->dst)
+		return 0;
+	if (!is_proximity(edge))
+		return 0;
+	if (force_zero(edge, use_coincidence))
+		return 0;
+	if (is_validity(edge))
+		return 1;
+	else
+		return 2;
+}
+
+/* Add "f" times the number of equality and inequality constraints of "bset"
+ * to "n_eq" and "n_ineq" and free "bset".
+ */
+static isl_stat update_count(__isl_take isl_basic_set *bset,
+	int f, int *n_eq, int *n_ineq)
+{
+	if (!bset)
+		return isl_stat_error;
+
+	*n_eq += isl_basic_set_n_equality(bset);
+	*n_ineq += isl_basic_set_n_inequality(bset);
+	isl_basic_set_free(bset);
+
+	return isl_stat_ok;
+}
+
+/* Count the number of equality and inequality constraints
+ * that will be added for the given map.
+ *
+ * The edges that require parameter coefficients are counted separately.
+ *
+ * "use_coincidence" is set if we should take into account coincidence edges.
+ */
+static isl_stat count_map_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge, __isl_take isl_map *map,
+	int *n_eq, int *n_ineq, int use_coincidence)
+{
+	isl_map *copy;
+	isl_basic_set *coef;
+	int f = edge_multiplicity(edge, use_coincidence);
+	int fp = parametric_intra_edge_multiplicity(edge, use_coincidence);
+
+	if (f == 0) {
+		isl_map_free(map);
+		return isl_stat_ok;
+	}
+
+	if (edge->src != edge->dst) {
+		coef = inter_coefficients(graph, edge, map);
+		return update_count(coef, f, n_eq, n_ineq);
+	}
+
+	if (fp > 0) {
+		copy = isl_map_copy(map);
+		coef = intra_coefficients(graph, edge->src, copy, 1);
+		if (update_count(coef, fp, n_eq, n_ineq) < 0)
+			goto error;
+	}
+
+	if (f > fp) {
+		copy = isl_map_copy(map);
+		coef = intra_coefficients(graph, edge->src, copy, 0);
+		if (update_count(coef, f - fp, n_eq, n_ineq) < 0)
+			goto error;
+	}
+
+	isl_map_free(map);
+	return isl_stat_ok;
+error:
+	isl_map_free(map);
+	return isl_stat_error;
+}
+
+/* Count the number of equality and inequality constraints
+ * that will be added to the main lp problem.
+ * We count as follows
+ * validity		-> 1 (>= 0)
+ * validity+proximity	-> 2 (>= 0 and upper bound)
+ * proximity		-> 2 (lower and upper bound)
+ * local(+any)		-> 2 (>= 0 and <= 0)
+ *
+ * If "use_coincidence" is set, then we treat coincidence edges as local edges.
+ * Otherwise, we ignore them.
+ */
+static int count_constraints(struct isl_sched_graph *graph,
+	int *n_eq, int *n_ineq, int use_coincidence)
+{
+	int i;
+
+	*n_eq = *n_ineq = 0;
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge = &graph->edge[i];
+		isl_map *map = isl_map_copy(edge->map);
+
+		if (count_map_constraints(graph, edge, map, n_eq, n_ineq,
+					    use_coincidence) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Count the number of constraints that will be added by
+ * add_bound_constant_constraints to bound the values of the constant terms
+ * and increment *n_eq and *n_ineq accordingly.
+ *
+ * In practice, add_bound_constant_constraints only adds inequalities.
+ */
+static isl_stat count_bound_constant_constraints(isl_ctx *ctx,
+	struct isl_sched_graph *graph, int *n_eq, int *n_ineq)
+{
+	if (isl_options_get_schedule_max_constant_term(ctx) == -1)
+		return isl_stat_ok;
+
+	*n_ineq += graph->n;
+
+	return isl_stat_ok;
+}
+
+/* Add constraints to bound the values of the constant terms in the schedule,
+ * if requested by the user.
+ *
+ * The maximal value of the constant terms is defined by the option
+ * "schedule_max_constant_term".
+ */
+static isl_stat add_bound_constant_constraints(isl_ctx *ctx,
+	struct isl_sched_graph *graph)
+{
+	int i, k;
+	int max;
+	int total;
+
+	max = isl_options_get_schedule_max_constant_term(ctx);
+	if (max == -1)
+		return isl_stat_ok;
+
+	total = isl_basic_set_dim(graph->lp, isl_dim_set);
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int pos;
+
+		k = isl_basic_set_alloc_inequality(graph->lp);
+		if (k < 0)
+			return isl_stat_error;
+		isl_seq_clr(graph->lp->ineq[k], 1 + total);
+		pos = node_cst_coef_offset(node);
+		isl_int_set_si(graph->lp->ineq[k][1 + pos], -1);
+		isl_int_set_si(graph->lp->ineq[k][0], max);
+	}
+
+	return isl_stat_ok;
+}
+
+/* Count the number of constraints that will be added by
+ * add_bound_coefficient_constraints and increment *n_eq and *n_ineq
+ * accordingly.
+ *
+ * In practice, add_bound_coefficient_constraints only adds inequalities.
+ */
+static int count_bound_coefficient_constraints(isl_ctx *ctx,
+	struct isl_sched_graph *graph, int *n_eq, int *n_ineq)
+{
+	int i;
+
+	if (isl_options_get_schedule_max_coefficient(ctx) == -1 &&
+	    !isl_options_get_schedule_treat_coalescing(ctx))
+		return 0;
+
+	for (i = 0; i < graph->n; ++i)
+		*n_ineq += graph->node[i].nparam + 2 * graph->node[i].nvar;
+
+	return 0;
+}
+
+/* Add constraints to graph->lp that bound the values of
+ * the parameter schedule coefficients of "node" to "max" and
+ * the variable schedule coefficients to the corresponding entry
+ * in node->max.
+ * In either case, a negative value means that no bound needs to be imposed.
+ *
+ * For parameter coefficients, this amounts to adding a constraint
+ *
+ *	c_n <= max
+ *
+ * i.e.,
+ *
+ *	-c_n + max >= 0
+ *
+ * The variables coefficients are, however, not represented directly.
+ * Instead, the variable coefficients c_x are written as differences
+ * c_x = c_x^+ - c_x^-.
+ * That is,
+ *
+ *	-max_i <= c_x_i <= max_i
+ *
+ * is encoded as
+ *
+ *	-max_i <= c_x_i^+ - c_x_i^- <= max_i
+ *
+ * or
+ *
+ *	-(c_x_i^+ - c_x_i^-) + max_i >= 0
+ *	c_x_i^+ - c_x_i^- + max_i >= 0
+ */
+static isl_stat node_add_coefficient_constraints(isl_ctx *ctx,
+	struct isl_sched_graph *graph, struct isl_sched_node *node, int max)
+{
+	int i, j, k;
+	int total;
+	isl_vec *ineq;
+
+	total = isl_basic_set_dim(graph->lp, isl_dim_set);
+
+	for (j = 0; j < node->nparam; ++j) {
+		int dim;
+
+		if (max < 0)
+			continue;
+
+		k = isl_basic_set_alloc_inequality(graph->lp);
+		if (k < 0)
+			return isl_stat_error;
+		dim = 1 + node_par_coef_offset(node) + j;
+		isl_seq_clr(graph->lp->ineq[k], 1 + total);
+		isl_int_set_si(graph->lp->ineq[k][dim], -1);
+		isl_int_set_si(graph->lp->ineq[k][0], max);
+	}
+
+	ineq = isl_vec_alloc(ctx, 1 + total);
+	ineq = isl_vec_clr(ineq);
+	if (!ineq)
+		return isl_stat_error;
+	for (i = 0; i < node->nvar; ++i) {
+		int pos = 1 + node_var_coef_pos(node, i);
+
+		if (isl_int_is_neg(node->max->el[i]))
+			continue;
+
+		isl_int_set_si(ineq->el[pos], 1);
+		isl_int_set_si(ineq->el[pos + 1], -1);
+		isl_int_set(ineq->el[0], node->max->el[i]);
+
+		k = isl_basic_set_alloc_inequality(graph->lp);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(graph->lp->ineq[k], ineq->el, 1 + total);
+
+		isl_seq_neg(ineq->el + pos, ineq->el + pos, 2);
+		k = isl_basic_set_alloc_inequality(graph->lp);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(graph->lp->ineq[k], ineq->el, 1 + total);
+
+		isl_seq_clr(ineq->el + pos, 2);
+	}
+	isl_vec_free(ineq);
+
+	return isl_stat_ok;
+error:
+	isl_vec_free(ineq);
+	return isl_stat_error;
+}
+
+/* Add constraints that bound the values of the variable and parameter
+ * coefficients of the schedule.
+ *
+ * The maximal value of the coefficients is defined by the option
+ * 'schedule_max_coefficient' and the entries in node->max.
+ * These latter entries are only set if either the schedule_max_coefficient
+ * option or the schedule_treat_coalescing option is set.
+ */
+static isl_stat add_bound_coefficient_constraints(isl_ctx *ctx,
+	struct isl_sched_graph *graph)
+{
+	int i;
+	int max;
+
+	max = isl_options_get_schedule_max_coefficient(ctx);
+
+	if (max == -1 && !isl_options_get_schedule_treat_coalescing(ctx))
+		return isl_stat_ok;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+
+		if (node_add_coefficient_constraints(ctx, graph, node, max) < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Add a constraint to graph->lp that equates the value at position
+ * "sum_pos" to the sum of the "n" values starting at "first".
+ */
+static isl_stat add_sum_constraint(struct isl_sched_graph *graph,
+	int sum_pos, int first, int n)
+{
+	int i, k;
+	int total;
+
+	total = isl_basic_set_dim(graph->lp, isl_dim_set);
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return isl_stat_error;
+	isl_seq_clr(graph->lp->eq[k], 1 + total);
+	isl_int_set_si(graph->lp->eq[k][1 + sum_pos], -1);
+	for (i = 0; i < n; ++i)
+		isl_int_set_si(graph->lp->eq[k][1 + first + i], 1);
+
+	return isl_stat_ok;
+}
+
+/* Add a constraint to graph->lp that equates the value at position
+ * "sum_pos" to the sum of the parameter coefficients of all nodes.
+ */
+static isl_stat add_param_sum_constraint(struct isl_sched_graph *graph,
+	int sum_pos)
+{
+	int i, j, k;
+	int total;
+
+	total = isl_basic_set_dim(graph->lp, isl_dim_set);
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return isl_stat_error;
+	isl_seq_clr(graph->lp->eq[k], 1 + total);
+	isl_int_set_si(graph->lp->eq[k][1 + sum_pos], -1);
+	for (i = 0; i < graph->n; ++i) {
+		int pos = 1 + node_par_coef_offset(&graph->node[i]);
+
+		for (j = 0; j < graph->node[i].nparam; ++j)
+			isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+	}
+
+	return isl_stat_ok;
+}
+
+/* Add a constraint to graph->lp that equates the value at position
+ * "sum_pos" to the sum of the variable coefficients of all nodes.
+ */
+static isl_stat add_var_sum_constraint(struct isl_sched_graph *graph,
+	int sum_pos)
+{
+	int i, j, k;
+	int total;
+
+	total = isl_basic_set_dim(graph->lp, isl_dim_set);
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return isl_stat_error;
+	isl_seq_clr(graph->lp->eq[k], 1 + total);
+	isl_int_set_si(graph->lp->eq[k][1 + sum_pos], -1);
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int pos = 1 + node_var_coef_offset(node);
+
+		for (j = 0; j < 2 * node->nvar; ++j)
+			isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+	}
+
+	return isl_stat_ok;
+}
+
+/* Construct an ILP problem for finding schedule coefficients
+ * that result in non-negative, but small dependence distances
+ * over all dependences.
+ * In particular, the dependence distances over proximity edges
+ * are bounded by m_0 + m_n n and we compute schedule coefficients
+ * with small values (preferably zero) of m_n and m_0.
+ *
+ * All variables of the ILP are non-negative.  The actual coefficients
+ * may be negative, so each coefficient is represented as the difference
+ * of two non-negative variables.  The negative part always appears
+ * immediately before the positive part.
+ * Other than that, the variables have the following order
+ *
+ *	- sum of positive and negative parts of m_n coefficients
+ *	- m_0
+ *	- sum of all c_n coefficients
+ *		(unconstrained when computing non-parametric schedules)
+ *	- sum of positive and negative parts of all c_x coefficients
+ *	- positive and negative parts of m_n coefficients
+ *	- for each node
+ *		- positive and negative parts of c_i_x, in opposite order
+ *		- c_i_n (if parametric)
+ *		- c_i_0
+ *
+ * The constraints are those from the edges plus two or three equalities
+ * to express the sums.
+ *
+ * If "use_coincidence" is set, then we treat coincidence edges as local edges.
+ * Otherwise, we ignore them.
+ */
+static isl_stat setup_lp(isl_ctx *ctx, struct isl_sched_graph *graph,
+	int use_coincidence)
+{
+	int i;
+	unsigned nparam;
+	unsigned total;
+	isl_space *space;
+	int parametric;
+	int param_pos;
+	int n_eq, n_ineq;
+
+	parametric = ctx->opt->schedule_parametric;
+	nparam = isl_space_dim(graph->node[0].space, isl_dim_param);
+	param_pos = 4;
+	total = param_pos + 2 * nparam;
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[graph->sorted[i]];
+		if (node_update_vmap(node) < 0)
+			return isl_stat_error;
+		node->start = total;
+		total += 1 + node->nparam + 2 * node->nvar;
+	}
+
+	if (count_constraints(graph, &n_eq, &n_ineq, use_coincidence) < 0)
+		return isl_stat_error;
+	if (count_bound_constant_constraints(ctx, graph, &n_eq, &n_ineq) < 0)
+		return isl_stat_error;
+	if (count_bound_coefficient_constraints(ctx, graph, &n_eq, &n_ineq) < 0)
+		return isl_stat_error;
+
+	space = isl_space_set_alloc(ctx, 0, total);
+	isl_basic_set_free(graph->lp);
+	n_eq += 2 + parametric;
+
+	graph->lp = isl_basic_set_alloc_space(space, 0, n_eq, n_ineq);
+
+	if (add_sum_constraint(graph, 0, param_pos, 2 * nparam) < 0)
+		return isl_stat_error;
+	if (parametric && add_param_sum_constraint(graph, 2) < 0)
+		return isl_stat_error;
+	if (add_var_sum_constraint(graph, 3) < 0)
+		return isl_stat_error;
+	if (add_bound_constant_constraints(ctx, graph) < 0)
+		return isl_stat_error;
+	if (add_bound_coefficient_constraints(ctx, graph) < 0)
+		return isl_stat_error;
+	if (add_all_validity_constraints(graph, use_coincidence) < 0)
+		return isl_stat_error;
+	if (add_all_proximity_constraints(graph, use_coincidence) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Analyze the conflicting constraint found by
+ * isl_tab_basic_set_non_trivial_lexmin.  If it corresponds to the validity
+ * constraint of one of the edges between distinct nodes, living, moreover
+ * in distinct SCCs, then record the source and sink SCC as this may
+ * be a good place to cut between SCCs.
+ */
+static int check_conflict(int con, void *user)
+{
+	int i;
+	struct isl_sched_graph *graph = user;
+
+	if (graph->src_scc >= 0)
+		return 0;
+
+	con -= graph->lp->n_eq;
+
+	if (con >= graph->lp->n_ineq)
+		return 0;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		if (!is_validity(&graph->edge[i]))
+			continue;
+		if (graph->edge[i].src == graph->edge[i].dst)
+			continue;
+		if (graph->edge[i].src->scc == graph->edge[i].dst->scc)
+			continue;
+		if (graph->edge[i].start > con)
+			continue;
+		if (graph->edge[i].end <= con)
+			continue;
+		graph->src_scc = graph->edge[i].src->scc;
+		graph->dst_scc = graph->edge[i].dst->scc;
+	}
+
+	return 0;
+}
+
+/* Check whether the next schedule row of the given node needs to be
+ * non-trivial.  Lower-dimensional domains may have some trivial rows,
+ * but as soon as the number of remaining required non-trivial rows
+ * is as large as the number or remaining rows to be computed,
+ * all remaining rows need to be non-trivial.
+ */
+static int needs_row(struct isl_sched_graph *graph, struct isl_sched_node *node)
+{
+	return node->nvar - node->rank >= graph->maxvar - graph->n_row;
+}
+
+/* Construct a non-triviality region with triviality directions
+ * corresponding to the rows of "indep".
+ * The rows of "indep" are expressed in terms of the schedule coefficients c_i,
+ * while the triviality directions are expressed in terms of
+ * pairs of non-negative variables c^+_i - c^-_i, with c^-_i appearing
+ * before c^+_i.  Furthermore,
+ * the pairs of non-negative variables representing the coefficients
+ * are stored in the opposite order.
+ */
+static __isl_give isl_mat *construct_trivial(__isl_keep isl_mat *indep)
+{
+	isl_ctx *ctx;
+	isl_mat *mat;
+	int i, j, n, n_var;
+
+	if (!indep)
+		return NULL;
+
+	ctx = isl_mat_get_ctx(indep);
+	n = isl_mat_rows(indep);
+	n_var = isl_mat_cols(indep);
+	mat = isl_mat_alloc(ctx, n, 2 * n_var);
+	if (!mat)
+		return NULL;
+	for (i = 0; i < n; ++i) {
+		for (j = 0; j < n_var; ++j) {
+			int nj = n_var - 1 - j;
+			isl_int_neg(mat->row[i][2 * nj], indep->row[i][j]);
+			isl_int_set(mat->row[i][2 * nj + 1], indep->row[i][j]);
+		}
+	}
+
+	return mat;
+}
+
+/* Solve the ILP problem constructed in setup_lp.
+ * For each node such that all the remaining rows of its schedule
+ * need to be non-trivial, we construct a non-triviality region.
+ * This region imposes that the next row is independent of previous rows.
+ * In particular, the non-triviality region enforces that at least
+ * one of the linear combinations in the rows of node->indep is non-zero.
+ */
+static __isl_give isl_vec *solve_lp(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i;
+	isl_vec *sol;
+	isl_basic_set *lp;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		isl_mat *trivial;
+
+		graph->region[i].pos = node_var_coef_offset(node);
+		if (needs_row(graph, node))
+			trivial = construct_trivial(node->indep);
+		else
+			trivial = isl_mat_zero(ctx, 0, 0);
+		graph->region[i].trivial = trivial;
+	}
+	lp = isl_basic_set_copy(graph->lp);
+	sol = isl_tab_basic_set_non_trivial_lexmin(lp, 2, graph->n,
+				       graph->region, &check_conflict, graph);
+	for (i = 0; i < graph->n; ++i)
+		isl_mat_free(graph->region[i].trivial);
+	return sol;
+}
+
+/* Extract the coefficients for the variables of "node" from "sol".
+ *
+ * Each schedule coefficient c_i_x is represented as the difference
+ * between two non-negative variables c_i_x^+ - c_i_x^-.
+ * The c_i_x^- appear before their c_i_x^+ counterpart.
+ * Furthermore, the order of these pairs is the opposite of that
+ * of the corresponding coefficients.
+ *
+ * Return c_i_x = c_i_x^+ - c_i_x^-
+ */
+static __isl_give isl_vec *extract_var_coef(struct isl_sched_node *node,
+	__isl_keep isl_vec *sol)
+{
+	int i;
+	int pos;
+	isl_vec *csol;
+
+	if (!sol)
+		return NULL;
+	csol = isl_vec_alloc(isl_vec_get_ctx(sol), node->nvar);
+	if (!csol)
+		return NULL;
+
+	pos = 1 + node_var_coef_offset(node);
+	for (i = 0; i < node->nvar; ++i)
+		isl_int_sub(csol->el[node->nvar - 1 - i],
+			    sol->el[pos + 2 * i + 1], sol->el[pos + 2 * i]);
+
+	return csol;
+}
+
+/* Update the schedules of all nodes based on the given solution
+ * of the LP problem.
+ * The new row is added to the current band.
+ * All possibly negative coefficients are encoded as a difference
+ * of two non-negative variables, so we need to perform the subtraction
+ * here.
+ *
+ * If coincident is set, then the caller guarantees that the new
+ * row satisfies the coincidence constraints.
+ */
+static int update_schedule(struct isl_sched_graph *graph,
+	__isl_take isl_vec *sol, int coincident)
+{
+	int i, j;
+	isl_vec *csol = NULL;
+
+	if (!sol)
+		goto error;
+	if (sol->size == 0)
+		isl_die(sol->ctx, isl_error_internal,
+			"no solution found", goto error);
+	if (graph->n_total_row >= graph->max_row)
+		isl_die(sol->ctx, isl_error_internal,
+			"too many schedule rows", goto error);
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int pos;
+		int row = isl_mat_rows(node->sched);
+
+		isl_vec_free(csol);
+		csol = extract_var_coef(node, sol);
+		if (!csol)
+			goto error;
+
+		isl_map_free(node->sched_map);
+		node->sched_map = NULL;
+		node->sched = isl_mat_add_rows(node->sched, 1);
+		if (!node->sched)
+			goto error;
+		pos = node_cst_coef_offset(node);
+		node->sched = isl_mat_set_element(node->sched,
+					row, 0, sol->el[1 + pos]);
+		pos = node_par_coef_offset(node);
+		for (j = 0; j < node->nparam; ++j)
+			node->sched = isl_mat_set_element(node->sched,
+					row, 1 + j, sol->el[1 + pos + j]);
+		for (j = 0; j < node->nvar; ++j)
+			node->sched = isl_mat_set_element(node->sched,
+					row, 1 + node->nparam + j, csol->el[j]);
+		node->coincident[graph->n_total_row] = coincident;
+	}
+	isl_vec_free(sol);
+	isl_vec_free(csol);
+
+	graph->n_row++;
+	graph->n_total_row++;
+
+	return 0;
+error:
+	isl_vec_free(sol);
+	isl_vec_free(csol);
+	return -1;
+}
+
+/* Convert row "row" of node->sched into an isl_aff living in "ls"
+ * and return this isl_aff.
+ */
+static __isl_give isl_aff *extract_schedule_row(__isl_take isl_local_space *ls,
+	struct isl_sched_node *node, int row)
+{
+	int j;
+	isl_int v;
+	isl_aff *aff;
+
+	isl_int_init(v);
+
+	aff = isl_aff_zero_on_domain(ls);
+	isl_mat_get_element(node->sched, row, 0, &v);
+	aff = isl_aff_set_constant(aff, v);
+	for (j = 0; j < node->nparam; ++j) {
+		isl_mat_get_element(node->sched, row, 1 + j, &v);
+		aff = isl_aff_set_coefficient(aff, isl_dim_param, j, v);
+	}
+	for (j = 0; j < node->nvar; ++j) {
+		isl_mat_get_element(node->sched, row, 1 + node->nparam + j, &v);
+		aff = isl_aff_set_coefficient(aff, isl_dim_in, j, v);
+	}
+
+	isl_int_clear(v);
+
+	return aff;
+}
+
+/* Convert the "n" rows starting at "first" of node->sched into a multi_aff
+ * and return this multi_aff.
+ *
+ * The result is defined over the uncompressed node domain.
+ */
+static __isl_give isl_multi_aff *node_extract_partial_schedule_multi_aff(
+	struct isl_sched_node *node, int first, int n)
+{
+	int i;
+	isl_space *space;
+	isl_local_space *ls;
+	isl_aff *aff;
+	isl_multi_aff *ma;
+	int nrow;
+
+	if (!node)
+		return NULL;
+	nrow = isl_mat_rows(node->sched);
+	if (node->compressed)
+		space = isl_multi_aff_get_domain_space(node->decompress);
+	else
+		space = isl_space_copy(node->space);
+	ls = isl_local_space_from_space(isl_space_copy(space));
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, n);
+	ma = isl_multi_aff_zero(space);
+
+	for (i = first; i < first + n; ++i) {
+		aff = extract_schedule_row(isl_local_space_copy(ls), node, i);
+		ma = isl_multi_aff_set_aff(ma, i - first, aff);
+	}
+
+	isl_local_space_free(ls);
+
+	if (node->compressed)
+		ma = isl_multi_aff_pullback_multi_aff(ma,
+					isl_multi_aff_copy(node->compress));
+
+	return ma;
+}
+
+/* Convert node->sched into a multi_aff and return this multi_aff.
+ *
+ * The result is defined over the uncompressed node domain.
+ */
+static __isl_give isl_multi_aff *node_extract_schedule_multi_aff(
+	struct isl_sched_node *node)
+{
+	int nrow;
+
+	nrow = isl_mat_rows(node->sched);
+	return node_extract_partial_schedule_multi_aff(node, 0, nrow);
+}
+
+/* Convert node->sched into a map and return this map.
+ *
+ * The result is cached in node->sched_map, which needs to be released
+ * whenever node->sched is updated.
+ * It is defined over the uncompressed node domain.
+ */
+static __isl_give isl_map *node_extract_schedule(struct isl_sched_node *node)
+{
+	if (!node->sched_map) {
+		isl_multi_aff *ma;
+
+		ma = node_extract_schedule_multi_aff(node);
+		node->sched_map = isl_map_from_multi_aff(ma);
+	}
+
+	return isl_map_copy(node->sched_map);
+}
+
+/* Construct a map that can be used to update a dependence relation
+ * based on the current schedule.
+ * That is, construct a map expressing that source and sink
+ * are executed within the same iteration of the current schedule.
+ * This map can then be intersected with the dependence relation.
+ * This is not the most efficient way, but this shouldn't be a critical
+ * operation.
+ */
+static __isl_give isl_map *specializer(struct isl_sched_node *src,
+	struct isl_sched_node *dst)
+{
+	isl_map *src_sched, *dst_sched;
+
+	src_sched = node_extract_schedule(src);
+	dst_sched = node_extract_schedule(dst);
+	return isl_map_apply_range(src_sched, isl_map_reverse(dst_sched));
+}
+
+/* Intersect the domains of the nested relations in domain and range
+ * of "umap" with "map".
+ */
+static __isl_give isl_union_map *intersect_domains(
+	__isl_take isl_union_map *umap, __isl_keep isl_map *map)
+{
+	isl_union_set *uset;
+
+	umap = isl_union_map_zip(umap);
+	uset = isl_union_set_from_set(isl_map_wrap(isl_map_copy(map)));
+	umap = isl_union_map_intersect_domain(umap, uset);
+	umap = isl_union_map_zip(umap);
+	return umap;
+}
+
+/* Update the dependence relation of the given edge based
+ * on the current schedule.
+ * If the dependence is carried completely by the current schedule, then
+ * it is removed from the edge_tables.  It is kept in the list of edges
+ * as otherwise all edge_tables would have to be recomputed.
+ */
+static int update_edge(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge)
+{
+	int empty;
+	isl_map *id;
+
+	id = specializer(edge->src, edge->dst);
+	edge->map = isl_map_intersect(edge->map, isl_map_copy(id));
+	if (!edge->map)
+		goto error;
+
+	if (edge->tagged_condition) {
+		edge->tagged_condition =
+			intersect_domains(edge->tagged_condition, id);
+		if (!edge->tagged_condition)
+			goto error;
+	}
+	if (edge->tagged_validity) {
+		edge->tagged_validity =
+			intersect_domains(edge->tagged_validity, id);
+		if (!edge->tagged_validity)
+			goto error;
+	}
+
+	empty = isl_map_plain_is_empty(edge->map);
+	if (empty < 0)
+		goto error;
+	if (empty)
+		graph_remove_edge(graph, edge);
+
+	isl_map_free(id);
+	return 0;
+error:
+	isl_map_free(id);
+	return -1;
+}
+
+/* Does the domain of "umap" intersect "uset"?
+ */
+static int domain_intersects(__isl_keep isl_union_map *umap,
+	__isl_keep isl_union_set *uset)
+{
+	int empty;
+
+	umap = isl_union_map_copy(umap);
+	umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(uset));
+	empty = isl_union_map_is_empty(umap);
+	isl_union_map_free(umap);
+
+	return empty < 0 ? -1 : !empty;
+}
+
+/* Does the range of "umap" intersect "uset"?
+ */
+static int range_intersects(__isl_keep isl_union_map *umap,
+	__isl_keep isl_union_set *uset)
+{
+	int empty;
+
+	umap = isl_union_map_copy(umap);
+	umap = isl_union_map_intersect_range(umap, isl_union_set_copy(uset));
+	empty = isl_union_map_is_empty(umap);
+	isl_union_map_free(umap);
+
+	return empty < 0 ? -1 : !empty;
+}
+
+/* Are the condition dependences of "edge" local with respect to
+ * the current schedule?
+ *
+ * That is, are domain and range of the condition dependences mapped
+ * to the same point?
+ *
+ * In other words, is the condition false?
+ */
+static int is_condition_false(struct isl_sched_edge *edge)
+{
+	isl_union_map *umap;
+	isl_map *map, *sched, *test;
+	int empty, local;
+
+	empty = isl_union_map_is_empty(edge->tagged_condition);
+	if (empty < 0 || empty)
+		return empty;
+
+	umap = isl_union_map_copy(edge->tagged_condition);
+	umap = isl_union_map_zip(umap);
+	umap = isl_union_set_unwrap(isl_union_map_domain(umap));
+	map = isl_map_from_union_map(umap);
+
+	sched = node_extract_schedule(edge->src);
+	map = isl_map_apply_domain(map, sched);
+	sched = node_extract_schedule(edge->dst);
+	map = isl_map_apply_range(map, sched);
+
+	test = isl_map_identity(isl_map_get_space(map));
+	local = isl_map_is_subset(map, test);
+	isl_map_free(map);
+	isl_map_free(test);
+
+	return local;
+}
+
+/* For each conditional validity constraint that is adjacent
+ * to a condition with domain in condition_source or range in condition_sink,
+ * turn it into an unconditional validity constraint.
+ */
+static int unconditionalize_adjacent_validity(struct isl_sched_graph *graph,
+	__isl_take isl_union_set *condition_source,
+	__isl_take isl_union_set *condition_sink)
+{
+	int i;
+
+	condition_source = isl_union_set_coalesce(condition_source);
+	condition_sink = isl_union_set_coalesce(condition_sink);
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		int adjacent;
+		isl_union_map *validity;
+
+		if (!is_conditional_validity(&graph->edge[i]))
+			continue;
+		if (is_validity(&graph->edge[i]))
+			continue;
+
+		validity = graph->edge[i].tagged_validity;
+		adjacent = domain_intersects(validity, condition_sink);
+		if (adjacent >= 0 && !adjacent)
+			adjacent = range_intersects(validity, condition_source);
+		if (adjacent < 0)
+			goto error;
+		if (!adjacent)
+			continue;
+
+		set_validity(&graph->edge[i]);
+	}
+
+	isl_union_set_free(condition_source);
+	isl_union_set_free(condition_sink);
+	return 0;
+error:
+	isl_union_set_free(condition_source);
+	isl_union_set_free(condition_sink);
+	return -1;
+}
+
+/* Update the dependence relations of all edges based on the current schedule
+ * and enforce conditional validity constraints that are adjacent
+ * to satisfied condition constraints.
+ *
+ * First check if any of the condition constraints are satisfied
+ * (i.e., not local to the outer schedule) and keep track of
+ * their domain and range.
+ * Then update all dependence relations (which removes the non-local
+ * constraints).
+ * Finally, if any condition constraints turned out to be satisfied,
+ * then turn all adjacent conditional validity constraints into
+ * unconditional validity constraints.
+ */
+static int update_edges(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i;
+	int any = 0;
+	isl_union_set *source, *sink;
+
+	source = isl_union_set_empty(isl_space_params_alloc(ctx, 0));
+	sink = isl_union_set_empty(isl_space_params_alloc(ctx, 0));
+	for (i = 0; i < graph->n_edge; ++i) {
+		int local;
+		isl_union_set *uset;
+		isl_union_map *umap;
+
+		if (!is_condition(&graph->edge[i]))
+			continue;
+		if (is_local(&graph->edge[i]))
+			continue;
+		local = is_condition_false(&graph->edge[i]);
+		if (local < 0)
+			goto error;
+		if (local)
+			continue;
+
+		any = 1;
+
+		umap = isl_union_map_copy(graph->edge[i].tagged_condition);
+		uset = isl_union_map_domain(umap);
+		source = isl_union_set_union(source, uset);
+
+		umap = isl_union_map_copy(graph->edge[i].tagged_condition);
+		uset = isl_union_map_range(umap);
+		sink = isl_union_set_union(sink, uset);
+	}
+
+	for (i = graph->n_edge - 1; i >= 0; --i) {
+		if (update_edge(graph, &graph->edge[i]) < 0)
+			goto error;
+	}
+
+	if (any)
+		return unconditionalize_adjacent_validity(graph, source, sink);
+
+	isl_union_set_free(source);
+	isl_union_set_free(sink);
+	return 0;
+error:
+	isl_union_set_free(source);
+	isl_union_set_free(sink);
+	return -1;
+}
+
+static void next_band(struct isl_sched_graph *graph)
+{
+	graph->band_start = graph->n_total_row;
+}
+
+/* Return the union of the universe domains of the nodes in "graph"
+ * that satisfy "pred".
+ */
+static __isl_give isl_union_set *isl_sched_graph_domain(isl_ctx *ctx,
+	struct isl_sched_graph *graph,
+	int (*pred)(struct isl_sched_node *node, int data), int data)
+{
+	int i;
+	isl_set *set;
+	isl_union_set *dom;
+
+	for (i = 0; i < graph->n; ++i)
+		if (pred(&graph->node[i], data))
+			break;
+
+	if (i >= graph->n)
+		isl_die(ctx, isl_error_internal,
+			"empty component", return NULL);
+
+	set = isl_set_universe(isl_space_copy(graph->node[i].space));
+	dom = isl_union_set_from_set(set);
+
+	for (i = i + 1; i < graph->n; ++i) {
+		if (!pred(&graph->node[i], data))
+			continue;
+		set = isl_set_universe(isl_space_copy(graph->node[i].space));
+		dom = isl_union_set_union(dom, isl_union_set_from_set(set));
+	}
+
+	return dom;
+}
+
+/* Return a list of unions of universe domains, where each element
+ * in the list corresponds to an SCC (or WCC) indexed by node->scc.
+ */
+static __isl_give isl_union_set_list *extract_sccs(isl_ctx *ctx,
+	struct isl_sched_graph *graph)
+{
+	int i;
+	isl_union_set_list *filters;
+
+	filters = isl_union_set_list_alloc(ctx, graph->scc);
+	for (i = 0; i < graph->scc; ++i) {
+		isl_union_set *dom;
+
+		dom = isl_sched_graph_domain(ctx, graph, &node_scc_exactly, i);
+		filters = isl_union_set_list_add(filters, dom);
+	}
+
+	return filters;
+}
+
+/* Return a list of two unions of universe domains, one for the SCCs up
+ * to and including graph->src_scc and another for the other SCCs.
+ */
+static __isl_give isl_union_set_list *extract_split(isl_ctx *ctx,
+	struct isl_sched_graph *graph)
+{
+	isl_union_set *dom;
+	isl_union_set_list *filters;
+
+	filters = isl_union_set_list_alloc(ctx, 2);
+	dom = isl_sched_graph_domain(ctx, graph,
+					&node_scc_at_most, graph->src_scc);
+	filters = isl_union_set_list_add(filters, dom);
+	dom = isl_sched_graph_domain(ctx, graph,
+					&node_scc_at_least, graph->src_scc + 1);
+	filters = isl_union_set_list_add(filters, dom);
+
+	return filters;
+}
+
+/* Copy nodes that satisfy node_pred from the src dependence graph
+ * to the dst dependence graph.
+ */
+static int copy_nodes(struct isl_sched_graph *dst, struct isl_sched_graph *src,
+	int (*node_pred)(struct isl_sched_node *node, int data), int data)
+{
+	int i;
+
+	dst->n = 0;
+	for (i = 0; i < src->n; ++i) {
+		int j;
+
+		if (!node_pred(&src->node[i], data))
+			continue;
+
+		j = dst->n;
+		dst->node[j].space = isl_space_copy(src->node[i].space);
+		dst->node[j].compressed = src->node[i].compressed;
+		dst->node[j].hull = isl_set_copy(src->node[i].hull);
+		dst->node[j].compress =
+			isl_multi_aff_copy(src->node[i].compress);
+		dst->node[j].decompress =
+			isl_multi_aff_copy(src->node[i].decompress);
+		dst->node[j].nvar = src->node[i].nvar;
+		dst->node[j].nparam = src->node[i].nparam;
+		dst->node[j].sched = isl_mat_copy(src->node[i].sched);
+		dst->node[j].sched_map = isl_map_copy(src->node[i].sched_map);
+		dst->node[j].coincident = src->node[i].coincident;
+		dst->node[j].sizes = isl_multi_val_copy(src->node[i].sizes);
+		dst->node[j].bounds = isl_basic_set_copy(src->node[i].bounds);
+		dst->node[j].max = isl_vec_copy(src->node[i].max);
+		dst->n++;
+
+		if (!dst->node[j].space || !dst->node[j].sched)
+			return -1;
+		if (dst->node[j].compressed &&
+		    (!dst->node[j].hull || !dst->node[j].compress ||
+		     !dst->node[j].decompress))
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Copy non-empty edges that satisfy edge_pred from the src dependence graph
+ * to the dst dependence graph.
+ * If the source or destination node of the edge is not in the destination
+ * graph, then it must be a backward proximity edge and it should simply
+ * be ignored.
+ */
+static int copy_edges(isl_ctx *ctx, struct isl_sched_graph *dst,
+	struct isl_sched_graph *src,
+	int (*edge_pred)(struct isl_sched_edge *edge, int data), int data)
+{
+	int i;
+	enum isl_edge_type t;
+
+	dst->n_edge = 0;
+	for (i = 0; i < src->n_edge; ++i) {
+		struct isl_sched_edge *edge = &src->edge[i];
+		isl_map *map;
+		isl_union_map *tagged_condition;
+		isl_union_map *tagged_validity;
+		struct isl_sched_node *dst_src, *dst_dst;
+
+		if (!edge_pred(edge, data))
+			continue;
+
+		if (isl_map_plain_is_empty(edge->map))
+			continue;
+
+		dst_src = graph_find_node(ctx, dst, edge->src->space);
+		dst_dst = graph_find_node(ctx, dst, edge->dst->space);
+		if (!dst_src || !dst_dst) {
+			if (is_validity(edge) || is_conditional_validity(edge))
+				isl_die(ctx, isl_error_internal,
+					"backward (conditional) validity edge",
+					return -1);
+			continue;
+		}
+
+		map = isl_map_copy(edge->map);
+		tagged_condition = isl_union_map_copy(edge->tagged_condition);
+		tagged_validity = isl_union_map_copy(edge->tagged_validity);
+
+		dst->edge[dst->n_edge].src = dst_src;
+		dst->edge[dst->n_edge].dst = dst_dst;
+		dst->edge[dst->n_edge].map = map;
+		dst->edge[dst->n_edge].tagged_condition = tagged_condition;
+		dst->edge[dst->n_edge].tagged_validity = tagged_validity;
+		dst->edge[dst->n_edge].types = edge->types;
+		dst->n_edge++;
+
+		if (edge->tagged_condition && !tagged_condition)
+			return -1;
+		if (edge->tagged_validity && !tagged_validity)
+			return -1;
+
+		for (t = isl_edge_first; t <= isl_edge_last; ++t) {
+			if (edge !=
+			    graph_find_edge(src, t, edge->src, edge->dst))
+				continue;
+			if (graph_edge_table_add(ctx, dst, t,
+					    &dst->edge[dst->n_edge - 1]) < 0)
+				return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* Compute the maximal number of variables over all nodes.
+ * This is the maximal number of linearly independent schedule
+ * rows that we need to compute.
+ * Just in case we end up in a part of the dependence graph
+ * with only lower-dimensional domains, we make sure we will
+ * compute the required amount of extra linearly independent rows.
+ */
+static int compute_maxvar(struct isl_sched_graph *graph)
+{
+	int i;
+
+	graph->maxvar = 0;
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int nvar;
+
+		if (node_update_vmap(node) < 0)
+			return -1;
+		nvar = node->nvar + graph->n_row - node->rank;
+		if (nvar > graph->maxvar)
+			graph->maxvar = nvar;
+	}
+
+	return 0;
+}
+
+/* Extract the subgraph of "graph" that consists of the node satisfying
+ * "node_pred" and the edges satisfying "edge_pred" and store
+ * the result in "sub".
+ */
+static int extract_sub_graph(isl_ctx *ctx, struct isl_sched_graph *graph,
+	int (*node_pred)(struct isl_sched_node *node, int data),
+	int (*edge_pred)(struct isl_sched_edge *edge, int data),
+	int data, struct isl_sched_graph *sub)
+{
+	int i, n = 0, n_edge = 0;
+	int t;
+
+	for (i = 0; i < graph->n; ++i)
+		if (node_pred(&graph->node[i], data))
+			++n;
+	for (i = 0; i < graph->n_edge; ++i)
+		if (edge_pred(&graph->edge[i], data))
+			++n_edge;
+	if (graph_alloc(ctx, sub, n, n_edge) < 0)
+		return -1;
+	sub->root = graph->root;
+	if (copy_nodes(sub, graph, node_pred, data) < 0)
+		return -1;
+	if (graph_init_table(ctx, sub) < 0)
+		return -1;
+	for (t = 0; t <= isl_edge_last; ++t)
+		sub->max_edge[t] = graph->max_edge[t];
+	if (graph_init_edge_tables(ctx, sub) < 0)
+		return -1;
+	if (copy_edges(ctx, sub, graph, edge_pred, data) < 0)
+		return -1;
+	sub->n_row = graph->n_row;
+	sub->max_row = graph->max_row;
+	sub->n_total_row = graph->n_total_row;
+	sub->band_start = graph->band_start;
+
+	return 0;
+}
+
+static __isl_give isl_schedule_node *compute_schedule(isl_schedule_node *node,
+	struct isl_sched_graph *graph);
+static __isl_give isl_schedule_node *compute_schedule_wcc(
+	isl_schedule_node *node, struct isl_sched_graph *graph);
+
+/* Compute a schedule for a subgraph of "graph".  In particular, for
+ * the graph composed of nodes that satisfy node_pred and edges that
+ * that satisfy edge_pred.
+ * If the subgraph is known to consist of a single component, then wcc should
+ * be set and then we call compute_schedule_wcc on the constructed subgraph.
+ * Otherwise, we call compute_schedule, which will check whether the subgraph
+ * is connected.
+ *
+ * The schedule is inserted at "node" and the updated schedule node
+ * is returned.
+ */
+static __isl_give isl_schedule_node *compute_sub_schedule(
+	__isl_take isl_schedule_node *node, isl_ctx *ctx,
+	struct isl_sched_graph *graph,
+	int (*node_pred)(struct isl_sched_node *node, int data),
+	int (*edge_pred)(struct isl_sched_edge *edge, int data),
+	int data, int wcc)
+{
+	struct isl_sched_graph split = { 0 };
+
+	if (extract_sub_graph(ctx, graph, node_pred, edge_pred, data,
+				&split) < 0)
+		goto error;
+
+	if (wcc)
+		node = compute_schedule_wcc(node, &split);
+	else
+		node = compute_schedule(node, &split);
+
+	graph_free(ctx, &split);
+	return node;
+error:
+	graph_free(ctx, &split);
+	return isl_schedule_node_free(node);
+}
+
+static int edge_scc_exactly(struct isl_sched_edge *edge, int scc)
+{
+	return edge->src->scc == scc && edge->dst->scc == scc;
+}
+
+static int edge_dst_scc_at_most(struct isl_sched_edge *edge, int scc)
+{
+	return edge->dst->scc <= scc;
+}
+
+static int edge_src_scc_at_least(struct isl_sched_edge *edge, int scc)
+{
+	return edge->src->scc >= scc;
+}
+
+/* Reset the current band by dropping all its schedule rows.
+ */
+static int reset_band(struct isl_sched_graph *graph)
+{
+	int i;
+	int drop;
+
+	drop = graph->n_total_row - graph->band_start;
+	graph->n_total_row -= drop;
+	graph->n_row -= drop;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+
+		isl_map_free(node->sched_map);
+		node->sched_map = NULL;
+
+		node->sched = isl_mat_drop_rows(node->sched,
+						graph->band_start, drop);
+
+		if (!node->sched)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Split the current graph into two parts and compute a schedule for each
+ * part individually.  In particular, one part consists of all SCCs up
+ * to and including graph->src_scc, while the other part contains the other
+ * SCCs.  The split is enforced by a sequence node inserted at position "node"
+ * in the schedule tree.  Return the updated schedule node.
+ * If either of these two parts consists of a sequence, then it is spliced
+ * into the sequence containing the two parts.
+ *
+ * The current band is reset. It would be possible to reuse
+ * the previously computed rows as the first rows in the next
+ * band, but recomputing them may result in better rows as we are looking
+ * at a smaller part of the dependence graph.
+ */
+static __isl_give isl_schedule_node *compute_split_schedule(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph)
+{
+	int is_seq;
+	isl_ctx *ctx;
+	isl_union_set_list *filters;
+
+	if (!node)
+		return NULL;
+
+	if (reset_band(graph) < 0)
+		return isl_schedule_node_free(node);
+
+	next_band(graph);
+
+	ctx = isl_schedule_node_get_ctx(node);
+	filters = extract_split(ctx, graph);
+	node = isl_schedule_node_insert_sequence(node, filters);
+	node = isl_schedule_node_child(node, 1);
+	node = isl_schedule_node_child(node, 0);
+
+	node = compute_sub_schedule(node, ctx, graph,
+				&node_scc_at_least, &edge_src_scc_at_least,
+				graph->src_scc + 1, 0);
+	is_seq = isl_schedule_node_get_type(node) == isl_schedule_node_sequence;
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_parent(node);
+	if (is_seq)
+		node = isl_schedule_node_sequence_splice_child(node, 1);
+	node = isl_schedule_node_child(node, 0);
+	node = isl_schedule_node_child(node, 0);
+	node = compute_sub_schedule(node, ctx, graph,
+				&node_scc_at_most, &edge_dst_scc_at_most,
+				graph->src_scc, 0);
+	is_seq = isl_schedule_node_get_type(node) == isl_schedule_node_sequence;
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_parent(node);
+	if (is_seq)
+		node = isl_schedule_node_sequence_splice_child(node, 0);
+
+	return node;
+}
+
+/* Insert a band node at position "node" in the schedule tree corresponding
+ * to the current band in "graph".  Mark the band node permutable
+ * if "permutable" is set.
+ * The partial schedules and the coincidence property are extracted
+ * from the graph nodes.
+ * Return the updated schedule node.
+ */
+static __isl_give isl_schedule_node *insert_current_band(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph,
+	int permutable)
+{
+	int i;
+	int start, end, n;
+	isl_multi_aff *ma;
+	isl_multi_pw_aff *mpa;
+	isl_multi_union_pw_aff *mupa;
+
+	if (!node)
+		return NULL;
+
+	if (graph->n < 1)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_internal,
+			"graph should have at least one node",
+			return isl_schedule_node_free(node));
+
+	start = graph->band_start;
+	end = graph->n_total_row;
+	n = end - start;
+
+	ma = node_extract_partial_schedule_multi_aff(&graph->node[0], start, n);
+	mpa = isl_multi_pw_aff_from_multi_aff(ma);
+	mupa = isl_multi_union_pw_aff_from_multi_pw_aff(mpa);
+
+	for (i = 1; i < graph->n; ++i) {
+		isl_multi_union_pw_aff *mupa_i;
+
+		ma = node_extract_partial_schedule_multi_aff(&graph->node[i],
+								start, n);
+		mpa = isl_multi_pw_aff_from_multi_aff(ma);
+		mupa_i = isl_multi_union_pw_aff_from_multi_pw_aff(mpa);
+		mupa = isl_multi_union_pw_aff_union_add(mupa, mupa_i);
+	}
+	node = isl_schedule_node_insert_partial_schedule(node, mupa);
+
+	for (i = 0; i < n; ++i)
+		node = isl_schedule_node_band_member_set_coincident(node, i,
+					graph->node[0].coincident[start + i]);
+	node = isl_schedule_node_band_set_permutable(node, permutable);
+
+	return node;
+}
+
+/* Update the dependence relations based on the current schedule,
+ * add the current band to "node" and then continue with the computation
+ * of the next band.
+ * Return the updated schedule node.
+ */
+static __isl_give isl_schedule_node *compute_next_band(
+	__isl_take isl_schedule_node *node,
+	struct isl_sched_graph *graph, int permutable)
+{
+	isl_ctx *ctx;
+
+	if (!node)
+		return NULL;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	if (update_edges(ctx, graph) < 0)
+		return isl_schedule_node_free(node);
+	node = insert_current_band(node, graph, permutable);
+	next_band(graph);
+
+	node = isl_schedule_node_child(node, 0);
+	node = compute_schedule(node, graph);
+	node = isl_schedule_node_parent(node);
+
+	return node;
+}
+
+/* Add the constraints "coef" derived from an edge from "node" to itself
+ * to graph->lp in order to respect the dependences and to try and carry them.
+ * "pos" is the sequence number of the edge that needs to be carried.
+ * "coef" represents general constraints on coefficients (c_0, c_x)
+ * of valid constraints for (y - x) with x and y instances of the node.
+ *
+ * The constraints added to graph->lp need to enforce
+ *
+ *	(c_j_0 + c_j_x y) - (c_j_0 + c_j_x x)
+ *	= c_j_x (y - x) >= e_i
+ *
+ * for each (x,y) in the dependence relation of the edge.
+ * That is, (-e_i, c_j_x) needs to be plugged in for (c_0, c_x),
+ * taking into account that each coefficient in c_j_x is represented
+ * as a pair of non-negative coefficients.
+ */
+static isl_stat add_intra_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_node *node, __isl_take isl_basic_set *coef, int pos)
+{
+	int offset;
+	isl_ctx *ctx;
+	isl_dim_map *dim_map;
+
+	if (!coef)
+		return isl_stat_error;
+
+	ctx = isl_basic_set_get_ctx(coef);
+	offset = coef_var_offset(coef);
+	dim_map = intra_dim_map(ctx, graph, node, offset, 1);
+	isl_dim_map_range(dim_map, 3 + pos, 0, 0, 0, 1, -1);
+	graph->lp = add_constraints_dim_map(graph->lp, coef, dim_map);
+
+	return isl_stat_ok;
+}
+
+/* Add the constraints "coef" derived from an edge from "src" to "dst"
+ * to graph->lp in order to respect the dependences and to try and carry them.
+ * "pos" is the sequence number of the edge that needs to be carried or
+ * -1 if no attempt should be made to carry the dependences.
+ * "coef" represents general constraints on coefficients (c_0, c_n, c_x, c_y)
+ * of valid constraints for (x, y) with x and y instances of "src" and "dst".
+ *
+ * The constraints added to graph->lp need to enforce
+ *
+ *	(c_k_0 + c_k_n n + c_k_x y) - (c_j_0 + c_j_n n + c_j_x x) >= e_i
+ *
+ * for each (x,y) in the dependence relation of the edge or
+ *
+ *	(c_k_0 + c_k_n n + c_k_x y) - (c_j_0 + c_j_n n + c_j_x x) >= 0
+ *
+ * if pos is -1.
+ * That is,
+ * (-e_i + c_k_0 - c_j_0, c_k_n - c_j_n, -c_j_x, c_k_x)
+ * or
+ * (c_k_0 - c_j_0, c_k_n - c_j_n, -c_j_x, c_k_x)
+ * needs to be plugged in for (c_0, c_n, c_x, c_y),
+ * taking into account that each coefficient in c_j_x and c_k_x is represented
+ * as a pair of non-negative coefficients.
+ */
+static isl_stat add_inter_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_node *src, struct isl_sched_node *dst,
+	__isl_take isl_basic_set *coef, int pos)
+{
+	int offset;
+	isl_ctx *ctx;
+	isl_dim_map *dim_map;
+
+	if (!coef)
+		return isl_stat_error;
+
+	ctx = isl_basic_set_get_ctx(coef);
+	offset = coef_var_offset(coef);
+	dim_map = inter_dim_map(ctx, graph, src, dst, offset, 1);
+	if (pos >= 0)
+		isl_dim_map_range(dim_map, 3 + pos, 0, 0, 0, 1, -1);
+	graph->lp = add_constraints_dim_map(graph->lp, coef, dim_map);
+
+	return isl_stat_ok;
+}
+
+/* Data structure for keeping track of the data needed
+ * to exploit non-trivial lineality spaces.
+ *
+ * "any_non_trivial" is true if there are any non-trivial lineality spaces.
+ * If "any_non_trivial" is not true, then "equivalent" and "mask" may be NULL.
+ * "equivalent" connects instances to other instances on the same line(s).
+ * "mask" contains the domain spaces of "equivalent".
+ * Any instance set not in "mask" does not have a non-trivial lineality space.
+ */
+struct isl_exploit_lineality_data {
+	isl_bool any_non_trivial;
+	isl_union_map *equivalent;
+	isl_union_set *mask;
+};
+
+/* Data structure collecting information used during the construction
+ * of an LP for carrying dependences.
+ *
+ * "intra" is a sequence of coefficient constraints for intra-node edges.
+ * "inter" is a sequence of coefficient constraints for inter-node edges.
+ * "lineality" contains data used to exploit non-trivial lineality spaces.
+ */
+struct isl_carry {
+	isl_basic_set_list *intra;
+	isl_basic_set_list *inter;
+	struct isl_exploit_lineality_data lineality;
+};
+
+/* Free all the data stored in "carry".
+ */
+static void isl_carry_clear(struct isl_carry *carry)
+{
+	isl_basic_set_list_free(carry->intra);
+	isl_basic_set_list_free(carry->inter);
+	isl_union_map_free(carry->lineality.equivalent);
+	isl_union_set_free(carry->lineality.mask);
+}
+
+/* Return a pointer to the node in "graph" that lives in "space".
+ * If the requested node has been compressed, then "space"
+ * corresponds to the compressed space.
+ *
+ * First try and see if "space" is the space of an uncompressed node.
+ * If so, return that node.
+ * Otherwise, "space" was constructed by construct_compressed_id and
+ * contains a user pointer pointing to the node in the tuple id.
+ * However, this node belongs to the original dependence graph.
+ * If "graph" is a subgraph of this original dependence graph,
+ * then the node with the same space still needs to be looked up
+ * in the current graph.
+ */
+static struct isl_sched_node *graph_find_compressed_node(isl_ctx *ctx,
+	struct isl_sched_graph *graph, __isl_keep isl_space *space)
+{
+	isl_id *id;
+	struct isl_sched_node *node;
+
+	if (!space)
+		return NULL;
+
+	node = graph_find_node(ctx, graph, space);
+	if (node)
+		return node;
+
+	id = isl_space_get_tuple_id(space, isl_dim_set);
+	node = isl_id_get_user(id);
+	isl_id_free(id);
+
+	if (!node)
+		return NULL;
+
+	if (!is_node(graph->root, node))
+		isl_die(ctx, isl_error_internal,
+			"space points to invalid node", return NULL);
+	if (graph != graph->root)
+		node = graph_find_node(ctx, graph, node->space);
+
+	return node;
+}
+
+/* Internal data structure for add_all_constraints.
+ *
+ * "graph" is the schedule constraint graph for which an LP problem
+ * is being constructed.
+ * "carry_inter" indicates whether inter-node edges should be carried.
+ * "pos" is the position of the next edge that needs to be carried.
+ */
+struct isl_add_all_constraints_data {
+	isl_ctx *ctx;
+	struct isl_sched_graph *graph;
+	int carry_inter;
+	int pos;
+};
+
+/* Add the constraints "coef" derived from an edge from a node to itself
+ * to data->graph->lp in order to respect the dependences and
+ * to try and carry them.
+ *
+ * The space of "coef" is of the form
+ *
+ *	coefficients[[c_cst] -> S[c_x]]
+ *
+ * with S[c_x] the (compressed) space of the node.
+ * Extract the node from the space and call add_intra_constraints.
+ */
+static isl_stat lp_add_intra(__isl_take isl_basic_set *coef, void *user)
+{
+	struct isl_add_all_constraints_data *data = user;
+	isl_space *space;
+	struct isl_sched_node *node;
+
+	space = isl_basic_set_get_space(coef);
+	space = isl_space_range(isl_space_unwrap(space));
+	node = graph_find_compressed_node(data->ctx, data->graph, space);
+	isl_space_free(space);
+	return add_intra_constraints(data->graph, node, coef, data->pos++);
+}
+
+/* Add the constraints "coef" derived from an edge from a node j
+ * to a node k to data->graph->lp in order to respect the dependences and
+ * to try and carry them (provided data->carry_inter is set).
+ *
+ * The space of "coef" is of the form
+ *
+ *	coefficients[[c_cst, c_n] -> [S_j[c_x] -> S_k[c_y]]]
+ *
+ * with S_j[c_x] and S_k[c_y] the (compressed) spaces of the nodes.
+ * Extract the nodes from the space and call add_inter_constraints.
+ */
+static isl_stat lp_add_inter(__isl_take isl_basic_set *coef, void *user)
+{
+	struct isl_add_all_constraints_data *data = user;
+	isl_space *space, *dom;
+	struct isl_sched_node *src, *dst;
+	int pos;
+
+	space = isl_basic_set_get_space(coef);
+	space = isl_space_unwrap(isl_space_range(isl_space_unwrap(space)));
+	dom = isl_space_domain(isl_space_copy(space));
+	src = graph_find_compressed_node(data->ctx, data->graph, dom);
+	isl_space_free(dom);
+	space = isl_space_range(space);
+	dst = graph_find_compressed_node(data->ctx, data->graph, space);
+	isl_space_free(space);
+
+	pos = data->carry_inter ? data->pos++ : -1;
+	return add_inter_constraints(data->graph, src, dst, coef, pos);
+}
+
+/* Add constraints to graph->lp that force all (conditional) validity
+ * dependences to be respected and attempt to carry them.
+ * "intra" is the sequence of coefficient constraints for intra-node edges.
+ * "inter" is the sequence of coefficient constraints for inter-node edges.
+ * "carry_inter" indicates whether inter-node edges should be carried or
+ * only respected.
+ */
+static isl_stat add_all_constraints(isl_ctx *ctx, struct isl_sched_graph *graph,
+	__isl_keep isl_basic_set_list *intra,
+	__isl_keep isl_basic_set_list *inter, int carry_inter)
+{
+	struct isl_add_all_constraints_data data = { ctx, graph, carry_inter };
+
+	data.pos = 0;
+	if (isl_basic_set_list_foreach(intra, &lp_add_intra, &data) < 0)
+		return isl_stat_error;
+	if (isl_basic_set_list_foreach(inter, &lp_add_inter, &data) < 0)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Internal data structure for count_all_constraints
+ * for keeping track of the number of equality and inequality constraints.
+ */
+struct isl_sched_count {
+	int n_eq;
+	int n_ineq;
+};
+
+/* Add the number of equality and inequality constraints of "bset"
+ * to data->n_eq and data->n_ineq.
+ */
+static isl_stat bset_update_count(__isl_take isl_basic_set *bset, void *user)
+{
+	struct isl_sched_count *data = user;
+
+	return update_count(bset, 1, &data->n_eq, &data->n_ineq);
+}
+
+/* Count the number of equality and inequality constraints
+ * that will be added to the carry_lp problem.
+ * We count each edge exactly once.
+ * "intra" is the sequence of coefficient constraints for intra-node edges.
+ * "inter" is the sequence of coefficient constraints for inter-node edges.
+ */
+static isl_stat count_all_constraints(__isl_keep isl_basic_set_list *intra,
+	__isl_keep isl_basic_set_list *inter, int *n_eq, int *n_ineq)
+{
+	struct isl_sched_count data;
+
+	data.n_eq = data.n_ineq = 0;
+	if (isl_basic_set_list_foreach(inter, &bset_update_count, &data) < 0)
+		return isl_stat_error;
+	if (isl_basic_set_list_foreach(intra, &bset_update_count, &data) < 0)
+		return isl_stat_error;
+
+	*n_eq = data.n_eq;
+	*n_ineq = data.n_ineq;
+
+	return isl_stat_ok;
+}
+
+/* Construct an LP problem for finding schedule coefficients
+ * such that the schedule carries as many validity dependences as possible.
+ * In particular, for each dependence i, we bound the dependence distance
+ * from below by e_i, with 0 <= e_i <= 1 and then maximize the sum
+ * of all e_i's.  Dependences with e_i = 0 in the solution are simply
+ * respected, while those with e_i > 0 (in practice e_i = 1) are carried.
+ * "intra" is the sequence of coefficient constraints for intra-node edges.
+ * "inter" is the sequence of coefficient constraints for inter-node edges.
+ * "n_edge" is the total number of edges.
+ * "carry_inter" indicates whether inter-node edges should be carried or
+ * only respected.  That is, if "carry_inter" is not set, then
+ * no e_i variables are introduced for the inter-node edges.
+ *
+ * All variables of the LP are non-negative.  The actual coefficients
+ * may be negative, so each coefficient is represented as the difference
+ * of two non-negative variables.  The negative part always appears
+ * immediately before the positive part.
+ * Other than that, the variables have the following order
+ *
+ *	- sum of (1 - e_i) over all edges
+ *	- sum of all c_n coefficients
+ *		(unconstrained when computing non-parametric schedules)
+ *	- sum of positive and negative parts of all c_x coefficients
+ *	- for each edge
+ *		- e_i
+ *	- for each node
+ *		- positive and negative parts of c_i_x, in opposite order
+ *		- c_i_n (if parametric)
+ *		- c_i_0
+ *
+ * The constraints are those from the (validity) edges plus three equalities
+ * to express the sums and n_edge inequalities to express e_i <= 1.
+ */
+static isl_stat setup_carry_lp(isl_ctx *ctx, struct isl_sched_graph *graph,
+	int n_edge, __isl_keep isl_basic_set_list *intra,
+	__isl_keep isl_basic_set_list *inter, int carry_inter)
+{
+	int i;
+	int k;
+	isl_space *dim;
+	unsigned total;
+	int n_eq, n_ineq;
+
+	total = 3 + n_edge;
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[graph->sorted[i]];
+		node->start = total;
+		total += 1 + node->nparam + 2 * node->nvar;
+	}
+
+	if (count_all_constraints(intra, inter, &n_eq, &n_ineq) < 0)
+		return isl_stat_error;
+
+	dim = isl_space_set_alloc(ctx, 0, total);
+	isl_basic_set_free(graph->lp);
+	n_eq += 3;
+	n_ineq += n_edge;
+	graph->lp = isl_basic_set_alloc_space(dim, 0, n_eq, n_ineq);
+	graph->lp = isl_basic_set_set_rational(graph->lp);
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return isl_stat_error;
+	isl_seq_clr(graph->lp->eq[k], 1 + total);
+	isl_int_set_si(graph->lp->eq[k][0], -n_edge);
+	isl_int_set_si(graph->lp->eq[k][1], 1);
+	for (i = 0; i < n_edge; ++i)
+		isl_int_set_si(graph->lp->eq[k][4 + i], 1);
+
+	if (add_param_sum_constraint(graph, 1) < 0)
+		return isl_stat_error;
+	if (add_var_sum_constraint(graph, 2) < 0)
+		return isl_stat_error;
+
+	for (i = 0; i < n_edge; ++i) {
+		k = isl_basic_set_alloc_inequality(graph->lp);
+		if (k < 0)
+			return isl_stat_error;
+		isl_seq_clr(graph->lp->ineq[k], 1 + total);
+		isl_int_set_si(graph->lp->ineq[k][4 + i], -1);
+		isl_int_set_si(graph->lp->ineq[k][0], 1);
+	}
+
+	if (add_all_constraints(ctx, graph, intra, inter, carry_inter) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+static __isl_give isl_schedule_node *compute_component_schedule(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph,
+	int wcc);
+
+/* If the schedule_split_scaled option is set and if the linear
+ * parts of the scheduling rows for all nodes in the graphs have
+ * a non-trivial common divisor, then remove this
+ * common divisor from the linear part.
+ * Otherwise, insert a band node directly and continue with
+ * the construction of the schedule.
+ *
+ * If a non-trivial common divisor is found, then
+ * the linear part is reduced and the remainder is ignored.
+ * The pieces of the graph that are assigned different remainders
+ * form (groups of) strongly connected components within
+ * the scaled down band.  If needed, they can therefore
+ * be ordered along this remainder in a sequence node.
+ * However, this ordering is not enforced here in order to allow
+ * the scheduler to combine some of the strongly connected components.
+ */
+static __isl_give isl_schedule_node *split_scaled(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph)
+{
+	int i;
+	int row;
+	isl_ctx *ctx;
+	isl_int gcd, gcd_i;
+
+	if (!node)
+		return NULL;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	if (!ctx->opt->schedule_split_scaled)
+		return compute_next_band(node, graph, 0);
+	if (graph->n <= 1)
+		return compute_next_band(node, graph, 0);
+
+	isl_int_init(gcd);
+	isl_int_init(gcd_i);
+
+	isl_int_set_si(gcd, 0);
+
+	row = isl_mat_rows(graph->node[0].sched) - 1;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int cols = isl_mat_cols(node->sched);
+
+		isl_seq_gcd(node->sched->row[row] + 1, cols - 1, &gcd_i);
+		isl_int_gcd(gcd, gcd, gcd_i);
+	}
+
+	isl_int_clear(gcd_i);
+
+	if (isl_int_cmp_si(gcd, 1) <= 0) {
+		isl_int_clear(gcd);
+		return compute_next_band(node, graph, 0);
+	}
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+
+		isl_int_fdiv_q(node->sched->row[row][0],
+			       node->sched->row[row][0], gcd);
+		isl_int_mul(node->sched->row[row][0],
+			    node->sched->row[row][0], gcd);
+		node->sched = isl_mat_scale_down_row(node->sched, row, gcd);
+		if (!node->sched)
+			goto error;
+	}
+
+	isl_int_clear(gcd);
+
+	return compute_next_band(node, graph, 0);
+error:
+	isl_int_clear(gcd);
+	return isl_schedule_node_free(node);
+}
+
+/* Is the schedule row "sol" trivial on node "node"?
+ * That is, is the solution zero on the dimensions linearly independent of
+ * the previously found solutions?
+ * Return 1 if the solution is trivial, 0 if it is not and -1 on error.
+ *
+ * Each coefficient is represented as the difference between
+ * two non-negative values in "sol".
+ * We construct the schedule row s and check if it is linearly
+ * independent of previously computed schedule rows
+ * by computing T s, with T the linear combinations that are zero
+ * on linearly dependent schedule rows.
+ * If the result consists of all zeros, then the solution is trivial.
+ */
+static int is_trivial(struct isl_sched_node *node, __isl_keep isl_vec *sol)
+{
+	int trivial;
+	isl_vec *node_sol;
+
+	if (!sol)
+		return -1;
+	if (node->nvar == node->rank)
+		return 0;
+
+	node_sol = extract_var_coef(node, sol);
+	node_sol = isl_mat_vec_product(isl_mat_copy(node->indep), node_sol);
+	if (!node_sol)
+		return -1;
+
+	trivial = isl_seq_first_non_zero(node_sol->el,
+					node->nvar - node->rank) == -1;
+
+	isl_vec_free(node_sol);
+
+	return trivial;
+}
+
+/* Is the schedule row "sol" trivial on any node where it should
+ * not be trivial?
+ * Return 1 if any solution is trivial, 0 if they are not and -1 on error.
+ */
+static int is_any_trivial(struct isl_sched_graph *graph,
+	__isl_keep isl_vec *sol)
+{
+	int i;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int trivial;
+
+		if (!needs_row(graph, node))
+			continue;
+		trivial = is_trivial(node, sol);
+		if (trivial < 0 || trivial)
+			return trivial;
+	}
+
+	return 0;
+}
+
+/* Does the schedule represented by "sol" perform loop coalescing on "node"?
+ * If so, return the position of the coalesced dimension.
+ * Otherwise, return node->nvar or -1 on error.
+ *
+ * In particular, look for pairs of coefficients c_i and c_j such that
+ * |c_j/c_i| > ceil(size_i/2), i.e., |c_j| > |c_i * ceil(size_i/2)|.
+ * If any such pair is found, then return i.
+ * If size_i is infinity, then no check on c_i needs to be performed.
+ */
+static int find_node_coalescing(struct isl_sched_node *node,
+	__isl_keep isl_vec *sol)
+{
+	int i, j;
+	isl_int max;
+	isl_vec *csol;
+
+	if (node->nvar <= 1)
+		return node->nvar;
+
+	csol = extract_var_coef(node, sol);
+	if (!csol)
+		return -1;
+	isl_int_init(max);
+	for (i = 0; i < node->nvar; ++i) {
+		isl_val *v;
+
+		if (isl_int_is_zero(csol->el[i]))
+			continue;
+		v = isl_multi_val_get_val(node->sizes, i);
+		if (!v)
+			goto error;
+		if (!isl_val_is_int(v)) {
+			isl_val_free(v);
+			continue;
+		}
+		v = isl_val_div_ui(v, 2);
+		v = isl_val_ceil(v);
+		if (!v)
+			goto error;
+		isl_int_mul(max, v->n, csol->el[i]);
+		isl_val_free(v);
+
+		for (j = 0; j < node->nvar; ++j) {
+			if (j == i)
+				continue;
+			if (isl_int_abs_gt(csol->el[j], max))
+				break;
+		}
+		if (j < node->nvar)
+			break;
+	}
+
+	isl_int_clear(max);
+	isl_vec_free(csol);
+	return i;
+error:
+	isl_int_clear(max);
+	isl_vec_free(csol);
+	return -1;
+}
+
+/* Force the schedule coefficient at position "pos" of "node" to be zero
+ * in "tl".
+ * The coefficient is encoded as the difference between two non-negative
+ * variables.  Force these two variables to have the same value.
+ */
+static __isl_give isl_tab_lexmin *zero_out_node_coef(
+	__isl_take isl_tab_lexmin *tl, struct isl_sched_node *node, int pos)
+{
+	int dim;
+	isl_ctx *ctx;
+	isl_vec *eq;
+
+	ctx = isl_space_get_ctx(node->space);
+	dim = isl_tab_lexmin_dim(tl);
+	if (dim < 0)
+		return isl_tab_lexmin_free(tl);
+	eq = isl_vec_alloc(ctx, 1 + dim);
+	eq = isl_vec_clr(eq);
+	if (!eq)
+		return isl_tab_lexmin_free(tl);
+
+	pos = 1 + node_var_coef_pos(node, pos);
+	isl_int_set_si(eq->el[pos], 1);
+	isl_int_set_si(eq->el[pos + 1], -1);
+	tl = isl_tab_lexmin_add_eq(tl, eq->el);
+	isl_vec_free(eq);
+
+	return tl;
+}
+
+/* Return the lexicographically smallest rational point in the basic set
+ * from which "tl" was constructed, double checking that this input set
+ * was not empty.
+ */
+static __isl_give isl_vec *non_empty_solution(__isl_keep isl_tab_lexmin *tl)
+{
+	isl_vec *sol;
+
+	sol = isl_tab_lexmin_get_solution(tl);
+	if (!sol)
+		return NULL;
+	if (sol->size == 0)
+		isl_die(isl_vec_get_ctx(sol), isl_error_internal,
+			"error in schedule construction",
+			return isl_vec_free(sol));
+	return sol;
+}
+
+/* Does the solution "sol" of the LP problem constructed by setup_carry_lp
+ * carry any of the "n_edge" groups of dependences?
+ * The value in the first position is the sum of (1 - e_i) over all "n_edge"
+ * edges, with 0 <= e_i <= 1 equal to 1 when the dependences represented
+ * by the edge are carried by the solution.
+ * If the sum of the (1 - e_i) is smaller than "n_edge" then at least
+ * one of those is carried.
+ *
+ * Note that despite the fact that the problem is solved using a rational
+ * solver, the solution is guaranteed to be integral.
+ * Specifically, the dependence distance lower bounds e_i (and therefore
+ * also their sum) are integers.  See Lemma 5 of [1].
+ *
+ * Any potential denominator of the sum is cleared by this function.
+ * The denominator is not relevant for any of the other elements
+ * in the solution.
+ *
+ * [1] P. Feautrier, Some Efficient Solutions to the Affine Scheduling
+ *     Problem, Part II: Multi-Dimensional Time.
+ *     In Intl. Journal of Parallel Programming, 1992.
+ */
+static int carries_dependences(__isl_keep isl_vec *sol, int n_edge)
+{
+	isl_int_divexact(sol->el[1], sol->el[1], sol->el[0]);
+	isl_int_set_si(sol->el[0], 1);
+	return isl_int_cmp_si(sol->el[1], n_edge) < 0;
+}
+
+/* Return the lexicographically smallest rational point in "lp",
+ * assuming that all variables are non-negative and performing some
+ * additional sanity checks.
+ * If "want_integral" is set, then compute the lexicographically smallest
+ * integer point instead.
+ * In particular, "lp" should not be empty by construction.
+ * Double check that this is the case.
+ * If dependences are not carried for any of the "n_edge" edges,
+ * then return an empty vector.
+ *
+ * If the schedule_treat_coalescing option is set and
+ * if the computed schedule performs loop coalescing on a given node,
+ * i.e., if it is of the form
+ *
+ *	c_i i + c_j j + ...
+ *
+ * with |c_j/c_i| >= size_i, then force the coefficient c_i to be zero
+ * to cut out this solution.  Repeat this process until no more loop
+ * coalescing occurs or until no more dependences can be carried.
+ * In the latter case, revert to the previously computed solution.
+ *
+ * If the caller requests an integral solution and if coalescing should
+ * be treated, then perform the coalescing treatment first as
+ * an integral solution computed before coalescing treatment
+ * would carry the same number of edges and would therefore probably
+ * also be coalescing.
+ *
+ * To allow the coalescing treatment to be performed first,
+ * the initial solution is allowed to be rational and it is only
+ * cut out (if needed) in the next iteration, if no coalescing measures
+ * were taken.
+ */
+static __isl_give isl_vec *non_neg_lexmin(struct isl_sched_graph *graph,
+	__isl_take isl_basic_set *lp, int n_edge, int want_integral)
+{
+	int i, pos, cut;
+	isl_ctx *ctx;
+	isl_tab_lexmin *tl;
+	isl_vec *sol, *prev = NULL;
+	int treat_coalescing;
+
+	if (!lp)
+		return NULL;
+	ctx = isl_basic_set_get_ctx(lp);
+	treat_coalescing = isl_options_get_schedule_treat_coalescing(ctx);
+	tl = isl_tab_lexmin_from_basic_set(lp);
+
+	cut = 0;
+	do {
+		int integral;
+
+		if (cut)
+			tl = isl_tab_lexmin_cut_to_integer(tl);
+		sol = non_empty_solution(tl);
+		if (!sol)
+			goto error;
+
+		integral = isl_int_is_one(sol->el[0]);
+		if (!carries_dependences(sol, n_edge)) {
+			if (!prev)
+				prev = isl_vec_alloc(ctx, 0);
+			isl_vec_free(sol);
+			sol = prev;
+			break;
+		}
+		prev = isl_vec_free(prev);
+		cut = want_integral && !integral;
+		if (cut)
+			prev = sol;
+		if (!treat_coalescing)
+			continue;
+		for (i = 0; i < graph->n; ++i) {
+			struct isl_sched_node *node = &graph->node[i];
+
+			pos = find_node_coalescing(node, sol);
+			if (pos < 0)
+				goto error;
+			if (pos < node->nvar)
+				break;
+		}
+		if (i < graph->n) {
+			prev = sol;
+			tl = zero_out_node_coef(tl, &graph->node[i], pos);
+			cut = 0;
+		}
+	} while (prev);
+
+	isl_tab_lexmin_free(tl);
+
+	return sol;
+error:
+	isl_tab_lexmin_free(tl);
+	isl_vec_free(prev);
+	isl_vec_free(sol);
+	return NULL;
+}
+
+/* If "edge" is an edge from a node to itself, then add the corresponding
+ * dependence relation to "umap".
+ * If "node" has been compressed, then the dependence relation
+ * is also compressed first.
+ */
+static __isl_give isl_union_map *add_intra(__isl_take isl_union_map *umap,
+	struct isl_sched_edge *edge)
+{
+	isl_map *map;
+	struct isl_sched_node *node = edge->src;
+
+	if (edge->src != edge->dst)
+		return umap;
+
+	map = isl_map_copy(edge->map);
+	if (node->compressed) {
+		map = isl_map_preimage_domain_multi_aff(map,
+				    isl_multi_aff_copy(node->decompress));
+		map = isl_map_preimage_range_multi_aff(map,
+				    isl_multi_aff_copy(node->decompress));
+	}
+	umap = isl_union_map_add_map(umap, map);
+	return umap;
+}
+
+/* If "edge" is an edge from a node to another node, then add the corresponding
+ * dependence relation to "umap".
+ * If the source or destination nodes of "edge" have been compressed,
+ * then the dependence relation is also compressed first.
+ */
+static __isl_give isl_union_map *add_inter(__isl_take isl_union_map *umap,
+	struct isl_sched_edge *edge)
+{
+	isl_map *map;
+
+	if (edge->src == edge->dst)
+		return umap;
+
+	map = isl_map_copy(edge->map);
+	if (edge->src->compressed)
+		map = isl_map_preimage_domain_multi_aff(map,
+				    isl_multi_aff_copy(edge->src->decompress));
+	if (edge->dst->compressed)
+		map = isl_map_preimage_range_multi_aff(map,
+				    isl_multi_aff_copy(edge->dst->decompress));
+	umap = isl_union_map_add_map(umap, map);
+	return umap;
+}
+
+/* Internal data structure used by union_drop_coalescing_constraints
+ * to collect bounds on all relevant statements.
+ *
+ * "graph" is the schedule constraint graph for which an LP problem
+ * is being constructed.
+ * "bounds" collects the bounds.
+ */
+struct isl_collect_bounds_data {
+	isl_ctx *ctx;
+	struct isl_sched_graph *graph;
+	isl_union_set *bounds;
+};
+
+/* Add the size bounds for the node with instance deltas in "set"
+ * to data->bounds.
+ */
+static isl_stat collect_bounds(__isl_take isl_set *set, void *user)
+{
+	struct isl_collect_bounds_data *data = user;
+	struct isl_sched_node *node;
+	isl_space *space;
+	isl_set *bounds;
+
+	space = isl_set_get_space(set);
+	isl_set_free(set);
+
+	node = graph_find_compressed_node(data->ctx, data->graph, space);
+	isl_space_free(space);
+
+	bounds = isl_set_from_basic_set(get_size_bounds(node));
+	data->bounds = isl_union_set_add_set(data->bounds, bounds);
+
+	return isl_stat_ok;
+}
+
+/* Drop some constraints from "delta" that could be exploited
+ * to construct loop coalescing schedules.
+ * In particular, drop those constraint that bound the difference
+ * to the size of the domain.
+ * Do this for each set/node in "delta" separately.
+ * The parameters are assumed to have been projected out by the caller.
+ */
+static __isl_give isl_union_set *union_drop_coalescing_constraints(isl_ctx *ctx,
+	struct isl_sched_graph *graph, __isl_take isl_union_set *delta)
+{
+	struct isl_collect_bounds_data data = { ctx, graph };
+
+	data.bounds = isl_union_set_empty(isl_space_params_alloc(ctx, 0));
+	if (isl_union_set_foreach_set(delta, &collect_bounds, &data) < 0)
+		data.bounds = isl_union_set_free(data.bounds);
+	delta = isl_union_set_plain_gist(delta, data.bounds);
+
+	return delta;
+}
+
+/* Given a non-trivial lineality space "lineality", add the corresponding
+ * universe set to data->mask and add a map from elements to
+ * other elements along the lines in "lineality" to data->equivalent.
+ * If this is the first time this function gets called
+ * (data->any_non_trivial is still false), then set data->any_non_trivial and
+ * initialize data->mask and data->equivalent.
+ *
+ * In particular, if the lineality space is defined by equality constraints
+ *
+ *	E x = 0
+ *
+ * then construct an affine mapping
+ *
+ *	f : x -> E x
+ *
+ * and compute the equivalence relation of having the same image under f:
+ *
+ *	{ x -> x' : E x = E x' }
+ */
+static isl_stat add_non_trivial_lineality(__isl_take isl_basic_set *lineality,
+	struct isl_exploit_lineality_data *data)
+{
+	isl_mat *eq;
+	isl_space *space;
+	isl_set *univ;
+	isl_multi_aff *ma;
+	isl_multi_pw_aff *mpa;
+	isl_map *map;
+	int n;
+
+	if (!lineality)
+		return isl_stat_error;
+	if (isl_basic_set_dim(lineality, isl_dim_div) != 0)
+		isl_die(isl_basic_set_get_ctx(lineality), isl_error_internal,
+			"local variables not allowed", goto error);
+
+	space = isl_basic_set_get_space(lineality);
+	if (!data->any_non_trivial) {
+		data->equivalent = isl_union_map_empty(isl_space_copy(space));
+		data->mask = isl_union_set_empty(isl_space_copy(space));
+	}
+	data->any_non_trivial = isl_bool_true;
+
+	univ = isl_set_universe(isl_space_copy(space));
+	data->mask = isl_union_set_add_set(data->mask, univ);
+
+	eq = isl_basic_set_extract_equalities(lineality);
+	n = isl_mat_rows(eq);
+	eq = isl_mat_insert_zero_rows(eq, 0, 1);
+	eq = isl_mat_set_element_si(eq, 0, 0, 1);
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, n);
+	ma = isl_multi_aff_from_aff_mat(space, eq);
+	mpa = isl_multi_pw_aff_from_multi_aff(ma);
+	map = isl_multi_pw_aff_eq_map(mpa, isl_multi_pw_aff_copy(mpa));
+	data->equivalent = isl_union_map_add_map(data->equivalent, map);
+
+	isl_basic_set_free(lineality);
+	return isl_stat_ok;
+error:
+	isl_basic_set_free(lineality);
+	return isl_stat_error;
+}
+
+/* Check if the lineality space "set" is non-trivial (i.e., is not just
+ * the origin or, in other words, satisfies a number of equality constraints
+ * that is smaller than the dimension of the set).
+ * If so, extend data->mask and data->equivalent accordingly.
+ *
+ * The input should not have any local variables already, but
+ * isl_set_remove_divs is called to make sure it does not.
+ */
+static isl_stat add_lineality(__isl_take isl_set *set, void *user)
+{
+	struct isl_exploit_lineality_data *data = user;
+	isl_basic_set *hull;
+	int dim, n_eq;
+
+	set = isl_set_remove_divs(set);
+	hull = isl_set_unshifted_simple_hull(set);
+	dim = isl_basic_set_dim(hull, isl_dim_set);
+	n_eq = isl_basic_set_n_equality(hull);
+	if (!hull)
+		return isl_stat_error;
+	if (dim != n_eq)
+		return add_non_trivial_lineality(hull, data);
+	isl_basic_set_free(hull);
+	return isl_stat_ok;
+}
+
+/* Check if the difference set on intra-node schedule constraints "intra"
+ * has any non-trivial lineality space.
+ * If so, then extend the difference set to a difference set
+ * on equivalent elements.  That is, if "intra" is
+ *
+ *	{ y - x : (x,y) \in V }
+ *
+ * and elements are equivalent if they have the same image under f,
+ * then return
+ *
+ *	{ y' - x' : (x,y) \in V and f(x) = f(x') and f(y) = f(y') }
+ *
+ * or, since f is linear,
+ *
+ *	{ y' - x' : (x,y) \in V and f(y - x) = f(y' - x') }
+ *
+ * The results of the search for non-trivial lineality spaces is stored
+ * in "data".
+ */
+static __isl_give isl_union_set *exploit_intra_lineality(
+	__isl_take isl_union_set *intra,
+	struct isl_exploit_lineality_data *data)
+{
+	isl_union_set *lineality;
+	isl_union_set *uset;
+
+	data->any_non_trivial = isl_bool_false;
+	lineality = isl_union_set_copy(intra);
+	lineality = isl_union_set_combined_lineality_space(lineality);
+	if (isl_union_set_foreach_set(lineality, &add_lineality, data) < 0)
+		data->any_non_trivial = isl_bool_error;
+	isl_union_set_free(lineality);
+
+	if (data->any_non_trivial < 0)
+		return isl_union_set_free(intra);
+	if (!data->any_non_trivial)
+		return intra;
+
+	uset = isl_union_set_copy(intra);
+	intra = isl_union_set_subtract(intra, isl_union_set_copy(data->mask));
+	uset = isl_union_set_apply(uset, isl_union_map_copy(data->equivalent));
+	intra = isl_union_set_union(intra, uset);
+
+	intra = isl_union_set_remove_divs(intra);
+
+	return intra;
+}
+
+/* If the difference set on intra-node schedule constraints was found to have
+ * any non-trivial lineality space by exploit_intra_lineality,
+ * as recorded in "data", then extend the inter-node
+ * schedule constraints "inter" to schedule constraints on equivalent elements.
+ * That is, if "inter" is V and
+ * elements are equivalent if they have the same image under f, then return
+ *
+ *	{ (x', y') : (x,y) \in V and f(x) = f(x') and f(y) = f(y') }
+ */
+static __isl_give isl_union_map *exploit_inter_lineality(
+	__isl_take isl_union_map *inter,
+	struct isl_exploit_lineality_data *data)
+{
+	isl_union_map *umap;
+
+	if (data->any_non_trivial < 0)
+		return isl_union_map_free(inter);
+	if (!data->any_non_trivial)
+		return inter;
+
+	umap = isl_union_map_copy(inter);
+	inter = isl_union_map_subtract_range(inter,
+				isl_union_set_copy(data->mask));
+	umap = isl_union_map_apply_range(umap,
+				isl_union_map_copy(data->equivalent));
+	inter = isl_union_map_union(inter, umap);
+	umap = isl_union_map_copy(inter);
+	inter = isl_union_map_subtract_domain(inter,
+				isl_union_set_copy(data->mask));
+	umap = isl_union_map_apply_range(isl_union_map_copy(data->equivalent),
+				umap);
+	inter = isl_union_map_union(inter, umap);
+
+	inter = isl_union_map_remove_divs(inter);
+
+	return inter;
+}
+
+/* For each (conditional) validity edge in "graph",
+ * add the corresponding dependence relation using "add"
+ * to a collection of dependence relations and return the result.
+ * If "coincidence" is set, then coincidence edges are considered as well.
+ */
+static __isl_give isl_union_map *collect_validity(struct isl_sched_graph *graph,
+	__isl_give isl_union_map *(*add)(__isl_take isl_union_map *umap,
+		struct isl_sched_edge *edge), int coincidence)
+{
+	int i;
+	isl_space *space;
+	isl_union_map *umap;
+
+	space = isl_space_copy(graph->node[0].space);
+	umap = isl_union_map_empty(space);
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge = &graph->edge[i];
+
+		if (!is_any_validity(edge) &&
+		    (!coincidence || !is_coincidence(edge)))
+			continue;
+
+		umap = add(umap, edge);
+	}
+
+	return umap;
+}
+
+/* Project out all parameters from "uset" and return the result.
+ */
+static __isl_give isl_union_set *union_set_drop_parameters(
+	__isl_take isl_union_set *uset)
+{
+	unsigned nparam;
+
+	nparam = isl_union_set_dim(uset, isl_dim_param);
+	return isl_union_set_project_out(uset, isl_dim_param, 0, nparam);
+}
+
+/* For each dependence relation on a (conditional) validity edge
+ * from a node to itself,
+ * construct the set of coefficients of valid constraints for elements
+ * in that dependence relation and collect the results.
+ * If "coincidence" is set, then coincidence edges are considered as well.
+ *
+ * In particular, for each dependence relation R, constraints
+ * on coefficients (c_0, c_x) are constructed such that
+ *
+ *	c_0 + c_x d >= 0 for each d in delta R = { y - x | (x,y) in R }
+ *
+ * If the schedule_treat_coalescing option is set, then some constraints
+ * that could be exploited to construct coalescing schedules
+ * are removed before the dual is computed, but after the parameters
+ * have been projected out.
+ * The entire computation is essentially the same as that performed
+ * by intra_coefficients, except that it operates on multiple
+ * edges together and that the parameters are always projected out.
+ *
+ * Additionally, exploit any non-trivial lineality space
+ * in the difference set after removing coalescing constraints and
+ * store the results of the non-trivial lineality space detection in "data".
+ * The procedure is currently run unconditionally, but it is unlikely
+ * to find any non-trivial lineality spaces if no coalescing constraints
+ * have been removed.
+ *
+ * Note that if a dependence relation is a union of basic maps,
+ * then each basic map needs to be treated individually as it may only
+ * be possible to carry the dependences expressed by some of those
+ * basic maps and not all of them.
+ * The collected validity constraints are therefore not coalesced and
+ * it is assumed that they are not coalesced automatically.
+ * Duplicate basic maps can be removed, however.
+ * In particular, if the same basic map appears as a disjunct
+ * in multiple edges, then it only needs to be carried once.
+ */
+static __isl_give isl_basic_set_list *collect_intra_validity(isl_ctx *ctx,
+	struct isl_sched_graph *graph, int coincidence,
+	struct isl_exploit_lineality_data *data)
+{
+	isl_union_map *intra;
+	isl_union_set *delta;
+	isl_basic_set_list *list;
+
+	intra = collect_validity(graph, &add_intra, coincidence);
+	delta = isl_union_map_deltas(intra);
+	delta = union_set_drop_parameters(delta);
+	delta = isl_union_set_remove_divs(delta);
+	if (isl_options_get_schedule_treat_coalescing(ctx))
+		delta = union_drop_coalescing_constraints(ctx, graph, delta);
+	delta = exploit_intra_lineality(delta, data);
+	list = isl_union_set_get_basic_set_list(delta);
+	isl_union_set_free(delta);
+
+	return isl_basic_set_list_coefficients(list);
+}
+
+/* For each dependence relation on a (conditional) validity edge
+ * from a node to some other node,
+ * construct the set of coefficients of valid constraints for elements
+ * in that dependence relation and collect the results.
+ * If "coincidence" is set, then coincidence edges are considered as well.
+ *
+ * In particular, for each dependence relation R, constraints
+ * on coefficients (c_0, c_n, c_x, c_y) are constructed such that
+ *
+ *	c_0 + c_n n + c_x x + c_y y >= 0 for each (x,y) in R
+ *
+ * This computation is essentially the same as that performed
+ * by inter_coefficients, except that it operates on multiple
+ * edges together.
+ *
+ * Additionally, exploit any non-trivial lineality space
+ * that may have been discovered by collect_intra_validity
+ * (as stored in "data").
+ *
+ * Note that if a dependence relation is a union of basic maps,
+ * then each basic map needs to be treated individually as it may only
+ * be possible to carry the dependences expressed by some of those
+ * basic maps and not all of them.
+ * The collected validity constraints are therefore not coalesced and
+ * it is assumed that they are not coalesced automatically.
+ * Duplicate basic maps can be removed, however.
+ * In particular, if the same basic map appears as a disjunct
+ * in multiple edges, then it only needs to be carried once.
+ */
+static __isl_give isl_basic_set_list *collect_inter_validity(
+	struct isl_sched_graph *graph, int coincidence,
+	struct isl_exploit_lineality_data *data)
+{
+	isl_union_map *inter;
+	isl_union_set *wrap;
+	isl_basic_set_list *list;
+
+	inter = collect_validity(graph, &add_inter, coincidence);
+	inter = exploit_inter_lineality(inter, data);
+	inter = isl_union_map_remove_divs(inter);
+	wrap = isl_union_map_wrap(inter);
+	list = isl_union_set_get_basic_set_list(wrap);
+	isl_union_set_free(wrap);
+	return isl_basic_set_list_coefficients(list);
+}
+
+/* Construct an LP problem for finding schedule coefficients
+ * such that the schedule carries as many of the "n_edge" groups of
+ * dependences as possible based on the corresponding coefficient
+ * constraints and return the lexicographically smallest non-trivial solution.
+ * "intra" is the sequence of coefficient constraints for intra-node edges.
+ * "inter" is the sequence of coefficient constraints for inter-node edges.
+ * If "want_integral" is set, then compute an integral solution
+ * for the coefficients rather than using the numerators
+ * of a rational solution.
+ * "carry_inter" indicates whether inter-node edges should be carried or
+ * only respected.
+ *
+ * If none of the "n_edge" groups can be carried
+ * then return an empty vector.
+ */
+static __isl_give isl_vec *compute_carrying_sol_coef(isl_ctx *ctx,
+	struct isl_sched_graph *graph, int n_edge,
+	__isl_keep isl_basic_set_list *intra,
+	__isl_keep isl_basic_set_list *inter, int want_integral,
+	int carry_inter)
+{
+	isl_basic_set *lp;
+
+	if (setup_carry_lp(ctx, graph, n_edge, intra, inter, carry_inter) < 0)
+		return NULL;
+
+	lp = isl_basic_set_copy(graph->lp);
+	return non_neg_lexmin(graph, lp, n_edge, want_integral);
+}
+
+/* Construct an LP problem for finding schedule coefficients
+ * such that the schedule carries as many of the validity dependences
+ * as possible and
+ * return the lexicographically smallest non-trivial solution.
+ * If "fallback" is set, then the carrying is performed as a fallback
+ * for the Pluto-like scheduler.
+ * If "coincidence" is set, then try and carry coincidence edges as well.
+ *
+ * The variable "n_edge" stores the number of groups that should be carried.
+ * If none of the "n_edge" groups can be carried
+ * then return an empty vector.
+ * If, moreover, "n_edge" is zero, then the LP problem does not even
+ * need to be constructed.
+ *
+ * If a fallback solution is being computed, then compute an integral solution
+ * for the coefficients rather than using the numerators
+ * of a rational solution.
+ *
+ * If a fallback solution is being computed, if there are any intra-node
+ * dependences, and if requested by the user, then first try
+ * to only carry those intra-node dependences.
+ * If this fails to carry any dependences, then try again
+ * with the inter-node dependences included.
+ */
+static __isl_give isl_vec *compute_carrying_sol(isl_ctx *ctx,
+	struct isl_sched_graph *graph, int fallback, int coincidence)
+{
+	int n_intra, n_inter;
+	int n_edge;
+	struct isl_carry carry = { 0 };
+	isl_vec *sol;
+
+	carry.intra = collect_intra_validity(ctx, graph, coincidence,
+						&carry.lineality);
+	carry.inter = collect_inter_validity(graph, coincidence,
+						&carry.lineality);
+	if (!carry.intra || !carry.inter)
+		goto error;
+	n_intra = isl_basic_set_list_n_basic_set(carry.intra);
+	n_inter = isl_basic_set_list_n_basic_set(carry.inter);
+
+	if (fallback && n_intra > 0 &&
+	    isl_options_get_schedule_carry_self_first(ctx)) {
+		sol = compute_carrying_sol_coef(ctx, graph, n_intra,
+				carry.intra, carry.inter, fallback, 0);
+		if (!sol || sol->size != 0 || n_inter == 0) {
+			isl_carry_clear(&carry);
+			return sol;
+		}
+		isl_vec_free(sol);
+	}
+
+	n_edge = n_intra + n_inter;
+	if (n_edge == 0) {
+		isl_carry_clear(&carry);
+		return isl_vec_alloc(ctx, 0);
+	}
+
+	sol = compute_carrying_sol_coef(ctx, graph, n_edge,
+				carry.intra, carry.inter, fallback, 1);
+	isl_carry_clear(&carry);
+	return sol;
+error:
+	isl_carry_clear(&carry);
+	return NULL;
+}
+
+/* Construct a schedule row for each node such that as many validity dependences
+ * as possible are carried and then continue with the next band.
+ * If "fallback" is set, then the carrying is performed as a fallback
+ * for the Pluto-like scheduler.
+ * If "coincidence" is set, then try and carry coincidence edges as well.
+ *
+ * If there are no validity dependences, then no dependence can be carried and
+ * the procedure is guaranteed to fail.  If there is more than one component,
+ * then try computing a schedule on each component separately
+ * to prevent or at least postpone this failure.
+ *
+ * If a schedule row is computed, then check that dependences are carried
+ * for at least one of the edges.
+ *
+ * If the computed schedule row turns out to be trivial on one or
+ * more nodes where it should not be trivial, then we throw it away
+ * and try again on each component separately.
+ *
+ * If there is only one component, then we accept the schedule row anyway,
+ * but we do not consider it as a complete row and therefore do not
+ * increment graph->n_row.  Note that the ranks of the nodes that
+ * do get a non-trivial schedule part will get updated regardless and
+ * graph->maxvar is computed based on these ranks.  The test for
+ * whether more schedule rows are required in compute_schedule_wcc
+ * is therefore not affected.
+ *
+ * Insert a band corresponding to the schedule row at position "node"
+ * of the schedule tree and continue with the construction of the schedule.
+ * This insertion and the continued construction is performed by split_scaled
+ * after optionally checking for non-trivial common divisors.
+ */
+static __isl_give isl_schedule_node *carry(__isl_take isl_schedule_node *node,
+	struct isl_sched_graph *graph, int fallback, int coincidence)
+{
+	int trivial;
+	isl_ctx *ctx;
+	isl_vec *sol;
+
+	if (!node)
+		return NULL;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	sol = compute_carrying_sol(ctx, graph, fallback, coincidence);
+	if (!sol)
+		return isl_schedule_node_free(node);
+	if (sol->size == 0) {
+		isl_vec_free(sol);
+		if (graph->scc > 1)
+			return compute_component_schedule(node, graph, 1);
+		isl_die(ctx, isl_error_unknown, "unable to carry dependences",
+			return isl_schedule_node_free(node));
+	}
+
+	trivial = is_any_trivial(graph, sol);
+	if (trivial < 0) {
+		sol = isl_vec_free(sol);
+	} else if (trivial && graph->scc > 1) {
+		isl_vec_free(sol);
+		return compute_component_schedule(node, graph, 1);
+	}
+
+	if (update_schedule(graph, sol, 0) < 0)
+		return isl_schedule_node_free(node);
+	if (trivial)
+		graph->n_row--;
+
+	return split_scaled(node, graph);
+}
+
+/* Construct a schedule row for each node such that as many validity dependences
+ * as possible are carried and then continue with the next band.
+ * Do so as a fallback for the Pluto-like scheduler.
+ * If "coincidence" is set, then try and carry coincidence edges as well.
+ */
+static __isl_give isl_schedule_node *carry_fallback(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph,
+	int coincidence)
+{
+	return carry(node, graph, 1, coincidence);
+}
+
+/* Construct a schedule row for each node such that as many validity dependences
+ * as possible are carried and then continue with the next band.
+ * Do so for the case where the Feautrier scheduler was selected
+ * by the user.
+ */
+static __isl_give isl_schedule_node *carry_feautrier(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph)
+{
+	return carry(node, graph, 0, 0);
+}
+
+/* Construct a schedule row for each node such that as many validity dependences
+ * as possible are carried and then continue with the next band.
+ * Do so as a fallback for the Pluto-like scheduler.
+ */
+static __isl_give isl_schedule_node *carry_dependences(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph)
+{
+	return carry_fallback(node, graph, 0);
+}
+
+/* Construct a schedule row for each node such that as many validity or
+ * coincidence dependences as possible are carried and
+ * then continue with the next band.
+ * Do so as a fallback for the Pluto-like scheduler.
+ */
+static __isl_give isl_schedule_node *carry_coincidence(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph)
+{
+	return carry_fallback(node, graph, 1);
+}
+
+/* Topologically sort statements mapped to the same schedule iteration
+ * and add insert a sequence node in front of "node"
+ * corresponding to this order.
+ * If "initialized" is set, then it may be assumed that compute_maxvar
+ * has been called on the current band.  Otherwise, call
+ * compute_maxvar if and before carry_dependences gets called.
+ *
+ * If it turns out to be impossible to sort the statements apart,
+ * because different dependences impose different orderings
+ * on the statements, then we extend the schedule such that
+ * it carries at least one more dependence.
+ */
+static __isl_give isl_schedule_node *sort_statements(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph,
+	int initialized)
+{
+	isl_ctx *ctx;
+	isl_union_set_list *filters;
+
+	if (!node)
+		return NULL;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	if (graph->n < 1)
+		isl_die(ctx, isl_error_internal,
+			"graph should have at least one node",
+			return isl_schedule_node_free(node));
+
+	if (graph->n == 1)
+		return node;
+
+	if (update_edges(ctx, graph) < 0)
+		return isl_schedule_node_free(node);
+
+	if (graph->n_edge == 0)
+		return node;
+
+	if (detect_sccs(ctx, graph) < 0)
+		return isl_schedule_node_free(node);
+
+	next_band(graph);
+	if (graph->scc < graph->n) {
+		if (!initialized && compute_maxvar(graph) < 0)
+			return isl_schedule_node_free(node);
+		return carry_dependences(node, graph);
+	}
+
+	filters = extract_sccs(ctx, graph);
+	node = isl_schedule_node_insert_sequence(node, filters);
+
+	return node;
+}
+
+/* Are there any (non-empty) (conditional) validity edges in the graph?
+ */
+static int has_validity_edges(struct isl_sched_graph *graph)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		int empty;
+
+		empty = isl_map_plain_is_empty(graph->edge[i].map);
+		if (empty < 0)
+			return -1;
+		if (empty)
+			continue;
+		if (is_any_validity(&graph->edge[i]))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Should we apply a Feautrier step?
+ * That is, did the user request the Feautrier algorithm and are
+ * there any validity dependences (left)?
+ */
+static int need_feautrier_step(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	if (ctx->opt->schedule_algorithm != ISL_SCHEDULE_ALGORITHM_FEAUTRIER)
+		return 0;
+
+	return has_validity_edges(graph);
+}
+
+/* Compute a schedule for a connected dependence graph using Feautrier's
+ * multi-dimensional scheduling algorithm and return the updated schedule node.
+ *
+ * The original algorithm is described in [1].
+ * The main idea is to minimize the number of scheduling dimensions, by
+ * trying to satisfy as many dependences as possible per scheduling dimension.
+ *
+ * [1] P. Feautrier, Some Efficient Solutions to the Affine Scheduling
+ *     Problem, Part II: Multi-Dimensional Time.
+ *     In Intl. Journal of Parallel Programming, 1992.
+ */
+static __isl_give isl_schedule_node *compute_schedule_wcc_feautrier(
+	isl_schedule_node *node, struct isl_sched_graph *graph)
+{
+	return carry_feautrier(node, graph);
+}
+
+/* Turn off the "local" bit on all (condition) edges.
+ */
+static void clear_local_edges(struct isl_sched_graph *graph)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i)
+		if (is_condition(&graph->edge[i]))
+			clear_local(&graph->edge[i]);
+}
+
+/* Does "graph" have both condition and conditional validity edges?
+ */
+static int need_condition_check(struct isl_sched_graph *graph)
+{
+	int i;
+	int any_condition = 0;
+	int any_conditional_validity = 0;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		if (is_condition(&graph->edge[i]))
+			any_condition = 1;
+		if (is_conditional_validity(&graph->edge[i]))
+			any_conditional_validity = 1;
+	}
+
+	return any_condition && any_conditional_validity;
+}
+
+/* Does "graph" contain any coincidence edge?
+ */
+static int has_any_coincidence(struct isl_sched_graph *graph)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i)
+		if (is_coincidence(&graph->edge[i]))
+			return 1;
+
+	return 0;
+}
+
+/* Extract the final schedule row as a map with the iteration domain
+ * of "node" as domain.
+ */
+static __isl_give isl_map *final_row(struct isl_sched_node *node)
+{
+	isl_multi_aff *ma;
+	int row;
+
+	row = isl_mat_rows(node->sched) - 1;
+	ma = node_extract_partial_schedule_multi_aff(node, row, 1);
+	return isl_map_from_multi_aff(ma);
+}
+
+/* Is the conditional validity dependence in the edge with index "edge_index"
+ * violated by the latest (i.e., final) row of the schedule?
+ * That is, is i scheduled after j
+ * for any conditional validity dependence i -> j?
+ */
+static int is_violated(struct isl_sched_graph *graph, int edge_index)
+{
+	isl_map *src_sched, *dst_sched, *map;
+	struct isl_sched_edge *edge = &graph->edge[edge_index];
+	int empty;
+
+	src_sched = final_row(edge->src);
+	dst_sched = final_row(edge->dst);
+	map = isl_map_copy(edge->map);
+	map = isl_map_apply_domain(map, src_sched);
+	map = isl_map_apply_range(map, dst_sched);
+	map = isl_map_order_gt(map, isl_dim_in, 0, isl_dim_out, 0);
+	empty = isl_map_is_empty(map);
+	isl_map_free(map);
+
+	if (empty < 0)
+		return -1;
+
+	return !empty;
+}
+
+/* Does "graph" have any satisfied condition edges that
+ * are adjacent to the conditional validity constraint with
+ * domain "conditional_source" and range "conditional_sink"?
+ *
+ * A satisfied condition is one that is not local.
+ * If a condition was forced to be local already (i.e., marked as local)
+ * then there is no need to check if it is in fact local.
+ *
+ * Additionally, mark all adjacent condition edges found as local.
+ */
+static int has_adjacent_true_conditions(struct isl_sched_graph *graph,
+	__isl_keep isl_union_set *conditional_source,
+	__isl_keep isl_union_set *conditional_sink)
+{
+	int i;
+	int any = 0;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		int adjacent, local;
+		isl_union_map *condition;
+
+		if (!is_condition(&graph->edge[i]))
+			continue;
+		if (is_local(&graph->edge[i]))
+			continue;
+
+		condition = graph->edge[i].tagged_condition;
+		adjacent = domain_intersects(condition, conditional_sink);
+		if (adjacent >= 0 && !adjacent)
+			adjacent = range_intersects(condition,
+							conditional_source);
+		if (adjacent < 0)
+			return -1;
+		if (!adjacent)
+			continue;
+
+		set_local(&graph->edge[i]);
+
+		local = is_condition_false(&graph->edge[i]);
+		if (local < 0)
+			return -1;
+		if (!local)
+			any = 1;
+	}
+
+	return any;
+}
+
+/* Are there any violated conditional validity dependences with
+ * adjacent condition dependences that are not local with respect
+ * to the current schedule?
+ * That is, is the conditional validity constraint violated?
+ *
+ * Additionally, mark all those adjacent condition dependences as local.
+ * We also mark those adjacent condition dependences that were not marked
+ * as local before, but just happened to be local already.  This ensures
+ * that they remain local if the schedule is recomputed.
+ *
+ * We first collect domain and range of all violated conditional validity
+ * dependences and then check if there are any adjacent non-local
+ * condition dependences.
+ */
+static int has_violated_conditional_constraint(isl_ctx *ctx,
+	struct isl_sched_graph *graph)
+{
+	int i;
+	int any = 0;
+	isl_union_set *source, *sink;
+
+	source = isl_union_set_empty(isl_space_params_alloc(ctx, 0));
+	sink = isl_union_set_empty(isl_space_params_alloc(ctx, 0));
+	for (i = 0; i < graph->n_edge; ++i) {
+		isl_union_set *uset;
+		isl_union_map *umap;
+		int violated;
+
+		if (!is_conditional_validity(&graph->edge[i]))
+			continue;
+
+		violated = is_violated(graph, i);
+		if (violated < 0)
+			goto error;
+		if (!violated)
+			continue;
+
+		any = 1;
+
+		umap = isl_union_map_copy(graph->edge[i].tagged_validity);
+		uset = isl_union_map_domain(umap);
+		source = isl_union_set_union(source, uset);
+		source = isl_union_set_coalesce(source);
+
+		umap = isl_union_map_copy(graph->edge[i].tagged_validity);
+		uset = isl_union_map_range(umap);
+		sink = isl_union_set_union(sink, uset);
+		sink = isl_union_set_coalesce(sink);
+	}
+
+	if (any)
+		any = has_adjacent_true_conditions(graph, source, sink);
+
+	isl_union_set_free(source);
+	isl_union_set_free(sink);
+	return any;
+error:
+	isl_union_set_free(source);
+	isl_union_set_free(sink);
+	return -1;
+}
+
+/* Examine the current band (the rows between graph->band_start and
+ * graph->n_total_row), deciding whether to drop it or add it to "node"
+ * and then continue with the computation of the next band, if any.
+ * If "initialized" is set, then it may be assumed that compute_maxvar
+ * has been called on the current band.  Otherwise, call
+ * compute_maxvar if and before carry_dependences gets called.
+ *
+ * The caller keeps looking for a new row as long as
+ * graph->n_row < graph->maxvar.  If the latest attempt to find
+ * such a row failed (i.e., we still have graph->n_row < graph->maxvar),
+ * then we either
+ * - split between SCCs and start over (assuming we found an interesting
+ *	pair of SCCs between which to split)
+ * - continue with the next band (assuming the current band has at least
+ *	one row)
+ * - if there is more than one SCC left, then split along all SCCs
+ * - if outer coincidence needs to be enforced, then try to carry as many
+ *	validity or coincidence dependences as possible and
+ *	continue with the next band
+ * - try to carry as many validity dependences as possible and
+ *	continue with the next band
+ * In each case, we first insert a band node in the schedule tree
+ * if any rows have been computed.
+ *
+ * If the caller managed to complete the schedule, we insert a band node
+ * (if any schedule rows were computed) and we finish off by topologically
+ * sorting the statements based on the remaining dependences.
+ */
+static __isl_give isl_schedule_node *compute_schedule_finish_band(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph,
+	int initialized)
+{
+	int insert;
+
+	if (!node)
+		return NULL;
+
+	if (graph->n_row < graph->maxvar) {
+		isl_ctx *ctx;
+		int empty = graph->n_total_row == graph->band_start;
+
+		ctx = isl_schedule_node_get_ctx(node);
+		if (!ctx->opt->schedule_maximize_band_depth && !empty)
+			return compute_next_band(node, graph, 1);
+		if (graph->src_scc >= 0)
+			return compute_split_schedule(node, graph);
+		if (!empty)
+			return compute_next_band(node, graph, 1);
+		if (graph->scc > 1)
+			return compute_component_schedule(node, graph, 1);
+		if (!initialized && compute_maxvar(graph) < 0)
+			return isl_schedule_node_free(node);
+		if (isl_options_get_schedule_outer_coincidence(ctx))
+			return carry_coincidence(node, graph);
+		return carry_dependences(node, graph);
+	}
+
+	insert = graph->n_total_row > graph->band_start;
+	if (insert) {
+		node = insert_current_band(node, graph, 1);
+		node = isl_schedule_node_child(node, 0);
+	}
+	node = sort_statements(node, graph, initialized);
+	if (insert)
+		node = isl_schedule_node_parent(node);
+
+	return node;
+}
+
+/* Construct a band of schedule rows for a connected dependence graph.
+ * The caller is responsible for determining the strongly connected
+ * components and calling compute_maxvar first.
+ *
+ * We try to find a sequence of as many schedule rows as possible that result
+ * in non-negative dependence distances (independent of the previous rows
+ * in the sequence, i.e., such that the sequence is tilable), with as
+ * many of the initial rows as possible satisfying the coincidence constraints.
+ * The computation stops if we can't find any more rows or if we have found
+ * all the rows we wanted to find.
+ *
+ * If ctx->opt->schedule_outer_coincidence is set, then we force the
+ * outermost dimension to satisfy the coincidence constraints.  If this
+ * turns out to be impossible, we fall back on the general scheme above
+ * and try to carry as many dependences as possible.
+ *
+ * If "graph" contains both condition and conditional validity dependences,
+ * then we need to check that that the conditional schedule constraint
+ * is satisfied, i.e., there are no violated conditional validity dependences
+ * that are adjacent to any non-local condition dependences.
+ * If there are, then we mark all those adjacent condition dependences
+ * as local and recompute the current band.  Those dependences that
+ * are marked local will then be forced to be local.
+ * The initial computation is performed with no dependences marked as local.
+ * If we are lucky, then there will be no violated conditional validity
+ * dependences adjacent to any non-local condition dependences.
+ * Otherwise, we mark some additional condition dependences as local and
+ * recompute.  We continue this process until there are no violations left or
+ * until we are no longer able to compute a schedule.
+ * Since there are only a finite number of dependences,
+ * there will only be a finite number of iterations.
+ */
+static isl_stat compute_schedule_wcc_band(isl_ctx *ctx,
+	struct isl_sched_graph *graph)
+{
+	int has_coincidence;
+	int use_coincidence;
+	int force_coincidence = 0;
+	int check_conditional;
+
+	if (sort_sccs(graph) < 0)
+		return isl_stat_error;
+
+	clear_local_edges(graph);
+	check_conditional = need_condition_check(graph);
+	has_coincidence = has_any_coincidence(graph);
+
+	if (ctx->opt->schedule_outer_coincidence)
+		force_coincidence = 1;
+
+	use_coincidence = has_coincidence;
+	while (graph->n_row < graph->maxvar) {
+		isl_vec *sol;
+		int violated;
+		int coincident;
+
+		graph->src_scc = -1;
+		graph->dst_scc = -1;
+
+		if (setup_lp(ctx, graph, use_coincidence) < 0)
+			return isl_stat_error;
+		sol = solve_lp(ctx, graph);
+		if (!sol)
+			return isl_stat_error;
+		if (sol->size == 0) {
+			int empty = graph->n_total_row == graph->band_start;
+
+			isl_vec_free(sol);
+			if (use_coincidence && (!force_coincidence || !empty)) {
+				use_coincidence = 0;
+				continue;
+			}
+			return isl_stat_ok;
+		}
+		coincident = !has_coincidence || use_coincidence;
+		if (update_schedule(graph, sol, coincident) < 0)
+			return isl_stat_error;
+
+		if (!check_conditional)
+			continue;
+		violated = has_violated_conditional_constraint(ctx, graph);
+		if (violated < 0)
+			return isl_stat_error;
+		if (!violated)
+			continue;
+		if (reset_band(graph) < 0)
+			return isl_stat_error;
+		use_coincidence = has_coincidence;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Compute a schedule for a connected dependence graph by considering
+ * the graph as a whole and return the updated schedule node.
+ *
+ * The actual schedule rows of the current band are computed by
+ * compute_schedule_wcc_band.  compute_schedule_finish_band takes
+ * care of integrating the band into "node" and continuing
+ * the computation.
+ */
+static __isl_give isl_schedule_node *compute_schedule_wcc_whole(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph)
+{
+	isl_ctx *ctx;
+
+	if (!node)
+		return NULL;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	if (compute_schedule_wcc_band(ctx, graph) < 0)
+		return isl_schedule_node_free(node);
+
+	return compute_schedule_finish_band(node, graph, 1);
+}
+
+/* Clustering information used by compute_schedule_wcc_clustering.
+ *
+ * "n" is the number of SCCs in the original dependence graph
+ * "scc" is an array of "n" elements, each representing an SCC
+ * of the original dependence graph.  All entries in the same cluster
+ * have the same number of schedule rows.
+ * "scc_cluster" maps each SCC index to the cluster to which it belongs,
+ * where each cluster is represented by the index of the first SCC
+ * in the cluster.  Initially, each SCC belongs to a cluster containing
+ * only that SCC.
+ *
+ * "scc_in_merge" is used by merge_clusters_along_edge to keep
+ * track of which SCCs need to be merged.
+ *
+ * "cluster" contains the merged clusters of SCCs after the clustering
+ * has completed.
+ *
+ * "scc_node" is a temporary data structure used inside copy_partial.
+ * For each SCC, it keeps track of the number of nodes in the SCC
+ * that have already been copied.
+ */
+struct isl_clustering {
+	int n;
+	struct isl_sched_graph *scc;
+	struct isl_sched_graph *cluster;
+	int *scc_cluster;
+	int *scc_node;
+	int *scc_in_merge;
+};
+
+/* Initialize the clustering data structure "c" from "graph".
+ *
+ * In particular, allocate memory, extract the SCCs from "graph"
+ * into c->scc, initialize scc_cluster and construct
+ * a band of schedule rows for each SCC.
+ * Within each SCC, there is only one SCC by definition.
+ * Each SCC initially belongs to a cluster containing only that SCC.
+ */
+static isl_stat clustering_init(isl_ctx *ctx, struct isl_clustering *c,
+	struct isl_sched_graph *graph)
+{
+	int i;
+
+	c->n = graph->scc;
+	c->scc = isl_calloc_array(ctx, struct isl_sched_graph, c->n);
+	c->cluster = isl_calloc_array(ctx, struct isl_sched_graph, c->n);
+	c->scc_cluster = isl_calloc_array(ctx, int, c->n);
+	c->scc_node = isl_calloc_array(ctx, int, c->n);
+	c->scc_in_merge = isl_calloc_array(ctx, int, c->n);
+	if (!c->scc || !c->cluster ||
+	    !c->scc_cluster || !c->scc_node || !c->scc_in_merge)
+		return isl_stat_error;
+
+	for (i = 0; i < c->n; ++i) {
+		if (extract_sub_graph(ctx, graph, &node_scc_exactly,
+					&edge_scc_exactly, i, &c->scc[i]) < 0)
+			return isl_stat_error;
+		c->scc[i].scc = 1;
+		if (compute_maxvar(&c->scc[i]) < 0)
+			return isl_stat_error;
+		if (compute_schedule_wcc_band(ctx, &c->scc[i]) < 0)
+			return isl_stat_error;
+		c->scc_cluster[i] = i;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Free all memory allocated for "c".
+ */
+static void clustering_free(isl_ctx *ctx, struct isl_clustering *c)
+{
+	int i;
+
+	if (c->scc)
+		for (i = 0; i < c->n; ++i)
+			graph_free(ctx, &c->scc[i]);
+	free(c->scc);
+	if (c->cluster)
+		for (i = 0; i < c->n; ++i)
+			graph_free(ctx, &c->cluster[i]);
+	free(c->cluster);
+	free(c->scc_cluster);
+	free(c->scc_node);
+	free(c->scc_in_merge);
+}
+
+/* Should we refrain from merging the cluster in "graph" with
+ * any other cluster?
+ * In particular, is its current schedule band empty and incomplete.
+ */
+static int bad_cluster(struct isl_sched_graph *graph)
+{
+	return graph->n_row < graph->maxvar &&
+		graph->n_total_row == graph->band_start;
+}
+
+/* Is "edge" a proximity edge with a non-empty dependence relation?
+ */
+static isl_bool is_non_empty_proximity(struct isl_sched_edge *edge)
+{
+	if (!is_proximity(edge))
+		return isl_bool_false;
+	return isl_bool_not(isl_map_plain_is_empty(edge->map));
+}
+
+/* Return the index of an edge in "graph" that can be used to merge
+ * two clusters in "c".
+ * Return graph->n_edge if no such edge can be found.
+ * Return -1 on error.
+ *
+ * In particular, return a proximity edge between two clusters
+ * that is not marked "no_merge" and such that neither of the
+ * two clusters has an incomplete, empty band.
+ *
+ * If there are multiple such edges, then try and find the most
+ * appropriate edge to use for merging.  In particular, pick the edge
+ * with the greatest weight.  If there are multiple of those,
+ * then pick one with the shortest distance between
+ * the two cluster representatives.
+ */
+static int find_proximity(struct isl_sched_graph *graph,
+	struct isl_clustering *c)
+{
+	int i, best = graph->n_edge, best_dist, best_weight;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge = &graph->edge[i];
+		int dist, weight;
+		isl_bool prox;
+
+		prox = is_non_empty_proximity(edge);
+		if (prox < 0)
+			return -1;
+		if (!prox)
+			continue;
+		if (edge->no_merge)
+			continue;
+		if (bad_cluster(&c->scc[edge->src->scc]) ||
+		    bad_cluster(&c->scc[edge->dst->scc]))
+			continue;
+		dist = c->scc_cluster[edge->dst->scc] -
+			c->scc_cluster[edge->src->scc];
+		if (dist == 0)
+			continue;
+		weight = edge->weight;
+		if (best < graph->n_edge) {
+			if (best_weight > weight)
+				continue;
+			if (best_weight == weight && best_dist <= dist)
+				continue;
+		}
+		best = i;
+		best_dist = dist;
+		best_weight = weight;
+	}
+
+	return best;
+}
+
+/* Internal data structure used in mark_merge_sccs.
+ *
+ * "graph" is the dependence graph in which a strongly connected
+ * component is constructed.
+ * "scc_cluster" maps each SCC index to the cluster to which it belongs.
+ * "src" and "dst" are the indices of the nodes that are being merged.
+ */
+struct isl_mark_merge_sccs_data {
+	struct isl_sched_graph *graph;
+	int *scc_cluster;
+	int src;
+	int dst;
+};
+
+/* Check whether the cluster containing node "i" depends on the cluster
+ * containing node "j".  If "i" and "j" belong to the same cluster,
+ * then they are taken to depend on each other to ensure that
+ * the resulting strongly connected component consists of complete
+ * clusters.  Furthermore, if "i" and "j" are the two nodes that
+ * are being merged, then they are taken to depend on each other as well.
+ * Otherwise, check if there is a (conditional) validity dependence
+ * from node[j] to node[i], forcing node[i] to follow node[j].
+ */
+static isl_bool cluster_follows(int i, int j, void *user)
+{
+	struct isl_mark_merge_sccs_data *data = user;
+	struct isl_sched_graph *graph = data->graph;
+	int *scc_cluster = data->scc_cluster;
+
+	if (data->src == i && data->dst == j)
+		return isl_bool_true;
+	if (data->src == j && data->dst == i)
+		return isl_bool_true;
+	if (scc_cluster[graph->node[i].scc] == scc_cluster[graph->node[j].scc])
+		return isl_bool_true;
+
+	return graph_has_validity_edge(graph, &graph->node[j], &graph->node[i]);
+}
+
+/* Mark all SCCs that belong to either of the two clusters in "c"
+ * connected by the edge in "graph" with index "edge", or to any
+ * of the intermediate clusters.
+ * The marking is recorded in c->scc_in_merge.
+ *
+ * The given edge has been selected for merging two clusters,
+ * meaning that there is at least a proximity edge between the two nodes.
+ * However, there may also be (indirect) validity dependences
+ * between the two nodes.  When merging the two clusters, all clusters
+ * containing one or more of the intermediate nodes along the
+ * indirect validity dependences need to be merged in as well.
+ *
+ * First collect all such nodes by computing the strongly connected
+ * component (SCC) containing the two nodes connected by the edge, where
+ * the two nodes are considered to depend on each other to make
+ * sure they end up in the same SCC.  Similarly, each node is considered
+ * to depend on every other node in the same cluster to ensure
+ * that the SCC consists of complete clusters.
+ *
+ * Then the original SCCs that contain any of these nodes are marked
+ * in c->scc_in_merge.
+ */
+static isl_stat mark_merge_sccs(isl_ctx *ctx, struct isl_sched_graph *graph,
+	int edge, struct isl_clustering *c)
+{
+	struct isl_mark_merge_sccs_data data;
+	struct isl_tarjan_graph *g;
+	int i;
+
+	for (i = 0; i < c->n; ++i)
+		c->scc_in_merge[i] = 0;
+
+	data.graph = graph;
+	data.scc_cluster = c->scc_cluster;
+	data.src = graph->edge[edge].src - graph->node;
+	data.dst = graph->edge[edge].dst - graph->node;
+
+	g = isl_tarjan_graph_component(ctx, graph->n, data.dst,
+					&cluster_follows, &data);
+	if (!g)
+		goto error;
+
+	i = g->op;
+	if (i < 3)
+		isl_die(ctx, isl_error_internal,
+			"expecting at least two nodes in component",
+			goto error);
+	if (g->order[--i] != -1)
+		isl_die(ctx, isl_error_internal,
+			"expecting end of component marker", goto error);
+
+	for (--i; i >= 0 && g->order[i] != -1; --i) {
+		int scc = graph->node[g->order[i]].scc;
+		c->scc_in_merge[scc] = 1;
+	}
+
+	isl_tarjan_graph_free(g);
+	return isl_stat_ok;
+error:
+	isl_tarjan_graph_free(g);
+	return isl_stat_error;
+}
+
+/* Construct the identifier "cluster_i".
+ */
+static __isl_give isl_id *cluster_id(isl_ctx *ctx, int i)
+{
+	char name[40];
+
+	snprintf(name, sizeof(name), "cluster_%d", i);
+	return isl_id_alloc(ctx, name, NULL);
+}
+
+/* Construct the space of the cluster with index "i" containing
+ * the strongly connected component "scc".
+ *
+ * In particular, construct a space called cluster_i with dimension equal
+ * to the number of schedule rows in the current band of "scc".
+ */
+static __isl_give isl_space *cluster_space(struct isl_sched_graph *scc, int i)
+{
+	int nvar;
+	isl_space *space;
+	isl_id *id;
+
+	nvar = scc->n_total_row - scc->band_start;
+	space = isl_space_copy(scc->node[0].space);
+	space = isl_space_params(space);
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, nvar);
+	id = cluster_id(isl_space_get_ctx(space), i);
+	space = isl_space_set_tuple_id(space, isl_dim_set, id);
+
+	return space;
+}
+
+/* Collect the domain of the graph for merging clusters.
+ *
+ * In particular, for each cluster with first SCC "i", construct
+ * a set in the space called cluster_i with dimension equal
+ * to the number of schedule rows in the current band of the cluster.
+ */
+static __isl_give isl_union_set *collect_domain(isl_ctx *ctx,
+	struct isl_sched_graph *graph, struct isl_clustering *c)
+{
+	int i;
+	isl_space *space;
+	isl_union_set *domain;
+
+	space = isl_space_params_alloc(ctx, 0);
+	domain = isl_union_set_empty(space);
+
+	for (i = 0; i < graph->scc; ++i) {
+		isl_space *space;
+
+		if (!c->scc_in_merge[i])
+			continue;
+		if (c->scc_cluster[i] != i)
+			continue;
+		space = cluster_space(&c->scc[i], i);
+		domain = isl_union_set_add_set(domain, isl_set_universe(space));
+	}
+
+	return domain;
+}
+
+/* Construct a map from the original instances to the corresponding
+ * cluster instance in the current bands of the clusters in "c".
+ */
+static __isl_give isl_union_map *collect_cluster_map(isl_ctx *ctx,
+	struct isl_sched_graph *graph, struct isl_clustering *c)
+{
+	int i, j;
+	isl_space *space;
+	isl_union_map *cluster_map;
+
+	space = isl_space_params_alloc(ctx, 0);
+	cluster_map = isl_union_map_empty(space);
+	for (i = 0; i < graph->scc; ++i) {
+		int start, n;
+		isl_id *id;
+
+		if (!c->scc_in_merge[i])
+			continue;
+
+		id = cluster_id(ctx, c->scc_cluster[i]);
+		start = c->scc[i].band_start;
+		n = c->scc[i].n_total_row - start;
+		for (j = 0; j < c->scc[i].n; ++j) {
+			isl_multi_aff *ma;
+			isl_map *map;
+			struct isl_sched_node *node = &c->scc[i].node[j];
+
+			ma = node_extract_partial_schedule_multi_aff(node,
+								    start, n);
+			ma = isl_multi_aff_set_tuple_id(ma, isl_dim_out,
+							    isl_id_copy(id));
+			map = isl_map_from_multi_aff(ma);
+			cluster_map = isl_union_map_add_map(cluster_map, map);
+		}
+		isl_id_free(id);
+	}
+
+	return cluster_map;
+}
+
+/* Add "umap" to the schedule constraints "sc" of all types of "edge"
+ * that are not isl_edge_condition or isl_edge_conditional_validity.
+ */
+static __isl_give isl_schedule_constraints *add_non_conditional_constraints(
+	struct isl_sched_edge *edge, __isl_keep isl_union_map *umap,
+	__isl_take isl_schedule_constraints *sc)
+{
+	enum isl_edge_type t;
+
+	if (!sc)
+		return NULL;
+
+	for (t = isl_edge_first; t <= isl_edge_last; ++t) {
+		if (t == isl_edge_condition ||
+		    t == isl_edge_conditional_validity)
+			continue;
+		if (!is_type(edge, t))
+			continue;
+		sc = isl_schedule_constraints_add(sc, t,
+						    isl_union_map_copy(umap));
+	}
+
+	return sc;
+}
+
+/* Add schedule constraints of types isl_edge_condition and
+ * isl_edge_conditional_validity to "sc" by applying "umap" to
+ * the domains of the wrapped relations in domain and range
+ * of the corresponding tagged constraints of "edge".
+ */
+static __isl_give isl_schedule_constraints *add_conditional_constraints(
+	struct isl_sched_edge *edge, __isl_keep isl_union_map *umap,
+	__isl_take isl_schedule_constraints *sc)
+{
+	enum isl_edge_type t;
+	isl_union_map *tagged;
+
+	for (t = isl_edge_condition; t <= isl_edge_conditional_validity; ++t) {
+		if (!is_type(edge, t))
+			continue;
+		if (t == isl_edge_condition)
+			tagged = isl_union_map_copy(edge->tagged_condition);
+		else
+			tagged = isl_union_map_copy(edge->tagged_validity);
+		tagged = isl_union_map_zip(tagged);
+		tagged = isl_union_map_apply_domain(tagged,
+					isl_union_map_copy(umap));
+		tagged = isl_union_map_zip(tagged);
+		sc = isl_schedule_constraints_add(sc, t, tagged);
+		if (!sc)
+			return NULL;
+	}
+
+	return sc;
+}
+
+/* Given a mapping "cluster_map" from the original instances to
+ * the cluster instances, add schedule constraints on the clusters
+ * to "sc" corresponding to the original constraints represented by "edge".
+ *
+ * For non-tagged dependence constraints, the cluster constraints
+ * are obtained by applying "cluster_map" to the edge->map.
+ *
+ * For tagged dependence constraints, "cluster_map" needs to be applied
+ * to the domains of the wrapped relations in domain and range
+ * of the tagged dependence constraints.  Pick out the mappings
+ * from these domains from "cluster_map" and construct their product.
+ * This mapping can then be applied to the pair of domains.
+ */
+static __isl_give isl_schedule_constraints *collect_edge_constraints(
+	struct isl_sched_edge *edge, __isl_keep isl_union_map *cluster_map,
+	__isl_take isl_schedule_constraints *sc)
+{
+	isl_union_map *umap;
+	isl_space *space;
+	isl_union_set *uset;
+	isl_union_map *umap1, *umap2;
+
+	if (!sc)
+		return NULL;
+
+	umap = isl_union_map_from_map(isl_map_copy(edge->map));
+	umap = isl_union_map_apply_domain(umap,
+				isl_union_map_copy(cluster_map));
+	umap = isl_union_map_apply_range(umap,
+				isl_union_map_copy(cluster_map));
+	sc = add_non_conditional_constraints(edge, umap, sc);
+	isl_union_map_free(umap);
+
+	if (!sc || (!is_condition(edge) && !is_conditional_validity(edge)))
+		return sc;
+
+	space = isl_space_domain(isl_map_get_space(edge->map));
+	uset = isl_union_set_from_set(isl_set_universe(space));
+	umap1 = isl_union_map_copy(cluster_map);
+	umap1 = isl_union_map_intersect_domain(umap1, uset);
+	space = isl_space_range(isl_map_get_space(edge->map));
+	uset = isl_union_set_from_set(isl_set_universe(space));
+	umap2 = isl_union_map_copy(cluster_map);
+	umap2 = isl_union_map_intersect_domain(umap2, uset);
+	umap = isl_union_map_product(umap1, umap2);
+
+	sc = add_conditional_constraints(edge, umap, sc);
+
+	isl_union_map_free(umap);
+	return sc;
+}
+
+/* Given a mapping "cluster_map" from the original instances to
+ * the cluster instances, add schedule constraints on the clusters
+ * to "sc" corresponding to all edges in "graph" between nodes that
+ * belong to SCCs that are marked for merging in "scc_in_merge".
+ */
+static __isl_give isl_schedule_constraints *collect_constraints(
+	struct isl_sched_graph *graph, int *scc_in_merge,
+	__isl_keep isl_union_map *cluster_map,
+	__isl_take isl_schedule_constraints *sc)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge = &graph->edge[i];
+
+		if (!scc_in_merge[edge->src->scc])
+			continue;
+		if (!scc_in_merge[edge->dst->scc])
+			continue;
+		sc = collect_edge_constraints(edge, cluster_map, sc);
+	}
+
+	return sc;
+}
+
+/* Construct a dependence graph for scheduling clusters with respect
+ * to each other and store the result in "merge_graph".
+ * In particular, the nodes of the graph correspond to the schedule
+ * dimensions of the current bands of those clusters that have been
+ * marked for merging in "c".
+ *
+ * First construct an isl_schedule_constraints object for this domain
+ * by transforming the edges in "graph" to the domain.
+ * Then initialize a dependence graph for scheduling from these
+ * constraints.
+ */
+static isl_stat init_merge_graph(isl_ctx *ctx, struct isl_sched_graph *graph,
+	struct isl_clustering *c, struct isl_sched_graph *merge_graph)
+{
+	isl_union_set *domain;
+	isl_union_map *cluster_map;
+	isl_schedule_constraints *sc;
+	isl_stat r;
+
+	domain = collect_domain(ctx, graph, c);
+	sc = isl_schedule_constraints_on_domain(domain);
+	if (!sc)
+		return isl_stat_error;
+	cluster_map = collect_cluster_map(ctx, graph, c);
+	sc = collect_constraints(graph, c->scc_in_merge, cluster_map, sc);
+	isl_union_map_free(cluster_map);
+
+	r = graph_init(merge_graph, sc);
+
+	isl_schedule_constraints_free(sc);
+
+	return r;
+}
+
+/* Compute the maximal number of remaining schedule rows that still need
+ * to be computed for the nodes that belong to clusters with the maximal
+ * dimension for the current band (i.e., the band that is to be merged).
+ * Only clusters that are about to be merged are considered.
+ * "maxvar" is the maximal dimension for the current band.
+ * "c" contains information about the clusters.
+ *
+ * Return the maximal number of remaining schedule rows or -1 on error.
+ */
+static int compute_maxvar_max_slack(int maxvar, struct isl_clustering *c)
+{
+	int i, j;
+	int max_slack;
+
+	max_slack = 0;
+	for (i = 0; i < c->n; ++i) {
+		int nvar;
+		struct isl_sched_graph *scc;
+
+		if (!c->scc_in_merge[i])
+			continue;
+		scc = &c->scc[i];
+		nvar = scc->n_total_row - scc->band_start;
+		if (nvar != maxvar)
+			continue;
+		for (j = 0; j < scc->n; ++j) {
+			struct isl_sched_node *node = &scc->node[j];
+			int slack;
+
+			if (node_update_vmap(node) < 0)
+				return -1;
+			slack = node->nvar - node->rank;
+			if (slack > max_slack)
+				max_slack = slack;
+		}
+	}
+
+	return max_slack;
+}
+
+/* If there are any clusters where the dimension of the current band
+ * (i.e., the band that is to be merged) is smaller than "maxvar" and
+ * if there are any nodes in such a cluster where the number
+ * of remaining schedule rows that still need to be computed
+ * is greater than "max_slack", then return the smallest current band
+ * dimension of all these clusters.  Otherwise return the original value
+ * of "maxvar".  Return -1 in case of any error.
+ * Only clusters that are about to be merged are considered.
+ * "c" contains information about the clusters.
+ */
+static int limit_maxvar_to_slack(int maxvar, int max_slack,
+	struct isl_clustering *c)
+{
+	int i, j;
+
+	for (i = 0; i < c->n; ++i) {
+		int nvar;
+		struct isl_sched_graph *scc;
+
+		if (!c->scc_in_merge[i])
+			continue;
+		scc = &c->scc[i];
+		nvar = scc->n_total_row - scc->band_start;
+		if (nvar >= maxvar)
+			continue;
+		for (j = 0; j < scc->n; ++j) {
+			struct isl_sched_node *node = &scc->node[j];
+			int slack;
+
+			if (node_update_vmap(node) < 0)
+				return -1;
+			slack = node->nvar - node->rank;
+			if (slack > max_slack) {
+				maxvar = nvar;
+				break;
+			}
+		}
+	}
+
+	return maxvar;
+}
+
+/* Adjust merge_graph->maxvar based on the number of remaining schedule rows
+ * that still need to be computed.  In particular, if there is a node
+ * in a cluster where the dimension of the current band is smaller
+ * than merge_graph->maxvar, but the number of remaining schedule rows
+ * is greater than that of any node in a cluster with the maximal
+ * dimension for the current band (i.e., merge_graph->maxvar),
+ * then adjust merge_graph->maxvar to the (smallest) current band dimension
+ * of those clusters.  Without this adjustment, the total number of
+ * schedule dimensions would be increased, resulting in a skewed view
+ * of the number of coincident dimensions.
+ * "c" contains information about the clusters.
+ *
+ * If the maximize_band_depth option is set and merge_graph->maxvar is reduced,
+ * then there is no point in attempting any merge since it will be rejected
+ * anyway.  Set merge_graph->maxvar to zero in such cases.
+ */
+static isl_stat adjust_maxvar_to_slack(isl_ctx *ctx,
+	struct isl_sched_graph *merge_graph, struct isl_clustering *c)
+{
+	int max_slack, maxvar;
+
+	max_slack = compute_maxvar_max_slack(merge_graph->maxvar, c);
+	if (max_slack < 0)
+		return isl_stat_error;
+	maxvar = limit_maxvar_to_slack(merge_graph->maxvar, max_slack, c);
+	if (maxvar < 0)
+		return isl_stat_error;
+
+	if (maxvar < merge_graph->maxvar) {
+		if (isl_options_get_schedule_maximize_band_depth(ctx))
+			merge_graph->maxvar = 0;
+		else
+			merge_graph->maxvar = maxvar;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Return the number of coincident dimensions in the current band of "graph",
+ * where the nodes of "graph" are assumed to be scheduled by a single band.
+ */
+static int get_n_coincident(struct isl_sched_graph *graph)
+{
+	int i;
+
+	for (i = graph->band_start; i < graph->n_total_row; ++i)
+		if (!graph->node[0].coincident[i])
+			break;
+
+	return i - graph->band_start;
+}
+
+/* Should the clusters be merged based on the cluster schedule
+ * in the current (and only) band of "merge_graph", given that
+ * coincidence should be maximized?
+ *
+ * If the number of coincident schedule dimensions in the merged band
+ * would be less than the maximal number of coincident schedule dimensions
+ * in any of the merged clusters, then the clusters should not be merged.
+ */
+static isl_bool ok_to_merge_coincident(struct isl_clustering *c,
+	struct isl_sched_graph *merge_graph)
+{
+	int i;
+	int n_coincident;
+	int max_coincident;
+
+	max_coincident = 0;
+	for (i = 0; i < c->n; ++i) {
+		if (!c->scc_in_merge[i])
+			continue;
+		n_coincident = get_n_coincident(&c->scc[i]);
+		if (n_coincident > max_coincident)
+			max_coincident = n_coincident;
+	}
+
+	n_coincident = get_n_coincident(merge_graph);
+
+	return n_coincident >= max_coincident;
+}
+
+/* Return the transformation on "node" expressed by the current (and only)
+ * band of "merge_graph" applied to the clusters in "c".
+ *
+ * First find the representation of "node" in its SCC in "c" and
+ * extract the transformation expressed by the current band.
+ * Then extract the transformation applied by "merge_graph"
+ * to the cluster to which this SCC belongs.
+ * Combine the two to obtain the complete transformation on the node.
+ *
+ * Note that the range of the first transformation is an anonymous space,
+ * while the domain of the second is named "cluster_X".  The range
+ * of the former therefore needs to be adjusted before the two
+ * can be combined.
+ */
+static __isl_give isl_map *extract_node_transformation(isl_ctx *ctx,
+	struct isl_sched_node *node, struct isl_clustering *c,
+	struct isl_sched_graph *merge_graph)
+{
+	struct isl_sched_node *scc_node, *cluster_node;
+	int start, n;
+	isl_id *id;
+	isl_space *space;
+	isl_multi_aff *ma, *ma2;
+
+	scc_node = graph_find_node(ctx, &c->scc[node->scc], node->space);
+	start = c->scc[node->scc].band_start;
+	n = c->scc[node->scc].n_total_row - start;
+	ma = node_extract_partial_schedule_multi_aff(scc_node, start, n);
+	space = cluster_space(&c->scc[node->scc], c->scc_cluster[node->scc]);
+	cluster_node = graph_find_node(ctx, merge_graph, space);
+	if (space && !cluster_node)
+		isl_die(ctx, isl_error_internal, "unable to find cluster",
+			space = isl_space_free(space));
+	id = isl_space_get_tuple_id(space, isl_dim_set);
+	ma = isl_multi_aff_set_tuple_id(ma, isl_dim_out, id);
+	isl_space_free(space);
+	n = merge_graph->n_total_row;
+	ma2 = node_extract_partial_schedule_multi_aff(cluster_node, 0, n);
+	ma = isl_multi_aff_pullback_multi_aff(ma2, ma);
+
+	return isl_map_from_multi_aff(ma);
+}
+
+/* Give a set of distances "set", are they bounded by a small constant
+ * in direction "pos"?
+ * In practice, check if they are bounded by 2 by checking that there
+ * are no elements with a value greater than or equal to 3 or
+ * smaller than or equal to -3.
+ */
+static isl_bool distance_is_bounded(__isl_keep isl_set *set, int pos)
+{
+	isl_bool bounded;
+	isl_set *test;
+
+	if (!set)
+		return isl_bool_error;
+
+	test = isl_set_copy(set);
+	test = isl_set_lower_bound_si(test, isl_dim_set, pos, 3);
+	bounded = isl_set_is_empty(test);
+	isl_set_free(test);
+
+	if (bounded < 0 || !bounded)
+		return bounded;
+
+	test = isl_set_copy(set);
+	test = isl_set_upper_bound_si(test, isl_dim_set, pos, -3);
+	bounded = isl_set_is_empty(test);
+	isl_set_free(test);
+
+	return bounded;
+}
+
+/* Does the set "set" have a fixed (but possible parametric) value
+ * at dimension "pos"?
+ */
+static isl_bool has_single_value(__isl_keep isl_set *set, int pos)
+{
+	int n;
+	isl_bool single;
+
+	if (!set)
+		return isl_bool_error;
+	set = isl_set_copy(set);
+	n = isl_set_dim(set, isl_dim_set);
+	set = isl_set_project_out(set, isl_dim_set, pos + 1, n - (pos + 1));
+	set = isl_set_project_out(set, isl_dim_set, 0, pos);
+	single = isl_set_is_singleton(set);
+	isl_set_free(set);
+
+	return single;
+}
+
+/* Does "map" have a fixed (but possible parametric) value
+ * at dimension "pos" of either its domain or its range?
+ */
+static isl_bool has_singular_src_or_dst(__isl_keep isl_map *map, int pos)
+{
+	isl_set *set;
+	isl_bool single;
+
+	set = isl_map_domain(isl_map_copy(map));
+	single = has_single_value(set, pos);
+	isl_set_free(set);
+
+	if (single < 0 || single)
+		return single;
+
+	set = isl_map_range(isl_map_copy(map));
+	single = has_single_value(set, pos);
+	isl_set_free(set);
+
+	return single;
+}
+
+/* Does the edge "edge" from "graph" have bounded dependence distances
+ * in the merged graph "merge_graph" of a selection of clusters in "c"?
+ *
+ * Extract the complete transformations of the source and destination
+ * nodes of the edge, apply them to the edge constraints and
+ * compute the differences.  Finally, check if these differences are bounded
+ * in each direction.
+ *
+ * If the dimension of the band is greater than the number of
+ * dimensions that can be expected to be optimized by the edge
+ * (based on its weight), then also allow the differences to be unbounded
+ * in the remaining dimensions, but only if either the source or
+ * the destination has a fixed value in that direction.
+ * This allows a statement that produces values that are used by
+ * several instances of another statement to be merged with that
+ * other statement.
+ * However, merging such clusters will introduce an inherently
+ * large proximity distance inside the merged cluster, meaning
+ * that proximity distances will no longer be optimized in
+ * subsequent merges.  These merges are therefore only allowed
+ * after all other possible merges have been tried.
+ * The first time such a merge is encountered, the weight of the edge
+ * is replaced by a negative weight.  The second time (i.e., after
+ * all merges over edges with a non-negative weight have been tried),
+ * the merge is allowed.
+ */
+static isl_bool has_bounded_distances(isl_ctx *ctx, struct isl_sched_edge *edge,
+	struct isl_sched_graph *graph, struct isl_clustering *c,
+	struct isl_sched_graph *merge_graph)
+{
+	int i, n, n_slack;
+	isl_bool bounded;
+	isl_map *map, *t;
+	isl_set *dist;
+
+	map = isl_map_copy(edge->map);
+	t = extract_node_transformation(ctx, edge->src, c, merge_graph);
+	map = isl_map_apply_domain(map, t);
+	t = extract_node_transformation(ctx, edge->dst, c, merge_graph);
+	map = isl_map_apply_range(map, t);
+	dist = isl_map_deltas(isl_map_copy(map));
+
+	bounded = isl_bool_true;
+	n = isl_set_dim(dist, isl_dim_set);
+	n_slack = n - edge->weight;
+	if (edge->weight < 0)
+		n_slack -= graph->max_weight + 1;
+	for (i = 0; i < n; ++i) {
+		isl_bool bounded_i, singular_i;
+
+		bounded_i = distance_is_bounded(dist, i);
+		if (bounded_i < 0)
+			goto error;
+		if (bounded_i)
+			continue;
+		if (edge->weight >= 0)
+			bounded = isl_bool_false;
+		n_slack--;
+		if (n_slack < 0)
+			break;
+		singular_i = has_singular_src_or_dst(map, i);
+		if (singular_i < 0)
+			goto error;
+		if (singular_i)
+			continue;
+		bounded = isl_bool_false;
+		break;
+	}
+	if (!bounded && i >= n && edge->weight >= 0)
+		edge->weight -= graph->max_weight + 1;
+	isl_map_free(map);
+	isl_set_free(dist);
+
+	return bounded;
+error:
+	isl_map_free(map);
+	isl_set_free(dist);
+	return isl_bool_error;
+}
+
+/* Should the clusters be merged based on the cluster schedule
+ * in the current (and only) band of "merge_graph"?
+ * "graph" is the original dependence graph, while "c" records
+ * which SCCs are involved in the latest merge.
+ *
+ * In particular, is there at least one proximity constraint
+ * that is optimized by the merge?
+ *
+ * A proximity constraint is considered to be optimized
+ * if the dependence distances are small.
+ */
+static isl_bool ok_to_merge_proximity(isl_ctx *ctx,
+	struct isl_sched_graph *graph, struct isl_clustering *c,
+	struct isl_sched_graph *merge_graph)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge = &graph->edge[i];
+		isl_bool bounded;
+
+		if (!is_proximity(edge))
+			continue;
+		if (!c->scc_in_merge[edge->src->scc])
+			continue;
+		if (!c->scc_in_merge[edge->dst->scc])
+			continue;
+		if (c->scc_cluster[edge->dst->scc] ==
+		    c->scc_cluster[edge->src->scc])
+			continue;
+		bounded = has_bounded_distances(ctx, edge, graph, c,
+						merge_graph);
+		if (bounded < 0 || bounded)
+			return bounded;
+	}
+
+	return isl_bool_false;
+}
+
+/* Should the clusters be merged based on the cluster schedule
+ * in the current (and only) band of "merge_graph"?
+ * "graph" is the original dependence graph, while "c" records
+ * which SCCs are involved in the latest merge.
+ *
+ * If the current band is empty, then the clusters should not be merged.
+ *
+ * If the band depth should be maximized and the merge schedule
+ * is incomplete (meaning that the dimension of some of the schedule
+ * bands in the original schedule will be reduced), then the clusters
+ * should not be merged.
+ *
+ * If the schedule_maximize_coincidence option is set, then check that
+ * the number of coincident schedule dimensions is not reduced.
+ *
+ * Finally, only allow the merge if at least one proximity
+ * constraint is optimized.
+ */
+static isl_bool ok_to_merge(isl_ctx *ctx, struct isl_sched_graph *graph,
+	struct isl_clustering *c, struct isl_sched_graph *merge_graph)
+{
+	if (merge_graph->n_total_row == merge_graph->band_start)
+		return isl_bool_false;
+
+	if (isl_options_get_schedule_maximize_band_depth(ctx) &&
+	    merge_graph->n_total_row < merge_graph->maxvar)
+		return isl_bool_false;
+
+	if (isl_options_get_schedule_maximize_coincidence(ctx)) {
+		isl_bool ok;
+
+		ok = ok_to_merge_coincident(c, merge_graph);
+		if (ok < 0 || !ok)
+			return ok;
+	}
+
+	return ok_to_merge_proximity(ctx, graph, c, merge_graph);
+}
+
+/* Apply the schedule in "t_node" to the "n" rows starting at "first"
+ * of the schedule in "node" and return the result.
+ *
+ * That is, essentially compute
+ *
+ *	T * N(first:first+n-1)
+ *
+ * taking into account the constant term and the parameter coefficients
+ * in "t_node".
+ */
+static __isl_give isl_mat *node_transformation(isl_ctx *ctx,
+	struct isl_sched_node *t_node, struct isl_sched_node *node,
+	int first, int n)
+{
+	int i, j;
+	isl_mat *t;
+	int n_row, n_col, n_param, n_var;
+
+	n_param = node->nparam;
+	n_var = node->nvar;
+	n_row = isl_mat_rows(t_node->sched);
+	n_col = isl_mat_cols(node->sched);
+	t = isl_mat_alloc(ctx, n_row, n_col);
+	if (!t)
+		return NULL;
+	for (i = 0; i < n_row; ++i) {
+		isl_seq_cpy(t->row[i], t_node->sched->row[i], 1 + n_param);
+		isl_seq_clr(t->row[i] + 1 + n_param, n_var);
+		for (j = 0; j < n; ++j)
+			isl_seq_addmul(t->row[i],
+					t_node->sched->row[i][1 + n_param + j],
+					node->sched->row[first + j],
+					1 + n_param + n_var);
+	}
+	return t;
+}
+
+/* Apply the cluster schedule in "t_node" to the current band
+ * schedule of the nodes in "graph".
+ *
+ * In particular, replace the rows starting at band_start
+ * by the result of applying the cluster schedule in "t_node"
+ * to the original rows.
+ *
+ * The coincidence of the schedule is determined by the coincidence
+ * of the cluster schedule.
+ */
+static isl_stat transform(isl_ctx *ctx, struct isl_sched_graph *graph,
+	struct isl_sched_node *t_node)
+{
+	int i, j;
+	int n_new;
+	int start, n;
+
+	start = graph->band_start;
+	n = graph->n_total_row - start;
+
+	n_new = isl_mat_rows(t_node->sched);
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		isl_mat *t;
+
+		t = node_transformation(ctx, t_node, node, start, n);
+		node->sched = isl_mat_drop_rows(node->sched, start, n);
+		node->sched = isl_mat_concat(node->sched, t);
+		node->sched_map = isl_map_free(node->sched_map);
+		if (!node->sched)
+			return isl_stat_error;
+		for (j = 0; j < n_new; ++j)
+			node->coincident[start + j] = t_node->coincident[j];
+	}
+	graph->n_total_row -= n;
+	graph->n_row -= n;
+	graph->n_total_row += n_new;
+	graph->n_row += n_new;
+
+	return isl_stat_ok;
+}
+
+/* Merge the clusters marked for merging in "c" into a single
+ * cluster using the cluster schedule in the current band of "merge_graph".
+ * The representative SCC for the new cluster is the SCC with
+ * the smallest index.
+ *
+ * The current band schedule of each SCC in the new cluster is obtained
+ * by applying the schedule of the corresponding original cluster
+ * to the original band schedule.
+ * All SCCs in the new cluster have the same number of schedule rows.
+ */
+static isl_stat merge(isl_ctx *ctx, struct isl_clustering *c,
+	struct isl_sched_graph *merge_graph)
+{
+	int i;
+	int cluster = -1;
+	isl_space *space;
+
+	for (i = 0; i < c->n; ++i) {
+		struct isl_sched_node *node;
+
+		if (!c->scc_in_merge[i])
+			continue;
+		if (cluster < 0)
+			cluster = i;
+		space = cluster_space(&c->scc[i], c->scc_cluster[i]);
+		if (!space)
+			return isl_stat_error;
+		node = graph_find_node(ctx, merge_graph, space);
+		isl_space_free(space);
+		if (!node)
+			isl_die(ctx, isl_error_internal,
+				"unable to find cluster",
+				return isl_stat_error);
+		if (transform(ctx, &c->scc[i], node) < 0)
+			return isl_stat_error;
+		c->scc_cluster[i] = cluster;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Try and merge the clusters of SCCs marked in c->scc_in_merge
+ * by scheduling the current cluster bands with respect to each other.
+ *
+ * Construct a dependence graph with a space for each cluster and
+ * with the coordinates of each space corresponding to the schedule
+ * dimensions of the current band of that cluster.
+ * Construct a cluster schedule in this cluster dependence graph and
+ * apply it to the current cluster bands if it is applicable
+ * according to ok_to_merge.
+ *
+ * If the number of remaining schedule dimensions in a cluster
+ * with a non-maximal current schedule dimension is greater than
+ * the number of remaining schedule dimensions in clusters
+ * with a maximal current schedule dimension, then restrict
+ * the number of rows to be computed in the cluster schedule
+ * to the minimal such non-maximal current schedule dimension.
+ * Do this by adjusting merge_graph.maxvar.
+ *
+ * Return isl_bool_true if the clusters have effectively been merged
+ * into a single cluster.
+ *
+ * Note that since the standard scheduling algorithm minimizes the maximal
+ * distance over proximity constraints, the proximity constraints between
+ * the merged clusters may not be optimized any further than what is
+ * sufficient to bring the distances within the limits of the internal
+ * proximity constraints inside the individual clusters.
+ * It may therefore make sense to perform an additional translation step
+ * to bring the clusters closer to each other, while maintaining
+ * the linear part of the merging schedule found using the standard
+ * scheduling algorithm.
+ */
+static isl_bool try_merge(isl_ctx *ctx, struct isl_sched_graph *graph,
+	struct isl_clustering *c)
+{
+	struct isl_sched_graph merge_graph = { 0 };
+	isl_bool merged;
+
+	if (init_merge_graph(ctx, graph, c, &merge_graph) < 0)
+		goto error;
+
+	if (compute_maxvar(&merge_graph) < 0)
+		goto error;
+	if (adjust_maxvar_to_slack(ctx, &merge_graph,c) < 0)
+		goto error;
+	if (compute_schedule_wcc_band(ctx, &merge_graph) < 0)
+		goto error;
+	merged = ok_to_merge(ctx, graph, c, &merge_graph);
+	if (merged && merge(ctx, c, &merge_graph) < 0)
+		goto error;
+
+	graph_free(ctx, &merge_graph);
+	return merged;
+error:
+	graph_free(ctx, &merge_graph);
+	return isl_bool_error;
+}
+
+/* Is there any edge marked "no_merge" between two SCCs that are
+ * about to be merged (i.e., that are set in "scc_in_merge")?
+ * "merge_edge" is the proximity edge along which the clusters of SCCs
+ * are going to be merged.
+ *
+ * If there is any edge between two SCCs with a negative weight,
+ * while the weight of "merge_edge" is non-negative, then this
+ * means that the edge was postponed.  "merge_edge" should then
+ * also be postponed since merging along the edge with negative weight should
+ * be postponed until all edges with non-negative weight have been tried.
+ * Replace the weight of "merge_edge" by a negative weight as well and
+ * tell the caller not to attempt a merge.
+ */
+static int any_no_merge(struct isl_sched_graph *graph, int *scc_in_merge,
+	struct isl_sched_edge *merge_edge)
+{
+	int i;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge = &graph->edge[i];
+
+		if (!scc_in_merge[edge->src->scc])
+			continue;
+		if (!scc_in_merge[edge->dst->scc])
+			continue;
+		if (edge->no_merge)
+			return 1;
+		if (merge_edge->weight >= 0 && edge->weight < 0) {
+			merge_edge->weight -= graph->max_weight + 1;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/* Merge the two clusters in "c" connected by the edge in "graph"
+ * with index "edge" into a single cluster.
+ * If it turns out to be impossible to merge these two clusters,
+ * then mark the edge as "no_merge" such that it will not be
+ * considered again.
+ *
+ * First mark all SCCs that need to be merged.  This includes the SCCs
+ * in the two clusters, but it may also include the SCCs
+ * of intermediate clusters.
+ * If there is already a no_merge edge between any pair of such SCCs,
+ * then simply mark the current edge as no_merge as well.
+ * Likewise, if any of those edges was postponed by has_bounded_distances,
+ * then postpone the current edge as well.
+ * Otherwise, try and merge the clusters and mark "edge" as "no_merge"
+ * if the clusters did not end up getting merged, unless the non-merge
+ * is due to the fact that the edge was postponed.  This postponement
+ * can be recognized by a change in weight (from non-negative to negative).
+ */
+static isl_stat merge_clusters_along_edge(isl_ctx *ctx,
+	struct isl_sched_graph *graph, int edge, struct isl_clustering *c)
+{
+	isl_bool merged;
+	int edge_weight = graph->edge[edge].weight;
+
+	if (mark_merge_sccs(ctx, graph, edge, c) < 0)
+		return isl_stat_error;
+
+	if (any_no_merge(graph, c->scc_in_merge, &graph->edge[edge]))
+		merged = isl_bool_false;
+	else
+		merged = try_merge(ctx, graph, c);
+	if (merged < 0)
+		return isl_stat_error;
+	if (!merged && edge_weight == graph->edge[edge].weight)
+		graph->edge[edge].no_merge = 1;
+
+	return isl_stat_ok;
+}
+
+/* Does "node" belong to the cluster identified by "cluster"?
+ */
+static int node_cluster_exactly(struct isl_sched_node *node, int cluster)
+{
+	return node->cluster == cluster;
+}
+
+/* Does "edge" connect two nodes belonging to the cluster
+ * identified by "cluster"?
+ */
+static int edge_cluster_exactly(struct isl_sched_edge *edge, int cluster)
+{
+	return edge->src->cluster == cluster && edge->dst->cluster == cluster;
+}
+
+/* Swap the schedule of "node1" and "node2".
+ * Both nodes have been derived from the same node in a common parent graph.
+ * Since the "coincident" field is shared with that node
+ * in the parent graph, there is no need to also swap this field.
+ */
+static void swap_sched(struct isl_sched_node *node1,
+	struct isl_sched_node *node2)
+{
+	isl_mat *sched;
+	isl_map *sched_map;
+
+	sched = node1->sched;
+	node1->sched = node2->sched;
+	node2->sched = sched;
+
+	sched_map = node1->sched_map;
+	node1->sched_map = node2->sched_map;
+	node2->sched_map = sched_map;
+}
+
+/* Copy the current band schedule from the SCCs that form the cluster
+ * with index "pos" to the actual cluster at position "pos".
+ * By construction, the index of the first SCC that belongs to the cluster
+ * is also "pos".
+ *
+ * The order of the nodes inside both the SCCs and the cluster
+ * is assumed to be same as the order in the original "graph".
+ *
+ * Since the SCC graphs will no longer be used after this function,
+ * the schedules are actually swapped rather than copied.
+ */
+static isl_stat copy_partial(struct isl_sched_graph *graph,
+	struct isl_clustering *c, int pos)
+{
+	int i, j;
+
+	c->cluster[pos].n_total_row = c->scc[pos].n_total_row;
+	c->cluster[pos].n_row = c->scc[pos].n_row;
+	c->cluster[pos].maxvar = c->scc[pos].maxvar;
+	j = 0;
+	for (i = 0; i < graph->n; ++i) {
+		int k;
+		int s;
+
+		if (graph->node[i].cluster != pos)
+			continue;
+		s = graph->node[i].scc;
+		k = c->scc_node[s]++;
+		swap_sched(&c->cluster[pos].node[j], &c->scc[s].node[k]);
+		if (c->scc[s].maxvar > c->cluster[pos].maxvar)
+			c->cluster[pos].maxvar = c->scc[s].maxvar;
+		++j;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Is there a (conditional) validity dependence from node[j] to node[i],
+ * forcing node[i] to follow node[j] or do the nodes belong to the same
+ * cluster?
+ */
+static isl_bool node_follows_strong_or_same_cluster(int i, int j, void *user)
+{
+	struct isl_sched_graph *graph = user;
+
+	if (graph->node[i].cluster == graph->node[j].cluster)
+		return isl_bool_true;
+	return graph_has_validity_edge(graph, &graph->node[j], &graph->node[i]);
+}
+
+/* Extract the merged clusters of SCCs in "graph", sort them, and
+ * store them in c->clusters.  Update c->scc_cluster accordingly.
+ *
+ * First keep track of the cluster containing the SCC to which a node
+ * belongs in the node itself.
+ * Then extract the clusters into c->clusters, copying the current
+ * band schedule from the SCCs that belong to the cluster.
+ * Do this only once per cluster.
+ *
+ * Finally, topologically sort the clusters and update c->scc_cluster
+ * to match the new scc numbering.  While the SCCs were originally
+ * sorted already, some SCCs that depend on some other SCCs may
+ * have been merged with SCCs that appear before these other SCCs.
+ * A reordering may therefore be required.
+ */
+static isl_stat extract_clusters(isl_ctx *ctx, struct isl_sched_graph *graph,
+	struct isl_clustering *c)
+{
+	int i;
+
+	for (i = 0; i < graph->n; ++i)
+		graph->node[i].cluster = c->scc_cluster[graph->node[i].scc];
+
+	for (i = 0; i < graph->scc; ++i) {
+		if (c->scc_cluster[i] != i)
+			continue;
+		if (extract_sub_graph(ctx, graph, &node_cluster_exactly,
+				&edge_cluster_exactly, i, &c->cluster[i]) < 0)
+			return isl_stat_error;
+		c->cluster[i].src_scc = -1;
+		c->cluster[i].dst_scc = -1;
+		if (copy_partial(graph, c, i) < 0)
+			return isl_stat_error;
+	}
+
+	if (detect_ccs(ctx, graph, &node_follows_strong_or_same_cluster) < 0)
+		return isl_stat_error;
+	for (i = 0; i < graph->n; ++i)
+		c->scc_cluster[graph->node[i].scc] = graph->node[i].cluster;
+
+	return isl_stat_ok;
+}
+
+/* Compute weights on the proximity edges of "graph" that can
+ * be used by find_proximity to find the most appropriate
+ * proximity edge to use to merge two clusters in "c".
+ * The weights are also used by has_bounded_distances to determine
+ * whether the merge should be allowed.
+ * Store the maximum of the computed weights in graph->max_weight.
+ *
+ * The computed weight is a measure for the number of remaining schedule
+ * dimensions that can still be completely aligned.
+ * In particular, compute the number of equalities between
+ * input dimensions and output dimensions in the proximity constraints.
+ * The directions that are already handled by outer schedule bands
+ * are projected out prior to determining this number.
+ *
+ * Edges that will never be considered by find_proximity are ignored.
+ */
+static isl_stat compute_weights(struct isl_sched_graph *graph,
+	struct isl_clustering *c)
+{
+	int i;
+
+	graph->max_weight = 0;
+
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge = &graph->edge[i];
+		struct isl_sched_node *src = edge->src;
+		struct isl_sched_node *dst = edge->dst;
+		isl_basic_map *hull;
+		isl_bool prox;
+		int n_in, n_out;
+
+		prox = is_non_empty_proximity(edge);
+		if (prox < 0)
+			return isl_stat_error;
+		if (!prox)
+			continue;
+		if (bad_cluster(&c->scc[edge->src->scc]) ||
+		    bad_cluster(&c->scc[edge->dst->scc]))
+			continue;
+		if (c->scc_cluster[edge->dst->scc] ==
+		    c->scc_cluster[edge->src->scc])
+			continue;
+
+		hull = isl_map_affine_hull(isl_map_copy(edge->map));
+		hull = isl_basic_map_transform_dims(hull, isl_dim_in, 0,
+						    isl_mat_copy(src->vmap));
+		hull = isl_basic_map_transform_dims(hull, isl_dim_out, 0,
+						    isl_mat_copy(dst->vmap));
+		hull = isl_basic_map_project_out(hull,
+						isl_dim_in, 0, src->rank);
+		hull = isl_basic_map_project_out(hull,
+						isl_dim_out, 0, dst->rank);
+		hull = isl_basic_map_remove_divs(hull);
+		n_in = isl_basic_map_dim(hull, isl_dim_in);
+		n_out = isl_basic_map_dim(hull, isl_dim_out);
+		hull = isl_basic_map_drop_constraints_not_involving_dims(hull,
+							isl_dim_in, 0, n_in);
+		hull = isl_basic_map_drop_constraints_not_involving_dims(hull,
+							isl_dim_out, 0, n_out);
+		if (!hull)
+			return isl_stat_error;
+		edge->weight = isl_basic_map_n_equality(hull);
+		isl_basic_map_free(hull);
+
+		if (edge->weight > graph->max_weight)
+			graph->max_weight = edge->weight;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Call compute_schedule_finish_band on each of the clusters in "c"
+ * in their topological order.  This order is determined by the scc
+ * fields of the nodes in "graph".
+ * Combine the results in a sequence expressing the topological order.
+ *
+ * If there is only one cluster left, then there is no need to introduce
+ * a sequence node.  Also, in this case, the cluster necessarily contains
+ * the SCC at position 0 in the original graph and is therefore also
+ * stored in the first cluster of "c".
+ */
+static __isl_give isl_schedule_node *finish_bands_clustering(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph,
+	struct isl_clustering *c)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_union_set_list *filters;
+
+	if (graph->scc == 1)
+		return compute_schedule_finish_band(node, &c->cluster[0], 0);
+
+	ctx = isl_schedule_node_get_ctx(node);
+
+	filters = extract_sccs(ctx, graph);
+	node = isl_schedule_node_insert_sequence(node, filters);
+
+	for (i = 0; i < graph->scc; ++i) {
+		int j = c->scc_cluster[i];
+		node = isl_schedule_node_child(node, i);
+		node = isl_schedule_node_child(node, 0);
+		node = compute_schedule_finish_band(node, &c->cluster[j], 0);
+		node = isl_schedule_node_parent(node);
+		node = isl_schedule_node_parent(node);
+	}
+
+	return node;
+}
+
+/* Compute a schedule for a connected dependence graph by first considering
+ * each strongly connected component (SCC) in the graph separately and then
+ * incrementally combining them into clusters.
+ * Return the updated schedule node.
+ *
+ * Initially, each cluster consists of a single SCC, each with its
+ * own band schedule.  The algorithm then tries to merge pairs
+ * of clusters along a proximity edge until no more suitable
+ * proximity edges can be found.  During this merging, the schedule
+ * is maintained in the individual SCCs.
+ * After the merging is completed, the full resulting clusters
+ * are extracted and in finish_bands_clustering,
+ * compute_schedule_finish_band is called on each of them to integrate
+ * the band into "node" and to continue the computation.
+ *
+ * compute_weights initializes the weights that are used by find_proximity.
+ */
+static __isl_give isl_schedule_node *compute_schedule_wcc_clustering(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph)
+{
+	isl_ctx *ctx;
+	struct isl_clustering c;
+	int i;
+
+	ctx = isl_schedule_node_get_ctx(node);
+
+	if (clustering_init(ctx, &c, graph) < 0)
+		goto error;
+
+	if (compute_weights(graph, &c) < 0)
+		goto error;
+
+	for (;;) {
+		i = find_proximity(graph, &c);
+		if (i < 0)
+			goto error;
+		if (i >= graph->n_edge)
+			break;
+		if (merge_clusters_along_edge(ctx, graph, i, &c) < 0)
+			goto error;
+	}
+
+	if (extract_clusters(ctx, graph, &c) < 0)
+		goto error;
+
+	node = finish_bands_clustering(node, graph, &c);
+
+	clustering_free(ctx, &c);
+	return node;
+error:
+	clustering_free(ctx, &c);
+	return isl_schedule_node_free(node);
+}
+
+/* Compute a schedule for a connected dependence graph and return
+ * the updated schedule node.
+ *
+ * If Feautrier's algorithm is selected, we first recursively try to satisfy
+ * as many validity dependences as possible. When all validity dependences
+ * are satisfied we extend the schedule to a full-dimensional schedule.
+ *
+ * Call compute_schedule_wcc_whole or compute_schedule_wcc_clustering
+ * depending on whether the user has selected the option to try and
+ * compute a schedule for the entire (weakly connected) component first.
+ * If there is only a single strongly connected component (SCC), then
+ * there is no point in trying to combine SCCs
+ * in compute_schedule_wcc_clustering, so compute_schedule_wcc_whole
+ * is called instead.
+ */
+static __isl_give isl_schedule_node *compute_schedule_wcc(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph)
+{
+	isl_ctx *ctx;
+
+	if (!node)
+		return NULL;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	if (detect_sccs(ctx, graph) < 0)
+		return isl_schedule_node_free(node);
+
+	if (compute_maxvar(graph) < 0)
+		return isl_schedule_node_free(node);
+
+	if (need_feautrier_step(ctx, graph))
+		return compute_schedule_wcc_feautrier(node, graph);
+
+	if (graph->scc <= 1 || isl_options_get_schedule_whole_component(ctx))
+		return compute_schedule_wcc_whole(node, graph);
+	else
+		return compute_schedule_wcc_clustering(node, graph);
+}
+
+/* Compute a schedule for each group of nodes identified by node->scc
+ * separately and then combine them in a sequence node (or as set node
+ * if graph->weak is set) inserted at position "node" of the schedule tree.
+ * Return the updated schedule node.
+ *
+ * If "wcc" is set then each of the groups belongs to a single
+ * weakly connected component in the dependence graph so that
+ * there is no need for compute_sub_schedule to look for weakly
+ * connected components.
+ */
+static __isl_give isl_schedule_node *compute_component_schedule(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph,
+	int wcc)
+{
+	int component;
+	isl_ctx *ctx;
+	isl_union_set_list *filters;
+
+	if (!node)
+		return NULL;
+	ctx = isl_schedule_node_get_ctx(node);
+
+	filters = extract_sccs(ctx, graph);
+	if (graph->weak)
+		node = isl_schedule_node_insert_set(node, filters);
+	else
+		node = isl_schedule_node_insert_sequence(node, filters);
+
+	for (component = 0; component < graph->scc; ++component) {
+		node = isl_schedule_node_child(node, component);
+		node = isl_schedule_node_child(node, 0);
+		node = compute_sub_schedule(node, ctx, graph,
+				    &node_scc_exactly,
+				    &edge_scc_exactly, component, wcc);
+		node = isl_schedule_node_parent(node);
+		node = isl_schedule_node_parent(node);
+	}
+
+	return node;
+}
+
+/* Compute a schedule for the given dependence graph and insert it at "node".
+ * Return the updated schedule node.
+ *
+ * We first check if the graph is connected (through validity and conditional
+ * validity dependences) and, if not, compute a schedule
+ * for each component separately.
+ * If the schedule_serialize_sccs option is set, then we check for strongly
+ * connected components instead and compute a separate schedule for
+ * each such strongly connected component.
+ */
+static __isl_give isl_schedule_node *compute_schedule(isl_schedule_node *node,
+	struct isl_sched_graph *graph)
+{
+	isl_ctx *ctx;
+
+	if (!node)
+		return NULL;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	if (isl_options_get_schedule_serialize_sccs(ctx)) {
+		if (detect_sccs(ctx, graph) < 0)
+			return isl_schedule_node_free(node);
+	} else {
+		if (detect_wccs(ctx, graph) < 0)
+			return isl_schedule_node_free(node);
+	}
+
+	if (graph->scc > 1)
+		return compute_component_schedule(node, graph, 1);
+
+	return compute_schedule_wcc(node, graph);
+}
+
+/* Compute a schedule on sc->domain that respects the given schedule
+ * constraints.
+ *
+ * In particular, the schedule respects all the validity dependences.
+ * If the default isl scheduling algorithm is used, it tries to minimize
+ * the dependence distances over the proximity dependences.
+ * If Feautrier's scheduling algorithm is used, the proximity dependence
+ * distances are only minimized during the extension to a full-dimensional
+ * schedule.
+ *
+ * If there are any condition and conditional validity dependences,
+ * then the conditional validity dependences may be violated inside
+ * a tilable band, provided they have no adjacent non-local
+ * condition dependences.
+ */
+__isl_give isl_schedule *isl_schedule_constraints_compute_schedule(
+	__isl_take isl_schedule_constraints *sc)
+{
+	isl_ctx *ctx = isl_schedule_constraints_get_ctx(sc);
+	struct isl_sched_graph graph = { 0 };
+	isl_schedule *sched;
+	isl_schedule_node *node;
+	isl_union_set *domain;
+
+	sc = isl_schedule_constraints_align_params(sc);
+
+	domain = isl_schedule_constraints_get_domain(sc);
+	if (isl_union_set_n_set(domain) == 0) {
+		isl_schedule_constraints_free(sc);
+		return isl_schedule_from_domain(domain);
+	}
+
+	if (graph_init(&graph, sc) < 0)
+		domain = isl_union_set_free(domain);
+
+	node = isl_schedule_node_from_domain(domain);
+	node = isl_schedule_node_child(node, 0);
+	if (graph.n > 0)
+		node = compute_schedule(node, &graph);
+	sched = isl_schedule_node_get_schedule(node);
+	isl_schedule_node_free(node);
+
+	graph_free(ctx, &graph);
+	isl_schedule_constraints_free(sc);
+
+	return sched;
+}
+
+/* Compute a schedule for the given union of domains that respects
+ * all the validity dependences and minimizes
+ * the dependence distances over the proximity dependences.
+ *
+ * This function is kept for backward compatibility.
+ */
+__isl_give isl_schedule *isl_union_set_compute_schedule(
+	__isl_take isl_union_set *domain,
+	__isl_take isl_union_map *validity,
+	__isl_take isl_union_map *proximity)
+{
+	isl_schedule_constraints *sc;
+
+	sc = isl_schedule_constraints_on_domain(domain);
+	sc = isl_schedule_constraints_set_validity(sc, validity);
+	sc = isl_schedule_constraints_set_proximity(sc, proximity);
+
+	return isl_schedule_constraints_compute_schedule(sc);
+}
diff --git a/final/lib/External/isl/isl_seq.c b/final/lib/External/isl/isl_seq.c
new file mode 100644
index 0000000..8e6c84c
--- /dev/null
+++ b/final/lib/External/isl/isl_seq.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2011      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_seq.h>
+
+void isl_seq_clr(isl_int *p, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_set_si(p[i], 0);
+}
+
+void isl_seq_set_si(isl_int *p, int v, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_set_si(p[i], v);
+}
+
+void isl_seq_set(isl_int *p, isl_int v, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_set(p[i], v);
+}
+
+void isl_seq_neg(isl_int *dst, isl_int *src, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_neg(dst[i], src[i]);
+}
+
+void isl_seq_cpy(isl_int *dst, isl_int *src, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_set(dst[i], src[i]);
+}
+
+void isl_seq_submul(isl_int *dst, isl_int f, isl_int *src, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_submul(dst[i], f, src[i]);
+}
+
+void isl_seq_addmul(isl_int *dst, isl_int f, isl_int *src, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_addmul(dst[i], f, src[i]);
+}
+
+void isl_seq_swp_or_cpy(isl_int *dst, isl_int *src, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_swap_or_set(dst[i], src[i]);
+}
+
+void isl_seq_scale(isl_int *dst, isl_int *src, isl_int m, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_mul(dst[i], src[i], m);
+}
+
+void isl_seq_scale_down(isl_int *dst, isl_int *src, isl_int m, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_divexact(dst[i], src[i], m);
+}
+
+void isl_seq_cdiv_q(isl_int *dst, isl_int *src, isl_int m, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_cdiv_q(dst[i], src[i], m);
+}
+
+void isl_seq_fdiv_q(isl_int *dst, isl_int *src, isl_int m, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_fdiv_q(dst[i], src[i], m);
+}
+
+void isl_seq_fdiv_r(isl_int *dst, isl_int *src, isl_int m, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		isl_int_fdiv_r(dst[i], src[i], m);
+}
+
+void isl_seq_combine(isl_int *dst, isl_int m1, isl_int *src1,
+			isl_int m2, isl_int *src2, unsigned len)
+{
+	int i;
+	isl_int tmp;
+
+	if (dst == src1 && isl_int_is_one(m1)) {
+		if (isl_int_is_zero(m2))
+			return;
+		for (i = 0; i < len; ++i)
+			isl_int_addmul(src1[i], m2, src2[i]);
+		return;
+	}
+
+	isl_int_init(tmp);
+	for (i = 0; i < len; ++i) {
+		isl_int_mul(tmp, m1, src1[i]);
+		isl_int_addmul(tmp, m2, src2[i]);
+		isl_int_set(dst[i], tmp);
+	}
+	isl_int_clear(tmp);
+}
+
+/*
+ * Let d = dst[pos] and s = src[pos]
+ * dst is replaced by |s| dst - sgn(s)d src
+ */
+void isl_seq_elim(isl_int *dst, isl_int *src, unsigned pos, unsigned len,
+		  isl_int *m)
+{
+	isl_int a;
+	isl_int b;
+
+	if (isl_int_is_zero(dst[pos]))
+		return;
+
+	isl_int_init(a);
+	isl_int_init(b);
+
+	isl_int_gcd(a, src[pos], dst[pos]);
+	isl_int_divexact(b, dst[pos], a);
+	if (isl_int_is_pos(src[pos]))
+		isl_int_neg(b, b);
+	isl_int_divexact(a, src[pos], a);
+	isl_int_abs(a, a);
+	isl_seq_combine(dst, a, dst, b, src, len);
+
+	if (m)
+		isl_int_mul(*m, *m, a);
+
+	isl_int_clear(a);
+	isl_int_clear(b);
+}
+
+int isl_seq_eq(isl_int *p1, isl_int *p2, unsigned len)
+{
+	int i;
+	for (i = 0; i < len; ++i)
+		if (isl_int_ne(p1[i], p2[i]))
+			return 0;
+	return 1;
+}
+
+int isl_seq_cmp(isl_int *p1, isl_int *p2, unsigned len)
+{
+	int i;
+	int cmp;
+	for (i = 0; i < len; ++i)
+		if ((cmp = isl_int_cmp(p1[i], p2[i])) != 0)
+			return cmp;
+	return 0;
+}
+
+int isl_seq_is_neg(isl_int *p1, isl_int *p2, unsigned len)
+{
+	int i;
+
+	for (i = 0; i < len; ++i) {
+		if (isl_int_abs_ne(p1[i], p2[i]))
+			return 0;
+		if (isl_int_is_zero(p1[i]))
+			continue;
+		if (isl_int_eq(p1[i], p2[i]))
+			return 0;
+	}
+	return 1;
+}
+
+int isl_seq_first_non_zero(isl_int *p, unsigned len)
+{
+	int i;
+
+	for (i = 0; i < len; ++i)
+		if (!isl_int_is_zero(p[i]))
+			return i;
+	return -1;
+}
+
+int isl_seq_last_non_zero(isl_int *p, unsigned len)
+{
+	int i;
+
+	for (i = len - 1; i >= 0; --i)
+		if (!isl_int_is_zero(p[i]))
+			return i;
+	return -1;
+}
+
+void isl_seq_abs_max(isl_int *p, unsigned len, isl_int *max)
+{
+	int i;
+
+	isl_int_set_si(*max, 0);
+
+	for (i = 0; i < len; ++i)
+		if (isl_int_abs_gt(p[i], *max))
+			isl_int_abs(*max, p[i]);
+}
+
+int isl_seq_abs_min_non_zero(isl_int *p, unsigned len)
+{
+	int i, min = isl_seq_first_non_zero(p, len);
+	if (min < 0)
+		return -1;
+	for (i = min + 1; i < len; ++i) {
+		if (isl_int_is_zero(p[i]))
+			continue;
+		if (isl_int_abs_lt(p[i], p[min]))
+			min = i;
+	}
+	return min;
+}
+
+void isl_seq_gcd(isl_int *p, unsigned len, isl_int *gcd)
+{
+	int i, min = isl_seq_abs_min_non_zero(p, len);
+
+	if (min < 0) {
+		isl_int_set_si(*gcd, 0);
+		return;
+	}
+	isl_int_abs(*gcd, p[min]);
+	for (i = 0; isl_int_cmp_si(*gcd, 1) > 0 && i < len; ++i) {
+		if (i == min)
+			continue;
+		if (isl_int_is_zero(p[i]))
+			continue;
+		isl_int_gcd(*gcd, *gcd, p[i]);
+	}
+}
+
+void isl_seq_normalize(struct isl_ctx *ctx, isl_int *p, unsigned len)
+{
+	if (len == 0)
+		return;
+	isl_seq_gcd(p, len, &ctx->normalize_gcd);
+	if (!isl_int_is_zero(ctx->normalize_gcd) &&
+	    !isl_int_is_one(ctx->normalize_gcd))
+		isl_seq_scale_down(p, p, ctx->normalize_gcd, len);
+}
+
+void isl_seq_lcm(isl_int *p, unsigned len, isl_int *lcm)
+{
+	int i;
+
+	if (len == 0) {
+		isl_int_set_si(*lcm, 1);
+		return;
+	}
+	isl_int_set(*lcm, p[0]);
+	for (i = 1; i < len; ++i)
+		isl_int_lcm(*lcm, *lcm, p[i]);
+}
+
+void isl_seq_inner_product(isl_int *p1, isl_int *p2, unsigned len,
+			   isl_int *prod)
+{
+	int i;
+	if (len == 0) {
+		isl_int_set_si(*prod, 0);
+		return;
+	}
+	isl_int_mul(*prod, p1[0], p2[0]);
+	for (i = 1; i < len; ++i)
+		isl_int_addmul(*prod, p1[i], p2[i]);
+}
+
+uint32_t isl_seq_hash(isl_int *p, unsigned len, uint32_t hash)
+{
+	int i;
+	for (i = 0; i < len; ++i) {
+		if (isl_int_is_zero(p[i]))
+			continue;
+		hash *= 16777619;
+		hash ^= (i & 0xFF);
+		hash = isl_int_hash(p[i], hash);
+	}
+	return hash;
+}
+
+/* Given two affine expressions "p" of length p_len (including the
+ * denominator and the constant term) and "subs" of length subs_len,
+ * plug in "subs" for the variable at position "pos".
+ * The variables of "subs" and "p" are assumed to match up to subs_len,
+ * but "p" may have additional variables.
+ * "v" is an initialized isl_int that can be used internally.
+ *
+ * In particular, if "p" represents the expression
+ *
+ *	(a i + g)/m
+ *
+ * with i the variable at position "pos" and "subs" represents the expression
+ *
+ *	f/d
+ *
+ * then the result represents the expression
+ *
+ *	(a f + d g)/(m d)
+ *
+ */
+void isl_seq_substitute(isl_int *p, int pos, isl_int *subs,
+	int p_len, int subs_len, isl_int v)
+{
+	isl_int_set(v, p[1 + pos]);
+	isl_int_set_si(p[1 + pos], 0);
+	isl_seq_combine(p + 1, subs[0], p + 1, v, subs + 1, subs_len - 1);
+	isl_seq_scale(p + subs_len, p + subs_len, subs[0], p_len - subs_len);
+	isl_int_mul(p[0], p[0], subs[0]);
+}
+
+uint32_t isl_seq_get_hash(isl_int *p, unsigned len)
+{
+	uint32_t hash = isl_hash_init();
+
+	return isl_seq_hash(p, len, hash);
+}
+
+uint32_t isl_seq_get_hash_bits(isl_int *p, unsigned len, unsigned bits)
+{
+	uint32_t hash;
+
+	hash = isl_seq_get_hash(p, len);
+	return isl_hash_bits(hash, bits);
+}
+
+void isl_seq_dump(isl_int *p, unsigned len)
+{
+	int i;
+
+	for (i = 0; i < len; ++i) {
+		if (i)
+			fprintf(stderr, " ");
+		isl_int_print(stderr, p[i], 0);
+	}
+	fprintf(stderr, "\n");
+}
diff --git a/final/lib/External/isl/isl_seq.h b/final/lib/External/isl/isl_seq.h
new file mode 100644
index 0000000..de0d2e6
--- /dev/null
+++ b/final/lib/External/isl/isl_seq.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_SEQ_H
+#define ISL_SEQ_H
+
+#include <sys/types.h>
+#include <isl_int.h>
+#include <isl/ctx.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Some common operations on sequences of isl_int's */
+
+void isl_seq_clr(isl_int *p, unsigned len);
+void isl_seq_set(isl_int *p, isl_int v, unsigned len);
+void isl_seq_set_si(isl_int *p, int v, unsigned len);
+void isl_seq_neg(isl_int *dst, isl_int *src, unsigned len);
+void isl_seq_cpy(isl_int *dst, isl_int *src, unsigned len);
+void isl_seq_addmul(isl_int *dst, isl_int f, isl_int *src, unsigned len);
+void isl_seq_submul(isl_int *dst, isl_int f, isl_int *src, unsigned len);
+void isl_seq_swp_or_cpy(isl_int *dst, isl_int *src, unsigned len);
+void isl_seq_scale(isl_int *dst, isl_int *src, isl_int f, unsigned len);
+void isl_seq_scale_down(isl_int *dst, isl_int *src, isl_int f, unsigned len);
+void isl_seq_cdiv_q(isl_int *dst, isl_int *src, isl_int m, unsigned len);
+void isl_seq_fdiv_q(isl_int *dst, isl_int *src, isl_int m, unsigned len);
+void isl_seq_fdiv_r(isl_int *dst, isl_int *src, isl_int m, unsigned len);
+void isl_seq_combine(isl_int *dst, isl_int m1, isl_int *src1,
+			isl_int m2, isl_int *src2, unsigned len);
+void isl_seq_elim(isl_int *dst, isl_int *src, unsigned pos, unsigned len,
+		  isl_int *m);
+void isl_seq_abs_max(isl_int *p, unsigned len, isl_int *max);
+void isl_seq_gcd(isl_int *p, unsigned len, isl_int *gcd);
+void isl_seq_lcm(isl_int *p, unsigned len, isl_int *lcm);
+void isl_seq_normalize(struct isl_ctx *ctx, isl_int *p, unsigned len);
+void isl_seq_inner_product(isl_int *p1, isl_int *p2, unsigned len,
+			   isl_int *prod);
+int isl_seq_first_non_zero(isl_int *p, unsigned len);
+int isl_seq_last_non_zero(isl_int *p, unsigned len);
+int isl_seq_abs_min_non_zero(isl_int *p, unsigned len);
+int isl_seq_eq(isl_int *p1, isl_int *p2, unsigned len);
+int isl_seq_cmp(isl_int *p1, isl_int *p2, unsigned len);
+int isl_seq_is_neg(isl_int *p1, isl_int *p2, unsigned len);
+
+void isl_seq_substitute(isl_int *p, int pos, isl_int *subs,
+	int p_len, int subs_len, isl_int v);
+
+uint32_t isl_seq_get_hash(isl_int *p, unsigned len);
+uint32_t isl_seq_get_hash_bits(isl_int *p, unsigned len, unsigned bits);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/isl_set_list.c b/final/lib/External/isl/isl_set_list.c
new file mode 100644
index 0000000..3334413
--- /dev/null
+++ b/final/lib/External/isl/isl_set_list.c
@@ -0,0 +1,32 @@
+#include <isl/set.h>
+#include <isl/union_set.h>
+
+#undef EL
+#define EL isl_basic_set
+
+#include <isl_list_templ.h>
+
+#undef EL
+#define EL isl_set
+
+#include <isl_list_templ.h>
+
+#undef EL
+#define EL isl_union_set
+
+#include <isl_list_templ.h>
+
+#undef BASE
+#define BASE basic_set
+
+#include <isl_list_templ.c>
+
+#undef BASE
+#define BASE set
+
+#include <isl_list_templ.c>
+
+#undef BASE
+#define BASE union_set
+
+#include <isl_list_templ.c>
diff --git a/final/lib/External/isl/isl_sort.c b/final/lib/External/isl/isl_sort.c
new file mode 100644
index 0000000..9ed273c
--- /dev/null
+++ b/final/lib/External/isl/isl_sort.c
@@ -0,0 +1,157 @@
+/*
+ * The code of this file was taken from http://jeffreystedfast.blogspot.be,
+ * where it was posted in 2011 by Jeffrey Stedfast under the MIT license.
+ * The MIT license text is as follows:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <isl_sort.h>
+
+#define MID(lo, hi) (lo + ((hi - lo) >> 1))
+
+/* The code here is an optimized merge sort. Starting from a generic merge sort
+ * the following optimizations were applied:
+ *
+ * o Batching of memcpy() calls: Instead of calling memcpy() to copy each and
+ *   every element into a temporary buffer, blocks of elements are copied
+ *   at a time.
+ *
+ * o To reduce the number of memcpy() calls further, copying leading
+ *   and trailing elements into our temporary buffer is avoided, in case it is
+ *   not necessary to merge them.
+ *
+ * A further optimization could be to specialize memcpy calls based on the
+ * size of the types we compare. For now, this code does not include the
+ * relevant optimization, as clang e.g. inlines a very efficient memcpy()
+ * implementation. It is not clear, that the specialized version as provided in
+ * the blog post, is really superior to the one that will be inlined by
+ * default. So we decided to keep the code simple until this optimization was
+ * proven to be beneficial.
+ */
+
+static void
+msort (void *array, void *buf, size_t low, size_t high, size_t size,
+       int (* compare) (const void *, const void *, void *), void *arg)
+{
+    char *a1, *al, *am, *ah, *ls, *hs, *lo, *hi, *b;
+    size_t copied = 0;
+    size_t mid;
+
+    mid = MID (low, high);
+
+    if (mid + 1 < high)
+        msort (array, buf, mid + 1, high, size, compare, arg);
+
+    if (mid > low)
+        msort (array, buf, low, mid, size, compare, arg);
+
+    ah = ((char *) array) + ((high + 1) * size);
+    am = ((char *) array) + ((mid + 1) * size);
+    a1 = al = ((char *) array) + (low * size);
+
+    b = (char *) buf;
+    lo = al;
+    hi = am;
+
+    do {
+        ls = lo;
+        hs = hi;
+
+        if (lo > al || hi > am) {
+            /* our last loop already compared lo & hi and found lo <= hi */
+            lo += size;
+        }
+
+        while (lo < am && compare (lo, hi, arg) <= 0)
+            lo += size;
+
+        if (lo < am) {
+            if (copied == 0) {
+                /* avoid copying the leading items */
+                a1 = lo;
+                ls = lo;
+            }
+
+            /* our last compare tells us hi < lo */
+            hi += size;
+
+            while (hi < ah && compare (hi, lo, arg) < 0)
+                hi += size;
+
+            if (lo > ls) {
+                memcpy (b, ls, lo - ls);
+                copied += (lo - ls);
+                b += (lo - ls);
+            }
+
+            memcpy (b, hs, hi - hs);
+            copied += (hi - hs);
+            b += (hi - hs);
+        } else if (copied) {
+            memcpy (b, ls, lo - ls);
+            copied += (lo - ls);
+            b += (lo - ls);
+
+            /* copy everything we needed to re-order back into array */
+            memcpy (a1, buf, copied);
+            return;
+        } else {
+            /* everything already in order */
+            return;
+        }
+    } while (hi < ah);
+
+    if (lo < am) {
+        memcpy (b, lo, am - lo);
+        copied += (am - lo);
+    }
+
+    memcpy (a1, buf, copied);
+}
+
+static int
+MergeSort (void *base, size_t nmemb, size_t size,
+           int (* compare) (const void *, const void *, void *), void *arg)
+{
+    void *tmp;
+
+    if (nmemb < 2)
+        return 0;
+
+    if (!(tmp = malloc (nmemb * size))) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    msort (base, tmp, 0, nmemb - 1, size, compare, arg);
+
+    free (tmp);
+
+    return 0;
+}
+
+int isl_sort(void *const pbase, size_t total_elems, size_t size,
+	int (*cmp)(const void *, const void *, void *arg), void *arg)
+{
+    return MergeSort (pbase, total_elems, size, cmp, arg);
+}
diff --git a/final/lib/External/isl/isl_sort.h b/final/lib/External/isl/isl_sort.h
new file mode 100644
index 0000000..b69fe01
--- /dev/null
+++ b/final/lib/External/isl/isl_sort.h
@@ -0,0 +1,9 @@
+#ifndef ISL_SORT_H
+#define ISL_SORT_H
+
+#include <stddef.h>
+
+int isl_sort(void *const pbase, size_t total_elems, size_t size,
+	int (*cmp)(const void *, const void *, void *arg), void *arg);
+
+#endif
diff --git a/final/lib/External/isl/isl_space.c b/final/lib/External/isl/isl_space.c
new file mode 100644
index 0000000..0ddacc2
--- /dev/null
+++ b/final/lib/External/isl/isl_space.c
@@ -0,0 +1,2612 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2013-2014 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <isl_space_private.h>
+#include <isl_id_private.h>
+#include <isl_reordering.h>
+
+isl_ctx *isl_space_get_ctx(__isl_keep isl_space *dim)
+{
+	return dim ? dim->ctx : NULL;
+}
+
+__isl_give isl_space *isl_space_alloc(isl_ctx *ctx,
+			unsigned nparam, unsigned n_in, unsigned n_out)
+{
+	isl_space *dim;
+
+	dim = isl_alloc_type(ctx, struct isl_space);
+	if (!dim)
+		return NULL;
+
+	dim->ctx = ctx;
+	isl_ctx_ref(ctx);
+	dim->ref = 1;
+	dim->nparam = nparam;
+	dim->n_in = n_in;
+	dim->n_out = n_out;
+
+	dim->tuple_id[0] = NULL;
+	dim->tuple_id[1] = NULL;
+
+	dim->nested[0] = NULL;
+	dim->nested[1] = NULL;
+
+	dim->n_id = 0;
+	dim->ids = NULL;
+
+	return dim;
+}
+
+/* Mark the space as being that of a set, by setting the domain tuple
+ * to isl_id_none.
+ */
+static __isl_give isl_space *mark_as_set(__isl_take isl_space *space)
+{
+	space = isl_space_cow(space);
+	if (!space)
+		return NULL;
+	space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none);
+	return space;
+}
+
+/* Is the space that of a set?
+ */
+isl_bool isl_space_is_set(__isl_keep isl_space *space)
+{
+	if (!space)
+		return isl_bool_error;
+	if (space->n_in != 0 || space->nested[0])
+		return isl_bool_false;
+	if (space->tuple_id[0] != &isl_id_none)
+		return isl_bool_false;
+	return isl_bool_true;
+}
+
+/* Is the given space that of a map?
+ */
+isl_bool isl_space_is_map(__isl_keep isl_space *space)
+{
+	if (!space)
+		return isl_bool_error;
+	return space->tuple_id[0] != &isl_id_none &&
+		space->tuple_id[1] != &isl_id_none;
+}
+
+__isl_give isl_space *isl_space_set_alloc(isl_ctx *ctx,
+			unsigned nparam, unsigned dim)
+{
+	isl_space *space;
+	space = isl_space_alloc(ctx, nparam, 0, dim);
+	space = mark_as_set(space);
+	return space;
+}
+
+/* Mark the space as being that of a parameter domain, by setting
+ * both tuples to isl_id_none.
+ */
+static __isl_give isl_space *mark_as_params(isl_space *space)
+{
+	if (!space)
+		return NULL;
+	space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none);
+	space = isl_space_set_tuple_id(space, isl_dim_out, &isl_id_none);
+	return space;
+}
+
+/* Is the space that of a parameter domain?
+ */
+isl_bool isl_space_is_params(__isl_keep isl_space *space)
+{
+	if (!space)
+		return isl_bool_error;
+	if (space->n_in != 0 || space->nested[0] ||
+	    space->n_out != 0 || space->nested[1])
+		return isl_bool_false;
+	if (space->tuple_id[0] != &isl_id_none)
+		return isl_bool_false;
+	if (space->tuple_id[1] != &isl_id_none)
+		return isl_bool_false;
+	return isl_bool_true;
+}
+
+/* Create a space for a parameter domain.
+ */
+__isl_give isl_space *isl_space_params_alloc(isl_ctx *ctx, unsigned nparam)
+{
+	isl_space *space;
+	space = isl_space_alloc(ctx, nparam, 0, 0);
+	space = mark_as_params(space);
+	return space;
+}
+
+static unsigned global_pos(__isl_keep isl_space *dim,
+				 enum isl_dim_type type, unsigned pos)
+{
+	struct isl_ctx *ctx = dim->ctx;
+
+	switch (type) {
+	case isl_dim_param:
+		isl_assert(ctx, pos < dim->nparam,
+			    return isl_space_dim(dim, isl_dim_all));
+		return pos;
+	case isl_dim_in:
+		isl_assert(ctx, pos < dim->n_in,
+			    return isl_space_dim(dim, isl_dim_all));
+		return pos + dim->nparam;
+	case isl_dim_out:
+		isl_assert(ctx, pos < dim->n_out,
+			    return isl_space_dim(dim, isl_dim_all));
+		return pos + dim->nparam + dim->n_in;
+	default:
+		isl_assert(ctx, 0, return isl_space_dim(dim, isl_dim_all));
+	}
+	return isl_space_dim(dim, isl_dim_all);
+}
+
+/* Extend length of ids array to the total number of dimensions.
+ */
+static __isl_give isl_space *extend_ids(__isl_take isl_space *dim)
+{
+	isl_id **ids;
+	int i;
+
+	if (isl_space_dim(dim, isl_dim_all) <= dim->n_id)
+		return dim;
+
+	if (!dim->ids) {
+		dim->ids = isl_calloc_array(dim->ctx,
+				isl_id *, isl_space_dim(dim, isl_dim_all));
+		if (!dim->ids)
+			goto error;
+	} else {
+		ids = isl_realloc_array(dim->ctx, dim->ids,
+				isl_id *, isl_space_dim(dim, isl_dim_all));
+		if (!ids)
+			goto error;
+		dim->ids = ids;
+		for (i = dim->n_id; i < isl_space_dim(dim, isl_dim_all); ++i)
+			dim->ids[i] = NULL;
+	}
+
+	dim->n_id = isl_space_dim(dim, isl_dim_all);
+
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+static __isl_give isl_space *set_id(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	dim = isl_space_cow(dim);
+
+	if (!dim)
+		goto error;
+
+	pos = global_pos(dim, type, pos);
+	if (pos == isl_space_dim(dim, isl_dim_all))
+		goto error;
+
+	if (pos >= dim->n_id) {
+		if (!id)
+			return dim;
+		dim = extend_ids(dim);
+		if (!dim)
+			goto error;
+	}
+
+	dim->ids[pos] = id;
+
+	return dim;
+error:
+	isl_id_free(id);
+	isl_space_free(dim);
+	return NULL;
+}
+
+static __isl_keep isl_id *get_id(__isl_keep isl_space *dim,
+				 enum isl_dim_type type, unsigned pos)
+{
+	if (!dim)
+		return NULL;
+
+	pos = global_pos(dim, type, pos);
+	if (pos == isl_space_dim(dim, isl_dim_all))
+		return NULL;
+	if (pos >= dim->n_id)
+		return NULL;
+	return dim->ids[pos];
+}
+
+static unsigned offset(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	switch (type) {
+	case isl_dim_param:	return 0;
+	case isl_dim_in:	return dim->nparam;
+	case isl_dim_out:	return dim->nparam + dim->n_in;
+	default:		return 0;
+	}
+}
+
+static unsigned n(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	switch (type) {
+	case isl_dim_param:	return dim->nparam;
+	case isl_dim_in:	return dim->n_in;
+	case isl_dim_out:	return dim->n_out;
+	case isl_dim_all:	return dim->nparam + dim->n_in + dim->n_out;
+	default:		return 0;
+	}
+}
+
+unsigned isl_space_dim(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	if (!dim)
+		return 0;
+	return n(dim, type);
+}
+
+unsigned isl_space_offset(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	if (!dim)
+		return 0;
+	return offset(dim, type);
+}
+
+static __isl_give isl_space *copy_ids(__isl_take isl_space *dst,
+	enum isl_dim_type dst_type, unsigned offset, __isl_keep isl_space *src,
+	enum isl_dim_type src_type)
+{
+	int i;
+	isl_id *id;
+
+	if (!dst)
+		return NULL;
+
+	for (i = 0; i < n(src, src_type); ++i) {
+		id = get_id(src, src_type, i);
+		if (!id)
+			continue;
+		dst = set_id(dst, dst_type, offset + i, isl_id_copy(id));
+		if (!dst)
+			return NULL;
+	}
+	return dst;
+}
+
+__isl_take isl_space *isl_space_dup(__isl_keep isl_space *dim)
+{
+	isl_space *dup;
+	if (!dim)
+		return NULL;
+	dup = isl_space_alloc(dim->ctx, dim->nparam, dim->n_in, dim->n_out);
+	if (!dup)
+		return NULL;
+	if (dim->tuple_id[0] &&
+	    !(dup->tuple_id[0] = isl_id_copy(dim->tuple_id[0])))
+		goto error;
+	if (dim->tuple_id[1] &&
+	    !(dup->tuple_id[1] = isl_id_copy(dim->tuple_id[1])))
+		goto error;
+	if (dim->nested[0] && !(dup->nested[0] = isl_space_copy(dim->nested[0])))
+		goto error;
+	if (dim->nested[1] && !(dup->nested[1] = isl_space_copy(dim->nested[1])))
+		goto error;
+	if (!dim->ids)
+		return dup;
+	dup = copy_ids(dup, isl_dim_param, 0, dim, isl_dim_param);
+	dup = copy_ids(dup, isl_dim_in, 0, dim, isl_dim_in);
+	dup = copy_ids(dup, isl_dim_out, 0, dim, isl_dim_out);
+	return dup;
+error:
+	isl_space_free(dup);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_cow(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+
+	if (dim->ref == 1)
+		return dim;
+	dim->ref--;
+	return isl_space_dup(dim);
+}
+
+__isl_give isl_space *isl_space_copy(__isl_keep isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+
+	dim->ref++;
+	return dim;
+}
+
+__isl_null isl_space *isl_space_free(__isl_take isl_space *space)
+{
+	int i;
+
+	if (!space)
+		return NULL;
+
+	if (--space->ref > 0)
+		return NULL;
+
+	isl_id_free(space->tuple_id[0]);
+	isl_id_free(space->tuple_id[1]);
+
+	isl_space_free(space->nested[0]);
+	isl_space_free(space->nested[1]);
+
+	for (i = 0; i < space->n_id; ++i)
+		isl_id_free(space->ids[i]);
+	free(space->ids);
+	isl_ctx_deref(space->ctx);
+	
+	free(space);
+
+	return NULL;
+}
+
+/* Check if "s" is a valid dimension or tuple name.
+ * We currently only forbid names that look like a number.
+ *
+ * s is assumed to be non-NULL.
+ */
+static int name_ok(isl_ctx *ctx, const char *s)
+{
+	char *p;
+	long dummy;
+
+	dummy = strtol(s, &p, 0);
+	if (p != s)
+		isl_die(ctx, isl_error_invalid, "name looks like a number",
+			return 0);
+
+	return 1;
+}
+
+/* Is it possible for the given dimension type to have a tuple id?
+ */
+static int space_can_have_id(__isl_keep isl_space *space,
+	enum isl_dim_type type)
+{
+	if (!space)
+		return 0;
+	if (isl_space_is_params(space))
+		isl_die(space->ctx, isl_error_invalid,
+			"parameter spaces don't have tuple ids", return 0);
+	if (isl_space_is_set(space) && type != isl_dim_set)
+		isl_die(space->ctx, isl_error_invalid,
+			"set spaces can only have a set id", return 0);
+	if (type != isl_dim_in && type != isl_dim_out)
+		isl_die(space->ctx, isl_error_invalid,
+			"only input, output and set tuples can have ids",
+			return 0);
+
+	return 1;
+}
+
+/* Does the tuple have an id?
+ */
+isl_bool isl_space_has_tuple_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type)
+{
+	if (!space_can_have_id(dim, type))
+		return isl_bool_error;
+	return dim->tuple_id[type - isl_dim_in] != NULL;
+}
+
+__isl_give isl_id *isl_space_get_tuple_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type)
+{
+	int has_id;
+
+	if (!dim)
+		return NULL;
+	has_id = isl_space_has_tuple_id(dim, type);
+	if (has_id < 0)
+		return NULL;
+	if (!has_id)
+		isl_die(dim->ctx, isl_error_invalid,
+			"tuple has no id", return NULL);
+	return isl_id_copy(dim->tuple_id[type - isl_dim_in]);
+}
+
+__isl_give isl_space *isl_space_set_tuple_id(__isl_take isl_space *dim,
+	enum isl_dim_type type, __isl_take isl_id *id)
+{
+	dim = isl_space_cow(dim);
+	if (!dim || !id)
+		goto error;
+	if (type != isl_dim_in && type != isl_dim_out)
+		isl_die(dim->ctx, isl_error_invalid,
+			"only input, output and set tuples can have names",
+			goto error);
+
+	isl_id_free(dim->tuple_id[type - isl_dim_in]);
+	dim->tuple_id[type - isl_dim_in] = id;
+
+	return dim;
+error:
+	isl_id_free(id);
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_reset_tuple_id(__isl_take isl_space *dim,
+	enum isl_dim_type type)
+{
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+	if (type != isl_dim_in && type != isl_dim_out)
+		isl_die(dim->ctx, isl_error_invalid,
+			"only input, output and set tuples can have names",
+			goto error);
+
+	isl_id_free(dim->tuple_id[type - isl_dim_in]);
+	dim->tuple_id[type - isl_dim_in] = NULL;
+
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Set the id of the given dimension of "space" to "id".
+ * If the dimension already has an id, then it is replaced.
+ * If the dimension is a parameter, then we need to change it
+ * in the nested spaces (if any) as well.
+ */
+__isl_give isl_space *isl_space_set_dim_id(__isl_take isl_space *space,
+	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
+{
+	space = isl_space_cow(space);
+	if (!space || !id)
+		goto error;
+
+	if (type == isl_dim_param) {
+		int i;
+
+		for (i = 0; i < 2; ++i) {
+			if (!space->nested[i])
+				continue;
+			space->nested[i] =
+				isl_space_set_dim_id(space->nested[i],
+						type, pos, isl_id_copy(id));
+			if (!space->nested[i])
+				goto error;
+		}
+	}
+
+	isl_id_free(get_id(space, type, pos));
+	return set_id(space, type, pos, id);
+error:
+	isl_id_free(id);
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Reset the id of the given dimension of "space".
+ * If the dimension already has an id, then it is removed.
+ * If the dimension is a parameter, then we need to reset it
+ * in the nested spaces (if any) as well.
+ */
+__isl_give isl_space *isl_space_reset_dim_id(__isl_take isl_space *space,
+	enum isl_dim_type type, unsigned pos)
+{
+	space = isl_space_cow(space);
+	if (!space)
+		goto error;
+
+	if (type == isl_dim_param) {
+		int i;
+
+		for (i = 0; i < 2; ++i) {
+			if (!space->nested[i])
+				continue;
+			space->nested[i] =
+				isl_space_reset_dim_id(space->nested[i],
+							type, pos);
+			if (!space->nested[i])
+				goto error;
+		}
+	}
+
+	isl_id_free(get_id(space, type, pos));
+	return set_id(space, type, pos, NULL);
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+isl_bool isl_space_has_dim_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!dim)
+		return isl_bool_error;
+	return get_id(dim, type, pos) != NULL;
+}
+
+__isl_give isl_id *isl_space_get_dim_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!dim)
+		return NULL;
+	if (!get_id(dim, type, pos))
+		isl_die(dim->ctx, isl_error_invalid,
+			"dim has no id", return NULL);
+	return isl_id_copy(get_id(dim, type, pos));
+}
+
+__isl_give isl_space *isl_space_set_tuple_name(__isl_take isl_space *dim,
+	enum isl_dim_type type, const char *s)
+{
+	isl_id *id;
+
+	if (!dim)
+		return NULL;
+
+	if (!s)
+		return isl_space_reset_tuple_id(dim, type);
+
+	if (!name_ok(dim->ctx, s))
+		goto error;
+
+	id = isl_id_alloc(dim->ctx, s, NULL);
+	return isl_space_set_tuple_id(dim, type, id);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Does the tuple have a name?
+ */
+isl_bool isl_space_has_tuple_name(__isl_keep isl_space *space,
+	enum isl_dim_type type)
+{
+	isl_id *id;
+
+	if (!space_can_have_id(space, type))
+		return isl_bool_error;
+	id = space->tuple_id[type - isl_dim_in];
+	return id && id->name;
+}
+
+__isl_keep const char *isl_space_get_tuple_name(__isl_keep isl_space *dim,
+	 enum isl_dim_type type)
+{
+	isl_id *id;
+	if (!dim)
+		return NULL;
+	if (type != isl_dim_in && type != isl_dim_out)
+		return NULL;
+	id = dim->tuple_id[type - isl_dim_in];
+	return id ? id->name : NULL;
+}
+
+__isl_give isl_space *isl_space_set_dim_name(__isl_take isl_space *dim,
+				 enum isl_dim_type type, unsigned pos,
+				 const char *s)
+{
+	isl_id *id;
+
+	if (!dim)
+		return NULL;
+	if (!s)
+		return isl_space_reset_dim_id(dim, type, pos);
+	if (!name_ok(dim->ctx, s))
+		goto error;
+	id = isl_id_alloc(dim->ctx, s, NULL);
+	return isl_space_set_dim_id(dim, type, pos, id);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Does the given dimension have a name?
+ */
+isl_bool isl_space_has_dim_name(__isl_keep isl_space *space,
+	enum isl_dim_type type, unsigned pos)
+{
+	isl_id *id;
+
+	if (!space)
+		return isl_bool_error;
+	id = get_id(space, type, pos);
+	return id && id->name;
+}
+
+__isl_keep const char *isl_space_get_dim_name(__isl_keep isl_space *dim,
+				 enum isl_dim_type type, unsigned pos)
+{
+	isl_id *id = get_id(dim, type, pos);
+	return id ? id->name : NULL;
+}
+
+int isl_space_find_dim_by_id(__isl_keep isl_space *dim, enum isl_dim_type type,
+	__isl_keep isl_id *id)
+{
+	int i;
+	int offset;
+	int n;
+
+	if (!dim || !id)
+		return -1;
+
+	offset = isl_space_offset(dim, type);
+	n = isl_space_dim(dim, type);
+	for (i = 0; i < n && offset + i < dim->n_id; ++i)
+		if (dim->ids[offset + i] == id)
+			return i;
+
+	return -1;
+}
+
+int isl_space_find_dim_by_name(__isl_keep isl_space *space,
+	enum isl_dim_type type, const char *name)
+{
+	int i;
+	int offset;
+	int n;
+
+	if (!space || !name)
+		return -1;
+
+	offset = isl_space_offset(space, type);
+	n = isl_space_dim(space, type);
+	for (i = 0; i < n && offset + i < space->n_id; ++i) {
+		isl_id *id = get_id(space, type, i);
+		if (id && id->name && !strcmp(id->name, name))
+			return i;
+	}
+
+	return -1;
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of "space".
+ */
+__isl_give isl_space *isl_space_reset_user(__isl_take isl_space *space)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_id *id;
+	const char *name;
+
+	if (!space)
+		return NULL;
+
+	ctx = isl_space_get_ctx(space);
+
+	for (i = 0; i < space->nparam && i < space->n_id; ++i) {
+		if (!isl_id_get_user(space->ids[i]))
+			continue;
+		space = isl_space_cow(space);
+		if (!space)
+			return NULL;
+		name = isl_id_get_name(space->ids[i]);
+		id = isl_id_alloc(ctx, name, NULL);
+		isl_id_free(space->ids[i]);
+		space->ids[i] = id;
+		if (!id)
+			return isl_space_free(space);
+	}
+
+	for (i = 0; i < 2; ++i) {
+		if (!space->tuple_id[i])
+			continue;
+		if (!isl_id_get_user(space->tuple_id[i]))
+			continue;
+		space = isl_space_cow(space);
+		if (!space)
+			return NULL;
+		name = isl_id_get_name(space->tuple_id[i]);
+		id = isl_id_alloc(ctx, name, NULL);
+		isl_id_free(space->tuple_id[i]);
+		space->tuple_id[i] = id;
+		if (!id)
+			return isl_space_free(space);
+	}
+
+	for (i = 0; i < 2; ++i) {
+		if (!space->nested[i])
+			continue;
+		space = isl_space_cow(space);
+		if (!space)
+			return NULL;
+		space->nested[i] = isl_space_reset_user(space->nested[i]);
+		if (!space->nested[i])
+			return isl_space_free(space);
+	}
+
+	return space;
+}
+
+static __isl_keep isl_id *tuple_id(__isl_keep isl_space *dim,
+	enum isl_dim_type type)
+{
+	if (!dim)
+		return NULL;
+	if (type == isl_dim_in)
+		return dim->tuple_id[0];
+	if (type == isl_dim_out)
+		return dim->tuple_id[1];
+	return NULL;
+}
+
+static __isl_keep isl_space *nested(__isl_keep isl_space *dim,
+	enum isl_dim_type type)
+{
+	if (!dim)
+		return NULL;
+	if (type == isl_dim_in)
+		return dim->nested[0];
+	if (type == isl_dim_out)
+		return dim->nested[1];
+	return NULL;
+}
+
+/* Are the two spaces the same, apart from positions and names of parameters?
+ */
+isl_bool isl_space_has_equal_tuples(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	if (!space1 || !space2)
+		return isl_bool_error;
+	if (space1 == space2)
+		return isl_bool_true;
+	return isl_space_tuple_is_equal(space1, isl_dim_in,
+					space2, isl_dim_in) &&
+	       isl_space_tuple_is_equal(space1, isl_dim_out,
+					space2, isl_dim_out);
+}
+
+/* Check if the tuple of type "type1" of "space1" is the same as
+ * the tuple of type "type2" of "space2".
+ *
+ * That is, check if the tuples have the same identifier, the same dimension
+ * and the same internal structure.
+ * The identifiers of the dimensions inside the tuples do not affect the result.
+ *
+ * Note that this function only checks the tuples themselves.
+ * If nested tuples are involved, then we need to be careful not
+ * to have result affected by possibly differing parameters
+ * in those nested tuples.
+ */
+isl_bool isl_space_tuple_is_equal(__isl_keep isl_space *space1,
+	enum isl_dim_type type1, __isl_keep isl_space *space2,
+	enum isl_dim_type type2)
+{
+	isl_id *id1, *id2;
+	isl_space *nested1, *nested2;
+
+	if (!space1 || !space2)
+		return isl_bool_error;
+
+	if (space1 == space2 && type1 == type2)
+		return isl_bool_true;
+
+	if (n(space1, type1) != n(space2, type2))
+		return isl_bool_false;
+	id1 = tuple_id(space1, type1);
+	id2 = tuple_id(space2, type2);
+	if (!id1 ^ !id2)
+		return isl_bool_false;
+	if (id1 && id1 != id2)
+		return isl_bool_false;
+	nested1 = nested(space1, type1);
+	nested2 = nested(space2, type2);
+	if (!nested1 ^ !nested2)
+		return isl_bool_false;
+	if (nested1 && !isl_space_has_equal_tuples(nested1, nested2))
+		return isl_bool_false;
+	return isl_bool_true;
+}
+
+/* This is the old, undocumented, name for isl_space_tuple_is_equal.
+ * It will be removed at some point.
+ */
+int isl_space_tuple_match(__isl_keep isl_space *space1, enum isl_dim_type type1,
+	__isl_keep isl_space *space2, enum isl_dim_type type2)
+{
+	return isl_space_tuple_is_equal(space1, type1, space2, type2);
+}
+
+static isl_bool match(__isl_keep isl_space *space1, enum isl_dim_type type1,
+	__isl_keep isl_space *space2, enum isl_dim_type type2)
+{
+	int i;
+
+	if (space1 == space2 && type1 == type2)
+		return isl_bool_true;
+
+	if (!isl_space_tuple_is_equal(space1, type1, space2, type2))
+		return isl_bool_false;
+
+	if (!space1->ids && !space2->ids)
+		return isl_bool_true;
+
+	for (i = 0; i < n(space1, type1); ++i) {
+		if (get_id(space1, type1, i) != get_id(space2, type2, i))
+			return isl_bool_false;
+	}
+	return isl_bool_true;
+}
+
+/* Do "space1" and "space2" have the same parameters?
+ */
+isl_bool isl_space_has_equal_params(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	if (!space1 || !space2)
+		return isl_bool_error;
+
+	return match(space1, isl_dim_param, space2, isl_dim_param);
+}
+
+/* Do "space1" and "space2" have the same identifiers for all
+ * the tuple variables?
+ */
+isl_bool isl_space_has_equal_ids(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	isl_bool equal;
+
+	if (!space1 || !space2)
+		return isl_bool_error;
+
+	equal = match(space1, isl_dim_in, space2, isl_dim_in);
+	if (equal < 0 || !equal)
+		return equal;
+	return match(space1, isl_dim_out, space2, isl_dim_out);
+}
+
+isl_bool isl_space_match(__isl_keep isl_space *space1, enum isl_dim_type type1,
+	__isl_keep isl_space *space2, enum isl_dim_type type2)
+{
+	if (!space1 || !space2)
+		return isl_bool_error;
+
+	return match(space1, type1, space2, type2);
+}
+
+static void get_ids(__isl_keep isl_space *dim, enum isl_dim_type type,
+	unsigned first, unsigned n, __isl_keep isl_id **ids)
+{
+	int i;
+
+	for (i = 0; i < n ; ++i)
+		ids[i] = get_id(dim, type, first + i);
+}
+
+static __isl_give isl_space *space_extend(__isl_take isl_space *space,
+			unsigned nparam, unsigned n_in, unsigned n_out)
+{
+	isl_id **ids = NULL;
+
+	if (!space)
+		return NULL;
+	if (space->nparam == nparam &&
+	    space->n_in == n_in && space->n_out == n_out)
+		return space;
+
+	isl_assert(space->ctx, space->nparam <= nparam, goto error);
+	isl_assert(space->ctx, space->n_in <= n_in, goto error);
+	isl_assert(space->ctx, space->n_out <= n_out, goto error);
+
+	space = isl_space_cow(space);
+	if (!space)
+		goto error;
+
+	if (space->ids) {
+		unsigned n;
+		n = nparam + n_in + n_out;
+		if (n < nparam || n < n_in || n < n_out)
+			isl_die(isl_space_get_ctx(space), isl_error_invalid,
+				"overflow in total number of dimensions",
+				goto error);
+		ids = isl_calloc_array(space->ctx, isl_id *, n);
+		if (!ids)
+			goto error;
+		get_ids(space, isl_dim_param, 0, space->nparam, ids);
+		get_ids(space, isl_dim_in, 0, space->n_in, ids + nparam);
+		get_ids(space, isl_dim_out, 0, space->n_out,
+			ids + nparam + n_in);
+		free(space->ids);
+		space->ids = ids;
+		space->n_id = nparam + n_in + n_out;
+	}
+	space->nparam = nparam;
+	space->n_in = n_in;
+	space->n_out = n_out;
+
+	return space;
+error:
+	free(ids);
+	isl_space_free(space);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_extend(__isl_take isl_space *space,
+	unsigned nparam, unsigned n_in, unsigned n_out)
+{
+	return space_extend(space, nparam, n_in, n_out);
+}
+
+__isl_give isl_space *isl_space_add_dims(__isl_take isl_space *space,
+	enum isl_dim_type type, unsigned n)
+{
+	space = isl_space_reset(space, type);
+	if (!space)
+		return NULL;
+	switch (type) {
+	case isl_dim_param:
+		space = space_extend(space,
+				space->nparam + n, space->n_in, space->n_out);
+		if (space && space->nested[0] &&
+		    !(space->nested[0] = isl_space_add_dims(space->nested[0],
+						    isl_dim_param, n)))
+			goto error;
+		if (space && space->nested[1] &&
+		    !(space->nested[1] = isl_space_add_dims(space->nested[1],
+						    isl_dim_param, n)))
+			goto error;
+		return space;
+	case isl_dim_in:
+		return space_extend(space,
+				space->nparam, space->n_in + n, space->n_out);
+	case isl_dim_out:
+		return space_extend(space,
+				space->nparam, space->n_in, space->n_out + n);
+	default:
+		isl_die(space->ctx, isl_error_invalid,
+			"cannot add dimensions of specified type", goto error);
+	}
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+static int valid_dim_type(enum isl_dim_type type)
+{
+	switch (type) {
+	case isl_dim_param:
+	case isl_dim_in:
+	case isl_dim_out:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/* Insert "n" dimensions of type "type" at position "pos".
+ * If we are inserting parameters, then they are also inserted in
+ * any nested spaces.
+ */
+__isl_give isl_space *isl_space_insert_dims(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned pos, unsigned n)
+{
+	isl_id **ids = NULL;
+
+	if (!dim)
+		return NULL;
+	if (n == 0)
+		return isl_space_reset(dim, type);
+
+	if (!valid_dim_type(type))
+		isl_die(dim->ctx, isl_error_invalid,
+			"cannot insert dimensions of specified type",
+			goto error);
+
+	isl_assert(dim->ctx, pos <= isl_space_dim(dim, type), goto error);
+
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+
+	if (dim->ids) {
+		enum isl_dim_type t, o = isl_dim_param;
+		int off;
+		int s[3];
+		ids = isl_calloc_array(dim->ctx, isl_id *,
+				     dim->nparam + dim->n_in + dim->n_out + n);
+		if (!ids)
+			goto error;
+		off = 0;
+		s[isl_dim_param - o] = dim->nparam;
+		s[isl_dim_in - o] = dim->n_in;
+		s[isl_dim_out - o] = dim->n_out;
+		for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+			if (t != type) {
+				get_ids(dim, t, 0, s[t - o], ids + off);
+				off += s[t - o];
+			} else {
+				get_ids(dim, t, 0, pos, ids + off);
+				off += pos + n;
+				get_ids(dim, t, pos, s[t - o] - pos, ids + off);
+				off += s[t - o] - pos;
+			}
+		}
+		free(dim->ids);
+		dim->ids = ids;
+		dim->n_id = dim->nparam + dim->n_in + dim->n_out + n;
+	}
+	switch (type) {
+	case isl_dim_param:	dim->nparam += n; break;
+	case isl_dim_in:	dim->n_in += n; break;
+	case isl_dim_out:	dim->n_out += n; break;
+	default:		;
+	}
+	dim = isl_space_reset(dim, type);
+
+	if (type == isl_dim_param) {
+		if (dim && dim->nested[0] &&
+		    !(dim->nested[0] = isl_space_insert_dims(dim->nested[0],
+						    isl_dim_param, pos, n)))
+			goto error;
+		if (dim && dim->nested[1] &&
+		    !(dim->nested[1] = isl_space_insert_dims(dim->nested[1],
+						    isl_dim_param, pos, n)))
+			goto error;
+	}
+
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_move_dims(__isl_take isl_space *space,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	int i;
+
+	space = isl_space_reset(space, src_type);
+	space = isl_space_reset(space, dst_type);
+	if (!space)
+		return NULL;
+	if (n == 0)
+		return space;
+
+	isl_assert(space->ctx, src_pos + n <= isl_space_dim(space, src_type),
+		goto error);
+
+	if (dst_type == src_type && dst_pos == src_pos)
+		return space;
+
+	isl_assert(space->ctx, dst_type != src_type, goto error);
+
+	space = isl_space_cow(space);
+	if (!space)
+		return NULL;
+
+	if (space->ids) {
+		isl_id **ids;
+		enum isl_dim_type t, o = isl_dim_param;
+		int off;
+		int s[3];
+		ids = isl_calloc_array(space->ctx, isl_id *,
+				 space->nparam + space->n_in + space->n_out);
+		if (!ids)
+			goto error;
+		off = 0;
+		s[isl_dim_param - o] = space->nparam;
+		s[isl_dim_in - o] = space->n_in;
+		s[isl_dim_out - o] = space->n_out;
+		for (t = isl_dim_param; t <= isl_dim_out; ++t) {
+			if (t == dst_type) {
+				get_ids(space, t, 0, dst_pos, ids + off);
+				off += dst_pos;
+				get_ids(space, src_type, src_pos, n, ids + off);
+				off += n;
+				get_ids(space, t, dst_pos, s[t - o] - dst_pos,
+						ids + off);
+				off += s[t - o] - dst_pos;
+			} else if (t == src_type) {
+				get_ids(space, t, 0, src_pos, ids + off);
+				off += src_pos;
+				get_ids(space, t, src_pos + n,
+					    s[t - o] - src_pos - n, ids + off);
+				off += s[t - o] - src_pos - n;
+			} else {
+				get_ids(space, t, 0, s[t - o], ids + off);
+				off += s[t - o];
+			}
+		}
+		free(space->ids);
+		space->ids = ids;
+		space->n_id = space->nparam + space->n_in + space->n_out;
+	}
+
+	switch (dst_type) {
+	case isl_dim_param:	space->nparam += n; break;
+	case isl_dim_in:	space->n_in += n; break;
+	case isl_dim_out:	space->n_out += n; break;
+	default:		;
+	}
+
+	switch (src_type) {
+	case isl_dim_param:	space->nparam -= n; break;
+	case isl_dim_in:	space->n_in -= n; break;
+	case isl_dim_out:	space->n_out -= n; break;
+	default:		;
+	}
+
+	if (dst_type != isl_dim_param && src_type != isl_dim_param)
+		return space;
+
+	for (i = 0; i < 2; ++i) {
+		if (!space->nested[i])
+			continue;
+		space->nested[i] = isl_space_replace(space->nested[i],
+						 isl_dim_param, space);
+		if (!space->nested[i])
+			goto error;
+	}
+
+	return space;
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Check that "space1" and "space2" have the same parameters,
+ * reporting an error if they do not.
+ */
+isl_stat isl_space_check_equal_params(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	isl_bool equal;
+
+	equal = isl_space_has_equal_params(space1, space2);
+	if (equal < 0)
+		return isl_stat_error;
+	if (!equal)
+		isl_die(isl_space_get_ctx(space1), isl_error_invalid,
+			"parameters need to match", return isl_stat_error);
+	return isl_stat_ok;
+}
+
+__isl_give isl_space *isl_space_join(__isl_take isl_space *left,
+	__isl_take isl_space *right)
+{
+	isl_space *dim;
+
+	if (isl_space_check_equal_params(left, right) < 0)
+		goto error;
+
+	isl_assert(left->ctx,
+		isl_space_tuple_is_equal(left, isl_dim_out, right, isl_dim_in),
+		goto error);
+
+	dim = isl_space_alloc(left->ctx, left->nparam, left->n_in, right->n_out);
+	if (!dim)
+		goto error;
+
+	dim = copy_ids(dim, isl_dim_param, 0, left, isl_dim_param);
+	dim = copy_ids(dim, isl_dim_in, 0, left, isl_dim_in);
+	dim = copy_ids(dim, isl_dim_out, 0, right, isl_dim_out);
+
+	if (dim && left->tuple_id[0] &&
+	    !(dim->tuple_id[0] = isl_id_copy(left->tuple_id[0])))
+		goto error;
+	if (dim && right->tuple_id[1] &&
+	    !(dim->tuple_id[1] = isl_id_copy(right->tuple_id[1])))
+		goto error;
+	if (dim && left->nested[0] &&
+	    !(dim->nested[0] = isl_space_copy(left->nested[0])))
+		goto error;
+	if (dim && right->nested[1] &&
+	    !(dim->nested[1] = isl_space_copy(right->nested[1])))
+		goto error;
+
+	isl_space_free(left);
+	isl_space_free(right);
+
+	return dim;
+error:
+	isl_space_free(left);
+	isl_space_free(right);
+	return NULL;
+}
+
+/* Given two map spaces { A -> C } and { B -> D }, construct the space
+ * { [A -> B] -> [C -> D] }.
+ * Given two set spaces { A } and { B }, construct the space { [A -> B] }.
+ */
+__isl_give isl_space *isl_space_product(__isl_take isl_space *left,
+	__isl_take isl_space *right)
+{
+	isl_space *dom1, *dom2, *nest1, *nest2;
+	int is_set;
+
+	if (!left || !right)
+		goto error;
+
+	is_set = isl_space_is_set(left);
+	if (is_set != isl_space_is_set(right))
+		isl_die(isl_space_get_ctx(left), isl_error_invalid,
+			"expecting either two set spaces or two map spaces",
+			goto error);
+	if (is_set)
+		return isl_space_range_product(left, right);
+
+	if (isl_space_check_equal_params(left, right) < 0)
+		goto error;
+
+	dom1 = isl_space_domain(isl_space_copy(left));
+	dom2 = isl_space_domain(isl_space_copy(right));
+	nest1 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
+
+	dom1 = isl_space_range(left);
+	dom2 = isl_space_range(right);
+	nest2 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
+
+	return isl_space_join(isl_space_reverse(nest1), nest2);
+error:
+	isl_space_free(left);
+	isl_space_free(right);
+	return NULL;
+}
+
+/* Given two spaces { A -> C } and { B -> C }, construct the space
+ * { [A -> B] -> C }
+ */
+__isl_give isl_space *isl_space_domain_product(__isl_take isl_space *left,
+	__isl_take isl_space *right)
+{
+	isl_space *ran, *dom1, *dom2, *nest;
+
+	if (isl_space_check_equal_params(left, right) < 0)
+		goto error;
+
+	if (!isl_space_tuple_is_equal(left, isl_dim_out, right, isl_dim_out))
+		isl_die(left->ctx, isl_error_invalid,
+			"ranges need to match", goto error);
+
+	ran = isl_space_range(isl_space_copy(left));
+
+	dom1 = isl_space_domain(left);
+	dom2 = isl_space_domain(right);
+	nest = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
+
+	return isl_space_join(isl_space_reverse(nest), ran);
+error:
+	isl_space_free(left);
+	isl_space_free(right);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_range_product(__isl_take isl_space *left,
+	__isl_take isl_space *right)
+{
+	isl_space *dom, *ran1, *ran2, *nest;
+
+	if (isl_space_check_equal_params(left, right) < 0)
+		goto error;
+
+	if (!isl_space_tuple_is_equal(left, isl_dim_in, right, isl_dim_in))
+		isl_die(left->ctx, isl_error_invalid,
+			"domains need to match", goto error);
+
+	dom = isl_space_domain(isl_space_copy(left));
+
+	ran1 = isl_space_range(left);
+	ran2 = isl_space_range(right);
+	nest = isl_space_wrap(isl_space_join(isl_space_reverse(ran1), ran2));
+
+	return isl_space_join(isl_space_reverse(dom), nest);
+error:
+	isl_space_free(left);
+	isl_space_free(right);
+	return NULL;
+}
+
+/* Given a space of the form [A -> B] -> [C -> D], return the space A -> C.
+ */
+__isl_give isl_space *isl_space_factor_domain(__isl_take isl_space *space)
+{
+	space = isl_space_domain_factor_domain(space);
+	space = isl_space_range_factor_domain(space);
+	return space;
+}
+
+/* Given a space of the form [A -> B] -> C, return the space A -> C.
+ */
+__isl_give isl_space *isl_space_domain_factor_domain(
+	__isl_take isl_space *space)
+{
+	isl_space *nested;
+	isl_space *domain;
+
+	if (!space)
+		return NULL;
+	if (!isl_space_domain_is_wrapping(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"domain not a product", return isl_space_free(space));
+
+	nested = space->nested[0];
+	domain = isl_space_copy(space);
+	domain = isl_space_drop_dims(domain, isl_dim_in,
+					nested->n_in, nested->n_out);
+	if (!domain)
+		return isl_space_free(space);
+	if (nested->tuple_id[0]) {
+		domain->tuple_id[0] = isl_id_copy(nested->tuple_id[0]);
+		if (!domain->tuple_id[0])
+			goto error;
+	}
+	if (nested->nested[0]) {
+		domain->nested[0] = isl_space_copy(nested->nested[0]);
+		if (!domain->nested[0])
+			goto error;
+	}
+
+	isl_space_free(space);
+	return domain;
+error:
+	isl_space_free(space);
+	isl_space_free(domain);
+	return NULL;
+}
+
+/* Given a space of the form [A -> B] -> C, return the space B -> C.
+ */
+__isl_give isl_space *isl_space_domain_factor_range(
+	__isl_take isl_space *space)
+{
+	isl_space *nested;
+	isl_space *range;
+
+	if (!space)
+		return NULL;
+	if (!isl_space_domain_is_wrapping(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"domain not a product", return isl_space_free(space));
+
+	nested = space->nested[0];
+	range = isl_space_copy(space);
+	range = isl_space_drop_dims(range, isl_dim_in, 0, nested->n_in);
+	if (!range)
+		return isl_space_free(space);
+	if (nested->tuple_id[1]) {
+		range->tuple_id[0] = isl_id_copy(nested->tuple_id[1]);
+		if (!range->tuple_id[0])
+			goto error;
+	}
+	if (nested->nested[1]) {
+		range->nested[0] = isl_space_copy(nested->nested[1]);
+		if (!range->nested[0])
+			goto error;
+	}
+
+	isl_space_free(space);
+	return range;
+error:
+	isl_space_free(space);
+	isl_space_free(range);
+	return NULL;
+}
+
+/* Given a space of the form A -> [B -> C], return the space A -> B.
+ */
+__isl_give isl_space *isl_space_range_factor_domain(
+	__isl_take isl_space *space)
+{
+	isl_space *nested;
+	isl_space *domain;
+
+	if (!space)
+		return NULL;
+	if (!isl_space_range_is_wrapping(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"range not a product", return isl_space_free(space));
+
+	nested = space->nested[1];
+	domain = isl_space_copy(space);
+	domain = isl_space_drop_dims(domain, isl_dim_out,
+					nested->n_in, nested->n_out);
+	if (!domain)
+		return isl_space_free(space);
+	if (nested->tuple_id[0]) {
+		domain->tuple_id[1] = isl_id_copy(nested->tuple_id[0]);
+		if (!domain->tuple_id[1])
+			goto error;
+	}
+	if (nested->nested[0]) {
+		domain->nested[1] = isl_space_copy(nested->nested[0]);
+		if (!domain->nested[1])
+			goto error;
+	}
+
+	isl_space_free(space);
+	return domain;
+error:
+	isl_space_free(space);
+	isl_space_free(domain);
+	return NULL;
+}
+
+/* Internal function that selects the range of the map that is
+ * embedded in either a set space or the range of a map space.
+ * In particular, given a space of the form [A -> B], return the space B.
+ * Given a space of the form A -> [B -> C], return the space A -> C.
+ */
+static __isl_give isl_space *range_factor_range(__isl_take isl_space *space)
+{
+	isl_space *nested;
+	isl_space *range;
+
+	if (!space)
+		return NULL;
+
+	nested = space->nested[1];
+	range = isl_space_copy(space);
+	range = isl_space_drop_dims(range, isl_dim_out, 0, nested->n_in);
+	if (!range)
+		return isl_space_free(space);
+	if (nested->tuple_id[1]) {
+		range->tuple_id[1] = isl_id_copy(nested->tuple_id[1]);
+		if (!range->tuple_id[1])
+			goto error;
+	}
+	if (nested->nested[1]) {
+		range->nested[1] = isl_space_copy(nested->nested[1]);
+		if (!range->nested[1])
+			goto error;
+	}
+
+	isl_space_free(space);
+	return range;
+error:
+	isl_space_free(space);
+	isl_space_free(range);
+	return NULL;
+}
+
+/* Given a space of the form A -> [B -> C], return the space A -> C.
+ */
+__isl_give isl_space *isl_space_range_factor_range(
+	__isl_take isl_space *space)
+{
+	if (!space)
+		return NULL;
+	if (!isl_space_range_is_wrapping(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"range not a product", return isl_space_free(space));
+
+	return range_factor_range(space);
+}
+
+/* Given a space of the form [A -> B], return the space B.
+ */
+static __isl_give isl_space *set_factor_range(__isl_take isl_space *space)
+{
+	if (!space)
+		return NULL;
+	if (!isl_space_is_wrapping(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"not a product", return isl_space_free(space));
+
+	return range_factor_range(space);
+}
+
+/* Given a space of the form [A -> B] -> [C -> D], return the space B -> D.
+ * Given a space of the form [A -> B], return the space B.
+ */
+__isl_give isl_space *isl_space_factor_range(__isl_take isl_space *space)
+{
+	if (!space)
+		return NULL;
+	if (isl_space_is_set(space))
+		return set_factor_range(space);
+	space = isl_space_domain_factor_range(space);
+	space = isl_space_range_factor_range(space);
+	return space;
+}
+
+__isl_give isl_space *isl_space_map_from_set(__isl_take isl_space *space)
+{
+	isl_ctx *ctx;
+	isl_id **ids = NULL;
+	int n_id;
+
+	if (!space)
+		return NULL;
+	ctx = isl_space_get_ctx(space);
+	if (!isl_space_is_set(space))
+		isl_die(ctx, isl_error_invalid, "not a set space", goto error);
+	space = isl_space_cow(space);
+	if (!space)
+		return NULL;
+	n_id = space->nparam + space->n_out + space->n_out;
+	if (n_id > 0 && space->ids) {
+		ids = isl_calloc_array(space->ctx, isl_id *, n_id);
+		if (!ids)
+			goto error;
+		get_ids(space, isl_dim_param, 0, space->nparam, ids);
+		get_ids(space, isl_dim_out, 0, space->n_out,
+			ids + space->nparam);
+	}
+	space->n_in = space->n_out;
+	if (ids) {
+		free(space->ids);
+		space->ids = ids;
+		space->n_id = n_id;
+		space = copy_ids(space, isl_dim_out, 0, space, isl_dim_in);
+	}
+	isl_id_free(space->tuple_id[0]);
+	space->tuple_id[0] = isl_id_copy(space->tuple_id[1]);
+	isl_space_free(space->nested[0]);
+	space->nested[0] = isl_space_copy(space->nested[1]);
+	return space;
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_map_from_domain_and_range(
+	__isl_take isl_space *domain, __isl_take isl_space *range)
+{
+	if (!domain || !range)
+		goto error;
+	if (!isl_space_is_set(domain))
+		isl_die(isl_space_get_ctx(domain), isl_error_invalid,
+			"domain is not a set space", goto error);
+	if (!isl_space_is_set(range))
+		isl_die(isl_space_get_ctx(range), isl_error_invalid,
+			"range is not a set space", goto error);
+	return isl_space_join(isl_space_reverse(domain), range);
+error:
+	isl_space_free(domain);
+	isl_space_free(range);
+	return NULL;
+}
+
+static __isl_give isl_space *set_ids(__isl_take isl_space *dim,
+	enum isl_dim_type type,
+	unsigned first, unsigned n, __isl_take isl_id **ids)
+{
+	int i;
+
+	for (i = 0; i < n ; ++i)
+		dim = set_id(dim, type, first + i, ids[i]);
+
+	return dim;
+}
+
+__isl_give isl_space *isl_space_reverse(__isl_take isl_space *dim)
+{
+	unsigned t;
+	isl_space *nested;
+	isl_id **ids = NULL;
+	isl_id *id;
+
+	if (!dim)
+		return NULL;
+	if (match(dim, isl_dim_in, dim, isl_dim_out))
+		return dim;
+
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+
+	id = dim->tuple_id[0];
+	dim->tuple_id[0] = dim->tuple_id[1];
+	dim->tuple_id[1] = id;
+
+	nested = dim->nested[0];
+	dim->nested[0] = dim->nested[1];
+	dim->nested[1] = nested;
+
+	if (dim->ids) {
+		int n_id = dim->n_in + dim->n_out;
+		ids = isl_alloc_array(dim->ctx, isl_id *, n_id);
+		if (n_id && !ids)
+			goto error;
+		get_ids(dim, isl_dim_in, 0, dim->n_in, ids);
+		get_ids(dim, isl_dim_out, 0, dim->n_out, ids + dim->n_in);
+	}
+
+	t = dim->n_in;
+	dim->n_in = dim->n_out;
+	dim->n_out = t;
+
+	if (dim->ids) {
+		dim = set_ids(dim, isl_dim_out, 0, dim->n_out, ids);
+		dim = set_ids(dim, isl_dim_in, 0, dim->n_in, ids + dim->n_out);
+		free(ids);
+	}
+
+	return dim;
+error:
+	free(ids);
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_drop_dims(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned first, unsigned num)
+{
+	int i;
+
+	if (!dim)
+		return NULL;
+
+	if (num == 0)
+		return isl_space_reset(dim, type);
+
+	if (!valid_dim_type(type))
+		isl_die(dim->ctx, isl_error_invalid,
+			"cannot drop dimensions of specified type", goto error);
+
+	if (first + num > n(dim, type) || first + num < first)
+		isl_die(isl_space_get_ctx(dim), isl_error_invalid,
+			"index out of bounds", return isl_space_free(dim));
+	dim = isl_space_cow(dim);
+	if (!dim)
+		goto error;
+	if (dim->ids) {
+		dim = extend_ids(dim);
+		if (!dim)
+			goto error;
+		for (i = 0; i < num; ++i)
+			isl_id_free(get_id(dim, type, first + i));
+		for (i = first+num; i < n(dim, type); ++i)
+			set_id(dim, type, i - num, get_id(dim, type, i));
+		switch (type) {
+		case isl_dim_param:
+			get_ids(dim, isl_dim_in, 0, dim->n_in,
+				dim->ids + offset(dim, isl_dim_in) - num);
+		case isl_dim_in:
+			get_ids(dim, isl_dim_out, 0, dim->n_out,
+				dim->ids + offset(dim, isl_dim_out) - num);
+		default:
+			;
+		}
+		dim->n_id -= num;
+	}
+	switch (type) {
+	case isl_dim_param:	dim->nparam -= num; break;
+	case isl_dim_in:	dim->n_in -= num; break;
+	case isl_dim_out:	dim->n_out -= num; break;
+	default:		;
+	}
+	dim = isl_space_reset(dim, type);
+	if (type == isl_dim_param) {
+		if (dim && dim->nested[0] &&
+		    !(dim->nested[0] = isl_space_drop_dims(dim->nested[0],
+						    isl_dim_param, first, num)))
+			goto error;
+		if (dim && dim->nested[1] &&
+		    !(dim->nested[1] = isl_space_drop_dims(dim->nested[1],
+						    isl_dim_param, first, num)))
+			goto error;
+	}
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_drop_inputs(__isl_take isl_space *dim,
+		unsigned first, unsigned n)
+{
+	if (!dim)
+		return NULL;
+	return isl_space_drop_dims(dim, isl_dim_in, first, n);
+}
+
+__isl_give isl_space *isl_space_drop_outputs(__isl_take isl_space *dim,
+		unsigned first, unsigned n)
+{
+	if (!dim)
+		return NULL;
+	return isl_space_drop_dims(dim, isl_dim_out, first, n);
+}
+
+__isl_give isl_space *isl_space_domain(__isl_take isl_space *space)
+{
+	if (!space)
+		return NULL;
+	space = isl_space_drop_dims(space, isl_dim_out, 0, space->n_out);
+	space = isl_space_reverse(space);
+	space = mark_as_set(space);
+	return space;
+}
+
+__isl_give isl_space *isl_space_from_domain(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	if (!isl_space_is_set(dim))
+		isl_die(isl_space_get_ctx(dim), isl_error_invalid,
+			"not a set space", goto error);
+	dim = isl_space_reverse(dim);
+	dim = isl_space_reset(dim, isl_dim_out);
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_range(__isl_take isl_space *space)
+{
+	if (!space)
+		return NULL;
+	space = isl_space_drop_dims(space, isl_dim_in, 0, space->n_in);
+	space = mark_as_set(space);
+	return space;
+}
+
+__isl_give isl_space *isl_space_from_range(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	if (!isl_space_is_set(dim))
+		isl_die(isl_space_get_ctx(dim), isl_error_invalid,
+			"not a set space", goto error);
+	return isl_space_reset(dim, isl_dim_in);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Given a map space A -> B, return the map space [A -> B] -> A.
+ */
+__isl_give isl_space *isl_space_domain_map(__isl_take isl_space *space)
+{
+	isl_space *domain;
+
+	domain = isl_space_from_range(isl_space_domain(isl_space_copy(space)));
+	space = isl_space_from_domain(isl_space_wrap(space));
+	space = isl_space_join(space, domain);
+
+	return space;
+}
+
+/* Given a map space A -> B, return the map space [A -> B] -> B.
+ */
+__isl_give isl_space *isl_space_range_map(__isl_take isl_space *space)
+{
+	isl_space *range;
+
+	range = isl_space_from_range(isl_space_range(isl_space_copy(space)));
+	space = isl_space_from_domain(isl_space_wrap(space));
+	space = isl_space_join(space, range);
+
+	return space;
+}
+
+__isl_give isl_space *isl_space_params(__isl_take isl_space *space)
+{
+	if (isl_space_is_params(space))
+		return space;
+	space = isl_space_drop_dims(space,
+			    isl_dim_in, 0, isl_space_dim(space, isl_dim_in));
+	space = isl_space_drop_dims(space,
+			    isl_dim_out, 0, isl_space_dim(space, isl_dim_out));
+	space = mark_as_params(space);
+	return space;
+}
+
+__isl_give isl_space *isl_space_set_from_params(__isl_take isl_space *space)
+{
+	if (!space)
+		return NULL;
+	if (!isl_space_is_params(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"not a parameter space", goto error);
+	return isl_space_reset(space, isl_dim_set);
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_underlying(__isl_take isl_space *dim,
+	unsigned n_div)
+{
+	int i;
+
+	if (!dim)
+		return NULL;
+	if (n_div == 0 &&
+	    dim->nparam == 0 && dim->n_in == 0 && dim->n_id == 0)
+		return isl_space_reset(isl_space_reset(dim, isl_dim_in), isl_dim_out);
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+	dim->n_out += dim->nparam + dim->n_in + n_div;
+	dim->nparam = 0;
+	dim->n_in = 0;
+
+	for (i = 0; i < dim->n_id; ++i)
+		isl_id_free(get_id(dim, isl_dim_out, i));
+	dim->n_id = 0;
+	dim = isl_space_reset(dim, isl_dim_in);
+	dim = isl_space_reset(dim, isl_dim_out);
+
+	return dim;
+}
+
+/* Are the two spaces the same, including positions and names of parameters?
+ */
+isl_bool isl_space_is_equal(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	isl_bool equal;
+
+	if (!space1 || !space2)
+		return isl_bool_error;
+	if (space1 == space2)
+		return isl_bool_true;
+	equal = isl_space_has_equal_params(space1, space2);
+	if (equal < 0 || !equal)
+		return equal;
+	return isl_space_has_equal_tuples(space1, space2);
+}
+
+/* Is space1 equal to the domain of space2?
+ *
+ * In the internal version we also allow space2 to be the space of a set,
+ * provided space1 is a parameter space.
+ */
+isl_bool isl_space_is_domain_internal(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	isl_bool equal_params;
+
+	if (!space1 || !space2)
+		return isl_bool_error;
+	if (!isl_space_is_set(space1))
+		return isl_bool_false;
+	equal_params = isl_space_has_equal_params(space1, space2);
+	if (equal_params < 0 || !equal_params)
+		return equal_params;
+	return isl_space_tuple_is_equal(space1, isl_dim_set,
+					space2, isl_dim_in);
+}
+
+/* Is space1 equal to the domain of space2?
+ */
+isl_bool isl_space_is_domain(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	if (!space2)
+		return isl_bool_error;
+	if (!isl_space_is_map(space2))
+		return isl_bool_false;
+	return isl_space_is_domain_internal(space1, space2);
+}
+
+/* Is space1 equal to the range of space2?
+ *
+ * In the internal version, space2 is allowed to be the space of a set,
+ * in which case it should be equal to space1.
+ */
+isl_bool isl_space_is_range_internal(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	isl_bool equal_params;
+
+	if (!space1 || !space2)
+		return isl_bool_error;
+	if (!isl_space_is_set(space1))
+		return isl_bool_false;
+	equal_params = isl_space_has_equal_params(space1, space2);
+	if (equal_params < 0 || !equal_params)
+		return equal_params;
+	return isl_space_tuple_is_equal(space1, isl_dim_set,
+					space2, isl_dim_out);
+}
+
+/* Is space1 equal to the range of space2?
+ */
+isl_bool isl_space_is_range(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	if (!space2)
+		return isl_bool_error;
+	if (!isl_space_is_map(space2))
+		return isl_bool_false;
+	return isl_space_is_range_internal(space1, space2);
+}
+
+/* Update "hash" by hashing in the parameters of "space".
+ */
+static uint32_t isl_hash_params(uint32_t hash, __isl_keep isl_space *space)
+{
+	int i;
+	isl_id *id;
+
+	if (!space)
+		return hash;
+
+	isl_hash_byte(hash, space->nparam % 256);
+
+	for (i = 0; i < space->nparam; ++i) {
+		id = get_id(space, isl_dim_param, i);
+		hash = isl_hash_id(hash, id);
+	}
+
+	return hash;
+}
+
+/* Update "hash" by hashing in the tuples of "space".
+ * Changes in this function should be reflected in isl_hash_tuples_domain.
+ */
+static uint32_t isl_hash_tuples(uint32_t hash, __isl_keep isl_space *space)
+{
+	isl_id *id;
+
+	if (!space)
+		return hash;
+
+	isl_hash_byte(hash, space->n_in % 256);
+	isl_hash_byte(hash, space->n_out % 256);
+
+	id = tuple_id(space, isl_dim_in);
+	hash = isl_hash_id(hash, id);
+	id = tuple_id(space, isl_dim_out);
+	hash = isl_hash_id(hash, id);
+
+	hash = isl_hash_tuples(hash, space->nested[0]);
+	hash = isl_hash_tuples(hash, space->nested[1]);
+
+	return hash;
+}
+
+/* Update "hash" by hashing in the domain tuple of "space".
+ * The result of this function is equal to the result of applying
+ * isl_hash_tuples to the domain of "space".
+ */
+static uint32_t isl_hash_tuples_domain(uint32_t hash,
+	__isl_keep isl_space *space)
+{
+	isl_id *id;
+
+	if (!space)
+		return hash;
+
+	isl_hash_byte(hash, 0);
+	isl_hash_byte(hash, space->n_in % 256);
+
+	hash = isl_hash_id(hash, &isl_id_none);
+	id = tuple_id(space, isl_dim_in);
+	hash = isl_hash_id(hash, id);
+
+	hash = isl_hash_tuples(hash, space->nested[0]);
+
+	return hash;
+}
+
+/* Return a hash value that digests the tuples of "space",
+ * i.e., that ignores the parameters.
+ */
+uint32_t isl_space_get_tuple_hash(__isl_keep isl_space *space)
+{
+	uint32_t hash;
+
+	if (!space)
+		return 0;
+
+	hash = isl_hash_init();
+	hash = isl_hash_tuples(hash, space);
+
+	return hash;
+}
+
+uint32_t isl_space_get_hash(__isl_keep isl_space *space)
+{
+	uint32_t hash;
+
+	if (!space)
+		return 0;
+
+	hash = isl_hash_init();
+	hash = isl_hash_params(hash, space);
+	hash = isl_hash_tuples(hash, space);
+
+	return hash;
+}
+
+/* Return the hash value of the domain of "space".
+ * That is, isl_space_get_domain_hash(space) is equal to
+ * isl_space_get_hash(isl_space_domain(space)).
+ */
+uint32_t isl_space_get_domain_hash(__isl_keep isl_space *space)
+{
+	uint32_t hash;
+
+	if (!space)
+		return 0;
+
+	hash = isl_hash_init();
+	hash = isl_hash_params(hash, space);
+	hash = isl_hash_tuples_domain(hash, space);
+
+	return hash;
+}
+
+isl_bool isl_space_is_wrapping(__isl_keep isl_space *dim)
+{
+	if (!dim)
+		return isl_bool_error;
+
+	if (!isl_space_is_set(dim))
+		return isl_bool_false;
+
+	return dim->nested[1] != NULL;
+}
+
+/* Is "space" the space of a map where the domain is a wrapped map space?
+ */
+isl_bool isl_space_domain_is_wrapping(__isl_keep isl_space *space)
+{
+	if (!space)
+		return isl_bool_error;
+
+	if (isl_space_is_set(space))
+		return isl_bool_false;
+
+	return space->nested[0] != NULL;
+}
+
+/* Is "space" the space of a map where the range is a wrapped map space?
+ */
+isl_bool isl_space_range_is_wrapping(__isl_keep isl_space *space)
+{
+	if (!space)
+		return isl_bool_error;
+
+	if (isl_space_is_set(space))
+		return isl_bool_false;
+
+	return space->nested[1] != NULL;
+}
+
+/* Is "space" a product of two spaces?
+ * That is, is it a wrapping set space or a map space
+ * with wrapping domain and range?
+ */
+isl_bool isl_space_is_product(__isl_keep isl_space *space)
+{
+	isl_bool is_set;
+	isl_bool is_product;
+
+	is_set = isl_space_is_set(space);
+	if (is_set < 0)
+		return isl_bool_error;
+	if (is_set)
+		return isl_space_is_wrapping(space);
+	is_product = isl_space_domain_is_wrapping(space);
+	if (is_product < 0 || !is_product)
+		return is_product;
+	return isl_space_range_is_wrapping(space);
+}
+
+__isl_give isl_space *isl_space_wrap(__isl_take isl_space *dim)
+{
+	isl_space *wrap;
+
+	if (!dim)
+		return NULL;
+
+	wrap = isl_space_set_alloc(dim->ctx,
+				    dim->nparam, dim->n_in + dim->n_out);
+
+	wrap = copy_ids(wrap, isl_dim_param, 0, dim, isl_dim_param);
+	wrap = copy_ids(wrap, isl_dim_set, 0, dim, isl_dim_in);
+	wrap = copy_ids(wrap, isl_dim_set, dim->n_in, dim, isl_dim_out);
+
+	if (!wrap)
+		goto error;
+
+	wrap->nested[1] = dim;
+
+	return wrap;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_unwrap(__isl_take isl_space *dim)
+{
+	isl_space *unwrap;
+
+	if (!dim)
+		return NULL;
+
+	if (!isl_space_is_wrapping(dim))
+		isl_die(dim->ctx, isl_error_invalid, "not a wrapping space",
+			goto error);
+
+	unwrap = isl_space_copy(dim->nested[1]);
+	isl_space_free(dim);
+
+	return unwrap;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+isl_bool isl_space_is_named_or_nested(__isl_keep isl_space *space,
+	enum isl_dim_type type)
+{
+	if (type != isl_dim_in && type != isl_dim_out)
+		return isl_bool_false;
+	if (!space)
+		return isl_bool_error;
+	if (space->tuple_id[type - isl_dim_in])
+		return isl_bool_true;
+	if (space->nested[type - isl_dim_in])
+		return isl_bool_true;
+	return isl_bool_false;
+}
+
+isl_bool isl_space_may_be_set(__isl_keep isl_space *space)
+{
+	isl_bool nested;
+
+	if (!space)
+		return isl_bool_error;
+	if (isl_space_is_set(space))
+		return isl_bool_true;
+	if (isl_space_dim(space, isl_dim_in) != 0)
+		return isl_bool_false;
+	nested = isl_space_is_named_or_nested(space, isl_dim_in);
+	if (nested < 0 || nested)
+		return isl_bool_not(nested);
+	return isl_bool_true;
+}
+
+__isl_give isl_space *isl_space_reset(__isl_take isl_space *dim,
+	enum isl_dim_type type)
+{
+	if (!isl_space_is_named_or_nested(dim, type))
+		return dim;
+
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+
+	isl_id_free(dim->tuple_id[type - isl_dim_in]);
+	dim->tuple_id[type - isl_dim_in] = NULL;
+	isl_space_free(dim->nested[type - isl_dim_in]);
+	dim->nested[type - isl_dim_in] = NULL;
+
+	return dim;
+}
+
+__isl_give isl_space *isl_space_flatten(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	if (!dim->nested[0] && !dim->nested[1])
+		return dim;
+
+	if (dim->nested[0])
+		dim = isl_space_reset(dim, isl_dim_in);
+	if (dim && dim->nested[1])
+		dim = isl_space_reset(dim, isl_dim_out);
+
+	return dim;
+}
+
+__isl_give isl_space *isl_space_flatten_domain(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	if (!dim->nested[0])
+		return dim;
+
+	return isl_space_reset(dim, isl_dim_in);
+}
+
+__isl_give isl_space *isl_space_flatten_range(__isl_take isl_space *dim)
+{
+	if (!dim)
+		return NULL;
+	if (!dim->nested[1])
+		return dim;
+
+	return isl_space_reset(dim, isl_dim_out);
+}
+
+/* Replace the dimensions of the given type of dst by those of src.
+ */
+__isl_give isl_space *isl_space_replace(__isl_take isl_space *dst,
+	enum isl_dim_type type, __isl_keep isl_space *src)
+{
+	dst = isl_space_cow(dst);
+
+	if (!dst || !src)
+		goto error;
+
+	dst = isl_space_drop_dims(dst, type, 0, isl_space_dim(dst, type));
+	dst = isl_space_add_dims(dst, type, isl_space_dim(src, type));
+	dst = copy_ids(dst, type, 0, src, type);
+
+	if (dst && type == isl_dim_param) {
+		int i;
+		for (i = 0; i <= 1; ++i) {
+			if (!dst->nested[i])
+				continue;
+			dst->nested[i] = isl_space_replace(dst->nested[i],
+							 type, src);
+			if (!dst->nested[i])
+				goto error;
+		}
+	}
+
+	return dst;
+error:
+	isl_space_free(dst);
+	return NULL;
+}
+
+/* Given a dimension specification "dim" of a set, create a dimension
+ * specification for the lift of the set.  In particular, the result
+ * is of the form [dim -> local[..]], with n_local variables in the
+ * range of the wrapped map.
+ */
+__isl_give isl_space *isl_space_lift(__isl_take isl_space *dim, unsigned n_local)
+{
+	isl_space *local_dim;
+
+	if (!dim)
+		return NULL;
+
+	local_dim = isl_space_dup(dim);
+	local_dim = isl_space_drop_dims(local_dim, isl_dim_set, 0, dim->n_out);
+	local_dim = isl_space_add_dims(local_dim, isl_dim_set, n_local);
+	local_dim = isl_space_set_tuple_name(local_dim, isl_dim_set, "local");
+	dim = isl_space_join(isl_space_from_domain(dim),
+			    isl_space_from_range(local_dim));
+	dim = isl_space_wrap(dim);
+	dim = isl_space_set_tuple_name(dim, isl_dim_set, "lifted");
+
+	return dim;
+}
+
+isl_bool isl_space_can_zip(__isl_keep isl_space *space)
+{
+	isl_bool is_set;
+
+	is_set = isl_space_is_set(space);
+	if (is_set < 0)
+		return isl_bool_error;
+	if (is_set)
+		return isl_bool_false;
+	return isl_space_is_product(space);
+}
+
+__isl_give isl_space *isl_space_zip(__isl_take isl_space *dim)
+{
+	isl_space *dom, *ran;
+	isl_space *dom_dom, *dom_ran, *ran_dom, *ran_ran;
+
+	if (!isl_space_can_zip(dim))
+		isl_die(dim->ctx, isl_error_invalid, "dim cannot be zipped",
+			goto error);
+
+	if (!dim)
+		return NULL;
+	dom = isl_space_unwrap(isl_space_domain(isl_space_copy(dim)));
+	ran = isl_space_unwrap(isl_space_range(dim));
+	dom_dom = isl_space_domain(isl_space_copy(dom));
+	dom_ran = isl_space_range(dom);
+	ran_dom = isl_space_domain(isl_space_copy(ran));
+	ran_ran = isl_space_range(ran);
+	dom = isl_space_join(isl_space_from_domain(dom_dom),
+			   isl_space_from_range(ran_dom));
+	ran = isl_space_join(isl_space_from_domain(dom_ran),
+			   isl_space_from_range(ran_ran));
+	return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)),
+			    isl_space_from_range(isl_space_wrap(ran)));
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Can we apply isl_space_curry to "space"?
+ * That is, does it have a nested relation in its domain?
+ */
+isl_bool isl_space_can_curry(__isl_keep isl_space *space)
+{
+	if (!space)
+		return isl_bool_error;
+
+	return !!space->nested[0];
+}
+
+/* Given a space (A -> B) -> C, return the corresponding space
+ * A -> (B -> C).
+ */
+__isl_give isl_space *isl_space_curry(__isl_take isl_space *space)
+{
+	isl_space *dom, *ran;
+	isl_space *dom_dom, *dom_ran;
+
+	if (!space)
+		return NULL;
+
+	if (!isl_space_can_curry(space))
+		isl_die(space->ctx, isl_error_invalid,
+			"space cannot be curried", goto error);
+
+	dom = isl_space_unwrap(isl_space_domain(isl_space_copy(space)));
+	ran = isl_space_range(space);
+	dom_dom = isl_space_domain(isl_space_copy(dom));
+	dom_ran = isl_space_range(dom);
+	ran = isl_space_join(isl_space_from_domain(dom_ran),
+			   isl_space_from_range(ran));
+	return isl_space_join(isl_space_from_domain(dom_dom),
+			    isl_space_from_range(isl_space_wrap(ran)));
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Can isl_space_range_curry be applied to "space"?
+ * That is, does it have a nested relation in its range,
+ * the domain of which is itself a nested relation?
+ */
+isl_bool isl_space_can_range_curry(__isl_keep isl_space *space)
+{
+	isl_bool can;
+
+	if (!space)
+		return isl_bool_error;
+	can = isl_space_range_is_wrapping(space);
+	if (can < 0 || !can)
+		return can;
+	return isl_space_can_curry(space->nested[1]);
+}
+
+/* Given a space A -> ((B -> C) -> D), return the corresponding space
+ * A -> (B -> (C -> D)).
+ */
+__isl_give isl_space *isl_space_range_curry(__isl_take isl_space *space)
+{
+	if (!space)
+		return NULL;
+
+	if (!isl_space_can_range_curry(space))
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"space range cannot be curried",
+			return isl_space_free(space));
+
+	space = isl_space_cow(space);
+	if (!space)
+		return NULL;
+	space->nested[1] = isl_space_curry(space->nested[1]);
+	if (!space->nested[1])
+		return isl_space_free(space);
+
+	return space;
+}
+
+/* Can we apply isl_space_uncurry to "space"?
+ * That is, does it have a nested relation in its range?
+ */
+isl_bool isl_space_can_uncurry(__isl_keep isl_space *space)
+{
+	if (!space)
+		return isl_bool_error;
+
+	return !!space->nested[1];
+}
+
+/* Given a space A -> (B -> C), return the corresponding space
+ * (A -> B) -> C.
+ */
+__isl_give isl_space *isl_space_uncurry(__isl_take isl_space *space)
+{
+	isl_space *dom, *ran;
+	isl_space *ran_dom, *ran_ran;
+
+	if (!space)
+		return NULL;
+
+	if (!isl_space_can_uncurry(space))
+		isl_die(space->ctx, isl_error_invalid,
+			"space cannot be uncurried",
+			return isl_space_free(space));
+
+	dom = isl_space_domain(isl_space_copy(space));
+	ran = isl_space_unwrap(isl_space_range(space));
+	ran_dom = isl_space_domain(isl_space_copy(ran));
+	ran_ran = isl_space_range(ran);
+	dom = isl_space_join(isl_space_from_domain(dom),
+			   isl_space_from_range(ran_dom));
+	return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)),
+			    isl_space_from_range(ran_ran));
+}
+
+isl_bool isl_space_has_named_params(__isl_keep isl_space *space)
+{
+	int i;
+	unsigned off;
+
+	if (!space)
+		return isl_bool_error;
+	if (space->nparam == 0)
+		return isl_bool_true;
+	off = isl_space_offset(space, isl_dim_param);
+	if (off + space->nparam > space->n_id)
+		return isl_bool_false;
+	for (i = 0; i < space->nparam; ++i)
+		if (!space->ids[off + i])
+			return isl_bool_false;
+	return isl_bool_true;
+}
+
+/* Check that "space" has only named parameters, reporting an error
+ * if it does not.
+ */
+isl_stat isl_space_check_named_params(__isl_keep isl_space *space)
+{
+	isl_bool named;
+
+	named = isl_space_has_named_params(space);
+	if (named < 0)
+		return isl_stat_error;
+	if (!named)
+		isl_die(isl_space_get_ctx(space), isl_error_invalid,
+			"unaligned unnamed parameters", return isl_stat_error);
+
+	return isl_stat_ok;
+}
+
+/* Align the initial parameters of dim1 to match the order in dim2.
+ */
+__isl_give isl_space *isl_space_align_params(__isl_take isl_space *dim1,
+	__isl_take isl_space *dim2)
+{
+	isl_reordering *exp;
+
+	if (!isl_space_has_named_params(dim1) || !isl_space_has_named_params(dim2))
+		isl_die(isl_space_get_ctx(dim1), isl_error_invalid,
+			"parameter alignment requires named parameters",
+			goto error);
+
+	dim2 = isl_space_params(dim2);
+	exp = isl_parameter_alignment_reordering(dim1, dim2);
+	exp = isl_reordering_extend_space(exp, dim1);
+	isl_space_free(dim2);
+	if (!exp)
+		return NULL;
+	dim1 = isl_space_copy(exp->dim);
+	isl_reordering_free(exp);
+	return dim1;
+error:
+	isl_space_free(dim1);
+	isl_space_free(dim2);
+	return NULL;
+}
+
+/* Given the space of set (domain), construct a space for a map
+ * with as domain the given space and as range the range of "model".
+ */
+__isl_give isl_space *isl_space_extend_domain_with_range(
+	__isl_take isl_space *space, __isl_take isl_space *model)
+{
+	if (!model)
+		goto error;
+
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out,
+				    isl_space_dim(model, isl_dim_out));
+	if (isl_space_has_tuple_id(model, isl_dim_out))
+		space = isl_space_set_tuple_id(space, isl_dim_out,
+				isl_space_get_tuple_id(model, isl_dim_out));
+	if (!space)
+		goto error;
+	if (model->nested[1]) {
+		isl_space *nested = isl_space_copy(model->nested[1]);
+		int n_nested, n_space;
+		nested = isl_space_align_params(nested, isl_space_copy(space));
+		n_nested = isl_space_dim(nested, isl_dim_param);
+		n_space = isl_space_dim(space, isl_dim_param);
+		if (n_nested > n_space)
+			nested = isl_space_drop_dims(nested, isl_dim_param,
+						n_space, n_nested - n_space);
+		if (!nested)
+			goto error;
+		space->nested[1] = nested;
+	}
+	isl_space_free(model);
+	return space;
+error:
+	isl_space_free(model);
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Compare the "type" dimensions of two isl_spaces.
+ *
+ * The order is fairly arbitrary.
+ */
+static int isl_space_cmp_type(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2, enum isl_dim_type type)
+{
+	int cmp;
+	isl_space *nested1, *nested2;
+
+	if (isl_space_dim(space1, type) != isl_space_dim(space2, type))
+		return isl_space_dim(space1, type) -
+			isl_space_dim(space2, type);
+
+	cmp = isl_id_cmp(tuple_id(space1, type), tuple_id(space2, type));
+	if (cmp != 0)
+		return cmp;
+
+	nested1 = nested(space1, type);
+	nested2 = nested(space2, type);
+	if (!nested1 != !nested2)
+		return !nested1 - !nested2;
+
+	if (nested1)
+		return isl_space_cmp(nested1, nested2);
+
+	return 0;
+}
+
+/* Compare two isl_spaces.
+ *
+ * The order is fairly arbitrary.
+ */
+int isl_space_cmp(__isl_keep isl_space *space1, __isl_keep isl_space *space2)
+{
+	int i;
+	int cmp;
+
+	if (space1 == space2)
+		return 0;
+	if (!space1)
+		return -1;
+	if (!space2)
+		return 1;
+
+	cmp = isl_space_cmp_type(space1, space2, isl_dim_param);
+	if (cmp != 0)
+		return cmp;
+	cmp = isl_space_cmp_type(space1, space2, isl_dim_in);
+	if (cmp != 0)
+		return cmp;
+	cmp = isl_space_cmp_type(space1, space2, isl_dim_out);
+	if (cmp != 0)
+		return cmp;
+
+	if (!space1->ids && !space2->ids)
+		return 0;
+
+	for (i = 0; i < n(space1, isl_dim_param); ++i) {
+		cmp = isl_id_cmp(get_id(space1, isl_dim_param, i),
+				 get_id(space2, isl_dim_param, i));
+		if (cmp != 0)
+			return cmp;
+	}
+
+	return 0;
+}
diff --git a/final/lib/External/isl/isl_space_private.h b/final/lib/External/isl/isl_space_private.h
new file mode 100644
index 0000000..783ba43
--- /dev/null
+++ b/final/lib/External/isl/isl_space_private.h
@@ -0,0 +1,66 @@
+#ifndef ISL_SPACE_PRIVATE
+#define ISL_SPACE_PRIVATE
+
+#include <isl/space.h>
+#include <isl/hash.h>
+#include <isl/id.h>
+
+struct isl_name;
+struct isl_space {
+	int ref;
+
+	struct isl_ctx *ctx;
+
+	unsigned nparam;
+	unsigned n_in;		/* zero for sets */
+	unsigned n_out;		/* dim for sets */
+
+	isl_id *tuple_id[2];
+	isl_space *nested[2];
+
+	unsigned n_id;
+	isl_id **ids;
+};
+
+__isl_give isl_space *isl_space_cow(__isl_take isl_space *dim);
+
+__isl_give isl_space *isl_space_underlying(__isl_take isl_space *dim,
+	unsigned n_div);
+
+uint32_t isl_space_get_tuple_hash(__isl_keep isl_space *space);
+uint32_t isl_space_get_hash(__isl_keep isl_space *space);
+uint32_t isl_space_get_domain_hash(__isl_keep isl_space *space);
+
+isl_bool isl_space_is_domain_internal(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2);
+isl_bool isl_space_is_range_internal(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2);
+
+unsigned isl_space_offset(__isl_keep isl_space *dim, enum isl_dim_type type);
+
+isl_bool isl_space_may_be_set(__isl_keep isl_space *space);
+isl_bool isl_space_is_named_or_nested(__isl_keep isl_space *space,
+	enum isl_dim_type type);
+isl_bool isl_space_has_equal_ids(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2);
+isl_bool isl_space_has_named_params(__isl_keep isl_space *space);
+isl_stat isl_space_check_named_params(__isl_keep isl_space *space);
+isl_stat isl_space_check_equal_params(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2);
+__isl_give isl_space *isl_space_reset(__isl_take isl_space *dim,
+	enum isl_dim_type type);
+__isl_give isl_space *isl_space_flatten(__isl_take isl_space *dim);
+__isl_give isl_space *isl_space_flatten_domain(__isl_take isl_space *dim);
+__isl_give isl_space *isl_space_flatten_range(__isl_take isl_space *dim);
+
+__isl_give isl_space *isl_space_replace(__isl_take isl_space *dst,
+	enum isl_dim_type type, __isl_keep isl_space *src);
+
+__isl_give isl_space *isl_space_lift(__isl_take isl_space *dim, unsigned n_local);
+
+__isl_give isl_space *isl_space_extend_domain_with_range(
+	__isl_take isl_space *domain, __isl_take isl_space *model);
+
+int isl_space_cmp(__isl_keep isl_space *space1, __isl_keep isl_space *space2);
+
+#endif
diff --git a/final/lib/External/isl/isl_srcdir.c.in b/final/lib/External/isl/isl_srcdir.c.in
new file mode 100644
index 0000000..38e30c5
--- /dev/null
+++ b/final/lib/External/isl/isl_srcdir.c.in
@@ -0,0 +1 @@
+static const char *srcdir = "@srcdir@";
diff --git a/final/lib/External/isl/isl_stream.c b/final/lib/External/isl/isl_stream.c
new file mode 100644
index 0000000..cf1fd5e
--- /dev/null
+++ b/final/lib/External/isl/isl_stream.c
@@ -0,0 +1,1170 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <isl/ctx.h>
+#include <isl_stream_private.h>
+#include <isl/map.h>
+#include <isl/aff.h>
+#include <isl_val_private.h>
+
+struct isl_keyword {
+	char			*name;
+	enum isl_token_type	type;
+};
+
+static int same_name(const void *entry, const void *val)
+{
+	const struct isl_keyword *keyword = (const struct isl_keyword *)entry;
+
+	return !strcmp(keyword->name, val);
+}
+
+enum isl_token_type isl_stream_register_keyword(__isl_keep isl_stream *s,
+	const char *name)
+{
+	struct isl_hash_table_entry *entry;
+	struct isl_keyword *keyword;
+	uint32_t name_hash;
+
+	if (!s->keywords) {
+		s->keywords = isl_hash_table_alloc(s->ctx, 10);
+		if (!s->keywords)
+			return ISL_TOKEN_ERROR;
+		s->next_type = ISL_TOKEN_LAST;
+	}
+
+	name_hash = isl_hash_string(isl_hash_init(), name);
+
+	entry = isl_hash_table_find(s->ctx, s->keywords, name_hash,
+					same_name, name, 1);
+	if (!entry)
+		return ISL_TOKEN_ERROR;
+	if (entry->data) {
+		keyword = entry->data;
+		return keyword->type;
+	}
+
+	keyword = isl_calloc_type(s->ctx, struct isl_keyword);
+	if (!keyword)
+		return ISL_TOKEN_ERROR;
+	keyword->type = s->next_type++;
+	keyword->name = strdup(name);
+	if (!keyword->name) {
+		free(keyword);
+		return ISL_TOKEN_ERROR;
+	}
+	entry->data = keyword;
+
+	return keyword->type;
+}
+
+struct isl_token *isl_token_new(isl_ctx *ctx,
+	int line, int col, unsigned on_new_line)
+{
+	struct isl_token *tok = isl_alloc_type(ctx, struct isl_token);
+	if (!tok)
+		return NULL;
+	tok->line = line;
+	tok->col = col;
+	tok->on_new_line = on_new_line;
+	tok->is_keyword = 0;
+	tok->u.s = NULL;
+	return tok;
+}
+
+/* Return the type of "tok".
+ */
+int isl_token_get_type(struct isl_token *tok)
+{
+	return tok ? tok->type : ISL_TOKEN_ERROR;
+}
+
+/* Given a token of type ISL_TOKEN_VALUE, return the value it represents.
+ */
+__isl_give isl_val *isl_token_get_val(isl_ctx *ctx, struct isl_token *tok)
+{
+	if (!tok)
+		return NULL;
+	if (tok->type != ISL_TOKEN_VALUE)
+		isl_die(ctx, isl_error_invalid, "not a value token",
+			return NULL);
+
+	return isl_val_int_from_isl_int(ctx, tok->u.v);
+}
+
+/* Given a token with a string representation, return a copy of this string.
+ */
+__isl_give char *isl_token_get_str(isl_ctx *ctx, struct isl_token *tok)
+{
+	if (!tok)
+		return NULL;
+	if (!tok->u.s)
+		isl_die(ctx, isl_error_invalid,
+			"token does not have a string representation",
+			return NULL);
+
+	return strdup(tok->u.s);
+}
+
+void isl_token_free(struct isl_token *tok)
+{
+	if (!tok)
+		return;
+	if (tok->type == ISL_TOKEN_VALUE)
+		isl_int_clear(tok->u.v);
+	else if (tok->type == ISL_TOKEN_MAP)
+		isl_map_free(tok->u.map);
+	else if (tok->type == ISL_TOKEN_AFF)
+		isl_pw_aff_free(tok->u.pwaff);
+	else
+		free(tok->u.s);
+	free(tok);
+}
+
+void isl_stream_error(__isl_keep isl_stream *s, struct isl_token *tok,
+	char *msg)
+{
+	int line = tok ? tok->line : s->line;
+	int col = tok ? tok->col : s->col;
+	fprintf(stderr, "syntax error (%d, %d): %s\n", line, col, msg);
+	if (tok) {
+		if (tok->type < 256)
+			fprintf(stderr, "got '%c'\n", tok->type);
+		else if (tok->type == ISL_TOKEN_IDENT)
+			fprintf(stderr, "got ident '%s'\n", tok->u.s);
+		else if (tok->is_keyword)
+			fprintf(stderr, "got keyword '%s'\n", tok->u.s);
+		else if (tok->type == ISL_TOKEN_VALUE) {
+			fprintf(stderr, "got value '");
+			isl_int_print(stderr, tok->u.v, 0);
+			fprintf(stderr, "'\n");
+		} else if (tok->type == ISL_TOKEN_MAP) {
+			isl_printer *p;
+			fprintf(stderr, "got map '");
+			p = isl_printer_to_file(s->ctx, stderr);
+			p = isl_printer_print_map(p, tok->u.map);
+			isl_printer_free(p);
+			fprintf(stderr, "'\n");
+		} else if (tok->type == ISL_TOKEN_AFF) {
+			isl_printer *p;
+			fprintf(stderr, "got affine expression '");
+			p = isl_printer_to_file(s->ctx, stderr);
+			p = isl_printer_print_pw_aff(p, tok->u.pwaff);
+			isl_printer_free(p);
+			fprintf(stderr, "'\n");
+		} else if (tok->u.s)
+			fprintf(stderr, "got token '%s'\n", tok->u.s);
+		else
+			fprintf(stderr, "got token type %d\n", tok->type);
+	}
+}
+
+static __isl_give isl_stream* isl_stream_new(struct isl_ctx *ctx)
+{
+	int i;
+	isl_stream *s = isl_calloc_type(ctx, struct isl_stream);
+	if (!s)
+		return NULL;
+	s->ctx = ctx;
+	isl_ctx_ref(s->ctx);
+	s->file = NULL;
+	s->str = NULL;
+	s->len = 0;
+	s->line = 1;
+	s->col = 1;
+	s->eof = 0;
+	s->last_line = 0;
+	s->c = -1;
+	s->n_un = 0;
+	for (i = 0; i < 5; ++i)
+		s->tokens[i] = NULL;
+	s->n_token = 0;
+	s->keywords = NULL;
+	s->size = 256;
+	s->buffer = isl_alloc_array(ctx, char, s->size);
+	if (!s->buffer)
+		goto error;
+	return s;
+error:
+	isl_stream_free(s);
+	return NULL;
+}
+
+__isl_give isl_stream* isl_stream_new_file(struct isl_ctx *ctx, FILE *file)
+{
+	isl_stream *s = isl_stream_new(ctx);
+	if (!s)
+		return NULL;
+	s->file = file;
+	return s;
+}
+
+__isl_give isl_stream* isl_stream_new_str(struct isl_ctx *ctx, const char *str)
+{
+	isl_stream *s;
+	if (!str)
+		return NULL;
+	s = isl_stream_new(ctx);
+	if (!s)
+		return NULL;
+	s->str = str;
+	return s;
+}
+
+/* Read a character from the stream and advance s->line and s->col
+ * to point to the next character.
+ */
+static int stream_getc(__isl_keep isl_stream *s)
+{
+	int c;
+	if (s->eof)
+		return -1;
+	if (s->n_un)
+		return s->c = s->un[--s->n_un];
+	if (s->file)
+		c = fgetc(s->file);
+	else {
+		c = *s->str++;
+		if (c == '\0')
+			c = -1;
+	}
+	if (c == -1)
+		s->eof = 1;
+	else if (c == '\n') {
+		s->line++;
+		s->col = 1;
+	} else
+		s->col++;
+	s->c = c;
+	return c;
+}
+
+static void isl_stream_ungetc(__isl_keep isl_stream *s, int c)
+{
+	isl_assert(s->ctx, s->n_un < 5, return);
+	s->un[s->n_un++] = c;
+	s->c = -1;
+}
+
+/* Read a character from the stream, skipping pairs of '\\' and '\n'.
+ * Set s->start_line and s->start_col to the line and column
+ * of the returned character.
+ */
+static int isl_stream_getc(__isl_keep isl_stream *s)
+{
+	int c;
+
+	do {
+		s->start_line = s->line;
+		s->start_col = s->col;
+		c = stream_getc(s);
+		if (c != '\\')
+			return c;
+		c = stream_getc(s);
+	} while (c == '\n');
+
+	isl_stream_ungetc(s, c);
+
+	return '\\';
+}
+
+static int isl_stream_push_char(__isl_keep isl_stream *s, int c)
+{
+	if (s->len >= s->size) {
+		char *buffer;
+		s->size = (3*s->size)/2;
+		buffer = isl_realloc_array(s->ctx, s->buffer, char, s->size);
+		if (!buffer)
+			return -1;
+		s->buffer = buffer;
+	}
+	s->buffer[s->len++] = c;
+	return 0;
+}
+
+void isl_stream_push_token(__isl_keep isl_stream *s, struct isl_token *tok)
+{
+	isl_assert(s->ctx, s->n_token < 5, return);
+	s->tokens[s->n_token++] = tok;
+}
+
+static enum isl_token_type check_keywords(__isl_keep isl_stream *s)
+{
+	struct isl_hash_table_entry *entry;
+	struct isl_keyword *keyword;
+	uint32_t name_hash;
+
+	if (!strcasecmp(s->buffer, "exists"))
+		return ISL_TOKEN_EXISTS;
+	if (!strcasecmp(s->buffer, "and"))
+		return ISL_TOKEN_AND;
+	if (!strcasecmp(s->buffer, "or"))
+		return ISL_TOKEN_OR;
+	if (!strcasecmp(s->buffer, "implies"))
+		return ISL_TOKEN_IMPLIES;
+	if (!strcasecmp(s->buffer, "not"))
+		return ISL_TOKEN_NOT;
+	if (!strcasecmp(s->buffer, "infty"))
+		return ISL_TOKEN_INFTY;
+	if (!strcasecmp(s->buffer, "infinity"))
+		return ISL_TOKEN_INFTY;
+	if (!strcasecmp(s->buffer, "NaN"))
+		return ISL_TOKEN_NAN;
+	if (!strcasecmp(s->buffer, "min"))
+		return ISL_TOKEN_MIN;
+	if (!strcasecmp(s->buffer, "max"))
+		return ISL_TOKEN_MAX;
+	if (!strcasecmp(s->buffer, "rat"))
+		return ISL_TOKEN_RAT;
+	if (!strcasecmp(s->buffer, "true"))
+		return ISL_TOKEN_TRUE;
+	if (!strcasecmp(s->buffer, "false"))
+		return ISL_TOKEN_FALSE;
+	if (!strcasecmp(s->buffer, "ceild"))
+		return ISL_TOKEN_CEILD;
+	if (!strcasecmp(s->buffer, "floord"))
+		return ISL_TOKEN_FLOORD;
+	if (!strcasecmp(s->buffer, "mod"))
+		return ISL_TOKEN_MOD;
+	if (!strcasecmp(s->buffer, "ceil"))
+		return ISL_TOKEN_CEIL;
+	if (!strcasecmp(s->buffer, "floor"))
+		return ISL_TOKEN_FLOOR;
+
+	if (!s->keywords)
+		return ISL_TOKEN_IDENT;
+
+	name_hash = isl_hash_string(isl_hash_init(), s->buffer);
+	entry = isl_hash_table_find(s->ctx, s->keywords, name_hash, same_name,
+					s->buffer, 0);
+	if (entry) {
+		keyword = entry->data;
+		return keyword->type;
+	}
+
+	return ISL_TOKEN_IDENT;
+}
+
+int isl_stream_skip_line(__isl_keep isl_stream *s)
+{
+	int c;
+
+	while ((c = isl_stream_getc(s)) != -1 && c != '\n')
+		/* nothing */
+		;
+
+	return c == -1 ? -1 : 0;
+}
+
+static struct isl_token *next_token(__isl_keep isl_stream *s, int same_line)
+{
+	int c;
+	struct isl_token *tok = NULL;
+	int line, col;
+	int old_line = s->last_line;
+
+	if (s->n_token) {
+		if (same_line && s->tokens[s->n_token - 1]->on_new_line)
+			return NULL;
+		return s->tokens[--s->n_token];
+	}
+
+	if (same_line && s->c == '\n')
+		return NULL;
+
+	s->len = 0;
+
+	/* skip spaces and comment lines */
+	while ((c = isl_stream_getc(s)) != -1) {
+		if (c == '#') {
+			if (isl_stream_skip_line(s) < 0)
+				break;
+			c = '\n';
+			if (same_line)
+				break;
+		} else if (!isspace(c) || (same_line && c == '\n'))
+			break;
+	}
+
+	line = s->start_line;
+	col = s->start_col;
+
+	if (c == -1 || (same_line && c == '\n'))
+		return NULL;
+	s->last_line = line;
+
+	if (c == '(' ||
+	    c == ')' ||
+	    c == '+' ||
+	    c == '*' ||
+	    c == '%' ||
+	    c == '?' ||
+	    c == '^' ||
+	    c == '@' ||
+	    c == '$' ||
+	    c == ',' ||
+	    c == '.' ||
+	    c == ';' ||
+	    c == '[' ||
+	    c == ']' ||
+	    c == '{' ||
+	    c == '}') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		tok->type = (enum isl_token_type)c;
+		return tok;
+	}
+	if (c == '-') {
+		int c;
+		if ((c = isl_stream_getc(s)) == '>') {
+			tok = isl_token_new(s->ctx, line, col, old_line != line);
+			if (!tok)
+				return NULL;
+			tok->u.s = strdup("->");
+			tok->type = ISL_TOKEN_TO;
+			return tok;
+		}
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		if (!isdigit(c)) {
+			tok = isl_token_new(s->ctx, line, col, old_line != line);
+			if (!tok)
+				return NULL;
+			tok->type = (enum isl_token_type) '-';
+			return tok;
+		}
+	}
+	if (c == '-' || isdigit(c)) {
+		int minus = c == '-';
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		tok->type = ISL_TOKEN_VALUE;
+		isl_int_init(tok->u.v);
+		if (isl_stream_push_char(s, c))
+			goto error;
+		while ((c = isl_stream_getc(s)) != -1 && isdigit(c))
+			if (isl_stream_push_char(s, c))
+				goto error;
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		isl_stream_push_char(s, '\0');
+		isl_int_read(tok->u.v, s->buffer);
+		if (minus && isl_int_is_zero(tok->u.v)) {
+			tok->col++;
+			tok->on_new_line = 0;
+			isl_stream_push_token(s, tok);
+			tok = isl_token_new(s->ctx, line, col, old_line != line);
+			if (!tok)
+				return NULL;
+			tok->type = (enum isl_token_type) '-';
+		}
+		return tok;
+	}
+	if (isalpha(c) || c == '_') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		isl_stream_push_char(s, c);
+		while ((c = isl_stream_getc(s)) != -1 &&
+				(isalnum(c) || c == '_'))
+			isl_stream_push_char(s, c);
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		while ((c = isl_stream_getc(s)) != -1 && c == '\'')
+			isl_stream_push_char(s, c);
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		isl_stream_push_char(s, '\0');
+		tok->type = check_keywords(s);
+		if (tok->type != ISL_TOKEN_IDENT)
+			tok->is_keyword = 1;
+		tok->u.s = strdup(s->buffer);
+		if (!tok->u.s)
+			goto error;
+		return tok;
+	}
+	if (c == '"') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		tok->type = ISL_TOKEN_STRING;
+		tok->u.s = NULL;
+		while ((c = isl_stream_getc(s)) != -1 && c != '"' && c != '\n')
+			isl_stream_push_char(s, c);
+		if (c != '"') {
+			isl_stream_error(s, NULL, "unterminated string");
+			goto error;
+		}
+		isl_stream_push_char(s, '\0');
+		tok->u.s = strdup(s->buffer);
+		return tok;
+	}
+	if (c == '=') {
+		int c;
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) == '=') {
+			tok->u.s = strdup("==");
+			tok->type = ISL_TOKEN_EQ_EQ;
+			return tok;
+		}
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		tok->type = (enum isl_token_type) '=';
+		return tok;
+	}
+	if (c == ':') {
+		int c;
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) == '=') {
+			tok->u.s = strdup(":=");
+			tok->type = ISL_TOKEN_DEF;
+			return tok;
+		}
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		tok->type = (enum isl_token_type) ':';
+		return tok;
+	}
+	if (c == '>') {
+		int c;
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) == '=') {
+			tok->u.s = strdup(">=");
+			tok->type = ISL_TOKEN_GE;
+			return tok;
+		} else if (c == '>') {
+			if ((c = isl_stream_getc(s)) == '=') {
+				tok->u.s = strdup(">>=");
+				tok->type = ISL_TOKEN_LEX_GE;
+				return tok;
+			}
+			tok->u.s = strdup(">>");
+			tok->type = ISL_TOKEN_LEX_GT;
+		} else {
+			tok->u.s = strdup(">");
+			tok->type = ISL_TOKEN_GT;
+		}
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		return tok;
+	}
+	if (c == '<') {
+		int c;
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) == '=') {
+			tok->u.s = strdup("<=");
+			tok->type = ISL_TOKEN_LE;
+			return tok;
+		} else if (c == '<') {
+			if ((c = isl_stream_getc(s)) == '=') {
+				tok->u.s = strdup("<<=");
+				tok->type = ISL_TOKEN_LEX_LE;
+				return tok;
+			}
+			tok->u.s = strdup("<<");
+			tok->type = ISL_TOKEN_LEX_LT;
+		} else {
+			tok->u.s = strdup("<");
+			tok->type = ISL_TOKEN_LT;
+		}
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		return tok;
+	}
+	if (c == '&') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		tok->type = ISL_TOKEN_AND;
+		if ((c = isl_stream_getc(s)) != '&' && c != -1) {
+			tok->u.s = strdup("&");
+			isl_stream_ungetc(s, c);
+		} else
+			tok->u.s = strdup("&&");
+		return tok;
+	}
+	if (c == '|') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		tok->type = ISL_TOKEN_OR;
+		if ((c = isl_stream_getc(s)) != '|' && c != -1) {
+			tok->u.s = strdup("|");
+			isl_stream_ungetc(s, c);
+		} else
+			tok->u.s = strdup("||");
+		return tok;
+	}
+	if (c == '/') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) != '\\' && c != -1) {
+			tok->type = (enum isl_token_type) '/';
+			isl_stream_ungetc(s, c);
+		} else {
+			tok->u.s = strdup("/\\");
+			tok->type = ISL_TOKEN_AND;
+		}
+		return tok;
+	}
+	if (c == '\\') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) != '/' && c != -1) {
+			tok->type = (enum isl_token_type) '\\';
+			isl_stream_ungetc(s, c);
+		} else {
+			tok->u.s = strdup("\\/");
+			tok->type = ISL_TOKEN_OR;
+		}
+		return tok;
+	}
+	if (c == '!') {
+		tok = isl_token_new(s->ctx, line, col, old_line != line);
+		if (!tok)
+			return NULL;
+		if ((c = isl_stream_getc(s)) == '=') {
+			tok->u.s = strdup("!=");
+			tok->type = ISL_TOKEN_NE;
+			return tok;
+		} else {
+			tok->type = ISL_TOKEN_NOT;
+			tok->u.s = strdup("!");
+		}
+		if (c != -1)
+			isl_stream_ungetc(s, c);
+		return tok;
+	}
+
+	tok = isl_token_new(s->ctx, line, col, old_line != line);
+	if (!tok)
+		return NULL;
+	tok->type = ISL_TOKEN_UNKNOWN;
+	return tok;
+error:
+	isl_token_free(tok);
+	return NULL;
+}
+
+struct isl_token *isl_stream_next_token(__isl_keep isl_stream *s)
+{
+	return next_token(s, 0);
+}
+
+struct isl_token *isl_stream_next_token_on_same_line(__isl_keep isl_stream *s)
+{
+	return next_token(s, 1);
+}
+
+int isl_stream_eat_if_available(__isl_keep isl_stream *s, int type)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	if (tok->type == type) {
+		isl_token_free(tok);
+		return 1;
+	}
+	isl_stream_push_token(s, tok);
+	return 0;
+}
+
+int isl_stream_next_token_is(__isl_keep isl_stream *s, int type)
+{
+	struct isl_token *tok;
+	int r;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return 0;
+	r = tok->type == type;
+	isl_stream_push_token(s, tok);
+	return r;
+}
+
+char *isl_stream_read_ident_if_available(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return NULL;
+	if (tok->type == ISL_TOKEN_IDENT) {
+		char *ident = strdup(tok->u.s);
+		isl_token_free(tok);
+		return ident;
+	}
+	isl_stream_push_token(s, tok);
+	return NULL;
+}
+
+int isl_stream_eat(__isl_keep isl_stream *s, int type)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return -1;
+	if (tok->type == type) {
+		isl_token_free(tok);
+		return 0;
+	}
+	isl_stream_error(s, tok, "expecting other token");
+	isl_stream_push_token(s, tok);
+	return -1;
+}
+
+int isl_stream_is_empty(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+
+	tok = isl_stream_next_token(s);
+
+	if (!tok)
+		return 1;
+
+	isl_stream_push_token(s, tok);
+	return 0;
+}
+
+static isl_stat free_keyword(void **p, void *user)
+{
+	struct isl_keyword *keyword = *p;
+
+	free(keyword->name);
+	free(keyword);
+
+	return isl_stat_ok;
+}
+
+void isl_stream_flush_tokens(__isl_keep isl_stream *s)
+{
+	int i;
+
+	if (!s)
+		return;
+	for (i = 0; i < s->n_token; ++i)
+		isl_token_free(s->tokens[i]);
+	s->n_token = 0;
+}
+
+isl_ctx *isl_stream_get_ctx(__isl_keep isl_stream *s)
+{
+	return s ? s->ctx : NULL;
+}
+
+void isl_stream_free(__isl_take isl_stream *s)
+{
+	if (!s)
+		return;
+	free(s->buffer);
+	if (s->n_token != 0) {
+		struct isl_token *tok = isl_stream_next_token(s);
+		isl_stream_error(s, tok, "unexpected token");
+		isl_token_free(tok);
+	}
+	if (s->keywords) {
+		isl_hash_table_foreach(s->ctx, s->keywords, &free_keyword, NULL);
+		isl_hash_table_free(s->ctx, s->keywords);
+	}
+	free(s->yaml_state);
+	free(s->yaml_indent);
+	isl_ctx_deref(s->ctx);
+	free(s);
+}
+
+/* Push "state" onto the stack of currently active YAML elements.
+ * The caller is responsible for setting the corresponding indentation.
+ * Return 0 on success and -1 on failure.
+ */
+static int push_state(__isl_keep isl_stream *s, enum isl_yaml_state state)
+{
+	if (s->yaml_size < s->yaml_depth + 1) {
+		int *indent;
+		enum isl_yaml_state *state;
+
+		state = isl_realloc_array(s->ctx, s->yaml_state,
+					enum isl_yaml_state, s->yaml_depth + 1);
+		if (!state)
+			return -1;
+		s->yaml_state = state;
+
+		indent = isl_realloc_array(s->ctx, s->yaml_indent,
+					int, s->yaml_depth + 1);
+		if (!indent)
+			return -1;
+		s->yaml_indent = indent;
+
+		s->yaml_size = s->yaml_depth + 1;
+	}
+
+	s->yaml_state[s->yaml_depth] = state;
+	s->yaml_depth++;
+
+	return 0;
+}
+
+/* Remove the innermost active YAML element from the stack.
+ * Return 0 on success and -1 on failure.
+ */
+static int pop_state(__isl_keep isl_stream *s)
+{
+	if (!s)
+		return -1;
+	if (s->yaml_depth < 1)
+		isl_die(isl_stream_get_ctx(s), isl_error_invalid,
+			"not in YAML construct", return -1);
+
+	s->yaml_depth--;
+
+	return 0;
+}
+
+/* Set the state of the innermost active YAML element to "state".
+ * Return 0 on success and -1 on failure.
+ */
+static int update_state(__isl_keep isl_stream *s, enum isl_yaml_state state)
+{
+	if (!s)
+		return -1;
+	if (s->yaml_depth < 1)
+		isl_die(isl_stream_get_ctx(s), isl_error_invalid,
+			"not in YAML construct", return -1);
+
+	s->yaml_state[s->yaml_depth - 1] = state;
+
+	return 0;
+}
+
+/* Return the state of the innermost active YAML element.
+ * Return isl_yaml_none if we are not inside any YAML element.
+ */
+static enum isl_yaml_state current_state(__isl_keep isl_stream *s)
+{
+	if (!s)
+		return isl_yaml_none;
+	if (s->yaml_depth < 1)
+		return isl_yaml_none;
+	return s->yaml_state[s->yaml_depth - 1];
+}
+
+/* Set the indentation of the innermost active YAML element to "indent".
+ * If "indent" is equal to ISL_YAML_INDENT_FLOW, then this means
+ * that the current elemient is in flow format.
+ */
+static int set_yaml_indent(__isl_keep isl_stream *s, int indent)
+{
+	if (s->yaml_depth < 1)
+		isl_die(s->ctx, isl_error_internal,
+			"not in YAML element", return -1);
+
+	s->yaml_indent[s->yaml_depth - 1] = indent;
+
+	return 0;
+}
+
+/* Return the indentation of the innermost active YAML element
+ * of -1 on error.
+ */
+static int get_yaml_indent(__isl_keep isl_stream *s)
+{
+	if (s->yaml_depth < 1)
+		isl_die(s->ctx, isl_error_internal,
+			"not in YAML element", return -1);
+
+	return s->yaml_indent[s->yaml_depth - 1];
+}
+
+/* Move to the next state at the innermost level.
+ * Return 1 if successful.
+ * Return 0 if we are at the end of the innermost level.
+ * Return -1 on error.
+ *
+ * If we are in state isl_yaml_mapping_key_start, then we have just
+ * started a mapping and we are expecting a key.  If the mapping started
+ * with a '{', then we check if the next token is a '}'.  If so,
+ * then the mapping is empty and there is no next state at this level.
+ * Otherwise, we assume that there is at least one key (the one from
+ * which we derived the indentation in isl_stream_yaml_read_start_mapping.
+ *
+ * If we are in state isl_yaml_mapping_key, then the we expect a colon
+ * followed by a value, so there is always a next state unless
+ * some error occurs.
+ *
+ * If we are in state isl_yaml_mapping_val, then there may or may
+ * not be a subsequent key in the same mapping.
+ * In flow format, the next key is preceded by a comma.
+ * In block format, the next key has the same indentation as the first key.
+ * If the first token has a smaller indentation, then we have reached
+ * the end of the current mapping.
+ *
+ * If we are in state isl_yaml_sequence_start, then we have just
+ * started a sequence.  If the sequence started with a '[',
+ * then we check if the next token is a ']'.  If so, then the sequence
+ * is empty and there is no next state at this level.
+ * Otherwise, we assume that there is at least one element in the sequence
+ * (the one from which we derived the indentation in
+ * isl_stream_yaml_read_start_sequence.
+ *
+ * If we are in state isl_yaml_sequence, then there may or may
+ * not be a subsequent element in the same sequence.
+ * In flow format, the next element is preceded by a comma.
+ * In block format, the next element is introduced by a dash with
+ * the same indentation as that of the first element.
+ * If the first token is not a dash or if it has a smaller indentation,
+ * then we have reached the end of the current sequence.
+ */
+int isl_stream_yaml_next(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+	enum isl_yaml_state state;
+	int indent;
+
+	state = current_state(s);
+	if (state == isl_yaml_none)
+		isl_die(s->ctx, isl_error_invalid,
+			"not in YAML element", return -1);
+	switch (state) {
+	case isl_yaml_mapping_key_start:
+		if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW &&
+		    isl_stream_next_token_is(s, '}'))
+			return 0;
+		if (update_state(s, isl_yaml_mapping_key) < 0)
+			return -1;
+		return 1;
+	case isl_yaml_mapping_key:
+		tok = isl_stream_next_token(s);
+		if (!tok) {
+			if (s->eof)
+				isl_stream_error(s, NULL, "unexpected EOF");
+			return -1;
+		}
+		if (tok->type == ':') {
+			isl_token_free(tok);
+			if (update_state(s, isl_yaml_mapping_val) < 0)
+				return -1;
+			return 1;
+		}
+		isl_stream_error(s, tok, "expecting ':'");
+		isl_stream_push_token(s, tok);
+		return -1;
+	case isl_yaml_mapping_val:
+		if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) {
+			if (!isl_stream_eat_if_available(s, ','))
+				return 0;
+			if (update_state(s, isl_yaml_mapping_key) < 0)
+				return -1;
+			return 1;
+		}
+		tok = isl_stream_next_token(s);
+		if (!tok)
+			return 0;
+		indent = tok->col - 1;
+		isl_stream_push_token(s, tok);
+		if (indent < get_yaml_indent(s))
+			return 0;
+		if (update_state(s, isl_yaml_mapping_key) < 0)
+			return -1;
+		return 1;
+	case isl_yaml_sequence_start:
+		if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) {
+			if (isl_stream_next_token_is(s, ']'))
+				return 0;
+			if (update_state(s, isl_yaml_sequence) < 0)
+				return -1;
+			return 1;
+		}
+		tok = isl_stream_next_token(s);
+		if (!tok) {
+			if (s->eof)
+				isl_stream_error(s, NULL, "unexpected EOF");
+			return -1;
+		}
+		if (tok->type == '-') {
+			isl_token_free(tok);
+			if (update_state(s, isl_yaml_sequence) < 0)
+				return -1;
+			return 1;
+		}
+		isl_stream_error(s, tok, "expecting '-'");
+		isl_stream_push_token(s, tok);
+		return 0;
+	case isl_yaml_sequence:
+		if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW)
+			return isl_stream_eat_if_available(s, ',');
+		tok = isl_stream_next_token(s);
+		if (!tok)
+			return 0;
+		indent = tok->col - 1;
+		if (indent < get_yaml_indent(s) || tok->type != '-') {
+			isl_stream_push_token(s, tok);
+			return 0;
+		}
+		isl_token_free(tok);
+		return 1;
+	default:
+		isl_die(s->ctx, isl_error_internal,
+			"unexpected state", return 0);
+	}
+}
+
+/* Start reading a YAML mapping.
+ * Return 0 on success and -1 on error.
+ *
+ * If the first token on the stream is a '{' then we remove this token
+ * from the stream and keep track of the fact that the mapping
+ * is given in flow format.
+ * Otherwise, we assume the first token is the first key of the mapping and
+ * keep track of its indentation, but keep the token on the stream.
+ * In both cases, the next token we expect is the first key of the mapping.
+ */
+int isl_stream_yaml_read_start_mapping(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+	int indent;
+
+	if (push_state(s, isl_yaml_mapping_key_start) < 0)
+		return -1;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		if (s->eof)
+			isl_stream_error(s, NULL, "unexpected EOF");
+		return -1;
+	}
+	if (isl_token_get_type(tok) == '{') {
+		isl_token_free(tok);
+		return set_yaml_indent(s, ISL_YAML_INDENT_FLOW);
+	}
+	indent = tok->col - 1;
+	isl_stream_push_token(s, tok);
+
+	return set_yaml_indent(s, indent);
+}
+
+/* Finish reading a YAML mapping.
+ * Return 0 on success and -1 on error.
+ *
+ * If the mapping started with a '{', then we expect a '}' to close
+ * the mapping.
+ * Otherwise, we double-check that the next token (if any)
+ * has a smaller indentation than that of the current mapping.
+ */
+int isl_stream_yaml_read_end_mapping(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+	int indent;
+
+	if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) {
+		if (isl_stream_eat(s, '}') < 0)
+			return -1;
+		return pop_state(s);
+	}
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return pop_state(s);
+
+	indent = tok->col - 1;
+	isl_stream_push_token(s, tok);
+
+	if (indent >= get_yaml_indent(s))
+		isl_die(isl_stream_get_ctx(s), isl_error_invalid,
+			"mapping not finished", return -1);
+
+	return pop_state(s);
+}
+
+/* Start reading a YAML sequence.
+ * Return 0 on success and -1 on error.
+ *
+ * If the first token on the stream is a '[' then we remove this token
+ * from the stream and keep track of the fact that the sequence
+ * is given in flow format.
+ * Otherwise, we assume the first token is the dash that introduces
+ * the first element of the sequence and keep track of its indentation,
+ * but keep the token on the stream.
+ * In both cases, the next token we expect is the first element
+ * of the sequence.
+ */
+int isl_stream_yaml_read_start_sequence(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+	int indent;
+
+	if (push_state(s, isl_yaml_sequence_start) < 0)
+		return -1;
+
+	tok = isl_stream_next_token(s);
+	if (!tok) {
+		if (s->eof)
+			isl_stream_error(s, NULL, "unexpected EOF");
+		return -1;
+	}
+	if (isl_token_get_type(tok) == '[') {
+		isl_token_free(tok);
+		return set_yaml_indent(s, ISL_YAML_INDENT_FLOW);
+	}
+	indent = tok->col - 1;
+	isl_stream_push_token(s, tok);
+
+	return set_yaml_indent(s, indent);
+}
+
+/* Finish reading a YAML sequence.
+ * Return 0 on success and -1 on error.
+ *
+ * If the sequence started with a '[', then we expect a ']' to close
+ * the sequence.
+ * Otherwise, we double-check that the next token (if any)
+ * is not a dash or that it has a smaller indentation than
+ * that of the current sequence.
+ */
+int isl_stream_yaml_read_end_sequence(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+	int indent;
+	int dash;
+
+	if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) {
+		if (isl_stream_eat(s, ']') < 0)
+			return -1;
+		return pop_state(s);
+	}
+
+	tok = isl_stream_next_token(s);
+	if (!tok)
+		return pop_state(s);
+
+	indent = tok->col - 1;
+	dash = tok->type == '-';
+	isl_stream_push_token(s, tok);
+
+	if (indent >= get_yaml_indent(s) && dash)
+		isl_die(isl_stream_get_ctx(s), isl_error_invalid,
+			"sequence not finished", return -1);
+
+	return pop_state(s);
+}
diff --git a/final/lib/External/isl/isl_stream_private.h b/final/lib/External/isl/isl_stream_private.h
new file mode 100644
index 0000000..b199ec6
--- /dev/null
+++ b/final/lib/External/isl/isl_stream_private.h
@@ -0,0 +1,69 @@
+#include <isl_int.h>
+#include <isl/stream.h>
+#include <isl_yaml.h>
+
+struct isl_token {
+	int type;
+
+	unsigned int on_new_line : 1;
+	unsigned is_keyword : 1;
+	int line;
+	int col;
+
+	union {
+		isl_int	v;
+		char	*s;
+		isl_map *map;
+		isl_pw_aff *pwaff;
+	} u;
+};
+
+struct isl_token *isl_token_new(isl_ctx *ctx,
+	int line, int col, unsigned on_new_line);
+
+/* An input stream that may be either a file or a string.
+ *
+ * line and col are the line and column number of the next character (1-based).
+ * start_line and start_col are set by isl_stream_getc to point
+ * to the position of the returned character.
+ * last_line is the line number of the previous token.
+ *
+ * yaml_state and yaml_indent keep track of the currently active YAML
+ * elements.  yaml_size is the size of these arrays, while yaml_depth
+ * is the number of elements currently in use.
+ * yaml_state and yaml_indent may be NULL if no YAML parsing is being
+ * performed.
+ * yaml_state keeps track of what is expected next at each level.
+ * yaml_indent keeps track of the indentation at each level, with
+ * ISL_YAML_INDENT_FLOW meaning that the element is in flow format
+ * (such that the indentation is not relevant).
+ */
+struct isl_stream {
+	struct isl_ctx	*ctx;
+	FILE        	*file;
+	const char  	*str;
+	int	    	line;
+	int	    	col;
+	int		start_line;
+	int		start_col;
+	int		last_line;
+	int	    	eof;
+
+	char	    	*buffer;
+	size_t	    	size;
+	size_t	    	len;
+	int	    	c;
+	int		un[5];
+	int		n_un;
+
+	struct isl_token	*tokens[5];
+	int	    	n_token;
+
+	struct isl_hash_table	*keywords;
+	enum isl_token_type	 next_type;
+
+	int			yaml_depth;
+	int			yaml_size;
+	enum isl_yaml_state	*yaml_state;
+	int			*yaml_indent;
+};
diff --git a/final/lib/External/isl/isl_tab.c b/final/lib/External/isl/isl_tab.c
new file mode 100644
index 0000000..fd184c5
--- /dev/null
+++ b/final/lib/External/isl/isl_tab.c
@@ -0,0 +1,4130 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2013      Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ * Copyright 2016      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include "isl_map_private.h"
+#include "isl_tab.h"
+#include <isl_seq.h>
+#include <isl_config.h>
+
+#include <bset_to_bmap.c>
+#include <bset_from_bmap.c>
+
+/*
+ * The implementation of tableaus in this file was inspired by Section 8
+ * of David Detlefs, Greg Nelson and James B. Saxe, "Simplify: a theorem
+ * prover for program checking".
+ */
+
+struct isl_tab *isl_tab_alloc(struct isl_ctx *ctx,
+	unsigned n_row, unsigned n_var, unsigned M)
+{
+	int i;
+	struct isl_tab *tab;
+	unsigned off = 2 + M;
+
+	tab = isl_calloc_type(ctx, struct isl_tab);
+	if (!tab)
+		return NULL;
+	tab->mat = isl_mat_alloc(ctx, n_row, off + n_var);
+	if (!tab->mat)
+		goto error;
+	tab->var = isl_alloc_array(ctx, struct isl_tab_var, n_var);
+	if (n_var && !tab->var)
+		goto error;
+	tab->con = isl_alloc_array(ctx, struct isl_tab_var, n_row);
+	if (n_row && !tab->con)
+		goto error;
+	tab->col_var = isl_alloc_array(ctx, int, n_var);
+	if (n_var && !tab->col_var)
+		goto error;
+	tab->row_var = isl_alloc_array(ctx, int, n_row);
+	if (n_row && !tab->row_var)
+		goto error;
+	for (i = 0; i < n_var; ++i) {
+		tab->var[i].index = i;
+		tab->var[i].is_row = 0;
+		tab->var[i].is_nonneg = 0;
+		tab->var[i].is_zero = 0;
+		tab->var[i].is_redundant = 0;
+		tab->var[i].frozen = 0;
+		tab->var[i].negated = 0;
+		tab->col_var[i] = i;
+	}
+	tab->n_row = 0;
+	tab->n_con = 0;
+	tab->n_eq = 0;
+	tab->max_con = n_row;
+	tab->n_col = n_var;
+	tab->n_var = n_var;
+	tab->max_var = n_var;
+	tab->n_param = 0;
+	tab->n_div = 0;
+	tab->n_dead = 0;
+	tab->n_redundant = 0;
+	tab->strict_redundant = 0;
+	tab->need_undo = 0;
+	tab->rational = 0;
+	tab->empty = 0;
+	tab->in_undo = 0;
+	tab->M = M;
+	tab->cone = 0;
+	tab->bottom.type = isl_tab_undo_bottom;
+	tab->bottom.next = NULL;
+	tab->top = &tab->bottom;
+
+	tab->n_zero = 0;
+	tab->n_unbounded = 0;
+	tab->basis = NULL;
+
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+isl_ctx *isl_tab_get_ctx(struct isl_tab *tab)
+{
+	return tab ? isl_mat_get_ctx(tab->mat) : NULL;
+}
+
+int isl_tab_extend_cons(struct isl_tab *tab, unsigned n_new)
+{
+	unsigned off;
+
+	if (!tab)
+		return -1;
+
+	off = 2 + tab->M;
+
+	if (tab->max_con < tab->n_con + n_new) {
+		struct isl_tab_var *con;
+
+		con = isl_realloc_array(tab->mat->ctx, tab->con,
+				    struct isl_tab_var, tab->max_con + n_new);
+		if (!con)
+			return -1;
+		tab->con = con;
+		tab->max_con += n_new;
+	}
+	if (tab->mat->n_row < tab->n_row + n_new) {
+		int *row_var;
+
+		tab->mat = isl_mat_extend(tab->mat,
+					tab->n_row + n_new, off + tab->n_col);
+		if (!tab->mat)
+			return -1;
+		row_var = isl_realloc_array(tab->mat->ctx, tab->row_var,
+					    int, tab->mat->n_row);
+		if (!row_var)
+			return -1;
+		tab->row_var = row_var;
+		if (tab->row_sign) {
+			enum isl_tab_row_sign *s;
+			s = isl_realloc_array(tab->mat->ctx, tab->row_sign,
+					enum isl_tab_row_sign, tab->mat->n_row);
+			if (!s)
+				return -1;
+			tab->row_sign = s;
+		}
+	}
+	return 0;
+}
+
+/* Make room for at least n_new extra variables.
+ * Return -1 if anything went wrong.
+ */
+int isl_tab_extend_vars(struct isl_tab *tab, unsigned n_new)
+{
+	struct isl_tab_var *var;
+	unsigned off = 2 + tab->M;
+
+	if (tab->max_var < tab->n_var + n_new) {
+		var = isl_realloc_array(tab->mat->ctx, tab->var,
+				    struct isl_tab_var, tab->n_var + n_new);
+		if (!var)
+			return -1;
+		tab->var = var;
+		tab->max_var = tab->n_var + n_new;
+	}
+
+	if (tab->mat->n_col < off + tab->n_col + n_new) {
+		int *p;
+
+		tab->mat = isl_mat_extend(tab->mat,
+				    tab->mat->n_row, off + tab->n_col + n_new);
+		if (!tab->mat)
+			return -1;
+		p = isl_realloc_array(tab->mat->ctx, tab->col_var,
+					    int, tab->n_col + n_new);
+		if (!p)
+			return -1;
+		tab->col_var = p;
+	}
+
+	return 0;
+}
+
+static void free_undo_record(struct isl_tab_undo *undo)
+{
+	switch (undo->type) {
+	case isl_tab_undo_saved_basis:
+		free(undo->u.col_var);
+		break;
+	default:;
+	}
+	free(undo);
+}
+
+static void free_undo(struct isl_tab *tab)
+{
+	struct isl_tab_undo *undo, *next;
+
+	for (undo = tab->top; undo && undo != &tab->bottom; undo = next) {
+		next = undo->next;
+		free_undo_record(undo);
+	}
+	tab->top = undo;
+}
+
+void isl_tab_free(struct isl_tab *tab)
+{
+	if (!tab)
+		return;
+	free_undo(tab);
+	isl_mat_free(tab->mat);
+	isl_vec_free(tab->dual);
+	isl_basic_map_free(tab->bmap);
+	free(tab->var);
+	free(tab->con);
+	free(tab->row_var);
+	free(tab->col_var);
+	free(tab->row_sign);
+	isl_mat_free(tab->samples);
+	free(tab->sample_index);
+	isl_mat_free(tab->basis);
+	free(tab);
+}
+
+struct isl_tab *isl_tab_dup(struct isl_tab *tab)
+{
+	int i;
+	struct isl_tab *dup;
+	unsigned off;
+
+	if (!tab)
+		return NULL;
+
+	off = 2 + tab->M;
+	dup = isl_calloc_type(tab->mat->ctx, struct isl_tab);
+	if (!dup)
+		return NULL;
+	dup->mat = isl_mat_dup(tab->mat);
+	if (!dup->mat)
+		goto error;
+	dup->var = isl_alloc_array(tab->mat->ctx, struct isl_tab_var, tab->max_var);
+	if (tab->max_var && !dup->var)
+		goto error;
+	for (i = 0; i < tab->n_var; ++i)
+		dup->var[i] = tab->var[i];
+	dup->con = isl_alloc_array(tab->mat->ctx, struct isl_tab_var, tab->max_con);
+	if (tab->max_con && !dup->con)
+		goto error;
+	for (i = 0; i < tab->n_con; ++i)
+		dup->con[i] = tab->con[i];
+	dup->col_var = isl_alloc_array(tab->mat->ctx, int, tab->mat->n_col - off);
+	if ((tab->mat->n_col - off) && !dup->col_var)
+		goto error;
+	for (i = 0; i < tab->n_col; ++i)
+		dup->col_var[i] = tab->col_var[i];
+	dup->row_var = isl_alloc_array(tab->mat->ctx, int, tab->mat->n_row);
+	if (tab->mat->n_row && !dup->row_var)
+		goto error;
+	for (i = 0; i < tab->n_row; ++i)
+		dup->row_var[i] = tab->row_var[i];
+	if (tab->row_sign) {
+		dup->row_sign = isl_alloc_array(tab->mat->ctx, enum isl_tab_row_sign,
+						tab->mat->n_row);
+		if (tab->mat->n_row && !dup->row_sign)
+			goto error;
+		for (i = 0; i < tab->n_row; ++i)
+			dup->row_sign[i] = tab->row_sign[i];
+	}
+	if (tab->samples) {
+		dup->samples = isl_mat_dup(tab->samples);
+		if (!dup->samples)
+			goto error;
+		dup->sample_index = isl_alloc_array(tab->mat->ctx, int,
+							tab->samples->n_row);
+		if (tab->samples->n_row && !dup->sample_index)
+			goto error;
+		dup->n_sample = tab->n_sample;
+		dup->n_outside = tab->n_outside;
+	}
+	dup->n_row = tab->n_row;
+	dup->n_con = tab->n_con;
+	dup->n_eq = tab->n_eq;
+	dup->max_con = tab->max_con;
+	dup->n_col = tab->n_col;
+	dup->n_var = tab->n_var;
+	dup->max_var = tab->max_var;
+	dup->n_param = tab->n_param;
+	dup->n_div = tab->n_div;
+	dup->n_dead = tab->n_dead;
+	dup->n_redundant = tab->n_redundant;
+	dup->rational = tab->rational;
+	dup->empty = tab->empty;
+	dup->strict_redundant = 0;
+	dup->need_undo = 0;
+	dup->in_undo = 0;
+	dup->M = tab->M;
+	tab->cone = tab->cone;
+	dup->bottom.type = isl_tab_undo_bottom;
+	dup->bottom.next = NULL;
+	dup->top = &dup->bottom;
+
+	dup->n_zero = tab->n_zero;
+	dup->n_unbounded = tab->n_unbounded;
+	dup->basis = isl_mat_dup(tab->basis);
+
+	return dup;
+error:
+	isl_tab_free(dup);
+	return NULL;
+}
+
+/* Construct the coefficient matrix of the product tableau
+ * of two tableaus.
+ * mat{1,2} is the coefficient matrix of tableau {1,2}
+ * row{1,2} is the number of rows in tableau {1,2}
+ * col{1,2} is the number of columns in tableau {1,2}
+ * off is the offset to the coefficient column (skipping the
+ *	denominator, the constant term and the big parameter if any)
+ * r{1,2} is the number of redundant rows in tableau {1,2}
+ * d{1,2} is the number of dead columns in tableau {1,2}
+ *
+ * The order of the rows and columns in the result is as explained
+ * in isl_tab_product.
+ */
+static struct isl_mat *tab_mat_product(struct isl_mat *mat1,
+	struct isl_mat *mat2, unsigned row1, unsigned row2,
+	unsigned col1, unsigned col2,
+	unsigned off, unsigned r1, unsigned r2, unsigned d1, unsigned d2)
+{
+	int i;
+	struct isl_mat *prod;
+	unsigned n;
+
+	prod = isl_mat_alloc(mat1->ctx, mat1->n_row + mat2->n_row,
+					off + col1 + col2);
+	if (!prod)
+		return NULL;
+
+	n = 0;
+	for (i = 0; i < r1; ++i) {
+		isl_seq_cpy(prod->row[n + i], mat1->row[i], off + d1);
+		isl_seq_clr(prod->row[n + i] + off + d1, d2);
+		isl_seq_cpy(prod->row[n + i] + off + d1 + d2,
+				mat1->row[i] + off + d1, col1 - d1);
+		isl_seq_clr(prod->row[n + i] + off + col1 + d1, col2 - d2);
+	}
+
+	n += r1;
+	for (i = 0; i < r2; ++i) {
+		isl_seq_cpy(prod->row[n + i], mat2->row[i], off);
+		isl_seq_clr(prod->row[n + i] + off, d1);
+		isl_seq_cpy(prod->row[n + i] + off + d1,
+			    mat2->row[i] + off, d2);
+		isl_seq_clr(prod->row[n + i] + off + d1 + d2, col1 - d1);
+		isl_seq_cpy(prod->row[n + i] + off + col1 + d1,
+			    mat2->row[i] + off + d2, col2 - d2);
+	}
+
+	n += r2;
+	for (i = 0; i < row1 - r1; ++i) {
+		isl_seq_cpy(prod->row[n + i], mat1->row[r1 + i], off + d1);
+		isl_seq_clr(prod->row[n + i] + off + d1, d2);
+		isl_seq_cpy(prod->row[n + i] + off + d1 + d2,
+				mat1->row[r1 + i] + off + d1, col1 - d1);
+		isl_seq_clr(prod->row[n + i] + off + col1 + d1, col2 - d2);
+	}
+
+	n += row1 - r1;
+	for (i = 0; i < row2 - r2; ++i) {
+		isl_seq_cpy(prod->row[n + i], mat2->row[r2 + i], off);
+		isl_seq_clr(prod->row[n + i] + off, d1);
+		isl_seq_cpy(prod->row[n + i] + off + d1,
+			    mat2->row[r2 + i] + off, d2);
+		isl_seq_clr(prod->row[n + i] + off + d1 + d2, col1 - d1);
+		isl_seq_cpy(prod->row[n + i] + off + col1 + d1,
+			    mat2->row[r2 + i] + off + d2, col2 - d2);
+	}
+
+	return prod;
+}
+
+/* Update the row or column index of a variable that corresponds
+ * to a variable in the first input tableau.
+ */
+static void update_index1(struct isl_tab_var *var,
+	unsigned r1, unsigned r2, unsigned d1, unsigned d2)
+{
+	if (var->index == -1)
+		return;
+	if (var->is_row && var->index >= r1)
+		var->index += r2;
+	if (!var->is_row && var->index >= d1)
+		var->index += d2;
+}
+
+/* Update the row or column index of a variable that corresponds
+ * to a variable in the second input tableau.
+ */
+static void update_index2(struct isl_tab_var *var,
+	unsigned row1, unsigned col1,
+	unsigned r1, unsigned r2, unsigned d1, unsigned d2)
+{
+	if (var->index == -1)
+		return;
+	if (var->is_row) {
+		if (var->index < r2)
+			var->index += r1;
+		else
+			var->index += row1;
+	} else {
+		if (var->index < d2)
+			var->index += d1;
+		else
+			var->index += col1;
+	}
+}
+
+/* Create a tableau that represents the Cartesian product of the sets
+ * represented by tableaus tab1 and tab2.
+ * The order of the rows in the product is
+ *	- redundant rows of tab1
+ *	- redundant rows of tab2
+ *	- non-redundant rows of tab1
+ *	- non-redundant rows of tab2
+ * The order of the columns is
+ *	- denominator
+ *	- constant term
+ *	- coefficient of big parameter, if any
+ *	- dead columns of tab1
+ *	- dead columns of tab2
+ *	- live columns of tab1
+ *	- live columns of tab2
+ * The order of the variables and the constraints is a concatenation
+ * of order in the two input tableaus.
+ */
+struct isl_tab *isl_tab_product(struct isl_tab *tab1, struct isl_tab *tab2)
+{
+	int i;
+	struct isl_tab *prod;
+	unsigned off;
+	unsigned r1, r2, d1, d2;
+
+	if (!tab1 || !tab2)
+		return NULL;
+
+	isl_assert(tab1->mat->ctx, tab1->M == tab2->M, return NULL);
+	isl_assert(tab1->mat->ctx, tab1->rational == tab2->rational, return NULL);
+	isl_assert(tab1->mat->ctx, tab1->cone == tab2->cone, return NULL);
+	isl_assert(tab1->mat->ctx, !tab1->row_sign, return NULL);
+	isl_assert(tab1->mat->ctx, !tab2->row_sign, return NULL);
+	isl_assert(tab1->mat->ctx, tab1->n_param == 0, return NULL);
+	isl_assert(tab1->mat->ctx, tab2->n_param == 0, return NULL);
+	isl_assert(tab1->mat->ctx, tab1->n_div == 0, return NULL);
+	isl_assert(tab1->mat->ctx, tab2->n_div == 0, return NULL);
+
+	off = 2 + tab1->M;
+	r1 = tab1->n_redundant;
+	r2 = tab2->n_redundant;
+	d1 = tab1->n_dead;
+	d2 = tab2->n_dead;
+	prod = isl_calloc_type(tab1->mat->ctx, struct isl_tab);
+	if (!prod)
+		return NULL;
+	prod->mat = tab_mat_product(tab1->mat, tab2->mat,
+				tab1->n_row, tab2->n_row,
+				tab1->n_col, tab2->n_col, off, r1, r2, d1, d2);
+	if (!prod->mat)
+		goto error;
+	prod->var = isl_alloc_array(tab1->mat->ctx, struct isl_tab_var,
+					tab1->max_var + tab2->max_var);
+	if ((tab1->max_var + tab2->max_var) && !prod->var)
+		goto error;
+	for (i = 0; i < tab1->n_var; ++i) {
+		prod->var[i] = tab1->var[i];
+		update_index1(&prod->var[i], r1, r2, d1, d2);
+	}
+	for (i = 0; i < tab2->n_var; ++i) {
+		prod->var[tab1->n_var + i] = tab2->var[i];
+		update_index2(&prod->var[tab1->n_var + i],
+				tab1->n_row, tab1->n_col,
+				r1, r2, d1, d2);
+	}
+	prod->con = isl_alloc_array(tab1->mat->ctx, struct isl_tab_var,
+					tab1->max_con +  tab2->max_con);
+	if ((tab1->max_con + tab2->max_con) && !prod->con)
+		goto error;
+	for (i = 0; i < tab1->n_con; ++i) {
+		prod->con[i] = tab1->con[i];
+		update_index1(&prod->con[i], r1, r2, d1, d2);
+	}
+	for (i = 0; i < tab2->n_con; ++i) {
+		prod->con[tab1->n_con + i] = tab2->con[i];
+		update_index2(&prod->con[tab1->n_con + i],
+				tab1->n_row, tab1->n_col,
+				r1, r2, d1, d2);
+	}
+	prod->col_var = isl_alloc_array(tab1->mat->ctx, int,
+					tab1->n_col + tab2->n_col);
+	if ((tab1->n_col + tab2->n_col) && !prod->col_var)
+		goto error;
+	for (i = 0; i < tab1->n_col; ++i) {
+		int pos = i < d1 ? i : i + d2;
+		prod->col_var[pos] = tab1->col_var[i];
+	}
+	for (i = 0; i < tab2->n_col; ++i) {
+		int pos = i < d2 ? d1 + i : tab1->n_col + i;
+		int t = tab2->col_var[i];
+		if (t >= 0)
+			t += tab1->n_var;
+		else
+			t -= tab1->n_con;
+		prod->col_var[pos] = t;
+	}
+	prod->row_var = isl_alloc_array(tab1->mat->ctx, int,
+					tab1->mat->n_row + tab2->mat->n_row);
+	if ((tab1->mat->n_row + tab2->mat->n_row) && !prod->row_var)
+		goto error;
+	for (i = 0; i < tab1->n_row; ++i) {
+		int pos = i < r1 ? i : i + r2;
+		prod->row_var[pos] = tab1->row_var[i];
+	}
+	for (i = 0; i < tab2->n_row; ++i) {
+		int pos = i < r2 ? r1 + i : tab1->n_row + i;
+		int t = tab2->row_var[i];
+		if (t >= 0)
+			t += tab1->n_var;
+		else
+			t -= tab1->n_con;
+		prod->row_var[pos] = t;
+	}
+	prod->samples = NULL;
+	prod->sample_index = NULL;
+	prod->n_row = tab1->n_row + tab2->n_row;
+	prod->n_con = tab1->n_con + tab2->n_con;
+	prod->n_eq = 0;
+	prod->max_con = tab1->max_con + tab2->max_con;
+	prod->n_col = tab1->n_col + tab2->n_col;
+	prod->n_var = tab1->n_var + tab2->n_var;
+	prod->max_var = tab1->max_var + tab2->max_var;
+	prod->n_param = 0;
+	prod->n_div = 0;
+	prod->n_dead = tab1->n_dead + tab2->n_dead;
+	prod->n_redundant = tab1->n_redundant + tab2->n_redundant;
+	prod->rational = tab1->rational;
+	prod->empty = tab1->empty || tab2->empty;
+	prod->strict_redundant = tab1->strict_redundant || tab2->strict_redundant;
+	prod->need_undo = 0;
+	prod->in_undo = 0;
+	prod->M = tab1->M;
+	prod->cone = tab1->cone;
+	prod->bottom.type = isl_tab_undo_bottom;
+	prod->bottom.next = NULL;
+	prod->top = &prod->bottom;
+
+	prod->n_zero = 0;
+	prod->n_unbounded = 0;
+	prod->basis = NULL;
+
+	return prod;
+error:
+	isl_tab_free(prod);
+	return NULL;
+}
+
+static struct isl_tab_var *var_from_index(struct isl_tab *tab, int i)
+{
+	if (i >= 0)
+		return &tab->var[i];
+	else
+		return &tab->con[~i];
+}
+
+struct isl_tab_var *isl_tab_var_from_row(struct isl_tab *tab, int i)
+{
+	return var_from_index(tab, tab->row_var[i]);
+}
+
+static struct isl_tab_var *var_from_col(struct isl_tab *tab, int i)
+{
+	return var_from_index(tab, tab->col_var[i]);
+}
+
+/* Check if there are any upper bounds on column variable "var",
+ * i.e., non-negative rows where var appears with a negative coefficient.
+ * Return 1 if there are no such bounds.
+ */
+static int max_is_manifestly_unbounded(struct isl_tab *tab,
+	struct isl_tab_var *var)
+{
+	int i;
+	unsigned off = 2 + tab->M;
+
+	if (var->is_row)
+		return 0;
+	for (i = tab->n_redundant; i < tab->n_row; ++i) {
+		if (!isl_int_is_neg(tab->mat->row[i][off + var->index]))
+			continue;
+		if (isl_tab_var_from_row(tab, i)->is_nonneg)
+			return 0;
+	}
+	return 1;
+}
+
+/* Check if there are any lower bounds on column variable "var",
+ * i.e., non-negative rows where var appears with a positive coefficient.
+ * Return 1 if there are no such bounds.
+ */
+static int min_is_manifestly_unbounded(struct isl_tab *tab,
+	struct isl_tab_var *var)
+{
+	int i;
+	unsigned off = 2 + tab->M;
+
+	if (var->is_row)
+		return 0;
+	for (i = tab->n_redundant; i < tab->n_row; ++i) {
+		if (!isl_int_is_pos(tab->mat->row[i][off + var->index]))
+			continue;
+		if (isl_tab_var_from_row(tab, i)->is_nonneg)
+			return 0;
+	}
+	return 1;
+}
+
+static int row_cmp(struct isl_tab *tab, int r1, int r2, int c, isl_int *t)
+{
+	unsigned off = 2 + tab->M;
+
+	if (tab->M) {
+		int s;
+		isl_int_mul(*t, tab->mat->row[r1][2], tab->mat->row[r2][off+c]);
+		isl_int_submul(*t, tab->mat->row[r2][2], tab->mat->row[r1][off+c]);
+		s = isl_int_sgn(*t);
+		if (s)
+			return s;
+	}
+	isl_int_mul(*t, tab->mat->row[r1][1], tab->mat->row[r2][off + c]);
+	isl_int_submul(*t, tab->mat->row[r2][1], tab->mat->row[r1][off + c]);
+	return isl_int_sgn(*t);
+}
+
+/* Given the index of a column "c", return the index of a row
+ * that can be used to pivot the column in, with either an increase
+ * (sgn > 0) or a decrease (sgn < 0) of the corresponding variable.
+ * If "var" is not NULL, then the row returned will be different from
+ * the one associated with "var".
+ *
+ * Each row in the tableau is of the form
+ *
+ *	x_r = a_r0 + \sum_i a_ri x_i
+ *
+ * Only rows with x_r >= 0 and with the sign of a_ri opposite to "sgn"
+ * impose any limit on the increase or decrease in the value of x_c
+ * and this bound is equal to a_r0 / |a_rc|.  We are therefore looking
+ * for the row with the smallest (most stringent) such bound.
+ * Note that the common denominator of each row drops out of the fraction.
+ * To check if row j has a smaller bound than row r, i.e.,
+ * a_j0 / |a_jc| < a_r0 / |a_rc| or a_j0 |a_rc| < a_r0 |a_jc|,
+ * we check if -sign(a_jc) (a_j0 a_rc - a_r0 a_jc) < 0,
+ * where -sign(a_jc) is equal to "sgn".
+ */
+static int pivot_row(struct isl_tab *tab,
+	struct isl_tab_var *var, int sgn, int c)
+{
+	int j, r, tsgn;
+	isl_int t;
+	unsigned off = 2 + tab->M;
+
+	isl_int_init(t);
+	r = -1;
+	for (j = tab->n_redundant; j < tab->n_row; ++j) {
+		if (var && j == var->index)
+			continue;
+		if (!isl_tab_var_from_row(tab, j)->is_nonneg)
+			continue;
+		if (sgn * isl_int_sgn(tab->mat->row[j][off + c]) >= 0)
+			continue;
+		if (r < 0) {
+			r = j;
+			continue;
+		}
+		tsgn = sgn * row_cmp(tab, r, j, c, &t);
+		if (tsgn < 0 || (tsgn == 0 &&
+					    tab->row_var[j] < tab->row_var[r]))
+			r = j;
+	}
+	isl_int_clear(t);
+	return r;
+}
+
+/* Find a pivot (row and col) that will increase (sgn > 0) or decrease
+ * (sgn < 0) the value of row variable var.
+ * If not NULL, then skip_var is a row variable that should be ignored
+ * while looking for a pivot row.  It is usually equal to var.
+ *
+ * As the given row in the tableau is of the form
+ *
+ *	x_r = a_r0 + \sum_i a_ri x_i
+ *
+ * we need to find a column such that the sign of a_ri is equal to "sgn"
+ * (such that an increase in x_i will have the desired effect) or a
+ * column with a variable that may attain negative values.
+ * If a_ri is positive, then we need to move x_i in the same direction
+ * to obtain the desired effect.  Otherwise, x_i has to move in the
+ * opposite direction.
+ */
+static void find_pivot(struct isl_tab *tab,
+	struct isl_tab_var *var, struct isl_tab_var *skip_var,
+	int sgn, int *row, int *col)
+{
+	int j, r, c;
+	isl_int *tr;
+
+	*row = *col = -1;
+
+	isl_assert(tab->mat->ctx, var->is_row, return);
+	tr = tab->mat->row[var->index] + 2 + tab->M;
+
+	c = -1;
+	for (j = tab->n_dead; j < tab->n_col; ++j) {
+		if (isl_int_is_zero(tr[j]))
+			continue;
+		if (isl_int_sgn(tr[j]) != sgn &&
+		    var_from_col(tab, j)->is_nonneg)
+			continue;
+		if (c < 0 || tab->col_var[j] < tab->col_var[c])
+			c = j;
+	}
+	if (c < 0)
+		return;
+
+	sgn *= isl_int_sgn(tr[c]);
+	r = pivot_row(tab, skip_var, sgn, c);
+	*row = r < 0 ? var->index : r;
+	*col = c;
+}
+
+/* Return 1 if row "row" represents an obviously redundant inequality.
+ * This means
+ *	- it represents an inequality or a variable
+ *	- that is the sum of a non-negative sample value and a positive
+ *	  combination of zero or more non-negative constraints.
+ */
+int isl_tab_row_is_redundant(struct isl_tab *tab, int row)
+{
+	int i;
+	unsigned off = 2 + tab->M;
+
+	if (tab->row_var[row] < 0 && !isl_tab_var_from_row(tab, row)->is_nonneg)
+		return 0;
+
+	if (isl_int_is_neg(tab->mat->row[row][1]))
+		return 0;
+	if (tab->strict_redundant && isl_int_is_zero(tab->mat->row[row][1]))
+		return 0;
+	if (tab->M && isl_int_is_neg(tab->mat->row[row][2]))
+		return 0;
+
+	for (i = tab->n_dead; i < tab->n_col; ++i) {
+		if (isl_int_is_zero(tab->mat->row[row][off + i]))
+			continue;
+		if (tab->col_var[i] >= 0)
+			return 0;
+		if (isl_int_is_neg(tab->mat->row[row][off + i]))
+			return 0;
+		if (!var_from_col(tab, i)->is_nonneg)
+			return 0;
+	}
+	return 1;
+}
+
+static void swap_rows(struct isl_tab *tab, int row1, int row2)
+{
+	int t;
+	enum isl_tab_row_sign s;
+
+	t = tab->row_var[row1];
+	tab->row_var[row1] = tab->row_var[row2];
+	tab->row_var[row2] = t;
+	isl_tab_var_from_row(tab, row1)->index = row1;
+	isl_tab_var_from_row(tab, row2)->index = row2;
+	tab->mat = isl_mat_swap_rows(tab->mat, row1, row2);
+
+	if (!tab->row_sign)
+		return;
+	s = tab->row_sign[row1];
+	tab->row_sign[row1] = tab->row_sign[row2];
+	tab->row_sign[row2] = s;
+}
+
+static int push_union(struct isl_tab *tab,
+	enum isl_tab_undo_type type, union isl_tab_undo_val u) WARN_UNUSED;
+static int push_union(struct isl_tab *tab,
+	enum isl_tab_undo_type type, union isl_tab_undo_val u)
+{
+	struct isl_tab_undo *undo;
+
+	if (!tab)
+		return -1;
+	if (!tab->need_undo)
+		return 0;
+
+	undo = isl_alloc_type(tab->mat->ctx, struct isl_tab_undo);
+	if (!undo)
+		return -1;
+	undo->type = type;
+	undo->u = u;
+	undo->next = tab->top;
+	tab->top = undo;
+
+	return 0;
+}
+
+int isl_tab_push_var(struct isl_tab *tab,
+	enum isl_tab_undo_type type, struct isl_tab_var *var)
+{
+	union isl_tab_undo_val u;
+	if (var->is_row)
+		u.var_index = tab->row_var[var->index];
+	else
+		u.var_index = tab->col_var[var->index];
+	return push_union(tab, type, u);
+}
+
+int isl_tab_push(struct isl_tab *tab, enum isl_tab_undo_type type)
+{
+	union isl_tab_undo_val u = { 0 };
+	return push_union(tab, type, u);
+}
+
+/* Push a record on the undo stack describing the current basic
+ * variables, so that the this state can be restored during rollback.
+ */
+int isl_tab_push_basis(struct isl_tab *tab)
+{
+	int i;
+	union isl_tab_undo_val u;
+
+	u.col_var = isl_alloc_array(tab->mat->ctx, int, tab->n_col);
+	if (tab->n_col && !u.col_var)
+		return -1;
+	for (i = 0; i < tab->n_col; ++i)
+		u.col_var[i] = tab->col_var[i];
+	return push_union(tab, isl_tab_undo_saved_basis, u);
+}
+
+int isl_tab_push_callback(struct isl_tab *tab, struct isl_tab_callback *callback)
+{
+	union isl_tab_undo_val u;
+	u.callback = callback;
+	return push_union(tab, isl_tab_undo_callback, u);
+}
+
+struct isl_tab *isl_tab_init_samples(struct isl_tab *tab)
+{
+	if (!tab)
+		return NULL;
+
+	tab->n_sample = 0;
+	tab->n_outside = 0;
+	tab->samples = isl_mat_alloc(tab->mat->ctx, 1, 1 + tab->n_var);
+	if (!tab->samples)
+		goto error;
+	tab->sample_index = isl_alloc_array(tab->mat->ctx, int, 1);
+	if (!tab->sample_index)
+		goto error;
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+int isl_tab_add_sample(struct isl_tab *tab, __isl_take isl_vec *sample)
+{
+	if (!tab || !sample)
+		goto error;
+
+	if (tab->n_sample + 1 > tab->samples->n_row) {
+		int *t = isl_realloc_array(tab->mat->ctx,
+			    tab->sample_index, int, tab->n_sample + 1);
+		if (!t)
+			goto error;
+		tab->sample_index = t;
+	}
+
+	tab->samples = isl_mat_extend(tab->samples,
+				tab->n_sample + 1, tab->samples->n_col);
+	if (!tab->samples)
+		goto error;
+
+	isl_seq_cpy(tab->samples->row[tab->n_sample], sample->el, sample->size);
+	isl_vec_free(sample);
+	tab->sample_index[tab->n_sample] = tab->n_sample;
+	tab->n_sample++;
+
+	return 0;
+error:
+	isl_vec_free(sample);
+	return -1;
+}
+
+struct isl_tab *isl_tab_drop_sample(struct isl_tab *tab, int s)
+{
+	if (s != tab->n_outside) {
+		int t = tab->sample_index[tab->n_outside];
+		tab->sample_index[tab->n_outside] = tab->sample_index[s];
+		tab->sample_index[s] = t;
+		isl_mat_swap_rows(tab->samples, tab->n_outside, s);
+	}
+	tab->n_outside++;
+	if (isl_tab_push(tab, isl_tab_undo_drop_sample) < 0) {
+		isl_tab_free(tab);
+		return NULL;
+	}
+
+	return tab;
+}
+
+/* Record the current number of samples so that we can remove newer
+ * samples during a rollback.
+ */
+int isl_tab_save_samples(struct isl_tab *tab)
+{
+	union isl_tab_undo_val u;
+
+	if (!tab)
+		return -1;
+
+	u.n = tab->n_sample;
+	return push_union(tab, isl_tab_undo_saved_samples, u);
+}
+
+/* Mark row with index "row" as being redundant.
+ * If we may need to undo the operation or if the row represents
+ * a variable of the original problem, the row is kept,
+ * but no longer considered when looking for a pivot row.
+ * Otherwise, the row is simply removed.
+ *
+ * The row may be interchanged with some other row.  If it
+ * is interchanged with a later row, return 1.  Otherwise return 0.
+ * If the rows are checked in order in the calling function,
+ * then a return value of 1 means that the row with the given
+ * row number may now contain a different row that hasn't been checked yet.
+ */
+int isl_tab_mark_redundant(struct isl_tab *tab, int row)
+{
+	struct isl_tab_var *var = isl_tab_var_from_row(tab, row);
+	var->is_redundant = 1;
+	isl_assert(tab->mat->ctx, row >= tab->n_redundant, return -1);
+	if (tab->preserve || tab->need_undo || tab->row_var[row] >= 0) {
+		if (tab->row_var[row] >= 0 && !var->is_nonneg) {
+			var->is_nonneg = 1;
+			if (isl_tab_push_var(tab, isl_tab_undo_nonneg, var) < 0)
+				return -1;
+		}
+		if (row != tab->n_redundant)
+			swap_rows(tab, row, tab->n_redundant);
+		tab->n_redundant++;
+		return isl_tab_push_var(tab, isl_tab_undo_redundant, var);
+	} else {
+		if (row != tab->n_row - 1)
+			swap_rows(tab, row, tab->n_row - 1);
+		isl_tab_var_from_row(tab, tab->n_row - 1)->index = -1;
+		tab->n_row--;
+		return 1;
+	}
+}
+
+/* Mark "tab" as a rational tableau.
+ * If it wasn't marked as a rational tableau already and if we may
+ * need to undo changes, then arrange for the marking to be undone
+ * during the undo.
+ */
+int isl_tab_mark_rational(struct isl_tab *tab)
+{
+	if (!tab)
+		return -1;
+	if (!tab->rational && tab->need_undo)
+		if (isl_tab_push(tab, isl_tab_undo_rational) < 0)
+			return -1;
+	tab->rational = 1;
+	return 0;
+}
+
+isl_stat isl_tab_mark_empty(struct isl_tab *tab)
+{
+	if (!tab)
+		return isl_stat_error;
+	if (!tab->empty && tab->need_undo)
+		if (isl_tab_push(tab, isl_tab_undo_empty) < 0)
+			return isl_stat_error;
+	tab->empty = 1;
+	return isl_stat_ok;
+}
+
+int isl_tab_freeze_constraint(struct isl_tab *tab, int con)
+{
+	struct isl_tab_var *var;
+
+	if (!tab)
+		return -1;
+
+	var = &tab->con[con];
+	if (var->frozen)
+		return 0;
+	if (var->index < 0)
+		return 0;
+	var->frozen = 1;
+
+	if (tab->need_undo)
+		return isl_tab_push_var(tab, isl_tab_undo_freeze, var);
+
+	return 0;
+}
+
+/* Update the rows signs after a pivot of "row" and "col", with "row_sgn"
+ * the original sign of the pivot element.
+ * We only keep track of row signs during PILP solving and in this case
+ * we only pivot a row with negative sign (meaning the value is always
+ * non-positive) using a positive pivot element.
+ *
+ * For each row j, the new value of the parametric constant is equal to
+ *
+ *	a_j0 - a_jc a_r0/a_rc
+ *
+ * where a_j0 is the original parametric constant, a_rc is the pivot element,
+ * a_r0 is the parametric constant of the pivot row and a_jc is the
+ * pivot column entry of the row j.
+ * Since a_r0 is non-positive and a_rc is positive, the sign of row j
+ * remains the same if a_jc has the same sign as the row j or if
+ * a_jc is zero.  In all other cases, we reset the sign to "unknown".
+ */
+static void update_row_sign(struct isl_tab *tab, int row, int col, int row_sgn)
+{
+	int i;
+	struct isl_mat *mat = tab->mat;
+	unsigned off = 2 + tab->M;
+
+	if (!tab->row_sign)
+		return;
+
+	if (tab->row_sign[row] == 0)
+		return;
+	isl_assert(mat->ctx, row_sgn > 0, return);
+	isl_assert(mat->ctx, tab->row_sign[row] == isl_tab_row_neg, return);
+	tab->row_sign[row] = isl_tab_row_pos;
+	for (i = 0; i < tab->n_row; ++i) {
+		int s;
+		if (i == row)
+			continue;
+		s = isl_int_sgn(mat->row[i][off + col]);
+		if (!s)
+			continue;
+		if (!tab->row_sign[i])
+			continue;
+		if (s < 0 && tab->row_sign[i] == isl_tab_row_neg)
+			continue;
+		if (s > 0 && tab->row_sign[i] == isl_tab_row_pos)
+			continue;
+		tab->row_sign[i] = isl_tab_row_unknown;
+	}
+}
+
+/* Given a row number "row" and a column number "col", pivot the tableau
+ * such that the associated variables are interchanged.
+ * The given row in the tableau expresses
+ *
+ *	x_r = a_r0 + \sum_i a_ri x_i
+ *
+ * or
+ *
+ *	x_c = 1/a_rc x_r - a_r0/a_rc + sum_{i \ne r} -a_ri/a_rc
+ *
+ * Substituting this equality into the other rows
+ *
+ *	x_j = a_j0 + \sum_i a_ji x_i
+ *
+ * with a_jc \ne 0, we obtain
+ *
+ *	x_j = a_jc/a_rc x_r + a_j0 - a_jc a_r0/a_rc + sum a_ji - a_jc a_ri/a_rc 
+ *
+ * The tableau
+ *
+ *	n_rc/d_r		n_ri/d_r
+ *	n_jc/d_j		n_ji/d_j
+ *
+ * where i is any other column and j is any other row,
+ * is therefore transformed into
+ *
+ * s(n_rc)d_r/|n_rc|		-s(n_rc)n_ri/|n_rc|
+ * s(n_rc)d_r n_jc/(|n_rc| d_j)	(n_ji |n_rc| - s(n_rc)n_jc n_ri)/(|n_rc| d_j)
+ *
+ * The transformation is performed along the following steps
+ *
+ *	d_r/n_rc		n_ri/n_rc
+ *	n_jc/d_j		n_ji/d_j
+ *
+ *	s(n_rc)d_r/|n_rc|	-s(n_rc)n_ri/|n_rc|
+ *	n_jc/d_j		n_ji/d_j
+ *
+ *	s(n_rc)d_r/|n_rc|	-s(n_rc)n_ri/|n_rc|
+ *	n_jc/(|n_rc| d_j)	n_ji/(|n_rc| d_j)
+ *
+ *	s(n_rc)d_r/|n_rc|	-s(n_rc)n_ri/|n_rc|
+ *	n_jc/(|n_rc| d_j)	(n_ji |n_rc|)/(|n_rc| d_j)
+ *
+ *	s(n_rc)d_r/|n_rc|	-s(n_rc)n_ri/|n_rc|
+ *	n_jc/(|n_rc| d_j)	(n_ji |n_rc| - s(n_rc)n_jc n_ri)/(|n_rc| d_j)
+ *
+ * s(n_rc)d_r/|n_rc|		-s(n_rc)n_ri/|n_rc|
+ * s(n_rc)d_r n_jc/(|n_rc| d_j)	(n_ji |n_rc| - s(n_rc)n_jc n_ri)/(|n_rc| d_j)
+ *
+ */
+int isl_tab_pivot(struct isl_tab *tab, int row, int col)
+{
+	int i, j;
+	int sgn;
+	int t;
+	isl_ctx *ctx;
+	struct isl_mat *mat = tab->mat;
+	struct isl_tab_var *var;
+	unsigned off = 2 + tab->M;
+
+	ctx = isl_tab_get_ctx(tab);
+	if (isl_ctx_next_operation(ctx) < 0)
+		return -1;
+
+	isl_int_swap(mat->row[row][0], mat->row[row][off + col]);
+	sgn = isl_int_sgn(mat->row[row][0]);
+	if (sgn < 0) {
+		isl_int_neg(mat->row[row][0], mat->row[row][0]);
+		isl_int_neg(mat->row[row][off + col], mat->row[row][off + col]);
+	} else
+		for (j = 0; j < off - 1 + tab->n_col; ++j) {
+			if (j == off - 1 + col)
+				continue;
+			isl_int_neg(mat->row[row][1 + j], mat->row[row][1 + j]);
+		}
+	if (!isl_int_is_one(mat->row[row][0]))
+		isl_seq_normalize(mat->ctx, mat->row[row], off + tab->n_col);
+	for (i = 0; i < tab->n_row; ++i) {
+		if (i == row)
+			continue;
+		if (isl_int_is_zero(mat->row[i][off + col]))
+			continue;
+		isl_int_mul(mat->row[i][0], mat->row[i][0], mat->row[row][0]);
+		for (j = 0; j < off - 1 + tab->n_col; ++j) {
+			if (j == off - 1 + col)
+				continue;
+			isl_int_mul(mat->row[i][1 + j],
+				    mat->row[i][1 + j], mat->row[row][0]);
+			isl_int_addmul(mat->row[i][1 + j],
+				    mat->row[i][off + col], mat->row[row][1 + j]);
+		}
+		isl_int_mul(mat->row[i][off + col],
+			    mat->row[i][off + col], mat->row[row][off + col]);
+		if (!isl_int_is_one(mat->row[i][0]))
+			isl_seq_normalize(mat->ctx, mat->row[i], off + tab->n_col);
+	}
+	t = tab->row_var[row];
+	tab->row_var[row] = tab->col_var[col];
+	tab->col_var[col] = t;
+	var = isl_tab_var_from_row(tab, row);
+	var->is_row = 1;
+	var->index = row;
+	var = var_from_col(tab, col);
+	var->is_row = 0;
+	var->index = col;
+	update_row_sign(tab, row, col, sgn);
+	if (tab->in_undo)
+		return 0;
+	for (i = tab->n_redundant; i < tab->n_row; ++i) {
+		if (isl_int_is_zero(mat->row[i][off + col]))
+			continue;
+		if (!isl_tab_var_from_row(tab, i)->frozen &&
+		    isl_tab_row_is_redundant(tab, i)) {
+			int redo = isl_tab_mark_redundant(tab, i);
+			if (redo < 0)
+				return -1;
+			if (redo)
+				--i;
+		}
+	}
+	return 0;
+}
+
+/* If "var" represents a column variable, then pivot is up (sgn > 0)
+ * or down (sgn < 0) to a row.  The variable is assumed not to be
+ * unbounded in the specified direction.
+ * If sgn = 0, then the variable is unbounded in both directions,
+ * and we pivot with any row we can find.
+ */
+static int to_row(struct isl_tab *tab, struct isl_tab_var *var, int sign) WARN_UNUSED;
+static int to_row(struct isl_tab *tab, struct isl_tab_var *var, int sign)
+{
+	int r;
+	unsigned off = 2 + tab->M;
+
+	if (var->is_row)
+		return 0;
+
+	if (sign == 0) {
+		for (r = tab->n_redundant; r < tab->n_row; ++r)
+			if (!isl_int_is_zero(tab->mat->row[r][off+var->index]))
+				break;
+		isl_assert(tab->mat->ctx, r < tab->n_row, return -1);
+	} else {
+		r = pivot_row(tab, NULL, sign, var->index);
+		isl_assert(tab->mat->ctx, r >= 0, return -1);
+	}
+
+	return isl_tab_pivot(tab, r, var->index);
+}
+
+/* Check whether all variables that are marked as non-negative
+ * also have a non-negative sample value.  This function is not
+ * called from the current code but is useful during debugging.
+ */
+static void check_table(struct isl_tab *tab) __attribute__ ((unused));
+static void check_table(struct isl_tab *tab)
+{
+	int i;
+
+	if (tab->empty)
+		return;
+	for (i = tab->n_redundant; i < tab->n_row; ++i) {
+		struct isl_tab_var *var;
+		var = isl_tab_var_from_row(tab, i);
+		if (!var->is_nonneg)
+			continue;
+		if (tab->M) {
+			isl_assert(tab->mat->ctx,
+				!isl_int_is_neg(tab->mat->row[i][2]), abort());
+			if (isl_int_is_pos(tab->mat->row[i][2]))
+				continue;
+		}
+		isl_assert(tab->mat->ctx, !isl_int_is_neg(tab->mat->row[i][1]),
+				abort());
+	}
+}
+
+/* Return the sign of the maximal value of "var".
+ * If the sign is not negative, then on return from this function,
+ * the sample value will also be non-negative.
+ *
+ * If "var" is manifestly unbounded wrt positive values, we are done.
+ * Otherwise, we pivot the variable up to a row if needed
+ * Then we continue pivoting down until either
+ *	- no more down pivots can be performed
+ *	- the sample value is positive
+ *	- the variable is pivoted into a manifestly unbounded column
+ */
+static int sign_of_max(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int row, col;
+
+	if (max_is_manifestly_unbounded(tab, var))
+		return 1;
+	if (to_row(tab, var, 1) < 0)
+		return -2;
+	while (!isl_int_is_pos(tab->mat->row[var->index][1])) {
+		find_pivot(tab, var, var, 1, &row, &col);
+		if (row == -1)
+			return isl_int_sgn(tab->mat->row[var->index][1]);
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -2;
+		if (!var->is_row) /* manifestly unbounded */
+			return 1;
+	}
+	return 1;
+}
+
+int isl_tab_sign_of_max(struct isl_tab *tab, int con)
+{
+	struct isl_tab_var *var;
+
+	if (!tab)
+		return -2;
+
+	var = &tab->con[con];
+	isl_assert(tab->mat->ctx, !var->is_redundant, return -2);
+	isl_assert(tab->mat->ctx, !var->is_zero, return -2);
+
+	return sign_of_max(tab, var);
+}
+
+static int row_is_neg(struct isl_tab *tab, int row)
+{
+	if (!tab->M)
+		return isl_int_is_neg(tab->mat->row[row][1]);
+	if (isl_int_is_pos(tab->mat->row[row][2]))
+		return 0;
+	if (isl_int_is_neg(tab->mat->row[row][2]))
+		return 1;
+	return isl_int_is_neg(tab->mat->row[row][1]);
+}
+
+static int row_sgn(struct isl_tab *tab, int row)
+{
+	if (!tab->M)
+		return isl_int_sgn(tab->mat->row[row][1]);
+	if (!isl_int_is_zero(tab->mat->row[row][2]))
+		return isl_int_sgn(tab->mat->row[row][2]);
+	else
+		return isl_int_sgn(tab->mat->row[row][1]);
+}
+
+/* Perform pivots until the row variable "var" has a non-negative
+ * sample value or until no more upward pivots can be performed.
+ * Return the sign of the sample value after the pivots have been
+ * performed.
+ */
+static int restore_row(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int row, col;
+
+	while (row_is_neg(tab, var->index)) {
+		find_pivot(tab, var, var, 1, &row, &col);
+		if (row == -1)
+			break;
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -2;
+		if (!var->is_row) /* manifestly unbounded */
+			return 1;
+	}
+	return row_sgn(tab, var->index);
+}
+
+/* Perform pivots until we are sure that the row variable "var"
+ * can attain non-negative values.  After return from this
+ * function, "var" is still a row variable, but its sample
+ * value may not be non-negative, even if the function returns 1.
+ */
+static int at_least_zero(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int row, col;
+
+	while (isl_int_is_neg(tab->mat->row[var->index][1])) {
+		find_pivot(tab, var, var, 1, &row, &col);
+		if (row == -1)
+			break;
+		if (row == var->index) /* manifestly unbounded */
+			return 1;
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -1;
+	}
+	return !isl_int_is_neg(tab->mat->row[var->index][1]);
+}
+
+/* Return a negative value if "var" can attain negative values.
+ * Return a non-negative value otherwise.
+ *
+ * If "var" is manifestly unbounded wrt negative values, we are done.
+ * Otherwise, if var is in a column, we can pivot it down to a row.
+ * Then we continue pivoting down until either
+ *	- the pivot would result in a manifestly unbounded column
+ *	  => we don't perform the pivot, but simply return -1
+ *	- no more down pivots can be performed
+ *	- the sample value is negative
+ * If the sample value becomes negative and the variable is supposed
+ * to be nonnegative, then we undo the last pivot.
+ * However, if the last pivot has made the pivoting variable
+ * obviously redundant, then it may have moved to another row.
+ * In that case we look for upward pivots until we reach a non-negative
+ * value again.
+ */
+static int sign_of_min(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int row, col;
+	struct isl_tab_var *pivot_var = NULL;
+
+	if (min_is_manifestly_unbounded(tab, var))
+		return -1;
+	if (!var->is_row) {
+		col = var->index;
+		row = pivot_row(tab, NULL, -1, col);
+		pivot_var = var_from_col(tab, col);
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -2;
+		if (var->is_redundant)
+			return 0;
+		if (isl_int_is_neg(tab->mat->row[var->index][1])) {
+			if (var->is_nonneg) {
+				if (!pivot_var->is_redundant &&
+				    pivot_var->index == row) {
+					if (isl_tab_pivot(tab, row, col) < 0)
+						return -2;
+				} else
+					if (restore_row(tab, var) < -1)
+						return -2;
+			}
+			return -1;
+		}
+	}
+	if (var->is_redundant)
+		return 0;
+	while (!isl_int_is_neg(tab->mat->row[var->index][1])) {
+		find_pivot(tab, var, var, -1, &row, &col);
+		if (row == var->index)
+			return -1;
+		if (row == -1)
+			return isl_int_sgn(tab->mat->row[var->index][1]);
+		pivot_var = var_from_col(tab, col);
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -2;
+		if (var->is_redundant)
+			return 0;
+	}
+	if (pivot_var && var->is_nonneg) {
+		/* pivot back to non-negative value */
+		if (!pivot_var->is_redundant && pivot_var->index == row) {
+			if (isl_tab_pivot(tab, row, col) < 0)
+				return -2;
+		} else
+			if (restore_row(tab, var) < -1)
+				return -2;
+	}
+	return -1;
+}
+
+static int row_at_most_neg_one(struct isl_tab *tab, int row)
+{
+	if (tab->M) {
+		if (isl_int_is_pos(tab->mat->row[row][2]))
+			return 0;
+		if (isl_int_is_neg(tab->mat->row[row][2]))
+			return 1;
+	}
+	return isl_int_is_neg(tab->mat->row[row][1]) &&
+	       isl_int_abs_ge(tab->mat->row[row][1],
+			      tab->mat->row[row][0]);
+}
+
+/* Return 1 if "var" can attain values <= -1.
+ * Return 0 otherwise.
+ *
+ * If the variable "var" is supposed to be non-negative (is_nonneg is set),
+ * then the sample value of "var" is assumed to be non-negative when the
+ * the function is called.  If 1 is returned then the constraint
+ * is not redundant and the sample value is made non-negative again before
+ * the function returns.
+ */
+int isl_tab_min_at_most_neg_one(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int row, col;
+	struct isl_tab_var *pivot_var;
+
+	if (min_is_manifestly_unbounded(tab, var))
+		return 1;
+	if (!var->is_row) {
+		col = var->index;
+		row = pivot_row(tab, NULL, -1, col);
+		pivot_var = var_from_col(tab, col);
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -1;
+		if (var->is_redundant)
+			return 0;
+		if (row_at_most_neg_one(tab, var->index)) {
+			if (var->is_nonneg) {
+				if (!pivot_var->is_redundant &&
+				    pivot_var->index == row) {
+					if (isl_tab_pivot(tab, row, col) < 0)
+						return -1;
+				} else
+					if (restore_row(tab, var) < -1)
+						return -1;
+			}
+			return 1;
+		}
+	}
+	if (var->is_redundant)
+		return 0;
+	do {
+		find_pivot(tab, var, var, -1, &row, &col);
+		if (row == var->index) {
+			if (var->is_nonneg && restore_row(tab, var) < -1)
+				return -1;
+			return 1;
+		}
+		if (row == -1)
+			return 0;
+		pivot_var = var_from_col(tab, col);
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -1;
+		if (var->is_redundant)
+			return 0;
+	} while (!row_at_most_neg_one(tab, var->index));
+	if (var->is_nonneg) {
+		/* pivot back to non-negative value */
+		if (!pivot_var->is_redundant && pivot_var->index == row)
+			if (isl_tab_pivot(tab, row, col) < 0)
+				return -1;
+		if (restore_row(tab, var) < -1)
+			return -1;
+	}
+	return 1;
+}
+
+/* Return 1 if "var" can attain values >= 1.
+ * Return 0 otherwise.
+ */
+static int at_least_one(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int row, col;
+	isl_int *r;
+
+	if (max_is_manifestly_unbounded(tab, var))
+		return 1;
+	if (to_row(tab, var, 1) < 0)
+		return -1;
+	r = tab->mat->row[var->index];
+	while (isl_int_lt(r[1], r[0])) {
+		find_pivot(tab, var, var, 1, &row, &col);
+		if (row == -1)
+			return isl_int_ge(r[1], r[0]);
+		if (row == var->index) /* manifestly unbounded */
+			return 1;
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -1;
+	}
+	return 1;
+}
+
+static void swap_cols(struct isl_tab *tab, int col1, int col2)
+{
+	int t;
+	unsigned off = 2 + tab->M;
+	t = tab->col_var[col1];
+	tab->col_var[col1] = tab->col_var[col2];
+	tab->col_var[col2] = t;
+	var_from_col(tab, col1)->index = col1;
+	var_from_col(tab, col2)->index = col2;
+	tab->mat = isl_mat_swap_cols(tab->mat, off + col1, off + col2);
+}
+
+/* Mark column with index "col" as representing a zero variable.
+ * If we may need to undo the operation the column is kept,
+ * but no longer considered.
+ * Otherwise, the column is simply removed.
+ *
+ * The column may be interchanged with some other column.  If it
+ * is interchanged with a later column, return 1.  Otherwise return 0.
+ * If the columns are checked in order in the calling function,
+ * then a return value of 1 means that the column with the given
+ * column number may now contain a different column that
+ * hasn't been checked yet.
+ */
+int isl_tab_kill_col(struct isl_tab *tab, int col)
+{
+	var_from_col(tab, col)->is_zero = 1;
+	if (tab->need_undo) {
+		if (isl_tab_push_var(tab, isl_tab_undo_zero,
+					    var_from_col(tab, col)) < 0)
+			return -1;
+		if (col != tab->n_dead)
+			swap_cols(tab, col, tab->n_dead);
+		tab->n_dead++;
+		return 0;
+	} else {
+		if (col != tab->n_col - 1)
+			swap_cols(tab, col, tab->n_col - 1);
+		var_from_col(tab, tab->n_col - 1)->index = -1;
+		tab->n_col--;
+		return 1;
+	}
+}
+
+static int row_is_manifestly_non_integral(struct isl_tab *tab, int row)
+{
+	unsigned off = 2 + tab->M;
+
+	if (tab->M && !isl_int_eq(tab->mat->row[row][2],
+				  tab->mat->row[row][0]))
+		return 0;
+	if (isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead,
+				    tab->n_col - tab->n_dead) != -1)
+		return 0;
+
+	return !isl_int_is_divisible_by(tab->mat->row[row][1],
+					tab->mat->row[row][0]);
+}
+
+/* For integer tableaus, check if any of the coordinates are stuck
+ * at a non-integral value.
+ */
+static int tab_is_manifestly_empty(struct isl_tab *tab)
+{
+	int i;
+
+	if (tab->empty)
+		return 1;
+	if (tab->rational)
+		return 0;
+
+	for (i = 0; i < tab->n_var; ++i) {
+		if (!tab->var[i].is_row)
+			continue;
+		if (row_is_manifestly_non_integral(tab, tab->var[i].index))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Row variable "var" is non-negative and cannot attain any values
+ * larger than zero.  This means that the coefficients of the unrestricted
+ * column variables are zero and that the coefficients of the non-negative
+ * column variables are zero or negative.
+ * Each of the non-negative variables with a negative coefficient can
+ * then also be written as the negative sum of non-negative variables
+ * and must therefore also be zero.
+ *
+ * If "temp_var" is set, then "var" is a temporary variable that
+ * will be removed after this function returns and for which
+ * no information is recorded on the undo stack.
+ * Do not add any undo records involving this variable in this case
+ * since the variable will have been removed before any future undo
+ * operations.  Also avoid marking the variable as redundant,
+ * since that either adds an undo record or needlessly removes the row
+ * (the caller will take care of removing the row).
+ */
+static isl_stat close_row(struct isl_tab *tab, struct isl_tab_var *var,
+	int temp_var) WARN_UNUSED;
+static isl_stat close_row(struct isl_tab *tab, struct isl_tab_var *var,
+	int temp_var)
+{
+	int j;
+	struct isl_mat *mat = tab->mat;
+	unsigned off = 2 + tab->M;
+
+	if (!var->is_nonneg)
+		isl_die(isl_tab_get_ctx(tab), isl_error_internal,
+			"expecting non-negative variable",
+			return isl_stat_error);
+	var->is_zero = 1;
+	if (!temp_var && tab->need_undo)
+		if (isl_tab_push_var(tab, isl_tab_undo_zero, var) < 0)
+			return isl_stat_error;
+	for (j = tab->n_dead; j < tab->n_col; ++j) {
+		int recheck;
+		if (isl_int_is_zero(mat->row[var->index][off + j]))
+			continue;
+		if (isl_int_is_pos(mat->row[var->index][off + j]))
+			isl_die(isl_tab_get_ctx(tab), isl_error_internal,
+				"row cannot have positive coefficients",
+				return isl_stat_error);
+		recheck = isl_tab_kill_col(tab, j);
+		if (recheck < 0)
+			return isl_stat_error;
+		if (recheck)
+			--j;
+	}
+	if (!temp_var && isl_tab_mark_redundant(tab, var->index) < 0)
+		return isl_stat_error;
+	if (tab_is_manifestly_empty(tab) && isl_tab_mark_empty(tab) < 0)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Add a constraint to the tableau and allocate a row for it.
+ * Return the index into the constraint array "con".
+ *
+ * This function assumes that at least one more row and at least
+ * one more element in the constraint array are available in the tableau.
+ */
+int isl_tab_allocate_con(struct isl_tab *tab)
+{
+	int r;
+
+	isl_assert(tab->mat->ctx, tab->n_row < tab->mat->n_row, return -1);
+	isl_assert(tab->mat->ctx, tab->n_con < tab->max_con, return -1);
+
+	r = tab->n_con;
+	tab->con[r].index = tab->n_row;
+	tab->con[r].is_row = 1;
+	tab->con[r].is_nonneg = 0;
+	tab->con[r].is_zero = 0;
+	tab->con[r].is_redundant = 0;
+	tab->con[r].frozen = 0;
+	tab->con[r].negated = 0;
+	tab->row_var[tab->n_row] = ~r;
+
+	tab->n_row++;
+	tab->n_con++;
+	if (isl_tab_push_var(tab, isl_tab_undo_allocate, &tab->con[r]) < 0)
+		return -1;
+
+	return r;
+}
+
+/* Move the entries in tab->var up one position, starting at "first",
+ * creating room for an extra entry at position "first".
+ * Since some of the entries of tab->row_var and tab->col_var contain
+ * indices into this array, they have to be updated accordingly.
+ */
+static int var_insert_entry(struct isl_tab *tab, int first)
+{
+	int i;
+
+	if (tab->n_var >= tab->max_var)
+		isl_die(isl_tab_get_ctx(tab), isl_error_internal,
+			"not enough room for new variable", return -1);
+	if (first > tab->n_var)
+		isl_die(isl_tab_get_ctx(tab), isl_error_internal,
+			"invalid initial position", return -1);
+
+	for (i = tab->n_var - 1; i >= first; --i) {
+		tab->var[i + 1] = tab->var[i];
+		if (tab->var[i + 1].is_row)
+			tab->row_var[tab->var[i + 1].index]++;
+		else
+			tab->col_var[tab->var[i + 1].index]++;
+	}
+
+	tab->n_var++;
+
+	return 0;
+}
+
+/* Drop the entry at position "first" in tab->var, moving all
+ * subsequent entries down.
+ * Since some of the entries of tab->row_var and tab->col_var contain
+ * indices into this array, they have to be updated accordingly.
+ */
+static int var_drop_entry(struct isl_tab *tab, int first)
+{
+	int i;
+
+	if (first >= tab->n_var)
+		isl_die(isl_tab_get_ctx(tab), isl_error_internal,
+			"invalid initial position", return -1);
+
+	tab->n_var--;
+
+	for (i = first; i < tab->n_var; ++i) {
+		tab->var[i] = tab->var[i + 1];
+		if (tab->var[i + 1].is_row)
+			tab->row_var[tab->var[i].index]--;
+		else
+			tab->col_var[tab->var[i].index]--;
+	}
+
+	return 0;
+}
+
+/* Add a variable to the tableau at position "r" and allocate a column for it.
+ * Return the index into the variable array "var", i.e., "r",
+ * or -1 on error.
+ */
+int isl_tab_insert_var(struct isl_tab *tab, int r)
+{
+	int i;
+	unsigned off = 2 + tab->M;
+
+	isl_assert(tab->mat->ctx, tab->n_col < tab->mat->n_col, return -1);
+
+	if (var_insert_entry(tab, r) < 0)
+		return -1;
+
+	tab->var[r].index = tab->n_col;
+	tab->var[r].is_row = 0;
+	tab->var[r].is_nonneg = 0;
+	tab->var[r].is_zero = 0;
+	tab->var[r].is_redundant = 0;
+	tab->var[r].frozen = 0;
+	tab->var[r].negated = 0;
+	tab->col_var[tab->n_col] = r;
+
+	for (i = 0; i < tab->n_row; ++i)
+		isl_int_set_si(tab->mat->row[i][off + tab->n_col], 0);
+
+	tab->n_col++;
+	if (isl_tab_push_var(tab, isl_tab_undo_allocate, &tab->var[r]) < 0)
+		return -1;
+
+	return r;
+}
+
+/* Add a variable to the tableau and allocate a column for it.
+ * Return the index into the variable array "var".
+ */
+int isl_tab_allocate_var(struct isl_tab *tab)
+{
+	if (!tab)
+		return -1;
+
+	return isl_tab_insert_var(tab, tab->n_var);
+}
+
+/* Add a row to the tableau.  The row is given as an affine combination
+ * of the original variables and needs to be expressed in terms of the
+ * column variables.
+ *
+ * This function assumes that at least one more row and at least
+ * one more element in the constraint array are available in the tableau.
+ *
+ * We add each term in turn.
+ * If r = n/d_r is the current sum and we need to add k x, then
+ * 	if x is a column variable, we increase the numerator of
+ *		this column by k d_r
+ *	if x = f/d_x is a row variable, then the new representation of r is
+ *
+ *		 n    k f   d_x/g n + d_r/g k f   m/d_r n + m/d_g k f
+ *		--- + --- = ------------------- = -------------------
+ *		d_r   d_r        d_r d_x/g                m
+ *
+ *	with g the gcd of d_r and d_x and m the lcm of d_r and d_x.
+ *
+ * If tab->M is set, then, internally, each variable x is represented
+ * as x' - M.  We then also need no subtract k d_r from the coefficient of M.
+ */
+int isl_tab_add_row(struct isl_tab *tab, isl_int *line)
+{
+	int i;
+	int r;
+	isl_int *row;
+	isl_int a, b;
+	unsigned off = 2 + tab->M;
+
+	r = isl_tab_allocate_con(tab);
+	if (r < 0)
+		return -1;
+
+	isl_int_init(a);
+	isl_int_init(b);
+	row = tab->mat->row[tab->con[r].index];
+	isl_int_set_si(row[0], 1);
+	isl_int_set(row[1], line[0]);
+	isl_seq_clr(row + 2, tab->M + tab->n_col);
+	for (i = 0; i < tab->n_var; ++i) {
+		if (tab->var[i].is_zero)
+			continue;
+		if (tab->var[i].is_row) {
+			isl_int_lcm(a,
+				row[0], tab->mat->row[tab->var[i].index][0]);
+			isl_int_swap(a, row[0]);
+			isl_int_divexact(a, row[0], a);
+			isl_int_divexact(b,
+				row[0], tab->mat->row[tab->var[i].index][0]);
+			isl_int_mul(b, b, line[1 + i]);
+			isl_seq_combine(row + 1, a, row + 1,
+			    b, tab->mat->row[tab->var[i].index] + 1,
+			    1 + tab->M + tab->n_col);
+		} else
+			isl_int_addmul(row[off + tab->var[i].index],
+							line[1 + i], row[0]);
+		if (tab->M && i >= tab->n_param && i < tab->n_var - tab->n_div)
+			isl_int_submul(row[2], line[1 + i], row[0]);
+	}
+	isl_seq_normalize(tab->mat->ctx, row, off + tab->n_col);
+	isl_int_clear(a);
+	isl_int_clear(b);
+
+	if (tab->row_sign)
+		tab->row_sign[tab->con[r].index] = isl_tab_row_unknown;
+
+	return r;
+}
+
+static isl_stat drop_row(struct isl_tab *tab, int row)
+{
+	isl_assert(tab->mat->ctx, ~tab->row_var[row] == tab->n_con - 1,
+		return isl_stat_error);
+	if (row != tab->n_row - 1)
+		swap_rows(tab, row, tab->n_row - 1);
+	tab->n_row--;
+	tab->n_con--;
+	return isl_stat_ok;
+}
+
+/* Drop the variable in column "col" along with the column.
+ * The column is removed first because it may need to be moved
+ * into the last position and this process requires
+ * the contents of the col_var array in a state
+ * before the removal of the variable.
+ */
+static isl_stat drop_col(struct isl_tab *tab, int col)
+{
+	int var;
+
+	var = tab->col_var[col];
+	if (col != tab->n_col - 1)
+		swap_cols(tab, col, tab->n_col - 1);
+	tab->n_col--;
+	if (var_drop_entry(tab, var) < 0)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Add inequality "ineq" and check if it conflicts with the
+ * previously added constraints or if it is obviously redundant.
+ *
+ * This function assumes that at least one more row and at least
+ * one more element in the constraint array are available in the tableau.
+ */
+isl_stat isl_tab_add_ineq(struct isl_tab *tab, isl_int *ineq)
+{
+	int r;
+	int sgn;
+	isl_int cst;
+
+	if (!tab)
+		return isl_stat_error;
+	if (tab->bmap) {
+		struct isl_basic_map *bmap = tab->bmap;
+
+		isl_assert(tab->mat->ctx, tab->n_eq == bmap->n_eq,
+			return isl_stat_error);
+		isl_assert(tab->mat->ctx,
+			    tab->n_con == bmap->n_eq + bmap->n_ineq,
+			    return isl_stat_error);
+		tab->bmap = isl_basic_map_add_ineq(tab->bmap, ineq);
+		if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)
+			return isl_stat_error;
+		if (!tab->bmap)
+			return isl_stat_error;
+	}
+	if (tab->cone) {
+		isl_int_init(cst);
+		isl_int_set_si(cst, 0);
+		isl_int_swap(ineq[0], cst);
+	}
+	r = isl_tab_add_row(tab, ineq);
+	if (tab->cone) {
+		isl_int_swap(ineq[0], cst);
+		isl_int_clear(cst);
+	}
+	if (r < 0)
+		return isl_stat_error;
+	tab->con[r].is_nonneg = 1;
+	if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)
+		return isl_stat_error;
+	if (isl_tab_row_is_redundant(tab, tab->con[r].index)) {
+		if (isl_tab_mark_redundant(tab, tab->con[r].index) < 0)
+			return isl_stat_error;
+		return isl_stat_ok;
+	}
+
+	sgn = restore_row(tab, &tab->con[r]);
+	if (sgn < -1)
+		return isl_stat_error;
+	if (sgn < 0)
+		return isl_tab_mark_empty(tab);
+	if (tab->con[r].is_row && isl_tab_row_is_redundant(tab, tab->con[r].index))
+		if (isl_tab_mark_redundant(tab, tab->con[r].index) < 0)
+			return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Pivot a non-negative variable down until it reaches the value zero
+ * and then pivot the variable into a column position.
+ */
+static int to_col(struct isl_tab *tab, struct isl_tab_var *var) WARN_UNUSED;
+static int to_col(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int i;
+	int row, col;
+	unsigned off = 2 + tab->M;
+
+	if (!var->is_row)
+		return 0;
+
+	while (isl_int_is_pos(tab->mat->row[var->index][1])) {
+		find_pivot(tab, var, NULL, -1, &row, &col);
+		isl_assert(tab->mat->ctx, row != -1, return -1);
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -1;
+		if (!var->is_row)
+			return 0;
+	}
+
+	for (i = tab->n_dead; i < tab->n_col; ++i)
+		if (!isl_int_is_zero(tab->mat->row[var->index][off + i]))
+			break;
+
+	isl_assert(tab->mat->ctx, i < tab->n_col, return -1);
+	if (isl_tab_pivot(tab, var->index, i) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* We assume Gaussian elimination has been performed on the equalities.
+ * The equalities can therefore never conflict.
+ * Adding the equalities is currently only really useful for a later call
+ * to isl_tab_ineq_type.
+ *
+ * This function assumes that at least one more row and at least
+ * one more element in the constraint array are available in the tableau.
+ */
+static struct isl_tab *add_eq(struct isl_tab *tab, isl_int *eq)
+{
+	int i;
+	int r;
+
+	if (!tab)
+		return NULL;
+	r = isl_tab_add_row(tab, eq);
+	if (r < 0)
+		goto error;
+
+	r = tab->con[r].index;
+	i = isl_seq_first_non_zero(tab->mat->row[r] + 2 + tab->M + tab->n_dead,
+					tab->n_col - tab->n_dead);
+	isl_assert(tab->mat->ctx, i >= 0, goto error);
+	i += tab->n_dead;
+	if (isl_tab_pivot(tab, r, i) < 0)
+		goto error;
+	if (isl_tab_kill_col(tab, i) < 0)
+		goto error;
+	tab->n_eq++;
+
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Does the sample value of row "row" of "tab" involve the big parameter,
+ * if any?
+ */
+static int row_is_big(struct isl_tab *tab, int row)
+{
+	return tab->M && !isl_int_is_zero(tab->mat->row[row][2]);
+}
+
+static int row_is_manifestly_zero(struct isl_tab *tab, int row)
+{
+	unsigned off = 2 + tab->M;
+
+	if (!isl_int_is_zero(tab->mat->row[row][1]))
+		return 0;
+	if (row_is_big(tab, row))
+		return 0;
+	return isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead,
+					tab->n_col - tab->n_dead) == -1;
+}
+
+/* Add an equality that is known to be valid for the given tableau.
+ *
+ * This function assumes that at least one more row and at least
+ * one more element in the constraint array are available in the tableau.
+ */
+int isl_tab_add_valid_eq(struct isl_tab *tab, isl_int *eq)
+{
+	struct isl_tab_var *var;
+	int r;
+
+	if (!tab)
+		return -1;
+	r = isl_tab_add_row(tab, eq);
+	if (r < 0)
+		return -1;
+
+	var = &tab->con[r];
+	r = var->index;
+	if (row_is_manifestly_zero(tab, r)) {
+		var->is_zero = 1;
+		if (isl_tab_mark_redundant(tab, r) < 0)
+			return -1;
+		return 0;
+	}
+
+	if (isl_int_is_neg(tab->mat->row[r][1])) {
+		isl_seq_neg(tab->mat->row[r] + 1, tab->mat->row[r] + 1,
+			    1 + tab->n_col);
+		var->negated = 1;
+	}
+	var->is_nonneg = 1;
+	if (to_col(tab, var) < 0)
+		return -1;
+	var->is_nonneg = 0;
+	if (isl_tab_kill_col(tab, var->index) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Add a zero row to "tab" and return the corresponding index
+ * in the constraint array.
+ *
+ * This function assumes that at least one more row and at least
+ * one more element in the constraint array are available in the tableau.
+ */
+static int add_zero_row(struct isl_tab *tab)
+{
+	int r;
+	isl_int *row;
+
+	r = isl_tab_allocate_con(tab);
+	if (r < 0)
+		return -1;
+
+	row = tab->mat->row[tab->con[r].index];
+	isl_seq_clr(row + 1, 1 + tab->M + tab->n_col);
+	isl_int_set_si(row[0], 1);
+
+	return r;
+}
+
+/* Add equality "eq" and check if it conflicts with the
+ * previously added constraints or if it is obviously redundant.
+ *
+ * This function assumes that at least one more row and at least
+ * one more element in the constraint array are available in the tableau.
+ * If tab->bmap is set, then two rows are needed instead of one.
+ */
+int isl_tab_add_eq(struct isl_tab *tab, isl_int *eq)
+{
+	struct isl_tab_undo *snap = NULL;
+	struct isl_tab_var *var;
+	int r;
+	int row;
+	int sgn;
+	isl_int cst;
+
+	if (!tab)
+		return -1;
+	isl_assert(tab->mat->ctx, !tab->M, return -1);
+
+	if (tab->need_undo)
+		snap = isl_tab_snap(tab);
+
+	if (tab->cone) {
+		isl_int_init(cst);
+		isl_int_set_si(cst, 0);
+		isl_int_swap(eq[0], cst);
+	}
+	r = isl_tab_add_row(tab, eq);
+	if (tab->cone) {
+		isl_int_swap(eq[0], cst);
+		isl_int_clear(cst);
+	}
+	if (r < 0)
+		return -1;
+
+	var = &tab->con[r];
+	row = var->index;
+	if (row_is_manifestly_zero(tab, row)) {
+		if (snap)
+			return isl_tab_rollback(tab, snap);
+		return drop_row(tab, row);
+	}
+
+	if (tab->bmap) {
+		tab->bmap = isl_basic_map_add_ineq(tab->bmap, eq);
+		if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)
+			return -1;
+		isl_seq_neg(eq, eq, 1 + tab->n_var);
+		tab->bmap = isl_basic_map_add_ineq(tab->bmap, eq);
+		isl_seq_neg(eq, eq, 1 + tab->n_var);
+		if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)
+			return -1;
+		if (!tab->bmap)
+			return -1;
+		if (add_zero_row(tab) < 0)
+			return -1;
+	}
+
+	sgn = isl_int_sgn(tab->mat->row[row][1]);
+
+	if (sgn > 0) {
+		isl_seq_neg(tab->mat->row[row] + 1, tab->mat->row[row] + 1,
+			    1 + tab->n_col);
+		var->negated = 1;
+		sgn = -1;
+	}
+
+	if (sgn < 0) {
+		sgn = sign_of_max(tab, var);
+		if (sgn < -1)
+			return -1;
+		if (sgn < 0) {
+			if (isl_tab_mark_empty(tab) < 0)
+				return -1;
+			return 0;
+		}
+	}
+
+	var->is_nonneg = 1;
+	if (to_col(tab, var) < 0)
+		return -1;
+	var->is_nonneg = 0;
+	if (isl_tab_kill_col(tab, var->index) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Construct and return an inequality that expresses an upper bound
+ * on the given div.
+ * In particular, if the div is given by
+ *
+ *	d = floor(e/m)
+ *
+ * then the inequality expresses
+ *
+ *	m d <= e
+ */
+static struct isl_vec *ineq_for_div(struct isl_basic_map *bmap, unsigned div)
+{
+	unsigned total;
+	unsigned div_pos;
+	struct isl_vec *ineq;
+
+	if (!bmap)
+		return NULL;
+
+	total = isl_basic_map_total_dim(bmap);
+	div_pos = 1 + total - bmap->n_div + div;
+
+	ineq = isl_vec_alloc(bmap->ctx, 1 + total);
+	if (!ineq)
+		return NULL;
+
+	isl_seq_cpy(ineq->el, bmap->div[div] + 1, 1 + total);
+	isl_int_neg(ineq->el[div_pos], bmap->div[div][0]);
+	return ineq;
+}
+
+/* For a div d = floor(f/m), add the constraints
+ *
+ *		f - m d >= 0
+ *		-(f-(m-1)) + m d >= 0
+ *
+ * Note that the second constraint is the negation of
+ *
+ *		f - m d >= m
+ *
+ * If add_ineq is not NULL, then this function is used
+ * instead of isl_tab_add_ineq to effectively add the inequalities.
+ *
+ * This function assumes that at least two more rows and at least
+ * two more elements in the constraint array are available in the tableau.
+ */
+static isl_stat add_div_constraints(struct isl_tab *tab, unsigned div,
+	isl_stat (*add_ineq)(void *user, isl_int *), void *user)
+{
+	unsigned total;
+	unsigned div_pos;
+	struct isl_vec *ineq;
+
+	total = isl_basic_map_total_dim(tab->bmap);
+	div_pos = 1 + total - tab->bmap->n_div + div;
+
+	ineq = ineq_for_div(tab->bmap, div);
+	if (!ineq)
+		goto error;
+
+	if (add_ineq) {
+		if (add_ineq(user, ineq->el) < 0)
+			goto error;
+	} else {
+		if (isl_tab_add_ineq(tab, ineq->el) < 0)
+			goto error;
+	}
+
+	isl_seq_neg(ineq->el, tab->bmap->div[div] + 1, 1 + total);
+	isl_int_set(ineq->el[div_pos], tab->bmap->div[div][0]);
+	isl_int_add(ineq->el[0], ineq->el[0], ineq->el[div_pos]);
+	isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);
+
+	if (add_ineq) {
+		if (add_ineq(user, ineq->el) < 0)
+			goto error;
+	} else {
+		if (isl_tab_add_ineq(tab, ineq->el) < 0)
+			goto error;
+	}
+
+	isl_vec_free(ineq);
+
+	return 0;
+error:
+	isl_vec_free(ineq);
+	return -1;
+}
+
+/* Check whether the div described by "div" is obviously non-negative.
+ * If we are using a big parameter, then we will encode the div
+ * as div' = M + div, which is always non-negative.
+ * Otherwise, we check whether div is a non-negative affine combination
+ * of non-negative variables.
+ */
+static int div_is_nonneg(struct isl_tab *tab, __isl_keep isl_vec *div)
+{
+	int i;
+
+	if (tab->M)
+		return 1;
+
+	if (isl_int_is_neg(div->el[1]))
+		return 0;
+
+	for (i = 0; i < tab->n_var; ++i) {
+		if (isl_int_is_neg(div->el[2 + i]))
+			return 0;
+		if (isl_int_is_zero(div->el[2 + i]))
+			continue;
+		if (!tab->var[i].is_nonneg)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Insert an extra div, prescribed by "div", to the tableau and
+ * the associated bmap (which is assumed to be non-NULL).
+ * The extra integer division is inserted at (tableau) position "pos".
+ * Return "pos" or -1 if an error occurred.
+ *
+ * If add_ineq is not NULL, then this function is used instead
+ * of isl_tab_add_ineq to add the div constraints.
+ * This complication is needed because the code in isl_tab_pip
+ * wants to perform some extra processing when an inequality
+ * is added to the tableau.
+ */
+int isl_tab_insert_div(struct isl_tab *tab, int pos, __isl_keep isl_vec *div,
+	isl_stat (*add_ineq)(void *user, isl_int *), void *user)
+{
+	int r;
+	int nonneg;
+	int n_div, o_div;
+
+	if (!tab || !div)
+		return -1;
+
+	if (div->size != 1 + 1 + tab->n_var)
+		isl_die(isl_tab_get_ctx(tab), isl_error_invalid,
+			"unexpected size", return -1);
+
+	isl_assert(tab->mat->ctx, tab->bmap, return -1);
+	n_div = isl_basic_map_dim(tab->bmap, isl_dim_div);
+	o_div = tab->n_var - n_div;
+	if (pos < o_div || pos > tab->n_var)
+		isl_die(isl_tab_get_ctx(tab), isl_error_invalid,
+			"invalid position", return -1);
+
+	nonneg = div_is_nonneg(tab, div);
+
+	if (isl_tab_extend_cons(tab, 3) < 0)
+		return -1;
+	if (isl_tab_extend_vars(tab, 1) < 0)
+		return -1;
+	r = isl_tab_insert_var(tab, pos);
+	if (r < 0)
+		return -1;
+
+	if (nonneg)
+		tab->var[r].is_nonneg = 1;
+
+	tab->bmap = isl_basic_map_insert_div(tab->bmap, pos - o_div, div);
+	if (!tab->bmap)
+		return -1;
+	if (isl_tab_push_var(tab, isl_tab_undo_bmap_div, &tab->var[r]) < 0)
+		return -1;
+
+	if (add_div_constraints(tab, pos - o_div, add_ineq, user) < 0)
+		return -1;
+
+	return r;
+}
+
+/* Add an extra div, prescribed by "div", to the tableau and
+ * the associated bmap (which is assumed to be non-NULL).
+ */
+int isl_tab_add_div(struct isl_tab *tab, __isl_keep isl_vec *div)
+{
+	if (!tab)
+		return -1;
+	return isl_tab_insert_div(tab, tab->n_var, div, NULL, NULL);
+}
+
+/* If "track" is set, then we want to keep track of all constraints in tab
+ * in its bmap field.  This field is initialized from a copy of "bmap",
+ * so we need to make sure that all constraints in "bmap" also appear
+ * in the constructed tab.
+ */
+__isl_give struct isl_tab *isl_tab_from_basic_map(
+	__isl_keep isl_basic_map *bmap, int track)
+{
+	int i;
+	struct isl_tab *tab;
+
+	if (!bmap)
+		return NULL;
+	tab = isl_tab_alloc(bmap->ctx,
+			    isl_basic_map_total_dim(bmap) + bmap->n_ineq + 1,
+			    isl_basic_map_total_dim(bmap), 0);
+	if (!tab)
+		return NULL;
+	tab->preserve = track;
+	tab->rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) {
+		if (isl_tab_mark_empty(tab) < 0)
+			goto error;
+		goto done;
+	}
+	for (i = 0; i < bmap->n_eq; ++i) {
+		tab = add_eq(tab, bmap->eq[i]);
+		if (!tab)
+			return tab;
+	}
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		if (isl_tab_add_ineq(tab, bmap->ineq[i]) < 0)
+			goto error;
+		if (tab->empty)
+			goto done;
+	}
+done:
+	if (track && isl_tab_track_bmap(tab, isl_basic_map_copy(bmap)) < 0)
+		goto error;
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+__isl_give struct isl_tab *isl_tab_from_basic_set(
+	__isl_keep isl_basic_set *bset, int track)
+{
+	return isl_tab_from_basic_map(bset, track);
+}
+
+/* Construct a tableau corresponding to the recession cone of "bset".
+ */
+struct isl_tab *isl_tab_from_recession_cone(__isl_keep isl_basic_set *bset,
+	int parametric)
+{
+	isl_int cst;
+	int i;
+	struct isl_tab *tab;
+	unsigned offset = 0;
+
+	if (!bset)
+		return NULL;
+	if (parametric)
+		offset = isl_basic_set_dim(bset, isl_dim_param);
+	tab = isl_tab_alloc(bset->ctx, bset->n_eq + bset->n_ineq,
+				isl_basic_set_total_dim(bset) - offset, 0);
+	if (!tab)
+		return NULL;
+	tab->rational = ISL_F_ISSET(bset, ISL_BASIC_SET_RATIONAL);
+	tab->cone = 1;
+
+	isl_int_init(cst);
+	isl_int_set_si(cst, 0);
+	for (i = 0; i < bset->n_eq; ++i) {
+		isl_int_swap(bset->eq[i][offset], cst);
+		if (offset > 0) {
+			if (isl_tab_add_eq(tab, bset->eq[i] + offset) < 0)
+				goto error;
+		} else
+			tab = add_eq(tab, bset->eq[i]);
+		isl_int_swap(bset->eq[i][offset], cst);
+		if (!tab)
+			goto done;
+	}
+	for (i = 0; i < bset->n_ineq; ++i) {
+		int r;
+		isl_int_swap(bset->ineq[i][offset], cst);
+		r = isl_tab_add_row(tab, bset->ineq[i] + offset);
+		isl_int_swap(bset->ineq[i][offset], cst);
+		if (r < 0)
+			goto error;
+		tab->con[r].is_nonneg = 1;
+		if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)
+			goto error;
+	}
+done:
+	isl_int_clear(cst);
+	return tab;
+error:
+	isl_int_clear(cst);
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Assuming "tab" is the tableau of a cone, check if the cone is
+ * bounded, i.e., if it is empty or only contains the origin.
+ */
+isl_bool isl_tab_cone_is_bounded(struct isl_tab *tab)
+{
+	int i;
+
+	if (!tab)
+		return isl_bool_error;
+	if (tab->empty)
+		return isl_bool_true;
+	if (tab->n_dead == tab->n_col)
+		return isl_bool_true;
+
+	for (;;) {
+		for (i = tab->n_redundant; i < tab->n_row; ++i) {
+			struct isl_tab_var *var;
+			int sgn;
+			var = isl_tab_var_from_row(tab, i);
+			if (!var->is_nonneg)
+				continue;
+			sgn = sign_of_max(tab, var);
+			if (sgn < -1)
+				return isl_bool_error;
+			if (sgn != 0)
+				return isl_bool_false;
+			if (close_row(tab, var, 0) < 0)
+				return isl_bool_error;
+			break;
+		}
+		if (tab->n_dead == tab->n_col)
+			return isl_bool_true;
+		if (i == tab->n_row)
+			return isl_bool_false;
+	}
+}
+
+int isl_tab_sample_is_integer(struct isl_tab *tab)
+{
+	int i;
+
+	if (!tab)
+		return -1;
+
+	for (i = 0; i < tab->n_var; ++i) {
+		int row;
+		if (!tab->var[i].is_row)
+			continue;
+		row = tab->var[i].index;
+		if (!isl_int_is_divisible_by(tab->mat->row[row][1],
+						tab->mat->row[row][0]))
+			return 0;
+	}
+	return 1;
+}
+
+static struct isl_vec *extract_integer_sample(struct isl_tab *tab)
+{
+	int i;
+	struct isl_vec *vec;
+
+	vec = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var);
+	if (!vec)
+		return NULL;
+
+	isl_int_set_si(vec->block.data[0], 1);
+	for (i = 0; i < tab->n_var; ++i) {
+		if (!tab->var[i].is_row)
+			isl_int_set_si(vec->block.data[1 + i], 0);
+		else {
+			int row = tab->var[i].index;
+			isl_int_divexact(vec->block.data[1 + i],
+				tab->mat->row[row][1], tab->mat->row[row][0]);
+		}
+	}
+
+	return vec;
+}
+
+struct isl_vec *isl_tab_get_sample_value(struct isl_tab *tab)
+{
+	int i;
+	struct isl_vec *vec;
+	isl_int m;
+
+	if (!tab)
+		return NULL;
+
+	vec = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var);
+	if (!vec)
+		return NULL;
+
+	isl_int_init(m);
+
+	isl_int_set_si(vec->block.data[0], 1);
+	for (i = 0; i < tab->n_var; ++i) {
+		int row;
+		if (!tab->var[i].is_row) {
+			isl_int_set_si(vec->block.data[1 + i], 0);
+			continue;
+		}
+		row = tab->var[i].index;
+		isl_int_gcd(m, vec->block.data[0], tab->mat->row[row][0]);
+		isl_int_divexact(m, tab->mat->row[row][0], m);
+		isl_seq_scale(vec->block.data, vec->block.data, m, 1 + i);
+		isl_int_divexact(m, vec->block.data[0], tab->mat->row[row][0]);
+		isl_int_mul(vec->block.data[1 + i], m, tab->mat->row[row][1]);
+	}
+	vec = isl_vec_normalize(vec);
+
+	isl_int_clear(m);
+	return vec;
+}
+
+/* Store the sample value of "var" of "tab" rounded up (if sgn > 0)
+ * or down (if sgn < 0) to the nearest integer in *v.
+ */
+static void get_rounded_sample_value(struct isl_tab *tab,
+	struct isl_tab_var *var, int sgn, isl_int *v)
+{
+	if (!var->is_row)
+		isl_int_set_si(*v, 0);
+	else if (sgn > 0)
+		isl_int_cdiv_q(*v, tab->mat->row[var->index][1],
+				   tab->mat->row[var->index][0]);
+	else
+		isl_int_fdiv_q(*v, tab->mat->row[var->index][1],
+				   tab->mat->row[var->index][0]);
+}
+
+/* Update "bmap" based on the results of the tableau "tab".
+ * In particular, implicit equalities are made explicit, redundant constraints
+ * are removed and if the sample value happens to be integer, it is stored
+ * in "bmap" (unless "bmap" already had an integer sample).
+ *
+ * The tableau is assumed to have been created from "bmap" using
+ * isl_tab_from_basic_map.
+ */
+struct isl_basic_map *isl_basic_map_update_from_tab(struct isl_basic_map *bmap,
+	struct isl_tab *tab)
+{
+	int i;
+	unsigned n_eq;
+
+	if (!bmap)
+		return NULL;
+	if (!tab)
+		return bmap;
+
+	n_eq = tab->n_eq;
+	if (tab->empty)
+		bmap = isl_basic_map_set_to_empty(bmap);
+	else
+		for (i = bmap->n_ineq - 1; i >= 0; --i) {
+			if (isl_tab_is_equality(tab, n_eq + i))
+				isl_basic_map_inequality_to_equality(bmap, i);
+			else if (isl_tab_is_redundant(tab, n_eq + i))
+				isl_basic_map_drop_inequality(bmap, i);
+		}
+	if (bmap->n_eq != n_eq)
+		bmap = isl_basic_map_gauss(bmap, NULL);
+	if (!tab->rational &&
+	    bmap && !bmap->sample && isl_tab_sample_is_integer(tab))
+		bmap->sample = extract_integer_sample(tab);
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_update_from_tab(struct isl_basic_set *bset,
+	struct isl_tab *tab)
+{
+	return bset_from_bmap(isl_basic_map_update_from_tab(bset_to_bmap(bset),
+								tab));
+}
+
+/* Drop the last constraint added to "tab" in position "r".
+ * The constraint is expected to have remained in a row.
+ */
+static isl_stat drop_last_con_in_row(struct isl_tab *tab, int r)
+{
+	if (!tab->con[r].is_row)
+		isl_die(isl_tab_get_ctx(tab), isl_error_internal,
+			"row unexpectedly moved to column",
+			return isl_stat_error);
+	if (r + 1 != tab->n_con)
+		isl_die(isl_tab_get_ctx(tab), isl_error_internal,
+			"additional constraints added", return isl_stat_error);
+	if (drop_row(tab, tab->con[r].index) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Given a non-negative variable "var", temporarily add a new non-negative
+ * variable that is the opposite of "var", ensuring that "var" can only attain
+ * the value zero.  The new variable is removed again before this function
+ * returns.  However, the effect of forcing "var" to be zero remains.
+ * If var = n/d is a row variable, then the new variable = -n/d.
+ * If var is a column variables, then the new variable = -var.
+ * If the new variable cannot attain non-negative values, then
+ * the resulting tableau is empty.
+ * Otherwise, we know the value will be zero and we close the row.
+ */
+static isl_stat cut_to_hyperplane(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	unsigned r;
+	isl_int *row;
+	int sgn;
+	unsigned off = 2 + tab->M;
+
+	if (var->is_zero)
+		return isl_stat_ok;
+	if (var->is_redundant || !var->is_nonneg)
+		isl_die(isl_tab_get_ctx(tab), isl_error_invalid,
+			"expecting non-redundant non-negative variable",
+			return isl_stat_error);
+
+	if (isl_tab_extend_cons(tab, 1) < 0)
+		return isl_stat_error;
+
+	r = tab->n_con;
+	tab->con[r].index = tab->n_row;
+	tab->con[r].is_row = 1;
+	tab->con[r].is_nonneg = 0;
+	tab->con[r].is_zero = 0;
+	tab->con[r].is_redundant = 0;
+	tab->con[r].frozen = 0;
+	tab->con[r].negated = 0;
+	tab->row_var[tab->n_row] = ~r;
+	row = tab->mat->row[tab->n_row];
+
+	if (var->is_row) {
+		isl_int_set(row[0], tab->mat->row[var->index][0]);
+		isl_seq_neg(row + 1,
+			    tab->mat->row[var->index] + 1, 1 + tab->n_col);
+	} else {
+		isl_int_set_si(row[0], 1);
+		isl_seq_clr(row + 1, 1 + tab->n_col);
+		isl_int_set_si(row[off + var->index], -1);
+	}
+
+	tab->n_row++;
+	tab->n_con++;
+
+	sgn = sign_of_max(tab, &tab->con[r]);
+	if (sgn < -1)
+		return isl_stat_error;
+	if (sgn < 0) {
+		if (drop_last_con_in_row(tab, r) < 0)
+			return isl_stat_error;
+		if (isl_tab_mark_empty(tab) < 0)
+			return isl_stat_error;
+		return isl_stat_ok;
+	}
+	tab->con[r].is_nonneg = 1;
+	/* sgn == 0 */
+	if (close_row(tab, &tab->con[r], 1) < 0)
+		return isl_stat_error;
+	if (drop_last_con_in_row(tab, r) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Given a tableau "tab" and an inequality constraint "con" of the tableau,
+ * relax the inequality by one.  That is, the inequality r >= 0 is replaced
+ * by r' = r + 1 >= 0.
+ * If r is a row variable, we simply increase the constant term by one
+ * (taking into account the denominator).
+ * If r is a column variable, then we need to modify each row that
+ * refers to r = r' - 1 by substituting this equality, effectively
+ * subtracting the coefficient of the column from the constant.
+ * We should only do this if the minimum is manifestly unbounded,
+ * however.  Otherwise, we may end up with negative sample values
+ * for non-negative variables.
+ * So, if r is a column variable with a minimum that is not
+ * manifestly unbounded, then we need to move it to a row.
+ * However, the sample value of this row may be negative,
+ * even after the relaxation, so we need to restore it.
+ * We therefore prefer to pivot a column up to a row, if possible.
+ */
+int isl_tab_relax(struct isl_tab *tab, int con)
+{
+	struct isl_tab_var *var;
+
+	if (!tab)
+		return -1;
+
+	var = &tab->con[con];
+
+	if (var->is_row && (var->index < 0 || var->index < tab->n_redundant))
+		isl_die(tab->mat->ctx, isl_error_invalid,
+			"cannot relax redundant constraint", return -1);
+	if (!var->is_row && (var->index < 0 || var->index < tab->n_dead))
+		isl_die(tab->mat->ctx, isl_error_invalid,
+			"cannot relax dead constraint", return -1);
+
+	if (!var->is_row && !max_is_manifestly_unbounded(tab, var))
+		if (to_row(tab, var, 1) < 0)
+			return -1;
+	if (!var->is_row && !min_is_manifestly_unbounded(tab, var))
+		if (to_row(tab, var, -1) < 0)
+			return -1;
+
+	if (var->is_row) {
+		isl_int_add(tab->mat->row[var->index][1],
+		    tab->mat->row[var->index][1], tab->mat->row[var->index][0]);
+		if (restore_row(tab, var) < 0)
+			return -1;
+	} else {
+		int i;
+		unsigned off = 2 + tab->M;
+
+		for (i = 0; i < tab->n_row; ++i) {
+			if (isl_int_is_zero(tab->mat->row[i][off + var->index]))
+				continue;
+			isl_int_sub(tab->mat->row[i][1], tab->mat->row[i][1],
+			    tab->mat->row[i][off + var->index]);
+		}
+
+	}
+
+	if (isl_tab_push_var(tab, isl_tab_undo_relax, var) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Replace the variable v at position "pos" in the tableau "tab"
+ * by v' = v + shift.
+ *
+ * If the variable is in a column, then we first check if we can
+ * simply plug in v = v' - shift.  The effect on a row with
+ * coefficient f/d for variable v is that the constant term c/d
+ * is replaced by (c - f * shift)/d.  If shift is positive and
+ * f is negative for each row that needs to remain non-negative,
+ * then this is clearly safe.  In other words, if the minimum of v
+ * is manifestly unbounded, then we can keep v in a column position.
+ * Otherwise, we can pivot it down to a row.
+ * Similarly, if shift is negative, we need to check if the maximum
+ * of is manifestly unbounded.
+ *
+ * If the variable is in a row (from the start or after pivoting),
+ * then the constant term c/d is replaced by (c + d * shift)/d.
+ */
+int isl_tab_shift_var(struct isl_tab *tab, int pos, isl_int shift)
+{
+	struct isl_tab_var *var;
+
+	if (!tab)
+		return -1;
+	if (isl_int_is_zero(shift))
+		return 0;
+
+	var = &tab->var[pos];
+	if (!var->is_row) {
+		if (isl_int_is_neg(shift)) {
+			if (!max_is_manifestly_unbounded(tab, var))
+				if (to_row(tab, var, 1) < 0)
+					return -1;
+		} else {
+			if (!min_is_manifestly_unbounded(tab, var))
+				if (to_row(tab, var, -1) < 0)
+					return -1;
+		}
+	}
+
+	if (var->is_row) {
+		isl_int_addmul(tab->mat->row[var->index][1],
+				shift, tab->mat->row[var->index][0]);
+	} else {
+		int i;
+		unsigned off = 2 + tab->M;
+
+		for (i = 0; i < tab->n_row; ++i) {
+			if (isl_int_is_zero(tab->mat->row[i][off + var->index]))
+				continue;
+			isl_int_submul(tab->mat->row[i][1],
+				    shift, tab->mat->row[i][off + var->index]);
+		}
+
+	}
+
+	return 0;
+}
+
+/* Remove the sign constraint from constraint "con".
+ *
+ * If the constraint variable was originally marked non-negative,
+ * then we make sure we mark it non-negative again during rollback.
+ */
+int isl_tab_unrestrict(struct isl_tab *tab, int con)
+{
+	struct isl_tab_var *var;
+
+	if (!tab)
+		return -1;
+
+	var = &tab->con[con];
+	if (!var->is_nonneg)
+		return 0;
+
+	var->is_nonneg = 0;
+	if (isl_tab_push_var(tab, isl_tab_undo_unrestrict, var) < 0)
+		return -1;
+
+	return 0;
+}
+
+int isl_tab_select_facet(struct isl_tab *tab, int con)
+{
+	if (!tab)
+		return -1;
+
+	return cut_to_hyperplane(tab, &tab->con[con]);
+}
+
+static int may_be_equality(struct isl_tab *tab, int row)
+{
+	return tab->rational ? isl_int_is_zero(tab->mat->row[row][1])
+			     : isl_int_lt(tab->mat->row[row][1],
+					    tab->mat->row[row][0]);
+}
+
+/* Return an isl_tab_var that has been marked or NULL if no such
+ * variable can be found.
+ * The marked field has only been set for variables that
+ * appear in non-redundant rows or non-dead columns.
+ *
+ * Pick the last constraint variable that is marked and
+ * that appears in either a non-redundant row or a non-dead columns.
+ * Since the returned variable is tested for being a redundant constraint or
+ * an implicit equality, there is no need to return any tab variable that
+ * corresponds to a variable.
+ */
+static struct isl_tab_var *select_marked(struct isl_tab *tab)
+{
+	int i;
+	struct isl_tab_var *var;
+
+	for (i = tab->n_con - 1; i >= 0; --i) {
+		var = &tab->con[i];
+		if (var->index < 0)
+			continue;
+		if (var->is_row && var->index < tab->n_redundant)
+			continue;
+		if (!var->is_row && var->index < tab->n_dead)
+			continue;
+		if (var->marked)
+			return var;
+	}
+
+	return NULL;
+}
+
+/* Check for (near) equalities among the constraints.
+ * A constraint is an equality if it is non-negative and if
+ * its maximal value is either
+ *	- zero (in case of rational tableaus), or
+ *	- strictly less than 1 (in case of integer tableaus)
+ *
+ * We first mark all non-redundant and non-dead variables that
+ * are not frozen and not obviously not an equality.
+ * Then we iterate over all marked variables if they can attain
+ * any values larger than zero or at least one.
+ * If the maximal value is zero, we mark any column variables
+ * that appear in the row as being zero and mark the row as being redundant.
+ * Otherwise, if the maximal value is strictly less than one (and the
+ * tableau is integer), then we restrict the value to being zero
+ * by adding an opposite non-negative variable.
+ * The order in which the variables are considered is not important.
+ */
+int isl_tab_detect_implicit_equalities(struct isl_tab *tab)
+{
+	int i;
+	unsigned n_marked;
+
+	if (!tab)
+		return -1;
+	if (tab->empty)
+		return 0;
+	if (tab->n_dead == tab->n_col)
+		return 0;
+
+	n_marked = 0;
+	for (i = tab->n_redundant; i < tab->n_row; ++i) {
+		struct isl_tab_var *var = isl_tab_var_from_row(tab, i);
+		var->marked = !var->frozen && var->is_nonneg &&
+			may_be_equality(tab, i);
+		if (var->marked)
+			n_marked++;
+	}
+	for (i = tab->n_dead; i < tab->n_col; ++i) {
+		struct isl_tab_var *var = var_from_col(tab, i);
+		var->marked = !var->frozen && var->is_nonneg;
+		if (var->marked)
+			n_marked++;
+	}
+	while (n_marked) {
+		struct isl_tab_var *var;
+		int sgn;
+		var = select_marked(tab);
+		if (!var)
+			break;
+		var->marked = 0;
+		n_marked--;
+		sgn = sign_of_max(tab, var);
+		if (sgn < 0)
+			return -1;
+		if (sgn == 0) {
+			if (close_row(tab, var, 0) < 0)
+				return -1;
+		} else if (!tab->rational && !at_least_one(tab, var)) {
+			if (cut_to_hyperplane(tab, var) < 0)
+				return -1;
+			return isl_tab_detect_implicit_equalities(tab);
+		}
+		for (i = tab->n_redundant; i < tab->n_row; ++i) {
+			var = isl_tab_var_from_row(tab, i);
+			if (!var->marked)
+				continue;
+			if (may_be_equality(tab, i))
+				continue;
+			var->marked = 0;
+			n_marked--;
+		}
+	}
+
+	return 0;
+}
+
+/* Update the element of row_var or col_var that corresponds to
+ * constraint tab->con[i] to a move from position "old" to position "i".
+ */
+static int update_con_after_move(struct isl_tab *tab, int i, int old)
+{
+	int *p;
+	int index;
+
+	index = tab->con[i].index;
+	if (index == -1)
+		return 0;
+	p = tab->con[i].is_row ? tab->row_var : tab->col_var;
+	if (p[index] != ~old)
+		isl_die(tab->mat->ctx, isl_error_internal,
+			"broken internal state", return -1);
+	p[index] = ~i;
+
+	return 0;
+}
+
+/* Rotate the "n" constraints starting at "first" to the right,
+ * putting the last constraint in the position of the first constraint.
+ */
+static int rotate_constraints(struct isl_tab *tab, int first, int n)
+{
+	int i, last;
+	struct isl_tab_var var;
+
+	if (n <= 1)
+		return 0;
+
+	last = first + n - 1;
+	var = tab->con[last];
+	for (i = last; i > first; --i) {
+		tab->con[i] = tab->con[i - 1];
+		if (update_con_after_move(tab, i, i - 1) < 0)
+			return -1;
+	}
+	tab->con[first] = var;
+	if (update_con_after_move(tab, first, last) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Make the equalities that are implicit in "bmap" but that have been
+ * detected in the corresponding "tab" explicit in "bmap" and update
+ * "tab" to reflect the new order of the constraints.
+ *
+ * In particular, if inequality i is an implicit equality then
+ * isl_basic_map_inequality_to_equality will move the inequality
+ * in front of the other equality and it will move the last inequality
+ * in the position of inequality i.
+ * In the tableau, the inequalities of "bmap" are stored after the equalities
+ * and so the original order
+ *
+ *		E E E E E A A A I B B B B L
+ *
+ * is changed into
+ *
+ *		I E E E E E A A A L B B B B
+ *
+ * where I is the implicit equality, the E are equalities,
+ * the A inequalities before I, the B inequalities after I and
+ * L the last inequality.
+ * We therefore need to rotate to the right two sets of constraints,
+ * those up to and including I and those after I.
+ *
+ * If "tab" contains any constraints that are not in "bmap" then they
+ * appear after those in "bmap" and they should be left untouched.
+ *
+ * Note that this function leaves "bmap" in a temporary state
+ * as it does not call isl_basic_map_gauss.  Calling this function
+ * is the responsibility of the caller.
+ */
+__isl_give isl_basic_map *isl_tab_make_equalities_explicit(struct isl_tab *tab,
+	__isl_take isl_basic_map *bmap)
+{
+	int i;
+
+	if (!tab || !bmap)
+		return isl_basic_map_free(bmap);
+	if (tab->empty)
+		return bmap;
+
+	for (i = bmap->n_ineq - 1; i >= 0; --i) {
+		if (!isl_tab_is_equality(tab, bmap->n_eq + i))
+			continue;
+		isl_basic_map_inequality_to_equality(bmap, i);
+		if (rotate_constraints(tab, 0, tab->n_eq + i + 1) < 0)
+			return isl_basic_map_free(bmap);
+		if (rotate_constraints(tab, tab->n_eq + i + 1,
+					bmap->n_ineq - i) < 0)
+			return isl_basic_map_free(bmap);
+		tab->n_eq++;
+	}
+
+	return bmap;
+}
+
+static int con_is_redundant(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	if (!tab)
+		return -1;
+	if (tab->rational) {
+		int sgn = sign_of_min(tab, var);
+		if (sgn < -1)
+			return -1;
+		return sgn >= 0;
+	} else {
+		int irred = isl_tab_min_at_most_neg_one(tab, var);
+		if (irred < 0)
+			return -1;
+		return !irred;
+	}
+}
+
+/* Check for (near) redundant constraints.
+ * A constraint is redundant if it is non-negative and if
+ * its minimal value (temporarily ignoring the non-negativity) is either
+ *	- zero (in case of rational tableaus), or
+ *	- strictly larger than -1 (in case of integer tableaus)
+ *
+ * We first mark all non-redundant and non-dead variables that
+ * are not frozen and not obviously negatively unbounded.
+ * Then we iterate over all marked variables if they can attain
+ * any values smaller than zero or at most negative one.
+ * If not, we mark the row as being redundant (assuming it hasn't
+ * been detected as being obviously redundant in the mean time).
+ */
+int isl_tab_detect_redundant(struct isl_tab *tab)
+{
+	int i;
+	unsigned n_marked;
+
+	if (!tab)
+		return -1;
+	if (tab->empty)
+		return 0;
+	if (tab->n_redundant == tab->n_row)
+		return 0;
+
+	n_marked = 0;
+	for (i = tab->n_redundant; i < tab->n_row; ++i) {
+		struct isl_tab_var *var = isl_tab_var_from_row(tab, i);
+		var->marked = !var->frozen && var->is_nonneg;
+		if (var->marked)
+			n_marked++;
+	}
+	for (i = tab->n_dead; i < tab->n_col; ++i) {
+		struct isl_tab_var *var = var_from_col(tab, i);
+		var->marked = !var->frozen && var->is_nonneg &&
+			!min_is_manifestly_unbounded(tab, var);
+		if (var->marked)
+			n_marked++;
+	}
+	while (n_marked) {
+		struct isl_tab_var *var;
+		int red;
+		var = select_marked(tab);
+		if (!var)
+			break;
+		var->marked = 0;
+		n_marked--;
+		red = con_is_redundant(tab, var);
+		if (red < 0)
+			return -1;
+		if (red && !var->is_redundant)
+			if (isl_tab_mark_redundant(tab, var->index) < 0)
+				return -1;
+		for (i = tab->n_dead; i < tab->n_col; ++i) {
+			var = var_from_col(tab, i);
+			if (!var->marked)
+				continue;
+			if (!min_is_manifestly_unbounded(tab, var))
+				continue;
+			var->marked = 0;
+			n_marked--;
+		}
+	}
+
+	return 0;
+}
+
+int isl_tab_is_equality(struct isl_tab *tab, int con)
+{
+	int row;
+	unsigned off;
+
+	if (!tab)
+		return -1;
+	if (tab->con[con].is_zero)
+		return 1;
+	if (tab->con[con].is_redundant)
+		return 0;
+	if (!tab->con[con].is_row)
+		return tab->con[con].index < tab->n_dead;
+
+	row = tab->con[con].index;
+
+	off = 2 + tab->M;
+	return isl_int_is_zero(tab->mat->row[row][1]) &&
+		!row_is_big(tab, row) &&
+		isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead,
+					tab->n_col - tab->n_dead) == -1;
+}
+
+/* Return the minimal value of the affine expression "f" with denominator
+ * "denom" in *opt, *opt_denom, assuming the tableau is not empty and
+ * the expression cannot attain arbitrarily small values.
+ * If opt_denom is NULL, then *opt is rounded up to the nearest integer.
+ * The return value reflects the nature of the result (empty, unbounded,
+ * minimal value returned in *opt).
+ *
+ * This function assumes that at least one more row and at least
+ * one more element in the constraint array are available in the tableau.
+ */
+enum isl_lp_result isl_tab_min(struct isl_tab *tab,
+	isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+	unsigned flags)
+{
+	int r;
+	enum isl_lp_result res = isl_lp_ok;
+	struct isl_tab_var *var;
+	struct isl_tab_undo *snap;
+
+	if (!tab)
+		return isl_lp_error;
+
+	if (tab->empty)
+		return isl_lp_empty;
+
+	snap = isl_tab_snap(tab);
+	r = isl_tab_add_row(tab, f);
+	if (r < 0)
+		return isl_lp_error;
+	var = &tab->con[r];
+	for (;;) {
+		int row, col;
+		find_pivot(tab, var, var, -1, &row, &col);
+		if (row == var->index) {
+			res = isl_lp_unbounded;
+			break;
+		}
+		if (row == -1)
+			break;
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return isl_lp_error;
+	}
+	isl_int_mul(tab->mat->row[var->index][0],
+		    tab->mat->row[var->index][0], denom);
+	if (ISL_FL_ISSET(flags, ISL_TAB_SAVE_DUAL)) {
+		int i;
+
+		isl_vec_free(tab->dual);
+		tab->dual = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_con);
+		if (!tab->dual)
+			return isl_lp_error;
+		isl_int_set(tab->dual->el[0], tab->mat->row[var->index][0]);
+		for (i = 0; i < tab->n_con; ++i) {
+			int pos;
+			if (tab->con[i].is_row) {
+				isl_int_set_si(tab->dual->el[1 + i], 0);
+				continue;
+			}
+			pos = 2 + tab->M + tab->con[i].index;
+			if (tab->con[i].negated)
+				isl_int_neg(tab->dual->el[1 + i],
+					    tab->mat->row[var->index][pos]);
+			else
+				isl_int_set(tab->dual->el[1 + i],
+					    tab->mat->row[var->index][pos]);
+		}
+	}
+	if (opt && res == isl_lp_ok) {
+		if (opt_denom) {
+			isl_int_set(*opt, tab->mat->row[var->index][1]);
+			isl_int_set(*opt_denom, tab->mat->row[var->index][0]);
+		} else
+			get_rounded_sample_value(tab, var, 1, opt);
+	}
+	if (isl_tab_rollback(tab, snap) < 0)
+		return isl_lp_error;
+	return res;
+}
+
+/* Is the constraint at position "con" marked as being redundant?
+ * If it is marked as representing an equality, then it is not
+ * considered to be redundant.
+ * Note that isl_tab_mark_redundant marks both the isl_tab_var as
+ * redundant and moves the corresponding row into the first
+ * tab->n_redundant positions (or removes the row, assigning it index -1),
+ * so the final test is actually redundant itself.
+ */
+int isl_tab_is_redundant(struct isl_tab *tab, int con)
+{
+	if (!tab)
+		return -1;
+	if (con < 0 || con >= tab->n_con)
+		isl_die(isl_tab_get_ctx(tab), isl_error_invalid,
+			"position out of bounds", return -1);
+	if (tab->con[con].is_zero)
+		return 0;
+	if (tab->con[con].is_redundant)
+		return 1;
+	return tab->con[con].is_row && tab->con[con].index < tab->n_redundant;
+}
+
+/* Is variable "var" of "tab" fixed to a constant value by its row
+ * in the tableau?
+ * If so and if "value" is not NULL, then store this constant value
+ * in "value".
+ *
+ * That is, is it a row variable that only has non-zero coefficients
+ * for dead columns?
+ */
+static isl_bool is_constant(struct isl_tab *tab, struct isl_tab_var *var,
+	isl_int *value)
+{
+	unsigned off = 2 + tab->M;
+	isl_mat *mat = tab->mat;
+	int n;
+	int row;
+	int pos;
+
+	if (!var->is_row)
+		return isl_bool_false;
+	row = var->index;
+	if (row_is_big(tab, row))
+		return isl_bool_false;
+	n = tab->n_col - tab->n_dead;
+	pos = isl_seq_first_non_zero(mat->row[row] + off + tab->n_dead, n);
+	if (pos != -1)
+		return isl_bool_false;
+	if (value)
+		isl_int_divexact(*value, mat->row[row][1], mat->row[row][0]);
+	return isl_bool_true;
+}
+
+/* Has the variable "var' of "tab" reached a value that is greater than
+ * or equal (if sgn > 0) or smaller than or equal (if sgn < 0) to "target"?
+ * "tmp" has been initialized by the caller and can be used
+ * to perform local computations.
+ *
+ * If the sample value involves the big parameter, then any value
+ * is reached.
+ * Otherwise check if n/d >= t, i.e., n >= d * t (if sgn > 0)
+ * or n/d <= t, i.e., n <= d * t (if sgn < 0).
+ */
+static int reached(struct isl_tab *tab, struct isl_tab_var *var, int sgn,
+	isl_int target, isl_int *tmp)
+{
+	if (row_is_big(tab, var->index))
+		return 1;
+	isl_int_mul(*tmp, tab->mat->row[var->index][0], target);
+	if (sgn > 0)
+		return isl_int_ge(tab->mat->row[var->index][1], *tmp);
+	else
+		return isl_int_le(tab->mat->row[var->index][1], *tmp);
+}
+
+/* Can variable "var" of "tab" attain the value "target" by
+ * pivoting up (if sgn > 0) or down (if sgn < 0)?
+ * If not, then pivot up [down] to the greatest [smallest]
+ * rational value.
+ * "tmp" has been initialized by the caller and can be used
+ * to perform local computations.
+ *
+ * If the variable is manifestly unbounded in the desired direction,
+ * then it can attain any value.
+ * Otherwise, it can be moved to a row.
+ * Continue pivoting until the target is reached.
+ * If no more pivoting can be performed, the maximal [minimal]
+ * rational value has been reached and the target cannot be reached.
+ * If the variable would be pivoted into a manifestly unbounded column,
+ * then the target can be reached.
+ */
+static isl_bool var_reaches(struct isl_tab *tab, struct isl_tab_var *var,
+	int sgn, isl_int target, isl_int *tmp)
+{
+	int row, col;
+
+	if (sgn < 0 && min_is_manifestly_unbounded(tab, var))
+		return isl_bool_true;
+	if (sgn > 0 && max_is_manifestly_unbounded(tab, var))
+		return isl_bool_true;
+	if (to_row(tab, var, sgn) < 0)
+		return isl_bool_error;
+	while (!reached(tab, var, sgn, target, tmp)) {
+		find_pivot(tab, var, var, sgn, &row, &col);
+		if (row == -1)
+			return isl_bool_false;
+		if (row == var->index)
+			return isl_bool_true;
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return isl_bool_error;
+	}
+
+	return isl_bool_true;
+}
+
+/* Check if variable "var" of "tab" can only attain a single (integer)
+ * value, and, if so, add an equality constraint to fix the variable
+ * to this single value and store the result in "target".
+ * "target" and "tmp" have been initialized by the caller.
+ *
+ * Given the current sample value, round it down and check
+ * whether it is possible to attain a strictly smaller integer value.
+ * If so, the variable is not restricted to a single integer value.
+ * Otherwise, the search stops at the smallest rational value.
+ * Round up this value and check whether it is possible to attain
+ * a strictly greater integer value.
+ * If so, the variable is not restricted to a single integer value.
+ * Otherwise, the search stops at the greatest rational value.
+ * If rounding down this value yields a value that is different
+ * from rounding up the smallest rational value, then the variable
+ * cannot attain any integer value.  Mark the tableau empty.
+ * Otherwise, add an equality constraint that fixes the variable
+ * to the single integer value found.
+ */
+static isl_bool detect_constant_with_tmp(struct isl_tab *tab,
+	struct isl_tab_var *var, isl_int *target, isl_int *tmp)
+{
+	isl_bool reached;
+	isl_vec *eq;
+	int pos;
+	isl_stat r;
+
+	get_rounded_sample_value(tab, var, -1, target);
+	isl_int_sub_ui(*target, *target, 1);
+	reached = var_reaches(tab, var, -1, *target, tmp);
+	if (reached < 0 || reached)
+		return isl_bool_not(reached);
+	get_rounded_sample_value(tab, var, 1, target);
+	isl_int_add_ui(*target, *target, 1);
+	reached = var_reaches(tab, var, 1, *target, tmp);
+	if (reached < 0 || reached)
+		return isl_bool_not(reached);
+	get_rounded_sample_value(tab, var, -1, tmp);
+	isl_int_sub_ui(*target, *target, 1);
+	if (isl_int_ne(*target, *tmp)) {
+		if (isl_tab_mark_empty(tab) < 0)
+			return isl_bool_error;
+		return isl_bool_false;
+	}
+
+	if (isl_tab_extend_cons(tab, 1) < 0)
+		return isl_bool_error;
+	eq = isl_vec_alloc(isl_tab_get_ctx(tab), 1 + tab->n_var);
+	if (!eq)
+		return isl_bool_error;
+	pos = var - tab->var;
+	isl_seq_clr(eq->el + 1, tab->n_var);
+	isl_int_set_si(eq->el[1 + pos], -1);
+	isl_int_set(eq->el[0], *target);
+	r = isl_tab_add_eq(tab, eq->el);
+	isl_vec_free(eq);
+
+	return r < 0 ? isl_bool_error : isl_bool_true;
+}
+
+/* Check if variable "var" of "tab" can only attain a single (integer)
+ * value, and, if so, add an equality constraint to fix the variable
+ * to this single value and store the result in "value" (if "value"
+ * is not NULL).
+ *
+ * If the current sample value involves the big parameter,
+ * then the variable cannot have a fixed integer value.
+ * If the variable is already fixed to a single value by its row, then
+ * there is no need to add another equality constraint.
+ *
+ * Otherwise, allocate some temporary variables and continue
+ * with detect_constant_with_tmp.
+ */
+static isl_bool get_constant(struct isl_tab *tab, struct isl_tab_var *var,
+	isl_int *value)
+{
+	isl_int target, tmp;
+	isl_bool is_cst;
+
+	if (var->is_row && row_is_big(tab, var->index))
+		return isl_bool_false;
+	is_cst = is_constant(tab, var, value);
+	if (is_cst < 0 || is_cst)
+		return is_cst;
+
+	if (!value)
+		isl_int_init(target);
+	isl_int_init(tmp);
+
+	is_cst = detect_constant_with_tmp(tab, var,
+					    value ? value : &target, &tmp);
+
+	isl_int_clear(tmp);
+	if (!value)
+		isl_int_clear(target);
+
+	return is_cst;
+}
+
+/* Check if variable "var" of "tab" can only attain a single (integer)
+ * value, and, if so, add an equality constraint to fix the variable
+ * to this single value and store the result in "value" (if "value"
+ * is not NULL).
+ *
+ * For rational tableaus, nothing needs to be done.
+ */
+isl_bool isl_tab_is_constant(struct isl_tab *tab, int var, isl_int *value)
+{
+	if (!tab)
+		return isl_bool_error;
+	if (var < 0 || var >= tab->n_var)
+		isl_die(isl_tab_get_ctx(tab), isl_error_invalid,
+			"position out of bounds", return isl_bool_error);
+	if (tab->rational)
+		return isl_bool_false;
+
+	return get_constant(tab, &tab->var[var], value);
+}
+
+/* Check if any of the variables of "tab" can only attain a single (integer)
+ * value, and, if so, add equality constraints to fix those variables
+ * to these single values.
+ *
+ * For rational tableaus, nothing needs to be done.
+ */
+isl_stat isl_tab_detect_constants(struct isl_tab *tab)
+{
+	int i;
+
+	if (!tab)
+		return isl_stat_error;
+	if (tab->rational)
+		return isl_stat_ok;
+
+	for (i = 0; i < tab->n_var; ++i) {
+		if (get_constant(tab, &tab->var[i], NULL) < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Take a snapshot of the tableau that can be restored by a call to
+ * isl_tab_rollback.
+ */
+struct isl_tab_undo *isl_tab_snap(struct isl_tab *tab)
+{
+	if (!tab)
+		return NULL;
+	tab->need_undo = 1;
+	return tab->top;
+}
+
+/* Does "tab" need to keep track of undo information?
+ * That is, was a snapshot taken that may need to be restored?
+ */
+isl_bool isl_tab_need_undo(struct isl_tab *tab)
+{
+	if (!tab)
+		return isl_bool_error;
+
+	return tab->need_undo;
+}
+
+/* Remove all tracking of undo information from "tab", invalidating
+ * any snapshots that may have been taken of the tableau.
+ * Since all snapshots have been invalidated, there is also
+ * no need to start keeping track of undo information again.
+ */
+void isl_tab_clear_undo(struct isl_tab *tab)
+{
+	if (!tab)
+		return;
+
+	free_undo(tab);
+	tab->need_undo = 0;
+}
+
+/* Undo the operation performed by isl_tab_relax.
+ */
+static isl_stat unrelax(struct isl_tab *tab, struct isl_tab_var *var)
+	WARN_UNUSED;
+static isl_stat unrelax(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	unsigned off = 2 + tab->M;
+
+	if (!var->is_row && !max_is_manifestly_unbounded(tab, var))
+		if (to_row(tab, var, 1) < 0)
+			return isl_stat_error;
+
+	if (var->is_row) {
+		isl_int_sub(tab->mat->row[var->index][1],
+		    tab->mat->row[var->index][1], tab->mat->row[var->index][0]);
+		if (var->is_nonneg) {
+			int sgn = restore_row(tab, var);
+			isl_assert(tab->mat->ctx, sgn >= 0,
+				return isl_stat_error);
+		}
+	} else {
+		int i;
+
+		for (i = 0; i < tab->n_row; ++i) {
+			if (isl_int_is_zero(tab->mat->row[i][off + var->index]))
+				continue;
+			isl_int_add(tab->mat->row[i][1], tab->mat->row[i][1],
+			    tab->mat->row[i][off + var->index]);
+		}
+
+	}
+
+	return isl_stat_ok;
+}
+
+/* Undo the operation performed by isl_tab_unrestrict.
+ *
+ * In particular, mark the variable as being non-negative and make
+ * sure the sample value respects this constraint.
+ */
+static isl_stat ununrestrict(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	var->is_nonneg = 1;
+
+	if (var->is_row && restore_row(tab, var) < -1)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Unmark the last redundant row in "tab" as being redundant.
+ * This undoes part of the modifications performed by isl_tab_mark_redundant.
+ * In particular, remove the redundant mark and make
+ * sure the sample value respects the constraint again.
+ * A variable that is marked non-negative by isl_tab_mark_redundant
+ * is covered by a separate undo record.
+ */
+static isl_stat restore_last_redundant(struct isl_tab *tab)
+{
+	struct isl_tab_var *var;
+
+	if (tab->n_redundant < 1)
+		isl_die(isl_tab_get_ctx(tab), isl_error_internal,
+			"no redundant rows", return isl_stat_error);
+
+	var = isl_tab_var_from_row(tab, tab->n_redundant - 1);
+	var->is_redundant = 0;
+	tab->n_redundant--;
+	restore_row(tab, var);
+
+	return isl_stat_ok;
+}
+
+static isl_stat perform_undo_var(struct isl_tab *tab, struct isl_tab_undo *undo)
+	WARN_UNUSED;
+static isl_stat perform_undo_var(struct isl_tab *tab, struct isl_tab_undo *undo)
+{
+	struct isl_tab_var *var = var_from_index(tab, undo->u.var_index);
+	switch (undo->type) {
+	case isl_tab_undo_nonneg:
+		var->is_nonneg = 0;
+		break;
+	case isl_tab_undo_redundant:
+		if (!var->is_row || var->index != tab->n_redundant - 1)
+			isl_die(isl_tab_get_ctx(tab), isl_error_internal,
+				"not undoing last redundant row", return -1);
+		return restore_last_redundant(tab);
+	case isl_tab_undo_freeze:
+		var->frozen = 0;
+		break;
+	case isl_tab_undo_zero:
+		var->is_zero = 0;
+		if (!var->is_row)
+			tab->n_dead--;
+		break;
+	case isl_tab_undo_allocate:
+		if (undo->u.var_index >= 0) {
+			isl_assert(tab->mat->ctx, !var->is_row,
+				return isl_stat_error);
+			return drop_col(tab, var->index);
+		}
+		if (!var->is_row) {
+			if (!max_is_manifestly_unbounded(tab, var)) {
+				if (to_row(tab, var, 1) < 0)
+					return isl_stat_error;
+			} else if (!min_is_manifestly_unbounded(tab, var)) {
+				if (to_row(tab, var, -1) < 0)
+					return isl_stat_error;
+			} else
+				if (to_row(tab, var, 0) < 0)
+					return isl_stat_error;
+		}
+		return drop_row(tab, var->index);
+	case isl_tab_undo_relax:
+		return unrelax(tab, var);
+	case isl_tab_undo_unrestrict:
+		return ununrestrict(tab, var);
+	default:
+		isl_die(tab->mat->ctx, isl_error_internal,
+			"perform_undo_var called on invalid undo record",
+			return isl_stat_error);
+	}
+
+	return isl_stat_ok;
+}
+
+/* Restore all rows that have been marked redundant by isl_tab_mark_redundant
+ * and that have been preserved in the tableau.
+ * Note that isl_tab_mark_redundant may also have marked some variables
+ * as being non-negative before marking them redundant.  These need
+ * to be removed as well as otherwise some constraints could end up
+ * getting marked redundant with respect to the variable.
+ */
+isl_stat isl_tab_restore_redundant(struct isl_tab *tab)
+{
+	if (!tab)
+		return isl_stat_error;
+
+	if (tab->need_undo)
+		isl_die(isl_tab_get_ctx(tab), isl_error_invalid,
+			"manually restoring redundant constraints "
+			"interferes with undo history",
+			return isl_stat_error);
+
+	while (tab->n_redundant > 0) {
+		if (tab->row_var[tab->n_redundant - 1] >= 0) {
+			struct isl_tab_var *var;
+
+			var = isl_tab_var_from_row(tab, tab->n_redundant - 1);
+			var->is_nonneg = 0;
+		}
+		restore_last_redundant(tab);
+	}
+	return isl_stat_ok;
+}
+
+/* Undo the addition of an integer division to the basic map representation
+ * of "tab" in position "pos".
+ */
+static isl_stat drop_bmap_div(struct isl_tab *tab, int pos)
+{
+	int off;
+
+	off = tab->n_var - isl_basic_map_dim(tab->bmap, isl_dim_div);
+	if (isl_basic_map_drop_div(tab->bmap, pos - off) < 0)
+		return isl_stat_error;
+	if (tab->samples) {
+		tab->samples = isl_mat_drop_cols(tab->samples, 1 + pos, 1);
+		if (!tab->samples)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Restore the tableau to the state where the basic variables
+ * are those in "col_var".
+ * We first construct a list of variables that are currently in
+ * the basis, but shouldn't.  Then we iterate over all variables
+ * that should be in the basis and for each one that is currently
+ * not in the basis, we exchange it with one of the elements of the
+ * list constructed before.
+ * We can always find an appropriate variable to pivot with because
+ * the current basis is mapped to the old basis by a non-singular
+ * matrix and so we can never end up with a zero row.
+ */
+static int restore_basis(struct isl_tab *tab, int *col_var)
+{
+	int i, j;
+	int n_extra = 0;
+	int *extra = NULL;	/* current columns that contain bad stuff */
+	unsigned off = 2 + tab->M;
+
+	extra = isl_alloc_array(tab->mat->ctx, int, tab->n_col);
+	if (tab->n_col && !extra)
+		goto error;
+	for (i = 0; i < tab->n_col; ++i) {
+		for (j = 0; j < tab->n_col; ++j)
+			if (tab->col_var[i] == col_var[j])
+				break;
+		if (j < tab->n_col)
+			continue;
+		extra[n_extra++] = i;
+	}
+	for (i = 0; i < tab->n_col && n_extra > 0; ++i) {
+		struct isl_tab_var *var;
+		int row;
+
+		for (j = 0; j < tab->n_col; ++j)
+			if (col_var[i] == tab->col_var[j])
+				break;
+		if (j < tab->n_col)
+			continue;
+		var = var_from_index(tab, col_var[i]);
+		row = var->index;
+		for (j = 0; j < n_extra; ++j)
+			if (!isl_int_is_zero(tab->mat->row[row][off+extra[j]]))
+				break;
+		isl_assert(tab->mat->ctx, j < n_extra, goto error);
+		if (isl_tab_pivot(tab, row, extra[j]) < 0)
+			goto error;
+		extra[j] = extra[--n_extra];
+	}
+
+	free(extra);
+	return 0;
+error:
+	free(extra);
+	return -1;
+}
+
+/* Remove all samples with index n or greater, i.e., those samples
+ * that were added since we saved this number of samples in
+ * isl_tab_save_samples.
+ */
+static void drop_samples_since(struct isl_tab *tab, int n)
+{
+	int i;
+
+	for (i = tab->n_sample - 1; i >= 0 && tab->n_sample > n; --i) {
+		if (tab->sample_index[i] < n)
+			continue;
+
+		if (i != tab->n_sample - 1) {
+			int t = tab->sample_index[tab->n_sample-1];
+			tab->sample_index[tab->n_sample-1] = tab->sample_index[i];
+			tab->sample_index[i] = t;
+			isl_mat_swap_rows(tab->samples, tab->n_sample-1, i);
+		}
+		tab->n_sample--;
+	}
+}
+
+static isl_stat perform_undo(struct isl_tab *tab, struct isl_tab_undo *undo)
+	WARN_UNUSED;
+static isl_stat perform_undo(struct isl_tab *tab, struct isl_tab_undo *undo)
+{
+	switch (undo->type) {
+	case isl_tab_undo_rational:
+		tab->rational = 0;
+		break;
+	case isl_tab_undo_empty:
+		tab->empty = 0;
+		break;
+	case isl_tab_undo_nonneg:
+	case isl_tab_undo_redundant:
+	case isl_tab_undo_freeze:
+	case isl_tab_undo_zero:
+	case isl_tab_undo_allocate:
+	case isl_tab_undo_relax:
+	case isl_tab_undo_unrestrict:
+		return perform_undo_var(tab, undo);
+	case isl_tab_undo_bmap_eq:
+		return isl_basic_map_free_equality(tab->bmap, 1);
+	case isl_tab_undo_bmap_ineq:
+		return isl_basic_map_free_inequality(tab->bmap, 1);
+	case isl_tab_undo_bmap_div:
+		return drop_bmap_div(tab, undo->u.var_index);
+	case isl_tab_undo_saved_basis:
+		if (restore_basis(tab, undo->u.col_var) < 0)
+			return isl_stat_error;
+		break;
+	case isl_tab_undo_drop_sample:
+		tab->n_outside--;
+		break;
+	case isl_tab_undo_saved_samples:
+		drop_samples_since(tab, undo->u.n);
+		break;
+	case isl_tab_undo_callback:
+		return undo->u.callback->run(undo->u.callback);
+	default:
+		isl_assert(tab->mat->ctx, 0, return isl_stat_error);
+	}
+	return isl_stat_ok;
+}
+
+/* Return the tableau to the state it was in when the snapshot "snap"
+ * was taken.
+ */
+int isl_tab_rollback(struct isl_tab *tab, struct isl_tab_undo *snap)
+{
+	struct isl_tab_undo *undo, *next;
+
+	if (!tab)
+		return -1;
+
+	tab->in_undo = 1;
+	for (undo = tab->top; undo && undo != &tab->bottom; undo = next) {
+		next = undo->next;
+		if (undo == snap)
+			break;
+		if (perform_undo(tab, undo) < 0) {
+			tab->top = undo;
+			free_undo(tab);
+			tab->in_undo = 0;
+			return -1;
+		}
+		free_undo_record(undo);
+	}
+	tab->in_undo = 0;
+	tab->top = undo;
+	if (!undo)
+		return -1;
+	return 0;
+}
+
+/* The given row "row" represents an inequality violated by all
+ * points in the tableau.  Check for some special cases of such
+ * separating constraints.
+ * In particular, if the row has been reduced to the constant -1,
+ * then we know the inequality is adjacent (but opposite) to
+ * an equality in the tableau.
+ * If the row has been reduced to r = c*(-1 -r'), with r' an inequality
+ * of the tableau and c a positive constant, then the inequality
+ * is adjacent (but opposite) to the inequality r'.
+ */
+static enum isl_ineq_type separation_type(struct isl_tab *tab, unsigned row)
+{
+	int pos;
+	unsigned off = 2 + tab->M;
+
+	if (tab->rational)
+		return isl_ineq_separate;
+
+	if (!isl_int_is_one(tab->mat->row[row][0]))
+		return isl_ineq_separate;
+
+	pos = isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead,
+					tab->n_col - tab->n_dead);
+	if (pos == -1) {
+		if (isl_int_is_negone(tab->mat->row[row][1]))
+			return isl_ineq_adj_eq;
+		else
+			return isl_ineq_separate;
+	}
+
+	if (!isl_int_eq(tab->mat->row[row][1],
+			tab->mat->row[row][off + tab->n_dead + pos]))
+		return isl_ineq_separate;
+
+	pos = isl_seq_first_non_zero(
+			tab->mat->row[row] + off + tab->n_dead + pos + 1,
+			tab->n_col - tab->n_dead - pos - 1);
+
+	return pos == -1 ? isl_ineq_adj_ineq : isl_ineq_separate;
+}
+
+/* Check the effect of inequality "ineq" on the tableau "tab".
+ * The result may be
+ *	isl_ineq_redundant:	satisfied by all points in the tableau
+ *	isl_ineq_separate:	satisfied by no point in the tableau
+ *	isl_ineq_cut:		satisfied by some by not all points
+ *	isl_ineq_adj_eq:	adjacent to an equality
+ *	isl_ineq_adj_ineq:	adjacent to an inequality.
+ */
+enum isl_ineq_type isl_tab_ineq_type(struct isl_tab *tab, isl_int *ineq)
+{
+	enum isl_ineq_type type = isl_ineq_error;
+	struct isl_tab_undo *snap = NULL;
+	int con;
+	int row;
+
+	if (!tab)
+		return isl_ineq_error;
+
+	if (isl_tab_extend_cons(tab, 1) < 0)
+		return isl_ineq_error;
+
+	snap = isl_tab_snap(tab);
+
+	con = isl_tab_add_row(tab, ineq);
+	if (con < 0)
+		goto error;
+
+	row = tab->con[con].index;
+	if (isl_tab_row_is_redundant(tab, row))
+		type = isl_ineq_redundant;
+	else if (isl_int_is_neg(tab->mat->row[row][1]) &&
+		 (tab->rational ||
+		    isl_int_abs_ge(tab->mat->row[row][1],
+				   tab->mat->row[row][0]))) {
+		int nonneg = at_least_zero(tab, &tab->con[con]);
+		if (nonneg < 0)
+			goto error;
+		if (nonneg)
+			type = isl_ineq_cut;
+		else
+			type = separation_type(tab, row);
+	} else {
+		int red = con_is_redundant(tab, &tab->con[con]);
+		if (red < 0)
+			goto error;
+		if (!red)
+			type = isl_ineq_cut;
+		else
+			type = isl_ineq_redundant;
+	}
+
+	if (isl_tab_rollback(tab, snap))
+		return isl_ineq_error;
+	return type;
+error:
+	return isl_ineq_error;
+}
+
+isl_stat isl_tab_track_bmap(struct isl_tab *tab, __isl_take isl_basic_map *bmap)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (!tab || !bmap)
+		goto error;
+
+	if (tab->empty) {
+		bmap = isl_basic_map_set_to_empty(bmap);
+		if (!bmap)
+			goto error;
+		tab->bmap = bmap;
+		return isl_stat_ok;
+	}
+
+	isl_assert(tab->mat->ctx, tab->n_eq == bmap->n_eq, goto error);
+	isl_assert(tab->mat->ctx,
+		    tab->n_con == bmap->n_eq + bmap->n_ineq, goto error);
+
+	tab->bmap = bmap;
+
+	return isl_stat_ok;
+error:
+	isl_basic_map_free(bmap);
+	return isl_stat_error;
+}
+
+isl_stat isl_tab_track_bset(struct isl_tab *tab, __isl_take isl_basic_set *bset)
+{
+	return isl_tab_track_bmap(tab, bset_to_bmap(bset));
+}
+
+__isl_keep isl_basic_set *isl_tab_peek_bset(struct isl_tab *tab)
+{
+	if (!tab)
+		return NULL;
+
+	return bset_from_bmap(tab->bmap);
+}
+
+static void isl_tab_print_internal(__isl_keep struct isl_tab *tab,
+	FILE *out, int indent)
+{
+	unsigned r, c;
+	int i;
+
+	if (!tab) {
+		fprintf(out, "%*snull tab\n", indent, "");
+		return;
+	}
+	fprintf(out, "%*sn_redundant: %d, n_dead: %d", indent, "",
+		tab->n_redundant, tab->n_dead);
+	if (tab->rational)
+		fprintf(out, ", rational");
+	if (tab->empty)
+		fprintf(out, ", empty");
+	fprintf(out, "\n");
+	fprintf(out, "%*s[", indent, "");
+	for (i = 0; i < tab->n_var; ++i) {
+		if (i)
+			fprintf(out, (i == tab->n_param ||
+				      i == tab->n_var - tab->n_div) ? "; "
+								    : ", ");
+		fprintf(out, "%c%d%s", tab->var[i].is_row ? 'r' : 'c',
+					tab->var[i].index,
+					tab->var[i].is_zero ? " [=0]" :
+					tab->var[i].is_redundant ? " [R]" : "");
+	}
+	fprintf(out, "]\n");
+	fprintf(out, "%*s[", indent, "");
+	for (i = 0; i < tab->n_con; ++i) {
+		if (i)
+			fprintf(out, ", ");
+		fprintf(out, "%c%d%s", tab->con[i].is_row ? 'r' : 'c',
+					tab->con[i].index,
+					tab->con[i].is_zero ? " [=0]" :
+					tab->con[i].is_redundant ? " [R]" : "");
+	}
+	fprintf(out, "]\n");
+	fprintf(out, "%*s[", indent, "");
+	for (i = 0; i < tab->n_row; ++i) {
+		const char *sign = "";
+		if (i)
+			fprintf(out, ", ");
+		if (tab->row_sign) {
+			if (tab->row_sign[i] == isl_tab_row_unknown)
+				sign = "?";
+			else if (tab->row_sign[i] == isl_tab_row_neg)
+				sign = "-";
+			else if (tab->row_sign[i] == isl_tab_row_pos)
+				sign = "+";
+			else
+				sign = "+-";
+		}
+		fprintf(out, "r%d: %d%s%s", i, tab->row_var[i],
+		    isl_tab_var_from_row(tab, i)->is_nonneg ? " [>=0]" : "", sign);
+	}
+	fprintf(out, "]\n");
+	fprintf(out, "%*s[", indent, "");
+	for (i = 0; i < tab->n_col; ++i) {
+		if (i)
+			fprintf(out, ", ");
+		fprintf(out, "c%d: %d%s", i, tab->col_var[i],
+		    var_from_col(tab, i)->is_nonneg ? " [>=0]" : "");
+	}
+	fprintf(out, "]\n");
+	r = tab->mat->n_row;
+	tab->mat->n_row = tab->n_row;
+	c = tab->mat->n_col;
+	tab->mat->n_col = 2 + tab->M + tab->n_col;
+	isl_mat_print_internal(tab->mat, out, indent);
+	tab->mat->n_row = r;
+	tab->mat->n_col = c;
+	if (tab->bmap)
+		isl_basic_map_print_internal(tab->bmap, out, indent);
+}
+
+void isl_tab_dump(__isl_keep struct isl_tab *tab)
+{
+	isl_tab_print_internal(tab, stderr, 0);
+}
diff --git a/final/lib/External/isl/isl_tab.h b/final/lib/External/isl/isl_tab.h
new file mode 100644
index 0000000..a1dacd9
--- /dev/null
+++ b/final/lib/External/isl/isl_tab.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#ifndef ISL_TAB_H
+#define ISL_TAB_H
+
+#include <isl/lp.h>
+#include <isl/map.h>
+#include <isl/mat.h>
+#include <isl/set.h>
+#include <isl_config.h>
+
+struct isl_tab_var {
+	int index;
+	unsigned is_row : 1;
+	unsigned is_nonneg : 1;
+	unsigned is_zero : 1;
+	unsigned is_redundant : 1;
+	unsigned marked : 1;
+	unsigned frozen : 1;
+	unsigned negated : 1;
+};
+
+enum isl_tab_undo_type {
+	isl_tab_undo_bottom,
+	isl_tab_undo_rational,
+	isl_tab_undo_empty,
+	isl_tab_undo_nonneg,
+	isl_tab_undo_redundant,
+	isl_tab_undo_freeze,
+	isl_tab_undo_zero,
+	isl_tab_undo_allocate,
+	isl_tab_undo_relax,
+	isl_tab_undo_unrestrict,
+	isl_tab_undo_bmap_ineq,
+	isl_tab_undo_bmap_eq,
+	isl_tab_undo_bmap_div,
+	isl_tab_undo_saved_basis,
+	isl_tab_undo_drop_sample,
+	isl_tab_undo_saved_samples,
+	isl_tab_undo_callback,
+};
+
+struct isl_tab_callback {
+	isl_stat (*run)(struct isl_tab_callback *cb);
+};
+
+union isl_tab_undo_val {
+	int		var_index;
+	int		*col_var;
+	int		n;
+	struct isl_tab_callback	*callback;
+};
+
+struct isl_tab_undo {
+	enum isl_tab_undo_type	type;
+	union isl_tab_undo_val	u;
+	struct isl_tab_undo	*next;
+};
+
+/* The tableau maintains equality relations.
+ * Each column and each row is associated to a variable or a constraint.
+ * The "value" of an inequality constraint is the value of the corresponding
+ * slack variable.
+ * The "row_var" and "col_var" arrays map column and row indices
+ * to indices in the "var" and "con" arrays.  The elements of these
+ * arrays maintain extra information about the variables and the constraints.
+ * Each row expresses the corresponding row variable as an affine expression
+ * of the column variables.
+ * The first two columns in the matrix contain the common denominator of
+ * the row and the numerator of the constant term.
+ * If "M" is set, then the third column represents the "big parameter".
+ * The third (M = 0) or fourth (M = 1) column
+ * in the matrix is called column 0 with respect to the col_var array.
+ * The sample value of the tableau is the value that assigns zero
+ * to all the column variables and the constant term of each affine
+ * expression to the corresponding row variable.
+ * The operations on the tableau maintain the property that the sample
+ * value satisfies the non-negativity constraints (usually on the slack
+ * variables).
+ *
+ * The big parameter represents an arbitrarily big (and divisible)
+ * positive number.  If present, then the sign of a row is determined
+ * lexicographically, with the sign of the big parameter coefficient
+ * considered first.  The big parameter is only used while
+ * solving PILP problems.
+ *
+ * The first n_dead column variables have their values fixed to zero.
+ * The corresponding tab_vars are flagged "is_zero".
+ * Some of the rows that have have zero coefficients in all but
+ * the dead columns are also flagged "is_zero".
+ *
+ * The first n_redundant rows correspond to inequality constraints
+ * that are always satisfied for any value satisfying the non-redundant
+ * rows.  The corresponding tab_vars are flagged "is_redundant".
+ * A row variable that is flagged "is_zero" is also flagged "is_redundant"
+ * since the constraint has been reduced to 0 = 0 and is therefore always
+ * satisfied.
+ *
+ * There are "n_var" variables in total.  The first "n_param" of these
+ * are called parameters and the last "n_div" of these are called divs.
+ * The basic tableau operations makes no distinction between different
+ * kinds of variables.  These special variables are only used while
+ * solving PILP problems.
+ *
+ * Dead columns and redundant rows are detected on the fly.
+ * However, the basic operations do not ensure that all dead columns
+ * or all redundant rows are detected.
+ * isl_tab_detect_implicit_equalities and isl_tab_detect_redundant can be used
+ * to perform an exhaustive search for dead columns and redundant rows.
+ *
+ * The samples matrix contains "n_sample" integer points that have at some
+ * point been elements satisfying the tableau.  The first "n_outside"
+ * of them no longer satisfy the tableau.  They are kept because they
+ * can be reinstated during rollback when the constraint that cut them
+ * out is removed.  These samples are only maintained for the context
+ * tableau while solving PILP problems.
+ *
+ * If "preserve" is set, then we want to keep all constraints in the
+ * tableau, even if they turn out to be redundant.
+ */
+enum isl_tab_row_sign {
+	isl_tab_row_unknown = 0,
+	isl_tab_row_pos,
+	isl_tab_row_neg,
+	isl_tab_row_any,
+};
+struct isl_tab {
+	struct isl_mat *mat;
+
+	unsigned n_row;
+	unsigned n_col;
+	unsigned n_dead;
+	unsigned n_redundant;
+
+	unsigned n_var;
+	unsigned n_param;
+	unsigned n_div;
+	unsigned max_var;
+	unsigned n_con;
+	unsigned n_eq;
+	unsigned max_con;
+	struct isl_tab_var *var;
+	struct isl_tab_var *con;
+	int *row_var;	/* v >= 0 -> var v;	v < 0 -> con ~v */
+	int *col_var;	/* v >= 0 -> var v;	v < 0 -> con ~v */
+	enum isl_tab_row_sign *row_sign;
+
+	struct isl_tab_undo bottom;
+	struct isl_tab_undo *top;
+
+	struct isl_vec *dual;
+	struct isl_basic_map *bmap;
+
+	unsigned n_sample;
+	unsigned n_outside;
+	int *sample_index;
+	struct isl_mat *samples;
+
+	int n_zero;
+	int n_unbounded;
+	struct isl_mat *basis;
+
+	int (*conflict)(int con, void *user);
+	void *conflict_user;
+
+	unsigned strict_redundant : 1;
+	unsigned need_undo : 1;
+	unsigned preserve : 1;
+	unsigned rational : 1;
+	unsigned empty : 1;
+	unsigned in_undo : 1;
+	unsigned M : 1;
+	unsigned cone : 1;
+};
+
+struct isl_tab *isl_tab_alloc(struct isl_ctx *ctx,
+	unsigned n_row, unsigned n_var, unsigned M);
+void isl_tab_free(struct isl_tab *tab);
+
+isl_ctx *isl_tab_get_ctx(struct isl_tab *tab);
+
+__isl_give struct isl_tab *isl_tab_from_basic_map(
+	__isl_keep isl_basic_map *bmap, int track);
+__isl_give struct isl_tab *isl_tab_from_basic_set(
+	__isl_keep isl_basic_set *bset, int track);
+struct isl_tab *isl_tab_from_recession_cone(struct isl_basic_set *bset,
+	int parametric);
+isl_bool isl_tab_cone_is_bounded(struct isl_tab *tab);
+struct isl_basic_map *isl_basic_map_update_from_tab(struct isl_basic_map *bmap,
+	struct isl_tab *tab);
+struct isl_basic_set *isl_basic_set_update_from_tab(struct isl_basic_set *bset,
+	struct isl_tab *tab);
+int isl_tab_detect_implicit_equalities(struct isl_tab *tab) WARN_UNUSED;
+__isl_give isl_basic_map *isl_tab_make_equalities_explicit(struct isl_tab *tab,
+	__isl_take isl_basic_map *bmap);
+int isl_tab_detect_redundant(struct isl_tab *tab) WARN_UNUSED;
+isl_stat isl_tab_restore_redundant(struct isl_tab *tab);
+#define ISL_TAB_SAVE_DUAL	(1 << 0)
+enum isl_lp_result isl_tab_min(struct isl_tab *tab,
+	isl_int *f, isl_int denom, isl_int *opt, isl_int *opt_denom,
+	unsigned flags) WARN_UNUSED;
+
+isl_stat isl_tab_add_ineq(struct isl_tab *tab, isl_int *ineq) WARN_UNUSED;
+int isl_tab_add_eq(struct isl_tab *tab, isl_int *eq) WARN_UNUSED;
+int isl_tab_add_valid_eq(struct isl_tab *tab, isl_int *eq) WARN_UNUSED;
+
+int isl_tab_freeze_constraint(struct isl_tab *tab, int con) WARN_UNUSED;
+
+isl_stat isl_tab_track_bmap(struct isl_tab *tab, __isl_take isl_basic_map *bmap)
+	WARN_UNUSED;
+isl_stat isl_tab_track_bset(struct isl_tab *tab, __isl_take isl_basic_set *bset)
+	WARN_UNUSED;
+__isl_keep isl_basic_set *isl_tab_peek_bset(struct isl_tab *tab);
+
+int isl_tab_is_equality(struct isl_tab *tab, int con);
+int isl_tab_is_redundant(struct isl_tab *tab, int con);
+
+int isl_tab_sample_is_integer(struct isl_tab *tab);
+struct isl_vec *isl_tab_get_sample_value(struct isl_tab *tab);
+
+enum isl_ineq_type {
+	isl_ineq_error = -1,
+	isl_ineq_redundant,
+	isl_ineq_separate,
+	isl_ineq_cut,
+	isl_ineq_adj_eq,
+	isl_ineq_adj_ineq,
+};
+
+enum isl_ineq_type isl_tab_ineq_type(struct isl_tab *tab, isl_int *ineq);
+
+struct isl_tab_undo *isl_tab_snap(struct isl_tab *tab);
+int isl_tab_rollback(struct isl_tab *tab, struct isl_tab_undo *snap) WARN_UNUSED;
+isl_bool isl_tab_need_undo(struct isl_tab *tab);
+void isl_tab_clear_undo(struct isl_tab *tab);
+
+int isl_tab_relax(struct isl_tab *tab, int con) WARN_UNUSED;
+int isl_tab_select_facet(struct isl_tab *tab, int con) WARN_UNUSED;
+int isl_tab_unrestrict(struct isl_tab *tab, int con) WARN_UNUSED;
+
+void isl_tab_dump(__isl_keep struct isl_tab *tab);
+
+/* Compute maximum instead of minimum. */
+#define ISL_OPT_MAX		(1 << 0)
+/* Compute full instead of partial optimum; also, domain argument is NULL. */
+#define ISL_OPT_FULL		(1 << 1)
+/* Result should be free of (unknown) quantified variables. */
+#define ISL_OPT_QE		(1 << 2)
+__isl_give isl_map *isl_tab_basic_map_partial_lexopt(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, unsigned flags);
+__isl_give isl_pw_multi_aff *isl_tab_basic_map_partial_lexopt_pw_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, unsigned flags);
+
+/* An isl_trivial_region represents a non-triviality region.
+ * The region is trivial if applying "trivial" to a given sequence
+ * of variables results in a zero vector.
+ * pos is the location (starting at 0) of the first variable in the sequence.
+ */
+struct isl_trivial_region {
+	int pos;
+	isl_mat *trivial;
+};
+
+__isl_give isl_vec *isl_tab_basic_set_non_trivial_lexmin(
+	__isl_take isl_basic_set *bset, int n_op, int n_region,
+	struct isl_trivial_region *region,
+	int (*conflict)(int con, void *user), void *user);
+
+struct isl_tab_lexmin;
+typedef struct isl_tab_lexmin isl_tab_lexmin;
+
+__isl_give isl_tab_lexmin *isl_tab_lexmin_from_basic_set(
+	__isl_take isl_basic_set *bset);
+int isl_tab_lexmin_dim(__isl_keep isl_tab_lexmin *tl);
+__isl_give isl_tab_lexmin *isl_tab_lexmin_add_eq(__isl_take isl_tab_lexmin *tl,
+	isl_int *eq);
+__isl_give isl_tab_lexmin *isl_tab_lexmin_cut_to_integer(
+	__isl_take isl_tab_lexmin *tl);
+__isl_give isl_vec *isl_tab_lexmin_get_solution(__isl_keep isl_tab_lexmin *tl);
+__isl_null isl_tab_lexmin *isl_tab_lexmin_free(__isl_take isl_tab_lexmin *tl);
+
+/* private */
+
+struct isl_tab_var *isl_tab_var_from_row(struct isl_tab *tab, int i);
+int isl_tab_mark_redundant(struct isl_tab *tab, int row) WARN_UNUSED;
+int isl_tab_mark_rational(struct isl_tab *tab) WARN_UNUSED;
+isl_stat isl_tab_mark_empty(struct isl_tab *tab) WARN_UNUSED;
+struct isl_tab *isl_tab_dup(struct isl_tab *tab);
+struct isl_tab *isl_tab_product(struct isl_tab *tab1, struct isl_tab *tab2);
+int isl_tab_extend_cons(struct isl_tab *tab, unsigned n_new) WARN_UNUSED;
+int isl_tab_allocate_con(struct isl_tab *tab) WARN_UNUSED;
+int isl_tab_extend_vars(struct isl_tab *tab, unsigned n_new) WARN_UNUSED;
+int isl_tab_allocate_var(struct isl_tab *tab) WARN_UNUSED;
+int isl_tab_insert_var(struct isl_tab *tab, int pos) WARN_UNUSED;
+int isl_tab_pivot(struct isl_tab *tab, int row, int col) WARN_UNUSED;
+int isl_tab_add_row(struct isl_tab *tab, isl_int *line) WARN_UNUSED;
+int isl_tab_row_is_redundant(struct isl_tab *tab, int row);
+int isl_tab_min_at_most_neg_one(struct isl_tab *tab, struct isl_tab_var *var);
+int isl_tab_sign_of_max(struct isl_tab *tab, int con);
+int isl_tab_kill_col(struct isl_tab *tab, int col) WARN_UNUSED;
+
+int isl_tab_push(struct isl_tab *tab, enum isl_tab_undo_type type) WARN_UNUSED;
+int isl_tab_push_var(struct isl_tab *tab,
+	enum isl_tab_undo_type type, struct isl_tab_var *var) WARN_UNUSED;
+int isl_tab_push_basis(struct isl_tab *tab) WARN_UNUSED;
+
+struct isl_tab *isl_tab_init_samples(struct isl_tab *tab) WARN_UNUSED;
+int isl_tab_add_sample(struct isl_tab *tab,
+	__isl_take isl_vec *sample) WARN_UNUSED;
+struct isl_tab *isl_tab_drop_sample(struct isl_tab *tab, int s);
+int isl_tab_save_samples(struct isl_tab *tab) WARN_UNUSED;
+
+struct isl_tab *isl_tab_detect_equalities(struct isl_tab *tab,
+	struct isl_tab *tab_cone) WARN_UNUSED;
+isl_bool isl_tab_is_constant(struct isl_tab *tab, int var, isl_int *value);
+isl_stat isl_tab_detect_constants(struct isl_tab *tab);
+
+int isl_tab_push_callback(struct isl_tab *tab,
+	struct isl_tab_callback *callback) WARN_UNUSED;
+
+int isl_tab_insert_div(struct isl_tab *tab, int pos, __isl_keep isl_vec *div,
+	isl_stat (*add_ineq)(void *user, isl_int *), void *user);
+int isl_tab_add_div(struct isl_tab *tab, __isl_keep isl_vec *div);
+
+int isl_tab_shift_var(struct isl_tab *tab, int pos, isl_int shift) WARN_UNUSED;
+
+#endif
diff --git a/final/lib/External/isl/isl_tab_lexopt_templ.c b/final/lib/External/isl/isl_tab_lexopt_templ.c
new file mode 100644
index 0000000..751e7bf
--- /dev/null
+++ b/final/lib/External/isl/isl_tab_lexopt_templ.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2011      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ */
+
+#define xSF(TYPE,SUFFIX) TYPE ## SUFFIX
+#define SF(TYPE,SUFFIX) xSF(TYPE,SUFFIX)
+
+/* Given a basic map with at least two parallel constraints (as found
+ * by the function parallel_constraints), first look for more constraints
+ * parallel to the two constraint and replace the found list of parallel
+ * constraints by a single constraint with as "input" part the minimum
+ * of the input parts of the list of constraints.  Then, recursively call
+ * basic_map_partial_lexopt (possibly finding more parallel constraints)
+ * and plug in the definition of the minimum in the result.
+ *
+ * As in parallel_constraints, only inequality constraints that only
+ * involve input variables that do not occur in any other inequality
+ * constraints are considered.
+ *
+ * More specifically, given a set of constraints
+ *
+ *	a x + b_i(p) >= 0
+ *
+ * Replace this set by a single constraint
+ *
+ *	a x + u >= 0
+ *
+ * with u a new parameter with constraints
+ *
+ *	u <= b_i(p)
+ *
+ * Any solution to the new system is also a solution for the original system
+ * since
+ *
+ *	a x >= -u >= -b_i(p)
+ *
+ * Moreover, m = min_i(b_i(p)) satisfies the constraints on u and can
+ * therefore be plugged into the solution.
+ */
+static TYPE *SF(basic_map_partial_lexopt_symm,SUFFIX)(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max, int first, int second)
+{
+	int i, n, k;
+	int *list = NULL;
+	unsigned n_in, n_out, n_div;
+	isl_ctx *ctx;
+	isl_vec *var = NULL;
+	isl_mat *cst = NULL;
+	isl_space *map_space, *set_space;
+
+	map_space = isl_basic_map_get_space(bmap);
+	set_space = empty ? isl_basic_set_get_space(dom) : NULL;
+
+	n_in = isl_basic_map_dim(bmap, isl_dim_param) +
+	       isl_basic_map_dim(bmap, isl_dim_in);
+	n_out = isl_basic_map_dim(bmap, isl_dim_all) - n_in;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	list = isl_alloc_array(ctx, int, bmap->n_ineq);
+	var = isl_vec_alloc(ctx, n_out);
+	if ((bmap->n_ineq && !list) || (n_out && !var))
+		goto error;
+
+	list[0] = first;
+	list[1] = second;
+	isl_seq_cpy(var->el, bmap->ineq[first] + 1 + n_in, n_out);
+	for (i = second + 1, n = 2; i < bmap->n_ineq; ++i) {
+		if (isl_seq_eq(var->el, bmap->ineq[i] + 1 + n_in, n_out) &&
+		    all_single_occurrence(bmap, i, n_in))
+			list[n++] = i;
+	}
+
+	cst = isl_mat_alloc(ctx, n, 1 + n_in);
+	if (!cst)
+		goto error;
+
+	for (i = 0; i < n; ++i)
+		isl_seq_cpy(cst->row[i], bmap->ineq[list[i]], 1 + n_in);
+
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap)
+		goto error;
+	for (i = n - 1; i >= 0; --i)
+		if (isl_basic_map_drop_inequality(bmap, list[i]) < 0)
+			goto error;
+
+	bmap = isl_basic_map_add_dims(bmap, isl_dim_in, 1);
+	bmap = isl_basic_map_extend_constraints(bmap, 0, 1);
+	k = isl_basic_map_alloc_inequality(bmap);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(bmap->ineq[k], 1 + n_in);
+	isl_int_set_si(bmap->ineq[k][1 + n_in], 1);
+	isl_seq_cpy(bmap->ineq[k] + 1 + n_in + 1, var->el, n_out);
+	bmap = isl_basic_map_finalize(bmap);
+
+	n_div = isl_basic_set_dim(dom, isl_dim_div);
+	dom = isl_basic_set_add_dims(dom, isl_dim_set, 1);
+	dom = isl_basic_set_extend_constraints(dom, 0, n);
+	for (i = 0; i < n; ++i) {
+		k = isl_basic_set_alloc_inequality(dom);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(dom->ineq[k], cst->row[i], 1 + n_in);
+		isl_int_set_si(dom->ineq[k][1 + n_in], -1);
+		isl_seq_clr(dom->ineq[k] + 1 + n_in + 1, n_div);
+	}
+
+	isl_vec_free(var);
+	free(list);
+
+	return SF(basic_map_partial_lexopt_symm_core,SUFFIX)(bmap, dom, empty,
+						max, cst, map_space, set_space);
+error:
+	isl_space_free(map_space);
+	isl_space_free(set_space);
+	isl_mat_free(cst);
+	isl_vec_free(var);
+	free(list);
+	isl_basic_set_free(dom);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Recursive part of isl_tab_basic_map_partial_lexopt*, after detecting
+ * equalities and removing redundant constraints.
+ *
+ * We first check if there are any parallel constraints (left).
+ * If not, we are in the base case.
+ * If there are parallel constraints, we replace them by a single
+ * constraint in basic_map_partial_lexopt_symm_pma and then call
+ * this function recursively to look for more parallel constraints.
+ */
+static __isl_give TYPE *SF(basic_map_partial_lexopt,SUFFIX)(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max)
+{
+	isl_bool par = isl_bool_false;
+	int first, second;
+
+	if (!bmap)
+		goto error;
+
+	if (bmap->ctx->opt->pip_symmetry)
+		par = parallel_constraints(bmap, &first, &second);
+	if (par < 0)
+		goto error;
+	if (!par)
+		return SF(basic_map_partial_lexopt_base,SUFFIX)(bmap, dom,
+								empty, max);
+
+	return SF(basic_map_partial_lexopt_symm,SUFFIX)(bmap, dom, empty, max,
+							 first, second);
+error:
+	isl_basic_set_free(dom);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Compute the lexicographic minimum (or maximum if "flags" includes
+ * ISL_OPT_MAX) of "bmap" over the domain "dom" and return the result as
+ * either a map or a piecewise multi-affine expression depending on TYPE.
+ * If "empty" is not NULL, then *empty is assigned a set that
+ * contains those parts of the domain where there is no solution.
+ * If "flags" includes ISL_OPT_FULL, then "dom" is NULL and the optimum
+ * should be computed over the domain of "bmap".  "empty" is also NULL
+ * in this case.
+ * If "bmap" is marked as rational (ISL_BASIC_MAP_RATIONAL),
+ * then we compute the rational optimum.  Otherwise, we compute
+ * the integral optimum.
+ *
+ * We perform some preprocessing.  As the PILP solver does not
+ * handle implicit equalities very well, we first make sure all
+ * the equalities are explicitly available.
+ *
+ * We also add context constraints to the basic map and remove
+ * redundant constraints.  This is only needed because of the
+ * way we handle simple symmetries.  In particular, we currently look
+ * for symmetries on the constraints, before we set up the main tableau.
+ * It is then no good to look for symmetries on possibly redundant constraints.
+ * If the domain was extracted from the basic map, then there is
+ * no need to add back those constraints again.
+ */
+__isl_give TYPE *SF(isl_tab_basic_map_partial_lexopt,SUFFIX)(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, unsigned flags)
+{
+	int max, full;
+	isl_bool compatible;
+
+	if (empty)
+		*empty = NULL;
+
+	full = ISL_FL_ISSET(flags, ISL_OPT_FULL);
+	if (full)
+		dom = extract_domain(bmap, flags);
+	compatible = isl_basic_map_compatible_domain(bmap, dom);
+	if (compatible < 0)
+		goto error;
+	if (!compatible)
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"domain does not match input", goto error);
+
+	max = ISL_FL_ISSET(flags, ISL_OPT_MAX);
+	if (isl_basic_set_dim(dom, isl_dim_all) == 0)
+		return SF(basic_map_partial_lexopt,SUFFIX)(bmap, dom, empty,
+							    max);
+
+	if (!full)
+		bmap = isl_basic_map_intersect_domain(bmap,
+						    isl_basic_set_copy(dom));
+	bmap = isl_basic_map_detect_equalities(bmap);
+	bmap = isl_basic_map_remove_redundancies(bmap);
+
+	return SF(basic_map_partial_lexopt,SUFFIX)(bmap, dom, empty, max);
+error:
+	isl_basic_set_free(dom);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_tab_pip.c b/final/lib/External/isl/isl_tab_pip.c
new file mode 100644
index 0000000..d4747b4
--- /dev/null
+++ b/final/lib/External/isl/isl_tab_pip.c
@@ -0,0 +1,5874 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2016-2017 Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
+ */
+
+#include <isl_ctx_private.h>
+#include "isl_map_private.h"
+#include <isl_seq.h>
+#include "isl_tab.h"
+#include "isl_sample.h"
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl_aff_private.h>
+#include <isl_constraint_private.h>
+#include <isl_options_private.h>
+#include <isl_config.h>
+
+#include <bset_to_bmap.c>
+
+/*
+ * The implementation of parametric integer linear programming in this file
+ * was inspired by the paper "Parametric Integer Programming" and the
+ * report "Solving systems of affine (in)equalities" by Paul Feautrier
+ * (and others).
+ *
+ * The strategy used for obtaining a feasible solution is different
+ * from the one used in isl_tab.c.  In particular, in isl_tab.c,
+ * upon finding a constraint that is not yet satisfied, we pivot
+ * in a row that increases the constant term of the row holding the
+ * constraint, making sure the sample solution remains feasible
+ * for all the constraints it already satisfied.
+ * Here, we always pivot in the row holding the constraint,
+ * choosing a column that induces the lexicographically smallest
+ * increment to the sample solution.
+ *
+ * By starting out from a sample value that is lexicographically
+ * smaller than any integer point in the problem space, the first
+ * feasible integer sample point we find will also be the lexicographically
+ * smallest.  If all variables can be assumed to be non-negative,
+ * then the initial sample value may be chosen equal to zero.
+ * However, we will not make this assumption.  Instead, we apply
+ * the "big parameter" trick.  Any variable x is then not directly
+ * used in the tableau, but instead it is represented by another
+ * variable x' = M + x, where M is an arbitrarily large (positive)
+ * value.  x' is therefore always non-negative, whatever the value of x.
+ * Taking as initial sample value x' = 0 corresponds to x = -M,
+ * which is always smaller than any possible value of x.
+ *
+ * The big parameter trick is used in the main tableau and
+ * also in the context tableau if isl_context_lex is used.
+ * In this case, each tableaus has its own big parameter.
+ * Before doing any real work, we check if all the parameters
+ * happen to be non-negative.  If so, we drop the column corresponding
+ * to M from the initial context tableau.
+ * If isl_context_gbr is used, then the big parameter trick is only
+ * used in the main tableau.
+ */
+
+struct isl_context;
+struct isl_context_op {
+	/* detect nonnegative parameters in context and mark them in tab */
+	struct isl_tab *(*detect_nonnegative_parameters)(
+			struct isl_context *context, struct isl_tab *tab);
+	/* return temporary reference to basic set representation of context */
+	struct isl_basic_set *(*peek_basic_set)(struct isl_context *context);
+	/* return temporary reference to tableau representation of context */
+	struct isl_tab *(*peek_tab)(struct isl_context *context);
+	/* add equality; check is 1 if eq may not be valid;
+	 * update is 1 if we may want to call ineq_sign on context later.
+	 */
+	void (*add_eq)(struct isl_context *context, isl_int *eq,
+			int check, int update);
+	/* add inequality; check is 1 if ineq may not be valid;
+	 * update is 1 if we may want to call ineq_sign on context later.
+	 */
+	void (*add_ineq)(struct isl_context *context, isl_int *ineq,
+			int check, int update);
+	/* check sign of ineq based on previous information.
+	 * strict is 1 if saturation should be treated as a positive sign.
+	 */
+	enum isl_tab_row_sign (*ineq_sign)(struct isl_context *context,
+			isl_int *ineq, int strict);
+	/* check if inequality maintains feasibility */
+	int (*test_ineq)(struct isl_context *context, isl_int *ineq);
+	/* return index of a div that corresponds to "div" */
+	int (*get_div)(struct isl_context *context, struct isl_tab *tab,
+			struct isl_vec *div);
+	/* insert div "div" to context at "pos" and return non-negativity */
+	isl_bool (*insert_div)(struct isl_context *context, int pos,
+		__isl_keep isl_vec *div);
+	int (*detect_equalities)(struct isl_context *context,
+			struct isl_tab *tab);
+	/* return row index of "best" split */
+	int (*best_split)(struct isl_context *context, struct isl_tab *tab);
+	/* check if context has already been determined to be empty */
+	int (*is_empty)(struct isl_context *context);
+	/* check if context is still usable */
+	int (*is_ok)(struct isl_context *context);
+	/* save a copy/snapshot of context */
+	void *(*save)(struct isl_context *context);
+	/* restore saved context */
+	void (*restore)(struct isl_context *context, void *);
+	/* discard saved context */
+	void (*discard)(void *);
+	/* invalidate context */
+	void (*invalidate)(struct isl_context *context);
+	/* free context */
+	__isl_null struct isl_context *(*free)(struct isl_context *context);
+};
+
+/* Shared parts of context representation.
+ *
+ * "n_unknown" is the number of final unknown integer divisions
+ * in the input domain.
+ */
+struct isl_context {
+	struct isl_context_op *op;
+	int n_unknown;
+};
+
+struct isl_context_lex {
+	struct isl_context context;
+	struct isl_tab *tab;
+};
+
+/* A stack (linked list) of solutions of subtrees of the search space.
+ *
+ * "ma" describes the solution as a function of "dom".
+ * In particular, the domain space of "ma" is equal to the space of "dom".
+ *
+ * If "ma" is NULL, then there is no solution on "dom".
+ */
+struct isl_partial_sol {
+	int level;
+	struct isl_basic_set *dom;
+	isl_multi_aff *ma;
+
+	struct isl_partial_sol *next;
+};
+
+struct isl_sol;
+struct isl_sol_callback {
+	struct isl_tab_callback callback;
+	struct isl_sol *sol;
+};
+
+/* isl_sol is an interface for constructing a solution to
+ * a parametric integer linear programming problem.
+ * Every time the algorithm reaches a state where a solution
+ * can be read off from the tableau, the function "add" is called
+ * on the isl_sol passed to find_solutions_main.  In a state where
+ * the tableau is empty, "add_empty" is called instead.
+ * "free" is called to free the implementation specific fields, if any.
+ *
+ * "error" is set if some error has occurred.  This flag invalidates
+ * the remainder of the data structure.
+ * If "rational" is set, then a rational optimization is being performed.
+ * "level" is the current level in the tree with nodes for each
+ * split in the context.
+ * If "max" is set, then a maximization problem is being solved, rather than
+ * a minimization problem, which means that the variables in the
+ * tableau have value "M - x" rather than "M + x".
+ * "n_out" is the number of output dimensions in the input.
+ * "space" is the space in which the solution (and also the input) lives.
+ *
+ * The context tableau is owned by isl_sol and is updated incrementally.
+ *
+ * There are currently three implementations of this interface,
+ * isl_sol_map, which simply collects the solutions in an isl_map
+ * and (optionally) the parts of the context where there is no solution
+ * in an isl_set,
+ * isl_sol_pma, which collects an isl_pw_multi_aff instead, and
+ * isl_sol_for, which calls a user-defined function for each part of
+ * the solution.
+ */
+struct isl_sol {
+	int error;
+	int rational;
+	int level;
+	int max;
+	int n_out;
+	isl_space *space;
+	struct isl_context *context;
+	struct isl_partial_sol *partial;
+	void (*add)(struct isl_sol *sol,
+		__isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma);
+	void (*add_empty)(struct isl_sol *sol, struct isl_basic_set *bset);
+	void (*free)(struct isl_sol *sol);
+	struct isl_sol_callback	dec_level;
+};
+
+static void sol_free(struct isl_sol *sol)
+{
+	struct isl_partial_sol *partial, *next;
+	if (!sol)
+		return;
+	for (partial = sol->partial; partial; partial = next) {
+		next = partial->next;
+		isl_basic_set_free(partial->dom);
+		isl_multi_aff_free(partial->ma);
+		free(partial);
+	}
+	isl_space_free(sol->space);
+	if (sol->context)
+		sol->context->op->free(sol->context);
+	sol->free(sol);
+	free(sol);
+}
+
+/* Push a partial solution represented by a domain and function "ma"
+ * onto the stack of partial solutions.
+ * If "ma" is NULL, then "dom" represents a part of the domain
+ * with no solution.
+ */
+static void sol_push_sol(struct isl_sol *sol,
+	__isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma)
+{
+	struct isl_partial_sol *partial;
+
+	if (sol->error || !dom)
+		goto error;
+
+	partial = isl_alloc_type(dom->ctx, struct isl_partial_sol);
+	if (!partial)
+		goto error;
+
+	partial->level = sol->level;
+	partial->dom = dom;
+	partial->ma = ma;
+	partial->next = sol->partial;
+
+	sol->partial = partial;
+
+	return;
+error:
+	isl_basic_set_free(dom);
+	isl_multi_aff_free(ma);
+	sol->error = 1;
+}
+
+/* Check that the final columns of "M", starting at "first", are zero.
+ */
+static isl_stat check_final_columns_are_zero(__isl_keep isl_mat *M,
+	unsigned first)
+{
+	int i;
+	unsigned rows, cols, n;
+
+	if (!M)
+		return isl_stat_error;
+	rows = isl_mat_rows(M);
+	cols = isl_mat_cols(M);
+	n = cols - first;
+	for (i = 0; i < rows; ++i)
+		if (isl_seq_first_non_zero(M->row[i] + first, n) != -1)
+			isl_die(isl_mat_get_ctx(M), isl_error_internal,
+				"final columns should be zero",
+				return isl_stat_error);
+	return isl_stat_ok;
+}
+
+/* Set the affine expressions in "ma" according to the rows in "M", which
+ * are defined over the local space "ls".
+ * The matrix "M" may have extra (zero) columns beyond the number
+ * of variables in "ls".
+ */
+static __isl_give isl_multi_aff *set_from_affine_matrix(
+	__isl_take isl_multi_aff *ma, __isl_take isl_local_space *ls,
+	__isl_take isl_mat *M)
+{
+	int i, dim;
+	isl_aff *aff;
+
+	if (!ma || !ls || !M)
+		goto error;
+
+	dim = isl_local_space_dim(ls, isl_dim_all);
+	if (check_final_columns_are_zero(M, 1 + dim) < 0)
+		goto error;
+	for (i = 1; i < M->n_row; ++i) {
+		aff = isl_aff_alloc(isl_local_space_copy(ls));
+		if (aff) {
+			isl_int_set(aff->v->el[0], M->row[0][0]);
+			isl_seq_cpy(aff->v->el + 1, M->row[i], 1 + dim);
+		}
+		aff = isl_aff_normalize(aff);
+		ma = isl_multi_aff_set_aff(ma, i - 1, aff);
+	}
+	isl_local_space_free(ls);
+	isl_mat_free(M);
+
+	return ma;
+error:
+	isl_local_space_free(ls);
+	isl_mat_free(M);
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+/* Push a partial solution represented by a domain and mapping M
+ * onto the stack of partial solutions.
+ *
+ * The affine matrix "M" maps the dimensions of the context
+ * to the output variables.  Convert it into an isl_multi_aff and
+ * then call sol_push_sol.
+ *
+ * Note that the description of the initial context may have involved
+ * existentially quantified variables, in which case they also appear
+ * in "dom".  These need to be removed before creating the affine
+ * expression because an affine expression cannot be defined in terms
+ * of existentially quantified variables without a known representation.
+ * Since newly added integer divisions are inserted before these
+ * existentially quantified variables, they are still in the final
+ * positions and the corresponding final columns of "M" are zero
+ * because align_context_divs adds the existentially quantified
+ * variables of the context to the main tableau without any constraints and
+ * any equality constraints that are added later on can only serve
+ * to eliminate these existentially quantified variables.
+ */
+static void sol_push_sol_mat(struct isl_sol *sol,
+	__isl_take isl_basic_set *dom, __isl_take isl_mat *M)
+{
+	isl_local_space *ls;
+	isl_multi_aff *ma;
+	int n_div, n_known;
+
+	n_div = isl_basic_set_dim(dom, isl_dim_div);
+	n_known = n_div - sol->context->n_unknown;
+
+	ma = isl_multi_aff_alloc(isl_space_copy(sol->space));
+	ls = isl_basic_set_get_local_space(dom);
+	ls = isl_local_space_drop_dims(ls, isl_dim_div,
+					n_known, n_div - n_known);
+	ma = set_from_affine_matrix(ma, ls, M);
+
+	if (!ma)
+		dom = isl_basic_set_free(dom);
+	sol_push_sol(sol, dom, ma);
+}
+
+/* Pop one partial solution from the partial solution stack and
+ * pass it on to sol->add or sol->add_empty.
+ */
+static void sol_pop_one(struct isl_sol *sol)
+{
+	struct isl_partial_sol *partial;
+
+	partial = sol->partial;
+	sol->partial = partial->next;
+
+	if (partial->ma)
+		sol->add(sol, partial->dom, partial->ma);
+	else
+		sol->add_empty(sol, partial->dom);
+	free(partial);
+}
+
+/* Return a fresh copy of the domain represented by the context tableau.
+ */
+static struct isl_basic_set *sol_domain(struct isl_sol *sol)
+{
+	struct isl_basic_set *bset;
+
+	if (sol->error)
+		return NULL;
+
+	bset = isl_basic_set_dup(sol->context->op->peek_basic_set(sol->context));
+	bset = isl_basic_set_update_from_tab(bset,
+			sol->context->op->peek_tab(sol->context));
+
+	return bset;
+}
+
+/* Check whether two partial solutions have the same affine expressions.
+ */
+static isl_bool same_solution(struct isl_partial_sol *s1,
+	struct isl_partial_sol *s2)
+{
+	if (!s1->ma != !s2->ma)
+		return isl_bool_false;
+	if (!s1->ma)
+		return isl_bool_true;
+
+	return isl_multi_aff_plain_is_equal(s1->ma, s2->ma);
+}
+
+/* Swap the initial two partial solutions in "sol".
+ *
+ * That is, go from
+ *
+ *	sol->partial = p1; p1->next = p2; p2->next = p3
+ *
+ * to
+ *
+ *	sol->partial = p2; p2->next = p1; p1->next = p3
+ */
+static void swap_initial(struct isl_sol *sol)
+{
+	struct isl_partial_sol *partial;
+
+	partial = sol->partial;
+	sol->partial = partial->next;
+	partial->next = partial->next->next;
+	sol->partial->next = partial;
+}
+
+/* Combine the initial two partial solution of "sol" into
+ * a partial solution with the current context domain of "sol" and
+ * the function description of the second partial solution in the list.
+ * The level of the new partial solution is set to the current level.
+ *
+ * That is, the first two partial solutions (D1,M1) and (D2,M2) are
+ * replaced by (D,M2), where D is the domain of "sol", which is assumed
+ * to be the union of D1 and D2, while M1 is assumed to be equal to M2
+ * (at least on D1).
+ */
+static isl_stat combine_initial_into_second(struct isl_sol *sol)
+{
+	struct isl_partial_sol *partial;
+	isl_basic_set *bset;
+
+	partial = sol->partial;
+
+	bset = sol_domain(sol);
+	isl_basic_set_free(partial->next->dom);
+	partial->next->dom = bset;
+	partial->next->level = sol->level;
+
+	if (!bset)
+		return isl_stat_error;
+
+	sol->partial = partial->next;
+	isl_basic_set_free(partial->dom);
+	isl_multi_aff_free(partial->ma);
+	free(partial);
+
+	return isl_stat_ok;
+}
+
+/* Are "ma1" and "ma2" equal to each other on "dom"?
+ *
+ * Combine "ma1" and "ma2" with "dom" and check if the results are the same.
+ * "dom" may have existentially quantified variables.  Eliminate them first
+ * as otherwise they would have to be eliminated twice, in a more complicated
+ * context.
+ */
+static isl_bool equal_on_domain(__isl_keep isl_multi_aff *ma1,
+	__isl_keep isl_multi_aff *ma2, __isl_keep isl_basic_set *dom)
+{
+	isl_set *set;
+	isl_pw_multi_aff *pma1, *pma2;
+	isl_bool equal;
+
+	set = isl_basic_set_compute_divs(isl_basic_set_copy(dom));
+	pma1 = isl_pw_multi_aff_alloc(isl_set_copy(set),
+					isl_multi_aff_copy(ma1));
+	pma2 = isl_pw_multi_aff_alloc(set, isl_multi_aff_copy(ma2));
+	equal = isl_pw_multi_aff_is_equal(pma1, pma2);
+	isl_pw_multi_aff_free(pma1);
+	isl_pw_multi_aff_free(pma2);
+
+	return equal;
+}
+
+/* The initial two partial solutions of "sol" are known to be at
+ * the same level.
+ * If they represent the same solution (on different parts of the domain),
+ * then combine them into a single solution at the current level.
+ * Otherwise, pop them both.
+ *
+ * Even if the two partial solution are not obviously the same,
+ * one may still be a simplification of the other over its own domain.
+ * Also check if the two sets of affine functions are equal when
+ * restricted to one of the domains.  If so, combine the two
+ * using the set of affine functions on the other domain.
+ * That is, for two partial solutions (D1,M1) and (D2,M2),
+ * if M1 = M2 on D1, then the pair of partial solutions can
+ * be replaced by (D1+D2,M2) and similarly when M1 = M2 on D2.
+ */
+static isl_stat combine_initial_if_equal(struct isl_sol *sol)
+{
+	struct isl_partial_sol *partial;
+	isl_bool same;
+
+	partial = sol->partial;
+
+	same = same_solution(partial, partial->next);
+	if (same < 0)
+		return isl_stat_error;
+	if (same)
+		return combine_initial_into_second(sol);
+	if (partial->ma && partial->next->ma) {
+		same = equal_on_domain(partial->ma, partial->next->ma,
+					partial->dom);
+		if (same < 0)
+			return isl_stat_error;
+		if (same)
+			return combine_initial_into_second(sol);
+		same = equal_on_domain(partial->ma, partial->next->ma,
+					partial->next->dom);
+		if (same) {
+			swap_initial(sol);
+			return combine_initial_into_second(sol);
+		}
+	}
+
+	sol_pop_one(sol);
+	sol_pop_one(sol);
+
+	return isl_stat_ok;
+}
+
+/* Pop all solutions from the partial solution stack that were pushed onto
+ * the stack at levels that are deeper than the current level.
+ * If the two topmost elements on the stack have the same level
+ * and represent the same solution, then their domains are combined.
+ * This combined domain is the same as the current context domain
+ * as sol_pop is called each time we move back to a higher level.
+ * If the outer level (0) has been reached, then all partial solutions
+ * at the current level are also popped off.
+ */
+static void sol_pop(struct isl_sol *sol)
+{
+	struct isl_partial_sol *partial;
+
+	if (sol->error)
+		return;
+
+	partial = sol->partial;
+	if (!partial)
+		return;
+
+	if (partial->level == 0 && sol->level == 0) {
+		for (partial = sol->partial; partial; partial = sol->partial)
+			sol_pop_one(sol);
+		return;
+	}
+
+	if (partial->level <= sol->level)
+		return;
+
+	if (partial->next && partial->next->level == partial->level) {
+		if (combine_initial_if_equal(sol) < 0)
+			goto error;
+	} else
+		sol_pop_one(sol);
+
+	if (sol->level == 0) {
+		for (partial = sol->partial; partial; partial = sol->partial)
+			sol_pop_one(sol);
+		return;
+	}
+
+	if (0)
+error:		sol->error = 1;
+}
+
+static void sol_dec_level(struct isl_sol *sol)
+{
+	if (sol->error)
+		return;
+
+	sol->level--;
+
+	sol_pop(sol);
+}
+
+static isl_stat sol_dec_level_wrap(struct isl_tab_callback *cb)
+{
+	struct isl_sol_callback *callback = (struct isl_sol_callback *)cb;
+
+	sol_dec_level(callback->sol);
+
+	return callback->sol->error ? isl_stat_error : isl_stat_ok;
+}
+
+/* Move down to next level and push callback onto context tableau
+ * to decrease the level again when it gets rolled back across
+ * the current state.  That is, dec_level will be called with
+ * the context tableau in the same state as it is when inc_level
+ * is called.
+ */
+static void sol_inc_level(struct isl_sol *sol)
+{
+	struct isl_tab *tab;
+
+	if (sol->error)
+		return;
+
+	sol->level++;
+	tab = sol->context->op->peek_tab(sol->context);
+	if (isl_tab_push_callback(tab, &sol->dec_level.callback) < 0)
+		sol->error = 1;
+}
+
+static void scale_rows(struct isl_mat *mat, isl_int m, int n_row)
+{
+	int i;
+
+	if (isl_int_is_one(m))
+		return;
+
+	for (i = 0; i < n_row; ++i)
+		isl_seq_scale(mat->row[i], mat->row[i], m, mat->n_col);
+}
+
+/* Add the solution identified by the tableau and the context tableau.
+ *
+ * The layout of the variables is as follows.
+ *	tab->n_var is equal to the total number of variables in the input
+ *			map (including divs that were copied from the context)
+ *			+ the number of extra divs constructed
+ *      Of these, the first tab->n_param and the last tab->n_div variables
+ *	correspond to the variables in the context, i.e.,
+ *		tab->n_param + tab->n_div = context_tab->n_var
+ *	tab->n_param is equal to the number of parameters and input
+ *			dimensions in the input map
+ *	tab->n_div is equal to the number of divs in the context
+ *
+ * If there is no solution, then call add_empty with a basic set
+ * that corresponds to the context tableau.  (If add_empty is NULL,
+ * then do nothing).
+ *
+ * If there is a solution, then first construct a matrix that maps
+ * all dimensions of the context to the output variables, i.e.,
+ * the output dimensions in the input map.
+ * The divs in the input map (if any) that do not correspond to any
+ * div in the context do not appear in the solution.
+ * The algorithm will make sure that they have an integer value,
+ * but these values themselves are of no interest.
+ * We have to be careful not to drop or rearrange any divs in the
+ * context because that would change the meaning of the matrix.
+ *
+ * To extract the value of the output variables, it should be noted
+ * that we always use a big parameter M in the main tableau and so
+ * the variable stored in this tableau is not an output variable x itself, but
+ *	x' = M + x (in case of minimization)
+ * or
+ *	x' = M - x (in case of maximization)
+ * If x' appears in a column, then its optimal value is zero,
+ * which means that the optimal value of x is an unbounded number
+ * (-M for minimization and M for maximization).
+ * We currently assume that the output dimensions in the original map
+ * are bounded, so this cannot occur.
+ * Similarly, when x' appears in a row, then the coefficient of M in that
+ * row is necessarily 1.
+ * If the row in the tableau represents
+ *	d x' = c + d M + e(y)
+ * then, in case of minimization, the corresponding row in the matrix
+ * will be
+ *	a c + a e(y)
+ * with a d = m, the (updated) common denominator of the matrix.
+ * In case of maximization, the row will be
+ *	-a c - a e(y)
+ */
+static void sol_add(struct isl_sol *sol, struct isl_tab *tab)
+{
+	struct isl_basic_set *bset = NULL;
+	struct isl_mat *mat = NULL;
+	unsigned off;
+	int row;
+	isl_int m;
+
+	if (sol->error || !tab)
+		goto error;
+
+	if (tab->empty && !sol->add_empty)
+		return;
+	if (sol->context->op->is_empty(sol->context))
+		return;
+
+	bset = sol_domain(sol);
+
+	if (tab->empty) {
+		sol_push_sol(sol, bset, NULL);
+		return;
+	}
+
+	off = 2 + tab->M;
+
+	mat = isl_mat_alloc(tab->mat->ctx, 1 + sol->n_out,
+					    1 + tab->n_param + tab->n_div);
+	if (!mat)
+		goto error;
+
+	isl_int_init(m);
+
+	isl_seq_clr(mat->row[0] + 1, mat->n_col - 1);
+	isl_int_set_si(mat->row[0][0], 1);
+	for (row = 0; row < sol->n_out; ++row) {
+		int i = tab->n_param + row;
+		int r, j;
+
+		isl_seq_clr(mat->row[1 + row], mat->n_col);
+		if (!tab->var[i].is_row) {
+			if (tab->M)
+				isl_die(mat->ctx, isl_error_invalid,
+					"unbounded optimum", goto error2);
+			continue;
+		}
+
+		r = tab->var[i].index;
+		if (tab->M &&
+		    isl_int_ne(tab->mat->row[r][2], tab->mat->row[r][0]))
+			isl_die(mat->ctx, isl_error_invalid,
+				"unbounded optimum", goto error2);
+		isl_int_gcd(m, mat->row[0][0], tab->mat->row[r][0]);
+		isl_int_divexact(m, tab->mat->row[r][0], m);
+		scale_rows(mat, m, 1 + row);
+		isl_int_divexact(m, mat->row[0][0], tab->mat->row[r][0]);
+		isl_int_mul(mat->row[1 + row][0], m, tab->mat->row[r][1]);
+		for (j = 0; j < tab->n_param; ++j) {
+			int col;
+			if (tab->var[j].is_row)
+				continue;
+			col = tab->var[j].index;
+			isl_int_mul(mat->row[1 + row][1 + j], m,
+				    tab->mat->row[r][off + col]);
+		}
+		for (j = 0; j < tab->n_div; ++j) {
+			int col;
+			if (tab->var[tab->n_var - tab->n_div+j].is_row)
+				continue;
+			col = tab->var[tab->n_var - tab->n_div+j].index;
+			isl_int_mul(mat->row[1 + row][1 + tab->n_param + j], m,
+				    tab->mat->row[r][off + col]);
+		}
+		if (sol->max)
+			isl_seq_neg(mat->row[1 + row], mat->row[1 + row],
+				    mat->n_col);
+	}
+
+	isl_int_clear(m);
+
+	sol_push_sol_mat(sol, bset, mat);
+	return;
+error2:
+	isl_int_clear(m);
+error:
+	isl_basic_set_free(bset);
+	isl_mat_free(mat);
+	sol->error = 1;
+}
+
+struct isl_sol_map {
+	struct isl_sol	sol;
+	struct isl_map	*map;
+	struct isl_set	*empty;
+};
+
+static void sol_map_free(struct isl_sol *sol)
+{
+	struct isl_sol_map *sol_map = (struct isl_sol_map *) sol;
+	isl_map_free(sol_map->map);
+	isl_set_free(sol_map->empty);
+}
+
+/* This function is called for parts of the context where there is
+ * no solution, with "bset" corresponding to the context tableau.
+ * Simply add the basic set to the set "empty".
+ */
+static void sol_map_add_empty(struct isl_sol_map *sol,
+	struct isl_basic_set *bset)
+{
+	if (!bset || !sol->empty)
+		goto error;
+
+	sol->empty = isl_set_grow(sol->empty, 1);
+	bset = isl_basic_set_simplify(bset);
+	bset = isl_basic_set_finalize(bset);
+	sol->empty = isl_set_add_basic_set(sol->empty, isl_basic_set_copy(bset));
+	if (!sol->empty)
+		goto error;
+	isl_basic_set_free(bset);
+	return;
+error:
+	isl_basic_set_free(bset);
+	sol->sol.error = 1;
+}
+
+static void sol_map_add_empty_wrap(struct isl_sol *sol,
+	struct isl_basic_set *bset)
+{
+	sol_map_add_empty((struct isl_sol_map *)sol, bset);
+}
+
+/* Given a basic set "dom" that represents the context and a tuple of
+ * affine expressions "ma" defined over this domain, construct a basic map
+ * that expresses this function on the domain.
+ */
+static void sol_map_add(struct isl_sol_map *sol,
+	__isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma)
+{
+	isl_basic_map *bmap;
+
+	if (sol->sol.error || !dom || !ma)
+		goto error;
+
+	bmap = isl_basic_map_from_multi_aff2(ma, sol->sol.rational);
+	bmap = isl_basic_map_intersect_domain(bmap, dom);
+	sol->map = isl_map_grow(sol->map, 1);
+	sol->map = isl_map_add_basic_map(sol->map, bmap);
+	if (!sol->map)
+		sol->sol.error = 1;
+	return;
+error:
+	isl_basic_set_free(dom);
+	isl_multi_aff_free(ma);
+	sol->sol.error = 1;
+}
+
+static void sol_map_add_wrap(struct isl_sol *sol,
+	__isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma)
+{
+	sol_map_add((struct isl_sol_map *)sol, dom, ma);
+}
+
+
+/* Store the "parametric constant" of row "row" of tableau "tab" in "line",
+ * i.e., the constant term and the coefficients of all variables that
+ * appear in the context tableau.
+ * Note that the coefficient of the big parameter M is NOT copied.
+ * The context tableau may not have a big parameter and even when it
+ * does, it is a different big parameter.
+ */
+static void get_row_parameter_line(struct isl_tab *tab, int row, isl_int *line)
+{
+	int i;
+	unsigned off = 2 + tab->M;
+
+	isl_int_set(line[0], tab->mat->row[row][1]);
+	for (i = 0; i < tab->n_param; ++i) {
+		if (tab->var[i].is_row)
+			isl_int_set_si(line[1 + i], 0);
+		else {
+			int col = tab->var[i].index;
+			isl_int_set(line[1 + i], tab->mat->row[row][off + col]);
+		}
+	}
+	for (i = 0; i < tab->n_div; ++i) {
+		if (tab->var[tab->n_var - tab->n_div + i].is_row)
+			isl_int_set_si(line[1 + tab->n_param + i], 0);
+		else {
+			int col = tab->var[tab->n_var - tab->n_div + i].index;
+			isl_int_set(line[1 + tab->n_param + i],
+				    tab->mat->row[row][off + col]);
+		}
+	}
+}
+
+/* Check if rows "row1" and "row2" have identical "parametric constants",
+ * as explained above.
+ * In this case, we also insist that the coefficients of the big parameter
+ * be the same as the values of the constants will only be the same
+ * if these coefficients are also the same.
+ */
+static int identical_parameter_line(struct isl_tab *tab, int row1, int row2)
+{
+	int i;
+	unsigned off = 2 + tab->M;
+
+	if (isl_int_ne(tab->mat->row[row1][1], tab->mat->row[row2][1]))
+		return 0;
+
+	if (tab->M && isl_int_ne(tab->mat->row[row1][2],
+				 tab->mat->row[row2][2]))
+		return 0;
+
+	for (i = 0; i < tab->n_param + tab->n_div; ++i) {
+		int pos = i < tab->n_param ? i :
+			tab->n_var - tab->n_div + i - tab->n_param;
+		int col;
+
+		if (tab->var[pos].is_row)
+			continue;
+		col = tab->var[pos].index;
+		if (isl_int_ne(tab->mat->row[row1][off + col],
+			       tab->mat->row[row2][off + col]))
+			return 0;
+	}
+	return 1;
+}
+
+/* Return an inequality that expresses that the "parametric constant"
+ * should be non-negative.
+ * This function is only called when the coefficient of the big parameter
+ * is equal to zero.
+ */
+static struct isl_vec *get_row_parameter_ineq(struct isl_tab *tab, int row)
+{
+	struct isl_vec *ineq;
+
+	ineq = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_param + tab->n_div);
+	if (!ineq)
+		return NULL;
+
+	get_row_parameter_line(tab, row, ineq->el);
+	if (ineq)
+		ineq = isl_vec_normalize(ineq);
+
+	return ineq;
+}
+
+/* Normalize a div expression of the form
+ *
+ *	[(g*f(x) + c)/(g * m)]
+ *
+ * with c the constant term and f(x) the remaining coefficients, to
+ *
+ *	[(f(x) + [c/g])/m]
+ */
+static void normalize_div(__isl_keep isl_vec *div)
+{
+	isl_ctx *ctx = isl_vec_get_ctx(div);
+	int len = div->size - 2;
+
+	isl_seq_gcd(div->el + 2, len, &ctx->normalize_gcd);
+	isl_int_gcd(ctx->normalize_gcd, ctx->normalize_gcd, div->el[0]);
+
+	if (isl_int_is_one(ctx->normalize_gcd))
+		return;
+
+	isl_int_divexact(div->el[0], div->el[0], ctx->normalize_gcd);
+	isl_int_fdiv_q(div->el[1], div->el[1], ctx->normalize_gcd);
+	isl_seq_scale_down(div->el + 2, div->el + 2, ctx->normalize_gcd, len);
+}
+
+/* Return an integer division for use in a parametric cut based
+ * on the given row.
+ * In particular, let the parametric constant of the row be
+ *
+ *		\sum_i a_i y_i
+ *
+ * where y_0 = 1, but none of the y_i corresponds to the big parameter M.
+ * The div returned is equal to
+ *
+ *		floor(\sum_i {-a_i} y_i) = floor((\sum_i (-a_i mod d) y_i)/d)
+ */
+static struct isl_vec *get_row_parameter_div(struct isl_tab *tab, int row)
+{
+	struct isl_vec *div;
+
+	div = isl_vec_alloc(tab->mat->ctx, 1 + 1 + tab->n_param + tab->n_div);
+	if (!div)
+		return NULL;
+
+	isl_int_set(div->el[0], tab->mat->row[row][0]);
+	get_row_parameter_line(tab, row, div->el + 1);
+	isl_seq_neg(div->el + 1, div->el + 1, div->size - 1);
+	normalize_div(div);
+	isl_seq_fdiv_r(div->el + 1, div->el + 1, div->el[0], div->size - 1);
+
+	return div;
+}
+
+/* Return an integer division for use in transferring an integrality constraint
+ * to the context.
+ * In particular, let the parametric constant of the row be
+ *
+ *		\sum_i a_i y_i
+ *
+ * where y_0 = 1, but none of the y_i corresponds to the big parameter M.
+ * The the returned div is equal to
+ *
+ *		floor(\sum_i {a_i} y_i) = floor((\sum_i (a_i mod d) y_i)/d)
+ */
+static struct isl_vec *get_row_split_div(struct isl_tab *tab, int row)
+{
+	struct isl_vec *div;
+
+	div = isl_vec_alloc(tab->mat->ctx, 1 + 1 + tab->n_param + tab->n_div);
+	if (!div)
+		return NULL;
+
+	isl_int_set(div->el[0], tab->mat->row[row][0]);
+	get_row_parameter_line(tab, row, div->el + 1);
+	normalize_div(div);
+	isl_seq_fdiv_r(div->el + 1, div->el + 1, div->el[0], div->size - 1);
+
+	return div;
+}
+
+/* Construct and return an inequality that expresses an upper bound
+ * on the given div.
+ * In particular, if the div is given by
+ *
+ *	d = floor(e/m)
+ *
+ * then the inequality expresses
+ *
+ *	m d <= e
+ */
+static __isl_give isl_vec *ineq_for_div(__isl_keep isl_basic_set *bset,
+	unsigned div)
+{
+	unsigned total;
+	unsigned div_pos;
+	struct isl_vec *ineq;
+
+	if (!bset)
+		return NULL;
+
+	total = isl_basic_set_total_dim(bset);
+	div_pos = 1 + total - bset->n_div + div;
+
+	ineq = isl_vec_alloc(bset->ctx, 1 + total);
+	if (!ineq)
+		return NULL;
+
+	isl_seq_cpy(ineq->el, bset->div[div] + 1, 1 + total);
+	isl_int_neg(ineq->el[div_pos], bset->div[div][0]);
+	return ineq;
+}
+
+/* Given a row in the tableau and a div that was created
+ * using get_row_split_div and that has been constrained to equality, i.e.,
+ *
+ *		d = floor(\sum_i {a_i} y_i) = \sum_i {a_i} y_i
+ *
+ * replace the expression "\sum_i {a_i} y_i" in the row by d,
+ * i.e., we subtract "\sum_i {a_i} y_i" and add 1 d.
+ * The coefficients of the non-parameters in the tableau have been
+ * verified to be integral.  We can therefore simply replace coefficient b
+ * by floor(b).  For the coefficients of the parameters we have
+ * floor(a_i) = a_i - {a_i}, while for the other coefficients, we have
+ * floor(b) = b.
+ */
+static struct isl_tab *set_row_cst_to_div(struct isl_tab *tab, int row, int div)
+{
+	isl_seq_fdiv_q(tab->mat->row[row] + 1, tab->mat->row[row] + 1,
+			tab->mat->row[row][0], 1 + tab->M + tab->n_col);
+
+	isl_int_set_si(tab->mat->row[row][0], 1);
+
+	if (tab->var[tab->n_var - tab->n_div + div].is_row) {
+		int drow = tab->var[tab->n_var - tab->n_div + div].index;
+
+		isl_assert(tab->mat->ctx,
+			isl_int_is_one(tab->mat->row[drow][0]), goto error);
+		isl_seq_combine(tab->mat->row[row] + 1,
+			tab->mat->ctx->one, tab->mat->row[row] + 1,
+			tab->mat->ctx->one, tab->mat->row[drow] + 1,
+			1 + tab->M + tab->n_col);
+	} else {
+		int dcol = tab->var[tab->n_var - tab->n_div + div].index;
+
+		isl_int_add_ui(tab->mat->row[row][2 + tab->M + dcol],
+				tab->mat->row[row][2 + tab->M + dcol], 1);
+	}
+
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Check if the (parametric) constant of the given row is obviously
+ * negative, meaning that we don't need to consult the context tableau.
+ * If there is a big parameter and its coefficient is non-zero,
+ * then this coefficient determines the outcome.
+ * Otherwise, we check whether the constant is negative and
+ * all non-zero coefficients of parameters are negative and
+ * belong to non-negative parameters.
+ */
+static int is_obviously_neg(struct isl_tab *tab, int row)
+{
+	int i;
+	int col;
+	unsigned off = 2 + tab->M;
+
+	if (tab->M) {
+		if (isl_int_is_pos(tab->mat->row[row][2]))
+			return 0;
+		if (isl_int_is_neg(tab->mat->row[row][2]))
+			return 1;
+	}
+
+	if (isl_int_is_nonneg(tab->mat->row[row][1]))
+		return 0;
+	for (i = 0; i < tab->n_param; ++i) {
+		/* Eliminated parameter */
+		if (tab->var[i].is_row)
+			continue;
+		col = tab->var[i].index;
+		if (isl_int_is_zero(tab->mat->row[row][off + col]))
+			continue;
+		if (!tab->var[i].is_nonneg)
+			return 0;
+		if (isl_int_is_pos(tab->mat->row[row][off + col]))
+			return 0;
+	}
+	for (i = 0; i < tab->n_div; ++i) {
+		if (tab->var[tab->n_var - tab->n_div + i].is_row)
+			continue;
+		col = tab->var[tab->n_var - tab->n_div + i].index;
+		if (isl_int_is_zero(tab->mat->row[row][off + col]))
+			continue;
+		if (!tab->var[tab->n_var - tab->n_div + i].is_nonneg)
+			return 0;
+		if (isl_int_is_pos(tab->mat->row[row][off + col]))
+			return 0;
+	}
+	return 1;
+}
+
+/* Check if the (parametric) constant of the given row is obviously
+ * non-negative, meaning that we don't need to consult the context tableau.
+ * If there is a big parameter and its coefficient is non-zero,
+ * then this coefficient determines the outcome.
+ * Otherwise, we check whether the constant is non-negative and
+ * all non-zero coefficients of parameters are positive and
+ * belong to non-negative parameters.
+ */
+static int is_obviously_nonneg(struct isl_tab *tab, int row)
+{
+	int i;
+	int col;
+	unsigned off = 2 + tab->M;
+
+	if (tab->M) {
+		if (isl_int_is_pos(tab->mat->row[row][2]))
+			return 1;
+		if (isl_int_is_neg(tab->mat->row[row][2]))
+			return 0;
+	}
+
+	if (isl_int_is_neg(tab->mat->row[row][1]))
+		return 0;
+	for (i = 0; i < tab->n_param; ++i) {
+		/* Eliminated parameter */
+		if (tab->var[i].is_row)
+			continue;
+		col = tab->var[i].index;
+		if (isl_int_is_zero(tab->mat->row[row][off + col]))
+			continue;
+		if (!tab->var[i].is_nonneg)
+			return 0;
+		if (isl_int_is_neg(tab->mat->row[row][off + col]))
+			return 0;
+	}
+	for (i = 0; i < tab->n_div; ++i) {
+		if (tab->var[tab->n_var - tab->n_div + i].is_row)
+			continue;
+		col = tab->var[tab->n_var - tab->n_div + i].index;
+		if (isl_int_is_zero(tab->mat->row[row][off + col]))
+			continue;
+		if (!tab->var[tab->n_var - tab->n_div + i].is_nonneg)
+			return 0;
+		if (isl_int_is_neg(tab->mat->row[row][off + col]))
+			return 0;
+	}
+	return 1;
+}
+
+/* Given a row r and two columns, return the column that would
+ * lead to the lexicographically smallest increment in the sample
+ * solution when leaving the basis in favor of the row.
+ * Pivoting with column c will increment the sample value by a non-negative
+ * constant times a_{V,c}/a_{r,c}, with a_{V,c} the elements of column c
+ * corresponding to the non-parametric variables.
+ * If variable v appears in a column c_v, the a_{v,c} = 1 iff c = c_v,
+ * with all other entries in this virtual row equal to zero.
+ * If variable v appears in a row, then a_{v,c} is the element in column c
+ * of that row.
+ *
+ * Let v be the first variable with a_{v,c1}/a_{r,c1} != a_{v,c2}/a_{r,c2}.
+ * Then if a_{v,c1}/a_{r,c1} < a_{v,c2}/a_{r,c2}, i.e.,
+ * a_{v,c2} a_{r,c1} - a_{v,c1} a_{r,c2} > 0, c1 results in the minimal
+ * increment.  Otherwise, it's c2.
+ */
+static int lexmin_col_pair(struct isl_tab *tab,
+	int row, int col1, int col2, isl_int tmp)
+{
+	int i;
+	isl_int *tr;
+
+	tr = tab->mat->row[row] + 2 + tab->M;
+
+	for (i = tab->n_param; i < tab->n_var - tab->n_div; ++i) {
+		int s1, s2;
+		isl_int *r;
+
+		if (!tab->var[i].is_row) {
+			if (tab->var[i].index == col1)
+				return col2;
+			if (tab->var[i].index == col2)
+				return col1;
+			continue;
+		}
+
+		if (tab->var[i].index == row)
+			continue;
+
+		r = tab->mat->row[tab->var[i].index] + 2 + tab->M;
+		s1 = isl_int_sgn(r[col1]);
+		s2 = isl_int_sgn(r[col2]);
+		if (s1 == 0 && s2 == 0)
+			continue;
+		if (s1 < s2)
+			return col1;
+		if (s2 < s1)
+			return col2;
+
+		isl_int_mul(tmp, r[col2], tr[col1]);
+		isl_int_submul(tmp, r[col1], tr[col2]);
+		if (isl_int_is_pos(tmp))
+			return col1;
+		if (isl_int_is_neg(tmp))
+			return col2;
+	}
+	return -1;
+}
+
+/* Given a row in the tableau, find and return the column that would
+ * result in the lexicographically smallest, but positive, increment
+ * in the sample point.
+ * If there is no such column, then return tab->n_col.
+ * If anything goes wrong, return -1.
+ */
+static int lexmin_pivot_col(struct isl_tab *tab, int row)
+{
+	int j;
+	int col = tab->n_col;
+	isl_int *tr;
+	isl_int tmp;
+
+	tr = tab->mat->row[row] + 2 + tab->M;
+
+	isl_int_init(tmp);
+
+	for (j = tab->n_dead; j < tab->n_col; ++j) {
+		if (tab->col_var[j] >= 0 &&
+		    (tab->col_var[j] < tab->n_param  ||
+		    tab->col_var[j] >= tab->n_var - tab->n_div))
+			continue;
+
+		if (!isl_int_is_pos(tr[j]))
+			continue;
+
+		if (col == tab->n_col)
+			col = j;
+		else
+			col = lexmin_col_pair(tab, row, col, j, tmp);
+		isl_assert(tab->mat->ctx, col >= 0, goto error);
+	}
+
+	isl_int_clear(tmp);
+	return col;
+error:
+	isl_int_clear(tmp);
+	return -1;
+}
+
+/* Return the first known violated constraint, i.e., a non-negative
+ * constraint that currently has an either obviously negative value
+ * or a previously determined to be negative value.
+ *
+ * If any constraint has a negative coefficient for the big parameter,
+ * if any, then we return one of these first.
+ */
+static int first_neg(struct isl_tab *tab)
+{
+	int row;
+
+	if (tab->M)
+		for (row = tab->n_redundant; row < tab->n_row; ++row) {
+			if (!isl_tab_var_from_row(tab, row)->is_nonneg)
+				continue;
+			if (!isl_int_is_neg(tab->mat->row[row][2]))
+				continue;
+			if (tab->row_sign)
+				tab->row_sign[row] = isl_tab_row_neg;
+			return row;
+		}
+	for (row = tab->n_redundant; row < tab->n_row; ++row) {
+		if (!isl_tab_var_from_row(tab, row)->is_nonneg)
+			continue;
+		if (tab->row_sign) {
+			if (tab->row_sign[row] == 0 &&
+			    is_obviously_neg(tab, row))
+				tab->row_sign[row] = isl_tab_row_neg;
+			if (tab->row_sign[row] != isl_tab_row_neg)
+				continue;
+		} else if (!is_obviously_neg(tab, row))
+			continue;
+		return row;
+	}
+	return -1;
+}
+
+/* Check whether the invariant that all columns are lexico-positive
+ * is satisfied.  This function is not called from the current code
+ * but is useful during debugging.
+ */
+static void check_lexpos(struct isl_tab *tab) __attribute__ ((unused));
+static void check_lexpos(struct isl_tab *tab)
+{
+	unsigned off = 2 + tab->M;
+	int col;
+	int var;
+	int row;
+
+	for (col = tab->n_dead; col < tab->n_col; ++col) {
+		if (tab->col_var[col] >= 0 &&
+		    (tab->col_var[col] < tab->n_param ||
+		     tab->col_var[col] >= tab->n_var - tab->n_div))
+			continue;
+		for (var = tab->n_param; var < tab->n_var - tab->n_div; ++var) {
+			if (!tab->var[var].is_row) {
+				if (tab->var[var].index == col)
+					break;
+				else
+					continue;
+			}
+			row = tab->var[var].index;
+			if (isl_int_is_zero(tab->mat->row[row][off + col]))
+				continue;
+			if (isl_int_is_pos(tab->mat->row[row][off + col]))
+				break;
+			fprintf(stderr, "lexneg column %d (row %d)\n",
+				col, row);
+		}
+		if (var >= tab->n_var - tab->n_div)
+			fprintf(stderr, "zero column %d\n", col);
+	}
+}
+
+/* Report to the caller that the given constraint is part of an encountered
+ * conflict.
+ */
+static int report_conflicting_constraint(struct isl_tab *tab, int con)
+{
+	return tab->conflict(con, tab->conflict_user);
+}
+
+/* Given a conflicting row in the tableau, report all constraints
+ * involved in the row to the caller.  That is, the row itself
+ * (if it represents a constraint) and all constraint columns with
+ * non-zero (and therefore negative) coefficients.
+ */
+static int report_conflict(struct isl_tab *tab, int row)
+{
+	int j;
+	isl_int *tr;
+
+	if (!tab->conflict)
+		return 0;
+
+	if (tab->row_var[row] < 0 &&
+	    report_conflicting_constraint(tab, ~tab->row_var[row]) < 0)
+		return -1;
+
+	tr = tab->mat->row[row] + 2 + tab->M;
+
+	for (j = tab->n_dead; j < tab->n_col; ++j) {
+		if (tab->col_var[j] >= 0 &&
+		    (tab->col_var[j] < tab->n_param  ||
+		    tab->col_var[j] >= tab->n_var - tab->n_div))
+			continue;
+
+		if (!isl_int_is_neg(tr[j]))
+			continue;
+
+		if (tab->col_var[j] < 0 &&
+		    report_conflicting_constraint(tab, ~tab->col_var[j]) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Resolve all known or obviously violated constraints through pivoting.
+ * In particular, as long as we can find any violated constraint, we
+ * look for a pivoting column that would result in the lexicographically
+ * smallest increment in the sample point.  If there is no such column
+ * then the tableau is infeasible.
+ */
+static int restore_lexmin(struct isl_tab *tab) WARN_UNUSED;
+static int restore_lexmin(struct isl_tab *tab)
+{
+	int row, col;
+
+	if (!tab)
+		return -1;
+	if (tab->empty)
+		return 0;
+	while ((row = first_neg(tab)) != -1) {
+		col = lexmin_pivot_col(tab, row);
+		if (col >= tab->n_col) {
+			if (report_conflict(tab, row) < 0)
+				return -1;
+			if (isl_tab_mark_empty(tab) < 0)
+				return -1;
+			return 0;
+		}
+		if (col < 0)
+			return -1;
+		if (isl_tab_pivot(tab, row, col) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+/* Given a row that represents an equality, look for an appropriate
+ * pivoting column.
+ * In particular, if there are any non-zero coefficients among
+ * the non-parameter variables, then we take the last of these
+ * variables.  Eliminating this variable in terms of the other
+ * variables and/or parameters does not influence the property
+ * that all column in the initial tableau are lexicographically
+ * positive.  The row corresponding to the eliminated variable
+ * will only have non-zero entries below the diagonal of the
+ * initial tableau.  That is, we transform
+ *
+ *		I				I
+ *		  1		into		a
+ *		    I				  I
+ *
+ * If there is no such non-parameter variable, then we are dealing with
+ * pure parameter equality and we pick any parameter with coefficient 1 or -1
+ * for elimination.  This will ensure that the eliminated parameter
+ * always has an integer value whenever all the other parameters are integral.
+ * If there is no such parameter then we return -1.
+ */
+static int last_var_col_or_int_par_col(struct isl_tab *tab, int row)
+{
+	unsigned off = 2 + tab->M;
+	int i;
+
+	for (i = tab->n_var - tab->n_div - 1; i >= 0 && i >= tab->n_param; --i) {
+		int col;
+		if (tab->var[i].is_row)
+			continue;
+		col = tab->var[i].index;
+		if (col <= tab->n_dead)
+			continue;
+		if (!isl_int_is_zero(tab->mat->row[row][off + col]))
+			return col;
+	}
+	for (i = tab->n_dead; i < tab->n_col; ++i) {
+		if (isl_int_is_one(tab->mat->row[row][off + i]))
+			return i;
+		if (isl_int_is_negone(tab->mat->row[row][off + i]))
+			return i;
+	}
+	return -1;
+}
+
+/* Add an equality that is known to be valid to the tableau.
+ * We first check if we can eliminate a variable or a parameter.
+ * If not, we add the equality as two inequalities.
+ * In this case, the equality was a pure parameter equality and there
+ * is no need to resolve any constraint violations.
+ *
+ * This function assumes that at least two more rows and at least
+ * two more elements in the constraint array are available in the tableau.
+ */
+static struct isl_tab *add_lexmin_valid_eq(struct isl_tab *tab, isl_int *eq)
+{
+	int i;
+	int r;
+
+	if (!tab)
+		return NULL;
+	r = isl_tab_add_row(tab, eq);
+	if (r < 0)
+		goto error;
+
+	r = tab->con[r].index;
+	i = last_var_col_or_int_par_col(tab, r);
+	if (i < 0) {
+		tab->con[r].is_nonneg = 1;
+		if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)
+			goto error;
+		isl_seq_neg(eq, eq, 1 + tab->n_var);
+		r = isl_tab_add_row(tab, eq);
+		if (r < 0)
+			goto error;
+		tab->con[r].is_nonneg = 1;
+		if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)
+			goto error;
+	} else {
+		if (isl_tab_pivot(tab, r, i) < 0)
+			goto error;
+		if (isl_tab_kill_col(tab, i) < 0)
+			goto error;
+		tab->n_eq++;
+	}
+
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Check if the given row is a pure constant.
+ */
+static int is_constant(struct isl_tab *tab, int row)
+{
+	unsigned off = 2 + tab->M;
+
+	return isl_seq_first_non_zero(tab->mat->row[row] + off + tab->n_dead,
+					tab->n_col - tab->n_dead) == -1;
+}
+
+/* Add an equality that may or may not be valid to the tableau.
+ * If the resulting row is a pure constant, then it must be zero.
+ * Otherwise, the resulting tableau is empty.
+ *
+ * If the row is not a pure constant, then we add two inequalities,
+ * each time checking that they can be satisfied.
+ * In the end we try to use one of the two constraints to eliminate
+ * a column.
+ *
+ * This function assumes that at least two more rows and at least
+ * two more elements in the constraint array are available in the tableau.
+ */
+static int add_lexmin_eq(struct isl_tab *tab, isl_int *eq) WARN_UNUSED;
+static int add_lexmin_eq(struct isl_tab *tab, isl_int *eq)
+{
+	int r1, r2;
+	int row;
+	struct isl_tab_undo *snap;
+
+	if (!tab)
+		return -1;
+	snap = isl_tab_snap(tab);
+	r1 = isl_tab_add_row(tab, eq);
+	if (r1 < 0)
+		return -1;
+	tab->con[r1].is_nonneg = 1;
+	if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r1]) < 0)
+		return -1;
+
+	row = tab->con[r1].index;
+	if (is_constant(tab, row)) {
+		if (!isl_int_is_zero(tab->mat->row[row][1]) ||
+		    (tab->M && !isl_int_is_zero(tab->mat->row[row][2]))) {
+			if (isl_tab_mark_empty(tab) < 0)
+				return -1;
+			return 0;
+		}
+		if (isl_tab_rollback(tab, snap) < 0)
+			return -1;
+		return 0;
+	}
+
+	if (restore_lexmin(tab) < 0)
+		return -1;
+	if (tab->empty)
+		return 0;
+
+	isl_seq_neg(eq, eq, 1 + tab->n_var);
+
+	r2 = isl_tab_add_row(tab, eq);
+	if (r2 < 0)
+		return -1;
+	tab->con[r2].is_nonneg = 1;
+	if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r2]) < 0)
+		return -1;
+
+	if (restore_lexmin(tab) < 0)
+		return -1;
+	if (tab->empty)
+		return 0;
+
+	if (!tab->con[r1].is_row) {
+		if (isl_tab_kill_col(tab, tab->con[r1].index) < 0)
+			return -1;
+	} else if (!tab->con[r2].is_row) {
+		if (isl_tab_kill_col(tab, tab->con[r2].index) < 0)
+			return -1;
+	}
+
+	if (tab->bmap) {
+		tab->bmap = isl_basic_map_add_ineq(tab->bmap, eq);
+		if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)
+			return -1;
+		isl_seq_neg(eq, eq, 1 + tab->n_var);
+		tab->bmap = isl_basic_map_add_ineq(tab->bmap, eq);
+		isl_seq_neg(eq, eq, 1 + tab->n_var);
+		if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)
+			return -1;
+		if (!tab->bmap)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Add an inequality to the tableau, resolving violations using
+ * restore_lexmin.
+ *
+ * This function assumes that at least one more row and at least
+ * one more element in the constraint array are available in the tableau.
+ */
+static struct isl_tab *add_lexmin_ineq(struct isl_tab *tab, isl_int *ineq)
+{
+	int r;
+
+	if (!tab)
+		return NULL;
+	if (tab->bmap) {
+		tab->bmap = isl_basic_map_add_ineq(tab->bmap, ineq);
+		if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)
+			goto error;
+		if (!tab->bmap)
+			goto error;
+	}
+	r = isl_tab_add_row(tab, ineq);
+	if (r < 0)
+		goto error;
+	tab->con[r].is_nonneg = 1;
+	if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)
+		goto error;
+	if (isl_tab_row_is_redundant(tab, tab->con[r].index)) {
+		if (isl_tab_mark_redundant(tab, tab->con[r].index) < 0)
+			goto error;
+		return tab;
+	}
+
+	if (restore_lexmin(tab) < 0)
+		goto error;
+	if (!tab->empty && tab->con[r].is_row &&
+		 isl_tab_row_is_redundant(tab, tab->con[r].index))
+		if (isl_tab_mark_redundant(tab, tab->con[r].index) < 0)
+			goto error;
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Check if the coefficients of the parameters are all integral.
+ */
+static int integer_parameter(struct isl_tab *tab, int row)
+{
+	int i;
+	int col;
+	unsigned off = 2 + tab->M;
+
+	for (i = 0; i < tab->n_param; ++i) {
+		/* Eliminated parameter */
+		if (tab->var[i].is_row)
+			continue;
+		col = tab->var[i].index;
+		if (!isl_int_is_divisible_by(tab->mat->row[row][off + col],
+						tab->mat->row[row][0]))
+			return 0;
+	}
+	for (i = 0; i < tab->n_div; ++i) {
+		if (tab->var[tab->n_var - tab->n_div + i].is_row)
+			continue;
+		col = tab->var[tab->n_var - tab->n_div + i].index;
+		if (!isl_int_is_divisible_by(tab->mat->row[row][off + col],
+						tab->mat->row[row][0]))
+			return 0;
+	}
+	return 1;
+}
+
+/* Check if the coefficients of the non-parameter variables are all integral.
+ */
+static int integer_variable(struct isl_tab *tab, int row)
+{
+	int i;
+	unsigned off = 2 + tab->M;
+
+	for (i = tab->n_dead; i < tab->n_col; ++i) {
+		if (tab->col_var[i] >= 0 &&
+		    (tab->col_var[i] < tab->n_param ||
+		     tab->col_var[i] >= tab->n_var - tab->n_div))
+			continue;
+		if (!isl_int_is_divisible_by(tab->mat->row[row][off + i],
+						tab->mat->row[row][0]))
+			return 0;
+	}
+	return 1;
+}
+
+/* Check if the constant term is integral.
+ */
+static int integer_constant(struct isl_tab *tab, int row)
+{
+	return isl_int_is_divisible_by(tab->mat->row[row][1],
+					tab->mat->row[row][0]);
+}
+
+#define I_CST	1 << 0
+#define I_PAR	1 << 1
+#define I_VAR	1 << 2
+
+/* Check for next (non-parameter) variable after "var" (first if var == -1)
+ * that is non-integer and therefore requires a cut and return
+ * the index of the variable.
+ * For parametric tableaus, there are three parts in a row,
+ * the constant, the coefficients of the parameters and the rest.
+ * For each part, we check whether the coefficients in that part
+ * are all integral and if so, set the corresponding flag in *f.
+ * If the constant and the parameter part are integral, then the
+ * current sample value is integral and no cut is required
+ * (irrespective of whether the variable part is integral).
+ */
+static int next_non_integer_var(struct isl_tab *tab, int var, int *f)
+{
+	var = var < 0 ? tab->n_param : var + 1;
+
+	for (; var < tab->n_var - tab->n_div; ++var) {
+		int flags = 0;
+		int row;
+		if (!tab->var[var].is_row)
+			continue;
+		row = tab->var[var].index;
+		if (integer_constant(tab, row))
+			ISL_FL_SET(flags, I_CST);
+		if (integer_parameter(tab, row))
+			ISL_FL_SET(flags, I_PAR);
+		if (ISL_FL_ISSET(flags, I_CST) && ISL_FL_ISSET(flags, I_PAR))
+			continue;
+		if (integer_variable(tab, row))
+			ISL_FL_SET(flags, I_VAR);
+		*f = flags;
+		return var;
+	}
+	return -1;
+}
+
+/* Check for first (non-parameter) variable that is non-integer and
+ * therefore requires a cut and return the corresponding row.
+ * For parametric tableaus, there are three parts in a row,
+ * the constant, the coefficients of the parameters and the rest.
+ * For each part, we check whether the coefficients in that part
+ * are all integral and if so, set the corresponding flag in *f.
+ * If the constant and the parameter part are integral, then the
+ * current sample value is integral and no cut is required
+ * (irrespective of whether the variable part is integral).
+ */
+static int first_non_integer_row(struct isl_tab *tab, int *f)
+{
+	int var = next_non_integer_var(tab, -1, f);
+
+	return var < 0 ? -1 : tab->var[var].index;
+}
+
+/* Add a (non-parametric) cut to cut away the non-integral sample
+ * value of the given row.
+ *
+ * If the row is given by
+ *
+ *	m r = f + \sum_i a_i y_i
+ *
+ * then the cut is
+ *
+ *	c = - {-f/m} + \sum_i {a_i/m} y_i >= 0
+ *
+ * The big parameter, if any, is ignored, since it is assumed to be big
+ * enough to be divisible by any integer.
+ * If the tableau is actually a parametric tableau, then this function
+ * is only called when all coefficients of the parameters are integral.
+ * The cut therefore has zero coefficients for the parameters.
+ *
+ * The current value is known to be negative, so row_sign, if it
+ * exists, is set accordingly.
+ *
+ * Return the row of the cut or -1.
+ */
+static int add_cut(struct isl_tab *tab, int row)
+{
+	int i;
+	int r;
+	isl_int *r_row;
+	unsigned off = 2 + tab->M;
+
+	if (isl_tab_extend_cons(tab, 1) < 0)
+		return -1;
+	r = isl_tab_allocate_con(tab);
+	if (r < 0)
+		return -1;
+
+	r_row = tab->mat->row[tab->con[r].index];
+	isl_int_set(r_row[0], tab->mat->row[row][0]);
+	isl_int_neg(r_row[1], tab->mat->row[row][1]);
+	isl_int_fdiv_r(r_row[1], r_row[1], tab->mat->row[row][0]);
+	isl_int_neg(r_row[1], r_row[1]);
+	if (tab->M)
+		isl_int_set_si(r_row[2], 0);
+	for (i = 0; i < tab->n_col; ++i)
+		isl_int_fdiv_r(r_row[off + i],
+			tab->mat->row[row][off + i], tab->mat->row[row][0]);
+
+	tab->con[r].is_nonneg = 1;
+	if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)
+		return -1;
+	if (tab->row_sign)
+		tab->row_sign[tab->con[r].index] = isl_tab_row_neg;
+
+	return tab->con[r].index;
+}
+
+#define CUT_ALL 1
+#define CUT_ONE 0
+
+/* Given a non-parametric tableau, add cuts until an integer
+ * sample point is obtained or until the tableau is determined
+ * to be integer infeasible.
+ * As long as there is any non-integer value in the sample point,
+ * we add appropriate cuts, if possible, for each of these
+ * non-integer values and then resolve the violated
+ * cut constraints using restore_lexmin.
+ * If one of the corresponding rows is equal to an integral
+ * combination of variables/constraints plus a non-integral constant,
+ * then there is no way to obtain an integer point and we return
+ * a tableau that is marked empty.
+ * The parameter cutting_strategy controls the strategy used when adding cuts
+ * to remove non-integer points. CUT_ALL adds all possible cuts
+ * before continuing the search. CUT_ONE adds only one cut at a time.
+ */
+static struct isl_tab *cut_to_integer_lexmin(struct isl_tab *tab,
+	int cutting_strategy)
+{
+	int var;
+	int row;
+	int flags;
+
+	if (!tab)
+		return NULL;
+	if (tab->empty)
+		return tab;
+
+	while ((var = next_non_integer_var(tab, -1, &flags)) != -1) {
+		do {
+			if (ISL_FL_ISSET(flags, I_VAR)) {
+				if (isl_tab_mark_empty(tab) < 0)
+					goto error;
+				return tab;
+			}
+			row = tab->var[var].index;
+			row = add_cut(tab, row);
+			if (row < 0)
+				goto error;
+			if (cutting_strategy == CUT_ONE)
+				break;
+		} while ((var = next_non_integer_var(tab, var, &flags)) != -1);
+		if (restore_lexmin(tab) < 0)
+			goto error;
+		if (tab->empty)
+			break;
+	}
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Check whether all the currently active samples also satisfy the inequality
+ * "ineq" (treated as an equality if eq is set).
+ * Remove those samples that do not.
+ */
+static struct isl_tab *check_samples(struct isl_tab *tab, isl_int *ineq, int eq)
+{
+	int i;
+	isl_int v;
+
+	if (!tab)
+		return NULL;
+
+	isl_assert(tab->mat->ctx, tab->bmap, goto error);
+	isl_assert(tab->mat->ctx, tab->samples, goto error);
+	isl_assert(tab->mat->ctx, tab->samples->n_col == 1 + tab->n_var, goto error);
+
+	isl_int_init(v);
+	for (i = tab->n_outside; i < tab->n_sample; ++i) {
+		int sgn;
+		isl_seq_inner_product(ineq, tab->samples->row[i],
+					1 + tab->n_var, &v);
+		sgn = isl_int_sgn(v);
+		if (eq ? (sgn == 0) : (sgn >= 0))
+			continue;
+		tab = isl_tab_drop_sample(tab, i);
+		if (!tab)
+			break;
+	}
+	isl_int_clear(v);
+
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Check whether the sample value of the tableau is finite,
+ * i.e., either the tableau does not use a big parameter, or
+ * all values of the variables are equal to the big parameter plus
+ * some constant.  This constant is the actual sample value.
+ */
+static int sample_is_finite(struct isl_tab *tab)
+{
+	int i;
+
+	if (!tab->M)
+		return 1;
+
+	for (i = 0; i < tab->n_var; ++i) {
+		int row;
+		if (!tab->var[i].is_row)
+			return 0;
+		row = tab->var[i].index;
+		if (isl_int_ne(tab->mat->row[row][0], tab->mat->row[row][2]))
+			return 0;
+	}
+	return 1;
+}
+
+/* Check if the context tableau of sol has any integer points.
+ * Leave tab in empty state if no integer point can be found.
+ * If an integer point can be found and if moreover it is finite,
+ * then it is added to the list of sample values.
+ *
+ * This function is only called when none of the currently active sample
+ * values satisfies the most recently added constraint.
+ */
+static struct isl_tab *check_integer_feasible(struct isl_tab *tab)
+{
+	struct isl_tab_undo *snap;
+
+	if (!tab)
+		return NULL;
+
+	snap = isl_tab_snap(tab);
+	if (isl_tab_push_basis(tab) < 0)
+		goto error;
+
+	tab = cut_to_integer_lexmin(tab, CUT_ALL);
+	if (!tab)
+		goto error;
+
+	if (!tab->empty && sample_is_finite(tab)) {
+		struct isl_vec *sample;
+
+		sample = isl_tab_get_sample_value(tab);
+
+		if (isl_tab_add_sample(tab, sample) < 0)
+			goto error;
+	}
+
+	if (!tab->empty && isl_tab_rollback(tab, snap) < 0)
+		goto error;
+
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Check if any of the currently active sample values satisfies
+ * the inequality "ineq" (an equality if eq is set).
+ */
+static int tab_has_valid_sample(struct isl_tab *tab, isl_int *ineq, int eq)
+{
+	int i;
+	isl_int v;
+
+	if (!tab)
+		return -1;
+
+	isl_assert(tab->mat->ctx, tab->bmap, return -1);
+	isl_assert(tab->mat->ctx, tab->samples, return -1);
+	isl_assert(tab->mat->ctx, tab->samples->n_col == 1 + tab->n_var, return -1);
+
+	isl_int_init(v);
+	for (i = tab->n_outside; i < tab->n_sample; ++i) {
+		int sgn;
+		isl_seq_inner_product(ineq, tab->samples->row[i],
+					1 + tab->n_var, &v);
+		sgn = isl_int_sgn(v);
+		if (eq ? (sgn == 0) : (sgn >= 0))
+			break;
+	}
+	isl_int_clear(v);
+
+	return i < tab->n_sample;
+}
+
+/* Insert a div specified by "div" to the tableau "tab" at position "pos" and
+ * return isl_bool_true if the div is obviously non-negative.
+ */
+static isl_bool context_tab_insert_div(struct isl_tab *tab, int pos,
+	__isl_keep isl_vec *div,
+	isl_stat (*add_ineq)(void *user, isl_int *), void *user)
+{
+	int i;
+	int r;
+	struct isl_mat *samples;
+	int nonneg;
+
+	r = isl_tab_insert_div(tab, pos, div, add_ineq, user);
+	if (r < 0)
+		return isl_bool_error;
+	nonneg = tab->var[r].is_nonneg;
+	tab->var[r].frozen = 1;
+
+	samples = isl_mat_extend(tab->samples,
+			tab->n_sample, 1 + tab->n_var);
+	tab->samples = samples;
+	if (!samples)
+		return isl_bool_error;
+	for (i = tab->n_outside; i < samples->n_row; ++i) {
+		isl_seq_inner_product(div->el + 1, samples->row[i],
+			div->size - 1, &samples->row[i][samples->n_col - 1]);
+		isl_int_fdiv_q(samples->row[i][samples->n_col - 1],
+			       samples->row[i][samples->n_col - 1], div->el[0]);
+	}
+	tab->samples = isl_mat_move_cols(tab->samples, 1 + pos,
+					1 + tab->n_var - 1, 1);
+	if (!tab->samples)
+		return isl_bool_error;
+
+	return nonneg;
+}
+
+/* Add a div specified by "div" to both the main tableau and
+ * the context tableau.  In case of the main tableau, we only
+ * need to add an extra div.  In the context tableau, we also
+ * need to express the meaning of the div.
+ * Return the index of the div or -1 if anything went wrong.
+ *
+ * The new integer division is added before any unknown integer
+ * divisions in the context to ensure that it does not get
+ * equated to some linear combination involving unknown integer
+ * divisions.
+ */
+static int add_div(struct isl_tab *tab, struct isl_context *context,
+	__isl_keep isl_vec *div)
+{
+	int r;
+	int pos;
+	isl_bool nonneg;
+	struct isl_tab *context_tab = context->op->peek_tab(context);
+
+	if (!tab || !context_tab)
+		goto error;
+
+	pos = context_tab->n_var - context->n_unknown;
+	if ((nonneg = context->op->insert_div(context, pos, div)) < 0)
+		goto error;
+
+	if (!context->op->is_ok(context))
+		goto error;
+
+	pos = tab->n_var - context->n_unknown;
+	if (isl_tab_extend_vars(tab, 1) < 0)
+		goto error;
+	r = isl_tab_insert_var(tab, pos);
+	if (r < 0)
+		goto error;
+	if (nonneg)
+		tab->var[r].is_nonneg = 1;
+	tab->var[r].frozen = 1;
+	tab->n_div++;
+
+	return tab->n_div - 1 - context->n_unknown;
+error:
+	context->op->invalidate(context);
+	return -1;
+}
+
+static int find_div(struct isl_tab *tab, isl_int *div, isl_int denom)
+{
+	int i;
+	unsigned total = isl_basic_map_total_dim(tab->bmap);
+
+	for (i = 0; i < tab->bmap->n_div; ++i) {
+		if (isl_int_ne(tab->bmap->div[i][0], denom))
+			continue;
+		if (!isl_seq_eq(tab->bmap->div[i] + 1, div, 1 + total))
+			continue;
+		return i;
+	}
+	return -1;
+}
+
+/* Return the index of a div that corresponds to "div".
+ * We first check if we already have such a div and if not, we create one.
+ */
+static int get_div(struct isl_tab *tab, struct isl_context *context,
+	struct isl_vec *div)
+{
+	int d;
+	struct isl_tab *context_tab = context->op->peek_tab(context);
+
+	if (!context_tab)
+		return -1;
+
+	d = find_div(context_tab, div->el + 1, div->el[0]);
+	if (d != -1)
+		return d;
+
+	return add_div(tab, context, div);
+}
+
+/* Add a parametric cut to cut away the non-integral sample value
+ * of the give row.
+ * Let a_i be the coefficients of the constant term and the parameters
+ * and let b_i be the coefficients of the variables or constraints
+ * in basis of the tableau.
+ * Let q be the div q = floor(\sum_i {-a_i} y_i).
+ *
+ * The cut is expressed as
+ *
+ *	c = \sum_i -{-a_i} y_i + \sum_i {b_i} x_i + q >= 0
+ *
+ * If q did not already exist in the context tableau, then it is added first.
+ * If q is in a column of the main tableau then the "+ q" can be accomplished
+ * by setting the corresponding entry to the denominator of the constraint.
+ * If q happens to be in a row of the main tableau, then the corresponding
+ * row needs to be added instead (taking care of the denominators).
+ * Note that this is very unlikely, but perhaps not entirely impossible.
+ *
+ * The current value of the cut is known to be negative (or at least
+ * non-positive), so row_sign is set accordingly.
+ *
+ * Return the row of the cut or -1.
+ */
+static int add_parametric_cut(struct isl_tab *tab, int row,
+	struct isl_context *context)
+{
+	struct isl_vec *div;
+	int d;
+	int i;
+	int r;
+	isl_int *r_row;
+	int col;
+	int n;
+	unsigned off = 2 + tab->M;
+
+	if (!context)
+		return -1;
+
+	div = get_row_parameter_div(tab, row);
+	if (!div)
+		return -1;
+
+	n = tab->n_div - context->n_unknown;
+	d = context->op->get_div(context, tab, div);
+	isl_vec_free(div);
+	if (d < 0)
+		return -1;
+
+	if (isl_tab_extend_cons(tab, 1) < 0)
+		return -1;
+	r = isl_tab_allocate_con(tab);
+	if (r < 0)
+		return -1;
+
+	r_row = tab->mat->row[tab->con[r].index];
+	isl_int_set(r_row[0], tab->mat->row[row][0]);
+	isl_int_neg(r_row[1], tab->mat->row[row][1]);
+	isl_int_fdiv_r(r_row[1], r_row[1], tab->mat->row[row][0]);
+	isl_int_neg(r_row[1], r_row[1]);
+	if (tab->M)
+		isl_int_set_si(r_row[2], 0);
+	for (i = 0; i < tab->n_param; ++i) {
+		if (tab->var[i].is_row)
+			continue;
+		col = tab->var[i].index;
+		isl_int_neg(r_row[off + col], tab->mat->row[row][off + col]);
+		isl_int_fdiv_r(r_row[off + col], r_row[off + col],
+				tab->mat->row[row][0]);
+		isl_int_neg(r_row[off + col], r_row[off + col]);
+	}
+	for (i = 0; i < tab->n_div; ++i) {
+		if (tab->var[tab->n_var - tab->n_div + i].is_row)
+			continue;
+		col = tab->var[tab->n_var - tab->n_div + i].index;
+		isl_int_neg(r_row[off + col], tab->mat->row[row][off + col]);
+		isl_int_fdiv_r(r_row[off + col], r_row[off + col],
+				tab->mat->row[row][0]);
+		isl_int_neg(r_row[off + col], r_row[off + col]);
+	}
+	for (i = 0; i < tab->n_col; ++i) {
+		if (tab->col_var[i] >= 0 &&
+		    (tab->col_var[i] < tab->n_param ||
+		     tab->col_var[i] >= tab->n_var - tab->n_div))
+			continue;
+		isl_int_fdiv_r(r_row[off + i],
+			tab->mat->row[row][off + i], tab->mat->row[row][0]);
+	}
+	if (tab->var[tab->n_var - tab->n_div + d].is_row) {
+		isl_int gcd;
+		int d_row = tab->var[tab->n_var - tab->n_div + d].index;
+		isl_int_init(gcd);
+		isl_int_gcd(gcd, tab->mat->row[d_row][0], r_row[0]);
+		isl_int_divexact(r_row[0], r_row[0], gcd);
+		isl_int_divexact(gcd, tab->mat->row[d_row][0], gcd);
+		isl_seq_combine(r_row + 1, gcd, r_row + 1,
+				r_row[0], tab->mat->row[d_row] + 1,
+				off - 1 + tab->n_col);
+		isl_int_mul(r_row[0], r_row[0], tab->mat->row[d_row][0]);
+		isl_int_clear(gcd);
+	} else {
+		col = tab->var[tab->n_var - tab->n_div + d].index;
+		isl_int_set(r_row[off + col], tab->mat->row[row][0]);
+	}
+
+	tab->con[r].is_nonneg = 1;
+	if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)
+		return -1;
+	if (tab->row_sign)
+		tab->row_sign[tab->con[r].index] = isl_tab_row_neg;
+
+	row = tab->con[r].index;
+
+	if (d >= n && context->op->detect_equalities(context, tab) < 0)
+		return -1;
+
+	return row;
+}
+
+/* Construct a tableau for bmap that can be used for computing
+ * the lexicographic minimum (or maximum) of bmap.
+ * If not NULL, then dom is the domain where the minimum
+ * should be computed.  In this case, we set up a parametric
+ * tableau with row signs (initialized to "unknown").
+ * If M is set, then the tableau will use a big parameter.
+ * If max is set, then a maximum should be computed instead of a minimum.
+ * This means that for each variable x, the tableau will contain the variable
+ * x' = M - x, rather than x' = M + x.  This in turn means that the coefficient
+ * of the variables in all constraints are negated prior to adding them
+ * to the tableau.
+ */
+static __isl_give struct isl_tab *tab_for_lexmin(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_basic_set *dom, unsigned M, int max)
+{
+	int i;
+	struct isl_tab *tab;
+	unsigned n_var;
+	unsigned o_var;
+
+	tab = isl_tab_alloc(bmap->ctx, 2 * bmap->n_eq + bmap->n_ineq + 1,
+			    isl_basic_map_total_dim(bmap), M);
+	if (!tab)
+		return NULL;
+
+	tab->rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+	if (dom) {
+		tab->n_param = isl_basic_set_total_dim(dom) - dom->n_div;
+		tab->n_div = dom->n_div;
+		tab->row_sign = isl_calloc_array(bmap->ctx,
+					enum isl_tab_row_sign, tab->mat->n_row);
+		if (tab->mat->n_row && !tab->row_sign)
+			goto error;
+	}
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY)) {
+		if (isl_tab_mark_empty(tab) < 0)
+			goto error;
+		return tab;
+	}
+
+	for (i = tab->n_param; i < tab->n_var - tab->n_div; ++i) {
+		tab->var[i].is_nonneg = 1;
+		tab->var[i].frozen = 1;
+	}
+	o_var = 1 + tab->n_param;
+	n_var = tab->n_var - tab->n_param - tab->n_div;
+	for (i = 0; i < bmap->n_eq; ++i) {
+		if (max)
+			isl_seq_neg(bmap->eq[i] + o_var,
+				    bmap->eq[i] + o_var, n_var);
+		tab = add_lexmin_valid_eq(tab, bmap->eq[i]);
+		if (max)
+			isl_seq_neg(bmap->eq[i] + o_var,
+				    bmap->eq[i] + o_var, n_var);
+		if (!tab || tab->empty)
+			return tab;
+	}
+	if (bmap->n_eq && restore_lexmin(tab) < 0)
+		goto error;
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		if (max)
+			isl_seq_neg(bmap->ineq[i] + o_var,
+				    bmap->ineq[i] + o_var, n_var);
+		tab = add_lexmin_ineq(tab, bmap->ineq[i]);
+		if (max)
+			isl_seq_neg(bmap->ineq[i] + o_var,
+				    bmap->ineq[i] + o_var, n_var);
+		if (!tab || tab->empty)
+			return tab;
+	}
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Given a main tableau where more than one row requires a split,
+ * determine and return the "best" row to split on.
+ *
+ * Given two rows in the main tableau, if the inequality corresponding
+ * to the first row is redundant with respect to that of the second row
+ * in the current tableau, then it is better to split on the second row,
+ * since in the positive part, both rows will be positive.
+ * (In the negative part a pivot will have to be performed and just about
+ * anything can happen to the sign of the other row.)
+ *
+ * As a simple heuristic, we therefore select the row that makes the most
+ * of the other rows redundant.
+ *
+ * Perhaps it would also be useful to look at the number of constraints
+ * that conflict with any given constraint.
+ *
+ * best is the best row so far (-1 when we have not found any row yet).
+ * best_r is the number of other rows made redundant by row best.
+ * When best is still -1, bset_r is meaningless, but it is initialized
+ * to some arbitrary value (0) anyway.  Without this redundant initialization
+ * valgrind may warn about uninitialized memory accesses when isl
+ * is compiled with some versions of gcc.
+ */
+static int best_split(struct isl_tab *tab, struct isl_tab *context_tab)
+{
+	struct isl_tab_undo *snap;
+	int split;
+	int row;
+	int best = -1;
+	int best_r = 0;
+
+	if (isl_tab_extend_cons(context_tab, 2) < 0)
+		return -1;
+
+	snap = isl_tab_snap(context_tab);
+
+	for (split = tab->n_redundant; split < tab->n_row; ++split) {
+		struct isl_tab_undo *snap2;
+		struct isl_vec *ineq = NULL;
+		int r = 0;
+		int ok;
+
+		if (!isl_tab_var_from_row(tab, split)->is_nonneg)
+			continue;
+		if (tab->row_sign[split] != isl_tab_row_any)
+			continue;
+
+		ineq = get_row_parameter_ineq(tab, split);
+		if (!ineq)
+			return -1;
+		ok = isl_tab_add_ineq(context_tab, ineq->el) >= 0;
+		isl_vec_free(ineq);
+		if (!ok)
+			return -1;
+
+		snap2 = isl_tab_snap(context_tab);
+
+		for (row = tab->n_redundant; row < tab->n_row; ++row) {
+			struct isl_tab_var *var;
+
+			if (row == split)
+				continue;
+			if (!isl_tab_var_from_row(tab, row)->is_nonneg)
+				continue;
+			if (tab->row_sign[row] != isl_tab_row_any)
+				continue;
+
+			ineq = get_row_parameter_ineq(tab, row);
+			if (!ineq)
+				return -1;
+			ok = isl_tab_add_ineq(context_tab, ineq->el) >= 0;
+			isl_vec_free(ineq);
+			if (!ok)
+				return -1;
+			var = &context_tab->con[context_tab->n_con - 1];
+			if (!context_tab->empty &&
+			    !isl_tab_min_at_most_neg_one(context_tab, var))
+				r++;
+			if (isl_tab_rollback(context_tab, snap2) < 0)
+				return -1;
+		}
+		if (best == -1 || r > best_r) {
+			best = split;
+			best_r = r;
+		}
+		if (isl_tab_rollback(context_tab, snap) < 0)
+			return -1;
+	}
+
+	return best;
+}
+
+static struct isl_basic_set *context_lex_peek_basic_set(
+	struct isl_context *context)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	if (!clex->tab)
+		return NULL;
+	return isl_tab_peek_bset(clex->tab);
+}
+
+static struct isl_tab *context_lex_peek_tab(struct isl_context *context)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	return clex->tab;
+}
+
+static void context_lex_add_eq(struct isl_context *context, isl_int *eq,
+		int check, int update)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	if (isl_tab_extend_cons(clex->tab, 2) < 0)
+		goto error;
+	if (add_lexmin_eq(clex->tab, eq) < 0)
+		goto error;
+	if (check) {
+		int v = tab_has_valid_sample(clex->tab, eq, 1);
+		if (v < 0)
+			goto error;
+		if (!v)
+			clex->tab = check_integer_feasible(clex->tab);
+	}
+	if (update)
+		clex->tab = check_samples(clex->tab, eq, 1);
+	return;
+error:
+	isl_tab_free(clex->tab);
+	clex->tab = NULL;
+}
+
+static void context_lex_add_ineq(struct isl_context *context, isl_int *ineq,
+		int check, int update)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	if (isl_tab_extend_cons(clex->tab, 1) < 0)
+		goto error;
+	clex->tab = add_lexmin_ineq(clex->tab, ineq);
+	if (check) {
+		int v = tab_has_valid_sample(clex->tab, ineq, 0);
+		if (v < 0)
+			goto error;
+		if (!v)
+			clex->tab = check_integer_feasible(clex->tab);
+	}
+	if (update)
+		clex->tab = check_samples(clex->tab, ineq, 0);
+	return;
+error:
+	isl_tab_free(clex->tab);
+	clex->tab = NULL;
+}
+
+static isl_stat context_lex_add_ineq_wrap(void *user, isl_int *ineq)
+{
+	struct isl_context *context = (struct isl_context *)user;
+	context_lex_add_ineq(context, ineq, 0, 0);
+	return context->op->is_ok(context) ? isl_stat_ok : isl_stat_error;
+}
+
+/* Check which signs can be obtained by "ineq" on all the currently
+ * active sample values.  See row_sign for more information.
+ */
+static enum isl_tab_row_sign tab_ineq_sign(struct isl_tab *tab, isl_int *ineq,
+	int strict)
+{
+	int i;
+	int sgn;
+	isl_int tmp;
+	enum isl_tab_row_sign res = isl_tab_row_unknown;
+
+	isl_assert(tab->mat->ctx, tab->samples, return isl_tab_row_unknown);
+	isl_assert(tab->mat->ctx, tab->samples->n_col == 1 + tab->n_var,
+			return isl_tab_row_unknown);
+
+	isl_int_init(tmp);
+	for (i = tab->n_outside; i < tab->n_sample; ++i) {
+		isl_seq_inner_product(tab->samples->row[i], ineq,
+					1 + tab->n_var, &tmp);
+		sgn = isl_int_sgn(tmp);
+		if (sgn > 0 || (sgn == 0 && strict)) {
+			if (res == isl_tab_row_unknown)
+				res = isl_tab_row_pos;
+			if (res == isl_tab_row_neg)
+				res = isl_tab_row_any;
+		}
+		if (sgn < 0) {
+			if (res == isl_tab_row_unknown)
+				res = isl_tab_row_neg;
+			if (res == isl_tab_row_pos)
+				res = isl_tab_row_any;
+		}
+		if (res == isl_tab_row_any)
+			break;
+	}
+	isl_int_clear(tmp);
+
+	return res;
+}
+
+static enum isl_tab_row_sign context_lex_ineq_sign(struct isl_context *context,
+			isl_int *ineq, int strict)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	return tab_ineq_sign(clex->tab, ineq, strict);
+}
+
+/* Check whether "ineq" can be added to the tableau without rendering
+ * it infeasible.
+ */
+static int context_lex_test_ineq(struct isl_context *context, isl_int *ineq)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	struct isl_tab_undo *snap;
+	int feasible;
+
+	if (!clex->tab)
+		return -1;
+
+	if (isl_tab_extend_cons(clex->tab, 1) < 0)
+		return -1;
+
+	snap = isl_tab_snap(clex->tab);
+	if (isl_tab_push_basis(clex->tab) < 0)
+		return -1;
+	clex->tab = add_lexmin_ineq(clex->tab, ineq);
+	clex->tab = check_integer_feasible(clex->tab);
+	if (!clex->tab)
+		return -1;
+	feasible = !clex->tab->empty;
+	if (isl_tab_rollback(clex->tab, snap) < 0)
+		return -1;
+
+	return feasible;
+}
+
+static int context_lex_get_div(struct isl_context *context, struct isl_tab *tab,
+		struct isl_vec *div)
+{
+	return get_div(tab, context, div);
+}
+
+/* Insert a div specified by "div" to the context tableau at position "pos" and
+ * return isl_bool_true if the div is obviously non-negative.
+ * context_tab_add_div will always return isl_bool_true, because all variables
+ * in a isl_context_lex tableau are non-negative.
+ * However, if we are using a big parameter in the context, then this only
+ * reflects the non-negativity of the variable used to _encode_ the
+ * div, i.e., div' = M + div, so we can't draw any conclusions.
+ */
+static isl_bool context_lex_insert_div(struct isl_context *context, int pos,
+	__isl_keep isl_vec *div)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	isl_bool nonneg;
+	nonneg = context_tab_insert_div(clex->tab, pos, div,
+					context_lex_add_ineq_wrap, context);
+	if (nonneg < 0)
+		return isl_bool_error;
+	if (clex->tab->M)
+		return isl_bool_false;
+	return nonneg;
+}
+
+static int context_lex_detect_equalities(struct isl_context *context,
+		struct isl_tab *tab)
+{
+	return 0;
+}
+
+static int context_lex_best_split(struct isl_context *context,
+		struct isl_tab *tab)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	struct isl_tab_undo *snap;
+	int r;
+
+	snap = isl_tab_snap(clex->tab);
+	if (isl_tab_push_basis(clex->tab) < 0)
+		return -1;
+	r = best_split(tab, clex->tab);
+
+	if (r >= 0 && isl_tab_rollback(clex->tab, snap) < 0)
+		return -1;
+
+	return r;
+}
+
+static int context_lex_is_empty(struct isl_context *context)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	if (!clex->tab)
+		return -1;
+	return clex->tab->empty;
+}
+
+static void *context_lex_save(struct isl_context *context)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	struct isl_tab_undo *snap;
+
+	snap = isl_tab_snap(clex->tab);
+	if (isl_tab_push_basis(clex->tab) < 0)
+		return NULL;
+	if (isl_tab_save_samples(clex->tab) < 0)
+		return NULL;
+
+	return snap;
+}
+
+static void context_lex_restore(struct isl_context *context, void *save)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	if (isl_tab_rollback(clex->tab, (struct isl_tab_undo *)save) < 0) {
+		isl_tab_free(clex->tab);
+		clex->tab = NULL;
+	}
+}
+
+static void context_lex_discard(void *save)
+{
+}
+
+static int context_lex_is_ok(struct isl_context *context)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	return !!clex->tab;
+}
+
+/* For each variable in the context tableau, check if the variable can
+ * only attain non-negative values.  If so, mark the parameter as non-negative
+ * in the main tableau.  This allows for a more direct identification of some
+ * cases of violated constraints.
+ */
+static struct isl_tab *tab_detect_nonnegative_parameters(struct isl_tab *tab,
+	struct isl_tab *context_tab)
+{
+	int i;
+	struct isl_tab_undo *snap;
+	struct isl_vec *ineq = NULL;
+	struct isl_tab_var *var;
+	int n;
+
+	if (context_tab->n_var == 0)
+		return tab;
+
+	ineq = isl_vec_alloc(tab->mat->ctx, 1 + context_tab->n_var);
+	if (!ineq)
+		goto error;
+
+	if (isl_tab_extend_cons(context_tab, 1) < 0)
+		goto error;
+
+	snap = isl_tab_snap(context_tab);
+
+	n = 0;
+	isl_seq_clr(ineq->el, ineq->size);
+	for (i = 0; i < context_tab->n_var; ++i) {
+		isl_int_set_si(ineq->el[1 + i], 1);
+		if (isl_tab_add_ineq(context_tab, ineq->el) < 0)
+			goto error;
+		var = &context_tab->con[context_tab->n_con - 1];
+		if (!context_tab->empty &&
+		    !isl_tab_min_at_most_neg_one(context_tab, var)) {
+			int j = i;
+			if (i >= tab->n_param)
+				j = i - tab->n_param + tab->n_var - tab->n_div;
+			tab->var[j].is_nonneg = 1;
+			n++;
+		}
+		isl_int_set_si(ineq->el[1 + i], 0);
+		if (isl_tab_rollback(context_tab, snap) < 0)
+			goto error;
+	}
+
+	if (context_tab->M && n == context_tab->n_var) {
+		context_tab->mat = isl_mat_drop_cols(context_tab->mat, 2, 1);
+		context_tab->M = 0;
+	}
+
+	isl_vec_free(ineq);
+	return tab;
+error:
+	isl_vec_free(ineq);
+	isl_tab_free(tab);
+	return NULL;
+}
+
+static struct isl_tab *context_lex_detect_nonnegative_parameters(
+	struct isl_context *context, struct isl_tab *tab)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	struct isl_tab_undo *snap;
+
+	if (!tab)
+		return NULL;
+
+	snap = isl_tab_snap(clex->tab);
+	if (isl_tab_push_basis(clex->tab) < 0)
+		goto error;
+
+	tab = tab_detect_nonnegative_parameters(tab, clex->tab);
+
+	if (isl_tab_rollback(clex->tab, snap) < 0)
+		goto error;
+
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+static void context_lex_invalidate(struct isl_context *context)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	isl_tab_free(clex->tab);
+	clex->tab = NULL;
+}
+
+static __isl_null struct isl_context *context_lex_free(
+	struct isl_context *context)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	isl_tab_free(clex->tab);
+	free(clex);
+
+	return NULL;
+}
+
+struct isl_context_op isl_context_lex_op = {
+	context_lex_detect_nonnegative_parameters,
+	context_lex_peek_basic_set,
+	context_lex_peek_tab,
+	context_lex_add_eq,
+	context_lex_add_ineq,
+	context_lex_ineq_sign,
+	context_lex_test_ineq,
+	context_lex_get_div,
+	context_lex_insert_div,
+	context_lex_detect_equalities,
+	context_lex_best_split,
+	context_lex_is_empty,
+	context_lex_is_ok,
+	context_lex_save,
+	context_lex_restore,
+	context_lex_discard,
+	context_lex_invalidate,
+	context_lex_free,
+};
+
+static struct isl_tab *context_tab_for_lexmin(__isl_take isl_basic_set *bset)
+{
+	struct isl_tab *tab;
+
+	if (!bset)
+		return NULL;
+	tab = tab_for_lexmin(bset_to_bmap(bset), NULL, 1, 0);
+	if (isl_tab_track_bset(tab, bset) < 0)
+		goto error;
+	tab = isl_tab_init_samples(tab);
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+static struct isl_context *isl_context_lex_alloc(struct isl_basic_set *dom)
+{
+	struct isl_context_lex *clex;
+
+	if (!dom)
+		return NULL;
+
+	clex = isl_alloc_type(dom->ctx, struct isl_context_lex);
+	if (!clex)
+		return NULL;
+
+	clex->context.op = &isl_context_lex_op;
+
+	clex->tab = context_tab_for_lexmin(isl_basic_set_copy(dom));
+	if (restore_lexmin(clex->tab) < 0)
+		goto error;
+	clex->tab = check_integer_feasible(clex->tab);
+	if (!clex->tab)
+		goto error;
+
+	return &clex->context;
+error:
+	clex->context.op->free(&clex->context);
+	return NULL;
+}
+
+/* Representation of the context when using generalized basis reduction.
+ *
+ * "shifted" contains the offsets of the unit hypercubes that lie inside the
+ * context.  Any rational point in "shifted" can therefore be rounded
+ * up to an integer point in the context.
+ * If the context is constrained by any equality, then "shifted" is not used
+ * as it would be empty.
+ */
+struct isl_context_gbr {
+	struct isl_context context;
+	struct isl_tab *tab;
+	struct isl_tab *shifted;
+	struct isl_tab *cone;
+};
+
+static struct isl_tab *context_gbr_detect_nonnegative_parameters(
+	struct isl_context *context, struct isl_tab *tab)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	if (!tab)
+		return NULL;
+	return tab_detect_nonnegative_parameters(tab, cgbr->tab);
+}
+
+static struct isl_basic_set *context_gbr_peek_basic_set(
+	struct isl_context *context)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	if (!cgbr->tab)
+		return NULL;
+	return isl_tab_peek_bset(cgbr->tab);
+}
+
+static struct isl_tab *context_gbr_peek_tab(struct isl_context *context)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	return cgbr->tab;
+}
+
+/* Initialize the "shifted" tableau of the context, which
+ * contains the constraints of the original tableau shifted
+ * by the sum of all negative coefficients.  This ensures
+ * that any rational point in the shifted tableau can
+ * be rounded up to yield an integer point in the original tableau.
+ */
+static void gbr_init_shifted(struct isl_context_gbr *cgbr)
+{
+	int i, j;
+	struct isl_vec *cst;
+	struct isl_basic_set *bset = isl_tab_peek_bset(cgbr->tab);
+	unsigned dim = isl_basic_set_total_dim(bset);
+
+	cst = isl_vec_alloc(cgbr->tab->mat->ctx, bset->n_ineq);
+	if (!cst)
+		return;
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		isl_int_set(cst->el[i], bset->ineq[i][0]);
+		for (j = 0; j < dim; ++j) {
+			if (!isl_int_is_neg(bset->ineq[i][1 + j]))
+				continue;
+			isl_int_add(bset->ineq[i][0], bset->ineq[i][0],
+				    bset->ineq[i][1 + j]);
+		}
+	}
+
+	cgbr->shifted = isl_tab_from_basic_set(bset, 0);
+
+	for (i = 0; i < bset->n_ineq; ++i)
+		isl_int_set(bset->ineq[i][0], cst->el[i]);
+
+	isl_vec_free(cst);
+}
+
+/* Check if the shifted tableau is non-empty, and if so
+ * use the sample point to construct an integer point
+ * of the context tableau.
+ */
+static struct isl_vec *gbr_get_shifted_sample(struct isl_context_gbr *cgbr)
+{
+	struct isl_vec *sample;
+
+	if (!cgbr->shifted)
+		gbr_init_shifted(cgbr);
+	if (!cgbr->shifted)
+		return NULL;
+	if (cgbr->shifted->empty)
+		return isl_vec_alloc(cgbr->tab->mat->ctx, 0);
+
+	sample = isl_tab_get_sample_value(cgbr->shifted);
+	sample = isl_vec_ceil(sample);
+
+	return sample;
+}
+
+static __isl_give isl_basic_set *drop_constant_terms(
+	__isl_take isl_basic_set *bset)
+{
+	int i;
+
+	if (!bset)
+		return NULL;
+
+	for (i = 0; i < bset->n_eq; ++i)
+		isl_int_set_si(bset->eq[i][0], 0);
+
+	for (i = 0; i < bset->n_ineq; ++i)
+		isl_int_set_si(bset->ineq[i][0], 0);
+
+	return bset;
+}
+
+static int use_shifted(struct isl_context_gbr *cgbr)
+{
+	if (!cgbr->tab)
+		return 0;
+	return cgbr->tab->bmap->n_eq == 0 && cgbr->tab->bmap->n_div == 0;
+}
+
+static struct isl_vec *gbr_get_sample(struct isl_context_gbr *cgbr)
+{
+	struct isl_basic_set *bset;
+	struct isl_basic_set *cone;
+
+	if (isl_tab_sample_is_integer(cgbr->tab))
+		return isl_tab_get_sample_value(cgbr->tab);
+
+	if (use_shifted(cgbr)) {
+		struct isl_vec *sample;
+
+		sample = gbr_get_shifted_sample(cgbr);
+		if (!sample || sample->size > 0)
+			return sample;
+
+		isl_vec_free(sample);
+	}
+
+	if (!cgbr->cone) {
+		bset = isl_tab_peek_bset(cgbr->tab);
+		cgbr->cone = isl_tab_from_recession_cone(bset, 0);
+		if (!cgbr->cone)
+			return NULL;
+		if (isl_tab_track_bset(cgbr->cone,
+					isl_basic_set_copy(bset)) < 0)
+			return NULL;
+	}
+	if (isl_tab_detect_implicit_equalities(cgbr->cone) < 0)
+		return NULL;
+
+	if (cgbr->cone->n_dead == cgbr->cone->n_col) {
+		struct isl_vec *sample;
+		struct isl_tab_undo *snap;
+
+		if (cgbr->tab->basis) {
+			if (cgbr->tab->basis->n_col != 1 + cgbr->tab->n_var) {
+				isl_mat_free(cgbr->tab->basis);
+				cgbr->tab->basis = NULL;
+			}
+			cgbr->tab->n_zero = 0;
+			cgbr->tab->n_unbounded = 0;
+		}
+
+		snap = isl_tab_snap(cgbr->tab);
+
+		sample = isl_tab_sample(cgbr->tab);
+
+		if (!sample || isl_tab_rollback(cgbr->tab, snap) < 0) {
+			isl_vec_free(sample);
+			return NULL;
+		}
+
+		return sample;
+	}
+
+	cone = isl_basic_set_dup(isl_tab_peek_bset(cgbr->cone));
+	cone = drop_constant_terms(cone);
+	cone = isl_basic_set_update_from_tab(cone, cgbr->cone);
+	cone = isl_basic_set_underlying_set(cone);
+	cone = isl_basic_set_gauss(cone, NULL);
+
+	bset = isl_basic_set_dup(isl_tab_peek_bset(cgbr->tab));
+	bset = isl_basic_set_update_from_tab(bset, cgbr->tab);
+	bset = isl_basic_set_underlying_set(bset);
+	bset = isl_basic_set_gauss(bset, NULL);
+
+	return isl_basic_set_sample_with_cone(bset, cone);
+}
+
+static void check_gbr_integer_feasible(struct isl_context_gbr *cgbr)
+{
+	struct isl_vec *sample;
+
+	if (!cgbr->tab)
+		return;
+
+	if (cgbr->tab->empty)
+		return;
+
+	sample = gbr_get_sample(cgbr);
+	if (!sample)
+		goto error;
+
+	if (sample->size == 0) {
+		isl_vec_free(sample);
+		if (isl_tab_mark_empty(cgbr->tab) < 0)
+			goto error;
+		return;
+	}
+
+	if (isl_tab_add_sample(cgbr->tab, sample) < 0)
+		goto error;
+
+	return;
+error:
+	isl_tab_free(cgbr->tab);
+	cgbr->tab = NULL;
+}
+
+static struct isl_tab *add_gbr_eq(struct isl_tab *tab, isl_int *eq)
+{
+	if (!tab)
+		return NULL;
+
+	if (isl_tab_extend_cons(tab, 2) < 0)
+		goto error;
+
+	if (isl_tab_add_eq(tab, eq) < 0)
+		goto error;
+
+	return tab;
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Add the equality described by "eq" to the context.
+ * If "check" is set, then we check if the context is empty after
+ * adding the equality.
+ * If "update" is set, then we check if the samples are still valid.
+ *
+ * We do not explicitly add shifted copies of the equality to
+ * cgbr->shifted since they would conflict with each other.
+ * Instead, we directly mark cgbr->shifted empty.
+ */
+static void context_gbr_add_eq(struct isl_context *context, isl_int *eq,
+		int check, int update)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+
+	cgbr->tab = add_gbr_eq(cgbr->tab, eq);
+
+	if (cgbr->shifted && !cgbr->shifted->empty && use_shifted(cgbr)) {
+		if (isl_tab_mark_empty(cgbr->shifted) < 0)
+			goto error;
+	}
+
+	if (cgbr->cone && cgbr->cone->n_col != cgbr->cone->n_dead) {
+		if (isl_tab_extend_cons(cgbr->cone, 2) < 0)
+			goto error;
+		if (isl_tab_add_eq(cgbr->cone, eq) < 0)
+			goto error;
+	}
+
+	if (check) {
+		int v = tab_has_valid_sample(cgbr->tab, eq, 1);
+		if (v < 0)
+			goto error;
+		if (!v)
+			check_gbr_integer_feasible(cgbr);
+	}
+	if (update)
+		cgbr->tab = check_samples(cgbr->tab, eq, 1);
+	return;
+error:
+	isl_tab_free(cgbr->tab);
+	cgbr->tab = NULL;
+}
+
+static void add_gbr_ineq(struct isl_context_gbr *cgbr, isl_int *ineq)
+{
+	if (!cgbr->tab)
+		return;
+
+	if (isl_tab_extend_cons(cgbr->tab, 1) < 0)
+		goto error;
+
+	if (isl_tab_add_ineq(cgbr->tab, ineq) < 0)
+		goto error;
+
+	if (cgbr->shifted && !cgbr->shifted->empty && use_shifted(cgbr)) {
+		int i;
+		unsigned dim;
+		dim = isl_basic_map_total_dim(cgbr->tab->bmap);
+
+		if (isl_tab_extend_cons(cgbr->shifted, 1) < 0)
+			goto error;
+
+		for (i = 0; i < dim; ++i) {
+			if (!isl_int_is_neg(ineq[1 + i]))
+				continue;
+			isl_int_add(ineq[0], ineq[0], ineq[1 + i]);
+		}
+
+		if (isl_tab_add_ineq(cgbr->shifted, ineq) < 0)
+			goto error;
+
+		for (i = 0; i < dim; ++i) {
+			if (!isl_int_is_neg(ineq[1 + i]))
+				continue;
+			isl_int_sub(ineq[0], ineq[0], ineq[1 + i]);
+		}
+	}
+
+	if (cgbr->cone && cgbr->cone->n_col != cgbr->cone->n_dead) {
+		if (isl_tab_extend_cons(cgbr->cone, 1) < 0)
+			goto error;
+		if (isl_tab_add_ineq(cgbr->cone, ineq) < 0)
+			goto error;
+	}
+
+	return;
+error:
+	isl_tab_free(cgbr->tab);
+	cgbr->tab = NULL;
+}
+
+static void context_gbr_add_ineq(struct isl_context *context, isl_int *ineq,
+		int check, int update)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+
+	add_gbr_ineq(cgbr, ineq);
+	if (!cgbr->tab)
+		return;
+
+	if (check) {
+		int v = tab_has_valid_sample(cgbr->tab, ineq, 0);
+		if (v < 0)
+			goto error;
+		if (!v)
+			check_gbr_integer_feasible(cgbr);
+	}
+	if (update)
+		cgbr->tab = check_samples(cgbr->tab, ineq, 0);
+	return;
+error:
+	isl_tab_free(cgbr->tab);
+	cgbr->tab = NULL;
+}
+
+static isl_stat context_gbr_add_ineq_wrap(void *user, isl_int *ineq)
+{
+	struct isl_context *context = (struct isl_context *)user;
+	context_gbr_add_ineq(context, ineq, 0, 0);
+	return context->op->is_ok(context) ? isl_stat_ok : isl_stat_error;
+}
+
+static enum isl_tab_row_sign context_gbr_ineq_sign(struct isl_context *context,
+			isl_int *ineq, int strict)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	return tab_ineq_sign(cgbr->tab, ineq, strict);
+}
+
+/* Check whether "ineq" can be added to the tableau without rendering
+ * it infeasible.
+ */
+static int context_gbr_test_ineq(struct isl_context *context, isl_int *ineq)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	struct isl_tab_undo *snap;
+	struct isl_tab_undo *shifted_snap = NULL;
+	struct isl_tab_undo *cone_snap = NULL;
+	int feasible;
+
+	if (!cgbr->tab)
+		return -1;
+
+	if (isl_tab_extend_cons(cgbr->tab, 1) < 0)
+		return -1;
+
+	snap = isl_tab_snap(cgbr->tab);
+	if (cgbr->shifted)
+		shifted_snap = isl_tab_snap(cgbr->shifted);
+	if (cgbr->cone)
+		cone_snap = isl_tab_snap(cgbr->cone);
+	add_gbr_ineq(cgbr, ineq);
+	check_gbr_integer_feasible(cgbr);
+	if (!cgbr->tab)
+		return -1;
+	feasible = !cgbr->tab->empty;
+	if (isl_tab_rollback(cgbr->tab, snap) < 0)
+		return -1;
+	if (shifted_snap) {
+		if (isl_tab_rollback(cgbr->shifted, shifted_snap))
+			return -1;
+	} else if (cgbr->shifted) {
+		isl_tab_free(cgbr->shifted);
+		cgbr->shifted = NULL;
+	}
+	if (cone_snap) {
+		if (isl_tab_rollback(cgbr->cone, cone_snap))
+			return -1;
+	} else if (cgbr->cone) {
+		isl_tab_free(cgbr->cone);
+		cgbr->cone = NULL;
+	}
+
+	return feasible;
+}
+
+/* Return the column of the last of the variables associated to
+ * a column that has a non-zero coefficient.
+ * This function is called in a context where only coefficients
+ * of parameters or divs can be non-zero.
+ */
+static int last_non_zero_var_col(struct isl_tab *tab, isl_int *p)
+{
+	int i;
+	int col;
+
+	if (tab->n_var == 0)
+		return -1;
+
+	for (i = tab->n_var - 1; i >= 0; --i) {
+		if (i >= tab->n_param && i < tab->n_var - tab->n_div)
+			continue;
+		if (tab->var[i].is_row)
+			continue;
+		col = tab->var[i].index;
+		if (!isl_int_is_zero(p[col]))
+			return col;
+	}
+
+	return -1;
+}
+
+/* Look through all the recently added equalities in the context
+ * to see if we can propagate any of them to the main tableau.
+ *
+ * The newly added equalities in the context are encoded as pairs
+ * of inequalities starting at inequality "first".
+ *
+ * We tentatively add each of these equalities to the main tableau
+ * and if this happens to result in a row with a final coefficient
+ * that is one or negative one, we use it to kill a column
+ * in the main tableau.  Otherwise, we discard the tentatively
+ * added row.
+ * This tentative addition of equality constraints turns
+ * on the undo facility of the tableau.  Turn it off again
+ * at the end, assuming it was turned off to begin with.
+ *
+ * Return 0 on success and -1 on failure.
+ */
+static int propagate_equalities(struct isl_context_gbr *cgbr,
+	struct isl_tab *tab, unsigned first)
+{
+	int i;
+	struct isl_vec *eq = NULL;
+	isl_bool needs_undo;
+
+	needs_undo = isl_tab_need_undo(tab);
+	if (needs_undo < 0)
+		goto error;
+	eq = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var);
+	if (!eq)
+		goto error;
+
+	if (isl_tab_extend_cons(tab, (cgbr->tab->bmap->n_ineq - first)/2) < 0)
+		goto error;
+
+	isl_seq_clr(eq->el + 1 + tab->n_param,
+		    tab->n_var - tab->n_param - tab->n_div);
+	for (i = first; i < cgbr->tab->bmap->n_ineq; i += 2) {
+		int j;
+		int r;
+		struct isl_tab_undo *snap;
+		snap = isl_tab_snap(tab);
+
+		isl_seq_cpy(eq->el, cgbr->tab->bmap->ineq[i], 1 + tab->n_param);
+		isl_seq_cpy(eq->el + 1 + tab->n_var - tab->n_div,
+			    cgbr->tab->bmap->ineq[i] + 1 + tab->n_param,
+			    tab->n_div);
+
+		r = isl_tab_add_row(tab, eq->el);
+		if (r < 0)
+			goto error;
+		r = tab->con[r].index;
+		j = last_non_zero_var_col(tab, tab->mat->row[r] + 2 + tab->M);
+		if (j < 0 || j < tab->n_dead ||
+		    !isl_int_is_one(tab->mat->row[r][0]) ||
+		    (!isl_int_is_one(tab->mat->row[r][2 + tab->M + j]) &&
+		     !isl_int_is_negone(tab->mat->row[r][2 + tab->M + j]))) {
+			if (isl_tab_rollback(tab, snap) < 0)
+				goto error;
+			continue;
+		}
+		if (isl_tab_pivot(tab, r, j) < 0)
+			goto error;
+		if (isl_tab_kill_col(tab, j) < 0)
+			goto error;
+
+		if (restore_lexmin(tab) < 0)
+			goto error;
+	}
+
+	if (!needs_undo)
+		isl_tab_clear_undo(tab);
+	isl_vec_free(eq);
+
+	return 0;
+error:
+	isl_vec_free(eq);
+	isl_tab_free(cgbr->tab);
+	cgbr->tab = NULL;
+	return -1;
+}
+
+static int context_gbr_detect_equalities(struct isl_context *context,
+	struct isl_tab *tab)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	unsigned n_ineq;
+
+	if (!cgbr->cone) {
+		struct isl_basic_set *bset = isl_tab_peek_bset(cgbr->tab);
+		cgbr->cone = isl_tab_from_recession_cone(bset, 0);
+		if (!cgbr->cone)
+			goto error;
+		if (isl_tab_track_bset(cgbr->cone,
+					isl_basic_set_copy(bset)) < 0)
+			goto error;
+	}
+	if (isl_tab_detect_implicit_equalities(cgbr->cone) < 0)
+		goto error;
+
+	n_ineq = cgbr->tab->bmap->n_ineq;
+	cgbr->tab = isl_tab_detect_equalities(cgbr->tab, cgbr->cone);
+	if (!cgbr->tab)
+		return -1;
+	if (cgbr->tab->bmap->n_ineq > n_ineq &&
+	    propagate_equalities(cgbr, tab, n_ineq) < 0)
+		return -1;
+
+	return 0;
+error:
+	isl_tab_free(cgbr->tab);
+	cgbr->tab = NULL;
+	return -1;
+}
+
+static int context_gbr_get_div(struct isl_context *context, struct isl_tab *tab,
+		struct isl_vec *div)
+{
+	return get_div(tab, context, div);
+}
+
+static isl_bool context_gbr_insert_div(struct isl_context *context, int pos,
+	__isl_keep isl_vec *div)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	if (cgbr->cone) {
+		int r, n_div, o_div;
+
+		n_div = isl_basic_map_dim(cgbr->cone->bmap, isl_dim_div);
+		o_div = cgbr->cone->n_var - n_div;
+
+		if (isl_tab_extend_cons(cgbr->cone, 3) < 0)
+			return isl_bool_error;
+		if (isl_tab_extend_vars(cgbr->cone, 1) < 0)
+			return isl_bool_error;
+		if ((r = isl_tab_insert_var(cgbr->cone, pos)) <0)
+			return isl_bool_error;
+
+		cgbr->cone->bmap = isl_basic_map_insert_div(cgbr->cone->bmap,
+						    r - o_div, div);
+		if (!cgbr->cone->bmap)
+			return isl_bool_error;
+		if (isl_tab_push_var(cgbr->cone, isl_tab_undo_bmap_div,
+				    &cgbr->cone->var[r]) < 0)
+			return isl_bool_error;
+	}
+	return context_tab_insert_div(cgbr->tab, pos, div,
+					context_gbr_add_ineq_wrap, context);
+}
+
+static int context_gbr_best_split(struct isl_context *context,
+		struct isl_tab *tab)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	struct isl_tab_undo *snap;
+	int r;
+
+	snap = isl_tab_snap(cgbr->tab);
+	r = best_split(tab, cgbr->tab);
+
+	if (r >= 0 && isl_tab_rollback(cgbr->tab, snap) < 0)
+		return -1;
+
+	return r;
+}
+
+static int context_gbr_is_empty(struct isl_context *context)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	if (!cgbr->tab)
+		return -1;
+	return cgbr->tab->empty;
+}
+
+struct isl_gbr_tab_undo {
+	struct isl_tab_undo *tab_snap;
+	struct isl_tab_undo *shifted_snap;
+	struct isl_tab_undo *cone_snap;
+};
+
+static void *context_gbr_save(struct isl_context *context)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	struct isl_gbr_tab_undo *snap;
+
+	if (!cgbr->tab)
+		return NULL;
+
+	snap = isl_alloc_type(cgbr->tab->mat->ctx, struct isl_gbr_tab_undo);
+	if (!snap)
+		return NULL;
+
+	snap->tab_snap = isl_tab_snap(cgbr->tab);
+	if (isl_tab_save_samples(cgbr->tab) < 0)
+		goto error;
+
+	if (cgbr->shifted)
+		snap->shifted_snap = isl_tab_snap(cgbr->shifted);
+	else
+		snap->shifted_snap = NULL;
+
+	if (cgbr->cone)
+		snap->cone_snap = isl_tab_snap(cgbr->cone);
+	else
+		snap->cone_snap = NULL;
+
+	return snap;
+error:
+	free(snap);
+	return NULL;
+}
+
+static void context_gbr_restore(struct isl_context *context, void *save)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	struct isl_gbr_tab_undo *snap = (struct isl_gbr_tab_undo *)save;
+	if (!snap)
+		goto error;
+	if (isl_tab_rollback(cgbr->tab, snap->tab_snap) < 0)
+		goto error;
+
+	if (snap->shifted_snap) {
+		if (isl_tab_rollback(cgbr->shifted, snap->shifted_snap) < 0)
+			goto error;
+	} else if (cgbr->shifted) {
+		isl_tab_free(cgbr->shifted);
+		cgbr->shifted = NULL;
+	}
+
+	if (snap->cone_snap) {
+		if (isl_tab_rollback(cgbr->cone, snap->cone_snap) < 0)
+			goto error;
+	} else if (cgbr->cone) {
+		isl_tab_free(cgbr->cone);
+		cgbr->cone = NULL;
+	}
+
+	free(snap);
+
+	return;
+error:
+	free(snap);
+	isl_tab_free(cgbr->tab);
+	cgbr->tab = NULL;
+}
+
+static void context_gbr_discard(void *save)
+{
+	struct isl_gbr_tab_undo *snap = (struct isl_gbr_tab_undo *)save;
+	free(snap);
+}
+
+static int context_gbr_is_ok(struct isl_context *context)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	return !!cgbr->tab;
+}
+
+static void context_gbr_invalidate(struct isl_context *context)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	isl_tab_free(cgbr->tab);
+	cgbr->tab = NULL;
+}
+
+static __isl_null struct isl_context *context_gbr_free(
+	struct isl_context *context)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	isl_tab_free(cgbr->tab);
+	isl_tab_free(cgbr->shifted);
+	isl_tab_free(cgbr->cone);
+	free(cgbr);
+
+	return NULL;
+}
+
+struct isl_context_op isl_context_gbr_op = {
+	context_gbr_detect_nonnegative_parameters,
+	context_gbr_peek_basic_set,
+	context_gbr_peek_tab,
+	context_gbr_add_eq,
+	context_gbr_add_ineq,
+	context_gbr_ineq_sign,
+	context_gbr_test_ineq,
+	context_gbr_get_div,
+	context_gbr_insert_div,
+	context_gbr_detect_equalities,
+	context_gbr_best_split,
+	context_gbr_is_empty,
+	context_gbr_is_ok,
+	context_gbr_save,
+	context_gbr_restore,
+	context_gbr_discard,
+	context_gbr_invalidate,
+	context_gbr_free,
+};
+
+static struct isl_context *isl_context_gbr_alloc(__isl_keep isl_basic_set *dom)
+{
+	struct isl_context_gbr *cgbr;
+
+	if (!dom)
+		return NULL;
+
+	cgbr = isl_calloc_type(dom->ctx, struct isl_context_gbr);
+	if (!cgbr)
+		return NULL;
+
+	cgbr->context.op = &isl_context_gbr_op;
+
+	cgbr->shifted = NULL;
+	cgbr->cone = NULL;
+	cgbr->tab = isl_tab_from_basic_set(dom, 1);
+	cgbr->tab = isl_tab_init_samples(cgbr->tab);
+	if (!cgbr->tab)
+		goto error;
+	check_gbr_integer_feasible(cgbr);
+
+	return &cgbr->context;
+error:
+	cgbr->context.op->free(&cgbr->context);
+	return NULL;
+}
+
+/* Allocate a context corresponding to "dom".
+ * The representation specific fields are initialized by
+ * isl_context_lex_alloc or isl_context_gbr_alloc.
+ * The shared "n_unknown" field is initialized to the number
+ * of final unknown integer divisions in "dom".
+ */
+static struct isl_context *isl_context_alloc(__isl_keep isl_basic_set *dom)
+{
+	struct isl_context *context;
+	int first;
+
+	if (!dom)
+		return NULL;
+
+	if (dom->ctx->opt->context == ISL_CONTEXT_LEXMIN)
+		context = isl_context_lex_alloc(dom);
+	else
+		context = isl_context_gbr_alloc(dom);
+
+	if (!context)
+		return NULL;
+
+	first = isl_basic_set_first_unknown_div(dom);
+	if (first < 0)
+		return context->op->free(context);
+	context->n_unknown = isl_basic_set_dim(dom, isl_dim_div) - first;
+
+	return context;
+}
+
+/* Initialize some common fields of "sol", which keeps track
+ * of the solution of an optimization problem on "bmap" over
+ * the domain "dom".
+ * If "max" is set, then a maximization problem is being solved, rather than
+ * a minimization problem, which means that the variables in the
+ * tableau have value "M - x" rather than "M + x".
+ */
+static isl_stat sol_init(struct isl_sol *sol, __isl_keep isl_basic_map *bmap,
+	__isl_keep isl_basic_set *dom, int max)
+{
+	sol->rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+	sol->dec_level.callback.run = &sol_dec_level_wrap;
+	sol->dec_level.sol = sol;
+	sol->max = max;
+	sol->n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	sol->space = isl_basic_map_get_space(bmap);
+
+	sol->context = isl_context_alloc(dom);
+	if (!sol->space || !sol->context)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Construct an isl_sol_map structure for accumulating the solution.
+ * If track_empty is set, then we also keep track of the parts
+ * of the context where there is no solution.
+ * If max is set, then we are solving a maximization, rather than
+ * a minimization problem, which means that the variables in the
+ * tableau have value "M - x" rather than "M + x".
+ */
+static struct isl_sol *sol_map_init(__isl_keep isl_basic_map *bmap,
+	__isl_take isl_basic_set *dom, int track_empty, int max)
+{
+	struct isl_sol_map *sol_map = NULL;
+	isl_space *space;
+
+	if (!bmap)
+		goto error;
+
+	sol_map = isl_calloc_type(bmap->ctx, struct isl_sol_map);
+	if (!sol_map)
+		goto error;
+
+	sol_map->sol.free = &sol_map_free;
+	if (sol_init(&sol_map->sol, bmap, dom, max) < 0)
+		goto error;
+	sol_map->sol.add = &sol_map_add_wrap;
+	sol_map->sol.add_empty = track_empty ? &sol_map_add_empty_wrap : NULL;
+	space = isl_space_copy(sol_map->sol.space);
+	sol_map->map = isl_map_alloc_space(space, 1, ISL_MAP_DISJOINT);
+	if (!sol_map->map)
+		goto error;
+
+	if (track_empty) {
+		sol_map->empty = isl_set_alloc_space(isl_basic_set_get_space(dom),
+							1, ISL_SET_DISJOINT);
+		if (!sol_map->empty)
+			goto error;
+	}
+
+	isl_basic_set_free(dom);
+	return &sol_map->sol;
+error:
+	isl_basic_set_free(dom);
+	sol_free(&sol_map->sol);
+	return NULL;
+}
+
+/* Check whether all coefficients of (non-parameter) variables
+ * are non-positive, meaning that no pivots can be performed on the row.
+ */
+static int is_critical(struct isl_tab *tab, int row)
+{
+	int j;
+	unsigned off = 2 + tab->M;
+
+	for (j = tab->n_dead; j < tab->n_col; ++j) {
+		if (tab->col_var[j] >= 0 &&
+		    (tab->col_var[j] < tab->n_param  ||
+		    tab->col_var[j] >= tab->n_var - tab->n_div))
+			continue;
+
+		if (isl_int_is_pos(tab->mat->row[row][off + j]))
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Check whether the inequality represented by vec is strict over the integers,
+ * i.e., there are no integer values satisfying the constraint with
+ * equality.  This happens if the gcd of the coefficients is not a divisor
+ * of the constant term.  If so, scale the constraint down by the gcd
+ * of the coefficients.
+ */
+static int is_strict(struct isl_vec *vec)
+{
+	isl_int gcd;
+	int strict = 0;
+
+	isl_int_init(gcd);
+	isl_seq_gcd(vec->el + 1, vec->size - 1, &gcd);
+	if (!isl_int_is_one(gcd)) {
+		strict = !isl_int_is_divisible_by(vec->el[0], gcd);
+		isl_int_fdiv_q(vec->el[0], vec->el[0], gcd);
+		isl_seq_scale_down(vec->el + 1, vec->el + 1, gcd, vec->size-1);
+	}
+	isl_int_clear(gcd);
+
+	return strict;
+}
+
+/* Determine the sign of the given row of the main tableau.
+ * The result is one of
+ *	isl_tab_row_pos: always non-negative; no pivot needed
+ *	isl_tab_row_neg: always non-positive; pivot
+ *	isl_tab_row_any: can be both positive and negative; split
+ *
+ * We first handle some simple cases
+ *	- the row sign may be known already
+ *	- the row may be obviously non-negative
+ *	- the parametric constant may be equal to that of another row
+ *	  for which we know the sign.  This sign will be either "pos" or
+ *	  "any".  If it had been "neg" then we would have pivoted before.
+ *
+ * If none of these cases hold, we check the value of the row for each
+ * of the currently active samples.  Based on the signs of these values
+ * we make an initial determination of the sign of the row.
+ *
+ *	all zero			->	unk(nown)
+ *	all non-negative		->	pos
+ *	all non-positive		->	neg
+ *	both negative and positive	->	all
+ *
+ * If we end up with "all", we are done.
+ * Otherwise, we perform a check for positive and/or negative
+ * values as follows.
+ *
+ *	samples	       neg	       unk	       pos
+ *	<0 ?			    Y        N	    Y        N
+ *					    pos    any      pos
+ *	>0 ?	     Y      N	 Y     N
+ *		    any    neg  any   neg
+ *
+ * There is no special sign for "zero", because we can usually treat zero
+ * as either non-negative or non-positive, whatever works out best.
+ * However, if the row is "critical", meaning that pivoting is impossible
+ * then we don't want to limp zero with the non-positive case, because
+ * then we we would lose the solution for those values of the parameters
+ * where the value of the row is zero.  Instead, we treat 0 as non-negative
+ * ensuring a split if the row can attain both zero and negative values.
+ * The same happens when the original constraint was one that could not
+ * be satisfied with equality by any integer values of the parameters.
+ * In this case, we normalize the constraint, but then a value of zero
+ * for the normalized constraint is actually a positive value for the
+ * original constraint, so again we need to treat zero as non-negative.
+ * In both these cases, we have the following decision tree instead:
+ *
+ *	all non-negative		->	pos
+ *	all negative			->	neg
+ *	both negative and non-negative	->	all
+ *
+ *	samples	       neg	          	       pos
+ *	<0 ?			             	    Y        N
+ *					           any      pos
+ *	>=0 ?	     Y      N
+ *		    any    neg
+ */
+static enum isl_tab_row_sign row_sign(struct isl_tab *tab,
+	struct isl_sol *sol, int row)
+{
+	struct isl_vec *ineq = NULL;
+	enum isl_tab_row_sign res = isl_tab_row_unknown;
+	int critical;
+	int strict;
+	int row2;
+
+	if (tab->row_sign[row] != isl_tab_row_unknown)
+		return tab->row_sign[row];
+	if (is_obviously_nonneg(tab, row))
+		return isl_tab_row_pos;
+	for (row2 = tab->n_redundant; row2 < tab->n_row; ++row2) {
+		if (tab->row_sign[row2] == isl_tab_row_unknown)
+			continue;
+		if (identical_parameter_line(tab, row, row2))
+			return tab->row_sign[row2];
+	}
+
+	critical = is_critical(tab, row);
+
+	ineq = get_row_parameter_ineq(tab, row);
+	if (!ineq)
+		goto error;
+
+	strict = is_strict(ineq);
+
+	res = sol->context->op->ineq_sign(sol->context, ineq->el,
+					  critical || strict);
+
+	if (res == isl_tab_row_unknown || res == isl_tab_row_pos) {
+		/* test for negative values */
+		int feasible;
+		isl_seq_neg(ineq->el, ineq->el, ineq->size);
+		isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);
+
+		feasible = sol->context->op->test_ineq(sol->context, ineq->el);
+		if (feasible < 0)
+			goto error;
+		if (!feasible)
+			res = isl_tab_row_pos;
+		else
+			res = (res == isl_tab_row_unknown) ? isl_tab_row_neg
+							   : isl_tab_row_any;
+		if (res == isl_tab_row_neg) {
+			isl_seq_neg(ineq->el, ineq->el, ineq->size);
+			isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);
+		}
+	}
+
+	if (res == isl_tab_row_neg) {
+		/* test for positive values */
+		int feasible;
+		if (!critical && !strict)
+			isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);
+
+		feasible = sol->context->op->test_ineq(sol->context, ineq->el);
+		if (feasible < 0)
+			goto error;
+		if (feasible)
+			res = isl_tab_row_any;
+	}
+
+	isl_vec_free(ineq);
+	return res;
+error:
+	isl_vec_free(ineq);
+	return isl_tab_row_unknown;
+}
+
+static void find_solutions(struct isl_sol *sol, struct isl_tab *tab);
+
+/* Find solutions for values of the parameters that satisfy the given
+ * inequality.
+ *
+ * We currently take a snapshot of the context tableau that is reset
+ * when we return from this function, while we make a copy of the main
+ * tableau, leaving the original main tableau untouched.
+ * These are fairly arbitrary choices.  Making a copy also of the context
+ * tableau would obviate the need to undo any changes made to it later,
+ * while taking a snapshot of the main tableau could reduce memory usage.
+ * If we were to switch to taking a snapshot of the main tableau,
+ * we would have to keep in mind that we need to save the row signs
+ * and that we need to do this before saving the current basis
+ * such that the basis has been restore before we restore the row signs.
+ */
+static void find_in_pos(struct isl_sol *sol, struct isl_tab *tab, isl_int *ineq)
+{
+	void *saved;
+
+	if (!sol->context)
+		goto error;
+	saved = sol->context->op->save(sol->context);
+
+	tab = isl_tab_dup(tab);
+	if (!tab)
+		goto error;
+
+	sol->context->op->add_ineq(sol->context, ineq, 0, 1);
+
+	find_solutions(sol, tab);
+
+	if (!sol->error)
+		sol->context->op->restore(sol->context, saved);
+	else
+		sol->context->op->discard(saved);
+	return;
+error:
+	sol->error = 1;
+}
+
+/* Record the absence of solutions for those values of the parameters
+ * that do not satisfy the given inequality with equality.
+ */
+static void no_sol_in_strict(struct isl_sol *sol,
+	struct isl_tab *tab, struct isl_vec *ineq)
+{
+	int empty;
+	void *saved;
+
+	if (!sol->context || sol->error)
+		goto error;
+	saved = sol->context->op->save(sol->context);
+
+	isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);
+
+	sol->context->op->add_ineq(sol->context, ineq->el, 1, 0);
+	if (!sol->context)
+		goto error;
+
+	empty = tab->empty;
+	tab->empty = 1;
+	sol_add(sol, tab);
+	tab->empty = empty;
+
+	isl_int_add_ui(ineq->el[0], ineq->el[0], 1);
+
+	sol->context->op->restore(sol->context, saved);
+	return;
+error:
+	sol->error = 1;
+}
+
+/* Reset all row variables that are marked to have a sign that may
+ * be both positive and negative to have an unknown sign.
+ */
+static void reset_any_to_unknown(struct isl_tab *tab)
+{
+	int row;
+
+	for (row = tab->n_redundant; row < tab->n_row; ++row) {
+		if (!isl_tab_var_from_row(tab, row)->is_nonneg)
+			continue;
+		if (tab->row_sign[row] == isl_tab_row_any)
+			tab->row_sign[row] = isl_tab_row_unknown;
+	}
+}
+
+/* Compute the lexicographic minimum of the set represented by the main
+ * tableau "tab" within the context "sol->context_tab".
+ * On entry the sample value of the main tableau is lexicographically
+ * less than or equal to this lexicographic minimum.
+ * Pivots are performed until a feasible point is found, which is then
+ * necessarily equal to the minimum, or until the tableau is found to
+ * be infeasible.  Some pivots may need to be performed for only some
+ * feasible values of the context tableau.  If so, the context tableau
+ * is split into a part where the pivot is needed and a part where it is not.
+ *
+ * Whenever we enter the main loop, the main tableau is such that no
+ * "obvious" pivots need to be performed on it, where "obvious" means
+ * that the given row can be seen to be negative without looking at
+ * the context tableau.  In particular, for non-parametric problems,
+ * no pivots need to be performed on the main tableau.
+ * The caller of find_solutions is responsible for making this property
+ * hold prior to the first iteration of the loop, while restore_lexmin
+ * is called before every other iteration.
+ *
+ * Inside the main loop, we first examine the signs of the rows of
+ * the main tableau within the context of the context tableau.
+ * If we find a row that is always non-positive for all values of
+ * the parameters satisfying the context tableau and negative for at
+ * least one value of the parameters, we perform the appropriate pivot
+ * and start over.  An exception is the case where no pivot can be
+ * performed on the row.  In this case, we require that the sign of
+ * the row is negative for all values of the parameters (rather than just
+ * non-positive).  This special case is handled inside row_sign, which
+ * will say that the row can have any sign if it determines that it can
+ * attain both negative and zero values.
+ *
+ * If we can't find a row that always requires a pivot, but we can find
+ * one or more rows that require a pivot for some values of the parameters
+ * (i.e., the row can attain both positive and negative signs), then we split
+ * the context tableau into two parts, one where we force the sign to be
+ * non-negative and one where we force is to be negative.
+ * The non-negative part is handled by a recursive call (through find_in_pos).
+ * Upon returning from this call, we continue with the negative part and
+ * perform the required pivot.
+ *
+ * If no such rows can be found, all rows are non-negative and we have
+ * found a (rational) feasible point.  If we only wanted a rational point
+ * then we are done.
+ * Otherwise, we check if all values of the sample point of the tableau
+ * are integral for the variables.  If so, we have found the minimal
+ * integral point and we are done.
+ * If the sample point is not integral, then we need to make a distinction
+ * based on whether the constant term is non-integral or the coefficients
+ * of the parameters.  Furthermore, in order to decide how to handle
+ * the non-integrality, we also need to know whether the coefficients
+ * of the other columns in the tableau are integral.  This leads
+ * to the following table.  The first two rows do not correspond
+ * to a non-integral sample point and are only mentioned for completeness.
+ *
+ *	constant	parameters	other
+ *
+ *	int		int		int	|
+ *	int		int		rat	| -> no problem
+ *
+ *	rat		int		int	  -> fail
+ *
+ *	rat		int		rat	  -> cut
+ *
+ *	int		rat		rat	|
+ *	rat		rat		rat	| -> parametric cut
+ *
+ *	int		rat		int	|
+ *	rat		rat		int	| -> split context
+ *
+ * If the parametric constant is completely integral, then there is nothing
+ * to be done.  If the constant term is non-integral, but all the other
+ * coefficient are integral, then there is nothing that can be done
+ * and the tableau has no integral solution.
+ * If, on the other hand, one or more of the other columns have rational
+ * coefficients, but the parameter coefficients are all integral, then
+ * we can perform a regular (non-parametric) cut.
+ * Finally, if there is any parameter coefficient that is non-integral,
+ * then we need to involve the context tableau.  There are two cases here.
+ * If at least one other column has a rational coefficient, then we
+ * can perform a parametric cut in the main tableau by adding a new
+ * integer division in the context tableau.
+ * If all other columns have integral coefficients, then we need to
+ * enforce that the rational combination of parameters (c + \sum a_i y_i)/m
+ * is always integral.  We do this by introducing an integer division
+ * q = floor((c + \sum a_i y_i)/m) and stipulating that its argument should
+ * always be integral in the context tableau, i.e., m q = c + \sum a_i y_i.
+ * Since q is expressed in the tableau as
+ *	c + \sum a_i y_i - m q >= 0
+ *	-c - \sum a_i y_i + m q + m - 1 >= 0
+ * it is sufficient to add the inequality
+ *	-c - \sum a_i y_i + m q >= 0
+ * In the part of the context where this inequality does not hold, the
+ * main tableau is marked as being empty.
+ */
+static void find_solutions(struct isl_sol *sol, struct isl_tab *tab)
+{
+	struct isl_context *context;
+	int r;
+
+	if (!tab || sol->error)
+		goto error;
+
+	context = sol->context;
+
+	if (tab->empty)
+		goto done;
+	if (context->op->is_empty(context))
+		goto done;
+
+	for (r = 0; r >= 0 && tab && !tab->empty; r = restore_lexmin(tab)) {
+		int flags;
+		int row;
+		enum isl_tab_row_sign sgn;
+		int split = -1;
+		int n_split = 0;
+
+		for (row = tab->n_redundant; row < tab->n_row; ++row) {
+			if (!isl_tab_var_from_row(tab, row)->is_nonneg)
+				continue;
+			sgn = row_sign(tab, sol, row);
+			if (!sgn)
+				goto error;
+			tab->row_sign[row] = sgn;
+			if (sgn == isl_tab_row_any)
+				n_split++;
+			if (sgn == isl_tab_row_any && split == -1)
+				split = row;
+			if (sgn == isl_tab_row_neg)
+				break;
+		}
+		if (row < tab->n_row)
+			continue;
+		if (split != -1) {
+			struct isl_vec *ineq;
+			if (n_split != 1)
+				split = context->op->best_split(context, tab);
+			if (split < 0)
+				goto error;
+			ineq = get_row_parameter_ineq(tab, split);
+			if (!ineq)
+				goto error;
+			is_strict(ineq);
+			reset_any_to_unknown(tab);
+			tab->row_sign[split] = isl_tab_row_pos;
+			sol_inc_level(sol);
+			find_in_pos(sol, tab, ineq->el);
+			tab->row_sign[split] = isl_tab_row_neg;
+			isl_seq_neg(ineq->el, ineq->el, ineq->size);
+			isl_int_sub_ui(ineq->el[0], ineq->el[0], 1);
+			if (!sol->error)
+				context->op->add_ineq(context, ineq->el, 0, 1);
+			isl_vec_free(ineq);
+			if (sol->error)
+				goto error;
+			continue;
+		}
+		if (tab->rational)
+			break;
+		row = first_non_integer_row(tab, &flags);
+		if (row < 0)
+			break;
+		if (ISL_FL_ISSET(flags, I_PAR)) {
+			if (ISL_FL_ISSET(flags, I_VAR)) {
+				if (isl_tab_mark_empty(tab) < 0)
+					goto error;
+				break;
+			}
+			row = add_cut(tab, row);
+		} else if (ISL_FL_ISSET(flags, I_VAR)) {
+			struct isl_vec *div;
+			struct isl_vec *ineq;
+			int d;
+			div = get_row_split_div(tab, row);
+			if (!div)
+				goto error;
+			d = context->op->get_div(context, tab, div);
+			isl_vec_free(div);
+			if (d < 0)
+				goto error;
+			ineq = ineq_for_div(context->op->peek_basic_set(context), d);
+			if (!ineq)
+				goto error;
+			sol_inc_level(sol);
+			no_sol_in_strict(sol, tab, ineq);
+			isl_seq_neg(ineq->el, ineq->el, ineq->size);
+			context->op->add_ineq(context, ineq->el, 1, 1);
+			isl_vec_free(ineq);
+			if (sol->error || !context->op->is_ok(context))
+				goto error;
+			tab = set_row_cst_to_div(tab, row, d);
+			if (context->op->is_empty(context))
+				break;
+		} else
+			row = add_parametric_cut(tab, row, context);
+		if (row < 0)
+			goto error;
+	}
+	if (r < 0)
+		goto error;
+done:
+	sol_add(sol, tab);
+	isl_tab_free(tab);
+	return;
+error:
+	isl_tab_free(tab);
+	sol->error = 1;
+}
+
+/* Does "sol" contain a pair of partial solutions that could potentially
+ * be merged?
+ *
+ * We currently only check that "sol" is not in an error state
+ * and that there are at least two partial solutions of which the final two
+ * are defined at the same level.
+ */
+static int sol_has_mergeable_solutions(struct isl_sol *sol)
+{
+	if (sol->error)
+		return 0;
+	if (!sol->partial)
+		return 0;
+	if (!sol->partial->next)
+		return 0;
+	return sol->partial->level == sol->partial->next->level;
+}
+
+/* Compute the lexicographic minimum of the set represented by the main
+ * tableau "tab" within the context "sol->context_tab".
+ *
+ * As a preprocessing step, we first transfer all the purely parametric
+ * equalities from the main tableau to the context tableau, i.e.,
+ * parameters that have been pivoted to a row.
+ * These equalities are ignored by the main algorithm, because the
+ * corresponding rows may not be marked as being non-negative.
+ * In parts of the context where the added equality does not hold,
+ * the main tableau is marked as being empty.
+ *
+ * Before we embark on the actual computation, we save a copy
+ * of the context.  When we return, we check if there are any
+ * partial solutions that can potentially be merged.  If so,
+ * we perform a rollback to the initial state of the context.
+ * The merging of partial solutions happens inside calls to
+ * sol_dec_level that are pushed onto the undo stack of the context.
+ * If there are no partial solutions that can potentially be merged
+ * then the rollback is skipped as it would just be wasted effort.
+ */
+static void find_solutions_main(struct isl_sol *sol, struct isl_tab *tab)
+{
+	int row;
+	void *saved;
+
+	if (!tab)
+		goto error;
+
+	sol->level = 0;
+
+	for (row = tab->n_redundant; row < tab->n_row; ++row) {
+		int p;
+		struct isl_vec *eq;
+
+		if (tab->row_var[row] < 0)
+			continue;
+		if (tab->row_var[row] >= tab->n_param &&
+		    tab->row_var[row] < tab->n_var - tab->n_div)
+			continue;
+		if (tab->row_var[row] < tab->n_param)
+			p = tab->row_var[row];
+		else
+			p = tab->row_var[row]
+				+ tab->n_param - (tab->n_var - tab->n_div);
+
+		eq = isl_vec_alloc(tab->mat->ctx, 1+tab->n_param+tab->n_div);
+		if (!eq)
+			goto error;
+		get_row_parameter_line(tab, row, eq->el);
+		isl_int_neg(eq->el[1 + p], tab->mat->row[row][0]);
+		eq = isl_vec_normalize(eq);
+
+		sol_inc_level(sol);
+		no_sol_in_strict(sol, tab, eq);
+
+		isl_seq_neg(eq->el, eq->el, eq->size);
+		sol_inc_level(sol);
+		no_sol_in_strict(sol, tab, eq);
+		isl_seq_neg(eq->el, eq->el, eq->size);
+
+		sol->context->op->add_eq(sol->context, eq->el, 1, 1);
+
+		isl_vec_free(eq);
+
+		if (isl_tab_mark_redundant(tab, row) < 0)
+			goto error;
+
+		if (sol->context->op->is_empty(sol->context))
+			break;
+
+		row = tab->n_redundant - 1;
+	}
+
+	saved = sol->context->op->save(sol->context);
+
+	find_solutions(sol, tab);
+
+	if (sol_has_mergeable_solutions(sol))
+		sol->context->op->restore(sol->context, saved);
+	else
+		sol->context->op->discard(saved);
+
+	sol->level = 0;
+	sol_pop(sol);
+
+	return;
+error:
+	isl_tab_free(tab);
+	sol->error = 1;
+}
+
+/* Check if integer division "div" of "dom" also occurs in "bmap".
+ * If so, return its position within the divs.
+ * If not, return -1.
+ */
+static int find_context_div(struct isl_basic_map *bmap,
+	struct isl_basic_set *dom, unsigned div)
+{
+	int i;
+	unsigned b_dim = isl_space_dim(bmap->dim, isl_dim_all);
+	unsigned d_dim = isl_space_dim(dom->dim, isl_dim_all);
+
+	if (isl_int_is_zero(dom->div[div][0]))
+		return -1;
+	if (isl_seq_first_non_zero(dom->div[div] + 2 + d_dim, dom->n_div) != -1)
+		return -1;
+
+	for (i = 0; i < bmap->n_div; ++i) {
+		if (isl_int_is_zero(bmap->div[i][0]))
+			continue;
+		if (isl_seq_first_non_zero(bmap->div[i] + 2 + d_dim,
+					   (b_dim - d_dim) + bmap->n_div) != -1)
+			continue;
+		if (isl_seq_eq(bmap->div[i], dom->div[div], 2 + d_dim))
+			return i;
+	}
+	return -1;
+}
+
+/* The correspondence between the variables in the main tableau,
+ * the context tableau, and the input map and domain is as follows.
+ * The first n_param and the last n_div variables of the main tableau
+ * form the variables of the context tableau.
+ * In the basic map, these n_param variables correspond to the
+ * parameters and the input dimensions.  In the domain, they correspond
+ * to the parameters and the set dimensions.
+ * The n_div variables correspond to the integer divisions in the domain.
+ * To ensure that everything lines up, we may need to copy some of the
+ * integer divisions of the domain to the map.  These have to be placed
+ * in the same order as those in the context and they have to be placed
+ * after any other integer divisions that the map may have.
+ * This function performs the required reordering.
+ */
+static __isl_give isl_basic_map *align_context_divs(
+	__isl_take isl_basic_map *bmap, __isl_keep isl_basic_set *dom)
+{
+	int i;
+	int common = 0;
+	int other;
+
+	for (i = 0; i < dom->n_div; ++i)
+		if (find_context_div(bmap, dom, i) != -1)
+			common++;
+	other = bmap->n_div - common;
+	if (dom->n_div - common > 0) {
+		bmap = isl_basic_map_extend_space(bmap, isl_space_copy(bmap->dim),
+				dom->n_div - common, 0, 0);
+		if (!bmap)
+			return NULL;
+	}
+	for (i = 0; i < dom->n_div; ++i) {
+		int pos = find_context_div(bmap, dom, i);
+		if (pos < 0) {
+			pos = isl_basic_map_alloc_div(bmap);
+			if (pos < 0)
+				goto error;
+			isl_int_set_si(bmap->div[pos][0], 0);
+		}
+		if (pos != other + i)
+			isl_basic_map_swap_div(bmap, pos, other + i);
+	}
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Base case of isl_tab_basic_map_partial_lexopt, after removing
+ * some obvious symmetries.
+ *
+ * We make sure the divs in the domain are properly ordered,
+ * because they will be added one by one in the given order
+ * during the construction of the solution map.
+ * Furthermore, make sure that the known integer divisions
+ * appear before any unknown integer division because the solution
+ * may depend on the known integer divisions, while anything that
+ * depends on any variable starting from the first unknown integer
+ * division is ignored in sol_pma_add.
+ */
+static struct isl_sol *basic_map_partial_lexopt_base_sol(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max,
+	struct isl_sol *(*init)(__isl_keep isl_basic_map *bmap,
+		    __isl_take isl_basic_set *dom, int track_empty, int max))
+{
+	struct isl_tab *tab;
+	struct isl_sol *sol = NULL;
+	struct isl_context *context;
+
+	if (dom->n_div) {
+		dom = isl_basic_set_sort_divs(dom);
+		bmap = align_context_divs(bmap, dom);
+	}
+	sol = init(bmap, dom, !!empty, max);
+	if (!sol)
+		goto error;
+
+	context = sol->context;
+	if (isl_basic_set_plain_is_empty(context->op->peek_basic_set(context)))
+		/* nothing */;
+	else if (isl_basic_map_plain_is_empty(bmap)) {
+		if (sol->add_empty)
+			sol->add_empty(sol,
+		    isl_basic_set_copy(context->op->peek_basic_set(context)));
+	} else {
+		tab = tab_for_lexmin(bmap,
+				    context->op->peek_basic_set(context), 1, max);
+		tab = context->op->detect_nonnegative_parameters(context, tab);
+		find_solutions_main(sol, tab);
+	}
+	if (sol->error)
+		goto error;
+
+	isl_basic_map_free(bmap);
+	return sol;
+error:
+	sol_free(sol);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Base case of isl_tab_basic_map_partial_lexopt, after removing
+ * some obvious symmetries.
+ *
+ * We call basic_map_partial_lexopt_base_sol and extract the results.
+ */
+static __isl_give isl_map *basic_map_partial_lexopt_base(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max)
+{
+	isl_map *result = NULL;
+	struct isl_sol *sol;
+	struct isl_sol_map *sol_map;
+
+	sol = basic_map_partial_lexopt_base_sol(bmap, dom, empty, max,
+						&sol_map_init);
+	if (!sol)
+		return NULL;
+	sol_map = (struct isl_sol_map *) sol;
+
+	result = isl_map_copy(sol_map->map);
+	if (empty)
+		*empty = isl_set_copy(sol_map->empty);
+	sol_free(&sol_map->sol);
+	return result;
+}
+
+/* Return a count of the number of occurrences of the "n" first
+ * variables in the inequality constraints of "bmap".
+ */
+static __isl_give int *count_occurrences(__isl_keep isl_basic_map *bmap,
+	int n)
+{
+	int i, j;
+	isl_ctx *ctx;
+	int *occurrences;
+
+	if (!bmap)
+		return NULL;
+	ctx = isl_basic_map_get_ctx(bmap);
+	occurrences = isl_calloc_array(ctx, int, n);
+	if (!occurrences)
+		return NULL;
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		for (j = 0; j < n; ++j) {
+			if (!isl_int_is_zero(bmap->ineq[i][1 + j]))
+				occurrences[j]++;
+		}
+	}
+
+	return occurrences;
+}
+
+/* Do all of the "n" variables with non-zero coefficients in "c"
+ * occur in exactly a single constraint.
+ * "occurrences" is an array of length "n" containing the number
+ * of occurrences of each of the variables in the inequality constraints.
+ */
+static int single_occurrence(int n, isl_int *c, int *occurrences)
+{
+	int i;
+
+	for (i = 0; i < n; ++i) {
+		if (isl_int_is_zero(c[i]))
+			continue;
+		if (occurrences[i] != 1)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Do all of the "n" initial variables that occur in inequality constraint
+ * "ineq" of "bmap" only occur in that constraint?
+ */
+static int all_single_occurrence(__isl_keep isl_basic_map *bmap, int ineq,
+	int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; ++i) {
+		if (isl_int_is_zero(bmap->ineq[ineq][1 + i]))
+			continue;
+		for (j = 0; j < bmap->n_ineq; ++j) {
+			if (j == ineq)
+				continue;
+			if (!isl_int_is_zero(bmap->ineq[j][1 + i]))
+				return 0;
+		}
+	}
+
+	return 1;
+}
+
+/* Structure used during detection of parallel constraints.
+ * n_in: number of "input" variables: isl_dim_param + isl_dim_in
+ * n_out: number of "output" variables: isl_dim_out + isl_dim_div
+ * val: the coefficients of the output variables
+ */
+struct isl_constraint_equal_info {
+	unsigned n_in;
+	unsigned n_out;
+	isl_int *val;
+};
+
+/* Check whether the coefficients of the output variables
+ * of the constraint in "entry" are equal to info->val.
+ */
+static int constraint_equal(const void *entry, const void *val)
+{
+	isl_int **row = (isl_int **)entry;
+	const struct isl_constraint_equal_info *info = val;
+
+	return isl_seq_eq((*row) + 1 + info->n_in, info->val, info->n_out);
+}
+
+/* Check whether "bmap" has a pair of constraints that have
+ * the same coefficients for the output variables.
+ * Note that the coefficients of the existentially quantified
+ * variables need to be zero since the existentially quantified
+ * of the result are usually not the same as those of the input.
+ * Furthermore, check that each of the input variables that occur
+ * in those constraints does not occur in any other constraint.
+ * If so, return true and return the row indices of the two constraints
+ * in *first and *second.
+ */
+static isl_bool parallel_constraints(__isl_keep isl_basic_map *bmap,
+	int *first, int *second)
+{
+	int i;
+	isl_ctx *ctx;
+	int *occurrences = NULL;
+	struct isl_hash_table *table = NULL;
+	struct isl_hash_table_entry *entry;
+	struct isl_constraint_equal_info info;
+	unsigned n_out;
+	unsigned n_div;
+
+	ctx = isl_basic_map_get_ctx(bmap);
+	table = isl_hash_table_alloc(ctx, bmap->n_ineq);
+	if (!table)
+		goto error;
+
+	info.n_in = isl_basic_map_dim(bmap, isl_dim_param) +
+		    isl_basic_map_dim(bmap, isl_dim_in);
+	occurrences = count_occurrences(bmap, info.n_in);
+	if (info.n_in && !occurrences)
+		goto error;
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	info.n_out = n_out + n_div;
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		uint32_t hash;
+
+		info.val = bmap->ineq[i] + 1 + info.n_in;
+		if (isl_seq_first_non_zero(info.val, n_out) < 0)
+			continue;
+		if (isl_seq_first_non_zero(info.val + n_out, n_div) >= 0)
+			continue;
+		if (!single_occurrence(info.n_in, bmap->ineq[i] + 1,
+					occurrences))
+			continue;
+		hash = isl_seq_get_hash(info.val, info.n_out);
+		entry = isl_hash_table_find(ctx, table, hash,
+					    constraint_equal, &info, 1);
+		if (!entry)
+			goto error;
+		if (entry->data)
+			break;
+		entry->data = &bmap->ineq[i];
+	}
+
+	if (i < bmap->n_ineq) {
+		*first = ((isl_int **)entry->data) - bmap->ineq; 
+		*second = i;
+	}
+
+	isl_hash_table_free(ctx, table);
+	free(occurrences);
+
+	return i < bmap->n_ineq;
+error:
+	isl_hash_table_free(ctx, table);
+	free(occurrences);
+	return isl_bool_error;
+}
+
+/* Given a set of upper bounds in "var", add constraints to "bset"
+ * that make the i-th bound smallest.
+ *
+ * In particular, if there are n bounds b_i, then add the constraints
+ *
+ *	b_i <= b_j	for j > i
+ *	b_i <  b_j	for j < i
+ */
+static __isl_give isl_basic_set *select_minimum(__isl_take isl_basic_set *bset,
+	__isl_keep isl_mat *var, int i)
+{
+	isl_ctx *ctx;
+	int j, k;
+
+	ctx = isl_mat_get_ctx(var);
+
+	for (j = 0; j < var->n_row; ++j) {
+		if (j == i)
+			continue;
+		k = isl_basic_set_alloc_inequality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_combine(bset->ineq[k], ctx->one, var->row[j],
+				ctx->negone, var->row[i], var->n_col);
+		isl_int_set_si(bset->ineq[k][var->n_col], 0);
+		if (j < i)
+			isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1);
+	}
+
+	bset = isl_basic_set_finalize(bset);
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* Given a set of upper bounds on the last "input" variable m,
+ * construct a set that assigns the minimal upper bound to m, i.e.,
+ * construct a set that divides the space into cells where one
+ * of the upper bounds is smaller than all the others and assign
+ * this upper bound to m.
+ *
+ * In particular, if there are n bounds b_i, then the result
+ * consists of n basic sets, each one of the form
+ *
+ *	m = b_i
+ *	b_i <= b_j	for j > i
+ *	b_i <  b_j	for j < i
+ */
+static __isl_give isl_set *set_minimum(__isl_take isl_space *dim,
+	__isl_take isl_mat *var)
+{
+	int i, k;
+	isl_basic_set *bset = NULL;
+	isl_set *set = NULL;
+
+	if (!dim || !var)
+		goto error;
+
+	set = isl_set_alloc_space(isl_space_copy(dim),
+				var->n_row, ISL_SET_DISJOINT);
+
+	for (i = 0; i < var->n_row; ++i) {
+		bset = isl_basic_set_alloc_space(isl_space_copy(dim), 0,
+					       1, var->n_row - 1);
+		k = isl_basic_set_alloc_equality(bset);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bset->eq[k], var->row[i], var->n_col);
+		isl_int_set_si(bset->eq[k][var->n_col], -1);
+		bset = select_minimum(bset, var, i);
+		set = isl_set_add_basic_set(set, bset);
+	}
+
+	isl_space_free(dim);
+	isl_mat_free(var);
+	return set;
+error:
+	isl_basic_set_free(bset);
+	isl_set_free(set);
+	isl_space_free(dim);
+	isl_mat_free(var);
+	return NULL;
+}
+
+/* Given that the last input variable of "bmap" represents the minimum
+ * of the bounds in "cst", check whether we need to split the domain
+ * based on which bound attains the minimum.
+ *
+ * A split is needed when the minimum appears in an integer division
+ * or in an equality.  Otherwise, it is only needed if it appears in
+ * an upper bound that is different from the upper bounds on which it
+ * is defined.
+ */
+static isl_bool need_split_basic_map(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_mat *cst)
+{
+	int i, j;
+	unsigned total;
+	unsigned pos;
+
+	pos = cst->n_col - 1;
+	total = isl_basic_map_dim(bmap, isl_dim_all);
+
+	for (i = 0; i < bmap->n_div; ++i)
+		if (!isl_int_is_zero(bmap->div[i][2 + pos]))
+			return isl_bool_true;
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		if (!isl_int_is_zero(bmap->eq[i][1 + pos]))
+			return isl_bool_true;
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		if (isl_int_is_nonneg(bmap->ineq[i][1 + pos]))
+			continue;
+		if (!isl_int_is_negone(bmap->ineq[i][1 + pos]))
+			return isl_bool_true;
+		if (isl_seq_first_non_zero(bmap->ineq[i] + 1 + pos + 1,
+					   total - pos - 1) >= 0)
+			return isl_bool_true;
+
+		for (j = 0; j < cst->n_row; ++j)
+			if (isl_seq_eq(bmap->ineq[i], cst->row[j], cst->n_col))
+				break;
+		if (j >= cst->n_row)
+			return isl_bool_true;
+	}
+
+	return isl_bool_false;
+}
+
+/* Given that the last set variable of "bset" represents the minimum
+ * of the bounds in "cst", check whether we need to split the domain
+ * based on which bound attains the minimum.
+ *
+ * We simply call need_split_basic_map here.  This is safe because
+ * the position of the minimum is computed from "cst" and not
+ * from "bmap".
+ */
+static isl_bool need_split_basic_set(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_mat *cst)
+{
+	return need_split_basic_map(bset_to_bmap(bset), cst);
+}
+
+/* Given that the last set variable of "set" represents the minimum
+ * of the bounds in "cst", check whether we need to split the domain
+ * based on which bound attains the minimum.
+ */
+static isl_bool need_split_set(__isl_keep isl_set *set, __isl_keep isl_mat *cst)
+{
+	int i;
+
+	for (i = 0; i < set->n; ++i) {
+		isl_bool split;
+
+		split = need_split_basic_set(set->p[i], cst);
+		if (split < 0 || split)
+			return split;
+	}
+
+	return isl_bool_false;
+}
+
+/* Given a set of which the last set variable is the minimum
+ * of the bounds in "cst", split each basic set in the set
+ * in pieces where one of the bounds is (strictly) smaller than the others.
+ * This subdivision is given in "min_expr".
+ * The variable is subsequently projected out.
+ *
+ * We only do the split when it is needed.
+ * For example if the last input variable m = min(a,b) and the only
+ * constraints in the given basic set are lower bounds on m,
+ * i.e., l <= m = min(a,b), then we can simply project out m
+ * to obtain l <= a and l <= b, without having to split on whether
+ * m is equal to a or b.
+ */
+static __isl_give isl_set *split(__isl_take isl_set *empty,
+	__isl_take isl_set *min_expr, __isl_take isl_mat *cst)
+{
+	int n_in;
+	int i;
+	isl_space *dim;
+	isl_set *res;
+
+	if (!empty || !min_expr || !cst)
+		goto error;
+
+	n_in = isl_set_dim(empty, isl_dim_set);
+	dim = isl_set_get_space(empty);
+	dim = isl_space_drop_dims(dim, isl_dim_set, n_in - 1, 1);
+	res = isl_set_empty(dim);
+
+	for (i = 0; i < empty->n; ++i) {
+		isl_bool split;
+		isl_set *set;
+
+		set = isl_set_from_basic_set(isl_basic_set_copy(empty->p[i]));
+		split = need_split_basic_set(empty->p[i], cst);
+		if (split < 0)
+			set = isl_set_free(set);
+		else if (split)
+			set = isl_set_intersect(set, isl_set_copy(min_expr));
+		set = isl_set_remove_dims(set, isl_dim_set, n_in - 1, 1);
+
+		res = isl_set_union_disjoint(res, set);
+	}
+
+	isl_set_free(empty);
+	isl_set_free(min_expr);
+	isl_mat_free(cst);
+	return res;
+error:
+	isl_set_free(empty);
+	isl_set_free(min_expr);
+	isl_mat_free(cst);
+	return NULL;
+}
+
+/* Given a map of which the last input variable is the minimum
+ * of the bounds in "cst", split each basic set in the set
+ * in pieces where one of the bounds is (strictly) smaller than the others.
+ * This subdivision is given in "min_expr".
+ * The variable is subsequently projected out.
+ *
+ * The implementation is essentially the same as that of "split".
+ */
+static __isl_give isl_map *split_domain(__isl_take isl_map *opt,
+	__isl_take isl_set *min_expr, __isl_take isl_mat *cst)
+{
+	int n_in;
+	int i;
+	isl_space *dim;
+	isl_map *res;
+
+	if (!opt || !min_expr || !cst)
+		goto error;
+
+	n_in = isl_map_dim(opt, isl_dim_in);
+	dim = isl_map_get_space(opt);
+	dim = isl_space_drop_dims(dim, isl_dim_in, n_in - 1, 1);
+	res = isl_map_empty(dim);
+
+	for (i = 0; i < opt->n; ++i) {
+		isl_map *map;
+		isl_bool split;
+
+		map = isl_map_from_basic_map(isl_basic_map_copy(opt->p[i]));
+		split = need_split_basic_map(opt->p[i], cst);
+		if (split < 0)
+			map = isl_map_free(map);
+		else if (split)
+			map = isl_map_intersect_domain(map,
+						       isl_set_copy(min_expr));
+		map = isl_map_remove_dims(map, isl_dim_in, n_in - 1, 1);
+
+		res = isl_map_union_disjoint(res, map);
+	}
+
+	isl_map_free(opt);
+	isl_set_free(min_expr);
+	isl_mat_free(cst);
+	return res;
+error:
+	isl_map_free(opt);
+	isl_set_free(min_expr);
+	isl_mat_free(cst);
+	return NULL;
+}
+
+static __isl_give isl_map *basic_map_partial_lexopt(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max);
+
+/* This function is called from basic_map_partial_lexopt_symm.
+ * The last variable of "bmap" and "dom" corresponds to the minimum
+ * of the bounds in "cst".  "map_space" is the space of the original
+ * input relation (of basic_map_partial_lexopt_symm) and "set_space"
+ * is the space of the original domain.
+ *
+ * We recursively call basic_map_partial_lexopt and then plug in
+ * the definition of the minimum in the result.
+ */
+static __isl_give isl_map *basic_map_partial_lexopt_symm_core(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max, __isl_take isl_mat *cst,
+	__isl_take isl_space *map_space, __isl_take isl_space *set_space)
+{
+	isl_map *opt;
+	isl_set *min_expr;
+
+	min_expr = set_minimum(isl_basic_set_get_space(dom), isl_mat_copy(cst));
+
+	opt = basic_map_partial_lexopt(bmap, dom, empty, max);
+
+	if (empty) {
+		*empty = split(*empty,
+			       isl_set_copy(min_expr), isl_mat_copy(cst));
+		*empty = isl_set_reset_space(*empty, set_space);
+	}
+
+	opt = split_domain(opt, min_expr, cst);
+	opt = isl_map_reset_space(opt, map_space);
+
+	return opt;
+}
+
+/* Extract a domain from "bmap" for the purpose of computing
+ * a lexicographic optimum.
+ *
+ * This function is only called when the caller wants to compute a full
+ * lexicographic optimum, i.e., without specifying a domain.  In this case,
+ * the caller is not interested in the part of the domain space where
+ * there is no solution and the domain can be initialized to those constraints
+ * of "bmap" that only involve the parameters and the input dimensions.
+ * This relieves the parametric programming engine from detecting those
+ * inequalities and transferring them to the context.  More importantly,
+ * it ensures that those inequalities are transferred first and not
+ * intermixed with inequalities that actually split the domain.
+ *
+ * If the caller does not require the absence of existentially quantified
+ * variables in the result (i.e., if ISL_OPT_QE is not set in "flags"),
+ * then the actual domain of "bmap" can be used.  This ensures that
+ * the domain does not need to be split at all just to separate out
+ * pieces of the domain that do not have a solution from piece that do.
+ * This domain cannot be used in general because it may involve
+ * (unknown) existentially quantified variables which will then also
+ * appear in the solution.
+ */
+static __isl_give isl_basic_set *extract_domain(__isl_keep isl_basic_map *bmap,
+	unsigned flags)
+{
+	int n_div;
+	int n_out;
+
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	bmap = isl_basic_map_copy(bmap);
+	if (ISL_FL_ISSET(flags, ISL_OPT_QE)) {
+		bmap = isl_basic_map_drop_constraints_involving_dims(bmap,
+							isl_dim_div, 0, n_div);
+		bmap = isl_basic_map_drop_constraints_involving_dims(bmap,
+							isl_dim_out, 0, n_out);
+	}
+	return isl_basic_map_domain(bmap);
+}
+
+#undef TYPE
+#define TYPE	isl_map
+#undef SUFFIX
+#define SUFFIX
+#include "isl_tab_lexopt_templ.c"
+
+struct isl_sol_for {
+	struct isl_sol	sol;
+	isl_stat	(*fn)(__isl_take isl_basic_set *dom,
+				__isl_take isl_aff_list *list, void *user);
+	void		*user;
+};
+
+static void sol_for_free(struct isl_sol *sol)
+{
+}
+
+/* Add the solution identified by the tableau and the context tableau.
+ * In particular, "dom" represents the context and "ma" expresses
+ * the solution on that context.
+ *
+ * See documentation of sol_add for more details.
+ *
+ * Instead of constructing a basic map, this function calls a user
+ * defined function with the current context as a basic set and
+ * a list of affine expressions representing the relation between
+ * the input and output.  The space over which the affine expressions
+ * are defined is the same as that of the domain.  The number of
+ * affine expressions in the list is equal to the number of output variables.
+ */
+static void sol_for_add(struct isl_sol_for *sol,
+	__isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_aff *aff;
+	isl_aff_list *list;
+
+	if (sol->sol.error || !dom || !ma)
+		goto error;
+
+	ctx = isl_basic_set_get_ctx(dom);
+	n = isl_multi_aff_dim(ma, isl_dim_out);
+	list = isl_aff_list_alloc(ctx, n);
+	for (i = 0; i < n; ++i) {
+		aff = isl_multi_aff_get_aff(ma, i);
+		list = isl_aff_list_add(list, aff);
+	}
+
+	dom = isl_basic_set_finalize(dom);
+
+	if (sol->fn(isl_basic_set_copy(dom), list, sol->user) < 0)
+		goto error;
+
+	isl_basic_set_free(dom);
+	isl_multi_aff_free(ma);
+	return;
+error:
+	isl_basic_set_free(dom);
+	isl_multi_aff_free(ma);
+	sol->sol.error = 1;
+}
+
+static void sol_for_add_wrap(struct isl_sol *sol,
+	__isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma)
+{
+	sol_for_add((struct isl_sol_for *)sol, dom, ma);
+}
+
+static struct isl_sol_for *sol_for_init(__isl_keep isl_basic_map *bmap, int max,
+	isl_stat (*fn)(__isl_take isl_basic_set *dom,
+		__isl_take isl_aff_list *list, void *user),
+	void *user)
+{
+	struct isl_sol_for *sol_for = NULL;
+	isl_space *dom_dim;
+	struct isl_basic_set *dom = NULL;
+
+	sol_for = isl_calloc_type(bmap->ctx, struct isl_sol_for);
+	if (!sol_for)
+		goto error;
+
+	dom_dim = isl_space_domain(isl_space_copy(bmap->dim));
+	dom = isl_basic_set_universe(dom_dim);
+
+	sol_for->sol.free = &sol_for_free;
+	if (sol_init(&sol_for->sol, bmap, dom, max) < 0)
+		goto error;
+	sol_for->fn = fn;
+	sol_for->user = user;
+	sol_for->sol.add = &sol_for_add_wrap;
+	sol_for->sol.add_empty = NULL;
+
+	isl_basic_set_free(dom);
+	return sol_for;
+error:
+	isl_basic_set_free(dom);
+	sol_free(&sol_for->sol);
+	return NULL;
+}
+
+static void sol_for_find_solutions(struct isl_sol_for *sol_for,
+	struct isl_tab *tab)
+{
+	find_solutions_main(&sol_for->sol, tab);
+}
+
+isl_stat isl_basic_map_foreach_lexopt(__isl_keep isl_basic_map *bmap, int max,
+	isl_stat (*fn)(__isl_take isl_basic_set *dom,
+		__isl_take isl_aff_list *list, void *user),
+	void *user)
+{
+	struct isl_sol_for *sol_for = NULL;
+
+	bmap = isl_basic_map_copy(bmap);
+	bmap = isl_basic_map_detect_equalities(bmap);
+	if (!bmap)
+		return isl_stat_error;
+
+	sol_for = sol_for_init(bmap, max, fn, user);
+	if (!sol_for)
+		goto error;
+
+	if (isl_basic_map_plain_is_empty(bmap))
+		/* nothing */;
+	else {
+		struct isl_tab *tab;
+		struct isl_context *context = sol_for->sol.context;
+		tab = tab_for_lexmin(bmap,
+				context->op->peek_basic_set(context), 1, max);
+		tab = context->op->detect_nonnegative_parameters(context, tab);
+		sol_for_find_solutions(sol_for, tab);
+		if (sol_for->sol.error)
+			goto error;
+	}
+
+	sol_free(&sol_for->sol);
+	isl_basic_map_free(bmap);
+	return isl_stat_ok;
+error:
+	sol_free(&sol_for->sol);
+	isl_basic_map_free(bmap);
+	return isl_stat_error;
+}
+
+/* Extract the subsequence of the sample value of "tab"
+ * starting at "pos" and of length "len".
+ */
+static __isl_give isl_vec *extract_sample_sequence(struct isl_tab *tab,
+	int pos, int len)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_vec *v;
+
+	ctx = isl_tab_get_ctx(tab);
+	v = isl_vec_alloc(ctx, len);
+	if (!v)
+		return NULL;
+	for (i = 0; i < len; ++i) {
+		if (!tab->var[pos + i].is_row) {
+			isl_int_set_si(v->el[i], 0);
+		} else {
+			int row;
+
+			row = tab->var[pos + i].index;
+			isl_int_set(v->el[i], tab->mat->row[row][1]);
+		}
+	}
+
+	return v;
+}
+
+/* Check if the sequence of variables starting at "pos"
+ * represents a trivial solution according to "trivial".
+ * That is, is the result of applying "trivial" to this sequence
+ * equal to the zero vector?
+ */
+static isl_bool region_is_trivial(struct isl_tab *tab, int pos,
+	__isl_keep isl_mat *trivial)
+{
+	int n, len;
+	isl_vec *v;
+	isl_bool is_trivial;
+
+	if (!trivial)
+		return isl_bool_error;
+
+	n = isl_mat_rows(trivial);
+	if (n == 0)
+		return isl_bool_false;
+
+	len = isl_mat_cols(trivial);
+	v = extract_sample_sequence(tab, pos, len);
+	v = isl_mat_vec_product(isl_mat_copy(trivial), v);
+	is_trivial = isl_vec_is_zero(v);
+	isl_vec_free(v);
+
+	return is_trivial;
+}
+
+/* Return the index of the first trivial region, "n_region" if all regions
+ * are non-trivial or -1 in case of error.
+ */
+static int first_trivial_region(struct isl_tab *tab,
+	int n_region, struct isl_trivial_region *region)
+{
+	int i;
+
+	for (i = 0; i < n_region; ++i) {
+		isl_bool trivial;
+		trivial = region_is_trivial(tab, region[i].pos,
+					region[i].trivial);
+		if (trivial < 0)
+			return -1;
+		if (trivial)
+			return i;
+	}
+
+	return n_region;
+}
+
+/* Check if the solution is optimal, i.e., whether the first
+ * n_op entries are zero.
+ */
+static int is_optimal(__isl_keep isl_vec *sol, int n_op)
+{
+	int i;
+
+	for (i = 0; i < n_op; ++i)
+		if (!isl_int_is_zero(sol->el[1 + i]))
+			return 0;
+	return 1;
+}
+
+/* Add constraints to "tab" that ensure that any solution is significantly
+ * better than that represented by "sol".  That is, find the first
+ * relevant (within first n_op) non-zero coefficient and force it (along
+ * with all previous coefficients) to be zero.
+ * If the solution is already optimal (all relevant coefficients are zero),
+ * then just mark the table as empty.
+ * "n_zero" is the number of coefficients that have been forced zero
+ * by previous calls to this function at the same level.
+ * Return the updated number of forced zero coefficients or -1 on error.
+ *
+ * This function assumes that at least 2 * (n_op - n_zero) more rows and
+ * at least 2 * (n_op - n_zero) more elements in the constraint array
+ * are available in the tableau.
+ */
+static int force_better_solution(struct isl_tab *tab,
+	__isl_keep isl_vec *sol, int n_op, int n_zero)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_vec *v = NULL;
+
+	if (!sol)
+		return -1;
+
+	for (i = n_zero; i < n_op; ++i)
+		if (!isl_int_is_zero(sol->el[1 + i]))
+			break;
+
+	if (i == n_op) {
+		if (isl_tab_mark_empty(tab) < 0)
+			return -1;
+		return n_op;
+	}
+
+	ctx = isl_vec_get_ctx(sol);
+	v = isl_vec_alloc(ctx, 1 + tab->n_var);
+	if (!v)
+		return -1;
+
+	n = i + 1;
+	for (; i >= n_zero; --i) {
+		v = isl_vec_clr(v);
+		isl_int_set_si(v->el[1 + i], -1);
+		if (add_lexmin_eq(tab, v->el) < 0)
+			goto error;
+	}
+
+	isl_vec_free(v);
+	return n;
+error:
+	isl_vec_free(v);
+	return -1;
+}
+
+/* Global internal data for isl_tab_basic_set_non_trivial_lexmin.
+ *
+ * "v" is a pre-allocated vector that can be used for adding
+ * constraints to the tableau.
+ */
+struct isl_trivial_global {
+	isl_vec *v;
+};
+
+/* Fix triviality direction "dir" of the given region to zero.
+ *
+ * This function assumes that at least two more rows and at least
+ * two more elements in the constraint array are available in the tableau.
+ */
+static isl_stat fix_zero(struct isl_tab *tab, struct isl_trivial_region *region,
+	int dir, struct isl_trivial_global *data)
+{
+	int len;
+
+	data->v = isl_vec_clr(data->v);
+	if (!data->v)
+		return isl_stat_error;
+	len = isl_mat_cols(region->trivial);
+	isl_seq_cpy(data->v->el + 1 + region->pos, region->trivial->row[dir],
+		    len);
+	if (add_lexmin_eq(tab, data->v->el) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* This function selects case "side" for non-triviality region "region",
+ * assuming all the equality constraints have been imposed already.
+ * In particular, the triviality direction side/2 is made positive
+ * if side is even and made negative if side is odd.
+ *
+ * This function assumes that at least one more row and at least
+ * one more element in the constraint array are available in the tableau.
+ */
+static struct isl_tab *pos_neg(struct isl_tab *tab,
+	struct isl_trivial_region *region,
+	int side, struct isl_trivial_global *data)
+{
+	int len;
+
+	data->v = isl_vec_clr(data->v);
+	if (!data->v)
+		goto error;
+	isl_int_set_si(data->v->el[0], -1);
+	len = isl_mat_cols(region->trivial);
+	if (side % 2 == 0)
+		isl_seq_cpy(data->v->el + 1 + region->pos,
+			    region->trivial->row[side / 2], len);
+	else
+		isl_seq_neg(data->v->el + 1 + region->pos,
+			    region->trivial->row[side / 2], len);
+	return add_lexmin_ineq(tab, data->v->el);
+error:
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Local data at each level of the backtracking procedure of
+ * isl_tab_basic_set_non_trivial_lexmin.
+ *
+ * "update" is set if a solution has been found in the current case
+ * of this level, such that a better solution needs to be enforced
+ * in the next case.
+ * "n_zero" is the number of initial coordinates that have already
+ * been forced to be zero at this level.
+ * "region" is the non-triviality region considered at this level.
+ * "side" is the index of the current case at this level.
+ * "n" is the number of triviality directions.
+ */
+struct isl_trivial {
+	int update;
+	int n_zero;
+	int region;
+	int side;
+	int n;
+	struct isl_tab_undo *snap;
+};
+
+/* Return the lexicographically smallest non-trivial solution of the
+ * given ILP problem.
+ *
+ * All variables are assumed to be non-negative.
+ *
+ * n_op is the number of initial coordinates to optimize.
+ * That is, once a solution has been found, we will only continue looking
+ * for solutions that result in significantly better values for those
+ * initial coordinates.  That is, we only continue looking for solutions
+ * that increase the number of initial zeros in this sequence.
+ *
+ * A solution is non-trivial, if it is non-trivial on each of the
+ * specified regions.  Each region represents a sequence of
+ * triviality directions on a sequence of variables that starts
+ * at a given position.  A solution is non-trivial on such a region if
+ * at least one of the triviality directions is non-zero
+ * on that sequence of variables.
+ *
+ * Whenever a conflict is encountered, all constraints involved are
+ * reported to the caller through a call to "conflict".
+ *
+ * We perform a simple branch-and-bound backtracking search.
+ * Each level in the search represents an initially trivial region
+ * that is forced to be non-trivial.
+ * At each level we consider 2 * n cases, where n
+ * is the number of triviality directions.
+ * In terms of those n directions v_i, we consider the cases
+ *	v_0 >= 1
+ *	v_0 <= -1
+ *	v_0 = 0 and v_1 >= 1
+ *	v_0 = 0 and v_1 <= -1
+ *	v_0 = 0 and v_1 = 0 and v_2 >= 1
+ *	v_0 = 0 and v_1 = 0 and v_2 <= -1
+ *	...
+ * in this order.
+ */
+__isl_give isl_vec *isl_tab_basic_set_non_trivial_lexmin(
+	__isl_take isl_basic_set *bset, int n_op, int n_region,
+	struct isl_trivial_region *region,
+	int (*conflict)(int con, void *user), void *user)
+{
+	struct isl_trivial_global data = { 0 };
+	int i;
+	int r;
+	isl_ctx *ctx;
+	isl_vec *sol = NULL;
+	struct isl_tab *tab;
+	struct isl_trivial *triv = NULL;
+	int level, init;
+
+	if (!bset)
+		return NULL;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	sol = isl_vec_alloc(ctx, 0);
+
+	tab = tab_for_lexmin(bset, NULL, 0, 0);
+	if (!tab)
+		goto error;
+	tab->conflict = conflict;
+	tab->conflict_user = user;
+
+	data.v = isl_vec_alloc(ctx, 1 + tab->n_var);
+	triv = isl_calloc_array(ctx, struct isl_trivial, n_region);
+	if (!data.v || (n_region && !triv))
+		goto error;
+
+	level = 0;
+	init = 1;
+
+	while (level >= 0) {
+		int side, base;
+
+		if (init) {
+			tab = cut_to_integer_lexmin(tab, CUT_ONE);
+			if (!tab)
+				goto error;
+			if (tab->empty)
+				goto backtrack;
+			r = first_trivial_region(tab, n_region, region);
+			if (r < 0)
+				goto error;
+			if (r == n_region) {
+				for (i = 0; i < level; ++i)
+					triv[i].update = 1;
+				isl_vec_free(sol);
+				sol = isl_tab_get_sample_value(tab);
+				if (!sol)
+					goto error;
+				if (is_optimal(sol, n_op))
+					break;
+				goto backtrack;
+			}
+			if (level >= n_region)
+				isl_die(ctx, isl_error_internal,
+					"nesting level too deep", goto error);
+			triv[level].n = isl_mat_rows(region[r].trivial);
+			if (isl_tab_extend_cons(tab,
+					    2 * triv[level].n + 2 * n_op) < 0)
+				goto error;
+			triv[level].region = r;
+			triv[level].side = 0;
+			triv[level].update = 0;
+			triv[level].n_zero = 0;
+		}
+
+		r = triv[level].region;
+		side = triv[level].side;
+		base = 2 * (side/2);
+
+		if (side >= 2 * triv[level].n) {
+backtrack:
+			level--;
+			init = 0;
+			if (level >= 0)
+				if (isl_tab_rollback(tab, triv[level].snap) < 0)
+					goto error;
+			continue;
+		}
+
+		if (triv[level].update) {
+			triv[level].n_zero = force_better_solution(tab, sol,
+						    n_op, triv[level].n_zero);
+			if (triv[level].n_zero < 0)
+				goto error;
+			triv[level].update = 0;
+		}
+
+		if (side == base && base >= 2 &&
+		    fix_zero(tab, &region[r], base / 2 - 1, &data) < 0)
+			goto error;
+
+		triv[level].snap = isl_tab_snap(tab);
+		if (isl_tab_push_basis(tab) < 0)
+			goto error;
+
+		tab = pos_neg(tab, &region[r], side, &data);
+		if (!tab)
+			goto error;
+
+		triv[level].side++;
+		level++;
+		init = 1;
+	}
+
+	free(triv);
+	isl_vec_free(data.v);
+	isl_tab_free(tab);
+	isl_basic_set_free(bset);
+
+	return sol;
+error:
+	free(triv);
+	isl_vec_free(data.v);
+	isl_tab_free(tab);
+	isl_basic_set_free(bset);
+	isl_vec_free(sol);
+	return NULL;
+}
+
+/* Wrapper for a tableau that is used for computing
+ * the lexicographically smallest rational point of a non-negative set.
+ * This point is represented by the sample value of "tab",
+ * unless "tab" is empty.
+ */
+struct isl_tab_lexmin {
+	isl_ctx *ctx;
+	struct isl_tab *tab;
+};
+
+/* Free "tl" and return NULL.
+ */
+__isl_null isl_tab_lexmin *isl_tab_lexmin_free(__isl_take isl_tab_lexmin *tl)
+{
+	if (!tl)
+		return NULL;
+	isl_ctx_deref(tl->ctx);
+	isl_tab_free(tl->tab);
+	free(tl);
+
+	return NULL;
+}
+
+/* Construct an isl_tab_lexmin for computing
+ * the lexicographically smallest rational point in "bset",
+ * assuming that all variables are non-negative.
+ */
+__isl_give isl_tab_lexmin *isl_tab_lexmin_from_basic_set(
+	__isl_take isl_basic_set *bset)
+{
+	isl_ctx *ctx;
+	isl_tab_lexmin *tl;
+
+	if (!bset)
+		return NULL;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	tl = isl_calloc_type(ctx, struct isl_tab_lexmin);
+	if (!tl)
+		goto error;
+	tl->ctx = ctx;
+	isl_ctx_ref(ctx);
+	tl->tab = tab_for_lexmin(bset, NULL, 0, 0);
+	isl_basic_set_free(bset);
+	if (!tl->tab)
+		return isl_tab_lexmin_free(tl);
+	return tl;
+error:
+	isl_basic_set_free(bset);
+	isl_tab_lexmin_free(tl);
+	return NULL;
+}
+
+/* Return the dimension of the set represented by "tl".
+ */
+int isl_tab_lexmin_dim(__isl_keep isl_tab_lexmin *tl)
+{
+	return tl ? tl->tab->n_var : -1;
+}
+
+/* Add the equality with coefficients "eq" to "tl", updating the optimal
+ * solution if needed.
+ * The equality is added as two opposite inequality constraints.
+ */
+__isl_give isl_tab_lexmin *isl_tab_lexmin_add_eq(__isl_take isl_tab_lexmin *tl,
+	isl_int *eq)
+{
+	unsigned n_var;
+
+	if (!tl || !eq)
+		return isl_tab_lexmin_free(tl);
+
+	if (isl_tab_extend_cons(tl->tab, 2) < 0)
+		return isl_tab_lexmin_free(tl);
+	n_var = tl->tab->n_var;
+	isl_seq_neg(eq, eq, 1 + n_var);
+	tl->tab = add_lexmin_ineq(tl->tab, eq);
+	isl_seq_neg(eq, eq, 1 + n_var);
+	tl->tab = add_lexmin_ineq(tl->tab, eq);
+
+	if (!tl->tab)
+		return isl_tab_lexmin_free(tl);
+
+	return tl;
+}
+
+/* Add cuts to "tl" until the sample value reaches an integer value or
+ * until the result becomes empty.
+ */
+__isl_give isl_tab_lexmin *isl_tab_lexmin_cut_to_integer(
+	__isl_take isl_tab_lexmin *tl)
+{
+	if (!tl)
+		return NULL;
+	tl->tab = cut_to_integer_lexmin(tl->tab, CUT_ONE);
+	if (!tl->tab)
+		return isl_tab_lexmin_free(tl);
+	return tl;
+}
+
+/* Return the lexicographically smallest rational point in the basic set
+ * from which "tl" was constructed.
+ * If the original input was empty, then return a zero-length vector.
+ */
+__isl_give isl_vec *isl_tab_lexmin_get_solution(__isl_keep isl_tab_lexmin *tl)
+{
+	if (!tl)
+		return NULL;
+	if (tl->tab->empty)
+		return isl_vec_alloc(tl->ctx, 0);
+	else
+		return isl_tab_get_sample_value(tl->tab);
+}
+
+struct isl_sol_pma {
+	struct isl_sol	sol;
+	isl_pw_multi_aff *pma;
+	isl_set *empty;
+};
+
+static void sol_pma_free(struct isl_sol *sol)
+{
+	struct isl_sol_pma *sol_pma = (struct isl_sol_pma *) sol;
+	isl_pw_multi_aff_free(sol_pma->pma);
+	isl_set_free(sol_pma->empty);
+}
+
+/* This function is called for parts of the context where there is
+ * no solution, with "bset" corresponding to the context tableau.
+ * Simply add the basic set to the set "empty".
+ */
+static void sol_pma_add_empty(struct isl_sol_pma *sol,
+	__isl_take isl_basic_set *bset)
+{
+	if (!bset || !sol->empty)
+		goto error;
+
+	sol->empty = isl_set_grow(sol->empty, 1);
+	bset = isl_basic_set_simplify(bset);
+	bset = isl_basic_set_finalize(bset);
+	sol->empty = isl_set_add_basic_set(sol->empty, bset);
+	if (!sol->empty)
+		sol->sol.error = 1;
+	return;
+error:
+	isl_basic_set_free(bset);
+	sol->sol.error = 1;
+}
+
+/* Given a basic set "dom" that represents the context and a tuple of
+ * affine expressions "maff" defined over this domain, construct
+ * an isl_pw_multi_aff with a single cell corresponding to "dom" and
+ * the affine expressions in "maff".
+ */
+static void sol_pma_add(struct isl_sol_pma *sol,
+	__isl_take isl_basic_set *dom, __isl_take isl_multi_aff *maff)
+{
+	isl_pw_multi_aff *pma;
+
+	dom = isl_basic_set_simplify(dom);
+	dom = isl_basic_set_finalize(dom);
+	pma = isl_pw_multi_aff_alloc(isl_set_from_basic_set(dom), maff);
+	sol->pma = isl_pw_multi_aff_add_disjoint(sol->pma, pma);
+	if (!sol->pma)
+		sol->sol.error = 1;
+}
+
+static void sol_pma_add_empty_wrap(struct isl_sol *sol,
+	__isl_take isl_basic_set *bset)
+{
+	sol_pma_add_empty((struct isl_sol_pma *)sol, bset);
+}
+
+static void sol_pma_add_wrap(struct isl_sol *sol,
+	__isl_take isl_basic_set *dom, __isl_take isl_multi_aff *ma)
+{
+	sol_pma_add((struct isl_sol_pma *)sol, dom, ma);
+}
+
+/* Construct an isl_sol_pma structure for accumulating the solution.
+ * If track_empty is set, then we also keep track of the parts
+ * of the context where there is no solution.
+ * If max is set, then we are solving a maximization, rather than
+ * a minimization problem, which means that the variables in the
+ * tableau have value "M - x" rather than "M + x".
+ */
+static struct isl_sol *sol_pma_init(__isl_keep isl_basic_map *bmap,
+	__isl_take isl_basic_set *dom, int track_empty, int max)
+{
+	struct isl_sol_pma *sol_pma = NULL;
+	isl_space *space;
+
+	if (!bmap)
+		goto error;
+
+	sol_pma = isl_calloc_type(bmap->ctx, struct isl_sol_pma);
+	if (!sol_pma)
+		goto error;
+
+	sol_pma->sol.free = &sol_pma_free;
+	if (sol_init(&sol_pma->sol, bmap, dom, max) < 0)
+		goto error;
+	sol_pma->sol.add = &sol_pma_add_wrap;
+	sol_pma->sol.add_empty = track_empty ? &sol_pma_add_empty_wrap : NULL;
+	space = isl_space_copy(sol_pma->sol.space);
+	sol_pma->pma = isl_pw_multi_aff_empty(space);
+	if (!sol_pma->pma)
+		goto error;
+
+	if (track_empty) {
+		sol_pma->empty = isl_set_alloc_space(isl_basic_set_get_space(dom),
+							1, ISL_SET_DISJOINT);
+		if (!sol_pma->empty)
+			goto error;
+	}
+
+	isl_basic_set_free(dom);
+	return &sol_pma->sol;
+error:
+	isl_basic_set_free(dom);
+	sol_free(&sol_pma->sol);
+	return NULL;
+}
+
+/* Base case of isl_tab_basic_map_partial_lexopt, after removing
+ * some obvious symmetries.
+ *
+ * We call basic_map_partial_lexopt_base_sol and extract the results.
+ */
+static __isl_give isl_pw_multi_aff *basic_map_partial_lexopt_base_pw_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max)
+{
+	isl_pw_multi_aff *result = NULL;
+	struct isl_sol *sol;
+	struct isl_sol_pma *sol_pma;
+
+	sol = basic_map_partial_lexopt_base_sol(bmap, dom, empty, max,
+						&sol_pma_init);
+	if (!sol)
+		return NULL;
+	sol_pma = (struct isl_sol_pma *) sol;
+
+	result = isl_pw_multi_aff_copy(sol_pma->pma);
+	if (empty)
+		*empty = isl_set_copy(sol_pma->empty);
+	sol_free(&sol_pma->sol);
+	return result;
+}
+
+/* Given that the last input variable of "maff" represents the minimum
+ * of some bounds, check whether we need to plug in the expression
+ * of the minimum.
+ *
+ * In particular, check if the last input variable appears in any
+ * of the expressions in "maff".
+ */
+static int need_substitution(__isl_keep isl_multi_aff *maff)
+{
+	int i;
+	unsigned pos;
+
+	pos = isl_multi_aff_dim(maff, isl_dim_in) - 1;
+
+	for (i = 0; i < maff->n; ++i)
+		if (isl_aff_involves_dims(maff->p[i], isl_dim_in, pos, 1))
+			return 1;
+
+	return 0;
+}
+
+/* Given a set of upper bounds on the last "input" variable m,
+ * construct a piecewise affine expression that selects
+ * the minimal upper bound to m, i.e.,
+ * divide the space into cells where one
+ * of the upper bounds is smaller than all the others and select
+ * this upper bound on that cell.
+ *
+ * In particular, if there are n bounds b_i, then the result
+ * consists of n cell, each one of the form
+ *
+ *	b_i <= b_j	for j > i
+ *	b_i <  b_j	for j < i
+ *
+ * The affine expression on this cell is
+ *
+ *	b_i
+ */
+static __isl_give isl_pw_aff *set_minimum_pa(__isl_take isl_space *space,
+	__isl_take isl_mat *var)
+{
+	int i;
+	isl_aff *aff = NULL;
+	isl_basic_set *bset = NULL;
+	isl_pw_aff *paff = NULL;
+	isl_space *pw_space;
+	isl_local_space *ls = NULL;
+
+	if (!space || !var)
+		goto error;
+
+	ls = isl_local_space_from_space(isl_space_copy(space));
+	pw_space = isl_space_copy(space);
+	pw_space = isl_space_from_domain(pw_space);
+	pw_space = isl_space_add_dims(pw_space, isl_dim_out, 1);
+	paff = isl_pw_aff_alloc_size(pw_space, var->n_row);
+
+	for (i = 0; i < var->n_row; ++i) {
+		isl_pw_aff *paff_i;
+
+		aff = isl_aff_alloc(isl_local_space_copy(ls));
+		bset = isl_basic_set_alloc_space(isl_space_copy(space), 0,
+					       0, var->n_row - 1);
+		if (!aff || !bset)
+			goto error;
+		isl_int_set_si(aff->v->el[0], 1);
+		isl_seq_cpy(aff->v->el + 1, var->row[i], var->n_col);
+		isl_int_set_si(aff->v->el[1 + var->n_col], 0);
+		bset = select_minimum(bset, var, i);
+		paff_i = isl_pw_aff_alloc(isl_set_from_basic_set(bset), aff);
+		paff = isl_pw_aff_add_disjoint(paff, paff_i);
+	}
+
+	isl_local_space_free(ls);
+	isl_space_free(space);
+	isl_mat_free(var);
+	return paff;
+error:
+	isl_aff_free(aff);
+	isl_basic_set_free(bset);
+	isl_pw_aff_free(paff);
+	isl_local_space_free(ls);
+	isl_space_free(space);
+	isl_mat_free(var);
+	return NULL;
+}
+
+/* Given a piecewise multi-affine expression of which the last input variable
+ * is the minimum of the bounds in "cst", plug in the value of the minimum.
+ * This minimum expression is given in "min_expr_pa".
+ * The set "min_expr" contains the same information, but in the form of a set.
+ * The variable is subsequently projected out.
+ *
+ * The implementation is similar to those of "split" and "split_domain".
+ * If the variable appears in a given expression, then minimum expression
+ * is plugged in.  Otherwise, if the variable appears in the constraints
+ * and a split is required, then the domain is split.  Otherwise, no split
+ * is performed.
+ */
+static __isl_give isl_pw_multi_aff *split_domain_pma(
+	__isl_take isl_pw_multi_aff *opt, __isl_take isl_pw_aff *min_expr_pa,
+	__isl_take isl_set *min_expr, __isl_take isl_mat *cst)
+{
+	int n_in;
+	int i;
+	isl_space *space;
+	isl_pw_multi_aff *res;
+
+	if (!opt || !min_expr || !cst)
+		goto error;
+
+	n_in = isl_pw_multi_aff_dim(opt, isl_dim_in);
+	space = isl_pw_multi_aff_get_space(opt);
+	space = isl_space_drop_dims(space, isl_dim_in, n_in - 1, 1);
+	res = isl_pw_multi_aff_empty(space);
+
+	for (i = 0; i < opt->n; ++i) {
+		isl_pw_multi_aff *pma;
+
+		pma = isl_pw_multi_aff_alloc(isl_set_copy(opt->p[i].set),
+					 isl_multi_aff_copy(opt->p[i].maff));
+		if (need_substitution(opt->p[i].maff))
+			pma = isl_pw_multi_aff_substitute(pma,
+					isl_dim_in, n_in - 1, min_expr_pa);
+		else {
+			isl_bool split;
+			split = need_split_set(opt->p[i].set, cst);
+			if (split < 0)
+				pma = isl_pw_multi_aff_free(pma);
+			else if (split)
+				pma = isl_pw_multi_aff_intersect_domain(pma,
+						       isl_set_copy(min_expr));
+		}
+		pma = isl_pw_multi_aff_project_out(pma,
+						    isl_dim_in, n_in - 1, 1);
+
+		res = isl_pw_multi_aff_add_disjoint(res, pma);
+	}
+
+	isl_pw_multi_aff_free(opt);
+	isl_pw_aff_free(min_expr_pa);
+	isl_set_free(min_expr);
+	isl_mat_free(cst);
+	return res;
+error:
+	isl_pw_multi_aff_free(opt);
+	isl_pw_aff_free(min_expr_pa);
+	isl_set_free(min_expr);
+	isl_mat_free(cst);
+	return NULL;
+}
+
+static __isl_give isl_pw_multi_aff *basic_map_partial_lexopt_pw_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max);
+
+/* This function is called from basic_map_partial_lexopt_symm.
+ * The last variable of "bmap" and "dom" corresponds to the minimum
+ * of the bounds in "cst".  "map_space" is the space of the original
+ * input relation (of basic_map_partial_lexopt_symm) and "set_space"
+ * is the space of the original domain.
+ *
+ * We recursively call basic_map_partial_lexopt and then plug in
+ * the definition of the minimum in the result.
+ */
+static __isl_give isl_pw_multi_aff *
+basic_map_partial_lexopt_symm_core_pw_multi_aff(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max, __isl_take isl_mat *cst,
+	__isl_take isl_space *map_space, __isl_take isl_space *set_space)
+{
+	isl_pw_multi_aff *opt;
+	isl_pw_aff *min_expr_pa;
+	isl_set *min_expr;
+
+	min_expr = set_minimum(isl_basic_set_get_space(dom), isl_mat_copy(cst));
+	min_expr_pa = set_minimum_pa(isl_basic_set_get_space(dom),
+					isl_mat_copy(cst));
+
+	opt = basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, max);
+
+	if (empty) {
+		*empty = split(*empty,
+			       isl_set_copy(min_expr), isl_mat_copy(cst));
+		*empty = isl_set_reset_space(*empty, set_space);
+	}
+
+	opt = split_domain_pma(opt, min_expr_pa, min_expr, cst);
+	opt = isl_pw_multi_aff_reset_space(opt, map_space);
+
+	return opt;
+}
+
+#undef TYPE
+#define TYPE	isl_pw_multi_aff
+#undef SUFFIX
+#define SUFFIX	_pw_multi_aff
+#include "isl_tab_lexopt_templ.c"
diff --git a/final/lib/External/isl/isl_tarjan.c b/final/lib/External/isl/isl_tarjan.c
new file mode 100644
index 0000000..a958c01
--- /dev/null
+++ b/final/lib/External/isl/isl_tarjan.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2010-2011 INRIA Saclay
+ * Copyright 2012      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <stdlib.h>
+#include <isl/ctx.h>
+#include <isl_tarjan.h>
+
+struct isl_tarjan_graph *isl_tarjan_graph_free(struct isl_tarjan_graph *g)
+{
+	if (!g)
+		return NULL;
+	free(g->node);
+	free(g->stack);
+	free(g->order);
+	free(g);
+	return NULL;
+}
+
+static struct isl_tarjan_graph *isl_tarjan_graph_alloc(isl_ctx *ctx, int len)
+{
+	struct isl_tarjan_graph *g;
+	int i;
+
+	g = isl_calloc_type(ctx, struct isl_tarjan_graph);
+	if (!g)
+		return NULL;
+	g->len = len;
+	g->node = isl_alloc_array(ctx, struct isl_tarjan_node, len);
+	if (len && !g->node)
+		goto error;
+	for (i = 0; i < len; ++i)
+		g->node[i].index = -1;
+	g->stack = isl_alloc_array(ctx, int, len);
+	if (len && !g->stack)
+		goto error;
+	g->order = isl_alloc_array(ctx, int, 2 * len);
+	if (len && !g->order)
+		goto error;
+
+	g->sp = 0;
+	g->index = 0;
+	g->op = 0;
+
+	return g;
+error:
+	isl_tarjan_graph_free(g);
+	return NULL;
+}
+
+/* Perform Tarjan's algorithm for computing the strongly connected components
+ * in the graph with g->len nodes and with edges defined by "follows".
+ */
+static isl_stat isl_tarjan_components(struct isl_tarjan_graph *g, int i,
+	isl_bool (*follows)(int i, int j, void *user), void *user)
+{
+	int j;
+
+	g->node[i].index = g->index;
+	g->node[i].min_index = g->index;
+	g->node[i].on_stack = 1;
+	g->index++;
+	g->stack[g->sp++] = i;
+
+	for (j = g->len - 1; j >= 0; --j) {
+		isl_bool f;
+
+		if (j == i)
+			continue;
+		if (g->node[j].index >= 0 &&
+			(!g->node[j].on_stack ||
+			 g->node[j].index > g->node[i].min_index))
+			continue;
+
+		f = follows(i, j, user);
+		if (f < 0)
+			return isl_stat_error;
+		if (!f)
+			continue;
+
+		if (g->node[j].index < 0) {
+			isl_tarjan_components(g, j, follows, user);
+			if (g->node[j].min_index < g->node[i].min_index)
+				g->node[i].min_index = g->node[j].min_index;
+		} else if (g->node[j].index < g->node[i].min_index)
+			g->node[i].min_index = g->node[j].index;
+	}
+
+	if (g->node[i].index != g->node[i].min_index)
+		return isl_stat_ok;
+
+	do {
+		j = g->stack[--g->sp];
+		g->node[j].on_stack = 0;
+		g->order[g->op++] = j;
+	} while (j != i);
+	g->order[g->op++] = -1;
+
+	return isl_stat_ok;
+}
+
+/* Decompose the graph with "len" nodes and edges defined by "follows"
+ * into strongly connected components (SCCs).
+ * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise.
+ * It should return -1 on error.
+ *
+ * If SCC a contains a node i that follows a node j in another SCC b
+ * (i.e., follows(i, j, user) returns 1), then SCC a will appear after SCC b
+ * in the result.
+ */
+struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len,
+	isl_bool (*follows)(int i, int j, void *user), void *user)
+{
+	int i;
+	struct isl_tarjan_graph *g = NULL;
+
+	g = isl_tarjan_graph_alloc(ctx, len);
+	if (!g)
+		return NULL;
+	for (i = len - 1; i >= 0; --i) {
+		if (g->node[i].index >= 0)
+			continue;
+		if (isl_tarjan_components(g, i, follows, user) < 0)
+			return isl_tarjan_graph_free(g);
+	}
+
+	return g;
+}
+
+/* Decompose the graph with "len" nodes and edges defined by "follows"
+ * into the strongly connected component (SCC) that contains "node"
+ * as well as all SCCs that are followed by this SCC.
+ * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise.
+ * It should return -1 on error.
+ *
+ * The SCC containing "node" will appear as the last component
+ * in g->order.
+ */
+struct isl_tarjan_graph *isl_tarjan_graph_component(isl_ctx *ctx, int len,
+	int node, isl_bool (*follows)(int i, int j, void *user), void *user)
+{
+	struct isl_tarjan_graph *g;
+
+	g = isl_tarjan_graph_alloc(ctx, len);
+	if (!g)
+		return NULL;
+	if (isl_tarjan_components(g, node, follows, user) < 0)
+		return isl_tarjan_graph_free(g);
+
+	return g;
+}
diff --git a/final/lib/External/isl/isl_tarjan.h b/final/lib/External/isl/isl_tarjan.h
new file mode 100644
index 0000000..af3452c
--- /dev/null
+++ b/final/lib/External/isl/isl_tarjan.h
@@ -0,0 +1,42 @@
+#ifndef ISL_TARJAN_H
+#define ISL_TARJAN_H
+
+/* Structure for representing the nodes in the graph being traversed
+ * using Tarjan's algorithm.
+ * index represents the order in which nodes are visited.
+ * min_index is the index of the root of a (sub)component.
+ * on_stack indicates whether the node is currently on the stack.
+ */
+struct isl_tarjan_node {
+	int index;
+	int min_index;
+	int on_stack;
+};
+
+/* Structure for representing the graph being traversed
+ * using Tarjan's algorithm.
+ * len is the number of nodes
+ * node is an array of nodes
+ * stack contains the nodes on the path from the root to the current node
+ * sp is the stack pointer
+ * index is the index of the last node visited
+ * order contains the elements of the components separated by -1
+ * op represents the current position in order
+ */
+struct isl_tarjan_graph {
+	int len;
+	struct isl_tarjan_node *node;
+	int *stack;
+	int sp;
+	int index;
+	int *order;
+	int op;
+};
+
+struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len,
+	isl_bool (*follows)(int i, int j, void *user), void *user);
+struct isl_tarjan_graph *isl_tarjan_graph_component(isl_ctx *ctx, int len,
+	int node, isl_bool (*follows)(int i, int j, void *user), void *user);
+struct isl_tarjan_graph *isl_tarjan_graph_free(struct isl_tarjan_graph *g);
+
+#endif
diff --git a/final/lib/External/isl/isl_test.c b/final/lib/External/isl/isl_test.c
new file mode 100644
index 0000000..2773be5
--- /dev/null
+++ b/final/lib/External/isl/isl_test.c
@@ -0,0 +1,7301 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
+ * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <limits.h>
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl_aff_private.h>
+#include <isl_space_private.h>
+#include <isl/set.h>
+#include <isl/flow.h>
+#include <isl_constraint_private.h>
+#include <isl/polynomial.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl_factorization.h>
+#include <isl/schedule.h>
+#include <isl/schedule_node.h>
+#include <isl_options_private.h>
+#include <isl_vertices_private.h>
+#include <isl/ast_build.h>
+#include <isl/val.h>
+#include <isl/ilp.h>
+#include <isl_ast_build_expr.h>
+#include <isl/options.h>
+
+#include "isl_srcdir.c"
+
+#define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
+
+static char *get_filename(isl_ctx *ctx, const char *name, const char *suffix) {
+	char *filename;
+	int length;
+	char *pattern = "%s/test_inputs/%s.%s";
+
+	length = strlen(pattern) - 6 + strlen(srcdir) + strlen(name)
+		+ strlen(suffix) + 1;
+	filename = isl_alloc_array(ctx, char, length);
+
+	if (!filename)
+		return NULL;
+
+	sprintf(filename, pattern, srcdir, name, suffix);
+
+	return filename;
+}
+
+void test_parse_map(isl_ctx *ctx, const char *str)
+{
+	isl_map *map;
+
+	map = isl_map_read_from_str(ctx, str);
+	assert(map);
+	isl_map_free(map);
+}
+
+int test_parse_map_equal(isl_ctx *ctx, const char *str, const char *str2)
+{
+	isl_map *map, *map2;
+	int equal;
+
+	map = isl_map_read_from_str(ctx, str);
+	map2 = isl_map_read_from_str(ctx, str2);
+	equal = isl_map_is_equal(map, map2);
+	isl_map_free(map);
+	isl_map_free(map2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "maps not equal",
+			return -1);
+
+	return 0;
+}
+
+void test_parse_pwqp(isl_ctx *ctx, const char *str)
+{
+	isl_pw_qpolynomial *pwqp;
+
+	pwqp = isl_pw_qpolynomial_read_from_str(ctx, str);
+	assert(pwqp);
+	isl_pw_qpolynomial_free(pwqp);
+}
+
+static void test_parse_pwaff(isl_ctx *ctx, const char *str)
+{
+	isl_pw_aff *pwaff;
+
+	pwaff = isl_pw_aff_read_from_str(ctx, str);
+	assert(pwaff);
+	isl_pw_aff_free(pwaff);
+}
+
+/* Check that we can read an isl_multi_val from "str" without errors.
+ */
+static int test_parse_multi_val(isl_ctx *ctx, const char *str)
+{
+	isl_multi_val *mv;
+
+	mv = isl_multi_val_read_from_str(ctx, str);
+	isl_multi_val_free(mv);
+
+	return mv ? 0 : -1;
+}
+
+/* Pairs of binary relation representations that should represent
+ * the same binary relations.
+ */
+struct {
+	const char *map1;
+	const char *map2;
+} parse_map_equal_tests[] = {
+	{ "{ [x,y]  : [([x/2]+y)/3] >= 1 }",
+	  "{ [x, y] : 2y >= 6 - x }" },
+	{ "{ [x,y] : x <= min(y, 2*y+3) }",
+	  "{ [x,y] : x <= y, 2*y + 3 }" },
+	{ "{ [x,y] : x >= min(y, 2*y+3) }",
+	  "{ [x, y] : (y <= x and y >= -3) or (2y <= -3 + x and y <= -4) }" },
+	{ "[n] -> { [c1] : c1>=0 and c1<=floord(n-4,3) }",
+	  "[n] -> { [c1] : c1 >= 0 and 3c1 <= -4 + n }" },
+	{ "{ [i,j] -> [i] : i < j; [i,j] -> [j] : j <= i }",
+	  "{ [i,j] -> [min(i,j)] }" },
+	{ "{ [i,j] : i != j }",
+	  "{ [i,j] : i < j or i > j }" },
+	{ "{ [i,j] : (i+1)*2 >= j }",
+	  "{ [i, j] : j <= 2 + 2i }" },
+	{ "{ [i] -> [i > 0 ? 4 : 5] }",
+	  "{ [i] -> [5] : i <= 0; [i] -> [4] : i >= 1 }" },
+	{ "[N=2,M] -> { [i=[(M+N)/4]] }",
+	  "[N, M] -> { [i] : N = 2 and 4i <= 2 + M and 4i >= -1 + M }" },
+	{ "{ [x] : x >= 0 }",
+	  "{ [x] : x-0 >= 0 }" },
+	{ "{ [i] : ((i > 10)) }",
+	  "{ [i] : i >= 11 }" },
+	{ "{ [i] -> [0] }",
+	  "{ [i] -> [0 * i] }" },
+	{ "{ [a] -> [b] : (not false) }",
+	  "{ [a] -> [b] : true }" },
+	{ "{ [i] : i/2 <= 5 }",
+	  "{ [i] : i <= 10 }" },
+	{ "{Sym=[n] [i] : i <= n }",
+	  "[n] -> { [i] : i <= n }" },
+	{ "{ [*] }",
+	  "{ [a] }" },
+	{ "{ [i] : 2*floor(i/2) = i }",
+	  "{ [i] : exists a : i = 2 a }" },
+	{ "{ [a] -> [b] : a = 5 implies b = 5 }",
+	  "{ [a] -> [b] : a != 5 or b = 5 }" },
+	{ "{ [a] -> [a - 1 : a > 0] }",
+	  "{ [a] -> [a - 1] : a > 0 }" },
+	{ "{ [a] -> [a - 1 : a > 0; a : a <= 0] }",
+	  "{ [a] -> [a - 1] : a > 0; [a] -> [a] : a <= 0 }" },
+	{ "{ [a] -> [(a) * 2 : a >= 0; 0 : a < 0] }",
+	  "{ [a] -> [2a] : a >= 0; [a] -> [0] : a < 0 }" },
+	{ "{ [a] -> [(a * 2) : a >= 0; 0 : a < 0] }",
+	  "{ [a] -> [2a] : a >= 0; [a] -> [0] : a < 0 }" },
+	{ "{ [a] -> [(a * 2 : a >= 0); 0 : a < 0] }",
+	  "{ [a] -> [2a] : a >= 0; [a] -> [0] : a < 0 }" },
+	{ "{ [a] -> [(a * 2 : a >= 0; 0 : a < 0)] }",
+	  "{ [a] -> [2a] : a >= 0; [a] -> [0] : a < 0 }" },
+	{ "{ [a,b] -> [i,j] : a,b << i,j }",
+	  "{ [a,b] -> [i,j] : a < i or (a = i and b < j) }" },
+	{ "{ [a,b] -> [i,j] : a,b <<= i,j }",
+	  "{ [a,b] -> [i,j] : a < i or (a = i and b <= j) }" },
+	{ "{ [a,b] -> [i,j] : a,b >> i,j }",
+	  "{ [a,b] -> [i,j] : a > i or (a = i and b > j) }" },
+	{ "{ [a,b] -> [i,j] : a,b >>= i,j }",
+	  "{ [a,b] -> [i,j] : a > i or (a = i and b >= j) }" },
+	{ "{ [n] -> [i] : exists (a, b, c: 8b <= i - 32a and "
+			    "8b >= -7 + i - 32 a and b >= 0 and b <= 3 and "
+			    "8c < n - 32a and i < n and c >= 0 and "
+			    "c <= 3 and c >= -4a) }",
+	  "{ [n] -> [i] : 0 <= i < n }" },
+	{ "{ [x] -> [] : exists (a, b: 0 <= a <= 1 and 0 <= b <= 3 and "
+			    "2b <= x - 8a and 2b >= -1 + x - 8a) }",
+	  "{ [x] -> [] : 0 <= x <= 15 }" },
+	{ "{ [x] -> [x] : }",
+	  "{ [x] -> [x] }" },
+};
+
+int test_parse(struct isl_ctx *ctx)
+{
+	int i;
+	isl_map *map, *map2;
+	const char *str, *str2;
+
+	if (test_parse_multi_val(ctx, "{ A[B[2] -> C[5, 7]] }") < 0)
+		return -1;
+	if (test_parse_multi_val(ctx, "[n] -> { [2] }") < 0)
+		return -1;
+	if (test_parse_multi_val(ctx, "{ A[4, infty, NaN, -1/2, 2/3] }") < 0)
+		return -1;
+
+	str = "{ [i] -> [-i] }";
+	map = isl_map_read_from_str(ctx, str);
+	assert(map);
+	isl_map_free(map);
+
+	str = "{ A[i] -> L[([i/3])] }";
+	map = isl_map_read_from_str(ctx, str);
+	assert(map);
+	isl_map_free(map);
+
+	test_parse_map(ctx, "{[[s] -> A[i]] -> [[s+1] -> A[i]]}");
+	test_parse_map(ctx, "{ [p1, y1, y2] -> [2, y1, y2] : "
+				"p1 = 1 && (y1 <= y2 || y2 = 0) }");
+
+	for (i = 0; i < ARRAY_SIZE(parse_map_equal_tests); ++i) {
+		str = parse_map_equal_tests[i].map1;
+		str2 = parse_map_equal_tests[i].map2;
+		if (test_parse_map_equal(ctx, str, str2) < 0)
+			return -1;
+	}
+
+	str = "{[new,old] -> [new+1-2*[(new+1)/2],old+1-2*[(old+1)/2]]}";
+	map = isl_map_read_from_str(ctx, str);
+	str = "{ [new, old] -> [o0, o1] : "
+	       "exists (e0 = [(-1 - new + o0)/2], e1 = [(-1 - old + o1)/2]: "
+	       "2e0 = -1 - new + o0 and 2e1 = -1 - old + o1 and o0 >= 0 and "
+	       "o0 <= 1 and o1 >= 0 and o1 <= 1) }";
+	map2 = isl_map_read_from_str(ctx, str);
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map);
+	isl_map_free(map2);
+
+	str = "{[new,old] -> [new+1-2*[(new+1)/2],old+1-2*[(old+1)/2]]}";
+	map = isl_map_read_from_str(ctx, str);
+	str = "{[new,old] -> [(new+1)%2,(old+1)%2]}";
+	map2 = isl_map_read_from_str(ctx, str);
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map);
+	isl_map_free(map2);
+
+	test_parse_pwqp(ctx, "{ [i] -> i + [ (i + [i/3])/2 ] }");
+	test_parse_map(ctx, "{ S1[i] -> [([i/10]),i%10] : 0 <= i <= 45 }");
+	test_parse_pwaff(ctx, "{ [i] -> [i + 1] : i > 0; [a] -> [a] : a < 0 }");
+	test_parse_pwqp(ctx, "{ [x] -> ([(x)/2] * [(x)/3]) }");
+	test_parse_pwaff(ctx, "{ [] -> [(100)] }");
+
+	return 0;
+}
+
+static int test_read(isl_ctx *ctx)
+{
+	char *filename;
+	FILE *input;
+	isl_basic_set *bset1, *bset2;
+	const char *str = "{[y]: Exists ( alpha : 2alpha = y)}";
+	int equal;
+
+	filename = get_filename(ctx, "set", "omega");
+	assert(filename);
+	input = fopen(filename, "r");
+	assert(input);
+
+	bset1 = isl_basic_set_read_from_file(ctx, input);
+	bset2 = isl_basic_set_read_from_str(ctx, str);
+
+	equal = isl_basic_set_is_equal(bset1, bset2);
+
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	free(filename);
+
+	fclose(input);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"read sets not equal", return -1);
+
+	return 0;
+}
+
+static int test_bounded(isl_ctx *ctx)
+{
+	isl_set *set;
+	isl_bool bounded;
+
+	set = isl_set_read_from_str(ctx, "[n] -> {[i] : 0 <= i <= n }");
+	bounded = isl_set_is_bounded(set);
+	isl_set_free(set);
+
+	if (bounded < 0)
+		return -1;
+	if (!bounded)
+		isl_die(ctx, isl_error_unknown,
+			"set not considered bounded", return -1);
+
+	set = isl_set_read_from_str(ctx, "{[n, i] : 0 <= i <= n }");
+	bounded = isl_set_is_bounded(set);
+	assert(!bounded);
+	isl_set_free(set);
+
+	if (bounded < 0)
+		return -1;
+	if (bounded)
+		isl_die(ctx, isl_error_unknown,
+			"set considered bounded", return -1);
+
+	set = isl_set_read_from_str(ctx, "[n] -> {[i] : i <= n }");
+	bounded = isl_set_is_bounded(set);
+	isl_set_free(set);
+
+	if (bounded < 0)
+		return -1;
+	if (bounded)
+		isl_die(ctx, isl_error_unknown,
+			"set considered bounded", return -1);
+
+	return 0;
+}
+
+/* Construct the basic set { [i] : 5 <= i <= N } */
+static int test_construction_1(isl_ctx *ctx)
+{
+	isl_int v;
+	isl_space *dim;
+	isl_local_space *ls;
+	isl_basic_set *bset;
+	isl_constraint *c;
+
+	isl_int_init(v);
+
+	dim = isl_space_set_alloc(ctx, 1, 1);
+	bset = isl_basic_set_universe(isl_space_copy(dim));
+	ls = isl_local_space_from_space(dim);
+
+	c = isl_constraint_alloc_inequality(isl_local_space_copy(ls));
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_coefficient(c, isl_dim_param, 0, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = isl_constraint_alloc_inequality(isl_local_space_copy(ls));
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -5);
+	c = isl_constraint_set_constant(c, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	isl_local_space_free(ls);
+	isl_basic_set_free(bset);
+
+	isl_int_clear(v);
+
+	return 0;
+}
+
+/* Construct the basic set { [x] : -100 <= x <= 100 }
+ * using isl_basic_set_{lower,upper}_bound_val and
+ * check that it is equal the same basic set parsed from a string.
+ */
+static int test_construction_2(isl_ctx *ctx)
+{
+	isl_bool equal;
+	isl_val *v;
+	isl_space *space;
+	isl_basic_set *bset1, *bset2;
+
+	v = isl_val_int_from_si(ctx, 100);
+	space = isl_space_set_alloc(ctx, 0, 1);
+	bset1 = isl_basic_set_universe(space);
+	bset1 = isl_basic_set_upper_bound_val(bset1, isl_dim_set, 0,
+						isl_val_copy(v));
+	bset1 = isl_basic_set_lower_bound_val(bset1, isl_dim_set, 0,
+						isl_val_neg(v));
+	bset2 = isl_basic_set_read_from_str(ctx, "{ [x] : -100 <= x <= 100 }");
+	equal = isl_basic_set_is_equal(bset1, bset2);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"failed construction", return -1);
+
+	return 0;
+}
+
+/* Basic tests for constructing basic sets.
+ */
+static int test_construction(isl_ctx *ctx)
+{
+	if (test_construction_1(ctx) < 0)
+		return -1;
+	if (test_construction_2(ctx) < 0)
+		return -1;
+	return 0;
+}
+
+static int test_dim(isl_ctx *ctx)
+{
+	const char *str;
+	isl_map *map1, *map2;
+	int equal;
+
+	map1 = isl_map_read_from_str(ctx,
+	    "[n] -> { [i] -> [j] : exists (a = [i/10] : i - 10a <= n ) }");
+	map1 = isl_map_add_dims(map1, isl_dim_in, 1);
+	map2 = isl_map_read_from_str(ctx,
+	    "[n] -> { [i,k] -> [j] : exists (a = [i/10] : i - 10a <= n ) }");
+	equal = isl_map_is_equal(map1, map2);
+	isl_map_free(map2);
+
+	map1 = isl_map_project_out(map1, isl_dim_in, 0, 1);
+	map2 = isl_map_read_from_str(ctx, "[n] -> { [i] -> [j] : n >= 0 }");
+	if (equal >= 0 && equal)
+		equal = isl_map_is_equal(map1, map2);
+
+	isl_map_free(map1);
+	isl_map_free(map2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected result", return -1);
+
+	str = "[n] -> { [i] -> [] : exists a : 0 <= i <= n and i = 2 a }";
+	map1 = isl_map_read_from_str(ctx, str);
+	str = "{ [i] -> [j] : exists a : 0 <= i <= j and i = 2 a }";
+	map2 = isl_map_read_from_str(ctx, str);
+	map1 = isl_map_move_dims(map1, isl_dim_out, 0, isl_dim_param, 0, 1);
+	equal = isl_map_is_equal(map1, map2);
+	isl_map_free(map1);
+	isl_map_free(map2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected result", return -1);
+
+	return 0;
+}
+
+struct {
+	__isl_give isl_val *(*op)(__isl_take isl_val *v);
+	const char *arg;
+	const char *res;
+} val_un_tests[] = {
+	{ &isl_val_neg, "0", "0" },
+	{ &isl_val_abs, "0", "0" },
+	{ &isl_val_2exp, "0", "1" },
+	{ &isl_val_floor, "0", "0" },
+	{ &isl_val_ceil, "0", "0" },
+	{ &isl_val_neg, "1", "-1" },
+	{ &isl_val_neg, "-1", "1" },
+	{ &isl_val_neg, "1/2", "-1/2" },
+	{ &isl_val_neg, "-1/2", "1/2" },
+	{ &isl_val_neg, "infty", "-infty" },
+	{ &isl_val_neg, "-infty", "infty" },
+	{ &isl_val_neg, "NaN", "NaN" },
+	{ &isl_val_abs, "1", "1" },
+	{ &isl_val_abs, "-1", "1" },
+	{ &isl_val_abs, "1/2", "1/2" },
+	{ &isl_val_abs, "-1/2", "1/2" },
+	{ &isl_val_abs, "infty", "infty" },
+	{ &isl_val_abs, "-infty", "infty" },
+	{ &isl_val_abs, "NaN", "NaN" },
+	{ &isl_val_floor, "1", "1" },
+	{ &isl_val_floor, "-1", "-1" },
+	{ &isl_val_floor, "1/2", "0" },
+	{ &isl_val_floor, "-1/2", "-1" },
+	{ &isl_val_floor, "infty", "infty" },
+	{ &isl_val_floor, "-infty", "-infty" },
+	{ &isl_val_floor, "NaN", "NaN" },
+	{ &isl_val_ceil, "1", "1" },
+	{ &isl_val_ceil, "-1", "-1" },
+	{ &isl_val_ceil, "1/2", "1" },
+	{ &isl_val_ceil, "-1/2", "0" },
+	{ &isl_val_ceil, "infty", "infty" },
+	{ &isl_val_ceil, "-infty", "-infty" },
+	{ &isl_val_ceil, "NaN", "NaN" },
+	{ &isl_val_2exp, "-3", "1/8" },
+	{ &isl_val_2exp, "-1", "1/2" },
+	{ &isl_val_2exp, "1", "2" },
+	{ &isl_val_2exp, "2", "4" },
+	{ &isl_val_2exp, "3", "8" },
+	{ &isl_val_inv, "1", "1" },
+	{ &isl_val_inv, "2", "1/2" },
+	{ &isl_val_inv, "1/2", "2" },
+	{ &isl_val_inv, "-2", "-1/2" },
+	{ &isl_val_inv, "-1/2", "-2" },
+	{ &isl_val_inv, "0", "NaN" },
+	{ &isl_val_inv, "NaN", "NaN" },
+	{ &isl_val_inv, "infty", "0" },
+	{ &isl_val_inv, "-infty", "0" },
+};
+
+/* Perform some basic tests of unary operations on isl_val objects.
+ */
+static int test_un_val(isl_ctx *ctx)
+{
+	int i;
+	isl_val *v, *res;
+	__isl_give isl_val *(*fn)(__isl_take isl_val *v);
+	int ok;
+
+	for (i = 0; i < ARRAY_SIZE(val_un_tests); ++i) {
+		v = isl_val_read_from_str(ctx, val_un_tests[i].arg);
+		res = isl_val_read_from_str(ctx, val_un_tests[i].res);
+		fn = val_un_tests[i].op;
+		v = fn(v);
+		if (isl_val_is_nan(res))
+			ok = isl_val_is_nan(v);
+		else
+			ok = isl_val_eq(v, res);
+		isl_val_free(v);
+		isl_val_free(res);
+		if (ok < 0)
+			return -1;
+		if (!ok)
+			isl_die(ctx, isl_error_unknown,
+				"unexpected result", return -1);
+	}
+
+	return 0;
+}
+
+struct {
+	__isl_give isl_val *(*fn)(__isl_take isl_val *v1,
+				__isl_take isl_val *v2);
+} val_bin_op[] = {
+	['+'] = { &isl_val_add },
+	['-'] = { &isl_val_sub },
+	['*'] = { &isl_val_mul },
+	['/'] = { &isl_val_div },
+	['g'] = { &isl_val_gcd },
+	['m'] = { &isl_val_min },
+	['M'] = { &isl_val_max },
+};
+
+struct {
+	const char *arg1;
+	unsigned char op;
+	const char *arg2;
+	const char *res;
+} val_bin_tests[] = {
+	{ "0", '+', "0", "0" },
+	{ "1", '+', "0", "1" },
+	{ "1", '+', "1", "2" },
+	{ "1", '-', "1", "0" },
+	{ "1", '*', "1", "1" },
+	{ "1", '/', "1", "1" },
+	{ "2", '*', "3", "6" },
+	{ "2", '*', "1/2", "1" },
+	{ "2", '*', "1/3", "2/3" },
+	{ "2/3", '*', "3/5", "2/5" },
+	{ "2/3", '*', "7/5", "14/15" },
+	{ "2", '/', "1/2", "4" },
+	{ "-2", '/', "-1/2", "4" },
+	{ "-2", '/', "1/2", "-4" },
+	{ "2", '/', "-1/2", "-4" },
+	{ "2", '/', "2", "1" },
+	{ "2", '/', "3", "2/3" },
+	{ "2/3", '/', "5/3", "2/5" },
+	{ "2/3", '/', "5/7", "14/15" },
+	{ "0", '/', "0", "NaN" },
+	{ "42", '/', "0", "NaN" },
+	{ "-42", '/', "0", "NaN" },
+	{ "infty", '/', "0", "NaN" },
+	{ "-infty", '/', "0", "NaN" },
+	{ "NaN", '/', "0", "NaN" },
+	{ "0", '/', "NaN", "NaN" },
+	{ "42", '/', "NaN", "NaN" },
+	{ "-42", '/', "NaN", "NaN" },
+	{ "infty", '/', "NaN", "NaN" },
+	{ "-infty", '/', "NaN", "NaN" },
+	{ "NaN", '/', "NaN", "NaN" },
+	{ "0", '/', "infty", "0" },
+	{ "42", '/', "infty", "0" },
+	{ "-42", '/', "infty", "0" },
+	{ "infty", '/', "infty", "NaN" },
+	{ "-infty", '/', "infty", "NaN" },
+	{ "NaN", '/', "infty", "NaN" },
+	{ "0", '/', "-infty", "0" },
+	{ "42", '/', "-infty", "0" },
+	{ "-42", '/', "-infty", "0" },
+	{ "infty", '/', "-infty", "NaN" },
+	{ "-infty", '/', "-infty", "NaN" },
+	{ "NaN", '/', "-infty", "NaN" },
+	{ "1", '-', "1/3", "2/3" },
+	{ "1/3", '+', "1/2", "5/6" },
+	{ "1/2", '+', "1/2", "1" },
+	{ "3/4", '-', "1/4", "1/2" },
+	{ "1/2", '-', "1/3", "1/6" },
+	{ "infty", '+', "42", "infty" },
+	{ "infty", '+', "infty", "infty" },
+	{ "42", '+', "infty", "infty" },
+	{ "infty", '-', "infty", "NaN" },
+	{ "infty", '*', "infty", "infty" },
+	{ "infty", '*', "-infty", "-infty" },
+	{ "-infty", '*', "infty", "-infty" },
+	{ "-infty", '*', "-infty", "infty" },
+	{ "0", '*', "infty", "NaN" },
+	{ "1", '*', "infty", "infty" },
+	{ "infty", '*', "0", "NaN" },
+	{ "infty", '*', "42", "infty" },
+	{ "42", '-', "infty", "-infty" },
+	{ "infty", '+', "-infty", "NaN" },
+	{ "4", 'g', "6", "2" },
+	{ "5", 'g', "6", "1" },
+	{ "42", 'm', "3", "3" },
+	{ "42", 'M', "3", "42" },
+	{ "3", 'm', "42", "3" },
+	{ "3", 'M', "42", "42" },
+	{ "42", 'm', "infty", "42" },
+	{ "42", 'M', "infty", "infty" },
+	{ "42", 'm', "-infty", "-infty" },
+	{ "42", 'M', "-infty", "42" },
+	{ "42", 'm', "NaN", "NaN" },
+	{ "42", 'M', "NaN", "NaN" },
+	{ "infty", 'm', "-infty", "-infty" },
+	{ "infty", 'M', "-infty", "infty" },
+};
+
+/* Perform some basic tests of binary operations on isl_val objects.
+ */
+static int test_bin_val(isl_ctx *ctx)
+{
+	int i;
+	isl_val *v1, *v2, *res;
+	__isl_give isl_val *(*fn)(__isl_take isl_val *v1,
+				__isl_take isl_val *v2);
+	int ok;
+
+	for (i = 0; i < ARRAY_SIZE(val_bin_tests); ++i) {
+		v1 = isl_val_read_from_str(ctx, val_bin_tests[i].arg1);
+		v2 = isl_val_read_from_str(ctx, val_bin_tests[i].arg2);
+		res = isl_val_read_from_str(ctx, val_bin_tests[i].res);
+		fn = val_bin_op[val_bin_tests[i].op].fn;
+		v1 = fn(v1, v2);
+		if (isl_val_is_nan(res))
+			ok = isl_val_is_nan(v1);
+		else
+			ok = isl_val_eq(v1, res);
+		isl_val_free(v1);
+		isl_val_free(res);
+		if (ok < 0)
+			return -1;
+		if (!ok)
+			isl_die(ctx, isl_error_unknown,
+				"unexpected result", return -1);
+	}
+
+	return 0;
+}
+
+/* Perform some basic tests on isl_val objects.
+ */
+static int test_val(isl_ctx *ctx)
+{
+	if (test_un_val(ctx) < 0)
+		return -1;
+	if (test_bin_val(ctx) < 0)
+		return -1;
+	return 0;
+}
+
+/* Sets described using existentially quantified variables that
+ * can also be described without.
+ */
+static const char *elimination_tests[] = {
+	"{ [i,j] : 2 * [i/2] + 3 * [j/4] <= 10 and 2 i = j }",
+	"{ [m, w] : exists a : w - 2m - 5 <= 3a <= m - 2w }",
+	"{ [m, w] : exists a : w >= 0 and a < m and -1 + w <= a <= 2m - w }",
+};
+
+/* Check that redundant existentially quantified variables are
+ * getting removed.
+ */
+static int test_elimination(isl_ctx *ctx)
+{
+	int i;
+	unsigned n;
+	isl_basic_set *bset;
+
+	for (i = 0; i < ARRAY_SIZE(elimination_tests); ++i) {
+		bset = isl_basic_set_read_from_str(ctx, elimination_tests[i]);
+		n = isl_basic_set_dim(bset, isl_dim_div);
+		isl_basic_set_free(bset);
+		if (!bset)
+			return -1;
+		if (n != 0)
+			isl_die(ctx, isl_error_unknown,
+				"expecting no existentials", return -1);
+	}
+
+	return 0;
+}
+
+static int test_div(isl_ctx *ctx)
+{
+	const char *str;
+	int empty;
+	isl_int v;
+	isl_space *dim;
+	isl_set *set;
+	isl_local_space *ls;
+	struct isl_basic_set *bset;
+	struct isl_constraint *c;
+
+	isl_int_init(v);
+
+	/* test 1 */
+	dim = isl_space_set_alloc(ctx, 0, 3);
+	bset = isl_basic_set_universe(isl_space_copy(dim));
+	ls = isl_local_space_from_space(dim);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 1, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 2, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 1, 2);
+
+	assert(bset && bset->n_div == 1);
+	isl_local_space_free(ls);
+	isl_basic_set_free(bset);
+
+	/* test 2 */
+	dim = isl_space_set_alloc(ctx, 0, 3);
+	bset = isl_basic_set_universe(isl_space_copy(dim));
+	ls = isl_local_space_from_space(dim);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 1, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 2, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 1, 2);
+
+	assert(bset && bset->n_div == 1);
+	isl_local_space_free(ls);
+	isl_basic_set_free(bset);
+
+	/* test 3 */
+	dim = isl_space_set_alloc(ctx, 0, 3);
+	bset = isl_basic_set_universe(isl_space_copy(dim));
+	ls = isl_local_space_from_space(dim);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 1, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, -3);
+	c = isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 4);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 2, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 1, 2);
+
+	assert(bset && bset->n_div == 1);
+	isl_local_space_free(ls);
+	isl_basic_set_free(bset);
+
+	/* test 4 */
+	dim = isl_space_set_alloc(ctx, 0, 3);
+	bset = isl_basic_set_universe(isl_space_copy(dim));
+	ls = isl_local_space_from_space(dim);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, 2);
+	c = isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 1, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 6);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 2, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 1, 2);
+
+	assert(isl_basic_set_is_empty(bset));
+	isl_local_space_free(ls);
+	isl_basic_set_free(bset);
+
+	/* test 5 */
+	dim = isl_space_set_alloc(ctx, 0, 3);
+	bset = isl_basic_set_universe(isl_space_copy(dim));
+	ls = isl_local_space_from_space(dim);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 2, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 1, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 2, 1);
+
+	assert(bset && bset->n_div == 0);
+	isl_basic_set_free(bset);
+	isl_local_space_free(ls);
+
+	/* test 6 */
+	dim = isl_space_set_alloc(ctx, 0, 3);
+	bset = isl_basic_set_universe(isl_space_copy(dim));
+	ls = isl_local_space_from_space(dim);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 6);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 2, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 1, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 2, 1);
+
+	assert(bset && bset->n_div == 1);
+	isl_basic_set_free(bset);
+	isl_local_space_free(ls);
+
+	/* test 7 */
+	/* This test is a bit tricky.  We set up an equality
+	 *		a + 3b + 3c = 6 e0
+	 * Normalization of divs creates _two_ divs
+	 *		a = 3 e0
+	 *		c - b - e0 = 2 e1
+	 * Afterwards e0 is removed again because it has coefficient -1
+	 * and we end up with the original equality and div again.
+	 * Perhaps we can avoid the introduction of this temporary div.
+	 */
+	dim = isl_space_set_alloc(ctx, 0, 4);
+	bset = isl_basic_set_universe(isl_space_copy(dim));
+	ls = isl_local_space_from_space(dim);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 1, v);
+	isl_int_set_si(v, -3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 2, v);
+	isl_int_set_si(v, 6);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 3, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 3, 1);
+
+	/* Test disabled for now */
+	/*
+	assert(bset && bset->n_div == 1);
+	*/
+	isl_local_space_free(ls);
+	isl_basic_set_free(bset);
+
+	/* test 8 */
+	dim = isl_space_set_alloc(ctx, 0, 5);
+	bset = isl_basic_set_universe(isl_space_copy(dim));
+	ls = isl_local_space_from_space(dim);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 1, v);
+	isl_int_set_si(v, -3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 3, v);
+	isl_int_set_si(v, 6);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 4, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 2, v);
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_constant(c, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 4, 1);
+
+	/* Test disabled for now */
+	/*
+	assert(bset && bset->n_div == 1);
+	*/
+	isl_local_space_free(ls);
+	isl_basic_set_free(bset);
+
+	/* test 9 */
+	dim = isl_space_set_alloc(ctx, 0, 4);
+	bset = isl_basic_set_universe(isl_space_copy(dim));
+	ls = isl_local_space_from_space(dim);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 1, v);
+	isl_int_set_si(v, -2);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 2, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, -1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 3, v);
+	isl_int_set_si(v, 2);
+	c = isl_constraint_set_constant(c, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 2, 2);
+
+	bset = isl_basic_set_fix_si(bset, isl_dim_set, 0, 2);
+
+	assert(!isl_basic_set_is_empty(bset));
+
+	isl_local_space_free(ls);
+	isl_basic_set_free(bset);
+
+	/* test 10 */
+	dim = isl_space_set_alloc(ctx, 0, 3);
+	bset = isl_basic_set_universe(isl_space_copy(dim));
+	ls = isl_local_space_from_space(dim);
+
+	c = isl_constraint_alloc_equality(isl_local_space_copy(ls));
+	isl_int_set_si(v, 1);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -2);
+	c = isl_constraint_set_coefficient(c, isl_dim_set, 2, v);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 2, 1);
+
+	bset = isl_basic_set_fix_si(bset, isl_dim_set, 0, 2);
+
+	isl_local_space_free(ls);
+	isl_basic_set_free(bset);
+
+	isl_int_clear(v);
+
+	str = "{ [i] : exists (e0, e1: 3e1 >= 1 + 2e0 and "
+	    "8e1 <= -1 + 5i - 5e0 and 2e1 >= 1 + 2i - 5e0) }";
+	set = isl_set_read_from_str(ctx, str);
+	set = isl_set_compute_divs(set);
+	isl_set_free(set);
+	if (!set)
+		return -1;
+
+	if (test_elimination(ctx) < 0)
+		return -1;
+
+	str = "{ [i,j,k] : 3 + i + 2j >= 0 and 2 * [(i+2j)/4] <= k }";
+	set = isl_set_read_from_str(ctx, str);
+	set = isl_set_remove_divs_involving_dims(set, isl_dim_set, 0, 2);
+	set = isl_set_fix_si(set, isl_dim_set, 2, -3);
+	empty = isl_set_is_empty(set);
+	isl_set_free(set);
+	if (empty < 0)
+		return -1;
+	if (!empty)
+		isl_die(ctx, isl_error_unknown,
+			"result not as accurate as expected", return -1);
+
+	return 0;
+}
+
+void test_application_case(struct isl_ctx *ctx, const char *name)
+{
+	char *filename;
+	FILE *input;
+	struct isl_basic_set *bset1, *bset2;
+	struct isl_basic_map *bmap;
+
+	filename = get_filename(ctx, name, "omega");
+	assert(filename);
+	input = fopen(filename, "r");
+	assert(input);
+
+	bset1 = isl_basic_set_read_from_file(ctx, input);
+	bmap = isl_basic_map_read_from_file(ctx, input);
+
+	bset1 = isl_basic_set_apply(bset1, bmap);
+
+	bset2 = isl_basic_set_read_from_file(ctx, input);
+
+	assert(isl_basic_set_is_equal(bset1, bset2) == 1);
+
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	free(filename);
+
+	fclose(input);
+}
+
+static int test_application(isl_ctx *ctx)
+{
+	test_application_case(ctx, "application");
+	test_application_case(ctx, "application2");
+
+	return 0;
+}
+
+void test_affine_hull_case(struct isl_ctx *ctx, const char *name)
+{
+	char *filename;
+	FILE *input;
+	struct isl_basic_set *bset1, *bset2;
+
+	filename = get_filename(ctx, name, "polylib");
+	assert(filename);
+	input = fopen(filename, "r");
+	assert(input);
+
+	bset1 = isl_basic_set_read_from_file(ctx, input);
+	bset2 = isl_basic_set_read_from_file(ctx, input);
+
+	bset1 = isl_basic_set_affine_hull(bset1);
+
+	assert(isl_basic_set_is_equal(bset1, bset2) == 1);
+
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	free(filename);
+
+	fclose(input);
+}
+
+int test_affine_hull(struct isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *set;
+	isl_basic_set *bset, *bset2;
+	int n;
+	int subset;
+
+	test_affine_hull_case(ctx, "affine2");
+	test_affine_hull_case(ctx, "affine");
+	test_affine_hull_case(ctx, "affine3");
+
+	str = "[m] -> { [i0] : exists (e0, e1: e1 <= 1 + i0 and "
+			"m >= 3 and 4i0 <= 2 + m and e1 >= i0 and "
+			"e1 >= 0 and e1 <= 2 and e1 >= 1 + 2e0 and "
+			"2e1 <= 1 + m + 4e0 and 2e1 >= 2 - m + 4i0 - 4e0) }";
+	set = isl_set_read_from_str(ctx, str);
+	bset = isl_set_affine_hull(set);
+	n = isl_basic_set_dim(bset, isl_dim_div);
+	isl_basic_set_free(bset);
+	if (n != 0)
+		isl_die(ctx, isl_error_unknown, "not expecting any divs",
+			return -1);
+
+	/* Check that isl_map_affine_hull is not confused by
+	 * the reordering of divs in isl_map_align_divs.
+	 */
+	str = "{ [a, b, c, 0] : exists (e0 = [(b)/32], e1 = [(c)/32]: "
+				"32e0 = b and 32e1 = c); "
+		"[a, 0, c, 0] : exists (e0 = [(c)/32]: 32e0 = c) }";
+	set = isl_set_read_from_str(ctx, str);
+	bset = isl_set_affine_hull(set);
+	isl_basic_set_free(bset);
+	if (!bset)
+		return -1;
+
+	str = "{ [a] : exists e0, e1, e2: 32e1 = 31 + 31a + 31e0 and "
+			"32e2 = 31 + 31e0 }";
+	set = isl_set_read_from_str(ctx, str);
+	bset = isl_set_affine_hull(set);
+	str = "{ [a] : exists e : a = 32 e }";
+	bset2 = isl_basic_set_read_from_str(ctx, str);
+	subset = isl_basic_set_is_subset(bset, bset2);
+	isl_basic_set_free(bset);
+	isl_basic_set_free(bset2);
+	if (subset < 0)
+		return -1;
+	if (!subset)
+		isl_die(ctx, isl_error_unknown, "not as accurate as expected",
+			return -1);
+
+	return 0;
+}
+
+/* Pairs of maps and the corresponding expected results of
+ * isl_map_plain_unshifted_simple_hull.
+ */
+struct {
+	const char *map;
+	const char *hull;
+} plain_unshifted_simple_hull_tests[] = {
+	{ "{ [i] -> [j] : i >= 1 and j >= 1 or i >= 2 and j <= 10 }",
+	  "{ [i] -> [j] : i >= 1 }" },
+	{ "{ [n] -> [i,j,k] : (i mod 3 = 2 and j mod 4 = 2) or "
+		"(j mod 4 = 2 and k mod 6 = n) }",
+	  "{ [n] -> [i,j,k] : j mod 4 = 2 }" },
+};
+
+/* Basic tests for isl_map_plain_unshifted_simple_hull.
+ */
+static int test_plain_unshifted_simple_hull(isl_ctx *ctx)
+{
+	int i;
+	isl_map *map;
+	isl_basic_map *hull, *expected;
+	isl_bool equal;
+
+	for (i = 0; i < ARRAY_SIZE(plain_unshifted_simple_hull_tests); ++i) {
+		const char *str;
+		str = plain_unshifted_simple_hull_tests[i].map;
+		map = isl_map_read_from_str(ctx, str);
+		str = plain_unshifted_simple_hull_tests[i].hull;
+		expected = isl_basic_map_read_from_str(ctx, str);
+		hull = isl_map_plain_unshifted_simple_hull(map);
+		equal = isl_basic_map_is_equal(hull, expected);
+		isl_basic_map_free(hull);
+		isl_basic_map_free(expected);
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown, "unexpected hull",
+				return -1);
+	}
+
+	return 0;
+}
+
+/* Pairs of sets and the corresponding expected results of
+ * isl_set_unshifted_simple_hull.
+ */
+struct {
+	const char *set;
+	const char *hull;
+} unshifted_simple_hull_tests[] = {
+	{ "{ [0,x,y] : x <= -1; [1,x,y] : x <= y <= -x; [2,x,y] : x <= 1 }",
+	  "{ [t,x,y] : 0 <= t <= 2 and x <= 1 }" },
+};
+
+/* Basic tests for isl_set_unshifted_simple_hull.
+ */
+static int test_unshifted_simple_hull(isl_ctx *ctx)
+{
+	int i;
+	isl_set *set;
+	isl_basic_set *hull, *expected;
+	isl_bool equal;
+
+	for (i = 0; i < ARRAY_SIZE(unshifted_simple_hull_tests); ++i) {
+		const char *str;
+		str = unshifted_simple_hull_tests[i].set;
+		set = isl_set_read_from_str(ctx, str);
+		str = unshifted_simple_hull_tests[i].hull;
+		expected = isl_basic_set_read_from_str(ctx, str);
+		hull = isl_set_unshifted_simple_hull(set);
+		equal = isl_basic_set_is_equal(hull, expected);
+		isl_basic_set_free(hull);
+		isl_basic_set_free(expected);
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown, "unexpected hull",
+				return -1);
+	}
+
+	return 0;
+}
+
+static int test_simple_hull(struct isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *set;
+	isl_basic_set *bset;
+	isl_bool is_empty;
+
+	str = "{ [x, y] : 3y <= 2x and y >= -2 + 2x and 2y >= 2 - x;"
+		"[y, x] : 3y <= 2x and y >= -2 + 2x and 2y >= 2 - x }";
+	set = isl_set_read_from_str(ctx, str);
+	bset = isl_set_simple_hull(set);
+	is_empty = isl_basic_set_is_empty(bset);
+	isl_basic_set_free(bset);
+
+	if (is_empty == isl_bool_error)
+		return -1;
+
+	if (is_empty == isl_bool_false)
+		isl_die(ctx, isl_error_unknown, "Empty set should be detected",
+			return -1);
+
+	if (test_plain_unshifted_simple_hull(ctx) < 0)
+		return -1;
+	if (test_unshifted_simple_hull(ctx) < 0)
+		return -1;
+
+	return 0;
+}
+
+void test_convex_hull_case(struct isl_ctx *ctx, const char *name)
+{
+	char *filename;
+	FILE *input;
+	struct isl_basic_set *bset1, *bset2;
+	struct isl_set *set;
+
+	filename = get_filename(ctx, name, "polylib");
+	assert(filename);
+	input = fopen(filename, "r");
+	assert(input);
+
+	bset1 = isl_basic_set_read_from_file(ctx, input);
+	bset2 = isl_basic_set_read_from_file(ctx, input);
+
+	set = isl_basic_set_union(bset1, bset2);
+	bset1 = isl_set_convex_hull(set);
+
+	bset2 = isl_basic_set_read_from_file(ctx, input);
+
+	assert(isl_basic_set_is_equal(bset1, bset2) == 1);
+
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	free(filename);
+
+	fclose(input);
+}
+
+struct {
+	const char *set;
+	const char *hull;
+} convex_hull_tests[] = {
+	{ "{ [i0, i1, i2] : (i2 = 1 and i0 = 0 and i1 >= 0) or "
+	       "(i0 = 1 and i1 = 0 and i2 = 1) or "
+	       "(i0 = 0 and i1 = 0 and i2 = 0) }",
+	  "{ [i0, i1, i2] : i0 >= 0 and i2 >= i0 and i2 <= 1 and i1 >= 0 }" },
+	{ "[n] -> { [i0, i1, i0] : i0 <= -4 + n; "
+	    "[i0, i0, i2] : n = 6 and i0 >= 0 and i2 <= 7 - i0 and "
+	    "i2 <= 5 and i2 >= 4; "
+	    "[3, i1, 3] : n = 5 and i1 <= 2 and i1 >= 0 }",
+	  "[n] -> { [i0, i1, i2] : i2 <= -1 + n and 2i2 <= -6 + 3n - i0 and "
+	    "i2 <= 5 + i0 and i2 >= i0 }" },
+	{ "{ [x, y] : 3y <= 2x and y >= -2 + 2x and 2y >= 2 - x }",
+	    "{ [x, y] : 1 = 0 }" },
+	{ "{ [x, y, z] : 0 <= x, y, z <= 10; [x, y, 0] : x >= 0 and y > 0; "
+	    "[x, y, 0] : x >= 0 and y < 0 }",
+	    "{ [x, y, z] : x >= 0 and 0 <= z <= 10 }" },
+};
+
+static int test_convex_hull_algo(isl_ctx *ctx, int convex)
+{
+	int i;
+	int orig_convex = ctx->opt->convex;
+	ctx->opt->convex = convex;
+
+	test_convex_hull_case(ctx, "convex0");
+	test_convex_hull_case(ctx, "convex1");
+	test_convex_hull_case(ctx, "convex2");
+	test_convex_hull_case(ctx, "convex3");
+	test_convex_hull_case(ctx, "convex4");
+	test_convex_hull_case(ctx, "convex5");
+	test_convex_hull_case(ctx, "convex6");
+	test_convex_hull_case(ctx, "convex7");
+	test_convex_hull_case(ctx, "convex8");
+	test_convex_hull_case(ctx, "convex9");
+	test_convex_hull_case(ctx, "convex10");
+	test_convex_hull_case(ctx, "convex11");
+	test_convex_hull_case(ctx, "convex12");
+	test_convex_hull_case(ctx, "convex13");
+	test_convex_hull_case(ctx, "convex14");
+	test_convex_hull_case(ctx, "convex15");
+
+	for (i = 0; i < ARRAY_SIZE(convex_hull_tests); ++i) {
+		isl_set *set1, *set2;
+		int equal;
+
+		set1 = isl_set_read_from_str(ctx, convex_hull_tests[i].set);
+		set2 = isl_set_read_from_str(ctx, convex_hull_tests[i].hull);
+		set1 = isl_set_from_basic_set(isl_set_convex_hull(set1));
+		equal = isl_set_is_equal(set1, set2);
+		isl_set_free(set1);
+		isl_set_free(set2);
+
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown,
+				"unexpected convex hull", return -1);
+	}
+
+	ctx->opt->convex = orig_convex;
+
+	return 0;
+}
+
+static int test_convex_hull(isl_ctx *ctx)
+{
+	if (test_convex_hull_algo(ctx, ISL_CONVEX_HULL_FM) < 0)
+		return -1;
+	if (test_convex_hull_algo(ctx, ISL_CONVEX_HULL_WRAP) < 0)
+		return -1;
+	return 0;
+}
+
+void test_gist_case(struct isl_ctx *ctx, const char *name)
+{
+	char *filename;
+	FILE *input;
+	struct isl_basic_set *bset1, *bset2;
+
+	filename = get_filename(ctx, name, "polylib");
+	assert(filename);
+	input = fopen(filename, "r");
+	assert(input);
+
+	bset1 = isl_basic_set_read_from_file(ctx, input);
+	bset2 = isl_basic_set_read_from_file(ctx, input);
+
+	bset1 = isl_basic_set_gist(bset1, bset2);
+
+	bset2 = isl_basic_set_read_from_file(ctx, input);
+
+	assert(isl_basic_set_is_equal(bset1, bset2) == 1);
+
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	free(filename);
+
+	fclose(input);
+}
+
+/* Inputs to isl_map_plain_gist_basic_map, along with the expected output.
+ */
+struct {
+	const char *map;
+	const char *context;
+	const char *gist;
+} plain_gist_tests[] = {
+	{ "{ [i] -> [j] : i >= 1 and j >= 1 or i >= 2 and j <= 10 }",
+	  "{ [i] -> [j] : i >= 1 }",
+	  "{ [i] -> [j] : j >= 1 or i >= 2 and j <= 10 }" },
+	{ "{ [n] -> [i,j,k] : (i mod 3 = 2 and j mod 4 = 2) or "
+		"(j mod 4 = 2 and k mod 6 = n) }",
+	  "{ [n] -> [i,j,k] : j mod 4 = 2 }",
+	  "{ [n] -> [i,j,k] : (i mod 3 = 2) or (k mod 6 = n) }" },
+	{ "{ [i] -> [j] : i > j and (exists a,b : i <= 2a + 5b <= 2) }",
+	  "{ [i] -> [j] : i > j }",
+	  "{ [i] -> [j] : exists a,b : i <= 2a + 5b <= 2 }" },
+};
+
+/* Basic tests for isl_map_plain_gist_basic_map.
+ */
+static int test_plain_gist(isl_ctx *ctx)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(plain_gist_tests); ++i) {
+		const char *str;
+		int equal;
+		isl_map *map, *gist;
+		isl_basic_map *context;
+
+		map = isl_map_read_from_str(ctx, plain_gist_tests[i].map);
+		str = plain_gist_tests[i].context;
+		context = isl_basic_map_read_from_str(ctx, str);
+		map = isl_map_plain_gist_basic_map(map, context);
+		gist = isl_map_read_from_str(ctx, plain_gist_tests[i].gist);
+		equal = isl_map_is_equal(map, gist);
+		isl_map_free(map);
+		isl_map_free(gist);
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown,
+				"incorrect gist result", return -1);
+	}
+
+	return 0;
+}
+
+struct {
+	const char *set;
+	const char *context;
+	const char *gist;
+} gist_tests[] = {
+	{ "{ [a, b, c] : a <= 15 and a >= 1 }",
+	  "{ [a, b, c] : exists (e0 = floor((-1 + a)/16): a >= 1 and "
+			"c <= 30 and 32e0 >= -62 + 2a + 2b - c and b >= 0) }",
+	  "{ [a, b, c] : a <= 15 }" },
+	{ "{ : }", "{ : 1 = 0 }", "{ : }" },
+	{ "{ : 1 = 0 }", "{ : 1 = 0 }", "{ : }" },
+	{ "[M] -> { [x] : exists (e0 = floor((-2 + x)/3): 3e0 = -2 + x) }",
+	  "[M] -> { [3M] }" , "[M] -> { [x] : 1 = 0 }" },
+	{ "{ [m, n, a, b] : a <= 2147 + n }",
+	  "{ [m, n, a, b] : (m >= 1 and n >= 1 and a <= 2148 - m and "
+			"b <= 2148 - n and b >= 0 and b >= 2149 - n - a) or "
+			"(n >= 1 and a >= 0 and b <= 2148 - n - a and "
+			"b >= 0) }",
+	  "{ [m, n, ku, kl] }" },
+	{ "{ [a, a, b] : a >= 10 }",
+	  "{ [a, b, c] : c >= a and c <= b and c >= 2 }",
+	  "{ [a, a, b] : a >= 10 }" },
+	{ "{ [i, j] : i >= 0 and i + j >= 0 }", "{ [i, j] : i <= 0 }",
+	  "{ [0, j] : j >= 0 }" },
+	/* Check that no constraints on i6 are introduced in the gist */
+	{ "[t1] -> { [i4, i6] : exists (e0 = floor((1530 - 4t1 - 5i4)/20): "
+		"20e0 <= 1530 - 4t1 - 5i4 and 20e0 >= 1511 - 4t1 - 5i4 and "
+		"5e0 <= 381 - t1 and i4 <= 1) }",
+	  "[t1] -> { [i4, i6] : exists (e0 = floor((-t1 + i6)/5): "
+		"5e0 = -t1 + i6 and i6 <= 6 and i6 >= 3) }",
+	  "[t1] -> { [i4, i6] : exists (e0 = floor((1530 - 4t1 - 5i4)/20): "
+		"i4 <= 1 and 5e0 <= 381 - t1 and 20e0 <= 1530 - 4t1 - 5i4 and "
+		"20e0 >= 1511 - 4t1 - 5i4) }" },
+	/* Check that no constraints on i6 are introduced in the gist */
+	{ "[t1, t2] -> { [i4, i5, i6] : exists (e0 = floor((1 + i4)/2), "
+		"e1 = floor((1530 - 4t1 - 5i4)/20), "
+		"e2 = floor((-4t1 - 5i4 + 10*floor((1 + i4)/2))/20), "
+		"e3 = floor((-1 + i4)/2): t2 = 0 and 2e3 = -1 + i4 and "
+			"20e2 >= -19 - 4t1 - 5i4 + 10e0 and 5e2 <= 1 - t1 and "
+			"2e0 <= 1 + i4 and 2e0 >= i4 and "
+			"20e1 <= 1530 - 4t1 - 5i4 and "
+			"20e1 >= 1511 - 4t1 - 5i4 and i4 <= 1 and "
+			"5e1 <= 381 - t1 and 20e2 <= -4t1 - 5i4 + 10e0) }",
+	  "[t1, t2] -> { [i4, i5, i6] : exists (e0 = floor((-17 + i4)/2), "
+		"e1 = floor((-t1 + i6)/5): 5e1 = -t1 + i6 and "
+			"2e0 <= -17 + i4 and 2e0 >= -18 + i4 and "
+			"10e0 <= -91 + 5i4 + 4i6 and "
+			"10e0 >= -105 + 5i4 + 4i6) }",
+	  "[t1, t2] -> { [i4, i5, i6] : exists (e0 = floor((381 - t1)/5), "
+		"e1 = floor((-1 + i4)/2): t2 = 0 and 2e1 = -1 + i4 and "
+		"i4 <= 1 and 5e0 <= 381 - t1 and 20e0 >= 1511 - 4t1 - 5i4) }" },
+	{ "{ [0, 0, q, p] : -5 <= q <= 5 and p >= 0 }",
+	  "{ [a, b, q, p] : b >= 1 + a }",
+	  "{ [a, b, q, p] : false }" },
+	{ "[n] -> { [x] : x = n && x mod 32 = 0 }",
+	  "[n] -> { [x] : x mod 32 = 0 }",
+	  "[n] -> { [x = n] }" },
+	{ "{ [x] : x mod 6 = 0 }", "{ [x] : x mod 3 = 0 }",
+	  "{ [x] : x mod 2 = 0 }" },
+	{ "{ [x] : x mod 3200 = 0 }", "{ [x] : x mod 10000 = 0 }",
+	  "{ [x] : x mod 128 = 0 }" },
+	{ "{ [x] : x mod 3200 = 0 }", "{ [x] : x mod 10 = 0 }",
+	  "{ [x] : x mod 3200 = 0 }" },
+	{ "{ [a, b, c] : a mod 2 = 0 and a = c }",
+	  "{ [a, b, c] : b mod 2 = 0 and b = c }",
+	  "{ [a, b, c = a] }" },
+	{ "{ [a, b, c] : a mod 6 = 0 and a = c }",
+	  "{ [a, b, c] : b mod 2 = 0 and b = c }",
+	  "{ [a, b, c = a] : a mod 3 = 0 }" },
+	{ "{ [x] : 0 <= x <= 4 or 6 <= x <= 9 }",
+	  "{ [x] : 1 <= x <= 3 or 7 <= x <= 8 }",
+	  "{ [x] }" },
+	{ "{ [x,y] : x < 0 and 0 <= y <= 4 or x >= -2 and -x <= y <= 10 + x }",
+	  "{ [x,y] : 1 <= y <= 3 }",
+	  "{ [x,y] }" },
+};
+
+/* Check that isl_set_gist behaves as expected.
+ *
+ * For the test cases in gist_tests, besides checking that the result
+ * is as expected, also check that applying the gist operation does
+ * not modify the input set (an earlier version of isl would do that) and
+ * that the test case is consistent, i.e., that the gist has the same
+ * intersection with the context as the input set.
+ */
+static int test_gist(struct isl_ctx *ctx)
+{
+	int i;
+	const char *str;
+	isl_basic_set *bset1, *bset2;
+	isl_map *map1, *map2;
+	int equal;
+
+	for (i = 0; i < ARRAY_SIZE(gist_tests); ++i) {
+		int equal_input, equal_intersection;
+		isl_set *set1, *set2, *copy, *context;
+
+		set1 = isl_set_read_from_str(ctx, gist_tests[i].set);
+		context = isl_set_read_from_str(ctx, gist_tests[i].context);
+		copy = isl_set_copy(set1);
+		set1 = isl_set_gist(set1, isl_set_copy(context));
+		set2 = isl_set_read_from_str(ctx, gist_tests[i].gist);
+		equal = isl_set_is_equal(set1, set2);
+		isl_set_free(set1);
+		set1 = isl_set_read_from_str(ctx, gist_tests[i].set);
+		equal_input = isl_set_is_equal(set1, copy);
+		isl_set_free(copy);
+		set1 = isl_set_intersect(set1, isl_set_copy(context));
+		set2 = isl_set_intersect(set2, context);
+		equal_intersection = isl_set_is_equal(set1, set2);
+		isl_set_free(set2);
+		isl_set_free(set1);
+		if (equal < 0 || equal_input < 0 || equal_intersection < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown,
+				"incorrect gist result", return -1);
+		if (!equal_input)
+			isl_die(ctx, isl_error_unknown,
+				"gist modified input", return -1);
+		if (!equal_input)
+			isl_die(ctx, isl_error_unknown,
+				"inconsistent gist test case", return -1);
+	}
+
+	test_gist_case(ctx, "gist1");
+
+	str = "[p0, p2, p3, p5, p6, p10] -> { [] : "
+	    "exists (e0 = [(15 + p0 + 15p6 + 15p10)/16], e1 = [(p5)/8], "
+	    "e2 = [(p6)/128], e3 = [(8p2 - p5)/128], "
+	    "e4 = [(128p3 - p6)/4096]: 8e1 = p5 and 128e2 = p6 and "
+	    "128e3 = 8p2 - p5 and 4096e4 = 128p3 - p6 and p2 >= 0 and "
+	    "16e0 >= 16 + 16p6 + 15p10 and  p2 <= 15 and p3 >= 0 and "
+	    "p3 <= 31 and  p6 >= 128p3 and p5 >= 8p2 and p10 >= 0 and "
+	    "16e0 <= 15 + p0 + 15p6 + 15p10 and 16e0 >= p0 + 15p6 + 15p10 and "
+	    "p10 <= 15 and p10 <= -1 + p0 - p6) }";
+	bset1 = isl_basic_set_read_from_str(ctx, str);
+	str = "[p0, p2, p3, p5, p6, p10] -> { [] : exists (e0 = [(p5)/8], "
+	    "e1 = [(p6)/128], e2 = [(8p2 - p5)/128], "
+	    "e3 = [(128p3 - p6)/4096]: 8e0 = p5 and 128e1 = p6 and "
+	    "128e2 = 8p2 - p5 and 4096e3 = 128p3 - p6 and p5 >= -7 and "
+	    "p2 >= 0 and 8p2 <= -1 + p0 and p2 <= 15 and p3 >= 0 and "
+	    "p3 <= 31 and 128p3 <= -1 + p0 and p6 >= -127 and "
+	    "p5 <= -1 + p0 and p6 <= -1 + p0 and p6 >= 128p3 and "
+	    "p0 >= 1 and p5 >= 8p2 and p10 >= 0 and p10 <= 15 ) }";
+	bset2 = isl_basic_set_read_from_str(ctx, str);
+	bset1 = isl_basic_set_gist(bset1, bset2);
+	assert(bset1 && bset1->n_div == 0);
+	isl_basic_set_free(bset1);
+
+	/* Check that the integer divisions of the second disjunct
+	 * do not spread to the first disjunct.
+	 */
+	str = "[t1] -> { S_0[] -> A[o0] : (exists (e0 = [(-t1 + o0)/16]: "
+		"16e0 = -t1 + o0 and o0 >= 0 and o0 <= 15 and t1 >= 0)) or "
+		"(exists (e0 = [(-1 + t1)/16], "
+			"e1 = [(-16 + t1 - 16e0)/4294967296]: "
+			"4294967296e1 = -16 + t1 - o0 - 16e0 and "
+			"16e0 <= -1 + t1 and 16e0 >= -16 + t1 and o0 >= 0 and "
+			"o0 <= 4294967295 and t1 <= -1)) }";
+	map1 = isl_map_read_from_str(ctx, str);
+	str = "[t1] -> { S_0[] -> A[o0] : t1 >= 0 and t1 <= 4294967295 }";
+	map2 = isl_map_read_from_str(ctx, str);
+	map1 = isl_map_gist(map1, map2);
+	if (!map1)
+		return -1;
+	if (map1->n != 1)
+		isl_die(ctx, isl_error_unknown, "expecting single disjunct",
+			isl_map_free(map1); return -1);
+	if (isl_basic_map_dim(map1->p[0], isl_dim_div) != 1)
+		isl_die(ctx, isl_error_unknown, "expecting single div",
+			isl_map_free(map1); return -1);
+	isl_map_free(map1);
+
+	if (test_plain_gist(ctx) < 0)
+		return -1;
+
+	return 0;
+}
+
+int test_coalesce_set(isl_ctx *ctx, const char *str, int check_one)
+{
+	isl_set *set, *set2;
+	int equal;
+	int one;
+
+	set = isl_set_read_from_str(ctx, str);
+	set = isl_set_coalesce(set);
+	set2 = isl_set_read_from_str(ctx, str);
+	equal = isl_set_is_equal(set, set2);
+	one = set && set->n == 1;
+	isl_set_free(set);
+	isl_set_free(set2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"coalesced set not equal to input", return -1);
+	if (check_one && !one)
+		isl_die(ctx, isl_error_unknown,
+			"coalesced set should not be a union", return -1);
+
+	return 0;
+}
+
+/* Inputs for coalescing tests with unbounded wrapping.
+ * "str" is a string representation of the input set.
+ * "single_disjunct" is set if we expect the result to consist of
+ *	a single disjunct.
+ */
+struct {
+	int single_disjunct;
+	const char *str;
+} coalesce_unbounded_tests[] = {
+	{ 1, "{ [x,y,z] : y + 2 >= 0 and x - y + 1 >= 0 and "
+			"-x - y + 1 >= 0 and -3 <= z <= 3;"
+		"[x,y,z] : -x+z + 20 >= 0 and -x-z + 20 >= 0 and "
+			"x-z + 20 >= 0 and x+z + 20 >= 0 and "
+			"-10 <= y <= 0}" },
+	{ 1, "{ [x,y] : 0 <= x,y <= 10; [5,y]: 4 <= y <= 11 }" },
+	{ 1, "{ [x,0,0] : -5 <= x <= 5; [0,y,1] : -5 <= y <= 5 }" },
+	{ 1, "{ [x,y] : 0 <= x <= 10 and 0 >= y >= -1 and x+y >= 0; [0,1] }" },
+	{ 1, "{ [x,y] : (0 <= x,y <= 4) or (2 <= x,y <= 5 and x + y <= 9) }" },
+};
+
+/* Test the functionality of isl_set_coalesce with the bounded wrapping
+ * option turned off.
+ */
+int test_coalesce_unbounded_wrapping(isl_ctx *ctx)
+{
+	int i;
+	int r = 0;
+	int bounded;
+
+	bounded = isl_options_get_coalesce_bounded_wrapping(ctx);
+	isl_options_set_coalesce_bounded_wrapping(ctx, 0);
+
+	for (i = 0; i < ARRAY_SIZE(coalesce_unbounded_tests); ++i) {
+		const char *str = coalesce_unbounded_tests[i].str;
+		int check_one = coalesce_unbounded_tests[i].single_disjunct;
+		if (test_coalesce_set(ctx, str, check_one) >= 0)
+			continue;
+		r = -1;
+		break;
+	}
+
+	isl_options_set_coalesce_bounded_wrapping(ctx, bounded);
+
+	return r;
+}
+
+/* Inputs for coalescing tests.
+ * "str" is a string representation of the input set.
+ * "single_disjunct" is set if we expect the result to consist of
+ *	a single disjunct.
+ */
+struct {
+	int single_disjunct;
+	const char *str;
+} coalesce_tests[] = {
+	{ 1, "{[x,y]: x >= 0 & x <= 10 & y >= 0 & y <= 10 or "
+		       "y >= x & x >= 2 & 5 >= y }" },
+	{ 1, "{[x,y]: y >= 0 & 2x + y <= 30 & y <= 10 & x >= 0 or "
+		       "x + y >= 10 & y <= x & x + y <= 20 & y >= 0}" },
+	{ 0, "{[x,y]: y >= 0 & 2x + y <= 30 & y <= 10 & x >= 0 or "
+		       "x + y >= 10 & y <= x & x + y <= 19 & y >= 0}" },
+	{ 1, "{[x,y]: y >= 0 & x <= 5 & y <= x or "
+		       "y >= 0 & x >= 6 & x <= 10 & y <= x}" },
+	{ 0, "{[x,y]: y >= 0 & x <= 5 & y <= x or "
+		       "y >= 0 & x >= 7 & x <= 10 & y <= x}" },
+	{ 0, "{[x,y]: y >= 0 & x <= 5 & y <= x or "
+		       "y >= 0 & x >= 6 & x <= 10 & y + 1 <= x}" },
+	{ 1, "{[x,y]: y >= 0 & x <= 5 & y <= x or y >= 0 & x = 6 & y <= 6}" },
+	{ 0, "{[x,y]: y >= 0 & x <= 5 & y <= x or y >= 0 & x = 7 & y <= 6}" },
+	{ 1, "{[x,y]: y >= 0 & x <= 5 & y <= x or y >= 0 & x = 6 & y <= 5}" },
+	{ 0, "{[x,y]: y >= 0 & x <= 5 & y <= x or y >= 0 & x = 6 & y <= 7}" },
+	{ 1, "[n] -> { [i] : i = 1 and n >= 2 or 2 <= i and i <= n }" },
+	{ 0, "{[x,y] : x >= 0 and y >= 0 or 0 <= y and y <= 5 and x = -1}" },
+	{ 1, "[n] -> { [i] : 1 <= i and i <= n - 1 or 2 <= i and i <= n }" },
+	{ 0, "[n] -> { [[i0] -> [o0]] : exists (e0 = [(i0)/4], e1 = [(o0)/4], "
+		"e2 = [(n)/2], e3 = [(-2 + i0)/4], e4 = [(-2 + o0)/4], "
+		"e5 = [(-2n + i0)/4]: 2e2 = n and 4e3 = -2 + i0 and "
+		"4e4 = -2 + o0 and i0 >= 8 + 2n and o0 >= 2 + i0 and "
+		"o0 <= 56 + 2n and o0 <= -12 + 4n and i0 <= 57 + 2n and "
+		"i0 <= -11 + 4n and o0 >= 6 + 2n and 4e0 <= i0 and "
+		"4e0 >= -3 + i0 and 4e1 <= o0 and 4e1 >= -3 + o0 and "
+		"4e5 <= -2n + i0 and 4e5 >= -3 - 2n + i0);"
+		"[[i0] -> [o0]] : exists (e0 = [(i0)/4], e1 = [(o0)/4], "
+		"e2 = [(n)/2], e3 = [(-2 + i0)/4], e4 = [(-2 + o0)/4], "
+		"e5 = [(-2n + i0)/4]: 2e2 = n and 4e3 = -2 + i0 and "
+		"4e4 = -2 + o0 and 2e0 >= 3 + n and e0 <= -4 + n and "
+		"2e0 <= 27 + n and e1 <= -4 + n and 2e1 <= 27 + n and "
+		"2e1 >= 2 + n and e1 >= 1 + e0 and i0 >= 7 + 2n and "
+		"i0 <= -11 + 4n and i0 <= 57 + 2n and 4e0 <= -2 + i0 and "
+		"4e0 >= -3 + i0 and o0 >= 6 + 2n and o0 <= -11 + 4n and "
+		"o0 <= 57 + 2n and 4e1 <= -2 + o0 and 4e1 >= -3 + o0 and "
+		"4e5 <= -2n + i0 and 4e5 >= -3 - 2n + i0 ) }" },
+	{ 0, "[n, m] -> { [o0, o2, o3] : (o3 = 1 and o0 >= 1 + m and "
+	      "o0 <= n + m and o2 <= m and o0 >= 2 + n and o2 >= 3) or "
+	      "(o0 >= 2 + n and o0 >= 1 + m and o0 <= n + m and n >= 1 and "
+	      "o3 <= -1 + o2 and o3 >= 1 - m + o2 and o3 >= 2 and o3 <= n) }" },
+	{ 0, "[M, N] -> { [[i0, i1, i2, i3, i4, i5, i6] -> "
+	  "[o0, o1, o2, o3, o4, o5, o6]] : "
+	  "(o6 <= -4 + 2M - 2N + i0 + i1 - i2 + i6 - o0 - o1 + o2 and "
+	  "o3 <= -2 + i3 and o6 >= 2 + i0 + i3 + i6 - o0 - o3 and "
+	  "o6 >= 2 - M + N + i3 + i4 + i6 - o3 - o4 and o0 <= -1 + i0 and "
+	  "o4 >= 4 - 3M + 3N - i0 - i1 + i2 + 2i3 + i4 + o0 + o1 - o2 - 2o3 "
+	  "and o6 <= -3 + 2M - 2N + i3 + i4 - i5 + i6 - o3 - o4 + o5 and "
+	  "2o6 <= -5 + 5M - 5N + 2i0 + i1 - i2 - i5 + 2i6 - 2o0 - o1 + o2 + o5 "
+	  "and o6 >= 2i0 + i1 + i6 - 2o0 - o1 and "
+	  "3o6 <= -5 + 4M - 4N + 2i0 + i1 - i2 + 2i3 + i4 - i5 + 3i6 "
+	  "- 2o0 - o1 + o2 - 2o3 - o4 + o5) or "
+	  "(N >= 2 and o3 <= -1 + i3 and o0 <= -1 + i0 and "
+	  "o6 >= i3 + i6 - o3 and M >= 0 and "
+	  "2o6 >= 1 + i0 + i3 + 2i6 - o0 - o3 and "
+	  "o6 >= 1 - M + i0 + i6 - o0 and N >= 2M and o6 >= i0 + i6 - o0) }" },
+	{ 0, "[M, N] -> { [o0] : (o0 = 0 and M >= 1 and N >= 2) or "
+		"(o0 = 0 and M >= 1 and N >= 2M and N >= 2 + M) or "
+		"(o0 = 0 and M >= 2 and N >= 3) or "
+		"(M = 0 and o0 = 0 and N >= 3) }" },
+	{ 0, "{ [i0, i1, i2, i3] : (i1 = 10i0 and i0 >= 1 and 10i0 <= 100 and "
+	    "i3 <= 9 + 10 i2 and i3 >= 1 + 10i2 and i3 >= 0) or "
+	    "(i1 <= 9 + 10i0 and i1 >= 1 + 10i0 and i2 >= 0 and "
+	    "i0 >= 0 and i1 <= 100 and i3 <= 9 + 10i2 and i3 >= 1 + 10i2) }" },
+	{ 0, "[M] -> { [i1] : (i1 >= 2 and i1 <= M) or (i1 = M and M >= 1) }" },
+	{ 0, "{[x,y] : x,y >= 0; [x,y] : 10 <= x <= 20 and y >= -1 }" },
+	{ 1, "{ [x, y] : (x >= 1 and y >= 1 and x <= 2 and y <= 2) or "
+		"(y = 3 and x = 1) }" },
+	{ 1, "[M] -> { [i0, i1, i2, i3, i4] : (i1 >= 3 and i4 >= 2 + i2 and "
+		"i2 >= 2 and i0 >= 2 and i3 >= 1 + i2 and i0 <= M and "
+		"i1 <= M and i3 <= M and i4 <= M) or "
+		"(i1 >= 2 and i4 >= 1 + i2 and i2 >= 2 and i0 >= 2 and "
+		"i3 >= 1 + i2 and i0 <= M and i1 <= -1 + M and i3 <= M and "
+		"i4 <= -1 + M) }" },
+	{ 1, "{ [x, y] : (x >= 0 and y >= 0 and x <= 10 and y <= 10) or "
+		"(x >= 1 and y >= 1 and x <= 11 and y <= 11) }" },
+	{ 0, "{[x,0] : x >= 0; [x,1] : x <= 20}" },
+	{ 1, "{ [x, 1 - x] : 0 <= x <= 1; [0,0] }" },
+	{ 1, "{ [0,0]; [i,i] : 1 <= i <= 10 }" },
+	{ 0, "{ [0,0]; [i,j] : 1 <= i,j <= 10 }" },
+	{ 1, "{ [0,0]; [i,2i] : 1 <= i <= 10 }" },
+	{ 0, "{ [0,0]; [i,2i] : 2 <= i <= 10 }" },
+	{ 0, "{ [1,0]; [i,2i] : 1 <= i <= 10 }" },
+	{ 0, "{ [0,1]; [i,2i] : 1 <= i <= 10 }" },
+	{ 0, "{ [a, b] : exists e : 2e = a and "
+		    "a >= 0 and (a <= 3 or (b <= 0 and b >= -4 + a)) }" },
+	{ 0, "{ [i, j, i', j'] : i <= 2 and j <= 2 and "
+			"j' >= -1 + 2i + j - 2i' and i' <= -1 + i and "
+			"j >= 1 and j' <= i + j - i' and i >= 1; "
+		"[1, 1, 1, 1] }" },
+	{ 1, "{ [i,j] : exists a,b : i = 2a and j = 3b; "
+		 "[i,j] : exists a : j = 3a }" },
+	{ 1, "{ [a, b, c] : (c <= 7 - b and b <= 1 and b >= 0 and "
+			"c >= 3 + b and b <= 3 + 8a and b >= -26 + 8a and "
+			"a >= 3) or "
+		    "(b <= 1 and c <= 7 and b >= 0 and c >= 4 + b and "
+			"b <= 3 + 8a and b >= -26 + 8a and a >= 3) }" },
+	{ 1, "{ [a, 0, c] : c >= 1 and c <= 29 and c >= -1 + 8a and "
+				"c <= 6 + 8a and a >= 3; "
+		"[a, -1, c] : c >= 1 and c <= 30 and c >= 8a and "
+				"c <= 7 + 8a and a >= 3 and a <= 4 }" },
+	{ 1, "{ [x,y] : 0 <= x <= 2 and y >= 0 and x + 2y <= 4; "
+		"[x,0] : 3 <= x <= 4 }" },
+	{ 1, "{ [x,y] : 0 <= x <= 3 and y >= 0 and x + 3y <= 6; "
+		"[x,0] : 4 <= x <= 5 }" },
+	{ 0, "{ [x,y] : 0 <= x <= 2 and y >= 0 and x + 2y <= 4; "
+		"[x,0] : 3 <= x <= 5 }" },
+	{ 0, "{ [x,y] : 0 <= x <= 2 and y >= 0 and x + y <= 4; "
+		"[x,0] : 3 <= x <= 4 }" },
+	{ 1, "{ [i0, i1] : i0 <= 122 and i0 >= 1 and 128i1 >= -249 + i0 and "
+			"i1 <= 0; "
+		"[i0, 0] : i0 >= 123 and i0 <= 124 }" },
+	{ 1, "{ [0,0]; [1,1] }" },
+	{ 1, "[n] -> { [k] : 16k <= -1 + n and k >= 1; [0] : n >= 2 }" },
+	{ 1, "{ [k, ii, k - ii] : ii >= -6 + k and ii <= 6 and ii >= 1 and "
+				"ii <= k;"
+		"[k, 0, k] : k <= 6 and k >= 1 }" },
+	{ 1, "{ [i,j] : i = 4 j and 0 <= i <= 100;"
+		"[i,j] : 1 <= i <= 100 and i >= 4j + 1 and i <= 4j + 2 }" },
+	{ 1, "{ [x,y] : x % 2 = 0 and y % 2 = 0; [x,x] : x % 2 = 0 }" },
+	{ 1, "[n] -> { [1] : n >= 0;"
+		    "[x] : exists (e0 = floor((x)/2): x >= 2 and "
+			"2e0 >= -1 + x and 2e0 <= x and 2e0 <= n) }" },
+	{ 1, "[n] -> { [x, y] : exists (e0 = floor((x)/2), e1 = floor((y)/3): "
+			"3e1 = y and x >= 2 and 2e0 >= -1 + x and "
+			"2e0 <= x and 2e0 <= n);"
+		    "[1, y] : exists (e0 = floor((y)/3): 3e0 = y and "
+			"n >= 0) }" },
+	{ 1, "[t1] -> { [i0] : (exists (e0 = floor((63t1)/64): "
+				"128e0 >= -134 + 127t1 and t1 >= 2 and "
+				"64e0 <= 63t1 and 64e0 >= -63 + 63t1)) or "
+				"t1 = 1 }" },
+	{ 1, "{ [i, i] : exists (e0 = floor((1 + 2i)/3): 3e0 <= 2i and "
+				"3e0 >= -1 + 2i and i <= 9 and i >= 1);"
+		"[0, 0] }" },
+	{ 1, "{ [t1] : exists (e0 = floor((-11 + t1)/2): 2e0 = -11 + t1 and "
+				"t1 >= 13 and t1 <= 16);"
+		"[t1] : t1 <= 15 and t1 >= 12 }" },
+	{ 1, "{ [x,y] : x = 3y and 0 <= y <= 2; [-3,-1] }" },
+	{ 1, "{ [x,y] : 2x = 3y and 0 <= y <= 4; [-3,-2] }" },
+	{ 0, "{ [x,y] : 2x = 3y and 0 <= y <= 4; [-2,-2] }" },
+	{ 0, "{ [x,y] : 2x = 3y and 0 <= y <= 4; [-3,-1] }" },
+	{ 1, "{ [i] : exists j : i = 4 j and 0 <= i <= 100;"
+		"[i] : exists j : 1 <= i <= 100 and i >= 4j + 1 and "
+				"i <= 4j + 2 }" },
+	{ 1, "{ [c0] : (exists (e0 : c0 - 1 <= 3e0 <= c0)) or "
+		"(exists (e0 : 3e0 = -2 + c0)) }" },
+	{ 0, "[n, b0, t0] -> "
+		"{ [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12] : "
+		"(exists (e0 = floor((-32b0 + i4)/1048576), "
+		"e1 = floor((i8)/32): 1048576e0 = -32b0 + i4 and 32e1 = i8 and "
+		"n <= 2147483647 and b0 <= 32767 and b0 >= 0 and "
+		"32b0 <= -2 + n and t0 <= 31 and t0 >= 0 and i0 >= 8 + n and "
+		"3i4 <= -96 + 3t0 + i0 and 3i4 >= -95 - n + 3t0 + i0 and "
+		"i8 >= -157 + i0 - 4i4 and i8 >= 0 and "
+		"i8 <= -33 + i0 - 4i4 and 3i8 <= -91 + 4n - i0)) or "
+		"(exists (e0 = floor((-32b0 + i4)/1048576), "
+		"e1 = floor((i8)/32): 1048576e0 = -32b0 + i4 and 32e1 = i8 and "
+		"n <= 2147483647 and b0 <= 32767 and b0 >= 0 and "
+		"32b0 <= -2 + n and t0 <= 31 and t0 >= 0 and i0 <= 7 + n and "
+		"4i4 <= -3 + i0 and 3i4 <= -96 + 3t0 + i0 and "
+		"3i4 >= -95 - n + 3t0 + i0 and i8 >= -157 + i0 - 4i4 and "
+		"i8 >= 0 and i8 <= -4 + i0 - 3i4 and i8 <= -41 + i0));"
+		"[i0, i1, i2, i3, 0, i5, i6, i7, i8, i9, i10, i11, i12] : "
+		"(exists (e0 = floor((i8)/32): b0 = 0 and 32e0 = i8 and "
+		"n <= 2147483647 and t0 <= 31 and t0 >= 0 and i0 >= 11 and "
+		"i0 >= 96 - 3t0 and i0 <= 95 + n - 3t0 and i0 <= 7 + n and "
+		"i8 >= -40 + i0 and i8 <= -10 + i0)) }" },
+	{ 0, "{ [i0, i1, i2] : "
+		"(exists (e0, e1 = floor((i0)/32), e2 = floor((i1)/32): "
+		"32e1 = i0 and 32e2 = i1 and i1 >= -31 + i0 and "
+		"i1 <= 31 + i0 and i2 >= -30 + i0 and i2 >= -30 + i1 and "
+		"32e0 >= -30 + i0 and 32e0 >= -30 + i1 and "
+		"32e0 >= -31 + i2 and 32e0 <= 30 + i2 and 32e0 <= 31 + i1 and "
+		"32e0 <= 31 + i0)) or "
+		"i0 >= 0 }" },
+	{ 1, "{ [a, b, c] : 2b = 1 + a and 2c = 2 + a; [0, 0, 0] }" },
+	{ 1, "{ [a, a, b, c] : 32*floor((a)/32) = a and 2*floor((b)/2) = b and "
+				"2*floor((c)/2) = c and 0 <= a <= 192;"
+		"[224, 224, b, c] : 2*floor((b)/2) = b and 2*floor((c)/2) = c }"
+	},
+	{ 1, "[n] -> { [a,b] : (exists e : 1 <= a <= 7e and 9e <= b <= n) or "
+				"(0 <= a <= b <= n) }" },
+	{ 1, "{ [a, b] : 0 <= a <= 2 and b >= 0 and "
+		"((0 < b <= 13) or (2*floor((a + b)/2) >= -5 + a + 2b)) }" },
+	{ 1, "{ [a] : (2 <= a <= 5) or (a mod 2 = 1 and 1 <= a <= 5) }" },
+	{ 1, "{ [a, b, c] : (b = -1 + a and 0 < a <= 3 and "
+				"9*floor((-4a + 2c)/9) <= -3 - 4a + 2c) or "
+			"(exists (e0 = floor((-16 + 2c)/9): a = 4 and "
+				"b = 3 and 9e0 <= -19 + 2c)) }" },
+	{ 1, "{ [a, b, c] : (b = -1 + a and 0 < a <= 3 and "
+				"9*floor((-4a + 2c)/9) <= -3 - 4a + 2c) or "
+			"(a = 4 and b = 3 and "
+				"9*floor((-16 + 2c)/9) <= -19 + 2c) }" },
+	{ 0, "{ [a, b, c] : (b <= 2 and b <= -2 + a) or "
+			"(b = -1 + a and 0 < a <= 3 and "
+				"9*floor((-4a + 2c)/9) <= -3 - 4a + 2c) or "
+			"(exists (e0 = floor((-16 + 2c)/9): a = 4 and "
+				"b = 3 and 9e0 <= -19 + 2c)) }" },
+	{ 1, "{ [y, x] : (x - y) mod 3 = 2 and 2 <= y <= 200 and 0 <= x <= 2;"
+		"[1, 0] }" },
+	{ 1, "{ [x, y] : (x - y) mod 3 = 2 and 2 <= y <= 200 and 0 <= x <= 2;"
+		"[0, 1] }" },
+	{ 1, "{ [1, y] : -1 <= y <= 1; [x, -x] : 0 <= x <= 1 }" },
+	{ 1, "{ [1, y] : 0 <= y <= 1; [x, -x] : 0 <= x <= 1 }" },
+	{ 1, "{ [x, y] : 0 <= x <= 10 and x - 4*floor(x/4) <= 1 and y <= 0; "
+	       "[x, y] : 0 <= x <= 10 and x - 4*floor(x/4) > 1 and y <= 0; "
+	       "[x, y] : 0 <= x <= 10 and x - 5*floor(x/5) <= 1 and 0 < y; "
+	       "[x, y] : 0 <= x <= 10 and x - 5*floor(x/5) > 1 and 0 < y }" },
+	{ 1, "{ [x, 0] : 0 <= x <= 10 and x mod 2 = 0; "
+	       "[x, 0] : 0 <= x <= 10 and x mod 2 = 1; "
+	       "[x, y] : 0 <= x <= 10 and 1 <= y <= 10 }" },
+	{ 1, "{ [a] : a <= 8 and "
+			"(a mod 10 = 7 or a mod 10 = 8 or a mod 10 = 9) }" },
+	{ 1, "{ [x, y] : 2y = -x and x <= 0 or "
+			"x <= -1 and 2y <= -x - 1 and 2y >= x - 1 }" },
+	{ 0, "{ [x, y] : 2y = -x and x <= 0 or "
+			"x <= -2 and 2y <= -x - 1 and 2y >= x - 1 }" },
+	{ 1, "{ [a] : (a <= 0 and 3*floor((a)/3) = a) or "
+			"(a < 0 and 3*floor((a)/3) < a) }" },
+	{ 1, "{ [a] : (a <= 0 and 3*floor((a)/3) = a) or "
+			"(a < -1 and 3*floor((a)/3) < a) }" },
+	{ 1, "{ [a, b] : a <= 1024 and b >= 0 and "
+		"((-31 - a + b <= 32*floor((-1 - a)/32) <= -33 + b and "
+		  "32*floor((-1 - a)/32) <= -16 + b + 16*floor((-1 - a)/16))"
+		"or (2 <= a <= 15 and b < a)) }" },
+	{ 1, "{ [a] : a > 0 and ((16*floor((a)/16) < a and "
+			"32*floor((a)/32) < a) or a <= 15) }" },
+	{ 1, "{ [a, b, c, d] : (-a + d) mod 64 = 0 and a <= 8 and b <= 1 and "
+			"10 - a <= c <= 3 and d >= 5 and 9 - 64b <= d <= 70;"
+	    "[a, b = 1, c, d] : (-a + d) mod 64 = 0 and a <= 8 and c >= 4 and "
+			"10 - a <= c <= 5 and 5 <= d <= 73 - c }" },
+	{ 1, "[n, m] -> { S_0[i] : (-n + i) mod 3 = 0 and m >= 3 + n and "
+			    "i >= n and 3*floor((2 + n + 2m)/3) <= n + 3m - i; "
+			 "S_0[n] : n <= m <= 2 + n }" },
+	{ 1, "{ [a, b] : exists (e0: 0 <= a <= 1 and b >= 0 and "
+			"2e0 >= -5 + a + 2b and 2e0 >= -1 + a + b and "
+			"2e0 <= a + b); "
+		"[a, b] : exists (e0: 0 <= a <= 1 and 2e0 >= -5 + a + 2b and "
+			"2e0 >= -1 - a + b and 2e0 <= -a + b and "
+			"2e0 < -a + 2b) }" },
+	{ 1, "{ [i, j, i - 8j] : 8 <= i <= 63 and -7 + i <= 8j <= i; "
+		"[i, 0, i] : 0 <= i <= 7 }" },
+};
+
+/* A specialized coalescing test case that would result
+ * in a segmentation fault or a failed assertion in earlier versions of isl.
+ */
+static int test_coalesce_special(struct isl_ctx *ctx)
+{
+	const char *str;
+	isl_map *map1, *map2;
+
+	str = "[y] -> { [S_L220_OUT[] -> T7[]] -> "
+	    "[[S_L309_IN[] -> T11[]] -> ce_imag2[1, o1]] : "
+	    "(y = 201 and o1 <= 239 and o1 >= 212) or "
+	    "(exists (e0 = [(y)/3]: 3e0 = y and y <= 198 and y >= 3 and "
+		"o1 <= 239 and o1 >= 212)) or "
+	    "(exists (e0 = [(y)/3]: 3e0 = y and y <= 201 and y >= 3 and "
+		"o1 <= 241 and o1 >= 240));"
+	    "[S_L220_OUT[] -> T7[]] -> "
+	    "[[S_L309_IN[] -> T11[]] -> ce_imag2[0, o1]] : "
+	    "(y = 2 and o1 <= 241 and o1 >= 212) or "
+	    "(exists (e0 = [(-2 + y)/3]: 3e0 = -2 + y and y <= 200 and "
+		"y >= 5 and o1 <= 241 and o1 >= 212)) }";
+	map1 = isl_map_read_from_str(ctx, str);
+	map1 = isl_map_align_divs_internal(map1);
+	map1 = isl_map_coalesce(map1);
+	str = "[y] -> { [S_L220_OUT[] -> T7[]] -> "
+	    "[[S_L309_IN[] -> T11[]] -> ce_imag2[o0, o1]] : "
+	    "exists (e0 = [(-1 - y + o0)/3]: 3e0 = -1 - y + o0 and "
+		"y <= 201 and o0 <= 2 and o1 >= 212 and o1 <= 241 and "
+		"o0 >= 3 - y and o0 <= -2 + y and o0 >= 0) }";
+	map2 = isl_map_read_from_str(ctx, str);
+	map2 = isl_map_union(map2, map1);
+	map2 = isl_map_align_divs_internal(map2);
+	map2 = isl_map_coalesce(map2);
+	isl_map_free(map2);
+	if (!map2)
+		return -1;
+
+	return 0;
+}
+
+/* A specialized coalescing test case that would result in an assertion
+ * in an earlier version of isl.
+ * The explicit call to isl_basic_set_union prevents the implicit
+ * equality constraints in the first basic map from being detected prior
+ * to the call to isl_set_coalesce, at least at the point
+ * where this test case was introduced.
+ */
+static int test_coalesce_special2(struct isl_ctx *ctx)
+{
+	const char *str;
+	isl_basic_set *bset1, *bset2;
+	isl_set *set;
+
+	str = "{ [x, y] : x, y >= 0 and x + 2y <= 1 and 2x + y <= 1 }";
+	bset1 = isl_basic_set_read_from_str(ctx, str);
+	str = "{ [x,0] : -1 <= x <= 1 and x mod 2 = 1 }" ;
+	bset2 = isl_basic_set_read_from_str(ctx, str);
+	set = isl_basic_set_union(bset1, bset2);
+	set = isl_set_coalesce(set);
+	isl_set_free(set);
+
+	if (!set)
+		return -1;
+	return 0;
+}
+
+/* Check that calling isl_set_coalesce does not leave other sets
+ * that may share some information with the input to isl_set_coalesce
+ * in an inconsistent state.
+ * In particular, older versions of isl would modify all copies
+ * of the basic sets in the isl_set_coalesce input in a way
+ * that could leave them in an inconsistent state.
+ * The result of printing any other set containing one of these
+ * basic sets would then result in an invalid set description.
+ */
+static int test_coalesce_special3(isl_ctx *ctx)
+{
+	const char *str;
+	char *s;
+	isl_set *set1, *set2;
+	isl_printer *p;
+
+	set1 = isl_set_read_from_str(ctx, "{ [0, 0, 0] }");
+	str = "{ [a, b, a + b] : a >= 0 and b >= 0 and 0 < a + b }";
+	set2 = isl_set_read_from_str(ctx, str);
+	set1 = isl_set_union(set1, isl_set_copy(set2));
+	set1 = isl_set_coalesce(set1);
+	isl_set_free(set1);
+
+	p = isl_printer_to_str(ctx);
+	p = isl_printer_print_set(p, set2);
+	isl_set_free(set2);
+	s = isl_printer_get_str(p);
+	isl_printer_free(p);
+	set1 = isl_set_read_from_str(ctx, s);
+	free(s);
+	isl_set_free(set1);
+
+	if (!set1)
+		return -1;
+
+	return 0;
+}
+
+/* Test the functionality of isl_set_coalesce.
+ * That is, check that the output is always equal to the input
+ * and in some cases that the result consists of a single disjunct.
+ */
+static int test_coalesce(struct isl_ctx *ctx)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coalesce_tests); ++i) {
+		const char *str = coalesce_tests[i].str;
+		int check_one = coalesce_tests[i].single_disjunct;
+		if (test_coalesce_set(ctx, str, check_one) < 0)
+			return -1;
+	}
+
+	if (test_coalesce_unbounded_wrapping(ctx) < 0)
+		return -1;
+	if (test_coalesce_special(ctx) < 0)
+		return -1;
+	if (test_coalesce_special2(ctx) < 0)
+		return -1;
+	if (test_coalesce_special3(ctx) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Construct a representation of the graph on the right of Figure 1
+ * in "Computing the Transitive Closure of a Union of
+ * Affine Integer Tuple Relations".
+ */
+static __isl_give isl_map *cocoa_fig_1_right_graph(isl_ctx *ctx)
+{
+	isl_set *dom;
+	isl_map *up, *right;
+
+	dom = isl_set_read_from_str(ctx,
+		"{ [x,y] : x >= 0 and -2 x + 3 y >= 0 and x <= 3 and "
+			"2 x - 3 y + 3 >= 0 }");
+	right = isl_map_read_from_str(ctx,
+		"{ [x,y] -> [x2,y2] : x2 = x + 1 and y2 = y }");
+	up = isl_map_read_from_str(ctx,
+		"{ [x,y] -> [x2,y2] : x2 = x and y2 = y + 1 }");
+	right = isl_map_intersect_domain(right, isl_set_copy(dom));
+	right = isl_map_intersect_range(right, isl_set_copy(dom));
+	up = isl_map_intersect_domain(up, isl_set_copy(dom));
+	up = isl_map_intersect_range(up, dom);
+	return isl_map_union(up, right);
+}
+
+/* Construct a representation of the power of the graph
+ * on the right of Figure 1 in "Computing the Transitive Closure of
+ * a Union of Affine Integer Tuple Relations".
+ */
+static __isl_give isl_map *cocoa_fig_1_right_power(isl_ctx *ctx)
+{
+	return isl_map_read_from_str(ctx,
+		"{ [1] -> [[0,0] -> [0,1]]; [2] -> [[0,0] -> [1,1]]; "
+		"  [1] -> [[0,1] -> [1,1]]; [1] -> [[2,2] -> [3,2]]; "
+		"  [2] -> [[2,2] -> [3,3]]; [1] -> [[3,2] -> [3,3]] }");
+}
+
+/* Construct a representation of the transitive closure of the graph
+ * on the right of Figure 1 in "Computing the Transitive Closure of
+ * a Union of Affine Integer Tuple Relations".
+ */
+static __isl_give isl_map *cocoa_fig_1_right_tc(isl_ctx *ctx)
+{
+	return isl_set_unwrap(isl_map_range(cocoa_fig_1_right_power(ctx)));
+}
+
+static int test_closure(isl_ctx *ctx)
+{
+	const char *str;
+	isl_map *map, *map2;
+	int exact, equal;
+
+	/* COCOA example 1 */
+	map = isl_map_read_from_str(ctx,
+		"[n] -> { [i,j] -> [i2,j2] : i2 = i + 1 and j2 = j + 1 and "
+			"1 <= i and i < n and 1 <= j and j < n or "
+			"i2 = i + 1 and j2 = j - 1 and "
+			"1 <= i and i < n and 2 <= j and j <= n }");
+	map = isl_map_power(map, &exact);
+	assert(exact);
+	isl_map_free(map);
+
+	/* COCOA example 1 */
+	map = isl_map_read_from_str(ctx,
+		"[n] -> { [i,j] -> [i2,j2] : i2 = i + 1 and j2 = j + 1 and "
+			"1 <= i and i < n and 1 <= j and j < n or "
+			"i2 = i + 1 and j2 = j - 1 and "
+			"1 <= i and i < n and 2 <= j and j <= n }");
+	map = isl_map_transitive_closure(map, &exact);
+	assert(exact);
+	map2 = isl_map_read_from_str(ctx,
+		"[n] -> { [i,j] -> [i2,j2] : exists (k1,k2,k : "
+			"1 <= i and i < n and 1 <= j and j <= n and "
+			"2 <= i2 and i2 <= n and 1 <= j2 and j2 <= n and "
+			"i2 = i + k1 + k2 and j2 = j + k1 - k2 and "
+			"k1 >= 0 and k2 >= 0 and k1 + k2 = k and k >= 1 )}");
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map2);
+	isl_map_free(map);
+
+	map = isl_map_read_from_str(ctx,
+		"[n] -> { [x] -> [y] : y = x + 1 and 0 <= x and x <= n and "
+				     " 0 <= y and y <= n }");
+	map = isl_map_transitive_closure(map, &exact);
+	map2 = isl_map_read_from_str(ctx,
+		"[n] -> { [x] -> [y] : y > x and 0 <= x and x <= n and "
+				     " 0 <= y and y <= n }");
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map2);
+	isl_map_free(map);
+
+	/* COCOA example 2 */
+	map = isl_map_read_from_str(ctx,
+		"[n] -> { [i,j] -> [i2,j2] : i2 = i + 2 and j2 = j + 2 and "
+			"1 <= i and i < n - 1 and 1 <= j and j < n - 1 or "
+			"i2 = i + 2 and j2 = j - 2 and "
+			"1 <= i and i < n - 1 and 3 <= j and j <= n }");
+	map = isl_map_transitive_closure(map, &exact);
+	assert(exact);
+	map2 = isl_map_read_from_str(ctx,
+		"[n] -> { [i,j] -> [i2,j2] : exists (k1,k2,k : "
+			"1 <= i and i < n - 1 and 1 <= j and j <= n and "
+			"3 <= i2 and i2 <= n and 1 <= j2 and j2 <= n and "
+			"i2 = i + 2 k1 + 2 k2 and j2 = j + 2 k1 - 2 k2 and "
+			"k1 >= 0 and k2 >= 0 and k1 + k2 = k and k >= 1) }");
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map);
+	isl_map_free(map2);
+
+	/* COCOA Fig.2 left */
+	map = isl_map_read_from_str(ctx,
+		"[n] -> { [i,j] -> [i2,j2] : i2 = i + 2 and j2 = j and "
+			"i <= 2 j - 3 and i <= n - 2 and j <= 2 i - 1 and "
+			"j <= n or "
+			"i2 = i and j2 = j + 2 and i <= 2 j - 1 and i <= n and "
+			"j <= 2 i - 3 and j <= n - 2 or "
+			"i2 = i + 1 and j2 = j + 1 and i <= 2 j - 1 and "
+			"i <= n - 1 and j <= 2 i - 1 and j <= n - 1 }");
+	map = isl_map_transitive_closure(map, &exact);
+	assert(exact);
+	isl_map_free(map);
+
+	/* COCOA Fig.2 right */
+	map = isl_map_read_from_str(ctx,
+		"[n] -> { [i,j] -> [i2,j2] : i2 = i + 3 and j2 = j and "
+			"i <= 2 j - 4 and i <= n - 3 and j <= 2 i - 1 and "
+			"j <= n or "
+			"i2 = i and j2 = j + 3 and i <= 2 j - 1 and i <= n and "
+			"j <= 2 i - 4 and j <= n - 3 or "
+			"i2 = i + 1 and j2 = j + 1 and i <= 2 j - 1 and "
+			"i <= n - 1 and j <= 2 i - 1 and j <= n - 1 }");
+	map = isl_map_power(map, &exact);
+	assert(exact);
+	isl_map_free(map);
+
+	/* COCOA Fig.2 right */
+	map = isl_map_read_from_str(ctx,
+		"[n] -> { [i,j] -> [i2,j2] : i2 = i + 3 and j2 = j and "
+			"i <= 2 j - 4 and i <= n - 3 and j <= 2 i - 1 and "
+			"j <= n or "
+			"i2 = i and j2 = j + 3 and i <= 2 j - 1 and i <= n and "
+			"j <= 2 i - 4 and j <= n - 3 or "
+			"i2 = i + 1 and j2 = j + 1 and i <= 2 j - 1 and "
+			"i <= n - 1 and j <= 2 i - 1 and j <= n - 1 }");
+	map = isl_map_transitive_closure(map, &exact);
+	assert(exact);
+	map2 = isl_map_read_from_str(ctx,
+		"[n] -> { [i,j] -> [i2,j2] : exists (k1,k2,k3,k : "
+			"i <= 2 j - 1 and i <= n and j <= 2 i - 1 and "
+			"j <= n and 3 + i + 2 j <= 3 n and "
+			"3 + 2 i + j <= 3n and i2 <= 2 j2 -1 and i2 <= n and "
+			"i2 <= 3 j2 - 4 and j2 <= 2 i2 -1 and j2 <= n and "
+			"13 + 4 j2 <= 11 i2 and i2 = i + 3 k1 + k3 and "
+			"j2 = j + 3 k2 + k3 and k1 >= 0 and k2 >= 0 and "
+			"k3 >= 0 and k1 + k2 + k3 = k and k > 0) }");
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map2);
+	isl_map_free(map);
+
+	map = cocoa_fig_1_right_graph(ctx);
+	map = isl_map_transitive_closure(map, &exact);
+	assert(exact);
+	map2 = cocoa_fig_1_right_tc(ctx);
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map2);
+	isl_map_free(map);
+
+	map = cocoa_fig_1_right_graph(ctx);
+	map = isl_map_power(map, &exact);
+	map2 = cocoa_fig_1_right_power(ctx);
+	equal = isl_map_is_equal(map, map2);
+	isl_map_free(map2);
+	isl_map_free(map);
+	if (equal < 0)
+		return -1;
+	if (!exact)
+		isl_die(ctx, isl_error_unknown, "power not exact", return -1);
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "unexpected power", return -1);
+
+	/* COCOA Theorem 1 counter example */
+	map = isl_map_read_from_str(ctx,
+		"{ [i,j] -> [i2,j2] : i = 0 and 0 <= j and j <= 1 and "
+			"i2 = 1 and j2 = j or "
+			"i = 0 and j = 0 and i2 = 0 and j2 = 1 }");
+	map = isl_map_transitive_closure(map, &exact);
+	assert(exact);
+	isl_map_free(map);
+
+	map = isl_map_read_from_str(ctx,
+		"[m,n] -> { [i,j] -> [i2,j2] : i2 = i and j2 = j + 2 and "
+			"1 <= i,i2 <= n and 1 <= j,j2 <= m or "
+			"i2 = i + 1 and 3 <= j2 - j <= 4 and "
+			"1 <= i,i2 <= n and 1 <= j,j2 <= m }");
+	map = isl_map_transitive_closure(map, &exact);
+	assert(exact);
+	isl_map_free(map);
+
+	/* Kelly et al 1996, fig 12 */
+	map = isl_map_read_from_str(ctx,
+		"[n] -> { [i,j] -> [i2,j2] : i2 = i and j2 = j + 1 and "
+			"1 <= i,j,j+1 <= n or "
+			"j = n and j2 = 1 and i2 = i + 1 and "
+			"1 <= i,i+1 <= n }");
+	map = isl_map_transitive_closure(map, &exact);
+	assert(exact);
+	map2 = isl_map_read_from_str(ctx,
+		"[n] -> { [i,j] -> [i2,j2] : 1 <= j < j2 <= n and "
+			"1 <= i <= n and i = i2 or "
+			"1 <= i < i2 <= n and 1 <= j <= n and "
+			"1 <= j2 <= n }");
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map2);
+	isl_map_free(map);
+
+	/* Omega's closure4 */
+	map = isl_map_read_from_str(ctx,
+		"[m,n] -> { [x,y] -> [x2,y2] : x2 = x and y2 = y + 1 and "
+			"1 <= x,y <= 10 or "
+			"x2 = x + 1 and y2 = y and "
+			"1 <= x <= 20 && 5 <= y <= 15 }");
+	map = isl_map_transitive_closure(map, &exact);
+	assert(exact);
+	isl_map_free(map);
+
+	map = isl_map_read_from_str(ctx,
+		"[n] -> { [x] -> [y]: 1 <= n <= y - x <= 10 }");
+	map = isl_map_transitive_closure(map, &exact);
+	assert(!exact);
+	map2 = isl_map_read_from_str(ctx,
+		"[n] -> { [x] -> [y] : 1 <= n <= 10 and y >= n + x }");
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map);
+	isl_map_free(map2);
+
+	str = "[n, m] -> { [i0, i1, i2, i3] -> [o0, o1, o2, o3] : "
+	    "i3 = 1 and o0 = i0 and o1 = -1 + i1 and o2 = -1 + i2 and "
+	    "o3 = -2 + i2 and i1 <= -1 + i0 and i1 >= 1 - m + i0 and "
+	    "i1 >= 2 and i1 <= n and i2 >= 3 and i2 <= 1 + n and i2 <= m }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_transitive_closure(map, &exact);
+	assert(exact);
+	map2 = isl_map_read_from_str(ctx, str);
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map);
+	isl_map_free(map2);
+
+	str = "{[0] -> [1]; [2] -> [3]}";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_transitive_closure(map, &exact);
+	assert(exact);
+	map2 = isl_map_read_from_str(ctx, str);
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map);
+	isl_map_free(map2);
+
+	str = "[n] -> { [[i0, i1, 1, 0, i0] -> [i5, 1]] -> "
+	    "[[i0, -1 + i1, 2, 0, i0] -> [-1 + i5, 2]] : "
+	    "exists (e0 = [(3 - n)/3]: i5 >= 2 and i1 >= 2 and "
+	    "3i0 <= -1 + n and i1 <= -1 + n and i5 <= -1 + n and "
+	    "3e0 >= 1 - n and 3e0 <= 2 - n and 3i0 >= -2 + n); "
+	    "[[i0, i1, 2, 0, i0] -> [i5, 1]] -> "
+	    "[[i0, i1, 1, 0, i0] -> [-1 + i5, 2]] : "
+	    "exists (e0 = [(3 - n)/3]: i5 >= 2 and i1 >= 1 and "
+	    "3i0 <= -1 + n and i1 <= -1 + n and i5 <= -1 + n and "
+	    "3e0 >= 1 - n and 3e0 <= 2 - n and 3i0 >= -2 + n); "
+	    "[[i0, i1, 1, 0, i0] -> [i5, 2]] -> "
+	    "[[i0, -1 + i1, 2, 0, i0] -> [i5, 1]] : "
+	    "exists (e0 = [(3 - n)/3]: i1 >= 2 and i5 >= 1 and "
+	    "3i0 <= -1 + n and i1 <= -1 + n and i5 <= -1 + n and "
+	    "3e0 >= 1 - n and 3e0 <= 2 - n and 3i0 >= -2 + n); "
+	    "[[i0, i1, 2, 0, i0] -> [i5, 2]] -> "
+	    "[[i0, i1, 1, 0, i0] -> [i5, 1]] : "
+	    "exists (e0 = [(3 - n)/3]: i5 >= 1 and i1 >= 1 and "
+	    "3i0 <= -1 + n and i1 <= -1 + n and i5 <= -1 + n and "
+	    "3e0 >= 1 - n and 3e0 <= 2 - n and 3i0 >= -2 + n) }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_transitive_closure(map, NULL);
+	assert(map);
+	isl_map_free(map);
+
+	return 0;
+}
+
+static int test_lex(struct isl_ctx *ctx)
+{
+	isl_space *dim;
+	isl_map *map;
+	int empty;
+
+	dim = isl_space_set_alloc(ctx, 0, 0);
+	map = isl_map_lex_le(dim);
+	empty = isl_map_is_empty(map);
+	isl_map_free(map);
+
+	if (empty < 0)
+		return -1;
+	if (empty)
+		isl_die(ctx, isl_error_unknown,
+			"expecting non-empty result", return -1);
+
+	return 0;
+}
+
+/* Inputs for isl_map_lexmin tests.
+ * "map" is the input and "lexmin" is the expected result.
+ */
+struct {
+	const char *map;
+	const char *lexmin;
+} lexmin_tests [] = {
+	{ "{ [x] -> [y] : x <= y <= 10; [x] -> [5] : -8 <= x <= 8 }",
+	  "{ [x] -> [5] : 6 <= x <= 8; "
+	    "[x] -> [x] : x <= 5 or (9 <= x <= 10) }" },
+	{ "{ [x] -> [y] : 4y = x or 4y = -1 + x or 4y = -2 + x }",
+	  "{ [x] -> [y] : 4y = x or 4y = -1 + x or 4y = -2 + x }" },
+	{ "{ [x] -> [y] : x = 4y; [x] -> [y] : x = 2y }",
+	  "{ [x] -> [y] : (4y = x and x >= 0) or "
+		"(exists (e0 = [(x)/4], e1 = [(-2 + x)/4]: 2y = x and "
+		"4e1 = -2 + x and 4e0 <= -1 + x and 4e0 >= -3 + x)) or "
+		"(exists (e0 = [(x)/4]: 2y = x and 4e0 = x and x <= -4)) }" },
+	{ "{ T[a] -> S[b, c] : a = 4b-2c and c >= b }",
+	  "{ T[a] -> S[b, c] : 2b = a and 2c = a }" },
+	/* Check that empty pieces are properly combined. */
+	{ "[K, N] -> { [x, y] -> [a, b] : K+2<=N<=K+4 and x>=4 and "
+		"2N-6<=x<K+N and N-1<=a<=K+N-1 and N+b-6<=a<=2N-4 and "
+		"b<=2N-3K+a and 3b<=4N-K+1 and b>=N and a>=x+1 }",
+	  "[K, N] -> { [x, y] -> [1 + x, N] : x >= -6 + 2N and "
+		"x <= -5 + 2N and x >= -1 + 3K - N and x <= -2 + K + N and "
+		"x >= 4 }" },
+	{ "{ [i, k, j] -> [a, b, c, d] : 8*floor((b)/8) = b and k <= 255 and "
+		"a <= 255 and c <= 255 and d <= 255 - j and "
+		"255 - j <= 7d <= 7 - i and 240d <= 239 + a and "
+		"247d <= 247 + k - j and 247d <= 247 + k - b and "
+		"247d <= 247 + i and 248 - b <= 248d <= c and "
+		"254d >= i - a + b and 254d >= -a + b and "
+		"255d >= -i + a - b and 1792d >= -63736 + 257b }",
+	  "{ [i, k, j] -> "
+	    "[-127762 + i + 502j, -62992 + 248j, 63240 - 248j, 255 - j] : "
+		"k <= 255 and 7j >= 1778 + i and 246j >= 62738 - k and "
+		"247j >= 62738 - i and 509j <= 129795 + i and "
+		"742j >= 188724 - i; "
+	    "[0, k, j] -> [1, 0, 248, 1] : k <= 255 and 248 <= j <= 254, k }" },
+	{ "{ [a] -> [b] : 0 <= b <= 255 and -509 + a <= 512b < a and "
+			"16*floor((8 + b)/16) <= 7 + b; "
+	    "[a] -> [1] }",
+	  "{ [a] -> [b = 1] : a >= 510 or a <= 0; "
+	    "[a] -> [b = 0] : 0 < a <= 509 }" },
+	{ "{ rat: [i] : 1 <= 2i <= 9 }", "{ rat: [i] : 2i = 1 }" },
+	{ "{ rat: [i] : 1 <= 2i <= 9 or i >= 10 }", "{ rat: [i] : 2i = 1 }" },
+};
+
+static int test_lexmin(struct isl_ctx *ctx)
+{
+	int i;
+	int equal;
+	const char *str;
+	isl_basic_map *bmap;
+	isl_map *map, *map2;
+	isl_set *set;
+	isl_set *set2;
+	isl_pw_multi_aff *pma;
+
+	str = "[p0, p1] -> { [] -> [] : "
+	    "exists (e0 = [(2p1)/3], e1, e2, e3 = [(3 - p1 + 3e0)/3], "
+	    "e4 = [(p1)/3], e5 = [(p1 + 3e4)/3]: "
+	    "3e0 >= -2 + 2p1 and 3e0 >= p1 and 3e3 >= 1 - p1 + 3e0 and "
+	    "3e0 <= 2p1 and 3e3 >= -2 + p1 and 3e3 <= -1 + p1 and p1 >= 3 and "
+	    "3e5 >= -2 + 2p1 and 3e5 >= p1 and 3e5 <= -1 + p1 + 3e4 and "
+	    "3e4 <= p1 and 3e4 >= -2 + p1 and e3 <= -1 + e0 and "
+	    "3e4 >= 6 - p1 + 3e1 and 3e1 >= p1 and 3e5 >= -2 + p1 + 3e4 and "
+	    "2e4 >= 3 - p1 + 2e1 and e4 <= e1 and 3e3 <= 2 - p1 + 3e0 and "
+	    "e5 >= 1 + e1 and 3e4 >= 6 - 2p1 + 3e1 and "
+	    "p0 >= 2 and p1 >= p0 and 3e2 >= p1 and 3e4 >= 6 - p1 + 3e2 and "
+	    "e2 <= e1 and e3 >= 1 and e4 <= e2) }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_lexmin(map);
+	isl_map_free(map);
+
+	str = "[C] -> { [obj,a,b,c] : obj <= 38 a + 7 b + 10 c and "
+	    "a + b <= 1 and c <= 10 b and c <= C and a,b,c,C >= 0 }";
+	set = isl_set_read_from_str(ctx, str);
+	set = isl_set_lexmax(set);
+	str = "[C] -> { [obj,a,b,c] : C = 8 }";
+	set2 = isl_set_read_from_str(ctx, str);
+	set = isl_set_intersect(set, set2);
+	assert(!isl_set_is_empty(set));
+	isl_set_free(set);
+
+	for (i = 0; i < ARRAY_SIZE(lexmin_tests); ++i) {
+		map = isl_map_read_from_str(ctx, lexmin_tests[i].map);
+		map = isl_map_lexmin(map);
+		map2 = isl_map_read_from_str(ctx, lexmin_tests[i].lexmin);
+		equal = isl_map_is_equal(map, map2);
+		isl_map_free(map);
+		isl_map_free(map2);
+
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown,
+				"unexpected result", return -1);
+	}
+
+	str = "{ [i] -> [i', j] : j = i - 8i' and i' >= 0 and i' <= 7 and "
+				" 8i' <= i and 8i' >= -7 + i }";
+	bmap = isl_basic_map_read_from_str(ctx, str);
+	pma = isl_basic_map_lexmin_pw_multi_aff(isl_basic_map_copy(bmap));
+	map2 = isl_map_from_pw_multi_aff(pma);
+	map = isl_map_from_basic_map(bmap);
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map);
+	isl_map_free(map2);
+
+	str = "[i] -> { [i', j] : j = i - 8i' and i' >= 0 and i' <= 7 and "
+				" 8i' <= i and 8i' >= -7 + i }";
+	set = isl_set_read_from_str(ctx, str);
+	pma = isl_set_lexmin_pw_multi_aff(isl_set_copy(set));
+	set2 = isl_set_from_pw_multi_aff(pma);
+	equal = isl_set_is_equal(set, set2);
+	isl_set_free(set);
+	isl_set_free(set2);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected difference between set and "
+			"piecewise affine expression", return -1);
+
+	return 0;
+}
+
+/* A specialized isl_set_min_val test case that would return the wrong result
+ * in earlier versions of isl.
+ * The explicit call to isl_basic_set_union prevents the second basic set
+ * from being determined to be empty prior to the call to isl_set_min_val,
+ * at least at the point where this test case was introduced.
+ */
+static int test_min_special(isl_ctx *ctx)
+{
+	const char *str;
+	isl_basic_set *bset1, *bset2;
+	isl_set *set;
+	isl_aff *obj;
+	isl_val *res;
+	int ok;
+
+	str = "{ [a, b] : a >= 2 and b >= 0 and 14 - a <= b <= 9 }";
+	bset1 = isl_basic_set_read_from_str(ctx, str);
+	str = "{ [a, b] : 1 <= a, b and a + b <= 1 }";
+	bset2 = isl_basic_set_read_from_str(ctx, str);
+	set = isl_basic_set_union(bset1, bset2);
+	obj = isl_aff_read_from_str(ctx, "{ [a, b] -> [a] }");
+
+	res = isl_set_min_val(set, obj);
+	ok = isl_val_cmp_si(res, 5) == 0;
+
+	isl_aff_free(obj);
+	isl_set_free(set);
+	isl_val_free(res);
+
+	if (!res)
+		return -1;
+	if (!ok)
+		isl_die(ctx, isl_error_unknown, "unexpected minimum",
+			return -1);
+
+	return 0;
+}
+
+/* A specialized isl_set_min_val test case that would return an error
+ * in earlier versions of isl.
+ */
+static int test_min_special2(isl_ctx *ctx)
+{
+	const char *str;
+	isl_basic_set *bset;
+	isl_aff *obj;
+	isl_val *res;
+
+	str = "{ [i, j, k] : 2j = i and 2k = i + 1 and i >= 2 }";
+	bset = isl_basic_set_read_from_str(ctx, str);
+
+	obj = isl_aff_read_from_str(ctx, "{ [i, j, k] -> [i] }");
+
+	res = isl_basic_set_max_val(bset, obj);
+
+	isl_basic_set_free(bset);
+	isl_aff_free(obj);
+	isl_val_free(res);
+
+	if (!res)
+		return -1;
+
+	return 0;
+}
+
+struct {
+	const char *set;
+	const char *obj;
+	__isl_give isl_val *(*fn)(__isl_keep isl_set *set,
+		__isl_keep isl_aff *obj);
+	const char *res;
+} opt_tests[] = {
+	{ "{ [-1]; [1] }", "{ [x] -> [x] }", &isl_set_min_val, "-1" },
+	{ "{ [-1]; [1] }", "{ [x] -> [x] }", &isl_set_max_val, "1" },
+	{ "{ [a, b] : 0 <= a, b <= 100 and b mod 2 = 0}",
+	  "{ [a, b] -> [floor((b - 2*floor((-a)/4))/5)] }",
+	  &isl_set_max_val, "30" },
+
+};
+
+/* Perform basic isl_set_min_val and isl_set_max_val tests.
+ * In particular, check the results on non-convex inputs.
+ */
+static int test_min(struct isl_ctx *ctx)
+{
+	int i;
+	isl_set *set;
+	isl_aff *obj;
+	isl_val *val, *res;
+	isl_bool ok;
+
+	for (i = 0; i < ARRAY_SIZE(opt_tests); ++i) {
+		set = isl_set_read_from_str(ctx, opt_tests[i].set);
+		obj = isl_aff_read_from_str(ctx, opt_tests[i].obj);
+		res = isl_val_read_from_str(ctx, opt_tests[i].res);
+		val = opt_tests[i].fn(set, obj);
+		ok = isl_val_eq(res, val);
+		isl_val_free(res);
+		isl_val_free(val);
+		isl_aff_free(obj);
+		isl_set_free(set);
+
+		if (ok < 0)
+			return -1;
+		if (!ok)
+			isl_die(ctx, isl_error_unknown,
+				"unexpected optimum", return -1);
+	}
+
+	if (test_min_special(ctx) < 0)
+		return -1;
+	if (test_min_special2(ctx) < 0)
+		return -1;
+
+	return 0;
+}
+
+struct must_may {
+	isl_map *must;
+	isl_map *may;
+};
+
+static isl_stat collect_must_may(__isl_take isl_map *dep, int must,
+	void *dep_user, void *user)
+{
+	struct must_may *mm = (struct must_may *)user;
+
+	if (must)
+		mm->must = isl_map_union(mm->must, dep);
+	else
+		mm->may = isl_map_union(mm->may, dep);
+
+	return isl_stat_ok;
+}
+
+static int common_space(void *first, void *second)
+{
+	int depth = *(int *)first;
+	return 2 * depth;
+}
+
+static int map_is_equal(__isl_keep isl_map *map, const char *str)
+{
+	isl_map *map2;
+	int equal;
+
+	if (!map)
+		return -1;
+
+	map2 = isl_map_read_from_str(map->ctx, str);
+	equal = isl_map_is_equal(map, map2);
+	isl_map_free(map2);
+
+	return equal;
+}
+
+static int map_check_equal(__isl_keep isl_map *map, const char *str)
+{
+	int equal;
+
+	equal = map_is_equal(map, str);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(isl_map_get_ctx(map), isl_error_unknown,
+			"result not as expected", return -1);
+	return 0;
+}
+
+static int test_dep(struct isl_ctx *ctx)
+{
+	const char *str;
+	isl_space *dim;
+	isl_map *map;
+	isl_access_info *ai;
+	isl_flow *flow;
+	int depth;
+	struct must_may mm;
+
+	depth = 3;
+
+	str = "{ [2,i,0] -> [i] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_alloc(map, &depth, &common_space, 2);
+
+	str = "{ [0,i,0] -> [i] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_add_source(ai, map, 1, &depth);
+
+	str = "{ [1,i,0] -> [5] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_add_source(ai, map, 1, &depth);
+
+	flow = isl_access_info_compute_flow(ai);
+	dim = isl_space_alloc(ctx, 0, 3, 3);
+	mm.must = isl_map_empty(isl_space_copy(dim));
+	mm.may = isl_map_empty(dim);
+
+	isl_flow_foreach(flow, collect_must_may, &mm);
+
+	str = "{ [0,i,0] -> [2,i,0] : (0 <= i <= 4) or (6 <= i <= 10); "
+	      "  [1,10,0] -> [2,5,0] }";
+	assert(map_is_equal(mm.must, str));
+	str = "{ [i,j,k] -> [l,m,n] : 1 = 0 }";
+	assert(map_is_equal(mm.may, str));
+
+	isl_map_free(mm.must);
+	isl_map_free(mm.may);
+	isl_flow_free(flow);
+
+
+	str = "{ [2,i,0] -> [i] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_alloc(map, &depth, &common_space, 2);
+
+	str = "{ [0,i,0] -> [i] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_add_source(ai, map, 1, &depth);
+
+	str = "{ [1,i,0] -> [5] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_add_source(ai, map, 0, &depth);
+
+	flow = isl_access_info_compute_flow(ai);
+	dim = isl_space_alloc(ctx, 0, 3, 3);
+	mm.must = isl_map_empty(isl_space_copy(dim));
+	mm.may = isl_map_empty(dim);
+
+	isl_flow_foreach(flow, collect_must_may, &mm);
+
+	str = "{ [0,i,0] -> [2,i,0] : (0 <= i <= 4) or (6 <= i <= 10) }";
+	assert(map_is_equal(mm.must, str));
+	str = "{ [0,5,0] -> [2,5,0]; [1,i,0] -> [2,5,0] : 0 <= i <= 10 }";
+	assert(map_is_equal(mm.may, str));
+
+	isl_map_free(mm.must);
+	isl_map_free(mm.may);
+	isl_flow_free(flow);
+
+
+	str = "{ [2,i,0] -> [i] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_alloc(map, &depth, &common_space, 2);
+
+	str = "{ [0,i,0] -> [i] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_add_source(ai, map, 0, &depth);
+
+	str = "{ [1,i,0] -> [5] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_add_source(ai, map, 0, &depth);
+
+	flow = isl_access_info_compute_flow(ai);
+	dim = isl_space_alloc(ctx, 0, 3, 3);
+	mm.must = isl_map_empty(isl_space_copy(dim));
+	mm.may = isl_map_empty(dim);
+
+	isl_flow_foreach(flow, collect_must_may, &mm);
+
+	str = "{ [0,i,0] -> [2,i,0] : 0 <= i <= 10; "
+	      "  [1,i,0] -> [2,5,0] : 0 <= i <= 10 }";
+	assert(map_is_equal(mm.may, str));
+	str = "{ [i,j,k] -> [l,m,n] : 1 = 0 }";
+	assert(map_is_equal(mm.must, str));
+
+	isl_map_free(mm.must);
+	isl_map_free(mm.may);
+	isl_flow_free(flow);
+
+
+	str = "{ [0,i,2] -> [i] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_alloc(map, &depth, &common_space, 2);
+
+	str = "{ [0,i,0] -> [i] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_add_source(ai, map, 0, &depth);
+
+	str = "{ [0,i,1] -> [5] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_add_source(ai, map, 0, &depth);
+
+	flow = isl_access_info_compute_flow(ai);
+	dim = isl_space_alloc(ctx, 0, 3, 3);
+	mm.must = isl_map_empty(isl_space_copy(dim));
+	mm.may = isl_map_empty(dim);
+
+	isl_flow_foreach(flow, collect_must_may, &mm);
+
+	str = "{ [0,i,0] -> [0,i,2] : 0 <= i <= 10; "
+	      "  [0,i,1] -> [0,5,2] : 0 <= i <= 5 }";
+	assert(map_is_equal(mm.may, str));
+	str = "{ [i,j,k] -> [l,m,n] : 1 = 0 }";
+	assert(map_is_equal(mm.must, str));
+
+	isl_map_free(mm.must);
+	isl_map_free(mm.may);
+	isl_flow_free(flow);
+
+
+	str = "{ [0,i,1] -> [i] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_alloc(map, &depth, &common_space, 2);
+
+	str = "{ [0,i,0] -> [i] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_add_source(ai, map, 0, &depth);
+
+	str = "{ [0,i,2] -> [5] : 0 <= i <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_add_source(ai, map, 0, &depth);
+
+	flow = isl_access_info_compute_flow(ai);
+	dim = isl_space_alloc(ctx, 0, 3, 3);
+	mm.must = isl_map_empty(isl_space_copy(dim));
+	mm.may = isl_map_empty(dim);
+
+	isl_flow_foreach(flow, collect_must_may, &mm);
+
+	str = "{ [0,i,0] -> [0,i,1] : 0 <= i <= 10; "
+	      "  [0,i,2] -> [0,5,1] : 0 <= i <= 4 }";
+	assert(map_is_equal(mm.may, str));
+	str = "{ [i,j,k] -> [l,m,n] : 1 = 0 }";
+	assert(map_is_equal(mm.must, str));
+
+	isl_map_free(mm.must);
+	isl_map_free(mm.may);
+	isl_flow_free(flow);
+
+
+	depth = 5;
+
+	str = "{ [1,i,0,0,0] -> [i,j] : 0 <= i <= 10 and 0 <= j <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_alloc(map, &depth, &common_space, 1);
+
+	str = "{ [0,i,0,j,0] -> [i,j] : 0 <= i <= 10 and 0 <= j <= 10 }";
+	map = isl_map_read_from_str(ctx, str);
+	ai = isl_access_info_add_source(ai, map, 1, &depth);
+
+	flow = isl_access_info_compute_flow(ai);
+	dim = isl_space_alloc(ctx, 0, 5, 5);
+	mm.must = isl_map_empty(isl_space_copy(dim));
+	mm.may = isl_map_empty(dim);
+
+	isl_flow_foreach(flow, collect_must_may, &mm);
+
+	str = "{ [0,i,0,j,0] -> [1,i,0,0,0] : 0 <= i,j <= 10 }";
+	assert(map_is_equal(mm.must, str));
+	str = "{ [0,0,0,0,0] -> [0,0,0,0,0] : 1 = 0 }";
+	assert(map_is_equal(mm.may, str));
+
+	isl_map_free(mm.must);
+	isl_map_free(mm.may);
+	isl_flow_free(flow);
+
+	return 0;
+}
+
+/* Check that the dependence analysis proceeds without errors.
+ * Earlier versions of isl would break down during the analysis
+ * due to the use of the wrong spaces.
+ */
+static int test_flow(isl_ctx *ctx)
+{
+	const char *str;
+	isl_union_map *access, *schedule;
+	isl_union_map *must_dep, *may_dep;
+	int r;
+
+	str = "{ S0[j] -> i[]; S1[j,i] -> i[]; S2[] -> i[]; S3[] -> i[] }";
+	access = isl_union_map_read_from_str(ctx, str);
+	str = "{ S0[j] -> [0,j,0,0] : 0 <= j < 10; "
+		"S1[j,i] -> [0,j,1,i] : 0 <= j < i < 10; "
+		"S2[] -> [1,0,0,0]; "
+		"S3[] -> [-1,0,0,0] }";
+	schedule = isl_union_map_read_from_str(ctx, str);
+	r = isl_union_map_compute_flow(access, isl_union_map_copy(access),
+					isl_union_map_copy(access), schedule,
+					&must_dep, &may_dep, NULL, NULL);
+	isl_union_map_free(may_dep);
+	isl_union_map_free(must_dep);
+
+	return r;
+}
+
+struct {
+	const char *map;
+	int sv;
+} sv_tests[] = {
+	{ "[N] -> { [i] -> [f] : 0 <= i <= N and 0 <= i - 10 f <= 9 }", 1 },
+	{ "[N] -> { [i] -> [f] : 0 <= i <= N and 0 <= i - 10 f <= 10 }", 0 },
+	{ "{ [i] -> [3*floor(i/2) + 5*floor(i/3)] }", 1 },
+	{ "{ S1[i] -> [i] : 0 <= i <= 9; S2[i] -> [i] : 0 <= i <= 9 }", 1 },
+	{ "{ [i] -> S1[i] : 0 <= i <= 9; [i] -> S2[i] : 0 <= i <= 9 }", 0 },
+	{ "{ A[i] -> [i]; B[i] -> [i]; B[i] -> [i + 1] }", 0 },
+	{ "{ A[i] -> [i]; B[i] -> [i] : i < 0; B[i] -> [i + 1] : i > 0 }", 1 },
+	{ "{ A[i] -> [i]; B[i] -> A[i] : i < 0; B[i] -> [i + 1] : i > 0 }", 1 },
+	{ "{ A[i] -> [i]; B[i] -> [j] : i - 1 <= j <= i }", 0 },
+};
+
+int test_sv(isl_ctx *ctx)
+{
+	isl_union_map *umap;
+	int i;
+	int sv;
+
+	for (i = 0; i < ARRAY_SIZE(sv_tests); ++i) {
+		umap = isl_union_map_read_from_str(ctx, sv_tests[i].map);
+		sv = isl_union_map_is_single_valued(umap);
+		isl_union_map_free(umap);
+		if (sv < 0)
+			return -1;
+		if (sv_tests[i].sv && !sv)
+			isl_die(ctx, isl_error_internal,
+				"map not detected as single valued", return -1);
+		if (!sv_tests[i].sv && sv)
+			isl_die(ctx, isl_error_internal,
+				"map detected as single valued", return -1);
+	}
+
+	return 0;
+}
+
+struct {
+	const char *str;
+	int bijective;
+} bijective_tests[] = {
+	{ "[N,M]->{[i,j] -> [i]}", 0 },
+	{ "[N,M]->{[i,j] -> [i] : j=i}", 1 },
+	{ "[N,M]->{[i,j] -> [i] : j=0}", 1 },
+	{ "[N,M]->{[i,j] -> [i] : j=N}", 1 },
+	{ "[N,M]->{[i,j] -> [j,i]}", 1 },
+	{ "[N,M]->{[i,j] -> [i+j]}", 0 },
+	{ "[N,M]->{[i,j] -> []}", 0 },
+	{ "[N,M]->{[i,j] -> [i,j,N]}", 1 },
+	{ "[N,M]->{[i,j] -> [2i]}", 0 },
+	{ "[N,M]->{[i,j] -> [i,i]}", 0 },
+	{ "[N,M]->{[i,j] -> [2i,i]}", 0 },
+	{ "[N,M]->{[i,j] -> [2i,j]}", 1 },
+	{ "[N,M]->{[i,j] -> [x,y] : 2x=i & y =j}", 1 },
+};
+
+static int test_bijective(struct isl_ctx *ctx)
+{
+	isl_map *map;
+	int i;
+	int bijective;
+
+	for (i = 0; i < ARRAY_SIZE(bijective_tests); ++i) {
+		map = isl_map_read_from_str(ctx, bijective_tests[i].str);
+		bijective = isl_map_is_bijective(map);
+		isl_map_free(map);
+		if (bijective < 0)
+			return -1;
+		if (bijective_tests[i].bijective && !bijective)
+			isl_die(ctx, isl_error_internal,
+				"map not detected as bijective", return -1);
+		if (!bijective_tests[i].bijective && bijective)
+			isl_die(ctx, isl_error_internal,
+				"map detected as bijective", return -1);
+	}
+
+	return 0;
+}
+
+/* Inputs for isl_pw_qpolynomial_gist tests.
+ * "pwqp" is the input, "set" is the context and "gist" is the expected result.
+ */
+struct {
+	const char *pwqp;
+	const char *set;
+	const char *gist;
+} pwqp_gist_tests[] = {
+	{ "{ [i] -> i }", "{ [k] : exists a : k = 2a }", "{ [i] -> i }" },
+	{ "{ [i] -> i + [ (i + [i/3])/2 ] }", "{ [10] }", "{ [i] -> 16 }" },
+	{ "{ [i] -> ([(i)/2]) }", "{ [k] : exists a : k = 2a+1 }",
+	  "{ [i] -> -1/2 + 1/2 * i }" },
+	{ "{ [i] -> i^2 : i != 0 }", "{ [i] : i != 0 }", "{ [i] -> i^2 }" },
+};
+
+static int test_pwqp(struct isl_ctx *ctx)
+{
+	int i;
+	const char *str;
+	isl_set *set;
+	isl_pw_qpolynomial *pwqp1, *pwqp2;
+	int equal;
+
+	str = "{ [i,j,k] -> 1 + 9 * [i/5] + 7 * [j/11] + 4 * [k/13] }";
+	pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str);
+
+	pwqp1 = isl_pw_qpolynomial_move_dims(pwqp1, isl_dim_param, 0,
+						isl_dim_in, 1, 1);
+
+	str = "[j] -> { [i,k] -> 1 + 9 * [i/5] + 7 * [j/11] + 4 * [k/13] }";
+	pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str);
+
+	pwqp1 = isl_pw_qpolynomial_sub(pwqp1, pwqp2);
+
+	assert(isl_pw_qpolynomial_is_zero(pwqp1));
+
+	isl_pw_qpolynomial_free(pwqp1);
+
+	for (i = 0; i < ARRAY_SIZE(pwqp_gist_tests); ++i) {
+		str = pwqp_gist_tests[i].pwqp;
+		pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str);
+		str = pwqp_gist_tests[i].set;
+		set = isl_set_read_from_str(ctx, str);
+		pwqp1 = isl_pw_qpolynomial_gist(pwqp1, set);
+		str = pwqp_gist_tests[i].gist;
+		pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str);
+		pwqp1 = isl_pw_qpolynomial_sub(pwqp1, pwqp2);
+		equal = isl_pw_qpolynomial_is_zero(pwqp1);
+		isl_pw_qpolynomial_free(pwqp1);
+
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown,
+				"unexpected result", return -1);
+	}
+
+	str = "{ [i] -> ([([i/2] + [i/2])/5]) }";
+	pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str);
+	str = "{ [i] -> ([(2 * [i/2])/5]) }";
+	pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str);
+
+	pwqp1 = isl_pw_qpolynomial_sub(pwqp1, pwqp2);
+
+	assert(isl_pw_qpolynomial_is_zero(pwqp1));
+
+	isl_pw_qpolynomial_free(pwqp1);
+
+	str = "{ [x] -> ([x/2] + [(x+1)/2]) }";
+	pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str);
+	str = "{ [x] -> x }";
+	pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str);
+
+	pwqp1 = isl_pw_qpolynomial_sub(pwqp1, pwqp2);
+
+	assert(isl_pw_qpolynomial_is_zero(pwqp1));
+
+	isl_pw_qpolynomial_free(pwqp1);
+
+	str = "{ [i] -> ([i/2]) : i >= 0; [i] -> ([i/3]) : i < 0 }";
+	pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str);
+	pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str);
+	pwqp1 = isl_pw_qpolynomial_coalesce(pwqp1);
+	pwqp1 = isl_pw_qpolynomial_sub(pwqp1, pwqp2);
+	assert(isl_pw_qpolynomial_is_zero(pwqp1));
+	isl_pw_qpolynomial_free(pwqp1);
+
+	str = "{ [a,b,a] -> (([(2*[a/3]+b)/5]) * ([(2*[a/3]+b)/5])) }";
+	pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str);
+	str = "{ [a,b,c] -> (([(2*[a/3]+b)/5]) * ([(2*[c/3]+b)/5])) }";
+	pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str);
+	set = isl_set_read_from_str(ctx, "{ [a,b,a] }");
+	pwqp1 = isl_pw_qpolynomial_intersect_domain(pwqp1, set);
+	equal = isl_pw_qpolynomial_plain_is_equal(pwqp1, pwqp2);
+	isl_pw_qpolynomial_free(pwqp1);
+	isl_pw_qpolynomial_free(pwqp2);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	str = "{ [a,b,c] -> (([(2*[a/3]+1)/5]) * ([(2*[c/3]+1)/5])) : b = 1 }";
+	pwqp2 = isl_pw_qpolynomial_read_from_str(ctx, str);
+	str = "{ [a,b,c] -> (([(2*[a/3]+b)/5]) * ([(2*[c/3]+b)/5])) }";
+	pwqp1 = isl_pw_qpolynomial_read_from_str(ctx, str);
+	pwqp1 = isl_pw_qpolynomial_fix_val(pwqp1, isl_dim_set, 1,
+						isl_val_one(ctx));
+	equal = isl_pw_qpolynomial_plain_is_equal(pwqp1, pwqp2);
+	isl_pw_qpolynomial_free(pwqp1);
+	isl_pw_qpolynomial_free(pwqp2);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	return 0;
+}
+
+static int test_split_periods(isl_ctx *ctx)
+{
+	const char *str;
+	isl_pw_qpolynomial *pwqp;
+
+	str = "{ [U,V] -> 1/3 * U + 2/3 * V - [(U + 2V)/3] + [U/2] : "
+		"U + 2V + 3 >= 0 and - U -2V  >= 0 and - U + 10 >= 0 and "
+		"U  >= 0; [U,V] -> U^2 : U >= 100 }";
+	pwqp = isl_pw_qpolynomial_read_from_str(ctx, str);
+
+	pwqp = isl_pw_qpolynomial_split_periods(pwqp, 2);
+
+	isl_pw_qpolynomial_free(pwqp);
+
+	if (!pwqp)
+		return -1;
+
+	return 0;
+}
+
+static int test_union(isl_ctx *ctx)
+{
+	const char *str;
+	isl_union_set *uset1, *uset2;
+	isl_union_map *umap1, *umap2;
+	int equal;
+
+	str = "{ [i] : 0 <= i <= 1 }";
+	uset1 = isl_union_set_read_from_str(ctx, str);
+	str = "{ [1] -> [0] }";
+	umap1 = isl_union_map_read_from_str(ctx, str);
+
+	umap2 = isl_union_set_lex_gt_union_set(isl_union_set_copy(uset1), uset1);
+	equal = isl_union_map_is_equal(umap1, umap2);
+
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "union maps not equal",
+			return -1);
+
+	str = "{ A[i] -> B[i]; B[i] -> C[i]; A[0] -> C[1] }";
+	umap1 = isl_union_map_read_from_str(ctx, str);
+	str = "{ A[i]; B[i] }";
+	uset1 = isl_union_set_read_from_str(ctx, str);
+
+	uset2 = isl_union_map_domain(umap1);
+
+	equal = isl_union_set_is_equal(uset1, uset2);
+
+	isl_union_set_free(uset1);
+	isl_union_set_free(uset2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "union sets not equal",
+			return -1);
+
+	return 0;
+}
+
+/* Check that computing a bound of a non-zero polynomial over an unbounded
+ * domain does not produce a rational value.
+ * In particular, check that the upper bound is infinity.
+ */
+static int test_bound_unbounded_domain(isl_ctx *ctx)
+{
+	const char *str;
+	isl_pw_qpolynomial *pwqp;
+	isl_pw_qpolynomial_fold *pwf, *pwf2;
+	isl_bool equal;
+
+	str = "{ [m,n] -> -m * n }";
+	pwqp = isl_pw_qpolynomial_read_from_str(ctx, str);
+	pwf = isl_pw_qpolynomial_bound(pwqp, isl_fold_max, NULL);
+	str = "{ infty }";
+	pwqp = isl_pw_qpolynomial_read_from_str(ctx, str);
+	pwf2 = isl_pw_qpolynomial_bound(pwqp, isl_fold_max, NULL);
+	equal = isl_pw_qpolynomial_fold_plain_is_equal(pwf, pwf2);
+	isl_pw_qpolynomial_fold_free(pwf);
+	isl_pw_qpolynomial_fold_free(pwf2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"expecting infinite polynomial bound", return -1);
+
+	return 0;
+}
+
+static int test_bound(isl_ctx *ctx)
+{
+	const char *str;
+	unsigned dim;
+	isl_pw_qpolynomial *pwqp;
+	isl_pw_qpolynomial_fold *pwf;
+
+	if (test_bound_unbounded_domain(ctx) < 0)
+		return -1;
+
+	str = "{ [[a, b, c, d] -> [e]] -> 0 }";
+	pwqp = isl_pw_qpolynomial_read_from_str(ctx, str);
+	pwf = isl_pw_qpolynomial_bound(pwqp, isl_fold_max, NULL);
+	dim = isl_pw_qpolynomial_fold_dim(pwf, isl_dim_in);
+	isl_pw_qpolynomial_fold_free(pwf);
+	if (dim != 4)
+		isl_die(ctx, isl_error_unknown, "unexpected input dimension",
+			return -1);
+
+	str = "{ [[x]->[x]] -> 1 : exists a : x = 2 a }";
+	pwqp = isl_pw_qpolynomial_read_from_str(ctx, str);
+	pwf = isl_pw_qpolynomial_bound(pwqp, isl_fold_max, NULL);
+	dim = isl_pw_qpolynomial_fold_dim(pwf, isl_dim_in);
+	isl_pw_qpolynomial_fold_free(pwf);
+	if (dim != 1)
+		isl_die(ctx, isl_error_unknown, "unexpected input dimension",
+			return -1);
+
+	return 0;
+}
+
+static int test_lift(isl_ctx *ctx)
+{
+	const char *str;
+	isl_basic_map *bmap;
+	isl_basic_set *bset;
+
+	str = "{ [i0] : exists e0 : i0 = 4e0 }";
+	bset = isl_basic_set_read_from_str(ctx, str);
+	bset = isl_basic_set_lift(bset);
+	bmap = isl_basic_map_from_range(bset);
+	bset = isl_basic_map_domain(bmap);
+	isl_basic_set_free(bset);
+
+	return 0;
+}
+
+struct {
+	const char *set1;
+	const char *set2;
+	int subset;
+} subset_tests[] = {
+	{ "{ [112, 0] }",
+	  "{ [i0, i1] : exists (e0 = [(i0 - i1)/16], e1: "
+		"16e0 <= i0 - i1 and 16e0 >= -15 + i0 - i1 and "
+		"16e1 <= i1 and 16e0 >= -i1 and 16e1 >= -i0 + i1) }", 1 },
+	{ "{ [65] }",
+	  "{ [i] : exists (e0 = [(255i)/256], e1 = [(127i + 65e0)/191], "
+		"e2 = [(3i + 61e1)/65], e3 = [(52i + 12e2)/61], "
+		"e4 = [(2i + e3)/3], e5 = [(4i + e3)/4], e6 = [(8i + e3)/12]: "
+		    "3e4 = 2i + e3 and 4e5 = 4i + e3 and 12e6 = 8i + e3 and "
+		    "i <= 255 and 64e3 >= -45 + 67i and i >= 0 and "
+		    "256e0 <= 255i and 256e0 >= -255 + 255i and "
+		    "191e1 <= 127i + 65e0 and 191e1 >= -190 + 127i + 65e0 and "
+		    "65e2 <= 3i + 61e1 and 65e2 >= -64 + 3i + 61e1 and "
+		    "61e3 <= 52i + 12e2 and 61e3 >= -60 + 52i + 12e2) }", 1 },
+	{ "{ [i] : 0 <= i <= 10 }", "{ rat: [i] : 0 <= i <= 10 }", 1 },
+	{ "{ rat: [i] : 0 <= i <= 10 }", "{ [i] : 0 <= i <= 10 }", 0 },
+	{ "{ rat: [0] }", "{ [i] : 0 <= i <= 10 }", 1 },
+	{ "{ rat: [(1)/2] }", "{ [i] : 0 <= i <= 10 }", 0 },
+	{ "{ [t, i] : (exists (e0 = [(2 + t)/4]: 4e0 <= 2 + t and "
+			"4e0 >= -1 + t and i >= 57 and i <= 62 and "
+			"4e0 <= 62 + t - i and 4e0 >= -61 + t + i and "
+			"t >= 0 and t <= 511 and 4e0 <= -57 + t + i and "
+			"4e0 >= 58 + t - i and i >= 58 + t and i >= 62 - t)) }",
+	  "{ [i0, i1] : (exists (e0 = [(4 + i0)/4]: 4e0 <= 62 + i0 - i1 and "
+			"4e0 >= 1 + i0 and i0 >= 0 and i0 <= 511 and "
+			"4e0 <= -57 + i0 + i1)) or "
+		"(exists (e0 = [(2 + i0)/4]: 4e0 <= i0 and "
+			"4e0 >= 58 + i0 - i1 and i0 >= 2 and i0 <= 511 and "
+			"4e0 >= -61 + i0 + i1)) or "
+		"(i1 <= 66 - i0 and i0 >= 2 and i1 >= 59 + i0) }", 1 },
+	{ "[a, b] -> { : a = 0 and b = -1 }", "[b, a] -> { : b >= -10 }", 1 },
+};
+
+static int test_subset(isl_ctx *ctx)
+{
+	int i;
+	isl_set *set1, *set2;
+	int subset;
+
+	for (i = 0; i < ARRAY_SIZE(subset_tests); ++i) {
+		set1 = isl_set_read_from_str(ctx, subset_tests[i].set1);
+		set2 = isl_set_read_from_str(ctx, subset_tests[i].set2);
+		subset = isl_set_is_subset(set1, set2);
+		isl_set_free(set1);
+		isl_set_free(set2);
+		if (subset < 0)
+			return -1;
+		if (subset != subset_tests[i].subset)
+			isl_die(ctx, isl_error_unknown,
+				"incorrect subset result", return -1);
+	}
+
+	return 0;
+}
+
+struct {
+	const char *minuend;
+	const char *subtrahend;
+	const char *difference;
+} subtract_domain_tests[] = {
+	{ "{ A[i] -> B[i] }", "{ A[i] }", "{ }" },
+	{ "{ A[i] -> B[i] }", "{ B[i] }", "{ A[i] -> B[i] }" },
+	{ "{ A[i] -> B[i] }", "{ A[i] : i > 0 }", "{ A[i] -> B[i] : i <= 0 }" },
+};
+
+static int test_subtract(isl_ctx *ctx)
+{
+	int i;
+	isl_union_map *umap1, *umap2;
+	isl_union_pw_multi_aff *upma1, *upma2;
+	isl_union_set *uset;
+	int equal;
+
+	for (i = 0; i < ARRAY_SIZE(subtract_domain_tests); ++i) {
+		umap1 = isl_union_map_read_from_str(ctx,
+				subtract_domain_tests[i].minuend);
+		uset = isl_union_set_read_from_str(ctx,
+				subtract_domain_tests[i].subtrahend);
+		umap2 = isl_union_map_read_from_str(ctx,
+				subtract_domain_tests[i].difference);
+		umap1 = isl_union_map_subtract_domain(umap1, uset);
+		equal = isl_union_map_is_equal(umap1, umap2);
+		isl_union_map_free(umap1);
+		isl_union_map_free(umap2);
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown,
+				"incorrect subtract domain result", return -1);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(subtract_domain_tests); ++i) {
+		upma1 = isl_union_pw_multi_aff_read_from_str(ctx,
+				subtract_domain_tests[i].minuend);
+		uset = isl_union_set_read_from_str(ctx,
+				subtract_domain_tests[i].subtrahend);
+		upma2 = isl_union_pw_multi_aff_read_from_str(ctx,
+				subtract_domain_tests[i].difference);
+		upma1 = isl_union_pw_multi_aff_subtract_domain(upma1, uset);
+		equal = isl_union_pw_multi_aff_plain_is_equal(upma1, upma2);
+		isl_union_pw_multi_aff_free(upma1);
+		isl_union_pw_multi_aff_free(upma2);
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown,
+				"incorrect subtract domain result", return -1);
+	}
+
+	return 0;
+}
+
+/* Check that intersecting the empty basic set with another basic set
+ * does not increase the number of constraints.  In particular,
+ * the empty basic set should maintain its canonical representation.
+ */
+static int test_intersect(isl_ctx *ctx)
+{
+	int n1, n2;
+	isl_basic_set *bset1, *bset2;
+
+	bset1 = isl_basic_set_read_from_str(ctx, "{ [a,b,c] : 1 = 0 }");
+	bset2 = isl_basic_set_read_from_str(ctx, "{ [1,2,3] }");
+	n1 = isl_basic_set_n_constraint(bset1);
+	bset1 = isl_basic_set_intersect(bset1, bset2);
+	n2 = isl_basic_set_n_constraint(bset1);
+	isl_basic_set_free(bset1);
+	if (!bset1)
+		return -1;
+	if (n1 != n2)
+		isl_die(ctx, isl_error_unknown,
+			"number of constraints of empty set changed",
+			return -1);
+
+	return 0;
+}
+
+int test_factorize(isl_ctx *ctx)
+{
+	const char *str;
+	isl_basic_set *bset;
+	isl_factorizer *f;
+
+	str = "{ [i0, i1, i2, i3, i4, i5, i6, i7] : 3i5 <= 2 - 2i0 and "
+	    "i0 >= -2 and i6 >= 1 + i3 and i7 >= 0 and 3i5 >= -2i0 and "
+	    "2i4 <= i2 and i6 >= 1 + 2i0 + 3i1 and i4 <= -1 and "
+	    "i6 >= 1 + 2i0 + 3i5 and i6 <= 2 + 2i0 + 3i5 and "
+	    "3i5 <= 2 - 2i0 - i2 + 3i4 and i6 <= 2 + 2i0 + 3i1 and "
+	    "i0 <= -1 and i7 <= i2 + i3 - 3i4 - i6 and "
+	    "3i5 >= -2i0 - i2 + 3i4 }";
+	bset = isl_basic_set_read_from_str(ctx, str);
+	f = isl_basic_set_factorizer(bset);
+	isl_basic_set_free(bset);
+	isl_factorizer_free(f);
+	if (!f)
+		isl_die(ctx, isl_error_unknown,
+			"failed to construct factorizer", return -1);
+
+	str = "{ [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12] : "
+	    "i12 <= 2 + i0 - i11 and 2i8 >= -i4 and i11 >= i1 and "
+	    "3i5 <= -i2 and 2i11 >= -i4 - 2i7 and i11 <= 3 + i0 + 3i9 and "
+	    "i11 <= -i4 - 2i7 and i12 >= -i10 and i2 >= -2 and "
+	    "i11 >= i1 + 3i10 and i11 >= 1 + i0 + 3i9 and "
+	    "i11 <= 1 - i4 - 2i8 and 6i6 <= 6 - i2 and 3i6 >= 1 - i2 and "
+	    "i11 <= 2 + i1 and i12 <= i4 + i11 and i12 >= i0 - i11 and "
+	    "3i5 >= -2 - i2 and i12 >= -1 + i4 + i11 and 3i3 <= 3 - i2 and "
+	    "9i6 <= 11 - i2 + 6i5 and 3i3 >= 1 - i2 and "
+	    "9i6 <= 5 - i2 + 6i3 and i12 <= -1 and i2 <= 0 }";
+	bset = isl_basic_set_read_from_str(ctx, str);
+	f = isl_basic_set_factorizer(bset);
+	isl_basic_set_free(bset);
+	isl_factorizer_free(f);
+	if (!f)
+		isl_die(ctx, isl_error_unknown,
+			"failed to construct factorizer", return -1);
+
+	return 0;
+}
+
+static isl_stat check_injective(__isl_take isl_map *map, void *user)
+{
+	int *injective = user;
+
+	*injective = isl_map_is_injective(map);
+	isl_map_free(map);
+
+	if (*injective < 0 || !*injective)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+int test_one_schedule(isl_ctx *ctx, const char *d, const char *w,
+	const char *r, const char *s, int tilable, int parallel)
+{
+	int i;
+	isl_union_set *D;
+	isl_union_map *W, *R, *S;
+	isl_union_map *empty;
+	isl_union_map *dep_raw, *dep_war, *dep_waw, *dep;
+	isl_union_map *validity, *proximity, *coincidence;
+	isl_union_map *schedule;
+	isl_union_map *test;
+	isl_union_set *delta;
+	isl_union_set *domain;
+	isl_set *delta_set;
+	isl_set *slice;
+	isl_set *origin;
+	isl_schedule_constraints *sc;
+	isl_schedule *sched;
+	int is_nonneg, is_parallel, is_tilable, is_injection, is_complete;
+
+	D = isl_union_set_read_from_str(ctx, d);
+	W = isl_union_map_read_from_str(ctx, w);
+	R = isl_union_map_read_from_str(ctx, r);
+	S = isl_union_map_read_from_str(ctx, s);
+
+	W = isl_union_map_intersect_domain(W, isl_union_set_copy(D));
+	R = isl_union_map_intersect_domain(R, isl_union_set_copy(D));
+
+	empty = isl_union_map_empty(isl_union_map_get_space(S));
+        isl_union_map_compute_flow(isl_union_map_copy(R),
+				   isl_union_map_copy(W), empty,
+				   isl_union_map_copy(S),
+				   &dep_raw, NULL, NULL, NULL);
+        isl_union_map_compute_flow(isl_union_map_copy(W),
+				   isl_union_map_copy(W),
+				   isl_union_map_copy(R),
+				   isl_union_map_copy(S),
+				   &dep_waw, &dep_war, NULL, NULL);
+
+	dep = isl_union_map_union(dep_waw, dep_war);
+	dep = isl_union_map_union(dep, dep_raw);
+	validity = isl_union_map_copy(dep);
+	coincidence = isl_union_map_copy(dep);
+	proximity = isl_union_map_copy(dep);
+
+	sc = isl_schedule_constraints_on_domain(isl_union_set_copy(D));
+	sc = isl_schedule_constraints_set_validity(sc, validity);
+	sc = isl_schedule_constraints_set_coincidence(sc, coincidence);
+	sc = isl_schedule_constraints_set_proximity(sc, proximity);
+	sched = isl_schedule_constraints_compute_schedule(sc);
+	schedule = isl_schedule_get_map(sched);
+	isl_schedule_free(sched);
+	isl_union_map_free(W);
+	isl_union_map_free(R);
+	isl_union_map_free(S);
+
+	is_injection = 1;
+	isl_union_map_foreach_map(schedule, &check_injective, &is_injection);
+
+	domain = isl_union_map_domain(isl_union_map_copy(schedule));
+	is_complete = isl_union_set_is_subset(D, domain);
+	isl_union_set_free(D);
+	isl_union_set_free(domain);
+
+	test = isl_union_map_reverse(isl_union_map_copy(schedule));
+	test = isl_union_map_apply_range(test, dep);
+	test = isl_union_map_apply_range(test, schedule);
+
+	delta = isl_union_map_deltas(test);
+	if (isl_union_set_n_set(delta) == 0) {
+		is_tilable = 1;
+		is_parallel = 1;
+		is_nonneg = 1;
+		isl_union_set_free(delta);
+	} else {
+		delta_set = isl_set_from_union_set(delta);
+
+		slice = isl_set_universe(isl_set_get_space(delta_set));
+		for (i = 0; i < tilable; ++i)
+			slice = isl_set_lower_bound_si(slice, isl_dim_set, i, 0);
+		is_tilable = isl_set_is_subset(delta_set, slice);
+		isl_set_free(slice);
+
+		slice = isl_set_universe(isl_set_get_space(delta_set));
+		for (i = 0; i < parallel; ++i)
+			slice = isl_set_fix_si(slice, isl_dim_set, i, 0);
+		is_parallel = isl_set_is_subset(delta_set, slice);
+		isl_set_free(slice);
+
+		origin = isl_set_universe(isl_set_get_space(delta_set));
+		for (i = 0; i < isl_set_dim(origin, isl_dim_set); ++i)
+			origin = isl_set_fix_si(origin, isl_dim_set, i, 0);
+
+		delta_set = isl_set_union(delta_set, isl_set_copy(origin));
+		delta_set = isl_set_lexmin(delta_set);
+
+		is_nonneg = isl_set_is_equal(delta_set, origin);
+
+		isl_set_free(origin);
+		isl_set_free(delta_set);
+	}
+
+	if (is_nonneg < 0 || is_parallel < 0 || is_tilable < 0 ||
+	    is_injection < 0 || is_complete < 0)
+		return -1;
+	if (!is_complete)
+		isl_die(ctx, isl_error_unknown,
+			"generated schedule incomplete", return -1);
+	if (!is_injection)
+		isl_die(ctx, isl_error_unknown,
+			"generated schedule not injective on each statement",
+			return -1);
+	if (!is_nonneg)
+		isl_die(ctx, isl_error_unknown,
+			"negative dependences in generated schedule",
+			return -1);
+	if (!is_tilable)
+		isl_die(ctx, isl_error_unknown,
+			"generated schedule not as tilable as expected",
+			return -1);
+	if (!is_parallel)
+		isl_die(ctx, isl_error_unknown,
+			"generated schedule not as parallel as expected",
+			return -1);
+
+	return 0;
+}
+
+/* Compute a schedule for the given instance set, validity constraints,
+ * proximity constraints and context and return a corresponding union map
+ * representation.
+ */
+static __isl_give isl_union_map *compute_schedule_with_context(isl_ctx *ctx,
+	const char *domain, const char *validity, const char *proximity,
+	const char *context)
+{
+	isl_set *con;
+	isl_union_set *dom;
+	isl_union_map *dep;
+	isl_union_map *prox;
+	isl_schedule_constraints *sc;
+	isl_schedule *schedule;
+	isl_union_map *sched;
+
+	con = isl_set_read_from_str(ctx, context);
+	dom = isl_union_set_read_from_str(ctx, domain);
+	dep = isl_union_map_read_from_str(ctx, validity);
+	prox = isl_union_map_read_from_str(ctx, proximity);
+	sc = isl_schedule_constraints_on_domain(dom);
+	sc = isl_schedule_constraints_set_context(sc, con);
+	sc = isl_schedule_constraints_set_validity(sc, dep);
+	sc = isl_schedule_constraints_set_proximity(sc, prox);
+	schedule = isl_schedule_constraints_compute_schedule(sc);
+	sched = isl_schedule_get_map(schedule);
+	isl_schedule_free(schedule);
+
+	return sched;
+}
+
+/* Compute a schedule for the given instance set, validity constraints and
+ * proximity constraints and return a corresponding union map representation.
+ */
+static __isl_give isl_union_map *compute_schedule(isl_ctx *ctx,
+	const char *domain, const char *validity, const char *proximity)
+{
+	return compute_schedule_with_context(ctx, domain, validity, proximity,
+						"{ : }");
+}
+
+/* Check that a schedule can be constructed on the given domain
+ * with the given validity and proximity constraints.
+ */
+static int test_has_schedule(isl_ctx *ctx, const char *domain,
+	const char *validity, const char *proximity)
+{
+	isl_union_map *sched;
+
+	sched = compute_schedule(ctx, domain, validity, proximity);
+	if (!sched)
+		return -1;
+
+	isl_union_map_free(sched);
+	return 0;
+}
+
+int test_special_schedule(isl_ctx *ctx, const char *domain,
+	const char *validity, const char *proximity, const char *expected_sched)
+{
+	isl_union_map *sched1, *sched2;
+	int equal;
+
+	sched1 = compute_schedule(ctx, domain, validity, proximity);
+	sched2 = isl_union_map_read_from_str(ctx, expected_sched);
+
+	equal = isl_union_map_is_equal(sched1, sched2);
+	isl_union_map_free(sched1);
+	isl_union_map_free(sched2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "unexpected schedule",
+			return -1);
+
+	return 0;
+}
+
+/* Check that the schedule map is properly padded, even after being
+ * reconstructed from the band forest.
+ */
+static int test_padded_schedule(isl_ctx *ctx)
+{
+	const char *str;
+	isl_union_set *D;
+	isl_union_map *validity, *proximity;
+	isl_schedule_constraints *sc;
+	isl_schedule *sched;
+	isl_union_map *map1, *map2;
+	isl_band_list *list;
+	int equal;
+
+	str = "[N] -> { S0[i] : 0 <= i <= N; S1[i, j] : 0 <= i, j <= N }";
+	D = isl_union_set_read_from_str(ctx, str);
+	validity = isl_union_map_empty(isl_union_set_get_space(D));
+	proximity = isl_union_map_copy(validity);
+	sc = isl_schedule_constraints_on_domain(D);
+	sc = isl_schedule_constraints_set_validity(sc, validity);
+	sc = isl_schedule_constraints_set_proximity(sc, proximity);
+	sched = isl_schedule_constraints_compute_schedule(sc);
+	map1 = isl_schedule_get_map(sched);
+	list = isl_schedule_get_band_forest(sched);
+	isl_band_list_free(list);
+	map2 = isl_schedule_get_map(sched);
+	isl_schedule_free(sched);
+	equal = isl_union_map_is_equal(map1, map2);
+	isl_union_map_free(map1);
+	isl_union_map_free(map2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"reconstructed schedule map not the same as original",
+			return -1);
+
+	return 0;
+}
+
+/* Check that conditional validity constraints are also taken into
+ * account across bands.
+ * In particular, try to make sure that live ranges D[1,0]->C[2,1] and
+ * D[2,0]->C[3,0] are not local in the outer band of the generated schedule
+ * and then check that the adjacent order constraint C[2,1]->D[2,0]
+ * is enforced by the rest of the schedule.
+ */
+static int test_special_conditional_schedule_constraints(isl_ctx *ctx)
+{
+	const char *str;
+	isl_union_set *domain;
+	isl_union_map *validity, *proximity, *condition;
+	isl_union_map *sink, *source, *dep;
+	isl_schedule_constraints *sc;
+	isl_schedule *schedule;
+	isl_union_access_info *access;
+	isl_union_flow *flow;
+	int empty;
+
+	str = "[n] -> { C[k, i] : k <= -1 + n and i >= 0 and i <= -1 + k; "
+	    "A[k] : k >= 1 and k <= -1 + n; "
+	    "B[k, i] : k <= -1 + n and i >= 0 and i <= -1 + k; "
+	    "D[k, i] : k <= -1 + n and i >= 0 and i <= -1 + k }";
+	domain = isl_union_set_read_from_str(ctx, str);
+	sc = isl_schedule_constraints_on_domain(domain);
+	str = "[n] -> { D[k, i] -> C[1 + k, k - i] : "
+		"k <= -2 + n and i >= 1 and i <= -1 + k; "
+		"D[k, i] -> C[1 + k, i] : "
+		"k <= -2 + n and i >= 1 and i <= -1 + k; "
+		"D[k, 0] -> C[1 + k, k] : k >= 1 and k <= -2 + n; "
+		"D[k, 0] -> C[1 + k, 0] : k >= 1 and k <= -2 + n }";
+	validity = isl_union_map_read_from_str(ctx, str);
+	sc = isl_schedule_constraints_set_validity(sc, validity);
+	str = "[n] -> { C[k, i] -> D[k, i] : "
+		"0 <= i <= -1 + k and k <= -1 + n }";
+	proximity = isl_union_map_read_from_str(ctx, str);
+	sc = isl_schedule_constraints_set_proximity(sc, proximity);
+	str = "[n] -> { [D[k, i] -> a[]] -> [C[1 + k, k - i] -> b[]] : "
+		"i <= -1 + k and i >= 1 and k <= -2 + n; "
+		"[B[k, i] -> c[]] -> [B[k, 1 + i] -> c[]] : "
+		"k <= -1 + n and i >= 0 and i <= -2 + k }";
+	condition = isl_union_map_read_from_str(ctx, str);
+	str = "[n] -> { [B[k, i] -> e[]] -> [D[k, i] -> a[]] : "
+		"i >= 0 and i <= -1 + k and k <= -1 + n; "
+		"[C[k, i] -> b[]] -> [D[k', -1 + k - i] -> a[]] : "
+		"i >= 0 and i <= -1 + k and k <= -1 + n and "
+		"k' <= -1 + n and k' >= k - i and k' >= 1 + k; "
+		"[C[k, i] -> b[]] -> [D[k, -1 + k - i] -> a[]] : "
+		"i >= 0 and i <= -1 + k and k <= -1 + n; "
+		"[B[k, i] -> c[]] -> [A[k'] -> d[]] : "
+		"k <= -1 + n and i >= 0 and i <= -1 + k and "
+		"k' >= 1 and k' <= -1 + n and k' >= 1 + k }";
+	validity = isl_union_map_read_from_str(ctx, str);
+	sc = isl_schedule_constraints_set_conditional_validity(sc, condition,
+								validity);
+	schedule = isl_schedule_constraints_compute_schedule(sc);
+	str = "{ D[2,0] -> [] }";
+	sink = isl_union_map_read_from_str(ctx, str);
+	access = isl_union_access_info_from_sink(sink);
+	str = "{ C[2,1] -> [] }";
+	source = isl_union_map_read_from_str(ctx, str);
+	access = isl_union_access_info_set_must_source(access, source);
+	access = isl_union_access_info_set_schedule(access, schedule);
+	flow = isl_union_access_info_compute_flow(access);
+	dep = isl_union_flow_get_must_dependence(flow);
+	isl_union_flow_free(flow);
+	empty = isl_union_map_is_empty(dep);
+	isl_union_map_free(dep);
+
+	if (empty < 0)
+		return -1;
+	if (empty)
+		isl_die(ctx, isl_error_unknown,
+			"conditional validity not respected", return -1);
+
+	return 0;
+}
+
+/* Check that the test for violated conditional validity constraints
+ * is not confused by domain compression.
+ * In particular, earlier versions of isl would apply
+ * a schedule on the compressed domains to the original domains,
+ * resulting in a failure to detect that the default schedule
+ * violates the conditional validity constraints.
+ */
+static int test_special_conditional_schedule_constraints_2(isl_ctx *ctx)
+{
+	const char *str;
+	isl_bool empty;
+	isl_union_set *domain;
+	isl_union_map *validity, *condition;
+	isl_schedule_constraints *sc;
+	isl_schedule *schedule;
+	isl_union_map *umap;
+	isl_map *map, *ge;
+
+	str = "{ A[0, i] : 0 <= i <= 10; B[1, i] : 0 <= i <= 10 }";
+	domain = isl_union_set_read_from_str(ctx, str);
+	sc = isl_schedule_constraints_on_domain(domain);
+	str = "{ B[1, i] -> A[0, i + 1] }";
+	condition = isl_union_map_read_from_str(ctx, str);
+	str = "{ A[0, i] -> B[1, i - 1] }";
+	validity = isl_union_map_read_from_str(ctx, str);
+	sc = isl_schedule_constraints_set_conditional_validity(sc, condition,
+						isl_union_map_copy(validity));
+	schedule = isl_schedule_constraints_compute_schedule(sc);
+	umap = isl_schedule_get_map(schedule);
+	isl_schedule_free(schedule);
+	validity = isl_union_map_apply_domain(validity,
+						isl_union_map_copy(umap));
+	validity = isl_union_map_apply_range(validity, umap);
+	map = isl_map_from_union_map(validity);
+	ge = isl_map_lex_ge(isl_space_domain(isl_map_get_space(map)));
+	map = isl_map_intersect(map, ge);
+	empty = isl_map_is_empty(map);
+	isl_map_free(map);
+
+	if (empty < 0)
+		return -1;
+	if (!empty)
+		isl_die(ctx, isl_error_unknown,
+			"conditional validity constraints not satisfied",
+			return -1);
+
+	return 0;
+}
+
+/* Input for testing of schedule construction based on
+ * conditional constraints.
+ *
+ * domain is the iteration domain
+ * flow are the flow dependences, which determine the validity and
+ * 	proximity constraints
+ * condition are the conditions on the conditional validity constraints
+ * conditional_validity are the conditional validity constraints
+ * outer_band_n is the expected number of members in the outer band
+ */
+struct {
+	const char *domain;
+	const char *flow;
+	const char *condition;
+	const char *conditional_validity;
+	int outer_band_n;
+} live_range_tests[] = {
+	/* Contrived example that illustrates that we need to keep
+	 * track of tagged condition dependences and
+	 * tagged conditional validity dependences
+	 * in isl_sched_edge separately.
+	 * In particular, the conditional validity constraints on A
+	 * cannot be satisfied,
+	 * but they can be ignored because there are no corresponding
+	 * condition constraints.  However, we do have an additional
+	 * conditional validity constraint that maps to the same
+	 * dependence relation
+	 * as the condition constraint on B.  If we did not make a distinction
+	 * between tagged condition and tagged conditional validity
+	 * dependences, then we
+	 * could end up treating this shared dependence as an condition
+	 * constraint on A, forcing a localization of the conditions,
+	 * which is impossible.
+	 */
+	{ "{ S[i] : 0 <= 1 < 100; T[i] : 0 <= 1 < 100 }",
+	  "{ S[i] -> S[i+1] : 0 <= i < 99 }",
+	  "{ [S[i] -> B[]] -> [S[i+1] -> B[]] : 0 <= i < 99 }",
+	  "{ [S[i] -> A[]] -> [T[i'] -> A[]] : 0 <= i', i < 100 and i != i';"
+	    "[T[i] -> A[]] -> [S[i'] -> A[]] : 0 <= i', i < 100 and i != i';"
+	    "[S[i] -> A[]] -> [S[i+1] -> A[]] : 0 <= i < 99 }",
+	  1
+	},
+	/* TACO 2013 Fig. 7 */
+	{ "[n] -> { S1[i,j] : 0 <= i,j < n; S2[i,j] : 0 <= i,j < n }",
+	  "[n] -> { S1[i,j] -> S2[i,j] : 0 <= i,j < n;"
+		   "S2[i,j] -> S2[i,j+1] : 0 <= i < n and 0 <= j < n - 1 }",
+	  "[n] -> { [S1[i,j] -> t[]] -> [S2[i,j] -> t[]] : 0 <= i,j < n;"
+		   "[S2[i,j] -> x1[]] -> [S2[i,j+1] -> x1[]] : "
+				"0 <= i < n and 0 <= j < n - 1 }",
+	  "[n] -> { [S2[i,j] -> t[]] -> [S1[i,j'] -> t[]] : "
+				"0 <= i < n and 0 <= j < j' < n;"
+		   "[S2[i,j] -> t[]] -> [S1[i',j'] -> t[]] : "
+				"0 <= i < i' < n and 0 <= j,j' < n;"
+		   "[S2[i,j] -> x1[]] -> [S2[i,j'] -> x1[]] : "
+				"0 <= i,j,j' < n and j < j' }",
+	    2
+	},
+	/* TACO 2013 Fig. 7, without tags */
+	{ "[n] -> { S1[i,j] : 0 <= i,j < n; S2[i,j] : 0 <= i,j < n }",
+	  "[n] -> { S1[i,j] -> S2[i,j] : 0 <= i,j < n;"
+		   "S2[i,j] -> S2[i,j+1] : 0 <= i < n and 0 <= j < n - 1 }",
+	  "[n] -> { S1[i,j] -> S2[i,j] : 0 <= i,j < n;"
+		   "S2[i,j] -> S2[i,j+1] : 0 <= i < n and 0 <= j < n - 1 }",
+	  "[n] -> { S2[i,j] -> S1[i,j'] : 0 <= i < n and 0 <= j < j' < n;"
+		   "S2[i,j] -> S1[i',j'] : 0 <= i < i' < n and 0 <= j,j' < n;"
+		   "S2[i,j] -> S2[i,j'] : 0 <= i,j,j' < n and j < j' }",
+	   1
+	},
+	/* TACO 2013 Fig. 12 */
+	{ "{ S1[i,0] : 0 <= i <= 1; S2[i,j] : 0 <= i <= 1 and 1 <= j <= 2;"
+	    "S3[i,3] : 0 <= i <= 1 }",
+	  "{ S1[i,0] -> S2[i,1] : 0 <= i <= 1;"
+	    "S2[i,1] -> S2[i,2] : 0 <= i <= 1;"
+	    "S2[i,2] -> S3[i,3] : 0 <= i <= 1 }",
+	  "{ [S1[i,0]->t[]] -> [S2[i,1]->t[]] : 0 <= i <= 1;"
+	    "[S2[i,1]->t[]] -> [S2[i,2]->t[]] : 0 <= i <= 1;"
+	    "[S2[i,2]->t[]] -> [S3[i,3]->t[]] : 0 <= i <= 1 }",
+	  "{ [S2[i,1]->t[]] -> [S2[i,2]->t[]] : 0 <= i <= 1;"
+	    "[S2[0,j]->t[]] -> [S2[1,j']->t[]] : 1 <= j,j' <= 2;"
+	    "[S2[0,j]->t[]] -> [S1[1,0]->t[]] : 1 <= j <= 2;"
+	    "[S3[0,3]->t[]] -> [S2[1,j]->t[]] : 1 <= j <= 2;"
+	    "[S3[0,3]->t[]] -> [S1[1,0]->t[]] }",
+	   1
+	}
+};
+
+/* Test schedule construction based on conditional constraints.
+ * In particular, check the number of members in the outer band node
+ * as an indication of whether tiling is possible or not.
+ */
+static int test_conditional_schedule_constraints(isl_ctx *ctx)
+{
+	int i;
+	isl_union_set *domain;
+	isl_union_map *condition;
+	isl_union_map *flow;
+	isl_union_map *validity;
+	isl_schedule_constraints *sc;
+	isl_schedule *schedule;
+	isl_schedule_node *node;
+	int n_member;
+
+	if (test_special_conditional_schedule_constraints(ctx) < 0)
+		return -1;
+	if (test_special_conditional_schedule_constraints_2(ctx) < 0)
+		return -1;
+
+	for (i = 0; i < ARRAY_SIZE(live_range_tests); ++i) {
+		domain = isl_union_set_read_from_str(ctx,
+				live_range_tests[i].domain);
+		flow = isl_union_map_read_from_str(ctx,
+				live_range_tests[i].flow);
+		condition = isl_union_map_read_from_str(ctx,
+				live_range_tests[i].condition);
+		validity = isl_union_map_read_from_str(ctx,
+				live_range_tests[i].conditional_validity);
+		sc = isl_schedule_constraints_on_domain(domain);
+		sc = isl_schedule_constraints_set_validity(sc,
+				isl_union_map_copy(flow));
+		sc = isl_schedule_constraints_set_proximity(sc, flow);
+		sc = isl_schedule_constraints_set_conditional_validity(sc,
+				condition, validity);
+		schedule = isl_schedule_constraints_compute_schedule(sc);
+		node = isl_schedule_get_root(schedule);
+		while (node &&
+		    isl_schedule_node_get_type(node) != isl_schedule_node_band)
+			node = isl_schedule_node_first_child(node);
+		n_member = isl_schedule_node_band_n_member(node);
+		isl_schedule_node_free(node);
+		isl_schedule_free(schedule);
+
+		if (!schedule)
+			return -1;
+		if (n_member != live_range_tests[i].outer_band_n)
+			isl_die(ctx, isl_error_unknown,
+				"unexpected number of members in outer band",
+				return -1);
+	}
+	return 0;
+}
+
+/* Check that the schedule computed for the given instance set and
+ * dependence relation strongly satisfies the dependences.
+ * In particular, check that no instance is scheduled before
+ * or together with an instance on which it depends.
+ * Earlier versions of isl would produce a schedule that
+ * only weakly satisfies the dependences.
+ */
+static int test_strongly_satisfying_schedule(isl_ctx *ctx)
+{
+	const char *domain, *dep;
+	isl_union_map *D, *schedule;
+	isl_map *map, *ge;
+	int empty;
+
+	domain = "{ B[i0, i1] : 0 <= i0 <= 1 and 0 <= i1 <= 11; "
+		    "A[i0] : 0 <= i0 <= 1 }";
+	dep = "{ B[i0, i1] -> B[i0, 1 + i1] : 0 <= i0 <= 1 and 0 <= i1 <= 10; "
+		"B[0, 11] -> A[1]; A[i0] -> B[i0, 0] : 0 <= i0 <= 1 }";
+	schedule = compute_schedule(ctx, domain, dep, dep);
+	D = isl_union_map_read_from_str(ctx, dep);
+	D = isl_union_map_apply_domain(D, isl_union_map_copy(schedule));
+	D = isl_union_map_apply_range(D, schedule);
+	map = isl_map_from_union_map(D);
+	ge = isl_map_lex_ge(isl_space_domain(isl_map_get_space(map)));
+	map = isl_map_intersect(map, ge);
+	empty = isl_map_is_empty(map);
+	isl_map_free(map);
+
+	if (empty < 0)
+		return -1;
+	if (!empty)
+		isl_die(ctx, isl_error_unknown,
+			"dependences not strongly satisfied", return -1);
+
+	return 0;
+}
+
+/* Compute a schedule for input where the instance set constraints
+ * conflict with the context constraints.
+ * Earlier versions of isl did not properly handle this situation.
+ */
+static int test_conflicting_context_schedule(isl_ctx *ctx)
+{
+	isl_union_map *schedule;
+	const char *domain, *context;
+
+	domain = "[n] -> { A[] : n >= 0 }";
+	context = "[n] -> { : n < 0 }";
+	schedule = compute_schedule_with_context(ctx,
+						domain, "{}", "{}", context);
+	isl_union_map_free(schedule);
+
+	if (!schedule)
+		return -1;
+
+	return 0;
+}
+
+/* Check that the dependence carrying step is not confused by
+ * a bound on the coefficient size.
+ * In particular, force the scheduler to move to a dependence carrying
+ * step by demanding outer coincidence and bound the size of
+ * the coefficients.  Earlier versions of isl would take this
+ * bound into account while carrying dependences, breaking
+ * fundamental assumptions.
+ * On the other hand, the dependence carrying step now tries
+ * to prevent loop coalescing by default, so check that indeed
+ * no loop coalescing occurs by comparing the computed schedule
+ * to the expected non-coalescing schedule.
+ */
+static int test_bounded_coefficients_schedule(isl_ctx *ctx)
+{
+	const char *domain, *dep;
+	isl_union_set *I;
+	isl_union_map *D;
+	isl_schedule_constraints *sc;
+	isl_schedule *schedule;
+	isl_union_map *sched1, *sched2;
+	isl_bool equal;
+
+	domain = "{ C[i0, i1] : 2 <= i0 <= 3999 and 0 <= i1 <= -1 + i0 }";
+	dep = "{ C[i0, i1] -> C[i0, 1 + i1] : i0 <= 3999 and i1 >= 0 and "
+						"i1 <= -2 + i0; "
+		"C[i0, -1 + i0] -> C[1 + i0, 0] : i0 <= 3998 and i0 >= 1 }";
+	I = isl_union_set_read_from_str(ctx, domain);
+	D = isl_union_map_read_from_str(ctx, dep);
+	sc = isl_schedule_constraints_on_domain(I);
+	sc = isl_schedule_constraints_set_validity(sc, isl_union_map_copy(D));
+	sc = isl_schedule_constraints_set_coincidence(sc, D);
+	isl_options_set_schedule_outer_coincidence(ctx, 1);
+	isl_options_set_schedule_max_coefficient(ctx, 20);
+	schedule = isl_schedule_constraints_compute_schedule(sc);
+	isl_options_set_schedule_max_coefficient(ctx, -1);
+	isl_options_set_schedule_outer_coincidence(ctx, 0);
+	sched1 = isl_schedule_get_map(schedule);
+	isl_schedule_free(schedule);
+
+	sched2 = isl_union_map_read_from_str(ctx, "{ C[x,y] -> [x,y] }");
+	equal = isl_union_map_is_equal(sched1, sched2);
+	isl_union_map_free(sched1);
+	isl_union_map_free(sched2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected schedule", return -1);
+
+	return 0;
+}
+
+/* Check that the bounds on the coefficients are respected.
+ * This function checks for a particular output schedule,
+ * but the exact output is not important, only that it does
+ * not contain any coefficients greater than 4.
+ * It is, however, easier to check for a particular output.
+ * This test is only run for the whole component scheduler
+ * because the incremental scheduler produces a slightly different schedule.
+ */
+static int test_bounded_coefficients_schedule_whole(isl_ctx *ctx)
+{
+	const char *domain, *dep, *str;
+	isl_union_set *I;
+	isl_union_map *D;
+	isl_schedule_constraints *sc;
+	isl_schedule *schedule;
+	isl_union_map *sched1, *sched2;
+	isl_bool equal;
+
+	domain = "{ S_4[i, j, k] : 0 <= i < j <= 10 and 0 <= k <= 100; "
+	    "S_2[i, j] : 0 <= i < j <= 10; S_6[i, j] : 0 <= i < j <= 10 }";
+	dep = "{ S_2[0, j] -> S_4[0, j, 0] : 0 < j <= 10; "
+	    "S_4[0, j, 100] -> S_6[0, j] : 0 < j <= 10 }";
+	I = isl_union_set_read_from_str(ctx, domain);
+	D = isl_union_map_read_from_str(ctx, dep);
+	sc = isl_schedule_constraints_on_domain(I);
+	sc = isl_schedule_constraints_set_validity(sc, D);
+	isl_options_set_schedule_max_constant_term(ctx, 10);
+	isl_options_set_schedule_max_coefficient(ctx, 4);
+	schedule = isl_schedule_constraints_compute_schedule(sc);
+	isl_options_set_schedule_max_coefficient(ctx, -1);
+	isl_options_set_schedule_max_constant_term(ctx, -1);
+	sched1 = isl_schedule_get_map(schedule);
+	isl_schedule_free(schedule);
+
+	str = "{ S_4[i, j, k] -> [i, j, 10 - k, 1]; "
+	    "S_2[i, j] -> [0, i, j, 0]; S_6[i, j] -> [0, 10 + i, j, 2] }";
+	sched2 = isl_union_map_read_from_str(ctx, str);
+	equal = isl_union_map_is_equal(sched1, sched2);
+	isl_union_map_free(sched1);
+	isl_union_map_free(sched2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected schedule", return -1);
+
+	return 0;
+}
+
+/* Check that a set of schedule constraints that only allow for
+ * a coalescing schedule still produces a schedule even if the user
+ * request a non-coalescing schedule.  Earlier versions of isl
+ * would not handle this case correctly.
+ */
+static int test_coalescing_schedule(isl_ctx *ctx)
+{
+	const char *domain, *dep;
+	isl_union_set *I;
+	isl_union_map *D;
+	isl_schedule_constraints *sc;
+	isl_schedule *schedule;
+	int treat_coalescing;
+
+	domain = "{ S[a, b] : 0 <= a <= 1 and 0 <= b <= 1 }";
+	dep = "{ S[a, b] -> S[a + b, 1 - b] }";
+	I = isl_union_set_read_from_str(ctx, domain);
+	D = isl_union_map_read_from_str(ctx, dep);
+	sc = isl_schedule_constraints_on_domain(I);
+	sc = isl_schedule_constraints_set_validity(sc, D);
+	treat_coalescing = isl_options_get_schedule_treat_coalescing(ctx);
+	isl_options_set_schedule_treat_coalescing(ctx, 1);
+	schedule = isl_schedule_constraints_compute_schedule(sc);
+	isl_options_set_schedule_treat_coalescing(ctx, treat_coalescing);
+	isl_schedule_free(schedule);
+	if (!schedule)
+		return -1;
+	return 0;
+}
+
+/* Check that the scheduler does not perform any needless
+ * compound skewing.  Earlier versions of isl would compute
+ * schedules in terms of transformed schedule coefficients and
+ * would not accurately keep track of the sum of the original
+ * schedule coefficients.  It could then produce the schedule
+ * S[t,i,j,k] -> [t, 2t + i, 2t + i + j, 2t + i + j + k]
+ * for the input below instead of the schedule below.
+ */
+static int test_skewing_schedule(isl_ctx *ctx)
+{
+	const char *D, *V, *P, *S;
+
+	D = "[n] -> { S[t,i,j,k] : 0 <= t,i,j,k < n }";
+	V = "[n] -> { S[t,i,j,k] -> S[t+1,a,b,c] : 0 <= t,i,j,k,a,b,c < n and "
+		"-2 <= a-i <= 2 and -1 <= a-i + b-j <= 1 and "
+		"-1 <= a-i + b-j + c-k <= 1 }";
+	P = "{ }";
+	S = "{ S[t,i,j,k] -> [t, 2t + i, t + i + j, 2t + k] }";
+
+	return test_special_schedule(ctx, D, V, P, S);
+}
+
+int test_schedule(isl_ctx *ctx)
+{
+	const char *D, *W, *R, *V, *P, *S;
+	int max_coincidence;
+	int treat_coalescing;
+
+	/* Handle resulting schedule with zero bands. */
+	if (test_one_schedule(ctx, "{[]}", "{}", "{}", "{[] -> []}", 0, 0) < 0)
+		return -1;
+
+	/* Jacobi */
+	D = "[T,N] -> { S1[t,i] : 1 <= t <= T and 2 <= i <= N - 1 }";
+	W = "{ S1[t,i] -> a[t,i] }";
+	R = "{ S1[t,i] -> a[t-1,i]; S1[t,i] -> a[t-1,i-1]; "
+	    	"S1[t,i] -> a[t-1,i+1] }";
+	S = "{ S1[t,i] -> [t,i] }";
+	if (test_one_schedule(ctx, D, W, R, S, 2, 0) < 0)
+		return -1;
+
+	/* Fig. 5 of CC2008 */
+	D = "[N] -> { S_0[i, j] : i >= 0 and i <= -1 + N and j >= 2 and "
+				"j <= -1 + N }";
+	W = "[N] -> { S_0[i, j] -> a[i, j] : i >= 0 and i <= -1 + N and "
+				"j >= 2 and j <= -1 + N }";
+	R = "[N] -> { S_0[i, j] -> a[j, i] : i >= 0 and i <= -1 + N and "
+				"j >= 2 and j <= -1 + N; "
+		    "S_0[i, j] -> a[i, -1 + j] : i >= 0 and i <= -1 + N and "
+				"j >= 2 and j <= -1 + N }";
+	S = "[N] -> { S_0[i, j] -> [0, i, 0, j, 0] }";
+	if (test_one_schedule(ctx, D, W, R, S, 2, 0) < 0)
+		return -1;
+
+	D = "{ S1[i] : 0 <= i <= 10; S2[i] : 0 <= i <= 9 }";
+	W = "{ S1[i] -> a[i] }";
+	R = "{ S2[i] -> a[i+1] }";
+	S = "{ S1[i] -> [0,i]; S2[i] -> [1,i] }";
+	if (test_one_schedule(ctx, D, W, R, S, 1, 1) < 0)
+		return -1;
+
+	D = "{ S1[i] : 0 <= i < 10; S2[i] : 0 <= i < 10 }";
+	W = "{ S1[i] -> a[i] }";
+	R = "{ S2[i] -> a[9-i] }";
+	S = "{ S1[i] -> [0,i]; S2[i] -> [1,i] }";
+	if (test_one_schedule(ctx, D, W, R, S, 1, 1) < 0)
+		return -1;
+
+	D = "[N] -> { S1[i] : 0 <= i < N; S2[i] : 0 <= i < N }";
+	W = "{ S1[i] -> a[i] }";
+	R = "[N] -> { S2[i] -> a[N-1-i] }";
+	S = "{ S1[i] -> [0,i]; S2[i] -> [1,i] }";
+	if (test_one_schedule(ctx, D, W, R, S, 1, 1) < 0)
+		return -1;
+	
+	D = "{ S1[i] : 0 < i < 10; S2[i] : 0 <= i < 10 }";
+	W = "{ S1[i] -> a[i]; S2[i] -> b[i] }";
+	R = "{ S2[i] -> a[i]; S1[i] -> b[i-1] }";
+	S = "{ S1[i] -> [i,0]; S2[i] -> [i,1] }";
+	if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+		return -1;
+
+	D = "[N] -> { S1[i] : 1 <= i <= N; S2[i,j] : 1 <= i,j <= N }";
+	W = "{ S1[i] -> a[0,i]; S2[i,j] -> a[i,j] }";
+	R = "{ S2[i,j] -> a[i-1,j] }";
+	S = "{ S1[i] -> [0,i,0]; S2[i,j] -> [1,i,j] }";
+	if (test_one_schedule(ctx, D, W, R, S, 2, 1) < 0)
+		return -1;
+
+	D = "[N] -> { S1[i] : 1 <= i <= N; S2[i,j] : 1 <= i,j <= N }";
+	W = "{ S1[i] -> a[i,0]; S2[i,j] -> a[i,j] }";
+	R = "{ S2[i,j] -> a[i,j-1] }";
+	S = "{ S1[i] -> [0,i,0]; S2[i,j] -> [1,i,j] }";
+	if (test_one_schedule(ctx, D, W, R, S, 2, 1) < 0)
+		return -1;
+
+	D = "[N] -> { S_0[]; S_1[i] : i >= 0 and i <= -1 + N; S_2[] }";
+	W = "[N] -> { S_0[] -> a[0]; S_2[] -> b[0]; "
+		    "S_1[i] -> a[1 + i] : i >= 0 and i <= -1 + N }";
+	R = "[N] -> { S_2[] -> a[N]; S_1[i] -> a[i] : i >= 0 and i <= -1 + N }";
+	S = "[N] -> { S_1[i] -> [1, i, 0]; S_2[] -> [2, 0, 1]; "
+		    "S_0[] -> [0, 0, 0] }";
+	if (test_one_schedule(ctx, D, W, R, S, 1, 0) < 0)
+		return -1;
+	ctx->opt->schedule_parametric = 0;
+	if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+		return -1;
+	ctx->opt->schedule_parametric = 1;
+
+	D = "[N] -> { S1[i] : 1 <= i <= N; S2[i] : 1 <= i <= N; "
+		    "S3[i,j] : 1 <= i,j <= N; S4[i] : 1 <= i <= N }";
+	W = "{ S1[i] -> a[i,0]; S2[i] -> a[0,i]; S3[i,j] -> a[i,j] }";
+	R = "[N] -> { S3[i,j] -> a[i-1,j]; S3[i,j] -> a[i,j-1]; "
+		    "S4[i] -> a[i,N] }";
+	S = "{ S1[i] -> [0,i,0]; S2[i] -> [1,i,0]; S3[i,j] -> [2,i,j]; "
+		"S4[i] -> [4,i,0] }";
+	max_coincidence = isl_options_get_schedule_maximize_coincidence(ctx);
+	isl_options_set_schedule_maximize_coincidence(ctx, 0);
+	if (test_one_schedule(ctx, D, W, R, S, 2, 0) < 0)
+		return -1;
+	isl_options_set_schedule_maximize_coincidence(ctx, max_coincidence);
+
+	D = "[N] -> { S_0[i, j] : i >= 1 and i <= N and j >= 1 and j <= N }";
+	W = "[N] -> { S_0[i, j] -> s[0] : i >= 1 and i <= N and j >= 1 and "
+					"j <= N }";
+	R = "[N] -> { S_0[i, j] -> s[0] : i >= 1 and i <= N and j >= 1 and "
+					"j <= N; "
+		    "S_0[i, j] -> a[i, j] : i >= 1 and i <= N and j >= 1 and "
+					"j <= N }";
+	S = "[N] -> { S_0[i, j] -> [0, i, 0, j, 0] }";
+	if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+		return -1;
+
+	D = "[N] -> { S_0[t] : t >= 0 and t <= -1 + N; "
+		    " S_2[t] : t >= 0 and t <= -1 + N; "
+		    " S_1[t, i] : t >= 0 and t <= -1 + N and i >= 0 and "
+				"i <= -1 + N }";
+	W = "[N] -> { S_0[t] -> a[t, 0] : t >= 0 and t <= -1 + N; "
+		    " S_2[t] -> b[t] : t >= 0 and t <= -1 + N; "
+		    " S_1[t, i] -> a[t, 1 + i] : t >= 0 and t <= -1 + N and "
+						"i >= 0 and i <= -1 + N }";
+	R = "[N] -> { S_1[t, i] -> a[t, i] : t >= 0 and t <= -1 + N and "
+					    "i >= 0 and i <= -1 + N; "
+		    " S_2[t] -> a[t, N] : t >= 0 and t <= -1 + N }";
+	S = "[N] -> { S_2[t] -> [0, t, 2]; S_1[t, i] -> [0, t, 1, i, 0]; "
+		    " S_0[t] -> [0, t, 0] }";
+
+	if (test_one_schedule(ctx, D, W, R, S, 2, 1) < 0)
+		return -1;
+	ctx->opt->schedule_parametric = 0;
+	if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+		return -1;
+	ctx->opt->schedule_parametric = 1;
+
+	D = "[N] -> { S1[i,j] : 0 <= i,j < N; S2[i,j] : 0 <= i,j < N }";
+	S = "{ S1[i,j] -> [0,i,j]; S2[i,j] -> [1,i,j] }";
+	if (test_one_schedule(ctx, D, "{}", "{}", S, 2, 2) < 0)
+		return -1;
+
+	D = "[M, N] -> { S_1[i] : i >= 0 and i <= -1 + M; "
+	    "S_0[i, j] : i >= 0 and i <= -1 + M and j >= 0 and j <= -1 + N }";
+	W = "[M, N] -> { S_0[i, j] -> a[j] : i >= 0 and i <= -1 + M and "
+					    "j >= 0 and j <= -1 + N; "
+			"S_1[i] -> b[0] : i >= 0 and i <= -1 + M }";
+	R = "[M, N] -> { S_0[i, j] -> a[0] : i >= 0 and i <= -1 + M and "
+					    "j >= 0 and j <= -1 + N; "
+			"S_1[i] -> b[0] : i >= 0 and i <= -1 + M }";
+	S = "[M, N] -> { S_1[i] -> [1, i, 0]; S_0[i, j] -> [0, i, 0, j, 0] }";
+	if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+		return -1;
+
+	D = "{ S_0[i] : i >= 0 }";
+	W = "{ S_0[i] -> a[i] : i >= 0 }";
+	R = "{ S_0[i] -> a[0] : i >= 0 }";
+	S = "{ S_0[i] -> [0, i, 0] }";
+	if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+		return -1;
+
+	D = "{ S_0[i] : i >= 0; S_1[i] : i >= 0 }";
+	W = "{ S_0[i] -> a[i] : i >= 0; S_1[i] -> b[i] : i >= 0 }";
+	R = "{ S_0[i] -> b[0] : i >= 0; S_1[i] -> a[i] : i >= 0 }";
+	S = "{ S_1[i] -> [0, i, 1]; S_0[i] -> [0, i, 0] }";
+	if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+		return -1;
+
+	D = "[n] -> { S_0[j, k] : j <= -1 + n and j >= 0 and "
+				"k <= -1 + n and k >= 0 }";
+	W = "[n] -> { S_0[j, k] -> B[j] : j <= -1 + n and j >= 0 and "							"k <= -1 + n and k >= 0 }";
+	R = "[n] -> { S_0[j, k] -> B[j] : j <= -1 + n and j >= 0 and "
+					"k <= -1 + n and k >= 0; "
+		    "S_0[j, k] -> B[k] : j <= -1 + n and j >= 0 and "
+					"k <= -1 + n and k >= 0; "
+		    "S_0[j, k] -> A[k] : j <= -1 + n and j >= 0 and "
+					"k <= -1 + n and k >= 0 }";
+	S = "[n] -> { S_0[j, k] -> [2, j, k] }";
+	ctx->opt->schedule_outer_coincidence = 1;
+	if (test_one_schedule(ctx, D, W, R, S, 0, 0) < 0)
+		return -1;
+	ctx->opt->schedule_outer_coincidence = 0;
+
+	D = "{Stmt_for_body24[i0, i1, i2, i3]:"
+		"i0 >= 0 and i0 <= 1 and i1 >= 0 and i1 <= 6 and i2 >= 2 and "
+		"i2 <= 6 - i1 and i3 >= 0 and i3 <= -1 + i2;"
+	     "Stmt_for_body24[i0, i1, 1, 0]:"
+		"i0 >= 0 and i0 <= 1 and i1 >= 0 and i1 <= 5;"
+	     "Stmt_for_body7[i0, i1, i2]:"
+		"i0 >= 0 and i0 <= 1 and i1 >= 0 and i1 <= 7 and i2 >= 0 and "
+		"i2 <= 7 }";
+
+	V = "{Stmt_for_body24[0, i1, i2, i3] -> "
+		"Stmt_for_body24[1, i1, i2, i3]:"
+		"i3 >= 0 and i3 <= -1 + i2 and i1 >= 0 and i2 <= 6 - i1 and "
+		"i2 >= 1;"
+	     "Stmt_for_body24[0, i1, i2, i3] -> "
+		"Stmt_for_body7[1, 1 + i1 + i3, 1 + i1 + i2]:"
+		"i3 <= -1 + i2 and i2 <= 6 - i1 and i2 >= 1 and i1 >= 0 and "
+		"i3 >= 0;"
+	      "Stmt_for_body24[0, i1, i2, i3] ->"
+		"Stmt_for_body7[1, i1, 1 + i1 + i3]:"
+		"i3 >= 0 and i2 <= 6 - i1 and i1 >= 0 and i3 <= -1 + i2;"
+	      "Stmt_for_body7[0, i1, i2] -> Stmt_for_body7[1, i1, i2]:"
+		"(i2 >= 1 + i1 and i2 <= 6 and i1 >= 0 and i1 <= 4) or "
+		"(i2 >= 3 and i2 <= 7 and i1 >= 1 and i2 >= 1 + i1) or "
+		"(i2 >= 0 and i2 <= i1 and i2 >= -7 + i1 and i1 <= 7);"
+	      "Stmt_for_body7[0, i1, 1 + i1] -> Stmt_for_body7[1, i1, 1 + i1]:"
+		"i1 <= 6 and i1 >= 0;"
+	      "Stmt_for_body7[0, 0, 7] -> Stmt_for_body7[1, 0, 7];"
+	      "Stmt_for_body7[i0, i1, i2] -> "
+		"Stmt_for_body24[i0, o1, -1 + i2 - o1, -1 + i1 - o1]:"
+		"i0 >= 0 and i0 <= 1 and o1 >= 0 and i2 >= 1 + i1 and "
+		"o1 <= -2 + i2 and i2 <= 7 and o1 <= -1 + i1;"
+	      "Stmt_for_body7[i0, i1, i2] -> "
+		"Stmt_for_body24[i0, i1, o2, -1 - i1 + i2]:"
+		"i0 >= 0 and i0 <= 1 and i1 >= 0 and o2 >= -i1 + i2 and "
+		"o2 >= 1 and o2 <= 6 - i1 and i2 >= 1 + i1 }";
+	P = V;
+
+	treat_coalescing = isl_options_get_schedule_treat_coalescing(ctx);
+	isl_options_set_schedule_treat_coalescing(ctx, 0);
+	if (test_has_schedule(ctx, D, V, P) < 0)
+		return -1;
+	isl_options_set_schedule_treat_coalescing(ctx, treat_coalescing);
+
+	D = "{ S_0[i, j] : i >= 1 and i <= 10 and j >= 1 and j <= 8 }";
+	V = "{ S_0[i, j] -> S_0[i, 1 + j] : i >= 1 and i <= 10 and "
+					   "j >= 1 and j <= 7;"
+		"S_0[i, j] -> S_0[1 + i, j] : i >= 1 and i <= 9 and "
+					     "j >= 1 and j <= 8 }";
+	P = "{ }";
+	S = "{ S_0[i, j] -> [i + j, i] }";
+	ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_FEAUTRIER;
+	if (test_special_schedule(ctx, D, V, P, S) < 0)
+		return -1;
+	ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_ISL;
+
+	/* Fig. 1 from Feautrier's "Some Efficient Solutions..." pt. 2, 1992 */
+	D = "[N] -> { S_0[i, j] : i >= 0 and i <= -1 + N and "
+				 "j >= 0 and j <= -1 + i }";
+	V = "[N] -> { S_0[i, j] -> S_0[i, 1 + j] : j <= -2 + i and "
+					"i <= -1 + N and j >= 0;"
+		     "S_0[i, -1 + i] -> S_0[1 + i, 0] : i >= 1 and "
+					"i <= -2 + N }";
+	P = "{ }";
+	S = "{ S_0[i, j] -> [i, j] }";
+	ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_FEAUTRIER;
+	if (test_special_schedule(ctx, D, V, P, S) < 0)
+		return -1;
+	ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_ISL;
+
+	/* Test both algorithms on a case with only proximity dependences. */
+	D = "{ S[i,j] : 0 <= i <= 10 }";
+	V = "{ }";
+	P = "{ S[i,j] -> S[i+1,j] : 0 <= i,j <= 10 }";
+	S = "{ S[i, j] -> [j, i] }";
+	ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_FEAUTRIER;
+	if (test_special_schedule(ctx, D, V, P, S) < 0)
+		return -1;
+	ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_ISL;
+	if (test_special_schedule(ctx, D, V, P, S) < 0)
+		return -1;
+	
+	D = "{ A[a]; B[] }";
+	V = "{}";
+	P = "{ A[a] -> B[] }";
+	if (test_has_schedule(ctx, D, V, P) < 0)
+		return -1;
+
+	if (test_padded_schedule(ctx) < 0)
+		return -1;
+
+	/* Check that check for progress is not confused by rational
+	 * solution.
+	 */
+	D = "[N] -> { S0[i, j] : i >= 0 and i <= N and j >= 0 and j <= N }";
+	V = "[N] -> { S0[i0, -1 + N] -> S0[2 + i0, 0] : i0 >= 0 and "
+							"i0 <= -2 + N; "
+			"S0[i0, i1] -> S0[i0, 1 + i1] : i0 >= 0 and "
+				"i0 <= N and i1 >= 0 and i1 <= -1 + N }";
+	P = "{}";
+	ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_FEAUTRIER;
+	if (test_has_schedule(ctx, D, V, P) < 0)
+		return -1;
+	ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_ISL;
+
+	/* Check that we allow schedule rows that are only non-trivial
+	 * on some full-dimensional domains.
+	 */
+	D = "{ S1[j] : 0 <= j <= 1; S0[]; S2[k] : 0 <= k <= 1 }";
+	V = "{ S0[] -> S1[j] : 0 <= j <= 1; S2[0] -> S0[];"
+		"S1[j] -> S2[1] : 0 <= j <= 1 }";
+	P = "{}";
+	ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_FEAUTRIER;
+	if (test_has_schedule(ctx, D, V, P) < 0)
+		return -1;
+	ctx->opt->schedule_algorithm = ISL_SCHEDULE_ALGORITHM_ISL;
+
+	if (test_conditional_schedule_constraints(ctx) < 0)
+		return -1;
+
+	if (test_strongly_satisfying_schedule(ctx) < 0)
+		return -1;
+
+	if (test_conflicting_context_schedule(ctx) < 0)
+		return -1;
+
+	if (test_bounded_coefficients_schedule(ctx) < 0)
+		return -1;
+	if (test_coalescing_schedule(ctx) < 0)
+		return -1;
+	if (test_skewing_schedule(ctx) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Perform scheduling tests using the whole component scheduler.
+ */
+static int test_schedule_whole(isl_ctx *ctx)
+{
+	int whole;
+	int r;
+
+	whole = isl_options_get_schedule_whole_component(ctx);
+	isl_options_set_schedule_whole_component(ctx, 1);
+	r = test_schedule(ctx);
+	if (r >= 0)
+		r = test_bounded_coefficients_schedule_whole(ctx);
+	isl_options_set_schedule_whole_component(ctx, whole);
+
+	return r;
+}
+
+/* Perform scheduling tests using the incremental scheduler.
+ */
+static int test_schedule_incremental(isl_ctx *ctx)
+{
+	int whole;
+	int r;
+
+	whole = isl_options_get_schedule_whole_component(ctx);
+	isl_options_set_schedule_whole_component(ctx, 0);
+	r = test_schedule(ctx);
+	isl_options_set_schedule_whole_component(ctx, whole);
+
+	return r;
+}
+
+int test_plain_injective(isl_ctx *ctx, const char *str, int injective)
+{
+	isl_union_map *umap;
+	int test;
+
+	umap = isl_union_map_read_from_str(ctx, str);
+	test = isl_union_map_plain_is_injective(umap);
+	isl_union_map_free(umap);
+	if (test < 0)
+		return -1;
+	if (test == injective)
+		return 0;
+	if (injective)
+		isl_die(ctx, isl_error_unknown,
+			"map not detected as injective", return -1);
+	else
+		isl_die(ctx, isl_error_unknown,
+			"map detected as injective", return -1);
+}
+
+int test_injective(isl_ctx *ctx)
+{
+	const char *str;
+
+	if (test_plain_injective(ctx, "{S[i,j] -> A[0]; T[i,j] -> B[1]}", 0))
+		return -1;
+	if (test_plain_injective(ctx, "{S[] -> A[0]; T[] -> B[0]}", 1))
+		return -1;
+	if (test_plain_injective(ctx, "{S[] -> A[0]; T[] -> A[1]}", 1))
+		return -1;
+	if (test_plain_injective(ctx, "{S[] -> A[0]; T[] -> A[0]}", 0))
+		return -1;
+	if (test_plain_injective(ctx, "{S[i] -> A[i,0]; T[i] -> A[i,1]}", 1))
+		return -1;
+	if (test_plain_injective(ctx, "{S[i] -> A[i]; T[i] -> A[i]}", 0))
+		return -1;
+	if (test_plain_injective(ctx, "{S[] -> A[0,0]; T[] -> A[0,1]}", 1))
+		return -1;
+	if (test_plain_injective(ctx, "{S[] -> A[0,0]; T[] -> A[1,0]}", 1))
+		return -1;
+
+	str = "{S[] -> A[0,0]; T[] -> A[0,1]; U[] -> A[1,0]}";
+	if (test_plain_injective(ctx, str, 1))
+		return -1;
+	str = "{S[] -> A[0,0]; T[] -> A[0,1]; U[] -> A[0,0]}";
+	if (test_plain_injective(ctx, str, 0))
+		return -1;
+
+	return 0;
+}
+
+static int aff_plain_is_equal(__isl_keep isl_aff *aff, const char *str)
+{
+	isl_aff *aff2;
+	int equal;
+
+	if (!aff)
+		return -1;
+
+	aff2 = isl_aff_read_from_str(isl_aff_get_ctx(aff), str);
+	equal = isl_aff_plain_is_equal(aff, aff2);
+	isl_aff_free(aff2);
+
+	return equal;
+}
+
+static int aff_check_plain_equal(__isl_keep isl_aff *aff, const char *str)
+{
+	int equal;
+
+	equal = aff_plain_is_equal(aff, str);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(isl_aff_get_ctx(aff), isl_error_unknown,
+			"result not as expected", return -1);
+	return 0;
+}
+
+struct {
+	__isl_give isl_aff *(*fn)(__isl_take isl_aff *aff1,
+				__isl_take isl_aff *aff2);
+} aff_bin_op[] = {
+	['+'] = { &isl_aff_add },
+	['-'] = { &isl_aff_sub },
+	['*'] = { &isl_aff_mul },
+	['/'] = { &isl_aff_div },
+};
+
+struct {
+	const char *arg1;
+	unsigned char op;
+	const char *arg2;
+	const char *res;
+} aff_bin_tests[] = {
+	{ "{ [i] -> [i] }", '+', "{ [i] -> [i] }",
+	  "{ [i] -> [2i] }" },
+	{ "{ [i] -> [i] }", '-', "{ [i] -> [i] }",
+	  "{ [i] -> [0] }" },
+	{ "{ [i] -> [i] }", '*', "{ [i] -> [2] }",
+	  "{ [i] -> [2i] }" },
+	{ "{ [i] -> [2] }", '*', "{ [i] -> [i] }",
+	  "{ [i] -> [2i] }" },
+	{ "{ [i] -> [i] }", '/', "{ [i] -> [2] }",
+	  "{ [i] -> [i/2] }" },
+	{ "{ [i] -> [2i] }", '/', "{ [i] -> [2] }",
+	  "{ [i] -> [i] }" },
+	{ "{ [i] -> [i] }", '+', "{ [i] -> [NaN] }",
+	  "{ [i] -> [NaN] }" },
+	{ "{ [i] -> [i] }", '-', "{ [i] -> [NaN] }",
+	  "{ [i] -> [NaN] }" },
+	{ "{ [i] -> [i] }", '*', "{ [i] -> [NaN] }",
+	  "{ [i] -> [NaN] }" },
+	{ "{ [i] -> [2] }", '*', "{ [i] -> [NaN] }",
+	  "{ [i] -> [NaN] }" },
+	{ "{ [i] -> [i] }", '/', "{ [i] -> [NaN] }",
+	  "{ [i] -> [NaN] }" },
+	{ "{ [i] -> [2] }", '/', "{ [i] -> [NaN] }",
+	  "{ [i] -> [NaN] }" },
+	{ "{ [i] -> [NaN] }", '+', "{ [i] -> [i] }",
+	  "{ [i] -> [NaN] }" },
+	{ "{ [i] -> [NaN] }", '-', "{ [i] -> [i] }",
+	  "{ [i] -> [NaN] }" },
+	{ "{ [i] -> [NaN] }", '*', "{ [i] -> [2] }",
+	  "{ [i] -> [NaN] }" },
+	{ "{ [i] -> [NaN] }", '*', "{ [i] -> [i] }",
+	  "{ [i] -> [NaN] }" },
+	{ "{ [i] -> [NaN] }", '/', "{ [i] -> [2] }",
+	  "{ [i] -> [NaN] }" },
+	{ "{ [i] -> [NaN] }", '/', "{ [i] -> [i] }",
+	  "{ [i] -> [NaN] }" },
+};
+
+/* Perform some basic tests of binary operations on isl_aff objects.
+ */
+static int test_bin_aff(isl_ctx *ctx)
+{
+	int i;
+	isl_aff *aff1, *aff2, *res;
+	__isl_give isl_aff *(*fn)(__isl_take isl_aff *aff1,
+				__isl_take isl_aff *aff2);
+	int ok;
+
+	for (i = 0; i < ARRAY_SIZE(aff_bin_tests); ++i) {
+		aff1 = isl_aff_read_from_str(ctx, aff_bin_tests[i].arg1);
+		aff2 = isl_aff_read_from_str(ctx, aff_bin_tests[i].arg2);
+		res = isl_aff_read_from_str(ctx, aff_bin_tests[i].res);
+		fn = aff_bin_op[aff_bin_tests[i].op].fn;
+		aff1 = fn(aff1, aff2);
+		if (isl_aff_is_nan(res))
+			ok = isl_aff_is_nan(aff1);
+		else
+			ok = isl_aff_plain_is_equal(aff1, res);
+		isl_aff_free(aff1);
+		isl_aff_free(res);
+		if (ok < 0)
+			return -1;
+		if (!ok)
+			isl_die(ctx, isl_error_unknown,
+				"unexpected result", return -1);
+	}
+
+	return 0;
+}
+
+struct {
+	__isl_give isl_pw_aff *(*fn)(__isl_take isl_pw_aff *pa1,
+				     __isl_take isl_pw_aff *pa2);
+} pw_aff_bin_op[] = {
+	['m'] = { &isl_pw_aff_min },
+	['M'] = { &isl_pw_aff_max },
+};
+
+/* Inputs for binary isl_pw_aff operation tests.
+ * "arg1" and "arg2" are the two arguments, "op" identifies the operation
+ * defined by pw_aff_bin_op, and "res" is the expected result.
+ */
+struct {
+	const char *arg1;
+	unsigned char op;
+	const char *arg2;
+	const char *res;
+} pw_aff_bin_tests[] = {
+	{ "{ [i] -> [i] }", 'm', "{ [i] -> [i] }",
+	  "{ [i] -> [i] }" },
+	{ "{ [i] -> [i] }", 'M', "{ [i] -> [i] }",
+	  "{ [i] -> [i] }" },
+	{ "{ [i] -> [i] }", 'm', "{ [i] -> [0] }",
+	  "{ [i] -> [i] : i <= 0; [i] -> [0] : i > 0 }" },
+	{ "{ [i] -> [i] }", 'M', "{ [i] -> [0] }",
+	  "{ [i] -> [i] : i >= 0; [i] -> [0] : i < 0 }" },
+	{ "{ [i] -> [i] }", 'm', "{ [i] -> [NaN] }",
+	  "{ [i] -> [NaN] }" },
+	{ "{ [i] -> [NaN] }", 'm', "{ [i] -> [i] }",
+	  "{ [i] -> [NaN] }" },
+};
+
+/* Perform some basic tests of binary operations on isl_pw_aff objects.
+ */
+static int test_bin_pw_aff(isl_ctx *ctx)
+{
+	int i;
+	isl_bool ok;
+	isl_pw_aff *pa1, *pa2, *res;
+
+	for (i = 0; i < ARRAY_SIZE(pw_aff_bin_tests); ++i) {
+		pa1 = isl_pw_aff_read_from_str(ctx, pw_aff_bin_tests[i].arg1);
+		pa2 = isl_pw_aff_read_from_str(ctx, pw_aff_bin_tests[i].arg2);
+		res = isl_pw_aff_read_from_str(ctx, pw_aff_bin_tests[i].res);
+		pa1 = pw_aff_bin_op[pw_aff_bin_tests[i].op].fn(pa1, pa2);
+		if (isl_pw_aff_involves_nan(res))
+			ok = isl_pw_aff_involves_nan(pa1);
+		else
+			ok = isl_pw_aff_plain_is_equal(pa1, res);
+		isl_pw_aff_free(pa1);
+		isl_pw_aff_free(res);
+		if (ok < 0)
+			return -1;
+		if (!ok)
+			isl_die(ctx, isl_error_unknown,
+				"unexpected result", return -1);
+	}
+
+	return 0;
+}
+
+struct {
+	__isl_give isl_union_pw_multi_aff *(*fn)(
+		__isl_take isl_union_pw_multi_aff *upma1,
+		__isl_take isl_union_pw_multi_aff *upma2);
+	const char *arg1;
+	const char *arg2;
+	const char *res;
+} upma_bin_tests[] = {
+	{ &isl_union_pw_multi_aff_add, "{ A[] -> [0]; B[0] -> [1] }",
+	  "{ B[x] -> [2] : x >= 0 }", "{ B[0] -> [3] }" },
+	{ &isl_union_pw_multi_aff_union_add, "{ A[] -> [0]; B[0] -> [1] }",
+	  "{ B[x] -> [2] : x >= 0 }",
+	  "{ A[] -> [0]; B[0] -> [3]; B[x] -> [2] : x >= 1 }" },
+	{ &isl_union_pw_multi_aff_pullback_union_pw_multi_aff,
+	  "{ A[] -> B[0]; C[x] -> B[1] : x < 10; C[y] -> B[2] : y >= 10 }",
+	  "{ D[i] -> A[] : i < 0; D[i] -> C[i + 5] : i >= 0 }",
+	  "{ D[i] -> B[0] : i < 0; D[i] -> B[1] : 0 <= i < 5; "
+	    "D[i] -> B[2] : i >= 5 }" },
+	{ &isl_union_pw_multi_aff_union_add, "{ B[x] -> A[1] : x <= 0 }",
+	  "{ B[x] -> C[2] : x > 0 }",
+	  "{ B[x] -> A[1] : x <= 0; B[x] -> C[2] : x > 0 }" },
+	{ &isl_union_pw_multi_aff_union_add, "{ B[x] -> A[1] : x <= 0 }",
+	  "{ B[x] -> A[2] : x >= 0 }",
+	  "{ B[x] -> A[1] : x < 0; B[x] -> A[2] : x > 0; B[0] -> A[3] }" },
+};
+
+/* Perform some basic tests of binary operations on
+ * isl_union_pw_multi_aff objects.
+ */
+static int test_bin_upma(isl_ctx *ctx)
+{
+	int i;
+	isl_union_pw_multi_aff *upma1, *upma2, *res;
+	int ok;
+
+	for (i = 0; i < ARRAY_SIZE(upma_bin_tests); ++i) {
+		upma1 = isl_union_pw_multi_aff_read_from_str(ctx,
+							upma_bin_tests[i].arg1);
+		upma2 = isl_union_pw_multi_aff_read_from_str(ctx,
+							upma_bin_tests[i].arg2);
+		res = isl_union_pw_multi_aff_read_from_str(ctx,
+							upma_bin_tests[i].res);
+		upma1 = upma_bin_tests[i].fn(upma1, upma2);
+		ok = isl_union_pw_multi_aff_plain_is_equal(upma1, res);
+		isl_union_pw_multi_aff_free(upma1);
+		isl_union_pw_multi_aff_free(res);
+		if (ok < 0)
+			return -1;
+		if (!ok)
+			isl_die(ctx, isl_error_unknown,
+				"unexpected result", return -1);
+	}
+
+	return 0;
+}
+
+struct {
+	__isl_give isl_union_pw_multi_aff *(*fn)(
+		__isl_take isl_union_pw_multi_aff *upma1,
+		__isl_take isl_union_pw_multi_aff *upma2);
+	const char *arg1;
+	const char *arg2;
+} upma_bin_fail_tests[] = {
+	{ &isl_union_pw_multi_aff_union_add, "{ B[x] -> A[1] : x <= 0 }",
+	  "{ B[x] -> C[2] : x >= 0 }" },
+};
+
+/* Perform some basic tests of binary operations on
+ * isl_union_pw_multi_aff objects that are expected to fail.
+ */
+static int test_bin_upma_fail(isl_ctx *ctx)
+{
+	int i, n;
+	isl_union_pw_multi_aff *upma1, *upma2;
+	int on_error;
+
+	on_error = isl_options_get_on_error(ctx);
+	isl_options_set_on_error(ctx, ISL_ON_ERROR_CONTINUE);
+	n = ARRAY_SIZE(upma_bin_fail_tests);
+	for (i = 0; i < n; ++i) {
+		upma1 = isl_union_pw_multi_aff_read_from_str(ctx,
+						upma_bin_fail_tests[i].arg1);
+		upma2 = isl_union_pw_multi_aff_read_from_str(ctx,
+						upma_bin_fail_tests[i].arg2);
+		upma1 = upma_bin_fail_tests[i].fn(upma1, upma2);
+		isl_union_pw_multi_aff_free(upma1);
+		if (upma1)
+			break;
+	}
+	isl_options_set_on_error(ctx, on_error);
+	if (i < n)
+		isl_die(ctx, isl_error_unknown,
+			"operation not expected to succeed", return -1);
+
+	return 0;
+}
+
+int test_aff(isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *set;
+	isl_space *space;
+	isl_local_space *ls;
+	isl_aff *aff;
+	int zero, equal;
+
+	if (test_bin_aff(ctx) < 0)
+		return -1;
+	if (test_bin_pw_aff(ctx) < 0)
+		return -1;
+	if (test_bin_upma(ctx) < 0)
+		return -1;
+	if (test_bin_upma_fail(ctx) < 0)
+		return -1;
+
+	space = isl_space_set_alloc(ctx, 0, 1);
+	ls = isl_local_space_from_space(space);
+	aff = isl_aff_zero_on_domain(ls);
+
+	aff = isl_aff_add_coefficient_si(aff, isl_dim_in, 0, 1);
+	aff = isl_aff_scale_down_ui(aff, 3);
+	aff = isl_aff_floor(aff);
+	aff = isl_aff_add_coefficient_si(aff, isl_dim_in, 0, 1);
+	aff = isl_aff_scale_down_ui(aff, 2);
+	aff = isl_aff_floor(aff);
+	aff = isl_aff_add_coefficient_si(aff, isl_dim_in, 0, 1);
+
+	str = "{ [10] }";
+	set = isl_set_read_from_str(ctx, str);
+	aff = isl_aff_gist(aff, set);
+
+	aff = isl_aff_add_constant_si(aff, -16);
+	zero = isl_aff_plain_is_zero(aff);
+	isl_aff_free(aff);
+
+	if (zero < 0)
+		return -1;
+	if (!zero)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	aff = isl_aff_read_from_str(ctx, "{ [-1] }");
+	aff = isl_aff_scale_down_ui(aff, 64);
+	aff = isl_aff_floor(aff);
+	equal = aff_check_plain_equal(aff, "{ [-1] }");
+	isl_aff_free(aff);
+	if (equal < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Check that the computation below results in a single expression.
+ * One or two expressions may result depending on which constraint
+ * ends up being considered as redundant with respect to the other
+ * constraints after the projection that is performed internally
+ * by isl_set_dim_min.
+ */
+static int test_dim_max_1(isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *set;
+	isl_pw_aff *pa;
+	int n;
+
+	str = "[n] -> { [a, b] : n >= 0 and 4a >= -4 + n and b >= 0 and "
+				"-4a <= b <= 3 and b < n - 4a }";
+	set = isl_set_read_from_str(ctx, str);
+	pa = isl_set_dim_min(set, 0);
+	n = isl_pw_aff_n_piece(pa);
+	isl_pw_aff_free(pa);
+
+	if (!pa)
+		return -1;
+	if (n != 1)
+		isl_die(ctx, isl_error_unknown, "expecting single expression",
+			return -1);
+
+	return 0;
+}
+
+int test_dim_max(isl_ctx *ctx)
+{
+	int equal;
+	const char *str;
+	isl_set *set1, *set2;
+	isl_set *set;
+	isl_map *map;
+	isl_pw_aff *pwaff;
+
+	if (test_dim_max_1(ctx) < 0)
+		return -1;
+
+	str = "[N] -> { [i] : 0 <= i <= min(N,10) }";
+	set = isl_set_read_from_str(ctx, str);
+	pwaff = isl_set_dim_max(set, 0);
+	set1 = isl_set_from_pw_aff(pwaff);
+	str = "[N] -> { [10] : N >= 10; [N] : N <= 9 and N >= 0 }";
+	set2 = isl_set_read_from_str(ctx, str);
+	equal = isl_set_is_equal(set1, set2);
+	isl_set_free(set1);
+	isl_set_free(set2);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	str = "[N] -> { [i] : 0 <= i <= max(2N,N+6) }";
+	set = isl_set_read_from_str(ctx, str);
+	pwaff = isl_set_dim_max(set, 0);
+	set1 = isl_set_from_pw_aff(pwaff);
+	str = "[N] -> { [6 + N] : -6 <= N <= 5; [2N] : N >= 6 }";
+	set2 = isl_set_read_from_str(ctx, str);
+	equal = isl_set_is_equal(set1, set2);
+	isl_set_free(set1);
+	isl_set_free(set2);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	str = "[N] -> { [i] : 0 <= i <= 2N or 0 <= i <= N+6 }";
+	set = isl_set_read_from_str(ctx, str);
+	pwaff = isl_set_dim_max(set, 0);
+	set1 = isl_set_from_pw_aff(pwaff);
+	str = "[N] -> { [6 + N] : -6 <= N <= 5; [2N] : N >= 6 }";
+	set2 = isl_set_read_from_str(ctx, str);
+	equal = isl_set_is_equal(set1, set2);
+	isl_set_free(set1);
+	isl_set_free(set2);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	str = "[N,M] -> { [i,j] -> [([i/16]), i%16, ([j/16]), j%16] : "
+			"0 <= i < N and 0 <= j < M }";
+	map = isl_map_read_from_str(ctx, str);
+	set = isl_map_range(map);
+
+	pwaff = isl_set_dim_max(isl_set_copy(set), 0);
+	set1 = isl_set_from_pw_aff(pwaff);
+	str = "[N,M] -> { [([(N-1)/16])] : M,N > 0 }";
+	set2 = isl_set_read_from_str(ctx, str);
+	equal = isl_set_is_equal(set1, set2);
+	isl_set_free(set1);
+	isl_set_free(set2);
+
+	pwaff = isl_set_dim_max(isl_set_copy(set), 3);
+	set1 = isl_set_from_pw_aff(pwaff);
+	str = "[N,M] -> { [t] : t = min(M-1,15) and M,N > 0 }";
+	set2 = isl_set_read_from_str(ctx, str);
+	if (equal >= 0 && equal)
+		equal = isl_set_is_equal(set1, set2);
+	isl_set_free(set1);
+	isl_set_free(set2);
+
+	isl_set_free(set);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	/* Check that solutions are properly merged. */
+	str = "[n] -> { [a, b, c] : c >= -4a - 2b and "
+				"c <= -1 + n - 4a - 2b and c >= -2b and "
+				"4a >= -4 + n and c >= 0 }";
+	set = isl_set_read_from_str(ctx, str);
+	pwaff = isl_set_dim_min(set, 2);
+	set1 = isl_set_from_pw_aff(pwaff);
+	str = "[n] -> { [(0)] : n >= 1 }";
+	set2 = isl_set_read_from_str(ctx, str);
+	equal = isl_set_is_equal(set1, set2);
+	isl_set_free(set1);
+	isl_set_free(set2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	/* Check that empty solution lie in the right space. */
+	str = "[n] -> { [t,a] : 1 = 0 }";
+	set = isl_set_read_from_str(ctx, str);
+	pwaff = isl_set_dim_max(set, 0);
+	set1 = isl_set_from_pw_aff(pwaff);
+	str = "[n] -> { [t] : 1 = 0 }";
+	set2 = isl_set_read_from_str(ctx, str);
+	equal = isl_set_is_equal(set1, set2);
+	isl_set_free(set1);
+	isl_set_free(set2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	return 0;
+}
+
+/* Is "pma" obviously equal to the isl_pw_multi_aff represented by "str"?
+ */
+static int pw_multi_aff_plain_is_equal(__isl_keep isl_pw_multi_aff *pma,
+	const char *str)
+{
+	isl_ctx *ctx;
+	isl_pw_multi_aff *pma2;
+	int equal;
+
+	if (!pma)
+		return -1;
+
+	ctx = isl_pw_multi_aff_get_ctx(pma);
+	pma2 = isl_pw_multi_aff_read_from_str(ctx, str);
+	equal = isl_pw_multi_aff_plain_is_equal(pma, pma2);
+	isl_pw_multi_aff_free(pma2);
+
+	return equal;
+}
+
+/* Check that "pma" is obviously equal to the isl_pw_multi_aff
+ * represented by "str".
+ */
+static int pw_multi_aff_check_plain_equal(__isl_keep isl_pw_multi_aff *pma,
+	const char *str)
+{
+	int equal;
+
+	equal = pw_multi_aff_plain_is_equal(pma, str);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_unknown,
+			"result not as expected", return -1);
+	return 0;
+}
+
+/* Basic test for isl_pw_multi_aff_product.
+ *
+ * Check that multiple pieces are properly handled.
+ */
+static int test_product_pma(isl_ctx *ctx)
+{
+	int equal;
+	const char *str;
+	isl_pw_multi_aff *pma1, *pma2;
+
+	str = "{ A[i] -> B[1] : i < 0; A[i] -> B[2] : i >= 0 }";
+	pma1 = isl_pw_multi_aff_read_from_str(ctx, str);
+	str = "{ C[] -> D[] }";
+	pma2 = isl_pw_multi_aff_read_from_str(ctx, str);
+	pma1 = isl_pw_multi_aff_product(pma1, pma2);
+	str = "{ [A[i] -> C[]] -> [B[(1)] -> D[]] : i < 0;"
+		"[A[i] -> C[]] -> [B[(2)] -> D[]] : i >= 0 }";
+	equal = pw_multi_aff_check_plain_equal(pma1, str);
+	isl_pw_multi_aff_free(pma1);
+	if (equal < 0)
+		return -1;
+
+	return 0;
+}
+
+int test_product(isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *set;
+	isl_union_set *uset1, *uset2;
+	int ok;
+
+	str = "{ A[i] }";
+	set = isl_set_read_from_str(ctx, str);
+	set = isl_set_product(set, isl_set_copy(set));
+	ok = isl_set_is_wrapping(set);
+	isl_set_free(set);
+	if (ok < 0)
+		return -1;
+	if (!ok)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	str = "{ [] }";
+	uset1 = isl_union_set_read_from_str(ctx, str);
+	uset1 = isl_union_set_product(uset1, isl_union_set_copy(uset1));
+	str = "{ [[] -> []] }";
+	uset2 = isl_union_set_read_from_str(ctx, str);
+	ok = isl_union_set_is_equal(uset1, uset2);
+	isl_union_set_free(uset1);
+	isl_union_set_free(uset2);
+	if (ok < 0)
+		return -1;
+	if (!ok)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	if (test_product_pma(ctx) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Check that two sets are not considered disjoint just because
+ * they have a different set of (named) parameters.
+ */
+static int test_disjoint(isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *set, *set2;
+	int disjoint;
+
+	str = "[n] -> { [[]->[]] }";
+	set = isl_set_read_from_str(ctx, str);
+	str = "{ [[]->[]] }";
+	set2 = isl_set_read_from_str(ctx, str);
+	disjoint = isl_set_is_disjoint(set, set2);
+	isl_set_free(set);
+	isl_set_free(set2);
+	if (disjoint < 0)
+		return -1;
+	if (disjoint)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	return 0;
+}
+
+/* Inputs for isl_pw_multi_aff_is_equal tests.
+ * "f1" and "f2" are the two function that need to be compared.
+ * "equal" is the expected result.
+ */
+struct {
+	int equal;
+	const char *f1;
+	const char *f2;
+} pma_equal_tests[] = {
+	{ 1, "[N] -> { [floor(N/2)] : 0 <= N <= 1 }",
+	     "[N] -> { [0] : 0 <= N <= 1 }" },
+	{ 1, "[N] -> { [floor(N/2)] : 0 <= N <= 2 }",
+	     "[N] -> { [0] : 0 <= N <= 1; [1] : N = 2 }" },
+	{ 0, "[N] -> { [floor(N/2)] : 0 <= N <= 2 }",
+	     "[N] -> { [0] : 0 <= N <= 1 }" },
+	{ 0, "{ [NaN] }", "{ [NaN] }" },
+};
+
+int test_equal(isl_ctx *ctx)
+{
+	int i;
+	const char *str;
+	isl_set *set, *set2;
+	int equal;
+
+	str = "{ S_6[i] }";
+	set = isl_set_read_from_str(ctx, str);
+	str = "{ S_7[i] }";
+	set2 = isl_set_read_from_str(ctx, str);
+	equal = isl_set_is_equal(set, set2);
+	isl_set_free(set);
+	isl_set_free(set2);
+	if (equal < 0)
+		return -1;
+	if (equal)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	for (i = 0; i < ARRAY_SIZE(pma_equal_tests); ++i) {
+		int expected = pma_equal_tests[i].equal;
+		isl_pw_multi_aff *f1, *f2;
+
+		f1 = isl_pw_multi_aff_read_from_str(ctx, pma_equal_tests[i].f1);
+		f2 = isl_pw_multi_aff_read_from_str(ctx, pma_equal_tests[i].f2);
+		equal = isl_pw_multi_aff_is_equal(f1, f2);
+		isl_pw_multi_aff_free(f1);
+		isl_pw_multi_aff_free(f2);
+		if (equal < 0)
+			return -1;
+		if (equal != expected)
+			isl_die(ctx, isl_error_unknown,
+				"unexpected equality result", return -1);
+	}
+
+	return 0;
+}
+
+static int test_plain_fixed(isl_ctx *ctx, __isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, int fixed)
+{
+	isl_bool test;
+
+	test = isl_map_plain_is_fixed(map, type, pos, NULL);
+	isl_map_free(map);
+	if (test < 0)
+		return -1;
+	if (test == fixed)
+		return 0;
+	if (fixed)
+		isl_die(ctx, isl_error_unknown,
+			"map not detected as fixed", return -1);
+	else
+		isl_die(ctx, isl_error_unknown,
+			"map detected as fixed", return -1);
+}
+
+int test_fixed(isl_ctx *ctx)
+{
+	const char *str;
+	isl_map *map;
+
+	str = "{ [i] -> [i] }";
+	map = isl_map_read_from_str(ctx, str);
+	if (test_plain_fixed(ctx, map, isl_dim_out, 0, 0))
+		return -1;
+	str = "{ [i] -> [1] }";
+	map = isl_map_read_from_str(ctx, str);
+	if (test_plain_fixed(ctx, map, isl_dim_out, 0, 1))
+		return -1;
+	str = "{ S_1[p1] -> [o0] : o0 = -2 and p1 >= 1 and p1 <= 7 }";
+	map = isl_map_read_from_str(ctx, str);
+	if (test_plain_fixed(ctx, map, isl_dim_out, 0, 1))
+		return -1;
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_neg(map);
+	if (test_plain_fixed(ctx, map, isl_dim_out, 0, 1))
+		return -1;
+
+	return 0;
+}
+
+struct isl_vertices_test_data {
+	const char *set;
+	int n;
+	const char *vertex[6];
+} vertices_tests[] = {
+	{ "{ A[t, i] : t = 12 and i >= 4 and i <= 12 }",
+	  2, { "{ A[12, 4] }", "{ A[12, 12] }" } },
+	{ "{ A[t, i] : t = 14 and i = 1 }",
+	  1, { "{ A[14, 1] }" } },
+	{ "[n, m] -> { [a, b, c] : b <= a and a <= n and b > 0 and c >= b and "
+				"c <= m and m <= n and m > 0 }",
+	  6, {
+		"[n, m] -> { [n, m, m] : 0 < m <= n }",
+		"[n, m] -> { [n, 1, m] : 0 < m <= n }",
+		"[n, m] -> { [n, 1, 1] : 0 < m <= n }",
+		"[n, m] -> { [m, m, m] : 0 < m <= n }",
+		"[n, m] -> { [1, 1, m] : 0 < m <= n }",
+		"[n, m] -> { [1, 1, 1] : 0 < m <= n }"
+	    } },
+};
+
+/* Check that "vertex" corresponds to one of the vertices in data->vertex.
+ */
+static isl_stat find_vertex(__isl_take isl_vertex *vertex, void *user)
+{
+	struct isl_vertices_test_data *data = user;
+	isl_ctx *ctx;
+	isl_multi_aff *ma;
+	isl_basic_set *bset;
+	isl_pw_multi_aff *pma;
+	int i;
+	isl_bool equal;
+
+	ctx = isl_vertex_get_ctx(vertex);
+	bset = isl_vertex_get_domain(vertex);
+	ma = isl_vertex_get_expr(vertex);
+	pma = isl_pw_multi_aff_alloc(isl_set_from_basic_set(bset), ma);
+
+	for (i = 0; i < data->n; ++i) {
+		isl_pw_multi_aff *pma_i;
+
+		pma_i = isl_pw_multi_aff_read_from_str(ctx, data->vertex[i]);
+		equal = isl_pw_multi_aff_plain_is_equal(pma, pma_i);
+		isl_pw_multi_aff_free(pma_i);
+
+		if (equal < 0 || equal)
+			break;
+	}
+
+	isl_pw_multi_aff_free(pma);
+	isl_vertex_free(vertex);
+
+	if (equal < 0)
+		return isl_stat_error;
+
+	return equal ? isl_stat_ok : isl_stat_error;
+}
+
+int test_vertices(isl_ctx *ctx)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vertices_tests); ++i) {
+		isl_basic_set *bset;
+		isl_vertices *vertices;
+		int ok = 1;
+		int n;
+
+		bset = isl_basic_set_read_from_str(ctx, vertices_tests[i].set);
+		vertices = isl_basic_set_compute_vertices(bset);
+		n = isl_vertices_get_n_vertices(vertices);
+		if (vertices_tests[i].n != n)
+			ok = 0;
+		if (isl_vertices_foreach_vertex(vertices, &find_vertex,
+						&vertices_tests[i]) < 0)
+			ok = 0;
+		isl_vertices_free(vertices);
+		isl_basic_set_free(bset);
+
+		if (!vertices)
+			return -1;
+		if (!ok)
+			isl_die(ctx, isl_error_unknown, "unexpected vertices",
+				return -1);
+	}
+
+	return 0;
+}
+
+int test_union_pw(isl_ctx *ctx)
+{
+	int equal;
+	const char *str;
+	isl_union_set *uset;
+	isl_union_pw_qpolynomial *upwqp1, *upwqp2;
+
+	str = "{ [x] -> x^2 }";
+	upwqp1 = isl_union_pw_qpolynomial_read_from_str(ctx, str);
+	upwqp2 = isl_union_pw_qpolynomial_copy(upwqp1);
+	uset = isl_union_pw_qpolynomial_domain(upwqp1);
+	upwqp1 = isl_union_pw_qpolynomial_copy(upwqp2);
+	upwqp1 = isl_union_pw_qpolynomial_intersect_domain(upwqp1, uset);
+	equal = isl_union_pw_qpolynomial_plain_is_equal(upwqp1, upwqp2);
+	isl_union_pw_qpolynomial_free(upwqp1);
+	isl_union_pw_qpolynomial_free(upwqp2);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	return 0;
+}
+
+/* Test that isl_union_pw_qpolynomial_eval picks up the function
+ * defined over the correct domain space.
+ */
+static int test_eval_1(isl_ctx *ctx)
+{
+	const char *str;
+	isl_point *pnt;
+	isl_set *set;
+	isl_union_pw_qpolynomial *upwqp;
+	isl_val *v;
+	int cmp;
+
+	str = "{ A[x] -> x^2; B[x] -> -x^2 }";
+	upwqp = isl_union_pw_qpolynomial_read_from_str(ctx, str);
+	str = "{ A[6] }";
+	set = isl_set_read_from_str(ctx, str);
+	pnt = isl_set_sample_point(set);
+	v = isl_union_pw_qpolynomial_eval(upwqp, pnt);
+	cmp = isl_val_cmp_si(v, 36);
+	isl_val_free(v);
+
+	if (!v)
+		return -1;
+	if (cmp != 0)
+		isl_die(ctx, isl_error_unknown, "unexpected value", return -1);
+
+	return 0;
+}
+
+/* Check that isl_qpolynomial_eval handles getting called on a void point.
+ */
+static int test_eval_2(isl_ctx *ctx)
+{
+	const char *str;
+	isl_point *pnt;
+	isl_set *set;
+	isl_qpolynomial *qp;
+	isl_val *v;
+	isl_bool ok;
+
+	str = "{ A[x] -> [x] }";
+	qp = isl_qpolynomial_from_aff(isl_aff_read_from_str(ctx, str));
+	str = "{ A[x] : false }";
+	set = isl_set_read_from_str(ctx, str);
+	pnt = isl_set_sample_point(set);
+	v = isl_qpolynomial_eval(qp, pnt);
+	ok = isl_val_is_nan(v);
+	isl_val_free(v);
+
+	if (ok < 0)
+		return -1;
+	if (!ok)
+		isl_die(ctx, isl_error_unknown, "expecting NaN", return -1);
+
+	return 0;
+}
+
+/* Perform basic polynomial evaluation tests.
+ */
+static int test_eval(isl_ctx *ctx)
+{
+	if (test_eval_1(ctx) < 0)
+		return -1;
+	if (test_eval_2(ctx) < 0)
+		return -1;
+	return 0;
+}
+
+/* Descriptions of sets that are tested for reparsing after printing.
+ */
+const char *output_tests[] = {
+	"{ [1, y] : 0 <= y <= 1; [x, -x] : 0 <= x <= 1 }",
+};
+
+/* Check that printing a set and reparsing a set from the printed output
+ * results in the same set.
+ */
+static int test_output_set(isl_ctx *ctx)
+{
+	int i;
+	char *str;
+	isl_set *set1, *set2;
+	isl_bool equal;
+
+	for (i = 0; i < ARRAY_SIZE(output_tests); ++i) {
+		set1 = isl_set_read_from_str(ctx, output_tests[i]);
+		str = isl_set_to_str(set1);
+		set2 = isl_set_read_from_str(ctx, str);
+		free(str);
+		equal = isl_set_is_equal(set1, set2);
+		isl_set_free(set1);
+		isl_set_free(set2);
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown,
+				"parsed output not the same", return -1);
+	}
+
+	return 0;
+}
+
+int test_output(isl_ctx *ctx)
+{
+	char *s;
+	const char *str;
+	isl_pw_aff *pa;
+	isl_printer *p;
+	int equal;
+
+	if (test_output_set(ctx) < 0)
+		return -1;
+
+	str = "[x] -> { [1] : x % 4 <= 2; [2] : x = 3 }";
+	pa = isl_pw_aff_read_from_str(ctx, str);
+
+	p = isl_printer_to_str(ctx);
+	p = isl_printer_set_output_format(p, ISL_FORMAT_C);
+	p = isl_printer_print_pw_aff(p, pa);
+	s = isl_printer_get_str(p);
+	isl_printer_free(p);
+	isl_pw_aff_free(pa);
+	if (!s)
+		equal = -1;
+	else
+		equal = !strcmp(s, "4 * floord(x, 4) + 2 >= x ? 1 : 2");
+	free(s);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown, "unexpected result", return -1);
+
+	return 0;
+}
+
+int test_sample(isl_ctx *ctx)
+{
+	const char *str;
+	isl_basic_set *bset1, *bset2;
+	int empty, subset;
+
+	str = "{ [a, b, c, d, e, f, g, h, i, j, k] : "
+	    "3i >= 1073741823b - c - 1073741823e + f and c >= 0 and "
+	    "3i >= -1 + 3221225466b + c + d - 3221225466e - f and "
+	    "2e >= a - b and 3e <= 2a and 3k <= -a and f <= -1 + a and "
+	    "3i <= 4 - a + 4b + 2c - e - 2f and 3k <= -a + c - f and "
+	    "3h >= -2 + a and 3g >= -3 - a and 3k >= -2 - a and "
+	    "3i >= -2 - a - 2c + 3e + 2f and 3h <= a + c - f and "
+	    "3h >= a + 2147483646b + 2c - 2147483646e - 2f and "
+	    "3g <= -1 - a and 3i <= 1 + c + d - f and a <= 1073741823 and "
+	    "f >= 1 - a + 1073741822b + c + d - 1073741822e and "
+	    "3i >= 1 + 2b - 2c + e + 2f + 3g and "
+	    "1073741822f <= 1073741822 - a + 1073741821b + 1073741822c +"
+		"d - 1073741821e and "
+	    "3j <= 3 - a + 3b and 3g <= -2 - 2b + c + d - e - f and "
+	    "3j >= 1 - a + b + 2e and "
+	    "3f >= -3 + a + 3221225462b + 3c + d - 3221225465e and "
+	    "3i <= 4 - a + 4b - e and "
+	    "f <= 1073741822 + 1073741822b - 1073741822e and 3h <= a and "
+	    "f >= 0 and 2e <= 4 - a + 5b - d and 2e <= a - b + d and "
+	    "c <= -1 + a and 3i >= -2 - a + 3e and "
+	    "1073741822e <= 1073741823 - a + 1073741822b + c and "
+	    "3g >= -4 + 3221225464b + 3c + d - 3221225467e - 3f and "
+	    "3i >= -1 + 3221225466b + 3c + d - 3221225466e - 3f and "
+	    "1073741823e >= 1 + 1073741823b - d and "
+	    "3i >= 1073741823b + c - 1073741823e - f and "
+	    "3i >= 1 + 2b + e + 3g }";
+	bset1 = isl_basic_set_read_from_str(ctx, str);
+	bset2 = isl_basic_set_sample(isl_basic_set_copy(bset1));
+	empty = isl_basic_set_is_empty(bset2);
+	subset = isl_basic_set_is_subset(bset2, bset1);
+	isl_basic_set_free(bset1);
+	isl_basic_set_free(bset2);
+	if (empty < 0 || subset < 0)
+		return -1;
+	if (empty)
+		isl_die(ctx, isl_error_unknown, "point not found", return -1);
+	if (!subset)
+		isl_die(ctx, isl_error_unknown, "bad point found", return -1);
+
+	return 0;
+}
+
+int test_fixed_power(isl_ctx *ctx)
+{
+	const char *str;
+	isl_map *map;
+	isl_int exp;
+	int equal;
+
+	isl_int_init(exp);
+	str = "{ [i] -> [i + 1] }";
+	map = isl_map_read_from_str(ctx, str);
+	isl_int_set_si(exp, 23);
+	map = isl_map_fixed_power(map, exp);
+	equal = map_check_equal(map, "{ [i] -> [i + 23] }");
+	isl_int_clear(exp);
+	isl_map_free(map);
+	if (equal < 0)
+		return -1;
+
+	return 0;
+}
+
+int test_slice(isl_ctx *ctx)
+{
+	const char *str;
+	isl_map *map;
+	int equal;
+
+	str = "{ [i] -> [j] }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_equate(map, isl_dim_in, 0, isl_dim_out, 0);
+	equal = map_check_equal(map, "{ [i] -> [i] }");
+	isl_map_free(map);
+	if (equal < 0)
+		return -1;
+
+	str = "{ [i] -> [j] }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_equate(map, isl_dim_in, 0, isl_dim_in, 0);
+	equal = map_check_equal(map, "{ [i] -> [j] }");
+	isl_map_free(map);
+	if (equal < 0)
+		return -1;
+
+	str = "{ [i] -> [j] }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_oppose(map, isl_dim_in, 0, isl_dim_out, 0);
+	equal = map_check_equal(map, "{ [i] -> [-i] }");
+	isl_map_free(map);
+	if (equal < 0)
+		return -1;
+
+	str = "{ [i] -> [j] }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_oppose(map, isl_dim_in, 0, isl_dim_in, 0);
+	equal = map_check_equal(map, "{ [0] -> [j] }");
+	isl_map_free(map);
+	if (equal < 0)
+		return -1;
+
+	str = "{ [i] -> [j] }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_order_gt(map, isl_dim_in, 0, isl_dim_out, 0);
+	equal = map_check_equal(map, "{ [i] -> [j] : i > j }");
+	isl_map_free(map);
+	if (equal < 0)
+		return -1;
+
+	str = "{ [i] -> [j] }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_order_gt(map, isl_dim_in, 0, isl_dim_in, 0);
+	equal = map_check_equal(map, "{ [i] -> [j] : false }");
+	isl_map_free(map);
+	if (equal < 0)
+		return -1;
+
+	return 0;
+}
+
+int test_eliminate(isl_ctx *ctx)
+{
+	const char *str;
+	isl_map *map;
+	int equal;
+
+	str = "{ [i] -> [j] : i = 2j }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_eliminate(map, isl_dim_out, 0, 1);
+	equal = map_check_equal(map, "{ [i] -> [j] : exists a : i = 2a }");
+	isl_map_free(map);
+	if (equal < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Check that isl_set_dim_residue_class detects that the values of j
+ * in the set below are all odd and that it does not detect any spurious
+ * strides.
+ */
+static int test_residue_class(isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *set;
+	isl_int m, r;
+	isl_stat res;
+
+	str = "{ [i,j] : j = 4 i + 1 and 0 <= i <= 100; "
+		"[i,j] : j = 4 i + 3 and 500 <= i <= 600 }";
+	set = isl_set_read_from_str(ctx, str);
+	isl_int_init(m);
+	isl_int_init(r);
+	res = isl_set_dim_residue_class(set, 1, &m, &r);
+	if (res >= 0 &&
+	    (isl_int_cmp_si(m, 2) != 0 || isl_int_cmp_si(r, 1) != 0))
+		isl_die(ctx, isl_error_unknown, "incorrect residue class",
+			res = isl_stat_error);
+	isl_int_clear(r);
+	isl_int_clear(m);
+	isl_set_free(set);
+
+	return res;
+}
+
+int test_align_parameters(isl_ctx *ctx)
+{
+	const char *str;
+	isl_space *space;
+	isl_multi_aff *ma1, *ma2;
+	int equal;
+
+	str = "{ A[B[] -> C[]] -> D[E[] -> F[]] }";
+	ma1 = isl_multi_aff_read_from_str(ctx, str);
+
+	space = isl_space_params_alloc(ctx, 1);
+	space = isl_space_set_dim_name(space, isl_dim_param, 0, "N");
+	ma1 = isl_multi_aff_align_params(ma1, space);
+
+	str = "[N] -> { A[B[] -> C[]] -> D[E[] -> F[]] }";
+	ma2 = isl_multi_aff_read_from_str(ctx, str);
+
+	equal = isl_multi_aff_plain_is_equal(ma1, ma2);
+
+	isl_multi_aff_free(ma1);
+	isl_multi_aff_free(ma2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"result not as expected", return -1);
+
+	return 0;
+}
+
+static int test_list(isl_ctx *ctx)
+{
+	isl_id *a, *b, *c, *d, *id;
+	isl_id_list *list;
+	int ok;
+
+	a = isl_id_alloc(ctx, "a", NULL);
+	b = isl_id_alloc(ctx, "b", NULL);
+	c = isl_id_alloc(ctx, "c", NULL);
+	d = isl_id_alloc(ctx, "d", NULL);
+
+	list = isl_id_list_alloc(ctx, 4);
+	list = isl_id_list_add(list, b);
+	list = isl_id_list_insert(list, 0, a);
+	list = isl_id_list_add(list, c);
+	list = isl_id_list_add(list, d);
+	list = isl_id_list_drop(list, 1, 1);
+
+	if (isl_id_list_n_id(list) != 3) {
+		isl_id_list_free(list);
+		isl_die(ctx, isl_error_unknown,
+			"unexpected number of elements in list", return -1);
+	}
+
+	id = isl_id_list_get_id(list, 0);
+	ok = id == a;
+	isl_id_free(id);
+	id = isl_id_list_get_id(list, 1);
+	ok = ok && id == c;
+	isl_id_free(id);
+	id = isl_id_list_get_id(list, 2);
+	ok = ok && id == d;
+	isl_id_free(id);
+
+	isl_id_list_free(list);
+
+	if (!ok)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected elements in list", return -1);
+
+	return 0;
+}
+
+const char *set_conversion_tests[] = {
+	"[N] -> { [i] : N - 1 <= 2 i <= N }",
+	"[N] -> { [i] : exists a : i = 4 a and N - 1 <= i <= N }",
+	"[N] -> { [i,j] : exists a : i = 4 a and N - 1 <= i, 2j <= N }",
+	"[N] -> { [[i]->[j]] : exists a : i = 4 a and N - 1 <= i, 2j <= N }",
+	"[N] -> { [3*floor(N/2) + 5*floor(N/3)] }",
+	"[a, b] -> { [c, d] : (4*floor((-a + c)/4) = -a + c and "
+			"32*floor((-b + d)/32) = -b + d and 5 <= c <= 8 and "
+			"-3 + c <= d <= 28 + c) }",
+};
+
+/* Check that converting from isl_set to isl_pw_multi_aff and back
+ * to isl_set produces the original isl_set.
+ */
+static int test_set_conversion(isl_ctx *ctx)
+{
+	int i;
+	const char *str;
+	isl_set *set1, *set2;
+	isl_pw_multi_aff *pma;
+	int equal;
+
+	for (i = 0; i < ARRAY_SIZE(set_conversion_tests); ++i) {
+		str = set_conversion_tests[i];
+		set1 = isl_set_read_from_str(ctx, str);
+		pma = isl_pw_multi_aff_from_set(isl_set_copy(set1));
+		set2 = isl_set_from_pw_multi_aff(pma);
+		equal = isl_set_is_equal(set1, set2);
+		isl_set_free(set1);
+		isl_set_free(set2);
+
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown, "bad conversion",
+				return -1);
+	}
+
+	return 0;
+}
+
+const char *conversion_tests[] = {
+	"{ [a, b, c, d] -> s0[a, b, e, f] : "
+	    "exists (e0 = [(a - 2c)/3], e1 = [(-4 + b - 5d)/9], "
+	    "e2 = [(-d + f)/9]: 3e0 = a - 2c and 9e1 = -4 + b - 5d and "
+	    "9e2 = -d + f and f >= 0 and f <= 8 and 9e >= -5 - 2a and "
+	    "9e <= -2 - 2a) }",
+	"{ [a, b] -> [c] : exists (e0 = floor((-a - b + c)/5): "
+	    "5e0 = -a - b + c and c >= -a and c <= 4 - a) }",
+	"{ [a, b] -> [c] : exists d : 18 * d = -3 - a + 2c and 1 <= c <= 3 }",
+};
+
+/* Check that converting from isl_map to isl_pw_multi_aff and back
+ * to isl_map produces the original isl_map.
+ */
+static int test_map_conversion(isl_ctx *ctx)
+{
+	int i;
+	isl_map *map1, *map2;
+	isl_pw_multi_aff *pma;
+	int equal;
+
+	for (i = 0; i < ARRAY_SIZE(conversion_tests); ++i) {
+		map1 = isl_map_read_from_str(ctx, conversion_tests[i]);
+		pma = isl_pw_multi_aff_from_map(isl_map_copy(map1));
+		map2 = isl_map_from_pw_multi_aff(pma);
+		equal = isl_map_is_equal(map1, map2);
+		isl_map_free(map1);
+		isl_map_free(map2);
+
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown, "bad conversion",
+				return -1);
+	}
+
+	return 0;
+}
+
+static int test_conversion(isl_ctx *ctx)
+{
+	if (test_set_conversion(ctx) < 0)
+		return -1;
+	if (test_map_conversion(ctx) < 0)
+		return -1;
+	return 0;
+}
+
+/* Check that isl_basic_map_curry does not modify input.
+ */
+static int test_curry(isl_ctx *ctx)
+{
+	const char *str;
+	isl_basic_map *bmap1, *bmap2;
+	int equal;
+
+	str = "{ [A[] -> B[]] -> C[] }";
+	bmap1 = isl_basic_map_read_from_str(ctx, str);
+	bmap2 = isl_basic_map_curry(isl_basic_map_copy(bmap1));
+	equal = isl_basic_map_is_equal(bmap1, bmap2);
+	isl_basic_map_free(bmap1);
+	isl_basic_map_free(bmap2);
+
+	if (equal < 0)
+		return -1;
+	if (equal)
+		isl_die(ctx, isl_error_unknown,
+			"curried map should not be equal to original",
+			return -1);
+
+	return 0;
+}
+
+struct {
+	const char *set;
+	const char *ma;
+	const char *res;
+} preimage_tests[] = {
+	{ "{ B[i,j] : 0 <= i < 10 and 0 <= j < 100 }",
+	  "{ A[j,i] -> B[i,j] }",
+	  "{ A[j,i] : 0 <= i < 10 and 0 <= j < 100 }" },
+	{ "{ rat: B[i,j] : 0 <= i, j and 3 i + 5 j <= 100 }",
+	  "{ A[a,b] -> B[a/2,b/6] }",
+	  "{ rat: A[a,b] : 0 <= a, b and 9 a + 5 b <= 600 }" },
+	{ "{ B[i,j] : 0 <= i, j and 3 i + 5 j <= 100 }",
+	  "{ A[a,b] -> B[a/2,b/6] }",
+	  "{ A[a,b] : 0 <= a, b and 9 a + 5 b <= 600 and "
+		    "exists i,j : a = 2 i and b = 6 j }" },
+	{ "[n] -> { S[i] : 0 <= i <= 100 }", "[n] -> { S[n] }",
+	  "[n] -> { : 0 <= n <= 100 }" },
+	{ "{ B[i] : 0 <= i < 100 and exists a : i = 4 a }",
+	  "{ A[a] -> B[2a] }",
+	  "{ A[a] : 0 <= a < 50 and exists b : a = 2 b }" },
+	{ "{ B[i] : 0 <= i < 100 and exists a : i = 4 a }",
+	  "{ A[a] -> B[([a/2])] }",
+	  "{ A[a] : 0 <= a < 200 and exists b : [a/2] = 4 b }" },
+	{ "{ B[i,j,k] : 0 <= i,j,k <= 100 }",
+	  "{ A[a] -> B[a,a,a/3] }",
+	  "{ A[a] : 0 <= a <= 100 and exists b : a = 3 b }" },
+	{ "{ B[i,j] : j = [(i)/2] } ", "{ A[i,j] -> B[i/3,j] }",
+	  "{ A[i,j] : j = [(i)/6] and exists a : i = 3 a }" },
+};
+
+static int test_preimage_basic_set(isl_ctx *ctx)
+{
+	int i;
+	isl_basic_set *bset1, *bset2;
+	isl_multi_aff *ma;
+	int equal;
+
+	for (i = 0; i < ARRAY_SIZE(preimage_tests); ++i) {
+		bset1 = isl_basic_set_read_from_str(ctx, preimage_tests[i].set);
+		ma = isl_multi_aff_read_from_str(ctx, preimage_tests[i].ma);
+		bset2 = isl_basic_set_read_from_str(ctx, preimage_tests[i].res);
+		bset1 = isl_basic_set_preimage_multi_aff(bset1, ma);
+		equal = isl_basic_set_is_equal(bset1, bset2);
+		isl_basic_set_free(bset1);
+		isl_basic_set_free(bset2);
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown, "bad preimage",
+				return -1);
+	}
+
+	return 0;
+}
+
+struct {
+	const char *map;
+	const char *ma;
+	const char *res;
+} preimage_domain_tests[] = {
+	{ "{ B[i,j] -> C[2i + 3j] : 0 <= i < 10 and 0 <= j < 100 }",
+	  "{ A[j,i] -> B[i,j] }",
+	  "{ A[j,i] -> C[2i + 3j] : 0 <= i < 10 and 0 <= j < 100 }" },
+	{ "{ B[i] -> C[i]; D[i] -> E[i] }",
+	  "{ A[i] -> B[i + 1] }",
+	  "{ A[i] -> C[i + 1] }" },
+	{ "{ B[i] -> C[i]; B[i] -> E[i] }",
+	  "{ A[i] -> B[i + 1] }",
+	  "{ A[i] -> C[i + 1]; A[i] -> E[i + 1] }" },
+	{ "{ B[i] -> C[([i/2])] }",
+	  "{ A[i] -> B[2i] }",
+	  "{ A[i] -> C[i] }" },
+	{ "{ B[i,j] -> C[([i/2]), ([(i+j)/3])] }",
+	  "{ A[i] -> B[([i/5]), ([i/7])] }",
+	  "{ A[i] -> C[([([i/5])/2]), ([(([i/5])+([i/7]))/3])] }" },
+	{ "[N] -> { B[i] -> C[([N/2]), i, ([N/3])] }",
+	  "[N] -> { A[] -> B[([N/5])] }",
+	  "[N] -> { A[] -> C[([N/2]), ([N/5]), ([N/3])] }" },
+	{ "{ B[i] -> C[i] : exists a : i = 5 a }",
+	  "{ A[i] -> B[2i] }",
+	  "{ A[i] -> C[2i] : exists a : 2i = 5 a }" },
+	{ "{ B[i] -> C[i] : exists a : i = 2 a; "
+	    "B[i] -> D[i] : exists a : i = 2 a + 1 }",
+	  "{ A[i] -> B[2i] }",
+	  "{ A[i] -> C[2i] }" },
+	{ "{ A[i] -> B[i] }", "{ C[i] -> A[(i + floor(i/3))/2] }",
+	  "{ C[i] -> B[j] : 2j = i + floor(i/3) }" },
+};
+
+static int test_preimage_union_map(isl_ctx *ctx)
+{
+	int i;
+	isl_union_map *umap1, *umap2;
+	isl_multi_aff *ma;
+	int equal;
+
+	for (i = 0; i < ARRAY_SIZE(preimage_domain_tests); ++i) {
+		umap1 = isl_union_map_read_from_str(ctx,
+						preimage_domain_tests[i].map);
+		ma = isl_multi_aff_read_from_str(ctx,
+						preimage_domain_tests[i].ma);
+		umap2 = isl_union_map_read_from_str(ctx,
+						preimage_domain_tests[i].res);
+		umap1 = isl_union_map_preimage_domain_multi_aff(umap1, ma);
+		equal = isl_union_map_is_equal(umap1, umap2);
+		isl_union_map_free(umap1);
+		isl_union_map_free(umap2);
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown, "bad preimage",
+				return -1);
+	}
+
+	return 0;
+}
+
+static int test_preimage(isl_ctx *ctx)
+{
+	if (test_preimage_basic_set(ctx) < 0)
+		return -1;
+	if (test_preimage_union_map(ctx) < 0)
+		return -1;
+
+	return 0;
+}
+
+struct {
+	const char *ma1;
+	const char *ma;
+	const char *res;
+} pullback_tests[] = {
+	{ "{ B[i,j] -> C[i + 2j] }" , "{ A[a,b] -> B[b,a] }",
+	  "{ A[a,b] -> C[b + 2a] }" },
+	{ "{ B[i] -> C[2i] }", "{ A[a] -> B[(a)/2] }", "{ A[a] -> C[a] }" },
+	{ "{ B[i] -> C[(i)/2] }", "{ A[a] -> B[2a] }", "{ A[a] -> C[a] }" },
+	{ "{ B[i] -> C[(i)/2] }", "{ A[a] -> B[(a)/3] }",
+	  "{ A[a] -> C[(a)/6] }" },
+	{ "{ B[i] -> C[2i] }", "{ A[a] -> B[5a] }", "{ A[a] -> C[10a] }" },
+	{ "{ B[i] -> C[2i] }", "{ A[a] -> B[(a)/3] }",
+	  "{ A[a] -> C[(2a)/3] }" },
+	{ "{ B[i,j] -> C[i + j] }", "{ A[a] -> B[a,a] }", "{ A[a] -> C[2a] }"},
+	{ "{ B[a] -> C[a,a] }", "{ A[i,j] -> B[i + j] }",
+	  "{ A[i,j] -> C[i + j, i + j] }"},
+	{ "{ B[i] -> C[([i/2])] }", "{ B[5] }", "{ C[2] }" },
+	{ "[n] -> { B[i,j] -> C[([i/2]) + 2j] }",
+	  "[n] -> { B[n,[n/3]] }", "[n] -> { C[([n/2]) + 2*[n/3]] }", },
+	{ "{ [i, j] -> [floor((i)/4) + floor((2*i+j)/5)] }",
+	  "{ [i, j] -> [floor((i)/3), j] }",
+	  "{ [i, j] -> [(floor((i)/12) + floor((j + 2*floor((i)/3))/5))] }" },
+};
+
+static int test_pullback(isl_ctx *ctx)
+{
+	int i;
+	isl_multi_aff *ma1, *ma2;
+	isl_multi_aff *ma;
+	int equal;
+
+	for (i = 0; i < ARRAY_SIZE(pullback_tests); ++i) {
+		ma1 = isl_multi_aff_read_from_str(ctx, pullback_tests[i].ma1);
+		ma = isl_multi_aff_read_from_str(ctx, pullback_tests[i].ma);
+		ma2 = isl_multi_aff_read_from_str(ctx, pullback_tests[i].res);
+		ma1 = isl_multi_aff_pullback_multi_aff(ma1, ma);
+		equal = isl_multi_aff_plain_is_equal(ma1, ma2);
+		isl_multi_aff_free(ma1);
+		isl_multi_aff_free(ma2);
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown, "bad pullback",
+				return -1);
+	}
+
+	return 0;
+}
+
+/* Check that negation is printed correctly and that equal expressions
+ * are correctly identified.
+ */
+static int test_ast(isl_ctx *ctx)
+{
+	isl_ast_expr *expr, *expr1, *expr2, *expr3;
+	char *str;
+	int ok, equal;
+
+	expr1 = isl_ast_expr_from_id(isl_id_alloc(ctx, "A", NULL));
+	expr2 = isl_ast_expr_from_id(isl_id_alloc(ctx, "B", NULL));
+	expr = isl_ast_expr_add(expr1, expr2);
+	expr2 = isl_ast_expr_copy(expr);
+	expr = isl_ast_expr_neg(expr);
+	expr2 = isl_ast_expr_neg(expr2);
+	equal = isl_ast_expr_is_equal(expr, expr2);
+	str = isl_ast_expr_to_C_str(expr);
+	ok = str ? !strcmp(str, "-(A + B)") : -1;
+	free(str);
+	isl_ast_expr_free(expr);
+	isl_ast_expr_free(expr2);
+
+	if (ok < 0 || equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"equal expressions not considered equal", return -1);
+	if (!ok)
+		isl_die(ctx, isl_error_unknown,
+			"isl_ast_expr printed incorrectly", return -1);
+
+	expr1 = isl_ast_expr_from_id(isl_id_alloc(ctx, "A", NULL));
+	expr2 = isl_ast_expr_from_id(isl_id_alloc(ctx, "B", NULL));
+	expr = isl_ast_expr_add(expr1, expr2);
+	expr3 = isl_ast_expr_from_id(isl_id_alloc(ctx, "C", NULL));
+	expr = isl_ast_expr_sub(expr3, expr);
+	str = isl_ast_expr_to_C_str(expr);
+	ok = str ? !strcmp(str, "C - (A + B)") : -1;
+	free(str);
+	isl_ast_expr_free(expr);
+
+	if (ok < 0)
+		return -1;
+	if (!ok)
+		isl_die(ctx, isl_error_unknown,
+			"isl_ast_expr printed incorrectly", return -1);
+
+	return 0;
+}
+
+/* Check that isl_ast_build_expr_from_set returns a valid expression
+ * for an empty set.  Note that isl_ast_build_expr_from_set getting
+ * called on an empty set probably indicates a bug in the caller.
+ */
+static int test_ast_build(isl_ctx *ctx)
+{
+	isl_set *set;
+	isl_ast_build *build;
+	isl_ast_expr *expr;
+
+	set = isl_set_universe(isl_space_params_alloc(ctx, 0));
+	build = isl_ast_build_from_context(set);
+
+	set = isl_set_empty(isl_space_params_alloc(ctx, 0));
+	expr = isl_ast_build_expr_from_set(build, set);
+
+	isl_ast_expr_free(expr);
+	isl_ast_build_free(build);
+
+	if (!expr)
+		return -1;
+
+	return 0;
+}
+
+/* Internal data structure for before_for and after_for callbacks.
+ *
+ * depth is the current depth
+ * before is the number of times before_for has been called
+ * after is the number of times after_for has been called
+ */
+struct isl_test_codegen_data {
+	int depth;
+	int before;
+	int after;
+};
+
+/* This function is called before each for loop in the AST generated
+ * from test_ast_gen1.
+ *
+ * Increment the number of calls and the depth.
+ * Check that the space returned by isl_ast_build_get_schedule_space
+ * matches the target space of the schedule returned by
+ * isl_ast_build_get_schedule.
+ * Return an isl_id that is checked by the corresponding call
+ * to after_for.
+ */
+static __isl_give isl_id *before_for(__isl_keep isl_ast_build *build,
+	void *user)
+{
+	struct isl_test_codegen_data *data = user;
+	isl_ctx *ctx;
+	isl_space *space;
+	isl_union_map *schedule;
+	isl_union_set *uset;
+	isl_set *set;
+	int empty;
+	char name[] = "d0";
+
+	ctx = isl_ast_build_get_ctx(build);
+
+	if (data->before >= 3)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected number of for nodes", return NULL);
+	if (data->depth >= 2)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected depth", return NULL);
+
+	snprintf(name, sizeof(name), "d%d", data->depth);
+	data->before++;
+	data->depth++;
+
+	schedule = isl_ast_build_get_schedule(build);
+	uset = isl_union_map_range(schedule);
+	if (!uset)
+		return NULL;
+	if (isl_union_set_n_set(uset) != 1) {
+		isl_union_set_free(uset);
+		isl_die(ctx, isl_error_unknown,
+			"expecting single range space", return NULL);
+	}
+
+	space = isl_ast_build_get_schedule_space(build);
+	set = isl_union_set_extract_set(uset, space);
+	isl_union_set_free(uset);
+	empty = isl_set_is_empty(set);
+	isl_set_free(set);
+
+	if (empty < 0)
+		return NULL;
+	if (empty)
+		isl_die(ctx, isl_error_unknown,
+			"spaces don't match", return NULL);
+
+	return isl_id_alloc(ctx, name, NULL);
+}
+
+/* This function is called after each for loop in the AST generated
+ * from test_ast_gen1.
+ *
+ * Increment the number of calls and decrement the depth.
+ * Check that the annotation attached to the node matches
+ * the isl_id returned by the corresponding call to before_for.
+ */
+static __isl_give isl_ast_node *after_for(__isl_take isl_ast_node *node,
+	__isl_keep isl_ast_build *build, void *user)
+{
+	struct isl_test_codegen_data *data = user;
+	isl_id *id;
+	const char *name;
+	int valid;
+
+	data->after++;
+	data->depth--;
+
+	if (data->after > data->before)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_unknown,
+			"mismatch in number of for nodes",
+			return isl_ast_node_free(node));
+
+	id = isl_ast_node_get_annotation(node);
+	if (!id)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_unknown,
+			"missing annotation", return isl_ast_node_free(node));
+
+	name = isl_id_get_name(id);
+	valid = name && atoi(name + 1) == data->depth;
+	isl_id_free(id);
+
+	if (!valid)
+		isl_die(isl_ast_node_get_ctx(node), isl_error_unknown,
+			"wrong annotation", return isl_ast_node_free(node));
+
+	return node;
+}
+
+/* Check that the before_each_for and after_each_for callbacks
+ * are called for each for loop in the generated code,
+ * that they are called in the right order and that the isl_id
+ * returned from the before_each_for callback is attached to
+ * the isl_ast_node passed to the corresponding after_each_for call.
+ */
+static int test_ast_gen1(isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *set;
+	isl_union_map *schedule;
+	isl_ast_build *build;
+	isl_ast_node *tree;
+	struct isl_test_codegen_data data;
+
+	str = "[N] -> { : N >= 10 }";
+	set = isl_set_read_from_str(ctx, str);
+	str = "[N] -> { A[i,j] -> S[8,i,3,j] : 0 <= i,j <= N; "
+		    "B[i,j] -> S[8,j,9,i] : 0 <= i,j <= N }";
+	schedule = isl_union_map_read_from_str(ctx, str);
+
+	data.before = 0;
+	data.after = 0;
+	data.depth = 0;
+	build = isl_ast_build_from_context(set);
+	build = isl_ast_build_set_before_each_for(build,
+			&before_for, &data);
+	build = isl_ast_build_set_after_each_for(build,
+			&after_for, &data);
+	tree = isl_ast_build_node_from_schedule_map(build, schedule);
+	isl_ast_build_free(build);
+	if (!tree)
+		return -1;
+
+	isl_ast_node_free(tree);
+
+	if (data.before != 3 || data.after != 3)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected number of for nodes", return -1);
+
+	return 0;
+}
+
+/* Check that the AST generator handles domains that are integrally disjoint
+ * but not rationally disjoint.
+ */
+static int test_ast_gen2(isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *set;
+	isl_union_map *schedule;
+	isl_union_map *options;
+	isl_ast_build *build;
+	isl_ast_node *tree;
+
+	str = "{ A[i,j] -> [i,j] : 0 <= i,j <= 1 }";
+	schedule = isl_union_map_read_from_str(ctx, str);
+	set = isl_set_universe(isl_space_params_alloc(ctx, 0));
+	build = isl_ast_build_from_context(set);
+
+	str = "{ [i,j] -> atomic[1] : i + j = 1; [i,j] -> unroll[1] : i = j }";
+	options = isl_union_map_read_from_str(ctx, str);
+	build = isl_ast_build_set_options(build, options);
+	tree = isl_ast_build_node_from_schedule_map(build, schedule);
+	isl_ast_build_free(build);
+	if (!tree)
+		return -1;
+	isl_ast_node_free(tree);
+
+	return 0;
+}
+
+/* Increment *user on each call.
+ */
+static __isl_give isl_ast_node *count_domains(__isl_take isl_ast_node *node,
+	__isl_keep isl_ast_build *build, void *user)
+{
+	int *n = user;
+
+	(*n)++;
+
+	return node;
+}
+
+/* Test that unrolling tries to minimize the number of instances.
+ * In particular, for the schedule given below, make sure it generates
+ * 3 nodes (rather than 101).
+ */
+static int test_ast_gen3(isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *set;
+	isl_union_map *schedule;
+	isl_union_map *options;
+	isl_ast_build *build;
+	isl_ast_node *tree;
+	int n_domain = 0;
+
+	str = "[n] -> { A[i] -> [i] : 0 <= i <= 100 and n <= i <= n + 2 }";
+	schedule = isl_union_map_read_from_str(ctx, str);
+	set = isl_set_universe(isl_space_params_alloc(ctx, 0));
+
+	str = "{ [i] -> unroll[0] }";
+	options = isl_union_map_read_from_str(ctx, str);
+
+	build = isl_ast_build_from_context(set);
+	build = isl_ast_build_set_options(build, options);
+	build = isl_ast_build_set_at_each_domain(build,
+			&count_domains, &n_domain);
+	tree = isl_ast_build_node_from_schedule_map(build, schedule);
+	isl_ast_build_free(build);
+	if (!tree)
+		return -1;
+
+	isl_ast_node_free(tree);
+
+	if (n_domain != 3)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected number of for nodes", return -1);
+
+	return 0;
+}
+
+/* Check that if the ast_build_exploit_nested_bounds options is set,
+ * we do not get an outer if node in the generated AST,
+ * while we do get such an outer if node if the options is not set.
+ */
+static int test_ast_gen4(isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *set;
+	isl_union_map *schedule;
+	isl_ast_build *build;
+	isl_ast_node *tree;
+	enum isl_ast_node_type type;
+	int enb;
+
+	enb = isl_options_get_ast_build_exploit_nested_bounds(ctx);
+	str = "[N,M] -> { A[i,j] -> [i,j] : 0 <= i <= N and 0 <= j <= M }";
+
+	isl_options_set_ast_build_exploit_nested_bounds(ctx, 1);
+
+	schedule = isl_union_map_read_from_str(ctx, str);
+	set = isl_set_universe(isl_space_params_alloc(ctx, 0));
+	build = isl_ast_build_from_context(set);
+	tree = isl_ast_build_node_from_schedule_map(build, schedule);
+	isl_ast_build_free(build);
+	if (!tree)
+		return -1;
+
+	type = isl_ast_node_get_type(tree);
+	isl_ast_node_free(tree);
+
+	if (type == isl_ast_node_if)
+		isl_die(ctx, isl_error_unknown,
+			"not expecting if node", return -1);
+
+	isl_options_set_ast_build_exploit_nested_bounds(ctx, 0);
+
+	schedule = isl_union_map_read_from_str(ctx, str);
+	set = isl_set_universe(isl_space_params_alloc(ctx, 0));
+	build = isl_ast_build_from_context(set);
+	tree = isl_ast_build_node_from_schedule_map(build, schedule);
+	isl_ast_build_free(build);
+	if (!tree)
+		return -1;
+
+	type = isl_ast_node_get_type(tree);
+	isl_ast_node_free(tree);
+
+	if (type != isl_ast_node_if)
+		isl_die(ctx, isl_error_unknown,
+			"expecting if node", return -1);
+
+	isl_options_set_ast_build_exploit_nested_bounds(ctx, enb);
+
+	return 0;
+}
+
+/* This function is called for each leaf in the AST generated
+ * from test_ast_gen5.
+ *
+ * We finalize the AST generation by extending the outer schedule
+ * with a zero-dimensional schedule.  If this results in any for loops,
+ * then this means that we did not pass along enough information
+ * about the outer schedule to the inner AST generation.
+ */
+static __isl_give isl_ast_node *create_leaf(__isl_take isl_ast_build *build,
+	void *user)
+{
+	isl_union_map *schedule, *extra;
+	isl_ast_node *tree;
+
+	schedule = isl_ast_build_get_schedule(build);
+	extra = isl_union_map_copy(schedule);
+	extra = isl_union_map_from_domain(isl_union_map_domain(extra));
+	schedule = isl_union_map_range_product(schedule, extra);
+	tree = isl_ast_build_node_from_schedule_map(build, schedule);
+	isl_ast_build_free(build);
+
+	if (!tree)
+		return NULL;
+
+	if (isl_ast_node_get_type(tree) == isl_ast_node_for)
+		isl_die(isl_ast_node_get_ctx(tree), isl_error_unknown,
+			"code should not contain any for loop",
+			return isl_ast_node_free(tree));
+
+	return tree;
+}
+
+/* Check that we do not lose any information when going back and
+ * forth between internal and external schedule.
+ *
+ * In particular, we create an AST where we unroll the only
+ * non-constant dimension in the schedule.  We therefore do
+ * not expect any for loops in the AST.  However, older versions
+ * of isl would not pass along enough information about the outer
+ * schedule when performing an inner code generation from a create_leaf
+ * callback, resulting in the inner code generation producing a for loop.
+ */
+static int test_ast_gen5(isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *set;
+	isl_union_map *schedule, *options;
+	isl_ast_build *build;
+	isl_ast_node *tree;
+
+	str = "{ A[] -> [1, 1, 2]; B[i] -> [1, i, 0] : i >= 1 and i <= 2 }";
+	schedule = isl_union_map_read_from_str(ctx, str);
+
+	str = "{ [a, b, c] -> unroll[1] : exists (e0 = [(a)/4]: "
+				"4e0 >= -1 + a - b and 4e0 <= -2 + a + b) }";
+	options = isl_union_map_read_from_str(ctx, str);
+
+	set = isl_set_universe(isl_space_params_alloc(ctx, 0));
+	build = isl_ast_build_from_context(set);
+	build = isl_ast_build_set_options(build, options);
+        build = isl_ast_build_set_create_leaf(build, &create_leaf, NULL);
+	tree = isl_ast_build_node_from_schedule_map(build, schedule);
+	isl_ast_build_free(build);
+	isl_ast_node_free(tree);
+	if (!tree)
+		return -1;
+
+	return 0;
+}
+
+/* Check that the expression
+ *
+ *	[n] -> { [n/2] : n <= 0 and n % 2 = 0; [0] : n > 0 }
+ *
+ * is not combined into
+ *
+ *	min(n/2, 0)
+ *
+ * as this would result in n/2 being evaluated in parts of
+ * the definition domain where n is not a multiple of 2.
+ */
+static int test_ast_expr(isl_ctx *ctx)
+{
+	const char *str;
+	isl_pw_aff *pa;
+	isl_ast_build *build;
+	isl_ast_expr *expr;
+	int min_max;
+	int is_min;
+
+	min_max = isl_options_get_ast_build_detect_min_max(ctx);
+	isl_options_set_ast_build_detect_min_max(ctx, 1);
+
+	str = "[n] -> { [n/2] : n <= 0 and n % 2 = 0; [0] : n > 0 }";
+	pa = isl_pw_aff_read_from_str(ctx, str);
+	build = isl_ast_build_alloc(ctx);
+	expr = isl_ast_build_expr_from_pw_aff(build, pa);
+	is_min = isl_ast_expr_get_type(expr) == isl_ast_expr_op &&
+		 isl_ast_expr_get_op_type(expr) == isl_ast_op_min;
+	isl_ast_build_free(build);
+	isl_ast_expr_free(expr);
+
+	isl_options_set_ast_build_detect_min_max(ctx, min_max);
+
+	if (!expr)
+		return -1;
+	if (is_min)
+		isl_die(ctx, isl_error_unknown,
+			"expressions should not be combined", return -1);
+
+	return 0;
+}
+
+static int test_ast_gen(isl_ctx *ctx)
+{
+	if (test_ast_gen1(ctx) < 0)
+		return -1;
+	if (test_ast_gen2(ctx) < 0)
+		return -1;
+	if (test_ast_gen3(ctx) < 0)
+		return -1;
+	if (test_ast_gen4(ctx) < 0)
+		return -1;
+	if (test_ast_gen5(ctx) < 0)
+		return -1;
+	if (test_ast_expr(ctx) < 0)
+		return -1;
+	return 0;
+}
+
+/* Check if dropping output dimensions from an isl_pw_multi_aff
+ * works properly.
+ */
+static int test_pw_multi_aff(isl_ctx *ctx)
+{
+	const char *str;
+	isl_pw_multi_aff *pma1, *pma2;
+	int equal;
+
+	str = "{ [i,j] -> [i+j, 4i-j] }";
+	pma1 = isl_pw_multi_aff_read_from_str(ctx, str);
+	str = "{ [i,j] -> [4i-j] }";
+	pma2 = isl_pw_multi_aff_read_from_str(ctx, str);
+
+	pma1 = isl_pw_multi_aff_drop_dims(pma1, isl_dim_out, 0, 1);
+
+	equal = isl_pw_multi_aff_plain_is_equal(pma1, pma2);
+
+	isl_pw_multi_aff_free(pma1);
+	isl_pw_multi_aff_free(pma2);
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"expressions not equal", return -1);
+
+	return 0;
+}
+
+/* Check that we can properly parse multi piecewise affine expressions
+ * where the piecewise affine expressions have different domains.
+ */
+static int test_multi_pw_aff(isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *dom, *dom2;
+	isl_multi_pw_aff *mpa1, *mpa2;
+	isl_pw_aff *pa;
+	int equal;
+	int equal_domain;
+
+	mpa1 = isl_multi_pw_aff_read_from_str(ctx, "{ [i] -> [i] }");
+	dom = isl_set_read_from_str(ctx, "{ [i] : i > 0 }");
+	mpa1 = isl_multi_pw_aff_intersect_domain(mpa1, dom);
+	mpa2 = isl_multi_pw_aff_read_from_str(ctx, "{ [i] -> [2i] }");
+	mpa2 = isl_multi_pw_aff_flat_range_product(mpa1, mpa2);
+	str = "{ [i] -> [(i : i > 0), 2i] }";
+	mpa1 = isl_multi_pw_aff_read_from_str(ctx, str);
+
+	equal = isl_multi_pw_aff_plain_is_equal(mpa1, mpa2);
+
+	pa = isl_multi_pw_aff_get_pw_aff(mpa1, 0);
+	dom = isl_pw_aff_domain(pa);
+	pa = isl_multi_pw_aff_get_pw_aff(mpa1, 1);
+	dom2 = isl_pw_aff_domain(pa);
+	equal_domain = isl_set_is_equal(dom, dom2);
+
+	isl_set_free(dom);
+	isl_set_free(dom2);
+	isl_multi_pw_aff_free(mpa1);
+	isl_multi_pw_aff_free(mpa2);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"expressions not equal", return -1);
+
+	if (equal_domain < 0)
+		return -1;
+	if (equal_domain)
+		isl_die(ctx, isl_error_unknown,
+			"domains unexpectedly equal", return -1);
+
+	return 0;
+}
+
+/* This is a regression test for a bug where isl_basic_map_simplify
+ * would end up in an infinite loop.  In particular, we construct
+ * an empty basic set that is not obviously empty.
+ * isl_basic_set_is_empty marks the basic set as empty.
+ * After projecting out i3, the variable can be dropped completely,
+ * but isl_basic_map_simplify refrains from doing so if the basic set
+ * is empty and would end up in an infinite loop if it didn't test
+ * explicitly for empty basic maps in the outer loop.
+ */
+static int test_simplify_1(isl_ctx *ctx)
+{
+	const char *str;
+	isl_basic_set *bset;
+	int empty;
+
+	str = "{ [i0, i1, i2, i3] : i0 >= -2 and 6i2 <= 4 + i0 + 5i1 and "
+		"i2 <= 22 and 75i2 <= 111 + 13i0 + 60i1 and "
+		"25i2 >= 38 + 6i0 + 20i1 and i0 <= -1 and i2 >= 20 and "
+		"i3 >= i2 }";
+	bset = isl_basic_set_read_from_str(ctx, str);
+	empty = isl_basic_set_is_empty(bset);
+	bset = isl_basic_set_project_out(bset, isl_dim_set, 3, 1);
+	isl_basic_set_free(bset);
+	if (!bset)
+		return -1;
+	if (!empty)
+		isl_die(ctx, isl_error_unknown,
+			"basic set should be empty", return -1);
+
+	return 0;
+}
+
+/* Check that the equality in the set description below
+ * is simplified away.
+ */
+static int test_simplify_2(isl_ctx *ctx)
+{
+	const char *str;
+	isl_basic_set *bset;
+	isl_bool universe;
+
+	str = "{ [a] : exists e0, e1: 32e1 = 31 + 31a + 31e0 }";
+	bset = isl_basic_set_read_from_str(ctx, str);
+	universe = isl_basic_set_plain_is_universe(bset);
+	isl_basic_set_free(bset);
+
+	if (universe < 0)
+		return -1;
+	if (!universe)
+		isl_die(ctx, isl_error_unknown,
+			"equality not simplified away", return -1);
+	return 0;
+}
+
+/* Some simplification tests.
+ */
+static int test_simplify(isl_ctx *ctx)
+{
+	if (test_simplify_1(ctx) < 0)
+		return -1;
+	if (test_simplify_2(ctx) < 0)
+		return -1;
+	return 0;
+}
+
+/* This is a regression test for a bug where isl_tab_basic_map_partial_lexopt
+ * with gbr context would fail to disable the use of the shifted tableau
+ * when transferring equalities for the input to the context, resulting
+ * in invalid sample values.
+ */
+static int test_partial_lexmin(isl_ctx *ctx)
+{
+	const char *str;
+	isl_basic_set *bset;
+	isl_basic_map *bmap;
+	isl_map *map;
+
+	str = "{ [1, b, c, 1 - c] -> [e] : 2e <= -c and 2e >= -3 + c }";
+	bmap = isl_basic_map_read_from_str(ctx, str);
+	str = "{ [a, b, c, d] : c <= 1 and 2d >= 6 - 4b - c }";
+	bset = isl_basic_set_read_from_str(ctx, str);
+	map = isl_basic_map_partial_lexmin(bmap, bset, NULL);
+	isl_map_free(map);
+
+	if (!map)
+		return -1;
+
+	return 0;
+}
+
+/* Check that the variable compression performed on the existentially
+ * quantified variables inside isl_basic_set_compute_divs is not confused
+ * by the implicit equalities among the parameters.
+ */
+static int test_compute_divs(isl_ctx *ctx)
+{
+	const char *str;
+	isl_basic_set *bset;
+	isl_set *set;
+
+	str = "[a, b, c, d, e] -> { [] : exists (e0: 2d = b and a <= 124 and "
+		"b <= 2046 and b >= 0 and b <= 60 + 64a and 2e >= b + 2c and "
+		"2e >= b and 2e <= 1 + b and 2e <= 1 + b + 2c and "
+		"32768e0 >= -124 + a and 2097152e0 <= 60 + 64a - b) }";
+	bset = isl_basic_set_read_from_str(ctx, str);
+	set = isl_basic_set_compute_divs(bset);
+	isl_set_free(set);
+	if (!set)
+		return -1;
+
+	return 0;
+}
+
+/* Check that the reaching domain elements and the prefix schedule
+ * at a leaf node are the same before and after grouping.
+ */
+static int test_schedule_tree_group_1(isl_ctx *ctx)
+{
+	int equal;
+	const char *str;
+	isl_id *id;
+	isl_union_set *uset;
+	isl_multi_union_pw_aff *mupa;
+	isl_union_pw_multi_aff *upma1, *upma2;
+	isl_union_set *domain1, *domain2;
+	isl_union_map *umap1, *umap2;
+	isl_schedule_node *node;
+
+	str = "{ S1[i,j] : 0 <= i,j < 10; S2[i,j] : 0 <= i,j < 10 }";
+	uset = isl_union_set_read_from_str(ctx, str);
+	node = isl_schedule_node_from_domain(uset);
+	node = isl_schedule_node_child(node, 0);
+	str = "[{ S1[i,j] -> [i]; S2[i,j] -> [9 - i] }]";
+	mupa = isl_multi_union_pw_aff_read_from_str(ctx, str);
+	node = isl_schedule_node_insert_partial_schedule(node, mupa);
+	node = isl_schedule_node_child(node, 0);
+	str = "[{ S1[i,j] -> [j]; S2[i,j] -> [j] }]";
+	mupa = isl_multi_union_pw_aff_read_from_str(ctx, str);
+	node = isl_schedule_node_insert_partial_schedule(node, mupa);
+	node = isl_schedule_node_child(node, 0);
+	umap1 = isl_schedule_node_get_prefix_schedule_union_map(node);
+	upma1 = isl_schedule_node_get_prefix_schedule_union_pw_multi_aff(node);
+	domain1 = isl_schedule_node_get_domain(node);
+	id = isl_id_alloc(ctx, "group", NULL);
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_group(node, id);
+	node = isl_schedule_node_child(node, 0);
+	umap2 = isl_schedule_node_get_prefix_schedule_union_map(node);
+	upma2 = isl_schedule_node_get_prefix_schedule_union_pw_multi_aff(node);
+	domain2 = isl_schedule_node_get_domain(node);
+	equal = isl_union_pw_multi_aff_plain_is_equal(upma1, upma2);
+	if (equal >= 0 && equal)
+		equal = isl_union_set_is_equal(domain1, domain2);
+	if (equal >= 0 && equal)
+		equal = isl_union_map_is_equal(umap1, umap2);
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+	isl_union_set_free(domain1);
+	isl_union_set_free(domain2);
+	isl_union_pw_multi_aff_free(upma1);
+	isl_union_pw_multi_aff_free(upma2);
+	isl_schedule_node_free(node);
+
+	if (equal < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"expressions not equal", return -1);
+
+	return 0;
+}
+
+/* Check that we can have nested groupings and that the union map
+ * schedule representation is the same before and after the grouping.
+ * Note that after the grouping, the union map representation contains
+ * the domain constraints from the ranges of the expansion nodes,
+ * while they are missing from the union map representation of
+ * the tree without expansion nodes.
+ *
+ * Also check that the global expansion is as expected.
+ */
+static int test_schedule_tree_group_2(isl_ctx *ctx)
+{
+	int equal, equal_expansion;
+	const char *str;
+	isl_id *id;
+	isl_union_set *uset;
+	isl_union_map *umap1, *umap2;
+	isl_union_map *expansion1, *expansion2;
+	isl_union_set_list *filters;
+	isl_multi_union_pw_aff *mupa;
+	isl_schedule *schedule;
+	isl_schedule_node *node;
+
+	str = "{ S1[i,j] : 0 <= i,j < 10; S2[i,j] : 0 <= i,j < 10; "
+		"S3[i,j] : 0 <= i,j < 10 }";
+	uset = isl_union_set_read_from_str(ctx, str);
+	node = isl_schedule_node_from_domain(uset);
+	node = isl_schedule_node_child(node, 0);
+	str = "[{ S1[i,j] -> [i]; S2[i,j] -> [i]; S3[i,j] -> [i] }]";
+	mupa = isl_multi_union_pw_aff_read_from_str(ctx, str);
+	node = isl_schedule_node_insert_partial_schedule(node, mupa);
+	node = isl_schedule_node_child(node, 0);
+	str = "{ S1[i,j] }";
+	uset = isl_union_set_read_from_str(ctx, str);
+	filters = isl_union_set_list_from_union_set(uset);
+	str = "{ S2[i,j]; S3[i,j] }";
+	uset = isl_union_set_read_from_str(ctx, str);
+	filters = isl_union_set_list_add(filters, uset);
+	node = isl_schedule_node_insert_sequence(node, filters);
+	node = isl_schedule_node_child(node, 1);
+	node = isl_schedule_node_child(node, 0);
+	str = "{ S2[i,j] }";
+	uset = isl_union_set_read_from_str(ctx, str);
+	filters = isl_union_set_list_from_union_set(uset);
+	str = "{ S3[i,j] }";
+	uset = isl_union_set_read_from_str(ctx, str);
+	filters = isl_union_set_list_add(filters, uset);
+	node = isl_schedule_node_insert_sequence(node, filters);
+
+	schedule = isl_schedule_node_get_schedule(node);
+	umap1 = isl_schedule_get_map(schedule);
+	uset = isl_schedule_get_domain(schedule);
+	umap1 = isl_union_map_intersect_domain(umap1, uset);
+	isl_schedule_free(schedule);
+
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_parent(node);
+	id = isl_id_alloc(ctx, "group1", NULL);
+	node = isl_schedule_node_group(node, id);
+	node = isl_schedule_node_child(node, 1);
+	node = isl_schedule_node_child(node, 0);
+	id = isl_id_alloc(ctx, "group2", NULL);
+	node = isl_schedule_node_group(node, id);
+
+	schedule = isl_schedule_node_get_schedule(node);
+	umap2 = isl_schedule_get_map(schedule);
+	isl_schedule_free(schedule);
+
+	node = isl_schedule_node_root(node);
+	node = isl_schedule_node_child(node, 0);
+	expansion1 = isl_schedule_node_get_subtree_expansion(node);
+	isl_schedule_node_free(node);
+
+	str = "{ group1[i] -> S1[i,j] : 0 <= i,j < 10; "
+		"group1[i] -> S2[i,j] : 0 <= i,j < 10; "
+		"group1[i] -> S3[i,j] : 0 <= i,j < 10 }";
+
+	expansion2 = isl_union_map_read_from_str(ctx, str);
+
+	equal = isl_union_map_is_equal(umap1, umap2);
+	equal_expansion = isl_union_map_is_equal(expansion1, expansion2);
+
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+	isl_union_map_free(expansion1);
+	isl_union_map_free(expansion2);
+
+	if (equal < 0 || equal_expansion < 0)
+		return -1;
+	if (!equal)
+		isl_die(ctx, isl_error_unknown,
+			"expressions not equal", return -1);
+	if (!equal_expansion)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected expansion", return -1);
+
+	return 0;
+}
+
+/* Some tests for the isl_schedule_node_group function.
+ */
+static int test_schedule_tree_group(isl_ctx *ctx)
+{
+	if (test_schedule_tree_group_1(ctx) < 0)
+		return -1;
+	if (test_schedule_tree_group_2(ctx) < 0)
+		return -1;
+	return 0;
+}
+
+struct {
+	const char *set;
+	const char *dual;
+} coef_tests[] = {
+	{ "{ rat: [i] : 0 <= i <= 10 }",
+	  "{ rat: coefficients[[cst] -> [a]] : cst >= 0 and 10a + cst >= 0 }" },
+	{ "{ rat: [i] : FALSE }",
+	  "{ rat: coefficients[[cst] -> [a]] }" },
+	{ "{ rat: [i] : }",
+	  "{ rat: coefficients[[cst] -> [0]] : cst >= 0 }" },
+};
+
+struct {
+	const char *set;
+	const char *dual;
+} sol_tests[] = {
+	{ "{ rat: coefficients[[cst] -> [a]] : cst >= 0 and 10a + cst >= 0 }",
+	  "{ rat: [i] : 0 <= i <= 10 }" },
+	{ "{ rat: coefficients[[cst] -> [a]] : FALSE }",
+	  "{ rat: [i] }" },
+	{ "{ rat: coefficients[[cst] -> [a]] }",
+	  "{ rat: [i] : FALSE }" },
+};
+
+/* Test the basic functionality of isl_basic_set_coefficients and
+ * isl_basic_set_solutions.
+ */
+static int test_dual(isl_ctx *ctx)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coef_tests); ++i) {
+		int equal;
+		isl_basic_set *bset1, *bset2;
+
+		bset1 = isl_basic_set_read_from_str(ctx, coef_tests[i].set);
+		bset2 = isl_basic_set_read_from_str(ctx, coef_tests[i].dual);
+		bset1 = isl_basic_set_coefficients(bset1);
+		equal = isl_basic_set_is_equal(bset1, bset2);
+		isl_basic_set_free(bset1);
+		isl_basic_set_free(bset2);
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown,
+				"incorrect dual", return -1);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sol_tests); ++i) {
+		int equal;
+		isl_basic_set *bset1, *bset2;
+
+		bset1 = isl_basic_set_read_from_str(ctx, sol_tests[i].set);
+		bset2 = isl_basic_set_read_from_str(ctx, sol_tests[i].dual);
+		bset1 = isl_basic_set_solutions(bset1);
+		equal = isl_basic_set_is_equal(bset1, bset2);
+		isl_basic_set_free(bset1);
+		isl_basic_set_free(bset2);
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown,
+				"incorrect dual", return -1);
+	}
+
+	return 0;
+}
+
+struct {
+	int scale_tile;
+	int shift_point;
+	const char *domain;
+	const char *schedule;
+	const char *sizes;
+	const char *tile;
+	const char *point;
+} tile_tests[] = {
+	{ 0, 0, "[n] -> { S[i,j] : 0 <= i,j < n }",
+	  "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]",
+	  "{ [32,32] }",
+	  "[{ S[i,j] -> [floor(i/32)] }, { S[i,j] -> [floor(j/32)] }]",
+	  "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]",
+	},
+	{ 1, 0, "[n] -> { S[i,j] : 0 <= i,j < n }",
+	  "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]",
+	  "{ [32,32] }",
+	  "[{ S[i,j] -> [32*floor(i/32)] }, { S[i,j] -> [32*floor(j/32)] }]",
+	  "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]",
+	},
+	{ 0, 1, "[n] -> { S[i,j] : 0 <= i,j < n }",
+	  "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]",
+	  "{ [32,32] }",
+	  "[{ S[i,j] -> [floor(i/32)] }, { S[i,j] -> [floor(j/32)] }]",
+	  "[{ S[i,j] -> [i%32] }, { S[i,j] -> [j%32] }]",
+	},
+	{ 1, 1, "[n] -> { S[i,j] : 0 <= i,j < n }",
+	  "[{ S[i,j] -> [i] }, { S[i,j] -> [j] }]",
+	  "{ [32,32] }",
+	  "[{ S[i,j] -> [32*floor(i/32)] }, { S[i,j] -> [32*floor(j/32)] }]",
+	  "[{ S[i,j] -> [i%32] }, { S[i,j] -> [j%32] }]",
+	},
+};
+
+/* Basic tiling tests.  Create a schedule tree with a domain and a band node,
+ * tile the band and then check if the tile and point bands have the
+ * expected partial schedule.
+ */
+static int test_tile(isl_ctx *ctx)
+{
+	int i;
+	int scale;
+	int shift;
+
+	scale = isl_options_get_tile_scale_tile_loops(ctx);
+	shift = isl_options_get_tile_shift_point_loops(ctx);
+
+	for (i = 0; i < ARRAY_SIZE(tile_tests); ++i) {
+		int opt;
+		int equal;
+		const char *str;
+		isl_union_set *domain;
+		isl_multi_union_pw_aff *mupa, *mupa2;
+		isl_schedule_node *node;
+		isl_multi_val *sizes;
+
+		opt = tile_tests[i].scale_tile;
+		isl_options_set_tile_scale_tile_loops(ctx, opt);
+		opt = tile_tests[i].shift_point;
+		isl_options_set_tile_shift_point_loops(ctx, opt);
+
+		str = tile_tests[i].domain;
+		domain = isl_union_set_read_from_str(ctx, str);
+		node = isl_schedule_node_from_domain(domain);
+		node = isl_schedule_node_child(node, 0);
+		str = tile_tests[i].schedule;
+		mupa = isl_multi_union_pw_aff_read_from_str(ctx, str);
+		node = isl_schedule_node_insert_partial_schedule(node, mupa);
+		str = tile_tests[i].sizes;
+		sizes = isl_multi_val_read_from_str(ctx, str);
+		node = isl_schedule_node_band_tile(node, sizes);
+
+		str = tile_tests[i].tile;
+		mupa = isl_multi_union_pw_aff_read_from_str(ctx, str);
+		mupa2 = isl_schedule_node_band_get_partial_schedule(node);
+		equal = isl_multi_union_pw_aff_plain_is_equal(mupa, mupa2);
+		isl_multi_union_pw_aff_free(mupa);
+		isl_multi_union_pw_aff_free(mupa2);
+
+		node = isl_schedule_node_child(node, 0);
+
+		str = tile_tests[i].point;
+		mupa = isl_multi_union_pw_aff_read_from_str(ctx, str);
+		mupa2 = isl_schedule_node_band_get_partial_schedule(node);
+		if (equal >= 0 && equal)
+			equal = isl_multi_union_pw_aff_plain_is_equal(mupa,
+									mupa2);
+		isl_multi_union_pw_aff_free(mupa);
+		isl_multi_union_pw_aff_free(mupa2);
+
+		isl_schedule_node_free(node);
+
+		if (equal < 0)
+			return -1;
+		if (!equal)
+			isl_die(ctx, isl_error_unknown,
+				"unexpected result", return -1);
+	}
+
+	isl_options_set_tile_scale_tile_loops(ctx, scale);
+	isl_options_set_tile_shift_point_loops(ctx, shift);
+
+	return 0;
+}
+
+/* Check that the domain hash of a space is equal to the hash
+ * of the domain of the space.
+ */
+static int test_domain_hash(isl_ctx *ctx)
+{
+	isl_map *map;
+	isl_space *space;
+	uint32_t hash1, hash2;
+
+	map = isl_map_read_from_str(ctx, "[n] -> { A[B[x] -> C[]] -> D[] }");
+	space = isl_map_get_space(map);
+	isl_map_free(map);
+	hash1 = isl_space_get_domain_hash(space);
+	space = isl_space_domain(space);
+	hash2 = isl_space_get_hash(space);
+	isl_space_free(space);
+
+	if (!space)
+		return -1;
+	if (hash1 != hash2)
+		isl_die(ctx, isl_error_unknown,
+			"domain hash not equal to hash of domain", return -1);
+
+	return 0;
+}
+
+/* Check that a universe basic set that is not obviously equal to the universe
+ * is still recognized as being equal to the universe.
+ */
+static int test_universe(isl_ctx *ctx)
+{
+	const char *s;
+	isl_basic_set *bset;
+	isl_bool is_univ;
+
+	s = "{ [] : exists x, y : 3y <= 2x and y >= -3 + 2x and 2y >= 2 - x }";
+	bset = isl_basic_set_read_from_str(ctx, s);
+	is_univ = isl_basic_set_is_universe(bset);
+	isl_basic_set_free(bset);
+
+	if (is_univ < 0)
+		return -1;
+	if (!is_univ)
+		isl_die(ctx, isl_error_unknown,
+			"not recognized as universe set", return -1);
+
+	return 0;
+}
+
+/* Sets for which chambers are computed and checked.
+ */
+const char *chambers_tests[] = {
+	"[A, B, C] -> { [x, y, z] : x >= 0 and y >= 0 and y <= A - x and "
+				"z >= 0 and z <= C - y and z <= B - x - y }",
+};
+
+/* Add the domain of "cell" to "cells".
+ */
+static isl_stat add_cell(__isl_take isl_cell *cell, void *user)
+{
+	isl_basic_set_list **cells = user;
+	isl_basic_set *dom;
+
+	dom = isl_cell_get_domain(cell);
+	isl_cell_free(cell);
+	*cells = isl_basic_set_list_add(*cells, dom);
+
+	return *cells ? isl_stat_ok : isl_stat_error;
+}
+
+/* Check that the elements of "list" are pairwise disjoint.
+ */
+static isl_stat check_pairwise_disjoint(__isl_keep isl_basic_set_list *list)
+{
+	int i, j, n;
+
+	if (!list)
+		return isl_stat_error;
+
+	n = isl_basic_set_list_n_basic_set(list);
+	for (i = 0; i < n; ++i) {
+		isl_basic_set *bset_i;
+
+		bset_i = isl_basic_set_list_get_basic_set(list, i);
+		for (j = i + 1; j < n; ++j) {
+			isl_basic_set *bset_j;
+			isl_bool disjoint;
+
+			bset_j = isl_basic_set_list_get_basic_set(list, j);
+			disjoint = isl_basic_set_is_disjoint(bset_i, bset_j);
+			isl_basic_set_free(bset_j);
+			if (!disjoint)
+				isl_die(isl_basic_set_list_get_ctx(list),
+					isl_error_unknown, "not disjoint",
+					break);
+			if (disjoint < 0 || !disjoint)
+				break;
+		}
+		isl_basic_set_free(bset_i);
+		if (j < n)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Check that the chambers computed by isl_vertices_foreach_disjoint_cell
+ * are pairwise disjoint.
+ */
+static int test_chambers(isl_ctx *ctx)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chambers_tests); ++i) {
+		isl_basic_set *bset;
+		isl_vertices *vertices;
+		isl_basic_set_list *cells;
+		isl_stat ok;
+
+		bset = isl_basic_set_read_from_str(ctx, chambers_tests[i]);
+		vertices = isl_basic_set_compute_vertices(bset);
+		cells = isl_basic_set_list_alloc(ctx, 0);
+		if (isl_vertices_foreach_disjoint_cell(vertices, &add_cell,
+							&cells) < 0)
+			cells = isl_basic_set_list_free(cells);
+		ok = check_pairwise_disjoint(cells);
+		isl_basic_set_list_free(cells);
+		isl_vertices_free(vertices);
+		isl_basic_set_free(bset);
+
+		if (ok < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+struct {
+	const char *name;
+	int (*fn)(isl_ctx *ctx);
+} tests [] = {
+	{ "universe", &test_universe },
+	{ "domain hash", &test_domain_hash },
+	{ "dual", &test_dual },
+	{ "dependence analysis", &test_flow },
+	{ "val", &test_val },
+	{ "compute divs", &test_compute_divs },
+	{ "partial lexmin", &test_partial_lexmin },
+	{ "simplify", &test_simplify },
+	{ "curry", &test_curry },
+	{ "piecewise multi affine expressions", &test_pw_multi_aff },
+	{ "multi piecewise affine expressions", &test_multi_pw_aff },
+	{ "conversion", &test_conversion },
+	{ "list", &test_list },
+	{ "align parameters", &test_align_parameters },
+	{ "preimage", &test_preimage },
+	{ "pullback", &test_pullback },
+	{ "AST", &test_ast },
+	{ "AST build", &test_ast_build },
+	{ "AST generation", &test_ast_gen },
+	{ "eliminate", &test_eliminate },
+	{ "residue class", &test_residue_class },
+	{ "div", &test_div },
+	{ "slice", &test_slice },
+	{ "fixed power", &test_fixed_power },
+	{ "sample", &test_sample },
+	{ "output", &test_output },
+	{ "vertices", &test_vertices },
+	{ "chambers", &test_chambers },
+	{ "fixed", &test_fixed },
+	{ "equal", &test_equal },
+	{ "disjoint", &test_disjoint },
+	{ "product", &test_product },
+	{ "dim_max", &test_dim_max },
+	{ "affine", &test_aff },
+	{ "injective", &test_injective },
+	{ "schedule (whole component)", &test_schedule_whole },
+	{ "schedule (incremental)", &test_schedule_incremental },
+	{ "schedule tree grouping", &test_schedule_tree_group },
+	{ "tile", &test_tile },
+	{ "union_pw", &test_union_pw },
+	{ "eval", &test_eval },
+	{ "parse", &test_parse },
+	{ "single-valued", &test_sv },
+	{ "affine hull", &test_affine_hull },
+	{ "simple_hull", &test_simple_hull },
+	{ "coalesce", &test_coalesce },
+	{ "factorize", &test_factorize },
+	{ "subset", &test_subset },
+	{ "subtract", &test_subtract },
+	{ "intersect", &test_intersect },
+	{ "lexmin", &test_lexmin },
+	{ "min", &test_min },
+	{ "gist", &test_gist },
+	{ "piecewise quasi-polynomials", &test_pwqp },
+	{ "lift", &test_lift },
+	{ "bound", &test_bound },
+	{ "union", &test_union },
+	{ "split periods", &test_split_periods },
+	{ "lexicographic order", &test_lex },
+	{ "bijectivity", &test_bijective },
+	{ "dataflow analysis", &test_dep },
+	{ "reading", &test_read },
+	{ "bounded", &test_bounded },
+	{ "construction", &test_construction },
+	{ "dimension manipulation", &test_dim },
+	{ "map application", &test_application },
+	{ "convex hull", &test_convex_hull },
+	{ "transitive closure", &test_closure },
+};
+
+int main(int argc, char **argv)
+{
+	int i;
+	struct isl_ctx *ctx;
+	struct isl_options *options;
+
+	options = isl_options_new_with_defaults();
+	assert(options);
+	argc = isl_options_parse(options, argc, argv, ISL_ARG_ALL);
+
+	ctx = isl_ctx_alloc_with_options(&isl_options_args, options);
+	for (i = 0; i < ARRAY_SIZE(tests); ++i) {
+		printf("%s\n", tests[i].name);
+		if (tests[i].fn(ctx) < 0)
+			goto error;
+	}
+	isl_ctx_free(ctx);
+	return 0;
+error:
+	isl_ctx_free(ctx);
+	return -1;
+}
diff --git a/final/lib/External/isl/isl_test_imath.c b/final/lib/External/isl/isl_test_imath.c
new file mode 100644
index 0000000..fdb0777
--- /dev/null
+++ b/final/lib/External/isl/isl_test_imath.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2015 INRIA Paris-Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Michael Kruse, INRIA Paris-Rocquencourt,
+ * Domaine de Voluceau, Rocquenqourt, B.P. 105,
+ * 78153 Le Chesnay Cedex France
+ */
+
+#include <limits.h>
+#include <assert.h>
+#include <isl_imath.h>
+
+/* This constant is not defined in limits.h, but IMath uses it */
+#define ULONG_MIN 0ul
+
+/* Test the IMath internals assumed by the imath implementation of isl_int.
+ *
+ * In particular, we test the ranges of IMath-defined types.
+ *
+ * Also, isl uses the existence and function of imath's struct
+ * fields. The digits are stored with less significant digits at lower array
+ * indices. Where they are stored (on the heap or in the field 'single') does
+ * not matter.
+ */
+int test_imath_internals()
+{
+	mpz_t val;
+	mp_result retval;
+
+	assert(sizeof(mp_small) == sizeof(long));
+	assert(MP_SMALL_MIN == LONG_MIN);
+	assert(MP_SMALL_MAX == LONG_MAX);
+
+	assert(sizeof(mp_usmall) == sizeof(unsigned long));
+	assert(MP_USMALL_MIN == ULONG_MIN);
+	assert(MP_USMALL_MAX == ULONG_MAX);
+
+	retval = mp_int_init_value(&val, 0);
+	assert(retval == MP_OK);
+	assert(val.alloc >= val.used);
+	assert(val.used == 1);
+	assert(val.sign == MP_ZPOS);
+	assert(val.digits[0] == 0);
+
+	retval = mp_int_set_value(&val, -1);
+	assert(retval == MP_OK);
+	assert(val.alloc >= val.used);
+	assert(val.used == 1);
+	assert(val.sign == MP_NEG);
+	assert(val.digits[0] == 1);
+
+	retval = mp_int_set_value(&val, 1);
+	assert(retval == MP_OK);
+	assert(val.alloc >= val.used);
+	assert(val.used == 1);
+	assert(val.sign == MP_ZPOS);
+	assert(val.digits[0] == 1);
+
+	retval = mp_int_mul_pow2(&val, sizeof(mp_digit) * CHAR_BIT, &val);
+	assert(retval == MP_OK);
+	assert(val.alloc >= val.used);
+	assert(val.used == 2);
+	assert(val.sign == MP_ZPOS);
+	assert(val.digits[0] == 0);
+	assert(val.digits[1] == 1);
+
+	mp_int_clear(&val);
+	return 0;
+}
+
+int main()
+{
+	if (test_imath_internals() < 0)
+		return -1;
+
+	return 0;
+}
diff --git a/final/lib/External/isl/isl_test_int.c b/final/lib/External/isl/isl_test_int.c
new file mode 100644
index 0000000..a996411
--- /dev/null
+++ b/final/lib/External/isl/isl_test_int.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright 2015 INRIA Paris-Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Michael Kruse, INRIA Paris-Rocquencourt,
+ * Domaine de Voluceau, Rocquenqourt, B.P. 105,
+ * 78153 Le Chesnay Cedex France
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <isl_int.h>
+
+#define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
+
+#ifdef USE_SMALL_INT_OPT
+/* Test whether small and big representation of the same number have the same
+ * hash.
+ */
+static void int_test_hash(isl_int val)
+{
+	uint32_t demotedhash, promotedhash;
+	isl_int demoted, promoted;
+
+	isl_int_init(demoted);
+	isl_int_set(demoted, val);
+
+	isl_int_init(promoted);
+	isl_int_set(promoted, val);
+
+	isl_sioimath_try_demote(demoted);
+	isl_sioimath_promote(promoted);
+
+	assert(isl_int_eq(demoted, promoted));
+
+	demotedhash = isl_int_hash(demoted, 0);
+	promotedhash = isl_int_hash(promoted, 0);
+	assert(demotedhash == promotedhash);
+
+	isl_int_clear(demoted);
+	isl_int_clear(promoted);
+}
+
+struct {
+	void (*fn)(isl_int);
+	char *val;
+} int_single_value_tests[] = {
+	{ &int_test_hash, "0" },
+	{ &int_test_hash, "1" },
+	{ &int_test_hash, "-1" },
+	{ &int_test_hash, "23" },
+	{ &int_test_hash, "-23" },
+	{ &int_test_hash, "107" },
+	{ &int_test_hash, "32768" },
+	{ &int_test_hash, "2147483647" },
+	{ &int_test_hash, "-2147483647" },
+	{ &int_test_hash, "2147483648" },
+	{ &int_test_hash, "-2147483648" },
+};
+
+static void int_test_single_value()
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(int_single_value_tests); i += 1) {
+		isl_int val;
+
+		isl_int_init(val);
+		isl_int_read(val, int_single_value_tests[i].val);
+
+		(*int_single_value_tests[i].fn)(val);
+
+		isl_int_clear(val);
+	}
+}
+
+static void invoke_alternate_representations_2args(char *arg1, char *arg2,
+	void (*fn)(isl_int, isl_int))
+{
+	int j;
+	isl_int int1, int2;
+
+	isl_int_init(int1);
+	isl_int_init(int2);
+
+	for (j = 0; j < 4; ++j) {
+		isl_int_read(int1, arg1);
+		isl_int_read(int2, arg2);
+
+		if (j & 1)
+			isl_sioimath_promote(int1);
+		else
+			isl_sioimath_try_demote(int1);
+
+		if (j & 2)
+			isl_sioimath_promote(int2);
+		else
+			isl_sioimath_try_demote(int2);
+
+		(*fn)(int1, int2);
+	}
+
+	isl_int_clear(int1);
+	isl_int_clear(int2);
+}
+
+static void invoke_alternate_representations_3args(char *arg1, char *arg2,
+	char *arg3, void (*fn)(isl_int, isl_int, isl_int))
+{
+	int j;
+	isl_int int1, int2, int3;
+
+	isl_int_init(int1);
+	isl_int_init(int2);
+	isl_int_init(int3);
+
+	for (j = 0; j < 8; ++j) {
+		isl_int_read(int1, arg1);
+		isl_int_read(int2, arg2);
+		isl_int_read(int3, arg3);
+
+		if (j & 1)
+			isl_sioimath_promote(int1);
+		else
+			isl_sioimath_try_demote(int1);
+
+		if (j & 2)
+			isl_sioimath_promote(int2);
+		else
+			isl_sioimath_try_demote(int2);
+
+		if (j & 4)
+			isl_sioimath_promote(int3);
+		else
+			isl_sioimath_try_demote(int3);
+
+		(*fn)(int1, int2, int3);
+	}
+
+	isl_int_clear(int1);
+	isl_int_clear(int2);
+	isl_int_clear(int3);
+}
+#else  /* USE_SMALL_INT_OPT */
+
+static void int_test_single_value()
+{
+}
+
+static void invoke_alternate_representations_2args(char *arg1, char *arg2,
+	void (*fn)(isl_int, isl_int))
+{
+	isl_int int1, int2;
+
+	isl_int_init(int1);
+	isl_int_init(int2);
+
+	isl_int_read(int1, arg1);
+	isl_int_read(int2, arg2);
+
+	(*fn)(int1, int2);
+
+	isl_int_clear(int1);
+	isl_int_clear(int2);
+}
+
+static void invoke_alternate_representations_3args(char *arg1, char *arg2,
+	char *arg3, void (*fn)(isl_int, isl_int, isl_int))
+{
+	isl_int int1, int2, int3;
+
+	isl_int_init(int1);
+	isl_int_init(int2);
+	isl_int_init(int3);
+
+	isl_int_read(int1, arg1);
+	isl_int_read(int2, arg2);
+	isl_int_read(int3, arg3);
+
+	(*fn)(int1, int2, int3);
+
+	isl_int_clear(int1);
+	isl_int_clear(int2);
+	isl_int_clear(int3);
+}
+#endif /* USE_SMALL_INT_OPT */
+
+static void int_test_neg(isl_int expected, isl_int arg)
+{
+	isl_int result;
+	isl_int_init(result);
+
+	isl_int_neg(result, arg);
+	assert(isl_int_eq(result, expected));
+
+	isl_int_neg(result, expected);
+	assert(isl_int_eq(result, arg));
+
+	isl_int_clear(result);
+}
+
+static void int_test_abs(isl_int expected, isl_int arg)
+{
+	isl_int result;
+	isl_int_init(result);
+
+	isl_int_abs(result, arg);
+	assert(isl_int_eq(result, expected));
+
+	isl_int_clear(result);
+}
+
+struct {
+	void (*fn)(isl_int, isl_int);
+	char *expected, *arg;
+} int_unary_tests[] = {
+	{ &int_test_neg, "0", "0" },
+	{ &int_test_neg, "-1", "1" },
+	{ &int_test_neg, "-2147483647", "2147483647" },
+	{ &int_test_neg, "-2147483648", "2147483648" },
+	{ &int_test_neg, "-9223372036854775807", "9223372036854775807" },
+	{ &int_test_neg, "-9223372036854775808", "9223372036854775808" },
+
+	{ &int_test_abs, "0", "0" },
+	{ &int_test_abs, "1", "1" },
+	{ &int_test_abs, "1", "-1" },
+	{ &int_test_abs, "2147483647", "2147483647" },
+	{ &int_test_abs, "2147483648", "-2147483648" },
+	{ &int_test_abs, "9223372036854775807", "9223372036854775807" },
+	{ &int_test_abs, "9223372036854775808", "-9223372036854775808" },
+};
+
+static void int_test_divexact(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	isl_int result;
+	unsigned long rhsulong;
+
+	if (isl_int_sgn(rhs) == 0)
+		return;
+
+	isl_int_init(result);
+
+	isl_int_divexact(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	isl_int_tdiv_q(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	isl_int_fdiv_q(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	isl_int_cdiv_q(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	if (isl_int_fits_ulong(rhs)) {
+		rhsulong = isl_int_get_ui(rhs);
+
+		isl_int_divexact_ui(result, lhs, rhsulong);
+		assert(isl_int_eq(expected, result));
+
+		isl_int_fdiv_q_ui(result, lhs, rhsulong);
+		assert(isl_int_eq(expected, result));
+
+		isl_int_cdiv_q_ui(result, lhs, rhsulong);
+		assert(isl_int_eq(expected, result));
+	}
+
+	isl_int_clear(result);
+}
+
+static void int_test_mul(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	isl_int result;
+	isl_int_init(result);
+
+	isl_int_mul(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	if (isl_int_fits_ulong(rhs)) {
+		unsigned long rhsulong = isl_int_get_ui(rhs);
+
+		isl_int_mul_ui(result, lhs, rhsulong);
+		assert(isl_int_eq(expected, result));
+	}
+
+	if (isl_int_fits_slong(rhs)) {
+		unsigned long rhsslong = isl_int_get_si(rhs);
+
+		isl_int_mul_si(result, lhs, rhsslong);
+		assert(isl_int_eq(expected, result));
+	}
+
+	isl_int_clear(result);
+}
+
+/* Use a triple that satisfies 'product = factor1 * factor2' to check the
+ * operations mul, divexact, tdiv, fdiv and cdiv.
+ */
+static void int_test_product(isl_int product, isl_int factor1, isl_int factor2)
+{
+	int_test_divexact(factor1, product, factor2);
+	int_test_divexact(factor2, product, factor1);
+
+	int_test_mul(product, factor1, factor2);
+	int_test_mul(product, factor2, factor1);
+}
+
+static void int_test_add(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	isl_int result;
+	isl_int_init(result);
+
+	isl_int_add(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	isl_int_clear(result);
+}
+
+static void int_test_sub(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	isl_int result;
+	isl_int_init(result);
+
+	isl_int_sub(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	isl_int_clear(result);
+}
+
+/* Use a triple that satisfies 'sum = term1 + term2' to check the operations add
+ * and sub.
+ */
+static void int_test_sum(isl_int sum, isl_int term1, isl_int term2)
+{
+	int_test_sub(term1, sum, term2);
+	int_test_sub(term2, sum, term1);
+
+	int_test_add(sum, term1, term2);
+	int_test_add(sum, term2, term1);
+}
+
+static void int_test_fdiv(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	unsigned long rhsulong;
+	isl_int result;
+	isl_int_init(result);
+
+	isl_int_fdiv_q(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	if (isl_int_fits_ulong(rhs)) {
+		rhsulong = isl_int_get_ui(rhs);
+
+		isl_int_fdiv_q_ui(result, lhs, rhsulong);
+		assert(isl_int_eq(expected, result));
+	}
+
+	isl_int_clear(result);
+}
+
+static void int_test_cdiv(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	unsigned long rhsulong;
+	isl_int result;
+	isl_int_init(result);
+
+	isl_int_cdiv_q(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	if (isl_int_fits_ulong(rhs)) {
+		rhsulong = isl_int_get_ui(rhs);
+
+		isl_int_cdiv_q_ui(result, lhs, rhsulong);
+		assert(isl_int_eq(expected, result));
+	}
+
+	isl_int_clear(result);
+}
+
+static void int_test_tdiv(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	isl_int result;
+	isl_int_init(result);
+
+	isl_int_tdiv_q(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	isl_int_clear(result);
+}
+
+static void int_test_fdiv_r(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	isl_int result;
+	isl_int_init(result);
+
+	isl_int_fdiv_r(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	isl_int_clear(result);
+}
+
+static void int_test_gcd(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	isl_int result;
+	isl_int_init(result);
+
+	isl_int_gcd(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	isl_int_gcd(result, rhs, lhs);
+	assert(isl_int_eq(expected, result));
+
+	isl_int_clear(result);
+}
+
+static void int_test_lcm(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	isl_int result;
+	isl_int_init(result);
+
+	isl_int_lcm(result, lhs, rhs);
+	assert(isl_int_eq(expected, result));
+
+	isl_int_lcm(result, rhs, lhs);
+	assert(isl_int_eq(expected, result));
+
+	isl_int_clear(result);
+}
+
+static int sgn(int val)
+{
+	if (val > 0)
+		return 1;
+	if (val < 0)
+		return -1;
+	return 0;
+}
+
+static void int_test_cmp(int exp, isl_int lhs, isl_int rhs)
+{
+	long rhslong;
+
+	assert(exp == sgn(isl_int_cmp(lhs, rhs)));
+
+	if (isl_int_fits_slong(rhs)) {
+		rhslong = isl_int_get_si(rhs);
+		assert(exp == sgn(isl_int_cmp_si(lhs, rhslong)));
+	}
+}
+
+/* Test the comparison relations over two numbers.
+ * expected is the sign (1, 0 or -1) of 'lhs - rhs'.
+ */
+static void int_test_cmps(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	int exp;
+	isl_int diff;
+
+	exp = isl_int_get_si(expected);
+
+	isl_int_init(diff);
+	isl_int_sub(diff, lhs, rhs);
+	assert(exp == isl_int_sgn(diff));
+	isl_int_clear(diff);
+
+	int_test_cmp(exp, lhs, rhs);
+	int_test_cmp(-exp, rhs, lhs);
+}
+
+static void int_test_abs_cmp(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	int exp;
+
+	exp = isl_int_get_si(expected);
+	assert(exp == sgn(isl_int_abs_cmp(lhs, rhs)));
+	assert(-exp == sgn(isl_int_abs_cmp(rhs, lhs)));
+}
+
+/* If "expected" is equal to 1, then check that "rhs" divides "lhs".
+ * If "expected" is equal to 0, then check that "rhs" does not divide "lhs".
+ */
+static void int_test_divisible(isl_int expected, isl_int lhs, isl_int rhs)
+{
+	int exp;
+
+	exp = isl_int_get_si(expected);
+	assert(isl_int_is_divisible_by(lhs, rhs) == exp);
+}
+
+struct {
+	void (*fn)(isl_int, isl_int, isl_int);
+	char *expected, *lhs, *rhs;
+} int_binary_tests[] = {
+	{ &int_test_sum, "0", "0", "0" },
+	{ &int_test_sum, "1", "1", "0" },
+	{ &int_test_sum, "2", "1", "1" },
+	{ &int_test_sum, "-1", "0", "-1" },
+	{ &int_test_sum, "-2", "-1", "-1" },
+
+	{ &int_test_sum, "2147483647", "1073741823", "1073741824" },
+	{ &int_test_sum, "-2147483648", "-1073741824", "-1073741824" },
+
+	{ &int_test_sum, "2147483648", "2147483647", "1" },
+	{ &int_test_sum, "-2147483648", "-2147483647", "-1" },
+
+	{ &int_test_product, "0", "0", "0" },
+	{ &int_test_product, "0", "0", "1" },
+	{ &int_test_product, "1", "1", "1" },
+
+	{ &int_test_product, "6", "2", "3" },
+	{ &int_test_product, "-6", "2", "-3" },
+	{ &int_test_product, "-6", "-2", "3" },
+	{ &int_test_product, "6", "-2", "-3" },
+
+	{ &int_test_product, "2147483648", "65536", "32768" },
+	{ &int_test_product, "-2147483648", "65536", "-32768" },
+
+	{ &int_test_product,
+	  "4611686014132420609", "2147483647", "2147483647" },
+	{ &int_test_product,
+	  "-4611686014132420609", "-2147483647", "2147483647" },
+
+	{ &int_test_product,
+	  "4611686016279904256", "2147483647", "2147483648" },
+	{ &int_test_product,
+	  "-4611686016279904256", "-2147483647", "2147483648" },
+	{ &int_test_product,
+	  "-4611686016279904256", "2147483647", "-2147483648" },
+	{ &int_test_product,
+	  "4611686016279904256", "-2147483647", "-2147483648" },
+
+	{ &int_test_product, "85070591730234615847396907784232501249",
+	  "9223372036854775807", "9223372036854775807" },
+	{ &int_test_product, "-85070591730234615847396907784232501249",
+	  "-9223372036854775807", "9223372036854775807" },
+
+	{ &int_test_product, "85070591730234615856620279821087277056",
+	  "9223372036854775807", "9223372036854775808" },
+	{ &int_test_product, "-85070591730234615856620279821087277056",
+	  "-9223372036854775807", "9223372036854775808" },
+	{ &int_test_product, "-85070591730234615856620279821087277056",
+	  "9223372036854775807", "-9223372036854775808" },
+	{ &int_test_product, "85070591730234615856620279821087277056",
+	  "-9223372036854775807", "-9223372036854775808" },
+
+	{ &int_test_product, "340282366920938463426481119284349108225",
+	  "18446744073709551615", "18446744073709551615" },
+	{ &int_test_product, "-340282366920938463426481119284349108225",
+	  "-18446744073709551615", "18446744073709551615" },
+
+	{ &int_test_product, "340282366920938463444927863358058659840",
+	  "18446744073709551615", "18446744073709551616" },
+	{ &int_test_product, "-340282366920938463444927863358058659840",
+	  "-18446744073709551615", "18446744073709551616" },
+	{ &int_test_product, "-340282366920938463444927863358058659840",
+	  "18446744073709551615", "-18446744073709551616" },
+	{ &int_test_product, "340282366920938463444927863358058659840",
+	  "-18446744073709551615", "-18446744073709551616" },
+
+	{ &int_test_fdiv, "0", "1", "2" },
+	{ &int_test_fdiv_r, "1", "1", "3" },
+	{ &int_test_fdiv, "-1", "-1", "2" },
+	{ &int_test_fdiv_r, "2", "-1", "3" },
+	{ &int_test_fdiv, "-1", "1", "-2" },
+	{ &int_test_fdiv_r, "-2", "1", "-3" },
+	{ &int_test_fdiv, "0", "-1", "-2" },
+	{ &int_test_fdiv_r, "-1", "-1", "-3" },
+
+	{ &int_test_cdiv, "1", "1", "2" },
+	{ &int_test_cdiv, "0", "-1", "2" },
+	{ &int_test_cdiv, "0", "1", "-2" },
+	{ &int_test_cdiv, "1", "-1", "-2" },
+
+	{ &int_test_cdiv, "1073741824", "2147483647", "2" },
+	{ &int_test_cdiv, "1073741824", "2147483648", "2" },
+	{ &int_test_cdiv, "-1073741824", "-2147483648", "2" },
+	{ &int_test_cdiv, "-1073741823", "-2147483647", "2" },
+
+	{ &int_test_tdiv, "0", "1", "2" },
+	{ &int_test_tdiv, "0", "-1", "2" },
+	{ &int_test_tdiv, "0", "1", "-2" },
+	{ &int_test_tdiv, "0", "-1", "-2" },
+
+	{ &int_test_gcd, "0", "0", "0" },
+	{ &int_test_lcm, "0", "0", "0" },
+	{ &int_test_gcd, "7", "0", "7" },
+	{ &int_test_lcm, "0", "0", "7" },
+	{ &int_test_gcd, "1", "1", "1" },
+	{ &int_test_lcm, "1", "1", "1" },
+	{ &int_test_gcd, "1", "1", "-1" },
+	{ &int_test_lcm, "1", "1", "-1" },
+	{ &int_test_gcd, "1", "-1", "-1" },
+	{ &int_test_lcm, "1", "-1", "-1" },
+	{ &int_test_gcd, "3", "6", "9" },
+	{ &int_test_lcm, "18", "6", "9" },
+	{ &int_test_gcd, "1", "14", "2147483647" },
+	{ &int_test_lcm, "15032385529", "7", "2147483647" },
+	{ &int_test_gcd, "2", "6", "-2147483648" },
+	{ &int_test_lcm, "6442450944", "6", "-2147483648" },
+	{ &int_test_gcd, "1", "6", "9223372036854775807" },
+	{ &int_test_lcm, "55340232221128654842", "6", "9223372036854775807" },
+	{ &int_test_gcd, "2", "6", "-9223372036854775808" },
+	{ &int_test_lcm, "27670116110564327424", "6", "-9223372036854775808" },
+	{ &int_test_gcd, "1", "18446744073709551616", "18446744073709551615" },
+	{ &int_test_lcm, "340282366920938463444927863358058659840",
+	  "18446744073709551616", "18446744073709551615" },
+
+	{ &int_test_cmps, "0", "0", "0" },
+	{ &int_test_abs_cmp, "0", "0", "0" },
+	{ &int_test_cmps, "1", "1", "0" },
+	{ &int_test_abs_cmp, "1", "1", "0" },
+	{ &int_test_cmps, "-1", "-1", "0" },
+	{ &int_test_abs_cmp, "1", "-1", "0" },
+	{ &int_test_cmps, "-1", "-1", "1" },
+	{ &int_test_abs_cmp, "0", "-1", "1" },
+
+	{ &int_test_cmps, "-1", "5", "2147483647" },
+	{ &int_test_abs_cmp, "-1", "5", "2147483647" },
+	{ &int_test_cmps, "1", "5", "-2147483648" },
+	{ &int_test_abs_cmp, "-1", "5", "-2147483648" },
+	{ &int_test_cmps, "-1", "5", "9223372036854775807" },
+	{ &int_test_abs_cmp, "-1", "5", "9223372036854775807" },
+	{ &int_test_cmps, "1", "5", "-9223372036854775809" },
+	{ &int_test_abs_cmp, "-1", "5", "-9223372036854775809" },
+
+	{ &int_test_divisible, "1", "0", "0" },
+	{ &int_test_divisible, "0", "1", "0" },
+	{ &int_test_divisible, "0", "2", "0" },
+	{ &int_test_divisible, "0", "2147483647", "0" },
+	{ &int_test_divisible, "0", "9223372036854775807", "0" },
+	{ &int_test_divisible, "1", "0", "1" },
+	{ &int_test_divisible, "1", "1", "1" },
+	{ &int_test_divisible, "1", "2", "1" },
+	{ &int_test_divisible, "1", "2147483647", "1" },
+	{ &int_test_divisible, "1", "9223372036854775807", "1" },
+	{ &int_test_divisible, "1", "0", "2" },
+	{ &int_test_divisible, "0", "1", "2" },
+	{ &int_test_divisible, "1", "2", "2" },
+	{ &int_test_divisible, "0", "2147483647", "2" },
+	{ &int_test_divisible, "0", "9223372036854775807", "2" },
+};
+
+/* Tests the isl_int_* function to give the expected results. Tests are
+ * grouped by the number of arguments they take.
+ *
+ * If small integer optimization is enabled, we also test whether the results
+ * are the same in small and big representation.
+ */
+int main()
+{
+	int i;
+
+	int_test_single_value();
+
+	for (i = 0; i < ARRAY_SIZE(int_unary_tests); i += 1) {
+		invoke_alternate_representations_2args(
+		    int_unary_tests[i].expected, int_unary_tests[i].arg,
+		    int_unary_tests[i].fn);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(int_binary_tests); i += 1) {
+		invoke_alternate_representations_3args(
+		    int_binary_tests[i].expected, int_binary_tests[i].lhs,
+		    int_binary_tests[i].rhs, int_binary_tests[i].fn);
+	}
+
+	return 0;
+}
diff --git a/final/lib/External/isl/isl_transitive_closure.c b/final/lib/External/isl/isl_transitive_closure.c
new file mode 100644
index 0000000..6e1b4bb
--- /dev/null
+++ b/final/lib/External/isl/isl_transitive_closure.c
@@ -0,0 +1,2948 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France 
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_map_private.h>
+#include <isl/map.h>
+#include <isl_seq.h>
+#include <isl_space_private.h>
+#include <isl_lp_private.h>
+#include <isl/union_map.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl_options_private.h>
+#include <isl_tarjan.h>
+
+int isl_map_is_transitively_closed(__isl_keep isl_map *map)
+{
+	isl_map *map2;
+	int closed;
+
+	map2 = isl_map_apply_range(isl_map_copy(map), isl_map_copy(map));
+	closed = isl_map_is_subset(map2, map);
+	isl_map_free(map2);
+
+	return closed;
+}
+
+int isl_union_map_is_transitively_closed(__isl_keep isl_union_map *umap)
+{
+	isl_union_map *umap2;
+	int closed;
+
+	umap2 = isl_union_map_apply_range(isl_union_map_copy(umap),
+					  isl_union_map_copy(umap));
+	closed = isl_union_map_is_subset(umap2, umap);
+	isl_union_map_free(umap2);
+
+	return closed;
+}
+ 
+/* Given a map that represents a path with the length of the path
+ * encoded as the difference between the last output coordindate
+ * and the last input coordinate, set this length to either
+ * exactly "length" (if "exactly" is set) or at least "length"
+ * (if "exactly" is not set).
+ */
+static __isl_give isl_map *set_path_length(__isl_take isl_map *map,
+	int exactly, int length)
+{
+	isl_space *dim;
+	struct isl_basic_map *bmap;
+	unsigned d;
+	unsigned nparam;
+	int k;
+	isl_int *c;
+
+	if (!map)
+		return NULL;
+
+	dim = isl_map_get_space(map);
+	d = isl_space_dim(dim, isl_dim_in);
+	nparam = isl_space_dim(dim, isl_dim_param);
+	bmap = isl_basic_map_alloc_space(dim, 0, 1, 1);
+	if (exactly) {
+		k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			goto error;
+		c = bmap->eq[k];
+	} else {
+		k = isl_basic_map_alloc_inequality(bmap);
+		if (k < 0)
+			goto error;
+		c = bmap->ineq[k];
+	}
+	isl_seq_clr(c, 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(c[0], -length);
+	isl_int_set_si(c[1 + nparam + d - 1], -1);
+	isl_int_set_si(c[1 + nparam + d + d - 1], 1);
+
+	bmap = isl_basic_map_finalize(bmap);
+	map = isl_map_intersect(map, isl_map_from_basic_map(bmap));
+
+	return map;
+error:
+	isl_basic_map_free(bmap);
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Check whether the overapproximation of the power of "map" is exactly
+ * the power of "map".  Let R be "map" and A_k the overapproximation.
+ * The approximation is exact if
+ *
+ *	A_1 = R
+ *	A_k = A_{k-1} \circ R			k >= 2
+ *
+ * Since A_k is known to be an overapproximation, we only need to check
+ *
+ *	A_1 \subset R
+ *	A_k \subset A_{k-1} \circ R		k >= 2
+ *
+ * In practice, "app" has an extra input and output coordinate
+ * to encode the length of the path.  So, we first need to add
+ * this coordinate to "map" and set the length of the path to
+ * one.
+ */
+static int check_power_exactness(__isl_take isl_map *map,
+	__isl_take isl_map *app)
+{
+	int exact;
+	isl_map *app_1;
+	isl_map *app_2;
+
+	map = isl_map_add_dims(map, isl_dim_in, 1);
+	map = isl_map_add_dims(map, isl_dim_out, 1);
+	map = set_path_length(map, 1, 1);
+
+	app_1 = set_path_length(isl_map_copy(app), 1, 1);
+
+	exact = isl_map_is_subset(app_1, map);
+	isl_map_free(app_1);
+
+	if (!exact || exact < 0) {
+		isl_map_free(app);
+		isl_map_free(map);
+		return exact;
+	}
+
+	app_1 = set_path_length(isl_map_copy(app), 0, 1);
+	app_2 = set_path_length(app, 0, 2);
+	app_1 = isl_map_apply_range(map, app_1);
+
+	exact = isl_map_is_subset(app_2, app_1);
+
+	isl_map_free(app_1);
+	isl_map_free(app_2);
+
+	return exact;
+}
+
+/* Check whether the overapproximation of the power of "map" is exactly
+ * the power of "map", possibly after projecting out the power (if "project"
+ * is set).
+ *
+ * If "project" is set and if "steps" can only result in acyclic paths,
+ * then we check
+ *
+ *	A = R \cup (A \circ R)
+ *
+ * where A is the overapproximation with the power projected out, i.e.,
+ * an overapproximation of the transitive closure.
+ * More specifically, since A is known to be an overapproximation, we check
+ *
+ *	A \subset R \cup (A \circ R)
+ *
+ * Otherwise, we check if the power is exact.
+ *
+ * Note that "app" has an extra input and output coordinate to encode
+ * the length of the part.  If we are only interested in the transitive
+ * closure, then we can simply project out these coordinates first.
+ */
+static int check_exactness(__isl_take isl_map *map, __isl_take isl_map *app,
+	int project)
+{
+	isl_map *test;
+	int exact;
+	unsigned d;
+
+	if (!project)
+		return check_power_exactness(map, app);
+
+	d = isl_map_dim(map, isl_dim_in);
+	app = set_path_length(app, 0, 1);
+	app = isl_map_project_out(app, isl_dim_in, d, 1);
+	app = isl_map_project_out(app, isl_dim_out, d, 1);
+
+	app = isl_map_reset_space(app, isl_map_get_space(map));
+
+	test = isl_map_apply_range(isl_map_copy(map), isl_map_copy(app));
+	test = isl_map_union(test, isl_map_copy(map));
+
+	exact = isl_map_is_subset(app, test);
+
+	isl_map_free(app);
+	isl_map_free(test);
+
+	isl_map_free(map);
+
+	return exact;
+}
+
+/*
+ * The transitive closure implementation is based on the paper
+ * "Computing the Transitive Closure of a Union of Affine Integer
+ * Tuple Relations" by Anna Beletska, Denis Barthou, Wlodzimierz Bielecki and
+ * Albert Cohen.
+ */
+
+/* Given a set of n offsets v_i (the rows of "steps"), construct a relation
+ * of the given dimension specification (Z^{n+1} -> Z^{n+1})
+ * that maps an element x to any element that can be reached
+ * by taking a non-negative number of steps along any of
+ * the extended offsets v'_i = [v_i 1].
+ * That is, construct
+ *
+ * { [x] -> [y] : exists k_i >= 0, y = x + \sum_i k_i v'_i }
+ *
+ * For any element in this relation, the number of steps taken
+ * is equal to the difference in the final coordinates.
+ */
+static __isl_give isl_map *path_along_steps(__isl_take isl_space *dim,
+	__isl_keep isl_mat *steps)
+{
+	int i, j, k;
+	struct isl_basic_map *path = NULL;
+	unsigned d;
+	unsigned n;
+	unsigned nparam;
+
+	if (!dim || !steps)
+		goto error;
+
+	d = isl_space_dim(dim, isl_dim_in);
+	n = steps->n_row;
+	nparam = isl_space_dim(dim, isl_dim_param);
+
+	path = isl_basic_map_alloc_space(isl_space_copy(dim), n, d, n);
+
+	for (i = 0; i < n; ++i) {
+		k = isl_basic_map_alloc_div(path);
+		if (k < 0)
+			goto error;
+		isl_assert(steps->ctx, i == k, goto error);
+		isl_int_set_si(path->div[k][0], 0);
+	}
+
+	for (i = 0; i < d; ++i) {
+		k = isl_basic_map_alloc_equality(path);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
+		isl_int_set_si(path->eq[k][1 + nparam + i], 1);
+		isl_int_set_si(path->eq[k][1 + nparam + d + i], -1);
+		if (i == d - 1)
+			for (j = 0; j < n; ++j)
+				isl_int_set_si(path->eq[k][1 + nparam + 2 * d + j], 1);
+		else
+			for (j = 0; j < n; ++j)
+				isl_int_set(path->eq[k][1 + nparam + 2 * d + j],
+					    steps->row[j][i]);
+	}
+
+	for (i = 0; i < n; ++i) {
+		k = isl_basic_map_alloc_inequality(path);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
+		isl_int_set_si(path->ineq[k][1 + nparam + 2 * d + i], 1);
+	}
+
+	isl_space_free(dim);
+
+	path = isl_basic_map_simplify(path);
+	path = isl_basic_map_finalize(path);
+	return isl_map_from_basic_map(path);
+error:
+	isl_space_free(dim);
+	isl_basic_map_free(path);
+	return NULL;
+}
+
+#define IMPURE		0
+#define PURE_PARAM	1
+#define PURE_VAR	2
+#define MIXED		3
+
+/* Check whether the parametric constant term of constraint c is never
+ * positive in "bset".
+ */
+static isl_bool parametric_constant_never_positive(
+	__isl_keep isl_basic_set *bset, isl_int *c, int *div_purity)
+{
+	unsigned d;
+	unsigned n_div;
+	unsigned nparam;
+	int i;
+	int k;
+	isl_bool empty;
+
+	n_div = isl_basic_set_dim(bset, isl_dim_div);
+	d = isl_basic_set_dim(bset, isl_dim_set);
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+
+	bset = isl_basic_set_copy(bset);
+	bset = isl_basic_set_cow(bset);
+	bset = isl_basic_set_extend_constraints(bset, 0, 1);
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(bset->ineq[k], 1 + isl_basic_set_total_dim(bset));
+	isl_seq_cpy(bset->ineq[k], c, 1 + nparam);
+	for (i = 0; i < n_div; ++i) {
+		if (div_purity[i] != PURE_PARAM)
+			continue;
+		isl_int_set(bset->ineq[k][1 + nparam + d + i],
+			    c[1 + nparam + d + i]);
+	}
+	isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1);
+	empty = isl_basic_set_is_empty(bset);
+	isl_basic_set_free(bset);
+
+	return empty;
+error:
+	isl_basic_set_free(bset);
+	return isl_bool_error;
+}
+
+/* Return PURE_PARAM if only the coefficients of the parameters are non-zero.
+ * Return PURE_VAR if only the coefficients of the set variables are non-zero.
+ * Return MIXED if only the coefficients of the parameters and the set
+ * 	variables are non-zero and if moreover the parametric constant
+ * 	can never attain positive values.
+ * Return IMPURE otherwise.
+ */
+static int purity(__isl_keep isl_basic_set *bset, isl_int *c, int *div_purity,
+	int eq)
+{
+	unsigned d;
+	unsigned n_div;
+	unsigned nparam;
+	isl_bool empty;
+	int i;
+	int p = 0, v = 0;
+
+	n_div = isl_basic_set_dim(bset, isl_dim_div);
+	d = isl_basic_set_dim(bset, isl_dim_set);
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+
+	for (i = 0; i < n_div; ++i) {
+		if (isl_int_is_zero(c[1 + nparam + d + i]))
+			continue;
+		switch (div_purity[i]) {
+		case PURE_PARAM: p = 1; break;
+		case PURE_VAR: v = 1; break;
+		default: return IMPURE;
+		}
+	}
+	if (!p && isl_seq_first_non_zero(c + 1, nparam) == -1)
+		return PURE_VAR;
+	if (!v && isl_seq_first_non_zero(c + 1 + nparam, d) == -1)
+		return PURE_PARAM;
+
+	empty = parametric_constant_never_positive(bset, c, div_purity);
+	if (eq && empty >= 0 && !empty) {
+		isl_seq_neg(c, c, 1 + nparam + d + n_div);
+		empty = parametric_constant_never_positive(bset, c, div_purity);
+	}
+
+	return empty < 0 ? -1 : empty ? MIXED : IMPURE;
+}
+
+/* Return an array of integers indicating the type of each div in bset.
+ * If the div is (recursively) defined in terms of only the parameters,
+ * then the type is PURE_PARAM.
+ * If the div is (recursively) defined in terms of only the set variables,
+ * then the type is PURE_VAR.
+ * Otherwise, the type is IMPURE.
+ */
+static __isl_give int *get_div_purity(__isl_keep isl_basic_set *bset)
+{
+	int i, j;
+	int *div_purity;
+	unsigned d;
+	unsigned n_div;
+	unsigned nparam;
+
+	if (!bset)
+		return NULL;
+
+	n_div = isl_basic_set_dim(bset, isl_dim_div);
+	d = isl_basic_set_dim(bset, isl_dim_set);
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+
+	div_purity = isl_alloc_array(bset->ctx, int, n_div);
+	if (n_div && !div_purity)
+		return NULL;
+
+	for (i = 0; i < bset->n_div; ++i) {
+		int p = 0, v = 0;
+		if (isl_int_is_zero(bset->div[i][0])) {
+			div_purity[i] = IMPURE;
+			continue;
+		}
+		if (isl_seq_first_non_zero(bset->div[i] + 2, nparam) != -1)
+			p = 1;
+		if (isl_seq_first_non_zero(bset->div[i] + 2 + nparam, d) != -1)
+			v = 1;
+		for (j = 0; j < i; ++j) {
+			if (isl_int_is_zero(bset->div[i][2 + nparam + d + j]))
+				continue;
+			switch (div_purity[j]) {
+			case PURE_PARAM: p = 1; break;
+			case PURE_VAR: v = 1; break;
+			default: p = v = 1; break;
+			}
+		}
+		div_purity[i] = v ? p ? IMPURE : PURE_VAR : PURE_PARAM;
+	}
+
+	return div_purity;
+}
+
+/* Given a path with the as yet unconstrained length at position "pos",
+ * check if setting the length to zero results in only the identity
+ * mapping.
+ */
+static int empty_path_is_identity(__isl_keep isl_basic_map *path, unsigned pos)
+{
+	isl_basic_map *test = NULL;
+	isl_basic_map *id = NULL;
+	int k;
+	int is_id;
+
+	test = isl_basic_map_copy(path);
+	test = isl_basic_map_extend_constraints(test, 1, 0);
+	k = isl_basic_map_alloc_equality(test);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(test->eq[k], 1 + isl_basic_map_total_dim(test));
+	isl_int_set_si(test->eq[k][pos], 1);
+	test = isl_basic_map_gauss(test, NULL);
+	id = isl_basic_map_identity(isl_basic_map_get_space(path));
+	is_id = isl_basic_map_is_equal(test, id);
+	isl_basic_map_free(test);
+	isl_basic_map_free(id);
+	return is_id;
+error:
+	isl_basic_map_free(test);
+	return -1;
+}
+
+/* If any of the constraints is found to be impure then this function
+ * sets *impurity to 1.
+ *
+ * If impurity is NULL then we are dealing with a non-parametric set
+ * and so the constraints are obviously PURE_VAR.
+ */
+static __isl_give isl_basic_map *add_delta_constraints(
+	__isl_take isl_basic_map *path,
+	__isl_keep isl_basic_set *delta, unsigned off, unsigned nparam,
+	unsigned d, int *div_purity, int eq, int *impurity)
+{
+	int i, k;
+	int n = eq ? delta->n_eq : delta->n_ineq;
+	isl_int **delta_c = eq ? delta->eq : delta->ineq;
+	unsigned n_div;
+
+	n_div = isl_basic_set_dim(delta, isl_dim_div);
+
+	for (i = 0; i < n; ++i) {
+		isl_int *path_c;
+		int p = PURE_VAR;
+		if (impurity)
+			p = purity(delta, delta_c[i], div_purity, eq);
+		if (p < 0)
+			goto error;
+		if (p != PURE_VAR && p != PURE_PARAM && !*impurity)
+			*impurity = 1;
+		if (p == IMPURE)
+			continue;
+		if (eq && p != MIXED) {
+			k = isl_basic_map_alloc_equality(path);
+			if (k < 0)
+				goto error;
+			path_c = path->eq[k];
+		} else {
+			k = isl_basic_map_alloc_inequality(path);
+			if (k < 0)
+				goto error;
+			path_c = path->ineq[k];
+		}
+		isl_seq_clr(path_c, 1 + isl_basic_map_total_dim(path));
+		if (p == PURE_VAR) {
+			isl_seq_cpy(path_c + off,
+				    delta_c[i] + 1 + nparam, d);
+			isl_int_set(path_c[off + d], delta_c[i][0]);
+		} else if (p == PURE_PARAM) {
+			isl_seq_cpy(path_c, delta_c[i], 1 + nparam);
+		} else {
+			isl_seq_cpy(path_c + off,
+				    delta_c[i] + 1 + nparam, d);
+			isl_seq_cpy(path_c, delta_c[i], 1 + nparam);
+		}
+		isl_seq_cpy(path_c + off - n_div,
+			    delta_c[i] + 1 + nparam + d, n_div);
+	}
+
+	return path;
+error:
+	isl_basic_map_free(path);
+	return NULL;
+}
+
+/* Given a set of offsets "delta", construct a relation of the
+ * given dimension specification (Z^{n+1} -> Z^{n+1}) that
+ * is an overapproximation of the relations that
+ * maps an element x to any element that can be reached
+ * by taking a non-negative number of steps along any of
+ * the elements in "delta".
+ * That is, construct an approximation of
+ *
+ *	{ [x] -> [y] : exists f \in \delta, k \in Z :
+ *					y = x + k [f, 1] and k >= 0 }
+ *
+ * For any element in this relation, the number of steps taken
+ * is equal to the difference in the final coordinates.
+ *
+ * In particular, let delta be defined as
+ *
+ *	\delta = [p] -> { [x] : A x + a >= 0 and B p + b >= 0 and
+ *				C x + C'p + c >= 0 and
+ *				D x + D'p + d >= 0 }
+ *
+ * where the constraints C x + C'p + c >= 0 are such that the parametric
+ * constant term of each constraint j, "C_j x + C'_j p + c_j",
+ * can never attain positive values, then the relation is constructed as
+ *
+ *	{ [x] -> [y] : exists [f, k] \in Z^{n+1} : y = x + f and
+ *			A f + k a >= 0 and B p + b >= 0 and
+ *			C f + C'p + c >= 0 and k >= 1 }
+ *	union { [x] -> [x] }
+ *
+ * If the zero-length paths happen to correspond exactly to the identity
+ * mapping, then we return
+ *
+ *	{ [x] -> [y] : exists [f, k] \in Z^{n+1} : y = x + f and
+ *			A f + k a >= 0 and B p + b >= 0 and
+ *			C f + C'p + c >= 0 and k >= 0 }
+ *
+ * instead.
+ *
+ * Existentially quantified variables in \delta are handled by
+ * classifying them as independent of the parameters, purely
+ * parameter dependent and others.  Constraints containing
+ * any of the other existentially quantified variables are removed.
+ * This is safe, but leads to an additional overapproximation.
+ *
+ * If there are any impure constraints, then we also eliminate
+ * the parameters from \delta, resulting in a set
+ *
+ *	\delta' = { [x] : E x + e >= 0 }
+ *
+ * and add the constraints
+ *
+ *			E f + k e >= 0
+ *
+ * to the constructed relation.
+ */
+static __isl_give isl_map *path_along_delta(__isl_take isl_space *dim,
+	__isl_take isl_basic_set *delta)
+{
+	isl_basic_map *path = NULL;
+	unsigned d;
+	unsigned n_div;
+	unsigned nparam;
+	unsigned off;
+	int i, k;
+	int is_id;
+	int *div_purity = NULL;
+	int impurity = 0;
+
+	if (!delta)
+		goto error;
+	n_div = isl_basic_set_dim(delta, isl_dim_div);
+	d = isl_basic_set_dim(delta, isl_dim_set);
+	nparam = isl_basic_set_dim(delta, isl_dim_param);
+	path = isl_basic_map_alloc_space(isl_space_copy(dim), n_div + d + 1,
+			d + 1 + delta->n_eq, delta->n_eq + delta->n_ineq + 1);
+	off = 1 + nparam + 2 * (d + 1) + n_div;
+
+	for (i = 0; i < n_div + d + 1; ++i) {
+		k = isl_basic_map_alloc_div(path);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(path->div[k][0], 0);
+	}
+
+	for (i = 0; i < d + 1; ++i) {
+		k = isl_basic_map_alloc_equality(path);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(path->eq[k], 1 + isl_basic_map_total_dim(path));
+		isl_int_set_si(path->eq[k][1 + nparam + i], 1);
+		isl_int_set_si(path->eq[k][1 + nparam + d + 1 + i], -1);
+		isl_int_set_si(path->eq[k][off + i], 1);
+	}
+
+	div_purity = get_div_purity(delta);
+	if (n_div && !div_purity)
+		goto error;
+
+	path = add_delta_constraints(path, delta, off, nparam, d,
+				     div_purity, 1, &impurity);
+	path = add_delta_constraints(path, delta, off, nparam, d,
+				     div_purity, 0, &impurity);
+	if (impurity) {
+		isl_space *dim = isl_basic_set_get_space(delta);
+		delta = isl_basic_set_project_out(delta,
+						  isl_dim_param, 0, nparam);
+		delta = isl_basic_set_add_dims(delta, isl_dim_param, nparam);
+		delta = isl_basic_set_reset_space(delta, dim);
+		if (!delta)
+			goto error;
+		path = isl_basic_map_extend_constraints(path, delta->n_eq,
+							delta->n_ineq + 1);
+		path = add_delta_constraints(path, delta, off, nparam, d,
+					     NULL, 1, NULL);
+		path = add_delta_constraints(path, delta, off, nparam, d,
+					     NULL, 0, NULL);
+		path = isl_basic_map_gauss(path, NULL);
+	}
+
+	is_id = empty_path_is_identity(path, off + d);
+	if (is_id < 0)
+		goto error;
+
+	k = isl_basic_map_alloc_inequality(path);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(path->ineq[k], 1 + isl_basic_map_total_dim(path));
+	if (!is_id)
+		isl_int_set_si(path->ineq[k][0], -1);
+	isl_int_set_si(path->ineq[k][off + d], 1);
+			
+	free(div_purity);
+	isl_basic_set_free(delta);
+	path = isl_basic_map_finalize(path);
+	if (is_id) {
+		isl_space_free(dim);
+		return isl_map_from_basic_map(path);
+	}
+	return isl_basic_map_union(path, isl_basic_map_identity(dim));
+error:
+	free(div_purity);
+	isl_space_free(dim);
+	isl_basic_set_free(delta);
+	isl_basic_map_free(path);
+	return NULL;
+}
+
+/* Given a dimension specification Z^{n+1} -> Z^{n+1} and a parameter "param",
+ * construct a map that equates the parameter to the difference
+ * in the final coordinates and imposes that this difference is positive.
+ * That is, construct
+ *
+ *	{ [x,x_s] -> [y,y_s] : k = y_s - x_s > 0 }
+ */
+static __isl_give isl_map *equate_parameter_to_length(__isl_take isl_space *dim,
+	unsigned param)
+{
+	struct isl_basic_map *bmap;
+	unsigned d;
+	unsigned nparam;
+	int k;
+
+	d = isl_space_dim(dim, isl_dim_in);
+	nparam = isl_space_dim(dim, isl_dim_param);
+	bmap = isl_basic_map_alloc_space(dim, 0, 1, 1);
+	k = isl_basic_map_alloc_equality(bmap);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(bmap->eq[k], 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->eq[k][1 + param], -1);
+	isl_int_set_si(bmap->eq[k][1 + nparam + d - 1], -1);
+	isl_int_set_si(bmap->eq[k][1 + nparam + d + d - 1], 1);
+
+	k = isl_basic_map_alloc_inequality(bmap);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(bmap->ineq[k], 1 + isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->ineq[k][1 + param], 1);
+	isl_int_set_si(bmap->ineq[k][0], -1);
+
+	bmap = isl_basic_map_finalize(bmap);
+	return isl_map_from_basic_map(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Check whether "path" is acyclic, where the last coordinates of domain
+ * and range of path encode the number of steps taken.
+ * That is, check whether
+ *
+ *	{ d | d = y - x and (x,y) in path }
+ *
+ * does not contain any element with positive last coordinate (positive length)
+ * and zero remaining coordinates (cycle).
+ */
+static int is_acyclic(__isl_take isl_map *path)
+{
+	int i;
+	int acyclic;
+	unsigned dim;
+	struct isl_set *delta;
+
+	delta = isl_map_deltas(path);
+	dim = isl_set_dim(delta, isl_dim_set);
+	for (i = 0; i < dim; ++i) {
+		if (i == dim -1)
+			delta = isl_set_lower_bound_si(delta, isl_dim_set, i, 1);
+		else
+			delta = isl_set_fix_si(delta, isl_dim_set, i, 0);
+	}
+
+	acyclic = isl_set_is_empty(delta);
+	isl_set_free(delta);
+
+	return acyclic;
+}
+
+/* Given a union of basic maps R = \cup_i R_i \subseteq D \times D
+ * and a dimension specification (Z^{n+1} -> Z^{n+1}),
+ * construct a map that is an overapproximation of the map
+ * that takes an element from the space D \times Z to another
+ * element from the same space, such that the first n coordinates of the
+ * difference between them is a sum of differences between images
+ * and pre-images in one of the R_i and such that the last coordinate
+ * is equal to the number of steps taken.
+ * That is, let
+ *
+ *	\Delta_i = { y - x | (x, y) in R_i }
+ *
+ * then the constructed map is an overapproximation of
+ *
+ *	{ (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
+ *				d = (\sum_i k_i \delta_i, \sum_i k_i) }
+ *
+ * The elements of the singleton \Delta_i's are collected as the
+ * rows of the steps matrix.  For all these \Delta_i's together,
+ * a single path is constructed.
+ * For each of the other \Delta_i's, we compute an overapproximation
+ * of the paths along elements of \Delta_i.
+ * Since each of these paths performs an addition, composition is
+ * symmetric and we can simply compose all resulting paths in any order.
+ */
+static __isl_give isl_map *construct_extended_path(__isl_take isl_space *dim,
+	__isl_keep isl_map *map, int *project)
+{
+	struct isl_mat *steps = NULL;
+	struct isl_map *path = NULL;
+	unsigned d;
+	int i, j, n;
+
+	if (!map)
+		goto error;
+
+	d = isl_map_dim(map, isl_dim_in);
+
+	path = isl_map_identity(isl_space_copy(dim));
+
+	steps = isl_mat_alloc(map->ctx, map->n, d);
+	if (!steps)
+		goto error;
+
+	n = 0;
+	for (i = 0; i < map->n; ++i) {
+		struct isl_basic_set *delta;
+
+		delta = isl_basic_map_deltas(isl_basic_map_copy(map->p[i]));
+
+		for (j = 0; j < d; ++j) {
+			isl_bool fixed;
+
+			fixed = isl_basic_set_plain_dim_is_fixed(delta, j,
+							    &steps->row[n][j]);
+			if (fixed < 0) {
+				isl_basic_set_free(delta);
+				goto error;
+			}
+			if (!fixed)
+				break;
+		}
+
+
+		if (j < d) {
+			path = isl_map_apply_range(path,
+				path_along_delta(isl_space_copy(dim), delta));
+			path = isl_map_coalesce(path);
+		} else {
+			isl_basic_set_free(delta);
+			++n;
+		}
+	}
+
+	if (n > 0) {
+		steps->n_row = n;
+		path = isl_map_apply_range(path,
+				path_along_steps(isl_space_copy(dim), steps));
+	}
+
+	if (project && *project) {
+		*project = is_acyclic(isl_map_copy(path));
+		if (*project < 0)
+			goto error;
+	}
+
+	isl_space_free(dim);
+	isl_mat_free(steps);
+	return path;
+error:
+	isl_space_free(dim);
+	isl_mat_free(steps);
+	isl_map_free(path);
+	return NULL;
+}
+
+static isl_bool isl_set_overlaps(__isl_keep isl_set *set1,
+	__isl_keep isl_set *set2)
+{
+	isl_set *i;
+	isl_bool no_overlap;
+
+	if (!set1 || !set2)
+		return isl_bool_error;
+
+	if (!isl_space_tuple_is_equal(set1->dim, isl_dim_set,
+					set2->dim, isl_dim_set))
+		return isl_bool_false;
+
+	i = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2));
+	no_overlap = isl_set_is_empty(i);
+	isl_set_free(i);
+
+	return isl_bool_not(no_overlap);
+}
+
+/* Given a union of basic maps R = \cup_i R_i \subseteq D \times D
+ * and a dimension specification (Z^{n+1} -> Z^{n+1}),
+ * construct a map that is an overapproximation of the map
+ * that takes an element from the dom R \times Z to an
+ * element from ran R \times Z, such that the first n coordinates of the
+ * difference between them is a sum of differences between images
+ * and pre-images in one of the R_i and such that the last coordinate
+ * is equal to the number of steps taken.
+ * That is, let
+ *
+ *	\Delta_i = { y - x | (x, y) in R_i }
+ *
+ * then the constructed map is an overapproximation of
+ *
+ *	{ (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
+ *				d = (\sum_i k_i \delta_i, \sum_i k_i) and
+ *				x in dom R and x + d in ran R and
+ *				\sum_i k_i >= 1 }
+ */
+static __isl_give isl_map *construct_component(__isl_take isl_space *dim,
+	__isl_keep isl_map *map, int *exact, int project)
+{
+	struct isl_set *domain = NULL;
+	struct isl_set *range = NULL;
+	struct isl_map *app = NULL;
+	struct isl_map *path = NULL;
+	isl_bool overlaps;
+
+	domain = isl_map_domain(isl_map_copy(map));
+	domain = isl_set_coalesce(domain);
+	range = isl_map_range(isl_map_copy(map));
+	range = isl_set_coalesce(range);
+	overlaps = isl_set_overlaps(domain, range);
+	if (overlaps < 0 || !overlaps) {
+		isl_set_free(domain);
+		isl_set_free(range);
+		isl_space_free(dim);
+
+		if (overlaps < 0)
+			map = NULL;
+		map = isl_map_copy(map);
+		map = isl_map_add_dims(map, isl_dim_in, 1);
+		map = isl_map_add_dims(map, isl_dim_out, 1);
+		map = set_path_length(map, 1, 1);
+		return map;
+	}
+	app = isl_map_from_domain_and_range(domain, range);
+	app = isl_map_add_dims(app, isl_dim_in, 1);
+	app = isl_map_add_dims(app, isl_dim_out, 1);
+
+	path = construct_extended_path(isl_space_copy(dim), map,
+					exact && *exact ? &project : NULL);
+	app = isl_map_intersect(app, path);
+
+	if (exact && *exact &&
+	    (*exact = check_exactness(isl_map_copy(map), isl_map_copy(app),
+				      project)) < 0)
+		goto error;
+
+	isl_space_free(dim);
+	app = set_path_length(app, 0, 1);
+	return app;
+error:
+	isl_space_free(dim);
+	isl_map_free(app);
+	return NULL;
+}
+
+/* Call construct_component and, if "project" is set, project out
+ * the final coordinates.
+ */
+static __isl_give isl_map *construct_projected_component(
+	__isl_take isl_space *dim,
+	__isl_keep isl_map *map, int *exact, int project)
+{
+	isl_map *app;
+	unsigned d;
+
+	if (!dim)
+		return NULL;
+	d = isl_space_dim(dim, isl_dim_in);
+
+	app = construct_component(dim, map, exact, project);
+	if (project) {
+		app = isl_map_project_out(app, isl_dim_in, d - 1, 1);
+		app = isl_map_project_out(app, isl_dim_out, d - 1, 1);
+	}
+	return app;
+}
+
+/* Compute an extended version, i.e., with path lengths, of
+ * an overapproximation of the transitive closure of "bmap"
+ * with path lengths greater than or equal to zero and with
+ * domain and range equal to "dom".
+ */
+static __isl_give isl_map *q_closure(__isl_take isl_space *dim,
+	__isl_take isl_set *dom, __isl_keep isl_basic_map *bmap, int *exact)
+{
+	int project = 1;
+	isl_map *path;
+	isl_map *map;
+	isl_map *app;
+
+	dom = isl_set_add_dims(dom, isl_dim_set, 1);
+	app = isl_map_from_domain_and_range(dom, isl_set_copy(dom));
+	map = isl_map_from_basic_map(isl_basic_map_copy(bmap));
+	path = construct_extended_path(dim, map, &project);
+	app = isl_map_intersect(app, path);
+
+	if ((*exact = check_exactness(map, isl_map_copy(app), project)) < 0)
+		goto error;
+
+	return app;
+error:
+	isl_map_free(app);
+	return NULL;
+}
+
+/* Check whether qc has any elements of length at least one
+ * with domain and/or range outside of dom and ran.
+ */
+static int has_spurious_elements(__isl_keep isl_map *qc,
+	__isl_keep isl_set *dom, __isl_keep isl_set *ran)
+{
+	isl_set *s;
+	int subset;
+	unsigned d;
+
+	if (!qc || !dom || !ran)
+		return -1;
+
+	d = isl_map_dim(qc, isl_dim_in);
+
+	qc = isl_map_copy(qc);
+	qc = set_path_length(qc, 0, 1);
+	qc = isl_map_project_out(qc, isl_dim_in, d - 1, 1);
+	qc = isl_map_project_out(qc, isl_dim_out, d - 1, 1);
+
+	s = isl_map_domain(isl_map_copy(qc));
+	subset = isl_set_is_subset(s, dom);
+	isl_set_free(s);
+	if (subset < 0)
+		goto error;
+	if (!subset) {
+		isl_map_free(qc);
+		return 1;
+	}
+
+	s = isl_map_range(qc);
+	subset = isl_set_is_subset(s, ran);
+	isl_set_free(s);
+
+	return subset < 0 ? -1 : !subset;
+error:
+	isl_map_free(qc);
+	return -1;
+}
+
+#define LEFT	2
+#define RIGHT	1
+
+/* For each basic map in "map", except i, check whether it combines
+ * with the transitive closure that is reflexive on C combines
+ * to the left and to the right.
+ *
+ * In particular, if
+ *
+ *	dom map_j \subseteq C
+ *
+ * then right[j] is set to 1.  Otherwise, if
+ *
+ *	ran map_i \cap dom map_j = \emptyset
+ *
+ * then right[j] is set to 0.  Otherwise, composing to the right
+ * is impossible.
+ *
+ * Similar, for composing to the left, we have if
+ *
+ *	ran map_j \subseteq C
+ *
+ * then left[j] is set to 1.  Otherwise, if
+ *
+ *	dom map_i \cap ran map_j = \emptyset
+ *
+ * then left[j] is set to 0.  Otherwise, composing to the left
+ * is impossible.
+ *
+ * The return value is or'd with LEFT if composing to the left
+ * is possible and with RIGHT if composing to the right is possible.
+ */
+static int composability(__isl_keep isl_set *C, int i,
+	isl_set **dom, isl_set **ran, int *left, int *right,
+	__isl_keep isl_map *map)
+{
+	int j;
+	int ok;
+
+	ok = LEFT | RIGHT;
+	for (j = 0; j < map->n && ok; ++j) {
+		isl_bool overlaps, subset;
+		if (j == i)
+			continue;
+
+		if (ok & RIGHT) {
+			if (!dom[j])
+				dom[j] = isl_set_from_basic_set(
+					isl_basic_map_domain(
+						isl_basic_map_copy(map->p[j])));
+			if (!dom[j])
+				return -1;
+			overlaps = isl_set_overlaps(ran[i], dom[j]);
+			if (overlaps < 0)
+				return -1;
+			if (!overlaps)
+				right[j] = 0;
+			else {
+				subset = isl_set_is_subset(dom[j], C);
+				if (subset < 0)
+					return -1;
+				if (subset)
+					right[j] = 1;
+				else
+					ok &= ~RIGHT;
+			}
+		}
+
+		if (ok & LEFT) {
+			if (!ran[j])
+				ran[j] = isl_set_from_basic_set(
+					isl_basic_map_range(
+						isl_basic_map_copy(map->p[j])));
+			if (!ran[j])
+				return -1;
+			overlaps = isl_set_overlaps(dom[i], ran[j]);
+			if (overlaps < 0)
+				return -1;
+			if (!overlaps)
+				left[j] = 0;
+			else {
+				subset = isl_set_is_subset(ran[j], C);
+				if (subset < 0)
+					return -1;
+				if (subset)
+					left[j] = 1;
+				else
+					ok &= ~LEFT;
+			}
+		}
+	}
+
+	return ok;
+}
+
+static __isl_give isl_map *anonymize(__isl_take isl_map *map)
+{
+	map = isl_map_reset(map, isl_dim_in);
+	map = isl_map_reset(map, isl_dim_out);
+	return map;
+}
+
+/* Return a map that is a union of the basic maps in "map", except i,
+ * composed to left and right with qc based on the entries of "left"
+ * and "right".
+ */
+static __isl_give isl_map *compose(__isl_keep isl_map *map, int i,
+	__isl_take isl_map *qc, int *left, int *right)
+{
+	int j;
+	isl_map *comp;
+
+	comp = isl_map_empty(isl_map_get_space(map));
+	for (j = 0; j < map->n; ++j) {
+		isl_map *map_j;
+
+		if (j == i)
+			continue;
+
+		map_j = isl_map_from_basic_map(isl_basic_map_copy(map->p[j]));
+		map_j = anonymize(map_j);
+		if (left && left[j])
+			map_j = isl_map_apply_range(map_j, isl_map_copy(qc));
+		if (right && right[j])
+			map_j = isl_map_apply_range(isl_map_copy(qc), map_j);
+		comp = isl_map_union(comp, map_j);
+	}
+
+	comp = isl_map_compute_divs(comp);
+	comp = isl_map_coalesce(comp);
+
+	isl_map_free(qc);
+
+	return comp;
+}
+
+/* Compute the transitive closure of "map" incrementally by
+ * computing
+ *
+ *	map_i^+ \cup qc^+
+ *
+ * or
+ *
+ *	map_i^+ \cup ((id \cup map_i^) \circ qc^+)
+ *
+ * or
+ *
+ *	map_i^+ \cup (qc^+ \circ (id \cup map_i^))
+ *
+ * depending on whether left or right are NULL.
+ */
+static __isl_give isl_map *compute_incremental(
+	__isl_take isl_space *dim, __isl_keep isl_map *map,
+	int i, __isl_take isl_map *qc, int *left, int *right, int *exact)
+{
+	isl_map *map_i;
+	isl_map *tc;
+	isl_map *rtc = NULL;
+
+	if (!map)
+		goto error;
+	isl_assert(map->ctx, left || right, goto error);
+
+	map_i = isl_map_from_basic_map(isl_basic_map_copy(map->p[i]));
+	tc = construct_projected_component(isl_space_copy(dim), map_i,
+						exact, 1);
+	isl_map_free(map_i);
+
+	if (*exact)
+		qc = isl_map_transitive_closure(qc, exact);
+
+	if (!*exact) {
+		isl_space_free(dim);
+		isl_map_free(tc);
+		isl_map_free(qc);
+		return isl_map_universe(isl_map_get_space(map));
+	}
+
+	if (!left || !right)
+		rtc = isl_map_union(isl_map_copy(tc),
+				    isl_map_identity(isl_map_get_space(tc)));
+	if (!right)
+		qc = isl_map_apply_range(rtc, qc);
+	if (!left)
+		qc = isl_map_apply_range(qc, rtc);
+	qc = isl_map_union(tc, qc);
+
+	isl_space_free(dim);
+
+	return qc;
+error:
+	isl_space_free(dim);
+	isl_map_free(qc);
+	return NULL;
+}
+
+/* Given a map "map", try to find a basic map such that
+ * map^+ can be computed as
+ *
+ * map^+ = map_i^+ \cup
+ *    \bigcup_j ((map_i^+ \cup Id_C)^+ \circ map_j \circ (map_i^+ \cup Id_C))^+
+ *
+ * with C the simple hull of the domain and range of the input map.
+ * map_i^ \cup Id_C is computed by allowing the path lengths to be zero
+ * and by intersecting domain and range with C.
+ * Of course, we need to check that this is actually equal to map_i^ \cup Id_C.
+ * Also, we only use the incremental computation if all the transitive
+ * closures are exact and if the number of basic maps in the union,
+ * after computing the integer divisions, is smaller than the number
+ * of basic maps in the input map.
+ */
+static int incemental_on_entire_domain(__isl_keep isl_space *dim,
+	__isl_keep isl_map *map,
+	isl_set **dom, isl_set **ran, int *left, int *right,
+	__isl_give isl_map **res)
+{
+	int i;
+	isl_set *C;
+	unsigned d;
+
+	*res = NULL;
+
+	C = isl_set_union(isl_map_domain(isl_map_copy(map)),
+			  isl_map_range(isl_map_copy(map)));
+	C = isl_set_from_basic_set(isl_set_simple_hull(C));
+	if (!C)
+		return -1;
+	if (C->n != 1) {
+		isl_set_free(C);
+		return 0;
+	}
+
+	d = isl_map_dim(map, isl_dim_in);
+
+	for (i = 0; i < map->n; ++i) {
+		isl_map *qc;
+		int exact_i, spurious;
+		int j;
+		dom[i] = isl_set_from_basic_set(isl_basic_map_domain(
+					isl_basic_map_copy(map->p[i])));
+		ran[i] = isl_set_from_basic_set(isl_basic_map_range(
+					isl_basic_map_copy(map->p[i])));
+		qc = q_closure(isl_space_copy(dim), isl_set_copy(C),
+				map->p[i], &exact_i);
+		if (!qc)
+			goto error;
+		if (!exact_i) {
+			isl_map_free(qc);
+			continue;
+		}
+		spurious = has_spurious_elements(qc, dom[i], ran[i]);
+		if (spurious) {
+			isl_map_free(qc);
+			if (spurious < 0)
+				goto error;
+			continue;
+		}
+		qc = isl_map_project_out(qc, isl_dim_in, d, 1);
+		qc = isl_map_project_out(qc, isl_dim_out, d, 1);
+		qc = isl_map_compute_divs(qc);
+		for (j = 0; j < map->n; ++j)
+			left[j] = right[j] = 1;
+		qc = compose(map, i, qc, left, right);
+		if (!qc)
+			goto error;
+		if (qc->n >= map->n) {
+			isl_map_free(qc);
+			continue;
+		}
+		*res = compute_incremental(isl_space_copy(dim), map, i, qc,
+				left, right, &exact_i);
+		if (!*res)
+			goto error;
+		if (exact_i)
+			break;
+		isl_map_free(*res);
+		*res = NULL;
+	}
+
+	isl_set_free(C);
+
+	return *res != NULL;
+error:
+	isl_set_free(C);
+	return -1;
+}
+
+/* Try and compute the transitive closure of "map" as
+ *
+ * map^+ = map_i^+ \cup
+ *    \bigcup_j ((map_i^+ \cup Id_C)^+ \circ map_j \circ (map_i^+ \cup Id_C))^+
+ *
+ * with C either the simple hull of the domain and range of the entire
+ * map or the simple hull of domain and range of map_i.
+ */
+static __isl_give isl_map *incremental_closure(__isl_take isl_space *dim,
+	__isl_keep isl_map *map, int *exact, int project)
+{
+	int i;
+	isl_set **dom = NULL;
+	isl_set **ran = NULL;
+	int *left = NULL;
+	int *right = NULL;
+	isl_set *C;
+	unsigned d;
+	isl_map *res = NULL;
+
+	if (!project)
+		return construct_projected_component(dim, map, exact, project);
+
+	if (!map)
+		goto error;
+	if (map->n <= 1)
+		return construct_projected_component(dim, map, exact, project);
+
+	d = isl_map_dim(map, isl_dim_in);
+
+	dom = isl_calloc_array(map->ctx, isl_set *, map->n);
+	ran = isl_calloc_array(map->ctx, isl_set *, map->n);
+	left = isl_calloc_array(map->ctx, int, map->n);
+	right = isl_calloc_array(map->ctx, int, map->n);
+	if (!ran || !dom || !left || !right)
+		goto error;
+
+	if (incemental_on_entire_domain(dim, map, dom, ran, left, right, &res) < 0)
+		goto error;
+
+	for (i = 0; !res && i < map->n; ++i) {
+		isl_map *qc;
+		int exact_i, spurious, comp;
+		if (!dom[i])
+			dom[i] = isl_set_from_basic_set(
+					isl_basic_map_domain(
+						isl_basic_map_copy(map->p[i])));
+		if (!dom[i])
+			goto error;
+		if (!ran[i])
+			ran[i] = isl_set_from_basic_set(
+					isl_basic_map_range(
+						isl_basic_map_copy(map->p[i])));
+		if (!ran[i])
+			goto error;
+		C = isl_set_union(isl_set_copy(dom[i]),
+				      isl_set_copy(ran[i]));
+		C = isl_set_from_basic_set(isl_set_simple_hull(C));
+		if (!C)
+			goto error;
+		if (C->n != 1) {
+			isl_set_free(C);
+			continue;
+		}
+		comp = composability(C, i, dom, ran, left, right, map);
+		if (!comp || comp < 0) {
+			isl_set_free(C);
+			if (comp < 0)
+				goto error;
+			continue;
+		}
+		qc = q_closure(isl_space_copy(dim), C, map->p[i], &exact_i);
+		if (!qc)
+			goto error;
+		if (!exact_i) {
+			isl_map_free(qc);
+			continue;
+		}
+		spurious = has_spurious_elements(qc, dom[i], ran[i]);
+		if (spurious) {
+			isl_map_free(qc);
+			if (spurious < 0)
+				goto error;
+			continue;
+		}
+		qc = isl_map_project_out(qc, isl_dim_in, d, 1);
+		qc = isl_map_project_out(qc, isl_dim_out, d, 1);
+		qc = isl_map_compute_divs(qc);
+		qc = compose(map, i, qc, (comp & LEFT) ? left : NULL,
+				(comp & RIGHT) ? right : NULL);
+		if (!qc)
+			goto error;
+		if (qc->n >= map->n) {
+			isl_map_free(qc);
+			continue;
+		}
+		res = compute_incremental(isl_space_copy(dim), map, i, qc,
+				(comp & LEFT) ? left : NULL,
+				(comp & RIGHT) ? right : NULL, &exact_i);
+		if (!res)
+			goto error;
+		if (exact_i)
+			break;
+		isl_map_free(res);
+		res = NULL;
+	}
+
+	for (i = 0; i < map->n; ++i) {
+		isl_set_free(dom[i]);
+		isl_set_free(ran[i]);
+	}
+	free(dom);
+	free(ran);
+	free(left);
+	free(right);
+
+	if (res) {
+		isl_space_free(dim);
+		return res;
+	}
+
+	return construct_projected_component(dim, map, exact, project);
+error:
+	if (dom)
+		for (i = 0; i < map->n; ++i)
+			isl_set_free(dom[i]);
+	free(dom);
+	if (ran)
+		for (i = 0; i < map->n; ++i)
+			isl_set_free(ran[i]);
+	free(ran);
+	free(left);
+	free(right);
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Given an array of sets "set", add "dom" at position "pos"
+ * and search for elements at earlier positions that overlap with "dom".
+ * If any can be found, then merge all of them, together with "dom", into
+ * a single set and assign the union to the first in the array,
+ * which becomes the new group leader for all groups involved in the merge.
+ * During the search, we only consider group leaders, i.e., those with
+ * group[i] = i, as the other sets have already been combined
+ * with one of the group leaders.
+ */
+static int merge(isl_set **set, int *group, __isl_take isl_set *dom, int pos)
+{
+	int i;
+
+	group[pos] = pos;
+	set[pos] = isl_set_copy(dom);
+
+	for (i = pos - 1; i >= 0; --i) {
+		isl_bool o;
+
+		if (group[i] != i)
+			continue;
+
+		o = isl_set_overlaps(set[i], dom);
+		if (o < 0)
+			goto error;
+		if (!o)
+			continue;
+
+		set[i] = isl_set_union(set[i], set[group[pos]]);
+		set[group[pos]] = NULL;
+		if (!set[i])
+			goto error;
+		group[group[pos]] = i;
+		group[pos] = i;
+	}
+
+	isl_set_free(dom);
+	return 0;
+error:
+	isl_set_free(dom);
+	return -1;
+}
+
+/* Replace each entry in the n by n grid of maps by the cross product
+ * with the relation { [i] -> [i + 1] }.
+ */
+static int add_length(__isl_keep isl_map *map, isl_map ***grid, int n)
+{
+	int i, j, k;
+	isl_space *dim;
+	isl_basic_map *bstep;
+	isl_map *step;
+	unsigned nparam;
+
+	if (!map)
+		return -1;
+
+	dim = isl_map_get_space(map);
+	nparam = isl_space_dim(dim, isl_dim_param);
+	dim = isl_space_drop_dims(dim, isl_dim_in, 0, isl_space_dim(dim, isl_dim_in));
+	dim = isl_space_drop_dims(dim, isl_dim_out, 0, isl_space_dim(dim, isl_dim_out));
+	dim = isl_space_add_dims(dim, isl_dim_in, 1);
+	dim = isl_space_add_dims(dim, isl_dim_out, 1);
+	bstep = isl_basic_map_alloc_space(dim, 0, 1, 0);
+	k = isl_basic_map_alloc_equality(bstep);
+	if (k < 0) {
+		isl_basic_map_free(bstep);
+		return -1;
+	}
+	isl_seq_clr(bstep->eq[k], 1 + isl_basic_map_total_dim(bstep));
+	isl_int_set_si(bstep->eq[k][0], 1);
+	isl_int_set_si(bstep->eq[k][1 + nparam], 1);
+	isl_int_set_si(bstep->eq[k][1 + nparam + 1], -1);
+	bstep = isl_basic_map_finalize(bstep);
+	step = isl_map_from_basic_map(bstep);
+
+	for (i = 0; i < n; ++i)
+		for (j = 0; j < n; ++j)
+			grid[i][j] = isl_map_product(grid[i][j],
+						     isl_map_copy(step));
+
+	isl_map_free(step);
+
+	return 0;
+}
+
+/* The core of the Floyd-Warshall algorithm.
+ * Updates the given n x x matrix of relations in place.
+ *
+ * The algorithm iterates over all vertices.  In each step, the whole
+ * matrix is updated to include all paths that go to the current vertex,
+ * possibly stay there a while (including passing through earlier vertices)
+ * and then come back.  At the start of each iteration, the diagonal
+ * element corresponding to the current vertex is replaced by its
+ * transitive closure to account for all indirect paths that stay
+ * in the current vertex.
+ */
+static void floyd_warshall_iterate(isl_map ***grid, int n, int *exact)
+{
+	int r, p, q;
+
+	for (r = 0; r < n; ++r) {
+		int r_exact;
+		grid[r][r] = isl_map_transitive_closure(grid[r][r],
+				(exact && *exact) ? &r_exact : NULL);
+		if (exact && *exact && !r_exact)
+			*exact = 0;
+
+		for (p = 0; p < n; ++p)
+			for (q = 0; q < n; ++q) {
+				isl_map *loop;
+				if (p == r && q == r)
+					continue;
+				loop = isl_map_apply_range(
+						isl_map_copy(grid[p][r]),
+						isl_map_copy(grid[r][q]));
+				grid[p][q] = isl_map_union(grid[p][q], loop);
+				loop = isl_map_apply_range(
+						isl_map_copy(grid[p][r]),
+					isl_map_apply_range(
+						isl_map_copy(grid[r][r]),
+						isl_map_copy(grid[r][q])));
+				grid[p][q] = isl_map_union(grid[p][q], loop);
+				grid[p][q] = isl_map_coalesce(grid[p][q]);
+			}
+	}
+}
+
+/* Given a partition of the domains and ranges of the basic maps in "map",
+ * apply the Floyd-Warshall algorithm with the elements in the partition
+ * as vertices.
+ *
+ * In particular, there are "n" elements in the partition and "group" is
+ * an array of length 2 * map->n with entries in [0,n-1].
+ *
+ * We first construct a matrix of relations based on the partition information,
+ * apply Floyd-Warshall on this matrix of relations and then take the
+ * union of all entries in the matrix as the final result.
+ *
+ * If we are actually computing the power instead of the transitive closure,
+ * i.e., when "project" is not set, then the result should have the
+ * path lengths encoded as the difference between an extra pair of
+ * coordinates.  We therefore apply the nested transitive closures
+ * to relations that include these lengths.  In particular, we replace
+ * the input relation by the cross product with the unit length relation
+ * { [i] -> [i + 1] }.
+ */
+static __isl_give isl_map *floyd_warshall_with_groups(__isl_take isl_space *dim,
+	__isl_keep isl_map *map, int *exact, int project, int *group, int n)
+{
+	int i, j, k;
+	isl_map ***grid = NULL;
+	isl_map *app;
+
+	if (!map)
+		goto error;
+
+	if (n == 1) {
+		free(group);
+		return incremental_closure(dim, map, exact, project);
+	}
+
+	grid = isl_calloc_array(map->ctx, isl_map **, n);
+	if (!grid)
+		goto error;
+	for (i = 0; i < n; ++i) {
+		grid[i] = isl_calloc_array(map->ctx, isl_map *, n);
+		if (!grid[i])
+			goto error;
+		for (j = 0; j < n; ++j)
+			grid[i][j] = isl_map_empty(isl_map_get_space(map));
+	}
+
+	for (k = 0; k < map->n; ++k) {
+		i = group[2 * k];
+		j = group[2 * k + 1];
+		grid[i][j] = isl_map_union(grid[i][j],
+				isl_map_from_basic_map(
+					isl_basic_map_copy(map->p[k])));
+	}
+
+	if (!project && add_length(map, grid, n) < 0)
+		goto error;
+
+	floyd_warshall_iterate(grid, n, exact);
+
+	app = isl_map_empty(isl_map_get_space(grid[0][0]));
+
+	for (i = 0; i < n; ++i) {
+		for (j = 0; j < n; ++j)
+			app = isl_map_union(app, grid[i][j]);
+		free(grid[i]);
+	}
+	free(grid);
+
+	free(group);
+	isl_space_free(dim);
+
+	return app;
+error:
+	if (grid)
+		for (i = 0; i < n; ++i) {
+			if (!grid[i])
+				continue;
+			for (j = 0; j < n; ++j)
+				isl_map_free(grid[i][j]);
+			free(grid[i]);
+		}
+	free(grid);
+	free(group);
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Partition the domains and ranges of the n basic relations in list
+ * into disjoint cells.
+ *
+ * To find the partition, we simply consider all of the domains
+ * and ranges in turn and combine those that overlap.
+ * "set" contains the partition elements and "group" indicates
+ * to which partition element a given domain or range belongs.
+ * The domain of basic map i corresponds to element 2 * i in these arrays,
+ * while the domain corresponds to element 2 * i + 1.
+ * During the construction group[k] is either equal to k,
+ * in which case set[k] contains the union of all the domains and
+ * ranges in the corresponding group, or is equal to some l < k,
+ * with l another domain or range in the same group.
+ */
+static int *setup_groups(isl_ctx *ctx, __isl_keep isl_basic_map **list, int n,
+	isl_set ***set, int *n_group)
+{
+	int i;
+	int *group = NULL;
+	int g;
+
+	*set = isl_calloc_array(ctx, isl_set *, 2 * n);
+	group = isl_alloc_array(ctx, int, 2 * n);
+
+	if (!*set || !group)
+		goto error;
+
+	for (i = 0; i < n; ++i) {
+		isl_set *dom;
+		dom = isl_set_from_basic_set(isl_basic_map_domain(
+				isl_basic_map_copy(list[i])));
+		if (merge(*set, group, dom, 2 * i) < 0)
+			goto error;
+		dom = isl_set_from_basic_set(isl_basic_map_range(
+				isl_basic_map_copy(list[i])));
+		if (merge(*set, group, dom, 2 * i + 1) < 0)
+			goto error;
+	}
+
+	g = 0;
+	for (i = 0; i < 2 * n; ++i)
+		if (group[i] == i) {
+			if (g != i) {
+				(*set)[g] = (*set)[i];
+				(*set)[i] = NULL;
+			}
+			group[i] = g++;
+		} else
+			group[i] = group[group[i]];
+
+	*n_group = g;
+
+	return group;
+error:
+	if (*set) {
+		for (i = 0; i < 2 * n; ++i)
+			isl_set_free((*set)[i]);
+		free(*set);
+		*set = NULL;
+	}
+	free(group);
+	return NULL;
+}
+
+/* Check if the domains and ranges of the basic maps in "map" can
+ * be partitioned, and if so, apply Floyd-Warshall on the elements
+ * of the partition.  Note that we also apply this algorithm
+ * if we want to compute the power, i.e., when "project" is not set.
+ * However, the results are unlikely to be exact since the recursive
+ * calls inside the Floyd-Warshall algorithm typically result in
+ * non-linear path lengths quite quickly.
+ */
+static __isl_give isl_map *floyd_warshall(__isl_take isl_space *dim,
+	__isl_keep isl_map *map, int *exact, int project)
+{
+	int i;
+	isl_set **set = NULL;
+	int *group = NULL;
+	int n;
+
+	if (!map)
+		goto error;
+	if (map->n <= 1)
+		return incremental_closure(dim, map, exact, project);
+
+	group = setup_groups(map->ctx, map->p, map->n, &set, &n);
+	if (!group)
+		goto error;
+
+	for (i = 0; i < 2 * map->n; ++i)
+		isl_set_free(set[i]);
+
+	free(set);
+
+	return floyd_warshall_with_groups(dim, map, exact, project, group, n);
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* Structure for representing the nodes of the graph of which
+ * strongly connected components are being computed.
+ *
+ * list contains the actual nodes
+ * check_closed is set if we may have used the fact that
+ * a pair of basic maps can be interchanged
+ */
+struct isl_tc_follows_data {
+	isl_basic_map **list;
+	int check_closed;
+};
+
+/* Check whether in the computation of the transitive closure
+ * "list[i]" (R_1) should follow (or be part of the same component as)
+ * "list[j]" (R_2).
+ *
+ * That is check whether
+ *
+ *	R_1 \circ R_2
+ *
+ * is a subset of
+ *
+ *	R_2 \circ R_1
+ *
+ * If so, then there is no reason for R_1 to immediately follow R_2
+ * in any path.
+ *
+ * *check_closed is set if the subset relation holds while
+ * R_1 \circ R_2 is not empty.
+ */
+static isl_bool basic_map_follows(int i, int j, void *user)
+{
+	struct isl_tc_follows_data *data = user;
+	struct isl_map *map12 = NULL;
+	struct isl_map *map21 = NULL;
+	isl_bool subset;
+
+	if (!isl_space_tuple_is_equal(data->list[i]->dim, isl_dim_in,
+				    data->list[j]->dim, isl_dim_out))
+		return isl_bool_false;
+
+	map21 = isl_map_from_basic_map(
+			isl_basic_map_apply_range(
+				isl_basic_map_copy(data->list[j]),
+				isl_basic_map_copy(data->list[i])));
+	subset = isl_map_is_empty(map21);
+	if (subset < 0)
+		goto error;
+	if (subset) {
+		isl_map_free(map21);
+		return isl_bool_false;
+	}
+
+	if (!isl_space_tuple_is_equal(data->list[i]->dim, isl_dim_in,
+				    data->list[i]->dim, isl_dim_out) ||
+	    !isl_space_tuple_is_equal(data->list[j]->dim, isl_dim_in,
+				    data->list[j]->dim, isl_dim_out)) {
+		isl_map_free(map21);
+		return isl_bool_true;
+	}
+
+	map12 = isl_map_from_basic_map(
+			isl_basic_map_apply_range(
+				isl_basic_map_copy(data->list[i]),
+				isl_basic_map_copy(data->list[j])));
+
+	subset = isl_map_is_subset(map21, map12);
+
+	isl_map_free(map12);
+	isl_map_free(map21);
+
+	if (subset)
+		data->check_closed = 1;
+
+	return subset < 0 ? isl_bool_error : !subset;
+error:
+	isl_map_free(map21);
+	return isl_bool_error;
+}
+
+/* Given a union of basic maps R = \cup_i R_i \subseteq D \times D
+ * and a dimension specification (Z^{n+1} -> Z^{n+1}),
+ * construct a map that is an overapproximation of the map
+ * that takes an element from the dom R \times Z to an
+ * element from ran R \times Z, such that the first n coordinates of the
+ * difference between them is a sum of differences between images
+ * and pre-images in one of the R_i and such that the last coordinate
+ * is equal to the number of steps taken.
+ * If "project" is set, then these final coordinates are not included,
+ * i.e., a relation of type Z^n -> Z^n is returned.
+ * That is, let
+ *
+ *	\Delta_i = { y - x | (x, y) in R_i }
+ *
+ * then the constructed map is an overapproximation of
+ *
+ *	{ (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
+ *				d = (\sum_i k_i \delta_i, \sum_i k_i) and
+ *				x in dom R and x + d in ran R }
+ *
+ * or
+ *
+ *	{ (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
+ *				d = (\sum_i k_i \delta_i) and
+ *				x in dom R and x + d in ran R }
+ *
+ * if "project" is set.
+ *
+ * We first split the map into strongly connected components, perform
+ * the above on each component and then join the results in the correct
+ * order, at each join also taking in the union of both arguments
+ * to allow for paths that do not go through one of the two arguments.
+ */
+static __isl_give isl_map *construct_power_components(__isl_take isl_space *dim,
+	__isl_keep isl_map *map, int *exact, int project)
+{
+	int i, n, c;
+	struct isl_map *path = NULL;
+	struct isl_tc_follows_data data;
+	struct isl_tarjan_graph *g = NULL;
+	int *orig_exact;
+	int local_exact;
+
+	if (!map)
+		goto error;
+	if (map->n <= 1)
+		return floyd_warshall(dim, map, exact, project);
+
+	data.list = map->p;
+	data.check_closed = 0;
+	g = isl_tarjan_graph_init(map->ctx, map->n, &basic_map_follows, &data);
+	if (!g)
+		goto error;
+
+	orig_exact = exact;
+	if (data.check_closed && !exact)
+		exact = &local_exact;
+
+	c = 0;
+	i = 0;
+	n = map->n;
+	if (project)
+		path = isl_map_empty(isl_map_get_space(map));
+	else
+		path = isl_map_empty(isl_space_copy(dim));
+	path = anonymize(path);
+	while (n) {
+		struct isl_map *comp;
+		isl_map *path_comp, *path_comb;
+		comp = isl_map_alloc_space(isl_map_get_space(map), n, 0);
+		while (g->order[i] != -1) {
+			comp = isl_map_add_basic_map(comp,
+				    isl_basic_map_copy(map->p[g->order[i]]));
+			--n;
+			++i;
+		}
+		path_comp = floyd_warshall(isl_space_copy(dim),
+						comp, exact, project);
+		path_comp = anonymize(path_comp);
+		path_comb = isl_map_apply_range(isl_map_copy(path),
+						isl_map_copy(path_comp));
+		path = isl_map_union(path, path_comp);
+		path = isl_map_union(path, path_comb);
+		isl_map_free(comp);
+		++i;
+		++c;
+	}
+
+	if (c > 1 && data.check_closed && !*exact) {
+		int closed;
+
+		closed = isl_map_is_transitively_closed(path);
+		if (closed < 0)
+			goto error;
+		if (!closed) {
+			isl_tarjan_graph_free(g);
+			isl_map_free(path);
+			return floyd_warshall(dim, map, orig_exact, project);
+		}
+	}
+
+	isl_tarjan_graph_free(g);
+	isl_space_free(dim);
+
+	return path;
+error:
+	isl_tarjan_graph_free(g);
+	isl_space_free(dim);
+	isl_map_free(path);
+	return NULL;
+}
+
+/* Given a union of basic maps R = \cup_i R_i \subseteq D \times D,
+ * construct a map that is an overapproximation of the map
+ * that takes an element from the space D to another
+ * element from the same space, such that the difference between
+ * them is a strictly positive sum of differences between images
+ * and pre-images in one of the R_i.
+ * The number of differences in the sum is equated to parameter "param".
+ * That is, let
+ *
+ *	\Delta_i = { y - x | (x, y) in R_i }
+ *
+ * then the constructed map is an overapproximation of
+ *
+ *	{ (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
+ *				d = \sum_i k_i \delta_i and k = \sum_i k_i > 0 }
+ * or
+ *
+ *	{ (x) -> (x + d) | \exists k_i >= 0, \delta_i \in \Delta_i :
+ *				d = \sum_i k_i \delta_i and \sum_i k_i > 0 }
+ *
+ * if "project" is set.
+ *
+ * If "project" is not set, then
+ * we construct an extended mapping with an extra coordinate
+ * that indicates the number of steps taken.  In particular,
+ * the difference in the last coordinate is equal to the number
+ * of steps taken to move from a domain element to the corresponding
+ * image element(s).
+ */
+static __isl_give isl_map *construct_power(__isl_keep isl_map *map,
+	int *exact, int project)
+{
+	struct isl_map *app = NULL;
+	isl_space *dim = NULL;
+
+	if (!map)
+		return NULL;
+
+	dim = isl_map_get_space(map);
+
+	dim = isl_space_add_dims(dim, isl_dim_in, 1);
+	dim = isl_space_add_dims(dim, isl_dim_out, 1);
+
+	app = construct_power_components(isl_space_copy(dim), map,
+					exact, project);
+
+	isl_space_free(dim);
+
+	return app;
+}
+
+/* Compute the positive powers of "map", or an overapproximation.
+ * If the result is exact, then *exact is set to 1.
+ *
+ * If project is set, then we are actually interested in the transitive
+ * closure, so we can use a more relaxed exactness check.
+ * The lengths of the paths are also projected out instead of being
+ * encoded as the difference between an extra pair of final coordinates.
+ */
+static __isl_give isl_map *map_power(__isl_take isl_map *map,
+	int *exact, int project)
+{
+	struct isl_map *app = NULL;
+
+	if (exact)
+		*exact = 1;
+
+	if (!map)
+		return NULL;
+
+	isl_assert(map->ctx,
+		isl_map_dim(map, isl_dim_in) == isl_map_dim(map, isl_dim_out),
+		goto error);
+
+	app = construct_power(map, exact, project);
+
+	isl_map_free(map);
+	return app;
+error:
+	isl_map_free(map);
+	isl_map_free(app);
+	return NULL;
+}
+
+/* Compute the positive powers of "map", or an overapproximation.
+ * The result maps the exponent to a nested copy of the corresponding power.
+ * If the result is exact, then *exact is set to 1.
+ * map_power constructs an extended relation with the path lengths
+ * encoded as the difference between the final coordinates.
+ * In the final step, this difference is equated to an extra parameter
+ * and made positive.  The extra coordinates are subsequently projected out
+ * and the parameter is turned into the domain of the result.
+ */
+__isl_give isl_map *isl_map_power(__isl_take isl_map *map, int *exact)
+{
+	isl_space *target_dim;
+	isl_space *dim;
+	isl_map *diff;
+	unsigned d;
+	unsigned param;
+
+	if (!map)
+		return NULL;
+
+	d = isl_map_dim(map, isl_dim_in);
+	param = isl_map_dim(map, isl_dim_param);
+
+	map = isl_map_compute_divs(map);
+	map = isl_map_coalesce(map);
+
+	if (isl_map_plain_is_empty(map)) {
+		map = isl_map_from_range(isl_map_wrap(map));
+		map = isl_map_add_dims(map, isl_dim_in, 1);
+		map = isl_map_set_dim_name(map, isl_dim_in, 0, "k");
+		return map;
+	}
+
+	target_dim = isl_map_get_space(map);
+	target_dim = isl_space_from_range(isl_space_wrap(target_dim));
+	target_dim = isl_space_add_dims(target_dim, isl_dim_in, 1);
+	target_dim = isl_space_set_dim_name(target_dim, isl_dim_in, 0, "k");
+
+	map = map_power(map, exact, 0);
+
+	map = isl_map_add_dims(map, isl_dim_param, 1);
+	dim = isl_map_get_space(map);
+	diff = equate_parameter_to_length(dim, param);
+	map = isl_map_intersect(map, diff);
+	map = isl_map_project_out(map, isl_dim_in, d, 1);
+	map = isl_map_project_out(map, isl_dim_out, d, 1);
+	map = isl_map_from_range(isl_map_wrap(map));
+	map = isl_map_move_dims(map, isl_dim_in, 0, isl_dim_param, param, 1);
+
+	map = isl_map_reset_space(map, target_dim);
+
+	return map;
+}
+
+/* Compute a relation that maps each element in the range of the input
+ * relation to the lengths of all paths composed of edges in the input
+ * relation that end up in the given range element.
+ * The result may be an overapproximation, in which case *exact is set to 0.
+ * The resulting relation is very similar to the power relation.
+ * The difference are that the domain has been projected out, the
+ * range has become the domain and the exponent is the range instead
+ * of a parameter.
+ */
+__isl_give isl_map *isl_map_reaching_path_lengths(__isl_take isl_map *map,
+	int *exact)
+{
+	isl_space *dim;
+	isl_map *diff;
+	unsigned d;
+	unsigned param;
+
+	if (!map)
+		return NULL;
+
+	d = isl_map_dim(map, isl_dim_in);
+	param = isl_map_dim(map, isl_dim_param);
+
+	map = isl_map_compute_divs(map);
+	map = isl_map_coalesce(map);
+
+	if (isl_map_plain_is_empty(map)) {
+		if (exact)
+			*exact = 1;
+		map = isl_map_project_out(map, isl_dim_out, 0, d);
+		map = isl_map_add_dims(map, isl_dim_out, 1);
+		return map;
+	}
+
+	map = map_power(map, exact, 0);
+
+	map = isl_map_add_dims(map, isl_dim_param, 1);
+	dim = isl_map_get_space(map);
+	diff = equate_parameter_to_length(dim, param);
+	map = isl_map_intersect(map, diff);
+	map = isl_map_project_out(map, isl_dim_in, 0, d + 1);
+	map = isl_map_project_out(map, isl_dim_out, d, 1);
+	map = isl_map_reverse(map);
+	map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_param, param, 1);
+
+	return map;
+}
+
+/* Given a map, compute the smallest superset of this map that is of the form
+ *
+ *	{ i -> j : L <= j - i <= U and exists a_p: j_p - i_p = M_p a_p }
+ *
+ * (where p ranges over the (non-parametric) dimensions),
+ * compute the transitive closure of this map, i.e.,
+ *
+ *	{ i -> j : exists k > 0:
+ *		k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p }
+ *
+ * and intersect domain and range of this transitive closure with
+ * the given domain and range.
+ *
+ * If with_id is set, then try to include as much of the identity mapping
+ * as possible, by computing
+ *
+ *	{ i -> j : exists k >= 0:
+ *		k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p }
+ *
+ * instead (i.e., allow k = 0).
+ *
+ * In practice, we compute the difference set
+ *
+ *	delta  = { j - i | i -> j in map },
+ *
+ * look for stride constraint on the individual dimensions and compute
+ * (constant) lower and upper bounds for each individual dimension,
+ * adding a constraint for each bound not equal to infinity.
+ */
+static __isl_give isl_map *box_closure_on_domain(__isl_take isl_map *map,
+	__isl_take isl_set *dom, __isl_take isl_set *ran, int with_id)
+{
+	int i;
+	int k;
+	unsigned d;
+	unsigned nparam;
+	unsigned total;
+	isl_space *dim;
+	isl_set *delta;
+	isl_map *app = NULL;
+	isl_basic_set *aff = NULL;
+	isl_basic_map *bmap = NULL;
+	isl_vec *obj = NULL;
+	isl_int opt;
+
+	isl_int_init(opt);
+
+	delta = isl_map_deltas(isl_map_copy(map));
+
+	aff = isl_set_affine_hull(isl_set_copy(delta));
+	if (!aff)
+		goto error;
+	dim = isl_map_get_space(map);
+	d = isl_space_dim(dim, isl_dim_in);
+	nparam = isl_space_dim(dim, isl_dim_param);
+	total = isl_space_dim(dim, isl_dim_all);
+	bmap = isl_basic_map_alloc_space(dim,
+					aff->n_div + 1, aff->n_div, 2 * d + 1);
+	for (i = 0; i < aff->n_div + 1; ++i) {
+		k = isl_basic_map_alloc_div(bmap);
+		if (k < 0)
+			goto error;
+		isl_int_set_si(bmap->div[k][0], 0);
+	}
+	for (i = 0; i < aff->n_eq; ++i) {
+		if (!isl_basic_set_eq_is_stride(aff, i))
+			continue;
+		k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_clr(bmap->eq[k], 1 + nparam);
+		isl_seq_cpy(bmap->eq[k] + 1 + nparam + d,
+				aff->eq[i] + 1 + nparam, d);
+		isl_seq_neg(bmap->eq[k] + 1 + nparam,
+				aff->eq[i] + 1 + nparam, d);
+		isl_seq_cpy(bmap->eq[k] + 1 + nparam + 2 * d,
+				aff->eq[i] + 1 + nparam + d, aff->n_div);
+		isl_int_set_si(bmap->eq[k][1 + total + aff->n_div], 0);
+	}
+	obj = isl_vec_alloc(map->ctx, 1 + nparam + d);
+	if (!obj)
+		goto error;
+	isl_seq_clr(obj->el, 1 + nparam + d);
+	for (i = 0; i < d; ++ i) {
+		enum isl_lp_result res;
+
+		isl_int_set_si(obj->el[1 + nparam + i], 1);
+
+		res = isl_set_solve_lp(delta, 0, obj->el, map->ctx->one, &opt,
+					NULL, NULL);
+		if (res == isl_lp_error)
+			goto error;
+		if (res == isl_lp_ok) {
+			k = isl_basic_map_alloc_inequality(bmap);
+			if (k < 0)
+				goto error;
+			isl_seq_clr(bmap->ineq[k],
+					1 + nparam + 2 * d + bmap->n_div);
+			isl_int_set_si(bmap->ineq[k][1 + nparam + i], -1);
+			isl_int_set_si(bmap->ineq[k][1 + nparam + d + i], 1);
+			isl_int_neg(bmap->ineq[k][1 + nparam + 2 * d + aff->n_div], opt);
+		}
+
+		res = isl_set_solve_lp(delta, 1, obj->el, map->ctx->one, &opt,
+					NULL, NULL);
+		if (res == isl_lp_error)
+			goto error;
+		if (res == isl_lp_ok) {
+			k = isl_basic_map_alloc_inequality(bmap);
+			if (k < 0)
+				goto error;
+			isl_seq_clr(bmap->ineq[k],
+					1 + nparam + 2 * d + bmap->n_div);
+			isl_int_set_si(bmap->ineq[k][1 + nparam + i], 1);
+			isl_int_set_si(bmap->ineq[k][1 + nparam + d + i], -1);
+			isl_int_set(bmap->ineq[k][1 + nparam + 2 * d + aff->n_div], opt);
+		}
+
+		isl_int_set_si(obj->el[1 + nparam + i], 0);
+	}
+	k = isl_basic_map_alloc_inequality(bmap);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(bmap->ineq[k],
+			1 + nparam + 2 * d + bmap->n_div);
+	if (!with_id)
+		isl_int_set_si(bmap->ineq[k][0], -1);
+	isl_int_set_si(bmap->ineq[k][1 + nparam + 2 * d + aff->n_div], 1);
+
+	app = isl_map_from_domain_and_range(dom, ran);
+
+	isl_vec_free(obj);
+	isl_basic_set_free(aff);
+	isl_map_free(map);
+	bmap = isl_basic_map_finalize(bmap);
+	isl_set_free(delta);
+	isl_int_clear(opt);
+
+	map = isl_map_from_basic_map(bmap);
+	map = isl_map_intersect(map, app);
+
+	return map;
+error:
+	isl_vec_free(obj);
+	isl_basic_map_free(bmap);
+	isl_basic_set_free(aff);
+	isl_set_free(dom);
+	isl_set_free(ran);
+	isl_map_free(map);
+	isl_set_free(delta);
+	isl_int_clear(opt);
+	return NULL;
+}
+
+/* Given a map, compute the smallest superset of this map that is of the form
+ *
+ *	{ i -> j : L <= j - i <= U and exists a_p: j_p - i_p = M_p a_p }
+ *
+ * (where p ranges over the (non-parametric) dimensions),
+ * compute the transitive closure of this map, i.e.,
+ *
+ *	{ i -> j : exists k > 0:
+ *		k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p }
+ *
+ * and intersect domain and range of this transitive closure with
+ * domain and range of the original map.
+ */
+static __isl_give isl_map *box_closure(__isl_take isl_map *map)
+{
+	isl_set *domain;
+	isl_set *range;
+
+	domain = isl_map_domain(isl_map_copy(map));
+	domain = isl_set_coalesce(domain);
+	range = isl_map_range(isl_map_copy(map));
+	range = isl_set_coalesce(range);
+
+	return box_closure_on_domain(map, domain, range, 0);
+}
+
+/* Given a map, compute the smallest superset of this map that is of the form
+ *
+ *	{ i -> j : L <= j - i <= U and exists a_p: j_p - i_p = M_p a_p }
+ *
+ * (where p ranges over the (non-parametric) dimensions),
+ * compute the transitive and partially reflexive closure of this map, i.e.,
+ *
+ *	{ i -> j : exists k >= 0:
+ *		k L <= j - i <= k U and exists a: j_p - i_p = M_p a_p }
+ *
+ * and intersect domain and range of this transitive closure with
+ * the given domain.
+ */
+static __isl_give isl_map *box_closure_with_identity(__isl_take isl_map *map,
+	__isl_take isl_set *dom)
+{
+	return box_closure_on_domain(map, dom, isl_set_copy(dom), 1);
+}
+
+/* Check whether app is the transitive closure of map.
+ * In particular, check that app is acyclic and, if so,
+ * check that
+ *
+ *	app \subset (map \cup (map \circ app))
+ */
+static int check_exactness_omega(__isl_keep isl_map *map,
+	__isl_keep isl_map *app)
+{
+	isl_set *delta;
+	int i;
+	int is_empty, is_exact;
+	unsigned d;
+	isl_map *test;
+
+	delta = isl_map_deltas(isl_map_copy(app));
+	d = isl_set_dim(delta, isl_dim_set);
+	for (i = 0; i < d; ++i)
+		delta = isl_set_fix_si(delta, isl_dim_set, i, 0);
+	is_empty = isl_set_is_empty(delta);
+	isl_set_free(delta);
+	if (is_empty < 0)
+		return -1;
+	if (!is_empty)
+		return 0;
+
+	test = isl_map_apply_range(isl_map_copy(app), isl_map_copy(map));
+	test = isl_map_union(test, isl_map_copy(map));
+	is_exact = isl_map_is_subset(app, test);
+	isl_map_free(test);
+
+	return is_exact;
+}
+
+/* Check if basic map M_i can be combined with all the other
+ * basic maps such that
+ *
+ *	(\cup_j M_j)^+
+ *
+ * can be computed as
+ *
+ *	M_i \cup (\cup_{j \ne i} M_i^* \circ M_j \circ M_i^*)^+
+ *
+ * In particular, check if we can compute a compact representation
+ * of
+ *
+ *		M_i^* \circ M_j \circ M_i^*
+ *
+ * for each j != i.
+ * Let M_i^? be an extension of M_i^+ that allows paths
+ * of length zero, i.e., the result of box_closure(., 1).
+ * The criterion, as proposed by Kelly et al., is that
+ * id = M_i^? - M_i^+ can be represented as a basic map
+ * and that
+ *
+ *	id \circ M_j \circ id = M_j
+ *
+ * for each j != i.
+ *
+ * If this function returns 1, then tc and qc are set to
+ * M_i^+ and M_i^?, respectively.
+ */
+static int can_be_split_off(__isl_keep isl_map *map, int i,
+	__isl_give isl_map **tc, __isl_give isl_map **qc)
+{
+	isl_map *map_i, *id = NULL;
+	int j = -1;
+	isl_set *C;
+
+	*tc = NULL;
+	*qc = NULL;
+
+	C = isl_set_union(isl_map_domain(isl_map_copy(map)),
+			  isl_map_range(isl_map_copy(map)));
+	C = isl_set_from_basic_set(isl_set_simple_hull(C));
+	if (!C)
+		goto error;
+
+	map_i = isl_map_from_basic_map(isl_basic_map_copy(map->p[i]));
+	*tc = box_closure(isl_map_copy(map_i));
+	*qc = box_closure_with_identity(map_i, C);
+	id = isl_map_subtract(isl_map_copy(*qc), isl_map_copy(*tc));
+
+	if (!id || !*qc)
+		goto error;
+	if (id->n != 1 || (*qc)->n != 1)
+		goto done;
+
+	for (j = 0; j < map->n; ++j) {
+		isl_map *map_j, *test;
+		int is_ok;
+
+		if (i == j)
+			continue;
+		map_j = isl_map_from_basic_map(
+					isl_basic_map_copy(map->p[j]));
+		test = isl_map_apply_range(isl_map_copy(id),
+						isl_map_copy(map_j));
+		test = isl_map_apply_range(test, isl_map_copy(id));
+		is_ok = isl_map_is_equal(test, map_j);
+		isl_map_free(map_j);
+		isl_map_free(test);
+		if (is_ok < 0)
+			goto error;
+		if (!is_ok)
+			break;
+	}
+
+done:
+	isl_map_free(id);
+	if (j == map->n)
+		return 1;
+
+	isl_map_free(*qc);
+	isl_map_free(*tc);
+	*qc = NULL;
+	*tc = NULL;
+
+	return 0;
+error:
+	isl_map_free(id);
+	isl_map_free(*qc);
+	isl_map_free(*tc);
+	*qc = NULL;
+	*tc = NULL;
+	return -1;
+}
+
+static __isl_give isl_map *box_closure_with_check(__isl_take isl_map *map,
+	int *exact)
+{
+	isl_map *app;
+
+	app = box_closure(isl_map_copy(map));
+	if (exact)
+		*exact = check_exactness_omega(map, app);
+
+	isl_map_free(map);
+	return app;
+}
+
+/* Compute an overapproximation of the transitive closure of "map"
+ * using a variation of the algorithm from
+ * "Transitive Closure of Infinite Graphs and its Applications"
+ * by Kelly et al.
+ *
+ * We first check whether we can can split of any basic map M_i and
+ * compute
+ *
+ *	(\cup_j M_j)^+
+ *
+ * as
+ *
+ *	M_i \cup (\cup_{j \ne i} M_i^* \circ M_j \circ M_i^*)^+
+ *
+ * using a recursive call on the remaining map.
+ *
+ * If not, we simply call box_closure on the whole map.
+ */
+static __isl_give isl_map *transitive_closure_omega(__isl_take isl_map *map,
+	int *exact)
+{
+	int i, j;
+	int exact_i;
+	isl_map *app;
+
+	if (!map)
+		return NULL;
+	if (map->n == 1)
+		return box_closure_with_check(map, exact);
+
+	for (i = 0; i < map->n; ++i) {
+		int ok;
+		isl_map *qc, *tc;
+		ok = can_be_split_off(map, i, &tc, &qc);
+		if (ok < 0)
+			goto error;
+		if (!ok)
+			continue;
+
+		app = isl_map_alloc_space(isl_map_get_space(map), map->n - 1, 0);
+
+		for (j = 0; j < map->n; ++j) {
+			if (j == i)
+				continue;
+			app = isl_map_add_basic_map(app,
+						isl_basic_map_copy(map->p[j]));
+		}
+
+		app = isl_map_apply_range(isl_map_copy(qc), app);
+		app = isl_map_apply_range(app, qc);
+
+		app = isl_map_union(tc, transitive_closure_omega(app, NULL));
+		exact_i = check_exactness_omega(map, app);
+		if (exact_i == 1) {
+			if (exact)
+				*exact = exact_i;
+			isl_map_free(map);
+			return app;
+		}
+		isl_map_free(app);
+		if (exact_i < 0)
+			goto error;
+	}
+
+	return box_closure_with_check(map, exact);
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Compute the transitive closure  of "map", or an overapproximation.
+ * If the result is exact, then *exact is set to 1.
+ * Simply use map_power to compute the powers of map, but tell
+ * it to project out the lengths of the paths instead of equating
+ * the length to a parameter.
+ */
+__isl_give isl_map *isl_map_transitive_closure(__isl_take isl_map *map,
+	int *exact)
+{
+	isl_space *target_dim;
+	int closed;
+
+	if (!map)
+		goto error;
+
+	if (map->ctx->opt->closure == ISL_CLOSURE_BOX)
+		return transitive_closure_omega(map, exact);
+
+	map = isl_map_compute_divs(map);
+	map = isl_map_coalesce(map);
+	closed = isl_map_is_transitively_closed(map);
+	if (closed < 0)
+		goto error;
+	if (closed) {
+		if (exact)
+			*exact = 1;
+		return map;
+	}
+
+	target_dim = isl_map_get_space(map);
+	map = map_power(map, exact, 1);
+	map = isl_map_reset_space(map, target_dim);
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+static isl_stat inc_count(__isl_take isl_map *map, void *user)
+{
+	int *n = user;
+
+	*n += map->n;
+
+	isl_map_free(map);
+
+	return isl_stat_ok;
+}
+
+static isl_stat collect_basic_map(__isl_take isl_map *map, void *user)
+{
+	int i;
+	isl_basic_map ***next = user;
+
+	for (i = 0; i < map->n; ++i) {
+		**next = isl_basic_map_copy(map->p[i]);
+		if (!**next)
+			goto error;
+		(*next)++;
+	}
+
+	isl_map_free(map);
+	return isl_stat_ok;
+error:
+	isl_map_free(map);
+	return isl_stat_error;
+}
+
+/* Perform Floyd-Warshall on the given list of basic relations.
+ * The basic relations may live in different dimensions,
+ * but basic relations that get assigned to the diagonal of the
+ * grid have domains and ranges of the same dimension and so
+ * the standard algorithm can be used because the nested transitive
+ * closures are only applied to diagonal elements and because all
+ * compositions are peformed on relations with compatible domains and ranges.
+ */
+static __isl_give isl_union_map *union_floyd_warshall_on_list(isl_ctx *ctx,
+	__isl_keep isl_basic_map **list, int n, int *exact)
+{
+	int i, j, k;
+	int n_group;
+	int *group = NULL;
+	isl_set **set = NULL;
+	isl_map ***grid = NULL;
+	isl_union_map *app;
+
+	group = setup_groups(ctx, list, n, &set, &n_group);
+	if (!group)
+		goto error;
+
+	grid = isl_calloc_array(ctx, isl_map **, n_group);
+	if (!grid)
+		goto error;
+	for (i = 0; i < n_group; ++i) {
+		grid[i] = isl_calloc_array(ctx, isl_map *, n_group);
+		if (!grid[i])
+			goto error;
+		for (j = 0; j < n_group; ++j) {
+			isl_space *dim1, *dim2, *dim;
+			dim1 = isl_space_reverse(isl_set_get_space(set[i]));
+			dim2 = isl_set_get_space(set[j]);
+			dim = isl_space_join(dim1, dim2);
+			grid[i][j] = isl_map_empty(dim);
+		}
+	}
+
+	for (k = 0; k < n; ++k) {
+		i = group[2 * k];
+		j = group[2 * k + 1];
+		grid[i][j] = isl_map_union(grid[i][j],
+				isl_map_from_basic_map(
+					isl_basic_map_copy(list[k])));
+	}
+	
+	floyd_warshall_iterate(grid, n_group, exact);
+
+	app = isl_union_map_empty(isl_map_get_space(grid[0][0]));
+
+	for (i = 0; i < n_group; ++i) {
+		for (j = 0; j < n_group; ++j)
+			app = isl_union_map_add_map(app, grid[i][j]);
+		free(grid[i]);
+	}
+	free(grid);
+
+	for (i = 0; i < 2 * n; ++i)
+		isl_set_free(set[i]);
+	free(set);
+
+	free(group);
+	return app;
+error:
+	if (grid)
+		for (i = 0; i < n_group; ++i) {
+			if (!grid[i])
+				continue;
+			for (j = 0; j < n_group; ++j)
+				isl_map_free(grid[i][j]);
+			free(grid[i]);
+		}
+	free(grid);
+	if (set) {
+		for (i = 0; i < 2 * n; ++i)
+			isl_set_free(set[i]);
+		free(set);
+	}
+	free(group);
+	return NULL;
+}
+
+/* Perform Floyd-Warshall on the given union relation.
+ * The implementation is very similar to that for non-unions.
+ * The main difference is that it is applied unconditionally.
+ * We first extract a list of basic maps from the union map
+ * and then perform the algorithm on this list.
+ */
+static __isl_give isl_union_map *union_floyd_warshall(
+	__isl_take isl_union_map *umap, int *exact)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_basic_map **list = NULL;
+	isl_basic_map **next;
+	isl_union_map *res;
+
+	n = 0;
+	if (isl_union_map_foreach_map(umap, inc_count, &n) < 0)
+		goto error;
+
+	ctx = isl_union_map_get_ctx(umap);
+	list = isl_calloc_array(ctx, isl_basic_map *, n);
+	if (!list)
+		goto error;
+
+	next = list;
+	if (isl_union_map_foreach_map(umap, collect_basic_map, &next) < 0)
+		goto error;
+
+	res = union_floyd_warshall_on_list(ctx, list, n, exact);
+
+	if (list) {
+		for (i = 0; i < n; ++i)
+			isl_basic_map_free(list[i]);
+		free(list);
+	}
+
+	isl_union_map_free(umap);
+	return res;
+error:
+	if (list) {
+		for (i = 0; i < n; ++i)
+			isl_basic_map_free(list[i]);
+		free(list);
+	}
+	isl_union_map_free(umap);
+	return NULL;
+}
+
+/* Decompose the give union relation into strongly connected components.
+ * The implementation is essentially the same as that of
+ * construct_power_components with the major difference that all
+ * operations are performed on union maps.
+ */
+static __isl_give isl_union_map *union_components(
+	__isl_take isl_union_map *umap, int *exact)
+{
+	int i;
+	int n;
+	isl_ctx *ctx;
+	isl_basic_map **list = NULL;
+	isl_basic_map **next;
+	isl_union_map *path = NULL;
+	struct isl_tc_follows_data data;
+	struct isl_tarjan_graph *g = NULL;
+	int c, l;
+	int recheck = 0;
+
+	n = 0;
+	if (isl_union_map_foreach_map(umap, inc_count, &n) < 0)
+		goto error;
+
+	if (n == 0)
+		return umap;
+	if (n <= 1)
+		return union_floyd_warshall(umap, exact);
+
+	ctx = isl_union_map_get_ctx(umap);
+	list = isl_calloc_array(ctx, isl_basic_map *, n);
+	if (!list)
+		goto error;
+
+	next = list;
+	if (isl_union_map_foreach_map(umap, collect_basic_map, &next) < 0)
+		goto error;
+
+	data.list = list;
+	data.check_closed = 0;
+	g = isl_tarjan_graph_init(ctx, n, &basic_map_follows, &data);
+	if (!g)
+		goto error;
+
+	c = 0;
+	i = 0;
+	l = n;
+	path = isl_union_map_empty(isl_union_map_get_space(umap));
+	while (l) {
+		isl_union_map *comp;
+		isl_union_map *path_comp, *path_comb;
+		comp = isl_union_map_empty(isl_union_map_get_space(umap));
+		while (g->order[i] != -1) {
+			comp = isl_union_map_add_map(comp,
+				    isl_map_from_basic_map(
+					isl_basic_map_copy(list[g->order[i]])));
+			--l;
+			++i;
+		}
+		path_comp = union_floyd_warshall(comp, exact);
+		path_comb = isl_union_map_apply_range(isl_union_map_copy(path),
+						isl_union_map_copy(path_comp));
+		path = isl_union_map_union(path, path_comp);
+		path = isl_union_map_union(path, path_comb);
+		++i;
+		++c;
+	}
+
+	if (c > 1 && data.check_closed && !*exact) {
+		int closed;
+
+		closed = isl_union_map_is_transitively_closed(path);
+		if (closed < 0)
+			goto error;
+		recheck = !closed;
+	}
+
+	isl_tarjan_graph_free(g);
+
+	for (i = 0; i < n; ++i)
+		isl_basic_map_free(list[i]);
+	free(list);
+
+	if (recheck) {
+		isl_union_map_free(path);
+		return union_floyd_warshall(umap, exact);
+	}
+
+	isl_union_map_free(umap);
+
+	return path;
+error:
+	isl_tarjan_graph_free(g);
+	if (list) {
+		for (i = 0; i < n; ++i)
+			isl_basic_map_free(list[i]);
+		free(list);
+	}
+	isl_union_map_free(umap);
+	isl_union_map_free(path);
+	return NULL;
+}
+
+/* Compute the transitive closure  of "umap", or an overapproximation.
+ * If the result is exact, then *exact is set to 1.
+ */
+__isl_give isl_union_map *isl_union_map_transitive_closure(
+	__isl_take isl_union_map *umap, int *exact)
+{
+	int closed;
+
+	if (!umap)
+		return NULL;
+
+	if (exact)
+		*exact = 1;
+
+	umap = isl_union_map_compute_divs(umap);
+	umap = isl_union_map_coalesce(umap);
+	closed = isl_union_map_is_transitively_closed(umap);
+	if (closed < 0)
+		goto error;
+	if (closed)
+		return umap;
+	umap = union_components(umap, exact);
+	return umap;
+error:
+	isl_union_map_free(umap);
+	return NULL;
+}
+
+struct isl_union_power {
+	isl_union_map *pow;
+	int *exact;
+};
+
+static isl_stat power(__isl_take isl_map *map, void *user)
+{
+	struct isl_union_power *up = user;
+
+	map = isl_map_power(map, up->exact);
+	up->pow = isl_union_map_from_map(map);
+
+	return isl_stat_error;
+}
+
+/* Construct a map [x] -> [x+1], with parameters prescribed by "dim".
+ */
+static __isl_give isl_union_map *increment(__isl_take isl_space *dim)
+{
+	int k;
+	isl_basic_map *bmap;
+
+	dim = isl_space_add_dims(dim, isl_dim_in, 1);
+	dim = isl_space_add_dims(dim, isl_dim_out, 1);
+	bmap = isl_basic_map_alloc_space(dim, 0, 1, 0);
+	k = isl_basic_map_alloc_equality(bmap);
+	if (k < 0)
+		goto error;
+	isl_seq_clr(bmap->eq[k], isl_basic_map_total_dim(bmap));
+	isl_int_set_si(bmap->eq[k][0], 1);
+	isl_int_set_si(bmap->eq[k][isl_basic_map_offset(bmap, isl_dim_in)], 1);
+	isl_int_set_si(bmap->eq[k][isl_basic_map_offset(bmap, isl_dim_out)], -1);
+	return isl_union_map_from_map(isl_map_from_basic_map(bmap));
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Construct a map [[x]->[y]] -> [y-x], with parameters prescribed by "dim".
+ */
+static __isl_give isl_union_map *deltas_map(__isl_take isl_space *dim)
+{
+	isl_basic_map *bmap;
+
+	dim = isl_space_add_dims(dim, isl_dim_in, 1);
+	dim = isl_space_add_dims(dim, isl_dim_out, 1);
+	bmap = isl_basic_map_universe(dim);
+	bmap = isl_basic_map_deltas_map(bmap);
+
+	return isl_union_map_from_map(isl_map_from_basic_map(bmap));
+}
+
+/* Compute the positive powers of "map", or an overapproximation.
+ * The result maps the exponent to a nested copy of the corresponding power.
+ * If the result is exact, then *exact is set to 1.
+ */
+__isl_give isl_union_map *isl_union_map_power(__isl_take isl_union_map *umap,
+	int *exact)
+{
+	int n;
+	isl_union_map *inc;
+	isl_union_map *dm;
+
+	if (!umap)
+		return NULL;
+	n = isl_union_map_n_map(umap);
+	if (n == 0)
+		return umap;
+	if (n == 1) {
+		struct isl_union_power up = { NULL, exact };
+		isl_union_map_foreach_map(umap, &power, &up);
+		isl_union_map_free(umap);
+		return up.pow;
+	}
+	inc = increment(isl_union_map_get_space(umap));
+	umap = isl_union_map_product(inc, umap);
+	umap = isl_union_map_transitive_closure(umap, exact);
+	umap = isl_union_map_zip(umap);
+	dm = deltas_map(isl_union_map_get_space(umap));
+	umap = isl_union_map_apply_domain(umap, dm);
+	
+	return umap;
+}
+
+#undef TYPE
+#define TYPE isl_map
+#include "isl_power_templ.c"
+
+#undef TYPE
+#define TYPE isl_union_map
+#include "isl_power_templ.c"
diff --git a/final/lib/External/isl/isl_union_eval.c b/final/lib/External/isl/isl_union_eval.c
new file mode 100644
index 0000000..3daab3f
--- /dev/null
+++ b/final/lib/External/isl/isl_union_eval.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ */
+
+#include <isl_union_macro.h>
+
+/* Is the domain space of "entry" equal to "space"?
+ */
+static int FN(UNION,has_domain_space)(const void *entry, const void *val)
+{
+	PART *part = (PART *)entry;
+	isl_space *space = (isl_space *) val;
+
+	if (isl_space_is_params(space))
+		return isl_space_is_set(part->dim);
+
+	return isl_space_tuple_is_equal(part->dim, isl_dim_in,
+					space, isl_dim_set);
+}
+
+__isl_give isl_val *FN(UNION,eval)(__isl_take UNION *u,
+	__isl_take isl_point *pnt)
+{
+	uint32_t hash;
+	struct isl_hash_table_entry *entry;
+	isl_space *space;
+	isl_val *v;
+
+	if (!u || !pnt)
+		goto error;
+
+	space = isl_space_copy(pnt->dim);
+	if (!space)
+		goto error;
+	hash = isl_space_get_hash(space);
+	entry = isl_hash_table_find(u->space->ctx, &u->table,
+				    hash, &FN(UNION,has_domain_space),
+				    space, 0);
+	isl_space_free(space);
+	if (!entry) {
+		v = isl_val_zero(isl_point_get_ctx(pnt));
+		isl_point_free(pnt);
+	} else {
+		v = FN(PART,eval)(FN(PART,copy)(entry->data), pnt);
+	}
+	FN(UNION,free)(u);
+	return v;
+error:
+	FN(UNION,free)(u);
+	isl_point_free(pnt);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_union_macro.h b/final/lib/External/isl/isl_union_macro.h
new file mode 100644
index 0000000..f445df6
--- /dev/null
+++ b/final/lib/External/isl/isl_union_macro.h
@@ -0,0 +1,4 @@
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xS(TYPE,NAME) struct TYPE ## _ ## NAME
+#define S(TYPE,NAME) xS(TYPE,NAME)
diff --git a/final/lib/External/isl/isl_union_map.c b/final/lib/External/isl/isl_union_map.c
new file mode 100644
index 0000000..a5ae135
--- /dev/null
+++ b/final/lib/External/isl/isl_union_map.c
@@ -0,0 +1,3883 @@
+/*
+ * Copyright 2010-2011 INRIA Saclay
+ * Copyright 2013-2014 Ecole Normale Superieure
+ * Copyright 2014      INRIA Rocquencourt
+ * Copyright 2016-2017 Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France 
+ * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
+ * B.P. 105 - 78153 Le Chesnay, France
+ */
+
+#define ISL_DIM_H
+#include <isl_map_private.h>
+#include <isl_union_map_private.h>
+#include <isl/ctx.h>
+#include <isl/hash.h>
+#include <isl/aff.h>
+#include <isl/map.h>
+#include <isl/set.h>
+#include <isl_space_private.h>
+#include <isl/union_set.h>
+#include <isl_maybe_map.h>
+#include <isl/deprecated/union_map_int.h>
+
+#include <bset_from_bmap.c>
+#include <set_to_map.c>
+#include <set_from_map.c>
+
+/* Return the number of parameters of "umap", where "type"
+ * is required to be set to isl_dim_param.
+ */
+unsigned isl_union_map_dim(__isl_keep isl_union_map *umap,
+	enum isl_dim_type type)
+{
+	if (!umap)
+		return 0;
+
+	if (type != isl_dim_param)
+		isl_die(isl_union_map_get_ctx(umap), isl_error_invalid,
+			"can only reference parameters", return 0);
+
+	return isl_space_dim(umap->dim, type);
+}
+
+/* Return the number of parameters of "uset", where "type"
+ * is required to be set to isl_dim_param.
+ */
+unsigned isl_union_set_dim(__isl_keep isl_union_set *uset,
+	enum isl_dim_type type)
+{
+	return isl_union_map_dim(uset, type);
+}
+
+/* Return the id of the specified dimension.
+ */
+__isl_give isl_id *isl_union_map_get_dim_id(__isl_keep isl_union_map *umap,
+	enum isl_dim_type type, unsigned pos)
+{
+	if (!umap)
+		return NULL;
+
+	if (type != isl_dim_param)
+		isl_die(isl_union_map_get_ctx(umap), isl_error_invalid,
+			"can only reference parameters", return NULL);
+
+	return isl_space_get_dim_id(umap->dim, type, pos);
+}
+
+/* Is this union set a parameter domain?
+ */
+isl_bool isl_union_set_is_params(__isl_keep isl_union_set *uset)
+{
+	isl_set *set;
+	isl_bool params;
+
+	if (!uset)
+		return isl_bool_error;
+	if (uset->table.n != 1)
+		return isl_bool_false;
+
+	set = isl_set_from_union_set(isl_union_set_copy(uset));
+	params = isl_set_is_params(set);
+	isl_set_free(set);
+	return params;
+}
+
+static __isl_give isl_union_map *isl_union_map_alloc(
+	__isl_take isl_space *space, int size)
+{
+	isl_union_map *umap;
+
+	space = isl_space_params(space);
+	if (!space)
+		return NULL;
+
+	umap = isl_calloc_type(space->ctx, isl_union_map);
+	if (!umap) {
+		isl_space_free(space);
+		return NULL;
+	}
+
+	umap->ref = 1;
+	umap->dim = space;
+	if (isl_hash_table_init(space->ctx, &umap->table, size) < 0)
+		return isl_union_map_free(umap);
+
+	return umap;
+}
+
+__isl_give isl_union_map *isl_union_map_empty(__isl_take isl_space *dim)
+{
+	return isl_union_map_alloc(dim, 16);
+}
+
+__isl_give isl_union_set *isl_union_set_empty(__isl_take isl_space *dim)
+{
+	return isl_union_map_empty(dim);
+}
+
+isl_ctx *isl_union_map_get_ctx(__isl_keep isl_union_map *umap)
+{
+	return umap ? umap->dim->ctx : NULL;
+}
+
+isl_ctx *isl_union_set_get_ctx(__isl_keep isl_union_set *uset)
+{
+	return uset ? uset->dim->ctx : NULL;
+}
+
+/* Return the space of "umap".
+ */
+__isl_keep isl_space *isl_union_map_peek_space(__isl_keep isl_union_map *umap)
+{
+	return umap ? umap->dim : NULL;
+}
+
+__isl_give isl_space *isl_union_map_get_space(__isl_keep isl_union_map *umap)
+{
+	return isl_space_copy(isl_union_map_peek_space(umap));
+}
+
+/* Return the position of the parameter with the given name
+ * in "umap".
+ * Return -1 if no such dimension can be found.
+ */
+int isl_union_map_find_dim_by_name(__isl_keep isl_union_map *umap,
+	enum isl_dim_type type, const char *name)
+{
+	if (!umap)
+		return -1;
+	return isl_space_find_dim_by_name(umap->dim, type, name);
+}
+
+__isl_give isl_space *isl_union_set_get_space(__isl_keep isl_union_set *uset)
+{
+	return isl_union_map_get_space(uset);
+}
+
+static isl_stat free_umap_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_map_free(map);
+	return isl_stat_ok;
+}
+
+static isl_stat add_map(__isl_take isl_map *map, void *user)
+{
+	isl_union_map **umap = (isl_union_map **)user;
+
+	*umap = isl_union_map_add_map(*umap, map);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_dup(__isl_keep isl_union_map *umap)
+{
+	isl_union_map *dup;
+
+	if (!umap)
+		return NULL;
+
+	dup = isl_union_map_empty(isl_space_copy(umap->dim));
+	if (isl_union_map_foreach_map(umap, &add_map, &dup) < 0)
+		goto error;
+	return dup;
+error:
+	isl_union_map_free(dup);
+	return NULL;
+}
+
+__isl_give isl_union_map *isl_union_map_cow(__isl_take isl_union_map *umap)
+{
+	if (!umap)
+		return NULL;
+
+	if (umap->ref == 1)
+		return umap;
+	umap->ref--;
+	return isl_union_map_dup(umap);
+}
+
+struct isl_union_align {
+	isl_reordering *exp;
+	isl_union_map *res;
+};
+
+static isl_stat align_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_reordering *exp;
+	struct isl_union_align *data = user;
+
+	exp = isl_reordering_extend_space(isl_reordering_copy(data->exp),
+				    isl_map_get_space(map));
+
+	data->res = isl_union_map_add_map(data->res,
+					isl_map_realign(isl_map_copy(map), exp));
+
+	return isl_stat_ok;
+}
+
+/* Align the parameters of umap along those of model.
+ * The result has the parameters of model first, in the same order
+ * as they appear in model, followed by any remaining parameters of
+ * umap that do not appear in model.
+ */
+__isl_give isl_union_map *isl_union_map_align_params(
+	__isl_take isl_union_map *umap, __isl_take isl_space *model)
+{
+	struct isl_union_align data = { NULL, NULL };
+	isl_bool equal_params;
+
+	if (!umap || !model)
+		goto error;
+
+	equal_params = isl_space_has_equal_params(umap->dim, model);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params) {
+		isl_space_free(model);
+		return umap;
+	}
+
+	model = isl_space_params(model);
+	data.exp = isl_parameter_alignment_reordering(umap->dim, model);
+	if (!data.exp)
+		goto error;
+
+	data.res = isl_union_map_alloc(isl_space_copy(data.exp->dim),
+					umap->table.n);
+	if (isl_hash_table_foreach(umap->dim->ctx, &umap->table,
+					&align_entry, &data) < 0)
+		goto error;
+
+	isl_reordering_free(data.exp);
+	isl_union_map_free(umap);
+	isl_space_free(model);
+	return data.res;
+error:
+	isl_reordering_free(data.exp);
+	isl_union_map_free(umap);
+	isl_union_map_free(data.res);
+	isl_space_free(model);
+	return NULL;
+}
+
+__isl_give isl_union_set *isl_union_set_align_params(
+	__isl_take isl_union_set *uset, __isl_take isl_space *model)
+{
+	return isl_union_map_align_params(uset, model);
+}
+
+__isl_give isl_union_map *isl_union_map_union(__isl_take isl_union_map *umap1,
+	__isl_take isl_union_map *umap2)
+{
+	umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2));
+	umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1));
+
+	umap1 = isl_union_map_cow(umap1);
+
+	if (!umap1 || !umap2)
+		goto error;
+
+	if (isl_union_map_foreach_map(umap2, &add_map, &umap1) < 0)
+		goto error;
+
+	isl_union_map_free(umap2);
+
+	return umap1;
+error:
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+	return NULL;
+}
+
+__isl_give isl_union_set *isl_union_set_union(__isl_take isl_union_set *uset1,
+	__isl_take isl_union_set *uset2)
+{
+	return isl_union_map_union(uset1, uset2);
+}
+
+__isl_give isl_union_map *isl_union_map_copy(__isl_keep isl_union_map *umap)
+{
+	if (!umap)
+		return NULL;
+
+	umap->ref++;
+	return umap;
+}
+
+__isl_give isl_union_set *isl_union_set_copy(__isl_keep isl_union_set *uset)
+{
+	return isl_union_map_copy(uset);
+}
+
+__isl_null isl_union_map *isl_union_map_free(__isl_take isl_union_map *umap)
+{
+	if (!umap)
+		return NULL;
+
+	if (--umap->ref > 0)
+		return NULL;
+
+	isl_hash_table_foreach(umap->dim->ctx, &umap->table,
+			       &free_umap_entry, NULL);
+	isl_hash_table_clear(&umap->table);
+	isl_space_free(umap->dim);
+	free(umap);
+	return NULL;
+}
+
+__isl_null isl_union_set *isl_union_set_free(__isl_take isl_union_set *uset)
+{
+	return isl_union_map_free(uset);
+}
+
+/* Do "umap" and "space" have the same parameters?
+ */
+isl_bool isl_union_map_space_has_equal_params(__isl_keep isl_union_map *umap,
+	__isl_keep isl_space *space)
+{
+	isl_space *umap_space;
+
+	umap_space = isl_union_map_peek_space(umap);
+	return isl_space_has_equal_params(umap_space, space);
+}
+
+static int has_space(const void *entry, const void *val)
+{
+	isl_map *map = (isl_map *)entry;
+	isl_space *space = (isl_space *) val;
+
+	return isl_space_is_equal(map->dim, space);
+}
+
+__isl_give isl_union_map *isl_union_map_add_map(__isl_take isl_union_map *umap,
+	__isl_take isl_map *map)
+{
+	uint32_t hash;
+	struct isl_hash_table_entry *entry;
+	isl_bool aligned;
+
+	if (!map || !umap)
+		goto error;
+
+	if (isl_map_plain_is_empty(map)) {
+		isl_map_free(map);
+		return umap;
+	}
+
+	aligned = isl_map_space_has_equal_params(map, umap->dim);
+	if (aligned < 0)
+		goto error;
+	if (!aligned) {
+		umap = isl_union_map_align_params(umap, isl_map_get_space(map));
+		map = isl_map_align_params(map, isl_union_map_get_space(umap));
+	}
+
+	umap = isl_union_map_cow(umap);
+
+	if (!map || !umap)
+		goto error;
+
+	hash = isl_space_get_hash(map->dim);
+	entry = isl_hash_table_find(umap->dim->ctx, &umap->table, hash,
+				    &has_space, map->dim, 1);
+	if (!entry)
+		goto error;
+
+	if (!entry->data)
+		entry->data = map;
+	else {
+		entry->data = isl_map_union(entry->data, isl_map_copy(map));
+		if (!entry->data)
+			goto error;
+		isl_map_free(map);
+	}
+
+	return umap;
+error:
+	isl_map_free(map);
+	isl_union_map_free(umap);
+	return NULL;
+}
+
+__isl_give isl_union_set *isl_union_set_add_set(__isl_take isl_union_set *uset,
+	__isl_take isl_set *set)
+{
+	return isl_union_map_add_map(uset, set_to_map(set));
+}
+
+__isl_give isl_union_map *isl_union_map_from_map(__isl_take isl_map *map)
+{
+	isl_space *dim;
+	isl_union_map *umap;
+
+	if (!map)
+		return NULL;
+
+	dim = isl_map_get_space(map);
+	dim = isl_space_params(dim);
+	umap = isl_union_map_empty(dim);
+	umap = isl_union_map_add_map(umap, map);
+
+	return umap;
+}
+
+__isl_give isl_union_set *isl_union_set_from_set(__isl_take isl_set *set)
+{
+	return isl_union_map_from_map(set_to_map(set));
+}
+
+__isl_give isl_union_map *isl_union_map_from_basic_map(
+	__isl_take isl_basic_map *bmap)
+{
+	return isl_union_map_from_map(isl_map_from_basic_map(bmap));
+}
+
+__isl_give isl_union_set *isl_union_set_from_basic_set(
+	__isl_take isl_basic_set *bset)
+{
+	return isl_union_map_from_basic_map(bset);
+}
+
+struct isl_union_map_foreach_data
+{
+	isl_stat (*fn)(__isl_take isl_map *map, void *user);
+	void *user;
+};
+
+static isl_stat call_on_copy(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	struct isl_union_map_foreach_data *data;
+	data = (struct isl_union_map_foreach_data *)user;
+
+	return data->fn(isl_map_copy(map), data->user);
+}
+
+int isl_union_map_n_map(__isl_keep isl_union_map *umap)
+{
+	return umap ? umap->table.n : 0;
+}
+
+int isl_union_set_n_set(__isl_keep isl_union_set *uset)
+{
+	return uset ? uset->table.n : 0;
+}
+
+isl_stat isl_union_map_foreach_map(__isl_keep isl_union_map *umap,
+	isl_stat (*fn)(__isl_take isl_map *map, void *user), void *user)
+{
+	struct isl_union_map_foreach_data data = { fn, user };
+
+	if (!umap)
+		return isl_stat_error;
+
+	return isl_hash_table_foreach(umap->dim->ctx, &umap->table,
+				      &call_on_copy, &data);
+}
+
+static isl_stat copy_map(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_map **map_p = user;
+
+	*map_p = isl_map_copy(map);
+
+	return isl_stat_error;
+}
+
+__isl_give isl_map *isl_map_from_union_map(__isl_take isl_union_map *umap)
+{
+	isl_ctx *ctx;
+	isl_map *map = NULL;
+
+	if (!umap)
+		return NULL;
+	ctx = isl_union_map_get_ctx(umap);
+	if (umap->table.n != 1)
+		isl_die(ctx, isl_error_invalid,
+			"union map needs to contain elements in exactly "
+			"one space", goto error);
+
+	isl_hash_table_foreach(ctx, &umap->table, &copy_map, &map);
+
+	isl_union_map_free(umap);
+
+	return map;
+error:
+	isl_union_map_free(umap);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_from_union_set(__isl_take isl_union_set *uset)
+{
+	return isl_map_from_union_map(uset);
+}
+
+/* Extract the map in "umap" that lives in the given space (ignoring
+ * parameters).
+ */
+__isl_give isl_map *isl_union_map_extract_map(__isl_keep isl_union_map *umap,
+	__isl_take isl_space *space)
+{
+	uint32_t hash;
+	struct isl_hash_table_entry *entry;
+
+	space = isl_space_drop_dims(space, isl_dim_param,
+					0, isl_space_dim(space, isl_dim_param));
+	space = isl_space_align_params(space, isl_union_map_get_space(umap));
+	if (!umap || !space)
+		goto error;
+
+	hash = isl_space_get_hash(space);
+	entry = isl_hash_table_find(umap->dim->ctx, &umap->table, hash,
+				    &has_space, space, 0);
+	if (!entry)
+		return isl_map_empty(space);
+	isl_space_free(space);
+	return isl_map_copy(entry->data);
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+__isl_give isl_set *isl_union_set_extract_set(__isl_keep isl_union_set *uset,
+	__isl_take isl_space *dim)
+{
+	return set_from_map(isl_union_map_extract_map(uset, dim));
+}
+
+/* Check if umap contains a map in the given space.
+ */
+isl_bool isl_union_map_contains(__isl_keep isl_union_map *umap,
+	__isl_keep isl_space *space)
+{
+	uint32_t hash;
+	struct isl_hash_table_entry *entry;
+
+	if (!umap || !space)
+		return isl_bool_error;
+
+	hash = isl_space_get_hash(space);
+	entry = isl_hash_table_find(umap->dim->ctx, &umap->table, hash,
+				    &has_space, space, 0);
+	return !!entry;
+}
+
+isl_bool isl_union_set_contains(__isl_keep isl_union_set *uset,
+	__isl_keep isl_space *space)
+{
+	return isl_union_map_contains(uset, space);
+}
+
+isl_stat isl_union_set_foreach_set(__isl_keep isl_union_set *uset,
+	isl_stat (*fn)(__isl_take isl_set *set, void *user), void *user)
+{
+	return isl_union_map_foreach_map(uset,
+		(isl_stat(*)(__isl_take isl_map *, void*))fn, user);
+}
+
+struct isl_union_set_foreach_point_data {
+	isl_stat (*fn)(__isl_take isl_point *pnt, void *user);
+	void *user;
+};
+
+static isl_stat foreach_point(__isl_take isl_set *set, void *user)
+{
+	struct isl_union_set_foreach_point_data *data = user;
+	isl_stat r;
+
+	r = isl_set_foreach_point(set, data->fn, data->user);
+	isl_set_free(set);
+
+	return r;
+}
+
+isl_stat isl_union_set_foreach_point(__isl_keep isl_union_set *uset,
+	isl_stat (*fn)(__isl_take isl_point *pnt, void *user), void *user)
+{
+	struct isl_union_set_foreach_point_data data = { fn, user };
+	return isl_union_set_foreach_set(uset, &foreach_point, &data);
+}
+
+/* Data structure that specifies how gen_bin_op should
+ * construct results from the inputs.
+ *
+ * If "subtract" is set, then a map in the first input is copied to the result
+ * if there is no corresponding map in the second input.
+ * Otherwise, a map in the first input with no corresponding map
+ * in the second input is ignored.
+ * If "filter" is not NULL, then it specifies which maps in the first
+ * input may have a matching map in the second input.
+ * In particular, it makes sure that "match_space" can be called
+ * on the space of the map.
+ * "match_space" specifies how to transform the space of a map
+ * in the first input to the space of the corresponding map
+ * in the second input.
+ * "fn_map" specifies how the matching maps, one from each input,
+ * should be combined to form a map in the result.
+ */
+struct isl_bin_op_control {
+	int subtract;
+	isl_bool (*filter)(__isl_keep isl_map *map);
+	__isl_give isl_space *(*match_space)(__isl_take isl_space *space);
+	__isl_give isl_map *(*fn_map)(__isl_take isl_map *map1,
+		__isl_take isl_map *map2);
+};
+
+/* Internal data structure for gen_bin_op.
+ * "control" specifies how the maps in the result should be constructed.
+ * "umap2" is a pointer to the second argument.
+ * "res" collects the results.
+ */
+struct isl_union_map_gen_bin_data {
+	struct isl_bin_op_control *control;
+	isl_union_map *umap2;
+	isl_union_map *res;
+};
+
+/* Add a copy of "map" to "res" and return the result.
+ */
+static __isl_give isl_union_map *bin_add_map(__isl_take isl_union_map *res,
+	__isl_keep isl_map *map)
+{
+	return isl_union_map_add_map(res, isl_map_copy(map));
+}
+
+/* Combine "map1" and "map2", add the result to "res" and return the result.
+ * Check whether the result is empty before adding it to "res".
+ */
+static __isl_give isl_union_map *bin_add_pair(__isl_take isl_union_map *res,
+	__isl_keep isl_map *map1, __isl_keep isl_map *map2,
+	struct isl_union_map_gen_bin_data *data)
+{
+	isl_bool empty;
+	isl_map *map;
+
+	map = data->control->fn_map(isl_map_copy(map1), isl_map_copy(map2));
+	empty = isl_map_is_empty(map);
+	if (empty < 0 || empty) {
+		isl_map_free(map);
+		if (empty < 0)
+			return isl_union_map_free(res);
+		return res;
+	}
+	return isl_union_map_add_map(res, map);
+}
+
+/* Dummy match_space function that simply returns the input space.
+ */
+static __isl_give isl_space *identity(__isl_take isl_space *space)
+{
+	return space;
+}
+
+/* Look for the map in data->umap2 that corresponds to "map", if any.
+ * Return (isl_bool_true, matching map) if there is one,
+ * (isl_bool_false, NULL) if there is no matching map and
+ * (isl_bool_error, NULL) on error.
+ *
+ * If not NULL, then data->control->filter specifies whether "map"
+ * can have any matching map.  If so,
+ * data->control->match_space specifies which map in data->umap2
+ * corresponds to "map".
+ */
+static __isl_keep isl_maybe_isl_map bin_try_get_match(
+	struct isl_union_map_gen_bin_data *data, __isl_keep isl_map *map)
+{
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	isl_space *space;
+	isl_maybe_isl_map res = { isl_bool_error, NULL };
+
+	if (data->control->filter) {
+		res.valid = data->control->filter(map);
+		if (res.valid < 0 || !res.valid)
+			return res;
+		res.valid = isl_bool_error;
+	}
+
+	space = isl_map_get_space(map);
+	if (data->control->match_space != &identity)
+		space = data->control->match_space(space);
+	if (!space)
+		return res;
+	hash = isl_space_get_hash(space);
+	entry2 = isl_hash_table_find(isl_union_map_get_ctx(data->umap2),
+				     &data->umap2->table, hash,
+				     &has_space, space, 0);
+	isl_space_free(space);
+	res.valid = entry2 != NULL;
+	if (entry2)
+		res.value = entry2->data;
+
+	return res;
+}
+
+/* isl_hash_table_foreach callback for gen_bin_op.
+ * Look for the map in data->umap2 that corresponds
+ * to the map that "entry" points to, apply the binary operation and
+ * add the result to data->res.
+ *
+ * If no corresponding map can be found, then the effect depends
+ * on data->control->subtract.  If it is set, then the current map
+ * is added directly to the result.  Otherwise, it is ignored.
+ */
+static isl_stat gen_bin_entry(void **entry, void *user)
+{
+	struct isl_union_map_gen_bin_data *data = user;
+	isl_map *map = *entry;
+	isl_maybe_isl_map m;
+
+	m = bin_try_get_match(data, map);
+	if (m.valid < 0)
+		return isl_stat_error;
+	if (!m.valid && !data->control->subtract)
+		return isl_stat_ok;
+
+	if (!m.valid)
+		data->res = bin_add_map(data->res, map);
+	else
+		data->res = bin_add_pair(data->res, map, m.value, data);
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Apply a binary operation to "umap1" and "umap2" based on "control".
+ * Run over all maps in "umap1" and look for the corresponding map in "umap2"
+ * in gen_bin_entry.
+ */
+static __isl_give isl_union_map *gen_bin_op(__isl_take isl_union_map *umap1,
+	__isl_take isl_union_map *umap2, struct isl_bin_op_control *control)
+{
+	struct isl_union_map_gen_bin_data data = { control, NULL, NULL };
+
+	umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2));
+	umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1));
+
+	if (!umap1 || !umap2)
+		goto error;
+
+	data.umap2 = umap2;
+	data.res = isl_union_map_alloc(isl_space_copy(umap1->dim),
+				       umap1->table.n);
+	if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table,
+				   &gen_bin_entry, &data) < 0)
+		goto error;
+
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+	return data.res;
+error:
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+	isl_union_map_free(data.res);
+	return NULL;
+}
+
+__isl_give isl_union_map *isl_union_map_subtract(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)
+{
+	struct isl_bin_op_control control = {
+		.subtract = 1,
+		.match_space = &identity,
+		.fn_map = &isl_map_subtract,
+	};
+
+	return gen_bin_op(umap1, umap2, &control);
+}
+
+__isl_give isl_union_set *isl_union_set_subtract(
+	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2)
+{
+	return isl_union_map_subtract(uset1, uset2);
+}
+
+struct isl_union_map_gen_bin_set_data {
+	isl_set *set;
+	isl_union_map *res;
+};
+
+static isl_stat intersect_params_entry(void **entry, void *user)
+{
+	struct isl_union_map_gen_bin_set_data *data = user;
+	isl_map *map = *entry;
+	int empty;
+
+	map = isl_map_copy(map);
+	map = isl_map_intersect_params(map, isl_set_copy(data->set));
+
+	empty = isl_map_is_empty(map);
+	if (empty < 0) {
+		isl_map_free(map);
+		return isl_stat_error;
+	}
+
+	data->res = isl_union_map_add_map(data->res, map);
+
+	return isl_stat_ok;
+}
+
+static __isl_give isl_union_map *gen_bin_set_op(__isl_take isl_union_map *umap,
+	__isl_take isl_set *set, isl_stat (*fn)(void **, void *))
+{
+	struct isl_union_map_gen_bin_set_data data = { NULL, NULL };
+
+	umap = isl_union_map_align_params(umap, isl_set_get_space(set));
+	set = isl_set_align_params(set, isl_union_map_get_space(umap));
+
+	if (!umap || !set)
+		goto error;
+
+	data.set = set;
+	data.res = isl_union_map_alloc(isl_space_copy(umap->dim),
+				       umap->table.n);
+	if (isl_hash_table_foreach(umap->dim->ctx, &umap->table,
+				   fn, &data) < 0)
+		goto error;
+
+	isl_union_map_free(umap);
+	isl_set_free(set);
+	return data.res;
+error:
+	isl_union_map_free(umap);
+	isl_set_free(set);
+	isl_union_map_free(data.res);
+	return NULL;
+}
+
+/* Intersect "umap" with the parameter domain "set".
+ *
+ * If "set" does not have any constraints, then we can return immediately.
+ */
+__isl_give isl_union_map *isl_union_map_intersect_params(
+	__isl_take isl_union_map *umap, __isl_take isl_set *set)
+{
+	int is_universe;
+
+	is_universe = isl_set_plain_is_universe(set);
+	if (is_universe < 0)
+		goto error;
+	if (is_universe) {
+		isl_set_free(set);
+		return umap;
+	}
+
+	return gen_bin_set_op(umap, set, &intersect_params_entry);
+error:
+	isl_union_map_free(umap);
+	isl_set_free(set);
+	return NULL;
+}
+
+__isl_give isl_union_set *isl_union_set_intersect_params(
+	__isl_take isl_union_set *uset, __isl_take isl_set *set)
+{
+	return isl_union_map_intersect_params(uset, set);
+}
+
+static __isl_give isl_union_map *union_map_intersect_params(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)
+{
+	return isl_union_map_intersect_params(umap,
+						isl_set_from_union_set(uset));
+}
+
+static __isl_give isl_union_map *union_map_gist_params(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)
+{
+	return isl_union_map_gist_params(umap, isl_set_from_union_set(uset));
+}
+
+struct isl_union_map_match_bin_data {
+	isl_union_map *umap2;
+	isl_union_map *res;
+	__isl_give isl_map *(*fn)(__isl_take isl_map*, __isl_take isl_map*);
+};
+
+static isl_stat match_bin_entry(void **entry, void *user)
+{
+	struct isl_union_map_match_bin_data *data = user;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	isl_map *map = *entry;
+	int empty;
+
+	hash = isl_space_get_hash(map->dim);
+	entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table,
+				     hash, &has_space, map->dim, 0);
+	if (!entry2)
+		return isl_stat_ok;
+
+	map = isl_map_copy(map);
+	map = data->fn(map, isl_map_copy(entry2->data));
+
+	empty = isl_map_is_empty(map);
+	if (empty < 0) {
+		isl_map_free(map);
+		return isl_stat_error;
+	}
+	if (empty) {
+		isl_map_free(map);
+		return isl_stat_ok;
+	}
+
+	data->res = isl_union_map_add_map(data->res, map);
+
+	return isl_stat_ok;
+}
+
+static __isl_give isl_union_map *match_bin_op(__isl_take isl_union_map *umap1,
+	__isl_take isl_union_map *umap2,
+	__isl_give isl_map *(*fn)(__isl_take isl_map*, __isl_take isl_map*))
+{
+	struct isl_union_map_match_bin_data data = { NULL, NULL, fn };
+
+	umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2));
+	umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1));
+
+	if (!umap1 || !umap2)
+		goto error;
+
+	data.umap2 = umap2;
+	data.res = isl_union_map_alloc(isl_space_copy(umap1->dim),
+				       umap1->table.n);
+	if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table,
+				   &match_bin_entry, &data) < 0)
+		goto error;
+
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+	return data.res;
+error:
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+	isl_union_map_free(data.res);
+	return NULL;
+}
+
+__isl_give isl_union_map *isl_union_map_intersect(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)
+{
+	return match_bin_op(umap1, umap2, &isl_map_intersect);
+}
+
+/* Compute the intersection of the two union_sets.
+ * As a special case, if exactly one of the two union_sets
+ * is a parameter domain, then intersect the parameter domain
+ * of the other one with this set.
+ */
+__isl_give isl_union_set *isl_union_set_intersect(
+	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2)
+{
+	int p1, p2;
+
+	p1 = isl_union_set_is_params(uset1);
+	p2 = isl_union_set_is_params(uset2);
+	if (p1 < 0 || p2 < 0)
+		goto error;
+	if (!p1 && p2)
+		return union_map_intersect_params(uset1, uset2);
+	if (p1 && !p2)
+		return union_map_intersect_params(uset2, uset1);
+	return isl_union_map_intersect(uset1, uset2);
+error:
+	isl_union_set_free(uset1);
+	isl_union_set_free(uset2);
+	return NULL;
+}
+
+static isl_stat gist_params_entry(void **entry, void *user)
+{
+	struct isl_union_map_gen_bin_set_data *data = user;
+	isl_map *map = *entry;
+	int empty;
+
+	map = isl_map_copy(map);
+	map = isl_map_gist_params(map, isl_set_copy(data->set));
+
+	empty = isl_map_is_empty(map);
+	if (empty < 0) {
+		isl_map_free(map);
+		return isl_stat_error;
+	}
+
+	data->res = isl_union_map_add_map(data->res, map);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_gist_params(
+	__isl_take isl_union_map *umap, __isl_take isl_set *set)
+{
+	return gen_bin_set_op(umap, set, &gist_params_entry);
+}
+
+__isl_give isl_union_set *isl_union_set_gist_params(
+	__isl_take isl_union_set *uset, __isl_take isl_set *set)
+{
+	return isl_union_map_gist_params(uset, set);
+}
+
+__isl_give isl_union_map *isl_union_map_gist(__isl_take isl_union_map *umap,
+	__isl_take isl_union_map *context)
+{
+	return match_bin_op(umap, context, &isl_map_gist);
+}
+
+__isl_give isl_union_set *isl_union_set_gist(__isl_take isl_union_set *uset,
+	__isl_take isl_union_set *context)
+{
+	if (isl_union_set_is_params(context))
+		return union_map_gist_params(uset, context);
+	return isl_union_map_gist(uset, context);
+}
+
+/* For each map in "umap", remove the constraints in the corresponding map
+ * of "context".
+ * Each map in "context" is assumed to consist of a single disjunct and
+ * to have explicit representations for all local variables.
+ */
+__isl_give isl_union_map *isl_union_map_plain_gist(
+	__isl_take isl_union_map *umap, __isl_take isl_union_map *context)
+{
+	return match_bin_op(umap, context, &isl_map_plain_gist);
+}
+
+/* For each set in "uset", remove the constraints in the corresponding set
+ * of "context".
+ * Each set in "context" is assumed to consist of a single disjunct and
+ * to have explicit representations for all local variables.
+ */
+__isl_give isl_union_set *isl_union_set_plain_gist(
+	__isl_take isl_union_set *uset, __isl_take isl_union_set *context)
+{
+	return isl_union_map_plain_gist(uset, context);
+}
+
+static __isl_give isl_map *lex_le_set(__isl_take isl_map *set1,
+	__isl_take isl_map *set2)
+{
+	return isl_set_lex_le_set(set_from_map(set1), set_from_map(set2));
+}
+
+static __isl_give isl_map *lex_lt_set(__isl_take isl_map *set1,
+	__isl_take isl_map *set2)
+{
+	return isl_set_lex_lt_set(set_from_map(set1), set_from_map(set2));
+}
+
+__isl_give isl_union_map *isl_union_set_lex_lt_union_set(
+	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2)
+{
+	return match_bin_op(uset1, uset2, &lex_lt_set);
+}
+
+__isl_give isl_union_map *isl_union_set_lex_le_union_set(
+	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2)
+{
+	return match_bin_op(uset1, uset2, &lex_le_set);
+}
+
+__isl_give isl_union_map *isl_union_set_lex_gt_union_set(
+	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2)
+{
+	return isl_union_map_reverse(isl_union_set_lex_lt_union_set(uset2, uset1));
+}
+
+__isl_give isl_union_map *isl_union_set_lex_ge_union_set(
+	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2)
+{
+	return isl_union_map_reverse(isl_union_set_lex_le_union_set(uset2, uset1));
+}
+
+__isl_give isl_union_map *isl_union_map_lex_gt_union_map(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)
+{
+	return isl_union_map_reverse(isl_union_map_lex_lt_union_map(umap2, umap1));
+}
+
+__isl_give isl_union_map *isl_union_map_lex_ge_union_map(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)
+{
+	return isl_union_map_reverse(isl_union_map_lex_le_union_map(umap2, umap1));
+}
+
+/* Intersect the domain of "umap" with "uset".
+ */
+static __isl_give isl_union_map *union_map_intersect_domain(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)
+{
+	struct isl_bin_op_control control = {
+		.match_space = &isl_space_domain,
+		.fn_map = &isl_map_intersect_domain,
+	};
+
+	return gen_bin_op(umap, uset, &control);
+}
+
+/* Intersect the domain of "umap" with "uset".
+ * If "uset" is a parameters domain, then intersect the parameter
+ * domain of "umap" with this set.
+ */
+__isl_give isl_union_map *isl_union_map_intersect_domain(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)
+{
+	if (isl_union_set_is_params(uset))
+		return union_map_intersect_params(umap, uset);
+	else
+		return union_map_intersect_domain(umap, uset);
+}
+
+/* Remove the elements of "uset" from the domain of "umap".
+ */
+__isl_give isl_union_map *isl_union_map_subtract_domain(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *dom)
+{
+	struct isl_bin_op_control control = {
+		.subtract = 1,
+		.match_space = &isl_space_domain,
+		.fn_map = &isl_map_subtract_domain,
+	};
+
+	return gen_bin_op(umap, dom, &control);
+}
+
+/* Remove the elements of "uset" from the range of "umap".
+ */
+__isl_give isl_union_map *isl_union_map_subtract_range(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *dom)
+{
+	struct isl_bin_op_control control = {
+		.subtract = 1,
+		.match_space = &isl_space_range,
+		.fn_map = &isl_map_subtract_range,
+	};
+
+	return gen_bin_op(umap, dom, &control);
+}
+
+/* Compute the gist of "umap" with respect to the domain "uset".
+ */
+static __isl_give isl_union_map *union_map_gist_domain(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)
+{
+	struct isl_bin_op_control control = {
+		.match_space = &isl_space_domain,
+		.fn_map = &isl_map_gist_domain,
+	};
+
+	return gen_bin_op(umap, uset, &control);
+}
+
+/* Compute the gist of "umap" with respect to the domain "uset".
+ * If "uset" is a parameters domain, then compute the gist
+ * with respect to this parameter domain.
+ */
+__isl_give isl_union_map *isl_union_map_gist_domain(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)
+{
+	if (isl_union_set_is_params(uset))
+		return union_map_gist_params(umap, uset);
+	else
+		return union_map_gist_domain(umap, uset);
+}
+
+/* Compute the gist of "umap" with respect to the range "uset".
+ */
+__isl_give isl_union_map *isl_union_map_gist_range(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)
+{
+	struct isl_bin_op_control control = {
+		.match_space = &isl_space_range,
+		.fn_map = &isl_map_gist_range,
+	};
+
+	return gen_bin_op(umap, uset, &control);
+}
+
+__isl_give isl_union_map *isl_union_map_intersect_range(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)
+{
+	struct isl_bin_op_control control = {
+		.match_space = &isl_space_range,
+		.fn_map = &isl_map_intersect_range,
+	};
+
+	return gen_bin_op(umap, uset, &control);
+}
+
+/* Intersect each map in "umap" in a space A -> [B -> C]
+ * with the corresponding map in "factor" in the space A -> C and
+ * collect the results.
+ */
+__isl_give isl_union_map *isl_union_map_intersect_range_factor_range(
+	__isl_take isl_union_map *umap, __isl_take isl_union_map *factor)
+{
+	struct isl_bin_op_control control = {
+		.filter = &isl_map_range_is_wrapping,
+		.match_space = &isl_space_range_factor_range,
+		.fn_map = &isl_map_intersect_range_factor_range,
+	};
+
+	return gen_bin_op(umap, factor, &control);
+}
+
+struct isl_union_map_bin_data {
+	isl_union_map *umap2;
+	isl_union_map *res;
+	isl_map *map;
+	isl_stat (*fn)(void **entry, void *user);
+};
+
+static isl_stat apply_range_entry(void **entry, void *user)
+{
+	struct isl_union_map_bin_data *data = user;
+	isl_map *map2 = *entry;
+	isl_bool empty;
+
+	if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_out,
+				 map2->dim, isl_dim_in))
+		return isl_stat_ok;
+
+	map2 = isl_map_apply_range(isl_map_copy(data->map), isl_map_copy(map2));
+
+	empty = isl_map_is_empty(map2);
+	if (empty < 0) {
+		isl_map_free(map2);
+		return isl_stat_error;
+	}
+	if (empty) {
+		isl_map_free(map2);
+		return isl_stat_ok;
+	}
+
+	data->res = isl_union_map_add_map(data->res, map2);
+
+	return isl_stat_ok;
+}
+
+static isl_stat bin_entry(void **entry, void *user)
+{
+	struct isl_union_map_bin_data *data = user;
+	isl_map *map = *entry;
+
+	data->map = map;
+	if (isl_hash_table_foreach(data->umap2->dim->ctx, &data->umap2->table,
+				   data->fn, data) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+static __isl_give isl_union_map *bin_op(__isl_take isl_union_map *umap1,
+	__isl_take isl_union_map *umap2,
+	isl_stat (*fn)(void **entry, void *user))
+{
+	struct isl_union_map_bin_data data = { NULL, NULL, NULL, fn };
+
+	umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2));
+	umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1));
+
+	if (!umap1 || !umap2)
+		goto error;
+
+	data.umap2 = umap2;
+	data.res = isl_union_map_alloc(isl_space_copy(umap1->dim),
+				       umap1->table.n);
+	if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table,
+				   &bin_entry, &data) < 0)
+		goto error;
+
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+	return data.res;
+error:
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+	isl_union_map_free(data.res);
+	return NULL;
+}
+
+__isl_give isl_union_map *isl_union_map_apply_range(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)
+{
+	return bin_op(umap1, umap2, &apply_range_entry);
+}
+
+__isl_give isl_union_map *isl_union_map_apply_domain(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)
+{
+	umap1 = isl_union_map_reverse(umap1);
+	umap1 = isl_union_map_apply_range(umap1, umap2);
+	return isl_union_map_reverse(umap1);
+}
+
+__isl_give isl_union_set *isl_union_set_apply(
+	__isl_take isl_union_set *uset, __isl_take isl_union_map *umap)
+{
+	return isl_union_map_apply_range(uset, umap);
+}
+
+static isl_stat map_lex_lt_entry(void **entry, void *user)
+{
+	struct isl_union_map_bin_data *data = user;
+	isl_map *map2 = *entry;
+
+	if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_out,
+				 map2->dim, isl_dim_out))
+		return isl_stat_ok;
+
+	map2 = isl_map_lex_lt_map(isl_map_copy(data->map), isl_map_copy(map2));
+
+	data->res = isl_union_map_add_map(data->res, map2);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_lex_lt_union_map(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)
+{
+	return bin_op(umap1, umap2, &map_lex_lt_entry);
+}
+
+static isl_stat map_lex_le_entry(void **entry, void *user)
+{
+	struct isl_union_map_bin_data *data = user;
+	isl_map *map2 = *entry;
+
+	if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_out,
+				 map2->dim, isl_dim_out))
+		return isl_stat_ok;
+
+	map2 = isl_map_lex_le_map(isl_map_copy(data->map), isl_map_copy(map2));
+
+	data->res = isl_union_map_add_map(data->res, map2);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_lex_le_union_map(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)
+{
+	return bin_op(umap1, umap2, &map_lex_le_entry);
+}
+
+static isl_stat product_entry(void **entry, void *user)
+{
+	struct isl_union_map_bin_data *data = user;
+	isl_map *map2 = *entry;
+
+	map2 = isl_map_product(isl_map_copy(data->map), isl_map_copy(map2));
+
+	data->res = isl_union_map_add_map(data->res, map2);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_product(__isl_take isl_union_map *umap1,
+	__isl_take isl_union_map *umap2)
+{
+	return bin_op(umap1, umap2, &product_entry);
+}
+
+static isl_stat set_product_entry(void **entry, void *user)
+{
+	struct isl_union_map_bin_data *data = user;
+	isl_set *set2 = *entry;
+
+	set2 = isl_set_product(isl_set_copy(data->map), isl_set_copy(set2));
+
+	data->res = isl_union_set_add_set(data->res, set2);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_set *isl_union_set_product(__isl_take isl_union_set *uset1,
+	__isl_take isl_union_set *uset2)
+{
+	return bin_op(uset1, uset2, &set_product_entry);
+}
+
+static isl_stat domain_product_entry(void **entry, void *user)
+{
+	struct isl_union_map_bin_data *data = user;
+	isl_map *map2 = *entry;
+
+	if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_out,
+				 map2->dim, isl_dim_out))
+		return isl_stat_ok;
+
+	map2 = isl_map_domain_product(isl_map_copy(data->map),
+				     isl_map_copy(map2));
+
+	data->res = isl_union_map_add_map(data->res, map2);
+
+	return isl_stat_ok;
+}
+
+/* Given two maps A -> B and C -> D, construct a map [A -> C] -> (B * D)
+ */
+__isl_give isl_union_map *isl_union_map_domain_product(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)
+{
+	return bin_op(umap1, umap2, &domain_product_entry);
+}
+
+static isl_stat range_product_entry(void **entry, void *user)
+{
+	struct isl_union_map_bin_data *data = user;
+	isl_map *map2 = *entry;
+
+	if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_in,
+				 map2->dim, isl_dim_in))
+		return isl_stat_ok;
+
+	map2 = isl_map_range_product(isl_map_copy(data->map),
+				     isl_map_copy(map2));
+
+	data->res = isl_union_map_add_map(data->res, map2);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_range_product(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)
+{
+	return bin_op(umap1, umap2, &range_product_entry);
+}
+
+/* If data->map A -> B and "map2" C -> D have the same range space,
+ * then add (A, C) -> (B * D) to data->res.
+ */
+static isl_stat flat_domain_product_entry(void **entry, void *user)
+{
+	struct isl_union_map_bin_data *data = user;
+	isl_map *map2 = *entry;
+
+	if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_out,
+				 map2->dim, isl_dim_out))
+		return isl_stat_ok;
+
+	map2 = isl_map_flat_domain_product(isl_map_copy(data->map),
+					  isl_map_copy(map2));
+
+	data->res = isl_union_map_add_map(data->res, map2);
+
+	return isl_stat_ok;
+}
+
+/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B * D).
+ */
+__isl_give isl_union_map *isl_union_map_flat_domain_product(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)
+{
+	return bin_op(umap1, umap2, &flat_domain_product_entry);
+}
+
+static isl_stat flat_range_product_entry(void **entry, void *user)
+{
+	struct isl_union_map_bin_data *data = user;
+	isl_map *map2 = *entry;
+
+	if (!isl_space_tuple_is_equal(data->map->dim, isl_dim_in,
+				 map2->dim, isl_dim_in))
+		return isl_stat_ok;
+
+	map2 = isl_map_flat_range_product(isl_map_copy(data->map),
+					  isl_map_copy(map2));
+
+	data->res = isl_union_map_add_map(data->res, map2);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_flat_range_product(
+	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)
+{
+	return bin_op(umap1, umap2, &flat_range_product_entry);
+}
+
+/* Data structure that specifies how un_op should modify
+ * the maps in the union map.
+ *
+ * If "inplace" is set, then the maps in the input union map
+ * are modified in place.  This means that "fn_map" should not
+ * change the meaning of the map or that the union map only
+ * has a single reference.
+ * If "total" is set, then all maps need to be modified and
+ * the results need to live in the same space.
+ * Otherwise, a new union map is constructed to store the results.
+ * If "filter" is not NULL, then only the input maps that satisfy "filter"
+ * are taken into account.  No filter can be set if "inplace" or
+ * "total" is set.
+ * "fn_map" specifies how the maps (selected by "filter")
+ * should be transformed.
+ */
+struct isl_un_op_control {
+	int inplace;
+	int total;
+	isl_bool (*filter)(__isl_keep isl_map *map);
+	__isl_give isl_map *(*fn_map)(__isl_take isl_map *map);
+};
+
+/* Internal data structure for "un_op".
+ * "control" specifies how the maps in the union map should be modified.
+ * "res" collects the results.
+ */
+struct isl_union_map_un_data {
+	struct isl_un_op_control *control;
+	isl_union_map *res;
+};
+
+/* isl_hash_table_foreach callback for un_op.
+ * Handle the map that "entry" points to.
+ *
+ * If control->filter is set, then check if this map satisfies the filter.
+ * If so (or if control->filter is not set), modify the map
+ * by calling control->fn_map and either add the result to data->res or
+ * replace the original entry by the result (if control->inplace is set).
+ */
+static isl_stat un_entry(void **entry, void *user)
+{
+	struct isl_union_map_un_data *data = user;
+	isl_map *map = *entry;
+
+	if (data->control->filter) {
+		isl_bool ok;
+
+		ok = data->control->filter(map);
+		if (ok < 0)
+			return isl_stat_error;
+		if (!ok)
+			return isl_stat_ok;
+	}
+
+	map = data->control->fn_map(isl_map_copy(map));
+	if (!map)
+		return isl_stat_error;
+	if (data->control->inplace) {
+		isl_map_free(*entry);
+		*entry = map;
+	} else {
+		data->res = isl_union_map_add_map(data->res, map);
+		if (!data->res)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Modify the maps in "umap" based on "control".
+ * If control->inplace is set, then modify the maps in "umap" in-place.
+ * Otherwise, create a new union map to hold the results.
+ * If control->total is set, then perform an inplace computation
+ * if "umap" is only referenced once.  Otherwise, create a new union map
+ * to store the results.
+ */
+static __isl_give isl_union_map *un_op(__isl_take isl_union_map *umap,
+	struct isl_un_op_control *control)
+{
+	struct isl_union_map_un_data data = { control };
+
+	if (!umap)
+		return NULL;
+	if ((control->inplace || control->total) && control->filter)
+		isl_die(isl_union_map_get_ctx(umap), isl_error_invalid,
+			"inplace/total modification cannot be filtered",
+			return isl_union_map_free(umap));
+
+	if (control->total && umap->ref == 1)
+		control->inplace = 1;
+	if (control->inplace) {
+		data.res = umap;
+	} else {
+		isl_space *space;
+
+		space = isl_union_map_get_space(umap);
+		data.res = isl_union_map_alloc(space, umap->table.n);
+	}
+	if (isl_hash_table_foreach(isl_union_map_get_ctx(umap),
+				    &umap->table, &un_entry, &data) < 0)
+		data.res = isl_union_map_free(data.res);
+
+	if (control->inplace)
+		return data.res;
+	isl_union_map_free(umap);
+	return data.res;
+}
+
+__isl_give isl_union_map *isl_union_map_from_range(
+	__isl_take isl_union_set *uset)
+{
+	struct isl_un_op_control control = {
+		.fn_map = &isl_map_from_range,
+	};
+	return un_op(uset, &control);
+}
+
+__isl_give isl_union_map *isl_union_map_from_domain(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_reverse(isl_union_map_from_range(uset));
+}
+
+__isl_give isl_union_map *isl_union_map_from_domain_and_range(
+	__isl_take isl_union_set *domain, __isl_take isl_union_set *range)
+{
+	return isl_union_map_apply_range(isl_union_map_from_domain(domain),
+				         isl_union_map_from_range(range));
+}
+
+/* Modify the maps in "umap" by applying "fn" on them.
+ * "fn" should apply to all maps in "umap" and should not modify the space.
+ */
+static __isl_give isl_union_map *total(__isl_take isl_union_map *umap,
+	__isl_give isl_map *(*fn)(__isl_take isl_map *))
+{
+	struct isl_un_op_control control = {
+		.total = 1,
+		.fn_map = fn,
+	};
+
+	return un_op(umap, &control);
+}
+
+/* Compute the affine hull of "map" and return the result as an isl_map.
+ */
+static __isl_give isl_map *isl_map_affine_hull_map(__isl_take isl_map *map)
+{
+	return isl_map_from_basic_map(isl_map_affine_hull(map));
+}
+
+__isl_give isl_union_map *isl_union_map_affine_hull(
+	__isl_take isl_union_map *umap)
+{
+	return total(umap, &isl_map_affine_hull_map);
+}
+
+__isl_give isl_union_set *isl_union_set_affine_hull(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_affine_hull(uset);
+}
+
+/* Wrapper around isl_set_combined_lineality_space
+ * that returns the combined lineality space in the form of an isl_set
+ * instead of an isl_basic_set.
+ */
+static __isl_give isl_set *combined_lineality_space(__isl_take isl_set *set)
+{
+	return isl_set_from_basic_set(isl_set_combined_lineality_space(set));
+}
+
+/* For each set in "uset", compute the (linear) hull
+ * of the lineality spaces of its basic sets and
+ * collect and return the results.
+ */
+__isl_give isl_union_set *isl_union_set_combined_lineality_space(
+	__isl_take isl_union_set *uset)
+{
+	struct isl_un_op_control control = {
+		.fn_map = &combined_lineality_space,
+	};
+	return un_op(uset, &control);
+}
+
+/* Compute the polyhedral hull of "map" and return the result as an isl_map.
+ */
+static __isl_give isl_map *isl_map_polyhedral_hull_map(__isl_take isl_map *map)
+{
+	return isl_map_from_basic_map(isl_map_polyhedral_hull(map));
+}
+
+__isl_give isl_union_map *isl_union_map_polyhedral_hull(
+	__isl_take isl_union_map *umap)
+{
+	return total(umap, &isl_map_polyhedral_hull_map);
+}
+
+__isl_give isl_union_set *isl_union_set_polyhedral_hull(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_polyhedral_hull(uset);
+}
+
+/* Compute a superset of the convex hull of "map" that is described
+ * by only translates of the constraints in the constituents of "map" and
+ * return the result as an isl_map.
+ */
+static __isl_give isl_map *isl_map_simple_hull_map(__isl_take isl_map *map)
+{
+	return isl_map_from_basic_map(isl_map_simple_hull(map));
+}
+
+__isl_give isl_union_map *isl_union_map_simple_hull(
+	__isl_take isl_union_map *umap)
+{
+	return total(umap, &isl_map_simple_hull_map);
+}
+
+__isl_give isl_union_set *isl_union_set_simple_hull(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_simple_hull(uset);
+}
+
+static __isl_give isl_union_map *inplace(__isl_take isl_union_map *umap,
+	__isl_give isl_map *(*fn)(__isl_take isl_map *))
+{
+	struct isl_un_op_control control = {
+		.inplace = 1,
+		.fn_map = fn,
+	};
+
+	return un_op(umap, &control);
+}
+
+/* Remove redundant constraints in each of the basic maps of "umap".
+ * Since removing redundant constraints does not change the meaning
+ * or the space, the operation can be performed in-place.
+ */
+__isl_give isl_union_map *isl_union_map_remove_redundancies(
+	__isl_take isl_union_map *umap)
+{
+	return inplace(umap, &isl_map_remove_redundancies);
+}
+
+/* Remove redundant constraints in each of the basic sets of "uset".
+ */
+__isl_give isl_union_set *isl_union_set_remove_redundancies(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_remove_redundancies(uset);
+}
+
+__isl_give isl_union_map *isl_union_map_coalesce(
+	__isl_take isl_union_map *umap)
+{
+	return inplace(umap, &isl_map_coalesce);
+}
+
+__isl_give isl_union_set *isl_union_set_coalesce(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_coalesce(uset);
+}
+
+__isl_give isl_union_map *isl_union_map_detect_equalities(
+	__isl_take isl_union_map *umap)
+{
+	return inplace(umap, &isl_map_detect_equalities);
+}
+
+__isl_give isl_union_set *isl_union_set_detect_equalities(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_detect_equalities(uset);
+}
+
+__isl_give isl_union_map *isl_union_map_compute_divs(
+	__isl_take isl_union_map *umap)
+{
+	return inplace(umap, &isl_map_compute_divs);
+}
+
+__isl_give isl_union_set *isl_union_set_compute_divs(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_compute_divs(uset);
+}
+
+__isl_give isl_union_map *isl_union_map_lexmin(
+	__isl_take isl_union_map *umap)
+{
+	return total(umap, &isl_map_lexmin);
+}
+
+__isl_give isl_union_set *isl_union_set_lexmin(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_lexmin(uset);
+}
+
+__isl_give isl_union_map *isl_union_map_lexmax(
+	__isl_take isl_union_map *umap)
+{
+	return total(umap, &isl_map_lexmax);
+}
+
+__isl_give isl_union_set *isl_union_set_lexmax(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_lexmax(uset);
+}
+
+/* Return the universe in the space of "map".
+ */
+static __isl_give isl_map *universe(__isl_take isl_map *map)
+{
+	isl_space *space;
+
+	space = isl_map_get_space(map);
+	isl_map_free(map);
+	return isl_map_universe(space);
+}
+
+__isl_give isl_union_map *isl_union_map_universe(__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.fn_map = &universe,
+	};
+	return un_op(umap, &control);
+}
+
+__isl_give isl_union_set *isl_union_set_universe(__isl_take isl_union_set *uset)
+{
+	return isl_union_map_universe(uset);
+}
+
+__isl_give isl_union_map *isl_union_map_reverse(__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.fn_map = &isl_map_reverse,
+	};
+	return un_op(umap, &control);
+}
+
+/* Compute the parameter domain of the given union map.
+ */
+__isl_give isl_set *isl_union_map_params(__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.fn_map = &isl_map_params,
+	};
+	int empty;
+
+	empty = isl_union_map_is_empty(umap);
+	if (empty < 0)
+		goto error;
+	if (empty) {
+		isl_space *space;
+		space = isl_union_map_get_space(umap);
+		isl_union_map_free(umap);
+		return isl_set_empty(space);
+	}
+	return isl_set_from_union_set(un_op(umap, &control));
+error:
+	isl_union_map_free(umap);
+	return NULL;
+}
+
+/* Compute the parameter domain of the given union set.
+ */
+__isl_give isl_set *isl_union_set_params(__isl_take isl_union_set *uset)
+{
+	return isl_union_map_params(uset);
+}
+
+__isl_give isl_union_set *isl_union_map_domain(__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.fn_map = &isl_map_domain,
+	};
+	return un_op(umap, &control);
+}
+
+__isl_give isl_union_set *isl_union_map_range(__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.fn_map = &isl_map_range,
+	};
+	return un_op(umap, &control);
+}
+
+__isl_give isl_union_map *isl_union_map_domain_map(
+	__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.fn_map = &isl_map_domain_map,
+	};
+	return un_op(umap, &control);
+}
+
+/* Construct an isl_pw_multi_aff that maps "map" to its domain and
+ * add the result to "res".
+ */
+static isl_stat domain_map_upma(__isl_take isl_map *map, void *user)
+{
+	isl_union_pw_multi_aff **res = user;
+	isl_multi_aff *ma;
+	isl_pw_multi_aff *pma;
+
+	ma = isl_multi_aff_domain_map(isl_map_get_space(map));
+	pma = isl_pw_multi_aff_alloc(isl_map_wrap(map), ma);
+	*res = isl_union_pw_multi_aff_add_pw_multi_aff(*res, pma);
+
+	return *res ? isl_stat_ok : isl_stat_error;
+
+}
+
+/* Return an isl_union_pw_multi_aff that maps a wrapped copy of "umap"
+ * to its domain.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_map_domain_map_union_pw_multi_aff(
+	__isl_take isl_union_map *umap)
+{
+	isl_union_pw_multi_aff *res;
+
+	res = isl_union_pw_multi_aff_empty(isl_union_map_get_space(umap));
+	if (isl_union_map_foreach_map(umap, &domain_map_upma, &res) < 0)
+		res = isl_union_pw_multi_aff_free(res);
+
+	isl_union_map_free(umap);
+	return res;
+}
+
+__isl_give isl_union_map *isl_union_map_range_map(
+	__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.fn_map = &isl_map_range_map,
+	};
+	return un_op(umap, &control);
+}
+
+/* Given a collection of wrapped maps of the form A[B -> C],
+ * return the collection of maps A[B -> C] -> B.
+ */
+__isl_give isl_union_map *isl_union_set_wrapped_domain_map(
+	__isl_take isl_union_set *uset)
+{
+	struct isl_un_op_control control = {
+		.filter = &isl_set_is_wrapping,
+		.fn_map = &isl_set_wrapped_domain_map,
+	};
+	return un_op(uset, &control);
+}
+
+/* Does "map" relate elements from the same space?
+ */
+static isl_bool equal_tuples(__isl_keep isl_map *map)
+{
+	return isl_space_tuple_is_equal(map->dim, isl_dim_in,
+					map->dim, isl_dim_out);
+}
+
+__isl_give isl_union_set *isl_union_map_deltas(__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.filter = &equal_tuples,
+		.fn_map = &isl_map_deltas,
+	};
+	return un_op(umap, &control);
+}
+
+__isl_give isl_union_map *isl_union_map_deltas_map(
+	__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.filter = &equal_tuples,
+		.fn_map = &isl_map_deltas_map,
+	};
+	return un_op(umap, &control);
+}
+
+__isl_give isl_union_map *isl_union_set_identity(__isl_take isl_union_set *uset)
+{
+	struct isl_un_op_control control = {
+		.fn_map = &isl_set_identity,
+	};
+	return un_op(uset, &control);
+}
+
+/* Construct an identity isl_pw_multi_aff on "set" and add it to *res.
+ */
+static isl_stat identity_upma(__isl_take isl_set *set, void *user)
+{
+	isl_union_pw_multi_aff **res = user;
+	isl_space *space;
+	isl_pw_multi_aff *pma;
+
+	space = isl_space_map_from_set(isl_set_get_space(set));
+	pma = isl_pw_multi_aff_identity(space);
+	pma = isl_pw_multi_aff_intersect_domain(pma, set);
+	*res = isl_union_pw_multi_aff_add_pw_multi_aff(*res, pma);
+
+	return *res ? isl_stat_ok : isl_stat_error;
+}
+
+/* Return an identity function on "uset" in the form
+ * of an isl_union_pw_multi_aff.
+ */
+__isl_give isl_union_pw_multi_aff *isl_union_set_identity_union_pw_multi_aff(
+	__isl_take isl_union_set *uset)
+{
+	isl_union_pw_multi_aff *res;
+
+	res = isl_union_pw_multi_aff_empty(isl_union_set_get_space(uset));
+	if (isl_union_set_foreach_set(uset, &identity_upma, &res) < 0)
+		res = isl_union_pw_multi_aff_free(res);
+
+	isl_union_set_free(uset);
+	return res;
+}
+
+/* For each map in "umap" of the form [A -> B] -> C,
+ * construct the map A -> C and collect the results.
+ */
+__isl_give isl_union_map *isl_union_map_domain_factor_domain(
+	__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.filter = &isl_map_domain_is_wrapping,
+		.fn_map = &isl_map_domain_factor_domain,
+	};
+	return un_op(umap, &control);
+}
+
+/* For each map in "umap" of the form [A -> B] -> C,
+ * construct the map B -> C and collect the results.
+ */
+__isl_give isl_union_map *isl_union_map_domain_factor_range(
+	__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.filter = &isl_map_domain_is_wrapping,
+		.fn_map = &isl_map_domain_factor_range,
+	};
+	return un_op(umap, &control);
+}
+
+/* For each map in "umap" of the form A -> [B -> C],
+ * construct the map A -> B and collect the results.
+ */
+__isl_give isl_union_map *isl_union_map_range_factor_domain(
+	__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.filter = &isl_map_range_is_wrapping,
+		.fn_map = &isl_map_range_factor_domain,
+	};
+	return un_op(umap, &control);
+}
+
+/* For each map in "umap" of the form A -> [B -> C],
+ * construct the map A -> C and collect the results.
+ */
+__isl_give isl_union_map *isl_union_map_range_factor_range(
+	__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.filter = &isl_map_range_is_wrapping,
+		.fn_map = &isl_map_range_factor_range,
+	};
+	return un_op(umap, &control);
+}
+
+/* For each map in "umap" of the form [A -> B] -> [C -> D],
+ * construct the map A -> C and collect the results.
+ */
+__isl_give isl_union_map *isl_union_map_factor_domain(
+	__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.filter = &isl_map_is_product,
+		.fn_map = &isl_map_factor_domain,
+	};
+	return un_op(umap, &control);
+}
+
+/* For each map in "umap" of the form [A -> B] -> [C -> D],
+ * construct the map B -> D and collect the results.
+ */
+__isl_give isl_union_map *isl_union_map_factor_range(
+	__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.filter = &isl_map_is_product,
+		.fn_map = &isl_map_factor_range,
+	};
+	return un_op(umap, &control);
+}
+
+__isl_give isl_union_map *isl_union_set_unwrap(__isl_take isl_union_set *uset)
+{
+	struct isl_un_op_control control = {
+		.filter = &isl_set_is_wrapping,
+		.fn_map = &isl_set_unwrap,
+	};
+	return un_op(uset, &control);
+}
+
+__isl_give isl_union_set *isl_union_map_wrap(__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.fn_map = &isl_map_wrap,
+	};
+	return un_op(umap, &control);
+}
+
+struct isl_union_map_is_subset_data {
+	isl_union_map *umap2;
+	isl_bool is_subset;
+};
+
+static isl_stat is_subset_entry(void **entry, void *user)
+{
+	struct isl_union_map_is_subset_data *data = user;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	isl_map *map = *entry;
+
+	hash = isl_space_get_hash(map->dim);
+	entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table,
+				     hash, &has_space, map->dim, 0);
+	if (!entry2) {
+		int empty = isl_map_is_empty(map);
+		if (empty < 0)
+			return isl_stat_error;
+		if (empty)
+			return isl_stat_ok;
+		data->is_subset = 0;
+		return isl_stat_error;
+	}
+
+	data->is_subset = isl_map_is_subset(map, entry2->data);
+	if (data->is_subset < 0 || !data->is_subset)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+isl_bool isl_union_map_is_subset(__isl_keep isl_union_map *umap1,
+	__isl_keep isl_union_map *umap2)
+{
+	struct isl_union_map_is_subset_data data = { NULL, isl_bool_true };
+
+	umap1 = isl_union_map_copy(umap1);
+	umap2 = isl_union_map_copy(umap2);
+	umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2));
+	umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1));
+
+	if (!umap1 || !umap2)
+		goto error;
+
+	data.umap2 = umap2;
+	if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table,
+				   &is_subset_entry, &data) < 0 &&
+	    data.is_subset)
+		goto error;
+
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+
+	return data.is_subset;
+error:
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+	return isl_bool_error;
+}
+
+isl_bool isl_union_set_is_subset(__isl_keep isl_union_set *uset1,
+	__isl_keep isl_union_set *uset2)
+{
+	return isl_union_map_is_subset(uset1, uset2);
+}
+
+isl_bool isl_union_map_is_equal(__isl_keep isl_union_map *umap1,
+	__isl_keep isl_union_map *umap2)
+{
+	isl_bool is_subset;
+
+	if (!umap1 || !umap2)
+		return isl_bool_error;
+	is_subset = isl_union_map_is_subset(umap1, umap2);
+	if (is_subset != isl_bool_true)
+		return is_subset;
+	is_subset = isl_union_map_is_subset(umap2, umap1);
+	return is_subset;
+}
+
+isl_bool isl_union_set_is_equal(__isl_keep isl_union_set *uset1,
+	__isl_keep isl_union_set *uset2)
+{
+	return isl_union_map_is_equal(uset1, uset2);
+}
+
+isl_bool isl_union_map_is_strict_subset(__isl_keep isl_union_map *umap1,
+	__isl_keep isl_union_map *umap2)
+{
+	isl_bool is_subset;
+
+	if (!umap1 || !umap2)
+		return isl_bool_error;
+	is_subset = isl_union_map_is_subset(umap1, umap2);
+	if (is_subset != isl_bool_true)
+		return is_subset;
+	is_subset = isl_union_map_is_subset(umap2, umap1);
+	if (is_subset == isl_bool_error)
+		return is_subset;
+	return !is_subset;
+}
+
+isl_bool isl_union_set_is_strict_subset(__isl_keep isl_union_set *uset1,
+	__isl_keep isl_union_set *uset2)
+{
+	return isl_union_map_is_strict_subset(uset1, uset2);
+}
+
+/* Internal data structure for isl_union_map_is_disjoint.
+ * umap2 is the union map with which we are comparing.
+ * is_disjoint is initialized to 1 and is set to 0 as soon
+ * as the union maps turn out not to be disjoint.
+ */
+struct isl_union_map_is_disjoint_data {
+	isl_union_map *umap2;
+	isl_bool is_disjoint;
+};
+
+/* Check if "map" is disjoint from data->umap2 and abort
+ * the search if it is not.
+ */
+static isl_stat is_disjoint_entry(void **entry, void *user)
+{
+	struct isl_union_map_is_disjoint_data *data = user;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	isl_map *map = *entry;
+
+	hash = isl_space_get_hash(map->dim);
+	entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table,
+				     hash, &has_space, map->dim, 0);
+	if (!entry2)
+		return isl_stat_ok;
+
+	data->is_disjoint = isl_map_is_disjoint(map, entry2->data);
+	if (data->is_disjoint < 0 || !data->is_disjoint)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Are "umap1" and "umap2" disjoint?
+ */
+isl_bool isl_union_map_is_disjoint(__isl_keep isl_union_map *umap1,
+	__isl_keep isl_union_map *umap2)
+{
+	struct isl_union_map_is_disjoint_data data = { NULL, isl_bool_true };
+
+	umap1 = isl_union_map_copy(umap1);
+	umap2 = isl_union_map_copy(umap2);
+	umap1 = isl_union_map_align_params(umap1,
+						isl_union_map_get_space(umap2));
+	umap2 = isl_union_map_align_params(umap2,
+						isl_union_map_get_space(umap1));
+
+	if (!umap1 || !umap2)
+		goto error;
+
+	data.umap2 = umap2;
+	if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table,
+				   &is_disjoint_entry, &data) < 0 &&
+	    data.is_disjoint)
+		goto error;
+
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+
+	return data.is_disjoint;
+error:
+	isl_union_map_free(umap1);
+	isl_union_map_free(umap2);
+	return isl_bool_error;
+}
+
+/* Are "uset1" and "uset2" disjoint?
+ */
+isl_bool isl_union_set_is_disjoint(__isl_keep isl_union_set *uset1,
+	__isl_keep isl_union_set *uset2)
+{
+	return isl_union_map_is_disjoint(uset1, uset2);
+}
+
+static isl_stat sample_entry(void **entry, void *user)
+{
+	isl_basic_map **sample = (isl_basic_map **)user;
+	isl_map *map = *entry;
+
+	*sample = isl_map_sample(isl_map_copy(map));
+	if (!*sample)
+		return isl_stat_error;
+	if (!isl_basic_map_plain_is_empty(*sample))
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+__isl_give isl_basic_map *isl_union_map_sample(__isl_take isl_union_map *umap)
+{
+	isl_basic_map *sample = NULL;
+
+	if (!umap)
+		return NULL;
+
+	if (isl_hash_table_foreach(umap->dim->ctx, &umap->table,
+				   &sample_entry, &sample) < 0 &&
+	    !sample)
+		goto error;
+
+	if (!sample)
+		sample = isl_basic_map_empty(isl_union_map_get_space(umap));
+
+	isl_union_map_free(umap);
+
+	return sample;
+error:
+	isl_union_map_free(umap);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_union_set_sample(__isl_take isl_union_set *uset)
+{
+	return bset_from_bmap(isl_union_map_sample(uset));
+}
+
+/* Return an element in "uset" in the form of an isl_point.
+ * Return a void isl_point if "uset" is empty.
+ */
+__isl_give isl_point *isl_union_set_sample_point(__isl_take isl_union_set *uset)
+{
+	return isl_basic_set_sample_point(isl_union_set_sample(uset));
+}
+
+struct isl_forall_data {
+	isl_bool res;
+	isl_bool (*fn)(__isl_keep isl_map *map);
+};
+
+static isl_stat forall_entry(void **entry, void *user)
+{
+	struct isl_forall_data *data = user;
+	isl_map *map = *entry;
+
+	data->res = data->fn(map);
+	if (data->res < 0)
+		return isl_stat_error;
+
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+static isl_bool union_map_forall(__isl_keep isl_union_map *umap,
+	isl_bool (*fn)(__isl_keep isl_map *map))
+{
+	struct isl_forall_data data = { isl_bool_true, fn };
+
+	if (!umap)
+		return isl_bool_error;
+
+	if (isl_hash_table_foreach(umap->dim->ctx, &umap->table,
+				   &forall_entry, &data) < 0 && data.res)
+		return isl_bool_error;
+
+	return data.res;
+}
+
+struct isl_forall_user_data {
+	isl_bool res;
+	isl_bool (*fn)(__isl_keep isl_map *map, void *user);
+	void *user;
+};
+
+static isl_stat forall_user_entry(void **entry, void *user)
+{
+	struct isl_forall_user_data *data = user;
+	isl_map *map = *entry;
+
+	data->res = data->fn(map, data->user);
+	if (data->res < 0)
+		return isl_stat_error;
+
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Check if fn(map, user) returns true for all maps "map" in umap.
+ */
+static isl_bool union_map_forall_user(__isl_keep isl_union_map *umap,
+	isl_bool (*fn)(__isl_keep isl_map *map, void *user), void *user)
+{
+	struct isl_forall_user_data data = { isl_bool_true, fn, user };
+
+	if (!umap)
+		return isl_bool_error;
+
+	if (isl_hash_table_foreach(umap->dim->ctx, &umap->table,
+				   &forall_user_entry, &data) < 0 && data.res)
+		return isl_bool_error;
+
+	return data.res;
+}
+
+isl_bool isl_union_map_is_empty(__isl_keep isl_union_map *umap)
+{
+	return union_map_forall(umap, &isl_map_is_empty);
+}
+
+isl_bool isl_union_set_is_empty(__isl_keep isl_union_set *uset)
+{
+	return isl_union_map_is_empty(uset);
+}
+
+static isl_bool is_subset_of_identity(__isl_keep isl_map *map)
+{
+	isl_bool is_subset;
+	isl_space *dim;
+	isl_map *id;
+
+	if (!map)
+		return isl_bool_error;
+
+	if (!isl_space_tuple_is_equal(map->dim, isl_dim_in,
+					map->dim, isl_dim_out))
+		return isl_bool_false;
+
+	dim = isl_map_get_space(map);
+	id = isl_map_identity(dim);
+
+	is_subset = isl_map_is_subset(map, id);
+
+	isl_map_free(id);
+
+	return is_subset;
+}
+
+/* Given an isl_union_map that consists of a single map, check
+ * if it is single-valued.
+ */
+static isl_bool single_map_is_single_valued(__isl_keep isl_union_map *umap)
+{
+	isl_map *map;
+	isl_bool sv;
+
+	umap = isl_union_map_copy(umap);
+	map = isl_map_from_union_map(umap);
+	sv = isl_map_is_single_valued(map);
+	isl_map_free(map);
+
+	return sv;
+}
+
+/* Internal data structure for single_valued_on_domain.
+ *
+ * "umap" is the union map to be tested.
+ * "sv" is set to 1 as long as "umap" may still be single-valued.
+ */
+struct isl_union_map_is_sv_data {
+	isl_union_map *umap;
+	isl_bool sv;
+};
+
+/* Check if the data->umap is single-valued on "set".
+ *
+ * If data->umap consists of a single map on "set", then test it
+ * as an isl_map.
+ *
+ * Otherwise, compute
+ *
+ *	M \circ M^-1
+ *
+ * check if the result is a subset of the identity mapping and
+ * store the result in data->sv.
+ *
+ * Terminate as soon as data->umap has been determined not to
+ * be single-valued.
+ */
+static isl_stat single_valued_on_domain(__isl_take isl_set *set, void *user)
+{
+	struct isl_union_map_is_sv_data *data = user;
+	isl_union_map *umap, *test;
+
+	umap = isl_union_map_copy(data->umap);
+	umap = isl_union_map_intersect_domain(umap,
+						isl_union_set_from_set(set));
+
+	if (isl_union_map_n_map(umap) == 1) {
+		data->sv = single_map_is_single_valued(umap);
+		isl_union_map_free(umap);
+	} else {
+		test = isl_union_map_reverse(isl_union_map_copy(umap));
+		test = isl_union_map_apply_range(test, umap);
+
+		data->sv = union_map_forall(test, &is_subset_of_identity);
+
+		isl_union_map_free(test);
+	}
+
+	if (data->sv < 0 || !data->sv)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Check if the given map is single-valued.
+ *
+ * If the union map consists of a single map, then test it as an isl_map.
+ * Otherwise, check if the union map is single-valued on each of its
+ * domain spaces.
+ */
+isl_bool isl_union_map_is_single_valued(__isl_keep isl_union_map *umap)
+{
+	isl_union_map *universe;
+	isl_union_set *domain;
+	struct isl_union_map_is_sv_data data;
+
+	if (isl_union_map_n_map(umap) == 1)
+		return single_map_is_single_valued(umap);
+
+	universe = isl_union_map_universe(isl_union_map_copy(umap));
+	domain = isl_union_map_domain(universe);
+
+	data.sv = isl_bool_true;
+	data.umap = umap;
+	if (isl_union_set_foreach_set(domain,
+			    &single_valued_on_domain, &data) < 0 && data.sv)
+		data.sv = isl_bool_error;
+	isl_union_set_free(domain);
+
+	return data.sv;
+}
+
+isl_bool isl_union_map_is_injective(__isl_keep isl_union_map *umap)
+{
+	isl_bool in;
+
+	umap = isl_union_map_copy(umap);
+	umap = isl_union_map_reverse(umap);
+	in = isl_union_map_is_single_valued(umap);
+	isl_union_map_free(umap);
+
+	return in;
+}
+
+/* Is "map" obviously not an identity relation because
+ * it maps elements from one space to another space?
+ * Update *non_identity accordingly.
+ *
+ * In particular, if the domain and range spaces are the same,
+ * then the map is not considered to obviously not be an identity relation.
+ * Otherwise, the map is considered to obviously not be an identity relation
+ * if it is is non-empty.
+ *
+ * If "map" is determined to obviously not be an identity relation,
+ * then the search is aborted.
+ */
+static isl_stat map_plain_is_not_identity(__isl_take isl_map *map, void *user)
+{
+	isl_bool *non_identity = user;
+	isl_bool equal;
+	isl_space *space;
+
+	space = isl_map_get_space(map);
+	equal = isl_space_tuple_is_equal(space, isl_dim_in, space, isl_dim_out);
+	if (equal >= 0 && !equal)
+		*non_identity = isl_bool_not(isl_map_is_empty(map));
+	else
+		*non_identity = isl_bool_not(equal);
+	isl_space_free(space);
+	isl_map_free(map);
+
+	if (*non_identity < 0 || *non_identity)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Is "umap" obviously not an identity relation because
+ * it maps elements from one space to another space?
+ *
+ * As soon as a map has been found that maps elements to a different space,
+ * non_identity is changed and the search is aborted.
+ */
+static isl_bool isl_union_map_plain_is_not_identity(
+	__isl_keep isl_union_map *umap)
+{
+	isl_bool non_identity;
+
+	non_identity = isl_bool_false;
+	if (isl_union_map_foreach_map(umap, &map_plain_is_not_identity,
+					&non_identity) < 0 &&
+	    non_identity == isl_bool_false)
+		return isl_bool_error;
+
+	return non_identity;
+}
+
+/* Does "map" only map elements to themselves?
+ * Update *identity accordingly.
+ *
+ * If "map" is determined not to be an identity relation,
+ * then the search is aborted.
+ */
+static isl_stat map_is_identity(__isl_take isl_map *map, void *user)
+{
+	isl_bool *identity = user;
+
+	*identity = isl_map_is_identity(map);
+	isl_map_free(map);
+
+	if (*identity < 0 || !*identity)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Does "umap" only map elements to themselves?
+ *
+ * First check if there are any maps that map elements to different spaces.
+ * If not, then check that all the maps (between identical spaces)
+ * are identity relations.
+ */
+isl_bool isl_union_map_is_identity(__isl_keep isl_union_map *umap)
+{
+	isl_bool non_identity;
+	isl_bool identity;
+
+	non_identity = isl_union_map_plain_is_not_identity(umap);
+	if (non_identity < 0 || non_identity)
+		return isl_bool_not(non_identity);
+
+	identity = isl_bool_true;
+	if (isl_union_map_foreach_map(umap, &map_is_identity, &identity) < 0 &&
+	    identity == isl_bool_true)
+		return isl_bool_error;
+
+	return identity;
+}
+
+/* Represents a map that has a fixed value (v) for one of its
+ * range dimensions.
+ * The map in this structure is not reference counted, so it
+ * is only valid while the isl_union_map from which it was
+ * obtained is still alive.
+ */
+struct isl_fixed_map {
+	isl_int v;
+	isl_map *map;
+};
+
+static struct isl_fixed_map *alloc_isl_fixed_map_array(isl_ctx *ctx,
+	int n)
+{
+	int i;
+	struct isl_fixed_map *v;
+
+	v = isl_calloc_array(ctx, struct isl_fixed_map, n);
+	if (!v)
+		return NULL;
+	for (i = 0; i < n; ++i)
+		isl_int_init(v[i].v);
+	return v;
+}
+
+static void free_isl_fixed_map_array(struct isl_fixed_map *v, int n)
+{
+	int i;
+
+	if (!v)
+		return;
+	for (i = 0; i < n; ++i)
+		isl_int_clear(v[i].v);
+	free(v);
+}
+
+/* Compare the "v" field of two isl_fixed_map structs.
+ */
+static int qsort_fixed_map_cmp(const void *p1, const void *p2)
+{
+	const struct isl_fixed_map *e1 = (const struct isl_fixed_map *) p1;
+	const struct isl_fixed_map *e2 = (const struct isl_fixed_map *) p2;
+
+	return isl_int_cmp(e1->v, e2->v);
+}
+
+/* Internal data structure used while checking whether all maps
+ * in a union_map have a fixed value for a given output dimension.
+ * v is the list of maps, with the fixed value for the dimension
+ * n is the number of maps considered so far
+ * pos is the output dimension under investigation
+ */
+struct isl_fixed_dim_data {
+	struct isl_fixed_map *v;
+	int n;
+	int pos;
+};
+
+static isl_bool fixed_at_pos(__isl_keep isl_map *map, void *user)
+{
+	struct isl_fixed_dim_data *data = user;
+
+	data->v[data->n].map = map;
+	return isl_map_plain_is_fixed(map, isl_dim_out, data->pos,
+				      &data->v[data->n++].v);
+}
+
+static isl_bool plain_injective_on_range(__isl_take isl_union_map *umap,
+	int first, int n_range);
+
+/* Given a list of the maps, with their fixed values at output dimension "pos",
+ * check whether the ranges of the maps form an obvious partition.
+ *
+ * We first sort the maps according to their fixed values.
+ * If all maps have a different value, then we know the ranges form
+ * a partition.
+ * Otherwise, we collect the maps with the same fixed value and
+ * check whether each such collection is obviously injective
+ * based on later dimensions.
+ */
+static int separates(struct isl_fixed_map *v, int n,
+	__isl_take isl_space *dim, int pos, int n_range)
+{
+	int i;
+
+	if (!v)
+		goto error;
+
+	qsort(v, n, sizeof(*v), &qsort_fixed_map_cmp);
+
+	for (i = 0; i + 1 < n; ++i) {
+		int j, k;
+		isl_union_map *part;
+		int injective;
+
+		for (j = i + 1; j < n; ++j)
+			if (isl_int_ne(v[i].v, v[j].v))
+				break;
+
+		if (j == i + 1)
+			continue;
+
+		part = isl_union_map_alloc(isl_space_copy(dim), j - i);
+		for (k = i; k < j; ++k)
+			part = isl_union_map_add_map(part,
+						     isl_map_copy(v[k].map));
+
+		injective = plain_injective_on_range(part, pos + 1, n_range);
+		if (injective < 0)
+			goto error;
+		if (!injective)
+			break;
+
+		i = j - 1;
+	}
+
+	isl_space_free(dim);
+	free_isl_fixed_map_array(v, n);
+	return i + 1 >= n;
+error:
+	isl_space_free(dim);
+	free_isl_fixed_map_array(v, n);
+	return -1;
+}
+
+/* Check whether the maps in umap have obviously distinct ranges.
+ * In particular, check for an output dimension in the range
+ * [first,n_range) for which all maps have a fixed value
+ * and then check if these values, possibly along with fixed values
+ * at later dimensions, entail distinct ranges.
+ */
+static isl_bool plain_injective_on_range(__isl_take isl_union_map *umap,
+	int first, int n_range)
+{
+	isl_ctx *ctx;
+	int n;
+	struct isl_fixed_dim_data data = { NULL };
+
+	ctx = isl_union_map_get_ctx(umap);
+
+	n = isl_union_map_n_map(umap);
+	if (!umap)
+		goto error;
+
+	if (n <= 1) {
+		isl_union_map_free(umap);
+		return isl_bool_true;
+	}
+
+	if (first >= n_range) {
+		isl_union_map_free(umap);
+		return isl_bool_false;
+	}
+
+	data.v = alloc_isl_fixed_map_array(ctx, n);
+	if (!data.v)
+		goto error;
+
+	for (data.pos = first; data.pos < n_range; ++data.pos) {
+		isl_bool fixed;
+		int injective;
+		isl_space *dim;
+
+		data.n = 0;
+		fixed = union_map_forall_user(umap, &fixed_at_pos, &data);
+		if (fixed < 0)
+			goto error;
+		if (!fixed)
+			continue;
+		dim = isl_union_map_get_space(umap);
+		injective = separates(data.v, n, dim, data.pos, n_range);
+		isl_union_map_free(umap);
+		return injective;
+	}
+
+	free_isl_fixed_map_array(data.v, n);
+	isl_union_map_free(umap);
+
+	return isl_bool_false;
+error:
+	free_isl_fixed_map_array(data.v, n);
+	isl_union_map_free(umap);
+	return isl_bool_error;
+}
+
+/* Check whether the maps in umap that map to subsets of "ran"
+ * have obviously distinct ranges.
+ */
+static isl_bool plain_injective_on_range_wrap(__isl_keep isl_set *ran,
+	void *user)
+{
+	isl_union_map *umap = user;
+
+	umap = isl_union_map_copy(umap);
+	umap = isl_union_map_intersect_range(umap,
+			isl_union_set_from_set(isl_set_copy(ran)));
+	return plain_injective_on_range(umap, 0, isl_set_dim(ran, isl_dim_set));
+}
+
+/* Check if the given union_map is obviously injective.
+ *
+ * In particular, we first check if all individual maps are obviously
+ * injective and then check if all the ranges of these maps are
+ * obviously disjoint.
+ */
+isl_bool isl_union_map_plain_is_injective(__isl_keep isl_union_map *umap)
+{
+	isl_bool in;
+	isl_union_map *univ;
+	isl_union_set *ran;
+
+	in = union_map_forall(umap, &isl_map_plain_is_injective);
+	if (in < 0)
+		return isl_bool_error;
+	if (!in)
+		return isl_bool_false;
+
+	univ = isl_union_map_universe(isl_union_map_copy(umap));
+	ran = isl_union_map_range(univ);
+
+	in = union_map_forall_user(ran, &plain_injective_on_range_wrap, umap);
+
+	isl_union_set_free(ran);
+
+	return in;
+}
+
+isl_bool isl_union_map_is_bijective(__isl_keep isl_union_map *umap)
+{
+	isl_bool sv;
+
+	sv = isl_union_map_is_single_valued(umap);
+	if (sv < 0 || !sv)
+		return sv;
+
+	return isl_union_map_is_injective(umap);
+}
+
+__isl_give isl_union_map *isl_union_map_zip(__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.filter = &isl_map_can_zip,
+		.fn_map = &isl_map_zip,
+	};
+	return un_op(umap, &control);
+}
+
+/* Given a union map, take the maps of the form A -> (B -> C) and
+ * return the union of the corresponding maps (A -> B) -> C.
+ */
+__isl_give isl_union_map *isl_union_map_uncurry(__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.filter = &isl_map_can_uncurry,
+		.fn_map = &isl_map_uncurry,
+	};
+	return un_op(umap, &control);
+}
+
+/* Given a union map, take the maps of the form (A -> B) -> C and
+ * return the union of the corresponding maps A -> (B -> C).
+ */
+__isl_give isl_union_map *isl_union_map_curry(__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.filter = &isl_map_can_curry,
+		.fn_map = &isl_map_curry,
+	};
+	return un_op(umap, &control);
+}
+
+/* Given a union map, take the maps of the form A -> ((B -> C) -> D) and
+ * return the union of the corresponding maps A -> (B -> (C -> D)).
+ */
+__isl_give isl_union_map *isl_union_map_range_curry(
+	__isl_take isl_union_map *umap)
+{
+	struct isl_un_op_control control = {
+		.filter = &isl_map_can_range_curry,
+		.fn_map = &isl_map_range_curry,
+	};
+	return un_op(umap, &control);
+}
+
+__isl_give isl_union_set *isl_union_set_lift(__isl_take isl_union_set *uset)
+{
+	struct isl_un_op_control control = {
+		.fn_map = &isl_set_lift,
+	};
+	return un_op(uset, &control);
+}
+
+static isl_stat coefficients_entry(void **entry, void *user)
+{
+	isl_set *set = *entry;
+	isl_union_set **res = user;
+
+	set = isl_set_copy(set);
+	set = isl_set_from_basic_set(isl_set_coefficients(set));
+	*res = isl_union_set_add_set(*res, set);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_set *isl_union_set_coefficients(
+	__isl_take isl_union_set *uset)
+{
+	isl_ctx *ctx;
+	isl_space *dim;
+	isl_union_set *res;
+
+	if (!uset)
+		return NULL;
+
+	ctx = isl_union_set_get_ctx(uset);
+	dim = isl_space_set_alloc(ctx, 0, 0);
+	res = isl_union_map_alloc(dim, uset->table.n);
+	if (isl_hash_table_foreach(uset->dim->ctx, &uset->table,
+				   &coefficients_entry, &res) < 0)
+		goto error;
+
+	isl_union_set_free(uset);
+	return res;
+error:
+	isl_union_set_free(uset);
+	isl_union_set_free(res);
+	return NULL;
+}
+
+static isl_stat solutions_entry(void **entry, void *user)
+{
+	isl_set *set = *entry;
+	isl_union_set **res = user;
+
+	set = isl_set_copy(set);
+	set = isl_set_from_basic_set(isl_set_solutions(set));
+	if (!*res)
+		*res = isl_union_set_from_set(set);
+	else
+		*res = isl_union_set_add_set(*res, set);
+
+	if (!*res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_set *isl_union_set_solutions(
+	__isl_take isl_union_set *uset)
+{
+	isl_union_set *res = NULL;
+
+	if (!uset)
+		return NULL;
+
+	if (uset->table.n == 0) {
+		res = isl_union_set_empty(isl_union_set_get_space(uset));
+		isl_union_set_free(uset);
+		return res;
+	}
+
+	if (isl_hash_table_foreach(uset->dim->ctx, &uset->table,
+				   &solutions_entry, &res) < 0)
+		goto error;
+
+	isl_union_set_free(uset);
+	return res;
+error:
+	isl_union_set_free(uset);
+	isl_union_set_free(res);
+	return NULL;
+}
+
+/* Is the domain space of "map" equal to "space"?
+ */
+static int domain_match(__isl_keep isl_map *map, __isl_keep isl_space *space)
+{
+	return isl_space_tuple_is_equal(map->dim, isl_dim_in,
+					space, isl_dim_out);
+}
+
+/* Is the range space of "map" equal to "space"?
+ */
+static int range_match(__isl_keep isl_map *map, __isl_keep isl_space *space)
+{
+	return isl_space_tuple_is_equal(map->dim, isl_dim_out,
+					space, isl_dim_out);
+}
+
+/* Is the set space of "map" equal to "space"?
+ */
+static int set_match(__isl_keep isl_map *map, __isl_keep isl_space *space)
+{
+	return isl_space_tuple_is_equal(map->dim, isl_dim_set,
+					space, isl_dim_out);
+}
+
+/* Internal data structure for preimage_pw_multi_aff.
+ *
+ * "pma" is the function under which the preimage should be taken.
+ * "space" is the space of "pma".
+ * "res" collects the results.
+ * "fn" computes the preimage for a given map.
+ * "match" returns true if "fn" can be called.
+ */
+struct isl_union_map_preimage_data {
+	isl_space *space;
+	isl_pw_multi_aff *pma;
+	isl_union_map *res;
+	int (*match)(__isl_keep isl_map *map, __isl_keep isl_space *space);
+	__isl_give isl_map *(*fn)(__isl_take isl_map *map,
+		__isl_take isl_pw_multi_aff *pma);
+};
+
+/* Call data->fn to compute the preimage of the domain or range of *entry
+ * under the function represented by data->pma, provided the domain/range
+ * space of *entry matches the target space of data->pma
+ * (as given by data->match), and add the result to data->res.
+ */
+static isl_stat preimage_entry(void **entry, void *user)
+{
+	int m;
+	isl_map *map = *entry;
+	struct isl_union_map_preimage_data *data = user;
+	isl_bool empty;
+
+	m = data->match(map, data->space);
+	if (m < 0)
+		return isl_stat_error;
+	if (!m)
+		return isl_stat_ok;
+
+	map = isl_map_copy(map);
+	map = data->fn(map, isl_pw_multi_aff_copy(data->pma));
+
+	empty = isl_map_is_empty(map);
+	if (empty < 0 || empty) {
+		isl_map_free(map);
+		return empty < 0 ? isl_stat_error : isl_stat_ok;
+	}
+
+	data->res = isl_union_map_add_map(data->res, map);
+
+	return isl_stat_ok;
+}
+
+/* Compute the preimage of the domain or range of "umap" under the function
+ * represented by "pma".
+ * In other words, plug in "pma" in the domain or range of "umap".
+ * The function "fn" performs the actual preimage computation on a map,
+ * while "match" determines to which maps the function should be applied.
+ */
+static __isl_give isl_union_map *preimage_pw_multi_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma,
+	int (*match)(__isl_keep isl_map *map, __isl_keep isl_space *space),
+	__isl_give isl_map *(*fn)(__isl_take isl_map *map,
+		__isl_take isl_pw_multi_aff *pma))
+{
+	isl_ctx *ctx;
+	isl_space *space;
+	struct isl_union_map_preimage_data data;
+
+	umap = isl_union_map_align_params(umap,
+					    isl_pw_multi_aff_get_space(pma));
+	pma = isl_pw_multi_aff_align_params(pma, isl_union_map_get_space(umap));
+
+	if (!umap || !pma)
+		goto error;
+
+	ctx = isl_union_map_get_ctx(umap);
+	space = isl_union_map_get_space(umap);
+	data.space = isl_pw_multi_aff_get_space(pma);
+	data.pma = pma;
+	data.res = isl_union_map_alloc(space, umap->table.n);
+	data.match = match;
+	data.fn = fn;
+	if (isl_hash_table_foreach(ctx, &umap->table, &preimage_entry,
+					&data) < 0)
+		data.res = isl_union_map_free(data.res);
+
+	isl_space_free(data.space);
+	isl_union_map_free(umap);
+	isl_pw_multi_aff_free(pma);
+	return data.res;
+error:
+	isl_union_map_free(umap);
+	isl_pw_multi_aff_free(pma);
+	return NULL;
+}
+
+/* Compute the preimage of the domain of "umap" under the function
+ * represented by "pma".
+ * In other words, plug in "pma" in the domain of "umap".
+ * The result contains maps that live in the same spaces as the maps of "umap"
+ * with domain space equal to the target space of "pma",
+ * except that the domain has been replaced by the domain space of "pma".
+ */
+__isl_give isl_union_map *isl_union_map_preimage_domain_pw_multi_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma)
+{
+	return preimage_pw_multi_aff(umap, pma, &domain_match,
+					&isl_map_preimage_domain_pw_multi_aff);
+}
+
+/* Compute the preimage of the range of "umap" under the function
+ * represented by "pma".
+ * In other words, plug in "pma" in the range of "umap".
+ * The result contains maps that live in the same spaces as the maps of "umap"
+ * with range space equal to the target space of "pma",
+ * except that the range has been replaced by the domain space of "pma".
+ */
+__isl_give isl_union_map *isl_union_map_preimage_range_pw_multi_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma)
+{
+	return preimage_pw_multi_aff(umap, pma, &range_match,
+					&isl_map_preimage_range_pw_multi_aff);
+}
+
+/* Compute the preimage of "uset" under the function represented by "pma".
+ * In other words, plug in "pma" in "uset".
+ * The result contains sets that live in the same spaces as the sets of "uset"
+ * with space equal to the target space of "pma",
+ * except that the space has been replaced by the domain space of "pma".
+ */
+__isl_give isl_union_set *isl_union_set_preimage_pw_multi_aff(
+	__isl_take isl_union_set *uset, __isl_take isl_pw_multi_aff *pma)
+{
+	return preimage_pw_multi_aff(uset, pma, &set_match,
+					&isl_set_preimage_pw_multi_aff);
+}
+
+/* Compute the preimage of the domain of "umap" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the domain of "umap".
+ * The result contains maps that live in the same spaces as the maps of "umap"
+ * with domain space equal to the target space of "ma",
+ * except that the domain has been replaced by the domain space of "ma".
+ */
+__isl_give isl_union_map *isl_union_map_preimage_domain_multi_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_multi_aff *ma)
+{
+	return isl_union_map_preimage_domain_pw_multi_aff(umap,
+					isl_pw_multi_aff_from_multi_aff(ma));
+}
+
+/* Compute the preimage of the range of "umap" under the function
+ * represented by "ma".
+ * In other words, plug in "ma" in the range of "umap".
+ * The result contains maps that live in the same spaces as the maps of "umap"
+ * with range space equal to the target space of "ma",
+ * except that the range has been replaced by the domain space of "ma".
+ */
+__isl_give isl_union_map *isl_union_map_preimage_range_multi_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_multi_aff *ma)
+{
+	return isl_union_map_preimage_range_pw_multi_aff(umap,
+					isl_pw_multi_aff_from_multi_aff(ma));
+}
+
+/* Compute the preimage of "uset" under the function represented by "ma".
+ * In other words, plug in "ma" in "uset".
+ * The result contains sets that live in the same spaces as the sets of "uset"
+ * with space equal to the target space of "ma",
+ * except that the space has been replaced by the domain space of "ma".
+ */
+__isl_give isl_union_map *isl_union_set_preimage_multi_aff(
+	__isl_take isl_union_set *uset, __isl_take isl_multi_aff *ma)
+{
+	return isl_union_set_preimage_pw_multi_aff(uset,
+					isl_pw_multi_aff_from_multi_aff(ma));
+}
+
+/* Internal data structure for preimage_multi_pw_aff.
+ *
+ * "mpa" is the function under which the preimage should be taken.
+ * "space" is the space of "mpa".
+ * "res" collects the results.
+ * "fn" computes the preimage for a given map.
+ * "match" returns true if "fn" can be called.
+ */
+struct isl_union_map_preimage_mpa_data {
+	isl_space *space;
+	isl_multi_pw_aff *mpa;
+	isl_union_map *res;
+	int (*match)(__isl_keep isl_map *map, __isl_keep isl_space *space);
+	__isl_give isl_map *(*fn)(__isl_take isl_map *map,
+		__isl_take isl_multi_pw_aff *mpa);
+};
+
+/* Call data->fn to compute the preimage of the domain or range of *entry
+ * under the function represented by data->mpa, provided the domain/range
+ * space of *entry matches the target space of data->mpa
+ * (as given by data->match), and add the result to data->res.
+ */
+static isl_stat preimage_mpa_entry(void **entry, void *user)
+{
+	int m;
+	isl_map *map = *entry;
+	struct isl_union_map_preimage_mpa_data *data = user;
+	isl_bool empty;
+
+	m = data->match(map, data->space);
+	if (m < 0)
+		return isl_stat_error;
+	if (!m)
+		return isl_stat_ok;
+
+	map = isl_map_copy(map);
+	map = data->fn(map, isl_multi_pw_aff_copy(data->mpa));
+
+	empty = isl_map_is_empty(map);
+	if (empty < 0 || empty) {
+		isl_map_free(map);
+		return empty < 0 ? isl_stat_error : isl_stat_ok;
+	}
+
+	data->res = isl_union_map_add_map(data->res, map);
+
+	return isl_stat_ok;
+}
+
+/* Compute the preimage of the domain or range of "umap" under the function
+ * represented by "mpa".
+ * In other words, plug in "mpa" in the domain or range of "umap".
+ * The function "fn" performs the actual preimage computation on a map,
+ * while "match" determines to which maps the function should be applied.
+ */
+static __isl_give isl_union_map *preimage_multi_pw_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_multi_pw_aff *mpa,
+	int (*match)(__isl_keep isl_map *map, __isl_keep isl_space *space),
+	__isl_give isl_map *(*fn)(__isl_take isl_map *map,
+		__isl_take isl_multi_pw_aff *mpa))
+{
+	isl_ctx *ctx;
+	isl_space *space;
+	struct isl_union_map_preimage_mpa_data data;
+
+	umap = isl_union_map_align_params(umap,
+					    isl_multi_pw_aff_get_space(mpa));
+	mpa = isl_multi_pw_aff_align_params(mpa, isl_union_map_get_space(umap));
+
+	if (!umap || !mpa)
+		goto error;
+
+	ctx = isl_union_map_get_ctx(umap);
+	space = isl_union_map_get_space(umap);
+	data.space = isl_multi_pw_aff_get_space(mpa);
+	data.mpa = mpa;
+	data.res = isl_union_map_alloc(space, umap->table.n);
+	data.match = match;
+	data.fn = fn;
+	if (isl_hash_table_foreach(ctx, &umap->table, &preimage_mpa_entry,
+					&data) < 0)
+		data.res = isl_union_map_free(data.res);
+
+	isl_space_free(data.space);
+	isl_union_map_free(umap);
+	isl_multi_pw_aff_free(mpa);
+	return data.res;
+error:
+	isl_union_map_free(umap);
+	isl_multi_pw_aff_free(mpa);
+	return NULL;
+}
+
+/* Compute the preimage of the domain of "umap" under the function
+ * represented by "mpa".
+ * In other words, plug in "mpa" in the domain of "umap".
+ * The result contains maps that live in the same spaces as the maps of "umap"
+ * with domain space equal to the target space of "mpa",
+ * except that the domain has been replaced by the domain space of "mpa".
+ */
+__isl_give isl_union_map *isl_union_map_preimage_domain_multi_pw_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_multi_pw_aff *mpa)
+{
+	return preimage_multi_pw_aff(umap, mpa, &domain_match,
+					&isl_map_preimage_domain_multi_pw_aff);
+}
+
+/* Internal data structure for preimage_upma.
+ *
+ * "umap" is the map of which the preimage should be computed.
+ * "res" collects the results.
+ * "fn" computes the preimage for a given piecewise multi-affine function.
+ */
+struct isl_union_map_preimage_upma_data {
+	isl_union_map *umap;
+	isl_union_map *res;
+	__isl_give isl_union_map *(*fn)(__isl_take isl_union_map *umap,
+		__isl_take isl_pw_multi_aff *pma);
+};
+
+/* Call data->fn to compute the preimage of the domain or range of data->umap
+ * under the function represented by pma and add the result to data->res.
+ */
+static isl_stat preimage_upma(__isl_take isl_pw_multi_aff *pma, void *user)
+{
+	struct isl_union_map_preimage_upma_data *data = user;
+	isl_union_map *umap;
+
+	umap = isl_union_map_copy(data->umap);
+	umap = data->fn(umap, pma);
+	data->res = isl_union_map_union(data->res, umap);
+
+	return data->res ? isl_stat_ok : isl_stat_error;
+}
+
+/* Compute the preimage of the domain or range of "umap" under the function
+ * represented by "upma".
+ * In other words, plug in "upma" in the domain or range of "umap".
+ * The function "fn" performs the actual preimage computation
+ * on a piecewise multi-affine function.
+ */
+static __isl_give isl_union_map *preimage_union_pw_multi_aff(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_union_pw_multi_aff *upma,
+	__isl_give isl_union_map *(*fn)(__isl_take isl_union_map *umap,
+		__isl_take isl_pw_multi_aff *pma))
+{
+	struct isl_union_map_preimage_upma_data data;
+
+	data.umap = umap;
+	data.res = isl_union_map_empty(isl_union_map_get_space(umap));
+	data.fn = fn;
+	if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
+						    &preimage_upma, &data) < 0)
+		data.res = isl_union_map_free(data.res);
+
+	isl_union_map_free(umap);
+	isl_union_pw_multi_aff_free(upma);
+
+	return data.res;
+}
+
+/* Compute the preimage of the domain of "umap" under the function
+ * represented by "upma".
+ * In other words, plug in "upma" in the domain of "umap".
+ * The result contains maps that live in the same spaces as the maps of "umap"
+ * with domain space equal to one of the target spaces of "upma",
+ * except that the domain has been replaced by one of the the domain spaces that
+ * corresponds to that target space of "upma".
+ */
+__isl_give isl_union_map *isl_union_map_preimage_domain_union_pw_multi_aff(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_union_pw_multi_aff *upma)
+{
+	return preimage_union_pw_multi_aff(umap, upma,
+				&isl_union_map_preimage_domain_pw_multi_aff);
+}
+
+/* Compute the preimage of the range of "umap" under the function
+ * represented by "upma".
+ * In other words, plug in "upma" in the range of "umap".
+ * The result contains maps that live in the same spaces as the maps of "umap"
+ * with range space equal to one of the target spaces of "upma",
+ * except that the range has been replaced by one of the the domain spaces that
+ * corresponds to that target space of "upma".
+ */
+__isl_give isl_union_map *isl_union_map_preimage_range_union_pw_multi_aff(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_union_pw_multi_aff *upma)
+{
+	return preimage_union_pw_multi_aff(umap, upma,
+				&isl_union_map_preimage_range_pw_multi_aff);
+}
+
+/* Compute the preimage of "uset" under the function represented by "upma".
+ * In other words, plug in "upma" in the range of "uset".
+ * The result contains sets that live in the same spaces as the sets of "uset"
+ * with space equal to one of the target spaces of "upma",
+ * except that the space has been replaced by one of the the domain spaces that
+ * corresponds to that target space of "upma".
+ */
+__isl_give isl_union_set *isl_union_set_preimage_union_pw_multi_aff(
+	__isl_take isl_union_set *uset,
+	__isl_take isl_union_pw_multi_aff *upma)
+{
+	return preimage_union_pw_multi_aff(uset, upma,
+					&isl_union_set_preimage_pw_multi_aff);
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the spaces of "umap".
+ */
+__isl_give isl_union_map *isl_union_map_reset_user(
+	__isl_take isl_union_map *umap)
+{
+	umap = isl_union_map_cow(umap);
+	if (!umap)
+		return NULL;
+	umap->dim = isl_space_reset_user(umap->dim);
+	if (!umap->dim)
+		return isl_union_map_free(umap);
+	return total(umap, &isl_map_reset_user);
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the spaces of "uset".
+ */
+__isl_give isl_union_set *isl_union_set_reset_user(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_reset_user(uset);
+}
+
+/* Remove all existentially quantified variables and integer divisions
+ * from "umap" using Fourier-Motzkin elimination.
+ */
+__isl_give isl_union_map *isl_union_map_remove_divs(
+	__isl_take isl_union_map *umap)
+{
+	return total(umap, &isl_map_remove_divs);
+}
+
+/* Remove all existentially quantified variables and integer divisions
+ * from "uset" using Fourier-Motzkin elimination.
+ */
+__isl_give isl_union_set *isl_union_set_remove_divs(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_remove_divs(uset);
+}
+
+/* Internal data structure for isl_union_map_project_out.
+ * "type", "first" and "n" are the arguments for the isl_map_project_out
+ * call.
+ * "res" collects the results.
+ */
+struct isl_union_map_project_out_data {
+	enum isl_dim_type type;
+	unsigned first;
+	unsigned n;
+
+	isl_union_map *res;
+};
+
+/* Turn the data->n dimensions of type data->type, starting at data->first
+ * into existentially quantified variables and add the result to data->res.
+ */
+static isl_stat project_out(__isl_take isl_map *map, void *user)
+{
+	struct isl_union_map_project_out_data *data = user;
+
+	map = isl_map_project_out(map, data->type, data->first, data->n);
+	data->res = isl_union_map_add_map(data->res, map);
+
+	return isl_stat_ok;
+}
+
+/* Turn the "n" dimensions of type "type", starting at "first"
+ * into existentially quantified variables.
+ * Since the space of an isl_union_map only contains parameters,
+ * type is required to be equal to isl_dim_param.
+ */
+__isl_give isl_union_map *isl_union_map_project_out(
+	__isl_take isl_union_map *umap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	isl_space *space;
+	struct isl_union_map_project_out_data data = { type, first, n };
+
+	if (!umap)
+		return NULL;
+
+	if (type != isl_dim_param)
+		isl_die(isl_union_map_get_ctx(umap), isl_error_invalid,
+			"can only project out parameters",
+			return isl_union_map_free(umap));
+
+	space = isl_union_map_get_space(umap);
+	space = isl_space_drop_dims(space, type, first, n);
+	data.res = isl_union_map_empty(space);
+	if (isl_union_map_foreach_map(umap, &project_out, &data) < 0)
+		data.res = isl_union_map_free(data.res);
+
+	isl_union_map_free(umap);
+
+	return data.res;
+}
+
+/* Turn the "n" dimensions of type "type", starting at "first"
+ * into existentially quantified variables.
+ * Since the space of an isl_union_set only contains parameters,
+ * "type" is required to be equal to isl_dim_param.
+ */
+__isl_give isl_union_set *isl_union_set_project_out(
+	__isl_take isl_union_set *uset,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return isl_union_map_project_out(uset, type, first, n);
+}
+
+/* Internal data structure for isl_union_map_involves_dims.
+ * "first" and "n" are the arguments for the isl_map_involves_dims calls.
+ */
+struct isl_union_map_involves_dims_data {
+	unsigned first;
+	unsigned n;
+};
+
+/* Does "map" _not_ involve the data->n parameters starting at data->first?
+ */
+static isl_bool map_excludes(__isl_keep isl_map *map, void *user)
+{
+	struct isl_union_map_involves_dims_data *data = user;
+	isl_bool involves;
+
+	involves = isl_map_involves_dims(map,
+					isl_dim_param, data->first, data->n);
+	if (involves < 0)
+		return isl_bool_error;
+	return !involves;
+}
+
+/* Does "umap" involve any of the n parameters starting at first?
+ * "type" is required to be set to isl_dim_param.
+ *
+ * "umap" involves any of those parameters if any of its maps
+ * involve the parameters.  In other words, "umap" does not
+ * involve any of the parameters if all its maps to not
+ * involve the parameters.
+ */
+isl_bool isl_union_map_involves_dims(__isl_keep isl_union_map *umap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	struct isl_union_map_involves_dims_data data = { first, n };
+	isl_bool excludes;
+
+	if (type != isl_dim_param)
+		isl_die(isl_union_map_get_ctx(umap), isl_error_invalid,
+			"can only reference parameters", return isl_bool_error);
+
+	excludes = union_map_forall_user(umap, &map_excludes, &data);
+
+	if (excludes < 0)
+		return isl_bool_error;
+
+	return !excludes;
+}
+
+/* Internal data structure for isl_union_map_reset_range_space.
+ * "range" is the space from which to set the range space.
+ * "res" collects the results.
+ */
+struct isl_union_map_reset_range_space_data {
+	isl_space *range;
+	isl_union_map *res;
+};
+
+/* Replace the range space of "map" by the range space of data->range and
+ * add the result to data->res.
+ */
+static isl_stat reset_range_space(__isl_take isl_map *map, void *user)
+{
+	struct isl_union_map_reset_range_space_data *data = user;
+	isl_space *space;
+
+	space = isl_map_get_space(map);
+	space = isl_space_domain(space);
+	space = isl_space_extend_domain_with_range(space,
+						isl_space_copy(data->range));
+	map = isl_map_reset_space(map, space);
+	data->res = isl_union_map_add_map(data->res, map);
+
+	return data->res ? isl_stat_ok : isl_stat_error;
+}
+
+/* Replace the range space of all the maps in "umap" by
+ * the range space of "space".
+ *
+ * This assumes that all maps have the same output dimension.
+ * This function should therefore not be made publicly available.
+ *
+ * Since the spaces of the maps change, so do their hash value.
+ * We therefore need to create a new isl_union_map.
+ */
+__isl_give isl_union_map *isl_union_map_reset_range_space(
+	__isl_take isl_union_map *umap, __isl_take isl_space *space)
+{
+	struct isl_union_map_reset_range_space_data data = { space };
+
+	data.res = isl_union_map_empty(isl_union_map_get_space(umap));
+	if (isl_union_map_foreach_map(umap, &reset_range_space, &data) < 0)
+		data.res = isl_union_map_free(data.res);
+
+	isl_space_free(space);
+	isl_union_map_free(umap);
+	return data.res;
+}
+
+/* Internal data structure for isl_union_map_order_at_multi_union_pw_aff.
+ * "mupa" is the function from which the isl_multi_pw_affs are extracted.
+ * "order" is applied to the extracted isl_multi_pw_affs that correspond
+ * to the domain and the range of each map.
+ * "res" collects the results.
+ */
+struct isl_union_order_at_data {
+	isl_multi_union_pw_aff *mupa;
+	__isl_give isl_map *(*order)(__isl_take isl_multi_pw_aff *mpa1,
+		__isl_take isl_multi_pw_aff *mpa2);
+	isl_union_map *res;
+};
+
+/* Intersect "map" with the result of applying data->order to
+ * the functions in data->mupa that apply to the domain and the range
+ * of "map" and add the result to data->res.
+ */
+static isl_stat order_at(__isl_take isl_map *map, void *user)
+{
+	struct isl_union_order_at_data *data = user;
+	isl_space *space;
+	isl_multi_pw_aff *mpa1, *mpa2;
+	isl_map *order;
+
+	space = isl_space_domain(isl_map_get_space(map));
+	mpa1 = isl_multi_union_pw_aff_extract_multi_pw_aff(data->mupa, space);
+	space = isl_space_range(isl_map_get_space(map));
+	mpa2 = isl_multi_union_pw_aff_extract_multi_pw_aff(data->mupa, space);
+	order = data->order(mpa1, mpa2);
+	map = isl_map_intersect(map, order);
+	data->res = isl_union_map_add_map(data->res, map);
+
+	return data->res ? isl_stat_ok : isl_stat_error;
+}
+
+/* Intersect each map in "umap" with the result of calling "order"
+ * on the functions is "mupa" that apply to the domain and the range
+ * of the map.
+ */
+static __isl_give isl_union_map *isl_union_map_order_at_multi_union_pw_aff(
+	__isl_take isl_union_map *umap, __isl_take isl_multi_union_pw_aff *mupa,
+	__isl_give isl_map *(*order)(__isl_take isl_multi_pw_aff *mpa1,
+		__isl_take isl_multi_pw_aff *mpa2))
+{
+	struct isl_union_order_at_data data;
+
+	umap = isl_union_map_align_params(umap,
+				isl_multi_union_pw_aff_get_space(mupa));
+	mupa = isl_multi_union_pw_aff_align_params(mupa,
+				isl_union_map_get_space(umap));
+	data.mupa = mupa;
+	data.order = order;
+	data.res = isl_union_map_empty(isl_union_map_get_space(umap));
+	if (isl_union_map_foreach_map(umap, &order_at, &data) < 0)
+		data.res = isl_union_map_free(data.res);
+
+	isl_multi_union_pw_aff_free(mupa);
+	isl_union_map_free(umap);
+	return data.res;
+}
+
+/* Return the subset of "umap" where the domain and the range
+ * have equal "mupa" values.
+ */
+__isl_give isl_union_map *isl_union_map_eq_at_multi_union_pw_aff(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_multi_union_pw_aff *mupa)
+{
+	return isl_union_map_order_at_multi_union_pw_aff(umap, mupa,
+						&isl_multi_pw_aff_eq_map);
+}
+
+/* Return the subset of "umap" where the domain has a lexicographically
+ * smaller "mupa" value than the range.
+ */
+__isl_give isl_union_map *isl_union_map_lex_lt_at_multi_union_pw_aff(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_multi_union_pw_aff *mupa)
+{
+	return isl_union_map_order_at_multi_union_pw_aff(umap, mupa,
+						&isl_multi_pw_aff_lex_lt_map);
+}
+
+/* Return the subset of "umap" where the domain has a lexicographically
+ * greater "mupa" value than the range.
+ */
+__isl_give isl_union_map *isl_union_map_lex_gt_at_multi_union_pw_aff(
+	__isl_take isl_union_map *umap,
+	__isl_take isl_multi_union_pw_aff *mupa)
+{
+	return isl_union_map_order_at_multi_union_pw_aff(umap, mupa,
+						&isl_multi_pw_aff_lex_gt_map);
+}
+
+/* Return the union of the elements in the list "list".
+ */
+__isl_give isl_union_set *isl_union_set_list_union(
+	__isl_take isl_union_set_list *list)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_space *space;
+	isl_union_set *res;
+
+	if (!list)
+		return NULL;
+
+	ctx = isl_union_set_list_get_ctx(list);
+	space = isl_space_params_alloc(ctx, 0);
+	res = isl_union_set_empty(space);
+
+	n = isl_union_set_list_n_union_set(list);
+	for (i = 0; i < n; ++i) {
+		isl_union_set *uset_i;
+
+		uset_i = isl_union_set_list_get_union_set(list, i);
+		res = isl_union_set_union(res, uset_i);
+	}
+
+	isl_union_set_list_free(list);
+	return res;
+}
+
+/* Update *hash with the hash value of "map".
+ */
+static isl_stat add_hash(__isl_take isl_map *map, void *user)
+{
+	uint32_t *hash = user;
+	uint32_t map_hash;
+
+	map_hash = isl_map_get_hash(map);
+	isl_hash_hash(*hash, map_hash);
+
+	isl_map_free(map);
+	return isl_stat_ok;
+}
+
+/* Return a hash value that digests "umap".
+ */
+uint32_t isl_union_map_get_hash(__isl_keep isl_union_map *umap)
+{
+	uint32_t hash;
+
+	if (!umap)
+		return 0;
+
+	hash = isl_hash_init();
+	if (isl_union_map_foreach_map(umap, &add_hash, &hash) < 0)
+		return 0;
+
+	return hash;
+}
+
+/* Return a hash value that digests "uset".
+ */
+uint32_t isl_union_set_get_hash(__isl_keep isl_union_set *uset)
+{
+	return isl_union_map_get_hash(uset);
+}
+
+/* Add the number of basic sets in "set" to "n".
+ */
+static isl_stat add_n(__isl_take isl_set *set, void *user)
+{
+	int *n = user;
+
+	*n += isl_set_n_basic_set(set);
+	isl_set_free(set);
+
+	return isl_stat_ok;
+}
+
+/* Return the total number of basic sets in "uset".
+ */
+int isl_union_set_n_basic_set(__isl_keep isl_union_set *uset)
+{
+	int n = 0;
+
+	if (isl_union_set_foreach_set(uset, &add_n, &n) < 0)
+		return -1;
+
+	return n;
+}
+
+/* Add the basic sets in "set" to "list".
+ */
+static isl_stat add_list(__isl_take isl_set *set, void *user)
+{
+	isl_basic_set_list **list = user;
+	isl_basic_set_list *list_i;
+
+	list_i = isl_set_get_basic_set_list(set);
+	*list = isl_basic_set_list_concat(*list, list_i);
+	isl_set_free(set);
+
+	if (!*list)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Return a list containing all the basic sets in "uset".
+ *
+ * First construct a list of the appropriate size and
+ * then add all the elements.
+ */
+__isl_give isl_basic_set_list *isl_union_set_get_basic_set_list(
+	__isl_keep isl_union_set *uset)
+{
+	int n;
+	isl_ctx *ctx;
+	isl_basic_set_list *list;
+
+	if (!uset)
+		return NULL;
+	ctx = isl_union_set_get_ctx(uset);
+	n = isl_union_set_n_basic_set(uset);
+	if (n < 0)
+		return NULL;
+	list = isl_basic_set_list_alloc(ctx, n);
+	if (isl_union_set_foreach_set(uset, &add_list, &list) < 0)
+		list = isl_basic_set_list_free(list);
+
+	return list;
+}
diff --git a/final/lib/External/isl/isl_union_map_private.h b/final/lib/External/isl/isl_union_map_private.h
new file mode 100644
index 0000000..1edd760
--- /dev/null
+++ b/final/lib/External/isl/isl_union_map_private.h
@@ -0,0 +1,16 @@
+#define isl_union_set_list	isl_union_map_list
+#define isl_union_set	isl_union_map
+#include <isl/union_map.h>
+#include <isl/union_set.h>
+
+struct isl_union_map {
+	int ref;
+	isl_space *dim;
+
+	struct isl_hash_table	table;
+};
+
+isl_bool isl_union_map_space_has_equal_params(__isl_keep isl_union_map *umap,
+	__isl_keep isl_space *space);
+__isl_give isl_union_map *isl_union_map_reset_range_space(
+	__isl_take isl_union_map *umap, __isl_take isl_space *space);
diff --git a/final/lib/External/isl/isl_union_multi.c b/final/lib/External/isl/isl_union_multi.c
new file mode 100644
index 0000000..e78e36b
--- /dev/null
+++ b/final/lib/External/isl/isl_union_multi.c
@@ -0,0 +1,465 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2013      Ecole Normale Superieure
+ * Copyright 2015      INRIA Paris-Rocquencourt
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ * and INRIA Paris-Rocquencourt, Domaine de Voluceau, Rocquenqourt, B.P. 105,
+ * 78153 Le Chesnay Cedex France
+ */
+
+#include <isl_hash_private.h>
+#include <isl_union_macro.h>
+
+/* A group of expressions defined over the same domain space "domain_space".
+ * The entries of "part_table" are the individual expressions,
+ * keyed on the entire space of the expression.
+ *
+ * Each UNION has its own groups, so there can only ever be a single
+ * reference to each group.
+ */
+S(UNION,group) {
+	isl_space *domain_space;
+	struct isl_hash_table	part_table;
+};
+
+/* A union of expressions defined over different disjoint domains.
+ * "space" describes the parameters.
+ * The entries of "table" are keyed on the domain space of the entry and
+ * contain groups of expressions that are defined over the same domain space.
+ */
+struct UNION {
+	int ref;
+	isl_space *space;
+
+	struct isl_hash_table	table;
+};
+
+/* Internal data structure for isl_union_*_foreach_group.
+ * "fn" is the function that needs to be called on each group.
+ */
+S(UNION,foreach_group_data)
+{
+	isl_stat (*fn)(__isl_keep S(UNION,group) *group, void *user);
+	void *user;
+};
+
+/* Call data->fn on the group stored at *entry.
+ */
+static isl_stat FN(UNION,call_on_group)(void **entry, void *user)
+{
+	S(UNION,group) *group = *entry;
+	S(UNION,foreach_group_data) *data;
+
+	data = (S(UNION,foreach_group_data) *) user;
+	return data->fn(group, data->user);
+}
+
+/* Call "fn" on each group of expressions in "u".
+ */
+static isl_stat FN(UNION,foreach_group)(__isl_keep UNION *u,
+	isl_stat (*fn)(__isl_keep S(UNION,group) *group, void *user),
+	void *user)
+{
+	S(UNION,foreach_group_data) data = { fn, user };
+
+	if (!u)
+		return isl_stat_error;
+
+	return isl_hash_table_foreach(u->space->ctx, &u->table,
+				      &FN(UNION,call_on_group), &data);
+}
+
+/* A isl_union_*_foreach_group callback for counting the total number
+ * of expressions in a UNION.  Add the number of expressions in "group"
+ * to *n.
+ */
+static isl_stat FN(UNION,count_part)(__isl_keep S(UNION,group) *group,
+	void *user)
+{
+	int *n = user;
+
+	if (!group)
+		return isl_stat_error;
+
+	*n += group->part_table.n;
+	return isl_stat_ok;
+}
+
+/* Return the number of base expressions in "u".
+ */
+int FN(FN(UNION,n),PARTS)(__isl_keep UNION *u)
+{
+	int n;
+
+	n = 0;
+	if (FN(UNION,foreach_group)(u, &FN(UNION,count_part), &n) < 0)
+		n = -1;
+	return n;
+}
+
+/* Free an entry in a group of expressions.
+ * Each entry in such a group is a single expression.
+ */
+static isl_stat FN(UNION,free_group_entry)(void **entry, void *user)
+{
+	PART *part = *entry;
+
+	FN(PART,free)(part);
+	return isl_stat_ok;
+}
+
+/* Free all memory allocated for "group" and return NULL.
+ */
+static __isl_null S(UNION,group) *FN(UNION,group_free)(
+	__isl_take S(UNION,group) *group)
+{
+	isl_ctx *ctx;
+
+	if (!group)
+		return NULL;
+
+	ctx = isl_space_get_ctx(group->domain_space);
+	isl_hash_table_foreach(ctx, &group->part_table,
+				&FN(UNION,free_group_entry), NULL);
+	isl_hash_table_clear(&group->part_table);
+	isl_space_free(group->domain_space);
+	free(group);
+	return NULL;
+}
+
+/* Allocate a group of expressions defined over the same domain space
+ * with domain space "domain_space" and initial size "size".
+ */
+static __isl_give S(UNION,group) *FN(UNION,group_alloc)(
+	__isl_take isl_space *domain_space, int size)
+{
+	isl_ctx *ctx;
+	S(UNION,group) *group;
+
+	if (!domain_space)
+		return NULL;
+	ctx = isl_space_get_ctx(domain_space);
+	group = isl_calloc_type(ctx, S(UNION,group));
+	if (!group)
+		goto error;
+	group->domain_space = domain_space;
+	if (isl_hash_table_init(ctx, &group->part_table, size) < 0)
+		return FN(UNION,group_free)(group);
+
+	return group;
+error:
+	isl_space_free(domain_space);
+	return NULL;
+}
+
+/* Is the space of "entry" equal to "space"?
+ */
+static int FN(UNION,has_space)(const void *entry, const void *val)
+{
+	PART *part = (PART *) entry;
+	isl_space *space = (isl_space *) val;
+
+	return isl_space_is_equal(part->dim, space);
+}
+
+/* Return a group equal to "group", but with a single reference.
+ * Since all groups have only a single reference, simply return "group".
+ */
+static __isl_give S(UNION,group) *FN(UNION,group_cow)(
+	__isl_take S(UNION,group) *group)
+{
+	return group;
+}
+
+S(UNION,foreach_data)
+{
+	isl_stat (*fn)(__isl_take PART *part, void *user);
+	void *user;
+};
+
+static isl_stat FN(UNION,call_on_copy)(void **entry, void *user)
+{
+	PART *part = *entry;
+	S(UNION,foreach_data) *data = (S(UNION,foreach_data) *) user;
+
+	part = FN(PART,copy)(part);
+	if (!part)
+		return isl_stat_error;
+	return data->fn(part, data->user);
+}
+
+/* Call data->fn on a copy of each expression in "group".
+ */
+static isl_stat FN(UNION,group_call_on_copy)(__isl_keep S(UNION,group) *group,
+	void *user)
+{
+	isl_ctx *ctx;
+
+	if (!group)
+		return isl_stat_error;
+
+	ctx = isl_space_get_ctx(group->domain_space);
+	return isl_hash_table_foreach(ctx, &group->part_table,
+				      &FN(UNION,call_on_copy), user);
+}
+
+isl_stat FN(FN(UNION,foreach),PARTS)(__isl_keep UNION *u,
+	isl_stat (*fn)(__isl_take PART *part, void *user), void *user)
+{
+	S(UNION,foreach_data) data = { fn, user };
+
+	if (!u)
+		return isl_stat_error;
+
+	return FN(UNION,foreach_group)(u, &FN(UNION,group_call_on_copy), &data);
+}
+
+/* Is the domain space of the group of expressions at "entry"
+ * equal to "space"?
+ */
+static int FN(UNION,group_has_domain_space)(const void *entry, const void *val)
+{
+	S(UNION,group) *group = (S(UNION,group) *) entry;
+	isl_space *space = (isl_space *) val;
+
+	return isl_space_is_domain_internal(group->domain_space, space);
+}
+
+/* Return the entry, if any, in "u" that lives in "space".
+ * If "reserve" is set, then an entry is created if it does not exist yet.
+ * Return NULL on error and isl_hash_table_entry_none if no entry was found.
+ * Note that when "reserve" is set, the function will never return
+ * isl_hash_table_entry_none.
+ *
+ * First look for the group of expressions with the same domain space,
+ * creating one if needed.
+ * Then look for the expression living in the specified space in that group.
+ */
+static struct isl_hash_table_entry *FN(UNION,find_part_entry)(
+	__isl_keep UNION *u, __isl_keep isl_space *space, int reserve)
+{
+	isl_ctx *ctx;
+	uint32_t hash;
+	struct isl_hash_table_entry *group_entry, *part_entry;
+	S(UNION,group) *group;
+
+	if (!u || !space)
+		return NULL;
+
+	ctx = FN(UNION,get_ctx)(u);
+	hash = isl_space_get_domain_hash(space);
+	group_entry = isl_hash_table_find(ctx, &u->table, hash,
+			    &FN(UNION,group_has_domain_space), space, reserve);
+	if (!group_entry)
+		return reserve ? NULL : isl_hash_table_entry_none;
+	if (reserve && !group_entry->data) {
+		isl_space *domain = isl_space_domain(isl_space_copy(space));
+		group = FN(UNION,group_alloc)(domain, 1);
+		group_entry->data = group;
+	} else {
+		group = group_entry->data;
+		if (reserve)
+			group = FN(UNION,group_cow)(group);
+	}
+	if (!group)
+		return NULL;
+	hash = isl_space_get_hash(space);
+	part_entry = isl_hash_table_find(ctx, &group->part_table, hash,
+				&FN(UNION,has_space), space, reserve);
+	if (!reserve && !part_entry)
+		return isl_hash_table_entry_none;
+	return part_entry;
+}
+
+/* Remove "part_entry" from the hash table of "u".
+ *
+ * First look the group_entry in "u" holding the group that
+ * contains "part_entry".  Remove "part_entry" from that group.
+ * If the group becomes empty, then also remove the group_entry from "u".
+ */
+static __isl_give UNION *FN(UNION,remove_part_entry)(__isl_take UNION *u,
+	struct isl_hash_table_entry *part_entry)
+{
+	isl_ctx *ctx;
+	uint32_t hash;
+	PART *part;
+	struct isl_hash_table_entry *group_entry;
+	S(UNION,group) *group;
+
+	if (!u || !part_entry)
+		return FN(UNION,free)(u);
+
+	part = part_entry->data;
+	ctx = FN(UNION,get_ctx)(u);
+	hash = isl_space_get_domain_hash(part->dim);
+	group_entry = isl_hash_table_find(ctx, &u->table, hash,
+			    &FN(UNION,group_has_domain_space), part->dim, 0);
+	if (!group_entry)
+		isl_die(ctx, isl_error_internal, "missing group",
+			return FN(UNION,free)(u));
+	group = group_entry->data;
+	isl_hash_table_remove(ctx, &group->part_table, part_entry);
+	FN(PART,free)(part);
+
+	if (group->part_table.n != 0)
+		return u;
+
+	isl_hash_table_remove(ctx, &u->table, group_entry);
+	FN(UNION,group_free)(group);
+
+	return u;
+}
+
+/* Are the domains of "part1" and "part2" disjoint?
+ */
+static isl_bool FN(UNION,disjoint_domain)(__isl_keep PART *part1,
+	__isl_keep PART *part2)
+{
+	isl_set *dom1, *dom2;
+	isl_bool disjoint;
+
+	if (!part1 || !part2)
+		return isl_bool_error;
+	dom1 = FN(PART,domain)(FN(PART,copy)(part1));
+	dom2 = FN(PART,domain)(FN(PART,copy)(part2));
+	disjoint = isl_set_is_disjoint(dom1, dom2);
+	isl_set_free(dom1);
+	isl_set_free(dom2);
+
+	return disjoint;
+}
+
+/* Check that the expression at *entry has a domain that is disjoint
+ * from that of "part", unless they also have the same target space.
+ */
+static isl_stat FN(UNION,check_disjoint_domain_entry)(void **entry, void *user)
+{
+	PART *part = user;
+	PART *other = *entry;
+	isl_bool equal;
+	isl_bool disjoint;
+
+	equal = isl_space_is_equal(part->dim, other->dim);
+	if (equal < 0)
+		return isl_stat_error;
+	if (equal)
+		return isl_stat_ok;
+
+	disjoint = FN(UNION,disjoint_domain)(part, other);
+	if (disjoint < 0)
+		return isl_stat_error;
+	if (!disjoint)
+		isl_die(FN(PART,get_ctx)(part), isl_error_invalid,
+			"overlapping domain with other part",
+			return isl_stat_error);
+	return isl_stat_ok;
+}
+
+/* Check that the domain of "part" is disjoint from the domain of the entries
+ * in "u" that are defined on the same domain space, but have a different
+ * target space.
+ * If there is no group of expressions in "u" with the same domain space,
+ * then everything is fine.  Otherwise, check the individual expressions
+ * in that group.
+ */
+static isl_stat FN(UNION,check_disjoint_domain_other)(__isl_keep UNION *u,
+	__isl_keep PART *part)
+{
+	isl_ctx *ctx;
+	uint32_t hash;
+	struct isl_hash_table_entry *group_entry;
+	S(UNION,group) *group;
+
+	if (!u || !part)
+		return isl_stat_error;
+	ctx = FN(UNION,get_ctx)(u);
+	hash = isl_space_get_domain_hash(part->dim);
+	group_entry = isl_hash_table_find(ctx, &u->table, hash,
+			    &FN(UNION,group_has_domain_space), part->dim, 0);
+	if (!group_entry)
+		return isl_stat_ok;
+	group = group_entry->data;
+	return isl_hash_table_foreach(ctx, &group->part_table,
+			      &FN(UNION,check_disjoint_domain_entry), part);
+}
+
+/* Check that the domain of "part1" is disjoint from the domain of "part2".
+ * This check is performed before "part2" is added to a UNION to ensure
+ * that the UNION expression remains a function.
+ */
+static isl_stat FN(UNION,check_disjoint_domain)(__isl_keep PART *part1,
+	__isl_keep PART *part2)
+{
+	isl_bool disjoint;
+
+	disjoint = FN(UNION,disjoint_domain)(part1, part2);
+	if (disjoint < 0)
+		return isl_stat_error;
+	if (!disjoint)
+		isl_die(FN(PART,get_ctx)(part1), isl_error_invalid,
+			"domain of additional part should be disjoint",
+			return isl_stat_error);
+	return isl_stat_ok;
+}
+
+/* Internal data structure for isl_union_*_foreach_inplace.
+ * "fn" is the function that needs to be called on each entry.
+ */
+S(UNION,foreach_inplace_data)
+{
+	isl_stat (*fn)(void **entry, void *user);
+	void *user;
+};
+
+/* isl_union_*_foreach_group callback for calling data->fn on
+ * each part entry in the group.
+ */
+static isl_stat FN(UNION,group_call_inplace)(__isl_keep S(UNION,group) *group,
+	void *user)
+{
+	isl_ctx *ctx;
+	S(UNION,foreach_inplace_data) *data;
+
+	if (!group)
+		return isl_stat_error;
+
+	data = (S(UNION,foreach_inplace_data) *) user;
+	ctx = isl_space_get_ctx(group->domain_space);
+	return isl_hash_table_foreach(ctx, &group->part_table,
+				      data->fn, data->user);
+}
+
+/* Call "fn" on each part entry of "u".
+ */
+static isl_stat FN(UNION,foreach_inplace)(__isl_keep UNION *u,
+	isl_stat (*fn)(void **part, void *user), void *user)
+{
+	S(UNION,foreach_inplace_data) data = { fn, user };
+
+	return FN(UNION,foreach_group)(u, &FN(UNION,group_call_inplace), &data);
+}
+
+/* Does "u" have a single reference?
+ * That is, can we change "u" inplace?
+ */
+static isl_bool FN(UNION,has_single_reference)(__isl_keep UNION *u)
+{
+	if (!u)
+		return isl_bool_error;
+	return u->ref == 1;
+}
+
+static isl_stat FN(UNION,free_u_entry)(void **entry, void *user)
+{
+	S(UNION,group) *group = *entry;
+	FN(UNION,group_free)(group);
+	return isl_stat_ok;
+}
+
+#include <isl_union_templ.c>
diff --git a/final/lib/External/isl/isl_union_neg.c b/final/lib/External/isl/isl_union_neg.c
new file mode 100644
index 0000000..386b8dc
--- /dev/null
+++ b/final/lib/External/isl/isl_union_neg.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ */
+
+#include <isl_union_macro.h>
+
+/* Return the opposite of "part".
+ */
+static __isl_give PART *FN(UNION,neg_entry)(__isl_take PART *part, void *user)
+{
+	return FN(PART,neg)(part);
+}
+
+/* Return the opposite of "u".
+ */
+__isl_give UNION *FN(UNION,neg)(__isl_take UNION *u)
+{
+	return FN(UNION,transform_inplace)(u, &FN(UNION,neg_entry), NULL);
+}
diff --git a/final/lib/External/isl/isl_union_set_private.h b/final/lib/External/isl/isl_union_set_private.h
new file mode 100644
index 0000000..32a7073
--- /dev/null
+++ b/final/lib/External/isl/isl_union_set_private.h
@@ -0,0 +1,11 @@
+#ifndef ISL_UNION_SET_PRIVATE_H
+#define ISL_UNION_SET_PRIVATE_H
+
+#include <isl/union_set.h>
+
+__isl_give isl_union_set *isl_union_set_combined_lineality_space(
+	__isl_take isl_union_set *uset);
+__isl_give isl_union_set *isl_union_set_plain_gist(
+	__isl_take isl_union_set *uset, __isl_take isl_union_set *context);
+
+#endif
diff --git a/final/lib/External/isl/isl_union_single.c b/final/lib/External/isl/isl_union_single.c
new file mode 100644
index 0000000..d365aae
--- /dev/null
+++ b/final/lib/External/isl/isl_union_single.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2013      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_hash_private.h>
+#include <isl_union_macro.h>
+
+/* A union of expressions defined over different domain spaces.
+ * "space" describes the parameters.
+ * The entries of "table" are keyed on the domain space of the entry.
+ */
+struct UNION {
+	int ref;
+#ifdef HAS_TYPE
+	enum isl_fold type;
+#endif
+	isl_space *space;
+
+	struct isl_hash_table	table;
+};
+
+/* Return the number of base expressions in "u".
+ */
+int FN(FN(UNION,n),PARTS)(__isl_keep UNION *u)
+{
+	return u ? u->table.n : 0;
+}
+
+S(UNION,foreach_data)
+{
+	isl_stat (*fn)(__isl_take PART *part, void *user);
+	void *user;
+};
+
+static isl_stat FN(UNION,call_on_copy)(void **entry, void *user)
+{
+	PART *part = *entry;
+	S(UNION,foreach_data) *data = (S(UNION,foreach_data) *)user;
+
+	part = FN(PART,copy)(part);
+	if (!part)
+		return isl_stat_error;
+	return data->fn(part, data->user);
+}
+
+isl_stat FN(FN(UNION,foreach),PARTS)(__isl_keep UNION *u,
+	isl_stat (*fn)(__isl_take PART *part, void *user), void *user)
+{
+	S(UNION,foreach_data) data = { fn, user };
+
+	if (!u)
+		return isl_stat_error;
+
+	return isl_hash_table_foreach(u->space->ctx, &u->table,
+				      &FN(UNION,call_on_copy), &data);
+}
+
+/* Is the domain space of "entry" equal to the domain of "space"?
+ */
+static int FN(UNION,has_same_domain_space)(const void *entry, const void *val)
+{
+	PART *part = (PART *)entry;
+	isl_space *space = (isl_space *) val;
+
+	if (isl_space_is_set(space))
+		return isl_space_is_set(part->dim);
+
+	return isl_space_tuple_is_equal(part->dim, isl_dim_in,
+					space, isl_dim_in);
+}
+
+/* Return the entry, if any, in "u" that lives in "space".
+ * If "reserve" is set, then an entry is created if it does not exist yet.
+ * Return NULL on error and isl_hash_table_entry_none if no entry was found.
+ * Note that when "reserve" is set, the function will never return
+ * isl_hash_table_entry_none.
+ *
+ * First look for the entry (if any) with the same domain space.
+ * If it exists, then check if the range space also matches.
+ */
+static struct isl_hash_table_entry *FN(UNION,find_part_entry)(
+	__isl_keep UNION *u, __isl_keep isl_space *space, int reserve)
+{
+	isl_ctx *ctx;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry;
+	isl_bool equal;
+	PART *part;
+
+	if (!u || !space)
+		return NULL;
+
+	ctx = FN(UNION,get_ctx)(u);
+	hash = isl_space_get_domain_hash(space);
+	entry = isl_hash_table_find(ctx, &u->table, hash,
+			&FN(UNION,has_same_domain_space), space, reserve);
+	if (!entry)
+		return reserve ? NULL : isl_hash_table_entry_none;
+	if (reserve && !entry->data)
+		return entry;
+	part = entry->data;
+	equal = isl_space_tuple_is_equal(part->dim, isl_dim_out,
+					    space, isl_dim_out);
+	if (equal < 0)
+		return NULL;
+	if (equal)
+		return entry;
+	if (!reserve)
+		return isl_hash_table_entry_none;
+	isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
+		"union expression can only contain a single "
+		"expression over a given domain", return NULL);
+}
+
+/* Remove "part_entry" from the hash table of "u".
+ */
+static __isl_give UNION *FN(UNION,remove_part_entry)(__isl_take UNION *u,
+	struct isl_hash_table_entry *part_entry)
+{
+	isl_ctx *ctx;
+
+	if (!u || !part_entry)
+		return FN(UNION,free)(u);
+
+	ctx = FN(UNION,get_ctx)(u);
+	isl_hash_table_remove(ctx, &u->table, part_entry);
+	FN(PART,free)(part_entry->data);
+
+	return u;
+}
+
+/* Check that the domain of "part" is disjoint from the domain of the entries
+ * in "u" that are defined on the same domain space, but have a different
+ * target space.
+ * Since a UNION with a single entry per domain space is not allowed
+ * to contain two entries with the same domain space, there cannot be
+ * any such other entry.
+ */
+static isl_stat FN(UNION,check_disjoint_domain_other)(__isl_keep UNION *u,
+	__isl_keep PART *part)
+{
+	return isl_stat_ok;
+}
+
+/* Check that the domain of "part1" is disjoint from the domain of "part2".
+ * This check is performed before "part2" is added to a UNION to ensure
+ * that the UNION expression remains a function.
+ * Since a UNION with a single entry per domain space is not allowed
+ * to contain two entries with the same domain space, fail unconditionally.
+ */
+static isl_stat FN(UNION,check_disjoint_domain)(__isl_keep PART *part1,
+	__isl_keep PART *part2)
+{
+	isl_die(FN(PART,get_ctx)(part1), isl_error_invalid,
+		"additional part should live on separate space",
+		return isl_stat_error);
+}
+
+/* Call "fn" on each part entry of "u".
+ */
+static isl_stat FN(UNION,foreach_inplace)(__isl_keep UNION *u,
+	isl_stat (*fn)(void **part, void *user), void *user)
+{
+	isl_ctx *ctx;
+
+	if (!u)
+		return isl_stat_error;
+	ctx = FN(UNION,get_ctx)(u);
+	return isl_hash_table_foreach(ctx, &u->table, fn, user);
+}
+
+/* Does "u" have a single reference?
+ * That is, can we change "u" inplace?
+ */
+static isl_bool FN(UNION,has_single_reference)(__isl_keep UNION *u)
+{
+	if (!u)
+		return isl_bool_error;
+	return u->ref == 1;
+}
+
+static isl_stat FN(UNION,free_u_entry)(void **entry, void *user)
+{
+	PART *part = *entry;
+	FN(PART,free)(part);
+	return isl_stat_ok;
+}
+
+#include <isl_union_templ.c>
diff --git a/final/lib/External/isl/isl_union_templ.c b/final/lib/External/isl/isl_union_templ.c
new file mode 100644
index 0000000..85f0570
--- /dev/null
+++ b/final/lib/External/isl/isl_union_templ.c
@@ -0,0 +1,1204 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2013      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France 
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+__isl_give UNION *FN(UNION,cow)(__isl_take UNION *u);
+
+isl_ctx *FN(UNION,get_ctx)(__isl_keep UNION *u)
+{
+	return u ? u->space->ctx : NULL;
+}
+
+__isl_give isl_space *FN(UNION,get_space)(__isl_keep UNION *u)
+{
+	if (!u)
+		return NULL;
+	return isl_space_copy(u->space);
+}
+
+/* Return the number of parameters of "u", where "type"
+ * is required to be set to isl_dim_param.
+ */
+unsigned FN(UNION,dim)(__isl_keep UNION *u, enum isl_dim_type type)
+{
+	if (!u)
+		return 0;
+
+	if (type != isl_dim_param)
+		isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
+			"can only reference parameters", return 0);
+
+	return isl_space_dim(u->space, type);
+}
+
+/* Return the position of the parameter with the given name
+ * in "u".
+ * Return -1 if no such dimension can be found.
+ */
+int FN(UNION,find_dim_by_name)(__isl_keep UNION *u, enum isl_dim_type type,
+	const char *name)
+{
+	if (!u)
+		return -1;
+	return isl_space_find_dim_by_name(u->space, type, name);
+}
+
+#ifdef HAS_TYPE
+static __isl_give UNION *FN(UNION,alloc)(__isl_take isl_space *dim,
+	enum isl_fold type, int size)
+#else
+static __isl_give UNION *FN(UNION,alloc)(__isl_take isl_space *dim, int size)
+#endif
+{
+	UNION *u;
+
+	dim = isl_space_params(dim);
+	if (!dim)
+		return NULL;
+
+	u = isl_calloc_type(dim->ctx, UNION);
+	if (!u)
+		goto error;
+
+	u->ref = 1;
+#ifdef HAS_TYPE
+	u->type = type;
+#endif
+	u->space = dim;
+	if (isl_hash_table_init(dim->ctx, &u->table, size) < 0)
+		return FN(UNION,free)(u);
+
+	return u;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+#ifdef HAS_TYPE
+__isl_give UNION *FN(UNION,ZERO)(__isl_take isl_space *dim, enum isl_fold type)
+{
+	return FN(UNION,alloc)(dim, type, 16);
+}
+#else
+__isl_give UNION *FN(UNION,ZERO)(__isl_take isl_space *dim)
+{
+	return FN(UNION,alloc)(dim, 16);
+}
+#endif
+
+__isl_give UNION *FN(UNION,copy)(__isl_keep UNION *u)
+{
+	if (!u)
+		return NULL;
+
+	u->ref++;
+	return u;
+}
+
+/* Extract the element of "u" living in "space" (ignoring parameters).
+ *
+ * Return the ZERO element if "u" does not contain any element
+ * living in "space".
+ */
+__isl_give PART *FN(FN(UNION,extract),PARTS)(__isl_keep UNION *u,
+	__isl_take isl_space *space)
+{
+	struct isl_hash_table_entry *entry;
+	isl_bool equal_params;
+
+	if (!u || !space)
+		goto error;
+	equal_params = isl_space_has_equal_params(u->space, space);
+	if (equal_params < 0)
+		goto error;
+	if (!equal_params) {
+		space = isl_space_drop_dims(space, isl_dim_param,
+					0, isl_space_dim(space, isl_dim_param));
+		space = isl_space_align_params(space,
+					FN(UNION,get_space)(u));
+		if (!space)
+			goto error;
+	}
+
+	entry = FN(UNION,find_part_entry)(u, space, 0);
+	if (!entry)
+		goto error;
+	if (entry == isl_hash_table_entry_none)
+#ifdef HAS_TYPE
+		return FN(PART,ZERO)(space, u->type);
+#else
+		return FN(PART,ZERO)(space);
+#endif
+	isl_space_free(space);
+	return FN(PART,copy)(entry->data);
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Add "part" to "u".
+ * If "disjoint" is set, then "u" is not allowed to already have
+ * a part that is defined over a domain that overlaps with the domain
+ * of "part".
+ * Otherwise, compute the union sum of "part" and the part in "u"
+ * defined on the same space.
+ */
+static __isl_give UNION *FN(UNION,add_part_generic)(__isl_take UNION *u,
+	__isl_take PART *part, int disjoint)
+{
+	int empty;
+	struct isl_hash_table_entry *entry;
+
+	if (!part)
+		goto error;
+
+	empty = FN(PART,IS_ZERO)(part);
+	if (empty < 0)
+		goto error;
+	if (empty) {
+		FN(PART,free)(part);
+		return u;
+	}
+
+	u = FN(UNION,align_params)(u, FN(PART,get_space)(part));
+	part = FN(PART,align_params)(part, FN(UNION,get_space)(u));
+
+	u = FN(UNION,cow)(u);
+
+	if (!u)
+		goto error;
+
+	if (FN(UNION,check_disjoint_domain_other)(u, part) < 0)
+		goto error;
+	entry = FN(UNION,find_part_entry)(u, part->dim, 1);
+	if (!entry)
+		goto error;
+
+	if (!entry->data)
+		entry->data = part;
+	else {
+		if (disjoint &&
+		    FN(UNION,check_disjoint_domain)(entry->data, part) < 0)
+			goto error;
+		entry->data = FN(PART,union_add_)(entry->data,
+						FN(PART,copy)(part));
+		if (!entry->data)
+			goto error;
+		empty = FN(PART,IS_ZERO)(part);
+		if (empty < 0)
+			goto error;
+		if (empty)
+			u = FN(UNION,remove_part_entry)(u, entry);
+		FN(PART,free)(part);
+	}
+
+	return u;
+error:
+	FN(PART,free)(part);
+	FN(UNION,free)(u);
+	return NULL;
+}
+
+/* Add "part" to "u", where "u" is assumed not to already have
+ * a part that is defined on the same space as "part".
+ */
+__isl_give UNION *FN(FN(UNION,add),PARTS)(__isl_take UNION *u,
+	__isl_take PART *part)
+{
+	return FN(UNION,add_part_generic)(u, part, 1);
+}
+
+#ifdef HAS_TYPE
+/* Allocate a UNION with the same type and the same size as "u" and
+ * with space "space".
+ */
+static __isl_give UNION *FN(UNION,alloc_same_size_on_space)(__isl_keep UNION *u,
+	__isl_take isl_space *space)
+{
+	if (!u)
+		goto error;
+	return FN(UNION,alloc)(space, u->type, u->table.n);
+error:
+	isl_space_free(space);
+	return NULL;
+}
+#else
+/* Allocate a UNION with the same size as "u" and with space "space".
+ */
+static __isl_give UNION *FN(UNION,alloc_same_size_on_space)(__isl_keep UNION *u,
+	__isl_take isl_space *space)
+{
+	if (!u)
+		goto error;
+	return FN(UNION,alloc)(space, u->table.n);
+error:
+	isl_space_free(space);
+	return NULL;
+}
+#endif
+
+/* Allocate a UNION with the same space, the same type (if any) and
+ * the same size as "u".
+ */
+static __isl_give UNION *FN(UNION,alloc_same_size)(__isl_keep UNION *u)
+{
+	return FN(UNION,alloc_same_size_on_space)(u, FN(UNION,get_space)(u));
+}
+
+/* Internal data structure for isl_union_*_transform_space.
+ * "fn' is applied to each entry in the input.
+ * "res" collects the results.
+ */
+S(UNION,transform_data)
+{
+	__isl_give PART *(*fn)(__isl_take PART *part, void *user);
+	void *user;
+
+	UNION *res;
+};
+
+/* Apply data->fn to "part" and add the result to data->res.
+ */
+static isl_stat FN(UNION,transform_entry)(__isl_take PART *part, void *user)
+{
+	S(UNION,transform_data) *data = (S(UNION,transform_data) *)user;
+
+	part = data->fn(part, data->user);
+	data->res = FN(FN(UNION,add),PARTS)(data->res, part);
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Return a UNION living in "space" that is obtained by applying "fn"
+ * to each of the entries in "u".
+ */
+static __isl_give UNION *FN(UNION,transform_space)(__isl_take UNION *u,
+	isl_space *space,
+	__isl_give PART *(*fn)(__isl_take PART *part, void *user), void *user)
+{
+	S(UNION,transform_data) data = { fn, user };
+
+	data.res = FN(UNION,alloc_same_size_on_space)(u, space);
+	if (FN(FN(UNION,foreach),PARTS)(u,
+					&FN(UNION,transform_entry), &data) < 0)
+		data.res = FN(UNION,free)(data.res);
+	FN(UNION,free)(u);
+	return data.res;
+}
+
+/* Return a UNION that lives in the same space as "u" and that is obtained
+ * by applying "fn" to each of the entries in "u".
+ */
+static __isl_give UNION *FN(UNION,transform)(__isl_take UNION *u,
+	__isl_give PART *(*fn)(__isl_take PART *part, void *user), void *user)
+{
+	return FN(UNION,transform_space)(u, FN(UNION,get_space)(u), fn, user);
+}
+
+/* Apply data->fn to *part and store the result back into *part.
+ */
+static isl_stat FN(UNION,transform_inplace_entry)(void **part, void *user)
+{
+	S(UNION,transform_data) *data = (S(UNION,transform_data) *) user;
+
+	*part = data->fn(*part, data->user);
+	if (!*part)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Update "u" by applying "fn" to each entry.
+ * This operation is assumed not to change the number of entries nor
+ * the spaces of the entries.
+ *
+ * If there is only one reference to "u", then change "u" inplace.
+ * Otherwise, create a new UNION from "u" and discard the original.
+ */
+static __isl_give UNION *FN(UNION,transform_inplace)(__isl_take UNION *u,
+	__isl_give PART *(*fn)(__isl_take PART *part, void *user), void *user)
+{
+	isl_bool single_ref;
+
+	single_ref = FN(UNION,has_single_reference)(u);
+	if (single_ref < 0)
+		return FN(UNION,free)(u);
+	if (single_ref) {
+		S(UNION,transform_data) data = { fn, user };
+		if (FN(UNION,foreach_inplace)(u,
+				&FN(UNION,transform_inplace_entry), &data) < 0)
+			return FN(UNION,free)(u);
+		return u;
+	}
+	return FN(UNION,transform)(u, fn, user);
+}
+
+/* An isl_union_*_transform callback for use in isl_union_*_dup
+ * that simply returns "part".
+ */
+static __isl_give PART *FN(UNION,copy_part)(__isl_take PART *part, void *user)
+{
+	return part;
+}
+
+__isl_give UNION *FN(UNION,dup)(__isl_keep UNION *u)
+{
+	u = FN(UNION,copy)(u);
+	return FN(UNION,transform)(u, &FN(UNION,copy_part), NULL);
+}
+
+__isl_give UNION *FN(UNION,cow)(__isl_take UNION *u)
+{
+	if (!u)
+		return NULL;
+
+	if (u->ref == 1)
+		return u;
+	u->ref--;
+	return FN(UNION,dup)(u);
+}
+
+__isl_null UNION *FN(UNION,free)(__isl_take UNION *u)
+{
+	if (!u)
+		return NULL;
+
+	if (--u->ref > 0)
+		return NULL;
+
+	isl_hash_table_foreach(u->space->ctx, &u->table,
+				&FN(UNION,free_u_entry), NULL);
+	isl_hash_table_clear(&u->table);
+	isl_space_free(u->space);
+	free(u);
+	return NULL;
+}
+
+static __isl_give PART *FN(UNION,align_entry)(__isl_take PART *part, void *user)
+{
+	isl_reordering *exp = user;
+
+	exp = isl_reordering_extend_space(isl_reordering_copy(exp),
+				    FN(PART,get_domain_space)(part));
+	return FN(PART,realign_domain)(part, exp);
+}
+
+/* Reorder the parameters of "u" according to the given reordering.
+ */
+static __isl_give UNION *FN(UNION,realign_domain)(__isl_take UNION *u,
+	__isl_take isl_reordering *r)
+{
+	isl_space *space;
+
+	if (!u || !r)
+		goto error;
+
+	space = isl_space_copy(r->dim);
+	u = FN(UNION,transform_space)(u, space, &FN(UNION,align_entry), r);
+	isl_reordering_free(r);
+	return u;
+error:
+	FN(UNION,free)(u);
+	isl_reordering_free(r);
+	return NULL;
+}
+
+/* Align the parameters of "u" to those of "model".
+ */
+__isl_give UNION *FN(UNION,align_params)(__isl_take UNION *u,
+	__isl_take isl_space *model)
+{
+	isl_bool equal_params;
+	isl_reordering *r;
+
+	if (!u || !model)
+		goto error;
+
+	equal_params = isl_space_has_equal_params(u->space, model);
+	if (equal_params < 0)
+		goto error;
+	if (equal_params) {
+		isl_space_free(model);
+		return u;
+	}
+
+	model = isl_space_params(model);
+	r = isl_parameter_alignment_reordering(u->space, model);
+	isl_space_free(model);
+
+	return FN(UNION,realign_domain)(u, r);
+error:
+	isl_space_free(model);
+	FN(UNION,free)(u);
+	return NULL;
+}
+
+/* Add "part" to *u, taking the union sum if "u" already has
+ * a part defined on the same space as "part".
+ */
+static isl_stat FN(UNION,union_add_part)(__isl_take PART *part, void *user)
+{
+	UNION **u = (UNION **)user;
+
+	*u = FN(UNION,add_part_generic)(*u, part, 0);
+
+	return isl_stat_ok;
+}
+
+/* Compute the sum of "u1" and "u2" on the union of their domains,
+ * with the actual sum on the shared domain and
+ * the defined expression on the symmetric difference of the domains.
+ *
+ * This is an internal function that is exposed under different
+ * names depending on whether the base expressions have a zero default
+ * value.
+ * If they do, then this function is called "add".
+ * Otherwise, it is called "union_add".
+ */
+static __isl_give UNION *FN(UNION,union_add_)(__isl_take UNION *u1,
+	__isl_take UNION *u2)
+{
+	u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2));
+	u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1));
+
+	u1 = FN(UNION,cow)(u1);
+
+	if (!u1 || !u2)
+		goto error;
+
+	if (FN(FN(UNION,foreach),PARTS)(u2, &FN(UNION,union_add_part), &u1) < 0)
+		goto error;
+
+	FN(UNION,free)(u2);
+
+	return u1;
+error:
+	FN(UNION,free)(u1);
+	FN(UNION,free)(u2);
+	return NULL;
+}
+
+__isl_give UNION *FN(FN(UNION,from),PARTS)(__isl_take PART *part)
+{
+	isl_space *dim;
+	UNION *u;
+
+	if (!part)
+		return NULL;
+
+	dim = FN(PART,get_space)(part);
+	dim = isl_space_drop_dims(dim, isl_dim_in, 0, isl_space_dim(dim, isl_dim_in));
+	dim = isl_space_drop_dims(dim, isl_dim_out, 0, isl_space_dim(dim, isl_dim_out));
+#ifdef HAS_TYPE
+	u = FN(UNION,ZERO)(dim, part->type);
+#else
+	u = FN(UNION,ZERO)(dim);
+#endif
+	u = FN(FN(UNION,add),PARTS)(u, part);
+
+	return u;
+}
+
+S(UNION,match_bin_data) {
+	UNION *u2;
+	UNION *res;
+	__isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *);
+};
+
+/* Check if data->u2 has an element living in the same space as "part".
+ * If so, call data->fn on the two elements and add the result to
+ * data->res.
+ */
+static isl_stat FN(UNION,match_bin_entry)(__isl_take PART *part, void *user)
+{
+	S(UNION,match_bin_data) *data = user;
+	struct isl_hash_table_entry *entry2;
+	isl_space *space;
+	PART *part2;
+
+	space = FN(PART,get_space)(part);
+	entry2 = FN(UNION,find_part_entry)(data->u2, space, 0);
+	isl_space_free(space);
+	if (!entry2)
+		goto error;
+	if (entry2 == isl_hash_table_entry_none) {
+		FN(PART,free)(part);
+		return isl_stat_ok;
+	}
+
+	part2 = entry2->data;
+	if (!isl_space_tuple_is_equal(part->dim, isl_dim_out,
+					part2->dim, isl_dim_out))
+		isl_die(FN(UNION,get_ctx)(data->u2), isl_error_invalid,
+			"entries should have the same range space",
+			goto error);
+
+	part = data->fn(part, FN(PART, copy)(entry2->data));
+
+	data->res = FN(FN(UNION,add),PARTS)(data->res, part);
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+error:
+	FN(PART,free)(part);
+	return isl_stat_error;
+}
+
+/* This function is currently only used from isl_polynomial.c
+ * and not from isl_fold.c.
+ */
+static __isl_give UNION *FN(UNION,match_bin_op)(__isl_take UNION *u1,
+	__isl_take UNION *u2,
+	__isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *))
+	__attribute__ ((unused));
+/* For each pair of elements in "u1" and "u2" living in the same space,
+ * call "fn" and collect the results.
+ */
+static __isl_give UNION *FN(UNION,match_bin_op)(__isl_take UNION *u1,
+	__isl_take UNION *u2,
+	__isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *))
+{
+	S(UNION,match_bin_data) data = { NULL, NULL, fn };
+
+	u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2));
+	u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1));
+
+	if (!u1 || !u2)
+		goto error;
+
+	data.u2 = u2;
+	data.res = FN(UNION,alloc_same_size)(u1);
+	if (FN(FN(UNION,foreach),PARTS)(u1,
+				    &FN(UNION,match_bin_entry), &data) < 0)
+		goto error;
+
+	FN(UNION,free)(u1);
+	FN(UNION,free)(u2);
+	return data.res;
+error:
+	FN(UNION,free)(u1);
+	FN(UNION,free)(u2);
+	FN(UNION,free)(data.res);
+	return NULL;
+}
+
+/* Compute the sum of "u1" and "u2".
+ *
+ * If the base expressions have a default zero value, then the sum
+ * is computed on the union of the domains of "u1" and "u2".
+ * Otherwise, it is computed on their shared domains.
+ */
+__isl_give UNION *FN(UNION,add)(__isl_take UNION *u1, __isl_take UNION *u2)
+{
+#if DEFAULT_IS_ZERO
+	return FN(UNION,union_add_)(u1, u2);
+#else
+	return FN(UNION,match_bin_op)(u1, u2, &FN(PART,add));
+#endif
+}
+
+#ifndef NO_SUB
+/* Subtract "u2" from "u1" and return the result.
+ */
+__isl_give UNION *FN(UNION,sub)(__isl_take UNION *u1, __isl_take UNION *u2)
+{
+	return FN(UNION,match_bin_op)(u1, u2, &FN(PART,sub));
+}
+#endif
+
+S(UNION,any_set_data) {
+	isl_set *set;
+	__isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*);
+};
+
+static __isl_give PART *FN(UNION,any_set_entry)(__isl_take PART *part,
+	void *user)
+{
+	S(UNION,any_set_data) *data = user;
+
+	return data->fn(part, isl_set_copy(data->set));
+}
+
+/* Update each element of "u" by calling "fn" on the element and "set".
+ */
+static __isl_give UNION *FN(UNION,any_set_op)(__isl_take UNION *u,
+	__isl_take isl_set *set,
+	__isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*))
+{
+	S(UNION,any_set_data) data = { NULL, fn };
+
+	u = FN(UNION,align_params)(u, isl_set_get_space(set));
+	set = isl_set_align_params(set, FN(UNION,get_space)(u));
+
+	if (!u || !set)
+		goto error;
+
+	data.set = set;
+	u = FN(UNION,transform)(u, &FN(UNION,any_set_entry), &data);
+	isl_set_free(set);
+	return u;
+error:
+	FN(UNION,free)(u);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Intersect the domain of "u" with the parameter domain "context".
+ */
+__isl_give UNION *FN(UNION,intersect_params)(__isl_take UNION *u,
+	__isl_take isl_set *set)
+{
+	return FN(UNION,any_set_op)(u, set, &FN(PW,intersect_params));
+}
+
+/* Compute the gist of the domain of "u" with respect to
+ * the parameter domain "context".
+ */
+__isl_give UNION *FN(UNION,gist_params)(__isl_take UNION *u,
+	__isl_take isl_set *set)
+{
+	return FN(UNION,any_set_op)(u, set, &FN(PW,gist_params));
+}
+
+S(UNION,match_domain_data) {
+	isl_union_set *uset;
+	UNION *res;
+	__isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*);
+};
+
+static int FN(UNION,set_has_dim)(const void *entry, const void *val)
+{
+	isl_set *set = (isl_set *)entry;
+	isl_space *dim = (isl_space *)val;
+
+	return isl_space_is_equal(set->dim, dim);
+}
+
+/* Find the set in data->uset that lives in the same space as the domain
+ * of "part", apply data->fn to *entry and this set (if any), and add
+ * the result to data->res.
+ */
+static isl_stat FN(UNION,match_domain_entry)(__isl_take PART *part, void *user)
+{
+	S(UNION,match_domain_data) *data = user;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	isl_space *space;
+
+	space = FN(PART,get_domain_space)(part);
+	hash = isl_space_get_hash(space);
+	entry2 = isl_hash_table_find(data->uset->dim->ctx, &data->uset->table,
+				     hash, &FN(UNION,set_has_dim), space, 0);
+	isl_space_free(space);
+	if (!entry2) {
+		FN(PART,free)(part);
+		return isl_stat_ok;
+	}
+
+	part = data->fn(part, isl_set_copy(entry2->data));
+
+	data->res = FN(FN(UNION,add),PARTS)(data->res, part);
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Apply fn to each pair of PW in u and set in uset such that
+ * the set lives in the same space as the domain of PW
+ * and collect the results.
+ */
+static __isl_give UNION *FN(UNION,match_domain_op)(__isl_take UNION *u,
+	__isl_take isl_union_set *uset,
+	__isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*))
+{
+	S(UNION,match_domain_data) data = { NULL, NULL, fn };
+
+	u = FN(UNION,align_params)(u, isl_union_set_get_space(uset));
+	uset = isl_union_set_align_params(uset, FN(UNION,get_space)(u));
+
+	if (!u || !uset)
+		goto error;
+
+	data.uset = uset;
+	data.res = FN(UNION,alloc_same_size)(u);
+	if (FN(FN(UNION,foreach),PARTS)(u,
+				   &FN(UNION,match_domain_entry), &data) < 0)
+		goto error;
+
+	FN(UNION,free)(u);
+	isl_union_set_free(uset);
+	return data.res;
+error:
+	FN(UNION,free)(u);
+	isl_union_set_free(uset);
+	FN(UNION,free)(data.res);
+	return NULL;
+}
+
+/* Intersect the domain of "u" with "uset".
+ * If "uset" is a parameters domain, then intersect the parameter
+ * domain of "u" with this set.
+ */
+__isl_give UNION *FN(UNION,intersect_domain)(__isl_take UNION *u,
+	__isl_take isl_union_set *uset)
+{
+	if (isl_union_set_is_params(uset))
+		return FN(UNION,intersect_params)(u,
+						isl_set_from_union_set(uset));
+	return FN(UNION,match_domain_op)(u, uset, &FN(PW,intersect_domain));
+}
+
+/* Take the set (which may be empty) in data->uset that lives
+ * in the same space as the domain of "pw", subtract it from the domain
+ * of "part" and return the result.
+ */
+static __isl_give PART *FN(UNION,subtract_domain_entry)(__isl_take PART *part,
+	void *user)
+{
+	isl_union_set *uset = user;
+	isl_space *space;
+	isl_set *set;
+
+	space = FN(PART,get_domain_space)(part);
+	set = isl_union_set_extract_set(uset, space);
+	return FN(PART,subtract_domain)(part, set);
+}
+
+/* Subtract "uset' from the domain of "u".
+ */
+__isl_give UNION *FN(UNION,subtract_domain)(__isl_take UNION *u,
+	__isl_take isl_union_set *uset)
+{
+	u = FN(UNION,transform)(u, &FN(UNION,subtract_domain_entry), uset);
+	isl_union_set_free(uset);
+	return u;
+}
+
+__isl_give UNION *FN(UNION,gist)(__isl_take UNION *u,
+	__isl_take isl_union_set *uset)
+{
+	if (isl_union_set_is_params(uset))
+		return FN(UNION,gist_params)(u, isl_set_from_union_set(uset));
+	return FN(UNION,match_domain_op)(u, uset, &FN(PW,gist));
+}
+
+/* Coalesce an entry in a UNION.  Coalescing is performed in-place.
+ * Since the UNION may have several references, the entry is only
+ * replaced if the coalescing is successful.
+ */
+static isl_stat FN(UNION,coalesce_entry)(void **entry, void *user)
+{
+	PART **part_p = (PART **) entry;
+	PART *part;
+
+	part = FN(PART,copy)(*part_p);
+	part = FN(PW,coalesce)(part);
+	if (!part)
+		return isl_stat_error;
+	FN(PART,free)(*part_p);
+	*part_p = part;
+
+	return isl_stat_ok;
+}
+
+__isl_give UNION *FN(UNION,coalesce)(__isl_take UNION *u)
+{
+	if (FN(UNION,foreach_inplace)(u, &FN(UNION,coalesce_entry), NULL) < 0)
+		goto error;
+
+	return u;
+error:
+	FN(UNION,free)(u);
+	return NULL;
+}
+
+static isl_stat FN(UNION,domain_entry)(__isl_take PART *part, void *user)
+{
+	isl_union_set **uset = (isl_union_set **)user;
+
+	*uset = isl_union_set_add_set(*uset, FN(PART,domain)(part));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_set *FN(UNION,domain)(__isl_take UNION *u)
+{
+	isl_union_set *uset;
+
+	uset = isl_union_set_empty(FN(UNION,get_space)(u));
+	if (FN(FN(UNION,foreach),PARTS)(u, &FN(UNION,domain_entry), &uset) < 0)
+		goto error;
+
+	FN(UNION,free)(u);
+	
+	return uset;
+error:
+	isl_union_set_free(uset);
+	FN(UNION,free)(u);
+	return NULL;
+}
+
+#ifdef HAS_TYPE
+/* Negate the type of "u".
+ */
+static __isl_give UNION *FN(UNION,negate_type)(__isl_take UNION *u)
+{
+	u = FN(UNION,cow)(u);
+	if (!u)
+		return NULL;
+	u->type = isl_fold_type_negate(u->type);
+	return u;
+}
+#else
+/* Negate the type of "u".
+ * Since "u" does not have a type, do nothing.
+ */
+static __isl_give UNION *FN(UNION,negate_type)(__isl_take UNION *u)
+{
+	return u;
+}
+#endif
+
+static __isl_give PART *FN(UNION,mul_isl_int_entry)(__isl_take PART *part,
+	void *user)
+{
+	isl_int *v = user;
+
+	return FN(PW,mul_isl_int)(part, *v);
+}
+
+__isl_give UNION *FN(UNION,mul_isl_int)(__isl_take UNION *u, isl_int v)
+{
+	if (isl_int_is_one(v))
+		return u;
+
+	if (DEFAULT_IS_ZERO && u && isl_int_is_zero(v)) {
+		UNION *zero;
+		isl_space *dim = FN(UNION,get_space)(u);
+#ifdef HAS_TYPE
+		zero = FN(UNION,ZERO)(dim, u->type);
+#else
+		zero = FN(UNION,ZERO)(dim);
+#endif
+		FN(UNION,free)(u);
+		return zero;
+	}
+
+	u = FN(UNION,transform_inplace)(u, &FN(UNION,mul_isl_int_entry), &v);
+	if (isl_int_is_neg(v))
+		u = FN(UNION,negate_type)(u);
+
+	return u;
+}
+
+/* Multiply "part" by the isl_val "user" and return the result.
+ */
+static __isl_give PART *FN(UNION,scale_val_entry)(__isl_take PART *part,
+	void *user)
+{
+	isl_val *v = user;
+
+	return FN(PART,scale_val)(part, isl_val_copy(v));
+}
+
+/* Multiply "u" by "v" and return the result.
+ */
+__isl_give UNION *FN(UNION,scale_val)(__isl_take UNION *u,
+	__isl_take isl_val *v)
+{
+	if (!u || !v)
+		goto error;
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return u;
+	}
+
+	if (DEFAULT_IS_ZERO && u && isl_val_is_zero(v)) {
+		UNION *zero;
+		isl_space *space = FN(UNION,get_space)(u);
+#ifdef HAS_TYPE
+		zero = FN(UNION,ZERO)(space, u->type);
+#else
+		zero = FN(UNION,ZERO)(space);
+#endif
+		FN(UNION,free)(u);
+		isl_val_free(v);
+		return zero;
+	}
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational factor", goto error);
+
+	u = FN(UNION,transform_inplace)(u, &FN(UNION,scale_val_entry), v);
+	if (isl_val_is_neg(v))
+		u = FN(UNION,negate_type)(u);
+
+	isl_val_free(v);
+	return u;
+error:
+	isl_val_free(v);
+	FN(UNION,free)(u);
+	return NULL;
+}
+
+/* Divide "part" by the isl_val "user" and return the result.
+ */
+static __isl_give PART *FN(UNION,scale_down_val_entry)(__isl_take PART *part,
+	void *user)
+{
+	isl_val *v = user;
+
+	return FN(PART,scale_down_val)(part, isl_val_copy(v));
+}
+
+/* Divide "u" by "v" and return the result.
+ */
+__isl_give UNION *FN(UNION,scale_down_val)(__isl_take UNION *u,
+	__isl_take isl_val *v)
+{
+	if (!u || !v)
+		goto error;
+	if (isl_val_is_one(v)) {
+		isl_val_free(v);
+		return u;
+	}
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational factor", goto error);
+	if (isl_val_is_zero(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"cannot scale down by zero", goto error);
+
+	u = FN(UNION,transform_inplace)(u, &FN(UNION,scale_down_val_entry), v);
+	if (isl_val_is_neg(v))
+		u = FN(UNION,negate_type)(u);
+
+	isl_val_free(v);
+	return u;
+error:
+	isl_val_free(v);
+	FN(UNION,free)(u);
+	return NULL;
+}
+
+S(UNION,plain_is_equal_data)
+{
+	UNION *u2;
+	isl_bool is_equal;
+};
+
+static isl_stat FN(UNION,plain_is_equal_entry)(void **entry, void *user)
+{
+	S(UNION,plain_is_equal_data) *data = user;
+	struct isl_hash_table_entry *entry2;
+	PW *pw = *entry;
+
+	entry2 = FN(UNION,find_part_entry)(data->u2, pw->dim, 0);
+	if (!entry2 || entry2 == isl_hash_table_entry_none) {
+		if (!entry2)
+			data->is_equal = isl_bool_error;
+		else
+			data->is_equal = isl_bool_false;
+		return isl_stat_error;
+	}
+
+	data->is_equal = FN(PW,plain_is_equal)(pw, entry2->data);
+	if (data->is_equal < 0 || !data->is_equal)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+isl_bool FN(UNION,plain_is_equal)(__isl_keep UNION *u1, __isl_keep UNION *u2)
+{
+	S(UNION,plain_is_equal_data) data = { NULL, isl_bool_true };
+	int n1, n2;
+
+	if (!u1 || !u2)
+		return isl_bool_error;
+	if (u1 == u2)
+		return isl_bool_true;
+	if (u1->table.n != u2->table.n)
+		return isl_bool_false;
+	n1 = FN(FN(UNION,n),PARTS)(u1);
+	n2 = FN(FN(UNION,n),PARTS)(u2);
+	if (n1 < 0 || n2 < 0)
+		return isl_bool_error;
+	if (n1 != n2)
+		return isl_bool_false;
+
+	u1 = FN(UNION,copy)(u1);
+	u2 = FN(UNION,copy)(u2);
+	u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2));
+	u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1));
+	if (!u1 || !u2)
+		goto error;
+
+	data.u2 = u2;
+	if (FN(UNION,foreach_inplace)(u1,
+			       &FN(UNION,plain_is_equal_entry), &data) < 0 &&
+	    data.is_equal)
+		goto error;
+
+	FN(UNION,free)(u1);
+	FN(UNION,free)(u2);
+
+	return data.is_equal;
+error:
+	FN(UNION,free)(u1);
+	FN(UNION,free)(u2);
+	return isl_bool_error;
+}
+
+/* Check whether the element that "entry" points to involves any NaNs and
+ * store the result in *nan.
+ * Abort as soon as one such element has been found.
+ */
+static isl_stat FN(UNION,involves_nan_entry)(void **entry, void *user)
+{
+	isl_bool *nan = user;
+	PW *pw = *entry;
+
+	*nan = FN(PW,involves_nan)(pw);
+	if (*nan < 0 || !nan)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Does "u" involve any NaNs?
+ */
+isl_bool FN(UNION,involves_nan)(__isl_keep UNION *u)
+{
+	isl_bool nan = isl_bool_false;
+
+	if (!u)
+		return isl_bool_error;
+
+	if (FN(UNION,foreach_inplace)(u,
+				    &FN(UNION,involves_nan_entry), &nan) < 0 &&
+	    !nan)
+		return isl_bool_error;
+
+	return nan;
+}
+
+/* Internal data structure for isl_union_*_drop_dims.
+ * type, first and n are passed to isl_*_drop_dims.
+ */
+S(UNION,drop_dims_data) {
+	enum isl_dim_type type;
+	unsigned first;
+	unsigned n;
+};
+
+/* Drop the parameters specified by "data" from "part" and return the result.
+ */
+static __isl_give PART *FN(UNION,drop_dims_entry)(__isl_take PART *part,
+	void *user)
+{
+	S(UNION,drop_dims_data) *data = user;
+
+	return FN(PART,drop_dims)(part, data->type, data->first, data->n);
+}
+
+/* Drop the specified parameters from "u".
+ * That is, type is required to be isl_dim_param.
+ */
+__isl_give UNION *FN(UNION,drop_dims)( __isl_take UNION *u,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	isl_space *space;
+	S(UNION,drop_dims_data) data = { type, first, n };
+
+	if (!u)
+		return NULL;
+
+	if (type != isl_dim_param)
+		isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
+			"can only project out parameters",
+			return FN(UNION,free)(u));
+
+	space = FN(UNION,get_space)(u);
+	space = isl_space_drop_dims(space, type, first, n);
+	return FN(UNION,transform_space)(u, space, &FN(UNION,drop_dims_entry),
+					&data);
+}
+
+/* Internal data structure for isl_union_*_set_dim_name.
+ * pos is the position of the parameter that needs to be renamed.
+ * s is the new name.
+ */
+S(UNION,set_dim_name_data) {
+	unsigned pos;
+	const char *s;
+};
+
+/* Change the name of the parameter at position data->pos of "part" to data->s
+ * and return the result.
+ */
+static __isl_give PART *FN(UNION,set_dim_name_entry)(__isl_take PART *part,
+	void *user)
+{
+	S(UNION,set_dim_name_data) *data = user;
+
+	return FN(PART,set_dim_name)(part, isl_dim_param, data->pos, data->s);
+}
+
+/* Change the name of the parameter at position "pos" to "s".
+ * That is, type is required to be isl_dim_param.
+ */
+__isl_give UNION *FN(UNION,set_dim_name)(__isl_take UNION *u,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	S(UNION,set_dim_name_data) data = { pos, s };
+	isl_space *space;
+
+	if (!u)
+		return NULL;
+
+	if (type != isl_dim_param)
+		isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
+			"can only set parameter names",
+			return FN(UNION,free)(u));
+
+	space = FN(UNION,get_space)(u);
+	space = isl_space_set_dim_name(space, type, pos, s);
+	return FN(UNION,transform_space)(u, space,
+					&FN(UNION,set_dim_name_entry), &data);
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the space of "part" and return the result.
+ */
+static __isl_give PART *FN(UNION,reset_user_entry)(__isl_take PART *part,
+	void *user)
+{
+	return FN(PART,reset_user)(part);
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the spaces of "u".
+ */
+__isl_give UNION *FN(UNION,reset_user)(__isl_take UNION *u)
+{
+	isl_space *space;
+
+	space = FN(UNION,get_space)(u);
+	space = isl_space_reset_user(space);
+	return FN(UNION,transform_space)(u, space, &FN(UNION,reset_user_entry),
+					NULL);
+}
diff --git a/final/lib/External/isl/isl_val.c b/final/lib/External/isl/isl_val.c
new file mode 100644
index 0000000..b2a98fa
--- /dev/null
+++ b/final/lib/External/isl/isl_val.c
@@ -0,0 +1,1693 @@
+/*
+ * Copyright 2013      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl_int.h>
+#include <isl_ctx_private.h>
+#include <isl_val_private.h>
+
+#undef BASE
+#define BASE val
+
+#include <isl_list_templ.c>
+
+/* Allocate an isl_val object with indeterminate value.
+ */
+__isl_give isl_val *isl_val_alloc(isl_ctx *ctx)
+{
+	isl_val *v;
+
+	v = isl_alloc_type(ctx, struct isl_val);
+	if (!v)
+		return NULL;
+
+	v->ctx = ctx;
+	isl_ctx_ref(ctx);
+	v->ref = 1;
+	isl_int_init(v->n);
+	isl_int_init(v->d);
+
+	return v;
+}
+
+/* Return a reference to an isl_val representing zero.
+ */
+__isl_give isl_val *isl_val_zero(isl_ctx *ctx)
+{
+	return isl_val_int_from_si(ctx, 0);
+}
+
+/* Return a reference to an isl_val representing one.
+ */
+__isl_give isl_val *isl_val_one(isl_ctx *ctx)
+{
+	return isl_val_int_from_si(ctx, 1);
+}
+
+/* Return a reference to an isl_val representing negative one.
+ */
+__isl_give isl_val *isl_val_negone(isl_ctx *ctx)
+{
+	return isl_val_int_from_si(ctx, -1);
+}
+
+/* Return a reference to an isl_val representing NaN.
+ */
+__isl_give isl_val *isl_val_nan(isl_ctx *ctx)
+{
+	isl_val *v;
+
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+
+	isl_int_set_si(v->n, 0);
+	isl_int_set_si(v->d, 0);
+
+	return v;
+}
+
+/* Change "v" into a NaN.
+ */
+__isl_give isl_val *isl_val_set_nan(__isl_take isl_val *v)
+{
+	if (!v)
+		return NULL;
+	if (isl_val_is_nan(v))
+		return v;
+	v = isl_val_cow(v);
+	if (!v)
+		return NULL;
+
+	isl_int_set_si(v->n, 0);
+	isl_int_set_si(v->d, 0);
+
+	return v;
+}
+
+/* Return a reference to an isl_val representing +infinity.
+ */
+__isl_give isl_val *isl_val_infty(isl_ctx *ctx)
+{
+	isl_val *v;
+
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+
+	isl_int_set_si(v->n, 1);
+	isl_int_set_si(v->d, 0);
+
+	return v;
+}
+
+/* Return a reference to an isl_val representing -infinity.
+ */
+__isl_give isl_val *isl_val_neginfty(isl_ctx *ctx)
+{
+	isl_val *v;
+
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+
+	isl_int_set_si(v->n, -1);
+	isl_int_set_si(v->d, 0);
+
+	return v;
+}
+
+/* Return a reference to an isl_val representing the integer "i".
+ */
+__isl_give isl_val *isl_val_int_from_si(isl_ctx *ctx, long i)
+{
+	isl_val *v;
+
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+
+	isl_int_set_si(v->n, i);
+	isl_int_set_si(v->d, 1);
+
+	return v;
+}
+
+/* Change the value of "v" to be equal to the integer "i".
+ */
+__isl_give isl_val *isl_val_set_si(__isl_take isl_val *v, long i)
+{
+	if (!v)
+		return NULL;
+	if (isl_val_is_int(v) && isl_int_cmp_si(v->n, i) == 0)
+		return v;
+	v = isl_val_cow(v);
+	if (!v)
+		return NULL;
+
+	isl_int_set_si(v->n, i);
+	isl_int_set_si(v->d, 1);
+
+	return v;
+}
+
+/* Change the value of "v" to be equal to zero.
+ */
+__isl_give isl_val *isl_val_set_zero(__isl_take isl_val *v)
+{
+	return isl_val_set_si(v, 0);
+}
+
+/* Return a reference to an isl_val representing the unsigned integer "u".
+ */
+__isl_give isl_val *isl_val_int_from_ui(isl_ctx *ctx, unsigned long u)
+{
+	isl_val *v;
+
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+
+	isl_int_set_ui(v->n, u);
+	isl_int_set_si(v->d, 1);
+
+	return v;
+}
+
+/* Return a reference to an isl_val representing the integer "n".
+ */
+__isl_give isl_val *isl_val_int_from_isl_int(isl_ctx *ctx, isl_int n)
+{
+	isl_val *v;
+
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+
+	isl_int_set(v->n, n);
+	isl_int_set_si(v->d, 1);
+
+	return v;
+}
+
+/* Return a reference to an isl_val representing the rational value "n"/"d".
+ * Normalizing the isl_val (if needed) is left to the caller.
+ */
+__isl_give isl_val *isl_val_rat_from_isl_int(isl_ctx *ctx,
+	isl_int n, isl_int d)
+{
+	isl_val *v;
+
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+
+	isl_int_set(v->n, n);
+	isl_int_set(v->d, d);
+
+	return v;
+}
+
+/* Return a new reference to "v".
+ */
+__isl_give isl_val *isl_val_copy(__isl_keep isl_val *v)
+{
+	if (!v)
+		return NULL;
+
+	v->ref++;
+	return v;
+}
+
+/* Return a fresh copy of "val".
+ */
+__isl_give isl_val *isl_val_dup(__isl_keep isl_val *val)
+{
+	isl_val *dup;
+
+	if (!val)
+		return NULL;
+
+	dup = isl_val_alloc(isl_val_get_ctx(val));
+	if (!dup)
+		return NULL;
+
+	isl_int_set(dup->n, val->n);
+	isl_int_set(dup->d, val->d);
+
+	return dup;
+}
+
+/* Return an isl_val that is equal to "val" and that has only
+ * a single reference.
+ */
+__isl_give isl_val *isl_val_cow(__isl_take isl_val *val)
+{
+	if (!val)
+		return NULL;
+
+	if (val->ref == 1)
+		return val;
+	val->ref--;
+	return isl_val_dup(val);
+}
+
+/* Free "v" and return NULL.
+ */
+__isl_null isl_val *isl_val_free(__isl_take isl_val *v)
+{
+	if (!v)
+		return NULL;
+
+	if (--v->ref > 0)
+		return NULL;
+
+	isl_ctx_deref(v->ctx);
+	isl_int_clear(v->n);
+	isl_int_clear(v->d);
+	free(v);
+	return NULL;
+}
+
+/* Extract the numerator of a rational value "v" as an integer.
+ *
+ * If "v" is not a rational value, then the result is undefined.
+ */
+long isl_val_get_num_si(__isl_keep isl_val *v)
+{
+	if (!v)
+		return 0;
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return 0);
+	if (!isl_int_fits_slong(v->n))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"numerator too large", return 0);
+	return isl_int_get_si(v->n);
+}
+
+/* Extract the numerator of a rational value "v" as an isl_int.
+ *
+ * If "v" is not a rational value, then the result is undefined.
+ */
+int isl_val_get_num_isl_int(__isl_keep isl_val *v, isl_int *n)
+{
+	if (!v)
+		return -1;
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return -1);
+	isl_int_set(*n, v->n);
+	return 0;
+}
+
+/* Extract the denominator of a rational value "v" as an integer.
+ *
+ * If "v" is not a rational value, then the result is undefined.
+ */
+long isl_val_get_den_si(__isl_keep isl_val *v)
+{
+	if (!v)
+		return 0;
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return 0);
+	if (!isl_int_fits_slong(v->d))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"denominator too large", return 0);
+	return isl_int_get_si(v->d);
+}
+
+/* Extract the denominator of a rational value "v" as an isl_val.
+ *
+ * If "v" is not a rational value, then the result is undefined.
+ */
+__isl_give isl_val *isl_val_get_den_val(__isl_keep isl_val *v)
+{
+	if (!v)
+		return NULL;
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return NULL);
+	return isl_val_int_from_isl_int(isl_val_get_ctx(v), v->d);
+}
+
+/* Return an approximation of "v" as a double.
+ */
+double isl_val_get_d(__isl_keep isl_val *v)
+{
+	if (!v)
+		return 0;
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return 0);
+	return isl_int_get_d(v->n) / isl_int_get_d(v->d);
+}
+
+/* Return the isl_ctx to which "val" belongs.
+ */
+isl_ctx *isl_val_get_ctx(__isl_keep isl_val *val)
+{
+	return val ? val->ctx : NULL;
+}
+
+/* Return a hash value that digests "val".
+ */
+uint32_t isl_val_get_hash(__isl_keep isl_val *val)
+{
+	uint32_t hash;
+
+	if (!val)
+		return 0;
+
+	hash = isl_hash_init();
+	hash = isl_int_hash(val->n, hash);
+	hash = isl_int_hash(val->d, hash);
+
+	return hash;
+}
+
+/* Normalize "v".
+ *
+ * In particular, make sure that the denominator of a rational value
+ * is positive and the numerator and denominator do not have any
+ * common divisors.
+ *
+ * This function should not be called by an external user
+ * since it will only be given normalized values.
+ */
+__isl_give isl_val *isl_val_normalize(__isl_take isl_val *v)
+{
+	isl_ctx *ctx;
+
+	if (!v)
+		return NULL;
+	if (isl_val_is_int(v))
+		return v;
+	if (!isl_val_is_rat(v))
+		return v;
+	if (isl_int_is_neg(v->d)) {
+		isl_int_neg(v->d, v->d);
+		isl_int_neg(v->n, v->n);
+	}
+	ctx = isl_val_get_ctx(v);
+	isl_int_gcd(ctx->normalize_gcd, v->n, v->d);
+	if (isl_int_is_one(ctx->normalize_gcd))
+		return v;
+	isl_int_divexact(v->n, v->n, ctx->normalize_gcd);
+	isl_int_divexact(v->d, v->d, ctx->normalize_gcd);
+	return v;
+}
+
+/* Return the opposite of "v".
+ */
+__isl_give isl_val *isl_val_neg(__isl_take isl_val *v)
+{
+	if (!v)
+		return NULL;
+	if (isl_val_is_nan(v))
+		return v;
+	if (isl_val_is_zero(v))
+		return v;
+
+	v = isl_val_cow(v);
+	if (!v)
+		return NULL;
+	isl_int_neg(v->n, v->n);
+
+	return v;
+}
+
+/* Return the inverse of "v".
+ */
+__isl_give isl_val *isl_val_inv(__isl_take isl_val *v)
+{
+	if (!v)
+		return NULL;
+	if (isl_val_is_nan(v))
+		return v;
+	if (isl_val_is_zero(v)) {
+		isl_ctx *ctx = isl_val_get_ctx(v);
+		isl_val_free(v);
+		return isl_val_nan(ctx);
+	}
+	if (isl_val_is_infty(v) || isl_val_is_neginfty(v)) {
+		isl_ctx *ctx = isl_val_get_ctx(v);
+		isl_val_free(v);
+		return isl_val_zero(ctx);
+	}
+
+	v = isl_val_cow(v);
+	if (!v)
+		return NULL;
+	isl_int_swap(v->n, v->d);
+
+	return isl_val_normalize(v);
+}
+
+/* Return the absolute value of "v".
+ */
+__isl_give isl_val *isl_val_abs(__isl_take isl_val *v)
+{
+	if (!v)
+		return NULL;
+	if (isl_val_is_nan(v))
+		return v;
+	if (isl_val_is_nonneg(v))
+		return v;
+	return isl_val_neg(v);
+}
+
+/* Return the "floor" (greatest integer part) of "v".
+ * That is, return the result of rounding towards -infinity.
+ */
+__isl_give isl_val *isl_val_floor(__isl_take isl_val *v)
+{
+	if (!v)
+		return NULL;
+	if (isl_val_is_int(v))
+		return v;
+	if (!isl_val_is_rat(v))
+		return v;
+
+	v = isl_val_cow(v);
+	if (!v)
+		return NULL;
+	isl_int_fdiv_q(v->n, v->n, v->d);
+	isl_int_set_si(v->d, 1);
+
+	return v;
+}
+
+/* Return the "ceiling" of "v".
+ * That is, return the result of rounding towards +infinity.
+ */
+__isl_give isl_val *isl_val_ceil(__isl_take isl_val *v)
+{
+	if (!v)
+		return NULL;
+	if (isl_val_is_int(v))
+		return v;
+	if (!isl_val_is_rat(v))
+		return v;
+
+	v = isl_val_cow(v);
+	if (!v)
+		return NULL;
+	isl_int_cdiv_q(v->n, v->n, v->d);
+	isl_int_set_si(v->d, 1);
+
+	return v;
+}
+
+/* Truncate "v".
+ * That is, return the result of rounding towards zero.
+ */
+__isl_give isl_val *isl_val_trunc(__isl_take isl_val *v)
+{
+	if (!v)
+		return NULL;
+	if (isl_val_is_int(v))
+		return v;
+	if (!isl_val_is_rat(v))
+		return v;
+
+	v = isl_val_cow(v);
+	if (!v)
+		return NULL;
+	isl_int_tdiv_q(v->n, v->n, v->d);
+	isl_int_set_si(v->d, 1);
+
+	return v;
+}
+
+/* Return 2^v, where v is an integer (that is not too large).
+ */
+__isl_give isl_val *isl_val_2exp(__isl_take isl_val *v)
+{
+	unsigned long exp;
+	int neg;
+
+	v = isl_val_cow(v);
+	if (!v)
+		return NULL;
+	if (!isl_val_is_int(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"can only compute integer powers",
+			return isl_val_free(v));
+	neg = isl_val_is_neg(v);
+	if (neg)
+		isl_int_neg(v->n, v->n);
+	if (!isl_int_fits_ulong(v->n))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"exponent too large", return isl_val_free(v));
+	exp = isl_int_get_ui(v->n);
+	if (neg) {
+		isl_int_mul_2exp(v->d, v->d, exp);
+		isl_int_set_si(v->n, 1);
+	} else {
+		isl_int_mul_2exp(v->n, v->d, exp);
+	}
+
+	return v;
+}
+
+/* Return the minimum of "v1" and "v2".
+ */
+__isl_give isl_val *isl_val_min(__isl_take isl_val *v1, __isl_take isl_val *v2)
+{
+	if (!v1 || !v2)
+		goto error;
+
+	if (isl_val_is_nan(v1)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_nan(v2)) {
+		isl_val_free(v1);
+		return v2;
+	}
+	if (isl_val_le(v1, v2)) {
+		isl_val_free(v2);
+		return v1;
+	} else {
+		isl_val_free(v1);
+		return v2;
+	}
+error:
+	isl_val_free(v1);
+	isl_val_free(v2);
+	return NULL;
+}
+
+/* Return the maximum of "v1" and "v2".
+ */
+__isl_give isl_val *isl_val_max(__isl_take isl_val *v1, __isl_take isl_val *v2)
+{
+	if (!v1 || !v2)
+		goto error;
+
+	if (isl_val_is_nan(v1)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_nan(v2)) {
+		isl_val_free(v1);
+		return v2;
+	}
+	if (isl_val_ge(v1, v2)) {
+		isl_val_free(v2);
+		return v1;
+	} else {
+		isl_val_free(v1);
+		return v2;
+	}
+error:
+	isl_val_free(v1);
+	isl_val_free(v2);
+	return NULL;
+}
+
+/* Return the sum of "v1" and "v2".
+ */
+__isl_give isl_val *isl_val_add(__isl_take isl_val *v1, __isl_take isl_val *v2)
+{
+	if (!v1 || !v2)
+		goto error;
+	if (isl_val_is_nan(v1)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_nan(v2)) {
+		isl_val_free(v1);
+		return v2;
+	}
+	if ((isl_val_is_infty(v1) && isl_val_is_neginfty(v2)) ||
+	    (isl_val_is_neginfty(v1) && isl_val_is_infty(v2))) {
+		isl_val_free(v2);
+		return isl_val_set_nan(v1);
+	}
+	if (isl_val_is_infty(v1) || isl_val_is_neginfty(v1)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_infty(v2) || isl_val_is_neginfty(v2)) {
+		isl_val_free(v1);
+		return v2;
+	}
+	if (isl_val_is_zero(v1)) {
+		isl_val_free(v1);
+		return v2;
+	}
+	if (isl_val_is_zero(v2)) {
+		isl_val_free(v2);
+		return v1;
+	}
+
+	v1 = isl_val_cow(v1);
+	if (!v1)
+		goto error;
+	if (isl_val_is_int(v1) && isl_val_is_int(v2))
+		isl_int_add(v1->n, v1->n, v2->n);
+	else {
+		if (isl_int_eq(v1->d, v2->d))
+			isl_int_add(v1->n, v1->n, v2->n);
+		else {
+			isl_int_mul(v1->n, v1->n, v2->d);
+			isl_int_addmul(v1->n, v2->n, v1->d);
+			isl_int_mul(v1->d, v1->d, v2->d);
+		}
+		v1 = isl_val_normalize(v1);
+	}
+	isl_val_free(v2);
+	return v1;
+error:
+	isl_val_free(v1);
+	isl_val_free(v2);
+	return NULL;
+}
+
+/* Return the sum of "v1" and "v2".
+ */
+__isl_give isl_val *isl_val_add_ui(__isl_take isl_val *v1, unsigned long v2)
+{
+	if (!v1)
+		return NULL;
+	if (!isl_val_is_rat(v1))
+		return v1;
+	if (v2 == 0)
+		return v1;
+	v1 = isl_val_cow(v1);
+	if (!v1)
+		return NULL;
+
+	isl_int_addmul_ui(v1->n, v1->d, v2);
+
+	return v1;
+}
+
+/* Subtract "v2" from "v1".
+ */
+__isl_give isl_val *isl_val_sub(__isl_take isl_val *v1, __isl_take isl_val *v2)
+{
+	if (!v1 || !v2)
+		goto error;
+	if (isl_val_is_nan(v1)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_nan(v2)) {
+		isl_val_free(v1);
+		return v2;
+	}
+	if ((isl_val_is_infty(v1) && isl_val_is_infty(v2)) ||
+	    (isl_val_is_neginfty(v1) && isl_val_is_neginfty(v2))) {
+		isl_val_free(v2);
+		return isl_val_set_nan(v1);
+	}
+	if (isl_val_is_infty(v1) || isl_val_is_neginfty(v1)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_infty(v2) || isl_val_is_neginfty(v2)) {
+		isl_val_free(v1);
+		return isl_val_neg(v2);
+	}
+	if (isl_val_is_zero(v2)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_zero(v1)) {
+		isl_val_free(v1);
+		return isl_val_neg(v2);
+	}
+
+	v1 = isl_val_cow(v1);
+	if (!v1)
+		goto error;
+	if (isl_val_is_int(v1) && isl_val_is_int(v2))
+		isl_int_sub(v1->n, v1->n, v2->n);
+	else {
+		if (isl_int_eq(v1->d, v2->d))
+			isl_int_sub(v1->n, v1->n, v2->n);
+		else {
+			isl_int_mul(v1->n, v1->n, v2->d);
+			isl_int_submul(v1->n, v2->n, v1->d);
+			isl_int_mul(v1->d, v1->d, v2->d);
+		}
+		v1 = isl_val_normalize(v1);
+	}
+	isl_val_free(v2);
+	return v1;
+error:
+	isl_val_free(v1);
+	isl_val_free(v2);
+	return NULL;
+}
+
+/* Subtract "v2" from "v1".
+ */
+__isl_give isl_val *isl_val_sub_ui(__isl_take isl_val *v1, unsigned long v2)
+{
+	if (!v1)
+		return NULL;
+	if (!isl_val_is_rat(v1))
+		return v1;
+	if (v2 == 0)
+		return v1;
+	v1 = isl_val_cow(v1);
+	if (!v1)
+		return NULL;
+
+	isl_int_submul_ui(v1->n, v1->d, v2);
+
+	return v1;
+}
+
+/* Return the product of "v1" and "v2".
+ */
+__isl_give isl_val *isl_val_mul(__isl_take isl_val *v1, __isl_take isl_val *v2)
+{
+	if (!v1 || !v2)
+		goto error;
+	if (isl_val_is_nan(v1)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_nan(v2)) {
+		isl_val_free(v1);
+		return v2;
+	}
+	if ((!isl_val_is_rat(v1) && isl_val_is_zero(v2)) ||
+	    (isl_val_is_zero(v1) && !isl_val_is_rat(v2))) {
+		isl_val_free(v2);
+		return isl_val_set_nan(v1);
+	}
+	if (isl_val_is_zero(v1)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_zero(v2)) {
+		isl_val_free(v1);
+		return v2;
+	}
+	if (isl_val_is_infty(v1) || isl_val_is_neginfty(v1)) {
+		if (isl_val_is_neg(v2))
+			v1 = isl_val_neg(v1);
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_infty(v2) || isl_val_is_neginfty(v2)) {
+		if (isl_val_is_neg(v1))
+			v2 = isl_val_neg(v2);
+		isl_val_free(v1);
+		return v2;
+	}
+
+	v1 = isl_val_cow(v1);
+	if (!v1)
+		goto error;
+	if (isl_val_is_int(v1) && isl_val_is_int(v2))
+		isl_int_mul(v1->n, v1->n, v2->n);
+	else {
+		isl_int_mul(v1->n, v1->n, v2->n);
+		isl_int_mul(v1->d, v1->d, v2->d);
+		v1 = isl_val_normalize(v1);
+	}
+	isl_val_free(v2);
+	return v1;
+error:
+	isl_val_free(v1);
+	isl_val_free(v2);
+	return NULL;
+}
+
+/* Return the product of "v1" and "v2".
+ *
+ * This is a private copy of isl_val_mul for use in the generic
+ * isl_multi_*_scale_val instantiated for isl_val.
+ */
+__isl_give isl_val *isl_val_scale_val(__isl_take isl_val *v1,
+	__isl_take isl_val *v2)
+{
+	return isl_val_mul(v1, v2);
+}
+
+/* Return the product of "v1" and "v2".
+ */
+__isl_give isl_val *isl_val_mul_ui(__isl_take isl_val *v1, unsigned long v2)
+{
+	if (!v1)
+		return NULL;
+	if (isl_val_is_nan(v1))
+		return v1;
+	if (!isl_val_is_rat(v1)) {
+		if (v2 == 0)
+			v1 = isl_val_set_nan(v1);
+		return v1;
+	}
+	if (v2 == 1)
+		return v1;
+	v1 = isl_val_cow(v1);
+	if (!v1)
+		return NULL;
+
+	isl_int_mul_ui(v1->n, v1->n, v2);
+
+	return isl_val_normalize(v1);
+}
+
+/* Divide "v1" by "v2".
+ */
+__isl_give isl_val *isl_val_div(__isl_take isl_val *v1, __isl_take isl_val *v2)
+{
+	if (!v1 || !v2)
+		goto error;
+	if (isl_val_is_nan(v1)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_nan(v2)) {
+		isl_val_free(v1);
+		return v2;
+	}
+	if (isl_val_is_zero(v2) ||
+	    (!isl_val_is_rat(v1) && !isl_val_is_rat(v2))) {
+		isl_val_free(v2);
+		return isl_val_set_nan(v1);
+	}
+	if (isl_val_is_zero(v1)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_infty(v1) || isl_val_is_neginfty(v1)) {
+		if (isl_val_is_neg(v2))
+			v1 = isl_val_neg(v1);
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_infty(v2) || isl_val_is_neginfty(v2)) {
+		isl_val_free(v2);
+		return isl_val_set_zero(v1);
+	}
+
+	v1 = isl_val_cow(v1);
+	if (!v1)
+		goto error;
+	if (isl_val_is_int(v2)) {
+		isl_int_mul(v1->d, v1->d, v2->n);
+		v1 = isl_val_normalize(v1);
+	} else {
+		isl_int_mul(v1->d, v1->d, v2->n);
+		isl_int_mul(v1->n, v1->n, v2->d);
+		v1 = isl_val_normalize(v1);
+	}
+	isl_val_free(v2);
+	return v1;
+error:
+	isl_val_free(v1);
+	isl_val_free(v2);
+	return NULL;
+}
+
+/* Divide "v1" by "v2".
+ */
+__isl_give isl_val *isl_val_div_ui(__isl_take isl_val *v1, unsigned long v2)
+{
+	if (!v1)
+		return NULL;
+	if (isl_val_is_nan(v1))
+		return v1;
+	if (v2 == 0)
+		return isl_val_set_nan(v1);
+	if (v2 == 1)
+		return v1;
+	if (isl_val_is_zero(v1))
+		return v1;
+	if (isl_val_is_infty(v1) || isl_val_is_neginfty(v1))
+		return v1;
+	v1 = isl_val_cow(v1);
+	if (!v1)
+		return NULL;
+
+	isl_int_mul_ui(v1->d, v1->d, v2);
+
+	return isl_val_normalize(v1);
+}
+
+/* Divide "v1" by "v2".
+ *
+ * This is a private copy of isl_val_div for use in the generic
+ * isl_multi_*_scale_down_val instantiated for isl_val.
+ */
+__isl_give isl_val *isl_val_scale_down_val(__isl_take isl_val *v1,
+	__isl_take isl_val *v2)
+{
+	return isl_val_div(v1, v2);
+}
+
+/* Given two integer values "v1" and "v2", check if "v1" is divisible by "v2".
+ */
+isl_bool isl_val_is_divisible_by(__isl_keep isl_val *v1, __isl_keep isl_val *v2)
+{
+	if (!v1 || !v2)
+		return isl_bool_error;
+
+	if (!isl_val_is_int(v1) || !isl_val_is_int(v2))
+		isl_die(isl_val_get_ctx(v1), isl_error_invalid,
+			"expecting two integers", return isl_bool_error);
+
+	return isl_int_is_divisible_by(v1->n, v2->n);
+}
+
+/* Given two integer values "v1" and "v2", return the residue of "v1"
+ * modulo "v2".
+ */
+__isl_give isl_val *isl_val_mod(__isl_take isl_val *v1, __isl_take isl_val *v2)
+{
+	if (!v1 || !v2)
+		goto error;
+	if (!isl_val_is_int(v1) || !isl_val_is_int(v2))
+		isl_die(isl_val_get_ctx(v1), isl_error_invalid,
+			"expecting two integers", goto error);
+	if (isl_val_is_nonneg(v1) && isl_val_lt(v1, v2)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	v1 = isl_val_cow(v1);
+	if (!v1)
+		goto error;
+	isl_int_fdiv_r(v1->n, v1->n, v2->n);
+	isl_val_free(v2);
+	return v1;
+error:
+	isl_val_free(v1);
+	isl_val_free(v2);
+	return NULL;
+}
+
+/* Given two integer values "v1" and "v2", return the residue of "v1"
+ * modulo "v2".
+ *
+ * This is a private copy of isl_val_mod for use in the generic
+ * isl_multi_*_mod_multi_val instantiated for isl_val.
+ */
+__isl_give isl_val *isl_val_mod_val(__isl_take isl_val *v1,
+	__isl_take isl_val *v2)
+{
+	return isl_val_mod(v1, v2);
+}
+
+/* Given two integer values, return their greatest common divisor.
+ */
+__isl_give isl_val *isl_val_gcd(__isl_take isl_val *v1, __isl_take isl_val *v2)
+{
+	if (!v1 || !v2)
+		goto error;
+	if (!isl_val_is_int(v1) || !isl_val_is_int(v2))
+		isl_die(isl_val_get_ctx(v1), isl_error_invalid,
+			"expecting two integers", goto error);
+	if (isl_val_eq(v1, v2)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_one(v1)) {
+		isl_val_free(v2);
+		return v1;
+	}
+	if (isl_val_is_one(v2)) {
+		isl_val_free(v1);
+		return v2;
+	}
+	v1 = isl_val_cow(v1);
+	if (!v1)
+		goto error;
+	isl_int_gcd(v1->n, v1->n, v2->n);
+	isl_val_free(v2);
+	return v1;
+error:
+	isl_val_free(v1);
+	isl_val_free(v2);
+	return NULL;
+}
+
+/* Compute x, y and g such that g = gcd(a,b) and a*x+b*y = g.
+ */
+static void isl_int_gcdext(isl_int *g, isl_int *x, isl_int *y,
+	isl_int a, isl_int b)
+{
+	isl_int d, tmp;
+	isl_int a_copy, b_copy;
+
+	isl_int_init(a_copy);
+	isl_int_init(b_copy);
+	isl_int_init(d);
+	isl_int_init(tmp);
+	isl_int_set(a_copy, a);
+	isl_int_set(b_copy, b);
+	isl_int_abs(*g, a_copy);
+	isl_int_abs(d, b_copy);
+	isl_int_set_si(*x, 1);
+	isl_int_set_si(*y, 0);
+	while (isl_int_is_pos(d)) {
+		isl_int_fdiv_q(tmp, *g, d);
+		isl_int_submul(*x, tmp, *y);
+		isl_int_submul(*g, tmp, d);
+		isl_int_swap(*g, d);
+		isl_int_swap(*x, *y);
+	}
+	if (isl_int_is_zero(a_copy))
+		isl_int_set_si(*x, 0);
+	else if (isl_int_is_neg(a_copy))
+		isl_int_neg(*x, *x);
+	if (isl_int_is_zero(b_copy))
+		isl_int_set_si(*y, 0);
+	else {
+		isl_int_mul(tmp, a_copy, *x);
+		isl_int_sub(tmp, *g, tmp);
+		isl_int_divexact(*y, tmp, b_copy);
+	}
+	isl_int_clear(d);
+	isl_int_clear(tmp);
+	isl_int_clear(a_copy);
+	isl_int_clear(b_copy);
+}
+
+/* Given two integer values v1 and v2, return their greatest common divisor g,
+ * as well as two integers x and y such that x * v1 + y * v2 = g.
+ */
+__isl_give isl_val *isl_val_gcdext(__isl_take isl_val *v1,
+	__isl_take isl_val *v2, __isl_give isl_val **x, __isl_give isl_val **y)
+{
+	isl_ctx *ctx;
+	isl_val *a = NULL, *b = NULL;
+
+	if (!x && !y)
+		return isl_val_gcd(v1, v2);
+
+	if (!v1 || !v2)
+		goto error;
+
+	ctx = isl_val_get_ctx(v1);
+	if (!isl_val_is_int(v1) || !isl_val_is_int(v2))
+		isl_die(ctx, isl_error_invalid,
+			"expecting two integers", goto error);
+
+	v1 = isl_val_cow(v1);
+	a = isl_val_alloc(ctx);
+	b = isl_val_alloc(ctx);
+	if (!v1 || !a || !b)
+		goto error;
+	isl_int_gcdext(&v1->n, &a->n, &b->n, v1->n, v2->n);
+	if (x) {
+		isl_int_set_si(a->d, 1);
+		*x = a;
+	} else
+		isl_val_free(a);
+	if (y) {
+		isl_int_set_si(b->d, 1);
+		*y = b;
+	} else
+		isl_val_free(b);
+	isl_val_free(v2);
+	return v1;
+error:
+	isl_val_free(v1);
+	isl_val_free(v2);
+	isl_val_free(a);
+	isl_val_free(b);
+	if (x)
+		*x = NULL;
+	if (y)
+		*y = NULL;
+	return NULL;
+}
+
+/* Does "v" represent an integer value?
+ */
+isl_bool isl_val_is_int(__isl_keep isl_val *v)
+{
+	if (!v)
+		return isl_bool_error;
+
+	return isl_int_is_one(v->d);
+}
+
+/* Does "v" represent a rational value?
+ */
+isl_bool isl_val_is_rat(__isl_keep isl_val *v)
+{
+	if (!v)
+		return isl_bool_error;
+
+	return !isl_int_is_zero(v->d);
+}
+
+/* Does "v" represent NaN?
+ */
+isl_bool isl_val_is_nan(__isl_keep isl_val *v)
+{
+	if (!v)
+		return isl_bool_error;
+
+	return isl_int_is_zero(v->n) && isl_int_is_zero(v->d);
+}
+
+/* Does "v" represent +infinity?
+ */
+isl_bool isl_val_is_infty(__isl_keep isl_val *v)
+{
+	if (!v)
+		return isl_bool_error;
+
+	return isl_int_is_pos(v->n) && isl_int_is_zero(v->d);
+}
+
+/* Does "v" represent -infinity?
+ */
+isl_bool isl_val_is_neginfty(__isl_keep isl_val *v)
+{
+	if (!v)
+		return isl_bool_error;
+
+	return isl_int_is_neg(v->n) && isl_int_is_zero(v->d);
+}
+
+/* Does "v" represent the integer zero?
+ */
+isl_bool isl_val_is_zero(__isl_keep isl_val *v)
+{
+	if (!v)
+		return isl_bool_error;
+
+	return isl_int_is_zero(v->n) && !isl_int_is_zero(v->d);
+}
+
+/* Does "v" represent the integer one?
+ */
+isl_bool isl_val_is_one(__isl_keep isl_val *v)
+{
+	if (!v)
+		return isl_bool_error;
+
+	if (isl_val_is_nan(v))
+		return isl_bool_false;
+
+	return isl_int_eq(v->n, v->d);
+}
+
+/* Does "v" represent the integer negative one?
+ */
+isl_bool isl_val_is_negone(__isl_keep isl_val *v)
+{
+	if (!v)
+		return isl_bool_error;
+
+	return isl_int_is_neg(v->n) && isl_int_abs_eq(v->n, v->d);
+}
+
+/* Is "v" (strictly) positive?
+ */
+isl_bool isl_val_is_pos(__isl_keep isl_val *v)
+{
+	if (!v)
+		return isl_bool_error;
+
+	return isl_int_is_pos(v->n);
+}
+
+/* Is "v" (strictly) negative?
+ */
+isl_bool isl_val_is_neg(__isl_keep isl_val *v)
+{
+	if (!v)
+		return isl_bool_error;
+
+	return isl_int_is_neg(v->n);
+}
+
+/* Is "v" non-negative?
+ */
+isl_bool isl_val_is_nonneg(__isl_keep isl_val *v)
+{
+	if (!v)
+		return isl_bool_error;
+
+	if (isl_val_is_nan(v))
+		return isl_bool_false;
+
+	return isl_int_is_nonneg(v->n);
+}
+
+/* Is "v" non-positive?
+ */
+isl_bool isl_val_is_nonpos(__isl_keep isl_val *v)
+{
+	if (!v)
+		return isl_bool_error;
+
+	if (isl_val_is_nan(v))
+		return isl_bool_false;
+
+	return isl_int_is_nonpos(v->n);
+}
+
+/* Return the sign of "v".
+ *
+ * The sign of NaN is undefined.
+ */
+int isl_val_sgn(__isl_keep isl_val *v)
+{
+	if (!v)
+		return 0;
+	if (isl_val_is_zero(v))
+		return 0;
+	if (isl_val_is_pos(v))
+		return 1;
+	return -1;
+}
+
+/* Is "v1" (strictly) less than "v2"?
+ */
+isl_bool isl_val_lt(__isl_keep isl_val *v1, __isl_keep isl_val *v2)
+{
+	isl_int t;
+	isl_bool lt;
+
+	if (!v1 || !v2)
+		return isl_bool_error;
+	if (isl_val_is_int(v1) && isl_val_is_int(v2))
+		return isl_int_lt(v1->n, v2->n);
+	if (isl_val_is_nan(v1) || isl_val_is_nan(v2))
+		return isl_bool_false;
+	if (isl_val_eq(v1, v2))
+		return isl_bool_false;
+	if (isl_val_is_infty(v2))
+		return isl_bool_true;
+	if (isl_val_is_infty(v1))
+		return isl_bool_false;
+	if (isl_val_is_neginfty(v1))
+		return isl_bool_true;
+	if (isl_val_is_neginfty(v2))
+		return isl_bool_false;
+
+	isl_int_init(t);
+	isl_int_mul(t, v1->n, v2->d);
+	isl_int_submul(t, v2->n, v1->d);
+	lt = isl_int_is_neg(t);
+	isl_int_clear(t);
+
+	return lt;
+}
+
+/* Is "v1" (strictly) greater than "v2"?
+ */
+isl_bool isl_val_gt(__isl_keep isl_val *v1, __isl_keep isl_val *v2)
+{
+	return isl_val_lt(v2, v1);
+}
+
+/* Is "v1" less than or equal to "v2"?
+ */
+isl_bool isl_val_le(__isl_keep isl_val *v1, __isl_keep isl_val *v2)
+{
+	isl_int t;
+	isl_bool le;
+
+	if (!v1 || !v2)
+		return isl_bool_error;
+	if (isl_val_is_int(v1) && isl_val_is_int(v2))
+		return isl_int_le(v1->n, v2->n);
+	if (isl_val_is_nan(v1) || isl_val_is_nan(v2))
+		return isl_bool_false;
+	if (isl_val_eq(v1, v2))
+		return isl_bool_true;
+	if (isl_val_is_infty(v2))
+		return isl_bool_true;
+	if (isl_val_is_infty(v1))
+		return isl_bool_false;
+	if (isl_val_is_neginfty(v1))
+		return isl_bool_true;
+	if (isl_val_is_neginfty(v2))
+		return isl_bool_false;
+
+	isl_int_init(t);
+	isl_int_mul(t, v1->n, v2->d);
+	isl_int_submul(t, v2->n, v1->d);
+	le = isl_int_is_nonpos(t);
+	isl_int_clear(t);
+
+	return le;
+}
+
+/* Is "v1" greater than or equal to "v2"?
+ */
+isl_bool isl_val_ge(__isl_keep isl_val *v1, __isl_keep isl_val *v2)
+{
+	return isl_val_le(v2, v1);
+}
+
+/* How does "v" compare to "i"?
+ *
+ * Return 1 if v is greater, -1 if v is smaller and 0 if v is equal to i.
+ *
+ * If v is NaN (or NULL), then the result is undefined.
+ */
+int isl_val_cmp_si(__isl_keep isl_val *v, long i)
+{
+	isl_int t;
+	int cmp;
+
+	if (!v)
+		return 0;
+	if (isl_val_is_int(v))
+		return isl_int_cmp_si(v->n, i);
+	if (isl_val_is_nan(v))
+		return 0;
+	if (isl_val_is_infty(v))
+		return 1;
+	if (isl_val_is_neginfty(v))
+		return -1;
+
+	isl_int_init(t);
+	isl_int_mul_si(t, v->d, i);
+	isl_int_sub(t, v->n, t);
+	cmp = isl_int_sgn(t);
+	isl_int_clear(t);
+
+	return cmp;
+}
+
+/* Is "v1" equal to "v2"?
+ */
+isl_bool isl_val_eq(__isl_keep isl_val *v1, __isl_keep isl_val *v2)
+{
+	if (!v1 || !v2)
+		return isl_bool_error;
+	if (isl_val_is_nan(v1) || isl_val_is_nan(v2))
+		return isl_bool_false;
+
+	return isl_int_eq(v1->n, v2->n) && isl_int_eq(v1->d, v2->d);
+}
+
+/* Is "v1" equal to "v2" in absolute value?
+ */
+isl_bool isl_val_abs_eq(__isl_keep isl_val *v1, __isl_keep isl_val *v2)
+{
+	if (!v1 || !v2)
+		return isl_bool_error;
+	if (isl_val_is_nan(v1) || isl_val_is_nan(v2))
+		return isl_bool_false;
+
+	return isl_int_abs_eq(v1->n, v2->n) && isl_int_eq(v1->d, v2->d);
+}
+
+/* Is "v1" different from "v2"?
+ */
+isl_bool isl_val_ne(__isl_keep isl_val *v1, __isl_keep isl_val *v2)
+{
+	if (!v1 || !v2)
+		return isl_bool_error;
+	if (isl_val_is_nan(v1) || isl_val_is_nan(v2))
+		return isl_bool_false;
+
+	return isl_int_ne(v1->n, v2->n) || isl_int_ne(v1->d, v2->d);
+}
+
+/* Print a textual representation of "v" onto "p".
+ */
+__isl_give isl_printer *isl_printer_print_val(__isl_take isl_printer *p,
+	__isl_keep isl_val *v)
+{
+	int neg;
+
+	if (!p || !v)
+		return isl_printer_free(p);
+
+	neg = isl_int_is_neg(v->n);
+	if (neg) {
+		p = isl_printer_print_str(p, "-");
+		isl_int_neg(v->n, v->n);
+	}
+	if (isl_int_is_zero(v->d)) {
+		int sgn = isl_int_sgn(v->n);
+		p = isl_printer_print_str(p, sgn < 0 ? "-infty" :
+					    sgn == 0 ? "NaN" : "infty");
+	} else
+		p = isl_printer_print_isl_int(p, v->n);
+	if (neg)
+		isl_int_neg(v->n, v->n);
+	if (!isl_int_is_zero(v->d) && !isl_int_is_one(v->d)) {
+		p = isl_printer_print_str(p, "/");
+		p = isl_printer_print_isl_int(p, v->d);
+	}
+
+	return p;
+}
+
+/* Is "val1" (obviously) equal to "val2"?
+ *
+ * This is a private copy of isl_val_eq for use in the generic
+ * isl_multi_*_plain_is_equal instantiated for isl_val.
+ */
+int isl_val_plain_is_equal(__isl_keep isl_val *val1, __isl_keep isl_val *val2)
+{
+	return isl_val_eq(val1, val2);
+}
+
+/* Does "v" have any non-zero coefficients
+ * for any dimension in the given range?
+ *
+ * This function is only meant to be used in the generic isl_multi_*
+ * functions which have to deal with base objects that have an associated
+ * space.  Since an isl_val does not have any coefficients, this function
+ * always return 0.
+ */
+int isl_val_involves_dims(__isl_keep isl_val *v, enum isl_dim_type type,
+	unsigned first, unsigned n)
+{
+	if (!v)
+		return -1;
+
+	return 0;
+}
+
+/* Insert "n" dimensions of type "type" at position "first".
+ *
+ * This function is only meant to be used in the generic isl_multi_*
+ * functions which have to deal with base objects that have an associated
+ * space.  Since an isl_val does not have an associated space, this function
+ * does not do anything.
+ */
+__isl_give isl_val *isl_val_insert_dims(__isl_take isl_val *v,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return v;
+}
+
+/* Drop the the "n" first dimensions of type "type" at position "first".
+ *
+ * This function is only meant to be used in the generic isl_multi_*
+ * functions which have to deal with base objects that have an associated
+ * space.  Since an isl_val does not have an associated space, this function
+ * does not do anything.
+ */
+__isl_give isl_val *isl_val_drop_dims(__isl_take isl_val *v,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return v;
+}
+
+/* Change the name of the dimension of type "type" at position "pos" to "s".
+ *
+ * This function is only meant to be used in the generic isl_multi_*
+ * functions which have to deal with base objects that have an associated
+ * space.  Since an isl_val does not have an associated space, this function
+ * does not do anything.
+ */
+__isl_give isl_val *isl_val_set_dim_name(__isl_take isl_val *v,
+	enum isl_dim_type type, unsigned pos, const char *s)
+{
+	return v;
+}
+
+/* Return the space of "v".
+ *
+ * This function is only meant to be used in the generic isl_multi_*
+ * functions which have to deal with base objects that have an associated
+ * space.  The conditions surrounding the call to this function make sure
+ * that this function will never actually get called.  We return a valid
+ * space anyway, just in case.
+ */
+__isl_give isl_space *isl_val_get_space(__isl_keep isl_val *v)
+{
+	if (!v)
+		return NULL;
+
+	return isl_space_params_alloc(isl_val_get_ctx(v), 0);
+}
+
+/* Reset the domain space of "v" to "space".
+ *
+ * This function is only meant to be used in the generic isl_multi_*
+ * functions which have to deal with base objects that have an associated
+ * space.  Since an isl_val does not have an associated space, this function
+ * does not do anything, apart from error handling and cleaning up memory.
+ */
+__isl_give isl_val *isl_val_reset_domain_space(__isl_take isl_val *v,
+	__isl_take isl_space *space)
+{
+	if (!space)
+		return isl_val_free(v);
+	isl_space_free(space);
+	return v;
+}
+
+/* Align the parameters of "v" to those of "space".
+ *
+ * This function is only meant to be used in the generic isl_multi_*
+ * functions which have to deal with base objects that have an associated
+ * space.  Since an isl_val does not have an associated space, this function
+ * does not do anything, apart from error handling and cleaning up memory.
+ * Note that the conditions surrounding the call to this function make sure
+ * that this function will never actually get called.
+ */
+__isl_give isl_val *isl_val_align_params(__isl_take isl_val *v,
+	__isl_take isl_space *space)
+{
+	if (!space)
+		return isl_val_free(v);
+	isl_space_free(space);
+	return v;
+}
+
+/* Reorder the dimensions of the domain of "v" according
+ * to the given reordering.
+ *
+ * This function is only meant to be used in the generic isl_multi_*
+ * functions which have to deal with base objects that have an associated
+ * space.  Since an isl_val does not have an associated space, this function
+ * does not do anything, apart from error handling and cleaning up memory.
+ */
+__isl_give isl_val *isl_val_realign_domain(__isl_take isl_val *v,
+	__isl_take isl_reordering *r)
+{
+	if (!r)
+		return isl_val_free(v);
+	isl_reordering_free(r);
+	return v;
+}
+
+/* Return an isl_val that is zero on "ls".
+ *
+ * This function is only meant to be used in the generic isl_multi_*
+ * functions which have to deal with base objects that have an associated
+ * space.  Since an isl_val does not have an associated space, this function
+ * simply returns a zero isl_val in the same context as "ls".
+ */
+__isl_give isl_val *isl_val_zero_on_domain(__isl_take isl_local_space *ls)
+{
+	isl_ctx *ctx;
+
+	if (!ls)
+		return NULL;
+	ctx = isl_local_space_get_ctx(ls);
+	isl_local_space_free(ls);
+	return isl_val_zero(ctx);
+}
+
+/* Do the parameters of "v" match those of "space"?
+ *
+ * This function is only meant to be used in the generic isl_multi_*
+ * functions which have to deal with base objects that have an associated
+ * space.  Since an isl_val does not have an associated space, this function
+ * simply returns true, except if "v" or "space" are NULL.
+ */
+isl_bool isl_val_matching_params(__isl_keep isl_val *v,
+	__isl_keep isl_space *space)
+{
+	if (!v || !space)
+		return isl_bool_error;
+	return isl_bool_true;
+}
+
+/* Check that the domain space of "v" matches "space".
+ *
+ * This function is only meant to be used in the generic isl_multi_*
+ * functions which have to deal with base objects that have an associated
+ * space.  Since an isl_val does not have an associated space, this function
+ * simply returns 0, except if "v" or "space" are NULL.
+ */
+isl_stat isl_val_check_match_domain_space(__isl_keep isl_val *v,
+	__isl_keep isl_space *space)
+{
+	if (!v || !space)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+#define isl_val_involves_nan isl_val_is_nan
+
+#undef BASE
+#define BASE val
+
+#define NO_DOMAIN
+#define NO_IDENTITY
+#define NO_FROM_BASE
+#define NO_MOVE_DIMS
+#include <isl_multi_templ.c>
+
+/* Apply "fn" to each of the elements of "mv" with as second argument "v".
+ */
+static __isl_give isl_multi_val *isl_multi_val_fn_val(
+	__isl_take isl_multi_val *mv,
+	__isl_give isl_val *(*fn)(__isl_take isl_val *v1,
+					__isl_take isl_val *v2),
+	__isl_take isl_val *v)
+{
+	int i;
+
+	mv = isl_multi_val_cow(mv);
+	if (!mv || !v)
+		goto error;
+
+	for (i = 0; i < mv->n; ++i) {
+		mv->p[i] = fn(mv->p[i], isl_val_copy(v));
+		if (!mv->p[i])
+			goto error;
+	}
+
+	isl_val_free(v);
+	return mv;
+error:
+	isl_val_free(v);
+	isl_multi_val_free(mv);
+	return NULL;
+}
+
+/* Add "v" to each of the elements of "mv".
+ */
+__isl_give isl_multi_val *isl_multi_val_add_val(__isl_take isl_multi_val *mv,
+	__isl_take isl_val *v)
+{
+	if (!v)
+		return isl_multi_val_free(mv);
+	if (isl_val_is_zero(v)) {
+		isl_val_free(v);
+		return mv;
+	}
+	return isl_multi_val_fn_val(mv, &isl_val_add, v);
+}
+
+/* Reduce the elements of "mv" modulo "v".
+ */
+__isl_give isl_multi_val *isl_multi_val_mod_val(__isl_take isl_multi_val *mv,
+	__isl_take isl_val *v)
+{
+	return isl_multi_val_fn_val(mv, &isl_val_mod, v);
+}
diff --git a/final/lib/External/isl/isl_val_gmp.c b/final/lib/External/isl/isl_val_gmp.c
new file mode 100644
index 0000000..42e8d44
--- /dev/null
+++ b/final/lib/External/isl/isl_val_gmp.c
@@ -0,0 +1,128 @@
+#include <string.h>
+#include <isl/val_gmp.h>
+#include <isl_val_private.h>
+
+/* Return a reference to an isl_val representing the integer "z".
+ */
+__isl_give isl_val *isl_val_int_from_gmp(isl_ctx *ctx, mpz_t z)
+{
+	isl_val *v;
+
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+
+	isl_int_set(v->n, z);
+	isl_int_set_si(v->d, 1);
+
+	return v;
+}
+
+/* Return a reference to an isl_val representing the rational value "n"/"d".
+ */
+__isl_give isl_val *isl_val_from_gmp(isl_ctx *ctx, const mpz_t n, const mpz_t d)
+{
+	isl_val *v;
+
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+
+	isl_int_set(v->n, n);
+	isl_int_set(v->d, d);
+
+	return isl_val_normalize(v);
+}
+
+/* Extract the numerator of a rational value "v" in "z".
+ *
+ * If "v" is not a rational value, then the result is undefined.
+ */
+int isl_val_get_num_gmp(__isl_keep isl_val *v, mpz_t z)
+{
+	if (!v)
+		return -1;
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return -1);
+	mpz_set(z, v->n);
+	return 0;
+}
+
+/* Extract the denominator of a rational value "v" in "z".
+ *
+ * If "v" is not a rational value, then the result is undefined.
+ */
+int isl_val_get_den_gmp(__isl_keep isl_val *v, mpz_t z)
+{
+	if (!v)
+		return -1;
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return -1);
+	mpz_set(z, v->d);
+	return 0;
+}
+
+/* Return a reference to an isl_val representing the unsigned
+ * integer value stored in the "n" chunks of size "size" at "chunks".
+ * The least significant chunk is assumed to be stored first.
+ */
+__isl_give isl_val *isl_val_int_from_chunks(isl_ctx *ctx, size_t n,
+	size_t size, const void *chunks)
+{
+	isl_val *v;
+
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+
+	mpz_import(v->n, n, -1, size, 0, 0, chunks);
+	isl_int_set_si(v->d, 1);
+
+	return v;
+}
+
+/* Return the number of chunks of size "size" required to
+ * store the absolute value of the numerator of "v".
+ */
+size_t isl_val_n_abs_num_chunks(__isl_keep isl_val *v, size_t size)
+{
+	if (!v)
+		return 0;
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return 0);
+
+	size *= 8;
+	return (mpz_sizeinbase(v->n, 2) + size - 1) / size;
+}
+
+/* Store a representation of the absolute value of the numerator of "v"
+ * in terms of chunks of size "size" at "chunks".
+ * The least significant chunk is stored first.
+ * The number of chunks in the result can be obtained by calling
+ * isl_val_n_abs_num_chunks.  The user is responsible for allocating
+ * enough memory to store the results.
+ *
+ * In the special case of a zero value, isl_val_n_abs_num_chunks will
+ * return one, while mpz_export will not fill in any chunks.  We therefore
+ * do it ourselves.
+ */
+int isl_val_get_abs_num_chunks(__isl_keep isl_val *v, size_t size,
+	void *chunks)
+{
+	if (!v || !chunks)
+		return -1;
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return -1);
+
+	mpz_export(chunks, NULL, -1, size, 0, 0, v->n);
+	if (isl_val_is_zero(v))
+		memset(chunks, 0, size);
+
+	return 0;
+}
diff --git a/final/lib/External/isl/isl_val_imath.c b/final/lib/External/isl/isl_val_imath.c
new file mode 100644
index 0000000..8f91700
--- /dev/null
+++ b/final/lib/External/isl/isl_val_imath.c
@@ -0,0 +1,64 @@
+#include <isl_val_private.h>
+
+/* Return a reference to an isl_val representing the unsigned
+ * integer value stored in the "n" chunks of size "size" at "chunks".
+ * The least significant chunk is assumed to be stored first.
+ */
+__isl_give isl_val *isl_val_int_from_chunks(isl_ctx *ctx, size_t n,
+	size_t size, const void *chunks)
+{
+	isl_val *v;
+
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+
+	impz_import(v->n, n, -1, size, 0, 0, chunks);
+	isl_int_set_si(v->d, 1);
+
+	return v;
+}
+
+/* Store a representation of the absolute value of the numerator of "v"
+ * in terms of chunks of size "size" at "chunks".
+ * The least significant chunk is stored first.
+ * The number of chunks in the result can be obtained by calling
+ * isl_val_n_abs_num_chunks.  The user is responsible for allocating
+ * enough memory to store the results.
+ *
+ * In the special case of a zero value, isl_val_n_abs_num_chunks will
+ * return one, while impz_export will not fill in any chunks.  We therefore
+ * do it ourselves.
+ */
+int isl_val_get_abs_num_chunks(__isl_keep isl_val *v, size_t size,
+	void *chunks)
+{
+	if (!v || !chunks)
+		return -1;
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return -1);
+
+	impz_export(chunks, NULL, -1, size, 0, 0, v->n);
+	if (isl_val_is_zero(v))
+		memset(chunks, 0, size);
+
+	return 0;
+}
+
+/* Return the number of chunks of size "size" required to
+ * store the absolute value of the numerator of "v".
+ */
+size_t isl_val_n_abs_num_chunks(__isl_keep isl_val *v, size_t size)
+{
+	if (!v)
+		return 0;
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return 0);
+
+	size *= 8;
+	return (impz_sizeinbase(v->n, 2) + size - 1) / size;
+}
diff --git a/final/lib/External/isl/isl_val_private.h b/final/lib/External/isl/isl_val_private.h
new file mode 100644
index 0000000..4276ddb
--- /dev/null
+++ b/final/lib/External/isl/isl_val_private.h
@@ -0,0 +1,75 @@
+#ifndef ISL_VAL_PRIVATE_H
+#define ISL_VAL_PRIVATE_H
+
+#include <isl_int.h>
+#include <isl/val.h>
+#include <isl/local_space.h>
+#include <isl_reordering.h>
+
+/* Represents a "value", which may be an integer value, a rational value,
+ * plus or minus infinity or "not a number".
+ *
+ * Internally, +infinity is represented as 1/0,
+ * -infinity as -1/0 and NaN as 0/0.
+ *
+ * A rational value is always normalized before it is passed to the user.
+ */
+struct isl_val {
+	int ref;
+	isl_ctx *ctx;
+
+	isl_int n;
+	isl_int d;
+};
+
+#undef EL
+#define EL isl_val
+
+#include <isl_list_templ.h>
+
+__isl_give isl_val *isl_val_alloc(isl_ctx *ctx);
+__isl_give isl_val *isl_val_normalize(__isl_take isl_val *v);
+__isl_give isl_val *isl_val_int_from_isl_int(isl_ctx *ctx, isl_int n);
+__isl_give isl_val *isl_val_rat_from_isl_int(isl_ctx *ctx,
+	isl_int n, isl_int d);
+__isl_give isl_val *isl_val_cow(__isl_take isl_val *val);
+
+int isl_val_get_num_isl_int(__isl_keep isl_val *v, isl_int *n);
+
+int isl_val_involves_dims(__isl_keep isl_val *v, enum isl_dim_type type,
+	unsigned first, unsigned n);
+__isl_give isl_val *isl_val_insert_dims(__isl_take isl_val *v,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_val *isl_val_drop_dims(__isl_take isl_val *v,
+	enum isl_dim_type type, unsigned first, unsigned n);
+__isl_give isl_val *isl_val_set_dim_name(__isl_take isl_val *v,
+	enum isl_dim_type type, unsigned pos, const char *s);
+__isl_give isl_space *isl_val_get_space(__isl_keep isl_val *v);
+__isl_give isl_val *isl_val_reset_domain_space(__isl_take isl_val *v,
+	__isl_take isl_space *space);
+__isl_give isl_val *isl_val_align_params(__isl_take isl_val *v,
+	__isl_take isl_space *space);
+__isl_give isl_val *isl_val_realign_domain(__isl_take isl_val *v,
+	__isl_take isl_reordering *r);
+__isl_give isl_val *isl_val_zero_on_domain(__isl_take isl_local_space *ls);
+
+__isl_give isl_val *isl_val_scale_val(__isl_take isl_val *v1,
+	__isl_take isl_val *v2);
+__isl_give isl_val *isl_val_scale_down_val(__isl_take isl_val *v1,
+	__isl_take isl_val *v2);
+__isl_give isl_val *isl_val_mod_val(__isl_take isl_val *v1,
+	__isl_take isl_val *v2);
+
+int isl_val_plain_is_equal(__isl_keep isl_val *val1, __isl_keep isl_val *val2);
+
+isl_bool isl_val_matching_params(__isl_keep isl_val *v,
+	__isl_keep isl_space *space);
+isl_stat isl_val_check_match_domain_space(__isl_keep isl_val *v,
+	__isl_keep isl_space *space);
+
+#undef BASE
+#define BASE val
+
+#include <isl_multi_templ.h>
+
+#endif
diff --git a/final/lib/External/isl/isl_val_sioimath.c b/final/lib/External/isl/isl_val_sioimath.c
new file mode 100644
index 0000000..42f87e3
--- /dev/null
+++ b/final/lib/External/isl/isl_val_sioimath.c
@@ -0,0 +1,68 @@
+#include <isl_val_private.h>
+
+/* Return a reference to an isl_val representing the unsigned
+ * integer value stored in the "n" chunks of size "size" at "chunks".
+ * The least significant chunk is assumed to be stored first.
+ */
+__isl_give isl_val *isl_val_int_from_chunks(isl_ctx *ctx, size_t n,
+	size_t size, const void *chunks)
+{
+	isl_val *v;
+
+	v = isl_val_alloc(ctx);
+	if (!v)
+		return NULL;
+
+	impz_import(isl_sioimath_reinit_big(v->n), n, -1, size, 0, 0, chunks);
+	isl_sioimath_try_demote(v->n);
+	isl_int_set_si(v->d, 1);
+
+	return v;
+}
+
+/* Store a representation of the absolute value of the numerator of "v"
+ * in terms of chunks of size "size" at "chunks".
+ * The least significant chunk is stored first.
+ * The number of chunks in the result can be obtained by calling
+ * isl_val_n_abs_num_chunks.  The user is responsible for allocating
+ * enough memory to store the results.
+ *
+ * In the special case of a zero value, isl_val_n_abs_num_chunks will
+ * return one, while impz_export will not fill in any chunks.  We therefore
+ * do it ourselves.
+ */
+int isl_val_get_abs_num_chunks(__isl_keep isl_val *v, size_t size,
+	void *chunks)
+{
+	isl_sioimath_scratchspace_t scratch;
+
+	if (!v || !chunks)
+		return -1;
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return -1);
+
+	impz_export(chunks, NULL, -1, size, 0, 0,
+	    isl_sioimath_bigarg_src(*v->n, &scratch));
+	if (isl_val_is_zero(v))
+		memset(chunks, 0, size);
+
+	return 0;
+}
+
+/* Return the number of chunks of size "size" required to
+ * store the absolute value of the numerator of "v".
+ */
+size_t isl_val_n_abs_num_chunks(__isl_keep isl_val *v, size_t size)
+{
+	if (!v)
+		return 0;
+
+	if (!isl_val_is_rat(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting rational value", return 0);
+
+	size *= 8;
+	return (isl_sioimath_sizeinbase(*v->n, 2) + size - 1) / size;
+}
diff --git a/final/lib/External/isl/isl_vec.c b/final/lib/External/isl/isl_vec.c
new file mode 100644
index 0000000..a48abf9
--- /dev/null
+++ b/final/lib/External/isl/isl_vec.c
@@ -0,0 +1,646 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2013      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl_ctx_private.h>
+#include <isl_seq.h>
+#include <isl_val_private.h>
+#include <isl_vec_private.h>
+#include <isl/deprecated/vec_int.h>
+
+isl_ctx *isl_vec_get_ctx(__isl_keep isl_vec *vec)
+{
+	return vec ? vec->ctx : NULL;
+}
+
+/* Return a hash value that digests "vec".
+ */
+uint32_t isl_vec_get_hash(__isl_keep isl_vec *vec)
+{
+	if (!vec)
+		return 0;
+
+	return isl_seq_get_hash(vec->el, vec->size);
+}
+
+__isl_give isl_vec *isl_vec_alloc(struct isl_ctx *ctx, unsigned size)
+{
+	struct isl_vec *vec;
+
+	vec = isl_alloc_type(ctx, struct isl_vec);
+	if (!vec)
+		return NULL;
+
+	vec->block = isl_blk_alloc(ctx, size);
+	if (isl_blk_is_error(vec->block))
+		goto error;
+
+	vec->ctx = ctx;
+	isl_ctx_ref(ctx);
+	vec->ref = 1;
+	vec->size = size;
+	vec->el = vec->block.data;
+
+	return vec;
+error:
+	isl_blk_free(ctx, vec->block);
+	free(vec);
+	return NULL;
+}
+
+__isl_give isl_vec *isl_vec_extend(__isl_take isl_vec *vec, unsigned size)
+{
+	if (!vec)
+		return NULL;
+	if (size <= vec->size)
+		return vec;
+
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+
+	vec->block = isl_blk_extend(vec->ctx, vec->block, size);
+	if (!vec->block.data)
+		goto error;
+
+	vec->size = size;
+	vec->el = vec->block.data;
+
+	return vec;
+error:
+	isl_vec_free(vec);
+	return NULL;
+}
+
+/* Apply the expansion specified by "exp" to the "n" elements starting at "pos".
+ * "expanded" it the number of elements that need to replace those "n"
+ * elements.  The entries in "exp" have increasing values between
+ * 0 and "expanded".
+ */
+__isl_give isl_vec *isl_vec_expand(__isl_take isl_vec *vec, int pos, int n,
+	int *exp, int expanded)
+{
+	int i, j;
+	int old_size, extra;
+
+	if (!vec)
+		return NULL;
+	if (expanded < n)
+		isl_die(isl_vec_get_ctx(vec), isl_error_invalid,
+			"not an expansion", return isl_vec_free(vec));
+	if (expanded == n)
+		return vec;
+	if (pos < 0 || n < 0 || pos + n > vec->size)
+		isl_die(isl_vec_get_ctx(vec), isl_error_invalid,
+			"position out of bounds", return isl_vec_free(vec));
+
+	old_size = vec->size;
+	extra = expanded - n;
+	vec = isl_vec_extend(vec, old_size + extra);
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+
+	for (i = old_size - 1; i >= pos + n; --i)
+		isl_int_set(vec->el[i + extra], vec->el[i]);
+
+	j = n - 1;
+	for (i = expanded - 1; i >= 0; --i) {
+		if (j >= 0 && exp[j] == i) {
+			if (i != j)
+				isl_int_swap(vec->el[pos + i],
+					     vec->el[pos + j]);
+			j--;
+		} else {
+			isl_int_set_si(vec->el[pos + i], 0);
+		}
+	}
+
+	return vec;
+}
+
+__isl_give isl_vec *isl_vec_zero_extend(__isl_take isl_vec *vec, unsigned size)
+{
+	int extra;
+
+	if (!vec)
+		return NULL;
+	if (size <= vec->size)
+		return vec;
+
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+
+	extra = size - vec->size;
+	vec = isl_vec_extend(vec, size);
+	if (!vec)
+		return NULL;
+
+	isl_seq_clr(vec->el + size - extra, extra);
+
+	return vec;
+}
+
+/* Return a vector containing the elements of "vec1" followed by
+ * those of "vec2".
+ */
+__isl_give isl_vec *isl_vec_concat(__isl_take isl_vec *vec1,
+	__isl_take isl_vec *vec2)
+{
+	if (!vec1 || !vec2)
+		goto error;
+
+	if (vec2->size == 0) {
+		isl_vec_free(vec2);
+		return vec1;
+	}
+
+	if (vec1->size == 0) {
+		isl_vec_free(vec1);
+		return vec2;
+	}
+
+	vec1 = isl_vec_extend(vec1, vec1->size + vec2->size);
+	if (!vec1)
+		goto error;
+
+	isl_seq_cpy(vec1->el + vec1->size - vec2->size, vec2->el, vec2->size);
+
+	isl_vec_free(vec2);
+	return vec1;
+error:
+	isl_vec_free(vec1);
+	isl_vec_free(vec2);
+	return NULL;
+}
+
+struct isl_vec *isl_vec_copy(struct isl_vec *vec)
+{
+	if (!vec)
+		return NULL;
+
+	vec->ref++;
+	return vec;
+}
+
+struct isl_vec *isl_vec_dup(struct isl_vec *vec)
+{
+	struct isl_vec *vec2;
+
+	if (!vec)
+		return NULL;
+	vec2 = isl_vec_alloc(vec->ctx, vec->size);
+	if (!vec2)
+		return NULL;
+	isl_seq_cpy(vec2->el, vec->el, vec->size);
+	return vec2;
+}
+
+struct isl_vec *isl_vec_cow(struct isl_vec *vec)
+{
+	struct isl_vec *vec2;
+	if (!vec)
+		return NULL;
+
+	if (vec->ref == 1)
+		return vec;
+
+	vec2 = isl_vec_dup(vec);
+	isl_vec_free(vec);
+	return vec2;
+}
+
+__isl_null isl_vec *isl_vec_free(__isl_take isl_vec *vec)
+{
+	if (!vec)
+		return NULL;
+
+	if (--vec->ref > 0)
+		return NULL;
+
+	isl_ctx_deref(vec->ctx);
+	isl_blk_free(vec->ctx, vec->block);
+	free(vec);
+
+	return NULL;
+}
+
+int isl_vec_size(__isl_keep isl_vec *vec)
+{
+	return vec ? vec->size : -1;
+}
+
+int isl_vec_get_element(__isl_keep isl_vec *vec, int pos, isl_int *v)
+{
+	if (!vec)
+		return -1;
+
+	if (pos < 0 || pos >= vec->size)
+		isl_die(vec->ctx, isl_error_invalid, "position out of range",
+			return -1);
+	isl_int_set(*v, vec->el[pos]);
+	return 0;
+}
+
+/* Extract the element at position "pos" of "vec".
+ */
+__isl_give isl_val *isl_vec_get_element_val(__isl_keep isl_vec *vec, int pos)
+{
+	isl_ctx *ctx;
+
+	if (!vec)
+		return NULL;
+	ctx = isl_vec_get_ctx(vec);
+	if (pos < 0 || pos >= vec->size)
+		isl_die(ctx, isl_error_invalid, "position out of range",
+			return NULL);
+	return isl_val_int_from_isl_int(ctx, vec->el[pos]);
+}
+
+__isl_give isl_vec *isl_vec_set_element(__isl_take isl_vec *vec,
+	int pos, isl_int v)
+{
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+	if (pos < 0 || pos >= vec->size)
+		isl_die(vec->ctx, isl_error_invalid, "position out of range",
+			goto error);
+	isl_int_set(vec->el[pos], v);
+	return vec;
+error:
+	isl_vec_free(vec);
+	return NULL;
+}
+
+__isl_give isl_vec *isl_vec_set_element_si(__isl_take isl_vec *vec,
+	int pos, int v)
+{
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+	if (pos < 0 || pos >= vec->size)
+		isl_die(vec->ctx, isl_error_invalid, "position out of range",
+			goto error);
+	isl_int_set_si(vec->el[pos], v);
+	return vec;
+error:
+	isl_vec_free(vec);
+	return NULL;
+}
+
+/* Replace the element at position "pos" of "vec" by "v".
+ */
+__isl_give isl_vec *isl_vec_set_element_val(__isl_take isl_vec *vec,
+	int pos, __isl_take isl_val *v)
+{
+	if (!v)
+		return isl_vec_free(vec);
+	if (!isl_val_is_int(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting integer value", goto error);
+	vec = isl_vec_set_element(vec, pos, v->n);
+	isl_val_free(v);
+	return vec;
+error:
+	isl_val_free(v);
+	return isl_vec_free(vec);
+}
+
+/* Compare the elements of "vec1" and "vec2" at position "pos".
+ */
+int isl_vec_cmp_element(__isl_keep isl_vec *vec1, __isl_keep isl_vec *vec2,
+	int pos)
+{
+	if (!vec1 || !vec2)
+		return 0;
+	if (pos < 0 || pos >= vec1->size || pos >= vec2->size)
+		isl_die(isl_vec_get_ctx(vec1), isl_error_invalid,
+			"position out of range", return 0);
+	return isl_int_cmp(vec1->el[pos], vec2->el[pos]);
+}
+
+/* Does "vec" contain only zero elements?
+ */
+isl_bool isl_vec_is_zero(__isl_keep isl_vec *vec)
+{
+	if (!vec)
+		return isl_bool_error;
+	return isl_seq_first_non_zero(vec->el, vec->size) < 0;
+}
+
+isl_bool isl_vec_is_equal(__isl_keep isl_vec *vec1, __isl_keep isl_vec *vec2)
+{
+	if (!vec1 || !vec2)
+		return isl_bool_error;
+
+	if (vec1->size != vec2->size)
+		return isl_bool_false;
+
+	return isl_seq_eq(vec1->el, vec2->el, vec1->size);
+}
+
+__isl_give isl_printer *isl_printer_print_vec(__isl_take isl_printer *printer,
+	__isl_keep isl_vec *vec)
+{
+	int i;
+
+	if (!printer || !vec)
+		goto error;
+
+	printer = isl_printer_print_str(printer, "[");
+	for (i = 0; i < vec->size; ++i) {
+		if (i)
+			printer = isl_printer_print_str(printer, ",");
+		printer = isl_printer_print_isl_int(printer, vec->el[i]);
+	}
+	printer = isl_printer_print_str(printer, "]");
+
+	return printer;
+error:
+	isl_printer_free(printer);
+	return NULL;
+}
+
+void isl_vec_dump(struct isl_vec *vec)
+{
+	isl_printer *printer;
+
+	if (!vec)
+		return;
+
+	printer = isl_printer_to_file(vec->ctx, stderr);
+	printer = isl_printer_print_vec(printer, vec);
+	printer = isl_printer_end_line(printer);
+
+	isl_printer_free(printer);
+}
+
+__isl_give isl_vec *isl_vec_set(__isl_take isl_vec *vec, isl_int v)
+{
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+	isl_seq_set(vec->el, v, vec->size);
+	return vec;
+}
+
+__isl_give isl_vec *isl_vec_set_si(__isl_take isl_vec *vec, int v)
+{
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+	isl_seq_set_si(vec->el, v, vec->size);
+	return vec;
+}
+
+/* Replace all elements of "vec" by "v".
+ */
+__isl_give isl_vec *isl_vec_set_val(__isl_take isl_vec *vec,
+	__isl_take isl_val *v)
+{
+	vec = isl_vec_cow(vec);
+	if (!vec || !v)
+		goto error;
+	if (!isl_val_is_int(v))
+		isl_die(isl_val_get_ctx(v), isl_error_invalid,
+			"expecting integer value", goto error);
+	isl_seq_set(vec->el, v->n, vec->size);
+	isl_val_free(v);
+	return vec;
+error:
+	isl_vec_free(vec);
+	isl_val_free(v);
+	return NULL;
+}
+
+__isl_give isl_vec *isl_vec_clr(__isl_take isl_vec *vec)
+{
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+	isl_seq_clr(vec->el, vec->size);
+	return vec;
+}
+
+void isl_vec_lcm(struct isl_vec *vec, isl_int *lcm)
+{
+	isl_seq_lcm(vec->block.data, vec->size, lcm);
+}
+
+/* Given a rational vector, with the denominator in the first element
+ * of the vector, round up all coordinates.
+ */
+__isl_give isl_vec *isl_vec_ceil(__isl_take isl_vec *vec)
+{
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+
+	isl_seq_cdiv_q(vec->el + 1, vec->el + 1, vec->el[0], vec->size - 1);
+
+	isl_int_set_si(vec->el[0], 1);
+
+	return vec;
+}
+
+struct isl_vec *isl_vec_normalize(struct isl_vec *vec)
+{
+	if (!vec)
+		return NULL;
+	isl_seq_normalize(vec->ctx, vec->el, vec->size);
+	return vec;
+}
+
+__isl_give isl_vec *isl_vec_neg(__isl_take isl_vec *vec)
+{
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+	isl_seq_neg(vec->el, vec->el, vec->size);
+	return vec;
+}
+
+__isl_give isl_vec *isl_vec_scale(__isl_take isl_vec *vec, isl_int m)
+{
+	if (isl_int_is_one(m))
+		return vec;
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+	isl_seq_scale(vec->el, vec->el, m, vec->size);
+	return vec;
+}
+
+/* Reduce the elements of "vec" modulo "m".
+ */
+__isl_give isl_vec *isl_vec_fdiv_r(__isl_take isl_vec *vec, isl_int m)
+{
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+
+	isl_seq_fdiv_r(vec->el, vec->el, m, vec->size);
+
+	return vec;
+}
+
+__isl_give isl_vec *isl_vec_add(__isl_take isl_vec *vec1,
+	__isl_take isl_vec *vec2)
+{
+	vec1 = isl_vec_cow(vec1);
+	if (!vec1 || !vec2)
+		goto error;
+
+	isl_assert(vec1->ctx, vec1->size == vec2->size, goto error);
+
+	isl_seq_combine(vec1->el, vec1->ctx->one, vec1->el,
+			vec1->ctx->one, vec2->el, vec1->size);
+	
+	isl_vec_free(vec2);
+	return vec1;
+error:
+	isl_vec_free(vec1);
+	isl_vec_free(vec2);
+	return NULL;
+}
+
+static int qsort_int_cmp(const void *p1, const void *p2)
+{
+	const isl_int *i1 = (const isl_int *) p1;
+	const isl_int *i2 = (const isl_int *) p2;
+
+	return isl_int_cmp(*i1, *i2);
+}
+
+__isl_give isl_vec *isl_vec_sort(__isl_take isl_vec *vec)
+{
+	if (!vec)
+		return NULL;
+	
+	qsort(vec->el, vec->size, sizeof(*vec->el), &qsort_int_cmp);
+
+	return vec;
+}
+
+__isl_give isl_vec *isl_vec_drop_els(__isl_take isl_vec *vec,
+	unsigned pos, unsigned n)
+{
+	if (n == 0)
+		return vec;
+	vec = isl_vec_cow(vec);
+	if (!vec)
+		return NULL;
+
+	if (pos + n > vec->size)
+		isl_die(vec->ctx, isl_error_invalid,
+			"range out of bounds", goto error);
+
+	if (pos + n != vec->size)
+		isl_seq_cpy(vec->el + pos, vec->el + pos + n,
+			    vec->size - pos - n);
+
+	vec->size -= n;
+	
+	return vec;
+error:
+	isl_vec_free(vec);
+	return NULL;
+}
+
+__isl_give isl_vec *isl_vec_insert_els(__isl_take isl_vec *vec,
+	unsigned pos, unsigned n)
+{
+	isl_vec *ext = NULL;
+
+	if (n == 0)
+		return vec;
+	if (!vec)
+		return NULL;
+
+	if (pos > vec->size)
+		isl_die(vec->ctx, isl_error_invalid,
+			"position out of bounds", goto error);
+
+	ext =  isl_vec_alloc(vec->ctx, vec->size + n);
+	if (!ext)
+		goto error;
+
+	isl_seq_cpy(ext->el, vec->el, pos);
+	isl_seq_cpy(ext->el + pos + n, vec->el + pos, vec->size - pos);
+
+	isl_vec_free(vec);
+	return ext;
+error:
+	isl_vec_free(vec);
+	isl_vec_free(ext);
+	return NULL;
+}
+
+__isl_give isl_vec *isl_vec_insert_zero_els(__isl_take isl_vec *vec,
+	unsigned pos, unsigned n)
+{
+	vec = isl_vec_insert_els(vec, pos, n);
+	if (!vec)
+		return NULL;
+
+	isl_seq_clr(vec->el + pos, n);
+
+	return vec;
+}
+
+/* Move the "n" elements starting as "src_pos" of "vec"
+ * to "dst_pos".  The elements originally at "dst_pos" are moved
+ * up or down depending on whether "dst_pos" is smaller or greater
+ * than "src_pos".
+ */
+__isl_give isl_vec *isl_vec_move_els(__isl_take isl_vec *vec,
+	unsigned dst_pos, unsigned src_pos, unsigned n)
+{
+	isl_vec *res;
+
+	if (!vec)
+		return NULL;
+
+	if (src_pos + n > vec->size)
+		isl_die(vec->ctx, isl_error_invalid,
+			"source range out of bounds", return isl_vec_free(vec));
+	if (dst_pos + n > vec->size)
+		isl_die(vec->ctx, isl_error_invalid,
+			"destination range out of bounds",
+			return isl_vec_free(vec));
+
+	if (n == 0 || dst_pos == src_pos)
+		return vec;
+
+	res = isl_vec_alloc(vec->ctx, vec->size);
+	if (!res)
+		return isl_vec_free(vec);
+
+	if (dst_pos < src_pos) {
+		isl_seq_cpy(res->el, vec->el, dst_pos);
+		isl_seq_cpy(res->el + dst_pos, vec->el + src_pos, n);
+		isl_seq_cpy(res->el + dst_pos + n,
+			    vec->el + dst_pos, src_pos - dst_pos);
+		isl_seq_cpy(res->el + src_pos + n,
+			    vec->el + src_pos + n, res->size - src_pos - n);
+	} else {
+		isl_seq_cpy(res->el, vec->el, src_pos);
+		isl_seq_cpy(res->el + src_pos,
+			    vec->el + src_pos + n, dst_pos - src_pos);
+		isl_seq_cpy(res->el + dst_pos, vec->el + src_pos, n);
+		isl_seq_cpy(res->el + dst_pos + n,
+			    vec->el + dst_pos + n, res->size - dst_pos - n);
+	}
+
+	isl_vec_free(vec);
+	return res;
+}
diff --git a/final/lib/External/isl/isl_vec_private.h b/final/lib/External/isl/isl_vec_private.h
new file mode 100644
index 0000000..8f6de86
--- /dev/null
+++ b/final/lib/External/isl/isl_vec_private.h
@@ -0,0 +1,31 @@
+#ifndef ISL_VEC_PRIVATE_H
+#define ISL_VEC_PRIVATE_H
+
+#include <isl_blk.h>
+#include <isl/vec.h>
+
+struct isl_vec {
+	int ref;
+
+	struct isl_ctx *ctx;
+
+	unsigned size;
+	isl_int *el;
+
+	struct isl_blk block;
+};
+
+uint32_t isl_vec_get_hash(__isl_keep isl_vec *vec);
+
+__isl_give isl_vec *isl_vec_cow(__isl_take isl_vec *vec);
+
+void isl_vec_lcm(struct isl_vec *vec, isl_int *lcm);
+int isl_vec_get_element(__isl_keep isl_vec *vec, int pos, isl_int *v);
+__isl_give isl_vec *isl_vec_set(__isl_take isl_vec *vec, isl_int v);
+
+isl_bool isl_vec_is_zero(__isl_keep isl_vec *vec);
+
+__isl_give isl_vec *isl_vec_expand(__isl_take isl_vec *vec, int pos, int n,
+	int *exp, int expanded);
+
+#endif
diff --git a/final/lib/External/isl/isl_version.c b/final/lib/External/isl/isl_version.c
new file mode 100644
index 0000000..114323d
--- /dev/null
+++ b/final/lib/External/isl/isl_version.c
@@ -0,0 +1,17 @@
+#include "isl_config.h"
+#include "gitversion.h"
+
+const char *isl_version(void)
+{
+	return GIT_HEAD_ID
+#ifdef USE_GMP_FOR_MP
+	"-GMP"
+#endif
+#ifdef USE_IMATH_FOR_MP
+	"-IMath"
+#ifdef USE_SMALL_INT_OPT
+	"-32"
+#endif
+#endif
+	"\n";
+}
diff --git a/final/lib/External/isl/isl_vertices.c b/final/lib/External/isl/isl_vertices.c
new file mode 100644
index 0000000..f70e410
--- /dev/null
+++ b/final/lib/External/isl/isl_vertices.c
@@ -0,0 +1,1569 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France 
+ */
+
+#include <isl_map_private.h>
+#include <isl_aff_private.h>
+#include <isl/set.h>
+#include <isl_seq.h>
+#include <isl_tab.h>
+#include <isl_space_private.h>
+#include <isl_morph.h>
+#include <isl_vertices_private.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+
+#define SELECTED	1
+#define DESELECTED	-1
+#define UNSELECTED	0
+
+static __isl_give isl_vertices *compute_chambers(__isl_take isl_basic_set *bset,
+	__isl_take isl_vertices *vertices);
+
+__isl_give isl_vertices *isl_vertices_copy(__isl_keep isl_vertices *vertices)
+{
+	if (!vertices)
+		return NULL;
+
+	vertices->ref++;
+	return vertices;
+}
+
+__isl_null isl_vertices *isl_vertices_free(__isl_take isl_vertices *vertices)
+{
+	int i;
+
+	if (!vertices)
+		return NULL;
+
+	if (--vertices->ref > 0)
+		return NULL;
+
+	for (i = 0; i < vertices->n_vertices; ++i) {
+		isl_basic_set_free(vertices->v[i].vertex);
+		isl_basic_set_free(vertices->v[i].dom);
+	}
+	free(vertices->v);
+
+	for (i = 0; i < vertices->n_chambers; ++i) {
+		free(vertices->c[i].vertices);
+		isl_basic_set_free(vertices->c[i].dom);
+	}
+	free(vertices->c);
+
+	isl_basic_set_free(vertices->bset);
+	free(vertices);
+
+	return NULL;
+}
+
+struct isl_vertex_list {
+	struct isl_vertex v;
+	struct isl_vertex_list *next;
+};
+
+static struct isl_vertex_list *free_vertex_list(struct isl_vertex_list *list)
+{
+	struct isl_vertex_list *next;
+
+	for (; list; list = next) {
+		next = list->next;
+		isl_basic_set_free(list->v.vertex);
+		isl_basic_set_free(list->v.dom);
+		free(list);
+	}
+
+	return NULL;
+}
+
+static __isl_give isl_vertices *vertices_from_list(__isl_keep isl_basic_set *bset,
+	int n_vertices, struct isl_vertex_list *list)
+{
+	int i;
+	struct isl_vertex_list *next;
+	isl_vertices *vertices;
+
+	vertices = isl_calloc_type(bset->ctx, isl_vertices);
+	if (!vertices)
+		goto error;
+	vertices->ref = 1;
+	vertices->bset = isl_basic_set_copy(bset);
+	vertices->v = isl_alloc_array(bset->ctx, struct isl_vertex, n_vertices);
+	if (n_vertices && !vertices->v)
+		goto error;
+	vertices->n_vertices = n_vertices;
+
+	for (i = 0; list; list = next, i++) {
+		next = list->next;
+		vertices->v[i] = list->v;
+		free(list);
+	}
+
+	return vertices;
+error:
+	isl_vertices_free(vertices);
+	free_vertex_list(list);
+	return NULL;
+}
+
+/* Prepend a vertex to the linked list "list" based on the equalities in "tab".
+ * Return isl_bool_true if the vertex was actually added and
+ * isl_bool_false otherwise.
+ * In particular, vertices with a lower-dimensional activity domain are
+ * not added to the list because they would not be included in any chamber.
+ * Return isl_bool_error on error.
+ */
+static isl_bool add_vertex(struct isl_vertex_list **list,
+	__isl_keep isl_basic_set *bset, struct isl_tab *tab)
+{
+	unsigned nvar;
+	struct isl_vertex_list *v = NULL;
+
+	if (isl_tab_detect_implicit_equalities(tab) < 0)
+		return isl_bool_error;
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+	v = isl_calloc_type(tab->mat->ctx, struct isl_vertex_list);
+	if (!v)
+		goto error;
+
+	v->v.vertex = isl_basic_set_copy(bset);
+	v->v.vertex = isl_basic_set_cow(v->v.vertex);
+	v->v.vertex = isl_basic_set_update_from_tab(v->v.vertex, tab);
+	v->v.vertex = isl_basic_set_simplify(v->v.vertex);
+	v->v.vertex = isl_basic_set_finalize(v->v.vertex);
+	if (!v->v.vertex)
+		goto error;
+	isl_assert(bset->ctx, v->v.vertex->n_eq >= nvar, goto error);
+	v->v.dom = isl_basic_set_copy(v->v.vertex);
+	v->v.dom = isl_basic_set_params(v->v.dom);
+	if (!v->v.dom)
+		goto error;
+
+	if (v->v.dom->n_eq > 0) {
+		free_vertex_list(v);
+		return isl_bool_false;
+	}
+
+	v->next = *list;
+	*list = v;
+
+	return isl_bool_true;
+error:
+	free_vertex_list(v);
+	return isl_bool_error;
+}
+
+/* Compute the parametric vertices and the chamber decomposition
+ * of an empty parametric polytope.
+ */
+static __isl_give isl_vertices *vertices_empty(__isl_keep isl_basic_set *bset)
+{
+	isl_vertices *vertices;
+
+	if (!bset)
+		return NULL;
+
+	vertices = isl_calloc_type(bset->ctx, isl_vertices);
+	if (!vertices)
+		return NULL;
+	vertices->bset = isl_basic_set_copy(bset);
+	vertices->ref = 1;
+
+	vertices->n_vertices = 0;
+	vertices->n_chambers = 0;
+
+	return vertices;
+}
+
+/* Compute the parametric vertices and the chamber decomposition
+ * of the parametric polytope defined using the same constraints
+ * as "bset" in the 0D case.
+ * There is exactly one 0D vertex and a single chamber containing
+ * the vertex.
+ */
+static __isl_give isl_vertices *vertices_0D(__isl_keep isl_basic_set *bset)
+{
+	isl_vertices *vertices;
+
+	if (!bset)
+		return NULL;
+
+	vertices = isl_calloc_type(bset->ctx, isl_vertices);
+	if (!vertices)
+		return NULL;
+	vertices->ref = 1;
+	vertices->bset = isl_basic_set_copy(bset);
+
+	vertices->v = isl_calloc_array(bset->ctx, struct isl_vertex, 1);
+	if (!vertices->v)
+		goto error;
+	vertices->n_vertices = 1;
+	vertices->v[0].vertex = isl_basic_set_copy(bset);
+	vertices->v[0].dom = isl_basic_set_params(isl_basic_set_copy(bset));
+	if (!vertices->v[0].vertex || !vertices->v[0].dom)
+		goto error;
+
+	vertices->c = isl_calloc_array(bset->ctx, struct isl_chamber, 1);
+	if (!vertices->c)
+		goto error;
+	vertices->n_chambers = 1;
+	vertices->c[0].n_vertices = 1;
+	vertices->c[0].vertices = isl_calloc_array(bset->ctx, int, 1);
+	if (!vertices->c[0].vertices)
+		goto error;
+	vertices->c[0].dom = isl_basic_set_copy(vertices->v[0].dom);
+	if (!vertices->c[0].dom)
+		goto error;
+
+	return vertices;
+error:
+	isl_vertices_free(vertices);
+	return NULL;
+}
+
+static int isl_mat_rank(__isl_keep isl_mat *mat)
+{
+	int row, col;
+	isl_mat *H;
+
+	H = isl_mat_left_hermite(isl_mat_copy(mat), 0, NULL, NULL);
+	if (!H)
+		return -1;
+
+	for (col = 0; col < H->n_col; ++col) {
+		for (row = 0; row < H->n_row; ++row)
+			if (!isl_int_is_zero(H->row[row][col]))
+				break;
+		if (row == H->n_row)
+			break;
+	}
+
+	isl_mat_free(H);
+
+	return col;
+}
+
+/* Is the row pointed to by "f" linearly independent of the "n" first
+ * rows in "facets"?
+ */
+static int is_independent(__isl_keep isl_mat *facets, int n, isl_int *f)
+{
+	int rank;
+
+	if (isl_seq_first_non_zero(f, facets->n_col) < 0)
+		return 0;
+
+	isl_seq_cpy(facets->row[n], f, facets->n_col);
+	facets->n_row = n + 1;
+	rank = isl_mat_rank(facets);
+	if (rank < 0)
+		return -1;
+
+	return rank == n + 1;
+}
+
+/* Check whether we can select constraint "level", given the current selection
+ * reflected by facets in "tab", the rows of "facets" and the earlier
+ * "selected" elements of "selection".
+ *
+ * If the constraint is (strictly) redundant in the tableau, selecting it would
+ * result in an empty tableau, so it can't be selected.
+ * If the set variable part of the constraint is not linearly independent
+ * of the set variable parts of the already selected constraints,
+ * the constraint cannot be selected.
+ * If selecting the constraint results in an empty tableau, the constraint
+ * cannot be selected.
+ * Finally, if selecting the constraint results in some explicitly
+ * deselected constraints turning into equalities, then the corresponding
+ * vertices have already been generated, so the constraint cannot be selected.
+ */
+static int can_select(__isl_keep isl_basic_set *bset, int level,
+	struct isl_tab *tab, __isl_keep isl_mat *facets, int selected,
+	int *selection)
+{
+	int i;
+	int indep;
+	unsigned ovar;
+	struct isl_tab_undo *snap;
+
+	if (isl_tab_is_redundant(tab, level))
+		return 0;
+
+	ovar = isl_space_offset(bset->dim, isl_dim_set);
+
+	indep = is_independent(facets, selected, bset->ineq[level] + 1 + ovar);
+	if (indep < 0)
+		return -1;
+	if (!indep)
+		return 0;
+
+	snap = isl_tab_snap(tab);
+	if (isl_tab_select_facet(tab, level) < 0)
+		return -1;
+
+	if (tab->empty) {
+		if (isl_tab_rollback(tab, snap) < 0)
+			return -1;
+		return 0;
+	}
+
+	for (i = 0; i < level; ++i) {
+		int sgn;
+
+		if (selection[i] != DESELECTED)
+			continue;
+
+		if (isl_tab_is_equality(tab, i))
+			sgn = 0;
+		else if (isl_tab_is_redundant(tab, i))
+			sgn = 1;
+		else
+			sgn = isl_tab_sign_of_max(tab, i);
+		if (sgn < -1)
+			return -1;
+		if (sgn <= 0) {
+			if (isl_tab_rollback(tab, snap) < 0)
+				return -1;
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+/* Compute the parametric vertices and the chamber decomposition
+ * of a parametric polytope that is not full-dimensional.
+ *
+ * Simply map the parametric polytope to a lower dimensional space
+ * and map the resulting vertices back.
+ */
+static __isl_give isl_vertices *lower_dim_vertices(
+	__isl_keep isl_basic_set *bset)
+{
+	isl_morph *morph;
+	isl_vertices *vertices;
+
+	bset = isl_basic_set_copy(bset);
+	morph = isl_basic_set_full_compression(bset);
+	bset = isl_morph_basic_set(isl_morph_copy(morph), bset);
+
+	vertices = isl_basic_set_compute_vertices(bset);
+	isl_basic_set_free(bset);
+
+	morph = isl_morph_inverse(morph);
+
+	vertices = isl_morph_vertices(morph, vertices);
+
+	return vertices;
+}
+
+/* Compute the parametric vertices and the chamber decomposition
+ * of the parametric polytope defined using the same constraints
+ * as "bset".  "bset" is assumed to have no existentially quantified
+ * variables.
+ *
+ * The vertices themselves are computed in a fairly simplistic way.
+ * We simply run through all combinations of d constraints,
+ * with d the number of set variables, and check if those d constraints
+ * define a vertex.  To avoid the generation of duplicate vertices,
+ * which we may happen if a vertex is defined by more that d constraints,
+ * we make sure we only generate the vertex for the d constraints with
+ * smallest index.
+ *
+ * We set up a tableau and keep track of which facets have been
+ * selected.  The tableau is marked strict_redundant so that we can be
+ * sure that any constraint that is marked redundant (and that is not
+ * also marked zero) is not an equality.
+ * If a constraint is marked DESELECTED, it means the constraint was
+ * SELECTED before (in combination with the same selection of earlier
+ * constraints).  If such a deselected constraint turns out to be an
+ * equality, then any vertex that may still be found with the current
+ * selection has already been generated when the constraint was selected.
+ * A constraint is marked UNSELECTED when there is no way selecting
+ * the constraint could lead to a vertex (in combination with the current
+ * selection of earlier constraints).
+ *
+ * The set variable coefficients of the selected constraints are stored
+ * in the facets matrix.
+ */
+__isl_give isl_vertices *isl_basic_set_compute_vertices(
+	__isl_keep isl_basic_set *bset)
+{
+	struct isl_tab *tab;
+	int level;
+	int init;
+	unsigned nvar;
+	int *selection = NULL;
+	int selected;
+	struct isl_tab_undo **snap = NULL;
+	isl_mat *facets = NULL;
+	struct isl_vertex_list *list = NULL;
+	int n_vertices = 0;
+	isl_vertices *vertices;
+
+	if (!bset)
+		return NULL;
+
+	if (isl_basic_set_plain_is_empty(bset))
+		return vertices_empty(bset);
+
+	if (bset->n_eq != 0)
+		return lower_dim_vertices(bset);
+
+	isl_assert(bset->ctx, isl_basic_set_dim(bset, isl_dim_div) == 0,
+		return NULL);
+
+	if (isl_basic_set_dim(bset, isl_dim_set) == 0)
+		return vertices_0D(bset);
+
+	nvar = isl_basic_set_dim(bset, isl_dim_set);
+
+	bset = isl_basic_set_copy(bset);
+	bset = isl_basic_set_set_rational(bset);
+	if (!bset)
+		return NULL;
+
+	tab = isl_tab_from_basic_set(bset, 0);
+	if (!tab)
+		goto error;
+	tab->strict_redundant = 1;
+
+	if (tab->empty)	{
+		vertices = vertices_empty(bset);
+		isl_basic_set_free(bset);
+		isl_tab_free(tab);
+		return vertices;
+	}
+
+	selection = isl_alloc_array(bset->ctx, int, bset->n_ineq);
+	snap = isl_alloc_array(bset->ctx, struct isl_tab_undo *, bset->n_ineq);
+	facets = isl_mat_alloc(bset->ctx, nvar, nvar);
+	if ((bset->n_ineq && (!selection || !snap)) || !facets)
+		goto error;
+
+	level = 0;
+	init = 1;
+	selected = 0;
+
+	while (level >= 0) {
+		if (level >= bset->n_ineq ||
+		    (!init && selection[level] != SELECTED)) {
+			--level;
+			init = 0;
+			continue;
+		}
+		if (init) {
+			int ok;
+			snap[level] = isl_tab_snap(tab);
+			ok = can_select(bset, level, tab, facets, selected,
+					selection);
+			if (ok < 0)
+				goto error;
+			if (ok) {
+				selection[level] = SELECTED;
+				selected++;
+			} else
+				selection[level] = UNSELECTED;
+		} else {
+			selection[level] = DESELECTED;
+			selected--;
+			if (isl_tab_rollback(tab, snap[level]) < 0)
+				goto error;
+		}
+		if (selected == nvar) {
+			if (tab->n_dead == nvar) {
+				isl_bool added = add_vertex(&list, bset, tab);
+				if (added < 0)
+					goto error;
+				if (added)
+					n_vertices++;
+			}
+			init = 0;
+			continue;
+		}
+		++level;
+		init = 1;
+	}
+
+	isl_mat_free(facets);
+	free(selection);
+	free(snap);
+
+	isl_tab_free(tab);
+
+	vertices = vertices_from_list(bset, n_vertices, list);
+
+	vertices = compute_chambers(bset, vertices);
+
+	return vertices;
+error:
+	free_vertex_list(list);
+	isl_mat_free(facets);
+	free(selection);
+	free(snap);
+	isl_tab_free(tab);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+struct isl_chamber_list {
+	struct isl_chamber c;
+	struct isl_chamber_list *next;
+};
+
+static void free_chamber_list(struct isl_chamber_list *list)
+{
+	struct isl_chamber_list *next;
+
+	for (; list; list = next) {
+		next = list->next;
+		isl_basic_set_free(list->c.dom);
+		free(list->c.vertices);
+		free(list);
+	}
+}
+
+/* Check whether the basic set "bset" is a superset of the basic set described
+ * by "tab", i.e., check whether all constraints of "bset" are redundant.
+ */
+static isl_bool bset_covers_tab(__isl_keep isl_basic_set *bset,
+	struct isl_tab *tab)
+{
+	int i;
+
+	if (!bset || !tab)
+		return isl_bool_error;
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		enum isl_ineq_type type = isl_tab_ineq_type(tab, bset->ineq[i]);
+		switch (type) {
+		case isl_ineq_error:		return isl_bool_error;
+		case isl_ineq_redundant:	continue;
+		default:			return isl_bool_false;
+		}
+	}
+
+	return isl_bool_true;
+}
+
+static __isl_give isl_vertices *vertices_add_chambers(
+	__isl_take isl_vertices *vertices, int n_chambers,
+	struct isl_chamber_list *list)
+{
+	int i;
+	isl_ctx *ctx;
+	struct isl_chamber_list *next;
+
+	ctx = isl_vertices_get_ctx(vertices);
+	vertices->c = isl_alloc_array(ctx, struct isl_chamber, n_chambers);
+	if (!vertices->c)
+		goto error;
+	vertices->n_chambers = n_chambers;
+
+	for (i = 0; list; list = next, i++) {
+		next = list->next;
+		vertices->c[i] = list->c;
+		free(list);
+	}
+
+	return vertices;
+error:
+	isl_vertices_free(vertices);
+	free_chamber_list(list);
+	return NULL;
+}
+
+/* Can "tab" be intersected with "bset" without resulting in
+ * a lower-dimensional set.
+ * "bset" itself is assumed to be full-dimensional.
+ */
+static isl_bool can_intersect(struct isl_tab *tab,
+	__isl_keep isl_basic_set *bset)
+{
+	int i;
+	struct isl_tab_undo *snap;
+
+	if (bset->n_eq > 0)
+		isl_die(isl_basic_set_get_ctx(bset), isl_error_internal,
+			"expecting full-dimensional input",
+			return isl_bool_error);
+
+	if (isl_tab_extend_cons(tab, bset->n_ineq) < 0)
+		return isl_bool_error;
+
+	snap = isl_tab_snap(tab);
+
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (isl_tab_ineq_type(tab, bset->ineq[i]) == isl_ineq_redundant)
+			continue;
+		if (isl_tab_add_ineq(tab, bset->ineq[i]) < 0)
+			return isl_bool_error;
+	}
+
+	if (isl_tab_detect_implicit_equalities(tab) < 0)
+		return isl_bool_error;
+	if (tab->n_dead) {
+		if (isl_tab_rollback(tab, snap) < 0)
+			return isl_bool_error;
+		return isl_bool_false;
+	}
+
+	return isl_bool_true;
+}
+
+static int add_chamber(struct isl_chamber_list **list,
+	__isl_keep isl_vertices *vertices, struct isl_tab *tab, int *selection)
+{
+	int n_frozen;
+	int i, j;
+	int n_vertices = 0;
+	struct isl_tab_undo *snap;
+	struct isl_chamber_list *c = NULL;
+
+	for (i = 0; i < vertices->n_vertices; ++i)
+		if (selection[i])
+			n_vertices++;
+
+	snap = isl_tab_snap(tab);
+
+	for (i = 0; i < tab->n_con && tab->con[i].frozen; ++i)
+		tab->con[i].frozen = 0;
+	n_frozen = i;
+
+	if (isl_tab_detect_redundant(tab) < 0)
+		return -1;
+
+	c = isl_calloc_type(tab->mat->ctx, struct isl_chamber_list);
+	if (!c)
+		goto error;
+	c->c.vertices = isl_alloc_array(tab->mat->ctx, int, n_vertices);
+	if (n_vertices && !c->c.vertices)
+		goto error;
+	c->c.dom = isl_basic_set_copy(isl_tab_peek_bset(tab));
+	c->c.dom = isl_basic_set_set_rational(c->c.dom);
+	c->c.dom = isl_basic_set_cow(c->c.dom);
+	c->c.dom = isl_basic_set_update_from_tab(c->c.dom, tab);
+	c->c.dom = isl_basic_set_simplify(c->c.dom);
+	c->c.dom = isl_basic_set_finalize(c->c.dom);
+	if (!c->c.dom)
+		goto error;
+
+	c->c.n_vertices = n_vertices;
+
+	for (i = 0, j = 0; i < vertices->n_vertices; ++i)
+		if (selection[i]) {
+			c->c.vertices[j] = i;
+			j++;
+		}
+
+	c->next = *list;
+	*list = c;
+
+	for (i = 0; i < n_frozen; ++i)
+		tab->con[i].frozen = 1;
+
+	if (isl_tab_rollback(tab, snap) < 0)
+		return -1;
+
+	return 0;
+error:
+	free_chamber_list(c);
+	return -1;
+}
+
+struct isl_facet_todo {
+	struct isl_tab *tab;	/* A tableau representation of the facet */
+	isl_basic_set *bset;    /* A normalized basic set representation */
+	isl_vec *constraint;	/* Constraint pointing to the other side */
+	struct isl_facet_todo *next;
+};
+
+static void free_todo(struct isl_facet_todo *todo)
+{
+	while (todo) {
+		struct isl_facet_todo *next = todo->next;
+
+		isl_tab_free(todo->tab);
+		isl_basic_set_free(todo->bset);
+		isl_vec_free(todo->constraint);
+		free(todo);
+
+		todo = next;
+	}
+}
+
+static struct isl_facet_todo *create_todo(struct isl_tab *tab, int con)
+{
+	int i;
+	int n_frozen;
+	struct isl_tab_undo *snap;
+	struct isl_facet_todo *todo;
+
+	snap = isl_tab_snap(tab);
+
+	for (i = 0; i < tab->n_con && tab->con[i].frozen; ++i)
+		tab->con[i].frozen = 0;
+	n_frozen = i;
+
+	if (isl_tab_detect_redundant(tab) < 0)
+		return NULL;
+
+	todo = isl_calloc_type(tab->mat->ctx, struct isl_facet_todo);
+	if (!todo)
+		return NULL;
+
+	todo->constraint = isl_vec_alloc(tab->mat->ctx, 1 + tab->n_var);
+	if (!todo->constraint)
+		goto error;
+	isl_seq_neg(todo->constraint->el, tab->bmap->ineq[con], 1 + tab->n_var);
+	todo->bset = isl_basic_set_copy(isl_tab_peek_bset(tab));
+	todo->bset = isl_basic_set_set_rational(todo->bset);
+	todo->bset = isl_basic_set_cow(todo->bset);
+	todo->bset = isl_basic_set_update_from_tab(todo->bset, tab);
+	todo->bset = isl_basic_set_simplify(todo->bset);
+	todo->bset = isl_basic_set_sort_constraints(todo->bset);
+	if (!todo->bset)
+		goto error;
+	ISL_F_SET(todo->bset, ISL_BASIC_SET_NORMALIZED);
+	todo->tab = isl_tab_dup(tab);
+	if (!todo->tab)
+		goto error;
+
+	for (i = 0; i < n_frozen; ++i)
+		tab->con[i].frozen = 1;
+
+	if (isl_tab_rollback(tab, snap) < 0)
+		goto error;
+
+	return todo;
+error:
+	free_todo(todo);
+	return NULL;
+}
+
+/* Create todo items for all interior facets of the chamber represented
+ * by "tab" and collect them in "next".
+ */
+static int init_todo(struct isl_facet_todo **next, struct isl_tab *tab)
+{
+	int i;
+	struct isl_tab_undo *snap;
+	struct isl_facet_todo *todo;
+
+	snap = isl_tab_snap(tab);
+
+	for (i = 0; i < tab->n_con; ++i) {
+		if (tab->con[i].frozen)
+			continue;
+		if (tab->con[i].is_redundant)
+			continue;
+
+		if (isl_tab_select_facet(tab, i) < 0)
+			return -1;
+
+		todo = create_todo(tab, i);
+		if (!todo)
+			return -1;
+
+		todo->next = *next;
+		*next = todo;
+
+		if (isl_tab_rollback(tab, snap) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Does the linked list contain a todo item that is the opposite of "todo".
+ * If so, return 1 and remove the opposite todo item.
+ */
+static int has_opposite(struct isl_facet_todo *todo,
+	struct isl_facet_todo **list)
+{
+	for (; *list; list = &(*list)->next) {
+		int eq;
+		eq = isl_basic_set_plain_is_equal(todo->bset, (*list)->bset);
+		if (eq < 0)
+			return -1;
+		if (!eq)
+			continue;
+		todo = *list;
+		*list = todo->next;
+		todo->next = NULL;
+		free_todo(todo);
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Create todo items for all interior facets of the chamber represented
+ * by "tab" and collect them in first->next, taking care to cancel
+ * opposite todo items.
+ */
+static int update_todo(struct isl_facet_todo *first, struct isl_tab *tab)
+{
+	int i;
+	struct isl_tab_undo *snap;
+	struct isl_facet_todo *todo;
+
+	snap = isl_tab_snap(tab);
+
+	for (i = 0; i < tab->n_con; ++i) {
+		int drop;
+
+		if (tab->con[i].frozen)
+			continue;
+		if (tab->con[i].is_redundant)
+			continue;
+
+		if (isl_tab_select_facet(tab, i) < 0)
+			return -1;
+
+		todo = create_todo(tab, i);
+		if (!todo)
+			return -1;
+
+		drop = has_opposite(todo, &first->next);
+		if (drop < 0)
+			return -1;
+
+		if (drop)
+			free_todo(todo);
+		else {
+			todo->next = first->next;
+			first->next = todo;
+		}
+
+		if (isl_tab_rollback(tab, snap) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* Compute the chamber decomposition of the parametric polytope respresented
+ * by "bset" given the parametric vertices and their activity domains.
+ *
+ * We are only interested in full-dimensional chambers.
+ * Each of these chambers is the intersection of the activity domains of
+ * one or more vertices and the union of all chambers is equal to the
+ * projection of the entire parametric polytope onto the parameter space.
+ *
+ * We first create an initial chamber by intersecting as many activity
+ * domains as possible without ending up with an empty or lower-dimensional
+ * set.  As a minor optimization, we only consider those activity domains
+ * that contain some arbitrary point.
+ *
+ * For each of the interior facets of the chamber, we construct a todo item,
+ * containing the facet and a constraint containing the other side of the facet,
+ * for constructing the chamber on the other side.
+ * While their are any todo items left, we pick a todo item and
+ * create the required chamber by intersecting all activity domains
+ * that contain the facet and have a full-dimensional intersection with
+ * the other side of the facet.  For each of the interior facets, we
+ * again create todo items, taking care to cancel opposite todo items.
+ */
+static __isl_give isl_vertices *compute_chambers(__isl_take isl_basic_set *bset,
+	__isl_take isl_vertices *vertices)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_vec *sample = NULL;
+	struct isl_tab *tab = NULL;
+	struct isl_tab_undo *snap;
+	int *selection = NULL;
+	int n_chambers = 0;
+	struct isl_chamber_list *list = NULL;
+	struct isl_facet_todo *todo = NULL;
+
+	if (!bset || !vertices)
+		goto error;
+
+	ctx = isl_vertices_get_ctx(vertices);
+	selection = isl_alloc_array(ctx, int, vertices->n_vertices);
+	if (vertices->n_vertices && !selection)
+		goto error;
+
+	bset = isl_basic_set_params(bset);
+
+	tab = isl_tab_from_basic_set(bset, 1);
+	if (!tab)
+		goto error;
+	for (i = 0; i < bset->n_ineq; ++i)
+		if (isl_tab_freeze_constraint(tab, i) < 0)
+			goto error;
+	isl_basic_set_free(bset);
+
+	snap = isl_tab_snap(tab);
+
+	sample = isl_tab_get_sample_value(tab);
+
+	for (i = 0; i < vertices->n_vertices; ++i) {
+		selection[i] = isl_basic_set_contains(vertices->v[i].dom, sample);
+		if (selection[i] < 0)
+			goto error;
+		if (!selection[i])
+			continue;
+		selection[i] = can_intersect(tab, vertices->v[i].dom);
+		if (selection[i] < 0)
+			goto error;
+	}
+
+	if (isl_tab_detect_redundant(tab) < 0)
+		goto error;
+
+	if (add_chamber(&list, vertices, tab, selection) < 0)
+		goto error;
+	n_chambers++;
+
+	if (init_todo(&todo, tab) < 0)
+		goto error;
+
+	while (todo) {
+		struct isl_facet_todo *next;
+
+		if (isl_tab_rollback(tab, snap) < 0)
+			goto error;
+
+		if (isl_tab_add_ineq(tab, todo->constraint->el) < 0)
+			goto error;
+		if (isl_tab_freeze_constraint(tab, tab->n_con - 1) < 0)
+			goto error;
+
+		for (i = 0; i < vertices->n_vertices; ++i) {
+			selection[i] = bset_covers_tab(vertices->v[i].dom,
+							todo->tab);
+			if (selection[i] < 0)
+				goto error;
+			if (!selection[i])
+				continue;
+			selection[i] = can_intersect(tab, vertices->v[i].dom);
+			if (selection[i] < 0)
+				goto error;
+		}
+
+		if (isl_tab_detect_redundant(tab) < 0)
+			goto error;
+
+		if (add_chamber(&list, vertices, tab, selection) < 0)
+			goto error;
+		n_chambers++;
+
+		if (update_todo(todo, tab) < 0)
+			goto error;
+
+		next = todo->next;
+		todo->next = NULL;
+		free_todo(todo);
+		todo = next;
+	}
+
+	isl_vec_free(sample);
+
+	isl_tab_free(tab);
+	free(selection);
+
+	vertices = vertices_add_chambers(vertices, n_chambers, list);
+
+	for (i = 0; vertices && i < vertices->n_vertices; ++i) {
+		isl_basic_set_free(vertices->v[i].dom);
+		vertices->v[i].dom = NULL;
+	}
+
+	return vertices;
+error:
+	free_chamber_list(list);
+	free_todo(todo);
+	isl_vec_free(sample);
+	isl_tab_free(tab);
+	free(selection);
+	if (!tab)
+		isl_basic_set_free(bset);
+	isl_vertices_free(vertices);
+	return NULL;
+}
+
+isl_ctx *isl_vertex_get_ctx(__isl_keep isl_vertex *vertex)
+{
+	return vertex ? isl_vertices_get_ctx(vertex->vertices) : NULL;
+}
+
+int isl_vertex_get_id(__isl_keep isl_vertex *vertex)
+{
+	return vertex ? vertex->id : -1;
+}
+
+/* Return the activity domain of the vertex "vertex".
+ */
+__isl_give isl_basic_set *isl_vertex_get_domain(__isl_keep isl_vertex *vertex)
+{
+	struct isl_vertex *v;
+
+	if (!vertex)
+		return NULL;
+
+	v = &vertex->vertices->v[vertex->id];
+	if (!v->dom) {
+		v->dom = isl_basic_set_copy(v->vertex);
+		v->dom = isl_basic_set_params(v->dom);
+		v->dom = isl_basic_set_set_integral(v->dom);
+	}
+
+	return isl_basic_set_copy(v->dom);
+}
+
+/* Return a multiple quasi-affine expression describing the vertex "vertex"
+ * in terms of the parameters,
+ */
+__isl_give isl_multi_aff *isl_vertex_get_expr(__isl_keep isl_vertex *vertex)
+{
+	struct isl_vertex *v;
+	isl_basic_set *bset;
+
+	if (!vertex)
+		return NULL;
+
+	v = &vertex->vertices->v[vertex->id];
+
+	bset = isl_basic_set_copy(v->vertex);
+	return isl_multi_aff_from_basic_set_equalities(bset);
+}
+
+static __isl_give isl_vertex *isl_vertex_alloc(__isl_take isl_vertices *vertices,
+	int id)
+{
+	isl_ctx *ctx;
+	isl_vertex *vertex;
+
+	if (!vertices)
+		return NULL;
+
+	ctx = isl_vertices_get_ctx(vertices);
+	vertex = isl_alloc_type(ctx, isl_vertex);
+	if (!vertex)
+		goto error;
+
+	vertex->vertices = vertices;
+	vertex->id = id;
+
+	return vertex;
+error:
+	isl_vertices_free(vertices);
+	return NULL;
+}
+
+void isl_vertex_free(__isl_take isl_vertex *vertex)
+{
+	if (!vertex)
+		return;
+	isl_vertices_free(vertex->vertices);
+	free(vertex);
+}
+
+isl_ctx *isl_cell_get_ctx(__isl_keep isl_cell *cell)
+{
+	return cell ? cell->dom->ctx : NULL;
+}
+
+__isl_give isl_basic_set *isl_cell_get_domain(__isl_keep isl_cell *cell)
+{
+	return cell ? isl_basic_set_copy(cell->dom) : NULL;
+}
+
+static __isl_give isl_cell *isl_cell_alloc(__isl_take isl_vertices *vertices,
+	__isl_take isl_basic_set *dom, int id)
+{
+	int i;
+	isl_cell *cell = NULL;
+
+	if (!vertices || !dom)
+		goto error;
+
+	cell = isl_calloc_type(dom->ctx, isl_cell);
+	if (!cell)
+		goto error;
+
+	cell->n_vertices = vertices->c[id].n_vertices;
+	cell->ids = isl_alloc_array(dom->ctx, int, cell->n_vertices);
+	if (cell->n_vertices && !cell->ids)
+		goto error;
+	for (i = 0; i < cell->n_vertices; ++i)
+		cell->ids[i] = vertices->c[id].vertices[i];
+	cell->vertices = vertices;
+	cell->dom = dom;
+
+	return cell;
+error:
+	isl_cell_free(cell);
+	isl_vertices_free(vertices);
+	isl_basic_set_free(dom);
+	return NULL;
+}
+
+void isl_cell_free(__isl_take isl_cell *cell)
+{
+	if (!cell)
+		return;
+
+	isl_vertices_free(cell->vertices);
+	free(cell->ids);
+	isl_basic_set_free(cell->dom);
+	free(cell);
+}
+
+/* Create a tableau of the cone obtained by first homogenizing the given
+ * polytope and then making all inequalities strict by setting the
+ * constant term to -1.
+ */
+static struct isl_tab *tab_for_shifted_cone(__isl_keep isl_basic_set *bset)
+{
+	int i;
+	isl_vec *c = NULL;
+	struct isl_tab *tab;
+
+	if (!bset)
+		return NULL;
+	tab = isl_tab_alloc(bset->ctx, bset->n_eq + bset->n_ineq + 1,
+			    1 + isl_basic_set_total_dim(bset), 0);
+	if (!tab)
+		return NULL;
+	tab->rational = ISL_F_ISSET(bset, ISL_BASIC_SET_RATIONAL);
+	if (ISL_F_ISSET(bset, ISL_BASIC_MAP_EMPTY)) {
+		if (isl_tab_mark_empty(tab) < 0)
+			goto error;
+		return tab;
+	}
+
+	c = isl_vec_alloc(bset->ctx, 1 + 1 + isl_basic_set_total_dim(bset));
+	if (!c)
+		goto error;
+
+	isl_int_set_si(c->el[0], 0);
+	for (i = 0; i < bset->n_eq; ++i) {
+		isl_seq_cpy(c->el + 1, bset->eq[i], c->size - 1);
+		if (isl_tab_add_eq(tab, c->el) < 0)
+			goto error;
+	}
+
+	isl_int_set_si(c->el[0], -1);
+	for (i = 0; i < bset->n_ineq; ++i) {
+		isl_seq_cpy(c->el + 1, bset->ineq[i], c->size - 1);
+		if (isl_tab_add_ineq(tab, c->el) < 0)
+			goto error;
+		if (tab->empty) {
+			isl_vec_free(c);
+			return tab;
+		}
+	}
+
+	isl_seq_clr(c->el + 1, c->size - 1);
+	isl_int_set_si(c->el[1], 1);
+	if (isl_tab_add_ineq(tab, c->el) < 0)
+		goto error;
+
+	isl_vec_free(c);
+	return tab;
+error:
+	isl_vec_free(c);
+	isl_tab_free(tab);
+	return NULL;
+}
+
+/* Compute an interior point of "bset" by selecting an interior
+ * point in homogeneous space and projecting the point back down.
+ */
+static __isl_give isl_vec *isl_basic_set_interior_point(
+	__isl_keep isl_basic_set *bset)
+{
+	isl_vec *vec;
+	struct isl_tab *tab;
+
+	tab = tab_for_shifted_cone(bset);
+	vec = isl_tab_get_sample_value(tab);
+	isl_tab_free(tab);
+	if (!vec)
+		return NULL;
+
+	isl_seq_cpy(vec->el, vec->el + 1, vec->size - 1);
+	vec->size--;
+
+	return vec;
+}
+
+/* Call "fn" on all chambers of the parametric polytope with the shared
+ * facets of neighboring chambers only appearing in one of the chambers.
+ *
+ * We pick an interior point from one of the chambers and then make
+ * all constraints that do not satisfy this point strict.
+ * For constraints that saturate the interior point, the sign
+ * of the first non-zero coefficient is used to determine which
+ * of the two (internal) constraints should be tightened.
+ */
+isl_stat isl_vertices_foreach_disjoint_cell(__isl_keep isl_vertices *vertices,
+	isl_stat (*fn)(__isl_take isl_cell *cell, void *user), void *user)
+{
+	int i;
+	isl_vec *vec;
+	isl_cell *cell;
+
+	if (!vertices)
+		return isl_stat_error;
+
+	if (vertices->n_chambers == 0)
+		return isl_stat_ok;
+
+	if (vertices->n_chambers == 1) {
+		isl_basic_set *dom = isl_basic_set_copy(vertices->c[0].dom);
+		dom = isl_basic_set_set_integral(dom);
+		cell = isl_cell_alloc(isl_vertices_copy(vertices), dom, 0);
+		if (!cell)
+			return isl_stat_error;
+		return fn(cell, user);
+	}
+
+	vec = isl_basic_set_interior_point(vertices->c[0].dom);
+	if (!vec)
+		return isl_stat_error;
+
+	for (i = 0; i < vertices->n_chambers; ++i) {
+		int r;
+		isl_basic_set *dom = isl_basic_set_copy(vertices->c[i].dom);
+		if (i)
+			dom = isl_basic_set_tighten_outward(dom, vec);
+		dom = isl_basic_set_set_integral(dom);
+		cell = isl_cell_alloc(isl_vertices_copy(vertices), dom, i);
+		if (!cell)
+			goto error;
+		r = fn(cell, user);
+		if (r < 0)
+			goto error;
+	}
+
+	isl_vec_free(vec);
+
+	return isl_stat_ok;
+error:
+	isl_vec_free(vec);
+	return isl_stat_error;
+}
+
+isl_stat isl_vertices_foreach_cell(__isl_keep isl_vertices *vertices,
+	isl_stat (*fn)(__isl_take isl_cell *cell, void *user), void *user)
+{
+	int i;
+	isl_cell *cell;
+
+	if (!vertices)
+		return isl_stat_error;
+
+	if (vertices->n_chambers == 0)
+		return isl_stat_ok;
+
+	for (i = 0; i < vertices->n_chambers; ++i) {
+		isl_stat r;
+		isl_basic_set *dom = isl_basic_set_copy(vertices->c[i].dom);
+
+		cell = isl_cell_alloc(isl_vertices_copy(vertices), dom, i);
+		if (!cell)
+			return isl_stat_error;
+
+		r = fn(cell, user);
+		if (r < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+isl_stat isl_vertices_foreach_vertex(__isl_keep isl_vertices *vertices,
+	isl_stat (*fn)(__isl_take isl_vertex *vertex, void *user), void *user)
+{
+	int i;
+	isl_vertex *vertex;
+
+	if (!vertices)
+		return isl_stat_error;
+
+	if (vertices->n_vertices == 0)
+		return isl_stat_ok;
+
+	for (i = 0; i < vertices->n_vertices; ++i) {
+		isl_stat r;
+
+		vertex = isl_vertex_alloc(isl_vertices_copy(vertices), i);
+		if (!vertex)
+			return isl_stat_error;
+
+		r = fn(vertex, user);
+		if (r < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+isl_stat isl_cell_foreach_vertex(__isl_keep isl_cell *cell,
+	isl_stat (*fn)(__isl_take isl_vertex *vertex, void *user), void *user)
+{
+	int i;
+	isl_vertex *vertex;
+
+	if (!cell)
+		return isl_stat_error;
+
+	if (cell->n_vertices == 0)
+		return isl_stat_ok;
+
+	for (i = 0; i < cell->n_vertices; ++i) {
+		isl_stat r;
+
+		vertex = isl_vertex_alloc(isl_vertices_copy(cell->vertices),
+					  cell->ids[i]);
+		if (!vertex)
+			return isl_stat_error;
+
+		r = fn(vertex, user);
+		if (r < 0)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+isl_ctx *isl_vertices_get_ctx(__isl_keep isl_vertices *vertices)
+{
+	return vertices ? vertices->bset->ctx : NULL;
+}
+
+int isl_vertices_get_n_vertices(__isl_keep isl_vertices *vertices)
+{
+	return vertices ? vertices->n_vertices : -1;
+}
+
+__isl_give isl_vertices *isl_morph_vertices(__isl_take isl_morph *morph,
+	__isl_take isl_vertices *vertices)
+{
+	int i;
+	isl_morph *param_morph = NULL;
+
+	if (!morph || !vertices)
+		goto error;
+
+	isl_assert(vertices->bset->ctx, vertices->ref == 1, goto error);
+
+	param_morph = isl_morph_copy(morph);
+	param_morph = isl_morph_dom_params(param_morph);
+	param_morph = isl_morph_ran_params(param_morph);
+
+	for (i = 0; i < vertices->n_vertices; ++i) {
+		vertices->v[i].dom = isl_morph_basic_set(
+			isl_morph_copy(param_morph), vertices->v[i].dom);
+		vertices->v[i].vertex = isl_morph_basic_set(
+			isl_morph_copy(morph), vertices->v[i].vertex);
+		if (!vertices->v[i].vertex)
+			goto error;
+	}
+
+	for (i = 0; i < vertices->n_chambers; ++i) {
+		vertices->c[i].dom = isl_morph_basic_set(
+			isl_morph_copy(param_morph), vertices->c[i].dom);
+		if (!vertices->c[i].dom)
+			goto error;
+	}
+
+	isl_morph_free(param_morph);
+	isl_morph_free(morph);
+	return vertices;
+error:
+	isl_morph_free(param_morph);
+	isl_morph_free(morph);
+	isl_vertices_free(vertices);
+	return NULL;
+}
+
+/* Construct a simplex isl_cell spanned by the vertices with indices in
+ * "simplex_ids" and "other_ids" and call "fn" on this isl_cell.
+ */
+static isl_stat call_on_simplex(__isl_keep isl_cell *cell,
+	int *simplex_ids, int n_simplex, int *other_ids, int n_other,
+	isl_stat (*fn)(__isl_take isl_cell *simplex, void *user), void *user)
+{
+	int i;
+	isl_ctx *ctx;
+	struct isl_cell *simplex;
+
+	ctx = isl_cell_get_ctx(cell);
+
+	simplex = isl_calloc_type(ctx, struct isl_cell);
+	if (!simplex)
+		return isl_stat_error;
+	simplex->vertices = isl_vertices_copy(cell->vertices);
+	if (!simplex->vertices)
+		goto error;
+	simplex->dom = isl_basic_set_copy(cell->dom);
+	if (!simplex->dom)
+		goto error;
+	simplex->n_vertices = n_simplex + n_other;
+	simplex->ids = isl_alloc_array(ctx, int, simplex->n_vertices);
+	if (!simplex->ids)
+		goto error;
+
+	for (i = 0; i < n_simplex; ++i)
+		simplex->ids[i] = simplex_ids[i];
+	for (i = 0; i < n_other; ++i)
+		simplex->ids[n_simplex + i] = other_ids[i];
+
+	return fn(simplex, user);
+error:
+	isl_cell_free(simplex);
+	return isl_stat_error;
+}
+
+/* Check whether the parametric vertex described by "vertex"
+ * lies on the facet corresponding to constraint "facet" of "bset".
+ * The isl_vec "v" is a temporary vector than can be used by this function.
+ *
+ * We eliminate the variables from the facet constraint using the
+ * equalities defining the vertex and check if the result is identical
+ * to zero.
+ *
+ * It would probably be better to keep track of the constraints defining
+ * a vertex during the vertex construction so that we could simply look
+ * it up here.
+ */
+static int vertex_on_facet(__isl_keep isl_basic_set *vertex,
+	__isl_keep isl_basic_set *bset, int facet, __isl_keep isl_vec *v)
+{
+	int i;
+	isl_int m;
+
+	isl_seq_cpy(v->el, bset->ineq[facet], v->size);
+
+	isl_int_init(m);
+	for (i = 0; i < vertex->n_eq; ++i) {
+		int k = isl_seq_last_non_zero(vertex->eq[i], v->size);
+		isl_seq_elim(v->el, vertex->eq[i], k, v->size, &m);
+	}
+	isl_int_clear(m);
+
+	return isl_seq_first_non_zero(v->el, v->size) == -1;
+}
+
+/* Triangulate the polytope spanned by the vertices with ids
+ * in "simplex_ids" and "other_ids" and call "fn" on each of
+ * the resulting simplices.
+ * If the input polytope is already a simplex, we simply call "fn".
+ * Otherwise, we pick a point from "other_ids" and add it to "simplex_ids".
+ * Then we consider each facet of "bset" that does not contain the point
+ * we just picked, but does contain some of the other points in "other_ids"
+ * and call ourselves recursively on the polytope spanned by the new
+ * "simplex_ids" and those points in "other_ids" that lie on the facet.
+ */
+static isl_stat triangulate(__isl_keep isl_cell *cell, __isl_keep isl_vec *v,
+	int *simplex_ids, int n_simplex, int *other_ids, int n_other,
+	isl_stat (*fn)(__isl_take isl_cell *simplex, void *user), void *user)
+{
+	int i, j, k;
+	int d, nparam;
+	int *ids;
+	isl_ctx *ctx;
+	isl_basic_set *vertex;
+	isl_basic_set *bset;
+
+	ctx = isl_cell_get_ctx(cell);
+	d = isl_basic_set_dim(cell->vertices->bset, isl_dim_set);
+	nparam = isl_basic_set_dim(cell->vertices->bset, isl_dim_param);
+
+	if (n_simplex + n_other == d + 1)
+		return call_on_simplex(cell, simplex_ids, n_simplex,
+				       other_ids, n_other, fn, user);
+
+	simplex_ids[n_simplex] = other_ids[0];
+	vertex = cell->vertices->v[other_ids[0]].vertex;
+	bset = cell->vertices->bset;
+
+	ids = isl_alloc_array(ctx, int, n_other - 1);
+	if (!ids)
+		goto error;
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (isl_seq_first_non_zero(bset->ineq[i] + 1 + nparam, d) == -1)
+			continue;
+		if (vertex_on_facet(vertex, bset, i, v))
+			continue;
+
+		for (j = 1, k = 0; j < n_other; ++j) {
+			isl_basic_set *ov;
+			ov = cell->vertices->v[other_ids[j]].vertex;
+			if (vertex_on_facet(ov, bset, i, v))
+				ids[k++] = other_ids[j];
+		}
+		if (k == 0)
+			continue;
+
+		if (triangulate(cell, v, simplex_ids, n_simplex + 1,
+				ids, k, fn, user) < 0)
+			goto error;
+	}
+	free(ids);
+
+	return isl_stat_ok;
+error:
+	free(ids);
+	return isl_stat_error;
+}
+
+/* Triangulate the given cell and call "fn" on each of the resulting
+ * simplices.
+ */
+isl_stat isl_cell_foreach_simplex(__isl_take isl_cell *cell,
+	isl_stat (*fn)(__isl_take isl_cell *simplex, void *user), void *user)
+{
+	int d, total;
+	int r;
+	isl_ctx *ctx;
+	isl_vec *v = NULL;
+	int *simplex_ids = NULL;
+
+	if (!cell)
+		return isl_stat_error;
+
+	d = isl_basic_set_dim(cell->vertices->bset, isl_dim_set);
+	total = isl_basic_set_total_dim(cell->vertices->bset);
+
+	if (cell->n_vertices == d + 1)
+		return fn(cell, user);
+
+	ctx = isl_cell_get_ctx(cell);
+	simplex_ids = isl_alloc_array(ctx, int, d + 1);
+	if (!simplex_ids)
+		goto error;
+
+	v = isl_vec_alloc(ctx, 1 + total);
+	if (!v)
+		goto error;
+
+	r = triangulate(cell, v, simplex_ids, 0,
+			cell->ids, cell->n_vertices, fn, user);
+
+	isl_vec_free(v);
+	free(simplex_ids);
+
+	isl_cell_free(cell);
+
+	return r;
+error:
+	free(simplex_ids);
+	isl_vec_free(v);
+	isl_cell_free(cell);
+	return isl_stat_error;
+}
diff --git a/final/lib/External/isl/isl_vertices_private.h b/final/lib/External/isl/isl_vertices_private.h
new file mode 100644
index 0000000..37e6407
--- /dev/null
+++ b/final/lib/External/isl/isl_vertices_private.h
@@ -0,0 +1,71 @@
+#ifndef ISL_VERTICES_PRIVATE_H
+#define ISL_VERTICES_PRIVATE_H
+
+#include <isl/set.h>
+#include <isl/vertices.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_morph;
+
+/* A parametric vertex.  "vertex" contains the actual description
+ * of the vertex as a singleton parametric set.  "dom" is the projection
+ * of "vertex" onto the parameter space, i.e., the activity domain
+ * of the vertex.
+ * During the construction of vertices and chambers, the activity domain
+ * of every parametric vertex is full-dimensional.
+ */
+struct isl_vertex {
+	isl_basic_set *dom;
+	isl_basic_set *vertex;
+};
+
+/* A chamber in the chamber decomposition.  The indices of the "n_vertices"
+ * active vertices are stored in "vertices".
+ */
+struct isl_chamber {
+	int n_vertices;
+	int *vertices;
+	isl_basic_set *dom;
+};
+
+struct isl_vertices {
+	int ref;
+
+	/* The rational basic set spanned by the vertices. */
+	isl_basic_set *bset;
+
+	int n_vertices;
+	struct isl_vertex *v;
+
+	int n_chambers;
+	struct isl_chamber *c;
+};
+
+struct isl_cell {
+	int n_vertices;
+	int *ids;
+	isl_vertices *vertices;
+	isl_basic_set *dom;
+};
+
+struct isl_external_vertex {
+	isl_vertices *vertices;
+	int id;
+};
+
+isl_stat isl_vertices_foreach_disjoint_cell(__isl_keep isl_vertices *vertices,
+	isl_stat (*fn)(__isl_take isl_cell *cell, void *user), void *user);
+isl_stat isl_cell_foreach_simplex(__isl_take isl_cell *cell,
+	isl_stat (*fn)(__isl_take isl_cell *simplex, void *user), void *user);
+
+__isl_give isl_vertices *isl_morph_vertices(__isl_take struct isl_morph *morph,
+	__isl_take isl_vertices *vertices);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/isl/isl_yaml.h b/final/lib/External/isl/isl_yaml.h
new file mode 100644
index 0000000..4d2c442
--- /dev/null
+++ b/final/lib/External/isl/isl_yaml.h
@@ -0,0 +1,18 @@
+#ifndef ISL_YAML_H
+#define ISL_YAML_H
+
+#define ISL_YAML_INDENT_FLOW		-1
+
+enum isl_yaml_state {
+	isl_yaml_none,
+	isl_yaml_mapping_first_key_start,
+	isl_yaml_mapping_key_start,
+	isl_yaml_mapping_key,
+	isl_yaml_mapping_val_start,
+	isl_yaml_mapping_val,
+	isl_yaml_sequence_first_start,
+	isl_yaml_sequence_start,
+	isl_yaml_sequence
+};
+
+#endif
diff --git a/final/lib/External/isl/ltmain.sh b/final/lib/External/isl/ltmain.sh
new file mode 100644
index 0000000..2ad8be8
--- /dev/null
+++ b/final/lib/External/isl/ltmain.sh
@@ -0,0 +1,11156 @@
+#! /bin/sh
+## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
+##               by inline-source v2014-01-03.01
+
+# libtool (GNU libtool) 2.4.6
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION="2.4.6 Debian-2.4.6-1"
+package_revision=2.4.6
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Run './libtool --help' for help with using this script from the
+# command line.
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# After configure completes, it has a better idea of some of the
+# shell tools we need than the defaults used by the functions shared
+# with bootstrap, so set those here where they can still be over-
+# ridden by the user, but otherwise take precedence.
+
+: ${AUTOCONF="autoconf"}
+: ${AUTOMAKE="automake"}
+
+
+## -------------------------- ##
+## Source external libraries. ##
+## -------------------------- ##
+
+# Much of our low-level functionality needs to be sourced from external
+# libraries, which are installed to $pkgauxdir.
+
+# Set a version string for this script.
+scriptversion=2015-01-20.17; # UTC
+
+# General shell script boiler plate, and helper functions.
+# Written by Gary V. Vaughan, 2004
+
+# Copyright (C) 2004-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# As a special exception to the GNU General Public License, if you distribute
+# this file as part of a program or library that is built using GNU Libtool,
+# you may include this file under the same distribution terms that you use
+# for the rest of that program.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Evaluate this file near the top of your script to gain access to
+# the functions and variables defined here:
+#
+#   . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh
+#
+# If you need to override any of the default environment variable
+# settings, do that before evaluating this file.
+
+
+## -------------------- ##
+## Shell normalisation. ##
+## -------------------- ##
+
+# Some shells need a little help to be as Bourne compatible as possible.
+# Before doing anything else, make sure all that help has been provided!
+
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac
+fi
+
+# NLS nuisances: We save the old values in case they are required later.
+_G_user_locale=
+_G_safe_locale=
+for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+  eval "if test set = \"\${$_G_var+set}\"; then
+          save_$_G_var=\$$_G_var
+          $_G_var=C
+	  export $_G_var
+	  _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\"
+	  _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\"
+	fi"
+done
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Make sure IFS has a sensible default
+sp=' '
+nl='
+'
+IFS="$sp	$nl"
+
+# There are apparently some retarded systems that use ';' as a PATH separator!
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+
+## ------------------------- ##
+## Locate command utilities. ##
+## ------------------------- ##
+
+
+# func_executable_p FILE
+# ----------------------
+# Check that FILE is an executable regular file.
+func_executable_p ()
+{
+    test -f "$1" && test -x "$1"
+}
+
+
+# func_path_progs PROGS_LIST CHECK_FUNC [PATH]
+# --------------------------------------------
+# Search for either a program that responds to --version with output
+# containing "GNU", or else returned by CHECK_FUNC otherwise, by
+# trying all the directories in PATH with each of the elements of
+# PROGS_LIST.
+#
+# CHECK_FUNC should accept the path to a candidate program, and
+# set $func_check_prog_result if it truncates its output less than
+# $_G_path_prog_max characters.
+func_path_progs ()
+{
+    _G_progs_list=$1
+    _G_check_func=$2
+    _G_PATH=${3-"$PATH"}
+
+    _G_path_prog_max=0
+    _G_path_prog_found=false
+    _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:}
+    for _G_dir in $_G_PATH; do
+      IFS=$_G_save_IFS
+      test -z "$_G_dir" && _G_dir=.
+      for _G_prog_name in $_G_progs_list; do
+        for _exeext in '' .EXE; do
+          _G_path_prog=$_G_dir/$_G_prog_name$_exeext
+          func_executable_p "$_G_path_prog" || continue
+          case `"$_G_path_prog" --version 2>&1` in
+            *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;;
+            *)     $_G_check_func $_G_path_prog
+		   func_path_progs_result=$func_check_prog_result
+		   ;;
+          esac
+          $_G_path_prog_found && break 3
+        done
+      done
+    done
+    IFS=$_G_save_IFS
+    test -z "$func_path_progs_result" && {
+      echo "no acceptable sed could be found in \$PATH" >&2
+      exit 1
+    }
+}
+
+
+# We want to be able to use the functions in this file before configure
+# has figured out where the best binaries are kept, which means we have
+# to search for them ourselves - except when the results are already set
+# where we skip the searches.
+
+# Unless the user overrides by setting SED, search the path for either GNU
+# sed, or the sed that truncates its output the least.
+test -z "$SED" && {
+  _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+  for _G_i in 1 2 3 4 5 6 7; do
+    _G_sed_script=$_G_sed_script$nl$_G_sed_script
+  done
+  echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed
+  _G_sed_script=
+
+  func_check_prog_sed ()
+  {
+    _G_path_prog=$1
+
+    _G_count=0
+    printf 0123456789 >conftest.in
+    while :
+    do
+      cat conftest.in conftest.in >conftest.tmp
+      mv conftest.tmp conftest.in
+      cp conftest.in conftest.nl
+      echo '' >> conftest.nl
+      "$_G_path_prog" -f conftest.sed <conftest.nl >conftest.out 2>/dev/null || break
+      diff conftest.out conftest.nl >/dev/null 2>&1 || break
+      _G_count=`expr $_G_count + 1`
+      if test "$_G_count" -gt "$_G_path_prog_max"; then
+        # Best one so far, save it but keep looking for a better one
+        func_check_prog_result=$_G_path_prog
+        _G_path_prog_max=$_G_count
+      fi
+      # 10*(2^10) chars as input seems more than enough
+      test 10 -lt "$_G_count" && break
+    done
+    rm -f conftest.in conftest.tmp conftest.nl conftest.out
+  }
+
+  func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin
+  rm -f conftest.sed
+  SED=$func_path_progs_result
+}
+
+
+# Unless the user overrides by setting GREP, search the path for either GNU
+# grep, or the grep that truncates its output the least.
+test -z "$GREP" && {
+  func_check_prog_grep ()
+  {
+    _G_path_prog=$1
+
+    _G_count=0
+    _G_path_prog_max=0
+    printf 0123456789 >conftest.in
+    while :
+    do
+      cat conftest.in conftest.in >conftest.tmp
+      mv conftest.tmp conftest.in
+      cp conftest.in conftest.nl
+      echo 'GREP' >> conftest.nl
+      "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' <conftest.nl >conftest.out 2>/dev/null || break
+      diff conftest.out conftest.nl >/dev/null 2>&1 || break
+      _G_count=`expr $_G_count + 1`
+      if test "$_G_count" -gt "$_G_path_prog_max"; then
+        # Best one so far, save it but keep looking for a better one
+        func_check_prog_result=$_G_path_prog
+        _G_path_prog_max=$_G_count
+      fi
+      # 10*(2^10) chars as input seems more than enough
+      test 10 -lt "$_G_count" && break
+    done
+    rm -f conftest.in conftest.tmp conftest.nl conftest.out
+  }
+
+  func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin
+  GREP=$func_path_progs_result
+}
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# All uppercase variable names are used for environment variables.  These
+# variables can be overridden by the user before calling a script that
+# uses them if a suitable command of that name is not already available
+# in the command search PATH.
+
+: ${CP="cp -f"}
+: ${ECHO="printf %s\n"}
+: ${EGREP="$GREP -E"}
+: ${FGREP="$GREP -F"}
+: ${LN_S="ln -s"}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+
+
+## -------------------- ##
+## Useful sed snippets. ##
+## -------------------- ##
+
+sed_dirname='s|/[^/]*$||'
+sed_basename='s|^.*/||'
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Same as above, but do not quote variable references.
+sed_double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g'
+
+# Sed substitution that converts a w32 file name or path
+# that contains forward slashes, into one that contains
+# (escaped) backslashes.  A very naive implementation.
+sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-'\' parameter expansions in output of sed_double_quote_subst that
+# were '\'-ed in input to the same.  If an odd number of '\' preceded a
+# '$' in input to sed_double_quote_subst, that '$' was protected from
+# expansion.  Since each input '\' is now two '\'s, look for any number
+# of runs of four '\'s followed by two '\'s and then a '$'.  '\' that '$'.
+_G_bs='\\'
+_G_bs2='\\\\'
+_G_bs4='\\\\\\\\'
+_G_dollar='\$'
+sed_double_backslash="\
+  s/$_G_bs4/&\\
+/g
+  s/^$_G_bs2$_G_dollar/$_G_bs&/
+  s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g
+  s/\n//g"
+
+
+## ----------------- ##
+## Global variables. ##
+## ----------------- ##
+
+# Except for the global variables explicitly listed below, the following
+# functions in the '^func_' namespace, and the '^require_' namespace
+# variables initialised in the 'Resource management' section, sourcing
+# this file will not pollute your global namespace with anything
+# else. There's no portable way to scope variables in Bourne shell
+# though, so actually running these functions will sometimes place
+# results into a variable named after the function, and often use
+# temporary variables in the '^_G_' namespace. If you are careful to
+# avoid using those namespaces casually in your sourcing script, things
+# should continue to work as you expect. And, of course, you can freely
+# overwrite any of the functions or variables defined here before
+# calling anything to customize them.
+
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77	  # $? = 77 is used to indicate a skipped test to automake.
+
+# Allow overriding, eg assuming that you follow the convention of
+# putting '$debug_cmd' at the start of all your functions, you can get
+# bash to show function call trace with:
+#
+#    debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
+debug_cmd=${debug_cmd-":"}
+exit_cmd=:
+
+# By convention, finish your script with:
+#
+#    exit $exit_status
+#
+# so that you can set exit_status to non-zero if you want to indicate
+# something went wrong during execution without actually bailing out at
+# the point of failure.
+exit_status=$EXIT_SUCCESS
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath=$0
+
+# The name of this program.
+progname=`$ECHO "$progpath" |$SED "$sed_basename"`
+
+# Make sure we have an absolute progpath for reexecution:
+case $progpath in
+  [\\/]*|[A-Za-z]:\\*) ;;
+  *[\\/]*)
+     progdir=`$ECHO "$progpath" |$SED "$sed_dirname"`
+     progdir=`cd "$progdir" && pwd`
+     progpath=$progdir/$progname
+     ;;
+  *)
+     _G_IFS=$IFS
+     IFS=${PATH_SEPARATOR-:}
+     for progdir in $PATH; do
+       IFS=$_G_IFS
+       test -x "$progdir/$progname" && break
+     done
+     IFS=$_G_IFS
+     test -n "$progdir" || progdir=`pwd`
+     progpath=$progdir/$progname
+     ;;
+esac
+
+
+## ----------------- ##
+## Standard options. ##
+## ----------------- ##
+
+# The following options affect the operation of the functions defined
+# below, and should be set appropriately depending on run-time para-
+# meters passed on the command line.
+
+opt_dry_run=false
+opt_quiet=false
+opt_verbose=false
+
+# Categories 'all' and 'none' are always available.  Append any others
+# you will pass as the first argument to func_warning from your own
+# code.
+warning_categories=
+
+# By default, display warnings according to 'opt_warning_types'.  Set
+# 'warning_func'  to ':' to elide all warnings, or func_fatal_error to
+# treat the next displayed warning as a fatal error.
+warning_func=func_warn_and_continue
+
+# Set to 'all' to display all warnings, 'none' to suppress all
+# warnings, or a space delimited list of some subset of
+# 'warning_categories' to display only the listed warnings.
+opt_warning_types=all
+
+
+## -------------------- ##
+## Resource management. ##
+## -------------------- ##
+
+# This section contains definitions for functions that each ensure a
+# particular resource (a file, or a non-empty configuration variable for
+# example) is available, and if appropriate to extract default values
+# from pertinent package files. Call them using their associated
+# 'require_*' variable to ensure that they are executed, at most, once.
+#
+# It's entirely deliberate that calling these functions can set
+# variables that don't obey the namespace limitations obeyed by the rest
+# of this file, in order that that they be as useful as possible to
+# callers.
+
+
+# require_term_colors
+# -------------------
+# Allow display of bold text on terminals that support it.
+require_term_colors=func_require_term_colors
+func_require_term_colors ()
+{
+    $debug_cmd
+
+    test -t 1 && {
+      # COLORTERM and USE_ANSI_COLORS environment variables take
+      # precedence, because most terminfo databases neglect to describe
+      # whether color sequences are supported.
+      test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"}
+
+      if test 1 = "$USE_ANSI_COLORS"; then
+        # Standard ANSI escape sequences
+        tc_reset=''
+        tc_bold='';   tc_standout=''
+        tc_red='';   tc_green=''
+        tc_blue='';  tc_cyan=''
+      else
+        # Otherwise trust the terminfo database after all.
+        test -n "`tput sgr0 2>/dev/null`" && {
+          tc_reset=`tput sgr0`
+          test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold`
+          tc_standout=$tc_bold
+          test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso`
+          test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1`
+          test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2`
+          test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4`
+          test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5`
+        }
+      fi
+    }
+
+    require_term_colors=:
+}
+
+
+## ----------------- ##
+## Function library. ##
+## ----------------- ##
+
+# This section contains a variety of useful functions to call in your
+# scripts. Take note of the portable wrappers for features provided by
+# some modern shells, which will fall back to slower equivalents on
+# less featureful shells.
+
+
+# func_append VAR VALUE
+# ---------------------
+# Append VALUE onto the existing contents of VAR.
+
+  # We should try to minimise forks, especially on Windows where they are
+  # unreasonably slow, so skip the feature probes when bash or zsh are
+  # being used:
+  if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then
+    : ${_G_HAVE_ARITH_OP="yes"}
+    : ${_G_HAVE_XSI_OPS="yes"}
+    # The += operator was introduced in bash 3.1
+    case $BASH_VERSION in
+      [12].* | 3.0 | 3.0*) ;;
+      *)
+        : ${_G_HAVE_PLUSEQ_OP="yes"}
+        ;;
+    esac
+  fi
+
+  # _G_HAVE_PLUSEQ_OP
+  # Can be empty, in which case the shell is probed, "yes" if += is
+  # useable or anything else if it does not work.
+  test -z "$_G_HAVE_PLUSEQ_OP" \
+    && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \
+    && _G_HAVE_PLUSEQ_OP=yes
+
+if test yes = "$_G_HAVE_PLUSEQ_OP"
+then
+  # This is an XSI compatible shell, allowing a faster implementation...
+  eval 'func_append ()
+  {
+    $debug_cmd
+
+    eval "$1+=\$2"
+  }'
+else
+  # ...otherwise fall back to using expr, which is often a shell builtin.
+  func_append ()
+  {
+    $debug_cmd
+
+    eval "$1=\$$1\$2"
+  }
+fi
+
+
+# func_append_quoted VAR VALUE
+# ----------------------------
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+if test yes = "$_G_HAVE_PLUSEQ_OP"; then
+  eval 'func_append_quoted ()
+  {
+    $debug_cmd
+
+    func_quote_for_eval "$2"
+    eval "$1+=\\ \$func_quote_for_eval_result"
+  }'
+else
+  func_append_quoted ()
+  {
+    $debug_cmd
+
+    func_quote_for_eval "$2"
+    eval "$1=\$$1\\ \$func_quote_for_eval_result"
+  }
+fi
+
+
+# func_append_uniq VAR VALUE
+# --------------------------
+# Append unique VALUE onto the existing contents of VAR, assuming
+# entries are delimited by the first character of VALUE.  For example:
+#
+#   func_append_uniq options " --another-option option-argument"
+#
+# will only append to $options if " --another-option option-argument "
+# is not already present somewhere in $options already (note spaces at
+# each end implied by leading space in second argument).
+func_append_uniq ()
+{
+    $debug_cmd
+
+    eval _G_current_value='`$ECHO $'$1'`'
+    _G_delim=`expr "$2" : '\(.\)'`
+
+    case $_G_delim$_G_current_value$_G_delim in
+      *"$2$_G_delim"*) ;;
+      *) func_append "$@" ;;
+    esac
+}
+
+
+# func_arith TERM...
+# ------------------
+# Set func_arith_result to the result of evaluating TERMs.
+  test -z "$_G_HAVE_ARITH_OP" \
+    && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \
+    && _G_HAVE_ARITH_OP=yes
+
+if test yes = "$_G_HAVE_ARITH_OP"; then
+  eval 'func_arith ()
+  {
+    $debug_cmd
+
+    func_arith_result=$(( $* ))
+  }'
+else
+  func_arith ()
+  {
+    $debug_cmd
+
+    func_arith_result=`expr "$@"`
+  }
+fi
+
+
+# func_basename FILE
+# ------------------
+# Set func_basename_result to FILE with everything up to and including
+# the last / stripped.
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  # If this shell supports suffix pattern removal, then use it to avoid
+  # forking. Hide the definitions single quotes in case the shell chokes
+  # on unsupported syntax...
+  _b='func_basename_result=${1##*/}'
+  _d='case $1 in
+        */*) func_dirname_result=${1%/*}$2 ;;
+        *  ) func_dirname_result=$3        ;;
+      esac'
+
+else
+  # ...otherwise fall back to using sed.
+  _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`'
+  _d='func_dirname_result=`$ECHO "$1"  |$SED "$sed_dirname"`
+      if test "X$func_dirname_result" = "X$1"; then
+        func_dirname_result=$3
+      else
+        func_append func_dirname_result "$2"
+      fi'
+fi
+
+eval 'func_basename ()
+{
+    $debug_cmd
+
+    '"$_b"'
+}'
+
+
+# func_dirname FILE APPEND NONDIR_REPLACEMENT
+# -------------------------------------------
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+eval 'func_dirname ()
+{
+    $debug_cmd
+
+    '"$_d"'
+}'
+
+
+# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT
+# --------------------------------------------------------
+# Perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# For efficiency, we do not delegate to the functions above but instead
+# duplicate the functionality here.
+eval 'func_dirname_and_basename ()
+{
+    $debug_cmd
+
+    '"$_b"'
+    '"$_d"'
+}'
+
+
+# func_echo ARG...
+# ----------------
+# Echo program name prefixed message.
+func_echo ()
+{
+    $debug_cmd
+
+    _G_message=$*
+
+    func_echo_IFS=$IFS
+    IFS=$nl
+    for _G_line in $_G_message; do
+      IFS=$func_echo_IFS
+      $ECHO "$progname: $_G_line"
+    done
+    IFS=$func_echo_IFS
+}
+
+
+# func_echo_all ARG...
+# --------------------
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+
+# func_echo_infix_1 INFIX ARG...
+# ------------------------------
+# Echo program name, followed by INFIX on the first line, with any
+# additional lines not showing INFIX.
+func_echo_infix_1 ()
+{
+    $debug_cmd
+
+    $require_term_colors
+
+    _G_infix=$1; shift
+    _G_indent=$_G_infix
+    _G_prefix="$progname: $_G_infix: "
+    _G_message=$*
+
+    # Strip color escape sequences before counting printable length
+    for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan"
+    do
+      test -n "$_G_tc" && {
+        _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"`
+        _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"`
+      }
+    done
+    _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`"  " ## exclude from sc_prohibit_nested_quotes
+
+    func_echo_infix_1_IFS=$IFS
+    IFS=$nl
+    for _G_line in $_G_message; do
+      IFS=$func_echo_infix_1_IFS
+      $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2
+      _G_prefix=$_G_indent
+    done
+    IFS=$func_echo_infix_1_IFS
+}
+
+
+# func_error ARG...
+# -----------------
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+    $debug_cmd
+
+    $require_term_colors
+
+    func_echo_infix_1 "  $tc_standout${tc_red}error$tc_reset" "$*" >&2
+}
+
+
+# func_fatal_error ARG...
+# -----------------------
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+    $debug_cmd
+
+    func_error "$*"
+    exit $EXIT_FAILURE
+}
+
+
+# func_grep EXPRESSION FILENAME
+# -----------------------------
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+    $debug_cmd
+
+    $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_len STRING
+# ---------------
+# Set func_len_result to the length of STRING. STRING may not
+# start with a hyphen.
+  test -z "$_G_HAVE_XSI_OPS" \
+    && (eval 'x=a/b/c;
+      test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+    && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  eval 'func_len ()
+  {
+    $debug_cmd
+
+    func_len_result=${#1}
+  }'
+else
+  func_len ()
+  {
+    $debug_cmd
+
+    func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+  }
+fi
+
+
+# func_mkdir_p DIRECTORY-PATH
+# ---------------------------
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+    $debug_cmd
+
+    _G_directory_path=$1
+    _G_dir_list=
+
+    if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then
+
+      # Protect directory names starting with '-'
+      case $_G_directory_path in
+        -*) _G_directory_path=./$_G_directory_path ;;
+      esac
+
+      # While some portion of DIR does not yet exist...
+      while test ! -d "$_G_directory_path"; do
+        # ...make a list in topmost first order.  Use a colon delimited
+	# list incase some portion of path contains whitespace.
+        _G_dir_list=$_G_directory_path:$_G_dir_list
+
+        # If the last portion added has no slash in it, the list is done
+        case $_G_directory_path in */*) ;; *) break ;; esac
+
+        # ...otherwise throw away the child directory and loop
+        _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"`
+      done
+      _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'`
+
+      func_mkdir_p_IFS=$IFS; IFS=:
+      for _G_dir in $_G_dir_list; do
+	IFS=$func_mkdir_p_IFS
+        # mkdir can fail with a 'File exist' error if two processes
+        # try to create one of the directories concurrently.  Don't
+        # stop in that case!
+        $MKDIR "$_G_dir" 2>/dev/null || :
+      done
+      IFS=$func_mkdir_p_IFS
+
+      # Bail out if we (or some other process) failed to create a directory.
+      test -d "$_G_directory_path" || \
+        func_fatal_error "Failed to create '$1'"
+    fi
+}
+
+
+# func_mktempdir [BASENAME]
+# -------------------------
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible.  If
+# given, BASENAME is the basename for that directory.
+func_mktempdir ()
+{
+    $debug_cmd
+
+    _G_template=${TMPDIR-/tmp}/${1-$progname}
+
+    if test : = "$opt_dry_run"; then
+      # Return a directory name, but don't create it in dry-run mode
+      _G_tmpdir=$_G_template-$$
+    else
+
+      # If mktemp works, use that first and foremost
+      _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null`
+
+      if test ! -d "$_G_tmpdir"; then
+        # Failing that, at least try and use $RANDOM to avoid a race
+        _G_tmpdir=$_G_template-${RANDOM-0}$$
+
+        func_mktempdir_umask=`umask`
+        umask 0077
+        $MKDIR "$_G_tmpdir"
+        umask $func_mktempdir_umask
+      fi
+
+      # If we're not in dry-run mode, bomb out on failure
+      test -d "$_G_tmpdir" || \
+        func_fatal_error "cannot create temporary directory '$_G_tmpdir'"
+    fi
+
+    $ECHO "$_G_tmpdir"
+}
+
+
+# func_normal_abspath PATH
+# ------------------------
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+func_normal_abspath ()
+{
+    $debug_cmd
+
+    # These SED scripts presuppose an absolute path with a trailing slash.
+    _G_pathcar='s|^/\([^/]*\).*$|\1|'
+    _G_pathcdr='s|^/[^/]*||'
+    _G_removedotparts=':dotsl
+		s|/\./|/|g
+		t dotsl
+		s|/\.$|/|'
+    _G_collapseslashes='s|/\{1,\}|/|g'
+    _G_finalslash='s|/*$|/|'
+
+    # Start from root dir and reassemble the path.
+    func_normal_abspath_result=
+    func_normal_abspath_tpath=$1
+    func_normal_abspath_altnamespace=
+    case $func_normal_abspath_tpath in
+      "")
+        # Empty path, that just means $cwd.
+        func_stripname '' '/' "`pwd`"
+        func_normal_abspath_result=$func_stripname_result
+        return
+        ;;
+      # The next three entries are used to spot a run of precisely
+      # two leading slashes without using negated character classes;
+      # we take advantage of case's first-match behaviour.
+      ///*)
+        # Unusual form of absolute path, do nothing.
+        ;;
+      //*)
+        # Not necessarily an ordinary path; POSIX reserves leading '//'
+        # and for example Cygwin uses it to access remote file shares
+        # over CIFS/SMB, so we conserve a leading double slash if found.
+        func_normal_abspath_altnamespace=/
+        ;;
+      /*)
+        # Absolute path, do nothing.
+        ;;
+      *)
+        # Relative path, prepend $cwd.
+        func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+        ;;
+    esac
+
+    # Cancel out all the simple stuff to save iterations.  We also want
+    # the path to end with a slash for ease of parsing, so make sure
+    # there is one (and only one) here.
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+          -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"`
+    while :; do
+      # Processed it all yet?
+      if test / = "$func_normal_abspath_tpath"; then
+        # If we ascended to the root using ".." the result may be empty now.
+        if test -z "$func_normal_abspath_result"; then
+          func_normal_abspath_result=/
+        fi
+        break
+      fi
+      func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+          -e "$_G_pathcar"`
+      func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+          -e "$_G_pathcdr"`
+      # Figure out what to do with it
+      case $func_normal_abspath_tcomponent in
+        "")
+          # Trailing empty path component, ignore it.
+          ;;
+        ..)
+          # Parent dir; strip last assembled component from result.
+          func_dirname "$func_normal_abspath_result"
+          func_normal_abspath_result=$func_dirname_result
+          ;;
+        *)
+          # Actual path component, append it.
+          func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent"
+          ;;
+      esac
+    done
+    # Restore leading double-slash if one was found on entry.
+    func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+
+# func_notquiet ARG...
+# --------------------
+# Echo program name prefixed message only when not in quiet mode.
+func_notquiet ()
+{
+    $debug_cmd
+
+    $opt_quiet || func_echo ${1+"$@"}
+
+    # A bug in bash halts the script if the last line of a function
+    # fails when set -e is in force, so we need another command to
+    # work around that:
+    :
+}
+
+
+# func_relative_path SRCDIR DSTDIR
+# --------------------------------
+# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR.
+func_relative_path ()
+{
+    $debug_cmd
+
+    func_relative_path_result=
+    func_normal_abspath "$1"
+    func_relative_path_tlibdir=$func_normal_abspath_result
+    func_normal_abspath "$2"
+    func_relative_path_tbindir=$func_normal_abspath_result
+
+    # Ascend the tree starting from libdir
+    while :; do
+      # check if we have found a prefix of bindir
+      case $func_relative_path_tbindir in
+        $func_relative_path_tlibdir)
+          # found an exact match
+          func_relative_path_tcancelled=
+          break
+          ;;
+        $func_relative_path_tlibdir*)
+          # found a matching prefix
+          func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+          func_relative_path_tcancelled=$func_stripname_result
+          if test -z "$func_relative_path_result"; then
+            func_relative_path_result=.
+          fi
+          break
+          ;;
+        *)
+          func_dirname $func_relative_path_tlibdir
+          func_relative_path_tlibdir=$func_dirname_result
+          if test -z "$func_relative_path_tlibdir"; then
+            # Have to descend all the way to the root!
+            func_relative_path_result=../$func_relative_path_result
+            func_relative_path_tcancelled=$func_relative_path_tbindir
+            break
+          fi
+          func_relative_path_result=../$func_relative_path_result
+          ;;
+      esac
+    done
+
+    # Now calculate path; take care to avoid doubling-up slashes.
+    func_stripname '' '/' "$func_relative_path_result"
+    func_relative_path_result=$func_stripname_result
+    func_stripname '/' '/' "$func_relative_path_tcancelled"
+    if test -n "$func_stripname_result"; then
+      func_append func_relative_path_result "/$func_stripname_result"
+    fi
+
+    # Normalisation. If bindir is libdir, return '.' else relative path.
+    if test -n "$func_relative_path_result"; then
+      func_stripname './' '' "$func_relative_path_result"
+      func_relative_path_result=$func_stripname_result
+    fi
+
+    test -n "$func_relative_path_result" || func_relative_path_result=.
+
+    :
+}
+
+
+# func_quote_for_eval ARG...
+# --------------------------
+# Aesthetically quote ARGs to be evaled later.
+# This function returns two values:
+#   i) func_quote_for_eval_result
+#      double-quoted, suitable for a subsequent eval
+#  ii) func_quote_for_eval_unquoted_result
+#      has all characters that are still active within double
+#      quotes backslashified.
+func_quote_for_eval ()
+{
+    $debug_cmd
+
+    func_quote_for_eval_unquoted_result=
+    func_quote_for_eval_result=
+    while test 0 -lt $#; do
+      case $1 in
+        *[\\\`\"\$]*)
+	  _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
+        *)
+          _G_unquoted_arg=$1 ;;
+      esac
+      if test -n "$func_quote_for_eval_unquoted_result"; then
+	func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg"
+      else
+        func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg"
+      fi
+
+      case $_G_unquoted_arg in
+        # Double-quote args containing shell metacharacters to delay
+        # word splitting, command substitution and variable expansion
+        # for a subsequent eval.
+        # Many Bourne shells cannot handle close brackets correctly
+        # in scan sets, so we specify it separately.
+        *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+          _G_quoted_arg=\"$_G_unquoted_arg\"
+          ;;
+        *)
+          _G_quoted_arg=$_G_unquoted_arg
+	  ;;
+      esac
+
+      if test -n "$func_quote_for_eval_result"; then
+	func_append func_quote_for_eval_result " $_G_quoted_arg"
+      else
+        func_append func_quote_for_eval_result "$_G_quoted_arg"
+      fi
+      shift
+    done
+}
+
+
+# func_quote_for_expand ARG
+# -------------------------
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    $debug_cmd
+
+    case $1 in
+      *[\\\`\"]*)
+	_G_arg=`$ECHO "$1" | $SED \
+	    -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        _G_arg=$1 ;;
+    esac
+
+    case $_G_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        _G_arg=\"$_G_arg\"
+        ;;
+    esac
+
+    func_quote_for_expand_result=$_G_arg
+}
+
+
+# func_stripname PREFIX SUFFIX NAME
+# ---------------------------------
+# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  eval 'func_stripname ()
+  {
+    $debug_cmd
+
+    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+    # positional parameters, so assign one to ordinary variable first.
+    func_stripname_result=$3
+    func_stripname_result=${func_stripname_result#"$1"}
+    func_stripname_result=${func_stripname_result%"$2"}
+  }'
+else
+  func_stripname ()
+  {
+    $debug_cmd
+
+    case $2 in
+      .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;;
+      *)  func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;;
+    esac
+  }
+fi
+
+
+# func_show_eval CMD [FAIL_EXP]
+# -----------------------------
+# Unless opt_quiet is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+    $debug_cmd
+
+    _G_cmd=$1
+    _G_fail_exp=${2-':'}
+
+    func_quote_for_expand "$_G_cmd"
+    eval "func_notquiet $func_quote_for_expand_result"
+
+    $opt_dry_run || {
+      eval "$_G_cmd"
+      _G_status=$?
+      if test 0 -ne "$_G_status"; then
+	eval "(exit $_G_status); $_G_fail_exp"
+      fi
+    }
+}
+
+
+# func_show_eval_locale CMD [FAIL_EXP]
+# ------------------------------------
+# Unless opt_quiet is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.  Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+    $debug_cmd
+
+    _G_cmd=$1
+    _G_fail_exp=${2-':'}
+
+    $opt_quiet || {
+      func_quote_for_expand "$_G_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    $opt_dry_run || {
+      eval "$_G_user_locale
+	    $_G_cmd"
+      _G_status=$?
+      eval "$_G_safe_locale"
+      if test 0 -ne "$_G_status"; then
+	eval "(exit $_G_status); $_G_fail_exp"
+      fi
+    }
+}
+
+
+# func_tr_sh
+# ----------
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result.  All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+    $debug_cmd
+
+    case $1 in
+    [0-9]* | *[!a-zA-Z0-9_]*)
+      func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'`
+      ;;
+    * )
+      func_tr_sh_result=$1
+      ;;
+    esac
+}
+
+
+# func_verbose ARG...
+# -------------------
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+    $debug_cmd
+
+    $opt_verbose && func_echo "$*"
+
+    :
+}
+
+
+# func_warn_and_continue ARG...
+# -----------------------------
+# Echo program name prefixed warning message to standard error.
+func_warn_and_continue ()
+{
+    $debug_cmd
+
+    $require_term_colors
+
+    func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2
+}
+
+
+# func_warning CATEGORY ARG...
+# ----------------------------
+# Echo program name prefixed warning message to standard error. Warning
+# messages can be filtered according to CATEGORY, where this function
+# elides messages where CATEGORY is not listed in the global variable
+# 'opt_warning_types'.
+func_warning ()
+{
+    $debug_cmd
+
+    # CATEGORY must be in the warning_categories list!
+    case " $warning_categories " in
+      *" $1 "*) ;;
+      *) func_internal_error "invalid warning category '$1'" ;;
+    esac
+
+    _G_category=$1
+    shift
+
+    case " $opt_warning_types " in
+      *" $_G_category "*) $warning_func ${1+"$@"} ;;
+    esac
+}
+
+
+# func_sort_ver VER1 VER2
+# -----------------------
+# 'sort -V' is not generally available.
+# Note this deviates from the version comparison in automake
+# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a
+# but this should suffice as we won't be specifying old
+# version formats or redundant trailing .0 in bootstrap.conf.
+# If we did want full compatibility then we should probably
+# use m4_version_compare from autoconf.
+func_sort_ver ()
+{
+    $debug_cmd
+
+    printf '%s\n%s\n' "$1" "$2" \
+      | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n
+}
+
+# func_lt_ver PREV CURR
+# ---------------------
+# Return true if PREV and CURR are in the correct order according to
+# func_sort_ver, otherwise false.  Use it like this:
+#
+#  func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..."
+func_lt_ver ()
+{
+    $debug_cmd
+
+    test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q`
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+#! /bin/sh
+
+# Set a version string for this script.
+scriptversion=2014-01-07.03; # UTC
+
+# A portable, pluggable option parser for Bourne shell.
+# Written by Gary V. Vaughan, 2010
+
+# Copyright (C) 2010-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# This file is a library for parsing options in your shell scripts along
+# with assorted other useful supporting features that you can make use
+# of too.
+#
+# For the simplest scripts you might need only:
+#
+#   #!/bin/sh
+#   . relative/path/to/funclib.sh
+#   . relative/path/to/options-parser
+#   scriptversion=1.0
+#   func_options ${1+"$@"}
+#   eval set dummy "$func_options_result"; shift
+#   ...rest of your script...
+#
+# In order for the '--version' option to work, you will need to have a
+# suitably formatted comment like the one at the top of this file
+# starting with '# Written by ' and ending with '# warranty; '.
+#
+# For '-h' and '--help' to work, you will also need a one line
+# description of your script's purpose in a comment directly above the
+# '# Written by ' line, like the one at the top of this file.
+#
+# The default options also support '--debug', which will turn on shell
+# execution tracing (see the comment above debug_cmd below for another
+# use), and '--verbose' and the func_verbose function to allow your script
+# to display verbose messages only when your user has specified
+# '--verbose'.
+#
+# After sourcing this file, you can plug processing for additional
+# options by amending the variables from the 'Configuration' section
+# below, and following the instructions in the 'Option parsing'
+# section further down.
+
+## -------------- ##
+## Configuration. ##
+## -------------- ##
+
+# You should override these variables in your script after sourcing this
+# file so that they reflect the customisations you have added to the
+# option parser.
+
+# The usage line for option parsing errors and the start of '-h' and
+# '--help' output messages. You can embed shell variables for delayed
+# expansion at the time the message is displayed, but you will need to
+# quote other shell meta-characters carefully to prevent them being
+# expanded when the contents are evaled.
+usage='$progpath [OPTION]...'
+
+# Short help message in response to '-h' and '--help'.  Add to this or
+# override it after sourcing this library to reflect the full set of
+# options your script accepts.
+usage_message="\
+       --debug        enable verbose shell tracing
+   -W, --warnings=CATEGORY
+                      report the warnings falling in CATEGORY [all]
+   -v, --verbose      verbosely report processing
+       --version      print version information and exit
+   -h, --help         print short or long help message and exit
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+long_help_message="
+Warning categories include:
+       'all'          show all warnings
+       'none'         turn off all the warnings
+       'error'        warnings are treated as fatal errors"
+
+# Help message printed before fatal option parsing errors.
+fatal_help="Try '\$progname --help' for more information."
+
+
+
+## ------------------------- ##
+## Hook function management. ##
+## ------------------------- ##
+
+# This section contains functions for adding, removing, and running hooks
+# to the main code.  A hook is just a named list of of function, that can
+# be run in order later on.
+
+# func_hookable FUNC_NAME
+# -----------------------
+# Declare that FUNC_NAME will run hooks added with
+# 'func_add_hook FUNC_NAME ...'.
+func_hookable ()
+{
+    $debug_cmd
+
+    func_append hookable_fns " $1"
+}
+
+
+# func_add_hook FUNC_NAME HOOK_FUNC
+# ---------------------------------
+# Request that FUNC_NAME call HOOK_FUNC before it returns.  FUNC_NAME must
+# first have been declared "hookable" by a call to 'func_hookable'.
+func_add_hook ()
+{
+    $debug_cmd
+
+    case " $hookable_fns " in
+      *" $1 "*) ;;
+      *) func_fatal_error "'$1' does not accept hook functions." ;;
+    esac
+
+    eval func_append ${1}_hooks '" $2"'
+}
+
+
+# func_remove_hook FUNC_NAME HOOK_FUNC
+# ------------------------------------
+# Remove HOOK_FUNC from the list of functions called by FUNC_NAME.
+func_remove_hook ()
+{
+    $debug_cmd
+
+    eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`'
+}
+
+
+# func_run_hooks FUNC_NAME [ARG]...
+# ---------------------------------
+# Run all hook functions registered to FUNC_NAME.
+# It is assumed that the list of hook functions contains nothing more
+# than a whitespace-delimited list of legal shell function names, and
+# no effort is wasted trying to catch shell meta-characters or preserve
+# whitespace.
+func_run_hooks ()
+{
+    $debug_cmd
+
+    case " $hookable_fns " in
+      *" $1 "*) ;;
+      *) func_fatal_error "'$1' does not support hook funcions.n" ;;
+    esac
+
+    eval _G_hook_fns=\$$1_hooks; shift
+
+    for _G_hook in $_G_hook_fns; do
+      eval $_G_hook '"$@"'
+
+      # store returned options list back into positional
+      # parameters for next 'cmd' execution.
+      eval _G_hook_result=\$${_G_hook}_result
+      eval set dummy "$_G_hook_result"; shift
+    done
+
+    func_quote_for_eval ${1+"$@"}
+    func_run_hooks_result=$func_quote_for_eval_result
+}
+
+
+
+## --------------- ##
+## Option parsing. ##
+## --------------- ##
+
+# In order to add your own option parsing hooks, you must accept the
+# full positional parameter list in your hook function, remove any
+# options that you action, and then pass back the remaining unprocessed
+# options in '<hooked_function_name>_result', escaped suitably for
+# 'eval'.  Like this:
+#
+#    my_options_prep ()
+#    {
+#        $debug_cmd
+#
+#        # Extend the existing usage message.
+#        usage_message=$usage_message'
+#      -s, --silent       don'\''t print informational messages
+#    '
+#
+#        func_quote_for_eval ${1+"$@"}
+#        my_options_prep_result=$func_quote_for_eval_result
+#    }
+#    func_add_hook func_options_prep my_options_prep
+#
+#
+#    my_silent_option ()
+#    {
+#        $debug_cmd
+#
+#        # Note that for efficiency, we parse as many options as we can
+#        # recognise in a loop before passing the remainder back to the
+#        # caller on the first unrecognised argument we encounter.
+#        while test $# -gt 0; do
+#          opt=$1; shift
+#          case $opt in
+#            --silent|-s) opt_silent=: ;;
+#            # Separate non-argument short options:
+#            -s*)         func_split_short_opt "$_G_opt"
+#                         set dummy "$func_split_short_opt_name" \
+#                             "-$func_split_short_opt_arg" ${1+"$@"}
+#                         shift
+#                         ;;
+#            *)            set dummy "$_G_opt" "$*"; shift; break ;;
+#          esac
+#        done
+#
+#        func_quote_for_eval ${1+"$@"}
+#        my_silent_option_result=$func_quote_for_eval_result
+#    }
+#    func_add_hook func_parse_options my_silent_option
+#
+#
+#    my_option_validation ()
+#    {
+#        $debug_cmd
+#
+#        $opt_silent && $opt_verbose && func_fatal_help "\
+#    '--silent' and '--verbose' options are mutually exclusive."
+#
+#        func_quote_for_eval ${1+"$@"}
+#        my_option_validation_result=$func_quote_for_eval_result
+#    }
+#    func_add_hook func_validate_options my_option_validation
+#
+# You'll alse need to manually amend $usage_message to reflect the extra
+# options you parse.  It's preferable to append if you can, so that
+# multiple option parsing hooks can be added safely.
+
+
+# func_options [ARG]...
+# ---------------------
+# All the functions called inside func_options are hookable. See the
+# individual implementations for details.
+func_hookable func_options
+func_options ()
+{
+    $debug_cmd
+
+    func_options_prep ${1+"$@"}
+    eval func_parse_options \
+        ${func_options_prep_result+"$func_options_prep_result"}
+    eval func_validate_options \
+        ${func_parse_options_result+"$func_parse_options_result"}
+
+    eval func_run_hooks func_options \
+        ${func_validate_options_result+"$func_validate_options_result"}
+
+    # save modified positional parameters for caller
+    func_options_result=$func_run_hooks_result
+}
+
+
+# func_options_prep [ARG]...
+# --------------------------
+# All initialisations required before starting the option parse loop.
+# Note that when calling hook functions, we pass through the list of
+# positional parameters.  If a hook function modifies that list, and
+# needs to propogate that back to rest of this script, then the complete
+# modified list must be put in 'func_run_hooks_result' before
+# returning.
+func_hookable func_options_prep
+func_options_prep ()
+{
+    $debug_cmd
+
+    # Option defaults:
+    opt_verbose=false
+    opt_warning_types=
+
+    func_run_hooks func_options_prep ${1+"$@"}
+
+    # save modified positional parameters for caller
+    func_options_prep_result=$func_run_hooks_result
+}
+
+
+# func_parse_options [ARG]...
+# ---------------------------
+# The main option parsing loop.
+func_hookable func_parse_options
+func_parse_options ()
+{
+    $debug_cmd
+
+    func_parse_options_result=
+
+    # this just eases exit handling
+    while test $# -gt 0; do
+      # Defer to hook functions for initial option parsing, so they
+      # get priority in the event of reusing an option name.
+      func_run_hooks func_parse_options ${1+"$@"}
+
+      # Adjust func_parse_options positional parameters to match
+      eval set dummy "$func_run_hooks_result"; shift
+
+      # Break out of the loop if we already parsed every option.
+      test $# -gt 0 || break
+
+      _G_opt=$1
+      shift
+      case $_G_opt in
+        --debug|-x)   debug_cmd='set -x'
+                      func_echo "enabling shell trace mode"
+                      $debug_cmd
+                      ;;
+
+        --no-warnings|--no-warning|--no-warn)
+                      set dummy --warnings none ${1+"$@"}
+                      shift
+		      ;;
+
+        --warnings|--warning|-W)
+                      test $# = 0 && func_missing_arg $_G_opt && break
+                      case " $warning_categories $1" in
+                        *" $1 "*)
+                          # trailing space prevents matching last $1 above
+                          func_append_uniq opt_warning_types " $1"
+                          ;;
+                        *all)
+                          opt_warning_types=$warning_categories
+                          ;;
+                        *none)
+                          opt_warning_types=none
+                          warning_func=:
+                          ;;
+                        *error)
+                          opt_warning_types=$warning_categories
+                          warning_func=func_fatal_error
+                          ;;
+                        *)
+                          func_fatal_error \
+                             "unsupported warning category: '$1'"
+                          ;;
+                      esac
+                      shift
+                      ;;
+
+        --verbose|-v) opt_verbose=: ;;
+        --version)    func_version ;;
+        -\?|-h)       func_usage ;;
+        --help)       func_help ;;
+
+	# Separate optargs to long options (plugins may need this):
+	--*=*)        func_split_equals "$_G_opt"
+	              set dummy "$func_split_equals_lhs" \
+                          "$func_split_equals_rhs" ${1+"$@"}
+                      shift
+                      ;;
+
+       # Separate optargs to short options:
+        -W*)
+                      func_split_short_opt "$_G_opt"
+                      set dummy "$func_split_short_opt_name" \
+                          "$func_split_short_opt_arg" ${1+"$@"}
+                      shift
+                      ;;
+
+        # Separate non-argument short options:
+        -\?*|-h*|-v*|-x*)
+                      func_split_short_opt "$_G_opt"
+                      set dummy "$func_split_short_opt_name" \
+                          "-$func_split_short_opt_arg" ${1+"$@"}
+                      shift
+                      ;;
+
+        --)           break ;;
+        -*)           func_fatal_help "unrecognised option: '$_G_opt'" ;;
+        *)            set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
+      esac
+    done
+
+    # save modified positional parameters for caller
+    func_quote_for_eval ${1+"$@"}
+    func_parse_options_result=$func_quote_for_eval_result
+}
+
+
+# func_validate_options [ARG]...
+# ------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+func_hookable func_validate_options
+func_validate_options ()
+{
+    $debug_cmd
+
+    # Display all warnings if -W was not given.
+    test -n "$opt_warning_types" || opt_warning_types=" $warning_categories"
+
+    func_run_hooks func_validate_options ${1+"$@"}
+
+    # Bail if the options were screwed!
+    $exit_cmd $EXIT_FAILURE
+
+    # save modified positional parameters for caller
+    func_validate_options_result=$func_run_hooks_result
+}
+
+
+
+## ----------------- ##
+## Helper functions. ##
+## ----------------- ##
+
+# This section contains the helper functions used by the rest of the
+# hookable option parser framework in ascii-betical order.
+
+
+# func_fatal_help ARG...
+# ----------------------
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+    $debug_cmd
+
+    eval \$ECHO \""Usage: $usage"\"
+    eval \$ECHO \""$fatal_help"\"
+    func_error ${1+"$@"}
+    exit $EXIT_FAILURE
+}
+
+
+# func_help
+# ---------
+# Echo long help message to standard output and exit.
+func_help ()
+{
+    $debug_cmd
+
+    func_usage_message
+    $ECHO "$long_help_message"
+    exit 0
+}
+
+
+# func_missing_arg ARGNAME
+# ------------------------
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+    $debug_cmd
+
+    func_error "Missing argument for '$1'."
+    exit_cmd=exit
+}
+
+
+# func_split_equals STRING
+# ------------------------
+# Set func_split_equals_lhs and func_split_equals_rhs shell variables after
+# splitting STRING at the '=' sign.
+test -z "$_G_HAVE_XSI_OPS" \
+    && (eval 'x=a/b/c;
+      test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+    && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+  # This is an XSI compatible shell, allowing a faster implementation...
+  eval 'func_split_equals ()
+  {
+      $debug_cmd
+
+      func_split_equals_lhs=${1%%=*}
+      func_split_equals_rhs=${1#*=}
+      test "x$func_split_equals_lhs" = "x$1" \
+        && func_split_equals_rhs=
+  }'
+else
+  # ...otherwise fall back to using expr, which is often a shell builtin.
+  func_split_equals ()
+  {
+      $debug_cmd
+
+      func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'`
+      func_split_equals_rhs=
+      test "x$func_split_equals_lhs" = "x$1" \
+        || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'`
+  }
+fi #func_split_equals
+
+
+# func_split_short_opt SHORTOPT
+# -----------------------------
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+  # This is an XSI compatible shell, allowing a faster implementation...
+  eval 'func_split_short_opt ()
+  {
+      $debug_cmd
+
+      func_split_short_opt_arg=${1#??}
+      func_split_short_opt_name=${1%"$func_split_short_opt_arg"}
+  }'
+else
+  # ...otherwise fall back to using expr, which is often a shell builtin.
+  func_split_short_opt ()
+  {
+      $debug_cmd
+
+      func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'`
+      func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'`
+  }
+fi #func_split_short_opt
+
+
+# func_usage
+# ----------
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+    $debug_cmd
+
+    func_usage_message
+    $ECHO "Run '$progname --help |${PAGER-more}' for full usage"
+    exit 0
+}
+
+
+# func_usage_message
+# ------------------
+# Echo short help message to standard output.
+func_usage_message ()
+{
+    $debug_cmd
+
+    eval \$ECHO \""Usage: $usage"\"
+    echo
+    $SED -n 's|^# ||
+        /^Written by/{
+          x;p;x
+        }
+	h
+	/^Written by/q' < "$progpath"
+    echo
+    eval \$ECHO \""$usage_message"\"
+}
+
+
+# func_version
+# ------------
+# Echo version message to standard output and exit.
+func_version ()
+{
+    $debug_cmd
+
+    printf '%s\n' "$progname $scriptversion"
+    $SED -n '
+        /(C)/!b go
+        :more
+        /\./!{
+          N
+          s|\n# | |
+          b more
+        }
+        :go
+        /^# Written by /,/# warranty; / {
+          s|^# ||
+          s|^# *$||
+          s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
+          p
+        }
+        /^# Written by / {
+          s|^# ||
+          p
+        }
+        /^warranty; /q' < "$progpath"
+
+    exit $?
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+
+# Set a version string.
+scriptversion='(GNU libtool) 2.4.6 Debian-2.4.6-1'
+
+
+# func_echo ARG...
+# ----------------
+# Libtool also displays the current mode in messages, so override
+# funclib.sh func_echo with this custom definition.
+func_echo ()
+{
+    $debug_cmd
+
+    _G_message=$*
+
+    func_echo_IFS=$IFS
+    IFS=$nl
+    for _G_line in $_G_message; do
+      IFS=$func_echo_IFS
+      $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line"
+    done
+    IFS=$func_echo_IFS
+}
+
+
+# func_warning ARG...
+# -------------------
+# Libtool warnings are not categorized, so override funclib.sh
+# func_warning with this simpler definition.
+func_warning ()
+{
+    $debug_cmd
+
+    $warning_func ${1+"$@"}
+}
+
+
+## ---------------- ##
+## Options parsing. ##
+## ---------------- ##
+
+# Hook in the functions to make sure our own options are parsed during
+# the option parsing loop.
+
+usage='$progpath [OPTION]... [MODE-ARG]...'
+
+# Short help message in response to '-h'.
+usage_message="Options:
+       --config             show all configuration variables
+       --debug              enable verbose shell tracing
+   -n, --dry-run            display commands without modifying any files
+       --features           display basic configuration information and exit
+       --mode=MODE          use operation mode MODE
+       --no-warnings        equivalent to '-Wnone'
+       --preserve-dup-deps  don't remove duplicate dependency libraries
+       --quiet, --silent    don't print informational messages
+       --tag=TAG            use configuration variables from tag TAG
+   -v, --verbose            print more informational messages than default
+       --version            print version information
+   -W, --warnings=CATEGORY  report the warnings falling in CATEGORY [all]
+   -h, --help, --help-all   print short, long, or detailed help message
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+func_help ()
+{
+    $debug_cmd
+
+    func_usage_message
+    $ECHO "$long_help_message
+
+MODE must be one of the following:
+
+       clean           remove files from the build directory
+       compile         compile a source file into a libtool object
+       execute         automatically set library path, then run a program
+       finish          complete the installation of libtool libraries
+       install         install libraries or executables
+       link            create a library or an executable
+       uninstall       remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE.  When passed as first option,
+'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that.
+Try '$progname --help --mode=MODE' for a more detailed description of MODE.
+
+When reporting a bug, please describe a test case to reproduce it and
+include the following information:
+
+       host-triplet:   $host
+       shell:          $SHELL
+       compiler:       $LTCC
+       compiler flags: $LTCFLAGS
+       linker:         $LD (gnu? $with_gnu_ld)
+       version:        $progname $scriptversion
+       automake:       `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
+       autoconf:       `($AUTOCONF --version) 2>/dev/null |$SED 1q`
+
+Report bugs to <bug-libtool@gnu.org>.
+GNU libtool home page: <http://www.gnu.org/s/libtool/>.
+General help using GNU software: <http://www.gnu.org/gethelp/>."
+    exit 0
+}
+
+
+# func_lo2o OBJECT-NAME
+# ---------------------
+# Transform OBJECT-NAME from a '.lo' suffix to the platform specific
+# object suffix.
+
+lo2o=s/\\.lo\$/.$objext/
+o2lo=s/\\.$objext\$/.lo/
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  eval 'func_lo2o ()
+  {
+    case $1 in
+      *.lo) func_lo2o_result=${1%.lo}.$objext ;;
+      *   ) func_lo2o_result=$1               ;;
+    esac
+  }'
+
+  # func_xform LIBOBJ-OR-SOURCE
+  # ---------------------------
+  # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise)
+  # suffix to a '.lo' libtool-object suffix.
+  eval 'func_xform ()
+  {
+    func_xform_result=${1%.*}.lo
+  }'
+else
+  # ...otherwise fall back to using sed.
+  func_lo2o ()
+  {
+    func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"`
+  }
+
+  func_xform ()
+  {
+    func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'`
+  }
+fi
+
+
+# func_fatal_configuration ARG...
+# -------------------------------
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+    func__fatal_error ${1+"$@"} \
+      "See the $PACKAGE documentation for more information." \
+      "Fatal configuration error."
+}
+
+
+# func_config
+# -----------
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+    re_begincf='^# ### BEGIN LIBTOOL'
+    re_endcf='^# ### END LIBTOOL'
+
+    # Default configuration.
+    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+    done
+
+    exit $?
+}
+
+
+# func_features
+# -------------
+# Display the features supported by this script.
+func_features ()
+{
+    echo "host: $host"
+    if test yes = "$build_libtool_libs"; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test yes = "$build_old_libs"; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+
+    exit $?
+}
+
+
+# func_enable_tag TAGNAME
+# -----------------------
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+    # Global variable:
+    tagname=$1
+
+    re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+    re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+    sed_extractcf=/$re_begincf/,/$re_endcf/p
+
+    # Validate tagname.
+    case $tagname in
+      *[!-_A-Za-z0-9,/]*)
+        func_fatal_error "invalid tag name: $tagname"
+        ;;
+    esac
+
+    # Don't test for the "default" C tag, as we know it's
+    # there but not specially marked.
+    case $tagname in
+        CC) ;;
+    *)
+        if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+	  taglist="$taglist $tagname"
+
+	  # Evaluate the configuration.  Be careful to quote the path
+	  # and the sed script, to avoid splitting on whitespace, but
+	  # also don't use non-portable quotes within backquotes within
+	  # quotes we have to do it in 2 steps:
+	  extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+	  eval "$extractedcf"
+        else
+	  func_error "ignoring unknown tag $tagname"
+        fi
+        ;;
+    esac
+}
+
+
+# func_check_version_match
+# ------------------------
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+    if test "$package_revision" != "$macro_revision"; then
+      if test "$VERSION" != "$macro_version"; then
+        if test -z "$macro_version"; then
+          cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+        else
+          cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+        fi
+      else
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+      fi
+
+      exit $EXIT_MISMATCH
+    fi
+}
+
+
+# libtool_options_prep [ARG]...
+# -----------------------------
+# Preparation for options parsed by libtool.
+libtool_options_prep ()
+{
+    $debug_mode
+
+    # Option defaults:
+    opt_config=false
+    opt_dlopen=
+    opt_dry_run=false
+    opt_help=false
+    opt_mode=
+    opt_preserve_dup_deps=false
+    opt_quiet=false
+
+    nonopt=
+    preserve_args=
+
+    # Shorthand for --mode=foo, only valid as the first argument
+    case $1 in
+    clean|clea|cle|cl)
+      shift; set dummy --mode clean ${1+"$@"}; shift
+      ;;
+    compile|compil|compi|comp|com|co|c)
+      shift; set dummy --mode compile ${1+"$@"}; shift
+      ;;
+    execute|execut|execu|exec|exe|ex|e)
+      shift; set dummy --mode execute ${1+"$@"}; shift
+      ;;
+    finish|finis|fini|fin|fi|f)
+      shift; set dummy --mode finish ${1+"$@"}; shift
+      ;;
+    install|instal|insta|inst|ins|in|i)
+      shift; set dummy --mode install ${1+"$@"}; shift
+      ;;
+    link|lin|li|l)
+      shift; set dummy --mode link ${1+"$@"}; shift
+      ;;
+    uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+      shift; set dummy --mode uninstall ${1+"$@"}; shift
+      ;;
+    esac
+
+    # Pass back the list of options.
+    func_quote_for_eval ${1+"$@"}
+    libtool_options_prep_result=$func_quote_for_eval_result
+}
+func_add_hook func_options_prep libtool_options_prep
+
+
+# libtool_parse_options [ARG]...
+# ---------------------------------
+# Provide handling for libtool specific options.
+libtool_parse_options ()
+{
+    $debug_cmd
+
+    # Perform our own loop to consume as many options as possible in
+    # each iteration.
+    while test $# -gt 0; do
+      _G_opt=$1
+      shift
+      case $_G_opt in
+        --dry-run|--dryrun|-n)
+                        opt_dry_run=:
+                        ;;
+
+        --config)       func_config ;;
+
+        --dlopen|-dlopen)
+                        opt_dlopen="${opt_dlopen+$opt_dlopen
+}$1"
+                        shift
+                        ;;
+
+        --preserve-dup-deps)
+                        opt_preserve_dup_deps=: ;;
+
+        --features)     func_features ;;
+
+        --finish)       set dummy --mode finish ${1+"$@"}; shift ;;
+
+        --help)         opt_help=: ;;
+
+        --help-all)     opt_help=': help-all' ;;
+
+        --mode)         test $# = 0 && func_missing_arg $_G_opt && break
+                        opt_mode=$1
+                        case $1 in
+                          # Valid mode arguments:
+                          clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+                          # Catch anything else as an error
+                          *) func_error "invalid argument for $_G_opt"
+                             exit_cmd=exit
+                             break
+                             ;;
+                        esac
+                        shift
+                        ;;
+
+        --no-silent|--no-quiet)
+                        opt_quiet=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --no-warnings|--no-warning|--no-warn)
+                        opt_warning=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --no-verbose)
+                        opt_verbose=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --silent|--quiet)
+                        opt_quiet=:
+                        opt_verbose=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --tag)          test $# = 0 && func_missing_arg $_G_opt && break
+                        opt_tag=$1
+                        func_append preserve_args " $_G_opt $1"
+                        func_enable_tag "$1"
+                        shift
+                        ;;
+
+        --verbose|-v)   opt_quiet=false
+                        opt_verbose=:
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+	# An option not handled by this hook function:
+        *)		set dummy "$_G_opt" ${1+"$@"};	shift; break  ;;
+      esac
+    done
+
+
+    # save modified positional parameters for caller
+    func_quote_for_eval ${1+"$@"}
+    libtool_parse_options_result=$func_quote_for_eval_result
+}
+func_add_hook func_parse_options libtool_parse_options
+
+
+
+# libtool_validate_options [ARG]...
+# ---------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+libtool_validate_options ()
+{
+    # save first non-option argument
+    if test 0 -lt $#; then
+      nonopt=$1
+      shift
+    fi
+
+    # preserve --debug
+    test : = "$debug_cmd" || func_append preserve_args " --debug"
+
+    case $host in
+      # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452
+      # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788
+      *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*)
+        # don't eliminate duplications in $postdeps and $predeps
+        opt_duplicate_compiler_generated_deps=:
+        ;;
+      *)
+        opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+        ;;
+    esac
+
+    $opt_help || {
+      # Sanity checks first:
+      func_check_version_match
+
+      test yes != "$build_libtool_libs" \
+        && test yes != "$build_old_libs" \
+        && func_fatal_configuration "not configured to build any kind of library"
+
+      # Darwin sucks
+      eval std_shrext=\"$shrext_cmds\"
+
+      # Only execute mode is allowed to have -dlopen flags.
+      if test -n "$opt_dlopen" && test execute != "$opt_mode"; then
+        func_error "unrecognized option '-dlopen'"
+        $ECHO "$help" 1>&2
+        exit $EXIT_FAILURE
+      fi
+
+      # Change the help message to a mode-specific one.
+      generic_help=$help
+      help="Try '$progname --help --mode=$opt_mode' for more information."
+    }
+
+    # Pass back the unparsed argument list
+    func_quote_for_eval ${1+"$@"}
+    libtool_validate_options_result=$func_quote_for_eval_result
+}
+func_add_hook func_validate_options libtool_validate_options
+
+
+# Process options as early as possible so that --help and --version
+# can return quickly.
+func_options ${1+"$@"}
+eval set dummy "$func_options_result"; shift
+
+
+
+## ----------- ##
+##    Main.    ##
+## ----------- ##
+
+magic='%%%MAGIC variable%%%'
+magic_exe='%%%MAGIC EXE variable%%%'
+
+# Global variables.
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# func_generated_by_libtool
+# True iff stdin has been generated by Libtool. This function is only
+# a basic sanity check; it will hardly flush out determined imposters.
+func_generated_by_libtool_p ()
+{
+  $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_p file
+# True iff FILE is a libtool '.la' library or '.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+    test -f "$1" &&
+      $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool '.la' library or '.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs.  To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway.  Works if 'file' does not exist.
+func_lalib_unsafe_p ()
+{
+    lalib_p=no
+    if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+	for lalib_p_l in 1 2 3 4
+	do
+	    read lalib_p_line
+	    case $lalib_p_line in
+		\#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+	    esac
+	done
+	exec 0<&5 5<&-
+    fi
+    test yes = "$lalib_p"
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+    test -f "$1" &&
+      $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+    func_ltwrapper_exec_suffix=
+    case $1 in
+    *.exe) ;;
+    *) func_ltwrapper_exec_suffix=.exe ;;
+    esac
+    $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+    func_dirname_and_basename "$1" "" "."
+    func_stripname '' '.exe' "$func_basename_result"
+    func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+    func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+    $debug_cmd
+
+    save_ifs=$IFS; IFS='~'
+    for cmd in $1; do
+      IFS=$sp$nl
+      eval cmd=\"$cmd\"
+      IFS=$save_ifs
+      func_show_eval "$cmd" "${2-:}"
+    done
+    IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)!  Also, sourcing
+# 'FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+    $debug_cmd
+
+    case $1 in
+    */* | *\\*)	. "$1" ;;
+    *)		. "./$1" ;;
+    esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot.  Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+  func_resolve_sysroot_result=$1
+  case $func_resolve_sysroot_result in
+  =*)
+    func_stripname '=' '' "$func_resolve_sysroot_result"
+    func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+    ;;
+  esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+  case $lt_sysroot:$1 in
+  ?*:"$lt_sysroot"*)
+    func_stripname "$lt_sysroot" '' "$1"
+    func_replace_sysroot_result='='$func_stripname_result
+    ;;
+  *)
+    # Including no sysroot.
+    func_replace_sysroot_result=$1
+    ;;
+  esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    $debug_cmd
+
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+	func_append_quoted CC_quoted "$arg"
+      done
+      CC_expanded=`func_echo_all $CC`
+      CC_quoted_expanded=`func_echo_all $CC_quoted`
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+	for z in $available_tags; do
+	  if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+	    # Evaluate the configuration.
+	    eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+	    CC_quoted=
+	    for arg in $CC; do
+	      # Double-quote args containing other shell metacharacters.
+	      func_append_quoted CC_quoted "$arg"
+	    done
+	    CC_expanded=`func_echo_all $CC`
+	    CC_quoted_expanded=`func_echo_all $CC_quoted`
+	    case "$@ " in
+	    " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+	    " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+	      # The compiler in the base compile command matches
+	      # the one in the tagged configuration.
+	      # Assume this is the tagged configuration we want.
+	      tagname=$z
+	      break
+	      ;;
+	    esac
+	  fi
+	done
+	# If $tagname still isn't set, then no tagged configuration
+	# was found and let the user know that the "--tag" command
+	# line option must be used.
+	if test -z "$tagname"; then
+	  func_echo "unable to infer tagged configuration"
+	  func_fatal_error "specify a tag with '--tag'"
+#	else
+#	  func_verbose "using $tagname tagged configuration"
+	fi
+	;;
+      esac
+    fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+    write_libobj=$1
+    if test yes = "$build_libtool_libs"; then
+      write_lobj=\'$2\'
+    else
+      write_lobj=none
+    fi
+
+    if test yes = "$build_old_libs"; then
+      write_oldobj=\'$3\'
+    else
+      write_oldobj=none
+    fi
+
+    $opt_dry_run || {
+      cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+      $MV "${write_libobj}T" "$write_libobj"
+    }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+  $debug_cmd
+
+  func_convert_core_file_wine_to_w32_result=$1
+  if test -n "$1"; then
+    # Unfortunately, winepath does not exit with a non-zero error code, so we
+    # are forced to check the contents of stdout. On the other hand, if the
+    # command is not found, the shell will set an exit code of 127 and print
+    # *an error message* to stdout. So we must check for both error code of
+    # zero AND non-empty stdout, which explains the odd construction:
+    func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+    if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then
+      func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+        $SED -e "$sed_naive_backslashify"`
+    else
+      func_convert_core_file_wine_to_w32_result=
+    fi
+  fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+  $debug_cmd
+
+  # unfortunately, winepath doesn't convert paths, only file names
+  func_convert_core_path_wine_to_w32_result=
+  if test -n "$1"; then
+    oldIFS=$IFS
+    IFS=:
+    for func_convert_core_path_wine_to_w32_f in $1; do
+      IFS=$oldIFS
+      func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+      if test -n "$func_convert_core_file_wine_to_w32_result"; then
+        if test -z "$func_convert_core_path_wine_to_w32_result"; then
+          func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result
+        else
+          func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+        fi
+      fi
+    done
+    IFS=$oldIFS
+  fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+  $debug_cmd
+
+  if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+    func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+    if test "$?" -ne 0; then
+      # on failure, ensure result is empty
+      func_cygpath_result=
+    fi
+  else
+    func_cygpath_result=
+    func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'"
+  fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format.  Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+  $debug_cmd
+
+  # awkward: cmd appends spaces to result
+  func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+    $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+  $debug_cmd
+
+  if test -z "$2" && test -n "$1"; then
+    func_error "Could not determine host file name corresponding to"
+    func_error "  '$1'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback:
+    func_to_host_file_result=$1
+  fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+  $debug_cmd
+
+  if test -z "$4" && test -n "$3"; then
+    func_error "Could not determine the host path corresponding to"
+    func_error "  '$3'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback.  This is a deliberately simplistic "conversion" and
+    # should not be "improved".  See libtool.info.
+    if test "x$1" != "x$2"; then
+      lt_replace_pathsep_chars="s|$1|$2|g"
+      func_to_host_path_result=`echo "$3" |
+        $SED -e "$lt_replace_pathsep_chars"`
+    else
+      func_to_host_path_result=$3
+    fi
+  fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+  $debug_cmd
+
+  case $4 in
+  $1 ) func_to_host_path_result=$3$func_to_host_path_result
+    ;;
+  esac
+  case $4 in
+  $2 ) func_append func_to_host_path_result "$3"
+    ;;
+  esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via '$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+  $debug_cmd
+
+  $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result.  If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+  $debug_cmd
+
+  case ,$2, in
+    *,"$to_tool_file_cmd",*)
+      func_to_tool_file_result=$1
+      ;;
+    *)
+      $to_tool_file_cmd "$1"
+      func_to_tool_file_result=$func_to_host_file_result
+      ;;
+  esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+  func_to_host_file_result=$1
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_to_host_file_result=$func_convert_core_msys_to_w32_result
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+    # LT_CYGPATH in this case.
+    func_to_host_file_result=`cygpath -m "$1"`
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format.  Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    func_convert_core_file_wine_to_w32 "$1"
+    func_to_host_file_result=$func_convert_core_file_wine_to_w32_result
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_msys_to_w32_result"
+    func_to_host_file_result=$func_cygpath_result
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format.  Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set.  Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+    func_convert_core_file_wine_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+    func_to_host_file_result=$func_cygpath_result
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via '$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format.  If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+#   file name conversion function    : func_convert_file_X_to_Y ()
+#   path conversion function         : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same.  If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+  $debug_cmd
+
+  if test -z "$to_host_path_cmd"; then
+    func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+    to_host_path_cmd=func_convert_path_$func_stripname_result
+  fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+  $debug_cmd
+
+  func_init_to_host_path_cmd
+  $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+  func_to_host_path_result=$1
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from ARG.  MSYS
+    # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+    # and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result=$func_convert_core_msys_to_w32_result
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format.  Requires a wine environment and
+# a working winepath.  Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result=$func_convert_core_path_wine_to_w32_result
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+    func_to_host_path_result=$func_cygpath_result
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format.  Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set.  Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+    func_to_host_path_result=$func_cygpath_result
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_dll_def_p FILE
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with _LT_DLL_DEF_P in libtool.m4
+func_dll_def_p ()
+{
+  $debug_cmd
+
+  func_dll_def_p_tmp=`$SED -n \
+    -e 's/^[	 ]*//' \
+    -e '/^\(;.*\)*$/d' \
+    -e 's/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p' \
+    -e q \
+    "$1"`
+  test DEF = "$func_dll_def_p_tmp"
+}
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+    $debug_cmd
+
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile=$nonopt  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+    pie_flag=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+	# do not "continue".  Instead, add this to base_compile
+	lastarg=$arg
+	arg_mode=normal
+	;;
+
+      target )
+	libobj=$arg
+	arg_mode=normal
+	continue
+	;;
+
+      normal )
+	# Accept any command-line options.
+	case $arg in
+	-o)
+	  test -n "$libobj" && \
+	    func_fatal_error "you cannot specify '-o' more than once"
+	  arg_mode=target
+	  continue
+	  ;;
+
+	-pie | -fpie | -fPIE)
+          func_append pie_flag " $arg"
+	  continue
+	  ;;
+
+	-shared | -static | -prefer-pic | -prefer-non-pic)
+	  func_append later " $arg"
+	  continue
+	  ;;
+
+	-no-suppress)
+	  suppress_opt=no
+	  continue
+	  ;;
+
+	-Xcompiler)
+	  arg_mode=arg  #  the next one goes into the "base_compile" arg list
+	  continue      #  The current "srcfile" will either be retained or
+	  ;;            #  replaced later.  I would guess that would be a bug.
+
+	-Wc,*)
+	  func_stripname '-Wc,' '' "$arg"
+	  args=$func_stripname_result
+	  lastarg=
+	  save_ifs=$IFS; IFS=,
+	  for arg in $args; do
+	    IFS=$save_ifs
+	    func_append_quoted lastarg "$arg"
+	  done
+	  IFS=$save_ifs
+	  func_stripname ' ' '' "$lastarg"
+	  lastarg=$func_stripname_result
+
+	  # Add the arguments to base_compile.
+	  func_append base_compile " $lastarg"
+	  continue
+	  ;;
+
+	*)
+	  # Accept the current argument as the source file.
+	  # The previous "srcfile" becomes the current argument.
+	  #
+	  lastarg=$srcfile
+	  srcfile=$arg
+	  ;;
+	esac  #  case $arg
+	;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      func_append_quoted base_compile "$lastarg"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      func_fatal_error "you must specify an argument for -Xcompile"
+      ;;
+    target)
+      func_fatal_error "you must specify a target with '-o'"
+      ;;
+    *)
+      # Get the name of the library object.
+      test -z "$libobj" && {
+	func_basename "$srcfile"
+	libobj=$func_basename_result
+      }
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    case $libobj in
+    *.[cCFSifmso] | \
+    *.ada | *.adb | *.ads | *.asm | \
+    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+    *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+      func_xform "$libobj"
+      libobj=$func_xform_result
+      ;;
+    esac
+
+    case $libobj in
+    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+    *)
+      func_fatal_error "cannot determine name of library object from '$libobj'"
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -shared)
+	test yes = "$build_libtool_libs" \
+	  || func_fatal_configuration "cannot build a shared library"
+	build_old_libs=no
+	continue
+	;;
+
+      -static)
+	build_libtool_libs=no
+	build_old_libs=yes
+	continue
+	;;
+
+      -prefer-pic)
+	pic_mode=yes
+	continue
+	;;
+
+      -prefer-non-pic)
+	pic_mode=no
+	continue
+	;;
+      esac
+    done
+
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
+      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'	 &()|`$[]' \
+      && func_warning "libobj name '$libobj' may not contain shell special characters."
+    func_dirname_and_basename "$obj" "/" ""
+    objname=$func_basename_result
+    xdir=$func_dirname_result
+    lobj=$xdir$objdir/$objname
+
+    test -z "$base_compile" && \
+      func_fatal_help "you must specify a compilation command"
+
+    # Delete any leftover library objects.
+    if test yes = "$build_old_libs"; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2* | cegcc*)
+      pic_mode=default
+      ;;
+    esac
+    if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test no = "$compiler_c_o"; then
+      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext
+      lockfile=$output_obj.lock
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test yes = "$need_locks"; then
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    elif test warn = "$need_locks"; then
+      if test -f "$lockfile"; then
+	$ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+      func_append removelist " $output_obj"
+      $ECHO "$srcfile" > "$lockfile"
+    fi
+
+    $opt_dry_run || $RM $removelist
+    func_append removelist " $lockfile"
+    trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+    func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+    srcfile=$func_to_tool_file_result
+    func_quote_for_eval "$srcfile"
+    qsrcfile=$func_quote_for_eval_result
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test yes = "$build_libtool_libs"; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test no != "$pic_mode"; then
+	command="$base_compile $qsrcfile $pic_flag"
+      else
+	# Don't build PIC code
+	command="$base_compile $qsrcfile"
+      fi
+
+      func_mkdir_p "$xdir$objdir"
+
+      if test -z "$output_obj"; then
+	# Place PIC objects in $objdir
+	func_append command " -o $lobj"
+      fi
+
+      func_show_eval_locale "$command"	\
+          'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+      if test warn = "$need_locks" &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+	func_show_eval '$MV "$output_obj" "$lobj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+
+      # Allow error messages only from the first compilation.
+      if test yes = "$suppress_opt"; then
+	suppress_output=' >/dev/null 2>&1'
+      fi
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test yes = "$build_old_libs"; then
+      if test yes != "$pic_mode"; then
+	# Don't build PIC code
+	command="$base_compile $qsrcfile$pie_flag"
+      else
+	command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test yes = "$compiler_c_o"; then
+	func_append command " -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      func_append command "$suppress_output"
+      func_show_eval_locale "$command" \
+        '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+      if test warn = "$need_locks" &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+	func_show_eval '$MV "$output_obj" "$obj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+    fi
+
+    $opt_dry_run || {
+      func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+      # Unlock the critical section if it was locked
+      if test no != "$need_locks"; then
+	removelist=$lockfile
+        $RM "$lockfile"
+      fi
+    }
+
+    exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+  test compile = "$opt_mode" && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+    # We need to display help for each of the modes.
+    case $opt_mode in
+      "")
+        # Generic help is extracted from the usage comments
+        # at the start of this file.
+        func_help
+        ;;
+
+      clean)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically '/bin/rm').  RM-OPTIONS are options (such as '-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      compile)
+      $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -no-suppress      do not suppress compiler output for multiple passes
+  -prefer-pic       try to build PIC objects only
+  -prefer-non-pic   try to build non-PIC objects only
+  -shared           do not build a '.o' file suitable for static linking
+  -static           only build a '.o' file suitable for static linking
+  -Wc,FLAG          pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a 'standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix '.c' with the
+library object suffix, '.lo'."
+        ;;
+
+      execute)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to '-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+        ;;
+
+      finish)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the '--dry-run' option if you just want to see what would be executed."
+        ;;
+
+      install)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the 'install' or 'cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+  -inst-prefix-dir PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+        ;;
+
+      link)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -bindir BINDIR    specify path to binaries directory (for systems where
+                    libraries must be found in the PATH setting at runtime)
+  -dlopen FILE      '-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  use a list of object files found in FILE to specify objects
+  -os2dllname NAME  force a short DLL name on OS/2 (no effect on other OSes)
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -shared           only do dynamic linking of libtool libraries
+  -shrext SUFFIX    override the standard shared library file extension
+  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-libtool-libs
+                    do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+  -weak LIBNAME     declare that the target provides the LIBNAME interface
+  -Wc,FLAG
+  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
+  -Wl,FLAG
+  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
+  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with '-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in '.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in '.la', then a libtool library is created,
+only library objects ('.lo' files) may be specified, and '-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created
+using 'ar' and 'ranlib', or on Windows using 'lib'.
+
+If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file
+is created, otherwise an executable program is created."
+        ;;
+
+      uninstall)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically '/bin/rm').  RM-OPTIONS are options (such as '-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      *)
+        func_fatal_help "invalid operation mode '$opt_mode'"
+        ;;
+    esac
+
+    echo
+    $ECHO "Try '$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+  if test : = "$opt_help"; then
+    func_mode_help
+  else
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	func_mode_help
+      done
+    } | $SED -n '1p; 2,$s/^Usage:/  or: /p'
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	echo
+	func_mode_help
+      done
+    } |
+    $SED '1d
+      /^When reporting/,/^Report/{
+	H
+	d
+      }
+      $x
+      /information about other modes/d
+      /more detailed .*MODE/d
+      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+  fi
+  exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+    $debug_cmd
+
+    # The first argument is the command name.
+    cmd=$nonopt
+    test -z "$cmd" && \
+      func_fatal_help "you must specify a COMMAND"
+
+    # Handle -dlopen flags immediately.
+    for file in $opt_dlopen; do
+      test -f "$file" \
+	|| func_fatal_help "'$file' is not a file"
+
+      dir=
+      case $file in
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "'$lib' is not a valid libtool archive"
+
+	# Read the libtool library.
+	dlname=
+	library_names=
+	func_source "$file"
+
+	# Skip this library if it cannot be dlopened.
+	if test -z "$dlname"; then
+	  # Warn if it was a shared library.
+	  test -n "$library_names" && \
+	    func_warning "'$file' was not linked with '-export-dynamic'"
+	  continue
+	fi
+
+	func_dirname "$file" "" "."
+	dir=$func_dirname_result
+
+	if test -f "$dir/$objdir/$dlname"; then
+	  func_append dir "/$objdir"
+	else
+	  if test ! -f "$dir/$dlname"; then
+	    func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'"
+	  fi
+	fi
+	;;
+
+      *.lo)
+	# Just add the directory containing the .lo file.
+	func_dirname "$file" "" "."
+	dir=$func_dirname_result
+	;;
+
+      *)
+	func_warning "'-dlopen' is ignored for non-libtool libraries and objects"
+	continue
+	;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir=$absdir
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+	eval "$shlibpath_var=\"\$dir\""
+      else
+	eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic=$magic
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -* | *.la | *.lo ) ;;
+      *)
+	# Do a test to see if this is really a libtool program.
+	if func_ltwrapper_script_p "$file"; then
+	  func_source "$file"
+	  # Transform arg to wrapped name.
+	  file=$progdir/$program
+	elif func_ltwrapper_executable_p "$file"; then
+	  func_ltwrapper_scriptname "$file"
+	  func_source "$func_ltwrapper_scriptname_result"
+	  # Transform arg to wrapped name.
+	  file=$progdir/$program
+	fi
+	;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      func_append_quoted args "$file"
+    done
+
+    if $opt_dry_run; then
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+	eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+	echo "export $shlibpath_var"
+      fi
+      $ECHO "$cmd$args"
+      exit $EXIT_SUCCESS
+    else
+      if test -n "$shlibpath_var"; then
+	# Export the shlibpath_var.
+	eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+      do
+	eval "if test \"\${save_$lt_var+set}\" = set; then
+                $lt_var=\$save_$lt_var; export $lt_var
+	      else
+		$lt_unset $lt_var
+	      fi"
+      done
+
+      # Now prepare to actually exec the command.
+      exec_cmd=\$cmd$args
+    fi
+}
+
+test execute = "$opt_mode" && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+    $debug_cmd
+
+    libs=
+    libdirs=
+    admincmds=
+
+    for opt in "$nonopt" ${1+"$@"}
+    do
+      if test -d "$opt"; then
+	func_append libdirs " $opt"
+
+      elif test -f "$opt"; then
+	if func_lalib_unsafe_p "$opt"; then
+	  func_append libs " $opt"
+	else
+	  func_warning "'$opt' is not a valid libtool archive"
+	fi
+
+      else
+	func_fatal_error "invalid argument '$opt'"
+      fi
+    done
+
+    if test -n "$libs"; then
+      if test -n "$lt_sysroot"; then
+        sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+        sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+      else
+        sysroot_cmd=
+      fi
+
+      # Remove sysroot references
+      if $opt_dry_run; then
+        for lib in $libs; do
+          echo "removing references to $lt_sysroot and '=' prefixes from $lib"
+        done
+      else
+        tmpdir=`func_mktempdir`
+        for lib in $libs; do
+	  $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+	    > $tmpdir/tmp-la
+	  mv -f $tmpdir/tmp-la $lib
+	done
+        ${RM}r "$tmpdir"
+      fi
+    fi
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for libdir in $libdirs; do
+	if test -n "$finish_cmds"; then
+	  # Do each command in the finish commands.
+	  func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+	fi
+	if test -n "$finish_eval"; then
+	  # Do the single finish_eval.
+	  eval cmds=\"$finish_eval\"
+	  $opt_dry_run || eval "$cmds" || func_append admincmds "
+       $cmds"
+	fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    $opt_quiet && exit $EXIT_SUCCESS
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      echo "----------------------------------------------------------------------"
+      echo "Libraries have been installed in:"
+      for libdir in $libdirs; do
+	$ECHO "   $libdir"
+      done
+      echo
+      echo "If you ever happen to want to link against installed libraries"
+      echo "in a given directory, LIBDIR, you must either use libtool, and"
+      echo "specify the full pathname of the library, or use the '-LLIBDIR'"
+      echo "flag during linking and do at least one of the following:"
+      if test -n "$shlibpath_var"; then
+	echo "   - add LIBDIR to the '$shlibpath_var' environment variable"
+	echo "     during execution"
+      fi
+      if test -n "$runpath_var"; then
+	echo "   - add LIBDIR to the '$runpath_var' environment variable"
+	echo "     during linking"
+      fi
+      if test -n "$hardcode_libdir_flag_spec"; then
+	libdir=LIBDIR
+	eval flag=\"$hardcode_libdir_flag_spec\"
+
+	$ECHO "   - use the '$flag' linker flag"
+      fi
+      if test -n "$admincmds"; then
+	$ECHO "   - have your system administrator run these commands:$admincmds"
+      fi
+      if test -f /etc/ld.so.conf; then
+	echo "   - have your system administrator add LIBDIR to '/etc/ld.so.conf'"
+      fi
+      echo
+
+      echo "See any operating system documentation about shared libraries for"
+      case $host in
+	solaris2.[6789]|solaris2.1[0-9])
+	  echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+	  echo "pages."
+	  ;;
+	*)
+	  echo "more information, such as the ld(1) and ld.so(8) manual pages."
+	  ;;
+      esac
+      echo "----------------------------------------------------------------------"
+    fi
+    exit $EXIT_SUCCESS
+}
+
+test finish = "$opt_mode" && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+    $debug_cmd
+
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" ||
+       # Allow the use of GNU shtool's install command.
+       case $nonopt in *shtool*) :;; *) false;; esac
+    then
+      # Aesthetically quote it.
+      func_quote_for_eval "$nonopt"
+      install_prog="$func_quote_for_eval_result "
+      arg=$1
+      shift
+    else
+      install_prog=
+      arg=$nonopt
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    func_quote_for_eval "$arg"
+    func_append install_prog "$func_quote_for_eval_result"
+    install_shared_prog=$install_prog
+    case " $install_prog " in
+      *[\\\ /]cp\ *) install_cp=: ;;
+      *) install_cp=false ;;
+    esac
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=false
+    stripme=
+    no_mode=:
+    for arg
+    do
+      arg2=
+      if test -n "$dest"; then
+	func_append files " $dest"
+	dest=$arg
+	continue
+      fi
+
+      case $arg in
+      -d) isdir=: ;;
+      -f)
+	if $install_cp; then :; else
+	  prev=$arg
+	fi
+	;;
+      -g | -m | -o)
+	prev=$arg
+	;;
+      -s)
+	stripme=" -s"
+	continue
+	;;
+      -*)
+	;;
+      *)
+	# If the previous option needed an argument, then skip it.
+	if test -n "$prev"; then
+	  if test X-m = "X$prev" && test -n "$install_override_mode"; then
+	    arg2=$install_override_mode
+	    no_mode=false
+	  fi
+	  prev=
+	else
+	  dest=$arg
+	  continue
+	fi
+	;;
+      esac
+
+      # Aesthetically quote the argument.
+      func_quote_for_eval "$arg"
+      func_append install_prog " $func_quote_for_eval_result"
+      if test -n "$arg2"; then
+	func_quote_for_eval "$arg2"
+      fi
+      func_append install_shared_prog " $func_quote_for_eval_result"
+    done
+
+    test -z "$install_prog" && \
+      func_fatal_help "you must specify an install program"
+
+    test -n "$prev" && \
+      func_fatal_help "the '$prev' option requires an argument"
+
+    if test -n "$install_override_mode" && $no_mode; then
+      if $install_cp; then :; else
+	func_quote_for_eval "$install_override_mode"
+	func_append install_shared_prog " -m $func_quote_for_eval_result"
+      fi
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+	func_fatal_help "no file or destination specified"
+      else
+	func_fatal_help "you must specify a destination"
+      fi
+    fi
+
+    # Strip any trailing slash from the destination.
+    func_stripname '' '/' "$dest"
+    dest=$func_stripname_result
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=:
+    if $isdir; then
+      destdir=$dest
+      destname=
+    else
+      func_dirname_and_basename "$dest" "" "."
+      destdir=$func_dirname_result
+      destname=$func_basename_result
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files; shift
+      test "$#" -gt 1 && \
+	func_fatal_help "'$dest' is not a directory"
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+	case $file in
+	*.lo) ;;
+	*)
+	  func_fatal_help "'$destdir' must be an absolute directory name"
+	  ;;
+	esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic=$magic
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+	# Do the static libraries later.
+	func_append staticlibs " $file"
+	;;
+
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "'$file' is not a valid libtool archive"
+
+	library_names=
+	old_library=
+	relink_command=
+	func_source "$file"
+
+	# Add the libdir to current_libdirs if it is the destination.
+	if test "X$destdir" = "X$libdir"; then
+	  case "$current_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append current_libdirs " $libdir" ;;
+	  esac
+	else
+	  # Note the libdir as a future libdir.
+	  case "$future_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append future_libdirs " $libdir" ;;
+	  esac
+	fi
+
+	func_dirname "$file" "/" ""
+	dir=$func_dirname_result
+	func_append dir "$objdir"
+
+	if test -n "$relink_command"; then
+	  # Determine the prefix the user has applied to our future dir.
+	  inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+	  # Don't allow the user to place us outside of our expected
+	  # location b/c this prevents finding dependent libraries that
+	  # are installed to the same prefix.
+	  # At present, this check doesn't affect windows .dll's that
+	  # are installed into $libdir/../bin (currently, that works fine)
+	  # but it's something to keep an eye on.
+	  test "$inst_prefix_dir" = "$destdir" && \
+	    func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir"
+
+	  if test -n "$inst_prefix_dir"; then
+	    # Stick the inst_prefix_dir data into the link command.
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+	  else
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+	  fi
+
+	  func_warning "relinking '$file'"
+	  func_show_eval "$relink_command" \
+	    'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"'
+	fi
+
+	# See the names of the shared library.
+	set dummy $library_names; shift
+	if test -n "$1"; then
+	  realname=$1
+	  shift
+
+	  srcname=$realname
+	  test -n "$relink_command" && srcname=${realname}T
+
+	  # Install the shared library and build the symlinks.
+	  func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+	      'exit $?'
+	  tstripme=$stripme
+	  case $host_os in
+	  cygwin* | mingw* | pw32* | cegcc*)
+	    case $realname in
+	    *.dll.a)
+	      tstripme=
+	      ;;
+	    esac
+	    ;;
+	  os2*)
+	    case $realname in
+	    *_dll.a)
+	      tstripme=
+	      ;;
+	    esac
+	    ;;
+	  esac
+	  if test -n "$tstripme" && test -n "$striplib"; then
+	    func_show_eval "$striplib $destdir/$realname" 'exit $?'
+	  fi
+
+	  if test "$#" -gt 0; then
+	    # Delete the old symlinks, and create new ones.
+	    # Try 'ln -sf' first, because the 'ln' binary might depend on
+	    # the symlink we replace!  Solaris /bin/ln does not understand -f,
+	    # so we also need to try rm && ln -s.
+	    for linkname
+	    do
+	      test "$linkname" != "$realname" \
+		&& func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+	    done
+	  fi
+
+	  # Do each command in the postinstall commands.
+	  lib=$destdir/$realname
+	  func_execute_cmds "$postinstall_cmds" 'exit $?'
+	fi
+
+	# Install the pseudo-library for information purposes.
+	func_basename "$file"
+	name=$func_basename_result
+	instname=$dir/${name}i
+	func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+	# Maybe install the static library, too.
+	test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+	;;
+
+      *.lo)
+	# Install (i.e. copy) a libtool object.
+
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile=$destdir/$destname
+	else
+	  func_basename "$file"
+	  destfile=$func_basename_result
+	  destfile=$destdir/$destfile
+	fi
+
+	# Deduce the name of the destination old-style object file.
+	case $destfile in
+	*.lo)
+	  func_lo2o "$destfile"
+	  staticdest=$func_lo2o_result
+	  ;;
+	*.$objext)
+	  staticdest=$destfile
+	  destfile=
+	  ;;
+	*)
+	  func_fatal_help "cannot copy a libtool object to '$destfile'"
+	  ;;
+	esac
+
+	# Install the libtool object if requested.
+	test -n "$destfile" && \
+	  func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+	# Install the old object if enabled.
+	if test yes = "$build_old_libs"; then
+	  # Deduce the name of the old-style object file.
+	  func_lo2o "$file"
+	  staticobj=$func_lo2o_result
+	  func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+	fi
+	exit $EXIT_SUCCESS
+	;;
+
+      *)
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile=$destdir/$destname
+	else
+	  func_basename "$file"
+	  destfile=$func_basename_result
+	  destfile=$destdir/$destfile
+	fi
+
+	# If the file is missing, and there is a .exe on the end, strip it
+	# because it is most likely a libtool script we actually want to
+	# install
+	stripped_ext=
+	case $file in
+	  *.exe)
+	    if test ! -f "$file"; then
+	      func_stripname '' '.exe' "$file"
+	      file=$func_stripname_result
+	      stripped_ext=.exe
+	    fi
+	    ;;
+	esac
+
+	# Do a test to see if this is really a libtool program.
+	case $host in
+	*cygwin* | *mingw*)
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      wrapper=$func_ltwrapper_scriptname_result
+	    else
+	      func_stripname '' '.exe' "$file"
+	      wrapper=$func_stripname_result
+	    fi
+	    ;;
+	*)
+	    wrapper=$file
+	    ;;
+	esac
+	if func_ltwrapper_script_p "$wrapper"; then
+	  notinst_deplibs=
+	  relink_command=
+
+	  func_source "$wrapper"
+
+	  # Check the variables that should have been set.
+	  test -z "$generated_by_libtool_version" && \
+	    func_fatal_error "invalid libtool wrapper script '$wrapper'"
+
+	  finalize=:
+	  for lib in $notinst_deplibs; do
+	    # Check to see that each library is installed.
+	    libdir=
+	    if test -f "$lib"; then
+	      func_source "$lib"
+	    fi
+	    libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'`
+	    if test -n "$libdir" && test ! -f "$libfile"; then
+	      func_warning "'$lib' has not been installed in '$libdir'"
+	      finalize=false
+	    fi
+	  done
+
+	  relink_command=
+	  func_source "$wrapper"
+
+	  outputname=
+	  if test no = "$fast_install" && test -n "$relink_command"; then
+	    $opt_dry_run || {
+	      if $finalize; then
+	        tmpdir=`func_mktempdir`
+		func_basename "$file$stripped_ext"
+		file=$func_basename_result
+	        outputname=$tmpdir/$file
+	        # Replace the output file specification.
+	        relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+	        $opt_quiet || {
+	          func_quote_for_expand "$relink_command"
+		  eval "func_echo $func_quote_for_expand_result"
+	        }
+	        if eval "$relink_command"; then :
+	          else
+		  func_error "error: relink '$file' with the above command before installing it"
+		  $opt_dry_run || ${RM}r "$tmpdir"
+		  continue
+	        fi
+	        file=$outputname
+	      else
+	        func_warning "cannot relink '$file'"
+	      fi
+	    }
+	  else
+	    # Install the binary that we compiled earlier.
+	    file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+	  fi
+	fi
+
+	# remove .exe since cygwin /usr/bin/install will append another
+	# one anyway
+	case $install_prog,$host in
+	*/usr/bin/install*,*cygwin*)
+	  case $file:$destfile in
+	  *.exe:*.exe)
+	    # this is ok
+	    ;;
+	  *.exe:*)
+	    destfile=$destfile.exe
+	    ;;
+	  *:*.exe)
+	    func_stripname '' '.exe' "$destfile"
+	    destfile=$func_stripname_result
+	    ;;
+	  esac
+	  ;;
+	esac
+	func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+	$opt_dry_run || if test -n "$outputname"; then
+	  ${RM}r "$tmpdir"
+	fi
+	;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      func_basename "$file"
+      name=$func_basename_result
+
+      # Set up the ranlib parameters.
+      oldlib=$destdir/$name
+      func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+      tool_oldlib=$func_to_tool_file_result
+
+      func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+	func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+      fi
+
+      # Do each command in the postinstall commands.
+      func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+    done
+
+    test -n "$future_libdirs" && \
+      func_warning "remember to run '$progname --finish$future_libdirs'"
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      $opt_dry_run && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test install = "$opt_mode" && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+    $debug_cmd
+
+    my_outputname=$1
+    my_originator=$2
+    my_pic_p=${3-false}
+    my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'`
+    my_dlsyms=
+
+    if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+      if test -n "$NM" && test -n "$global_symbol_pipe"; then
+	my_dlsyms=${my_outputname}S.c
+      else
+	func_error "not configured to extract global symbols from dlpreopened files"
+      fi
+    fi
+
+    if test -n "$my_dlsyms"; then
+      case $my_dlsyms in
+      "") ;;
+      *.c)
+	# Discover the nlist of each of the dlfiles.
+	nlist=$output_objdir/$my_outputname.nm
+
+	func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+	# Parse the name list into a source file.
+	func_verbose "creating $output_objdir/$my_dlsyms"
+
+	$opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
+/* External symbol declarations for the compiler. */\
+"
+
+	if test yes = "$dlself"; then
+	  func_verbose "generating symbol list for '$output'"
+
+	  $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+	  # Add our own program objects to the symbol list.
+	  progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	  for progfile in $progfiles; do
+	    func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+	    func_verbose "extracting global C symbols from '$func_to_tool_file_result'"
+	    $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+	  done
+
+	  if test -n "$exclude_expsyms"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  if test -n "$export_symbols_regex"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  # Prepare the list of exported symbols
+	  if test -z "$export_symbols"; then
+	    export_symbols=$output_objdir/$outputname.exp
+	    $opt_dry_run || {
+	      $RM $export_symbols
+	      eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+	      case $host in
+	      *cygwin* | *mingw* | *cegcc* )
+                eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+	        ;;
+	      esac
+	    }
+	  else
+	    $opt_dry_run || {
+	      eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+	      eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	      case $host in
+	        *cygwin* | *mingw* | *cegcc* )
+	          eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+	          eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+	          ;;
+	      esac
+	    }
+	  fi
+	fi
+
+	for dlprefile in $dlprefiles; do
+	  func_verbose "extracting global C symbols from '$dlprefile'"
+	  func_basename "$dlprefile"
+	  name=$func_basename_result
+          case $host in
+	    *cygwin* | *mingw* | *cegcc* )
+	      # if an import library, we need to obtain dlname
+	      if func_win32_import_lib_p "$dlprefile"; then
+	        func_tr_sh "$dlprefile"
+	        eval "curr_lafile=\$libfile_$func_tr_sh_result"
+	        dlprefile_dlbasename=
+	        if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+	          # Use subshell, to avoid clobbering current variable values
+	          dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+	          if test -n "$dlprefile_dlname"; then
+	            func_basename "$dlprefile_dlname"
+	            dlprefile_dlbasename=$func_basename_result
+	          else
+	            # no lafile. user explicitly requested -dlpreopen <import library>.
+	            $sharedlib_from_linklib_cmd "$dlprefile"
+	            dlprefile_dlbasename=$sharedlib_from_linklib_result
+	          fi
+	        fi
+	        $opt_dry_run || {
+	          if test -n "$dlprefile_dlbasename"; then
+	            eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+	          else
+	            func_warning "Could not compute DLL name from $name"
+	            eval '$ECHO ": $name " >> "$nlist"'
+	          fi
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+	            $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+	        }
+	      else # not an import lib
+	        $opt_dry_run || {
+	          eval '$ECHO ": $name " >> "$nlist"'
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	        }
+	      fi
+	    ;;
+	    *)
+	      $opt_dry_run || {
+	        eval '$ECHO ": $name " >> "$nlist"'
+	        func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	        eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	      }
+	    ;;
+          esac
+	done
+
+	$opt_dry_run || {
+	  # Make sure we have at least an empty file.
+	  test -f "$nlist" || : > "$nlist"
+
+	  if test -n "$exclude_expsyms"; then
+	    $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+	    $MV "$nlist"T "$nlist"
+	  fi
+
+	  # Try sorting and uniquifying the output.
+	  if $GREP -v "^: " < "$nlist" |
+	      if sort -k 3 </dev/null >/dev/null 2>&1; then
+		sort -k 3
+	      else
+		sort +2
+	      fi |
+	      uniq > "$nlist"S; then
+	    :
+	  else
+	    $GREP -v "^: " < "$nlist" > "$nlist"S
+	  fi
+
+	  if test -f "$nlist"S; then
+	    eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+	  else
+	    echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+	  fi
+
+	  func_show_eval '$RM "${nlist}I"'
+	  if test -n "$global_symbol_to_import"; then
+	    eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I'
+	  fi
+
+	  echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols.  */
+typedef struct {
+  const char *name;
+  void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];\
+"
+
+	  if test -s "$nlist"I; then
+	    echo >> "$output_objdir/$my_dlsyms" "\
+static void lt_syminit(void)
+{
+  LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols;
+  for (; symbol->name; ++symbol)
+    {"
+	    $SED 's/.*/      if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms"
+	    echo >> "$output_objdir/$my_dlsyms" "\
+    }
+}"
+	  fi
+	  echo >> "$output_objdir/$my_dlsyms" "\
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{ {\"$my_originator\", (void *) 0},"
+
+	  if test -s "$nlist"I; then
+	    echo >> "$output_objdir/$my_dlsyms" "\
+  {\"@INIT@\", (void *) &lt_syminit},"
+	  fi
+
+	  case $need_lib_prefix in
+	  no)
+	    eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  *)
+	    eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  esac
+	  echo >> "$output_objdir/$my_dlsyms" "\
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+	} # !$opt_dry_run
+
+	pic_flag_for_symtable=
+	case "$compile_command " in
+	*" -static "*) ;;
+	*)
+	  case $host in
+	  # compiling the symbol table file with pic_flag works around
+	  # a FreeBSD bug that causes programs to crash when -lm is
+	  # linked before any other PIC object.  But we must not use
+	  # pic_flag when linking with -static.  The problem exists in
+	  # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+	  *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+	    pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+	  *-*-hpux*)
+	    pic_flag_for_symtable=" $pic_flag"  ;;
+	  *)
+	    $my_pic_p && pic_flag_for_symtable=" $pic_flag"
+	    ;;
+	  esac
+	  ;;
+	esac
+	symtab_cflags=
+	for arg in $LTCFLAGS; do
+	  case $arg in
+	  -pie | -fpie | -fPIE) ;;
+	  *) func_append symtab_cflags " $arg" ;;
+	  esac
+	done
+
+	# Now compile the dynamic symbol file.
+	func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+	# Clean up the generated files.
+	func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"'
+
+	# Transform the symbol file into the correct name.
+	symfileobj=$output_objdir/${my_outputname}S.$objext
+	case $host in
+	*cygwin* | *mingw* | *cegcc* )
+	  if test -f "$output_objdir/$my_outputname.def"; then
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	  else
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  fi
+	  ;;
+	*)
+	  compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  ;;
+	esac
+	;;
+      *)
+	func_fatal_error "unknown suffix for '$my_dlsyms'"
+	;;
+      esac
+    else
+      # We keep going just in case the user didn't refer to
+      # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+      # really was required.
+
+      # Nullify the symbol file.
+      compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+    fi
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+  $debug_cmd
+
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+  test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+  $debug_cmd
+
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+  test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+  $debug_cmd
+
+  win32_libid_type=unknown
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+      case $nm_interface in
+      "MS dumpbin")
+	if func_cygming_ms_implib_p "$1" ||
+	   func_cygming_gnu_implib_p "$1"
+	then
+	  win32_nmres=import
+	else
+	  win32_nmres=
+	fi
+	;;
+      *)
+	func_to_tool_file "$1" func_convert_file_msys_to_w32
+	win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+	  $SED -n -e '
+	    1,100{
+		/ I /{
+		    s|.*|import|
+		    p
+		    q
+		}
+	    }'`
+	;;
+      esac
+      case $win32_nmres in
+      import*)  win32_libid_type="x86 archive import";;
+      *)        win32_libid_type="x86 archive static";;
+      esac
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+  $debug_cmd
+
+  sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+  $debug_cmd
+
+  match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+  $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+    $SED '/^Contents of section '"$match_literal"':/{
+      # Place marker at beginning of archive member dllname section
+      s/.*/====MARK====/
+      p
+      d
+    }
+    # These lines can sometimes be longer than 43 characters, but
+    # are always uninteresting
+    /:[	 ]*file format pe[i]\{,1\}-/d
+    /^In archive [^:]*:/d
+    # Ensure marker is printed
+    /^====MARK====/p
+    # Remove all lines with less than 43 characters
+    /^.\{43\}/!d
+    # From remaining lines, remove first 43 characters
+    s/^.\{43\}//' |
+    $SED -n '
+      # Join marker and all lines until next marker into a single line
+      /^====MARK====/ b para
+      H
+      $ b para
+      b
+      :para
+      x
+      s/\n//g
+      # Remove the marker
+      s/^====MARK====//
+      # Remove trailing dots and whitespace
+      s/[\. \t]*$//
+      # Print
+      /./p' |
+    # we now have a list, one entry per line, of the stringified
+    # contents of the appropriate section of all members of the
+    # archive that possess that section. Heuristic: eliminate
+    # all those that have a first or second character that is
+    # a '.' (that is, objdump's representation of an unprintable
+    # character.) This should work for all archives with less than
+    # 0x302f exports -- but will fail for DLLs whose name actually
+    # begins with a literal '.' or a single character followed by
+    # a '.'.
+    #
+    # Of those that remain, print the first one.
+    $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+  $debug_cmd
+
+  if func_cygming_gnu_implib_p "$1"; then
+    # binutils import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+  elif func_cygming_ms_implib_p "$1"; then
+    # ms-generated import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+  else
+    # unknown
+    sharedlib_from_linklib_result=
+  fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    $debug_cmd
+
+    f_ex_an_ar_dir=$1; shift
+    f_ex_an_ar_oldlib=$1
+    if test yes = "$lock_old_archive_extraction"; then
+      lockfile=$f_ex_an_ar_oldlib.lock
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    fi
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+		   'stat=$?; rm -f "$lockfile"; exit $stat'
+    if test yes = "$lock_old_archive_extraction"; then
+      $opt_dry_run || rm -f "$lockfile"
+    fi
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+    fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    $debug_cmd
+
+    my_gentop=$1; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=
+    my_xlib=
+    my_xabs=
+    my_xdir=
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+	[\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;;
+	*) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      func_basename "$my_xlib"
+      my_xlib=$func_basename_result
+      my_xlib_u=$my_xlib
+      while :; do
+        case " $extracted_archives " in
+	*" $my_xlib_u "*)
+	  func_arith $extracted_serial + 1
+	  extracted_serial=$func_arith_result
+	  my_xlib_u=lt$extracted_serial-$my_xlib ;;
+	*) break ;;
+	esac
+      done
+      extracted_archives="$extracted_archives $my_xlib_u"
+      my_xdir=$my_gentop/$my_xlib_u
+
+      func_mkdir_p "$my_xdir"
+
+      case $host in
+      *-darwin*)
+	func_verbose "Extracting $my_xabs"
+	# Do not bother doing anything if just a dry run
+	$opt_dry_run || {
+	  darwin_orig_dir=`pwd`
+	  cd $my_xdir || exit $?
+	  darwin_archive=$my_xabs
+	  darwin_curdir=`pwd`
+	  func_basename "$darwin_archive"
+	  darwin_base_archive=$func_basename_result
+	  darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+	  if test -n "$darwin_arches"; then
+	    darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+	    darwin_arch=
+	    func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+	    for darwin_arch in  $darwin_arches; do
+	      func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch"
+	      $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive"
+	      cd "unfat-$$/$darwin_base_archive-$darwin_arch"
+	      func_extract_an_archive "`pwd`" "$darwin_base_archive"
+	      cd "$darwin_curdir"
+	      $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive"
+	    done # $darwin_arches
+            ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+	    darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u`
+	    darwin_file=
+	    darwin_files=
+	    for darwin_file in $darwin_filelist; do
+	      darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+	      $LIPO -create -output "$darwin_file" $darwin_files
+	    done # $darwin_filelist
+	    $RM -rf unfat-$$
+	    cd "$darwin_orig_dir"
+	  else
+	    cd $darwin_orig_dir
+	    func_extract_an_archive "$my_xdir" "$my_xabs"
+	  fi # $darwin_arches
+	} # !$opt_dry_run
+	;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+	;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+    done
+
+    func_extract_archives_result=$my_oldobjs
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable.  Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take.  If 'yes', then the emitted script
+# will assume that the directory where it is stored is
+# the $objdir directory.  This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+	func_emit_wrapper_arg1=${1-no}
+
+	$ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variables:
+  generated_by_libtool_version='$macro_version'
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$ECHO are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    file=\"\$0\""
+
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+    $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+    ECHO=\"$qECHO\"
+  fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+  lt_script_arg0=\$0
+  shift
+  for lt_opt
+  do
+    case \"\$lt_opt\" in
+    --lt-debug) lt_option_debug=1 ;;
+    --lt-dump-script)
+        lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+        test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+        lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+        cat \"\$lt_dump_D/\$lt_dump_F\"
+        exit 0
+      ;;
+    --lt-*)
+        \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+        exit 1
+      ;;
+    esac
+  done
+
+  # Print the debug banner immediately:
+  if test -n \"\$lt_option_debug\"; then
+    echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2
+  fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+  lt_dump_args_N=1;
+  for lt_arg
+  do
+    \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\"
+    lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+  done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+  case $host in
+  # Backslashes separate directories on plain windows
+  *-*-mingw | *-*-os2* | *-cegcc*)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+    ;;
+
+  *)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+    ;;
+  esac
+  $ECHO "\
+      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+      exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+  case \" \$* \" in
+  *\\ --lt-*)
+    for lt_wr_arg
+    do
+      case \$lt_wr_arg in
+      --lt-*) ;;
+      *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+      esac
+      shift
+    done ;;
+  esac
+  func_exec_program_core \${1+\"\$@\"}
+}
+
+  # Parse options
+  func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+  done
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+  if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+    # special case for '.'
+    if test \"\$thisdir\" = \".\"; then
+      thisdir=\`pwd\`
+    fi
+    # remove .libs from thisdir
+    case \"\$thisdir\" in
+    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+    $objdir )   thisdir=. ;;
+    esac
+  fi
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+	if test yes = "$fast_install"; then
+	  $ECHO "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" ||
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $MKDIR \"\$progdir\"
+    else
+      $RM \"\$progdir/\$file\"
+    fi"
+
+	  $ECHO "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+	\$ECHO \"\$relink_command_output\" >&2
+	$RM \"\$progdir/\$file\"
+	exit 1
+      fi
+    fi
+
+    $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $RM \"\$progdir/\$program\";
+      $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $RM \"\$progdir/\$file\"
+  fi"
+	else
+	  $ECHO "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+	fi
+
+	$ECHO "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+	# fixup the dll searchpath if we need to.
+	#
+	# Fix the DLL searchpath if we need to.  Do this before prepending
+	# to shlibpath, because on Windows, both are PATH and uninstalled
+	# libraries must come first.
+	if test -n "$dllsearchpath"; then
+	  $ECHO "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+	fi
+
+	# Export our shlibpath_var if we have one.
+	if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	  $ECHO "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+	fi
+
+	$ECHO "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+      func_exec_program \${1+\"\$@\"}
+    fi
+  else
+    # The program doesn't exist.
+    \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2
+    \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+    \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+	cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+*/
+EOF
+	    cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+#  include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
+/* declarations of non-ANSI functions */
+#if defined __MINGW32__
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined __CYGWIN__
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined other_platform || defined ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined _MSC_VER
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+# define S_IXUSR _S_IEXEC
+#elif defined __MINGW32__
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+#elif defined __CYGWIN__
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined other platforms ... */
+#endif
+
+#if defined PATH_MAX
+# define LT_PATHMAX PATH_MAX
+#elif defined MAXPATHLEN
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \
+  defined __OS2__
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+#  define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+	(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free (stale); stale = 0; } \
+} while (0)
+
+#if defined LT_DEBUGWRAPPER
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+	    cat <<EOF
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+# define externally_visible volatile
+#else
+# define externally_visible __attribute__((externally_visible)) volatile
+#endif
+externally_visible const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+	    if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+              func_to_host_path "$temp_rpath"
+	      cat <<EOF
+const char * LIB_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * LIB_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test -n "$dllsearchpath"; then
+              func_to_host_path "$dllsearchpath:"
+	      cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test yes = "$fast_install"; then
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+	    else
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+	    fi
+
+
+	    cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX         "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt            = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int  newargc;
+  char *tmp_pathspec;
+  char *actual_cwrapper_path;
+  char *actual_cwrapper_name;
+  char *target_name;
+  char *lt_argv_zero;
+  int rval = 127;
+
+  int i;
+
+  program_name = (char *) xstrdup (base_name (argv[0]));
+  newargz = XMALLOC (char *, (size_t) argc + 1);
+
+  /* very simple arg parsing; don't want to rely on getopt
+   * also, copy all non cwrapper options to newargz, except
+   * argz[0], which is handled differently
+   */
+  newargc=0;
+  for (i = 1; i < argc; i++)
+    {
+      if (STREQ (argv[i], dumpscript_opt))
+	{
+EOF
+	    case $host in
+	      *mingw* | *cygwin* )
+		# make stdout use "unix" line endings
+		echo "          setmode(1,_O_BINARY);"
+		;;
+	      esac
+
+	    cat <<"EOF"
+	  lt_dump_script (stdout);
+	  return 0;
+	}
+      if (STREQ (argv[i], debug_opt))
+	{
+          lt_debug = 1;
+          continue;
+	}
+      if (STREQ (argv[i], ltwrapper_option_prefix))
+        {
+          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+             namespace, but it is not one of the ones we know about and
+             have already dealt with, above (inluding dump-script), then
+             report an error. Otherwise, targets might begin to believe
+             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+             namespace. The first time any user complains about this, we'll
+             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+             or a configure.ac-settable value.
+           */
+          lt_fatal (__FILE__, __LINE__,
+		    "unrecognized %s option: '%s'",
+                    ltwrapper_option_prefix, argv[i]);
+        }
+      /* otherwise ... */
+      newargz[++newargc] = xstrdup (argv[i]);
+    }
+  newargz[++newargc] = NULL;
+
+EOF
+	    cat <<EOF
+  /* The GNU banner must be the first non-error debug message */
+  lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE) $VERSION\n");
+EOF
+	    cat <<"EOF"
+  lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+  tmp_pathspec = find_executable (argv[0]);
+  if (tmp_pathspec == NULL)
+    lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (before symlink chase) at: %s\n",
+		  tmp_pathspec);
+
+  actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (after symlink chase) at: %s\n",
+		  actual_cwrapper_path);
+  XFREE (tmp_pathspec);
+
+  actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+  strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+  /* wrapper name transforms */
+  strendzap (actual_cwrapper_name, ".exe");
+  tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+  XFREE (actual_cwrapper_name);
+  actual_cwrapper_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  /* target_name transforms -- use actual target program name; might have lt- prefix */
+  target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+  strendzap (target_name, ".exe");
+  tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+  XFREE (target_name);
+  target_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(main) libtool target name: %s\n",
+		  target_name);
+EOF
+
+	    cat <<EOF
+  newargz[0] =
+    XMALLOC (char, (strlen (actual_cwrapper_path) +
+		    strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+  strcpy (newargz[0], actual_cwrapper_path);
+  strcat (newargz[0], "$objdir");
+  strcat (newargz[0], "/");
+EOF
+
+	    cat <<"EOF"
+  /* stop here, and copy so we don't have to do this twice */
+  tmp_pathspec = xstrdup (newargz[0]);
+
+  /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+  strcat (newargz[0], actual_cwrapper_name);
+
+  /* DO want the lt- prefix here if it exists, so use target_name */
+  lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+  XFREE (tmp_pathspec);
+  tmp_pathspec = NULL;
+EOF
+
+	    case $host_os in
+	      mingw*)
+	    cat <<"EOF"
+  {
+    char* p;
+    while ((p = strchr (newargz[0], '\\')) != NULL)
+      {
+	*p = '/';
+      }
+    while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+      {
+	*p = '/';
+      }
+  }
+EOF
+	    ;;
+	    esac
+
+	    cat <<"EOF"
+  XFREE (target_name);
+  XFREE (actual_cwrapper_path);
+  XFREE (actual_cwrapper_name);
+
+  lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+  lt_setenv ("DUALCASE", "1");  /* for MSK sh */
+  /* Update the DLL searchpath.  EXE_PATH_VALUE ($dllsearchpath) must
+     be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+     because on Windows, both *_VARNAMEs are PATH but uninstalled
+     libraries must come first. */
+  lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+  lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+  lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+		  nonnull (lt_argv_zero));
+  for (i = 0; i < newargc; i++)
+    {
+      lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+		      i, nonnull (newargz[i]));
+    }
+
+EOF
+
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+  /* execv doesn't actually work on mingw as expected on unix */
+  newargz = prepare_spawn (newargz);
+  rval = (int) _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+  if (rval == -1)
+    {
+      /* failed to start process */
+      lt_debugprintf (__FILE__, __LINE__,
+		      "(main) failed to launch target \"%s\": %s\n",
+		      lt_argv_zero, nonnull (strerror (errno)));
+      return 127;
+    }
+  return rval;
+EOF
+		;;
+	      *)
+		cat <<"EOF"
+  execv (lt_argv_zero, newargz);
+  return rval; /* =127, but avoids unused variable warning */
+EOF
+		;;
+	    esac
+
+	    cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+  void *p = (void *) malloc (num);
+  if (!p)
+    lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+			  string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+  const char *base;
+
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return base;
+}
+
+int
+check_executable (const char *path)
+{
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if ((stat (path, &st) >= 0)
+      && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+    return 1;
+  else
+    return 0;
+}
+
+int
+make_executable (const char *path)
+{
+  int rval = 0;
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if (stat (path, &st) >= 0)
+    {
+      rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+    }
+  return rval;
+}
+
+/* Searches for the full path of the wrapper.  Returns
+   newly allocated full path name if found, NULL otherwise
+   Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+  int has_slash = 0;
+  const char *p;
+  const char *p_next;
+  /* static buffer for getcwd */
+  char tmp[LT_PATHMAX + 1];
+  size_t tmp_len;
+  char *concat_name;
+
+  lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+                  nonempty (wrapper));
+
+  if ((wrapper == NULL) || (*wrapper == '\0'))
+    return NULL;
+
+  /* Absolute path? */
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+  if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+    {
+      concat_name = xstrdup (wrapper);
+      if (check_executable (concat_name))
+	return concat_name;
+      XFREE (concat_name);
+    }
+  else
+    {
+#endif
+      if (IS_DIR_SEPARATOR (wrapper[0]))
+	{
+	  concat_name = xstrdup (wrapper);
+	  if (check_executable (concat_name))
+	    return concat_name;
+	  XFREE (concat_name);
+	}
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+    }
+#endif
+
+  for (p = wrapper; *p; p++)
+    if (*p == '/')
+      {
+	has_slash = 1;
+	break;
+      }
+  if (!has_slash)
+    {
+      /* no slashes; search PATH */
+      const char *path = getenv ("PATH");
+      if (path != NULL)
+	{
+	  for (p = path; *p; p = p_next)
+	    {
+	      const char *q;
+	      size_t p_len;
+	      for (q = p; *q; q++)
+		if (IS_PATH_SEPARATOR (*q))
+		  break;
+	      p_len = (size_t) (q - p);
+	      p_next = (*q == '\0' ? q : q + 1);
+	      if (p_len == 0)
+		{
+		  /* empty path: current directory */
+		  if (getcwd (tmp, LT_PATHMAX) == NULL)
+		    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+                              nonnull (strerror (errno)));
+		  tmp_len = strlen (tmp);
+		  concat_name =
+		    XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, tmp, tmp_len);
+		  concat_name[tmp_len] = '/';
+		  strcpy (concat_name + tmp_len + 1, wrapper);
+		}
+	      else
+		{
+		  concat_name =
+		    XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, p, p_len);
+		  concat_name[p_len] = '/';
+		  strcpy (concat_name + p_len + 1, wrapper);
+		}
+	      if (check_executable (concat_name))
+		return concat_name;
+	      XFREE (concat_name);
+	    }
+	}
+      /* not found in PATH; assume curdir */
+    }
+  /* Relative path | not found in path: prepend cwd */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+              nonnull (strerror (errno)));
+  tmp_len = strlen (tmp);
+  concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+  memcpy (concat_name, tmp, tmp_len);
+  concat_name[tmp_len] = '/';
+  strcpy (concat_name + tmp_len + 1, wrapper);
+
+  if (check_executable (concat_name))
+    return concat_name;
+  XFREE (concat_name);
+  return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+  return xstrdup (pathspec);
+#else
+  char buf[LT_PATHMAX];
+  struct stat s;
+  char *tmp_pathspec = xstrdup (pathspec);
+  char *p;
+  int has_symlinks = 0;
+  while (strlen (tmp_pathspec) && !has_symlinks)
+    {
+      lt_debugprintf (__FILE__, __LINE__,
+		      "checking path component for symlinks: %s\n",
+		      tmp_pathspec);
+      if (lstat (tmp_pathspec, &s) == 0)
+	{
+	  if (S_ISLNK (s.st_mode) != 0)
+	    {
+	      has_symlinks = 1;
+	      break;
+	    }
+
+	  /* search backwards for last DIR_SEPARATOR */
+	  p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+	  while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    p--;
+	  if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    {
+	      /* no more DIR_SEPARATORS left */
+	      break;
+	    }
+	  *p = '\0';
+	}
+      else
+	{
+	  lt_fatal (__FILE__, __LINE__,
+		    "error accessing file \"%s\": %s",
+		    tmp_pathspec, nonnull (strerror (errno)));
+	}
+    }
+  XFREE (tmp_pathspec);
+
+  if (!has_symlinks)
+    {
+      return xstrdup (pathspec);
+    }
+
+  tmp_pathspec = realpath (pathspec, buf);
+  if (tmp_pathspec == 0)
+    {
+      lt_fatal (__FILE__, __LINE__,
+		"could not follow symlinks for %s", pathspec);
+    }
+  return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert (str != NULL);
+  assert (pat != NULL);
+
+  len = strlen (str);
+  patlen = strlen (pat);
+
+  if (patlen <= len)
+    {
+      str += len - patlen;
+      if (STREQ (str, pat))
+	*str = '\0';
+    }
+  return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+  va_list args;
+  if (lt_debug)
+    {
+      (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+      va_start (args, fmt);
+      (void) vfprintf (stderr, fmt, args);
+      va_end (args);
+    }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+	       int line, const char *mode,
+	       const char *message, va_list ap)
+{
+  fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+  va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+  return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+  return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_setenv) setting '%s' to '%s'\n",
+                  nonnull (name), nonnull (value));
+  {
+#ifdef HAVE_SETENV
+    /* always make a copy, for consistency with !HAVE_SETENV */
+    char *str = xstrdup (value);
+    setenv (name, str, 1);
+#else
+    size_t len = strlen (name) + 1 + strlen (value) + 1;
+    char *str = XMALLOC (char, len);
+    sprintf (str, "%s=%s", name, value);
+    if (putenv (str) != EXIT_SUCCESS)
+      {
+        XFREE (str);
+      }
+#endif
+  }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+  char *new_value;
+  if (orig_value && *orig_value)
+    {
+      size_t orig_value_len = strlen (orig_value);
+      size_t add_len = strlen (add);
+      new_value = XMALLOC (char, add_len + orig_value_len + 1);
+      if (to_end)
+        {
+          strcpy (new_value, orig_value);
+          strcpy (new_value + orig_value_len, add);
+        }
+      else
+        {
+          strcpy (new_value, add);
+          strcpy (new_value + add_len, orig_value);
+        }
+    }
+  else
+    {
+      new_value = xstrdup (add);
+    }
+  return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      /* some systems can't cope with a ':'-terminated path #' */
+      size_t len = strlen (new_value);
+      while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+        {
+          new_value[--len] = '\0';
+        }
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+EOF
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+   Note that spawn() does not by itself call the command interpreter
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+         GetVersionEx(&v);
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+      }) ? "cmd.exe" : "command.com").
+   Instead it simply concatenates the arguments, separated by ' ', and calls
+   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+   special way:
+   - Space and tab are interpreted as delimiters. They are not treated as
+     delimiters if they are surrounded by double quotes: "...".
+   - Unescaped double quotes are removed from the input. Their only effect is
+     that within double quotes, space and tab are treated like normal
+     characters.
+   - Backslashes not followed by double quotes are not special.
+   - But 2*n+1 backslashes followed by a double quote become
+     n backslashes followed by a double quote (n >= 0):
+       \" -> "
+       \\\" -> \"
+       \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+  size_t argc;
+  char **new_argv;
+  size_t i;
+
+  /* Count number of arguments.  */
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  /* Allocate new argument vector.  */
+  new_argv = XMALLOC (char *, argc + 1);
+
+  /* Put quoted arguments into the new argument vector.  */
+  for (i = 0; i < argc; i++)
+    {
+      const char *string = argv[i];
+
+      if (string[0] == '\0')
+	new_argv[i] = xstrdup ("\"\"");
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+	{
+	  int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+	  size_t length;
+	  unsigned int backslashes;
+	  const char *s;
+	  char *quoted_string;
+	  char *p;
+
+	  length = 0;
+	  backslashes = 0;
+	  if (quote_around)
+	    length++;
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		length += backslashes + 1;
+	      length++;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    length += backslashes + 1;
+
+	  quoted_string = XMALLOC (char, length + 1);
+
+	  p = quoted_string;
+	  backslashes = 0;
+	  if (quote_around)
+	    *p++ = '"';
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		{
+		  unsigned int j;
+		  for (j = backslashes + 1; j > 0; j--)
+		    *p++ = '\\';
+		}
+	      *p++ = c;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    {
+	      unsigned int j;
+	      for (j = backslashes; j > 0; j--)
+		*p++ = '\\';
+	      *p++ = '"';
+	    }
+	  *p = '\0';
+
+	  new_argv[i] = quoted_string;
+	}
+      else
+	new_argv[i] = (char *) string;
+    }
+  new_argv[argc] = NULL;
+
+  return new_argv;
+}
+EOF
+		;;
+	    esac
+
+            cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+	    func_emit_wrapper yes |
+	      $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/  fputs ("\1", f);/p
+g
+D'
+            cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+    $debug_cmd
+
+    case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+    *import*) : ;;
+    *) false ;;
+    esac
+}
+
+# func_suncc_cstd_abi
+# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!!
+# Several compiler flags select an ABI that is incompatible with the
+# Cstd library. Avoid specifying it if any are in CXXFLAGS.
+func_suncc_cstd_abi ()
+{
+    $debug_cmd
+
+    case " $compile_command " in
+    *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*)
+      suncc_use_cstd_abi=no
+      ;;
+    *)
+      suncc_use_cstd_abi=yes
+      ;;
+    esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+    $debug_cmd
+
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # what system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll that has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args=$nonopt
+    base_compile="$nonopt $@"
+    compile_command=$nonopt
+    finalize_command=$nonopt
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+    new_inherited_linker_flags=
+
+    avoid_version=no
+    bindir=
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    os2dllname=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=false
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+    weak_libs=
+    single_module=$wl-single_module
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -shared)
+	test yes != "$build_libtool_libs" \
+	  && func_fatal_configuration "cannot build a shared library"
+	build_old_libs=no
+	break
+	;;
+      -all-static | -static | -static-libtool-libs)
+	case $arg in
+	-all-static)
+	  if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then
+	    func_warning "complete static linking is impossible in this configuration"
+	  fi
+	  if test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	-static)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=built
+	  ;;
+	-static-libtool-libs)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	esac
+	build_libtool_libs=no
+	build_old_libs=yes
+	break
+	;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg=$1
+      shift
+      func_quote_for_eval "$arg"
+      qarg=$func_quote_for_eval_unquoted_result
+      func_append libtool_args " $func_quote_for_eval_result"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+	case $prev in
+	output)
+	  func_append compile_command " @OUTPUT@"
+	  func_append finalize_command " @OUTPUT@"
+	  ;;
+	esac
+
+	case $prev in
+	bindir)
+	  bindir=$arg
+	  prev=
+	  continue
+	  ;;
+	dlfiles|dlprefiles)
+	  $preload || {
+	    # Add the symbol object into the linking commands.
+	    func_append compile_command " @SYMFILE@"
+	    func_append finalize_command " @SYMFILE@"
+	    preload=:
+	  }
+	  case $arg in
+	  *.la | *.lo) ;;  # We handle these cases below.
+	  force)
+	    if test no = "$dlself"; then
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  self)
+	    if test dlprefiles = "$prev"; then
+	      dlself=yes
+	    elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then
+	      dlself=yes
+	    else
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  *)
+	    if test dlfiles = "$prev"; then
+	      func_append dlfiles " $arg"
+	    else
+	      func_append dlprefiles " $arg"
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  esac
+	  ;;
+	expsyms)
+	  export_symbols=$arg
+	  test -f "$arg" \
+	    || func_fatal_error "symbol file '$arg' does not exist"
+	  prev=
+	  continue
+	  ;;
+	expsyms_regex)
+	  export_symbols_regex=$arg
+	  prev=
+	  continue
+	  ;;
+	framework)
+	  case $host in
+	    *-*-darwin*)
+	      case "$deplibs " in
+		*" $qarg.ltframework "*) ;;
+		*) func_append deplibs " $qarg.ltframework" # this is fixed later
+		   ;;
+	      esac
+	      ;;
+	  esac
+	  prev=
+	  continue
+	  ;;
+	inst_prefix)
+	  inst_prefix_dir=$arg
+	  prev=
+	  continue
+	  ;;
+	mllvm)
+	  # Clang does not use LLVM to link, so we can simply discard any
+	  # '-mllvm $arg' options when doing the link step.
+	  prev=
+	  continue
+	  ;;
+	objectlist)
+	  if test -f "$arg"; then
+	    save_arg=$arg
+	    moreargs=
+	    for fil in `cat "$save_arg"`
+	    do
+#	      func_append moreargs " $fil"
+	      arg=$fil
+	      # A libtool-controlled object.
+
+	      # Check to see that this really is a libtool object.
+	      if func_lalib_unsafe_p "$arg"; then
+		pic_object=
+		non_pic_object=
+
+		# Read the .lo file
+		func_source "$arg"
+
+		if test -z "$pic_object" ||
+		   test -z "$non_pic_object" ||
+		   test none = "$pic_object" &&
+		   test none = "$non_pic_object"; then
+		  func_fatal_error "cannot find name of object for '$arg'"
+		fi
+
+		# Extract subdirectory from the argument.
+		func_dirname "$arg" "/" ""
+		xdir=$func_dirname_result
+
+		if test none != "$pic_object"; then
+		  # Prepend the subdirectory the object is found in.
+		  pic_object=$xdir$pic_object
+
+		  if test dlfiles = "$prev"; then
+		    if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
+		      func_append dlfiles " $pic_object"
+		      prev=
+		      continue
+		    else
+		      # If libtool objects are unsupported, then we need to preload.
+		      prev=dlprefiles
+		    fi
+		  fi
+
+		  # CHECK ME:  I think I busted this.  -Ossama
+		  if test dlprefiles = "$prev"; then
+		    # Preload the old-style object.
+		    func_append dlprefiles " $pic_object"
+		    prev=
+		  fi
+
+		  # A PIC object.
+		  func_append libobjs " $pic_object"
+		  arg=$pic_object
+		fi
+
+		# Non-PIC object.
+		if test none != "$non_pic_object"; then
+		  # Prepend the subdirectory the object is found in.
+		  non_pic_object=$xdir$non_pic_object
+
+		  # A standard non-PIC object
+		  func_append non_pic_objects " $non_pic_object"
+		  if test -z "$pic_object" || test none = "$pic_object"; then
+		    arg=$non_pic_object
+		  fi
+		else
+		  # If the PIC object exists, use it instead.
+		  # $xdir was prepended to $pic_object above.
+		  non_pic_object=$pic_object
+		  func_append non_pic_objects " $non_pic_object"
+		fi
+	      else
+		# Only an error if not doing a dry-run.
+		if $opt_dry_run; then
+		  # Extract subdirectory from the argument.
+		  func_dirname "$arg" "/" ""
+		  xdir=$func_dirname_result
+
+		  func_lo2o "$arg"
+		  pic_object=$xdir$objdir/$func_lo2o_result
+		  non_pic_object=$xdir$func_lo2o_result
+		  func_append libobjs " $pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+	        else
+		  func_fatal_error "'$arg' is not a valid libtool object"
+		fi
+	      fi
+	    done
+	  else
+	    func_fatal_error "link input file '$arg' does not exist"
+	  fi
+	  arg=$save_arg
+	  prev=
+	  continue
+	  ;;
+	os2dllname)
+	  os2dllname=$arg
+	  prev=
+	  continue
+	  ;;
+	precious_regex)
+	  precious_files_regex=$arg
+	  prev=
+	  continue
+	  ;;
+	release)
+	  release=-$arg
+	  prev=
+	  continue
+	  ;;
+	rpath | xrpath)
+	  # We need an absolute path.
+	  case $arg in
+	  [\\/]* | [A-Za-z]:[\\/]*) ;;
+	  *)
+	    func_fatal_error "only absolute run-paths are allowed"
+	    ;;
+	  esac
+	  if test rpath = "$prev"; then
+	    case "$rpath " in
+	    *" $arg "*) ;;
+	    *) func_append rpath " $arg" ;;
+	    esac
+	  else
+	    case "$xrpath " in
+	    *" $arg "*) ;;
+	    *) func_append xrpath " $arg" ;;
+	    esac
+	  fi
+	  prev=
+	  continue
+	  ;;
+	shrext)
+	  shrext_cmds=$arg
+	  prev=
+	  continue
+	  ;;
+	weak)
+	  func_append weak_libs " $arg"
+	  prev=
+	  continue
+	  ;;
+	xcclinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xcompiler)
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xlinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $wl$qarg"
+	  prev=
+	  func_append compile_command " $wl$qarg"
+	  func_append finalize_command " $wl$qarg"
+	  continue
+	  ;;
+	*)
+	  eval "$prev=\"\$arg\""
+	  prev=
+	  continue
+	  ;;
+	esac
+      fi # test -n "$prev"
+
+      prevarg=$arg
+
+      case $arg in
+      -all-static)
+	if test -n "$link_static_flag"; then
+	  # See comment for -static flag below, for more details.
+	  func_append compile_command " $link_static_flag"
+	  func_append finalize_command " $link_static_flag"
+	fi
+	continue
+	;;
+
+      -allow-undefined)
+	# FIXME: remove this flag sometime in the future.
+	func_fatal_error "'-allow-undefined' must not be used because it is the default"
+	;;
+
+      -avoid-version)
+	avoid_version=yes
+	continue
+	;;
+
+      -bindir)
+	prev=bindir
+	continue
+	;;
+
+      -dlopen)
+	prev=dlfiles
+	continue
+	;;
+
+      -dlpreopen)
+	prev=dlprefiles
+	continue
+	;;
+
+      -export-dynamic)
+	export_dynamic=yes
+	continue
+	;;
+
+      -export-symbols | -export-symbols-regex)
+	if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	  func_fatal_error "more than one -exported-symbols argument is not allowed"
+	fi
+	if test X-export-symbols = "X$arg"; then
+	  prev=expsyms
+	else
+	  prev=expsyms_regex
+	fi
+	continue
+	;;
+
+      -framework)
+	prev=framework
+	continue
+	;;
+
+      -inst-prefix-dir)
+	prev=inst_prefix
+	continue
+	;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+	case $with_gcc/$host in
+	no/*-*-irix* | /*-*-irix*)
+	  func_append compile_command " $arg"
+	  func_append finalize_command " $arg"
+	  ;;
+	esac
+	continue
+	;;
+
+      -L*)
+	func_stripname "-L" '' "$arg"
+	if test -z "$func_stripname_result"; then
+	  if test "$#" -gt 0; then
+	    func_fatal_error "require no space between '-L' and '$1'"
+	  else
+	    func_fatal_error "need path for '-L' option"
+	  fi
+	fi
+	func_resolve_sysroot "$func_stripname_result"
+	dir=$func_resolve_sysroot_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  absdir=`cd "$dir" && pwd`
+	  test -z "$absdir" && \
+	    func_fatal_error "cannot determine absolute directory name of '$dir'"
+	  dir=$absdir
+	  ;;
+	esac
+	case "$deplibs " in
+	*" -L$dir "* | *" $arg "*)
+	  # Will only happen for absolute or sysroot arguments
+	  ;;
+	*)
+	  # Preserve sysroot, but never include relative directories
+	  case $dir in
+	    [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+	    *) func_append deplibs " -L$dir" ;;
+	  esac
+	  func_append lib_search_path " $dir"
+	  ;;
+	esac
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$dir:"*) ;;
+	  ::) dllsearchpath=$dir;;
+	  *) func_append dllsearchpath ":$dir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+	continue
+	;;
+
+      -l*)
+	if test X-lc = "X$arg" || test X-lm = "X$arg"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # These systems don't actually have a C or math library (as such)
+	    continue
+	    ;;
+	  *-*-os2*)
+	    # These systems don't actually have a C library (as such)
+	    test X-lc = "X$arg" && continue
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+	    # Do not include libc due to us having libc/libc_r.
+	    test X-lc = "X$arg" && continue
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C and math libraries are in the System framework
+	    func_append deplibs " System.ltframework"
+	    continue
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    test X-lc = "X$arg" && continue
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    test X-lc = "X$arg" && continue
+	    ;;
+	  esac
+	elif test X-lc_r = "X$arg"; then
+	 case $host in
+	 *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+	   # Do not include libc_r directly, use -pthread flag.
+	   continue
+	   ;;
+	 esac
+	fi
+	func_append deplibs " $arg"
+	continue
+	;;
+
+      -mllvm)
+	prev=mllvm
+	continue
+	;;
+
+      -module)
+	module=yes
+	continue
+	;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      # Darwin uses the -arch flag to determine output architecture.
+      -model|-arch|-isysroot|--sysroot)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	prev=xcompiler
+	continue
+	;;
+
+      -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+      |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	case "$new_inherited_linker_flags " in
+	    *" $arg "*) ;;
+	    * ) func_append new_inherited_linker_flags " $arg" ;;
+	esac
+	continue
+	;;
+
+      -multi_module)
+	single_module=$wl-multi_module
+	continue
+	;;
+
+      -no-fast-install)
+	fast_install=no
+	continue
+	;;
+
+      -no-install)
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+	  # The PATH hackery in wrapper scripts is required on Windows
+	  # and Darwin in order for the loader to find any dlls it needs.
+	  func_warning "'-no-install' is ignored for $host"
+	  func_warning "assuming '-no-fast-install' instead"
+	  fast_install=no
+	  ;;
+	*) no_install=yes ;;
+	esac
+	continue
+	;;
+
+      -no-undefined)
+	allow_undefined=no
+	continue
+	;;
+
+      -objectlist)
+	prev=objectlist
+	continue
+	;;
+
+      -os2dllname)
+	prev=os2dllname
+	continue
+	;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+	prev=precious_regex
+	continue
+	;;
+
+      -release)
+	prev=release
+	continue
+	;;
+
+      -rpath)
+	prev=rpath
+	continue
+	;;
+
+      -R)
+	prev=xrpath
+	continue
+	;;
+
+      -R*)
+	func_stripname '-R' '' "$arg"
+	dir=$func_stripname_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	=*)
+	  func_stripname '=' '' "$dir"
+	  dir=$lt_sysroot$func_stripname_result
+	  ;;
+	*)
+	  func_fatal_error "only absolute run-paths are allowed"
+	  ;;
+	esac
+	case "$xrpath " in
+	*" $dir "*) ;;
+	*) func_append xrpath " $dir" ;;
+	esac
+	continue
+	;;
+
+      -shared)
+	# The effects of -shared are defined in a previous loop.
+	continue
+	;;
+
+      -shrext)
+	prev=shrext
+	continue
+	;;
+
+      -static | -static-libtool-libs)
+	# The effects of -static are defined in a previous loop.
+	# We used to do the same as -all-static on platforms that
+	# didn't have a PIC flag, but the assumption that the effects
+	# would be equivalent was wrong.  It would break on at least
+	# Digital Unix and AIX.
+	continue
+	;;
+
+      -thread-safe)
+	thread_safe=yes
+	continue
+	;;
+
+      -version-info)
+	prev=vinfo
+	continue
+	;;
+
+      -version-number)
+	prev=vinfo
+	vinfo_number=yes
+	continue
+	;;
+
+      -weak)
+        prev=weak
+	continue
+	;;
+
+      -Wc,*)
+	func_stripname '-Wc,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs=$IFS; IFS=,
+	for flag in $args; do
+	  IFS=$save_ifs
+          func_quote_for_eval "$flag"
+	  func_append arg " $func_quote_for_eval_result"
+	  func_append compiler_flags " $func_quote_for_eval_result"
+	done
+	IFS=$save_ifs
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Wl,*)
+	func_stripname '-Wl,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs=$IFS; IFS=,
+	for flag in $args; do
+	  IFS=$save_ifs
+          func_quote_for_eval "$flag"
+	  func_append arg " $wl$func_quote_for_eval_result"
+	  func_append compiler_flags " $wl$func_quote_for_eval_result"
+	  func_append linker_flags " $func_quote_for_eval_result"
+	done
+	IFS=$save_ifs
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Xcompiler)
+	prev=xcompiler
+	continue
+	;;
+
+      -Xlinker)
+	prev=xlinker
+	continue
+	;;
+
+      -XCClinker)
+	prev=xcclinker
+	continue
+	;;
+
+      # -msg_* for osf cc
+      -msg_*)
+	func_quote_for_eval "$arg"
+	arg=$func_quote_for_eval_result
+	;;
+
+      # Flags to be passed through unchanged, with rationale:
+      # -64, -mips[0-9]      enable 64-bit mode for the SGI compiler
+      # -r[0-9][0-9]*        specify processor for the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+      # +DA*, +DD*           enable 64-bit mode for the HP compiler
+      # -q*                  compiler args for the IBM compiler
+      # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+      # -F/path              path to uninstalled frameworks, gcc on darwin
+      # -p, -pg, --coverage, -fprofile-*  profiling flags for GCC
+      # -fstack-protector*   stack protector flags for GCC
+      # @file                GCC response files
+      # -tp=*                Portland pgcc target processor selection
+      # --sysroot=*          for sysroot support
+      # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+      # -specs=*             GCC specs files
+      # -stdlib=*            select c++ std lib with clang
+      # -fsanitize=*         Clang/GCC memory and address sanitizer
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+      -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
+      -specs=*|-fsanitize=*)
+        func_quote_for_eval "$arg"
+	arg=$func_quote_for_eval_result
+        func_append compile_command " $arg"
+        func_append finalize_command " $arg"
+        func_append compiler_flags " $arg"
+        continue
+        ;;
+
+      -Z*)
+        if test os2 = "`expr $host : '.*\(os2\)'`"; then
+          # OS/2 uses -Zxxx to specify OS/2-specific options
+	  compiler_flags="$compiler_flags $arg"
+	  func_append compile_command " $arg"
+	  func_append finalize_command " $arg"
+	  case $arg in
+	  -Zlinker | -Zstack)
+	    prev=xcompiler
+	    ;;
+	  esac
+	  continue
+        else
+	  # Otherwise treat like 'Some other compiler flag' below
+	  func_quote_for_eval "$arg"
+	  arg=$func_quote_for_eval_result
+        fi
+	;;
+
+      # Some other compiler flag.
+      -* | +*)
+        func_quote_for_eval "$arg"
+	arg=$func_quote_for_eval_result
+	;;
+
+      *.$objext)
+	# A standard object.
+	func_append objs " $arg"
+	;;
+
+      *.lo)
+	# A libtool-controlled object.
+
+	# Check to see that this really is a libtool object.
+	if func_lalib_unsafe_p "$arg"; then
+	  pic_object=
+	  non_pic_object=
+
+	  # Read the .lo file
+	  func_source "$arg"
+
+	  if test -z "$pic_object" ||
+	     test -z "$non_pic_object" ||
+	     test none = "$pic_object" &&
+	     test none = "$non_pic_object"; then
+	    func_fatal_error "cannot find name of object for '$arg'"
+	  fi
+
+	  # Extract subdirectory from the argument.
+	  func_dirname "$arg" "/" ""
+	  xdir=$func_dirname_result
+
+	  test none = "$pic_object" || {
+	    # Prepend the subdirectory the object is found in.
+	    pic_object=$xdir$pic_object
+
+	    if test dlfiles = "$prev"; then
+	      if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
+		func_append dlfiles " $pic_object"
+		prev=
+		continue
+	      else
+		# If libtool objects are unsupported, then we need to preload.
+		prev=dlprefiles
+	      fi
+	    fi
+
+	    # CHECK ME:  I think I busted this.  -Ossama
+	    if test dlprefiles = "$prev"; then
+	      # Preload the old-style object.
+	      func_append dlprefiles " $pic_object"
+	      prev=
+	    fi
+
+	    # A PIC object.
+	    func_append libobjs " $pic_object"
+	    arg=$pic_object
+	  }
+
+	  # Non-PIC object.
+	  if test none != "$non_pic_object"; then
+	    # Prepend the subdirectory the object is found in.
+	    non_pic_object=$xdir$non_pic_object
+
+	    # A standard non-PIC object
+	    func_append non_pic_objects " $non_pic_object"
+	    if test -z "$pic_object" || test none = "$pic_object"; then
+	      arg=$non_pic_object
+	    fi
+	  else
+	    # If the PIC object exists, use it instead.
+	    # $xdir was prepended to $pic_object above.
+	    non_pic_object=$pic_object
+	    func_append non_pic_objects " $non_pic_object"
+	  fi
+	else
+	  # Only an error if not doing a dry-run.
+	  if $opt_dry_run; then
+	    # Extract subdirectory from the argument.
+	    func_dirname "$arg" "/" ""
+	    xdir=$func_dirname_result
+
+	    func_lo2o "$arg"
+	    pic_object=$xdir$objdir/$func_lo2o_result
+	    non_pic_object=$xdir$func_lo2o_result
+	    func_append libobjs " $pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  else
+	    func_fatal_error "'$arg' is not a valid libtool object"
+	  fi
+	fi
+	;;
+
+      *.$libext)
+	# An archive.
+	func_append deplibs " $arg"
+	func_append old_deplibs " $arg"
+	continue
+	;;
+
+      *.la)
+	# A libtool-controlled library.
+
+	func_resolve_sysroot "$arg"
+	if test dlfiles = "$prev"; then
+	  # This library was specified with -dlopen.
+	  func_append dlfiles " $func_resolve_sysroot_result"
+	  prev=
+	elif test dlprefiles = "$prev"; then
+	  # The library was specified with -dlpreopen.
+	  func_append dlprefiles " $func_resolve_sysroot_result"
+	  prev=
+	else
+	  func_append deplibs " $func_resolve_sysroot_result"
+	fi
+	continue
+	;;
+
+      # Some other compiler argument.
+      *)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	func_quote_for_eval "$arg"
+	arg=$func_quote_for_eval_result
+	;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+      fi
+    done # argument parsing loop
+
+    test -n "$prev" && \
+      func_fatal_help "the '$prevarg' option requires an argument"
+
+    if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      func_append compile_command " $arg"
+      func_append finalize_command " $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    func_basename "$output"
+    outputname=$func_basename_result
+    libobjs_save=$libobjs
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    # Definition is injected by LT_CONFIG during libtool generation.
+    func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH"
+
+    func_dirname "$output" "/" ""
+    output_objdir=$func_dirname_result$objdir
+    func_to_tool_file "$output_objdir/"
+    tool_output_objdir=$func_to_tool_file_result
+    # Create the object directory.
+    func_mkdir_p "$output_objdir"
+
+    # Determine the type of output
+    case $output in
+    "")
+      func_fatal_help "you must specify an output file"
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if $opt_preserve_dup_deps; then
+	case "$libs " in
+	*" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	esac
+      fi
+      func_append libs " $deplib"
+    done
+
+    if test lib = "$linkmode"; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if $opt_duplicate_compiler_generated_deps; then
+	for pre_post_dep in $predeps $postdeps; do
+	  case "$pre_post_deps " in
+	  *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+	  esac
+	  func_append pre_post_deps " $pre_post_dep"
+	done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+
+    case $linkmode in
+    lib)
+	passes="conv dlpreopen link"
+	for file in $dlfiles $dlprefiles; do
+	  case $file in
+	  *.la) ;;
+	  *)
+	    func_fatal_help "libraries can '-dlopen' only libtool libraries: $file"
+	    ;;
+	  esac
+	done
+	;;
+    prog)
+	compile_deplibs=
+	finalize_deplibs=
+	alldeplibs=false
+	newdlfiles=
+	newdlprefiles=
+	passes="conv scan dlopen dlpreopen link"
+	;;
+    *)  passes="conv"
+	;;
+    esac
+
+    for pass in $passes; do
+      # The preopen pass in lib mode reverses $deplibs; put it back here
+      # so that -L comes before libs that need it for instance...
+      if test lib,link = "$linkmode,$pass"; then
+	## FIXME: Find the place where the list is rebuilt in the wrong
+	##        order, and fix it there properly
+        tmp_deplibs=
+	for deplib in $deplibs; do
+	  tmp_deplibs="$deplib $tmp_deplibs"
+	done
+	deplibs=$tmp_deplibs
+      fi
+
+      if test lib,link = "$linkmode,$pass" ||
+	 test prog,scan = "$linkmode,$pass"; then
+	libs=$deplibs
+	deplibs=
+      fi
+      if test prog = "$linkmode"; then
+	case $pass in
+	dlopen) libs=$dlfiles ;;
+	dlpreopen) libs=$dlprefiles ;;
+	link)
+	  libs="$deplibs %DEPLIBS%"
+	  test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
+	  ;;
+	esac
+      fi
+      if test lib,dlpreopen = "$linkmode,$pass"; then
+	# Collect and forward deplibs of preopened libtool libs
+	for lib in $dlprefiles; do
+	  # Ignore non-libtool-libs
+	  dependency_libs=
+	  func_resolve_sysroot "$lib"
+	  case $lib in
+	  *.la)	func_source "$func_resolve_sysroot_result" ;;
+	  esac
+
+	  # Collect preopened libtool deplibs, except any this library
+	  # has declared as weak libs
+	  for deplib in $dependency_libs; do
+	    func_basename "$deplib"
+            deplib_base=$func_basename_result
+	    case " $weak_libs " in
+	    *" $deplib_base "*) ;;
+	    *) func_append deplibs " $deplib" ;;
+	    esac
+	  done
+	done
+	libs=$dlprefiles
+      fi
+      if test dlopen = "$pass"; then
+	# Collect dlpreopened libraries
+	save_deplibs=$deplibs
+	deplibs=
+      fi
+
+      for deplib in $libs; do
+	lib=
+	found=false
+	case $deplib in
+	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+        |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	  if test prog,link = "$linkmode,$pass"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    func_append compiler_flags " $deplib"
+	    if test lib = "$linkmode"; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-l*)
+	  if test lib != "$linkmode" && test prog != "$linkmode"; then
+	    func_warning "'-l' is ignored for archives/objects"
+	    continue
+	  fi
+	  func_stripname '-l' '' "$deplib"
+	  name=$func_stripname_result
+	  if test lib = "$linkmode"; then
+	    searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+	  else
+	    searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+	  fi
+	  for searchdir in $searchdirs; do
+	    for search_ext in .la $std_shrext .so .a; do
+	      # Search the libtool library
+	      lib=$searchdir/lib$name$search_ext
+	      if test -f "$lib"; then
+		if test .la = "$search_ext"; then
+		  found=:
+		else
+		  found=false
+		fi
+		break 2
+	      fi
+	    done
+	  done
+	  if $found; then
+	    # deplib is a libtool library
+	    # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+	    # We need to do some special things here, and not later.
+	    if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+	      case " $predeps $postdeps " in
+	      *" $deplib "*)
+		if func_lalib_p "$lib"; then
+		  library_names=
+		  old_library=
+		  func_source "$lib"
+		  for l in $old_library $library_names; do
+		    ll=$l
+		  done
+		  if test "X$ll" = "X$old_library"; then # only static version available
+		    found=false
+		    func_dirname "$lib" "" "."
+		    ladir=$func_dirname_result
+		    lib=$ladir/$old_library
+		    if test prog,link = "$linkmode,$pass"; then
+		      compile_deplibs="$deplib $compile_deplibs"
+		      finalize_deplibs="$deplib $finalize_deplibs"
+		    else
+		      deplibs="$deplib $deplibs"
+		      test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+		    fi
+		    continue
+		  fi
+		fi
+		;;
+	      *) ;;
+	      esac
+	    fi
+	  else
+	    # deplib doesn't seem to be a libtool library
+	    if test prog,link = "$linkmode,$pass"; then
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      deplibs="$deplib $deplibs"
+	      test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    continue
+	  fi
+	  ;; # -l
+	*.ltframework)
+	  if test prog,link = "$linkmode,$pass"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    deplibs="$deplib $deplibs"
+	    if test lib = "$linkmode"; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-L*)
+	  case $linkmode in
+	  lib)
+	    deplibs="$deplib $deplibs"
+	    test conv = "$pass" && continue
+	    newdependency_libs="$deplib $newdependency_libs"
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  prog)
+	    if test conv = "$pass"; then
+	      deplibs="$deplib $deplibs"
+	      continue
+	    fi
+	    if test scan = "$pass"; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  *)
+	    func_warning "'-L' is ignored for archives/objects"
+	    ;;
+	  esac # linkmode
+	  continue
+	  ;; # -L
+	-R*)
+	  if test link = "$pass"; then
+	    func_stripname '-R' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    dir=$func_resolve_sysroot_result
+	    # Make sure the xrpath contains only unique directories.
+	    case "$xrpath " in
+	    *" $dir "*) ;;
+	    *) func_append xrpath " $dir" ;;
+	    esac
+	  fi
+	  deplibs="$deplib $deplibs"
+	  continue
+	  ;;
+	*.la)
+	  func_resolve_sysroot "$deplib"
+	  lib=$func_resolve_sysroot_result
+	  ;;
+	*.$libext)
+	  if test conv = "$pass"; then
+	    deplibs="$deplib $deplibs"
+	    continue
+	  fi
+	  case $linkmode in
+	  lib)
+	    # Linking convenience modules into shared libraries is allowed,
+	    # but linking other static libraries is non-portable.
+	    case " $dlpreconveniencelibs " in
+	    *" $deplib "*) ;;
+	    *)
+	      valid_a_lib=false
+	      case $deplibs_check_method in
+		match_pattern*)
+		  set dummy $deplibs_check_method; shift
+		  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+		  if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+		    | $EGREP "$match_pattern_regex" > /dev/null; then
+		    valid_a_lib=:
+		  fi
+		;;
+		pass_all)
+		  valid_a_lib=:
+		;;
+	      esac
+	      if $valid_a_lib; then
+		echo
+		$ECHO "*** Warning: Linking the shared library $output against the"
+		$ECHO "*** static library $deplib is not portable!"
+		deplibs="$deplib $deplibs"
+	      else
+		echo
+		$ECHO "*** Warning: Trying to link with static lib archive $deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because the file extensions .$libext of this argument makes me believe"
+		echo "*** that it is just a static archive that I should not use here."
+	      fi
+	      ;;
+	    esac
+	    continue
+	    ;;
+	  prog)
+	    if test link != "$pass"; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    continue
+	    ;;
+	  esac # linkmode
+	  ;; # *.$libext
+	*.lo | *.$objext)
+	  if test conv = "$pass"; then
+	    deplibs="$deplib $deplibs"
+	  elif test prog = "$linkmode"; then
+	    if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then
+	      # If there is no dlopen support or we're linking statically,
+	      # we need to preload.
+	      func_append newdlprefiles " $deplib"
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      func_append newdlfiles " $deplib"
+	    fi
+	  fi
+	  continue
+	  ;;
+	%DEPLIBS%)
+	  alldeplibs=:
+	  continue
+	  ;;
+	esac # case $deplib
+
+	$found || test -f "$lib" \
+	  || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'"
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$lib" \
+	  || func_fatal_error "'$lib' is not a valid libtool archive"
+
+	func_dirname "$lib" "" "."
+	ladir=$func_dirname_result
+
+	dlname=
+	dlopen=
+	dlpreopen=
+	libdir=
+	library_names=
+	old_library=
+	inherited_linker_flags=
+	# If the library was installed with an old release of libtool,
+	# it will not redefine variables installed, or shouldnotlink
+	installed=yes
+	shouldnotlink=no
+	avoidtemprpath=
+
+
+	# Read the .la file
+	func_source "$lib"
+
+	# Convert "-framework foo" to "foo.ltframework"
+	if test -n "$inherited_linker_flags"; then
+	  tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+	  for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+	    case " $new_inherited_linker_flags " in
+	      *" $tmp_inherited_linker_flag "*) ;;
+	      *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+	    esac
+	  done
+	fi
+	dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	if test lib,link = "$linkmode,$pass" ||
+	   test prog,scan = "$linkmode,$pass" ||
+	   { test prog != "$linkmode" && test lib != "$linkmode"; }; then
+	  test -n "$dlopen" && func_append dlfiles " $dlopen"
+	  test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+	fi
+
+	if test conv = "$pass"; then
+	  # Only check for convenience libraries
+	  deplibs="$lib $deplibs"
+	  if test -z "$libdir"; then
+	    if test -z "$old_library"; then
+	      func_fatal_error "cannot find name of link library for '$lib'"
+	    fi
+	    # It is a libtool convenience library, so add in its objects.
+	    func_append convenience " $ladir/$objdir/$old_library"
+	    func_append old_convenience " $ladir/$objdir/$old_library"
+	    tmp_libs=
+	    for deplib in $dependency_libs; do
+	      deplibs="$deplib $deplibs"
+	      if $opt_preserve_dup_deps; then
+		case "$tmp_libs " in
+		*" $deplib "*) func_append specialdeplibs " $deplib" ;;
+		esac
+	      fi
+	      func_append tmp_libs " $deplib"
+	    done
+	  elif test prog != "$linkmode" && test lib != "$linkmode"; then
+	    func_fatal_error "'$lib' is not a convenience library"
+	  fi
+	  continue
+	fi # $pass = conv
+
+
+	# Get the name of the library we link against.
+	linklib=
+	if test -n "$old_library" &&
+	   { test yes = "$prefer_static_libs" ||
+	     test built,no = "$prefer_static_libs,$installed"; }; then
+	  linklib=$old_library
+	else
+	  for l in $old_library $library_names; do
+	    linklib=$l
+	  done
+	fi
+	if test -z "$linklib"; then
+	  func_fatal_error "cannot find name of link library for '$lib'"
+	fi
+
+	# This library was specified with -dlopen.
+	if test dlopen = "$pass"; then
+	  test -z "$libdir" \
+	    && func_fatal_error "cannot -dlopen a convenience library: '$lib'"
+	  if test -z "$dlname" ||
+	     test yes != "$dlopen_support" ||
+	     test no = "$build_libtool_libs"
+	  then
+	    # If there is no dlname, no dlopen support or we're linking
+	    # statically, we need to preload.  We also need to preload any
+	    # dependent libraries so libltdl's deplib preloader doesn't
+	    # bomb out in the load deplibs phase.
+	    func_append dlprefiles " $lib $dependency_libs"
+	  else
+	    func_append newdlfiles " $lib"
+	  fi
+	  continue
+	fi # $pass = dlopen
+
+	# We need an absolute path.
+	case $ladir in
+	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;;
+	*)
+	  abs_ladir=`cd "$ladir" && pwd`
+	  if test -z "$abs_ladir"; then
+	    func_warning "cannot determine absolute directory name of '$ladir'"
+	    func_warning "passing it literally to the linker, although it might fail"
+	    abs_ladir=$ladir
+	  fi
+	  ;;
+	esac
+	func_basename "$lib"
+	laname=$func_basename_result
+
+	# Find the relevant object directory and library name.
+	if test yes = "$installed"; then
+	  if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    func_warning "library '$lib' was moved."
+	    dir=$ladir
+	    absdir=$abs_ladir
+	    libdir=$abs_ladir
+	  else
+	    dir=$lt_sysroot$libdir
+	    absdir=$lt_sysroot$libdir
+	  fi
+	  test yes = "$hardcode_automatic" && avoidtemprpath=yes
+	else
+	  if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    dir=$ladir
+	    absdir=$abs_ladir
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  else
+	    dir=$ladir/$objdir
+	    absdir=$abs_ladir/$objdir
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  fi
+	fi # $installed = yes
+	func_stripname 'lib' '.la' "$laname"
+	name=$func_stripname_result
+
+	# This library was specified with -dlpreopen.
+	if test dlpreopen = "$pass"; then
+	  if test -z "$libdir" && test prog = "$linkmode"; then
+	    func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'"
+	  fi
+	  case $host in
+	    # special handling for platforms with PE-DLLs.
+	    *cygwin* | *mingw* | *cegcc* )
+	      # Linker will automatically link against shared library if both
+	      # static and shared are present.  Therefore, ensure we extract
+	      # symbols from the import library if a shared library is present
+	      # (otherwise, the dlopen module name will be incorrect).  We do
+	      # this by putting the import library name into $newdlprefiles.
+	      # We recover the dlopen module name by 'saving' the la file
+	      # name in a special purpose variable, and (later) extracting the
+	      # dlname from the la file.
+	      if test -n "$dlname"; then
+	        func_tr_sh "$dir/$linklib"
+	        eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+	        func_append newdlprefiles " $dir/$linklib"
+	      else
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      fi
+	    ;;
+	    * )
+	      # Prefer using a static library (so that no silly _DYNAMIC symbols
+	      # are required to link).
+	      if test -n "$old_library"; then
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      # Otherwise, use the dlname, so that lt_dlopen finds it.
+	      elif test -n "$dlname"; then
+	        func_append newdlprefiles " $dir/$dlname"
+	      else
+	        func_append newdlprefiles " $dir/$linklib"
+	      fi
+	    ;;
+	  esac
+	fi # $pass = dlpreopen
+
+	if test -z "$libdir"; then
+	  # Link the convenience library
+	  if test lib = "$linkmode"; then
+	    deplibs="$dir/$old_library $deplibs"
+	  elif test prog,link = "$linkmode,$pass"; then
+	    compile_deplibs="$dir/$old_library $compile_deplibs"
+	    finalize_deplibs="$dir/$old_library $finalize_deplibs"
+	  else
+	    deplibs="$lib $deplibs" # used for prog,scan pass
+	  fi
+	  continue
+	fi
+
+
+	if test prog = "$linkmode" && test link != "$pass"; then
+	  func_append newlib_search_path " $ladir"
+	  deplibs="$lib $deplibs"
+
+	  linkalldeplibs=false
+	  if test no != "$link_all_deplibs" || test -z "$library_names" ||
+	     test no = "$build_libtool_libs"; then
+	    linkalldeplibs=:
+	  fi
+
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    case $deplib in
+	    -L*) func_stripname '-L' '' "$deplib"
+	         func_resolve_sysroot "$func_stripname_result"
+	         func_append newlib_search_path " $func_resolve_sysroot_result"
+		 ;;
+	    esac
+	    # Need to link against all dependency_libs?
+	    if $linkalldeplibs; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      # Need to hardcode shared library paths
+	      # or/and link against static libraries
+	      newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    if $opt_preserve_dup_deps; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $deplib"
+	  done # for deplib
+	  continue
+	fi # $linkmode = prog...
+
+	if test prog,link = "$linkmode,$pass"; then
+	  if test -n "$library_names" &&
+	     { { test no = "$prefer_static_libs" ||
+	         test built,yes = "$prefer_static_libs,$installed"; } ||
+	       test -z "$old_library"; }; then
+	    # We need to hardcode the library path
+	    if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then
+	      # Make sure the rpath contains only unique directories.
+	      case $temp_rpath: in
+	      *"$absdir:"*) ;;
+	      *) func_append temp_rpath "$absdir:" ;;
+	      esac
+	    fi
+
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi # $linkmode,$pass = prog,link...
+
+	  if $alldeplibs &&
+	     { test pass_all = "$deplibs_check_method" ||
+	       { test yes = "$build_libtool_libs" &&
+		 test -n "$library_names"; }; }; then
+	    # We only need to search for static libraries
+	    continue
+	  fi
+	fi
+
+	link_static=no # Whether the deplib will be linked statically
+	use_static_libs=$prefer_static_libs
+	if test built = "$use_static_libs" && test yes = "$installed"; then
+	  use_static_libs=no
+	fi
+	if test -n "$library_names" &&
+	   { test no = "$use_static_libs" || test -z "$old_library"; }; then
+	  case $host in
+	  *cygwin* | *mingw* | *cegcc* | *os2*)
+	      # No point in relinking DLLs because paths are not encoded
+	      func_append notinst_deplibs " $lib"
+	      need_relink=no
+	    ;;
+	  *)
+	    if test no = "$installed"; then
+	      func_append notinst_deplibs " $lib"
+	      need_relink=yes
+	    fi
+	    ;;
+	  esac
+	  # This is a shared library
+
+	  # Warn about portability, can't link against -module's on some
+	  # systems (darwin).  Don't bleat about dlopened modules though!
+	  dlopenmodule=
+	  for dlpremoduletest in $dlprefiles; do
+	    if test "X$dlpremoduletest" = "X$lib"; then
+	      dlopenmodule=$dlpremoduletest
+	      break
+	    fi
+	  done
+	  if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then
+	    echo
+	    if test prog = "$linkmode"; then
+	      $ECHO "*** Warning: Linking the executable $output against the loadable module"
+	    else
+	      $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+	    fi
+	    $ECHO "*** $linklib is not portable!"
+	  fi
+	  if test lib = "$linkmode" &&
+	     test yes = "$hardcode_into_libs"; then
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi
+
+	  if test -n "$old_archive_from_expsyms_cmds"; then
+	    # figure out the soname
+	    set dummy $library_names
+	    shift
+	    realname=$1
+	    shift
+	    libname=`eval "\\$ECHO \"$libname_spec\""`
+	    # use dlname if we got it. it's perfectly good, no?
+	    if test -n "$dlname"; then
+	      soname=$dlname
+	    elif test -n "$soname_spec"; then
+	      # bleh windows
+	      case $host in
+	      *cygwin* | mingw* | *cegcc* | *os2*)
+	        func_arith $current - $age
+		major=$func_arith_result
+		versuffix=-$major
+		;;
+	      esac
+	      eval soname=\"$soname_spec\"
+	    else
+	      soname=$realname
+	    fi
+
+	    # Make a new name for the extract_expsyms_cmds to use
+	    soroot=$soname
+	    func_basename "$soroot"
+	    soname=$func_basename_result
+	    func_stripname 'lib' '.dll' "$soname"
+	    newlib=libimp-$func_stripname_result.a
+
+	    # If the library has no export list, then create one now
+	    if test -f "$output_objdir/$soname-def"; then :
+	    else
+	      func_verbose "extracting exported symbol list from '$soname'"
+	      func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+	    fi
+
+	    # Create $newlib
+	    if test -f "$output_objdir/$newlib"; then :; else
+	      func_verbose "generating import library for '$soname'"
+	      func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+	    fi
+	    # make sure the library variables are pointing to the new library
+	    dir=$output_objdir
+	    linklib=$newlib
+	  fi # test -n "$old_archive_from_expsyms_cmds"
+
+	  if test prog = "$linkmode" || test relink != "$opt_mode"; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    lib_linked=yes
+	    case $hardcode_action in
+	    immediate | unsupported)
+	      if test no = "$hardcode_direct"; then
+		add=$dir/$linklib
+		case $host in
+		  *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;;
+		  *-*-sysv4*uw2*) add_dir=-L$dir ;;
+		  *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+		    *-*-unixware7*) add_dir=-L$dir ;;
+		  *-*-darwin* )
+		    # if the lib is a (non-dlopened) module then we cannot
+		    # link against it, someone is ignoring the earlier warnings
+		    if /usr/bin/file -L $add 2> /dev/null |
+			 $GREP ": [^:]* bundle" >/dev/null; then
+		      if test "X$dlopenmodule" != "X$lib"; then
+			$ECHO "*** Warning: lib $linklib is a module, not a shared library"
+			if test -z "$old_library"; then
+			  echo
+			  echo "*** And there doesn't seem to be a static archive available"
+			  echo "*** The link will probably fail, sorry"
+			else
+			  add=$dir/$old_library
+			fi
+		      elif test -n "$old_library"; then
+			add=$dir/$old_library
+		      fi
+		    fi
+		esac
+	      elif test no = "$hardcode_minus_L"; then
+		case $host in
+		*-*-sunos*) add_shlibpath=$dir ;;
+		esac
+		add_dir=-L$dir
+		add=-l$name
+	      elif test no = "$hardcode_shlibpath_var"; then
+		add_shlibpath=$dir
+		add=-l$name
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    relink)
+	      if test yes = "$hardcode_direct" &&
+	         test no = "$hardcode_direct_absolute"; then
+		add=$dir/$linklib
+	      elif test yes = "$hardcode_minus_L"; then
+		add_dir=-L$absdir
+		# Try looking first in the location we're being installed to.
+		if test -n "$inst_prefix_dir"; then
+		  case $libdir in
+		    [\\/]*)
+		      func_append add_dir " -L$inst_prefix_dir$libdir"
+		      ;;
+		  esac
+		fi
+		add=-l$name
+	      elif test yes = "$hardcode_shlibpath_var"; then
+		add_shlibpath=$dir
+		add=-l$name
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    *) lib_linked=no ;;
+	    esac
+
+	    if test yes != "$lib_linked"; then
+	      func_fatal_configuration "unsupported hardcode properties"
+	    fi
+
+	    if test -n "$add_shlibpath"; then
+	      case :$compile_shlibpath: in
+	      *":$add_shlibpath:"*) ;;
+	      *) func_append compile_shlibpath "$add_shlibpath:" ;;
+	      esac
+	    fi
+	    if test prog = "$linkmode"; then
+	      test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+	      test -n "$add" && compile_deplibs="$add $compile_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	      if test yes != "$hardcode_direct" &&
+		 test yes != "$hardcode_minus_L" &&
+		 test yes = "$hardcode_shlibpath_var"; then
+		case :$finalize_shlibpath: in
+		*":$libdir:"*) ;;
+		*) func_append finalize_shlibpath "$libdir:" ;;
+		esac
+	      fi
+	    fi
+	  fi
+
+	  if test prog = "$linkmode" || test relink = "$opt_mode"; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    # Finalize command for both is simple: just hardcode it.
+	    if test yes = "$hardcode_direct" &&
+	       test no = "$hardcode_direct_absolute"; then
+	      add=$libdir/$linklib
+	    elif test yes = "$hardcode_minus_L"; then
+	      add_dir=-L$libdir
+	      add=-l$name
+	    elif test yes = "$hardcode_shlibpath_var"; then
+	      case :$finalize_shlibpath: in
+	      *":$libdir:"*) ;;
+	      *) func_append finalize_shlibpath "$libdir:" ;;
+	      esac
+	      add=-l$name
+	    elif test yes = "$hardcode_automatic"; then
+	      if test -n "$inst_prefix_dir" &&
+		 test -f "$inst_prefix_dir$libdir/$linklib"; then
+		add=$inst_prefix_dir$libdir/$linklib
+	      else
+		add=$libdir/$linklib
+	      fi
+	    else
+	      # We cannot seem to hardcode it, guess we'll fake it.
+	      add_dir=-L$libdir
+	      # Try looking first in the location we're being installed to.
+	      if test -n "$inst_prefix_dir"; then
+		case $libdir in
+		  [\\/]*)
+		    func_append add_dir " -L$inst_prefix_dir$libdir"
+		    ;;
+		esac
+	      fi
+	      add=-l$name
+	    fi
+
+	    if test prog = "$linkmode"; then
+	      test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+	      test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	    fi
+	  fi
+	elif test prog = "$linkmode"; then
+	  # Here we assume that one of hardcode_direct or hardcode_minus_L
+	  # is not unsupported.  This is valid on all known static and
+	  # shared platforms.
+	  if test unsupported != "$hardcode_direct"; then
+	    test -n "$old_library" && linklib=$old_library
+	    compile_deplibs="$dir/$linklib $compile_deplibs"
+	    finalize_deplibs="$dir/$linklib $finalize_deplibs"
+	  else
+	    compile_deplibs="-l$name -L$dir $compile_deplibs"
+	    finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+	  fi
+	elif test yes = "$build_libtool_libs"; then
+	  # Not a shared library
+	  if test pass_all != "$deplibs_check_method"; then
+	    # We're trying link a shared library against a static one
+	    # but the system doesn't support it.
+
+	    # Just print a warning and add the library to dependency_libs so
+	    # that the program can be linked against the static library.
+	    echo
+	    $ECHO "*** Warning: This system cannot link to static lib archive $lib."
+	    echo "*** I have the capability to make that library automatically link in when"
+	    echo "*** you link to this library.  But I can only do this if you have a"
+	    echo "*** shared version of the library, which you do not appear to have."
+	    if test yes = "$module"; then
+	      echo "*** But as you try to build a module library, libtool will still create "
+	      echo "*** a static module, that should work as long as the dlopening application"
+	      echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+	      if test -z "$global_symbol_pipe"; then
+		echo
+		echo "*** However, this would only work if libtool was able to extract symbol"
+		echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
+		echo "*** not find such a program.  So, this module is probably useless."
+		echo "*** 'nm' from GNU binutils and a full rebuild may help."
+	      fi
+	      if test no = "$build_old_libs"; then
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  else
+	    deplibs="$dir/$old_library $deplibs"
+	    link_static=yes
+	  fi
+	fi # link shared/static library?
+
+	if test lib = "$linkmode"; then
+	  if test -n "$dependency_libs" &&
+	     { test yes != "$hardcode_into_libs" ||
+	       test yes = "$build_old_libs" ||
+	       test yes = "$link_static"; }; then
+	    # Extract -R from dependency_libs
+	    temp_deplibs=
+	    for libdir in $dependency_libs; do
+	      case $libdir in
+	      -R*) func_stripname '-R' '' "$libdir"
+	           temp_xrpath=$func_stripname_result
+		   case " $xrpath " in
+		   *" $temp_xrpath "*) ;;
+		   *) func_append xrpath " $temp_xrpath";;
+		   esac;;
+	      *) func_append temp_deplibs " $libdir";;
+	      esac
+	    done
+	    dependency_libs=$temp_deplibs
+	  fi
+
+	  func_append newlib_search_path " $absdir"
+	  # Link against this library
+	  test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+	  # ... and its dependency_libs
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    newdependency_libs="$deplib $newdependency_libs"
+	    case $deplib in
+              -L*) func_stripname '-L' '' "$deplib"
+                   func_resolve_sysroot "$func_stripname_result";;
+              *) func_resolve_sysroot "$deplib" ;;
+            esac
+	    if $opt_preserve_dup_deps; then
+	      case "$tmp_libs " in
+	      *" $func_resolve_sysroot_result "*)
+                func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $func_resolve_sysroot_result"
+	  done
+
+	  if test no != "$link_all_deplibs"; then
+	    # Add the search paths of all dependency libraries
+	    for deplib in $dependency_libs; do
+	      path=
+	      case $deplib in
+	      -L*) path=$deplib ;;
+	      *.la)
+	        func_resolve_sysroot "$deplib"
+	        deplib=$func_resolve_sysroot_result
+	        func_dirname "$deplib" "" "."
+		dir=$func_dirname_result
+		# We need an absolute path.
+		case $dir in
+		[\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;;
+		*)
+		  absdir=`cd "$dir" && pwd`
+		  if test -z "$absdir"; then
+		    func_warning "cannot determine absolute directory name of '$dir'"
+		    absdir=$dir
+		  fi
+		  ;;
+		esac
+		if $GREP "^installed=no" $deplib > /dev/null; then
+		case $host in
+		*-*-darwin*)
+		  depdepl=
+		  eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+		  if test -n "$deplibrary_names"; then
+		    for tmp in $deplibrary_names; do
+		      depdepl=$tmp
+		    done
+		    if test -f "$absdir/$objdir/$depdepl"; then
+		      depdepl=$absdir/$objdir/$depdepl
+		      darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+                      if test -z "$darwin_install_name"; then
+                          darwin_install_name=`$OTOOL64 -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
+                      fi
+		      func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl"
+		      func_append linker_flags " -dylib_file $darwin_install_name:$depdepl"
+		      path=
+		    fi
+		  fi
+		  ;;
+		*)
+		  path=-L$absdir/$objdir
+		  ;;
+		esac
+		else
+		  eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  test -z "$libdir" && \
+		    func_fatal_error "'$deplib' is not a valid libtool archive"
+		  test "$absdir" != "$libdir" && \
+		    func_warning "'$deplib' seems to be moved"
+
+		  path=-L$absdir
+		fi
+		;;
+	      esac
+	      case " $deplibs " in
+	      *" $path "*) ;;
+	      *) deplibs="$path $deplibs" ;;
+	      esac
+	    done
+	  fi # link_all_deplibs != no
+	fi # linkmode = lib
+      done # for deplib in $libs
+      if test link = "$pass"; then
+	if test prog = "$linkmode"; then
+	  compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+	  finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+	else
+	  compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	fi
+      fi
+      dependency_libs=$newdependency_libs
+      if test dlpreopen = "$pass"; then
+	# Link the dlpreopened libraries before other libraries
+	for deplib in $save_deplibs; do
+	  deplibs="$deplib $deplibs"
+	done
+      fi
+      if test dlopen != "$pass"; then
+	test conv = "$pass" || {
+	  # Make sure lib_search_path contains only unique directories.
+	  lib_search_path=
+	  for dir in $newlib_search_path; do
+	    case "$lib_search_path " in
+	    *" $dir "*) ;;
+	    *) func_append lib_search_path " $dir" ;;
+	    esac
+	  done
+	  newlib_search_path=
+	}
+
+	if test prog,link = "$linkmode,$pass"; then
+	  vars="compile_deplibs finalize_deplibs"
+	else
+	  vars=deplibs
+	fi
+	for var in $vars dependency_libs; do
+	  # Add libraries to $var in reverse order
+	  eval tmp_libs=\"\$$var\"
+	  new_libs=
+	  for deplib in $tmp_libs; do
+	    # FIXME: Pedantically, this is the right thing to do, so
+	    #        that some nasty dependency loop isn't accidentally
+	    #        broken:
+	    #new_libs="$deplib $new_libs"
+	    # Pragmatically, this seems to cause very few problems in
+	    # practice:
+	    case $deplib in
+	    -L*) new_libs="$deplib $new_libs" ;;
+	    -R*) ;;
+	    *)
+	      # And here is the reason: when a library appears more
+	      # than once as an explicit dependence of a library, or
+	      # is implicitly linked in more than once by the
+	      # compiler, it is considered special, and multiple
+	      # occurrences thereof are not removed.  Compare this
+	      # with having the same library being listed as a
+	      # dependency of multiple other libraries: in this case,
+	      # we know (pedantically, we assume) the library does not
+	      # need to be listed more than once, so we keep only the
+	      # last copy.  This is not always right, but it is rare
+	      # enough that we require users that really mean to play
+	      # such unportable linking tricks to link the library
+	      # using -Wl,-lname, so that libtool does not consider it
+	      # for duplicate removal.
+	      case " $specialdeplibs " in
+	      *" $deplib "*) new_libs="$deplib $new_libs" ;;
+	      *)
+		case " $new_libs " in
+		*" $deplib "*) ;;
+		*) new_libs="$deplib $new_libs" ;;
+		esac
+		;;
+	      esac
+	      ;;
+	    esac
+	  done
+	  tmp_libs=
+	  for deplib in $new_libs; do
+	    case $deplib in
+	    -L*)
+	      case " $tmp_libs " in
+	      *" $deplib "*) ;;
+	      *) func_append tmp_libs " $deplib" ;;
+	      esac
+	      ;;
+	    *) func_append tmp_libs " $deplib" ;;
+	    esac
+	  done
+	  eval $var=\"$tmp_libs\"
+	done # for var
+      fi
+
+      # Add Sun CC postdeps if required:
+      test CXX = "$tagname" && {
+        case $host_os in
+        linux*)
+          case `$CC -V 2>&1 | sed 5q` in
+          *Sun\ C*) # Sun C++ 5.9
+            func_suncc_cstd_abi
+
+            if test no != "$suncc_use_cstd_abi"; then
+              func_append postdeps ' -library=Cstd -library=Crun'
+            fi
+            ;;
+          esac
+          ;;
+
+        solaris*)
+          func_cc_basename "$CC"
+          case $func_cc_basename_result in
+          CC* | sunCC*)
+            func_suncc_cstd_abi
+
+            if test no != "$suncc_use_cstd_abi"; then
+              func_append postdeps ' -library=Cstd -library=Crun'
+            fi
+            ;;
+          esac
+          ;;
+        esac
+      }
+
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs; do
+	case " $predeps $postdeps $compiler_lib_search_path " in
+	*" $i "*)
+	  i=
+	  ;;
+	esac
+	if test -n "$i"; then
+	  func_append tmp_libs " $i"
+	fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test prog = "$linkmode"; then
+      dlfiles=$newdlfiles
+    fi
+    if test prog = "$linkmode" || test lib = "$linkmode"; then
+      dlprefiles=$newdlprefiles
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+	func_warning "'-dlopen' is ignored for archives"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "'-l' and '-L' are ignored for archives" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "'-rpath' is ignored for archives"
+
+      test -n "$xrpath" && \
+	func_warning "'-R' is ignored for archives"
+
+      test -n "$vinfo" && \
+	func_warning "'-version-info/-version-number' is ignored for archives"
+
+      test -n "$release" && \
+	func_warning "'-release' is ignored for archives"
+
+      test -n "$export_symbols$export_symbols_regex" && \
+	func_warning "'-export-symbols' is ignored for archives"
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs=$output
+      func_append objs "$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form 'libNAME.la'.
+      case $outputname in
+      lib*)
+	func_stripname 'lib' '.la' "$outputname"
+	name=$func_stripname_result
+	eval shared_ext=\"$shrext_cmds\"
+	eval libname=\"$libname_spec\"
+	;;
+      *)
+	test no = "$module" \
+	  && func_fatal_help "libtool library '$output' must begin with 'lib'"
+
+	if test no != "$need_lib_prefix"; then
+	  # Add the "lib" prefix for modules if required
+	  func_stripname '' '.la' "$outputname"
+	  name=$func_stripname_result
+	  eval shared_ext=\"$shrext_cmds\"
+	  eval libname=\"$libname_spec\"
+	else
+	  func_stripname '' '.la' "$outputname"
+	  libname=$func_stripname_result
+	fi
+	;;
+      esac
+
+      if test -n "$objs"; then
+	if test pass_all != "$deplibs_check_method"; then
+	  func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs"
+	else
+	  echo
+	  $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+	  $ECHO "*** objects $objs is not portable!"
+	  func_append libobjs " $objs"
+	fi
+      fi
+
+      test no = "$dlself" \
+	|| func_warning "'-dlopen self' is ignored for libtool libraries"
+
+      set dummy $rpath
+      shift
+      test 1 -lt "$#" \
+	&& func_warning "ignoring multiple '-rpath's for a libtool library"
+
+      install_libdir=$1
+
+      oldlibs=
+      if test -z "$rpath"; then
+	if test yes = "$build_libtool_libs"; then
+	  # Building a libtool convenience library.
+	  # Some compilers have problems with a '.al' extension so
+	  # convenience libraries should have the same extension an
+	  # archive normally would.
+	  oldlibs="$output_objdir/$libname.$libext $oldlibs"
+	  build_libtool_libs=convenience
+	  build_old_libs=yes
+	fi
+
+	test -n "$vinfo" && \
+	  func_warning "'-version-info/-version-number' is ignored for convenience libraries"
+
+	test -n "$release" && \
+	  func_warning "'-release' is ignored for convenience libraries"
+      else
+
+	# Parse the version information argument.
+	save_ifs=$IFS; IFS=:
+	set dummy $vinfo 0 0 0
+	shift
+	IFS=$save_ifs
+
+	test -n "$7" && \
+	  func_fatal_help "too many parameters to '-version-info'"
+
+	# convert absolute version numbers to libtool ages
+	# this retains compatibility with .la files and attempts
+	# to make the code below a bit more comprehensible
+
+	case $vinfo_number in
+	yes)
+	  number_major=$1
+	  number_minor=$2
+	  number_revision=$3
+	  #
+	  # There are really only two kinds -- those that
+	  # use the current revision as the major version
+	  # and those that subtract age and use age as
+	  # a minor version.  But, then there is irix
+	  # that has an extra 1 added just for fun
+	  #
+	  case $version_type in
+	  # correct linux to gnu/linux during the next big refactor
+	  darwin|freebsd-elf|linux|osf|windows|none)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age=$number_minor
+	    revision=$number_revision
+	    ;;
+	  freebsd-aout|qnx|sunos)
+	    current=$number_major
+	    revision=$number_minor
+	    age=0
+	    ;;
+	  irix|nonstopux)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age=$number_minor
+	    revision=$number_minor
+	    lt_irix_increment=no
+	    ;;
+	  *)
+	    func_fatal_configuration "$modename: unknown library version type '$version_type'"
+	    ;;
+	  esac
+	  ;;
+	no)
+	  current=$1
+	  revision=$2
+	  age=$3
+	  ;;
+	esac
+
+	# Check that each of the things are valid numbers.
+	case $current in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "CURRENT '$current' must be a nonnegative integer"
+	  func_fatal_error "'$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $revision in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "REVISION '$revision' must be a nonnegative integer"
+	  func_fatal_error "'$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $age in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "AGE '$age' must be a nonnegative integer"
+	  func_fatal_error "'$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	if test "$age" -gt "$current"; then
+	  func_error "AGE '$age' is greater than the current interface number '$current'"
+	  func_fatal_error "'$vinfo' is not valid version information"
+	fi
+
+	# Calculate the version variables.
+	major=
+	versuffix=
+	verstring=
+	case $version_type in
+	none) ;;
+
+	darwin)
+	  # Like Linux, but with the current version available in
+	  # verstring for coding it into the library header
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=$major.$age.$revision
+	  # Darwin ld doesn't like 0 for these options...
+	  func_arith $current + 1
+	  minor_current=$func_arith_result
+	  xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+          # On Darwin other compilers
+          case $CC in
+              nagfor*)
+                  verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+                  ;;
+              *)
+                  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+                  ;;
+          esac
+	  ;;
+
+	freebsd-aout)
+	  major=.$current
+	  versuffix=.$current.$revision
+	  ;;
+
+	freebsd-elf)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=$major.$age.$revision
+	  ;;
+
+	irix | nonstopux)
+	  if test no = "$lt_irix_increment"; then
+	    func_arith $current - $age
+	  else
+	    func_arith $current - $age + 1
+	  fi
+	  major=$func_arith_result
+
+	  case $version_type in
+	    nonstopux) verstring_prefix=nonstopux ;;
+	    *)         verstring_prefix=sgi ;;
+	  esac
+	  verstring=$verstring_prefix$major.$revision
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$revision
+	  while test 0 -ne "$loop"; do
+	    func_arith $revision - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring=$verstring_prefix$major.$iface:$verstring
+	  done
+
+	  # Before this point, $major must not contain '.'.
+	  major=.$major
+	  versuffix=$major.$revision
+	  ;;
+
+	linux) # correct to gnu/linux during the next big refactor
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=$major.$age.$revision
+	  ;;
+
+	osf)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=.$current.$age.$revision
+	  verstring=$current.$age.$revision
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$age
+	  while test 0 -ne "$loop"; do
+	    func_arith $current - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring=$verstring:$iface.0
+	  done
+
+	  # Make executables depend on our current version.
+	  func_append verstring ":$current.0"
+	  ;;
+
+	qnx)
+	  major=.$current
+	  versuffix=.$current
+	  ;;
+
+	sco)
+	  major=.$current
+	  versuffix=.$current
+	  ;;
+
+	sunos)
+	  major=.$current
+	  versuffix=.$current.$revision
+	  ;;
+
+	windows)
+	  # Use '-' rather than '.', since we only want one
+	  # extension on DOS 8.3 file systems.
+	  func_arith $current - $age
+	  major=$func_arith_result
+	  versuffix=-$major
+	  ;;
+
+	*)
+	  func_fatal_configuration "unknown library version type '$version_type'"
+	  ;;
+	esac
+
+	# Clear the version info if we defaulted, and they specified a release.
+	if test -z "$vinfo" && test -n "$release"; then
+	  major=
+	  case $version_type in
+	  darwin)
+	    # we can't check for "0.0" in archive_cmds due to quoting
+	    # problems, so we reset it completely
+	    verstring=
+	    ;;
+	  *)
+	    verstring=0.0
+	    ;;
+	  esac
+	  if test no = "$need_version"; then
+	    versuffix=
+	  else
+	    versuffix=.0.0
+	  fi
+	fi
+
+	# Remove version info from name if versioning should be avoided
+	if test yes,no = "$avoid_version,$need_version"; then
+	  major=
+	  versuffix=
+	  verstring=
+	fi
+
+	# Check to see if the archive will have undefined symbols.
+	if test yes = "$allow_undefined"; then
+	  if test unsupported = "$allow_undefined_flag"; then
+	    if test yes = "$build_old_libs"; then
+	      func_warning "undefined symbols not allowed in $host shared libraries; building static only"
+	      build_libtool_libs=no
+	    else
+	      func_fatal_error "can't build $host shared library unless -no-undefined is specified"
+	    fi
+	  fi
+	else
+	  # Don't allow undefined symbols.
+	  allow_undefined_flag=$no_undefined_flag
+	fi
+
+      fi
+
+      func_generate_dlsyms "$libname" "$libname" :
+      func_append libobjs " $symfileobj"
+      test " " = "$libobjs" && libobjs=
+
+      if test relink != "$opt_mode"; then
+	# Remove our outputs, but don't remove object files since they
+	# may have been created when compiling PIC objects.
+	removelist=
+	tempremovelist=`$ECHO "$output_objdir/*"`
+	for p in $tempremovelist; do
+	  case $p in
+	    *.$objext | *.gcno)
+	       ;;
+	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*)
+	       if test -n "$precious_files_regex"; then
+		 if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+		 then
+		   continue
+		 fi
+	       fi
+	       func_append removelist " $p"
+	       ;;
+	    *) ;;
+	  esac
+	done
+	test -n "$removelist" && \
+	  func_show_eval "${RM}r \$removelist"
+      fi
+
+      # Now set the variables for building old libraries.
+      if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then
+	func_append oldlibs " $output_objdir/$libname.$libext"
+
+	# Transform .lo files to .o files.
+	oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #	lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+      #	deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+      #	dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+      #done
+
+      if test -n "$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	temp_xrpath=
+	for libdir in $xrpath; do
+	  func_replace_sysroot "$libdir"
+	  func_append temp_xrpath " -R$func_replace_sysroot_result"
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+	if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then
+	  dependency_libs="$temp_xrpath $dependency_libs"
+	fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles=$dlfiles
+      dlfiles=
+      for lib in $old_dlfiles; do
+	case " $dlprefiles $dlfiles " in
+	*" $lib "*) ;;
+	*) func_append dlfiles " $lib" ;;
+	esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles=$dlprefiles
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+	case "$dlprefiles " in
+	*" $lib "*) ;;
+	*) func_append dlprefiles " $lib" ;;
+	esac
+      done
+
+      if test yes = "$build_libtool_libs"; then
+	if test -n "$rpath"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # these systems don't actually have a c library (as such)!
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C library is in the System framework
+	    func_append deplibs " System.ltframework"
+	    ;;
+	  *-*-netbsd*)
+	    # Don't link with libc until the a.out ld.so is fixed.
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    ;;
+	  *)
+	    # Add libc to deplibs on all other systems if necessary.
+	    if test yes = "$build_libtool_need_lc"; then
+	      func_append deplibs " -lc"
+	    fi
+	    ;;
+	  esac
+	fi
+
+	# Transform deplibs into only deplibs that can be linked in shared.
+	name_save=$name
+	libname_save=$libname
+	release_save=$release
+	versuffix_save=$versuffix
+	major_save=$major
+	# I'm not sure if I'm treating the release correctly.  I think
+	# release should show up in the -l (ie -lgmp5) so we don't want to
+	# add it in twice.  Is that correct?
+	release=
+	versuffix=
+	major=
+	newdeplibs=
+	droppeddeps=no
+	case $deplibs_check_method in
+	pass_all)
+	  # Don't check for shared/static.  Everything works.
+	  # This might be a little naive.  We might want to check
+	  # whether the library exists or not.  But this is on
+	  # osf3 & osf4 and I'm not really sure... Just
+	  # implementing what was already the behavior.
+	  newdeplibs=$deplibs
+	  ;;
+	test_compile)
+	  # This code stresses the "libraries are programs" paradigm to its
+	  # limits. Maybe even breaks it.  We compile a program, linking it
+	  # against the deplibs as a proxy for the library.  Then we can check
+	  # whether they linked in statically or dynamically with ldd.
+	  $opt_dry_run || $RM conftest.c
+	  cat > conftest.c <<EOF
+	  int main() { return 0; }
+EOF
+	  $opt_dry_run || $RM conftest
+	  if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+	    ldd_output=`ldd conftest`
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+		  case " $predeps $postdeps " in
+		  *" $i "*)
+		    func_append newdeplibs " $i"
+		    i=
+		    ;;
+		  esac
+		fi
+		if test -n "$i"; then
+		  libname=`eval "\\$ECHO \"$libname_spec\""`
+		  deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		  set dummy $deplib_matches; shift
+		  deplib_match=$1
+		  if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
+		    func_append newdeplibs " $i"
+		  else
+		    droppeddeps=yes
+		    echo
+		    $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		    echo "*** I have the capability to make that library automatically link in when"
+		    echo "*** you link to this library.  But I can only do this if you have a"
+		    echo "*** shared version of the library, which I believe you do not have"
+		    echo "*** because a test_compile did reveal that the linker did not use it for"
+		    echo "*** its dynamic dependency list that programs get resolved with at runtime."
+		  fi
+		fi
+		;;
+	      *)
+		func_append newdeplibs " $i"
+		;;
+	      esac
+	    done
+	  else
+	    # Error occurred in the first compile.  Let's try to salvage
+	    # the situation: Compile a separate program for each library.
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		$opt_dry_run || $RM conftest
+		if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+		  ldd_output=`ldd conftest`
+		  if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+		    case " $predeps $postdeps " in
+		    *" $i "*)
+		      func_append newdeplibs " $i"
+		      i=
+		      ;;
+		    esac
+		  fi
+		  if test -n "$i"; then
+		    libname=`eval "\\$ECHO \"$libname_spec\""`
+		    deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		    set dummy $deplib_matches; shift
+		    deplib_match=$1
+		    if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
+		      func_append newdeplibs " $i"
+		    else
+		      droppeddeps=yes
+		      echo
+		      $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		      echo "*** I have the capability to make that library automatically link in when"
+		      echo "*** you link to this library.  But I can only do this if you have a"
+		      echo "*** shared version of the library, which you do not appear to have"
+		      echo "*** because a test_compile did reveal that the linker did not use this one"
+		      echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+		    fi
+		  fi
+		else
+		  droppeddeps=yes
+		  echo
+		  $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
+		  echo "*** make it link in!  You will probably need to install it or some"
+		  echo "*** library that it depends on before this library will be fully"
+		  echo "*** functional.  Installing it before continuing would be even better."
+		fi
+		;;
+	      *)
+		func_append newdeplibs " $i"
+		;;
+	      esac
+	    done
+	  fi
+	  ;;
+	file_magic*)
+	  set dummy $deplibs_check_method; shift
+	  file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib"; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		if test -n "$file_magic_glob"; then
+		  libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+		else
+		  libnameglob=$libname
+		fi
+		test yes = "$want_nocaseglob" && nocaseglob=`shopt -p nocaseglob`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  if test yes = "$want_nocaseglob"; then
+		    shopt -s nocaseglob
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		    $nocaseglob
+		  else
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		  fi
+		  for potent_lib in $potential_libs; do
+		      # Follow soft links.
+		      if ls -lLd "$potent_lib" 2>/dev/null |
+			 $GREP " -> " >/dev/null; then
+			continue
+		      fi
+		      # The statement above tries to avoid entering an
+		      # endless loop below, in case of cyclic links.
+		      # We might still enter an endless loop, since a link
+		      # loop can be closed while we follow links,
+		      # but so what?
+		      potlib=$potent_lib
+		      while test -h "$potlib" 2>/dev/null; do
+			potliblink=`ls -ld $potlib | $SED 's/.* -> //'`
+			case $potliblink in
+			[\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;;
+			*) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";;
+			esac
+		      done
+		      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+			 $SED -e 10q |
+			 $EGREP "$file_magic_regex" > /dev/null; then
+			func_append newdeplibs " $a_deplib"
+			a_deplib=
+			break 2
+		      fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib"; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib"; then
+		  $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a file magic. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	match_pattern*)
+	  set dummy $deplibs_check_method; shift
+	  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib"; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		    potlib=$potent_lib # see symlink-check above in file_magic test
+		    if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+		       $EGREP "$match_pattern_regex" > /dev/null; then
+		      func_append newdeplibs " $a_deplib"
+		      a_deplib=
+		      break 2
+		    fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib"; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib"; then
+		  $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a regex pattern. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	none | unknown | *)
+	  newdeplibs=
+	  tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+	  if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+	    for i in $predeps $postdeps; do
+	      # can't use Xsed below, because $i might contain '/'
+	      tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"`
+	    done
+	  fi
+	  case $tmp_deplibs in
+	  *[!\	\ ]*)
+	    echo
+	    if test none = "$deplibs_check_method"; then
+	      echo "*** Warning: inter-library dependencies are not supported in this platform."
+	    else
+	      echo "*** Warning: inter-library dependencies are not known to be supported."
+	    fi
+	    echo "*** All declared inter-library dependencies are being dropped."
+	    droppeddeps=yes
+	    ;;
+	  esac
+	  ;;
+	esac
+	versuffix=$versuffix_save
+	major=$major_save
+	release=$release_save
+	libname=$libname_save
+	name=$name_save
+
+	case $host in
+	*-*-rhapsody* | *-*-darwin1.[012])
+	  # On Rhapsody replace the C library with the System framework
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+	  ;;
+	esac
+
+	if test yes = "$droppeddeps"; then
+	  if test yes = "$module"; then
+	    echo
+	    echo "*** Warning: libtool could not satisfy all declared inter-library"
+	    $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
+	    echo "*** a static module, that should work as long as the dlopening"
+	    echo "*** application is linked with the -dlopen flag."
+	    if test -z "$global_symbol_pipe"; then
+	      echo
+	      echo "*** However, this would only work if libtool was able to extract symbol"
+	      echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
+	      echo "*** not find such a program.  So, this module is probably useless."
+	      echo "*** 'nm' from GNU binutils and a full rebuild may help."
+	    fi
+	    if test no = "$build_old_libs"; then
+	      oldlibs=$output_objdir/$libname.$libext
+	      build_libtool_libs=module
+	      build_old_libs=yes
+	    else
+	      build_libtool_libs=no
+	    fi
+	  else
+	    echo "*** The inter-library dependencies that have been dropped here will be"
+	    echo "*** automatically added whenever a program is linked with this library"
+	    echo "*** or is declared to -dlopen it."
+
+	    if test no = "$allow_undefined"; then
+	      echo
+	      echo "*** Since this library must not contain undefined symbols,"
+	      echo "*** because either the platform does not support them or"
+	      echo "*** it was explicitly requested with -no-undefined,"
+	      echo "*** libtool will only create a static version of it."
+	      if test no = "$build_old_libs"; then
+		oldlibs=$output_objdir/$libname.$libext
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  fi
+	fi
+	# Done checking deplibs!
+	deplibs=$newdeplibs
+      fi
+      # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+      case $host in
+	*-*-darwin*)
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  ;;
+      esac
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      deplibs=$new_libs
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test yes = "$build_libtool_libs"; then
+	# Remove $wl instances when linking with ld.
+	# FIXME: should test the right _cmds variable.
+	case $archive_cmds in
+	  *\$LD\ *) wl= ;;
+        esac
+	if test yes = "$hardcode_into_libs"; then
+	  # Hardcode the library paths
+	  hardcode_libdirs=
+	  dep_rpath=
+	  rpath=$finalize_rpath
+	  test relink = "$opt_mode" || rpath=$compile_rpath$rpath
+	  for libdir in $rpath; do
+	    if test -n "$hardcode_libdir_flag_spec"; then
+	      if test -n "$hardcode_libdir_separator"; then
+		func_replace_sysroot "$libdir"
+		libdir=$func_replace_sysroot_result
+		if test -z "$hardcode_libdirs"; then
+		  hardcode_libdirs=$libdir
+		else
+		  # Just accumulate the unique libdirs.
+		  case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+		  *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		    ;;
+		  *)
+		    func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		    ;;
+		  esac
+		fi
+	      else
+		eval flag=\"$hardcode_libdir_flag_spec\"
+		func_append dep_rpath " $flag"
+	      fi
+	    elif test -n "$runpath_var"; then
+	      case "$perm_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append perm_rpath " $libdir" ;;
+	      esac
+	    fi
+	  done
+	  # Substitute the hardcoded libdirs into the rpath.
+	  if test -n "$hardcode_libdir_separator" &&
+	     test -n "$hardcode_libdirs"; then
+	    libdir=$hardcode_libdirs
+	    eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+	  fi
+	  if test -n "$runpath_var" && test -n "$perm_rpath"; then
+	    # We should set the runpath_var.
+	    rpath=
+	    for dir in $perm_rpath; do
+	      func_append rpath "$dir:"
+	    done
+	    eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+	  fi
+	  test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+	fi
+
+	shlibpath=$finalize_shlibpath
+	test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath
+	if test -n "$shlibpath"; then
+	  eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+	fi
+
+	# Get the real and link names of the library.
+	eval shared_ext=\"$shrext_cmds\"
+	eval library_names=\"$library_names_spec\"
+	set dummy $library_names
+	shift
+	realname=$1
+	shift
+
+	if test -n "$soname_spec"; then
+	  eval soname=\"$soname_spec\"
+	else
+	  soname=$realname
+	fi
+	if test -z "$dlname"; then
+	  dlname=$soname
+	fi
+
+	lib=$output_objdir/$realname
+	linknames=
+	for link
+	do
+	  func_append linknames " $link"
+	done
+
+	# Use standard objects if they are pic
+	test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	test "X$libobjs" = "X " && libobjs=
+
+	delfiles=
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+	  export_symbols=$output_objdir/$libname.uexp
+	  func_append delfiles " $export_symbols"
+	fi
+
+	orig_export_symbols=
+	case $host_os in
+	cygwin* | mingw* | cegcc*)
+	  if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+	    # exporting using user supplied symfile
+	    func_dll_def_p "$export_symbols" || {
+	      # and it's NOT already a .def file. Must figure out
+	      # which of the given symbols are data symbols and tag
+	      # them as such. So, trigger use of export_symbols_cmds.
+	      # export_symbols gets reassigned inside the "prepare
+	      # the list of exported symbols" if statement, so the
+	      # include_expsyms logic still works.
+	      orig_export_symbols=$export_symbols
+	      export_symbols=
+	      always_export_symbols=yes
+	    }
+	  fi
+	  ;;
+	esac
+
+	# Prepare the list of exported symbols
+	if test -z "$export_symbols"; then
+	  if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then
+	    func_verbose "generating symbol list for '$libname.la'"
+	    export_symbols=$output_objdir/$libname.exp
+	    $opt_dry_run || $RM $export_symbols
+	    cmds=$export_symbols_cmds
+	    save_ifs=$IFS; IFS='~'
+	    for cmd1 in $cmds; do
+	      IFS=$save_ifs
+	      # Take the normal branch if the nm_file_list_spec branch
+	      # doesn't work or if tool conversion is not needed.
+	      case $nm_file_list_spec~$to_tool_file_cmd in
+		*~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+		  try_normal_branch=yes
+		  eval cmd=\"$cmd1\"
+		  func_len " $cmd"
+		  len=$func_len_result
+		  ;;
+		*)
+		  try_normal_branch=no
+		  ;;
+	      esac
+	      if test yes = "$try_normal_branch" \
+		 && { test "$len" -lt "$max_cmd_len" \
+		      || test "$max_cmd_len" -le -1; }
+	      then
+		func_show_eval "$cmd" 'exit $?'
+		skipped_export=false
+	      elif test -n "$nm_file_list_spec"; then
+		func_basename "$output"
+		output_la=$func_basename_result
+		save_libobjs=$libobjs
+		save_output=$output
+		output=$output_objdir/$output_la.nm
+		func_to_tool_file "$output"
+		libobjs=$nm_file_list_spec$func_to_tool_file_result
+		func_append delfiles " $output"
+		func_verbose "creating $NM input file list: $output"
+		for obj in $save_libobjs; do
+		  func_to_tool_file "$obj"
+		  $ECHO "$func_to_tool_file_result"
+		done > "$output"
+		eval cmd=\"$cmd1\"
+		func_show_eval "$cmd" 'exit $?'
+		output=$save_output
+		libobjs=$save_libobjs
+		skipped_export=false
+	      else
+		# The command line is too long to execute in one step.
+		func_verbose "using reloadable object file for export list..."
+		skipped_export=:
+		# Break out early, otherwise skipped_export may be
+		# set to false by a later but shorter cmd.
+		break
+	      fi
+	    done
+	    IFS=$save_ifs
+	    if test -n "$export_symbols_regex" && test : != "$skipped_export"; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+	fi
+
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  tmp_export_symbols=$export_symbols
+	  test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
+	  $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	fi
+
+	if test : != "$skipped_export" && test -n "$orig_export_symbols"; then
+	  # The given exports_symbols file has to be filtered, so filter it.
+	  func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
+	  # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	  # 's' commands, which not all seds can handle. GNU sed should be fine
+	  # though. Also, the filter scales superlinearly with the number of
+	  # global variables. join(1) would be nice here, but unfortunately
+	  # isn't a blessed tool.
+	  $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	  func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	  export_symbols=$output_objdir/$libname.def
+	  $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	fi
+
+	tmp_deplibs=
+	for test_deplib in $deplibs; do
+	  case " $convenience " in
+	  *" $test_deplib "*) ;;
+	  *)
+	    func_append tmp_deplibs " $test_deplib"
+	    ;;
+	  esac
+	done
+	deplibs=$tmp_deplibs
+
+	if test -n "$convenience"; then
+	  if test -n "$whole_archive_flag_spec" &&
+	    test yes = "$compiler_needs_object" &&
+	    test -z "$libobjs"; then
+	    # extract the archives, so we have objects to list.
+	    # TODO: could optimize this to just extract one archive.
+	    whole_archive_flag_spec=
+	  fi
+	  if test -n "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  else
+	    gentop=$output_objdir/${outputname}x
+	    func_append generated " $gentop"
+
+	    func_extract_archives $gentop $convenience
+	    func_append libobjs " $func_extract_archives_result"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	fi
+
+	if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then
+	  eval flag=\"$thread_safe_flag_spec\"
+	  func_append linker_flags " $flag"
+	fi
+
+	# Make a backup of the uninstalled library when relinking
+	if test relink = "$opt_mode"; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+	fi
+
+	# Do each of the archive commands.
+	if test yes = "$module" && test -n "$module_cmds"; then
+	  if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	    eval test_cmds=\"$module_expsym_cmds\"
+	    cmds=$module_expsym_cmds
+	  else
+	    eval test_cmds=\"$module_cmds\"
+	    cmds=$module_cmds
+	  fi
+	else
+	  if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	    eval test_cmds=\"$archive_expsym_cmds\"
+	    cmds=$archive_expsym_cmds
+	  else
+	    eval test_cmds=\"$archive_cmds\"
+	    cmds=$archive_cmds
+	  fi
+	fi
+
+	if test : != "$skipped_export" &&
+	   func_len " $test_cmds" &&
+	   len=$func_len_result &&
+	   test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  :
+	else
+	  # The command line is too long to link in one step, link piecewise
+	  # or, if using GNU ld and skipped_export is not :, use a linker
+	  # script.
+
+	  # Save the value of $output and $libobjs because we want to
+	  # use them later.  If we have whole_archive_flag_spec, we
+	  # want to use save_libobjs as it was before
+	  # whole_archive_flag_spec was expanded, because we can't
+	  # assume the linker understands whole_archive_flag_spec.
+	  # This may have to be revisited, in case too many
+	  # convenience libraries get linked in and end up exceeding
+	  # the spec.
+	  if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	  fi
+	  save_output=$output
+	  func_basename "$output"
+	  output_la=$func_basename_result
+
+	  # Clear the reloadable object creation command queue and
+	  # initialize k to one.
+	  test_cmds=
+	  concat_cmds=
+	  objlist=
+	  last_robj=
+	  k=1
+
+	  if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then
+	    output=$output_objdir/$output_la.lnkscript
+	    func_verbose "creating GNU ld script: $output"
+	    echo 'INPUT (' > $output
+	    for obj in $save_libobjs
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    echo ')' >> $output
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$func_to_tool_file_result
+	  elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then
+	    output=$output_objdir/$output_la.lnk
+	    func_verbose "creating linker input file list: $output"
+	    : > $output
+	    set x $save_libobjs
+	    shift
+	    firstobj=
+	    if test yes = "$compiler_needs_object"; then
+	      firstobj="$1 "
+	      shift
+	    fi
+	    for obj
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+	  else
+	    if test -n "$save_libobjs"; then
+	      func_verbose "creating reloadable object files..."
+	      output=$output_objdir/$output_la-$k.$objext
+	      eval test_cmds=\"$reload_cmds\"
+	      func_len " $test_cmds"
+	      len0=$func_len_result
+	      len=$len0
+
+	      # Loop over the list of objects to be linked.
+	      for obj in $save_libobjs
+	      do
+		func_len " $obj"
+		func_arith $len + $func_len_result
+		len=$func_arith_result
+		if test -z "$objlist" ||
+		   test "$len" -lt "$max_cmd_len"; then
+		  func_append objlist " $obj"
+		else
+		  # The command $test_cmds is almost too long, add a
+		  # command to the queue.
+		  if test 1 -eq "$k"; then
+		    # The first file doesn't have a previous command to add.
+		    reload_objs=$objlist
+		    eval concat_cmds=\"$reload_cmds\"
+		  else
+		    # All subsequent reloadable object files will link in
+		    # the last one created.
+		    reload_objs="$objlist $last_robj"
+		    eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+		  fi
+		  last_robj=$output_objdir/$output_la-$k.$objext
+		  func_arith $k + 1
+		  k=$func_arith_result
+		  output=$output_objdir/$output_la-$k.$objext
+		  objlist=" $obj"
+		  func_len " $last_robj"
+		  func_arith $len0 + $func_len_result
+		  len=$func_arith_result
+		fi
+	      done
+	      # Handle the remaining objects by creating one last
+	      # reloadable object file.  All subsequent reloadable object
+	      # files will link in the last one created.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      reload_objs="$objlist $last_robj"
+	      eval concat_cmds=\"\$concat_cmds$reload_cmds\"
+	      if test -n "$last_robj"; then
+	        eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+	      fi
+	      func_append delfiles " $output"
+
+	    else
+	      output=
+	    fi
+
+	    ${skipped_export-false} && {
+	      func_verbose "generating symbol list for '$libname.la'"
+	      export_symbols=$output_objdir/$libname.exp
+	      $opt_dry_run || $RM $export_symbols
+	      libobjs=$output
+	      # Append the command to create the export file.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+	      if test -n "$last_robj"; then
+		eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+	      fi
+	    }
+
+	    test -n "$save_libobjs" &&
+	      func_verbose "creating a temporary reloadable object file: $output"
+
+	    # Loop through the commands generated above and execute them.
+	    save_ifs=$IFS; IFS='~'
+	    for cmd in $concat_cmds; do
+	      IFS=$save_ifs
+	      $opt_quiet || {
+		  func_quote_for_expand "$cmd"
+		  eval "func_echo $func_quote_for_expand_result"
+	      }
+	      $opt_dry_run || eval "$cmd" || {
+		lt_exit=$?
+
+		# Restore the uninstalled library and exit
+		if test relink = "$opt_mode"; then
+		  ( cd "$output_objdir" && \
+		    $RM "${realname}T" && \
+		    $MV "${realname}U" "$realname" )
+		fi
+
+		exit $lt_exit
+	      }
+	    done
+	    IFS=$save_ifs
+
+	    if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+
+          ${skipped_export-false} && {
+	    if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	      tmp_export_symbols=$export_symbols
+	      test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
+	      $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	    fi
+
+	    if test -n "$orig_export_symbols"; then
+	      # The given exports_symbols file has to be filtered, so filter it.
+	      func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
+	      # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	      # 's' commands, which not all seds can handle. GNU sed should be fine
+	      # though. Also, the filter scales superlinearly with the number of
+	      # global variables. join(1) would be nice here, but unfortunately
+	      # isn't a blessed tool.
+	      $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	      func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	      export_symbols=$output_objdir/$libname.def
+	      $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	    fi
+	  }
+
+	  libobjs=$output
+	  # Restore the value of output.
+	  output=$save_output
+
+	  if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	  # Expand the library linking commands again to reset the
+	  # value of $libobjs for piecewise linking.
+
+	  # Do each of the archive commands.
+	  if test yes = "$module" && test -n "$module_cmds"; then
+	    if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	      cmds=$module_expsym_cmds
+	    else
+	      cmds=$module_cmds
+	    fi
+	  else
+	    if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	      cmds=$archive_expsym_cmds
+	    else
+	      cmds=$archive_cmds
+	    fi
+	  fi
+	fi
+
+	if test -n "$delfiles"; then
+	  # Append the command to remove temporary files to $cmds.
+	  eval cmds=\"\$cmds~\$RM $delfiles\"
+	fi
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop=$output_objdir/${outputname}x
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append libobjs " $func_extract_archives_result"
+	  test "X$libobjs" = "X " && libobjs=
+	fi
+
+	save_ifs=$IFS; IFS='~'
+	for cmd in $cmds; do
+	  IFS=$sp$nl
+	  eval cmd=\"$cmd\"
+	  IFS=$save_ifs
+	  $opt_quiet || {
+	    func_quote_for_expand "$cmd"
+	    eval "func_echo $func_quote_for_expand_result"
+	  }
+	  $opt_dry_run || eval "$cmd" || {
+	    lt_exit=$?
+
+	    # Restore the uninstalled library and exit
+	    if test relink = "$opt_mode"; then
+	      ( cd "$output_objdir" && \
+	        $RM "${realname}T" && \
+		$MV "${realname}U" "$realname" )
+	    fi
+
+	    exit $lt_exit
+	  }
+	done
+	IFS=$save_ifs
+
+	# Restore the uninstalled library and exit
+	if test relink = "$opt_mode"; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+	  if test -n "$convenience"; then
+	    if test -z "$whole_archive_flag_spec"; then
+	      func_show_eval '${RM}r "$gentop"'
+	    fi
+	  fi
+
+	  exit $EXIT_SUCCESS
+	fi
+
+	# Create links to the real library.
+	for linkname in $linknames; do
+	  if test "$realname" != "$linkname"; then
+	    func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+	  fi
+	done
+
+	# If -module or -export-dynamic was specified, set the dlname.
+	if test yes = "$module" || test yes = "$export_dynamic"; then
+	  # On all known operating systems, these are identical.
+	  dlname=$soname
+	fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+	func_warning "'-dlopen' is ignored for objects"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "'-l' and '-L' are ignored for objects" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "'-rpath' is ignored for objects"
+
+      test -n "$xrpath" && \
+	func_warning "'-R' is ignored for objects"
+
+      test -n "$vinfo" && \
+	func_warning "'-version-info' is ignored for objects"
+
+      test -n "$release" && \
+	func_warning "'-release' is ignored for objects"
+
+      case $output in
+      *.lo)
+	test -n "$objs$old_deplibs" && \
+	  func_fatal_error "cannot build library object '$output' from non-libtool objects"
+
+	libobj=$output
+	func_lo2o "$libobj"
+	obj=$func_lo2o_result
+	;;
+      *)
+	libobj=
+	obj=$output
+	;;
+      esac
+
+      # Delete the old objects.
+      $opt_dry_run || $RM $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # if reload_cmds runs $LD directly, get rid of -Wl from
+      # whole_archive_flag_spec and hope we can get by with turning comma
+      # into space.
+      case $reload_cmds in
+        *\$LD[\ \$]*) wl= ;;
+      esac
+      if test -n "$convenience"; then
+	if test -n "$whole_archive_flag_spec"; then
+	  eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+	  test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+	  reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags
+	else
+	  gentop=$output_objdir/${obj}x
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $convenience
+	  reload_conv_objs="$reload_objs $func_extract_archives_result"
+	fi
+      fi
+
+      # If we're not building shared, we need to use non_pic_objs
+      test yes = "$build_libtool_libs" || libobjs=$non_pic_objects
+
+      # Create the old-style object.
+      reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs
+
+      output=$obj
+      func_execute_cmds "$reload_cmds" 'exit $?'
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      test yes = "$build_libtool_libs" || {
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	# Create an invalid libtool object if no PIC, so that we don't
+	# accidentally link it into a program.
+	# $show "echo timestamp > $libobj"
+	# $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+	exit $EXIT_SUCCESS
+      }
+
+      if test -n "$pic_flag" || test default != "$pic_mode"; then
+	# Only do commands if we really have different PIC objects.
+	reload_objs="$libobjs $reload_conv_objs"
+	output=$libobj
+	func_execute_cmds "$reload_cmds" 'exit $?'
+      fi
+
+      if test -n "$gentop"; then
+	func_show_eval '${RM}r "$gentop"'
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+	*cygwin*) func_stripname '' '.exe' "$output"
+	          output=$func_stripname_result.exe;;
+      esac
+      test -n "$vinfo" && \
+	func_warning "'-version-info' is ignored for programs"
+
+      test -n "$release" && \
+	func_warning "'-release' is ignored for programs"
+
+      $preload \
+	&& test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \
+	&& func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+	# On Rhapsody replace the C library is the System framework
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	;;
+      esac
+
+      case $host in
+      *-*-darwin*)
+	# Don't allow lazy linking, it breaks C++ global constructors
+	# But is supposedly fixed on 10.4 or later (yay!).
+	if test CXX = "$tagname"; then
+	  case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+	    10.[0123])
+	      func_append compile_command " $wl-bind_at_load"
+	      func_append finalize_command " $wl-bind_at_load"
+	    ;;
+	  esac
+	fi
+	# Time to change all our "foo.ltframework" stuff back to "-framework foo"
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	;;
+      esac
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $compile_deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $compile_deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      compile_deplibs=$new_libs
+
+
+      func_append compile_command " $compile_deplibs"
+      func_append finalize_command " $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	for libdir in $rpath $xrpath; do
+	  # This is the magic to use -rpath.
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs=$libdir
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append perm_rpath " $libdir" ;;
+	  esac
+	fi
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$libdir:"*) ;;
+	  ::) dllsearchpath=$libdir;;
+	  *) func_append dllsearchpath ":$libdir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir=$hardcode_libdirs
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath=$rpath
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs=$libdir
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$finalize_perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_perm_rpath " $libdir" ;;
+	  esac
+	fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir=$hardcode_libdirs
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath=$rpath
+
+      if test -n "$libobjs" && test yes = "$build_old_libs"; then
+	# Transform all the library objects into standard objects.
+	compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+      fi
+
+      func_generate_dlsyms "$outputname" "@PROGRAM@" false
+
+      # template prelinking step
+      if test -n "$prelink_cmds"; then
+	func_execute_cmds "$prelink_cmds" 'exit $?'
+      fi
+
+      wrappers_required=:
+      case $host in
+      *cegcc* | *mingw32ce*)
+        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+        wrappers_required=false
+        ;;
+      *cygwin* | *mingw* )
+        test yes = "$build_libtool_libs" || wrappers_required=false
+        ;;
+      *)
+        if test no = "$need_relink" || test yes != "$build_libtool_libs"; then
+          wrappers_required=false
+        fi
+        ;;
+      esac
+      $wrappers_required || {
+	# Replace the output file specification.
+	compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	link_command=$compile_command$compile_rpath
+
+	# We have no uninstalled library dependencies, so finalize right now.
+	exit_status=0
+	func_show_eval "$link_command" 'exit_status=$?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	# Delete the generated files.
+	if test -f "$output_objdir/${outputname}S.$objext"; then
+	  func_show_eval '$RM "$output_objdir/${outputname}S.$objext"'
+	fi
+
+	exit $exit_status
+      }
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+	compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+	finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+	if test -n "$perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+	if test -n "$finalize_perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $finalize_perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+      fi
+
+      if test yes = "$no_install"; then
+	# We don't need to create a wrapper script.
+	link_command=$compile_var$compile_command$compile_rpath
+	# Replace the output file specification.
+	link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	# Delete the old output file.
+	$opt_dry_run || $RM $output
+	# Link the executable and exit
+	func_show_eval "$link_command" 'exit $?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      case $hardcode_action,$fast_install in
+        relink,*)
+	  # Fast installation is not supported
+	  link_command=$compile_var$compile_command$compile_rpath
+	  relink_command=$finalize_var$finalize_command$finalize_rpath
+
+	  func_warning "this platform does not like uninstalled shared libraries"
+	  func_warning "'$output' will be relinked during installation"
+	  ;;
+        *,yes)
+	  link_command=$finalize_var$compile_command$finalize_rpath
+	  relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+          ;;
+	*,no)
+	  link_command=$compile_var$compile_command$compile_rpath
+	  relink_command=$finalize_var$finalize_command$finalize_rpath
+          ;;
+	*,needless)
+	  link_command=$finalize_var$compile_command$finalize_rpath
+	  relink_command=
+          ;;
+      esac
+
+      # Replace the output file specification.
+      link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      func_show_eval "$link_command" 'exit $?'
+
+      if test -n "$postlink_cmds"; then
+	func_to_tool_file "$output_objdir/$outputname"
+	postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	func_execute_cmds "$postlink_cmds" 'exit $?'
+      fi
+
+      # Now create the wrapper script.
+      func_verbose "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+	# Preserve any variables that may affect compiler behavior
+	for var in $variables_saved_for_relink; do
+	  if eval test -z \"\${$var+set}\"; then
+	    relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	  elif eval var_value=\$$var; test -z "$var_value"; then
+	    relink_command="$var=; export $var; $relink_command"
+	  else
+	    func_quote_for_eval "$var_value"
+	    relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	  fi
+	done
+	relink_command="(cd `pwd`; $relink_command)"
+	relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if not in dry run mode.
+      $opt_dry_run || {
+	# win32 will think the script is a binary if it has
+	# a .exe suffix, so we strip it off here.
+	case $output in
+	  *.exe) func_stripname '' '.exe' "$output"
+	         output=$func_stripname_result ;;
+	esac
+	# test for cygwin because mv fails w/o .exe extensions
+	case $host in
+	  *cygwin*)
+	    exeext=.exe
+	    func_stripname '' '.exe' "$outputname"
+	    outputname=$func_stripname_result ;;
+	  *) exeext= ;;
+	esac
+	case $host in
+	  *cygwin* | *mingw* )
+	    func_dirname_and_basename "$output" "" "."
+	    output_name=$func_basename_result
+	    output_path=$func_dirname_result
+	    cwrappersource=$output_path/$objdir/lt-$output_name.c
+	    cwrapper=$output_path/$output_name.exe
+	    $RM $cwrappersource $cwrapper
+	    trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_cwrapperexe_src > $cwrappersource
+
+	    # The wrapper executable is built using the $host compiler,
+	    # because it contains $host paths and files. If cross-
+	    # compiling, it, like the target executable, must be
+	    # executed on the $host or under an emulation environment.
+	    $opt_dry_run || {
+	      $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+	      $STRIP $cwrapper
+	    }
+
+	    # Now, create the wrapper script for func_source use:
+	    func_ltwrapper_scriptname $cwrapper
+	    $RM $func_ltwrapper_scriptname_result
+	    trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+	    $opt_dry_run || {
+	      # note: this script will not be executed, so do not chmod.
+	      if test "x$build" = "x$host"; then
+		$cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+	      else
+		func_emit_wrapper no > $func_ltwrapper_scriptname_result
+	      fi
+	    }
+	  ;;
+	  * )
+	    $RM $output
+	    trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_wrapper no > $output
+	    chmod +x $output
+	  ;;
+	esac
+      }
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      case $build_libtool_libs in
+        convenience)
+	  oldobjs="$libobjs_save $symfileobj"
+	  addlibs=$convenience
+	  build_libtool_libs=no
+	  ;;
+	module)
+	  oldobjs=$libobjs_save
+	  addlibs=$old_convenience
+	  build_libtool_libs=no
+          ;;
+	*)
+	  oldobjs="$old_deplibs $non_pic_objects"
+	  $preload && test -f "$symfileobj" \
+	    && func_append oldobjs " $symfileobj"
+	  addlibs=$old_convenience
+	  ;;
+      esac
+
+      if test -n "$addlibs"; then
+	gentop=$output_objdir/${outputname}x
+	func_append generated " $gentop"
+
+	func_extract_archives $gentop $addlibs
+	func_append oldobjs " $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then
+	cmds=$old_archive_from_new_cmds
+      else
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop=$output_objdir/${outputname}x
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append oldobjs " $func_extract_archives_result"
+	fi
+
+	# POSIX demands no paths to be encoded in archives.  We have
+	# to avoid creating archives with duplicate basenames if we
+	# might have to extract them afterwards, e.g., when creating a
+	# static archive out of a convenience library, or when linking
+	# the entirety of a libtool archive into another (currently
+	# not supported by libtool).
+	if (for obj in $oldobjs
+	    do
+	      func_basename "$obj"
+	      $ECHO "$func_basename_result"
+	    done | sort | sort -uc >/dev/null 2>&1); then
+	  :
+	else
+	  echo "copying selected object files to avoid basename conflicts..."
+	  gentop=$output_objdir/${outputname}x
+	  func_append generated " $gentop"
+	  func_mkdir_p "$gentop"
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  counter=1
+	  for obj in $save_oldobjs
+	  do
+	    func_basename "$obj"
+	    objbase=$func_basename_result
+	    case " $oldobjs " in
+	    " ") oldobjs=$obj ;;
+	    *[\ /]"$objbase "*)
+	      while :; do
+		# Make sure we don't pick an alternate name that also
+		# overlaps.
+		newobj=lt$counter-$objbase
+		func_arith $counter + 1
+		counter=$func_arith_result
+		case " $oldobjs " in
+		*[\ /]"$newobj "*) ;;
+		*) if test ! -f "$gentop/$newobj"; then break; fi ;;
+		esac
+	      done
+	      func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+	      func_append oldobjs " $gentop/$newobj"
+	      ;;
+	    *) func_append oldobjs " $obj" ;;
+	    esac
+	  done
+	fi
+	func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+	tool_oldlib=$func_to_tool_file_result
+	eval cmds=\"$old_archive_cmds\"
+
+	func_len " $cmds"
+	len=$func_len_result
+	if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  cmds=$old_archive_cmds
+	elif test -n "$archiver_list_spec"; then
+	  func_verbose "using command file archive linking..."
+	  for obj in $oldobjs
+	  do
+	    func_to_tool_file "$obj"
+	    $ECHO "$func_to_tool_file_result"
+	  done > $output_objdir/$libname.libcmd
+	  func_to_tool_file "$output_objdir/$libname.libcmd"
+	  oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+	  cmds=$old_archive_cmds
+	else
+	  # the command line is too long to link in one step, link in parts
+	  func_verbose "using piecewise archive linking..."
+	  save_RANLIB=$RANLIB
+	  RANLIB=:
+	  objlist=
+	  concat_cmds=
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  # Is there a better way of finding the last object in the list?
+	  for obj in $save_oldobjs
+	  do
+	    last_oldobj=$obj
+	  done
+	  eval test_cmds=\"$old_archive_cmds\"
+	  func_len " $test_cmds"
+	  len0=$func_len_result
+	  len=$len0
+	  for obj in $save_oldobjs
+	  do
+	    func_len " $obj"
+	    func_arith $len + $func_len_result
+	    len=$func_arith_result
+	    func_append objlist " $obj"
+	    if test "$len" -lt "$max_cmd_len"; then
+	      :
+	    else
+	      # the above command should be used before it gets too long
+	      oldobjs=$objlist
+	      if test "$obj" = "$last_oldobj"; then
+		RANLIB=$save_RANLIB
+	      fi
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\$concat_cmds$old_archive_cmds\"
+	      objlist=
+	      len=$len0
+	    fi
+	  done
+	  RANLIB=$save_RANLIB
+	  oldobjs=$objlist
+	  if test -z "$oldobjs"; then
+	    eval cmds=\"\$concat_cmds\"
+	  else
+	    eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+	  fi
+	fi
+      fi
+      func_execute_cmds "$cmds" 'exit $?'
+    done
+
+    test -n "$generated" && \
+      func_show_eval "${RM}r$generated"
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test yes = "$build_old_libs" && old_library=$libname.$libext
+      func_verbose "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+	if eval test -z \"\${$var+set}\"; then
+	  relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	elif eval var_value=\$$var; test -z "$var_value"; then
+	  relink_command="$var=; export $var; $relink_command"
+	else
+	  func_quote_for_eval "$var_value"
+	  relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      if test yes = "$hardcode_automatic"; then
+	relink_command=
+      fi
+
+      # Only create the output if not a dry run.
+      $opt_dry_run || {
+	for installed in no yes; do
+	  if test yes = "$installed"; then
+	    if test -z "$install_libdir"; then
+	      break
+	    fi
+	    output=$output_objdir/${outputname}i
+	    # Replace all uninstalled libtool libraries with the installed ones
+	    newdependency_libs=
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      *.la)
+		func_basename "$deplib"
+		name=$func_basename_result
+		func_resolve_sysroot "$deplib"
+		eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+		test -z "$libdir" && \
+		  func_fatal_error "'$deplib' is not a valid libtool archive"
+		func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      -L*)
+		func_stripname -L '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -L$func_replace_sysroot_result"
+		;;
+	      -R*)
+		func_stripname -R '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -R$func_replace_sysroot_result"
+		;;
+	      *) func_append newdependency_libs " $deplib" ;;
+	      esac
+	    done
+	    dependency_libs=$newdependency_libs
+	    newdlfiles=
+
+	    for lib in $dlfiles; do
+	      case $lib in
+	      *.la)
+	        func_basename "$lib"
+		name=$func_basename_result
+		eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "'$lib' is not a valid libtool archive"
+		func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      *) func_append newdlfiles " $lib" ;;
+	      esac
+	    done
+	    dlfiles=$newdlfiles
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+	      *.la)
+		# Only pass preopened files to the pseudo-archive (for
+		# eventual linking with the app. that links it) if we
+		# didn't already link the preopened objects directly into
+		# the library:
+		func_basename "$lib"
+		name=$func_basename_result
+		eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "'$lib' is not a valid libtool archive"
+		func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      esac
+	    done
+	    dlprefiles=$newdlprefiles
+	  else
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlfiles " $abs"
+	    done
+	    dlfiles=$newdlfiles
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlprefiles " $abs"
+	    done
+	    dlprefiles=$newdlprefiles
+	  fi
+	  $RM $output
+	  # place dlname in correct position for cygwin
+	  # In fact, it would be nice if we could use this code for all target
+	  # systems that can't hard-code library paths into their executables
+	  # and that have no shared library path variable independent of PATH,
+	  # but it turns out we can't easily determine that from inspecting
+	  # libtool variables, so we have to hard-code the OSs to which it
+	  # applies here; at the moment, that means platforms that use the PE
+	  # object format with DLL files.  See the long comment at the top of
+	  # tests/bindir.at for full details.
+	  tdlname=$dlname
+	  case $host,$output,$installed,$module,$dlname in
+	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+	      # If a -bindir argument was supplied, place the dll there.
+	      if test -n "$bindir"; then
+		func_relative_path "$install_libdir" "$bindir"
+		tdlname=$func_relative_path_result/$dlname
+	      else
+		# Otherwise fall back on heuristic.
+		tdlname=../bin/$dlname
+	      fi
+	      ;;
+	  esac
+	  $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that cannot go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+	  if test no,yes = "$installed,$need_relink"; then
+	    $ECHO >> $output "\
+relink_command=\"$relink_command\""
+	  fi
+	done
+      }
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+}
+
+if test link = "$opt_mode" || test relink = "$opt_mode"; then
+  func_mode_link ${1+"$@"}
+fi
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+    $debug_cmd
+
+    RM=$nonopt
+    files=
+    rmforce=false
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic=$magic
+
+    for arg
+    do
+      case $arg in
+      -f) func_append RM " $arg"; rmforce=: ;;
+      -*) func_append RM " $arg" ;;
+      *) func_append files " $arg" ;;
+      esac
+    done
+
+    test -z "$RM" && \
+      func_fatal_help "you must specify an RM program"
+
+    rmdirs=
+
+    for file in $files; do
+      func_dirname "$file" "" "."
+      dir=$func_dirname_result
+      if test . = "$dir"; then
+	odir=$objdir
+      else
+	odir=$dir/$objdir
+      fi
+      func_basename "$file"
+      name=$func_basename_result
+      test uninstall = "$opt_mode" && odir=$dir
+
+      # Remember odir for removal later, being careful to avoid duplicates
+      if test clean = "$opt_mode"; then
+	case " $rmdirs " in
+	  *" $odir "*) ;;
+	  *) func_append rmdirs " $odir" ;;
+	esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if { test -L "$file"; } >/dev/null 2>&1 ||
+	 { test -h "$file"; } >/dev/null 2>&1 ||
+	 test -f "$file"; then
+	:
+      elif test -d "$file"; then
+	exit_status=1
+	continue
+      elif $rmforce; then
+	continue
+      fi
+
+      rmfiles=$file
+
+      case $name in
+      *.la)
+	# Possibly a libtool archive, so verify it.
+	if func_lalib_p "$file"; then
+	  func_source $dir/$name
+
+	  # Delete the libtool libraries and symlinks.
+	  for n in $library_names; do
+	    func_append rmfiles " $odir/$n"
+	  done
+	  test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+	  case $opt_mode in
+	  clean)
+	    case " $library_names " in
+	    *" $dlname "*) ;;
+	    *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+	    esac
+	    test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+	    ;;
+	  uninstall)
+	    if test -n "$library_names"; then
+	      # Do each command in the postuninstall commands.
+	      func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1'
+	    fi
+
+	    if test -n "$old_library"; then
+	      # Do each command in the old_postuninstall commands.
+	      func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1'
+	    fi
+	    # FIXME: should reinstall the best remaining shared library.
+	    ;;
+	  esac
+	fi
+	;;
+
+      *.lo)
+	# Possibly a libtool object, so verify it.
+	if func_lalib_p "$file"; then
+
+	  # Read the .lo file
+	  func_source $dir/$name
+
+	  # Add PIC object to the list of files to remove.
+	  if test -n "$pic_object" && test none != "$pic_object"; then
+	    func_append rmfiles " $dir/$pic_object"
+	  fi
+
+	  # Add non-PIC object to the list of files to remove.
+	  if test -n "$non_pic_object" && test none != "$non_pic_object"; then
+	    func_append rmfiles " $dir/$non_pic_object"
+	  fi
+	fi
+	;;
+
+      *)
+	if test clean = "$opt_mode"; then
+	  noexename=$name
+	  case $file in
+	  *.exe)
+	    func_stripname '' '.exe' "$file"
+	    file=$func_stripname_result
+	    func_stripname '' '.exe' "$name"
+	    noexename=$func_stripname_result
+	    # $file with .exe has already been added to rmfiles,
+	    # add $file without .exe
+	    func_append rmfiles " $file"
+	    ;;
+	  esac
+	  # Do a test to see if this is a libtool program.
+	  if func_ltwrapper_p "$file"; then
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      relink_command=
+	      func_source $func_ltwrapper_scriptname_result
+	      func_append rmfiles " $func_ltwrapper_scriptname_result"
+	    else
+	      relink_command=
+	      func_source $dir/$noexename
+	    fi
+
+	    # note $name still contains .exe if it was in $file originally
+	    # as does the version of $file that was added into $rmfiles
+	    func_append rmfiles " $odir/$name $odir/${name}S.$objext"
+	    if test yes = "$fast_install" && test -n "$relink_command"; then
+	      func_append rmfiles " $odir/lt-$name"
+	    fi
+	    if test "X$noexename" != "X$name"; then
+	      func_append rmfiles " $odir/lt-$noexename.c"
+	    fi
+	  fi
+	fi
+	;;
+      esac
+      func_show_eval "$RM $rmfiles" 'exit_status=1'
+    done
+
+    # Try to remove the $objdir's in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+	func_show_eval "rmdir $dir >/dev/null 2>&1"
+      fi
+    done
+
+    exit $exit_status
+}
+
+if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then
+  func_mode_uninstall ${1+"$@"}
+fi
+
+test -z "$opt_mode" && {
+  help=$generic_help
+  func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+  func_fatal_help "invalid operation mode '$opt_mode'"
+
+if test -n "$exec_cmd"; then
+  eval exec "$exec_cmd"
+  exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# where we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/final/lib/External/isl/m4/ax_c___attribute__.m4 b/final/lib/External/isl/m4/ax_c___attribute__.m4
new file mode 100644
index 0000000..cf3d62b
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_c___attribute__.m4
@@ -0,0 +1,66 @@
+# ===========================================================================
+#    http://www.gnu.org/software/autoconf-archive/ax_c___attribute__.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_C___ATTRIBUTE__
+#
+# DESCRIPTION
+#
+#   Provides a test for the compiler support of __attribute__ extensions.
+#   Defines HAVE___ATTRIBUTE__ if it is found.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Stepan Kasal <skasal@redhat.com>
+#   Copyright (c) 2008 Christian Haggstrom
+#   Copyright (c) 2008 Ryan McCabe <ryan@numb.org>
+#
+#   This program is free software; you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation; either version 2 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 8
+
+AC_DEFUN([AX_C___ATTRIBUTE__], [
+  AC_CACHE_CHECK([for __attribute__], [ax_cv___attribute__],
+    [AC_COMPILE_IFELSE(
+      [AC_LANG_PROGRAM(
+	[[#include <stdlib.h>
+	  static void foo(void) __attribute__ ((unused));
+	  static void
+	  foo(void) {
+	      exit(1);
+	  }
+        ]], [])],
+      [ax_cv___attribute__=yes],
+      [ax_cv___attribute__=no]
+    )
+  ])
+  if test "$ax_cv___attribute__" = "yes"; then
+    AC_DEFINE([HAVE___ATTRIBUTE__], 1, [define if your compiler has __attribute__])
+  fi
+])
diff --git a/final/lib/External/isl/m4/ax_cc_maxopt.m4 b/final/lib/External/isl/m4/ax_cc_maxopt.m4
new file mode 100644
index 0000000..92d522d
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_cc_maxopt.m4
@@ -0,0 +1,188 @@
+# ===========================================================================
+#          http://www.nongnu.org/autoconf-archive/ax_cc_maxopt.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CC_MAXOPT
+#
+# DESCRIPTION
+#
+#   Try to turn on "good" C optimization flags for various compilers and
+#   architectures, for some definition of "good". (In our case, good for
+#   FFTW and hopefully for other scientific codes. Modify as needed.)
+#
+#   The user can override the flags by setting the CFLAGS environment
+#   variable. The user can also specify --enable-portable-binary in order to
+#   disable any optimization flags that might result in a binary that only
+#   runs on the host architecture.
+#
+#   Note also that the flags assume that ANSI C aliasing rules are followed
+#   by the code (e.g. for gcc's -fstrict-aliasing), and that floating-point
+#   computations can be re-ordered as needed.
+#
+#   Requires macros: AX_CHECK_COMPILER_FLAGS, AX_COMPILER_VENDOR,
+#   AX_GCC_ARCHFLAG, AX_GCC_X86_CPUID.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+#   Copyright (c) 2008 Matteo Frigo
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+AC_DEFUN([AX_CC_MAXOPT],
+[
+AC_REQUIRE([AC_PROG_CC])
+AC_REQUIRE([AX_COMPILER_VENDOR])
+AC_REQUIRE([AC_CANONICAL_HOST])
+
+AC_ARG_ENABLE(portable-binary, [AC_HELP_STRING([--enable-portable-binary], [disable compiler optimizations that would produce unportable binaries])],
+	acx_maxopt_portable=$withval, acx_maxopt_portable=no)
+
+# Try to determine "good" native compiler flags if none specified via CFLAGS
+if test "$ac_test_CFLAGS" != "set"; then
+  CFLAGS=""
+  case $ax_cv_c_compiler_vendor in
+    dec) CFLAGS="-newc -w0 -O5 -ansi_alias -ansi_args -fp_reorder -tune host"
+	 if test "x$acx_maxopt_portable" = xno; then
+           CFLAGS="$CFLAGS -arch host"
+         fi;;
+
+    sun) CFLAGS="-native -fast -xO5 -dalign"
+	 if test "x$acx_maxopt_portable" = xyes; then
+	   CFLAGS="$CFLAGS -xarch=generic"
+         fi;;
+
+    hp)  CFLAGS="+Oall +Optrs_ansi +DSnative"
+	 if test "x$acx_maxopt_portable" = xyes; then
+	   CFLAGS="$CFLAGS +DAportable"
+	 fi;;
+
+    ibm) if test "x$acx_maxopt_portable" = xno; then
+           xlc_opt="-qarch=auto -qtune=auto"
+	 else
+           xlc_opt="-qtune=auto"
+	 fi
+         AX_CHECK_COMPILER_FLAGS($xlc_opt,
+         	CFLAGS="-O3 -qansialias -w $xlc_opt",
+               [CFLAGS="-O3 -qansialias -w"
+                echo "******************************************************"
+                echo "*  You seem to have the IBM  C compiler.  It is      *"
+                echo "*  recommended for best performance that you use:    *"
+                echo "*                                                    *"
+                echo "*    CFLAGS=-O3 -qarch=xxx -qtune=xxx -qansialias -w *"
+                echo "*                      ^^^        ^^^                *"
+                echo "*  where xxx is pwr2, pwr3, 604, or whatever kind of *"
+                echo "*  CPU you have.  (Set the CFLAGS environment var.   *"
+                echo "*  and re-run configure.)  For more info, man cc.    *"
+                echo "******************************************************"])
+         ;;
+
+    intel) CFLAGS="-O3 -ansi_alias"
+	if test "x$acx_maxopt_portable" = xno; then
+	  icc_archflag=unknown
+	  icc_flags=""
+	  case $host_cpu in
+	    i686*|x86_64*)
+              # icc accepts gcc assembly syntax, so these should work:
+	      AX_GCC_X86_CPUID(0)
+              AX_GCC_X86_CPUID(1)
+	      case $ax_cv_gcc_x86_cpuid_0 in # see AX_GCC_ARCHFLAG
+                *:756e6547:*:*) # Intel
+                  case $ax_cv_gcc_x86_cpuid_1 in
+                    *6a?:*[[234]]:*:*|*6[[789b]]?:*:*:*) icc_flags="-xK";;
+                    *f3[[347]]:*:*:*|*f4[1347]:*:*:*) icc_flags="-xP -xN -xW -xK";;
+                    *f??:*:*:*) icc_flags="-xN -xW -xK";;
+                  esac ;;
+              esac ;;
+          esac
+          if test "x$icc_flags" != x; then
+            for flag in $icc_flags; do
+              AX_CHECK_COMPILER_FLAGS($flag, [icc_archflag=$flag; break])
+            done
+          fi
+          AC_MSG_CHECKING([for icc architecture flag])
+	  AC_MSG_RESULT($icc_archflag)
+          if test "x$icc_archflag" != xunknown; then
+            CFLAGS="$CFLAGS $icc_archflag"
+          fi
+        fi
+	;;
+
+    gnu)
+     # default optimization flags for gcc on all systems
+     CFLAGS="-O3 -fomit-frame-pointer"
+
+     # -malign-double for x86 systems
+     AX_CHECK_COMPILER_FLAGS(-malign-double, CFLAGS="$CFLAGS -malign-double")
+
+     #  -fstrict-aliasing for gcc-2.95+
+     AX_CHECK_COMPILER_FLAGS(-fstrict-aliasing,
+	CFLAGS="$CFLAGS -fstrict-aliasing")
+
+     # note that we enable "unsafe" fp optimization with other compilers, too
+     AX_CHECK_COMPILER_FLAGS(-ffast-math, CFLAGS="$CFLAGS -ffast-math")
+
+     AX_GCC_ARCHFLAG($acx_maxopt_portable)
+
+     # drop to -O1 for gcc 4.2
+     $CC --version |
+	sed -e 's/.* \(@<:@0-9@:>@@<:@0-9@:>@*\)\.\(@<:@0-9@:>@@<:@0-9@:>@*\).*/\1 \2/' |
+	(read major minor
+	    if test $major -eq 4 -a $minor -eq 2; then
+				exit 0
+	    fi
+	    exit 1
+	) && CFLAGS="-O1"
+     ;;
+  esac
+
+  if test -z "$CFLAGS"; then
+	echo ""
+	echo "********************************************************"
+        echo "* WARNING: Don't know the best CFLAGS for this system  *"
+        echo "* Use ./configure CFLAGS=... to specify your own flags *"
+	echo "* (otherwise, a default of CFLAGS=-O3 will be used)    *"
+	echo "********************************************************"
+	echo ""
+        CFLAGS="-O3"
+  fi
+
+  AX_CHECK_COMPILER_FLAGS($CFLAGS, [], [
+	echo ""
+        echo "********************************************************"
+        echo "* WARNING: The guessed CFLAGS don't seem to work with  *"
+        echo "* your compiler.                                       *"
+        echo "* Use ./configure CFLAGS=... to specify your own flags *"
+        echo "********************************************************"
+        echo ""
+        CFLAGS=""
+  ])
+
+fi
+])
diff --git a/final/lib/External/isl/m4/ax_check_compiler_flags.m4 b/final/lib/External/isl/m4/ax_check_compiler_flags.m4
new file mode 100644
index 0000000..7da8324
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_check_compiler_flags.m4
@@ -0,0 +1,74 @@
+# ===========================================================================
+#     http://www.nongnu.org/autoconf-archive/ax_check_compiler_flags.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CHECK_COMPILER_FLAGS(FLAGS, [ACTION-SUCCESS], [ACTION-FAILURE])
+#
+# DESCRIPTION
+#
+#   Check whether the given compiler FLAGS work with the current language's
+#   compiler, or whether they give an error. (Warnings, however, are
+#   ignored.)
+#
+#   ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+#   success/failure.
+#
+# LICENSE
+#
+#   Copyright (c) 2009 Steven G. Johnson <stevenj@alum.mit.edu>
+#   Copyright (c) 2009 Matteo Frigo
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+AC_DEFUN([AX_CHECK_COMPILER_FLAGS],
+[AC_PREREQ(2.59) dnl for _AC_LANG_PREFIX
+AC_MSG_CHECKING([whether _AC_LANG compiler accepts $1])
+dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname:
+AS_LITERAL_IF([$1],
+  [AC_CACHE_VAL(AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1]), [
+      ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
+      _AC_LANG_PREFIX[]FLAGS="$1"
+      AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
+        AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=yes,
+        AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=no)
+      _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])],
+  [ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
+   _AC_LANG_PREFIX[]FLAGS="$1"
+   AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
+     eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=yes,
+     eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=no)
+   _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])
+eval ax_check_compiler_flags=$AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])
+AC_MSG_RESULT($ax_check_compiler_flags)
+if test "x$ax_check_compiler_flags" = xyes; then
+	m4_default([$2], :)
+else
+	m4_default([$3], :)
+fi
+])dnl AX_CHECK_COMPILER_FLAGS
diff --git a/final/lib/External/isl/m4/ax_compiler_vendor.m4 b/final/lib/External/isl/m4/ax_compiler_vendor.m4
new file mode 100644
index 0000000..3214706
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_compiler_vendor.m4
@@ -0,0 +1,63 @@
+# ===========================================================================
+#    http://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_COMPILER_VENDOR
+#
+# DESCRIPTION
+#
+#   Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun,
+#   hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft,
+#   watcom, etc. The vendor is returned in the cache variable
+#   $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+#   Copyright (c) 2008 Matteo Frigo
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 9
+
+AC_DEFUN([AX_COMPILER_VENDOR],
+[
+AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
+ [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown
+  # note: don't check for gcc first since some other compilers define __GNUC__
+  for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ pathscale:__PATHCC__,__PATHSCALE__ clang:__clang__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
+    vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
+#if !($vencpp)
+      thisisanerror;
+#endif
+])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break])
+  done
+ ])
+])
diff --git a/final/lib/External/isl/m4/ax_create_pkgconfig_info.m4 b/final/lib/External/isl/m4/ax_create_pkgconfig_info.m4
new file mode 100644
index 0000000..308e64f
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_create_pkgconfig_info.m4
@@ -0,0 +1,351 @@
+# ============================================================================
+#  http://www.gnu.org/software/autoconf-archive/ax_create_pkgconfig_info.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+#   AX_CREATE_PKGCONFIG_INFO [(outputfile, [requires [,libs [,summary [,cflags [, ldflags]]]]])]
+#
+# DESCRIPTION
+#
+#   Defaults:
+#
+#     $1 = $PACKAGE_NAME.pc
+#     $2 = (empty)
+#     $3 = $PACKAGE_LIBS $LIBS (as set at that point in configure.ac)
+#     $4 = $PACKAGE_SUMMARY (or $1 Library)
+#     $5 = $PACKAGE_CFLAGS (as set at the point in configure.ac)
+#     $6 = $PACKAGE_LDFLAGS (as set at the point in configure.ac)
+#
+#     PACKAGE_NAME defaults to $PACKAGE if not set.
+#     PACKAGE_LIBS defaults to -l$PACKAGE_NAME if not set.
+#
+#   The resulting file is called $PACKAGE.pc.in / $PACKAGE.pc
+#
+#   You will find this macro most useful in conjunction with
+#   ax_spec_defaults that can read good initializers from the .spec file. In
+#   consequencd, most of the generatable installable stuff can be made from
+#   information being updated in a single place for the whole project.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+#   Copyright (c) 2008 Sven Verdoolaege <skimo@kotnet.org>
+#
+#   This program is free software; you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation; either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 12
+
+AC_DEFUN([AX_CREATE_PKGCONFIG_INFO],[dnl
+AS_VAR_PUSHDEF([PKGCONFIG_suffix],[ax_create_pkgconfig_suffix])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_libdir],[ax_create_pkgconfig_libdir])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_libfile],[ax_create_pkgconfig_libfile])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_libname],[ax_create_pkgconfig_libname])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_version],[ax_create_pkgconfig_version])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_description],[ax_create_pkgconfig_description])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_requires],[ax_create_pkgconfig_requires])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_pkglibs],[ax_create_pkgconfig_pkglibs])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_libs],[ax_create_pkgconfig_libs])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_ldflags],[ax_create_pkgconfig_ldflags])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_cppflags],[ax_create_pkgconfig_cppflags])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_generate],[ax_create_pkgconfig_generate])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_src_libdir],[ax_create_pkgconfig_src_libdir])dnl
+AS_VAR_PUSHDEF([PKGCONFIG_src_headers],[ax_create_pkgconfig_src_headers])dnl
+
+# we need the expanded forms...
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+AC_MSG_CHECKING(our pkgconfig libname)
+test ".$PKGCONFIG_libname" != "." || \
+PKGCONFIG_libname="ifelse($1,,${PACKAGE_NAME},`basename $1 .pc`)"
+test ".$PKGCONFIG_libname" != "." || \
+PKGCONFIG_libname="$PACKAGE"
+PKGCONFIG_libname=`eval echo "$PKGCONFIG_libname"`
+PKGCONFIG_libname=`eval echo "$PKGCONFIG_libname"`
+AC_MSG_RESULT($PKGCONFIG_libname)
+
+AC_MSG_CHECKING(our pkgconfig version)
+test ".$PKGCONFIG_version" != "." || \
+PKGCONFIG_version="${PACKAGE_VERSION}"
+test ".$PKGCONFIG_version" != "." || \
+PKGCONFIG_version="$VERSION"
+PKGCONFIG_version=`eval echo "$PKGCONFIG_version"`
+PKGCONFIG_version=`eval echo "$PKGCONFIG_version"`
+AC_MSG_RESULT($PKGCONFIG_version)
+
+AC_MSG_CHECKING(our pkgconfig_libdir)
+test ".$pkgconfig_libdir" = "." && \
+pkgconfig_libdir='${libdir}/pkgconfig'
+PKGCONFIG_libdir=`eval echo "$pkgconfig_libdir"`
+PKGCONFIG_libdir=`eval echo "$PKGCONFIG_libdir"`
+PKGCONFIG_libdir=`eval echo "$PKGCONFIG_libdir"`
+AC_MSG_RESULT($pkgconfig_libdir)
+test "$pkgconfig_libdir" != "$PKGCONFIG_libdir" && (
+AC_MSG_RESULT(expanded our pkgconfig_libdir... $PKGCONFIG_libdir))
+AC_SUBST([pkgconfig_libdir])
+
+AC_MSG_CHECKING(our pkgconfig_libfile)
+test ".$pkgconfig_libfile" != "." || \
+pkgconfig_libfile="ifelse($1,,$PKGCONFIG_libname.pc,`basename $1`)"
+PKGCONFIG_libfile=`eval echo "$pkgconfig_libfile"`
+PKGCONFIG_libfile=`eval echo "$PKGCONFIG_libfile"`
+AC_MSG_RESULT($pkgconfig_libfile)
+test "$pkgconfig_libfile" != "$PKGCONFIG_libfile" && (
+AC_MSG_RESULT(expanded our pkgconfig_libfile... $PKGCONFIG_libfile))
+AC_SUBST([pkgconfig_libfile])
+
+AC_MSG_CHECKING(our package / suffix)
+PKGCONFIG_suffix="$program_suffix"
+test ".$PKGCONFIG_suffix" != .NONE || PKGCONFIG_suffix=""
+AC_MSG_RESULT(${PACKAGE_NAME} / ${PKGCONFIG_suffix})
+
+AC_MSG_CHECKING(our pkgconfig description)
+PKGCONFIG_description="ifelse($4,,$PACKAGE_SUMMARY,$4)"
+test ".$PKGCONFIG_description" != "." || \
+PKGCONFIG_description="$PKGCONFIG_libname Library"
+PKGCONFIG_description=`eval echo "$PKGCONFIG_description"`
+PKGCONFIG_description=`eval echo "$PKGCONFIG_description"`
+AC_MSG_RESULT($PKGCONFIG_description)
+
+AC_MSG_CHECKING(our pkgconfig requires)
+PKGCONFIG_requires="ifelse($2,,$PACKAGE_REQUIRES,$2)"
+PKGCONFIG_requires=`eval echo "$PKGCONFIG_requires"`
+PKGCONFIG_requires=`eval echo "$PKGCONFIG_requires"`
+AC_MSG_RESULT($PKGCONFIG_requires)
+
+AC_MSG_CHECKING(our pkgconfig ext libs)
+PKGCONFIG_pkglibs="$PACKAGE_LIBS"
+test ".$PKGCONFIG_pkglibs" != "." || PKGCONFIG_pkglibs="-l$PKGCONFIG_libname"
+PKGCONFIG_libs="ifelse($3,,$PKGCONFIG_pkglibs $LIBS,$3)"
+PKGCONFIG_libs=`eval echo "$PKGCONFIG_libs"`
+PKGCONFIG_libs=`eval echo "$PKGCONFIG_libs"`
+AC_MSG_RESULT($PKGCONFIG_libs)
+
+AC_MSG_CHECKING(our pkgconfig cppflags)
+PKGCONFIG_cppflags="ifelse($5,,$PACKAGE_CFLAGS,$5)"
+PKGCONFIG_cppflags=`eval echo "$PKGCONFIG_cppflags"`
+PKGCONFIG_cppflags=`eval echo "$PKGCONFIG_cppflags"`
+AC_MSG_RESULT($PKGCONFIG_cppflags)
+
+AC_MSG_CHECKING(our pkgconfig ldflags)
+PKGCONFIG_ldflags="ifelse($6,,$PACKAGE_LDFLAGS,$5)"
+PKGCONFIG_ldflags=`eval echo "$PKGCONFIG_ldflags"`
+PKGCONFIG_ldflags=`eval echo "$PKGCONFIG_ldflags"`
+AC_MSG_RESULT($PKGCONFIG_ldflags)
+
+test ".$PKGCONFIG_generate" != "." || \
+PKGCONFIG_generate="ifelse($1,,$PKGCONFIG_libname.pc,$1)"
+PKGCONFIG_generate=`eval echo "$PKGCONFIG_generate"`
+PKGCONFIG_generate=`eval echo "$PKGCONFIG_generate"`
+test "$pkgconfig_libfile" != "$PKGCONFIG_generate" && (
+AC_MSG_RESULT(generate the pkgconfig later... $PKGCONFIG_generate))
+
+if test ".$PKGCONFIG_src_libdir" = "." ; then
+PKGCONFIG_src_libdir=`pwd`
+PKGCONFIG_src_libdir=`AS_DIRNAME("$PKGCONFIG_src_libdir/$PKGCONFIG_generate")`
+test ! -d $PKGCONFIG_src_libdir/src || \
+PKGCONFIG_src_libdir="$PKGCONFIG_src_libdir/src"
+case ".$objdir" in
+*libs) PKGCONFIG_src_libdir="$PKGCONFIG_src_libdir/$objdir" ;; esac
+AC_MSG_RESULT(noninstalled pkgconfig -L $PKGCONFIG_src_libdir)
+fi
+
+if test ".$PKGCONFIG_src_headers" = "." ; then
+PKGCONFIG_src_headers=`pwd`
+v="$ac_top_srcdir" ;
+test ".$v" != "." || v="$ax_spec_dir"
+test ".$v" != "." || v="$srcdir"
+case "$v" in /*) PKGCONFIG_src_headers="" ;; esac
+PKGCONFIG_src_headers=`AS_DIRNAME("$PKGCONFIG_src_headers/$v/x")`
+test ! -d $PKGCONFIG_src_headers/incl[]ude || \
+PKGCONFIG_src_headers="$PKGCONFIG_src_headers/incl[]ude"
+AC_MSG_RESULT(noninstalled pkgconfig -I $PKGCONFIG_src_headers)
+fi
+
+
+dnl AC_CONFIG_COMMANDS crap disallows to use $PKGCONFIG_libfile here...
+AC_CONFIG_COMMANDS([$ax_create_pkgconfig_generate],[
+pkgconfig_generate="$ax_create_pkgconfig_generate"
+if test ! -f "$pkgconfig_generate.in"
+then generate="true"
+elif grep ' generated by configure ' $pkgconfig_generate.in >/dev/null
+then generate="true"
+else generate="false";
+fi
+if $generate ; then
+AC_MSG_NOTICE(creating $pkgconfig_generate.in)
+cat > $pkgconfig_generate.in <<AXEOF
+# generated by configure / remove this line to disable regeneration
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+libdir=@libdir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+includedir=@includedir@
+package=@PACKAGE@
+suffix=@suffix@
+
+Name: @PACKAGE_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @PACKAGE_VERSION@
+Requires: @PACKAGE_REQUIRES@
+Libs: -L\${libdir} @LDFLAGS@ @LIBS@
+Cflags: -I\${includedir} @CPPFLAGS@
+AXEOF
+fi # DONE generate $pkgconfig_generate.in
+AC_MSG_NOTICE(creating $pkgconfig_generate)
+cat >conftest.sed <<AXEOF
+s|@prefix@|${pkgconfig_prefix}|
+s|@exec_prefix@|${pkgconfig_execprefix}|
+s|@bindir@|${pkgconfig_bindir}|
+s|@libdir@|${pkgconfig_libdir}|
+s|@datarootdir@|${pkgconfig_datarootdir}|
+s|@datadir@|${pkgconfig_datadir}|
+s|@sysconfdir@|${pkgconfig_sysconfdir}|
+s|@includedir@|${pkgconfig_includedir}|
+s|@suffix@|${pkgconfig_suffix}|
+s|@PACKAGE@|${pkgconfig_package}|
+s|@PACKAGE_NAME@|${pkgconfig_libname}|
+s|@PACKAGE_DESCRIPTION@|${pkgconfig_description}|
+s|@PACKAGE_VERSION@|${pkgconfig_version}|
+s|@PACKAGE_REQUIRES@|${pkgconfig_requires}|
+s|@LIBS@|${pkgconfig_libs}|
+s|@LDFLAGS@|${pkgconfig_ldflags}|
+s|@CPPFLAGS@|${pkgconfig_cppflags}|
+AXEOF
+sed -f conftest.sed  $pkgconfig_generate.in > $pkgconfig_generate
+if test ! -s $pkgconfig_generate ; then
+    AC_MSG_ERROR([$pkgconfig_generate is empty])
+fi ; rm conftest.sed # DONE generate $pkgconfig_generate
+pkgconfig_uninstalled=`echo $pkgconfig_generate |sed 's/.pc$/-uninstalled.pc/'`
+AC_MSG_NOTICE(creating $pkgconfig_uninstalled)
+cat >conftest.sed <<AXEOF
+s|@prefix@|${pkgconfig_prefix}|
+s|@exec_prefix@|${pkgconfig_execprefix}|
+s|@bindir@|${pkgconfig_bindir}|
+s|@libdir@|${pkgconfig_src_libdir}|
+s|@datarootdir@|${pkgconfig_datarootdir}|
+s|@datadir@|${pkgconfig_datadir}|
+s|@sysconfdir@|${pkgconfig_sysconfdir}|
+s|@includedir@|${pkgconfig_src_headers}|
+s|@suffix@|${pkgconfig_suffix}|
+s|@PACKAGE@|${pkgconfig_package}|
+s|@PACKAGE_NAME@|${pkgconfig_libname}|
+s|@PACKAGE_DESCRIPTION@|${pkgconfig_description}|
+s|@PACKAGE_VERSION@|${pkgconfig_version}|
+s|@PACKAGE_REQUIRES@|${pkgconfig_requires}|
+s|@LIBS@|${pkgconfig_libs}|
+s|@LDFLAGS@|${pkgconfig_ldflags}|
+s|@CPPFLAGS@|${pkgconfig_cppflags}|
+AXEOF
+sed -f conftest.sed $pkgconfig_generate.in > $pkgconfig_uninstalled
+if test ! -s $pkgconfig_uninstalled ; then
+    AC_MSG_ERROR([$pkgconfig_uninstalled is empty])
+fi ; rm conftest.sed # DONE generate $pkgconfig_uninstalled
+           pkgconfig_requires_add=`echo ${pkgconfig_requires}`
+if test ".$pkgconfig_requires_add" != "." ; then
+           pkgconfig_requires_add="pkg-config $pkgconfig_requires_add"
+    else   pkgconfig_requires_add=":" ; fi
+pkgconfig_uninstalled=`echo $pkgconfig_generate |sed 's/.pc$/-uninstalled.sh/'`
+AC_MSG_NOTICE(creating $pkgconfig_uninstalled)
+cat >conftest.sed <<AXEOF
+s|@prefix@|\"${pkgconfig_prefix}\"|
+s|@exec_prefix@|\"${pkgconfig_execprefix}\"|
+s|@bindir@|\"${pkgconfig_bindir}\"|
+s|@libdir@|\"${pkgconfig_src_libdir}\"|
+s|@datarootdir@|\"${pkgconfig_datarootdir}\"|
+s|@datadir@|\"${pkgconfig_datadir}\"|
+s|@sysconfdir@|\"${pkgconfig_sysconfdir}\"|
+s|@includedir@|\"${pkgconfig_src_headers}\"|
+s|@suffix@|\"${pkgconfig_suffix}\"|
+s|@PACKAGE@|\"${pkgconfig_package}\"|
+s|@PACKAGE_NAME@|\"${pkgconfig_libname}\"|
+s|@PACKAGE_DESCRIPTION@|\"${pkgconfig_description}\"|
+s|@PACKAGE_VERSION@|\"${pkgconfig_version}\"|
+s|@PACKAGE_REQUIRES@|\"${pkgconfig_requires}\"|
+s|@LIBS@|\"${pkgconfig_libs}\"|
+s|@LDFLAGS@|\"${pkgconfig_ldflags}\"|
+s|@CPPFLAGS@|\"${pkgconfig_cppflags}\"|
+s>Name:>for option\\; do case \"\$option\" in --list-all|--name) echo >
+s>Description: *>\\;\\; --help) pkg-config --help \\; echo Buildscript Of >
+s>Version: *>\\;\\; --modversion|--version) echo >
+s>Requires:>\\;\\; --requires) echo $pkgconfig_requires_add>
+s>Libs: *>\\;\\; --libs) echo >
+s>Cflags: *>\\;\\; --cflags) echo >
+/--libs)/a\\
+       $pkgconfig_requires_add
+/--cflags)/a\\
+       $pkgconfig_requires_add\\
+;; --variable=*) eval echo '\$'\`echo \$option | sed -e 's/.*=//'\`\\
+;; --uninstalled) exit 0 \\
+;; *) ;; esac done
+AXEOF
+sed -f conftest.sed  $pkgconfig_generate.in > $pkgconfig_uninstalled
+if test ! -s $pkgconfig_uninstalled ; then
+    AC_MSG_ERROR([$pkgconfig_uninstalled is empty])
+fi ; rm conftest.sed # DONE generate $pkgconfig_uninstalled
+],[
+dnl AC_CONFIG_COMMANDS crap, the AS_PUSHVAR defines are invalid here...
+ax_create_pkgconfig_generate="$ax_create_pkgconfig_generate"
+pkgconfig_prefix='$prefix'
+pkgconfig_execprefix='$exec_prefix'
+pkgconfig_bindir='$bindir'
+pkgconfig_libdir='$libdir'
+pkgconfig_includedir='$includedir'
+pkgconfig_datarootdir='$datarootdir'
+pkgconfig_datadir='$datadir'
+pkgconfig_sysconfdir='$sysconfdir'
+pkgconfig_suffix='$ax_create_pkgconfig_suffix'
+pkgconfig_package='$PACKAGE_NAME'
+pkgconfig_libname='$ax_create_pkgconfig_libname'
+pkgconfig_description='$ax_create_pkgconfig_description'
+pkgconfig_version='$ax_create_pkgconfig_version'
+pkgconfig_requires='$ax_create_pkgconfig_requires'
+pkgconfig_libs='$ax_create_pkgconfig_libs'
+pkgconfig_ldflags='$ax_create_pkgconfig_ldflags'
+pkgconfig_cppflags='$ax_create_pkgconfig_cppflags'
+pkgconfig_src_libdir='$ax_create_pkgconfig_src_libdir'
+pkgconfig_src_headers='$ax_create_pkgconfig_src_headers'
+])dnl
+AS_VAR_POPDEF([PKGCONFIG_suffix])dnl
+AS_VAR_POPDEF([PKGCONFIG_libdir])dnl
+AS_VAR_POPDEF([PKGCONFIG_libfile])dnl
+AS_VAR_POPDEF([PKGCONFIG_libname])dnl
+AS_VAR_POPDEF([PKGCONFIG_version])dnl
+AS_VAR_POPDEF([PKGCONFIG_description])dnl
+AS_VAR_POPDEF([PKGCONFIG_requires])dnl
+AS_VAR_POPDEF([PKGCONFIG_pkglibs])dnl
+AS_VAR_POPDEF([PKGCONFIG_libs])dnl
+AS_VAR_POPDEF([PKGCONFIG_ldflags])dnl
+AS_VAR_POPDEF([PKGCONFIG_cppflags])dnl
+AS_VAR_POPDEF([PKGCONFIG_generate])dnl
+AS_VAR_POPDEF([PKGCONFIG_src_libdir])dnl
+AS_VAR_POPDEF([PKGCONFIG_src_headers])dnl
+])
diff --git a/final/lib/External/isl/m4/ax_create_stdint_h.m4 b/final/lib/External/isl/m4/ax_create_stdint_h.m4
new file mode 100644
index 0000000..7b82165
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_create_stdint_h.m4
@@ -0,0 +1,739 @@
+# ===========================================================================
+#           http://autoconf-archive.cryp.to/ax_create_stdint_h.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CREATE_STDINT_H [( HEADER-TO-GENERATE [, HEDERS-TO-CHECK])]
+#
+# DESCRIPTION
+#
+#   the "ISO C9X: 7.18 Integer types <stdint.h>" section requires the
+#   existence of an include file <stdint.h> that defines a set of typedefs,
+#   especially uint8_t,int32_t,uintptr_t. Many older installations will not
+#   provide this file, but some will have the very same definitions in
+#   <inttypes.h>. In other enviroments we can use the inet-types in
+#   <sys/types.h> which would define the typedefs int8_t and u_int8_t
+#   respectivly.
+#
+#   This macros will create a local "_stdint.h" or the headerfile given as
+#   an argument. In many cases that file will just "#include <stdint.h>" or
+#   "#include <inttypes.h>", while in other environments it will provide the
+#   set of basic 'stdint's definitions/typedefs:
+#
+#     int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,intptr_t,uintptr_t
+#     int_least32_t.. int_fast32_t.. intmax_t
+#
+#   which may or may not rely on the definitions of other files, or using
+#   the AC_CHECK_SIZEOF macro to determine the actual sizeof each type.
+#
+#   if your header files require the stdint-types you will want to create an
+#   installable file mylib-int.h that all your other installable header may
+#   include. So if you have a library package named "mylib", just use
+#
+#        AX_CREATE_STDINT_H(mylib-int.h)
+#
+#   in configure.ac and go to install that very header file in Makefile.am
+#   along with the other headers (mylib.h) - and the mylib-specific headers
+#   can simply use "#include <mylib-int.h>" to obtain the stdint-types.
+#
+#   Remember, if the system already had a valid <stdint.h>, the generated
+#   file will include it directly. No need for fuzzy HAVE_STDINT_H things...
+#   (oops, GCC 4.2.x has deliberatly disabled its stdint.h for non-c99
+#   compilation and the c99-mode is not the default. Therefore this macro
+#   will not use the compiler's stdint.h - please complain to the GCC
+#   developers).
+#
+# LAST MODIFICATION
+#
+#   2008-04-12
+#
+# COPYLEFT
+#
+#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+#
+#   This program is free software; you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation; either version 2 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Macro Archive. When you make and
+#   distribute a modified version of the Autoconf Macro, you may extend this
+#   special exception to the GPL to apply to your modified version as well.
+
+AC_DEFUN([AX_CHECK_DATA_MODEL],[
+   AC_CHECK_SIZEOF(char)
+   AC_CHECK_SIZEOF(short)
+   AC_CHECK_SIZEOF(int)
+   AC_CHECK_SIZEOF(long)
+   AC_CHECK_SIZEOF(void*)
+   ac_cv_char_data_model=""
+   ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_char"
+   ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_short"
+   ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_int"
+   ac_cv_long_data_model=""
+   ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_int"
+   ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_long"
+   ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_voidp"
+   AC_MSG_CHECKING([data model])
+   case "$ac_cv_char_data_model/$ac_cv_long_data_model" in
+    122/242)     ac_cv_data_model="IP16"  ; n="standard 16bit machine" ;;
+    122/244)     ac_cv_data_model="LP32"  ; n="standard 32bit machine" ;;
+    122/*)       ac_cv_data_model="i16"   ; n="unusual int16 model" ;;
+    124/444)     ac_cv_data_model="ILP32" ; n="standard 32bit unixish" ;;
+    124/488)     ac_cv_data_model="LP64"  ; n="standard 64bit unixish" ;;
+    124/448)     ac_cv_data_model="LLP64" ; n="unusual 64bit unixish" ;;
+    124/*)       ac_cv_data_model="i32"   ; n="unusual int32 model" ;;
+    128/888)     ac_cv_data_model="ILP64" ; n="unusual 64bit numeric" ;;
+    128/*)       ac_cv_data_model="i64"   ; n="unusual int64 model" ;;
+    222/*2)      ac_cv_data_model="DSP16" ; n="strict 16bit dsptype" ;;
+    333/*3)      ac_cv_data_model="DSP24" ; n="strict 24bit dsptype" ;;
+    444/*4)      ac_cv_data_model="DSP32" ; n="strict 32bit dsptype" ;;
+    666/*6)      ac_cv_data_model="DSP48" ; n="strict 48bit dsptype" ;;
+    888/*8)      ac_cv_data_model="DSP64" ; n="strict 64bit dsptype" ;;
+    222/*|333/*|444/*|666/*|888/*) :
+                 ac_cv_data_model="iDSP"  ; n="unusual dsptype" ;;
+     *)          ac_cv_data_model="none"  ; n="very unusual model" ;;
+   esac
+   AC_MSG_RESULT([$ac_cv_data_model ($ac_cv_long_data_model, $n)])
+])
+
+dnl AX_CHECK_HEADER_STDINT_X([HEADERLIST][,ACTION-IF])
+AC_DEFUN([AX_CHECK_HEADER_STDINT_X],[
+AC_CACHE_CHECK([for stdint uintptr_t], [ac_cv_header_stdint_x],[
+ ac_cv_header_stdint_x="" # the 1997 typedefs (inttypes.h)
+  AC_MSG_RESULT([(..)])
+  for i in m4_ifval([$1],[$1],[stdint.h inttypes.h sys/inttypes.h sys/types.h])
+  do
+   unset ac_cv_type_uintptr_t
+   unset ac_cv_type_uint64_t
+   AC_CHECK_TYPE(uintptr_t,[ac_cv_header_stdint_x=$i],continue,[#include <$i>])
+   AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>])
+   m4_ifvaln([$2],[$2]) break
+  done
+  AC_MSG_CHECKING([for stdint uintptr_t])
+ ])
+])
+
+AC_DEFUN([AX_CHECK_HEADER_STDINT_O],[
+AC_CACHE_CHECK([for stdint uint32_t], [ac_cv_header_stdint_o],[
+ ac_cv_header_stdint_o="" # the 1995 typedefs (sys/inttypes.h)
+  AC_MSG_RESULT([(..)])
+  for i in m4_ifval([$1],[$1],[inttypes.h sys/inttypes.h sys/types.h stdint.h])
+  do
+   unset ac_cv_type_uint32_t
+   unset ac_cv_type_uint64_t
+   AC_CHECK_TYPE(uint32_t,[ac_cv_header_stdint_o=$i],continue,[#include <$i>])
+   AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>])
+   m4_ifvaln([$2],[$2]) break
+   break;
+  done
+  AC_MSG_CHECKING([for stdint uint32_t])
+ ])
+])
+
+AC_DEFUN([AX_CHECK_HEADER_STDINT_U],[
+AC_CACHE_CHECK([for stdint u_int32_t], [ac_cv_header_stdint_u],[
+ ac_cv_header_stdint_u="" # the BSD typedefs (sys/types.h)
+  AC_MSG_RESULT([(..)])
+  for i in m4_ifval([$1],[$1],[sys/types.h inttypes.h sys/inttypes.h]) ; do
+   unset ac_cv_type_u_int32_t
+   unset ac_cv_type_u_int64_t
+   AC_CHECK_TYPE(u_int32_t,[ac_cv_header_stdint_u=$i],continue,[#include <$i>])
+   AC_CHECK_TYPE(u_int64_t,[and64="/u_int64_t"],[and64=""],[#include<$i>])
+   m4_ifvaln([$2],[$2]) break
+   break;
+  done
+  AC_MSG_CHECKING([for stdint u_int32_t])
+ ])
+])
+
+AC_DEFUN([AX_CREATE_STDINT_H],
+[# ------ AX CREATE STDINT H -------------------------------------
+AC_MSG_CHECKING([for stdint types])
+ac_stdint_h=`echo ifelse($1, , _stdint.h, $1)`
+# try to shortcircuit - if the default include path of the compiler
+# can find a "stdint.h" header then we assume that all compilers can.
+AC_CACHE_VAL([ac_cv_header_stdint_t],[
+old_CXXFLAGS="$CXXFLAGS" ; CXXFLAGS=""
+old_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS=""
+old_CFLAGS="$CFLAGS"     ; CFLAGS=""
+AC_TRY_COMPILE([#include <stdint.h>],[int_least32_t v = 0;],
+[ac_cv_stdint_result="(assuming C99 compatible system)"
+ ac_cv_header_stdint_t="stdint.h"; ],
+[ac_cv_header_stdint_t=""])
+if test "$GCC" = "yes" && test ".$ac_cv_header_stdint_t" = "."; then
+CFLAGS="-std=c99"
+AC_TRY_COMPILE([#include <stdint.h>],[int_least32_t v = 0;],
+[AC_MSG_WARN(your GCC compiler has a defunct stdint.h for its default-mode)])
+fi
+CXXFLAGS="$old_CXXFLAGS"
+CPPFLAGS="$old_CPPFLAGS"
+CFLAGS="$old_CFLAGS" ])
+
+v="... $ac_cv_header_stdint_h"
+if test "$ac_stdint_h" = "stdint.h" ; then
+ AC_MSG_RESULT([(are you sure you want them in ./stdint.h?)])
+elif test "$ac_stdint_h" = "inttypes.h" ; then
+ AC_MSG_RESULT([(are you sure you want them in ./inttypes.h?)])
+elif test "_$ac_cv_header_stdint_t" = "_" ; then
+ AC_MSG_RESULT([(putting them into $ac_stdint_h)$v])
+else
+ ac_cv_header_stdint="$ac_cv_header_stdint_t"
+ AC_MSG_RESULT([$ac_cv_header_stdint (shortcircuit)])
+fi
+
+if test "_$ac_cv_header_stdint_t" = "_" ; then # can not shortcircuit..
+
+dnl .....intro message done, now do a few system checks.....
+dnl btw, all old CHECK_TYPE macros do automatically "DEFINE" a type,
+dnl therefore we use the autoconf implementation detail CHECK_TYPE_NEW
+dnl instead that is triggered with 3 or more arguments (see types.m4)
+
+inttype_headers=`echo $2 | sed -e 's/,/ /g'`
+
+ac_cv_stdint_result="(no helpful system typedefs seen)"
+AX_CHECK_HEADER_STDINT_X(dnl
+   stdint.h inttypes.h sys/inttypes.h $inttype_headers,
+   ac_cv_stdint_result="(seen uintptr_t$and64 in $i)")
+
+if test "_$ac_cv_header_stdint_x" = "_" ; then
+AX_CHECK_HEADER_STDINT_O(dnl,
+   inttypes.h sys/inttypes.h stdint.h $inttype_headers,
+   ac_cv_stdint_result="(seen uint32_t$and64 in $i)")
+fi
+
+if test "_$ac_cv_header_stdint_x" = "_" ; then
+if test "_$ac_cv_header_stdint_o" = "_" ; then
+AX_CHECK_HEADER_STDINT_U(dnl,
+   sys/types.h inttypes.h sys/inttypes.h $inttype_headers,
+   ac_cv_stdint_result="(seen u_int32_t$and64 in $i)")
+fi fi
+
+dnl if there was no good C99 header file, do some typedef checks...
+if test "_$ac_cv_header_stdint_x" = "_" ; then
+   AC_MSG_CHECKING([for stdint datatype model])
+   AC_MSG_RESULT([(..)])
+   AX_CHECK_DATA_MODEL
+fi
+
+if test "_$ac_cv_header_stdint_x" != "_" ; then
+   ac_cv_header_stdint="$ac_cv_header_stdint_x"
+elif  test "_$ac_cv_header_stdint_o" != "_" ; then
+   ac_cv_header_stdint="$ac_cv_header_stdint_o"
+elif  test "_$ac_cv_header_stdint_u" != "_" ; then
+   ac_cv_header_stdint="$ac_cv_header_stdint_u"
+else
+   ac_cv_header_stdint="stddef.h"
+fi
+
+AC_MSG_CHECKING([for extra inttypes in chosen header])
+AC_MSG_RESULT([($ac_cv_header_stdint)])
+dnl see if int_least and int_fast types are present in _this_ header.
+unset ac_cv_type_int_least32_t
+unset ac_cv_type_int_fast32_t
+AC_CHECK_TYPE(int_least32_t,,,[#include <$ac_cv_header_stdint>])
+AC_CHECK_TYPE(int_fast32_t,,,[#include<$ac_cv_header_stdint>])
+AC_CHECK_TYPE(intmax_t,,,[#include <$ac_cv_header_stdint>])
+
+fi # shortcircut to system "stdint.h"
+# ------------------ PREPARE VARIABLES ------------------------------
+if test "$GCC" = "yes" ; then
+ac_cv_stdint_message="using gnu compiler "`$CC --version | head -1`
+else
+ac_cv_stdint_message="using $CC"
+fi
+
+AC_MSG_RESULT([make use of $ac_cv_header_stdint in $ac_stdint_h dnl
+$ac_cv_stdint_result])
+
+dnl -----------------------------------------------------------------
+# ----------------- DONE inttypes.h checks START header -------------
+AC_CONFIG_COMMANDS([$ac_stdint_h],[
+AC_MSG_NOTICE(creating $ac_stdint_h : $_ac_stdint_h)
+ac_stdint=$tmp/_stdint.h
+
+echo "#ifndef" $_ac_stdint_h >$ac_stdint
+echo "#define" $_ac_stdint_h "1" >>$ac_stdint
+echo "#ifndef" _GENERATED_STDINT_H >>$ac_stdint
+echo "#define" _GENERATED_STDINT_H '"'$PACKAGE $VERSION'"' >>$ac_stdint
+echo "/* generated $ac_cv_stdint_message */" >>$ac_stdint
+if test "_$ac_cv_header_stdint_t" != "_" ; then
+echo "#define _STDINT_HAVE_STDINT_H" "1" >>$ac_stdint
+echo "#include <stdint.h>" >>$ac_stdint
+echo "#endif" >>$ac_stdint
+echo "#endif" >>$ac_stdint
+else
+
+cat >>$ac_stdint <<STDINT_EOF
+
+/* ................... shortcircuit part ........................... */
+
+#if defined HAVE_STDINT_H || defined _STDINT_HAVE_STDINT_H
+#include <stdint.h>
+#else
+#include <stddef.h>
+
+/* .................... configured part ............................ */
+
+STDINT_EOF
+
+echo "/* whether we have a C99 compatible stdint header file */" >>$ac_stdint
+if test "_$ac_cv_header_stdint_x" != "_" ; then
+  ac_header="$ac_cv_header_stdint_x"
+  echo "#define _STDINT_HEADER_INTPTR" '"'"$ac_header"'"' >>$ac_stdint
+else
+  echo "/* #undef _STDINT_HEADER_INTPTR */" >>$ac_stdint
+fi
+
+echo "/* whether we have a C96 compatible inttypes header file */" >>$ac_stdint
+if  test "_$ac_cv_header_stdint_o" != "_" ; then
+  ac_header="$ac_cv_header_stdint_o"
+  echo "#define _STDINT_HEADER_UINT32" '"'"$ac_header"'"' >>$ac_stdint
+else
+  echo "/* #undef _STDINT_HEADER_UINT32 */" >>$ac_stdint
+fi
+
+echo "/* whether we have a BSD compatible inet types header */" >>$ac_stdint
+if  test "_$ac_cv_header_stdint_u" != "_" ; then
+  ac_header="$ac_cv_header_stdint_u"
+  echo "#define _STDINT_HEADER_U_INT32" '"'"$ac_header"'"' >>$ac_stdint
+else
+  echo "/* #undef _STDINT_HEADER_U_INT32 */" >>$ac_stdint
+fi
+
+echo "" >>$ac_stdint
+
+if test "_$ac_header" != "_" ; then if test "$ac_header" != "stddef.h" ; then
+  echo "#include <$ac_header>" >>$ac_stdint
+  echo "" >>$ac_stdint
+fi fi
+
+echo "/* which 64bit typedef has been found */" >>$ac_stdint
+if test "$ac_cv_type_uint64_t" = "yes" ; then
+echo "#define   _STDINT_HAVE_UINT64_T" "1"  >>$ac_stdint
+else
+echo "/* #undef _STDINT_HAVE_UINT64_T */" >>$ac_stdint
+fi
+if test "$ac_cv_type_u_int64_t" = "yes" ; then
+echo "#define   _STDINT_HAVE_U_INT64_T" "1"  >>$ac_stdint
+else
+echo "/* #undef _STDINT_HAVE_U_INT64_T */" >>$ac_stdint
+fi
+echo "" >>$ac_stdint
+
+echo "/* which type model has been detected */" >>$ac_stdint
+if test "_$ac_cv_char_data_model" != "_" ; then
+echo "#define   _STDINT_CHAR_MODEL" "$ac_cv_char_data_model" >>$ac_stdint
+echo "#define   _STDINT_LONG_MODEL" "$ac_cv_long_data_model" >>$ac_stdint
+else
+echo "/* #undef _STDINT_CHAR_MODEL // skipped */" >>$ac_stdint
+echo "/* #undef _STDINT_LONG_MODEL // skipped */" >>$ac_stdint
+fi
+echo "" >>$ac_stdint
+
+echo "/* whether int_least types were detected */" >>$ac_stdint
+if test "$ac_cv_type_int_least32_t" = "yes"; then
+echo "#define   _STDINT_HAVE_INT_LEAST32_T" "1"  >>$ac_stdint
+else
+echo "/* #undef _STDINT_HAVE_INT_LEAST32_T */" >>$ac_stdint
+fi
+echo "/* whether int_fast types were detected */" >>$ac_stdint
+if test "$ac_cv_type_int_fast32_t" = "yes"; then
+echo "#define   _STDINT_HAVE_INT_FAST32_T" "1" >>$ac_stdint
+else
+echo "/* #undef _STDINT_HAVE_INT_FAST32_T */" >>$ac_stdint
+fi
+echo "/* whether intmax_t type was detected */" >>$ac_stdint
+if test "$ac_cv_type_intmax_t" = "yes"; then
+echo "#define   _STDINT_HAVE_INTMAX_T" "1" >>$ac_stdint
+else
+echo "/* #undef _STDINT_HAVE_INTMAX_T */" >>$ac_stdint
+fi
+echo "" >>$ac_stdint
+
+  cat >>$ac_stdint <<STDINT_EOF
+/* .................... detections part ............................ */
+
+/* whether we need to define bitspecific types from compiler base types */
+#ifndef _STDINT_HEADER_INTPTR
+#ifndef _STDINT_HEADER_UINT32
+#ifndef _STDINT_HEADER_U_INT32
+#define _STDINT_NEED_INT_MODEL_T
+#else
+#define _STDINT_HAVE_U_INT_TYPES
+#endif
+#endif
+#endif
+
+#ifdef _STDINT_HAVE_U_INT_TYPES
+#undef _STDINT_NEED_INT_MODEL_T
+#endif
+
+#ifdef  _STDINT_CHAR_MODEL
+#if     _STDINT_CHAR_MODEL+0 == 122 || _STDINT_CHAR_MODEL+0 == 124
+#ifndef _STDINT_BYTE_MODEL
+#define _STDINT_BYTE_MODEL 12
+#endif
+#endif
+#endif
+
+#ifndef _STDINT_HAVE_INT_LEAST32_T
+#define _STDINT_NEED_INT_LEAST_T
+#endif
+
+#ifndef _STDINT_HAVE_INT_FAST32_T
+#define _STDINT_NEED_INT_FAST_T
+#endif
+
+#ifndef _STDINT_HEADER_INTPTR
+#define _STDINT_NEED_INTPTR_T
+#ifndef _STDINT_HAVE_INTMAX_T
+#define _STDINT_NEED_INTMAX_T
+#endif
+#endif
+
+
+/* .................... definition part ............................ */
+
+/* some system headers have good uint64_t */
+#ifndef _HAVE_UINT64_T
+#if     defined _STDINT_HAVE_UINT64_T  || defined HAVE_UINT64_T
+#define _HAVE_UINT64_T
+#elif   defined _STDINT_HAVE_U_INT64_T || defined HAVE_U_INT64_T
+#define _HAVE_UINT64_T
+typedef u_int64_t uint64_t;
+#endif
+#endif
+
+#ifndef _HAVE_UINT64_T
+/* .. here are some common heuristics using compiler runtime specifics */
+#if defined __STDC_VERSION__ && defined __STDC_VERSION__ >= 199901L
+#define _HAVE_UINT64_T
+#define _HAVE_LONGLONG_UINT64_T
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+
+#elif !defined __STRICT_ANSI__
+#if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__
+#define _HAVE_UINT64_T
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+#elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__
+/* note: all ELF-systems seem to have loff-support which needs 64-bit */
+#if !defined _NO_LONGLONG
+#define _HAVE_UINT64_T
+#define _HAVE_LONGLONG_UINT64_T
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+#endif
+
+#elif defined __alpha || (defined __mips && defined _ABIN32)
+#if !defined _NO_LONGLONG
+typedef long int64_t;
+typedef unsigned long uint64_t;
+#endif
+  /* compiler/cpu type to define int64_t */
+#endif
+#endif
+#endif
+
+#if defined _STDINT_HAVE_U_INT_TYPES
+/* int8_t int16_t int32_t defined by inet code, redeclare the u_intXX types */
+typedef u_int8_t uint8_t;
+typedef u_int16_t uint16_t;
+typedef u_int32_t uint32_t;
+
+/* glibc compatibility */
+#ifndef __int8_t_defined
+#define __int8_t_defined
+#endif
+#endif
+
+#ifdef _STDINT_NEED_INT_MODEL_T
+/* we must guess all the basic types. Apart from byte-adressable system, */
+/* there a few 32-bit-only dsp-systems that we guard with BYTE_MODEL 8-} */
+/* (btw, those nibble-addressable systems are way off, or so we assume) */
+
+dnl   /* have a look at "64bit and data size neutrality" at */
+dnl   /* http://unix.org/version2/whatsnew/login_64bit.html */
+dnl   /* (the shorthand "ILP" types always have a "P" part) */
+
+#if defined _STDINT_BYTE_MODEL
+#if _STDINT_LONG_MODEL+0 == 242
+/* 2:4:2 =  IP16 = a normal 16-bit system                */
+typedef unsigned char   uint8_t;
+typedef unsigned short  uint16_t;
+typedef unsigned long   uint32_t;
+#ifndef __int8_t_defined
+#define __int8_t_defined
+typedef          char    int8_t;
+typedef          short   int16_t;
+typedef          long    int32_t;
+#endif
+#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL == 444
+/* 2:4:4 =  LP32 = a 32-bit system derived from a 16-bit */
+/* 4:4:4 = ILP32 = a normal 32-bit system                */
+typedef unsigned char   uint8_t;
+typedef unsigned short  uint16_t;
+typedef unsigned int    uint32_t;
+#ifndef __int8_t_defined
+#define __int8_t_defined
+typedef          char    int8_t;
+typedef          short   int16_t;
+typedef          int     int32_t;
+#endif
+#elif _STDINT_LONG_MODEL+0 == 484 || _STDINT_LONG_MODEL+0 == 488
+/* 4:8:4 =  IP32 = a 32-bit system prepared for 64-bit    */
+/* 4:8:8 =  LP64 = a normal 64-bit system                 */
+typedef unsigned char   uint8_t;
+typedef unsigned short  uint16_t;
+typedef unsigned int    uint32_t;
+#ifndef __int8_t_defined
+#define __int8_t_defined
+typedef          char    int8_t;
+typedef          short   int16_t;
+typedef          int     int32_t;
+#endif
+/* this system has a "long" of 64bit */
+#ifndef _HAVE_UINT64_T
+#define _HAVE_UINT64_T
+typedef unsigned long   uint64_t;
+typedef          long    int64_t;
+#endif
+#elif _STDINT_LONG_MODEL+0 == 448
+/*      LLP64   a 64-bit system derived from a 32-bit system */
+typedef unsigned char   uint8_t;
+typedef unsigned short  uint16_t;
+typedef unsigned int    uint32_t;
+#ifndef __int8_t_defined
+#define __int8_t_defined
+typedef          char    int8_t;
+typedef          short   int16_t;
+typedef          int     int32_t;
+#endif
+/* assuming the system has a "long long" */
+#ifndef _HAVE_UINT64_T
+#define _HAVE_UINT64_T
+#define _HAVE_LONGLONG_UINT64_T
+typedef unsigned long long uint64_t;
+typedef          long long  int64_t;
+#endif
+#else
+#define _STDINT_NO_INT32_T
+#endif
+#else
+#define _STDINT_NO_INT8_T
+#define _STDINT_NO_INT32_T
+#endif
+#endif
+
+/*
+ * quote from SunOS-5.8 sys/inttypes.h:
+ * Use at your own risk.  As of February 1996, the committee is squarely
+ * behind the fixed sized types; the "least" and "fast" types are still being
+ * discussed.  The probability that the "fast" types may be removed before
+ * the standard is finalized is high enough that they are not currently
+ * implemented.
+ */
+
+#if defined _STDINT_NEED_INT_LEAST_T
+typedef  int8_t    int_least8_t;
+typedef  int16_t   int_least16_t;
+typedef  int32_t   int_least32_t;
+#ifdef _HAVE_UINT64_T
+typedef  int64_t   int_least64_t;
+#endif
+
+typedef uint8_t   uint_least8_t;
+typedef uint16_t  uint_least16_t;
+typedef uint32_t  uint_least32_t;
+#ifdef _HAVE_UINT64_T
+typedef uint64_t  uint_least64_t;
+#endif
+  /* least types */
+#endif
+
+#if defined _STDINT_NEED_INT_FAST_T
+typedef  int8_t    int_fast8_t;
+typedef  int       int_fast16_t;
+typedef  int32_t   int_fast32_t;
+#ifdef _HAVE_UINT64_T
+typedef  int64_t   int_fast64_t;
+#endif
+
+typedef uint8_t   uint_fast8_t;
+typedef unsigned  uint_fast16_t;
+typedef uint32_t  uint_fast32_t;
+#ifdef _HAVE_UINT64_T
+typedef uint64_t  uint_fast64_t;
+#endif
+  /* fast types */
+#endif
+
+#ifdef _STDINT_NEED_INTMAX_T
+#ifdef _HAVE_UINT64_T
+typedef  int64_t       intmax_t;
+typedef uint64_t      uintmax_t;
+#else
+typedef          long  intmax_t;
+typedef unsigned long uintmax_t;
+#endif
+#endif
+
+#ifdef _STDINT_NEED_INTPTR_T
+#ifndef __intptr_t_defined
+#define __intptr_t_defined
+/* we encourage using "long" to store pointer values, never use "int" ! */
+#if   _STDINT_LONG_MODEL+0 == 242 || _STDINT_LONG_MODEL+0 == 484
+typedef  unsigned int   uintptr_t;
+typedef           int    intptr_t;
+#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL+0 == 444
+typedef  unsigned long  uintptr_t;
+typedef           long   intptr_t;
+#elif _STDINT_LONG_MODEL+0 == 448 && defined _HAVE_UINT64_T
+typedef        uint64_t uintptr_t;
+typedef         int64_t  intptr_t;
+#else /* matches typical system types ILP32 and LP64 - but not IP16 or LLP64 */
+typedef  unsigned long  uintptr_t;
+typedef           long   intptr_t;
+#endif
+#endif
+#endif
+
+/* The ISO C99 standard specifies that in C++ implementations these
+   should only be defined if explicitly requested.  */
+#if !defined __cplusplus || defined __STDC_CONSTANT_MACROS
+#ifndef UINT32_C
+
+/* Signed.  */
+# define INT8_C(c)      c
+# define INT16_C(c)     c
+# define INT32_C(c)     c
+# ifdef _HAVE_LONGLONG_UINT64_T
+#  define INT64_C(c)    c ## L
+# else
+#  define INT64_C(c)    c ## LL
+# endif
+
+/* Unsigned.  */
+# define UINT8_C(c)     c ## U
+# define UINT16_C(c)    c ## U
+# define UINT32_C(c)    c ## U
+# ifdef _HAVE_LONGLONG_UINT64_T
+#  define UINT64_C(c)   c ## UL
+# else
+#  define UINT64_C(c)   c ## ULL
+# endif
+
+/* Maximal type.  */
+# ifdef _HAVE_LONGLONG_UINT64_T
+#  define INTMAX_C(c)   c ## L
+#  define UINTMAX_C(c)  c ## UL
+# else
+#  define INTMAX_C(c)   c ## LL
+#  define UINTMAX_C(c)  c ## ULL
+# endif
+
+  /* literalnumbers */
+#endif
+#endif
+
+/* These limits are merily those of a two complement byte-oriented system */
+
+/* Minimum of signed integral types.  */
+# define INT8_MIN               (-128)
+# define INT16_MIN              (-32767-1)
+# define INT32_MIN              (-2147483647-1)
+#ifndef INT64_MIN
+# define INT64_MIN              (-__INT64_C(9223372036854775807)-1)
+#endif
+/* Maximum of signed integral types.  */
+# define INT8_MAX               (127)
+# define INT16_MAX              (32767)
+# define INT32_MAX              (2147483647)
+#ifndef INT64_MAX
+# define INT64_MAX              (__INT64_C(9223372036854775807))
+#endif
+
+/* Maximum of unsigned integral types.  */
+#ifndef UINT8_MAX
+# define UINT8_MAX              (255)
+#endif
+#ifndef UINT16_MAX
+# define UINT16_MAX             (65535)
+#endif
+# define UINT32_MAX             (4294967295U)
+#ifndef UINT64_MAX
+# define UINT64_MAX             (__UINT64_C(18446744073709551615))
+#endif
+
+/* Minimum of signed integral types having a minimum size.  */
+# define INT_LEAST8_MIN         INT8_MIN
+# define INT_LEAST16_MIN        INT16_MIN
+# define INT_LEAST32_MIN        INT32_MIN
+# define INT_LEAST64_MIN        INT64_MIN
+/* Maximum of signed integral types having a minimum size.  */
+# define INT_LEAST8_MAX         INT8_MAX
+# define INT_LEAST16_MAX        INT16_MAX
+# define INT_LEAST32_MAX        INT32_MAX
+# define INT_LEAST64_MAX        INT64_MAX
+
+/* Maximum of unsigned integral types having a minimum size.  */
+# define UINT_LEAST8_MAX        UINT8_MAX
+# define UINT_LEAST16_MAX       UINT16_MAX
+# define UINT_LEAST32_MAX       UINT32_MAX
+# define UINT_LEAST64_MAX       UINT64_MAX
+
+  /* shortcircuit*/
+#endif
+  /* once */
+#endif
+#endif
+STDINT_EOF
+fi
+    if cmp -s $ac_stdint_h $ac_stdint 2>/dev/null; then
+      AC_MSG_NOTICE([$ac_stdint_h is unchanged])
+    else
+      ac_dir=`AS_DIRNAME(["$ac_stdint_h"])`
+      AS_MKDIR_P(["$ac_dir"])
+      rm -f $ac_stdint_h
+      mv $ac_stdint $ac_stdint_h
+    fi
+],[# variables for create stdint.h replacement
+PACKAGE="$PACKAGE"
+VERSION="$VERSION"
+ac_stdint_h="$ac_stdint_h"
+_ac_stdint_h=AS_TR_CPP(_$PACKAGE-$ac_stdint_h)
+ac_cv_stdint_message="$ac_cv_stdint_message"
+ac_cv_header_stdint_t="$ac_cv_header_stdint_t"
+ac_cv_header_stdint_x="$ac_cv_header_stdint_x"
+ac_cv_header_stdint_o="$ac_cv_header_stdint_o"
+ac_cv_header_stdint_u="$ac_cv_header_stdint_u"
+ac_cv_type_uint64_t="$ac_cv_type_uint64_t"
+ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t"
+ac_cv_char_data_model="$ac_cv_char_data_model"
+ac_cv_long_data_model="$ac_cv_long_data_model"
+ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t"
+ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t"
+ac_cv_type_intmax_t="$ac_cv_type_intmax_t"
+])
+])
diff --git a/final/lib/External/isl/m4/ax_cxx_compile_stdcxx.m4 b/final/lib/External/isl/m4/ax_cxx_compile_stdcxx.m4
new file mode 100644
index 0000000..5032bba
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_cxx_compile_stdcxx.m4
@@ -0,0 +1,982 @@
+# ===========================================================================
+#  https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the specified
+#   version of the C++ standard.  If necessary, add switches to CXX and
+#   CXXCPP to enable support.  VERSION may be '11' (for the C++11 standard)
+#   or '14' (for the C++14 standard).
+#
+#   The second argument, if specified, indicates whether you insist on an
+#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+#   -std=c++11).  If neither is specified, you get whatever works, with
+#   preference for an extended mode.
+#
+#   The third argument, if specified 'mandatory' or if left unspecified,
+#   indicates that baseline support for the specified C++ standard is
+#   required and that the macro should error out if no mode with that
+#   support is found.  If specified 'optional', then configuration proceeds
+#   regardless, after defining HAVE_CXX${VERSION} if and only if a
+#   supporting mode is found.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+#   Copyright (c) 2015 Paul Norman <penorman@mac.com>
+#   Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+#   Copyright (c) 2016 Krzesimir Nowak <qdlacz@gmail.com>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.  This file is offered as-is, without any
+#   warranty.
+
+#serial 7
+
+dnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
+dnl  (serial version number 13).
+
+AX_REQUIRE_DEFINED([AC_MSG_WARN])
+AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
+  m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
+        [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
+        [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
+        [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$2], [], [],
+        [$2], [ext], [],
+        [$2], [noext], [],
+        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
+        [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
+  AC_LANG_PUSH([C++])dnl
+  ac_success=no
+  AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
+  ax_cv_cxx_compile_cxx$1,
+  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+    [ax_cv_cxx_compile_cxx$1=yes],
+    [ax_cv_cxx_compile_cxx$1=no])])
+  if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
+    ac_success=yes
+  fi
+
+  m4_if([$2], [noext], [], [dnl
+  if test x$ac_success = xno; then
+    for alternative in ${ax_cxx_compile_alternatives}; do
+      switch="-std=gnu++${alternative}"
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                     $cachevar,
+        [ac_save_CXX="$CXX"
+         CXX="$CXX $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXX="$ac_save_CXX"])
+      if eval test x\$$cachevar = xyes; then
+        CXX="$CXX $switch"
+        if test -n "$CXXCPP" ; then
+          CXXCPP="$CXXCPP $switch"
+        fi
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+
+  m4_if([$2], [ext], [], [dnl
+  if test x$ac_success = xno; then
+    dnl HP's aCC needs +std=c++11 according to:
+    dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
+    dnl Cray's crayCC needs "-h std=c++11"
+    for alternative in ${ax_cxx_compile_alternatives}; do
+      for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
+        cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+        AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                       $cachevar,
+          [ac_save_CXX="$CXX"
+           CXX="$CXX $switch"
+           AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+            [eval $cachevar=yes],
+            [eval $cachevar=no])
+           CXX="$ac_save_CXX"])
+        if eval test x\$$cachevar = xyes; then
+          CXX="$CXX $switch"
+          if test -n "$CXXCPP" ; then
+            CXXCPP="$CXXCPP $switch"
+          fi
+          ac_success=yes
+          break
+        fi
+      done
+      if test x$ac_success = xyes; then
+        break
+      fi
+    done
+  fi])
+  AC_LANG_POP([C++])
+  if test x$ax_cxx_compile_cxx$1_required = xtrue; then
+    if test x$ac_success = xno; then
+      AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
+    fi
+  fi
+  if test x$ac_success = xno; then
+    HAVE_CXX$1=0
+    AC_MSG_NOTICE([No compiler with C++$1 support was found])
+  else
+    HAVE_CXX$1=1
+    AC_DEFINE(HAVE_CXX$1,1,
+              [define if the compiler supports basic C++$1 syntax])
+  fi
+  AC_SUBST(HAVE_CXX$1)
+  m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])])
+])
+
+
+dnl  Test body for checking C++11 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+)
+
+
+dnl  Test body for checking C++14 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+)
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
+)
+
+dnl  Tests for new features in C++11
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+]])
+
+
+dnl  Tests for new features in C++14
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
+
+// If the compiler admits that it is not ready for C++14, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201402L
+
+#error "This is not a C++14 compiler"
+
+#else
+
+namespace cxx14
+{
+
+  namespace test_polymorphic_lambdas
+  {
+
+    int
+    test()
+    {
+      const auto lambda = [](auto&&... args){
+        const auto istiny = [](auto x){
+          return (sizeof(x) == 1UL) ? 1 : 0;
+        };
+        const int aretiny[] = { istiny(args)... };
+        return aretiny[0];
+      };
+      return lambda(1, 1L, 1.0f, '1');
+    }
+
+  }
+
+  namespace test_binary_literals
+  {
+
+    constexpr auto ivii = 0b0000000000101010;
+    static_assert(ivii == 42, "wrong value");
+
+  }
+
+  namespace test_generalized_constexpr
+  {
+
+    template < typename CharT >
+    constexpr unsigned long
+    strlen_c(const CharT *const s) noexcept
+    {
+      auto length = 0UL;
+      for (auto p = s; *p; ++p)
+        ++length;
+      return length;
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("x") == 1UL, "");
+    static_assert(strlen_c("test") == 4UL, "");
+    static_assert(strlen_c("another\0test") == 7UL, "");
+
+  }
+
+  namespace test_lambda_init_capture
+  {
+
+    int
+    test()
+    {
+      auto x = 0;
+      const auto lambda1 = [a = x](int b){ return a + b; };
+      const auto lambda2 = [a = lambda1(x)](){ return a; };
+      return lambda2();
+    }
+
+  }
+
+  namespace test_digit_separators
+  {
+
+    constexpr auto ten_million = 100'000'000;
+    static_assert(ten_million == 100000000, "");
+
+  }
+
+  namespace test_return_type_deduction
+  {
+
+    auto f(int& x) { return x; }
+    decltype(auto) g(int& x) { return x; }
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static constexpr auto value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static constexpr auto value = true;
+    };
+
+    int
+    test()
+    {
+      auto x = 0;
+      static_assert(is_same<int, decltype(f(x))>::value, "");
+      static_assert(is_same<int&, decltype(g(x))>::value, "");
+      return x;
+    }
+
+  }
+
+}  // namespace cxx14
+
+#endif  // __cplusplus >= 201402L
+
+]])
+
+
+dnl  Tests for new features in C++17
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
+
+// If the compiler admits that it is not ready for C++17, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus <= 201402L
+
+#error "This is not a C++17 compiler"
+
+#else
+
+#if defined(__clang__)
+  #define REALLY_CLANG
+#else
+  #if defined(__GNUC__)
+    #define REALLY_GCC
+  #endif
+#endif
+
+#include <initializer_list>
+#include <utility>
+#include <type_traits>
+
+namespace cxx17
+{
+
+#if !defined(REALLY_CLANG)
+  namespace test_constexpr_lambdas
+  {
+
+    // TODO: test it with clang++ from git
+
+    constexpr int foo = [](){return 42;}();
+
+  }
+#endif // !defined(REALLY_CLANG)
+
+  namespace test::nested_namespace::definitions
+  {
+
+  }
+
+  namespace test_fold_expression
+  {
+
+    template<typename... Args>
+    int multiply(Args... args)
+    {
+      return (args * ... * 1);
+    }
+
+    template<typename... Args>
+    bool all(Args... args)
+    {
+      return (args && ...);
+    }
+
+  }
+
+  namespace test_extended_static_assert
+  {
+
+    static_assert (true);
+
+  }
+
+  namespace test_auto_brace_init_list
+  {
+
+    auto foo = {5};
+    auto bar {5};
+
+    static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
+    static_assert(std::is_same<int, decltype(bar)>::value);
+  }
+
+  namespace test_typename_in_template_template_parameter
+  {
+
+    template<template<typename> typename X> struct D;
+
+  }
+
+  namespace test_fallthrough_nodiscard_maybe_unused_attributes
+  {
+
+    int f1()
+    {
+      return 42;
+    }
+
+    [[nodiscard]] int f2()
+    {
+      [[maybe_unused]] auto unused = f1();
+
+      switch (f1())
+      {
+      case 17:
+        f1();
+        [[fallthrough]];
+      case 42:
+        f1();
+      }
+      return f1();
+    }
+
+  }
+
+  namespace test_extended_aggregate_initialization
+  {
+
+    struct base1
+    {
+      int b1, b2 = 42;
+    };
+
+    struct base2
+    {
+      base2() {
+        b3 = 42;
+      }
+      int b3;
+    };
+
+    struct derived : base1, base2
+    {
+        int d;
+    };
+
+    derived d1 {{1, 2}, {}, 4};  // full initialization
+    derived d2 {{}, {}, 4};      // value-initialized bases
+
+  }
+
+  namespace test_general_range_based_for_loop
+  {
+
+    struct iter
+    {
+      int i;
+
+      int& operator* ()
+      {
+        return i;
+      }
+
+      const int& operator* () const
+      {
+        return i;
+      }
+
+      iter& operator++()
+      {
+        ++i;
+        return *this;
+      }
+    };
+
+    struct sentinel
+    {
+      int i;
+    };
+
+    bool operator== (const iter& i, const sentinel& s)
+    {
+      return i.i == s.i;
+    }
+
+    bool operator!= (const iter& i, const sentinel& s)
+    {
+      return !(i == s);
+    }
+
+    struct range
+    {
+      iter begin() const
+      {
+        return {0};
+      }
+
+      sentinel end() const
+      {
+        return {5};
+      }
+    };
+
+    void f()
+    {
+      range r {};
+
+      for (auto i : r)
+      {
+        [[maybe_unused]] auto v = i;
+      }
+    }
+
+  }
+
+  namespace test_lambda_capture_asterisk_this_by_value
+  {
+
+    struct t
+    {
+      int i;
+      int foo()
+      {
+        return [*this]()
+        {
+          return i;
+        }();
+      }
+    };
+
+  }
+
+  namespace test_enum_class_construction
+  {
+
+    enum class byte : unsigned char
+    {};
+
+    byte foo {42};
+
+  }
+
+  namespace test_constexpr_if
+  {
+
+    template <bool cond>
+    int f ()
+    {
+      if constexpr(cond)
+      {
+        return 13;
+      }
+      else
+      {
+        return 42;
+      }
+    }
+
+  }
+
+  namespace test_selection_statement_with_initializer
+  {
+
+    int f()
+    {
+      return 13;
+    }
+
+    int f2()
+    {
+      if (auto i = f(); i > 0)
+      {
+        return 3;
+      }
+
+      switch (auto i = f(); i + 4)
+      {
+      case 17:
+        return 2;
+
+      default:
+        return 1;
+      }
+    }
+
+  }
+
+#if !defined(REALLY_CLANG)
+  namespace test_template_argument_deduction_for_class_templates
+  {
+
+    // TODO: test it with clang++ from git
+
+    template <typename T1, typename T2>
+    struct pair
+    {
+      pair (T1 p1, T2 p2)
+        : m1 {p1},
+          m2 {p2}
+      {}
+
+      T1 m1;
+      T2 m2;
+    };
+
+    void f()
+    {
+      [[maybe_unused]] auto p = pair{13, 42u};
+    }
+
+  }
+#endif // !defined(REALLY_CLANG)
+
+  namespace test_non_type_auto_template_parameters
+  {
+
+    template <auto n>
+    struct B
+    {};
+
+    B<5> b1;
+    B<'a'> b2;
+
+  }
+
+#if !defined(REALLY_CLANG)
+  namespace test_structured_bindings
+  {
+
+    // TODO: test it with clang++ from git
+
+    int arr[2] = { 1, 2 };
+    std::pair<int, int> pr = { 1, 2 };
+
+    auto f1() -> int(&)[2]
+    {
+      return arr;
+    }
+
+    auto f2() -> std::pair<int, int>&
+    {
+      return pr;
+    }
+
+    struct S
+    {
+      int x1 : 2;
+      volatile double y1;
+    };
+
+    S f3()
+    {
+      return {};
+    }
+
+    auto [ x1, y1 ] = f1();
+    auto& [ xr1, yr1 ] = f1();
+    auto [ x2, y2 ] = f2();
+    auto& [ xr2, yr2 ] = f2();
+    const auto [ x3, y3 ] = f3();
+
+  }
+#endif // !defined(REALLY_CLANG)
+
+#if !defined(REALLY_CLANG)
+  namespace test_exception_spec_type_system
+  {
+
+    // TODO: test it with clang++ from git
+
+    struct Good {};
+    struct Bad {};
+
+    void g1() noexcept;
+    void g2();
+
+    template<typename T>
+    Bad
+    f(T*, T*);
+
+    template<typename T1, typename T2>
+    Good
+    f(T1*, T2*);
+
+    static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
+
+  }
+#endif // !defined(REALLY_CLANG)
+
+  namespace test_inline_variables
+  {
+
+    template<class T> void f(T)
+    {}
+
+    template<class T> inline T g(T)
+    {
+      return T{};
+    }
+
+    template<> inline void f<>(int)
+    {}
+
+    template<> int g<>(int)
+    {
+      return 5;
+    }
+
+  }
+
+}  // namespace cxx17
+
+#endif  // __cplusplus <= 201402L
+
+]])
diff --git a/final/lib/External/isl/m4/ax_cxx_compile_stdcxx_11.m4 b/final/lib/External/isl/m4/ax_cxx_compile_stdcxx_11.m4
new file mode 100644
index 0000000..0aadeaf
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_cxx_compile_stdcxx_11.m4
@@ -0,0 +1,39 @@
+# ============================================================================
+#  http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the C++11
+#   standard; if necessary, add switches to CXX and CXXCPP to enable
+#   support.
+#
+#   This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX
+#   macro with the version set to C++11.  The two optional arguments are
+#   forwarded literally as the second and third argument respectively.
+#   Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for
+#   more information.  If you want to use this macro, you also need to
+#   download the ax_cxx_compile_stdcxx.m4 file.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+#   Copyright (c) 2015 Paul Norman <penorman@mac.com>
+#   Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 17
+
+AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX])
+AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])])
diff --git a/final/lib/External/isl/m4/ax_detect_clang.m4 b/final/lib/External/isl/m4/ax_detect_clang.m4
new file mode 100644
index 0000000..d3021e0
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_detect_clang.m4
@@ -0,0 +1,168 @@
+AC_DEFUN([AX_DETECT_CLANG], [
+AC_SUBST(CLANG_CXXFLAGS)
+AC_SUBST(CLANG_LDFLAGS)
+AC_SUBST(CLANG_LIBS)
+AC_PROG_GREP
+AC_PROG_SED
+llvm_config="llvm-config"
+AC_CHECK_PROG([llvm_config_found], ["$llvm_config"], [yes])
+if test "x$with_clang_prefix" != "x"; then
+	llvm_config="$with_clang_prefix/bin/llvm-config"
+	if test -x "$llvm_config"; then
+		llvm_config_found=yes
+	fi
+fi
+if test "$llvm_config_found" != yes; then
+	AC_MSG_ERROR([llvm-config not found])
+fi
+CLANG_CXXFLAGS=`$llvm_config --cxxflags | \
+	$SED -e 's/-Wcovered-switch-default//;s/-gsplit-dwarf//'`
+CLANG_LDFLAGS=`$llvm_config --ldflags`
+targets=`$llvm_config --targets-built`
+components="$targets asmparser bitreader support mc"
+$llvm_config --components | $GREP option > /dev/null 2> /dev/null
+if test $? -eq 0; then
+	components="$components option"
+fi
+CLANG_LIBS=`$llvm_config --libs $components`
+systemlibs=`$llvm_config --system-libs 2> /dev/null | tail -1`
+if test $? -eq 0; then
+	CLANG_LIBS="$CLANG_LIBS $systemlibs"
+fi
+CLANG_PREFIX=`$llvm_config --prefix`
+AC_DEFINE_UNQUOTED(CLANG_PREFIX, ["$CLANG_PREFIX"], [Clang installation prefix])
+
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CLANG_CXXFLAGS $CPPFLAGS"
+AC_LANG_PUSH(C++)
+AC_CHECK_HEADER([clang/Basic/SourceLocation.h], [],
+	[AC_ERROR([clang header file not found])])
+AC_EGREP_HEADER([getDefaultTargetTriple], [llvm/Support/Host.h], [],
+	[AC_DEFINE([getDefaultTargetTriple], [getHostTriple],
+	[Define to getHostTriple for older versions of clang])])
+AC_EGREP_HEADER([getExpansionLineNumber], [clang/Basic/SourceLocation.h], [],
+	[AC_DEFINE([getExpansionLineNumber], [getInstantiationLineNumber],
+	[Define to getInstantiationLineNumber for older versions of clang])])
+AC_EGREP_HEADER([DiagnosticsEngine], [clang/Basic/Diagnostic.h], [],
+	[AC_DEFINE([DiagnosticsEngine], [Diagnostic],
+	[Define to Diagnostic for older versions of clang])])
+AC_EGREP_HEADER([ArrayRef], [clang/Driver/Driver.h],
+	[AC_DEFINE([USE_ARRAYREF], [],
+		[Define if Driver::BuildCompilation takes ArrayRef])])
+AC_EGREP_HEADER([CXXIsProduction], [clang/Driver/Driver.h],
+	[AC_DEFINE([HAVE_CXXISPRODUCTION], [],
+		[Define if Driver constructor takes CXXIsProduction argument])])
+AC_EGREP_HEADER([ IsProduction], [clang/Driver/Driver.h],
+	[AC_DEFINE([HAVE_ISPRODUCTION], [],
+		[Define if Driver constructor takes IsProduction argument])])
+AC_TRY_COMPILE([#include <clang/Driver/Driver.h>], [
+	using namespace clang;
+	DiagnosticsEngine *Diags;
+	new driver::Driver("", "", "", *Diags);
+], [AC_DEFINE([DRIVER_CTOR_TAKES_DEFAULTIMAGENAME], [],
+	      [Define if Driver constructor takes default image name])])
+AC_EGREP_HEADER([void HandleTopLevelDecl\(], [clang/AST/ASTConsumer.h],
+	[AC_DEFINE([HandleTopLevelDeclReturn], [void],
+		   [Return type of HandleTopLevelDeclReturn])
+	 AC_DEFINE([HandleTopLevelDeclContinue], [],
+		   [Return type of HandleTopLevelDeclReturn])],
+	[AC_DEFINE([HandleTopLevelDeclReturn], [bool],
+		   [Return type of HandleTopLevelDeclReturn])
+	 AC_DEFINE([HandleTopLevelDeclContinue], [true],
+		   [Return type of HandleTopLevelDeclReturn])])
+AC_CHECK_HEADER([clang/Basic/DiagnosticOptions.h],
+	[AC_DEFINE([HAVE_BASIC_DIAGNOSTICOPTIONS_H], [],
+		   [Define if clang/Basic/DiagnosticOptions.h exists])])
+AC_CHECK_HEADER([clang/Lex/PreprocessorOptions.h],
+	[AC_DEFINE([HAVE_LEX_PREPROCESSOROPTIONS_H], [],
+		   [Define if clang/Lex/PreprocessorOptions.h exists])], [],
+	[#include <clang/Basic/LLVM.h>])
+AC_TRY_COMPILE([#include <clang/Basic/TargetInfo.h>], [
+	using namespace clang;
+	std::shared_ptr<TargetOptions> TO;
+	DiagnosticsEngine *Diags;
+	TargetInfo::CreateTargetInfo(*Diags, TO);
+], [AC_DEFINE([CREATETARGETINFO_TAKES_SHARED_PTR], [],
+	      [Define if TargetInfo::CreateTargetInfo takes shared_ptr])])
+AC_TRY_COMPILE([#include <clang/Basic/TargetInfo.h>], [
+	using namespace clang;
+	TargetOptions *TO;
+	DiagnosticsEngine *Diags;
+	TargetInfo::CreateTargetInfo(*Diags, TO);
+], [AC_DEFINE([CREATETARGETINFO_TAKES_POINTER], [],
+	      [Define if TargetInfo::CreateTargetInfo takes pointer])])
+AC_TRY_COMPILE([#include <clang/Frontend/CompilerInstance.h>], [
+	using namespace clang;
+	DiagnosticConsumer *client;
+	CompilerInstance *Clang;
+	Clang->createDiagnostics(client);
+], [], [AC_DEFINE([CREATEDIAGNOSTICS_TAKES_ARG], [],
+	[Define if CompilerInstance::createDiagnostics takes argc and argv])])
+AC_TRY_COMPILE([#include <clang/Lex/HeaderSearchOptions.h>], [
+	using namespace clang;
+	HeaderSearchOptions HSO;
+	HSO.AddPath("", frontend::Angled, false, false);
+], [AC_DEFINE([ADDPATH_TAKES_4_ARGUMENTS], [],
+	[Define if HeaderSearchOptions::AddPath takes 4 arguments])])
+AC_EGREP_HEADER([getNumParams],
+	[clang/AST/CanonicalType.h],
+	[AC_DEFINE([getNumArgs], [getNumParams],
+	    [Define to getNumParams for newer versions of clang])
+	 AC_DEFINE([getArgType], [getParamType],
+	    [Define to getParamType for newer versions of clang])])
+AC_EGREP_HEADER([getReturnType],
+	[clang/AST/CanonicalType.h], [],
+	[AC_DEFINE([getReturnType], [getResultType],
+	    [Define to getResultType for older versions of clang])])
+AC_TRY_COMPILE([#include <clang/Frontend/CompilerInstance.h>], [
+	using namespace clang;
+	CompilerInstance *Clang;
+	Clang->createPreprocessor(TU_Complete);
+], [AC_DEFINE([CREATEPREPROCESSOR_TAKES_TUKIND], [],
+[Define if CompilerInstance::createPreprocessor takes TranslationUnitKind])])
+AC_EGREP_HEADER([setMainFileID], [clang/Basic/SourceManager.h],
+	[AC_DEFINE([HAVE_SETMAINFILEID], [],
+	[Define if SourceManager has a setMainFileID method])])
+AC_CHECK_HEADER([llvm/ADT/OwningPtr.h],
+	[AC_DEFINE([HAVE_ADT_OWNINGPTR_H], [],
+		   [Define if llvm/ADT/OwningPtr.h exists])])
+AC_EGREP_HEADER([initializeBuiltins],
+	[clang/Basic/Builtins.h], [],
+	[AC_DEFINE([initializeBuiltins], [InitializeBuiltins],
+		[Define to InitializeBuiltins for older versions of clang])])
+AC_EGREP_HEADER([IK_C], [clang/Frontend/FrontendOptions.h], [],
+	 [AC_DEFINE([IK_C], [InputKind::C],
+	    [Define to InputKind::C for newer versions of clang])])
+AC_TRY_COMPILE([
+	#include <clang/Basic/TargetOptions.h>
+	#include <clang/Lex/PreprocessorOptions.h>
+	#include <clang/Frontend/CompilerInstance.h>
+], [
+	using namespace clang;
+	CompilerInstance *Clang;
+	TargetOptions TO;
+	llvm::Triple T(TO.Triple);
+	PreprocessorOptions PO;
+	CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C,
+			T, PO, LangStandard::lang_unspecified);
+], [AC_DEFINE([SETLANGDEFAULTS_TAKES_5_ARGUMENTS], [],
+	[Define if CompilerInvocation::setLangDefaults takes 5 arguments])])
+AC_TRY_COMPILE([
+	#include <clang/Frontend/CompilerInstance.h>
+	#include <clang/Frontend/CompilerInvocation.h>
+], [
+	using namespace clang;
+	CompilerInvocation *invocation;
+	CompilerInstance *Clang;
+	Clang->setInvocation(std::make_shared<CompilerInvocation>(*invocation));
+], [AC_DEFINE([SETINVOCATION_TAKES_SHARED_PTR], [],
+	[Defined if CompilerInstance::setInvocation takes a shared_ptr])])
+AC_LANG_POP
+CPPFLAGS="$SAVE_CPPFLAGS"
+
+SAVE_LDFLAGS="$LDFLAGS"
+LDFLAGS="$CLANG_LDFLAGS $LDFLAGS"
+AC_SUBST(LIB_CLANG_EDIT)
+AC_CHECK_LIB([clangEdit], [main], [LIB_CLANG_EDIT=-lclangEdit], [])
+LDFLAGS="$SAVE_LDFLAGS"
+])
diff --git a/final/lib/External/isl/m4/ax_detect_git_head.m4 b/final/lib/External/isl/m4/ax_detect_git_head.m4
new file mode 100644
index 0000000..31a6fe3
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_detect_git_head.m4
@@ -0,0 +1,32 @@
+AC_DEFUN([AX_DETECT_GIT_HEAD], [
+	AC_SUBST(GIT_HEAD_ID)
+	AC_SUBST(GIT_HEAD)
+	AC_SUBST(GIT_HEAD_VERSION)
+	if test -f $srcdir/.git; then
+		gitdir=`GIT_DIR=$srcdir/.git git rev-parse --git-dir`
+		GIT_HEAD="$gitdir/index"
+		GIT_REPO="$gitdir"
+		GIT_HEAD_ID=`GIT_DIR=$GIT_REPO git describe --always`
+	elif test -f $srcdir/.git/HEAD; then
+		GIT_HEAD="$srcdir/.git/index"
+		GIT_REPO="$srcdir/.git"
+		GIT_HEAD_ID=`GIT_DIR=$GIT_REPO git describe --always`
+	elif test -f $srcdir/GIT_HEAD_ID; then
+		GIT_HEAD_ID=`cat $srcdir/GIT_HEAD_ID`
+	else
+		mysrcdir=`(cd $srcdir; pwd)`
+		head=`basename $mysrcdir | sed -e 's/.*-//'`
+		head2=`echo $head | sed -e 's/[^0-9a-f]//'`
+		head3=`echo $head2 | sed -e 's/........................................//'`
+		if test "x$head3" = "x" -a "x$head" = "x$head2"; then
+			GIT_HEAD_ID="$head"
+		else
+			GIT_HEAD_ID="UNKNOWN"
+		fi
+	fi
+	if test -z "$GIT_REPO" ; then
+		GIT_HEAD_VERSION="$GIT_HEAD_ID"
+	else
+	    GIT_HEAD_VERSION="\`GIT_DIR=$GIT_REPO git describe --always\`"
+	fi
+])
diff --git a/final/lib/External/isl/m4/ax_detect_gmp.m4 b/final/lib/External/isl/m4/ax_detect_gmp.m4
new file mode 100644
index 0000000..43fa20d
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_detect_gmp.m4
@@ -0,0 +1,48 @@
+AC_DEFUN([AX_DETECT_GMP], [
+AC_DEFINE([USE_GMP_FOR_MP], [], [use gmp to implement isl_int])
+AX_SUBMODULE(gmp,system|build,system)
+case "$with_gmp" in
+system)
+	if test "x$with_gmp_prefix" != "x"; then
+		isl_configure_args="$isl_configure_args --with-gmp=$with_gmp_prefix"
+		MP_CPPFLAGS="-I$with_gmp_prefix/include"
+		MP_LDFLAGS="-L$with_gmp_prefix/lib"
+	fi
+	MP_LIBS=-lgmp
+	SAVE_CPPFLAGS="$CPPFLAGS"
+	SAVE_LDFLAGS="$LDFLAGS"
+	SAVE_LIBS="$LIBS"
+	CPPFLAGS="$MP_CPPFLAGS $CPPFLAGS"
+	LDFLAGS="$MP_LDFLAGS $LDFLAGS"
+	LIBS="$MP_LIBS $LIBS"
+	AC_CHECK_HEADER([gmp.h], [], [AC_ERROR([gmp.h header not found])])
+	AC_CHECK_LIB([gmp], [main], [], [AC_ERROR([gmp library not found])])
+	AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <gmp.h>]], [[
+		mpz_t n, d;
+		if (mpz_divisible_p(n, d))
+			mpz_divexact_ui(n, n, 4);
+	]])], [], [AC_ERROR([gmp library too old])])
+	CPPFLAGS="$SAVE_CPPFLAGS"
+	LDFLAGS="$SAVE_LDFLAGS"
+	LIBS="$SAVE_LIBS"
+	;;
+build)
+	MP_CPPFLAGS="-I$gmp_srcdir -I$with_gmp_builddir"
+	MP_LIBS="$with_gmp_builddir/libgmp.la"
+	;;
+esac
+SAVE_CPPFLAGS="$CPPFLAGS"
+SAVE_LDFLAGS="$LDFLAGS"
+SAVE_LIBS="$LIBS"
+CPPFLAGS="$MP_CPPFLAGS $CPPFLAGS"
+LDFLAGS="$MP_LDFLAGS $LDFLAGS"
+LIBS="$MP_LIBS $LIBS"
+need_get_memory_functions=false
+AC_CHECK_DECLS(mp_get_memory_functions,[],[
+	need_get_memory_functions=true
+],[#include <gmp.h>])
+CPPFLAGS="$SAVE_CPPFLAGS"
+LDFLAGS="$SAVE_LDFLAGS"
+LIBS="$SAVE_LIBS"
+AM_CONDITIONAL(NEED_GET_MEMORY_FUNCTIONS, test x$need_get_memory_functions = xtrue)
+])
diff --git a/final/lib/External/isl/m4/ax_detect_imath.m4 b/final/lib/External/isl/m4/ax_detect_imath.m4
new file mode 100644
index 0000000..9c30a61
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_detect_imath.m4
@@ -0,0 +1,15 @@
+AC_DEFUN([AX_DETECT_IMATH], [
+AC_DEFINE([USE_IMATH_FOR_MP], [], [use imath to implement isl_int])
+
+MP_CPPFLAGS="-I$srcdir/imath_wrap"
+MP_LDFLAGS=""
+MP_LIBS=""
+
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$MP_CPPFLAGS $CPPFLAGS"
+AC_CHECK_HEADER([imath.h], [], [AC_ERROR([imath.h header not found])])
+AC_CHECK_HEADER([gmp_compat.h], [], [AC_ERROR([gmp_compat.h header not found])])
+CPPFLAGS="$SAVE_CPPFLAGS"
+
+AM_CONDITIONAL(NEED_GET_MEMORY_FUNCTIONS, test x = xfalse)
+])
diff --git a/final/lib/External/isl/m4/ax_gcc_archflag.m4 b/final/lib/External/isl/m4/ax_gcc_archflag.m4
new file mode 100644
index 0000000..dedeef4
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_gcc_archflag.m4
@@ -0,0 +1,213 @@
+# ===========================================================================
+#         http://www.nongnu.org/autoconf-archive/ax_gcc_archflag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_GCC_ARCHFLAG([PORTABLE?], [ACTION-SUCCESS], [ACTION-FAILURE])
+#
+# DESCRIPTION
+#
+#   This macro tries to guess the "native" arch corresponding to the target
+#   architecture for use with gcc's -march=arch or -mtune=arch flags. If
+#   found, the cache variable $ax_cv_gcc_archflag is set to this flag and
+#   ACTION-SUCCESS is executed; otherwise $ax_cv_gcc_archflag is is set to
+#   "unknown" and ACTION-FAILURE is executed. The default ACTION-SUCCESS is
+#   to add $ax_cv_gcc_archflag to the end of $CFLAGS.
+#
+#   PORTABLE? should be either [yes] (default) or [no]. In the former case,
+#   the flag is set to -mtune (or equivalent) so that the architecture is
+#   only used for tuning, but the instruction set used is still portable. In
+#   the latter case, the flag is set to -march (or equivalent) so that
+#   architecture-specific instructions are enabled.
+#
+#   The user can specify --with-gcc-arch=<arch> in order to override the
+#   macro's choice of architecture, or --without-gcc-arch to disable this.
+#
+#   When cross-compiling, or if $CC is not gcc, then ACTION-FAILURE is
+#   called unless the user specified --with-gcc-arch manually.
+#
+#   Requires macros: AX_CHECK_COMPILER_FLAGS, AX_GCC_X86_CPUID
+#
+#   (The main emphasis here is on recent CPUs, on the principle that doing
+#   high-performance computing on old hardware is uncommon.)
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+#   Copyright (c) 2008 Matteo Frigo
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+AC_DEFUN([AX_GCC_ARCHFLAG],
+[AC_REQUIRE([AC_PROG_CC])
+AC_REQUIRE([AC_CANONICAL_HOST])
+
+AC_ARG_WITH(gcc-arch, [AC_HELP_STRING([--with-gcc-arch=<arch>], [use architecture <arch> for gcc -march/-mtune, instead of guessing])],
+	ax_gcc_arch=$withval, ax_gcc_arch=yes)
+
+AC_MSG_CHECKING([for gcc architecture flag])
+AC_MSG_RESULT([])
+AC_CACHE_VAL(ax_cv_gcc_archflag,
+[
+ax_cv_gcc_archflag="unknown"
+
+if test "$GCC" = yes; then
+
+if test "x$ax_gcc_arch" = xyes; then
+ax_gcc_arch=""
+if test "$cross_compiling" = no; then
+case $host_cpu in
+  i[[3456]]86*|x86_64*) # use cpuid codes, in part from x86info-1.7 by D. Jones
+     AX_GCC_X86_CPUID(0)
+     AX_GCC_X86_CPUID(1)
+     case $ax_cv_gcc_x86_cpuid_0 in
+       *:756e6547:*:*) # Intel
+          case $ax_cv_gcc_x86_cpuid_1 in
+	    *5[[48]]?:*:*:*) ax_gcc_arch="pentium-mmx pentium" ;;
+	    *5??:*:*:*) ax_gcc_arch=pentium ;;
+	    *6[[3456]]?:*:*:*) ax_gcc_arch="pentium2 pentiumpro" ;;
+	    *6a?:*[[01]]:*:*) ax_gcc_arch="pentium2 pentiumpro" ;;
+	    *6a?:*[[234]]:*:*) ax_gcc_arch="pentium3 pentiumpro" ;;
+	    *6[[9d]]?:*:*:*) ax_gcc_arch="pentium-m pentium3 pentiumpro" ;;
+	    *6[[78b]]?:*:*:*) ax_gcc_arch="pentium3 pentiumpro" ;;
+	    *6??:*:*:*) ax_gcc_arch=pentiumpro ;;
+            *f3[[347]]:*:*:*|*f4[1347]:*:*:*)
+		case $host_cpu in
+                  x86_64*) ax_gcc_arch="nocona pentium4 pentiumpro" ;;
+                  *) ax_gcc_arch="prescott pentium4 pentiumpro" ;;
+                esac ;;
+            *f??:*:*:*) ax_gcc_arch="pentium4 pentiumpro";;
+          esac ;;
+       *:68747541:*:*) # AMD
+          case $ax_cv_gcc_x86_cpuid_1 in
+	    *5[[67]]?:*:*:*) ax_gcc_arch=k6 ;;
+	    *5[[8d]]?:*:*:*) ax_gcc_arch="k6-2 k6" ;;
+	    *5[[9]]?:*:*:*) ax_gcc_arch="k6-3 k6" ;;
+	    *60?:*:*:*) ax_gcc_arch=k7 ;;
+	    *6[[12]]?:*:*:*) ax_gcc_arch="athlon k7" ;;
+	    *6[[34]]?:*:*:*) ax_gcc_arch="athlon-tbird k7" ;;
+	    *67?:*:*:*) ax_gcc_arch="athlon-4 athlon k7" ;;
+	    *6[[68a]]?:*:*:*)
+	       AX_GCC_X86_CPUID(0x80000006) # L2 cache size
+	       case $ax_cv_gcc_x86_cpuid_0x80000006 in
+                 *:*:*[[1-9a-f]]??????:*) # (L2 = ecx >> 16) >= 256
+			ax_gcc_arch="athlon-xp athlon-4 athlon k7" ;;
+                 *) ax_gcc_arch="athlon-4 athlon k7" ;;
+	       esac ;;
+	    *f[[4cef8b]]?:*:*:*) ax_gcc_arch="athlon64 k8" ;;
+	    *f5?:*:*:*) ax_gcc_arch="opteron k8" ;;
+	    *f7?:*:*:*) ax_gcc_arch="athlon-fx opteron k8" ;;
+	    *f??:*:*:*) ax_gcc_arch="k8" ;;
+          esac ;;
+	*:746e6543:*:*) # IDT
+	   case $ax_cv_gcc_x86_cpuid_1 in
+	     *54?:*:*:*) ax_gcc_arch=winchip-c6 ;;
+	     *58?:*:*:*) ax_gcc_arch=winchip2 ;;
+	     *6[[78]]?:*:*:*) ax_gcc_arch=c3 ;;
+	     *69?:*:*:*) ax_gcc_arch="c3-2 c3" ;;
+	   esac ;;
+     esac
+     if test x"$ax_gcc_arch" = x; then # fallback
+	case $host_cpu in
+	  i586*) ax_gcc_arch=pentium ;;
+	  i686*) ax_gcc_arch=pentiumpro ;;
+        esac
+     fi
+     ;;
+
+  sparc*)
+     AC_PATH_PROG([PRTDIAG], [prtdiag], [prtdiag], [$PATH:/usr/platform/`uname -i`/sbin/:/usr/platform/`uname -m`/sbin/])
+     cputype=`(((grep cpu /proc/cpuinfo | cut -d: -f2) ; ($PRTDIAG -v |grep -i sparc) ; grep -i cpu /var/run/dmesg.boot ) | head -n 1) 2> /dev/null`
+     cputype=`echo "$cputype" | tr -d ' -' |tr $as_cr_LETTERS $as_cr_letters`
+     case $cputype in
+         *ultrasparciv*) ax_gcc_arch="ultrasparc4 ultrasparc3 ultrasparc v9" ;;
+         *ultrasparciii*) ax_gcc_arch="ultrasparc3 ultrasparc v9" ;;
+         *ultrasparc*) ax_gcc_arch="ultrasparc v9" ;;
+         *supersparc*|*tms390z5[[05]]*) ax_gcc_arch="supersparc v8" ;;
+         *hypersparc*|*rt62[[056]]*) ax_gcc_arch="hypersparc v8" ;;
+         *cypress*) ax_gcc_arch=cypress ;;
+     esac ;;
+
+  alphaev5) ax_gcc_arch=ev5 ;;
+  alphaev56) ax_gcc_arch=ev56 ;;
+  alphapca56) ax_gcc_arch="pca56 ev56" ;;
+  alphapca57) ax_gcc_arch="pca57 pca56 ev56" ;;
+  alphaev6) ax_gcc_arch=ev6 ;;
+  alphaev67) ax_gcc_arch=ev67 ;;
+  alphaev68) ax_gcc_arch="ev68 ev67" ;;
+  alphaev69) ax_gcc_arch="ev69 ev68 ev67" ;;
+  alphaev7) ax_gcc_arch="ev7 ev69 ev68 ev67" ;;
+  alphaev79) ax_gcc_arch="ev79 ev7 ev69 ev68 ev67" ;;
+
+  powerpc*)
+     cputype=`((grep cpu /proc/cpuinfo | head -n 1 | cut -d: -f2 | cut -d, -f1 | sed 's/ //g') ; /usr/bin/machine ; /bin/machine; grep CPU /var/run/dmesg.boot | head -n 1 | cut -d" " -f2) 2> /dev/null`
+     cputype=`echo $cputype | sed -e 's/ppc//g;s/ *//g'`
+     case $cputype in
+       *750*) ax_gcc_arch="750 G3" ;;
+       *740[[0-9]]*) ax_gcc_arch="$cputype 7400 G4" ;;
+       *74[[4-5]][[0-9]]*) ax_gcc_arch="$cputype 7450 G4" ;;
+       *74[[0-9]][[0-9]]*) ax_gcc_arch="$cputype G4" ;;
+       *970*) ax_gcc_arch="970 G5 power4";;
+       *POWER4*|*power4*|*gq*) ax_gcc_arch="power4 970";;
+       *POWER5*|*power5*|*gr*|*gs*) ax_gcc_arch="power5 power4 970";;
+       603ev|8240) ax_gcc_arch="$cputype 603e 603";;
+       *) ax_gcc_arch=$cputype ;;
+     esac
+     ax_gcc_arch="$ax_gcc_arch powerpc"
+     ;;
+esac
+fi # not cross-compiling
+fi # guess arch
+
+if test "x$ax_gcc_arch" != x -a "x$ax_gcc_arch" != xno; then
+for arch in $ax_gcc_arch; do
+  if test "x[]m4_default([$1],yes)" = xyes; then # if we require portable code
+    flags="-mtune=$arch"
+    # -mcpu=$arch and m$arch generate nonportable code on every arch except
+    # x86.  And some other arches (e.g. Alpha) don't accept -mtune.  Grrr.
+    case $host_cpu in i*86|x86_64*) flags="$flags -mcpu=$arch -m$arch";; esac
+  else
+    flags="-march=$arch -mcpu=$arch -m$arch"
+  fi
+  for flag in $flags; do
+    AX_CHECK_COMPILER_FLAGS($flag, [ax_cv_gcc_archflag=$flag; break])
+  done
+  test "x$ax_cv_gcc_archflag" = xunknown || break
+done
+fi
+
+fi # $GCC=yes
+])
+AC_MSG_CHECKING([for gcc architecture flag])
+AC_MSG_RESULT($ax_cv_gcc_archflag)
+if test "x$ax_cv_gcc_archflag" = xunknown; then
+  m4_default([$3],:)
+else
+  m4_default([$2], [CFLAGS="$CFLAGS $ax_cv_gcc_archflag"])
+fi
+])
diff --git a/final/lib/External/isl/m4/ax_gcc_warn_unused_result.m4 b/final/lib/External/isl/m4/ax_gcc_warn_unused_result.m4
new file mode 100644
index 0000000..a957f8f
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_gcc_warn_unused_result.m4
@@ -0,0 +1,56 @@
+# ===========================================================================
+#    http://www.nongnu.org/autoconf-archive/ax_gcc_warn_unused_result.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_GCC_WARN_UNUSED_RESULT
+#
+# DESCRIPTION
+#
+#   The macro will compile a test program to see whether the compiler does
+#   understand the per-function postfix pragma.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+#
+#   This program is free software; you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation; either version 2 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+AC_DEFUN([AX_GCC_WARN_UNUSED_RESULT],[dnl
+AC_CACHE_CHECK(
+ [whether the compiler supports function __attribute__((__warn_unused_result__))],
+ ax_cv_gcc_warn_unused_result,[
+ AC_TRY_COMPILE([__attribute__((__warn_unused_result__))
+ int f(int i) { return i; }],
+ [],
+ ax_cv_gcc_warn_unused_result=yes, ax_cv_gcc_warn_unused_result=no)])
+ if test "$ax_cv_gcc_warn_unused_result" = yes; then
+   AC_DEFINE([GCC_WARN_UNUSED_RESULT],[__attribute__((__warn_unused_result__))],
+    [most gcc compilers know a function __attribute__((__warn_unused_result__))])
+ fi
+])
diff --git a/final/lib/External/isl/m4/ax_gcc_x86_cpuid.m4 b/final/lib/External/isl/m4/ax_gcc_x86_cpuid.m4
new file mode 100644
index 0000000..5420b09
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_gcc_x86_cpuid.m4
@@ -0,0 +1,77 @@
+# ===========================================================================
+#        http://www.nongnu.org/autoconf-archive/ax_gcc_x86_cpuid.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_GCC_X86_CPUID(OP)
+#
+# DESCRIPTION
+#
+#   On Pentium and later x86 processors, with gcc or a compiler that has a
+#   compatible syntax for inline assembly instructions, run a small program
+#   that executes the cpuid instruction with input OP. This can be used to
+#   detect the CPU type.
+#
+#   On output, the values of the eax, ebx, ecx, and edx registers are stored
+#   as hexadecimal strings as "eax:ebx:ecx:edx" in the cache variable
+#   ax_cv_gcc_x86_cpuid_OP.
+#
+#   If the cpuid instruction fails (because you are running a
+#   cross-compiler, or because you are not using gcc, or because you are on
+#   a processor that doesn't have this instruction), ax_cv_gcc_x86_cpuid_OP
+#   is set to the string "unknown".
+#
+#   This macro mainly exists to be used in AX_GCC_ARCHFLAG.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+#   Copyright (c) 2008 Matteo Frigo
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+AC_DEFUN([AX_GCC_X86_CPUID],
+[AC_REQUIRE([AC_PROG_CC])
+AC_LANG_PUSH([C])
+AC_CACHE_CHECK(for x86 cpuid $1 output, ax_cv_gcc_x86_cpuid_$1,
+ [AC_RUN_IFELSE([AC_LANG_PROGRAM([#include <stdio.h>], [
+     int op = $1, eax, ebx, ecx, edx;
+     FILE *f;
+      __asm__("cpuid"
+        : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+        : "a" (op));
+     f = fopen("conftest_cpuid", "w"); if (!f) return 1;
+     fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx);
+     fclose(f);
+     return 0;
+])],
+     [ax_cv_gcc_x86_cpuid_$1=`cat conftest_cpuid`; rm -f conftest_cpuid],
+     [ax_cv_gcc_x86_cpuid_$1=unknown; rm -f conftest_cpuid],
+     [ax_cv_gcc_x86_cpuid_$1=unknown])])
+AC_LANG_POP([C])
+])
diff --git a/final/lib/External/isl/m4/ax_set_warning_flags.m4 b/final/lib/External/isl/m4/ax_set_warning_flags.m4
new file mode 100644
index 0000000..c64ad7d
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_set_warning_flags.m4
@@ -0,0 +1,17 @@
+dnl Add a set of flags to WARNING_FLAGS, that enable compiler warnings for
+dnl isl. The warnings that are enabled vary with the compiler and only include
+dnl warnings that did not trigger at the time of adding these flags.
+AC_DEFUN([AX_SET_WARNING_FLAGS],[dnl
+	AX_COMPILER_VENDOR
+
+	WARNING_FLAGS=""
+
+	if test "${ax_cv_c_compiler_vendor}" = "clang"; then
+		dnl isl is at the moment clean of -Wall warnings.  If clang adds
+		dnl new warnings to -Wall which cause false positives, the
+		dnl specific warning types will be disabled explicitally (by
+		dnl adding for example -Wno-return-type). To temporarily disable
+		dnl all warnings run configure with CFLAGS=-Wno-all.
+		WARNING_FLAGS="-Wall"
+	fi
+])
diff --git a/final/lib/External/isl/m4/ax_submodule.m4 b/final/lib/External/isl/m4/ax_submodule.m4
new file mode 100644
index 0000000..7cf8995
--- /dev/null
+++ b/final/lib/External/isl/m4/ax_submodule.m4
@@ -0,0 +1,71 @@
+AC_DEFUN([AX_SUBMODULE],
+[
+
+m4_if(m4_bregexp($2,|,choice),choice,
+	[AC_ARG_WITH($1,
+		[AS_HELP_STRING([--with-$1=$2],
+				[Which $1 to use [default=$3]])])])
+case "system" in
+$2)
+	AC_ARG_WITH($1_prefix,
+		    [AS_HELP_STRING([--with-$1-prefix=DIR],
+				    [Prefix of $1 installation])])
+	AC_ARG_WITH($1_exec_prefix,
+		    [AS_HELP_STRING([--with-$1-exec-prefix=DIR],
+				    [Exec prefix of $1 installation])])
+esac
+m4_if(m4_bregexp($2,build,build),build,
+	[AC_ARG_WITH($1_builddir,
+		[AS_HELP_STRING([--with-$1-builddir=DIR],
+				[Location of $1 builddir])])])
+if test "x$with_$1_prefix" != "x" -a "x$with_$1_exec_prefix" = "x"; then
+	with_$1_exec_prefix=$with_$1_prefix
+fi
+if test "x$with_$1_prefix" != "x" -o "x$with_$1_exec_prefix" != "x"; then
+	if test "x$with_$1" != "x" -a "x$with_$1" != "xyes" -a "x$with_$1" != "xsystem"; then
+		AC_MSG_ERROR([Setting $with_$1_prefix implies use of system $1])
+	fi
+	with_$1="system"
+fi
+if test "x$with_$1_builddir" != "x"; then
+	if test "x$with_$1" != "x" -a "x$with_$1" != "xyes" -a "x$with_$1" != "xbuild"; then
+		AC_MSG_ERROR([Setting $with_$1_builddir implies use of build $1])
+	fi
+	with_$1="build"
+	$1_srcdir=`echo @abs_srcdir@ | $with_$1_builddir/config.status --file=-`
+	AC_MSG_NOTICE($1 sources in $$1_srcdir)
+fi
+if test "x$with_$1_exec_prefix" != "x"; then
+	export PKG_CONFIG_PATH="$with_$1_exec_prefix/lib/pkgconfig${PKG_CONFIG_PATH+:$PKG_CONFIG_PATH}"
+fi
+case "$with_$1" in
+$2)
+	;;
+*)
+	case "$3" in
+	bundled)
+		if test -d $srcdir/.git -a \
+			-d $srcdir/$1 -a \
+			! -d $srcdir/$1/.git; then
+			AC_MSG_WARN([git repo detected, but submodule $1 not initialized])
+			AC_MSG_WARN([You may want to run])
+			AC_MSG_WARN([	git submodule init])
+			AC_MSG_WARN([	git submodule update])
+			AC_MSG_WARN([	sh autogen.sh])
+		fi
+		if test -f $srcdir/$1/configure; then
+			with_$1="bundled"
+		else
+			with_$1="no"
+		fi
+		;;
+	*)
+		with_$1="$3"
+		;;
+	esac
+	;;
+esac
+AC_MSG_CHECKING([which $1 to use])
+AC_MSG_RESULT($with_$1)
+
+])
diff --git a/final/lib/External/isl/m4/libtool.m4 b/final/lib/External/isl/m4/libtool.m4
new file mode 100644
index 0000000..ee80844
--- /dev/null
+++ b/final/lib/External/isl/m4/libtool.m4
@@ -0,0 +1,8387 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+#   Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the  same
+# distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+])
+
+# serial 58 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+       [m4_default([$3],
+		   [m4_fatal([Libtool version $1 or higher is required],
+		             63)])],
+       [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+  *\ * | *\	*)
+    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS=$ltmain
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_PREPARE_CC_BASENAME
+# -----------------------
+m4_defun([_LT_PREPARE_CC_BASENAME], [
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+    for cc_temp in @S|@*""; do
+      case $cc_temp in
+        compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+        distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+        \-*) ;;
+        *) break;;
+      esac
+    done
+    func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+])# _LT_PREPARE_CC_BASENAME
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME,
+# but that macro is also expanded into generated libtool script, which
+# arranges for $SED and $ECHO to be set by different means.
+m4_defun([_LT_CC_BASENAME],
+[m4_require([_LT_PREPARE_CC_BASENAME])dnl
+AC_REQUIRE([_LT_DECL_SED])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+func_cc_basename $1
+cc_basename=$func_cc_basename_result
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+m4_require([_LT_CMD_TRUNCATE])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options that allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}"; then
+   setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}"; then
+   setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test set != "${COLLECT_NAMES+set}"; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a '.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+old_CC=$CC
+old_CFLAGS=$CFLAGS
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    _LT_PATH_MAGIC
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from 'configure', and 'config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
+# 'config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain=$ac_aux_dir/ltmain.sh
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the 'libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME.  Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+	[m4_ifval([$1], [$1], [$2])])
+    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+    m4_ifval([$4],
+	[lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+    lt_dict_add_subkey([lt_decl_dict], [$2],
+	[tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+  [0], [m4_fatal([$0: too few arguments: $#])],
+  [1], [m4_fatal([$0: too few arguments: $#: $1])],
+  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+     m4_if([$2], [],
+	   m4_quote(lt_decl_varnames),
+	m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+			lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to 'config.status' so that its
+# declaration there will have the same value as in 'configure'.  VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly.  In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+#    <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags='_LT_TAGS'dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+#    # Some comment about what VAR is for.
+#    visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+					   [description])))[]dnl
+m4_pushdef([_libtool_name],
+    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+    [0], [_libtool_name=[$]$1],
+    [1], [_libtool_name=$lt_[]$1],
+    [2], [_libtool_name=$lt_[]$1],
+    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool'
+# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into 'config.status', and then the shell code to quote escape them in
+# for loops in 'config.status'.  Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+	dnl If the libtool generation code has been placed in $CONFIG_LT,
+	dnl instead of duplicating it all over again into config.status,
+	dnl then we will have config.status run $CONFIG_LT later, so it
+	dnl needs to know what name is stored there:
+        [AC_CONFIG_COMMANDS([libtool],
+            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+    dnl If the libtool generation code is destined for config.status,
+    dnl expand the accumulated commands and init code now:
+    [AC_CONFIG_COMMANDS([libtool],
+        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable.  If COMMENT is supplied, it is inserted after the
+# '#!' sequence but before initialization text begins.  After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script.  The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test 0 = "$lt_write_fail" && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+  echo
+  AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+'$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+  -h, --help      print this help, then exit
+  -V, --version   print version number, then exit
+  -q, --quiet     do not print progress messages
+  -d, --debug     don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test 0 != $[#]
+do
+  case $[1] in
+    --version | --v* | -V )
+      echo "$lt_cl_version"; exit 0 ;;
+    --help | --h* | -h )
+      echo "$lt_cl_help"; exit 0 ;;
+    --debug | --d* | -d )
+      debug=: ;;
+    --quiet | --q* | --silent | --s* | -q )
+      lt_cl_silent=: ;;
+
+    -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try '$[0] --help' for more information.]) ;;
+
+    *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try '$[0] --help' for more information.]) ;;
+  esac
+  shift
+done
+
+if $lt_cl_silent; then
+  exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure.  Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test yes = "$silent" &&
+  lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars.  Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+  m4_if(_LT_TAG, [C], [
+    # See if we are running on zsh, and set the options that allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}"; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile=${ofile}T
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+# Generated automatically by $as_me ($PACKAGE) $VERSION
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+    cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_PREPARE_MUNGE_PATH_LIST
+_LT_PREPARE_CC_BASENAME
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test set != "${COLLECT_NAMES+set}"; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+  _LT_PROG_LTMAIN
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    RM='$RM'
+    ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+  [C],			[_LT_LANG(C)],
+  [C++],		[_LT_LANG(CXX)],
+  [Go],			[_LT_LANG(GO)],
+  [Java],		[_LT_LANG(GCJ)],
+  [Fortran 77],		[_LT_LANG(F77)],
+  [Fortran],		[_LT_LANG(FC)],
+  [Windows Resource],	[_LT_LANG(RC)],
+  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+    [_LT_LANG($1)],
+    [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+  [LT_SUPPORTED_TAG([$1])dnl
+  m4_append([_LT_TAGS], [$1 ])dnl
+  m4_define([_LT_LANG_]$1[_enabled], [])dnl
+  _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_GO.  When it is available in    #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC],     [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+  fi
+fi
+if test -z "$GOC"; then
+  AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+  [LT_LANG(CXX)],
+  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+  [LT_LANG(F77)],
+  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+  [LT_LANG(FC)],
+  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+  [LT_LANG(GCJ)],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+    [LT_LANG(GCJ)],
+    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+      [LT_LANG(GCJ)],
+      [m4_ifdef([AC_PROG_GCJ],
+	[m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([A][M_PROG_GCJ],
+	[m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([LT_PROG_GCJ],
+	[m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+  [LT_LANG(GO)],
+  [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+  [LT_LANG(RC)],
+  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+  case $host_os in
+    rhapsody* | darwin*)
+    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+    AC_CHECK_TOOL([LIPO], [lipo], [:])
+    AC_CHECK_TOOL([OTOOL], [otool], [:])
+    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+    _LT_DECL([], [DSYMUTIL], [1],
+      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+    _LT_DECL([], [NMEDIT], [1],
+      [Tool to change global to local symbols on Mac OS X])
+    _LT_DECL([], [LIPO], [1],
+      [Tool to manipulate fat objects and archives on Mac OS X])
+    _LT_DECL([], [OTOOL], [1],
+      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+    _LT_DECL([], [OTOOL64], [1],
+      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+      [lt_cv_apple_cc_single_mod=no
+      if test -z "$LT_MULTI_MODULE"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	# If there is a non-empty error log, and "single_module"
+	# appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	# Otherwise, if the output was created with a 0 exit code from
+	# the compiler, it worked.
+	elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi])
+
+    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+      [lt_cv_ld_exported_symbols_list],
+      [lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+	[lt_cv_ld_exported_symbols_list=yes],
+	[lt_cv_ld_exported_symbols_list=no])
+	LDFLAGS=$save_LDFLAGS
+    ])
+
+    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+      [lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+      $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+    ])
+    case $host_os in
+    rhapsody* | darwin1.[[012]])
+      _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+	10.[[012]][[,.]]*)
+	  _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test yes = "$lt_cv_apple_cc_single_mod"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test yes = "$lt_cv_ld_exported_symbols_list"; then
+      _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
+    fi
+    if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_automatic, $1)=yes
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  if test yes = "$lt_cv_ld_force_load"; then
+    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+    m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+                  [FC],  [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+  else
+    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  fi
+  _LT_TAGVAR(link_all_deplibs, $1)=yes
+  _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined
+  case $cc_basename in
+     ifort*|nagfor*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test yes = "$_lt_dar_can_shared"; then
+    output_verbose_link_cmd=func_echo_all
+    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+    m4_if([$1], [CXX],
+[   if test yes != "$lt_cv_apple_cc_single_mod"; then
+      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
+      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
+    fi
+],[])
+  else
+  _LT_TAGVAR(ld_shlibs, $1)=no
+  fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test set = "${lt_cv_aix_libpath+set}"; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+  lt_aix_libpath_sed='[
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }]'
+  _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi],[])
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib
+  fi
+  ])
+  aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script that will find a shell with a builtin
+# printf (that we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+case $ECHO in
+  printf*) AC_MSG_RESULT([printf]) ;;
+  print*) AC_MSG_RESULT([print -r]) ;;
+  *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test "X`printf %s $ECHO`" = "X$ECHO" \
+      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@],
+  [Search for dependent libraries within DIR (or the compiler's sysroot
+   if not specified).])],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted.  We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case $with_sysroot in #(
+ yes)
+   if test yes = "$GCC"; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   AC_MSG_RESULT([$with_sysroot])
+   AC_MSG_ERROR([The sysroot must be an absolute path.])
+   ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and where our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+  [AS_HELP_STRING([--disable-libtool-lock],
+    [avoid locking (might break parallel builds)])])
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out what ABI is being produced by ac_compile, and set mode
+  # options accordingly.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE=32
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE=64
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    if test yes = "$lt_cv_prog_gnu_ld"; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+mips64*-*linux*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    emul=elf
+    case `/usr/bin/file conftest.$ac_objext` in
+      *32-bit*)
+	emul="${emul}32"
+	;;
+      *64-bit*)
+	emul="${emul}64"
+	;;
+    esac
+    case `/usr/bin/file conftest.$ac_objext` in
+      *MSB*)
+	emul="${emul}btsmip"
+	;;
+      *LSB*)
+	emul="${emul}ltsmip"
+	;;
+    esac
+    case `/usr/bin/file conftest.$ac_objext` in
+      *N32*)
+	emul="${emul}n32"
+	;;
+    esac
+    LD="${LD-ld} -m $emul"
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.  Note that the listed cases only cover the
+  # situations where additional linker options are needed (such as when
+  # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+  # vice versa); the common cases where no linker options are needed do
+  # not appear in the list.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    case `/usr/bin/file conftest.o` in
+	      *x86-64*)
+		LD="${LD-ld} -m elf32_x86_64"
+		;;
+	      *)
+		LD="${LD-ld} -m elf_i386"
+		;;
+	    esac
+	    ;;
+	  powerpc64le-*linux*)
+	    LD="${LD-ld} -m elf32lppclinux"
+	    ;;
+	  powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  powerpcle-*linux*)
+	    LD="${LD-ld} -m elf64lppc"
+	    ;;
+	  powerpc-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS=$CFLAGS
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test yes != "$lt_cv_cc_needs_belf"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS=$SAVE_CFLAGS
+  fi
+  ;;
+*-*solaris*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*|x86_64-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD=${LD-ld}_sol2
+        fi
+        ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks=$enable_libtool_lock
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+  [lt_cv_ar_at_file=no
+   AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+     [echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([lt_ar_try])
+      if test 0 -eq "$ac_status"; then
+	# Ensure the archiver fails upon bogus file names.
+	rm -f conftest.$ac_objext libconftest.a
+	AC_TRY_EVAL([lt_ar_try])
+	if test 0 -ne "$ac_status"; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+     ])
+  ])
+
+if test no = "$lt_cv_ar_at_file"; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+  [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+    [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  bitrig* | openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+    [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+    [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"  ## exclude from sc_useless_quotes_in_assignment
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $RM conftest*
+])
+
+if test yes = "[$]$2"; then
+    m4_if([$5], , :, [$5])
+else
+    m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                  [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS=$LDFLAGS
+   LDFLAGS="$LDFLAGS $3"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS=$save_LDFLAGS
+])
+
+if test yes = "[$]$2"; then
+    m4_if([$4], , :, [$4])
+else
+    m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring=ABCD
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[	 ]]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len" && \
+       test undefined != "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test X`env echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test 17 != "$i" # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+])
+if test -n "$lt_cv_sys_max_cmd_len"; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+    [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test yes = "$cross_compiling"; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}]
+_LT_EOF
+  if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_dlunknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test yes != "$enable_dlopen"; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen=load_add_on
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen=LoadLibrary
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen=dlopen
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+    # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[
+    lt_cv_dlopen=dyld
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+    ;;
+
+  tpf*)
+    # Don't try to run any link tests for TPF.  We know it's impossible
+    # because TPF is a cross-compiler, and we know how we open DSOs.
+    lt_cv_dlopen=dlopen
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=no
+    ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+	  [lt_cv_dlopen=shl_load],
+      [AC_CHECK_LIB([dld], [shl_load],
+	    [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld],
+	[AC_CHECK_FUNC([dlopen],
+	      [lt_cv_dlopen=dlopen],
+	  [AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],
+	    [AC_CHECK_LIB([svld], [dlopen],
+		  [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld],
+	      [AC_CHECK_LIB([dld], [dld_link],
+		    [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld])
+	      ])
+	    ])
+	  ])
+	])
+      ])
+    ;;
+  esac
+
+  if test no = "$lt_cv_dlopen"; then
+    enable_dlopen=no
+  else
+    enable_dlopen=yes
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS=$CPPFLAGS
+    test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS=$LDFLAGS
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS=$LIBS
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+	  lt_cv_dlopen_self, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test yes = "$lt_cv_dlopen_self"; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+	  lt_cv_dlopen_self_static, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS=$save_CPPFLAGS
+    LDFLAGS=$save_LDFLAGS
+    LIBS=$save_LIBS
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+	 [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+	 [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+	 [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+	[Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links=nottested
+if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test no = "$hard_links"; then
+    AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+         [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/",
+  [Define to the sub-directory where libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+   test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then
+
+  # We can hardcode non-existent directories.
+  if test no != "$_LT_TAGVAR(hardcode_direct, $1)" &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" &&
+     test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test relink = "$_LT_TAGVAR(hardcode_action, $1)" ||
+   test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test yes = "$shlibpath_overrides_runpath" ||
+     test no = "$enable_shared"; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+    [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP"; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      AC_MSG_RESULT([yes])
+    else
+      AC_MSG_RESULT([no])
+    fi
+    ;;
+  *)
+    AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_PREPARE_MUNGE_PATH_LIST
+# ---------------------------
+# Make sure func_munge_path_list() is defined correctly.
+m4_defun([_LT_PREPARE_MUNGE_PATH_LIST],
+[[# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+#       string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+#       string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+#       string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+#       "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+#       VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+    case x@S|@2 in
+    x)
+        ;;
+    *:)
+        eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\"
+        ;;
+    x:*)
+        eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\"
+        ;;
+    *::*)
+        eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+        eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\"
+        ;;
+    *)
+        eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\"
+        ;;
+    esac
+}
+]])# _LT_PREPARE_PATH_LIST
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+	[], [
+if test yes = "$GCC"; then
+  case $host_os in
+    darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+    *) lt_awk_arg='/^libraries:/' ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
+    *) lt_sed_strip_eq='s|=/|/|g' ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary...
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  # ...but if some path component already ends with the multilib dir we assume
+  # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+  case "$lt_multi_os_dir; $lt_search_path_spec " in
+  "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+    lt_multi_os_dir=
+    ;;
+  esac
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+    elif test -n "$lt_multi_os_dir"; then
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS = " "; FS = "/|\n";} {
+  lt_foo = "";
+  lt_count = 0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo = "/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=.so
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+AC_ARG_VAR([LT_SYS_LIBRARY_PATH],
+[User-defined run-time library search path.])
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='$libname$release$shared_ext$major'
+  ;;
+
+aix[[4-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test ia64 = "$host_cpu"; then
+    # AIX 5 supports IA64
+    library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line '#! .'.  This would cause the generated library to
+    # depend on '.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # Using Import Files as archive members, it is possible to support
+    # filename-based versioning of shared library archives on AIX. While
+    # this would work for both with and without runtime linking, it will
+    # prevent static linking of such archives. So we do filename-based
+    # shared library versioning with .so extension only, which is used
+    # when both runtime linking and shared linking is enabled.
+    # Unfortunately, runtime linking may impact performance, so we do
+    # not want this to be the default eventually. Also, we use the
+    # versioned .so libs for executables only if there is the -brtl
+    # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+    # To allow for filename-based versioning support, we need to create
+    # libNAME.so.V as an archive file, containing:
+    # *) an Import File, referring to the versioned filename of the
+    #    archive as well as the shared archive member, telling the
+    #    bitwidth (32 or 64) of that shared object, and providing the
+    #    list of exported symbols of that shared object, eventually
+    #    decorated with the 'weak' keyword
+    # *) the shared object with the F_LOADONLY flag set, to really avoid
+    #    it being seen by the linker.
+    # At run time we better use the real file rather than another symlink,
+    # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+    case $with_aix_soname,$aix_use_runtimelinking in
+    # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    aix,yes) # traditional libtool
+      dynamic_linker='AIX unversionable lib.so'
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      ;;
+    aix,no) # traditional AIX only
+      dynamic_linker='AIX lib.a[(]lib.so.V[)]'
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      ;;
+    svr4,*) # full svr4 only
+      dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,yes) # both, prefer svr4
+      dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # unpreferred sharedlib libNAME.a needs extra handling
+      postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+      postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,no) # both, prefer aix
+      dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]"
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+      postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+      postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+      ;;
+    esac
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='$libname$shared_ext'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+m4_if([$1], [],[
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+    library_names_spec='$libname.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec=$LIB
+      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$major$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[[23]].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      soname_spec='$libname$release$shared_ext$major'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    if test 32 = "$HPUX_IA64_MODE"; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux32
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux64
+    fi
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[[3-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test yes = "$lt_cv_prog_gnu_ld"; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+  sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+linux*android*)
+  version_type=none # Android doesn't support versioned libraries.
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext'
+  soname_spec='$libname$release$shared_ext'
+  finish_cmds=
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  dynamic_linker='Android linker'
+  # Don't embed -rpath directories since the linker doesn't support them.
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+    [lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+	 LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+	 [lt_cv_shlibpath_overrides_runpath=yes])])
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+    ])
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Ideally, we could use ldconfig to report *all* directores which are
+  # searched for libraries, however this is still not possible.  Aside from not
+  # being certain /sbin/ldconfig is available, command
+  # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+  # even though it is searched at run-time.  Try to do the best guess by
+  # appending ld.so.conf contents (and includes) to the search path.
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsdelf*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='NetBSD ld.elf_so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd* | bitrig*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec=/usr/lib
+  need_lib_prefix=no
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    need_version=no
+  else
+    need_version=yes
+  fi
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+os2*)
+  libname_spec='$name'
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
+  need_lib_prefix=no
+  # OS/2 can only load a DLL with a base name of 8 characters or less.
+  soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+    v=$($ECHO $release$versuffix | tr -d .-);
+    n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+    $ECHO $n$v`$shared_ext'
+  library_names_spec='${libname}_dll.$libext'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=BEGINLIBPATH
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  postinstall_cmds='base_file=`basename \$file`~
+    dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+    dldir=$destdir/`dirname \$dlpath`~
+    test -d \$dldir || mkdir -p \$dldir~
+    $install_prog $dir/$dlname \$dldir/$dlname~
+    chmod a+x \$dldir/$dlname~
+    if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+      eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+    fi'
+  postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+    dlpath=$dir/\$dldll~
+    $RM \$dlpath'
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test yes = "$with_gnu_ld"; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec; then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+    soname_spec='$libname$shared_ext.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=sco
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test yes = "$with_gnu_ld"; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test no = "$dynamic_linker" && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test yes = "$GCC"; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+  sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
+fi
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+  sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
+fi
+
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+    [Variables whose values should be saved in libtool wrapper scripts and
+    restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+    [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+    [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+    [[List of archive names.  First name is the real one, the rest are links.
+    The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+    [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+    [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+    [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+    [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+    [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+    [[As "finish_cmds", except a single script fragment to be evaled but
+    not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+    [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+    [Compile-time system search path for libraries])
+_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2],
+    [Detected run-time system search path for libraries])
+_LT_DECL([], [configure_time_lt_sys_library_path], [2],
+    [Explicit LT_SYS_LIBRARY_PATH set during ./configure time])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program that can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD=$MAGIC_CMD
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="m4_if([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS=$lt_save_ifs
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$1"; then
+      lt_cv_path_MAGIC_CMD=$ac_dir/"$1"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS=$lt_save_ifs
+  MAGIC_CMD=$lt_save_MAGIC_CMD
+  ;;
+esac])
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+	 [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program that can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+    [AS_HELP_STRING([--with-gnu-ld],
+	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test no = "$withval" || with_gnu_ld=yes],
+    [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test yes = "$GCC"; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return, which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD=$ac_prog
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test yes = "$with_gnu_ld"; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS=$lt_save_ifs
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD=$ac_dir/$ac_prog
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test no != "$with_gnu_ld" && break
+	;;
+      *)
+	test yes != "$with_gnu_ld" && break
+	;;
+      esac
+    fi
+  done
+  IFS=$lt_save_ifs
+else
+  lt_cv_path_LD=$LD # Let the user override the test with a path.
+fi])
+LD=$lt_cv_path_LD
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test yes != "$GCC"; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test yes = "$GCC"; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_PATH_DD
+# -----------
+# find a working dd
+m4_defun([_LT_PATH_DD],
+[AC_CACHE_CHECK([for a working dd], [ac_cv_path_lt_DD],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd],
+[if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+  cmp -s conftest.i conftest.out \
+  && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi])
+rm -f conftest.i conftest2.i conftest.out])
+])# _LT_PATH_DD
+
+
+# _LT_CMD_TRUNCATE
+# ----------------
+# find command to truncate a binary pipe
+m4_defun([_LT_CMD_TRUNCATE],
+[m4_require([_LT_PATH_DD])
+AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+  cmp -s conftest.i conftest.out \
+  && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"])
+_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1],
+  [Command to truncate a binary pipe])
+])# _LT_CMD_TRUNCATE
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# 'unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  if ( file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[[3-9]]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd* | netbsdelf*-gnu)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd* | bitrig*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+os2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+    [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+    [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+    [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+    [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM=$NM
+else
+  lt_nm_to_check=${ac_tool_prefix}nm
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS=$lt_save_ifs
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm=$ac_dir/$lt_tmp_nm
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the 'sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	# MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+	case $build_os in
+	mingw*) lt_bad_file=conftest.nm/nofile ;;
+	*) lt_bad_file=/dev/null ;;
+	esac
+	case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+	*$lt_bad_file* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break 2
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break 2
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS=$lt_save_ifs
+  done
+  : ${lt_cv_path_NM=no}
+fi])
+if test no != "$lt_cv_path_NM"; then
+  NM=$lt_cv_path_NM
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+    case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols -headers"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+  AC_SUBST([DUMPBIN])
+  if test : != "$DUMPBIN"; then
+    NM=$DUMPBIN
+  fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+  [lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+  cat conftest.out >&AS_MESSAGE_LOG_FD
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh;
+  # decide which one to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd=$ECHO
+  ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+    [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+  [lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*])
+if test yes != "$lt_cv_path_mainfest_tool"; then
+  MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# _LT_DLL_DEF_P([FILE])
+# ---------------------
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with func_dll_def_p in the libtool script
+AC_DEFUN([_LT_DLL_DEF_P],
+[dnl
+  test DEF = "`$SED -n dnl
+    -e '\''s/^[[	 ]]*//'\'' dnl Strip leading whitespace
+    -e '\''/^\(;.*\)*$/d'\'' dnl      Delete empty lines and comments
+    -e '\''s/^\(EXPORTS\|LIBRARY\)\([[	 ]].*\)*$/DEF/p'\'' dnl
+    -e q dnl                          Only consider the first "real" line
+    $1`" dnl
+])# _LT_DLL_DEF_P
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw)
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM=-lm)
+  ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test yes = "$GCC"; then
+  case $cc_basename in
+  nvcc*)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+  esac
+
+  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+	[Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*)
+  if test ia64 = "$host_cpu"; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris*)
+  symcode='[[BDRT]]'
+  ;;
+sco3.2v5*)
+  symcode='[[DT]]'
+  ;;
+sysv4.2uw2*)
+  symcode='[[DT]]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[[ABDT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  # Gets list of data symbols to import.
+  lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+  # Adjust the below global symbol transforms to fixup imported variables.
+  lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+  lt_c_name_hook=" -e 's/^I .* \(.*\)$/  {\"\1\", (void *) 0},/p'"
+  lt_c_name_lib_hook="\
+  -e 's/^I .* \(lib.*\)$/  {\"\1\", (void *) 0},/p'\
+  -e 's/^I .* \(.*\)$/  {\"lib\1\", (void *) 0},/p'"
+else
+  # Disable hooks by default.
+  lt_cv_sys_global_symbol_to_import=
+  lt_cdecl_hook=
+  lt_c_name_hook=
+  lt_c_name_lib_hook=
+fi
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/  {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"lib\1\", (void *) \&\1},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function,
+    # D for any global variable and I for any imported variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK ['"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+"     /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+"     /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+"     {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+"     s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx]"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[	 ]]\($symcode$symcode*\)[[	 ]][[	 ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT@&t@_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data.  */
+# define LT@&t@_DLSYM_CONST
+#else
+# define LT@&t@_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT@&t@_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_globsym_save_LIBS=$LIBS
+	  lt_globsym_save_CFLAGS=$CFLAGS
+	  LIBS=conftstm.$ac_objext
+	  CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+	  if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then
+	    pipe_works=yes
+	  fi
+	  LIBS=$lt_globsym_save_LIBS
+	  CFLAGS=$lt_globsym_save_CFLAGS
+	else
+	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test yes = "$pipe_works"; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+    [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+    [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1],
+    [Transform the output of nm into a list of symbols to manually relocate])
+_LT_DECL([global_symbol_to_c_name_address],
+    [lt_cv_sys_global_symbol_to_c_name_address], [1],
+    [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+    [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([nm_interface], [lt_cv_nm_interface], [1],
+    [The name lister interface])
+_LT_DECL([], [nm_file_list_spec], [1],
+    [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+  # C++ specific cases for pic, static, wl, etc.
+  if test yes = "$GXX"; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test ia64 = "$host_cpu"; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the '-m68020' flag to GCC prevents building anything better,
+            # like '-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      case $host_os in
+      os2*)
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+	;;
+      esac
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[[4-9]]*)
+	# All AIX code is PIC.
+	if test ia64 = "$host_cpu"; then
+	  # AIX 5 now supports IA64 processor
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	else
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      mingw* | cygwin* | os2* | pw32* | cegcc*)
+	# This hack is so that the source file can tell whether it is being
+	# built for inclusion in a dll (and should export symbols for example).
+	m4_if([$1], [GCJ], [],
+	  [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+	    if test ia64 != "$host_cpu"; then
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    ;;
+	  ecpc* )
+	    # old Intel C++ for x86_64, which still supported -KPIC.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  icpc* )
+	    # Intel C++, used to be incompatible with GCC.
+	    # ICC 10 doesn't accept -KPIC any more.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+	    # IBM XL 8.0, 9.0 on PPC and BlueGene
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd* | netbsdelf*-gnu)
+	;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+	;;
+    esac
+  fi
+],
+[
+  if test yes = "$GCC"; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test ia64 = "$host_cpu"; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the '-m68020' flag to GCC prevents building anything better,
+            # like '-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      case $host_os in
+      os2*)
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+      if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test ia64 = "$host_cpu"; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      case $cc_basename in
+      nagfor*)
+        # NAG Fortran compiler
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      esac
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      case $host_os in
+      os2*)
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+	;;
+      esac
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+      case $cc_basename in
+      # old Intel for x86_64, which still supported -KPIC.
+      ecc*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	;;
+      tcc*)
+	# Fabrice Bellard et al's Tiny C Compiler
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  ;;
+        *Intel*\ [[CF]]*Compiler*)
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	  ;;
+	*Portland\ Group*)
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    rdos*)
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    unicos*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+case $host_os in
+  # For platforms that do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+	[Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+	[How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+  $lt_tmp_static_flag,
+  [],
+  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+	[Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  case $host_os in
+  aix[[4-9]]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+    # Without the "-l" option, or with the "-B" option, AIX nm treats
+    # weak defined symbols like other global defined symbols, whereas
+    # GNU nm marks them as "W".
+    # While the 'weak' keyword is ignored in the Export File, we need
+    # it in the Import File for the 'aix-soname' feature, so we have
+    # to replace the "-B" option with "-P" for AIX nm.
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds
+    ;;
+  cygwin* | mingw* | cegcc*)
+    case $cc_basename in
+    cl*)
+      _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+      ;;
+    *)
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+      ;;
+    esac
+    ;;
+  linux* | k*bsd*-gnu | gnu*)
+    _LT_TAGVAR(link_all_deplibs, $1)=no
+    ;;
+  *)
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+    ;;
+  esac
+], [
+  runpath_var=
+  _LT_TAGVAR(allow_undefined_flag, $1)=
+  _LT_TAGVAR(always_export_symbols, $1)=no
+  _LT_TAGVAR(archive_cmds, $1)=
+  _LT_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_TAGVAR(compiler_needs_object, $1)=no
+  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(hardcode_automatic, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_TAGVAR(inherit_rpath, $1)=no
+  _LT_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_TAGVAR(module_cmds, $1)=
+  _LT_TAGVAR(module_expsym_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ' (' and ')$', so one must not match beginning or
+  # end of line.  Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+  # as well as any symbol that contains 'd'.
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test yes != "$GCC"; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd* | bitrig*)
+    with_gnu_ld=no
+    ;;
+  linux* | k*bsd*-gnu | gnu*)
+    _LT_TAGVAR(link_all_deplibs, $1)=no
+    ;;
+  esac
+
+  _LT_TAGVAR(ld_shlibs, $1)=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test yes = "$with_gnu_ld"; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+	  *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test yes = "$lt_use_gnu_ld_interface"; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='$wl'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+    else
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[[3-9]]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test ia64 != "$host_cpu"; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=no
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file, use it as
+	# is; otherwise, prepend EXPORTS...
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+          cp $export_symbols $output_objdir/$soname.def;
+        else
+          echo EXPORTS > $output_objdir/$soname.def;
+          cat $export_symbols >> $output_objdir/$soname.def;
+        fi~
+        $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    haiku*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      shrext_cmds=.dll
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	prefix_cmds="$SED"~
+	if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	  prefix_cmds="$prefix_cmds -e 1d";
+	fi~
+	prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      ;;
+
+    interix[[3-9]]*)
+      _LT_TAGVAR(hardcode_direct, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test linux-dietlibc = "$host_os"; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test no = "$tmp_diet"
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+	  tmp_sharedflag='--shared' ;;
+        nagfor*)                        # NAGFOR 5.3
+          tmp_sharedflag='-Wl,-shared' ;;
+	xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+
+        if test yes = "$supports_anon_versioning"; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+            cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+            echo "local: *; };" >> $output_objdir/$libname.ver~
+            $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	tcc*)
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic'
+	  ;;
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test yes = "$supports_anon_versioning"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+              cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+              echo "local: *; };" >> $output_objdir/$libname.ver~
+              $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then
+      runpath_var=
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	_LT_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix[[4-9]]*)
+      if test ia64 = "$host_cpu"; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to GNU nm, but means don't demangle to AIX nm.
+	# Without the "-l" option, or with the "-B" option, AIX nm treats
+	# weak defined symbols like other global defined symbols, whereas
+	# GNU nm marks them as "W".
+	# While the 'weak' keyword is ignored in the Export File, we need
+	# it in the Import File for the 'aix-soname' feature, so we have
+	# to replace the "-B" option with "-P" for AIX nm.
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+	else
+	  _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# have runtime linking enabled, and use it for executables.
+	# For shared libraries, we enable/disable runtime linking
+	# depending on the kind of the shared library created -
+	# when "with_aix_soname,aix_use_runtimelinking" is:
+	# "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "aix,yes"  lib.so          shared, rtl:yes, for executables
+	#            lib.a           static archive
+	# "both,no"  lib.so.V(shr.o) shared, rtl:yes
+	#            lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a(lib.so.V) shared, rtl:no
+	# "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a           static archive
+	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+	    # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	    # so we don't have lib.a shared libs to link our executables.
+	    # We have to force runtime linking in this case.
+	    aix_use_runtimelinking=yes
+	    LDFLAGS="$LDFLAGS -Wl,-brtl"
+	  fi
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_TAGVAR(archive_cmds, $1)=''
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+      case $with_aix_soname,$aix_use_runtimelinking in
+      aix,*) ;; # traditional, no import file
+      svr4,* | *,yes) # use import file
+	# The Import File defines what to hardcode.
+	_LT_TAGVAR(hardcode_direct, $1)=no
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+	;;
+      esac
+
+      if test yes = "$GCC"; then
+	case $host_os in aix4.[[012]]|aix4.[[012]].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`$CC -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test yes = "$aix_use_runtimelinking"; then
+	  shared_flag="$shared_flag "'$wl-G'
+	fi
+	# Need to ensure runtime linking is disabled for the traditional
+	# shared library, or the linker may eventually find shared libraries
+	# /with/ Import File - we do not want to mix them.
+	shared_flag_aix='-shared'
+	shared_flag_svr4='-shared $wl-G'
+      else
+	# not using gcc
+	if test ia64 = "$host_cpu"; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test yes = "$aix_use_runtimelinking"; then
+	    shared_flag='$wl-G'
+	  else
+	    shared_flag='$wl-bM:SRE'
+	  fi
+	  shared_flag_aix='$wl-bM:SRE'
+	  shared_flag_svr4='$wl-G'
+	fi
+      fi
+
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        _LT_SYS_MODULE_PATH_AIX([$1])
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+      else
+	if test ia64 = "$host_cpu"; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
+	  _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 _LT_SYS_MODULE_PATH_AIX([$1])
+	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+	  if test yes = "$with_gnu_ld"; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	  fi
+	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	  # -brtl affects multiple linker settings, -berok does not and is overridden later
+	  compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+	  if test svr4 != "$with_aix_soname"; then
+	    # This is similar to how AIX traditionally builds its shared libraries.
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	  fi
+	  if test aix != "$with_aix_soname"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	  else
+	    # used by -dlpreopen to get the symbols
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	  fi
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[[45]]*)
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	_LT_TAGVAR(always_export_symbols, $1)=yes
+	_LT_TAGVAR(file_list_spec, $1)='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=.dll
+	# FIXME: Setting linknames here is a bad hack.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+            cp "$export_symbols" "$output_objdir/$soname.def";
+            echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+          else
+            $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+          fi~
+          $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+          linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	_LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+	_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+          lt_tool_outputfile="@TOOL_OUTPUT@"~
+          case $lt_outputfile in
+            *.exe|*.EXE) ;;
+            *)
+              lt_outputfile=$lt_outputfile.exe
+              lt_tool_outputfile=$lt_tool_outputfile.exe
+              ;;
+          esac~
+          if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+            $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+            $RM "$lt_outputfile.manifest";
+          fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=.dll
+	# FIXME: Setting linknames here is a bad hack.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	_LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	# FIXME: Should let the user specify the lib program.
+	_LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+      _LT_DARWIN_LINKER_FEATURES($1)
+      ;;
+
+    dgux*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+      ;;
+
+    hpux10*)
+      if test yes,no = "$GCC,$with_gnu_ld"; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test no = "$with_gnu_ld"; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	_LT_TAGVAR(hardcode_minus_L, $1)=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test yes,no = "$GCC,$with_gnu_ld"; then
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	m4_if($1, [], [
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  _LT_LINKER_OPTION([if $CC understands -b],
+	    _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+	    [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+	    [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+	  [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+	  ;;
+	esac
+      fi
+      if test no = "$with_gnu_ld"; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  ;;
+	*)
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+	  [lt_cv_irix_exported_symbol],
+	  [save_LDFLAGS=$LDFLAGS
+	   LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
+	   AC_LINK_IFELSE(
+	     [AC_LANG_SOURCE(
+	        [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+			      [C++], [[int foo (void) { return 0; }]],
+			      [Fortran 77], [[
+      subroutine foo
+      end]],
+			      [Fortran], [[
+      subroutine foo
+      end]])])],
+	      [lt_cv_irix_exported_symbol=yes],
+	      [lt_cv_irix_exported_symbol=no])
+           LDFLAGS=$save_LDFLAGS])
+	if test yes = "$lt_cv_irix_exported_symbol"; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
+	fi
+	_LT_TAGVAR(link_all_deplibs, $1)=no
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(inherit_rpath, $1)=yes
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    linux*)
+      case $cc_basename in
+      tcc*)
+	# Fabrice Bellard et al's Tiny C Compiler
+	_LT_TAGVAR(ld_shlibs, $1)=yes
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	;;
+      esac
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd* | bitrig*)
+      if test -f /usr/libexec/ld.so; then
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+	else
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	fi
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      shrext_cmds=.dll
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	prefix_cmds="$SED"~
+	if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	  prefix_cmds="$prefix_cmds -e 1d";
+	fi~
+	prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      ;;
+
+    osf3*)
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+          $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+      if test yes = "$GCC"; then
+	wlarc='$wl'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+          $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+            $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='$wl'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+            $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands '-z linker_flag'.  GCC discards it without '$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test yes = "$GCC"; then
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+	else
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test sequent = "$host_vendor"; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+        ;;
+	motorola)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	_LT_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We CANNOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+      _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+
+    if test sni = "$host_vendor"; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+    [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test yes,yes = "$GCC,$enable_shared"; then
+    case $_LT_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+	[lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+	[$RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+	  pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+	  _LT_TAGVAR(allow_undefined_flag, $1)=
+	  if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+	  then
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	  else
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  fi
+	  _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+	])
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+    [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+    [enable_shared_with_static_runtimes], [0],
+    [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+    [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+    [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+    [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+    [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+    [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+    [Commands used to build a loadable module if different from building
+    a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+    [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+    [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+    [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+    [Flag to hardcode $libdir into a binary during linking.
+    This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+    [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+    [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
+    DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+    [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
+    DIR into the resulting binary and the resulting library dependency is
+    "absolute", i.e impossible to change by setting $shlibpath_var if the
+    library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+    [Set to "yes" if building a shared library automatically hardcodes DIR
+    into the library and all subsequent libraries and executables linked
+    against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+    [Set to yes if linker adds runtime paths of dependent libraries
+    to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+    [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+    [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+    [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+    [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+    [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+    [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+    [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+    [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl    [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC=$CC
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_SYS_DYNAMIC_LINKER($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+  LT_SYS_DLOPEN_SELF
+  _LT_CMD_STRIPLIB
+
+  # Report what library types will actually be built
+  AC_MSG_CHECKING([if libtool supports shared libraries])
+  AC_MSG_RESULT([$can_build_shared])
+
+  AC_MSG_CHECKING([whether to build shared libraries])
+  test no = "$can_build_shared" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test yes = "$enable_shared" && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[[4-9]]*)
+    if test ia64 != "$host_cpu"; then
+      case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+      yes,aix,yes) ;;			# shared object as lib.so file only
+      yes,svr4,*) ;;			# shared object as lib.so archive member only
+      yes,*) enable_static=no ;;	# shared object in lib.a archive as well
+      esac
+    fi
+    ;;
+  esac
+  AC_MSG_RESULT([$enable_shared])
+
+  AC_MSG_CHECKING([whether to build static libraries])
+  # Make sure either enable_shared or enable_static is yes.
+  test yes = "$enable_shared" || enable_static=yes
+  AC_MSG_RESULT([$enable_static])
+
+  _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC=$lt_save_CC
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test no != "$CXX" &&
+    ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
+    (test g++ != "$CXX"))); then
+  AC_PROG_CXXCPP
+else
+  _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_caught_CXX_error"; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_CFLAGS=$CFLAGS
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  CFLAGS=$CXXFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test yes = "$GXX"; then
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+    else
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+    fi
+
+    if test yes = "$GXX"; then
+      # Set up default GNU C++ configuration
+
+      LT_PATH_LD
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test yes = "$with_gnu_ld"; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='$wl'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+	  $GREP 'no-whole-archive' > /dev/null; then
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+        else
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+    _LT_TAGVAR(ld_shlibs, $1)=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+      aix[[4-9]]*)
+        if test ia64 = "$host_cpu"; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # have runtime linking enabled, and use it for executables.
+          # For shared libraries, we enable/disable runtime linking
+          # depending on the kind of the shared library created -
+          # when "with_aix_soname,aix_use_runtimelinking" is:
+          # "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "aix,yes"  lib.so          shared, rtl:yes, for executables
+          #            lib.a           static archive
+          # "both,no"  lib.so.V(shr.o) shared, rtl:yes
+          #            lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a(lib.so.V) shared, rtl:no
+          # "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a           static archive
+          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	    for ld_flag in $LDFLAGS; do
+	      case $ld_flag in
+	      *-brtl*)
+	        aix_use_runtimelinking=yes
+	        break
+	        ;;
+	      esac
+	    done
+	    if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+	      # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	      # so we don't have lib.a shared libs to link our executables.
+	      # We have to force runtime linking in this case.
+	      aix_use_runtimelinking=yes
+	      LDFLAGS="$LDFLAGS -Wl,-brtl"
+	    fi
+	    ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        _LT_TAGVAR(archive_cmds, $1)=''
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+        case $with_aix_soname,$aix_use_runtimelinking in
+        aix,*) ;;	# no import file
+        svr4,* | *,yes) # use import file
+          # The Import File defines what to hardcode.
+          _LT_TAGVAR(hardcode_direct, $1)=no
+          _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+          ;;
+        esac
+
+        if test yes = "$GXX"; then
+          case $host_os in aix4.[[012]]|aix4.[[012]].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+	  collect2name=`$CC -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	    # We have reworked collect2
+	    :
+	  else
+	    # We have old collect2
+	    _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	    # It fails to find uninstalled libraries when the uninstalled
+	    # path is not listed in the libpath.  Setting hardcode_minus_L
+	    # to unsupported forces relinking
+	    _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+          esac
+          shared_flag='-shared'
+	  if test yes = "$aix_use_runtimelinking"; then
+	    shared_flag=$shared_flag' $wl-G'
+	  fi
+	  # Need to ensure runtime linking is disabled for the traditional
+	  # shared library, or the linker may eventually find shared libraries
+	  # /with/ Import File - we do not want to mix them.
+	  shared_flag_aix='-shared'
+	  shared_flag_svr4='-shared $wl-G'
+        else
+          # not using gcc
+          if test ia64 = "$host_cpu"; then
+	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	  # chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+          else
+	    if test yes = "$aix_use_runtimelinking"; then
+	      shared_flag='$wl-G'
+	    else
+	      shared_flag='$wl-bM:SRE'
+	    fi
+	    shared_flag_aix='$wl-bM:SRE'
+	    shared_flag_svr4='$wl-G'
+          fi
+        fi
+
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+	# export.
+        _LT_TAGVAR(always_export_symbols, $1)=yes
+	if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          # The "-G" linker flag allows undefined symbols.
+          _LT_TAGVAR(no_undefined_flag, $1)='-bernotok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          _LT_SYS_MODULE_PATH_AIX([$1])
+          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+        else
+          if test ia64 = "$host_cpu"; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
+	    _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+          else
+	    # Determine the default libpath from the value encoded in an
+	    # empty executable.
+	    _LT_SYS_MODULE_PATH_AIX([$1])
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+	    # Warning - without using the other run time loading flags,
+	    # -berok will link without error, but may produce a broken library.
+	    _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+	    _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+	    if test yes = "$with_gnu_ld"; then
+	      # We only use this code for GNU lds that support --whole-archive.
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+	    else
+	      # Exported symbols can be pulled into shared objects from archives
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	    fi
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	    # -brtl affects multiple linker settings, -berok does not and is overridden later
+	    compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+	    if test svr4 != "$with_aix_soname"; then
+	      # This is similar to how AIX traditionally builds its shared
+	      # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+	      _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	    fi
+	    if test aix != "$with_aix_soname"; then
+	      _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	    else
+	      # used by -dlpreopen to get the symbols
+	      _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	    fi
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
+          fi
+        fi
+        ;;
+
+      beos*)
+	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	  # support --undefined.  This deserves some investigation.  FIXME
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+	  # FIXME: insert proper C++ library support
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	  ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+	case $GXX,$cc_basename in
+	,cl* | no,cl*)
+	  # Native MSVC
+	  # hardcode_libdir_flag_spec is actually meaningless, as there is
+	  # no search path for DLLs.
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  _LT_TAGVAR(always_export_symbols, $1)=yes
+	  _LT_TAGVAR(file_list_spec, $1)='@'
+	  # Tell ltmain to make .lib files, not .a files.
+	  libext=lib
+	  # Tell ltmain to make .dll files, not .so files.
+	  shrext_cmds=.dll
+	  # FIXME: Setting linknames here is a bad hack.
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+              cp "$export_symbols" "$output_objdir/$soname.def";
+              echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+            else
+              $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+            fi~
+            $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+            linknames='
+	  # The linker will not automatically build a static lib if we build a DLL.
+	  # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	  # Don't use ranlib
+	  _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+	  _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+            lt_tool_outputfile="@TOOL_OUTPUT@"~
+            case $lt_outputfile in
+              *.exe|*.EXE) ;;
+              *)
+                lt_outputfile=$lt_outputfile.exe
+                lt_tool_outputfile=$lt_tool_outputfile.exe
+                ;;
+            esac~
+            func_to_tool_file "$lt_outputfile"~
+            if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+              $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+              $RM "$lt_outputfile.manifest";
+            fi'
+	  ;;
+	*)
+	  # g++
+	  # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+	  # as there is no search path for DLLs.
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  _LT_TAGVAR(always_export_symbols, $1)=no
+	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+	  if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    # If the export-symbols file already is a .def file, use it as
+	    # is; otherwise, prepend EXPORTS...
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+              cp $export_symbols $output_objdir/$soname.def;
+            else
+              echo EXPORTS > $output_objdir/$soname.def;
+              cat $export_symbols >> $output_objdir/$soname.def;
+            fi~
+            $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	  ;;
+	esac
+	;;
+      darwin* | rhapsody*)
+        _LT_DARWIN_LINKER_FEATURES($1)
+	;;
+
+      os2*)
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	_LT_TAGVAR(hardcode_minus_L, $1)=yes
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	shrext_cmds=.dll
+	_LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	  $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	  $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	  $ECHO EXPORTS >> $output_objdir/$libname.def~
+	  emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	  $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	  emximp -o $lib $output_objdir/$libname.def'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	  $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	  $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	  $ECHO EXPORTS >> $output_objdir/$libname.def~
+	  prefix_cmds="$SED"~
+	  if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	    prefix_cmds="$prefix_cmds -e 1d";
+	  fi~
+	  prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	  cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	  $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	  emximp -o $lib $output_objdir/$libname.def'
+	_LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          ghcx*)
+	    # Green Hills C++ Compiler
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      freebsd2.*)
+        # C++ shared libraries reported to be fairly broken before
+	# switch to ELF
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      freebsd-elf*)
+        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+        ;;
+
+      haiku*)
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        ;;
+
+      hpux9*)
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+				             # but as the default
+				             # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            _LT_TAGVAR(ld_shlibs, $1)=no
+            ;;
+          aCC*)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            ;;
+          *)
+            if test yes = "$GXX"; then
+              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              _LT_TAGVAR(ld_shlibs, $1)=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test no = "$with_gnu_ld"; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            _LT_TAGVAR(hardcode_direct, $1)=no
+            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+            ;;
+          *)
+            _LT_TAGVAR(hardcode_direct, $1)=yes
+            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+					         # but as the default
+					         # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          aCC*)
+	    case $host_cpu in
+	      hppa*64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      ia64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      *)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	    esac
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+          *)
+	    if test yes = "$GXX"; then
+	      if test no = "$with_gnu_ld"; then
+	        case $host_cpu in
+	          hppa*64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          ia64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          *)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	        esac
+	      fi
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      interix[[3-9]]*)
+	_LT_TAGVAR(hardcode_direct, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+	# Instead, shared libraries are loaded at an image base (0x10000000 by
+	# default) and relocated if they conflict, which is a slow very memory
+	# consuming and fragmenting process.  To avoid this, we pick a random,
+	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+	    # SGI C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    if test yes = "$GXX"; then
+	      if test no = "$with_gnu_ld"; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	      else
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
+	      fi
+	    fi
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+	    ;;
+        esac
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(inherit_rpath, $1)=yes
+        ;;
+
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+	    ;;
+	  icpc* | ecpc* )
+	    # Intel C++
+	    with_gnu_ld=yes
+	    # version 8.0 and above of icpc choke on multiply defined symbols
+	    # if we add $predep_objects and $postdep_objects, however 7.1 and
+	    # earlier do not add the objects themselves.
+	    case `$CC -V 2>&1` in
+	      *"Version 7."*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	      *)  # Version 8.0 or newer
+	        tmp_idyn=
+	        case $host_cpu in
+		  ia64*) tmp_idyn=' -i_dynamic';;
+		esac
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	    esac
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+	    ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+	    case `$CC -V` in
+	    *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+	      _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+               compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+	      _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+                $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+                $RANLIB $oldlib'
+	      _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+	      ;;
+	    *) # Version 6 and above use weak symbols
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+	      ;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+            ;;
+	  cxx*)
+	    # Compaq C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname  -o $lib $wl-retain-symbols-file $wl$export_symbols'
+
+	    runpath_var=LD_RUN_PATH
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+	    ;;
+	  xl* | mpixl* | bgxl*)
+	    # IBM XL 8.0 on PPC, with GNU ld
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	    if test yes = "$supports_anon_versioning"; then
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+                cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+                echo "local: *; };" >> $output_objdir/$libname.ver~
+                $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+	    fi
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	      _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+	      # Not sure whether something based on
+	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	      # would be better.
+	      output_verbose_link_cmd='func_echo_all'
+
+	      # Archives containing C++ object files must be created using
+	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	      # necessary to make sure instantiated templates are included
+	      # in the archive.
+	      _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	  *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	esac
+	;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+	  wlarc=
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	fi
+	# Workaround some broken pre-1.5 toolchains
+	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+	;;
+
+      *nto* | *qnx*)
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+	;;
+
+      openbsd* | bitrig*)
+	if test -f /usr/libexec/ld.so; then
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+	  fi
+	  output_verbose_link_cmd=func_echo_all
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Archives containing C++ object files must be created using
+	    # the KAI C++ compiler.
+	    case $host in
+	      osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+	      *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+	    esac
+	    ;;
+          RCC*)
+	    # Rational C++ 2.4.1
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          cxx*)
+	    case $host in
+	      osf3*)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+		;;
+	      *)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+                  echo "-hidden">> $lib.exp~
+                  $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
+                  $RM $lib.exp'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+		;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+	  *)
+	    if test yes,no = "$GXX,$with_gnu_ld"; then
+	      _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+	      case $host in
+	        osf3*)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+		  ;;
+	        *)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+		  ;;
+	      esac
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+	      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	      # Commands to make compiler produce verbose output that lists
+	      # what "hidden" libraries, object files and flags are used when
+	      # linking a shared library.
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.x
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          lcc*)
+	    # Lucid
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+	    _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+              $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	    _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	    case $host_os in
+	      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+	      *)
+		# The compiler driver will combine and reorder linker options,
+		# but understands '-z linker_flag'.
+	        # Supported since Solaris 2.6 (maybe 2.5.1?)
+		_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	        ;;
+	    esac
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+	    output_verbose_link_cmd='func_echo_all'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	    ;;
+          gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+
+	    # The C++ compiler must be used to create the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    # GNU C++ compiler with Solaris linker
+	    if test yes,no = "$GXX,$with_gnu_ld"; then
+	      _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs'
+	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+                  $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      else
+	        # g++ 2.7 appears to require '-G' NOT '-shared' on this
+	        # platform.
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+                  $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      fi
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
+	      case $host_os in
+		solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+		*)
+		  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+		  ;;
+	      esac
+	    fi
+	    ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+	# Note: We CANNOT use -z defs as we might desire, because we do not
+	# link with -lc, and that would cause any symbols used from libc to
+	# always be unresolved, which means just about no library would
+	# ever link correctly.  If we're not using GNU ld we use -z text
+	# though, which does catch some bad symbols but isn't as heavy-handed
+	# as -z defs.
+	_LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+	_LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
+	_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+	_LT_TAGVAR(link_all_deplibs, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
+	runpath_var='LD_RUN_PATH'
+
+	case $cc_basename in
+          CC*)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+              '"$_LT_TAGVAR(old_archive_cmds, $1)"
+	    _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+              '"$_LT_TAGVAR(reload_cmds, $1)"
+	    ;;
+	  *)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+	    # NonStop-UX NCC 3.20
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+    esac
+
+    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+    test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
+
+    _LT_TAGVAR(GCC, $1)=$GXX
+    _LT_TAGVAR(LD, $1)=$LD
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test yes != "$_lt_caught_CXX_error"
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+  case @S|@2 in
+  .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;;
+  *)  func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;;
+  esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case $prev$p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test x-L = "$p" ||
+          test x-R = "$p"; then
+	 prev=$p
+	 continue
+       fi
+
+       # Expand the sysroot to ease extracting the directories later.
+       if test -z "$prev"; then
+         case $p in
+         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+         esac
+       fi
+       case $p in
+       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+       esac
+       if test no = "$pre_test_object_deps_done"; then
+	 case $prev in
+	 -L | -R)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+	     _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p
+	   else
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+	   _LT_TAGVAR(postdeps, $1)=$prev$p
+	 else
+	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p"
+	 fi
+       fi
+       prev=
+       ;;
+
+    *.lto.$objext) ;; # Ignore GCC LTO objects
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test no = "$pre_test_object_deps_done"; then
+	 if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+	   _LT_TAGVAR(predep_objects, $1)=$p
+	 else
+	   _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+	 fi
+       else
+	 if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+	   _LT_TAGVAR(postdep_objects, $1)=$p
+	 else
+	   _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  _LT_TAGVAR(predep_objects,$1)=
+  _LT_TAGVAR(postdep_objects,$1)=
+  _LT_TAGVAR(postdeps,$1)=
+  ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+    [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+    [Dependencies to place before and after the objects being linked to
+    create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+    [The library search path used internally by the compiler when linking
+    a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test no = "$F77"; then
+  _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_disable_F77"; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${F77-"f77"}
+  CFLAGS=$FFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+  GCC=$G77
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test no = "$can_build_shared" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test yes = "$enable_shared" && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test ia64 != "$host_cpu"; then
+	  case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+	  yes,aix,yes) ;;		# shared object as lib.so file only
+	  yes,svr4,*) ;;		# shared object as lib.so archive member only
+	  yes,*) enable_static=no ;;	# shared object in lib.a archive as well
+	  esac
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test yes = "$enable_shared" || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)=$G77
+    _LT_TAGVAR(LD, $1)=$LD
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_F77"
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test no = "$FC"; then
+  _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_disable_FC"; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${FC-"f95"}
+  CFLAGS=$FCFLAGS
+  compiler=$CC
+  GCC=$ac_cv_fc_compiler_gnu
+
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test no = "$can_build_shared" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test yes = "$enable_shared" && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test ia64 != "$host_cpu"; then
+	  case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+	  yes,aix,yes) ;;		# shared object as lib.so file only
+	  yes,svr4,*) ;;		# shared object as lib.so archive member only
+	  yes,*) enable_static=no ;;	# shared object in lib.a archive as well
+	  esac
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test yes = "$enable_shared" || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu
+    _LT_TAGVAR(LD, $1)=$LD
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_FC"
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)=$LD
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)=$LD
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code=$lt_simple_compile_test_code
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+  :
+  _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+    [AC_CHECK_TOOL(GCJ, gcj,)
+      test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2"
+      AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f "$lt_ac_sed" && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test 10 -lt "$lt_ac_count" && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test "$lt_ac_count" -gt "$lt_ac_max"; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine what file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path).  These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+         [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+         [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
diff --git a/final/lib/External/isl/m4/ltoptions.m4 b/final/lib/External/isl/m4/ltoptions.m4
new file mode 100644
index 0000000..94b0829
--- /dev/null
+++ b/final/lib/External/isl/m4/ltoptions.m4
@@ -0,0 +1,437 @@
+# Helper functions for option handling.                    -*- Autoconf -*-
+#
+#   Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
+#   Foundation, Inc.
+#   Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 8 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+        _LT_MANGLE_DEFUN([$1], [$2]),
+    [m4_warning([Unknown $1 option '$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+	    [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+		      [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME.  If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+    [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+  dnl
+  dnl Simply set some default values (i.e off) if boolean options were not
+  dnl specified:
+  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+  ])
+  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+  ])
+  dnl
+  dnl If no reference was made to various pairs of opposing options, then
+  dnl we run the default mode handler for the pair.  For example, if neither
+  dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
+  dnl archives by default:
+  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+		   [_LT_ENABLE_FAST_INSTALL])
+  _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
+		   [_LT_WITH_AIX_SONAME([aix])])
+  ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS],      [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the 'shared' and
+# 'disable-shared' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'.  If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+	[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac],
+    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+    _LT_DECL([build_libtool_libs], [enable_shared], [0],
+	[Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the 'static' and
+# 'disable-static' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'.  If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+	[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac],
+    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+    _LT_DECL([build_old_libs], [enable_static], [0],
+	[Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the 'fast-install'
+# and 'disable-fast-install' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'.  If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac],
+    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+	 [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the 'fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the 'disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_AIX_SONAME([DEFAULT])
+# ----------------------------------
+# implement the --with-aix-soname flag, and support the `aix-soname=aix'
+# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
+# is either `aix', `both' or `svr4'.  If omitted, it defaults to `aix'.
+m4_define([_LT_WITH_AIX_SONAME],
+[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
+shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[[5-9]]*,yes)
+  AC_MSG_CHECKING([which variant of shared library versioning to provide])
+  AC_ARG_WITH([aix-soname],
+    [AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
+      [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
+    [case $withval in
+    aix|svr4|both)
+      ;;
+    *)
+      AC_MSG_ERROR([Unknown argument to --with-aix-soname])
+      ;;
+    esac
+    lt_cv_with_aix_soname=$with_aix_soname],
+    [AC_CACHE_VAL([lt_cv_with_aix_soname],
+      [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
+    with_aix_soname=$lt_cv_with_aix_soname])
+  AC_MSG_RESULT([$with_aix_soname])
+  if test aix != "$with_aix_soname"; then
+    # For the AIX way of multilib, we name the shared archive member
+    # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+    # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+    # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+    # the AIX toolchain works better with OBJECT_MODE set (default 32).
+    if test 64 = "${OBJECT_MODE-32}"; then
+      shared_archive_member_spec=shr_64
+    else
+      shared_archive_member_spec=shr
+    fi
+  fi
+  ;;
+*)
+  with_aix_soname=aix
+  ;;
+esac
+
+_LT_DECL([], [shared_archive_member_spec], [0],
+    [Shared archive member basename, for filename based shared library versioning on AIX])dnl
+])# _LT_WITH_AIX_SONAME
+
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
+# LT_INIT options.
+# MODE is either 'yes' or 'no'.  If omitted, it defaults to 'both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+    [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for lt_pkg in $withval; do
+	IFS=$lt_save_ifs
+	if test "X$lt_pkg" = "X$lt_p"; then
+	  pic_mode=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac],
+    [pic_mode=m4_default([$1], [default])])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+		 [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+		 [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+		 [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+		 [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+		 [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/final/lib/External/isl/m4/ltsugar.m4 b/final/lib/External/isl/m4/ltsugar.m4
new file mode 100644
index 0000000..48bc934
--- /dev/null
+++ b/final/lib/External/isl/m4/ltsugar.m4
@@ -0,0 +1,124 @@
+# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
+#
+# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
+# Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+       [$#], [2], [[$2]],
+       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59, which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+       [$#], 1, [],
+       [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+	   m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+	     [m4_foreach([_Lt_suffix],
+		]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+	[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+	  [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+		 [lt_append([$1], [$2], [$3])$4],
+		 [$5])],
+	  [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+	m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+	[$5],
+    [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+  [lt_join(m4_quote(m4_default([$4], [[, ]])),
+           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+		      [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/final/lib/External/isl/m4/ltversion.m4 b/final/lib/External/isl/m4/ltversion.m4
new file mode 100644
index 0000000..fa04b52
--- /dev/null
+++ b/final/lib/External/isl/m4/ltversion.m4
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers			-*- Autoconf -*-
+#
+#   Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 4179 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.6])
+m4_define([LT_PACKAGE_REVISION], [2.4.6])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.6'
+macro_revision='2.4.6'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/final/lib/External/isl/m4/lt~obsolete.m4 b/final/lib/External/isl/m4/lt~obsolete.m4
new file mode 100644
index 0000000..c6b26f8
--- /dev/null
+++ b/final/lib/External/isl/m4/lt~obsolete.m4
@@ -0,0 +1,99 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
+#
+#   Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
+#   Foundation, Inc.
+#   Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else.  This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION],	[AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP],		[AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT],		[AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],	[AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN],		[AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR],		[AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL],	[AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN],		[AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER],	[AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK],		[AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],	[AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],	[AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],	[AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR],		[AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR],		[AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],	[AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC],		[AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU],		[AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG],	[AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD],	[AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS],	[AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP],	[AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP],		[AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED],		[AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME],		[AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE],	[AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE],	[AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL],		[AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP],		[AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN],		[AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],	[AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG],		[AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL],	[AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX],		[AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77],		[AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ],		[AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG],	[AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG],	[AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG],	[AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],	[AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG],	[AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG],		[AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C],	[AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],	[AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP],		[AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],	[AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77],		[AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC],		[AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX],		[AC_DEFUN([_LT_PROG_CXX])])
diff --git a/final/lib/External/isl/missing b/final/lib/External/isl/missing
new file mode 100755
index 0000000..f62bbae
--- /dev/null
+++ b/final/lib/External/isl/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2013-10-28.13; # UTC
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try '$0 --help' for more information"
+  exit 1
+fi
+
+case $1 in
+
+  --is-lightweight)
+    # Used by our autoconf macros to check whether the available missing
+    # script is modern enough.
+    exit 0
+    ;;
+
+  --run)
+    # Back-compat with the calling convention used by older automake.
+    shift
+    ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal   autoconf  autoheader   autom4te  automake  makeinfo
+  bison     yacc      flex         lex       help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+    exit $?
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit $?
+    ;;
+
+  -*)
+    echo 1>&2 "$0: unknown '$1' option"
+    echo 1>&2 "Try '$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch.  This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+  msg="probably too old"
+elif test $st -eq 127; then
+  # Program was missing.
+  msg="missing on your system"
+else
+  # Program was found and executed, but failed.  Give up.
+  exit $st
+fi
+
+perl_URL=http://www.perl.org/
+flex_URL=http://flex.sourceforge.net/
+gnu_software_URL=http://www.gnu.org/software
+
+program_details ()
+{
+  case $1 in
+    aclocal|automake)
+      echo "The '$1' program is part of the GNU Automake package:"
+      echo "<$gnu_software_URL/automake>"
+      echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/autoconf>"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+    autoconf|autom4te|autoheader)
+      echo "The '$1' program is part of the GNU Autoconf package:"
+      echo "<$gnu_software_URL/autoconf/>"
+      echo "It also requires GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+  esac
+}
+
+give_advice ()
+{
+  # Normalize program name to check for.
+  normalized_program=`echo "$1" | sed '
+    s/^gnu-//; t
+    s/^gnu//; t
+    s/^g//; t'`
+
+  printf '%s\n' "'$1' is $msg."
+
+  configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+  case $normalized_program in
+    autoconf*)
+      echo "You should only need it if you modified 'configure.ac',"
+      echo "or m4 files included by it."
+      program_details 'autoconf'
+      ;;
+    autoheader*)
+      echo "You should only need it if you modified 'acconfig.h' or"
+      echo "$configure_deps."
+      program_details 'autoheader'
+      ;;
+    automake*)
+      echo "You should only need it if you modified 'Makefile.am' or"
+      echo "$configure_deps."
+      program_details 'automake'
+      ;;
+    aclocal*)
+      echo "You should only need it if you modified 'acinclude.m4' or"
+      echo "$configure_deps."
+      program_details 'aclocal'
+      ;;
+   autom4te*)
+      echo "You might have modified some maintainer files that require"
+      echo "the 'autom4te' program to be rebuilt."
+      program_details 'autom4te'
+      ;;
+    bison*|yacc*)
+      echo "You should only need it if you modified a '.y' file."
+      echo "You may want to install the GNU Bison package:"
+      echo "<$gnu_software_URL/bison/>"
+      ;;
+    lex*|flex*)
+      echo "You should only need it if you modified a '.l' file."
+      echo "You may want to install the Fast Lexical Analyzer package:"
+      echo "<$flex_URL>"
+      ;;
+    help2man*)
+      echo "You should only need it if you modified a dependency" \
+           "of a man page."
+      echo "You may want to install the GNU Help2man package:"
+      echo "<$gnu_software_URL/help2man/>"
+    ;;
+    makeinfo*)
+      echo "You should only need it if you modified a '.texi' file, or"
+      echo "any other file indirectly affecting the aspect of the manual."
+      echo "You might want to install the Texinfo package:"
+      echo "<$gnu_software_URL/texinfo/>"
+      echo "The spurious makeinfo call might also be the consequence of"
+      echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+      echo "want to install GNU make:"
+      echo "<$gnu_software_URL/make/>"
+      ;;
+    *)
+      echo "You might have modified some files without having the proper"
+      echo "tools for further handling them.  Check the 'README' file, it"
+      echo "often tells you about the needed prerequisites for installing"
+      echo "this package.  You may also peek at any GNU archive site, in"
+      echo "case some other package contains this missing '$1' program."
+      ;;
+  esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+                       -e '2,$s/^/         /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/final/lib/External/isl/mp_get_memory_functions.c b/final/lib/External/isl/mp_get_memory_functions.c
new file mode 100644
index 0000000..e14e336
--- /dev/null
+++ b/final/lib/External/isl/mp_get_memory_functions.c
@@ -0,0 +1,14 @@
+#include <gmp.h>
+
+void mp_get_memory_functions(
+		void *(**alloc_func_ptr) (size_t),
+		void *(**realloc_func_ptr) (void *, size_t, size_t),
+		void (**free_func_ptr) (void *, size_t))
+{
+	if (alloc_func_ptr)
+		*alloc_func_ptr = __gmp_allocate_func;
+	if (realloc_func_ptr)
+		*realloc_func_ptr = __gmp_reallocate_func;
+	if (free_func_ptr)
+		*free_func_ptr = __gmp_free_func;
+}
diff --git a/final/lib/External/isl/pip.c b/final/lib/External/isl/pip.c
new file mode 100644
index 0000000..002bc70
--- /dev/null
+++ b/final/lib/External/isl/pip.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <isl_map_private.h>
+#include <isl/aff.h>
+#include <isl/set.h>
+#include "isl_tab.h"
+#include "isl_sample.h"
+#include "isl_scan.h"
+#include <isl_seq.h>
+#include <isl_ilp_private.h>
+#include <isl/printer.h>
+#include <isl_point_private.h>
+#include <isl_vec_private.h>
+#include <isl/options.h>
+#include <isl_config.h>
+
+/* The input of this program is the same as that of the "example" program
+ * from the PipLib distribution, except that the "big parameter column"
+ * should always be -1.
+ *
+ * Context constraints in PolyLib format
+ * -1
+ * Problem constraints in PolyLib format
+ * Optional list of options
+ *
+ * The options are
+ *	Maximize	compute maximum instead of minimum
+ *	Rational	compute rational optimum instead of integer optimum
+ *	Urs_parms	don't assume parameters are non-negative
+ *	Urs_unknowns	don't assume unknowns are non-negative
+ */
+
+struct options {
+	struct isl_options	*isl;
+	unsigned		 verify;
+	unsigned		 format;
+};
+
+#define FORMAT_SET	0
+#define FORMAT_AFF	1
+
+struct isl_arg_choice pip_format[] = {
+	{"set",		FORMAT_SET},
+	{"affine",	FORMAT_AFF},
+	{0}
+};
+
+ISL_ARGS_START(struct options, options_args)
+ISL_ARG_CHILD(struct options, isl, "isl", &isl_options_args, "isl options")
+ISL_ARG_BOOL(struct options, verify, 'T', "verify", 0, NULL)
+ISL_ARG_CHOICE(struct options, format, 0, "format",
+	pip_format, FORMAT_SET, "output format")
+ISL_ARGS_END
+
+ISL_ARG_DEF(options, struct options, options_args)
+
+static __isl_give isl_basic_set *set_bounds(__isl_take isl_basic_set *bset)
+{
+	unsigned nparam;
+	int i, r;
+	isl_point *pt, *pt2;
+	isl_basic_set *box;
+
+	nparam = isl_basic_set_dim(bset, isl_dim_param);
+	r = nparam >= 8 ? 4 : nparam >= 5 ? 6 : 30;
+
+	pt = isl_basic_set_sample_point(isl_basic_set_copy(bset));
+	pt2 = isl_point_copy(pt);
+
+	for (i = 0; i < nparam; ++i) {
+		pt = isl_point_add_ui(pt, isl_dim_param, i, r);
+		pt2 = isl_point_sub_ui(pt2, isl_dim_param, i, r);
+	}
+
+	box = isl_basic_set_box_from_points(pt, pt2);
+
+	return isl_basic_set_intersect(bset, box);
+}
+
+static struct isl_basic_set *to_parameter_domain(struct isl_basic_set *context)
+{
+	context = isl_basic_set_move_dims(context, isl_dim_param, 0,
+		    isl_dim_set, 0, isl_basic_set_dim(context, isl_dim_set));
+	context = isl_basic_set_params(context);
+	return context;
+}
+
+/* Plug in the initial values of "params" for the parameters in "bset" and
+ * return the result.  The remaining entries in "params", if any,
+ * correspond to the existentially quantified variables in the description
+ * of the original context and can be ignored.
+ */
+static __isl_give isl_basic_set *plug_in_parameters(
+	__isl_take isl_basic_set *bset, __isl_take isl_vec *params)
+{
+	int i, n;
+
+	n = isl_basic_set_dim(bset, isl_dim_param);
+	for (i = 0; i < n; ++i)
+		bset = isl_basic_set_fix(bset,
+					 isl_dim_param, i, params->el[1 + i]);
+
+	bset = isl_basic_set_remove_dims(bset, isl_dim_param, 0, n);
+
+	isl_vec_free(params);
+
+	return bset;
+}
+
+/* Plug in the initial values of "params" for the parameters in "set" and
+ * return the result.  The remaining entries in "params", if any,
+ * correspond to the existentially quantified variables in the description
+ * of the original context and can be ignored.
+ */
+static __isl_give isl_set *set_plug_in_parameters(__isl_take isl_set *set,
+	__isl_take isl_vec *params)
+{
+	int i, n;
+
+	n = isl_set_dim(set, isl_dim_param);
+	for (i = 0; i < n; ++i)
+		set = isl_set_fix(set, isl_dim_param, i, params->el[1 + i]);
+
+	set = isl_set_remove_dims(set, isl_dim_param, 0, n);
+
+	isl_vec_free(params);
+
+	return set;
+}
+
+/* Compute the lexicographically minimal (or maximal if max is set)
+ * element of bset for the given values of the parameters, by
+ * successively solving an ilp problem in each direction.
+ */
+static __isl_give isl_vec *opt_at(__isl_take isl_basic_set *bset,
+	__isl_take isl_vec *params, int max)
+{
+	unsigned dim;
+	isl_ctx *ctx;
+	struct isl_vec *opt;
+	struct isl_vec *obj;
+	int i;
+
+	dim = isl_basic_set_dim(bset, isl_dim_set);
+
+	bset = plug_in_parameters(bset, params);
+
+	ctx = isl_basic_set_get_ctx(bset);
+	if (isl_basic_set_plain_is_empty(bset)) {
+		opt = isl_vec_alloc(ctx, 0);
+		isl_basic_set_free(bset);
+		return opt;
+	}
+
+	opt = isl_vec_alloc(ctx, 1 + dim);
+	assert(opt);
+
+	obj = isl_vec_alloc(ctx, 1 + dim);
+	assert(obj);
+
+	isl_int_set_si(opt->el[0], 1);
+	isl_int_set_si(obj->el[0], 0);
+
+	for (i = 0; i < dim; ++i) {
+		enum isl_lp_result res;
+
+		isl_seq_clr(obj->el + 1, dim);
+		isl_int_set_si(obj->el[1 + i], 1);
+		res = isl_basic_set_solve_ilp(bset, max, obj->el,
+						&opt->el[1 + i], NULL);
+		if (res == isl_lp_empty)
+			goto empty;
+		assert(res == isl_lp_ok);
+		bset = isl_basic_set_fix(bset, isl_dim_set, i, opt->el[1 + i]);
+	}
+
+	isl_basic_set_free(bset);
+	isl_vec_free(obj);
+
+	return opt;
+empty:
+	isl_vec_free(opt);
+	opt = isl_vec_alloc(ctx, 0);
+	isl_basic_set_free(bset);
+	isl_vec_free(obj);
+
+	return opt;
+}
+
+struct isl_scan_pip {
+	struct isl_scan_callback callback;
+	isl_basic_set *bset;
+	isl_set *sol;
+	isl_set *empty;
+	int stride;
+	int n;
+	int max;
+};
+
+/* Check if the "manually" computed optimum of bset at the "sample"
+ * values of the parameters agrees with the solution of pilp problem
+ * represented by the pair (sol, empty).
+ * In particular, if there is no solution for this value of the parameters,
+ * then it should be an element of the parameter domain "empty".
+ * Otherwise, the optimal solution, should be equal to the result of
+ * plugging in the value of the parameters in "sol".
+ */
+static isl_stat scan_one(struct isl_scan_callback *callback,
+	__isl_take isl_vec *sample)
+{
+	struct isl_scan_pip *sp = (struct isl_scan_pip *)callback;
+	struct isl_vec *opt;
+
+	sp->n--;
+
+	opt = opt_at(isl_basic_set_copy(sp->bset), isl_vec_copy(sample), sp->max);
+	assert(opt);
+
+	if (opt->size == 0) {
+		isl_point *sample_pnt;
+		sample_pnt = isl_point_alloc(isl_set_get_space(sp->empty), sample);
+		assert(isl_set_contains_point(sp->empty, sample_pnt));
+		isl_point_free(sample_pnt);
+		isl_vec_free(opt);
+	} else {
+		isl_set *sol;
+		isl_set *opt_set;
+		opt_set = isl_set_from_basic_set(isl_basic_set_from_vec(opt));
+		sol = set_plug_in_parameters(isl_set_copy(sp->sol), sample);
+		assert(isl_set_is_equal(opt_set, sol));
+		isl_set_free(sol);
+		isl_set_free(opt_set);
+	}
+
+	if (!(sp->n % sp->stride)) {
+		printf("o");
+		fflush(stdout);
+	}
+
+	return sp->n >= 1 ? isl_stat_ok : isl_stat_error;
+}
+
+static void check_solution(isl_basic_set *bset, isl_basic_set *context,
+	isl_set *sol, isl_set *empty, int max)
+{
+	struct isl_scan_pip sp;
+	isl_int count, count_max;
+	int i, n;
+	int r;
+
+	context = set_bounds(context);
+	context = isl_basic_set_underlying_set(context);
+
+	isl_int_init(count);
+	isl_int_init(count_max);
+
+	isl_int_set_si(count_max, 2000);
+	r = isl_basic_set_count_upto(context, count_max, &count);
+	assert(r >= 0);
+	n = isl_int_get_si(count);
+
+	isl_int_clear(count_max);
+	isl_int_clear(count);
+
+	sp.callback.add = scan_one;
+	sp.bset = bset;
+	sp.sol = sol;
+	sp.empty = empty;
+	sp.n = n;
+	sp.stride = n > 70 ? 1 + (n + 1)/70 : 1;
+	sp.max = max;
+
+	for (i = 0; i < n; i += sp.stride)
+		printf(".");
+	printf("\r");
+	fflush(stdout);
+
+	isl_basic_set_scan(context, &sp.callback);
+
+	printf("\n");
+
+	isl_basic_set_free(bset);
+}
+
+int main(int argc, char **argv)
+{
+	struct isl_ctx *ctx;
+	struct isl_basic_set *context, *bset, *copy, *context_copy;
+	struct isl_set *set = NULL;
+	struct isl_set *empty;
+	isl_pw_multi_aff *pma = NULL;
+	int neg_one;
+	char s[1024];
+	int urs_parms = 0;
+	int urs_unknowns = 0;
+	int max = 0;
+	int rational = 0;
+	int n;
+	int nparam;
+	struct options *options;
+
+	options = options_new_with_defaults();
+	assert(options);
+	argc = options_parse(options, argc, argv, ISL_ARG_ALL);
+
+	ctx = isl_ctx_alloc_with_options(&options_args, options);
+
+	context = isl_basic_set_read_from_file(ctx, stdin);
+	assert(context);
+	n = fscanf(stdin, "%d", &neg_one);
+	assert(n == 1);
+	assert(neg_one == -1);
+	bset = isl_basic_set_read_from_file(ctx, stdin);
+
+	while (fgets(s, sizeof(s), stdin)) {
+		if (strncasecmp(s, "Maximize", 8) == 0)
+			max = 1;
+		if (strncasecmp(s, "Rational", 8) == 0) {
+			rational = 1;
+			bset = isl_basic_set_set_rational(bset);
+		}
+		if (strncasecmp(s, "Urs_parms", 9) == 0)
+			urs_parms = 1;
+		if (strncasecmp(s, "Urs_unknowns", 12) == 0)
+			urs_unknowns = 1;
+	}
+	if (!urs_parms)
+		context = isl_basic_set_intersect(context,
+		isl_basic_set_positive_orthant(isl_basic_set_get_space(context)));
+	context = to_parameter_domain(context);
+	nparam = isl_basic_set_dim(context, isl_dim_param);
+	if (nparam != isl_basic_set_dim(bset, isl_dim_param)) {
+		int dim = isl_basic_set_dim(bset, isl_dim_set);
+		bset = isl_basic_set_move_dims(bset, isl_dim_param, 0,
+					    isl_dim_set, dim - nparam, nparam);
+	}
+	if (!urs_unknowns)
+		bset = isl_basic_set_intersect(bset,
+		isl_basic_set_positive_orthant(isl_basic_set_get_space(bset)));
+
+	if (options->verify) {
+		copy = isl_basic_set_copy(bset);
+		context_copy = isl_basic_set_copy(context);
+	}
+
+	if (options->format == FORMAT_AFF) {
+		if (max)
+			pma = isl_basic_set_partial_lexmax_pw_multi_aff(bset,
+								context, &empty);
+		else
+			pma = isl_basic_set_partial_lexmin_pw_multi_aff(bset,
+								context, &empty);
+	} else {
+		if (max)
+			set = isl_basic_set_partial_lexmax(bset,
+								context, &empty);
+		else
+			set = isl_basic_set_partial_lexmin(bset,
+								context, &empty);
+	}
+
+	if (options->verify) {
+		assert(!rational);
+		if (options->format == FORMAT_AFF)
+			set = isl_set_from_pw_multi_aff(pma);
+		check_solution(copy, context_copy, set, empty, max);
+		isl_set_free(set);
+	} else {
+		isl_printer *p;
+		p = isl_printer_to_file(ctx, stdout);
+		if (options->format == FORMAT_AFF)
+			p = isl_printer_print_pw_multi_aff(p, pma);
+		else
+			p = isl_printer_print_set(p, set);
+		p = isl_printer_end_line(p);
+		p = isl_printer_print_str(p, "no solution: ");
+		p = isl_printer_print_set(p, empty);
+		p = isl_printer_end_line(p);
+		isl_printer_free(p);
+		isl_set_free(set);
+		isl_pw_multi_aff_free(pma);
+	}
+
+	isl_set_free(empty);
+	isl_ctx_free(ctx);
+
+	return 0;
+}
diff --git a/final/lib/External/isl/pip_test.sh.in b/final/lib/External/isl/pip_test.sh.in
new file mode 100755
index 0000000..5f36b77
--- /dev/null
+++ b/final/lib/External/isl/pip_test.sh.in
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+EXEEXT=@EXEEXT@
+srcdir=@srcdir@
+
+PIP_TESTS="\
+	boulet.pip \
+	brisebarre.pip \
+	cg1.pip \
+	esced.pip \
+	ex2.pip \
+	ex.pip \
+	exist.pip \
+	exist2.pip \
+	fimmel.pip \
+	max.pip \
+	negative.pip \
+	seghir-vd.pip \
+	small.pip \
+	sor1d.pip \
+	square.pip \
+	sven.pip \
+	tobi.pip"
+
+for i in $PIP_TESTS; do
+	echo $i;
+	./isl_pip$EXEEXT --format=set --context=gbr -T < $srcdir/test_inputs/$i || exit
+	./isl_pip$EXEEXT --format=set --context=lexmin -T < $srcdir/test_inputs/$i || exit
+	./isl_pip$EXEEXT --format=affine --context=gbr -T < $srcdir/test_inputs/$i || exit
+	./isl_pip$EXEEXT --format=affine --context=lexmin -T < $srcdir/test_inputs/$i || exit
+done
diff --git a/final/lib/External/isl/polyhedron_detect_equalities.c b/final/lib/External/isl/polyhedron_detect_equalities.c
new file mode 100644
index 0000000..c3dcec5
--- /dev/null
+++ b/final/lib/External/isl/polyhedron_detect_equalities.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <isl/set.h>
+
+int main(int argc, char **argv)
+{
+	struct isl_ctx *ctx = isl_ctx_alloc();
+	struct isl_basic_set *bset;
+	isl_printer *p;
+
+	bset = isl_basic_set_read_from_file(ctx, stdin);
+	bset = isl_basic_set_detect_equalities(bset);
+
+	p = isl_printer_to_file(ctx, stdout);
+	p = isl_printer_set_output_format(p, ISL_FORMAT_POLYLIB);
+	p = isl_printer_print_basic_set(p, bset);
+	isl_printer_free(p);
+
+	isl_basic_set_free(bset);
+	isl_ctx_free(ctx);
+
+	return 0;
+}
diff --git a/final/lib/External/isl/polyhedron_minimize.c b/final/lib/External/isl/polyhedron_minimize.c
new file mode 100644
index 0000000..526b373
--- /dev/null
+++ b/final/lib/External/isl/polyhedron_minimize.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <assert.h>
+#include <isl/set.h>
+#include <isl/vec.h>
+#include <isl_ilp_private.h>
+#include <isl_seq.h>
+#include <isl_vec_private.h>
+
+/* The input of this program is the same as that of the "polytope_minimize"
+ * program from the barvinok distribution.
+ *
+ * Constraints of set is PolyLib format.
+ * Linear or affine objective function in PolyLib format.
+ */
+
+static struct isl_vec *isl_vec_lin_to_aff(struct isl_vec *vec)
+{
+	struct isl_vec *aff;
+
+	if (!vec)
+		return NULL;
+	aff = isl_vec_alloc(vec->ctx, 1 + vec->size);
+	if (!aff)
+		goto error;
+	isl_int_set_si(aff->el[0], 0);
+	isl_seq_cpy(aff->el + 1, vec->el, vec->size);
+	isl_vec_free(vec);
+	return aff;
+error:
+	isl_vec_free(vec);
+	return NULL;
+}
+
+/* Rotate elements of vector right.
+ * In particular, move the constant term from the end of the
+ * vector to the start of the vector.
+ */
+static struct isl_vec *vec_ror(struct isl_vec *vec)
+{
+	int i;
+
+	if (!vec)
+		return NULL;
+	for (i = vec->size - 2; i >= 0; --i)
+		isl_int_swap(vec->el[i], vec->el[i + 1]);
+	return vec;
+}
+
+int main(int argc, char **argv)
+{
+	struct isl_ctx *ctx = isl_ctx_alloc();
+	struct isl_basic_set *bset;
+	struct isl_vec *obj;
+	struct isl_vec *sol;
+	isl_int opt;
+	unsigned dim;
+	enum isl_lp_result res;
+	isl_printer *p;
+
+	isl_int_init(opt);
+	bset = isl_basic_set_read_from_file(ctx, stdin);
+	assert(bset);
+	obj = isl_vec_read_from_file(ctx, stdin);
+	assert(obj);
+	dim = isl_basic_set_total_dim(bset);
+	assert(obj->size >= dim && obj->size <= dim + 1);
+	if (obj->size != dim + 1)
+		obj = isl_vec_lin_to_aff(obj);
+	else
+		obj = vec_ror(obj);
+	res = isl_basic_set_solve_ilp(bset, 0, obj->el, &opt, &sol);
+	switch (res) {
+	case isl_lp_error:
+		fprintf(stderr, "error\n");
+		return -1;
+	case isl_lp_empty:
+		fprintf(stdout, "empty\n");
+		break;
+	case isl_lp_unbounded:
+		fprintf(stdout, "unbounded\n");
+		break;
+	case isl_lp_ok:
+		p = isl_printer_to_file(ctx, stdout);
+		p = isl_printer_print_vec(p, sol);
+		p = isl_printer_end_line(p);
+		p = isl_printer_print_isl_int(p, opt);
+		p = isl_printer_end_line(p);
+		isl_printer_free(p);
+	}
+	isl_basic_set_free(bset);
+	isl_vec_free(obj);
+	isl_vec_free(sol);
+	isl_ctx_free(ctx);
+	isl_int_clear(opt);
+
+	return 0;
+}
diff --git a/final/lib/External/isl/polyhedron_sample.c b/final/lib/External/isl/polyhedron_sample.c
new file mode 100644
index 0000000..3fc442f
--- /dev/null
+++ b/final/lib/External/isl/polyhedron_sample.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <assert.h>
+#include <isl_map_private.h>
+#include "isl_sample.h"
+#include <isl/vec.h>
+
+int main(int argc, char **argv)
+{
+	struct isl_ctx *ctx = isl_ctx_alloc();
+	struct isl_basic_set *bset;
+	struct isl_vec *sample;
+	isl_printer *p;
+
+	bset = isl_basic_set_read_from_file(ctx, stdin);
+	sample = isl_basic_set_sample_vec(isl_basic_set_copy(bset));
+	p = isl_printer_to_file(ctx, stdout);
+	p = isl_printer_print_vec(p, sample);
+	p = isl_printer_end_line(p);
+	isl_printer_free(p);
+	assert(sample);
+	if (isl_vec_size(sample) > 0)
+		assert(isl_basic_set_contains(bset, sample));
+	isl_basic_set_free(bset);
+	isl_vec_free(sample);
+	isl_ctx_free(ctx);
+
+	return 0;
+}
diff --git a/final/lib/External/isl/polytope_scan.c b/final/lib/External/isl/polytope_scan.c
new file mode 100644
index 0000000..c787432
--- /dev/null
+++ b/final/lib/External/isl/polytope_scan.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, K.U.Leuven, Departement
+ * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
+ */
+
+#include <assert.h>
+#include <isl_map_private.h>
+#include "isl_equalities.h"
+#include <isl_seq.h>
+#include "isl_scan.h"
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+
+/* The input of this program is the same as that of the "polytope_scan"
+ * program from the barvinok distribution.
+ *
+ * Constraints of set is PolyLib format.
+ *
+ * The input set is assumed to be bounded.
+ */
+
+struct scan_samples {
+	struct isl_scan_callback callback;
+	struct isl_mat *samples;
+};
+
+static isl_stat scan_samples_add_sample(struct isl_scan_callback *cb,
+	__isl_take isl_vec *sample)
+{
+	struct scan_samples *ss = (struct scan_samples *)cb;
+
+	ss->samples = isl_mat_extend(ss->samples, ss->samples->n_row + 1,
+						  ss->samples->n_col);
+	if (!ss->samples)
+		goto error;
+
+	isl_seq_cpy(ss->samples->row[ss->samples->n_row - 1],
+		    sample->el, sample->size);
+
+	isl_vec_free(sample);
+	return isl_stat_ok;
+error:
+	isl_vec_free(sample);
+	return isl_stat_error;
+}
+
+static struct isl_mat *isl_basic_set_scan_samples(struct isl_basic_set *bset)
+{
+	isl_ctx *ctx;
+	unsigned dim;
+	struct scan_samples ss;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	dim = isl_basic_set_total_dim(bset);
+	ss.callback.add = scan_samples_add_sample;
+	ss.samples = isl_mat_alloc(ctx, 0, 1 + dim);
+	if (!ss.samples)
+		goto error;
+
+	if (isl_basic_set_scan(bset, &ss.callback) < 0) {
+		isl_mat_free(ss.samples);
+		return NULL;
+	}
+
+	return ss.samples;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+static struct isl_mat *isl_basic_set_samples(struct isl_basic_set *bset)
+{
+	struct isl_mat *T;
+	struct isl_mat *samples;
+
+	if (!bset)
+		return NULL;
+
+	if (bset->n_eq == 0)
+		return isl_basic_set_scan_samples(bset);
+
+	bset = isl_basic_set_remove_equalities(bset, &T, NULL);
+	samples = isl_basic_set_scan_samples(bset);
+	return isl_mat_product(samples, isl_mat_transpose(T));
+}
+
+int main(int argc, char **argv)
+{
+	struct isl_ctx *ctx = isl_ctx_alloc();
+	struct isl_basic_set *bset;
+	struct isl_mat *samples;
+
+	bset = isl_basic_set_read_from_file(ctx, stdin);
+	samples = isl_basic_set_samples(bset);
+	isl_mat_print_internal(samples, stdout, 0);
+	isl_mat_free(samples);
+	isl_ctx_free(ctx);
+
+	return 0;
+}
diff --git a/final/lib/External/isl/print.c b/final/lib/External/isl/print.c
new file mode 100644
index 0000000..bea1ff1
--- /dev/null
+++ b/final/lib/External/isl/print.c
@@ -0,0 +1,106 @@
+#include <isl/ctx.h>
+#include <isl/id.h>
+#include <isl/space.h>
+#include <isl/local_space.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl/polynomial.h>
+#include <isl/band.h>
+#include <isl/constraint.h>
+#include <isl/aff.h>
+#include <isl/ast.h>
+#include <isl/printer.h>
+#include <isl/val.h>
+
+#undef BASE
+#define BASE id
+#include <print_templ.c>
+#undef BASE
+#define BASE val
+#include <print_templ.c>
+#undef BASE
+#define BASE multi_val
+#include <print_templ.c>
+#undef BASE
+#define BASE space
+#include <print_templ.c>
+#undef BASE
+#define BASE local_space
+#include <print_templ.c>
+#undef BASE
+#define BASE basic_set
+#include <print_templ.c>
+#undef BASE
+#define BASE basic_map
+#include <print_templ.c>
+#undef BASE
+#define BASE set
+#include <print_templ.c>
+#undef BASE
+#define BASE map
+#include <print_templ.c>
+#undef BASE
+#define BASE union_set
+#include <print_templ.c>
+#undef BASE
+#define BASE union_map
+#include <print_templ.c>
+#undef BASE
+#define BASE qpolynomial
+#include <print_templ.c>
+#undef BASE
+#define BASE qpolynomial_fold
+#include <print_templ.c>
+#undef BASE
+#define BASE pw_qpolynomial
+#include <print_templ.c>
+#undef BASE
+#define BASE pw_qpolynomial_fold
+#include <print_templ.c>
+#undef BASE
+#define BASE union_pw_qpolynomial
+#include <print_templ.c>
+#undef BASE
+#define BASE union_pw_qpolynomial_fold
+#include <print_templ.c>
+#undef BASE
+#define BASE band
+#include <print_templ.c>
+#undef BASE
+#define BASE constraint
+#include <print_templ.c>
+#undef BASE
+#define BASE aff
+#include <print_templ.c>
+#undef BASE
+#define BASE pw_aff
+#include <print_templ.c>
+#undef BASE
+#define BASE multi_aff
+#include <print_templ.c>
+#undef BASE
+#define BASE pw_multi_aff
+#include <print_templ.c>
+#undef BASE
+#define BASE union_pw_multi_aff
+#include <print_templ.c>
+#undef BASE
+#define BASE multi_pw_aff
+#include <print_templ.c>
+#undef BASE
+#define BASE union_pw_aff
+#include <print_templ.c>
+#undef BASE
+#define BASE multi_union_pw_aff
+#include <print_templ.c>
+#undef BASE
+#define BASE point
+#include <print_templ.c>
+#undef BASE
+#define BASE ast_expr
+#include <print_templ_yaml.c>
+#undef BASE
+#define BASE ast_node
+#include <print_templ_yaml.c>
diff --git a/final/lib/External/isl/print_templ.c b/final/lib/External/isl/print_templ.c
new file mode 100644
index 0000000..d6b0db7
--- /dev/null
+++ b/final/lib/External/isl/print_templ.c
@@ -0,0 +1,36 @@
+#include <isl_printer_private.h>
+
+#define xCAT(A,B) A ## B
+#define CAT(A,B) xCAT(A,B)
+#undef TYPE
+#define TYPE CAT(isl_,BASE)
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+
+void FN(TYPE,dump)(__isl_keep TYPE *obj)
+{
+	isl_printer *p;
+
+	if (!obj)
+		return;
+	p = isl_printer_to_file(FN(TYPE,get_ctx)(obj), stderr);
+	p = isl_printer_set_dump(p, 1);
+	p = FN(isl_printer_print,BASE)(p, obj);
+	p = isl_printer_end_line(p);
+	isl_printer_free(p);
+}
+
+__isl_give char *FN(TYPE,to_str)(__isl_keep TYPE *obj)
+{
+	isl_printer *p;
+	char *s;
+
+	if (!obj)
+		return NULL;
+	p = isl_printer_to_str(FN(TYPE,get_ctx)(obj));
+	p = FN(isl_printer_print,BASE)(p, obj);
+	s = isl_printer_get_str(p);
+	isl_printer_free(p);
+
+	return s;
+}
diff --git a/final/lib/External/isl/print_templ_yaml.c b/final/lib/External/isl/print_templ_yaml.c
new file mode 100644
index 0000000..50f7f1f
--- /dev/null
+++ b/final/lib/External/isl/print_templ_yaml.c
@@ -0,0 +1,39 @@
+#define xCAT(A,B) A ## B
+#define CAT(A,B) xCAT(A,B)
+#undef TYPE
+#define TYPE CAT(isl_,BASE)
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+
+void FN(TYPE,dump)(__isl_keep TYPE *obj)
+{
+	isl_printer *p;
+
+	if (!obj)
+		return;
+
+	p = isl_printer_to_file(FN(TYPE,get_ctx)(obj), stderr);
+	p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_BLOCK);
+	p = FN(isl_printer_print,BASE)(p, obj);
+	isl_printer_free(p);
+}
+
+/* Return a string representation of "obj".
+ * Print the object in flow format.
+ */
+__isl_give char *FN(TYPE,to_str)(__isl_keep TYPE *obj)
+{
+	isl_printer *p;
+	char *s;
+
+	if (!obj)
+		return NULL;
+
+	p = isl_printer_to_str(FN(TYPE,get_ctx)(obj));
+	p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
+	p = FN(isl_printer_print,BASE)(p, obj);
+	s = isl_printer_get_str(p);
+	isl_printer_free(p);
+
+	return s;
+}
diff --git a/final/lib/External/isl/read_in_string_templ.c b/final/lib/External/isl/read_in_string_templ.c
new file mode 100644
index 0000000..3dc630e
--- /dev/null
+++ b/final/lib/External/isl/read_in_string_templ.c
@@ -0,0 +1,38 @@
+#include <isl/stream.h>
+
+#define xCAT(A,B) A ## B
+#define CAT(A,B) xCAT(A,B)
+#undef TYPE
+#define TYPE CAT(isl_,BASE)
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+
+/* Read an object of type TYPE from "s", where the object may
+ * either be specified directly or as a string.
+ *
+ * First check if the next token in "s" is a string.  If so, try and
+ * extract the object from the string.
+ * Otherwise, try and read the object directly from "s".
+ */
+static __isl_give TYPE *FN(read,BASE)(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+	int type;
+
+	tok = isl_stream_next_token(s);
+	type = isl_token_get_type(tok);
+	if (type == ISL_TOKEN_STRING) {
+		char *str;
+		isl_ctx *ctx;
+		TYPE *res;
+
+		ctx = isl_stream_get_ctx(s);
+		str = isl_token_get_str(ctx, tok);
+		res = FN(TYPE,read_from_str)(ctx, str);
+		free(str);
+		isl_token_free(tok);
+		return res;
+	}
+	isl_stream_push_token(s, tok);
+	return FN(isl_stream_read,BASE)(s);
+}
diff --git a/final/lib/External/isl/schedule.c b/final/lib/External/isl/schedule.c
new file mode 100644
index 0000000..2373914
--- /dev/null
+++ b/final/lib/External/isl/schedule.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege.
+ */
+
+/* This program takes an isl_schedule_constraints object as input and
+ * prints a schedule that satisfies those constraints.
+ */
+
+#include <stdlib.h>
+#include <isl/options.h>
+#include <isl/schedule.h>
+
+int main(int argc, char **argv)
+{
+	isl_ctx *ctx;
+	isl_printer *p;
+	isl_schedule_constraints *sc;
+	isl_schedule *schedule;
+	struct isl_options *options;
+
+	options = isl_options_new_with_defaults();
+	argc = isl_options_parse(options, argc, argv, ISL_ARG_ALL);
+	ctx = isl_ctx_alloc_with_options(&isl_options_args, options);
+
+	sc = isl_schedule_constraints_read_from_file(ctx, stdin);
+	schedule = isl_schedule_constraints_compute_schedule(sc);
+
+	p = isl_printer_to_file(ctx, stdout);
+	p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_BLOCK);
+	p = isl_printer_print_schedule(p, schedule);
+	isl_printer_free(p);
+
+	isl_schedule_free(schedule);
+
+	isl_ctx_free(ctx);
+
+	return p ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/final/lib/External/isl/schedule_cmp.c b/final/lib/External/isl/schedule_cmp.c
new file mode 100644
index 0000000..8bf02ea
--- /dev/null
+++ b/final/lib/External/isl/schedule_cmp.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2017      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege.
+ */
+
+#include <stdlib.h>
+
+#include <isl/arg.h>
+#include <isl/options.h>
+#include <isl/schedule.h>
+
+struct options {
+	struct isl_options *isl;
+	char *schedule1;
+	char *schedule2;
+};
+
+ISL_ARGS_START(struct options, options_args)
+ISL_ARG_CHILD(struct options, isl, "isl", &isl_options_args, "isl options")
+ISL_ARG_ARG(struct options, schedule1, "schedule1", NULL)
+ISL_ARG_ARG(struct options, schedule2, "schedule2", NULL)
+ISL_ARGS_END
+
+ISL_ARG_DEF(options, struct options, options_args)
+
+static void die(const char *msg)
+{
+	fprintf(stderr, "%s\n", msg);
+	exit(EXIT_FAILURE);
+}
+
+static FILE *open_or_die(const char *filename)
+{
+	FILE *file;
+
+	file = fopen(filename, "r");
+	if (!file) {
+		fprintf(stderr, "Unable to open %s\n", filename);
+		exit(EXIT_FAILURE);
+	}
+	return file;
+}
+
+/* Given two YAML descriptions of isl_schedule objects, check whether
+ * they are equivalent.
+ * Return EXIT_SUCCESS if they are and EXIT_FAILURE if they are not
+ * or if anything else went wrong.
+ */
+int main(int argc, char **argv)
+{
+	isl_ctx *ctx;
+	struct options *options;
+	FILE *input1, *input2;
+	isl_bool equal;
+	isl_schedule *s1, *s2;
+
+	options = options_new_with_defaults();
+	if (!options)
+		return EXIT_FAILURE;
+
+	ctx = isl_ctx_alloc_with_options(&options_args, options);
+	argc = options_parse(options, argc, argv, ISL_ARG_ALL);
+
+	input1 = open_or_die(options->schedule1);
+	input2 = open_or_die(options->schedule2);
+	s1 = isl_schedule_read_from_file(ctx, input1);
+	s2 = isl_schedule_read_from_file(ctx, input2);
+
+	equal = isl_schedule_plain_is_equal(s1, s2);
+	if (equal < 0)
+		return EXIT_FAILURE;
+	if (!equal)
+		die("schedules differ");
+
+	isl_schedule_free(s1);
+	isl_schedule_free(s2);
+	fclose(input1);
+	fclose(input2);
+	isl_ctx_free(ctx);
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/isl/schedule_test.sh.in b/final/lib/External/isl/schedule_test.sh.in
new file mode 100644
index 0000000..afba802
--- /dev/null
+++ b/final/lib/External/isl/schedule_test.sh.in
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+EXEEXT=@EXEEXT@
+GREP=@GREP@
+SED=@SED@
+srcdir=@srcdir@
+
+failed=0
+
+for i in $srcdir/test_inputs/schedule/*.sc; do
+	echo $i;
+	base=`basename $i .sc`
+	test=test-$base.st
+	dir=`dirname $i`
+	ref=$dir/$base.st
+	options=`$GREP 'OPTIONS:' $i | $SED 's/.*://'`
+	(./isl_schedule$EXEEXT $options < $i > $test &&
+	./isl_schedule_cmp$EXEEXT $ref $test && rm $test) || failed=1
+done
+
+test $failed -eq 0 || exit
diff --git a/final/lib/External/isl/set_from_map.c b/final/lib/External/isl/set_from_map.c
new file mode 100644
index 0000000..cf6f814
--- /dev/null
+++ b/final/lib/External/isl/set_from_map.c
@@ -0,0 +1,8 @@
+#include <isl/map_type.h>
+
+/* Return the set that was treated as the map "map".
+ */
+static __isl_give isl_set *set_from_map(__isl_take isl_map *map)
+{
+	return (isl_set *) map;
+}
diff --git a/final/lib/External/isl/set_to_map.c b/final/lib/External/isl/set_to_map.c
new file mode 100644
index 0000000..dc67ed2
--- /dev/null
+++ b/final/lib/External/isl/set_to_map.c
@@ -0,0 +1,10 @@
+#include <isl/map_type.h>
+
+/* Treat "set" as a map.
+ * Internally, isl_set is defined to isl_map, so in practice,
+ * this function performs a redundant cast.
+ */
+static __isl_give isl_map *set_to_map(__isl_take isl_set *set)
+{
+	return (isl_map *) set;
+}
diff --git a/final/lib/External/isl/test-driver b/final/lib/External/isl/test-driver
new file mode 100755
index 0000000..8e575b0
--- /dev/null
+++ b/final/lib/External/isl/test-driver
@@ -0,0 +1,148 @@
+#! /bin/sh
+# test-driver - basic testsuite driver script.
+
+scriptversion=2013-07-13.22; # UTC
+
+# Copyright (C) 2011-2014 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+# Make unconditional expansion of undefined variables an error.  This
+# helps a lot in preventing typo-related bugs.
+set -u
+
+usage_error ()
+{
+  echo "$0: $*" >&2
+  print_usage >&2
+  exit 2
+}
+
+print_usage ()
+{
+  cat <<END
+Usage:
+  test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
+              [--expect-failure={yes|no}] [--color-tests={yes|no}]
+              [--enable-hard-errors={yes|no}] [--]
+              TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+END
+}
+
+test_name= # Used for reporting.
+log_file=  # Where to save the output of the test script.
+trs_file=  # Where to save the metadata of the test run.
+expect_failure=no
+color_tests=no
+enable_hard_errors=yes
+while test $# -gt 0; do
+  case $1 in
+  --help) print_usage; exit $?;;
+  --version) echo "test-driver $scriptversion"; exit $?;;
+  --test-name) test_name=$2; shift;;
+  --log-file) log_file=$2; shift;;
+  --trs-file) trs_file=$2; shift;;
+  --color-tests) color_tests=$2; shift;;
+  --expect-failure) expect_failure=$2; shift;;
+  --enable-hard-errors) enable_hard_errors=$2; shift;;
+  --) shift; break;;
+  -*) usage_error "invalid option: '$1'";;
+   *) break;;
+  esac
+  shift
+done
+
+missing_opts=
+test x"$test_name" = x && missing_opts="$missing_opts --test-name"
+test x"$log_file"  = x && missing_opts="$missing_opts --log-file"
+test x"$trs_file"  = x && missing_opts="$missing_opts --trs-file"
+if test x"$missing_opts" != x; then
+  usage_error "the following mandatory options are missing:$missing_opts"
+fi
+
+if test $# -eq 0; then
+  usage_error "missing argument"
+fi
+
+if test $color_tests = yes; then
+  # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
+  red='' # Red.
+  grn='' # Green.
+  lgn='' # Light green.
+  blu='' # Blue.
+  mgn='' # Magenta.
+  std=''     # No color.
+else
+  red= grn= lgn= blu= mgn= std=
+fi
+
+do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
+trap "st=129; $do_exit" 1
+trap "st=130; $do_exit" 2
+trap "st=141; $do_exit" 13
+trap "st=143; $do_exit" 15
+
+# Test script is run here.
+"$@" >$log_file 2>&1
+estatus=$?
+
+if test $enable_hard_errors = no && test $estatus -eq 99; then
+  tweaked_estatus=1
+else
+  tweaked_estatus=$estatus
+fi
+
+case $tweaked_estatus:$expect_failure in
+  0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
+  0:*)   col=$grn res=PASS  recheck=no  gcopy=no;;
+  77:*)  col=$blu res=SKIP  recheck=no  gcopy=yes;;
+  99:*)  col=$mgn res=ERROR recheck=yes gcopy=yes;;
+  *:yes) col=$lgn res=XFAIL recheck=no  gcopy=yes;;
+  *:*)   col=$red res=FAIL  recheck=yes gcopy=yes;;
+esac
+
+# Report the test outcome and exit status in the logs, so that one can
+# know whether the test passed or failed simply by looking at the '.log'
+# file, without the need of also peaking into the corresponding '.trs'
+# file (automake bug#11814).
+echo "$res $test_name (exit status: $estatus)" >>$log_file
+
+# Report outcome to console.
+echo "${col}${res}${std}: $test_name"
+
+# Register the test result, and other relevant metadata.
+echo ":test-result: $res" > $trs_file
+echo ":global-test-result: $res" >> $trs_file
+echo ":recheck: $recheck" >> $trs_file
+echo ":copy-in-global-log: $gcopy" >> $trs_file
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/final/lib/External/isl/test_inputs/affine.polylib b/final/lib/External/isl/test_inputs/affine.polylib
new file mode 100644
index 0000000..f14720c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/affine.polylib
@@ -0,0 +1,9 @@
+# the affine hull of {[a,b] : a=b && 1 <= a <= 163} ...
+3 4
+0 1 -1 0
+1 1  0 -1
+1 -1 0 163
+
+# ... is {[a,b] : a=b} (and not {[In_1,In_2]}, as Omega 1.2 claims)
+1 4
+0 1 -1 0
diff --git a/final/lib/External/isl/test_inputs/affine2.polylib b/final/lib/External/isl/test_inputs/affine2.polylib
new file mode 100644
index 0000000..c67db77
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/affine2.polylib
@@ -0,0 +1,9 @@
+5 5
+1 -2 0 1 0
+1 2 0 -1 1
+1 0 -2 1 0
+1 0 2 -1 1
+1 0 0 1 -1
+
+1 5
+0 1 -1 0 0
diff --git a/final/lib/External/isl/test_inputs/affine3.polylib b/final/lib/External/isl/test_inputs/affine3.polylib
new file mode 100644
index 0000000..f2bc9a2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/affine3.polylib
@@ -0,0 +1,7 @@
+3 4
+1 1 0 0
+1 -7 4 2
+1 5 -4 2
+
+1 4
+0 3 -2 0
diff --git a/final/lib/External/isl/test_inputs/application.omega b/final/lib/External/isl/test_inputs/application.omega
new file mode 100644
index 0000000..8f4fd1d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/application.omega
@@ -0,0 +1,3 @@
+{[x]}
+{[x] -> [y] : y = 2x}
+{[y]: Exists ( alpha : 2alpha = y)}
diff --git a/final/lib/External/isl/test_inputs/application2.omega b/final/lib/External/isl/test_inputs/application2.omega
new file mode 100644
index 0000000..f2af1e8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/application2.omega
@@ -0,0 +1,3 @@
+{[x] : x >= 0 && x <= 20 }
+{[x] -> [y] : y = 2x}
+{[y]: Exists ( alpha : 2alpha = y && 0 <= y && y <= 40)}
diff --git a/final/lib/External/isl/test_inputs/basicLinear.pwqp b/final/lib/External/isl/test_inputs/basicLinear.pwqp
new file mode 100644
index 0000000..0af7fab
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/basicLinear.pwqp
@@ -0,0 +1 @@
+[P, Q] -> { [n, m] -> n : n >= 1 and m >= n and m <= P and m <= Q }
diff --git a/final/lib/External/isl/test_inputs/basicLinear2.pwqp b/final/lib/External/isl/test_inputs/basicLinear2.pwqp
new file mode 100644
index 0000000..d411a36
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/basicLinear2.pwqp
@@ -0,0 +1 @@
+[P, Q] -> { [n, m] -> n : n >= 1 and m >= n and m <= P and n >= -1 + Q }
diff --git a/final/lib/External/isl/test_inputs/basicTest.pwqp b/final/lib/External/isl/test_inputs/basicTest.pwqp
new file mode 100644
index 0000000..52e7fc8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/basicTest.pwqp
@@ -0,0 +1 @@
+[p] -> { [n, m] -> (n + n^2) : n >= 1 and m >= n and m <= p }
diff --git a/final/lib/External/isl/test_inputs/basicTestParameterPosNeg.pwqp b/final/lib/External/isl/test_inputs/basicTestParameterPosNeg.pwqp
new file mode 100644
index 0000000..6cb4490
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/basicTestParameterPosNeg.pwqp
@@ -0,0 +1 @@
+[p] -> { [n, m] -> (n + n^3) : n >= -1 and m >= n and m <= p }
diff --git a/final/lib/External/isl/test_inputs/boulet.pip b/final/lib/External/isl/test_inputs/boulet.pip
new file mode 100644
index 0000000..78e90dd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/boulet.pip
@@ -0,0 +1,13 @@
+0 3
+
+-1
+
+5 6
+1 1 -1  2 0 0
+1 0  1  1 4 20
+1 0 -1 -1 0 0
+1 0  1 -1 2 10
+1 0 -1  1 2 10
+
+Urs_parms
+Urs_unknowns
diff --git a/final/lib/External/isl/test_inputs/brisebarre.pip b/final/lib/External/isl/test_inputs/brisebarre.pip
new file mode 100644
index 0000000..f3decad
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/brisebarre.pip
@@ -0,0 +1,34 @@
+# ---------------------- CONTEXT ----------------------
+1 2
+1    0
+
+-1
+
+# ----------------------- DOMAIN ----------------------
+26 6
+1    3    0    0     0    -98300
+1   -3    0    0     0     98308
+1  432   36    6     1 -14757611
+1 -432  -36   -6    -1  14758510
+1   54    9    3     1  -1923190
+1  -54   -9   -3    -1   1923303
+1   48   12    6     3  -1782238
+1  -48  -12   -6    -3   1782339
+1   27    9    6     4  -1045164
+1  -27   -9   -6    -4   1045221
+1  432  180  150   125 -17434139
+1 -432 -180 -150  -125  17435038
+1    6    3    3     3   -252443
+1   -6   -3   -3    -3    252456
+1  432  252  294   343 -18949275
+1 -432 -252 -294  -343  18950174
+1   27   18   24    32  -1234720
+1  -27  -18  -24   -32   1234777
+1   48   36   54    81  -2288453
+1  -48  -36  -54   -81   2288554
+1   54   45   75   125  -2684050
+1  -54  -45  -75  -125   2684163
+1  432  396  726  1331 -22386005
+1 -432 -396 -726 -1331  22386904
+1    3    3    6    12   -162072
+1   -3   -3   -6   -12    162080
diff --git a/final/lib/External/isl/test_inputs/cg1.pip b/final/lib/External/isl/test_inputs/cg1.pip
new file mode 100644
index 0000000..78e31f1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/cg1.pip
@@ -0,0 +1,15 @@
+2 4
+  1  1  0 -1
+  1 -1  1  0
+
+-1
+
+8 7
+  1  0  1  0 -1  0  0
+  1  0 -1  0  1  0  0
+  1  1  0  0  0 -1  0
+  1 -1  0  0  0  1  0
+  1  0  1  0  0  0 -1
+  1  0 -1  0  0  1  0
+  1  0 -1  1  0  0 -1
+  1  0  0 -1  0  1  0
diff --git a/final/lib/External/isl/test_inputs/codegen/atomic.c b/final/lib/External/isl/test_inputs/codegen/atomic.c
new file mode 100644
index 0000000..0b70279
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/atomic.c
@@ -0,0 +1,6 @@
+for (int c0 = 0; c0 <= 10; c0 += 1) {
+  if (c0 <= 9)
+    a(c0);
+  if (c0 >= 1)
+    b(c0 - 1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/atomic.in b/final/lib/External/isl/test_inputs/codegen/atomic.in
new file mode 100644
index 0000000..6d8f818
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/atomic.in
@@ -0,0 +1,3 @@
+{ a[i] -> [i, 0] : 0 <= i < 10; b[i] -> [i+1, 1] : 0 <= i < 10 }
+{ : }
+{ [i, d] -> atomic[x] }
diff --git a/final/lib/External/isl/test_inputs/codegen/atomic.st b/final/lib/External/isl/test_inputs/codegen/atomic.st
new file mode 100644
index 0000000..7591b05
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/atomic.st
@@ -0,0 +1,8 @@
+domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }"
+child:
+  schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]"
+  options: "{ atomic[x] }"
+  child:
+    sequence:
+    - filter: "{ a[i] }"
+    - filter: "{ b[i] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/atomic2.c b/final/lib/External/isl/test_inputs/codegen/atomic2.c
new file mode 100644
index 0000000..9c4a57e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/atomic2.c
@@ -0,0 +1,2 @@
+for (int c0 = ((b0 + 32767) % 32768) + 1; c0 <= 65534; c0 += 32768)
+  A(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/atomic2.in b/final/lib/External/isl/test_inputs/codegen/atomic2.in
new file mode 100644
index 0000000..99901d0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/atomic2.in
@@ -0,0 +1,4 @@
+# Check that isl properly handles atomic domains that are unions.
+[nn, b0] -> { A[a] -> [a, 0, b0] : exists (e0 = [(b0 - a)/32768]: 32768e0 = b0 - a and a >= 1 and b0 >= 0 and b0 <= 32767 and a <= 65534) }
+[nn, b0] -> { : b0 >= 0 and b0 <= 32767 }
+[nn, b0] -> { [a, b, c] -> atomic[2] : c >= 1; [a, 0, c] -> atomic[2] }
diff --git a/final/lib/External/isl/test_inputs/codegen/atomic3.c b/final/lib/External/isl/test_inputs/codegen/atomic3.c
new file mode 100644
index 0000000..c6deb76
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/atomic3.c
@@ -0,0 +1,9 @@
+for (int c0 = 0; c0 <= 64; c0 += 1) {
+  if (c0 >= 63) {
+    sync();
+  } else if (c0 >= 1) {
+    sync();
+  } else {
+    sync();
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/atomic3.in b/final/lib/External/isl/test_inputs/codegen/atomic3.in
new file mode 100644
index 0000000..4d0c495
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/atomic3.in
@@ -0,0 +1,5 @@
+# Check that isl is not confused by inconsistent
+# separation_class and atomic options.
+{ sync[] -> [i, 0] : 0 <= i <= 64 }
+{ : }
+{ [i, 0] -> separation_class[[1] -> [0]] : 1 <= i <= 62; [i, 0] -> atomic[1]}
diff --git a/final/lib/External/isl/test_inputs/codegen/atomic4.c b/final/lib/External/isl/test_inputs/codegen/atomic4.c
new file mode 100644
index 0000000..624c2af
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/atomic4.c
@@ -0,0 +1,2 @@
+for (int c0 = 0; c0 <= 64; c0 += 1)
+  sync();
diff --git a/final/lib/External/isl/test_inputs/codegen/atomic4.in b/final/lib/External/isl/test_inputs/codegen/atomic4.in
new file mode 100644
index 0000000..c5dab10
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/atomic4.in
@@ -0,0 +1,4 @@
+# Check that isl is not confused by inconsistent separate and atomic options.
+{ sync[] -> [i, 0] : 0 <= i <= 64 }
+{ : }
+{ [i, 0] -> separate[1] : 1 <= i <= 62; [i, 0] -> atomic[1] : i <= 10 or i >= 20 }
diff --git a/final/lib/External/isl/test_inputs/codegen/cholesky.c b/final/lib/External/isl/test_inputs/codegen/cholesky.c
new file mode 100644
index 0000000..7e6f215
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cholesky.c
@@ -0,0 +1,4 @@
+for (int c0 = 3993; c0 <= 63893; c0 += 1)
+  if (2 * c0 - 3993 * ((3 * c0 + 5990) / 5990) >= 0)
+    for (int c4 = -c0 + 1997 * ((3 * c0 + 5990) / 5990) + 1; c4 <= 12; c4 += 1)
+      S_3(c4, -c0 + 1997 * ((3 * c0 + 5990) / 5990), 2 * c0 - 3993 * ((3 * c0 + 5990) / 5990));
diff --git a/final/lib/External/isl/test_inputs/codegen/cholesky.st b/final/lib/External/isl/test_inputs/codegen/cholesky.st
new file mode 100644
index 0000000..2dd62b9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cholesky.st
@@ -0,0 +1,9 @@
+# Earlier versions of isl would fail to produce an AST for this input
+# due to a simplification bug.
+domain: "{ S_3[i, j, k] : 0 <= i <= 12 and 0 <= j < i and 0 <= k < j }"
+child:
+  schedule: "[{ S_3[i, j, k] -> [(3993j + 1997k)] }]"
+  child:
+    schedule: "[{ S_3[i, j, k] -> [(32*floor((2j + k)/32))] }, { S_3[i, j, k] -> [(32*floor((i)/32))] }]"
+    child:
+      schedule: "[{ S_3[i, j, k] -> [(2j + k - 32*floor((2j + k)/32))] }, { S_3[i, j, k] -> [(i)] }]"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/0D-1.c b/final/lib/External/isl/test_inputs/codegen/cloog/0D-1.c
new file mode 100644
index 0000000..7f22e2e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/0D-1.c
@@ -0,0 +1 @@
+S1();
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/0D-1.st b/final/lib/External/isl/test_inputs/codegen/cloog/0D-1.st
new file mode 100644
index 0000000..d718258
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/0D-1.st
@@ -0,0 +1,3 @@
+domain: "{ S1[] }"
+child:
+  context: "{ [] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/0D-2.c b/final/lib/External/isl/test_inputs/codegen/cloog/0D-2.c
new file mode 100644
index 0000000..b87b57e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/0D-2.c
@@ -0,0 +1,2 @@
+if (M >= 0)
+  S1();
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/0D-2.st b/final/lib/External/isl/test_inputs/codegen/cloog/0D-2.st
new file mode 100644
index 0000000..3ee60f6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/0D-2.st
@@ -0,0 +1,3 @@
+domain: "[M] -> { S1[] : M >= 0 }"
+child:
+  context: "[M] -> { [] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/0D-3.c b/final/lib/External/isl/test_inputs/codegen/cloog/0D-3.c
new file mode 100644
index 0000000..7f22e2e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/0D-3.c
@@ -0,0 +1 @@
+S1();
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/0D-3.st b/final/lib/External/isl/test_inputs/codegen/cloog/0D-3.st
new file mode 100644
index 0000000..97cd37e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/0D-3.st
@@ -0,0 +1,3 @@
+domain: "[M] -> { S1[] : M >= 0 }"
+child:
+  context: "[M] -> { [] : M >= 0 }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/1point-1.c b/final/lib/External/isl/test_inputs/codegen/cloog/1point-1.c
new file mode 100644
index 0000000..53dd893
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/1point-1.c
@@ -0,0 +1 @@
+S1(2 * M, M);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/1point-1.st b/final/lib/External/isl/test_inputs/codegen/cloog/1point-1.st
new file mode 100644
index 0000000..6194878
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/1point-1.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S1[2M, M] }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/1point-2.c b/final/lib/External/isl/test_inputs/codegen/cloog/1point-2.c
new file mode 100644
index 0000000..0a8cbe3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/1point-2.c
@@ -0,0 +1 @@
+S1(2 * M, N + 2);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/1point-2.st b/final/lib/External/isl/test_inputs/codegen/cloog/1point-2.st
new file mode 100644
index 0000000..9e7adfa
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/1point-2.st
@@ -0,0 +1,6 @@
+domain: "[M, N] -> { S1[2M, 2 + N] }"
+child:
+  context: "[M, N] -> { [] }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]"
+    options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/4-param.c b/final/lib/External/isl/test_inputs/codegen/cloog/4-param.c
new file mode 100644
index 0000000..bd38c70
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/4-param.c
@@ -0,0 +1,14 @@
+{
+  for (int c0 = p; c0 <= min(m - 1, q); c0 += 1)
+    S2(c0);
+  for (int c0 = m; c0 <= min(n, p - 1); c0 += 1)
+    S1(c0);
+  for (int c0 = max(m, p); c0 <= min(n, q); c0 += 1) {
+    S1(c0);
+    S2(c0);
+  }
+  for (int c0 = max(max(m, n + 1), p); c0 <= q; c0 += 1)
+    S2(c0);
+  for (int c0 = max(max(m, p), q + 1); c0 <= n; c0 += 1)
+    S1(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/4-param.st b/final/lib/External/isl/test_inputs/codegen/cloog/4-param.st
new file mode 100644
index 0000000..2433595
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/4-param.st
@@ -0,0 +1,10 @@
+domain: "[m, n, p, q] -> { S1[i0] : i0 >= m and i0 <= n; S2[i0] : i0 >= p and i0 <= q }"
+child:
+  context: "[m, n, p, q] -> { [] }"
+  child:
+    schedule: "[m, n, p, q] -> [{ S2[i0] -> [(i0)]; S1[i0] -> [(i0)] }]"
+    options: "[m, n, p, q] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[m, n, p, q] -> { S1[i0] }"
+      - filter: "[m, n, p, q] -> { S2[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/README b/final/lib/External/isl/test_inputs/codegen/cloog/README
new file mode 100644
index 0000000..9250f11
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/README
@@ -0,0 +1,2 @@
+The tests in this directory have been adapted from the corresponding CLooG
+test cases.
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/backtrack.c b/final/lib/External/isl/test_inputs/codegen/cloog/backtrack.c
new file mode 100644
index 0000000..df0407a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/backtrack.c
@@ -0,0 +1 @@
+S1(0);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/backtrack.st b/final/lib/External/isl/test_inputs/codegen/cloog/backtrack.st
new file mode 100644
index 0000000..23fb152
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/backtrack.st
@@ -0,0 +1,6 @@
+domain: "{ S1[0] }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0] -> [(i0)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-1.c b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-1.c
new file mode 100644
index 0000000..95eb5f7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-1.c
@@ -0,0 +1,2 @@
+for (int c0 = 0; c0 <= 2; c0 += 1)
+  S1(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-1.st b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-1.st
new file mode 100644
index 0000000..7c599e8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-1.st
@@ -0,0 +1,6 @@
+domain: "{ S1[i0] : i0 >= 0 and i0 <= 2 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0] -> [(i0)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-2.c b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-2.c
new file mode 100644
index 0000000..df0407a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-2.c
@@ -0,0 +1 @@
+S1(0);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-2.st b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-2.st
new file mode 100644
index 0000000..23fb152
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-2.st
@@ -0,0 +1,6 @@
+domain: "{ S1[0] }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0] -> [(i0)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-3.c b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-3.c
new file mode 100644
index 0000000..d0dd54b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-3.c
@@ -0,0 +1,2 @@
+for (int c0 = 0; c0 <= M; c0 += 1)
+  S1(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-3.st b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-3.st
new file mode 100644
index 0000000..437f566
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-3.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S1[i0] : i0 >= 0 and i0 <= M }"
+child:
+  context: "[M] -> { [] : M >= 0 }"
+  child:
+    schedule: "[M] -> [{ S1[i0] -> [(i0)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-4.c b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-4.c
new file mode 100644
index 0000000..0ebb7cc
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-4.c
@@ -0,0 +1,2 @@
+for (int c0 = 0; c0 <= M + 1; c0 += 1)
+  S1(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-4.st b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-4.st
new file mode 100644
index 0000000..a5a0b1a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-4.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S1[i0] : i0 >= 0 and i0 <= 1 + M }"
+child:
+  context: "[M] -> { [] : M >= 0 }"
+  child:
+    schedule: "[M] -> [{ S1[i0] -> [(i0)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-5.c b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-5.c
new file mode 100644
index 0000000..09e8c42
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-5.c
@@ -0,0 +1 @@
+S1(1, floord(M + 1, 2));
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-5.st b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-5.st
new file mode 100644
index 0000000..e0bc58f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-5.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S1[1, i1] : 2i1 >= M and 2i1 <= 1 + M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-6.c b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-6.c
new file mode 100644
index 0000000..da8a3fb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-6.c
@@ -0,0 +1 @@
+S1(-1);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-6.st b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-6.st
new file mode 100644
index 0000000..a65f088
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/basic-bounds-6.st
@@ -0,0 +1,6 @@
+domain: "{ S1[-1] }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0] -> [(i0)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/block.c b/final/lib/External/isl/test_inputs/codegen/cloog/block.c
new file mode 100644
index 0000000..e24ef30
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/block.c
@@ -0,0 +1,6 @@
+{
+  S1();
+  S3(0);
+  S2();
+  S3(1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/block.st b/final/lib/External/isl/test_inputs/codegen/cloog/block.st
new file mode 100644
index 0000000..0ab2d88
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/block.st
@@ -0,0 +1,10 @@
+domain: "{ S1[]; S3[i0] : i0 >= 0 and i0 <= 1; S2[] }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S2[] -> [(1)]; S3[i0] -> [(i0)]; S1[] -> [(0)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[]; S2[] }"
+      - filter: "{ S3[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/block2.c b/final/lib/External/isl/test_inputs/codegen/cloog/block2.c
new file mode 100644
index 0000000..d3fbbd7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/block2.c
@@ -0,0 +1,5 @@
+for (int c0 = 0; c0 <= 9; c0 += 1) {
+  S1(c0, 1);
+  S3(c0, 1);
+  S2(c0, 1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/block2.st b/final/lib/External/isl/test_inputs/codegen/cloog/block2.st
new file mode 100644
index 0000000..b18ce92
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/block2.st
@@ -0,0 +1,11 @@
+domain: "{ S2[i0, 1] : i0 >= 0 and i0 <= 9; S1[i0, 1] : i0 >= 0 and i0 <= 9; S3[i0, 1] : i0 >= 0 and i0 <= 9 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S3[i0, i1] -> [(i0)]; S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S3[i0, i1] -> [(i1)]; S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[i0, i1] }"
+      - filter: "{ S3[i0, i1] }"
+      - filter: "{ S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/block3.c b/final/lib/External/isl/test_inputs/codegen/cloog/block3.c
new file mode 100644
index 0000000..ff4d553
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/block3.c
@@ -0,0 +1,6 @@
+{
+  S1();
+  for (int c0 = 0; c0 <= 1; c0 += 1)
+    S3(c0);
+  S2();
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/block3.st b/final/lib/External/isl/test_inputs/codegen/cloog/block3.st
new file mode 100644
index 0000000..85f197f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/block3.st
@@ -0,0 +1,6 @@
+domain: "{ S1[]; S3[i0] : i0 >= 0 and i0 <= 1; S2[] }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S2[] -> [(1)]; S3[i0] -> [(i0)]; S1[] -> [(0)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/byu98-1-2-3.c b/final/lib/External/isl/test_inputs/codegen/cloog/byu98-1-2-3.c
new file mode 100644
index 0000000..fad89a9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/byu98-1-2-3.c
@@ -0,0 +1,18 @@
+{
+  for (int c0 = 2; c0 <= 3; c0 += 1)
+    for (int c1 = -c0 + 6; c1 <= 6; c1 += 1)
+      S1(c0, c1);
+  for (int c0 = 4; c0 <= 8; c0 += 1) {
+    if (c0 == 4)
+      for (int c1 = 3; c1 <= 4; c1 += 1)
+        S1(4, c1);
+    if (c0 <= 5) {
+      S1(c0, -c0 + 9);
+      S2(c0, -c0 + 9);
+    } else {
+      S2(c0, -c0 + 9);
+    }
+    for (int c1 = max(c0 - 1, -c0 + 10); c1 <= 6; c1 += 1)
+      S1(c0, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/byu98-1-2-3.st b/final/lib/External/isl/test_inputs/codegen/cloog/byu98-1-2-3.st
new file mode 100644
index 0000000..84d3791
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/byu98-1-2-3.st
@@ -0,0 +1,10 @@
+domain: "{ S2[i0, 9 - i0] : i0 <= 8 and i0 >= 4; S1[i0, i1] : i1 >= 6 - i0 and i0 >= 2 and i1 >= 3 and i1 <= 6 and i1 >= -1 + i0 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[i0, i1] }"
+      - filter: "{ S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/cholesky.c b/final/lib/External/isl/test_inputs/codegen/cloog/cholesky.c
new file mode 100644
index 0000000..1cf61c2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/cholesky.c
@@ -0,0 +1,12 @@
+for (int c0 = 1; c0 <= n; c0 += 1) {
+  S1(c0);
+  for (int c1 = 1; c1 < c0; c1 += 1)
+    S2(c0, c1);
+  S3(c0);
+  for (int c1 = c0 + 1; c1 <= n; c1 += 1) {
+    S4(c0, c1);
+    for (int c2 = 1; c2 < c0; c2 += 1)
+      S5(c0, c1, c2);
+    S6(c0, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/cholesky.st b/final/lib/External/isl/test_inputs/codegen/cloog/cholesky.st
new file mode 100644
index 0000000..a6e910a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/cholesky.st
@@ -0,0 +1,26 @@
+domain: "[n] -> { S2[i0, i1] : i0 >= 1 and i0 <= n and i1 >= 1 and i1 <= -1 + i0; S1[i0] : i0 >= 1 and i0 <= n; S4[i0, i1] : i0 >= 1 and i0 <= n and i1 >= 1 + i0 and i1 <= n; S5[i0, i1, i2] : i0 >= 1 and i0 <= n and i1 >= 1 + i0 and i1 <= n and i2 >= 1 and i2 <= -1 + i0; S6[i0, i1] : i0 >= 1 and i0 <= n and i1 >= 1 + i0 and i1 <= n; S3[i0] : i0 >= 1 and i0 <= n }"
+child:
+  context: "[n] -> { [] }"
+  child:
+    schedule: "[n] -> [{ S1[i0] -> [(i0)]; S4[i0, i1] -> [(i0)]; S6[i0, i1] -> [(i0)]; S3[i0] -> [(i0)]; S5[i0, i1, i2] -> [(i0)]; S2[i0, i1] -> [(i0)] }]"
+    options: "[n] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[n] -> { S1[i0] }"
+      - filter: "[n] -> { S2[i0, i1] }"
+        child:
+          schedule: "[n] -> [{ S2[i0, i1] -> [(i1)] }]"
+          options: "[n] -> { separate[i0] }"
+      - filter: "[n] -> { S3[i0] }"
+      - filter: "[n] -> { S4[i0, i1]; S5[i0, i1, i2]; S6[i0, i1] }"
+        child:
+          schedule: "[n] -> [{ S4[i0, i1] -> [(i1)]; S6[i0, i1] -> [(i1)]; S5[i0, i1, i2] -> [(i1)] }]"
+          options: "[n] -> { separate[i0] }"
+          child:
+            sequence:
+            - filter: "[n] -> { S4[i0, i1] }"
+            - filter: "[n] -> { S5[i0, i1, i2] }"
+              child:
+                schedule: "[n] -> [{ S5[i0, i1, i2] -> [(i2)] }]"
+                options: "[n] -> { separate[i0] }"
+            - filter: "[n] -> { S6[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/cholesky2.c b/final/lib/External/isl/test_inputs/codegen/cloog/cholesky2.c
new file mode 100644
index 0000000..7834ff4
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/cholesky2.c
@@ -0,0 +1,17 @@
+{
+  for (int c1 = 1; c1 <= M; c1 += 1) {
+    S1(c1);
+    for (int c2 = c1 + 1; c2 <= M; c2 += 1)
+      S4(c1, c2);
+  }
+  for (int c0 = 1; c0 < 3 * M - 1; c0 += 3) {
+    S3((c0 + 2) / 3);
+    for (int c1 = (c0 + 5) / 3; c1 <= M; c1 += 1) {
+      S6((c0 + 2) / 3, c1);
+      for (int c4 = (c0 + 5) / 3; c4 < c1; c4 += 1)
+        S5(c4, c1, (c0 + 2) / 3);
+    }
+    for (int c1 = (c0 + 5) / 3; c1 <= M; c1 += 1)
+      S2(c1, (c0 + 2) / 3);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/cholesky2.st b/final/lib/External/isl/test_inputs/codegen/cloog/cholesky2.st
new file mode 100644
index 0000000..d49ff85
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/cholesky2.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S4[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 + i0 and i1 <= M; S5[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 1 + i0 and i1 <= M and i2 >= 1 and i2 <= -1 + i0; S6[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 + i0 and i1 <= M; S3[i0] : i0 >= 1 and i0 <= M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= -1 + i0; S1[i0] : i0 >= 1 and i0 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0] -> [(0)]; S3[i0] -> [(-2 + 3i0)]; S4[i0, i1] -> [(0)]; S5[i0, i1, i2] -> [(-1 + 3i2)]; S2[i0, i1] -> [(3i1)]; S6[i0, i1] -> [(-1 + 3i0)] }, { S1[i0] -> [(i0)]; S3[i0] -> [(0)]; S4[i0, i1] -> [(i0)]; S5[i0, i1, i2] -> [(i1)]; S2[i0, i1] -> [(i0)]; S6[i0, i1] -> [(i1)] }, { S1[i0] -> [(0)]; S3[i0] -> [(0)]; S4[i0, i1] -> [(i1)]; S5[i0, i1, i2] -> [(i2)]; S2[i0, i1] -> [(0)]; S6[i0, i1] -> [(0)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/christian.c b/final/lib/External/isl/test_inputs/codegen/cloog/christian.c
new file mode 100644
index 0000000..113249a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/christian.c
@@ -0,0 +1,6 @@
+for (int c0 = -N + 1; c0 <= N; c0 += 1) {
+  for (int c1 = max(0, c0); c1 < min(N, N + c0); c1 += 1)
+    S1(c1, -c0 + c1);
+  for (int c1 = max(0, c0 - 1); c1 < min(N, N + c0 - 1); c1 += 1)
+    S2(c1, -c0 + c1 + 1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/christian.st b/final/lib/External/isl/test_inputs/codegen/cloog/christian.st
new file mode 100644
index 0000000..b451774
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/christian.st
@@ -0,0 +1,6 @@
+domain: "[N] -> { S1[i0, i1] : i0 >= 0 and i0 <= -1 + N and i1 >= 0 and i1 <= -1 + N; S2[i0, i1] : i0 >= 0 and i0 <= -1 + N and i1 >= 0 and i1 <= -1 + N }"
+child:
+  context: "[N] -> { [] }"
+  child:
+    schedule: "[N] -> [{ S1[i0, i1] -> [(i0 - i1)]; S2[i0, i1] -> [(1 + i0 - i1)] }]"
+    options: "[N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/classen.c b/final/lib/External/isl/test_inputs/codegen/cloog/classen.c
new file mode 100644
index 0000000..3155aa7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/classen.c
@@ -0,0 +1,86 @@
+if (m >= 1) {
+  if (m == 1) {
+    S1(0, 1, 1, 1);
+    S8(0, 1);
+  } else {
+    S1(0, 1, 1, 1);
+    S2(0, 1, 1, 1, 1, 1, 2, 1);
+    S3(0, 1, 1, 2, 1, 1, 1, 2);
+    S4(0, 1, 2, 2, 1, 1, 2, 2);
+    S8(0, 1);
+  }
+  for (int c0 = 1; c0 < 2 * m - 3; c0 += 1) {
+    if (c0 + 1 == m) {
+      S5(m - 2, 1, m - 1, 1, m - 1, 1, m, 1);
+      S1(m - 1, 1, m, 1);
+      S3(m - 1, 1, m, 2, m, 1, m, 2);
+    } else if (m >= c0 + 2) {
+      S5(c0 - 1, 1, c0, 1, c0, 1, c0 + 1, 1);
+      S1(c0, 1, c0 + 1, 1);
+      S2(c0, 1, c0 + 1, 1, c0 + 1, 1, c0 + 2, 1);
+      S4(c0, 1, c0 + 2, 2, c0 + 1, 1, c0 + 2, 2);
+      S3(c0, 1, c0 + 1, 2, c0 + 1, 1, c0 + 1, 2);
+    } else {
+      S5(c0 - 1, -m + c0 + 2, c0, -m + c0 + 2, m - 1, -m + c0 + 2, m, -m + c0 + 2);
+      S6(c0 - 1, -m + c0 + 1, c0, -m + c0 + 2, m, -m + c0 + 1, m, -m + c0 + 2);
+      S1(c0, -m + c0 + 2, m, -m + c0 + 2);
+      S3(c0, -m + c0 + 2, c0 + 1, -m + c0 + 3, m, -m + c0 + 2, m, -m + c0 + 3);
+    }
+    for (int c1 = max(2, -m + c0 + 3); c1 <= min(m - 1, c0); c1 += 1) {
+      S5(c0 - 1, c1, c0, c1, c0 - c1 + 1, c1, c0 - c1 + 2, c1);
+      S7(c0 - 1, c1 - 1, c0 + 1, c1, c0 - c1 + 2, c1 - 1, c0 - c1 + 3, c1);
+      S6(c0 - 1, c1 - 1, c0, c1, c0 - c1 + 2, c1 - 1, c0 - c1 + 2, c1);
+      S1(c0, c1, c0 - c1 + 2, c1);
+      S2(c0, c1, c0 + 1, c1, c0 - c1 + 2, c1, c0 - c1 + 3, c1);
+      S4(c0, c1, c0 + 2, c1 + 1, c0 - c1 + 2, c1, c0 - c1 + 3, c1 + 1);
+      S3(c0, c1, c0 + 1, c1 + 1, c0 - c1 + 2, c1, c0 - c1 + 2, c1 + 1);
+    }
+    if (c0 + 1 == m) {
+      S7(m - 2, m - 1, m, m, 1, m - 1, 2, m);
+      S6(m - 2, m - 1, m - 1, m, 1, m - 1, 1, m);
+      S1(m - 1, m, 1, m);
+      S2(m - 1, m, m, m, 1, m, 2, m);
+    } else if (c0 >= m) {
+      S5(c0 - 1, m, c0, m, -m + c0 + 1, m, -m + c0 + 2, m);
+      S7(c0 - 1, m - 1, c0 + 1, m, -m + c0 + 2, m - 1, -m + c0 + 3, m);
+      S6(c0 - 1, m - 1, c0, m, -m + c0 + 2, m - 1, -m + c0 + 2, m);
+      S1(c0, m, -m + c0 + 2, m);
+      S2(c0, m, c0 + 1, m, -m + c0 + 2, m, -m + c0 + 3, m);
+    } else {
+      S6(c0 - 1, c0, c0, c0 + 1, 1, c0, 1, c0 + 1);
+      S7(c0 - 1, c0, c0 + 1, c0 + 1, 1, c0, 2, c0 + 1);
+      S1(c0, c0 + 1, 1, c0 + 1);
+      S2(c0, c0 + 1, c0 + 1, c0 + 1, 1, c0 + 1, 2, c0 + 1);
+      S4(c0, c0 + 1, c0 + 2, c0 + 2, 1, c0 + 1, 2, c0 + 2);
+      S3(c0, c0 + 1, c0 + 1, c0 + 2, 1, c0 + 1, 1, c0 + 2);
+    }
+    for (int c2 = max(1, -m + c0 + 2); c2 <= min(m, c0 + 1); c2 += 1)
+      S8(c0, c2);
+  }
+  if (m >= 2) {
+    if (m >= 3) {
+      S5(2 * m - 4, m - 1, 2 * m - 3, m - 1, m - 1, m - 1, m, m - 1);
+      S6(2 * m - 4, m - 2, 2 * m - 3, m - 1, m, m - 2, m, m - 1);
+      S1(2 * m - 3, m - 1, m, m - 1);
+      S3(2 * m - 3, m - 1, 2 * m - 2, m, m, m - 1, m, m);
+      S5(2 * m - 4, m, 2 * m - 3, m, m - 2, m, m - 1, m);
+      S7(2 * m - 4, m - 1, 2 * m - 2, m, m - 1, m - 1, m, m);
+      S6(2 * m - 4, m - 1, 2 * m - 3, m, m - 1, m - 1, m - 1, m);
+      S1(2 * m - 3, m, m - 1, m);
+    } else {
+      S5(0, 1, 1, 1, 1, 1, 2, 1);
+      S1(1, 1, 2, 1);
+      S3(1, 1, 2, 2, 2, 1, 2, 2);
+      S7(0, 1, 2, 2, 1, 1, 2, 2);
+      S6(0, 1, 1, 2, 1, 1, 1, 2);
+      S1(1, 2, 1, 2);
+    }
+    S2(2 * m - 3, m, 2 * m - 2, m, m - 1, m, m, m);
+    for (int c2 = m - 1; c2 <= m; c2 += 1)
+      S8(2 * m - 3, c2);
+    S5(2 * m - 3, m, 2 * m - 2, m, m - 1, m, m, m);
+    S6(2 * m - 3, m - 1, 2 * m - 2, m, m, m - 1, m, m);
+    S1(2 * m - 2, m, m, m);
+    S8(2 * m - 2, m);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/classen.st b/final/lib/External/isl/test_inputs/codegen/cloog/classen.st
new file mode 100644
index 0000000..e9d3baf
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/classen.st
@@ -0,0 +1,24 @@
+domain: "[m] -> { S2[coordT1, coordP1, 1 + coordT1, coordP1, 2 + coordT1 - coordP1, coordP1, 3 + coordT1 - coordP1, coordP1] : m >= 1 and coordT1 <= -3 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= m and coordP1 >= 3 - m + coordT1 and coordP1 >= 1; S4[coordT1, coordP1, 2 + coordT1, 1 + coordP1, 2 + coordT1 - coordP1, coordP1, 3 + coordT1 - coordP1, 1 + coordP1] : m >= 1 and coordT1 <= -4 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= -1 + m and coordP1 >= 3 - m + coordT1 and coordP1 >= 1; S6[coordT1, coordP1, 1 + coordT1, 1 + coordP1, 2 + coordT1 - coordP1, coordP1, 2 + coordT1 - coordP1, 1 + coordP1] : m >= 1 and coordT1 <= -3 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= -1 + m and coordP1 >= 2 - m + coordT1 and coordP1 >= 1; S1[coordT1, coordP1, 2 + coordT1 - coordP1, coordP1] : m >= 1 and coordP1 >= 2 - m + coordT1 and coordP1 <= 1 + coordT1 and coordP1 <= m and coordP1 >= 1; S8[coordT1, coordP1] : coordT1 <= -2 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= m and coordP1 >= 2 - m + coordT1 and coordP1 >= 1; S5[coordT1, coordP1, 1 + coordT1, coordP1, 2 + coordT1 - coordP1, coordP1, 3 + coordT1 - coordP1, coordP1] : m >= 1 and coordT1 <= -3 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= m and coordP1 >= 3 - m + coordT1 and coordP1 >= 1; S7[coordT1, coordP1, 2 + coordT1, 1 + coordP1, 2 + coordT1 - coordP1, coordP1, 3 + coordT1 - coordP1, 1 + coordP1] : m >= 1 and coordT1 <= -4 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= -1 + m and coordP1 >= 3 - m + coordT1 and coordP1 >= 1; S3[coordT1, coordP1, 1 + coordT1, 1 + coordP1, 2 + coordT1 - coordP1, coordP1, 2 + coordT1 - coordP1, 1 + coordP1] : m >= 1 and coordT1 <= -3 + 2m and coordT1 >= 0 and coordP1 <= 1 + coordT1 and coordP1 <= -1 + m and coordP1 >= 2 - m + coordT1 and coordP1 >= 1 }"
+child:
+  context: "[m] -> { [] : m >= 0 }"
+  child:
+    schedule: "[m] -> [{ S7[i0, i1, i2, i3, i4, i5, i6, i7] -> [(1 + i0)]; S4[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i0)]; S8[i0, i1] -> [(i0)]; S3[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i0)]; S1[i0, i1, i2, i3] -> [(i0)]; S2[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i0)]; S5[i0, i1, i2, i3, i4, i5, i6, i7] -> [(1 + i0)]; S6[i0, i1, i2, i3, i4, i5, i6, i7] -> [(1 + i0)] }]"
+    options: "[m] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[m] -> { S2[i0, i1, i2, i3, i4, i5, i6, i7]; S6[i0, i1, i2, i3, i4, i5, i6, i7]; S4[i0, i1, i2, i3, i4, i5, i6, i7]; S1[i0, i1, i2, i3]; S7[i0, i1, i2, i3, i4, i5, i6, i7]; S5[i0, i1, i2, i3, i4, i5, i6, i7]; S3[i0, i1, i2, i3, i4, i5, i6, i7] }"
+        child:
+          schedule: "[m] -> [{ S7[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i3)]; S4[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i1)]; S3[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i1)]; S1[i0, i1, i2, i3] -> [(i1)]; S2[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i1)]; S5[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i3)]; S6[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i3)] }]"
+          options: "[m] -> { separate[i0] }"
+          child:
+            sequence:
+            - filter: "[m] -> { S6[i0, i1, i2, i3, i4, i5, i6, i7]; S5[i0, i1, i2, i3, i4, i5, i6, i7]; S7[i0, i1, i2, i3, i4, i5, i6, i7] }"
+              child:
+                schedule: "[m] -> [{ S7[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i4)]; S5[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i4)]; S6[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i4)] }, { S7[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i5)]; S5[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i5)]; S6[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i5)] }]"
+                options: "[m] -> { separate[i0] }"
+            - filter: "[m] -> { S1[i0, i1, i2, i3] }"
+            - filter: "[m] -> { S2[i0, i1, i2, i3, i4, i5, i6, i7]; S4[i0, i1, i2, i3, i4, i5, i6, i7]; S3[i0, i1, i2, i3, i4, i5, i6, i7] }"
+              child:
+                schedule: "[m] -> [{ S4[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i4)]; S3[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i4)]; S2[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i4)] }, { S4[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i5)]; S3[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i5)]; S2[i0, i1, i2, i3, i4, i5, i6, i7] -> [(i5)] }]"
+                options: "[m] -> { separate[i0] }"
+      - filter: "[m] -> { S8[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/classen2.c b/final/lib/External/isl/test_inputs/codegen/cloog/classen2.c
new file mode 100644
index 0000000..a737d2d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/classen2.c
@@ -0,0 +1,4 @@
+for (int c0 = max(max(max(max(max(max(4, 5 * outerTimeTileScatter), 5 * outerProcTileScatter1), 5 * outerProcTileScatter2 + 1), 5 * outerProcTileScatter1 + 5 * outerProcTileScatter2 - N), 10 * outerProcTileScatter2 - N + 1), 10 * outerProcTileScatter1 - 2 * N + 2); c0 <= min(min(min(min(min(min(5 * outerTimeTileScatter + 4, 10 * outerProcTileScatter1 + 4), 5 * outerProcTileScatter1 + 5 * outerProcTileScatter2 + 5), 5 * outerProcTileScatter1 + M + 2), 2 * M + 2 * N - 6), 5 * outerProcTileScatter2 + M + N), 10 * outerProcTileScatter2 + N + 3); c0 += 1)
+  for (int c1 = max(max(max(max(5 * outerProcTileScatter1, 5 * outerProcTileScatter2 + 1), -5 * outerProcTileScatter2 + c0 - 1), -M + c0 + 2), (c0 + 1) / 2 + 2); c1 <= min(min(min(min(5 * outerProcTileScatter1 + 4, 5 * outerProcTileScatter2 + N + 2), -5 * outerProcTileScatter2 + N + c0), c0), N + c0 / 2 - 1); c1 += 1)
+    for (int c2 = max(max(5 * outerProcTileScatter2, -N + c1 + 2), c0 - c1 + 3); c2 <= min(min(5 * outerProcTileScatter2 + 4, c1 - 1), N + c0 - c1); c2 += 1)
+      S1(c0 - c1 + 1, -c0 + c1 + c2 - 2, c1 - c2, c0, c1, c2);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/classen2.st b/final/lib/External/isl/test_inputs/codegen/cloog/classen2.st
new file mode 100644
index 0000000..f7115ca
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/classen2.st
@@ -0,0 +1,6 @@
+domain: "[outerTimeTileScatter, outerProcTileScatter1, outerProcTileScatter2, M, N] -> { S1[compIter1, compIter2, compIter3, 2compIter1 + compIter2 + compIter3, 1 + compIter1 + compIter2 + compIter3, 1 + compIter1 + compIter2] : N >= 3 and compIter3 <= 3 + 5outerProcTileScatter1 - compIter1 - compIter2 and compIter2 >= -1 + 5outerProcTileScatter2 - compIter1 and M >= 2 and compIter3 <= 4 + 5outerTimeTileScatter - 2compIter1 - compIter2 and compIter2 <= 3 + 5outerProcTileScatter2 - compIter1 and compIter3 >= 1 and compIter3 <= -2 + N and compIter2 >= 1 and compIter2 <= -2 + N and compIter1 >= 1 and compIter1 <= -1 + M and compIter3 >= 5outerTimeTileScatter - 2compIter1 - compIter2 and compIter3 >= -1 + 5outerProcTileScatter1 - compIter1 - compIter2 }"
+child:
+  context: "[outerTimeTileScatter, outerProcTileScatter1, outerProcTileScatter2, M, N] -> { [] }"
+  child:
+    schedule: "[outerTimeTileScatter, outerProcTileScatter1, outerProcTileScatter2, M, N] -> [{ S1[i0, i1, i2, i3, i4, i5] -> [(i3)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i4)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i5)] }]"
+    options: "[outerTimeTileScatter, outerProcTileScatter1, outerProcTileScatter2, M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/constant.c b/final/lib/External/isl/test_inputs/codegen/cloog/constant.c
new file mode 100644
index 0000000..f39a3a2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/constant.c
@@ -0,0 +1,18 @@
+{
+  for (int c1 = 0; c1 <= min(1023, M + 1024); c1 += 1) {
+    S1(c1);
+    S3(c1);
+  }
+  for (int c1 = max(0, M + 1025); c1 <= 1023; c1 += 1) {
+    S2(c1);
+    S3(c1);
+  }
+  for (int c0 = 0; c0 <= min(1023, M + 1024); c0 += 1) {
+    S4(c0);
+    S6(c0);
+  }
+  for (int c0 = max(0, M + 1025); c0 <= 1023; c0 += 1) {
+    S5(c0);
+    S6(c0);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/constant.st b/final/lib/External/isl/test_inputs/codegen/cloog/constant.st
new file mode 100644
index 0000000..f4f85f7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/constant.st
@@ -0,0 +1,11 @@
+domain: "[M] -> { S4[i0] : i0 >= 0 and i0 <= 1023 and i0 <= 1024 + M; S5[i0] : i0 >= 0 and i0 <= 1023 and i0 >= 1025 + M; S3[i0] : i0 >= 0 and i0 <= 1023; S2[i0] : i0 >= 0 and i0 <= 1023 and i0 >= 1025 + M; S1[i0] : i0 >= 0 and i0 <= 1023 and i0 <= 1024 + M; S6[i0] : i0 >= 0 and i0 <= 1023 }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S2[i0] -> [(-1)]; S4[i0] -> [(i0)]; S1[i0] -> [(-1)]; S3[i0] -> [(-1)]; S6[i0] -> [(i0)]; S5[i0] -> [(i0)] }, { S2[i0] -> [(i0)]; S4[i0] -> [(0)]; S1[i0] -> [(i0)]; S3[i0] -> [(i0)]; S6[i0] -> [(0)]; S5[i0] -> [(0)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S4[i0]; S1[i0] }"
+      - filter: "[M] -> { S5[i0]; S2[i0] }"
+      - filter: "[M] -> { S3[i0]; S6[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/constbound.c b/final/lib/External/isl/test_inputs/codegen/cloog/constbound.c
new file mode 100644
index 0000000..7fbebe0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/constbound.c
@@ -0,0 +1,8 @@
+for (int c0 = 0; c0 <= 199; c0 += 1) {
+  for (int c1 = 50 * c0; c1 <= 50 * c0 + 24; c1 += 1)
+    for (int c2 = 0; c2 <= c1; c2 += 1)
+      S1(c0, c1, c2);
+  for (int c1 = 50 * c0 + 25; c1 <= 50 * c0 + 49; c1 += 1)
+    for (int c2 = 0; c2 <= c1; c2 += 1)
+      S2(c0, c1, c2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/constbound.st b/final/lib/External/isl/test_inputs/codegen/cloog/constbound.st
new file mode 100644
index 0000000..1f6789e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/constbound.st
@@ -0,0 +1,16 @@
+domain: "{ S2[i0, i1, i2] : i1 >= 0 and i1 <= 9999 and i2 >= 0 and i2 <= i1 and i1 >= 25 + 50i0 and i1 <= 49 + 50i0; S1[i0, i1, i2] : i1 >= 0 and i1 <= 9999 and i2 >= 0 and i2 <= i1 and i1 >= 50i0 and i1 <= 24 + 50i0 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[i0, i1, i2] }"
+        child:
+          schedule: "[{ S1[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)] }]"
+          options: "{ separate[i0] }"
+      - filter: "{ S2[i0, i1, i2] }"
+        child:
+          schedule: "[{ S2[i0, i1, i2] -> [(i1)] }, { S2[i0, i1, i2] -> [(i2)] }]"
+          options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/darte.c b/final/lib/External/isl/test_inputs/codegen/cloog/darte.c
new file mode 100644
index 0000000..acb6371
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/darte.c
@@ -0,0 +1,14 @@
+for (int c0 = -n + 1; c0 <= n; c0 += 1) {
+  if (c0 <= 0)
+    for (int c2 = -c0 + 4; c2 <= 2 * n - c0 + 2; c2 += 2)
+      S1(1, -c0 + 1, ((c0 + c2) / 2) - 1);
+  for (int c1 = max(c0 + 2, -c0 + 4); c1 <= min(2 * n - c0, 2 * n + c0); c1 += 2) {
+    for (int c2 = c1 + 2; c2 <= 2 * n + c1; c2 += 2)
+      S1((c0 + c1) / 2, (-c0 + c1) / 2, (-c1 + c2) / 2);
+    for (int c2 = 1; c2 <= n; c2 += 1)
+      S2(((c0 + c1) / 2) - 1, (-c0 + c1) / 2, c2);
+  }
+  if (c0 >= 1)
+    for (int c2 = 1; c2 <= n; c2 += 1)
+      S2(n, n - c0 + 1, c2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/darte.st b/final/lib/External/isl/test_inputs/codegen/cloog/darte.st
new file mode 100644
index 0000000..33e9386
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/darte.st
@@ -0,0 +1,6 @@
+domain: "[n] -> { S1[i0, i1, i2] : i0 >= 1 and i0 <= n and i1 >= 1 and i1 <= n and i2 >= 1 and i2 <= n; S2[i0, i1, i2] : i0 >= 1 and i0 <= n and i1 >= 1 and i1 <= n and i2 >= 1 and i2 <= n }"
+child:
+  context: "[n] -> { [] }"
+  child:
+    schedule: "[n] -> [{ S1[i0, i1, i2] -> [(i0 - i1)]; S2[i0, i1, i2] -> [(1 + i0 - i1)] }, { S1[i0, i1, i2] -> [(i0 + i1)]; S2[i0, i1, i2] -> [(2 + i0 + i1)] }, { S1[i0, i1, i2] -> [(i0 + i1 + 2i2)]; S2[i0, i1, i2] -> [(i2)] }]"
+    options: "[n] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/dealII.c b/final/lib/External/isl/test_inputs/codegen/cloog/dealII.c
new file mode 100644
index 0000000..99ac53e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/dealII.c
@@ -0,0 +1,18 @@
+{
+  for (int c0 = 0; c0 <= min(min(T_2 - 1, T_67 - 1), T_66); c0 += 1) {
+    S1(c0);
+    S2(c0);
+  }
+  for (int c0 = max(0, T_66 + 1); c0 < min(T_2, T_67); c0 += 1)
+    S1(c0);
+  for (int c0 = T_67; c0 <= min(T_2 - 1, T_66); c0 += 1) {
+    S1(c0);
+    S2(c0);
+  }
+  for (int c0 = max(T_67, T_66 + 1); c0 < T_2; c0 += 1)
+    S1(c0);
+  for (int c0 = T_2; c0 <= min(T_67 - 1, T_66); c0 += 1)
+    S2(c0);
+  if (T_2 == 0 && T_67 == 0)
+    S1(0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/dealII.st b/final/lib/External/isl/test_inputs/codegen/cloog/dealII.st
new file mode 100644
index 0000000..586e8fb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/dealII.st
@@ -0,0 +1,10 @@
+domain: "[T_2, T_67, T_66] -> { S1[scat_0] : (scat_0 >= 0 and scat_0 <= -1 + T_2) or (scat_0 <= -T_67 and scat_0 >= 0); S2[scat_0] : (scat_0 >= 0 and scat_0 <= T_66 and scat_0 <= -1 + T_2) or (scat_0 >= 0 and scat_0 <= T_66 and scat_0 <= -1 + T_67) }"
+child:
+  context: "[T_2, T_67, T_66] -> { [] : T_2 <= 4 and T_2 >= 0 and T_67 <= 4 and T_67 >= 0 }"
+  child:
+    schedule: "[T_2, T_67, T_66] -> [{ S2[scat_0] -> [(scat_0)]; S1[scat_0] -> [(scat_0)] }]"
+    options: "[T_2, T_67, T_66] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[T_2, T_67, T_66] -> { S1[scat_0] }"
+      - filter: "[T_2, T_67, T_66] -> { S2[scat_0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/donotsimp.c b/final/lib/External/isl/test_inputs/codegen/cloog/donotsimp.c
new file mode 100644
index 0000000..6e2cfce
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/donotsimp.c
@@ -0,0 +1,6 @@
+for (int c0 = 1; c0 <= 10; c0 += 1) {
+  for (int c1 = 1; c1 <= c0; c1 += 1)
+    S1(c0, c1);
+  for (int c1 = 11; c1 <= M; c1 += 1)
+    S2(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/donotsimp.st b/final/lib/External/isl/test_inputs/codegen/cloog/donotsimp.st
new file mode 100644
index 0000000..1dd72f4
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/donotsimp.st
@@ -0,0 +1,9 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= 10 and i1 >= 1 and i1 <= i0; S2[i0, i1] : i0 >= 1 and i0 <= 10 and i1 >= 11 and i1 <= M }"
+child:
+  context: "[M] -> { [] : M >= 20 }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      schedule: "[M] -> [{ S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+      options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/dot.c b/final/lib/External/isl/test_inputs/codegen/cloog/dot.c
new file mode 100644
index 0000000..b08de33
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/dot.c
@@ -0,0 +1,7 @@
+{
+  for (int c1 = 1; c1 <= M; c1 += 1)
+    S1(0, c1);
+  for (int c0 = 1; c0 <= N; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S2(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/dot.st b/final/lib/External/isl/test_inputs/codegen/cloog/dot.st
new file mode 100644
index 0000000..a9ca44a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/dot.st
@@ -0,0 +1,10 @@
+domain: "[M, N] -> { S1[0, i1] : i1 <= M and N >= 0 and i1 >= 1; S2[i0, i1] : i0 >= 1 and i1 <= M and i0 <= N and i1 >= 1 }"
+child:
+  context: "[M, N] -> { [] : M >= 1 and N >= 1 }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S1[i0, i1] }"
+      - filter: "[M, N] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/dot2.c b/final/lib/External/isl/test_inputs/codegen/cloog/dot2.c
new file mode 100644
index 0000000..1990d26
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/dot2.c
@@ -0,0 +1,12 @@
+{
+  for (int c0 = 1; c0 <= min(M, N); c0 += 1) {
+    S1(c0);
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S2(c0, c1);
+  }
+  for (int c0 = M + 1; c0 <= N; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S2(c0, c1);
+  for (int c0 = N + 1; c0 <= M; c0 += 1)
+    S1(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/dot2.st b/final/lib/External/isl/test_inputs/codegen/cloog/dot2.st
new file mode 100644
index 0000000..192d23c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/dot2.st
@@ -0,0 +1,10 @@
+domain: "[M, N] -> { S1[i0] : i0 >= 1 and i0 <= M; S2[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M }"
+child:
+  context: "[M, N] -> { [] : M >= 1 and N >= 1 }"
+  child:
+    schedule: "[M, N] -> [{ S2[i0, i1] -> [(i0)]; S1[i0] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0] -> [(0)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S1[i0] }"
+      - filter: "[M, N] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/durbin_e_s.c b/final/lib/External/isl/test_inputs/codegen/cloog/durbin_e_s.c
new file mode 100644
index 0000000..2559099
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/durbin_e_s.c
@@ -0,0 +1,23 @@
+{
+  S4(1, 0, 0);
+  S7(1, 0, 0);
+  S8(1, 0, 3);
+  for (int c0 = 2; c0 <= 9; c0 += 1) {
+    S2(c0, -7, 0);
+    for (int c1 = -7; c1 < c0 - 8; c1 += 1)
+      S3(c0, c1, 1);
+    S6(c0, c0 - 9, 2);
+    S8(c0, 0, 3);
+    for (int c1 = 1; c1 < c0; c1 += 1)
+      S5(c0, c1, 3);
+  }
+  S2(10, -7, 0);
+  for (int c1 = -7; c1 <= 1; c1 += 1)
+    S3(10, c1, 1);
+  S6(10, 1, 2);
+  for (int c1 = 1; c1 <= 9; c1 += 1) {
+    S5(10, c1, 3);
+    S1(10, c1, 4);
+  }
+  S1(10, 10, 4);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/durbin_e_s.st b/final/lib/External/isl/test_inputs/codegen/cloog/durbin_e_s.st
new file mode 100644
index 0000000..8b08767
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/durbin_e_s.st
@@ -0,0 +1,16 @@
+domain: "{ S2[i0, -7, 0] : i0 >= 2 and i0 <= 10; S4[1, 0, 0]; S6[i0, -9 + i0, 2] : i0 >= 2 and i0 <= 10; S1[10, i1, 4] : i1 >= 1 and i1 <= 10; S5[i0, i1, 3] : i1 <= -1 + i0 and i0 <= 10 and i1 >= 1; S7[1, 0, 0]; S8[i0, 0, 3] : i0 >= 1 and i0 <= 9; S3[i0, i1, 1] : i1 >= -7 and i0 <= 10 and i1 <= -9 + i0 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S6[i0, i1, i2] -> [(i0)]; S8[i0, i1, i2] -> [(i0)]; S5[i0, i1, i2] -> [(i0)]; S4[i0, i1, i2] -> [(i0)]; S7[i0, i1, i2] -> [(i0)]; S3[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)] }, { S6[i0, i1, i2] -> [(i1)]; S8[i0, i1, i2] -> [(i1)]; S5[i0, i1, i2] -> [(i1)]; S4[i0, i1, i2] -> [(i1)]; S7[i0, i1, i2] -> [(i1)]; S3[i0, i1, i2] -> [(i1)]; S1[i0, i1, i2] -> [(i1)]; S2[i0, i1, i2] -> [(i1)] }, { S6[i0, i1, i2] -> [(i2)]; S8[i0, i1, i2] -> [(i2)]; S5[i0, i1, i2] -> [(i2)]; S4[i0, i1, i2] -> [(i2)]; S7[i0, i1, i2] -> [(i2)]; S3[i0, i1, i2] -> [(i2)]; S1[i0, i1, i2] -> [(i2)]; S2[i0, i1, i2] -> [(i2)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[i0, i1, i2] }"
+      - filter: "{ S2[i0, i1, i2] }"
+      - filter: "{ S3[i0, i1, i2] }"
+      - filter: "{ S4[i0, i1, i2] }"
+      - filter: "{ S5[i0, i1, i2] }"
+      - filter: "{ S6[i0, i1, i2] }"
+      - filter: "{ S7[i0, i1, i2] }"
+      - filter: "{ S8[i0, i1, i2] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/emploi.c b/final/lib/External/isl/test_inputs/codegen/cloog/emploi.c
new file mode 100644
index 0000000..80ee37d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/emploi.c
@@ -0,0 +1,5 @@
+for (int c0 = 1; c0 <= n; c0 += 1) {
+  S1(c0);
+  for (int c1 = 1; c1 <= m; c1 += 1)
+    S2(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/emploi.st b/final/lib/External/isl/test_inputs/codegen/cloog/emploi.st
new file mode 100644
index 0000000..a7f4c26
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/emploi.st
@@ -0,0 +1,10 @@
+domain: "[m, n] -> { S1[i0] : (i0 >= 1 and i0 <= n and i0 <= 2m) or (i0 >= m and i0 >= 1 and i0 <= n); S2[i0, i1] : i0 >= 1 and i0 <= n and i1 >= 1 and i1 <= m }"
+child:
+  context: "[m, n] -> { [] }"
+  child:
+    schedule: "[m, n] -> [{ S1[i0] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0] -> [(0)]; S2[i0, i1] -> [(i1)] }]"
+    options: "[m, n] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[m, n] -> { S1[i0] }"
+      - filter: "[m, n] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/equality.c b/final/lib/External/isl/test_inputs/codegen/cloog/equality.c
new file mode 100644
index 0000000..fa6ff75
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/equality.c
@@ -0,0 +1,7 @@
+for (int c0 = 0; c0 <= 5; c0 += 1)
+  for (int c1 = min(4, 2 * c0); c1 <= max(4, 2 * c0); c1 += 1) {
+    if (c1 == 2 * c0)
+      S1(c0, 2 * c0);
+    if (c1 == 4)
+      S2(c0, 4);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/equality.st b/final/lib/External/isl/test_inputs/codegen/cloog/equality.st
new file mode 100644
index 0000000..084689c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/equality.st
@@ -0,0 +1,10 @@
+domain: "{ S2[i0, 4] : i0 >= 0 and i0 <= 5; S1[i0, 2i0] : i0 >= 0 and i0 <= 5 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "{ atomic[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[i0, i1] }"
+      - filter: "{ S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/equality2.c b/final/lib/External/isl/test_inputs/codegen/cloog/equality2.c
new file mode 100644
index 0000000..be22da2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/equality2.c
@@ -0,0 +1,8 @@
+for (int c0 = 1; c0 <= 10000; c0 += 1)
+  for (int c1 = 1000; c1 <= 1016; c1 += 1)
+    for (int c2 = 1; c2 < 2 * c1 - 1998; c2 += 1) {
+      if (c1 <= 1008 && c2 + 1999 == 2 * c1)
+        S2(c0, c1, 2 * c1 - 1999, 1, c0, 2 * c1 - 1000, 1, 2, c0, c1 - 499, 2 * c1 - 1999, c0, 2 * c1 - 1999, c1 - 999, c1 - 999);
+      if (c2 == 1 && c1 % 2 == 0)
+        S1(c0, c1, 1, 2, c0, (c1 / 2) + 1, c1 - 999, c0, c1 - 999, (c1 / 2) - 499, (c1 / 2) - 499);
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/equality2.st b/final/lib/External/isl/test_inputs/codegen/cloog/equality2.st
new file mode 100644
index 0000000..bbcb338
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/equality2.st
@@ -0,0 +1,10 @@
+domain: "{ S1[i0, i1, 1, 2, i0, i5, -999 + i1, i0, -999 + i1, i9, i10] : 2i5 = 2 + i1 and 2i9 = -998 + i1 and 2i10 = -998 + i1 and i0 >= 1 and i0 <= 10000 and i1 >= 1000 and i1 <= 1016; S2[i0, i1, -1999 + 2i1, 1, i0, -1000 + 2i1, 1, 2, i0, -499 + i1, -1999 + 2i1, i0, -1999 + 2i1, -999 + i1, -999 + i1] : i0 >= 1 and i0 <= 10000 and i1 >= 1000 and i1 <= 1008 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i0)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i0)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i1)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i1)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i2)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i2)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i3)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i3)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i4)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i4)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i5)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i5)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i6)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i6)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i7)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i7)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i8)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i8)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i9)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i9)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(i10)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i10)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(0)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i11)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(0)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i12)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(0)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i13)] }, { S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] -> [(0)]; S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] -> [(i14)] }]"
+    options: "{ atomic[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] }"
+      - filter: "{ S2[i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/esced.c b/final/lib/External/isl/test_inputs/codegen/cloog/esced.c
new file mode 100644
index 0000000..f7c7ee0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/esced.c
@@ -0,0 +1,5 @@
+for (int c0 = 1; c0 <= m; c0 += 1) {
+  S1(c0);
+  for (int c1 = 1; c1 <= n; c1 += 1)
+    S2(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/esced.st b/final/lib/External/isl/test_inputs/codegen/cloog/esced.st
new file mode 100644
index 0000000..f48ccf6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/esced.st
@@ -0,0 +1,10 @@
+domain: "[n, m] -> { S1[i0] : i0 >= 1 and i0 <= m; S2[i0, i1] : i0 >= 1 and i0 <= m and i1 >= 1 and i1 <= n }"
+child:
+  context: "[n, m] -> { [] }"
+  child:
+    schedule: "[n, m] -> [{ S2[i0, i1] -> [(i0)]; S1[i0] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0] -> [(0)] }]"
+    options: "[n, m] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[n, m] -> { S1[i0] }"
+      - filter: "[n, m] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/ex1.c b/final/lib/External/isl/test_inputs/codegen/cloog/ex1.c
new file mode 100644
index 0000000..2627f23
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/ex1.c
@@ -0,0 +1,15 @@
+{
+  for (int c0 = 0; c0 <= 14; c0 += 1)
+    for (int c1 = 0; c1 < n - 14; c1 += 1)
+      S1(c0, c1);
+  for (int c0 = 15; c0 <= n; c0 += 1) {
+    for (int c1 = 0; c1 <= 9; c1 += 1)
+      S1(c0, c1);
+    for (int c1 = 10; c1 < n - 14; c1 += 1) {
+      S1(c0, c1);
+      S2(c0, c1);
+    }
+    for (int c1 = n - 14; c1 <= n; c1 += 1)
+      S2(c0, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/ex1.st b/final/lib/External/isl/test_inputs/codegen/cloog/ex1.st
new file mode 100644
index 0000000..ea02538
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/ex1.st
@@ -0,0 +1,10 @@
+domain: "[n] -> { S1[i0, i1] : i0 >= 0 and i0 <= n and i1 >= 0 and i1 <= -15 + n; S2[i0, i1] : i0 >= 15 and i0 <= n and i1 >= 10 and i1 <= n }"
+child:
+  context: "[n] -> { [] : n >= 25 }"
+  child:
+    schedule: "[n] -> [{ S2[i0, i1] -> [(i0)]; S1[i0, i1] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0, i1] -> [(i1)] }]"
+    options: "[n] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[n] -> { S1[i0, i1] }"
+      - filter: "[n] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/faber.c b/final/lib/External/isl/test_inputs/codegen/cloog/faber.c
new file mode 100644
index 0000000..4aef0a5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/faber.c
@@ -0,0 +1,149 @@
+{
+  for (int c0 = 0; c0 <= 36; c0 += 1) {
+    for (int c1 = -6; c1 < c0 / 14 - 5; c1 += 1) {
+      for (int c2 = -((-2 * c1 + 3) / 5) + 9; c2 <= c1 + 12; c2 += 1)
+        S6(c0, c1, c2);
+      for (int c2 = c1 + 24; c2 <= -2 * c1 + 24; c2 += 1)
+        S2(c0, c1, c2);
+      for (int c2 = -2 * c1 + 30; c2 <= c1 + 48; c2 += 1)
+        S1(c0, c1, c2);
+    }
+    for (int c1 = c0 / 14 - 5; c1 < 0; c1 += 1) {
+      if (c1 >= -3 && 2 * c0 >= 7 * c1 + 42)
+        S7(c0, c1, 6);
+      for (int c2 = max(c1 - (6 * c0 + 77) / 77 + 13, -((-2 * c1 + 3) / 5) + 9); c2 <= c1 + 12; c2 += 1)
+        S6(c0, c1, c2);
+      for (int c2 = c1 - (3 * c0 + 14) / 14 + 49; c2 <= c1 + 48; c2 += 1)
+        S1(c0, c1, c2);
+    }
+    S3(c0, 0, 0);
+    S10(c0, 0, 0);
+    for (int c2 = 1; c2 <= 5; c2 += 1)
+      S3(c0, 0, c2);
+    for (int c2 = 6; c2 <= 2 * c0 / 21 + 4; c2 += 1) {
+      S3(c0, 0, c2);
+      S7(c0, 0, c2);
+    }
+    for (int c2 = max(6, 2 * c0 / 21 + 5); c2 <= -((6 * c0 + 77) / 77) + 12; c2 += 1)
+      S3(c0, 0, c2);
+    for (int c2 = -((6 * c0 + 77) / 77) + 13; c2 <= 12; c2 += 1) {
+      S3(c0, 0, c2);
+      S6(c0, 0, c2);
+    }
+    for (int c2 = 13; c2 <= 24; c2 += 1)
+      S3(c0, 0, c2);
+    for (int c2 = -((3 * c0 + 14) / 14) + 49; c2 <= 48; c2 += 1)
+      S1(c0, 0, c2);
+    for (int c1 = 1; c1 <= 18; c1 += 1) {
+      for (int c2 = -8 * c1; c2 <= min(6, -8 * c1 + 24); c2 += 1)
+        S3(c0, c1, c2);
+      if (c1 == 2) {
+        S3(c0, 2, 7);
+      } else if (c0 <= 34 && c1 == 1) {
+        S3(c0, 1, 7);
+      } else if (c0 >= 35 && c1 == 1) {
+        S3(c0, 1, 7);
+        S7(c0, 1, 7);
+      }
+      for (int c2 = 8; c2 <= min(-8 * c1 + 24, c1 - (6 * c0 + 77) / 77 + 12); c2 += 1)
+        S3(c0, c1, c2);
+      for (int c2 = max(-8 * c1 + 25, c1 - (6 * c0 + 77) / 77 + 13); c2 <= c1 + 12; c2 += 1)
+        S6(c0, c1, c2);
+      if (c1 == 1) {
+        for (int c2 = -((6 * c0 + 77) / 77) + 14; c2 <= 13; c2 += 1) {
+          S3(c0, 1, c2);
+          S6(c0, 1, c2);
+        }
+        for (int c2 = 14; c2 <= 16; c2 += 1)
+          S3(c0, 1, c2);
+      }
+      for (int c2 = c1 - (3 * c0 + 14) / 14 + 49; c2 <= c1 + 48; c2 += 1)
+        S1(c0, c1, c2);
+    }
+    for (int c1 = 19; c1 <= 24; c1 += 1) {
+      for (int c2 = -8 * c1; c2 <= -8 * c1 + 24; c2 += 1)
+        S3(c0, c1, c2);
+      for (int c2 = c1 - (6 * c0 + 77) / 77 + 13; c2 <= 30; c2 += 1)
+        S6(c0, c1, c2);
+    }
+  }
+  for (int c0 = 37; c0 <= 218; c0 += 1) {
+    for (int c1 = (c0 + 5) / 14 - 8; c1 < min(0, c0 / 14 - 5); c1 += 1) {
+      if (c0 <= 46 && c1 == -3)
+        S7(c0, -3, 6);
+      if (77 * c1 + 77 * ((-2 * c1 - 2) / 5) + 524 >= 6 * c0)
+        S6(c0, c1, -((-2 * c1 + 3) / 5) + 9);
+      for (int c2 = c1 + 24; c2 <= -2 * c1 + 24; c2 += 1)
+        S2(c0, c1, c2);
+      for (int c2 = -2 * c1 + 30; c2 <= c1 - (3 * c0 + 17) / 14 + 56; c2 += 1)
+        S1(c0, c1, c2);
+    }
+    for (int c1 = c0 / 14 - 5; c1 < 0; c1 += 1) {
+      if (7 * c1 + 114 >= 2 * c0)
+        S7(c0, c1, 6);
+      for (int c2 = max(8, c1 - (6 * c0 + 77) / 77 + 13); c2 <= c1 - (6 * c0 + 91) / 77 + 15; c2 += 1)
+        S6(c0, c1, c2);
+      for (int c2 = c1 - (3 * c0 + 14) / 14 + 49; c2 <= c1 - (3 * c0 + 17) / 14 + 56; c2 += 1)
+        S1(c0, c1, c2);
+    }
+    if (c0 <= 148)
+      for (int c1 = max(0, (c0 + 5) / 14 - 8); c1 < c0 / 14 - 5; c1 += 1) {
+        if (c1 == 0)
+          S2(c0, 0, 24);
+        for (int c2 = max(c1 + 24, -2 * c1 + 30); c2 <= c1 - (3 * c0 + 17) / 14 + 56; c2 += 1)
+          S1(c0, c1, c2);
+      }
+    if (c0 >= 70 && c0 % 14 >= 9)
+      for (int c2 = max(c0 / 14 + 19, -((3 * c0 + 14) / 14) + c0 / 14 + 44); c2 <= -((3 * c0 + 17) / 14) + c0 / 14 + 51; c2 += 1)
+        S1(c0, c0 / 14 - 5, c2);
+    for (int c1 = max(0, (c0 + 5) / 14 - 5); c1 < c0 / 14 - 2; c1 += 1) {
+      for (int c2 = max(c1, -2 * c1 + 6); c2 <= min(c1 + 5, -2 * c1 + 24); c2 += 1)
+        S9(c0, c1, c2);
+      for (int c2 = c1 + 6; c2 <= min((2 * c1 + 1) / 5 + 7, (2 * c0 - 7 * c1 - 10) / 21 + 1); c2 += 1)
+        S9(c0, c1, c2);
+      for (int c2 = max(c1 + 6, (2 * c0 - 7 * c1 - 10) / 21 + 2); c2 <= (2 * c1 + 1) / 5 + 7; c2 += 1) {
+        S7(c0, c1, c2);
+        S9(c0, c1, c2);
+      }
+      if (c1 <= 3)
+        S9(c0, c1, (2 * c1 + 1) / 5 + 8);
+      for (int c2 = (2 * c1 + 1) / 5 + 9; c2 <= c1 - (6 * c0 + 91) / 77 + 15; c2 += 1) {
+        S6(c0, c1, c2);
+        S9(c0, c1, c2);
+      }
+      for (int c2 = max(max(c1 + 6, c1 - (6 * c0 + 91) / 77 + 16), (2 * c1 + 1) / 5 + 9); c2 <= -2 * c1 + 24; c2 += 1)
+        S9(c0, c1, c2);
+      for (int c2 = max(c1, -2 * c1 + 30); c2 <= min(c1 + 24, c1 - (3 * c0 + 17) / 14 + 47); c2 += 1)
+        S8(c0, c1, c2);
+      for (int c2 = max(c1 + 24, c1 - (3 * c0 + 14) / 14 + 49); c2 <= c1 - (3 * c0 + 17) / 14 + 56; c2 += 1)
+        S1(c0, c1, c2);
+    }
+    for (int c1 = c0 / 14 - 2; c1 <= 18; c1 += 1) {
+      for (int c2 = max(6, (c0 + 5) / 14 + 1); c2 <= min(min(c1, c0 / 14 + 3), -c1 + c1 / 2 + 18); c2 += 1)
+        S5(c0, c1, c2);
+      for (int c2 = max(c1 + (3 * c0 + 3) / 14 - 40, -c1 + (c1 + 1) / 2 + 21); c2 <= min(c1, c1 + 3 * c0 / 14 - 33); c2 += 1)
+        S4(c0, c1, c2);
+      for (int c2 = c1 + 6; c2 <= min((2 * c1 + 1) / 5 + 7, (2 * c0 - 7 * c1 + 63) / 21 + 1); c2 += 1)
+        S7(c0, c1, c2);
+      for (int c2 = max(max(c1 + 6, c1 - (6 * c0 + 77) / 77 + 13), (2 * c1 + 1) / 5 + 9); c2 <= c1 - (6 * c0 + 91) / 77 + 15; c2 += 1)
+        S6(c0, c1, c2);
+      for (int c2 = max(c1, c1 - (3 * c0 + 14) / 14 + 40); c2 <= min(c1 + 24, c1 - (3 * c0 + 17) / 14 + 47); c2 += 1)
+        S8(c0, c1, c2);
+      for (int c2 = max(c1 + 24, c1 - (3 * c0 + 14) / 14 + 49); c2 <= c1 - (3 * c0 + 17) / 14 + 56; c2 += 1)
+        S1(c0, c1, c2);
+    }
+    for (int c1 = 19; c1 <= 24; c1 += 1) {
+      for (int c2 = max(c1 - 12, (c0 + 5) / 14 + 1); c2 <= min(c0 / 14 + 3, -c1 + c1 / 2 + 18); c2 += 1)
+        S5(c0, c1, c2);
+      for (int c2 = max(max(c1 - 12, c1 + (3 * c0 + 3) / 14 - 40), -c1 + (c1 + 1) / 2 + 21); c2 <= min(c1, c1 + 3 * c0 / 14 - 33); c2 += 1)
+        S4(c0, c1, c2);
+      for (int c2 = max(c1 + 6, c1 - (6 * c0 + 77) / 77 + 13); c2 <= min(30, c1 - (6 * c0 + 91) / 77 + 15); c2 += 1)
+        S6(c0, c1, c2);
+      for (int c2 = max(c1, c1 - (3 * c0 + 14) / 14 + 40); c2 <= min(c1 + 24, c1 - (3 * c0 + 17) / 14 + 47); c2 += 1)
+        S8(c0, c1, c2);
+    }
+    for (int c1 = 25; c1 <= min(42, -((3 * c0 + 17) / 14) + 71); c1 += 1)
+      for (int c2 = max(c1 - 12, c1 + (3 * c0 + 3) / 14 - 40); c2 <= min(min(30, c1), c1 + 3 * c0 / 14 - 33); c2 += 1)
+        S4(c0, c1, c2);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/faber.st b/final/lib/External/isl/test_inputs/codegen/cloog/faber.st
new file mode 100644
index 0000000..f800894
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/faber.st
@@ -0,0 +1,18 @@
+domain: "{ S2[idx4, idx5, idx6] : 14idx5 <= -84 + idx4 and 14idx5 >= -120 + idx4 and idx6 >= 24 + idx5 and idx6 <= 48 + idx5 and idx5 >= -6 and idx5 <= 18 and idx6 <= 24 - 2idx5; S4[idx4, idx5, idx6] : 14idx6 <= -462 + 3idx4 + 14idx5 and 14idx6 >= -570 + 3idx4 + 14idx5 and idx6 <= idx5 and idx6 >= -12 + idx5 and idx6 >= 6 and idx6 <= 30 and 2idx6 >= 42 - idx5; S6[idx4, idx5, idx6] : 77idx6 >= 924 - 6idx4 + 77idx5 and 77idx6 <= 1140 - 6idx4 + 77idx5 and idx6 <= 12 + idx5 and idx6 >= 6 + idx5 and idx6 >= 6 and idx6 <= 30 and 5idx6 >= 42 + 2idx5; S1[idx4, idx5, idx6] : 14idx6 >= 672 - 3idx4 + 14idx5 and 14idx6 <= 780 - 3idx4 + 14idx5 and idx6 >= 24 + idx5 and idx6 <= 48 + idx5 and idx5 >= -6 and idx5 <= 18 and idx6 >= 30 - 2idx5; S5[idx4, idx5, idx6] : 14idx6 <= 42 + idx4 and 14idx6 >= 6 + idx4 and idx6 <= idx5 and idx6 >= -12 + idx5 and idx6 >= 6 and idx6 <= 30 and 2idx6 <= 36 - idx5; S7[idx4, idx5, idx6] : 21idx6 <= 84 + 2idx4 - 7idx5 and 21idx6 >= 12 + 2idx4 - 7idx5 and idx6 <= 12 + idx5 and idx6 >= 6 + idx5 and idx6 >= 6 and idx6 <= 30 and 5idx6 <= 36 + 2idx5; S8[idx4, idx5, idx6] : 14idx6 >= 546 - 3idx4 + 14idx5 and 14idx6 <= 654 - 3idx4 + 14idx5 and idx6 >= idx5 and idx6 <= 24 + idx5 and idx5 >= 0 and idx5 <= 24 and idx6 >= 30 - 2idx5; S3[idx4, idx5, idx6] : idx4 >= 0 and idx4 <= 36 and idx6 >= -8idx5 and idx6 <= 24 - 8idx5 and idx5 >= 0 and idx5 <= 24; S9[idx4, idx5, idx6] : 14idx5 <= -42 + idx4 and 14idx5 >= -78 + idx4 and idx6 >= idx5 and idx6 <= 24 + idx5 and idx5 >= 0 and idx5 <= 24 and idx6 <= 24 - 2idx5 and idx6 >= 6 - 2idx5; S10[idx4, idx5, idx6] : 7idx6 <= idx4 - 28idx5 and 7idx6 >= -36 + idx4 - 28idx5 and idx6 >= idx5 and idx6 <= 24 + idx5 and idx5 >= 0 and idx5 <= 24 and idx6 <= -2idx5 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S6[idx4, idx5, idx6] -> [(idx4)]; S8[idx4, idx5, idx6] -> [(idx4)]; S5[idx4, idx5, idx6] -> [(idx4)]; S9[idx4, idx5, idx6] -> [(idx4)]; S4[idx4, idx5, idx6] -> [(idx4)]; S10[idx4, idx5, idx6] -> [(idx4)]; S7[idx4, idx5, idx6] -> [(idx4)]; S3[idx4, idx5, idx6] -> [(idx4)]; S1[idx4, idx5, idx6] -> [(idx4)]; S2[idx4, idx5, idx6] -> [(idx4)] }, { S6[idx4, idx5, idx6] -> [(idx5)]; S8[idx4, idx5, idx6] -> [(idx5)]; S5[idx4, idx5, idx6] -> [(idx5)]; S9[idx4, idx5, idx6] -> [(idx5)]; S4[idx4, idx5, idx6] -> [(idx5)]; S10[idx4, idx5, idx6] -> [(idx5)]; S7[idx4, idx5, idx6] -> [(idx5)]; S3[idx4, idx5, idx6] -> [(idx5)]; S1[idx4, idx5, idx6] -> [(idx5)]; S2[idx4, idx5, idx6] -> [(idx5)] }, { S6[idx4, idx5, idx6] -> [(idx6)]; S8[idx4, idx5, idx6] -> [(idx6)]; S5[idx4, idx5, idx6] -> [(idx6)]; S9[idx4, idx5, idx6] -> [(idx6)]; S4[idx4, idx5, idx6] -> [(idx6)]; S10[idx4, idx5, idx6] -> [(idx6)]; S7[idx4, idx5, idx6] -> [(idx6)]; S3[idx4, idx5, idx6] -> [(idx6)]; S1[idx4, idx5, idx6] -> [(idx6)]; S2[idx4, idx5, idx6] -> [(idx6)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[idx4, idx5, idx6] }"
+      - filter: "{ S2[idx4, idx5, idx6] }"
+      - filter: "{ S3[idx4, idx5, idx6] }"
+      - filter: "{ S4[idx4, idx5, idx6] }"
+      - filter: "{ S5[idx4, idx5, idx6] }"
+      - filter: "{ S6[idx4, idx5, idx6] }"
+      - filter: "{ S7[idx4, idx5, idx6] }"
+      - filter: "{ S8[idx4, idx5, idx6] }"
+      - filter: "{ S9[idx4, idx5, idx6] }"
+      - filter: "{ S10[idx4, idx5, idx6] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-1-1-2.c b/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-1-1-2.c
new file mode 100644
index 0000000..45fe75e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-1-1-2.c
@@ -0,0 +1,9 @@
+{
+  S3(1, 1);
+  for (int c0 = 2; c0 <= M; c0 += 1) {
+    S1(c0, 1);
+    for (int c1 = 2; c1 < c0; c1 += 1)
+      S2(c0, c1);
+    S4(c0, c0);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-1-1-2.st b/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-1-1-2.st
new file mode 100644
index 0000000..152e6b0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-1-1-2.st
@@ -0,0 +1,12 @@
+domain: "[M] -> { S4[i0, i0] : M >= 3 and i0 <= M and i0 >= 2; S1[i0, 1] : M >= 3 and i0 <= M and i0 >= 2; S3[1, 1] : M >= 3; S2[i0, i1] : i1 <= -1 + i0 and i1 >= 2 and i0 <= M }"
+child:
+  context: "[M] -> { [] : M >= 3 }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S4[i0, i1] -> [(i0)]; S3[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S4[i0, i1] -> [(i1)]; S3[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S1[i0, i1] }"
+      - filter: "[M] -> { S2[i0, i1] }"
+      - filter: "[M] -> { S3[i0, i1] }"
+      - filter: "[M] -> { S4[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-2-1-2-3.c b/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-2-1-2-3.c
new file mode 100644
index 0000000..cfc3e7d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-2-1-2-3.c
@@ -0,0 +1,10 @@
+{
+  S3(1, 0);
+  for (int c2 = 2; c2 <= M; c2 += 1)
+    S1(1, 1, c2);
+  for (int c0 = 2; c0 <= M; c0 += 1) {
+    S4(c0, 0);
+    for (int c2 = c0 + 1; c2 <= M; c2 += 1)
+      S2(c0, 1, c2);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-2-1-2-3.st b/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-2-1-2-3.st
new file mode 100644
index 0000000..76f0831
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-2-1-2-3.st
@@ -0,0 +1,12 @@
+domain: "[M] -> { S4[i0, 0] : i0 >= 2 and M >= 3 and i0 <= M; S3[1, 0] : M >= 3; S2[i0, 1, i2] : i2 >= 1 + i0 and i0 >= 2 and i2 <= M; S1[1, 1, i2] : M >= 3 and i2 <= M and i2 >= 2 }"
+child:
+  context: "[M] -> { [] : M >= 3 }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i0)]; S4[i0, i1] -> [(i0)]; S3[i0, i1] -> [(i0)]; S2[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i1)]; S4[i0, i1] -> [(i1)]; S3[i0, i1] -> [(i1)]; S2[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)]; S4[i0, i1] -> [(0)]; S3[i0, i1] -> [(0)]; S2[i0, i1, i2] -> [(i2)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S1[i0, i1, i2] }"
+      - filter: "[M] -> { S2[i0, i1, i2] }"
+      - filter: "[M] -> { S3[i0, i1] }"
+      - filter: "[M] -> { S4[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-3-1-2.c b/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-3-1-2.c
new file mode 100644
index 0000000..9300d18
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-3-1-2.c
@@ -0,0 +1,17 @@
+{
+  S3(2, 1);
+  S1(3, 1);
+  for (int c0 = 4; c0 <= M + 1; c0 += 1) {
+    S1(c0, 1);
+    for (int c1 = 2; c1 < (c0 + 1) / 2; c1 += 1)
+      S2(c0, c1);
+    if (c0 % 2 == 0)
+      S4(c0, c0 / 2);
+  }
+  for (int c0 = M + 2; c0 <= 2 * M; c0 += 1) {
+    for (int c1 = -M + c0; c1 < (c0 + 1) / 2; c1 += 1)
+      S2(c0, c1);
+    if (c0 % 2 == 0)
+      S4(c0, c0 / 2);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-3-1-2.st b/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-3-1-2.st
new file mode 100644
index 0000000..35677b4
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/forwardsub-3-1-2.st
@@ -0,0 +1,12 @@
+domain: "[M] -> { S4[i0, i1] : 2i1 = i0 and M >= 3 and i0 <= 2M and i0 >= 4; S1[i0, 1] : M >= 3 and i0 <= 1 + M and i0 >= 3; S3[2, 1] : M >= 3; S2[i0, i1] : 2i1 <= -1 + i0 and i1 >= 2 and i1 >= -M + i0 }"
+child:
+  context: "[M] -> { [] : M >= 3 }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S4[i0, i1] -> [(i0)]; S3[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S4[i0, i1] -> [(i1)]; S3[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S1[i0, i1] }"
+      - filter: "[M] -> { S2[i0, i1] }"
+      - filter: "[M] -> { S3[i0, i1] }"
+      - filter: "[M] -> { S4[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/gauss.c b/final/lib/External/isl/test_inputs/codegen/cloog/gauss.c
new file mode 100644
index 0000000..4bbe42c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/gauss.c
@@ -0,0 +1,7 @@
+for (int c0 = 1; c0 < M; c0 += 1)
+  for (int c1 = c0 + 1; c1 <= M; c1 += 1) {
+    for (int c3 = 1; c3 < c0; c3 += 1)
+      S1(c0, c3, c1);
+    for (int c3 = c0 + 1; c3 <= M; c3 += 1)
+      S2(c0, c3, c1);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/gauss.st b/final/lib/External/isl/test_inputs/codegen/cloog/gauss.st
new file mode 100644
index 0000000..7173a4c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/gauss.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S2[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 1 + i0 and i1 <= M and i2 >= 1 + i0 and i2 <= M; S1[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= -1 + i0 and i2 >= 1 + i0 and i2 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i2)]; S2[i0, i1, i2] -> [(i2)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/gesced.c b/final/lib/External/isl/test_inputs/codegen/cloog/gesced.c
new file mode 100644
index 0000000..40cdad9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/gesced.c
@@ -0,0 +1,16 @@
+{
+  for (int c0 = 1; c0 <= N; c0 += 1)
+    S1(c0);
+  for (int c0 = N + 1; c0 <= 2 * N; c0 += 1)
+    for (int c1 = 1; c1 <= N; c1 += 1)
+      S2(c1, -N + c0);
+  for (int c0 = 2 * N + 1; c0 <= M + N; c0 += 1) {
+    for (int c1 = 1; c1 <= N; c1 += 1)
+      S2(c1, -N + c0);
+    for (int c1 = 1; c1 <= N; c1 += 1)
+      S3(c1, -2 * N + c0);
+  }
+  for (int c0 = M + N + 1; c0 <= M + 2 * N; c0 += 1)
+    for (int c1 = 1; c1 <= N; c1 += 1)
+      S3(c1, -2 * N + c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/gesced.st b/final/lib/External/isl/test_inputs/codegen/cloog/gesced.st
new file mode 100644
index 0000000..3534f75
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/gesced.st
@@ -0,0 +1,6 @@
+domain: "[M, N] -> { S3[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M; S1[i0] : i0 >= 1 and i0 <= N; S2[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M }"
+child:
+  context: "[M, N] -> { [] : N <= M and M >= 2 and N >= 2 }"
+  child:
+    schedule: "[M, N] -> [{ S2[i0, i1] -> [(N + i1)]; S3[i0, i1] -> [(2N + i1)]; S1[i0] -> [(i0)] }]"
+    options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/gesced2.c b/final/lib/External/isl/test_inputs/codegen/cloog/gesced2.c
new file mode 100644
index 0000000..eeba38e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/gesced2.c
@@ -0,0 +1,20 @@
+{
+  for (int c0 = 1; c0 <= 4; c0 += 1)
+    for (int c1 = 5; c1 < M - 9; c1 += 1)
+      S1(c0, c1);
+  for (int c0 = 5; c0 < M - 9; c0 += 1) {
+    for (int c1 = -c0 + 1; c1 <= 4; c1 += 1)
+      S2(c0 + c1, c0);
+    for (int c1 = 5; c1 <= min(M - 10, M - c0); c1 += 1) {
+      S2(c0 + c1, c0);
+      S1(c0, c1);
+    }
+    for (int c1 = M - c0 + 1; c1 < M - 9; c1 += 1)
+      S1(c0, c1);
+    for (int c1 = M - 9; c1 <= M - c0; c1 += 1)
+      S2(c0 + c1, c0);
+  }
+  for (int c0 = M - 9; c0 <= M; c0 += 1)
+    for (int c1 = 5; c1 < M - 9; c1 += 1)
+      S1(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/gesced2.st b/final/lib/External/isl/test_inputs/codegen/cloog/gesced2.st
new file mode 100644
index 0000000..c5f41bf
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/gesced2.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 5 and i1 <= -10 + M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 5 and i1 <= -10 + M }"
+child:
+  context: "[M] -> { [] : M >= 16 }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i1)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i0 - i1)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/gesced3.c b/final/lib/External/isl/test_inputs/codegen/cloog/gesced3.c
new file mode 100644
index 0000000..c163ed0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/gesced3.c
@@ -0,0 +1,10 @@
+{
+  for (int c0 = M + 1; c0 <= 2 * M; c0 += 1)
+    S1(-M + c0);
+  for (int c0 = 2 * M + 1; c0 <= M + N; c0 += 1) {
+    S2(-2 * M + c0);
+    S1(-M + c0);
+  }
+  for (int c0 = M + N + 1; c0 <= 2 * M + N; c0 += 1)
+    S2(-2 * M + c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/gesced3.st b/final/lib/External/isl/test_inputs/codegen/cloog/gesced3.st
new file mode 100644
index 0000000..cb0a285
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/gesced3.st
@@ -0,0 +1,6 @@
+domain: "[M, N] -> { S1[i0] : i0 >= 1 and i0 <= N; S2[i0] : i0 >= 1 and i0 <= N }"
+child:
+  context: "[M, N] -> { [] : N >= M and M >= 2 }"
+  child:
+    schedule: "[M, N] -> [{ S2[i0] -> [(2M + i0)]; S1[i0] -> [(M + i0)] }]"
+    options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/guide.c b/final/lib/External/isl/test_inputs/codegen/cloog/guide.c
new file mode 100644
index 0000000..bc48f1e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/guide.c
@@ -0,0 +1,6 @@
+{
+  for (int c0 = 1; c0 <= N; c0 += 1)
+    S1(c0);
+  for (int c0 = N + 1; c0 <= 2 * N; c0 += 1)
+    S2(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/guide.st b/final/lib/External/isl/test_inputs/codegen/cloog/guide.st
new file mode 100644
index 0000000..3ca5c6e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/guide.st
@@ -0,0 +1,10 @@
+domain: "[M, N] -> { S1[i0] : (i0 >= 1 and i0 <= N and i0 <= 2M) or (i0 >= M and i0 >= 1 and i0 <= N); S2[i0] : i0 >= 1 + N and i0 <= 2N }"
+child:
+  context: "[M, N] -> { [] }"
+  child:
+    schedule: "[M, N] -> [{ S2[i0] -> [(i0)]; S1[i0] -> [(i0)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S1[i0] }"
+      - filter: "[M, N] -> { S2[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/iftest.c b/final/lib/External/isl/test_inputs/codegen/cloog/iftest.c
new file mode 100644
index 0000000..0f41fb7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/iftest.c
@@ -0,0 +1,2 @@
+for (int c0 = 1; c0 <= n; c0 += 1)
+  S1(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/iftest.st b/final/lib/External/isl/test_inputs/codegen/cloog/iftest.st
new file mode 100644
index 0000000..cd26fab
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/iftest.st
@@ -0,0 +1,6 @@
+domain: "[m, n] -> { S1[i0] : (i0 >= m and i0 >= 1 and i0 <= n) or (i0 >= 1 and i0 <= n and i0 <= 2m) }"
+child:
+  context: "[m, n] -> { [] }"
+  child:
+    schedule: "[m, n] -> [{ S1[i0] -> [(i0)] }]"
+    options: "[m, n] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/iftest2.c b/final/lib/External/isl/test_inputs/codegen/cloog/iftest2.c
new file mode 100644
index 0000000..8e3e4c1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/iftest2.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= N; c0 += 1)
+  for (int c1 = 1; c1 <= M; c1 += 1)
+    S1(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/iftest2.st b/final/lib/External/isl/test_inputs/codegen/cloog/iftest2.st
new file mode 100644
index 0000000..f073f5c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/iftest2.st
@@ -0,0 +1,6 @@
+domain: "[M, N] -> { S1[i0, i1] : (i0 >= M and i0 <= N and i1 >= 1 and i1 <= M) or (i0 >= 1 and i0 <= N and i0 <= 2M and i1 >= 1 and i1 <= M) }"
+child:
+  context: "[M, N] -> { [] }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]"
+    options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/infinite2.c b/final/lib/External/isl/test_inputs/codegen/cloog/infinite2.c
new file mode 100644
index 0000000..bbb6d6e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/infinite2.c
@@ -0,0 +1,9 @@
+{
+  for (int c0 = 1; c0 <= N; c0 += 1) {
+    S1(c0);
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S2(c0, c1);
+  }
+  for (int c0 = N + 1; 1; c0 += 1)
+    S1(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/infinite2.st b/final/lib/External/isl/test_inputs/codegen/cloog/infinite2.st
new file mode 100644
index 0000000..7bd85d3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/infinite2.st
@@ -0,0 +1,10 @@
+domain: "[M, N] -> { S1[i0] : i0 >= 1; S2[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M }"
+child:
+  context: "[M, N] -> { [] : M >= 1 and N >= 1 }"
+  child:
+    schedule: "[M, N] -> [{ S2[i0, i1] -> [(i0)]; S1[i0] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0] -> [(0)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S1[i0] }"
+      - filter: "[M, N] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/jacobi-shared.c b/final/lib/External/isl/test_inputs/codegen/cloog/jacobi-shared.c
new file mode 100644
index 0000000..bf70932
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/jacobi-shared.c
@@ -0,0 +1,3 @@
+if (((t1 + 31) % 32) + g2 >= 2 && N >= ((t1 + 31) % 32) + g2 + 2 && (h0 + 1) % 2 == 0)
+  for (int c0 = max(((t0 + 15) % 16) + 1, ((g1 + t0 + 13) % 16) - g1 + 3); c0 <= min(32, N - g1 - 1); c0 += 16)
+    S1(g1 + c0 - 1, -((g2 - t1 + 32) % 32) + g2 + 31);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/jacobi-shared.st b/final/lib/External/isl/test_inputs/codegen/cloog/jacobi-shared.st
new file mode 100644
index 0000000..73f5dd8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/jacobi-shared.st
@@ -0,0 +1,6 @@
+domain: "[T, N, h0, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> { S1[i0, i1] : exists (e0 = floor((-1 + h0)/2), e1 = floor((-32b0 + g1)/2048), e2 = floor((-32b1 + g2)/1024), e3 = floor((-15 - t0 + i0)/16), e4 = floor((-31 - t1 + i1)/32): g0 = h0 and 2e0 = -1 + h0 and 2048e1 = -32b0 + g1 and 1024e2 = -32b1 + g2 and 16e3 = -15 - t0 + i0 and 32e4 = -31 - t1 + i1 and h0 >= 1 and h0 <= -1 + 2T and i0 >= 2 and i0 <= -2 + N and i1 >= 2 and i1 <= -2 + N and b1 <= 31 and b1 >= 0 and b0 <= 63 and b0 >= 0 and i1 <= 31 + g2 and i1 >= g2 and N >= 4 and i0 >= g1 and i0 <= 31 + g1 and g2 <= -2 + N and g2 >= -29 and g1 <= -2 + N and g1 >= -29 and g1 >= 32b0 and g2 >= 32b1 and 32b0 <= -2 + N and 32b1 <= -2 + N and t0 >= 0 and t0 <= 15 and t1 >= 0 and t1 <= 31) }"
+child:
+  context: "[T, N, h0, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> { [] : exists (e0 = floor((-32b0 + g1)/2048), e1 = floor((-32b1 + g2)/1024): g0 = h0 and 2048e0 = -32b0 + g1 and 1024e1 = -32b1 + g2 and g2 <= -2 + N and g2 >= -29 and g1 <= -2 + N and g1 >= -29 and b1 >= 0 and b1 <= 31 and b0 <= 63 and 32b1 <= -2 + N and 32b0 <= -2 + N and b0 >= 0 and N >= 4 and h0 >= 0 and h0 <= -1 + 2T and g2 >= 32b1 and g1 >= 32b0 and t0 >= 0 and t0 <= 15 and t1 >= 0 and t1 <= 31) }"
+  child:
+    schedule: "[T, N, h0, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> [{ S1[i0, i1] -> [(1 - g1 + i0)] }, { S1[i0, i1] -> [(1 - g2 + i1)] }, { S1[i0, i1] -> [(t0)] }, { S1[i0, i1] -> [(t1)] }]"
+    options: "[T, N, h0, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> { separate[x] : x >= 3 }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/largeur.c b/final/lib/External/isl/test_inputs/codegen/cloog/largeur.c
new file mode 100644
index 0000000..faced0a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/largeur.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= M; c0 += 1)
+  for (int c1 = 1; c1 <= c0; c1 += 1)
+    S1(c1, c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/largeur.st b/final/lib/External/isl/test_inputs/codegen/cloog/largeur.st
new file mode 100644
index 0000000..bb29f21
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/largeur.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= i0 and i1 <= M }"
+child:
+  context: "[M] -> { [] : M >= 0 }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }, { S1[i0, i1] -> [(i0)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/levenshtein-1-2-3.c b/final/lib/External/isl/test_inputs/codegen/cloog/levenshtein-1-2-3.c
new file mode 100644
index 0000000..70d1ea5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/levenshtein-1-2-3.c
@@ -0,0 +1,32 @@
+{
+  S1(0, 0);
+  for (int c0 = 1; c0 <= N; c0 += 1) {
+    S2(c0, 0);
+    for (int c1 = 1; c1 < c0; c1 += 1)
+      S6(c0, c1);
+    S3(c0, c0);
+  }
+  S7(N + 1, 0);
+  for (int c1 = 1; c1 <= N; c1 += 1) {
+    S6(N + 1, c1);
+    S8(N + 1, c1);
+  }
+  for (int c0 = N + 2; c0 < 2 * M - N - 1; c0 += 1) {
+    S7(c0, -N + (N + c0 + 1) / 2 - 1);
+    if ((N + c0) % 2 == 0) {
+      S5(c0, (-N + c0) / 2);
+      S8(c0, (-N + c0) / 2);
+    }
+    for (int c1 = -N + (N + c0) / 2 + 1; c1 < (N + c0 + 1) / 2; c1 += 1) {
+      S6(c0, c1);
+      S8(c0, c1);
+    }
+    if ((N + c0) % 2 == 0) {
+      S4(c0, (N + c0) / 2);
+      S8(c0, (N + c0) / 2);
+    }
+  }
+  for (int c0 = 2 * M - N - 1; c0 < 2 * M - 1; c0 += 1)
+    for (int c1 = -M + c0 + 1; c1 < M; c1 += 1)
+      S6(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/levenshtein-1-2-3.st b/final/lib/External/isl/test_inputs/codegen/cloog/levenshtein-1-2-3.st
new file mode 100644
index 0000000..9b1d7cb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/levenshtein-1-2-3.st
@@ -0,0 +1,16 @@
+domain: "[M, N] -> { S5[i0, i1] : 2i1 = -N + i0 and i0 >= 2 + N and i0 <= -2 + 2M - N and N >= 1; S3[i0, i0] : i0 >= 1 and i0 <= N and N <= -2 + M; S7[i0, i1] : i0 >= 1 + N and 2i1 <= -1 - N + i0 and i0 <= -2 + 2M - N and 2i1 >= -2 - N + i0 and N <= -2 + M and N >= 1; S6[i0, i1] : 2i1 <= -1 + N + i0 and i1 <= -1 + i0 and i1 >= 1 - M + i0 and 2i1 >= 1 - N + i0 and i1 >= 1 and i1 <= -1 + M and N <= -2 + M; S1[0, 0] : N <= -2 + M and N >= 1; S2[i0, 0] : i0 >= 1 and i0 <= N and N <= -2 + M; S4[i0, i1] : 2i1 = N + i0 and i0 >= 2 + N and i0 <= -2 + 2M - N and N >= 1; S8[i0, i1] : i0 >= 1 + N and 2i1 <= N + i0 and 2i1 >= -N + i0 and i0 <= -2 + 2M - N and N <= -2 + M and N >= 1 }"
+child:
+  context: "[M, N] -> { [] : N <= -2 + M and N >= 1 }"
+  child:
+    schedule: "[M, N] -> [{ S7[i0, i1] -> [(i0)]; S5[i0, i1] -> [(i0)]; S1[i0, i1] -> [(i0)]; S3[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)]; S4[i0, i1] -> [(i0)]; S8[i0, i1] -> [(i0)]; S6[i0, i1] -> [(i0)] }, { S7[i0, i1] -> [(i1)]; S5[i0, i1] -> [(i1)]; S1[i0, i1] -> [(i1)]; S3[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)]; S4[i0, i1] -> [(i1)]; S8[i0, i1] -> [(i1)]; S6[i0, i1] -> [(i1)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S1[i0, i1] }"
+      - filter: "[M, N] -> { S2[i0, i1] }"
+      - filter: "[M, N] -> { S3[i0, i1] }"
+      - filter: "[M, N] -> { S4[i0, i1] }"
+      - filter: "[M, N] -> { S5[i0, i1] }"
+      - filter: "[M, N] -> { S6[i0, i1] }"
+      - filter: "[M, N] -> { S7[i0, i1] }"
+      - filter: "[M, N] -> { S8[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/lex.c b/final/lib/External/isl/test_inputs/codegen/cloog/lex.c
new file mode 100644
index 0000000..e81e97e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/lex.c
@@ -0,0 +1,4 @@
+for (int c0 = 0; c0 <= 10; c0 += 1) {
+  S2(c0);
+  S1(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/lex.st b/final/lib/External/isl/test_inputs/codegen/cloog/lex.st
new file mode 100644
index 0000000..2d4d58d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/lex.st
@@ -0,0 +1,10 @@
+domain: "{ S1[i0] : i0 >= 0 and i0 <= 10; S2[i0] : i0 >= 0 and i0 <= 10 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S2[i0] -> [(i0)]; S1[i0] -> [(i0)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S2[i0] }"
+      - filter: "{ S1[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/lineality-1-2.c b/final/lib/External/isl/test_inputs/codegen/cloog/lineality-1-2.c
new file mode 100644
index 0000000..bb1e071
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/lineality-1-2.c
@@ -0,0 +1,8 @@
+for (int c0 = 1; c0 <= M; c0 += 1) {
+  for (int c1 = 1; c1 < c0; c1 += 1)
+    S1(c0, c1);
+  S1(c0, c0);
+  S2(c0, c0);
+  for (int c1 = c0 + 1; c1 <= M; c1 += 1)
+    S1(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/lineality-1-2.st b/final/lib/External/isl/test_inputs/codegen/cloog/lineality-1-2.st
new file mode 100644
index 0000000..0d079b5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/lineality-1-2.st
@@ -0,0 +1,10 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i1 >= 1 and i0 <= M and i1 <= M; S2[i0, i0] : i0 >= 1 and i0 <= M }"
+child:
+  context: "[M] -> { [] : M >= 2 }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S1[i0, i1] }"
+      - filter: "[M] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/lineality-2-1-2.c b/final/lib/External/isl/test_inputs/codegen/cloog/lineality-2-1-2.c
new file mode 100644
index 0000000..97a4b04
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/lineality-2-1-2.c
@@ -0,0 +1,12 @@
+for (int c0 = 1; c0 <= M; c0 += 1) {
+  for (int c1 = 1; c1 <= min(M, c0 + 1); c1 += 1)
+    S1(c0, c1);
+  if (M >= c0 + 2) {
+    S1(c0, c0 + 2);
+    S2(c0, c0 + 2);
+  }
+  for (int c1 = c0 + 3; c1 <= M; c1 += 1)
+    S1(c0, c1);
+  if (c0 + 1 >= M)
+    S2(c0, c0 + 2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/lineality-2-1-2.st b/final/lib/External/isl/test_inputs/codegen/cloog/lineality-2-1-2.st
new file mode 100644
index 0000000..dbadca7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/lineality-2-1-2.st
@@ -0,0 +1,10 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i1 >= 1 and i0 <= M and i1 <= M; S2[i0, 2 + i0] : i0 >= 1 and i0 <= M }"
+child:
+  context: "[M] -> { [] : M >= 2 }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S1[i0, i1] }"
+      - filter: "[M] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/logo.c b/final/lib/External/isl/test_inputs/codegen/cloog/logo.c
new file mode 100644
index 0000000..abe35b5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/logo.c
@@ -0,0 +1,17 @@
+{
+  for (int c1 = 0; c1 <= 7; c1 += 1)
+    S1(1, c1);
+  for (int c0 = 2; c0 <= 6; c0 += 1) {
+    for (int c1 = 0; c1 < c0 - 1; c1 += 1)
+      S2(c0, c1);
+    for (int c1 = c0 - 1; c1 <= 4; c1 += 1) {
+      S1(c0, c1);
+      S2(c0, c1);
+    }
+    for (int c1 = 5; c1 <= 7; c1 += 1)
+      S1(c0, c1);
+  }
+  for (int c0 = 7; c0 <= 8; c0 += 1)
+    for (int c1 = c0 - 1; c1 <= 7; c1 += 1)
+      S1(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/logo.st b/final/lib/External/isl/test_inputs/codegen/cloog/logo.st
new file mode 100644
index 0000000..89fe649
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/logo.st
@@ -0,0 +1,10 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i1 <= 7 and i1 >= -1 + i0; S2[i0, i1] : i0 >= 2 and i0 <= 6 and i1 >= 0 and i1 <= 4 }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S1[i0, i1] }"
+      - filter: "[M] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/logopar.c b/final/lib/External/isl/test_inputs/codegen/cloog/logopar.c
new file mode 100644
index 0000000..70f98e8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/logopar.c
@@ -0,0 +1,17 @@
+{
+  for (int c1 = 0; c1 <= m; c1 += 1)
+    S1(1, c1);
+  for (int c0 = 2; c0 <= n; c0 += 1) {
+    for (int c1 = 0; c1 < c0 - 1; c1 += 1)
+      S2(c0, c1);
+    for (int c1 = c0 - 1; c1 <= n; c1 += 1) {
+      S1(c0, c1);
+      S2(c0, c1);
+    }
+    for (int c1 = n + 1; c1 <= m; c1 += 1)
+      S1(c0, c1);
+  }
+  for (int c0 = n + 1; c0 <= m + 1; c0 += 1)
+    for (int c1 = c0 - 1; c1 <= m; c1 += 1)
+      S1(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/logopar.st b/final/lib/External/isl/test_inputs/codegen/cloog/logopar.st
new file mode 100644
index 0000000..8ed609b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/logopar.st
@@ -0,0 +1,10 @@
+domain: "[m, n] -> { S1[i0, i1] : i0 >= 1 and i1 <= m and i1 >= -1 + i0; S2[i0, i1] : i0 >= 2 and i0 <= n and i1 >= 0 and i1 <= n }"
+child:
+  context: "[m, n] -> { [] : n <= m and m >= 0 and n >= 2 }"
+  child:
+    schedule: "[m, n] -> [{ S2[i0, i1] -> [(i0)]; S1[i0, i1] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0, i1] -> [(i1)] }]"
+    options: "[m, n] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[m, n] -> { S1[i0, i1] }"
+      - filter: "[m, n] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/lu.c b/final/lib/External/isl/test_inputs/codegen/cloog/lu.c
new file mode 100644
index 0000000..a7fe2b3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/lu.c
@@ -0,0 +1,7 @@
+for (int c0 = 1; c0 <= n; c0 += 1) {
+  for (int c1 = 2; c1 <= n; c1 += 1)
+    for (int c2 = 1; c2 < min(c0, c1); c2 += 1)
+      S2(c2, c1, c0);
+  for (int c3 = c0 + 1; c3 <= n; c3 += 1)
+    S1(c0, c3);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/lu.st b/final/lib/External/isl/test_inputs/codegen/cloog/lu.st
new file mode 100644
index 0000000..6f9320c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/lu.st
@@ -0,0 +1,6 @@
+domain: "[n] -> { S1[i0, i1] : i0 >= 1 and i0 <= n and i1 >= 1 + i0 and i1 <= n; S2[i0, i1, i2] : i0 >= 1 and i0 <= n and i1 >= 1 + i0 and i1 <= n and i2 >= 1 + i0 and i2 <= n }"
+child:
+  context: "[n] -> { [] }"
+  child:
+    schedule: "[n] -> [{ S2[i0, i1, i2] -> [(i2)]; S1[i0, i1] -> [(i0)] }, { S2[i0, i1, i2] -> [(i1)]; S1[i0, i1] -> [(n)] }]"
+    options: "[n] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/lu2.c b/final/lib/External/isl/test_inputs/codegen/cloog/lu2.c
new file mode 100644
index 0000000..d5cc912
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/lu2.c
@@ -0,0 +1,7 @@
+for (int c0 = 1; c0 <= n; c0 += 1) {
+  for (int c1 = 2; c1 <= n; c1 += 1)
+    for (int c2 = 1; c2 < min(c0, c1); c2 += 1)
+      S2(c0, c1, c2, c1, c0);
+  for (int c3 = c0 + 1; c3 <= n; c3 += 1)
+    S1(c0, n, c0, c3);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/lu2.st b/final/lib/External/isl/test_inputs/codegen/cloog/lu2.st
new file mode 100644
index 0000000..eb0ab21
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/lu2.st
@@ -0,0 +1,10 @@
+domain: "[n] -> { S2[i0, i1, i2, i1, i0] : i2 >= 1 and i2 <= n and i2 <= -1 + i1 and i1 <= n and i2 <= -1 + i0 and i0 <= n; S1[i0, n, i0, i3] : i0 >= 1 and i0 <= n and i3 >= 1 + i0 and i3 <= n }"
+child:
+  context: "[n] -> { [] }"
+  child:
+    schedule: "[n] -> [{ S2[i0, i1, i2, i3, i4] -> [(i0)]; S1[i0, i1, i2, i3] -> [(i0)] }, { S2[i0, i1, i2, i3, i4] -> [(i1)]; S1[i0, i1, i2, i3] -> [(i1)] }, { S2[i0, i1, i2, i3, i4] -> [(i2)]; S1[i0, i1, i2, i3] -> [(i2)] }, { S2[i0, i1, i2, i3, i4] -> [(i3)]; S1[i0, i1, i2, i3] -> [(i3)] }, { S2[i0, i1, i2, i3, i4] -> [(i4)]; S1[i0, i1, i2, i3] -> [(0)] }]"
+    options: "[n] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[n] -> { S1[i0, i1, i2, i3] }"
+      - filter: "[n] -> { S2[i0, i1, i2, i3, i4] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/lux.c b/final/lib/External/isl/test_inputs/codegen/cloog/lux.c
new file mode 100644
index 0000000..3b33025
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/lux.c
@@ -0,0 +1,7 @@
+for (int c0 = 1; c0 <= M; c0 += 1) {
+  for (int c1 = 1; c1 < c0; c1 += 1)
+    for (int c2 = c1 + 1; c2 <= M; c2 += 1)
+      S2(c0, c1, c2, c2, c0);
+  for (int c3 = c0 + 1; c3 <= M; c3 += 1)
+    S1(c0, c0, M, c3);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/lux.st b/final/lib/External/isl/test_inputs/codegen/cloog/lux.st
new file mode 100644
index 0000000..8c5bdb6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/lux.st
@@ -0,0 +1,10 @@
+domain: "[M] -> { S1[i0, i0, M, i3] : i0 >= 1 and i0 <= M and i3 >= 1 + i0 and i3 <= M; S2[i0, i1, i2, i2, i0] : i1 >= 1 and i1 <= M and i2 >= 1 + i1 and i2 <= M and i1 <= -1 + i0 and i0 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i0)]; S2[i0, i1, i2, i3, i4] -> [(i0)] }, { S1[i0, i1, i2, i3] -> [(i1)]; S2[i0, i1, i2, i3, i4] -> [(i1)] }, { S1[i0, i1, i2, i3] -> [(i2)]; S2[i0, i1, i2, i3, i4] -> [(i2)] }, { S1[i0, i1, i2, i3] -> [(i3)]; S2[i0, i1, i2, i3, i4] -> [(i3)] }, { S1[i0, i1, i2, i3] -> [(0)]; S2[i0, i1, i2, i3, i4] -> [(i4)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S1[i0, i1, i2, i3] }"
+      - filter: "[M] -> { S2[i0, i1, i2, i3, i4] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/merge.c b/final/lib/External/isl/test_inputs/codegen/cloog/merge.c
new file mode 100644
index 0000000..64564ad
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/merge.c
@@ -0,0 +1,8 @@
+{
+  S1(0);
+  for (int c0 = 0; c0 <= 10; c0 += 1) {
+    if (c0 >= 2)
+      S2(c0);
+    S3(c0);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/merge.st b/final/lib/External/isl/test_inputs/codegen/cloog/merge.st
new file mode 100644
index 0000000..d451317
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/merge.st
@@ -0,0 +1,11 @@
+domain: "{ S3[i0] : i0 >= 0 and i0 <= 10; S1[0]; S2[i0] : i0 >= 2 and i0 <= 10 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S2[i0] -> [(i0)]; S3[i0] -> [(i0)]; S1[i0] -> [(i0)] }]"
+    options: "{ atomic[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[i0] }"
+      - filter: "{ S2[i0] }"
+      - filter: "{ S3[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/min-1-1.c b/final/lib/External/isl/test_inputs/codegen/cloog/min-1-1.c
new file mode 100644
index 0000000..b869e1b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/min-1-1.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= N; c0 += 1)
+  for (int c1 = 0; c1 <= min(min(M, c0), N - c0); c1 += 1)
+    S1(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/min-1-1.st b/final/lib/External/isl/test_inputs/codegen/cloog/min-1-1.st
new file mode 100644
index 0000000..cf3dc12
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/min-1-1.st
@@ -0,0 +1,6 @@
+domain: "[M, N] -> { S1[i0, i1] : i0 >= 1 and i1 >= 0 and i1 <= M and i1 <= i0 and i1 <= N - i0 }"
+child:
+  context: "[M, N] -> { [] }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]"
+    options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/min-2-1.c b/final/lib/External/isl/test_inputs/codegen/cloog/min-2-1.c
new file mode 100644
index 0000000..8e6fabf
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/min-2-1.c
@@ -0,0 +1,4 @@
+for (int c0 = 1; c0 <= N; c0 += 1)
+  for (int c1 = 0; c1 <= min(min(M, c0), N - c0); c1 += 1)
+    for (int c2 = 0; c2 <= min(min(M, c0), N - c0); c2 += 1)
+      S1(c0, c1, c2);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/min-2-1.st b/final/lib/External/isl/test_inputs/codegen/cloog/min-2-1.st
new file mode 100644
index 0000000..c2a4852
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/min-2-1.st
@@ -0,0 +1,6 @@
+domain: "[M, N] -> { S1[i0, i1, i2] : i0 >= 1 and i1 >= 0 and i1 <= M and i1 <= i0 and i1 <= N - i0 and i2 >= 0 and i2 <= M and i2 <= i0 and i2 <= N - i0 }"
+child:
+  context: "[M, N] -> { [] }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)] }]"
+    options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/min-3-1.c b/final/lib/External/isl/test_inputs/codegen/cloog/min-3-1.c
new file mode 100644
index 0000000..8d11d76
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/min-3-1.c
@@ -0,0 +1,3 @@
+for (int c0 = 0; c0 <= min(10, M); c0 += 1)
+  for (int c1 = 0; c1 <= min(10, M); c1 += 1)
+    S1(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/min-3-1.st b/final/lib/External/isl/test_inputs/codegen/cloog/min-3-1.st
new file mode 100644
index 0000000..30dec04
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/min-3-1.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 0 and i0 <= M and i0 <= 10 and i1 >= 0 and i1 <= M and i1 <= 10 }"
+child:
+  context: "[M] -> { [] : M >= 0 }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/min-4-1.c b/final/lib/External/isl/test_inputs/codegen/cloog/min-4-1.c
new file mode 100644
index 0000000..da272fc
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/min-4-1.c
@@ -0,0 +1,2 @@
+for (int c0 = max(-M, -N); c0 <= min(N, O); c0 += 1)
+  S1(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/min-4-1.st b/final/lib/External/isl/test_inputs/codegen/cloog/min-4-1.st
new file mode 100644
index 0000000..8c0fd86
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/min-4-1.st
@@ -0,0 +1,6 @@
+domain: "[M, N, O] -> { S1[i0] : i0 >= -M and i0 >= -N and i0 <= N and i0 <= O }"
+child:
+  context: "[M, N, O] -> { [] }"
+  child:
+    schedule: "[M, N, O] -> [{ S1[i0] -> [(i0)] }]"
+    options: "[M, N, O] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/mod.c b/final/lib/External/isl/test_inputs/codegen/cloog/mod.c
new file mode 100644
index 0000000..cafe0b8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/mod.c
@@ -0,0 +1,3 @@
+for (int c0 = 0; c0 <= 3; c0 += 1)
+  if ((c0 + 1) % 3 >= 1)
+    S1(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/mod.st b/final/lib/External/isl/test_inputs/codegen/cloog/mod.st
new file mode 100644
index 0000000..cecdef1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/mod.st
@@ -0,0 +1,6 @@
+domain: "{ S1[i0] : exists (e0 = floor((1 + i0)/3): 3e0 <= i0 and 3e0 >= -1 + i0 and i0 >= 0 and i0 <= 3) }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0] -> [(i0)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/mod2.c b/final/lib/External/isl/test_inputs/codegen/cloog/mod2.c
new file mode 100644
index 0000000..cafe0b8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/mod2.c
@@ -0,0 +1,3 @@
+for (int c0 = 0; c0 <= 3; c0 += 1)
+  if ((c0 + 1) % 3 >= 1)
+    S1(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/mod2.st b/final/lib/External/isl/test_inputs/codegen/cloog/mod2.st
new file mode 100644
index 0000000..3097bb7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/mod2.st
@@ -0,0 +1,6 @@
+domain: "{ S1[i] : exists (e0 = floor((1 + i)/3): 3e0 <= i and 3e0 >= -1 + i and i >= 0 and i <= 3) }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i] -> [(i)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/mod3.c b/final/lib/External/isl/test_inputs/codegen/cloog/mod3.c
new file mode 100644
index 0000000..f8d879c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/mod3.c
@@ -0,0 +1,4 @@
+for (int c0 = max(0, 32 * h0 - 1991); c0 <= min(999, 32 * h0 + 31); c0 += 1)
+  if ((32 * h0 - c0 + 32) % 64 >= 1)
+    for (int c1 = 0; c1 <= 999; c1 += 1)
+      S1(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/mod3.st b/final/lib/External/isl/test_inputs/codegen/cloog/mod3.st
new file mode 100644
index 0000000..eaad170
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/mod3.st
@@ -0,0 +1,6 @@
+domain: "[h0] -> { S1[i0, i1] : exists (e0 = floor((32 + 32h0 - i0)/64): 64e0 <= 31 + 32h0 - i0 and 64e0 >= -31 + 32h0 - i0 and i0 >= 0 and i0 <= 999 and i0 >= -2015 + 32h0 and 32e0 >= -999 + 32h0 - i0 and i1 >= 0 and i1 <= 999 and i0 <= 32 + 32h0) }"
+child:
+  context: "[h0] -> { [] : h0 <= 93 and h0 >= 0 }"
+  child:
+    schedule: "[h0] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]"
+    options: "[h0] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/mod4.c b/final/lib/External/isl/test_inputs/codegen/cloog/mod4.c
new file mode 100644
index 0000000..a5dca24
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/mod4.c
@@ -0,0 +1,5 @@
+for (int c0 = 2; c0 <= 10; c0 += 3) {
+  S1(c0, (c0 + 1) / 3, (c0 + 1) / 3, 2, (c0 - 2) / 3);
+  S2(c0, (c0 + 1) / 3, (c0 + 1) / 3, 2, (c0 - 2) / 3);
+  S3(c0, (c0 + 1) / 3, (c0 + 1) / 3, 2, (c0 - 2) / 3);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/mod4.st b/final/lib/External/isl/test_inputs/codegen/cloog/mod4.st
new file mode 100644
index 0000000..99501a8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/mod4.st
@@ -0,0 +1,11 @@
+domain: "{ S1[j, div41, div42, 2, mod6_a] : 3mod6_a = -2 + j and j >= 1 and j <= 10 and 3div41 >= j and 3div42 >= -1 + j and 3div42 <= 1 + j and 3div41 <= 2 + j; S2[j, div41, div42, 2, mod6_a] : 3div42 = 1 + j and 3mod6_a = -2 + j and 3div41 >= 1 + j and 3div41 <= 2 + j and j >= 1 and j <= 10; S3[j, div41, div42, 2, mod6_a] : 3mod6_a = -2 + j and j >= 1 and j <= 10 and 3div41 >= j and 3div42 >= -1 + j and 3div42 <= 1 + j and 3div41 <= 2 + j }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[j, div41, div42, mod6, mod6_a] -> [(j)]; S3[j, div41, div42, mod6, mod6_a] -> [(j)]; S2[j, div41, div42, mod6, mod6_a] -> [(j)] }, { S1[j, div41, div42, mod6, mod6_a] -> [(div41)]; S3[j, div41, div42, mod6, mod6_a] -> [(div41)]; S2[j, div41, div42, mod6, mod6_a] -> [(div41)] }, { S1[j, div41, div42, mod6, mod6_a] -> [(div42)]; S3[j, div41, div42, mod6, mod6_a] -> [(div42)]; S2[j, div41, div42, mod6, mod6_a] -> [(div42)] }, { S1[j, div41, div42, mod6, mod6_a] -> [(mod6)]; S3[j, div41, div42, mod6, mod6_a] -> [(mod6)]; S2[j, div41, div42, mod6, mod6_a] -> [(mod6)] }, { S1[j, div41, div42, mod6, mod6_a] -> [(mod6_a)]; S3[j, div41, div42, mod6, mod6_a] -> [(mod6_a)]; S2[j, div41, div42, mod6, mod6_a] -> [(mod6_a)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[j, div41, div42, mod6, mod6_a] }"
+      - filter: "{ S2[j, div41, div42, mod6, mod6_a] }"
+      - filter: "{ S3[j, div41, div42, mod6, mod6_a] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/mode.c b/final/lib/External/isl/test_inputs/codegen/cloog/mode.c
new file mode 100644
index 0000000..5596b26
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/mode.c
@@ -0,0 +1,10 @@
+for (int c0 = 0; c0 <= M; c0 += 1) {
+  for (int c1 = 0; c1 <= min(N, c0); c1 += 1) {
+    S1(c0, c1);
+    S2(c0, c1);
+  }
+  for (int c1 = c0 + 1; c1 <= N; c1 += 1)
+    S2(c0, c1);
+  for (int c1 = max(0, N + 1); c1 <= c0; c1 += 1)
+    S1(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/mode.st b/final/lib/External/isl/test_inputs/codegen/cloog/mode.st
new file mode 100644
index 0000000..68ece14
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/mode.st
@@ -0,0 +1,10 @@
+domain: "[M, N] -> { S1[i0, i1] : i0 >= 0 and i0 <= M and i1 >= 0 and i1 <= i0; S2[i0, i1] : i0 >= 0 and i0 <= M and i1 >= 0 and i1 <= N }"
+child:
+  context: "[M, N] -> { [] }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S1[i0, i1] }"
+      - filter: "[M, N] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/multi-mm-1.c b/final/lib/External/isl/test_inputs/codegen/cloog/multi-mm-1.c
new file mode 100644
index 0000000..271d863
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/multi-mm-1.c
@@ -0,0 +1,8 @@
+for (int c0 = 0; c0 <= M; c0 += 1) {
+  for (int c1 = 0; c1 <= min(N, c0); c1 += 1) {
+    S1(c0, c1);
+    S2(c0, c1);
+  }
+  for (int c1 = N + 1; c1 <= c0; c1 += 1)
+    S1(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/multi-mm-1.st b/final/lib/External/isl/test_inputs/codegen/cloog/multi-mm-1.st
new file mode 100644
index 0000000..de96851
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/multi-mm-1.st
@@ -0,0 +1,10 @@
+domain: "[M, N] -> { S1[i0, i1] : i1 >= 0 and i1 <= i0 and i0 <= M; S2[i0, i1] : i1 >= 0 and i1 <= i0 and i0 <= M and i1 <= N }"
+child:
+  context: "[M, N] -> { [] : N <= M and N >= 1 }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S1[i0, i1] }"
+      - filter: "[M, N] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/multi-stride.c b/final/lib/External/isl/test_inputs/codegen/cloog/multi-stride.c
new file mode 100644
index 0000000..2c63c08
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/multi-stride.c
@@ -0,0 +1,2 @@
+{
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/multi-stride.st b/final/lib/External/isl/test_inputs/codegen/cloog/multi-stride.st
new file mode 100644
index 0000000..2c7788b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/multi-stride.st
@@ -0,0 +1,6 @@
+domain: "{ S1[i0, i1, i2] : 2i1 = -1 + i0 and 6i2 = -2 + i0 and i0 >= 0 and i0 <= 100 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/multi-stride2.c b/final/lib/External/isl/test_inputs/codegen/cloog/multi-stride2.c
new file mode 100644
index 0000000..14f8050
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/multi-stride2.c
@@ -0,0 +1,2 @@
+for (int c0 = 5; c0 <= 100; c0 += 6)
+  S1(c0, (c0 - 1) / 2, (c0 - 2) / 3);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/multi-stride2.st b/final/lib/External/isl/test_inputs/codegen/cloog/multi-stride2.st
new file mode 100644
index 0000000..e3fc0bc
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/multi-stride2.st
@@ -0,0 +1,6 @@
+domain: "{ S1[i0, i1, i2] : 2i1 = -1 + i0 and 3i2 = -2 + i0 and i0 >= 0 and i0 <= 100 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/mxm-shared.c b/final/lib/External/isl/test_inputs/codegen/cloog/mxm-shared.c
new file mode 100644
index 0000000..4308a9c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/mxm-shared.c
@@ -0,0 +1,3 @@
+if (N >= g0 + t1 + 1 && t1 <= 7 && g4 % 4 == 0)
+  for (int c0 = t0; c0 <= min(127, N - g1 - 1); c0 += 16)
+    S1(g0 + t1, g1 + c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/mxm-shared.st b/final/lib/External/isl/test_inputs/codegen/cloog/mxm-shared.st
new file mode 100644
index 0000000..c86ed9c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/mxm-shared.st
@@ -0,0 +1,6 @@
+domain: "[N, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> { S1[g0 + t1, i1] : (exists (e0 = floor((g1)/128), e1 = floor((128b1 - g1)/4096), e2 = floor((-8b0 + g0)/128), e3 = floor((-t0 + i1)/16): g3 = 128b1 and g4 = 0 and g2 = 8b0 and 128e0 = g1 and 4096e1 = 128b1 - g1 and 128e2 = -8b0 + g0 and 16e3 = -t0 + i1 and b0 <= 15 and b0 >= 0 and b1 <= 31 and b1 >= 0 and g0 >= 8b0 and g1 >= 128b1 and t0 <= 15 and t0 >= 0 and t1 <= 7 and t1 >= 0 and t1 <= -1 + N - g0 and i1 >= g1 and i1 <= 127 + g1 and i1 <= -1 + N)) or (exists (e0 = floor((g1)/128), e1 = floor((128b1 - g1)/4096), e2 = floor((g4)/4), e3 = floor((-8b0 + g0)/128), e4 = floor((-t0 + i1)/16): g3 = 128b1 and g2 = 8b0 and 128e0 = g1 and 4096e1 = 128b1 - g1 and 4e2 = g4 and 128e3 = -8b0 + g0 and 16e4 = -t0 + i1 and b0 <= 15 and b0 >= 0 and b1 <= 31 and b1 >= 0 and g0 >= 8b0 and g1 >= 128b1 and g4 >= 0 and g4 <= -1 + N and t0 <= 15 and t0 >= 0 and t1 <= 7 and t1 >= 0 and t1 <= -1 + N - g0 and i1 >= g1 and i1 <= 127 + g1 and i1 <= -1 + N)) }"
+child:
+  context: "[N, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> { [] : exists (e0 = floor((g0)/8), e1 = floor((-128b1 + g1)/4096), e2 = floor((8b0 - g0)/128): g2 = 8b0 and g3 = 128b1 and 8e0 = g0 and 4096e1 = -128b1 + g1 and 128e2 = 8b0 - g0 and b0 >= 0 and g4 <= -1 + N and b0 <= 15 and g1 <= -1 + N and g4 >= 0 and b1 <= 31 and g0 <= -1 + N and g1 >= 128b1 and b1 >= 0 and g0 >= 8b0 and t0 >= 0 and t0 <= 15 and t1 >= 0 and t1 <= 15) }"
+  child:
+    schedule: "[N, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> [{ S1[i0, i1] -> [(-g1 + i1)] }, { S1[i0, i1] -> [(t1)] }, { S1[i0, i1] -> [(t0)] }, { S1[i0, i1] -> [(t1)] }]"
+    options: "[N, b0, b1, g0, g1, g2, g3, g4, t0, t1] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/no_lindep.c b/final/lib/External/isl/test_inputs/codegen/cloog/no_lindep.c
new file mode 100644
index 0000000..1432b5e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/no_lindep.c
@@ -0,0 +1 @@
+S1(N + 2);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/no_lindep.st b/final/lib/External/isl/test_inputs/codegen/cloog/no_lindep.st
new file mode 100644
index 0000000..da06c8d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/no_lindep.st
@@ -0,0 +1,6 @@
+domain: "[M, N] -> { S1[2 + N] }"
+child:
+  context: "[M, N] -> { [] }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0] -> [(1 + M)] }, { S1[i0] -> [(N)] }]"
+    options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/nul_basic1.c b/final/lib/External/isl/test_inputs/codegen/cloog/nul_basic1.c
new file mode 100644
index 0000000..9293aef
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/nul_basic1.c
@@ -0,0 +1,2 @@
+for (int c0 = 0; c0 <= M; c0 += 2)
+  S1(c0, c0 / 2);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/nul_basic1.st b/final/lib/External/isl/test_inputs/codegen/cloog/nul_basic1.st
new file mode 100644
index 0000000..d8a3201
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/nul_basic1.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S1[i0, i1] : 2i1 = i0 and i0 >= 0 and i0 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/nul_basic2.c b/final/lib/External/isl/test_inputs/codegen/cloog/nul_basic2.c
new file mode 100644
index 0000000..2b7bb4d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/nul_basic2.c
@@ -0,0 +1,5 @@
+for (int c0 = 2; c0 <= n; c0 += 2) {
+  if (c0 % 4 == 0)
+    S2(c0, c0 / 4);
+  S1(c0, c0 / 2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/nul_basic2.st b/final/lib/External/isl/test_inputs/codegen/cloog/nul_basic2.st
new file mode 100644
index 0000000..3258c67
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/nul_basic2.st
@@ -0,0 +1,10 @@
+domain: "[n] -> { S1[i0, i1] : 2i1 = i0 and i0 >= 1 and i0 <= n; S2[i0, i1] : 4i1 = i0 and i0 >= 1 and i0 <= n }"
+child:
+  context: "[n] -> { [] : n >= 2 }"
+  child:
+    schedule: "[n] -> [{ S2[i0, i1] -> [(i0)]; S1[i0, i1] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0, i1] -> [(i1)] }]"
+    options: "[n] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[n] -> { S1[i0, i1] }"
+      - filter: "[n] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/nul_complex1.c b/final/lib/External/isl/test_inputs/codegen/cloog/nul_complex1.c
new file mode 100644
index 0000000..067e751
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/nul_complex1.c
@@ -0,0 +1,3 @@
+for (int c0 = 0; c0 <= 5 * n; c0 += 1)
+  for (int c1 = max(-((5 * n - c0 + 1) % 2) - n + c0 + 1, 2 * ((c0 + 2) / 3)); c1 <= min(c0, n + c0 - (n + c0 + 2) / 3); c1 += 2)
+    S1((3 * c1 / 2) - c0, c0 - c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/nul_complex1.st b/final/lib/External/isl/test_inputs/codegen/cloog/nul_complex1.st
new file mode 100644
index 0000000..93e3329
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/nul_complex1.st
@@ -0,0 +1,6 @@
+domain: "[n] -> { S1[i0, i1] : i0 >= 0 and i0 <= n and i1 >= 0 and i1 <= n }"
+child:
+  context: "[n] -> { [] }"
+  child:
+    schedule: "[n] -> [{ S1[i0, i1] -> [(2i0 + 3i1)] }, { S1[i0, i1] -> [(2i0 + 2i1)] }]"
+    options: "[n] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/nul_lcpc.c b/final/lib/External/isl/test_inputs/codegen/cloog/nul_lcpc.c
new file mode 100644
index 0000000..e6f3968
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/nul_lcpc.c
@@ -0,0 +1,13 @@
+{
+  for (int c0 = 1; c0 <= 6; c0 += 2) {
+    for (int c2 = 1; c2 <= c0; c2 += 1) {
+      S1(c0, (c0 - 1) / 2, c2);
+      S2(c0, (c0 - 1) / 2, c2);
+    }
+    for (int c2 = c0 + 1; c2 <= p; c2 += 1)
+      S1(c0, (c0 - 1) / 2, c2);
+  }
+  for (int c0 = 7; c0 <= m; c0 += 2)
+    for (int c2 = 1; c2 <= p; c2 += 1)
+      S1(c0, (c0 - 1) / 2, c2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/nul_lcpc.st b/final/lib/External/isl/test_inputs/codegen/cloog/nul_lcpc.st
new file mode 100644
index 0000000..4571d78
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/nul_lcpc.st
@@ -0,0 +1,10 @@
+domain: "[m, n, p] -> { S1[i, k, j] : 2k = -1 + i and i >= 1 and i <= m and j >= 1 and j <= p; S2[i, k, j] : 2k = -1 + i and i >= 1 and i <= n and j >= 1 and j <= i }"
+child:
+  context: "[m, n, p] -> { [] : n = 6 and m >= 7 and p >= 7 }"
+  child:
+    schedule: "[m, n, p] -> [{ S1[i, k, j] -> [(i)]; S2[i, k, j] -> [(i)] }, { S1[i, k, j] -> [(k)]; S2[i, k, j] -> [(k)] }, { S1[i, k, j] -> [(j)]; S2[i, k, j] -> [(j)] }]"
+    options: "[m, n, p] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[m, n, p] -> { S1[i, k, j] }"
+      - filter: "[m, n, p] -> { S2[i, k, j] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/orc.c b/final/lib/External/isl/test_inputs/codegen/cloog/orc.c
new file mode 100644
index 0000000..4099944
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/orc.c
@@ -0,0 +1,16 @@
+{
+  for (int c0 = 0; c0 <= 2; c0 += 1) {
+    S1(c0);
+    for (int c1 = 0; c1 <= -c0 + 11; c1 += 1) {
+      S2(c0, c1);
+      S3(c0, c1);
+    }
+    S4(c0);
+  }
+  for (int c0 = 0; c0 <= 14; c0 += 1) {
+    S5(c0);
+    for (int c1 = 0; c1 <= 9; c1 += 1)
+      S6(c0, c1);
+    S7(c0);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/orc.st b/final/lib/External/isl/test_inputs/codegen/cloog/orc.st
new file mode 100644
index 0000000..a67a880
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/orc.st
@@ -0,0 +1,13 @@
+domain: "{ S5[i] : i >= 0 and i <= 14; S6[i, j] : i >= 0 and i <= 14 and j >= 0 and j <= 9; S7[i] : i >= 0 and i <= 14; S4[i] : i >= 0 and i <= 2; S2[i, j] : i >= 0 and i <= 2 and j >= 0 and j <= 11 - i; S1[i] : i >= 0 and i <= 2; S3[i, j] : i >= 0 and i <= 2 and j >= 0 and j <= 11 - i }"
+child:
+  context: "{ [] }"
+  child:
+    sequence:
+    - filter: "{ S4[i0]; S2[i0, i1]; S1[i0]; S3[i0, i1] }"
+      child:
+        schedule: "[{ S3[i0, i1] -> [(1 + 3i0)]; S2[i0, i1] -> [(1 + 3i0)]; S1[i0] -> [(3i0)]; S4[i0] -> [(2 + 3i0)] }, { S3[i0, i1] -> [(1 + 2i1)]; S2[i0, i1] -> [(2i1)]; S1[i0] -> [(0)]; S4[i0] -> [(0)] }]"
+        options: "{ separate[i0] }"
+    - filter: "{ S5[i0]; S6[i0, i1]; S7[i0] }"
+      child:
+        schedule: "[{ S6[i0, i1] -> [(1 + 3i0)]; S7[i0] -> [(2 + 3i0)]; S5[i0] -> [(3i0)] }, { S6[i0, i1] -> [(i1)]; S7[i0] -> [(0)]; S5[i0] -> [(0)] }]"
+        options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/otl.c b/final/lib/External/isl/test_inputs/codegen/cloog/otl.c
new file mode 100644
index 0000000..7937334
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/otl.c
@@ -0,0 +1,7 @@
+if (M >= 3 && N >= 4)
+  for (int c0 = 1; c0 < (2 * M + 2 * N - 2) / 5; c0 += 1)
+    for (int c1 = max(c0 - (M + 2) / 5, (c0 + 1) / 2); c1 <= min(min(c0, (M + 2 * N) / 5 - 1), (2 * N + 5 * c0 + 1) / 10); c1 += 1)
+      for (int c2 = max(max(max(max(0, c0 - c1 - 1), c1 - (N + 6) / 5 + 1), c0 - (M + N + 4) / 5 + 1), floord(-N + 5 * c0 - 3, 10) + 1); c2 <= min(min(min(c1, (M + N - 2) / 5), c0 - c1 + (N - 1) / 5 + 1), (N + 5 * c0 + 3) / 10); c2 += 1)
+        for (int c3 = max(max(max(c0, 2 * c1 - (2 * N + 5) / 5 + 1), c1 + c2 - (N + 3) / 5), 2 * c2 - (N + 2) / 5); c3 <= min(min(min(min(min(c0 + 1, c1 + c2 + 1), c1 + (M - 2) / 5 + 1), 2 * c2 + (N - 2) / 5 + 1), (2 * M + 2 * N - 1) / 5 - 1), c2 + (M + N) / 5); c3 += 1)
+          for (int c4 = max(max(max(max(c1, c0 - c2), c0 - (M + 6) / 5 + 1), c3 - (M + 2) / 5), (c3 + 1) / 2); c4 <= min(min(min(min(min(min(min(c0, c1 + 1), -c2 + c3 + (N - 1) / 5 + 1), c0 - c2 + N / 5 + 1), (M + 2 * N + 1) / 5 - 1), c2 + (N + 2) / 5), (2 * N + 5 * c0 + 3) / 10), (2 * N + 5 * c3 + 2) / 10); c4 += 1)
+            S1(c0, c1, c2, c3, c4, c2);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/otl.st b/final/lib/External/isl/test_inputs/codegen/cloog/otl.st
new file mode 100644
index 0000000..da70683
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/otl.st
@@ -0,0 +1,6 @@
+domain: "[M, N] -> { S1[outerTimeTileIter, outerProcTileIter1, outerProcTileIter2, innerTimeTileIter, innerProcTileIter1, outerProcTileIter2] : 5outerTimeTileIter <= -7 + 2M + 2N and innerProcTileIter1 >= outerTimeTileIter - outerProcTileIter2 and 10outerProcTileIter2 >= -2 - N + 5outerTimeTileIter and outerProcTileIter2 >= -1 + outerTimeTileIter - outerProcTileIter1 and 2innerProcTileIter1 >= outerTimeTileIter and outerTimeTileIter >= 1 and outerProcTileIter1 >= 1 and 2outerProcTileIter1 >= outerTimeTileIter and outerProcTileIter2 >= 0 and 5outerProcTileIter2 >= 1 - M - N + 5outerTimeTileIter and 5innerProcTileIter1 >= -1 - M + 5outerTimeTileIter and innerTimeTileIter >= outerTimeTileIter and 5outerProcTileIter1 >= -2 - M + 5outerTimeTileIter and innerTimeTileIter >= 1 and 5innerTimeTileIter >= -3 - N + 5outerProcTileIter1 + 5outerProcTileIter2 and 5outerProcTileIter2 <= 4 + N + 5outerTimeTileIter - 5outerProcTileIter1 and innerProcTileIter1 >= 1 and outerProcTileIter2 <= outerTimeTileIter and 5innerTimeTileIter >= -2N + 10outerProcTileIter1 and 5outerProcTileIter1 <= -5 + M + 2N and 10outerProcTileIter1 <= 1 + 2N + 5outerTimeTileIter and 5outerProcTileIter2 >= -1 - N + 5outerProcTileIter1 and innerProcTileIter1 >= outerProcTileIter1 and innerTimeTileIter >= outerProcTileIter1 and outerProcTileIter2 <= outerProcTileIter1 and outerProcTileIter1 <= outerTimeTileIter and 5innerProcTileIter1 <= 4 + N - 5outerProcTileIter2 + 5innerTimeTileIter and 5innerProcTileIter1 <= 5 + N + 5outerTimeTileIter - 5outerProcTileIter2 and 5innerTimeTileIter >= -2 - N + 10outerProcTileIter2 and 5outerProcTileIter2 <= -2 + M + N and 10outerProcTileIter2 <= 3 + N + 5outerTimeTileIter and N >= 4 and innerProcTileIter1 >= outerProcTileIter2 and innerTimeTileIter >= outerProcTileIter2 and M >= 3 and innerProcTileIter1 <= outerTimeTileIter and 5innerTimeTileIter <= -6 + 2M + 2N and innerProcTileIter1 >= -1 - outerProcTileIter2 + innerTimeTileIter and 5innerTimeTileIter <= 3 + N + 10outerProcTileIter2 and innerTimeTileIter <= 1 + outerProcTileIter1 + outerProcTileIter2 and innerProcTileIter1 <= 1 + outerProcTileIter1 and 2innerProcTileIter1 >= innerTimeTileIter and 5innerProcTileIter1 <= 2 + N + 5outerProcTileIter2 and innerTimeTileIter <= 1 + 2outerProcTileIter1 and innerProcTileIter1 <= innerTimeTileIter and 5innerTimeTileIter <= M + N + 5outerProcTileIter2 and 5innerProcTileIter1 >= -2 - M + 5innerTimeTileIter and 10innerProcTileIter1 <= 3 + 2N + 5outerTimeTileIter and innerTimeTileIter <= 1 + outerTimeTileIter and 5innerTimeTileIter <= 3 + M + 5outerProcTileIter1 and 5innerProcTileIter1 <= -4 + M + 2N and 10innerProcTileIter1 <= 2 + 2N + 5innerTimeTileIter }"
+child:
+  context: "[M, N] -> { [] : M >= 1 and N >= 1 }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1, i2, i3, i4, i5] -> [(i0)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i1)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i2)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i3)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i4)] }, { S1[i0, i1, i2, i3, i4, i5] -> [(i5)] }]"
+    options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/param-split.c b/final/lib/External/isl/test_inputs/codegen/cloog/param-split.c
new file mode 100644
index 0000000..a9d9712
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/param-split.c
@@ -0,0 +1,6 @@
+for (int c0 = 0; c0 <= max(0, M); c0 += 1) {
+  if (M >= c0)
+    S1(c0);
+  if (c0 == 0)
+    S2(0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/param-split.st b/final/lib/External/isl/test_inputs/codegen/cloog/param-split.st
new file mode 100644
index 0000000..371372f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/param-split.st
@@ -0,0 +1,10 @@
+domain: "[M] -> { S2[0]; S1[i0] : i0 >= 0 and i0 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S2[i0] -> [(i0)]; S1[i0] -> [(i0)] }]"
+    options: "[M] -> { atomic[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S1[i0] }"
+      - filter: "[M] -> { S2[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/pouchet.c b/final/lib/External/isl/test_inputs/codegen/cloog/pouchet.c
new file mode 100644
index 0000000..97974bb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/pouchet.c
@@ -0,0 +1,12 @@
+for (int c0 = 1; c0 <= floord(Ny, 2) + 2; c0 += 1)
+  for (int c1 = max(c0 - 1, c0 / 2 + 1); c1 <= min(c0, (Ny + 2 * c0) / 4); c1 += 1) {
+    if (Ny + 2 * c0 >= 4 * c1 + 1) {
+      for (int c2 = 1; c2 <= 2; c2 += 1) {
+        S1(c0 - c1, c1, 2 * c0 - 2 * c1, -2 * c0 + 4 * c1, c2);
+        S2(c0 - c1, c1, 2 * c0 - 2 * c1, -2 * c0 + 4 * c1 - 1, c2);
+      }
+    } else {
+      for (int c2 = 1; c2 <= 2; c2 += 1)
+        S2((-Ny + 2 * c0) / 4, (Ny + 2 * c0) / 4, (-Ny / 2) + c0, Ny - 1, c2);
+    }
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/pouchet.st b/final/lib/External/isl/test_inputs/codegen/cloog/pouchet.st
new file mode 100644
index 0000000..8ba0928
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/pouchet.st
@@ -0,0 +1,6 @@
+domain: "[Ny] -> { S1[i0, i1, 2i0, -2i0 + 2i1, i4] : i0 >= 0 and i0 <= 1 and i1 >= 1 + i0 and 2i1 <= -1 + Ny + 2i0 and i4 >= 1 and i4 <= 2; S2[i0, i1, 2i0, -1 - 2i0 + 2i1, i4] : i0 >= 0 and i0 <= 1 and i1 >= 1 + i0 and 2i1 <= Ny + 2i0 and i4 >= 1 and i4 <= 2 }"
+child:
+  context: "[Ny] -> { [] }"
+  child:
+    schedule: "[Ny] -> [{ S1[i0, i1, i2, i3, i4] -> [(i0 + i1)]; S2[i0, i1, i2, i3, i4] -> [(i0 + i1)] }, { S1[i0, i1, i2, i3, i4] -> [(i1)]; S2[i0, i1, i2, i3, i4] -> [(i1)] }, { S1[i0, i1, i2, i3, i4] -> [(i4)]; S2[i0, i1, i2, i3, i4] -> [(i4)] }, { S1[i0, i1, i2, i3, i4] -> [(i2)]; S2[i0, i1, i2, i3, i4] -> [(i2)] }, { S1[i0, i1, i2, i3, i4] -> [(i3)]; S2[i0, i1, i2, i3, i4] -> [(1 + i3)] }, { S1[i0, i1, i2, i3, i4] -> [(i4)]; S2[i0, i1, i2, i3, i4] -> [(1 + i4)] }]"
+    options: "[Ny] -> { separate[x] : x >= 2 }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/rectangle.c b/final/lib/External/isl/test_inputs/codegen/cloog/rectangle.c
new file mode 100644
index 0000000..10d1f76
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/rectangle.c
@@ -0,0 +1,3 @@
+for (int c0 = 0; c0 <= 2 * n; c0 += 1)
+  for (int c1 = max(0, -n + c0); c1 <= min(n, c0); c1 += 1)
+    S1(c1, c0 - c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/rectangle.st b/final/lib/External/isl/test_inputs/codegen/cloog/rectangle.st
new file mode 100644
index 0000000..a4a9e51
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/rectangle.st
@@ -0,0 +1,6 @@
+domain: "[n] -> { S1[i0, i1] : i0 >= 0 and i0 <= n and i1 >= 0 and i1 <= n }"
+child:
+  context: "[n] -> { [] : n >= 0 }"
+  child:
+    schedule: "[n] -> [{ S1[i0, i1] -> [(i0 + i1)] }]"
+    options: "[n] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-QR.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-QR.c
new file mode 100644
index 0000000..fee61aa
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-QR.c
@@ -0,0 +1,54 @@
+if (N >= 1) {
+  S1(0);
+  if (N == 1) {
+    for (int c1 = 0; c1 < M; c1 += 1)
+      S2(0, c1);
+    S3(0);
+    for (int c1 = 0; c1 < M; c1 += 1)
+      S4(0, c1);
+    S10(0);
+    S5(0);
+  } else {
+    for (int c1 = 0; c1 < M; c1 += 1)
+      S2(0, c1);
+    S3(0);
+    for (int c1 = 0; c1 < M; c1 += 1)
+      S4(0, c1);
+    S10(0);
+    S1(1);
+    S5(0);
+  }
+  for (int c0 = 2; c0 < N; c0 += 1) {
+    for (int c1 = c0 - 1; c1 < N; c1 += 1) {
+      S6(c0 - 2, c1);
+      for (int c2 = c0 - 2; c2 < M; c2 += 1)
+        S7(c0 - 2, c1, c2);
+      S8(c0 - 2, c1);
+      for (int c2 = c0 - 2; c2 < M; c2 += 1)
+        S9(c0 - 2, c1, c2);
+    }
+    for (int c1 = c0 - 1; c1 < M; c1 += 1)
+      S2(c0 - 1, c1);
+    S3(c0 - 1);
+    for (int c1 = c0 - 1; c1 < M; c1 += 1)
+      S4(c0 - 1, c1);
+    S10(c0 - 1);
+    S1(c0);
+    S5(c0 - 1);
+  }
+  if (N >= 2) {
+    S6(N - 2, N - 1);
+    for (int c2 = N - 2; c2 < M; c2 += 1)
+      S7(N - 2, N - 1, c2);
+    S8(N - 2, N - 1);
+    for (int c2 = N - 2; c2 < M; c2 += 1)
+      S9(N - 2, N - 1, c2);
+    for (int c1 = N - 1; c1 < M; c1 += 1)
+      S2(N - 1, c1);
+    S3(N - 1);
+    for (int c1 = N - 1; c1 < M; c1 += 1)
+      S4(N - 1, c1);
+    S10(N - 1);
+    S5(N - 1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-QR.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-QR.st
new file mode 100644
index 0000000..8be6a03
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-QR.st
@@ -0,0 +1,36 @@
+domain: "[M, N] -> { S5[i0] : i0 >= 0 and i0 <= -1 + N; S1[i0] : i0 >= 0 and i0 <= -1 + N; S3[i0] : i0 >= 0 and i0 <= -1 + N; S2[i0, i1] : i0 >= 0 and i0 <= -1 + N and i1 >= i0 and i1 <= -1 + M; S6[i0, i1] : i0 >= 0 and i1 >= 1 + i0 and i1 <= -1 + N; S9[i0, i1, i2] : i0 >= 0 and i1 >= 1 + i0 and i1 <= -1 + N and i2 >= i0 and i2 <= -1 + M; S4[i0, i1] : i0 >= 0 and i0 <= -1 + N and i1 >= i0 and i1 <= -1 + M; S8[i0, i1] : i0 >= 0 and i1 >= 1 + i0 and i1 <= -1 + N; S10[i0] : i0 >= 0 and i0 <= -1 + N; S7[i0, i1, i2] : i0 >= 0 and i1 >= 1 + i0 and i1 <= -1 + N and i2 >= i0 and i2 <= -1 + M }"
+child:
+  context: "[M, N] -> { [] }"
+  child:
+    schedule: "[M, N] -> [{ S3[i0] -> [(1 + i0)]; S10[i0] -> [(1 + i0)]; S5[i0] -> [(1 + i0)]; S7[i0, i1, i2] -> [(2 + i0)]; S9[i0, i1, i2] -> [(2 + i0)]; S2[i0, i1] -> [(1 + i0)]; S4[i0, i1] -> [(1 + i0)]; S8[i0, i1] -> [(2 + i0)]; S1[i0] -> [(i0)]; S6[i0, i1] -> [(2 + i0)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S6[i0, i1]; S9[i0, i1, i2]; S8[i0, i1]; S7[i0, i1, i2] }"
+        child:
+          schedule: "[M, N] -> [{ S7[i0, i1, i2] -> [(i1)]; S9[i0, i1, i2] -> [(i1)]; S8[i0, i1] -> [(i1)]; S6[i0, i1] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
+          child:
+            sequence:
+            - filter: "[M, N] -> { S6[i0, i1] }"
+            - filter: "[M, N] -> { S7[i0, i1, i2] }"
+              child:
+                schedule: "[M, N] -> [{ S7[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N] -> { separate[i0] }"
+            - filter: "[M, N] -> { S8[i0, i1] }"
+            - filter: "[M, N] -> { S9[i0, i1, i2] }"
+              child:
+                schedule: "[M, N] -> [{ S9[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N] -> { separate[i0] }"
+      - filter: "[M, N] -> { S2[i0, i1] }"
+        child:
+          schedule: "[M, N] -> [{ S2[i0, i1] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
+      - filter: "[M, N] -> { S3[i0] }"
+      - filter: "[M, N] -> { S4[i0, i1] }"
+        child:
+          schedule: "[M, N] -> [{ S4[i0, i1] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
+      - filter: "[M, N] -> { S10[i0] }"
+      - filter: "[M, N] -> { S1[i0] }"
+      - filter: "[M, N] -> { S5[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-bastoul3.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-bastoul3.c
new file mode 100644
index 0000000..6d82ce4
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-bastoul3.c
@@ -0,0 +1,3 @@
+for (int c0 = 3; c0 <= 9; c0 += 1)
+  for (int c1 = max(c0 - 6, -(c0 % 2) + 2); c1 <= min(3, c0 - 2); c1 += 2)
+    S1(c0, c1, (c0 - c1) / 2);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-bastoul3.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-bastoul3.st
new file mode 100644
index 0000000..66fe7a3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-bastoul3.st
@@ -0,0 +1,6 @@
+domain: "{ S1[i0, i1, i2] : 2i2 = i0 - i1 and i1 >= 1 and i1 <= 3 and i1 <= -2 + i0 and i1 >= -6 + i0 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-cholesky2.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-cholesky2.c
new file mode 100644
index 0000000..73f7790
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-cholesky2.c
@@ -0,0 +1,9 @@
+for (int c0 = 2; c0 < 3 * M; c0 += 1) {
+  if ((c0 + 1) % 3 == 0)
+    S1((c0 + 1) / 3);
+  for (int c1 = (c0 + 1) / 3 + 1; c1 <= min(M, c0 - 2); c1 += 1)
+    for (int c2 = -c1 + (c0 + c1 + 1) / 2 + 1; c2 <= min(c1, c0 - c1); c2 += 1)
+      S3(c0 - c1 - c2 + 1, c1, c2);
+  for (int c1 = -c0 + 2 * ((2 * c0 + 1) / 3) + 2; c1 <= min(M, c0); c1 += 2)
+    S2(((c0 - c1) / 2) + 1, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-cholesky2.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-cholesky2.st
new file mode 100644
index 0000000..4ae03d7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-cholesky2.st
@@ -0,0 +1,20 @@
+domain: "[M] -> { S3[i0, i1, i2] : i0 >= 1 and i1 <= M and i2 >= 1 + i0 and i2 <= i1; S2[i0, i1] : i0 >= 1 and i1 >= 1 + i0 and i1 <= M; S1[i0] : i0 >= 1 and i0 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0] -> [(-1 + 3i0)]; S3[i0, i1, i2] -> [(-1 + i0 + i1 + i2)]; S2[i0, i1] -> [(-2 + 2i0 + i1)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S1[i0] }"
+      - filter: "[M] -> { S3[i0, i1, i2] }"
+        child:
+          schedule: "[M] -> [{ S3[i0, i1, i2] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
+          child:
+            schedule: "[M] -> [{ S3[i0, i1, i2] -> [(i2)] }]"
+            options: "[M] -> { separate[i0] }"
+      - filter: "[M] -> { S2[i0, i1] }"
+        child:
+          schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-fusion1.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-fusion1.c
new file mode 100644
index 0000000..d586eba
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-fusion1.c
@@ -0,0 +1,8 @@
+{
+  for (int c0 = 0; c0 <= M; c0 += 1)
+    S1(c0);
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    S2(c0);
+  for (int c0 = 0; c0 <= M; c0 += 1)
+    S3(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-fusion1.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-fusion1.st
new file mode 100644
index 0000000..25c0cfd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-fusion1.st
@@ -0,0 +1,17 @@
+domain: "[M] -> { S3[i0] : i0 >= 0 and i0 <= M; S2[i0] : i0 >= 1 and i0 <= M; S1[i0] : i0 >= 0 and i0 <= M }"
+child:
+  context: "[M] -> { [] : M >= 1 }"
+  child:
+    sequence:
+    - filter: "[M] -> { S1[i0] }"
+      child:
+        schedule: "[M] -> [{ S1[i0] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+    - filter: "[M] -> { S2[i0] }"
+      child:
+        schedule: "[M] -> [{ S2[i0] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+    - filter: "[M] -> { S3[i0] }"
+      child:
+        schedule: "[M] -> [{ S3[i0] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-fusion2.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-fusion2.c
new file mode 100644
index 0000000..e31aaec
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-fusion2.c
@@ -0,0 +1,12 @@
+if (N >= 1) {
+  for (int c1 = 1; c1 <= M; c1 += 1)
+    S1(1, c1);
+  for (int c0 = 2; c0 <= N; c0 += 1) {
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S2(c0 - 1, c1);
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S1(c0, c1);
+  }
+  for (int c1 = 1; c1 <= M; c1 += 1)
+    S2(N, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-fusion2.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-fusion2.st
new file mode 100644
index 0000000..ee65424
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-fusion2.st
@@ -0,0 +1,16 @@
+domain: "[M, N] -> { S1[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M; S2[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M }"
+child:
+  context: "[M, N] -> { [] }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(1 + i0)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S2[i0, i1] }"
+        child:
+          schedule: "[M, N] -> [{ S2[i0, i1] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
+      - filter: "[M, N] -> { S1[i0, i1] }"
+        child:
+          schedule: "[M, N] -> [{ S1[i0, i1] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-jacobi2.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-jacobi2.c
new file mode 100644
index 0000000..6a04045
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-jacobi2.c
@@ -0,0 +1,3 @@
+for (int c0 = 0; c0 < M; c0 += 1)
+  for (int c1 = 0; c1 < M; c1 += 1)
+    S1(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-jacobi2.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-jacobi2.st
new file mode 100644
index 0000000..fe1230d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-jacobi2.st
@@ -0,0 +1,9 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 0 and i0 <= -1 + M and i1 >= 0 and i1 <= -1 + M }"
+child:
+  context: "[M] -> { [] : M >= 1 }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }]"
+      options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-jacobi3.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-jacobi3.c
new file mode 100644
index 0000000..7253575
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-jacobi3.c
@@ -0,0 +1,8 @@
+for (int c0 = 1; c0 <= M; c0 += 1) {
+  for (int c2 = 2; c2 < N; c2 += 1)
+    for (int c3 = 2; c3 < N; c3 += 1)
+      S1(c0, c2, c3);
+  for (int c2 = 2; c2 < N; c2 += 1)
+    for (int c3 = 2; c3 < N; c3 += 1)
+      S2(c0, c2, c3);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-jacobi3.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-jacobi3.st
new file mode 100644
index 0000000..815ffe2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-jacobi3.st
@@ -0,0 +1,22 @@
+domain: "[M, N] -> { S2[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + N; S1[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + N }"
+child:
+  context: "[M, N] -> { [] }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(2i0)]; S2[i0, i1, i2] -> [(1 + 2i0)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S1[i0, i1, i2] }"
+        child:
+          schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
+          child:
+            schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N] -> { separate[i0] }"
+      - filter: "[M, N] -> { S2[i0, i1, i2] }"
+        child:
+          schedule: "[M, N] -> [{ S2[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
+          child:
+            schedule: "[M, N] -> [{ S2[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam1.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam1.c
new file mode 100644
index 0000000..e326941
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam1.c
@@ -0,0 +1,10 @@
+for (int c0 = -99; c0 <= 100; c0 += 1) {
+  if (c0 <= 0)
+    S1(1, -c0 + 1);
+  for (int c1 = max(1, -2 * c0 + 3); c1 <= min(199, -2 * c0 + 199); c1 += 2) {
+    S2(((c1 - 1) / 2) + c0, (c1 + 1) / 2);
+    S1(((c1 + 1) / 2) + c0, (c1 + 1) / 2);
+  }
+  if (c0 >= 1)
+    S2(100, -c0 + 101);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam1.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam1.st
new file mode 100644
index 0000000..cf7efee
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam1.st
@@ -0,0 +1,13 @@
+domain: "{ S2[i0, i1] : i0 >= 1 and i0 <= 100 and i1 >= 1 and i1 <= 100; S1[i0, i1] : i0 >= 1 and i0 <= 100 and i1 >= 1 and i1 <= 100 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0, i1] -> [(i0 - i1)]; S2[i0, i1] -> [(1 + i0 - i1)] }]"
+    options: "{ separate[i0] }"
+    child:
+      schedule: "[{ S1[i0, i1] -> [(2i1)]; S2[i0, i1] -> [(-1 + 2i1)] }]"
+      options: "{ separate[i0] }"
+      child:
+        sequence:
+        - filter: "{ S1[i0, i1] }"
+        - filter: "{ S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam2.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam2.c
new file mode 100644
index 0000000..483fe52
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam2.c
@@ -0,0 +1,10 @@
+{
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    S1(c0);
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    for (int c1 = 2; c1 <= N; c1 += 1)
+      S2(c0, c1);
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    for (int c1 = 1; c1 < N; c1 += 1)
+      S3(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam2.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam2.st
new file mode 100644
index 0000000..b53558f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam2.st
@@ -0,0 +1,23 @@
+domain: "[M, N] -> { S3[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= -1 + N; S1[i0] : i0 >= 1 and i0 <= M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 2 and i1 <= N }"
+child:
+  context: "[M, N] -> { [] : M >= 1 and N >= 1 }"
+  child:
+    sequence:
+    - filter: "[M, N] -> { S1[i0] }"
+      child:
+        schedule: "[M, N] -> [{ S1[i0] -> [(i0)] }]"
+        options: "[M, N] -> { separate[i0] }"
+    - filter: "[M, N] -> { S2[i0, i1] }"
+      child:
+        schedule: "[M, N] -> [{ S2[i0, i1] -> [(i0)] }]"
+        options: "[M, N] -> { separate[i0] }"
+        child:
+          schedule: "[M, N] -> [{ S2[i0, i1] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
+    - filter: "[M, N] -> { S3[i0, i1] }"
+      child:
+        schedule: "[M, N] -> [{ S3[i0, i1] -> [(i0)] }]"
+        options: "[M, N] -> { separate[i0] }"
+        child:
+          schedule: "[M, N] -> [{ S3[i0, i1] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam3.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam3.c
new file mode 100644
index 0000000..9d290b5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam3.c
@@ -0,0 +1,11 @@
+for (int c0 = 5; c0 <= 5 * M; c0 += 1) {
+  for (int c1 = max(2, floord(-M + c0, 4)); c1 < min(-((5 * M - c0 + 1) % 2) + M, (c0 + 1) / 3 - 2); c1 += 1)
+    for (int c2 = max(1, -M - c1 + (M + c0) / 2 - 2); c2 < min(c1, -2 * c1 + (c0 + c1) / 2 - 2); c2 += 1)
+      S1(c0 - 2 * c1 - 2 * c2 - 5, c1, c2);
+  for (int c1 = max(1, floord(-M + c0, 4)); c1 < (c0 + 1) / 5; c1 += 1)
+    S2(c0 - 4 * c1 - 3, c1);
+  if (c0 % 5 == 0)
+    S4(c0 / 5);
+  for (int c1 = max(-3 * M - c0 + 3 * ((M + c0) / 2) + 1, -((c0 - 1) % 3) + 3); c1 < (c0 + 1) / 5; c1 += 3)
+    S3((c0 - 2 * c1 - 1) / 3, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam3.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam3.st
new file mode 100644
index 0000000..cedd5e5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam3.st
@@ -0,0 +1,23 @@
+domain: "[M] -> { S4[i0] : i0 >= 1 and i0 <= M; S3[i0, i1] : i0 <= M and i1 >= 1 and i1 <= -1 + i0; S2[i0, i1] : i0 <= M and i1 >= 1 and i1 <= -1 + i0; S1[i0, i1, i2] : i0 <= M and i1 <= -1 + i0 and i2 >= 1 and i2 <= -1 + i1 }"
+child:
+  context: "[M] -> { [] : M >= 1 }"
+  child:
+    schedule: "[M] -> [{ S4[i0] -> [(5i0)]; S1[i0, i1, i2] -> [(5 + i0 + 2i1 + 2i2)]; S3[i0, i1] -> [(1 + 3i0 + 2i1)]; S2[i0, i1] -> [(3 + i0 + 4i1)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S1[i0, i1, i2] }"
+        child:
+          schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
+          child:
+            schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i2)] }]"
+            options: "[M] -> { separate[i0] }"
+      - filter: "[M] -> { S2[i0, i1] }"
+        child:
+          schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
+      - filter: "[M] -> { S4[i0]; S3[i0, i1] }"
+        child:
+          schedule: "[M] -> [{ S4[i0] -> [(0)]; S3[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam4.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam4.c
new file mode 100644
index 0000000..ed00e99
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam4.c
@@ -0,0 +1,10 @@
+for (int c0 = 1; c0 < 2 * M - 1; c0 += 1) {
+  for (int c1 = max(-M + 1, -c0 + 1); c1 < 0; c1 += 1) {
+    for (int c3 = max(1, -M + c0 + 1); c3 <= min(M - 1, c0 + c1); c3 += 1)
+      S1(c3, c0 + c1 - c3, -c1);
+    for (int c2 = max(-M + c0 + 1, -c1); c2 < min(M, c0); c2 += 1)
+      S2(c0 - c2, c1 + c2, c2);
+  }
+  for (int c3 = max(1, -M + c0 + 1); c3 <= min(M - 1, c0); c3 += 1)
+    S1(c3, c0 - c3, 0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam4.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam4.st
new file mode 100644
index 0000000..14b0052
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam4.st
@@ -0,0 +1,19 @@
+domain: "[M] -> { S2[i0, i1, i2] : i0 >= 1 and i0 <= -1 + M and i1 >= 0 and i2 >= 1 + i1 and i2 <= -1 + M; S1[i0, i1, i2] : i0 >= 1 and i0 <= -1 + M and i1 >= 0 and i2 >= 0 and i2 <= -1 + M - i1 }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i0 + i1 + i2)]; S2[i0, i1, i2] -> [(i0 + i2)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      schedule: "[M] -> [{ S1[i0, i1, i2] -> [(-i2)]; S2[i0, i1, i2] -> [(i1 - i2)] }]"
+      options: "[M] -> { separate[i0] }"
+      child:
+        sequence:
+        - filter: "[M] -> { S1[i0, i1, i2] }"
+          child:
+            schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i2)] }]"
+            options: "[M] -> { separate[i0] }"
+        - filter: "[M] -> { S2[i0, i1, i2] }"
+          child:
+            schedule: "[M] -> [{ S2[i0, i1, i2] -> [(i2)] }]"
+            options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam5.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam5.c
new file mode 100644
index 0000000..05cbb74
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam5.c
@@ -0,0 +1,11 @@
+{
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S1(c0, c1);
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S2(c0, c1);
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S3(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam5.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam5.st
new file mode 100644
index 0000000..5684455
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam5.st
@@ -0,0 +1,26 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M; S3[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    sequence:
+    - filter: "[M] -> { S1[i0, i1] }"
+      child:
+        schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
+    - filter: "[M] -> { S2[i0, i1] }"
+      child:
+        schedule: "[M] -> [{ S2[i0, i1] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
+    - filter: "[M] -> { S3[i0, i1] }"
+      child:
+        schedule: "[M] -> [{ S3[i0, i1] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S3[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam6.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam6.c
new file mode 100644
index 0000000..39e4538
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam6.c
@@ -0,0 +1,8 @@
+{
+  for (int c0 = 0; c0 <= M; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S1(c0, c1);
+  for (int c0 = 0; c0 <= M; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S2(c1, c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam6.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam6.st
new file mode 100644
index 0000000..3119ef1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-lim-lam6.st
@@ -0,0 +1,19 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 0 and i0 <= M and i1 >= 1 and i1 <= M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 0 and i1 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    sequence:
+    - filter: "[M] -> { S1[i0, i1] }"
+      child:
+        schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
+    - filter: "[M] -> { S2[i0, i1] }"
+      child:
+        schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S2[i0, i1] -> [(i0)] }]"
+          options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-liu-zhuge1.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-liu-zhuge1.c
new file mode 100644
index 0000000..84f6a25
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-liu-zhuge1.c
@@ -0,0 +1,19 @@
+if (M >= 0 && N >= 0)
+  for (int c0 = -4; c0 <= 3 * M + N; c0 += 1) {
+    if (c0 >= 3 * M) {
+      S2(M, -3 * M + c0);
+    } else if (3 * M >= c0 + 4 && (c0 + 1) % 3 == 0) {
+      S1((c0 + 4) / 3, 0);
+    }
+    for (int c1 = max(-3 * M + c0 + 3, (c0 + 6) % 3); c1 <= min(N - 1, c0); c1 += 3) {
+      S2((c0 - c1) / 3, c1);
+      S1(((c0 - c1) / 3) + 1, c1 + 1);
+    }
+    if (3 * M + N >= c0 + 3 && c0 >= N && (N - c0) % 3 == 0) {
+      S2((-N + c0) / 3, N);
+    } else if (N >= c0 + 4 && c0 >= -3) {
+      S1(0, c0 + 4);
+    }
+    for (int c1 = max(-3 * M + c0, (c0 + 6) % 3); c1 <= min(N, c0); c1 += 3)
+      S3((c0 - c1) / 3, c1);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-liu-zhuge1.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-liu-zhuge1.st
new file mode 100644
index 0000000..e915285
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-liu-zhuge1.st
@@ -0,0 +1,16 @@
+domain: "[M, N] -> { S3[i0, i1] : i0 >= 0 and i0 <= M and i1 >= 0 and i1 <= N; S1[i0, i1] : i0 >= 0 and i0 <= M and i1 >= 0 and i1 <= N; S2[i0, i1] : i0 >= 0 and i0 <= M and i1 >= 0 and i1 <= N }"
+child:
+  context: "[M, N] -> { [] }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1] -> [(-4 + 3i0 + i1)]; S2[i0, i1] -> [(3i0 + i1)]; S3[i0, i1] -> [(3i0 + i1)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S1[i0, i1]; S2[i0, i1] }"
+        child:
+          schedule: "[M, N] -> [{ S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
+      - filter: "[M, N] -> { S3[i0, i1] }"
+        child:
+          schedule: "[M, N] -> [{ S3[i0, i1] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner3.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner3.c
new file mode 100644
index 0000000..a164372
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner3.c
@@ -0,0 +1,4 @@
+for (int c0 = 1; c0 <= M; c0 += 1)
+  for (int c1 = 2; c1 <= M + c0; c1 += 1)
+    for (int c2 = max(1, -c0 + c1); c2 <= min(M, c1 - 1); c2 += 1)
+      S1(c0, c2, c1 - c2);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner3.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner3.st
new file mode 100644
index 0000000..90b561a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner3.st
@@ -0,0 +1,12 @@
+domain: "[M] -> { S1[i0, i1, i2] : i0 <= M and i1 >= 1 and i1 <= M and i2 >= 1 and i2 <= i0 }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i0)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i1 + i2)] }]"
+      options: "[M] -> { separate[i0] }"
+      child:
+        schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i1)] }]"
+        options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner4.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner4.c
new file mode 100644
index 0000000..cf9c764
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner4.c
@@ -0,0 +1,5 @@
+for (int c0 = 2; c0 <= 2 * M; c0 += 1)
+  for (int c1 = 1; c1 <= M; c1 += 1)
+    for (int c2 = 1; c2 <= M; c2 += 1)
+      for (int c3 = max(1, -M + c0); c3 <= min(M, c0 - 1); c3 += 1)
+        S1(c2, c1, c3, c0 - c3);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner4.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner4.st
new file mode 100644
index 0000000..516da7e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner4.st
@@ -0,0 +1,15 @@
+domain: "[M] -> { S1[i0, i1, i2, i3] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M and i2 >= 1 and i2 <= M and i3 >= 1 and i3 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i2 + i3)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i1)] }]"
+      options: "[M] -> { separate[i0] }"
+      child:
+        schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i2)] }]"
+          options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner5.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner5.c
new file mode 100644
index 0000000..6193503
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner5.c
@@ -0,0 +1,5 @@
+for (int c0 = 1; c0 <= M; c0 += 1)
+  for (int c1 = 1; c1 <= M; c1 += 1)
+    for (int c2 = 1; c2 <= M; c2 += 1)
+      for (int c3 = 1; c3 <= M; c3 += 1)
+        S1(c1, c2, c0, c3);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner5.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner5.st
new file mode 100644
index 0000000..691d924
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-loechner5.st
@@ -0,0 +1,15 @@
+domain: "[M] -> { S1[i0, i1, i2, i3] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M and i2 >= 1 and i2 <= M and i3 >= 1 and i3 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i2)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i0)] }]"
+      options: "[M] -> { separate[i0] }"
+      child:
+        schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i1)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S1[i0, i1, i2, i3] -> [(i3)] }]"
+          options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-long.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-long.c
new file mode 100644
index 0000000..e929c56
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-long.c
@@ -0,0 +1,14 @@
+for (int c0 = 1; c0 < O; c0 += 1) {
+  for (int c1 = Q; c1 < N; c1 += 1) {
+    for (int c2 = P; c2 < M; c2 += 1)
+      S1(c0, c1, c2);
+    for (int c2 = 1; c2 < M; c2 += 1)
+      S2(c0, c1, c2);
+  }
+  for (int c1 = 1; c1 < N; c1 += 1) {
+    for (int c2 = P; c2 < M; c2 += 1)
+      S3(c0, c1, c2);
+    for (int c2 = 1; c2 < M; c2 += 1)
+      S4(c0, c1, c2);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-long.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-long.st
new file mode 100644
index 0000000..5a292ab
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-long.st
@@ -0,0 +1,36 @@
+domain: "[M, N, O, P, Q, R, S, T, U] -> { S1[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= Q and i1 <= -1 + N and i2 >= P and i2 <= -1 + M; S3[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= P and i2 <= -1 + M; S4[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S2[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= Q and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M }"
+child:
+  context: "[M, N, O, P, Q, R, S, T, U] -> { [] : M >= 10 and N >= 10 and O >= 10 and P >= 1 and P <= 2 and Q >= 1 and Q <= 2 and R >= 1 and R <= 2 and S >= 0 and S <= 1 and T >= 0 and T <= 1 and U >= 0 and U <= 1 }"
+  child:
+    schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)]; S3[i0, i1, i2] -> [(i0)] }]"
+    options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N, O, P, Q, R, S, T, U] -> { S1[i0, i1, i2]; S2[i0, i1, i2] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i1)]; S1[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            sequence:
+            - filter: "[M, N, O, P, Q, R, S, T, U] -> { S1[i0, i1, i2] }"
+              child:
+                schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S1[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+            - filter: "[M, N, O, P, Q, R, S, T, U] -> { S2[i0, i1, i2] }"
+              child:
+                schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+      - filter: "[M, N, O, P, Q, R, S, T, U] -> { S3[i0, i1, i2]; S4[i0, i1, i2] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i1)]; S3[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            sequence:
+            - filter: "[M, N, O, P, Q, R, S, T, U] -> { S3[i0, i1, i2] }"
+              child:
+                schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S3[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+            - filter: "[M, N, O, P, Q, R, S, T, U] -> { S4[i0, i1, i2] }"
+              child:
+                schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-interp.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-interp.c
new file mode 100644
index 0000000..c5d7774
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-interp.c
@@ -0,0 +1,85 @@
+{
+  if (N >= 2)
+    for (int c0 = 1; c0 < O; c0 += 1) {
+      for (int c3 = 1; c3 <= M; c3 += 1)
+        S1(c0, 1, c3);
+      for (int c3 = 1; c3 < M; c3 += 1) {
+        S6(c0, 1, c3);
+        S7(c0, 1, c3);
+      }
+      if (N >= 3) {
+        for (int c3 = 1; c3 <= M; c3 += 1)
+          S3(c0, 1, c3);
+        for (int c3 = 1; c3 <= M; c3 += 1)
+          S1(c0, 2, c3);
+        for (int c3 = 1; c3 < M; c3 += 1) {
+          S6(c0, 2, c3);
+          S7(c0, 2, c3);
+        }
+        for (int c3 = 1; c3 < M; c3 += 1)
+          S11(c0, 1, c3);
+      } else {
+        for (int c3 = 1; c3 <= M; c3 += 1)
+          S3(c0, 1, c3);
+        for (int c3 = 1; c3 < M; c3 += 1)
+          S11(c0, 1, c3);
+      }
+      for (int c1 = 3; c1 < 2 * N - 4; c1 += 2) {
+        for (int c3 = 1; c3 < M; c3 += 1)
+          S10(c0, (c1 - 1) / 2, c3);
+        for (int c3 = 1; c3 <= M; c3 += 1)
+          S3(c0, (c1 + 1) / 2, c3);
+        for (int c3 = 1; c3 <= M; c3 += 1)
+          S1(c0, (c1 + 3) / 2, c3);
+        for (int c3 = 1; c3 < M; c3 += 1) {
+          S6(c0, (c1 + 3) / 2, c3);
+          S7(c0, (c1 + 3) / 2, c3);
+        }
+        for (int c3 = 1; c3 < M; c3 += 1)
+          S11(c0, (c1 + 1) / 2, c3);
+      }
+      if (N >= 3) {
+        for (int c3 = 1; c3 < M; c3 += 1)
+          S10(c0, N - 2, c3);
+        for (int c3 = 1; c3 <= M; c3 += 1)
+          S3(c0, N - 1, c3);
+        for (int c3 = 1; c3 < M; c3 += 1)
+          S11(c0, N - 1, c3);
+      }
+      for (int c3 = 1; c3 < M; c3 += 1)
+        S10(c0, N - 1, c3);
+    }
+  for (int c0 = 1; c0 < O; c0 += 1)
+    for (int c1 = 1; c1 < N; c1 += 1) {
+      for (int c3 = 1; c3 <= M; c3 += 1)
+        S2(c0, c1, c3);
+      for (int c3 = 1; c3 < M; c3 += 1)
+        S8(c0, c1, c3);
+      for (int c3 = 1; c3 < M; c3 += 1)
+        S9(c0, c1, c3);
+    }
+  for (int c0 = 1; c0 < O; c0 += 1)
+    for (int c1 = 1; c1 < N; c1 += 1)
+      for (int c2 = 1; c2 < M; c2 += 1)
+        S4(c0, c1, c2);
+  for (int c0 = 1; c0 < O; c0 += 1)
+    for (int c1 = 1; c1 < N; c1 += 1)
+      for (int c2 = 1; c2 < M; c2 += 1)
+        S5(c0, c1, c2);
+  for (int c0 = R; c0 < O; c0 += 1)
+    for (int c1 = Q; c1 < N; c1 += 1)
+      for (int c2 = P; c2 < M; c2 += 1)
+        S12(c0, c1, c2);
+  for (int c0 = R; c0 < O; c0 += 1)
+    for (int c1 = Q; c1 < N; c1 += 1)
+      for (int c2 = 1; c2 < M; c2 += 1)
+        S13(c0, c1, c2);
+  for (int c0 = R; c0 < O; c0 += 1)
+    for (int c1 = 1; c1 < N; c1 += 1)
+      for (int c2 = P; c2 < M; c2 += 1)
+        S14(c0, c1, c2);
+  for (int c0 = R; c0 < O; c0 += 1)
+    for (int c1 = 1; c1 < N; c1 += 1)
+      for (int c2 = 1; c2 < M; c2 += 1)
+        S15(c0, c1, c2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-interp.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-interp.st
new file mode 100644
index 0000000..2d63015
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-interp.st
@@ -0,0 +1,115 @@
+domain: "[M, N, O, P, Q, R, S, T, U] -> { S8[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S12[i0, i1, i2] : i0 >= R and i0 <= -1 + O and i1 >= Q and i1 <= -1 + N and i2 >= P and i2 <= -1 + M; S5[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S10[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S6[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S1[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= M; S3[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= M; S4[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S15[i0, i1, i2] : i0 >= R and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S11[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S2[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= M; S7[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S9[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S14[i0, i1, i2] : i0 >= R and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= P and i2 <= -1 + M; S13[i0, i1, i2] : i0 >= R and i0 <= -1 + O and i1 >= Q and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M }"
+child:
+  context: "[M, N, O, P, Q, R, S, T, U] -> { [] }"
+  child:
+    sequence:
+    - filter: "[M, N, O, P, Q, R, S, T, U] -> { S10[i0, i1, i2]; S6[i0, i1, i2]; S3[i0, i1, i2]; S1[i0, i1, i2]; S11[i0, i1, i2]; S7[i0, i1, i2] }"
+      child:
+        schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S11[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)]; S6[i0, i1, i2] -> [(i0)]; S10[i0, i1, i2] -> [(i0)]; S3[i0, i1, i2] -> [(i0)]; S7[i0, i1, i2] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S11[i0, i1, i2] -> [(2i1)]; S1[i0, i1, i2] -> [(-3 + 2i1)]; S6[i0, i1, i2] -> [(-2 + 2i1)]; S10[i0, i1, i2] -> [(1 + 2i1)]; S3[i0, i1, i2] -> [(-1 + 2i1)]; S7[i0, i1, i2] -> [(-2 + 2i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            sequence:
+            - filter: "[M, N, O, P, Q, R, S, T, U] -> { S10[i0, i1, i2] }"
+              child:
+                schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S10[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+            - filter: "[M, N, O, P, Q, R, S, T, U] -> { S3[i0, i1, i2] }"
+              child:
+                schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S3[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+            - filter: "[M, N, O, P, Q, R, S, T, U] -> { S6[i0, i1, i2]; S1[i0, i1, i2]; S7[i0, i1, i2] }"
+              child:
+                schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S1[i0, i1, i2] -> [(i2)]; S6[i0, i1, i2] -> [(i2)]; S7[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+                child:
+                  sequence:
+                  - filter: "[M, N, O, P, Q, R, S, T, U] -> { S6[i0, i1, i2]; S1[i0, i1, i2] }"
+                  - filter: "[M, N, O, P, Q, R, S, T, U] -> { S7[i0, i1, i2] }"
+            - filter: "[M, N, O, P, Q, R, S, T, U] -> { S11[i0, i1, i2] }"
+              child:
+                schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S11[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+    - filter: "[M, N, O, P, Q, R, S, T, U] -> { S2[i0, i1, i2]; S9[i0, i1, i2]; S8[i0, i1, i2] }"
+      child:
+        schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i0)]; S8[i0, i1, i2] -> [(i0)]; S9[i0, i1, i2] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(2i1)]; S8[i0, i1, i2] -> [(2i1)]; S9[i0, i1, i2] -> [(1 + 2i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            sequence:
+            - filter: "[M, N, O, P, Q, R, S, T, U] -> { S2[i0, i1, i2] }"
+              child:
+                schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+            - filter: "[M, N, O, P, Q, R, S, T, U] -> { S8[i0, i1, i2] }"
+              child:
+                schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S8[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+            - filter: "[M, N, O, P, Q, R, S, T, U] -> { S9[i0, i1, i2] }"
+              child:
+                schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S9[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+    - filter: "[M, N, O, P, Q, R, S, T, U] -> { S4[i0, i1, i2] }"
+      child:
+        schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+    - filter: "[M, N, O, P, Q, R, S, T, U] -> { S5[i0, i1, i2] }"
+      child:
+        schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S5[i0, i1, i2] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S5[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S5[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+    - filter: "[M, N, O, P, Q, R, S, T, U] -> { S12[i0, i1, i2] }"
+      child:
+        schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S12[i0, i1, i2] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S12[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S12[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+    - filter: "[M, N, O, P, Q, R, S, T, U] -> { S13[i0, i1, i2] }"
+      child:
+        schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S13[i0, i1, i2] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S13[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S13[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+    - filter: "[M, N, O, P, Q, R, S, T, U] -> { S14[i0, i1, i2] }"
+      child:
+        schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S14[i0, i1, i2] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S14[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S14[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+    - filter: "[M, N, O, P, Q, R, S, T, U] -> { S15[i0, i1, i2] }"
+      child:
+        schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S15[i0, i1, i2] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S15[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S15[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-interp2.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-interp2.c
new file mode 100644
index 0000000..48c5dfd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-interp2.c
@@ -0,0 +1,18 @@
+{
+  for (int c0 = 1; c0 < O; c0 += 1)
+    for (int c1 = Q; c1 < N; c1 += 1)
+      for (int c2 = P; c2 < M; c2 += 1)
+        S1(c0, c1, c2);
+  for (int c0 = 1; c0 < O; c0 += 1)
+    for (int c1 = Q; c1 < N; c1 += 1)
+      for (int c2 = 1; c2 < M; c2 += 1)
+        S2(c0, c1, c2);
+  for (int c0 = 1; c0 < O; c0 += 1)
+    for (int c1 = 1; c1 < N; c1 += 1)
+      for (int c2 = P; c2 < M; c2 += 1)
+        S3(c0, c1, c2);
+  for (int c0 = 1; c0 < O; c0 += 1)
+    for (int c1 = 1; c1 < N; c1 += 1)
+      for (int c2 = 1; c2 < M; c2 += 1)
+        S4(c0, c1, c2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-interp2.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-interp2.st
new file mode 100644
index 0000000..a2ea2b3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-interp2.st
@@ -0,0 +1,45 @@
+domain: "[M, N, O, P, Q, R, S, T, U] -> { S1[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= Q and i1 <= -1 + N and i2 >= P and i2 <= -1 + M; S3[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= P and i2 <= -1 + M; S4[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= 1 and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M; S2[i0, i1, i2] : i0 >= 1 and i0 <= -1 + O and i1 >= Q and i1 <= -1 + N and i2 >= 1 and i2 <= -1 + M }"
+child:
+  context: "[M, N, O, P, Q, R, S, T, U] -> { [] }"
+  child:
+    sequence:
+    - filter: "[M, N, O, P, Q, R, S, T, U] -> { S1[i0, i1, i2] }"
+      child:
+        schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S1[i0, i1, i2] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S1[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S1[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+    - filter: "[M, N, O, P, Q, R, S, T, U] -> { S2[i0, i1, i2] }"
+      child:
+        schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S2[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+    - filter: "[M, N, O, P, Q, R, S, T, U] -> { S3[i0, i1, i2] }"
+      child:
+        schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S3[i0, i1, i2] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S3[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S3[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+    - filter: "[M, N, O, P, Q, R, S, T, U] -> { S4[i0, i1, i2] }"
+      child:
+        schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+        child:
+          schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
+          child:
+            schedule: "[M, N, O, P, Q, R, S, T, U] -> [{ S4[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O, P, Q, R, S, T, U] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-psinv.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-psinv.c
new file mode 100644
index 0000000..cfb4045
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-psinv.c
@@ -0,0 +1,9 @@
+for (int c0 = 2; c0 < O; c0 += 1)
+  for (int c1 = 3; c1 < 2 * N - 2; c1 += 2) {
+    for (int c3 = 1; c3 <= M; c3 += 1) {
+      S1(c0, (c1 + 1) / 2, c3);
+      S2(c0, (c1 + 1) / 2, c3);
+    }
+    for (int c3 = 2; c3 < M; c3 += 1)
+      S3(c0, (c1 + 1) / 2, c3);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-psinv.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-psinv.st
new file mode 100644
index 0000000..c64638b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-psinv.st
@@ -0,0 +1,23 @@
+domain: "[M, N, O] -> { S3[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + M; S2[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 1 and i2 <= M; S1[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 1 and i2 <= M }"
+child:
+  context: "[M, N, O] -> { [] }"
+  child:
+    schedule: "[M, N, O] -> [{ S3[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)] }]"
+    options: "[M, N, O] -> { separate[i0] }"
+    child:
+      schedule: "[M, N, O] -> [{ S3[i0, i1, i2] -> [(2i1)]; S2[i0, i1, i2] -> [(-1 + 2i1)]; S1[i0, i1, i2] -> [(-1 + 2i1)] }]"
+      options: "[M, N, O] -> { separate[i0] }"
+      child:
+        sequence:
+        - filter: "[M, N, O] -> { S2[i0, i1, i2]; S1[i0, i1, i2] }"
+          child:
+            schedule: "[M, N, O] -> [{ S2[i0, i1, i2] -> [(i2)]; S1[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O] -> { separate[i0] }"
+            child:
+              sequence:
+              - filter: "[M, N, O] -> { S1[i0, i1, i2] }"
+              - filter: "[M, N, O] -> { S2[i0, i1, i2] }"
+        - filter: "[M, N, O] -> { S3[i0, i1, i2] }"
+          child:
+            schedule: "[M, N, O] -> [{ S3[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-resid.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-resid.c
new file mode 100644
index 0000000..cfb4045
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-resid.c
@@ -0,0 +1,9 @@
+for (int c0 = 2; c0 < O; c0 += 1)
+  for (int c1 = 3; c1 < 2 * N - 2; c1 += 2) {
+    for (int c3 = 1; c3 <= M; c3 += 1) {
+      S1(c0, (c1 + 1) / 2, c3);
+      S2(c0, (c1 + 1) / 2, c3);
+    }
+    for (int c3 = 2; c3 < M; c3 += 1)
+      S3(c0, (c1 + 1) / 2, c3);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-resid.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-resid.st
new file mode 100644
index 0000000..c64638b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-resid.st
@@ -0,0 +1,23 @@
+domain: "[M, N, O] -> { S3[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + M; S2[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 1 and i2 <= M; S1[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 1 and i2 <= M }"
+child:
+  context: "[M, N, O] -> { [] }"
+  child:
+    schedule: "[M, N, O] -> [{ S3[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)] }]"
+    options: "[M, N, O] -> { separate[i0] }"
+    child:
+      schedule: "[M, N, O] -> [{ S3[i0, i1, i2] -> [(2i1)]; S2[i0, i1, i2] -> [(-1 + 2i1)]; S1[i0, i1, i2] -> [(-1 + 2i1)] }]"
+      options: "[M, N, O] -> { separate[i0] }"
+      child:
+        sequence:
+        - filter: "[M, N, O] -> { S2[i0, i1, i2]; S1[i0, i1, i2] }"
+          child:
+            schedule: "[M, N, O] -> [{ S2[i0, i1, i2] -> [(i2)]; S1[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O] -> { separate[i0] }"
+            child:
+              sequence:
+              - filter: "[M, N, O] -> { S1[i0, i1, i2] }"
+              - filter: "[M, N, O] -> { S2[i0, i1, i2] }"
+        - filter: "[M, N, O] -> { S3[i0, i1, i2] }"
+          child:
+            schedule: "[M, N, O] -> [{ S3[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-rprj3.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-rprj3.c
new file mode 100644
index 0000000..e73ba5d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-rprj3.c
@@ -0,0 +1,35 @@
+if (M >= 2 && N >= 3)
+  for (int c0 = 2; c0 < O; c0 += 1) {
+    for (int c2 = 2; c2 <= M; c2 += 1)
+      S1(c0, 2, c2);
+    for (int c1 = 3; c1 < N; c1 += 1) {
+      for (int c2 = 2; c2 <= M; c2 += 1)
+        S2(c0, c1 - 1, c2);
+      if (M >= 3)
+        S4(c0, c1 - 1, 2);
+      for (int c2 = 2; c2 < M - 1; c2 += 1) {
+        S3(c0, c1 - 1, c2);
+        S5(c0, c1 - 1, c2);
+        S4(c0, c1 - 1, c2 + 1);
+      }
+      if (M >= 3) {
+        S3(c0, c1 - 1, M - 1);
+        S5(c0, c1 - 1, M - 1);
+      }
+      for (int c2 = 2; c2 <= M; c2 += 1)
+        S1(c0, c1, c2);
+    }
+    for (int c2 = 2; c2 <= M; c2 += 1)
+      S2(c0, N - 1, c2);
+    if (M >= 3)
+      S4(c0, N - 1, 2);
+    for (int c2 = 2; c2 < M - 1; c2 += 1) {
+      S3(c0, N - 1, c2);
+      S5(c0, N - 1, c2);
+      S4(c0, N - 1, c2 + 1);
+    }
+    if (M >= 3) {
+      S3(c0, N - 1, M - 1);
+      S5(c0, N - 1, M - 1);
+    }
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-rprj3.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-rprj3.st
new file mode 100644
index 0000000..d330a83
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-mg-rprj3.st
@@ -0,0 +1,28 @@
+domain: "[M, N, O, P, Q, R] -> { S2[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= M; S4[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + M; S1[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= M; S5[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + M; S3[i0, i1, i2] : i0 >= 2 and i0 <= -1 + O and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + M }"
+child:
+  context: "[M, N, O, P, Q, R] -> { [] }"
+  child:
+    schedule: "[M, N, O, P, Q, R] -> [{ S5[i0, i1, i2] -> [(i0)]; S3[i0, i1, i2] -> [(i0)]; S4[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)] }]"
+    options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+    child:
+      schedule: "[M, N, O, P, Q, R] -> [{ S5[i0, i1, i2] -> [(1 + i1)]; S3[i0, i1, i2] -> [(1 + i1)]; S4[i0, i1, i2] -> [(1 + i1)]; S1[i0, i1, i2] -> [(i1)]; S2[i0, i1, i2] -> [(1 + i1)] }]"
+      options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+      child:
+        sequence:
+        - filter: "[M, N, O, P, Q, R] -> { S2[i0, i1, i2] }"
+          child:
+            schedule: "[M, N, O, P, Q, R] -> [{ S2[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+        - filter: "[M, N, O, P, Q, R] -> { S4[i0, i1, i2]; S5[i0, i1, i2]; S3[i0, i1, i2] }"
+          child:
+            schedule: "[M, N, O, P, Q, R] -> [{ S5[i0, i1, i2] -> [(i2)]; S3[i0, i1, i2] -> [(i2)]; S4[i0, i1, i2] -> [(-1 + i2)] }]"
+            options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+            child:
+              sequence:
+              - filter: "[M, N, O, P, Q, R] -> { S3[i0, i1, i2] }"
+              - filter: "[M, N, O, P, Q, R] -> { S5[i0, i1, i2] }"
+              - filter: "[M, N, O, P, Q, R] -> { S4[i0, i1, i2] }"
+        - filter: "[M, N, O, P, Q, R] -> { S1[i0, i1, i2] }"
+          child:
+            schedule: "[M, N, O, P, Q, R] -> [{ S1[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N, O, P, Q, R] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali1.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali1.c
new file mode 100644
index 0000000..43c6ef0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali1.c
@@ -0,0 +1,7 @@
+for (int c0 = 1; c0 <= M; c0 += 1)
+  for (int c1 = 1; c1 < 2 * N; c1 += 1) {
+    for (int c2 = max(1, -N + c1); c2 < (c1 + 1) / 2; c2 += 1)
+      S1(c0, c1 - c2, c2);
+    if ((c1 + 1) % 2 == 0)
+      S2(c0, (c1 + 1) / 2);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali1.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali1.st
new file mode 100644
index 0000000..4ab2a65
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali1.st
@@ -0,0 +1,16 @@
+domain: "[M, N] -> { S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= N; S1[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 <= N and i2 >= 1 and i2 <= -1 + i1 }"
+child:
+  context: "[M, N] -> { [] }"
+  child:
+    schedule: "[M, N] -> [{ S2[i0, i1] -> [(i0)]; S1[i0, i1, i2] -> [(i0)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      schedule: "[M, N] -> [{ S2[i0, i1] -> [(-1 + 2i1)]; S1[i0, i1, i2] -> [(i1 + i2)] }]"
+      options: "[M, N] -> { separate[i0] }"
+      child:
+        sequence:
+        - filter: "[M, N] -> { S1[i0, i1, i2] }"
+          child:
+            schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N] -> { separate[i0] }"
+        - filter: "[M, N] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali2.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali2.c
new file mode 100644
index 0000000..195f15b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali2.c
@@ -0,0 +1,8 @@
+{
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S1(c0, c1);
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S2(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali2.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali2.st
new file mode 100644
index 0000000..ff76034
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali2.st
@@ -0,0 +1,19 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    sequence:
+    - filter: "[M] -> { S1[i0, i1] }"
+      child:
+        schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
+    - filter: "[M] -> { S2[i0, i1] }"
+      child:
+        schedule: "[M] -> [{ S2[i0, i1] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali3.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali3.c
new file mode 100644
index 0000000..eede142
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali3.c
@@ -0,0 +1,9 @@
+{
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S1(c0, c1);
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      for (int c2 = 1; c2 <= M; c2 += 1)
+        S2(c0, c1, c2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali3.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali3.st
new file mode 100644
index 0000000..c3065a1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali3.st
@@ -0,0 +1,22 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M; S2[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M and i2 >= 1 and i2 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    sequence:
+    - filter: "[M] -> { S1[i0, i1] }"
+      child:
+        schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
+    - filter: "[M] -> { S2[i0, i1, i2] }"
+      child:
+        schedule: "[M] -> [{ S2[i0, i1, i2] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S2[i0, i1, i2] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
+          child:
+            schedule: "[M] -> [{ S2[i0, i1, i2] -> [(i2)] }]"
+            options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali4.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali4.c
new file mode 100644
index 0000000..195f15b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali4.c
@@ -0,0 +1,8 @@
+{
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S1(c0, c1);
+  for (int c0 = 1; c0 <= M; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S2(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali4.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali4.st
new file mode 100644
index 0000000..0d724e9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali4.st
@@ -0,0 +1,19 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M; S2[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M }"
+child:
+  context: "[M] -> { [] : M >= 2 }"
+  child:
+    sequence:
+    - filter: "[M] -> { S1[i0, i1] }"
+      child:
+        schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S1[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
+    - filter: "[M] -> { S2[i0, i1] }"
+      child:
+        schedule: "[M] -> [{ S2[i0, i1] -> [(i0)] }]"
+        options: "[M] -> { separate[i0] }"
+        child:
+          schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali5.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali5.c
new file mode 100644
index 0000000..0e9bcf4
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali5.c
@@ -0,0 +1,10 @@
+for (int c0 = 3; c0 < 2 * M; c0 += 1) {
+  for (int c1 = c0 / 2 + 2; c1 <= M; c1 += 1)
+    for (int c3 = c0 / 2 + 1; c3 < min(c0, c1); c3 += 1)
+      S1(c3, c0 - c3, c1);
+  for (int c1 = max(1, -M + c0); c1 < (c0 + 1) / 2; c1 += 1)
+    S2(c0 - c1, c1);
+  for (int c1 = c0 / 2 + 2; c1 <= M; c1 += 1)
+    for (int c3 = c0 / 2 + 1; c3 < min(c0, c1); c3 += 1)
+      S3(c3, c0 - c3, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali5.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali5.st
new file mode 100644
index 0000000..d83eb55
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali5.st
@@ -0,0 +1,26 @@
+domain: "[M] -> { S3[i0, i1, i2] : i1 >= 1 and i1 <= -1 + i0 and i2 >= 1 + i0 and i2 <= M; S2[i0, i1] : i0 <= M and i1 >= 1 and i1 <= -1 + i0; S1[i0, i1, i2] : i1 >= 1 and i1 <= -1 + i0 and i2 >= 1 + i0 and i2 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i0 + i1)]; S3[i0, i1, i2] -> [(i0 + i1)]; S2[i0, i1] -> [(i0 + i1)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S1[i0, i1, i2] }"
+        child:
+          schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i2)] }]"
+          options: "[M] -> { separate[i0] }"
+          child:
+            schedule: "[M] -> [{ S1[i0, i1, i2] -> [(i2)] }]"
+            options: "[M] -> { separate[i0] }"
+      - filter: "[M] -> { S2[i0, i1] }"
+        child:
+          schedule: "[M] -> [{ S2[i0, i1] -> [(i1)] }]"
+          options: "[M] -> { separate[i0] }"
+      - filter: "[M] -> { S3[i0, i1, i2] }"
+        child:
+          schedule: "[M] -> [{ S3[i0, i1, i2] -> [(i2)] }]"
+          options: "[M] -> { separate[i0] }"
+          child:
+            schedule: "[M] -> [{ S3[i0, i1, i2] -> [(i2)] }]"
+            options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali6.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali6.c
new file mode 100644
index 0000000..7253575
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali6.c
@@ -0,0 +1,8 @@
+for (int c0 = 1; c0 <= M; c0 += 1) {
+  for (int c2 = 2; c2 < N; c2 += 1)
+    for (int c3 = 2; c3 < N; c3 += 1)
+      S1(c0, c2, c3);
+  for (int c2 = 2; c2 < N; c2 += 1)
+    for (int c3 = 2; c3 < N; c3 += 1)
+      S2(c0, c2, c3);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali6.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali6.st
new file mode 100644
index 0000000..3cf78bf
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-pingali6.st
@@ -0,0 +1,22 @@
+domain: "[M, N] -> { S2[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + N; S1[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 2 and i1 <= -1 + N and i2 >= 2 and i2 <= -1 + N }"
+child:
+  context: "[M, N] -> { [] : M >= 1 and N >= 1 }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(2i0)]; S2[i0, i1, i2] -> [(1 + 2i0)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S1[i0, i1, i2] }"
+        child:
+          schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
+          child:
+            schedule: "[M, N] -> [{ S1[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N] -> { separate[i0] }"
+      - filter: "[M, N] -> { S2[i0, i1, i2] }"
+        child:
+          schedule: "[M, N] -> [{ S2[i0, i1, i2] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
+          child:
+            schedule: "[M, N] -> [{ S2[i0, i1, i2] -> [(i2)] }]"
+            options: "[M, N] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-stride.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-stride.c
new file mode 100644
index 0000000..6a970d4
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-stride.c
@@ -0,0 +1,2 @@
+for (int c0 = 2; c0 <= M; c0 += 7)
+  S1(c0, (c0 - 2) / 7);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-stride.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-stride.st
new file mode 100644
index 0000000..135c90c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-stride.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S1[i0, i1] : 7i1 = -2 + i0 and i0 >= 2 and i0 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-stride2.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-stride2.c
new file mode 100644
index 0000000..6a970d4
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-stride2.c
@@ -0,0 +1,2 @@
+for (int c0 = 2; c0 <= M; c0 += 7)
+  S1(c0, (c0 - 2) / 7);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-stride2.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-stride2.st
new file mode 100644
index 0000000..0600029
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-stride2.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S1[i0, i1] : 7i1 = -2 + i0 and i0 >= 0 and i0 <= M }"
+child:
+  context: "[M] -> { [] }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-tang-xue1.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-tang-xue1.c
new file mode 100644
index 0000000..2a0f875
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-tang-xue1.c
@@ -0,0 +1,5 @@
+for (int c0 = 0; c0 <= 9; c0 += 2)
+  for (int c1 = 0; c1 <= min(4, c0 + 3); c1 += 2)
+    for (int c2 = max(1, c0); c2 <= min(c0 + 1, c0 - c1 + 4); c2 += 1)
+      for (int c3 = max(1, -c0 + c1 + c2); c3 <= min(4, -c0 + c1 + c2 + 1); c3 += 1)
+        S1(c0 / 2, (-c0 + c1) / 2, -c0 + c2, -c1 + c3);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-tang-xue1.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-tang-xue1.st
new file mode 100644
index 0000000..89d8b72
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-tang-xue1.st
@@ -0,0 +1,15 @@
+domain: "{ S1[i0, i1, i2, i3] : i3 <= 4 - 2i0 - 2i1 and i3 >= i2 and i2 <= 9 - 2i0 and i2 >= 0 and i2 >= 1 - 2i0 and i3 <= 1 + i2 and i2 <= 1 and i3 >= 1 - 2i0 - 2i1 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0, i1, i2, i3] -> [(2i0)] }]"
+    options: "{ separate[i0] }"
+    child:
+      schedule: "[{ S1[i0, i1, i2, i3] -> [(2i0 + 2i1)] }]"
+      options: "{ separate[i0] }"
+      child:
+        schedule: "[{ S1[i0, i1, i2, i3] -> [(2i0 + i2)] }]"
+        options: "{ separate[i0] }"
+        child:
+          schedule: "[{ S1[i0, i1, i2, i3] -> [(2i0 + 2i1 + i3)] }]"
+          options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-two.c b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-two.c
new file mode 100644
index 0000000..3946c42
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-two.c
@@ -0,0 +1 @@
+S1(1, 1, 5);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-two.st b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-two.st
new file mode 100644
index 0000000..c780ca2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-two.st
@@ -0,0 +1,6 @@
+domain: "{ S1[i0, i1, i2] : 2i1 = 3 - i0 and 2i2 = 9 + i0 and i0 >= 0 and i0 <= 1 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i0, i1, i2] -> [(i0)] }, { S1[i0, i1, i2] -> [(i1)] }, { S1[i0, i1, i2] -> [(i2)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/singleton.c b/final/lib/External/isl/test_inputs/codegen/cloog/singleton.c
new file mode 100644
index 0000000..0023bc6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/singleton.c
@@ -0,0 +1,4 @@
+{
+  S2();
+  S1();
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/singleton.st b/final/lib/External/isl/test_inputs/codegen/cloog/singleton.st
new file mode 100644
index 0000000..a38487b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/singleton.st
@@ -0,0 +1,7 @@
+domain: "{ S1[]; S2[] }"
+child:
+  context: "{ [] }"
+  child:
+    sequence:
+    - filter: "{ S2[] }"
+    - filter: "{ S1[] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/sor1d.c b/final/lib/External/isl/test_inputs/codegen/cloog/sor1d.c
new file mode 100644
index 0000000..92c6b33
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/sor1d.c
@@ -0,0 +1,13 @@
+if (M >= 1 && N >= 3)
+  for (int c0 = -1; c0 <= (3 * M + N - 5) / 100; c0 += 1) {
+    for (int c1 = max(max(0, c0 - (2 * M + N + 95) / 100 + 1), floord(-N + 100 * c0 + 106, 300)); c1 <= min(min(c0, M / 100), (c0 + 1) / 3); c1 += 1)
+      for (int c2 = max(200 * c1 - 3, 100 * c0 - 100 * c1); c2 <= min(min(2 * M + N - 5, 100 * c0 - 100 * c1 + 99), N + 200 * c1 + 193); c2 += 1) {
+        if (c1 >= 1 && N + 200 * c1 >= c2 + 7)
+          S3(c0 - c1, c1 - 1, c1, 100 * c1 - 1, -200 * c1 + c2 + 6);
+        for (int c3 = max(max(1, 100 * c1), -N + (N + c2) / 2 + 3); c3 <= min(min(M, 100 * c1 + 99), c2 / 2 + 1); c3 += 1)
+          S1(c0 - c1, c1, c3, c2 - 2 * c3 + 4);
+        if (M >= 100 * c1 + 100 && c2 >= 200 * c1 + 197)
+          S2(c0 - c1, c1, c1 + 1, 100 * c1 + 99, -200 * c1 + c2 - 194);
+      }
+    S4(c0);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/sor1d.st b/final/lib/External/isl/test_inputs/codegen/cloog/sor1d.st
new file mode 100644
index 0000000..bdde2e5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/sor1d.st
@@ -0,0 +1,24 @@
+domain: "[M, N] -> { S2[i0, i1, 1 + i1, 99 + 100i1, i4] : i4 >= 3 and i4 >= -193 - 200i1 and i4 >= -194 + 100i0 - 200i1 and 100i0 >= -284 - 3N and i4 <= -1 + N and i4 <= -201 + 2M + N - 200i1 and i4 <= -95 + 100i0 - 200i1 and 100i0 >= -94 - N and 50i0 >= -45 - N and 3N >= -134 - M and i1 >= 0 and N >= 4 and 200i1 >= -192 - N and 200i1 >= -193 - N + 100i0 and 100i0 <= -7 + 2M + N and 7N >= -463 - 2M and 100i1 <= -100 + M and i0 >= 0 and 200i1 <= -204 + 2M + N and 2i1 <= -1 + i0 and 5N >= -75 - 2M and N >= 8 - 2M and 50i0 <= -6 + M + N and 50i0 <= 89 + M + 2N and 100i0 <= -15 + 2M + 3N and M >= 2 and 100i1 <= -5 + M + N and 2N >= -39 - M and 200i1 <= 96 + N + 100i0 and 3N >= 16 - 2M and 100i1 >= -94 - N + 50i0 and N >= 6 - M and 100i1 >= -94 - N; S3[i0, i1, 1 + i1, 99 + 100i1, i4] : i4 >= 3 and i4 >= -193 - 200i1 and i4 >= -194 + 100i0 - 200i1 and 100i0 >= -284 - 3N and i4 <= -1 + N and i4 <= -201 + 2M + N - 200i1 and i4 <= -95 + 100i0 - 200i1 and 100i0 >= -94 - N and 50i0 >= -45 - N and 3N >= -134 - M and i1 >= 0 and N >= 4 and 200i1 >= -192 - N and 200i1 >= -193 - N + 100i0 and 100i0 <= -7 + 2M + N and 7N >= -463 - 2M and 100i1 <= -100 + M and i0 >= 0 and 200i1 <= -204 + 2M + N and 2i1 <= -1 + i0 and 5N >= -75 - 2M and N >= 8 - 2M and 50i0 <= -6 + M + N and 50i0 <= 89 + M + 2N and 100i0 <= -15 + 2M + 3N and M >= 2 and 100i1 <= -5 + M + N and 2N >= -39 - M and 200i1 <= 96 + N + 100i0 and 3N >= 16 - 2M and 100i1 >= -94 - N + 50i0 and N >= 6 - M and 100i1 >= -94 - N; S4[i0] : 200i0 >= -781 - 3N and 200i0 >= -391 - N and 50i0 >= -268 - N and 100i0 >= -392 - N and i0 >= -1 and 200i0 <= 377 + 6M + 5N and 100i0 <= 335 + 3M + 3N and 100i0 <= 190 + 3M + 2N and 200i0 <= -13 + 6M + 3N and 100i0 <= -5 + 3M + N and 3N >= -484 - 2M and N >= -95 - M and N >= -192 - 3M and 5N >= -873 - 3M and 2N >= -189 - 3M and 7N >= -1062 - 6M and 5N >= -771 - 6M and 4N >= -579 - 3M and N >= 3 and N >= 5 - 2M and M >= 1; S1[i0, i1, i2, i3] : i3 >= 4 + 100i0 - 2i2 and i3 >= 2 and i3 <= 103 + 100i0 - 2i2 and i3 <= -1 + N and i2 >= 1 and i2 >= 100i1 and 2i2 >= 5 - N + 100i0 and i2 <= M and i2 <= 99 + 100i1 and i2 <= 50 + 50i0 and i1 >= 0 and 200i1 >= -193 - N + 100i0 and 100i1 <= M and 2i1 <= 1 + i0 and i0 >= 0 and 100i0 <= -5 + 2M + N and N >= 3 and N >= -94 - 2M and M >= 1 }"
+child:
+  context: "[M, N] -> { [] : M >= 0 and N >= 0 }"
+  child:
+    schedule: "[M, N] -> [{ S2[i0, i1, i2, i3, i4] -> [(i0 + i1)]; S1[i0, i1, i2, i3] -> [(i0 + i1)]; S3[i0, i1, i2, i3, i4] -> [(1 + i0 + i1)]; S4[i0] -> [(i0)] }]"
+    options: "[M, N] -> { atomic[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S2[i0, i1, i2, i3, i4]; S3[i0, i1, i2, i3, i4]; S1[i0, i1, i2, i3] }"
+        child:
+          schedule: "[M, N] -> [{ S2[i0, i1, i2, i3, i4] -> [(i1)]; S1[i0, i1, i2, i3] -> [(i1)]; S3[i0, i1, i2, i3, i4] -> [(i2)] }, { S2[i0, i1, i2, i3, i4] -> [(-4 + 2i3 + i4)]; S1[i0, i1, i2, i3] -> [(-4 + 2i2 + i3)]; S3[i0, i1, i2, i3, i4] -> [(-4 + 2i3 + i4)] }, { S2[i0, i1, i2, i3, i4] -> [(i3)]; S1[i0, i1, i2, i3] -> [(i2)]; S3[i0, i1, i2, i3, i4] -> [(i3)] }]"
+          options: "[M, N] -> { atomic[i0] }"
+          child:
+            sequence:
+            - filter: "[M, N] -> { S3[i0, i1, i2, i3, i4] }"
+              child:
+                schedule: "[M, N] -> [{ S3[i0, i1, i2, i3, i4] -> [(i1)] }, { S3[i0, i1, i2, i3, i4] -> [(i4)] }]"
+                options: "[M, N] -> { atomic[i0] }"
+            - filter: "[M, N] -> { S1[i0, i1, i2, i3] }"
+            - filter: "[M, N] -> { S2[i0, i1, i2, i3, i4] }"
+              child:
+                schedule: "[M, N] -> [{ S2[i0, i1, i2, i3, i4] -> [(i2)] }, { S2[i0, i1, i2, i3, i4] -> [(i4)] }]"
+                options: "[M, N] -> { atomic[i0] }"
+      - filter: "[M, N] -> { S4[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/square+triangle-1-1-2-3.c b/final/lib/External/isl/test_inputs/codegen/cloog/square+triangle-1-1-2-3.c
new file mode 100644
index 0000000..316213f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/square+triangle-1-1-2-3.c
@@ -0,0 +1,9 @@
+for (int c0 = 1; c0 <= M; c0 += 1) {
+  S1(c0, 1);
+  for (int c1 = 2; c1 <= c0; c1 += 1) {
+    S1(c0, c1);
+    S2(c0, c1);
+  }
+  for (int c1 = c0 + 1; c1 <= M; c1 += 1)
+    S1(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/square+triangle-1-1-2-3.st b/final/lib/External/isl/test_inputs/codegen/cloog/square+triangle-1-1-2-3.st
new file mode 100644
index 0000000..bff294d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/square+triangle-1-1-2-3.st
@@ -0,0 +1,10 @@
+domain: "[M] -> { S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= M; S2[i0, i1] : i1 >= 2 and i1 <= i0 and i0 <= M }"
+child:
+  context: "[M] -> { [] : M >= 1 }"
+  child:
+    schedule: "[M] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "[M] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M] -> { S1[i0, i1] }"
+      - filter: "[M] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/stride.c b/final/lib/External/isl/test_inputs/codegen/cloog/stride.c
new file mode 100644
index 0000000..9bd4ddf
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/stride.c
@@ -0,0 +1,7 @@
+{
+  for (int c0 = 3; c0 <= 24; c0 += 3)
+    S2(c0, c0 / 3);
+  S1(25);
+  for (int c0 = 27; c0 <= 100; c0 += 3)
+    S2(c0, c0 / 3);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/stride.st b/final/lib/External/isl/test_inputs/codegen/cloog/stride.st
new file mode 100644
index 0000000..d83f979
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/stride.st
@@ -0,0 +1,6 @@
+domain: "{ S2[i0, i1] : 3i1 = i0 and i0 >= 3 and i0 <= 100; S1[25] }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S2[i0, i1] -> [(i0)]; S1[i0] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0] -> [(0)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/stride2.c b/final/lib/External/isl/test_inputs/codegen/cloog/stride2.c
new file mode 100644
index 0000000..c56af8e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/stride2.c
@@ -0,0 +1,8 @@
+{
+  for (int c0 = 3; c0 <= 26; c0 += 3)
+    S2(c0, c0 / 3);
+  S1(27);
+  S2(27, 9);
+  for (int c0 = 30; c0 <= 100; c0 += 3)
+    S2(c0, c0 / 3);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/stride2.st b/final/lib/External/isl/test_inputs/codegen/cloog/stride2.st
new file mode 100644
index 0000000..d2e3420
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/stride2.st
@@ -0,0 +1,6 @@
+domain: "{ S2[i0, i1] : 3i1 = i0 and i0 >= 3 and i0 <= 100; S1[27] }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S2[i0, i1] -> [(i0)]; S1[i0] -> [(i0)] }, { S2[i0, i1] -> [(i1)]; S1[i0] -> [(0)] }]"
+    options: "{ separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/stride3.c b/final/lib/External/isl/test_inputs/codegen/cloog/stride3.c
new file mode 100644
index 0000000..d145938
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/stride3.c
@@ -0,0 +1,2 @@
+for (int c0 = max(1, m); c0 <= n; c0 += 1)
+  S1(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/stride3.st b/final/lib/External/isl/test_inputs/codegen/cloog/stride3.st
new file mode 100644
index 0000000..f970d2c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/stride3.st
@@ -0,0 +1,6 @@
+domain: "[m, n] -> { S1[i] : i >= 1 and i <= n and i >= m }"
+child:
+  context: "[m, n] -> { [] }"
+  child:
+    schedule: "[m, n] -> [{ S1[i0] -> [(50i0)] }]"
+    options: "[m, n] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/stride4.c b/final/lib/External/isl/test_inputs/codegen/cloog/stride4.c
new file mode 100644
index 0000000..03908e6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/stride4.c
@@ -0,0 +1,3 @@
+if (t >= 0 && t <= 15)
+  for (int c0 = t; c0 <= 99; c0 += 16)
+    S1(c0, t);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/stride4.st b/final/lib/External/isl/test_inputs/codegen/cloog/stride4.st
new file mode 100644
index 0000000..9ffa62a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/stride4.st
@@ -0,0 +1,6 @@
+domain: "[t] -> { S1[i0, t] : exists (e0 = floor((t - i0)/16): 16e0 = t - i0 and i0 >= 0 and i0 <= 99 and t >= 0 and t <= 15) }"
+child:
+  context: "[t] -> { [] }"
+  child:
+    schedule: "[t] -> [{ S1[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)] }]"
+    options: "[t] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/swim.c b/final/lib/External/isl/test_inputs/codegen/cloog/swim.c
new file mode 100644
index 0000000..14f6514
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/swim.c
@@ -0,0 +1,159 @@
+if (M == 1) {
+  S1();
+  S2();
+  S3();
+  S4();
+  S5();
+  S6();
+  S7();
+  S8();
+  S9();
+  S10();
+  S11();
+  S12();
+  S13();
+  S14();
+  S15();
+  S16();
+  S17();
+  S18();
+  S19();
+  S20();
+  S21();
+  S22();
+  S23();
+  S24();
+  S25();
+  S26();
+  S27();
+  for (int c0 = 1; c0 <= N; c0 += 1) {
+    for (int c1 = 1; c1 <= N; c1 += 1) {
+      S28(c0, c1);
+      S29(c0, c1);
+      S30(c0, c1);
+    }
+    S31(c0);
+  }
+  S32();
+  S33();
+  S34();
+  if (O <= 1)
+    S35();
+  S36();
+  S37();
+  for (int c0 = 2; c0 <= P; c0 += 1) {
+    S38(c0);
+    S39(c0);
+    for (int c1 = 1; c1 <= Q; c1 += 1)
+      for (int c2 = 1; c2 <= R; c2 += 1) {
+        S40(c0, c1, c2);
+        S41(c0, c1, c2);
+        S42(c0, c1, c2);
+        S43(c0, c1, c2);
+      }
+    for (int c1 = 1; c1 <= Q; c1 += 1) {
+      S44(c0, c1);
+      S45(c0, c1);
+      S46(c0, c1);
+      S47(c0, c1);
+    }
+    for (int c1 = 1; c1 <= R; c1 += 1) {
+      S48(c0, c1);
+      S49(c0, c1);
+      S50(c0, c1);
+      S51(c0, c1);
+    }
+    S52(c0);
+    S53(c0);
+    S54(c0);
+    S55(c0);
+    S56(c0);
+    S57(c0);
+    S58(c0);
+    for (int c1 = 1; c1 <= Q; c1 += 1)
+      for (int c2 = 1; c2 <= R; c2 += 1) {
+        S59(c0, c1, c2);
+        S60(c0, c1, c2);
+        S61(c0, c1, c2);
+      }
+    for (int c1 = 1; c1 <= Q; c1 += 1) {
+      S62(c0, c1);
+      S63(c0, c1);
+      S64(c0, c1);
+    }
+    for (int c1 = 1; c1 <= R; c1 += 1) {
+      S65(c0, c1);
+      S66(c0, c1);
+      S67(c0, c1);
+    }
+    S68(c0);
+    S69(c0);
+    S70(c0);
+    S71(c0);
+    S72(c0);
+    S73(c0);
+    S74(c0);
+    S75(c0);
+    S76(c0);
+    S77(c0);
+    S78(c0);
+    S79(c0);
+    S80(c0);
+    S81(c0);
+    S82(c0);
+    S83(c0);
+    S84(c0);
+    S85(c0);
+    S86(c0);
+    S87(c0);
+    S88(c0);
+    S89(c0);
+    S90(c0);
+    S91(c0);
+    S92(c0);
+    S93(c0);
+    S94(c0);
+    for (int c1 = 1; c1 <= N; c1 += 1) {
+      for (int c2 = 1; c2 <= N; c2 += 1) {
+        S95(c0, c1, c2);
+        S96(c0, c1, c2);
+        S97(c0, c1, c2);
+      }
+      S98(c0, c1);
+    }
+    S99(c0);
+    S100(c0);
+    S101(c0);
+    for (int c1 = 1; c1 <= Q; c1 += 1)
+      for (int c2 = 1; c2 <= R; c2 += 1) {
+        S102(c0, c1, c2);
+        S103(c0, c1, c2);
+        S104(c0, c1, c2);
+        S105(c0, c1, c2);
+        S106(c0, c1, c2);
+        S107(c0, c1, c2);
+      }
+    for (int c1 = 1; c1 <= Q; c1 += 1) {
+      S108(c0, c1);
+      S109(c0, c1);
+      S110(c0, c1);
+      S111(c0, c1);
+      S112(c0, c1);
+      S113(c0, c1);
+    }
+    for (int c1 = 1; c1 <= R; c1 += 1) {
+      S114(c0, c1);
+      S115(c0, c1);
+      S116(c0, c1);
+      S117(c0, c1);
+      S118(c0, c1);
+      S119(c0, c1);
+    }
+    S120(c0);
+    S121(c0);
+    S122(c0);
+    S123(c0);
+    S124(c0);
+    S125(c0);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/swim.st b/final/lib/External/isl/test_inputs/codegen/cloog/swim.st
new file mode 100644
index 0000000..ff08bb1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/swim.st
@@ -0,0 +1,223 @@
+domain: "[M, N, O, P, Q, R] -> { S40[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S106[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S99[i0] : M = 1 and i0 >= 2 and i0 <= P; S83[i0] : M = 1 and i0 >= 2 and i0 <= P; S86[i0] : M = 1 and i0 >= 2 and i0 <= P; S56[i0] : M = 1 and i0 >= 2 and i0 <= P; S124[i0] : M = 1 and i0 >= 2 and i0 <= P; S66[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S46[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S64[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S22[] : M = 1; S15[] : M = 1; S30[i0, i1] : M = 1 and i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= N; S14[] : M = 1; S12[] : M = 1; S87[i0] : M = 1 and i0 >= 2 and i0 <= P; S110[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S73[i0] : M = 1 and i0 >= 2 and i0 <= P; S44[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S31[i0] : M = 1 and i0 >= 1 and i0 <= N; S118[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S8[] : M = 1; S125[i0] : M = 1 and i0 >= 2 and i0 <= P; S63[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S25[] : M = 1; S51[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S91[i0] : M = 1 and i0 >= 2 and i0 <= P; S84[i0] : M = 1 and i0 >= 2 and i0 <= P; S35[] : M = 1 and O <= 1; S97[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= N and i2 >= 1 and i2 <= N; S75[i0] : M = 1 and i0 >= 2 and i0 <= P; S19[] : M = 1; S50[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S114[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S13[] : M = 1; S72[i0] : M = 1 and i0 >= 2 and i0 <= P; S78[i0] : M = 1 and i0 >= 2 and i0 <= P; S39[i0] : M = 1 and i0 >= 2 and i0 <= P; S102[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S107[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S68[i0] : M = 1 and i0 >= 2 and i0 <= P; S32[] : M = 1; S41[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S69[i0] : M = 1 and i0 >= 2 and i0 <= P; S3[] : M = 1; S100[i0] : M = 1 and i0 >= 2 and i0 <= P; S11[] : M = 1; S76[i0] : M = 1 and i0 >= 2 and i0 <= P; S88[i0] : M = 1 and i0 >= 2 and i0 <= P; S49[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S45[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S10[] : M = 1; S80[i0] : M = 1 and i0 >= 2 and i0 <= P; S61[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S67[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S70[i0] : M = 1 and i0 >= 2 and i0 <= P; S29[i0, i1] : M = 1 and i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= N; S60[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S21[] : M = 1; S92[i0] : M = 1 and i0 >= 2 and i0 <= P; S47[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S24[] : M = 1; S16[] : M = 1; S105[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S18[] : M = 1; S48[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S5[] : M = 1; S113[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S7[] : M = 1; S38[i0] : M = 1 and i0 >= 2 and i0 <= P; S54[i0] : M = 1 and i0 >= 2 and i0 <= P; S109[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S23[] : M = 1; S82[i0] : M = 1 and i0 >= 2 and i0 <= P; S59[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S77[i0] : M = 1 and i0 >= 2 and i0 <= P; S101[i0] : M = 1 and i0 >= 2 and i0 <= P; S37[] : M = 1; S71[i0] : M = 1 and i0 >= 2 and i0 <= P; S121[i0] : M = 1 and i0 >= 2 and i0 <= P; S115[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S104[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S94[i0] : M = 1 and i0 >= 2 and i0 <= P; S6[] : M = 1; S43[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S1[] : M = 1; S98[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= N; S55[i0] : M = 1 and i0 >= 2 and i0 <= P; S58[i0] : M = 1 and i0 >= 2 and i0 <= P; S42[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S89[i0] : M = 1 and i0 >= 2 and i0 <= P; S53[i0] : M = 1 and i0 >= 2 and i0 <= P; S111[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S52[i0] : M = 1 and i0 >= 2 and i0 <= P; S85[i0] : M = 1 and i0 >= 2 and i0 <= P; S26[] : M = 1; S79[i0] : M = 1 and i0 >= 2 and i0 <= P; S81[i0] : M = 1 and i0 >= 2 and i0 <= P; S57[i0] : M = 1 and i0 >= 2 and i0 <= P; S4[] : M = 1; S123[i0] : M = 1 and i0 >= 2 and i0 <= P; S36[] : M = 1; S65[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S34[] : M = 1; S119[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S9[] : M = 1; S28[i0, i1] : M = 1 and i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= N; S20[] : M = 1; S117[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S112[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S103[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q and i2 >= 1 and i2 <= R; S17[] : M = 1; S96[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= N and i2 >= 1 and i2 <= N; S95[i0, i1, i2] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= N and i2 >= 1 and i2 <= N; S62[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S90[i0] : M = 1 and i0 >= 2 and i0 <= P; S120[i0] : M = 1 and i0 >= 2 and i0 <= P; S116[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= R; S108[i0, i1] : M = 1 and i0 >= 2 and i0 <= P and i1 >= 1 and i1 <= Q; S74[i0] : M = 1 and i0 >= 2 and i0 <= P; S93[i0] : M = 1 and i0 >= 2 and i0 <= P; S2[] : M = 1; S27[] : M = 1; S122[i0] : M = 1 and i0 >= 2 and i0 <= P; S33[] : M = 1 }"
+child:
+  context: "[M, N, O, P, Q, R] -> { [] }"
+  child:
+    sequence:
+    - filter: "[M, N, O, P, Q, R] -> { S1[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S2[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S3[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S4[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S5[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S6[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S7[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S8[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S9[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S10[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S11[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S12[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S13[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S14[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S15[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S16[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S17[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S18[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S19[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S20[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S21[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S22[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S23[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S24[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S25[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S26[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S27[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S30[i0, i1]; S28[i0, i1]; S31[i0]; S29[i0, i1] }"
+      child:
+        schedule: "[M, N, O, P, Q, R] -> [{ S31[i0] -> [(i0)]; S29[i0, i1] -> [(i0)]; S30[i0, i1] -> [(i0)]; S28[i0, i1] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+        child:
+          sequence:
+          - filter: "[M, N, O, P, Q, R] -> { S30[i0, i1]; S28[i0, i1]; S29[i0, i1] }"
+            child:
+              schedule: "[M, N, O, P, Q, R] -> [{ S29[i0, i1] -> [(i1)]; S30[i0, i1] -> [(i1)]; S28[i0, i1] -> [(i1)] }]"
+              options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+              child:
+                sequence:
+                - filter: "[M, N, O, P, Q, R] -> { S28[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S29[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S30[i0, i1] }"
+          - filter: "[M, N, O, P, Q, R] -> { S31[i0] }"
+    - filter: "[M, N, O, P, Q, R] -> { S32[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S33[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S34[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S35[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S36[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S37[] }"
+    - filter: "[M, N, O, P, Q, R] -> { S58[i0]; S116[i0, i1]; S120[i0]; S106[i0, i1, i2]; S102[i0, i1, i2]; S114[i0, i1]; S113[i0, i1]; S122[i0]; S83[i0]; S103[i0, i1, i2]; S71[i0]; S50[i0, i1]; S98[i0, i1]; S65[i0, i1]; S82[i0]; S109[i0, i1]; S51[i0, i1]; S60[i0, i1, i2]; S91[i0]; S78[i0]; S101[i0]; S123[i0]; S111[i0, i1]; S97[i0, i1, i2]; S67[i0, i1]; S117[i0, i1]; S88[i0]; S79[i0]; S46[i0, i1]; S56[i0]; S45[i0, i1]; S74[i0]; S49[i0, i1]; S75[i0]; S115[i0, i1]; S119[i0, i1]; S42[i0, i1, i2]; S57[i0]; S62[i0, i1]; S99[i0]; S107[i0, i1, i2]; S100[i0]; S104[i0, i1, i2]; S70[i0]; S89[i0]; S125[i0]; S44[i0, i1]; S93[i0]; S90[i0]; S84[i0]; S105[i0, i1, i2]; S95[i0, i1, i2]; S66[i0, i1]; S77[i0]; S38[i0]; S41[i0, i1, i2]; S92[i0]; S87[i0]; S47[i0, i1]; S108[i0, i1]; S54[i0]; S76[i0]; S112[i0, i1]; S80[i0]; S55[i0]; S39[i0]; S59[i0, i1, i2]; S121[i0]; S86[i0]; S110[i0, i1]; S48[i0, i1]; S68[i0]; S53[i0]; S72[i0]; S85[i0]; S52[i0]; S69[i0]; S61[i0, i1, i2]; S43[i0, i1, i2]; S124[i0]; S73[i0]; S81[i0]; S63[i0, i1]; S118[i0, i1]; S96[i0, i1, i2]; S40[i0, i1, i2]; S94[i0]; S64[i0, i1] }"
+      child:
+        schedule: "[M, N, O, P, Q, R] -> [{ S99[i0] -> [(i0)]; S97[i0, i1, i2] -> [(i0)]; S53[i0] -> [(i0)]; S101[i0] -> [(i0)]; S60[i0, i1, i2] -> [(i0)]; S40[i0, i1, i2] -> [(i0)]; S103[i0, i1, i2] -> [(i0)]; S55[i0] -> [(i0)]; S89[i0] -> [(i0)]; S56[i0] -> [(i0)]; S87[i0] -> [(i0)]; S115[i0, i1] -> [(i0)]; S123[i0] -> [(i0)]; S88[i0] -> [(i0)]; S70[i0] -> [(i0)]; S59[i0, i1, i2] -> [(i0)]; S52[i0] -> [(i0)]; S54[i0] -> [(i0)]; S63[i0, i1] -> [(i0)]; S92[i0] -> [(i0)]; S93[i0] -> [(i0)]; S119[i0, i1] -> [(i0)]; S76[i0] -> [(i0)]; S57[i0] -> [(i0)]; S44[i0, i1] -> [(i0)]; S79[i0] -> [(i0)]; S61[i0, i1, i2] -> [(i0)]; S69[i0] -> [(i0)]; S117[i0, i1] -> [(i0)]; S121[i0] -> [(i0)]; S84[i0] -> [(i0)]; S83[i0] -> [(i0)]; S43[i0, i1, i2] -> [(i0)]; S98[i0, i1] -> [(i0)]; S78[i0] -> [(i0)]; S114[i0, i1] -> [(i0)]; S66[i0, i1] -> [(i0)]; S77[i0] -> [(i0)]; S109[i0, i1] -> [(i0)]; S42[i0, i1, i2] -> [(i0)]; S58[i0] -> [(i0)]; S71[i0] -> [(i0)]; S68[i0] -> [(i0)]; S116[i0, i1] -> [(i0)]; S81[i0] -> [(i0)]; S125[i0] -> [(i0)]; S80[i0] -> [(i0)]; S73[i0] -> [(i0)]; S110[i0, i1] -> [(i0)]; S72[i0] -> [(i0)]; S51[i0, i1] -> [(i0)]; S122[i0] -> [(i0)]; S38[i0] -> [(i0)]; S39[i0] -> [(i0)]; S90[i0] -> [(i0)]; S113[i0, i1] -> [(i0)]; S46[i0, i1] -> [(i0)]; S47[i0, i1] -> [(i0)]; S96[i0, i1, i2] -> [(i0)]; S45[i0, i1] -> [(i0)]; S49[i0, i1] -> [(i0)]; S118[i0, i1] -> [(i0)]; S50[i0, i1] -> [(i0)]; S102[i0, i1, i2] -> [(i0)]; S112[i0, i1] -> [(i0)]; S86[i0] -> [(i0)]; S124[i0] -> [(i0)]; S41[i0, i1, i2] -> [(i0)]; S100[i0] -> [(i0)]; S104[i0, i1, i2] -> [(i0)]; S75[i0] -> [(i0)]; S62[i0, i1] -> [(i0)]; S85[i0] -> [(i0)]; S105[i0, i1, i2] -> [(i0)]; S82[i0] -> [(i0)]; S111[i0, i1] -> [(i0)]; S48[i0, i1] -> [(i0)]; S65[i0, i1] -> [(i0)]; S120[i0] -> [(i0)]; S107[i0, i1, i2] -> [(i0)]; S106[i0, i1, i2] -> [(i0)]; S95[i0, i1, i2] -> [(i0)]; S108[i0, i1] -> [(i0)]; S91[i0] -> [(i0)]; S67[i0, i1] -> [(i0)]; S74[i0] -> [(i0)]; S64[i0, i1] -> [(i0)]; S94[i0] -> [(i0)] }]"
+        options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+        child:
+          sequence:
+          - filter: "[M, N, O, P, Q, R] -> { S38[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S39[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S40[i0, i1, i2]; S41[i0, i1, i2]; S43[i0, i1, i2]; S42[i0, i1, i2] }"
+            child:
+              schedule: "[M, N, O, P, Q, R] -> [{ S43[i0, i1, i2] -> [(i1)]; S41[i0, i1, i2] -> [(i1)]; S40[i0, i1, i2] -> [(i1)]; S42[i0, i1, i2] -> [(i1)] }]"
+              options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+              child:
+                schedule: "[M, N, O, P, Q, R] -> [{ S43[i0, i1, i2] -> [(i2)]; S41[i0, i1, i2] -> [(i2)]; S40[i0, i1, i2] -> [(i2)]; S42[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+                child:
+                  sequence:
+                  - filter: "[M, N, O, P, Q, R] -> { S40[i0, i1, i2] }"
+                  - filter: "[M, N, O, P, Q, R] -> { S41[i0, i1, i2] }"
+                  - filter: "[M, N, O, P, Q, R] -> { S42[i0, i1, i2] }"
+                  - filter: "[M, N, O, P, Q, R] -> { S43[i0, i1, i2] }"
+          - filter: "[M, N, O, P, Q, R] -> { S46[i0, i1]; S45[i0, i1]; S44[i0, i1]; S47[i0, i1] }"
+            child:
+              schedule: "[M, N, O, P, Q, R] -> [{ S47[i0, i1] -> [(i1)]; S46[i0, i1] -> [(i1)]; S44[i0, i1] -> [(i1)]; S45[i0, i1] -> [(i1)] }]"
+              options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+              child:
+                sequence:
+                - filter: "[M, N, O, P, Q, R] -> { S44[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S45[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S46[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S47[i0, i1] }"
+          - filter: "[M, N, O, P, Q, R] -> { S51[i0, i1]; S49[i0, i1]; S50[i0, i1]; S48[i0, i1] }"
+            child:
+              schedule: "[M, N, O, P, Q, R] -> [{ S51[i0, i1] -> [(i1)]; S49[i0, i1] -> [(i1)]; S48[i0, i1] -> [(i1)]; S50[i0, i1] -> [(i1)] }]"
+              options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+              child:
+                sequence:
+                - filter: "[M, N, O, P, Q, R] -> { S48[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S49[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S50[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S51[i0, i1] }"
+          - filter: "[M, N, O, P, Q, R] -> { S52[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S53[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S54[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S55[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S56[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S57[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S58[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S60[i0, i1, i2]; S59[i0, i1, i2]; S61[i0, i1, i2] }"
+            child:
+              schedule: "[M, N, O, P, Q, R] -> [{ S61[i0, i1, i2] -> [(i1)]; S59[i0, i1, i2] -> [(i1)]; S60[i0, i1, i2] -> [(i1)] }]"
+              options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+              child:
+                schedule: "[M, N, O, P, Q, R] -> [{ S61[i0, i1, i2] -> [(i2)]; S59[i0, i1, i2] -> [(i2)]; S60[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+                child:
+                  sequence:
+                  - filter: "[M, N, O, P, Q, R] -> { S59[i0, i1, i2] }"
+                  - filter: "[M, N, O, P, Q, R] -> { S60[i0, i1, i2] }"
+                  - filter: "[M, N, O, P, Q, R] -> { S61[i0, i1, i2] }"
+          - filter: "[M, N, O, P, Q, R] -> { S62[i0, i1]; S63[i0, i1]; S64[i0, i1] }"
+            child:
+              schedule: "[M, N, O, P, Q, R] -> [{ S64[i0, i1] -> [(i1)]; S62[i0, i1] -> [(i1)]; S63[i0, i1] -> [(i1)] }]"
+              options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+              child:
+                sequence:
+                - filter: "[M, N, O, P, Q, R] -> { S62[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S63[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S64[i0, i1] }"
+          - filter: "[M, N, O, P, Q, R] -> { S65[i0, i1]; S66[i0, i1]; S67[i0, i1] }"
+            child:
+              schedule: "[M, N, O, P, Q, R] -> [{ S66[i0, i1] -> [(i1)]; S65[i0, i1] -> [(i1)]; S67[i0, i1] -> [(i1)] }]"
+              options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+              child:
+                sequence:
+                - filter: "[M, N, O, P, Q, R] -> { S65[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S66[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S67[i0, i1] }"
+          - filter: "[M, N, O, P, Q, R] -> { S68[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S69[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S70[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S71[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S72[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S73[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S74[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S75[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S76[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S77[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S78[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S79[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S80[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S81[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S82[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S83[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S84[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S85[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S86[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S87[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S88[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S89[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S90[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S91[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S92[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S93[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S94[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S96[i0, i1, i2]; S98[i0, i1]; S97[i0, i1, i2]; S95[i0, i1, i2] }"
+            child:
+              schedule: "[M, N, O, P, Q, R] -> [{ S98[i0, i1] -> [(i1)]; S95[i0, i1, i2] -> [(i1)]; S96[i0, i1, i2] -> [(i1)]; S97[i0, i1, i2] -> [(i1)] }]"
+              options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+              child:
+                sequence:
+                - filter: "[M, N, O, P, Q, R] -> { S96[i0, i1, i2]; S97[i0, i1, i2]; S95[i0, i1, i2] }"
+                  child:
+                    schedule: "[M, N, O, P, Q, R] -> [{ S95[i0, i1, i2] -> [(i2)]; S96[i0, i1, i2] -> [(i2)]; S97[i0, i1, i2] -> [(i2)] }]"
+                    options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+                    child:
+                      sequence:
+                      - filter: "[M, N, O, P, Q, R] -> { S95[i0, i1, i2] }"
+                      - filter: "[M, N, O, P, Q, R] -> { S96[i0, i1, i2] }"
+                      - filter: "[M, N, O, P, Q, R] -> { S97[i0, i1, i2] }"
+                - filter: "[M, N, O, P, Q, R] -> { S98[i0, i1] }"
+          - filter: "[M, N, O, P, Q, R] -> { S99[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S100[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S101[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S107[i0, i1, i2]; S105[i0, i1, i2]; S102[i0, i1, i2]; S104[i0, i1, i2]; S106[i0, i1, i2]; S103[i0, i1, i2] }"
+            child:
+              schedule: "[M, N, O, P, Q, R] -> [{ S102[i0, i1, i2] -> [(i1)]; S103[i0, i1, i2] -> [(i1)]; S104[i0, i1, i2] -> [(i1)]; S107[i0, i1, i2] -> [(i1)]; S106[i0, i1, i2] -> [(i1)]; S105[i0, i1, i2] -> [(i1)] }]"
+              options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+              child:
+                schedule: "[M, N, O, P, Q, R] -> [{ S102[i0, i1, i2] -> [(i2)]; S103[i0, i1, i2] -> [(i2)]; S104[i0, i1, i2] -> [(i2)]; S107[i0, i1, i2] -> [(i2)]; S106[i0, i1, i2] -> [(i2)]; S105[i0, i1, i2] -> [(i2)] }]"
+                options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+                child:
+                  sequence:
+                  - filter: "[M, N, O, P, Q, R] -> { S102[i0, i1, i2] }"
+                  - filter: "[M, N, O, P, Q, R] -> { S103[i0, i1, i2] }"
+                  - filter: "[M, N, O, P, Q, R] -> { S104[i0, i1, i2] }"
+                  - filter: "[M, N, O, P, Q, R] -> { S105[i0, i1, i2] }"
+                  - filter: "[M, N, O, P, Q, R] -> { S106[i0, i1, i2] }"
+                  - filter: "[M, N, O, P, Q, R] -> { S107[i0, i1, i2] }"
+          - filter: "[M, N, O, P, Q, R] -> { S113[i0, i1]; S112[i0, i1]; S108[i0, i1]; S111[i0, i1]; S110[i0, i1]; S109[i0, i1] }"
+            child:
+              schedule: "[M, N, O, P, Q, R] -> [{ S110[i0, i1] -> [(i1)]; S112[i0, i1] -> [(i1)]; S111[i0, i1] -> [(i1)]; S113[i0, i1] -> [(i1)]; S109[i0, i1] -> [(i1)]; S108[i0, i1] -> [(i1)] }]"
+              options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+              child:
+                sequence:
+                - filter: "[M, N, O, P, Q, R] -> { S108[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S109[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S110[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S111[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S112[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S113[i0, i1] }"
+          - filter: "[M, N, O, P, Q, R] -> { S119[i0, i1]; S114[i0, i1]; S117[i0, i1]; S115[i0, i1]; S118[i0, i1]; S116[i0, i1] }"
+            child:
+              schedule: "[M, N, O, P, Q, R] -> [{ S115[i0, i1] -> [(i1)]; S116[i0, i1] -> [(i1)]; S118[i0, i1] -> [(i1)]; S117[i0, i1] -> [(i1)]; S119[i0, i1] -> [(i1)]; S114[i0, i1] -> [(i1)] }]"
+              options: "[M, N, O, P, Q, R] -> { separate[i0] }"
+              child:
+                sequence:
+                - filter: "[M, N, O, P, Q, R] -> { S114[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S115[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S116[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S117[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S118[i0, i1] }"
+                - filter: "[M, N, O, P, Q, R] -> { S119[i0, i1] }"
+          - filter: "[M, N, O, P, Q, R] -> { S120[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S121[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S122[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S123[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S124[i0] }"
+          - filter: "[M, N, O, P, Q, R] -> { S125[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/test.c b/final/lib/External/isl/test_inputs/codegen/cloog/test.c
new file mode 100644
index 0000000..f0544ab
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/test.c
@@ -0,0 +1,17 @@
+{
+  for (int c0 = 1; c0 <= 2; c0 += 1)
+    for (int c1 = 1; c1 <= M; c1 += 1)
+      S1(c0, c1);
+  for (int c0 = 3; c0 <= N; c0 += 1) {
+    for (int c1 = 1; c1 <= min(M, c0 - 1); c1 += 1)
+      S1(c0, c1);
+    if (c0 >= M + 1) {
+      S2(c0, c0);
+    } else {
+      S1(c0, c0);
+      S2(c0, c0);
+    }
+    for (int c1 = c0 + 1; c1 <= M; c1 += 1)
+      S1(c0, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/test.st b/final/lib/External/isl/test_inputs/codegen/cloog/test.st
new file mode 100644
index 0000000..97a290e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/test.st
@@ -0,0 +1,10 @@
+domain: "[M, N] -> { S1[i0, i1] : i0 >= 1 and i0 <= N and i1 >= 1 and i1 <= M; S2[i0, i0] : i0 >= 3 and i0 <= N }"
+child:
+  context: "[M, N] -> { [] : N >= M and M >= 4 }"
+  child:
+    schedule: "[M, N] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[M, N] -> { S1[i0, i1] }"
+      - filter: "[M, N] -> { S2[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/thomasset.c b/final/lib/External/isl/test_inputs/codegen/cloog/thomasset.c
new file mode 100644
index 0000000..8d6709e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/thomasset.c
@@ -0,0 +1,9 @@
+{
+  for (int c0 = 0; c0 <= floord(n - 1, 3); c0 += 1)
+    for (int c2 = 3 * c0 + 1; c2 <= min(n, 3 * c0 + 3); c2 += 1)
+      S1(c2, c0);
+  for (int c0 = floord(n, 3); c0 <= 2 * floord(n, 3); c0 += 1)
+    for (int c1 = 0; c1 < n; c1 += 1)
+      for (int c3 = max(1, (n % 3) - n + 3 * c0); c3 <= min(n, (n % 3) - n + 3 * c0 + 2); c3 += 1)
+        S2(c1 + 1, c3, 0, n / 3, c0 - n / 3);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/thomasset.st b/final/lib/External/isl/test_inputs/codegen/cloog/thomasset.st
new file mode 100644
index 0000000..612b650
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/thomasset.st
@@ -0,0 +1,6 @@
+domain: "[n] -> { S1[i, j] : i <= n and i >= 1 and 3j <= -1 + i and 3j >= -3 + i; S2[i, j, 0, p, q] : i <= n and j <= n and j >= 1 and i >= 1 and 3q <= j and 3q >= -2 + j and 3p <= n and 3p >= -2 + n }"
+child:
+  context: "[n] -> { [] }"
+  child:
+    schedule: "[n] -> [{ S2[i0, i1, i2, i3, i4] -> [(i2 + i3 + i4)]; S1[i0, i1] -> [(i1)] }, { S2[i0, i1, i2, i3, i4] -> [(-1 + i0)]; S1[i0, i1] -> [(0)] }]"
+    options: "[n] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/tiling.c b/final/lib/External/isl/test_inputs/codegen/cloog/tiling.c
new file mode 100644
index 0000000..971b988
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/tiling.c
@@ -0,0 +1,3 @@
+for (int c0 = 0; c0 <= n / 10; c0 += 1)
+  for (int c1 = 10 * c0; c1 <= min(n, 10 * c0 + 9); c1 += 1)
+    S1(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/tiling.st b/final/lib/External/isl/test_inputs/codegen/cloog/tiling.st
new file mode 100644
index 0000000..5e8f0af
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/tiling.st
@@ -0,0 +1,6 @@
+domain: "[n] -> { S1[ii, i] : i >= 0 and i <= n and i <= 9 + 10ii and i >= 10ii }"
+child:
+  context: "[n] -> { [] : n >= 0 }"
+  child:
+    schedule: "[n] -> [{ S1[ii, i] -> [(ii)] }, { S1[ii, i] -> [(i)] }]"
+    options: "[n] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/uday_scalars.c b/final/lib/External/isl/test_inputs/codegen/cloog/uday_scalars.c
new file mode 100644
index 0000000..7d870a5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/uday_scalars.c
@@ -0,0 +1,6 @@
+{
+  for (int c0 = 0; c0 <= n; c0 += 1)
+    S1(c0, 0, 0);
+  for (int c0 = 0; c0 <= n; c0 += 1)
+    S2(0, c0, 0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/uday_scalars.st b/final/lib/External/isl/test_inputs/codegen/cloog/uday_scalars.st
new file mode 100644
index 0000000..1501e83
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/uday_scalars.st
@@ -0,0 +1,13 @@
+domain: "[n] -> { S1[j, 0, 0] : j >= 0 and j <= n; S2[0, l, 0] : l >= 0 and l <= n }"
+child:
+  context: "[n] -> { [] }"
+  child:
+    sequence:
+    - filter: "[n] -> { S1[i0, i1, i2] }"
+      child:
+        schedule: "[n] -> [{ S1[i0, i1, i2] -> [(i0)] }]"
+        options: "[n] -> { separate[i0] }"
+    - filter: "[n] -> { S2[i0, i1, i2] }"
+      child:
+        schedule: "[n] -> [{ S2[i0, i1, i2] -> [(i1)] }]"
+        options: "[n] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/union.c b/final/lib/External/isl/test_inputs/codegen/cloog/union.c
new file mode 100644
index 0000000..b9daaf9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/union.c
@@ -0,0 +1,7 @@
+if (M >= 11) {
+  for (int c0 = -100; c0 <= 0; c0 += 1)
+    S1(-c0);
+} else {
+  for (int c0 = 0; c0 <= 100; c0 += 1)
+    S1(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/union.st b/final/lib/External/isl/test_inputs/codegen/cloog/union.st
new file mode 100644
index 0000000..c2622dc
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/union.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S1[i0] : i0 >= 0 and i0 <= 100 }"
+child:
+  context: "[M] -> { [] : M >= 1 or M <= -1 }"
+  child:
+    schedule: "[M] -> [{ S1[i0] -> [(i0)] : M <= 10; S1[i0] -> [(-i0)] : M >= 11 }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/unroll.c b/final/lib/External/isl/test_inputs/codegen/cloog/unroll.c
new file mode 100644
index 0000000..83c4577
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/unroll.c
@@ -0,0 +1,13 @@
+{
+  S1(0);
+  S1(1);
+  S1(2);
+  S1(3);
+  S1(4);
+  S1(5);
+  S1(6);
+  S1(7);
+  S1(8);
+  S1(9);
+  S1(10);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/unroll.st b/final/lib/External/isl/test_inputs/codegen/cloog/unroll.st
new file mode 100644
index 0000000..8780a63
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/unroll.st
@@ -0,0 +1,6 @@
+domain: "[n] -> { S1[i] : i >= 0 and i <= 10 }"
+child:
+  context: "[n] -> { [] }"
+  child:
+    schedule: "[n] -> [{ S1[i] -> [(i)] }]"
+    options: "[n] -> { unroll[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/unroll2.c b/final/lib/External/isl/test_inputs/codegen/cloog/unroll2.c
new file mode 100644
index 0000000..58f2705
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/unroll2.c
@@ -0,0 +1,5 @@
+if (n >= -1 && n <= 9) {
+  if (n >= 0)
+    S1(n);
+  S1(n + 1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/unroll2.st b/final/lib/External/isl/test_inputs/codegen/cloog/unroll2.st
new file mode 100644
index 0000000..32cbb8c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/unroll2.st
@@ -0,0 +1,6 @@
+domain: "[n] -> { S1[i] : i >= n and i <= 1 + n and n <= 9 and i >= 0 }"
+child:
+  context: "[n] -> { [] }"
+  child:
+    schedule: "[n] -> [{ S1[i] -> [(i)] }]"
+    options: "[n] -> { unroll[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/usvd_e_t.c b/final/lib/External/isl/test_inputs/codegen/cloog/usvd_e_t.c
new file mode 100644
index 0000000..af8c9fe
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/usvd_e_t.c
@@ -0,0 +1,348 @@
+{
+  for (int c0 = 0; c0 <= 2; c0 += 1) {
+    S1(c0, 0, 0);
+    for (int c1 = 0; c1 <= 4; c1 += 1)
+      S2(c0, c1, 0);
+  }
+  S1(3, 0, 0);
+  for (int c1 = 0; c1 <= 4; c1 += 1)
+    S2(3, c1, 0);
+  for (int c1 = 7; c1 <= 11; c1 += 1)
+    S8(3, c1, 0);
+  S1(4, 0, 0);
+  S2(4, 0, 0);
+  S3(4, 0, 0);
+  S5(4, 0, 0);
+  for (int c1 = 1; c1 <= 4; c1 += 1) {
+    S2(4, c1, 0);
+    S5(4, c1, 0);
+  }
+  for (int c1 = 7; c1 <= 11; c1 += 1)
+    S8(4, c1, 0);
+  for (int c0 = 5; c0 <= 6; c0 += 1) {
+    for (int c1 = -4; c1 < c0 - 8; c1 += 1)
+      S6(c0, c1, 0);
+    for (int c1 = c0 - 9; c1 < 0; c1 += 1)
+      S7(c0, c1, 0);
+    S3(c0, 0, 0);
+    S7(c0, 0, 0);
+    for (int c1 = 1; c1 < c0 - 3; c1 += 1)
+      S4(c0, c1, -1);
+    for (int c1 = c0 - 4; c1 <= 4; c1 += 1)
+      S5(c0, c1, 0);
+    for (int c1 = 7; c1 <= 11; c1 += 1)
+      S8(c0, c1, 0);
+  }
+  for (int c1 = -4; c1 < -1; c1 += 1)
+    S6(7, c1, 0);
+  for (int c1 = -2; c1 < 0; c1 += 1)
+    S7(7, c1, 0);
+  S3(7, 0, 0);
+  S7(7, 0, 0);
+  for (int c1 = 1; c1 <= 3; c1 += 1)
+    S4(7, c1, -1);
+  for (int c1 = 3; c1 <= 4; c1 += 1)
+    S5(7, c1, 0);
+  S9(7, 4, 0);
+  S10(7, 4, 0);
+  S11(7, 4, 0);
+  S21(7, 4, 0);
+  S23(7, 4, 0);
+  S11(7, 4, 1);
+  S16(7, 4, 1);
+  S17(7, 4, 1);
+  for (int c2 = 2; c2 <= 4; c2 += 1)
+    S11(7, 4, c2);
+  S12(7, 5, 0);
+  S21(7, 5, 0);
+  S22(7, 5, 0);
+  S23(7, 5, 0);
+  S12(7, 5, 1);
+  S16(7, 5, 1);
+  S17(7, 5, 1);
+  for (int c2 = 2; c2 <= 4; c2 += 1)
+    S12(7, 5, c2);
+  S21(7, 6, 0);
+  S22(7, 6, 0);
+  S23(7, 6, 0);
+  for (int c1 = 7; c1 <= 8; c1 += 1) {
+    S8(7, c1, 0);
+    S21(7, c1, 0);
+    S22(7, c1, 0);
+    S23(7, c1, 0);
+  }
+  S8(7, 9, 0);
+  S22(7, 9, 0);
+  for (int c1 = 10; c1 <= 11; c1 += 1)
+    S8(7, c1, 0);
+  for (int c1 = -4; c1 < 0; c1 += 1)
+    S6(8, c1, 0);
+  S7(8, -1, 0);
+  S3(8, 0, 0);
+  S7(8, 0, 0);
+  S19(8, 1, -2);
+  S4(8, 1, -1);
+  S19(8, 1, -1);
+  S19(8, 1, 0);
+  S15(8, 1, 4);
+  S18(8, 1, 4);
+  for (int c2 = -4; c2 < -2; c2 += 1) {
+    S14(8, 2, c2);
+    S20(8, 2, c2);
+  }
+  S14(8, 2, -2);
+  S19(8, 2, -2);
+  S20(8, 2, -2);
+  S4(8, 2, -1);
+  S14(8, 2, -1);
+  S19(8, 2, -1);
+  S20(8, 2, -1);
+  S14(8, 2, 0);
+  S19(8, 2, 0);
+  S20(8, 2, 0);
+  S15(8, 2, 4);
+  S18(8, 2, 4);
+  for (int c2 = -4; c2 < -1; c2 += 1) {
+    S14(8, 3, c2);
+    S20(8, 3, c2);
+  }
+  S4(8, 3, -1);
+  S14(8, 3, -1);
+  S20(8, 3, -1);
+  S14(8, 3, 0);
+  S20(8, 3, 0);
+  S15(8, 3, 4);
+  S18(8, 3, 4);
+  for (int c2 = -4; c2 < -1; c2 += 1) {
+    S14(8, 4, c2);
+    S20(8, 4, c2);
+  }
+  S4(8, 4, -1);
+  S14(8, 4, -1);
+  S20(8, 4, -1);
+  S5(8, 4, 0);
+  S9(8, 4, 0);
+  S10(8, 4, 0);
+  S14(8, 4, 0);
+  S20(8, 4, 0);
+  S23(8, 4, 0);
+  S13(8, 4, 1);
+  S21(8, 4, 1);
+  S23(8, 4, 1);
+  S24(8, 4, 1);
+  S13(8, 4, 2);
+  S16(8, 4, 2);
+  S17(8, 4, 2);
+  S24(8, 4, 2);
+  S13(8, 4, 3);
+  S24(8, 4, 3);
+  S13(8, 4, 4);
+  S15(8, 4, 4);
+  S23(8, 5, 0);
+  S11(8, 5, 1);
+  S21(8, 5, 1);
+  S22(8, 5, 1);
+  S23(8, 5, 1);
+  S24(8, 5, 1);
+  S11(8, 5, 2);
+  S16(8, 5, 2);
+  S17(8, 5, 2);
+  S24(8, 5, 2);
+  S11(8, 5, 3);
+  S24(8, 5, 3);
+  S11(8, 5, 4);
+  S15(8, 5, 4);
+  S23(8, 6, 0);
+  S12(8, 6, 1);
+  S21(8, 6, 1);
+  S22(8, 6, 1);
+  S23(8, 6, 1);
+  S24(8, 6, 1);
+  S12(8, 6, 2);
+  S16(8, 6, 2);
+  S17(8, 6, 2);
+  S24(8, 6, 2);
+  S12(8, 6, 3);
+  S24(8, 6, 3);
+  S12(8, 6, 4);
+  for (int c1 = 7; c1 <= 8; c1 += 1) {
+    S23(8, c1, 0);
+    S21(8, c1, 1);
+    S22(8, c1, 1);
+    S23(8, c1, 1);
+    for (int c2 = 1; c2 <= 3; c2 += 1)
+      S24(8, c1, c2);
+  }
+  S22(8, 9, 1);
+  S7(9, 0, 0);
+  for (int c1 = 1; c1 <= 2; c1 += 1) {
+    for (int c2 = -1; c2 <= 0; c2 += 1)
+      S19(9, c1, c2);
+    for (int c2 = 4; c2 <= 5; c2 += 1) {
+      S15(9, c1, c2);
+      S18(9, c1, c2);
+    }
+  }
+  S20(9, 3, -4);
+  for (int c2 = -3; c2 < -1; c2 += 1) {
+    S14(9, 3, c2);
+    S20(9, 3, c2);
+  }
+  for (int c2 = -1; c2 <= 0; c2 += 1) {
+    S14(9, 3, c2);
+    S19(9, 3, c2);
+    S20(9, 3, c2);
+  }
+  for (int c2 = 4; c2 <= 5; c2 += 1) {
+    S15(9, 3, c2);
+    S18(9, 3, c2);
+  }
+  S20(9, 4, -4);
+  for (int c2 = -3; c2 < 0; c2 += 1) {
+    S14(9, 4, c2);
+    S20(9, 4, c2);
+  }
+  S9(9, 4, 0);
+  S10(9, 4, 0);
+  S14(9, 4, 0);
+  S20(9, 4, 0);
+  for (int c2 = 0; c2 <= 1; c2 += 1)
+    S23(9, 4, c2);
+  S13(9, 4, 2);
+  S21(9, 4, 2);
+  S23(9, 4, 2);
+  S24(9, 4, 2);
+  S13(9, 4, 3);
+  S16(9, 4, 3);
+  S17(9, 4, 3);
+  S24(9, 4, 3);
+  S13(9, 4, 4);
+  for (int c2 = 4; c2 <= 5; c2 += 1) {
+    S15(9, 4, c2);
+    S18(9, 4, c2);
+  }
+  for (int c2 = 0; c2 <= 1; c2 += 1)
+    S23(9, 5, c2);
+  S13(9, 5, 2);
+  S21(9, 5, 2);
+  S22(9, 5, 2);
+  S23(9, 5, 2);
+  S24(9, 5, 2);
+  S13(9, 5, 3);
+  S16(9, 5, 3);
+  S17(9, 5, 3);
+  S24(9, 5, 3);
+  S13(9, 5, 4);
+  for (int c2 = 4; c2 <= 5; c2 += 1)
+    S15(9, 5, c2);
+  for (int c2 = 0; c2 <= 1; c2 += 1)
+    S23(9, 6, c2);
+  S11(9, 6, 2);
+  S21(9, 6, 2);
+  S22(9, 6, 2);
+  S23(9, 6, 2);
+  S24(9, 6, 2);
+  S11(9, 6, 3);
+  S16(9, 6, 3);
+  S17(9, 6, 3);
+  S24(9, 6, 3);
+  S11(9, 6, 4);
+  for (int c2 = 0; c2 <= 1; c2 += 1)
+    S23(9, 7, c2);
+  S12(9, 7, 2);
+  S21(9, 7, 2);
+  S22(9, 7, 2);
+  S23(9, 7, 2);
+  S24(9, 7, 2);
+  S12(9, 7, 3);
+  S16(9, 7, 3);
+  S17(9, 7, 3);
+  S24(9, 7, 3);
+  S12(9, 7, 4);
+  for (int c2 = 0; c2 <= 1; c2 += 1)
+    S23(9, 8, c2);
+  S21(9, 8, 2);
+  S22(9, 8, 2);
+  S23(9, 8, 2);
+  for (int c2 = 2; c2 <= 3; c2 += 1)
+    S24(9, 8, c2);
+  S22(9, 9, 2);
+  for (int c1 = 1; c1 <= 3; c1 += 1) {
+    S19(10, c1, 0);
+    S26(10, c1, 3);
+    S15(10, c1, 4);
+    S18(10, c1, 4);
+    S25(10, c1, 4);
+    for (int c2 = 5; c2 <= 6; c2 += 1) {
+      S15(10, c1, c2);
+      S18(10, c1, c2);
+    }
+  }
+  for (int c2 = -4; c2 < -2; c2 += 1)
+    S20(10, 4, c2);
+  for (int c2 = -2; c2 < 0; c2 += 1) {
+    S14(10, 4, c2);
+    S20(10, 4, c2);
+  }
+  S9(10, 4, 0);
+  S10(10, 4, 0);
+  S14(10, 4, 0);
+  S19(10, 4, 0);
+  S20(10, 4, 0);
+  S13(10, 4, 3);
+  S21(10, 4, 3);
+  S24(10, 4, 3);
+  S26(10, 4, 3);
+  S13(10, 4, 4);
+  S15(10, 4, 4);
+  S16(10, 4, 4);
+  S17(10, 4, 4);
+  S18(10, 4, 4);
+  S25(10, 4, 4);
+  for (int c2 = 5; c2 <= 6; c2 += 1) {
+    S15(10, 4, c2);
+    S18(10, 4, c2);
+  }
+  S13(10, 5, 3);
+  S21(10, 5, 3);
+  S22(10, 5, 3);
+  S24(10, 5, 3);
+  S26(10, 5, 3);
+  S13(10, 5, 4);
+  S15(10, 5, 4);
+  S16(10, 5, 4);
+  S17(10, 5, 4);
+  S18(10, 5, 4);
+  S25(10, 5, 4);
+  for (int c2 = 5; c2 <= 6; c2 += 1) {
+    S15(10, 5, c2);
+    S18(10, 5, c2);
+  }
+  S13(10, 6, 3);
+  S21(10, 6, 3);
+  S22(10, 6, 3);
+  S24(10, 6, 3);
+  S13(10, 6, 4);
+  S16(10, 6, 4);
+  S17(10, 6, 4);
+  S11(10, 7, 3);
+  S21(10, 7, 3);
+  S22(10, 7, 3);
+  S24(10, 7, 3);
+  S11(10, 7, 4);
+  S16(10, 7, 4);
+  S17(10, 7, 4);
+  S12(10, 8, 3);
+  S21(10, 8, 3);
+  S22(10, 8, 3);
+  S24(10, 8, 3);
+  S12(10, 8, 4);
+  S16(10, 8, 4);
+  S17(10, 8, 4);
+  S22(10, 9, 3);
+  for (int c0 = 11; c0 <= 14; c0 += 1)
+    for (int c1 = 1; c1 <= 5; c1 += 1) {
+      S26(c0, c1, 3);
+      S25(c0, c1, 4);
+    }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/usvd_e_t.st b/final/lib/External/isl/test_inputs/codegen/cloog/usvd_e_t.st
new file mode 100644
index 0000000..6494165
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/usvd_e_t.st
@@ -0,0 +1,34 @@
+domain: "{ S22[i0, i1, -7 + i0] : i0 >= 7 and i1 >= 5 and i1 <= 9 and i0 <= 10; S21[i0, i1, -7 + i0] : i0 <= 10 and i1 >= 4 and i1 <= 8 and i0 >= 7; S4[i0, i1, -1] : i0 <= 8 and i1 >= 1 and i1 <= -4 + i0; S8[i0, i1, 0] : i0 >= 3 and i0 <= 7 and i1 >= 7 and i1 <= 11; S25[i0, i1, 4] : i0 >= 10 and i0 <= 14 and i1 >= 1 and i1 <= 5; S15[i0, i1, i2] : i0 <= 10 and i1 >= 1 and i1 <= 5 and i2 >= 4 and i2 <= -4 + i0; S6[i0, i1, 0] : i0 <= 8 and i1 >= -4 and i1 <= -9 + i0; S16[i0, i1, -6 + i0] : i0 <= 10 and i1 >= 4 and i0 >= 7 and i1 <= -2 + i0; S7[i0, i1, 0] : i0 >= 5 and i1 <= 0 and i1 >= -9 + i0; S1[i0, 0, 0] : i0 >= 0 and i0 <= 4; S2[i0, i1, 0] : i0 >= 0 and i0 <= 4 and i1 >= 0 and i1 <= 4; S26[i0, i1, 3] : i0 >= 10 and i0 <= 14 and i1 >= 1 and i1 <= 5; S10[i0, 4, 0] : i0 >= 7 and i0 <= 10; S12[i0, -2 + i0, i2] : i0 >= 7 and i0 <= 10 and i2 <= 4 and i2 >= -7 + i0; S23[i0, i1, i2] : i0 <= 9 and i1 >= 4 and i1 <= 8 and i2 >= 0 and i2 <= -7 + i0; S13[i0, i1, i2] : i0 <= 10 and i1 >= 4 and i2 <= 4 and i2 >= -7 + i0 and i1 <= -4 + i0; S20[i0, i1, i2] : i0 >= 8 and i1 <= 4 and i2 >= -4 and i2 <= 0 and i1 >= -6 + i0; S24[i0, i1, i2] : i0 >= 8 and i1 >= 4 and i1 <= 8 and i2 <= 3 and i2 >= -7 + i0; S19[i0, i1, i2] : i0 >= 8 and i1 >= 1 and i2 <= 0 and i2 >= -10 + i0 and i1 <= -6 + i0; S11[i0, -3 + i0, i2] : i0 <= 10 and i0 >= 7 and i2 <= 4 and i2 >= -7 + i0; S14[i0, i1, i2] : i0 >= 8 and i1 <= 4 and i2 <= 0 and i2 >= -12 + i0 and i1 >= -6 + i0; S3[i0, 0, 0] : i0 >= 4 and i0 <= 8; S9[i0, 4, 0] : i0 >= 7 and i0 <= 10; S18[i0, i1, i2] : i0 <= 10 and i1 >= 1 and i2 >= 4 and i2 <= -4 + i0 and i1 <= -5 + i0; S5[i0, i1, 0] : i0 >= 4 and i1 <= 4 and i1 >= -4 + i0; S17[i0, i1, -6 + i0] : i0 >= 7 and i1 >= 4 and i0 <= 10 and i1 <= -2 + i0 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S8[i0, i1, i2] -> [(i0)]; S21[i0, i1, i2] -> [(i0)]; S9[i0, i1, i2] -> [(i0)]; S10[i0, i1, i2] -> [(i0)]; S24[i0, i1, i2] -> [(i0)]; S15[i0, i1, i2] -> [(i0)]; S12[i0, i1, i2] -> [(i0)]; S7[i0, i1, i2] -> [(i0)]; S6[i0, i1, i2] -> [(i0)]; S23[i0, i1, i2] -> [(i0)]; S22[i0, i1, i2] -> [(i0)]; S16[i0, i1, i2] -> [(i0)]; S17[i0, i1, i2] -> [(i0)]; S25[i0, i1, i2] -> [(i0)]; S18[i0, i1, i2] -> [(i0)]; S26[i0, i1, i2] -> [(i0)]; S5[i0, i1, i2] -> [(i0)]; S2[i0, i1, i2] -> [(i0)]; S4[i0, i1, i2] -> [(i0)]; S13[i0, i1, i2] -> [(i0)]; S3[i0, i1, i2] -> [(i0)]; S14[i0, i1, i2] -> [(i0)]; S19[i0, i1, i2] -> [(i0)]; S20[i0, i1, i2] -> [(i0)]; S11[i0, i1, i2] -> [(i0)]; S1[i0, i1, i2] -> [(i0)] }, { S8[i0, i1, i2] -> [(i1)]; S21[i0, i1, i2] -> [(i1)]; S9[i0, i1, i2] -> [(i1)]; S10[i0, i1, i2] -> [(i1)]; S24[i0, i1, i2] -> [(i1)]; S15[i0, i1, i2] -> [(i1)]; S12[i0, i1, i2] -> [(i1)]; S7[i0, i1, i2] -> [(i1)]; S6[i0, i1, i2] -> [(i1)]; S23[i0, i1, i2] -> [(i1)]; S22[i0, i1, i2] -> [(i1)]; S16[i0, i1, i2] -> [(i1)]; S17[i0, i1, i2] -> [(i1)]; S25[i0, i1, i2] -> [(i1)]; S18[i0, i1, i2] -> [(i1)]; S26[i0, i1, i2] -> [(i1)]; S5[i0, i1, i2] -> [(i1)]; S2[i0, i1, i2] -> [(i1)]; S4[i0, i1, i2] -> [(i1)]; S13[i0, i1, i2] -> [(i1)]; S3[i0, i1, i2] -> [(i1)]; S14[i0, i1, i2] -> [(i1)]; S19[i0, i1, i2] -> [(i1)]; S20[i0, i1, i2] -> [(i1)]; S11[i0, i1, i2] -> [(i1)]; S1[i0, i1, i2] -> [(i1)] }, { S8[i0, i1, i2] -> [(i2)]; S21[i0, i1, i2] -> [(i2)]; S9[i0, i1, i2] -> [(i2)]; S10[i0, i1, i2] -> [(i2)]; S24[i0, i1, i2] -> [(i2)]; S15[i0, i1, i2] -> [(i2)]; S12[i0, i1, i2] -> [(i2)]; S7[i0, i1, i2] -> [(i2)]; S6[i0, i1, i2] -> [(i2)]; S23[i0, i1, i2] -> [(i2)]; S22[i0, i1, i2] -> [(i2)]; S16[i0, i1, i2] -> [(i2)]; S17[i0, i1, i2] -> [(i2)]; S25[i0, i1, i2] -> [(i2)]; S18[i0, i1, i2] -> [(i2)]; S26[i0, i1, i2] -> [(i2)]; S5[i0, i1, i2] -> [(i2)]; S2[i0, i1, i2] -> [(i2)]; S4[i0, i1, i2] -> [(i2)]; S13[i0, i1, i2] -> [(i2)]; S3[i0, i1, i2] -> [(i2)]; S14[i0, i1, i2] -> [(i2)]; S19[i0, i1, i2] -> [(i2)]; S20[i0, i1, i2] -> [(i2)]; S11[i0, i1, i2] -> [(i2)]; S1[i0, i1, i2] -> [(i2)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[i0, i1, i2] }"
+      - filter: "{ S2[i0, i1, i2] }"
+      - filter: "{ S3[i0, i1, i2] }"
+      - filter: "{ S4[i0, i1, i2] }"
+      - filter: "{ S5[i0, i1, i2] }"
+      - filter: "{ S6[i0, i1, i2] }"
+      - filter: "{ S7[i0, i1, i2] }"
+      - filter: "{ S8[i0, i1, i2] }"
+      - filter: "{ S9[i0, i1, i2] }"
+      - filter: "{ S10[i0, i1, i2] }"
+      - filter: "{ S11[i0, i1, i2] }"
+      - filter: "{ S12[i0, i1, i2] }"
+      - filter: "{ S13[i0, i1, i2] }"
+      - filter: "{ S14[i0, i1, i2] }"
+      - filter: "{ S15[i0, i1, i2] }"
+      - filter: "{ S16[i0, i1, i2] }"
+      - filter: "{ S17[i0, i1, i2] }"
+      - filter: "{ S18[i0, i1, i2] }"
+      - filter: "{ S19[i0, i1, i2] }"
+      - filter: "{ S20[i0, i1, i2] }"
+      - filter: "{ S21[i0, i1, i2] }"
+      - filter: "{ S22[i0, i1, i2] }"
+      - filter: "{ S23[i0, i1, i2] }"
+      - filter: "{ S24[i0, i1, i2] }"
+      - filter: "{ S25[i0, i1, i2] }"
+      - filter: "{ S26[i0, i1, i2] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/vasilache.c b/final/lib/External/isl/test_inputs/codegen/cloog/vasilache.c
new file mode 100644
index 0000000..0df7889
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/vasilache.c
@@ -0,0 +1,24 @@
+{
+  S1();
+  S2();
+  for (int c0 = 0; c0 < N; c0 += 1)
+    for (int c1 = 0; c1 < N; c1 += 1) {
+      S4(c0, c1);
+      S5(c0, c1);
+    }
+  for (int c0 = 0; c0 < N; c0 += 1)
+    for (int c1 = 0; c1 < N; c1 += 1)
+      for (int c2 = 0; c2 <= (N - 1) / 32; c2 += 1) {
+        S7(c0, c1, c2, 32 * c2);
+        for (int c3 = 32 * c2 + 1; c3 <= min(N - 1, 32 * c2 + 31); c3 += 1) {
+          S6(c0, c1, c2, c3 - 1);
+          S7(c0, c1, c2, c3);
+        }
+        if (32 * c2 + 31 >= N) {
+          S6(c0, c1, c2, N - 1);
+        } else {
+          S6(c0, c1, c2, 32 * c2 + 31);
+        }
+      }
+  S8();
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/vasilache.st b/final/lib/External/isl/test_inputs/codegen/cloog/vasilache.st
new file mode 100644
index 0000000..f0cd320
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/vasilache.st
@@ -0,0 +1,37 @@
+domain: "[M, N] -> { S5[i0, i1] : i0 >= 0 and i0 <= -1 + N and i1 >= 0 and i1 <= -1 + N; S8[]; S2[]; S7[i0, i1, i2, i3] : i0 >= 0 and i0 <= -1 + N and i1 >= 0 and i1 <= -1 + N and i3 >= 0 and i3 <= -1 + N and i3 >= 32i2 and i3 <= 31 + 32i2; S4[i0, i1] : i0 >= 0 and i0 <= -1 + N and i1 >= 0 and i1 <= -1 + N; S1[]; S3[] : M >= 79; S6[i0, i1, i2, i3] : i0 >= 0 and i0 <= -1 + N and i1 >= 0 and i1 <= -1 + N and i3 >= 0 and i3 <= -1 + N and i3 >= 32i2 and i3 <= 31 + 32i2 }"
+child:
+  context: "[M, N] -> { [] : M <= 3 and N >= 100 }"
+  child:
+    sequence:
+    - filter: "[M, N] -> { S1[] }"
+    - filter: "[M, N] -> { S2[] }"
+    - filter: "[M, N] -> { S3[] }"
+    - filter: "[M, N] -> { S5[i0, i1]; S4[i0, i1] }"
+      child:
+        schedule: "[M, N] -> [{ S5[i0, i1] -> [(i0)]; S4[i0, i1] -> [(i0)] }]"
+        options: "[M, N] -> { separate[i0] }"
+        child:
+          schedule: "[M, N] -> [{ S5[i0, i1] -> [(i1)]; S4[i0, i1] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
+          child:
+            sequence:
+            - filter: "[M, N] -> { S4[i0, i1] }"
+            - filter: "[M, N] -> { S5[i0, i1] }"
+    - filter: "[M, N] -> { S7[i0, i1, i2, i3]; S6[i0, i1, i2, i3] }"
+      child:
+        schedule: "[M, N] -> [{ S7[i0, i1, i2, i3] -> [(i0)]; S6[i0, i1, i2, i3] -> [(i0)] }]"
+        options: "[M, N] -> { separate[i0] }"
+        child:
+          schedule: "[M, N] -> [{ S7[i0, i1, i2, i3] -> [(i1)]; S6[i0, i1, i2, i3] -> [(i1)] }]"
+          options: "[M, N] -> { separate[i0] }"
+          child:
+            schedule: "[M, N] -> [{ S7[i0, i1, i2, i3] -> [(i2)]; S6[i0, i1, i2, i3] -> [(i2)] }]"
+            options: "[M, N] -> { separate[i0] }"
+            child:
+              schedule: "[M, N] -> [{ S7[i0, i1, i2, i3] -> [(i3)]; S6[i0, i1, i2, i3] -> [(1 + i3)] }]"
+              options: "[M, N] -> { separate[i0] }"
+              child:
+                sequence:
+                - filter: "[M, N] -> { S6[i0, i1, i2, i3] }"
+                - filter: "[M, N] -> { S7[i0, i1, i2, i3] }"
+    - filter: "[M, N] -> { S8[] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/vivien.c b/final/lib/External/isl/test_inputs/codegen/cloog/vivien.c
new file mode 100644
index 0000000..3976bab
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/vivien.c
@@ -0,0 +1,88 @@
+{
+  for (int c0 = -27 * n + 2; c0 <= 1; c0 += 1)
+    S1(c0 - 1);
+  for (int c0 = 2; c0 <= min(2 * n, n + 29); c0 += 1) {
+    if (c0 >= 3) {
+      if (2 * n >= c0 + 1) {
+        S4(c0 - c0 / 2 - 1, c0 / 2 + 1);
+        if (c0 + 2 >= 2 * n) {
+          for (int c2 = 1; c2 < -n + c0; c2 += 1)
+            S5(-n + c0, n, c2);
+        } else if (c0 >= 5) {
+          S4(c0 - c0 / 2 - 2, c0 / 2 + 2);
+          for (int c2 = 1; c2 < c0 - c0 / 2 - 1; c2 += 1)
+            S5(c0 - c0 / 2 - 1, c0 / 2 + 1, c2);
+        }
+      }
+      for (int c1 = -c0 + c0 / 2 + 3; c1 <= min(-1, n - c0); c1 += 1) {
+        S6(-c1 + 2, c0 + c1 - 2);
+        S4(-c1, c0 + c1);
+        for (int c2 = 1; c2 <= -c1; c2 += 1)
+          S5(-c1 + 1, c0 + c1 - 1, c2);
+      }
+      if (2 * n >= c0 + 3 && c0 >= n + 2) {
+        S6(-n + c0 + 1, n - 1);
+        for (int c2 = 1; c2 < -n + c0; c2 += 1)
+          S5(-n + c0, n, c2);
+      }
+      if (n >= 3 && c0 == n + 2) {
+        S1(n + 1);
+        S6(2, n);
+      } else {
+        if (c0 >= n + 3 && 2 * n >= c0 + 1)
+          S6(-n + c0, n);
+        if (c0 >= n + 3) {
+          S1(c0 - 1);
+        } else {
+          if (n + 1 >= c0 && c0 <= 4) {
+            S1(c0 - 1);
+          } else if (c0 >= 5 && n + 1 >= c0) {
+            S1(c0 - 1);
+            S6(2, c0 - 2);
+          }
+          if (n + 1 >= c0)
+            S6(1, c0 - 1);
+        }
+      }
+      if (n == 2 && c0 == 4)
+        S1(3);
+    } else {
+      S1(1);
+    }
+    if (c0 % 2 == 0)
+      S3(c0 / 2);
+    for (int c1 = max(1, -n + c0); c1 < (c0 + 1) / 2; c1 += 1)
+      S2(c0 - c1, c1);
+  }
+  for (int c0 = max(2 * n + 1, -27 * n + 2); c0 <= n + 29; c0 += 1)
+    S1(c0 - 1);
+  for (int c0 = n + 30; c0 <= 2 * n; c0 += 1) {
+    if (2 * n >= c0 + 1) {
+      S4(c0 - c0 / 2 - 1, c0 / 2 + 1);
+      if (c0 + 2 >= 2 * n) {
+        for (int c2 = 1; c2 < -n + c0; c2 += 1)
+          S5(-n + c0, n, c2);
+      } else {
+        S4(c0 - c0 / 2 - 2, c0 / 2 + 2);
+        for (int c2 = 1; c2 < c0 - c0 / 2 - 1; c2 += 1)
+          S5(c0 - c0 / 2 - 1, c0 / 2 + 1, c2);
+      }
+      for (int c1 = -c0 + c0 / 2 + 3; c1 <= n - c0; c1 += 1) {
+        S6(-c1 + 2, c0 + c1 - 2);
+        S4(-c1, c0 + c1);
+        for (int c2 = 1; c2 <= -c1; c2 += 1)
+          S5(-c1 + 1, c0 + c1 - 1, c2);
+      }
+      if (2 * n >= c0 + 3) {
+        S6(-n + c0 + 1, n - 1);
+        for (int c2 = 1; c2 < -n + c0; c2 += 1)
+          S5(-n + c0, n, c2);
+      }
+      S6(-n + c0, n);
+    }
+    if (c0 % 2 == 0)
+      S3(c0 / 2);
+    for (int c1 = -n + c0; c1 < (c0 + 1) / 2; c1 += 1)
+      S2(c0 - c1, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/vivien.st b/final/lib/External/isl/test_inputs/codegen/cloog/vivien.st
new file mode 100644
index 0000000..681b170
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/vivien.st
@@ -0,0 +1,6 @@
+domain: "[n] -> { S2[i, j] : 29j >= 1 - i and i <= n and j >= 1 and j <= -1 + i; S1[i] : i >= 1 - 27n and i <= 28 + n; S4[i, j] : i >= 1 and i <= n and j >= 1 + i and j <= n; S5[i, j, k] : i >= 1 and i <= n and j >= 1 + i and j <= n and k >= 1 and k <= -1 + i; S6[i, j] : i >= 1 and i <= n and j >= 1 + i and j <= n; S3[i] : i >= 1 and i <= n }"
+child:
+  context: "[n] -> { [] }"
+  child:
+    schedule: "[n] -> [{ S1[i0] -> [(2 + 2i0)]; S4[i0, i1] -> [(2i0 + 2i1)]; S6[i0, i1] -> [(2i0 + 2i1)]; S3[i0] -> [(1 + 4i0)]; S5[i0, i1, i2] -> [(2i0 + 2i1)]; S2[i0, i1] -> [(1 + 2i0 + 2i1)] }, { S1[i0] -> [(0)]; S4[i0, i1] -> [(-i0)]; S6[i0, i1] -> [(2 - i0)]; S3[i0] -> [(0)]; S5[i0, i1, i2] -> [(1 - i0)]; S2[i0, i1] -> [(i1)] }, { S1[i0] -> [(0)]; S4[i0, i1] -> [(0)]; S6[i0, i1] -> [(0)]; S3[i0] -> [(0)]; S5[i0, i1, i2] -> [(i2)]; S2[i0, i1] -> [(0)] }]"
+    options: "[n] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/vivien2.c b/final/lib/External/isl/test_inputs/codegen/cloog/vivien2.c
new file mode 100644
index 0000000..f13c6d7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/vivien2.c
@@ -0,0 +1,80 @@
+{
+  for (int c0 = -27 * n + 2; c0 <= 1; c0 += 1)
+    S1(c0 - 1);
+  for (int c0 = 2; c0 <= n + 29; c0 += 1) {
+    if (c0 >= 3) {
+      S4(c0 - c0 / 2 - 1, c0 / 2 + 1);
+      if (c0 >= 5 && 2 * n >= c0 + 3) {
+        S4(c0 - c0 / 2 - 2, c0 / 2 + 2);
+        for (int c2 = 1; c2 < c0 - c0 / 2 - 1; c2 += 1)
+          S5(c0 - c0 / 2 - 1, c0 / 2 + 1, c2);
+      }
+      for (int c1 = -c0 + c0 / 2 + 3; c1 <= min(-1, n - c0); c1 += 1) {
+        S6(-c1 + 2, c0 + c1 - 2);
+        S4(-c1, c0 + c1);
+        for (int c2 = 1; c2 <= -c1; c2 += 1)
+          S5(-c1 + 1, c0 + c1 - 1, c2);
+      }
+      if (2 * n >= c0 + 3 && c0 >= n + 2) {
+        S6(-n + c0 + 1, n - 1);
+        for (int c2 = 1; c2 < -n + c0; c2 += 1)
+          S5(-n + c0, n, c2);
+        if (c0 == n + 2) {
+          S1(n + 1);
+          S6(2, n);
+        }
+      } else if (c0 + 2 >= 2 * n) {
+        for (int c2 = 1; c2 < -n + c0; c2 += 1)
+          S5(-n + c0, n, c2);
+      }
+      if (c0 >= n + 3) {
+        S6(-n + c0, n);
+        S1(c0 - 1);
+      } else {
+        if (c0 >= 5 && n + 1 >= c0) {
+          S1(c0 - 1);
+          S6(2, c0 - 2);
+        } else if (c0 <= 4) {
+          S1(c0 - 1);
+        }
+        if (n + 1 >= c0)
+          S6(1, c0 - 1);
+      }
+    } else {
+      S1(1);
+    }
+    if (c0 % 2 == 0)
+      S3(c0 / 2);
+    for (int c1 = max(1, -n + c0); c1 < (c0 + 1) / 2; c1 += 1)
+      S2(c0 - c1, c1);
+  }
+  for (int c0 = n + 30; c0 <= 2 * n; c0 += 1) {
+    if (2 * n >= c0 + 1) {
+      S4(c0 - c0 / 2 - 1, c0 / 2 + 1);
+      if (c0 + 2 >= 2 * n) {
+        for (int c2 = 1; c2 < -n + c0; c2 += 1)
+          S5(-n + c0, n, c2);
+      } else {
+        S4(c0 - c0 / 2 - 2, c0 / 2 + 2);
+        for (int c2 = 1; c2 < c0 - c0 / 2 - 1; c2 += 1)
+          S5(c0 - c0 / 2 - 1, c0 / 2 + 1, c2);
+      }
+      for (int c1 = -c0 + c0 / 2 + 3; c1 <= n - c0; c1 += 1) {
+        S6(-c1 + 2, c0 + c1 - 2);
+        S4(-c1, c0 + c1);
+        for (int c2 = 1; c2 <= -c1; c2 += 1)
+          S5(-c1 + 1, c0 + c1 - 1, c2);
+      }
+      if (2 * n >= c0 + 3) {
+        S6(-n + c0 + 1, n - 1);
+        for (int c2 = 1; c2 < -n + c0; c2 += 1)
+          S5(-n + c0, n, c2);
+      }
+      S6(-n + c0, n);
+    }
+    if (c0 % 2 == 0)
+      S3(c0 / 2);
+    for (int c1 = -n + c0; c1 < (c0 + 1) / 2; c1 += 1)
+      S2(c0 - c1, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/vivien2.st b/final/lib/External/isl/test_inputs/codegen/cloog/vivien2.st
new file mode 100644
index 0000000..932fbc2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/vivien2.st
@@ -0,0 +1,6 @@
+domain: "[n] -> { S2[i, j] : 29j >= 1 - i and i <= n and j >= 1 and j <= -1 + i; S1[i] : i >= 1 - 27n and i <= 28 + n; S4[i, j] : i >= 1 and i <= n and j >= 1 + i and j <= n; S5[i, j, k] : i >= 1 and i <= n and j >= 1 + i and j <= n and k >= 1 and k <= -1 + i; S6[i, j] : i >= 1 and i <= n and j >= 1 + i and j <= n; S3[i] : i >= 1 and i <= n }"
+child:
+  context: "[n] -> { [] : n >= 30 }"
+  child:
+    schedule: "[n] -> [{ S1[i0] -> [(2 + 2i0)]; S4[i0, i1] -> [(2i0 + 2i1)]; S6[i0, i1] -> [(2i0 + 2i1)]; S3[i0] -> [(1 + 4i0)]; S5[i0, i1, i2] -> [(2i0 + 2i1)]; S2[i0, i1] -> [(1 + 2i0 + 2i1)] }, { S1[i0] -> [(0)]; S4[i0, i1] -> [(-i0)]; S6[i0, i1] -> [(2 - i0)]; S3[i0] -> [(0)]; S5[i0, i1, i2] -> [(1 - i0)]; S2[i0, i1] -> [(i1)] }, { S1[i0] -> [(0)]; S4[i0, i1] -> [(0)]; S6[i0, i1] -> [(0)]; S3[i0] -> [(0)]; S5[i0, i1, i2] -> [(i2)]; S2[i0, i1] -> [(0)] }]"
+    options: "[n] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/walters.c b/final/lib/External/isl/test_inputs/codegen/cloog/walters.c
new file mode 100644
index 0000000..3854892
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/walters.c
@@ -0,0 +1,16 @@
+{
+  S2(1, 0, 1, 0);
+  S4(1, 0, 1, 0);
+  S3(2, 0, 1, 1);
+  S4(2, 0, 1, 1);
+  for (int c0 = 3; c0 <= 10; c0 += 1) {
+    if ((c0 + 1) % 3 == 0) {
+      S3(c0, (c0 - 2) / 3, (c0 + 1) / 3, (c0 + 1) / 3);
+    } else if (c0 % 3 == 0) {
+      S1(c0, c0 / 3, c0 / 3, c0 / 3);
+    } else {
+      S2(c0, (c0 - 1) / 3, (c0 + 2) / 3, (c0 - 1) / 3);
+    }
+    S4(c0, c0 / 3, (c0 - 1) / 3 + 1, c0 - (c0 - 1) / 3 - c0 / 3 - 1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/walters.st b/final/lib/External/isl/test_inputs/codegen/cloog/walters.st
new file mode 100644
index 0000000..f168c99
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/walters.st
@@ -0,0 +1,12 @@
+domain: "{ S2[i, div36, div37, div38] : 3div37 = 2 + i and i >= 1 and i <= 10 and 3div36 >= -2 + i and 3div38 <= 1 + i and 3div38 >= -1 + i and 3div36 <= i; S4[i, div36, div37, div38] : i >= 1 and i <= 10 and 3div36 <= i and 3div36 >= -2 + i and 3div37 <= 2 + i and 3div37 >= i and 3div38 <= 1 + i and 3div38 >= -1 + i; S1[i, div36, div37, div38] : 3div36 = i and i >= 3 and i <= 10 and 3div37 >= i and 3div38 <= 1 + i and 3div37 <= 2 + i and 3div38 >= -1 + i; S3[i, div36, div37, div38] : 3div38 = 1 + i and i <= 10 and i >= 2 and 3div36 >= -2 + i and 3div37 <= 2 + i and 3div36 <= i and 3div37 >= i }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[i, div36, div37, div38] -> [(i)]; S4[i, div36, div37, div38] -> [(i)]; S3[i, div36, div37, div38] -> [(i)]; S2[i, div36, div37, div38] -> [(i)] }, { S1[i, div36, div37, div38] -> [(div36)]; S4[i, div36, div37, div38] -> [(div36)]; S3[i, div36, div37, div38] -> [(div36)]; S2[i, div36, div37, div38] -> [(div36)] }, { S1[i, div36, div37, div38] -> [(div37)]; S4[i, div36, div37, div38] -> [(div37)]; S3[i, div36, div37, div38] -> [(div37)]; S2[i, div36, div37, div38] -> [(div37)] }, { S1[i, div36, div37, div38] -> [(div38)]; S4[i, div36, div37, div38] -> [(div38)]; S3[i, div36, div37, div38] -> [(div38)]; S2[i, div36, div37, div38] -> [(div38)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[i, div36, div37, div38] }"
+      - filter: "{ S2[i, div36, div37, div38] }"
+      - filter: "{ S3[i, div36, div37, div38] }"
+      - filter: "{ S4[i, div36, div37, div38] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/walters2.c b/final/lib/External/isl/test_inputs/codegen/cloog/walters2.c
new file mode 100644
index 0000000..27565fb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/walters2.c
@@ -0,0 +1,12 @@
+{
+  for (int c1 = 0; c1 <= 51; c1 += 1)
+    S2(0, c1);
+  for (int c0 = 1; c0 <= 24; c0 += 1) {
+    S2(c0, 0);
+    for (int c1 = 1; c1 <= 50; c1 += 1)
+      S1(c0, c1);
+    S2(c0, 51);
+  }
+  for (int c1 = 0; c1 <= 51; c1 += 1)
+    S2(25, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/walters2.st b/final/lib/External/isl/test_inputs/codegen/cloog/walters2.st
new file mode 100644
index 0000000..5caba80
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/walters2.st
@@ -0,0 +1,10 @@
+domain: "{ S2[j, 51] : j <= 24 and j >= 1; S2[25, i] : i <= 51 and i >= 1; S2[j, 0] : j <= 25 and j >= 1; S2[0, i] : i <= 51 and i >= 0; S1[j, i] : j >= 1 and j <= 24 and i >= 1 and i <= 50 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[j, i] -> [(j)]; S2[j, i] -> [(j)] }, { S1[j, i] -> [(i)]; S2[j, i] -> [(i)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[j, i] }"
+      - filter: "{ S2[j, i] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/walters3.c b/final/lib/External/isl/test_inputs/codegen/cloog/walters3.c
new file mode 100644
index 0000000..bafb9ac
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/walters3.c
@@ -0,0 +1,7 @@
+{
+  for (int c0 = 2; c0 <= 8; c0 += 2) {
+    S1(c0, c0 / 2, c0 / 2);
+    S2(c0, c0 / 2, c0 / 2);
+  }
+  S2(10, 5, 5);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/walters3.st b/final/lib/External/isl/test_inputs/codegen/cloog/walters3.st
new file mode 100644
index 0000000..1a14273
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/walters3.st
@@ -0,0 +1,10 @@
+domain: "{ S2[j, a, b] : 2a = j and j >= 1 and j <= 10 and 2b <= j and 2b >= -1 + j; S1[j, a, b] : 2a = j and 2b = j and j <= 8 and j >= 2 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S1[j, a, b] -> [(j)]; S2[j, a, b] -> [(j)] }, { S1[j, a, b] -> [(a)]; S2[j, a, b] -> [(a)] }, { S1[j, a, b] -> [(b)]; S2[j, a, b] -> [(b)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[j, a, b] }"
+      - filter: "{ S2[j, a, b] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/wavefront.c b/final/lib/External/isl/test_inputs/codegen/cloog/wavefront.c
new file mode 100644
index 0000000..7db0788
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/wavefront.c
@@ -0,0 +1,3 @@
+for (int c0 = 2; c0 <= n + m; c0 += 1)
+  for (int c1 = max(1, -m + c0); c1 <= min(n, c0 - 1); c1 += 1)
+    S1(c1, c0 - c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/wavefront.st b/final/lib/External/isl/test_inputs/codegen/cloog/wavefront.st
new file mode 100644
index 0000000..b31e0de
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/wavefront.st
@@ -0,0 +1,6 @@
+domain: "[n, m] -> { S1[i0, i1] : i0 >= 1 and i0 <= n and i1 >= 1 and i1 <= m }"
+child:
+  context: "[n, m] -> { [] }"
+  child:
+    schedule: "[n, m] -> [{ S1[i0, i1] -> [(i0 + i1)] }, { S1[i0, i1] -> [(i0)] }]"
+    options: "[n, m] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/yosr.c b/final/lib/External/isl/test_inputs/codegen/cloog/yosr.c
new file mode 100644
index 0000000..1c20057
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/yosr.c
@@ -0,0 +1,12 @@
+{
+  for (int c0 = 1; c0 < n; c0 += 1) {
+    for (int c2 = c0 + 1; c2 <= n; c2 += 1)
+      S1(c0, c2);
+    for (int c1 = 1; c1 < c0; c1 += 1)
+      for (int c2 = c1 + 1; c2 <= n; c2 += 1)
+        S2(c1, c2, c0);
+  }
+  for (int c1 = 1; c1 < n; c1 += 1)
+    for (int c2 = c1 + 1; c2 <= n; c2 += 1)
+      S2(c1, c2, n);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/yosr.st b/final/lib/External/isl/test_inputs/codegen/cloog/yosr.st
new file mode 100644
index 0000000..3ad4297
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/yosr.st
@@ -0,0 +1,6 @@
+domain: "[n] -> { S1[i0, i1] : i0 >= 1 and i0 <= -1 + n and i1 >= 1 + i0 and i1 <= n; S2[i0, i1, i2] : i0 >= 1 and i0 <= -1 + n and i1 >= 1 + i0 and i1 <= n and i2 >= 1 + i0 and i2 <= n }"
+child:
+  context: "[n] -> { [] }"
+  child:
+    schedule: "[n] -> [{ S2[i0, i1, i2] -> [(i2)]; S1[i0, i1] -> [(i0)] }]"
+    options: "[n] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/yosr2.c b/final/lib/External/isl/test_inputs/codegen/cloog/yosr2.c
new file mode 100644
index 0000000..1a3e992
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/yosr2.c
@@ -0,0 +1,13 @@
+{
+  for (int c1 = 1; c1 <= M; c1 += 1)
+    S2(c1);
+  for (int c0 = 2; c0 <= M; c0 += 1) {
+    for (int c2 = 1; c2 < c0; c2 += 1)
+      S1(c0, c2);
+    for (int c1 = 1; c1 < c0; c1 += 1)
+      S4(c1, c0);
+    for (int c2 = c0 + 1; c2 <= M; c2 += 1)
+      for (int c3 = 1; c3 < c0; c3 += 1)
+        S3(c0, c2, c3);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/yosr2.st b/final/lib/External/isl/test_inputs/codegen/cloog/yosr2.st
new file mode 100644
index 0000000..eb1ab41
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/yosr2.st
@@ -0,0 +1,6 @@
+domain: "[M] -> { S4[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 + i0 and i1 <= M; S3[i0, i1, i2] : i0 >= 1 and i0 <= M and i1 >= 1 + i0 and i1 <= M and i2 >= 1 and i2 <= -1 + i0; S1[i0, i1] : i0 >= 1 and i0 <= M and i1 >= 1 and i1 <= -1 + i0; S2[i0] : i0 >= 1 and i0 <= M }"
+child:
+  context: "[M] -> { [] : M >= 2 }"
+  child:
+    schedule: "[M] -> [{ S2[i0] -> [(0)]; S1[i0, i1] -> [(i0)]; S4[i0, i1] -> [(i1)]; S3[i0, i1, i2] -> [(i0)] }]"
+    options: "[M] -> { separate[i0] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/youcef.c b/final/lib/External/isl/test_inputs/codegen/cloog/youcef.c
new file mode 100644
index 0000000..1bc7ffd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/youcef.c
@@ -0,0 +1,6 @@
+for (int c0 = 0; c0 <= 5; c0 += 1) {
+  S1(c0, c0);
+  for (int c1 = c0; c1 <= 5; c1 += 1)
+    S2(c0, c1);
+  S3(c0, 5);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/youcef.st b/final/lib/External/isl/test_inputs/codegen/cloog/youcef.st
new file mode 100644
index 0000000..fa7cbda
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/youcef.st
@@ -0,0 +1,11 @@
+domain: "{ S2[i0, i1] : i0 >= 0 and i0 <= 5 and i1 >= i0 and i1 <= 5; S1[i0, i0] : i0 >= 0 and i0 <= 5; S3[i0, 5] : i0 >= 0 and i0 <= 5 }"
+child:
+  context: "{ [] }"
+  child:
+    schedule: "[{ S3[i0, i1] -> [(i0)]; S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)] }, { S3[i0, i1] -> [(i1)]; S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)] }]"
+    options: "{ separate[i0] }"
+    child:
+      sequence:
+      - filter: "{ S1[i0, i1] }"
+      - filter: "{ S2[i0, i1] }"
+      - filter: "{ S3[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/youcefn.c b/final/lib/External/isl/test_inputs/codegen/cloog/youcefn.c
new file mode 100644
index 0000000..1107790
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/youcefn.c
@@ -0,0 +1,10 @@
+{
+  for (int c0 = 1; c0 <= n; c0 += 1) {
+    S1(c0, c0);
+    for (int c1 = c0; c1 <= n; c1 += 1)
+      S2(c0, c1);
+    S3(c0, n);
+  }
+  for (int c0 = n + 1; c0 <= m; c0 += 1)
+    S3(c0, n);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/cloog/youcefn.st b/final/lib/External/isl/test_inputs/codegen/cloog/youcefn.st
new file mode 100644
index 0000000..9405c65
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/youcefn.st
@@ -0,0 +1,11 @@
+domain: "[n, m] -> { S1[i0, i0] : i0 >= 1 and i0 <= n; S3[i0, n] : i0 >= 1 and i0 <= m; S2[i0, i1] : i0 >= 1 and i0 <= n and i1 >= i0 and i1 <= n }"
+child:
+  context: "[n, m] -> { [] : n >= 2 and m >= n }"
+  child:
+    schedule: "[n, m] -> [{ S1[i0, i1] -> [(i0)]; S2[i0, i1] -> [(i0)]; S3[i0, i1] -> [(i0)] }, { S1[i0, i1] -> [(i1)]; S2[i0, i1] -> [(i1)]; S3[i0, i1] -> [(i1)] }]"
+    options: "[n, m] -> { separate[i0] }"
+    child:
+      sequence:
+      - filter: "[n, m] -> { S1[i0, i1] }"
+      - filter: "[n, m] -> { S2[i0, i1] }"
+      - filter: "[n, m] -> { S3[i0, i1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/component0.c b/final/lib/External/isl/test_inputs/codegen/component0.c
new file mode 100644
index 0000000..9b1c685
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component0.c
@@ -0,0 +1,5 @@
+{
+  A();
+  for (int c0 = 0; c0 <= 9; c0 += 1)
+    B(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/component0.st b/final/lib/External/isl/test_inputs/codegen/component0.st
new file mode 100644
index 0000000..3483af0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component0.st
@@ -0,0 +1,3 @@
+domain: "{ A[]; B[i] : 0 <= i < 10 }"
+child:
+  schedule: "[{ A[] -> [0]; B[i] -> [i] }]"
diff --git a/final/lib/External/isl/test_inputs/codegen/component1.c b/final/lib/External/isl/test_inputs/codegen/component1.c
new file mode 100644
index 0000000..9b1c685
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component1.c
@@ -0,0 +1,5 @@
+{
+  A();
+  for (int c0 = 0; c0 <= 9; c0 += 1)
+    B(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/component1.st b/final/lib/External/isl/test_inputs/codegen/component1.st
new file mode 100644
index 0000000..87c5eeb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component1.st
@@ -0,0 +1,7 @@
+domain: "{ A[]; B[i] : 0 <= i < 10 }"
+child:
+  schedule: "[{ A[] -> [0]; B[i] -> [i] }]"
+  child:
+    sequence:
+    - filter: "{ A[] }"
+    - filter: "{ B[i] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/component2.c b/final/lib/External/isl/test_inputs/codegen/component2.c
new file mode 100644
index 0000000..c963c7a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component2.c
@@ -0,0 +1,5 @@
+for (int c0 = 0; c0 <= 9; c0 += 1) {
+  B(c0);
+  if (c0 == 0)
+    A();
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/component2.st b/final/lib/External/isl/test_inputs/codegen/component2.st
new file mode 100644
index 0000000..70acba4
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component2.st
@@ -0,0 +1,7 @@
+domain: "{ A[]; B[i] : 0 <= i < 10 }"
+child:
+  schedule: "[{ A[] -> [0]; B[i] -> [i] }]"
+  child:
+    sequence:
+    - filter: "{ B[i] }"
+    - filter: "{ A[] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/component3.c b/final/lib/External/isl/test_inputs/codegen/component3.c
new file mode 100644
index 0000000..9b1c685
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component3.c
@@ -0,0 +1,5 @@
+{
+  A();
+  for (int c0 = 0; c0 <= 9; c0 += 1)
+    B(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/component3.st b/final/lib/External/isl/test_inputs/codegen/component3.st
new file mode 100644
index 0000000..c0bb65b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component3.st
@@ -0,0 +1,7 @@
+domain: "{ A[]; B[i] : 0 <= i < 10 }"
+child:
+  schedule: "[{ A[] -> [0]; B[i] -> [i] }]"
+  child:
+    set:
+    - filter: "{ B[i] }"
+    - filter: "{ A[] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/component4.c b/final/lib/External/isl/test_inputs/codegen/component4.c
new file mode 100644
index 0000000..1f188dd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component4.c
@@ -0,0 +1,7 @@
+{
+  for (int c1 = 0; c1 <= 9; c1 += 1)
+    A(c1);
+  for (int c0 = 0; c0 <= 9; c0 += 1)
+    for (int c2 = 0; c2 <= 9; c2 += 1)
+      B(c0, c2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/component4.st b/final/lib/External/isl/test_inputs/codegen/component4.st
new file mode 100644
index 0000000..c9e400b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component4.st
@@ -0,0 +1,7 @@
+domain: "{ A[i] : 0 <= i < 10; B[i,j] : 0 <= i,j < 10 }"
+child:
+  schedule: "[{ A[i] -> [0]; B[i,j] -> [i] }]"
+  child:
+    sequence:
+    - filter: "{ A[i] }"
+    - filter: "{ B[i,j] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/component5.c b/final/lib/External/isl/test_inputs/codegen/component5.c
new file mode 100644
index 0000000..072f2ea
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component5.c
@@ -0,0 +1,6 @@
+for (int c0 = 0; c0 <= 9; c0 += 1)
+  for (int c1 = 0; c1 <= 9; c1 += 1) {
+    if (c0 == 0)
+      A(c1);
+    B(c0, c1);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/component5.st b/final/lib/External/isl/test_inputs/codegen/component5.st
new file mode 100644
index 0000000..1d22898
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component5.st
@@ -0,0 +1,9 @@
+domain: "{ A[i] : 0 <= i < 10; B[i,j] : 0 <= i,j < 10 }"
+child:
+  schedule: "[{ A[i] -> [0]; B[i,j] -> [i] }]"
+  child:
+    schedule: "[{ A[i] -> [i]; B[i,j] -> [j] }]"
+    child:
+      sequence:
+      - filter: "{ A[i] }"
+      - filter: "{ B[i,j] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/component6.c b/final/lib/External/isl/test_inputs/codegen/component6.c
new file mode 100644
index 0000000..9b1c685
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component6.c
@@ -0,0 +1,5 @@
+{
+  A();
+  for (int c0 = 0; c0 <= 9; c0 += 1)
+    B(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/component6.st b/final/lib/External/isl/test_inputs/codegen/component6.st
new file mode 100644
index 0000000..d13e8bf
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/component6.st
@@ -0,0 +1,10 @@
+# Check that components are still detected in presence of nested context node
+domain: "{ A[]; B[i] : 0 <= i < 10 }"
+child:
+  schedule: "[{ A[] -> [0]; B[i] -> [i] }]"
+  child:
+    context: "[n] -> { [i] : 0 <= n <= i }"
+    child:
+      sequence:
+      - filter: "{ A[] }"
+      - filter: "{ B[i] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/correlation.c b/final/lib/External/isl/test_inputs/codegen/correlation.c
new file mode 100644
index 0000000..e771b43
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/correlation.c
@@ -0,0 +1,45 @@
+for (int c0 = 0; c0 < m; c0 += 32)
+  for (int c1 = (n >= 32 && m >= c0 + 2) || (m == 1 && c0 == 0) ? 0 : 32 * n - 32 * floord(31 * n + 31, 32); c1 <= ((n <= -1 && c0 == 0) || (m == 1 && n >= 0 && c0 == 0) ? max(0, n - 1) : n); c1 += 32)
+    for (int c2 = c0; c2 <= (m >= 2 && c0 + 31 >= m && n >= c1 && c1 + 31 >= n ? 2 * m - 3 : (m >= 2 * c0 + 63 && c1 <= -32 && n >= c1 && c1 + 31 >= n) || (m >= c0 + 32 && 2 * c0 + 62 >= m && n >= c1 && c1 + 31 >= n) || (n >= 0 && c0 >= 32 && m >= 2 * c0 + 63 && c1 == n) || (m >= 63 && n >= 32 && c0 == 0 && c1 == n) ? 2 * c0 + 61 : m - 1); c2 += 32) {
+      if (n >= c1 + 32 && c1 >= 0 && 2 * c0 >= c2 + 32) {
+        for (int c4 = 0; c4 <= 31; c4 += 1)
+          for (int c5 = max(0, c0 - c2 + 1); c5 <= min(31, m - c2 - 1); c5 += 1)
+            S_27(c0, c2 + c5, c1 + c4);
+      } else if (c0 >= 32 && c1 >= 0 && c2 >= 2 * c0) {
+        for (int c4 = 0; c4 <= min(31, n - c1 - 1); c4 += 1)
+          for (int c5 = 0; c5 <= min(31, m - c2 - 1); c5 += 1)
+            S_27(c0, c2 + c5, c1 + c4);
+      } else if (c0 == 0 && c1 >= 0) {
+        for (int c4 = 0; c4 <= min(31, n - c1 - 1); c4 += 1)
+          for (int c5 = 0; c5 <= min(31, m - c2 - 1); c5 += 1) {
+            if (c1 == 0 && c4 == 0)
+              S_14(c2 + c5);
+            S_19(c1 + c4, c2 + c5);
+            if (c2 + c5 >= 1)
+              S_27(0, c2 + c5, c1 + c4);
+          }
+      }
+      if (c1 >= 0) {
+        for (int c3 = 1; c3 <= min(31, (c2 / 2) - c0); c3 += 1)
+          for (int c4 = 0; c4 <= min(31, n - c1 - 1); c4 += 1)
+            for (int c5 = 0; c5 <= min(31, m - c2 - 1); c5 += 1)
+              S_27(c0 + c3, c2 + c5, c1 + c4);
+        if (n >= c1 + 32) {
+          for (int c3 = max(1, (c2 / 2) - c0 + 1); c3 <= min(min(31, m - c0 - 2), -c0 + c2 + 30); c3 += 1)
+            for (int c4 = 0; c4 <= 31; c4 += 1)
+              for (int c5 = max(0, c0 - c2 + c3 + 1); c5 <= min(31, m - c2 - 1); c5 += 1)
+                S_27(c0 + c3, c2 + c5, c1 + c4);
+        } else if (n <= 0 && c0 == 0 && c1 == 0) {
+          for (int c5 = 0; c5 <= min(31, m - c2 - 1); c5 += 1)
+            S_14(c2 + c5);
+        }
+      }
+      if (n >= c1 && c1 + 31 >= n)
+        for (int c3 = max(0, (c2 / 2) - c0 + 1); c3 <= min(31, m - c0 - 1); c3 += 1) {
+          for (int c4 = max(0, -c1); c4 < n - c1; c4 += 1)
+            for (int c5 = max(0, c0 - c2 + c3 + 1); c5 <= min(31, m - c2 - 1); c5 += 1)
+              S_27(c0 + c3, c2 + c5, c1 + c4);
+          for (int c5 = max(0, c0 - c2 + c3); c5 <= min(31, 2 * c0 - c2 + 2 * c3 - 1); c5 += 1)
+            S_29(-c0 + c2 - c3 + c5, c0 + c3);
+        }
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/correlation.st b/final/lib/External/isl/test_inputs/codegen/correlation.st
new file mode 100644
index 0000000..bba5a09
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/correlation.st
@@ -0,0 +1,18 @@
+domain: "[m, n] -> { S_14[j] : 0 <= j < m; S_19[i, j] : 0 <= i < n and 0 <= j < m; S_27[i, j, k] : i >= 0 and i < j < m and 0 <= k < n; S_29[i, j] : i >= 0 and i < j < m }"
+child:
+  context: "[m, n] -> { [] : 0 < m <= 2147483647 and -2147483648 <= n <= 2147483647 }"
+  child:
+            schedule: "[m, n] -> [{ S_19[i, j] -> [(0)]; S_29[i, j] -> [(32*floor((j)/32))]; S_27[i, j, k] -> [(32*floor((i)/32))]; S_14[j] -> [(0)] }, { S_19[i, j] -> [(32*floor((i)/32))]; S_29[i, j] -> [(32*floor((n)/32))]; S_27[i, j, k] -> [(32*floor((k)/32))]; S_14[j] -> [(0)] }, { S_19[i, j] -> [(32*floor((j)/32))]; S_29[i, j] -> [(32*floor((i + j)/32))]; S_27[i, j, k] -> [(32*floor((j)/32))]; S_14[j] -> [(32*floor((j)/32))] }]"
+            permutable: 1
+            coincident: [ 1, 1, 1 ]
+            options: "{ atomic[i0] : 0 <= i0 <= 2 }"
+            child:
+              schedule: "[m, n] -> [{ S_19[i, j] -> [(0)]; S_29[i, j] -> [(j - 32*floor((j)/32))]; S_27[i, j, k] -> [(i - 32*floor((i)/32))]; S_14[j] -> [(0)] }, { S_19[i, j] -> [(i - 32*floor((i)/32))]; S_29[i, j] -> [(n - 32*floor((n)/32))]; S_27[i, j, k] -> [(k - 32*floor((k)/32))]; S_14[j] -> [(0)] }, { S_19[i, j] -> [(j - 32*floor((j)/32))]; S_29[i, j] -> [(i + j - 32*floor((i + j)/32))]; S_27[i, j, k] -> [(j - 32*floor((j)/32))]; S_14[j] -> [(j - 32*floor((j)/32))] }]"
+              permutable: 1
+              coincident: [ 1, 1, 1 ]
+              child:
+                sequence:
+                - filter: "[m, n] -> { S_29[i, j] }"
+                - filter: "[m, n] -> { S_14[j] }"
+                - filter: "[m, n] -> { S_19[i, j] }"
+                - filter: "[m, n] -> { S_27[i, j, k] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/disjuncts.c b/final/lib/External/isl/test_inputs/codegen/disjuncts.c
new file mode 100644
index 0000000..207e337
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/disjuncts.c
@@ -0,0 +1,10 @@
+for (int c0 = 0; c0 <= n; c0 += 1)
+  for (int c1 = 0; c1 <= n; c1 += 1)
+    if (c1 == n || c0 == n || c1 == 0 || c0 == 0) {
+      for (int c3 = 0; c3 <= n; c3 += 1)
+        for (int c4 = 0; c4 <= n; c4 += 1)
+          a(c0, c1, c3, c4);
+      for (int c3 = 0; c3 <= n; c3 += 1)
+        for (int c4 = 0; c4 <= n; c4 += 1)
+          b(c0, c1, c3, c4);
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/disjuncts.in b/final/lib/External/isl/test_inputs/codegen/disjuncts.in
new file mode 100644
index 0000000..0138670
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/disjuncts.in
@@ -0,0 +1,7 @@
+# Check that conditions are hoisted up from the innermost loop
+[n] -> { a[i,j,k,l] -> [i,j,0,k,l] :
+	    0 <= i,j,k,l <= n and (i = 0 or j = 0 or i = n or j = n);
+	 b[i,j,k,l] -> [i,j,1,k,l] :
+	    0 <= i,j,k,l <= n and (i = 0 or j = 0 or i = n or j = n) }
+{ : }
+{ [i,j,t,k,l] -> atomic[x] }
diff --git a/final/lib/External/isl/test_inputs/codegen/disjuncts2.c b/final/lib/External/isl/test_inputs/codegen/disjuncts2.c
new file mode 100644
index 0000000..6011a3b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/disjuncts2.c
@@ -0,0 +1,3 @@
+if (P >= Q + 1 || Q >= P + 1)
+  for (int c0 = 0; c0 < N; c0 += 1)
+    S(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/disjuncts2.st b/final/lib/External/isl/test_inputs/codegen/disjuncts2.st
new file mode 100644
index 0000000..d0170a6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/disjuncts2.st
@@ -0,0 +1,4 @@
+# Check that the loop is generated only once with an outer disjunctive condition
+domain: "[N, Q, P] -> { S[i0] : 0 <= i0 < N and (P > Q or P < Q) }"
+child:
+  schedule: "[N, Q, P] -> [{ S[i0] -> [(i0)] }]"
diff --git a/final/lib/External/isl/test_inputs/codegen/dwt.c b/final/lib/External/isl/test_inputs/codegen/dwt.c
new file mode 100644
index 0000000..a4de671
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/dwt.c
@@ -0,0 +1,9 @@
+for (int c0 = 0; c0 < Ncl; c0 += 1) {
+  if (Ncl >= c0 + 2 && c0 >= 1) {
+    S(c0, 28);
+  } else if (c0 == 0) {
+    S(0, 26);
+  } else {
+    S(Ncl - 1, 27);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/dwt.in b/final/lib/External/isl/test_inputs/codegen/dwt.in
new file mode 100644
index 0000000..424b0f3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/dwt.in
@@ -0,0 +1,3 @@
+[Ncl] -> { S[j, 28] -> [j] : j <= -2 + Ncl and Ncl <= 256 and Ncl >= 40 and j >= 1; S[0, 26] -> [0] : Ncl <= 256 and Ncl >= 40; S[-1 + Ncl, 27] -> [-1 + Ncl] : Ncl <= 256 and Ncl >= 40 }
+[Ncl] -> {  :  Ncl >= 40 and Ncl <= 256 }
+{  }
diff --git a/final/lib/External/isl/test_inputs/codegen/empty.c b/final/lib/External/isl/test_inputs/codegen/empty.c
new file mode 100644
index 0000000..0205735
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/empty.c
@@ -0,0 +1,6 @@
+for (int c0 = 0; c0 <= 10; c0 += 1) {
+  S0(c0);
+  S1(c0);
+  if (c0 == 5)
+    S2();
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/empty.in b/final/lib/External/isl/test_inputs/codegen/empty.in
new file mode 100644
index 0000000..17febea
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/empty.in
@@ -0,0 +1,5 @@
+# Earlier versions of isl would end up with an empty partial
+# executed relation and fail to detect this emptiness.
+[M] -> { S0[i] -> [i, -M] : 0 <= i <= 10; S1[i] -> [i, 0] : 0 <= i <= 10; S2[] -> [5, 0] }
+[M] -> {  : M >= 1 }
+{ }
diff --git a/final/lib/External/isl/test_inputs/codegen/filter.c b/final/lib/External/isl/test_inputs/codegen/filter.c
new file mode 100644
index 0000000..c326fa8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/filter.c
@@ -0,0 +1,9 @@
+if (n >= m + 1) {
+  for (int c0 = 0; c0 < n; c0 += 1)
+    for (int c2 = 0; c2 < n; c2 += 1)
+      A(c0, c2);
+} else {
+  for (int c0 = 0; c0 < n; c0 += 1)
+    for (int c2 = 0; c2 < n; c2 += 1)
+      A(c0, c2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/filter.st b/final/lib/External/isl/test_inputs/codegen/filter.st
new file mode 100644
index 0000000..719fb7e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/filter.st
@@ -0,0 +1,18 @@
+# Check proper handling of filters that turn out to be empty on their paths
+domain: "[n,m] -> { A[i,j] : 0 <= i,j < n }"
+child:
+  set:
+  - filter: "[n,m] -> { A[i,j] : m < n }"
+    child:
+      schedule: "[{ A[i,j] -> [i] }]"
+      child:
+        set:
+        - filter: "[n,m] -> { A[i,j] : m < n }"
+        - filter: "[n,m] -> { A[i,j] : m >= n }"
+  - filter: "[n,m] -> { A[i,j] : m >= n }"
+    child:
+      schedule: "[{ A[i,j] -> [i] }]"
+      child:
+        set:
+        - filter: "[n,m] -> { A[i,j] : m < n }"
+        - filter: "[n,m] -> { A[i,j] : m >= n }"
diff --git a/final/lib/External/isl/test_inputs/codegen/gemm.c b/final/lib/External/isl/test_inputs/codegen/gemm.c
new file mode 100644
index 0000000..d309b23
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/gemm.c
@@ -0,0 +1,6 @@
+for (int c0 = 0; c0 < ni; c0 += 1)
+  for (int c1 = 0; c1 < nj; c1 += 1) {
+    S_2(c0, c1);
+    for (int c2 = 0; c2 < nk; c2 += 1)
+      S_4(c0, c1, c2);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/gemm.st b/final/lib/External/isl/test_inputs/codegen/gemm.st
new file mode 100644
index 0000000..31df19d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/gemm.st
@@ -0,0 +1,12 @@
+domain: "[ni, nj, nk] -> { S_4[i, j, k] : k <= -1 + nk and k >= 0 and j <= -1 + nj and j >= 0 and i <= -1 + ni and i >= 0; S_2[i, j] : j <= -1 + nj and j >= 0 and i <= -1 + ni and i >= 0 }"
+child:
+  set:
+  - filter: "[ni, nj, nk] -> { S_4[i, j, k]; S_2[i, j] }"
+    child:
+      schedule: "[ni, nj, nk] -> [{ S_4[i, j, k] -> [(i)]; S_2[i, j] -> [(i)] }, { S_4[i, j, k] -> [(j)]; S_2[i, j] -> [(j)] }, { S_4[i, j, k] -> [(k)]; S_2[i, j] -> [(0)] }]"
+      permutable: 1
+      coincident: [ 1, 1, 0 ]
+      child:
+        sequence:
+        - filter: "[ni, nj, nk] -> { S_2[i, j] }"
+        - filter: "[ni, nj, nk] -> { S_4[i, j, k] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/hoist.c b/final/lib/External/isl/test_inputs/codegen/hoist.c
new file mode 100644
index 0000000..7ba854f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/hoist.c
@@ -0,0 +1,45 @@
+if (ni >= t0 + 1 && nj >= t1 + 1)
+  for (int c2 = 0; c2 <= min(15, nk - 1); c2 += 1) {
+    S_1(t0, t1, c2);
+    if (nj >= t1 + 17) {
+      S_1(t0, t1 + 16, c2);
+      if (nj >= t1 + 33) {
+        S_1(t0, t1 + 32, c2);
+        if (nj >= t1 + 49)
+          S_1(t0, t1 + 48, c2);
+      }
+    }
+    if (ni >= t0 + 17) {
+      S_1(t0 + 16, t1, c2);
+      if (nj >= t1 + 17) {
+        S_1(t0 + 16, t1 + 16, c2);
+        if (nj >= t1 + 33) {
+          S_1(t0 + 16, t1 + 32, c2);
+          if (nj >= t1 + 49)
+            S_1(t0 + 16, t1 + 48, c2);
+        }
+      }
+      if (ni >= t0 + 33) {
+        S_1(t0 + 32, t1, c2);
+        if (nj >= t1 + 17) {
+          S_1(t0 + 32, t1 + 16, c2);
+          if (nj >= t1 + 33) {
+            S_1(t0 + 32, t1 + 32, c2);
+            if (nj >= t1 + 49)
+              S_1(t0 + 32, t1 + 48, c2);
+          }
+        }
+        if (ni >= t0 + 49) {
+          S_1(t0 + 48, t1, c2);
+          if (nj >= t1 + 17) {
+            S_1(t0 + 48, t1 + 16, c2);
+            if (nj >= t1 + 33) {
+              S_1(t0 + 48, t1 + 32, c2);
+              if (nj >= t1 + 49)
+                S_1(t0 + 48, t1 + 48, c2);
+            }
+          }
+        }
+      }
+    }
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/hoist.in b/final/lib/External/isl/test_inputs/codegen/hoist.in
new file mode 100644
index 0000000..80a9052
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/hoist.in
@@ -0,0 +1,10 @@
+# check that the shared conditions ni >= t0 + 1 and nj >= t1 + 1
+# are hoisted out of the loop
+[ni, nj, nk, t0, t1] -> { S_1[i, j, k] -> [t0, t1, k, i, j] :
+	exists (e0 = [(-t0 + i)/16], e1 = [(-t1 + j)/16]:
+	16e0 = -t0 + i and 16e1 = -t1 + j and k >= 0 and j >= 0 and
+	j <= -1 + nj and i >= 0 and i <= -1 + ni and k <= -1 + nk and
+	ni >= 1 and nj >= 1 and nk >= 1 and j <= 63 and t1 >= 0 and
+	i <= 63 and k <= 15 and t0 >= 0 and t1 <= 15 and t0 <= 15) }
+[t0, t1] -> { : 0 <= t0, t1 <= 15 }
+{ [t0, t1, i5, i6, i7] -> unroll[x] : x >= 3}
diff --git a/final/lib/External/isl/test_inputs/codegen/hoist2.c b/final/lib/External/isl/test_inputs/codegen/hoist2.c
new file mode 100644
index 0000000..907652f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/hoist2.c
@@ -0,0 +1,5 @@
+for (int c0 = 1; c0 <= 5; c0 += 1)
+  if (c0 <= 3 || (b == 1 && t1 + c0 >= 10) || (t1 == 5 && b == 1 && c0 == 4))
+    for (int c1 = t1 - 64 * b + 64; c1 <= min(70, -c0 + 73); c1 += 64)
+      if (c0 <= 3 || (t1 + c0 >= 10 && c1 == t1) || c1 == 5)
+        A(c0, 64 * b + c1 - 8);
diff --git a/final/lib/External/isl/test_inputs/codegen/hoist2.in b/final/lib/External/isl/test_inputs/codegen/hoist2.in
new file mode 100644
index 0000000..6a29a02
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/hoist2.in
@@ -0,0 +1,5 @@
+# Check that the constraints hoisted from the inner loop
+# do not end up involving the inner loop iterator.
+[t1, b] -> { A[i1, i2] -> [i1, 8 - 64b + i2] : exists (e0, e1 = [(-8 + t1 - i2)/64]: 64e1 = -8 + t1 - i2 and i2 >= 1 and i2 <= 127 and 2e0 >= -3 + i1 and 2e0 >= -1 - i1 and 2e0 <= 8 - i1 and 2e0 <= 6 + i1 and 2e0 >= -65 - 64b + i2 and 2e0 >= -1 + 64b - i2 and e0 <= 1 and e0 >= 0 and 2e0 <= 62 + 64b - i2 and b <= 1 and b >= 0 and i1 >= 1 and i1 <= 2046 and t1 >= 5 and t1 <= 8) }
+[t1, b] -> { : b >= 0 and b <= 1 and t1 >= 5 and t1 <= 8 }
+[t1] -> { [i0, i1, i5, a] -> atomic[x]}
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate1.c b/final/lib/External/isl/test_inputs/codegen/isolate1.c
new file mode 100644
index 0000000..db6edf8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate1.c
@@ -0,0 +1,8 @@
+{
+  for (int c0 = 0; c0 <= 3; c0 += 1)
+    A(c0);
+  for (int c0 = 4; c0 <= 6; c0 += 1)
+    A(c0);
+  for (int c0 = 7; c0 <= 99; c0 += 1)
+    A(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate1.st b/final/lib/External/isl/test_inputs/codegen/isolate1.st
new file mode 100644
index 0000000..037dda1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate1.st
@@ -0,0 +1,5 @@
+# Check that the isolate option is adjusted by schedule space scaling
+domain: "{ A[i] : 0 <= i < 100 }"
+child:
+  schedule: "[{ A[i] -> [3i] }]"
+  options: "{ isolate[[] -> [x]] : 10 <= x <= 20 }"
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate2.c b/final/lib/External/isl/test_inputs/codegen/isolate2.c
new file mode 100644
index 0000000..28a78bc
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate2.c
@@ -0,0 +1,9 @@
+for (int c0 = 0; c0 <= 99; c0 += 1) {
+  if (c0 >= 4 && c0 <= 6) {
+    for (int c1 = 0; c1 <= 99; c1 += 1)
+      A(c0, c1);
+  } else {
+    for (int c1 = 0; c1 <= 99; c1 += 1)
+      A(c0, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate2.st b/final/lib/External/isl/test_inputs/codegen/isolate2.st
new file mode 100644
index 0000000..a9478f3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate2.st
@@ -0,0 +1,7 @@
+# Check that the isolate option is adjusted by schedule space scaling
+domain: "{ A[i,j] : 0 <= i,j < 100 }"
+child:
+  schedule: "[{ A[i,j] -> [3i] }]"
+  child:
+    schedule: "[{ A[i,j] -> [3j] }]"
+    options: "{ isolate[[x] -> [y]] : 10 <= x <= 20 }"
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate3.c b/final/lib/External/isl/test_inputs/codegen/isolate3.c
new file mode 100644
index 0000000..921ea49
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate3.c
@@ -0,0 +1,17 @@
+{
+  for (int c0 = 0; c0 <= 9; c0 += 1)
+    A(c0);
+  A(10);
+  A(11);
+  A(12);
+  A(13);
+  A(14);
+  A(15);
+  A(16);
+  A(17);
+  A(18);
+  A(19);
+  A(20);
+  for (int c0 = 21; c0 <= 99; c0 += 1)
+    A(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate3.st b/final/lib/External/isl/test_inputs/codegen/isolate3.st
new file mode 100644
index 0000000..bce38a8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate3.st
@@ -0,0 +1,5 @@
+# Check use of options specific to isolated part
+domain: "{ A[i] : 0 <= i < 100 }"
+child:
+  schedule: "[{ A[i] -> [i] }]"
+  options: "{ isolate[[] -> [x]] : 10 <= x <= 20; [isolate[] -> unroll[x]] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate4.c b/final/lib/External/isl/test_inputs/codegen/isolate4.c
new file mode 100644
index 0000000..71484e1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate4.c
@@ -0,0 +1,13 @@
+{
+  A(0);
+  A(1);
+  A(2);
+  A(3);
+  A(4);
+  for (int c0 = 5; c0 <= 15; c0 += 1)
+    A(c0);
+  A(16);
+  A(17);
+  A(18);
+  A(19);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate4.st b/final/lib/External/isl/test_inputs/codegen/isolate4.st
new file mode 100644
index 0000000..58b5168
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate4.st
@@ -0,0 +1,5 @@
+# Check that generic options are not applied to isolated part
+domain: "{ A[i] : 0 <= i < 20 }"
+child:
+  schedule: "[{ A[i] -> [i] }]"
+  options: "{ isolate[[] -> [x]] : 5 <= x <= 15; unroll[x] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate5.c b/final/lib/External/isl/test_inputs/codegen/isolate5.c
new file mode 100644
index 0000000..0f1588d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate5.c
@@ -0,0 +1,29 @@
+{
+  for (int c0 = 0; c0 <= 9; c0 += 1) {
+    if ((c0 + 1) % 2 == 0) {
+      for (int c1 = 0; c1 <= 1; c1 += 1)
+        B((c0 - 1) / 2, c1);
+    } else {
+      for (int c1 = 0; c1 <= 1; c1 += 1)
+        A(c0 / 2, c1);
+    }
+  }
+  for (int c0 = 10; c0 <= 89; c0 += 1) {
+    if ((c0 + 1) % 2 == 0) {
+      for (int c1 = 0; c1 <= 1; c1 += 1)
+        B((c0 - 1) / 2, c1);
+    } else {
+      for (int c1 = 0; c1 <= 1; c1 += 1)
+        A(c0 / 2, c1);
+    }
+  }
+  for (int c0 = 90; c0 <= 199; c0 += 1) {
+    if ((c0 + 1) % 2 == 0) {
+      for (int c1 = 0; c1 <= 1; c1 += 1)
+        B((c0 - 1) / 2, c1);
+    } else {
+      for (int c1 = 0; c1 <= 1; c1 += 1)
+        A(c0 / 2, c1);
+    }
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate5.st b/final/lib/External/isl/test_inputs/codegen/isolate5.st
new file mode 100644
index 0000000..86b0dd1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate5.st
@@ -0,0 +1,5 @@
+# Check that use of isolate option prevents shifted stride detection
+domain: "{ A[i,j] : 0 <= i < 100 and 0 <= j < 2; B[i,j] : 0 <= i < 100 and 0 <= j < 2 }"
+child:
+  schedule: "[{ A[i,j] -> [2i]; B[i,j] -> [2i+1] }, { A[i,j] -> [j]; B[i,j] -> [j]}]"
+  options: "{ isolate[[] -> [x, y]] : 10 <= x < 90 }"
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate6.c b/final/lib/External/isl/test_inputs/codegen/isolate6.c
new file mode 100644
index 0000000..e92a2b8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate6.c
@@ -0,0 +1,26 @@
+{
+  for (int c0 = 0; c0 <= 8; c0 += 1) {
+    for (int c1 = 0; c1 <= -c0 + 8; c1 += 1)
+      for (int c2 = 10 * c0; c2 <= 10 * c0 + 9; c2 += 1) {
+        A(c2, 10 * c1);
+        A(c2, 10 * c1 + 1);
+        A(c2, 10 * c1 + 2);
+        A(c2, 10 * c1 + 3);
+        A(c2, 10 * c1 + 4);
+        A(c2, 10 * c1 + 5);
+        A(c2, 10 * c1 + 6);
+        A(c2, 10 * c1 + 7);
+        A(c2, 10 * c1 + 8);
+        A(c2, 10 * c1 + 9);
+      }
+    for (int c1 = -c0 + 9; c1 <= -c0 + 10; c1 += 1)
+      for (int c2 = 10 * c0; c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1)
+        for (int c3 = 10 * c1; c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1)
+          A(c2, c3);
+  }
+  for (int c0 = 9; c0 <= 10; c0 += 1)
+    for (int c1 = 0; c1 <= -c0 + 10; c1 += 1)
+      for (int c2 = 10 * c0; c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1)
+        for (int c3 = 10 * c1; c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1)
+          A(c2, c3);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate6.st b/final/lib/External/isl/test_inputs/codegen/isolate6.st
new file mode 100644
index 0000000..1342223
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate6.st
@@ -0,0 +1,8 @@
+# Example from the manual
+domain: "{ A[i,j] : 0 <= i,j and i + j <= 100 }"
+child:
+  schedule: "[{ A[i,j] -> [floor(i/10)] }, \
+	{ A[i,j] -> [floor(j/10)] }, \
+	{ A[i,j] -> [i] }, { A[i,j] -> [j] }]"
+  options: "{ isolate[[] -> [a,b,c,d]] : 0 <= 10a,10b and \
+	10a+9+10b+9 <= 100; [isolate[] -> unroll[3]] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate7.c b/final/lib/External/isl/test_inputs/codegen/isolate7.c
new file mode 100644
index 0000000..1eac202
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate7.c
@@ -0,0 +1,29 @@
+{
+  for (int c0 = 0; c0 < n - 31; c0 += 32)
+    for (int c1 = 0; c1 <= n; c1 += 32) {
+      if (n >= c1 + 32) {
+        for (int c2 = 0; c2 <= 31; c2 += 1)
+          for (int c3 = 0; c3 <= 31; c3 += 1)
+            S_1(c0 + c2, c1 + c3);
+      } else {
+        for (int c2 = 0; c2 <= 31; c2 += 1) {
+          for (int c3 = 0; c3 < n - c1; c3 += 1)
+            S_1(c0 + c2, c1 + c3);
+          S_2(c0 + c2);
+        }
+      }
+    }
+  for (int c1 = 0; c1 < n; c1 += 32) {
+    if (n >= c1 + 32) {
+      for (int c2 = 0; c2 < (n + 32) % 32; c2 += 1)
+        for (int c3 = 0; c3 <= 31; c3 += 1)
+          S_1(-((n + 32) % 32) + n + c2, c1 + c3);
+    } else {
+      for (int c2 = 0; c2 < n - c1; c2 += 1) {
+        for (int c3 = 0; c3 < n - c1; c3 += 1)
+          S_1(c1 + c2, c1 + c3);
+        S_2(c1 + c2);
+      }
+    }
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/isolate7.st b/final/lib/External/isl/test_inputs/codegen/isolate7.st
new file mode 100644
index 0000000..673eb08
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate7.st
@@ -0,0 +1,16 @@
+# Check that no expressions of the form ((-n + 2147483648) % 32) are produced.
+domain: "[n] -> { S_2[i] : i >= 0 and i <= -1 + n; S_1[i, j] : j >= 0 and j <= -1 + n and i >= 0 and i <= -1 + n }"
+child:
+  context: "[n] -> { [] : n <= 2147483647 and n >= 0 }"
+  child:
+    schedule: "[n] -> [{ S_1[i, j] -> [(32*floor((i)/32))]; S_2[i] -> [(32*floor((i)/32))] }, { S_1[i, j] -> [(32*floor((j)/32))]; S_2[i] -> [(32*floor((n)/32))] }]"
+    permutable: 1
+    options: "[n] -> { atomic[i0] : i0 >= 0 and i0 <= 1; isolate[[] -> [i0, i1]] : (exists (e0 = floor((i0)/32), e1 = floor((i1)/32): 32e0 = i0 and 32e1 = i1 and i0 >= 0 and i0 <= -32 + n and i1 >= 0 and i1 <= n)) or (exists (e0 = floor((i0)/32), e1 = floor((i1)/32): 32e0 = i0 and 32e1 = i1 and i0 >= 0 and i0 <= -32 + n and i1 >= -31 + n and i1 <= -31 + 2n)) }"
+    child:
+          schedule: "[n] -> [{ S_1[i, j] -> [(i - 32*floor((i)/32))]; S_2[i] -> [(i - 32*floor((i)/32))] }, { S_1[i, j] -> [(j - 32*floor((j)/32))]; S_2[i] -> [(n - 32*floor((n)/32))] }]"
+          permutable: 1
+          options: "{ separate[i0] : i0 >= 0 and i0 <= 1 }"
+          child:
+            sequence:
+            - filter: "[n] -> { S_1[i, j] }"
+            - filter: "[n] -> { S_2[i] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/jacobi_kernel4.c b/final/lib/External/isl/test_inputs/codegen/jacobi_kernel4.c
new file mode 100644
index 0000000..97b4544
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/jacobi_kernel4.c
@@ -0,0 +1,2 @@
+if (8 * a + 64 * b >= t0 + 2 * t + 512 * floord(-t0 - 8 * a + 64 * b + 2 * t - 1, 512) + 512 && t0 + 512 * floord(-t0 - 8 * a + 64 * b + 2 * t - 1, 512) >= -511 && t0 + 512 * floord(-t0 - 8 * a + 64 * b + 2 * t - 1, 512) <= 1310206)
+  S_0(t, -((-t0 - 8 * a + 64 * b + 2 * t + 511) % 512) - 8 * a + 64 * b + 2 * t + 511);
diff --git a/final/lib/External/isl/test_inputs/codegen/jacobi_kernel4.in b/final/lib/External/isl/test_inputs/codegen/jacobi_kernel4.in
new file mode 100644
index 0000000..9eadc1b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/jacobi_kernel4.in
@@ -0,0 +1,4 @@
+# Check that an affine value is extracted for the final dimension
+[t0,a,b,t] -> { S_0[t, i] -> [i, t0] : exists (e0 = [(t0 - i)/512]:  512e0 = t0 - i and 64b >= 2t + i - 8a and 64b <= -2t + i + 8a and 4a <= 3 + t and 4a >= t and t >= 0 and t <= 1999 and i >= 1 and i <= 1310718 and a >= 0 and a <= 500 and 8b <= 163839 + a and b <= 20480 and 8b >= 1 - a and b >= 0 and 32b <= 655359 - t + 4a and 32b >= 1 + t - 4a and t0 >= 0 and t0 <= 511) }
+[t0,a,b,t] -> { :  t <= -1 + 4a + 32b and t >= 0 and t <= 4a and t >= -3 + 4a and t <= 1999 and t <= 655359 + 4a - 32b and t0 >= 0 and t0 <= 511 }
+[t0] -> {  }
diff --git a/final/lib/External/isl/test_inputs/codegen/lu.c b/final/lib/External/isl/test_inputs/codegen/lu.c
new file mode 100644
index 0000000..022d6f2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/lu.c
@@ -0,0 +1,18 @@
+for (int c0 = 0; c0 < n - 1; c0 += 32)
+  for (int c1 = c0; c1 < n; c1 += 32)
+    for (int c2 = c0; c2 < n; c2 += 32) {
+      if (c1 >= c0 + 32) {
+        for (int c3 = c0; c3 <= min(c0 + 31, c2 + 30); c3 += 1)
+          for (int c4 = c1; c4 <= min(n - 1, c1 + 31); c4 += 1)
+            for (int c5 = max(c2, c3 + 1); c5 <= min(n - 1, c2 + 31); c5 += 1)
+              S_6(c3, c4, c5);
+      } else {
+        for (int c3 = c0; c3 <= min(min(n - 2, c0 + 31), c2 + 30); c3 += 1) {
+          for (int c5 = max(c2, c3 + 1); c5 <= min(n - 1, c2 + 31); c5 += 1)
+            S_2(c3, c5);
+          for (int c4 = c3 + 1; c4 <= min(n - 1, c0 + 31); c4 += 1)
+            for (int c5 = max(c2, c3 + 1); c5 <= min(n - 1, c2 + 31); c5 += 1)
+              S_6(c3, c4, c5);
+        }
+      }
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/lu.in b/final/lib/External/isl/test_inputs/codegen/lu.in
new file mode 100644
index 0000000..ea884f5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/lu.in
@@ -0,0 +1,4 @@
+# Check that the stride of the second loop is properly detected
+[n] -> { S_2[k, j] -> [o0, o0, o2, k, k, j, 1] : exists (e0 = floor((o2)/32), e1 = floor((o0)/32): 32e0 = o2 and 32e1 = o0 and o0 <= k and o0 >= -31 + k and k >= 0 and j <= -1 + n and o2 <= j and o2 >= -31 + j and j >= 1 + k); S_6[k, i, j] -> [o0, o1, o2, k, i, j, 0] : exists (e0 = floor((o0)/32), e1 = floor((o1)/32), e2 = floor((o2)/32): 32e0 = o0 and 32e1 = o1 and 32e2 = o2 and o0 <= k and o0 >= -31 + k and o1 <= i and o1 >= -31 + i and o2 <= j and o2 >= -31 + j and k >= 0 and i >= 1 + k and j <= -1 + n and j >= 1 + k and i <= -1 + n) }
+{  :  }
+{ [a,b,c,d,e,f,g] -> atomic[x] : x < 3; [a,b,c,d,e,f,g] -> separate[x] : x >= 3  }
diff --git a/final/lib/External/isl/test_inputs/codegen/mod.c b/final/lib/External/isl/test_inputs/codegen/mod.c
new file mode 100644
index 0000000..dcd8319
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/mod.c
@@ -0,0 +1,2 @@
+if (2 * (n % 100) == 3 * (m % 200))
+  A();
diff --git a/final/lib/External/isl/test_inputs/codegen/mod.in b/final/lib/External/isl/test_inputs/codegen/mod.in
new file mode 100644
index 0000000..7a04c5a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/mod.in
@@ -0,0 +1,4 @@
+# check that modulo constraint is generated correctly
+[n, m] -> { A[] -> [] : 2 * (n % 100) = 3 * (m % 200) }
+[n, m] -> { : m, n >= 0 }
+{}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/README b/final/lib/External/isl/test_inputs/codegen/omega/README
new file mode 100644
index 0000000..80e27fd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/README
@@ -0,0 +1,5 @@
+The tests in this directory have been adapted from the corresponding omega+
+test cases.
+The options have been derived semi-automatically and may not always
+correspond to the intended meaning of the specified "effort" in the omega+
+test cases.
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/basics-0.c b/final/lib/External/isl/test_inputs/codegen/omega/basics-0.c
new file mode 100644
index 0000000..53995e9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/basics-0.c
@@ -0,0 +1,8 @@
+{
+  for (int c0 = 5; c0 <= 8; c0 += 1)
+    s0(c0);
+  for (int c0 = 10; c0 <= 16; c0 += 2)
+    s0(c0);
+  for (int c0 = 20; c0 <= 25; c0 += 1)
+    s0(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/basics-0.in b/final/lib/External/isl/test_inputs/codegen/omega/basics-0.in
new file mode 100644
index 0000000..025da3d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/basics-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1] -> [In_1] : (In_1 >= 5 and In_1 <= 8) or (exists (e0 = [(In_1)/2]: 2e0 = In_1 and In_1 >= 10 and In_1 <= 16)) or (In_1 >= 20 and In_1 <= 25) }
+{  :  }
+{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/basics-1.c b/final/lib/External/isl/test_inputs/codegen/omega/basics-1.c
new file mode 100644
index 0000000..d3d6970
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/basics-1.c
@@ -0,0 +1,3 @@
+for (int c0 = -9; c0 <= 9; c0 += 1)
+  for (int c1 = max(1, -c0 + 1); c1 <= min(10, -c0 + 10); c1 += 1)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/basics-1.in b/final/lib/External/isl/test_inputs/codegen/omega/basics-1.in
new file mode 100644
index 0000000..82e1093
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/basics-1.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, In_2] : In_2 >= 1 - In_1 and In_2 >= 1 and In_2 <= 10 - In_1 and In_2 <= 10 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/chosol-0.c b/final/lib/External/isl/test_inputs/codegen/omega/chosol-0.c
new file mode 100644
index 0000000..464ee49
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/chosol-0.c
@@ -0,0 +1,9 @@
+{
+  for (int c1 = 2; c1 <= n; c1 += 1)
+    s0(c1);
+  for (int c1 = 1; c1 < n; c1 += 1) {
+    for (int c3 = c1 + 1; c3 <= n; c3 += 1)
+      s1(c3, c1);
+    s2(c1 + 1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/chosol-0.in b/final/lib/External/isl/test_inputs/codegen/omega/chosol-0.in
new file mode 100644
index 0000000..81fde50
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/chosol-0.in
@@ -0,0 +1,3 @@
+[n] -> { s0[i] -> [0, i, 0, 0] : i >= 2 and i <= n; s1[i, j] -> [1, j, 0, i] : j >= 1 and j <= -1 + i and i <= n; s2[i] -> [1, -1 + i, 1, 0] : i >= 2 and i <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/chosol-1.c b/final/lib/External/isl/test_inputs/codegen/omega/chosol-1.c
new file mode 100644
index 0000000..464ee49
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/chosol-1.c
@@ -0,0 +1,9 @@
+{
+  for (int c1 = 2; c1 <= n; c1 += 1)
+    s0(c1);
+  for (int c1 = 1; c1 < n; c1 += 1) {
+    for (int c3 = c1 + 1; c3 <= n; c3 += 1)
+      s1(c3, c1);
+    s2(c1 + 1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/chosol-1.in b/final/lib/External/isl/test_inputs/codegen/omega/chosol-1.in
new file mode 100644
index 0000000..b5abf29
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/chosol-1.in
@@ -0,0 +1,3 @@
+[n] -> { s0[i] -> [0, i, 0, 0] : i >= 2 and i <= n; s1[i, j] -> [1, j, 0, i] : j >= 1 and j <= -1 + i and i <= n; s2[i] -> [1, -1 + i, 1, 0] : i >= 2 and i <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 1; [i0, i1, i2, i3] -> separate[o0] : o0 >= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/code_gen-0.c b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-0.c
new file mode 100644
index 0000000..6340134
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-0.c
@@ -0,0 +1,7 @@
+for (int c0 = 1; c0 <= 8; c0 += 1)
+  for (int c1 = 0; c1 <= 7; c1 += 1) {
+    if (c0 >= 2 && c0 <= 6 && c1 <= 4)
+      s1(c0, c1);
+    if (c1 + 1 >= c0)
+      s0(c0, c1);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/code_gen-0.in b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-0.in
new file mode 100644
index 0000000..a3fa3b1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-0.in
@@ -0,0 +1,3 @@
+{ s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_1 <= 6 and In_2 >= 0 and In_2 <= 4; s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_2 >= -1 + In_1 and In_2 <= 7 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 1; [i0, i1] -> separate[o0] : o0 >= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/code_gen-1.c b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-1.c
new file mode 100644
index 0000000..1c554dc
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-1.c
@@ -0,0 +1,16 @@
+for (int c0 = 1; c0 <= 8; c0 += 1) {
+  if (c0 >= 2) {
+    if (c0 <= 6)
+      for (int c1 = 0; c1 < c0 - 1; c1 += 1)
+        s1(c0, c1);
+    for (int c1 = c0 - 1; c1 <= 4; c1 += 1) {
+      s1(c0, c1);
+      s0(c0, c1);
+    }
+    for (int c1 = max(5, c0 - 1); c1 <= 7; c1 += 1)
+      s0(c0, c1);
+  } else {
+    for (int c1 = 0; c1 <= 7; c1 += 1)
+      s0(1, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/code_gen-1.in b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-1.in
new file mode 100644
index 0000000..c6f7fa5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-1.in
@@ -0,0 +1,3 @@
+{ s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_1 <= 6 and In_2 >= 0 and In_2 <= 4; s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_2 >= -1 + In_1 and In_2 <= 7 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/code_gen-2.c b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-2.c
new file mode 100644
index 0000000..f92e583
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-2.c
@@ -0,0 +1,17 @@
+{
+  for (int c1 = 0; c1 <= 7; c1 += 1)
+    s0(1, c1);
+  for (int c0 = 2; c0 <= 6; c0 += 1) {
+    for (int c1 = 0; c1 < c0 - 1; c1 += 1)
+      s1(c0, c1);
+    for (int c1 = c0 - 1; c1 <= 4; c1 += 1) {
+      s1(c0, c1);
+      s0(c0, c1);
+    }
+    for (int c1 = 5; c1 <= 7; c1 += 1)
+      s0(c0, c1);
+  }
+  for (int c0 = 7; c0 <= 8; c0 += 1)
+    for (int c1 = c0 - 1; c1 <= 7; c1 += 1)
+      s0(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/code_gen-2.in b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-2.in
new file mode 100644
index 0000000..03a7b5d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-2.in
@@ -0,0 +1,3 @@
+{ s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_1 <= 6 and In_2 >= 0 and In_2 <= 4; s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_2 >= -1 + In_1 and In_2 <= 7 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= -1; [i0, i1] -> separate[o0] : o0 >= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/collard-0.c b/final/lib/External/isl/test_inputs/codegen/omega/collard-0.c
new file mode 100644
index 0000000..413fbda
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/collard-0.c
@@ -0,0 +1,16 @@
+{
+  for (int c4 = 1; c4 <= n; c4 += 1)
+    s2(c4);
+  for (int c1 = 1; c1 < n; c1 += 1) {
+    for (int c4 = 0; c4 < n - c1; c4 += 1)
+      s0(c1, n - c4);
+    for (int c3 = 0; c3 < n - c1; c3 += 1)
+      for (int c4 = c1 + 1; c4 <= n; c4 += 1)
+        s1(c1, n - c3, c4);
+  }
+  for (int c1 = 1; c1 <= n; c1 += 1) {
+    s4(c1);
+    for (int c3 = c1 + 1; c3 <= n; c3 += 1)
+      s3(c3, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/collard-0.in b/final/lib/External/isl/test_inputs/codegen/omega/collard-0.in
new file mode 100644
index 0000000..d803da7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/collard-0.in
@@ -0,0 +1,3 @@
+[n] -> { s1[i, j, k] -> [1, i, 1, n - j, k] : j >= 1 + i and k >= 1 + i and i >= 1 and j <= n and k <= n; s2[i] -> [0, 0, 0, 0, i] : i >= 1 and i <= n; s4[i] -> [2, i, 0, 0, 0] : i >= 1 and i <= n; s0[i, j] -> [1, i, 0, n - i, n - j] : i >= 1 and j >= 1 + i and j <= n; s3[i, j] -> [2, j, 1, i, j] : j >= 1 and j <= -1 + i and i <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 4; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/dagstuhl1-0.c b/final/lib/External/isl/test_inputs/codegen/omega/dagstuhl1-0.c
new file mode 100644
index 0000000..3e403dd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/dagstuhl1-0.c
@@ -0,0 +1,2 @@
+for (int c0 = 0; c0 <= 99; c0 += 1)
+  s0(c0 % 10, c0 / 10);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/dagstuhl1-0.in b/final/lib/External/isl/test_inputs/codegen/omega/dagstuhl1-0.in
new file mode 100644
index 0000000..0c2b107
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/dagstuhl1-0.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [i + 10j] : i >= 0 and i <= 9 and j >= 0 and j <= 9 }
+{  :  }
+{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/dagstuhl1-1.c b/final/lib/External/isl/test_inputs/codegen/omega/dagstuhl1-1.c
new file mode 100644
index 0000000..98953fb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/dagstuhl1-1.c
@@ -0,0 +1,2 @@
+for (int c0 = 0; c0 <= 99; c0 += 1)
+  s0(c0, c0 % 10, c0 / 10);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/dagstuhl1-1.in b/final/lib/External/isl/test_inputs/codegen/omega/dagstuhl1-1.in
new file mode 100644
index 0000000..e0c7273
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/dagstuhl1-1.in
@@ -0,0 +1,3 @@
+{s0[p,i,j] -> [p,i,j] : 0 <= i,j <= 9 && p = i+10j}
+{  :  }
+{ [p,i,j] -> separate[o0] : o0 >= 2; [p,i,j] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/fc1-0.c b/final/lib/External/isl/test_inputs/codegen/omega/fc1-0.c
new file mode 100644
index 0000000..fbec13a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/fc1-0.c
@@ -0,0 +1,7 @@
+for (int c0 = 0; c0 < n - 1; c0 += 1) {
+  for (int c3 = 0; c3 < n - c0 - 1; c3 += 1)
+    s0(c0 + 1, n - c3);
+  for (int c3 = 0; c3 < n - c0 - 1; c3 += 1)
+    for (int c6 = c0 + 2; c6 <= n; c6 += 1)
+      s1(c0 + 1, n - c3, c6);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/fc1-0.in b/final/lib/External/isl/test_inputs/codegen/omega/fc1-0.in
new file mode 100644
index 0000000..688f958
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/fc1-0.in
@@ -0,0 +1,3 @@
+[n] -> { s0[i, j] -> [-1 + i, 0, n - i, n - j] : i >= 1 and j >= 1 + i and j <= n; s1[i, j, k] -> [-1 + i, 1, n - i, n - j] : j >= 1 + i and k >= 1 + i and i >= 1 and j <= n and k <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/fc1-1.c b/final/lib/External/isl/test_inputs/codegen/omega/fc1-1.c
new file mode 100644
index 0000000..768a04f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/fc1-1.c
@@ -0,0 +1,17 @@
+{
+  for (int c3 = 1; c3 <= n; c3 += 1)
+    s2(c3);
+  for (int c0 = 0; c0 < n - 1; c0 += 1) {
+    for (int c3 = 0; c3 < n - c0 - 1; c3 += 1)
+      s0(c0 + 1, n - c3);
+    for (int c3 = 0; c3 < n - c0 - 1; c3 += 1)
+      for (int c6 = c0 + 2; c6 <= n; c6 += 1)
+        s1(c0 + 1, n - c3, c6);
+  }
+  for (int c0 = n - 1; c0 < 2 * n - 1; c0 += 1) {
+    if (c0 >= n)
+      for (int c2 = -n + c0 + 2; c2 <= n; c2 += 1)
+        s3(c2, -n + c0 + 1);
+    s4(-n + c0 + 2);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/fc1-1.in b/final/lib/External/isl/test_inputs/codegen/omega/fc1-1.in
new file mode 100644
index 0000000..c9135ff
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/fc1-1.in
@@ -0,0 +1,3 @@
+[n] -> { s1[i, j, k] -> [-1 + i, 1, n - i, n - j] : j >= 1 + i and k >= 1 + i and i >= 1 and j <= n and k <= n; s3[i, j] -> [-1 + n + j, 0, i, j] : j >= 1 and j <= -1 + i and i <= n; s4[i] -> [-2 + n + i, 1, 0, 0] : i >= 1 and i <= n; s0[i, j] -> [-1 + i, 0, n - i, n - j] : i >= 1 and j >= 1 + i and j <= n; s2[i] -> [0, 0, 0, i] : i >= 1 and i <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/fc1-2.c b/final/lib/External/isl/test_inputs/codegen/omega/fc1-2.c
new file mode 100644
index 0000000..768a04f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/fc1-2.c
@@ -0,0 +1,17 @@
+{
+  for (int c3 = 1; c3 <= n; c3 += 1)
+    s2(c3);
+  for (int c0 = 0; c0 < n - 1; c0 += 1) {
+    for (int c3 = 0; c3 < n - c0 - 1; c3 += 1)
+      s0(c0 + 1, n - c3);
+    for (int c3 = 0; c3 < n - c0 - 1; c3 += 1)
+      for (int c6 = c0 + 2; c6 <= n; c6 += 1)
+        s1(c0 + 1, n - c3, c6);
+  }
+  for (int c0 = n - 1; c0 < 2 * n - 1; c0 += 1) {
+    if (c0 >= n)
+      for (int c2 = -n + c0 + 2; c2 <= n; c2 += 1)
+        s3(c2, -n + c0 + 1);
+    s4(-n + c0 + 2);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/fc1-2.in b/final/lib/External/isl/test_inputs/codegen/omega/fc1-2.in
new file mode 100644
index 0000000..6d9a162
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/fc1-2.in
@@ -0,0 +1,3 @@
+[n] -> { s1[i, j, k] -> [-1 + i, 1, n - i, n - j] : j >= 1 + i and k >= 1 + i and i >= 1 and j <= n and k <= n; s3[i, j] -> [-1 + n + j, 0, i, j] : j >= 1 and j <= -1 + i and i <= n; s4[i] -> [-2 + n + i, 1, 0, 0] : i >= 1 and i <= n; s0[i, j] -> [-1 + i, 0, n - i, n - j] : i >= 1 and j >= 1 + i and j <= n; s2[i] -> [0, 0, 0, i] : i >= 1 and i <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 1; [i0, i1, i2, i3] -> separate[o0] : o0 >= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/fc2-0.c b/final/lib/External/isl/test_inputs/codegen/omega/fc2-0.c
new file mode 100644
index 0000000..fbec13a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/fc2-0.c
@@ -0,0 +1,7 @@
+for (int c0 = 0; c0 < n - 1; c0 += 1) {
+  for (int c3 = 0; c3 < n - c0 - 1; c3 += 1)
+    s0(c0 + 1, n - c3);
+  for (int c3 = 0; c3 < n - c0 - 1; c3 += 1)
+    for (int c6 = c0 + 2; c6 <= n; c6 += 1)
+      s1(c0 + 1, n - c3, c6);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/fc2-0.in b/final/lib/External/isl/test_inputs/codegen/omega/fc2-0.in
new file mode 100644
index 0000000..688f958
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/fc2-0.in
@@ -0,0 +1,3 @@
+[n] -> { s0[i, j] -> [-1 + i, 0, n - i, n - j] : i >= 1 and j >= 1 + i and j <= n; s1[i, j, k] -> [-1 + i, 1, n - i, n - j] : j >= 1 + i and k >= 1 + i and i >= 1 and j <= n and k <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/fc2-1.c b/final/lib/External/isl/test_inputs/codegen/omega/fc2-1.c
new file mode 100644
index 0000000..768a04f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/fc2-1.c
@@ -0,0 +1,17 @@
+{
+  for (int c3 = 1; c3 <= n; c3 += 1)
+    s2(c3);
+  for (int c0 = 0; c0 < n - 1; c0 += 1) {
+    for (int c3 = 0; c3 < n - c0 - 1; c3 += 1)
+      s0(c0 + 1, n - c3);
+    for (int c3 = 0; c3 < n - c0 - 1; c3 += 1)
+      for (int c6 = c0 + 2; c6 <= n; c6 += 1)
+        s1(c0 + 1, n - c3, c6);
+  }
+  for (int c0 = n - 1; c0 < 2 * n - 1; c0 += 1) {
+    if (c0 >= n)
+      for (int c2 = -n + c0 + 2; c2 <= n; c2 += 1)
+        s3(c2, -n + c0 + 1);
+    s4(-n + c0 + 2);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/fc2-1.in b/final/lib/External/isl/test_inputs/codegen/omega/fc2-1.in
new file mode 100644
index 0000000..c9135ff
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/fc2-1.in
@@ -0,0 +1,3 @@
+[n] -> { s1[i, j, k] -> [-1 + i, 1, n - i, n - j] : j >= 1 + i and k >= 1 + i and i >= 1 and j <= n and k <= n; s3[i, j] -> [-1 + n + j, 0, i, j] : j >= 1 and j <= -1 + i and i <= n; s4[i] -> [-2 + n + i, 1, 0, 0] : i >= 1 and i <= n; s0[i, j] -> [-1 + i, 0, n - i, n - j] : i >= 1 and j >= 1 + i and j <= n; s2[i] -> [0, 0, 0, i] : i >= 1 and i <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-0.c b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-0.c
new file mode 100644
index 0000000..db7f437
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-0.c
@@ -0,0 +1,2 @@
+for (int c0 = 4 * floord(m - 1, 12) + 4; c0 <= floord(n, 3); c0 += 4)
+  s0(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-0.in b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-0.in
new file mode 100644
index 0000000..45faa57
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-0.in
@@ -0,0 +1,3 @@
+[m, n] -> { s0[In_1] -> [In_1] : exists (e0 = [(In_1)/4]: 4e0 = In_1 and 3In_1 >= m and 3In_1 <= n) }
+{  :  }
+[m, n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-1.c b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-1.c
new file mode 100644
index 0000000..bc87982
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-1.c
@@ -0,0 +1,2 @@
+for (int c0 = floord(m, 4); c0 <= n; c0 += 1)
+  s0(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-1.in b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-1.in
new file mode 100644
index 0000000..7ae72ab
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-1.in
@@ -0,0 +1,3 @@
+[m, n] -> { s0[In_1] -> [In_1] : 4In_1 >= -3 + m and In_1 <= n }
+{  :  }
+[m, n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-2.c b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-2.c
new file mode 100644
index 0000000..ff5f3c3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-2.c
@@ -0,0 +1,2 @@
+for (int c0 = 4 * floord(m, 4); c0 <= n; c0 += 1)
+  s0(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-2.in b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-2.in
new file mode 100644
index 0000000..73e1b8e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-2.in
@@ -0,0 +1,3 @@
+[m, n] -> { s0[In_1] -> [In_1] : exists (e0 = [(m)/4]: 4e0 <= m and 4e0 >= -3 + m and 4e0 <= In_1 and In_1 <= n) }
+{  :  }
+[m, n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-3.c b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-3.c
new file mode 100644
index 0000000..e3c9728
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-3.c
@@ -0,0 +1,2 @@
+for (int c0 = 3 * floord(m, 3) + 4 * floord(m, 4); c0 <= n; c0 += 1)
+  s0(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-3.in b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-3.in
new file mode 100644
index 0000000..1ff7e2c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-3.in
@@ -0,0 +1,3 @@
+[m, n] -> { s0[In_1] -> [In_1] : exists (e0 = [(m)/3], e1 = [(m)/4]: 4e1 <= m and 3e0 <= m and 4e1 >= -3 + m and 3e0 >= -2 + m and In_1 <= n and 4e1 <= In_1 - 3e0) }
+{  :  }
+[m, n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-4.c b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-4.c
new file mode 100644
index 0000000..dc6ba0a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-4.c
@@ -0,0 +1,3 @@
+if (n >= 3 * floord(n + 1, 3))
+  for (int c0 = m; c0 <= 5 * floord(n + 1, 3); c0 += 1)
+    s0(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-4.in b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-4.in
new file mode 100644
index 0000000..7a726c3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-4.in
@@ -0,0 +1,3 @@
+[n, m] -> { s0[In_1] -> [In_1] : exists (e0 = [(1 + n)/3]: In_1 >= m and 5e0 >= In_1 and 3e0 <= n and 3e0 >= -1 + n) }
+{  :  }
+[n, m] -> { [i0] -> atomic[o0] : o0 <= -1; [i0] -> separate[o0] : o0 >= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-5.c b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-5.c
new file mode 100644
index 0000000..3e9f47d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-5.c
@@ -0,0 +1,2 @@
+for (int c0 = 4 * floord(m, 32); c0 <= n; c0 += 1)
+  s0(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-5.in b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-5.in
new file mode 100644
index 0000000..cc24250
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-5.in
@@ -0,0 +1,3 @@
+[m, n] -> { s0[In_1] -> [In_1] : exists (e0 = [(m)/32]: 32e0 <= m and 32e0 >= -31 + m and 4e0 <= In_1 and In_1 <= n) }
+{  :  }
+[m, n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-6.c b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-6.c
new file mode 100644
index 0000000..743b0c9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-6.c
@@ -0,0 +1,3 @@
+if (m >= 8 * floord(m + 1, 8))
+  for (int c0 = 4 * floord(m + 1, 32); c0 <= n; c0 += 1)
+    s0(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-6.in b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-6.in
new file mode 100644
index 0000000..78d2be9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/floor_bound-6.in
@@ -0,0 +1,3 @@
+[m, n] -> { s0[In_1] -> [In_1] : exists (e0 = [(1 + m)/8], e1 = [(e0)/4]: 8e0 <= m and 8e0 >= -6 + m and 4e1 <= In_1 and In_1 <= n and 32e1 <= 1 + m and 32e1 >= -30 + m) }
+{  :  }
+[m, n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gc-0.c b/final/lib/External/isl/test_inputs/codegen/omega/gc-0.c
new file mode 100644
index 0000000..d8234a3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gc-0.c
@@ -0,0 +1,2 @@
+for (int c0 = 2; c0 <= 8; c0 += 2)
+  s0(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gc-0.in b/final/lib/External/isl/test_inputs/codegen/omega/gc-0.in
new file mode 100644
index 0000000..063e353
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gc-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1] -> [In_1] : exists (e0 = [(In_1)/2]: 2e0 = In_1 and In_1 >= 2 and In_1 <= 8) }
+{  :  }
+{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/ge-0.c b/final/lib/External/isl/test_inputs/codegen/omega/ge-0.c
new file mode 100644
index 0000000..1c22a5d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ge-0.c
@@ -0,0 +1,7 @@
+for (int c0 = 2; c0 <= n; c0 += 1)
+  for (int c1 = 1; c1 <= n; c1 += 1) {
+    for (int c3 = 1; c3 < min(c0, c1); c3 += 1)
+      s1(c3, c0, c1);
+    if (c0 >= c1 + 1)
+      s0(c1, c0);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/ge-0.in b/final/lib/External/isl/test_inputs/codegen/omega/ge-0.in
new file mode 100644
index 0000000..edd7c36
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ge-0.in
@@ -0,0 +1,3 @@
+[n] -> { s0[k, i] -> [i, k, 1, 0] : k >= 1 and i >= 1 + k and i <= n; s1[k, i, j] -> [i, j, 0, k] : i >= 1 + k and j >= 1 + k and k >= 1 and i <= n and j <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/ge-1.c b/final/lib/External/isl/test_inputs/codegen/omega/ge-1.c
new file mode 100644
index 0000000..1c22a5d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ge-1.c
@@ -0,0 +1,7 @@
+for (int c0 = 2; c0 <= n; c0 += 1)
+  for (int c1 = 1; c1 <= n; c1 += 1) {
+    for (int c3 = 1; c3 < min(c0, c1); c3 += 1)
+      s1(c3, c0, c1);
+    if (c0 >= c1 + 1)
+      s0(c1, c0);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/ge-1.in b/final/lib/External/isl/test_inputs/codegen/omega/ge-1.in
new file mode 100644
index 0000000..4a08142
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ge-1.in
@@ -0,0 +1,3 @@
+[n] -> { s0[k, i] -> [i, k, 1, 0] : k >= 1 and i >= 1 + k and i <= n; s1[k, i, j] -> [i, j, 0, k] : i >= 1 + k and j >= 1 + k and k >= 1 and i <= n and j <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 1; [i0, i1, i2, i3] -> separate[o0] : o0 >= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gist-0.c b/final/lib/External/isl/test_inputs/codegen/omega/gist-0.c
new file mode 100644
index 0000000..4608d61
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gist-0.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= n; c0 += 4)
+  for (int c1 = c0; c1 <= n; c1 += 3)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gist-0.in b/final/lib/External/isl/test_inputs/codegen/omega/gist-0.in
new file mode 100644
index 0000000..b2f3366
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gist-0.in
@@ -0,0 +1,3 @@
+[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-1 + In_1)/4], e1 = [(-3 - In_1 + 4In_2)/12]: 4e0 = -1 + In_1 and 12e1 = -3 - In_1 + 4In_2 and In_1 >= 1 and In_2 >= In_1 and In_2 <= n) }
+{  :  }
+[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gist-1.c b/final/lib/External/isl/test_inputs/codegen/omega/gist-1.c
new file mode 100644
index 0000000..8f1c692
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gist-1.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= n; c0 += 4)
+  for (int c1 = c0; c1 <= n; c1 += 8)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gist-1.in b/final/lib/External/isl/test_inputs/codegen/omega/gist-1.in
new file mode 100644
index 0000000..ecbf8e7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gist-1.in
@@ -0,0 +1,3 @@
+[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-1 + In_1)/4], e1 = [(-In_1 + In_2)/8]: 4e0 = -1 + In_1 and 8e1 = -In_1 + In_2 and In_1 >= 1 and In_2 >= In_1 and In_2 <= n) }
+{  :  }
+[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gist-2.c b/final/lib/External/isl/test_inputs/codegen/omega/gist-2.c
new file mode 100644
index 0000000..3174987
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gist-2.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= n; c0 += 256)
+  for (int c1 = c0; c1 <= n; c1 += 8)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gist-2.in b/final/lib/External/isl/test_inputs/codegen/omega/gist-2.in
new file mode 100644
index 0000000..63edb52
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gist-2.in
@@ -0,0 +1,3 @@
+[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-1 + In_1)/256], e1 = [(-1 + In_2)/8]: 256e0 = -1 + In_1 and 8e1 = -1 + In_2 and In_1 >= 1 and In_2 >= In_1 and In_2 <= n) }
+{  :  }
+[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gist-3.c b/final/lib/External/isl/test_inputs/codegen/omega/gist-3.c
new file mode 100644
index 0000000..513f385
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gist-3.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 < n; c0 += 4)
+  for (int c1 = c0 + 1; c1 <= n; c1 += 6)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gist-3.in b/final/lib/External/isl/test_inputs/codegen/omega/gist-3.in
new file mode 100644
index 0000000..43cac12
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gist-3.in
@@ -0,0 +1,3 @@
+[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-1 + In_1)/4], e1 = [(-1 - In_1 + In_2)/6]: 4e0 = -1 + In_1 and 6e1 = -1 - In_1 + In_2 and In_1 >= 1 and In_2 >= 1 + In_1 and In_2 <= n) }
+{  :  }
+[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gist-4.c b/final/lib/External/isl/test_inputs/codegen/omega/gist-4.c
new file mode 100644
index 0000000..a6f6fd0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gist-4.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= n; c0 += 6)
+  for (int c1 = c0; c1 <= n; c1 += 4)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gist-4.in b/final/lib/External/isl/test_inputs/codegen/omega/gist-4.in
new file mode 100644
index 0000000..f67f837
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gist-4.in
@@ -0,0 +1,3 @@
+[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-1 + In_1)/6], e1 = [(-2 - In_1 + 3In_2)/12]: 6e0 = -1 + In_1 and 12e1 = -2 - In_1 + 3In_2 and In_1 >= 1 and In_2 >= In_1 and In_2 <= n) }
+{  :  }
+[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gist-5.c b/final/lib/External/isl/test_inputs/codegen/omega/gist-5.c
new file mode 100644
index 0000000..c2df61f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gist-5.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= n; c0 += 12)
+  for (int c1 = c0; c1 <= n; c1 += 8)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/gist-5.in b/final/lib/External/isl/test_inputs/codegen/omega/gist-5.in
new file mode 100644
index 0000000..8b192c1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/gist-5.in
@@ -0,0 +1,3 @@
+[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-1 + In_1)/12], e1 = [(-2 - In_1 + 3In_2)/24]: 12e0 = -1 + In_1 and 24e1 = -2 - In_1 + 3In_2 and In_1 >= 1 and In_2 >= In_1 and In_2 <= n) }
+{  :  }
+[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/guard1-0.c b/final/lib/External/isl/test_inputs/codegen/omega/guard1-0.c
new file mode 100644
index 0000000..e430f2b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/guard1-0.c
@@ -0,0 +1,2 @@
+if ((n - m - 1) % 3 == 0)
+  s0(n, m);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/guard1-0.in b/final/lib/External/isl/test_inputs/codegen/omega/guard1-0.in
new file mode 100644
index 0000000..52964e2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/guard1-0.in
@@ -0,0 +1,3 @@
+[n, m] -> { s0[n, m] -> [n, m] : exists (e0 = [(-2 - n + m)/3]: 3e0 = -2 - n + m) }
+{  :  }
+[n, m] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/guard1-1.c b/final/lib/External/isl/test_inputs/codegen/omega/guard1-1.c
new file mode 100644
index 0000000..3994a61
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/guard1-1.c
@@ -0,0 +1,2 @@
+if ((n + m + 1) % 2 == 0)
+  s0(n, m);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/guard1-1.in b/final/lib/External/isl/test_inputs/codegen/omega/guard1-1.in
new file mode 100644
index 0000000..141f585
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/guard1-1.in
@@ -0,0 +1,3 @@
+[n, m] -> { s0[n, m] -> [n, m] : exists (e0 = [(-1 - n + m)/2]: 2e0 = -1 - n + m) }
+{  :  }
+[n, m] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/hpf-0.c b/final/lib/External/isl/test_inputs/codegen/omega/hpf-0.c
new file mode 100644
index 0000000..c676558
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/hpf-0.c
@@ -0,0 +1,4 @@
+if (P2 >= 0 && P2 <= 3 && P1 == P2)
+  for (int c0 = 0; c0 <= min(2, -P2 + 4); c0 += 1)
+    for (int c2 = (-P2 - c0 + 6) % 3; c2 <= 3; c2 += 3)
+      s0(c0, c0, c2, c2);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/hpf-0.in b/final/lib/External/isl/test_inputs/codegen/omega/hpf-0.in
new file mode 100644
index 0000000..e697792
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/hpf-0.in
@@ -0,0 +1,3 @@
+[P1, P2] -> { s0[In_1, In_1, In_3, In_3] -> [In_1, In_1, In_3, In_3] : exists (e0 = [(-2P2 - 2In_1 + In_3)/3]: P1 = P2 and 3e0 = -2P2 - 2In_1 + In_3 and P2 >= 0 and P2 <= 3 and In_1 <= 4 - P2 and In_1 >= 0 and In_1 <= 2 and In_3 >= 0 and In_3 <= 3) }
+{  :  }
+[P2, P1] -> { [i0, i1, i2, i3] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/if_then-0.c b/final/lib/External/isl/test_inputs/codegen/omega/if_then-0.c
new file mode 100644
index 0000000..d2e100b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-0.c
@@ -0,0 +1,13 @@
+if (m <= 1) {
+  for (int c0 = 1; c0 <= n; c0 += 1)
+    for (int c1 = 1; c1 <= n; c1 += 1)
+      s2(c0, c1);
+} else if (n >= m + 1) {
+  for (int c0 = 1; c0 <= n; c0 += 1)
+    for (int c1 = 1; c1 <= n; c1 += 1)
+      s0(c0, c1);
+} else {
+  for (int c0 = 1; c0 <= n; c0 += 1)
+    for (int c1 = 1; c1 <= n; c1 += 1)
+      s1(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/if_then-0.in b/final/lib/External/isl/test_inputs/codegen/omega/if_then-0.in
new file mode 100644
index 0000000..93f3f7c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-0.in
@@ -0,0 +1,3 @@
+[n, m] -> { s2[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= n and In_2 >= 1 and In_2 <= n and m <= 1; s0[In_1, In_2] -> [In_1, In_2] : m >= 2 and m <= -1 + n and In_1 >= 1 and In_1 <= n and In_2 >= 1 and In_2 <= n; s1[In_1, In_2] -> [In_1, In_2] : In_1 <= n and In_2 <= n and m >= n and In_1 >= 1 and In_2 >= 1 and m >= 2 }
+{  :  }
+[n, m] -> { [i0, i1] -> atomic[o0] : o0 <= 1; [i0, i1] -> separate[o0] : o0 >= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/if_then-1.c b/final/lib/External/isl/test_inputs/codegen/omega/if_then-1.c
new file mode 100644
index 0000000..5e2cd82
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-1.c
@@ -0,0 +1,9 @@
+for (int c0 = 1; c0 <= 100; c0 += 1) {
+  if (n >= 2)
+    s0(c0);
+  for (int c1 = 1; c1 <= 100; c1 += 1) {
+    s2(c0, c1);
+    if (n >= 2)
+      s1(c0, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/if_then-1.in b/final/lib/External/isl/test_inputs/codegen/omega/if_then-1.in
new file mode 100644
index 0000000..0258439
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-1.in
@@ -0,0 +1,3 @@
+[n] -> { s0[In_1] -> [In_1,0] : In_1 >= 1 and In_1 <= 100 and n >= 2; s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and n >= 2; s2[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 }
+{  :  }
+[n] -> { [i0,i1] -> separate[o0] : o0 >= 2; [i0,i1] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/if_then-2.c b/final/lib/External/isl/test_inputs/codegen/omega/if_then-2.c
new file mode 100644
index 0000000..b3f4a24
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-2.c
@@ -0,0 +1,12 @@
+for (int c0 = 1; c0 <= 100; c0 += 1) {
+  if (n >= 2) {
+    s0(c0);
+    for (int c1 = 1; c1 <= 100; c1 += 1) {
+      s2(c0, c1);
+      s1(c0, c1);
+    }
+  } else {
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      s2(c0, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/if_then-2.in b/final/lib/External/isl/test_inputs/codegen/omega/if_then-2.in
new file mode 100644
index 0000000..0a220ee
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-2.in
@@ -0,0 +1,3 @@
+[n] -> { s0[In_1] -> [In_1,0] : In_1 >= 1 and In_1 <= 100 and n >= 2; s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and n >= 2; s2[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 }
+{  :  }
+[n] -> { [i0,i1] -> separate[o0] : o0 >= 1; [i0,i1] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/if_then-3.c b/final/lib/External/isl/test_inputs/codegen/omega/if_then-3.c
new file mode 100644
index 0000000..94dc201
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-3.c
@@ -0,0 +1,13 @@
+if (n >= 2) {
+  for (int c0 = 1; c0 <= 100; c0 += 1) {
+    s0(c0);
+    for (int c1 = 1; c1 <= 100; c1 += 1) {
+      s2(c0, c1);
+      s1(c0, c1);
+    }
+  }
+} else {
+  for (int c0 = 1; c0 <= 100; c0 += 1)
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      s2(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/if_then-3.in b/final/lib/External/isl/test_inputs/codegen/omega/if_then-3.in
new file mode 100644
index 0000000..a0315f1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-3.in
@@ -0,0 +1,3 @@
+[n] -> { s0[In_1] -> [In_1,0] : In_1 >= 1 and In_1 <= 100 and n >= 2; s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and n >= 2; s2[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 }
+{  :  }
+[n] -> { [i0,i1] -> separate[o0] : o0 >= 0; [i0,i1] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/if_then-4.c b/final/lib/External/isl/test_inputs/codegen/omega/if_then-4.c
new file mode 100644
index 0000000..fa81628
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-4.c
@@ -0,0 +1,7 @@
+for (int c0 = 4; c0 <= 100; c0 += 4) {
+  for (int c1 = 1; c1 <= 100; c1 += 1)
+    s0(c0, c1);
+  if (c0 >= 8 && c0 <= 96)
+    for (int c1 = 10; c1 <= 100; c1 += 1)
+      s1(c0 + 2, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/if_then-4.in b/final/lib/External/isl/test_inputs/codegen/omega/if_then-4.in
new file mode 100644
index 0000000..30dc8dc
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-4.in
@@ -0,0 +1,3 @@
+{ s1[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-2 + In_1)/4]: 4e0 = -2 + In_1 and In_1 >= 10 and In_1 <= 98 and In_2 >= 10 and In_2 <= 100); s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_1)/4]: 4e0 = In_1 and In_1 >= 4 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100) }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 1; [i0, i1] -> separate[o0] : o0 >= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/if_then-5.c b/final/lib/External/isl/test_inputs/codegen/omega/if_then-5.c
new file mode 100644
index 0000000..fa81628
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-5.c
@@ -0,0 +1,7 @@
+for (int c0 = 4; c0 <= 100; c0 += 4) {
+  for (int c1 = 1; c1 <= 100; c1 += 1)
+    s0(c0, c1);
+  if (c0 >= 8 && c0 <= 96)
+    for (int c1 = 10; c1 <= 100; c1 += 1)
+      s1(c0 + 2, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/if_then-5.in b/final/lib/External/isl/test_inputs/codegen/omega/if_then-5.in
new file mode 100644
index 0000000..87a40f4
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-5.in
@@ -0,0 +1,3 @@
+{ s1[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-2 + In_1)/4]: 4e0 = -2 + In_1 and In_1 >= 10 and In_1 <= 98 and In_2 >= 10 and In_2 <= 100); s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_1)/4]: 4e0 = In_1 and In_1 >= 4 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100) }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter1-0.c b/final/lib/External/isl/test_inputs/codegen/omega/iter1-0.c
new file mode 100644
index 0000000..c15c86b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter1-0.c
@@ -0,0 +1,2 @@
+for (int c0 = 2; c0 <= 9; c0 += 1)
+  s0(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter1-0.in b/final/lib/External/isl/test_inputs/codegen/omega/iter1-0.in
new file mode 100644
index 0000000..8b87678
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter1-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1] -> [In_1] : In_1 >= 2 and In_1 <= 9 }
+{  :  }
+{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter2-0.c b/final/lib/External/isl/test_inputs/codegen/omega/iter2-0.c
new file mode 100644
index 0000000..5506929
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter2-0.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= 10; c0 += 1)
+  for (int c1 = 10; c1 <= 100; c1 += 1)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter2-0.in b/final/lib/External/isl/test_inputs/codegen/omega/iter2-0.in
new file mode 100644
index 0000000..16ea0df
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter2-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 10 and In_2 >= 10 and In_2 <= 100 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter3-0.c b/final/lib/External/isl/test_inputs/codegen/omega/iter3-0.c
new file mode 100644
index 0000000..43b6e3a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter3-0.c
@@ -0,0 +1,3 @@
+for (int c0 = 2; c0 <= 8; c0 += 1)
+  for (int c1 = c0 + 1; c1 <= 9; c1 += 1)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter3-0.in b/final/lib/External/isl/test_inputs/codegen/omega/iter3-0.in
new file mode 100644
index 0000000..fc26493
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter3-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_2 >= 1 + In_1 and In_2 <= 9 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter4-0.c b/final/lib/External/isl/test_inputs/codegen/omega/iter4-0.c
new file mode 100644
index 0000000..65e3702
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter4-0.c
@@ -0,0 +1,3 @@
+for (int c0 = 2; c0 <= 9; c0 += 1)
+  for (int c1 = c0 + 1; c1 <= 2 * c0; c1 += 1)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter4-0.in b/final/lib/External/isl/test_inputs/codegen/omega/iter4-0.in
new file mode 100644
index 0000000..94001d5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter4-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_2 >= 1 + In_1 and In_2 <= 2In_1 and In_1 <= 9 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter5-0.c b/final/lib/External/isl/test_inputs/codegen/omega/iter5-0.c
new file mode 100644
index 0000000..66c7c09
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter5-0.c
@@ -0,0 +1,3 @@
+for (int c0 = 2; c0 <= 9; c0 += 1)
+  for (int c1 = c0 + 1; c1 <= min(16, 2 * c0); c1 += 1)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter5-0.in b/final/lib/External/isl/test_inputs/codegen/omega/iter5-0.in
new file mode 100644
index 0000000..1e4f739
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter5-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_2 >= 1 + In_1 and In_2 <= 2In_1 and In_2 <= 16 and In_1 <= 9 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter6-0.c b/final/lib/External/isl/test_inputs/codegen/omega/iter6-0.c
new file mode 100644
index 0000000..a0346b6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter6-0.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= 5; c0 += 1)
+  for (int c1 = 12; c1 <= 17; c1 += 1)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter6-0.in b/final/lib/External/isl/test_inputs/codegen/omega/iter6-0.in
new file mode 100644
index 0000000..1b8ed2b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter6-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 1 and In_1 <= 5 and In_2 >= 12 and In_2 <= 17 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter6-1.c b/final/lib/External/isl/test_inputs/codegen/omega/iter6-1.c
new file mode 100644
index 0000000..daccd39
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter6-1.c
@@ -0,0 +1,2 @@
+for (int c0 = 46; c0 <= 70; c0 += 12)
+  s0(c0, (17 * c0 - 170) / 12);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter6-1.in b/final/lib/External/isl/test_inputs/codegen/omega/iter6-1.in
new file mode 100644
index 0000000..4ee2ad6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter6-1.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, o1] : 12In_2 = -170 + 17In_1 and 12o1 = -170 + 17In_1 and In_1 >= 46 and In_1 <= 70 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter7-0.c b/final/lib/External/isl/test_inputs/codegen/omega/iter7-0.c
new file mode 100644
index 0000000..2606890
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter7-0.c
@@ -0,0 +1,2 @@
+for (int c0 = 1; c0 <= 3; c0 += 2)
+  s0(c0, (-3 * c0 + 15) / 2);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter7-0.in b/final/lib/External/isl/test_inputs/codegen/omega/iter7-0.in
new file mode 100644
index 0000000..90d3efb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter7-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, o1] : 2In_2 = 15 - 3In_1 and 2o1 = 15 - 3In_1 and In_1 <= 3 and In_1 >= 1 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter8-0.c b/final/lib/External/isl/test_inputs/codegen/omega/iter8-0.c
new file mode 100644
index 0000000..a33fc49
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter8-0.c
@@ -0,0 +1,2 @@
+for (int c0 = max(exprVar2 + 1, exprVar2 + 8 * floord(-exprVar2 + exprVar1 - 1, 8) + 9); c0 <= 16; c0 += 8)
+  s0(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter8-0.in b/final/lib/External/isl/test_inputs/codegen/omega/iter8-0.in
new file mode 100644
index 0000000..6829280
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter8-0.in
@@ -0,0 +1,3 @@
+[exprVar2, exprVar3, exprVar1] -> { s0[In_1] -> [In_1] : exists (e0 = [(-1 - exprVar2 + In_1)/8]: exprVar3 = 0 and 8e0 = -1 - exprVar2 + In_1 and exprVar1 >= 1 and In_1 >= 1 + exprVar1 and In_1 <= 16 and In_1 >= 1 + exprVar2) }
+[exprVar3, exprVar2, exprVar1] -> {  : exists (e0: exprVar3 = 0 and 8e0 >= -15 + exprVar2 and exprVar2 <= 15 and exprVar1 >= 1 and 8e0 <= exprVar2 - exprVar1) }
+[exprVar2, exprVar3, exprVar1] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter9-0.c b/final/lib/External/isl/test_inputs/codegen/omega/iter9-0.c
new file mode 100644
index 0000000..baedaa0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter9-0.c
@@ -0,0 +1,11 @@
+for (int c0 = 1; c0 <= 15; c0 += 1) {
+  if (((-exprVar1 + 15) % 8) + c0 <= 15) {
+    s1(c0);
+    s3(c0);
+    s2(c0);
+    s0(c0);
+    s4(c0);
+  }
+  if (((-exprVar1 + 15) % 8) + c0 <= 15 || (exprVar1 - c0 + 1) % 8 == 0)
+    s5(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/iter9-0.in b/final/lib/External/isl/test_inputs/codegen/omega/iter9-0.in
new file mode 100644
index 0000000..9596d73
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/iter9-0.in
@@ -0,0 +1,3 @@
+[exprVar2, exprVar1] -> { s3[In_1] -> [In_1] : exists (e0: exprVar2 = 0 and 8e0 >= -15 + exprVar1 and exprVar1 <= 15 and In_1 >= 1 and 8e0 <= exprVar1 - In_1); s4[In_1] -> [In_1] : exists (e0: exprVar2 = 0 and 8e0 >= -15 + exprVar1 and exprVar1 <= 15 and In_1 >= 1 and 8e0 <= exprVar1 - In_1); s1[In_1] -> [In_1] : exists (e0: exprVar2 = 0 and 8e0 >= -15 + exprVar1 and exprVar1 <= 15 and In_1 >= 1 and 8e0 <= exprVar1 - In_1); s5[In_1] -> [In_1] : (exists (e0: exprVar2 = 0 and 8e0 >= -15 + exprVar1 and exprVar1 <= 15 and In_1 >= 1 and 8e0 <= exprVar1 - In_1)) or (exists (e0 = [(-1 - exprVar1 + In_1)/8]: exprVar2 = 0 and 8e0 = -1 - exprVar1 + In_1 and In_1 >= 1 + exprVar1 and In_1 >= 1 and In_1 <= 15)); s0[In_1] -> [In_1] : exists (e0: exprVar2 = 0 and 8e0 >= -15 + exprVar1 and exprVar1 <= 15 and In_1 >= 1 and 8e0 <= exprVar1 - In_1); s2[In_1] -> [In_1] : exists (e0: exprVar2 = 0 and 8e0 >= -15 + exprVar1 and exprVar1 <= 15 and In_1 >= 1 and 8e0 <= exprVar1 - In_1) }
+[exprVar2, exprVar1] -> {  : exprVar2 = 0 and exprVar1 <= 15 }
+[exprVar2, exprVar1] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lefur00-0.c b/final/lib/External/isl/test_inputs/codegen/omega/lefur00-0.c
new file mode 100644
index 0000000..5594244
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lefur00-0.c
@@ -0,0 +1,5 @@
+for (int c0 = 0; c0 <= 15; c0 += 1)
+  for (int c1 = max(2 * c0 - 15, c0 / 2); c1 <= min(15, c0 + 1); c1 += 1)
+    for (int c2 = max(max(max(1, 67 * c0 - (c0 + 1) / 3), 67 * c1 - (c1 + 2) / 3), 133 * c0 - 67 * c1 + (c0 + c1 + 1) / 3 - 66); c2 <= min(min(1000, 100 * c0 + 99), 133 * c0 - 67 * c1 + (c0 + c1 + 2) / 3 + 132); c2 += 1)
+      for (int c3 = max(max(c2, 200 * c0 - c2), 100 * c1 + (c2 + 1) / 2); c3 <= min(min(2 * c2 + 1, 200 * c0 - c2 + 199), 100 * c1 + (c2 + 1) / 2 + 99); c3 += 1)
+        s0(c0, c1, c2, c3);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lefur00-0.in b/final/lib/External/isl/test_inputs/codegen/omega/lefur00-0.in
new file mode 100644
index 0000000..cf99c81
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lefur00-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4] -> [In_1, In_2, In_3, In_4] : In_3 >= 1 and In_4 >= In_3 and In_4 <= 1 + 2In_3 and In_3 <= 1000 and In_4 >= 200In_1 - In_3 and In_4 <= 199 + 200In_1 - In_3 and 2In_4 >= 200In_2 + In_3 and 2In_4 <= 199 + 200In_2 + In_3 }
+{  :  }
+{ [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lefur01-0.c b/final/lib/External/isl/test_inputs/codegen/omega/lefur01-0.c
new file mode 100644
index 0000000..5594244
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lefur01-0.c
@@ -0,0 +1,5 @@
+for (int c0 = 0; c0 <= 15; c0 += 1)
+  for (int c1 = max(2 * c0 - 15, c0 / 2); c1 <= min(15, c0 + 1); c1 += 1)
+    for (int c2 = max(max(max(1, 67 * c0 - (c0 + 1) / 3), 67 * c1 - (c1 + 2) / 3), 133 * c0 - 67 * c1 + (c0 + c1 + 1) / 3 - 66); c2 <= min(min(1000, 100 * c0 + 99), 133 * c0 - 67 * c1 + (c0 + c1 + 2) / 3 + 132); c2 += 1)
+      for (int c3 = max(max(c2, 200 * c0 - c2), 100 * c1 + (c2 + 1) / 2); c3 <= min(min(2 * c2 + 1, 200 * c0 - c2 + 199), 100 * c1 + (c2 + 1) / 2 + 99); c3 += 1)
+        s0(c0, c1, c2, c3);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lefur01-0.in b/final/lib/External/isl/test_inputs/codegen/omega/lefur01-0.in
new file mode 100644
index 0000000..cf99c81
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lefur01-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4] -> [In_1, In_2, In_3, In_4] : In_3 >= 1 and In_4 >= In_3 and In_4 <= 1 + 2In_3 and In_3 <= 1000 and In_4 >= 200In_1 - In_3 and In_4 <= 199 + 200In_1 - In_3 and 2In_4 >= 200In_2 + In_3 and 2In_4 <= 199 + 200In_2 + In_3 }
+{  :  }
+{ [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lefur01-1.c b/final/lib/External/isl/test_inputs/codegen/omega/lefur01-1.c
new file mode 100644
index 0000000..5594244
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lefur01-1.c
@@ -0,0 +1,5 @@
+for (int c0 = 0; c0 <= 15; c0 += 1)
+  for (int c1 = max(2 * c0 - 15, c0 / 2); c1 <= min(15, c0 + 1); c1 += 1)
+    for (int c2 = max(max(max(1, 67 * c0 - (c0 + 1) / 3), 67 * c1 - (c1 + 2) / 3), 133 * c0 - 67 * c1 + (c0 + c1 + 1) / 3 - 66); c2 <= min(min(1000, 100 * c0 + 99), 133 * c0 - 67 * c1 + (c0 + c1 + 2) / 3 + 132); c2 += 1)
+      for (int c3 = max(max(c2, 200 * c0 - c2), 100 * c1 + (c2 + 1) / 2); c3 <= min(min(2 * c2 + 1, 200 * c0 - c2 + 199), 100 * c1 + (c2 + 1) / 2 + 99); c3 += 1)
+        s0(c0, c1, c2, c3);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lefur01-1.in b/final/lib/External/isl/test_inputs/codegen/omega/lefur01-1.in
new file mode 100644
index 0000000..bc9611d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lefur01-1.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4] -> [In_1, In_2, In_3, In_4] : In_3 >= 1 and In_4 >= In_3 and In_4 <= 1 + 2In_3 and In_3 <= 1000 and In_4 >= 200In_1 - In_3 and In_4 <= 199 + 200In_1 - In_3 and 2In_4 >= 200In_2 + In_3 and 2In_4 <= 199 + 200In_2 + In_3 }
+{  :  }
+{ [i0, i1, i2, i3] -> atomic[o0] : o0 <= 1; [i0, i1, i2, i3] -> separate[o0] : o0 >= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lefur03-0.c b/final/lib/External/isl/test_inputs/codegen/omega/lefur03-0.c
new file mode 100644
index 0000000..8b61d26
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lefur03-0.c
@@ -0,0 +1,7 @@
+for (int c0 = 0; c0 <= 3; c0 += 1)
+  for (int c1 = max(0, 2 * c0 - 3); c1 <= min(3, c0 + 1); c1 += 1)
+    for (int c2 = c0; c2 <= min(min(3, 2 * c0 - c1 + 1), 3 * c1 + 2); c2 += 1)
+      for (int c3 = max(max(max(0, c1 - (-c1 + 3) / 3), c0 - (-c2 + 3) / 3), c2 + floord(3 * c1 - c2 - 1, 6)); c3 <= min(3, c0 + 1); c3 += 1)
+        for (int c4 = max(max(max(max(-200 * c1 + 400 * c3 - 199, 250 * c3 + 1), 667 * c0 - 333 * c1 - (c0 + c1 + 3) / 3 - 332), 333 * c1 + c1 / 3), 333 * c2 + (c2 + 1) / 3); c4 <= min(min(min(min(1000, 500 * c0 + 499), -200 * c1 + 400 * c3 + 400), 333 * c2 - (-c2 + 3) / 3 + 333), 333 * c3 - (-c3 + 3) / 3 + 334); c4 += 1)
+          for (int c5 = max(max(max(c4, 1000 * c0 - c4), 1000 * c3 - 2 * c4 + 2), 500 * c1 + (c4 + 1) / 2); c5 <= min(min(min(2 * c4 + 1, 1000 * c0 - c4 + 999), 1000 * c3 - 2 * c4 + 1001), 500 * c1 + (c4 + 1) / 2 + 499); c5 += 1)
+            s0(c0, c1, c2, c3, c4, c5);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lefur03-0.in b/final/lib/External/isl/test_inputs/codegen/omega/lefur03-0.in
new file mode 100644
index 0000000..890f413
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lefur03-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5, In_6] -> [In_1, In_2, In_3, In_4, In_5, In_6] : In_6 >= In_5 and In_6 <= 1 + 2In_5 and In_5 <= 1000 and In_6 >= 1000In_1 - In_5 and In_6 <= 999 + 1000In_1 - In_5 and In_6 >= 2 + 1000In_4 - 2In_5 and In_6 <= 1001 + 1000In_4 - 2In_5 and In_4 >= 0 and 2In_6 >= 1000In_2 + In_5 and 2In_6 <= 999 + 1000In_2 + In_5 and 3In_5 >= -1 + 1000In_3 and 3In_5 <= 998 + 1000In_3 }
+{  :  }
+{ [i0, i1, i2, i3, i4, i5] -> separate[o0] : o0 >= 5; [i0, i1, i2, i3, i4, i5] -> atomic[o0] : o0 <= 4 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lefur04-0.c b/final/lib/External/isl/test_inputs/codegen/omega/lefur04-0.c
new file mode 100644
index 0000000..d0046d9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lefur04-0.c
@@ -0,0 +1,8 @@
+for (int c0 = 0; c0 <= 3; c0 += 1)
+  for (int c1 = max(0, 2 * c0 - 3); c1 <= min(c0 + 1, -c0 + 6); c1 += 1)
+    for (int c2 = c0; c2 <= min(min(3, 2 * c0 - c1 + 1), 3 * c1 + 2); c2 += 1)
+      for (int c3 = max(max(max(0, c1 - (-c1 + 3) / 3), c0 - (-c2 + 3) / 3), c2 + floord(3 * c1 - c2 - 1, 6)); c3 <= min(3, c0 + 1); c3 += 1)
+        for (int c5 = max(max(max(max(0, 2 * c3 - 4), c1 - (-c1 + 3) / 3), c2 - (c2 + 3) / 3), c3 - (c3 + 3) / 3); c5 <= min(min(c1 + 1, c3), -c2 + 2 * c3 - (c2 + 3) / 3 + 2); c5 += 1)
+          for (int c6 = max(max(max(max(max(-200 * c1 + 400 * c3 - 199, 250 * c3 + 1), 1000 * c0 - 500 * c5 - 501), 667 * c0 - 333 * c1 - (c0 + c1 + 3) / 3 - 332), 333 * c1 + c1 / 3), 333 * c2 + (c2 + 1) / 3); c6 <= min(min(min(min(min(min(1000, 500 * c0 + 499), -200 * c1 + 400 * c3 + 400), 500 * c5 + 501), 1000 * c0 - 500 * c5 + 997), 333 * c2 - (-c2 + 3) / 3 + 333), 333 * c3 - (-c3 + 3) / 3 + 334); c6 += 1)
+            for (int c7 = max(max(max(max(500 * c5 + 2, c6), 1000 * c0 - c6), 1000 * c3 - 2 * c6 + 2), 500 * c1 + (c6 + 1) / 2); c7 <= min(min(min(min(500 * c5 + 501, 2 * c6 + 1), 1000 * c0 - c6 + 999), 1000 * c3 - 2 * c6 + 1001), 500 * c1 + (c6 + 1) / 2 + 499); c7 += 1)
+              s0(c0, c1, c2, c3, c2 / 3, c5, c6, c7);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lefur04-0.in b/final/lib/External/isl/test_inputs/codegen/omega/lefur04-0.in
new file mode 100644
index 0000000..c50a0da
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lefur04-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5, In_6, In_7, In_8] -> [In_1, In_2, In_3, In_4, In_5, In_6, In_7, In_8] : In_7 >= 1000In_5 and In_8 >= In_7 and In_8 <= 501 + 500In_6 and In_8 <= 1 + 2In_7 and In_7 <= 999 + 1000In_5 and In_7 <= 1000 and In_8 >= 1000In_1 - In_7 and In_8 <= 999 + 1000In_1 - In_7 and 2In_8 >= 1000In_2 + In_7 and 2In_8 <= 999 + 1000In_2 + In_7 and 3In_7 >= -1 + 1000In_3 and 3In_7 <= 998 + 1000In_3 and In_8 >= 2 + 500In_6 and In_6 >= 0 and In_8 >= 2 + 1000In_4 - 2In_7 and In_8 <= 1001 + 1000In_4 - 2In_7 }
+{  :  }
+{ [i0, i1, i2, i3, i4, i5, i6, i7] -> atomic[o0] : o0 <= 6; [i0, i1, i2, i3, i4, i5, i6, i7] -> separate[o0] : o0 >= 7 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift1-0.c b/final/lib/External/isl/test_inputs/codegen/omega/lift1-0.c
new file mode 100644
index 0000000..f7b1ae9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-0.c
@@ -0,0 +1,9 @@
+for (int c0 = 1; c0 <= 100; c0 += 1)
+  for (int c1 = 1; c1 <= 100; c1 += 1)
+    for (int c2 = 1; c2 <= 100; c2 += 1)
+      for (int c3 = 1; c3 <= 100; c3 += 1)
+        for (int c4 = 1; c4 <= 100; c4 += 1) {
+          s1(c0, c1, c2, c3, c4);
+          if (c0 <= 60)
+            s0(c0, c1, c2, c3, c4);
+        }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift1-0.in b/final/lib/External/isl/test_inputs/codegen/omega/lift1-0.in
new file mode 100644
index 0000000..31ae11a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 }
+{  :  }
+{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 5; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 4 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift1-1.c b/final/lib/External/isl/test_inputs/codegen/omega/lift1-1.c
new file mode 100644
index 0000000..b522fd9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-1.c
@@ -0,0 +1,14 @@
+for (int c0 = 1; c0 <= 100; c0 += 1)
+  for (int c1 = 1; c1 <= 100; c1 += 1)
+    for (int c2 = 1; c2 <= 100; c2 += 1)
+      for (int c3 = 1; c3 <= 100; c3 += 1) {
+        if (c0 >= 61) {
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+        } else {
+          for (int c4 = 1; c4 <= 100; c4 += 1) {
+            s1(c0, c1, c2, c3, c4);
+            s0(c0, c1, c2, c3, c4);
+          }
+        }
+      }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift1-1.in b/final/lib/External/isl/test_inputs/codegen/omega/lift1-1.in
new file mode 100644
index 0000000..44de4ac
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-1.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 }
+{  :  }
+{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 4; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift1-2.c b/final/lib/External/isl/test_inputs/codegen/omega/lift1-2.c
new file mode 100644
index 0000000..00e7b16
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-2.c
@@ -0,0 +1,15 @@
+for (int c0 = 1; c0 <= 100; c0 += 1)
+  for (int c1 = 1; c1 <= 100; c1 += 1)
+    for (int c2 = 1; c2 <= 100; c2 += 1) {
+      if (c0 >= 61) {
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+      } else {
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1) {
+            s1(c0, c1, c2, c3, c4);
+            s0(c0, c1, c2, c3, c4);
+          }
+      }
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift1-2.in b/final/lib/External/isl/test_inputs/codegen/omega/lift1-2.in
new file mode 100644
index 0000000..241fbb9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-2.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 }
+{  :  }
+{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift1-3.c b/final/lib/External/isl/test_inputs/codegen/omega/lift1-3.c
new file mode 100644
index 0000000..6249150
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-3.c
@@ -0,0 +1,16 @@
+for (int c0 = 1; c0 <= 100; c0 += 1)
+  for (int c1 = 1; c1 <= 100; c1 += 1) {
+    if (c0 >= 61) {
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+    } else {
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1) {
+            s1(c0, c1, c2, c3, c4);
+            s0(c0, c1, c2, c3, c4);
+          }
+    }
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift1-3.in b/final/lib/External/isl/test_inputs/codegen/omega/lift1-3.in
new file mode 100644
index 0000000..a50a9ec
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-3.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 }
+{  :  }
+{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 2; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift1-4.c b/final/lib/External/isl/test_inputs/codegen/omega/lift1-4.c
new file mode 100644
index 0000000..b981ad8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-4.c
@@ -0,0 +1,17 @@
+for (int c0 = 1; c0 <= 100; c0 += 1) {
+  if (c0 >= 61) {
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+  } else {
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1) {
+            s1(c0, c1, c2, c3, c4);
+            s0(c0, c1, c2, c3, c4);
+          }
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift1-4.in b/final/lib/External/isl/test_inputs/codegen/omega/lift1-4.in
new file mode 100644
index 0000000..db7d85c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-4.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 }
+{  :  }
+{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 1; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift1-5.c b/final/lib/External/isl/test_inputs/codegen/omega/lift1-5.c
new file mode 100644
index 0000000..2a24f68
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-5.c
@@ -0,0 +1,16 @@
+{
+  for (int c0 = 1; c0 <= 60; c0 += 1)
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1) {
+            s1(c0, c1, c2, c3, c4);
+            s0(c0, c1, c2, c3, c4);
+          }
+  for (int c0 = 61; c0 <= 100; c0 += 1)
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift1-5.in b/final/lib/External/isl/test_inputs/codegen/omega/lift1-5.in
new file mode 100644
index 0000000..2f9d578
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-5.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 }
+{  :  }
+{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 0; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift2-0.c b/final/lib/External/isl/test_inputs/codegen/omega/lift2-0.c
new file mode 100644
index 0000000..181d6e5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-0.c
@@ -0,0 +1,9 @@
+for (int c0 = 1; c0 <= 100; c0 += 1)
+  for (int c1 = 1; c1 <= 100; c1 += 1)
+    for (int c2 = 1; c2 <= 100; c2 += 1)
+      for (int c3 = 1; c3 <= 100; c3 += 1)
+        for (int c4 = 1; c4 <= 100; c4 += 1) {
+          s1(c0, c1, c2, c3, c4);
+          if (c0 >= 5 && c0 <= 60)
+            s0(c0, c1, c2, c3, c4);
+        }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift2-0.in b/final/lib/External/isl/test_inputs/codegen/omega/lift2-0.in
new file mode 100644
index 0000000..5df0444
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 5 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 }
+{  :  }
+{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 5; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 4 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift2-1.c b/final/lib/External/isl/test_inputs/codegen/omega/lift2-1.c
new file mode 100644
index 0000000..625c734
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-1.c
@@ -0,0 +1,17 @@
+for (int c0 = 1; c0 <= 100; c0 += 1)
+  for (int c1 = 1; c1 <= 100; c1 += 1)
+    for (int c2 = 1; c2 <= 100; c2 += 1)
+      for (int c3 = 1; c3 <= 100; c3 += 1) {
+        if (c0 >= 61) {
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+        } else if (c0 <= 4) {
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+        } else {
+          for (int c4 = 1; c4 <= 100; c4 += 1) {
+            s1(c0, c1, c2, c3, c4);
+            s0(c0, c1, c2, c3, c4);
+          }
+        }
+      }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift2-1.in b/final/lib/External/isl/test_inputs/codegen/omega/lift2-1.in
new file mode 100644
index 0000000..7ef2a8d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-1.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 5 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 }
+{  :  }
+{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 4; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift2-2.c b/final/lib/External/isl/test_inputs/codegen/omega/lift2-2.c
new file mode 100644
index 0000000..63e897c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-2.c
@@ -0,0 +1,19 @@
+for (int c0 = 1; c0 <= 100; c0 += 1)
+  for (int c1 = 1; c1 <= 100; c1 += 1)
+    for (int c2 = 1; c2 <= 100; c2 += 1) {
+      if (c0 >= 61) {
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+      } else if (c0 <= 4) {
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+      } else {
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1) {
+            s1(c0, c1, c2, c3, c4);
+            s0(c0, c1, c2, c3, c4);
+          }
+      }
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift2-2.in b/final/lib/External/isl/test_inputs/codegen/omega/lift2-2.in
new file mode 100644
index 0000000..3e9a978
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-2.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 5 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 }
+{  :  }
+{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift2-3.c b/final/lib/External/isl/test_inputs/codegen/omega/lift2-3.c
new file mode 100644
index 0000000..f87f197
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-3.c
@@ -0,0 +1,21 @@
+for (int c0 = 1; c0 <= 100; c0 += 1)
+  for (int c1 = 1; c1 <= 100; c1 += 1) {
+    if (c0 >= 61) {
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+    } else if (c0 <= 4) {
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+    } else {
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1) {
+            s1(c0, c1, c2, c3, c4);
+            s0(c0, c1, c2, c3, c4);
+          }
+    }
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift2-3.in b/final/lib/External/isl/test_inputs/codegen/omega/lift2-3.in
new file mode 100644
index 0000000..0580f07
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-3.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 5 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 }
+{  :  }
+{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 2; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift2-4.c b/final/lib/External/isl/test_inputs/codegen/omega/lift2-4.c
new file mode 100644
index 0000000..65ae7ae
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-4.c
@@ -0,0 +1,23 @@
+for (int c0 = 1; c0 <= 100; c0 += 1) {
+  if (c0 >= 61) {
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+  } else if (c0 <= 4) {
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+  } else {
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1) {
+            s1(c0, c1, c2, c3, c4);
+            s0(c0, c1, c2, c3, c4);
+          }
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift2-4.in b/final/lib/External/isl/test_inputs/codegen/omega/lift2-4.in
new file mode 100644
index 0000000..d64462a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-4.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 5 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 }
+{  :  }
+{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 1; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift2-5.c b/final/lib/External/isl/test_inputs/codegen/omega/lift2-5.c
new file mode 100644
index 0000000..16bd6db
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-5.c
@@ -0,0 +1,22 @@
+{
+  for (int c0 = 1; c0 <= 4; c0 += 1)
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+  for (int c0 = 5; c0 <= 60; c0 += 1)
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1) {
+            s1(c0, c1, c2, c3, c4);
+            s0(c0, c1, c2, c3, c4);
+          }
+  for (int c0 = 61; c0 <= 100; c0 += 1)
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      for (int c2 = 1; c2 <= 100; c2 += 1)
+        for (int c3 = 1; c3 <= 100; c3 += 1)
+          for (int c4 = 1; c4 <= 100; c4 += 1)
+            s1(c0, c1, c2, c3, c4);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lift2-5.in b/final/lib/External/isl/test_inputs/codegen/omega/lift2-5.in
new file mode 100644
index 0000000..37a57be
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-5.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 5 and In_1 <= 60 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100; s1[In_1, In_2, In_3, In_4, In_5] -> [In_1, In_2, In_3, In_4, In_5] : In_1 >= 1 and In_1 <= 100 and In_2 >= 1 and In_2 <= 100 and In_3 >= 1 and In_3 <= 100 and In_4 >= 1 and In_4 <= 100 and In_5 >= 1 and In_5 <= 100 }
+{  :  }
+{ [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 0; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu-0.c b/final/lib/External/isl/test_inputs/codegen/omega/lu-0.c
new file mode 100644
index 0000000..e71f47b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu-0.c
@@ -0,0 +1,10 @@
+for (int c0 = 1; c0 < n; c0 += 64)
+  for (int c1 = c0 - 1; c1 <= n; c1 += 64)
+    for (int c2 = c0; c2 <= n; c2 += 1) {
+      for (int c3 = c0; c3 <= min(min(c0 + 63, c1 + 62), c2 - 1); c3 += 1)
+        for (int c4 = max(c1, c3 + 1); c4 <= min(n, c1 + 63); c4 += 1)
+          s1(c3, c4, c2);
+      if (c0 + 63 >= c2)
+        for (int c4 = max(c1, c2 + 1); c4 <= min(n, c1 + 63); c4 += 1)
+          s0(c2, c4);
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu-0.in b/final/lib/External/isl/test_inputs/codegen/omega/lu-0.in
new file mode 100644
index 0000000..510d677
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu-0.in
@@ -0,0 +1,3 @@
+[n] -> { s1[k, i, j] -> [t1, t2, j, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and i >= 1 + k and j >= 1 + k and k >= 1 and i <= n and j <= n); s0[k, i] -> [t1, t2, k, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and k >= 1 and i >= 1 + k and i <= n) }
+{  :  }
+[n] -> { [t1, t2, i2, i3, i4] -> separate[o0] : o0 >= 5; [t1, t2, i2, i3, i4] -> atomic[o0] : o0 <= 4 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu-1.c b/final/lib/External/isl/test_inputs/codegen/omega/lu-1.c
new file mode 100644
index 0000000..e71f47b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu-1.c
@@ -0,0 +1,10 @@
+for (int c0 = 1; c0 < n; c0 += 64)
+  for (int c1 = c0 - 1; c1 <= n; c1 += 64)
+    for (int c2 = c0; c2 <= n; c2 += 1) {
+      for (int c3 = c0; c3 <= min(min(c0 + 63, c1 + 62), c2 - 1); c3 += 1)
+        for (int c4 = max(c1, c3 + 1); c4 <= min(n, c1 + 63); c4 += 1)
+          s1(c3, c4, c2);
+      if (c0 + 63 >= c2)
+        for (int c4 = max(c1, c2 + 1); c4 <= min(n, c1 + 63); c4 += 1)
+          s0(c2, c4);
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu-1.in b/final/lib/External/isl/test_inputs/codegen/omega/lu-1.in
new file mode 100644
index 0000000..2e8f7ef
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu-1.in
@@ -0,0 +1,3 @@
+[n] -> { s1[k, i, j] -> [t1, t2, j, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and i >= 1 + k and j >= 1 + k and k >= 1 and i <= n and j <= n); s0[k, i] -> [t1, t2, k, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and k >= 1 and i >= 1 + k and i <= n) }
+{  :  }
+[n] -> { [t1, t2, i2, i3, i4] -> separate[o0] : o0 >= 4; [t1, t2, i2, i3, i4] -> atomic[o0] : o0 <= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu-2.c b/final/lib/External/isl/test_inputs/codegen/omega/lu-2.c
new file mode 100644
index 0000000..e71f47b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu-2.c
@@ -0,0 +1,10 @@
+for (int c0 = 1; c0 < n; c0 += 64)
+  for (int c1 = c0 - 1; c1 <= n; c1 += 64)
+    for (int c2 = c0; c2 <= n; c2 += 1) {
+      for (int c3 = c0; c3 <= min(min(c0 + 63, c1 + 62), c2 - 1); c3 += 1)
+        for (int c4 = max(c1, c3 + 1); c4 <= min(n, c1 + 63); c4 += 1)
+          s1(c3, c4, c2);
+      if (c0 + 63 >= c2)
+        for (int c4 = max(c1, c2 + 1); c4 <= min(n, c1 + 63); c4 += 1)
+          s0(c2, c4);
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu-2.in b/final/lib/External/isl/test_inputs/codegen/omega/lu-2.in
new file mode 100644
index 0000000..ab2ec41
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu-2.in
@@ -0,0 +1,3 @@
+[n] -> { s1[k, i, j] -> [t1, t2, j, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and i >= 1 + k and j >= 1 + k and k >= 1 and i <= n and j <= n); s0[k, i] -> [t1, t2, k, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and k >= 1 and i >= 1 + k and i <= n) }
+{  :  }
+[n] -> { [t1, t2, i2, i3, i4] -> separate[o0] : o0 >= 3; [t1, t2, i2, i3, i4] -> atomic[o0] : o0 <= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu-3.c b/final/lib/External/isl/test_inputs/codegen/omega/lu-3.c
new file mode 100644
index 0000000..3fd0d4e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu-3.c
@@ -0,0 +1,14 @@
+for (int c0 = 1; c0 < n; c0 += 64)
+  for (int c1 = c0 - 1; c1 <= n; c1 += 64) {
+    for (int c2 = c0; c2 <= min(n, c0 + 63); c2 += 1) {
+      for (int c3 = c0; c3 <= min(c1 + 62, c2 - 1); c3 += 1)
+        for (int c4 = max(c1, c3 + 1); c4 <= min(n, c1 + 63); c4 += 1)
+          s1(c3, c4, c2);
+      for (int c4 = max(c1, c2 + 1); c4 <= min(n, c1 + 63); c4 += 1)
+        s0(c2, c4);
+    }
+    for (int c2 = c0 + 64; c2 <= n; c2 += 1)
+      for (int c3 = c0; c3 <= min(c0 + 63, c1 + 62); c3 += 1)
+        for (int c4 = max(c1, c3 + 1); c4 <= min(n, c1 + 63); c4 += 1)
+          s1(c3, c4, c2);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu-3.in b/final/lib/External/isl/test_inputs/codegen/omega/lu-3.in
new file mode 100644
index 0000000..817db46
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu-3.in
@@ -0,0 +1,3 @@
+[n] -> { s1[k, i, j] -> [t1, t2, j, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and i >= 1 + k and j >= 1 + k and k >= 1 and i <= n and j <= n); s0[k, i] -> [t1, t2, k, k, i] : exists (e0 = [(-1 + t1)/64], e1 = [(t2)/64]: 64e0 = -1 + t1 and 64e1 = t2 and t1 >= -63 + k and t1 <= k and t2 >= -63 + i and t2 <= i and k >= 1 and i >= 1 + k and i <= n) }
+{  :  }
+[n] -> { [t1, t2, i2, i3, i4] -> separate[o0] : o0 >= 2; [t1, t2, i2, i3, i4] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-0.c b/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-0.c
new file mode 100644
index 0000000..da2571a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-0.c
@@ -0,0 +1,7 @@
+for (int c0 = 1; c0 <= n; c0 += 1)
+  for (int c1 = 2; c1 <= n; c1 += 1) {
+    for (int c3 = 1; c3 < min(c0, c1); c3 += 1)
+      s1(c3, c1, c0);
+    if (c1 >= c0 + 1)
+      s0(c0, c1);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-0.in b/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-0.in
new file mode 100644
index 0000000..5aae58c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-0.in
@@ -0,0 +1,3 @@
+[n] -> { s0[k, j] -> [k, j, 1, 0] : k >= 1 and j >= 1 + k and j <= n; s1[k, j, i] -> [i, j, 0, k] : j >= 1 + k and i >= 1 + k and k >= 1 and j <= n and i <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-1.c b/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-1.c
new file mode 100644
index 0000000..da2571a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-1.c
@@ -0,0 +1,7 @@
+for (int c0 = 1; c0 <= n; c0 += 1)
+  for (int c1 = 2; c1 <= n; c1 += 1) {
+    for (int c3 = 1; c3 < min(c0, c1); c3 += 1)
+      s1(c3, c1, c0);
+    if (c1 >= c0 + 1)
+      s0(c0, c1);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-1.in b/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-1.in
new file mode 100644
index 0000000..06a860c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-1.in
@@ -0,0 +1,3 @@
+[n] -> { s0[k, j] -> [k, j, 1, 0] : k >= 1 and j >= 1 + k and j <= n; s1[k, j, i] -> [i, j, 0, k] : j >= 1 + k and i >= 1 + k and k >= 1 and j <= n and i <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 1; [i0, i1, i2, i3] -> separate[o0] : o0 >= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-2.c b/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-2.c
new file mode 100644
index 0000000..561ae11
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-2.c
@@ -0,0 +1,11 @@
+if (n >= 2)
+  for (int c0 = 1; c0 <= n; c0 += 1) {
+    for (int c1 = 2; c1 <= c0; c1 += 1)
+      for (int c3 = 1; c3 < c1; c3 += 1)
+        s1(c3, c1, c0);
+    for (int c1 = c0 + 1; c1 <= n; c1 += 1) {
+      for (int c3 = 1; c3 < c0; c3 += 1)
+        s1(c3, c1, c0);
+      s0(c0, c1);
+    }
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-2.in b/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-2.in
new file mode 100644
index 0000000..6ad8a44
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu_ijk-2.in
@@ -0,0 +1,3 @@
+[n] -> { s0[k, j] -> [k, j, 1, 0] : k >= 1 and j >= 1 + k and j <= n; s1[k, j, i] -> [i, j, 0, k] : j >= 1 + k and i >= 1 + k and k >= 1 and j <= n and i <= n }
+{  :  }
+[n] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 0; [i0, i1, i2, i3] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-0.c b/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-0.c
new file mode 100644
index 0000000..3309454
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-0.c
@@ -0,0 +1,13 @@
+if (ub >= lb)
+  for (int c0 = 1; c0 <= ub; c0 += 1)
+    for (int c1 = c0; c1 <= n; c1 += 1) {
+      if (c0 >= lb && c1 >= c0 + 1) {
+        s0(c0, c1);
+        if (n >= ub + 1)
+          s2(c0, c1);
+      } else if (lb >= c0 + 1) {
+        s3(c0, c1, lb, c0, c1);
+      }
+      for (int c3 = max(lb, c0); c3 <= ub; c3 += 1)
+        s1(c0, c1, c3);
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-0.in b/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-0.in
new file mode 100644
index 0000000..0dd0953
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-0.in
@@ -0,0 +1,3 @@
+[n, lb, ub] -> { s1[k, i, j] -> [k, i, 1, j, 0, 0, 0, 0] : k >= 1 and j >= k and j <= n and j <= ub and i >= k and i <= n and j >= lb; s3[k, i, lb, k, i] -> [k, i, 1, lb, -1, k, i, 0] : k >= 1 and k <= -1 + lb and lb <= n and ub >= lb and i >= k and i <= n; s0[k, i] -> [k, i, 0, 0, 0, 0, 0, 0] : k >= 1 and k >= lb and i >= 1 + k and i <= n and k <= ub; s2[k, i] -> [k, i, 0, 0, 1, 0, 0, 0] : k >= 1 and k >= lb and k <= ub and ub <= -1 + n and i >= 1 + k and i <= n }
+[lb, n, ub] -> {  : ub <= n and lb >= 1 }
+[n, lb, ub] -> { [i0, i1, i2, i3, i4, i5, i6, i7] -> atomic[o0] : o0 <= 7; [i0, i1, i2, i3, i4, i5, i6, i7] -> separate[o0] : o0 >= 8 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-1.c b/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-1.c
new file mode 100644
index 0000000..3309454
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-1.c
@@ -0,0 +1,13 @@
+if (ub >= lb)
+  for (int c0 = 1; c0 <= ub; c0 += 1)
+    for (int c1 = c0; c1 <= n; c1 += 1) {
+      if (c0 >= lb && c1 >= c0 + 1) {
+        s0(c0, c1);
+        if (n >= ub + 1)
+          s2(c0, c1);
+      } else if (lb >= c0 + 1) {
+        s3(c0, c1, lb, c0, c1);
+      }
+      for (int c3 = max(lb, c0); c3 <= ub; c3 += 1)
+        s1(c0, c1, c3);
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-1.in b/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-1.in
new file mode 100644
index 0000000..5d628be
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-1.in
@@ -0,0 +1,3 @@
+[n, lb, ub] -> { s1[k, i, j] -> [k, i, 1, j, 0, 0, 0, 0] : k >= 1 and j >= k and j <= n and j <= ub and i >= k and i <= n and j >= lb; s3[k, i, lb, k, i] -> [k, i, 1, lb, -1, k, i, 0] : k >= 1 and k <= -1 + lb and lb <= n and ub >= lb and i >= k and i <= n; s0[k, i] -> [k, i, 0, 0, 0, 0, 0, 0] : k >= 1 and k >= lb and i >= 1 + k and i <= n and k <= ub; s2[k, i] -> [k, i, 0, 0, 1, 0, 0, 0] : k >= 1 and k >= lb and k <= ub and ub <= -1 + n and i >= 1 + k and i <= n }
+[lb, n, ub] -> {  : ub <= n and lb >= 1 }
+[n, lb, ub] -> { [i0, i1, i2, i3, i4, i5, i6, i7] -> atomic[o0] : o0 <= 6; [i0, i1, i2, i3, i4, i5, i6, i7] -> separate[o0] : o0 >= 7 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m1-0.c b/final/lib/External/isl/test_inputs/codegen/omega/m1-0.c
new file mode 100644
index 0000000..bb14935
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m1-0.c
@@ -0,0 +1,6 @@
+for (int c0 = 1; c0 <= 9; c0 += 1)
+  for (int c1 = 1; c1 <= 9; c1 += 1) {
+    s0(c0, c1);
+    if (c0 == 5)
+      s1(5, c1);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m1-0.in b/final/lib/External/isl/test_inputs/codegen/omega/m1-0.in
new file mode 100644
index 0000000..ca2b8a9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m1-0.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [i, j, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[5, j] -> [5, j, 1] : j >= 1 and j <= 9 }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m1-1.c b/final/lib/External/isl/test_inputs/codegen/omega/m1-1.c
new file mode 100644
index 0000000..580c5af
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m1-1.c
@@ -0,0 +1,14 @@
+for (int c0 = 1; c0 <= 9; c0 += 1) {
+  if (c0 >= 6) {
+    for (int c1 = 1; c1 <= 9; c1 += 1)
+      s0(c0, c1);
+  } else if (c0 <= 4) {
+    for (int c1 = 1; c1 <= 9; c1 += 1)
+      s0(c0, c1);
+  } else {
+    for (int c1 = 1; c1 <= 9; c1 += 1) {
+      s0(5, c1);
+      s1(5, c1);
+    }
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m1-1.in b/final/lib/External/isl/test_inputs/codegen/omega/m1-1.in
new file mode 100644
index 0000000..08dbf45
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m1-1.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [i, j, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[5, j] -> [5, j, 1] : j >= 1 and j <= 9 }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m10-0.c b/final/lib/External/isl/test_inputs/codegen/omega/m10-0.c
new file mode 100644
index 0000000..2b51c7b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m10-0.c
@@ -0,0 +1,7 @@
+for (int c0 = 1; c0 <= 18; c0 += 1)
+  for (int c1 = 1; c1 <= 9; c1 += 1) {
+    if (c0 % 2 == 0)
+      s0(c1, c0 / 2);
+    if (c0 <= 9)
+      s1(c1, c0);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m10-0.in b/final/lib/External/isl/test_inputs/codegen/omega/m10-0.in
new file mode 100644
index 0000000..3046811
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m10-0.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [4j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [2j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m10-1.c b/final/lib/External/isl/test_inputs/codegen/omega/m10-1.c
new file mode 100644
index 0000000..2275457
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m10-1.c
@@ -0,0 +1,15 @@
+for (int c0 = 1; c0 <= 18; c0 += 1) {
+  if (c0 >= 2 && c0 <= 9) {
+    for (int c1 = 1; c1 <= 9; c1 += 1) {
+      if (c0 % 2 == 0)
+        s0(c1, c0 / 2);
+      s1(c1, c0);
+    }
+  } else if (c0 == 1) {
+    for (int c1 = 1; c1 <= 9; c1 += 1)
+      s1(c1, 1);
+  } else if (c0 % 2 == 0) {
+    for (int c1 = 1; c1 <= 9; c1 += 1)
+      s0(c1, c0 / 2);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m10-1.in b/final/lib/External/isl/test_inputs/codegen/omega/m10-1.in
new file mode 100644
index 0000000..81dfc3b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m10-1.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [4j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [2j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m11-0.c b/final/lib/External/isl/test_inputs/codegen/omega/m11-0.c
new file mode 100644
index 0000000..bf727b3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m11-0.c
@@ -0,0 +1,6 @@
+for (int c0 = 1; c0 <= min(4, floord(2 * m - 1, 17) + 1); c0 += 1)
+  for (int c1 = 1; c1 <= min(2, -2 * c0 + (2 * m + 3 * c0 - 4) / 10 + 3); c1 += 1)
+    for (int c2 = 0; c2 <= min(2, -c0 - c1 + (2 * m + 3 * c0 + 10 * c1 + 6) / 20 + 1); c2 += 1)
+      for (int c3 = 8 * c0 + (c0 + 1) / 2 - 8; c3 <= min(min(30, m - 5 * c1 - 10 * c2 + 5), 8 * c0 + c0 / 2); c3 += 1)
+        for (int c4 = 5 * c1 + 10 * c2 - 4; c4 <= min(5 * c1 + 10 * c2, m - c3 + 1); c4 += 1)
+          s0(c0, c1, c2, c3, c4, -9 * c0 + c3 + c0 / 2 + 9, -5 * c1 - 5 * c2 + c4 + 5);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m11-0.in b/final/lib/External/isl/test_inputs/codegen/omega/m11-0.in
new file mode 100644
index 0000000..d85fcf2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m11-0.in
@@ -0,0 +1,3 @@
+[m] -> { s0[In_1, In_2, In_3, In_4, In_5, In_6, 5 - 5In_2 - 5In_3 + In_5] -> [In_1, In_2, In_3, In_4, In_5, In_6, 5 - 5In_2 - 5In_3 + In_5] : In_2 >= 1 and 2In_3 >= 1 - In_2 and In_2 <= 2 and 2In_3 <= 6 - In_2 and In_4 <= 30 and In_1 >= 1 and 2In_6 <= 18 - 17In_1 + 2In_4 and 2In_6 >= 17 - 17In_1 + 2In_4 and In_5 <= 5In_2 + 10In_3 and In_5 >= -4 + 5In_2 + 10In_3 and 2In_4 <= 17In_1 and 2In_4 >= -16 + 17In_1 and In_5 <= 1 + m - In_4 }
+{  :  }
+[m] -> { [i0, i1, i2, i3, i4, i5, i6] -> atomic[o0] : o0 <= 5; [i0, i1, i2, i3, i4, i5, i6] -> separate[o0] : o0 >= 6 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m12-0.c b/final/lib/External/isl/test_inputs/codegen/omega/m12-0.c
new file mode 100644
index 0000000..2dc6ab1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m12-0.c
@@ -0,0 +1,3 @@
+for (int c1 = 1; c1 <= n; c1 += 1)
+  for (int c2 = 1; c2 <= m; c2 += 1)
+    s0(1, c1, c2, 0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m12-0.in b/final/lib/External/isl/test_inputs/codegen/omega/m12-0.in
new file mode 100644
index 0000000..0c988ab
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m12-0.in
@@ -0,0 +1,3 @@
+[m, n] -> { s0[1, In_2, In_3, 0] -> [1, In_2, In_3, 0] : In_3 >= 1 and In_3 <= m and In_2 >= 1 and In_2 <= n }
+{  :  }
+[m, n] -> { [i0, i1, i2, i3] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m12-1.c b/final/lib/External/isl/test_inputs/codegen/omega/m12-1.c
new file mode 100644
index 0000000..f72181e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m12-1.c
@@ -0,0 +1,25 @@
+{
+  for (int c1 = 1; c1 <= n; c1 += 1)
+    for (int c2 = 1; c2 <= m; c2 += 1) {
+      s0(1, c1, c2, 0);
+      s1(1, c1, c2, 0);
+    }
+  for (int c1 = 1; c1 <= n; c1 += 1) {
+    s3(2, c1, 0, 0);
+    s2(2, c1, 0, 0);
+  }
+  for (int c1 = 1; c1 <= m; c1 += 1) {
+    for (int c3 = 1; c3 <= n; c3 += 1) {
+      s4(3, c1, 1, c3);
+      s5(3, c1, 1, c3);
+    }
+    for (int c3 = 1; c3 <= n; c3 += 1) {
+      s7(3, c1, 2, c3);
+      s6(3, c1, 2, c3);
+    }
+  }
+  for (int c1 = 1; c1 <= m; c1 += 1) {
+    s8(4, c1, 0, 0);
+    s9(4, c1, 0, 0);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m12-1.in b/final/lib/External/isl/test_inputs/codegen/omega/m12-1.in
new file mode 100644
index 0000000..355075f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m12-1.in
@@ -0,0 +1,3 @@
+[m, n] -> { s1[1, In_2, In_3, 0] -> [1, In_2, In_3, 0] : In_3 >= 1 and In_3 <= m and In_2 >= 1 and In_2 <= n; s2[2, In_2, 0, 0] -> [2, In_2, 0, 0] : In_2 >= 1 and In_2 <= n; s3[2, In_2, 0, 0] -> [2, In_2, 0, 0] : In_2 >= 1 and In_2 <= n; s8[4, In_2, 0, 0] -> [4, In_2, 0, 0] : In_2 >= 1 and In_2 <= m; s0[1, In_2, In_3, 0] -> [1, In_2, In_3, 0] : In_3 >= 1 and In_3 <= m and In_2 >= 1 and In_2 <= n; s7[3, In_2, 2, In_4] -> [3, In_2, 2, In_4] : In_4 >= 1 and In_4 <= n and In_2 >= 1 and In_2 <= m; s4[3, In_2, 1, In_4] -> [3, In_2, 1, In_4] : In_4 >= 1 and In_4 <= n and In_2 >= 1 and In_2 <= m; s6[3, In_2, 2, In_4] -> [3, In_2, 2, In_4] : In_4 >= 1 and In_4 <= n and In_2 >= 1 and In_2 <= m; s9[4, In_2, 0, 0] -> [4, In_2, 0, 0] : In_2 >= 1 and In_2 <= m; s5[3, In_2, 1, In_4] -> [3, In_2, 1, In_4] : In_4 >= 1 and In_4 <= n and In_2 >= 1 and In_2 <= m }
+{  :  }
+[m, n] -> { [i0, i1, i2, i3] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m2-0.c b/final/lib/External/isl/test_inputs/codegen/omega/m2-0.c
new file mode 100644
index 0000000..08ee8dc
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m2-0.c
@@ -0,0 +1,12 @@
+for (int c0 = 2; c0 <= 9; c0 += 1) {
+  if (c0 >= 5) {
+    s1(c0, 1);
+    for (int c1 = 2; c1 <= 9; c1 += 1) {
+      s1(c0, c1);
+      s0(c0, c1);
+    }
+  } else {
+    for (int c1 = 2; c1 <= 9; c1 += 1)
+      s0(c0, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m2-0.in b/final/lib/External/isl/test_inputs/codegen/omega/m2-0.in
new file mode 100644
index 0000000..ae7780e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m2-0.in
@@ -0,0 +1,3 @@
+{ s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 5 and In_1 <= 9 and In_2 >= 1 and In_2 <= 9; s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_1 <= 9 and In_2 >= 2 and In_2 <= 9 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m2-1.c b/final/lib/External/isl/test_inputs/codegen/omega/m2-1.c
new file mode 100644
index 0000000..09255e0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m2-1.c
@@ -0,0 +1,12 @@
+{
+  for (int c0 = 2; c0 <= 4; c0 += 1)
+    for (int c1 = 2; c1 <= 9; c1 += 1)
+      s0(c0, c1);
+  for (int c0 = 5; c0 <= 9; c0 += 1) {
+    s1(c0, 1);
+    for (int c1 = 2; c1 <= 9; c1 += 1) {
+      s1(c0, c1);
+      s0(c0, c1);
+    }
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m2-1.in b/final/lib/External/isl/test_inputs/codegen/omega/m2-1.in
new file mode 100644
index 0000000..32302bb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m2-1.in
@@ -0,0 +1,3 @@
+{ s1[In_1, In_2] -> [In_1, In_2] : In_1 >= 5 and In_1 <= 9 and In_2 >= 1 and In_2 <= 9; s0[In_1, In_2] -> [In_1, In_2] : In_1 >= 2 and In_1 <= 9 and In_2 >= 2 and In_2 <= 9 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= -1; [i0, i1] -> separate[o0] : o0 >= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m3-0.c b/final/lib/External/isl/test_inputs/codegen/omega/m3-0.c
new file mode 100644
index 0000000..d3d6970
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m3-0.c
@@ -0,0 +1,3 @@
+for (int c0 = -9; c0 <= 9; c0 += 1)
+  for (int c1 = max(1, -c0 + 1); c1 <= min(10, -c0 + 10); c1 += 1)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m3-0.in b/final/lib/External/isl/test_inputs/codegen/omega/m3-0.in
new file mode 100644
index 0000000..82e1093
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m3-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, In_2] : In_2 >= 1 - In_1 and In_2 >= 1 and In_2 <= 10 - In_1 and In_2 <= 10 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m4-0.c b/final/lib/External/isl/test_inputs/codegen/omega/m4-0.c
new file mode 100644
index 0000000..a528073
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m4-0.c
@@ -0,0 +1,5 @@
+for (int c0 = 1; c0 <= 9; c0 += 1)
+  for (int c1 = 1; c1 <= 9; c1 += 1) {
+    s0(c1, c0);
+    s1(c1, c0);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m4-0.in b/final/lib/External/isl/test_inputs/codegen/omega/m4-0.in
new file mode 100644
index 0000000..b7912a3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m4-0.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m4-1.c b/final/lib/External/isl/test_inputs/codegen/omega/m4-1.c
new file mode 100644
index 0000000..a528073
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m4-1.c
@@ -0,0 +1,5 @@
+for (int c0 = 1; c0 <= 9; c0 += 1)
+  for (int c1 = 1; c1 <= 9; c1 += 1) {
+    s0(c1, c0);
+    s1(c1, c0);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m4-1.in b/final/lib/External/isl/test_inputs/codegen/omega/m4-1.in
new file mode 100644
index 0000000..c9e17d9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m4-1.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m7-0.c b/final/lib/External/isl/test_inputs/codegen/omega/m7-0.c
new file mode 100644
index 0000000..d9f93d9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m7-0.c
@@ -0,0 +1,6 @@
+for (int c0 = 1; c0 <= 9; c0 += 1)
+  for (int c1 = 1; c1 <= 9; c1 += 1) {
+    s0(c1, c0);
+    if (c0 % 2 == 0)
+      s1(c1, c0);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m7-0.in b/final/lib/External/isl/test_inputs/codegen/omega/m7-0.in
new file mode 100644
index 0000000..45a1850
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m7-0.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [j, i, 1] : exists (e0 = [(j)/2]: 2e0 = j and i >= 1 and i <= 9 and j >= 2 and j <= 8) }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m7-1.c b/final/lib/External/isl/test_inputs/codegen/omega/m7-1.c
new file mode 100644
index 0000000..d33abe9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m7-1.c
@@ -0,0 +1,11 @@
+for (int c0 = 1; c0 <= 9; c0 += 1) {
+  if ((c0 + 1) % 2 == 0) {
+    for (int c1 = 1; c1 <= 9; c1 += 1)
+      s0(c1, c0);
+  } else {
+    for (int c1 = 1; c1 <= 9; c1 += 1) {
+      s0(c1, c0);
+      s1(c1, c0);
+    }
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m7-1.in b/final/lib/External/isl/test_inputs/codegen/omega/m7-1.in
new file mode 100644
index 0000000..f4b6f6f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m7-1.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [j, i, 1] : exists (e0 = [(j)/2]: 2e0 = j and i >= 1 and i <= 9 and j >= 2 and j <= 8) }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m8-0.c b/final/lib/External/isl/test_inputs/codegen/omega/m8-0.c
new file mode 100644
index 0000000..9aaed9e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m8-0.c
@@ -0,0 +1,6 @@
+for (int c0 = 2; c0 <= 8; c0 += 2)
+  for (int c1 = 1; c1 <= 9; c1 += 1) {
+    if (c0 % 4 == 0)
+      s0(c1, c0);
+    s1(c1, c0);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m8-0.in b/final/lib/External/isl/test_inputs/codegen/omega/m8-0.in
new file mode 100644
index 0000000..e9a0e39
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m8-0.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [j, i, 0] : exists (e0 = [(j)/4]: 4e0 = j and i >= 1 and i <= 9 and j >= 4 and j <= 8); s1[i, j] -> [j, i, 1] : exists (e0 = [(j)/2]: 2e0 = j and i >= 1 and i <= 9 and j >= 2 and j <= 8) }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m8-1.c b/final/lib/External/isl/test_inputs/codegen/omega/m8-1.c
new file mode 100644
index 0000000..4f8a00f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m8-1.c
@@ -0,0 +1,11 @@
+for (int c0 = 2; c0 <= 8; c0 += 2) {
+  if ((c0 + 2) % 4 == 0) {
+    for (int c1 = 1; c1 <= 9; c1 += 1)
+      s1(c1, c0);
+  } else {
+    for (int c1 = 1; c1 <= 9; c1 += 1) {
+      s0(c1, c0);
+      s1(c1, c0);
+    }
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m8-1.in b/final/lib/External/isl/test_inputs/codegen/omega/m8-1.in
new file mode 100644
index 0000000..80e57e4
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m8-1.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [j, i, 0] : exists (e0 = [(j)/4]: 4e0 = j and i >= 1 and i <= 9 and j >= 4 and j <= 8); s1[i, j] -> [j, i, 1] : exists (e0 = [(j)/2]: 2e0 = j and i >= 1 and i <= 9 and j >= 2 and j <= 8) }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m9-0.c b/final/lib/External/isl/test_inputs/codegen/omega/m9-0.c
new file mode 100644
index 0000000..a528073
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m9-0.c
@@ -0,0 +1,5 @@
+for (int c0 = 1; c0 <= 9; c0 += 1)
+  for (int c1 = 1; c1 <= 9; c1 += 1) {
+    s0(c1, c0);
+    s1(c1, c0);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m9-0.in b/final/lib/External/isl/test_inputs/codegen/omega/m9-0.in
new file mode 100644
index 0000000..fc38bf2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m9-0.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [2j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [2j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m9-1.c b/final/lib/External/isl/test_inputs/codegen/omega/m9-1.c
new file mode 100644
index 0000000..a528073
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m9-1.c
@@ -0,0 +1,5 @@
+for (int c0 = 1; c0 <= 9; c0 += 1)
+  for (int c1 = 1; c1 <= 9; c1 += 1) {
+    s0(c1, c0);
+    s1(c1, c0);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/m9-1.in b/final/lib/External/isl/test_inputs/codegen/omega/m9-1.in
new file mode 100644
index 0000000..398e326
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m9-1.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [2j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [2j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/olda-0.c b/final/lib/External/isl/test_inputs/codegen/omega/olda-0.c
new file mode 100644
index 0000000..b05f991
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/olda-0.c
@@ -0,0 +1,8 @@
+for (int c0 = 1; c0 <= morb; c0 += 1)
+  for (int c1 = 1; c1 <= np; c1 += 1)
+    for (int c2 = 1; c2 <= np; c2 += 1) {
+      if (c2 >= c1)
+        s0(c2, c1, c0);
+      if (c1 >= c2)
+        s1(c1, c2, c0);
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/olda-0.in b/final/lib/External/isl/test_inputs/codegen/omega/olda-0.in
new file mode 100644
index 0000000..88f86f5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/olda-0.in
@@ -0,0 +1,3 @@
+[np, morb] -> { s0[mp, mq, mi] -> [mi, mq, mp, 0] : mq >= 1 and mq <= mp and mp <= np and mi >= 1 and mi <= morb; s1[mp, mq, mi] -> [mi, mp, mq, 1] : mq >= 1 and mq <= mp and mp <= np and mi >= 1 and mi <= morb }
+{  :  }
+[np, morb] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2; [i0, i1, i2, i3] -> separate[o0] : o0 >= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/olda-1.c b/final/lib/External/isl/test_inputs/codegen/omega/olda-1.c
new file mode 100644
index 0000000..4b30980
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/olda-1.c
@@ -0,0 +1,9 @@
+for (int c0 = 1; c0 <= morb; c0 += 1)
+  for (int c1 = 1; c1 <= np; c1 += 1) {
+    for (int c2 = 1; c2 < c1; c2 += 1)
+      s1(c1, c2, c0);
+    s0(c1, c1, c0);
+    s1(c1, c1, c0);
+    for (int c2 = c1 + 1; c2 <= np; c2 += 1)
+      s0(c2, c1, c0);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/olda-1.in b/final/lib/External/isl/test_inputs/codegen/omega/olda-1.in
new file mode 100644
index 0000000..a3a387f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/olda-1.in
@@ -0,0 +1,3 @@
+[np, morb] -> { s0[mp, mq, mi] -> [mi, mq, mp, 0] : mq >= 1 and mq <= mp and mp <= np and mi >= 1 and mi <= morb; s1[mp, mq, mi] -> [mi, mp, mq, 1] : mq >= 1 and mq <= mp and mp <= np and mi >= 1 and mi <= morb }
+{  :  }
+[np, morb] -> { [i0, i1, i2, i3] -> atomic[o0] : o0 <= 1; [i0, i1, i2, i3] -> separate[o0] : o0 >= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/p.delft-0.c b/final/lib/External/isl/test_inputs/codegen/omega/p.delft-0.c
new file mode 100644
index 0000000..c676558
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/p.delft-0.c
@@ -0,0 +1,4 @@
+if (P2 >= 0 && P2 <= 3 && P1 == P2)
+  for (int c0 = 0; c0 <= min(2, -P2 + 4); c0 += 1)
+    for (int c2 = (-P2 - c0 + 6) % 3; c2 <= 3; c2 += 3)
+      s0(c0, c0, c2, c2);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/p.delft-0.in b/final/lib/External/isl/test_inputs/codegen/omega/p.delft-0.in
new file mode 100644
index 0000000..5b277a1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/p.delft-0.in
@@ -0,0 +1,3 @@
+[P2, P1] -> { s0[In_1, In_1, In_3, In_3] -> [In_1, In_1, In_3, In_3] : exists (e0 = [(-2P2 - 2In_1 + In_3)/3]: P1 = P2 and 3e0 = -2P2 - 2In_1 + In_3 and P2 >= 0 and P2 <= 3 and In_1 <= 4 - P2 and In_1 >= 0 and In_1 <= 2 and In_3 >= 0 and In_3 <= 3) }
+{  :  }
+[P2, P1] -> { [i0, i1, i2, i3] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3] -> atomic[o0] : o0 <= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/p.delft2-0.c b/final/lib/External/isl/test_inputs/codegen/omega/p.delft2-0.c
new file mode 100644
index 0000000..ab1bc72
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/p.delft2-0.c
@@ -0,0 +1,11 @@
+if (P1 >= 0 && P1 <= 3 && P2 >= 0 && P2 <= 3)
+  for (int c0 = P1 - 1; c0 <= 3; c0 += 1)
+    for (int c2 = 0; c2 <= 7; c2 += 1)
+      for (int c3 = 0; c3 <= 7; c3 += 1)
+        if (4 * P2 >= 2 * c3 + 9 * floord(4 * P2 - 2 * c3 - 1, 9) + 6) {
+          if (P1 >= 1 && c0 + 1 == P1 && 4 * P1 >= 2 * c2 + 9 * floord(4 * P1 - 2 * c2 - 1, 9) + 7) {
+            s0(P1 - 1, P2, c2, c3, ((-4 * P1 + 2 * c2 + 9) % 9) + 1, -4 * P2 + 2 * c3 - 9 * floord(-4 * P2 + 2 * c3, 9));
+          } else if (P1 == 0 && c0 == 3 && c2 % 4 == 0) {
+            s0(3, P2, c2, c3, (-c2 / 4) + 3, -4 * P2 + 2 * c3 - 9 * floord(-4 * P2 + 2 * c3, 9));
+          }
+        }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/p.delft2-0.in b/final/lib/External/isl/test_inputs/codegen/omega/p.delft2-0.in
new file mode 100644
index 0000000..f44b9bf
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/p.delft2-0.in
@@ -0,0 +1,3 @@
+[P1, P2] -> { s0[In_1, P2, In_3, In_4, In_5, In_6] -> [In_1, P2, In_3, In_4, In_5, In_6] : (exists (e0 = [(8 + 4In_1 + 16In_3 + In_5)/9], e1 = [(12 - 4P1 + 9e0)/16], e2 = [(-2In_1 - 2In_3 + In_5)/3], e3 = [(-5P2 - 2In_4 + In_6)/9]: 3e2 = -2In_1 - 2In_3 + In_5 and 9e3 = -5P2 - 2In_4 + In_6 and P1 >= 0 and In_1 >= 1 + P1 and In_1 <= 3 and P2 >= 0 and P2 <= 3 and In_6 >= 0 and In_6 <= 3 and In_5 >= 0 and In_5 <= 3 and In_5 >= 1 - 4In_1 - 16In_3 and In_5 <= 126 - 4In_1 - 16In_3 and In_6 <= 126 - 4P2 - 16In_4 and 16e1 <= -4P1 + 9e0 and 2In_6 <= P2 + 4In_4 and 9e0 <= 3 + 4In_1 + 16In_3 + In_5 and 9e0 >= 4In_1 + 16In_3 + In_5 and 16e1 >= -3 - 4P1 + 9e0)) or (exists (e0 = [(8 + 4In_1 + 16In_3 + In_5)/9], e1 = [(12 - 4P1 + 9e0)/16], e2 = [(-2In_1 - 2In_3 + In_5)/3], e3 = [(-5P2 - 2In_4 + In_6)/9]: 3e2 = -2In_1 - 2In_3 + In_5 and 9e3 = -5P2 - 2In_4 + In_6 and In_1 >= 0 and In_1 <= -1 + P1 and P1 <= 3 and In_6 >= 0 and In_6 <= 3 and In_6 <= 1 + 2In_4 and P2 >= 0 and P2 <= 3 and In_5 >= 0 and In_5 <= 3 and In_5 >= 1 - 4In_1 - 16In_3 and In_5 <= 126 - 4In_1 - 16In_3 and In_6 <= 126 - 4P2 - 16In_4 and 16e1 <= -4P1 + 9e0 and 9e0 <= 3 + 4In_1 + 16In_3 + In_5 and 9e0 >= 4In_1 + 16In_3 + In_5 and 16e1 >= -3 - 4P1 + 9e0)) }
+{  :  }
+[P1, P2] -> { [i0, i1, i2, i3, i4, i5] -> atomic[o0] : o0 <= 4; [i0, i1, i2, i3, i4, i5] -> separate[o0] : o0 >= 5 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/p6-0.c b/final/lib/External/isl/test_inputs/codegen/omega/p6-0.c
new file mode 100644
index 0000000..53995e9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/p6-0.c
@@ -0,0 +1,8 @@
+{
+  for (int c0 = 5; c0 <= 8; c0 += 1)
+    s0(c0);
+  for (int c0 = 10; c0 <= 16; c0 += 2)
+    s0(c0);
+  for (int c0 = 20; c0 <= 25; c0 += 1)
+    s0(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/p6-0.in b/final/lib/External/isl/test_inputs/codegen/omega/p6-0.in
new file mode 100644
index 0000000..025da3d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/p6-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1] -> [In_1] : (In_1 >= 5 and In_1 <= 8) or (exists (e0 = [(In_1)/2]: 2e0 = In_1 and In_1 >= 10 and In_1 <= 16)) or (In_1 >= 20 and In_1 <= 25) }
+{  :  }
+{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/p6-1.c b/final/lib/External/isl/test_inputs/codegen/omega/p6-1.c
new file mode 100644
index 0000000..d3d6970
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/p6-1.c
@@ -0,0 +1,3 @@
+for (int c0 = -9; c0 <= 9; c0 += 1)
+  for (int c1 = max(1, -c0 + 1); c1 <= min(10, -c0 + 10); c1 += 1)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/p6-1.in b/final/lib/External/isl/test_inputs/codegen/omega/p6-1.in
new file mode 100644
index 0000000..82e1093
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/p6-1.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, In_2] : In_2 >= 1 - In_1 and In_2 >= 1 and In_2 <= 10 - In_1 and In_2 <= 10 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride1-0.c b/final/lib/External/isl/test_inputs/codegen/omega/stride1-0.c
new file mode 100644
index 0000000..c65c2e3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride1-0.c
@@ -0,0 +1,2 @@
+for (int c0 = 3; c0 <= 9; c0 += 3)
+  s0(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride1-0.in b/final/lib/External/isl/test_inputs/codegen/omega/stride1-0.in
new file mode 100644
index 0000000..e099087
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride1-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1] -> [In_1] : exists (e0 = [(In_1)/3]: 3e0 = In_1 and In_1 >= 3 and In_1 <= 9) }
+{  :  }
+{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride2-0.c b/final/lib/External/isl/test_inputs/codegen/omega/stride2-0.c
new file mode 100644
index 0000000..0a7e8e7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride2-0.c
@@ -0,0 +1,3 @@
+for (int c0 = 0; c0 <= n; c0 += 32)
+  for (int c1 = c0; c1 <= min(n, c0 + 31); c1 += 1)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride2-0.in b/final/lib/External/isl/test_inputs/codegen/omega/stride2-0.in
new file mode 100644
index 0000000..73dc13d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride2-0.in
@@ -0,0 +1,3 @@
+[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_1)/32]: 32e0 = In_1 and In_2 <= 31 + In_1 and In_1 >= 0 and In_2 >= In_1 and In_2 <= n) }
+{  :  }
+[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride3-0.c b/final/lib/External/isl/test_inputs/codegen/omega/stride3-0.c
new file mode 100644
index 0000000..8913c80
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride3-0.c
@@ -0,0 +1,3 @@
+for (int c0 = 3; c0 <= n; c0 += 32)
+  for (int c1 = c0; c1 <= min(n, c0 + 31); c1 += 1)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride3-0.in b/final/lib/External/isl/test_inputs/codegen/omega/stride3-0.in
new file mode 100644
index 0000000..360d7d0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride3-0.in
@@ -0,0 +1,3 @@
+[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(-3 + In_1)/32]: 32e0 = -3 + In_1 and In_2 <= 31 + In_1 and In_1 >= 3 and In_2 >= In_1 and In_2 <= n) }
+{  :  }
+[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride4-0.c b/final/lib/External/isl/test_inputs/codegen/omega/stride4-0.c
new file mode 100644
index 0000000..ed62b59
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride4-0.c
@@ -0,0 +1,2 @@
+for (int c0 = 18; c0 <= 98; c0 += 5)
+  s0(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride4-0.in b/final/lib/External/isl/test_inputs/codegen/omega/stride4-0.in
new file mode 100644
index 0000000..8779c3c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride4-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1] -> [In_1] : exists (e0 = [(-3 + In_1)/5]: 5e0 = -3 + In_1 and In_1 >= 18 and In_1 <= 98) }
+{  :  }
+{ [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride5-0.c b/final/lib/External/isl/test_inputs/codegen/omega/stride5-0.c
new file mode 100644
index 0000000..2eeeb5a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride5-0.c
@@ -0,0 +1,3 @@
+for (int c0 = 2; c0 <= min(100, -2 * n + 400); c0 += 2)
+  for (int c1 = 2 * n + c0; c1 <= 400; c1 += 2)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride5-0.in b/final/lib/External/isl/test_inputs/codegen/omega/stride5-0.in
new file mode 100644
index 0000000..c26c547
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride5-0.in
@@ -0,0 +1,3 @@
+[n] -> { s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_1)/2], e1 = [(In_2)/2]: 2e0 = In_1 and 2e1 = In_2 and In_1 >= 2 and In_1 <= 100 and In_2 <= 400 and In_2 >= 2n + In_1) }
+{  :  }
+[n] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride6-0.c b/final/lib/External/isl/test_inputs/codegen/omega/stride6-0.c
new file mode 100644
index 0000000..f4df469
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride6-0.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= 101; c0 += 1)
+  for (int c1 = -((c0 - 1) % 2) + c0 + 1; c1 <= 400; c1 += 2)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride6-0.in b/final/lib/External/isl/test_inputs/codegen/omega/stride6-0.in
new file mode 100644
index 0000000..16fda74
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride6-0.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_2)/2]: 2e0 = In_2 and In_1 >= 1 and In_2 >= In_1 and In_2 <= 400 and In_1 <= 101) }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride6-1.c b/final/lib/External/isl/test_inputs/codegen/omega/stride6-1.c
new file mode 100644
index 0000000..070028f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride6-1.c
@@ -0,0 +1,3 @@
+for (int c0 = 2; c0 <= 100; c0 += 2)
+  for (int c1 = c0; c1 <= 400; c1 += 2)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride6-1.in b/final/lib/External/isl/test_inputs/codegen/omega/stride6-1.in
new file mode 100644
index 0000000..91eaab2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride6-1.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_1)/2], e1 = [(In_2)/2]: 2e0 = In_1 and 2e1 = In_2 and In_1 >= 2 and In_2 >= In_1 and In_2 <= 400 and In_1 <= 100) }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride6-2.c b/final/lib/External/isl/test_inputs/codegen/omega/stride6-2.c
new file mode 100644
index 0000000..070028f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride6-2.c
@@ -0,0 +1,3 @@
+for (int c0 = 2; c0 <= 100; c0 += 2)
+  for (int c1 = c0; c1 <= 400; c1 += 2)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride6-2.in b/final/lib/External/isl/test_inputs/codegen/omega/stride6-2.in
new file mode 100644
index 0000000..91eaab2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride6-2.in
@@ -0,0 +1,3 @@
+{ s0[In_1, In_2] -> [In_1, In_2] : exists (e0 = [(In_1)/2], e1 = [(In_2)/2]: 2e0 = In_1 and 2e1 = In_2 and In_1 >= 2 and In_2 >= In_1 and In_2 <= 400 and In_1 <= 100) }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride7-0.c b/final/lib/External/isl/test_inputs/codegen/omega/stride7-0.c
new file mode 100644
index 0000000..a1f7a18
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride7-0.c
@@ -0,0 +1,15 @@
+for (int c0 = 1; c0 <= 36; c0 += 1) {
+  if (c0 <= 3) {
+    for (int c1 = 1; c1 <= 9; c1 += 1)
+      s1(c1, c0);
+  } else if (c0 <= 9) {
+    for (int c1 = 1; c1 <= 9; c1 += 1) {
+      if (c0 % 4 == 0)
+        s0(c1, c0 / 4);
+      s1(c1, c0);
+    }
+  } else if (c0 % 4 == 0) {
+    for (int c1 = 1; c1 <= 9; c1 += 1)
+      s0(c1, c0 / 4);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride7-0.in b/final/lib/External/isl/test_inputs/codegen/omega/stride7-0.in
new file mode 100644
index 0000000..b84f204
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride7-0.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [4j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride7-1.c b/final/lib/External/isl/test_inputs/codegen/omega/stride7-1.c
new file mode 100644
index 0000000..e79d58d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride7-1.c
@@ -0,0 +1,14 @@
+{
+  for (int c0 = 1; c0 <= 3; c0 += 1)
+    for (int c1 = 1; c1 <= 9; c1 += 1)
+      s1(c1, c0);
+  for (int c0 = 4; c0 <= 9; c0 += 1)
+    for (int c1 = 1; c1 <= 9; c1 += 1) {
+      if (c0 % 4 == 0)
+        s0(c1, c0 / 4);
+      s1(c1, c0);
+    }
+  for (int c0 = 3; c0 <= 9; c0 += 1)
+    for (int c1 = 1; c1 <= 9; c1 += 1)
+      s0(c1, c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/stride7-1.in b/final/lib/External/isl/test_inputs/codegen/omega/stride7-1.in
new file mode 100644
index 0000000..3ec82b9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride7-1.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [4j, i, 0] : i >= 1 and i <= 9 and j >= 1 and j <= 9; s1[i, j] -> [j, i, 1] : i >= 1 and i <= 9 and j >= 1 and j <= 9 }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 0; [i0, i1, i2] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/substitution-0.c b/final/lib/External/isl/test_inputs/codegen/omega/substitution-0.c
new file mode 100644
index 0000000..b12c07d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/substitution-0.c
@@ -0,0 +1,3 @@
+for (int c0 = 0; c0 <= 10; c0 += 1)
+  for (int c1 = max(2 * c0 - 4, c0); c1 <= min(2 * c0, c0 + 6); c1 += 1)
+    s0(2 * c0 - c1, -c0 + c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/substitution-0.in b/final/lib/External/isl/test_inputs/codegen/omega/substitution-0.in
new file mode 100644
index 0000000..f4af716
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/substitution-0.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [i + j, i + 2j] : i >= 0 and i <= 4 and j >= 0 and j <= 6 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/substitution-1.c b/final/lib/External/isl/test_inputs/codegen/omega/substitution-1.c
new file mode 100644
index 0000000..51ab952
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/substitution-1.c
@@ -0,0 +1,3 @@
+for (int c0 = 0; c0 <= 14; c0 += 1)
+  for (int c1 = max(2 * c0 - 12, -c0 + 3 * ((c0 + 1) / 2)); c1 <= min(2 * c0, c0 / 2 + 9); c1 += 3)
+    s0((2 * c0 - c1) / 3, (-c0 + 2 * c1) / 3);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/substitution-1.in b/final/lib/External/isl/test_inputs/codegen/omega/substitution-1.in
new file mode 100644
index 0000000..504b220
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/substitution-1.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [2i + j, i + 2j] : i >= 0 and i <= 4 and j >= 0 and j <= 6 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/substitution-2.c b/final/lib/External/isl/test_inputs/codegen/omega/substitution-2.c
new file mode 100644
index 0000000..9748950
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/substitution-2.c
@@ -0,0 +1,2 @@
+for (int c0 = -3; c0 <= 96; c0 += 1)
+  s0(c0, c0 + 4);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/substitution-2.in b/final/lib/External/isl/test_inputs/codegen/omega/substitution-2.in
new file mode 100644
index 0000000..bc9af0c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/substitution-2.in
@@ -0,0 +1,3 @@
+{ s0[i, 4 + i] -> [i, 4 + i] : i >= -3 and i <= 96 }
+{  :  }
+{ [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/substitution-3.c b/final/lib/External/isl/test_inputs/codegen/omega/substitution-3.c
new file mode 100644
index 0000000..86c197f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/substitution-3.c
@@ -0,0 +1 @@
+s0(n + 19);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/substitution-3.in b/final/lib/External/isl/test_inputs/codegen/omega/substitution-3.in
new file mode 100644
index 0000000..ea1ac1a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/substitution-3.in
@@ -0,0 +1,3 @@
+[n] -> { s0[19 + n] -> [19 + n] }
+{  :  }
+[n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/substitution-4.c b/final/lib/External/isl/test_inputs/codegen/omega/substitution-4.c
new file mode 100644
index 0000000..27b3199
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/substitution-4.c
@@ -0,0 +1 @@
+s0(n + 1);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/substitution-4.in b/final/lib/External/isl/test_inputs/codegen/omega/substitution-4.in
new file mode 100644
index 0000000..ecb07cd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/substitution-4.in
@@ -0,0 +1,3 @@
+[n] -> { s0[i] -> [i] : exists (e0 = [(-1 - n + i)/18]: 18e0 = -1 - n + i and i <= 16 + n and i >= 1 + n) }
+{  :  }
+[n] -> { [i0] -> separate[o0] : o0 >= 0; [i0] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/syr2k-0.c b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-0.c
new file mode 100644
index 0000000..bb3ef7f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-0.c
@@ -0,0 +1,4 @@
+for (int c0 = 1; c0 <= min(n, 2 * b - 1); c0 += 1)
+  for (int c1 = max(-n + 1, -b + 1); c1 <= min(b - c0, n - c0); c1 += 1)
+    for (int c2 = max(1, c0 + c1); c2 <= min(n, n + c1); c2 += 1)
+      s0(-c0 - c1 + c2 + 1, -c1 + c2, c2);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/syr2k-0.in b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-0.in
new file mode 100644
index 0000000..28a7deb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-0.in
@@ -0,0 +1,3 @@
+[n, b] -> { s0[i, j, k] -> [1 - i + j, -j + k, k] : i >= 1 and j >= i and j <= n and k >= 1 and k <= n and k <= -1 + b + i and k >= 1 - b + j }
+{  :  }
+[n, b] -> { [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/syr2k-1.c b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-1.c
new file mode 100644
index 0000000..22ec83e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-1.c
@@ -0,0 +1,4 @@
+for (int c0 = 1; c0 <= min(n, 2 * b - 1); c0 += 1)
+  for (int c1 = -b + 1; c1 <= b - c0; c1 += 1)
+    for (int c2 = max(1, c0 + c1); c2 <= min(n, n + c1); c2 += 1)
+      s0(-c0 - c1 + c2 + 1, -c1 + c2, c2);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/syr2k-1.in b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-1.in
new file mode 100644
index 0000000..496aebe
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-1.in
@@ -0,0 +1,3 @@
+[n, b] -> { s0[i, j, k] -> [1 - i + j, -j + k, k] : i >= 1 and j >= i and j <= n and k >= 1 and k <= n and k <= -1 + b + i and k >= 1 - b + j }
+[b, n] -> {  : b >= 1 and n >= b }
+[n, b] -> { [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/syr2k-2.c b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-2.c
new file mode 100644
index 0000000..bb3ef7f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-2.c
@@ -0,0 +1,4 @@
+for (int c0 = 1; c0 <= min(n, 2 * b - 1); c0 += 1)
+  for (int c1 = max(-n + 1, -b + 1); c1 <= min(b - c0, n - c0); c1 += 1)
+    for (int c2 = max(1, c0 + c1); c2 <= min(n, n + c1); c2 += 1)
+      s0(-c0 - c1 + c2 + 1, -c1 + c2, c2);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/syr2k-2.in b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-2.in
new file mode 100644
index 0000000..28a7deb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-2.in
@@ -0,0 +1,3 @@
+[n, b] -> { s0[i, j, k] -> [1 - i + j, -j + k, k] : i >= 1 and j >= i and j <= n and k >= 1 and k <= n and k <= -1 + b + i and k >= 1 - b + j }
+{  :  }
+[n, b] -> { [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/syr2k-3.c b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-3.c
new file mode 100644
index 0000000..22ec83e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-3.c
@@ -0,0 +1,4 @@
+for (int c0 = 1; c0 <= min(n, 2 * b - 1); c0 += 1)
+  for (int c1 = -b + 1; c1 <= b - c0; c1 += 1)
+    for (int c2 = max(1, c0 + c1); c2 <= min(n, n + c1); c2 += 1)
+      s0(-c0 - c1 + c2 + 1, -c1 + c2, c2);
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/syr2k-3.in b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-3.in
new file mode 100644
index 0000000..496aebe
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/syr2k-3.in
@@ -0,0 +1,3 @@
+[n, b] -> { s0[i, j, k] -> [1 - i + j, -j + k, k] : i >= 1 and j >= i and j <= n and k >= 1 and k <= n and k <= -1 + b + i and k >= 1 - b + j }
+[b, n] -> {  : b >= 1 and n >= b }
+[n, b] -> { [i0, i1, i2] -> separate[o0] : o0 >= 2; [i0, i1, i2] -> atomic[o0] : o0 <= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check-sblock-0.c b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check-sblock-0.c
new file mode 100644
index 0000000..db05735
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check-sblock-0.c
@@ -0,0 +1,15 @@
+{
+  for (int c1 = 0; c1 <= 1; c1 += 1) {
+    if (c1 == 1) {
+      s0(1, 1, 1, 0, 0);
+      s0(1, 1, 1, N - 1, 0);
+    } else {
+      for (int c3 = 0; c3 < N; c3 += 1)
+        s0(1, 0, 1, c3, 0);
+    }
+  }
+  for (int c1 = 0; c1 <= floord(T - 1, 1000); c1 += 1)
+    for (int c2 = 1000 * c1 + 1; c2 <= min(N + T - 3, N + 1000 * c1 + 997); c2 += 1)
+      for (int c3 = max(0, -N - 1000 * c1 + c2 + 2); c3 <= min(min(999, T - 1000 * c1 - 1), -1000 * c1 + c2 - 1); c3 += 1)
+        s1(2, 1000 * c1 + c3, 1, -1000 * c1 + c2 - c3, 1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check-sblock-0.in b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check-sblock-0.in
new file mode 100644
index 0000000..b1f92ea
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check-sblock-0.in
@@ -0,0 +1,3 @@
+[T, N] -> { s1[2, t, 1, i, 1] -> [2, tb, t + i, t - 1000tb, 0] : 1000tb <= t and 1000tb >= -999 + t and i >= 1 and i <= -2 + N and t >= 0 and t <= -1 + T; s0[1, 0, 1, In_4, 0] -> [1, 0, 1, In_4, 0] : In_4 >= 0 and In_4 <= -1 + N; s0[1, 1, 1, 0, 0] -> [1, 1, 1, 0, 0]; s0[1, 1, 1, -1 + N, 0] -> [1, 1, 1, -1 + N, 0] }
+[T, N] -> {  : T >= 0 and N >= 4 }
+[N] -> { [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check0-0.c b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check0-0.c
new file mode 100644
index 0000000..484bd1f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check0-0.c
@@ -0,0 +1,13 @@
+{
+  for (int c1 = 0; c1 < N; c1 += 1)
+    s0(1, c1, 1, 0, 0);
+  for (int c1 = 0; c1 <= floord(T - 1, 500); c1 += 1)
+    for (int c2 = 1000 * c1; c2 <= min(N + 2 * T - 3, N + 1000 * c1 + 997); c2 += 1) {
+      for (int c3 = max(0, -((N + c2) % 2) - N - 1000 * c1 + c2 + 2); c3 <= min(min(998, 2 * T - 1000 * c1 - 2), -1000 * c1 + c2 - 2); c3 += 2) {
+        s1(2, 1000 * c1 + c3, 0, -1000 * c1 + c2 - c3, 1);
+        s2(2, 1000 * c1 + c3 + 1, 0, -1000 * c1 + c2 - c3 - 1, 1);
+      }
+      if (2 * T >= c2 + 1 && 1000 * c1 + 999 >= c2)
+        s1(2, ((c2 + 1) % 2) + c2 - 1, 0, -((c2 + 1) % 2) + 1, 1);
+    }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check0-0.in b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check0-0.in
new file mode 100644
index 0000000..ce585b0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check0-0.in
@@ -0,0 +1,3 @@
+[T, N] -> { s1[2, t, 0, i, 1] -> [2, tb, t + i, t - 1000tb, 1] : exists (e0 = [(t - 1000tb)/2]: 2e0 = t - 1000tb and 1000tb <= t and 1000tb >= -999 + t and i >= 0 and i <= -1 + N and t >= 0 and t <= -2 + 2T); s0[1, In_2, 1, 0, 0] -> [1, In_2, 1, 0, 0] : In_2 >= 0 and In_2 <= -1 + N; s2[2, t, 0, i, 1] -> [2, tb, t + i, t - 1000tb, 1] : exists (e0 = [(-1 + t - 1000tb)/2]: 2e0 = -1 + t - 1000tb and 1000tb <= t and 1000tb >= -999 + t and i >= 1 and i <= -2 + N and t >= 1 and t <= -1 + 2T) }
+[T, N] -> {  : T >= 0 and N >= 4 }
+[N] -> { [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 3; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/ts1d-mp-i_ts-m_b-0.c b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-mp-i_ts-m_b-0.c
new file mode 100644
index 0000000..b5569c9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-mp-i_ts-m_b-0.c
@@ -0,0 +1,36 @@
+{
+  for (int c1 = -1; c1 < T; c1 += 1)
+    for (int c2 = 0; c2 < N; c2 += 1) {
+      if (c1 == -1) {
+        s0(1, -1, c2, 0, 0);
+      } else if (c2 == 0) {
+        s0(1, c1, 0, 0, 0);
+      } else if (c2 + 1 == N) {
+        s0(1, c1, N - 1, 0, 0);
+      }
+    }
+  for (int c1 = 0; c1 <= floord(T - 1, 500); c1 += 1) {
+    for (int c3 = -((c1 + 9) / 8) + 2; c3 <= floord(N - 500 * c1 - 3, 4000) + 1; c3 += 1)
+      for (int c4 = max(500 * c1 + 1, 1000 * c1 + 4000 * c3 - 3999); c4 <= min(min(N + T - 3, 1000 * c1 + 4000 * c3 - 3000), 2 * N - 4000 * c3 + 3995); c4 += 1)
+        for (int c5 = max(0, -N - 500 * c1 + c4 + 2); c5 <= min(min(T - 500 * c1 - 1, -500 * c1 + c4 - 1), -500 * c1 - 2000 * c3 + (c4 + 1) / 2 + 1999); c5 += 1)
+          s1(2, 500 * c1 + c5, 1, -500 * c1 + c4 - c5, 1);
+    for (int c3 = max(-((T + 4000) / 4000) + 2, -((c1 + 9) / 8) + 2); c3 <= floord(N - 500 * c1 - 3, 4000) + 1; c3 += 1)
+      for (int c4 = max(1000 * c1 + 4000 * c3 - 3999, -4000 * c3 + 4000); c4 <= min(min(2 * T + 4000 * c3 - 4000, 1000 * c1 + 4000 * c3 - 3000), 2 * N - 4000 * c3 + 3995); c4 += 1)
+        s2(2, -2000 * c3 + (c4 + 1) / 2 + 1999, 1, 2000 * c3 + c4 - (c4 + 1) / 2 - 1999, 1);
+    for (int c3 = -((c1 + 7) / 8) + 1; c3 <= min(floord(N + T - 1000 * c1 - 1004, 4000) + 1, floord(N - 500 * c1 - 504, 4000) + 1); c3 += 1)
+      for (int c4 = max(500 * c1 + 1, 1000 * c1 + 4000 * c3 - 2999); c4 <= min(min(N + T - 3, N + 500 * c1 + 497), 1000 * c1 + 4000 * c3); c4 += 1)
+        for (int c5 = max(0, -N - 500 * c1 + c4 + 2); c5 <= min(min(499, T - 500 * c1 - 1), -500 * c1 + c4 - 1); c5 += 1)
+          s3(2, 500 * c1 + c5, 1, -500 * c1 + c4 - c5, 1);
+    for (int c3 = max(-((T + 4000) / 4000) + 1, -((c1 + 9) / 8) + 1); c3 <= floord(N - 500 * c1 - 3, 4000); c3 += 1)
+      for (int c4 = max(-4000 * c3, 1000 * c1 + 4000 * c3 + 1); c4 <= min(min(2 * N - 4000 * c3 - 5, 2 * T + 4000 * c3), 1000 * c1 + 4000 * c3 + 1000); c4 += 1)
+        s4(2, -2000 * c3 + (c4 + 1) / 2 - 1, 1, 2000 * c3 + c4 - (c4 + 1) / 2 + 1, 1);
+    for (int c3 = -((c1 + 8) / 8) + 1; c3 <= min(floord(N + T - 1000 * c1 - 4, 4000), floord(N - 500 * c1 + 496, 4000)); c3 += 1)
+      for (int c4 = max(1000 * c1 + 4000 * c3 + 1, -4000 * c3 + 2); c4 <= min(min(min(N + T - 3, N + 500 * c1 + 497), 2 * T + 4000 * c3 - 2), 1000 * c1 + 4000 * c3 + 998); c4 += 1)
+        for (int c5 = max(-N - 500 * c1 + c4 + 2, -500 * c1 - 2000 * c3 + (c4 + 1) / 2); c5 <= min(min(499, T - 500 * c1 - 1), -500 * c1 + c4 - 1); c5 += 1)
+          s5(2, 500 * c1 + c5, 1, -500 * c1 + c4 - c5, 1);
+  }
+  if (T >= 1)
+    for (int c3 = -((T + 3998) / 4000) + 1; c3 <= floord(N - T - 2, 4000) + 1; c3 += 1)
+      for (int c4 = max(T, 2 * T + 4000 * c3 - 4001); c4 < min(N + T - 2, 2 * T + 4000 * c3 - 1); c4 += 1)
+        s6(2, T - 1, 1, -T + c4 + 1, 1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/ts1d-mp-i_ts-m_b-0.in b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-mp-i_ts-m_b-0.in
new file mode 100644
index 0000000..0f86a1c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-mp-i_ts-m_b-0.in
@@ -0,0 +1,3 @@
+[T, N] -> { s1[2, t, 1, i, 1] -> [2, tb, 1, proc, t + i, t - 500tb, 0] : 4000proc >= 3000 + t + i - 1000tb and 500tb <= t and 4000proc <= 3999 - t + i and i >= 1 and i <= -2 + N and t >= 0 and t <= -1 + T; s0[1, -1, c, 0, 0] -> [1, -1, c, 0, 0, 0, 0] : c >= 0 and c <= -1 + N; s0[1, b, 0, 0, 0] -> [1, b, 0, 0, 0, 0, 0] : b >= 0 and b <= -1 + T; s0[1, b, -1 + N, 0, 0] -> [1, b, -1 + N, 0, 0, 0, 0] : b >= 0 and b <= -1 + T; s6[2, -1 + T, 1, i, 1] -> [3, tb, 7, proc, -1 + T + i, -1 + T - 500tb, 0] : 500tb <= -1 + T and 500tb >= -500 + T and 4000proc >= 1 - T + i and 4000proc <= 4000 - T + i and i >= 1 and i <= -2 + N and T >= 1; s3[2, t, 1, i, 1] -> [2, tb, 3, proc, t + i, t - 500tb, 0] : 500tb <= t and 500tb >= -499 + t and 4000proc <= 2999 + t + i - 1000tb and 4000proc >= t + i - 1000tb and i >= 1 and i <= -2 + N and t >= 0 and t <= -1 + T; s2[2, t, 1, i, 1] -> [2, tb, 2, proc, t + i, t - 500tb, 0] : 500tb <= t and 500tb >= -499 + t and 4000proc <= 3999 - t + i and 4000proc >= 3998 - t + i and i >= 1 and i <= -2 + N and t >= 0 and t <= -1 + T; s4[2, t, 1, i, 1] -> [2, tb, 4, Out_4, t + i, t - 500tb, 0] : 500tb <= t and 500tb >= -499 + t and 4000Out_4 <= -1 - t + i and 4000Out_4 >= -2 - t + i and i >= 1 and i <= -2 + N and t >= 0 and t <= -1 + T; s5[2, t, 1, i, 1] -> [2, tb, 5, proc, t + i, t - 500tb, 0] : 500tb >= -499 + t and 4000proc <= -1 + t + i - 1000tb and 4000proc >= -t + i and i >= 1 and i <= -2 + N and t >= 0 and t <= -1 + T }
+[T, N] -> {  : T >= 0 and N >= 4 }
+[N, T] -> { [i0, i1, i2, i3, i4, i5, i6] -> atomic[o0] : o0 <= 5; [i0, i1, i2, i3, i4, i5, i6] -> separate[o0] : o0 >= 6 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/ts1d-orig0-0.c b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-orig0-0.c
new file mode 100644
index 0000000..9eff756
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-orig0-0.c
@@ -0,0 +1,10 @@
+{
+  for (int c1 = 0; c1 < N; c1 += 1)
+    s0(1, c1, 1, 0, 0);
+  for (int c1 = 0; c1 < T; c1 += 1) {
+    for (int c3 = 0; c3 < N; c3 += 1)
+      s1(2, c1, 0, c3, 1);
+    for (int c3 = 1; c3 < N - 1; c3 += 1)
+      s2(2, c1, 1, c3, 1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/ts1d-orig0-0.in b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-orig0-0.in
new file mode 100644
index 0000000..153ba7e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-orig0-0.in
@@ -0,0 +1,3 @@
+[T, N] -> { s1[2, In_2, 0, In_4, 1] -> [2, In_2, 0, In_4, 1] : In_4 >= 0 and In_4 <= -1 + N and In_2 >= 0 and In_2 <= -1 + T; s0[1, In_2, 1, 0, 0] -> [1, In_2, 1, 0, 0] : In_2 >= 0 and In_2 <= -1 + N; s2[2, In_2, 1, In_4, 1] -> [2, In_2, 1, In_4, 1] : In_4 >= 1 and In_4 <= -2 + N and In_2 >= 0 and In_2 <= -1 + T }
+[T, N] -> {  : T >= 0 and N >= 4 }
+[N] -> { [i0, i1, i2, i3, i4] -> separate[o0] : o0 >= 4; [i0, i1, i2, i3, i4] -> atomic[o0] : o0 <= 3 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak1-0.c b/final/lib/External/isl/test_inputs/codegen/omega/wak1-0.c
new file mode 100644
index 0000000..32ea68e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak1-0.c
@@ -0,0 +1,27 @@
+{
+  for (int c0 = a3; c0 <= min(min(a1 - 1, b3), a2 - 1); c0 += 1)
+    s2(c0);
+  for (int c0 = a1; c0 <= min(b1, a2 - 1); c0 += 1) {
+    s0(c0);
+    if (c0 >= a3 && b3 >= c0)
+      s2(c0);
+  }
+  for (int c0 = max(max(a1, b1 + 1), a3); c0 <= min(b3, a2 - 1); c0 += 1)
+    s2(c0);
+  for (int c0 = a2; c0 <= b2; c0 += 1) {
+    if (c0 >= a1 && b1 >= c0)
+      s0(c0);
+    s1(c0);
+    if (c0 >= a3 && b3 >= c0)
+      s2(c0);
+  }
+  for (int c0 = max(max(a3, a2), b2 + 1); c0 <= min(a1 - 1, b3); c0 += 1)
+    s2(c0);
+  for (int c0 = max(max(a1, a2), b2 + 1); c0 <= b1; c0 += 1) {
+    s0(c0);
+    if (c0 >= a3 && b3 >= c0)
+      s2(c0);
+  }
+  for (int c0 = max(max(max(max(a1, b1 + 1), a3), a2), b2 + 1); c0 <= b3; c0 += 1)
+    s2(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak1-0.in b/final/lib/External/isl/test_inputs/codegen/omega/wak1-0.in
new file mode 100644
index 0000000..4cf37cb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak1-0.in
@@ -0,0 +1,3 @@
+[a3, b3, a2, b2, a1, b1] -> { s2[i] -> [i, 2] : i >= a3 and i <= b3; s0[i] -> [i, 0] : i >= a1 and i <= b1; s1[i] -> [i, 1] : i >= a2 and i <= b2 }
+{  :  }
+[a1, b1] -> { [i0, i1] -> separate[o0] : o0 >= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak1-1.c b/final/lib/External/isl/test_inputs/codegen/omega/wak1-1.c
new file mode 100644
index 0000000..a09f705
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak1-1.c
@@ -0,0 +1,55 @@
+{
+  for (int c0 = a2; c0 <= min(min(a1 - 1, a3 - 1), b2); c0 += 1)
+    s1(c0);
+  for (int c0 = a3; c0 <= min(min(a1 - 1, b3), a2 - 1); c0 += 1)
+    s2(c0);
+  for (int c0 = max(a3, a2); c0 <= min(min(a1 - 1, b3), b2); c0 += 1) {
+    s1(c0);
+    s2(c0);
+  }
+  for (int c0 = max(max(a3, b3 + 1), a2); c0 <= min(a1 - 1, b2); c0 += 1)
+    s1(c0);
+  for (int c0 = a1; c0 <= min(min(b1, a3 - 1), a2 - 1); c0 += 1)
+    s0(c0);
+  for (int c0 = max(a1, a2); c0 <= min(min(b1, a3 - 1), b2); c0 += 1) {
+    s0(c0);
+    s1(c0);
+  }
+  for (int c0 = max(a1, a3); c0 <= min(min(b1, b3), a2 - 1); c0 += 1) {
+    s0(c0);
+    s2(c0);
+  }
+  for (int c0 = max(max(a1, a3), b3 + 1); c0 <= min(b1, a2 - 1); c0 += 1)
+    s0(c0);
+  for (int c0 = max(max(a1, a3), a2); c0 <= min(min(b1, b3), b2); c0 += 1) {
+    s0(c0);
+    s1(c0);
+    s2(c0);
+  }
+  for (int c0 = max(max(max(a1, a3), b3 + 1), a2); c0 <= min(b1, b2); c0 += 1) {
+    s0(c0);
+    s1(c0);
+  }
+  for (int c0 = max(max(a1, a2), b2 + 1); c0 <= min(b1, a3 - 1); c0 += 1)
+    s0(c0);
+  for (int c0 = max(max(a3, a2), b2 + 1); c0 <= min(a1 - 1, b3); c0 += 1)
+    s2(c0);
+  for (int c0 = max(max(max(a1, a3), a2), b2 + 1); c0 <= min(b1, b3); c0 += 1) {
+    s0(c0);
+    s2(c0);
+  }
+  for (int c0 = max(max(max(max(a1, a3), b3 + 1), a2), b2 + 1); c0 <= b1; c0 += 1)
+    s0(c0);
+  for (int c0 = max(max(a1, b1 + 1), a2); c0 <= min(a3 - 1, b2); c0 += 1)
+    s1(c0);
+  for (int c0 = max(max(a1, b1 + 1), a3); c0 <= min(b3, a2 - 1); c0 += 1)
+    s2(c0);
+  for (int c0 = max(max(max(a1, b1 + 1), a3), a2); c0 <= min(b3, b2); c0 += 1) {
+    s1(c0);
+    s2(c0);
+  }
+  for (int c0 = max(max(max(max(a1, b1 + 1), a3), b3 + 1), a2); c0 <= b2; c0 += 1)
+    s1(c0);
+  for (int c0 = max(max(max(max(a1, b1 + 1), a3), a2), b2 + 1); c0 <= b3; c0 += 1)
+    s2(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak1-1.in b/final/lib/External/isl/test_inputs/codegen/omega/wak1-1.in
new file mode 100644
index 0000000..75c96d4
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak1-1.in
@@ -0,0 +1,3 @@
+[a3, b3, a2, b2, a1, b1] -> { s2[i] -> [i, 2] : i >= a3 and i <= b3; s0[i] -> [i, 0] : i >= a1 and i <= b1; s1[i] -> [i, 1] : i >= a2 and i <= b2 }
+{  :  }
+[a1, b1] -> { [i0, i1] -> separate[o0] : o0 >= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak2-0.c b/final/lib/External/isl/test_inputs/codegen/omega/wak2-0.c
new file mode 100644
index 0000000..96e9f19
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak2-0.c
@@ -0,0 +1,25 @@
+if (c2 >= d2 + 1) {
+  for (int c0 = a1; c0 <= b1; c0 += 1)
+    for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1)
+      s0(c0, c1_0);
+} else {
+  for (int c0 = a1; c0 <= min(b1, a2 - 1); c0 += 1)
+    for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1)
+      s0(c0, c1_0);
+  for (int c0 = a2; c0 <= b2; c0 += 1) {
+    if (c0 >= a1 && b1 >= c0)
+      for (int c1_0 = c1; c1_0 <= min(d1, c2 - 1); c1_0 += 1)
+        s0(c0, c1_0);
+    for (int c1_0 = c2; c1_0 <= d2; c1_0 += 1) {
+      if (c0 >= a1 && b1 >= c0 && c1_0 >= c1 && d1 >= c1_0)
+        s0(c0, c1_0);
+      s1(c0, c1_0);
+    }
+    if (c0 >= a1 && b1 >= c0)
+      for (int c1_0 = max(c1, d2 + 1); c1_0 <= d1; c1_0 += 1)
+        s0(c0, c1_0);
+  }
+  for (int c0 = max(max(a1, a2), b2 + 1); c0 <= b1; c0 += 1)
+    for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1)
+      s0(c0, c1_0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak2-0.in b/final/lib/External/isl/test_inputs/codegen/omega/wak2-0.in
new file mode 100644
index 0000000..da7a695
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak2-0.in
@@ -0,0 +1,3 @@
+[a2, b2, c2, d2, a1, b1, c1, d1] -> { s0[i, j] -> [i, j, 0] : i >= a1 and i <= b1 and j >= c1 and j <= d1; s1[i, j] -> [i, j, 1] : i >= a2 and i <= b2 and j >= c2 and j <= d2 }
+{  :  }
+[a1, b1, c1, d1] -> { [i0, i1, i2] -> separate[o0] : o0 >= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak2-1.c b/final/lib/External/isl/test_inputs/codegen/omega/wak2-1.c
new file mode 100644
index 0000000..58c2971
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak2-1.c
@@ -0,0 +1,34 @@
+if (c2 >= d2 + 1) {
+  for (int c0 = a1; c0 <= b1; c0 += 1)
+    for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1)
+      s0(c0, c1_0);
+} else {
+  for (int c0 = a1; c0 <= min(b1, a2 - 1); c0 += 1)
+    for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1)
+      s0(c0, c1_0);
+  for (int c0 = a2; c0 <= b2; c0 += 1) {
+    if (a1 >= c0 + 1) {
+      for (int c1_0 = c2; c1_0 <= d2; c1_0 += 1)
+        s1(c0, c1_0);
+    } else if (c0 >= b1 + 1) {
+      for (int c1_0 = c2; c1_0 <= d2; c1_0 += 1)
+        s1(c0, c1_0);
+    } else {
+      for (int c1_0 = c2; c1_0 <= min(c1 - 1, d2); c1_0 += 1)
+        s1(c0, c1_0);
+      for (int c1_0 = c1; c1_0 <= min(d1, c2 - 1); c1_0 += 1)
+        s0(c0, c1_0);
+      for (int c1_0 = max(c1, c2); c1_0 <= min(d1, d2); c1_0 += 1) {
+        s0(c0, c1_0);
+        s1(c0, c1_0);
+      }
+      for (int c1_0 = max(max(c1, d1 + 1), c2); c1_0 <= d2; c1_0 += 1)
+        s1(c0, c1_0);
+      for (int c1_0 = max(c1, d2 + 1); c1_0 <= d1; c1_0 += 1)
+        s0(c0, c1_0);
+    }
+  }
+  for (int c0 = max(max(a1, a2), b2 + 1); c0 <= b1; c0 += 1)
+    for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1)
+      s0(c0, c1_0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak2-1.in b/final/lib/External/isl/test_inputs/codegen/omega/wak2-1.in
new file mode 100644
index 0000000..c92ac3c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak2-1.in
@@ -0,0 +1,3 @@
+[a2, b2, c2, d2, a1, b1, c1, d1] -> { s0[i, j] -> [i, j, 0] : i >= a1 and i <= b1 and j >= c1 and j <= d1; s1[i, j] -> [i, j, 1] : i >= a2 and i <= b2 and j >= c2 and j <= d2 }
+{  :  }
+[a1, b1, c1, d1] -> { [i0, i1, i2] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak3-0.c b/final/lib/External/isl/test_inputs/codegen/omega/wak3-0.c
new file mode 100644
index 0000000..06be04a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak3-0.c
@@ -0,0 +1,8 @@
+for (int c0 = a; c0 <= b + 20; c0 += 1) {
+  if (b >= c0)
+    s0(c0);
+  if (c0 >= a + 10 && b + 10 >= c0)
+    s1(c0);
+  if (c0 >= a + 20)
+    s2(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak3-0.in b/final/lib/External/isl/test_inputs/codegen/omega/wak3-0.in
new file mode 100644
index 0000000..a4c4de9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak3-0.in
@@ -0,0 +1,3 @@
+[a, b] -> { s2[i] -> [i, 2] : i >= 20 + a and i <= 20 + b; s0[i] -> [i, 0] : i >= a and i <= b; s1[i] -> [i, 1] : i >= 10 + a and i <= 10 + b }
+{  :  }
+[a, b] -> { [i0, i1] -> atomic[o0] : o0 <= 0; [i0, i1] -> separate[o0] : o0 >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak3-1.c b/final/lib/External/isl/test_inputs/codegen/omega/wak3-1.c
new file mode 100644
index 0000000..3045b21
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak3-1.c
@@ -0,0 +1,21 @@
+{
+  for (int c0 = a; c0 <= min(a + 9, b); c0 += 1)
+    s0(c0);
+  for (int c0 = a + 10; c0 <= min(a + 19, b); c0 += 1) {
+    s0(c0);
+    s1(c0);
+  }
+  for (int c0 = max(a + 10, b + 1); c0 <= min(a + 19, b + 10); c0 += 1)
+    s1(c0);
+  for (int c0 = a + 20; c0 <= b; c0 += 1) {
+    s0(c0);
+    s1(c0);
+    s2(c0);
+  }
+  for (int c0 = max(a + 20, b + 1); c0 <= b + 10; c0 += 1) {
+    s1(c0);
+    s2(c0);
+  }
+  for (int c0 = max(a + 20, b + 11); c0 <= b + 20; c0 += 1)
+    s2(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak3-1.in b/final/lib/External/isl/test_inputs/codegen/omega/wak3-1.in
new file mode 100644
index 0000000..ae319e5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak3-1.in
@@ -0,0 +1,3 @@
+[a, b] -> { s2[i] -> [i, 2] : i >= 20 + a and i <= 20 + b; s0[i] -> [i, 0] : i >= a and i <= b; s1[i] -> [i, 1] : i >= 10 + a and i <= 10 + b }
+{  :  }
+[a, b] -> { [i0, i1] -> atomic[o0] : o0 <= -1; [i0, i1] -> separate[o0] : o0 >= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak4-0.c b/final/lib/External/isl/test_inputs/codegen/omega/wak4-0.c
new file mode 100644
index 0000000..5cefe4b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak4-0.c
@@ -0,0 +1,4 @@
+for (int c0 = max(max(max(max(a1, a2), a3), a4), a5); c0 <= min(min(min(min(b1, b2), b3), b4), b5); c0 += 1) {
+  s0(c0);
+  s1(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak4-0.in b/final/lib/External/isl/test_inputs/codegen/omega/wak4-0.in
new file mode 100644
index 0000000..9862df2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak4-0.in
@@ -0,0 +1,3 @@
+[a1, a2, a3, a4, a5, b1, b2, b3, b4, b5] -> { s0[i] -> [i, 0] : i >= a1 and i >= a2 and i >= a3 and i >= a4 and i >= a5 and i <= b1 and i <= b2 and i <= b3 and i <= b4 and i <= b5; s1[i] -> [i, 1] : i >= a1 and i >= a2 and i >= a3 and i >= a4 and i >= a5 and i <= b1 and i <= b2 and i <= b3 and i <= b4 and i <= b5 }
+{  :  }
+[a1, a2, a3, a4, a5, b1, b2, b3, b4, b5] -> { [i0, i1] -> separate[o0] : o0 >= 1; [i0, i1] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak4-1.c b/final/lib/External/isl/test_inputs/codegen/omega/wak4-1.c
new file mode 100644
index 0000000..5cefe4b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak4-1.c
@@ -0,0 +1,4 @@
+for (int c0 = max(max(max(max(a1, a2), a3), a4), a5); c0 <= min(min(min(min(b1, b2), b3), b4), b5); c0 += 1) {
+  s0(c0);
+  s1(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/wak4-1.in b/final/lib/External/isl/test_inputs/codegen/omega/wak4-1.in
new file mode 100644
index 0000000..076cdd1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak4-1.in
@@ -0,0 +1,3 @@
+[a1, a2, a3, a4, a5, b1, b2, b3, b4, b5] -> { s0[i] -> [i, 0] : i >= a1 and i >= a2 and i >= a3 and i >= a4 and i >= a5 and i <= b1 and i <= b2 and i <= b3 and i <= b4 and i <= b5; s1[i] -> [i, 1] : i >= a1 and i >= a2 and i >= a3 and i >= a4 and i >= a5 and i <= b1 and i <= b2 and i <= b3 and i <= b4 and i <= b5 }
+{  :  }
+[a1, a2, a3, a4, a5, b1, b2, b3, b4, b5] -> { [i0, i1] -> separate[o0] : o0 >= 0; [i0, i1] -> atomic[o0] : o0 <= -1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/x-0.c b/final/lib/External/isl/test_inputs/codegen/omega/x-0.c
new file mode 100644
index 0000000..f890920
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/x-0.c
@@ -0,0 +1,14 @@
+for (int c0 = 1; c0 <= 11; c0 += 1) {
+  for (int c1 = max(1, c0 - 3); c1 <= min(c0, -c0 + 8); c1 += 1)
+    s1(c1, c0 - c1 + 1);
+  for (int c1 = max(1, -c0 + 9); c1 <= min(c0 - 4, -c0 + 12); c1 += 1)
+    s0(c1, c0 + c1 - 8);
+  for (int c1 = max(c0 - 3, -c0 + 9); c1 <= min(c0, -c0 + 12); c1 += 1) {
+    s0(c1, c0 + c1 - 8);
+    s1(c1, c0 - c1 + 1);
+  }
+  for (int c1 = max(c0 - 3, -c0 + 13); c1 <= min(8, c0); c1 += 1)
+    s1(c1, c0 - c1 + 1);
+  for (int c1 = max(c0 + 1, -c0 + 9); c1 <= min(8, -c0 + 12); c1 += 1)
+    s0(c1, c0 + c1 - 8);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/x-0.in b/final/lib/External/isl/test_inputs/codegen/omega/x-0.in
new file mode 100644
index 0000000..24340ef
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/x-0.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [8 - i + j, i, 0] : i >= 1 and i <= 8 and j >= 1 and j <= 4; s1[i, j] -> [-1 + i + j, i, 1] : i >= 1 and i <= 8 and j >= 1 and j <= 4 }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/x-1.c b/final/lib/External/isl/test_inputs/codegen/omega/x-1.c
new file mode 100644
index 0000000..f890920
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/x-1.c
@@ -0,0 +1,14 @@
+for (int c0 = 1; c0 <= 11; c0 += 1) {
+  for (int c1 = max(1, c0 - 3); c1 <= min(c0, -c0 + 8); c1 += 1)
+    s1(c1, c0 - c1 + 1);
+  for (int c1 = max(1, -c0 + 9); c1 <= min(c0 - 4, -c0 + 12); c1 += 1)
+    s0(c1, c0 + c1 - 8);
+  for (int c1 = max(c0 - 3, -c0 + 9); c1 <= min(c0, -c0 + 12); c1 += 1) {
+    s0(c1, c0 + c1 - 8);
+    s1(c1, c0 - c1 + 1);
+  }
+  for (int c1 = max(c0 - 3, -c0 + 13); c1 <= min(8, c0); c1 += 1)
+    s1(c1, c0 - c1 + 1);
+  for (int c1 = max(c0 + 1, -c0 + 9); c1 <= min(8, -c0 + 12); c1 += 1)
+    s0(c1, c0 + c1 - 8);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/omega/x-1.in b/final/lib/External/isl/test_inputs/codegen/omega/x-1.in
new file mode 100644
index 0000000..24340ef
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/x-1.in
@@ -0,0 +1,3 @@
+{ s0[i, j] -> [8 - i + j, i, 0] : i >= 1 and i <= 8 and j >= 1 and j <= 4; s1[i, j] -> [-1 + i + j, i, 1] : i >= 1 and i <= 8 and j >= 1 and j <= 4 }
+{  :  }
+{ [i0, i1, i2] -> separate[o0] : o0 >= 1; [i0, i1, i2] -> atomic[o0] : o0 <= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/pldi2012/README b/final/lib/External/isl/test_inputs/codegen/pldi2012/README
new file mode 100644
index 0000000..316e838
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/README
@@ -0,0 +1,2 @@
+These examples are taken from the "Polyhedra Scanning Revisited" paper
+by Chun Chen.
diff --git a/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_b.c b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_b.c
new file mode 100644
index 0000000..5e2cd82
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_b.c
@@ -0,0 +1,9 @@
+for (int c0 = 1; c0 <= 100; c0 += 1) {
+  if (n >= 2)
+    s0(c0);
+  for (int c1 = 1; c1 <= 100; c1 += 1) {
+    s2(c0, c1);
+    if (n >= 2)
+      s1(c0, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_b.in b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_b.in
new file mode 100644
index 0000000..9314917
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_b.in
@@ -0,0 +1,5 @@
+[n] -> { s0[i] -> [i,0] : 1 <= i <= 100 and n > 1;
+	 s1[i,j] -> [i,j] : 1 <= i,j <= 100 and n > 1;
+	 s2[i,j] -> [i,j] : 1 <= i,j <= 100 }
+[n] -> {  :  }
+[n] -> { [i,j] -> separate[x] : x >= 2 }
diff --git a/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_c.c b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_c.c
new file mode 100644
index 0000000..b3f4a24
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_c.c
@@ -0,0 +1,12 @@
+for (int c0 = 1; c0 <= 100; c0 += 1) {
+  if (n >= 2) {
+    s0(c0);
+    for (int c1 = 1; c1 <= 100; c1 += 1) {
+      s2(c0, c1);
+      s1(c0, c1);
+    }
+  } else {
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      s2(c0, c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_c.in b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_c.in
new file mode 100644
index 0000000..06a3266
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_c.in
@@ -0,0 +1,5 @@
+[n] -> { s0[i] -> [i,0] : 1 <= i <= 100 and n > 1;
+	 s1[i,j] -> [i,j] : 1 <= i,j <= 100 and n > 1;
+	 s2[i,j] -> [i,j] : 1 <= i,j <= 100 }
+[n] -> {  :  }
+[n] -> { [i,j] -> separate[x] : x >= 1 }
diff --git a/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_d.c b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_d.c
new file mode 100644
index 0000000..94dc201
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_d.c
@@ -0,0 +1,13 @@
+if (n >= 2) {
+  for (int c0 = 1; c0 <= 100; c0 += 1) {
+    s0(c0);
+    for (int c1 = 1; c1 <= 100; c1 += 1) {
+      s2(c0, c1);
+      s1(c0, c1);
+    }
+  }
+} else {
+  for (int c0 = 1; c0 <= 100; c0 += 1)
+    for (int c1 = 1; c1 <= 100; c1 += 1)
+      s2(c0, c1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_d.in b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_d.in
new file mode 100644
index 0000000..339e39d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_d.in
@@ -0,0 +1,5 @@
+[n] -> { s0[i] -> [i,0] : 1 <= i <= 100 and n > 1;
+	 s1[i,j] -> [i,j] : 1 <= i,j <= 100 and n > 1;
+	 s2[i,j] -> [i,j] : 1 <= i,j <= 100 }
+[n] -> {  :  }
+[n] -> { [i,j] -> separate[x] : x >= 0 }
diff --git a/final/lib/External/isl/test_inputs/codegen/pldi2012/figure8_a.c b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure8_a.c
new file mode 100644
index 0000000..4608d61
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure8_a.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= n; c0 += 4)
+  for (int c1 = c0; c1 <= n; c1 += 3)
+    s0(c0, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/pldi2012/figure8_a.in b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure8_a.in
new file mode 100644
index 0000000..df6543c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure8_a.in
@@ -0,0 +1,4 @@
+[n] -> { s0[i,j] -> [i,j] : exists alpha, beta: 1 <= i <= n and i <= j <= n and
+			    i = 1 + 4 alpha and j = i + 3 beta}
+[n] -> { : }
+[n] -> {}
diff --git a/final/lib/External/isl/test_inputs/codegen/pldi2012/figure8_b.c b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure8_b.c
new file mode 100644
index 0000000..9455969
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure8_b.c
@@ -0,0 +1,8 @@
+{
+  for (int c0 = 2; c0 < n - 1; c0 += 4) {
+    s1(c0);
+    s0(c0 + 2);
+  }
+  if (n >= 1 && n % 4 >= 2)
+    s1(-(n % 4) + n + 2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/pldi2012/figure8_b.in b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure8_b.in
new file mode 100644
index 0000000..2effb0a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure8_b.in
@@ -0,0 +1,4 @@
+[n] -> { s0[i] -> [i] : exists alpha: 1 <= i <= n and i = 4 alpha;
+	 s1[i] -> [i] : exists alpha: 1 <= i <= n and i = 4 alpha + 2 }
+[n] -> { : }
+[n] -> { }
diff --git a/final/lib/External/isl/test_inputs/codegen/redundant.c b/final/lib/External/isl/test_inputs/codegen/redundant.c
new file mode 100644
index 0000000..057416e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/redundant.c
@@ -0,0 +1,11 @@
+for (int c0 = 0; c0 <= 2; c0 += 1)
+  for (int c1 = max(0, b0 - 4 * c0 - 1); c1 <= 1; c1 += 1) {
+    if (b0 >= 1 && 4 * c0 + c1 >= 1)
+      for (int c2 = 1; c2 <= 2; c2 += 1)
+        for (int c3 = 1; c3 <= 14; c3 += 1)
+          write(c0, c1, 8 * b0 + c2 - 5, c3);
+    for (int c2 = max(max(3, -8 * b0 + 6), 8 * c0 - 12); c2 <= min(min(7, -8 * b0 + 17), 8 * c0 + 6); c2 += 1)
+      if (4 * c0 + c1 + 1 >= 2 * ((2 * c1 + c2 - 1) / 4) && 2 * ((2 * c1 + c2 - 1) / 4) + 7 >= 4 * c0 + c1 && (2 * c1 + c2 - 1) % 4 >= 1 && ((2 * c1 + c2 - 1) % 4) + 11 >= 2 * c2)
+        for (int c3 = 1; c3 <= 14; c3 += 1)
+          write(c0, c1, 8 * b0 + c2 - 5, c3);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/redundant.st b/final/lib/External/isl/test_inputs/codegen/redundant.st
new file mode 100644
index 0000000..e766f74
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/redundant.st
@@ -0,0 +1,6 @@
+# Check that b1 >= 1 is not dropped by mistake in 4 * c0 + c1 >= 1 part
+domain: "[b0] -> { write[i0, o1, o2, o3] : ((exists (e0 = floor((4 + o2)/8), e1 = floor((5 + o2)/8), e2 = floor((4 + o2)/262144), e3, e4: o1 <= 1 and o1 >= 0 and o2 <= 12 and o2 >= 1 and o3 <= 14 and o3 >= 1 and 8e0 <= 4 + o2 and 8e1 <= 5 + o2 and 262144e2 <= 4 - 8b0 + o2 and 262144e2 >= -262139 + o2 and 262144e2 <= 4 + o2 and 262144e2 >= -3 - 8b0 + o2 and 4e4 <= 1 - 8i0 + 2o1 - o2 + 8e0 and 4e4 <= 4 - 8i0 + 2o1 + o2 - 8e0 and 4e4 >= 2o1 + o2 - 8e1 - 8e3 and 4e4 >= -3 + 2o1 + o2 - 8e0 - 8e3 and 4e4 >= -6 + 2o1 - o2 + 8e0 - 8e3 and 2e4 >= -9 + o1 and 2e4 <= -1 + o1 and 4e4 <= -6 + 2o1 - o2 + 8e1 - 8e3 and 4e4 >= -3 - 8i0 + 2o1 + o2 - 8e0 and 4e4 >= -6 - 8i0 + 2o1 - o2 + 8e0)) or (exists (e0 = floor((4 + o2)/8), e1 = floor((5 + o2)/8), e2 = floor((4 + o2)/262144), e3, e4: o1 <= 1 and o1 >= 0 and o2 <= 12 and o2 >= 1 and o3 <= 14 and o3 >= 1 and 8e0 <= 4 + o2 and 8e1 >= -2 + o2 and 262144e2 <= 4 - 8b0 + o2 and 262144e2 >= -262139 + o2 and 262144e2 <= 4 + o2 and 262144e2 >= -3 - 8b0 + o2 and 4e4 <= 1 - 8i0 + 2o1 - o2 + 8e0 and 4e4 <= 4 - 8i0 + 2o1 + o2 - 8e0 and 4e4 >= -3 + 2o1 + o2 - 8e0 - 8e3 and 4e4 >= -6 + 2o1 - o2 + 8e0 - 8e3 and 2e4 >= -9 + o1 and 2e4 <= -1 + o1 and 4e4 <= 1 + 2o1 - o2 + 8e0 - 8e3 and 4e4 <= 4 + 2o1 + o2 - 8e0 - 8e3 and 4e4 <= -1 + 2o1 + o2 - 8e1 - 8e3 and 4e4 >= -3 - 8i0 + 2o1 + o2 - 8e0 and 4e4 >= -6 - 8i0 + 2o1 - o2 + 8e0)) or (exists (e0 = floor((2 + o2)/8), e1 = floor((4 + o2)/8), e2 = floor((4 + o2)/262144), e3, e4: o1 <= 1 and o1 >= 0 and o2 <= 13 and o2 >= 3 and o3 <= 14 and o3 >= 1 and 8e0 >= -5 + o2 and 8e1 <= 4 + o2 and 262144e2 <= 4 - 8b0 + o2 and 262144e2 >= -262139 + o2 and 262144e2 <= 4 + o2 and 262144e2 >= -3 - 8b0 + o2 and 4e4 <= 1 - 8i0 + 2o1 - o2 + 8e1 and 4e4 <= 4 - 8i0 + 2o1 + o2 - 8e1 and 4e4 >= -3 + 2o1 + o2 - 8e1 - 8e3 and 4e4 >= -6 + 2o1 - o2 + 8e1 - 8e3 and 2e4 >= -9 + o1 and 2e4 <= -1 + o1 and 4e4 <= 1 + 2o1 - o2 + 8e1 - 8e3 and 4e4 <= -4 + 2o1 + o2 - 8e0 - 8e3 and 4e4 <= 4 + 2o1 + o2 - 8e1 - 8e3 and 4e4 >= -3 - 8i0 + 2o1 + o2 - 8e1 and 4e4 >= -6 - 8i0 + 2o1 - o2 + 8e1))) and b0 >= 0 and i0 <= 2 and i0 >= 0 and b0 <= 2 }"
+child:
+  context: "[b0] -> { [] : b0 <= 2 and b0 >= 0 }"
+  child:
+    schedule: "[b0] -> [{ write[i0, o1, o2, o3] -> [i0] }, { write[i0, i1, i2, i3] -> [(i1)] }, { write[i0, i1, i2, i3] -> [(5 - 8b0 + i2)] }, { write[i0,i1, i2, i3] -> [(i3)] }]"
diff --git a/final/lib/External/isl/test_inputs/codegen/roman.c b/final/lib/External/isl/test_inputs/codegen/roman.c
new file mode 100644
index 0000000..d7e4077
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/roman.c
@@ -0,0 +1,32 @@
+{
+  for (int c1 = 0; c1 <= min(np1 - i, -i + 1); c1 += 1) {
+    S_9(c1);
+    S_12(c1);
+  }
+  for (int c1 = max(0, -i + 2); c1 <= -((-np1 + i + 4294967295) % 4294967296) + 4294967295; c1 += 1) {
+    S_9(c1);
+    S_10(c1);
+    for (int c3 = 0; c3 <= min(19, i + c1 - 3); c3 += 1) {
+      S_15(c1, c3);
+      for (int c5 = 0; c5 < c3; c5 += 1) {
+        S_16(c1, c3, c5);
+        S_17(c1, c3, c5);
+      }
+      S_16(c1, c3, c3);
+      S_18(c1, c3);
+      S_24(c1, c3);
+      S_19(c1, c3);
+    }
+    if (i + c1 <= 21) {
+      S_15(c1, i + c1 - 2);
+      for (int c5 = 0; c5 < i + c1 - 2; c5 += 1) {
+        S_16(c1, i + c1 - 2, c5);
+        S_17(c1, i + c1 - 2, c5);
+      }
+      S_16(c1, i + c1 - 2, i + c1 - 2);
+      S_18(c1, i + c1 - 2);
+      S_24(c1, i + c1 - 2);
+    }
+    S_12(c1);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/roman.in b/final/lib/External/isl/test_inputs/codegen/roman.in
new file mode 100644
index 0000000..55182a6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/roman.in
@@ -0,0 +1,5 @@
+# Older versions of isl would get confused on this input due to disappearing
+# div constraints.
+[np1, i] -> { S_17[i0, i1, i2] -> [0, i0, 2, i1, 1, i2, 1] : exists (e0 = [(np1 - i)/4294967296], e1 = [(-2 + i + i0)/4294967296], e2 = [(i1)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i1 >= 0 and 4294967296e1 <= -2 + i + i0 and 4294967296e1 >= -4294967297 + i + i0 and 4294967296e1 <= -2 + i + i0 - i1 and i1 <= 19 and i2 >= 0 and 4294967296e2 <= i1 and 4294967296e2 >= -4294967295 + i1 and 4294967296e2 <= i1 - i2 and i2 <= 19 and i0 >= 2 - i and i2 <= -1 + i1); S_18[i0, i1] -> [0, i0, 2, i1, 2, 0, 0] : exists (e0 = [(np1 - i)/4294967296], e1 = [(-2 + i + i0)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i1 >= 0 and 4294967296e1 <= -2 + i + i0 and 4294967296e1 >= -4294967297 + i + i0 and 4294967296e1 <= -2 + i + i0 - i1 and i1 <= 19 and i0 >= 2 - i); S_24[i0, i1] -> [0, i0, 2, i1, 3, 0, 0] : exists (e0 = [(np1 - i)/4294967296], e1 = [(-2 + i + i0)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i1 >= 0 and 4294967296e1 <= -2 + i + i0 and 4294967296e1 >= -4294967297 + i + i0 and 4294967296e1 <= -2 + i + i0 - i1 and i1 <= 19 and i0 >= 2 - i); S_15[i0, i1] -> [0, i0, 2, i1, 0, 0, 0] : exists (e0 = [(np1 - i)/4294967296], e1 = [(-2 + i + i0)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i1 >= 0 and 4294967296e1 <= -2 + i + i0 and 4294967296e1 >= -4294967297 + i + i0 and 4294967296e1 <= -2 + i + i0 - i1 and i1 <= 19 and i0 >= 2 - i); S_9[i0] -> [0, i0, 0, 0, 0, 0, 0] : exists (e0 = [(np1 - i)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20); S_10[i0] -> [0, i0, 1, 0, 0, 0, 0] : exists (e0 = [(np1 - i)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i0 >= 2 - i); S_19[i0, i1] -> [0, i0, 2, i1, 4, 0, 0] : exists (e0 = [(np1 - i)/4294967296], e1 = [(-2 + i + i0)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i1 >= 0 and 4294967296e1 <= -2 + i + i0 and 4294967296e1 >= -4294967297 + i + i0 and 4294967296e1 <= -2 + i + i0 - i1 and i1 <= 19 and i0 >= 2 - i and i1 <= -3 + i + i0); S_12[i0] -> [0, i0, 3, 0, 0, 0, 0] : exists (e0 = [(np1 - i)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20); S_16[i0, i1, i2] -> [0, i0, 2, i1, 1, i2, 0] : exists (e0 = [(np1 - i)/4294967296], e1 = [(-2 + i + i0)/4294967296], e2 = [(i1)/4294967296]: i0 >= 0 and 4294967296e0 <= np1 - i and 4294967296e0 >= -4294967295 + np1 - i and 4294967296e0 <= np1 - i - i0 and i0 <= 20 and i1 >= 0 and 4294967296e1 <= -2 + i + i0 and 4294967296e1 >= -4294967297 + i + i0 and 4294967296e1 <= -2 + i + i0 - i1 and i1 <= 19 and i2 >= 0 and 4294967296e2 <= i1 and 4294967296e2 >= -4294967295 + i1 and 4294967296e2 <= i1 - i2 and i2 <= 19 and i0 >= 2 - i) }
+[np1, i] -> {  : exists (e0 = [(np1 - i)/4294967296]: 4294967296e0 <= np1 - i and 4294967296e0 >= -20 + np1 - i and np1 >= -2147483648 and np1 <= 2147483647 and i >= -2147483648 and i <= 2147483647) }
+[np1, i] -> { [i0, i1, i2, i3, i4, i5, i6] -> separate[o0] }
diff --git a/final/lib/External/isl/test_inputs/codegen/separate.c b/final/lib/External/isl/test_inputs/codegen/separate.c
new file mode 100644
index 0000000..14d91be
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separate.c
@@ -0,0 +1,8 @@
+{
+  a(0);
+  for (int c0 = 1; c0 <= 9; c0 += 1) {
+    a(c0);
+    b(c0 - 1);
+  }
+  b(9);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/separate.in b/final/lib/External/isl/test_inputs/codegen/separate.in
new file mode 100644
index 0000000..07ea4aa
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separate.in
@@ -0,0 +1,3 @@
+{ a[i] -> [i, 0] : 0 <= i < 10; b[i] -> [i+1, 1] : 0 <= i < 10 }
+{ : }
+{ [i, d] -> separate[x] }
diff --git a/final/lib/External/isl/test_inputs/codegen/separate.st b/final/lib/External/isl/test_inputs/codegen/separate.st
new file mode 100644
index 0000000..2eed716
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separate.st
@@ -0,0 +1,8 @@
+domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }"
+child:
+  schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]"
+  options: "{ separate[x] }"
+  child:
+    sequence:
+    - filter: "{ a[i] }"
+    - filter: "{ b[i] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/separate2.c b/final/lib/External/isl/test_inputs/codegen/separate2.c
new file mode 100644
index 0000000..76ee58d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separate2.c
@@ -0,0 +1,8 @@
+for (int c0 = 0; c0 <= 1; c0 += 1)
+  for (int c5 = 0; c5 <= 31; c5 += 1)
+    for (int c6 = max(0, 2 * (length % 16) + 2 * c5 - 62); c6 <= 30; c6 += 1) {
+      if (2 * length + c6 >= 2 * (length % 16) + 2 && c6 + 62 >= 2 * (length % 16) + 2 * c5 && 2 * (length % 16) >= c6 + 2 && 2 * (length % 16) + 2 * c5 >= c6 && 2 * (length % 32) + c6 == 2 * (length % 16) + 2 * c5 && (2 * c5 - c6) % 32 == 0)
+        S_3(c0, 0, (c6 / 2) - (length % 16) + length);
+      if (length <= 15 && length >= c5 + 1 && c6 >= 1 && length >= c6)
+        S_0(c0, c5, c6 - 1);
+    }
diff --git a/final/lib/External/isl/test_inputs/codegen/separate2.in b/final/lib/External/isl/test_inputs/codegen/separate2.in
new file mode 100644
index 0000000..8f4ebf1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separate2.in
@@ -0,0 +1,4 @@
+# Check that rational affine expressions are printer properly.
+[tsteps, length] -> { S_0[iter, i, j] -> [iter, 0, o2, o3, 0, o5, o6, 4] : exists (e0 = [(o2)/32], e1 = [(o3)/32], e2 = [(-i + o5)/32], e3 = [(-31 + j - o6)/32]: tsteps = 2 and 32e0 = o2 and 32e1 = o3 and 32e2 = -i + o5 and 32e3 = -31 + j - o6 and o2 <= i and o2 >= -31 + i and o3 <= 1 + j and o3 >= -30 + j and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 31 and i <= -1 + length and i >= 0 and iter >= 0 and iter <= 1 and j <= -1 + length and j >= 0 and o2 >= -31 + length and o3 >= -30 + 2length); S_3[iter, 0, j] -> [iter, 0, o2, o3, o4, o5, o6, 2] : exists (e0 = [(o2)/32], e1 = [(o3)/32], e2 = [(o4)/32], e3 = [(-2o5 + o6)/32], e4 = [(j - o5)/32]: tsteps = 2 and 32e0 = o2 and 32e1 = o3 and 32e2 = o4 and 32e3 = -2o5 + o6 and 32e4 = j - o5 and iter <= 1 and j <= -1 + length and o2 <= j and o2 >= -31 + j and o3 <= 2j and o3 >= -30 + 2j and o4 >= 0 and o4 <= 31 and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 30 and j >= 1 and iter >= 0 and o2 >= -31 + length and o3 >= -30 + 2length) }
+[tsteps, length] -> {  : length >= 1 and length <= 1024 and tsteps = 2 }
+{ [o0,o1,o2,o3,o4,o5,o6,o7] -> separate[x] }
diff --git a/final/lib/External/isl/test_inputs/codegen/separation_class.c b/final/lib/External/isl/test_inputs/codegen/separation_class.c
new file mode 100644
index 0000000..daac0d7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separation_class.c
@@ -0,0 +1,17 @@
+{
+  for (int c0 = 0; c0 <= 8; c0 += 1) {
+    for (int c1 = 0; c1 <= -c0 + 8; c1 += 1)
+      for (int c2 = 10 * c0; c2 <= 10 * c0 + 9; c2 += 1)
+        for (int c3 = 10 * c1; c3 <= 10 * c1 + 9; c3 += 1)
+          A(c2, c3);
+    for (int c1 = -c0 + 9; c1 <= -c0 + 10; c1 += 1)
+      for (int c2 = 10 * c0; c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1)
+        for (int c3 = 10 * c1; c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1)
+          A(c2, c3);
+  }
+  for (int c0 = 9; c0 <= 10; c0 += 1)
+    for (int c1 = 0; c1 <= -c0 + 10; c1 += 1)
+      for (int c2 = 10 * c0; c2 <= min(10 * c0 + 9, -10 * c1 + 100); c2 += 1)
+        for (int c3 = 10 * c1; c3 <= min(10 * c1 + 9, -c2 + 100); c3 += 1)
+          A(c2, c3);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/separation_class.in b/final/lib/External/isl/test_inputs/codegen/separation_class.in
new file mode 100644
index 0000000..f42ea27
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separation_class.in
@@ -0,0 +1,6 @@
+{ A[i,j] -> [([i/10]),[j/10],i,j] : 0 <= i,j and i + j <= 100 }
+{ : }
+{ [a,b,c,d] -> separation_class[[0]->[0]] :
+	exists b': 0 <= 10a,10b' and 10a+9+10b'+9 <= 100;
+  [a,b,c,d] -> separation_class[[1]->[0]] :
+	0 <= 10a,10b and 10a+9+10b+9 <= 100 }
diff --git a/final/lib/External/isl/test_inputs/codegen/separation_class2.c b/final/lib/External/isl/test_inputs/codegen/separation_class2.c
new file mode 100644
index 0000000..80be0a7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separation_class2.c
@@ -0,0 +1,15 @@
+{
+  for (int c0 = 0; c0 < -(n % 8) + n; c0 += 8) {
+    for (int c1 = 0; c1 < -(n % 8) + n; c1 += 8)
+      for (int c2 = 0; c2 <= 7; c2 += 1)
+        for (int c3 = 0; c3 <= 7; c3 += 1)
+          A(c0 + c2, c1 + c3);
+    for (int c2 = 0; c2 <= 7; c2 += 1)
+      for (int c3 = 0; c3 < n % 8; c3 += 1)
+        A(c0 + c2, -(n % 8) + n + c3);
+  }
+  for (int c1 = 0; c1 < n; c1 += 8)
+    for (int c2 = 0; c2 < n % 8; c2 += 1)
+      for (int c3 = 0; c3 <= min(7, n - c1 - 1); c3 += 1)
+        A(-(n % 8) + n + c2, c1 + c3);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/separation_class2.in b/final/lib/External/isl/test_inputs/codegen/separation_class2.in
new file mode 100644
index 0000000..5469626
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separation_class2.in
@@ -0,0 +1,3 @@
+[n] -> { A[i,j] -> [it,jt, ip, jp] : 0 <= i,j < n and ip = i % 8 and it = i - ip and jp = j % 8 and jt = j - jp}
+[n] -> { : n >= 10}
+[n] -> { [it, jt, ip, jp] -> separation_class[[x]->[1]]: (exists id, jd: 0 <= x <= 3 and it < n - id and jt < n - jd and id = n %8 and jd = n %8)}
diff --git a/final/lib/External/isl/test_inputs/codegen/separation_class3.c b/final/lib/External/isl/test_inputs/codegen/separation_class3.c
new file mode 100644
index 0000000..cea4e04
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separation_class3.c
@@ -0,0 +1,31 @@
+for (int c0 = 0; c0 <= 4; c0 += 1) {
+  if (c0 == 0) {
+    S_0(0, 4);
+  } else {
+    S_0(2 * c0 - 1, 1);
+    if (c0 == 4) {
+      for (int c6 = 3; c6 <= 5; c6 += 1)
+        S_0(7, c6);
+    } else {
+      for (int c4 = 2 * c0 - 1; c4 <= 2 * c0; c4 += 1)
+        for (int c6 = -2 * c0 + c4 + 4; c6 <= 2 * c0 - c4 + 4; c6 += 1)
+          S_0(c4, c6);
+    }
+  }
+  for (int c4 = max(0, 2 * c0 - 1); c4 <= min(7, 2 * c0); c4 += 1)
+    for (int c6 = -2 * c0 + c4 + 8; c6 <= 8; c6 += 1)
+      S_0(c4, c6);
+  if (c0 >= 1 && c0 <= 3) {
+    for (int c2 = 0; c2 <= 1; c2 += 1)
+      for (int c4 = 2 * c0 - 1; c4 <= 2 * c0; c4 += 1)
+        for (int c6 = 2 * c0 + 4 * c2 - c4 + 1; c6 <= -2 * c0 + 4 * c2 + c4 + 3; c6 += 1)
+          S_0(c4, c6);
+  } else if (c0 == 4) {
+    for (int c2 = 0; c2 <= 1; c2 += 1)
+      S_0(7, 4 * c2 + 2);
+  } else {
+    for (int c2 = 0; c2 <= 1; c2 += 1)
+      for (int c6 = 4 * c2 + 1; c6 <= 4 * c2 + 3; c6 += 1)
+        S_0(0, c6);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/separation_class3.in b/final/lib/External/isl/test_inputs/codegen/separation_class3.in
new file mode 100644
index 0000000..1aaf251
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separation_class3.in
@@ -0,0 +1,4 @@
+{ S_0[t, i] -> [o0, 1, o2, 0, t, 0, i] : 4o2 >= -4 + t + i - 2o0 and 4o2 >= -3 - t + i + 2o0 and 2o0 <= 1 + t and 2o0 >= t and 4o2 <= -1 + t + i - 2o0 and t >= 0 and t <= 7 and i >= 1 and i <= 8; S_0[t, i] -> [o0, 0, o2, 0, t, 0, i] : 4o2 >= t + i - 2o0 and 4o2 <= -t + i + 2o0 and 2o0 <= 1 + t and 2o0 >= t and t >= 0 and t <= 7 and i >= 1 and i <= 8 }
+{:}
+{ [i0, 1, i2, i3, i4, i5, i6] -> separation_class[[2] -> [0]] : i2 <= 1 and i2 >= 0 and i0 <= 3 and i0 >= 1; [i0, 0, 1, i3, i4, i5, i6] -> separation_class[[2] -> [0]] : i0 <= 3 and i0 >= 1; [i0, i1, i2, i3, i4, i5, i6] -> unroll[1] }
+
diff --git a/final/lib/External/isl/test_inputs/codegen/separation_class4.c b/final/lib/External/isl/test_inputs/codegen/separation_class4.c
new file mode 100644
index 0000000..6d877d6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separation_class4.c
@@ -0,0 +1,22 @@
+for (int c0 = 0; c0 <= 128; c0 += 1) {
+  if (c0 <= 127) {
+    if (c0 == 0) {
+      for (int c3 = 0; c3 <= 1; c3 += 1)
+        for (int c5 = c3 + 58; c5 <= -c3 + 61; c5 += 1)
+          S_0(c3, c5);
+    } else {
+      for (int c2 = 1; c2 <= 2; c2 += 1)
+        for (int c3 = max(4 * c0 - 2, 4 * c0 + 6 * c2 - 12); c3 <= min(4 * c0 + 1, 4 * c0 + 6 * c2 - 7); c3 += 1)
+          for (int c5 = max(4 * c0 - c3 + 57, -4 * c0 + c3 + 58); c5 <= min(4 * c0 - c3 + 61, -4 * c0 + c3 + 62); c5 += 1)
+            S_0(c3, c5);
+    }
+    for (int c2 = 1; c2 <= 2; c2 += 1)
+      for (int c3 = max(4 * c0, 4 * c0 + 6 * c2 - 10); c3 <= min(4 * c0 + 3, 4 * c0 + 6 * c2 - 5); c3 += 1)
+        for (int c5 = max(-4 * c0 + c3 + 59, 4 * c0 - c3 + 62); c5 <= min(-4 * c0 + c3 + 63, 4 * c0 - c3 + 66); c5 += 1)
+          S_0(c3, c5);
+  } else {
+    for (int c3 = 510; c3 <= 511; c3 += 1)
+      for (int c5 = -c3 + 569; c5 < c3 - 449; c5 += 1)
+        S_0(c3, c5);
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/separation_class4.in b/final/lib/External/isl/test_inputs/codegen/separation_class4.in
new file mode 100644
index 0000000..c04dd79
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separation_class4.in
@@ -0,0 +1,10 @@
+# Check that isl is not confused by the combination of separation classes
+# and unroll.
+{ S_0[t, i] -> [o0, 1, o9, t] : 4o0 >= -3 + t and 4o0 <= t and i >= 60 and i <= 65 and 6o9 >= 5 + t - 4o0 and 6o9 <= 10 + t - 4o0 and 4o0 <= -62 + t + i and 4o0 >= 59 + t - i and o0 >= 0 and o0 <= 127 and t <= 511 and t >= 0 and 4o0 >= -66 + t + i and 4o0 <= 63 + t - i;
+S_0[t, i] -> [o0, 0, o9, t] : 4o0 >= -1 + t and 4o0 <= 2 + t and i >= 57 and i <= 62 and 6o9 >= 7 + t - 4o0 and 6o9 <= 12 + t - 4o0 and t >= 0 and t <= 511 and 4o0 <= -57 + t + i and 4o0 >= 58 + t - i and o0 >= 0 and o0 <= 128 and 4o0 >= -61 + t + i and 4o0 <= 62 + t - i }
+{ : }
+{ [i0, i1, i2, t] -> unroll[1];
+[i0, 1, i2, t] -> separation_class[[1] -> [0]]
+	: 0 <= i0 <= 127;
+[i0, 0, i2, t] -> separation_class[[1] -> [0]]
+	: 1 <= i0 <= 127}
diff --git a/final/lib/External/isl/test_inputs/codegen/shift.c b/final/lib/External/isl/test_inputs/codegen/shift.c
new file mode 100644
index 0000000..f4156bc
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/shift.c
@@ -0,0 +1,4 @@
+for (int c0 = 0; c0 <= 9; c0 += 1) {
+  A(c0);
+  B(c0);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/shift.in b/final/lib/External/isl/test_inputs/codegen/shift.in
new file mode 100644
index 0000000..702c527
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/shift.in
@@ -0,0 +1,3 @@
+{ A[i] -> [2i]: 0 <= i < 10; B[i] -> [2i+1] : 0 <= i < 10 }
+{ : }
+{ }
diff --git a/final/lib/External/isl/test_inputs/codegen/shift2.c b/final/lib/External/isl/test_inputs/codegen/shift2.c
new file mode 100644
index 0000000..a0571c9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/shift2.c
@@ -0,0 +1,56 @@
+for (int c0 = 0; c0 <= 1; c0 += 1) {
+  for (int c1 = 0; c1 < length - 1; c1 += 32) {
+    for (int c2 = c1; c2 < length; c2 += 32) {
+      if (c1 == 0)
+        for (int c3 = 0; c3 <= min(length, 2 * c2 - 31); c3 += 32)
+          for (int c5 = 0; c5 <= min(31, length - c2 - 1); c5 += 1)
+            for (int c6 = max(0, -c3 + 1); c6 <= min(31, length - c3); c6 += 1)
+              S_0(c0, c2 + c5, c3 + c6 - 1);
+      for (int c3 = 2 * c2; c3 <= min(2 * length - 2, 2 * c2 + 62); c3 += 32)
+        for (int c4 = 0; c4 <= min(min(31, length - c1 - 2), (c3 / 2) - c1 + 14); c4 += 1) {
+          if (c1 == 0 && c2 == 0 && c4 == 0)
+            for (int c6 = max(0, -c3 + 1); c6 <= min(31, length - c3); c6 += 1)
+              S_0(c0, 0, c3 + c6 - 1);
+          if (c1 == 0 && c3 == 2 * c2 + 32 && c4 == 0)
+            for (int c5 = max(0, -c2 + 1); c5 <= 15; c5 += 1)
+              for (int c6 = 0; c6 <= min(31, length - 2 * c2 - 32); c6 += 1)
+                S_0(c0, c2 + c5, 2 * c2 + c6 + 31);
+          for (int c5 = max((c3 / 2) - c2, c1 - c2 + c4 + 1); c5 <= min(length - c2 - 1, (c3 / 2) - c2 + 15); c5 += 1) {
+            if (c1 == 0 && c4 == 0)
+              for (int c6 = max(0, -c3 + 1); c6 <= min(length - c3, 2 * c2 - c3 + 2 * c5 - 1); c6 += 1)
+                S_0(c0, c2 + c5, c3 + c6 - 1);
+            S_3(c0, c1 + c4, c2 + c5);
+            if (c1 == 0 && c4 == 0 && length >= 2 * c2 + 2 * c5)
+              S_0(c0, c2 + c5, 2 * c2 + 2 * c5 - 1);
+            if (c1 == 0 && c4 == 0)
+              for (int c6 = 2 * c2 - c3 + 2 * c5 + 1; c6 <= min(31, length - c3); c6 += 1)
+                S_0(c0, c2 + c5, c3 + c6 - 1);
+          }
+          if (c1 == 0 && c3 == 2 * c2 && c4 == 0)
+            for (int c5 = 16; c5 <= min(31, length - c2 - 1); c5 += 1)
+              for (int c6 = max(0, -2 * c2 + 1); c6 <= min(31, length - 2 * c2); c6 += 1)
+                S_0(c0, c2 + c5, 2 * c2 + c6 - 1);
+          if (c1 == 0 && c3 + 30 >= 2 * length && c4 == 0)
+            S_4(c0);
+        }
+      if (c1 == 0) {
+        for (int c3 = 2 * c2 + 64; c3 <= length; c3 += 32)
+          for (int c5 = 0; c5 <= 31; c5 += 1)
+            for (int c6 = 0; c6 <= min(31, length - c3); c6 += 1)
+              S_0(c0, c2 + c5, c3 + c6 - 1);
+        if (c2 + 16 == length)
+          S_4(c0);
+      }
+    }
+    if (c1 == 0 && length % 32 == 0)
+      S_4(c0);
+  }
+  if (length <= 1)
+    for (int c5 = 0; c5 <= length; c5 += 1) {
+      if (c5 == length) {
+        S_4(c0);
+      } else {
+        S_0(c0, 0, 0);
+      }
+    }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/shift2.in b/final/lib/External/isl/test_inputs/codegen/shift2.in
new file mode 100644
index 0000000..3c05fac
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/shift2.in
@@ -0,0 +1,5 @@
+# Check that the shifting code is not confused by domains that
+# have a non-obviously fixed value.
+[tsteps, length] -> { S_4[iter] -> [iter, 0, o2, o3, 0, o5, o6, 3] : exists (e0 = [(o2)/32], e1 = [(o3)/32], e2 = [(-length + o5)/32], e3 = [(-2length + o6)/32]: tsteps = 2 and 32e0 = o2 and 32e1 = o3 and 32e2 = -length + o5 and 32e3 = -2length + o6 and o2 <= length and o2 >= -31 + length and o3 <= 2length and o3 >= -30 + 2length and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 30 and iter <= 1 and iter >= 0); S_3[iter, i, j] -> [iter, o1, o2, o3, o4, o5, o6, 2] : exists (e0 = [(o1)/32], e1 = [(o2)/32], e2 = [(o3)/32], e3 = [(-i + o4)/32], e4 = [(-j + o5)/32], e5 = [(-2j + o6)/32]: tsteps = 2 and 32e0 = o1 and 32e1 = o2 and 32e2 = o3 and 32e3 = -i + o4 and 32e4 = -j + o5 and 32e5 = -2j + o6 and o1 <= i and o1 >= -31 + i and o2 <= j and o2 >= -31 + j and o3 <= 2j and o3 >= -30 + 2j and o4 >= 0 and o4 <= 31 and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 30 and j >= 1 + i and i >= 0 and iter <= 1 and iter >= 0 and j <= -1 + length); S_0[iter, i, j] -> [iter, 0, o2, o3, 0, o5, o6, 4] : exists (e0 = [(o2)/32], e1 = [(o3)/32], e2 = [(-i + o5)/32], e3 = [(-31 + j - o6)/32]: tsteps = 2 and 32e0 = o2 and 32e1 = o3 and 32e2 = -i + o5 and 32e3 = -31 + j - o6 and o2 <= i and o2 >= -31 + i and o3 <= 1 + j and o3 >= -30 + j and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 31 and i <= -1 + length and i >= 0 and iter >= 0 and iter <= 1 and j <= -1 + length and j >= 0) }
+[tsteps, length] -> {  : length >= 0 and length <= 1024 and tsteps = 2 }
+{ }
diff --git a/final/lib/External/isl/test_inputs/codegen/shift_unroll.c b/final/lib/External/isl/test_inputs/codegen/shift_unroll.c
new file mode 100644
index 0000000..2a38286
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/shift_unroll.c
@@ -0,0 +1,14 @@
+for (int c0 = 0; c0 <= 9; c0 += 1) {
+  A(c0, 0);
+  A(c0, 1);
+  A(c0, 2);
+  A(c0, 3);
+  A(c0, 4);
+  A(c0, 5);
+  A(c0, 6);
+  A(c0, 7);
+  A(c0, 8);
+  A(c0, 9);
+  for (int c2 = 0; c2 <= 9; c2 += 1)
+    B(c0, c2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/shift_unroll.in b/final/lib/External/isl/test_inputs/codegen/shift_unroll.in
new file mode 100644
index 0000000..4b773c2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/shift_unroll.in
@@ -0,0 +1,3 @@
+{ A[i,j] -> [2i,0,j]: 0 <= i,j < 10; B[i,j] -> [2i+1,1,j] : 0 <= i,j < 10 }
+{ : }
+{ [i,0,j] -> unroll[2] }
diff --git a/final/lib/External/isl/test_inputs/codegen/single_valued.c b/final/lib/External/isl/test_inputs/codegen/single_valued.c
new file mode 100644
index 0000000..e071002
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/single_valued.c
@@ -0,0 +1,2 @@
+if (2 * ((t1 - 1) % 64) + 8 >= t1)
+  S(-(2 * ((t1 - 1) % 64)) + t1 + 126);
diff --git a/final/lib/External/isl/test_inputs/codegen/single_valued.in b/final/lib/External/isl/test_inputs/codegen/single_valued.in
new file mode 100644
index 0000000..d729942
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/single_valued.in
@@ -0,0 +1,5 @@
+# Check that isl recognizes that the inverse schedule is single-valued
+# and does not end up in an infinite recursion.
+[t1] -> {S[c2] -> [c2]: t1 <= c2 <= 134 and (c2+t1) % 128 = 0 and c2 > 0}
+[t1] -> {: t1 > 0}
+[t1] -> {}
diff --git a/final/lib/External/isl/test_inputs/codegen/sor1d-part.c b/final/lib/External/isl/test_inputs/codegen/sor1d-part.c
new file mode 100644
index 0000000..096d34d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/sor1d-part.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 < max((6 * M + 3 * N + 188) / 200 - 2, (N + 93) / 100 + 3 * ((2 * M + N - 4) / 200) - 1); c0 += 1)
+  for (int c1 = max(0, floord(-N + 100 * c0 + 106, 300)); c1 <= min((2 * M + N - 4) / 200 - 1, (c0 - 1) / 3); c1 += 1)
+    S2(c0 - c1, c1);
diff --git a/final/lib/External/isl/test_inputs/codegen/sor1d-part.st b/final/lib/External/isl/test_inputs/codegen/sor1d-part.st
new file mode 100644
index 0000000..9bbf3d3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/sor1d-part.st
@@ -0,0 +1,10 @@
+# Check that a proper upper bound is generated for the outer loop.
+# Earlier versions of isl would generate an incorrect bound.
+domain: "[M, N] -> { S2[i0, i1] : i1 >= 0 and  200i1 >= -193 - N + 100i0 and i0 >= 0 and 200i1 <= -204 + 2M + N and 2i1 <= -1 + i0 and 100i1 >= -94 - N + 50i0 and 100i1 >= -94 - N }"
+child:
+  context: "[M, N] -> { [] : M >= 0 and N >= 4 }"
+  child:
+    schedule: "[M, N] -> [{ S2[i0, i1] -> [(i0 + i1)]}]"
+    options: "[M, N] -> { separate[i0] }"
+    child:
+          schedule: "[M, N] -> [{ S2[i0, i1] -> [(i1)]}]"
diff --git a/final/lib/External/isl/test_inputs/codegen/stride.c b/final/lib/External/isl/test_inputs/codegen/stride.c
new file mode 100644
index 0000000..5b68829
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/stride.c
@@ -0,0 +1,6 @@
+for (int c0 = 0; c0 <= 100; c0 += 2) {
+  for (int c3 = 0; c3 <= 100; c3 += 1)
+    A(c0, c3);
+  for (int c2 = 0; c2 <= 100; c2 += 1)
+    B(c0, c2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/stride.in b/final/lib/External/isl/test_inputs/codegen/stride.in
new file mode 100644
index 0000000..b01c566
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/stride.in
@@ -0,0 +1,6 @@
+# Check that we find a common stride on the first dimension
+# even if it is imposed by different inner dimensions
+{ A[i,k] -> [i,0,j,k] : 0 <= i,k <= 100 and i = 2 j;
+  B[i,k] -> [i,1,k,j] : 0 <= i,k <= 100 and i = 2 j }
+{ : }
+{ }
diff --git a/final/lib/External/isl/test_inputs/codegen/stride5.c b/final/lib/External/isl/test_inputs/codegen/stride5.c
new file mode 100644
index 0000000..5954439
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/stride5.c
@@ -0,0 +1,3 @@
+if (n % 2 == 0)
+  for (int c0 = (-n / 2) + 2 * floord(n - 1, 4) + 2; c0 <= 100; c0 += 2)
+    S(c0);
diff --git a/final/lib/External/isl/test_inputs/codegen/stride5.in b/final/lib/External/isl/test_inputs/codegen/stride5.in
new file mode 100644
index 0000000..a67a802
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/stride5.in
@@ -0,0 +1,3 @@
+[n] -> { S[t] -> [t] : exists e : 2 t - n = 4e and 0 <= t <= 100 }
+[n] -> { : }
+{ }
diff --git a/final/lib/External/isl/test_inputs/codegen/stride6.c b/final/lib/External/isl/test_inputs/codegen/stride6.c
new file mode 100644
index 0000000..c09e8b5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/stride6.c
@@ -0,0 +1,4 @@
+for (int c1 = -1024; c1 <= 0; c1 += 32)
+  for (int c2 = max(-((niter - 1) % 32) + niter - 1, -((niter - c1) % 32) + niter - c1 - 32); c2 <= min(niter + 1022, niter - c1 - 1); c2 += 32)
+    for (int c5 = max(max(0, -c1 - 1023), niter - c1 - c2 - 32); c5 <= min(min(31, -c1), niter - c1 - c2 - 1); c5 += 1)
+      S_4(niter - 1, -c1 - c5);
diff --git a/final/lib/External/isl/test_inputs/codegen/stride6.in b/final/lib/External/isl/test_inputs/codegen/stride6.in
new file mode 100644
index 0000000..86ca54a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/stride6.in
@@ -0,0 +1,3 @@
+[niter] -> { S_4[-1 + niter, i] -> [o0, o1, o2, o3, o4, o5, o6, o7, 4] : exists (e0 = [(o0)/32], e1 = [(o1)/32], e2 = [(o2)/32], e3 = [(o3)/32], e4 = [(-31i + o5)/32], e5 = [(-i - o4 + o6)/32], e6 = [(-o4 + o7)/32], e7 = [(-1 + niter - o4)/32]: 32e0 = o0 and 32e1 = o1 and 32e2 = o2 and 32e3 = o3 and 32e4 = -31i + o5 and 32e5 = -i - o4 + o6 and 32e6 = -o4 + o7 and 32e7 = -1 + niter - o4 and o0 <= -1 + niter and o0 >= -32 + niter and o1 <= -i and o1 >= -31 - i and o2 <= -1 + niter + i and o2 >= -32 + niter + i and o3 <= 1023 + niter and o3 >= 992 + niter and o4 >= 0 and o4 <= 31 and o5 >= 0 and o5 <= 31 and o6 >= 0 and o6 <= 31 and o7 >= 0 and o7 <= 31 and i <= 1023 and i >= 0 and niter >= 1) }
+[niter] -> {  : niter <= 8192 and niter >= 1 }
+[niter] -> {  }
diff --git a/final/lib/External/isl/test_inputs/codegen/stride7.c b/final/lib/External/isl/test_inputs/codegen/stride7.c
new file mode 100644
index 0000000..b64c66d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/stride7.c
@@ -0,0 +1,6 @@
+for (int c0 = 2; c0 <= 200; c0 += 64) {
+  for (int c2 = c0 - 1; c2 <= 120; c2 += 1)
+    s2(c0, c2);
+  for (int c2 = 122; c2 <= c0 + 62; c2 += 1)
+    s4(c0, c2);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/stride7.in b/final/lib/External/isl/test_inputs/codegen/stride7.in
new file mode 100644
index 0000000..cac9cac
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/stride7.in
@@ -0,0 +1,7 @@
+# Check that no redundant guards are introduced
+{ s4[a, b] -> [a, 2, b] : exists (e0 = floor((-2 + a)/64):
+    64e0 = -2 + a and a <= 200 and b <= 62 + a and b >= 122);
+  s2[a, b] -> [a, 2, b] : exists (e0 = floor((-2 + a)/64):
+    64e0 = -2 + a and a >= 2 and b <= 120 and b >= -1 + a and a <= 100) }
+{ : }
+{ }
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll.c b/final/lib/External/isl/test_inputs/codegen/unroll.c
new file mode 100644
index 0000000..63594bb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll.c
@@ -0,0 +1,5 @@
+{
+  A(0);
+  A(100000000);
+  A(200000000);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll.in b/final/lib/External/isl/test_inputs/codegen/unroll.in
new file mode 100644
index 0000000..65561e2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll.in
@@ -0,0 +1,5 @@
+# Test that unrolling takes into account stride constraints.
+# If it didn't, it would run essentially forever on this example.
+[n] -> { A[i] -> [i] : exists a : i = 100000000 a and 0 <= a <= 2 }
+{:}
+{ [i] -> unroll[0] }
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll10.c b/final/lib/External/isl/test_inputs/codegen/unroll10.c
new file mode 100644
index 0000000..061954e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll10.c
@@ -0,0 +1,29 @@
+if (m >= 1 && n >= 1) {
+  A(0);
+  if (m >= 2 && n >= 2) {
+    A(1);
+    if (m >= 3 && n >= 3) {
+      A(2);
+      if (m >= 4 && n >= 4) {
+        A(3);
+        if (m >= 5 && n >= 5) {
+          A(4);
+          if (m >= 6 && n >= 6) {
+            A(5);
+            if (m >= 7 && n >= 7) {
+              A(6);
+              if (m >= 8 && n >= 8) {
+                A(7);
+                if (m >= 9 && n >= 9) {
+                  A(8);
+                  if (m >= 10 && n >= 10)
+                    A(9);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll10.in b/final/lib/External/isl/test_inputs/codegen/unroll10.in
new file mode 100644
index 0000000..5890c4e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll10.in
@@ -0,0 +1,4 @@
+# Check that all information is taken into account while trying to unroll
+[m,n] -> { A[i] -> [i] : 0 <= i < n,m }
+[m,n] -> { : m <= 10 or n <= 10 }
+{ [i] -> unroll[x] }
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll10.st b/final/lib/External/isl/test_inputs/codegen/unroll10.st
new file mode 100644
index 0000000..77c5b19
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll10.st
@@ -0,0 +1,7 @@
+# Check that all information is taken into account while trying to unroll
+domain: "[m,n] -> { A[i] : 0 <= i < n,m }"
+child:
+  context: "[m,n] -> { [] : m <= 10 or n <= 10 }"
+  child:
+    schedule: "[{ A[i] -> [i] }]"
+    options: "{ unroll[x] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll11.c b/final/lib/External/isl/test_inputs/codegen/unroll11.c
new file mode 100644
index 0000000..c1fc529
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll11.c
@@ -0,0 +1,8 @@
+{
+  if (t1 >= 126)
+    S(0, t1 - 384);
+  S(0, t1 - 256);
+  if (t1 >= 126)
+    S(1, t1 - 384);
+  S(1, t1 - 256);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll11.in b/final/lib/External/isl/test_inputs/codegen/unroll11.in
new file mode 100644
index 0000000..79445e2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll11.in
@@ -0,0 +1,10 @@
+# Check that the most appropriate lower bound is selected
+[t1,t2]->{ S[i,j] -> [i,j] : exists (alpha, beta :
+    0 <= i <= 1 &&
+    t1 = j+128alpha &&
+    0 <= j+2beta < 128 &&
+    510 <= t2+2beta <= 514 &&
+    0 <= 2beta - t2 <= 5
+)}
+[t1,t2] -> {: 125 <= t1 <= 127 and 254 <= t2 < 257}
+{[i,j] -> unroll[x]}
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll2.c b/final/lib/External/isl/test_inputs/codegen/unroll2.c
new file mode 100644
index 0000000..7ae38be
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll2.c
@@ -0,0 +1,11 @@
+{
+  A(0);
+  A(1);
+  A(2);
+  A(3);
+  for (int c0 = 4; c0 <= 99996; c0 += 1)
+    A(c0);
+  A(99997);
+  A(99998);
+  A(99999);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll2.in b/final/lib/External/isl/test_inputs/codegen/unroll2.in
new file mode 100644
index 0000000..0fb36ab
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll2.in
@@ -0,0 +1,5 @@
+# Check that the different disjuncts in the unroll option
+# are handled separately.
+{ A[i] -> [i] : 0 <= i < 100000 }
+{ : }
+{ [i] -> unroll[0] : i < 4 or i > 99996 }
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll3.c b/final/lib/External/isl/test_inputs/codegen/unroll3.c
new file mode 100644
index 0000000..f6f390d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll3.c
@@ -0,0 +1,2 @@
+if ((t1 + 121) % 128 <= 123)
+  write_shared_A(((t1 + 121) % 128) + 1);
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll3.in b/final/lib/External/isl/test_inputs/codegen/unroll3.in
new file mode 100644
index 0000000..098e501
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll3.in
@@ -0,0 +1,6 @@
+# Check that the entire schedule is completely unrolled and
+# in particular that no spurious loop is introduced.
+[t1] -> { write_shared_A[i2] -> [1, 3, 6 + i2, 0, t1] : (exists (e0 = [(-6 + t1 - i2)/128]: 128e0 = -6 + t1 - i2 and i2 <= 122 and i2 >= 1 and t1 >= 0 and t1 <= 127)) or (exists (e0 = [(-6 + t1 - i2)/128]: 128e0 = -6 + t1 - i2 and i2 >= 123 and i2 <= 124 and t1 <= 127 and t1 >= 0 )) }
+[t1] -> { : t1 >= 0 and t1 <= 127 }
+[t1] -> { [i0, i1, i2, i3, i4] -> unroll[o0] }
+
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll4.c b/final/lib/External/isl/test_inputs/codegen/unroll4.c
new file mode 100644
index 0000000..6d4c341
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll4.c
@@ -0,0 +1,16 @@
+{
+  write_shared_A(3, ((t1 + 3) % 4) + 1, ((t2 + 31) % 32) + 1);
+  if (t2 >= 1 && t2 <= 2 && t1 % 3 == 0)
+    write_shared_A(3, (-t1 / 3) + 4, t2 + 32);
+  if (((-((t1 + 3) % 4) + t2 + 30) % 32) + t1 >= ((t1 + 3) % 4) + ((t2 + 1) % 2) - 4 * ((-t1 + 4) / 4) + 1)
+    write_shared_A(3, ((t1 + 3) % 4) + 5, -((((t1 + 3) % 4) - t2 + 33) % 32) + t1 + 4 * ((-t1 + 4) / 4) + 32);
+  if (t1 >= 1 && t2 >= t1 + 1 && t2 <= 4)
+    write_shared_A(3, t1 + 4, t2 + 32);
+  write_shared_A(4, ((t1 + 3) % 4) + 1, ((t2 + 31) % 32) + 1);
+  if (t2 >= 1 && t2 <= 2 && t1 % 3 == 0)
+    write_shared_A(4, (-t1 / 3) + 4, t2 + 32);
+  if (((-((t1 + 3) % 4) + t2 + 30) % 32) + t1 >= ((t1 + 3) % 4) + ((t2 + 1) % 2) - 4 * ((-t1 + 4) / 4) + 1)
+    write_shared_A(4, ((t1 + 3) % 4) + 5, -((((t1 + 3) % 4) - t2 + 33) % 32) + t1 + 4 * ((-t1 + 4) / 4) + 32);
+  if (t1 >= 1 && t2 >= t1 + 1 && t2 <= 4)
+    write_shared_A(4, t1 + 4, t2 + 32);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll4.in b/final/lib/External/isl/test_inputs/codegen/unroll4.in
new file mode 100644
index 0000000..d8be866
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll4.in
@@ -0,0 +1,5 @@
+# Check that the generated code does not contain two declarations
+# of the same variable in the same scope.
+[t1, t2, g] -> { write_shared_A[a, b, c] -> [0, a, b, c] : exists (e0, e1 = [(-t1 + b)/4], e2 = [(-t2 + c)/32]: 4e1 = -t1 + b and 32e2 = -t2 + c and e0 <= 2 + 3g and e0 >= 3g and a <= 4 and a >= 3 and t2 >= 0 and t1 <= 3 and 2e0 >= 5 - c + 6g and 2e0 <= 36 - c + 6g and 2e0 >= 5 - b + 6g and 2e0 <= 8 - b + 6g and 2e0 <= 638 - c and 2e0 <= 638 - b and 2e0 >= 2 - a + 6g and 2e0 >= -8 + a + 6g and 2e0 <= 1 + a + 6g and 2e0 <= 11 - a + 6g and e0 >= 0 and e0 <= 254 and t1 >= 0 and t2 <= 31 and b >= 1 and b <= 126 and c >= 1 and c <= 126 and g <= 3 and g >= 0) }
+[t1, t2, g] -> { : g <= 3 and g >= 0 and t1 >= 0 and t1 <= 3 and t2 >= 0 and t2 <= 5 }
+[t1, t2] -> { [i0, i1, i2, i3] -> unroll[x] }
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll6.c b/final/lib/External/isl/test_inputs/codegen/unroll6.c
new file mode 100644
index 0000000..1d8cc5e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll6.c
@@ -0,0 +1,8 @@
+{
+  if (g >= 0 && nn >= 128 * g + 6 && nn >= ((t1 + 127) % 128) + 128 * g + 3)
+    for (int c1 = 393214; c1 < nn - 1; c1 += 393216)
+      A(c1, ((t1 + 127) % 128) + 128 * g + 1, ((t1 + 127) % 128) + 1);
+  if (t1 >= 1 && t1 <= 2 && nn >= t1 + 128 * g + 130 && t1 + 128 * g >= -127)
+    for (int c1 = 393214; c1 < nn - 1; c1 += 393216)
+      A(c1, t1 + 128 * g + 128, t1 + 128);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll6.in b/final/lib/External/isl/test_inputs/codegen/unroll6.in
new file mode 100644
index 0000000..b4338e3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll6.in
@@ -0,0 +1,7 @@
+# Check that the right lower bound is chosen for unrolling.
+# Older versions of isl would pick a lower bound that resulted
+# in a number of slices that exceeds the maximal value of an integer
+# and then only generated code for a truncated number (zero) of slices.
+[nn, t1, g] -> { A[a, b, c] -> [c] : exists (e0 = [(2 + a)/393216], e1 = [(t1 - c)/128]: 128g = b - c and 393216e0 = 2 + a and 128e1 = t1 - c and c <= 130 and c >= 6 - nn + b and c <= 128 + b and nn >= 137 and t1 >= 0 and c >= 1 and a <= -2 + nn and a >= 1 and nn <= 9223372036854775807 and b >= 1 and b <= -2 + nn and t1 <= 127) }
+[nn, t1, g] -> { : nn <= 9223372036854775807 and nn >= 137 and t1 >= 0 and t1 <= 127 }
+{ [c] -> unroll[x] }
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll7.c b/final/lib/External/isl/test_inputs/codegen/unroll7.c
new file mode 100644
index 0000000..8392185
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll7.c
@@ -0,0 +1,10 @@
+{
+  S(0, 0);
+  S(0, 3);
+  S(0, 4);
+  S(1, 1);
+  S(1, 4);
+  S(2, 2);
+  S(3, 3);
+  S(4, 4);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll7.in b/final/lib/External/isl/test_inputs/codegen/unroll7.in
new file mode 100644
index 0000000..494e597
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll7.in
@@ -0,0 +1,5 @@
+# Check that some code is generated.
+# Older versions of isl would abort on unknown divs.
+{ S[i,j] -> [i,j]: exists (alpha, beta: j=i+4alpha +3beta and 0 <= alpha < 24 and 0 <= beta and 0 <= i,j < 5) }
+{ : }
+{ [i,j] -> unroll[x] }
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll8.c b/final/lib/External/isl/test_inputs/codegen/unroll8.c
new file mode 100644
index 0000000..b3ca142
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll8.c
@@ -0,0 +1,6 @@
+for (int c0 = 0; c0 <= 99; c0 += 1) {
+  A(c0, 0);
+  A(c0, 1);
+  B(c0, 0);
+  B(c0, 1);
+}
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll8.st b/final/lib/External/isl/test_inputs/codegen/unroll8.st
new file mode 100644
index 0000000..94fb49e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll8.st
@@ -0,0 +1,5 @@
+# Check that options are adjusted by shifted stride detection
+domain: "{ A[i,j] : 0 <= i < 100 and 0 <= j < 2; B[i,j] : 0 <= i < 100 and 0 <= j < 2 }"
+child:
+  schedule: "[{ A[i,j] -> [2i]; B[i,j] -> [2i+1] }, { A[i,j] -> [j]; B[i,j] -> [j]}]"
+  options: "{ unroll[1] }"
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll9.c b/final/lib/External/isl/test_inputs/codegen/unroll9.c
new file mode 100644
index 0000000..b00ea41
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll9.c
@@ -0,0 +1,7 @@
+for (int c0 = 0; c0 <= 99; c0 += 1)
+  for (int c1 = 0; c1 <= 99; c1 += 1) {
+    A(c1, 0, c0);
+    A(c1, 1, c0);
+    B(c1, 0, c0);
+    B(c1, 1, c0);
+  }
diff --git a/final/lib/External/isl/test_inputs/codegen/unroll9.st b/final/lib/External/isl/test_inputs/codegen/unroll9.st
new file mode 100644
index 0000000..653da41
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll9.st
@@ -0,0 +1,7 @@
+# Check that options are interpreted locally
+domain: "{ A[i,j,k] : 0 <= i,k < 100 and 0 <= j < 2; B[i,j,k] : 0 <= i,k < 100 and 0 <= j < 2 }"
+child:
+  schedule: "[{ A[i,j,k] -> [k]; B[i,j,k] -> [k] }]"
+  child:
+    schedule: "[{ A[i,j,k] -> [2i]; B[i,j,k] -> [2i+1] }, { A[i,j,k] -> [j]; B[i,j,k] -> [j]}]"
+    options: "{ unroll[1] }"
diff --git a/final/lib/External/isl/test_inputs/convex0.polylib b/final/lib/External/isl/test_inputs/convex0.polylib
new file mode 100644
index 0000000..cbc4d3b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex0.polylib
@@ -0,0 +1,11 @@
+2 3
+1 1 0
+1 -1 1
+
+2 3
+1 1 -1
+1 -1 2
+
+2 3
+1 1 0
+1 -1 2
diff --git a/final/lib/External/isl/test_inputs/convex1.polylib b/final/lib/External/isl/test_inputs/convex1.polylib
new file mode 100644
index 0000000..b563d8d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex1.polylib
@@ -0,0 +1,17 @@
+# {j,N | 0<=j<=N-1; 2<=N}
+4 4
+1   1  0   0
+1  -1  1  -1
+1   0  1  -2
+1   0  0   1
+# {j, N | 1<=j<=N; 1<=N}
+4 4
+1  1  0  -1
+1 -1  1   0
+1  0  1  -1
+1  0  0   1
+# {j,N | 0<=j<=N; 2<=j+N}
+3 4
+   1    1    1   -2
+   1    1    0    0
+   1   -1    1    0
diff --git a/final/lib/External/isl/test_inputs/convex10.polylib b/final/lib/External/isl/test_inputs/convex10.polylib
new file mode 100644
index 0000000..3d58cbf
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex10.polylib
@@ -0,0 +1,17 @@
+3 4
+1 54 1 -4
+1 2 -1 58
+1 0 -1 6
+
+4 4
+1 54 1 -4
+1 2 -1 58
+1 0 1 -7
+1 -4 1 0
+
+4 4
+1  54    1   -4
+1   2   -1   58
+1   0   -1  116
+1   0    0    1
+
diff --git a/final/lib/External/isl/test_inputs/convex11.polylib b/final/lib/External/isl/test_inputs/convex11.polylib
new file mode 100644
index 0000000..f664114
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex11.polylib
@@ -0,0 +1,14 @@
+3 4
+1 0 -1 6
+1 -1 1 1
+1 1 1 -10
+
+3 4
+1 1 0 -4
+1 -1 -1 8
+1 -1 1 1
+
+3 4
+1 0 -1 6
+1 1 0 -4
+1 -1 1 1
diff --git a/final/lib/External/isl/test_inputs/convex12.polylib b/final/lib/External/isl/test_inputs/convex12.polylib
new file mode 100644
index 0000000..e476630
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex12.polylib
@@ -0,0 +1,12 @@
+3 5
+1   0    0    1    1
+1   0    1    0    1
+1  -1   -1    0   -2
+
+3 5
+1   0    0    1    2
+1   1   -1    0    0
+1   1    0    0   -1
+
+1 5
+1   0    0    1    2
diff --git a/final/lib/External/isl/test_inputs/convex13.polylib b/final/lib/External/isl/test_inputs/convex13.polylib
new file mode 100644
index 0000000..1b35912
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex13.polylib
@@ -0,0 +1,17 @@
+3 5
+1   0    0   -1    3
+1   0   -1    0    2
+1   1    1    1   -4
+
+3 5
+1   0    0    1    0
+1   1    0    0   -1
+1   1    2    0    1
+
+6 5
+1   3    2    0   -1
+1   3    0    2   -3
+1   1    0    1   -1
+1   1    1    1    0
+1   1    1    0    0
+1   1    0    0    1
diff --git a/final/lib/External/isl/test_inputs/convex14.polylib b/final/lib/External/isl/test_inputs/convex14.polylib
new file mode 100644
index 0000000..caaa8f5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex14.polylib
@@ -0,0 +1,14 @@
+3 4
+0 1 0 2
+1 0 1 0
+1 0 -1 2
+
+3 4
+1 1 0 0
+1 0 1 0
+1 0 -1 2
+
+3 4
+1 1 0 2
+1 0 1 0
+1 0 -1 2
diff --git a/final/lib/External/isl/test_inputs/convex15.polylib b/final/lib/External/isl/test_inputs/convex15.polylib
new file mode 100644
index 0000000..0118fa8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex15.polylib
@@ -0,0 +1,66 @@
+17 8
+1    -1    -8     0    16     0     0    37
+1     1     0   -48     0     2     0    -3
+1     0   -16   -32    16     1     0    14
+1    -1    24     0     0     1     0    18
+1    -1     8    16     0     0     1    21
+1     0     0   -16     0     1     1    -2
+1     1    32    16   -32     0     0    -1
+1    -1    16    16     0     0     0    28
+1     1    -8   -32     0     1     0    -1
+1     0     0     0     0     1     0    -1
+1     0    16    16   -16     0     1    -1
+1     1     8     0   -16     0     0     0
+1     0     3     2    -2     0     0     0
+1     0     1     2    -1     0     0     0
+1     0    -1    -1     1     0     0     0
+1    -1     8     0     0     1     2     4
+1    -1   -24   -32    32     1     0    36
+
+13 8
+1    -1     0     0     0     1     3    -4
+1     1     0   -48     0     2     0    -2
+1     0     0     0     0     1     0    -1
+1     0    -8     0     0     0     1    -1
+1     0     3     2    -2     0     0     0
+1     1   -16   -16     0     0     0     0
+1     1   -24     0     0     0     0     0
+1     0     1     0     0     0     0     0
+1     0    -3    -2     2     0     0     1
+1    -1     0    16     0     0     2    13
+1    -1    24     0     0     1     0    20
+1    -1    16    16     0     0     0    29
+1    -1     0    48     0     0     0    45
+
+31 8
+   1    0    1    0    0    0    0    0 
+   1    0    0  -16    0    1    1   -2 
+   1    0    0    0    0    1    0   -1 
+   1   -1    8    0    0    1    2    4 
+   1    0    3    2   -2    0    0    0 
+   1   -1   24    0    0    1    0   20 
+   1    1    0  -48    0    2    0   -2 
+   1   -1  -24  -32   32    1    0   36 
+   1    0    0    0    0    0    1   -1 
+   1   -1   24   64  -16    0    0   45 
+   1  -15  120  112    0   15   38   52 
+   1    1   24   32  -32    0    0    0 
+   1    0   -2   -2    2    0    0    1 
+   1   -1    8   16    0    0    1   21 
+   1  -15  120  352    0    0   23  307 
+   1    1   -8  -32    0    1    0   -1 
+   1    1   -8    0    0    0    0    0 
+   1    1   -8  -16    0    0    0    0 
+   1    0   16   16  -16    0    1   -1 
+   1   -1   16   16    0    0    0   29 
+   1   -1   -8    0   16    0    0   37 
+   1   -1    8   32    0    0    0   37 
+   1    1    8    0  -16    0    0    0 
+   1  -15  360  592 -240    0   23  307 
+   1   -1   -6    2   14    0    2   20 
+   1  -15  360  352 -240   15   38   52 
+   1   -1    8   48    0    0    0   45 
+   1    0  -16  -32   16    1    0   14 
+   1   -1   -6  -14   14    1    3    3 
+   1    1  -38  -78   30    2    0   13 
+   1    1   -3  -50    2    2    0   -1 
diff --git a/final/lib/External/isl/test_inputs/convex2.polylib b/final/lib/External/isl/test_inputs/convex2.polylib
new file mode 100644
index 0000000..0bfd737
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex2.polylib
@@ -0,0 +1,24 @@
+# {i,j,N | 1<=i<=N; 0<=j<=N-1; 2<=N}
+6 5
+1  1  0  0 -1
+1 -1  0  1  0
+1  0  1  0  0
+1  0 -1  1 -1 
+1  0  0  1 -2
+1  0  0  0  1
+# {i,j,N | 1<=i<=N; 1<=j<=N; 2<=N}
+6 5
+1  1  0  0 -1
+1 -1  0  1  0
+1  0  1  0 -1
+1  0 -1  1  0
+1  0  0  1 -2
+1  0  0  0  1
+# {i,j,N | 1<=i<=N; 0<=j<=N; 2<=N}
+6 5
+   1    0    0    1   -2
+   1   -1    0    1    0
+   1    0   -1    1    0
+   1    1    0    0   -1
+   1    0    1    0    0
+   1    0    0    0    1
diff --git a/final/lib/External/isl/test_inputs/convex3.polylib b/final/lib/External/isl/test_inputs/convex3.polylib
new file mode 100644
index 0000000..ea612c6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex3.polylib
@@ -0,0 +1,10 @@
+1 4
+1 1 1 -6
+
+3 4
+1 1 1 -3
+1 1 0 -5
+1 -1 0 10
+
+1 4
+1 1 1 -3
diff --git a/final/lib/External/isl/test_inputs/convex4.polylib b/final/lib/External/isl/test_inputs/convex4.polylib
new file mode 100644
index 0000000..0c08653
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex4.polylib
@@ -0,0 +1,9 @@
+1 4
+1 1 1 -6
+
+2 4
+0 1 0 -1
+0 0 1 -4
+
+1 4
+1 1 1 -5
diff --git a/final/lib/External/isl/test_inputs/convex5.polylib b/final/lib/External/isl/test_inputs/convex5.polylib
new file mode 100644
index 0000000..3aae7c2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex5.polylib
@@ -0,0 +1,12 @@
+2 4
+0 1 0 -2
+0 0 1 -6
+
+2 4
+0 1 0 -1
+0 0 1 -4
+
+3 4
+0 -2 1 -2
+1  1 0 -1
+1 -1 0  2
diff --git a/final/lib/External/isl/test_inputs/convex6.polylib b/final/lib/External/isl/test_inputs/convex6.polylib
new file mode 100644
index 0000000..1bdb4e1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex6.polylib
@@ -0,0 +1,17 @@
+3 4
+1   1    1   -2
+1  -1    1    2
+1   0   -1    2
+
+3 4
+1   0    1   -1
+1   1   -1    1
+1  -1   -1    5
+
+6 4
+1  -1    0    4
+1   1    0    0
+1   1    2   -2
+1  -1    2    2
+1   1   -2    4
+1  -1   -2    8
diff --git a/final/lib/External/isl/test_inputs/convex7.polylib b/final/lib/External/isl/test_inputs/convex7.polylib
new file mode 100644
index 0000000..70eb483
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex7.polylib
@@ -0,0 +1,9 @@
+1 4
+0 0 1 0
+
+2 4
+1 1 -1 1
+1 -1 -1 1
+
+1 4
+1 0 -1 1
diff --git a/final/lib/External/isl/test_inputs/convex8.polylib b/final/lib/External/isl/test_inputs/convex8.polylib
new file mode 100644
index 0000000..ea1b757
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex8.polylib
@@ -0,0 +1,24 @@
+4 5
+1   1    1    1    0
+1   0   -1    0    0
+1  -1    0    0    2
+1   1    1   -1    0
+
+4 5
+1  -1    1    0    2
+1   1   -2   -2   -1
+1  -1    0    2    3
+1   1    0    0   -1
+
+10 5
+1   1    0    1    0
+1   1    1    0    0
+1   0    1    1    2
+1  -3    1   -1    8
+1  -3    1    1    8
+1   0    1   -1    2
+1   1    0   -1    0
+1   1   -2   -1    0
+1  -1   -3    2    6
+1   1   -5   -2    2
+
diff --git a/final/lib/External/isl/test_inputs/convex9.polylib b/final/lib/External/isl/test_inputs/convex9.polylib
new file mode 100644
index 0000000..f68fca0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/convex9.polylib
@@ -0,0 +1,14 @@
+4 4
+1 1 0 0
+1 -1 0 1
+1 0 1 0
+1 0 -1 10
+
+2 4
+1 1 0 -10
+0 0 -1 5
+
+3 4
+1 1 0 0
+1 0 1 0
+1 0 -1 10
diff --git a/final/lib/External/isl/test_inputs/devos.pwqp b/final/lib/External/isl/test_inputs/devos.pwqp
new file mode 100644
index 0000000..b452544
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/devos.pwqp
@@ -0,0 +1 @@
+[U] -> { [i0] -> ((1/3 * U + 2/3 * i0) - [(U + 2i0)/3]) : 2i0 >= -3 - U and 2i0 <= -U and U >= 0 and U <= 10 }
diff --git a/final/lib/External/isl/test_inputs/equality1.pwqp b/final/lib/External/isl/test_inputs/equality1.pwqp
new file mode 100644
index 0000000..eb16a4b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/equality1.pwqp
@@ -0,0 +1 @@
+[n] -> { [x] -> 1 + [(x+1)/3] : exists a : x = 3a +1 && 0 <= x <= n }
diff --git a/final/lib/External/isl/test_inputs/equality2.pwqp b/final/lib/External/isl/test_inputs/equality2.pwqp
new file mode 100644
index 0000000..1629a65
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/equality2.pwqp
@@ -0,0 +1 @@
+[n] -> { [x,y] -> x^2 * y : n = 2x + 4y and 0 <= x,y <= 10 }
diff --git a/final/lib/External/isl/test_inputs/equality3.pwqp b/final/lib/External/isl/test_inputs/equality3.pwqp
new file mode 100644
index 0000000..c6f8c3a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/equality3.pwqp
@@ -0,0 +1 @@
+[m,n] -> { [x,y] -> x^2 * y : n = 2x + 4y and 0 <= x,y <= 10 and 3 n = 5 m }
diff --git a/final/lib/External/isl/test_inputs/equality4.pwqp b/final/lib/External/isl/test_inputs/equality4.pwqp
new file mode 100644
index 0000000..49da2e7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/equality4.pwqp
@@ -0,0 +1 @@
+[m,n] -> { [x,y] -> x^2 * y + m + 13 * n: n = 2x + 4y and 0 <= x,y <= 10 and 3 n = 5 m }
diff --git a/final/lib/External/isl/test_inputs/equality5.pwqp b/final/lib/External/isl/test_inputs/equality5.pwqp
new file mode 100644
index 0000000..09cb752
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/equality5.pwqp
@@ -0,0 +1 @@
+[m,n] -> { [x,y,z] -> x^2 * y + z + m + 13 * n: n = 2x + 4y and 0 <= x,y <= 10 and 3 n = 5 m and z = x + y }
diff --git a/final/lib/External/isl/test_inputs/esced.pip b/final/lib/External/isl/test_inputs/esced.pip
new file mode 100644
index 0000000..dbf56ff
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/esced.pip
@@ -0,0 +1,27 @@
+0 2
+
+-1
+
+16 18
+1 0 0 0 0 0 0 0 0 -1 0 0 1 0 0 0 0 0
+1 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 0 0 0
+1 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 0 0
+1 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 0
+1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
+1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
+
+
+0 0 0 0 -1 0 0 0 0 1 -1 0 0 0 0 0 0 0
+0 0 0 0 0 -1 0 0 0 0 0 1 0 0 0 0 0 0
+
+0 -1 0 0 0 0 0 0 0 0 1 -1 0 0 0 0 0 0
+
+0 0 0 0 0 0 -1 0 0 0 0 0 1 -1 0 -1 0 0
+0 0 0 0 0 0 0 -1 0 0 0 0 0 0 1 0 0 0
+0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 1 0
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 0
+0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0
+
+1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1
+1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 -1
diff --git a/final/lib/External/isl/test_inputs/ex.pip b/final/lib/External/isl/test_inputs/ex.pip
new file mode 100644
index 0000000..a405450
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/ex.pip
@@ -0,0 +1,9 @@
+1 5
+1 -1  1  1  0 
+
+-1
+
+3 7
+1  0 -1  0  1  0  0 
+1 -1  0  0  0  1  0 
+1  1  1 -1  0  0  0 
diff --git a/final/lib/External/isl/test_inputs/ex2.pip b/final/lib/External/isl/test_inputs/ex2.pip
new file mode 100644
index 0000000..bb59848
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/ex2.pip
@@ -0,0 +1,9 @@
+1 5
+1 -1 1 1 0
+
+-1
+
+3 7
+1 0 -1 0 1 0 0
+1 -1 0 0 0 1 0
+1 1 1 -1 0 0 0
diff --git a/final/lib/External/isl/test_inputs/exist.pip b/final/lib/External/isl/test_inputs/exist.pip
new file mode 100644
index 0000000..3e026e5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/exist.pip
@@ -0,0 +1,5 @@
+[n] -> { : n mod 2 = 0 }
+
+-1
+
+[n] -> { [i] : n <= i }
diff --git a/final/lib/External/isl/test_inputs/exist2.pip b/final/lib/External/isl/test_inputs/exist2.pip
new file mode 100644
index 0000000..441190a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/exist2.pip
@@ -0,0 +1,5 @@
+[n, a, b] -> { : exists e : 1 <= a <= 7e and 9e <= b <= n }
+
+-1
+
+[n, a, b] -> { [i] : n <= 2i }
diff --git a/final/lib/External/isl/test_inputs/faddeev.pwqp b/final/lib/External/isl/test_inputs/faddeev.pwqp
new file mode 100644
index 0000000..e7db61d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/faddeev.pwqp
@@ -0,0 +1 @@
+[N] -> { [i, j, k] -> (((4 + 6 * N + 2 * N^2) + (-2 - 2 * N) * j) + ((-2 - N) + j) * k) : j = 1 + i and k = 1 + i and i >= 3 and N <= 100 and i <= N and N >= 10 }
diff --git a/final/lib/External/isl/test_inputs/fimmel.pip b/final/lib/External/isl/test_inputs/fimmel.pip
new file mode 100644
index 0000000..a6dee41
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/fimmel.pip
@@ -0,0 +1,12 @@
+0 4
+
+-1
+
+7 6
+1 2  6 0 0 -9
+1 5 -3 0 0 0
+1 2 -10 0 0 15
+1 -2 6 0 0 -3
+1 -2 -6 0 0 17
+1 0 1 -1 0 0
+1 1 0 0 -1 0
diff --git a/final/lib/External/isl/test_inputs/flow/kill_loop-tree.ai b/final/lib/External/isl/test_inputs/flow/kill_loop-tree.ai
new file mode 100644
index 0000000..835e1c0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_loop-tree.ai
@@ -0,0 +1,11 @@
+sink: "{ S[] -> a[] }"
+must_source: "{ T[i] -> a[] : 0 <= i <= 9 }"
+kill: "{ T[9] -> a[] }"
+schedule:
+  domain: "{ T[i]; S[] }"
+  child:
+    sequence:
+    - filter: "{ T[i] }"
+      child:
+        schedule: "[{ T[i] -> [(i)] }]"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_loop-tree.flow b/final/lib/External/isl/test_inputs/flow/kill_loop-tree.flow
new file mode 100644
index 0000000..ef089e5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_loop-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{ T[i = 9] -> [S[] -> a[]] }"
+may_dependence: "{ T[i = 9] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_loop.ai b/final/lib/External/isl/test_inputs/flow/kill_loop.ai
new file mode 100644
index 0000000..619028f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_loop.ai
@@ -0,0 +1,4 @@
+sink: { S[] -> a[] }
+must_source: { T[i] -> a[] : 0 <= i < 10 }
+kill: { T[9] -> a[] }
+schedule_map: { T[i] -> [0,i]; S[] -> [1,0] }
diff --git a/final/lib/External/isl/test_inputs/flow/kill_loop.flow b/final/lib/External/isl/test_inputs/flow/kill_loop.flow
new file mode 100644
index 0000000..ef089e5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_loop.flow
@@ -0,0 +1,4 @@
+must_dependence: "{ T[i = 9] -> [S[] -> a[]] }"
+may_dependence: "{ T[i = 9] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_loop2-tree.ai b/final/lib/External/isl/test_inputs/flow/kill_loop2-tree.ai
new file mode 100644
index 0000000..19d5ff6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_loop2-tree.ai
@@ -0,0 +1,11 @@
+sink: "{ S[] -> a[] }"
+must_source: "{ T[i] -> a[] : 0 <= i <= 9 }"
+kill: "{ K[] -> a[] }"
+schedule:
+  domain: "{ T[i]; S[]; K[] }"
+  child:
+    sequence:
+    - filter: "{ T[i]; K[] }"
+      child:
+        schedule: "[{ T[i] -> [(i)]; K[] -> [(10)] }]"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_loop2-tree.flow b/final/lib/External/isl/test_inputs/flow/kill_loop2-tree.flow
new file mode 100644
index 0000000..ec75edb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_loop2-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{  }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_loop2.ai b/final/lib/External/isl/test_inputs/flow/kill_loop2.ai
new file mode 100644
index 0000000..622bc21
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_loop2.ai
@@ -0,0 +1,4 @@
+sink: { S[] -> a[] }
+must_source: { T[i] -> a[] : 0 <= i < 10 }
+kill: { K[] -> a[] }
+schedule_map: { T[i] -> [0,i]; K[] -> [0,10]; S[] -> [1,0] }
diff --git a/final/lib/External/isl/test_inputs/flow/kill_loop2.flow b/final/lib/External/isl/test_inputs/flow/kill_loop2.flow
new file mode 100644
index 0000000..ec75edb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_loop2.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{  }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_loop3-tree.ai b/final/lib/External/isl/test_inputs/flow/kill_loop3-tree.ai
new file mode 100644
index 0000000..b14325b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_loop3-tree.ai
@@ -0,0 +1,11 @@
+sink: "{ S[] -> a[] }"
+must_source: "{ T[i] -> a[] : 0 <= i <= 9 }"
+kill: "{ K[] -> a[] }"
+schedule:
+  domain: "{ T[i]; S[]; K[] }"
+  child:
+    sequence:
+    - filter: "{ T[i]; K[] }"
+      child:
+        schedule: "[{ T[i] -> [(i)]; K[] -> [(9)] }]"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_loop3-tree.flow b/final/lib/External/isl/test_inputs/flow/kill_loop3-tree.flow
new file mode 100644
index 0000000..51d2e2a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_loop3-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[i = 9] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_loop3.ai b/final/lib/External/isl/test_inputs/flow/kill_loop3.ai
new file mode 100644
index 0000000..436e13c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_loop3.ai
@@ -0,0 +1,4 @@
+sink: { S[] -> a[] }
+must_source: { T[i] -> a[] : 0 <= i < 10 }
+kill: { K[] -> a[] }
+schedule_map: { T[i] -> [0,i]; K[] -> [0,9]; S[] -> [1,0] }
diff --git a/final/lib/External/isl/test_inputs/flow/kill_loop3.flow b/final/lib/External/isl/test_inputs/flow/kill_loop3.flow
new file mode 100644
index 0000000..51d2e2a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_loop3.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[i = 9] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_may_loop-tree.ai b/final/lib/External/isl/test_inputs/flow/kill_may_loop-tree.ai
new file mode 100644
index 0000000..9159e47
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_may_loop-tree.ai
@@ -0,0 +1,11 @@
+sink: "{ S[] -> a[] }"
+may_source: "{ T[i] -> a[] : 0 <= i <= 9 }"
+kill: "{ T[4] -> a[] }"
+schedule:
+  domain: "{ T[i]; S[] }"
+  child:
+    sequence:
+    - filter: "{ T[i] }"
+      child:
+        schedule: "[{ T[i] -> [(i)] }]"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_may_loop-tree.flow b/final/lib/External/isl/test_inputs/flow/kill_may_loop-tree.flow
new file mode 100644
index 0000000..7a89b0d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_may_loop-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[i] -> [S[] -> a[]] : 4 <= i <= 9 }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_may_loop.ai b/final/lib/External/isl/test_inputs/flow/kill_may_loop.ai
new file mode 100644
index 0000000..5d197f6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_may_loop.ai
@@ -0,0 +1,4 @@
+sink: { S[] -> a[] }
+may_source: { T[i] -> a[] : 0 <= i < 10 }
+kill: { T[4] -> a[] }
+schedule_map: { T[i] -> [0,i]; S[] -> [1,0] }
diff --git a/final/lib/External/isl/test_inputs/flow/kill_may_loop.flow b/final/lib/External/isl/test_inputs/flow/kill_may_loop.flow
new file mode 100644
index 0000000..7a89b0d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_may_loop.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[i] -> [S[] -> a[]] : 4 <= i <= 9 }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_may_loop2-tree.ai b/final/lib/External/isl/test_inputs/flow/kill_may_loop2-tree.ai
new file mode 100644
index 0000000..fb5d88f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_may_loop2-tree.ai
@@ -0,0 +1,11 @@
+sink: "{ S[] -> a[] }"
+may_source: "{ T[i] -> a[] : 0 <= i <= 9 }"
+kill: "{ T[9] -> a[] }"
+schedule:
+  domain: "{ T[i]; S[] }"
+  child:
+    sequence:
+    - filter: "{ T[i] }"
+      child:
+        schedule: "[{ T[i] -> [(i)] }]"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_may_loop2-tree.flow b/final/lib/External/isl/test_inputs/flow/kill_may_loop2-tree.flow
new file mode 100644
index 0000000..51d2e2a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_may_loop2-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[i = 9] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_may_loop2.ai b/final/lib/External/isl/test_inputs/flow/kill_may_loop2.ai
new file mode 100644
index 0000000..09aaf70
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_may_loop2.ai
@@ -0,0 +1,4 @@
+sink: { S[] -> a[] }
+may_source: { T[i] -> a[] : 0 <= i < 10 }
+kill: { T[9] -> a[] }
+schedule_map: { T[i] -> [0,i]; S[] -> [1,0] }
diff --git a/final/lib/External/isl/test_inputs/flow/kill_may_loop2.flow b/final/lib/External/isl/test_inputs/flow/kill_may_loop2.flow
new file mode 100644
index 0000000..51d2e2a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_may_loop2.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[i = 9] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_may_loop3-tree.ai b/final/lib/External/isl/test_inputs/flow/kill_may_loop3-tree.ai
new file mode 100644
index 0000000..8097695
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_may_loop3-tree.ai
@@ -0,0 +1,11 @@
+sink: "{ S[] -> a[] }"
+may_source: "{ T[i] -> a[] : 0 <= i <= 9 }"
+kill: "{ K[] -> a[] }"
+schedule:
+  domain: "{ T[i]; S[]; K[] }"
+  child:
+    sequence:
+    - filter: "{ T[i]; K[] }"
+      child:
+        schedule: "[{ T[i] -> [(i)]; K[] -> [(4)] }]"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_may_loop3-tree.flow b/final/lib/External/isl/test_inputs/flow/kill_may_loop3-tree.flow
new file mode 100644
index 0000000..7a89b0d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_may_loop3-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[i] -> [S[] -> a[]] : 4 <= i <= 9 }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/kill_may_loop3.ai b/final/lib/External/isl/test_inputs/flow/kill_may_loop3.ai
new file mode 100644
index 0000000..b1d2d6c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_may_loop3.ai
@@ -0,0 +1,4 @@
+sink: { S[] -> a[] }
+may_source: { T[i] -> a[] : 0 <= i < 10 }
+kill: { K[] -> a[] }
+schedule_map: { T[i] -> [0,i]; K[] -> [0,4]; S[] -> [1,0] }
diff --git a/final/lib/External/isl/test_inputs/flow/kill_may_loop3.flow b/final/lib/External/isl/test_inputs/flow/kill_may_loop3.flow
new file mode 100644
index 0000000..7a89b0d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/kill_may_loop3.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[i] -> [S[] -> a[]] : 4 <= i <= 9 }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/loop-tree.ai b/final/lib/External/isl/test_inputs/flow/loop-tree.ai
new file mode 100644
index 0000000..e7fa351
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/loop-tree.ai
@@ -0,0 +1,10 @@
+sink: "{ S[] -> a[] }"
+must_source: "{ T[i] -> a[] : 0 <= i <= 9 }"
+schedule:
+  domain: "{ T[i]; S[] }"
+  child:
+    sequence:
+    - filter: "{ T[i] }"
+      child:
+        schedule: "[{ T[i] -> [(i)] }]"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/loop-tree.flow b/final/lib/External/isl/test_inputs/flow/loop-tree.flow
new file mode 100644
index 0000000..ef089e5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/loop-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{ T[i = 9] -> [S[] -> a[]] }"
+may_dependence: "{ T[i = 9] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/loop.ai b/final/lib/External/isl/test_inputs/flow/loop.ai
new file mode 100644
index 0000000..88c6efa
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/loop.ai
@@ -0,0 +1,3 @@
+sink: { S[] -> a[] }
+must_source: { T[i] -> a[] : 0 <= i < 10 }
+schedule_map: { T[i] -> [0,i]; S[] -> [1,0] }
diff --git a/final/lib/External/isl/test_inputs/flow/loop.flow b/final/lib/External/isl/test_inputs/flow/loop.flow
new file mode 100644
index 0000000..ef089e5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/loop.flow
@@ -0,0 +1,4 @@
+must_dependence: "{ T[i = 9] -> [S[] -> a[]] }"
+may_dependence: "{ T[i = 9] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/may_loop-tree.ai b/final/lib/External/isl/test_inputs/flow/may_loop-tree.ai
new file mode 100644
index 0000000..de44645
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/may_loop-tree.ai
@@ -0,0 +1,10 @@
+sink: "{ S[] -> a[] }"
+may_source: "{ T[i] -> a[] : 0 <= i <= 9 }"
+schedule:
+  domain: "{ T[i]; S[] }"
+  child:
+    sequence:
+    - filter: "{ T[i] }"
+      child:
+        schedule: "[{ T[i] -> [(i)] }]"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/may_loop-tree.flow b/final/lib/External/isl/test_inputs/flow/may_loop-tree.flow
new file mode 100644
index 0000000..f944ee2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/may_loop-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[i] -> [S[] -> a[]] : 0 <= i <= 9 }"
+must_no_source: "{  }"
+may_no_source: "{ S[] -> a[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/may_loop.ai b/final/lib/External/isl/test_inputs/flow/may_loop.ai
new file mode 100644
index 0000000..0a52ce5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/may_loop.ai
@@ -0,0 +1,3 @@
+sink: { S[] -> a[] }
+may_source: { T[i] -> a[] : 0 <= i < 10 }
+schedule_map: { T[i] -> [0,i]; S[] -> [1,0] }
diff --git a/final/lib/External/isl/test_inputs/flow/may_loop.flow b/final/lib/External/isl/test_inputs/flow/may_loop.flow
new file mode 100644
index 0000000..f944ee2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/may_loop.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[i] -> [S[] -> a[]] : 0 <= i <= 9 }"
+must_no_source: "{  }"
+may_no_source: "{ S[] -> a[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/mixed_loop-tree.ai b/final/lib/External/isl/test_inputs/flow/mixed_loop-tree.ai
new file mode 100644
index 0000000..960bafb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/mixed_loop-tree.ai
@@ -0,0 +1,11 @@
+sink: "{ S[] -> a[] }"
+must_source: "{ T[i] -> a[] : 2*floor((i)/2) = i and 0 <= i <= 9 }"
+may_source: "{ T[i] -> a[] : 2*floor((1 + i)/2) = 1 + i and 0 <= i <= 9 }"
+schedule:
+  domain: "{ T[i]; S[] }"
+  child:
+    sequence:
+    - filter: "{ T[i] }"
+      child:
+        schedule: "[{ T[i] -> [(i)] }]"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/mixed_loop-tree.flow b/final/lib/External/isl/test_inputs/flow/mixed_loop-tree.flow
new file mode 100644
index 0000000..76033be
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/mixed_loop-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[i = 9] -> [S[] -> a[]]; T[i = 8] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/mixed_loop.ai b/final/lib/External/isl/test_inputs/flow/mixed_loop.ai
new file mode 100644
index 0000000..c797820
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/mixed_loop.ai
@@ -0,0 +1,4 @@
+sink: { S[] -> a[] }
+must_source: { T[i] -> a[] : 0 <= i < 10 and i mod 2 = 0 }
+may_source: { T[i] -> a[] : 0 <= i < 10 and i mod 2 = 1 }
+schedule_map: { T[i] -> [0,i]; S[] -> [1,0] }
diff --git a/final/lib/External/isl/test_inputs/flow/mixed_loop.flow b/final/lib/External/isl/test_inputs/flow/mixed_loop.flow
new file mode 100644
index 0000000..76033be
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/mixed_loop.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[i = 9] -> [S[] -> a[]]; T[i = 8] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi.ai b/final/lib/External/isl/test_inputs/flow/multi.ai
new file mode 100644
index 0000000..c76ed66
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi.ai
@@ -0,0 +1,10 @@
+sink: "{ [S_2[] -> __pet_ref_4[]] -> a[] }"
+must_source: "{ [S_0[] -> __pet_ref_0[]] -> a[]; [S_2[] -> __pet_ref_3[]] -> b[]; [S_1[] -> __pet_ref_1[]] -> a[]; [S_1[] -> __pet_ref_2[]] -> a[] }"
+may_source: "{ [S_1[] -> __pet_ref_2[]] -> a[]; [S_1[] -> __pet_ref_1[]] -> a[]; [S_2[] -> __pet_ref_3[]] -> b[]; [S_0[] -> __pet_ref_0[]] -> a[] }"
+schedule:
+  domain: "{ [S_1[] -> __pet_ref_1[]]; [S_1[] -> __pet_ref_2[]]; [S_2[] -> __pet_ref_3[]]; [S_0[] -> __pet_ref_0[]]; [S_2[] -> __pet_ref_4[]] }"
+  child:
+    sequence:
+    - filter: "{ [S_0[] -> __pet_ref_0[]] }"
+    - filter: "{ [S_1[] -> __pet_ref_1[]]; [S_1[] -> __pet_ref_2[]] }"
+    - filter: "{ [S_2[] -> __pet_ref_3[]]; [S_2[] -> __pet_ref_4[]] }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi.flow b/final/lib/External/isl/test_inputs/flow/multi.flow
new file mode 100644
index 0000000..da6b0a1
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ [S_1[] -> __pet_ref_2[]] -> [[S_2[] -> __pet_ref_4[]] -> a[]]; [S_1[] -> __pet_ref_1[]] -> [[S_2[] -> __pet_ref_4[]] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source-tree.ai b/final/lib/External/isl/test_inputs/flow/multi_source-tree.ai
new file mode 100644
index 0000000..cf5826e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source-tree.ai
@@ -0,0 +1,8 @@
+sink: "{ S[] -> a[] }"
+must_source: "{ T[] -> a[]; U[] -> a[] }"
+schedule:
+  domain: "{ U[]; S[]; T[] }"
+  child:
+    sequence:
+    - filter: "{ T[]; U[] }"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source-tree.flow b/final/lib/External/isl/test_inputs/flow/multi_source-tree.flow
new file mode 100644
index 0000000..e8f953a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[] -> [S[] -> a[]]; U[] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source.ai b/final/lib/External/isl/test_inputs/flow/multi_source.ai
new file mode 100644
index 0000000..1ce3689
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source.ai
@@ -0,0 +1,3 @@
+sink: { S[] -> a[] }
+must_source: { T[] -> a[]; U[] -> a[] }
+schedule_map: { T[] -> [0]; U[] -> [0]; S[] -> [1] }
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source.flow b/final/lib/External/isl/test_inputs/flow/multi_source.flow
new file mode 100644
index 0000000..e8f953a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[] -> [S[] -> a[]]; U[] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source2-tree.ai b/final/lib/External/isl/test_inputs/flow/multi_source2-tree.ai
new file mode 100644
index 0000000..d88d96b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source2-tree.ai
@@ -0,0 +1,9 @@
+sink: "{ S[] -> a[] }"
+must_source: "{ T[] -> a[] }"
+may_source: "{ U[] -> a[] }"
+schedule:
+  domain: "{ U[]; S[]; T[] }"
+  child:
+    sequence:
+    - filter: "{ T[]; U[] }"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source2-tree.flow b/final/lib/External/isl/test_inputs/flow/multi_source2-tree.flow
new file mode 100644
index 0000000..e8f953a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source2-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[] -> [S[] -> a[]]; U[] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source2.ai b/final/lib/External/isl/test_inputs/flow/multi_source2.ai
new file mode 100644
index 0000000..ba9f46e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source2.ai
@@ -0,0 +1,4 @@
+sink: { S[] -> a[] }
+must_source: { T[] -> a[] }
+may_source: { U[] -> a[] }
+schedule_map: { T[] -> [0]; U[] -> [0]; S[] -> [1] }
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source2.flow b/final/lib/External/isl/test_inputs/flow/multi_source2.flow
new file mode 100644
index 0000000..e8f953a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source2.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[] -> [S[] -> a[]]; U[] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source3-tree.ai b/final/lib/External/isl/test_inputs/flow/multi_source3-tree.ai
new file mode 100644
index 0000000..7cd2465
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source3-tree.ai
@@ -0,0 +1,13 @@
+sink: "{ S[] -> a[] }"
+must_source: "{ T[] -> a[]; U[] -> a[] }"
+may_source: "{ V[] -> a[] }"
+schedule:
+  domain: "{ S[]; U[]; T[]; V[] }"
+  child:
+    sequence:
+    - filter: "{ U[]; T[]; V[] }"
+      child:
+        sequence:
+        - filter: "{ T[]; U[] }"
+        - filter: "{ V[] }"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source3-tree.flow b/final/lib/External/isl/test_inputs/flow/multi_source3-tree.flow
new file mode 100644
index 0000000..b037575
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source3-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[] -> [S[] -> a[]]; U[] -> [S[] -> a[]]; V[] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source3.ai b/final/lib/External/isl/test_inputs/flow/multi_source3.ai
new file mode 100644
index 0000000..e2e3d47
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source3.ai
@@ -0,0 +1,4 @@
+sink: { S[] -> a[] }
+must_source: { T[] -> a[]; U[] -> a[] }
+may_source: { V[] -> a[] }
+schedule_map: { T[] -> [0,0]; U[] -> [0,0]; V[] -> [0,1]; S[] -> [1,0] }
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source3.flow b/final/lib/External/isl/test_inputs/flow/multi_source3.flow
new file mode 100644
index 0000000..b037575
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source3.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[] -> [S[] -> a[]]; U[] -> [S[] -> a[]]; V[] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source4-tree.ai b/final/lib/External/isl/test_inputs/flow/multi_source4-tree.ai
new file mode 100644
index 0000000..431ac76
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source4-tree.ai
@@ -0,0 +1,13 @@
+sink: "{ S[] -> a[] }"
+must_source: "{ T[] -> a[]; U[] -> a[] }"
+may_source: "{ V[] -> a[] }"
+schedule:
+  domain: "{ S[]; U[]; T[]; V[] }"
+  child:
+    sequence:
+    - filter: "{ U[]; T[]; V[] }"
+      child:
+        sequence:
+        - filter: "{ U[] }"
+        - filter: "{ V[]; T[] }"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source4-tree.flow b/final/lib/External/isl/test_inputs/flow/multi_source4-tree.flow
new file mode 100644
index 0000000..8bf4111
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source4-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[] -> [S[] -> a[]]; V[] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source4.ai b/final/lib/External/isl/test_inputs/flow/multi_source4.ai
new file mode 100644
index 0000000..8ce0ebe
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source4.ai
@@ -0,0 +1,4 @@
+sink: { S[] -> a[] }
+must_source: { T[] -> a[]; U[] -> a[] }
+may_source: { V[] -> a[] }
+schedule_map: { T[] -> [0,1]; U[] -> [0,0]; V[] -> [0,1]; S[] -> [1,0] }
diff --git a/final/lib/External/isl/test_inputs/flow/multi_source4.flow b/final/lib/External/isl/test_inputs/flow/multi_source4.flow
new file mode 100644
index 0000000..8bf4111
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/multi_source4.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[] -> [S[] -> a[]]; V[] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/no_source-tree.ai b/final/lib/External/isl/test_inputs/flow/no_source-tree.ai
new file mode 100644
index 0000000..e3eea6d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/no_source-tree.ai
@@ -0,0 +1,3 @@
+sink: "{ S[] -> a[] }"
+schedule:
+  domain: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/no_source-tree.flow b/final/lib/External/isl/test_inputs/flow/no_source-tree.flow
new file mode 100644
index 0000000..2ed34cd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/no_source-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{  }"
+must_no_source: "{ S[] -> a[] }"
+may_no_source: "{ S[] -> a[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/no_source.ai b/final/lib/External/isl/test_inputs/flow/no_source.ai
new file mode 100644
index 0000000..52b07d6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/no_source.ai
@@ -0,0 +1,2 @@
+sink: { S[] -> a[] }
+schedule_map: { S[] -> [] }
diff --git a/final/lib/External/isl/test_inputs/flow/no_source.flow b/final/lib/External/isl/test_inputs/flow/no_source.flow
new file mode 100644
index 0000000..2ed34cd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/no_source.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{  }"
+must_no_source: "{ S[] -> a[] }"
+may_no_source: "{ S[] -> a[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/no_source2-tree.ai b/final/lib/External/isl/test_inputs/flow/no_source2-tree.ai
new file mode 100644
index 0000000..1ef6e52
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/no_source2-tree.ai
@@ -0,0 +1,8 @@
+sink: "{ S[] -> a[] }"
+must_source: "{ T[] -> a[] }"
+schedule:
+  domain: "{ S[]; T[] }"
+  child:
+    sequence:
+    - filter: "{ S[] }"
+    - filter: "{ T[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/no_source2-tree.flow b/final/lib/External/isl/test_inputs/flow/no_source2-tree.flow
new file mode 100644
index 0000000..2ed34cd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/no_source2-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{  }"
+must_no_source: "{ S[] -> a[] }"
+may_no_source: "{ S[] -> a[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/no_source2.ai b/final/lib/External/isl/test_inputs/flow/no_source2.ai
new file mode 100644
index 0000000..b13e798
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/no_source2.ai
@@ -0,0 +1,3 @@
+sink: { S[] -> a[] }
+must_source: { T[] -> a[] }
+schedule_map: { T[] -> [1]; S[] -> [0] }
diff --git a/final/lib/External/isl/test_inputs/flow/no_source2.flow b/final/lib/External/isl/test_inputs/flow/no_source2.flow
new file mode 100644
index 0000000..2ed34cd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/no_source2.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{  }"
+must_no_source: "{ S[] -> a[] }"
+may_no_source: "{ S[] -> a[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/single_may_source-tree.ai b/final/lib/External/isl/test_inputs/flow/single_may_source-tree.ai
new file mode 100644
index 0000000..f05980a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/single_may_source-tree.ai
@@ -0,0 +1,8 @@
+sink: "{ S[] -> a[] }"
+may_source: "{ T[] -> a[] }"
+schedule:
+  domain: "{ S[]; T[] }"
+  child:
+    sequence:
+    - filter: "{ T[] }"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/single_may_source-tree.flow b/final/lib/External/isl/test_inputs/flow/single_may_source-tree.flow
new file mode 100644
index 0000000..3034b85
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/single_may_source-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{ S[] -> a[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/single_may_source.ai b/final/lib/External/isl/test_inputs/flow/single_may_source.ai
new file mode 100644
index 0000000..58d0a7f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/single_may_source.ai
@@ -0,0 +1,3 @@
+sink: { S[] -> a[] }
+may_source: { T[] -> a[] }
+schedule_map: { T[] -> [0]; S[] -> [1] }
diff --git a/final/lib/External/isl/test_inputs/flow/single_may_source.flow b/final/lib/External/isl/test_inputs/flow/single_may_source.flow
new file mode 100644
index 0000000..3034b85
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/single_may_source.flow
@@ -0,0 +1,4 @@
+must_dependence: "{  }"
+may_dependence: "{ T[] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{ S[] -> a[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/single_source-tree.ai b/final/lib/External/isl/test_inputs/flow/single_source-tree.ai
new file mode 100644
index 0000000..3af5f2f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/single_source-tree.ai
@@ -0,0 +1,8 @@
+sink: "{ S[] -> a[] }"
+must_source: "{ T[] -> a[] }"
+schedule:
+  domain: "{ S[]; T[] }"
+  child:
+    sequence:
+    - filter: "{ T[] }"
+    - filter: "{ S[] }"
diff --git a/final/lib/External/isl/test_inputs/flow/single_source-tree.flow b/final/lib/External/isl/test_inputs/flow/single_source-tree.flow
new file mode 100644
index 0000000..e72b8d7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/single_source-tree.flow
@@ -0,0 +1,4 @@
+must_dependence: "{ T[] -> [S[] -> a[]] }"
+may_dependence: "{ T[] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/flow/single_source.ai b/final/lib/External/isl/test_inputs/flow/single_source.ai
new file mode 100644
index 0000000..0a00e5b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/single_source.ai
@@ -0,0 +1,3 @@
+sink: { S[] -> a[] }
+must_source: { T[] -> a[] }
+schedule_map: { T[] -> [0]; S[] -> [1] }
diff --git a/final/lib/External/isl/test_inputs/flow/single_source.flow b/final/lib/External/isl/test_inputs/flow/single_source.flow
new file mode 100644
index 0000000..e72b8d7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/flow/single_source.flow
@@ -0,0 +1,4 @@
+must_dependence: "{ T[] -> [S[] -> a[]] }"
+may_dependence: "{ T[] -> [S[] -> a[]] }"
+must_no_source: "{  }"
+may_no_source: "{  }"
diff --git a/final/lib/External/isl/test_inputs/gist1.polylib b/final/lib/External/isl/test_inputs/gist1.polylib
new file mode 100644
index 0000000..802a4eb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/gist1.polylib
@@ -0,0 +1,14 @@
+4 5
+0 1 0 0 -1
+0 0 1 0 1
+0 0 0 1 -3
+1 0 0 0 1
+
+4 5
+0 1 0 0 -1
+0 0 1 1 -2
+1 0 0 1 0
+1 0 0 -1 3
+
+1 5
+0 0 1 0 1
diff --git a/final/lib/External/isl/test_inputs/linearExample.pwqp b/final/lib/External/isl/test_inputs/linearExample.pwqp
new file mode 100644
index 0000000..24c5394
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/linearExample.pwqp
@@ -0,0 +1 @@
+[N, M, L] -> { [i, j, k] -> ((1/2 * i + 5 * j) + 1/7 * k) : i >= 0 and k >= -N + i and k >= -M - j and j <= L + i and L >= 0 and L >= -M }
diff --git a/final/lib/External/isl/test_inputs/max.pip b/final/lib/External/isl/test_inputs/max.pip
new file mode 100644
index 0000000..e8af57b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/max.pip
@@ -0,0 +1,9 @@
+0 3
+
+-1
+
+4 5
+1 -1  0  1  0
+1  0 -1  1  0
+1 -1  3 -2 12
+1  2 -1 -1  3
diff --git a/final/lib/External/isl/test_inputs/neg.pwqp b/final/lib/External/isl/test_inputs/neg.pwqp
new file mode 100644
index 0000000..596a7d7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/neg.pwqp
@@ -0,0 +1 @@
+[n] -> { [i0] -> i0^2 : i0 >= -20 - n and i0 <= n and i0 <= -1 and n >= 0 }
diff --git a/final/lib/External/isl/test_inputs/negative.pip b/final/lib/External/isl/test_inputs/negative.pip
new file mode 100644
index 0000000..45090a5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/negative.pip
@@ -0,0 +1,9 @@
+1 3
+#  n  1
+1  1 -1 # n >= 1
+-1
+
+2 4
+#  i  n  1
+1  1  0  1 # i >= -1
+1 -1  1  0 # i <= n
diff --git a/final/lib/External/isl/test_inputs/philippe.pwqp b/final/lib/External/isl/test_inputs/philippe.pwqp
new file mode 100644
index 0000000..1c56e7a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/philippe.pwqp
@@ -0,0 +1 @@
+[N] -> { [i, j] -> ((1/2 * i + 1/2 * i^2) + j) : i <= N and j >= 0 and j <= i }
diff --git a/final/lib/External/isl/test_inputs/philippe3vars.pwqp b/final/lib/External/isl/test_inputs/philippe3vars.pwqp
new file mode 100644
index 0000000..8d07496
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/philippe3vars.pwqp
@@ -0,0 +1 @@
+[N] -> { [i, j, k] -> (((1/2 * i + 1/2 * i^2) + j) + k^3) : i >= 0 and k >= -N + i and k >= -j and j <= i }
diff --git a/final/lib/External/isl/test_inputs/philippe3vars3pars.pwqp b/final/lib/External/isl/test_inputs/philippe3vars3pars.pwqp
new file mode 100644
index 0000000..f81b8cc
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/philippe3vars3pars.pwqp
@@ -0,0 +1 @@
+[N, M, L] -> { [i, j, k] -> (((1/2 * i + 1/2 * i^2) + j) + k^3) : i >= 0 and k >= -N + i and k >= -M - j and j <= L + i and L >= 0 and L >= -M }
diff --git a/final/lib/External/isl/test_inputs/philippeNeg.pwqp b/final/lib/External/isl/test_inputs/philippeNeg.pwqp
new file mode 100644
index 0000000..24dc805
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/philippeNeg.pwqp
@@ -0,0 +1 @@
+[N] -> { [i, j] -> ((1/2 * i + 1/2 * i^2) + j) : i <= N and j >= -1 and j <= i }
diff --git a/final/lib/External/isl/test_inputs/philippePolynomialCoeff.pwqp b/final/lib/External/isl/test_inputs/philippePolynomialCoeff.pwqp
new file mode 100644
index 0000000..e6327c7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/philippePolynomialCoeff.pwqp
@@ -0,0 +1 @@
+[N, M] -> { [i, j] -> ((N * i + (1/5 * N + N^2) * i^2) + 5 * j) : i <= N and j >= 0 and j <= i and M >= 0 }
diff --git a/final/lib/External/isl/test_inputs/philippePolynomialCoeff1P.pwqp b/final/lib/External/isl/test_inputs/philippePolynomialCoeff1P.pwqp
new file mode 100644
index 0000000..ae01d2f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/philippePolynomialCoeff1P.pwqp
@@ -0,0 +1 @@
+[N] -> { [i, j] -> ((N * i + (1/5 * N + N^2) * i^2) + 5 * j) : i <= N and j >= 0 and j <= i }
diff --git a/final/lib/External/isl/test_inputs/product.pwqp b/final/lib/External/isl/test_inputs/product.pwqp
new file mode 100644
index 0000000..ee48b85
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/product.pwqp
@@ -0,0 +1 @@
+[N] -> { [i0, i1, i2] -> (i0^3 * i1^2 + N * i1 * i2) : i0 >= 0 and i0 <= N and i1 >= 0 and i1 <= N and i2 >= 0 and i2 <= N }
diff --git a/final/lib/External/isl/test_inputs/schedule/feautrier_compressed.sc b/final/lib/External/isl/test_inputs/schedule/feautrier_compressed.sc
new file mode 100644
index 0000000..f90bd88
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/schedule/feautrier_compressed.sc
@@ -0,0 +1,5 @@
+# Check that the Feautrier schedule is not confused by
+# compressed nodes in a subgraph of the original dependence graph.
+# OPTIONS: --schedule-algorithm=feautrier
+domain: { A[]; B[0]; C[] }
+validity: { A[] -> B[0] }
diff --git a/final/lib/External/isl/test_inputs/schedule/feautrier_compressed.st b/final/lib/External/isl/test_inputs/schedule/feautrier_compressed.st
new file mode 100644
index 0000000..8d6c654
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/schedule/feautrier_compressed.st
@@ -0,0 +1,11 @@
+domain: "{ B[0]; C[]; A[] }"
+child:
+  set:
+  - filter: "{ B[i0]; A[] }"
+    child:
+      schedule: "[{ B[i0] -> [(1)]; A[] -> [(0)] }]"
+      child:
+        set:
+        - filter: "{ A[] }"
+        - filter: "{ B[i0] }"
+  - filter: "{ C[] }"
diff --git a/final/lib/External/isl/test_inputs/seghir-vd.pip b/final/lib/External/isl/test_inputs/seghir-vd.pip
new file mode 100644
index 0000000..b5395fb
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/seghir-vd.pip
@@ -0,0 +1,17 @@
+0 6
+
+-1
+
+9 8
+ 0 0 0 1 1 0 0 2
+ 1 2 1 0 0 1 0 0
+ 1 0 1 0 -1 0 0 -1
+ 1 -2 -1 0 0 0 0 -1
+ 1 7 3 0 0 0 0 -1
+ 1 -6 -4 0 1 0 3 1
+ 1 -7 -3 0 0 1 6 4
+ 1 0 0 0 0 0 1 0
+ 1 0 0 0 0 0 0 1
+
+Urs_parms
+Urs_unknowns
diff --git a/final/lib/External/isl/test_inputs/set.omega b/final/lib/External/isl/test_inputs/set.omega
new file mode 100644
index 0000000..ac8485f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/set.omega
@@ -0,0 +1 @@
+{[y]: Exists ( alpha : 2alpha = y)}
diff --git a/final/lib/External/isl/test_inputs/small.pip b/final/lib/External/isl/test_inputs/small.pip
new file mode 100644
index 0000000..59557d2
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/small.pip
@@ -0,0 +1,9 @@
+0 2
+
+-1
+
+4 4
+1  1  0  0
+1  0  1  0
+1  1 -3 12
+1 -2  1  3
diff --git a/final/lib/External/isl/test_inputs/sor1d.pip b/final/lib/External/isl/test_inputs/sor1d.pip
new file mode 100644
index 0000000..1bef89e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/sor1d.pip
@@ -0,0 +1,28 @@
+2 4
+ 1	1	0	0
+ 1	0	1	0
+
+-1
+
+20 8
+ 
+ 0	-1	0	0	0	0	0	2
+ 0	0	-1	0	0	0	0	1
+ 0	0	0	-1	0	0	0	2
+ 0	0	0	0	-1	0	0	4
+ 1	0	0	0	1	0	0	-2
+ 1	-2	0	2	1	0	0	-4
+ 1	0	0	0	-1	0	1	-1
+ 1	2	0	-2	-1	0	0	5
+ 1	0	0	1	0	0	0	-1
+ 1	0	-2	1	0	0	0	0
+ 1	-2	0	2	0	0	1	-5
+ 1	0	0	-1	0	1	0	0
+ 1	0	2	-1	0	0	0	1
+ 1	2	0	-2	0	0	0	3
+ 1	0	1	0	0	0	0	0
+ 1	-2	4	0	0	0	1	-3
+ 1	0	-2	0	0	1	0	0
+ 1	2	-4	0	0	0	0	3
+ 1	2	0	0	0	0	0	1
+ 1	-2	0	0	0	2	1	-5
diff --git a/final/lib/External/isl/test_inputs/split.pwqp b/final/lib/External/isl/test_inputs/split.pwqp
new file mode 100644
index 0000000..1804563
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/split.pwqp
@@ -0,0 +1 @@
+[n] -> { [x] -> -1 + [(x+5)/7] : -n - 20 <= x <= n }
diff --git a/final/lib/External/isl/test_inputs/square.pip b/final/lib/External/isl/test_inputs/square.pip
new file mode 100644
index 0000000..7bb3f0c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/square.pip
@@ -0,0 +1,9 @@
+0 3
+
+-1
+
+4 5
+1  1  0  0  0
+1 -1  0  1  0
+1  0  1  0  0
+1  0 -1  1  0
diff --git a/final/lib/External/isl/test_inputs/sven.pip b/final/lib/External/isl/test_inputs/sven.pip
new file mode 100644
index 0000000..8602769
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/sven.pip
@@ -0,0 +1,7 @@
+0 3
+
+-1
+
+2 3
+1  1 -4
+1 -1 10
diff --git a/final/lib/External/isl/test_inputs/test3Deg3Var.pwqp b/final/lib/External/isl/test_inputs/test3Deg3Var.pwqp
new file mode 100644
index 0000000..d9a9ea9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/test3Deg3Var.pwqp
@@ -0,0 +1 @@
+[p] -> { [n, m] -> (n + n^3) : n >= 1 and m >= n and m <= p }
diff --git a/final/lib/External/isl/test_inputs/tobi.pip b/final/lib/External/isl/test_inputs/tobi.pip
new file mode 100644
index 0000000..c31beae
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/tobi.pip
@@ -0,0 +1,15 @@
+2 3
+1 1 -281
+1 -1 14000
+
+-1
+
+6 6
+0  -392     0     8    -1     0
+0   392     8     0     1     0
+1    -1     0     0     0     0
+1     1     0     0     0    35
+1   392     0     0     1     0
+1  -392     0     0    -1   280
+
+Urs_unknowns
diff --git a/final/lib/External/isl/test_inputs/toplas.pwqp b/final/lib/External/isl/test_inputs/toplas.pwqp
new file mode 100644
index 0000000..9c09995
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/toplas.pwqp
@@ -0,0 +1 @@
+[n] -> { [i0, i1] -> (((4 * n - n^2) + (-3/2 + 2 * n) * i0 - 1/2 * i0^2) - i1) : i1 >= -1 + 3n - i0 and i1 >= -1 + 2n - i0 and i0 >= 0 and i1 <= -2 + 4n - i0 and i0 <= -2 + 4n and i0 <= -1 + 3n and i1 >= 0 and i1 <= -1 + n }
diff --git a/final/lib/External/isl/test_inputs/unexpanded.pwqp b/final/lib/External/isl/test_inputs/unexpanded.pwqp
new file mode 100644
index 0000000..5626d3b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/unexpanded.pwqp
@@ -0,0 +1 @@
+{ [x, y] -> ((x - x^2) * y + (-x + x^2) * y^2) : x >= 0 and x <= 2 and y >= 0 and y <= 2 }
diff --git a/final/lib/External/isl_config.h.cmake b/final/lib/External/isl_config.h.cmake
new file mode 100644
index 0000000..036dc4f
--- /dev/null
+++ b/final/lib/External/isl_config.h.cmake
@@ -0,0 +1,56 @@
+/* define if your compiler has __attribute__ */
+#cmakedefine HAVE___ATTRIBUTE__ /**/
+
+/* most gcc compilers know a function __attribute__((__warn_unused_result__)) */
+#define GCC_WARN_UNUSED_RESULT @GCC_WARN_UNUSED_RESULT@
+
+
+/* Define to 1 if you have the declaration of `ffs', and to 0 if you don't. */
+#define HAVE_DECL_FFS @HAVE_DECL_FFS@
+
+/* Define to 1 if you have the declaration of `__builtin_ffs', and to 0 if you
+   don't. */
+#define HAVE_DECL___BUILTIN_FFS @HAVE_DECL___BUILTIN_FFS@
+
+/* Define to 1 if you have the declaration of `_BitScanForward', and to 0 if
+   you don't. */
+#define HAVE_DECL__BITSCANFORWARD @HAVE_DECL__BITSCANFORWARD@
+
+
+/* Define to 1 if you have the declaration of `strcasecmp', and to 0 if you
+   don't. */
+#define HAVE_DECL_STRCASECMP @HAVE_DECL_STRCASECMP@
+
+/* Define to 1 if you have the declaration of `_stricmp', and to 0 if you
+   don't. */
+#define HAVE_DECL__STRICMP @HAVE_DECL__STRICMP@
+
+
+/* Define to 1 if you have the declaration of `strncasecmp', and to 0 if you
+   don't. */
+#define HAVE_DECL_STRNCASECMP @HAVE_DECL_STRNCASECMP@
+
+/* Define to 1 if you have the declaration of `_strnicmp', and to 0 if you
+   don't. */
+#define HAVE_DECL__STRNICMP @HAVE_DECL__STRNICMP@
+
+
+/* Define to 1 if you have the declaration of `snprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL_SNPRINTF @HAVE_DECL_SNPRINTF@
+
+/* Define to 1 if you have the declaration of `_snprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL__SNPRINTF @HAVE_DECL__SNPRINTF@
+
+
+/* use gmp to implement isl_int */
+#cmakedefine USE_GMP_FOR_MP
+
+/* use imath to implement isl_int */
+#cmakedefine USE_IMATH_FOR_MP
+
+/* Use small integer optimization */
+#cmakedefine USE_SMALL_INT_OPT
+
+#include <isl_config_post.h>
diff --git a/final/lib/External/isl_srcdir.c.cmake b/final/lib/External/isl_srcdir.c.cmake
new file mode 100644
index 0000000..34ef890
--- /dev/null
+++ b/final/lib/External/isl_srcdir.c.cmake
@@ -0,0 +1 @@
+static const char *srcdir = "@ISL_SOURCE_DIR@";
diff --git a/final/lib/External/pet/include/pet.h b/final/lib/External/pet/include/pet.h
new file mode 100644
index 0000000..28a28b8
--- /dev/null
+++ b/final/lib/External/pet/include/pet.h
@@ -0,0 +1,622 @@
+#ifndef PET_H
+#define PET_H
+
+#include <isl/aff.h>
+#include <isl/arg.h>
+#include <isl/ast_build.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/union_map.h>
+#include <isl/printer.h>
+#include <isl/id_to_ast_expr.h>
+#include <isl/id_to_pw_aff.h>
+#include <isl/schedule.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct pet_options;
+ISL_ARG_DECL(pet_options, struct pet_options, pet_options_args)
+
+/* Create an isl_ctx that references the pet options. */
+isl_ctx *isl_ctx_alloc_with_pet_options();
+
+/* If autodetect is set, any valid scop is extracted.
+ * Otherwise, the scop needs to be delimited by pragmas.
+ */
+int pet_options_set_autodetect(isl_ctx *ctx, int val);
+int pet_options_get_autodetect(isl_ctx *ctx);
+
+int pet_options_set_detect_conditional_assignment(isl_ctx *ctx, int val);
+int pet_options_get_detect_conditional_assignment(isl_ctx *ctx);
+
+/* If encapsulate-dynamic-control is set, then any dynamic control
+ * in the input program will be encapsulated in macro statements.
+ * This means in particular that no statements with arguments
+ * will be created.
+ */
+int pet_options_set_encapsulate_dynamic_control(isl_ctx *ctx, int val);
+int pet_options_get_encapsulate_dynamic_control(isl_ctx *ctx);
+
+#define	PET_OVERFLOW_AVOID	0
+#define	PET_OVERFLOW_IGNORE	1
+int pet_options_set_signed_overflow(isl_ctx *ctx, int val);
+int pet_options_get_signed_overflow(isl_ctx *ctx);
+
+struct pet_loc;
+typedef struct pet_loc pet_loc;
+
+/* Return an additional reference to "loc". */
+__isl_give pet_loc *pet_loc_copy(__isl_keep pet_loc *loc);
+/* Free a reference to "loc". */
+pet_loc *pet_loc_free(__isl_take pet_loc *loc);
+
+/* Return the offset in the input file of the start of "loc". */
+unsigned pet_loc_get_start(__isl_keep pet_loc *loc);
+/* Return the offset in the input file of the character after "loc". */
+unsigned pet_loc_get_end(__isl_keep pet_loc *loc);
+/* Return the line number of a line within the "loc" region. */
+int pet_loc_get_line(__isl_keep pet_loc *loc);
+/* Return the indentation of the "loc" region. */
+__isl_keep const char *pet_loc_get_indent(__isl_keep pet_loc *loc);
+
+enum pet_expr_type {
+	pet_expr_error = -1,
+	pet_expr_access,
+	pet_expr_call,
+	pet_expr_cast,
+	pet_expr_int,
+	pet_expr_double,
+	pet_expr_op
+};
+
+enum pet_op_type {
+	/* only compound assignments operators before assignment */
+	pet_op_add_assign,
+	pet_op_sub_assign,
+	pet_op_mul_assign,
+	pet_op_div_assign,
+	pet_op_and_assign,
+	pet_op_xor_assign,
+	pet_op_or_assign,
+	pet_op_assign,
+	pet_op_add,
+	pet_op_sub,
+	pet_op_mul,
+	pet_op_div,
+	pet_op_mod,
+	pet_op_shl,
+	pet_op_shr,
+	pet_op_eq,
+	pet_op_ne,
+	pet_op_le,
+	pet_op_ge,
+	pet_op_lt,
+	pet_op_gt,
+	pet_op_minus,
+	pet_op_post_inc,
+	pet_op_post_dec,
+	pet_op_pre_inc,
+	pet_op_pre_dec,
+	pet_op_address_of,
+	pet_op_assume,
+	pet_op_kill,
+	pet_op_and,
+	pet_op_xor,
+	pet_op_or,
+	pet_op_not,
+	pet_op_land,
+	pet_op_lor,
+	pet_op_lnot,
+	pet_op_cond,
+	pet_op_last
+};
+
+/* Index into the pet_expr->args array when pet_expr->type == pet_expr_unary
+ */
+enum pet_un_arg_type {
+	pet_un_arg
+};
+
+/* Indices into the pet_expr->args array when
+ * pet_expr->type == pet_expr_binary
+ */
+enum pet_bin_arg_type {
+	pet_bin_lhs,
+	pet_bin_rhs
+};
+
+/* Indices into the pet_expr->args array when
+ * pet_expr->type == pet_expr_ternary
+ */
+enum pet_ter_arg_type {
+	pet_ter_cond,
+	pet_ter_true,
+	pet_ter_false
+};
+
+struct pet_expr;
+typedef struct pet_expr pet_expr;
+
+/* Return an additional reference to "expr". */
+__isl_give pet_expr *pet_expr_copy(__isl_keep pet_expr *expr);
+/* Free a reference to "expr". */
+__isl_null pet_expr *pet_expr_free(__isl_take pet_expr *expr);
+
+/* Return the isl_ctx in which "expr" was created. */
+isl_ctx *pet_expr_get_ctx(__isl_keep pet_expr *expr);
+
+/* Return the type of "expr". */
+enum pet_expr_type pet_expr_get_type(__isl_keep pet_expr *expr);
+/* Return the number of arguments of "expr". */
+int pet_expr_get_n_arg(__isl_keep pet_expr *expr);
+/* Set the number of arguments of "expr" to "n". */
+__isl_give pet_expr *pet_expr_set_n_arg(__isl_take pet_expr *expr, int n);
+/* Return the argument of "expr" at position "pos". */
+__isl_give pet_expr *pet_expr_get_arg(__isl_keep pet_expr *expr, int pos);
+/* Replace the argument of "expr" at position "pos" by "arg". */
+__isl_give pet_expr *pet_expr_set_arg(__isl_take pet_expr *expr, int pos,
+	__isl_take pet_expr *arg);
+
+/* Return the operation type of operation expression "expr". */
+enum pet_op_type pet_expr_op_get_type(__isl_keep pet_expr *expr);
+/* Replace the operation type of operation expression "expr" by "type". */
+__isl_give pet_expr *pet_expr_op_set_type(__isl_take pet_expr *expr,
+	enum pet_op_type type);
+
+/* Construct a (read) access pet_expr from an index expression. */
+__isl_give pet_expr *pet_expr_from_index(__isl_take isl_multi_pw_aff *index);
+
+/* Does "expr" represent an affine expression? */
+isl_bool pet_expr_is_affine(__isl_keep pet_expr *expr);
+/* Does the access expression "expr" read the accessed elements? */
+isl_bool pet_expr_access_is_read(__isl_keep pet_expr *expr);
+/* Does the access expression "expr" write to the accessed elements? */
+isl_bool pet_expr_access_is_write(__isl_keep pet_expr *expr);
+/* Does the access expression "expr" kill the accessed elements? */
+isl_bool pet_expr_access_is_kill(__isl_keep pet_expr *expr);
+/* Mark "expr" as a read depending on "read". */
+__isl_give pet_expr *pet_expr_access_set_read(__isl_take pet_expr *expr,
+	int read);
+/* Mark "expr" as a write depending on "write". */
+__isl_give pet_expr *pet_expr_access_set_write(__isl_take pet_expr *expr,
+	int write);
+/* Mark "expr" as a kill depending on "kill". */
+__isl_give pet_expr *pet_expr_access_set_kill(__isl_take pet_expr *expr,
+	int kill);
+/* Return the reference identifier of access expression "expr". */
+__isl_give isl_id *pet_expr_access_get_ref_id(__isl_keep pet_expr *expr);
+/* Replace the reference identifier of access expression "expr" by "ref_id". */
+__isl_give pet_expr *pet_expr_access_set_ref_id(__isl_take pet_expr *expr,
+	__isl_take isl_id *ref_id);
+/* Return the identifier of the outer array accessed by "expr". */
+__isl_give isl_id *pet_expr_access_get_id(__isl_keep pet_expr *expr);
+/* Return the index expression of access expression "expr". */
+__isl_give isl_multi_pw_aff *pet_expr_access_get_index(
+	__isl_keep pet_expr *expr);
+
+/* Return the potential read access relation of access expression "expr". */
+__isl_give isl_union_map *pet_expr_access_get_may_read(
+	__isl_keep pet_expr *expr);
+/* Return the potential write access relation of access expression "expr". */
+__isl_give isl_union_map *pet_expr_access_get_may_write(
+	__isl_keep pet_expr *expr);
+/* Return the definite write access relation of access expression "expr". */
+__isl_give isl_union_map *pet_expr_access_get_must_write(
+	__isl_keep pet_expr *expr);
+/* Return the argument dependent potential read access relation of "expr". */
+__isl_give isl_union_map *pet_expr_access_get_dependent_may_read(
+	__isl_keep pet_expr *expr);
+/* Return the argument dependent potential write access relation of "expr". */
+__isl_give isl_union_map *pet_expr_access_get_dependent_may_write(
+	__isl_keep pet_expr *expr);
+/* Return the argument dependent definite write access relation of "expr". */
+__isl_give isl_union_map *pet_expr_access_get_dependent_must_write(
+	__isl_keep pet_expr *expr);
+/* Return the tagged potential read access relation of access "expr". */
+__isl_give isl_union_map *pet_expr_access_get_tagged_may_read(
+	__isl_keep pet_expr *expr);
+/* Return the tagged potential write access relation of access "expr". */
+__isl_give isl_union_map *pet_expr_access_get_tagged_may_write(
+	__isl_keep pet_expr *expr);
+
+/* Return the name of the function called by "expr". */
+__isl_keep const char *pet_expr_call_get_name(__isl_keep pet_expr *expr);
+/* Replace the name of the function called by "expr" by "name". */
+__isl_give pet_expr *pet_expr_call_set_name(__isl_take pet_expr *expr,
+	__isl_keep const char *name);
+
+/* Create a pet_expr representing a cast of "arg" to "type_name". */
+__isl_give pet_expr *pet_expr_new_cast(const char *type_name,
+	__isl_take pet_expr *arg);
+/* Replace the type of the cast performed by "expr" by "name". */
+__isl_give pet_expr *pet_expr_cast_set_type_name(__isl_take pet_expr *expr,
+	__isl_keep const char *name);
+
+/* Return the value of the integer represented by "expr". */
+__isl_give isl_val *pet_expr_int_get_val(__isl_keep pet_expr *expr);
+/* Replace the value of the integer represented by "expr" by "v". */
+__isl_give pet_expr *pet_expr_int_set_val(__isl_take pet_expr *expr,
+	__isl_take isl_val *v);
+
+/* Return a string representation of the double expression "expr". */
+__isl_give char *pet_expr_double_get_str(__isl_keep pet_expr *expr);
+/* Replace value and string representation of the double expression "expr" */
+__isl_give pet_expr *pet_expr_double_set(__isl_take pet_expr *expr,
+	double d, __isl_keep const char *s);
+
+/* Call "fn" on each of the subexpressions of "expr" of type pet_expr_access. */
+int pet_expr_foreach_access_expr(__isl_keep pet_expr *expr,
+	int (*fn)(__isl_keep pet_expr *expr, void *user), void *user);
+/* Call "fn" on each of the subexpressions of "expr" of type pet_expr_call. */
+int pet_expr_foreach_call_expr(__isl_keep pet_expr *expr,
+	int (*fn)(__isl_keep pet_expr *expr, void *user), void *user);
+
+struct pet_context;
+typedef struct pet_context pet_context;
+
+/* Create a context with the given domain. */
+__isl_give pet_context *pet_context_alloc(__isl_take isl_set *domain);
+/* Return an additional reference to "pc". */
+__isl_give pet_context *pet_context_copy(__isl_keep pet_context *pc);
+/* Free a reference to "pc". */
+__isl_null pet_context *pet_context_free(__isl_take pet_context *pc);
+
+/* Return the isl_ctx in which "pc" was created. */
+isl_ctx *pet_context_get_ctx(__isl_keep pet_context *pc);
+
+/* Extract an affine expression defined over the domain of "pc" from "expr"
+ * or return NaN.
+ */
+__isl_give isl_pw_aff *pet_expr_extract_affine(__isl_keep pet_expr *expr,
+	__isl_keep pet_context *pc);
+
+void pet_expr_dump(__isl_keep pet_expr *expr);
+
+enum pet_tree_type {
+	pet_tree_error = -1,
+	pet_tree_expr,
+	pet_tree_block,
+	pet_tree_break,
+	pet_tree_continue,
+	pet_tree_decl,		/* A declaration without initialization */
+	pet_tree_decl_init,	/* A declaration with initialization */
+	pet_tree_if,		/* An if without an else branch */
+	pet_tree_if_else,	/* An if with an else branch */
+	pet_tree_for,
+	pet_tree_infinite_loop,
+	pet_tree_while,
+	pet_tree_return,
+};
+
+struct pet_tree;
+typedef struct pet_tree pet_tree;
+
+/* Return the isl_ctx in which "tree" was created. */
+isl_ctx *pet_tree_get_ctx(__isl_keep pet_tree *tree);
+
+/* Return an additional reference to "tree". */
+__isl_give pet_tree *pet_tree_copy(__isl_keep pet_tree *tree);
+/* Free a reference to "tree". */
+__isl_null pet_tree *pet_tree_free(__isl_take pet_tree *tree);
+
+/* Return the location of "tree". */
+__isl_give pet_loc *pet_tree_get_loc(__isl_keep pet_tree *tree);
+
+/* Return the type of "tree". */
+enum pet_tree_type pet_tree_get_type(__isl_keep pet_tree *tree);
+
+/* Return the expression of the expression tree "tree". */
+__isl_give pet_expr *pet_tree_expr_get_expr(__isl_keep pet_tree *tree);
+
+/* Return the expression returned by the return tree "tree". */
+__isl_give pet_expr *pet_tree_return_get_expr(__isl_keep pet_tree *tree);
+
+/* Return the number of children of the block tree "tree". */
+int pet_tree_block_n_child(__isl_keep pet_tree *tree);
+/* Return child "pos" of the block tree "tree". */
+__isl_give pet_tree *pet_tree_block_get_child(__isl_keep pet_tree *tree,
+	int pos);
+
+/* Is "tree" a declaration (with or without initialization)? */
+int pet_tree_is_decl(__isl_keep pet_tree *tree);
+/* Return the variable declared by the declaration tree "tree". */
+__isl_give pet_expr *pet_tree_decl_get_var(__isl_keep pet_tree *tree);
+/* Return the initial value of the pet_tree_decl_init tree "tree". */
+__isl_give pet_expr *pet_tree_decl_get_init(__isl_keep pet_tree *tree);
+
+/* Return the condition of the if tree "tree". */
+__isl_give pet_expr *pet_tree_if_get_cond(__isl_keep pet_tree *tree);
+/* Return the then branch of the if tree "tree". */
+__isl_give pet_tree *pet_tree_if_get_then(__isl_keep pet_tree *tree);
+/* Return the else branch of the if tree with else branch "tree". */
+__isl_give pet_tree *pet_tree_if_get_else(__isl_keep pet_tree *tree);
+
+/* Is "tree" a for loop, a while loop or an infinite loop? */
+int pet_tree_is_loop(__isl_keep pet_tree *tree);
+/* Return the induction variable of the for loop "tree" */
+__isl_give pet_expr *pet_tree_loop_get_var(__isl_keep pet_tree *tree);
+/* Return the initial value of the induction variable of the for loop "tree" */
+__isl_give pet_expr *pet_tree_loop_get_init(__isl_keep pet_tree *tree);
+/* Return the condition of the loop tree "tree" */
+__isl_give pet_expr *pet_tree_loop_get_cond(__isl_keep pet_tree *tree);
+/* Return the induction variable of the for loop "tree" */
+__isl_give pet_expr *pet_tree_loop_get_inc(__isl_keep pet_tree *tree);
+/* Return the body of the loop tree "tree" */
+__isl_give pet_tree *pet_tree_loop_get_body(__isl_keep pet_tree *tree);
+
+/* Call "fn" on each top-level expression in the nodes of "tree" */
+int pet_tree_foreach_expr(__isl_keep pet_tree *tree,
+	int (*fn)(__isl_keep pet_expr *expr, void *user), void *user);
+/* Call "fn" on each access subexpression in the nodes of "tree" */
+int pet_tree_foreach_access_expr(__isl_keep pet_tree *tree,
+	int (*fn)(__isl_keep pet_expr *expr, void *user), void *user);
+/* Modify all call subexpressions in the nodes of "tree" through "fn". */
+__isl_give pet_tree *pet_tree_map_call_expr(__isl_take pet_tree *tree,
+	__isl_give pet_expr *(*fn)(__isl_take pet_expr *expr, void *user),
+	void *user);
+
+void pet_tree_dump(__isl_keep pet_tree *tree);
+
+/* "loc" represents the region of the source code that is represented
+ * by this statement.
+ *
+ * If the statement has arguments, i.e., n_arg != 0, then
+ * "domain" is a wrapped map, mapping the iteration domain
+ * to the values of the arguments for which this statement
+ * is executed.
+ * Otherwise, it is simply the iteration domain.
+ *
+ * If one of the arguments is an access expression that accesses
+ * more than one element for a given iteration, then the constraints
+ * on the value of this argument (encoded in "domain") should be satisfied
+ * for all of those accessed elements.
+ */
+struct pet_stmt {
+	pet_loc *loc;
+	isl_set *domain;
+	pet_tree *body;
+
+	unsigned n_arg;
+	pet_expr **args;
+};
+
+/* Return the iteration space of "stmt". */
+__isl_give isl_space *pet_stmt_get_space(struct pet_stmt *stmt);
+
+/* Is "stmt" an assignment statement? */
+int pet_stmt_is_assign(struct pet_stmt *stmt);
+/* Is "stmt" a kill statement? */
+int pet_stmt_is_kill(struct pet_stmt *stmt);
+
+/* pet_stmt_build_ast_exprs is currently limited to only handle
+ * some forms of data dependent accesses.
+ * If pet_stmt_can_build_ast_exprs returns 1, then pet_stmt_build_ast_exprs
+ * can safely be called on "stmt".
+ */
+int pet_stmt_can_build_ast_exprs(struct pet_stmt *stmt);
+/* Construct an associative array from reference identifiers of
+ * access expressions in "stmt" to the corresponding isl_ast_expr.
+ * Each index expression is first transformed through "fn_index"
+ * (if not NULL).  Then an AST expression is generated using "build".
+ * Finally, the AST expression is transformed using "fn_expr"
+ * (if not NULL).
+ */
+__isl_give isl_id_to_ast_expr *pet_stmt_build_ast_exprs(struct pet_stmt *stmt,
+	__isl_keep isl_ast_build *build,
+	__isl_give isl_multi_pw_aff *(*fn_index)(
+		__isl_take isl_multi_pw_aff *mpa, __isl_keep isl_id *id,
+		void *user), void *user_index,
+	__isl_give isl_ast_expr *(*fn_expr)(__isl_take isl_ast_expr *expr,
+		__isl_keep isl_id *id, void *user), void *user_expr);
+
+/* Print "stmt" to "p".
+ *
+ * The access expressions in "stmt" are replaced by the isl_ast_expr
+ * associated to its reference identifier in "ref2expr".
+ */
+__isl_give isl_printer *pet_stmt_print_body(struct pet_stmt *stmt,
+	__isl_take isl_printer *p, __isl_keep isl_id_to_ast_expr *ref2expr);
+
+/* This structure represents a defined type.
+ * "name" is the name of the type, while "definition" is a string
+ * representation of its definition.
+ */
+struct pet_type {
+	char *name;
+	char *definition;
+};
+
+/* context holds constraints on the parameter that ensure that
+ * this array has a valid (i.e., non-negative) size
+ *
+ * extent holds constraints on the indices
+ *
+ * value_bounds holds constraints on the elements of the array
+ * and may be NULL if no such constraints were specified by the user
+ *
+ * element_size is the size in bytes of each array element
+ * element_type is the type of the array elements.
+ * element_is_record is set if this type is a record type.
+ *
+ * live_out is set if the array appears in a live-out pragma
+ *
+ * if uniquely_defined is set then the array is written by a single access
+ * such that any element that is ever read
+ * is known to be assigned exactly once before the read
+ *
+ * declared is set if the array was declared somewhere inside the scop.
+ * exposed is set if the declared array is visible outside the scop.
+ * outer is set if the type of the array elements is a record and
+ * the fields of this record are represented by separate pet_array structures.
+ */
+struct pet_array {
+	isl_set *context;
+	isl_set *extent;
+	isl_set *value_bounds;
+	char *element_type;
+	int element_is_record;
+	int element_size;
+	int live_out;
+	int uniquely_defined;
+	int declared;
+	int exposed;
+	int outer;
+};
+
+/* This structure represents an implication on a boolean filter.
+ * In particular, if the filter value of an element in the domain
+ * of "extension" is equal to "satisfied", then the filter values
+ * of the corresponding images in "extension" are also equal
+ * to "satisfied".
+ */
+struct pet_implication {
+	int satisfied;
+	isl_map *extension;
+};
+
+/* This structure represents an independence implied by a for loop
+ * that is marked as independent in the source code.
+ * "filter" contains pairs of statement instances that are guaranteed
+ * not to be dependent on each other based on the independent for loop,
+ * assuming that no dependences carried by this loop are implied
+ * by the variables in "local".
+ * "local" contains the variables that are local to the loop that was
+ * marked independent.
+ */
+struct pet_independence {
+	isl_union_map *filter;
+	isl_union_set *local;
+};
+
+/* "loc" represents the region of the source code that is represented
+ * by this scop.
+ * If the scop was detected based on scop and endscop pragmas, then
+ * the lines containing these pragmas are included in this region.
+ * In the final result, the context describes the set of parameter values
+ * for which the scop can be executed.
+ * During the construction of the pet_scop, the context lives in a set space
+ * where each dimension refers to an outer loop.
+ * context_value describes assignments to the parameters (if any)
+ * outside of the scop.
+ *
+ * "schedule" is the schedule of the statements in the scop.
+ *
+ * The n_type types define types that may be referenced from by the arrays.
+ *
+ * The n_implication implications describe implications on boolean filters.
+ *
+ * The n_independence independences describe independences implied
+ * by for loops that are marked independent in the source code.
+ */
+struct pet_scop {
+	pet_loc *loc;
+
+	isl_set *context;
+	isl_set *context_value;
+	isl_schedule *schedule;
+
+	int n_type;
+	struct pet_type **types;
+
+	int n_array;
+	struct pet_array **arrays;
+
+	int n_stmt;
+	struct pet_stmt **stmts;
+
+	int n_implication;
+	struct pet_implication **implications;
+
+	int n_independence;
+	struct pet_independence **independences;
+};
+typedef struct pet_scop pet_scop;
+
+/* Return a textual representation of the operator. */
+const char *pet_op_str(enum pet_op_type op);
+int pet_op_is_inc_dec(enum pet_op_type op);
+
+/* Extract a pet_scop from a C source file.
+ * If function is not NULL, then the pet_scop is extracted from
+ * a function with that name.
+ */
+__isl_give pet_scop *pet_scop_extract_from_C_source(isl_ctx *ctx,
+	const char *filename, const char *function);
+
+/* Transform the C source file "input" by rewriting each scop
+ * When autodetecting scops, at most one scop per function is rewritten.
+ * The transformed C code is written to "output".
+ */
+int pet_transform_C_source(isl_ctx *ctx, const char *input, FILE *output,
+	__isl_give isl_printer *(*transform)(__isl_take isl_printer *p,
+		__isl_take pet_scop *scop, void *user), void *user);
+/* Given a scop and a printer passed to a pet_transform_C_source callback,
+ * print the original corresponding code to the printer.
+ */
+__isl_give isl_printer *pet_scop_print_original(__isl_keep pet_scop *scop,
+	__isl_take isl_printer *p);
+
+/* Update all isl_sets and isl_maps such that they all have the same
+ * parameters in the same order.
+ */
+__isl_give pet_scop *pet_scop_align_params(__isl_take pet_scop *scop);
+
+/* Does "scop" contain any data dependent accesses? */
+int pet_scop_has_data_dependent_accesses(__isl_keep pet_scop *scop);
+/* Does "scop" contain any data dependent conditions? */
+int pet_scop_has_data_dependent_conditions(__isl_keep pet_scop *scop);
+/* pet_stmt_build_ast_exprs is currently limited to only handle
+ * some forms of data dependent accesses.
+ * If pet_scop_can_build_ast_exprs returns 1, then pet_stmt_build_ast_exprs
+ * can safely be called on all statements in the scop.
+ */
+int pet_scop_can_build_ast_exprs(__isl_keep pet_scop *scop);
+
+void pet_scop_dump(__isl_keep pet_scop *scop);
+__isl_null pet_scop *pet_scop_free(__isl_take pet_scop *scop);
+
+/* Return the context of "scop". */
+__isl_give isl_set *pet_scop_get_context(__isl_keep pet_scop *scop);
+/* Return the schedule of "scop". */
+__isl_give isl_schedule *pet_scop_get_schedule(__isl_keep pet_scop *scop);
+/* Return the set of all statement instances. */
+__isl_give isl_union_set *pet_scop_get_instance_set(__isl_keep pet_scop *scop);
+/* Return the potential read access relation. */
+__isl_give isl_union_map *pet_scop_get_may_reads(__isl_keep pet_scop *scop);
+/* Return the tagged potential read access relation. */
+__isl_give isl_union_map *pet_scop_get_tagged_may_reads(
+	__isl_keep pet_scop *scop);
+/* Return the potential write access relation. */
+__isl_give isl_union_map *pet_scop_get_may_writes(__isl_keep pet_scop *scop);
+/* Return the definite write access relation. */
+__isl_give isl_union_map *pet_scop_get_must_writes(__isl_keep pet_scop *scop);
+/* Return the tagged potential write access relation. */
+__isl_give isl_union_map *pet_scop_get_tagged_may_writes(
+	__isl_keep pet_scop *scop);
+/* Return the tagged definite write access relation. */
+__isl_give isl_union_map *pet_scop_get_tagged_must_writes(
+	__isl_keep pet_scop *scop);
+/* Return the definite kill access relation. */
+__isl_give isl_union_map *pet_scop_get_must_kills(__isl_keep pet_scop *scop);
+/* Return the tagged definite kill access relation. */
+__isl_give isl_union_map *pet_scop_get_tagged_must_kills(
+	__isl_keep pet_scop *scop);
+
+/* Compute a mapping from all outermost arrays (of structs) in scop
+ * to their innermost members.
+ */
+__isl_give isl_union_map *pet_scop_compute_outer_to_inner(
+	__isl_keep pet_scop *scop);
+/* Compute a mapping from all outermost arrays (of structs) in scop
+ * to their members, including the outermost arrays themselves.
+ */
+__isl_give isl_union_map *pet_scop_compute_outer_to_any(
+	__isl_keep pet_scop *scop);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/final/lib/External/ppcg/ChangeLog b/final/lib/External/ppcg/ChangeLog
new file mode 100644
index 0000000..e902701
--- /dev/null
+++ b/final/lib/External/ppcg/ChangeLog
@@ -0,0 +1,29 @@
+version: 0.07
+date: Tue Feb  7 17:23:22 CET 2017
+changes:
+	- support hybrid tiling
+---
+version: 0.06
+date: Fri May  6 12:08:50 CEST 2016
+changes:
+	- use PPCG specific macro names in generated code
+	- complete transition to schedule trees
+	- maximize coincidence by default
+	- map arrays with constant index expressions to private memory
+	- optionally group chains of statements
+---
+version: 0.05
+date: Fri Jan 15 09:30:23 CET 2016
+changes:
+	- fix live-out computation
+	- optionally compute schedule for C target
+	- optionally perform tiling for C target
+	- create single kernel for non-permutable subtree
+---
+version: 0.04
+date: Wed Jun 17 10:52:58 CEST 2015
+changes:
+	- use schedule trees
+	- fix live-range reordering
+	- improve generation of synchronization
+	- exploit independences during dependence analysis
diff --git a/final/lib/External/ppcg/GIT_HEAD_ID b/final/lib/External/ppcg/GIT_HEAD_ID
new file mode 100644
index 0000000..642f492
--- /dev/null
+++ b/final/lib/External/ppcg/GIT_HEAD_ID
@@ -0,0 +1 @@
+ppcg-0.07
diff --git a/final/lib/External/ppcg/Makefile.am b/final/lib/External/ppcg/Makefile.am
new file mode 100644
index 0000000..7c12da3
--- /dev/null
+++ b/final/lib/External/ppcg/Makefile.am
@@ -0,0 +1,77 @@
+if BUNDLED_ISL
+    MAYBE_ISL = isl
+    ISL_LA = $(top_builddir)/isl/libisl.la
+    LOCAL_ISL_LA = isl/libisl.la
+endif
+if BUNDLED_PET
+    MAYBE_PET = pet
+    PET_LA = $(top_builddir)/pet/libpet.la
+endif
+
+SUBDIRS = $(MAYBE_ISL) $(MAYBE_PET) .
+
+FORCE:
+isl/libisl.la: FORCE
+	cd isl; $(MAKE) $(AM_MAKEFLAGS) libisl.la
+pet/libpet.la: FORCE
+	cd pet; $(MAKE) $(AM_MAKEFLAGS) libpet.la
+
+ACLOCAL_AMFLAGS = -I m4
+
+LIB_ISL = $(ISL_LA) @ISL_LIBS@
+LIB_PET = $(PET_LA) @PET_LIBS@
+
+AM_CPPFLAGS = @ISL_CFLAGS@ @PET_CFLAGS@
+LDADD = $(LIB_PET) $(LIB_ISL)
+
+bin_PROGRAMS = ppcg
+ppcg_SOURCES = \
+	cpu.c \
+	cpu.h \
+	cuda.c \
+	cuda.h \
+	opencl.c \
+	opencl.h \
+	cuda_common.h \
+	cuda_common.c \
+	gpu.c \
+	gpu.h \
+	gpu_array_tile.c \
+	gpu_array_tile.h \
+	gpu_group.c \
+	gpu_group.h \
+	gpu_hybrid.c \
+	gpu_hybrid.h \
+	gpu_print.c \
+	gpu_print.h \
+	gpu_tree.c \
+	gpu_tree.h \
+	grouping.c \
+	hybrid.c \
+	hybrid.h \
+	schedule.c \
+	schedule.h \
+	ppcg_options.c \
+	ppcg_options.h \
+	ppcg.c \
+	ppcg.h \
+	print.c \
+	print.h \
+	util.c \
+	util.h \
+	version.c
+
+TESTS = @extra_tests@
+EXTRA_TESTS = opencl_test.sh polybench_test.sh
+TEST_EXTENSIONS = .sh
+
+EXTRA_DIST = \
+	ocl_utilities.c \
+	ocl_utilities.h \
+	tests
+
+dist-hook:
+	echo @GIT_HEAD_VERSION@ > $(distdir)/GIT_HEAD_ID
+
+gitversion.h: @GIT_HEAD@
+	$(AM_V_GEN)echo '#define GIT_HEAD_ID "'@GIT_HEAD_VERSION@'"' > $@
diff --git a/final/lib/External/ppcg/Makefile.in b/final/lib/External/ppcg/Makefile.in
new file mode 100644
index 0000000..c1b7193
--- /dev/null
+++ b/final/lib/External/ppcg/Makefile.in
@@ -0,0 +1,1379 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = ppcg$(EXEEXT)
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_opencl.m4 \
+	$(top_srcdir)/m4/ax_check_openmp.m4 \
+	$(top_srcdir)/m4/ax_detect_git_head.m4 \
+	$(top_srcdir)/m4/ax_submodule.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+	$(am__configure_deps) $(am__DIST_COMMON)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES = polybench_test.sh opencl_test.sh
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_ppcg_OBJECTS = cpu.$(OBJEXT) cuda.$(OBJEXT) opencl.$(OBJEXT) \
+	cuda_common.$(OBJEXT) gpu.$(OBJEXT) gpu_array_tile.$(OBJEXT) \
+	gpu_group.$(OBJEXT) gpu_print.$(OBJEXT) gpu_tree.$(OBJEXT) \
+	schedule.$(OBJEXT) ppcg_options.$(OBJEXT) ppcg.$(OBJEXT) \
+	print.$(OBJEXT) version.$(OBJEXT)
+ppcg_OBJECTS = $(am_ppcg_OBJECTS)
+ppcg_LDADD = $(LDADD)
+am__DEPENDENCIES_1 = $(PET_LA)
+am__DEPENDENCIES_2 = $(ISL_LA)
+ppcg_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(ppcg_SOURCES)
+DIST_SOURCES = $(ppcg_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	cscope check recheck distdir dist dist-all distcheck
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+TEST_SUITE_LOG = test-suite.log
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.sh.log=.log)
+SH_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+SH_LOG_COMPILE = $(SH_LOG_COMPILER) $(AM_SH_LOG_FLAGS) $(SH_LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+DIST_SUBDIRS = isl pet .
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/opencl_test.sh.in \
+	$(srcdir)/polybench_test.sh.in ChangeLog README compile \
+	config.guess config.sub depcomp install-sh ltmain.sh missing \
+	test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  if test -d "$(distdir)"; then \
+    find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+      && rm -rf "$(distdir)" \
+      || { sleep 5 && rm -rf "$(distdir)"; }; \
+  else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+DIST_TARGETS = dist-gzip
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+  | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GIT_HEAD = @GIT_HEAD@
+GIT_HEAD_ID = @GIT_HEAD_ID@
+GIT_HEAD_VERSION = @GIT_HEAD_VERSION@
+GREP = @GREP@
+HAVE_OPENCL = @HAVE_OPENCL@
+HAVE_OPENMP = @HAVE_OPENMP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+ISL_CFLAGS = @ISL_CFLAGS@
+ISL_LIBS = @ISL_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PET_CFLAGS = @PET_CFLAGS@
+PET_LIBS = @PET_LIBS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POLYBENCH_DIR = @POLYBENCH_DIR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+extra_tests = @extra_tests@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@BUNDLED_ISL_TRUE@MAYBE_ISL = isl
+@BUNDLED_ISL_TRUE@ISL_LA = $(top_builddir)/isl/libisl.la
+@BUNDLED_ISL_TRUE@LOCAL_ISL_LA = isl/libisl.la
+@BUNDLED_PET_TRUE@MAYBE_PET = pet
+@BUNDLED_PET_TRUE@PET_LA = $(top_builddir)/pet/libpet.la
+SUBDIRS = $(MAYBE_ISL) $(MAYBE_PET) .
+ACLOCAL_AMFLAGS = -I m4
+LIB_ISL = $(ISL_LA) @ISL_LIBS@
+LIB_PET = $(PET_LA) @PET_LIBS@
+AM_CPPFLAGS = @ISL_CFLAGS@ @PET_CFLAGS@
+LDADD = $(LIB_PET) $(LIB_ISL)
+ppcg_SOURCES = \
+	cpu.c \
+	cpu.h \
+	cuda.c \
+	cuda.h \
+	opencl.c \
+	opencl.h \
+	cuda_common.h \
+	cuda_common.c \
+	gpu.c \
+	gpu.h \
+	gpu_array_tile.c \
+	gpu_array_tile.h \
+	gpu_group.c \
+	gpu_group.h \
+	gpu_print.c \
+	gpu_print.h \
+	gpu_tree.c \
+	gpu_tree.h \
+	schedule.c \
+	schedule.h \
+	ppcg_options.c \
+	ppcg_options.h \
+	ppcg.c \
+	ppcg.h \
+	print.c \
+	print.h \
+	util.h \
+	version.c
+
+TESTS = @extra_tests@
+EXTRA_TESTS = opencl_test.sh polybench_test.sh
+TEST_EXTENSIONS = .sh
+EXTRA_DIST = \
+	ocl_utilities.c \
+	ocl_utilities.h \
+	tests
+
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .sh .sh$(EXEEXT) .trs
+am--refresh: Makefile
+	@:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+	      $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	$(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+polybench_test.sh: $(top_builddir)/config.status $(srcdir)/polybench_test.sh.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+opencl_test.sh: $(top_builddir)/config.status $(srcdir)/opencl_test.sh.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+	fi; \
+	for p in $$list; do echo "$$p $$p"; done | \
+	sed 's/$(EXEEXT)$$//' | \
+	while read p p1; do if test -f $$p \
+	 || test -f $$p1 \
+	  ; then echo "$$p"; echo "$$p"; else :; fi; \
+	done | \
+	sed -e 'p;s,.*/,,;n;h' \
+	    -e 's|.*|.|' \
+	    -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+	sed 'N;N;N;s,\n, ,g' | \
+	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+	    if ($$2 == $$4) files[d] = files[d] " " $$1; \
+	    else { print "f", $$3 "/" $$4, $$1; } } \
+	  END { for (d in files) print "f", d, files[d] }' | \
+	while read type dir files; do \
+	    if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+	    test -z "$$files" || { \
+	    echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+	    $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+	    } \
+	; done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	files=`for p in $$list; do echo "$$p"; done | \
+	  sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+	      -e 's/$$/$(EXEEXT)/' \
+	`; \
+	test -n "$$list" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+	@list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+ppcg$(EXEEXT): $(ppcg_OBJECTS) $(ppcg_DEPENDENCIES) $(EXTRA_ppcg_DEPENDENCIES) 
+	@rm -f ppcg$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(ppcg_OBJECTS) $(ppcg_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cuda.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cuda_common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpu_array_tile.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpu_group.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpu_print.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpu_tree.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opencl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppcg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppcg_options.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/schedule.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool config.lt
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+	test ! -s cscope.files \
+	  || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+	-rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+	-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all 
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+.sh.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(SH_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_SH_LOG_DRIVER_FLAGS) $(SH_LOG_DRIVER_FLAGS) -- $(SH_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.sh$(EXEEXT).log:
+@am__EXEEXT_TRUE@	@p='$<'; \
+@am__EXEEXT_TRUE@	$(am__set_b); \
+@am__EXEEXT_TRUE@	$(am__check_pre) $(SH_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_SH_LOG_DRIVER_FLAGS) $(SH_LOG_DRIVER_FLAGS) -- $(SH_LOG_COMPILE) \
+@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+	$(am__remove_distdir)
+	test -d "$(distdir)" || mkdir "$(distdir)"
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+	$(MAKE) $(AM_MAKEFLAGS) \
+	  top_distdir="$(top_distdir)" distdir="$(distdir)" \
+	  dist-hook
+	-test -n "$(am__skip_mode_fix)" \
+	|| find "$(distdir)" -type d ! -perm -755 \
+		-exec chmod u+rwx,go+rx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__post_remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+	$(am__post_remove_distdir)
+
+dist-lzip: distdir
+	tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+	$(am__post_remove_distdir)
+
+dist-xz: distdir
+	tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+	$(am__post_remove_distdir)
+
+dist-tarZ: distdir
+	@echo WARNING: "Support for distribution archives compressed with" \
+		       "legacy program 'compress' is deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__post_remove_distdir)
+
+dist-shar: distdir
+	@echo WARNING: "Support for shar distribution archives is" \
+	               "deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	$(am__post_remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__post_remove_distdir)
+
+dist dist-all:
+	$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+	$(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.lz*) \
+	  lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+	*.tar.xz*) \
+	  xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir)
+	chmod u+w $(distdir)
+	mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
+	chmod a-w $(distdir)
+	test -d $(distdir)/_build || exit 0; \
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && am__cwd=`pwd` \
+	  && $(am__cd) $(distdir)/_build/sub \
+	  && ../../configure \
+	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	    --srcdir=../.. --prefix="$$dc_install_base" \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+	  && cd "$$am__cwd" \
+	  || exit 1
+	$(am__post_remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+	@test -n '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: trying to run $@ with an empty' \
+	       '$$(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	$(am__cd) '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile $(PROGRAMS)
+installdirs: installdirs-recursive
+installdirs-am:
+	for dir in "$(DESTDIR)$(bindir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+	am--refresh check check-TESTS check-am clean clean-binPROGRAMS \
+	clean-cscope clean-generic clean-libtool cscope cscopelist-am \
+	ctags ctags-am dist dist-all dist-bzip2 dist-gzip dist-hook \
+	dist-lzip dist-shar dist-tarZ dist-xz dist-zip distcheck \
+	distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distcleancheck distdir \
+	distuninstallcheck dvi dvi-am html html-am info info-am \
+	install install-am install-binPROGRAMS install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	recheck tags tags-am uninstall uninstall-am \
+	uninstall-binPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+FORCE:
+isl/libisl.la: FORCE
+	cd isl; $(MAKE) $(AM_MAKEFLAGS) libisl.la
+pet/libpet.la: FORCE
+	cd pet; $(MAKE) $(AM_MAKEFLAGS) libpet.la
+
+dist-hook:
+	echo @GIT_HEAD_VERSION@ > $(distdir)/GIT_HEAD_ID
+
+gitversion.h: @GIT_HEAD@
+	$(AM_V_GEN)echo '#define GIT_HEAD_ID "'@GIT_HEAD_VERSION@'"' > $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/final/lib/External/ppcg/README b/final/lib/External/ppcg/README
new file mode 100644
index 0000000..450786a
--- /dev/null
+++ b/final/lib/External/ppcg/README
@@ -0,0 +1,246 @@
+Requirements:
+
+- automake, autoconf, libtool
+	(not needed when compiling a release)
+- pkg-config (http://www.freedesktop.org/wiki/Software/pkg-config)
+	(not needed when compiling a release using the included isl and pet)
+- gmp (http://gmplib.org/)
+- libyaml (http://pyyaml.org/wiki/LibYAML)
+	(only needed if you want to compile the pet executable)
+- LLVM/clang libraries, 2.9 or higher (http://clang.llvm.org/get_started.html)
+	Unless you have some other reasons for wanting to use the svn version,
+	it is best to install the latest release (3.9).
+	For more details, see pet/README.
+
+If you are installing on Ubuntu, then you can install the following packages:
+
+automake autoconf libtool pkg-config libgmp3-dev libyaml-dev libclang-dev llvm
+
+Note that you need at least version 3.2 of libclang-dev (ubuntu raring).
+Older versions of this package did not include the required libraries.
+If you are using an older version of ubuntu, then you need to compile and
+install LLVM/clang from source.
+
+
+Preparing:
+
+Grab the latest release and extract it or get the source from
+the git repository as follows.  This process requires autoconf,
+automake, libtool and pkg-config.
+
+	git clone git://repo.or.cz/ppcg.git
+	cd ppcg
+	./get_submodules.sh
+	./autogen.sh
+
+
+Compilation:
+
+	./configure
+	make
+	make check
+
+If you have installed any of the required libraries in a non-standard
+location, then you may need to use the --with-gmp-prefix,
+--with-libyaml-prefix and/or --with-clang-prefix options
+when calling "./configure".
+
+
+Using PPCG to generate CUDA or OpenCL code
+
+To convert a fragment of a C program to CUDA, insert a line containing
+
+	#pragma scop
+
+before the fragment and add a line containing
+
+	#pragma endscop
+
+after the fragment.  To generate CUDA code run
+	
+	ppcg --target=cuda file.c
+
+where file.c is the file containing the fragment.  The generated
+code is stored in file_host.cu and file_kernel.cu.
+
+To generate OpenCL code run
+
+	ppcg --target=opencl file.c
+
+where file.c is the file containing the fragment.  The generated code
+is stored in file_host.c and file_kernel.cl.
+
+
+Specifying tile, grid and block sizes
+
+The iterations space tile size, grid size and block size can
+be specified using the --sizes option.  The argument is a union map
+in isl notation mapping kernels identified by their sequence number
+in a "kernel" space to singleton sets in the "tile", "grid" and "block"
+spaces.  The sizes are specified outermost to innermost.
+
+The dimension of the "tile" space indicates the (maximal) number of loop
+dimensions to tile.  The elements of the single integer tuple
+specify the tile sizes in each dimension.
+In case of hybrid tiling, the first element is half the size of
+the tile in the time (sequential) dimension.  The second element
+specifies the number of elements in the base of the hexagon.
+The remaining elements specify the tile sizes in the remaining space
+dimensions.
+
+The dimension of the "grid" space indicates the (maximal) number of block
+dimensions in the grid.  The elements of the single integer tuple
+specify the number of blocks in each dimension.
+
+The dimension of the "block" space indicates the (maximal) number of thread
+dimensions in the grid.  The elements of the single integer tuple
+specify the number of threads in each dimension.
+
+For example,
+
+    { kernel[0] -> tile[64,64]; kernel[i] -> block[16] : i != 4 }
+
+specifies that in kernel 0, two loops should be tiled with a tile
+size of 64 in both dimensions and that all kernels except kernel 4
+should be run using a block of 16 threads.
+
+Since PPCG performs some scheduling, it can be difficult to predict
+what exactly will end up in a kernel.  If you want to specify
+tile, grid or block sizes, you may want to run PPCG first with the defaults,
+examine the kernels and then run PPCG again with the desired sizes.
+Instead of examining the kernels, you can also specify the option
+--dump-sizes on the first run to obtain the effectively used default sizes.
+
+
+Compiling the generated CUDA code with nvcc
+
+To get optimal performance from nvcc, it is important to choose --arch
+according to your target GPU.  Specifically, use the flag "--arch sm_20"
+for fermi, "--arch sm_30" for GK10x Kepler and "--arch sm_35" for
+GK110 Kepler.  We discourage the use of older cards as we have seen
+correctness issues with compilation for older architectures.
+Note that in the absence of any --arch flag, nvcc defaults to
+"--arch sm_13". This will not only be slower, but can also cause
+correctness issues.
+If you want to obtain results that are identical to those obtained
+by the original code, then you may need to disable some optimizations
+by passing the "--fmad=false" option.
+
+
+Compiling the generated OpenCL code with gcc
+
+To compile the host code you need to link against the file
+ocl_utilities.c which contains utility functions used by the generated
+OpenCL host code.  To compile the host code with gcc, run
+
+  gcc -std=c99 file_host.c ocl_utilities.c -lOpenCL
+
+Note that we have experienced the generated OpenCL code freezing
+on some inputs (e.g., the PolyBench symm benchmark) when using
+at least some version of the Nvidia OpenCL library, while the
+corresponding CUDA code runs fine.
+We have experienced no such freezes when using AMD, ARM or Intel
+OpenCL libraries.
+
+By default, the compiled executable will need the _kernel.cl file at
+run time.  Alternatively, the option --opencl-embed-kernel-code may be
+given to place the kernel code in a string literal.  The kernel code is
+then compiled into the host binary, such that the _kernel.cl file is no
+longer needed at run time.  Any kernel include files, in particular
+those supplied using --opencl-include-file, will still be required at
+run time.
+
+
+Function calls
+
+Function calls inside the analyzed fragment are reproduced
+in the CUDA or OpenCL code, but for now it is left to the user
+to make sure that the functions that are being called are
+available from the generated kernels.
+
+In the case of OpenCL code, the --opencl-include-file option
+may be used to specify one or more files to be #include'd
+from the generated code.  These files may then contain
+the definitions of the functions being called from the
+program fragment.  If the pathnames of the included files
+are relative to the current directory, then you may need
+to additionally specify the --opencl-compiler-options=-I.
+to make sure that the files can be found by the OpenCL compiler.
+The included files may contain definitions of types used by the
+generated kernels.  By default, PPCG generates definitions for
+types as needed, but these definitions may collide with those in
+the included files, as PPCG does not consider the contents of the
+included files.  The --no-opencl-print-kernel-types will prevent
+PPCG from generating type definitions.
+
+
+GNU extensions
+
+By default, PPCG may print out macro definitions that involve
+GNU extensions such as __typeof__ and statement expressions.
+Some compilers may not support these extensions.
+In particular, OpenCL 1.2 beignet 1.1.1 (git-6de6918)
+has been reported not to support __typeof__.
+The use of these extensions can be turned off with the
+--no-allow-gnu-extensions option.
+
+
+Processing PolyBench
+
+When processing a PolyBench/C 3.2 benchmark, you should always specify
+-DPOLYBENCH_USE_C99_PROTO on the ppcg command line.  Otherwise, the source
+files are inconsistent, having fixed size arrays but parametrically
+bounded loops iterating over them.
+However, you should not specify this define when compiling
+the PPCG generated code using nvcc since CUDA does not support VLAs.
+
+
+CUDA and function overloading
+
+While CUDA supports function overloading based on the arguments types,
+no such function overloading exists in the input language C.  Since PPCG
+simply prints out the same function name as in the original code, this
+may result in a different function being called based on the types
+of the arguments.  For example, if the original code contains a call
+to the function sqrt() with a float argument, then the argument will
+be promoted to a double and the sqrt() function will be called.
+In the transformed (CUDA) code, however, overloading will cause the
+function sqrtf() to be called.  Until this issue has been resolved in PPCG,
+we recommend that users either explicitly call the function sqrtf() or
+explicitly cast the argument to double in the input code.
+
+
+Contact
+
+For bug reports, feature requests and questions,
+contact http://groups.google.com/group/isl-development
+
+Whenever you report a bug, please mention the exact version of PPCG
+that you are using (output of "./ppcg --version").  If you are unable
+to compile PPCG, then report the git version (output of "git describe")
+or the version number included in the name of the tarball.
+
+
+Citing PPCG
+
+If you use PPCG for your research, you are invited to cite
+the following paper.
+
+@article{Verdoolaege2013PPCG,
+    author = {Verdoolaege, Sven and Juega, Juan Carlos and Cohen, Albert and
+		G\'{o}mez, Jos{\'e} Ignacio and Tenllado, Christian and
+		Catthoor, Francky},
+    title = {Polyhedral parallel code generation for CUDA},
+    journal = {ACM Trans. Archit. Code Optim.},
+    issue_date = {January 2013},
+    volume = {9},
+    number = {4},
+    month = jan,
+    year = {2013},
+    issn = {1544-3566},
+    pages = {54:1--54:23},
+    doi = {10.1145/2400682.2400713},
+    acmid = {2400713},
+    publisher = {ACM},
+    address = {New York, NY, USA},
+}
diff --git a/final/lib/External/ppcg/aclocal.m4 b/final/lib/External/ppcg/aclocal.m4
new file mode 100644
index 0000000..1a669ee
--- /dev/null
+++ b/final/lib/External/ppcg/aclocal.m4
@@ -0,0 +1,1376 @@
+# generated automatically by aclocal 1.15 -*- Autoconf -*-
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
+# serial 1 (pkg-config-0.24)
+# 
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=m4_default([$1], [0.9.0])
+	AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		AC_MSG_RESULT([yes])
+	else
+		AC_MSG_RESULT([no])
+		PKG_CONFIG=""
+	fi
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists.  Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+# only at the first occurence in configure.ac, so if the first place
+# it's called might be skipped (such as if it is within an "if", you
+# have to call PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+  m4_default([$2], [:])
+m4_ifvaln([$3], [else
+  $3])dnl
+fi])
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+    pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+    PKG_CHECK_EXISTS([$3],
+                     [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes ],
+		     [pkg_failed=yes])
+ else
+    pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+   	AC_MSG_RESULT([no])
+        _PKG_SHORT_ERRORS_SUPPORTED
+        if test $_pkg_short_errors_supported = yes; then
+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+        else 
+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+	m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+        ])
+elif test $pkg_failed = untried; then
+     	AC_MSG_RESULT([no])
+	m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
+        ])
+else
+	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+        AC_MSG_RESULT([yes])
+	$3
+fi[]dnl
+])# PKG_CHECK_MODULES
+
+
+# PKG_INSTALLDIR(DIRECTORY)
+# -------------------------
+# Substitutes the variable pkgconfigdir as the location where a module
+# should install pkg-config .pc files. By default the directory is
+# $libdir/pkgconfig, but the default can be changed by passing
+# DIRECTORY. The user can override through the --with-pkgconfigdir
+# parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+    [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+    [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+]) dnl PKG_INSTALLDIR
+
+
+# PKG_NOARCH_INSTALLDIR(DIRECTORY)
+# -------------------------
+# Substitutes the variable noarch_pkgconfigdir as the location where a
+# module should install arch-independent pkg-config .pc files. By
+# default the directory is $datadir/pkgconfig, but the default can be
+# changed by passing DIRECTORY. The user can override through the
+# --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+    [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+    [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+]) dnl PKG_NOARCH_INSTALLDIR
+
+
+# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# -------------------------------------------
+# Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])# PKG_CHECK_VAR
+
+# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.15'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.15], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.15])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+       [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC],   [depcc="$CC"   am_compiler_list=],
+      [$1], [CXX],  [depcc="$CXX"  am_compiler_list=],
+      [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+      [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+      [$1], [UPC],  [depcc="$UPC"  am_compiler_list=],
+      [$1], [GCJ],  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                    [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  am__universal=false
+  m4_case([$1], [CC],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac],
+    [CXX],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac])
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+  [--enable-dependency-tracking],
+  [do not reject slow dependency extractors])
+AS_HELP_STRING(
+  [--disable-dependency-tracking],
+  [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`AS_DIRNAME("$mf")`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`AS_DIRNAME(["$file"])`
+      AS_MKDIR_P([$dirpart/$fdir])
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each '.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+             [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+  m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+  [ok:ok],,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+	      [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+			     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+		  [_AM_DEPENDENCIES([CC])],
+		  [m4_define([AC_PROG_CC],
+			     m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+		  [_AM_DEPENDENCIES([CXX])],
+		  [m4_define([AC_PROG_CXX],
+			     m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+		  [_AM_DEPENDENCIES([OBJC])],
+		  [m4_define([AC_PROG_OBJC],
+			     m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+		  [_AM_DEPENDENCIES([OBJCXX])],
+		  [m4_define([AC_PROG_OBJCXX],
+			     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+  fi
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes.	            -*- Autoconf -*-
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake.  We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+  [whether $CC understands -c and -o together],
+  [am_cv_prog_cc_c_o],
+  [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[[\\\"\#\$\&\'\`$am_lf]]*)
+    AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+  *[[\\\"\#\$\&\'\`$am_lf\ \	]]*)
+    AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$[*]" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$[*]" != "X $srcdir/configure conftest.file" \
+	&& test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment])
+     fi
+     if test "$[2]" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+  [AC_MSG_CHECKING([that generated files are newer than configure])
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+  [--enable-silent-rules],
+  [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+  [--disable-silent-rules],
+  [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+   [am_cv_make_support_nested_variables],
+   [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+  dnl Using '$V' instead of '$(V)' breaks IRIX make.
+  AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+  [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+  [m4_case([$1],
+    [ustar],
+     [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+      # There is notably a 21 bits limit for the UID and the GID.  In fact,
+      # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+      # and bug#13588).
+      am_max_uid=2097151 # 2^21 - 1
+      am_max_gid=$am_max_uid
+      # The $UID and $GID variables are not portable, so we need to resort
+      # to the POSIX-mandated id(1) utility.  Errors in the 'id' calls
+      # below are definitely unexpected, so allow the users to see them
+      # (that is, avoid stderr redirection).
+      am_uid=`id -u || echo unknown`
+      am_gid=`id -g || echo unknown`
+      AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+      if test $am_uid -le $am_max_uid; then
+         AC_MSG_RESULT([yes])
+      else
+         AC_MSG_RESULT([no])
+         _am_tools=none
+      fi
+      AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+      if test $am_gid -le $am_max_gid; then
+         AC_MSG_RESULT([yes])
+      else
+        AC_MSG_RESULT([no])
+        _am_tools=none
+      fi],
+
+  [pax],
+    [],
+
+  [m4_fatal([Unknown tar format])])
+
+  AC_MSG_CHECKING([how to create a $1 tar archive])
+
+  # Go ahead even if we have the value already cached.  We do so because we
+  # need to set the values for the 'am__tar' and 'am__untar' variables.
+  _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+  for _am_tool in $_am_tools; do
+    case $_am_tool in
+    gnutar)
+      for _am_tar in tar gnutar gtar; do
+        AM_RUN_LOG([$_am_tar --version]) && break
+      done
+      am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+      am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+      am__untar="$_am_tar -xf -"
+      ;;
+    plaintar)
+      # Must skip GNU tar: if it does not support --format= it doesn't create
+      # ustar tarball either.
+      (tar --version) >/dev/null 2>&1 && continue
+      am__tar='tar chf - "$$tardir"'
+      am__tar_='tar chf - "$tardir"'
+      am__untar='tar xf -'
+      ;;
+    pax)
+      am__tar='pax -L -x $1 -w "$$tardir"'
+      am__tar_='pax -L -x $1 -w "$tardir"'
+      am__untar='pax -r'
+      ;;
+    cpio)
+      am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+      am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+      am__untar='cpio -i -H $1 -d'
+      ;;
+    none)
+      am__tar=false
+      am__tar_=false
+      am__untar=false
+      ;;
+    esac
+
+    # If the value was cached, stop now.  We just wanted to have am__tar
+    # and am__untar set.
+    test -n "${am_cv_prog_tar_$1}" && break
+
+    # tar/untar a dummy directory, and stop if the command works.
+    rm -rf conftest.dir
+    mkdir conftest.dir
+    echo GrepMe > conftest.dir/file
+    AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+    rm -rf conftest.dir
+    if test -s conftest.tar; then
+      AM_RUN_LOG([$am__untar <conftest.tar])
+      AM_RUN_LOG([cat conftest.dir/file])
+      grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+    fi
+  done
+  rm -rf conftest.dir
+
+  AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+  AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/ax_check_opencl.m4])
+m4_include([m4/ax_check_openmp.m4])
+m4_include([m4/ax_detect_git_head.m4])
+m4_include([m4/ax_submodule.m4])
+m4_include([m4/libtool.m4])
+m4_include([m4/ltoptions.m4])
+m4_include([m4/ltsugar.m4])
+m4_include([m4/ltversion.m4])
+m4_include([m4/lt~obsolete.m4])
diff --git a/final/lib/External/ppcg/compile b/final/lib/External/ppcg/compile
new file mode 100755
index 0000000..531136b
--- /dev/null
+++ b/final/lib/External/ppcg/compile
@@ -0,0 +1,347 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2012-10-14.11; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" ""	$nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+  file=$1
+  case $file in
+    / | /[!/]*) # absolute file, and not a UNC file
+      if test -z "$file_conv"; then
+	# lazily determine how to convert abs files
+	case `uname -s` in
+	  MINGW*)
+	    file_conv=mingw
+	    ;;
+	  CYGWIN*)
+	    file_conv=cygwin
+	    ;;
+	  *)
+	    file_conv=wine
+	    ;;
+	esac
+      fi
+      case $file_conv/,$2, in
+	*,$file_conv,*)
+	  ;;
+	mingw/*)
+	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+	  ;;
+	cygwin/*)
+	  file=`cygpath -m "$file" || echo "$file"`
+	  ;;
+	wine/*)
+	  file=`winepath -w "$file" || echo "$file"`
+	  ;;
+      esac
+      ;;
+  esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+  func_file_conv "$1"
+  if test -z "$lib_path"; then
+    lib_path=$file
+  else
+    lib_path="$lib_path;$file"
+  fi
+  linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+  lib=$1
+  found=no
+  save_IFS=$IFS
+  IFS=';'
+  for dir in $lib_path $LIB
+  do
+    IFS=$save_IFS
+    if $shared && test -f "$dir/$lib.dll.lib"; then
+      found=yes
+      lib=$dir/$lib.dll.lib
+      break
+    fi
+    if test -f "$dir/$lib.lib"; then
+      found=yes
+      lib=$dir/$lib.lib
+      break
+    fi
+    if test -f "$dir/lib$lib.a"; then
+      found=yes
+      lib=$dir/lib$lib.a
+      break
+    fi
+  done
+  IFS=$save_IFS
+
+  if test "$found" != yes; then
+    lib=$lib.lib
+  fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+  # Assume a capable shell
+  lib_path=
+  shared=:
+  linker_opts=
+  for arg
+  do
+    if test -n "$eat"; then
+      eat=
+    else
+      case $1 in
+	-o)
+	  # configure might choose to run compile as 'compile cc -o foo foo.c'.
+	  eat=1
+	  case $2 in
+	    *.o | *.[oO][bB][jJ])
+	      func_file_conv "$2"
+	      set x "$@" -Fo"$file"
+	      shift
+	      ;;
+	    *)
+	      func_file_conv "$2"
+	      set x "$@" -Fe"$file"
+	      shift
+	      ;;
+	  esac
+	  ;;
+	-I)
+	  eat=1
+	  func_file_conv "$2" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-I*)
+	  func_file_conv "${1#-I}" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-l)
+	  eat=1
+	  func_cl_dashl "$2"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-l*)
+	  func_cl_dashl "${1#-l}"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-L)
+	  eat=1
+	  func_cl_dashL "$2"
+	  ;;
+	-L*)
+	  func_cl_dashL "${1#-L}"
+	  ;;
+	-static)
+	  shared=false
+	  ;;
+	-Wl,*)
+	  arg=${1#-Wl,}
+	  save_ifs="$IFS"; IFS=','
+	  for flag in $arg; do
+	    IFS="$save_ifs"
+	    linker_opts="$linker_opts $flag"
+	  done
+	  IFS="$save_ifs"
+	  ;;
+	-Xlinker)
+	  eat=1
+	  linker_opts="$linker_opts $2"
+	  ;;
+	-*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+	*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+	  func_file_conv "$1"
+	  set x "$@" -Tp"$file"
+	  shift
+	  ;;
+	*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+	  func_file_conv "$1" mingw
+	  set x "$@" "$file"
+	  shift
+	  ;;
+	*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+      esac
+    fi
+    shift
+  done
+  if test -n "$linker_opts"; then
+    linker_opts="-link$linker_opts"
+  fi
+  exec "$@" $linker_opts
+  exit 1
+}
+
+eat=
+
+case $1 in
+  '')
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit $?
+    ;;
+  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+    func_cl_wrapper "$@"      # Doesn't return...
+    ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+	# configure might choose to run compile as 'compile cc -o foo foo.c'.
+	# So we strip '-o arg' only if arg is an object.
+	eat=1
+	case $2 in
+	  *.o | *.obj)
+	    ofile=$2
+	    ;;
+	  *)
+	    set x "$@" -o "$2"
+	    shift
+	    ;;
+	esac
+	;;
+      *.c)
+	cfile=$1
+	set x "$@" "$1"
+	shift
+	;;
+      *)
+	set x "$@" "$1"
+	shift
+	;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no '-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # '.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/final/lib/External/ppcg/config.guess b/final/lib/External/ppcg/config.guess
new file mode 100644
index 0000000..d622a44
--- /dev/null
+++ b/final/lib/External/ppcg/config.guess
@@ -0,0 +1,1530 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+#   2011, 2012 Free Software Foundation, Inc.
+
+timestamp='2012-02-10'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner.  Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+		os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+	exitcode=$?
+	trap '' 0
+	exit $exitcode ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+	echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+	echo m68k-milan-mint${UNAME_RELEASE}
+	exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+	echo m68k-hades-mint${UNAME_RELEASE}
+	exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+	echo m68k-unknown-mint${UNAME_RELEASE}
+	exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+	# DG/UX returns AViiON for all architectures
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[4567])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+		    case "${sc_cpu_version}" in
+		      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+		      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+		      532)                      # CPU_PA_RISC2_0
+			case "${sc_kernel_bits}" in
+			  32) HP_ARCH="hppa2.0n" ;;
+			  64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+			esac ;;
+		    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^		//' << EOF >$dummy.c
+
+		#define _HPUX_SOURCE
+		#include <stdlib.h>
+		#include <unistd.h>
+
+		int main ()
+		{
+		#if defined(_SC_KERNEL_BITS)
+		    long bits = sysconf(_SC_KERNEL_BITS);
+		#endif
+		    long cpu  = sysconf (_SC_CPU_VERSION);
+
+		    switch (cpu)
+			{
+			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+			case CPU_PA_RISC2_0:
+		#if defined(_SC_KERNEL_BITS)
+			    switch (bits)
+				{
+				case 64: puts ("hppa2.0w"); break;
+				case 32: puts ("hppa2.0n"); break;
+				default: puts ("hppa2.0"); break;
+				} break;
+		#else  /* !defined(_SC_KERNEL_BITS) */
+			    puts ("hppa2.0"); break;
+		#endif
+			default: puts ("hppa1.0"); break;
+			}
+		    exit (0);
+		}
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+	exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+	exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+	exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+	exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    5000:UNIX_System_V:4.*:*)
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	case ${UNAME_PROCESSOR} in
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:MSYS*:*)
+	echo ${UNAME_MACHINE}-pc-msys
+	exit ;;
+    i*:windows32*:*)
+	# uname -m includes "-pc" on this system.
+	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:*)
+	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    aarch64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    aarch64_be:Linux:*:*)
+	UNAME_MACHINE=aarch64_be
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+	esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+		| grep -q __ARM_PCS_VFP
+	    then
+		echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	    else
+		echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
+	    fi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    hexagon:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	LIBC=gnu
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-gnu
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    tile*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+	# Unixware is an offshoot of SVR4, but it has its own version
+	# number series starting with 2...
+	# I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+	# Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+	# uname -m prints for DJGPP always 'pc', but it prints nothing about
+	# the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+	exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+			# says <Richard.M.Bartel@ccMail.Census.GOV>
+	echo i586-unisys-sysv4
+	exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+		echo mips-nec-sysv${UNAME_RELEASE}
+	else
+		echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+	exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    i386)
+		eval $set_cc_for_build
+		if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+		  if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		      (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		      grep IS_64BIT_ARCH >/dev/null
+		  then
+		      UNAME_PROCESSOR="x86_64"
+		  fi
+		fi ;;
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+	echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+    x86_64:VMkernel:*:*)
+	echo ${UNAME_MACHINE}-unknown-esx
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+	"4"
+#else
+	""
+#endif
+	); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/final/lib/External/ppcg/config.sub b/final/lib/External/ppcg/config.sub
new file mode 100644
index 0000000..6205f84
--- /dev/null
+++ b/final/lib/External/ppcg/config.sub
@@ -0,0 +1,1782 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+#   2011, 2012 Free Software Foundation, Inc.
+
+timestamp='2012-04-18'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray | -microblaze)
+		os=
+		basic_machine=$1
+		;;
+	-bluegene*)
+		os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+	-chorusrdb)
+		os=-chorusrdb
+		basic_machine=$1
+		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*178)
+		os=-lynxos178
+		;;
+	-lynx*5)
+		os=-lynxos5
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| aarch64 | aarch64_be \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+        | be32 | be64 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| epiphany \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| hexagon \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| le32 | le64 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nds32 | nds32le | nds32be \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| open8 \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle \
+	| pyramid \
+	| rl78 | rx \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu \
+	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+	| ubicom32 \
+	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+	| we32k \
+	| x86 | xc16x | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	c54x)
+		basic_machine=tic54x-unknown
+		;;
+	c55x)
+		basic_machine=tic55x-unknown
+		;;
+	c6x)
+		basic_machine=tic6x-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	strongarm | thumb | xscale)
+		basic_machine=arm-unknown
+		;;
+	xgate)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	xscaleeb)
+		basic_machine=armeb-unknown
+		;;
+
+	xscaleel)
+		basic_machine=armel-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| aarch64-* | aarch64_be-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| be32-* | be64-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| hexagon-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| le32-* | le64-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nds32-* | nds32le-* | nds32be-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| open8-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+	| pyramid-* \
+	| rl78-* | romp-* | rs6000-* | rx-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+	| tahoe-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tile*-* \
+	| tron-* \
+	| ubicom32-* \
+	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+	| vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c54x-*)
+		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c55x-*)
+		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c6x-*)
+		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16 | cr16-*)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	microblaze)
+		basic_machine=microblaze-xilinx
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	msys)
+		basic_machine=i386-pc
+		os=-msys
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	nacl)
+		basic_machine=le32-unknown
+		os=-nacl
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	neo-tandem)
+		basic_machine=neo-tandem
+		;;
+	nse-tandem)
+		basic_machine=nse-tandem
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc | ppcbe)	basic_machine=powerpc-unknown
+		;;
+	ppc-* | ppcbe-*)
+		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	strongarm-* | thumb-*)
+		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tile*)
+		basic_machine=$basic_machine-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	xscale-* | xscalee[bl]-*)
+		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+	# First match some system type aliases
+	# that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-auroraux)
+		os=-auroraux
+		;;
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+	      | -sym* | -kopensolaris* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-android* \
+	      | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+	-os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+	-tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-nacl*)
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	score-*)
+		os=-elf
+		;;
+	spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+	c4x-* | tic4x-*)
+		os=-coff
+		;;
+	hexagon-*)
+		os=-elf
+		;;
+	tic54x-*)
+		os=-coff
+		;;
+	tic55x-*)
+		os=-coff
+		;;
+	tic6x-*)
+		os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+	mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/final/lib/External/ppcg/configure b/final/lib/External/ppcg/configure
new file mode 100755
index 0000000..bedcabf
--- /dev/null
+++ b/final/lib/External/ppcg/configure
@@ -0,0 +1,14613 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for ppcg 0.04.
+#
+# Report bugs to <isl-development@googlegroups.com>.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+
+  test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org and
+$0: isl-development@googlegroups.com about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='ppcg'
+PACKAGE_TARNAME='ppcg'
+PACKAGE_VERSION='0.04'
+PACKAGE_STRING='ppcg 0.04'
+PACKAGE_BUGREPORT='isl-development@googlegroups.com'
+PACKAGE_URL=''
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+enable_option_checking=no
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+subdirs
+GIT_HEAD_VERSION
+GIT_HEAD
+GIT_HEAD_ID
+extra_tests
+POLYBENCH_DIR
+PET_LIBS
+PET_CFLAGS
+BUNDLED_PET_FALSE
+BUNDLED_PET_TRUE
+ISL_LIBS
+ISL_CFLAGS
+BUNDLED_ISL_FALSE
+BUNDLED_ISL_TRUE
+HAVE_OPENCL
+HAVE_OPENMP
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
+CPP
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+MANIFEST_TOOL
+RANLIB
+ac_ct_AR
+AR
+DLLTOOL
+OBJDUMP
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+EGREP
+GREP
+SED
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+LIBTOOL
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_dependency_tracking
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_gnu_ld
+with_sysroot
+enable_libtool_lock
+with_isl
+with_isl_prefix
+with_isl_exec_prefix
+with_isl_builddir
+with_pet
+with_pet_prefix
+with_pet_exec_prefix
+with_polybench
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+ISL_CFLAGS
+ISL_LIBS
+PET_CFLAGS
+PET_LIBS'
+ac_subdirs_all='isl
+pet'
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures ppcg 0.04 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/ppcg]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of ppcg 0.04:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-silent-rules   less verbose build output (undo: "make V=1")
+  --disable-silent-rules  verbose build output (undo: "make V=0")
+  --enable-dependency-tracking
+                          do not reject slow dependency extractors
+  --disable-dependency-tracking
+                          speeds up one-time build
+  --enable-shared[=PKGS]  build shared libraries [default=yes]
+  --enable-static[=PKGS]  build static libraries [default=yes]
+  --enable-fast-install[=PKGS]
+                          optimize for fast installation [default=yes]
+  --disable-libtool-lock  avoid locking (might break parallel builds)
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-pic[=PKGS]       try to use only PIC/non-PIC objects [default=use
+                          both]
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-sysroot=DIR Search for dependent libraries within DIR
+                        (or the compiler's sysroot if not specified).
+  --with-isl=build|bundled|system
+                          Which isl to use [default=bundled]
+  --with-isl-prefix=DIR   Prefix of isl installation
+  --with-isl-exec-prefix=DIR
+                          Exec prefix of isl installation
+  --with-isl-builddir=DIR Location of isl builddir
+  --with-pet=bundled|system
+                          Which pet to use [default=bundled]
+  --with-pet-prefix=DIR   Prefix of pet installation
+  --with-pet-exec-prefix=DIR
+                          Exec prefix of pet installation
+  --with-polybench=DIR    PolyBench location
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
+  ISL_CFLAGS  C compiler flags for ISL, overriding pkg-config
+  ISL_LIBS    linker flags for ISL, overriding pkg-config
+  PET_CFLAGS  C compiler flags for PET, overriding pkg-config
+  PET_LIBS    linker flags for PET, overriding pkg-config
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <isl-development@googlegroups.com>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+ppcg configure 0.04
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ----------------------------------------------- ##
+## Report this to isl-development@googlegroups.com ##
+## ----------------------------------------------- ##"
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by ppcg $as_me 0.04, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_aux_dir=
+for ac_dir in . "$srcdir"/.; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in . \"$srcdir\"/." "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+
+am__api_version='1.15'
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[\\\"\#\$\&\'\`$am_lf]*)
+    as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+  *[\\\"\#\$\&\'\`$am_lf\ \	]*)
+    as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$*" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$*" != "X $srcdir/configure conftest.file" \
+	&& test "$*" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	as_fn_error $? "ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment" "$LINENO" 5
+     fi
+     if test "$2" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$2" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+  program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if ${ac_cv_path_mkdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in mkdir gmkdir; do
+	 for ac_exec_ext in '' $ac_executable_extensions; do
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+	     'mkdir (GNU coreutils) '* | \
+	     'mkdir (coreutils) '* | \
+	     'mkdir (fileutils) '4.1*)
+	       ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+	       break 3;;
+	   esac
+	 done
+       done
+  done
+IFS=$as_save_IFS
+
+fi
+
+  test -d ./--version && rmdir ./--version
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    MKDIR_P="$ac_install_sh -d"
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  am__isrc=' -I$(srcdir)'
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='ppcg'
+ VERSION='0.04'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
+# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar  pax cpio none'
+
+am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+
+
+
+
+
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+  fi
+fi
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=0;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+   ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+  enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+case `pwd` in
+  *\ * | *\	*)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.2'
+macro_revision='1.3337'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO ""
+}
+
+case "$ECHO" in
+  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+   then ac_cv_path_FGREP="$GREP -F"
+   else
+     if test -z "$FGREP"; then
+  ac_path_FGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in fgrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+  # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'FGREP' >> "conftest.nl"
+    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_FGREP="$ac_path_FGREP"
+      ac_path_FGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_FGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_FGREP"; then
+    as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_FGREP=$FGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in dumpbin "link -dump"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DUMPBIN"; then
+  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$DUMPBIN" && break
+  done
+fi
+if test -z "$DUMPBIN"; then
+  ac_ct_DUMPBIN=$DUMPBIN
+  for ac_prog in dumpbin "link -dump"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DUMPBIN"; then
+  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_DUMPBIN" && break
+done
+
+  if test "x$ac_ct_DUMPBIN" = x; then
+    DUMPBIN=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DUMPBIN=$ac_ct_DUMPBIN
+  fi
+fi
+
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+  cat conftest.out >&5
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+    i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[	 ]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len" && \
+	test undefined != "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,b/c, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
+if ${lt_cv_to_host_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+
+fi
+
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
+if ${lt_cv_to_tool_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  #assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+
+fi
+
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test "$GCC" != yes; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJDUMP"; then
+  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+  ac_ct_OBJDUMP=$OBJDUMP
+  # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJDUMP"; then
+  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OBJDUMP="objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJDUMP" = x; then
+    OBJDUMP="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OBJDUMP=$ac_ct_OBJDUMP
+  fi
+else
+  OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[45]*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[3-9]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd* | netbsdelf*-gnu)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+  ac_ct_DLLTOOL=$DLLTOOL
+  # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DLLTOOL"; then
+  ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DLLTOOL" = x; then
+    DLLTOOL="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DLLTOOL=$ac_ct_DLLTOOL
+  fi
+else
+  DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in ar
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$AR" && break
+  done
+fi
+if test -z "$AR"; then
+  ac_ct_AR=$AR
+  for ac_prog in ar
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_AR" && break
+done
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+fi
+
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+$as_echo_n "checking for archiver @FILE support... " >&6; }
+if ${lt_cv_ar_at_file+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ar_at_file=no
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
+      { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+      if test "$ac_status" -eq 0; then
+	# Ensure the archiver fails upon bogus file names.
+	rm -f conftest.$ac_objext libconftest.a
+	{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	if test "$ac_status" -ne 0; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+$as_echo "$lt_cv_ar_at_file" >&6; }
+
+if test "x$lt_cv_ar_at_file" = xno; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[BCDT]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[ABCDGISTW]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[ABCDEGRST]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[BCDEGRST]'
+  ;;
+osf*)
+  symcode='[BCDEGQRST]'
+  ;;
+solaris*)
+  symcode='[BDRT]'
+  ;;
+sco3.2v5*)
+  symcode='[DT]'
+  ;;
+sysv4.2uw2*)
+  symcode='[DT]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[ABDT]'
+  ;;
+sysv4)
+  symcode='[DFNSTU]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK '"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[	 ]\($symcode$symcode*\)[	 ][	 ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+  (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_globsym_save_LIBS=$LIBS
+	  lt_globsym_save_CFLAGS=$CFLAGS
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS=$lt_globsym_save_LIBS
+	  CFLAGS=$lt_globsym_save_CFLAGS
+	else
+	  echo "cannot find nm_test_func in $nlist" >&5
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&5
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+    fi
+  else
+    echo "$progname: failed program was:" >&5
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+$as_echo_n "checking for sysroot... " >&6; }
+
+# Check whether --with-sysroot was given.
+if test "${with_sysroot+set}" = set; then :
+  withval=$with_sysroot;
+else
+  with_sysroot=no
+fi
+
+
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+   if test "$GCC" = yes; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5
+$as_echo "${with_sysroot}" >&6; }
+   as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
+   ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+$as_echo "${lt_sysroot:-no}" >&6; }
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+  enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE="32"
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE="64"
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    case `/usr/bin/file conftest.o` in
+	      *x86-64*)
+		LD="${LD-ld} -m elf32_x86_64"
+		;;
+	      *)
+		LD="${LD-ld} -m elf_i386"
+		;;
+	    esac
+	    ;;
+	  ppc64-*linux*|powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  ppc*-*linux*|powerpc*-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_cc_needs_belf=yes
+else
+  lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+     ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD="${LD-ld}_sol2"
+        fi
+        ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$MANIFEST_TOOL"; then
+  ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
+if test -n "$MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+$as_echo "$MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
+  ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
+  # Extract the first word of "mt", so it can be a program name with args.
+set dummy mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_MANIFEST_TOOL"; then
+  ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
+if test -n "$ac_ct_MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_MANIFEST_TOOL" = x; then
+    MANIFEST_TOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
+  fi
+else
+  MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
+fi
+
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if ${lt_cv_path_mainfest_tool+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&5
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+  MANIFEST_TOOL=:
+fi
+
+
+
+
+
+
+  case $host_os in
+    rhapsody* | darwin*)
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DSYMUTIL"; then
+  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+  ac_ct_DSYMUTIL=$DSYMUTIL
+  # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DSYMUTIL"; then
+  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DSYMUTIL" = x; then
+    DSYMUTIL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DSYMUTIL=$ac_ct_DSYMUTIL
+  fi
+else
+  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NMEDIT"; then
+  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+  ac_ct_NMEDIT=$NMEDIT
+  # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_NMEDIT"; then
+  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_NMEDIT="nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_NMEDIT" = x; then
+    NMEDIT=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    NMEDIT=$ac_ct_NMEDIT
+  fi
+else
+  NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LIPO"; then
+  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+  ac_ct_LIPO=$LIPO
+  # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_LIPO"; then
+  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_LIPO="lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_LIPO" = x; then
+    LIPO=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    LIPO=$ac_ct_LIPO
+  fi
+else
+  LIPO="$ac_cv_prog_LIPO"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL"; then
+  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+  ac_ct_OTOOL=$OTOOL
+  # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL"; then
+  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL="otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL" = x; then
+    OTOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL=$ac_ct_OTOOL
+  fi
+else
+  OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL64"; then
+  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+  ac_ct_OTOOL64=$OTOOL64
+  # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL64"; then
+  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL64="otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL64" = x; then
+    OTOOL64=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL64=$ac_ct_OTOOL64
+  fi
+else
+  OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	# If there is a non-empty error log, and "single_module"
+	# appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+	  cat conftest.err >&5
+	# Otherwise, if the output was created with a 0 exit code from
+	# the compiler, it worked.
+	elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&5
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_ld_exported_symbols_list=yes
+else
+  lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+      echo "$AR cru libconftest.a conftest.o" >&5
+      $AR cru libconftest.a conftest.o 2>&5
+      echo "$RANLIB libconftest.a" >&5
+      $RANLIB libconftest.a 2>&5
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+	cat conftest.err >&5
+      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&5
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+    case $host_os in
+    rhapsody* | darwin1.[012])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	10.[012]*)
+	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dlfcn.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+# Set options
+
+
+
+        enable_dlopen=no
+
+
+  enable_win32_dll=no
+
+
+            # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+  enableval=$enable_shared; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+  # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+  enableval=$enable_static; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+  withval=$with_pic; lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for lt_pkg in $withval; do
+	IFS="$lt_save_ifs"
+	if test "X$lt_pkg" = "X$lt_p"; then
+	  pic_mode=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+  # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+  enableval=$enable_fast_install; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/${ac_tool_prefix}file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  else
+    MAGIC_CMD=:
+  fi
+fi
+
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+  *)
+    lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+  esac
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_rtti_exceptions=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="-fno-rtti -fno-exceptions"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_rtti_exceptions=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+    lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+    :
+fi
+
+fi
+
+
+
+
+
+
+  lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+
+  if test "$GCC" = yes; then
+    lt_prog_compiler_wl='-Wl,'
+    lt_prog_compiler_static='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      lt_prog_compiler_pic='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      lt_prog_compiler_wl='-Xlinker '
+      if test -n "$lt_prog_compiler_pic"; then
+        lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      else
+	lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-KPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='--shared'
+	lt_prog_compiler_static='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	lt_prog_compiler_wl='-Wl,-Wl,,'
+	lt_prog_compiler_pic='-PIC'
+	lt_prog_compiler_static='-Bstatic'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fpic'
+	lt_prog_compiler_static='-Bstatic'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-qpic'
+	lt_prog_compiler_static='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Wl,'
+	  ;;
+        *Intel*\ [CF]*Compiler*)
+	  lt_prog_compiler_wl='-Wl,'
+	  lt_prog_compiler_pic='-fPIC'
+	  lt_prog_compiler_static='-static'
+	  ;;
+	*Portland\ Group*)
+	  lt_prog_compiler_wl='-Wl,'
+	  lt_prog_compiler_pic='-fpic'
+	  lt_prog_compiler_static='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    rdos*)
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	lt_prog_compiler_wl='-Qoption ld ';;
+      *)
+	lt_prog_compiler_wl='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl='-Qoption ld '
+      lt_prog_compiler_pic='-PIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	lt_prog_compiler_pic='-Kconform_pic'
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    unicos*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_can_build_shared=no
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic='-pic'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared=no
+      ;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic=
+    ;;
+  *)
+    lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+    ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+    case $lt_prog_compiler_pic in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+     esac
+else
+    lt_prog_compiler_pic=
+     lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+    :
+else
+    lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test "$hard_links" = no; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  runpath_var=
+  allow_undefined_flag=
+  always_export_symbols=no
+  archive_cmds=
+  archive_expsym_cmds=
+  compiler_needs_object=no
+  enable_shared_with_static_runtimes=no
+  export_dynamic_flag_spec=
+  export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  hardcode_automatic=no
+  hardcode_direct=no
+  hardcode_direct_absolute=no
+  hardcode_libdir_flag_spec=
+  hardcode_libdir_separator=
+  hardcode_minus_L=no
+  hardcode_shlibpath_var=unsupported
+  inherit_rpath=no
+  link_all_deplibs=unknown
+  module_cmds=
+  module_expsym_cmds=
+  old_archive_from_new_cmds=
+  old_archive_from_expsyms_cmds=
+  thread_safe_flag_spec=
+  whole_archive_flag_spec=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  linux* | k*bsd*-gnu | gnu*)
+    link_all_deplibs=no
+    ;;
+  esac
+
+  ld_shlibs=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+	  *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+    export_dynamic_flag_spec='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      whole_archive_flag_spec=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[3-9]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	allow_undefined_flag=unsupported
+	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      export_dynamic_flag_spec='${wl}--export-all-symbols'
+      allow_undefined_flag=unsupported
+      always_export_symbols=no
+      enable_shared_with_static_runtimes=yes
+      export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+      exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    haiku*)
+      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      link_all_deplibs=yes
+      ;;
+
+    interix[3-9]*)
+      hardcode_direct=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+      export_dynamic_flag_spec='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  whole_archive_flag_spec=
+	  tmp_sharedflag='--shared' ;;
+	xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+	  hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+	  archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        ld_shlibs=no
+      fi
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+	    archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    ld_shlibs=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+    esac
+
+    if test "$ld_shlibs" = no; then
+      runpath_var=
+      hardcode_libdir_flag_spec=
+      export_dynamic_flag_spec=
+      whole_archive_flag_spec=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag=unsupported
+      always_export_symbols=yes
+      archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	hardcode_direct=unsupported
+      fi
+      ;;
+
+    aix[4-9]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	# Also, AIX nm treats weak defined symbols like other global
+	# defined symbols, whereas GNU nm marks them as "W".
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds=''
+      hardcode_direct=yes
+      hardcode_direct_absolute=yes
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      file_list_spec='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[012]|aix4.[012].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  hardcode_direct=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  hardcode_minus_L=yes
+	  hardcode_libdir_flag_spec='-L$libdir'
+	  hardcode_libdir_separator=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+	link_all_deplibs=no
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      export_dynamic_flag_spec='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	allow_undefined_flag='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+	  allow_undefined_flag="-z nodefs"
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+	 hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  no_undefined_flag=' ${wl}-bernotok'
+	  allow_undefined_flag=' ${wl}-berok'
+	  if test "$with_gnu_ld" = yes; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    whole_archive_flag_spec='$convenience'
+	  fi
+	  archive_cmds_need_lc=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[45]*)
+      export_dynamic_flag_spec=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	hardcode_libdir_flag_spec=' '
+	allow_undefined_flag=unsupported
+	always_export_symbols=yes
+	file_list_spec='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	    sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	  else
+	    sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	  fi~
+	  $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	  linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, )='true'
+	enable_shared_with_static_runtimes=yes
+	exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	old_postinstall_cmds='chmod 644 $oldlib'
+	postlink_cmds='lt_outputfile="@OUTPUT@"~
+	  lt_tool_outputfile="@TOOL_OUTPUT@"~
+	  case $lt_outputfile in
+	    *.exe|*.EXE) ;;
+	    *)
+	      lt_outputfile="$lt_outputfile.exe"
+	      lt_tool_outputfile="$lt_tool_outputfile.exe"
+	      ;;
+	  esac~
+	  if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	    $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	    $RM "$lt_outputfile.manifest";
+	  fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	hardcode_libdir_flag_spec=' '
+	allow_undefined_flag=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	old_archive_from_new_cmds='true'
+	# FIXME: Should let the user specify the lib program.
+	old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	enable_shared_with_static_runtimes=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc=no
+  hardcode_direct=no
+  hardcode_automatic=yes
+  hardcode_shlibpath_var=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+  else
+    whole_archive_flag_spec=''
+  fi
+  link_all_deplibs=yes
+  allow_undefined_flag="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+  else
+  ld_shlibs=no
+  fi
+
+      ;;
+
+    dgux*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      export_dynamic_flag_spec='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator=:
+	hardcode_direct=yes
+	hardcode_direct_absolute=yes
+	export_dynamic_flag_spec='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	hardcode_minus_L=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler__b=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS -b"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler__b=yes
+       fi
+     else
+       lt_cv_prog_compiler__b=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+    archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+    archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  hardcode_direct=no
+	  hardcode_shlibpath_var=no
+	  ;;
+	*)
+	  hardcode_direct=yes
+	  hardcode_direct_absolute=yes
+	  export_dynamic_flag_spec='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  save_LDFLAGS="$LDFLAGS"
+	   LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+	   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int foo (void) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_irix_exported_symbol=yes
+else
+  lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+           LDFLAGS="$save_LDFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+	if test "$lt_cv_irix_exported_symbol" = yes; then
+          archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+	fi
+      else
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      inherit_rpath=yes
+      link_all_deplibs=yes
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    newsos6)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_shlibpath_var=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	hardcode_direct=yes
+	hardcode_shlibpath_var=no
+	hardcode_direct_absolute=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	  export_dynamic_flag_spec='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+	     archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     hardcode_libdir_flag_spec='-R$libdir'
+	     ;;
+	   *)
+	     archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_separator=:
+      ;;
+
+    solaris*)
+      no_undefined_flag=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_shlibpath_var=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      link_all_deplibs=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  reload_cmds='$CC -r -o $output$reload_objs'
+	  hardcode_direct=no
+        ;;
+	motorola)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var=no
+      export_dynamic_flag_spec='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	hardcode_shlibpath_var=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	ld_shlibs=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag='${wl}-z,text'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      no_undefined_flag='${wl}-z,text'
+      allow_undefined_flag='${wl}-z,nodefs'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-R,$libdir'
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      export_dynamic_flag_spec='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      ld_shlibs=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	export_dynamic_flag_spec='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$lt_prog_compiler_wl
+	  pic_flag=$lt_prog_compiler_pic
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$allow_undefined_flag
+	  allow_undefined_flag=
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	  then
+	    lt_cv_archive_cmds_need_lc=no
+	  else
+	    lt_cv_archive_cmds_need_lc=yes
+	  fi
+	  allow_undefined_flag=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+      archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[lt_foo]++; }
+  if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[23].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[3-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+	 LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+  lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsdelf*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='NetBSD ld.elf_so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+   test -n "$runpath_var" ||
+   test "X$hardcode_automatic" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$hardcode_direct" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+     test "$hardcode_minus_L" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+   test "$inherit_rpath" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+  if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+
+fi
+
+    ;;
+
+  *)
+    ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+  lt_cv_dlopen="shl_load"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_shl_load=yes
+else
+  ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+  ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_svld_dlopen=yes
+else
+  ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_dld_link=yes
+else
+  ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self_static=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self_static=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    fi
+    ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+  # Report which library types will actually be built
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[4-9]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.9.0
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
+
+
+	HAVE_OPENMP=no
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenMP support by $CC" >&5
+$as_echo_n "checking for OpenMP support by $CC... " >&6; }
+	echo | $CC -x c - -fsyntax-only -fopenmp -Werror >/dev/null 2>/dev/null
+	if test $? -eq 0; then
+		HAVE_OPENMP=yes
+	fi
+
+
+
+	HAVE_OPENCL=no
+	ac_fn_c_check_header_mongrel "$LINENO" "CL/opencl.h" "ac_cv_header_CL_opencl_h" "$ac_includes_default"
+if test "x$ac_cv_header_CL_opencl_h" = xyes; then :
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clGetPlatformIDs in -lOpenCL" >&5
+$as_echo_n "checking for clGetPlatformIDs in -lOpenCL... " >&6; }
+if ${ac_cv_lib_OpenCL_clGetPlatformIDs+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lOpenCL  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clGetPlatformIDs ();
+int
+main ()
+{
+return clGetPlatformIDs ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_OpenCL_clGetPlatformIDs=yes
+else
+  ac_cv_lib_OpenCL_clGetPlatformIDs=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_OpenCL_clGetPlatformIDs" >&5
+$as_echo "$ac_cv_lib_OpenCL_clGetPlatformIDs" >&6; }
+if test "x$ac_cv_lib_OpenCL_clGetPlatformIDs" = xyes; then :
+
+			SAVE_LIBS=$LIBS
+			LIBS="$LIBS -lOpenCL"
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenCL CPU device" >&5
+$as_echo_n "checking for OpenCL CPU device... " >&6; }
+			if test "$cross_compiling" = yes; then :
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run test program while cross compiling
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <CL/opencl.h>
+int
+main ()
+{
+
+	cl_platform_id platform;
+	cl_device_id dev;
+
+	if (clGetPlatformIDs(1, &platform, NULL) < 0)
+		return 1;
+	if (clGetDeviceIDs(platform, CL_DEVICE_TYPE_CPU, 1, &dev, NULL) < 0)
+		return 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  HAVE_OPENCL=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_OPENCL" >&5
+$as_echo "$HAVE_OPENCL" >&6; }
+			LIBS=$SAVE_LIBS
+
+fi
+
+fi
+
+
+
+if test $HAVE_OPENCL = yes; then
+	extra_tests="$extra_tests opencl_test.sh"
+fi
+
+
+
+
+
+# Check whether --with-isl was given.
+if test "${with_isl+set}" = set; then :
+  withval=$with_isl;
+fi
+
+case "system" in
+build|bundled|system)
+
+# Check whether --with-isl_prefix was given.
+if test "${with_isl_prefix+set}" = set; then :
+  withval=$with_isl_prefix;
+fi
+
+
+# Check whether --with-isl_exec_prefix was given.
+if test "${with_isl_exec_prefix+set}" = set; then :
+  withval=$with_isl_exec_prefix;
+fi
+
+esac
+
+# Check whether --with-isl_builddir was given.
+if test "${with_isl_builddir+set}" = set; then :
+  withval=$with_isl_builddir;
+fi
+
+if test "x$with_isl_prefix" != "x" -a "x$with_isl_exec_prefix" = "x"; then
+	with_isl_exec_prefix=$with_isl_prefix
+fi
+if test "x$with_isl_prefix" != "x" -o "x$with_isl_exec_prefix" != "x"; then
+	if test "x$with_isl" != "x" -a "x$with_isl" != "xsystem"; then
+		as_fn_error $? "Setting $with_isl_prefix implies use of system isl" "$LINENO" 5
+	fi
+	with_isl="system"
+fi
+if test "x$with_isl_builddir" != "x"; then
+	if test "x$with_isl" != "x" -a "x$with_isl" != "xbuild"; then
+		as_fn_error $? "Setting $with_isl_builddir implies use of build isl" "$LINENO" 5
+	fi
+	with_isl="build"
+	isl_srcdir=`echo @abs_srcdir@ | $with_isl_builddir/config.status --file=-`
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: isl sources in $isl_srcdir" >&5
+$as_echo "$as_me: isl sources in $isl_srcdir" >&6;}
+fi
+if test "x$with_isl_exec_prefix" != "x"; then
+	export PKG_CONFIG_PATH="$with_isl_exec_prefix/lib/pkgconfig${PKG_CONFIG_PATH+:$PKG_CONFIG_PATH}"
+fi
+case "$with_isl" in
+build|bundled|system)
+	;;
+*)
+	case "bundled" in
+	bundled)
+		if test -d $srcdir/.git -a \
+			-d $srcdir/isl -a \
+			"`cd $srcdir; git submodule status isl | cut -c1`" = '-'; then
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: git repo detected, but submodule isl not initialized" >&5
+$as_echo "$as_me: WARNING: git repo detected, but submodule isl not initialized" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You may want to run" >&5
+$as_echo "$as_me: WARNING: You may want to run" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 	git submodule init" >&5
+$as_echo "$as_me: WARNING: 	git submodule init" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 	git submodule update" >&5
+$as_echo "$as_me: WARNING: 	git submodule update" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 	sh autogen.sh" >&5
+$as_echo "$as_me: WARNING: 	sh autogen.sh" >&2;}
+		fi
+		if test -f $srcdir/isl/configure; then
+			with_isl="bundled"
+		else
+			case "system" in
+			build|bundled|system)
+				with_isl="system"
+				;;
+			*)
+				with_isl="no"
+				;;
+			esac
+		fi
+		;;
+	*)
+		with_isl="bundled"
+		;;
+	esac
+	;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which isl to use" >&5
+$as_echo_n "checking which isl to use... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_isl" >&5
+$as_echo "$with_isl" >&6; }
+
+
+
+ if test $with_isl = bundled; then
+  BUNDLED_ISL_TRUE=
+  BUNDLED_ISL_FALSE='#'
+else
+  BUNDLED_ISL_TRUE='#'
+  BUNDLED_ISL_FALSE=
+fi
+
+
+
+
+case "$with_isl" in
+bundled)
+	ISL_CFLAGS="-I\$(top_srcdir)/isl/include -I\$(top_builddir)/isl/include"
+	ISL_CFLAGS="$ISL_CFLAGS"
+	ppcg_configure_args="$ppcg_configure_args --with-isl-builddir=../isl"
+	ppcg_configure_args="$ppcg_configure_args --with-isl=build"
+	;;
+build)
+	ISL_BUILDDIR=`echo @abs_builddir@ | $with_isl_builddir/config.status --file=-`
+	ppcg_configure_args="$ppcg_configure_args --with-isl-builddir=$ISL_BUILDDIR"
+	ISL_CFLAGS="-I$isl_srcdir/include -I$ISL_BUILDDIR/include"
+	ISL_CFLAGS="$ISL_CFLAGS"
+	ISL_LIBS="$with_isl_builddir/libisl.la"
+	;;
+system)
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ISL" >&5
+$as_echo_n "checking for ISL... " >&6; }
+
+if test -n "$ISL_CFLAGS"; then
+    pkg_cv_ISL_CFLAGS="$ISL_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"isl\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "isl") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ISL_CFLAGS=`$PKG_CONFIG --cflags "isl" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$ISL_LIBS"; then
+    pkg_cv_ISL_LIBS="$ISL_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"isl\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "isl") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ISL_LIBS=`$PKG_CONFIG --libs "isl" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        ISL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "isl" 2>&1`
+        else
+	        ISL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "isl" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$ISL_PKG_ERRORS" >&5
+
+	as_fn_error $? "Package requirements (isl) were not met:
+
+$ISL_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables ISL_CFLAGS
+and ISL_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables ISL_CFLAGS
+and ISL_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
+else
+	ISL_CFLAGS=$pkg_cv_ISL_CFLAGS
+	ISL_LIBS=$pkg_cv_ISL_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+esac
+
+
+
+
+
+# Check whether --with-pet was given.
+if test "${with_pet+set}" = set; then :
+  withval=$with_pet;
+fi
+
+case "system" in
+bundled|system)
+
+# Check whether --with-pet_prefix was given.
+if test "${with_pet_prefix+set}" = set; then :
+  withval=$with_pet_prefix;
+fi
+
+
+# Check whether --with-pet_exec_prefix was given.
+if test "${with_pet_exec_prefix+set}" = set; then :
+  withval=$with_pet_exec_prefix;
+fi
+
+esac
+
+if test "x$with_pet_prefix" != "x" -a "x$with_pet_exec_prefix" = "x"; then
+	with_pet_exec_prefix=$with_pet_prefix
+fi
+if test "x$with_pet_prefix" != "x" -o "x$with_pet_exec_prefix" != "x"; then
+	if test "x$with_pet" != "x" -a "x$with_pet" != "xsystem"; then
+		as_fn_error $? "Setting $with_pet_prefix implies use of system pet" "$LINENO" 5
+	fi
+	with_pet="system"
+fi
+if test "x$with_pet_builddir" != "x"; then
+	if test "x$with_pet" != "x" -a "x$with_pet" != "xbuild"; then
+		as_fn_error $? "Setting $with_pet_builddir implies use of build pet" "$LINENO" 5
+	fi
+	with_pet="build"
+	pet_srcdir=`echo @abs_srcdir@ | $with_pet_builddir/config.status --file=-`
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: pet sources in $pet_srcdir" >&5
+$as_echo "$as_me: pet sources in $pet_srcdir" >&6;}
+fi
+if test "x$with_pet_exec_prefix" != "x"; then
+	export PKG_CONFIG_PATH="$with_pet_exec_prefix/lib/pkgconfig${PKG_CONFIG_PATH+:$PKG_CONFIG_PATH}"
+fi
+case "$with_pet" in
+bundled|system)
+	;;
+*)
+	case "bundled" in
+	bundled)
+		if test -d $srcdir/.git -a \
+			-d $srcdir/pet -a \
+			"`cd $srcdir; git submodule status pet | cut -c1`" = '-'; then
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: git repo detected, but submodule pet not initialized" >&5
+$as_echo "$as_me: WARNING: git repo detected, but submodule pet not initialized" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You may want to run" >&5
+$as_echo "$as_me: WARNING: You may want to run" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 	git submodule init" >&5
+$as_echo "$as_me: WARNING: 	git submodule init" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 	git submodule update" >&5
+$as_echo "$as_me: WARNING: 	git submodule update" >&2;}
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 	sh autogen.sh" >&5
+$as_echo "$as_me: WARNING: 	sh autogen.sh" >&2;}
+		fi
+		if test -f $srcdir/pet/configure; then
+			with_pet="bundled"
+		else
+			case "system" in
+			bundled|system)
+				with_pet="system"
+				;;
+			*)
+				with_pet="no"
+				;;
+			esac
+		fi
+		;;
+	*)
+		with_pet="bundled"
+		;;
+	esac
+	;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which pet to use" >&5
+$as_echo_n "checking which pet to use... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_pet" >&5
+$as_echo "$with_pet" >&6; }
+
+
+
+ if test $with_pet = bundled; then
+  BUNDLED_PET_TRUE=
+  BUNDLED_PET_FALSE='#'
+else
+  BUNDLED_PET_TRUE='#'
+  BUNDLED_PET_FALSE=
+fi
+
+
+
+
+case "$with_pet" in
+bundled)
+	PET_CFLAGS="$PET_CFLAGS -I\$(top_srcdir)/pet/include"
+	;;
+system)
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PET" >&5
+$as_echo_n "checking for PET... " >&6; }
+
+if test -n "$PET_CFLAGS"; then
+    pkg_cv_PET_CFLAGS="$PET_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pet\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "pet") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_PET_CFLAGS=`$PKG_CONFIG --cflags "pet" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$PET_LIBS"; then
+    pkg_cv_PET_LIBS="$PET_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pet\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "pet") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_PET_LIBS=`$PKG_CONFIG --libs "pet" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        PET_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "pet" 2>&1`
+        else
+	        PET_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "pet" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$PET_PKG_ERRORS" >&5
+
+	as_fn_error $? "Package requirements (pet) were not met:
+
+$PET_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables PET_CFLAGS
+and PET_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables PET_CFLAGS
+and PET_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
+else
+	PET_CFLAGS=$pkg_cv_PET_CFLAGS
+	PET_LIBS=$pkg_cv_PET_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+	;;
+esac
+
+
+
+
+# Check whether --with-polybench was given.
+if test "${with_polybench+set}" = set; then :
+  withval=$with_polybench;
+	if test -f "$with_polybench/utilities/benchmark_list"; then
+		POLYBENCH_DIR=$with_polybench
+		extra_tests="$extra_tests polybench_test.sh"
+	fi
+
+fi
+
+
+
+
+
+
+	if test -f $srcdir/.git/HEAD; then
+		GIT_HEAD="$srcdir/.git/index"
+		GIT_REPO="$srcdir/.git"
+		GIT_HEAD_ID=`GIT_DIR=$GIT_REPO git describe --always`
+	elif test -f $srcdir/GIT_HEAD_ID; then
+		GIT_HEAD_ID=`cat $srcdir/GIT_HEAD_ID`
+	else
+		mysrcdir=`(cd $srcdir; pwd)`
+		head=`basename $mysrcdir | sed -e 's/.*-//'`
+		head2=`echo $head | sed -e 's/^0-9a-f//'`
+		head3=`echo $head2 | sed -e 's/........................................//'`
+		if test "x$head3" = "x" -a "x$head" = "x$head2"; then
+			GIT_HEAD_ID="$head"
+		else
+			GIT_HEAD_ID="UNKNOWN"
+		fi
+	fi
+	if test -z "$GIT_REPO" ; then
+		GIT_HEAD_VERSION="$GIT_HEAD_ID"
+	else
+		GIT_HEAD_VERSION="\`GIT_DIR=$GIT_REPO git describe --always\`"
+	fi
+
+echo '#define GIT_HEAD_ID "'$GIT_HEAD_ID'"' > gitversion.h
+
+ac_config_files="$ac_config_files Makefile"
+
+ac_config_files="$ac_config_files polybench_test.sh"
+
+ac_config_files="$ac_config_files opencl_test.sh"
+
+if test $with_isl = bundled; then
+
+
+subdirs="$subdirs isl"
+
+fi
+if test $with_pet = bundled; then
+	subdirs="$subdirs pet"
+
+fi
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section.  Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*([^)]*)\)[	 ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[	 `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+	g
+	s/^\n//
+	s/\n/ /g
+	p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+  am__EXEEXT_TRUE=
+  am__EXEEXT_FALSE='#'
+else
+  am__EXEEXT_TRUE='#'
+  am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+  as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUNDLED_ISL_TRUE}" && test -z "${BUNDLED_ISL_FALSE}"; then
+  as_fn_error $? "conditional \"BUNDLED_ISL\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUNDLED_PET_TRUE}" && test -z "${BUNDLED_PET_FALSE}"; then
+  as_fn_error $? "conditional \"BUNDLED_PET\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by ppcg $as_me 0.04, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Configuration commands:
+$config_commands
+
+Report bugs to <isl-development@googlegroups.com>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+ppcg config.status 0.04
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h |  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
+want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
+lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SHELL \
+ECHO \
+PATH_SEPARATOR \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+file_magic_glob \
+want_nocaseglob \
+DLLTOOL \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+archiver_list_spec \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+nm_file_list_spec \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_pic \
+lt_prog_compiler_wl \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+MANIFEST_TOOL \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_separator \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postlink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "polybench_test.sh") CONFIG_FILES="$CONFIG_FILES polybench_test.sh" ;;
+    "opencl_test.sh") CONFIG_FILES="$CONFIG_FILES opencl_test.sh" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X "  :F $CONFIG_FILES      :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+  ac_MKDIR_P=$MKDIR_P
+  case $MKDIR_P in
+  [\\/$]* | ?:[\\/]* ) ;;
+  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$mf" : 'X\(//\)[^/]' \| \
+	 X"$mf" : 'X\(//\)$' \| \
+	 X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$file" : 'X\(//\)[^/]' \| \
+	 X"$file" : 'X\(//\)$' \| \
+	 X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      as_dir=$dirpart/$fdir; as_fn_mkdir_p
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+ ;;
+    "libtool":C)
+
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags=""
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The PATH separator for the build system.
+PATH_SEPARATOR=$lt_PATH_SEPARATOR
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and in which our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+  if test x"$xsi_shell" = xyes; then
+  sed -e '/^func_dirname ()$/,/^} # func_dirname /c\
+func_dirname ()\
+{\
+\    case ${1} in\
+\      */*) func_dirname_result="${1%/*}${2}" ;;\
+\      *  ) func_dirname_result="${3}" ;;\
+\    esac\
+} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_basename ()$/,/^} # func_basename /c\
+func_basename ()\
+{\
+\    func_basename_result="${1##*/}"\
+} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\
+func_dirname_and_basename ()\
+{\
+\    case ${1} in\
+\      */*) func_dirname_result="${1%/*}${2}" ;;\
+\      *  ) func_dirname_result="${3}" ;;\
+\    esac\
+\    func_basename_result="${1##*/}"\
+} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_stripname ()$/,/^} # func_stripname /c\
+func_stripname ()\
+{\
+\    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\
+\    # positional parameters, so assign one to ordinary parameter first.\
+\    func_stripname_result=${3}\
+\    func_stripname_result=${func_stripname_result#"${1}"}\
+\    func_stripname_result=${func_stripname_result%"${2}"}\
+} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\
+func_split_long_opt ()\
+{\
+\    func_split_long_opt_name=${1%%=*}\
+\    func_split_long_opt_arg=${1#*=}\
+} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\
+func_split_short_opt ()\
+{\
+\    func_split_short_opt_arg=${1#??}\
+\    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\
+} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\
+func_lo2o ()\
+{\
+\    case ${1} in\
+\      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\
+\      *)    func_lo2o_result=${1} ;;\
+\    esac\
+} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_xform ()$/,/^} # func_xform /c\
+func_xform ()\
+{\
+    func_xform_result=${1%.*}.lo\
+} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_arith ()$/,/^} # func_arith /c\
+func_arith ()\
+{\
+    func_arith_result=$(( $* ))\
+} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_len ()$/,/^} # func_len /c\
+func_len ()\
+{\
+    func_len_result=${#1}\
+} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+fi
+
+if test x"$lt_shell_append" = xyes; then
+  sed -e '/^func_append ()$/,/^} # func_append /c\
+func_append ()\
+{\
+    eval "${1}+=\\${2}"\
+} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\
+func_append_quoted ()\
+{\
+\    func_quote_for_eval "${2}"\
+\    eval "${1}+=\\\\ \\$func_quote_for_eval_result"\
+} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  # Save a `func_append' function call where possible by direct use of '+='
+  sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+else
+  # Save a `func_append' function call even when '+=' is not available
+  sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5
+$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;}
+fi
+
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+
+ ;;
+    "polybench_test.sh":F) chmod +x polybench_test.sh ;;
+    "opencl_test.sh":F) chmod +x opencl_test.sh ;;
+
+  esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+			ac_configure_args="$ac_configure_args $ppcg_configure_args"
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+
+#
+# CONFIG_SUBDIRS section.
+#
+if test "$no_recursion" != yes; then
+
+  # Remove --cache-file, --srcdir, and --disable-option-checking arguments
+  # so they do not pile up.
+  ac_sub_configure_args=
+  ac_prev=
+  eval "set x $ac_configure_args"
+  shift
+  for ac_arg
+  do
+    if test -n "$ac_prev"; then
+      ac_prev=
+      continue
+    fi
+    case $ac_arg in
+    -cache-file | --cache-file | --cache-fil | --cache-fi \
+    | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+      ac_prev=cache_file ;;
+    -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+    | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \
+    | --c=*)
+      ;;
+    --config-cache | -C)
+      ;;
+    -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+      ac_prev=srcdir ;;
+    -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+      ;;
+    -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+      ac_prev=prefix ;;
+    -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+      ;;
+    --disable-option-checking)
+      ;;
+    *)
+      case $ac_arg in
+      *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+      esac
+      as_fn_append ac_sub_configure_args " '$ac_arg'" ;;
+    esac
+  done
+
+  # Always prepend --prefix to ensure using the same prefix
+  # in subdir configurations.
+  ac_arg="--prefix=$prefix"
+  case $ac_arg in
+  *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+  esac
+  ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args"
+
+  # Pass --silent
+  if test "$silent" = yes; then
+    ac_sub_configure_args="--silent $ac_sub_configure_args"
+  fi
+
+  # Always prepend --disable-option-checking to silence warnings, since
+  # different subdirs can have different --enable and --with options.
+  ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args"
+
+  ac_popdir=`pwd`
+  for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue
+
+    # Do not complain, so a configure script can configure whichever
+    # parts of a large source tree are present.
+    test -d "$srcdir/$ac_dir" || continue
+
+    ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)"
+    $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5
+    $as_echo "$ac_msg" >&6
+    as_dir="$ac_dir"; as_fn_mkdir_p
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+    cd "$ac_dir"
+
+    # Check for guested configure; otherwise get Cygnus style configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      ac_sub_configure=$ac_srcdir/configure.gnu
+    elif test -f "$ac_srcdir/configure"; then
+      ac_sub_configure=$ac_srcdir/configure
+    elif test -f "$ac_srcdir/configure.in"; then
+      # This should be Cygnus configure.
+      ac_sub_configure=$ac_aux_dir/configure
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5
+$as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;}
+      ac_sub_configure=
+    fi
+
+    # The recursion is here.
+    if test -n "$ac_sub_configure"; then
+      # Make the cache file name correct relative to the subdirectory.
+      case $cache_file in
+      [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;;
+      *) # Relative name.
+	ac_sub_cache_file=$ac_top_build_prefix$cache_file ;;
+      esac
+
+      { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5
+$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;}
+      # The eval makes quoting arguments work.
+      eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \
+	   --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" ||
+	as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5
+    fi
+
+    cd "$ac_popdir"
+  done
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/final/lib/External/ppcg/configure.ac b/final/lib/External/ppcg/configure.ac
new file mode 100644
index 0000000..a4b1aaa
--- /dev/null
+++ b/final/lib/External/ppcg/configure.ac
@@ -0,0 +1,83 @@
+AC_INIT([ppcg], [0.07], [isl-development@googlegroups.com])
+AC_CONFIG_AUX_DIR([.])
+AC_CONFIG_MACRO_DIR([m4])
+AM_INIT_AUTOMAKE([foreign])
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
+
+AC_PROG_CC
+AC_PROG_LIBTOOL
+PKG_PROG_PKG_CONFIG
+
+AX_CHECK_OPENMP
+AX_CHECK_OPENCL
+if test $HAVE_OPENCL = yes; then
+	extra_tests="$extra_tests opencl_test.sh"
+fi
+
+AX_SUBMODULE(isl,build|bundled|system,bundled)
+AM_CONDITIONAL(BUNDLED_ISL, test $with_isl = bundled)
+
+AC_SUBST(ISL_CFLAGS)
+AC_SUBST(ISL_LIBS)
+case "$with_isl" in
+bundled)
+	ISL_CFLAGS="-I\$(top_srcdir)/isl/include -I\$(top_builddir)/isl/include"
+	ISL_CFLAGS="$ISL_CFLAGS"
+	ppcg_configure_args="$ppcg_configure_args --with-isl-builddir=../isl"
+	ppcg_configure_args="$ppcg_configure_args --with-isl=build"
+	ppcg_configure_args="$ppcg_configure_args --with-clang=system"
+	;;
+build)
+	ISL_BUILDDIR=`echo @abs_builddir@ | $with_isl_builddir/config.status --file=-`
+	ppcg_configure_args="$ppcg_configure_args --with-isl-builddir=$ISL_BUILDDIR"
+	ISL_CFLAGS="-I$isl_srcdir/include -I$ISL_BUILDDIR/include"
+	ISL_CFLAGS="$ISL_CFLAGS"
+	ISL_LIBS="$with_isl_builddir/libisl.la"
+	;;
+system)
+	PKG_CHECK_MODULES([ISL], [isl])
+esac
+
+AX_SUBMODULE(pet,bundled|system,bundled)
+AM_CONDITIONAL(BUNDLED_PET, test $with_pet = bundled)
+
+AC_SUBST(PET_CFLAGS)
+AC_SUBST(PET_LIBS)
+case "$with_pet" in
+bundled)
+	PET_CFLAGS="$PET_CFLAGS -I\$(top_srcdir)/pet/include"
+	;;
+system)
+	PKG_CHECK_MODULES([PET], [pet])
+	;;
+esac
+
+AC_SUBST(POLYBENCH_DIR)
+AC_SUBST(extra_tests)
+AC_ARG_WITH([polybench],
+	[AS_HELP_STRING([--with-polybench=DIR], [PolyBench location])],
+	[
+	if test -f "$with_polybench/utilities/benchmark_list"; then
+		POLYBENCH_DIR=$with_polybench
+		extra_tests="$extra_tests polybench_test.sh"
+	fi
+	])
+
+AX_DETECT_GIT_HEAD
+echo '#define GIT_HEAD_ID "'$GIT_HEAD_ID'"' > gitversion.h
+
+AC_CONFIG_FILES(Makefile)
+AC_CONFIG_FILES([polybench_test.sh], [chmod +x polybench_test.sh])
+AC_CONFIG_FILES([opencl_test.sh], [chmod +x opencl_test.sh])
+if test $with_isl = bundled; then
+	AC_CONFIG_SUBDIRS(isl)
+fi
+if test $with_pet = bundled; then
+	AC_CONFIG_SUBDIRS(pet)
+fi
+AC_CONFIG_COMMANDS_POST([
+	dnl pass on arguments to subdir configures, but don't
+	dnl add them to config.status
+	ac_configure_args="$ac_configure_args $ppcg_configure_args"
+])
+AC_OUTPUT
diff --git a/final/lib/External/ppcg/cpu.c b/final/lib/External/ppcg/cpu.c
new file mode 100644
index 0000000..7ca6f1a
--- /dev/null
+++ b/final/lib/External/ppcg/cpu.c
@@ -0,0 +1,802 @@
+/*
+ * Copyright 2012 INRIA Paris-Rocquencourt
+ * Copyright 2012 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Tobias Grosser, INRIA Paris-Rocquencourt,
+ * Domaine de Voluceau, Rocquenqourt, B.P. 105,
+ * 78153 Le Chesnay Cedex France
+ * and Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <isl/aff.h>
+#include <isl/ctx.h>
+#include <isl/flow.h>
+#include <isl/map.h>
+#include <isl/ast_build.h>
+#include <isl/schedule.h>
+#include <isl/schedule_node.h>
+#include <pet.h>
+
+#include "ppcg.h"
+#include "ppcg_options.h"
+#include "cpu.h"
+#include "print.h"
+#include "schedule.h"
+#include "util.h"
+
+/* Representation of a statement inside a generated AST.
+ *
+ * "stmt" refers to the original statement.
+ * "ref2expr" maps the reference identifier of each access in
+ * the statement to an AST expression that should be printed
+ * at the place of the access.
+ */
+struct ppcg_stmt {
+	struct pet_stmt *stmt;
+
+	isl_id_to_ast_expr *ref2expr;
+};
+
+static void ppcg_stmt_free(void *user)
+{
+	struct ppcg_stmt *stmt = user;
+
+	if (!stmt)
+		return;
+
+	isl_id_to_ast_expr_free(stmt->ref2expr);
+
+	free(stmt);
+}
+
+/* Derive the output file name from the input file name.
+ * 'input' is the entire path of the input file. The output
+ * is the file name plus the additional extension.
+ *
+ * We will basically replace everything after the last point
+ * with '.ppcg.c'. This means file.c becomes file.ppcg.c
+ */
+static FILE *get_output_file(const char *input, const char *output)
+{
+	char name[PATH_MAX];
+	const char *ext;
+	const char ppcg_marker[] = ".ppcg";
+	int len;
+	FILE *file;
+
+	len = ppcg_extract_base_name(name, input);
+
+	strcpy(name + len, ppcg_marker);
+	ext = strrchr(input, '.');
+	strcpy(name + len + sizeof(ppcg_marker) - 1, ext ? ext : ".c");
+
+	if (!output)
+		output = name;
+
+	file = fopen(output, "w");
+	if (!file) {
+		fprintf(stderr, "Unable to open '%s' for writing\n", output);
+		return NULL;
+	}
+
+	return file;
+}
+
+/* Data used to annotate for nodes in the ast.
+ */
+struct ast_node_userinfo {
+	/* The for node is an openmp parallel for node. */
+	int is_openmp;
+};
+
+/* Information used while building the ast.
+ */
+struct ast_build_userinfo {
+	/* The current ppcg scop. */
+	struct ppcg_scop *scop;
+
+	/* Are we currently in a parallel for loop? */
+	int in_parallel_for;
+};
+
+/* Check if the current scheduling dimension is parallel.
+ *
+ * We check for parallelism by verifying that the loop does not carry any
+ * dependences.
+ * If the live_range_reordering option is set, then this currently
+ * includes the order dependences.  In principle, non-zero order dependences
+ * could be allowed, but this would require privatization and/or expansion.
+ *
+ * Parallelism test: if the distance is zero in all outer dimensions, then it
+ * has to be zero in the current dimension as well.
+ * Implementation: first, translate dependences into time space, then force
+ * outer dimensions to be equal.  If the distance is zero in the current
+ * dimension, then the loop is parallel.
+ * The distance is zero in the current dimension if it is a subset of a map
+ * with equal values for the current dimension.
+ */
+static int ast_schedule_dim_is_parallel(__isl_keep isl_ast_build *build,
+	struct ppcg_scop *scop)
+{
+	isl_union_map *schedule, *deps;
+	isl_map *schedule_deps, *test;
+	isl_space *schedule_space;
+	unsigned i, dimension, is_parallel;
+
+	schedule = isl_ast_build_get_schedule(build);
+	schedule_space = isl_ast_build_get_schedule_space(build);
+
+	dimension = isl_space_dim(schedule_space, isl_dim_out) - 1;
+
+	deps = isl_union_map_copy(scop->dep_flow);
+	deps = isl_union_map_union(deps, isl_union_map_copy(scop->dep_false));
+	if (scop->options->live_range_reordering) {
+		isl_union_map *order = isl_union_map_copy(scop->dep_order);
+		deps = isl_union_map_union(deps, order);
+	}
+	deps = isl_union_map_apply_range(deps, isl_union_map_copy(schedule));
+	deps = isl_union_map_apply_domain(deps, schedule);
+
+	if (isl_union_map_is_empty(deps)) {
+		isl_union_map_free(deps);
+		isl_space_free(schedule_space);
+		return 1;
+	}
+
+	schedule_deps = isl_map_from_union_map(deps);
+
+	for (i = 0; i < dimension; i++)
+		schedule_deps = isl_map_equate(schedule_deps, isl_dim_out, i,
+					       isl_dim_in, i);
+
+	test = isl_map_universe(isl_map_get_space(schedule_deps));
+	test = isl_map_equate(test, isl_dim_out, dimension, isl_dim_in,
+			      dimension);
+	is_parallel = isl_map_is_subset(schedule_deps, test);
+
+	isl_space_free(schedule_space);
+	isl_map_free(test);
+	isl_map_free(schedule_deps);
+
+	return is_parallel;
+}
+
+/* Mark a for node openmp parallel, if it is the outermost parallel for node.
+ */
+static void mark_openmp_parallel(__isl_keep isl_ast_build *build,
+	struct ast_build_userinfo *build_info,
+	struct ast_node_userinfo *node_info)
+{
+	if (build_info->in_parallel_for)
+		return;
+
+	if (ast_schedule_dim_is_parallel(build, build_info->scop)) {
+		build_info->in_parallel_for = 1;
+		node_info->is_openmp = 1;
+	}
+}
+
+/* Allocate an ast_node_info structure and initialize it with default values.
+ */
+static struct ast_node_userinfo *allocate_ast_node_userinfo()
+{
+	struct ast_node_userinfo *node_info;
+	node_info = (struct ast_node_userinfo *)
+		malloc(sizeof(struct ast_node_userinfo));
+	node_info->is_openmp = 0;
+	return node_info;
+}
+
+/* Free an ast_node_info structure.
+ */
+static void free_ast_node_userinfo(void *ptr)
+{
+	struct ast_node_userinfo *info;
+	info = (struct ast_node_userinfo *) ptr;
+	free(info);
+}
+
+/* This method is executed before the construction of a for node. It creates
+ * an isl_id that is used to annotate the subsequently generated ast for nodes.
+ *
+ * In this function we also run the following analyses:
+ *
+ * 	- Detection of openmp parallel loops
+ */
+static __isl_give isl_id *ast_build_before_for(
+	__isl_keep isl_ast_build *build, void *user)
+{
+	isl_id *id;
+	struct ast_build_userinfo *build_info;
+	struct ast_node_userinfo *node_info;
+
+	build_info = (struct ast_build_userinfo *) user;
+	node_info = allocate_ast_node_userinfo();
+	id = isl_id_alloc(isl_ast_build_get_ctx(build), "", node_info);
+	id = isl_id_set_free_user(id, free_ast_node_userinfo);
+
+	mark_openmp_parallel(build, build_info, node_info);
+
+	return id;
+}
+
+/* This method is executed after the construction of a for node.
+ *
+ * It performs the following actions:
+ *
+ * 	- Reset the 'in_parallel_for' flag, as soon as we leave a for node,
+ * 	  that is marked as openmp parallel.
+ *
+ */
+static __isl_give isl_ast_node *ast_build_after_for(
+	__isl_take isl_ast_node *node, __isl_keep isl_ast_build *build,
+	void *user)
+{
+	isl_id *id;
+	struct ast_build_userinfo *build_info;
+	struct ast_node_userinfo *info;
+
+	id = isl_ast_node_get_annotation(node);
+	info = isl_id_get_user(id);
+
+	if (info && info->is_openmp) {
+		build_info = (struct ast_build_userinfo *) user;
+		build_info->in_parallel_for = 0;
+	}
+
+	isl_id_free(id);
+
+	return node;
+}
+
+/* Find the element in scop->stmts that has the given "id".
+ */
+static struct pet_stmt *find_stmt(struct ppcg_scop *scop, __isl_keep isl_id *id)
+{
+	int i;
+
+	for (i = 0; i < scop->pet->n_stmt; ++i) {
+		struct pet_stmt *stmt = scop->pet->stmts[i];
+		isl_id *id_i;
+
+		id_i = isl_set_get_tuple_id(stmt->domain);
+		isl_id_free(id_i);
+
+		if (id_i == id)
+			return stmt;
+	}
+
+	isl_die(isl_id_get_ctx(id), isl_error_internal,
+		"statement not found", return NULL);
+}
+
+/* Print a user statement in the generated AST.
+ * The ppcg_stmt has been attached to the node in at_each_domain.
+ */
+static __isl_give isl_printer *print_user(__isl_take isl_printer *p,
+	__isl_take isl_ast_print_options *print_options,
+	__isl_keep isl_ast_node *node, void *user)
+{
+	struct ppcg_stmt *stmt;
+	isl_id *id;
+
+	id = isl_ast_node_get_annotation(node);
+	stmt = isl_id_get_user(id);
+	isl_id_free(id);
+
+	p = pet_stmt_print_body(stmt->stmt, p, stmt->ref2expr);
+
+	isl_ast_print_options_free(print_options);
+
+	return p;
+}
+
+
+/* Print a for loop node as an openmp parallel loop.
+ *
+ * To print an openmp parallel loop we print a normal for loop, but add
+ * "#pragma openmp parallel for" in front.
+ *
+ * Variables that are declared within the body of this for loop are
+ * automatically openmp 'private'. Iterators declared outside of the
+ * for loop are automatically openmp 'shared'. As ppcg declares all iterators
+ * at the position where they are assigned, there is no need to explicitly mark
+ * variables. Their automatically assigned type is already correct.
+ *
+ * This function only generates valid OpenMP code, if the ast was generated
+ * with the 'atomic-bounds' option enabled.
+ *
+ */
+static __isl_give isl_printer *print_for_with_openmp(
+	__isl_keep isl_ast_node *node, __isl_take isl_printer *p,
+	__isl_take isl_ast_print_options *print_options)
+{
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "#pragma omp parallel for");
+	p = isl_printer_end_line(p);
+
+	p = isl_ast_node_for_print(node, p, print_options);
+
+	return p;
+}
+
+/* Print a for node.
+ *
+ * Depending on how the node is annotated, we either print a normal
+ * for node or an openmp parallel for node.
+ */
+static __isl_give isl_printer *print_for(__isl_take isl_printer *p,
+	__isl_take isl_ast_print_options *print_options,
+	__isl_keep isl_ast_node *node, void *user)
+{
+	isl_id *id;
+	int openmp;
+
+	openmp = 0;
+	id = isl_ast_node_get_annotation(node);
+
+	if (id) {
+		struct ast_node_userinfo *info;
+
+		info = (struct ast_node_userinfo *) isl_id_get_user(id);
+		if (info && info->is_openmp)
+			openmp = 1;
+	}
+
+	if (openmp)
+		p = print_for_with_openmp(node, p, print_options);
+	else
+		p = isl_ast_node_for_print(node, p, print_options);
+
+	isl_id_free(id);
+
+	return p;
+}
+
+/* Index transformation callback for pet_stmt_build_ast_exprs.
+ *
+ * "index" expresses the array indices in terms of statement iterators
+ * "iterator_map" expresses the statement iterators in terms of
+ * AST loop iterators.
+ *
+ * The result expresses the array indices in terms of
+ * AST loop iterators.
+ */
+static __isl_give isl_multi_pw_aff *pullback_index(
+	__isl_take isl_multi_pw_aff *index, __isl_keep isl_id *id, void *user)
+{
+	isl_pw_multi_aff *iterator_map = user;
+
+	iterator_map = isl_pw_multi_aff_copy(iterator_map);
+	return isl_multi_pw_aff_pullback_pw_multi_aff(index, iterator_map);
+}
+
+/* Transform the accesses in the statement associated to the domain
+ * called by "node" to refer to the AST loop iterators, construct
+ * corresponding AST expressions using "build",
+ * collect them in a ppcg_stmt and annotate the node with the ppcg_stmt.
+ */
+static __isl_give isl_ast_node *at_each_domain(__isl_take isl_ast_node *node,
+	__isl_keep isl_ast_build *build, void *user)
+{
+	struct ppcg_scop *scop = user;
+	isl_ast_expr *expr, *arg;
+	isl_ctx *ctx;
+	isl_id *id;
+	isl_map *map;
+	isl_pw_multi_aff *iterator_map;
+	struct ppcg_stmt *stmt;
+
+	ctx = isl_ast_node_get_ctx(node);
+	stmt = isl_calloc_type(ctx, struct ppcg_stmt);
+	if (!stmt)
+		goto error;
+
+	expr = isl_ast_node_user_get_expr(node);
+	arg = isl_ast_expr_get_op_arg(expr, 0);
+	isl_ast_expr_free(expr);
+	id = isl_ast_expr_get_id(arg);
+	isl_ast_expr_free(arg);
+	stmt->stmt = find_stmt(scop, id);
+	isl_id_free(id);
+	if (!stmt->stmt)
+		goto error;
+
+	map = isl_map_from_union_map(isl_ast_build_get_schedule(build));
+	map = isl_map_reverse(map);
+	iterator_map = isl_pw_multi_aff_from_map(map);
+	stmt->ref2expr = pet_stmt_build_ast_exprs(stmt->stmt, build,
+				    &pullback_index, iterator_map, NULL, NULL);
+	isl_pw_multi_aff_free(iterator_map);
+
+	id = isl_id_alloc(isl_ast_node_get_ctx(node), NULL, stmt);
+	id = isl_id_set_free_user(id, &ppcg_stmt_free);
+	return isl_ast_node_set_annotation(node, id);
+error:
+	ppcg_stmt_free(stmt);
+	return isl_ast_node_free(node);
+}
+
+/* Set *depth (initialized to 0 by the caller) to the maximum
+ * of the schedule depths of the leaf nodes for which this function is called.
+ */
+static isl_bool update_depth(__isl_keep isl_schedule_node *node, void *user)
+{
+	int *depth = user;
+	int node_depth;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_leaf)
+		return isl_bool_true;
+	node_depth = isl_schedule_node_get_schedule_depth(node);
+	if (node_depth > *depth)
+		*depth = node_depth;
+
+	return isl_bool_false;
+}
+
+/* This function is called for each node in a CPU AST.
+ * In case of a user node, print the macro definitions required
+ * for printing the AST expressions in the annotation, if any.
+ * For other nodes, return true such that descendants are also
+ * visited.
+ *
+ * In particular, print the macro definitions needed for the substitutions
+ * of the original user statements.
+ */
+static isl_bool at_node(__isl_keep isl_ast_node *node, void *user)
+{
+	struct ppcg_stmt *stmt;
+	isl_id *id;
+	isl_printer **p = user;
+
+	if (isl_ast_node_get_type(node) != isl_ast_node_user)
+		return isl_bool_true;
+
+	id = isl_ast_node_get_annotation(node);
+	stmt = isl_id_get_user(id);
+	isl_id_free(id);
+
+	if (!stmt)
+		return isl_bool_error;
+
+	*p = ppcg_print_body_macros(*p, stmt->ref2expr);
+	if (!*p)
+		return isl_bool_error;
+
+	return isl_bool_false;
+}
+
+/* Print the required macros for the CPU AST "node" to "p",
+ * including those needed for the user statements inside the AST.
+ */
+static __isl_give isl_printer *cpu_print_macros(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node)
+{
+	if (isl_ast_node_foreach_descendant_top_down(node, &at_node, &p) < 0)
+		return isl_printer_free(p);
+	p = ppcg_print_macros(p, node);
+	return p;
+}
+
+/* Code generate the scop 'scop' using "schedule"
+ * and print the corresponding C code to 'p'.
+ */
+static __isl_give isl_printer *print_scop(struct ppcg_scop *scop,
+	__isl_take isl_schedule *schedule, __isl_take isl_printer *p,
+	struct ppcg_options *options)
+{
+	isl_ctx *ctx = isl_printer_get_ctx(p);
+	isl_ast_build *build;
+	isl_ast_print_options *print_options;
+	isl_ast_node *tree;
+	isl_id_list *iterators;
+	struct ast_build_userinfo build_info;
+	int depth;
+
+	depth = 0;
+	if (isl_schedule_foreach_schedule_node_top_down(schedule, &update_depth,
+						&depth) < 0)
+		goto error;
+
+	build = isl_ast_build_alloc(ctx);
+	iterators = ppcg_scop_generate_names(scop, depth, "c");
+	build = isl_ast_build_set_iterators(build, iterators);
+	build = isl_ast_build_set_at_each_domain(build, &at_each_domain, scop);
+
+	if (options->openmp) {
+		build_info.scop = scop;
+		build_info.in_parallel_for = 0;
+
+		build = isl_ast_build_set_before_each_for(build,
+							&ast_build_before_for,
+							&build_info);
+		build = isl_ast_build_set_after_each_for(build,
+							&ast_build_after_for,
+							&build_info);
+	}
+
+	tree = isl_ast_build_node_from_schedule(build, schedule);
+	isl_ast_build_free(build);
+
+	print_options = isl_ast_print_options_alloc(ctx);
+	print_options = isl_ast_print_options_set_print_user(print_options,
+							&print_user, NULL);
+
+	print_options = isl_ast_print_options_set_print_for(print_options,
+							&print_for, NULL);
+
+	p = cpu_print_macros(p, tree);
+	p = isl_ast_node_print(tree, p, print_options);
+
+	isl_ast_node_free(tree);
+
+	return p;
+error:
+	isl_schedule_free(schedule);
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Tile the band node "node" with tile sizes "sizes" and
+ * mark all members of the resulting tile node as "atomic".
+ */
+static __isl_give isl_schedule_node *tile(__isl_take isl_schedule_node *node,
+	__isl_take isl_multi_val *sizes)
+{
+	node = isl_schedule_node_band_tile(node, sizes);
+	node = ppcg_set_schedule_node_type(node, isl_ast_loop_atomic);
+
+	return node;
+}
+
+/* Tile "node", if it is a band node with at least 2 members.
+ * The tile sizes are set from the "tile_size" option.
+ */
+static __isl_give isl_schedule_node *tile_band(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	struct ppcg_scop *scop = user;
+	int n;
+	isl_space *space;
+	isl_multi_val *sizes;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_band)
+		return node;
+
+	n = isl_schedule_node_band_n_member(node);
+	if (n <= 1)
+		return node;
+
+	space = isl_schedule_node_band_get_space(node);
+	sizes = ppcg_multi_val_from_int(space, scop->options->tile_size);
+
+	return tile(node, sizes);
+}
+
+/* Construct schedule constraints from the dependences in ps
+ * for the purpose of computing a schedule for a CPU.
+ *
+ * The proximity constraints are set to the flow dependences.
+ *
+ * If live-range reordering is allowed then the conditional validity
+ * constraints are set to the order dependences with the flow dependences
+ * as condition.  That is, a live-range (flow dependence) will be either
+ * local to an iteration of a band or all adjacent order dependences
+ * will be respected by the band.
+ * The validity constraints are set to the union of the flow dependences
+ * and the forced dependences, while the coincidence constraints
+ * are set to the union of the flow dependences, the forced dependences and
+ * the order dependences.
+ *
+ * If live-range reordering is not allowed, then both the validity
+ * and the coincidence constraints are set to the union of the flow
+ * dependences and the false dependences.
+ *
+ * Note that the coincidence constraints are only set when the "openmp"
+ * options is set.  Even though the way openmp pragmas are introduced
+ * does not rely on the coincident property of the schedule band members,
+ * the coincidence constraints do affect the way the schedule is constructed,
+ * such that more schedule dimensions should be detected as parallel
+ * by ast_schedule_dim_is_parallel.
+ * Since the order dependences are also taken into account by
+ * ast_schedule_dim_is_parallel, they are also added to
+ * the coincidence constraints.  If the openmp handling learns
+ * how to privatize some memory, then the corresponding order
+ * dependences can be removed from the coincidence constraints.
+ */
+static __isl_give isl_schedule_constraints *construct_cpu_schedule_constraints(
+	struct ppcg_scop *ps)
+{
+	isl_schedule_constraints *sc;
+	isl_union_map *validity, *coincidence;
+
+	sc = isl_schedule_constraints_on_domain(isl_union_set_copy(ps->domain));
+	if (ps->options->live_range_reordering) {
+		sc = isl_schedule_constraints_set_conditional_validity(sc,
+				isl_union_map_copy(ps->tagged_dep_flow),
+				isl_union_map_copy(ps->tagged_dep_order));
+		validity = isl_union_map_copy(ps->dep_flow);
+		validity = isl_union_map_union(validity,
+				isl_union_map_copy(ps->dep_forced));
+		if (ps->options->openmp) {
+			coincidence = isl_union_map_copy(validity);
+			coincidence = isl_union_map_union(coincidence,
+					isl_union_map_copy(ps->dep_order));
+		}
+	} else {
+		validity = isl_union_map_copy(ps->dep_flow);
+		validity = isl_union_map_union(validity,
+				isl_union_map_copy(ps->dep_false));
+		if (ps->options->openmp)
+			coincidence = isl_union_map_copy(validity);
+	}
+	if (ps->options->openmp)
+		sc = isl_schedule_constraints_set_coincidence(sc, coincidence);
+	sc = isl_schedule_constraints_set_validity(sc, validity);
+	sc = isl_schedule_constraints_set_proximity(sc,
+					isl_union_map_copy(ps->dep_flow));
+
+	return sc;
+}
+
+/* Compute a schedule for the scop "ps".
+ *
+ * First derive the appropriate schedule constraints from the dependences
+ * in "ps" and then compute a schedule from those schedule constraints,
+ * possibly grouping statement instances based on the input schedule.
+ */
+static __isl_give isl_schedule *compute_cpu_schedule(struct ppcg_scop *ps)
+{
+	isl_schedule_constraints *sc;
+	isl_schedule *schedule;
+
+	if (!ps)
+		return NULL;
+
+	sc = construct_cpu_schedule_constraints(ps);
+
+	if (ps->options->debug->dump_schedule_constraints)
+		isl_schedule_constraints_dump(sc);
+	schedule = ppcg_compute_schedule(sc, ps->schedule, ps->options);
+
+	return schedule;
+}
+
+/* Compute a new schedule to the scop "ps" if the reschedule option is set.
+ * Otherwise, return a copy of the original schedule.
+ */
+static __isl_give isl_schedule *optionally_compute_schedule(void *user)
+{
+	struct ppcg_scop *ps = user;
+
+	if (!ps)
+		return NULL;
+	if (!ps->options->reschedule)
+		return isl_schedule_copy(ps->schedule);
+	return compute_cpu_schedule(ps);
+}
+
+/* Compute a schedule based on the dependences in "ps" and
+ * tile it if requested by the user.
+ */
+static __isl_give isl_schedule *get_schedule(struct ppcg_scop *ps,
+	struct ppcg_options *options)
+{
+	isl_ctx *ctx;
+	isl_schedule *schedule;
+
+	if (!ps)
+		return NULL;
+
+	ctx = isl_union_set_get_ctx(ps->domain);
+	schedule = ppcg_get_schedule(ctx, options,
+				    &optionally_compute_schedule, ps);
+	if (ps->options->tile)
+		schedule = isl_schedule_map_schedule_node_bottom_up(schedule,
+							&tile_band, ps);
+
+	return schedule;
+}
+
+/* Generate CPU code for the scop "ps" using "schedule" and
+ * print the corresponding C code to "p", including variable declarations.
+ */
+static __isl_give isl_printer *print_cpu_with_schedule(
+	__isl_take isl_printer *p, struct ppcg_scop *ps,
+	__isl_take isl_schedule *schedule, struct ppcg_options *options)
+{
+	int hidden;
+	isl_set *context;
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "/* ppcg generated CPU code */");
+	p = isl_printer_end_line(p);
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_end_line(p);
+
+	p = ppcg_set_macro_names(p);
+	p = ppcg_print_exposed_declarations(p, ps);
+	hidden = ppcg_scop_any_hidden_declarations(ps);
+	if (hidden) {
+		p = ppcg_start_block(p);
+		p = ppcg_print_hidden_declarations(p, ps);
+	}
+
+	context = isl_set_copy(ps->context);
+	context = isl_set_from_params(context);
+	schedule = isl_schedule_insert_context(schedule, context);
+	if (options->debug->dump_final_schedule)
+		isl_schedule_dump(schedule);
+	p = print_scop(ps, schedule, p, options);
+	if (hidden)
+		p = ppcg_end_block(p);
+
+	return p;
+}
+
+/* Generate CPU code for the scop "ps" and print the corresponding C code
+ * to "p", including variable declarations.
+ */
+__isl_give isl_printer *print_cpu(__isl_take isl_printer *p,
+	struct ppcg_scop *ps, struct ppcg_options *options)
+{
+	isl_schedule *schedule;
+
+	schedule = isl_schedule_copy(ps->schedule);
+	return print_cpu_with_schedule(p, ps, schedule, options);
+}
+
+/* Generate CPU code for "scop" and print it to "p".
+ *
+ * First obtain a schedule for "scop" and then print code for "scop"
+ * using that schedule.
+ */
+static __isl_give isl_printer *generate(__isl_take isl_printer *p,
+	struct ppcg_scop *scop, struct ppcg_options *options)
+{
+	isl_schedule *schedule;
+
+	schedule = get_schedule(scop, options);
+
+	return print_cpu_with_schedule(p, scop, schedule, options);
+}
+
+/* Wrapper around generate for use as a ppcg_transform callback.
+ */
+static __isl_give isl_printer *print_cpu_wrap(__isl_take isl_printer *p,
+	struct ppcg_scop *scop, void *user)
+{
+	struct ppcg_options *options = user;
+
+	return generate(p, scop, options);
+}
+
+/* Transform the code in the file called "input" by replacing
+ * all scops by corresponding CPU code and write the results to a file
+ * called "output".
+ */
+int generate_cpu(isl_ctx *ctx, struct ppcg_options *options,
+	const char *input, const char *output)
+{
+	FILE *output_file;
+	int r;
+
+	output_file = get_output_file(input, output);
+	if (!output_file)
+		return -1;
+
+	r = ppcg_transform(ctx, input, output_file, options,
+					&print_cpu_wrap, options);
+
+	fclose(output_file);
+
+	return r;
+}
diff --git a/final/lib/External/ppcg/cpu.h b/final/lib/External/ppcg/cpu.h
new file mode 100644
index 0000000..6caf993
--- /dev/null
+++ b/final/lib/External/ppcg/cpu.h
@@ -0,0 +1,15 @@
+#ifndef _CPU_H
+#define _CPU_H
+
+#include <isl/ctx.h>
+
+#include "ppcg.h"
+
+struct ppcg_options;
+
+__isl_give isl_printer *print_cpu(__isl_take isl_printer *p,
+	struct ppcg_scop *ps, struct ppcg_options *options);
+int generate_cpu(isl_ctx *ctx, struct ppcg_options *options,
+	const char *input, const char *output);
+
+#endif
diff --git a/final/lib/External/ppcg/cuda.c b/final/lib/External/ppcg/cuda.c
new file mode 100644
index 0000000..380d652
--- /dev/null
+++ b/final/lib/External/ppcg/cuda.c
@@ -0,0 +1,730 @@
+/*
+ * Copyright 2012      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl/aff.h>
+#include <isl/ast.h>
+
+#include "cuda_common.h"
+#include "cuda.h"
+#include "gpu.h"
+#include "gpu_print.h"
+#include "print.h"
+#include "util.h"
+
+static __isl_give isl_printer *print_cuda_macros(__isl_take isl_printer *p)
+{
+	const char *macros =
+		"#define cudaCheckReturn(ret) \\\n"
+		"  do { \\\n"
+		"    cudaError_t cudaCheckReturn_e = (ret); \\\n"
+		"    if (cudaCheckReturn_e != cudaSuccess) { \\\n"
+		"      fprintf(stderr, \"CUDA error: %s\\n\", "
+		"cudaGetErrorString(cudaCheckReturn_e)); \\\n"
+		"      fflush(stderr); \\\n"
+		"    } \\\n"
+		"    assert(cudaCheckReturn_e == cudaSuccess); \\\n"
+		"  } while(0)\n"
+		"#define cudaCheckKernel() \\\n"
+		"  do { \\\n"
+		"    cudaCheckReturn(cudaGetLastError()); \\\n"
+		"  } while(0)\n\n";
+
+	p = isl_printer_print_str(p, macros);
+	return p;
+}
+
+/* Print a declaration for the device array corresponding to "array" on "p".
+ */
+static __isl_give isl_printer *declare_device_array(__isl_take isl_printer *p,
+	struct gpu_array_info *array)
+{
+	int i;
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, array->type);
+	p = isl_printer_print_str(p, " ");
+	if (!array->linearize && array->n_index > 1)
+		p = isl_printer_print_str(p, "(");
+	p = isl_printer_print_str(p, "*dev_");
+	p = isl_printer_print_str(p, array->name);
+	if (!array->linearize && array->n_index > 1) {
+		p = isl_printer_print_str(p, ")");
+		for (i = 1; i < array->n_index; i++) {
+			isl_ast_expr *bound;
+			bound = isl_ast_expr_get_op_arg(array->bound_expr,
+							1 + i);
+			p = isl_printer_print_str(p, "[");
+			p = isl_printer_print_ast_expr(p, bound);
+			p = isl_printer_print_str(p, "]");
+			isl_ast_expr_free(bound);
+		}
+	}
+	p = isl_printer_print_str(p, ";");
+	p = isl_printer_end_line(p);
+
+	return p;
+}
+
+static __isl_give isl_printer *declare_device_arrays(__isl_take isl_printer *p,
+	struct gpu_prog *prog)
+{
+	int i;
+
+	for (i = 0; i < prog->n_array; ++i) {
+		if (!gpu_array_requires_device_allocation(&prog->array[i]))
+			continue;
+
+		p = declare_device_array(p, &prog->array[i]);
+	}
+	p = isl_printer_start_line(p);
+	p = isl_printer_end_line(p);
+	return p;
+}
+
+static __isl_give isl_printer *allocate_device_arrays(
+	__isl_take isl_printer *p, struct gpu_prog *prog)
+{
+	int i;
+
+	for (i = 0; i < prog->n_array; ++i) {
+		struct gpu_array_info *array = &prog->array[i];
+
+		if (!gpu_array_requires_device_allocation(&prog->array[i]))
+			continue;
+		p = ppcg_ast_expr_print_macros(array->bound_expr, p);
+		p = isl_printer_start_line(p);
+		p = isl_printer_print_str(p,
+			"cudaCheckReturn(cudaMalloc((void **) &dev_");
+		p = isl_printer_print_str(p, prog->array[i].name);
+		p = isl_printer_print_str(p, ", ");
+		p = gpu_array_info_print_size(p, &prog->array[i]);
+		p = isl_printer_print_str(p, "));");
+		p = isl_printer_end_line(p);
+	}
+	p = isl_printer_start_line(p);
+	p = isl_printer_end_line(p);
+	return p;
+}
+
+static __isl_give isl_printer *free_device_arrays(__isl_take isl_printer *p,
+	struct gpu_prog *prog)
+{
+	int i;
+
+	for (i = 0; i < prog->n_array; ++i) {
+		if (!gpu_array_requires_device_allocation(&prog->array[i]))
+			continue;
+		p = isl_printer_start_line(p);
+		p = isl_printer_print_str(p, "cudaCheckReturn(cudaFree(dev_");
+		p = isl_printer_print_str(p, prog->array[i].name);
+		p = isl_printer_print_str(p, "));");
+		p = isl_printer_end_line(p);
+	}
+
+	return p;
+}
+
+/* Print code to "p" for copying "array" from the host to the device
+ * in its entirety.  The bounds on the extent of "array" have
+ * been precomputed in extract_array_info and are used in
+ * gpu_array_info_print_size.
+ */
+static __isl_give isl_printer *copy_array_to_device(__isl_take isl_printer *p,
+	struct gpu_array_info *array)
+{
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "cudaCheckReturn(cudaMemcpy(dev_");
+	p = isl_printer_print_str(p, array->name);
+	p = isl_printer_print_str(p, ", ");
+
+	if (gpu_array_is_scalar(array))
+		p = isl_printer_print_str(p, "&");
+	p = isl_printer_print_str(p, array->name);
+	p = isl_printer_print_str(p, ", ");
+
+	p = gpu_array_info_print_size(p, array);
+	p = isl_printer_print_str(p, ", cudaMemcpyHostToDevice));");
+	p = isl_printer_end_line(p);
+
+	return p;
+}
+
+/* Print code to "p" for copying "array" back from the device to the host
+ * in its entirety.  The bounds on the extent of "array" have
+ * been precomputed in extract_array_info and are used in
+ * gpu_array_info_print_size.
+ */
+static __isl_give isl_printer *copy_array_from_device(
+	__isl_take isl_printer *p, struct gpu_array_info *array)
+{
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "cudaCheckReturn(cudaMemcpy(");
+	if (gpu_array_is_scalar(array))
+		p = isl_printer_print_str(p, "&");
+	p = isl_printer_print_str(p, array->name);
+	p = isl_printer_print_str(p, ", dev_");
+	p = isl_printer_print_str(p, array->name);
+	p = isl_printer_print_str(p, ", ");
+	p = gpu_array_info_print_size(p, array);
+	p = isl_printer_print_str(p, ", cudaMemcpyDeviceToHost));");
+	p = isl_printer_end_line(p);
+
+	return p;
+}
+
+static __isl_give isl_printer* print_reverse_list(__isl_take isl_printer *p, int len, int *list)
+{
+	int i;
+
+	if (len == 0)
+		return p;
+
+	p = isl_printer_print_str(p, "(");
+	for (i = 0; i < len; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, ", ");
+		p = isl_printer_print_int(p, list[len - 1 - i]);
+	}
+	return isl_printer_print_str(p, ")");
+}
+
+/* Print the effective grid size as a list of the sizes in each
+ * dimension, from innermost to outermost.
+ */
+static __isl_give isl_printer *print_grid_size(__isl_take isl_printer *p,
+	struct ppcg_kernel *kernel)
+{
+	int i;
+	int dim;
+
+	dim = isl_multi_pw_aff_dim(kernel->grid_size, isl_dim_set);
+	if (dim == 0)
+		return p;
+
+	p = isl_printer_print_str(p, "(");
+	for (i = dim - 1; i >= 0; --i) {
+		isl_ast_expr *bound;
+
+		bound = isl_ast_expr_get_op_arg(kernel->grid_size_expr, 1 + i);
+		p = isl_printer_print_ast_expr(p, bound);
+		isl_ast_expr_free(bound);
+
+		if (i > 0)
+			p = isl_printer_print_str(p, ", ");
+	}
+
+	p = isl_printer_print_str(p, ")");
+
+	return p;
+}
+
+/* Print the grid definition.
+ */
+static __isl_give isl_printer *print_grid(__isl_take isl_printer *p,
+	struct ppcg_kernel *kernel)
+{
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "dim3 k");
+	p = isl_printer_print_int(p, kernel->id);
+	p = isl_printer_print_str(p, "_dimGrid");
+	p = print_grid_size(p, kernel);
+	p = isl_printer_print_str(p, ";");
+	p = isl_printer_end_line(p);
+
+	return p;
+}
+
+/* Print the arguments to a kernel declaration or call.  If "types" is set,
+ * then print a declaration (including the types of the arguments).
+ *
+ * The arguments are printed in the following order
+ * - the arrays accessed by the kernel
+ * - the parameters
+ * - the host loop iterators
+ */
+static __isl_give isl_printer *print_kernel_arguments(__isl_take isl_printer *p,
+	struct gpu_prog *prog, struct ppcg_kernel *kernel, int types)
+{
+	int i, n;
+	int first = 1;
+	unsigned nparam;
+	isl_space *space;
+	const char *type;
+
+	for (i = 0; i < prog->n_array; ++i) {
+		int required;
+
+		required = ppcg_kernel_requires_array_argument(kernel, i);
+		if (required < 0)
+			return isl_printer_free(p);
+		if (!required)
+			continue;
+
+		if (!first)
+			p = isl_printer_print_str(p, ", ");
+
+		if (types)
+			p = gpu_array_info_print_declaration_argument(p,
+				&prog->array[i], NULL);
+		else
+			p = gpu_array_info_print_call_argument(p,
+				&prog->array[i]);
+
+		first = 0;
+	}
+
+	space = isl_union_set_get_space(kernel->arrays);
+	nparam = isl_space_dim(space, isl_dim_param);
+	for (i = 0; i < nparam; ++i) {
+		const char *name;
+
+		name = isl_space_get_dim_name(space, isl_dim_param, i);
+
+		if (!first)
+			p = isl_printer_print_str(p, ", ");
+		if (types)
+			p = isl_printer_print_str(p, "int ");
+		p = isl_printer_print_str(p, name);
+
+		first = 0;
+	}
+	isl_space_free(space);
+
+	n = isl_space_dim(kernel->space, isl_dim_set);
+	type = isl_options_get_ast_iterator_type(prog->ctx);
+	for (i = 0; i < n; ++i) {
+		const char *name;
+
+		if (!first)
+			p = isl_printer_print_str(p, ", ");
+		name = isl_space_get_dim_name(kernel->space, isl_dim_set, i);
+		if (types) {
+			p = isl_printer_print_str(p, type);
+			p = isl_printer_print_str(p, " ");
+		}
+		p = isl_printer_print_str(p, name);
+
+		first = 0;
+	}
+
+	return p;
+}
+
+/* Print the header of the given kernel.
+ */
+static __isl_give isl_printer *print_kernel_header(__isl_take isl_printer *p,
+	struct gpu_prog *prog, struct ppcg_kernel *kernel)
+{
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "__global__ void kernel");
+	p = isl_printer_print_int(p, kernel->id);
+	p = isl_printer_print_str(p, "(");
+	p = print_kernel_arguments(p, prog, kernel, 1);
+	p = isl_printer_print_str(p, ")");
+
+	return p;
+}
+
+/* Print the header of the given kernel to both gen->cuda.kernel_h
+ * and gen->cuda.kernel_c.
+ */
+static void print_kernel_headers(struct gpu_prog *prog,
+	struct ppcg_kernel *kernel, struct cuda_info *cuda)
+{
+	isl_printer *p;
+
+	p = isl_printer_to_file(prog->ctx, cuda->kernel_h);
+	p = isl_printer_set_output_format(p, ISL_FORMAT_C);
+	p = print_kernel_header(p, prog, kernel);
+	p = isl_printer_print_str(p, ";");
+	p = isl_printer_end_line(p);
+	isl_printer_free(p);
+
+	p = isl_printer_to_file(prog->ctx, cuda->kernel_c);
+	p = isl_printer_set_output_format(p, ISL_FORMAT_C);
+	p = print_kernel_header(p, prog, kernel);
+	p = isl_printer_end_line(p);
+	isl_printer_free(p);
+}
+
+static void print_indent(FILE *dst, int indent)
+{
+	fprintf(dst, "%*s", indent, "");
+}
+
+/* Print a list of iterators of type "type" with names "ids" to "out".
+ * Each iterator is assigned one of the cuda identifiers in cuda_dims.
+ * In particular, the last iterator is assigned the x identifier
+ * (the first in the list of cuda identifiers).
+ */
+static void print_iterators(FILE *out, const char *type,
+	__isl_keep isl_id_list *ids, const char *cuda_dims[])
+{
+	int i, n;
+
+	n = isl_id_list_n_id(ids);
+	if (n <= 0)
+		return;
+	print_indent(out, 4);
+	fprintf(out, "%s ", type);
+	for (i = 0; i < n; ++i) {
+		isl_id *id;
+
+		if (i)
+			fprintf(out, ", ");
+		id = isl_id_list_get_id(ids, i);
+		fprintf(out, "%s = %s", isl_id_get_name(id),
+			cuda_dims[n - 1 - i]);
+		isl_id_free(id);
+	}
+	fprintf(out, ";\n");
+}
+
+static void print_kernel_iterators(FILE *out, struct ppcg_kernel *kernel)
+{
+	isl_ctx *ctx = isl_ast_node_get_ctx(kernel->tree);
+	const char *type;
+	const char *block_dims[] = { "blockIdx.x", "blockIdx.y" };
+	const char *thread_dims[] = { "threadIdx.x", "threadIdx.y",
+					"threadIdx.z" };
+
+	type = isl_options_get_ast_iterator_type(ctx);
+
+	print_iterators(out, type, kernel->block_ids, block_dims);
+	print_iterators(out, type, kernel->thread_ids, thread_dims);
+}
+
+static __isl_give isl_printer *print_kernel_var(__isl_take isl_printer *p,
+	struct ppcg_kernel_var *var)
+{
+	int j;
+
+	p = isl_printer_start_line(p);
+	if (var->type == ppcg_access_shared)
+		p = isl_printer_print_str(p, "__shared__ ");
+	p = isl_printer_print_str(p, var->array->type);
+	p = isl_printer_print_str(p, " ");
+	p = isl_printer_print_str(p,  var->name);
+	for (j = 0; j < var->array->n_index; ++j) {
+		isl_val *v;
+
+		p = isl_printer_print_str(p, "[");
+		v = isl_vec_get_element_val(var->size, j);
+		p = isl_printer_print_val(p, v);
+		isl_val_free(v);
+		p = isl_printer_print_str(p, "]");
+	}
+	p = isl_printer_print_str(p, ";");
+	p = isl_printer_end_line(p);
+
+	return p;
+}
+
+static __isl_give isl_printer *print_kernel_vars(__isl_take isl_printer *p,
+	struct ppcg_kernel *kernel)
+{
+	int i;
+
+	for (i = 0; i < kernel->n_var; ++i)
+		p = print_kernel_var(p, &kernel->var[i]);
+
+	return p;
+}
+
+/* Print a sync statement.
+ */
+static __isl_give isl_printer *print_sync(__isl_take isl_printer *p,
+	struct ppcg_kernel_stmt *stmt)
+{
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "__syncthreads();");
+	p = isl_printer_end_line(p);
+
+	return p;
+}
+
+/* This function is called for each user statement in the AST,
+ * i.e., for each kernel body statement, copy statement or sync statement.
+ */
+static __isl_give isl_printer *print_kernel_stmt(__isl_take isl_printer *p,
+	__isl_take isl_ast_print_options *print_options,
+	__isl_keep isl_ast_node *node, void *user)
+{
+	isl_id *id;
+	struct ppcg_kernel_stmt *stmt;
+
+	id = isl_ast_node_get_annotation(node);
+	stmt = isl_id_get_user(id);
+	isl_id_free(id);
+
+	isl_ast_print_options_free(print_options);
+
+	switch (stmt->type) {
+	case ppcg_kernel_copy:
+		return ppcg_kernel_print_copy(p, stmt);
+	case ppcg_kernel_sync:
+		return print_sync(p, stmt);
+	case ppcg_kernel_domain:
+		return ppcg_kernel_print_domain(p, stmt);
+	}
+
+	return p;
+}
+
+static void print_kernel(struct gpu_prog *prog, struct ppcg_kernel *kernel,
+	struct cuda_info *cuda)
+{
+	isl_ctx *ctx = isl_ast_node_get_ctx(kernel->tree);
+	isl_ast_print_options *print_options;
+	isl_printer *p;
+
+	print_kernel_headers(prog, kernel, cuda);
+	fprintf(cuda->kernel_c, "{\n");
+	print_kernel_iterators(cuda->kernel_c, kernel);
+
+	p = isl_printer_to_file(ctx, cuda->kernel_c);
+	p = isl_printer_set_output_format(p, ISL_FORMAT_C);
+	p = isl_printer_indent(p, 4);
+
+	p = print_kernel_vars(p, kernel);
+	p = isl_printer_end_line(p);
+	p = ppcg_set_macro_names(p);
+	p = gpu_print_macros(p, kernel->tree);
+
+	print_options = isl_ast_print_options_alloc(ctx);
+	print_options = isl_ast_print_options_set_print_user(print_options,
+							&print_kernel_stmt, NULL);
+	p = isl_ast_node_print(kernel->tree, p, print_options);
+	isl_printer_free(p);
+
+	fprintf(cuda->kernel_c, "}\n");
+}
+
+/* Print code for initializing the device for execution of the transformed
+ * code.  This includes declaring locally defined variables as well as
+ * declaring and allocating the required copies of arrays on the device.
+ */
+static __isl_give isl_printer *init_device(__isl_take isl_printer *p,
+	struct gpu_prog *prog)
+{
+	p = print_cuda_macros(p);
+
+	p = gpu_print_local_declarations(p, prog);
+	p = declare_device_arrays(p, prog);
+	p = allocate_device_arrays(p, prog);
+
+	return p;
+}
+
+/* Print code for clearing the device after execution of the transformed code.
+ * In particular, free the memory that was allocated on the device.
+ */
+static __isl_give isl_printer *clear_device(__isl_take isl_printer *p,
+	struct gpu_prog *prog)
+{
+	p = free_device_arrays(p, prog);
+
+	return p;
+}
+
+/* Print a statement for copying an array to or from the device,
+ * or for initializing or clearing the device.
+ * The statement identifier of a copying node is called
+ * "to_device_<array name>" or "from_device_<array name>" and
+ * its user pointer points to the gpu_array_info of the array
+ * that needs to be copied.
+ * The node for initializing the device is called "init_device".
+ * The node for clearing the device is called "clear_device".
+ *
+ * Extract the array (if any) from the identifier and call
+ * init_device, clear_device, copy_array_to_device or copy_array_from_device.
+ */
+static __isl_give isl_printer *print_device_node(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node, struct gpu_prog *prog)
+{
+	isl_ast_expr *expr, *arg;
+	isl_id *id;
+	const char *name;
+	struct gpu_array_info *array;
+
+	expr = isl_ast_node_user_get_expr(node);
+	arg = isl_ast_expr_get_op_arg(expr, 0);
+	id = isl_ast_expr_get_id(arg);
+	name = isl_id_get_name(id);
+	array = isl_id_get_user(id);
+	isl_id_free(id);
+	isl_ast_expr_free(arg);
+	isl_ast_expr_free(expr);
+
+	if (!name)
+		return isl_printer_free(p);
+	if (!strcmp(name, "init_device"))
+		return init_device(p, prog);
+	if (!strcmp(name, "clear_device"))
+		return clear_device(p, prog);
+	if (!array)
+		return isl_printer_free(p);
+
+	if (!prefixcmp(name, "to_device"))
+		return copy_array_to_device(p, array);
+	else
+		return copy_array_from_device(p, array);
+}
+
+struct print_host_user_data {
+	struct cuda_info *cuda;
+	struct gpu_prog *prog;
+};
+
+/* Print the user statement of the host code to "p".
+ *
+ * The host code may contain original user statements, kernel launches,
+ * statements that copy data to/from the device and statements
+ * the initialize or clear the device.
+ * The original user statements and the kernel launches have
+ * an associated annotation, while the other statements do not.
+ * The latter are handled by print_device_node.
+ * The annotation on the user statements is called "user".
+ *
+ * In case of a kernel launch, print a block of statements that
+ * defines the grid and the block and then launches the kernel.
+ */
+__isl_give isl_printer *print_host_user(__isl_take isl_printer *p,
+	__isl_take isl_ast_print_options *print_options,
+	__isl_keep isl_ast_node *node, void *user)
+{
+	isl_id *id;
+	int is_user;
+	struct ppcg_kernel *kernel;
+	struct ppcg_kernel_stmt *stmt;
+	struct print_host_user_data *data;
+
+	isl_ast_print_options_free(print_options);
+
+	data = (struct print_host_user_data *) user;
+
+	id = isl_ast_node_get_annotation(node);
+	if (!id)
+		return print_device_node(p, node, data->prog);
+
+	is_user = !strcmp(isl_id_get_name(id), "user");
+	kernel = is_user ? NULL : isl_id_get_user(id);
+	stmt = is_user ? isl_id_get_user(id) : NULL;
+	isl_id_free(id);
+
+	if (is_user)
+		return ppcg_kernel_print_domain(p, stmt);
+
+	p = ppcg_start_block(p);
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "dim3 k");
+	p = isl_printer_print_int(p, kernel->id);
+	p = isl_printer_print_str(p, "_dimBlock");
+	p = print_reverse_list(p, kernel->n_block, kernel->block_dim);
+	p = isl_printer_print_str(p, ";");
+	p = isl_printer_end_line(p);
+
+	p = print_grid(p, kernel);
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "kernel");
+	p = isl_printer_print_int(p, kernel->id);
+	p = isl_printer_print_str(p, " <<<k");
+	p = isl_printer_print_int(p, kernel->id);
+	p = isl_printer_print_str(p, "_dimGrid, k");
+	p = isl_printer_print_int(p, kernel->id);
+	p = isl_printer_print_str(p, "_dimBlock>>> (");
+	p = print_kernel_arguments(p, data->prog, kernel, 0);
+	p = isl_printer_print_str(p, ");");
+	p = isl_printer_end_line(p);
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "cudaCheckKernel();");
+	p = isl_printer_end_line(p);
+
+	p = ppcg_end_block(p);
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_end_line(p);
+
+#if 0
+	print_kernel(data->prog, kernel, data->cuda);
+#endif
+
+	return p;
+}
+
+static __isl_give isl_printer *print_host_code(__isl_take isl_printer *p,
+	struct gpu_prog *prog, __isl_keep isl_ast_node *tree,
+	struct cuda_info *cuda)
+{
+	isl_ast_print_options *print_options;
+	isl_ctx *ctx = isl_ast_node_get_ctx(tree);
+	struct print_host_user_data data = { cuda, prog };
+
+	print_options = isl_ast_print_options_alloc(ctx);
+	print_options = isl_ast_print_options_set_print_user(print_options,
+						&print_host_user, &data);
+
+	p = gpu_print_macros(p, tree);
+	p = isl_ast_node_print(tree, p, print_options);
+
+	return p;
+}
+
+/* Given a gpu_prog "prog" and the corresponding transformed AST
+ * "tree", print the entire CUDA code to "p".
+ * "types" collects the types for which a definition has already
+ * been printed.
+ */
+static __isl_give isl_printer *print_cuda(__isl_take isl_printer *p,
+	struct gpu_prog *prog, __isl_keep isl_ast_node *tree,
+	struct gpu_types *types, void *user)
+{
+	struct cuda_info *cuda = user;
+	isl_printer *kernel;
+
+	kernel = isl_printer_to_file(isl_printer_get_ctx(p), cuda->kernel_c);
+	kernel = isl_printer_set_output_format(kernel, ISL_FORMAT_C);
+	kernel = gpu_print_types(kernel, types, prog);
+	isl_printer_free(kernel);
+
+	if (!kernel)
+		return isl_printer_free(p);
+
+	p = print_host_code(p, prog, tree, cuda);
+
+	return p;
+}
+
+/* Transform the code in the file called "input" by replacing
+ * all scops by corresponding CUDA code.
+ * The names of the output files are derived from "input".
+ *
+ * We let generate_gpu do all the hard work and then let it call
+ * us back for printing the AST in print_cuda.
+ *
+ * To prepare for this printing, we first open the output files
+ * and we close them after generate_gpu has finished.
+ */
+int generate_cuda(isl_ctx *ctx, struct ppcg_options *options,
+	const char *input)
+{
+	struct cuda_info cuda;
+	int r;
+
+	cuda_open_files(&cuda, input);
+
+	r = generate_gpu(ctx, input, cuda.host_c, options, &print_cuda, &cuda);
+
+	cuda_close_files(&cuda);
+
+	return r;
+}
diff --git a/final/lib/External/ppcg/cuda.h b/final/lib/External/ppcg/cuda.h
new file mode 100644
index 0000000..450fc69
--- /dev/null
+++ b/final/lib/External/ppcg/cuda.h
@@ -0,0 +1,13 @@
+#ifndef _CUDA_H
+#define _CUDA_H
+
+#include "ppcg_options.h"
+#include "ppcg.h"
+
+int generate_cuda(isl_ctx *ctx, struct ppcg_options *options,
+	const char *input);
+
+__isl_give isl_printer *print_host_user(__isl_take isl_printer *p,
+	__isl_take isl_ast_print_options *print_options,
+	__isl_keep isl_ast_node *node, void *user);
+#endif
diff --git a/final/lib/External/ppcg/cuda_common.c b/final/lib/External/ppcg/cuda_common.c
new file mode 100644
index 0000000..497353f
--- /dev/null
+++ b/final/lib/External/ppcg/cuda_common.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010      INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ */
+
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+
+#include "cuda_common.h"
+#include "ppcg.h"
+
+/* Open the host .cu file and the kernel .hu and .cu files for writing.
+ * Add the necessary includes.
+ */
+void cuda_open_files(struct cuda_info *info, const char *input)
+{
+    char name[PATH_MAX];
+    int len;
+
+    len = ppcg_extract_base_name(name, input);
+
+    strcpy(name + len, "_host.cu");
+    info->host_c = fopen(name, "w");
+
+    strcpy(name + len, "_kernel.cu");
+    info->kernel_c = fopen(name, "w");
+
+    strcpy(name + len, "_kernel.hu");
+    info->kernel_h = fopen(name, "w");
+    fprintf(info->host_c, "#include <assert.h>\n");
+    fprintf(info->host_c, "#include <stdio.h>\n");
+    fprintf(info->host_c, "#include \"%s\"\n", name);
+    fprintf(info->kernel_c, "#include \"%s\"\n", name);
+    fprintf(info->kernel_h, "#include \"cuda.h\"\n\n");
+}
+
+/* Close all output files.
+ */
+void cuda_close_files(struct cuda_info *info)
+{
+    fclose(info->kernel_c);
+    fclose(info->kernel_h);
+    fclose(info->host_c);
+}
diff --git a/final/lib/External/ppcg/cuda_common.h b/final/lib/External/ppcg/cuda_common.h
new file mode 100644
index 0000000..2a7db95
--- /dev/null
+++ b/final/lib/External/ppcg/cuda_common.h
@@ -0,0 +1,15 @@
+#ifndef _CUDA_COMMON_H_
+#define _CUDA_COMMON_H_
+
+#include <stdio.h>
+
+struct cuda_info {
+	FILE *host_c;
+	FILE *kernel_c;
+	FILE *kernel_h;
+};
+
+void cuda_open_files(struct cuda_info *info, const char *input);
+void cuda_close_files(struct cuda_info *info);
+
+#endif
diff --git a/final/lib/External/ppcg/depcomp b/final/lib/External/ppcg/depcomp
new file mode 100644
index 0000000..25a39e6
--- /dev/null
+++ b/final/lib/External/ppcg/depcomp
@@ -0,0 +1,708 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2012-03-27.16; # UTC
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
+# 2011, 2012 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+  '')
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+  depmode     Dependency tracking mode.
+  source      Source file read by 'PROGRAMS ARGS'.
+  object      Object file output by 'PROGRAMS ARGS'.
+  DEPDIR      directory where to store dependencies.
+  depfile     Dependency file to output.
+  tmpdepfile  Temporary file to use when outputting dependencies.
+  libtool     Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "depcomp $scriptversion"
+    exit $?
+    ;;
+esac
+
+# A tabulation character.
+tab='	'
+# A newline character.
+nl='
+'
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+   # This is just like dashmstdout with a different argument.
+   dashmflag=-xM
+   depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+   # This is just like msvisualcpp but w/o cygpath translation.
+   # Just convert the backslash-escaped backslashes to single forward
+   # slashes to satisfy depend.m4
+   cygpath_u='sed s,\\\\,/,g'
+   depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+   # This is just like msvc7 but w/o cygpath translation.
+   # Just convert the backslash-escaped backslashes to single forward
+   # slashes to satisfy depend.m4
+   cygpath_u='sed s,\\\\,/,g'
+   depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+   # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations.
+   gccflag=-qmakedep=gcc,-MF
+   depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am.  Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+  for arg
+  do
+    case $arg in
+    -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+    *)  set fnord "$@" "$arg" ;;
+    esac
+    shift # fnord
+    shift # $arg
+  done
+  "$@"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+  tr ' ' "$nl" < "$tmpdepfile" |
+## Some versions of gcc put a space before the ':'.  On the theory
+## that the space means something, we add a space to the output as
+## well.  hp depmode also adds that space, but also prefixes the VPATH
+## to the object.  Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+      | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like '#:fec' to the end of the
+    # dependency line.
+    tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+    tr "$nl" ' ' >> "$depfile"
+    echo >> "$depfile"
+
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' "$nl" < "$tmpdepfile" \
+   | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+   >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+xlc)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts '$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+  test "x$dir" = "x$object" && dir=
+  base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$base.u
+    tmpdepfile3=$dir.libs/$base.u
+    "$@" -Wc,-M
+  else
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$dir$base.u
+    tmpdepfile3=$dir$base.u
+    "$@" -M
+  fi
+  stat=$?
+
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    # Each line is of the form 'foo.o: dependent.h'.
+    # Do two passes, one to just change these to
+    # '$object: dependent.h' and one to simply 'dependent.h:'.
+    sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+    sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+icc)
+  # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'.
+  # However on
+  #    $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+  # ICC 7.0 will fill foo.d with something like
+  #    foo.o: sub/foo.c
+  #    foo.o: sub/foo.h
+  # which is wrong.  We want
+  #    sub/foo.o: sub/foo.c
+  #    sub/foo.o: sub/foo.h
+  #    sub/foo.c:
+  #    sub/foo.h:
+  # ICC 7.1 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using '\':
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+  # tcc 0.9.26 (FIXME still under development at the moment of writing)
+  # will emit a similar output, but also prepend the continuation lines
+  # with horizontal tabulation characters.
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form 'foo.o: dependent.h',
+  # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # '$object: dependent.h' and one to simply 'dependent.h:'.
+  sed -e "s/^[ $tab][ $tab]*/  /" -e "s,^[^:]*:,$object :," \
+    < "$tmpdepfile" > "$depfile"
+  sed '
+    s/[ '"$tab"'][ '"$tab"']*/ /g
+    s/^ *//
+    s/ *\\*$//
+    s/^[^:]*: *//
+    /^$/d
+    /:$/d
+    s/$/ :/
+  ' < "$tmpdepfile" >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp2)
+  # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+  # compilers, which have integrated preprocessors.  The correct option
+  # to use with these is +Maked; it writes dependencies to a file named
+  # 'foo.d', which lands next to the object file, wherever that
+  # happens to be.
+  # Much of this is similar to the tru64 case; see comments there.
+  dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+  test "x$dir" = "x$object" && dir=
+  base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir.libs/$base.d
+    "$@" -Wc,+Maked
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    "$@" +Maked
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+     rm -f "$tmpdepfile1" "$tmpdepfile2"
+     exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+    # Add 'dependent.h:' lines.
+    sed -ne '2,${
+	       s/^ *//
+	       s/ \\*$//
+	       s/$/:/
+	       p
+	     }' "$tmpdepfile" >> "$depfile"
+  else
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile" "$tmpdepfile2"
+  ;;
+
+tru64)
+   # The Tru64 compiler uses -MD to generate dependencies as a side
+   # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+   # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+   # dependencies in 'foo.d' instead, so we check for that too.
+   # Subdirectories are respected.
+   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+   test "x$dir" = "x$object" && dir=
+   base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+   if test "$libtool" = yes; then
+      # With Tru64 cc, shared objects can also be used to make a
+      # static library.  This mechanism is used in libtool 1.4 series to
+      # handle both shared and static libraries in a single compilation.
+      # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+      #
+      # With libtool 1.5 this exception was removed, and libtool now
+      # generates 2 separate objects for the 2 libraries.  These two
+      # compilations output dependencies in $dir.libs/$base.o.d and
+      # in $dir$base.o.d.  We have to check for both files, because
+      # one of the two compilations can be disabled.  We should prefer
+      # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+      # automatically cleaned when .libs/ is deleted, while ignoring
+      # the former would cause a distcleancheck panic.
+      tmpdepfile1=$dir.libs/$base.lo.d   # libtool 1.4
+      tmpdepfile2=$dir$base.o.d          # libtool 1.5
+      tmpdepfile3=$dir.libs/$base.o.d    # libtool 1.5
+      tmpdepfile4=$dir.libs/$base.d      # Compaq CCC V6.2-504
+      "$@" -Wc,-MD
+   else
+      tmpdepfile1=$dir$base.o.d
+      tmpdepfile2=$dir$base.d
+      tmpdepfile3=$dir$base.d
+      tmpdepfile4=$dir$base.d
+      "$@" -MD
+   fi
+
+   stat=$?
+   if test $stat -eq 0; then :
+   else
+      rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+      exit $stat
+   fi
+
+   for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+   do
+     test -f "$tmpdepfile" && break
+   done
+   if test -f "$tmpdepfile"; then
+      sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+      sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+   else
+      echo "#dummy" > "$depfile"
+   fi
+   rm -f "$tmpdepfile"
+   ;;
+
+msvc7)
+  if test "$libtool" = yes; then
+    showIncludes=-Wc,-showIncludes
+  else
+    showIncludes=-showIncludes
+  fi
+  "$@" $showIncludes > "$tmpdepfile"
+  stat=$?
+  grep -v '^Note: including file: ' "$tmpdepfile"
+  if test "$stat" = 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The first sed program below extracts the file names and escapes
+  # backslashes for cygpath.  The second sed program outputs the file
+  # name when reading, but also accumulates all include files in the
+  # hold buffer in order to output them again at the end.  This only
+  # works with sed implementations that can handle large buffers.
+  sed < "$tmpdepfile" -n '
+/^Note: including file:  *\(.*\)/ {
+  s//\1/
+  s/\\/\\\\/g
+  p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+  s/.*/'"$tab"'/
+  G
+  p
+}' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvc7msys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for ':'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+  "$@" $dashmflag |
+    sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  tr ' ' "$nl" < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no eat=no
+  for arg
+  do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    if test $eat = yes; then
+      eat=no
+      continue
+    fi
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -arch)
+      eat=yes ;;
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix=`echo "$object" | sed 's/^.*\././'`
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  # makedepend may prepend the VPATH from the source file name to the object.
+  # No need to regex-escape $object, excess matching of '.' is harmless.
+  sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+  sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E |
+    sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+       -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+    sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+	set fnord "$@"
+	shift
+	shift
+	;;
+    *)
+	set fnord "$@" "$arg"
+	shift
+	shift
+	;;
+    esac
+  done
+  "$@" -E 2>/dev/null |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+  echo "$tab" >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvcmsys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/final/lib/External/ppcg/external.c b/final/lib/External/ppcg/external.c
new file mode 100644
index 0000000..3a63ffb
--- /dev/null
+++ b/final/lib/External/ppcg/external.c
@@ -0,0 +1,181 @@
+#include "assert.h"
+#include "stdio.h"
+#include "stdlib.h"
+
+#define die() { \
+  fprintf(stderr, "Dummy function %s called\n", __FUNCTION__); \
+  abort(); \
+}
+
+void pet_scop_compute_outer_to_any(){
+  die();
+}
+void pet_scop_compute_outer_to_inner(){
+  die();
+}
+void pet_tree_get_type(){
+  die();
+}
+void pet_tree_foreach_access_expr(){
+  die();
+}
+void pet_expr_get_ctx(){
+  die();
+}
+void pet_expr_access_is_read(){
+  die();
+}
+void pet_expr_access_is_write(){
+  die();
+}
+void pet_expr_access_get_tagged_may_read(){
+  die();
+}
+void pet_expr_access_get_tagged_may_write(){
+  die();
+}
+void pet_expr_access_get_must_write(){
+  die();
+}
+void pet_expr_access_get_index(){
+  die();
+}
+void pet_expr_access_get_ref_id(){
+  die();
+}
+void print_cpu(){
+  die();
+}
+
+void pet_stmt_print_body(){
+  die();
+}
+void pet_loc_get_start(){
+  die();
+}
+void pet_loc_get_end(){
+  die();
+}
+void pet_scop_collect_tagged_may_reads(){
+  die();
+}
+void pet_scop_collect_may_reads(){
+  die();
+}
+void pet_scop_collect_tagged_may_writes(){
+  die();
+}
+void pet_scop_collect_may_writes(){
+  die();
+}
+void pet_scop_collect_tagged_must_writes(){
+  die();
+}
+void pet_scop_collect_must_writes(){
+  die();
+}
+void pet_scop_collect_tagged_must_kills(){
+  die();
+}
+void pet_transform_C_source(){
+  die();
+}
+void pet_scop_print_original(){
+  die();
+}
+void pet_scop_free(){
+  die();
+}
+void pet_scop_align_params(){
+  die();
+}
+void pet_scop_can_build_ast_exprs(){
+  die();
+}
+void pet_scop_has_data_dependent_conditions(){
+  die();
+}
+void pet_tree_foreach_expr(){
+  die();
+}
+void pet_expr_foreach_call_expr(){
+  die();
+}
+void pet_stmt_is_kill(){
+  die();
+}
+void pet_options_args() {
+  die();
+}
+void ppcg_print_guarded() {
+  die();
+}
+void ppcg_version() {
+  die();
+}
+void pet_options_set_encapsulate_dynamic_control() {
+  die();
+}
+void generate_opencl() {
+  die();
+}
+void generate_cpu() {
+  die();
+}
+void pet_stmt_build_ast_exprs() {
+  die();
+}
+ void pet_scop_get_tagged_may_reads() {
+  die();
+}
+ void pet_scop_get_may_reads() {
+  die();
+}
+void pet_scop_get_may_writes() {
+  die();
+}
+void pet_scop_get_must_writes() {
+  die();
+}
+void pet_scop_get_tagged_may_writes() {
+  die();
+}
+void pet_scop_get_tagged_must_writes() {
+die();
+}
+void pet_scop_get_must_kills() {
+  die();
+}
+void pet_scop_get_tagged_must_kills() {
+  die();
+}
+void pet_expr_call_get_name() {
+  die();
+}
+void pet_expr_call_set_name() {
+  die();
+}
+void pet_expr_get_arg() {
+  die();
+}
+void pet_expr_new_cast() {
+  die();
+}
+void pet_expr_set_arg() {
+  die();
+}
+void pet_tree_copy() {
+  die();
+}
+void pet_tree_free() {
+  die();
+}
+void pet_tree_map_call_expr() {
+  die();
+}
+void pet_expr_access_get_may_read() {
+  die();
+}
+void pet_expr_access_get_may_write() {
+  die();
+}
diff --git a/final/lib/External/ppcg/gpu.c b/final/lib/External/ppcg/gpu.c
new file mode 100644
index 0000000..cfd998f
--- /dev/null
+++ b/final/lib/External/ppcg/gpu.c
@@ -0,0 +1,5849 @@
+/*
+ * Copyright 2010-2011 INRIA Saclay
+ * Copyright 2012-2013 Ecole Normale Superieure
+ * Copyright 2015-2016 Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isl/polynomial.h>
+#include <isl/union_set.h>
+#include <isl/aff.h>
+#include <isl/ilp.h>
+#include <isl/flow.h>
+#include <isl/schedule.h>
+#include <isl/schedule_node.h>
+#include <isl/options.h>
+#include <isl/ast_build.h>
+
+#include "cpu.h"
+#include "gpu.h"
+#include "gpu_array_tile.h"
+#include "gpu_group.h"
+#include "gpu_hybrid.h"
+#include "gpu_tree.h"
+#include "hybrid.h"
+#include "schedule.h"
+#include "ppcg_options.h"
+#include "print.h"
+#include "util.h"
+
+struct gpu_array_info;
+
+/* Return the name of the outer array (of structs) accessed by "access".
+ */
+static const char *get_outer_array_name(__isl_keep isl_map *access)
+{
+	isl_space *space;
+	const char *name;
+
+	space = isl_space_range(isl_map_get_space(access));
+	while (space && isl_space_is_wrapping(space))
+		space = isl_space_domain(isl_space_unwrap(space));
+	name = isl_space_get_tuple_name(space, isl_dim_set);
+	isl_space_free(space);
+
+	return name;
+}
+
+/* Collect all references to the given array and store pointers to them
+ * in array->refs.
+ */
+void collect_references(struct gpu_prog *prog,
+	struct gpu_array_info *array)
+{
+	int i;
+	int n;
+
+	n = 0;
+	for (i = 0; i < prog->n_stmts; ++i) {
+		struct gpu_stmt *stmt = &prog->stmts[i];
+		struct gpu_stmt_access *access;
+
+		for (access = stmt->accesses; access; access = access->next) {
+			const char *name;
+			name = get_outer_array_name(access->access);
+			if (name && !strcmp(array->name, name))
+				n++;
+		}
+	}
+
+	array->n_ref = n;
+	array->refs = isl_alloc_array(prog->ctx, struct gpu_stmt_access *, n);
+	assert(array->refs);
+
+	n = 0;
+	for (i = 0; i < prog->n_stmts; ++i) {
+		struct gpu_stmt *stmt = &prog->stmts[i];
+		struct gpu_stmt_access *access;
+
+		for (access = stmt->accesses; access; access = access->next) {
+			const char *name;
+			name = get_outer_array_name(access->access);
+			if (!name || strcmp(array->name, name))
+				continue;
+
+			array->refs[n++] = access;
+		}
+	}
+}
+
+/* Compute and return the extent of "array", taking into account the set of
+ * accessed elements.
+ *
+ * In particular, the extent in the outer dimension is taken
+ * from "accessed", while the extents in the remaining dimensions
+ * are taken from array->extent.
+ *
+ * The extent in the outer dimension cannot be taken from array->extent
+ * because that may be unbounded.  Furthermore, even if it is bounded,
+ * it may be larger than the piece of the array that is being accessed.
+ */
+static __isl_give isl_set *compute_extent(struct pet_array *array,
+	__isl_keep isl_set *accessed)
+{
+	int n_index;
+	isl_id *id;
+	isl_set *outer;
+	isl_set *extent;
+
+	extent = isl_set_copy(array->extent);
+
+	n_index = isl_set_dim(accessed, isl_dim_set);
+	if (n_index == 0)
+		return extent;
+
+	extent = isl_set_project_out(extent, isl_dim_set, 0, 1);
+	outer = isl_set_copy(accessed);
+	outer = isl_set_project_out(outer, isl_dim_set, 1, n_index - 1);
+	extent = isl_set_flat_product(outer, extent);
+	id = isl_set_get_tuple_id(accessed);
+	extent = isl_set_set_tuple_id(extent, id);
+
+	return extent;
+}
+
+/* Is the array "array" being extracted a read-only scalar?
+ *
+ * That is, is "array" a scalar that is never possibly written to.
+ * An array containing structures is never considered to be a scalar.
+ */
+static int is_read_only_scalar(struct gpu_array_info *array,
+	struct gpu_prog *prog)
+{
+	isl_set *space;
+	isl_union_map *write;
+	int empty;
+
+	if (array->has_compound_element)
+		return 0;
+	if (array->n_index != 0)
+		return 0;
+
+	write = isl_union_map_copy(prog->may_write);
+	space = isl_set_universe(isl_space_copy(array->space));
+	write = isl_union_map_intersect_range(write,
+						isl_union_set_from_set(space));
+	empty = isl_union_map_is_empty(write);
+	isl_union_map_free(write);
+
+	return empty;
+}
+
+/* Is "array" only accessed as individual, fixed elements?
+ * That is, does each access to "array" access a single, fixed element?
+ */
+isl_bool only_fixed_element_accessed(struct gpu_array_info *array)
+{
+	int i;
+
+	for (i = 0; i < array->n_ref; ++i)
+		if (!array->refs[i]->fixed_element)
+			return isl_bool_false;
+
+	return isl_bool_true;
+}
+
+/* Compute bounds on the host array "pa" based on the corresponding
+ * accessed elements in "arrays"
+ * and collect all references to the array.
+ * Store the results in "info".
+ *
+ * If the array is zero-dimensional and does not contain structures,
+ * i.e., if the array is a scalar, we check whether it is read-only.
+ * We also check whether the array is accessed at all.
+ */
+static int extract_array_info(struct gpu_prog *prog,
+	struct gpu_array_info *info, struct pet_array *pa,
+	__isl_keep isl_union_set *arrays)
+{
+	int empty;
+	const char *name;
+	int n_index;
+	isl_multi_pw_aff *bounds;
+	isl_set *accessed, *extent;
+
+	n_index = isl_set_dim(pa->extent, isl_dim_set);
+	name = isl_set_get_tuple_name(pa->extent);
+
+	info->space = isl_set_get_space(pa->extent);
+	info->name = strdup(name);
+	info->n_index = n_index;
+	info->linearize = prog->scop->options->linearize_device_arrays;
+
+	info->type = strdup(pa->element_type);
+	info->size = pa->element_size;
+	info->local = pa->declared && !pa->exposed;
+	info->has_compound_element = pa->element_is_record;
+	info->read_only_scalar = is_read_only_scalar(info, prog);
+
+	info->declared_extent = isl_set_copy(pa->extent);
+	accessed = isl_union_set_extract_set(arrays,
+					    isl_space_copy(info->space));
+	empty = isl_set_is_empty(accessed);
+	extent = compute_extent(pa, accessed);
+	isl_set_free(accessed);
+	info->extent = extent;
+	if (empty < 0)
+		return -1;
+	info->accessed = !empty;
+	bounds = ppcg_size_from_extent(isl_set_copy(extent));
+	bounds = isl_multi_pw_aff_gist(bounds, isl_set_copy(prog->context));
+	if (!bounds)
+		return -1;
+	if (!isl_multi_pw_aff_is_cst(bounds))
+		info->linearize = 1;
+	info->bound = bounds;
+
+	collect_references(prog, info);
+	info->only_fixed_element = only_fixed_element_accessed(info);
+
+	return 0;
+}
+
+/* Remove independence from the order constraints "order" on array "array".
+ * Since the pairs of iterations in the filter relation of an independence
+ * are guaranteed to be completely independent by the user, there is
+ * no need to ensure that live ranges are ordered along those pairs.
+ * We make an exception for local variables, though, as the independence
+ * guarantee does not apply to those.
+ *
+ * The order constraints are used in two places.
+ * Those on scalars are used in check_scalar_live_ranges to check if
+ * we need to force the scalar to be private.  Any non-local scalar
+ * should not be forced scalar if it only appears in independent loops.
+ * Those on non-scalars are added to the coincidence constraints
+ * in compute_schedule because we do not support any array expansion.
+ * Accesses to non-local arrays should not prevent a loop from being
+ * considered coincident so we should indeed remove those constraints
+ * from the order constraints.
+ */
+static __isl_give isl_union_map *remove_independences(struct gpu_prog *prog,
+	struct gpu_array_info *array, __isl_take isl_union_map *order)
+{
+	// We do not have independence information in Polly. Hence, make this
+	// function a no-op.
+	return order;
+	int i;
+
+	for (i = 0; i < prog->scop->pet->n_independence; ++i) {
+		struct pet_independence *pi = prog->scop->pet->independences[i];
+		if (isl_union_set_contains(pi->local, array->space))
+			continue;
+
+		order = isl_union_map_subtract(order,
+						isl_union_map_copy(pi->filter));
+	}
+
+	return order;
+}
+
+/* For each array in "prog", store the (untagged) order dependences
+ * derived from the array in array->dep_order.
+ * In particular, consider all references that access the given array
+ * and take the order dependences that have one of these references
+ * as source.  (Since an order dependence relates two references to
+ * the same array, the target of these order dependences will also
+ * be one of these references.)
+ * Additionally, store the union of these array->dep_order relations
+ * for all arrays that cannot be mapped to private memory in prog->array_order.
+ */
+void collect_order_dependences(struct gpu_prog *prog)
+{
+	int i;
+	isl_space *space;
+	isl_union_map *accesses;
+
+	space = isl_union_map_get_space(prog->read);
+	prog->array_order = isl_union_map_empty(space);
+
+	accesses = isl_union_map_copy(prog->scop->tagged_reads);
+	accesses = isl_union_map_union(accesses,
+			    isl_union_map_copy(prog->scop->tagged_may_writes));
+	accesses = isl_union_map_universe(accesses);
+	accesses = isl_union_map_apply_range(accesses,
+					    isl_union_map_copy(prog->to_outer));
+
+	for (i = 0; i < prog->n_array; ++i) {
+		struct gpu_array_info *array = &prog->array[i];
+		isl_set *set;
+		isl_union_set *uset;
+		isl_union_map *order;
+
+		set = isl_set_universe(isl_space_copy(array->space));
+		uset = isl_union_set_from_set(set);
+		uset = isl_union_map_domain(
+		    isl_union_map_intersect_range(isl_union_map_copy(accesses),
+						    uset));
+		order = isl_union_map_copy(prog->scop->tagged_dep_order);
+		order = isl_union_map_intersect_domain(order, uset);
+		order = isl_union_map_zip(order);
+		order = isl_union_set_unwrap(isl_union_map_domain(order));
+		order = remove_independences(prog, array, order);
+		array->dep_order = order;
+
+		if (gpu_array_can_be_private(array))
+			continue;
+
+		prog->array_order = isl_union_map_union(prog->array_order,
+					isl_union_map_copy(array->dep_order));
+	}
+
+	isl_union_map_free(accesses);
+}
+
+/* Construct a gpu_array_info for each array referenced by prog->scop and
+ * collect them in prog->array.
+ *
+ * The sizes are based on the extents and the set of possibly accessed
+ * elements by "prog".
+ * If there are any member accesses involved, then they are first mapped
+ * to the outer arrays of structs.
+ * Only extract gpu_array_info entries for these outer arrays.
+ *
+ * If we are allowing live range reordering, then also set
+ * the dep_order field.  Otherwise leave it NULL.
+ */
+static int collect_array_info(struct gpu_prog *prog)
+{
+	int i;
+	int r = 0;
+	isl_union_set *arrays;
+
+	arrays = isl_union_map_range(isl_union_map_copy(prog->read));
+	arrays = isl_union_set_union(arrays,
+		    isl_union_map_range(isl_union_map_copy(prog->may_write)));
+
+	arrays = isl_union_set_apply(arrays,
+					isl_union_map_copy(prog->to_outer));
+
+	arrays = isl_union_set_coalesce(arrays);
+
+	prog->n_array = prog->scop->pet->n_array;
+	prog->array = isl_calloc_array(prog->ctx,
+				     struct gpu_array_info, prog->n_array);
+	assert(prog->array);
+	prog->n_array = 0;
+	for (i = 0; i < prog->scop->pet->n_array; ++i) {
+		isl_bool field;
+
+		field = isl_set_is_wrapping(prog->scop->pet->arrays[i]->extent);
+		if (field < 0)
+			break;
+		if (field)
+			continue;
+		if (extract_array_info(prog, &prog->array[prog->n_array++],
+					prog->scop->pet->arrays[i], arrays) < 0)
+			r = -1;
+	}
+	if (i < prog->scop->pet->n_array)
+		r = -1;
+
+	isl_union_set_free(arrays);
+
+	if (prog->scop->options->live_range_reordering)
+		collect_order_dependences(prog);
+
+	return r;
+}
+
+static void free_array_info(struct gpu_prog *prog)
+{
+	int i;
+
+	for (i = 0; i < prog->n_array; ++i) {
+		free(prog->array[i].type);
+		free(prog->array[i].name);
+		isl_multi_pw_aff_free(prog->array[i].bound);
+		isl_ast_expr_free(prog->array[i].bound_expr);
+		isl_space_free(prog->array[i].space);
+		isl_set_free(prog->array[i].declared_extent);
+		isl_set_free(prog->array[i].extent);
+		isl_ast_expr_free(prog->array[i].declared_size);
+		free(prog->array[i].refs);
+		isl_union_map_free(prog->array[i].dep_order);
+	}
+	free(prog->array);
+}
+
+/* Check if a gpu array is a scalar.  A scalar is a value that is not stored
+ * as an array or through a pointer reference, but as a single data element.
+ * At the moment, scalars are represented as zero-dimensional arrays.
+ * Note that the single data element may be an entire structure.
+ */
+int gpu_array_is_scalar(struct gpu_array_info *array)
+{
+	return array->n_index == 0;
+}
+
+/* Can "array" be mapped to private memory?
+ * That is, is it only accessed as individual elements with
+ * constant index expressions?
+ */
+isl_bool gpu_array_can_be_private(struct gpu_array_info *array)
+{
+	if (!array)
+		return isl_bool_error;
+	return array->only_fixed_element;
+}
+
+/* Is "array" a read-only scalar?
+ */
+int gpu_array_is_read_only_scalar(struct gpu_array_info *array)
+{
+	return array->read_only_scalar;
+}
+
+/* Does "array" need to be allocated on the device?
+ * If it is a read-only scalar, then it will be passed as an argument
+ * to the kernel and therefore does not require any allocation.
+ * If this device memory is not accessed at all, then it does not
+ * need to be allocated either.
+ */
+int gpu_array_requires_device_allocation(struct gpu_array_info *array)
+{
+	if (gpu_array_is_read_only_scalar(array))
+		return 0;
+	if (!array->global)
+		return 0;
+	return 1;
+}
+
+/* Return the set of parameter values for which the array has a positive
+ * size in all dimensions.
+ * If the sizes are only valid for some parameter values, then those
+ * constraints are also taken into account.
+ */
+__isl_give isl_set *gpu_array_positive_size_guard(struct gpu_array_info *array)
+{
+	int i;
+	isl_space *space;
+	isl_set *guard;
+
+	if (!array)
+		return NULL;
+
+	space = isl_space_params(isl_space_copy(array->space));
+	guard = isl_set_universe(space);
+
+	for (i = 0; i < array->n_index; ++i) {
+		isl_pw_aff *bound;
+		isl_set *guard_i, *zero;
+
+		bound = isl_multi_pw_aff_get_pw_aff(array->bound, i);
+		guard_i = isl_pw_aff_nonneg_set(isl_pw_aff_copy(bound));
+		zero = isl_pw_aff_zero_set(bound);
+		guard_i = isl_set_subtract(guard_i, zero);
+		guard = isl_set_intersect(guard, guard_i);
+	}
+
+	return guard;
+}
+
+/* Internal data structure for extract_size_of_type.
+ * "type" specifies the name of the space that we want to extract.
+ * "res" is used to store the subset of that space.
+ */
+struct ppcg_extract_size_data {
+	const char *type;
+	isl_set *res;
+};
+
+/* This function is called for each set in a union_set.
+ * If the name of the set matches data->type, we store the
+ * set in data->res.
+ */
+static isl_stat extract_size_of_type(__isl_take isl_set *size, void *user)
+{
+	struct ppcg_extract_size_data *data = user;
+	const char *name;
+
+	name = isl_set_get_tuple_name(size);
+	if (name && !strcmp(name, data->type)) {
+		data->res = size;
+		return isl_stat_error;
+	}
+
+	isl_set_free(size);
+	return isl_stat_ok;
+}
+
+/* Given a union map { kernel[i] -> *[...] },
+ * return the range in the space called "type" for the kernel with
+ * sequence number "id".
+ */
+static __isl_give isl_set *extract_sizes(__isl_keep isl_union_map *sizes,
+	const char *type, int id)
+{
+	isl_space *space;
+	isl_set *dom;
+	isl_union_set *local_sizes;
+	struct ppcg_extract_size_data data = { type, NULL };
+
+	if (!sizes)
+		return NULL;
+
+	space = isl_union_map_get_space(sizes);
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, 1);
+	space = isl_space_set_tuple_name(space, isl_dim_set, "kernel");
+	dom = isl_set_universe(space);
+	dom = isl_set_fix_si(dom, isl_dim_set, 0, id);
+
+	local_sizes = isl_union_set_apply(isl_union_set_from_set(dom),
+					isl_union_map_copy(sizes));
+	isl_union_set_foreach_set(local_sizes, &extract_size_of_type, &data);
+	isl_union_set_free(local_sizes);
+	return data.res;
+}
+
+/* Given a singleton set, extract the first (at most *len) elements
+ * of the single integer tuple into *sizes and update *len if needed.
+ */
+static void read_sizes_from_set(__isl_take isl_set *set, int *sizes, int *len)
+{
+	int i;
+	int dim;
+
+	if (!set)
+		return;
+
+	dim = isl_set_dim(set, isl_dim_set);
+	if (dim < *len)
+		*len = dim;
+
+	for (i = 0; i < *len; ++i) {
+		isl_val *v;
+
+		v = isl_set_plain_get_val_if_fixed(set, isl_dim_set, i);
+		assert(v);
+
+		sizes[i] = isl_val_get_num_si(v);
+		isl_val_free(v);
+	}
+
+	isl_set_free(set);
+}
+
+/* Add the map { kernel[id] -> type[sizes] } to gen->used_sizes,
+ * if the option debug->dump_sizes is set.
+ */
+static void set_used_sizes(struct gpu_gen *gen, const char *type, int id,
+	int *sizes, int len)
+{
+	int i;
+	isl_space *space;
+	isl_map *map;
+
+	if (!gen->options->debug->dump_sizes)
+		return;
+
+	space = isl_union_map_get_space(gen->used_sizes);
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, 1);
+	space = isl_space_set_tuple_name(space, isl_dim_set, "kernel");
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, len);
+	space = isl_space_set_tuple_name(space, isl_dim_out, type);
+
+	map = isl_map_universe(space);
+	map = isl_map_fix_si(map, isl_dim_in, 0, id);
+	for (i = 0; i < len; ++i)
+		map = isl_map_fix_si(map, isl_dim_out, i, sizes[i]);
+
+	gen->used_sizes = isl_union_map_add_map(gen->used_sizes, map);
+}
+
+/* Extract user specified "tile" sizes from the "sizes" command line option,
+ * defaulting to option->tile_size in each dimension.
+ * *tile_len contains the maximum number of tile sizes needed.
+ * Update *tile_len to the number of specified tile sizes, if any, and
+ * return a pointer to the tile sizes (or NULL on error).
+ * Add the effectively used sizes to gen->used_sizes.
+ */
+static int *read_tile_sizes(struct gpu_gen *gen, int *tile_len)
+{
+	int n;
+	int *tile_size;
+	isl_set *size;
+
+	tile_size = isl_alloc_array(gen->ctx, int, *tile_len);
+	if (!tile_size)
+		return NULL;
+	for (n = 0; n < *tile_len; ++n)
+		tile_size[n] = gen->options->tile_size;
+
+	size = extract_sizes(gen->sizes, "tile", gen->kernel_id);
+	read_sizes_from_set(size, tile_size, tile_len);
+	set_used_sizes(gen, "tile", gen->kernel_id, tile_size, *tile_len);
+
+	return tile_size;
+}
+
+/* Extract user specified "block" sizes from the "sizes" command line option,
+ * after filling in some potentially useful defaults.
+ */
+static void read_block_sizes(struct ppcg_kernel *kernel,
+	__isl_keep isl_union_map *sizes)
+{
+	isl_set *size;
+
+	if (kernel->n_block > 3)
+		kernel->n_block = 3;
+	switch (kernel->n_block) {
+	case 1:
+		kernel->block_dim[0] = 512;
+		break;
+	case 2:
+		kernel->block_dim[0] = 32;
+		kernel->block_dim[1] = 16;
+		break;
+	default:
+		kernel->block_dim[0] = 32;
+		kernel->block_dim[1] = 4;
+		kernel->block_dim[2] = 4;
+		break;
+	}
+
+	size = extract_sizes(sizes, "block", kernel->id);
+	read_sizes_from_set(size, kernel->block_dim, &kernel->n_block);
+}
+
+/* Extract user specified "grid" sizes from the "sizes" command line option,
+ * after filling in some potentially useful defaults.
+ */
+static void read_grid_sizes(struct ppcg_kernel *kernel,
+	__isl_keep isl_union_map *sizes)
+{
+	isl_set *size;
+
+	if (kernel->n_grid > 2)
+		kernel->n_grid = 2;
+	switch (kernel->n_grid) {
+	case 1:
+		kernel->grid_dim[0] = 32768;
+		break;
+	default:
+		kernel->grid_dim[0] = 256;
+		kernel->grid_dim[1] = 256;
+		break;
+	}
+
+	size = extract_sizes(sizes, "grid", kernel->id);
+	read_sizes_from_set(size, kernel->grid_dim, &kernel->n_grid);
+}
+
+/* Extract user specified grid and block sizes from the gen->sizes
+ * command line option after filling in some potentially useful defaults.
+ * Store the extracted sizes in "kernel".
+ * Add the effectively used sizes to gen->used_sizes.
+ */
+static void read_grid_and_block_sizes(struct ppcg_kernel *kernel,
+	struct gpu_gen *gen)
+{
+	read_block_sizes(kernel, gen->sizes);
+	read_grid_sizes(kernel, gen->sizes);
+	set_used_sizes(gen, "block", kernel->id,
+					    kernel->block_dim, kernel->n_block);
+	set_used_sizes(gen, "grid", kernel->id,
+					    kernel->grid_dim, kernel->n_grid);
+}
+
+static void *free_stmts(struct gpu_stmt *stmts, int n)
+{
+	int i;
+
+	if (!stmts)
+		return NULL;
+
+	for (i = 0; i < n; ++i) {
+		struct gpu_stmt_access *access, *next;
+
+		for (access = stmts[i].accesses; access; access = next) {
+			next = access->next;
+			isl_id_free(access->ref_id);
+			isl_map_free(access->access);
+			isl_map_free(access->tagged_access);
+			free(access);
+		}
+
+		isl_id_free(stmts[i].id);
+	}
+	free(stmts);
+
+	return NULL;
+}
+
+/* Add parameters p[i] with identifiers "ids" to "set",
+ * with bounds to 0 <= p[i] < size[i].
+ */
+__isl_give isl_set *add_bounded_parameters(__isl_take isl_set *set,
+	int *size, __isl_keep isl_id_list *ids)
+{
+	int i, len;
+	unsigned nparam;
+
+	len = isl_id_list_n_id(ids);
+	nparam = isl_set_dim(set, isl_dim_param);
+	set = isl_set_add_dims(set, isl_dim_param, len);
+
+	for (i = 0; i < len; ++i) {
+		isl_id *id;
+
+		id = isl_id_list_get_id(ids, i);
+		set = isl_set_set_dim_id(set, isl_dim_param, nparam + i, id);
+		set = isl_set_lower_bound_si(set, isl_dim_param, nparam + i, 0);
+		set = isl_set_upper_bound_si(set, isl_dim_param,
+					    nparam + i, size[i] - 1);
+	}
+
+	return set;
+}
+
+/* Add "len" parameters p[i] with identifiers "ids" and intersect "set"
+ * with
+ *
+ *	{ : 0 <= p[i] < size[i] }
+ *
+ * or an overapproximation.
+ */
+static __isl_give isl_set *add_bounded_parameters_dynamic(
+	__isl_take isl_set *set, __isl_keep isl_multi_pw_aff *size,
+	__isl_keep isl_id_list *ids)
+{
+	int i, len;
+	unsigned nparam;
+	isl_space *space;
+	isl_local_space *ls;
+
+	len = isl_multi_pw_aff_dim(size, isl_dim_out);
+	nparam = isl_set_dim(set, isl_dim_param);
+	set = isl_set_add_dims(set, isl_dim_param, len);
+
+	for (i = 0; i < len; ++i) {
+		isl_id *id;
+
+		id = isl_id_list_get_id(ids, i);
+		set = isl_set_set_dim_id(set, isl_dim_param, nparam + i, id);
+	}
+
+	space = isl_space_params(isl_set_get_space(set));
+	ls = isl_local_space_from_space(space);
+	for (i = 0; i < len; ++i) {
+		isl_pw_aff *param, *size_i, *zero;
+		isl_set *bound;
+
+		param = isl_pw_aff_var_on_domain(isl_local_space_copy(ls),
+						isl_dim_param, nparam + i);
+
+		size_i = isl_multi_pw_aff_get_pw_aff(size, i);
+		bound = isl_pw_aff_lt_set(isl_pw_aff_copy(param), size_i);
+		bound = isl_set_from_basic_set(isl_set_simple_hull(bound));
+		set = isl_set_intersect_params(set, bound);
+
+		zero = isl_pw_aff_zero_on_domain(isl_local_space_copy(ls));
+		bound = isl_pw_aff_ge_set(param, zero);
+		set = isl_set_intersect_params(set, bound);
+	}
+	isl_local_space_free(ls);
+
+	return set;
+}
+
+/* Return the union of all tagged access relations in the group.
+ */
+static __isl_give isl_union_map *group_tagged_access_relation(
+	struct gpu_array_ref_group *group)
+{
+	int i;
+	isl_union_map *access;
+
+	access = isl_union_map_empty(isl_map_get_space(group->access));
+	for (i = 0; i < group->n_ref; ++i) {
+		isl_map *map_i;
+
+		map_i = isl_map_copy(group->refs[i]->tagged_access);
+		access = isl_union_map_union(access,
+					    isl_union_map_from_map(map_i));
+	}
+
+	return access;
+}
+
+/* Return the extent of "array", recomputed from the bounds.
+ * The recomputed extent may be simpler than the original extent.
+ */
+static __isl_give isl_set *array_extent(struct gpu_array_info *array)
+{
+	int i;
+	isl_id *id;
+	isl_space *space;
+	isl_local_space *ls;
+	isl_set *extent;
+
+	id = isl_set_get_tuple_id(array->extent);
+	space = isl_set_get_space(array->extent);
+	extent = isl_set_universe(isl_space_copy(space));
+	ls = isl_local_space_from_space(space);
+	for (i = 0; i < array->n_index; ++i) {
+		isl_pw_aff *bound;
+		isl_aff *aff;
+		isl_pw_aff *index;
+		isl_set *lt;
+
+		extent = isl_set_lower_bound_si(extent, isl_dim_set, i, 0);
+
+		aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
+						isl_dim_set, i);
+		index = isl_pw_aff_from_aff(aff);
+		bound = isl_multi_pw_aff_get_pw_aff(array->bound, i);
+		bound = isl_pw_aff_from_range(bound);
+		bound = isl_pw_aff_add_dims(bound, isl_dim_in, array->n_index);
+		bound = isl_pw_aff_set_tuple_id(bound, isl_dim_in,
+						isl_id_copy(id));
+		lt = isl_pw_aff_lt_set(index, bound);
+		extent = isl_set_intersect(extent, lt);
+	}
+	isl_local_space_free(ls);
+	isl_id_free(id);
+
+	return extent;
+}
+
+/* Return a map from the first group->shared_tile->depth dimensions
+ * of the computed schedule to the array tile in
+ * global memory that corresponds to the shared memory copy.
+ *
+ * In particular, return a map
+ *
+ *	{ D[i] -> A[a] }
+ *
+ * with constraints
+ *
+ *	tile_offset(i) <= a <= tile_offset(i) + tile_size - 1		(1)
+ *
+ * and
+ *
+ *	0 <= a <= array_size - 1					(2)
+ *
+ * Note that if some stride has been detected (i.e., when
+ * group->shared_tile->bound[i].shift is set), then a in (1) refers
+ * to the shifted and scaled down version.
+ *
+ * Constraints (1) are obtained by mapping the size constraints on the
+ * shared/private memory tile back to the access relation.
+ * Constraints (2) are obtained from the (recomputed) extent.
+ */
+static __isl_give isl_map *group_tile(struct gpu_array_ref_group *group)
+{
+	int i;
+	int n_index = group->array->n_index;
+	isl_map *tile;
+	isl_space *space;
+	isl_set *local;
+	isl_set *extent;
+
+	space = isl_multi_aff_get_space(group->shared_tile->tiling);
+	space = isl_space_range(space);
+	local = isl_set_universe(space);
+	for (i = 0; i < n_index; ++i) {
+		isl_val *bound;
+
+		local = isl_set_lower_bound_si(local, isl_dim_set, i, 0);
+		bound = isl_val_copy(group->shared_tile->bound[i].size);
+		bound = isl_val_sub_ui(bound, 1);
+		local = isl_set_upper_bound_val(local, isl_dim_set, i, bound);
+	}
+	local = isl_set_preimage_multi_aff(local,
+				isl_multi_aff_copy(group->shared_tile->tiling));
+	tile = isl_set_unwrap(local);
+	extent = array_extent(group->array);
+	tile = isl_map_intersect_range(tile, extent);
+
+	return tile;
+}
+
+/* Given a mapping "iterator_map" from the AST schedule to a domain,
+ * return the corresponding mapping from the AST schedule to
+ * to the outer kernel->copy_schedule_dim dimensions of
+ * the schedule computed by PPCG for this kernel.
+ *
+ * Note that kernel->copy_schedule_dim is at least as large as
+ * the largest depth of any array reference group associated to the kernel.
+ * This is needed as the returned schedule is used to extract a mapping
+ * to the outer tile->depth dimensions in transform_index.
+ */
+static __isl_give isl_pw_multi_aff *compute_sched_to_copy(
+	struct ppcg_kernel *kernel, __isl_take isl_pw_multi_aff *iterator_map)
+{
+	isl_union_pw_multi_aff *upma;
+	isl_pw_multi_aff *pma;
+	isl_space *space;
+
+	space = isl_space_range(isl_pw_multi_aff_get_space(iterator_map));
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out,
+					kernel->copy_schedule_dim);
+
+	upma = isl_union_pw_multi_aff_copy(kernel->copy_schedule);
+	pma = isl_union_pw_multi_aff_extract_pw_multi_aff(upma, space);
+	isl_union_pw_multi_aff_free(upma);
+
+	return isl_pw_multi_aff_pullback_pw_multi_aff(pma, iterator_map);
+}
+
+/* If max_shared_memory is not set to infinity (-1), then make
+ * sure that the total amount of shared memory required by the
+ * array reference groups mapped to shared memory by "kernel"
+ * is no larger than this maximum.
+ *
+ * We apply a greedy approach and discard (keep in global memory)
+ * those groups that would result in a total memory size that
+ * is larger than the maximum.
+ *
+ * This function should be called after any function that may
+ * affect the decision on whether to place a reference group
+ * in private, shared or global memory.
+ */
+static void check_shared_memory_bound(struct ppcg_kernel *kernel)
+{
+	int i, j;
+	isl_val *left, *size;
+
+	if (kernel->options->max_shared_memory < 0)
+		return;
+
+	left = isl_val_int_from_si(kernel->ctx,
+				    kernel->options->max_shared_memory);
+
+	for (i = 0; i < kernel->n_array; ++i) {
+		struct gpu_local_array_info *local = &kernel->array[i];
+
+		for (j = 0; j < local->n_group; ++j) {
+			struct gpu_array_ref_group *group;
+			enum ppcg_group_access_type type;
+
+			group = local->groups[j];
+			type = gpu_array_ref_group_type(group);
+			if (type != ppcg_access_shared)
+				continue;
+
+			size = gpu_array_tile_size(group->shared_tile);
+			size = isl_val_mul_ui(size, local->array->size);
+
+			if (isl_val_le(size, left)) {
+				left = isl_val_sub(left, size);
+				continue;
+			}
+			isl_val_free(size);
+
+			group->shared_tile =
+					gpu_array_tile_free(group->shared_tile);
+		}
+	}
+
+	isl_val_free(left);
+}
+
+/* Mark all arrays of "kernel" that have an array reference group
+ * that is not mapped to private or shared memory as
+ * accessing the corresponding global device memory.
+ */
+static void mark_global_arrays(struct ppcg_kernel *kernel)
+{
+	int i, j;
+
+	for (i = 0; i < kernel->n_array; ++i) {
+		struct gpu_local_array_info *local = &kernel->array[i];
+
+		if (local->global)
+			continue;
+		for (j = 0; j < local->n_group; ++j) {
+			if (gpu_array_ref_group_tile(local->groups[j]))
+				continue;
+
+			local->global = 1;
+			local->array->global = 1;
+			break;
+		}
+	}
+}
+
+/* Compute a tiling for all the array reference groups in "kernel".
+ */
+static void compute_group_tilings(struct ppcg_kernel *kernel)
+{
+	int i, j;
+
+	for (i = 0; i < kernel->n_array; ++i) {
+		struct gpu_local_array_info *array = &kernel->array[i];
+
+		for (j = 0; j < array->n_group; ++j)
+			gpu_array_ref_group_compute_tiling(array->groups[j]);
+	}
+}
+
+/* Compute the effective grid size as a list of the sizes in each dimension.
+ *
+ * The grid size specified by the user or set by default
+ * in read_grid_sizes() and applied by the block filter,
+ * may be too large for the given code in the sense that
+ * it may contain blocks that don't need to execute anything.
+ * We therefore don't return this grid size, but instead the
+ * smallest grid size that ensures that all blocks that actually
+ * execute code are included in the grid.
+ *
+ * We first extract a description of the grid, i.e., the possible values
+ * of the block ids, from the domain elements in "domain" and
+ * kernel->block_filter.
+ * The block ids are parameters in kernel->block_filter.
+ * We simply need to change them into set dimensions.
+ *
+ * Then, for each block dimension, we compute the maximal value of the block id
+ * and add one.
+ */
+static __isl_give isl_multi_pw_aff *extract_grid_size(
+	struct ppcg_kernel *kernel, __isl_take isl_union_set *domain)
+{
+	int i;
+	isl_set *grid;
+	isl_set *context;
+	isl_multi_pw_aff *size;
+
+	domain = isl_union_set_intersect(domain,
+				    isl_union_set_copy(kernel->block_filter));
+	grid = isl_union_set_params(domain);
+	grid = isl_set_from_params(grid);
+	grid = isl_set_add_dims(grid, isl_dim_set, kernel->n_grid);
+	for (i = 0; i < kernel->n_grid; ++i) {
+		int pos;
+		isl_id *id;
+
+		id = isl_id_list_get_id(kernel->block_ids, i);
+		pos = isl_set_find_dim_by_id(grid, isl_dim_param, id);
+		isl_id_free(id);
+		assert(pos >= 0);
+		grid = isl_set_equate(grid, isl_dim_param, pos, isl_dim_set, i);
+		grid = isl_set_project_out(grid, isl_dim_param, pos, 1);
+	}
+
+	grid = isl_set_coalesce(grid);
+	size = ppcg_size_from_extent(grid);
+	context = isl_set_params(isl_set_copy(kernel->context));
+	return isl_multi_pw_aff_gist(size, context);
+}
+
+/* Compute the size of a fixed bounding box around the origin and "set",
+ * where "set" is assumed to contain only non-negative elements,
+ * and store the results in "size".
+ * In particular, compute the maximal value of "set" in each direction
+ * and add one.
+ */
+static void extract_fixed_size(__isl_take isl_set *set, int *size)
+{
+	int i, n;
+	isl_local_space *ls;
+	isl_aff *obj;
+
+	n = isl_set_dim(set, isl_dim_set);
+	ls = isl_local_space_from_space(isl_set_get_space(set));
+	obj = isl_aff_zero_on_domain(ls);
+	for (i = 0; i < n; ++i) {
+		isl_val *max;
+
+		obj = isl_aff_set_coefficient_si(obj, isl_dim_in, i, 1);
+		max = isl_set_max_val(set, obj);
+		size[i] = isl_val_get_num_si(max) + 1;
+		isl_val_free(max);
+		obj = isl_aff_set_coefficient_si(obj, isl_dim_in, i, 0);
+	}
+	isl_aff_free(obj);
+	isl_set_free(set);
+}
+
+/* Compute the effective block size as a list of the sizes in each dimension
+ * and store the sizes in kernel->block_dim.
+ *
+ * The block size specified by the user or set by default
+ * in read_block_sizes() and applied by the thread filter,
+ * may be too large for the given code in the sense that
+ * it may contain threads that don't need to execute anything.
+ * We therefore update this block size in kernel->block_dim
+ * to the smallest block size that ensures that all threads
+ * that actually execute code are included in the block.
+ *
+ * The set of possible values of the thread ids is obtained from
+ * the domain elements "domain" and kernel->thread_filter.
+ * The current implementation eliminates all parameters, ensuring
+ * that the size is a fixed constant in each dimension.
+ * In principle we could also compute parametric sizes.
+ * We would have to make sure to project out all b%d and t%d parameters,
+ * however.
+ */
+static isl_stat extract_block_size(struct ppcg_kernel *kernel,
+	__isl_take isl_union_set *domain)
+{
+	int i;
+	int nparam;
+	isl_set *block;
+
+	domain = isl_union_set_intersect(domain,
+				    isl_union_set_copy(kernel->thread_filter));
+	block = isl_union_set_params(domain);
+	block = isl_set_from_params(block);
+	block = isl_set_add_dims(block, isl_dim_set, kernel->n_block);
+	for (i = 0; i < kernel->n_block; ++i) {
+		int pos;
+		isl_id *id;
+
+		if (!block)
+			return isl_stat_error;
+
+		id = isl_id_list_get_id(kernel->thread_ids, i);
+		pos = isl_set_find_dim_by_id(block, isl_dim_param, id);
+		isl_id_free(id);
+		if (pos < 0)
+			isl_die(isl_set_get_ctx(block), isl_error_internal,
+				"missing constraints on thread identifier",
+				block = isl_set_free(block));
+		block = isl_set_equate(block, isl_dim_param, pos,
+					isl_dim_set, i);
+	}
+	nparam = isl_set_dim(block, isl_dim_param);
+	block = isl_set_project_out(block, isl_dim_param, 0, nparam);
+
+	if (!block)
+		return isl_stat_error;
+
+	extract_fixed_size(block, kernel->block_dim);
+
+	return isl_stat_ok;
+}
+
+struct ppcg_kernel *ppcg_kernel_free(struct ppcg_kernel *kernel)
+{
+	int i, j;
+
+	if (!kernel)
+		return NULL;
+
+	isl_id_list_free(kernel->block_ids);
+	isl_id_list_free(kernel->thread_ids);
+	isl_multi_pw_aff_free(kernel->grid_size);
+	isl_ast_expr_free(kernel->grid_size_expr);
+	isl_set_free(kernel->context);
+	isl_union_set_free(kernel->core);
+	isl_union_set_free(kernel->arrays);
+	isl_union_pw_multi_aff_free(kernel->contraction);
+	isl_union_set_free(kernel->expanded_domain);
+	isl_space_free(kernel->space);
+	isl_ast_node_free(kernel->tree);
+	isl_union_set_free(kernel->block_filter);
+	isl_union_set_free(kernel->thread_filter);
+	isl_union_pw_multi_aff_free(kernel->copy_schedule);
+	isl_union_set_free(kernel->sync_writes);
+
+	for (i = 0; i < kernel->n_array; ++i) {
+		struct gpu_local_array_info *array = &kernel->array[i];
+
+		for (j = 0; j < array->n_group; ++j)
+			gpu_array_ref_group_free(array->groups[j]);
+		free(array->groups);
+
+		isl_multi_pw_aff_free(array->bound);
+		isl_ast_expr_free(array->bound_expr);
+	}
+	free(kernel->array);
+
+	for (i = 0; i < kernel->n_var; ++i) {
+		free(kernel->var[i].name);
+		isl_vec_free(kernel->var[i].size);
+	}
+	free(kernel->var);
+
+	free(kernel);
+
+	return NULL;
+}
+
+/* Wrapper around ppcg_kernel_free for use as a isl_id_set_free_user callback.
+ */
+static void ppcg_kernel_free_wrap(void *user)
+{
+	struct ppcg_kernel *kernel = user;
+
+	ppcg_kernel_free(kernel);
+}
+
+static void create_kernel_var(isl_ctx *ctx, struct gpu_array_ref_group *group,
+	struct ppcg_kernel_var *var)
+{
+	int j;
+	struct gpu_array_tile *tile;
+	isl_printer *p;
+
+	var->array = group->array;
+
+	var->type = gpu_array_ref_group_type(group);
+	tile = gpu_array_ref_group_tile(group);
+
+	p = isl_printer_to_str(ctx);
+	p = gpu_array_ref_group_print_name(group, p);
+	var->name = isl_printer_get_str(p);
+	isl_printer_free(p);
+
+	var->size = isl_vec_alloc(ctx, group->array->n_index);
+
+	for (j = 0; j < group->array->n_index; ++j)
+		var->size = isl_vec_set_element_val(var->size, j,
+					    isl_val_copy(tile->bound[j].size));
+}
+
+static int create_kernel_vars(struct ppcg_kernel *kernel)
+{
+	int i, j, n;
+
+	n = 0;
+	for (i = 0; i < kernel->n_array; ++i) {
+		struct gpu_local_array_info *array = &kernel->array[i];
+
+		for (j = 0; j < array->n_group; ++j) {
+			struct gpu_array_ref_group *group = array->groups[j];
+			enum ppcg_group_access_type type;
+
+			type = gpu_array_ref_group_type(group);
+			if (type != ppcg_access_global)
+				++n;
+		}
+	}
+
+	kernel->n_var = n;
+	kernel->var = isl_calloc_array(kernel->ctx, struct ppcg_kernel_var, n);
+	if (!kernel->var)
+		return -1;
+
+	n = 0;
+	for (i = 0; i < kernel->n_array; ++i) {
+		struct gpu_local_array_info *array = &kernel->array[i];
+
+		for (j = 0; j < array->n_group; ++j) {
+			struct gpu_array_ref_group *group = array->groups[j];
+			enum ppcg_group_access_type type;
+
+			type = gpu_array_ref_group_type(group);
+			if (type == ppcg_access_global)
+				continue;
+			create_kernel_var(kernel->ctx, group, &kernel->var[n]);
+			++n;
+		}
+	}
+
+	return 0;
+}
+
+/* Replace "pa" by the zero function defined over the universe domain
+ * in the space of "pa".
+ */
+static __isl_give isl_pw_aff *set_universally_zero(__isl_take isl_pw_aff *pa)
+{
+	isl_space *space;
+	isl_aff *zero;
+
+	space = isl_space_domain(isl_pw_aff_get_space(pa));
+	isl_pw_aff_free(pa);
+	zero = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+
+	return isl_pw_aff_from_aff(zero);
+}
+
+/* The sizes of the arrays on the host that have been computed by
+ * extract_array_info may depend on the parameters.  Use the extra
+ * constraints on the parameters that are valid at "host_domain"
+ * to simplify these expressions and store the results in kernel->array.
+ *
+ * We only need these localized bounds for arrays that are accessed
+ * by the current kernel.  If we have found at least one reference group
+ * then the array is accessed by the kernel.
+ *
+ * The resulting sizes may be functions that are nowhere defined
+ * in case the access function cannot possibly access anything inside
+ * the kernel for some reason.  If so, they are replaced by the zero
+ * function.  Since the access function cannot actually access anything,
+ * there is no harm in printing the array sizes as zero.
+ */
+static void localize_bounds(struct ppcg_kernel *kernel,
+	__isl_keep isl_set *host_domain)
+{
+	int i, j;
+	isl_set *context;
+
+	context = isl_set_copy(host_domain);
+	context = isl_set_params(context);
+
+	for (i = 0; i < kernel->n_array; ++i) {
+		struct gpu_local_array_info *local = &kernel->array[i];
+		isl_multi_pw_aff *bound;
+		int n_index;
+
+		if (local->n_group == 0)
+			continue;
+
+		n_index = local->array->n_index;
+		bound = isl_multi_pw_aff_copy(local->array->bound);
+
+		for (j = 0; j < n_index; ++j) {
+			isl_pw_aff *pwaff;
+			int empty;
+
+			pwaff = isl_multi_pw_aff_get_pw_aff(bound, j);
+			pwaff = isl_pw_aff_gist(pwaff, isl_set_copy(context));
+			empty = isl_pw_aff_is_empty(pwaff);
+			if (empty < 0)
+				pwaff = isl_pw_aff_free(pwaff);
+			else if (empty)
+				pwaff = set_universally_zero(pwaff);
+			bound = isl_multi_pw_aff_set_pw_aff(bound, j, pwaff);
+		}
+
+		local->n_index = n_index;
+		local->bound = bound;
+	}
+	isl_set_free(context);
+}
+
+/* Create the array of gpu_local_array_info structures "array"
+ * inside "kernel".  The number of elements in this array is
+ * the same as the number of arrays in "prog".
+ * Initialize the "array" field of each local array to point
+ * to the corresponding array in "prog".
+ */
+static struct ppcg_kernel *ppcg_kernel_create_local_arrays(
+	struct ppcg_kernel *kernel, struct gpu_prog *prog)
+{
+	int i;
+	isl_ctx *ctx;
+
+	ctx = isl_set_get_ctx(prog->context);
+	kernel->array = isl_calloc_array(ctx,
+			    struct gpu_local_array_info, prog->n_array);
+	if (!kernel->array)
+		return ppcg_kernel_free(kernel);
+	kernel->n_array = prog->n_array;
+
+	for (i = 0; i < prog->n_array; ++i)
+		kernel->array[i].array = &prog->array[i];
+
+	return kernel;
+}
+
+/* Does "kernel" need to be passed an argument corresponding to array "i"?
+ *
+ * The argument is only needed if the kernel accesses this device memory.
+ */
+int ppcg_kernel_requires_array_argument(struct ppcg_kernel *kernel, int i)
+{
+	return kernel->array[i].global;
+}
+
+/* Find the element in gen->stmt that has the given "id".
+ * Return NULL if no such gpu_stmt can be found.
+ */
+static struct gpu_stmt *find_stmt(struct gpu_prog *prog, __isl_keep isl_id *id)
+{
+	int i;
+
+	for (i = 0; i < prog->n_stmts; ++i) {
+		if (id == prog->stmts[i].id)
+			break;
+	}
+
+	return i < prog->n_stmts ? &prog->stmts[i] : NULL;
+}
+
+void ppcg_kernel_stmt_free(void *user)
+{
+	struct ppcg_kernel_stmt *stmt = user;
+
+	if (!stmt)
+		return;
+
+	switch (stmt->type) {
+	case ppcg_kernel_copy:
+		isl_ast_expr_free(stmt->u.c.index);
+		isl_ast_expr_free(stmt->u.c.local_index);
+		break;
+	case ppcg_kernel_domain:
+		isl_id_to_ast_expr_free(stmt->u.d.ref2expr);
+		break;
+	case ppcg_kernel_sync:
+		break;
+	}
+
+	free(stmt);
+}
+
+/* Return the gpu_stmt_access in the list "accesses" that corresponds
+ * to "ref_id".
+ */
+static struct gpu_stmt_access *find_access(struct gpu_stmt_access *accesses,
+	__isl_keep isl_id *ref_id)
+{
+	struct gpu_stmt_access *access;
+
+	for (access = accesses; access; access = access->next)
+		if (access->ref_id == ref_id)
+			return access;
+
+	return NULL;
+}
+
+/* Return the index of the array called "name" in the list of arrays.
+ */
+static int find_array_index(struct ppcg_kernel *kernel, const char *name)
+{
+	int i;
+
+	for (i = 0; i < kernel->n_array; ++i)
+		if (!strcmp(name, kernel->array[i].array->name))
+			return i;
+
+	return -1;
+}
+
+/* Internal data structure for the index and AST expression transformation
+ * callbacks for pet_stmt_build_ast_exprs.
+ *
+ * "kernel" is the kernel for which are computing AST expressions and
+ * may be NULL if we are not inside a kernel.
+ * "accesses" is the list of gpu_stmt_access in the statement.
+ * "iterator_map" expresses the statement iterators in terms of
+ * the AST loop iterators.
+ * "sched2copy" expresses the outer copy_schedule_dim dimensions of
+ * the kernel schedule in terms of the AST loop iterators and
+ * may be NULL if we are not inside a kernel.
+ *
+ * The following fields are set in transform_index and used in transform_expr.
+ * "array" is the array that is being accessed.
+ * "global" is set if the global array is accessed (rather than
+ * shared/private memory).
+ * "local_array" refers to information on the array specialized
+ * to the current kernel.
+ */
+struct ppcg_transform_data {
+    struct ppcg_options *options;
+    struct ppcg_kernel *kernel;
+	struct gpu_stmt_access *accesses;
+	isl_pw_multi_aff *iterator_map;
+	isl_pw_multi_aff *sched2copy;
+
+	struct gpu_array_info *array;
+	int global;
+	struct gpu_local_array_info *local_array;
+};
+
+/* Return a pointer to the gpu_array_ref_group in "local"
+ * that contains the reference "access".
+ * Return NULL if no such group can be found.
+ */
+static struct gpu_array_ref_group *find_ref_group(
+	struct gpu_local_array_info *local, struct gpu_stmt_access *access)
+{
+	int i, j;
+
+	for (i = 0; i < local->n_group; ++i) {
+		struct gpu_array_ref_group *group = local->groups[i];
+
+		for (j = 0; j < group->n_ref; ++j)
+			if (group->refs[j] == access)
+				return group;
+	}
+
+	return NULL;
+}
+
+/* Given an index expression "index" of the form
+ *
+ *	L -> F(A),
+ *
+ * with F(A) either A or some subfield of A and L the AST loop iterators,
+ * and a tiling "tiling" of the form
+ *
+ *	[L -> A] -> T
+ *
+ * apply the tiling to the outer array in the index expression to obtain
+ *
+ *	L -> T(A)
+ *
+ * If F(A) is some subfield of A, then separate the member access
+ * into the base index expression and the field index expression,
+ * apply the tiling to the base index expression and combine the result
+ * with the field index expression.
+ *
+ * If F(A) is A, then modify index to keep track of the iterators
+ *
+ *	L -> [L -> A]
+ *
+ * and combine the result with the tiling to obtain a tiled index expression
+ * in terms of the AST loop iterators
+ *
+ *	L -> T
+ */
+static __isl_give isl_multi_pw_aff *tile_outer(
+	__isl_take isl_multi_pw_aff *index, __isl_take isl_multi_pw_aff *tiling)
+{
+	isl_bool is_wrapping;
+	isl_space *space;
+	isl_multi_pw_aff *mpa;
+
+	is_wrapping = isl_multi_pw_aff_range_is_wrapping(index);
+	if (is_wrapping < 0)
+		goto error;
+	if (is_wrapping) {
+		isl_multi_pw_aff *field;
+
+		field = isl_multi_pw_aff_copy(index);
+		field = isl_multi_pw_aff_range_factor_range(field);
+		index = isl_multi_pw_aff_range_factor_domain(index);
+		index = tile_outer(index, tiling);
+		return isl_multi_pw_aff_range_product(index, field);
+	}
+
+	space = isl_space_domain(isl_multi_pw_aff_get_space(index));
+	space = isl_space_map_from_set(space);
+	mpa = isl_multi_pw_aff_identity(space);
+	index = isl_multi_pw_aff_range_product(mpa, index);
+	index = isl_multi_pw_aff_pullback_multi_pw_aff(tiling, index);
+
+	return index;
+error:
+	isl_multi_pw_aff_free(index);
+	isl_multi_pw_aff_free(tiling);
+	return NULL;
+}
+
+/* Index transformation callback for pet_stmt_build_ast_exprs.
+ *
+ * "index" expresses the array indices in terms of statement iterators
+ *
+ * We first reformulate "index" in terms of the AST loop iterators.
+ * Then we check if we are accessing the global array or
+ * a shared/private copy.  In particular, if we are not inside a kernel
+ * then we must be accessing a global array.
+ * In the former case, we simply return
+ * the updated index.  If "index" is an affine expression rather
+ * than an array access, then we also return the updated index here.
+ *
+ * If no reference groups have been computed for the array,
+ * then we can only be accessing the global array.
+ *
+ * Otherwise, we apply the tiling to the index.
+ * This tiling is of the form
+ *
+ *	[D -> A] -> T
+ *
+ * where D corresponds to the outer tile->depth dimensions of
+ * the kernel schedule.
+ * The index is of the form
+ *
+ *	L -> A
+ *
+ * We update the tiling to refer to the AST loop iterators
+ *
+ *	[L -> A] -> T
+ *
+ * and combine it with the index to obtain a tiled index expression in terms
+ * of the AST loop iterators
+ *
+ *	L -> T
+ *
+ * Note that while the tiling applies directly to an outer array.
+ * the index may refer to some subfield of this outer array.
+ * In such cases, the result will refer to the same subfield of the tile.
+ * That is, an index expression of the form  L -> F(A) will be transformed
+ * into an index expression of the form L -> F(T).
+ */
+static __isl_give isl_multi_pw_aff *transform_index(
+	__isl_take isl_multi_pw_aff *index, __isl_keep isl_id *ref_id,
+	void *user)
+{
+	struct ppcg_transform_data *data = user;
+	struct gpu_stmt_access *access;
+	struct gpu_array_ref_group *group;
+	struct gpu_array_tile *tile;
+	isl_pw_multi_aff *iterator_map;
+	int i;
+	int dim;
+	const char *name;
+	isl_space *space;
+	isl_multi_pw_aff *tiling;
+	isl_pw_multi_aff *pma;
+	isl_pw_multi_aff *sched2depth;
+
+	data->array = NULL;
+
+	iterator_map = isl_pw_multi_aff_copy(data->iterator_map);
+	index = isl_multi_pw_aff_pullback_pw_multi_aff(index, iterator_map);
+
+	if (!data->kernel)
+		return index;
+
+	access = find_access(data->accesses, ref_id);
+	if (!access)
+		return index;
+	if (!isl_map_has_tuple_name(access->access, isl_dim_out))
+		return index;
+
+	name = get_outer_array_name(access->access);
+	i = find_array_index(data->kernel, name);
+	if (i < 0)
+		isl_die(isl_multi_pw_aff_get_ctx(index), isl_error_internal,
+			"cannot find array",
+			return isl_multi_pw_aff_free(index));
+	data->local_array = &data->kernel->array[i];
+	data->array = data->local_array->array;
+
+	group = find_ref_group(data->local_array, access);
+	if (!group) {
+		data->global = 1;
+		return index;
+	}
+
+	tile = gpu_array_ref_group_tile(group);
+	data->global = !tile;
+	if (!tile)
+		return index;
+
+	space = isl_space_domain(isl_multi_aff_get_space(tile->tiling));
+	space = isl_space_range(isl_space_unwrap(space));
+	space = isl_space_map_from_set(space);
+	pma = isl_pw_multi_aff_identity(space);
+	sched2depth = isl_pw_multi_aff_copy(data->sched2copy);
+	dim = isl_pw_multi_aff_dim(sched2depth, isl_dim_out);
+	sched2depth = isl_pw_multi_aff_drop_dims(sched2depth, isl_dim_out,
+					    tile->depth, dim - tile->depth);
+	pma = isl_pw_multi_aff_product(sched2depth, pma);
+	tiling = isl_multi_pw_aff_from_multi_aff(
+				    isl_multi_aff_copy(tile->tiling));
+	tiling = isl_multi_pw_aff_pullback_pw_multi_aff(tiling, pma);
+
+	index = tile_outer(index, tiling);
+
+	return index;
+}
+
+/* Dereference "expr" by adding an index [0].
+ * The original "expr" is assumed not to have any indices.
+ *
+ * If "expr" is a member access, then the dereferencing needs
+ * to be applied to the structure argument of this member access.
+ */
+static __isl_give isl_ast_expr *dereference(__isl_take isl_ast_expr *expr)
+{
+	isl_ctx *ctx;
+	isl_ast_expr *arg0, *res;
+	isl_ast_expr_list *list;
+
+	arg0 = isl_ast_expr_get_op_arg(expr, 0);
+	if (!arg0)
+		return isl_ast_expr_free(expr);
+	if (isl_ast_expr_get_type(arg0) == isl_ast_expr_op &&
+	    isl_ast_expr_get_op_type(arg0) == isl_ast_op_member) {
+		isl_ast_expr *arg;
+
+		arg = isl_ast_expr_get_op_arg(arg0, 0);
+		arg = dereference(arg);
+		arg0 = isl_ast_expr_set_op_arg(arg0, 0, arg);
+		expr = isl_ast_expr_set_op_arg(expr, 0, arg0);
+
+		return expr;
+	}
+	isl_ast_expr_free(arg0);
+
+	ctx = isl_ast_expr_get_ctx(expr);
+	res = isl_ast_expr_from_val(isl_val_zero(ctx));
+	list = isl_ast_expr_list_from_ast_expr(res);
+	res = isl_ast_expr_get_op_arg(expr, 0);
+	res = isl_ast_expr_access(res, list);
+	isl_ast_expr_free(expr);
+
+	return res;
+}
+
+/* Linearize the index expression "expr" based on the array bounds
+ * of "array".
+ *
+ * That is, transform expression
+ *
+ *	A[i_0][i_1]...[i_n]
+ *
+ * to
+ *
+ *	A[(..((i_0 * b_1 + i_1) ... ) * b_n + i_n]
+ *
+ * where b_0, b_1, ..., b_n are the bounds on the array.
+ *
+ * If the base of "expr" is a member access, then the linearization needs
+ * to be applied to the structure argument of this member access.
+ *
+ * In the base case, if "expr" has no arguments (other than the name of
+ * the array), then we are passing an entire array to a function.
+ * In this case, there is nothing to linearize.
+ * Note that at this point an expression with no arguments can
+ * only be an entire array because the scalar case and
+ * the case of single struct are handled by the caller.
+ *
+ * If the number of specified index expressions in "expr"
+ * is smaller than the dimension of the accessed array,
+ * then the missing i_j also do not appear in the linearized expression.
+ * Furthermore, since such an expression does not refer to a single
+ * element while the default linearized expression would refer to
+ * a single element, we return the expression
+ *
+ *	A + (..((i_0 * b_1 + i_1) ... ) * b_l + i_l)
+ *
+ * instead.  Note that because of the special case handling above,
+ * we can assume here that there is at least one index expression.
+ */
+__isl_give isl_ast_expr *gpu_local_array_info_linearize_index(
+	struct gpu_local_array_info *array, __isl_take isl_ast_expr *expr)
+{
+	int i, n;
+	isl_ast_expr *arg0;
+	isl_ast_expr *res;
+	isl_ast_expr_list *list;
+
+	arg0 = isl_ast_expr_get_op_arg(expr, 0);
+	if (isl_ast_expr_get_type(arg0) == isl_ast_expr_op &&
+	    isl_ast_expr_get_op_type(arg0) == isl_ast_op_member) {
+		isl_ast_expr *arg;
+
+		arg = isl_ast_expr_get_op_arg(arg0, 0);
+		arg = gpu_local_array_info_linearize_index(array, arg);
+		arg0 = isl_ast_expr_set_op_arg(arg0, 0, arg);
+		expr = isl_ast_expr_set_op_arg(expr, 0, arg0);
+
+		return expr;
+	}
+	isl_ast_expr_free(arg0);
+
+	if (isl_ast_expr_get_op_n_arg(expr) == 1)
+		return expr;
+
+	n = isl_ast_expr_get_op_n_arg(expr);
+	res = isl_ast_expr_get_op_arg(expr, 1);
+	for (i = 1; i < array->n_index; ++i) {
+		isl_ast_expr *expr_i;
+
+		expr_i = isl_ast_expr_get_op_arg(array->bound_expr, 1 + i);
+		res = isl_ast_expr_mul(res, expr_i);
+
+		if (i + 1 >= n)
+			continue;
+		expr_i = isl_ast_expr_get_op_arg(expr, i + 1);
+		res = isl_ast_expr_add(res, expr_i);
+	}
+
+	if (1 + array->n_index > n) {
+		res = isl_ast_expr_add(isl_ast_expr_get_op_arg(expr, 0), res);
+	} else {
+		list = isl_ast_expr_list_from_ast_expr(res);
+		res = isl_ast_expr_get_op_arg(expr, 0);
+		res = isl_ast_expr_access(res, list);
+	}
+
+	isl_ast_expr_free(expr);
+
+	return res;
+}
+
+/* AST expression transformation callback for pet_stmt_build_ast_exprs.
+ *
+ * If the AST expression refers to an array that is not accessed
+ * at all, then this means the value of the expression is not used,
+ * so we might as well print zero (NULL pointer) instead.
+ *
+ * If the AST expression refers to a global scalar that is not
+ * a read-only scalar, then its address was passed to the kernel and
+ * we need to dereference it.
+ *
+ * If the AST expression refers to an access to a global array,
+ * then we linearize the access exploiting the bounds in data->local_array.
+ */
+static __isl_give isl_ast_expr *transform_expr(__isl_take isl_ast_expr *expr,
+	__isl_keep isl_id *id, void *user)
+{
+	struct ppcg_transform_data *data = user;
+
+	if (!data->array)
+		return expr;
+	if (!data->array->accessed) {
+		isl_ctx *ctx;
+
+		ctx = isl_ast_expr_get_ctx(expr);
+		isl_ast_expr_free(expr);
+		return isl_ast_expr_from_val(isl_val_zero(ctx));
+	}
+	if (gpu_array_is_read_only_scalar(data->array))
+		return expr;
+	if (!data->global)
+		return expr;
+	if (data->array->n_index == 0)
+		return dereference(expr);
+	if (!data->array->linearize)
+		return expr;
+
+	return gpu_local_array_info_linearize_index(data->local_array, expr);
+}
+
+/* This function is called for each instance of a user statement
+ * in the kernel "kernel", identified by "gpu_stmt".
+ * "kernel" may be NULL if we are not inside a kernel.
+ *
+ * We attach a struct ppcg_kernel_stmt to the "node", containing
+ * a computed AST expression for each access, through an annotation
+ * with name "user".
+ * These AST expressions are computed from iterator_map,
+ * which expresses the domain
+ * elements in terms of the generated loops, and sched2copy,
+ * which expresses the outer copy_schedule_dim dimensions of
+ * the kernel schedule computed by PPCG in terms of the generated loops.
+ */
+static __isl_give isl_ast_node *create_domain_leaf(
+	struct ppcg_kernel *kernel, __isl_take isl_ast_node *node,
+	__isl_keep isl_ast_build *build, struct gpu_stmt *gpu_stmt,
+    struct gpu_gen *gen)
+{
+	struct ppcg_transform_data data;
+	struct ppcg_kernel_stmt *stmt;
+	isl_ctx *ctx;
+	isl_id *id;
+	isl_pw_multi_aff *sched2copy;
+	isl_map *map;
+	isl_pw_multi_aff *iterator_map;
+	isl_union_map *schedule;
+
+	if (!node)
+		return NULL;
+	ctx = isl_ast_node_get_ctx(node);
+
+	stmt = isl_calloc_type(ctx, struct ppcg_kernel_stmt);
+	if (!stmt)
+		return isl_ast_node_free(node);
+
+	schedule = isl_ast_build_get_schedule(build);
+	map = isl_map_reverse(isl_map_from_union_map(schedule));
+	iterator_map = isl_pw_multi_aff_from_map(map);
+	if (kernel)
+		sched2copy = compute_sched_to_copy(kernel,
+					isl_pw_multi_aff_copy(iterator_map));
+	else
+		sched2copy = NULL;
+
+	stmt->type = ppcg_kernel_domain;
+	stmt->u.d.stmt = gpu_stmt;
+
+	data.kernel = kernel;
+	data.accesses = stmt->u.d.stmt->accesses;
+	data.iterator_map = iterator_map;
+	data.sched2copy = sched2copy;
+	stmt->u.d.ref2expr = gen->build_ast_expr(stmt->u.d.stmt->stmt,
+					    build, &transform_index, &data,
+					    &transform_expr, &data);
+
+	isl_pw_multi_aff_free(iterator_map);
+	isl_pw_multi_aff_free(sched2copy);
+
+	id = isl_id_alloc(ctx, "user", stmt);
+	id = isl_id_set_free_user(id, &ppcg_kernel_stmt_free);
+	return isl_ast_node_set_annotation(node, id);
+}
+
+/* This function is called for each statement node in the AST
+ * for copying to or from shared/private memory.
+ * Attach a pointer to a ppcg_kernel_stmt representing the copy
+ * statement to the node.
+ * The statement name is "read" or "write", depending on whether we are
+ * reading from global memory or writing to global memory.
+ *
+ * The schedule is of the form
+ *
+ *	type[D -> A] -> L
+ *
+ * where D corresponds to the outer tile->depth dimensions of
+ * the kernel schedule, A to the global array and L to the outer
+ * generated AST schedule.
+ * We compute the inverse and strip off the type, resulting in
+ *
+ *	L -> [D -> A]
+ *
+ * We combine this mapping with on the one hand the projection
+ *
+ *	[D -> A] -> A
+ *
+ * and on the other hand the group tiling
+ *
+ *	[D -> A] -> T
+ *
+ * resulting in
+ *
+ *	L -> A		and 	L -> T
+ *
+ * and store the corresponding expressions in stmt->index and stmt->local_index,
+ * where stmt points to the ppcg_kernel_stmt that is attached to the node.
+ * stmt->index is linearized if the global memory array is linearized.
+ */
+static __isl_give isl_ast_node *create_access_leaf(struct ppcg_kernel *kernel,
+	struct gpu_array_ref_group *group, __isl_take isl_ast_node *node,
+	__isl_keep isl_ast_build *build)
+{
+	struct ppcg_kernel_stmt *stmt;
+	struct gpu_array_tile *tile;
+	isl_id *id;
+	isl_ast_expr *expr;
+	isl_space *space;
+	isl_map *access;
+	isl_pw_multi_aff *pma, *pma2;
+	const char *type;
+
+	stmt = isl_calloc_type(kernel->ctx, struct ppcg_kernel_stmt);
+	if (!stmt)
+		return isl_ast_node_free(node);
+
+	access = isl_map_from_union_map(isl_ast_build_get_schedule(build));
+	type = isl_map_get_tuple_name(access, isl_dim_in);
+	stmt->u.c.read = !strcmp(type, "read");
+	access = isl_map_reverse(access);
+	pma = isl_pw_multi_aff_from_map(access);
+	pma = isl_pw_multi_aff_reset_tuple_id(pma, isl_dim_out);
+
+	space = isl_space_range(isl_pw_multi_aff_get_space(pma));
+	space = isl_space_unwrap(space);
+	pma2 = isl_pw_multi_aff_range_map(space);
+	pma2 = isl_pw_multi_aff_pullback_pw_multi_aff(pma2,
+						    isl_pw_multi_aff_copy(pma));
+	expr = isl_ast_build_access_from_pw_multi_aff(build, pma2);
+	if (group->array->linearize)
+		expr = gpu_local_array_info_linearize_index(group->local_array,
+							    expr);
+	stmt->u.c.index = expr;
+
+	tile = gpu_array_ref_group_tile(group);
+	pma2 = isl_pw_multi_aff_from_multi_aff(
+					    isl_multi_aff_copy(tile->tiling));
+	pma2 = isl_pw_multi_aff_pullback_pw_multi_aff(pma2, pma);
+	expr = isl_ast_build_access_from_pw_multi_aff(build, pma2);
+	stmt->u.c.local_index = expr;
+
+	stmt->u.c.array = group->array;
+	stmt->u.c.local_array = group->local_array;
+	stmt->type = ppcg_kernel_copy;
+
+	id = isl_id_alloc(kernel->ctx, "copy", stmt);
+	id = isl_id_set_free_user(id, &ppcg_kernel_stmt_free);
+	return isl_ast_node_set_annotation(node, id);
+}
+
+/* Create a synchronization ppcg_kernel_stmt and
+ * attach it to the node "node" representing the synchronization.
+ */
+static __isl_give isl_ast_node *create_sync_leaf(
+	struct ppcg_kernel *kernel, __isl_take isl_ast_node *node,
+	__isl_keep isl_ast_build *build)
+{
+	struct ppcg_kernel_stmt *stmt;
+	isl_id *id;
+
+	stmt = isl_calloc_type(kernel->ctx, struct ppcg_kernel_stmt);
+	if (!stmt)
+		return isl_ast_node_free(node);
+
+	stmt->type = ppcg_kernel_sync;
+	id = isl_id_alloc(kernel->ctx, "sync", stmt);
+	id = isl_id_set_free_user(id, &ppcg_kernel_stmt_free);
+	return isl_ast_node_set_annotation(node, id);
+}
+
+/* Build AST expressions for the device array sizes of all arrays in "prog"
+ * that require allocation on the device using "build", as well as
+ * for the original array sizes of all arrays that need to be declared
+ * on the host.
+ * "node" is freed in case of error.
+ */
+static __isl_give isl_ast_node *build_array_bounds(
+	__isl_take isl_ast_node *node, struct gpu_prog *prog,
+	__isl_keep isl_ast_build *build)
+{
+	int i;
+
+	for (i = 0; i < prog->n_array; ++i) {
+		struct gpu_array_info *array = &prog->array[i];
+		isl_multi_pw_aff *size;
+		isl_ast_expr *expr;
+
+		if (!gpu_array_requires_device_allocation(array))
+			continue;
+
+		size = isl_multi_pw_aff_copy(array->bound);
+		expr = ppcg_build_size_expr(size, build);
+		array->bound_expr = expr;
+		if (!expr)
+			return isl_ast_node_free(node);
+	}
+
+	for (i = 0; i < prog->n_array; ++i) {
+		struct gpu_array_info *array = &prog->array[i];
+		isl_set *extent;
+		isl_multi_pw_aff *size;
+		isl_ast_expr *expr;
+
+		if (!array->declare_local)
+			continue;
+		extent = isl_set_copy(array->declared_extent);
+		size = ppcg_size_from_extent(extent);
+		expr = ppcg_build_size_expr(size, build);
+		array->declared_size = expr;
+		if (!expr)
+			return isl_ast_node_free(node);
+	}
+
+	return node;
+}
+
+/* Internal data structure for at_domain.
+ *
+ * "prog" represents the entire scop.
+ * "kernel" points to the kernel to which the current schedule node
+ * belongs.  It is set by before_mark and reset by after_mark.
+ * It may be NULL if we are outside any kernel.
+ */
+struct ppcg_at_domain_data {
+    struct gpu_prog *prog;
+    struct gpu_gen *gen;
+    struct ppcg_kernel *kernel;
+};
+
+/* This function is called for each instance of a user statement
+ * in the kernel.  This may be one of the original user statements
+ * or a statement introduced by PPCG.
+ *
+ * We first check if the statement id corresponds to a gpu statement,
+ * which indicates the statement is an original user statement. Any statement
+ * that is not an original user statement has been introduced by PPCG and
+ * requires special handling.
+ *
+ * If the user statement is one of the original user statements, then we call
+ * create_domain_leaf.  If it is "init_device", then we call
+ * build_array_bounds.  Otherwise, we check if it is a copy or synchronization
+ * statement and call the appropriate functions.  Statements that copy an array
+ * to/from the device do not need any further treatment.
+ * Neither does "clear_device".
+ */
+static __isl_give isl_ast_node *at_domain(__isl_take isl_ast_node *node,
+	__isl_keep isl_ast_build *build, void *user)
+{
+	struct ppcg_at_domain_data *data = user;
+	struct gpu_stmt *gpu_stmt;
+	isl_ast_expr *expr, *arg;
+	isl_id *id;
+	int is_sync;
+	const char *name;
+	void *p;
+
+	expr = isl_ast_node_user_get_expr(node);
+	arg = isl_ast_expr_get_op_arg(expr, 0);
+	id = isl_ast_expr_get_id(arg);
+	name = isl_id_get_name(id);
+	p = isl_id_get_user(id);
+	isl_ast_expr_free(expr);
+	isl_ast_expr_free(arg);
+
+	gpu_stmt = find_stmt(data->prog, id);
+	is_sync = gpu_tree_id_is_sync(id, data->kernel);
+	isl_id_free(id);
+
+	if (gpu_stmt)
+		return create_domain_leaf(data->kernel, node, build, gpu_stmt,
+                                  data->gen);
+
+	if (!prefixcmp(name, "to_device_") || !prefixcmp(name, "from_device_"))
+		return node;
+	if (!strcmp(name, "init_device"))
+		return build_array_bounds(node, data->prog, build);
+	if (!strcmp(name, "clear_device"))
+		return node;
+	if (is_sync < 0)
+		return isl_ast_node_free(node);
+	if (!strcmp(name, "read") || !strcmp(name, "write")) {
+		struct gpu_array_ref_group *group = p;
+		return create_access_leaf(data->kernel, group, node, build);
+	}
+	if (!is_sync)
+		isl_die(data->prog->ctx, isl_error_internal,
+			"unknown statement type",
+			return isl_ast_node_free(node));
+	return create_sync_leaf(data->kernel, node, build);
+}
+
+/* Given a set of wrapped references "ref", return the corresponding
+ * access relations based on the tagged access relations "tagged".
+ *
+ * The elements of "ref" are of the form
+ *
+ *	[D -> R]
+ *
+ * with D an iteration domains and R a reference.
+ * The elements of "tagged" are of the form
+ *
+ *	[D -> R] -> A
+ *
+ * with A an array.
+ *
+ * Extend "tagged" to include the iteration domain in the range, i.e.,
+ *
+ *	[D -> R] -> [D -> A]
+ *
+ * apply the result to "ref" and then unwrap the resulting set
+ * to obtain relations of the form
+ *
+ *	D -> A
+ */
+static __isl_give isl_union_map *wrapped_reference_to_access(
+	__isl_take isl_union_set *ref, __isl_take isl_union_map *tagged)
+{
+	isl_union_map *tag2access;
+
+	tag2access = isl_union_map_copy(tagged);
+	tag2access = isl_union_map_universe(tag2access);
+	tag2access = isl_union_set_unwrap(isl_union_map_domain(tag2access));
+	tag2access = isl_union_map_domain_map(tag2access);
+	tag2access = isl_union_map_range_product(tag2access, tagged);
+
+	ref = isl_union_set_coalesce(ref);
+	ref = isl_union_set_apply(ref, tag2access);
+
+	return isl_union_set_unwrap(ref);
+}
+
+/* Given an access relation "access" from one or more array reference groups,
+ * remove those reads if ("read" is 1) or writes (if "read" is 0)
+ * that are only needed to communicate data within
+ * the same iteration of "sched".
+ * The domain of "sched" corresponds to the original statement instances,
+ * i.e., those that appear in the domains of the access relations.
+ * "tagged" contains all tagged access relations to all
+ * the array reference groups accessed by "access" from statement
+ * instances scheduled by "sched".
+ *
+ * If the access is a read then it is either an element of
+ *
+ *	live_in union (range flow)
+ *
+ * where live_in and flow may be overapproximations, or
+ * it reads an uninitialized value (that is not live-in because
+ * there is an intermediate kill) or it reads a value that was
+ * written within the same (compound) statement instance.
+ * If the access is a write then it is either an element of
+ *
+ *	live_out union (domain flow)
+ *
+ * or it writes a value that is never read (and is not live-out
+ * because of an intermediate kill) or only
+ * within the same (compound) statement instance.
+ * In both cases, the access relation is also a subset of
+ * the group access relation.
+ *
+ * The cases where an uninitialized value is read or a value is written
+ * that is never read or where the dataflow occurs within a statement
+ * instance are also considered local and may also be removed.
+ *
+ * Essentially, we compute the intersection of "access" with either
+ *
+ *	live_in union (range non-local-flow)
+ *
+ * or
+ *
+ *	live_out union (domain non-local-flow)
+ *
+ * We first construct a relation "local"
+ *
+ *	[[D -> R] -> [D' -> R']]
+ *
+ * of pairs of domain iterations accessing the reference group
+ * and references in the group that are coscheduled by "sched".
+ *
+ * If this relation does not intersect the dataflow dependences,
+ * then there is nothing we can possibly remove, unless the dataflow
+ * dependences themselves only relate a subset of the accesses.
+ * In particular, the accesses may not be involved in any dataflow
+ * dependences, either because they are uninitialized reads/dead writes
+ * or because the dataflow occurs inside a statement instance.
+ *
+ * Since the computation below may break up the access relation
+ * into smaller pieces, we only perform the intersection with
+ * the non-local dependent accesses if the local pairs
+ * intersect the dataflow dependences.  Otherwise, we intersect
+ * with the universe of the non-local dependent accesses.
+ * This should at least remove accesses from statements that
+ * do not participate in any dependences.
+ *
+ * In particular, we remove the "local" dataflow dependences from
+ * the set of all dataflow dependences, or at least those
+ * that may contribute to a domain/range that intersects
+ * the domain of "access".
+ * Note that if the potential dataflow dependences are an overapproximation
+ * of the actual dataflow dependences, then the result remains an
+ * overapproximation of the non-local dataflow dependences.
+ * Copying to/from global memory is only needed for the references
+ * in the domain/range of the result or for accesses that are live out/in
+ * for the entire scop.
+ *
+ * We therefore map the domain/range of the "external" relation
+ * to the corresponding access relation and take the union with
+ * the live out/in relation.
+ */
+static __isl_give isl_union_map *remove_local_accesses(
+	struct gpu_prog *prog, __isl_take isl_union_map *tagged,
+	__isl_take isl_union_map *access, __isl_take isl_union_map *sched,
+	int read)
+{
+	int empty;
+	isl_union_pw_multi_aff *tagger;
+	isl_union_set *domain, *access_domain;
+	isl_union_map *local, *external, *universe;
+	isl_union_set *tag_set;
+
+	if (isl_union_map_is_empty(access)) {
+		isl_union_map_free(sched);
+		isl_union_map_free(tagged);
+		return access;
+	}
+
+	tagger = isl_union_pw_multi_aff_copy(prog->scop->tagger);
+	domain = isl_union_map_domain(isl_union_map_copy(tagged));
+	tagger = isl_union_pw_multi_aff_intersect_domain(tagger,
+					isl_union_set_copy(domain));
+	sched = isl_union_map_preimage_domain_union_pw_multi_aff(sched, tagger);
+
+	local = isl_union_map_apply_range(sched,
+			    isl_union_map_reverse(isl_union_map_copy(sched)));
+	local = isl_union_map_intersect(local,
+			isl_union_map_copy(prog->scop->tagged_dep_flow));
+
+	empty = isl_union_map_is_empty(local);
+
+	external = isl_union_map_copy(prog->scop->tagged_dep_flow);
+	universe = isl_union_map_universe(isl_union_map_copy(access));
+	access_domain = isl_union_map_domain(universe);
+	domain = isl_union_set_universe(domain);
+	universe = isl_union_set_unwrap(domain);
+	universe = isl_union_map_intersect_domain(universe, access_domain);
+	domain = isl_union_map_wrap(universe);
+	if (read)
+		external = isl_union_map_intersect_range(external, domain);
+	else
+		external = isl_union_map_intersect_domain(external, domain);
+	external = isl_union_map_intersect_params(external,
+				isl_set_copy(prog->scop->context));
+	external = isl_union_map_subtract(external, local);
+
+	if (read) {
+		tag_set = isl_union_map_range(external);
+		external = wrapped_reference_to_access(tag_set, tagged);
+		external = isl_union_map_union(external,
+				isl_union_map_copy(prog->scop->live_in));
+	} else {
+		tag_set = isl_union_map_domain(external);
+		external = wrapped_reference_to_access(tag_set, tagged);
+		external = isl_union_map_union(external,
+				isl_union_map_copy(prog->scop->live_out));
+	}
+
+	if (empty < 0)
+		external = isl_union_map_free(external);
+	else if (empty)
+		external = isl_union_map_universe(external);
+
+	access = isl_union_map_intersect(access, external);
+
+	return access;
+}
+
+/* Given an access relation "access" from "group", remove those reads
+ * if ("read" is 1) or writes (if "read" is 0) that are only needed to
+ * communicate data within the same iteration of the schedule "prefix"
+ * at the position where the copying of the group is inserted.
+ * That is, the output dimension of "prefix"
+ * is equal to tile->depth.
+ * The domain of "prefix" corresponds to the original statement instances,
+ * i.e., those that appear in the domains of the access relations.
+ *
+ * Extract the tagged access relation of "group" and
+ * then call remove_local_accesses.
+ */
+static __isl_give isl_union_map *remove_local_accesses_group(
+	struct ppcg_kernel *kernel, struct gpu_array_ref_group *group,
+	__isl_take isl_union_map *access, __isl_keep isl_union_map *prefix,
+	int read)
+{
+	isl_union_map *sched, *tagged;
+
+	if (isl_union_map_is_empty(access))
+		return access;
+
+	tagged = group_tagged_access_relation(group);
+	sched = isl_union_map_copy(prefix);
+
+	return remove_local_accesses(kernel->prog, tagged, access, sched, read);
+}
+
+/* Build an access AST expression for the effective grid size using "build".
+ * Store the result in kernel->grid_size_expr.
+ */
+static isl_stat build_grid_size(struct ppcg_kernel *kernel,
+	__isl_keep isl_ast_build *build)
+{
+	isl_multi_pw_aff *size;
+
+	size = isl_multi_pw_aff_copy(kernel->grid_size);
+	size = isl_multi_pw_aff_set_tuple_name(size, isl_dim_out, "grid");
+	kernel->grid_size_expr = ppcg_build_size_expr(size, build);
+
+	if (!kernel->grid_size_expr)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Build access AST expressions for the localized array sizes using "build".
+ * Store the result in local->bound_expr.
+ * Only do this for arrays for which localized bounds have been computed.
+ */
+static isl_stat build_local_array_sizes(struct ppcg_kernel *kernel,
+	__isl_keep isl_ast_build *build)
+{
+	int i;
+
+	for (i = 0; i < kernel->n_array; ++i) {
+		struct gpu_local_array_info *local = &kernel->array[i];
+		isl_multi_pw_aff *size;
+
+		if (local->n_group == 0)
+			continue;
+		size = isl_multi_pw_aff_copy(local->bound);
+		local->bound_expr = ppcg_build_size_expr(size, build);
+		if (!local->bound_expr)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Build access AST expressions for the effective grid size and
+ * the localized array sizes using "build".
+ */
+static isl_stat build_grid_and_local_array_sizes(struct ppcg_kernel *kernel,
+	__isl_keep isl_ast_build *build)
+{
+	if (build_grid_size(kernel, build) < 0)
+		return isl_stat_error;
+	if (build_local_array_sizes(kernel, build) < 0)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* This function is called before the AST generator starts traversing
+ * the schedule subtree of a node with mark "mark".
+ *
+ * If the mark is called "kernel", store the kernel pointer in data->kernel
+ * for use in at_domain and build AST expressions for the grid size and
+ * the localized array sizes.
+ */
+static isl_stat before_mark(__isl_keep isl_id *mark,
+	__isl_keep isl_ast_build *build, void *user)
+{
+	struct ppcg_at_domain_data *data = user;
+
+	if (!mark)
+		return isl_stat_error;
+	if (!strcmp(isl_id_get_name(mark), "kernel")) {
+		data->kernel = isl_id_get_user(mark);
+		if (build_grid_and_local_array_sizes(data->kernel, build) < 0)
+			return isl_stat_error;
+	}
+	return isl_stat_ok;
+}
+
+/* This function is called after the AST generator has finished traversing
+ * the schedule subtree of a mark node.  "node" points to the corresponding
+ * mark AST node.
+ *
+ * If the mark is called "kernel", then replace "node" by a user node
+ * that "calls" the kernel, representing the launch of the kernel.
+ * The original "node" is stored inside the kernel object so that
+ * it can be used to print the device code.
+ * Note that this assumes that a kernel is only launched once.
+ * Also clear data->kernel.
+ */
+static __isl_give isl_ast_node *after_mark(__isl_take isl_ast_node *node,
+        __isl_keep isl_ast_build *build, void *user)
+{
+	isl_ctx *ctx;
+	isl_id *id;
+	isl_ast_expr *expr;
+	isl_ast_expr_list *list;
+	struct ppcg_kernel *kernel;
+	struct ppcg_at_domain_data *data = user;
+
+	ctx = isl_ast_node_get_ctx(node);
+	id = isl_ast_node_mark_get_id(node);
+	if (!id)
+		return isl_ast_node_free(node);
+	if (strcmp(isl_id_get_name(id), "kernel") || !data->kernel) {
+		isl_id_free(id);
+		return node;
+	}
+	kernel = data->kernel;
+	data->kernel = NULL;
+	kernel->space = isl_ast_build_get_schedule_space(build);
+	kernel->tree = isl_ast_node_mark_get_node(node);
+	isl_ast_node_free(node);
+
+	expr = isl_ast_expr_from_id(isl_id_copy(id));
+	list = isl_ast_expr_list_alloc(ctx, 0);
+	expr = isl_ast_expr_call(expr, list);
+	node = isl_ast_node_alloc_user(expr);
+	node = isl_ast_node_set_annotation(node, id);
+
+	return node;
+}
+
+static isl_bool update_depth(__isl_keep isl_schedule_node *node, void *user)
+{
+	int *depth = user;
+	int node_depth;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_leaf)
+		return isl_bool_true;
+	node_depth = isl_schedule_node_get_schedule_depth(node);
+	if (node_depth > *depth)
+		*depth = node_depth;
+
+	return isl_bool_false;
+}
+
+/* Use isl to generate code for both the host and the device
+ * from "schedule".
+ * The device code is marked by "kernel" mark nodes in the schedule tree,
+ * containing a pointer to a ppcg_kernel object.
+ * The returned AST only contains the AST for the host code.
+ * The ASTs for the device code are embedded in ppcg_kernel objects
+ * attached to the leaf nodes that call "kernel".
+ */
+__isl_give isl_ast_node *generate_code(struct gpu_gen *gen,
+	__isl_take isl_schedule *schedule)
+{
+	struct ppcg_at_domain_data data;
+	isl_ast_build *build;
+	isl_ast_node *tree;
+	isl_id_list *iterators;
+	int depth;
+
+    data.prog = gen->prog;
+    data.gen = gen;
+	data.kernel = NULL;
+
+	depth = 0;
+	if (isl_schedule_foreach_schedule_node_top_down(schedule, &update_depth,
+						&depth) < 0)
+		return NULL;
+	build = isl_ast_build_alloc(gen->prog->ctx);
+	iterators = ppcg_scop_generate_names(gen->prog->scop, depth, "c");
+	build = isl_ast_build_set_iterators(build, iterators);
+	build = isl_ast_build_set_at_each_domain(build, &at_domain, &data);
+	build = isl_ast_build_set_before_each_mark(build, &before_mark, &data);
+	build = isl_ast_build_set_after_each_mark(build, &after_mark, &data);
+	if (gen->prog->scop->options->debug->dump_final_schedule)
+		isl_schedule_dump(schedule);
+	tree = isl_ast_build_node_from_schedule(build, schedule);
+	isl_ast_build_free(build);
+
+	return tree;
+}
+
+__isl_give isl_union_map *extract_sizes_from_str(isl_ctx *ctx, const char *str)
+{
+	if (!str)
+		return NULL;
+	return isl_union_map_read_from_str(ctx, str);
+}
+
+/* Can "node" be tiled and then mapped to block and thread identifiers?
+ * That is, is it permutable with at least one coincident dimension?
+ */
+static int is_permutable(__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return -1;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_band)
+		return 0;
+	if (!isl_schedule_node_band_get_permutable(node))
+		return 0;
+	if (isl_schedule_node_band_n_member(node) < 1)
+		return 0;
+	if (!isl_schedule_node_band_member_get_coincident(node, 0))
+		return 0;
+
+	return 1;
+}
+
+/* A isl_schedule_foreach_schedule_node_top_down callback
+ * for setting *any_permutable and aborting the search
+ * if "node" is a permutable band with coincident dimensions.
+ * Otherwise, continue searching.
+ */
+static isl_bool set_permutable(__isl_keep isl_schedule_node *node, void *user)
+{
+	int *any_permutable = user;
+	int permutable;
+
+	permutable = is_permutable(node);
+	if (permutable < 0)
+		return isl_bool_error;
+	if (!permutable)
+		return isl_bool_true;
+
+	*any_permutable = 1;
+
+	return isl_bool_error;
+}
+
+/* Does the subtree rooted at "node" have any suitably permutable band nodes?
+ * That is, does it have any nodes that are permutable and that
+ * have a least one coincident dimension?
+ */
+static int subtree_has_permutable_bands(__isl_keep isl_schedule_node *node)
+{
+	int any_parallelism = 0;
+
+	if (isl_schedule_node_foreach_descendant_top_down(node, &set_permutable,
+						&any_parallelism) < 0 &&
+	    !any_parallelism)
+		return -1;
+
+	return any_parallelism;
+}
+
+/* Does "schedule" contain any permutable band with at least one coincident
+ * member?
+ */
+int has_any_permutable_node(__isl_keep isl_schedule *schedule)
+{
+	isl_schedule_node *root;
+	int any_permutable;
+
+	root = isl_schedule_get_root(schedule);
+	any_permutable = subtree_has_permutable_bands(root);
+	isl_schedule_node_free(root);
+
+	return any_permutable;
+}
+
+/* Is "node" a candidate for mapping to block and thread identifiers?
+ * In particular, is it permutable with at least one coincident dimension?
+ * Alternatively, does the subtree rooted at "node" not contain
+ * any such permutable node?  Filter nodes are skipped in this case,
+ * because a band node will be inserted in front of the returned
+ * node and this is not possible for filter nodes that are children
+ * of set or sequence nodes.
+ */
+static int is_candidate(__isl_keep isl_schedule_node *node)
+{
+	int permutable;
+
+	if (isl_schedule_node_get_type(node) == isl_schedule_node_leaf)
+		return 1;
+	permutable = is_permutable(node);
+	if (permutable < 0 || permutable)
+		return permutable;
+	if (isl_schedule_node_get_type(node) == isl_schedule_node_filter)
+		return 0;
+	permutable = subtree_has_permutable_bands(node);
+	if (permutable < 0)
+		return -1;
+	return !permutable;
+}
+
+/* Is "node" the outermost node in its branch that can be tiled
+ * and then mapped to block and thread identifiers?
+ * If there are no such nodes in the subtree at "node" and
+ * if "node" is not a filter node, then it is accepted too.
+ */
+static int is_outer_tilable(__isl_keep isl_schedule_node *node)
+{
+	int tilable;
+	isl_schedule_node *ancestor;
+
+	tilable = is_candidate(node);
+	if (tilable < 0)
+		return -1;
+	if (!tilable)
+		return 0;
+
+	tilable = 0;
+	ancestor = isl_schedule_node_copy(node);
+	while (isl_schedule_node_has_parent(ancestor)) {
+		ancestor = isl_schedule_node_parent(ancestor);
+
+		tilable = is_candidate(ancestor);
+		if (tilable < 0 || tilable)
+			break;
+	}
+
+	isl_schedule_node_free(ancestor);
+	return tilable < 0 ? -1 : !tilable;
+}
+
+/* Collect the references to all writes in "group".
+ * Each reference is represented by a universe set in a space
+ *
+ *	[S[i,j] -> R[]]
+ *
+ * with S[i,j] the statement instance space and R[] the array reference.
+ */
+static __isl_give isl_union_set *group_tagged_writes(
+	struct gpu_array_ref_group *group)
+{
+	int i;
+	isl_space *space;
+	isl_union_set *writes;
+
+	space = isl_map_get_space(group->access);
+	writes = isl_union_set_empty(space);
+	for (i = 0; i < group->n_ref; ++i) {
+		isl_space *space;
+		isl_set *writes_i;
+
+		if (!group->refs[i]->write)
+			continue;
+
+		space = isl_map_get_space(group->refs[i]->tagged_access);
+		space = isl_space_domain(space);
+		writes_i = isl_set_universe(space);
+		writes = isl_union_set_add_set(writes, writes_i);
+	}
+
+	return writes;
+}
+
+/* Is there any write access in "group" that requires synchronization
+ * on a write to global memory?
+ * We currently take into account all writes that would require
+ * synchronization at the thread level depth, but if the copying
+ * for this group is performed at an outer level, then we do not
+ * actually need to take into account dependences at intermediate levels.
+ */
+static int any_sync_writes_in_group(struct ppcg_kernel *kernel,
+	struct gpu_array_ref_group *group)
+{
+	isl_union_set *writes;
+	int empty, disjoint;
+
+	empty = isl_union_set_is_empty(kernel->sync_writes);
+	if (empty < 0)
+		return -1;
+	if (empty)
+		return 0;
+
+	writes = group_tagged_writes(group);
+	disjoint = isl_union_set_is_disjoint(kernel->sync_writes, writes);
+	isl_union_set_free(writes);
+
+	return disjoint < 0 ? -1 : !disjoint;
+}
+
+/* Collect the references to all writes in "kernel" that write directly
+ * to global or shared memory, i.e., that are not mapped to private memory.
+ * Each reference is represented by a universe set in a space
+ *
+ *	[S[i,j] -> R[]]
+ *
+ * with S[i,j] the statement instance space and R[] the array reference.
+ */
+static __isl_give isl_union_set *collect_non_private_tagged_writes(
+	struct ppcg_kernel *kernel)
+{
+	isl_union_set *writes;
+	int i, j;
+
+	writes = isl_union_set_empty(isl_union_set_get_space(kernel->arrays));
+
+	for (i = 0; i < kernel->n_array; ++i) {
+		struct gpu_local_array_info *array = &kernel->array[i];
+
+		for (j = 0; j < array->n_group; ++j) {
+			struct gpu_array_ref_group *group = array->groups[j];
+			enum ppcg_group_access_type type;
+			isl_union_set *writes_ij;
+
+			if (!group->write)
+				continue;
+			type = gpu_array_ref_group_type(group);
+			if (type == ppcg_access_private)
+				continue;
+			writes_ij = group_tagged_writes(group);
+			writes = isl_union_set_union(writes, writes_ij);
+		}
+	}
+
+	return writes;
+}
+
+/* Are there any direct writes to global memory that require
+ * synchronization?
+ */
+static int any_global_or_shared_sync_writes(struct ppcg_kernel *kernel)
+{
+	isl_union_set *writes;
+	int empty, disjoint;
+
+	empty = isl_union_set_is_empty(kernel->sync_writes);
+	if (empty < 0)
+		return -1;
+	if (empty)
+		return 0;
+
+	writes = collect_non_private_tagged_writes(kernel);
+	disjoint = isl_union_set_is_disjoint(kernel->sync_writes, writes);
+	isl_union_set_free(writes);
+
+	return disjoint < 0 ? -1 : !disjoint;
+}
+
+/* Construct an isl_multi_val for use as tile sizes for tiling "node"
+ * from the elements in "tile_size".
+ */
+static __isl_give isl_multi_val *construct_band_tiles_sizes(
+	__isl_keep isl_schedule_node *node, int *tile_size)
+{
+	isl_space *space;
+
+	if (!node)
+		return NULL;
+
+	space = isl_schedule_node_band_get_space(node);
+	return ppcg_multi_val_from_int_list(space, tile_size);
+}
+
+/* Replace the partial schedule S of the band node "node" by
+ *
+ *	floor(S/f)
+ *
+ * or
+ *
+ *	f * floor(S/f)
+ *
+ * if scale_tile_loops is set, with f the integers in "factor".
+ * The list that "factor" points to is assumed to contain at least
+ * as many elements as the number of members in the band.
+ */
+static __isl_give isl_schedule_node *snap_band_to_sizes(
+	__isl_take isl_schedule_node *node, int *factor,
+	struct ppcg_options *options)
+{
+	isl_multi_val *mv;
+
+	mv = construct_band_tiles_sizes(node, factor);
+	node = isl_schedule_node_band_scale_down(node, isl_multi_val_copy(mv));
+	if (options->scale_tile_loops)
+		node = isl_schedule_node_band_scale(node,
+							isl_multi_val_copy(mv));
+	isl_multi_val_free(mv);
+
+	return node;
+}
+
+/* Tile "band" with tile size specified by "sizes".
+ *
+ * Since the tile loops will be mapped to block ids, we forcibly
+ * turn off tile loop scaling.  We may want to enable tile loop scaling
+ * at some later point, but then we would have to support the detection
+ * of strides during the mapping to block ids.
+ * Similarly, since the point loops will be mapped to thread ids,
+ * we forcibly shift the point loops so that they start at zero.
+ */
+static __isl_give isl_schedule_node *tile_band(
+	__isl_take isl_schedule_node *node, __isl_take isl_multi_val *sizes)
+{
+	isl_ctx *ctx = isl_schedule_node_get_ctx(node);
+	int scale_tile;
+	int shift_point;
+
+	scale_tile = isl_options_get_tile_scale_tile_loops(ctx);
+	isl_options_set_tile_scale_tile_loops(ctx, 0);
+	shift_point = isl_options_get_tile_shift_point_loops(ctx);
+	isl_options_set_tile_shift_point_loops(ctx, 1);
+
+	node = isl_schedule_node_band_tile(node, sizes);
+
+	isl_options_set_tile_scale_tile_loops(ctx, scale_tile);
+	isl_options_set_tile_shift_point_loops(ctx, shift_point);
+
+	return node;
+}
+
+/* Extract the set of parameter values and outer schedule dimensions
+ * for which any statement instance
+ * in the kernel inserted at "node" needs to be executed.
+ * Intersect the set of parameter values derived from the host schedule
+ * relation with the context of "prog".
+ */
+static __isl_give isl_set *extract_context(__isl_keep isl_schedule_node *node,
+	struct gpu_prog *prog)
+{
+	isl_union_map *schedule;
+	isl_union_set *schedule_domain;
+	isl_set *context;
+	int empty;
+
+	schedule = isl_schedule_node_get_prefix_schedule_relation(node);
+	schedule_domain = isl_union_map_range(schedule);
+	empty = isl_union_set_is_empty(schedule_domain);
+	if (empty < 0) {
+		isl_union_set_free(schedule_domain);
+		return NULL;
+	}
+	if (empty) {
+		int depth;
+		isl_space *space;
+
+		space = isl_union_set_get_space(schedule_domain);
+		isl_union_set_free(schedule_domain);
+		space = isl_space_set_from_params(space);
+		depth = isl_schedule_node_get_schedule_depth(node);
+		space = isl_space_add_dims(space, isl_dim_set, depth);
+		context = isl_set_empty(space);
+	} else {
+		context = isl_set_from_union_set(schedule_domain);
+	}
+	context = isl_set_intersect_params(context,
+					    isl_set_copy(prog->context));
+
+	return context;
+}
+
+/* Return the set of outer array elements accessed by
+ * by the statement instances in "domain" in "prog".
+ * The instances in "domain" are those that appear
+ * in the domains of the access relations in "prog".
+ */
+static __isl_give isl_union_set *accessed_by_domain(
+	__isl_take isl_union_set *domain, struct gpu_prog *prog)
+{
+	isl_union_map *access;
+	isl_union_set *arrays;
+
+	access = isl_union_map_union(isl_union_map_copy(prog->read),
+				     isl_union_map_copy(prog->may_write));
+	access = isl_union_map_intersect_domain(access, domain);
+	arrays = isl_union_map_range(access);
+	arrays = isl_union_set_apply(arrays,
+				isl_union_map_copy(prog->to_outer));
+
+	return arrays;
+}
+
+/* Return the number of outer band members of the band node "node"
+ * that are marked coincident.
+ */
+static int n_outer_coincidence(__isl_keep isl_schedule_node *node)
+{
+	int i, n;
+
+	n = isl_schedule_node_band_n_member(node);
+
+	for (i = 0; i < n; ++i)
+		if (!isl_schedule_node_band_member_get_coincident(node, i))
+			break;
+
+	return i;
+}
+
+/* If the band node "node" has more than "n" members, then split off
+ * the first "n" of them.
+ */
+static __isl_give isl_schedule_node *split_band(
+	__isl_take isl_schedule_node *node, int n)
+{
+	int dim;
+
+	dim = isl_schedule_node_band_n_member(node);
+	if (n < dim)
+		node = isl_schedule_node_band_split(node, n);
+
+	return node;
+}
+
+/* Scale a band node that may have been split by split_band.
+ * "sizes" are the scaling factors for the original node.
+ * "node" either points to the original band node, or the outer
+ * of the two pieces after splitting.
+ *
+ * If the number of elements in "node" is smaller than the number of
+ * elements in "sizes", then some splitting has occurred and we split
+ * "sizes" in the same way.
+ */
+static __isl_give isl_schedule_node *scale_band(
+	__isl_take isl_schedule_node *node, __isl_take isl_multi_val *sizes)
+{
+	int n, dim;
+
+	n = isl_multi_val_dim(sizes, isl_dim_set);
+	dim = isl_schedule_node_band_n_member(node);
+	if (n > dim) {
+		isl_multi_val *sizes2;
+
+		sizes2 = isl_multi_val_copy(sizes);
+		sizes = isl_multi_val_drop_dims(sizes,
+						isl_dim_set, dim, n - dim);
+		sizes2 = isl_multi_val_drop_dims(sizes2, isl_dim_set, 0, dim);
+		node = isl_schedule_node_child(node, 0);
+		node = isl_schedule_node_band_scale(node, sizes2);
+		node = isl_schedule_node_parent(node);
+	}
+
+	return isl_schedule_node_band_scale(node, sizes);
+}
+
+/* Return an isl_multi_aff, with as elements the parameters in "space"
+ * that have the names specified by the elements in "names".
+ * If (some of) these parameters do not already appear in "space",
+ * then they are added first.
+ */
+static __isl_give isl_multi_aff *parameter_vector(__isl_take isl_space *space,
+	__isl_keep isl_id_list *names)
+{
+	int i, n;
+	isl_local_space *ls;
+	isl_multi_aff *ma;
+
+	if (!names)
+		space = isl_space_free(space);
+
+	n = isl_id_list_n_id(names);
+	for (i = 0; i < n; ++i) {
+		int pos;
+		isl_id *id;
+
+		id = isl_id_list_get_id(names, i);
+		pos = isl_space_find_dim_by_id(space, isl_dim_param, id);
+		if (pos >= 0) {
+			isl_id_free(id);
+			continue;
+		}
+		pos = isl_space_dim(space, isl_dim_param);
+		space = isl_space_add_dims(space, isl_dim_param, 1);
+		space = isl_space_set_dim_id(space, isl_dim_param, pos, id);
+	}
+	ma = isl_multi_aff_zero(isl_space_copy(space));
+	ls = isl_local_space_from_space(isl_space_domain(space));
+	for (i = 0; i < n; ++i) {
+		int pos;
+		isl_id *id;
+		isl_aff *aff;
+
+		id = isl_id_list_get_id(names, i);
+		pos = isl_space_find_dim_by_id(space, isl_dim_param, id);
+		isl_id_free(id);
+		aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
+					    isl_dim_param, pos);
+		ma = isl_multi_aff_set_aff(ma, i, aff);
+	}
+	isl_local_space_free(ls);
+
+	return ma;
+}
+
+/* Return constraints on the domain elements that equate a sequence of
+ * parameters called "names", to the partial schedule
+ * of "node" modulo the integers in "size".
+ * The number of elements in the array "size" should be equal
+ * to the number of elements in "names".
+ * The number of members of the band node "node" should be smaller
+ * than or equal to this number.  If it is smaller, then the first
+ * elements of "names" are equated to zero.
+ */
+static __isl_give isl_union_set *set_schedule_modulo(
+	__isl_keep isl_schedule_node *node, __isl_keep isl_id_list *names,
+	int *size)
+{
+	int n, n_zero;
+	isl_space *space;
+	isl_multi_aff *ma;
+	isl_multi_union_pw_aff *mupa, *mupa2;
+	isl_multi_val *mv;
+	isl_union_set *domain;
+
+	if (!node)
+		return NULL;
+	n = isl_id_list_n_id(names);
+	if (n == 0)
+		return isl_schedule_node_get_universe_domain(node);
+	n_zero = n - isl_schedule_node_band_n_member(node);
+
+	mupa = isl_schedule_node_band_get_partial_schedule(node);
+	mv = construct_band_tiles_sizes(node, size + n_zero);
+	mupa = isl_multi_union_pw_aff_mod_multi_val(mupa, mv);
+
+	space = isl_multi_union_pw_aff_get_space(mupa);
+	space = isl_space_params(space);
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, n_zero);
+	ma = isl_multi_aff_zero(space);
+
+	domain = isl_schedule_node_get_universe_domain(node);
+	mupa2 = isl_multi_union_pw_aff_multi_aff_on_domain(
+						isl_union_set_copy(domain), ma);
+	mupa = isl_multi_union_pw_aff_range_product(mupa2, mupa);
+
+	space = isl_multi_union_pw_aff_get_space(mupa);
+	ma = parameter_vector(space, names);
+
+	mupa2 = isl_multi_union_pw_aff_multi_aff_on_domain(domain, ma);
+	mupa = isl_multi_union_pw_aff_sub(mupa, mupa2);
+
+	return isl_multi_union_pw_aff_zero_union_set(mupa);
+}
+
+/* Insert a context node at "node" introducing the block and thread
+ * identifiers along with their bounds, which are stored in kernel->grid_size
+ * and kernel->block_dim.
+ * Note that the bounds on the block identifiers may implicitly impose
+ * constraints on the parameters.  A guard needs to be inserted
+ * in the schedule tree to ensure that those bounds hold at "node".
+ * This guard is inserted in insert_guard.
+ */
+static __isl_give isl_schedule_node *insert_context(struct ppcg_kernel *kernel,
+	__isl_take isl_schedule_node *node)
+{
+	isl_set *context;
+
+	context = isl_set_universe(isl_set_get_space(kernel->context));
+
+	context = add_bounded_parameters_dynamic(context,
+					kernel->grid_size, kernel->block_ids);
+	context = add_bounded_parameters(context,
+					kernel->block_dim, kernel->thread_ids);
+
+	node = isl_schedule_node_insert_context(node, context);
+
+	return node;
+}
+
+/* Insert a guard that eliminates kernel launches where the kernel
+ * obviously does not have any work to do.
+ *
+ * In particular, eliminate kernel launches where there are obviously
+ * zero blocks.
+ * Use the same block size constraints that are used to create the context
+ * to ensure that all constraints implicit in the constructed context
+ * are imposed by the guard.
+ *
+ * Additionally, add other constraints that are valid
+ * for each executed instance ("context"), as long as this does not result
+ * in a disjunction.
+ */
+static __isl_give isl_schedule_node *insert_guard(
+	__isl_take isl_schedule_node *node, __isl_keep isl_set *context,
+	__isl_keep isl_multi_pw_aff *size, struct ppcg_scop *scop)
+{
+	unsigned nparam, n;
+	isl_set *guard;
+	isl_id_list *ids;
+
+	guard = isl_set_copy(context);
+	guard = isl_set_compute_divs(guard);
+	guard = isl_set_from_basic_set(isl_set_simple_hull(guard));
+
+	nparam = isl_set_dim(guard, isl_dim_param);
+	n = isl_multi_pw_aff_dim(size, isl_dim_out);
+	ids = ppcg_scop_generate_names(scop, n, "__ppcg_tmp");
+	guard = add_bounded_parameters_dynamic(guard, size, ids);
+	isl_id_list_free(ids);
+	guard = isl_set_project_out(guard, isl_dim_param, nparam, n);
+
+	node = isl_schedule_node_insert_guard(node, guard);
+
+	return node;
+}
+
+/* Does any array reference group mapping require the band that is mapped
+ * to threads to be unrolled?
+ */
+static int kernel_requires_unroll(struct ppcg_kernel *kernel)
+{
+	int i, j;
+
+	for (i = 0; i < kernel->n_array; ++i) {
+		struct gpu_local_array_info *array = &kernel->array[i];
+
+		for (j = 0; j < array->n_group; ++j) {
+			struct gpu_array_ref_group *group = array->groups[j];
+			if (gpu_array_ref_group_requires_unroll(group))
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
+/* Mark the given band node "node" for unrolling by the AST generator and
+ * then sink it to the leaves of the schedule tree.
+ * All dimensions of "node" are assumed to be coincident, such that this
+ * sinking is a valid operation.
+ */
+static __isl_give isl_schedule_node *unroll(__isl_take isl_schedule_node *node)
+{
+	node = ppcg_set_schedule_node_type(node, isl_ast_loop_unroll);
+
+	node = isl_schedule_node_band_sink(node);
+
+	return node;
+}
+
+/* Insert a synchronization node in the schedule tree of "node"
+ * after the core computation of "kernel" at the level of the band
+ * that is mapped to threads, except if that level is equal to
+ * that of the band that is mapped to blocks or if there are no writes
+ * to global or shared memory in the core computation that require
+ * synchronization.
+ * If there are any writes to shared memory and the shared memory
+ * copying is performed at the same level, then synchronization
+ * is needed between the core and the copying anyway, so we might
+ * as well add it here.  If the copying is performed at a higher
+ * level, then different iterations of intermediate schedule dimensions
+ * may have a different mapping from between shared memory elements and
+ * threads, such that synchronization is required after the core.
+ * "node" is assumed to point to the kernel node.
+ *
+ * If the shared and the thread mark point to the same node, then make
+ * sure the synchronization is inserted outside of the shared mark.
+ */
+static __isl_give isl_schedule_node *add_sync(struct ppcg_kernel *kernel,
+	__isl_take isl_schedule_node *node)
+{
+	int depth;
+	int need_sync;
+
+	need_sync = any_global_or_shared_sync_writes(kernel);
+	if (need_sync < 0)
+		return isl_schedule_node_free(node);
+	if (!need_sync)
+		return node;
+
+	node = gpu_tree_move_down_to_thread(node, kernel->core);
+	depth = isl_schedule_node_get_schedule_depth(node);
+	node = gpu_tree_move_up_to_kernel(node);
+	if (depth == isl_schedule_node_get_schedule_depth(node))
+		return node;
+
+	node = gpu_tree_move_down_to_depth(node, depth, kernel->core);
+	node = gpu_tree_ensure_following_sync(node, kernel);
+
+	node = gpu_tree_move_up_to_kernel(node);
+
+	return node;
+}
+
+/* Return a read ("read" is 1) or write access relation for "group"
+ * with those accesses removed that are only needed to communicate data
+ * within the subtree of the schedule rooted at "node".
+ * Furthermore, include the prefix schedule at "node".
+ * That is, return a relation of the form
+ *
+ *	S -> [D -> A]
+ *
+ * with D the outer schedule dimensions at "node".
+ */
+static __isl_give isl_union_map *anchored_non_local_accesses(
+	struct ppcg_kernel *kernel, struct gpu_array_ref_group *group,
+	__isl_take isl_schedule_node *node, int read)
+{
+	isl_union_map *access;
+	isl_union_map *prefix;
+
+	prefix = isl_schedule_node_get_prefix_schedule_relation(node);
+	prefix = isl_union_map_preimage_domain_union_pw_multi_aff(prefix,
+			    isl_union_pw_multi_aff_copy(kernel->contraction));
+	access = gpu_array_ref_group_access_relation(group, read, !read);
+	access = remove_local_accesses_group(kernel, group, access, prefix,
+						read);
+	access = isl_union_map_range_product(prefix, access);
+
+	return access;
+}
+
+/* Given an array reference group "group", create a mapping
+ *
+ *	read[D -> A] -> [D -> A]
+ *
+ * if "read" is set or
+ *
+ *	write[D -> A] -> [D -> A]
+ *
+ * if "read" is not set.
+ * D corresponds to the outer tile->depth dimensions of
+ * the kernel schedule.
+ */
+static __isl_give isl_multi_aff *create_from_access(isl_ctx *ctx,
+	struct gpu_array_ref_group *group, int read)
+{
+	struct gpu_array_tile *tile;
+	isl_space *space;
+	isl_id *id;
+
+	tile = gpu_array_ref_group_tile(group);
+	space = isl_space_copy(group->array->space);
+	space = isl_space_from_range(space);
+	space = isl_space_add_dims(space, isl_dim_in, tile->depth);
+	space = isl_space_wrap(space);
+	space = isl_space_map_from_set(space);
+
+	id = isl_id_alloc(ctx, read ? "read" : "write", group);
+	space = isl_space_set_tuple_id(space, isl_dim_in, id);
+
+	return isl_multi_aff_identity(space);
+}
+
+/* If any writes in "group" require synchronization, then make sure
+ * that there is a synchronization node for "kernel" after the node
+ * following "node" in a sequence.
+ *
+ * If "shared" is set and no synchronization is needed for
+ * the writes to global memory, then add synchronization before
+ * the kernel to protect shared memory from being overwritten
+ * by the next iteration of the core computation.
+ * No additional synchronization is needed to protect against
+ * the next copy into shared memory because each element of
+ * the shared memory tile is always copied by the same thread.
+ */
+static __isl_give isl_schedule_node *add_group_write_sync(
+	__isl_take isl_schedule_node *node, struct ppcg_kernel *kernel,
+	struct gpu_array_ref_group *group, int shared)
+{
+	int need_sync;
+
+	need_sync = any_sync_writes_in_group(kernel, group);
+	if (need_sync < 0)
+		return isl_schedule_node_free(node);
+	if (need_sync) {
+		node = isl_schedule_node_parent(node);
+		node = isl_schedule_node_next_sibling(node);
+		node = isl_schedule_node_child(node, 0);
+		node = gpu_tree_ensure_following_sync(node, kernel);
+	} else if (shared) {
+		struct gpu_array_tile *tile;
+
+		tile = gpu_array_ref_group_tile(group);
+		node = isl_schedule_node_parent(node);
+		node = isl_schedule_node_parent(node);
+		node = gpu_tree_move_down_to_depth(node, tile->depth,
+							kernel->core);
+		node = gpu_tree_move_left_to_sync(node, kernel);
+	}
+
+	return node;
+}
+
+/* Add copy statements to the schedule tree of "node"
+ * for reading from global memory to private memory (if "read" is set) or
+ * for writing back from private memory to global memory
+ * (if "read" is not set) for the array reference group "group" that
+ * is mapped to private memory.
+ * On input, "node" points to the kernel node, and it is moved
+ * back there on output.
+ *
+ * The copies are performed in the order of the array elements.
+ * The copy statement instances include a reference to the outer
+ * tile->depth dimensions of the kernel schedule for ease of
+ * combining them with the group tiling.
+ *
+ * That is, the extra schedule is of the form
+ *
+ *	type[D -> A] -> A
+ *
+ * where D corresponds to the outer tile->depth dimensions of
+ * the kernel schedule and A to the global array.
+ * This schedule is unrolled because registers are not addressable.
+ *
+ * The copying is inserted in the schedule tree through an extension
+ * of the form
+ *
+ *	D -> type[D -> A]
+ *
+ * where the extra domain elements type[D -> A] are those accessed
+ * by the group.
+ * A filter is inserted on type[D -> A] to ensure that the element
+ * is read/written by the same thread that needs the element.
+ * This filter is obtained by applying
+ *
+ *	S -> type[D -> A]
+ *
+ * to the thread filter for the core statements.
+ *
+ * The extension is inserted before the core computation in case of a read
+ * and after the core computation in case of a write.
+ * In the latter case, we also make sure that there is a synchronization
+ * node after the write to global memory, unless this write is performed
+ * at the outer level of the kernel.
+ * In principle, this synchronization could be inserted higher
+ * in the schedule tree depending on where the corresponding reads
+ * from global memory are performed.
+ */
+static __isl_give isl_schedule_node *add_copies_group_private(
+	struct ppcg_kernel *kernel, struct gpu_array_ref_group *group,
+	__isl_take isl_schedule_node *node, int read)
+{
+	struct gpu_array_tile *tile;
+	isl_union_map *access;
+	isl_union_set *domain;
+	isl_space *space;
+	isl_multi_aff *from_access;
+	isl_multi_pw_aff *mpa;
+	isl_multi_union_pw_aff *mupa;
+	isl_union_pw_multi_aff *contraction;
+	isl_schedule_node *graft;
+	isl_union_set *filter;
+	int kernel_depth;
+	int empty;
+
+	kernel_depth = isl_schedule_node_get_schedule_depth(node);
+	tile = gpu_array_ref_group_tile(group);
+	node = gpu_tree_move_down_to_depth(node, tile->depth, kernel->core);
+
+	access = anchored_non_local_accesses(kernel, group, node, read);
+	empty = isl_union_map_is_empty(access);
+	if (empty < 0 || empty) {
+		isl_union_map_free(access);
+		if (empty < 0)
+			return isl_schedule_node_free(node);
+		return gpu_tree_move_up_to_kernel(node);
+	}
+
+	group->array->global = 1;
+	group->local_array->global = 1;
+
+	from_access = create_from_access(kernel->ctx, group, read);
+	space = isl_space_domain(isl_multi_aff_get_space(from_access));
+	access = isl_union_map_preimage_range_multi_aff(access, from_access);
+
+	filter = isl_union_set_copy(kernel->thread_filter);
+	contraction = isl_union_pw_multi_aff_copy(kernel->contraction);
+	filter = isl_union_set_preimage_union_pw_multi_aff(filter, contraction);
+	filter = isl_union_set_apply(filter, isl_union_map_copy(access));
+	filter = isl_union_set_detect_equalities(filter);
+	filter = isl_union_set_coalesce(filter);
+
+	domain = isl_union_map_range(access);
+	access = isl_union_set_wrapped_domain_map(domain);
+	access = isl_union_map_reverse(access);
+	access = isl_union_map_coalesce(access);
+	graft = isl_schedule_node_from_extension(access);
+
+	space = isl_space_map_from_set(space);
+	mpa = isl_multi_pw_aff_identity(space);
+	mpa = isl_multi_pw_aff_range_factor_range(mpa);
+	mupa = isl_multi_union_pw_aff_from_multi_pw_aff(mpa);
+
+	graft = isl_schedule_node_child(graft, 0);
+	graft = isl_schedule_node_insert_partial_schedule(graft, mupa);
+	graft = unroll(graft);
+
+	graft = isl_schedule_node_insert_filter(graft, filter);
+
+	graft = isl_schedule_node_parent(graft);
+
+	if (read)
+		node = isl_schedule_node_graft_before(node, graft);
+	else {
+		node = isl_schedule_node_graft_after(node, graft);
+		if (kernel_depth < tile->depth)
+			node = add_group_write_sync(node, kernel, group, 0);
+	}
+
+	node = gpu_tree_move_up_to_kernel(node);
+
+	return node;
+}
+
+/* Add copy statements to the schedule tree of "node"
+ * for reading from global memory to shared memory (if "read" is set) or
+ * for writing back from shared memory to global memory
+ * (if "read" is not set) for the array reference group "group" that
+ * is mapped to shared memory.
+ * On input, "node" points to the kernel node, and it is moved
+ * back there on output.
+ *
+ * The copies are performed in the order of the corresponding shared
+ * memory tile.
+ * The copy statement instances include a reference to the outer
+ * tile->depth dimensions of the kernel schedule for ease of
+ * combining them with the group tiling.
+ *
+ * If we are performing a read from global memory to shared memory and
+ * if the array involved is not a scalar, then we copy
+ * the entire tile to shared memory.  This may result in some extra
+ * elements getting copied, but it should lead to simpler code
+ * (which means that fewer registers may be needed) and less divergence.
+ *
+ * Otherwise, we only copy the elements that will be read or have been written
+ * in the kernel.
+ *
+ * That is, the extra schedule is of the form
+ *
+ *	type[D -> A] -> T
+ *
+ * where D corresponds to the outer tile->depth dimensions of
+ * the kernel schedule, A to the global array and T is the corresponding
+ * shared memory tile.
+ *
+ * The copying is inserted in the schedule tree through an extension
+ * of the form
+ *
+ *	D -> type[D -> A]
+ *
+ * where the extra domain elements type[D -> A] are those accessed
+ * by the group.  In the case of read from a non-scalar, this set
+ * is replaced by the entire shared memory tile.
+ *
+ * If the "unroll_copy_shared" option is set, then the AST generator
+ * is instructed to unroll the copying code.
+ *
+ * A filter is inserted on type[D -> A] to map the copy instances
+ * to the threads.  In particular, the thread identifiers are
+ * equated to the position inside the shared memory tile (T)
+ * modulo the block size.
+ * We try to align the innermost tile dimension with the innermost
+ * thread identifier (x) as a heuristic to improve coalescing.
+ * In particular, if the dimension of the tile is greater than
+ * the dimension of the block, then the schedule mapping to the tile
+ * is broken up into two pieces and the filter is applied to the inner part.
+ * If, on the other hand, the dimension of the tile is smaller than
+ * the dimension of the block, then the initial thread identifiers
+ * are equated to zero and the remaining thread identifiers are
+ * matched to the memory tile.
+ *
+ * The extension is inserted before the core computation in case of a read
+ * and after the core computation in case of a write.
+ * In the case of a read, we first need to make sure there is some
+ * synchronization before the core computation such that we can put the read
+ * from global memory to shared memory before that synchronization.
+ * This ensures that all threads have finished copying into shared memory
+ * before the shared memory is used.
+ * We also need to make sure that there is a synchronization node after
+ * the core computation to ensure that the next load into shared memory
+ * only happens after all data has been used.  There is no need for
+ * this synchronization if we are at the outer level since then there
+ * won't be a next load.
+ * In the case of a write, we need to make sure there is some synchronization
+ * after the core computation such taht we can put the write from shared
+ * memory to global memory after that synchronization.
+ * Unless we are at the outer level, we also need a synchronization node
+ * after the write to ensure the data is saved to global memory
+ * before the next iteration write to the same shared memory.
+ * It also makes sure the data has arrived in global memory before
+ * it is read in a subsequent iteration.
+ */
+static __isl_give isl_schedule_node *add_copies_group_shared(
+	struct ppcg_kernel *kernel, struct gpu_array_ref_group *group,
+	__isl_take isl_schedule_node *node, int read)
+{
+	struct gpu_array_tile *tile;
+	isl_union_map *access;
+	isl_union_set *domain;
+	isl_multi_aff *ma;
+	isl_multi_aff *from_access;
+	isl_multi_pw_aff *mpa;
+	isl_multi_union_pw_aff *mupa;
+	isl_schedule_node *graft;
+	isl_union_set *filter;
+	int skip;
+	int kernel_depth;
+	int empty;
+
+	tile = gpu_array_ref_group_tile(group);
+	kernel_depth = isl_schedule_node_get_schedule_depth(node);
+	node = gpu_tree_move_down_to_depth(node, tile->depth, kernel->core);
+
+	access = anchored_non_local_accesses(kernel, group, node, read);
+	empty = isl_union_map_is_empty(access);
+	if (empty < 0 || empty) {
+		isl_union_map_free(access);
+		if (empty < 0)
+			return isl_schedule_node_free(node);
+		return gpu_tree_move_up_to_kernel(node);
+	}
+
+	group->array->global = 1;
+	group->local_array->global = 1;
+
+	from_access = create_from_access(kernel->ctx, group, read);
+
+	ma = isl_multi_aff_copy(tile->tiling);
+	ma = isl_multi_aff_pullback_multi_aff(ma,
+					    isl_multi_aff_copy(from_access));
+	mpa = isl_multi_pw_aff_from_multi_aff(ma);
+	mupa = isl_multi_union_pw_aff_from_multi_pw_aff(mpa);
+
+	domain = isl_union_map_range(access);
+
+	if (read && !gpu_array_is_scalar(group->array)) {
+		isl_map *map;
+		isl_union_set_free(domain);
+		map = group_tile(group);
+		domain = isl_union_set_from_set(isl_map_wrap(map));
+	}
+
+	domain = isl_union_set_preimage_multi_aff(domain, from_access);
+	access = isl_union_set_wrapped_domain_map(domain);
+	access = isl_union_map_reverse(access);
+	access = isl_union_map_coalesce(access);
+	graft = isl_schedule_node_from_extension(access);
+
+	graft = isl_schedule_node_child(graft, 0);
+
+	graft = isl_schedule_node_insert_partial_schedule(graft, mupa);
+	if (kernel->options->unroll_copy_shared)
+		graft = ppcg_set_schedule_node_type(graft, isl_ast_loop_unroll);
+
+	if (tile->n > kernel->n_block && kernel->n_block > 0) {
+		graft = isl_schedule_node_band_split(graft,
+						tile->n - kernel->n_block);
+		graft = isl_schedule_node_child(graft, 0);
+	}
+	if (tile->n < kernel->n_block)
+		skip = kernel->n_block - tile->n;
+	else
+		skip = 0;
+	filter = set_schedule_modulo(graft, kernel->thread_ids,
+					kernel->block_dim);
+	if (!kernel->options->wrap)
+		graft = snap_band_to_sizes(graft, kernel->block_dim + skip,
+			    kernel->options);
+	if (tile->n > kernel->n_block && kernel->n_block > 0)
+		graft = isl_schedule_node_parent(graft);
+	graft = isl_schedule_node_insert_filter(graft, filter);
+
+	while (graft && isl_schedule_node_has_parent(graft))
+		graft = isl_schedule_node_parent(graft);
+
+	if (read) {
+		if (kernel_depth < tile->depth)
+			node = gpu_tree_ensure_sync_after_core(node, kernel);
+		node = gpu_tree_move_left_to_sync(node, kernel);
+		node = isl_schedule_node_graft_before(node, graft);
+	} else {
+		node = gpu_tree_move_right_to_sync(node, kernel);
+		node = isl_schedule_node_graft_after(node, graft);
+		if (kernel_depth < tile->depth)
+			node = add_group_write_sync(node, kernel, group, 1);
+	}
+
+	node = gpu_tree_move_up_to_kernel(node);
+
+	return node;
+}
+
+/* Check whether the array reference group "group" is mapped to
+ * private or shared memory and, if so,
+ * add copy statements to the schedule tree of "node"
+ * for reading from global memory to private or shared memory
+ * (if "read" is set) or for writing back from private or shared memory
+ * to global memory (if "read" is not set) for this group.
+ * On input, "node" points to the kernel node, and it is moved
+ * back there on output.
+ */
+static __isl_give isl_schedule_node *add_copies_group(
+	struct ppcg_kernel *kernel, struct gpu_array_ref_group *group,
+	__isl_take isl_schedule_node *node, int read)
+{
+	enum ppcg_group_access_type type;
+
+	type = gpu_array_ref_group_type(group);
+	if (type == ppcg_access_private)
+		return add_copies_group_private(kernel, group, node, read);
+	if (type == ppcg_access_shared)
+		return add_copies_group_shared(kernel, group, node, read);
+	return node;
+}
+
+/* For each array reference group that is mapped to private or shared memory,
+ * add copy statements to the schedule tree of "node"
+ * for reading from global memory to private or shared memory
+ * and for writing back.
+ * On input, "node" points to the kernel node, and it is moved
+ * back there on output.
+ */
+static __isl_give isl_schedule_node *add_copies(struct ppcg_kernel *kernel,
+	__isl_take isl_schedule_node *node)
+{
+	int i, j;
+
+	for (i = 0; i < kernel->n_array; ++i) {
+		struct gpu_local_array_info *array = &kernel->array[i];
+
+		for (j = 0; j < array->n_group; ++j) {
+			struct gpu_array_ref_group *group = array->groups[j];
+
+			node = add_copies_group(kernel, group, node, 1);
+			if (!node)
+				return NULL;
+			node = add_copies_group(kernel, group, node, 0);
+			if (!node)
+				return NULL;
+		}
+	}
+
+	return node;
+}
+
+/* Mark all dimensions in the current band node atomic.
+ */
+static __isl_give isl_schedule_node *atomic(__isl_take isl_schedule_node *node)
+{
+	return ppcg_set_schedule_node_type(node, isl_ast_loop_atomic);
+}
+
+/* Mark "node" atomic, if it is a band node.
+ * Do the same for all ancestors.
+ * Return a pointer to "node" (in the updated schedule tree).
+ */
+static __isl_give isl_schedule_node *atomic_ancestors(
+	__isl_take isl_schedule_node *node)
+{
+	int pos;
+
+	if (!node)
+		return NULL;
+	if (!isl_schedule_node_has_parent(node))
+		return node;
+
+	pos = isl_schedule_node_get_child_position(node);
+	node = isl_schedule_node_parent(node);
+	if (isl_schedule_node_get_type(node) == isl_schedule_node_band)
+		node = atomic(node);
+	node = atomic_ancestors(node);
+	node = isl_schedule_node_child(node, pos);
+
+	return node;
+}
+
+/* Collect all write references that require synchronization.
+ * "node" is assumed to point to the kernel node.
+ * Each reference is represented by a universe set in a space
+ *
+ *	[S[i,j] -> R[]]
+ *
+ * with S[i,j] the statement instance space and R[] the array reference.
+ *
+ * This function should be called before block and thread filters are added.
+ *
+ * Synchronization is needed after a write if there is a subsequent read
+ * within the same block that may not be performed by the same thread.
+ * There should not be any dependences between different blocks,
+ * so we start with the flow dependences within the same kernel invocation
+ * and we subtract from these those dependences that are mapped
+ * to the same iteration of the bands where synchronization is inserted.
+ * We do not remove pairs of instances that are known to map to
+ * the same thread across different iterations of the intermediate
+ * bands because the read may be performed by a different thread
+ * than the one that needs the value if shared memory is involved.
+ *
+ * We also consider all pairs of possible writes that access the same
+ * memory location and that may be mapped to the same block but not
+ * to the same iteration of the intermediate bands.
+ * In theory, it would be possible for one thread to still be in
+ * a previous iteration of a loop in these bands.
+ * A write to global memory in this delayed thread could then overwrite
+ * a write from another thread that has already moved on to
+ * the next iteration.
+ *
+ * After computing the above writes paired off with reads or writes
+ * that depend on them, we project onto the domain writes.
+ * Sychronization is needed after writes to global memory
+ * through these references.
+ */
+static __isl_give isl_union_set *compute_sync_writes(
+	struct ppcg_kernel *kernel, __isl_keep isl_schedule_node *node)
+{
+	isl_union_map *local;
+	isl_union_map *may_writes, *shared_access;
+	isl_union_map *kernel_prefix, *thread_prefix;
+	isl_union_map *equal;
+	isl_union_set *wrap;
+	isl_union_set *domain;
+	isl_union_pw_multi_aff *contraction;
+
+	kernel_prefix = isl_schedule_node_get_prefix_schedule_union_map(node);
+	node = isl_schedule_node_copy(node);
+	node = gpu_tree_move_down_to_thread(node, kernel->core);
+	thread_prefix = isl_schedule_node_get_prefix_schedule_union_map(node);
+	isl_schedule_node_free(node);
+
+	contraction = kernel->contraction;
+	kernel_prefix = isl_union_map_preimage_domain_union_pw_multi_aff(
+		    kernel_prefix, isl_union_pw_multi_aff_copy(contraction));
+	thread_prefix = isl_union_map_preimage_domain_union_pw_multi_aff(
+		    thread_prefix, isl_union_pw_multi_aff_copy(contraction));
+	domain = isl_union_set_copy(kernel->expanded_domain);
+	domain = isl_union_set_universe(domain);
+
+	may_writes = isl_union_map_copy(kernel->prog->scop->tagged_may_writes);
+	may_writes = isl_union_map_curry(may_writes);
+	may_writes = isl_union_map_intersect_domain(may_writes, domain);
+	may_writes = isl_union_map_uncurry(may_writes);
+	shared_access = isl_union_map_copy(may_writes);
+	shared_access = isl_union_map_apply_range(shared_access,
+					isl_union_map_reverse(may_writes));
+
+	local = isl_union_map_copy(kernel->prog->scop->tagged_dep_flow);
+	local = isl_union_map_union(local, shared_access);
+	local = isl_union_map_zip(local);
+
+	equal = isl_union_map_apply_range(kernel_prefix,
+		    isl_union_map_reverse(isl_union_map_copy(kernel_prefix)));
+	wrap = isl_union_map_wrap(equal);
+	local = isl_union_map_intersect_domain(local, wrap);
+	equal = isl_union_map_apply_range(thread_prefix,
+		    isl_union_map_reverse(isl_union_map_copy(thread_prefix)));
+	wrap = isl_union_map_wrap(equal);
+	local = isl_union_map_subtract_domain(local, wrap);
+
+	local = isl_union_map_zip(local);
+	local = isl_union_map_universe(local);
+
+	return isl_union_map_domain(local);
+}
+
+/* Group the domain elements into a single space, named kernelX,
+ * with X the kernel sequence number "kernel_id".
+ */
+static __isl_give isl_schedule_node *group_statements(
+	__isl_take isl_schedule_node *node, int kernel_id)
+{
+	char buffer[20];
+	isl_id *id;
+
+	if (!node)
+		return NULL;
+
+	snprintf(buffer, sizeof(buffer), "kernel%d", kernel_id);
+	id = isl_id_alloc(isl_schedule_node_get_ctx(node), buffer, NULL);
+	return isl_schedule_node_group(node, id);
+}
+
+/* Create a ppcg_kernel representing the domain instances that reach "node"
+ * and insert a mark node pointing to the ppcg_kernel before "node".
+ * The band that "node" points to is the band that needs to be mapped
+ * to block identifiers.  The band that needs to be mapped to thread
+ * identifiers should be marked by a "thread" mark by the caller.
+ * The linear branch between the current node and the "thread" mark
+ * may also have a "shared" mark.  If present, the mapping to shared
+ * memory is computed at that point.
+ * Both marks are removed by this function.
+ * If "scale" is set, then the band that "node" points to is scaled
+ * by "sizes".
+ *
+ * Mark all outer band nodes as atomic to ensure each kernel is only
+ * scheduled once.
+ * If the domain elements that reach "node" live in more than one space,
+ * then group the domain elements into a single space, named kernelX,
+ * with X the kernel sequence number.
+ *
+ * Insert a guard node governing the kernel node to ensure that
+ * no kernels with zero blocks are launched.
+ *
+ * Insert a context node describing the block and thread
+ * identifiers inside the kernel mark.
+ * The context node needs to be inserted after the effective block size
+ * has been determined such that the bounds on the thread identifiers
+ * would reflect the effective block size.
+ * Insert a filter node inside the context node mapping the statement
+ * instances to block identifiers.  In particular, the block identifiers
+ * are equated to the partial schedule of band that was marked for mapping
+ * to blocks modulo the grid size.
+ * Insert a filter node inside the "thread" mark mapping the statement
+ * instances to thread identifiers.  In particular, the thread identifiers
+ * are equated to the partial schedule of band that was marked for mapping
+ * to threads modulo the block size.
+ *
+ * Compute array reference groups for all arrays, set the local
+ * array bounds based on the set of domain instances that reach
+ * the kernel node, check the total amount of shared memory used
+ * and compute all group tilings.
+ * The array reference groups are computed after the block filter
+ * has been inserted because it affects the mapping to shared or
+ * private memory.  This computation also requires the thread filter
+ * (in the ppcg_kernel object), but this thread filter should not
+ * have been added to the schedule tree yet since the computation
+ * requires the schedule of the band that needs to be mapped to
+ * threads before the privatization is applied.
+ *
+ * If any array reference group requires the band mapped to threads
+ * to be unrolled, then we perform the required unrolling.
+ *
+ * We save a copy of the schedule that may influence the mappings
+ * to shared or private memory in kernel->copy_schedule.
+ *
+ * Finally, we add synchronization and copy statements to the schedule tree,
+ * remove the "thread" mark and create representations for the local
+ * variables in the kernel.
+ *
+ * We keep a copy of the isl_id that points to the kernel to ensure
+ * that the kernel does not get destroyed if the schedule node
+ * is freed due to some error condition.
+ */
+__isl_give isl_schedule_node *gpu_create_kernel(struct gpu_gen *gen,
+	__isl_take isl_schedule_node *node, int scale,
+	__isl_keep isl_multi_val *sizes)
+{
+	struct ppcg_kernel *kernel;
+	isl_id *id;
+	isl_schedule_node *node_thread;
+	isl_union_map *host_schedule;
+	isl_union_pw_multi_aff *contraction;
+	isl_set *host_domain;
+	isl_union_set *domain, *expanded;
+	int single_statement;
+
+	node = gpu_tree_insert_shared_before_thread(node);
+	if (!node)
+		return NULL;
+
+	kernel = isl_calloc_type(gen->ctx, struct ppcg_kernel);
+	kernel = ppcg_kernel_create_local_arrays(kernel, gen->prog);
+	if (!kernel)
+		return isl_schedule_node_free(node);
+
+	domain = isl_schedule_node_get_domain(node);
+	single_statement = isl_union_set_n_set(domain) == 1;
+
+	kernel->ctx = gen->ctx;
+	kernel->prog = gen->prog;
+	kernel->options = gen->options;
+	kernel->context = extract_context(node, gen->prog);
+	kernel->core = isl_union_set_universe(isl_union_set_copy(domain));
+	contraction = isl_schedule_node_get_subtree_contraction(node);
+	kernel->contraction = isl_union_pw_multi_aff_copy(contraction);
+	expanded = isl_union_set_copy(domain);
+	expanded = isl_union_set_preimage_union_pw_multi_aff(expanded,
+						contraction);
+	kernel->expanded_domain = isl_union_set_copy(expanded);
+	kernel->arrays = accessed_by_domain(expanded, gen->prog);
+	kernel->n_grid = n_outer_coincidence(node);
+	node_thread = isl_schedule_node_copy(node);
+	node_thread = gpu_tree_move_down_to_thread(node_thread, kernel->core);
+	node_thread = isl_schedule_node_child(node_thread, 0);
+	kernel->n_block = n_outer_coincidence(node_thread);
+	isl_schedule_node_free(node_thread);
+	kernel->id = gen->kernel_id++;
+	read_grid_and_block_sizes(kernel, gen);
+
+	kernel->sync_writes = compute_sync_writes(kernel, node);
+
+	host_schedule = isl_schedule_node_get_prefix_schedule_union_map(node);
+	host_domain = isl_set_from_union_set(isl_union_map_range(
+								host_schedule));
+
+	node = atomic_ancestors(node);
+
+	id = isl_id_alloc(gen->ctx, "kernel", kernel);
+	id = isl_id_set_free_user(id, &ppcg_kernel_free_wrap);
+	node = isl_schedule_node_insert_mark(node, isl_id_copy(id));
+
+	if (!single_statement)
+		node = group_statements(node, kernel->id);
+
+	node = isl_schedule_node_child(node, 0);
+	node = split_band(node, kernel->n_grid);
+	kernel->block_ids = ppcg_scop_generate_names(gen->prog->scop,
+						kernel->n_grid, "b");
+	kernel->block_filter = set_schedule_modulo(node, kernel->block_ids,
+						kernel->grid_dim);
+	kernel->grid_size = extract_grid_size(kernel,
+						isl_union_set_copy(domain));
+	if (!kernel->options->wrap)
+		node = snap_band_to_sizes(node, kernel->grid_dim,
+						kernel->options);
+	if (scale)
+		node = scale_band(node, isl_multi_val_copy(sizes));
+	node = isl_schedule_node_parent(node);
+	if (!single_statement)
+		node = isl_schedule_node_parent(node);
+	node = insert_guard(node, kernel->context, kernel->grid_size,
+				gen->prog->scop);
+	node = gpu_tree_move_down_to_thread(node, kernel->core);
+	node = isl_schedule_node_child(node, 0);
+	node = split_band(node, kernel->n_block);
+	kernel->thread_ids = ppcg_scop_generate_names(gen->prog->scop,
+						kernel->n_block, "t");
+	kernel->thread_filter = set_schedule_modulo(node, kernel->thread_ids,
+						kernel->block_dim);
+	if (extract_block_size(kernel, domain) < 0)
+		node = isl_schedule_node_free(node);
+
+	node = gpu_tree_move_up_to_kernel(node);
+	node = isl_schedule_node_child(node, 0);
+	node = insert_context(kernel, node);
+	node = isl_schedule_node_child(node, 0);
+	node = isl_schedule_node_insert_filter(node,
+				    isl_union_set_copy(kernel->block_filter));
+
+	node = gpu_tree_move_up_to_kernel(node);
+
+	if (gpu_group_references(kernel, node) < 0)
+		node = isl_schedule_node_free(node);
+	localize_bounds(kernel, host_domain);
+	isl_set_free(host_domain);
+
+	check_shared_memory_bound(kernel);
+	mark_global_arrays(kernel);
+	compute_group_tilings(kernel);
+
+	node = gpu_tree_move_down_to_thread(node, kernel->core);
+	node = isl_schedule_node_child(node, 0);
+	if (!kernel->options->wrap)
+		node = snap_band_to_sizes(node, kernel->block_dim,
+						kernel->options);
+	node = isl_schedule_node_insert_filter(node,
+				    isl_union_set_copy(kernel->thread_filter));
+	if (kernel_requires_unroll(kernel)) {
+		node = isl_schedule_node_child(node, 0);
+		node = unroll(node);
+	}
+
+	node = gpu_tree_move_up_to_thread(node);
+	kernel->copy_schedule_dim = isl_schedule_node_get_schedule_depth(node);
+	kernel->copy_schedule =
+		isl_schedule_node_get_prefix_schedule_union_pw_multi_aff(node);
+	contraction = isl_union_pw_multi_aff_copy(kernel->contraction);
+	kernel->copy_schedule =
+		isl_union_pw_multi_aff_pullback_union_pw_multi_aff(
+					    kernel->copy_schedule, contraction);
+
+	node = gpu_tree_move_up_to_kernel(node);
+
+	node = add_sync(kernel, node);
+	node = add_copies(kernel, node);
+
+	node = gpu_tree_move_down_to_shared(node, kernel->core);
+	node = isl_schedule_node_delete(node);
+
+	node = gpu_tree_move_down_to_thread(node, kernel->core);
+	node = isl_schedule_node_delete(node);
+
+	node = gpu_tree_move_up_to_kernel(node);
+
+	if (create_kernel_vars(kernel) < 0)
+		node = isl_schedule_node_free(node);
+
+	if (!single_statement)
+		node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_parent(node);
+
+	isl_id_free(id);
+	return node;
+}
+
+/* Insert a zero-dimensional permutable band at "node".
+ */
+static __isl_give isl_schedule_node *insert_empty_permutable_band(
+	__isl_take isl_schedule_node *node)
+{
+	isl_space *space;
+	isl_schedule *schedule;
+	isl_union_set *domain;
+	isl_multi_union_pw_aff *mupa;
+
+	schedule = isl_schedule_node_get_schedule(node);
+	domain = isl_schedule_get_domain(schedule);
+	space = isl_union_set_get_space(domain);
+	isl_union_set_free(domain);
+	isl_schedule_free(schedule);
+
+	space = isl_space_set_from_params(space);
+	mupa = isl_multi_union_pw_aff_zero(space);
+	node = isl_schedule_node_insert_partial_schedule(node, mupa);
+	node = isl_schedule_node_band_set_permutable(node, 1);
+
+	return node;
+}
+
+/* See if hybrid tiling can be performed on "node" and its parent.
+ * If so, apply hybrid tiling and return the updated schedule tree.
+ * If not, return the original schedule tree.
+ * Return NULL on error.
+ *
+ * First check if "node", together with its parent, meets
+ * the basic requirements for hybrid tiling.
+ * If so, compute the relative dependence distances of "node"
+ * with respect to its parent and check if they are sufficiently bounded.
+ * If so, apply hybrid tiling using user specified tile sizes.
+ *
+ * The tile sizes are read before the dependence distance bounds are
+ * computed, because the user may have specified fewer dimensions
+ * than are available.  In this case, the remaining schedule dimensions
+ * are split off and the dependence distances should be computed
+ * after these dimensions have been split off.
+ */
+static __isl_give isl_schedule_node *try_hybrid_tile(struct gpu_gen *gen,
+	__isl_take isl_schedule_node *node)
+{
+	int tile_len;
+	int *tile_size;
+	isl_bool ok;
+	isl_schedule_node *orig = node;
+	ppcg_ht_bounds *bounds;
+
+	ok = ppcg_ht_parent_has_input_pattern(node);
+	if (ok < 0)
+		return isl_schedule_node_free(node);
+	if (!ok)
+		return orig;
+
+	tile_len = 1 + isl_schedule_node_band_n_member(node);
+	tile_size = read_tile_sizes(gen, &tile_len);
+	if (!tile_size)
+		return isl_schedule_node_free(node);
+
+	node = isl_schedule_node_copy(node);
+	node = split_band(node, tile_len - 1);
+	node = isl_schedule_node_parent(node);
+	bounds = ppcg_ht_compute_bounds(gen->prog->scop, node);
+	node = isl_schedule_node_child(node, 0);
+
+	ok = ppcg_ht_bounds_is_valid(bounds);
+	if (ok >= 0 && ok)
+		node = gpu_hybrid_tile(gen, node, bounds, tile_size);
+	else
+		ppcg_ht_bounds_free(bounds);
+	free(tile_size);
+
+	if (ok >= 0 && !ok) {
+		isl_schedule_node_free(node);
+		return orig;
+	}
+	isl_schedule_node_free(orig);
+	if (ok < 0)
+		return isl_schedule_node_free(node);
+	return node;
+}
+
+/* If "node" is the outermost permutable band that can be mapped to block and
+ * thread identifiers in its branch (or the root of a subtree with
+ * no such outer bands),
+ * then mark the band as such, attaching a ppcg_kernel to the mark.
+ *
+ * If hybrid tiling is allowed, then first try and apply it
+ * to "node" and its parent.
+ *
+ * If "node" is the root of a subtree without permutable bands,
+ * then insert a zero-dimensional permutable band such that
+ * we can assume that "node" always points to a band node.
+ * This includes the case where "node" already points to a band node,
+ * but one without any coincident dimension.  In this case,
+ * the extra node ensures that this original node does not get tiled.
+ *
+ * Tile "node" using user specified tile sizes, after splitting the band
+ * if the number of specified tile sizes is smaller than the dimension
+ * of the band.  Mark the point band of this tiling as the band that
+ * needs to be mapped to threads and instruct the AST generator to unroll
+ * the band if the "unroll_gpu_tile" option is set.
+ * Create a kernel representing the domain instances that reach "node" and
+ * insert a mark node pointing to the ppcg_kernel before the band node.
+ */
+static __isl_give isl_schedule_node *mark_outer_permutable(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	struct gpu_gen *gen = user;
+	int outer;
+	int scale;
+	int tile_len;
+	int *tile_size;
+	isl_id *id;
+	isl_multi_val *sizes;
+
+	outer = is_outer_tilable(node);
+	if (outer < 0)
+		return isl_schedule_node_free(node);
+	if (!outer)
+		return node;
+
+	if (gen->options->hybrid) {
+		isl_schedule_node *saved = isl_schedule_node_copy(node);
+		node = try_hybrid_tile(gen, node);
+		isl_schedule_node_free(saved);
+		if (node != saved)
+			return node;
+	}
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_band ||
+	    !isl_schedule_node_band_member_get_coincident(node, 0))
+		node = insert_empty_permutable_band(node);
+
+	tile_len = isl_schedule_node_band_n_member(node);
+	tile_size = read_tile_sizes(gen, &tile_len);
+	if (!tile_size)
+		return isl_schedule_node_free(node);
+	if (tile_len < isl_schedule_node_band_n_member(node))
+		node = isl_schedule_node_band_split(node, tile_len);
+	sizes = construct_band_tiles_sizes(node, tile_size);
+	node = tile_band(node, isl_multi_val_copy(sizes));
+	node = isl_schedule_node_child(node, 0);
+	if (gen->options->unroll_gpu_tile)
+		node = ppcg_set_schedule_node_type(node, isl_ast_loop_unroll);
+	id = isl_id_alloc(gen->ctx, "thread", NULL);
+	node = isl_schedule_node_insert_mark(node, id);
+	node = isl_schedule_node_parent(node);
+
+	scale = gen->options->scale_tile_loops;
+	node = gpu_create_kernel(gen, node, scale, sizes);
+	isl_multi_val_free(sizes);
+	free(tile_size);
+
+	return node;
+}
+
+/* Given a set or sequence node, return the union the filters of either all
+ * (if "only_initial" is not set) or the initial (if "only_initial" is set)
+ * direct subtrees that do not contain any suitably permutable bands
+ * (according to subtree_has_permutable_bands).
+ */
+static __isl_give isl_union_set *get_non_parallel_subtree_filters(
+	__isl_keep isl_schedule_node *node, int only_initial)
+{
+	isl_space *space;
+	isl_union_set *filter;
+	int i, n;
+
+	n = isl_schedule_node_n_children(node);
+	if (n < 0)
+		return NULL;
+
+	node = isl_schedule_node_copy(node);
+	node = isl_schedule_node_child(node, 0);
+	filter = isl_schedule_node_filter_get_filter(node);
+	node = isl_schedule_node_parent(node);
+	space = isl_union_set_get_space(filter);
+	isl_union_set_free(filter);
+	filter = isl_union_set_empty(space);
+
+	for (i = 0; i < n; ++i) {
+		int parallelism;
+
+		node = isl_schedule_node_child(node, i);
+		parallelism = subtree_has_permutable_bands(node);
+		if (parallelism < 0) {
+			filter = isl_union_set_free(filter);
+		} else if (!parallelism) {
+			isl_union_set *filter_i;
+			filter_i = isl_schedule_node_filter_get_filter(node);
+			filter = isl_union_set_union(filter, filter_i);
+		} else if (only_initial)
+			break;
+		node = isl_schedule_node_parent(node);
+	}
+
+	isl_schedule_node_free(node);
+
+	return filter;
+}
+
+/* Given a set or sequence node, return the union of the filters of
+ * the direct subtrees that do not contain any suitably permutable bands
+ * (according to subtree_has_permutable_bands).
+ */
+static __isl_give isl_union_set *get_all_non_parallel_subtree_filters(
+	__isl_keep isl_schedule_node *node)
+{
+	return get_non_parallel_subtree_filters(node, 0);
+}
+
+/* Given a set or sequence node, return the union of the filters of
+ * the initial direct subtrees that do not contain any suitably permutable
+ * bands (according to subtree_has_permutable_bands).
+ */
+static __isl_give isl_union_set *get_initial_non_parallel_subtree_filters(
+	__isl_keep isl_schedule_node *node)
+{
+	return get_non_parallel_subtree_filters(node, 1);
+}
+
+/* Mark all variables that are accessed by the statement instances in "domain"
+ * and that are local to "prog" as requiring a declaration in the host code.
+ * The statement instances in "domain" correspond to (a subset of)
+ * the active instances at "node".
+ * "node" is not modified by this function, except that NULL is returned
+ * in case of error.
+ */
+static __isl_give isl_schedule_node *declare_accessed_local_variables(
+	__isl_take isl_schedule_node *node, struct gpu_prog *prog,
+	__isl_keep isl_union_set *domain)
+{
+	isl_union_pw_multi_aff *contraction;
+	isl_union_set *arrays;
+	int i;
+
+	if (!ppcg_scop_any_hidden_declarations(prog->scop))
+		return node;
+	contraction = isl_schedule_node_get_subtree_contraction(node);
+	domain = isl_union_set_copy(domain);
+	domain = isl_union_set_preimage_union_pw_multi_aff(domain, contraction);
+	arrays = accessed_by_domain(domain, prog);
+
+	for (i = 0; i < prog->n_array; ++i) {
+		isl_space *space;
+		isl_set *set;
+		int empty;
+
+		if (!prog->array[i].local)
+			continue;
+		space = isl_set_get_space(prog->array[i].extent);
+		set = isl_union_set_extract_set(arrays, space);
+		empty = isl_set_plain_is_empty(set);
+		isl_set_free(set);
+		if (empty < 0)
+			goto error;
+		if (!empty)
+			prog->array[i].declare_local = 1;
+	}
+
+	isl_union_set_free(arrays);
+	return node;
+error:
+	isl_union_set_free(arrays);
+	return isl_schedule_node_free(node);
+}
+
+/* If "node" points to a set node, then separate its children
+ * into subtrees that have suitably permutable bands and
+ * those that do not.
+ * Adjust the schedule tree in order to execute the second group
+ * after the first group and return a pointer to the first group,
+ * assuming there are any such subtrees.
+ * If "node" points to a sequence node, then separate the initial
+ * children that do not have suitably permutable bands and
+ * return a pointer to the subsequence of children that do have such bands,
+ * assuming there are any such subtrees.
+ *
+ * In both cases, mark all local variables in "prog" that are accessed by
+ * the group without permutable bands as requiring a declaration on the host.
+ */
+static __isl_give isl_schedule_node *isolate_permutable_subtrees(
+	__isl_take isl_schedule_node *node, struct gpu_prog *prog)
+{
+	isl_union_set *filter;
+	enum isl_schedule_node_type type;
+
+	if (!node)
+		return NULL;
+	type = isl_schedule_node_get_type(node);
+	if (type == isl_schedule_node_set) {
+		filter = get_all_non_parallel_subtree_filters(node);
+		node = declare_accessed_local_variables(node, prog, filter);
+		node = isl_schedule_node_order_after(node, filter);
+	} else if (type == isl_schedule_node_sequence) {
+		filter = get_initial_non_parallel_subtree_filters(node);
+		node = declare_accessed_local_variables(node, prog, filter);
+		node = isl_schedule_node_order_before(node, filter);
+	}
+
+	return node;
+}
+
+/* Replace any reference to an array element in the range of "copy"
+ * by a reference to all array elements (defined by the extent of the array).
+ */
+static __isl_give isl_union_map *approximate_copy_out(
+	__isl_take isl_union_map *copy, struct gpu_prog *prog)
+{
+	int i;
+	isl_union_map *res;
+
+	res = isl_union_map_empty(isl_union_map_get_space(copy));
+
+	for (i = 0; i < prog->n_array; ++i) {
+		isl_space *space;
+		isl_set *set;
+		isl_union_map *copy_i;
+		isl_union_set *extent, *domain;
+
+		space = isl_space_copy(prog->array[i].space);
+		extent = isl_union_set_from_set(isl_set_universe(space));
+		copy_i = isl_union_map_copy(copy);
+		copy_i = isl_union_map_intersect_range(copy_i, extent);
+		set = isl_set_copy(prog->array[i].extent);
+		extent = isl_union_set_from_set(set);
+		domain = isl_union_map_domain(copy_i);
+		copy_i = isl_union_map_from_domain_and_range(domain, extent);
+		res = isl_union_map_union(res, copy_i);
+	}
+
+	isl_union_map_free(copy);
+
+	return res;
+}
+
+/* Insert "kernel" marks that point to a ppcg_kernel structure
+ * in front of all outermost tilable band that (by construction)
+ * have at least one parallel loop.
+ */
+static __isl_give isl_schedule_node *mark_kernels(struct gpu_gen *gen,
+	__isl_take isl_schedule_node *node)
+{
+	return isl_schedule_node_map_descendant_bottom_up(node,
+						&mark_outer_permutable, gen);
+}
+
+/* Construct schedule constraints from the dependences in prog->scop and
+ * the array order dependences in prog->array_order.
+ *
+ * If live range reordering is allowed, then we need to make sure
+ * that live ranges on arrays are not run in parallel since doing
+ * so would require array expansion.  We therefore add the array
+ * order dependences to the coincidence dependences.  Non-zero array
+ * order dependences will then prevent a schedule dimension from being
+ * considered parallel.
+ * Live ranges derived from scalars are allowed to be run in parallel
+ * since we force the scalars to be mapped to private memory in
+ * check_scalar_live_ranges.
+ * If live range reordering is allowed, then the false dependences
+ * are not added to the validity constraints as that would prevent
+ * reordering.  Instead, the external false dependences that enforce that reads
+ * from potentially live-in data precede any later write and
+ * that writes of potentially live-out data follow any other earlier write
+ * are added to the validity and the coincidence constraints.
+ * The false dependences are still added to the proximity constraints
+ * for consistency with the case where live range reordering is not allowed.
+ * The coincidence constraints then consist of flow dependences,
+ * external false dependences and array order dependences.
+ * The independences can be filtered out from the first two sets.
+ * They have already been filtered out from the array order dependences
+ * on a per array basis in collect_order_dependences.
+ * There is no need for a per array handling of the other two sets
+ * as there should be no flow or external false dependence on local
+ * variables that can be filtered out.
+ */
+static __isl_give isl_schedule_constraints *construct_schedule_constraints(
+	struct gpu_prog *prog)
+{
+	isl_union_set *domain;
+	isl_union_map *dep_raw, *dep;
+	isl_union_map *validity, *proximity, *coincidence;
+	isl_schedule_constraints *sc;
+
+	domain = isl_union_set_copy(prog->scop->domain);
+	sc = isl_schedule_constraints_on_domain(domain);
+	sc = isl_schedule_constraints_set_context(sc,
+				isl_set_copy(prog->scop->context));
+	if (prog->scop->options->live_range_reordering) {
+		sc = isl_schedule_constraints_set_conditional_validity(sc,
+			isl_union_map_copy(prog->scop->tagged_dep_flow),
+			isl_union_map_copy(prog->scop->tagged_dep_order));
+		proximity = isl_union_map_copy(prog->scop->dep_flow);
+		validity = isl_union_map_copy(proximity);
+		validity = isl_union_map_union(validity,
+			    isl_union_map_copy(prog->scop->dep_forced));
+		proximity = isl_union_map_union(proximity,
+			    isl_union_map_copy(prog->scop->dep_false));
+		coincidence = isl_union_map_copy(validity);
+		coincidence = isl_union_map_subtract(coincidence,
+			isl_union_map_copy(prog->scop->independence));
+		coincidence = isl_union_map_union(coincidence,
+				isl_union_map_copy(prog->array_order));
+	} else {
+		dep_raw = isl_union_map_copy(prog->scop->dep_flow);
+		dep = isl_union_map_copy(prog->scop->dep_false);
+		dep = isl_union_map_union(dep, dep_raw);
+		dep = isl_union_map_coalesce(dep);
+		proximity = isl_union_map_copy(dep);
+		coincidence = isl_union_map_copy(dep);
+		validity = dep;
+	}
+	sc = isl_schedule_constraints_set_validity(sc, validity);
+	sc = isl_schedule_constraints_set_coincidence(sc, coincidence);
+	sc = isl_schedule_constraints_set_proximity(sc, proximity);
+
+	if (prog->scop->options->debug->dump_schedule_constraints)
+		isl_schedule_constraints_dump(sc);
+	return sc;
+}
+
+/* Compute an appropriate schedule based on the accesses in
+ * gen->read and gen->write.
+ *
+ * We derive schedule constraints from the dependences in gen->prog->scop
+ * and then use isl to compute a schedule that has a parallel loop
+ * in each tilable band.
+ * During the schedule construction, some statement instances
+ * may be grouped first based on the input schedule.
+ */
+static __isl_give isl_schedule *compute_schedule(struct gpu_gen *gen)
+{
+	isl_schedule_constraints *sc;
+	isl_schedule *schedule;
+
+	sc = construct_schedule_constraints(gen->prog);
+	schedule = gen->prog->scop->schedule;
+	schedule = ppcg_compute_schedule(sc, schedule, gen->options);
+
+	return schedule;
+}
+
+/* If the band node "node" has exactly one member then mark it permutable.
+ */
+static __isl_give isl_schedule_node *band_set_permutable(
+	__isl_take isl_schedule_node *node,
+	__isl_keep isl_schedule_constraints *sc)
+{
+	if (isl_schedule_node_band_n_member(node) == 1)
+		node = isl_schedule_node_band_set_permutable(node, 1);
+
+	return node;
+}
+
+/* Return the coincidence constraints between pairs of instances
+ * that are scheduled together by the ancestors of "node".
+ * That is, select those coincidence constraints that relate
+ * pairs of instances that have the same value for the prefix schedule.
+ * If the schedule depth is zero, then the prefix schedule does not
+ * contain any information, so we intersect domain and range
+ * of the schedule constraints with the reaching domain elements instead.
+ */
+static __isl_give isl_union_map *get_local_coincidence(
+	__isl_keep isl_schedule_node *node,
+	__isl_keep isl_schedule_constraints *sc)
+{
+	isl_union_map *coincidence;
+	isl_multi_union_pw_aff *prefix;
+	isl_union_pw_multi_aff *contraction;
+
+	coincidence = isl_schedule_constraints_get_coincidence(sc);
+	contraction = isl_schedule_node_get_subtree_contraction(node);
+	if (isl_schedule_node_get_schedule_depth(node) == 0) {
+		isl_union_set *domain;
+
+		domain = isl_schedule_node_get_domain(node);
+		domain = isl_union_set_preimage_union_pw_multi_aff(domain,
+						    contraction);
+		coincidence = isl_union_map_intersect_domain(coincidence,
+						    isl_union_set_copy(domain));
+		coincidence = isl_union_map_intersect_range(coincidence,
+						    domain);
+		return coincidence;
+	}
+
+	prefix = isl_schedule_node_get_prefix_schedule_multi_union_pw_aff(node);
+	prefix = isl_multi_union_pw_aff_pullback_union_pw_multi_aff(prefix,
+								contraction);
+	return isl_union_map_eq_at_multi_union_pw_aff(coincidence, prefix);
+}
+
+/* For each member in the band node "node", determine whether
+ * it is coincident with respect to the outer nodes and mark
+ * it accordingly.
+ *
+ * That is, for each coincidence constraint between pairs
+ * of instances that are scheduled together by the outer nodes,
+ * check that domain and range are assigned the same value
+ * by the band member.  This test is performed by checking
+ * that imposing the same value for the band member does not
+ * remove any elements from the set of coincidence constraints.
+ */
+static __isl_give isl_schedule_node *band_set_coincident(
+	__isl_take isl_schedule_node *node,
+	__isl_keep isl_schedule_constraints *sc)
+{
+	isl_union_map *coincidence;
+	isl_union_pw_multi_aff *contraction;
+	isl_multi_union_pw_aff *partial;
+	int i, n;
+
+	coincidence = get_local_coincidence(node, sc);
+
+	partial = isl_schedule_node_band_get_partial_schedule(node);
+	contraction = isl_schedule_node_get_subtree_contraction(node);
+	partial = isl_multi_union_pw_aff_pullback_union_pw_multi_aff(partial,
+								contraction);
+	n = isl_schedule_node_band_n_member(node);
+	for (i = 0; i < n; ++i) {
+		isl_union_map *coincidence_i;
+		isl_union_pw_aff *upa;
+		isl_multi_union_pw_aff *partial_i;
+		int subset;
+
+		upa = isl_multi_union_pw_aff_get_union_pw_aff(partial, i);
+		partial_i = isl_multi_union_pw_aff_from_union_pw_aff(upa);
+		coincidence_i = isl_union_map_copy(coincidence);
+		coincidence_i = isl_union_map_eq_at_multi_union_pw_aff(
+						    coincidence_i, partial_i);
+		subset = isl_union_map_is_subset(coincidence, coincidence_i);
+		isl_union_map_free(coincidence_i);
+
+		if (subset < 0)
+			break;
+		node = isl_schedule_node_band_member_set_coincident(node, i,
+								    subset);
+	}
+	if (i < n)
+		node = isl_schedule_node_free(node);
+	isl_multi_union_pw_aff_free(partial);
+	isl_union_map_free(coincidence);
+
+	return node;
+}
+
+/* If "node" is a band, then set its properties.
+ *
+ * In particular, if the band has exactly one member, then mark it permutable.
+ * Mark the band member coincident based on the coincidence constraints
+ * of "sc".
+ */
+static __isl_give isl_schedule_node *set_band_properties(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	isl_schedule_constraints *sc = user;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_band)
+		return node;
+	if (isl_schedule_node_band_n_member(node) == 0)
+		return node;
+
+	node = band_set_permutable(node, sc);
+	node = band_set_coincident(node, sc);
+
+	return node;
+}
+
+/* Return the original schedule with all bands marked permutable and
+ * all band members marked coincident based on the coincidence constraints.
+ * The bands are explicitly marked permutable so that they will be considered
+ * by mark_outer_permutable.
+ */
+static __isl_give isl_schedule *determine_properties_original_schedule(
+	struct gpu_gen *gen)
+{
+	isl_schedule *schedule;
+	isl_schedule_constraints *sc;
+
+	schedule = isl_schedule_copy(gen->prog->scop->schedule);
+	sc = construct_schedule_constraints(gen->prog);
+	schedule = isl_schedule_map_schedule_node_bottom_up(schedule,
+						    &set_band_properties, sc);
+	isl_schedule_constraints_free(sc);
+
+	return schedule;
+}
+
+/* Compute a schedule or determine the properties of the original schedule
+ * depending on the value of the "reschedule" option.
+ */
+static __isl_give isl_schedule *compute_or_set_properties(void *user)
+{
+	struct gpu_gen *gen = user;
+
+	if (gen->options->reschedule)
+		return compute_schedule(gen);
+	else
+		return determine_properties_original_schedule(gen);
+}
+
+/* Obtain a schedule for the scop, by reading it from
+ * a file, by computing one or by determining the properties
+ * of the original schedule.
+ */
+__isl_give isl_schedule *get_schedule(struct gpu_gen *gen)
+{
+	return ppcg_get_schedule(gen->ctx, gen->options,
+				&compute_or_set_properties, gen);
+}
+
+/* Construct the string "<a>_<b>".
+ */
+static char *concat(isl_ctx *ctx, const char *a, const char *b)
+{
+	isl_printer *p;
+	char *s;
+
+	p = isl_printer_to_str(ctx);
+	p = isl_printer_print_str(p, a);
+	p = isl_printer_print_str(p, "_");
+	p = isl_printer_print_str(p, b);
+	s = isl_printer_get_str(p);
+	isl_printer_free(p);
+
+	return s;
+}
+
+/* For each array in "prog" of which an element appears in "accessed" and
+ * that is not a read only scalar, create a zero-dimensional universe set
+ * of which the tuple id has name "<prefix>_<name of array>" and a user
+ * pointer pointing to the array (gpu_array_info).
+ *
+ * If the array is local to "prog", then make sure it will be declared
+ * in the host code.
+ *
+ * Return the list of these universe sets.
+ */
+static __isl_give isl_union_set_list *create_copy_filters(struct gpu_prog *prog,
+	const char *prefix, __isl_take isl_union_set *accessed)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_union_set_list *filters;
+
+	ctx = prog->ctx;
+	filters = isl_union_set_list_alloc(ctx, 0);
+	for (i = 0; i < prog->n_array; ++i) {
+		struct gpu_array_info *array = &prog->array[i];
+		isl_space *space;
+		isl_set *accessed_i;
+		int empty;
+		char *name;
+		isl_id *id;
+		isl_union_set *uset;
+
+		if (gpu_array_is_read_only_scalar(array))
+			continue;
+
+		space = isl_space_copy(array->space);
+		accessed_i = isl_union_set_extract_set(accessed, space);
+		empty = isl_set_plain_is_empty(accessed_i);
+		isl_set_free(accessed_i);
+		if (empty < 0) {
+			filters = isl_union_set_list_free(filters);
+			break;
+		}
+		if (empty)
+			continue;
+
+		array->global = 1;
+		if (array->local)
+			array->declare_local = 1;
+
+		name = concat(ctx, prefix, array->name);
+		id = name ? isl_id_alloc(ctx, name, array) : NULL;
+		free(name);
+		space = isl_space_set_alloc(ctx, 0, 0);
+		space = isl_space_set_tuple_id(space, isl_dim_set, id);
+		uset = isl_union_set_from_set(isl_set_universe(space));
+
+		filters = isl_union_set_list_add(filters, uset);
+	}
+	isl_union_set_free(accessed);
+
+	return filters;
+}
+
+/* Make sure that code for the statements in "filters" that
+ * copy arrays to or from the device is only generated when
+ * the size of the corresponding array is positive.
+ * That is, add a set node underneath "graft" with "filters" as children
+ * and for each child add a guard that the selects the parameter
+ * values for which the corresponding array has a positive size.
+ * The array is available in the user pointer of the statement identifier.
+ * "depth" is the schedule depth of the position where "graft"
+ * will be added.
+ */
+static __isl_give isl_schedule_node *insert_positive_size_guards(
+	__isl_take isl_schedule_node *graft,
+	__isl_take isl_union_set_list *filters, int depth)
+{
+	int i, n;
+
+	graft = isl_schedule_node_child(graft, 0);
+	graft = isl_schedule_node_insert_set(graft, filters);
+	n = isl_schedule_node_n_children(graft);
+	for (i = 0; i < n; ++i) {
+		isl_union_set *filter;
+		isl_set *domain, *guard;
+		isl_id *id;
+		struct gpu_array_info *array;
+
+		graft = isl_schedule_node_child(graft, i);
+		filter = isl_schedule_node_filter_get_filter(graft);
+		domain = isl_set_from_union_set(filter);
+		id = isl_set_get_tuple_id(domain);
+		array = isl_id_get_user(id);
+		isl_id_free(id);
+		isl_set_free(domain);
+		guard = gpu_array_positive_size_guard(array);
+		guard = isl_set_from_params(guard);
+		guard = isl_set_add_dims(guard, isl_dim_set, depth);
+		graft = isl_schedule_node_child(graft, 0);
+		graft = isl_schedule_node_insert_guard(graft, guard);
+		graft = isl_schedule_node_parent(graft);
+		graft = isl_schedule_node_parent(graft);
+	}
+	graft = isl_schedule_node_parent(graft);
+
+	return graft;
+}
+
+/* Create a graft for copying arrays to or from the device,
+ * whenever the size of the array is strictly positive.
+ * Each statement is called "<prefix>_<name of array>" and
+ * the identifier has a user pointer pointing to the array.
+ * The graft will be added at the position specified by "node".
+ * "copy" contains the array elements that need to be copied.
+ * Only arrays of which some elements need to be copied
+ * will have a corresponding statement in the graph.
+ * Note though that each such statement will copy the entire array.
+ */
+static __isl_give isl_schedule_node *create_copy_device(struct gpu_prog *prog,
+	__isl_keep isl_schedule_node *node, const char *prefix,
+	__isl_take isl_union_set *copy)
+{
+	int depth;
+	isl_ctx *ctx;
+	isl_space *space;
+	isl_union_set *all, *domain;
+	isl_union_set_list *filters;
+	isl_union_map *extension;
+	isl_schedule_node *graft;
+
+	ctx = prog->ctx;
+	depth = isl_schedule_node_get_schedule_depth(node);
+	filters = create_copy_filters(prog, prefix, copy);
+	all = isl_union_set_list_union(isl_union_set_list_copy(filters));
+
+	space = depth < 0 ? NULL : isl_space_set_alloc(ctx, 0, depth);
+	domain = isl_union_set_from_set(isl_set_universe(space));
+	extension = isl_union_map_from_domain_and_range(domain, all);
+	graft = isl_schedule_node_from_extension(extension);
+
+	if (!filters)
+		return isl_schedule_node_free(graft);
+	if (isl_union_set_list_n_union_set(filters) == 0) {
+		isl_union_set_list_free(filters);
+		return graft;
+	}
+
+	return insert_positive_size_guards(graft, filters, depth);
+}
+
+/* Return (the universe spaces of) the arrays that are declared
+ * inside the scop corresponding to "prog" and for which all
+ * potential writes inside the scop form a subset of "domain".
+ */
+static __isl_give isl_union_set *extract_local_accesses(struct gpu_prog *prog,
+	__isl_keep isl_union_set *domain)
+{
+	int i;
+	isl_union_set *local;
+
+	local = isl_union_set_empty(isl_union_set_get_space(domain));
+
+	for (i = 0; i < prog->n_array; ++i) {
+		isl_set *set;
+		isl_union_map *to_outer;
+		isl_union_map *may_write;
+		isl_union_set *write_domain;
+		isl_union_set *fields;
+		int subset;
+
+		if (!prog->array[i].local)
+			continue;
+
+		set = isl_set_universe(isl_space_copy(prog->array[i].space));
+		to_outer = isl_union_map_copy(prog->to_outer);
+		to_outer = isl_union_map_intersect_range(to_outer,
+				    isl_union_set_from_set(isl_set_copy(set)));
+		fields = isl_union_map_domain(to_outer);
+		may_write = isl_union_map_copy(prog->may_write);
+		may_write = isl_union_map_intersect_range(may_write, fields);
+		write_domain = isl_union_map_domain(may_write);
+		subset = isl_union_set_is_subset(write_domain, domain);
+		isl_union_set_free(write_domain);
+
+		if (subset < 0) {
+			isl_set_free(set);
+			return isl_union_set_free(local);
+		} else if (subset) {
+			local = isl_union_set_add_set(local, set);
+		} else {
+			isl_set_free(set);
+		}
+	}
+
+	return local;
+}
+
+/* Internal data structure for node_may_persist.
+ *
+ * "tagger" maps tagged iteration domains to the corresponding untagged
+ *	iteration domain.
+ *
+ * "may_persist_flow" is the set of all tagged dataflow dependences
+ * with those dependences removed that either precede or follow
+ * the kernel launch in a sequence.
+ * "inner_band_flow" is the set of all tagged dataflow dependences
+ * that are local to a given iteration of the outer band nodes
+ * with respect to the current node.
+ * "local_flow" is equal to "inner_band_flow", except that the domain
+ * and the range have been intersected with intermediate filters
+ * on children of sets or sequences.
+ */
+struct ppcg_may_persist_data {
+	isl_union_pw_multi_aff *tagger;
+
+	isl_union_map *local_flow;
+	isl_union_map *inner_band_flow;
+	isl_union_map *may_persist_flow;
+};
+
+/* Update the information in "data" based on the band ancestor "node".
+ *
+ * In particular, we restrict the dependences in data->local_flow
+ * to those dependence where the source and the sink occur in
+ * the same iteration of the given band node.
+ * We also update data->inner_band_flow to the new value of
+ * data->local_flow.
+ */
+static int update_may_persist_at_band(__isl_keep isl_schedule_node *node,
+	struct ppcg_may_persist_data *data)
+{
+	isl_multi_union_pw_aff *partial;
+	isl_union_pw_multi_aff *contraction;
+	isl_union_map *flow;
+
+	if (isl_schedule_node_band_n_member(node) == 0)
+		return 0;
+
+	partial = isl_schedule_node_band_get_partial_schedule(node);
+	contraction = isl_schedule_node_get_subtree_contraction(node);
+	partial = isl_multi_union_pw_aff_pullback_union_pw_multi_aff(partial,
+								contraction);
+	partial = isl_multi_union_pw_aff_pullback_union_pw_multi_aff(partial,
+				isl_union_pw_multi_aff_copy(data->tagger));
+
+	flow = data->local_flow;
+	flow = isl_union_map_eq_at_multi_union_pw_aff(flow, partial);
+	data->local_flow = flow;
+
+	isl_union_map_free(data->inner_band_flow);
+	data->inner_band_flow = isl_union_map_copy(data->local_flow);
+
+	return 0;
+}
+
+/* Given a set of local reaching domain elements "domain",
+ * expand them to the corresponding leaf domain elements using "contraction"
+ * and insert the array references tags using data->tagger.
+ */
+static __isl_give isl_union_set *expand_and_tag(
+	__isl_take isl_union_set *domain,
+	__isl_take isl_union_pw_multi_aff *contraction,
+	struct ppcg_may_persist_data *data)
+{
+	domain = isl_union_set_preimage_union_pw_multi_aff(domain,
+			    contraction);
+	domain = isl_union_set_preimage_union_pw_multi_aff(domain,
+			    isl_union_pw_multi_aff_copy(data->tagger));
+	return domain;
+}
+
+/* Given a filter node that is the child of a set or sequence node,
+ * restrict data->local_flow to refer only to those elements
+ * in the filter of the node.
+ * "contraction" maps the leaf domain elements of the schedule tree
+ * to the corresponding domain elements at (the parent of) "node".
+ */
+static int filter_flow(__isl_keep isl_schedule_node *node,
+	struct ppcg_may_persist_data *data,
+	__isl_take isl_union_pw_multi_aff *contraction)
+{
+	isl_union_set *filter;
+	isl_union_map *flow;
+
+	flow = data->local_flow;
+	filter = isl_schedule_node_filter_get_filter(node);
+	filter = expand_and_tag(filter, contraction, data);
+	flow = isl_union_map_intersect_domain(flow, isl_union_set_copy(filter));
+	flow = isl_union_map_intersect_range(flow, filter);
+	data->local_flow = flow;
+
+	return 0;
+}
+
+/* Given a filter node "node", collect the filters on all preceding siblings
+ * (which are also filter nodes), add them to "filters" and return the result.
+ */
+static __isl_give isl_union_set *add_previous_filters(
+	__isl_take isl_union_set *filters, __isl_keep isl_schedule_node *node)
+{
+	isl_schedule_node *sibling;
+
+	sibling = isl_schedule_node_copy(node);
+	while (sibling && isl_schedule_node_has_previous_sibling(sibling)) {
+		isl_union_set *filter;
+
+		sibling = isl_schedule_node_previous_sibling(sibling);
+		filter = isl_schedule_node_filter_get_filter(sibling);
+		filters = isl_union_set_union(filters, filter);
+	}
+	isl_schedule_node_free(sibling);
+	if (!sibling)
+		return isl_union_set_free(filters);
+
+	return filters;
+}
+
+/* Given a filter node "node", collect the filters on all following siblings
+ * (which are also filter nodes), add them to "filters" and return the result.
+ */
+static __isl_give isl_union_set *add_next_filters(
+	__isl_take isl_union_set *filters, __isl_keep isl_schedule_node *node)
+{
+	isl_schedule_node *sibling;
+
+	sibling = isl_schedule_node_copy(node);
+	while (sibling && isl_schedule_node_has_next_sibling(sibling)) {
+		isl_union_set *filter;
+
+		sibling = isl_schedule_node_next_sibling(sibling);
+		filter = isl_schedule_node_filter_get_filter(sibling);
+		filters = isl_union_set_union(filters, filter);
+	}
+	isl_schedule_node_free(sibling);
+	if (!sibling)
+		return isl_union_set_free(filters);
+
+	return filters;
+}
+
+/* Remove those flow dependences from data->may_persist_flow
+ * that flow between elements of "domain" within the same iteration
+ * of all outer band nodes.
+ * "contraction" maps the leaf domain elements of the schedule tree
+ * to the corresponding elements "domain".
+ */
+static void remove_external_flow(struct ppcg_may_persist_data *data,
+	__isl_take isl_union_set *domain,
+	__isl_keep isl_union_pw_multi_aff *contraction)
+{
+	isl_union_map *flow;
+
+	contraction = isl_union_pw_multi_aff_copy(contraction);
+	domain = expand_and_tag(domain, contraction, data);
+	flow = isl_union_map_copy(data->local_flow);
+	flow = isl_union_map_intersect_domain(flow, isl_union_set_copy(domain));
+	flow = isl_union_map_intersect_range(flow, domain);
+
+	data->may_persist_flow = isl_union_map_subtract(data->may_persist_flow,
+							flow);
+}
+
+/* Update the information in "data" based on the filter ancestor "node".
+ * We only need to modify anything if the filter is the child
+ * of a set or sequence node.
+ *
+ * In the case of a sequence, we remove the dependences between
+ * statement instances that are both executed either before or
+ * after the subtree that will be mapped to a kernel, within
+ * the same iteration of outer bands.
+ *
+ * In both cases, we restrict data->local_flow to the current child.
+ */
+static int update_may_persist_at_filter(__isl_keep isl_schedule_node *node,
+	struct ppcg_may_persist_data *data)
+{
+	enum isl_schedule_node_type type;
+	isl_schedule_node *parent;
+	isl_space *space;
+	isl_union_pw_multi_aff *contraction;
+	isl_union_set *before, *after, *filter;
+
+	type = isl_schedule_node_get_parent_type(node);
+	if (type != isl_schedule_node_sequence && type != isl_schedule_node_set)
+		return 0;
+
+	parent = isl_schedule_node_copy(node);
+	parent = isl_schedule_node_parent(parent);
+	contraction = isl_schedule_node_get_subtree_contraction(parent);
+	isl_schedule_node_free(parent);
+
+	if (type == isl_schedule_node_set)
+		return filter_flow(node, data, contraction);
+
+	filter = isl_schedule_node_filter_get_filter(node);
+	space = isl_union_set_get_space(filter);
+	isl_union_set_free(filter);
+	before = isl_union_set_empty(space);
+	after = isl_union_set_copy(before);
+	before = add_previous_filters(before, node);
+	after = add_next_filters(after, node);
+
+	remove_external_flow(data, before, contraction);
+	remove_external_flow(data, after, contraction);
+
+	return filter_flow(node, data, contraction);
+}
+
+/* Update the information in "data" based on the ancestor "node".
+ */
+static isl_stat update_may_persist_at(__isl_keep isl_schedule_node *node,
+	void *user)
+{
+	struct ppcg_may_persist_data *data = user;
+
+	switch (isl_schedule_node_get_type(node)) {
+	case isl_schedule_node_error:
+		return isl_stat_error;
+	case isl_schedule_node_context:
+	case isl_schedule_node_domain:
+	case isl_schedule_node_expansion:
+	case isl_schedule_node_extension:
+	case isl_schedule_node_guard:
+	case isl_schedule_node_leaf:
+	case isl_schedule_node_mark:
+	case isl_schedule_node_sequence:
+	case isl_schedule_node_set:
+		break;
+	case isl_schedule_node_band:
+		if (update_may_persist_at_band(node, data) < 0)
+			return isl_stat_error;
+		break;
+	case isl_schedule_node_filter:
+		if (update_may_persist_at_filter(node, data) < 0)
+			return isl_stat_error;
+		break;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Determine the set of array elements that may need to be perserved
+ * by a kernel constructed from the subtree at "node".
+ * This includes the set of array elements that may need to be preserved
+ * by the entire scop (prog->may_persist) and the elements for which
+ * there is a potential flow dependence that may cross a kernel launch.
+ *
+ * To determine the second set, we start from all flow dependences.
+ * From this set of dependences, we remove those that cannot possibly
+ * require data to be preserved by a kernel launch.
+ * In particular, we consider the following sets of dependences.
+ * - dependences of which the write occurs inside the kernel.
+ *   If the data is needed outside the kernel, then it will
+ *   be copied out immediately after the kernel launch, so there
+ *   is no need for any special care.
+ * - dependences of which the read occurs inside the kernel and the
+ *   corresponding write occurs inside the same iteration of the
+ *   outer band nodes.  This means that the data is needed in
+ *   the first kernel launch after the write, which is already
+ *   taken care of by the standard copy-in.  That is, the data
+ *   do not need to be preserved by any intermediate call to
+ *   the same kernel.
+ * - dependences of which the write and the read either both occur
+ *   before the kernel launch or both occur after the kernel launch,
+ *   within the same iteration of the outer band nodes with respect
+ *   to the sequence that determines the ordering of the dependence
+ *   and the kernel launch.  Such flow dependences cannot cross
+ *   any kernel launch.
+ *
+ * For the remaining (tagged) dependences, we take the domain
+ * (i.e., the tagged writes) and apply the tagged access relation
+ * to obtain the accessed data elements.
+ * These are then combined with the elements that may need to be
+ * preserved by the entire scop.
+ */
+static __isl_give isl_union_set *node_may_persist(
+	__isl_keep isl_schedule_node *node, struct gpu_prog *prog)
+{
+	struct ppcg_may_persist_data data;
+	isl_union_pw_multi_aff *contraction;
+	isl_union_set *domain;
+	isl_union_set *persist;
+	isl_union_map *flow, *local_flow;
+
+	data.tagger = prog->scop->tagger;
+
+	flow = isl_union_map_copy(prog->scop->tagged_dep_flow);
+	data.local_flow = isl_union_map_copy(flow);
+	data.inner_band_flow = isl_union_map_copy(flow);
+	data.may_persist_flow = flow;
+	if (isl_schedule_node_foreach_ancestor_top_down(node,
+					&update_may_persist_at, &data) < 0)
+		data.may_persist_flow =
+				    isl_union_map_free(data.may_persist_flow);
+	flow = data.may_persist_flow;
+	isl_union_map_free(data.local_flow);
+
+	domain = isl_schedule_node_get_domain(node);
+	contraction = isl_schedule_node_get_subtree_contraction(node);
+	domain = isl_union_set_preimage_union_pw_multi_aff(domain,
+				    contraction);
+	domain = isl_union_set_preimage_union_pw_multi_aff(domain,
+				    isl_union_pw_multi_aff_copy(data.tagger));
+	flow = isl_union_map_subtract_domain(flow, isl_union_set_copy(domain));
+	local_flow = data.inner_band_flow;
+	local_flow = isl_union_map_intersect_range(local_flow, domain);
+	flow = isl_union_map_subtract(flow, local_flow);
+
+	persist = isl_union_map_domain(flow);
+	persist = isl_union_set_apply(persist,
+			isl_union_map_copy(prog->scop->tagged_may_writes));
+	persist = isl_union_set_union(persist,
+			isl_union_set_copy(prog->may_persist));
+
+	return persist;
+}
+
+/* Add nodes for copying outer arrays in and out of the device
+ * before and after the subtree "node", which contains one or more kernels.
+ * "domain" contains the original statement instances, i.e.,
+ * those that correspond to the domains of the access relations in "prog".
+ * In particular, the domain has not been contracted in any way.
+ * "prefix" contains the prefix schedule at that point, in terms
+ * of the same original statement instances.
+ *
+ * We first compute the sets of outer array elements that need
+ * to be copied in and out and then graft in the nodes for
+ * performing this copying.
+ *
+ * In particular, for each array that is possibly written anywhere in
+ * the subtree "node" and that may be used after "node"
+ * or that may be visible outside the corresponding scop,
+ * we copy out its entire extent.
+ *
+ * Any array elements that is read without first being written inside
+ * the subtree "node" needs to be copied in.
+ * Furthermore, if there are any array elements that
+ * are copied out, but that may not be written inside "node, then
+ * they also need to be copied in to ensure that the value after execution
+ * is the same as the value before execution, at least for those array
+ * elements that may have their values preserved by the scop or that
+ * may be written before "node" and read after "node".
+ * In case the array elements are structures, we need to take into
+ * account that all members of the structures need to be written
+ * by "node" before we can avoid copying the data structure in.
+ *
+ * Note that the may_write relation is intersected with the domain,
+ * which has been intersected with the context.
+ * This helps in those cases where the arrays are declared with a fixed size,
+ * while the accesses are parametric and the context assigns a fixed value
+ * to the parameters.
+ *
+ * If an element from a local array is read without first being written,
+ * then there is no point in copying it in since it cannot have been
+ * written prior to the scop.  Warn about the uninitialized read instead.
+ */
+static __isl_give isl_schedule_node *add_to_from_device(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *domain,
+	__isl_take isl_union_map *prefix, struct gpu_prog *prog)
+{
+	isl_union_set *local;
+	isl_union_set *may_persist;
+	isl_union_map *may_write, *must_write, *copy_out, *not_written;
+	isl_union_map *read, *copy_in;
+	isl_union_map *tagged;
+	isl_union_map *local_uninitialized;
+	isl_schedule_node *graft;
+
+	tagged = isl_union_map_copy(prog->scop->tagged_reads);
+	tagged = isl_union_map_union(tagged,
+			    isl_union_map_copy(prog->scop->tagged_may_writes));
+
+	may_write = isl_union_map_copy(prog->may_write);
+	may_write = isl_union_map_intersect_domain(may_write,
+					isl_union_set_copy(domain));
+	may_write = remove_local_accesses(prog,
+					isl_union_map_copy(tagged), may_write,
+					isl_union_map_copy(prefix), 0);
+	may_write = isl_union_map_apply_range(may_write,
+					isl_union_map_copy(prog->to_outer));
+	may_write = isl_union_map_apply_domain(may_write,
+					isl_union_map_copy(prefix));
+	may_write = approximate_copy_out(may_write, prog);
+	copy_out = isl_union_map_copy(may_write);
+	may_write = isl_union_map_apply_range(may_write,
+					isl_union_map_copy(prog->to_inner));
+	must_write = isl_union_map_copy(prog->must_write);
+	must_write = isl_union_map_apply_domain(must_write,
+					isl_union_map_copy(prefix));
+	may_persist = node_may_persist(node, prog);
+	may_write = isl_union_map_intersect_range(may_write, may_persist);
+	not_written = isl_union_map_subtract(may_write, must_write);
+
+	local = extract_local_accesses(prog, domain);
+	read = isl_union_map_copy(prog->read);
+	read = isl_union_map_intersect_domain(read, domain);
+	read = remove_local_accesses(prog, tagged, read,
+					isl_union_map_copy(prefix), 1);
+	local = isl_union_set_apply(local, isl_union_map_copy(prog->to_inner));
+	local_uninitialized = isl_union_map_copy(prog->scop->live_in);
+	local_uninitialized = isl_union_map_intersect_range(local_uninitialized,
+							    local);
+	local_uninitialized = isl_union_map_intersect(local_uninitialized,
+						    isl_union_map_copy(read));
+	if (!isl_union_map_is_empty(local_uninitialized)) {
+		fprintf(stderr,
+			"possibly uninitialized reads (not copied in):\n");
+		isl_union_map_dump(local_uninitialized);
+	}
+	read = isl_union_map_subtract(read, local_uninitialized);
+	read = isl_union_map_apply_domain(read, prefix);
+	copy_in = isl_union_map_union(read, not_written);
+	copy_in = isl_union_map_apply_range(copy_in,
+				    isl_union_map_copy(prog->to_outer));
+
+	graft = create_copy_device(prog, node, "to_device",
+						isl_union_map_range(copy_in));
+	node = isl_schedule_node_graft_before(node, graft);
+	graft = create_copy_device(prog, node, "from_device",
+						isl_union_map_range(copy_out));
+	node = isl_schedule_node_graft_after(node, graft);
+
+	return node;
+}
+
+/* Add nodes for initializing ("init_device") and clearing ("clear_device")
+ * the device before and after "node".
+ */
+static __isl_give isl_schedule_node *add_init_clear_device(
+	__isl_take isl_schedule_node *node)
+{
+	isl_ctx *ctx;
+	isl_space *space;
+	isl_union_set *domain;
+	isl_schedule_node *graft;
+
+	ctx = isl_schedule_node_get_ctx(node);
+
+	space = isl_space_set_alloc(ctx, 0, 0);
+	space = isl_space_set_tuple_name(space, isl_dim_set, "init_device");
+	domain = isl_union_set_from_set(isl_set_universe(space));
+	graft = isl_schedule_node_from_domain(domain);
+
+	node = isl_schedule_node_graft_before(node, graft);
+
+	space = isl_space_set_alloc(ctx, 0, 0);
+	space = isl_space_set_tuple_name(space, isl_dim_set, "clear_device");
+	domain = isl_union_set_from_set(isl_set_universe(space));
+	graft = isl_schedule_node_from_domain(domain);
+
+	node = isl_schedule_node_graft_after(node, graft);
+
+	return node;
+}
+
+/* Update "schedule" for mapping to a GPU device.
+ *
+ * In particular, insert a context node, create kernels for
+ * each outermost tilable band and introduce nodes for copying arrays
+ * in and out of the device and for initializing and clearing the device.
+ * If the child of the initial root points to a set node,
+ * then children of this node that do not contain any tilable bands
+ * are separated from the other children and are not mapped to
+ * the device.
+ *
+ * The GPU code is generated in a context where at least one
+ * statement instance is executed.  The corresponding guard is inserted
+ * around the entire schedule.
+ */
+__isl_give isl_schedule *map_to_device(struct gpu_gen *gen,
+	__isl_take isl_schedule *schedule, int to_from_device)
+{
+	isl_schedule_node *node;
+	isl_set *context;
+	isl_set *guard;
+	isl_union_set *domain;
+	isl_union_map *prefix;
+	isl_union_pw_multi_aff *contraction;
+	struct gpu_prog *prog;
+
+	context = isl_set_copy(gen->prog->context);
+	context = isl_set_from_params(context);
+	schedule = isl_schedule_insert_context(schedule, context);
+
+	prog = gen->prog;
+	guard = isl_union_set_params(isl_union_set_copy(prog->scop->domain));
+	prog->context = isl_set_intersect(prog->context, isl_set_copy(guard));
+	guard = isl_set_from_params(guard);
+
+	node = isl_schedule_get_root(schedule);
+	isl_schedule_free(schedule);
+	node = isl_schedule_node_child(node, 0);
+	node = isl_schedule_node_child(node, 0);
+	node = isolate_permutable_subtrees(node, gen->prog);
+	domain = isl_schedule_node_get_domain(node);
+	contraction = isl_schedule_node_get_subtree_contraction(node);
+	domain = isl_union_set_preimage_union_pw_multi_aff(domain,
+				    isl_union_pw_multi_aff_copy(contraction));
+	prefix = isl_schedule_node_get_prefix_schedule_union_map(node);
+	prefix = isl_union_map_preimage_domain_union_pw_multi_aff(prefix,
+				    contraction);
+	node = mark_kernels(gen, node);
+	if (to_from_device) {
+		node = add_to_from_device(node, domain, prefix, gen->prog);
+	} else {
+		isl_union_set_free(domain);
+		isl_union_map_free(prefix);
+	}
+	node = isl_schedule_node_root(node);
+	node = isl_schedule_node_child(node, 0);
+	node = isl_schedule_node_child(node, 0);
+	node = isl_schedule_node_insert_guard(node, guard);
+	node = isl_schedule_node_child(node, 0);
+	node = add_init_clear_device(node);
+	schedule = isl_schedule_node_get_schedule(node);
+	isl_schedule_node_free(node);
+
+	return schedule;
+}
+
+/* Internal data structure for extract_access.
+ * "next_access" points to the end of a linked list that is extended
+ * by extract_access.
+ * "single_expression" is set if the access expressions belong to
+ * an expression statement (i.e., a statement without internal control).
+ * "any_to_outer" maps all intermediate arrays to their outer arrays.
+ */
+struct ppcg_extract_access_data {
+	struct gpu_stmt_access **next_access;
+	int single_expression;
+	isl_union_map *any_to_outer;
+};
+
+/* Given a tagged access relation to a single array "tagged", extract it
+ * as a map, taking into account that the input may be empty.
+ * If the access relation is empty, then it does not contain
+ * any space information, so we try to recover it from the index
+ * expression.
+ * The space of the index expression is of the form I -> A,
+ * with I the statement instances and A the array, or [I -> F] -> A,
+ * with F the filters corresponding to arguments.
+ * We first drop F, if present, obtaining I -> A.
+ * Then we construct I -> R, with R the reference tag,
+ * combine the two into I -> [R -> A] and uncurry to obtain
+ * the final result [I -> R] -> A.
+ * Note that the index expression may have a lower dimension
+ * than that of the array, but this dimension is not used
+ * if the access relation is empty.
+ */
+static __isl_give isl_map *extract_single_tagged_access(
+	__isl_take isl_union_map *tagged, __isl_keep pet_expr *expr)
+{
+	int empty;
+	isl_id *id;
+	isl_space *space, *space2;
+	isl_multi_pw_aff *index;
+
+	empty = isl_union_map_is_empty(tagged);
+	if (empty < 0)
+		goto error;
+	if (!empty)
+		return isl_map_from_union_map(tagged);
+	isl_union_map_free(tagged);
+
+	index = pet_expr_access_get_index(expr);
+	space = isl_multi_pw_aff_get_space(index);
+	isl_multi_pw_aff_free(index);
+	if (isl_space_domain_is_wrapping(space))
+		space = isl_space_domain_factor_domain(space);
+	space2 = isl_space_copy(space);
+	space2 = isl_space_from_domain(isl_space_domain(space));
+	id = pet_expr_access_get_ref_id(expr);
+	space2 = isl_space_set_tuple_id(space2, isl_dim_out, id);
+	space = isl_space_range_product(space2, space);
+	space = isl_space_uncurry(space);
+
+	return isl_map_empty(space);
+error:
+	isl_union_map_free(tagged);
+	return NULL;
+}
+
+/* Does the index expression "index" of "expr" represent an access
+ * to a single element?
+ * That is, is "index" completely specified?
+ *
+ * If "expr" accesses elements from different spaces (i.e., fields
+ * of a structure), then it does not access a single element.
+ * Otherwise, if the single space of the access matches the space
+ * of "index", then the index expression is completely specified
+ * (no pointer to a lower-dimensional slice of the accessed array)
+ * and a single element is being accessed.
+ */
+static isl_bool complete_index(__isl_keep pet_expr *expr,
+	__isl_keep isl_multi_pw_aff *index)
+{
+	isl_union_map *read, *write, *all;
+	isl_map *map;
+	isl_space *space1, *space2;
+	isl_bool complete;
+
+	read = pet_expr_access_get_may_read(expr);
+	write = pet_expr_access_get_may_write(expr);
+	all = isl_union_map_union(read, write);
+	if (!all)
+		return isl_bool_error;
+	if (isl_union_map_n_map(all) != 1) {
+		isl_union_map_free(all);
+		return isl_bool_false;
+	}
+	map = isl_map_from_union_map(all);
+	space1 = isl_map_get_space(map);
+	isl_map_free(map);
+	space2 = isl_multi_pw_aff_get_space(index);
+	complete = isl_space_tuple_is_equal(space1, isl_dim_out,
+					    space2, isl_dim_out);
+	isl_space_free(space1);
+	isl_space_free(space2);
+
+	return complete;
+}
+
+/* Does "expr" access a single, fixed element (independently of the statement
+ * instance)?
+ * That is, does it have a completely specified constant index expression?
+ *
+ * Note that it is not sufficient for the index expression to be
+ * piecewise constant.  isl_multi_pw_aff_is_cst can therefore not be used.
+ */
+static isl_bool accesses_fixed_element(__isl_keep pet_expr *expr)
+{
+	int i, n;
+	isl_multi_pw_aff *index;
+	isl_bool fixed = isl_bool_true;
+
+	index = pet_expr_access_get_index(expr);
+	if (index < 0)
+		return isl_bool_error;
+	n = isl_multi_pw_aff_dim(index, isl_dim_out);
+	for (i = 0; i < n; ++i) {
+		isl_pw_aff *pa;
+
+		pa = isl_multi_pw_aff_get_pw_aff(index, 0);
+		fixed = isl_pw_aff_n_piece(pa) == 1;
+		if (fixed)
+			fixed = isl_pw_aff_is_cst(pa);
+		isl_pw_aff_free(pa);
+		if (fixed < 0 || !fixed)
+			break;
+	}
+	if (fixed >= 0 && fixed)
+		fixed = complete_index(expr, index);
+	isl_multi_pw_aff_free(index);
+
+	return fixed;
+}
+
+/* Extract a gpu_stmt_access from "expr", append it to the list
+ * that ends in *data->next_access and update the end of the list.
+ * If the access expression performs a write, then it is considered
+ * exact only if it appears in a single expression statement and
+ * if its may access relation is equal to its must access relation.
+ *
+ * The combined set of may accesses may be a union if member accesses
+ * are involved, but the entire set is derived from a single reference and
+ * therefore from a single index expression.  These accesses therefore
+ * all map to the same outer array.
+ */
+static int extract_access(__isl_keep pet_expr *expr, void *user)
+{
+	struct ppcg_extract_access_data *data = user;
+	isl_union_map *tagged;
+	struct gpu_stmt_access *access;
+	isl_ctx *ctx = pet_expr_get_ctx(expr);
+	isl_multi_pw_aff *index;
+
+	access = isl_alloc_type(ctx, struct gpu_stmt_access);
+	assert(access);
+	access->next = NULL;
+	access->read = pet_expr_access_is_read(expr);
+	access->write = pet_expr_access_is_write(expr);
+	tagged = pet_expr_access_get_tagged_may_read(expr);
+	tagged = isl_union_map_union(tagged,
+				pet_expr_access_get_tagged_may_write(expr));
+	tagged = isl_union_map_apply_range(tagged,
+					isl_union_map_copy(data->any_to_outer));
+	if (!access->write) {
+		access->exact_write = 1;
+	} else if (!data->single_expression) {
+		access->exact_write = 0;
+	} else {
+		isl_union_map *must, *may;
+		may = isl_union_map_copy(tagged);
+		may = isl_union_map_domain_factor_domain(may);
+		must = pet_expr_access_get_must_write(expr);
+		access->exact_write = isl_union_map_is_equal(must, may);
+		isl_union_map_free(must);
+		isl_union_map_free(may);
+	}
+	index = pet_expr_access_get_index(expr);
+	access->n_index = isl_multi_pw_aff_dim(index, isl_dim_out);
+	isl_multi_pw_aff_free(index);
+	access->ref_id = pet_expr_access_get_ref_id(expr);
+	access->tagged_access = extract_single_tagged_access(tagged, expr);
+	access->access = isl_map_copy(access->tagged_access);
+	access->access = isl_map_domain_factor_domain(access->access);
+	access->fixed_element = accesses_fixed_element(expr);
+
+	*data->next_access = access;
+	data->next_access = &(*data->next_access)->next;
+
+	if (!access->access || access->fixed_element < 0)
+		return -1;
+
+	return 0;
+}
+
+/* Construct a linked list of gpu_stmt_access objects,
+ * one for each access expression in the statement body.
+ * "any_to_outer" maps all intermediate arrays to their outer arrays.
+ */
+static int pet_stmt_extract_accesses(struct gpu_stmt *stmt,
+	__isl_keep isl_union_map *any_to_outer)
+{
+	struct ppcg_extract_access_data data;
+
+	stmt->accesses = NULL;
+	data.next_access = &stmt->accesses;
+	data.single_expression =
+		pet_tree_get_type(stmt->stmt->body) == pet_tree_expr;
+	data.any_to_outer = any_to_outer;
+	return pet_tree_foreach_access_expr(stmt->stmt->body,
+						&extract_access, &data);
+}
+
+/* Has statement "stmt" been killed from "scop"?
+ * That is, is the instance set of "scop" free from any
+ * instances of "stmt"?
+ */
+static isl_bool is_stmt_killed(struct ppcg_scop *scop, struct pet_stmt *stmt)
+{
+	isl_space *space;
+	isl_set *left;
+	isl_bool empty;
+
+	if (!scop || !stmt)
+		return isl_bool_error;
+	space = isl_set_get_space(stmt->domain);
+	left = isl_union_set_extract_set(scop->domain, space);
+	empty = isl_set_plain_is_empty(left);
+	isl_set_free(left);
+
+	return empty;
+}
+
+/* Return an array of gpu_stmt representing the statements in "scop".
+ * Do not collect array accesses for statements that have been killed.
+ */
+static struct gpu_stmt *extract_stmts(isl_ctx *ctx, struct ppcg_scop *scop,
+	__isl_keep isl_union_map *any_to_outer)
+{
+	int i;
+	struct gpu_stmt *stmts;
+
+	stmts = isl_calloc_array(ctx, struct gpu_stmt, scop->pet->n_stmt);
+	if (!stmts)
+		return NULL;
+
+	for (i = 0; i < scop->pet->n_stmt; ++i) {
+		struct gpu_stmt *s = &stmts[i];
+		isl_bool killed;
+
+		s->id = isl_set_get_tuple_id(scop->pet->stmts[i]->domain);
+		s->stmt = scop->pet->stmts[i];
+		killed = is_stmt_killed(scop, scop->pet->stmts[i]);
+		if (killed < 0)
+			return free_stmts(stmts, i + 1);
+		if (killed)
+			continue;
+		if (pet_stmt_extract_accesses(s, any_to_outer) < 0)
+			return free_stmts(stmts, i + 1);
+	}
+
+	return stmts;
+}
+
+/* Generate CUDA code for "scop" and print it to "p".
+ * After generating an AST for the transformed scop as explained below,
+ * we call "gen->print" to print the AST in the desired output format
+ * to "p".
+ *
+ * If it turns out that it does not make sense to generate GPU code,
+ * then we generate CPU code instead.
+ *
+ * The declarations of the arrays that are visible outside of the scop
+ * are printed outside of the code generated from the schedule,
+ * because the generated code may involve a guard around the entire code.
+ *
+ * We first compute a schedule that respects the dependences
+ * of the original program and select the outermost bands
+ * of tilable dimensions that have at least one parallel loop.
+ * If the --load-schedule is specified, then the loaded schedule
+ * is used instead of a computed schedule.
+ *
+ * Each of these bands B is then tiled according to "tile" sizes, resulting
+ * in two nested bands, with a kernel marker on top
+ *
+ *		K
+ *		|
+ *		T
+ *		|
+ *		P
+ *
+ * We then split off at most 2 parallel dimensions from the T band and
+ * at most 3 parallel dimension from the P band
+ *
+ *		K
+ *		|
+ *		T
+ *		T1
+ *		|
+ *		T2
+ *		|
+ *		P1
+ *		|
+ *		P2
+ *
+ * A filter is introduced in front of T1 that maps the domain instances
+ * to block identifiers.  Similarly, a filter is introduced in front of P1
+ * that maps the domain instances to thread identifiers.
+ *
+ * For each iteration of the T2 band and for each array, we compute
+ * the array elements accessed by that iteration, construct a rectangular
+ * box around it and shift it to the origin.  The result is used
+ * as shared memory for the array.
+ *
+ * Copying and synchronization statements are added to this schedule tree.
+ * In principle, these are added in front of the P1 band, but some of
+ * them may get hoisted up to higher levels.
+ *
+ * The entire AST is then generated from the single resulting schedule tree.
+ * During the generation the subtrees at kernel nodes (K) are saved
+ * aside and replaced by kernel calls.  The result is printed as host code
+ * while the saved subtrees are printed as device code.
+ */
+static __isl_give isl_printer *generate(__isl_take isl_printer *p,
+	struct gpu_gen *gen, struct ppcg_scop *scop,
+	struct ppcg_options *options)
+{
+	struct gpu_prog *prog;
+	isl_ctx *ctx;
+	isl_schedule *schedule;
+	int any_permutable;
+
+	if (!scop)
+		return isl_printer_free(p);
+
+	ctx = isl_printer_get_ctx(p);
+	prog = gpu_prog_alloc(ctx, scop);
+	if (!prog)
+		return isl_printer_free(p);
+
+	gen->prog = prog;
+	schedule = get_schedule(gen);
+
+	any_permutable = has_any_permutable_node(schedule);
+	if (any_permutable < 0 || !any_permutable) {
+		if (any_permutable < 0)
+			p = isl_printer_free(p);
+		else
+			p = print_cpu(p, scop, options);
+		isl_schedule_free(schedule);
+	} else {
+		const int create_to_from_device = 1;
+		schedule = map_to_device(gen, schedule, create_to_from_device);
+		gen->tree = generate_code(gen, schedule);
+		p = ppcg_set_macro_names(p);
+		p = ppcg_print_exposed_declarations(p, prog->scop);
+		p = gen->print(p, gen->prog, gen->tree, &gen->types,
+				    gen->print_user);
+		isl_ast_node_free(gen->tree);
+	}
+
+	gpu_prog_free(prog);
+
+	return p;
+}
+
+/* Wrapper around generate for use as a ppcg_transform callback.
+ */
+static __isl_give isl_printer *generate_wrap(__isl_take isl_printer *p,
+	struct ppcg_scop *scop, void *user)
+{
+	struct gpu_gen *gen = user;
+
+	return generate(p, gen, scop, gen->options);
+}
+
+/* Transform the code in the file called "input" by replacing
+ * all scops by corresponding GPU code and write the results to "out".
+ */
+int generate_gpu(isl_ctx *ctx, const char *input, FILE *out,
+	struct ppcg_options *options,
+	__isl_give isl_printer *(*print)(__isl_take isl_printer *p,
+		struct gpu_prog *prog, __isl_keep isl_ast_node *tree,
+		struct gpu_types *types, void *user), void *user)
+{
+	struct gpu_gen gen;
+	int r;
+	int i;
+
+	gen.ctx = ctx;
+	gen.sizes = extract_sizes_from_str(ctx, options->sizes);
+	gen.options = options;
+	gen.kernel_id = 0;
+	gen.print = print;
+	gen.print_user = user;
+	gen.types.n = 0;
+	gen.types.name = NULL;
+
+	if (options->debug->dump_sizes) {
+		isl_space *space = isl_space_params_alloc(ctx, 0);
+		gen.used_sizes = isl_union_map_empty(space);
+	}
+
+	r = ppcg_transform(ctx, input, out, options, &generate_wrap, &gen);
+
+	if (options->debug->dump_sizes) {
+		isl_union_map_dump(gen.used_sizes);
+		isl_union_map_free(gen.used_sizes);
+	}
+
+	isl_union_map_free(gen.sizes);
+	for (i = 0; i < gen.types.n; ++i)
+		free(gen.types.name[i]);
+	free(gen.types.name);
+
+	return r;
+}
+
+/* Compute the set of inner array elements that may have their values
+ * preserved by "prog".  In particular, collect the array elements of
+ * arrays that are not local to "prog" and remove those elements that
+ * are definitely killed or definitely written by "prog".
+ */
+__isl_give isl_union_set *compute_may_persist(struct gpu_prog *prog)
+{
+	int i;
+	isl_union_set *may_persist, *killed;
+	isl_union_map *must_kill;
+
+	may_persist = isl_union_set_empty(isl_set_get_space(prog->context));
+	for (i = 0; i < prog->n_array; ++i) {
+		isl_set *extent;
+
+		if (prog->array[i].local)
+			continue;
+
+		extent = isl_set_copy(prog->array[i].extent);
+		may_persist = isl_union_set_add_set(may_persist, extent);
+	}
+
+	may_persist = isl_union_set_intersect_params(may_persist,
+						isl_set_copy(prog->context));
+	may_persist = isl_union_set_apply(may_persist,
+					isl_union_map_copy(prog->to_inner));
+	must_kill = isl_union_map_copy(prog->tagged_must_kill);
+	killed = isl_union_map_range(must_kill);
+	must_kill = isl_union_map_copy(prog->must_write);
+	killed = isl_union_set_union(killed, isl_union_map_range(must_kill));
+
+	may_persist = isl_union_set_subtract(may_persist, killed);
+	return may_persist;
+}
+
+struct gpu_prog *gpu_prog_alloc(isl_ctx *ctx, struct ppcg_scop *scop)
+{
+	struct gpu_prog *prog;
+	isl_space *space;
+	isl_map *id;
+
+	if (!scop)
+		return NULL;
+
+	prog = isl_calloc_type(ctx, struct gpu_prog);
+	assert(prog);
+
+	prog->ctx = ctx;
+	prog->scop = scop;
+	prog->context = isl_set_copy(scop->context);
+	prog->n_stmts = scop->pet->n_stmt;
+	prog->any_to_outer = pet_scop_compute_outer_to_any(scop->pet);
+	prog->any_to_outer = isl_union_map_reverse(prog->any_to_outer);
+	space = isl_union_map_get_space(prog->any_to_outer);
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, 1);
+	space = isl_space_map_from_set(space);
+	id = isl_map_identity(space);
+	prog->any_to_outer = isl_union_map_add_map(prog->any_to_outer, id);
+	prog->stmts = extract_stmts(ctx, scop, prog->any_to_outer);
+	prog->read = isl_union_map_copy(scop->reads);
+	prog->may_write = isl_union_map_copy(scop->may_writes);
+	prog->must_write = isl_union_map_copy(scop->must_writes);
+	prog->tagged_must_kill = isl_union_map_copy(scop->tagged_must_kills);
+	prog->to_inner = pet_scop_compute_outer_to_inner(scop->pet);
+	prog->to_outer = isl_union_map_copy(prog->to_inner);
+	prog->to_outer = isl_union_map_reverse(prog->to_outer);
+
+	if (!prog->stmts)
+		return gpu_prog_free(prog);
+
+	if (collect_array_info(prog) < 0)
+		return gpu_prog_free(prog);
+	prog->may_persist = compute_may_persist(prog);
+
+	return prog;
+}
+
+void *gpu_prog_free(struct gpu_prog *prog)
+{
+	if (!prog)
+		return NULL;
+	free_array_info(prog);
+	free_stmts(prog->stmts, prog->n_stmts);
+	isl_union_map_free(prog->any_to_outer);
+	isl_union_map_free(prog->to_outer);
+	isl_union_map_free(prog->to_inner);
+	isl_union_map_free(prog->read);
+	isl_union_map_free(prog->may_write);
+	isl_union_map_free(prog->must_write);
+	isl_union_map_free(prog->tagged_must_kill);
+	isl_union_map_free(prog->array_order);
+	isl_union_set_free(prog->may_persist);
+	isl_set_free(prog->context);
+	free(prog);
+	return NULL;
+}
diff --git a/final/lib/External/ppcg/gpu.h b/final/lib/External/ppcg/gpu.h
new file mode 100644
index 0000000..62fb0f7
--- /dev/null
+++ b/final/lib/External/ppcg/gpu.h
@@ -0,0 +1,459 @@
+#ifndef _GPU_H
+#define _GPU_H
+
+#include <isl/ast.h>
+#include <isl/id.h>
+#include <isl/id_to_ast_expr.h>
+
+#include <pet.h>
+
+#include "ppcg.h"
+#include "ppcg_options.h"
+
+/* An access to an outer array element or an iterator.
+ * Accesses to iterators have an access relation that maps to an unnamed space.
+ * An access may be both read and write.
+ * If the access relation is empty, then the output dimension may
+ * not be equal to the dimension of the corresponding array.
+ */
+struct gpu_stmt_access {
+	/* Access reads elements */
+	int read;
+	/* Access writes elements */
+	int write;
+	/* All writes are definite writes. */
+	int exact_write;
+	/* Is a single, fixed element being accessed? */
+	isl_bool fixed_element;
+	/* The number of index expressions specified in the access. */
+	int n_index;
+
+	/* May access relation */
+	isl_map *access;
+	/* May access relation with as domain a mapping from iteration domain
+	 * to a reference identifier.
+	 */
+	isl_map *tagged_access;
+	/* The reference id of the corresponding pet_expr. */
+	isl_id *ref_id;
+
+	struct gpu_stmt_access *next;
+};
+
+/* A representation of a user statement.
+ * "stmt" points to the corresponding pet statement.
+ * "id" is the identifier of the instance set of the statement.
+ * "accesses" is a linked list of accesses performed by the statement.
+ * If the statement has been killed, i.e., if it will not be scheduled,
+ * then this linked list may be empty even if the actual statement does
+ * perform accesses.
+ */
+struct gpu_stmt {
+	isl_id *id;
+	struct pet_stmt *stmt;
+
+	struct gpu_stmt_access *accesses;
+};
+
+/* Represents an outer array possibly accessed by a gpu_prog.
+ */
+struct gpu_array_info {
+	/* The array data space. */
+	isl_space *space;
+	/* Element type. */
+	char *type;
+	/* Element size. */
+	int size;
+	/* Name of the array. */
+	char *name;
+	/* Declared extent of original array. */
+	isl_set *declared_extent;
+	/* AST expression for declared size of original array. */
+	isl_ast_expr *declared_size;
+	/* Extent of the array that needs to be copied. */
+	isl_set *extent;
+	/* Number of indices. */
+	unsigned n_index;
+	/* For each index, a bound on "extent" in that direction. */
+	isl_multi_pw_aff *bound;
+	/* The corresponding access AST expression, if the array needs
+	 * to be allocated on the device.
+	 */
+	isl_ast_expr *bound_expr;
+
+	/* All references to this array; point to elements of a linked list. */
+	int n_ref;
+	struct gpu_stmt_access **refs;
+
+	/* Is this array accessed at all by the program? */
+	int accessed;
+
+	/* Is this a scalar that is read-only within the entire program? */
+	int read_only_scalar;
+
+	/* Are the elements of the array structures? */
+	int has_compound_element;
+
+	/* Are the elements only accessed through constant index expressions? */
+	int only_fixed_element;
+
+	/* Is the array local to the scop? */
+	int local;
+	/* Is the array local and should it be declared on the host? */
+	int declare_local;
+
+	/* Is the corresponding global device memory accessed in any way? */
+	int global;
+
+	/* Should the array be linearized? */
+	int linearize;
+
+	/* Order dependences on this array.
+	 * Only used if live_range_reordering option is set.
+	 * It is set to NULL otherwise.
+	 */
+	isl_union_map *dep_order;
+
+    void *user;
+};
+
+/* Represents an outer array accessed by a ppcg_kernel, localized
+ * to the context of this kernel.
+ *
+ * "array" points to the corresponding array in the gpu_prog.
+ * The "n_group" "groups" are the reference groups associated to the array.
+ * If "force_private" is set, then the array (in practice a scalar)
+ * must be mapped to a register.
+ * "global" is set if the global device memory corresponding
+ * to this array is accessed by the kernel.
+ * "bound" is equal to array->bound specialized to the current kernel.
+ * "bound_expr" is the corresponding access AST expression.
+ */
+struct gpu_local_array_info {
+	struct gpu_array_info *array;
+
+	int n_group;
+	struct gpu_array_ref_group **groups;
+
+	int force_private;
+	int global;
+
+	unsigned n_index;
+	isl_multi_pw_aff *bound;
+	isl_ast_expr *bound_expr;
+};
+
+__isl_give isl_ast_expr *gpu_local_array_info_linearize_index(
+	struct gpu_local_array_info *array, __isl_take isl_ast_expr *expr);
+
+/* A sequence of "n" names of types.
+ */
+struct gpu_types {
+	int n;
+	char **name;
+};
+
+/* "read" and "write" contain the original access relations, possibly
+ * involving member accesses.
+ *
+ * The elements of "array", as well as the ranges of "copy_in" and "copy_out"
+ * only refer to the outer arrays of any possible member accesses.
+ */
+struct gpu_prog {
+	isl_ctx *ctx;
+
+	struct ppcg_scop *scop;
+
+	/* Set of parameter values */
+	isl_set *context;
+
+	/* All potential read accesses in the entire program */
+	isl_union_map *read;
+
+	/* All potential write accesses in the entire program */
+	isl_union_map *may_write;
+	/* All definite write accesses in the entire program */
+	isl_union_map *must_write;
+	/* All tagged definite kills in the entire program */
+	isl_union_map *tagged_must_kill;
+
+	/* The set of inner array elements that may be preserved. */
+	isl_union_set *may_persist;
+
+	/* A mapping from all innermost arrays to their outer arrays. */
+	isl_union_map *to_outer;
+	/* A mapping from the outer arrays to all corresponding inner arrays. */
+	isl_union_map *to_inner;
+	/* A mapping from all intermediate arrays to their outer arrays,
+	 * including an identity mapping from the anonymous 1D space to itself.
+	 */
+	isl_union_map *any_to_outer;
+
+	/* Order dependences on non-scalars. */
+	isl_union_map *array_order;
+
+	/* Array of statements */
+	int n_stmts;
+	struct gpu_stmt *stmts;
+
+	int n_array;
+	struct gpu_array_info *array;
+};
+
+struct gpu_gen {
+	isl_ctx *ctx;
+	struct ppcg_options *options;
+
+	/* Callback for printing of AST in appropriate format. */
+	__isl_give isl_printer *(*print)(__isl_take isl_printer *p,
+		struct gpu_prog *prog, __isl_keep isl_ast_node *tree,
+		struct gpu_types *types, void *user);
+	void *print_user;
+
+    isl_id_to_ast_expr *(*build_ast_expr)(void *stmt,
+            isl_ast_build *build,
+            isl_multi_pw_aff *(*fn_index)(
+                __isl_take isl_multi_pw_aff *mpa, isl_id *id,
+                void *user),
+            void *user_index,
+            isl_ast_expr *(*fn_expr)(isl_ast_expr *expr,
+                isl_id *id, void *user),
+        void *user_expr);
+
+	struct gpu_prog *prog;
+	/* The generated AST. */
+	isl_ast_node *tree;
+
+	/* The sequence of types for which a definition has been printed. */
+	struct gpu_types types;
+
+	/* User specified tile, grid and block sizes for each kernel */
+	isl_union_map *sizes;
+
+	/* Effectively used tile, grid and block sizes for each kernel */
+	isl_union_map *used_sizes;
+
+	/* Identifier of the next kernel. */
+	int kernel_id;
+};
+
+enum ppcg_group_access_type {
+	ppcg_access_global,
+	ppcg_access_shared,
+	ppcg_access_private
+};
+
+enum ppcg_kernel_stmt_type {
+	ppcg_kernel_copy,
+	ppcg_kernel_domain,
+	ppcg_kernel_sync
+};
+
+/* Representation of special statements, in particular copy statements
+ * and __syncthreads statements, inside a kernel.
+ *
+ * type represents the kind of statement
+ *
+ *
+ * for ppcg_kernel_copy statements we have
+ *
+ * read is set if the statement should copy data from global memory
+ * to shared memory or registers.
+ *
+ * index expresses an access to the array element that needs to be copied
+ * local_index expresses the corresponding element in the tile
+ *
+ * array refers to the original array being copied
+ * local_array is a pointer to the appropriate element in the "array"
+ *	array of the ppcg_kernel to which this copy access belongs
+ *
+ *
+ * for ppcg_kernel_domain statements we have
+ *
+ * stmt is the corresponding input statement
+ *
+ * n_access is the number of accesses in stmt
+ * access is an array of local information about the accesses
+ */
+struct ppcg_kernel_stmt {
+	enum ppcg_kernel_stmt_type type;
+
+	union {
+		struct {
+			int read;
+			isl_ast_expr *index;
+			isl_ast_expr *local_index;
+			struct gpu_array_info *array;
+			struct gpu_local_array_info *local_array;
+		} c;
+		struct {
+			struct gpu_stmt *stmt;
+			isl_id_to_ast_expr *ref2expr;
+		} d;
+	} u;
+};
+
+/* Representation of a local variable in a kernel.
+ */
+struct ppcg_kernel_var {
+	struct gpu_array_info *array;
+	enum ppcg_group_access_type type;
+	char *name;
+	isl_vec *size;
+};
+
+/* Representation of a kernel.
+ *
+ * prog describes the original code from which the kernel is extracted.
+ *
+ * id is the sequence number of the kernel.
+ *
+ * block_ids contains the list of block identifiers for this kernel.
+ * thread_ids contains the list of thread identifiers for this kernel.
+ *
+ * the first n_grid elements of grid_dim represent the specified size
+ * of the grid.
+ * the first n_block elements of block_dim represent the specified or
+ * effective size of the block.
+ * Note that in the input file, the sizes of the grid and the blocks
+ * are specified in the order x, y, z, but internally, the sizes
+ * are stored in reverse order, so that the last element always
+ * refers to the x dimension.
+ *
+ * grid_size reflects the effective grid size.
+ * grid_size_expr contains a corresponding access AST expression, built within
+ * the context where the launch appears.
+ *
+ * context contains the values of the parameters and outer schedule dimensions
+ * for which any statement instance in this kernel needs to be executed.
+ *
+ * n_sync is the number of synchronization operations that have
+ * been introduced in the schedule tree corresponding to this kernel (so far).
+ *
+ * core contains the spaces of the statement domains that form
+ * the core computation of the kernel.  It is used to navigate
+ * the tree during the construction of the device part of the schedule
+ * tree in gpu_create_kernel.
+ *
+ * expanded_domain contains the original statement instances,
+ * i.e., those that appear in the domains of access relations,
+ * that are involved in the kernel.
+ * contraction maps those original statement instances to
+ * the statement instances that are active at the point
+ * in the schedule tree where the kernel is created.
+ *
+ * arrays is the set of possibly accessed outer array elements.
+ *
+ * space is the schedule space of the AST context.  That is, it represents
+ * the loops of the generated host code containing the kernel launch.
+ *
+ * n_array is the total number of arrays in the input program and also
+ * the number of element in the array array.
+ * array contains information about each array that is local
+ * to the current kernel.  If an array is not used in a kernel,
+ * then the corresponding entry does not contain any information.
+ *
+ * any_force_private is set if any array in the kernel is marked force_private
+ *
+ * block_filter contains constraints on the domain elements in the kernel
+ * that encode the mapping to block identifiers, where the block identifiers
+ * are represented by "n_grid" parameters with as names the elements
+ * of "block_ids".
+ *
+ * thread_filter contains constraints on the domain elements in the kernel
+ * that encode the mapping to thread identifiers, where the thread identifiers
+ * are represented by "n_block" parameters with as names the elements
+ * of "thread_ids".
+ *
+ * copy_schedule corresponds to the schedule dimensions of
+ * the (tiled) schedule for this kernel that have been taken into account
+ * for computing private/shared memory tiles.
+ * The domain corresponds to the original statement instances, i.e.,
+ * those that appear in the leaves of the schedule tree.
+ * copy_schedule_dim is the dimension of this schedule.
+ *
+ * sync_writes contains write references that require synchronization.
+ * Each reference is represented by a universe set in a space [S[i,j] -> R[]]
+ * with S[i,j] the statement instance space and R[] the array reference.
+ */
+struct ppcg_kernel {
+	isl_ctx *ctx;
+	struct ppcg_options *options;
+
+	struct gpu_prog *prog;
+
+	int id;
+
+	isl_id_list *block_ids;
+	isl_id_list *thread_ids;
+
+	int n_grid;
+	int n_block;
+	int grid_dim[2];
+	int block_dim[3];
+
+	isl_multi_pw_aff *grid_size;
+	isl_ast_expr *grid_size_expr;
+	isl_set *context;
+
+	int n_sync;
+	isl_union_set *core;
+	isl_union_set *arrays;
+
+	isl_union_pw_multi_aff *contraction;
+	isl_union_set *expanded_domain;
+
+	isl_space *space;
+
+	int n_array;
+	struct gpu_local_array_info *array;
+
+	int n_var;
+	struct ppcg_kernel_var *var;
+
+	int any_force_private;
+
+	isl_union_set *block_filter;
+	isl_union_set *thread_filter;
+	isl_union_pw_multi_aff *copy_schedule;
+	int copy_schedule_dim;
+
+	isl_union_set *sync_writes;
+
+	isl_ast_node *tree;
+};
+
+int gpu_array_is_scalar(struct gpu_array_info *array);
+int gpu_array_is_read_only_scalar(struct gpu_array_info *array);
+int gpu_array_requires_device_allocation(struct gpu_array_info *array);
+__isl_give isl_set *gpu_array_positive_size_guard(struct gpu_array_info *array);
+isl_bool gpu_array_can_be_private(struct gpu_array_info *array);
+
+struct gpu_prog *gpu_prog_alloc(isl_ctx *ctx, struct ppcg_scop *scop);
+void *gpu_prog_free(struct gpu_prog *prog);
+
+int ppcg_kernel_requires_array_argument(struct ppcg_kernel *kernel, int i);
+
+int generate_gpu(isl_ctx *ctx, const char *input, FILE *out,
+	struct ppcg_options *options,
+	__isl_give isl_printer *(*print)(__isl_take isl_printer *p,
+		struct gpu_prog *prog, __isl_keep isl_ast_node *tree,
+		struct gpu_types *types, void *user), void *user);
+
+__isl_give isl_schedule_node *gpu_create_kernel(struct gpu_gen *gen,
+	__isl_take isl_schedule_node *node, int scale,
+	__isl_keep isl_multi_val *sizes);
+
+__isl_give isl_schedule *get_schedule(struct gpu_gen *gen);
+int has_any_permutable_node(__isl_keep isl_schedule *schedule);
+__isl_give isl_schedule *map_to_device(struct gpu_gen *gen,
+                                       __isl_take isl_schedule *schedule,
+                                      int to_from_device);
+__isl_give isl_ast_node *generate_code(struct gpu_gen *gen,
+                                       __isl_take isl_schedule *schedule);
+
+__isl_give isl_union_set *compute_may_persist(struct gpu_prog *prog);
+void collect_references(struct gpu_prog *prog, struct gpu_array_info *array);
+void collect_order_dependences(struct gpu_prog *prog);
+isl_bool only_fixed_element_accessed(struct gpu_array_info *array);
+#endif
diff --git a/final/lib/External/ppcg/gpu_array_tile.c b/final/lib/External/ppcg/gpu_array_tile.c
new file mode 100644
index 0000000..b358f2b
--- /dev/null
+++ b/final/lib/External/ppcg/gpu_array_tile.c
@@ -0,0 +1,71 @@
+#include <isl/aff.h>
+#include <isl/map.h>
+
+#include "gpu_array_tile.h"
+
+struct gpu_array_tile *gpu_array_tile_free(struct gpu_array_tile *tile)
+{
+	int j;
+
+	if (!tile)
+		return NULL;
+
+	for (j = 0; j < tile->n; ++j) {
+		isl_val_free(tile->bound[j].size);
+		isl_val_free(tile->bound[j].stride);
+		isl_aff_free(tile->bound[j].lb);
+		isl_aff_free(tile->bound[j].shift);
+	}
+	free(tile->bound);
+	isl_multi_aff_free(tile->tiling);
+	free(tile);
+
+	return NULL;
+}
+
+/* Create a gpu_array_tile for an array of dimension "n_index".
+ */
+struct gpu_array_tile *gpu_array_tile_create(isl_ctx *ctx, int n_index)
+{
+	int i;
+	struct gpu_array_tile *tile;
+
+	tile = isl_calloc_type(ctx, struct gpu_array_tile);
+	if (!tile)
+		return NULL;
+
+	tile->ctx = ctx;
+	tile->bound = isl_alloc_array(ctx, struct gpu_array_bound, n_index);
+	if (!tile->bound)
+		return gpu_array_tile_free(tile);
+
+	tile->n = n_index;
+
+	for (i = 0; i < n_index; ++i) {
+		tile->bound[i].size = NULL;
+		tile->bound[i].lb = NULL;
+		tile->bound[i].stride = NULL;
+		tile->bound[i].shift = NULL;
+	}
+
+	return tile;
+}
+
+/* Compute the size of the tile specified by "tile"
+ * in number of elements and return the result.
+ */
+__isl_give isl_val *gpu_array_tile_size(struct gpu_array_tile *tile)
+{
+	int i;
+	isl_val *size;
+
+	if (!tile)
+		return NULL;
+
+	size = isl_val_one(tile->ctx);
+
+	for (i = 0; i < tile->n; ++i)
+		size = isl_val_mul(size, isl_val_copy(tile->bound[i].size));
+
+	return size;
+}
diff --git a/final/lib/External/ppcg/gpu_array_tile.h b/final/lib/External/ppcg/gpu_array_tile.h
new file mode 100644
index 0000000..53b8e3d
--- /dev/null
+++ b/final/lib/External/ppcg/gpu_array_tile.h
@@ -0,0 +1,59 @@
+#ifndef GPU_ARRAY_TILE_H
+#define GPU_ARRAY_TILE_H
+
+#include <isl/aff_type.h>
+#include <isl/map_type.h>
+#include <isl/val.h>
+
+/* The fields stride and shift only contain valid information
+ * if shift != NULL.
+ * If so, they express that current index is such that if you add shift,
+ * then the result is always a multiple of stride.
+ * Let D represent the initial tile->depth dimensions of the computed schedule.
+ * The spaces of "lb" and "shift" are of the form
+ *
+ *	D -> [b]
+ */
+struct gpu_array_bound {
+	isl_val *size;
+	isl_aff *lb;
+
+	isl_val *stride;
+	isl_aff *shift;
+};
+
+/* A tile of an outer array.
+ *
+ * requires_unroll is set if the schedule dimensions that are mapped
+ * to threads need to be unrolled for this (private) tile to be used.
+ *
+ * "depth" reflects the number of schedule dimensions that affect the tile.
+ * The copying into and/or out of the tile is performed at that depth.
+ *
+ * n is the dimension of the array.
+ * bound is an array of size "n" representing the lower bound
+ *	and size for each index.
+ *
+ * tiling maps a tile in the global array to the corresponding
+ * shared/private memory tile and is of the form
+ *
+ *	{ [D[i] -> A[a]] -> T[(a + shift(i))/stride - lb(i)] }
+ *
+ * where D represents the initial "depth" dimensions
+ * of the computed schedule.
+ */
+struct gpu_array_tile {
+	isl_ctx *ctx;
+	int requires_unroll;
+	int depth;
+	int n;
+	struct gpu_array_bound *bound;
+	isl_multi_aff *tiling;
+};
+
+struct gpu_array_tile *gpu_array_tile_create(isl_ctx *ctx, int n_index);
+struct gpu_array_tile *gpu_array_tile_free(struct gpu_array_tile *tile);
+
+__isl_give isl_val *gpu_array_tile_size(struct gpu_array_tile *tile);
+
+#endif
diff --git a/final/lib/External/ppcg/gpu_group.c b/final/lib/External/ppcg/gpu_group.c
new file mode 100644
index 0000000..7b869b9
--- /dev/null
+++ b/final/lib/External/ppcg/gpu_group.c
@@ -0,0 +1,1828 @@
+/*
+ * Copyright 2010-2011 INRIA Saclay
+ * Copyright 2012-2014 Ecole Normale Superieure
+ * Copyright 2015      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl/constraint.h>
+#include <isl/ilp.h>
+
+#include "gpu_array_tile.h"
+#include "gpu_group.h"
+#include "gpu_tree.h"
+#include "schedule.h"
+
+/* Print the name of the local copy of a given group of array references.
+ */
+__isl_give isl_printer *gpu_array_ref_group_print_name(
+	struct gpu_array_ref_group *group, __isl_take isl_printer *p)
+{
+	int global = 0;
+	enum ppcg_group_access_type type;
+
+	type = gpu_array_ref_group_type(group);
+	if (type == ppcg_access_private)
+		p = isl_printer_print_str(p, "private_");
+	else if (type == ppcg_access_shared)
+		p = isl_printer_print_str(p, "shared_");
+	else
+		global = 1;
+	p = isl_printer_print_str(p, group->array->name);
+	if (!global && group->local_array->n_group > 1) {
+		p = isl_printer_print_str(p, "_");
+		p = isl_printer_print_int(p, group->nr);
+	}
+
+	return p;
+}
+
+/* Return the union of all read (read = 1) and/or write (write = 1)
+ * access relations in the group.
+ */
+__isl_give isl_union_map *gpu_array_ref_group_access_relation(
+	struct gpu_array_ref_group *group, int read, int write)
+{
+	int i;
+	isl_union_map *access;
+
+	access = isl_union_map_empty(isl_map_get_space(group->access));
+	for (i = 0; i < group->n_ref; ++i) {
+		isl_map *map_i;
+
+		if (!((read && group->refs[i]->read) ||
+		     (write && group->refs[i]->write)))
+			continue;
+		map_i = isl_map_copy(group->refs[i]->access);
+		access = isl_union_map_union(access,
+					    isl_union_map_from_map(map_i));
+	}
+
+	return access;
+}
+
+/* Should this array reference group be mapped to private, shared or global
+ * memory?
+ * If we have computed both a private and a shared tile, then
+ * the tile with the smallest depth is used.  If both have the same depth,
+ * then the private tile is used.
+ */
+enum ppcg_group_access_type gpu_array_ref_group_type(
+	struct gpu_array_ref_group *group)
+{
+	if (group->private_tile && group->shared_tile &&
+	    group->shared_tile->depth < group->private_tile->depth)
+		return ppcg_access_shared;
+	if (group->private_tile)
+		return ppcg_access_private;
+	if (group->shared_tile)
+		return ppcg_access_shared;
+	return ppcg_access_global;
+}
+
+
+/* Return the effective gpu_array_tile associated to "group" or
+ * NULL if there is no such gpu_array_tile.
+ */
+struct gpu_array_tile *gpu_array_ref_group_tile(
+	struct gpu_array_ref_group *group)
+{
+	switch (gpu_array_ref_group_type(group)) {
+	case ppcg_access_global:
+		return NULL;
+	case ppcg_access_shared:
+		return group->shared_tile;
+	case ppcg_access_private:
+		return group->private_tile;
+	}
+}
+
+/* Does the tile associated to "group" require unrolling of the schedule
+ * dimensions mapped to threads?
+ * Note that this can only happen for private tiles.
+ */
+int gpu_array_ref_group_requires_unroll(struct gpu_array_ref_group *group)
+{
+	struct gpu_array_tile *tile;
+
+	tile = gpu_array_ref_group_tile(group);
+	if (!tile)
+		return 0;
+	return tile->requires_unroll;
+}
+
+/* Given a constraint
+ *
+ *		a(p,i) + j = g f(e)
+ *
+ * or -a(p,i) - j = g f(e) if sign < 0,
+ * store a(p,i) in bound->shift and g (stride) in bound->stride.
+ * a(p,i) is assumed to be an expression in only the parameters
+ * and the input dimensions.
+ */
+static void extract_stride(__isl_keep isl_constraint *c,
+	struct gpu_array_bound *bound, __isl_keep isl_val *stride, int sign)
+{
+	int i;
+	isl_val *v;
+	isl_space *space;
+	unsigned nparam;
+	unsigned nvar;
+	isl_aff *aff;
+
+	isl_val_free(bound->stride);
+	bound->stride = isl_val_copy(stride);
+
+	space = isl_constraint_get_space(c);
+	space = isl_space_domain(space);
+
+	nparam = isl_space_dim(space, isl_dim_param);
+	nvar = isl_space_dim(space, isl_dim_set);
+
+	v = isl_constraint_get_constant_val(c);
+	if (sign < 0)
+		v = isl_val_neg(v);
+	aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+	aff = isl_aff_set_constant_val(aff, v);
+
+	for (i = 0; i < nparam; ++i) {
+		if (!isl_constraint_involves_dims(c, isl_dim_param, i, 1))
+			continue;
+		v = isl_constraint_get_coefficient_val(c, isl_dim_param, i);
+		if (sign < 0)
+			v = isl_val_neg(v);
+		aff = isl_aff_add_coefficient_val(aff, isl_dim_param, i, v);
+	}
+
+	for (i = 0; i < nvar; ++i) {
+		if (!isl_constraint_involves_dims(c, isl_dim_in, i, 1))
+			continue;
+		v = isl_constraint_get_coefficient_val(c, isl_dim_in, i);
+		if (sign < 0)
+			v = isl_val_neg(v);
+		aff = isl_aff_add_coefficient_val(aff, isl_dim_in, i, v);
+	}
+
+	bound->shift = aff;
+}
+
+/* Given an equality constraint of a map with a single output dimension j,
+ * check if the constraint is of the form
+ *
+ *		a(p,i) + j = g f(e)
+ *
+ * with a(p,i) an expression in the parameters and input dimensions
+ * and f(e) an expression in the existentially quantified variables.
+ * If so, and if g is larger than any such g from a previously considered
+ * constraint, then call extract_stride to record the stride information
+ * in bound.
+ */
+static isl_stat check_stride_constraint(__isl_take isl_constraint *c,
+	void *user)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_val *v;
+	unsigned n_div;
+	struct gpu_array_bound *bound = user;
+
+	ctx = isl_constraint_get_ctx(c);
+	n_div = isl_constraint_dim(c, isl_dim_div);
+	v = isl_constraint_get_coefficient_val(c, isl_dim_out, 0);
+
+	if (n_div && (isl_val_is_one(v) || isl_val_is_negone(v))) {
+		int s = isl_val_sgn(v);
+		isl_val *stride = isl_val_zero(ctx);
+
+		isl_val_free(v);
+		for (i = 0; i < n_div; ++i) {
+			v = isl_constraint_get_coefficient_val(c,
+								isl_dim_div, i);
+			stride = isl_val_gcd(stride, v);
+		}
+		if (!isl_val_is_zero(stride) &&
+		    isl_val_gt(stride, bound->stride))
+			extract_stride(c, bound, stride, s);
+
+		isl_val_free(stride);
+	} else
+		isl_val_free(v);
+
+	isl_constraint_free(c);
+	return isl_stat_ok;
+}
+
+/* Given contraints on an array index i, check if we can find
+ * a shift a(p) and a stride g such that
+ *
+ *	a(p) + i = 0 mod g
+ *
+ * If so, record the information in bound and apply the mapping
+ * i -> (i + a(p))/g to the array index in bounds and return
+ * the new constraints.
+ * If not, simply return the original constraints.
+ *
+ * If bounds is a subset of the space
+ *
+ *	D -> i
+ *
+ * then the bound recorded in bound->shift is of the form
+ *
+ *	D -> s(D)
+ *
+ * with s(D) equal to a(p) above.
+ * Next, we construct a mapping of the form
+ *
+ *	[D -> i] -> [D -> (i + S(D))/g]
+ *
+ * This mapping is computed as follows.
+ * We first introduce "i" in the domain through precomposition
+ * with [D -> i] -> D obtaining
+ *
+ *	[D -> i] -> s(D)
+ *
+ * Adding [D -> i] -> i produces
+ *
+ *	[D -> i] -> i + s(D)
+ *
+ * and the domain product with [D -> i] -> D yields
+ *
+ *	[D -> i] -> [D -> i + s(D)]
+ *
+ * Composition with [D -> i] -> [D -> i/g] gives the desired result.
+ */
+static __isl_give isl_basic_map *check_stride(struct gpu_array_bound *bound,
+	__isl_take isl_basic_map *bounds)
+{
+	isl_space *space;
+	isl_basic_map *hull;
+	isl_basic_map *shift, *id, *bmap, *scale;
+	isl_basic_set *bset;
+	isl_aff *aff;
+
+	bound->stride = NULL;
+
+	hull = isl_basic_map_affine_hull(isl_basic_map_copy(bounds));
+
+	isl_basic_map_foreach_constraint(hull, &check_stride_constraint, bound);
+
+	isl_basic_map_free(hull);
+
+	if (!bound->stride)
+		return bounds;
+
+	shift = isl_basic_map_from_aff(isl_aff_copy(bound->shift));
+	space = isl_basic_map_get_space(bounds);
+	bmap = isl_basic_map_domain_map(isl_basic_map_universe(space));
+	shift = isl_basic_map_apply_range(bmap, shift);
+	space = isl_basic_map_get_space(bounds);
+	id = isl_basic_map_range_map(isl_basic_map_universe(space));
+	shift = isl_basic_map_sum(id, shift);
+	space = isl_basic_map_get_space(bounds);
+	id = isl_basic_map_domain_map(isl_basic_map_universe(space));
+	shift = isl_basic_map_range_product(id, shift);
+
+	space = isl_space_domain(isl_basic_map_get_space(bounds));
+	id = isl_basic_map_identity(isl_space_map_from_set(space));
+	space = isl_space_range(isl_basic_map_get_space(bounds));
+	aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+	aff = isl_aff_add_coefficient_si(aff, isl_dim_in, 0, 1);
+	aff = isl_aff_scale_down_val(aff, isl_val_copy(bound->stride));
+	scale = isl_basic_map_from_aff(aff);
+	scale = isl_basic_map_product(id, scale);
+
+	bmap = isl_basic_map_apply_range(shift, scale);
+	bset = isl_basic_set_apply(isl_basic_map_wrap(bounds), bmap);
+	bounds = isl_basic_set_unwrap(bset);
+
+	return bounds;
+}
+
+/* Data used in compute_array_dim_size and compute_size_in_direction.
+ *
+ * pos is the position of the variable representing the array index,
+ * i.e., the variable for which want to compute the size.  This variable
+ * is also the last variable in the set.
+ */
+struct gpu_size_info {
+	isl_basic_set *bset;
+	struct gpu_array_bound *bound;
+	int pos;
+};
+
+/* Given a constraint from the basic set describing the bounds on
+ * an array index, check if it is a lower bound, say m i >= b(x), and,
+ * if so, check whether the expression "i - ceil(b(x)/m) + 1" has a constant
+ * upper bound.  If so, and if this bound is smaller than any bound
+ * derived from earlier constraints, set the size to this bound on
+ * the expression and the lower bound to ceil(b(x)/m).
+ */
+static isl_stat compute_size_in_direction(__isl_take isl_constraint *c,
+	void *user)
+{
+	struct gpu_size_info *size = user;
+	unsigned nparam;
+	unsigned n_div;
+	isl_val *v;
+	isl_aff *aff;
+	isl_aff *lb;
+
+	nparam = isl_basic_set_dim(size->bset, isl_dim_param);
+	n_div = isl_constraint_dim(c, isl_dim_div);
+
+	if (isl_constraint_involves_dims(c, isl_dim_div, 0, n_div) ||
+	    !isl_constraint_is_lower_bound(c, isl_dim_set, size->pos)) {
+		isl_constraint_free(c);
+		return isl_stat_ok;
+	}
+
+	aff = isl_constraint_get_bound(c, isl_dim_set, size->pos);
+	aff = isl_aff_ceil(aff);
+
+	lb = isl_aff_copy(aff);
+
+	aff = isl_aff_neg(aff);
+	aff = isl_aff_add_coefficient_si(aff, isl_dim_in, size->pos, 1);
+
+	v = isl_basic_set_max_val(size->bset, aff);
+	isl_aff_free(aff);
+
+	if (isl_val_is_int(v)) {
+		v = isl_val_add_ui(v, 1);
+		if (!size->bound->size || isl_val_lt(v, size->bound->size)) {
+			isl_val_free(size->bound->size);
+			size->bound->size = isl_val_copy(v);
+			lb = isl_aff_drop_dims(lb, isl_dim_in, size->pos, 1);
+			isl_aff_free(size->bound->lb);
+			size->bound->lb = isl_aff_copy(lb);
+		}
+	}
+	isl_val_free(v);
+	isl_aff_free(lb);
+
+	isl_constraint_free(c);
+
+	return isl_stat_ok;
+}
+
+/* Given a basic map "bounds" that maps parameters and input dimensions
+ * to a single output dimension, look for an expression in the parameters
+ * and input dimensions such that the range of the output dimension shifted
+ * by this expression is a constant.
+ *
+ * In particular, we currently only consider lower bounds on the output
+ * dimension as candidate expressions.
+ */
+static int compute_array_dim_size(struct gpu_array_bound *bound,
+	__isl_take isl_basic_map *bounds)
+{
+	struct gpu_size_info size;
+
+	bounds = isl_basic_map_detect_equalities(bounds);
+	bounds = check_stride(bound, bounds);
+
+	bound->size = NULL;
+	bound->lb = NULL;
+
+	size.bound = bound;
+	size.pos = isl_basic_map_dim(bounds, isl_dim_in);
+	size.bset = isl_basic_map_wrap(bounds);
+	size.bset = isl_basic_set_flatten(size.bset);
+	size.bset = isl_set_simple_hull(isl_basic_set_compute_divs(size.bset));
+	isl_basic_set_foreach_constraint(size.bset, &compute_size_in_direction,
+					&size);
+	isl_basic_set_free(size.bset);
+
+	return bound->size ? 0 : -1;
+}
+
+/* Check if we can find a memory tile for the given array
+ * based on the given accesses, and if so, put the results in "tile".
+ *
+ * We project the accesses on each index in turn and look for a parametric
+ * offset such that the size is constant.
+ *
+ * tile->depth is initialized to the input dimension of the computed bounds.
+ */
+static int can_tile(__isl_keep isl_map *access, struct gpu_array_tile *tile)
+{
+	int i;
+
+	tile->depth = isl_map_dim(access, isl_dim_in);
+
+	for (i = 0; i < tile->n; ++i) {
+		isl_map *access_i;
+		isl_basic_map *hull;
+
+		access_i = isl_map_copy(access);
+		access_i = isl_map_project_out(access_i, isl_dim_out, 0, i);
+		access_i = isl_map_project_out(access_i, isl_dim_out,
+					    1, tile->n - (i + 1));
+		access_i = isl_map_compute_divs(access_i);
+		hull = isl_map_simple_hull(access_i);
+		if (compute_array_dim_size(&tile->bound[i], hull) < 0)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Internal data structure for gpu_group_references.
+ *
+ * scop represents the input scop.
+ * kernel_depth is the schedule depth where the kernel launch will
+ * be introduced, i.e., it is the depth of the band that is mapped
+ * to blocks.
+ * shared_depth is the schedule depth at which the copying to/from
+ * shared memory is computed.  The copy operation may then
+ * later be hoisted to a higher level.
+ * thread_depth is the schedule depth where the thread mark is located,
+ * i.e., it is the depth of the band that is mapped to threads and also
+ * the schedule depth at which the copying to/from private memory
+ * is computed.  The copy operation may then later be hoisted to
+ * a higher level.
+ * n_thread is the number of schedule dimensions in the band that
+ * is mapped to threads.
+ * privatization lives in the range of thread_sched (i.e., it is
+ * of dimension thread_depth + n_thread) and encodes the mapping
+ * to thread identifiers (as parameters).
+ * host_sched contains the kernel_depth dimensions of the host schedule.
+ * shared_sched contains the first shared_depth dimensions of the
+ * kernel schedule.
+ * copy_sched contains the first thread_depth dimensions of the
+ * kernel schedule.
+ * thread_sched contains the first (thread_depth + n_thread) dimensions
+ * of the kernel schedule.
+ * full_sched is a union_map representation of the entire kernel schedule.
+ * The schedules are all formulated in terms of the original statement
+ * instances, i.e., those that appear in the domains of the access
+ * relations.
+ */
+struct gpu_group_data {
+	struct ppcg_scop *scop;
+	int kernel_depth;
+	int shared_depth;
+	int thread_depth;
+	int n_thread;
+	isl_set *privatization;
+	isl_union_map *host_sched;
+	isl_union_map *shared_sched;
+	isl_union_map *copy_sched;
+	isl_union_map *thread_sched;
+	isl_union_map *full_sched;
+};
+
+/* Construct a map from domain_space to domain_space that increments
+ * the dimension at position "pos" and leaves all other dimensions
+ * constant.
+ */
+static __isl_give isl_map *next(__isl_take isl_space *domain_space, int pos)
+{
+	isl_space *space;
+	isl_aff *aff;
+	isl_multi_aff *next;
+
+	space = isl_space_map_from_set(domain_space);
+	next = isl_multi_aff_identity(space);
+	aff = isl_multi_aff_get_aff(next, pos);
+	aff = isl_aff_add_constant_si(aff, 1);
+	next = isl_multi_aff_set_aff(next, pos, aff);
+
+	return isl_map_from_multi_aff(next);
+}
+
+/* Check if the given access is coalesced (or if there is no point
+ * in trying to coalesce the access by mapping the array to shared memory).
+ * That is, check whether incrementing the dimension that will get
+ * wrapped over the last thread index results in incrementing
+ * the last array index.
+ *
+ * If no two consecutive array elements are ever accessed by "access",
+ * then mapping the corresponding array to shared memory will not
+ * improve coalescing.  In fact, the copying will likely be performed
+ * by a single thread.  Consider the access as coalesced such that
+ * the caller will not try and map the array to shared memory just
+ * to improve coalescing.
+ *
+ * This function is only called for access relations without reuse and
+ * kernels with at least one thread identifier.
+ */
+static int access_is_coalesced(struct gpu_group_data *data,
+	__isl_keep isl_union_map *access)
+{
+	int dim;
+	isl_space *space;
+	isl_set *accessed;
+	isl_map *access_map;
+	isl_map *next_thread_x;
+	isl_map *next_element;
+	isl_map *map;
+	int coalesced, empty;
+
+	access = isl_union_map_copy(access);
+	access = isl_union_map_apply_domain(access,
+				isl_union_map_copy(data->full_sched));
+	access_map = isl_map_from_union_map(access);
+
+	space = isl_map_get_space(access_map);
+	space = isl_space_range(space);
+	dim = isl_space_dim(space, isl_dim_set);
+	if (dim == 0)
+		next_element = isl_map_empty(isl_space_map_from_set(space));
+	else
+		next_element = next(space, dim - 1);
+
+	accessed = isl_map_range(isl_map_copy(access_map));
+	map = isl_map_copy(next_element);
+	map = isl_map_intersect_domain(map, isl_set_copy(accessed));
+	map = isl_map_intersect_range(map, accessed);
+	empty = isl_map_is_empty(map);
+	isl_map_free(map);
+
+	if (empty < 0 || empty) {
+		isl_map_free(next_element);
+		isl_map_free(access_map);
+		return empty;
+	}
+
+	space = isl_map_get_space(access_map);
+	space = isl_space_domain(space);
+	next_thread_x = next(space, data->thread_depth + data->n_thread - 1);
+
+	map = isl_map_apply_domain(next_thread_x, isl_map_copy(access_map));
+	map = isl_map_apply_range(map, access_map);
+
+	coalesced = isl_map_is_subset(map, next_element);
+
+	isl_map_free(next_element);
+	isl_map_free(map);
+
+	return coalesced;
+}
+
+/* Replace the host schedule dimensions in the access relation "access"
+ * by parameters, so that they are treated as fixed when checking for reuse
+ * (within a kernel) or whether two consecutive elements are accessed
+ * (within a kernel).
+ */
+static __isl_give isl_union_map *localize_access(struct gpu_group_data *data,
+	__isl_take isl_union_map *access)
+{
+	int n;
+	isl_space *space;
+	isl_set *param;
+	isl_union_map *umap;
+	isl_id_list *ids;
+
+	umap = isl_union_map_copy(data->host_sched);
+	space = isl_union_map_get_space(umap);
+	n = data->kernel_depth;
+	ids = ppcg_scop_generate_names(data->scop, n, "__ppcg_host_");
+	param = parametrization(space, n, 0, ids);
+	isl_id_list_free(ids);
+	umap = isl_union_map_intersect_range(umap,
+						isl_union_set_from_set(param));
+	access = isl_union_map_intersect_domain(access,
+						isl_union_map_domain(umap));
+
+	return access;
+}
+
+/* Given an access relation in terms of at least data->thread_depth initial
+ * dimensions of the computed schedule, check if it is bijective for
+ * fixed values of the first data->thread_depth dimensions.
+ * We perform this check by equating these dimensions to parameters.
+ */
+static int access_is_bijective(struct gpu_group_data *data,
+	__isl_keep isl_map *access)
+{
+	int res;
+	int dim;
+	isl_set *par;
+	isl_space *space;
+	isl_id_list *ids;
+
+	access = isl_map_copy(access);
+	space = isl_space_params(isl_map_get_space(access));
+	ids = ppcg_scop_generate_names(data->scop, data->thread_depth, "s");
+	dim = isl_map_dim(access, isl_dim_in);
+	par = parametrization(space, dim, 0, ids);
+	isl_id_list_free(ids);
+	access = isl_map_intersect_domain(access, par);
+	res = isl_map_is_bijective(access);
+	isl_map_free(access);
+
+	return res;
+}
+
+/* Compute the number of outer schedule tile dimensions that affect
+ * the offset of "tile".
+ * If there is no such dimension, then return the index
+ * of the first kernel dimension, i.e., data->kernel_depth.
+ */
+static int compute_tile_depth(struct gpu_group_data *data,
+	struct gpu_array_tile *tile)
+{
+	int i, j;
+
+	for (j = tile->depth - 1; j >= data->kernel_depth; --j) {
+		for (i = 0; i < tile->n; ++i) {
+			isl_aff *lb;
+			isl_aff *shift;
+
+			lb = tile->bound[i].lb;
+			if (isl_aff_involves_dims(lb, isl_dim_in, j, 1))
+				break;
+
+			shift = tile->bound[i].shift;
+			if (!shift)
+				continue;
+			if (isl_aff_involves_dims(shift, isl_dim_in, j, 1))
+				break;
+		}
+		if (i < tile->n)
+			break;
+	}
+
+	return ++j;
+}
+
+/* Return the lowest depth between data->kernel_depth and data->thread_depth
+ * at which every array element accessed through "acc" is accessed
+ * by a single thread.  The input dimension of "acc" is
+ * data->thread_depth + data->n_thread, where the final data->n_thread
+ * dimensions are those that will be mapped to threads.
+ * If the values for these dimensions are uniquely determined
+ * by the array index and a given number of outer dimensions, then
+ * there is only one thread accessing that array element within those
+ * outer dimensions.
+ *
+ * The input space of "acc" is first split up, such that it has the form
+ *
+ *	[O -> T] -> A
+ *
+ * with O the outer dimensions, T the dimensions that will be mapped to threads
+ * and A the array index.
+ *
+ * Then the positions of T and A are interchanged to simplify the test
+ * whether T uniquely depends on O and A.
+ * In particular, the above access relation is first combined with
+ *
+ *	[O -> T] -> T
+ *
+ * to form
+ *
+ *	[O -> T] -> [A -> T]
+ *
+ * from which
+ *
+ *	O -> [A -> T]
+ *
+ * is extracted, which is then uncurried to
+ *
+ *	[O -> A] -> T
+ *
+ * Finally, the final dimensions of O are projected out one by one
+ * until T is no longer uniquely determined by A and the remaining
+ * dimensions in O.  The value returned is that of the last dimension
+ * that was successfully projected out.
+ * Note that there is no need to test whether [O -> A] -> T itself
+ * is single-valued as that was already tested in access_is_bijective.
+ */
+static int compute_accessed_by_single_thread_depth(struct gpu_group_data *data,
+	__isl_keep isl_map *acc)
+{
+	int i;
+	isl_space *space;
+	isl_map *map;
+	isl_bool sv;
+
+	if (data->thread_depth == data->kernel_depth)
+		return data->thread_depth;
+
+	acc = isl_map_copy(acc);
+
+	space = isl_map_get_space(acc);
+	space = isl_space_params(space);
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, data->thread_depth);
+	space = isl_space_from_domain(space);
+	space = isl_space_add_dims(space, isl_dim_out, data->n_thread);
+	space = isl_space_wrap(space);
+	map = isl_set_flatten_map(isl_set_universe(space));
+	acc = isl_map_apply_range(map, acc);
+
+	space = isl_space_domain(isl_map_get_space(acc));
+	map = isl_map_range_map(isl_map_universe(isl_space_unwrap(space)));
+	acc = isl_map_range_product(acc, map);
+	acc = isl_map_domain_factor_domain(acc);
+	acc = isl_map_uncurry(acc);
+
+	for (i = data->thread_depth - 1; i >= data->kernel_depth; --i) {
+		acc = isl_map_project_out(acc, isl_dim_in, i, 1);
+		sv = isl_map_is_single_valued(acc);
+		if (sv < 0)
+			return -1;
+		if (!sv)
+			break;
+	}
+
+	isl_map_free(acc);
+
+	return ++i;
+}
+
+/* Adjust the fields of "tile" to reflect the new input dimension "depth".
+ * The dimension beyond "depth" are assumed not to affect the tile,
+ * so they can simply be dropped.
+ */
+static int tile_adjust_depth(struct gpu_array_tile *tile, int depth)
+{
+	int i;
+
+	if (tile->depth == depth)
+		return 0;
+
+	for (i = 0; i < tile->n; ++i) {
+		tile->bound[i].lb = isl_aff_drop_dims(tile->bound[i].lb,
+					isl_dim_in, depth, tile->depth - depth);
+		if (!tile->bound[i].lb)
+			return -1;
+		if (!tile->bound[i].shift)
+			continue;
+		tile->bound[i].shift = isl_aff_drop_dims(tile->bound[i].shift,
+					isl_dim_in, depth, tile->depth - depth);
+		if (!tile->bound[i].shift)
+			return -1;
+	}
+
+	tile->depth = depth;
+
+	return 0;
+}
+
+/* Determine the number of schedule dimensions that affect the offset of the
+ * shared or private tile "tile" and store the result in tile->depth, with
+ * a lower bound of data->kernel_depth.
+ * Also adjust the fields of the tile to only refer to the tile->depth
+ * outer schedule dimensions.
+ */
+static isl_stat tile_set_depth(struct gpu_group_data *data,
+	struct gpu_array_tile *tile)
+{
+	if (tile_adjust_depth(tile, compute_tile_depth(data, tile)) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Determine the number of schedule dimensions that affect the offset of the
+ * shared tile and store the minimum of the private and shared tile depth
+ * in group->min_depth, with a lower bound of data->kernel_depth.
+ * If there is no tile defined on the array reference group,
+ * then set group->min_depth to data->thread_depth.
+ */
+static int set_depth(struct gpu_group_data *data,
+	struct gpu_array_ref_group *group)
+{
+	group->min_depth = data->thread_depth;
+
+	if (group->private_tile) {
+		if (group->private_tile->depth < group->min_depth)
+			group->min_depth = group->private_tile->depth;
+	}
+	if (group->shared_tile) {
+		if (tile_set_depth(data, group->shared_tile) < 0)
+			return -1;
+		if (group->shared_tile->depth < group->min_depth)
+			group->min_depth = group->shared_tile->depth;
+	}
+
+	return 0;
+}
+
+/* Fill up the groups array with singleton groups, i.e., one group
+ * per reference, initializing the array, access, write, n_ref and refs fields.
+ * In particular the access field is initialized to the scheduled
+ * access relation of the array reference.
+ *
+ * Return the number of elements initialized, i.e., the number of
+ * active references in the current kernel.
+ */
+static int populate_array_references(struct gpu_local_array_info *local,
+	struct gpu_array_ref_group **groups, struct gpu_group_data *data)
+{
+	int i;
+	int n;
+	isl_ctx *ctx = isl_union_map_get_ctx(data->copy_sched);
+
+	n = 0;
+	for (i = 0; i < local->array->n_ref; ++i) {
+		isl_union_map *umap;
+		isl_map *map;
+		struct gpu_array_ref_group *group;
+		struct gpu_stmt_access *access = local->array->refs[i];
+
+		map = isl_map_copy(access->access);
+		umap = isl_union_map_from_map(map);
+		umap = isl_union_map_apply_domain(umap,
+				isl_union_map_copy(data->copy_sched));
+
+		if (isl_union_map_is_empty(umap)) {
+			isl_union_map_free(umap);
+			continue;
+		}
+
+		map = isl_map_from_union_map(umap);
+		map = isl_map_detect_equalities(map);
+
+		group = isl_calloc_type(ctx, struct gpu_array_ref_group);
+		if (!group)
+			return -1;
+		group->local_array = local;
+		group->array = local->array;
+		group->access = map;
+		group->write = access->write;
+		group->exact_write = access->exact_write;
+		group->slice = access->n_index < local->array->n_index;
+		group->refs = &local->array->refs[i];
+		group->n_ref = 1;
+
+		groups[n++] = group;
+	}
+
+	return n;
+}
+
+/* If group->n_ref == 1, then group->refs was set by
+ * populate_array_references to point directly into
+ * group->array->refs and should not be freed.
+ * If group->n_ref > 1, then group->refs was set by join_groups
+ * to point to a newly allocated array.
+ */
+struct gpu_array_ref_group *gpu_array_ref_group_free(
+	struct gpu_array_ref_group *group)
+{
+	if (!group)
+		return NULL;
+	gpu_array_tile_free(group->shared_tile);
+	gpu_array_tile_free(group->private_tile);
+	isl_map_free(group->access);
+	if (group->n_ref > 1)
+		free(group->refs);
+	free(group);
+	return NULL;
+}
+
+/* Check if the access relations of group1 and group2 overlap within
+ * copy_sched.
+ */
+static int accesses_overlap(struct gpu_array_ref_group *group1,
+	struct gpu_array_ref_group *group2)
+{
+	int disjoint;
+
+	disjoint = isl_map_is_disjoint(group1->access, group2->access);
+	if (disjoint < 0)
+		return -1;
+
+	return !disjoint;
+}
+
+/* Combine the given two groups into a single group, containing
+ * the references of both groups.
+ */
+static struct gpu_array_ref_group *join_groups(
+	struct gpu_array_ref_group *group1,
+	struct gpu_array_ref_group *group2)
+{
+	int i;
+	isl_ctx *ctx;
+	struct gpu_array_ref_group *group;
+
+	if (!group1 || !group2)
+		return NULL;
+
+	ctx = isl_map_get_ctx(group1->access);
+	group = isl_calloc_type(ctx, struct gpu_array_ref_group);
+	if (!group)
+		return NULL;
+	group->local_array = group1->local_array;
+	group->array = group1->array;
+	group->access = isl_map_union(isl_map_copy(group1->access),
+					isl_map_copy(group2->access));
+	group->write = group1->write || group2->write;
+	group->exact_write = group1->exact_write && group2->exact_write;
+	group->slice = group1->slice || group2->slice;
+	group->n_ref = group1->n_ref + group2->n_ref;
+	group->refs = isl_alloc_array(ctx, struct gpu_stmt_access *,
+					group->n_ref);
+	if (!group->refs)
+		return gpu_array_ref_group_free(group);
+	for (i = 0; i < group1->n_ref; ++i)
+		group->refs[i] = group1->refs[i];
+	for (i = 0; i < group2->n_ref; ++i)
+		group->refs[group1->n_ref + i] = group2->refs[i];
+
+	return group;
+}
+
+/* Combine the given two groups into a single group and free
+ * the original two groups.
+ */
+static struct gpu_array_ref_group *join_groups_and_free(
+	struct gpu_array_ref_group *group1,
+	struct gpu_array_ref_group *group2)
+{
+	struct gpu_array_ref_group *group;
+
+	group = join_groups(group1, group2);
+	gpu_array_ref_group_free(group1);
+	gpu_array_ref_group_free(group2);
+	return group;
+}
+
+/* Report that the array reference group with the given access relation
+ * is not mapped to shared memory in the given kernel because
+ * it does not exhibit any reuse and is considered to be coalesced.
+ */
+static void report_no_reuse_and_coalesced(struct ppcg_kernel *kernel,
+	__isl_keep isl_union_map *access)
+{
+	isl_ctx *ctx;
+	isl_printer *p;
+
+	ctx = isl_union_map_get_ctx(access);
+	p = isl_printer_to_file(ctx, stdout);
+	p = isl_printer_print_str(p, "Array reference group ");
+	p = isl_printer_print_union_map(p, access);
+	p = isl_printer_print_str(p,
+	    " not considered for mapping to shared memory in kernel");
+	p = isl_printer_print_int(p, kernel->id);
+	p = isl_printer_print_str(p,
+	    " because it exhibits no reuse and is considered to be coalesced");
+	p = isl_printer_end_line(p);
+	isl_printer_free(p);
+}
+
+/* Given an access relation in terms of the data->thread_depth initial
+ * dimensions of the computed schedule and the thread identifiers
+ * (as parameters), check if the use of the corresponding private tile
+ * requires unrolling.
+ *
+ * If we are creating a private tile because we are forced to,
+ * then no unrolling is required.
+ * Otherwise we check if "access" is bijective and unrolling
+ * is required if it is not.  Note that the access relation
+ * has already been determined to be bijective before the introduction
+ * of the thread identifiers and the removal of the schedule dimensions
+ * that are mapped to these threads.  If the access relation is no longer
+ * bijective, then this means that more than one value of one of those
+ * schedule dimensions is mapped to the same thread and therefore
+ * unrolling is required.
+ */
+static int check_requires_unroll(struct gpu_group_data *data,
+	__isl_keep isl_map *access, int force_private)
+{
+	int bijective;
+
+	if (force_private)
+		return 0;
+	bijective = access_is_bijective(data, access);
+	if (bijective < 0)
+		return -1;
+	return !bijective;
+}
+
+/* Map the domain of "access" to the outer data->shared_depth
+ * schedule dimensions.  When data->shared_depth is equal to
+ * data->thread_depth, this result is already available in group->access.
+ */
+static __isl_give isl_map *shared_access(struct gpu_array_ref_group *group,
+	__isl_keep isl_union_map *access, struct gpu_group_data *data)
+{
+	isl_union_map *shared;
+
+	if (data->shared_depth == data->thread_depth)
+		return isl_map_copy(group->access);
+
+	shared = isl_union_map_copy(access);
+	shared = isl_union_map_apply_domain(shared,
+			isl_union_map_copy(data->shared_sched));
+	return isl_map_from_union_map(shared);
+}
+
+/* Compute the private and/or shared memory tiles for the array
+ * reference group "group" of array "array".
+ * Return 0 on success and -1 on error.
+ *
+ * If the array is a read-only scalar or if the user requested
+ * not to use shared or private memory, then we do not need to do anything.
+ *
+ * If any reference in the reference group accesses more than one element,
+ * then we would have to make sure that the layout in shared memory
+ * is the same as that in global memory.  Since we do not handle this yet
+ * (and it may not even be possible), we refuse to map to private or
+ * shared memory in such cases.
+ *
+ * If the array group involves any may writes (that are not must writes),
+ * then we would have to make sure that we load the data into shared/private
+ * memory first in case the data is not written by the kernel
+ * (but still written back out to global memory).
+ * Since we don't have any such mechanism at the moment, we don't
+ * compute shared/private tiles for groups involving may writes.
+ *
+ * We only try to compute a shared memory tile if there is any reuse
+ * or if the access is not coalesced.
+ * Reuse and coalescing are checked within the given kernel.
+ *
+ * For computing a private memory tile, we also require that there is
+ * some reuse.  Moreover, we require that the access is private
+ * to the thread.  That is, we check that any given array element
+ * is only accessed by a single thread.
+ * We compute an access relation that maps the outer
+ * data->thread_depth + data->n_thread schedule dimensions.
+ * The latter data->n_thread will be mapped to thread identifiers.
+ * We actually check that those iterators that will be wrapped
+ * partition the array space.  This check is stricter than necessary
+ * since several iterations may be mapped onto the same thread
+ * and then they could be allowed to access the same memory elements,
+ * but our check does not allow this situation.
+ *
+ * For private memory tiles, the number of schedule dimensions that
+ * affect the offset is computed and stored in tile->depth, with
+ * a lower bound of data->kernel_depth.  If this depth is smaller
+ * than the minimal depth that still ensures that every element
+ * is accessed by a single thread, then the depth is raised
+ * to this minimal depth.
+ * The fields of the tile are then adjusted to only refer to the tile->depth
+ * outer schedule dimensions.
+ *
+ * We also check that the index expression only depends on parallel
+ * loops.  That way, we can move those loops innermost and unroll them.
+ * Again, we use a test that is stricter than necessary.
+ * We actually check whether the index expression only depends
+ * on the iterators that are wrapped over the threads.
+ * These are necessarily parallel, but there may be more parallel loops.
+ *
+ * Combining the injectivity of the first test with the single-valuedness
+ * of the second test, we simply test for bijectivity.
+ *
+ * If the use of the private tile requires unrolling, but some
+ * of the other arrays are forcibly mapped to private memory,
+ * then we do not allow the use of this private tile since
+ * we cannot move the schedule dimensions that need to be unrolled down
+ * without performing some kind of expansion on those arrays
+ * that are forcibly mapped to private memory.
+ *
+ * If the array is marked force_private, then we bypass all checks
+ * and assume we can (and should) use registers only.
+ *
+ * If it turns out we can (or have to) use registers, we compute
+ * the private memory tile size using can_tile, after introducing a dependence
+ * on the thread indices.
+ */
+static int compute_group_bounds_core(struct ppcg_kernel *kernel,
+	struct gpu_array_ref_group *group, struct gpu_group_data *data)
+{
+	isl_ctx *ctx = isl_space_get_ctx(group->array->space);
+	isl_union_map *access, *local;
+	int n_index = group->array->n_index;
+	int no_reuse, coalesced;
+	isl_map *acc;
+	int force_private = group->local_array->force_private;
+	int use_shared = !force_private && kernel->options->use_shared_memory &&
+				data->n_thread > 0;
+	int use_private = force_private || kernel->options->use_private_memory;
+	int r = 0;
+	int requires_unroll;
+	int unique_depth;
+
+	if (!use_shared && !use_private)
+		return 0;
+	if (gpu_array_is_read_only_scalar(group->array))
+		return 0;
+	if (!force_private && !group->exact_write)
+		return 0;
+	if (group->slice)
+		return 0;
+
+	access = gpu_array_ref_group_access_relation(group, 1, 1);
+	local = localize_access(data, isl_union_map_copy(access));
+	no_reuse = isl_union_map_is_injective(local);
+	if (no_reuse < 0)
+		r = -1;
+	if (use_shared && no_reuse)
+		coalesced = access_is_coalesced(data, local);
+	isl_union_map_free(local);
+
+	if (r >= 0 && kernel->options->debug->verbose &&
+	    use_shared && no_reuse && coalesced)
+		report_no_reuse_and_coalesced(kernel, access);
+
+	if (use_shared && (!no_reuse || !coalesced)) {
+		group->shared_tile = gpu_array_tile_create(ctx,
+							group->array->n_index);
+		acc = shared_access(group, access, data);
+		if (!group->shared_tile)
+			r = -1;
+		else if (!can_tile(acc, group->shared_tile))
+			group->shared_tile =
+					gpu_array_tile_free(group->shared_tile);
+		isl_map_free(acc);
+	}
+
+	if (r < 0 || (!force_private && (!use_private || no_reuse))) {
+		isl_union_map_free(access);
+		return r;
+	}
+
+	access = isl_union_map_apply_domain(access,
+					isl_union_map_copy(data->thread_sched));
+
+	acc = isl_map_from_union_map(access);
+
+	if (!force_private && !access_is_bijective(data, acc)) {
+		isl_map_free(acc);
+		return 0;
+	}
+
+	unique_depth = compute_accessed_by_single_thread_depth(data, acc);
+
+	acc = isl_map_intersect_domain(acc, isl_set_copy(data->privatization));
+	acc = isl_map_project_out(acc, isl_dim_in, data->thread_depth,
+								data->n_thread);
+	requires_unroll = check_requires_unroll(data, acc, force_private);
+	if (unique_depth < 0 || requires_unroll < 0 ||
+	    (requires_unroll && kernel->any_force_private)) {
+		isl_map_free(acc);
+		return requires_unroll < 0 ? -1 : 0;
+	}
+
+	group->private_tile = gpu_array_tile_create(ctx, n_index);
+	if (!group->private_tile) {
+		isl_map_free(acc);
+		return -1;
+	}
+	group->private_tile->requires_unroll = requires_unroll;
+	if (!can_tile(acc, group->private_tile))
+		group->private_tile = gpu_array_tile_free(group->private_tile);
+
+	isl_map_free(acc);
+
+	if (group->private_tile) {
+		struct gpu_array_tile *tile = group->private_tile;
+		int tile_depth = compute_tile_depth(data, tile);
+		if (tile_depth < unique_depth)
+			tile_depth = unique_depth;
+		if (tile_adjust_depth(tile, tile_depth) < 0)
+			return -1;
+	}
+
+	if (force_private && !group->private_tile)
+		isl_die(ctx, isl_error_internal,
+			"unable to map array reference group to registers",
+			return -1);
+
+	return 0;
+}
+
+/* Compute the private and/or shared memory tiles for the array
+ * reference group "group" of array "array" and set the tile depth.
+ * Return 0 on success and -1 on error.
+ */
+static int compute_group_bounds(struct ppcg_kernel *kernel,
+	struct gpu_array_ref_group *group, struct gpu_group_data *data)
+{
+	if (!group)
+		return -1;
+	if (compute_group_bounds_core(kernel, group, data) < 0)
+		return -1;
+	if (set_depth(data, group) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* If two groups have overlapping access relations (as determined by
+ * the "overlap" function) and if one of them involves a write,
+ * then merge the two groups into one.
+ * If "compute_bounds" is set, then call compute_group_bounds
+ * on the merged groups.
+ *
+ * Return the updated number of groups.
+ * Return -1 on error.
+ */
+static int group_writes(struct ppcg_kernel *kernel,
+	int n, struct gpu_array_ref_group **groups,
+	int (*overlap)(struct gpu_array_ref_group *group1,
+		struct gpu_array_ref_group *group2), int compute_bounds,
+	struct gpu_group_data *data)
+{
+	int i, j;
+
+	for (i = 0; i < n; ++i) {
+		for (j = n - 1; j > i; --j) {
+			if (!groups[i]->write && !groups[j]->write)
+				continue;
+
+			if (!overlap(groups[i], groups[j]))
+				continue;
+
+			groups[i] = join_groups_and_free(groups[i], groups[j]);
+			if (j != n - 1)
+				groups[j] = groups[n - 1];
+			groups[n - 1] = NULL;
+			n--;
+
+			if (!groups[i])
+				return -1;
+			if (compute_bounds &&
+			    compute_group_bounds(kernel, groups[i], data) < 0)
+				return -1;
+		}
+	}
+
+	return n;
+}
+
+/* If two groups have overlapping access relations (within the innermost
+ * loop) and if one of them involves a write, then merge the two groups
+ * into one.
+ *
+ * Return the updated number of groups.
+ */
+static int group_overlapping_writes(struct ppcg_kernel *kernel,
+	int n, struct gpu_array_ref_group **groups,
+	struct gpu_group_data *data)
+{
+	return group_writes(kernel, n, groups, &accesses_overlap, 0, data);
+}
+
+/* Check if the access relations of group1 and group2 overlap within
+ * the outermost min(group1->min_depth, group2->min_depth) loops.
+ */
+static int depth_accesses_overlap(struct gpu_array_ref_group *group1,
+	struct gpu_array_ref_group *group2)
+{
+	int depth;
+	int dim;
+	int empty;
+	isl_map *map_i, *map_j, *map;
+
+	depth = group1->min_depth;
+	if (group2->min_depth < depth)
+		depth = group2->min_depth;
+	map_i = isl_map_copy(group1->access);
+	dim = isl_map_dim(map_i, isl_dim_in);
+	map_i = isl_map_eliminate(map_i, isl_dim_in, depth, dim - depth);
+	map_j = isl_map_copy(group2->access);
+	map_j = isl_map_eliminate(map_j, isl_dim_in, depth, dim - depth);
+	map = isl_map_intersect(map_i, map_j);
+	empty = isl_map_is_empty(map);
+	isl_map_free(map);
+
+	return !empty;
+}
+
+/* If two groups have overlapping access relations (within the outer
+ * depth loops) and if one of them involves a write,
+ * then merge the two groups into one.
+ *
+ * Return the updated number of groups.
+ */
+static int group_depth_overlapping_writes(struct ppcg_kernel *kernel,
+	int n, struct gpu_array_ref_group **groups, struct gpu_group_data *data)
+{
+	return group_writes(kernel, n, groups, &depth_accesses_overlap, 1,
+				data);
+}
+
+/* Is the size of the tile specified by "tile" smaller than the sum of
+ * the sizes of the tiles specified by "tile1" and "tile2"?
+ */
+static int smaller_tile(struct gpu_array_tile *tile,
+	struct gpu_array_tile *tile1, struct gpu_array_tile *tile2)
+{
+	int smaller;
+	isl_val *size, *size1, *size2;
+
+	size = gpu_array_tile_size(tile);
+	size1 = gpu_array_tile_size(tile1);
+	size2 = gpu_array_tile_size(tile2);
+
+	size = isl_val_sub(size, size1);
+	size = isl_val_sub(size, size2);
+	smaller = isl_val_is_neg(size);
+
+	isl_val_free(size);
+
+	return smaller;
+}
+
+/* Given an initial grouping of array references and shared memory tiles
+ * for each group that allows for a shared memory tile, merge two groups
+ * if both have a shared memory tile, the merged group also has
+ * a shared memory tile and the size of the tile for the merge group
+ * is smaller than the sum of the tile sizes of the individual groups.
+ *
+ * If merging two groups decreases the depth of the tile of
+ * one or both of the two groups, then we need to check for overlapping
+ * writes again.
+ *
+ * Return the number of groups after merging.
+ * Return -1 on error.
+ */
+static int group_common_shared_memory_tile(struct ppcg_kernel *kernel,
+	struct gpu_array_info *array, int n,
+	struct gpu_array_ref_group **groups, struct gpu_group_data *data)
+{
+	int i, j;
+	int recompute_overlap = 0;
+
+	for (i = 0; i < n; ++i) {
+		if (!groups[i]->shared_tile)
+			continue;
+		for (j = n - 1; j > i; --j) {
+			struct gpu_array_ref_group *group;
+
+			if (!groups[j]->shared_tile)
+				continue;
+
+			if (!depth_accesses_overlap(groups[i], groups[j]))
+				continue;
+
+			group = join_groups(groups[i], groups[j]);
+			if (compute_group_bounds(kernel, group, data) < 0) {
+				gpu_array_ref_group_free(group);
+				return -1;
+			}
+			if (!group->shared_tile ||
+			    !smaller_tile(group->shared_tile,
+					groups[i]->shared_tile,
+					groups[j]->shared_tile)) {
+				gpu_array_ref_group_free(group);
+				continue;
+			}
+
+			if (group->min_depth < groups[i]->min_depth ||
+			    group->min_depth < groups[j]->min_depth)
+				recompute_overlap = 1;
+			gpu_array_ref_group_free(groups[i]);
+			gpu_array_ref_group_free(groups[j]);
+			groups[i] = group;
+			if (j != n - 1)
+				groups[j] = groups[n - 1];
+			n--;
+		}
+	}
+
+	if (recompute_overlap)
+		n = group_depth_overlapping_writes(kernel, n, groups, data);
+	return n;
+}
+
+/* Set array->n_group and array->groups to n and groups.
+ *
+ * Additionally, set the "nr" field of each group.
+ */
+static void set_array_groups(struct gpu_local_array_info *array,
+	int n, struct gpu_array_ref_group **groups)
+{
+	int i;
+
+	array->n_group = n;
+	array->groups = groups;
+
+	for (i = 0; i < n; ++i)
+		groups[i]->nr = i;
+}
+
+/* Combine all groups in "groups" into a single group and return
+ * the new number of groups (1 or 0 if there were no groups to start with).
+ */
+static int join_all_groups(int n, struct gpu_array_ref_group **groups)
+{
+	int i;
+
+	for (i = n - 1; i > 0; --i) {
+		groups[0] = join_groups_and_free(groups[0], groups[i]);
+		groups[i] = NULL;
+		n--;
+	}
+
+	return n;
+}
+
+/* Group array references that should be considered together when
+ * deciding whether to access them from private, shared or global memory.
+ * Return -1 on error.
+ *
+ * In particular, if two array references overlap and if one of them
+ * is a write, then the two references are grouped together.
+ * We first perform an initial grouping based only on the access relation.
+ * After computing shared and private memory tiles, we check for
+ * overlapping writes again, but this time taking into account
+ * the depth of the effective tile.
+ *
+ * Furthermore, if two groups admit a shared memory tile and if the
+ * combination of the two also admits a shared memory tile, we merge
+ * the two groups.
+ *
+ * If the array contains structures, then we compute a single
+ * reference group without trying to find any tiles
+ * since we do not map such arrays to private or shared
+ * memory.  The only exception is when those arrays of structures
+ * are required to be mapped to private memory.
+ */
+static int group_array_references(struct ppcg_kernel *kernel,
+	struct gpu_local_array_info *local, struct gpu_group_data *data)
+{
+	int i;
+	int n;
+	isl_ctx *ctx = isl_union_map_get_ctx(data->shared_sched);
+	struct gpu_array_ref_group **groups;
+
+	groups = isl_calloc_array(ctx, struct gpu_array_ref_group *,
+					local->array->n_ref);
+	if (!groups)
+		return -1;
+
+	n = populate_array_references(local, groups, data);
+
+	if (local->array->has_compound_element && !local->force_private) {
+		n = join_all_groups(n, groups);
+		set_array_groups(local, n, groups);
+		return 0;
+	}
+
+	n = group_overlapping_writes(kernel, n, groups, data);
+
+	for (i = 0; i < n; ++i)
+		if (compute_group_bounds(kernel, groups[i], data) < 0)
+			n = -1;
+
+	n = group_depth_overlapping_writes(kernel, n, groups, data);
+
+	n = group_common_shared_memory_tile(kernel, local->array,
+					    n, groups, data);
+
+	set_array_groups(local, n, groups);
+
+	if (n >= 0)
+		return 0;
+
+	for (i = 0; i < local->array->n_ref; ++i)
+		gpu_array_ref_group_free(groups[i]);
+	return -1;
+}
+
+/* For each array in the input program that can be mapped to private memory,
+ * check if there are any order dependences active inside the current kernel,
+ * within the same iteration of the host schedule, i.e., the prefix
+ * schedule at "node".
+ * If so, mark the array as force_private so that its reference groups will be
+ * mapped to a registers.
+ *
+ * Note that the arrays that cannot be mapped to private memory have
+ * had their order dependences added to prog->array_order and
+ * subsequently to the coincidence constraints.
+ */
+static void check_can_be_private_live_ranges(struct ppcg_kernel *kernel,
+	__isl_keep isl_schedule_node *node)
+{
+	int i;
+	isl_union_set *domain;
+	isl_multi_union_pw_aff *prefix;
+	isl_union_pw_multi_aff *contraction;
+
+	if (!kernel->options->live_range_reordering)
+		return;
+
+	kernel->any_force_private = 0;
+
+	prefix = isl_schedule_node_get_prefix_schedule_multi_union_pw_aff(node);
+	contraction = isl_union_pw_multi_aff_copy(kernel->contraction);
+	prefix = isl_multi_union_pw_aff_pullback_union_pw_multi_aff(prefix,
+								contraction);
+	domain = isl_union_set_copy(kernel->expanded_domain);
+	domain = isl_union_set_universe(domain);
+
+	for (i = 0; i < kernel->n_array; ++i) {
+		struct gpu_local_array_info *local = &kernel->array[i];
+		isl_union_map *order;
+
+		local->force_private = 0;
+		if (!gpu_array_can_be_private(local->array))
+			continue;
+		order = isl_union_map_copy(local->array->dep_order);
+		order = isl_union_map_intersect_domain(order,
+						    isl_union_set_copy(domain));
+		order = isl_union_map_intersect_range(order,
+						    isl_union_set_copy(domain));
+		order = isl_union_map_eq_at_multi_union_pw_aff(order,
+					isl_multi_union_pw_aff_copy(prefix));
+		if (!isl_union_map_is_empty(order)) {
+			local->force_private = 1;
+			kernel->any_force_private = 1;
+		}
+		isl_union_map_free(order);
+	}
+
+	isl_multi_union_pw_aff_free(prefix);
+	isl_union_set_free(domain);
+}
+
+/* Expand the domain of the schedule "s" by plugging in
+ * the contraction "contraction" and return the result.
+ */
+static __isl_give isl_union_map *expand(__isl_take isl_union_map *s,
+	__isl_keep isl_union_pw_multi_aff *contraction)
+{
+	contraction = isl_union_pw_multi_aff_copy(contraction);
+	s = isl_union_map_preimage_domain_union_pw_multi_aff(s, contraction);
+	return s;
+}
+
+/* Create a set of dimension data->thread_depth + data->n_thread
+ * that equates the residue of the final data->n_thread dimensions
+ * modulo the kernel->block_dim sizes to the thread identifiers.
+ * Store the computed set in data->privatization.
+ *
+ * The construction starts with the space of kernel->thread_filter,
+ * which is known to reference all thread identifiers.
+ */
+static void compute_privatization(struct gpu_group_data *data,
+	struct ppcg_kernel *kernel)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_space *space;
+	isl_local_space *ls;
+	isl_set *set;
+
+	ctx = isl_union_map_get_ctx(data->shared_sched);
+	space = isl_union_set_get_space(kernel->thread_filter);
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set,
+				    data->thread_depth + data->n_thread);
+	set = isl_set_universe(space);
+	space = isl_set_get_space(set);
+	ls = isl_local_space_from_space(space);
+
+	for (i = 0; i < data->n_thread; ++i) {
+		isl_aff *aff, *aff2;
+		isl_constraint *c;
+		isl_val *v;
+		isl_id *id;
+		int pos;
+
+		aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
+					isl_dim_set, data->thread_depth + i);
+		v = isl_val_int_from_si(ctx, kernel->block_dim[i]);
+		aff = isl_aff_mod_val(aff, v);
+		id = isl_id_list_get_id(kernel->thread_ids, i);
+		pos = isl_set_find_dim_by_id(set, isl_dim_param, id);
+		isl_id_free(id);
+		aff2 = isl_aff_var_on_domain(isl_local_space_copy(ls),
+					isl_dim_param, pos);
+		aff = isl_aff_sub(aff, aff2);
+		c = isl_equality_from_aff(aff);
+		set = isl_set_add_constraint(set, c);
+	}
+
+	isl_local_space_free(ls);
+	data->privatization = set;
+}
+
+/* Return the prefix schedule at "node" as a relation
+ * between domain elements and schedule dimensions after detecting
+ * equalities in this relation.
+ */
+static __isl_give isl_union_map *prefix_with_equalities(
+	__isl_keep isl_schedule_node *node)
+{
+	isl_union_map *schedule;
+
+	schedule = isl_schedule_node_get_prefix_schedule_relation(node);
+	schedule = isl_union_map_detect_equalities(schedule);
+
+	return schedule;
+}
+
+/* Group references of all arrays in "kernel".
+ * "node" points to the kernel mark.
+ * The mapping to shared memory in computed at the "shared" mark.
+ *
+ * We first extract all required schedule information into
+ * a gpu_group_data structure and then consider each array
+ * in turn.
+ */
+int gpu_group_references(struct ppcg_kernel *kernel,
+	__isl_keep isl_schedule_node *node)
+{
+	int i;
+	int r = 0;
+	isl_union_pw_multi_aff *contraction;
+	struct gpu_group_data data;
+
+	check_can_be_private_live_ranges(kernel, node);
+
+	data.scop = kernel->prog->scop;
+
+	data.kernel_depth = isl_schedule_node_get_schedule_depth(node);
+	data.host_sched = isl_schedule_node_get_prefix_schedule_relation(node);
+
+	node = isl_schedule_node_copy(node);
+	node = gpu_tree_move_down_to_shared(node, kernel->core);
+	data.shared_depth = isl_schedule_node_get_schedule_depth(node);
+	data.shared_sched = prefix_with_equalities(node);
+
+	node = gpu_tree_move_down_to_thread(node, kernel->core);
+	node = isl_schedule_node_child(node, 0);
+	data.thread_depth = isl_schedule_node_get_schedule_depth(node);
+	data.n_thread = isl_schedule_node_band_n_member(node);
+	if (data.thread_depth == data.shared_depth)
+		data.copy_sched = isl_union_map_copy(data.shared_sched);
+	else
+		data.copy_sched = prefix_with_equalities(node);
+	data.thread_sched = isl_union_map_copy(data.copy_sched);
+	data.thread_sched = isl_union_map_flat_range_product(data.thread_sched,
+		isl_schedule_node_band_get_partial_schedule_union_map(node));
+	data.thread_sched = isl_union_map_detect_equalities(data.thread_sched);
+
+	contraction = isl_union_pw_multi_aff_copy(kernel->contraction);
+	data.host_sched = expand(data.host_sched, contraction);
+	data.shared_sched = expand(data.shared_sched, contraction);
+	if (data.thread_depth == data.shared_depth) {
+		isl_union_map_free(data.copy_sched);
+		data.copy_sched = isl_union_map_copy(data.shared_sched);
+	} else {
+		data.copy_sched = expand(data.copy_sched, contraction);
+	}
+	data.thread_sched = expand(data.thread_sched, contraction);
+	isl_union_pw_multi_aff_free(contraction);
+
+	node = isl_schedule_node_child(node, 0);
+	data.full_sched = isl_union_map_copy(data.thread_sched);
+	data.full_sched = isl_union_map_flat_range_product(data.full_sched,
+		isl_schedule_node_get_subtree_schedule_union_map(node));
+	isl_schedule_node_free(node);
+
+	compute_privatization(&data, kernel);
+
+	for (i = 0; i < kernel->n_array; ++i) {
+		r = group_array_references(kernel, &kernel->array[i], &data);
+		if (r < 0)
+			break;
+	}
+
+	isl_union_map_free(data.host_sched);
+	isl_union_map_free(data.shared_sched);
+	isl_union_map_free(data.copy_sched);
+	isl_union_map_free(data.thread_sched);
+	isl_union_map_free(data.full_sched);
+	isl_set_free(data.privatization);
+
+	return r;
+}
+
+/* Given a description of an array tile "tile" and the "space"
+ *
+ *	{ D -> A }
+ *
+ * where D represents the first tile->depth schedule dimensions
+ * and A represents the array, construct an isl_multi_aff
+ *
+ *	{ [D[i] -> A[a]] -> A'[a'] }
+ *
+ * with A' a scaled down copy of A according to the shifts and strides
+ * in "tile".  In particular,
+ *
+ *	a' = (a + shift(i))/stride
+ *
+ * "insert_array" represents
+ *
+ *	{ [D -> A] -> D }
+ *
+ * and is used to insert A into the domain of functions that only
+ * reference D.
+ */
+static __isl_give isl_multi_aff *strided_tile(
+	struct gpu_array_tile *tile, __isl_keep isl_space *space,
+	__isl_keep isl_multi_aff *insert_array)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_multi_aff *shift;
+	isl_multi_val *stride;
+	isl_space *space2;
+	isl_local_space *ls;
+	isl_multi_aff *tiling;
+
+	ctx = isl_space_get_ctx(space);
+	space2 = isl_space_domain(isl_space_copy(space));
+	ls = isl_local_space_from_space(space2);
+	space2 = isl_space_range(isl_space_copy(space));
+	stride = isl_multi_val_zero(space2);
+	shift = isl_multi_aff_zero(isl_space_copy(space));
+
+	for (i = 0; i < tile->n; ++i) {
+		struct gpu_array_bound *bound = &tile->bound[i];
+		isl_val *stride_i;
+		isl_aff *shift_i;
+
+		if (tile->bound[i].shift) {
+			stride_i = isl_val_copy(bound->stride);
+			shift_i = isl_aff_copy(bound->shift);
+		} else {
+			stride_i = isl_val_one(ctx);
+			shift_i = isl_aff_zero_on_domain(
+					isl_local_space_copy(ls));
+		}
+
+		stride = isl_multi_val_set_val(stride, i, stride_i);
+		shift = isl_multi_aff_set_aff(shift, i, shift_i);
+	}
+	isl_local_space_free(ls);
+
+	shift = isl_multi_aff_pullback_multi_aff(shift,
+				    isl_multi_aff_copy(insert_array));
+
+	tiling = isl_multi_aff_range_map(isl_space_copy(space));
+	tiling = isl_multi_aff_add(tiling, shift);
+	tiling = isl_multi_aff_scale_down_multi_val(tiling, stride);
+
+	return tiling;
+}
+
+/* Compute a tiling for the array reference group "group".
+ *
+ * The tiling is of the form
+ *
+ *	{ [D[i] -> A[a]] -> T[t] }
+ *
+ * where D represents the first tile->depth schedule dimensions,
+ * A represents the global array and T represents the shared or
+ * private memory tile.  The name of T is the name of the local
+ * array.
+ *
+ * If there is any stride in the accesses, then the mapping is
+ *
+ *	t = (a + shift(i))/stride - lb(i)
+ *
+ * otherwise, it is simply
+ *
+ *	t = a - lb(i)
+ */
+void gpu_array_ref_group_compute_tiling(struct gpu_array_ref_group *group)
+{
+	int i;
+	struct gpu_array_tile *tile;
+	isl_space *space;
+	isl_multi_aff *tiling, *lb, *insert_array;
+	isl_printer *p;
+	char *local_name;
+
+	tile = gpu_array_ref_group_tile(group);
+	if (!tile)
+		return;
+
+	space = isl_map_get_space(group->access);
+	space = isl_space_from_range(isl_space_range(space));
+	space = isl_space_add_dims(space, isl_dim_in, tile->depth);
+	insert_array = isl_multi_aff_domain_map(isl_space_copy(space));
+
+	for (i = 0; i < tile->n; ++i)
+		if (tile->bound[i].shift)
+			break;
+
+	if (i < tile->n)
+		tiling = strided_tile(tile, space, insert_array);
+	else
+		tiling = isl_multi_aff_range_map(isl_space_copy(space));
+
+	lb = isl_multi_aff_zero(space);
+	for (i = 0; i < tile->n; ++i) {
+		isl_aff *lb_i = isl_aff_copy(tile->bound[i].lb);
+		lb = isl_multi_aff_set_aff(lb, i, lb_i);
+	}
+	lb = isl_multi_aff_pullback_multi_aff(lb, insert_array);
+
+	tiling = isl_multi_aff_sub(tiling, lb);
+
+	p = isl_printer_to_str(isl_multi_aff_get_ctx(tiling));
+	p = gpu_array_ref_group_print_name(group, p);
+	local_name = isl_printer_get_str(p);
+	isl_printer_free(p);
+	tiling = isl_multi_aff_set_tuple_name(tiling, isl_dim_out, local_name);
+	free(local_name);
+
+	tile->tiling = tiling;
+}
diff --git a/final/lib/External/ppcg/gpu_group.h b/final/lib/External/ppcg/gpu_group.h
new file mode 100644
index 0000000..c94812d
--- /dev/null
+++ b/final/lib/External/ppcg/gpu_group.h
@@ -0,0 +1,65 @@
+#ifndef GPU_GROUP_H
+#define GPU_GROUP_H
+
+#include <isl/schedule_node.h>
+#include "gpu.h"
+
+/* A group of array references in a kernel that should be handled together.
+ * If private_tile is not NULL, then it is mapped to registers.
+ * Otherwise, if shared_tile is not NULL, it is mapped to shared memory.
+ * Otherwise, it is accessed from global memory.
+ * Note that if both private_tile and shared_tile are set, then shared_tile
+ * is only used inside group_common_shared_memory_tile.
+ */
+struct gpu_array_ref_group {
+	/* The references in this group access this local array. */
+	struct gpu_local_array_info *local_array;
+	/* This is the corresponding array. */
+	struct gpu_array_info *array;
+	/* Position of this group in the list of reference groups of array. */
+	int nr;
+
+	/* The following fields are use during the construction of the groups.
+	 * access is the combined access relation relative to the private
+	 * memory tiling.  In particular, the domain of the map corresponds
+	 * to the first thread_depth dimensions of the kernel schedule.
+	 * write is set if any access in the group is a write.
+	 * exact_write is set if all writes are definite writes.
+	 * slice is set if there is at least one access in the group
+	 * that refers to more than one element
+	 * "min_depth" is the minimum of the tile depths and thread_depth.
+	 */
+	isl_map *access;
+	int write;
+	int exact_write;
+	int slice;
+	int min_depth;
+
+	/* The shared memory tile, NULL if none. */
+	struct gpu_array_tile *shared_tile;
+
+	/* The private memory tile, NULL if none. */
+	struct gpu_array_tile *private_tile;
+
+	/* References in this group; point to elements of a linked list. */
+	int n_ref;
+	struct gpu_stmt_access **refs;
+};
+
+int gpu_group_references(struct ppcg_kernel *kernel,
+	__isl_keep isl_schedule_node *node);
+
+__isl_give isl_printer *gpu_array_ref_group_print_name(
+	struct gpu_array_ref_group *group, __isl_take isl_printer *p);
+void gpu_array_ref_group_compute_tiling(struct gpu_array_ref_group *group);
+__isl_give isl_union_map *gpu_array_ref_group_access_relation(
+	struct gpu_array_ref_group *group, int read, int write);
+int gpu_array_ref_group_requires_unroll(struct gpu_array_ref_group *group);
+enum ppcg_group_access_type gpu_array_ref_group_type(
+	struct gpu_array_ref_group *group);
+struct gpu_array_tile *gpu_array_ref_group_tile(
+	struct gpu_array_ref_group *group);
+struct gpu_array_ref_group *gpu_array_ref_group_free(
+	struct gpu_array_ref_group *group);
+
+#endif
diff --git a/final/lib/External/ppcg/gpu_hybrid.c b/final/lib/External/ppcg/gpu_hybrid.c
new file mode 100644
index 0000000..f1b8af3
--- /dev/null
+++ b/final/lib/External/ppcg/gpu_hybrid.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2013      Ecole Normale Superieure
+ * Copyright 2015      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <string.h>
+
+#include <isl/val.h>
+#include <isl/space.h>
+#include <isl/union_set.h>
+#include <isl/schedule_node.h>
+
+#include "hybrid.h"
+#include "gpu_hybrid.h"
+#include "gpu_tree.h"
+#include "schedule.h"
+#include "util.h"
+
+/* Have all domain elements been filtered out before reaching
+ * the "node" position in the schedule tree?
+ */
+static isl_bool has_empty_domain(__isl_keep isl_schedule_node *node)
+{
+	isl_union_set *domain;
+	isl_bool empty;
+
+	domain = isl_schedule_node_get_domain(node);
+	empty = isl_union_set_is_empty(domain);
+	isl_union_set_free(domain);
+
+	return empty;
+}
+
+/* Given a pointer to a phase in the result of hybrid tiling,
+ * map the phase to the device, provided the phase is non-empty.
+ * Empty phases can occur if the input schedule domain can be
+ * covered by a small number of hexagons that all belong to the same phase.
+ *
+ * The input has the following form:
+ *
+ *	M - CT - P - C - ...
+ *
+ * with M the phase marker, CT the space tiling, P the original
+ * parent band and C the original child band.
+ * The (outer dimensions of the) C band need to be mapped to threads.
+ * The (outer dimension of the) CT band needs to be mapped to blocks.
+ * The mapping to shared memory needs to be computed between the CT and
+ * the P band.
+ *
+ * The C band is first shifted to start at zero.
+ * Then the appropriate markers are introduced and a kernel is
+ * created for the tree rooted at CT.
+ * If the "unroll_gpu_tile" option is set, then the AST generator
+ * is instructed to unroll the P and C bands.
+ */
+static __isl_give isl_schedule_node *update_phase(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	struct gpu_gen *gen = user;
+	int depth0, depth;
+	isl_ctx *ctx;
+	isl_id *id;
+	isl_bool empty_domain;
+	ppcg_ht_phase *phase;
+
+	empty_domain = has_empty_domain(node);
+	if (empty_domain < 0)
+		return isl_schedule_node_free(node);
+	if (empty_domain)
+		return node;
+
+	if (!node)
+		return NULL;
+	ctx = isl_schedule_node_get_ctx(node);
+
+	phase = ppcg_ht_phase_extract_from_mark(node);
+
+	depth0 = isl_schedule_node_get_tree_depth(node);
+
+	node = isl_schedule_node_child(node, 0);
+
+	node = isl_schedule_node_child(node, 0);
+	node = isl_schedule_node_child(node, 0);
+	node = ppcg_ht_phase_shift_space_point(phase, node);
+	if (gen->options->unroll_gpu_tile)
+		node = ppcg_set_schedule_node_type(node, isl_ast_loop_unroll);
+	id = isl_id_alloc(ctx, "thread", NULL);
+	node = isl_schedule_node_insert_mark(node, id);
+	node = isl_schedule_node_parent(node);
+	if (gen->options->unroll_gpu_tile)
+		node = ppcg_set_schedule_node_type(node, isl_ast_loop_unroll);
+	id = isl_id_alloc(ctx, "shared", NULL);
+	node = isl_schedule_node_insert_mark(node, id);
+	node = isl_schedule_node_parent(node);
+
+	node = gpu_create_kernel(gen, node, 0, NULL);
+
+	depth = isl_schedule_node_get_tree_depth(node);
+	node = isl_schedule_node_ancestor(node, depth - depth0);
+
+	return node;
+}
+
+/* Apply hybrid tiling on "node" and its parent based on the (valid)
+ * bounds on the relative dependence distances "bounds" and
+ * the tile sizes in "tile_sizes".
+ * The number of elements in "tile_sizes" is at least as large
+ * as the sum of the dimensions of the parent and the child node.
+ *
+ * Convert the tile_sizes to an isl_multi_val in the right space,
+ * insert the hybrid tiling and then create a kernel inside each phase.
+ * Finally, remove the phase marks.
+ */
+__isl_give isl_schedule_node *gpu_hybrid_tile(struct gpu_gen *gen,
+	__isl_take isl_schedule_node *node, __isl_take ppcg_ht_bounds *bounds,
+	int *tile_sizes)
+{
+	isl_multi_val *mv;
+	isl_space *space, *space2;
+
+	if (!node || !bounds)
+		goto error;
+
+	space2 = isl_schedule_node_band_get_space(node);
+	node = isl_schedule_node_parent(node);
+	space = isl_schedule_node_band_get_space(node);
+	space = isl_space_product(space, space2);
+	mv = ppcg_multi_val_from_int_list(space, tile_sizes);
+
+	node = ppcg_ht_bounds_insert_tiling(bounds, mv, node, gen->options);
+
+	node = hybrid_tile_foreach_phase(node, &update_phase, gen);
+
+	node = hybrid_tile_drop_phase_marks(node);
+
+	return node;
+error:
+	isl_schedule_node_free(node);
+	ppcg_ht_bounds_free(bounds);
+	return NULL;
+}
diff --git a/final/lib/External/ppcg/gpu_hybrid.h b/final/lib/External/ppcg/gpu_hybrid.h
new file mode 100644
index 0000000..0348261
--- /dev/null
+++ b/final/lib/External/ppcg/gpu_hybrid.h
@@ -0,0 +1,13 @@
+#ifndef GPU_HYBRID_H
+#define GPU_HYBRID_H
+
+#include <isl/schedule_node.h>
+
+#include "gpu.h"
+#include "hybrid.h"
+
+__isl_give isl_schedule_node *gpu_hybrid_tile(struct gpu_gen *gen,
+	__isl_take isl_schedule_node *node, __isl_take ppcg_ht_bounds *bounds,
+	int *tile_sizes);
+
+#endif
diff --git a/final/lib/External/ppcg/gpu_print.c b/final/lib/External/ppcg/gpu_print.c
new file mode 100644
index 0000000..a1ae968
--- /dev/null
+++ b/final/lib/External/ppcg/gpu_print.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2012      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <string.h>
+
+#include <isl/aff.h>
+
+#include "gpu_print.h"
+#include "print.h"
+#include "schedule.h"
+
+/* Print declarations to "p" for arrays that are local to "prog"
+ * but that are used on the host and therefore require a declaration.
+ */
+__isl_give isl_printer *gpu_print_local_declarations(__isl_take isl_printer *p,
+	struct gpu_prog *prog)
+{
+	int i;
+
+	if (!prog)
+		return isl_printer_free(p);
+
+	for (i = 0; i < prog->n_array; ++i) {
+		struct gpu_array_info *array = &prog->array[i];
+		isl_ast_expr *size;
+
+		if (!array->declare_local)
+			continue;
+		size = array->declared_size;
+		p = ppcg_print_declaration_with_size(p, array->type, size);
+	}
+
+	return p;
+}
+
+/* Print an expression for the size of "array" in bytes.
+ */
+__isl_give isl_printer *gpu_array_info_print_size(__isl_take isl_printer *prn,
+	struct gpu_array_info *array)
+{
+	int i;
+
+	for (i = 0; i < array->n_index; ++i) {
+		isl_ast_expr *bound;
+
+		prn = isl_printer_print_str(prn, "(");
+		bound = isl_ast_expr_get_op_arg(array->bound_expr, 1 + i);
+		prn = isl_printer_print_ast_expr(prn, bound);
+		isl_ast_expr_free(bound);
+		prn = isl_printer_print_str(prn, ") * ");
+	}
+	prn = isl_printer_print_str(prn, "sizeof(");
+	prn = isl_printer_print_str(prn, array->type);
+	prn = isl_printer_print_str(prn, ")");
+
+	return prn;
+}
+
+/* Print the declaration of a non-linearized array argument.
+ */
+static __isl_give isl_printer *print_non_linearized_declaration_argument(
+	__isl_take isl_printer *p, struct gpu_array_info *array)
+{
+	p = isl_printer_print_str(p, array->type);
+	p = isl_printer_print_str(p, " ");
+
+	p = isl_printer_print_ast_expr(p, array->bound_expr);
+
+	return p;
+}
+
+/* Print the declaration of an array argument.
+ * "memory_space" allows to specify a memory space prefix.
+ */
+__isl_give isl_printer *gpu_array_info_print_declaration_argument(
+	__isl_take isl_printer *p, struct gpu_array_info *array,
+	const char *memory_space)
+{
+	if (gpu_array_is_read_only_scalar(array)) {
+		p = isl_printer_print_str(p, array->type);
+		p = isl_printer_print_str(p, " ");
+		p = isl_printer_print_str(p, array->name);
+		return p;
+	}
+
+	if (memory_space) {
+		p = isl_printer_print_str(p, memory_space);
+		p = isl_printer_print_str(p, " ");
+	}
+
+	if (array->n_index != 0 && !array->linearize)
+		return print_non_linearized_declaration_argument(p, array);
+
+	p = isl_printer_print_str(p, array->type);
+	p = isl_printer_print_str(p, " ");
+	p = isl_printer_print_str(p, "*");
+	p = isl_printer_print_str(p, array->name);
+
+	return p;
+}
+
+/* Print the call of an array argument.
+ */
+__isl_give isl_printer *gpu_array_info_print_call_argument(
+	__isl_take isl_printer *p, struct gpu_array_info *array)
+{
+	if (gpu_array_is_read_only_scalar(array))
+		return isl_printer_print_str(p, array->name);
+
+	p = isl_printer_print_str(p, "dev_");
+	p = isl_printer_print_str(p, array->name);
+
+	return p;
+}
+
+/* Print an access to the element in the private/shared memory copy
+ * described by "stmt".  The index of the copy is recorded in
+ * stmt->local_index as an access to the array.
+ */
+static __isl_give isl_printer *stmt_print_local_index(__isl_take isl_printer *p,
+	struct ppcg_kernel_stmt *stmt)
+{
+	return isl_printer_print_ast_expr(p, stmt->u.c.local_index);
+}
+
+/* Print an access to the element in the global memory copy
+ * described by "stmt".  The index of the copy is recorded in
+ * stmt->index as an access to the array.
+ */
+static __isl_give isl_printer *stmt_print_global_index(
+	__isl_take isl_printer *p, struct ppcg_kernel_stmt *stmt)
+{
+	struct gpu_array_info *array = stmt->u.c.array;
+	isl_ast_expr *index;
+
+	if (gpu_array_is_scalar(array)) {
+		if (!gpu_array_is_read_only_scalar(array))
+			p = isl_printer_print_str(p, "*");
+		p = isl_printer_print_str(p, array->name);
+		return p;
+	}
+
+	index = isl_ast_expr_copy(stmt->u.c.index);
+
+	p = isl_printer_print_ast_expr(p, index);
+	isl_ast_expr_free(index);
+
+	return p;
+}
+
+/* Print a copy statement.
+ *
+ * A read copy statement is printed as
+ *
+ *	local = global;
+ *
+ * while a write copy statement is printed as
+ *
+ *	global = local;
+ */
+__isl_give isl_printer *ppcg_kernel_print_copy(__isl_take isl_printer *p,
+	struct ppcg_kernel_stmt *stmt)
+{
+	p = isl_printer_start_line(p);
+	if (stmt->u.c.read) {
+		p = stmt_print_local_index(p, stmt);
+		p = isl_printer_print_str(p, " = ");
+		p = stmt_print_global_index(p, stmt);
+	} else {
+		p = stmt_print_global_index(p, stmt);
+		p = isl_printer_print_str(p, " = ");
+		p = stmt_print_local_index(p, stmt);
+	}
+	p = isl_printer_print_str(p, ";");
+	p = isl_printer_end_line(p);
+
+	return p;
+}
+
+__isl_give isl_printer *ppcg_kernel_print_domain(__isl_take isl_printer *p,
+	struct ppcg_kernel_stmt *stmt)
+{
+	return pet_stmt_print_body(stmt->u.d.stmt->stmt, p, stmt->u.d.ref2expr);
+}
+
+/* This function is called for each node in a GPU AST.
+ * In case of a user node, print the macro definitions required
+ * for printing the AST expressions in the annotation, if any.
+ * For other nodes, return true such that descendants are also
+ * visited.
+ *
+ * In particular, for a kernel launch, print the macro definitions
+ * needed for the grid size.
+ * For a copy statement, print the macro definitions needed
+ * for the two index expressions.
+ * For an original user statement, print the macro definitions
+ * needed for the substitutions.
+ */
+static isl_bool at_node(__isl_keep isl_ast_node *node, void *user)
+{
+	const char *name;
+	isl_id *id;
+	int is_kernel;
+	struct ppcg_kernel *kernel;
+	struct ppcg_kernel_stmt *stmt;
+	isl_printer **p = user;
+
+	if (isl_ast_node_get_type(node) != isl_ast_node_user)
+		return isl_bool_true;
+
+	id = isl_ast_node_get_annotation(node);
+	if (!id)
+		return isl_bool_false;
+
+	name = isl_id_get_name(id);
+	if (!name)
+		return isl_bool_error;
+	is_kernel = !strcmp(name, "kernel");
+	kernel = is_kernel ? isl_id_get_user(id) : NULL;
+	stmt = is_kernel ? NULL : isl_id_get_user(id);
+	isl_id_free(id);
+
+	if ((is_kernel && !kernel) || (!is_kernel && !stmt))
+		return isl_bool_error;
+
+	if (is_kernel) {
+		*p = ppcg_ast_expr_print_macros(kernel->grid_size_expr, *p);
+	} else if (stmt->type == ppcg_kernel_copy) {
+		*p = ppcg_ast_expr_print_macros(stmt->u.c.index, *p);
+		*p = ppcg_ast_expr_print_macros(stmt->u.c.local_index, *p);
+	} else if (stmt->type == ppcg_kernel_domain) {
+		*p = ppcg_print_body_macros(*p, stmt->u.d.ref2expr);
+	}
+	if (!*p)
+		return isl_bool_error;
+
+	return isl_bool_false;
+}
+
+/* Print the required macros for the GPU AST "node" to "p",
+ * including those needed for the user statements inside the AST.
+ */
+__isl_give isl_printer *gpu_print_macros(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node)
+{
+	if (isl_ast_node_foreach_descendant_top_down(node, &at_node, &p) < 0)
+		return isl_printer_free(p);
+	p = ppcg_print_macros(p, node);
+	return p;
+}
+
+/* Was the definition of "type" printed before?
+ * That is, does its name appear in the list of printed types "types"?
+ */
+static int already_printed(struct gpu_types *types,
+	struct pet_type *type)
+{
+	int i;
+
+	for (i = 0; i < types->n; ++i)
+		if (!strcmp(types->name[i], type->name))
+			return 1;
+
+	return 0;
+}
+
+/* Print the definitions of all types prog->scop that have not been
+ * printed before (according to "types") on "p".
+ * Extend the list of printed types "types" with the newly printed types.
+ */
+__isl_give isl_printer *gpu_print_types(__isl_take isl_printer *p,
+	struct gpu_types *types, struct gpu_prog *prog)
+{
+	int i, n;
+	isl_ctx *ctx;
+	char **name;
+
+	n = prog->scop->pet->n_type;
+
+	if (n == 0)
+		return p;
+
+	ctx = isl_printer_get_ctx(p);
+	name = isl_realloc_array(ctx, types->name, char *, types->n + n);
+	if (!name)
+		return isl_printer_free(p);
+	types->name = name;
+
+	for (i = 0; i < n; ++i) {
+		struct pet_type *type = prog->scop->pet->types[i];
+
+		if (already_printed(types, type))
+			continue;
+
+		p = isl_printer_start_line(p);
+		p = isl_printer_print_str(p, type->definition);
+		p = isl_printer_print_str(p, ";");
+		p = isl_printer_end_line(p);
+
+		types->name[types->n++] = strdup(type->name);
+	}
+
+	return p;
+}
diff --git a/final/lib/External/ppcg/gpu_print.h b/final/lib/External/ppcg/gpu_print.h
new file mode 100644
index 0000000..7f07d36
--- /dev/null
+++ b/final/lib/External/ppcg/gpu_print.h
@@ -0,0 +1,28 @@
+#ifndef GPU_PRINT_H
+#define GPU_PRINT_H
+
+#include "gpu.h"
+
+__isl_give isl_printer *gpu_print_local_declarations(__isl_take isl_printer *p,
+	struct gpu_prog *prog);
+
+__isl_give isl_printer *gpu_print_types(__isl_take isl_printer *p,
+	struct gpu_types *types, struct gpu_prog *prog);
+
+__isl_give isl_printer *gpu_print_macros(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node);
+
+__isl_give isl_printer *gpu_array_info_print_size(__isl_take isl_printer *prn,
+	struct gpu_array_info *array);
+__isl_give isl_printer *gpu_array_info_print_declaration_argument(
+	__isl_take isl_printer *p, struct gpu_array_info *array,
+	const char *memory_space);
+__isl_give isl_printer *gpu_array_info_print_call_argument(
+	__isl_take isl_printer *p, struct gpu_array_info *array);
+
+__isl_give isl_printer *ppcg_kernel_print_copy(__isl_take isl_printer *p,
+	struct ppcg_kernel_stmt *stmt);
+__isl_give isl_printer *ppcg_kernel_print_domain(__isl_take isl_printer *p,
+	struct ppcg_kernel_stmt *stmt);
+
+#endif
diff --git a/final/lib/External/ppcg/gpu_tree.c b/final/lib/External/ppcg/gpu_tree.c
new file mode 100644
index 0000000..918bc0b
--- /dev/null
+++ b/final/lib/External/ppcg/gpu_tree.c
@@ -0,0 +1,639 @@
+/*
+ * Copyright 2013      Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <string.h>
+
+#include <isl/set.h>
+#include <isl/union_set.h>
+
+#include "gpu_tree.h"
+
+/* The functions in this file are used to navigate part of a schedule tree
+ * that is mapped to blocks.  Initially, this part consists of a linear
+ * branch segment with a mark node with name "kernel" on the outer end
+ * and a mark node with name "thread" on the inner end.
+ * During the mapping to blocks, branching may be introduced, but only
+ * one of the elements in each sequence contains the "thread" mark.
+ * The filter of this element (and only this filter) contains
+ * domain elements identified by the "core" argument of the functions
+ * that move down this tree.
+ *
+ * Synchronization statements have a name that starts with "sync" and
+ * a user pointer pointing to the kernel that contains the synchronization.
+ * The functions inserting or detecting synchronizations take a ppcg_kernel
+ * argument to be able to create or identify such statements.
+ * They may also use two fields in this structure, the "core" field
+ * to move around in the tree and the "n_sync" field to make sure that
+ * each synchronization has a different name (within the kernel).
+ */
+
+/* Is "node" a mark node with an identifier called "name"?
+ */
+static int is_marked(__isl_keep isl_schedule_node *node, const char *name)
+{
+	isl_id *mark;
+	int has_name;
+
+	if (!node)
+		return -1;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_mark)
+		return 0;
+
+	mark = isl_schedule_node_mark_get_id(node);
+	if (!mark)
+		return -1;
+
+	has_name = !strcmp(isl_id_get_name(mark), name);
+	isl_id_free(mark);
+
+	return has_name;
+}
+
+/* Is "node" a mark node with an identifier called "kernel"?
+ */
+int gpu_tree_node_is_kernel(__isl_keep isl_schedule_node *node)
+{
+	return is_marked(node, "kernel");
+}
+
+/* Is "node" a mark node with an identifier called "shared"?
+ */
+static int node_is_shared(__isl_keep isl_schedule_node *node)
+{
+	return is_marked(node, "shared");
+}
+
+/* Is "node" a mark node with an identifier called "thread"?
+ */
+static int node_is_thread(__isl_keep isl_schedule_node *node)
+{
+	return is_marked(node, "thread");
+}
+
+/* Insert a mark node with identifier "shared" in front of "node".
+ */
+static __isl_give isl_schedule_node *insert_shared(
+	__isl_take isl_schedule_node *node)
+{
+	isl_ctx *ctx;
+	isl_id *id;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	id = isl_id_alloc(ctx, "shared", NULL);
+	node = isl_schedule_node_insert_mark(node, id);
+
+	return node;
+}
+
+/* Insert a "shared" mark in front of the "thread" mark
+ * provided the linear branch between "node" and the "thread" mark
+ * does not contain such a "shared" mark already.
+ *
+ * As a side effect, this function checks that the subtree at "node"
+ * actually contains a "thread" mark and that there is no branching
+ * in between "node" and this "thread" mark.
+ */
+__isl_give isl_schedule_node *gpu_tree_insert_shared_before_thread(
+	__isl_take isl_schedule_node *node)
+{
+	int depth0, depth;
+	int any_shared = 0;
+
+	if (!node)
+		return NULL;
+
+	depth0 = isl_schedule_node_get_tree_depth(node);
+
+	for (;;) {
+		int is_thread;
+		int n;
+
+		if (!any_shared) {
+			any_shared = node_is_shared(node);
+			if (any_shared < 0)
+				return isl_schedule_node_free(node);
+		}
+		is_thread = node_is_thread(node);
+		if (is_thread < 0)
+			return isl_schedule_node_free(node);
+		if (is_thread)
+			break;
+		n = isl_schedule_node_n_children(node);
+		if (n == 0)
+			isl_die(isl_schedule_node_get_ctx(node),
+				isl_error_invalid,
+				"no thread marker found",
+				return isl_schedule_node_free(node));
+		if (n > 1)
+			isl_die(isl_schedule_node_get_ctx(node),
+				isl_error_invalid,
+				"expecting single thread marker",
+				return isl_schedule_node_free(node));
+
+		node = isl_schedule_node_child(node, 0);
+	}
+
+	if (!any_shared)
+		node = insert_shared(node);
+	depth = isl_schedule_node_get_tree_depth(node);
+	node = isl_schedule_node_ancestor(node, depth - depth0);
+
+	return node;
+}
+
+/* Assuming "node" is a filter node, does it correspond to the branch
+ * that contains the "thread" mark, i.e., does it contain any elements
+ * in "core"?
+ */
+static int node_is_core(__isl_keep isl_schedule_node *node,
+	__isl_keep isl_union_set *core)
+{
+	int disjoint;
+	isl_union_set *filter;
+
+	filter = isl_schedule_node_filter_get_filter(node);
+	disjoint = isl_union_set_is_disjoint(filter, core);
+	isl_union_set_free(filter);
+	if (disjoint < 0)
+		return -1;
+
+	return !disjoint;
+}
+
+/* Move to the only child of "node" that has the "thread" mark as descendant,
+ * where the branch containing this mark is identified by the domain elements
+ * in "core".
+ *
+ * If "node" is not a sequence, then it only has one child and we move
+ * to that single child.
+ * Otherwise, we check each of the filters in the children, pick
+ * the one that corresponds to "core" and return a pointer to the child
+ * of the filter node.
+ */
+static __isl_give isl_schedule_node *core_child(
+	__isl_take isl_schedule_node *node, __isl_keep isl_union_set *core)
+{
+	int i, n;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence)
+		return isl_schedule_node_child(node, 0);
+
+	n = isl_schedule_node_n_children(node);
+	for (i = 0; i < n; ++i) {
+		int is_core;
+
+		node = isl_schedule_node_child(node, i);
+		is_core = node_is_core(node, core);
+
+		if (is_core < 0)
+			return isl_schedule_node_free(node);
+		if (is_core)
+			return isl_schedule_node_child(node, 0);
+
+		node = isl_schedule_node_parent(node);
+	}
+
+	isl_die(isl_schedule_node_get_ctx(node), isl_error_internal,
+		"core child not found", return isl_schedule_node_free(node));
+}
+
+/* Move down the branch between "kernel" and "thread" until
+ * the "shared" mark is reached, where the branch containing the "shared"
+ * mark is identified by the domain elements in "core".
+ */
+__isl_give isl_schedule_node *gpu_tree_move_down_to_shared(
+	__isl_take isl_schedule_node *node, __isl_keep isl_union_set *core)
+{
+	int is_shared;
+
+	while ((is_shared = node_is_shared(node)) == 0)
+		node = core_child(node, core);
+	if (is_shared < 0)
+		node = isl_schedule_node_free(node);
+
+	return node;
+}
+
+/* Move down the branch between "kernel" and "thread" until
+ * the "thread" mark is reached, where the branch containing the "thread"
+ * mark is identified by the domain elements in "core".
+ */
+__isl_give isl_schedule_node *gpu_tree_move_down_to_thread(
+	__isl_take isl_schedule_node *node, __isl_keep isl_union_set *core)
+{
+	int is_thread;
+
+	while ((is_thread = node_is_thread(node)) == 0)
+		node = core_child(node, core);
+	if (is_thread < 0)
+		node = isl_schedule_node_free(node);
+
+	return node;
+}
+
+/* Move up the tree underneath the "thread" mark until
+ * the "thread" mark is reached.
+ */
+__isl_give isl_schedule_node *gpu_tree_move_up_to_thread(
+	__isl_take isl_schedule_node *node)
+{
+	int is_thread;
+
+	while ((is_thread = node_is_thread(node)) == 0)
+		node = isl_schedule_node_parent(node);
+	if (is_thread < 0)
+		node = isl_schedule_node_free(node);
+
+	return node;
+}
+
+/* Move up the tree underneath the "kernel" mark until
+ * the "kernel" mark is reached.
+ */
+__isl_give isl_schedule_node *gpu_tree_move_up_to_kernel(
+	__isl_take isl_schedule_node *node)
+{
+	int is_kernel;
+
+	while ((is_kernel = gpu_tree_node_is_kernel(node)) == 0)
+		node = isl_schedule_node_parent(node);
+	if (is_kernel < 0)
+		node = isl_schedule_node_free(node);
+
+	return node;
+}
+
+/* Move down from the "kernel" mark (or at least a node with schedule
+ * depth smaller than or equal to "depth") to a band node at schedule
+ * depth "depth".  The "thread" mark is assumed to have a schedule
+ * depth greater than or equal to "depth".  The branch containing the
+ * "thread" mark is identified by the domain elements in "core".
+ *
+ * If the desired schedule depth is in the middle of band node,
+ * then the band node is split into two pieces, the second piece
+ * at the desired schedule depth.
+ */
+__isl_give isl_schedule_node *gpu_tree_move_down_to_depth(
+	__isl_take isl_schedule_node *node, int depth,
+	__isl_keep isl_union_set *core)
+{
+	int is_shared;
+	int is_thread = 0;
+
+	while (node && isl_schedule_node_get_schedule_depth(node) < depth) {
+		if (isl_schedule_node_get_type(node) ==
+						    isl_schedule_node_band) {
+			int node_depth, node_dim;
+			node_depth = isl_schedule_node_get_schedule_depth(node);
+			node_dim = isl_schedule_node_band_n_member(node);
+			if (node_depth + node_dim > depth)
+				node = isl_schedule_node_band_split(node,
+							depth - node_depth);
+		}
+		node = core_child(node, core);
+	}
+	while ((is_shared = node_is_shared(node)) == 0 &&
+	    (is_thread = node_is_thread(node)) == 0 &&
+	    isl_schedule_node_get_type(node) != isl_schedule_node_band)
+		node = core_child(node, core);
+	if (is_shared < 0 || is_thread < 0)
+		node = isl_schedule_node_free(node);
+
+	return node;
+}
+
+/* Create a union set containing a single set with a tuple identifier
+ * called "syncX" and user pointer equal to "kernel".
+ */
+static __isl_give isl_union_set *create_sync_domain(struct ppcg_kernel *kernel)
+{
+	isl_space *space;
+	isl_id *id;
+	char name[40];
+
+	space = isl_space_set_alloc(kernel->ctx, 0, 0);
+	snprintf(name, sizeof(name), "sync%d", kernel->n_sync++);
+	id = isl_id_alloc(kernel->ctx, name, kernel);
+	space = isl_space_set_tuple_id(space, isl_dim_set, id);
+	return isl_union_set_from_set(isl_set_universe(space));
+}
+
+/* Is "id" the identifier of a synchronization statement inside "kernel"?
+ * That is, does its name start with "sync" and does it point to "kernel"?
+ */
+int gpu_tree_id_is_sync(__isl_keep isl_id *id, struct ppcg_kernel *kernel)
+{
+	const char *name;
+
+	name = isl_id_get_name(id);
+	if (!name)
+		return 0;
+	else if (strncmp(name, "sync", 4))
+		return 0;
+	return isl_id_get_user(id) == kernel;
+}
+
+/* Does "domain" consist of a single set with a tuple identifier
+ * corresponding to a synchronization for "kernel"?
+ */
+static int domain_is_sync(__isl_keep isl_union_set *domain,
+	struct ppcg_kernel *kernel)
+{
+	int is_sync;
+	isl_id *id;
+	isl_set *set;
+
+	if (isl_union_set_n_set(domain) != 1)
+		return 0;
+	set = isl_set_from_union_set(isl_union_set_copy(domain));
+	id = isl_set_get_tuple_id(set);
+	is_sync = gpu_tree_id_is_sync(id, kernel);
+	isl_id_free(id);
+	isl_set_free(set);
+
+	return is_sync;
+}
+
+/* Does "node" point to a filter selecting a synchronization statement
+ * for "kernel"?
+ */
+static int node_is_sync_filter(__isl_keep isl_schedule_node *node,
+	struct ppcg_kernel *kernel)
+{
+	int is_sync;
+	enum isl_schedule_node_type type;
+	isl_union_set *domain;
+
+	if (!node)
+		return -1;
+	type = isl_schedule_node_get_type(node);
+	if (type != isl_schedule_node_filter)
+		return 0;
+	domain = isl_schedule_node_filter_get_filter(node);
+	is_sync = domain_is_sync(domain, kernel);
+	isl_union_set_free(domain);
+
+	return is_sync;
+}
+
+/* Is "node" part of a sequence with a previous synchronization statement
+ * for "kernel"?
+ * That is, is the parent of "node" a filter such that there is
+ * a previous filter that picks out exactly such a synchronization statement?
+ */
+static int has_preceding_sync(__isl_keep isl_schedule_node *node,
+	struct ppcg_kernel *kernel)
+{
+	int found = 0;
+
+	node = isl_schedule_node_copy(node);
+	node = isl_schedule_node_parent(node);
+	while (!found && isl_schedule_node_has_previous_sibling(node)) {
+		node = isl_schedule_node_previous_sibling(node);
+		if (!node)
+			break;
+		found = node_is_sync_filter(node, kernel);
+	}
+	if (!node)
+		found = -1;
+	isl_schedule_node_free(node);
+
+	return found;
+}
+
+/* Is "node" part of a sequence with a subsequent synchronization statement
+ * for "kernel"?
+ * That is, is the parent of "node" a filter such that there is
+ * a subsequent filter that picks out exactly such a synchronization statement?
+ */
+static int has_following_sync(__isl_keep isl_schedule_node *node,
+	struct ppcg_kernel *kernel)
+{
+	int found = 0;
+
+	node = isl_schedule_node_copy(node);
+	node = isl_schedule_node_parent(node);
+	while (!found && isl_schedule_node_has_next_sibling(node)) {
+		node = isl_schedule_node_next_sibling(node);
+		if (!node)
+			break;
+		found = node_is_sync_filter(node, kernel);
+	}
+	if (!node)
+		found = -1;
+	isl_schedule_node_free(node);
+
+	return found;
+}
+
+/* Does the subtree rooted at "node" (which is a band node) contain
+ * any synchronization statement for "kernel" that precedes
+ * the core computation of "kernel" (identified by the elements
+ * in kernel->core)?
+ */
+static int has_sync_before_core(__isl_keep isl_schedule_node *node,
+	struct ppcg_kernel *kernel)
+{
+	int has_sync = 0;
+	int is_thread;
+
+	node = isl_schedule_node_copy(node);
+	while ((is_thread = node_is_thread(node)) == 0) {
+		node = core_child(node, kernel->core);
+		has_sync = has_preceding_sync(node, kernel);
+		if (has_sync < 0 || has_sync)
+			break;
+	}
+	if (is_thread < 0 || !node)
+		has_sync = -1;
+	isl_schedule_node_free(node);
+
+	return has_sync;
+}
+
+/* Does the subtree rooted at "node" (which is a band node) contain
+ * any synchronization statement for "kernel" that follows
+ * the core computation of "kernel" (identified by the elements
+ * in kernel->core)?
+ */
+static int has_sync_after_core(__isl_keep isl_schedule_node *node,
+	struct ppcg_kernel *kernel)
+{
+	int has_sync = 0;
+	int is_thread;
+
+	node = isl_schedule_node_copy(node);
+	while ((is_thread = node_is_thread(node)) == 0) {
+		node = core_child(node, kernel->core);
+		has_sync = has_following_sync(node, kernel);
+		if (has_sync < 0 || has_sync)
+			break;
+	}
+	if (is_thread < 0 || !node)
+		has_sync = -1;
+	isl_schedule_node_free(node);
+
+	return has_sync;
+}
+
+/* Insert (or extend) an extension on top of "node" that puts
+ * a synchronization node for "kernel" before "node".
+ * Return a pointer to the original node in the updated schedule tree.
+ */
+static __isl_give isl_schedule_node *insert_sync_before(
+	__isl_take isl_schedule_node *node, struct ppcg_kernel *kernel)
+{
+	isl_union_set *domain;
+	isl_schedule_node *graft;
+
+	if (!node)
+		return NULL;
+
+	domain = create_sync_domain(kernel);
+	graft = isl_schedule_node_from_domain(domain);
+	node = isl_schedule_node_graft_before(node, graft);
+
+	return node;
+}
+
+/* Insert (or extend) an extension on top of "node" that puts
+ * a synchronization node for "kernel" afater "node".
+ * Return a pointer to the original node in the updated schedule tree.
+ */
+static __isl_give isl_schedule_node *insert_sync_after(
+	__isl_take isl_schedule_node *node, struct ppcg_kernel *kernel)
+{
+	isl_union_set *domain;
+	isl_schedule_node *graft;
+
+	if (!node)
+		return NULL;
+
+	domain = create_sync_domain(kernel);
+	graft = isl_schedule_node_from_domain(domain);
+	node = isl_schedule_node_graft_after(node, graft);
+
+	return node;
+}
+
+/* Insert an extension on top of "node" that puts a synchronization node
+ * for "kernel" before "node" unless there already is
+ * such a synchronization node.
+ */
+__isl_give isl_schedule_node *gpu_tree_ensure_preceding_sync(
+	__isl_take isl_schedule_node *node, struct ppcg_kernel *kernel)
+{
+	int has_sync;
+
+	has_sync = has_preceding_sync(node, kernel);
+	if (has_sync < 0)
+		return isl_schedule_node_free(node);
+	if (has_sync)
+		return node;
+	return insert_sync_before(node, kernel);
+}
+
+/* Insert an extension on top of "node" that puts a synchronization node
+ * for "kernel" after "node" unless there already is
+ * such a synchronization node.
+ */
+__isl_give isl_schedule_node *gpu_tree_ensure_following_sync(
+	__isl_take isl_schedule_node *node, struct ppcg_kernel *kernel)
+{
+	int has_sync;
+
+	has_sync = has_following_sync(node, kernel);
+	if (has_sync < 0)
+		return isl_schedule_node_free(node);
+	if (has_sync)
+		return node;
+	return insert_sync_after(node, kernel);
+}
+
+/* Insert an extension on top of "node" that puts a synchronization node
+ * for "kernel" after "node" unless there already is such a sync node or
+ * "node" itself already * contains a synchronization node following
+ * the core computation of "kernel".
+ */
+__isl_give isl_schedule_node *gpu_tree_ensure_sync_after_core(
+	__isl_take isl_schedule_node *node, struct ppcg_kernel *kernel)
+{
+	int has_sync;
+
+	has_sync = has_sync_after_core(node, kernel);
+	if (has_sync < 0)
+		return isl_schedule_node_free(node);
+	if (has_sync)
+		return node;
+	has_sync = has_following_sync(node, kernel);
+	if (has_sync < 0)
+		return isl_schedule_node_free(node);
+	if (has_sync)
+		return node;
+	return insert_sync_after(node, kernel);
+}
+
+/* Move left in the sequence on top of "node" to a synchronization node
+ * for "kernel".
+ * If "node" itself contains a synchronization node preceding
+ * the core computation of "kernel", then return "node" itself.
+ * Otherwise, if "node" does not have a preceding synchronization node,
+ * then create one first.
+ */
+__isl_give isl_schedule_node *gpu_tree_move_left_to_sync(
+	__isl_take isl_schedule_node *node, struct ppcg_kernel *kernel)
+{
+	int has_sync;
+	int is_sync;
+
+	has_sync = has_sync_before_core(node, kernel);
+	if (has_sync < 0)
+		return isl_schedule_node_free(node);
+	if (has_sync)
+		return node;
+	node = gpu_tree_ensure_preceding_sync(node, kernel);
+	node = isl_schedule_node_parent(node);
+	while ((is_sync = node_is_sync_filter(node, kernel)) == 0)
+		node = isl_schedule_node_previous_sibling(node);
+	if (is_sync < 0)
+		node = isl_schedule_node_free(node);
+	node = isl_schedule_node_child(node, 0);
+
+	return node;
+}
+
+/* Move right in the sequence on top of "node" to a synchronization node
+ * for "kernel".
+ * If "node" itself contains a synchronization node following
+ * the core computation of "kernel", then return "node" itself.
+ * Otherwise, if "node" does not have a following synchronization node,
+ * then create one first.
+ */
+__isl_give isl_schedule_node *gpu_tree_move_right_to_sync(
+	__isl_take isl_schedule_node *node, struct ppcg_kernel *kernel)
+{
+	int has_sync;
+	int is_sync;
+
+	has_sync = has_sync_after_core(node, kernel);
+	if (has_sync < 0)
+		return isl_schedule_node_free(node);
+	if (has_sync)
+		return node;
+	node = gpu_tree_ensure_following_sync(node, kernel);
+	node = isl_schedule_node_parent(node);
+	while ((is_sync = node_is_sync_filter(node, kernel)) == 0)
+		node = isl_schedule_node_next_sibling(node);
+	if (is_sync < 0)
+		node = isl_schedule_node_free(node);
+	node = isl_schedule_node_child(node, 0);
+
+	return node;
+}
diff --git a/final/lib/External/ppcg/gpu_tree.h b/final/lib/External/ppcg/gpu_tree.h
new file mode 100644
index 0000000..a2a0258
--- /dev/null
+++ b/final/lib/External/ppcg/gpu_tree.h
@@ -0,0 +1,33 @@
+#ifndef GPU_TREE_H
+#define GPU_TREE_H
+
+#include <isl/schedule_node.h>
+
+#include "gpu.h"
+
+__isl_give isl_schedule_node *gpu_tree_insert_shared_before_thread(
+	__isl_take isl_schedule_node *node);
+int gpu_tree_node_is_kernel(__isl_keep isl_schedule_node *node);
+__isl_give isl_schedule_node *gpu_tree_move_down_to_shared(
+	__isl_take isl_schedule_node *node, __isl_keep isl_union_set *core);
+__isl_give isl_schedule_node *gpu_tree_move_up_to_thread(
+	__isl_take isl_schedule_node *node);
+__isl_give isl_schedule_node *gpu_tree_move_down_to_thread(
+	__isl_take isl_schedule_node *node, __isl_keep isl_union_set *core);
+__isl_give isl_schedule_node *gpu_tree_move_up_to_kernel(
+	__isl_take isl_schedule_node *node);
+__isl_give isl_schedule_node *gpu_tree_move_down_to_depth(
+	__isl_take isl_schedule_node *node, int depth,
+	__isl_keep isl_union_set *core);
+
+int gpu_tree_id_is_sync(__isl_keep isl_id *id, struct ppcg_kernel *kernel);
+__isl_give isl_schedule_node *gpu_tree_ensure_sync_after_core(
+	__isl_take isl_schedule_node *node, struct ppcg_kernel *kernel);
+__isl_give isl_schedule_node *gpu_tree_ensure_following_sync(
+	__isl_take isl_schedule_node *node, struct ppcg_kernel *kernel);
+__isl_give isl_schedule_node *gpu_tree_move_left_to_sync(
+	__isl_take isl_schedule_node *node, struct ppcg_kernel *kernel);
+__isl_give isl_schedule_node *gpu_tree_move_right_to_sync(
+	__isl_take isl_schedule_node *node, struct ppcg_kernel *kernel);
+
+#endif
diff --git a/final/lib/External/ppcg/grouping.c b/final/lib/External/ppcg/grouping.c
new file mode 100644
index 0000000..1c98bdb
--- /dev/null
+++ b/final/lib/External/ppcg/grouping.c
@@ -0,0 +1,684 @@
+/*
+ * Copyright 2016      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege.
+ */
+
+#include <isl/ctx.h>
+#include <isl/id.h>
+#include <isl/val.h>
+#include <isl/space.h>
+#include <isl/aff.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl/schedule.h>
+#include <isl/schedule_node.h>
+
+#include "ppcg.h"
+
+/* Internal data structure for use during the detection of statements
+ * that can be grouped.
+ *
+ * "sc" contains the original schedule constraints (not a copy).
+ * "dep" contains the intersection of the validity and the proximity
+ * constraints in "sc".  It may be NULL if it has not been computed yet.
+ * "group_id" is the identifier for the next group that is extracted.
+ *
+ * "domain" is the set of statement instances that belong to any of the groups.
+ * "contraction" maps the elements of "domain" to the corresponding group
+ * instances.
+ * "schedule" schedules the statements in each group relatively to each other.
+ * These last three fields are NULL if no groups have been found so far.
+ */
+struct ppcg_grouping {
+	isl_schedule_constraints *sc;
+
+	isl_union_map *dep;
+	int group_id;
+
+	isl_union_set *domain;
+	isl_union_pw_multi_aff *contraction;
+	isl_schedule *schedule;
+};
+
+/* Clear all memory allocated by "grouping".
+ */
+static void ppcg_grouping_clear(struct ppcg_grouping *grouping)
+{
+	isl_union_map_free(grouping->dep);
+	isl_union_set_free(grouping->domain);
+	isl_union_pw_multi_aff_free(grouping->contraction);
+	isl_schedule_free(grouping->schedule);
+}
+
+/* Compute the intersection of the proximity and validity dependences
+ * in grouping->sc and store the result in grouping->dep, unless
+ * this intersection has been computed before.
+ */
+static isl_stat ppcg_grouping_compute_dep(struct ppcg_grouping *grouping)
+{
+	isl_union_map *validity, *proximity;
+
+	if (grouping->dep)
+		return isl_stat_ok;
+
+	validity = isl_schedule_constraints_get_validity(grouping->sc);
+	proximity = isl_schedule_constraints_get_proximity(grouping->sc);
+	grouping->dep = isl_union_map_intersect(validity, proximity);
+
+	if (!grouping->dep)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Information extracted from one or more consecutive leaves
+ * in the input schedule.
+ *
+ * "list" contains the sets of statement instances in the leaves,
+ * one element in the list for each original leaf.
+ * "domain" contains the union of the sets in "list".
+ * "prefix" contains the prefix schedule of these elements.
+ */
+struct ppcg_grouping_leaf {
+	isl_union_set *domain;
+	isl_union_set_list *list;
+	isl_multi_union_pw_aff *prefix;
+};
+
+/* Free all memory allocated for "leaves".
+ */
+static void ppcg_grouping_leaf_free(int n, struct ppcg_grouping_leaf leaves[])
+{
+	int i;
+
+	if (!leaves)
+		return;
+
+	for (i = 0; i < n; ++i) {
+		isl_union_set_free(leaves[i].domain);
+		isl_union_set_list_free(leaves[i].list);
+		isl_multi_union_pw_aff_free(leaves[i].prefix);
+	}
+
+	free(leaves);
+}
+
+/* Short-hand for retrieving the prefix schedule at "node"
+ * in the form of an isl_multi_union_pw_aff.
+ */
+static __isl_give isl_multi_union_pw_aff *get_prefix(
+	__isl_keep isl_schedule_node *node)
+{
+	return isl_schedule_node_get_prefix_schedule_multi_union_pw_aff(node);
+}
+
+/* Return an array of "n" elements with information extracted from
+ * the "n" children of "node" starting at "first", all of which
+ * are known to be filtered leaves.
+ */
+struct ppcg_grouping_leaf *extract_leaves(__isl_keep isl_schedule_node *node,
+	int first, int n)
+{
+	int i;
+	isl_ctx *ctx;
+	struct ppcg_grouping_leaf *leaves;
+
+	if (!node)
+		return NULL;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	leaves = isl_calloc_array(ctx, struct ppcg_grouping_leaf, n);
+	if (!leaves)
+		return NULL;
+
+	for (i = 0; i < n; ++i) {
+		isl_schedule_node *child;
+		isl_union_set *domain;
+
+		child = isl_schedule_node_get_child(node, first + i);
+		child = isl_schedule_node_child(child, 0);
+		domain = isl_schedule_node_get_domain(child);
+		leaves[i].domain = isl_union_set_copy(domain);
+		leaves[i].list = isl_union_set_list_from_union_set(domain);
+		leaves[i].prefix = get_prefix(child);
+		isl_schedule_node_free(child);
+	}
+
+	return leaves;
+}
+
+/* Internal data structure used by merge_leaves.
+ *
+ * "src" and "dst" point to the two consecutive leaves that are
+ * under investigation for being merged.
+ * "merge" is initially set to 0 and is set to 1 as soon as
+ * it turns out that it is useful to merge the two leaves.
+ */
+struct ppcg_merge_leaves_data {
+	int merge;
+	struct ppcg_grouping_leaf *src;
+	struct ppcg_grouping_leaf *dst;
+};
+
+/* Given a relation "map" between instances of two statements A and B,
+ * does it relate every instance of A (according to the domain of "src")
+ * to every instance of B (according to the domain of "dst")?
+ */
+static isl_bool covers_src_and_dst(__isl_keep isl_map *map,
+	struct ppcg_grouping_leaf *src, struct ppcg_grouping_leaf *dst)
+{
+	isl_space *space;
+	isl_set *set1, *set2;
+	isl_bool is_subset;
+
+	space = isl_space_domain(isl_map_get_space(map));
+	set1 = isl_union_set_extract_set(src->domain, space);
+	set2 = isl_map_domain(isl_map_copy(map));
+	is_subset = isl_set_is_subset(set1, set2);
+	isl_set_free(set1);
+	isl_set_free(set2);
+	if (is_subset < 0 || !is_subset)
+		return is_subset;
+
+	space = isl_space_range(isl_map_get_space(map));
+	set1 = isl_union_set_extract_set(dst->domain, space);
+	set2 = isl_map_range(isl_map_copy(map));
+	is_subset = isl_set_is_subset(set1, set2);
+	isl_set_free(set1);
+	isl_set_free(set2);
+
+	return is_subset;
+}
+
+/* Given a relation "map" between instances of two statements A and B,
+ * are pairs of related instances executed together in the input schedule?
+ * That is, is each pair of instances assigned the same value
+ * by the corresponding prefix schedules?
+ *
+ * In particular, select the subset of "map" that has pairs of elements
+ * with the same value for the prefix schedules and then check
+ * if "map" is still a subset of the result.
+ */
+static isl_bool matches_prefix(__isl_keep isl_map *map,
+	struct ppcg_grouping_leaf *src, struct ppcg_grouping_leaf *dst)
+{
+	isl_union_map *umap, *equal;
+	isl_multi_union_pw_aff *src_prefix, *dst_prefix, *prefix;
+	isl_bool is_subset;
+
+	src_prefix = isl_multi_union_pw_aff_copy(src->prefix);
+	dst_prefix = isl_multi_union_pw_aff_copy(dst->prefix);
+	prefix = isl_multi_union_pw_aff_union_add(src_prefix, dst_prefix);
+
+	umap = isl_union_map_from_map(isl_map_copy(map));
+	equal = isl_union_map_copy(umap);
+	equal = isl_union_map_eq_at_multi_union_pw_aff(equal, prefix);
+
+	is_subset = isl_union_map_is_subset(umap, equal);
+
+	isl_union_map_free(umap);
+	isl_union_map_free(equal);
+
+	return is_subset;
+}
+
+/* Given a set of validity and proximity schedule constraints "map"
+ * between statements in consecutive leaves in a valid schedule,
+ * should the two leaves be merged into one?
+ *
+ * In particular, the two are merged if the constraints form
+ * a bijection between every instance of the first statement and
+ * every instance of the second statement.  Moreover, each
+ * pair of such dependent instances needs to be executed consecutively
+ * in the input schedule.  That is, they need to be assigned
+ * the same value by their prefix schedules.
+ *
+ * What this means is that for each instance of the first statement
+ * there is exactly one instance of the second statement that
+ * is executed immediately after the instance of the first statement and
+ * that, moreover, both depends on this statement instance and
+ * should be brought as close as possible to this statement instance.
+ * In other words, it is both possible to execute the two instances
+ * together (according to the input schedule) and desirable to do so
+ * (according to the validity and proximity schedule constraints).
+ */
+static isl_stat check_merge(__isl_take isl_map *map, void *user)
+{
+	struct ppcg_merge_leaves_data *data = user;
+	isl_bool ok;
+
+	ok = covers_src_and_dst(map, data->src, data->dst);
+	if (ok >= 0 && ok)
+		ok = isl_map_is_bijective(map);
+	if (ok >= 0 && ok)
+		ok = matches_prefix(map, data->src, data->dst);
+
+	isl_map_free(map);
+
+	if (ok < 0)
+		return isl_stat_error;
+	if (!ok)
+		return isl_stat_ok;
+
+	data->merge = 1;
+	return isl_stat_error;
+}
+
+/* Merge the leaves at position "pos" and "pos + 1" in "leaves".
+ */
+static isl_stat merge_pair(int n, struct ppcg_grouping_leaf leaves[], int pos)
+{
+	int i;
+
+	leaves[pos].domain = isl_union_set_union(leaves[pos].domain,
+						leaves[pos + 1].domain);
+	leaves[pos].list = isl_union_set_list_concat(leaves[pos].list,
+						leaves[pos + 1].list);
+	leaves[pos].prefix = isl_multi_union_pw_aff_union_add(
+				leaves[pos].prefix, leaves[pos + 1].prefix);
+	for (i = pos + 1; i + 1 < n; ++i)
+		leaves[i] = leaves[i + 1];
+	leaves[n - 1].domain = NULL;
+	leaves[n - 1].list = NULL;
+	leaves[n - 1].prefix = NULL;
+
+	if (!leaves[pos].domain || !leaves[pos].list || !leaves[pos].prefix)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Merge pairs of consecutive leaves in "leaves" taking into account
+ * the intersection of validity and proximity schedule constraints "dep".
+ *
+ * If a leaf has been merged with the next leaf, then the combination
+ * is checked again for merging with the next leaf.
+ * That is, if the leaves are A, B and C, then B may not have been
+ * merged with C, but after merging A and B, it could still be useful
+ * to merge the combination AB with C.
+ *
+ * Two leaves A and B are merged if there are instances of at least
+ * one pair of statements, one statement in A and one B, such that
+ * the validity and proximity schedule constraints between them
+ * make them suitable for merging according to check_merge.
+ *
+ * Return the final number of leaves in the sequence, or -1 on error.
+ */
+static int merge_leaves(int n, struct ppcg_grouping_leaf leaves[],
+	__isl_keep isl_union_map *dep)
+{
+	int i;
+	struct ppcg_merge_leaves_data data;
+
+	for (i = n - 1; i >= 0; --i) {
+		isl_union_map *dep_i;
+		isl_stat ok;
+
+		if (i + 1 >= n)
+			continue;
+
+		dep_i = isl_union_map_copy(dep);
+		dep_i = isl_union_map_intersect_domain(dep_i,
+				isl_union_set_copy(leaves[i].domain));
+		dep_i = isl_union_map_intersect_range(dep_i,
+				isl_union_set_copy(leaves[i + 1].domain));
+		data.merge = 0;
+		data.src = &leaves[i];
+		data.dst = &leaves[i + 1];
+		ok = isl_union_map_foreach_map(dep_i, &check_merge, &data);
+		isl_union_map_free(dep_i);
+		if (ok < 0 && !data.merge)
+			return -1;
+		if (!data.merge)
+			continue;
+		if (merge_pair(n, leaves, i) < 0)
+			return -1;
+		--n;
+		++i;
+	}
+
+	return n;
+}
+
+/* Construct a schedule with "domain" as domain, that executes
+ * the elements of "list" in order (as a sequence).
+ */
+static __isl_give isl_schedule *schedule_from_domain_and_list(
+	__isl_keep isl_union_set *domain, __isl_keep isl_union_set_list *list)
+{
+	isl_schedule *schedule;
+	isl_schedule_node *node;
+
+	schedule = isl_schedule_from_domain(isl_union_set_copy(domain));
+	node = isl_schedule_get_root(schedule);
+	isl_schedule_free(schedule);
+	node = isl_schedule_node_child(node, 0);
+	list = isl_union_set_list_copy(list);
+	node = isl_schedule_node_insert_sequence(node, list);
+	schedule = isl_schedule_node_get_schedule(node);
+	isl_schedule_node_free(node);
+
+	return schedule;
+}
+
+/* Construct a unique identifier for a group in "grouping".
+ *
+ * The name is of the form G_n, with n the first value starting at
+ * grouping->group_id that does not result in an identifier
+ * that is already in use in the domain of the original schedule
+ * constraints.
+ */
+static isl_id *construct_group_id(struct ppcg_grouping *grouping,
+	__isl_take isl_space *space)
+{
+	isl_ctx *ctx;
+	isl_id *id;
+	isl_bool empty;
+	isl_union_set *domain;
+
+	if (!space)
+		return NULL;
+
+	ctx = isl_space_get_ctx(space);
+	domain = isl_schedule_constraints_get_domain(grouping->sc);
+
+	do {
+		char buffer[20];
+		isl_id *id;
+		isl_set *set;
+
+		snprintf(buffer, sizeof(buffer), "G_%d", grouping->group_id);
+		grouping->group_id++;
+		id = isl_id_alloc(ctx, buffer, NULL);
+		space = isl_space_set_tuple_id(space, isl_dim_set, id);
+		set = isl_union_set_extract_set(domain, isl_space_copy(space));
+		empty = isl_set_plain_is_empty(set);
+		isl_set_free(set);
+	} while (empty >= 0 && !empty);
+
+	if (empty < 0)
+		space = isl_space_free(space);
+
+	id = isl_space_get_tuple_id(space, isl_dim_set);
+
+	isl_space_free(space);
+	isl_union_set_free(domain);
+
+	return id;
+}
+
+/* Construct a contraction from "prefix" and "domain" for a new group
+ * in "grouping".
+ *
+ * The values of the prefix schedule "prefix" are used as instances
+ * of the new group.  The identifier of the group is constructed
+ * in such a way that it does not conflict with those of earlier
+ * groups nor with statements in the domain of the original
+ * schedule constraints.
+ * The isl_multi_union_pw_aff "prefix" then simply needs to be
+ * converted to an isl_union_pw_multi_aff.  However, this is not
+ * possible if "prefix" is zero-dimensional, so in this case,
+ * a contraction is constructed from "domain" instead.
+ */
+static isl_union_pw_multi_aff *group_contraction_from_prefix_and_domain(
+	struct ppcg_grouping *grouping,
+	__isl_keep isl_multi_union_pw_aff *prefix,
+	__isl_keep isl_union_set *domain)
+{
+	isl_id *id;
+	isl_space *space;
+	int dim;
+
+	space = isl_multi_union_pw_aff_get_space(prefix);
+	if (!space)
+		return NULL;
+	dim = isl_space_dim(space, isl_dim_set);
+	id = construct_group_id(grouping, space);
+	if (dim == 0) {
+		isl_multi_val *mv;
+
+		space = isl_multi_union_pw_aff_get_space(prefix);
+		space = isl_space_set_tuple_id(space, isl_dim_set, id);
+		mv = isl_multi_val_zero(space);
+		domain = isl_union_set_copy(domain);
+		return isl_union_pw_multi_aff_multi_val_on_domain(domain, mv);
+	}
+	prefix = isl_multi_union_pw_aff_copy(prefix);
+	prefix = isl_multi_union_pw_aff_set_tuple_id(prefix, isl_dim_out, id);
+	return isl_union_pw_multi_aff_from_multi_union_pw_aff(prefix);
+}
+
+/* Extend "grouping" with groups corresponding to merged
+ * leaves in the list of potentially merged leaves "leaves".
+ *
+ * The "list" field of each element in "leaves" contains a list
+ * of the instances sets of the original leaves that have been
+ * merged into this element.  If at least two of the original leaves
+ * have been merged into a given element, then add the corresponding
+ * group to "grouping".
+ * In particular, the domain is extended with the statement instances
+ * of the merged leaves, the contraction is extended with a mapping
+ * of these statement instances to instances of a new group and
+ * the schedule is extended with a schedule that executes
+ * the statement instances according to the order of the leaves
+ * in which they appear.
+ * Since the instances of the groups should already be scheduled apart
+ * in the schedule into which this schedule will be plugged in,
+ * the schedules of the individual groups are combined independently
+ * of each other (as a set).
+ */
+static isl_stat add_groups(struct ppcg_grouping *grouping,
+	int n, struct ppcg_grouping_leaf leaves[])
+{
+	int i;
+
+	for (i = 0; i < n; ++i) {
+		int n_leaf;
+		isl_schedule *schedule;
+		isl_union_set *domain;
+		isl_union_pw_multi_aff *upma;
+
+		n_leaf = isl_union_set_list_n_union_set(leaves[i].list);
+		if (n_leaf < 0)
+			return isl_stat_error;
+		if (n_leaf <= 1)
+			continue;
+		schedule = schedule_from_domain_and_list(leaves[i].domain,
+							leaves[i].list);
+		upma = group_contraction_from_prefix_and_domain(grouping,
+					leaves[i].prefix, leaves[i].domain);
+
+		domain = isl_union_set_copy(leaves[i].domain);
+		if (grouping->domain) {
+			domain = isl_union_set_union(domain, grouping->domain);
+			upma = isl_union_pw_multi_aff_union_add(upma,
+						grouping->contraction);
+			schedule = isl_schedule_set(schedule,
+						grouping->schedule);
+		}
+		grouping->domain = domain;
+		grouping->contraction = upma;
+		grouping->schedule = schedule;
+
+		if (!grouping->domain || !grouping->contraction ||
+		    !grouping->schedule)
+			return isl_stat_error;
+	}
+
+	return isl_stat_ok;
+}
+
+/* Look for any pairs of consecutive leaves among the "n" children of "node"
+ * starting at "first" that should be merged together.
+ * Store the results in "grouping".
+ *
+ * First make sure the intersection of validity and proximity
+ * schedule constraints is available and extract the required
+ * information from the "n" leaves.
+ * Then try and merge consecutive leaves based on the validity
+ * and proximity constraints.
+ * If any pairs were successfully merged, then add groups
+ * corresponding to the merged leaves to "grouping".
+ */
+static isl_stat group_subsequence(__isl_keep isl_schedule_node *node,
+	int first, int n, struct ppcg_grouping *grouping)
+{
+	int n_merge;
+	struct ppcg_grouping_leaf *leaves;
+
+	if (ppcg_grouping_compute_dep(grouping) < 0)
+		return isl_stat_error;
+
+	leaves = extract_leaves(node, first, n);
+	if (!leaves)
+		return isl_stat_error;
+
+	n_merge = merge_leaves(n, leaves, grouping->dep);
+	if (n_merge >= 0 && n_merge < n &&
+	    add_groups(grouping, n_merge, leaves) < 0)
+		return isl_stat_error;
+
+	ppcg_grouping_leaf_free(n, leaves);
+
+	return isl_stat_ok;
+}
+
+/* If "node" is a sequence, then check if it has any consecutive
+ * leaves that should be merged together and store the results
+ * in "grouping".
+ *
+ * In particular, call group_subsequence on each consecutive
+ * sequence of (filtered) leaves among the children of "node".
+ */
+static isl_bool detect_groups(__isl_keep isl_schedule_node *node, void *user)
+{
+	int i, n, first;
+	struct ppcg_grouping *grouping = user;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence)
+		return isl_bool_true;
+
+	n = isl_schedule_node_n_children(node);
+	if (n < 0)
+		return isl_bool_error;
+
+	first = -1;
+	for (i = 0; i < n; ++i) {
+		isl_schedule_node *child;
+		enum isl_schedule_node_type type;
+
+		child = isl_schedule_node_get_child(node, i);
+		child = isl_schedule_node_child(child, 0);
+		type = isl_schedule_node_get_type(child);
+		isl_schedule_node_free(child);
+
+		if (first >= 0 && type != isl_schedule_node_leaf) {
+			if (group_subsequence(node, first, i - first,
+						grouping) < 0)
+				return isl_bool_error;
+			first = -1;
+		}
+		if (first < 0 && type == isl_schedule_node_leaf)
+			first = i;
+	}
+	if (first >= 0) {
+		if (group_subsequence(node, first, n - first, grouping) < 0)
+			return isl_bool_error;
+	}
+
+	return isl_bool_true;
+}
+
+/* Complete "grouping" to cover all statement instances in the domain
+ * of grouping->sc.
+ *
+ * In particular, grouping->domain is set to the full set of statement
+ * instances; group->contraction is extended with an identity
+ * contraction on the additional instances and group->schedule
+ * is extended with an independent schedule on those additional instances.
+ * In the extension of group->contraction, the additional instances
+ * are split into those belong to different statements and those
+ * that belong to some of the same statements.  The first group
+ * is replaced by its universe in order to simplify the contraction extension.
+ */
+static void complete_grouping(struct ppcg_grouping *grouping)
+{
+	isl_union_set *domain, *left, *overlap;
+	isl_union_pw_multi_aff *upma;
+	isl_schedule *schedule;
+
+	domain = isl_schedule_constraints_get_domain(grouping->sc);
+	left = isl_union_set_subtract(isl_union_set_copy(domain),
+				    isl_union_set_copy(grouping->domain));
+	schedule = isl_schedule_from_domain(isl_union_set_copy(left));
+	schedule = isl_schedule_set(schedule, grouping->schedule);
+	grouping->schedule = schedule;
+
+	overlap = isl_union_set_universe(grouping->domain);
+	grouping->domain = domain;
+	overlap = isl_union_set_intersect(isl_union_set_copy(left), overlap);
+	left = isl_union_set_subtract(left, isl_union_set_copy(overlap));
+	left = isl_union_set_universe(left);
+	left = isl_union_set_union(left, overlap);
+	upma = isl_union_set_identity_union_pw_multi_aff(left);
+	upma = isl_union_pw_multi_aff_union_add(upma, grouping->contraction);
+	grouping->contraction = upma;
+}
+
+/* Compute a schedule on the domain of "sc" that respects the schedule
+ * constraints in "sc".
+ *
+ * "schedule" is a known correct schedule that is used to combine
+ * groups of statements if options->group_chains is set.
+ * In particular, statements that are executed consecutively in a sequence
+ * in this schedule and where all instances of the second depend on
+ * the instance of the first that is executed in the same iteration
+ * of outer band nodes are grouped together into a single statement.
+ * The schedule constraints are then mapped to these groups of statements
+ * and the resulting schedule is expanded again to refer to the original
+ * statements.
+ */
+__isl_give isl_schedule *ppcg_compute_schedule(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_keep isl_schedule *schedule, struct ppcg_options *options)
+{
+	struct ppcg_grouping grouping = { sc };
+	isl_union_pw_multi_aff *contraction;
+	isl_union_map *umap;
+	isl_schedule *res, *expansion;
+
+	if (!options->group_chains)
+		return isl_schedule_constraints_compute_schedule(sc);
+
+	grouping.group_id = 0;
+	if (isl_schedule_foreach_schedule_node_top_down(schedule,
+			&detect_groups, &grouping) < 0)
+		goto error;
+	if (!grouping.contraction) {
+		ppcg_grouping_clear(&grouping);
+		return isl_schedule_constraints_compute_schedule(sc);
+	}
+	complete_grouping(&grouping);
+	contraction = isl_union_pw_multi_aff_copy(grouping.contraction);
+	umap = isl_union_map_from_union_pw_multi_aff(contraction);
+
+	sc = isl_schedule_constraints_apply(sc, umap);
+
+	res = isl_schedule_constraints_compute_schedule(sc);
+
+	contraction = isl_union_pw_multi_aff_copy(grouping.contraction);
+	expansion = isl_schedule_copy(grouping.schedule);
+	res = isl_schedule_expand(res, contraction, expansion);
+
+	ppcg_grouping_clear(&grouping);
+	return res;
+error:
+	ppcg_grouping_clear(&grouping);
+	isl_schedule_constraints_free(sc);
+	return NULL;
+}
diff --git a/final/lib/External/ppcg/hybrid.c b/final/lib/External/ppcg/hybrid.c
new file mode 100644
index 0000000..b0a047c
--- /dev/null
+++ b/final/lib/External/ppcg/hybrid.c
@@ -0,0 +1,2242 @@
+/*
+ * Copyright 2013      Ecole Normale Superieure
+ * Copyright 2015      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <string.h>
+
+#include <isl/space.h>
+#include <isl/constraint.h>
+#include <isl/val.h>
+#include <isl/aff.h>
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+
+#include "hybrid.h"
+#include "schedule.h"
+
+/* The hybrid tiling implemented in this file is based on
+ * Grosser et al., "Hybrid Hexagonal/Classical Tiling for GPUs".
+ */
+
+/* Bounds on relative dependence distances in input to hybrid tiling.
+ * upper is an upper bound on the relative dependence distances
+ * in the first space dimension
+ * -lower is a lower bound on the relative dependence distances
+ * in all space dimensions.
+ *
+ * In particular,
+ *
+ *	d_i >= -lower_i d_0
+ * and
+ *	d_1 <= upper d_0
+ *
+ * for each dependence distance vector d, where d_1 is the component
+ * corresponding to the first space dimension.
+ *
+ * upper and lower are always non-negative.
+ * Some of the values may be NaN if no bound could be found.
+ */
+struct ppcg_ht_bounds {
+	isl_val *upper;
+	isl_multi_val *lower;
+};
+
+/* Free "bounds" along with all its fields.
+ */
+__isl_null ppcg_ht_bounds *ppcg_ht_bounds_free(
+	__isl_take ppcg_ht_bounds *bounds)
+{
+	if (!bounds)
+		return NULL;
+	isl_val_free(bounds->upper);
+	isl_multi_val_free(bounds->lower);
+	free(bounds);
+
+	return NULL;
+}
+
+/* Create a ppcg_ht_bounds object for a band living in "space".
+ * The bounds are initialized to NaN.
+ */
+__isl_give ppcg_ht_bounds *ppcg_ht_bounds_alloc(__isl_take isl_space *space)
+{
+	int i, n;
+	isl_ctx *ctx;
+	ppcg_ht_bounds *bounds;
+
+	if (!space)
+		return NULL;
+
+	ctx = isl_space_get_ctx(space);
+	bounds = isl_alloc_type(ctx, struct ppcg_ht_bounds);
+	if (!bounds)
+		goto error;
+	bounds->upper = isl_val_nan(ctx);
+	bounds->lower = isl_multi_val_zero(space);
+	n = isl_multi_val_dim(bounds->lower, isl_dim_set);
+	for (i = 0; i < n; ++i) {
+		isl_val *v = isl_val_copy(bounds->upper);
+		bounds->lower = isl_multi_val_set_val(bounds->lower, i, v);
+	}
+
+	if (!bounds->lower || !bounds->upper)
+		return ppcg_ht_bounds_free(bounds);
+
+	return bounds;
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+void ppcg_ht_bounds_dump(__isl_keep ppcg_ht_bounds *bounds)
+{
+	if (!bounds)
+		return;
+
+	fprintf(stderr, "lower: ");
+	isl_multi_val_dump(bounds->lower);
+	fprintf(stderr, "upper: ");
+	isl_val_dump(bounds->upper);
+}
+
+/* Return the upper bound on the relative dependence distances
+ * in the first space dimension.
+ */
+__isl_give isl_val *ppcg_ht_bounds_get_upper(__isl_keep ppcg_ht_bounds *bounds)
+{
+	if (!bounds)
+		return NULL;
+	return isl_val_copy(bounds->upper);
+}
+
+/* Replace the upper bound on the relative dependence distances
+ * in the first space dimension by "upper".
+ */
+__isl_give ppcg_ht_bounds *ppcg_ht_bounds_set_upper(
+	__isl_take ppcg_ht_bounds *bounds, __isl_take isl_val *upper)
+{
+	if (!bounds || !upper)
+		goto error;
+	isl_val_free(bounds->upper);
+	bounds->upper = upper;
+	return bounds;
+error:
+	ppcg_ht_bounds_free(bounds);
+	isl_val_free(upper);
+	return NULL;
+}
+
+/* Return the lower bound on the relative dependence distances
+ * in space dimension "pos".
+ */
+__isl_give isl_val *ppcg_ht_bounds_get_lower(__isl_keep ppcg_ht_bounds *bounds,
+	int pos)
+{
+	if (!bounds)
+		return NULL;
+	return isl_multi_val_get_val(bounds->lower, pos);
+}
+
+/* Replace the lower bound on the relative dependence distances
+ * in space dimension "pos" by "lower".
+ */
+__isl_give ppcg_ht_bounds *ppcg_ht_bounds_set_lower(
+	__isl_take ppcg_ht_bounds *bounds, int pos, __isl_take isl_val *lower)
+{
+	if (!bounds || !lower)
+		goto error;
+	bounds->lower = isl_multi_val_set_val(bounds->lower, pos, lower);
+	if (!bounds->lower)
+		return ppcg_ht_bounds_free(bounds);
+	return bounds;
+error:
+	ppcg_ht_bounds_free(bounds);
+	isl_val_free(lower);
+	return NULL;
+}
+
+/* Can the bounds on relative dependence distances recorded in "bounds"
+ * be used to perform hybrid tiling?
+ * In particular, have appropriate lower and upper bounds been found?
+ * Any NaN indicates that no corresponding bound was found.
+ */
+isl_bool ppcg_ht_bounds_is_valid(__isl_keep ppcg_ht_bounds *bounds)
+{
+	isl_bool is_nan;
+	int i, n;
+
+	if (!bounds)
+		return isl_bool_error;
+	is_nan = isl_val_is_nan(bounds->upper);
+	if (is_nan < 0)
+		return isl_bool_error;
+	if (is_nan)
+		return isl_bool_false;
+
+	n = isl_multi_val_dim(bounds->lower, isl_dim_set);
+	for (i = 0; i < n; ++i) {
+		isl_val *v;
+
+		v = isl_multi_val_get_val(bounds->lower, i);
+		is_nan = isl_val_is_nan(v);
+		if (is_nan < 0)
+			return isl_bool_error;
+		if (is_nan)
+			return isl_bool_false;
+		isl_val_free(v);
+	}
+
+	return isl_bool_true;
+}
+
+/* Structure that represents the basic hexagonal tiling,
+ * along with information that is needed to perform the hybrid tiling.
+ *
+ * "bounds" are the bounds on the dependence distances that
+ * define the hexagonal shape and the required skewing in the remaining
+ * space dimensions.
+ *
+ * "input_node" points to the input pair of band nodes.
+ * "input_schedule" is the partial schedule of this input pair of band nodes.
+ * The space of this schedule is [P -> C], where P is the space
+ * of the parent node and C is the space of the child node.
+ *
+ * "space_sizes" represent the total size of a tile for the space
+ * dimensions, i.e., those corresponding to the child node.
+ * The space of "space_sizes" is C.
+ * If S_0 is the original tile size in the first space dimension,
+ * then the first entry of "space_sizes" is equal to
+ * W = 2*S_0 + floor(d_l h) + floor(d_u h).
+ * The remaining entries are the same as in the original tile sizes.
+ *
+ * The basic hexagonal tiling "hex" is defined
+ * in a "ts" (time-space) space and corresponds to the phase-1 tiles.
+ * "time_tile" maps the "ts" space to outer time tile.
+ * Is is equal to ts[t, s] -> floor(t/(2 * S_t)), with S_t the original tile
+ * size corresponding to the parent node.
+ * "local_time" maps the "ts" space to the time dimension inside each tile.
+ * It is equal to ts[t, s] -> t mod (2 S_t), with S_t the original tile
+ * size corresponding to the parent node.
+ * "shift_space" shifts the tiles at time tile T = floor(t/(2 S_t))
+ * in the space dimension such that they align to a multiple of W.
+ * It is equal to ts[t, s] -> s + (-(2 * shift_s)*T) % W,
+ * with shift_s = S_0 + floor(d_u h).
+ * "shift_phase" is the shift taken to go from phase 0 to phase 1
+ * It is equal to ts[t, s] -> ts[t + S_t, s + shift_s],
+ * with shift_s = S_0 + floor(d_u h).
+ *
+ * "project_ts" projects the space of the input schedule to the ts-space.
+ * It is equal to [P[t] -> C[s_0, ...]] -> ts[t, s_0].
+ */
+struct ppcg_ht_tiling {
+	int ref;
+
+	ppcg_ht_bounds *bounds;
+	isl_schedule_node *input_node;
+	isl_multi_union_pw_aff *input_schedule;
+
+	isl_multi_val *space_sizes;
+
+	isl_aff *time_tile;
+	isl_aff *local_time;
+	isl_aff *shift_space;
+	isl_multi_aff *shift_phase;
+	isl_set *hex;
+
+	isl_multi_aff *project_ts;
+};
+typedef struct ppcg_ht_tiling ppcg_ht_tiling;
+
+/* Return the space of the pair of band nodes that form the input
+ * to the hybrid tiling.
+ * In particular, return the space [P -> C], where P is the space
+ * of the parent node and C is the space of the child node.
+ */
+__isl_give isl_space *ppcg_ht_tiling_get_input_space(
+	__isl_keep ppcg_ht_tiling *tile)
+{
+	if (!tile)
+		return NULL;
+
+	return isl_multi_union_pw_aff_get_space(tile->input_schedule);
+}
+
+/* Remove a reference to "tile" and free "tile" along with all its fields
+ * as soon as the reference count drops to zero.
+ */
+static __isl_null ppcg_ht_tiling *ppcg_ht_tiling_free(
+	__isl_take ppcg_ht_tiling *tiling)
+{
+	if (!tiling)
+		return NULL;
+	if (--tiling->ref > 0)
+		return NULL;
+
+	ppcg_ht_bounds_free(tiling->bounds);
+	isl_schedule_node_free(tiling->input_node);
+	isl_multi_union_pw_aff_free(tiling->input_schedule);
+	isl_multi_val_free(tiling->space_sizes);
+	isl_aff_free(tiling->time_tile);
+	isl_aff_free(tiling->local_time);
+	isl_aff_free(tiling->shift_space);
+	isl_multi_aff_free(tiling->shift_phase);
+	isl_set_free(tiling->hex);
+	isl_multi_aff_free(tiling->project_ts);
+	free(tiling);
+
+	return NULL;
+}
+
+/* Return a new reference to "tiling".
+ */
+__isl_give ppcg_ht_tiling *ppcg_ht_tiling_copy(
+	__isl_keep ppcg_ht_tiling *tiling)
+{
+	if (!tiling)
+		return NULL;
+
+	tiling->ref++;
+	return tiling;
+}
+
+/* Return the isl_ctx to which "tiling" belongs.
+ */
+isl_ctx *ppcg_ht_tiling_get_ctx(__isl_keep ppcg_ht_tiling *tiling)
+{
+	if (!tiling)
+		return NULL;
+
+	return isl_multi_union_pw_aff_get_ctx(tiling->input_schedule);
+}
+
+/* Representation of one of the two phases of hybrid tiling.
+ *
+ * "tiling" points to the shared tiling data.
+ *
+ * "time_tile", "local_time" and "shift_space" are equal to the corresponding
+ * fields of "tiling", pulled back to the input space.
+ * In case of phase 0, these expressions have also been moved
+ * from phase 1 to phase 0.
+ *
+ * "domain" contains the hexagonal tiling of this phase.
+ *
+ * "space_shift" is the shift that should be added to the space band
+ * in order to be able to apply rectangular tiling to the space.
+ * For phase 1, it is equal to
+ *
+ *	[P[t] -> C[s_0, s_i]] -> C[(-(2 * shift_s)*T) % W, dl_i * u]
+ *
+ * with shift_s = S_0 + floor(d_u h),
+ * T equal to "time_tile" and u equal to "local_time".
+ * For phase 0, it is equal to
+ *
+ *	[P[t] -> C[s_0, s_i]] -> C[shift_s + (-(2 * shift_s)*T) % W, dl_i * u]
+ *
+ * "space_tile" is the space tiling.  It is equal to
+ *
+ *	[P[t] -> C[s]] -> C[floor((s + space_shift)/space_size]
+ */
+struct ppcg_ht_phase {
+	ppcg_ht_tiling *tiling;
+
+	isl_aff *time_tile;
+	isl_aff *local_time;
+	isl_aff *shift_space;
+	isl_set *domain;
+
+	isl_multi_aff *space_shift;
+	isl_multi_aff *space_tile;
+};
+
+/* Free "phase" along with all its fields.
+ */
+static __isl_null ppcg_ht_phase *ppcg_ht_phase_free(
+	__isl_take ppcg_ht_phase *phase)
+{
+	if (!phase)
+		return NULL;
+
+	ppcg_ht_tiling_free(phase->tiling);
+	isl_aff_free(phase->time_tile);
+	isl_aff_free(phase->local_time);
+	isl_aff_free(phase->shift_space);
+	isl_set_free(phase->domain);
+	isl_multi_aff_free(phase->space_shift);
+	isl_multi_aff_free(phase->space_tile);
+	free(phase);
+
+	return NULL;
+}
+
+/* Wrapper around ppcg_ht_phase_free for use as an argument
+ * to isl_id_set_free_user.
+ */
+static void ppcg_ht_phase_free_wrap(void *user)
+{
+	ppcg_ht_phase *phase = user;
+
+	ppcg_ht_phase_free(phase);
+}
+
+/* Return the domain of hybrid tiling phase "phase".
+ */
+static __isl_give isl_set *ppcg_ht_phase_get_domain(ppcg_ht_phase *phase)
+{
+	if (!phase)
+		return NULL;
+
+	return isl_set_copy(phase->domain);
+}
+
+/* Return the space of the pair of band nodes that form the input
+ * to the hybrid tiling of which "phase" is a phase.
+ * In particular, return the space [P -> C], where P is the space
+ * of the parent node and C is the space of the child node.
+ */
+static __isl_give isl_space *ppcg_ht_phase_get_input_space(
+	__isl_keep ppcg_ht_phase *phase)
+{
+	if (!phase)
+		return NULL;
+
+	return ppcg_ht_tiling_get_input_space(phase->tiling);
+}
+
+/* Construct the lower left constraint of the hexagonal tile, i.e.,
+ *
+ *	du a - b <= (2h+1) du - duh
+ *	-du a + b + (2h+1) du - duh >= 0
+ *
+ * where duh = floor(du * h).
+ *
+ * This constraint corresponds to (6) in
+ * "Hybrid Hexagonal/Classical Tiling for GPUs".
+ */
+static __isl_give isl_constraint *hex_lower_left(__isl_take isl_local_space *ls,
+	__isl_keep isl_val *h, __isl_keep isl_val *du, __isl_keep isl_val *duh)
+{
+	isl_val *v;
+	isl_aff *aff;
+
+	v = isl_val_add_ui(isl_val_mul_ui(isl_val_copy(h), 2), 1);
+	v = isl_val_mul(v, isl_val_copy(du));
+	v = isl_val_sub(v, isl_val_copy(duh));
+	aff = isl_aff_val_on_domain(ls, v);
+	v = isl_val_neg(isl_val_copy(du));
+	aff = isl_aff_set_coefficient_val(aff, isl_dim_in, 0, v);
+	aff = isl_aff_set_coefficient_si(aff, isl_dim_in, 1, 1);
+
+	return isl_inequality_from_aff(aff);
+}
+
+/* Construct the lower constraint of the hexagonal tile, i.e.,
+ *
+ *	a <= 2h+1
+ *	-a + 2h+1 >= 0
+ *
+ * This constraint corresponds to (7) in
+ * "Hybrid Hexagonal/Classical Tiling for GPUs".
+ */
+static __isl_give isl_constraint *hex_lower(__isl_take isl_local_space *ls,
+	__isl_keep isl_val *h)
+{
+	isl_val *v;
+	isl_aff *aff;
+
+	v = isl_val_add_ui(isl_val_mul_ui(isl_val_copy(h), 2), 1);
+	aff = isl_aff_val_on_domain(ls, v);
+	aff = isl_aff_set_coefficient_si(aff, isl_dim_in, 0, -1);
+
+	return isl_inequality_from_aff(aff);
+}
+
+/* Construct the lower right constraint of the hexagonal tile, i.e.,
+ *
+ *	dl a + b <= (2h+1) dl + duh + (s0-1)
+ *	-dl a - b + (2h+1) dl + duh + (s0-1) >= 0
+ *
+ * where duh = floor(du * h).
+ *
+ * This constraint corresponds to (8) in
+ * "Hybrid Hexagonal/Classical Tiling for GPUs".
+ */
+static __isl_give isl_constraint *hex_lower_right(
+	__isl_take isl_local_space *ls, __isl_keep isl_val *h,
+	__isl_keep isl_val *s0, __isl_keep isl_val *dl, __isl_keep isl_val *duh)
+{
+	isl_val *v;
+	isl_aff *aff;
+
+	v = isl_val_add_ui(isl_val_mul_ui(isl_val_copy(h), 2), 1);
+	v = isl_val_mul(v, isl_val_copy(dl));
+	v = isl_val_add(v, isl_val_copy(duh));
+	v = isl_val_add(v, isl_val_copy(s0));
+	v = isl_val_sub_ui(v, 1);
+	aff = isl_aff_val_on_domain(ls, v);
+	v = isl_val_neg(isl_val_copy(dl));
+	aff = isl_aff_set_coefficient_val(aff, isl_dim_in, 0, v);
+	aff = isl_aff_set_coefficient_si(aff, isl_dim_in, 1, -1);
+
+	return isl_inequality_from_aff(aff);
+}
+
+/* Construct the upper left constraint of the hexagonal tile, i.e.,
+ *
+ *	dl a + b >= h dl - (d - 1)/d				with d = den(dl)
+ *	dl a + b - h dl + (d - 1)/d >= 0
+ *
+ * This constraint corresponds to (10) in
+ * "Hybrid Hexagonal/Classical Tiling for GPUs".
+ */
+static __isl_give isl_constraint *hex_upper_left(__isl_take isl_local_space *ls,
+	__isl_keep isl_val *h, __isl_keep isl_val *dl)
+{
+	isl_val *v, *d;
+	isl_aff *aff;
+
+	d = isl_val_get_den_val(dl);
+	v = isl_val_sub_ui(isl_val_copy(d), 1);
+	v = isl_val_div(v, d);
+	v = isl_val_sub(v, isl_val_mul(isl_val_copy(h), isl_val_copy(dl)));
+	aff = isl_aff_val_on_domain(ls, v);
+	aff = isl_aff_set_coefficient_val(aff, isl_dim_in, 0, isl_val_copy(dl));
+	aff = isl_aff_set_coefficient_si(aff, isl_dim_in, 1, 1);
+
+	return isl_inequality_from_aff(aff);
+}
+
+/* Construct the upper right constraint of the hexagonal tile, i.e.,
+ *
+ *	du a - b >= du h - duh - (s0-1) - dlh - (d - 1)/d	with d = den(du)
+ *	du a - b - du h + duh + (s0-1) + dlh + (d - 1)/d >= 0
+ *
+ * where dlh = floor(dl * h) and duh = floor(du * h).
+ *
+ * This constraint corresponds to (12) in
+ * "Hybrid Hexagonal/Classical Tiling for GPUs".
+ */
+static __isl_give isl_constraint *hex_upper_right(
+	__isl_take isl_local_space *ls, __isl_keep isl_val *h,
+	__isl_keep isl_val *s0, __isl_keep isl_val *du,
+	__isl_keep isl_val *dlh, __isl_keep isl_val *duh)
+{
+	isl_val *v, *d;
+	isl_aff *aff;
+
+	d = isl_val_get_den_val(du);
+	v = isl_val_sub_ui(isl_val_copy(d), 1);
+	v = isl_val_div(v, d);
+	v = isl_val_sub(v, isl_val_mul(isl_val_copy(h), isl_val_copy(du)));
+	v = isl_val_add(v, isl_val_copy(duh));
+	v = isl_val_add(v, isl_val_copy(dlh));
+	v = isl_val_add(v, isl_val_copy(s0));
+	v = isl_val_sub_ui(v, 1);
+	aff = isl_aff_val_on_domain(ls, v);
+	aff = isl_aff_set_coefficient_val(aff, isl_dim_in, 0, isl_val_copy(du));
+	aff = isl_aff_set_coefficient_si(aff, isl_dim_in, 1, -1);
+
+	return isl_inequality_from_aff(aff);
+}
+
+/* Construct the uppper constraint of the hexagonal tile, i.e.,
+ *
+ *	a >= 0
+ *
+ * This constraint corresponds to (13) in
+ * "Hybrid Hexagonal/Classical Tiling for GPUs".
+ */
+static __isl_give isl_constraint *hex_upper(__isl_take isl_local_space *ls)
+{
+	isl_aff *aff;
+
+	aff = isl_aff_var_on_domain(ls, isl_dim_set, 0);
+
+	return isl_inequality_from_aff(aff);
+}
+
+/* Construct the basic hexagonal tile shape.
+ * "space" is the 2D space in which the hexagon should be constructed.
+ * h is st-1, with st the tile size in the time dimension
+ * s0 is the tile size in the space dimension
+ * dl is a bound on the negative relative dependence distances, i.e.,
+ *
+ *	d_s >= -dl d_t
+ *
+ * du is a bound on the positive relative dependence distances, i.e.,
+ *
+ *	d_s <= du d_t
+ *
+ * with (d_t,d_s) any dependence distance vector.
+ * dlh = floor(dl * h)
+ * duh = floor(du * h)
+ *
+ * The shape of the hexagon is as follows:
+ *
+ *		0 dlh   dlh+s0-1
+ *		   ______                __
+ * 0		  /      \_             /
+ *		 /         \_          /
+ * h		/            \ ______ /
+ * h+1		\_           //      \\_
+ *		  \_        //         \\_
+ * 2h+1		    \______//            \\
+ *		0   duh   duh+s0-1
+ *		             duh+s0-1+dlh
+ *		                  duh+s0-1+dlh+1+s0+1
+ *
+ * The next hexagon is shifted by duh + dlh + 2 * s0.
+ *
+ * The slope of the "/" constraints is dl.
+ * The slope of the "\_" constraints is du.
+ */
+static __isl_give isl_set *compute_hexagon(__isl_take isl_space *space,
+	__isl_keep isl_val *h, __isl_keep isl_val *s0,
+	__isl_keep isl_val *dl, __isl_keep isl_val *du,
+	__isl_keep isl_val *dlh, __isl_keep isl_val *duh)
+{
+	isl_local_space *ls;
+	isl_constraint *c;
+	isl_basic_set *bset;
+
+	ls = isl_local_space_from_space(space);
+
+	c = hex_lower_left(isl_local_space_copy(ls), h, du, duh);
+	bset = isl_basic_set_from_constraint(c);
+
+	c = hex_lower(isl_local_space_copy(ls), h);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = hex_lower_right(isl_local_space_copy(ls), h, s0, dl, duh);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = hex_upper_left(isl_local_space_copy(ls), h, dl);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = hex_upper_right(isl_local_space_copy(ls), h, s0, du, dlh, duh);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	c = hex_upper(ls);
+	bset = isl_basic_set_add_constraint(bset, c);
+
+	return isl_set_from_basic_set(bset);
+}
+
+/* Name of the ts-space.
+ */
+static const char *ts_space_name = "ts";
+
+/* Construct and return the space ts[t, s].
+ */
+static __isl_give isl_space *construct_ts_space(isl_ctx *ctx)
+{
+	isl_space *s;
+
+	s = isl_space_set_alloc(ctx, 0, 2);
+	s = isl_space_set_tuple_name(s, isl_dim_set, ts_space_name);
+
+	return s;
+}
+
+/* Name of the local ts-space.
+ */
+static const char *local_ts_space_name = "local_ts";
+
+/* Construct and return the space local_ts[t, s].
+ */
+static __isl_give isl_space *construct_local_ts_space(isl_ctx *ctx)
+{
+	isl_space *s;
+
+	s = isl_space_set_alloc(ctx, 0, 2);
+	s = isl_space_set_tuple_name(s, isl_dim_set, local_ts_space_name);
+
+	return s;
+}
+
+/* Compute the total size of a tile for the space dimensions,
+ * i.e., those corresponding to the child node
+ * of the input pattern.
+ * If S_0 is the original tile size in the first space dimension,
+ * then the first entry of "space_sizes" is equal to
+ * W = 2*S_0 + floor(d_l h) + floor(d_u h).
+ * The remaining entries are the same as in the original tile sizes.
+ * "tile_sizes" contains the original tile sizes, including
+ * the tile size corresponding to the parent node.
+ * "dlh" is equal to floor(d_l h).
+ * "duh" is equal to floor(d_u h).
+ */
+static __isl_give isl_multi_val *compute_space_sizes(
+	__isl_keep isl_multi_val *tile_sizes,
+	__isl_keep isl_val *dlh, __isl_keep isl_val *duh)
+{
+	isl_val *size;
+	isl_multi_val *space_sizes;
+
+	space_sizes = isl_multi_val_copy(tile_sizes);
+	space_sizes = isl_multi_val_factor_range(space_sizes);
+	size = isl_multi_val_get_val(space_sizes, 0);
+	size = isl_val_mul_ui(size, 2);
+	size = isl_val_add(size, isl_val_copy(duh));
+	size = isl_val_add(size, isl_val_copy(dlh));
+	space_sizes = isl_multi_val_set_val(space_sizes, 0, size);
+
+	return space_sizes;
+}
+
+/* Compute the offset of phase 1 with respect to phase 0
+ * in the ts-space ("space").
+ * In particular, return
+ *
+ *	ts[st, s0 + duh]
+ */
+static __isl_give isl_multi_val *compute_phase_shift(
+	__isl_keep isl_space *space, __isl_keep isl_val *st,
+	__isl_keep isl_val *s0, __isl_keep isl_val *duh)
+{
+	isl_val *v;
+	isl_multi_val *phase_shift;
+
+	phase_shift = isl_multi_val_zero(isl_space_copy(space));
+	phase_shift = isl_multi_val_set_val(phase_shift, 0, isl_val_copy(st));
+	v = isl_val_add(isl_val_copy(duh), isl_val_copy(s0));
+	phase_shift = isl_multi_val_set_val(phase_shift, 1, v);
+
+	return phase_shift;
+}
+
+/* Return the function
+ *
+ *	ts[t, s] -> floor(t/(2 * st))
+ *
+ * representing the time tile.
+ * "space" is the space ts[t, s].
+ */
+static __isl_give isl_aff *compute_time_tile(__isl_keep isl_space *space,
+	__isl_keep isl_val *st)
+{
+	isl_val *v;
+	isl_aff *t;
+	isl_local_space *ls;
+
+	ls = isl_local_space_from_space(isl_space_copy(space));
+	t = isl_aff_var_on_domain(ls, isl_dim_set, 0);
+	v = isl_val_mul_ui(isl_val_copy(st), 2);
+	t = isl_aff_floor(isl_aff_scale_down_val(t, v));
+
+	return t;
+}
+
+/* Compute a shift in the space dimension for tiles
+ * at time tile T = floor(t/(2 * S_t))
+ * such that they align to a multiple of the total space tile dimension W.
+ * In particular, compute
+ *
+ *	ts[t, s] -> s + (-(2 * shift_s)*T) % W
+ *
+ * where shift_s is the shift of phase 1 with respect to phase 0
+ * in the space dimension (the first element of "phase_shift").
+ * W is stored in the first element of "space_sizes".
+ * "time_tile" is the function
+ *
+ *	ts[t, s] -> floor(t/(2 * S_T))
+ *
+ * Since phase 1 is shifted by shift_s with respect to phase 0,
+ * the next line of phase 0 (at T+1) is shifted by 2*shift_s
+ * with respect to the previous line (at T).
+ * A shift of -(2 * shift_s)*T therefore allows the basic pattern
+ * (which starts at 0) to be applied.
+ * However, this shift will be used to obtain the tile coordinate
+ * in the first space dimension and if the original values
+ * in the space dimension are non-negative, then the shift should
+ * not make them negative.  Moreover, the shift should be as minimal
+ * as possible.
+ * Since the pattern repeats itself with a period of W in the space
+ * dimension, the shift can be replaced by (-(2 * shift_s)*T) % W.
+ */
+static __isl_give isl_aff *compute_shift_space(__isl_keep isl_aff *time_tile,
+	__isl_keep isl_multi_val *space_sizes,
+	__isl_keep isl_multi_val *phase_shift)
+{
+	isl_val *v;
+	isl_aff *s, *t;
+	isl_local_space *ls;
+
+	ls = isl_local_space_from_space(isl_aff_get_domain_space(time_tile));
+	t = isl_aff_copy(time_tile);
+	v = isl_val_mul_ui(isl_multi_val_get_val(phase_shift, 1), 2);
+	v = isl_val_neg(v);
+	t = isl_aff_scale_val(t, v);
+	v = isl_multi_val_get_val(space_sizes, 0);
+	t = isl_aff_mod_val(t, v);
+	s = isl_aff_var_on_domain(ls, isl_dim_set, 1);
+	s = isl_aff_add(s, t);
+
+	return s;
+}
+
+/* Give the phase_shift ts[S_t, S_0 + floor(d_u h)],
+ * compute a function that applies the shift, i.e.,
+ *
+ *	ts[t, s] -> ts[t + S_t, s + S_0 + floor(d_u h)],
+ */
+static __isl_give isl_multi_aff *compute_shift_phase(
+	__isl_keep isl_multi_val *phase_shift)
+{
+	isl_space *space;
+	isl_multi_aff *shift;
+
+	space = isl_multi_val_get_space(phase_shift);
+	shift = isl_multi_aff_multi_val_on_space(space,
+					isl_multi_val_copy(phase_shift));
+	space = isl_multi_aff_get_space(shift);
+	shift = isl_multi_aff_add(shift, isl_multi_aff_identity(space));
+
+	return shift;
+}
+
+/* Compute a mapping from the ts-space to the local coordinates
+ * within each tile.  In particular, compute
+ *
+ *	ts[t, s] -> local_ts[t % (2 S_t), (s + (-(2 * shift_s)*T) % W) % W]
+ *
+ * "ts" is the space ts[t, s]
+ * "local_ts" is the space local_ts[t, s]
+ * "shift_space" is equal to ts[t, s] -> s + (-(2 * shift_s)*T) % W
+ * "st" is the tile size in the time dimension S_t.
+ * The first element of "space_sizes" is equal to W.
+ */
+static __isl_give isl_multi_aff *compute_localize(
+	__isl_keep isl_space *local_ts, __isl_keep isl_aff *shift_space,
+	__isl_keep isl_val *st, __isl_keep isl_multi_val *space_sizes)
+{
+	isl_val *v;
+	isl_space *space;
+	isl_aff *s, *t;
+	isl_multi_aff *localize;
+
+	space = isl_aff_get_domain_space(shift_space);
+	local_ts = isl_space_copy(local_ts);
+	space = isl_space_map_from_domain_and_range(space, local_ts);
+	localize = isl_multi_aff_identity(space);
+	t = isl_multi_aff_get_aff(localize, 0);
+	v = isl_val_mul_ui(isl_val_copy(st), 2);
+	t = isl_aff_mod_val(t, v);
+	localize = isl_multi_aff_set_aff(localize, 0, t);
+	s = isl_aff_copy(shift_space);
+	v = isl_multi_val_get_val(space_sizes, 0);
+	s = isl_aff_mod_val(s, v);
+	localize = isl_multi_aff_set_aff(localize, 1, s);
+
+	return localize;
+}
+
+/* Set the project_ts field of "tiling".
+ *
+ * This field projects the space of the input schedule to the ts-space.
+ * It is equal to [P[t] -> C[s_0, ...]] -> ts[t, s_0].
+ */
+static __isl_give ppcg_ht_tiling *ppcg_ht_tiling_set_project_ts(
+	__isl_take ppcg_ht_tiling *tiling)
+{
+	int n;
+	isl_space *space;
+	isl_multi_aff *project;
+
+	if (!tiling)
+		return NULL;
+
+	space = ppcg_ht_tiling_get_input_space(tiling);
+	n = isl_space_dim(space, isl_dim_set);
+	project = isl_multi_aff_project_out_map(space, isl_dim_set, 2, n - 2);
+	project = isl_multi_aff_set_tuple_name(project,
+						isl_dim_out, ts_space_name);
+	if (!project)
+		return ppcg_ht_tiling_free(tiling);
+
+	tiling->project_ts = project;
+
+	return tiling;
+}
+
+/* Construct a hybrid tiling description from bounds on the dependence
+ * distances "bounds".
+ * "input_node" points to the original parent node.
+ * "input_schedule" is the combined schedule of the parent and child
+ * node in the input.
+ * "tile_sizes" are the original, user specified tile sizes.
+ */
+static __isl_give ppcg_ht_tiling *ppcg_ht_bounds_construct_tiling(
+	__isl_take ppcg_ht_bounds *bounds,
+	__isl_keep isl_schedule_node *input_node,
+	__isl_keep isl_multi_union_pw_aff *input_schedule,
+	__isl_keep isl_multi_val *tile_sizes)
+{
+	isl_ctx *ctx;
+	ppcg_ht_tiling *tiling;
+	isl_multi_val *space_sizes, *phase_shift;
+	isl_aff *time_tile, *shift_space;
+	isl_multi_aff *localize;
+	isl_val *h, *duh, *dlh;
+	isl_val *st, *s0, *du, *dl;
+	isl_space *ts, *local_ts;
+
+	if (!bounds || !input_node || !input_schedule || !tile_sizes)
+		goto error;
+
+	ctx = isl_multi_union_pw_aff_get_ctx(input_schedule);
+	tiling = isl_calloc_type(ctx, struct ppcg_ht_tiling);
+	if (!tiling)
+		goto error;
+	tiling->ref = 1;
+
+	st = isl_multi_val_get_val(tile_sizes, 0);
+	h = isl_val_sub_ui(isl_val_copy(st), 1);
+	s0 = isl_multi_val_get_val(tile_sizes, 1);
+	du = ppcg_ht_bounds_get_upper(bounds);
+	dl = ppcg_ht_bounds_get_lower(bounds, 0);
+
+	duh = isl_val_floor(isl_val_mul(isl_val_copy(du), isl_val_copy(h)));
+	dlh = isl_val_floor(isl_val_mul(isl_val_copy(dl), isl_val_copy(h)));
+
+	ts = construct_ts_space(ctx);
+	local_ts = construct_local_ts_space(ctx);
+
+	space_sizes = compute_space_sizes(tile_sizes, dlh, duh);
+	phase_shift = compute_phase_shift(ts, st, s0, duh);
+	time_tile = compute_time_tile(ts, st);
+	shift_space = compute_shift_space(time_tile, space_sizes, phase_shift);
+	localize = compute_localize(local_ts, shift_space, st, space_sizes);
+	isl_space_free(ts);
+
+	tiling->input_node = isl_schedule_node_copy(input_node);
+	tiling->input_schedule = isl_multi_union_pw_aff_copy(input_schedule);
+	tiling->space_sizes = space_sizes;
+	tiling->bounds = bounds;
+	tiling->local_time = isl_multi_aff_get_aff(localize, 0);
+	tiling->hex = compute_hexagon(local_ts, h, s0, dl, du, dlh, duh);
+	tiling->hex = isl_set_preimage_multi_aff(tiling->hex, localize);
+	tiling->time_tile = time_tile;
+	tiling->shift_space = shift_space;
+	tiling->shift_phase = compute_shift_phase(phase_shift);
+	isl_multi_val_free(phase_shift);
+
+	isl_val_free(duh);
+	isl_val_free(dlh);
+	isl_val_free(du);
+	isl_val_free(dl);
+	isl_val_free(s0);
+	isl_val_free(st);
+	isl_val_free(h);
+
+	if (!tiling->input_schedule || !tiling->local_time || !tiling->hex ||
+	    !tiling->shift_space || !tiling->shift_phase)
+		return ppcg_ht_tiling_free(tiling);
+
+	tiling = ppcg_ht_tiling_set_project_ts(tiling);
+
+	return tiling;
+error:
+	ppcg_ht_bounds_free(bounds);
+	return NULL;
+}
+
+/* Are all members of the band node "node" coincident?
+ */
+static isl_bool all_coincident(__isl_keep isl_schedule_node *node)
+{
+	int i, n;
+
+	n = isl_schedule_node_band_n_member(node);
+	for (i = 0; i < n; ++i) {
+		isl_bool c;
+
+		c = isl_schedule_node_band_member_get_coincident(node, i);
+		if (c < 0 || !c)
+			return c;
+	}
+
+	return isl_bool_true;
+}
+
+/* Does "node" satisfy the properties of the inner node in the input
+ * pattern for hybrid tiling?
+ * That is, is it a band node with only coincident members, of which
+ * there is at least one?
+ */
+static isl_bool has_child_properties(__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return isl_bool_error;
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_band)
+		return isl_bool_false;
+	if (isl_schedule_node_band_n_member(node) < 1)
+		return isl_bool_false;
+	return all_coincident(node);
+}
+
+/* Does "node" satisfy the properties of the outer node in the input
+ * pattern for hybrid tiling?
+ * That is, is it a band node with a single member?
+ */
+static isl_bool has_parent_properties(__isl_keep isl_schedule_node *node)
+{
+	if (!node)
+		return isl_bool_error;
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_band)
+		return isl_bool_false;
+	if (isl_schedule_node_band_n_member(node) != 1)
+		return isl_bool_false;
+	return isl_bool_true;
+}
+
+/* Does the parent of "node" satisfy the input patttern for hybrid tiling?
+ * That is, does "node" satisfy the properties of the inner node and
+ * does the parent of "node" satisfy the properties of the outer node?
+ */
+isl_bool ppcg_ht_parent_has_input_pattern(__isl_keep isl_schedule_node *node)
+{
+	isl_bool has_pattern;
+
+	has_pattern = has_child_properties(node);
+	if (has_pattern < 0 || !has_pattern)
+		return has_pattern;
+
+	node = isl_schedule_node_copy(node);
+	node = isl_schedule_node_parent(node);
+	has_pattern = has_parent_properties(node);
+	isl_schedule_node_free(node);
+
+	return has_pattern;
+}
+
+/* Does "node" satisfy the input patttern for hybrid tiling?
+ * That is, does "node" satisfy the properties of the outer node and
+ * does the child of "node" satisfy the properties of the inner node?
+ */
+isl_bool ppcg_ht_has_input_pattern(__isl_keep isl_schedule_node *node)
+{
+	isl_bool has_pattern;
+
+	has_pattern = has_parent_properties(node);
+	if (has_pattern < 0 || !has_pattern)
+		return has_pattern;
+
+	node = isl_schedule_node_get_child(node, 0);
+	has_pattern = has_child_properties(node);
+	isl_schedule_node_free(node);
+
+	return has_pattern;
+}
+
+/* Check that "node" satisfies the input pattern for hybrid tiling.
+ * Error out if it does not.
+ */
+static isl_stat check_input_pattern(__isl_keep isl_schedule_node *node)
+{
+	isl_bool has_pattern;
+
+	has_pattern = ppcg_ht_has_input_pattern(node);
+	if (has_pattern < 0)
+		return isl_stat_error;
+	if (!has_pattern)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_invalid,
+			"invalid input pattern for hybrid tiling",
+			return isl_stat_error);
+
+	return isl_stat_ok;
+}
+
+/* Extract the input schedule from "node", i.e., the product
+ * of the partial schedules of the parent and child nodes
+ * in the input pattern.
+ */
+static __isl_give isl_multi_union_pw_aff *extract_input_schedule(
+	__isl_keep isl_schedule_node *node)
+{
+	isl_multi_union_pw_aff *partial, *partial2;
+
+	partial = isl_schedule_node_band_get_partial_schedule(node);
+	node = isl_schedule_node_get_child(node, 0);
+	partial2 = isl_schedule_node_band_get_partial_schedule(node);
+	isl_schedule_node_free(node);
+
+	return isl_multi_union_pw_aff_range_product(partial, partial2);
+}
+
+/* Collect all dependences from "scop" that are relevant for performing
+ * hybrid tiling on "node" and its child and map them to the schedule
+ * space of this pair of nodes.
+ *
+ * In case live range reordering is not used,
+ * the flow and the false dependences are collected.
+ * In case live range reordering is used,
+ * the flow and the forced dependences are collected, as well
+ * as the order dependences that are adjacent to non-local
+ * flow dependences.
+ *
+ * In all cases, only dependences that map to the same instance
+ * of the outer part of the schedule are considered.
+ */
+static __isl_give isl_map *collect_deps(struct ppcg_scop *scop,
+	__isl_keep isl_schedule_node *node)
+{
+	isl_space *space;
+	isl_multi_union_pw_aff *prefix, *partial;
+	isl_union_map *flow, *other, *dep, *umap;
+	isl_map *map;
+
+	prefix = isl_schedule_node_get_prefix_schedule_multi_union_pw_aff(node);
+	partial = extract_input_schedule(node);
+	space = isl_multi_union_pw_aff_get_space(partial);
+
+	flow = isl_union_map_copy(scop->dep_flow);
+	flow = isl_union_map_eq_at_multi_union_pw_aff(flow,
+					isl_multi_union_pw_aff_copy(prefix));
+	if (!scop->options->live_range_reordering) {
+		other = isl_union_map_copy(scop->dep_false);
+		other = isl_union_map_eq_at_multi_union_pw_aff(other, prefix);
+	} else {
+		isl_union_map *local, *non_local, *order, *adj;
+		isl_union_set *domain, *range;
+
+		other = isl_union_map_copy(scop->dep_forced);
+		other = isl_union_map_eq_at_multi_union_pw_aff(other,
+					isl_multi_union_pw_aff_copy(prefix));
+		local = isl_union_map_copy(flow);
+		local = isl_union_map_eq_at_multi_union_pw_aff(local,
+					isl_multi_union_pw_aff_copy(partial));
+		non_local = isl_union_map_copy(flow);
+		non_local = isl_union_map_subtract(non_local, local);
+
+		order = isl_union_map_copy(scop->dep_order);
+		order = isl_union_map_eq_at_multi_union_pw_aff(order, prefix);
+		adj = isl_union_map_copy(order);
+		domain = isl_union_map_domain(isl_union_map_copy(non_local));
+		domain = isl_union_set_coalesce(domain);
+		adj = isl_union_map_intersect_range(adj, domain);
+		other = isl_union_map_union(other, adj);
+
+		adj = order;
+		range = isl_union_map_range(non_local);
+		range = isl_union_set_coalesce(range);
+		adj = isl_union_map_intersect_domain(adj, range);
+		other = isl_union_map_union(other, adj);
+	}
+	dep = isl_union_map_union(flow, other);
+
+	umap = isl_union_map_from_multi_union_pw_aff(partial);
+	dep = isl_union_map_apply_domain(dep, isl_union_map_copy(umap));
+	dep = isl_union_map_apply_range(dep, umap);
+
+	space = isl_space_map_from_set(space);
+	map = isl_union_map_extract_map(dep, space);
+	isl_union_map_free(dep);
+
+	map = isl_map_coalesce(map);
+
+	return map;
+}
+
+/* Given a constraint of the form
+ *
+ *	a i_0 + b i_1 >= 0
+ * or
+ *	a i_0 + b i_1 = 0
+ *
+ * use it to update one or both of the non-negative bounds
+ * in "list" = (min, max) such that
+ *
+ *	i_1 >= -min i_0
+ * and
+ *	i_1 <= max i_0
+ *
+ * If b = 0, then the constraint cannot be used.
+ * Otherwise, the constraint is equivalent to
+ *
+ *	sgn(b) i_1 >= - a/abs(b) i_0
+ * i.e.,
+ *	i_1 >= - a/abs(b) i_0
+ * or
+ *	i_1 <= a/abs(b) i_0
+ *
+ * Set the first or second element of "list" to max(0, a/abs(b)),
+ * according to the sign of "b".  Or set both in case the constraint
+ * is an equality, taking into account the sign change.
+ */
+static __isl_give isl_val_list *list_set_min_max(__isl_take isl_val_list *list,
+	__isl_keep isl_constraint *c)
+{
+	isl_val *a, *b;
+	int sign;
+	int pos;
+	isl_bool eq, is_zero, is_neg;
+
+	eq = isl_constraint_is_equality(c);
+	if (eq < 0)
+		return isl_val_list_free(list);
+
+	b = isl_constraint_get_coefficient_val(c, isl_dim_set, 1);
+	is_zero = isl_val_is_zero(b);
+	if (is_zero == isl_bool_true) {
+		isl_val_free(b);
+		return list;
+	}
+	a = isl_constraint_get_coefficient_val(c, isl_dim_set, 0);
+	sign = isl_val_sgn(b);
+	b = isl_val_abs(b);
+	a = isl_val_div(a, b);
+
+	if (eq)
+		b = isl_val_copy(a);
+
+	pos = sign > 0 ? 0 : 1;
+	is_neg = isl_val_is_neg(a);
+	if (is_neg == isl_bool_true)
+		a = isl_val_set_si(a, 0);
+	list = isl_val_list_set_val(list, pos, a);
+
+	if (!eq)
+		return is_neg < 0 ? isl_val_list_free(list) : list;
+
+	pos = 1 - pos;
+	a = isl_val_neg(b);
+	is_neg = isl_val_is_neg(a);
+	if (is_neg == isl_bool_true)
+		a = isl_val_set_si(a, 0);
+	list = isl_val_list_set_val(list, pos, a);
+
+	return is_neg < 0 ? isl_val_list_free(list) : list;
+}
+
+/* If constraint "c" passes through the origin, then try and use it
+ * to update the non-negative bounds in "list" = (min, max) such that
+ *
+ *	i_1 >= -min i_0
+ * and
+ *	i_1 <= max i_0
+ */
+static isl_stat set_min_max(__isl_take isl_constraint *c, void *user)
+{
+	isl_val *v;
+	isl_val_list **list = user;
+	isl_bool is_zero;
+
+	v = isl_constraint_get_constant_val(c);
+	is_zero = isl_val_is_zero(v);
+	isl_val_free(v);
+
+	if (is_zero == isl_bool_true)
+		*list = list_set_min_max(*list, c);
+
+	isl_constraint_free(c);
+	return is_zero < 0 ? isl_stat_error : isl_stat_ok;
+}
+
+/* Given a set of dependence distance vectors "dist", compute
+ * pair of non-negative bounds min and max such that
+ *
+ *	d_pos >= -min d_0
+ * and
+ *	d_pos <= max d_0
+ *
+ * and return the pair (min, max).
+ * If no bound can be found in either direction, then the bound
+ * is replaced by NaN.
+ *
+ * The dependence distances are first projected onto the (d_0, d_pos).
+ * Then the zero dependence distance is added and the convex hull is computed.
+ * Finally, the bounds are extracted from the constraints of the convex hull
+ * that pass through the origin.
+ */
+static __isl_give isl_val_list *min_max_dist(__isl_keep isl_set *dist, int pos)
+{
+	isl_space *space;
+	isl_basic_set *hull;
+	int dim;
+	isl_ctx *ctx;
+	isl_val *nan;
+	isl_val_list *list;
+
+	ctx = isl_set_get_ctx(dist);
+	nan = isl_val_nan(ctx);
+	list = isl_val_list_alloc(ctx, 2);
+	list = isl_val_list_add(list, isl_val_copy(nan));
+	list = isl_val_list_add(list, nan);
+
+	dist = isl_set_copy(dist);
+	dim = isl_set_dim(dist, isl_dim_set);
+	if (dist && pos >= dim)
+		isl_die(ctx, isl_error_internal, "position out of bounds",
+			dist = isl_set_free(dist));
+	dist = isl_set_project_out(dist, isl_dim_set, pos + 1, dim - (pos + 1));
+	dist = isl_set_project_out(dist, isl_dim_set, 1, pos - 1);
+
+	space = isl_set_get_space(dist);
+	dist = isl_set_union(dist, isl_set_from_point(isl_point_zero(space)));
+	dist = isl_set_remove_divs(dist);
+	hull = isl_set_convex_hull(dist);
+
+	if (isl_basic_set_foreach_constraint(hull, &set_min_max, &list) < 0)
+		list = isl_val_list_free(list);
+	isl_basic_set_free(hull);
+
+	return list;
+}
+
+/* Given a schedule node "node" that, together with its child,
+ * satisfies the input pattern for hybrid tiling, compute bounds
+ * on the relative dependence distances of the child node with
+ * respect to the parent node.  These bounds are needed to
+ * construct a hybrid tiling.
+ *
+ * First all relevant dependences are collected and mapped
+ * to the schedule space of the pair of nodes.  Then, the
+ * dependence distances are computed in this space.
+ *
+ * These dependence distances are then projected onto a two-dimensional
+ * space consisting of the single schedule dimension of the outer node
+ * and one of the schedule dimensions of the inner node.
+ * The maximal and minimal relative dependence distances are extracted
+ * from these projections.
+ * This process is repeated for each of the schedule dimensions
+ * of the inner node.  For the first dimension, both minimal and
+ * maximal relative dependence distances are stored in the result.
+ * For the other dimensions, only the minimal relative dependence
+ * distance is stored.
+ */
+__isl_give ppcg_ht_bounds *ppcg_ht_compute_bounds(struct ppcg_scop *scop,
+	__isl_keep isl_schedule_node *node)
+{
+	ppcg_ht_bounds *bnd;
+	isl_space *space;
+	isl_map *map;
+	isl_set *dist;
+	isl_val_list *pair;
+	isl_schedule_node *child;
+	int n;
+	int i, dim;
+
+	if (!scop || !node || check_input_pattern(node) < 0)
+		return NULL;
+
+	child = isl_schedule_node_get_child(node, 0);
+	space = isl_schedule_node_band_get_space(child);
+	dim = isl_schedule_node_band_n_member(child);
+	isl_schedule_node_free(child);
+	bnd = ppcg_ht_bounds_alloc(space);
+	if (!bnd)
+		return NULL;
+
+	map = collect_deps(scop, node);
+
+	dist = isl_map_deltas(map);
+	n = isl_set_dim(dist, isl_dim_param);
+	dist = isl_set_project_out(dist, isl_dim_param, 0, n);
+
+	pair = min_max_dist(dist, 1);
+	bnd = ppcg_ht_bounds_set_lower(bnd, 0, isl_val_list_get_val(pair, 0));
+	bnd = ppcg_ht_bounds_set_upper(bnd, isl_val_list_get_val(pair, 1));
+	isl_val_list_free(pair);
+
+	for (i = 1; i < dim; ++i) {
+		pair = min_max_dist(dist, 1 + i);
+		bnd = ppcg_ht_bounds_set_lower(bnd, i,
+						isl_val_list_get_val(pair, 0));
+		isl_val_list_free(pair);
+	}
+
+	isl_set_free(dist);
+
+	return bnd;
+}
+
+/* Check if all the fields of "phase" are valid, freeing "phase"
+ * if they are not.
+ */
+static __isl_give ppcg_ht_phase *check_phase(__isl_take ppcg_ht_phase *phase)
+{
+	if (!phase)
+		return NULL;
+
+	if (!phase->tiling || !phase->local_time ||
+	    !phase->shift_space || !phase->domain)
+		return ppcg_ht_phase_free(phase);
+
+	return phase;
+}
+
+/* Construct a ppcg_ht_phase object, that simply copies
+ * information from "tiling".
+ * That is, the result is defined over the "ts" space and
+ * corresponds to phase 1.
+ */
+static __isl_give ppcg_ht_phase *construct_phase(
+	__isl_keep ppcg_ht_tiling *tiling)
+{
+	isl_ctx *ctx;
+	ppcg_ht_phase *phase;
+
+	if (!tiling)
+		return NULL;
+
+	ctx = ppcg_ht_tiling_get_ctx(tiling);
+	phase = isl_calloc_type(ctx, struct ppcg_ht_phase);
+	if (!phase)
+		return NULL;
+	phase->tiling = ppcg_ht_tiling_copy(tiling);
+	phase->time_tile = isl_aff_copy(tiling->time_tile);
+	phase->local_time = isl_aff_copy(tiling->local_time);
+	phase->shift_space = isl_aff_copy(tiling->shift_space);
+	phase->domain = isl_set_copy(tiling->hex);
+
+	return check_phase(phase);
+}
+
+/* Align the parameters of the elements of "phase" to those of "space".
+ */
+static __isl_give ppcg_ht_phase *phase_align_params(
+	__isl_take ppcg_ht_phase *phase, __isl_take isl_space *space)
+{
+	if (!phase)
+		goto error;
+
+	phase->time_tile = isl_aff_align_params(phase->time_tile,
+							isl_space_copy(space));
+	phase->local_time = isl_aff_align_params(phase->local_time,
+							isl_space_copy(space));
+	phase->shift_space = isl_aff_align_params(phase->shift_space,
+							isl_space_copy(space));
+	phase->domain = isl_set_align_params(phase->domain, space);
+
+	return check_phase(phase);
+error:
+	isl_space_free(space);
+	return NULL;
+}
+
+/* Pull back "phase" over "ma".
+ * That is, take a phase defined over the range of "ma" and
+ * turn it into a phase defined over the domain of "ma".
+ */
+static __isl_give ppcg_ht_phase *pullback_phase(__isl_take ppcg_ht_phase *phase,
+	__isl_take isl_multi_aff *ma)
+{
+	phase = phase_align_params(phase, isl_multi_aff_get_space(ma));
+	if (!phase)
+		goto error;
+
+	phase->time_tile = isl_aff_pullback_multi_aff(phase->time_tile,
+							isl_multi_aff_copy(ma));
+	phase->local_time = isl_aff_pullback_multi_aff(phase->local_time,
+							isl_multi_aff_copy(ma));
+	phase->shift_space = isl_aff_pullback_multi_aff(phase->shift_space,
+							isl_multi_aff_copy(ma));
+	phase->domain = isl_set_preimage_multi_aff(phase->domain, ma);
+
+	return check_phase(phase);
+error:
+	isl_multi_aff_free(ma);
+	return NULL;
+}
+
+/* Pullback "phase" over phase->tiling->shift_phase, which shifts
+ * phase 0 to phase 1.  The pullback therefore takes a phase 1
+ * description and turns it into a phase 0 description.
+ */
+static __isl_give ppcg_ht_phase *shift_phase(__isl_take ppcg_ht_phase *phase)
+{
+	ppcg_ht_tiling *tiling;
+
+	if (!phase)
+		return NULL;
+
+	tiling = phase->tiling;
+	return pullback_phase(phase, isl_multi_aff_copy(tiling->shift_phase));
+}
+
+/* Take a "phase" defined over the ts-space and plug in the projection
+ * from the input schedule space to the ts-space.
+ * The result is then defined over this input schedule space.
+ */
+static __isl_give ppcg_ht_phase *lift_phase(__isl_take ppcg_ht_phase *phase)
+{
+	ppcg_ht_tiling *tiling;
+
+	if (!phase)
+		return NULL;
+
+	tiling = phase->tiling;
+	return pullback_phase(phase, isl_multi_aff_copy(tiling->project_ts));
+}
+
+/* Compute the shift that should be added to the space band
+ * in order to be able to apply rectangular tiling to the space.
+ * Store the shift in phase->space_shift.
+ *
+ * In the first dimension, it is equal to shift_space - s.
+ * For phase 1, this results in
+ *
+ *	(-(2 * shift_s)*T) % W
+ *
+ * In phase 0, the "s" in shift_space has been replaced by "s + shift_s",
+ * so the result is
+ *
+ *	shift_s + (-(2 * shift_s)*T) % W
+ *
+ * In the other dimensions, the shift is equal to
+ *
+ *	dl_i * local_time.
+ */
+static __isl_give ppcg_ht_phase *compute_space_shift(
+	__isl_take ppcg_ht_phase *phase)
+{
+	int i, n;
+	isl_space *space;
+	isl_local_space *ls;
+	isl_aff *aff, *s;
+	isl_multi_aff *space_shift;
+
+	if (!phase)
+		return NULL;
+
+	space = ppcg_ht_phase_get_input_space(phase);
+	space = isl_space_unwrap(space);
+	space = isl_space_range_map(space);
+
+	space_shift = isl_multi_aff_zero(space);
+	aff = isl_aff_copy(phase->shift_space);
+	ls = isl_local_space_from_space(isl_aff_get_domain_space(aff));
+	s = isl_aff_var_on_domain(ls, isl_dim_set, 1);
+	aff = isl_aff_sub(aff, s);
+	space_shift = isl_multi_aff_set_aff(space_shift, 0, aff);
+
+	n = isl_multi_aff_dim(space_shift, isl_dim_out);
+	for (i = 1; i < n; ++i) {
+		isl_val *v;
+		isl_aff *time;
+
+		v = ppcg_ht_bounds_get_lower(phase->tiling->bounds, i);
+		time = isl_aff_copy(phase->local_time);
+		time = isl_aff_scale_val(time, v);
+		space_shift = isl_multi_aff_set_aff(space_shift, i, time);
+	}
+
+	if (!space_shift)
+		return ppcg_ht_phase_free(phase);
+	phase->space_shift = space_shift;
+	return phase;
+}
+
+/* Compute the space tiling and store the result in phase->space_tile.
+ * The space tiling is of the form
+ *
+ *	[P[t] -> C[s]] -> C[floor((s + space_shift)/space_size]
+ */
+static __isl_give ppcg_ht_phase *compute_space_tile(
+	__isl_take ppcg_ht_phase *phase)
+{
+	isl_space *space;
+	isl_multi_val *space_sizes;
+	isl_multi_aff *space_shift;
+	isl_multi_aff *tile;
+
+	if (!phase)
+		return NULL;
+
+	space = ppcg_ht_phase_get_input_space(phase);
+	space = isl_space_unwrap(space);
+	tile = isl_multi_aff_range_map(space);
+	space_shift = isl_multi_aff_copy(phase->space_shift);
+	tile = isl_multi_aff_add(space_shift, tile);
+	space_sizes = isl_multi_val_copy(phase->tiling->space_sizes);
+	tile = isl_multi_aff_scale_down_multi_val(tile, space_sizes);
+	tile = isl_multi_aff_floor(tile);
+
+	if (!tile)
+		return ppcg_ht_phase_free(phase);
+	phase->space_tile = tile;
+	return phase;
+}
+
+/* Construct a representation for one of the two phase for hybrid tiling
+ * "tiling".  If "shift" is not set, then the phase is constructed
+ * directly from the hexagonal tile shape in "tiling", which represents
+ * the phase-1 tiles.  If "shift" is set, then this tile shape is shifted
+ * back over tiling->shift_phase to obtain the phase-0 tiles.
+ *
+ * First copy data from "tiling", then optionally shift the phase and
+ * finally move the tiling from the "ts" space of "tiling" to
+ * the space of the input pattern.
+ *
+ * After the basic phase has been computed, also compute
+ * the corresponding space shift.
+ */
+static __isl_give ppcg_ht_phase *ppcg_ht_tiling_compute_phase(
+	__isl_keep ppcg_ht_tiling *tiling, int shift)
+{
+	ppcg_ht_phase *phase;
+
+	phase = construct_phase(tiling);
+	if (shift)
+		phase = shift_phase(phase);
+	phase = lift_phase(phase);
+
+	phase = compute_space_shift(phase);
+	phase = compute_space_tile(phase);
+
+	return phase;
+}
+
+/* Consruct a function that is equal to the time tile of "phase0"
+ * on the domain of "phase0" and equal to the time tile of "phase1"
+ * on the domain of "phase1".
+ * The two domains are assumed to form a partition of the input
+ * schedule space.
+ */
+static __isl_give isl_pw_multi_aff *combine_time_tile(
+	__isl_keep ppcg_ht_phase *phase0, __isl_keep ppcg_ht_phase *phase1)
+{
+	isl_aff *T;
+	isl_pw_aff *time, *time1;
+
+	if (!phase0 || !phase1)
+		return NULL;
+
+	T = isl_aff_copy(phase0->time_tile);
+	time = isl_pw_aff_alloc(ppcg_ht_phase_get_domain(phase0), T);
+
+	T = isl_aff_copy(phase1->time_tile);
+	time1 = isl_pw_aff_alloc(ppcg_ht_phase_get_domain(phase1), T);
+
+	time = isl_pw_aff_union_add(time, time1);
+
+	return isl_pw_multi_aff_from_pw_aff(time);
+}
+
+/* Name used in mark nodes that contain a pointer to a ppcg_ht_phase.
+ */
+static char *ppcg_phase_name = "phase";
+
+/* Does "id" contain a pointer to a ppcg_ht_phase?
+ * That is, is it called "phase"?
+ */
+static isl_bool is_phase_id(__isl_keep isl_id *id)
+{
+	const char *name;
+
+	name = isl_id_get_name(id);
+	if (!name)
+		return isl_bool_error;
+
+	return !strcmp(name, ppcg_phase_name);
+}
+
+/* Given a mark node with an identifier that points to a ppcg_ht_phase,
+ * extract this ppcg_ht_phase pointer.
+ */
+__isl_keep ppcg_ht_phase *ppcg_ht_phase_extract_from_mark(
+	__isl_keep isl_schedule_node *node)
+{
+	isl_bool is_phase;
+	isl_id *id;
+	void *p;
+
+	if (!node)
+		return NULL;
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_mark)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_internal,
+			"not a phase mark", return NULL);
+
+	id = isl_schedule_node_mark_get_id(node);
+	is_phase = is_phase_id(id);
+	p = isl_id_get_user(id);
+	isl_id_free(id);
+
+	if (is_phase < 0)
+		return NULL;
+	if (!is_phase)
+		isl_die(isl_schedule_node_get_ctx(node), isl_error_internal,
+			"not a phase mark", return NULL);
+
+	return p;
+}
+
+/* Insert a mark node at "node" holding a pointer to "phase".
+ */
+static __isl_give isl_schedule_node *insert_phase(
+	__isl_take isl_schedule_node *node, __isl_take ppcg_ht_phase *phase)
+{
+	isl_ctx *ctx;
+	isl_id *id;
+
+	if (!node)
+		goto error;
+	ctx = isl_schedule_node_get_ctx(node);
+	id = isl_id_alloc(ctx, ppcg_phase_name, phase);
+	if (!id)
+		goto error;
+	id = isl_id_set_free_user(id, &ppcg_ht_phase_free_wrap);
+	node = isl_schedule_node_insert_mark(node, id);
+
+	return node;
+error:
+	ppcg_ht_phase_free(phase);
+	isl_schedule_node_free(node);
+	return NULL;
+}
+
+/* Construct a mapping from the elements of the original pair of bands
+ * to which tiling was applied that belong to a tile of "phase"
+ * to that tile, preserving the values for the outer bands.
+ *
+ * The mapping is of the form
+ *
+ *	[[outer] -> [P -> C]] -> [[outer] -> [tile]]
+ *
+ * where tile is defined by a concatenation of the time_tile and
+ * the space_tile.
+ */
+static __isl_give isl_map *construct_tile_map(__isl_keep ppcg_ht_phase *phase)
+{
+	int depth;
+	isl_space *space;
+	isl_multi_aff *ma;
+	isl_multi_aff *tiling;
+	isl_map *el2tile;
+
+	depth = isl_schedule_node_get_schedule_depth(
+						phase->tiling->input_node);
+	space = isl_aff_get_space(phase->time_tile);
+	space = isl_space_params(space);
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, depth);
+	space = isl_space_map_from_set(space);
+	ma = isl_multi_aff_identity(space);
+
+	tiling = isl_multi_aff_flat_range_product(
+		isl_multi_aff_from_aff(isl_aff_copy(phase->time_tile)),
+		isl_multi_aff_copy(phase->space_tile));
+	el2tile = isl_map_from_multi_aff(tiling);
+	el2tile = isl_map_intersect_domain(el2tile,
+						isl_set_copy(phase->domain));
+	el2tile = isl_map_product(isl_map_from_multi_aff(ma), el2tile);
+
+	return el2tile;
+}
+
+/* Return a description of the full tiles of "phase" at the point
+ * in the original schedule tree where the tiling was applied.
+ *
+ * First construct a mapping from the input schedule dimensions
+ * up to an including the original pair of bands to which hybrid tiling
+ * was applied to schedule dimensions in which this original pair
+ * has been replaced by the tiles.
+ * This mapping is of the form
+ *
+ *	[[outer] -> [P -> C]] -> [[outer] -> [tile]]
+ *
+ * Apply this mapping to the set of all values for the input
+ * schedule dimensions and then apply its inverse.
+ * The result is the set of values for the input schedule dimensions
+ * that would map to any of the tiles.  Subtracting from this set
+ * the set of values that are actually executed produces the set
+ * of values that belong to a tile but that are not executed.
+ * Mapping these back to the tiles produces a description of
+ * the partial tiles.  Subtracting these from the set of all tiles
+ * produces a description of the full tiles in the form
+ *
+ *	[[outer] -> [tile]]
+ */
+static __isl_give isl_set *compute_full_tile(__isl_keep ppcg_ht_phase *phase)
+{
+	isl_schedule_node *node;
+	isl_union_set *domain;
+	isl_union_map *prefix, *schedule;
+	isl_set *all, *partial, *all_el;
+	isl_map *tile2el, *el2tile;
+	isl_multi_union_pw_aff *mupa;
+
+	el2tile = construct_tile_map(phase);
+	tile2el = isl_map_reverse(isl_map_copy(el2tile));
+
+	node = phase->tiling->input_node;
+	prefix = isl_schedule_node_get_prefix_schedule_union_map(node);
+	domain = isl_schedule_node_get_domain(node);
+	mupa = isl_multi_union_pw_aff_copy(phase->tiling->input_schedule);
+	schedule = isl_union_map_from_multi_union_pw_aff(mupa);
+	schedule = isl_union_map_range_product(prefix, schedule);
+	all_el = isl_set_from_union_set(isl_union_set_apply(domain, schedule));
+	all_el = isl_set_coalesce(all_el);
+
+	all = isl_set_apply(isl_set_copy(all_el), isl_map_copy(el2tile));
+
+	partial = isl_set_copy(all);
+	partial = isl_set_apply(partial, tile2el);
+	partial = isl_set_subtract(partial, all_el);
+	partial = isl_set_apply(partial, el2tile);
+
+	return isl_set_subtract(all, partial);
+}
+
+/* Copy the AST loop types of the non-isolated part to those
+ * of the isolated part.
+ */
+static __isl_give isl_schedule_node *set_isolate_loop_type(
+	__isl_take isl_schedule_node *node)
+{
+	int i, n;
+
+	n = isl_schedule_node_band_n_member(node);
+	for (i = 0; i < n; ++i) {
+		enum isl_ast_loop_type type;
+
+		type = isl_schedule_node_band_member_get_ast_loop_type(node, i);
+		node = isl_schedule_node_band_member_set_isolate_ast_loop_type(
+								node, i, type);
+	}
+
+	return node;
+}
+
+/* If options->isolate_full_tiles is set, then mark the full tiles
+ * in "node" for isolation.  The full tiles are derived from "phase".
+ * "node" may point to a part of the tiling, e.g., the space tiling.
+ *
+ * The full tiles are originally computed in the form
+ *
+ *	[[outer] -> [tile]]
+ *
+ * However, the band that "node" points to may only contain
+ * subset of the tile dimensions.
+ * The description above is therefore treated as
+ *
+ *	[[outer] -> [before; this; after]]
+ *
+ * before is of size "pos"; this is of size "dim"; and
+ * after is of size "out - pos - dim".
+ * The after part is first project out.  Then the range is split
+ * into a before and this part and finally the before part is moved
+ * to the domain, resulting in
+ *
+ *	[[outer; before] -> [this]]
+ *
+ * This description is then used as the isolate option.
+ *
+ * The AST loop type for the isolated part is set to be the same
+ * as that of the non-isolated part.
+ */
+static __isl_give isl_schedule_node *ppcg_ht_phase_isolate_full_tile_node(
+	__isl_keep ppcg_ht_phase *phase, __isl_take isl_schedule_node *node,
+	struct ppcg_options *options)
+{
+	int in, out, pos, depth, dim;
+	isl_space *space;
+	isl_multi_aff *ma1, *ma2;
+	isl_set *tile;
+	isl_map *map;
+	isl_set *set;
+	isl_union_set *opt;
+
+	if (!options->isolate_full_tiles)
+		return node;
+
+	depth = isl_schedule_node_get_schedule_depth(node);
+	dim = isl_schedule_node_band_n_member(node);
+
+	tile = compute_full_tile(phase);
+	map = isl_set_unwrap(tile);
+	in = isl_map_dim(map, isl_dim_in);
+	out = isl_map_dim(map, isl_dim_out);
+	pos = depth - in;
+	map = isl_map_project_out(map, isl_dim_out, pos + dim,
+				out - (pos + dim));
+	space = isl_space_range(isl_map_get_space(map));
+	ma1 = isl_multi_aff_project_out_map(isl_space_copy(space),
+					   isl_dim_set, pos, dim);
+	ma2 = isl_multi_aff_project_out_map(space, isl_dim_set, 0, pos);
+	ma1 = isl_multi_aff_range_product(ma1, ma2);
+	map = isl_map_apply_range(map, isl_map_from_multi_aff(ma1));
+	map = isl_map_uncurry(map);
+	map = isl_map_flatten_domain(map);
+	set = isl_map_wrap(map);
+	set = isl_set_set_tuple_name(set, "isolate");
+
+	opt = isl_schedule_node_band_get_ast_build_options(node);
+	opt = isl_union_set_add_set(opt, set);
+	node = isl_schedule_node_band_set_ast_build_options(node, opt);
+	node = set_isolate_loop_type(node);
+
+	return node;
+}
+
+/* Insert a band node for performing the space tiling for "phase" at "node".
+ * In particular, insert a band node with partial schedule
+ *
+ *	[P[t] -> C[s]] -> C[floor((s + space_shift)/space_size)]
+ *
+ * pulled back over the input schedule.
+ * "options" determines whether full tiles should be separated
+ * from partial tiles.
+ *
+ * The first tile dimension iterates over the hexagons in the same
+ * phase, which are independent by construction.  The first dimension
+ * is therefore marked coincident.
+ * All dimensions are also marked for being generated as atomic loops
+ * because separation is usually not desirable on tile loops.
+ */
+static __isl_give isl_schedule_node *insert_space_tiling(
+	__isl_keep ppcg_ht_phase *phase, __isl_take isl_schedule_node *node,
+	struct ppcg_options *options)
+{
+	isl_multi_aff *space_tile;
+	isl_multi_union_pw_aff *mupa;
+
+	if (!phase)
+		return isl_schedule_node_free(node);
+
+	space_tile = isl_multi_aff_copy(phase->space_tile);
+	mupa = isl_multi_union_pw_aff_copy(phase->tiling->input_schedule);
+	mupa = isl_multi_union_pw_aff_apply_multi_aff(mupa, space_tile);
+	node = isl_schedule_node_insert_partial_schedule(node, mupa);
+	node = ppcg_set_schedule_node_type(node, isl_ast_loop_atomic);
+	node = ppcg_ht_phase_isolate_full_tile_node(phase, node, options);
+	node = isl_schedule_node_band_member_set_coincident(node, 0, 1);
+
+	return node;
+}
+
+/* Given a pointer "node" to (a copy of) the original child node
+ * in the input pattern, adjust its partial schedule such that
+ * it starts at zero within each tile.
+ *
+ * That is, replace "s" by (s + space_shift) % space_sizes.
+ */
+__isl_give isl_schedule_node *ppcg_ht_phase_shift_space_point(
+	__isl_keep ppcg_ht_phase *phase, __isl_take isl_schedule_node *node)
+{
+	isl_multi_val *space_sizes;
+	isl_multi_aff *space_shift;
+	isl_multi_union_pw_aff *mupa;
+
+	space_shift = isl_multi_aff_copy(phase->space_shift);
+	mupa = isl_multi_union_pw_aff_copy(phase->tiling->input_schedule);
+	mupa = isl_multi_union_pw_aff_apply_multi_aff(mupa, space_shift);
+	node = isl_schedule_node_band_shift(node, mupa);
+	space_sizes = isl_multi_val_copy(phase->tiling->space_sizes);
+	node = isl_schedule_node_band_mod(node, space_sizes);
+
+	return node;
+}
+
+/* Does
+ *
+ *	s0 > delta + 2 * {delta * h} - 1
+ *
+ * hold?
+ */
+static isl_bool wide_enough(__isl_keep isl_val *s0, __isl_keep isl_val *delta,
+	__isl_keep isl_val *h)
+{
+	isl_val *v, *v2;
+	isl_bool ok;
+
+	v = isl_val_mul(isl_val_copy(delta), isl_val_copy(h));
+	v2 = isl_val_floor(isl_val_copy(v));
+	v = isl_val_sub(v, v2);
+	v = isl_val_mul_ui(v, 2);
+	v = isl_val_add(v, isl_val_copy(delta));
+	v = isl_val_sub_ui(v, 1);
+	ok = isl_val_gt(s0, v);
+	isl_val_free(v);
+
+	return ok;
+}
+
+/* Is the tile size specified by "sizes" wide enough in the first space
+ * dimension, i.e., the base of the hexagon?  This ensures that,
+ * after hybrid tiling using "bounds" and these sizes,
+ * neighboring hexagons in the same phase are far enough apart
+ * that they do not depend on each other.
+ * The test is only meaningful if the bounds are valid.
+ *
+ * Let st be (half) the size in the time dimension and s0 the base
+ * size in the first space dimension.  Let delta be the dependence
+ * distance in either positive or negative direction.  In principle,
+ * it should be enough to have s0 + 1 > delta, i.e., s0 >= delta.
+ * However, in case of fractional delta, the tile is not extended
+ * with delta * (st - 1), but instead with floor(delta * (st - 1)).
+ * The condition therefore needs to be adjusted to
+ *
+ *	s0 + 1 > delta + 2 {delta * (st - 1)}
+ *
+ * (with {} the fractional part) to account for the two slanted sides.
+ * The condition in the paper "Hybrid Hexagonal/Classical Tiling for GPUs"
+ * translates to
+ *
+ *	s0 >= delta + {delta * (st - 1)}
+ *
+ * Since 1 > frac(delta * (st - 1)), this condition implies
+ * the condition above.
+ *
+ * The condition is checked for both directions.
+ */
+isl_bool ppcg_ht_bounds_supports_sizes(__isl_keep ppcg_ht_bounds *bounds,
+	__isl_keep isl_multi_val *sizes)
+{
+	isl_val *s0, *h;
+	isl_val *delta;
+	isl_bool ok;
+
+	ok = ppcg_ht_bounds_is_valid(bounds);
+	if (ok < 0 || !ok)
+		return ok;
+
+	h = isl_val_sub_ui(isl_multi_val_get_val(sizes, 0), 1);
+	s0 = isl_multi_val_get_val(sizes, 1);
+
+	delta = ppcg_ht_bounds_get_lower(bounds, 0);
+	ok = wide_enough(s0, delta, h);
+	isl_val_free(delta);
+
+	delta = ppcg_ht_bounds_get_upper(bounds);
+	if (ok == isl_bool_true)
+		ok = wide_enough(s0, delta, h);
+	isl_val_free(delta);
+
+	isl_val_free(s0);
+	isl_val_free(h);
+
+	return ok;
+}
+
+/* Check that the tile will be wide enough in the first space
+ * dimension, i.e., the base of the hexagon.  This ensures that
+ * neighboring hexagons in the same phase are far enough apart
+ * that they do not depend on each other.
+ *
+ * Error out if the condition fails to hold.
+ */
+static isl_stat check_width(__isl_keep ppcg_ht_bounds *bounds,
+	__isl_keep isl_multi_val *sizes)
+{
+	isl_bool ok;
+
+	ok = ppcg_ht_bounds_supports_sizes(bounds, sizes);
+
+	if (ok < 0)
+		return isl_stat_error;
+	if (!ok)
+		isl_die(isl_multi_val_get_ctx(sizes), isl_error_invalid,
+			"base of hybrid tiling hexagon not sufficiently wide",
+			return isl_stat_error);
+
+	return isl_stat_ok;
+}
+
+/* Given valid bounds on the relative dependence distances for
+ * the pair of nested nodes that "node" point to, as well as sufficiently
+ * wide tile sizes "sizes", insert the corresponding time and space tiling
+ * at "node", along with a pair of phase nodes that can be used
+ * to make further changes.
+ * The space of "sizes" should be the product of the spaces
+ * of the schedules of the pair of parent and child nodes.
+ * "options" determines whether full tiles should be separated
+ * from partial tiles.
+ *
+ * In particular, given an input of the form
+ *
+ *	P - C - ...
+ *
+ * the output has the form
+ *
+ *	        /- F0 - M0 - CT0 - P - C - ...
+ *	PT - seq
+ *	        \- F1 - M1 - CT1 - P - C - ...
+ *
+ * PT is the global time tiling.  Within each of these tiles,
+ * two phases are executed in order.  Within each phase, the schedule
+ * space is further subdivided into tiles through CT0 and CT1.
+ * The first dimension of each of these iterates over the hexagons
+ * within a phase and these are independent by construction.
+ * The F0 and F1 filters filter the statement instances that belong
+ * to the corresponding phase.  The M0 and M1 marks contain a pointer
+ * to a ppcg_ht_phase object that can be used to perform further changes.
+ *
+ * After checking that input satisfies the requirements,
+ * a data structure is constructed that represents the tiling and
+ * two additional data structures are constructed for the two phases
+ * of the tiling.  These are then used to define the filters F0 and F1 and
+ * combined to construct the time tiling PT.
+ * Then the time tiling node PT is inserted, followed by
+ * the sequence with the two filters, the CT space tiling nodes and
+ * the phase markers M.
+ */
+__isl_give isl_schedule_node *ppcg_ht_bounds_insert_tiling(
+	__isl_take ppcg_ht_bounds *bounds, __isl_take isl_multi_val *sizes,
+	__isl_take isl_schedule_node *node, struct ppcg_options *options)
+{
+	isl_ctx *ctx;
+	isl_union_set *phase0;
+	isl_union_set *phase1;
+	isl_multi_union_pw_aff *input, *dom_time;
+	isl_union_pw_multi_aff *upma;
+	isl_pw_multi_aff *time;
+	isl_union_set_list *phases;
+	ppcg_ht_tiling *tiling;
+	ppcg_ht_phase *phase_0;
+	ppcg_ht_phase *phase_1;
+
+	if (!node || !sizes || !bounds)
+		goto error;
+	if (check_input_pattern(node) < 0 || check_width(bounds, sizes) < 0)
+		goto error;
+
+	ctx = isl_schedule_node_get_ctx(node);
+
+	input = extract_input_schedule(node);
+
+	tiling = ppcg_ht_bounds_construct_tiling(bounds, node, input, sizes);
+	phase_0 = ppcg_ht_tiling_compute_phase(tiling, 1);
+	phase_1 = ppcg_ht_tiling_compute_phase(tiling, 0);
+	time = combine_time_tile(phase_0, phase_1);
+	ppcg_ht_tiling_free(tiling);
+
+	upma = isl_union_pw_multi_aff_from_multi_union_pw_aff(
+					isl_multi_union_pw_aff_copy(input));
+	phase0 = isl_union_set_from_set(ppcg_ht_phase_get_domain(phase_0));
+	phase0 = isl_union_set_preimage_union_pw_multi_aff(phase0,
+					isl_union_pw_multi_aff_copy(upma));
+	phase1 = isl_union_set_from_set(ppcg_ht_phase_get_domain(phase_1));
+	phase1 = isl_union_set_preimage_union_pw_multi_aff(phase1, upma);
+
+	phases = isl_union_set_list_alloc(ctx, 2);
+	phases = isl_union_set_list_add(phases, phase0);
+	phases = isl_union_set_list_add(phases, phase1);
+
+	dom_time = isl_multi_union_pw_aff_apply_pw_multi_aff(input, time);
+	node = isl_schedule_node_insert_partial_schedule(node, dom_time);
+
+	node = isl_schedule_node_child(node, 0);
+
+	node = isl_schedule_node_insert_sequence(node, phases);
+	node = isl_schedule_node_child(node, 0);
+	node = isl_schedule_node_child(node, 0);
+	node = insert_space_tiling(phase_0, node, options);
+	node = insert_phase(node, phase_0);
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_next_sibling(node);
+	node = isl_schedule_node_child(node, 0);
+	node = insert_space_tiling(phase_1, node, options);
+	node = insert_phase(node, phase_1);
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_parent(node);
+
+	node = isl_schedule_node_parent(node);
+
+	isl_multi_val_free(sizes);
+	return node;
+error:
+	isl_multi_val_free(sizes);
+	isl_schedule_node_free(node);
+	ppcg_ht_bounds_free(bounds);
+	return NULL;
+}
+
+/* Given a branch "node" that contains a sequence node with two phases
+ * of hybrid tiling as input, call "fn" on each of the two phase marker
+ * nodes.
+ *
+ * That is, the input is as follows
+ *
+ *	         /- F0 - M0 - ...
+ *	... - seq
+ *	         \- F1 - M1 - ...
+ *
+ * and "fn" is called on M0 and on M1.
+ */
+__isl_give isl_schedule_node *hybrid_tile_foreach_phase(
+	__isl_take isl_schedule_node *node,
+	__isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node,
+		void *user), void *user)
+{
+	int depth0, depth;
+
+	depth0 = isl_schedule_node_get_tree_depth(node);
+
+	while (node &&
+	    isl_schedule_node_get_type(node) != isl_schedule_node_sequence)
+		node = isl_schedule_node_child(node, 0);
+
+	node = isl_schedule_node_child(node, 0);
+	node = isl_schedule_node_child(node, 0);
+	if (!node)
+		return NULL;
+	node = fn(node, user);
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_next_sibling(node);
+	node = isl_schedule_node_child(node, 0);
+	if (!node)
+		return NULL;
+	node = fn(node, user);
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_parent(node);
+
+	depth = isl_schedule_node_get_tree_depth(node);
+	node = isl_schedule_node_ancestor(node, depth - depth0);
+
+	return node;
+}
+
+/* This function is called on each of the two phase marks
+ * in a hybrid tiling tree.
+ * Drop the phase mark at "node".
+ */
+static __isl_give isl_schedule_node *drop_phase_mark(
+	__isl_take isl_schedule_node *node, void *user)
+{
+	isl_id *id;
+	isl_bool is_phase;
+
+	if (isl_schedule_node_get_type(node) != isl_schedule_node_mark)
+		return node;
+
+	id = isl_schedule_node_mark_get_id(node);
+	is_phase = is_phase_id(id);
+	isl_id_free(id);
+
+	if (is_phase < 0)
+		return isl_schedule_node_free(node);
+	if (is_phase)
+		node = isl_schedule_node_delete(node);
+
+	return node;
+}
+
+/* Given a branch "node" that contains a sequence node with two phases
+ * of hybrid tiling as input, remove the two phase marker nodes.
+ *
+ * That is, the input is as follows
+ *
+ *	         /- F0 - M0 - ...
+ *	... - seq
+ *	         \- F1 - M1 - ...
+ *
+ * and the output is
+ *
+ *	         /- F0 - ...
+ *	... - seq
+ *	         \- F1 - ...
+ */
+__isl_give isl_schedule_node *hybrid_tile_drop_phase_marks(
+	__isl_take isl_schedule_node *node)
+{
+	return hybrid_tile_foreach_phase(node, &drop_phase_mark, NULL);
+}
diff --git a/final/lib/External/ppcg/hybrid.h b/final/lib/External/ppcg/hybrid.h
new file mode 100644
index 0000000..71136c6
--- /dev/null
+++ b/final/lib/External/ppcg/hybrid.h
@@ -0,0 +1,41 @@
+#ifndef HYBRID_H
+#define HYBRID_H
+
+#include <isl/val.h>
+#include <isl/schedule_node.h>
+
+#include "ppcg.h"
+
+struct ppcg_ht_bounds;
+typedef struct ppcg_ht_bounds ppcg_ht_bounds;
+
+struct ppcg_ht_phase;
+typedef struct ppcg_ht_phase ppcg_ht_phase;
+
+isl_bool ppcg_ht_has_input_pattern(__isl_keep isl_schedule_node *node);
+isl_bool ppcg_ht_parent_has_input_pattern(__isl_keep isl_schedule_node *node);
+
+__isl_give ppcg_ht_bounds *ppcg_ht_compute_bounds(struct ppcg_scop *scop,
+	__isl_keep isl_schedule_node *node);
+void ppcg_ht_bounds_dump(__isl_keep ppcg_ht_bounds *bounds);
+isl_bool ppcg_ht_bounds_is_valid(__isl_keep ppcg_ht_bounds *bounds);
+isl_bool ppcg_ht_bounds_supports_sizes(__isl_keep ppcg_ht_bounds *bounds,
+	__isl_keep isl_multi_val *sizes);
+__isl_give isl_schedule_node *ppcg_ht_bounds_insert_tiling(
+	__isl_take ppcg_ht_bounds *bounds, __isl_take isl_multi_val *sizes,
+	__isl_take isl_schedule_node *node, struct ppcg_options *options);
+__isl_null ppcg_ht_bounds *ppcg_ht_bounds_free(
+	__isl_take ppcg_ht_bounds *bounds);
+
+__isl_keep ppcg_ht_phase *ppcg_ht_phase_extract_from_mark(
+	__isl_keep isl_schedule_node *node);
+__isl_give isl_schedule_node *ppcg_ht_phase_shift_space_point(
+	__isl_keep ppcg_ht_phase *phase, __isl_take isl_schedule_node *node);
+__isl_give isl_schedule_node *hybrid_tile_foreach_phase(
+	__isl_take isl_schedule_node *node,
+	__isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node,
+		void *user), void *user);
+__isl_give isl_schedule_node *hybrid_tile_drop_phase_marks(
+	__isl_take isl_schedule_node *node);
+
+#endif
diff --git a/final/lib/External/ppcg/install-sh b/final/lib/External/ppcg/install-sh
new file mode 100644
index 0000000..a9244eb
--- /dev/null
+++ b/final/lib/External/ppcg/install-sh
@@ -0,0 +1,527 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2011-01-19.21; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" ""	$nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+  doit_exec=exec
+else
+  doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+  test "$posix_glob" != "?" || {
+    if (set -f) 2>/dev/null; then
+      posix_glob=
+    else
+      posix_glob=:
+    fi
+  }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+     --help     display this help and exit.
+     --version  display version info and exit.
+
+  -c            (ignored)
+  -C            install only if different (preserve the last data modification time)
+  -d            create directories instead of installing files.
+  -g GROUP      $chgrpprog installed files to GROUP.
+  -m MODE       $chmodprog installed files to MODE.
+  -o USER       $chownprog installed files to USER.
+  -s            $stripprog installed files.
+  -t DIRECTORY  install into DIRECTORY.
+  -T            report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+  RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+  case $1 in
+    -c) ;;
+
+    -C) copy_on_change=true;;
+
+    -d) dir_arg=true;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+	shift;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) mode=$2
+	case $mode in
+	  *' '* | *'	'* | *'
+'*	  | *'*'* | *'?'* | *'['*)
+	    echo "$0: invalid mode: $mode" >&2
+	    exit 1;;
+	esac
+	shift;;
+
+    -o) chowncmd="$chownprog $2"
+	shift;;
+
+    -s) stripcmd=$stripprog;;
+
+    -t) dst_arg=$2
+	# Protect names problematic for `test' and other utilities.
+	case $dst_arg in
+	  -* | [=\(\)!]) dst_arg=./$dst_arg;;
+	esac
+	shift;;
+
+    -T) no_target_directory=true;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    --)	shift
+	break;;
+
+    -*)	echo "$0: invalid option: $1" >&2
+	exit 1;;
+
+    *)  break;;
+  esac
+  shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dst_arg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dst_arg"
+      shift # fnord
+    fi
+    shift # arg
+    dst_arg=$arg
+    # Protect names problematic for `test' and other utilities.
+    case $dst_arg in
+      -* | [=\(\)!]) dst_arg=./$dst_arg;;
+    esac
+  done
+fi
+
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call `install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  do_exit='(exit $ret); exit $ret'
+  trap "ret=129; $do_exit" 1
+  trap "ret=130; $do_exit" 2
+  trap "ret=141; $do_exit" 13
+  trap "ret=143; $do_exit" 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
+
+for src
+do
+  # Protect names problematic for `test' and other utilities.
+  case $src in
+    -* | [=\(\)!]) src=./$src;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dst_arg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+    dst=$dst_arg
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test -n "$no_target_directory"; then
+	echo "$0: $dst_arg: Is a directory" >&2
+	exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      # Prefer dirname, but fall back on a substitute if dirname fails.
+      dstdir=`
+	(dirname "$dst") 2>/dev/null ||
+	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	     X"$dst" : 'X\(//\)[^/]' \| \
+	     X"$dst" : 'X\(//\)$' \| \
+	     X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+	echo X"$dst" |
+	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)[^/].*/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\).*/{
+		   s//\1/
+		   q
+		 }
+		 s/.*/./; q'
+      `
+
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+	# Create intermediate dirs using mode 755 as modified by the umask.
+	# This is like FreeBSD 'install' as of 1997-10-28.
+	umask=`umask`
+	case $stripcmd.$umask in
+	  # Optimize common cases.
+	  *[2367][2367]) mkdir_umask=$umask;;
+	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+	  *[0-7])
+	    mkdir_umask=`expr $umask + 22 \
+	      - $umask % 100 % 40 + $umask % 20 \
+	      - $umask % 10 % 4 + $umask % 2
+	    `;;
+	  *) mkdir_umask=$umask,go-w;;
+	esac
+
+	# With -d, create the new directory with the user-specified mode.
+	# Otherwise, rely on $mkdir_umask.
+	if test -n "$dir_arg"; then
+	  mkdir_mode=-m$mode
+	else
+	  mkdir_mode=
+	fi
+
+	posix_mkdir=false
+	case $umask in
+	  *[123567][0-7][0-7])
+	    # POSIX mkdir -p sets u+wx bits regardless of umask, which
+	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+	    ;;
+	  *)
+	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+	    if (umask $mkdir_umask &&
+		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+	    then
+	      if test -z "$dir_arg" || {
+		   # Check for POSIX incompatibilities with -m.
+		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+		   # other-writeable bit of parent directory when it shouldn't.
+		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+		   ls_ld_tmpdir=`ls -ld "$tmpdir"`
+		   case $ls_ld_tmpdir in
+		     d????-?r-*) different_mode=700;;
+		     d????-?--*) different_mode=755;;
+		     *) false;;
+		   esac &&
+		   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+		   }
+		 }
+	      then posix_mkdir=:
+	      fi
+	      rmdir "$tmpdir/d" "$tmpdir"
+	    else
+	      # Remove any dirs left behind by ancient mkdir implementations.
+	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+	    fi
+	    trap '' 0;;
+	esac;;
+    esac
+
+    if
+      $posix_mkdir && (
+	umask $mkdir_umask &&
+	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+	/*) prefix='/';;
+	[-=\(\)!]*) prefix='./';;
+	*)  prefix='';;
+      esac
+
+      eval "$initialize_posix_glob"
+
+      oIFS=$IFS
+      IFS=/
+      $posix_glob set -f
+      set fnord $dstdir
+      shift
+      $posix_glob set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+	test X"$d" = X && continue
+
+	prefix=$prefix$d
+	if test -d "$prefix"; then
+	  prefixes=
+	else
+	  if $posix_mkdir; then
+	    (umask=$mkdir_umask &&
+	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+	    # Don't fail if two instances are running concurrently.
+	    test -d "$prefix" || exit 1
+	  else
+	    case $prefix in
+	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+	      *) qprefix=$prefix;;
+	    esac
+	    prefixes="$prefixes '$qprefix'"
+	  fi
+	fi
+	prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+	# Don't fail if two instances are running concurrently.
+	(umask $mkdir_umask &&
+	 eval "\$doit_exec \$mkdirprog $prefixes") ||
+	  test -d "$dstdir" || exit 1
+	obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # If -C, don't bother to copy if it wouldn't change the file.
+    if $copy_on_change &&
+       old=`LC_ALL=C ls -dlL "$dst"	2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"	2>/dev/null` &&
+
+       eval "$initialize_posix_glob" &&
+       $posix_glob set -f &&
+       set X $old && old=:$2:$4:$5:$6 &&
+       set X $new && new=:$2:$4:$5:$6 &&
+       $posix_glob set +f &&
+
+       test "$old" = "$new" &&
+       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+    then
+      rm -f "$dsttmp"
+    else
+      # Rename the file to the real destination.
+      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+      # The rename failed, perhaps because mv can't rename something else
+      # to itself, or perhaps because mv is so ancient that it does not
+      # support -f.
+      {
+	# Now remove or move aside any old file at destination location.
+	# We try this two ways since rm can't unlink itself on some
+	# systems and the destination file might be busy for other
+	# reasons.  In this case, the final cleanup might fail but the new
+	# file should still install successfully.
+	{
+	  test ! -f "$dst" ||
+	  $doit $rmcmd -f "$dst" 2>/dev/null ||
+	  { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+	    { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+	  } ||
+	  { echo "$0: cannot unlink or rename $dst" >&2
+	    (exit 1); exit 1
+	  }
+	} &&
+
+	# Now rename the file to the real destination.
+	$doit $mvcmd "$dsttmp" "$dst"
+      }
+    fi || exit 1
+
+    trap '' 0
+  fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/final/lib/External/ppcg/ltmain.sh b/final/lib/External/ppcg/ltmain.sh
new file mode 100644
index 0000000..b9205ee
--- /dev/null
+++ b/final/lib/External/ppcg/ltmain.sh
@@ -0,0 +1,9661 @@
+
+# libtool (GNU libtool) 2.4.2
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+#       --config             show all configuration variables
+#       --debug              enable verbose shell tracing
+#   -n, --dry-run            display commands without modifying any files
+#       --features           display basic configuration information and exit
+#       --mode=MODE          use operation mode MODE
+#       --preserve-dup-deps  don't remove duplicate dependency libraries
+#       --quiet, --silent    don't print informational messages
+#       --no-quiet, --no-silent
+#                            print informational messages (default)
+#       --no-warn            don't display warning messages
+#       --tag=TAG            use configuration variables from tag TAG
+#   -v, --verbose            print more informational messages than default
+#       --no-verbose         don't print the extra informational messages
+#       --version            print version information
+#   -h, --help, --help-all   print short, long, or detailed help message
+#
+# MODE must be one of the following:
+#
+#         clean              remove files from the build directory
+#         compile            compile a source file into a libtool object
+#         execute            automatically set library path, then run a program
+#         finish             complete the installation of libtool libraries
+#         install            install libraries or executables
+#         link               create a library or an executable
+#         uninstall          remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE.  When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+#         host-triplet:	$host
+#         shell:		$SHELL
+#         compiler:		$LTCC
+#         compiler flags:		$LTCFLAGS
+#         linker:		$LD (gnu? $with_gnu_ld)
+#         $progname:	(GNU libtool) 2.4.2 Debian-2.4.2-1.2ubuntu1
+#         automake:	$automake_version
+#         autoconf:	$autoconf_version
+#
+# Report bugs to <bug-libtool@gnu.org>.
+# GNU libtool home page: <http://www.gnu.org/software/libtool/>.
+# General help using GNU software: <http://www.gnu.org/gethelp/>.
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION="2.4.2 Debian-2.4.2-1.2ubuntu1"
+TIMESTAMP=""
+package_revision=1.3337
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# NLS nuisances: We save the old values to restore during execute mode.
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+  eval "if test \"\${$lt_var+set}\" = set; then
+          save_$lt_var=\$$lt_var
+          $lt_var=C
+	  export $lt_var
+	  lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+	  lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+	fi"
+done
+LC_ALL=C
+LANGUAGE=C
+export LANGUAGE LC_ALL
+
+$lt_unset CDPATH
+
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+
+
+: ${CP="cp -f"}
+test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77	  # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" 	$lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+    func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+    if test "X$func_dirname_result" = "X${1}"; then
+      func_dirname_result="${3}"
+    else
+      func_dirname_result="$func_dirname_result${2}"
+    fi
+} # func_dirname may be replaced by extended shell implementation
+
+
+# func_basename file
+func_basename ()
+{
+    func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+} # func_basename may be replaced by extended shell implementation
+
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+    # Extract subdirectory from the argument.
+    func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
+    if test "X$func_dirname_result" = "X${1}"; then
+      func_dirname_result="${3}"
+    else
+      func_dirname_result="$func_dirname_result${2}"
+    fi
+    func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
+} # func_dirname_and_basename may be replaced by extended shell implementation
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+    case ${2} in
+      .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+      *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+    esac
+} # func_stripname may be replaced by extended shell implementation
+
+
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+		s@/\./@/@g
+		t dotsl
+		s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+#             value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+  # Start from root dir and reassemble the path.
+  func_normal_abspath_result=
+  func_normal_abspath_tpath=$1
+  func_normal_abspath_altnamespace=
+  case $func_normal_abspath_tpath in
+    "")
+      # Empty path, that just means $cwd.
+      func_stripname '' '/' "`pwd`"
+      func_normal_abspath_result=$func_stripname_result
+      return
+    ;;
+    # The next three entries are used to spot a run of precisely
+    # two leading slashes without using negated character classes;
+    # we take advantage of case's first-match behaviour.
+    ///*)
+      # Unusual form of absolute path, do nothing.
+    ;;
+    //*)
+      # Not necessarily an ordinary path; POSIX reserves leading '//'
+      # and for example Cygwin uses it to access remote file shares
+      # over CIFS/SMB, so we conserve a leading double slash if found.
+      func_normal_abspath_altnamespace=/
+    ;;
+    /*)
+      # Absolute path, do nothing.
+    ;;
+    *)
+      # Relative path, prepend $cwd.
+      func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+    ;;
+  esac
+  # Cancel out all the simple stuff to save iterations.  We also want
+  # the path to end with a slash for ease of parsing, so make sure
+  # there is one (and only one) here.
+  func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+  while :; do
+    # Processed it all yet?
+    if test "$func_normal_abspath_tpath" = / ; then
+      # If we ascended to the root using ".." the result may be empty now.
+      if test -z "$func_normal_abspath_result" ; then
+        func_normal_abspath_result=/
+      fi
+      break
+    fi
+    func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcar"`
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcdr"`
+    # Figure out what to do with it
+    case $func_normal_abspath_tcomponent in
+      "")
+        # Trailing empty path component, ignore it.
+      ;;
+      ..)
+        # Parent dir; strip last assembled component from result.
+        func_dirname "$func_normal_abspath_result"
+        func_normal_abspath_result=$func_dirname_result
+      ;;
+      *)
+        # Actual path component, append it.
+        func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+      ;;
+    esac
+  done
+  # Restore leading double-slash if one was found on entry.
+  func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+#             value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+  func_relative_path_result=
+  func_normal_abspath "$1"
+  func_relative_path_tlibdir=$func_normal_abspath_result
+  func_normal_abspath "$2"
+  func_relative_path_tbindir=$func_normal_abspath_result
+
+  # Ascend the tree starting from libdir
+  while :; do
+    # check if we have found a prefix of bindir
+    case $func_relative_path_tbindir in
+      $func_relative_path_tlibdir)
+        # found an exact match
+        func_relative_path_tcancelled=
+        break
+        ;;
+      $func_relative_path_tlibdir*)
+        # found a matching prefix
+        func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+        func_relative_path_tcancelled=$func_stripname_result
+        if test -z "$func_relative_path_result"; then
+          func_relative_path_result=.
+        fi
+        break
+        ;;
+      *)
+        func_dirname $func_relative_path_tlibdir
+        func_relative_path_tlibdir=${func_dirname_result}
+        if test "x$func_relative_path_tlibdir" = x ; then
+          # Have to descend all the way to the root!
+          func_relative_path_result=../$func_relative_path_result
+          func_relative_path_tcancelled=$func_relative_path_tbindir
+          break
+        fi
+        func_relative_path_result=../$func_relative_path_result
+        ;;
+    esac
+  done
+
+  # Now calculate path; take care to avoid doubling-up slashes.
+  func_stripname '' '/' "$func_relative_path_result"
+  func_relative_path_result=$func_stripname_result
+  func_stripname '/' '/' "$func_relative_path_tcancelled"
+  if test "x$func_stripname_result" != x ; then
+    func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+  fi
+
+  # Normalisation. If bindir is libdir, return empty string,
+  # else relative path ending with a slash; either way, target
+  # file name can be directly appended.
+  if test ! -z "$func_relative_path_result"; then
+    func_stripname './' '' "$func_relative_path_result/"
+    func_relative_path_result=$func_stripname_result
+  fi
+}
+
+# The name of this program:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+  [\\/]*|[A-Za-z]:\\*) ;;
+  *[\\/]*)
+     progdir=$func_dirname_result
+     progdir=`cd "$progdir" && pwd`
+     progpath="$progdir/$progname"
+     ;;
+  *)
+     save_IFS="$IFS"
+     IFS=${PATH_SEPARATOR-:}
+     for progdir in $PATH; do
+       IFS="$save_IFS"
+       test -x "$progdir/$progname" && break
+     done
+     IFS="$save_IFS"
+     test -n "$progdir" || progdir=`pwd`
+     progpath="$progdir/$progname"
+     ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s,[].[^$\\*\/],\\&,g'
+
+# Sed substitution that converts a w32 file name or path
+# which contains forward slashes, into one that contains
+# (escaped) backslashes.  A very naive implementation.
+lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same.  If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'.  `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+  s/$bs4/&\\
+/g
+  s/^$bs2$dollar/$bs&/
+  s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+  s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+    $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+    $opt_verbose && func_echo ${1+"$@"}
+
+    # A bug in bash halts the script if the last line of a function
+    # fails when set -e is in force, so we need another command to
+    # work around that:
+    :
+}
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+    $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+    $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+
+    # bash bug again:
+    :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+    func_error ${1+"$@"}
+    exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+    func_error ${1+"$@"}
+    func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information."  ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+    $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+    my_directory_path="$1"
+    my_dir_list=
+
+    if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+      # Protect directory names starting with `-'
+      case $my_directory_path in
+        -*) my_directory_path="./$my_directory_path" ;;
+      esac
+
+      # While some portion of DIR does not yet exist...
+      while test ! -d "$my_directory_path"; do
+        # ...make a list in topmost first order.  Use a colon delimited
+	# list incase some portion of path contains whitespace.
+        my_dir_list="$my_directory_path:$my_dir_list"
+
+        # If the last portion added has no slash in it, the list is done
+        case $my_directory_path in */*) ;; *) break ;; esac
+
+        # ...otherwise throw away the child directory and loop
+        my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+      done
+      my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+
+      save_mkdir_p_IFS="$IFS"; IFS=':'
+      for my_dir in $my_dir_list; do
+	IFS="$save_mkdir_p_IFS"
+        # mkdir can fail with a `File exist' error if two processes
+        # try to create one of the directories concurrently.  Don't
+        # stop in that case!
+        $MKDIR "$my_dir" 2>/dev/null || :
+      done
+      IFS="$save_mkdir_p_IFS"
+
+      # Bail out if we (or some other process) failed to create a directory.
+      test -d "$my_directory_path" || \
+        func_fatal_error "Failed to create \`$1'"
+    fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible.  If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+    my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+    if test "$opt_dry_run" = ":"; then
+      # Return a directory name, but don't create it in dry-run mode
+      my_tmpdir="${my_template}-$$"
+    else
+
+      # If mktemp works, use that first and foremost
+      my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+      if test ! -d "$my_tmpdir"; then
+        # Failing that, at least try and use $RANDOM to avoid a race
+        my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+        save_mktempdir_umask=`umask`
+        umask 0077
+        $MKDIR "$my_tmpdir"
+        umask $save_mktempdir_umask
+      fi
+
+      # If we're not in dry-run mode, bomb out on failure
+      test -d "$my_tmpdir" || \
+        func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+    fi
+
+    $ECHO "$my_tmpdir"
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+    case $1 in
+      *[\\\`\"\$]*)
+	func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
+      *)
+        func_quote_for_eval_unquoted_result="$1" ;;
+    esac
+
+    case $func_quote_for_eval_unquoted_result in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting, command substitution and and variable
+      # expansion for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+        ;;
+      *)
+        func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+    esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    case $1 in
+      *[\\\`\"]*)
+	my_arg=`$ECHO "$1" | $SED \
+	    -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        my_arg="$1" ;;
+    esac
+
+    case $my_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        my_arg="\"$my_arg\""
+        ;;
+    esac
+
+    func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$my_cmd"
+      my_status=$?
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.  Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$lt_user_locale
+	    $my_cmd"
+      my_status=$?
+      eval "$lt_safe_locale"
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+# func_tr_sh
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result.  All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+  case $1 in
+  [0-9]* | *[!a-zA-Z0-9_]*)
+    func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'`
+    ;;
+  * )
+    func_tr_sh_result=$1
+    ;;
+  esac
+}
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+    $opt_debug
+
+    $SED -n '/(C)/!b go
+	:more
+	/\./!{
+	  N
+	  s/\n# / /
+	  b more
+	}
+	:go
+	/^# '$PROGRAM' (GNU /,/# warranty; / {
+        s/^# //
+	s/^# *$//
+        s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+        p
+     }' < "$progpath"
+     exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+    $opt_debug
+
+    $SED -n '/^# Usage:/,/^#  *.*--help/ {
+        s/^# //
+	s/^# *$//
+	s/\$progname/'$progname'/
+	p
+    }' < "$progpath"
+    echo
+    $ECHO "run \`$progname --help | more' for full usage"
+    exit $?
+}
+
+# func_help [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
+func_help ()
+{
+    $opt_debug
+
+    $SED -n '/^# Usage:/,/# Report bugs to/ {
+	:print
+        s/^# //
+	s/^# *$//
+	s*\$progname*'$progname'*
+	s*\$host*'"$host"'*
+	s*\$SHELL*'"$SHELL"'*
+	s*\$LTCC*'"$LTCC"'*
+	s*\$LTCFLAGS*'"$LTCFLAGS"'*
+	s*\$LD*'"$LD"'*
+	s/\$with_gnu_ld/'"$with_gnu_ld"'/
+	s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/
+	s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/
+	p
+	d
+     }
+     /^# .* home page:/b print
+     /^# General help using/b print
+     ' < "$progpath"
+    ret=$?
+    if test -z "$1"; then
+      exit $ret
+    fi
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+    $opt_debug
+
+    func_error "missing argument for $1."
+    exit_cmd=exit
+}
+
+
+# func_split_short_opt shortopt
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+func_split_short_opt ()
+{
+    my_sed_short_opt='1s/^\(..\).*$/\1/;q'
+    my_sed_short_rest='1s/^..\(.*\)$/\1/;q'
+
+    func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"`
+    func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"`
+} # func_split_short_opt may be replaced by extended shell implementation
+
+
+# func_split_long_opt longopt
+# Set func_split_long_opt_name and func_split_long_opt_arg shell
+# variables after splitting LONGOPT at the `=' sign.
+func_split_long_opt ()
+{
+    my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q'
+    my_sed_long_arg='1s/^--[^=]*=//'
+
+    func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"`
+    func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"`
+} # func_split_long_opt may be replaced by extended shell implementation
+
+exit_cmd=:
+
+
+
+
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+nonopt=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+    eval "${1}=\$${1}\${2}"
+} # func_append may be replaced by extended shell implementation
+
+# func_append_quoted var value
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+func_append_quoted ()
+{
+    func_quote_for_eval "${2}"
+    eval "${1}=\$${1}\\ \$func_quote_for_eval_result"
+} # func_append_quoted may be replaced by extended shell implementation
+
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+    func_arith_result=`expr "${@}"`
+} # func_arith may be replaced by extended shell implementation
+
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+    func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len`
+} # func_len may be replaced by extended shell implementation
+
+
+# func_lo2o object
+func_lo2o ()
+{
+    func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+} # func_lo2o may be replaced by extended shell implementation
+
+
+# func_xform libobj-or-source
+func_xform ()
+{
+    func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
+} # func_xform may be replaced by extended shell implementation
+
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+    func_error ${1+"$@"}
+    func_error "See the $PACKAGE documentation for more information."
+    func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+    re_begincf='^# ### BEGIN LIBTOOL'
+    re_endcf='^# ### END LIBTOOL'
+
+    # Default configuration.
+    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+    done
+
+    exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+    echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+
+    exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+  # Global variable:
+  tagname="$1"
+
+  re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+  re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+  sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+  # Validate tagname.
+  case $tagname in
+    *[!-_A-Za-z0-9,/]*)
+      func_fatal_error "invalid tag name: $tagname"
+      ;;
+  esac
+
+  # Don't test for the "default" C tag, as we know it's
+  # there but not specially marked.
+  case $tagname in
+    CC) ;;
+    *)
+      if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+	taglist="$taglist $tagname"
+
+	# Evaluate the configuration.  Be careful to quote the path
+	# and the sed script, to avoid splitting on whitespace, but
+	# also don't use non-portable quotes within backquotes within
+	# quotes we have to do it in 2 steps:
+	extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+	eval "$extractedcf"
+      else
+	func_error "ignoring unknown tag $tagname"
+      fi
+      ;;
+  esac
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+  if test "$package_revision" != "$macro_revision"; then
+    if test "$VERSION" != "$macro_version"; then
+      if test -z "$macro_version"; then
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      else
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      fi
+    else
+      cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+    fi
+
+    exit $EXIT_MISMATCH
+  fi
+}
+
+
+# Shorthand for --mode=foo, only valid as the first argument
+case $1 in
+clean|clea|cle|cl)
+  shift; set dummy --mode clean ${1+"$@"}; shift
+  ;;
+compile|compil|compi|comp|com|co|c)
+  shift; set dummy --mode compile ${1+"$@"}; shift
+  ;;
+execute|execut|execu|exec|exe|ex|e)
+  shift; set dummy --mode execute ${1+"$@"}; shift
+  ;;
+finish|finis|fini|fin|fi|f)
+  shift; set dummy --mode finish ${1+"$@"}; shift
+  ;;
+install|instal|insta|inst|ins|in|i)
+  shift; set dummy --mode install ${1+"$@"}; shift
+  ;;
+link|lin|li|l)
+  shift; set dummy --mode link ${1+"$@"}; shift
+  ;;
+uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+  shift; set dummy --mode uninstall ${1+"$@"}; shift
+  ;;
+esac
+
+
+
+# Option defaults:
+opt_debug=:
+opt_dry_run=false
+opt_config=false
+opt_preserve_dup_deps=false
+opt_features=false
+opt_finish=false
+opt_help=false
+opt_help_all=false
+opt_silent=:
+opt_warning=:
+opt_verbose=:
+opt_silent=false
+opt_verbose=false
+
+
+# Parse options once, thoroughly.  This comes as soon as possible in the
+# script to make things like `--version' happen as quickly as we can.
+{
+  # this just eases exit handling
+  while test $# -gt 0; do
+    opt="$1"
+    shift
+    case $opt in
+      --debug|-x)	opt_debug='set -x'
+			func_echo "enabling shell trace mode"
+			$opt_debug
+			;;
+      --dry-run|--dryrun|-n)
+			opt_dry_run=:
+			;;
+      --config)
+			opt_config=:
+func_config
+			;;
+      --dlopen|-dlopen)
+			optarg="$1"
+			opt_dlopen="${opt_dlopen+$opt_dlopen
+}$optarg"
+			shift
+			;;
+      --preserve-dup-deps)
+			opt_preserve_dup_deps=:
+			;;
+      --features)
+			opt_features=:
+func_features
+			;;
+      --finish)
+			opt_finish=:
+set dummy --mode finish ${1+"$@"}; shift
+			;;
+      --help)
+			opt_help=:
+			;;
+      --help-all)
+			opt_help_all=:
+opt_help=': help-all'
+			;;
+      --mode)
+			test $# = 0 && func_missing_arg $opt && break
+			optarg="$1"
+			opt_mode="$optarg"
+case $optarg in
+  # Valid mode arguments:
+  clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+  # Catch anything else as an error
+  *) func_error "invalid argument for $opt"
+     exit_cmd=exit
+     break
+     ;;
+esac
+			shift
+			;;
+      --no-silent|--no-quiet)
+			opt_silent=false
+func_append preserve_args " $opt"
+			;;
+      --no-warning|--no-warn)
+			opt_warning=false
+func_append preserve_args " $opt"
+			;;
+      --no-verbose)
+			opt_verbose=false
+func_append preserve_args " $opt"
+			;;
+      --silent|--quiet)
+			opt_silent=:
+func_append preserve_args " $opt"
+        opt_verbose=false
+			;;
+      --verbose|-v)
+			opt_verbose=:
+func_append preserve_args " $opt"
+opt_silent=false
+			;;
+      --tag)
+			test $# = 0 && func_missing_arg $opt && break
+			optarg="$1"
+			opt_tag="$optarg"
+func_append preserve_args " $opt $optarg"
+func_enable_tag "$optarg"
+			shift
+			;;
+
+      -\?|-h)		func_usage				;;
+      --help)		func_help				;;
+      --version)	func_version				;;
+
+      # Separate optargs to long options:
+      --*=*)
+			func_split_long_opt "$opt"
+			set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"}
+			shift
+			;;
+
+      # Separate non-argument short options:
+      -\?*|-h*|-n*|-v*)
+			func_split_short_opt "$opt"
+			set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"}
+			shift
+			;;
+
+      --)		break					;;
+      -*)		func_fatal_help "unrecognized option \`$opt'" ;;
+      *)		set dummy "$opt" ${1+"$@"};	shift; break  ;;
+    esac
+  done
+
+  # Validate options:
+
+  # save first non-option argument
+  if test "$#" -gt 0; then
+    nonopt="$opt"
+    shift
+  fi
+
+  # preserve --debug
+  test "$opt_debug" = : || func_append preserve_args " --debug"
+
+  case $host in
+    *cygwin* | *mingw* | *pw32* | *cegcc*)
+      # don't eliminate duplications in $postdeps and $predeps
+      opt_duplicate_compiler_generated_deps=:
+      ;;
+    *)
+      opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+      ;;
+  esac
+
+  $opt_help || {
+    # Sanity checks first:
+    func_check_version_match
+
+    if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+      func_fatal_configuration "not configured to build any kind of library"
+    fi
+
+    # Darwin sucks
+    eval std_shrext=\"$shrext_cmds\"
+
+    # Only execute mode is allowed to have -dlopen flags.
+    if test -n "$opt_dlopen" && test "$opt_mode" != execute; then
+      func_error "unrecognized option \`-dlopen'"
+      $ECHO "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    # Change the help message to a mode-specific one.
+    generic_help="$help"
+    help="Try \`$progname --help --mode=$opt_mode' for more information."
+  }
+
+
+  # Bail if the options were screwed
+  $exit_cmd $EXIT_FAILURE
+}
+
+
+
+
+## ----------- ##
+##    Main.    ##
+## ----------- ##
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+    test -f "$1" &&
+      $SED -e 4q "$1" 2>/dev/null \
+        | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs.  To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway.  Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+    lalib_p=no
+    if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+	for lalib_p_l in 1 2 3 4
+	do
+	    read lalib_p_line
+	    case "$lalib_p_line" in
+		\#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+	    esac
+	done
+	exec 0<&5 5<&-
+    fi
+    test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+    func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+    func_ltwrapper_exec_suffix=
+    case $1 in
+    *.exe) ;;
+    *) func_ltwrapper_exec_suffix=.exe ;;
+    esac
+    $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+    func_dirname_and_basename "$1" "" "."
+    func_stripname '' '.exe' "$func_basename_result"
+    func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+    func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+    $opt_debug
+    save_ifs=$IFS; IFS='~'
+    for cmd in $1; do
+      IFS=$save_ifs
+      eval cmd=\"$cmd\"
+      func_show_eval "$cmd" "${2-:}"
+    done
+    IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)!  Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+    $opt_debug
+    case $1 in
+    */* | *\\*)	. "$1" ;;
+    *)		. "./$1" ;;
+    esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot.  Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+  func_resolve_sysroot_result=$1
+  case $func_resolve_sysroot_result in
+  =*)
+    func_stripname '=' '' "$func_resolve_sysroot_result"
+    func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+    ;;
+  esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+  case "$lt_sysroot:$1" in
+  ?*:"$lt_sysroot"*)
+    func_stripname "$lt_sysroot" '' "$1"
+    func_replace_sysroot_result="=$func_stripname_result"
+    ;;
+  *)
+    # Including no sysroot.
+    func_replace_sysroot_result=$1
+    ;;
+  esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    $opt_debug
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+	func_append_quoted CC_quoted "$arg"
+      done
+      CC_expanded=`func_echo_all $CC`
+      CC_quoted_expanded=`func_echo_all $CC_quoted`
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+	for z in $available_tags; do
+	  if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+	    # Evaluate the configuration.
+	    eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+	    CC_quoted=
+	    for arg in $CC; do
+	      # Double-quote args containing other shell metacharacters.
+	      func_append_quoted CC_quoted "$arg"
+	    done
+	    CC_expanded=`func_echo_all $CC`
+	    CC_quoted_expanded=`func_echo_all $CC_quoted`
+	    case "$@ " in
+	    " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+	    " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+	      # The compiler in the base compile command matches
+	      # the one in the tagged configuration.
+	      # Assume this is the tagged configuration we want.
+	      tagname=$z
+	      break
+	      ;;
+	    esac
+	  fi
+	done
+	# If $tagname still isn't set, then no tagged configuration
+	# was found and let the user know that the "--tag" command
+	# line option must be used.
+	if test -z "$tagname"; then
+	  func_echo "unable to infer tagged configuration"
+	  func_fatal_error "specify a tag with \`--tag'"
+#	else
+#	  func_verbose "using $tagname tagged configuration"
+	fi
+	;;
+      esac
+    fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+    write_libobj=${1}
+    if test "$build_libtool_libs" = yes; then
+      write_lobj=\'${2}\'
+    else
+      write_lobj=none
+    fi
+
+    if test "$build_old_libs" = yes; then
+      write_oldobj=\'${3}\'
+    else
+      write_oldobj=none
+    fi
+
+    $opt_dry_run || {
+      cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+      $MV "${write_libobj}T" "${write_libobj}"
+    }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+  $opt_debug
+  func_convert_core_file_wine_to_w32_result="$1"
+  if test -n "$1"; then
+    # Unfortunately, winepath does not exit with a non-zero error code, so we
+    # are forced to check the contents of stdout. On the other hand, if the
+    # command is not found, the shell will set an exit code of 127 and print
+    # *an error message* to stdout. So we must check for both error code of
+    # zero AND non-empty stdout, which explains the odd construction:
+    func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+    if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then
+      func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+        $SED -e "$lt_sed_naive_backslashify"`
+    else
+      func_convert_core_file_wine_to_w32_result=
+    fi
+  fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+  $opt_debug
+  # unfortunately, winepath doesn't convert paths, only file names
+  func_convert_core_path_wine_to_w32_result=""
+  if test -n "$1"; then
+    oldIFS=$IFS
+    IFS=:
+    for func_convert_core_path_wine_to_w32_f in $1; do
+      IFS=$oldIFS
+      func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+      if test -n "$func_convert_core_file_wine_to_w32_result" ; then
+        if test -z "$func_convert_core_path_wine_to_w32_result"; then
+          func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result"
+        else
+          func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+        fi
+      fi
+    done
+    IFS=$oldIFS
+  fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+  $opt_debug
+  if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+    func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+    if test "$?" -ne 0; then
+      # on failure, ensure result is empty
+      func_cygpath_result=
+    fi
+  else
+    func_cygpath_result=
+    func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'"
+  fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format.  Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+  $opt_debug
+  # awkward: cmd appends spaces to result
+  func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+    $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+  $opt_debug
+  if test -z "$2" && test -n "$1" ; then
+    func_error "Could not determine host file name corresponding to"
+    func_error "  \`$1'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback:
+    func_to_host_file_result="$1"
+  fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+  $opt_debug
+  if test -z "$4" && test -n "$3"; then
+    func_error "Could not determine the host path corresponding to"
+    func_error "  \`$3'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback.  This is a deliberately simplistic "conversion" and
+    # should not be "improved".  See libtool.info.
+    if test "x$1" != "x$2"; then
+      lt_replace_pathsep_chars="s|$1|$2|g"
+      func_to_host_path_result=`echo "$3" |
+        $SED -e "$lt_replace_pathsep_chars"`
+    else
+      func_to_host_path_result="$3"
+    fi
+  fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+  $opt_debug
+  case $4 in
+  $1 ) func_to_host_path_result="$3$func_to_host_path_result"
+    ;;
+  esac
+  case $4 in
+  $2 ) func_append func_to_host_path_result "$3"
+    ;;
+  esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via `$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+  $opt_debug
+  $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result.  If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+  $opt_debug
+  case ,$2, in
+    *,"$to_tool_file_cmd",*)
+      func_to_tool_file_result=$1
+      ;;
+    *)
+      $to_tool_file_cmd "$1"
+      func_to_tool_file_result=$func_to_host_file_result
+      ;;
+  esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+  func_to_host_file_result="$1"
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_to_host_file_result="$func_convert_core_msys_to_w32_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+    # LT_CYGPATH in this case.
+    func_to_host_file_result=`cygpath -m "$1"`
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format.  Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_file_wine_to_w32 "$1"
+    func_to_host_file_result="$func_convert_core_file_wine_to_w32_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_msys_to_w32_result"
+    func_to_host_file_result="$func_cygpath_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format.  Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set.  Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+    func_convert_core_file_wine_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+    func_to_host_file_result="$func_cygpath_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via `$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format.  If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+#   file name conversion function    : func_convert_file_X_to_Y ()
+#   path conversion function         : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same.  If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+  $opt_debug
+  if test -z "$to_host_path_cmd"; then
+    func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+    to_host_path_cmd="func_convert_path_${func_stripname_result}"
+  fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+  $opt_debug
+  func_init_to_host_path_cmd
+  $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+  func_to_host_path_result="$1"
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from ARG.  MSYS
+    # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+    # and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result="$func_convert_core_msys_to_w32_result"
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format.  Requires a wine environment and
+# a working winepath.  Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result="$func_convert_core_path_wine_to_w32_result"
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+    func_to_host_path_result="$func_cygpath_result"
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format.  Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set.  Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+    func_to_host_path_result="$func_cygpath_result"
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+    $opt_debug
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+    pie_flag=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+	# do not "continue".  Instead, add this to base_compile
+	lastarg="$arg"
+	arg_mode=normal
+	;;
+
+      target )
+	libobj="$arg"
+	arg_mode=normal
+	continue
+	;;
+
+      normal )
+	# Accept any command-line options.
+	case $arg in
+	-o)
+	  test -n "$libobj" && \
+	    func_fatal_error "you cannot specify \`-o' more than once"
+	  arg_mode=target
+	  continue
+	  ;;
+
+	-pie | -fpie | -fPIE)
+          func_append pie_flag " $arg"
+	  continue
+	  ;;
+
+	-shared | -static | -prefer-pic | -prefer-non-pic)
+	  func_append later " $arg"
+	  continue
+	  ;;
+
+	-no-suppress)
+	  suppress_opt=no
+	  continue
+	  ;;
+
+	-Xcompiler)
+	  arg_mode=arg  #  the next one goes into the "base_compile" arg list
+	  continue      #  The current "srcfile" will either be retained or
+	  ;;            #  replaced later.  I would guess that would be a bug.
+
+	-Wc,*)
+	  func_stripname '-Wc,' '' "$arg"
+	  args=$func_stripname_result
+	  lastarg=
+	  save_ifs="$IFS"; IFS=','
+	  for arg in $args; do
+	    IFS="$save_ifs"
+	    func_append_quoted lastarg "$arg"
+	  done
+	  IFS="$save_ifs"
+	  func_stripname ' ' '' "$lastarg"
+	  lastarg=$func_stripname_result
+
+	  # Add the arguments to base_compile.
+	  func_append base_compile " $lastarg"
+	  continue
+	  ;;
+
+	*)
+	  # Accept the current argument as the source file.
+	  # The previous "srcfile" becomes the current argument.
+	  #
+	  lastarg="$srcfile"
+	  srcfile="$arg"
+	  ;;
+	esac  #  case $arg
+	;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      func_append_quoted base_compile "$lastarg"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      func_fatal_error "you must specify an argument for -Xcompile"
+      ;;
+    target)
+      func_fatal_error "you must specify a target with \`-o'"
+      ;;
+    *)
+      # Get the name of the library object.
+      test -z "$libobj" && {
+	func_basename "$srcfile"
+	libobj="$func_basename_result"
+      }
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    case $libobj in
+    *.[cCFSifmso] | \
+    *.ada | *.adb | *.ads | *.asm | \
+    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+    *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+      func_xform "$libobj"
+      libobj=$func_xform_result
+      ;;
+    esac
+
+    case $libobj in
+    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+    *)
+      func_fatal_error "cannot determine name of library object from \`$libobj'"
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	continue
+	;;
+
+      -static)
+	build_libtool_libs=no
+	build_old_libs=yes
+	continue
+	;;
+
+      -prefer-pic)
+	pic_mode=yes
+	continue
+	;;
+
+      -prefer-non-pic)
+	pic_mode=no
+	continue
+	;;
+      esac
+    done
+
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
+      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'	 &()|`$[]' \
+      && func_warning "libobj name \`$libobj' may not contain shell special characters."
+    func_dirname_and_basename "$obj" "/" ""
+    objname="$func_basename_result"
+    xdir="$func_dirname_result"
+    lobj=${xdir}$objdir/$objname
+
+    test -z "$base_compile" && \
+      func_fatal_help "you must specify a compilation command"
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2* | cegcc*)
+      pic_mode=default
+      ;;
+    esac
+    if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test "$compiler_c_o" = no; then
+      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
+      lockfile="$output_obj.lock"
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test "$need_locks" = yes; then
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    elif test "$need_locks" = warn; then
+      if test -f "$lockfile"; then
+	$ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+      func_append removelist " $output_obj"
+      $ECHO "$srcfile" > "$lockfile"
+    fi
+
+    $opt_dry_run || $RM $removelist
+    func_append removelist " $lockfile"
+    trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+    func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+    srcfile=$func_to_tool_file_result
+    func_quote_for_eval "$srcfile"
+    qsrcfile=$func_quote_for_eval_result
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test "$pic_mode" != no; then
+	command="$base_compile $qsrcfile $pic_flag"
+      else
+	# Don't build PIC code
+	command="$base_compile $qsrcfile"
+      fi
+
+      func_mkdir_p "$xdir$objdir"
+
+      if test -z "$output_obj"; then
+	# Place PIC objects in $objdir
+	func_append command " -o $lobj"
+      fi
+
+      func_show_eval_locale "$command"	\
+          'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+	func_show_eval '$MV "$output_obj" "$lobj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+
+      # Allow error messages only from the first compilation.
+      if test "$suppress_opt" = yes; then
+	suppress_output=' >/dev/null 2>&1'
+      fi
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      if test "$pic_mode" != yes; then
+	# Don't build PIC code
+	command="$base_compile $qsrcfile$pie_flag"
+      else
+	command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test "$compiler_c_o" = yes; then
+	func_append command " -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      func_append command "$suppress_output"
+      func_show_eval_locale "$command" \
+        '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+	func_show_eval '$MV "$output_obj" "$obj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+    fi
+
+    $opt_dry_run || {
+      func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+      # Unlock the critical section if it was locked
+      if test "$need_locks" != no; then
+	removelist=$lockfile
+        $RM "$lockfile"
+      fi
+    }
+
+    exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+  test "$opt_mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+    # We need to display help for each of the modes.
+    case $opt_mode in
+      "")
+        # Generic help is extracted from the usage comments
+        # at the start of this file.
+        func_help
+        ;;
+
+      clean)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      compile)
+      $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -no-suppress      do not suppress compiler output for multiple passes
+  -prefer-pic       try to build PIC objects only
+  -prefer-non-pic   try to build non-PIC objects only
+  -shared           do not build a \`.o' file suitable for static linking
+  -static           only build a \`.o' file suitable for static linking
+  -Wc,FLAG          pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+        ;;
+
+      execute)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+        ;;
+
+      finish)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+        ;;
+
+      install)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+  -inst-prefix-dir PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+        ;;
+
+      link)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -bindir BINDIR    specify path to binaries directory (for systems where
+                    libraries must be found in the PATH setting at runtime)
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  Use a list of object files found in FILE to specify objects
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -shared           only do dynamic linking of libtool libraries
+  -shrext SUFFIX    override the standard shared library file extension
+  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-libtool-libs
+                    do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+  -weak LIBNAME     declare that the target provides the LIBNAME interface
+  -Wc,FLAG
+  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
+  -Wl,FLAG
+  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
+  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+        ;;
+
+      uninstall)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      *)
+        func_fatal_help "invalid operation mode \`$opt_mode'"
+        ;;
+    esac
+
+    echo
+    $ECHO "Try \`$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+  if test "$opt_help" = :; then
+    func_mode_help
+  else
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	func_mode_help
+      done
+    } | sed -n '1p; 2,$s/^Usage:/  or: /p'
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	echo
+	func_mode_help
+      done
+    } |
+    sed '1d
+      /^When reporting/,/^Report/{
+	H
+	d
+      }
+      $x
+      /information about other modes/d
+      /more detailed .*MODE/d
+      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+  fi
+  exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+    $opt_debug
+    # The first argument is the command name.
+    cmd="$nonopt"
+    test -z "$cmd" && \
+      func_fatal_help "you must specify a COMMAND"
+
+    # Handle -dlopen flags immediately.
+    for file in $opt_dlopen; do
+      test -f "$file" \
+	|| func_fatal_help "\`$file' is not a file"
+
+      dir=
+      case $file in
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+	# Read the libtool library.
+	dlname=
+	library_names=
+	func_source "$file"
+
+	# Skip this library if it cannot be dlopened.
+	if test -z "$dlname"; then
+	  # Warn if it was a shared library.
+	  test -n "$library_names" && \
+	    func_warning "\`$file' was not linked with \`-export-dynamic'"
+	  continue
+	fi
+
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+
+	if test -f "$dir/$objdir/$dlname"; then
+	  func_append dir "/$objdir"
+	else
+	  if test ! -f "$dir/$dlname"; then
+	    func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+	  fi
+	fi
+	;;
+
+      *.lo)
+	# Just add the directory containing the .lo file.
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+	;;
+
+      *)
+	func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+	continue
+	;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+	eval "$shlibpath_var=\"\$dir\""
+      else
+	eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -* | *.la | *.lo ) ;;
+      *)
+	# Do a test to see if this is really a libtool program.
+	if func_ltwrapper_script_p "$file"; then
+	  func_source "$file"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	elif func_ltwrapper_executable_p "$file"; then
+	  func_ltwrapper_scriptname "$file"
+	  func_source "$func_ltwrapper_scriptname_result"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	fi
+	;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      func_append_quoted args "$file"
+    done
+
+    if test "X$opt_dry_run" = Xfalse; then
+      if test -n "$shlibpath_var"; then
+	# Export the shlibpath_var.
+	eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+      do
+	eval "if test \"\${save_$lt_var+set}\" = set; then
+                $lt_var=\$save_$lt_var; export $lt_var
+	      else
+		$lt_unset $lt_var
+	      fi"
+      done
+
+      # Now prepare to actually exec the command.
+      exec_cmd="\$cmd$args"
+    else
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+	eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+	echo "export $shlibpath_var"
+      fi
+      $ECHO "$cmd$args"
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$opt_mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+    $opt_debug
+    libs=
+    libdirs=
+    admincmds=
+
+    for opt in "$nonopt" ${1+"$@"}
+    do
+      if test -d "$opt"; then
+	func_append libdirs " $opt"
+
+      elif test -f "$opt"; then
+	if func_lalib_unsafe_p "$opt"; then
+	  func_append libs " $opt"
+	else
+	  func_warning "\`$opt' is not a valid libtool archive"
+	fi
+
+      else
+	func_fatal_error "invalid argument \`$opt'"
+      fi
+    done
+
+    if test -n "$libs"; then
+      if test -n "$lt_sysroot"; then
+        sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+        sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+      else
+        sysroot_cmd=
+      fi
+
+      # Remove sysroot references
+      if $opt_dry_run; then
+        for lib in $libs; do
+          echo "removing references to $lt_sysroot and \`=' prefixes from $lib"
+        done
+      else
+        tmpdir=`func_mktempdir`
+        for lib in $libs; do
+	  sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+	    > $tmpdir/tmp-la
+	  mv -f $tmpdir/tmp-la $lib
+	done
+        ${RM}r "$tmpdir"
+      fi
+    fi
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for libdir in $libdirs; do
+	if test -n "$finish_cmds"; then
+	  # Do each command in the finish commands.
+	  func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+	fi
+	if test -n "$finish_eval"; then
+	  # Do the single finish_eval.
+	  eval cmds=\"$finish_eval\"
+	  $opt_dry_run || eval "$cmds" || func_append admincmds "
+       $cmds"
+	fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    $opt_silent && exit $EXIT_SUCCESS
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      echo "----------------------------------------------------------------------"
+      echo "Libraries have been installed in:"
+      for libdir in $libdirs; do
+	$ECHO "   $libdir"
+      done
+      echo
+      echo "If you ever happen to want to link against installed libraries"
+      echo "in a given directory, LIBDIR, you must either use libtool, and"
+      echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+      echo "flag during linking and do at least one of the following:"
+      if test -n "$shlibpath_var"; then
+	echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+	echo "     during execution"
+      fi
+      if test -n "$runpath_var"; then
+	echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+	echo "     during linking"
+      fi
+      if test -n "$hardcode_libdir_flag_spec"; then
+	libdir=LIBDIR
+	eval flag=\"$hardcode_libdir_flag_spec\"
+
+	$ECHO "   - use the \`$flag' linker flag"
+      fi
+      if test -n "$admincmds"; then
+	$ECHO "   - have your system administrator run these commands:$admincmds"
+      fi
+      if test -f /etc/ld.so.conf; then
+	echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+      fi
+      echo
+
+      echo "See any operating system documentation about shared libraries for"
+      case $host in
+	solaris2.[6789]|solaris2.1[0-9])
+	  echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+	  echo "pages."
+	  ;;
+	*)
+	  echo "more information, such as the ld(1) and ld.so(8) manual pages."
+	  ;;
+      esac
+      echo "----------------------------------------------------------------------"
+    fi
+    exit $EXIT_SUCCESS
+}
+
+test "$opt_mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+    $opt_debug
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+       # Allow the use of GNU shtool's install command.
+       case $nonopt in *shtool*) :;; *) false;; esac; then
+      # Aesthetically quote it.
+      func_quote_for_eval "$nonopt"
+      install_prog="$func_quote_for_eval_result "
+      arg=$1
+      shift
+    else
+      install_prog=
+      arg=$nonopt
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    func_quote_for_eval "$arg"
+    func_append install_prog "$func_quote_for_eval_result"
+    install_shared_prog=$install_prog
+    case " $install_prog " in
+      *[\\\ /]cp\ *) install_cp=: ;;
+      *) install_cp=false ;;
+    esac
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    no_mode=:
+    for arg
+    do
+      arg2=
+      if test -n "$dest"; then
+	func_append files " $dest"
+	dest=$arg
+	continue
+      fi
+
+      case $arg in
+      -d) isdir=yes ;;
+      -f)
+	if $install_cp; then :; else
+	  prev=$arg
+	fi
+	;;
+      -g | -m | -o)
+	prev=$arg
+	;;
+      -s)
+	stripme=" -s"
+	continue
+	;;
+      -*)
+	;;
+      *)
+	# If the previous option needed an argument, then skip it.
+	if test -n "$prev"; then
+	  if test "x$prev" = x-m && test -n "$install_override_mode"; then
+	    arg2=$install_override_mode
+	    no_mode=false
+	  fi
+	  prev=
+	else
+	  dest=$arg
+	  continue
+	fi
+	;;
+      esac
+
+      # Aesthetically quote the argument.
+      func_quote_for_eval "$arg"
+      func_append install_prog " $func_quote_for_eval_result"
+      if test -n "$arg2"; then
+	func_quote_for_eval "$arg2"
+      fi
+      func_append install_shared_prog " $func_quote_for_eval_result"
+    done
+
+    test -z "$install_prog" && \
+      func_fatal_help "you must specify an install program"
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prev' option requires an argument"
+
+    if test -n "$install_override_mode" && $no_mode; then
+      if $install_cp; then :; else
+	func_quote_for_eval "$install_override_mode"
+	func_append install_shared_prog " -m $func_quote_for_eval_result"
+      fi
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+	func_fatal_help "no file or destination specified"
+      else
+	func_fatal_help "you must specify a destination"
+      fi
+    fi
+
+    # Strip any trailing slash from the destination.
+    func_stripname '' '/' "$dest"
+    dest=$func_stripname_result
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test "$isdir" = yes; then
+      destdir="$dest"
+      destname=
+    else
+      func_dirname_and_basename "$dest" "" "."
+      destdir="$func_dirname_result"
+      destname="$func_basename_result"
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files; shift
+      test "$#" -gt 1 && \
+	func_fatal_help "\`$dest' is not a directory"
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+	case $file in
+	*.lo) ;;
+	*)
+	  func_fatal_help "\`$destdir' must be an absolute directory name"
+	  ;;
+	esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+	# Do the static libraries later.
+	func_append staticlibs " $file"
+	;;
+
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$file' is not a valid libtool archive"
+
+	library_names=
+	old_library=
+	relink_command=
+	func_source "$file"
+
+	# Add the libdir to current_libdirs if it is the destination.
+	if test "X$destdir" = "X$libdir"; then
+	  case "$current_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append current_libdirs " $libdir" ;;
+	  esac
+	else
+	  # Note the libdir as a future libdir.
+	  case "$future_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append future_libdirs " $libdir" ;;
+	  esac
+	fi
+
+	func_dirname "$file" "/" ""
+	dir="$func_dirname_result"
+	func_append dir "$objdir"
+
+	if test -n "$relink_command"; then
+	  # Determine the prefix the user has applied to our future dir.
+	  inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+	  # Don't allow the user to place us outside of our expected
+	  # location b/c this prevents finding dependent libraries that
+	  # are installed to the same prefix.
+	  # At present, this check doesn't affect windows .dll's that
+	  # are installed into $libdir/../bin (currently, that works fine)
+	  # but it's something to keep an eye on.
+	  test "$inst_prefix_dir" = "$destdir" && \
+	    func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+	  if test -n "$inst_prefix_dir"; then
+	    # Stick the inst_prefix_dir data into the link command.
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+	  else
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+	  fi
+
+	  func_warning "relinking \`$file'"
+	  func_show_eval "$relink_command" \
+	    'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+	fi
+
+	# See the names of the shared library.
+	set dummy $library_names; shift
+	if test -n "$1"; then
+	  realname="$1"
+	  shift
+
+	  srcname="$realname"
+	  test -n "$relink_command" && srcname="$realname"T
+
+	  # Install the shared library and build the symlinks.
+	  func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+	      'exit $?'
+	  tstripme="$stripme"
+	  case $host_os in
+	  cygwin* | mingw* | pw32* | cegcc*)
+	    case $realname in
+	    *.dll.a)
+	      tstripme=""
+	      ;;
+	    esac
+	    ;;
+	  esac
+	  if test -n "$tstripme" && test -n "$striplib"; then
+	    func_show_eval "$striplib $destdir/$realname" 'exit $?'
+	  fi
+
+	  if test "$#" -gt 0; then
+	    # Delete the old symlinks, and create new ones.
+	    # Try `ln -sf' first, because the `ln' binary might depend on
+	    # the symlink we replace!  Solaris /bin/ln does not understand -f,
+	    # so we also need to try rm && ln -s.
+	    for linkname
+	    do
+	      test "$linkname" != "$realname" \
+		&& func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+	    done
+	  fi
+
+	  # Do each command in the postinstall commands.
+	  lib="$destdir/$realname"
+	  func_execute_cmds "$postinstall_cmds" 'exit $?'
+	fi
+
+	# Install the pseudo-library for information purposes.
+	func_basename "$file"
+	name="$func_basename_result"
+	instname="$dir/$name"i
+	func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+	# Maybe install the static library, too.
+	test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+	;;
+
+      *.lo)
+	# Install (i.e. copy) a libtool object.
+
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# Deduce the name of the destination old-style object file.
+	case $destfile in
+	*.lo)
+	  func_lo2o "$destfile"
+	  staticdest=$func_lo2o_result
+	  ;;
+	*.$objext)
+	  staticdest="$destfile"
+	  destfile=
+	  ;;
+	*)
+	  func_fatal_help "cannot copy a libtool object to \`$destfile'"
+	  ;;
+	esac
+
+	# Install the libtool object if requested.
+	test -n "$destfile" && \
+	  func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+	# Install the old object if enabled.
+	if test "$build_old_libs" = yes; then
+	  # Deduce the name of the old-style object file.
+	  func_lo2o "$file"
+	  staticobj=$func_lo2o_result
+	  func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+	fi
+	exit $EXIT_SUCCESS
+	;;
+
+      *)
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# If the file is missing, and there is a .exe on the end, strip it
+	# because it is most likely a libtool script we actually want to
+	# install
+	stripped_ext=""
+	case $file in
+	  *.exe)
+	    if test ! -f "$file"; then
+	      func_stripname '' '.exe' "$file"
+	      file=$func_stripname_result
+	      stripped_ext=".exe"
+	    fi
+	    ;;
+	esac
+
+	# Do a test to see if this is really a libtool program.
+	case $host in
+	*cygwin* | *mingw*)
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      wrapper=$func_ltwrapper_scriptname_result
+	    else
+	      func_stripname '' '.exe' "$file"
+	      wrapper=$func_stripname_result
+	    fi
+	    ;;
+	*)
+	    wrapper=$file
+	    ;;
+	esac
+	if func_ltwrapper_script_p "$wrapper"; then
+	  notinst_deplibs=
+	  relink_command=
+
+	  func_source "$wrapper"
+
+	  # Check the variables that should have been set.
+	  test -z "$generated_by_libtool_version" && \
+	    func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+	  finalize=yes
+	  for lib in $notinst_deplibs; do
+	    # Check to see that each library is installed.
+	    libdir=
+	    if test -f "$lib"; then
+	      func_source "$lib"
+	    fi
+	    libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+	    if test -n "$libdir" && test ! -f "$libfile"; then
+	      func_warning "\`$lib' has not been installed in \`$libdir'"
+	      finalize=no
+	    fi
+	  done
+
+	  relink_command=
+	  func_source "$wrapper"
+
+	  outputname=
+	  if test "$fast_install" = no && test -n "$relink_command"; then
+	    $opt_dry_run || {
+	      if test "$finalize" = yes; then
+	        tmpdir=`func_mktempdir`
+		func_basename "$file$stripped_ext"
+		file="$func_basename_result"
+	        outputname="$tmpdir/$file"
+	        # Replace the output file specification.
+	        relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+	        $opt_silent || {
+	          func_quote_for_expand "$relink_command"
+		  eval "func_echo $func_quote_for_expand_result"
+	        }
+	        if eval "$relink_command"; then :
+	          else
+		  func_error "error: relink \`$file' with the above command before installing it"
+		  $opt_dry_run || ${RM}r "$tmpdir"
+		  continue
+	        fi
+	        file="$outputname"
+	      else
+	        func_warning "cannot relink \`$file'"
+	      fi
+	    }
+	  else
+	    # Install the binary that we compiled earlier.
+	    file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+	  fi
+	fi
+
+	# remove .exe since cygwin /usr/bin/install will append another
+	# one anyway
+	case $install_prog,$host in
+	*/usr/bin/install*,*cygwin*)
+	  case $file:$destfile in
+	  *.exe:*.exe)
+	    # this is ok
+	    ;;
+	  *.exe:*)
+	    destfile=$destfile.exe
+	    ;;
+	  *:*.exe)
+	    func_stripname '' '.exe' "$destfile"
+	    destfile=$func_stripname_result
+	    ;;
+	  esac
+	  ;;
+	esac
+	func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+	$opt_dry_run || if test -n "$outputname"; then
+	  ${RM}r "$tmpdir"
+	fi
+	;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      func_basename "$file"
+      name="$func_basename_result"
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+      func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+      tool_oldlib=$func_to_tool_file_result
+
+      func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+	func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+      fi
+
+      # Do each command in the postinstall commands.
+      func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+    done
+
+    test -n "$future_libdirs" && \
+      func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      $opt_dry_run && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$opt_mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+    $opt_debug
+    my_outputname="$1"
+    my_originator="$2"
+    my_pic_p="${3-no}"
+    my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+    my_dlsyms=
+
+    if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+      if test -n "$NM" && test -n "$global_symbol_pipe"; then
+	my_dlsyms="${my_outputname}S.c"
+      else
+	func_error "not configured to extract global symbols from dlpreopened files"
+      fi
+    fi
+
+    if test -n "$my_dlsyms"; then
+      case $my_dlsyms in
+      "") ;;
+      *.c)
+	# Discover the nlist of each of the dlfiles.
+	nlist="$output_objdir/${my_outputname}.nm"
+
+	func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+	# Parse the name list into a source file.
+	func_verbose "creating $output_objdir/$my_dlsyms"
+
+	$opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+	if test "$dlself" = yes; then
+	  func_verbose "generating symbol list for \`$output'"
+
+	  $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+	  # Add our own program objects to the symbol list.
+	  progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	  for progfile in $progfiles; do
+	    func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+	    func_verbose "extracting global C symbols from \`$func_to_tool_file_result'"
+	    $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+	  done
+
+	  if test -n "$exclude_expsyms"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  if test -n "$export_symbols_regex"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  # Prepare the list of exported symbols
+	  if test -z "$export_symbols"; then
+	    export_symbols="$output_objdir/$outputname.exp"
+	    $opt_dry_run || {
+	      $RM $export_symbols
+	      eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+	      case $host in
+	      *cygwin* | *mingw* | *cegcc* )
+                eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+	        ;;
+	      esac
+	    }
+	  else
+	    $opt_dry_run || {
+	      eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+	      eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	      case $host in
+	        *cygwin* | *mingw* | *cegcc* )
+	          eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+	          eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+	          ;;
+	      esac
+	    }
+	  fi
+	fi
+
+	for dlprefile in $dlprefiles; do
+	  func_verbose "extracting global C symbols from \`$dlprefile'"
+	  func_basename "$dlprefile"
+	  name="$func_basename_result"
+          case $host in
+	    *cygwin* | *mingw* | *cegcc* )
+	      # if an import library, we need to obtain dlname
+	      if func_win32_import_lib_p "$dlprefile"; then
+	        func_tr_sh "$dlprefile"
+	        eval "curr_lafile=\$libfile_$func_tr_sh_result"
+	        dlprefile_dlbasename=""
+	        if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+	          # Use subshell, to avoid clobbering current variable values
+	          dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+	          if test -n "$dlprefile_dlname" ; then
+	            func_basename "$dlprefile_dlname"
+	            dlprefile_dlbasename="$func_basename_result"
+	          else
+	            # no lafile. user explicitly requested -dlpreopen <import library>.
+	            $sharedlib_from_linklib_cmd "$dlprefile"
+	            dlprefile_dlbasename=$sharedlib_from_linklib_result
+	          fi
+	        fi
+	        $opt_dry_run || {
+	          if test -n "$dlprefile_dlbasename" ; then
+	            eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+	          else
+	            func_warning "Could not compute DLL name from $name"
+	            eval '$ECHO ": $name " >> "$nlist"'
+	          fi
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+	            $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+	        }
+	      else # not an import lib
+	        $opt_dry_run || {
+	          eval '$ECHO ": $name " >> "$nlist"'
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	        }
+	      fi
+	    ;;
+	    *)
+	      $opt_dry_run || {
+	        eval '$ECHO ": $name " >> "$nlist"'
+	        func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	        eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	      }
+	    ;;
+          esac
+	done
+
+	$opt_dry_run || {
+	  # Make sure we have at least an empty file.
+	  test -f "$nlist" || : > "$nlist"
+
+	  if test -n "$exclude_expsyms"; then
+	    $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+	    $MV "$nlist"T "$nlist"
+	  fi
+
+	  # Try sorting and uniquifying the output.
+	  if $GREP -v "^: " < "$nlist" |
+	      if sort -k 3 </dev/null >/dev/null 2>&1; then
+		sort -k 3
+	      else
+		sort +2
+	      fi |
+	      uniq > "$nlist"S; then
+	    :
+	  else
+	    $GREP -v "^: " < "$nlist" > "$nlist"S
+	  fi
+
+	  if test -f "$nlist"S; then
+	    eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+	  else
+	    echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+	  fi
+
+	  echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols.  */
+typedef struct {
+  const char *name;
+  void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+  { \"$my_originator\", (void *) 0 },"
+
+	  case $need_lib_prefix in
+	  no)
+	    eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  *)
+	    eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  esac
+	  echo >> "$output_objdir/$my_dlsyms" "\
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+	} # !$opt_dry_run
+
+	pic_flag_for_symtable=
+	case "$compile_command " in
+	*" -static "*) ;;
+	*)
+	  case $host in
+	  # compiling the symbol table file with pic_flag works around
+	  # a FreeBSD bug that causes programs to crash when -lm is
+	  # linked before any other PIC object.  But we must not use
+	  # pic_flag when linking with -static.  The problem exists in
+	  # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+	  *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+	    pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+	  *-*-hpux*)
+	    pic_flag_for_symtable=" $pic_flag"  ;;
+	  *)
+	    if test "X$my_pic_p" != Xno; then
+	      pic_flag_for_symtable=" $pic_flag"
+	    fi
+	    ;;
+	  esac
+	  ;;
+	esac
+	symtab_cflags=
+	for arg in $LTCFLAGS; do
+	  case $arg in
+	  -pie | -fpie | -fPIE) ;;
+	  *) func_append symtab_cflags " $arg" ;;
+	  esac
+	done
+
+	# Now compile the dynamic symbol file.
+	func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+	# Clean up the generated files.
+	func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+	# Transform the symbol file into the correct name.
+	symfileobj="$output_objdir/${my_outputname}S.$objext"
+	case $host in
+	*cygwin* | *mingw* | *cegcc* )
+	  if test -f "$output_objdir/$my_outputname.def"; then
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	  else
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  fi
+	  ;;
+	*)
+	  compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  ;;
+	esac
+	;;
+      *)
+	func_fatal_error "unknown suffix for \`$my_dlsyms'"
+	;;
+      esac
+    else
+      # We keep going just in case the user didn't refer to
+      # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+      # really was required.
+
+      # Nullify the symbol file.
+      compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+    fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+  $opt_debug
+  win32_libid_type="unknown"
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+      func_to_tool_file "$1" func_convert_file_msys_to_w32
+      win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+	$SED -n -e '
+	    1,100{
+		/ I /{
+		    s,.*,import,
+		    p
+		    q
+		}
+	    }'`
+      case $win32_nmres in
+      import*)  win32_libid_type="x86 archive import";;
+      *)        win32_libid_type="x86 archive static";;
+      esac
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+  $opt_debug
+  sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+  $opt_debug
+  match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+  $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+    $SED '/^Contents of section '"$match_literal"':/{
+      # Place marker at beginning of archive member dllname section
+      s/.*/====MARK====/
+      p
+      d
+    }
+    # These lines can sometimes be longer than 43 characters, but
+    # are always uninteresting
+    /:[	 ]*file format pe[i]\{,1\}-/d
+    /^In archive [^:]*:/d
+    # Ensure marker is printed
+    /^====MARK====/p
+    # Remove all lines with less than 43 characters
+    /^.\{43\}/!d
+    # From remaining lines, remove first 43 characters
+    s/^.\{43\}//' |
+    $SED -n '
+      # Join marker and all lines until next marker into a single line
+      /^====MARK====/ b para
+      H
+      $ b para
+      b
+      :para
+      x
+      s/\n//g
+      # Remove the marker
+      s/^====MARK====//
+      # Remove trailing dots and whitespace
+      s/[\. \t]*$//
+      # Print
+      /./p' |
+    # we now have a list, one entry per line, of the stringified
+    # contents of the appropriate section of all members of the
+    # archive which possess that section. Heuristic: eliminate
+    # all those which have a first or second character that is
+    # a '.' (that is, objdump's representation of an unprintable
+    # character.) This should work for all archives with less than
+    # 0x302f exports -- but will fail for DLLs whose name actually
+    # begins with a literal '.' or a single character followed by
+    # a '.'.
+    #
+    # Of those that remain, print the first one.
+    $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+  $opt_debug
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+  test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+  $opt_debug
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+  test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+  $opt_debug
+  if func_cygming_gnu_implib_p "$1" ; then
+    # binutils import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+  elif func_cygming_ms_implib_p "$1" ; then
+    # ms-generated import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+  else
+    # unknown
+    sharedlib_from_linklib_result=""
+  fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    $opt_debug
+    f_ex_an_ar_dir="$1"; shift
+    f_ex_an_ar_oldlib="$1"
+    if test "$lock_old_archive_extraction" = yes; then
+      lockfile=$f_ex_an_ar_oldlib.lock
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    fi
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+		   'stat=$?; rm -f "$lockfile"; exit $stat'
+    if test "$lock_old_archive_extraction" = yes; then
+      $opt_dry_run || rm -f "$lockfile"
+    fi
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+    fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    $opt_debug
+    my_gentop="$1"; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=""
+    my_xlib=""
+    my_xabs=""
+    my_xdir=""
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+	[\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+	*) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      func_basename "$my_xlib"
+      my_xlib="$func_basename_result"
+      my_xlib_u=$my_xlib
+      while :; do
+        case " $extracted_archives " in
+	*" $my_xlib_u "*)
+	  func_arith $extracted_serial + 1
+	  extracted_serial=$func_arith_result
+	  my_xlib_u=lt$extracted_serial-$my_xlib ;;
+	*) break ;;
+	esac
+      done
+      extracted_archives="$extracted_archives $my_xlib_u"
+      my_xdir="$my_gentop/$my_xlib_u"
+
+      func_mkdir_p "$my_xdir"
+
+      case $host in
+      *-darwin*)
+	func_verbose "Extracting $my_xabs"
+	# Do not bother doing anything if just a dry run
+	$opt_dry_run || {
+	  darwin_orig_dir=`pwd`
+	  cd $my_xdir || exit $?
+	  darwin_archive=$my_xabs
+	  darwin_curdir=`pwd`
+	  darwin_base_archive=`basename "$darwin_archive"`
+	  darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+	  if test -n "$darwin_arches"; then
+	    darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+	    darwin_arch=
+	    func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+	    for darwin_arch in  $darwin_arches ; do
+	      func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+	      cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+	      cd "$darwin_curdir"
+	      $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+	    done # $darwin_arches
+            ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+	    darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+	    darwin_file=
+	    darwin_files=
+	    for darwin_file in $darwin_filelist; do
+	      darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+	      $LIPO -create -output "$darwin_file" $darwin_files
+	    done # $darwin_filelist
+	    $RM -rf unfat-$$
+	    cd "$darwin_orig_dir"
+	  else
+	    cd $darwin_orig_dir
+	    func_extract_an_archive "$my_xdir" "$my_xabs"
+	  fi # $darwin_arches
+	} # !$opt_dry_run
+	;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+	;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+    done
+
+    func_extract_archives_result="$my_oldobjs"
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable.  Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take.  If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory.  This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+	func_emit_wrapper_arg1=${1-no}
+
+	$ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variables:
+  generated_by_libtool_version='$macro_version'
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$ECHO are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    file=\"\$0\""
+
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+    $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+    ECHO=\"$qECHO\"
+  fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+  lt_script_arg0=\$0
+  shift
+  for lt_opt
+  do
+    case \"\$lt_opt\" in
+    --lt-debug) lt_option_debug=1 ;;
+    --lt-dump-script)
+        lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+        test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+        lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+        cat \"\$lt_dump_D/\$lt_dump_F\"
+        exit 0
+      ;;
+    --lt-*)
+        \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+        exit 1
+      ;;
+    esac
+  done
+
+  # Print the debug banner immediately:
+  if test -n \"\$lt_option_debug\"; then
+    echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2
+  fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+  lt_dump_args_N=1;
+  for lt_arg
+  do
+    \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\"
+    lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+  done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+  case $host in
+  # Backslashes separate directories on plain windows
+  *-*-mingw | *-*-os2* | *-cegcc*)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+    ;;
+
+  *)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+    ;;
+  esac
+  $ECHO "\
+      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+      exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+  case \" \$* \" in
+  *\\ --lt-*)
+    for lt_wr_arg
+    do
+      case \$lt_wr_arg in
+      --lt-*) ;;
+      *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+      esac
+      shift
+    done ;;
+  esac
+  func_exec_program_core \${1+\"\$@\"}
+}
+
+  # Parse options
+  func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+  done
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+  if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+    # special case for '.'
+    if test \"\$thisdir\" = \".\"; then
+      thisdir=\`pwd\`
+    fi
+    # remove .libs from thisdir
+    case \"\$thisdir\" in
+    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+    $objdir )   thisdir=. ;;
+    esac
+  fi
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+	if test "$fast_install" = yes; then
+	  $ECHO "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" ||
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $MKDIR \"\$progdir\"
+    else
+      $RM \"\$progdir/\$file\"
+    fi"
+
+	  $ECHO "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+	$ECHO \"\$relink_command_output\" >&2
+	$RM \"\$progdir/\$file\"
+	exit 1
+      fi
+    fi
+
+    $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $RM \"\$progdir/\$program\";
+      $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $RM \"\$progdir/\$file\"
+  fi"
+	else
+	  $ECHO "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+	fi
+
+	$ECHO "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+	# fixup the dll searchpath if we need to.
+	#
+	# Fix the DLL searchpath if we need to.  Do this before prepending
+	# to shlibpath, because on Windows, both are PATH and uninstalled
+	# libraries must come first.
+	if test -n "$dllsearchpath"; then
+	  $ECHO "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+	fi
+
+	# Export our shlibpath_var if we have one.
+	if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	  $ECHO "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+	fi
+
+	$ECHO "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+      func_exec_program \${1+\"\$@\"}
+    fi
+  else
+    # The program doesn't exist.
+    \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+    \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+    \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+	cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+*/
+EOF
+	    cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+#  include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+#  define _INTPTR_T_DEFINED
+#  define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+  defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+#  define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+	(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#if defined(LT_DEBUGWRAPPER)
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+	    cat <<EOF
+volatile const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+	    if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+              func_to_host_path "$temp_rpath"
+	      cat <<EOF
+const char * LIB_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * LIB_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test -n "$dllsearchpath"; then
+              func_to_host_path "$dllsearchpath:"
+	      cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test "$fast_install" = yes; then
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+	    else
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+	    fi
+
+
+	    cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX         "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt            = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int  newargc;
+  char *tmp_pathspec;
+  char *actual_cwrapper_path;
+  char *actual_cwrapper_name;
+  char *target_name;
+  char *lt_argv_zero;
+  intptr_t rval = 127;
+
+  int i;
+
+  program_name = (char *) xstrdup (base_name (argv[0]));
+  newargz = XMALLOC (char *, argc + 1);
+
+  /* very simple arg parsing; don't want to rely on getopt
+   * also, copy all non cwrapper options to newargz, except
+   * argz[0], which is handled differently
+   */
+  newargc=0;
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], dumpscript_opt) == 0)
+	{
+EOF
+	    case "$host" in
+	      *mingw* | *cygwin* )
+		# make stdout use "unix" line endings
+		echo "          setmode(1,_O_BINARY);"
+		;;
+	      esac
+
+	    cat <<"EOF"
+	  lt_dump_script (stdout);
+	  return 0;
+	}
+      if (strcmp (argv[i], debug_opt) == 0)
+	{
+          lt_debug = 1;
+          continue;
+	}
+      if (strcmp (argv[i], ltwrapper_option_prefix) == 0)
+        {
+          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+             namespace, but it is not one of the ones we know about and
+             have already dealt with, above (inluding dump-script), then
+             report an error. Otherwise, targets might begin to believe
+             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+             namespace. The first time any user complains about this, we'll
+             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+             or a configure.ac-settable value.
+           */
+          lt_fatal (__FILE__, __LINE__,
+		    "unrecognized %s option: '%s'",
+                    ltwrapper_option_prefix, argv[i]);
+        }
+      /* otherwise ... */
+      newargz[++newargc] = xstrdup (argv[i]);
+    }
+  newargz[++newargc] = NULL;
+
+EOF
+	    cat <<EOF
+  /* The GNU banner must be the first non-error debug message */
+  lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\n");
+EOF
+	    cat <<"EOF"
+  lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+  tmp_pathspec = find_executable (argv[0]);
+  if (tmp_pathspec == NULL)
+    lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (before symlink chase) at: %s\n",
+		  tmp_pathspec);
+
+  actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (after symlink chase) at: %s\n",
+		  actual_cwrapper_path);
+  XFREE (tmp_pathspec);
+
+  actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+  strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+  /* wrapper name transforms */
+  strendzap (actual_cwrapper_name, ".exe");
+  tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+  XFREE (actual_cwrapper_name);
+  actual_cwrapper_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  /* target_name transforms -- use actual target program name; might have lt- prefix */
+  target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+  strendzap (target_name, ".exe");
+  tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+  XFREE (target_name);
+  target_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(main) libtool target name: %s\n",
+		  target_name);
+EOF
+
+	    cat <<EOF
+  newargz[0] =
+    XMALLOC (char, (strlen (actual_cwrapper_path) +
+		    strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+  strcpy (newargz[0], actual_cwrapper_path);
+  strcat (newargz[0], "$objdir");
+  strcat (newargz[0], "/");
+EOF
+
+	    cat <<"EOF"
+  /* stop here, and copy so we don't have to do this twice */
+  tmp_pathspec = xstrdup (newargz[0]);
+
+  /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+  strcat (newargz[0], actual_cwrapper_name);
+
+  /* DO want the lt- prefix here if it exists, so use target_name */
+  lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+  XFREE (tmp_pathspec);
+  tmp_pathspec = NULL;
+EOF
+
+	    case $host_os in
+	      mingw*)
+	    cat <<"EOF"
+  {
+    char* p;
+    while ((p = strchr (newargz[0], '\\')) != NULL)
+      {
+	*p = '/';
+      }
+    while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+      {
+	*p = '/';
+      }
+  }
+EOF
+	    ;;
+	    esac
+
+	    cat <<"EOF"
+  XFREE (target_name);
+  XFREE (actual_cwrapper_path);
+  XFREE (actual_cwrapper_name);
+
+  lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+  lt_setenv ("DUALCASE", "1");  /* for MSK sh */
+  /* Update the DLL searchpath.  EXE_PATH_VALUE ($dllsearchpath) must
+     be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+     because on Windows, both *_VARNAMEs are PATH but uninstalled
+     libraries must come first. */
+  lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+  lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+  lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+		  nonnull (lt_argv_zero));
+  for (i = 0; i < newargc; i++)
+    {
+      lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+		      i, nonnull (newargz[i]));
+    }
+
+EOF
+
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+  /* execv doesn't actually work on mingw as expected on unix */
+  newargz = prepare_spawn (newargz);
+  rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+  if (rval == -1)
+    {
+      /* failed to start process */
+      lt_debugprintf (__FILE__, __LINE__,
+		      "(main) failed to launch target \"%s\": %s\n",
+		      lt_argv_zero, nonnull (strerror (errno)));
+      return 127;
+    }
+  return rval;
+EOF
+		;;
+	      *)
+		cat <<"EOF"
+  execv (lt_argv_zero, newargz);
+  return rval; /* =127, but avoids unused variable warning */
+EOF
+		;;
+	    esac
+
+	    cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+  void *p = (void *) malloc (num);
+  if (!p)
+    lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+			  string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+  const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return base;
+}
+
+int
+check_executable (const char *path)
+{
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if ((stat (path, &st) >= 0)
+      && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+    return 1;
+  else
+    return 0;
+}
+
+int
+make_executable (const char *path)
+{
+  int rval = 0;
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if (stat (path, &st) >= 0)
+    {
+      rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+    }
+  return rval;
+}
+
+/* Searches for the full path of the wrapper.  Returns
+   newly allocated full path name if found, NULL otherwise
+   Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+  int has_slash = 0;
+  const char *p;
+  const char *p_next;
+  /* static buffer for getcwd */
+  char tmp[LT_PATHMAX + 1];
+  int tmp_len;
+  char *concat_name;
+
+  lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+                  nonempty (wrapper));
+
+  if ((wrapper == NULL) || (*wrapper == '\0'))
+    return NULL;
+
+  /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+    {
+      concat_name = xstrdup (wrapper);
+      if (check_executable (concat_name))
+	return concat_name;
+      XFREE (concat_name);
+    }
+  else
+    {
+#endif
+      if (IS_DIR_SEPARATOR (wrapper[0]))
+	{
+	  concat_name = xstrdup (wrapper);
+	  if (check_executable (concat_name))
+	    return concat_name;
+	  XFREE (concat_name);
+	}
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+    }
+#endif
+
+  for (p = wrapper; *p; p++)
+    if (*p == '/')
+      {
+	has_slash = 1;
+	break;
+      }
+  if (!has_slash)
+    {
+      /* no slashes; search PATH */
+      const char *path = getenv ("PATH");
+      if (path != NULL)
+	{
+	  for (p = path; *p; p = p_next)
+	    {
+	      const char *q;
+	      size_t p_len;
+	      for (q = p; *q; q++)
+		if (IS_PATH_SEPARATOR (*q))
+		  break;
+	      p_len = q - p;
+	      p_next = (*q == '\0' ? q : q + 1);
+	      if (p_len == 0)
+		{
+		  /* empty path: current directory */
+		  if (getcwd (tmp, LT_PATHMAX) == NULL)
+		    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+                              nonnull (strerror (errno)));
+		  tmp_len = strlen (tmp);
+		  concat_name =
+		    XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, tmp, tmp_len);
+		  concat_name[tmp_len] = '/';
+		  strcpy (concat_name + tmp_len + 1, wrapper);
+		}
+	      else
+		{
+		  concat_name =
+		    XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, p, p_len);
+		  concat_name[p_len] = '/';
+		  strcpy (concat_name + p_len + 1, wrapper);
+		}
+	      if (check_executable (concat_name))
+		return concat_name;
+	      XFREE (concat_name);
+	    }
+	}
+      /* not found in PATH; assume curdir */
+    }
+  /* Relative path | not found in path: prepend cwd */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+              nonnull (strerror (errno)));
+  tmp_len = strlen (tmp);
+  concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+  memcpy (concat_name, tmp, tmp_len);
+  concat_name[tmp_len] = '/';
+  strcpy (concat_name + tmp_len + 1, wrapper);
+
+  if (check_executable (concat_name))
+    return concat_name;
+  XFREE (concat_name);
+  return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+  return xstrdup (pathspec);
+#else
+  char buf[LT_PATHMAX];
+  struct stat s;
+  char *tmp_pathspec = xstrdup (pathspec);
+  char *p;
+  int has_symlinks = 0;
+  while (strlen (tmp_pathspec) && !has_symlinks)
+    {
+      lt_debugprintf (__FILE__, __LINE__,
+		      "checking path component for symlinks: %s\n",
+		      tmp_pathspec);
+      if (lstat (tmp_pathspec, &s) == 0)
+	{
+	  if (S_ISLNK (s.st_mode) != 0)
+	    {
+	      has_symlinks = 1;
+	      break;
+	    }
+
+	  /* search backwards for last DIR_SEPARATOR */
+	  p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+	  while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    p--;
+	  if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    {
+	      /* no more DIR_SEPARATORS left */
+	      break;
+	    }
+	  *p = '\0';
+	}
+      else
+	{
+	  lt_fatal (__FILE__, __LINE__,
+		    "error accessing file \"%s\": %s",
+		    tmp_pathspec, nonnull (strerror (errno)));
+	}
+    }
+  XFREE (tmp_pathspec);
+
+  if (!has_symlinks)
+    {
+      return xstrdup (pathspec);
+    }
+
+  tmp_pathspec = realpath (pathspec, buf);
+  if (tmp_pathspec == 0)
+    {
+      lt_fatal (__FILE__, __LINE__,
+		"could not follow symlinks for %s", pathspec);
+    }
+  return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert (str != NULL);
+  assert (pat != NULL);
+
+  len = strlen (str);
+  patlen = strlen (pat);
+
+  if (patlen <= len)
+    {
+      str += len - patlen;
+      if (strcmp (str, pat) == 0)
+	*str = '\0';
+    }
+  return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+  va_list args;
+  if (lt_debug)
+    {
+      (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+      va_start (args, fmt);
+      (void) vfprintf (stderr, fmt, args);
+      va_end (args);
+    }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+	       int line, const char *mode,
+	       const char *message, va_list ap)
+{
+  fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+  va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+  return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+  return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_setenv) setting '%s' to '%s'\n",
+                  nonnull (name), nonnull (value));
+  {
+#ifdef HAVE_SETENV
+    /* always make a copy, for consistency with !HAVE_SETENV */
+    char *str = xstrdup (value);
+    setenv (name, str, 1);
+#else
+    int len = strlen (name) + 1 + strlen (value) + 1;
+    char *str = XMALLOC (char, len);
+    sprintf (str, "%s=%s", name, value);
+    if (putenv (str) != EXIT_SUCCESS)
+      {
+        XFREE (str);
+      }
+#endif
+  }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+  char *new_value;
+  if (orig_value && *orig_value)
+    {
+      int orig_value_len = strlen (orig_value);
+      int add_len = strlen (add);
+      new_value = XMALLOC (char, add_len + orig_value_len + 1);
+      if (to_end)
+        {
+          strcpy (new_value, orig_value);
+          strcpy (new_value + orig_value_len, add);
+        }
+      else
+        {
+          strcpy (new_value, add);
+          strcpy (new_value + add_len, orig_value);
+        }
+    }
+  else
+    {
+      new_value = xstrdup (add);
+    }
+  return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      /* some systems can't cope with a ':'-terminated path #' */
+      int len = strlen (new_value);
+      while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+        {
+          new_value[len-1] = '\0';
+        }
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+EOF
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+   Note that spawn() does not by itself call the command interpreter
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+         GetVersionEx(&v);
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+      }) ? "cmd.exe" : "command.com").
+   Instead it simply concatenates the arguments, separated by ' ', and calls
+   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+   special way:
+   - Space and tab are interpreted as delimiters. They are not treated as
+     delimiters if they are surrounded by double quotes: "...".
+   - Unescaped double quotes are removed from the input. Their only effect is
+     that within double quotes, space and tab are treated like normal
+     characters.
+   - Backslashes not followed by double quotes are not special.
+   - But 2*n+1 backslashes followed by a double quote become
+     n backslashes followed by a double quote (n >= 0):
+       \" -> "
+       \\\" -> \"
+       \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+  size_t argc;
+  char **new_argv;
+  size_t i;
+
+  /* Count number of arguments.  */
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  /* Allocate new argument vector.  */
+  new_argv = XMALLOC (char *, argc + 1);
+
+  /* Put quoted arguments into the new argument vector.  */
+  for (i = 0; i < argc; i++)
+    {
+      const char *string = argv[i];
+
+      if (string[0] == '\0')
+	new_argv[i] = xstrdup ("\"\"");
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+	{
+	  int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+	  size_t length;
+	  unsigned int backslashes;
+	  const char *s;
+	  char *quoted_string;
+	  char *p;
+
+	  length = 0;
+	  backslashes = 0;
+	  if (quote_around)
+	    length++;
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		length += backslashes + 1;
+	      length++;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    length += backslashes + 1;
+
+	  quoted_string = XMALLOC (char, length + 1);
+
+	  p = quoted_string;
+	  backslashes = 0;
+	  if (quote_around)
+	    *p++ = '"';
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		{
+		  unsigned int j;
+		  for (j = backslashes + 1; j > 0; j--)
+		    *p++ = '\\';
+		}
+	      *p++ = c;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    {
+	      unsigned int j;
+	      for (j = backslashes; j > 0; j--)
+		*p++ = '\\';
+	      *p++ = '"';
+	    }
+	  *p = '\0';
+
+	  new_argv[i] = quoted_string;
+	}
+      else
+	new_argv[i] = (char *) string;
+    }
+  new_argv[argc] = NULL;
+
+  return new_argv;
+}
+EOF
+		;;
+	    esac
+
+            cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+	    func_emit_wrapper yes |
+	      $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/  fputs ("\1", f);/p
+g
+D'
+            cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+    $opt_debug
+    case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+    *import*) : ;;
+    *) false ;;
+    esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+    $opt_debug
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # which system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll which has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args=$nonopt
+    base_compile="$nonopt $@"
+    compile_command=$nonopt
+    finalize_command=$nonopt
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+    new_inherited_linker_flags=
+
+    avoid_version=no
+    bindir=
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=no
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+    weak_libs=
+    single_module="${wl}-single_module"
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	break
+	;;
+      -all-static | -static | -static-libtool-libs)
+	case $arg in
+	-all-static)
+	  if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+	    func_warning "complete static linking is impossible in this configuration"
+	  fi
+	  if test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	-static)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=built
+	  ;;
+	-static-libtool-libs)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	esac
+	build_libtool_libs=no
+	build_old_libs=yes
+	break
+	;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg="$1"
+      shift
+      func_quote_for_eval "$arg"
+      qarg=$func_quote_for_eval_unquoted_result
+      func_append libtool_args " $func_quote_for_eval_result"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+	case $prev in
+	output)
+	  func_append compile_command " @OUTPUT@"
+	  func_append finalize_command " @OUTPUT@"
+	  ;;
+	esac
+
+	case $prev in
+	bindir)
+	  bindir="$arg"
+	  prev=
+	  continue
+	  ;;
+	dlfiles|dlprefiles)
+	  if test "$preload" = no; then
+	    # Add the symbol object into the linking commands.
+	    func_append compile_command " @SYMFILE@"
+	    func_append finalize_command " @SYMFILE@"
+	    preload=yes
+	  fi
+	  case $arg in
+	  *.la | *.lo) ;;  # We handle these cases below.
+	  force)
+	    if test "$dlself" = no; then
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  self)
+	    if test "$prev" = dlprefiles; then
+	      dlself=yes
+	    elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+	      dlself=yes
+	    else
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  *)
+	    if test "$prev" = dlfiles; then
+	      func_append dlfiles " $arg"
+	    else
+	      func_append dlprefiles " $arg"
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  esac
+	  ;;
+	expsyms)
+	  export_symbols="$arg"
+	  test -f "$arg" \
+	    || func_fatal_error "symbol file \`$arg' does not exist"
+	  prev=
+	  continue
+	  ;;
+	expsyms_regex)
+	  export_symbols_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	framework)
+	  case $host in
+	    *-*-darwin*)
+	      case "$deplibs " in
+		*" $qarg.ltframework "*) ;;
+		*) func_append deplibs " $qarg.ltframework" # this is fixed later
+		   ;;
+	      esac
+	      ;;
+	  esac
+	  prev=
+	  continue
+	  ;;
+	inst_prefix)
+	  inst_prefix_dir="$arg"
+	  prev=
+	  continue
+	  ;;
+	objectlist)
+	  if test -f "$arg"; then
+	    save_arg=$arg
+	    moreargs=
+	    for fil in `cat "$save_arg"`
+	    do
+#	      func_append moreargs " $fil"
+	      arg=$fil
+	      # A libtool-controlled object.
+
+	      # Check to see that this really is a libtool object.
+	      if func_lalib_unsafe_p "$arg"; then
+		pic_object=
+		non_pic_object=
+
+		# Read the .lo file
+		func_source "$arg"
+
+		if test -z "$pic_object" ||
+		   test -z "$non_pic_object" ||
+		   test "$pic_object" = none &&
+		   test "$non_pic_object" = none; then
+		  func_fatal_error "cannot find name of object for \`$arg'"
+		fi
+
+		# Extract subdirectory from the argument.
+		func_dirname "$arg" "/" ""
+		xdir="$func_dirname_result"
+
+		if test "$pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  pic_object="$xdir$pic_object"
+
+		  if test "$prev" = dlfiles; then
+		    if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		      func_append dlfiles " $pic_object"
+		      prev=
+		      continue
+		    else
+		      # If libtool objects are unsupported, then we need to preload.
+		      prev=dlprefiles
+		    fi
+		  fi
+
+		  # CHECK ME:  I think I busted this.  -Ossama
+		  if test "$prev" = dlprefiles; then
+		    # Preload the old-style object.
+		    func_append dlprefiles " $pic_object"
+		    prev=
+		  fi
+
+		  # A PIC object.
+		  func_append libobjs " $pic_object"
+		  arg="$pic_object"
+		fi
+
+		# Non-PIC object.
+		if test "$non_pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  non_pic_object="$xdir$non_pic_object"
+
+		  # A standard non-PIC object
+		  func_append non_pic_objects " $non_pic_object"
+		  if test -z "$pic_object" || test "$pic_object" = none ; then
+		    arg="$non_pic_object"
+		  fi
+		else
+		  # If the PIC object exists, use it instead.
+		  # $xdir was prepended to $pic_object above.
+		  non_pic_object="$pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+		fi
+	      else
+		# Only an error if not doing a dry-run.
+		if $opt_dry_run; then
+		  # Extract subdirectory from the argument.
+		  func_dirname "$arg" "/" ""
+		  xdir="$func_dirname_result"
+
+		  func_lo2o "$arg"
+		  pic_object=$xdir$objdir/$func_lo2o_result
+		  non_pic_object=$xdir$func_lo2o_result
+		  func_append libobjs " $pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+	        else
+		  func_fatal_error "\`$arg' is not a valid libtool object"
+		fi
+	      fi
+	    done
+	  else
+	    func_fatal_error "link input file \`$arg' does not exist"
+	  fi
+	  arg=$save_arg
+	  prev=
+	  continue
+	  ;;
+	precious_regex)
+	  precious_files_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	release)
+	  release="-$arg"
+	  prev=
+	  continue
+	  ;;
+	rpath | xrpath)
+	  # We need an absolute path.
+	  case $arg in
+	  [\\/]* | [A-Za-z]:[\\/]*) ;;
+	  *)
+	    func_fatal_error "only absolute run-paths are allowed"
+	    ;;
+	  esac
+	  if test "$prev" = rpath; then
+	    case "$rpath " in
+	    *" $arg "*) ;;
+	    *) func_append rpath " $arg" ;;
+	    esac
+	  else
+	    case "$xrpath " in
+	    *" $arg "*) ;;
+	    *) func_append xrpath " $arg" ;;
+	    esac
+	  fi
+	  prev=
+	  continue
+	  ;;
+	shrext)
+	  shrext_cmds="$arg"
+	  prev=
+	  continue
+	  ;;
+	weak)
+	  func_append weak_libs " $arg"
+	  prev=
+	  continue
+	  ;;
+	xcclinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xcompiler)
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xlinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $wl$qarg"
+	  prev=
+	  func_append compile_command " $wl$qarg"
+	  func_append finalize_command " $wl$qarg"
+	  continue
+	  ;;
+	*)
+	  eval "$prev=\"\$arg\""
+	  prev=
+	  continue
+	  ;;
+	esac
+      fi # test -n "$prev"
+
+      prevarg="$arg"
+
+      case $arg in
+      -all-static)
+	if test -n "$link_static_flag"; then
+	  # See comment for -static flag below, for more details.
+	  func_append compile_command " $link_static_flag"
+	  func_append finalize_command " $link_static_flag"
+	fi
+	continue
+	;;
+
+      -allow-undefined)
+	# FIXME: remove this flag sometime in the future.
+	func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+	;;
+
+      -avoid-version)
+	avoid_version=yes
+	continue
+	;;
+
+      -bindir)
+	prev=bindir
+	continue
+	;;
+
+      -dlopen)
+	prev=dlfiles
+	continue
+	;;
+
+      -dlpreopen)
+	prev=dlprefiles
+	continue
+	;;
+
+      -export-dynamic)
+	export_dynamic=yes
+	continue
+	;;
+
+      -export-symbols | -export-symbols-regex)
+	if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	  func_fatal_error "more than one -exported-symbols argument is not allowed"
+	fi
+	if test "X$arg" = "X-export-symbols"; then
+	  prev=expsyms
+	else
+	  prev=expsyms_regex
+	fi
+	continue
+	;;
+
+      -framework)
+	prev=framework
+	continue
+	;;
+
+      -inst-prefix-dir)
+	prev=inst_prefix
+	continue
+	;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+	case $with_gcc/$host in
+	no/*-*-irix* | /*-*-irix*)
+	  func_append compile_command " $arg"
+	  func_append finalize_command " $arg"
+	  ;;
+	esac
+	continue
+	;;
+
+      -L*)
+	func_stripname "-L" '' "$arg"
+	if test -z "$func_stripname_result"; then
+	  if test "$#" -gt 0; then
+	    func_fatal_error "require no space between \`-L' and \`$1'"
+	  else
+	    func_fatal_error "need path for \`-L' option"
+	  fi
+	fi
+	func_resolve_sysroot "$func_stripname_result"
+	dir=$func_resolve_sysroot_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  absdir=`cd "$dir" && pwd`
+	  test -z "$absdir" && \
+	    func_fatal_error "cannot determine absolute directory name of \`$dir'"
+	  dir="$absdir"
+	  ;;
+	esac
+	case "$deplibs " in
+	*" -L$dir "* | *" $arg "*)
+	  # Will only happen for absolute or sysroot arguments
+	  ;;
+	*)
+	  # Preserve sysroot, but never include relative directories
+	  case $dir in
+	    [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+	    *) func_append deplibs " -L$dir" ;;
+	  esac
+	  func_append lib_search_path " $dir"
+	  ;;
+	esac
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$dir:"*) ;;
+	  ::) dllsearchpath=$dir;;
+	  *) func_append dllsearchpath ":$dir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+	continue
+	;;
+
+      -l*)
+	if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # These systems don't actually have a C or math library (as such)
+	    continue
+	    ;;
+	  *-*-os2*)
+	    # These systems don't actually have a C library (as such)
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C and math libraries are in the System framework
+	    func_append deplibs " System.ltframework"
+	    continue
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  esac
+	elif test "X$arg" = "X-lc_r"; then
+	 case $host in
+	 *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	   # Do not include libc_r directly, use -pthread flag.
+	   continue
+	   ;;
+	 esac
+	fi
+	func_append deplibs " $arg"
+	continue
+	;;
+
+      -module)
+	module=yes
+	continue
+	;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      # Darwin uses the -arch flag to determine output architecture.
+      -model|-arch|-isysroot|--sysroot)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	prev=xcompiler
+	continue
+	;;
+
+      -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+      |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	case "$new_inherited_linker_flags " in
+	    *" $arg "*) ;;
+	    * ) func_append new_inherited_linker_flags " $arg" ;;
+	esac
+	continue
+	;;
+
+      -multi_module)
+	single_module="${wl}-multi_module"
+	continue
+	;;
+
+      -no-fast-install)
+	fast_install=no
+	continue
+	;;
+
+      -no-install)
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+	  # The PATH hackery in wrapper scripts is required on Windows
+	  # and Darwin in order for the loader to find any dlls it needs.
+	  func_warning "\`-no-install' is ignored for $host"
+	  func_warning "assuming \`-no-fast-install' instead"
+	  fast_install=no
+	  ;;
+	*) no_install=yes ;;
+	esac
+	continue
+	;;
+
+      -no-undefined)
+	allow_undefined=no
+	continue
+	;;
+
+      -objectlist)
+	prev=objectlist
+	continue
+	;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+	prev=precious_regex
+	continue
+	;;
+
+      -release)
+	prev=release
+	continue
+	;;
+
+      -rpath)
+	prev=rpath
+	continue
+	;;
+
+      -R)
+	prev=xrpath
+	continue
+	;;
+
+      -R*)
+	func_stripname '-R' '' "$arg"
+	dir=$func_stripname_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	=*)
+	  func_stripname '=' '' "$dir"
+	  dir=$lt_sysroot$func_stripname_result
+	  ;;
+	*)
+	  func_fatal_error "only absolute run-paths are allowed"
+	  ;;
+	esac
+	case "$xrpath " in
+	*" $dir "*) ;;
+	*) func_append xrpath " $dir" ;;
+	esac
+	continue
+	;;
+
+      -shared)
+	# The effects of -shared are defined in a previous loop.
+	continue
+	;;
+
+      -shrext)
+	prev=shrext
+	continue
+	;;
+
+      -static | -static-libtool-libs)
+	# The effects of -static are defined in a previous loop.
+	# We used to do the same as -all-static on platforms that
+	# didn't have a PIC flag, but the assumption that the effects
+	# would be equivalent was wrong.  It would break on at least
+	# Digital Unix and AIX.
+	continue
+	;;
+
+      -thread-safe)
+	thread_safe=yes
+	continue
+	;;
+
+      -version-info)
+	prev=vinfo
+	continue
+	;;
+
+      -version-number)
+	prev=vinfo
+	vinfo_number=yes
+	continue
+	;;
+
+      -weak)
+        prev=weak
+	continue
+	;;
+
+      -Wc,*)
+	func_stripname '-Wc,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  func_append arg " $func_quote_for_eval_result"
+	  func_append compiler_flags " $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Wl,*)
+	func_stripname '-Wl,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  func_append arg " $wl$func_quote_for_eval_result"
+	  func_append compiler_flags " $wl$func_quote_for_eval_result"
+	  func_append linker_flags " $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Xcompiler)
+	prev=xcompiler
+	continue
+	;;
+
+      -Xlinker)
+	prev=xlinker
+	continue
+	;;
+
+      -XCClinker)
+	prev=xcclinker
+	continue
+	;;
+
+      # -msg_* for osf cc
+      -msg_*)
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      # Flags to be passed through unchanged, with rationale:
+      # -64, -mips[0-9]      enable 64-bit mode for the SGI compiler
+      # -r[0-9][0-9]*        specify processor for the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+      # +DA*, +DD*           enable 64-bit mode for the HP compiler
+      # -q*                  compiler args for the IBM compiler
+      # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+      # -F/path              path to uninstalled frameworks, gcc on darwin
+      # -p, -pg, --coverage, -fprofile-*  profiling flags for GCC
+      # @file                GCC response files
+      # -tp=*                Portland pgcc target processor selection
+      # --sysroot=*          for sysroot support
+      # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+      -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+        func_append compile_command " $arg"
+        func_append finalize_command " $arg"
+        func_append compiler_flags " $arg"
+        continue
+        ;;
+
+      # Some other compiler flag.
+      -* | +*)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      *.$objext)
+	# A standard object.
+	func_append objs " $arg"
+	;;
+
+      *.lo)
+	# A libtool-controlled object.
+
+	# Check to see that this really is a libtool object.
+	if func_lalib_unsafe_p "$arg"; then
+	  pic_object=
+	  non_pic_object=
+
+	  # Read the .lo file
+	  func_source "$arg"
+
+	  if test -z "$pic_object" ||
+	     test -z "$non_pic_object" ||
+	     test "$pic_object" = none &&
+	     test "$non_pic_object" = none; then
+	    func_fatal_error "cannot find name of object for \`$arg'"
+	  fi
+
+	  # Extract subdirectory from the argument.
+	  func_dirname "$arg" "/" ""
+	  xdir="$func_dirname_result"
+
+	  if test "$pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    pic_object="$xdir$pic_object"
+
+	    if test "$prev" = dlfiles; then
+	      if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		func_append dlfiles " $pic_object"
+		prev=
+		continue
+	      else
+		# If libtool objects are unsupported, then we need to preload.
+		prev=dlprefiles
+	      fi
+	    fi
+
+	    # CHECK ME:  I think I busted this.  -Ossama
+	    if test "$prev" = dlprefiles; then
+	      # Preload the old-style object.
+	      func_append dlprefiles " $pic_object"
+	      prev=
+	    fi
+
+	    # A PIC object.
+	    func_append libobjs " $pic_object"
+	    arg="$pic_object"
+	  fi
+
+	  # Non-PIC object.
+	  if test "$non_pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    non_pic_object="$xdir$non_pic_object"
+
+	    # A standard non-PIC object
+	    func_append non_pic_objects " $non_pic_object"
+	    if test -z "$pic_object" || test "$pic_object" = none ; then
+	      arg="$non_pic_object"
+	    fi
+	  else
+	    # If the PIC object exists, use it instead.
+	    # $xdir was prepended to $pic_object above.
+	    non_pic_object="$pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  fi
+	else
+	  # Only an error if not doing a dry-run.
+	  if $opt_dry_run; then
+	    # Extract subdirectory from the argument.
+	    func_dirname "$arg" "/" ""
+	    xdir="$func_dirname_result"
+
+	    func_lo2o "$arg"
+	    pic_object=$xdir$objdir/$func_lo2o_result
+	    non_pic_object=$xdir$func_lo2o_result
+	    func_append libobjs " $pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  else
+	    func_fatal_error "\`$arg' is not a valid libtool object"
+	  fi
+	fi
+	;;
+
+      *.$libext)
+	# An archive.
+	func_append deplibs " $arg"
+	func_append old_deplibs " $arg"
+	continue
+	;;
+
+      *.la)
+	# A libtool-controlled library.
+
+	func_resolve_sysroot "$arg"
+	if test "$prev" = dlfiles; then
+	  # This library was specified with -dlopen.
+	  func_append dlfiles " $func_resolve_sysroot_result"
+	  prev=
+	elif test "$prev" = dlprefiles; then
+	  # The library was specified with -dlpreopen.
+	  func_append dlprefiles " $func_resolve_sysroot_result"
+	  prev=
+	else
+	  func_append deplibs " $func_resolve_sysroot_result"
+	fi
+	continue
+	;;
+
+      # Some other compiler argument.
+      *)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+      fi
+    done # argument parsing loop
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prevarg' option requires an argument"
+
+    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      func_append compile_command " $arg"
+      func_append finalize_command " $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    func_basename "$output"
+    outputname="$func_basename_result"
+    libobjs_save="$libobjs"
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    func_dirname "$output" "/" ""
+    output_objdir="$func_dirname_result$objdir"
+    func_to_tool_file "$output_objdir/"
+    tool_output_objdir=$func_to_tool_file_result
+    # Create the object directory.
+    func_mkdir_p "$output_objdir"
+
+    # Determine the type of output
+    case $output in
+    "")
+      func_fatal_help "you must specify an output file"
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if $opt_preserve_dup_deps ; then
+	case "$libs " in
+	*" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	esac
+      fi
+      func_append libs " $deplib"
+    done
+
+    if test "$linkmode" = lib; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if $opt_duplicate_compiler_generated_deps; then
+	for pre_post_dep in $predeps $postdeps; do
+	  case "$pre_post_deps " in
+	  *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+	  esac
+	  func_append pre_post_deps " $pre_post_dep"
+	done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+
+    case $linkmode in
+    lib)
+	passes="conv dlpreopen link"
+	for file in $dlfiles $dlprefiles; do
+	  case $file in
+	  *.la) ;;
+	  *)
+	    func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+	    ;;
+	  esac
+	done
+	;;
+    prog)
+	compile_deplibs=
+	finalize_deplibs=
+	alldeplibs=no
+	newdlfiles=
+	newdlprefiles=
+	passes="conv scan dlopen dlpreopen link"
+	;;
+    *)  passes="conv"
+	;;
+    esac
+
+    for pass in $passes; do
+      # The preopen pass in lib mode reverses $deplibs; put it back here
+      # so that -L comes before libs that need it for instance...
+      if test "$linkmode,$pass" = "lib,link"; then
+	## FIXME: Find the place where the list is rebuilt in the wrong
+	##        order, and fix it there properly
+        tmp_deplibs=
+	for deplib in $deplibs; do
+	  tmp_deplibs="$deplib $tmp_deplibs"
+	done
+	deplibs="$tmp_deplibs"
+      fi
+
+      if test "$linkmode,$pass" = "lib,link" ||
+	 test "$linkmode,$pass" = "prog,scan"; then
+	libs="$deplibs"
+	deplibs=
+      fi
+      if test "$linkmode" = prog; then
+	case $pass in
+	dlopen) libs="$dlfiles" ;;
+	dlpreopen) libs="$dlprefiles" ;;
+	link)
+	  libs="$deplibs %DEPLIBS%"
+	  test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
+	  ;;
+	esac
+      fi
+      if test "$linkmode,$pass" = "lib,dlpreopen"; then
+	# Collect and forward deplibs of preopened libtool libs
+	for lib in $dlprefiles; do
+	  # Ignore non-libtool-libs
+	  dependency_libs=
+	  func_resolve_sysroot "$lib"
+	  case $lib in
+	  *.la)	func_source "$func_resolve_sysroot_result" ;;
+	  esac
+
+	  # Collect preopened libtool deplibs, except any this library
+	  # has declared as weak libs
+	  for deplib in $dependency_libs; do
+	    func_basename "$deplib"
+            deplib_base=$func_basename_result
+	    case " $weak_libs " in
+	    *" $deplib_base "*) ;;
+	    *) func_append deplibs " $deplib" ;;
+	    esac
+	  done
+	done
+	libs="$dlprefiles"
+      fi
+      if test "$pass" = dlopen; then
+	# Collect dlpreopened libraries
+	save_deplibs="$deplibs"
+	deplibs=
+      fi
+
+      for deplib in $libs; do
+	lib=
+	found=no
+	case $deplib in
+	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+        |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    func_append compiler_flags " $deplib"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-l*)
+	  if test "$linkmode" != lib && test "$linkmode" != prog; then
+	    func_warning "\`-l' is ignored for archives/objects"
+	    continue
+	  fi
+	  func_stripname '-l' '' "$deplib"
+	  name=$func_stripname_result
+	  if test "$linkmode" = lib; then
+	    searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+	  else
+	    searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+	  fi
+	  for searchdir in $searchdirs; do
+	    for search_ext in .la $std_shrext .so .a; do
+	      # Search the libtool library
+	      lib="$searchdir/lib${name}${search_ext}"
+	      if test -f "$lib"; then
+		if test "$search_ext" = ".la"; then
+		  found=yes
+		else
+		  found=no
+		fi
+		break 2
+	      fi
+	    done
+	  done
+	  if test "$found" != yes; then
+	    # deplib doesn't seem to be a libtool library
+	    if test "$linkmode,$pass" = "prog,link"; then
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      deplibs="$deplib $deplibs"
+	      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    continue
+	  else # deplib is a libtool library
+	    # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+	    # We need to do some special things here, and not later.
+	    if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	      case " $predeps $postdeps " in
+	      *" $deplib "*)
+		if func_lalib_p "$lib"; then
+		  library_names=
+		  old_library=
+		  func_source "$lib"
+		  for l in $old_library $library_names; do
+		    ll="$l"
+		  done
+		  if test "X$ll" = "X$old_library" ; then # only static version available
+		    found=no
+		    func_dirname "$lib" "" "."
+		    ladir="$func_dirname_result"
+		    lib=$ladir/$old_library
+		    if test "$linkmode,$pass" = "prog,link"; then
+		      compile_deplibs="$deplib $compile_deplibs"
+		      finalize_deplibs="$deplib $finalize_deplibs"
+		    else
+		      deplibs="$deplib $deplibs"
+		      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+		    fi
+		    continue
+		  fi
+		fi
+		;;
+	      *) ;;
+	      esac
+	    fi
+	  fi
+	  ;; # -l
+	*.ltframework)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    deplibs="$deplib $deplibs"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-L*)
+	  case $linkmode in
+	  lib)
+	    deplibs="$deplib $deplibs"
+	    test "$pass" = conv && continue
+	    newdependency_libs="$deplib $newdependency_libs"
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  prog)
+	    if test "$pass" = conv; then
+	      deplibs="$deplib $deplibs"
+	      continue
+	    fi
+	    if test "$pass" = scan; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  *)
+	    func_warning "\`-L' is ignored for archives/objects"
+	    ;;
+	  esac # linkmode
+	  continue
+	  ;; # -L
+	-R*)
+	  if test "$pass" = link; then
+	    func_stripname '-R' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    dir=$func_resolve_sysroot_result
+	    # Make sure the xrpath contains only unique directories.
+	    case "$xrpath " in
+	    *" $dir "*) ;;
+	    *) func_append xrpath " $dir" ;;
+	    esac
+	  fi
+	  deplibs="$deplib $deplibs"
+	  continue
+	  ;;
+	*.la)
+	  func_resolve_sysroot "$deplib"
+	  lib=$func_resolve_sysroot_result
+	  ;;
+	*.$libext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	    continue
+	  fi
+	  case $linkmode in
+	  lib)
+	    # Linking convenience modules into shared libraries is allowed,
+	    # but linking other static libraries is non-portable.
+	    case " $dlpreconveniencelibs " in
+	    *" $deplib "*) ;;
+	    *)
+	      valid_a_lib=no
+	      case $deplibs_check_method in
+		match_pattern*)
+		  set dummy $deplibs_check_method; shift
+		  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+		  if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+		    | $EGREP "$match_pattern_regex" > /dev/null; then
+		    valid_a_lib=yes
+		  fi
+		;;
+		pass_all)
+		  valid_a_lib=yes
+		;;
+	      esac
+	      if test "$valid_a_lib" != yes; then
+		echo
+		$ECHO "*** Warning: Trying to link with static lib archive $deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because the file extensions .$libext of this argument makes me believe"
+		echo "*** that it is just a static archive that I should not use here."
+	      else
+		echo
+		$ECHO "*** Warning: Linking the shared library $output against the"
+		$ECHO "*** static library $deplib is not portable!"
+		deplibs="$deplib $deplibs"
+	      fi
+	      ;;
+	    esac
+	    continue
+	    ;;
+	  prog)
+	    if test "$pass" != link; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    continue
+	    ;;
+	  esac # linkmode
+	  ;; # *.$libext
+	*.lo | *.$objext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	  elif test "$linkmode" = prog; then
+	    if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+	      # If there is no dlopen support or we're linking statically,
+	      # we need to preload.
+	      func_append newdlprefiles " $deplib"
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      func_append newdlfiles " $deplib"
+	    fi
+	  fi
+	  continue
+	  ;;
+	%DEPLIBS%)
+	  alldeplibs=yes
+	  continue
+	  ;;
+	esac # case $deplib
+
+	if test "$found" = yes || test -f "$lib"; then :
+	else
+	  func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+	fi
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$lib" \
+	  || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+	func_dirname "$lib" "" "."
+	ladir="$func_dirname_result"
+
+	dlname=
+	dlopen=
+	dlpreopen=
+	libdir=
+	library_names=
+	old_library=
+	inherited_linker_flags=
+	# If the library was installed with an old release of libtool,
+	# it will not redefine variables installed, or shouldnotlink
+	installed=yes
+	shouldnotlink=no
+	avoidtemprpath=
+
+
+	# Read the .la file
+	func_source "$lib"
+
+	# Convert "-framework foo" to "foo.ltframework"
+	if test -n "$inherited_linker_flags"; then
+	  tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+	  for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+	    case " $new_inherited_linker_flags " in
+	      *" $tmp_inherited_linker_flag "*) ;;
+	      *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+	    esac
+	  done
+	fi
+	dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	if test "$linkmode,$pass" = "lib,link" ||
+	   test "$linkmode,$pass" = "prog,scan" ||
+	   { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+	  test -n "$dlopen" && func_append dlfiles " $dlopen"
+	  test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+	fi
+
+	if test "$pass" = conv; then
+	  # Only check for convenience libraries
+	  deplibs="$lib $deplibs"
+	  if test -z "$libdir"; then
+	    if test -z "$old_library"; then
+	      func_fatal_error "cannot find name of link library for \`$lib'"
+	    fi
+	    # It is a libtool convenience library, so add in its objects.
+	    func_append convenience " $ladir/$objdir/$old_library"
+	    func_append old_convenience " $ladir/$objdir/$old_library"
+	    tmp_libs=
+	    for deplib in $dependency_libs; do
+	      deplibs="$deplib $deplibs"
+	      if $opt_preserve_dup_deps ; then
+		case "$tmp_libs " in
+		*" $deplib "*) func_append specialdeplibs " $deplib" ;;
+		esac
+	      fi
+	      func_append tmp_libs " $deplib"
+	    done
+	  elif test "$linkmode" != prog && test "$linkmode" != lib; then
+	    func_fatal_error "\`$lib' is not a convenience library"
+	  fi
+	  continue
+	fi # $pass = conv
+
+
+	# Get the name of the library we link against.
+	linklib=
+	if test -n "$old_library" &&
+	   { test "$prefer_static_libs" = yes ||
+	     test "$prefer_static_libs,$installed" = "built,no"; }; then
+	  linklib=$old_library
+	else
+	  for l in $old_library $library_names; do
+	    linklib="$l"
+	  done
+	fi
+	if test -z "$linklib"; then
+	  func_fatal_error "cannot find name of link library for \`$lib'"
+	fi
+
+	# This library was specified with -dlopen.
+	if test "$pass" = dlopen; then
+	  if test -z "$libdir"; then
+	    func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+	  fi
+	  if test -z "$dlname" ||
+	     test "$dlopen_support" != yes ||
+	     test "$build_libtool_libs" = no; then
+	    # If there is no dlname, no dlopen support or we're linking
+	    # statically, we need to preload.  We also need to preload any
+	    # dependent libraries so libltdl's deplib preloader doesn't
+	    # bomb out in the load deplibs phase.
+	    func_append dlprefiles " $lib $dependency_libs"
+	  else
+	    func_append newdlfiles " $lib"
+	  fi
+	  continue
+	fi # $pass = dlopen
+
+	# We need an absolute path.
+	case $ladir in
+	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+	*)
+	  abs_ladir=`cd "$ladir" && pwd`
+	  if test -z "$abs_ladir"; then
+	    func_warning "cannot determine absolute directory name of \`$ladir'"
+	    func_warning "passing it literally to the linker, although it might fail"
+	    abs_ladir="$ladir"
+	  fi
+	  ;;
+	esac
+	func_basename "$lib"
+	laname="$func_basename_result"
+
+	# Find the relevant object directory and library name.
+	if test "X$installed" = Xyes; then
+	  if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    func_warning "library \`$lib' was moved."
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    libdir="$abs_ladir"
+	  else
+	    dir="$lt_sysroot$libdir"
+	    absdir="$lt_sysroot$libdir"
+	  fi
+	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+	else
+	  if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  else
+	    dir="$ladir/$objdir"
+	    absdir="$abs_ladir/$objdir"
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  fi
+	fi # $installed = yes
+	func_stripname 'lib' '.la' "$laname"
+	name=$func_stripname_result
+
+	# This library was specified with -dlpreopen.
+	if test "$pass" = dlpreopen; then
+	  if test -z "$libdir" && test "$linkmode" = prog; then
+	    func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+	  fi
+	  case "$host" in
+	    # special handling for platforms with PE-DLLs.
+	    *cygwin* | *mingw* | *cegcc* )
+	      # Linker will automatically link against shared library if both
+	      # static and shared are present.  Therefore, ensure we extract
+	      # symbols from the import library if a shared library is present
+	      # (otherwise, the dlopen module name will be incorrect).  We do
+	      # this by putting the import library name into $newdlprefiles.
+	      # We recover the dlopen module name by 'saving' the la file
+	      # name in a special purpose variable, and (later) extracting the
+	      # dlname from the la file.
+	      if test -n "$dlname"; then
+	        func_tr_sh "$dir/$linklib"
+	        eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+	        func_append newdlprefiles " $dir/$linklib"
+	      else
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      fi
+	    ;;
+	    * )
+	      # Prefer using a static library (so that no silly _DYNAMIC symbols
+	      # are required to link).
+	      if test -n "$old_library"; then
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      # Otherwise, use the dlname, so that lt_dlopen finds it.
+	      elif test -n "$dlname"; then
+	        func_append newdlprefiles " $dir/$dlname"
+	      else
+	        func_append newdlprefiles " $dir/$linklib"
+	      fi
+	    ;;
+	  esac
+	fi # $pass = dlpreopen
+
+	if test -z "$libdir"; then
+	  # Link the convenience library
+	  if test "$linkmode" = lib; then
+	    deplibs="$dir/$old_library $deplibs"
+	  elif test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$dir/$old_library $compile_deplibs"
+	    finalize_deplibs="$dir/$old_library $finalize_deplibs"
+	  else
+	    deplibs="$lib $deplibs" # used for prog,scan pass
+	  fi
+	  continue
+	fi
+
+
+	if test "$linkmode" = prog && test "$pass" != link; then
+	  func_append newlib_search_path " $ladir"
+	  deplibs="$lib $deplibs"
+
+	  linkalldeplibs=no
+	  if test "$link_all_deplibs" != no || test -z "$library_names" ||
+	     test "$build_libtool_libs" = no; then
+	    linkalldeplibs=yes
+	  fi
+
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    case $deplib in
+	    -L*) func_stripname '-L' '' "$deplib"
+	         func_resolve_sysroot "$func_stripname_result"
+	         func_append newlib_search_path " $func_resolve_sysroot_result"
+		 ;;
+	    esac
+	    # Need to link against all dependency_libs?
+	    if test "$linkalldeplibs" = yes; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      # Need to hardcode shared library paths
+	      # or/and link against static libraries
+	      newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    if $opt_preserve_dup_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $deplib"
+	  done # for deplib
+	  continue
+	fi # $linkmode = prog...
+
+	if test "$linkmode,$pass" = "prog,link"; then
+	  if test -n "$library_names" &&
+	     { { test "$prefer_static_libs" = no ||
+	         test "$prefer_static_libs,$installed" = "built,yes"; } ||
+	       test -z "$old_library"; }; then
+	    # We need to hardcode the library path
+	    if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+	      # Make sure the rpath contains only unique directories.
+	      case "$temp_rpath:" in
+	      *"$absdir:"*) ;;
+	      *) func_append temp_rpath "$absdir:" ;;
+	      esac
+	    fi
+
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi # $linkmode,$pass = prog,link...
+
+	  if test "$alldeplibs" = yes &&
+	     { test "$deplibs_check_method" = pass_all ||
+	       { test "$build_libtool_libs" = yes &&
+		 test -n "$library_names"; }; }; then
+	    # We only need to search for static libraries
+	    continue
+	  fi
+	fi
+
+	link_static=no # Whether the deplib will be linked statically
+	use_static_libs=$prefer_static_libs
+	if test "$use_static_libs" = built && test "$installed" = yes; then
+	  use_static_libs=no
+	fi
+	if test -n "$library_names" &&
+	   { test "$use_static_libs" = no || test -z "$old_library"; }; then
+	  case $host in
+	  *cygwin* | *mingw* | *cegcc*)
+	      # No point in relinking DLLs because paths are not encoded
+	      func_append notinst_deplibs " $lib"
+	      need_relink=no
+	    ;;
+	  *)
+	    if test "$installed" = no; then
+	      func_append notinst_deplibs " $lib"
+	      need_relink=yes
+	    fi
+	    ;;
+	  esac
+	  # This is a shared library
+
+	  # Warn about portability, can't link against -module's on some
+	  # systems (darwin).  Don't bleat about dlopened modules though!
+	  dlopenmodule=""
+	  for dlpremoduletest in $dlprefiles; do
+	    if test "X$dlpremoduletest" = "X$lib"; then
+	      dlopenmodule="$dlpremoduletest"
+	      break
+	    fi
+	  done
+	  if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+	    echo
+	    if test "$linkmode" = prog; then
+	      $ECHO "*** Warning: Linking the executable $output against the loadable module"
+	    else
+	      $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+	    fi
+	    $ECHO "*** $linklib is not portable!"
+	  fi
+	  if test "$linkmode" = lib &&
+	     test "$hardcode_into_libs" = yes; then
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi
+
+	  if test -n "$old_archive_from_expsyms_cmds"; then
+	    # figure out the soname
+	    set dummy $library_names
+	    shift
+	    realname="$1"
+	    shift
+	    libname=`eval "\\$ECHO \"$libname_spec\""`
+	    # use dlname if we got it. it's perfectly good, no?
+	    if test -n "$dlname"; then
+	      soname="$dlname"
+	    elif test -n "$soname_spec"; then
+	      # bleh windows
+	      case $host in
+	      *cygwin* | mingw* | *cegcc*)
+	        func_arith $current - $age
+		major=$func_arith_result
+		versuffix="-$major"
+		;;
+	      esac
+	      eval soname=\"$soname_spec\"
+	    else
+	      soname="$realname"
+	    fi
+
+	    # Make a new name for the extract_expsyms_cmds to use
+	    soroot="$soname"
+	    func_basename "$soroot"
+	    soname="$func_basename_result"
+	    func_stripname 'lib' '.dll' "$soname"
+	    newlib=libimp-$func_stripname_result.a
+
+	    # If the library has no export list, then create one now
+	    if test -f "$output_objdir/$soname-def"; then :
+	    else
+	      func_verbose "extracting exported symbol list from \`$soname'"
+	      func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+	    fi
+
+	    # Create $newlib
+	    if test -f "$output_objdir/$newlib"; then :; else
+	      func_verbose "generating import library for \`$soname'"
+	      func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+	    fi
+	    # make sure the library variables are pointing to the new library
+	    dir=$output_objdir
+	    linklib=$newlib
+	  fi # test -n "$old_archive_from_expsyms_cmds"
+
+	  if test "$linkmode" = prog || test "$opt_mode" != relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    lib_linked=yes
+	    case $hardcode_action in
+	    immediate | unsupported)
+	      if test "$hardcode_direct" = no; then
+		add="$dir/$linklib"
+		case $host in
+		  *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+		  *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+		  *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+		    *-*-unixware7*) add_dir="-L$dir" ;;
+		  *-*-darwin* )
+		    # if the lib is a (non-dlopened) module then we can not
+		    # link against it, someone is ignoring the earlier warnings
+		    if /usr/bin/file -L $add 2> /dev/null |
+			 $GREP ": [^:]* bundle" >/dev/null ; then
+		      if test "X$dlopenmodule" != "X$lib"; then
+			$ECHO "*** Warning: lib $linklib is a module, not a shared library"
+			if test -z "$old_library" ; then
+			  echo
+			  echo "*** And there doesn't seem to be a static archive available"
+			  echo "*** The link will probably fail, sorry"
+			else
+			  add="$dir/$old_library"
+			fi
+		      elif test -n "$old_library"; then
+			add="$dir/$old_library"
+		      fi
+		    fi
+		esac
+	      elif test "$hardcode_minus_L" = no; then
+		case $host in
+		*-*-sunos*) add_shlibpath="$dir" ;;
+		esac
+		add_dir="-L$dir"
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = no; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    relink)
+	      if test "$hardcode_direct" = yes &&
+	         test "$hardcode_direct_absolute" = no; then
+		add="$dir/$linklib"
+	      elif test "$hardcode_minus_L" = yes; then
+		add_dir="-L$absdir"
+		# Try looking first in the location we're being installed to.
+		if test -n "$inst_prefix_dir"; then
+		  case $libdir in
+		    [\\/]*)
+		      func_append add_dir " -L$inst_prefix_dir$libdir"
+		      ;;
+		  esac
+		fi
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = yes; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    *) lib_linked=no ;;
+	    esac
+
+	    if test "$lib_linked" != yes; then
+	      func_fatal_configuration "unsupported hardcode properties"
+	    fi
+
+	    if test -n "$add_shlibpath"; then
+	      case :$compile_shlibpath: in
+	      *":$add_shlibpath:"*) ;;
+	      *) func_append compile_shlibpath "$add_shlibpath:" ;;
+	      esac
+	    fi
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+	      test -n "$add" && compile_deplibs="$add $compile_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	      if test "$hardcode_direct" != yes &&
+		 test "$hardcode_minus_L" != yes &&
+		 test "$hardcode_shlibpath_var" = yes; then
+		case :$finalize_shlibpath: in
+		*":$libdir:"*) ;;
+		*) func_append finalize_shlibpath "$libdir:" ;;
+		esac
+	      fi
+	    fi
+	  fi
+
+	  if test "$linkmode" = prog || test "$opt_mode" = relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    # Finalize command for both is simple: just hardcode it.
+	    if test "$hardcode_direct" = yes &&
+	       test "$hardcode_direct_absolute" = no; then
+	      add="$libdir/$linklib"
+	    elif test "$hardcode_minus_L" = yes; then
+	      add_dir="-L$libdir"
+	      add="-l$name"
+	    elif test "$hardcode_shlibpath_var" = yes; then
+	      case :$finalize_shlibpath: in
+	      *":$libdir:"*) ;;
+	      *) func_append finalize_shlibpath "$libdir:" ;;
+	      esac
+	      add="-l$name"
+	    elif test "$hardcode_automatic" = yes; then
+	      if test -n "$inst_prefix_dir" &&
+		 test -f "$inst_prefix_dir$libdir/$linklib" ; then
+		add="$inst_prefix_dir$libdir/$linklib"
+	      else
+		add="$libdir/$linklib"
+	      fi
+	    else
+	      # We cannot seem to hardcode it, guess we'll fake it.
+	      add_dir="-L$libdir"
+	      # Try looking first in the location we're being installed to.
+	      if test -n "$inst_prefix_dir"; then
+		case $libdir in
+		  [\\/]*)
+		    func_append add_dir " -L$inst_prefix_dir$libdir"
+		    ;;
+		esac
+	      fi
+	      add="-l$name"
+	    fi
+
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+	      test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	    fi
+	  fi
+	elif test "$linkmode" = prog; then
+	  # Here we assume that one of hardcode_direct or hardcode_minus_L
+	  # is not unsupported.  This is valid on all known static and
+	  # shared platforms.
+	  if test "$hardcode_direct" != unsupported; then
+	    test -n "$old_library" && linklib="$old_library"
+	    compile_deplibs="$dir/$linklib $compile_deplibs"
+	    finalize_deplibs="$dir/$linklib $finalize_deplibs"
+	  else
+	    compile_deplibs="-l$name -L$dir $compile_deplibs"
+	    finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+	  fi
+	elif test "$build_libtool_libs" = yes; then
+	  # Not a shared library
+	  if test "$deplibs_check_method" != pass_all; then
+	    # We're trying link a shared library against a static one
+	    # but the system doesn't support it.
+
+	    # Just print a warning and add the library to dependency_libs so
+	    # that the program can be linked against the static library.
+	    echo
+	    $ECHO "*** Warning: This system can not link to static lib archive $lib."
+	    echo "*** I have the capability to make that library automatically link in when"
+	    echo "*** you link to this library.  But I can only do this if you have a"
+	    echo "*** shared version of the library, which you do not appear to have."
+	    if test "$module" = yes; then
+	      echo "*** But as you try to build a module library, libtool will still create "
+	      echo "*** a static module, that should work as long as the dlopening application"
+	      echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+	      if test -z "$global_symbol_pipe"; then
+		echo
+		echo "*** However, this would only work if libtool was able to extract symbol"
+		echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+		echo "*** not find such a program.  So, this module is probably useless."
+		echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	      fi
+	      if test "$build_old_libs" = no; then
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  else
+	    deplibs="$dir/$old_library $deplibs"
+	    link_static=yes
+	  fi
+	fi # link shared/static library?
+
+	if test "$linkmode" = lib; then
+	  if test -n "$dependency_libs" &&
+	     { test "$hardcode_into_libs" != yes ||
+	       test "$build_old_libs" = yes ||
+	       test "$link_static" = yes; }; then
+	    # Extract -R from dependency_libs
+	    temp_deplibs=
+	    for libdir in $dependency_libs; do
+	      case $libdir in
+	      -R*) func_stripname '-R' '' "$libdir"
+	           temp_xrpath=$func_stripname_result
+		   case " $xrpath " in
+		   *" $temp_xrpath "*) ;;
+		   *) func_append xrpath " $temp_xrpath";;
+		   esac;;
+	      *) func_append temp_deplibs " $libdir";;
+	      esac
+	    done
+	    dependency_libs="$temp_deplibs"
+	  fi
+
+	  func_append newlib_search_path " $absdir"
+	  # Link against this library
+	  test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+	  # ... and its dependency_libs
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    newdependency_libs="$deplib $newdependency_libs"
+	    case $deplib in
+              -L*) func_stripname '-L' '' "$deplib"
+                   func_resolve_sysroot "$func_stripname_result";;
+              *) func_resolve_sysroot "$deplib" ;;
+            esac
+	    if $opt_preserve_dup_deps ; then
+	      case "$tmp_libs " in
+	      *" $func_resolve_sysroot_result "*)
+                func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $func_resolve_sysroot_result"
+	  done
+
+	  if test "$link_all_deplibs" != no; then
+	    # Add the search paths of all dependency libraries
+	    for deplib in $dependency_libs; do
+	      path=
+	      case $deplib in
+	      -L*) path="$deplib" ;;
+	      *.la)
+	        func_resolve_sysroot "$deplib"
+	        deplib=$func_resolve_sysroot_result
+	        func_dirname "$deplib" "" "."
+		dir=$func_dirname_result
+		# We need an absolute path.
+		case $dir in
+		[\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+		*)
+		  absdir=`cd "$dir" && pwd`
+		  if test -z "$absdir"; then
+		    func_warning "cannot determine absolute directory name of \`$dir'"
+		    absdir="$dir"
+		  fi
+		  ;;
+		esac
+		if $GREP "^installed=no" $deplib > /dev/null; then
+		case $host in
+		*-*-darwin*)
+		  depdepl=
+		  eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+		  if test -n "$deplibrary_names" ; then
+		    for tmp in $deplibrary_names ; do
+		      depdepl=$tmp
+		    done
+		    if test -f "$absdir/$objdir/$depdepl" ; then
+		      depdepl="$absdir/$objdir/$depdepl"
+		      darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+                      if test -z "$darwin_install_name"; then
+                          darwin_install_name=`${OTOOL64} -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
+                      fi
+		      func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+		      func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}"
+		      path=
+		    fi
+		  fi
+		  ;;
+		*)
+		  path="-L$absdir/$objdir"
+		  ;;
+		esac
+		else
+		  eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  test -z "$libdir" && \
+		    func_fatal_error "\`$deplib' is not a valid libtool archive"
+		  test "$absdir" != "$libdir" && \
+		    func_warning "\`$deplib' seems to be moved"
+
+		  path="-L$absdir"
+		fi
+		;;
+	      esac
+	      case " $deplibs " in
+	      *" $path "*) ;;
+	      *) deplibs="$path $deplibs" ;;
+	      esac
+	    done
+	  fi # link_all_deplibs != no
+	fi # linkmode = lib
+      done # for deplib in $libs
+      if test "$pass" = link; then
+	if test "$linkmode" = "prog"; then
+	  compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+	  finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+	else
+	  compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	fi
+      fi
+      dependency_libs="$newdependency_libs"
+      if test "$pass" = dlpreopen; then
+	# Link the dlpreopened libraries before other libraries
+	for deplib in $save_deplibs; do
+	  deplibs="$deplib $deplibs"
+	done
+      fi
+      if test "$pass" != dlopen; then
+	if test "$pass" != conv; then
+	  # Make sure lib_search_path contains only unique directories.
+	  lib_search_path=
+	  for dir in $newlib_search_path; do
+	    case "$lib_search_path " in
+	    *" $dir "*) ;;
+	    *) func_append lib_search_path " $dir" ;;
+	    esac
+	  done
+	  newlib_search_path=
+	fi
+
+	if test "$linkmode,$pass" != "prog,link"; then
+	  vars="deplibs"
+	else
+	  vars="compile_deplibs finalize_deplibs"
+	fi
+	for var in $vars dependency_libs; do
+	  # Add libraries to $var in reverse order
+	  eval tmp_libs=\"\$$var\"
+	  new_libs=
+	  for deplib in $tmp_libs; do
+	    # FIXME: Pedantically, this is the right thing to do, so
+	    #        that some nasty dependency loop isn't accidentally
+	    #        broken:
+	    #new_libs="$deplib $new_libs"
+	    # Pragmatically, this seems to cause very few problems in
+	    # practice:
+	    case $deplib in
+	    -L*) new_libs="$deplib $new_libs" ;;
+	    -R*) ;;
+	    *)
+	      # And here is the reason: when a library appears more
+	      # than once as an explicit dependence of a library, or
+	      # is implicitly linked in more than once by the
+	      # compiler, it is considered special, and multiple
+	      # occurrences thereof are not removed.  Compare this
+	      # with having the same library being listed as a
+	      # dependency of multiple other libraries: in this case,
+	      # we know (pedantically, we assume) the library does not
+	      # need to be listed more than once, so we keep only the
+	      # last copy.  This is not always right, but it is rare
+	      # enough that we require users that really mean to play
+	      # such unportable linking tricks to link the library
+	      # using -Wl,-lname, so that libtool does not consider it
+	      # for duplicate removal.
+	      case " $specialdeplibs " in
+	      *" $deplib "*) new_libs="$deplib $new_libs" ;;
+	      *)
+		case " $new_libs " in
+		*" $deplib "*) ;;
+		*) new_libs="$deplib $new_libs" ;;
+		esac
+		;;
+	      esac
+	      ;;
+	    esac
+	  done
+	  tmp_libs=
+	  for deplib in $new_libs; do
+	    case $deplib in
+	    -L*)
+	      case " $tmp_libs " in
+	      *" $deplib "*) ;;
+	      *) func_append tmp_libs " $deplib" ;;
+	      esac
+	      ;;
+	    *) func_append tmp_libs " $deplib" ;;
+	    esac
+	  done
+	  eval $var=\"$tmp_libs\"
+	done # for var
+      fi
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs ; do
+	case " $predeps $postdeps $compiler_lib_search_path " in
+	*" $i "*)
+	  i=""
+	  ;;
+	esac
+	if test -n "$i" ; then
+	  func_append tmp_libs " $i"
+	fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test "$linkmode" = prog; then
+      dlfiles="$newdlfiles"
+    fi
+    if test "$linkmode" = prog || test "$linkmode" = lib; then
+      dlprefiles="$newdlprefiles"
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for archives"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for archives" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for archives"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for archives"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info/-version-number' is ignored for archives"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for archives"
+
+      test -n "$export_symbols$export_symbols_regex" && \
+	func_warning "\`-export-symbols' is ignored for archives"
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs="$output"
+      func_append objs "$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case $outputname in
+      lib*)
+	func_stripname 'lib' '.la' "$outputname"
+	name=$func_stripname_result
+	eval shared_ext=\"$shrext_cmds\"
+	eval libname=\"$libname_spec\"
+	;;
+      *)
+	test "$module" = no && \
+	  func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+	if test "$need_lib_prefix" != no; then
+	  # Add the "lib" prefix for modules if required
+	  func_stripname '' '.la' "$outputname"
+	  name=$func_stripname_result
+	  eval shared_ext=\"$shrext_cmds\"
+	  eval libname=\"$libname_spec\"
+	else
+	  func_stripname '' '.la' "$outputname"
+	  libname=$func_stripname_result
+	fi
+	;;
+      esac
+
+      if test -n "$objs"; then
+	if test "$deplibs_check_method" != pass_all; then
+	  func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+	else
+	  echo
+	  $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+	  $ECHO "*** objects $objs is not portable!"
+	  func_append libobjs " $objs"
+	fi
+      fi
+
+      test "$dlself" != no && \
+	func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+      set dummy $rpath
+      shift
+      test "$#" -gt 1 && \
+	func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+      install_libdir="$1"
+
+      oldlibs=
+      if test -z "$rpath"; then
+	if test "$build_libtool_libs" = yes; then
+	  # Building a libtool convenience library.
+	  # Some compilers have problems with a `.al' extension so
+	  # convenience libraries should have the same extension an
+	  # archive normally would.
+	  oldlibs="$output_objdir/$libname.$libext $oldlibs"
+	  build_libtool_libs=convenience
+	  build_old_libs=yes
+	fi
+
+	test -n "$vinfo" && \
+	  func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+	test -n "$release" && \
+	  func_warning "\`-release' is ignored for convenience libraries"
+      else
+
+	# Parse the version information argument.
+	save_ifs="$IFS"; IFS=':'
+	set dummy $vinfo 0 0 0
+	shift
+	IFS="$save_ifs"
+
+	test -n "$7" && \
+	  func_fatal_help "too many parameters to \`-version-info'"
+
+	# convert absolute version numbers to libtool ages
+	# this retains compatibility with .la files and attempts
+	# to make the code below a bit more comprehensible
+
+	case $vinfo_number in
+	yes)
+	  number_major="$1"
+	  number_minor="$2"
+	  number_revision="$3"
+	  #
+	  # There are really only two kinds -- those that
+	  # use the current revision as the major version
+	  # and those that subtract age and use age as
+	  # a minor version.  But, then there is irix
+	  # which has an extra 1 added just for fun
+	  #
+	  case $version_type in
+	  # correct linux to gnu/linux during the next big refactor
+	  darwin|linux|osf|windows|none)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_revision"
+	    ;;
+	  freebsd-aout|freebsd-elf|qnx|sunos)
+	    current="$number_major"
+	    revision="$number_minor"
+	    age="0"
+	    ;;
+	  irix|nonstopux)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_minor"
+	    lt_irix_increment=no
+	    ;;
+	  *)
+	    func_fatal_configuration "$modename: unknown library version type \`$version_type'"
+	    ;;
+	  esac
+	  ;;
+	no)
+	  current="$1"
+	  revision="$2"
+	  age="$3"
+	  ;;
+	esac
+
+	# Check that each of the things are valid numbers.
+	case $current in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "CURRENT \`$current' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $revision in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "REVISION \`$revision' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $age in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "AGE \`$age' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	if test "$age" -gt "$current"; then
+	  func_error "AGE \`$age' is greater than the current interface number \`$current'"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	fi
+
+	# Calculate the version variables.
+	major=
+	versuffix=
+	verstring=
+	case $version_type in
+	none) ;;
+
+	darwin)
+	  # Like Linux, but with the current version available in
+	  # verstring for coding it into the library header
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  # Darwin ld doesn't like 0 for these options...
+	  func_arith $current + 1
+	  minor_current=$func_arith_result
+	  xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+	  ;;
+
+	freebsd-aout)
+	  major=".$current"
+	  versuffix=".$current.$revision";
+	  ;;
+
+	freebsd-elf)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	irix | nonstopux)
+	  if test "X$lt_irix_increment" = "Xno"; then
+	    func_arith $current - $age
+	  else
+	    func_arith $current - $age + 1
+	  fi
+	  major=$func_arith_result
+
+	  case $version_type in
+	    nonstopux) verstring_prefix=nonstopux ;;
+	    *)         verstring_prefix=sgi ;;
+	  esac
+	  verstring="$verstring_prefix$major.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$revision
+	  while test "$loop" -ne 0; do
+	    func_arith $revision - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring_prefix$major.$iface:$verstring"
+	  done
+
+	  # Before this point, $major must not contain `.'.
+	  major=.$major
+	  versuffix="$major.$revision"
+	  ;;
+
+	linux) # correct to gnu/linux during the next big refactor
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  ;;
+
+	osf)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=".$current.$age.$revision"
+	  verstring="$current.$age.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$age
+	  while test "$loop" -ne 0; do
+	    func_arith $current - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring:${iface}.0"
+	  done
+
+	  # Make executables depend on our current version.
+	  func_append verstring ":${current}.0"
+	  ;;
+
+	qnx)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	sunos)
+	  major=".$current"
+	  versuffix=".$current.$revision"
+	  ;;
+
+	windows)
+	  # Use '-' rather than '.', since we only want one
+	  # extension on DOS 8.3 filesystems.
+	  func_arith $current - $age
+	  major=$func_arith_result
+	  versuffix="-$major"
+	  ;;
+
+	*)
+	  func_fatal_configuration "unknown library version type \`$version_type'"
+	  ;;
+	esac
+
+	# Clear the version info if we defaulted, and they specified a release.
+	if test -z "$vinfo" && test -n "$release"; then
+	  major=
+	  case $version_type in
+	  darwin)
+	    # we can't check for "0.0" in archive_cmds due to quoting
+	    # problems, so we reset it completely
+	    verstring=
+	    ;;
+	  *)
+	    verstring="0.0"
+	    ;;
+	  esac
+	  if test "$need_version" = no; then
+	    versuffix=
+	  else
+	    versuffix=".0.0"
+	  fi
+	fi
+
+	# Remove version info from name if versioning should be avoided
+	if test "$avoid_version" = yes && test "$need_version" = no; then
+	  major=
+	  versuffix=
+	  verstring=""
+	fi
+
+	# Check to see if the archive will have undefined symbols.
+	if test "$allow_undefined" = yes; then
+	  if test "$allow_undefined_flag" = unsupported; then
+	    func_warning "undefined symbols not allowed in $host shared libraries"
+	    build_libtool_libs=no
+	    build_old_libs=yes
+	  fi
+	else
+	  # Don't allow undefined symbols.
+	  allow_undefined_flag="$no_undefined_flag"
+	fi
+
+      fi
+
+      func_generate_dlsyms "$libname" "$libname" "yes"
+      func_append libobjs " $symfileobj"
+      test "X$libobjs" = "X " && libobjs=
+
+      if test "$opt_mode" != relink; then
+	# Remove our outputs, but don't remove object files since they
+	# may have been created when compiling PIC objects.
+	removelist=
+	tempremovelist=`$ECHO "$output_objdir/*"`
+	for p in $tempremovelist; do
+	  case $p in
+	    *.$objext | *.gcno)
+	       ;;
+	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+	       if test "X$precious_files_regex" != "X"; then
+		 if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+		 then
+		   continue
+		 fi
+	       fi
+	       func_append removelist " $p"
+	       ;;
+	    *) ;;
+	  esac
+	done
+	test -n "$removelist" && \
+	  func_show_eval "${RM}r \$removelist"
+      fi
+
+      # Now set the variables for building old libraries.
+      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+	func_append oldlibs " $output_objdir/$libname.$libext"
+
+	# Transform .lo files to .o files.
+	oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #	lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+      #	deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+      #	dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+      #done
+
+      if test -n "$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	temp_xrpath=
+	for libdir in $xrpath; do
+	  func_replace_sysroot "$libdir"
+	  func_append temp_xrpath " -R$func_replace_sysroot_result"
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+	if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+	  dependency_libs="$temp_xrpath $dependency_libs"
+	fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles="$dlfiles"
+      dlfiles=
+      for lib in $old_dlfiles; do
+	case " $dlprefiles $dlfiles " in
+	*" $lib "*) ;;
+	*) func_append dlfiles " $lib" ;;
+	esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles="$dlprefiles"
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+	case "$dlprefiles " in
+	*" $lib "*) ;;
+	*) func_append dlprefiles " $lib" ;;
+	esac
+      done
+
+      if test "$build_libtool_libs" = yes; then
+	if test -n "$rpath"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # these systems don't actually have a c library (as such)!
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C library is in the System framework
+	    func_append deplibs " System.ltframework"
+	    ;;
+	  *-*-netbsd*)
+	    # Don't link with libc until the a.out ld.so is fixed.
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    ;;
+	  *)
+	    # Add libc to deplibs on all other systems if necessary.
+	    if test "$build_libtool_need_lc" = "yes"; then
+	      func_append deplibs " -lc"
+	    fi
+	    ;;
+	  esac
+	fi
+
+	# Transform deplibs into only deplibs that can be linked in shared.
+	name_save=$name
+	libname_save=$libname
+	release_save=$release
+	versuffix_save=$versuffix
+	major_save=$major
+	# I'm not sure if I'm treating the release correctly.  I think
+	# release should show up in the -l (ie -lgmp5) so we don't want to
+	# add it in twice.  Is that correct?
+	release=""
+	versuffix=""
+	major=""
+	newdeplibs=
+	droppeddeps=no
+	case $deplibs_check_method in
+	pass_all)
+	  # Don't check for shared/static.  Everything works.
+	  # This might be a little naive.  We might want to check
+	  # whether the library exists or not.  But this is on
+	  # osf3 & osf4 and I'm not really sure... Just
+	  # implementing what was already the behavior.
+	  newdeplibs=$deplibs
+	  ;;
+	test_compile)
+	  # This code stresses the "libraries are programs" paradigm to its
+	  # limits. Maybe even breaks it.  We compile a program, linking it
+	  # against the deplibs as a proxy for the library.  Then we can check
+	  # whether they linked in statically or dynamically with ldd.
+	  $opt_dry_run || $RM conftest.c
+	  cat > conftest.c <<EOF
+	  int main() { return 0; }
+EOF
+	  $opt_dry_run || $RM conftest
+	  if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+	    ldd_output=`ldd conftest`
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		  case " $predeps $postdeps " in
+		  *" $i "*)
+		    func_append newdeplibs " $i"
+		    i=""
+		    ;;
+		  esac
+		fi
+		if test -n "$i" ; then
+		  libname=`eval "\\$ECHO \"$libname_spec\""`
+		  deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		  set dummy $deplib_matches; shift
+		  deplib_match=$1
+		  if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		    func_append newdeplibs " $i"
+		  else
+		    droppeddeps=yes
+		    echo
+		    $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		    echo "*** I have the capability to make that library automatically link in when"
+		    echo "*** you link to this library.  But I can only do this if you have a"
+		    echo "*** shared version of the library, which I believe you do not have"
+		    echo "*** because a test_compile did reveal that the linker did not use it for"
+		    echo "*** its dynamic dependency list that programs get resolved with at runtime."
+		  fi
+		fi
+		;;
+	      *)
+		func_append newdeplibs " $i"
+		;;
+	      esac
+	    done
+	  else
+	    # Error occurred in the first compile.  Let's try to salvage
+	    # the situation: Compile a separate program for each library.
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		$opt_dry_run || $RM conftest
+		if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+		  ldd_output=`ldd conftest`
+		  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		    case " $predeps $postdeps " in
+		    *" $i "*)
+		      func_append newdeplibs " $i"
+		      i=""
+		      ;;
+		    esac
+		  fi
+		  if test -n "$i" ; then
+		    libname=`eval "\\$ECHO \"$libname_spec\""`
+		    deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		    set dummy $deplib_matches; shift
+		    deplib_match=$1
+		    if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		      func_append newdeplibs " $i"
+		    else
+		      droppeddeps=yes
+		      echo
+		      $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		      echo "*** I have the capability to make that library automatically link in when"
+		      echo "*** you link to this library.  But I can only do this if you have a"
+		      echo "*** shared version of the library, which you do not appear to have"
+		      echo "*** because a test_compile did reveal that the linker did not use this one"
+		      echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+		    fi
+		  fi
+		else
+		  droppeddeps=yes
+		  echo
+		  $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
+		  echo "*** make it link in!  You will probably need to install it or some"
+		  echo "*** library that it depends on before this library will be fully"
+		  echo "*** functional.  Installing it before continuing would be even better."
+		fi
+		;;
+	      *)
+		func_append newdeplibs " $i"
+		;;
+	      esac
+	    done
+	  fi
+	  ;;
+	file_magic*)
+	  set dummy $deplibs_check_method; shift
+	  file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		if test -n "$file_magic_glob"; then
+		  libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+		else
+		  libnameglob=$libname
+		fi
+		test "$want_nocaseglob" = yes && nocaseglob=`shopt -p nocaseglob`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  if test "$want_nocaseglob" = yes; then
+		    shopt -s nocaseglob
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		    $nocaseglob
+		  else
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		  fi
+		  for potent_lib in $potential_libs; do
+		      # Follow soft links.
+		      if ls -lLd "$potent_lib" 2>/dev/null |
+			 $GREP " -> " >/dev/null; then
+			continue
+		      fi
+		      # The statement above tries to avoid entering an
+		      # endless loop below, in case of cyclic links.
+		      # We might still enter an endless loop, since a link
+		      # loop can be closed while we follow links,
+		      # but so what?
+		      potlib="$potent_lib"
+		      while test -h "$potlib" 2>/dev/null; do
+			potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+			case $potliblink in
+			[\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+			*) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+			esac
+		      done
+		      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+			 $SED -e 10q |
+			 $EGREP "$file_magic_regex" > /dev/null; then
+			func_append newdeplibs " $a_deplib"
+			a_deplib=""
+			break 2
+		      fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a file magic. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	match_pattern*)
+	  set dummy $deplibs_check_method; shift
+	  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		    potlib="$potent_lib" # see symlink-check above in file_magic test
+		    if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+		       $EGREP "$match_pattern_regex" > /dev/null; then
+		      func_append newdeplibs " $a_deplib"
+		      a_deplib=""
+		      break 2
+		    fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a regex pattern. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	none | unknown | *)
+	  newdeplibs=""
+	  tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+	  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	    for i in $predeps $postdeps ; do
+	      # can't use Xsed below, because $i might contain '/'
+	      tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+	    done
+	  fi
+	  case $tmp_deplibs in
+	  *[!\	\ ]*)
+	    echo
+	    if test "X$deplibs_check_method" = "Xnone"; then
+	      echo "*** Warning: inter-library dependencies are not supported in this platform."
+	    else
+	      echo "*** Warning: inter-library dependencies are not known to be supported."
+	    fi
+	    echo "*** All declared inter-library dependencies are being dropped."
+	    droppeddeps=yes
+	    ;;
+	  esac
+	  ;;
+	esac
+	versuffix=$versuffix_save
+	major=$major_save
+	release=$release_save
+	libname=$libname_save
+	name=$name_save
+
+	case $host in
+	*-*-rhapsody* | *-*-darwin1.[012])
+	  # On Rhapsody replace the C library with the System framework
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+	  ;;
+	esac
+
+	if test "$droppeddeps" = yes; then
+	  if test "$module" = yes; then
+	    echo
+	    echo "*** Warning: libtool could not satisfy all declared inter-library"
+	    $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
+	    echo "*** a static module, that should work as long as the dlopening"
+	    echo "*** application is linked with the -dlopen flag."
+	    if test -z "$global_symbol_pipe"; then
+	      echo
+	      echo "*** However, this would only work if libtool was able to extract symbol"
+	      echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+	      echo "*** not find such a program.  So, this module is probably useless."
+	      echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	    fi
+	    if test "$build_old_libs" = no; then
+	      oldlibs="$output_objdir/$libname.$libext"
+	      build_libtool_libs=module
+	      build_old_libs=yes
+	    else
+	      build_libtool_libs=no
+	    fi
+	  else
+	    echo "*** The inter-library dependencies that have been dropped here will be"
+	    echo "*** automatically added whenever a program is linked with this library"
+	    echo "*** or is declared to -dlopen it."
+
+	    if test "$allow_undefined" = no; then
+	      echo
+	      echo "*** Since this library must not contain undefined symbols,"
+	      echo "*** because either the platform does not support them or"
+	      echo "*** it was explicitly requested with -no-undefined,"
+	      echo "*** libtool will only create a static version of it."
+	      if test "$build_old_libs" = no; then
+		oldlibs="$output_objdir/$libname.$libext"
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  fi
+	fi
+	# Done checking deplibs!
+	deplibs=$newdeplibs
+      fi
+      # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+      case $host in
+	*-*-darwin*)
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  ;;
+      esac
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      deplibs="$new_libs"
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test "$build_libtool_libs" = yes; then
+	# Remove ${wl} instances when linking with ld.
+	# FIXME: should test the right _cmds variable.
+	case $archive_cmds in
+	  *\$LD\ *) wl= ;;
+        esac
+	if test "$hardcode_into_libs" = yes; then
+	  # Hardcode the library paths
+	  hardcode_libdirs=
+	  dep_rpath=
+	  rpath="$finalize_rpath"
+	  test "$opt_mode" != relink && rpath="$compile_rpath$rpath"
+	  for libdir in $rpath; do
+	    if test -n "$hardcode_libdir_flag_spec"; then
+	      if test -n "$hardcode_libdir_separator"; then
+		func_replace_sysroot "$libdir"
+		libdir=$func_replace_sysroot_result
+		if test -z "$hardcode_libdirs"; then
+		  hardcode_libdirs="$libdir"
+		else
+		  # Just accumulate the unique libdirs.
+		  case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+		  *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		    ;;
+		  *)
+		    func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		    ;;
+		  esac
+		fi
+	      else
+		eval flag=\"$hardcode_libdir_flag_spec\"
+		func_append dep_rpath " $flag"
+	      fi
+	    elif test -n "$runpath_var"; then
+	      case "$perm_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append perm_rpath " $libdir" ;;
+	      esac
+	    fi
+	  done
+	  # Substitute the hardcoded libdirs into the rpath.
+	  if test -n "$hardcode_libdir_separator" &&
+	     test -n "$hardcode_libdirs"; then
+	    libdir="$hardcode_libdirs"
+	    eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+	  fi
+	  if test -n "$runpath_var" && test -n "$perm_rpath"; then
+	    # We should set the runpath_var.
+	    rpath=
+	    for dir in $perm_rpath; do
+	      func_append rpath "$dir:"
+	    done
+	    eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+	  fi
+	  test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+	fi
+
+	shlibpath="$finalize_shlibpath"
+	test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+	if test -n "$shlibpath"; then
+	  eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+	fi
+
+	# Get the real and link names of the library.
+	eval shared_ext=\"$shrext_cmds\"
+	eval library_names=\"$library_names_spec\"
+	set dummy $library_names
+	shift
+	realname="$1"
+	shift
+
+	if test -n "$soname_spec"; then
+	  eval soname=\"$soname_spec\"
+	else
+	  soname="$realname"
+	fi
+	if test -z "$dlname"; then
+	  dlname=$soname
+	fi
+
+	lib="$output_objdir/$realname"
+	linknames=
+	for link
+	do
+	  func_append linknames " $link"
+	done
+
+	# Use standard objects if they are pic
+	test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	test "X$libobjs" = "X " && libobjs=
+
+	delfiles=
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+	  export_symbols="$output_objdir/$libname.uexp"
+	  func_append delfiles " $export_symbols"
+	fi
+
+	orig_export_symbols=
+	case $host_os in
+	cygwin* | mingw* | cegcc*)
+	  if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+	    # exporting using user supplied symfile
+	    if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+	      # and it's NOT already a .def file. Must figure out
+	      # which of the given symbols are data symbols and tag
+	      # them as such. So, trigger use of export_symbols_cmds.
+	      # export_symbols gets reassigned inside the "prepare
+	      # the list of exported symbols" if statement, so the
+	      # include_expsyms logic still works.
+	      orig_export_symbols="$export_symbols"
+	      export_symbols=
+	      always_export_symbols=yes
+	    fi
+	  fi
+	  ;;
+	esac
+
+	# Prepare the list of exported symbols
+	if test -z "$export_symbols"; then
+	  if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+	    func_verbose "generating symbol list for \`$libname.la'"
+	    export_symbols="$output_objdir/$libname.exp"
+	    $opt_dry_run || $RM $export_symbols
+	    cmds=$export_symbols_cmds
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd1 in $cmds; do
+	      IFS="$save_ifs"
+	      # Take the normal branch if the nm_file_list_spec branch
+	      # doesn't work or if tool conversion is not needed.
+	      case $nm_file_list_spec~$to_tool_file_cmd in
+		*~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+		  try_normal_branch=yes
+		  eval cmd=\"$cmd1\"
+		  func_len " $cmd"
+		  len=$func_len_result
+		  ;;
+		*)
+		  try_normal_branch=no
+		  ;;
+	      esac
+	      if test "$try_normal_branch" = yes \
+		 && { test "$len" -lt "$max_cmd_len" \
+		      || test "$max_cmd_len" -le -1; }
+	      then
+		func_show_eval "$cmd" 'exit $?'
+		skipped_export=false
+	      elif test -n "$nm_file_list_spec"; then
+		func_basename "$output"
+		output_la=$func_basename_result
+		save_libobjs=$libobjs
+		save_output=$output
+		output=${output_objdir}/${output_la}.nm
+		func_to_tool_file "$output"
+		libobjs=$nm_file_list_spec$func_to_tool_file_result
+		func_append delfiles " $output"
+		func_verbose "creating $NM input file list: $output"
+		for obj in $save_libobjs; do
+		  func_to_tool_file "$obj"
+		  $ECHO "$func_to_tool_file_result"
+		done > "$output"
+		eval cmd=\"$cmd1\"
+		func_show_eval "$cmd" 'exit $?'
+		output=$save_output
+		libobjs=$save_libobjs
+		skipped_export=false
+	      else
+		# The command line is too long to execute in one step.
+		func_verbose "using reloadable object file for export list..."
+		skipped_export=:
+		# Break out early, otherwise skipped_export may be
+		# set to false by a later but shorter cmd.
+		break
+	      fi
+	    done
+	    IFS="$save_ifs"
+	    if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+	fi
+
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  tmp_export_symbols="$export_symbols"
+	  test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	  $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	fi
+
+	if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+	  # The given exports_symbols file has to be filtered, so filter it.
+	  func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	  # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	  # 's' commands which not all seds can handle. GNU sed should be fine
+	  # though. Also, the filter scales superlinearly with the number of
+	  # global variables. join(1) would be nice here, but unfortunately
+	  # isn't a blessed tool.
+	  $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	  func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	  export_symbols=$output_objdir/$libname.def
+	  $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	fi
+
+	tmp_deplibs=
+	for test_deplib in $deplibs; do
+	  case " $convenience " in
+	  *" $test_deplib "*) ;;
+	  *)
+	    func_append tmp_deplibs " $test_deplib"
+	    ;;
+	  esac
+	done
+	deplibs="$tmp_deplibs"
+
+	if test -n "$convenience"; then
+	  if test -n "$whole_archive_flag_spec" &&
+	    test "$compiler_needs_object" = yes &&
+	    test -z "$libobjs"; then
+	    # extract the archives, so we have objects to list.
+	    # TODO: could optimize this to just extract one archive.
+	    whole_archive_flag_spec=
+	  fi
+	  if test -n "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  else
+	    gentop="$output_objdir/${outputname}x"
+	    func_append generated " $gentop"
+
+	    func_extract_archives $gentop $convenience
+	    func_append libobjs " $func_extract_archives_result"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	fi
+
+	if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+	  eval flag=\"$thread_safe_flag_spec\"
+	  func_append linker_flags " $flag"
+	fi
+
+	# Make a backup of the uninstalled library when relinking
+	if test "$opt_mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+	fi
+
+	# Do each of the archive commands.
+	if test "$module" = yes && test -n "$module_cmds" ; then
+	  if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	    eval test_cmds=\"$module_expsym_cmds\"
+	    cmds=$module_expsym_cmds
+	  else
+	    eval test_cmds=\"$module_cmds\"
+	    cmds=$module_cmds
+	  fi
+	else
+	  if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	    eval test_cmds=\"$archive_expsym_cmds\"
+	    cmds=$archive_expsym_cmds
+	  else
+	    eval test_cmds=\"$archive_cmds\"
+	    cmds=$archive_cmds
+	  fi
+	fi
+
+	if test "X$skipped_export" != "X:" &&
+	   func_len " $test_cmds" &&
+	   len=$func_len_result &&
+	   test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  :
+	else
+	  # The command line is too long to link in one step, link piecewise
+	  # or, if using GNU ld and skipped_export is not :, use a linker
+	  # script.
+
+	  # Save the value of $output and $libobjs because we want to
+	  # use them later.  If we have whole_archive_flag_spec, we
+	  # want to use save_libobjs as it was before
+	  # whole_archive_flag_spec was expanded, because we can't
+	  # assume the linker understands whole_archive_flag_spec.
+	  # This may have to be revisited, in case too many
+	  # convenience libraries get linked in and end up exceeding
+	  # the spec.
+	  if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	  fi
+	  save_output=$output
+	  func_basename "$output"
+	  output_la=$func_basename_result
+
+	  # Clear the reloadable object creation command queue and
+	  # initialize k to one.
+	  test_cmds=
+	  concat_cmds=
+	  objlist=
+	  last_robj=
+	  k=1
+
+	  if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+	    output=${output_objdir}/${output_la}.lnkscript
+	    func_verbose "creating GNU ld script: $output"
+	    echo 'INPUT (' > $output
+	    for obj in $save_libobjs
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    echo ')' >> $output
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$func_to_tool_file_result
+	  elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+	    output=${output_objdir}/${output_la}.lnk
+	    func_verbose "creating linker input file list: $output"
+	    : > $output
+	    set x $save_libobjs
+	    shift
+	    firstobj=
+	    if test "$compiler_needs_object" = yes; then
+	      firstobj="$1 "
+	      shift
+	    fi
+	    for obj
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+	  else
+	    if test -n "$save_libobjs"; then
+	      func_verbose "creating reloadable object files..."
+	      output=$output_objdir/$output_la-${k}.$objext
+	      eval test_cmds=\"$reload_cmds\"
+	      func_len " $test_cmds"
+	      len0=$func_len_result
+	      len=$len0
+
+	      # Loop over the list of objects to be linked.
+	      for obj in $save_libobjs
+	      do
+		func_len " $obj"
+		func_arith $len + $func_len_result
+		len=$func_arith_result
+		if test "X$objlist" = X ||
+		   test "$len" -lt "$max_cmd_len"; then
+		  func_append objlist " $obj"
+		else
+		  # The command $test_cmds is almost too long, add a
+		  # command to the queue.
+		  if test "$k" -eq 1 ; then
+		    # The first file doesn't have a previous command to add.
+		    reload_objs=$objlist
+		    eval concat_cmds=\"$reload_cmds\"
+		  else
+		    # All subsequent reloadable object files will link in
+		    # the last one created.
+		    reload_objs="$objlist $last_robj"
+		    eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+		  fi
+		  last_robj=$output_objdir/$output_la-${k}.$objext
+		  func_arith $k + 1
+		  k=$func_arith_result
+		  output=$output_objdir/$output_la-${k}.$objext
+		  objlist=" $obj"
+		  func_len " $last_robj"
+		  func_arith $len0 + $func_len_result
+		  len=$func_arith_result
+		fi
+	      done
+	      # Handle the remaining objects by creating one last
+	      # reloadable object file.  All subsequent reloadable object
+	      # files will link in the last one created.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      reload_objs="$objlist $last_robj"
+	      eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
+	      if test -n "$last_robj"; then
+	        eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+	      fi
+	      func_append delfiles " $output"
+
+	    else
+	      output=
+	    fi
+
+	    if ${skipped_export-false}; then
+	      func_verbose "generating symbol list for \`$libname.la'"
+	      export_symbols="$output_objdir/$libname.exp"
+	      $opt_dry_run || $RM $export_symbols
+	      libobjs=$output
+	      # Append the command to create the export file.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+	      if test -n "$last_robj"; then
+		eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+	      fi
+	    fi
+
+	    test -n "$save_libobjs" &&
+	      func_verbose "creating a temporary reloadable object file: $output"
+
+	    # Loop through the commands generated above and execute them.
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd in $concat_cmds; do
+	      IFS="$save_ifs"
+	      $opt_silent || {
+		  func_quote_for_expand "$cmd"
+		  eval "func_echo $func_quote_for_expand_result"
+	      }
+	      $opt_dry_run || eval "$cmd" || {
+		lt_exit=$?
+
+		# Restore the uninstalled library and exit
+		if test "$opt_mode" = relink; then
+		  ( cd "$output_objdir" && \
+		    $RM "${realname}T" && \
+		    $MV "${realname}U" "$realname" )
+		fi
+
+		exit $lt_exit
+	      }
+	    done
+	    IFS="$save_ifs"
+
+	    if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+
+          if ${skipped_export-false}; then
+	    if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	      tmp_export_symbols="$export_symbols"
+	      test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	      $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	    fi
+
+	    if test -n "$orig_export_symbols"; then
+	      # The given exports_symbols file has to be filtered, so filter it.
+	      func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	      # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	      # 's' commands which not all seds can handle. GNU sed should be fine
+	      # though. Also, the filter scales superlinearly with the number of
+	      # global variables. join(1) would be nice here, but unfortunately
+	      # isn't a blessed tool.
+	      $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	      func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	      export_symbols=$output_objdir/$libname.def
+	      $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	    fi
+	  fi
+
+	  libobjs=$output
+	  # Restore the value of output.
+	  output=$save_output
+
+	  if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	  # Expand the library linking commands again to reset the
+	  # value of $libobjs for piecewise linking.
+
+	  # Do each of the archive commands.
+	  if test "$module" = yes && test -n "$module_cmds" ; then
+	    if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	      cmds=$module_expsym_cmds
+	    else
+	      cmds=$module_cmds
+	    fi
+	  else
+	    if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	      cmds=$archive_expsym_cmds
+	    else
+	      cmds=$archive_cmds
+	    fi
+	  fi
+	fi
+
+	if test -n "$delfiles"; then
+	  # Append the command to remove temporary files to $cmds.
+	  eval cmds=\"\$cmds~\$RM $delfiles\"
+	fi
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append libobjs " $func_extract_archives_result"
+	  test "X$libobjs" = "X " && libobjs=
+	fi
+
+	save_ifs="$IFS"; IFS='~'
+	for cmd in $cmds; do
+	  IFS="$save_ifs"
+	  eval cmd=\"$cmd\"
+	  $opt_silent || {
+	    func_quote_for_expand "$cmd"
+	    eval "func_echo $func_quote_for_expand_result"
+	  }
+	  $opt_dry_run || eval "$cmd" || {
+	    lt_exit=$?
+
+	    # Restore the uninstalled library and exit
+	    if test "$opt_mode" = relink; then
+	      ( cd "$output_objdir" && \
+	        $RM "${realname}T" && \
+		$MV "${realname}U" "$realname" )
+	    fi
+
+	    exit $lt_exit
+	  }
+	done
+	IFS="$save_ifs"
+
+	# Restore the uninstalled library and exit
+	if test "$opt_mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+	  if test -n "$convenience"; then
+	    if test -z "$whole_archive_flag_spec"; then
+	      func_show_eval '${RM}r "$gentop"'
+	    fi
+	  fi
+
+	  exit $EXIT_SUCCESS
+	fi
+
+	# Create links to the real library.
+	for linkname in $linknames; do
+	  if test "$realname" != "$linkname"; then
+	    func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+	  fi
+	done
+
+	# If -module or -export-dynamic was specified, set the dlname.
+	if test "$module" = yes || test "$export_dynamic" = yes; then
+	  # On all known operating systems, these are identical.
+	  dlname="$soname"
+	fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for objects"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for objects" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for objects"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for objects"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for objects"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for objects"
+
+      case $output in
+      *.lo)
+	test -n "$objs$old_deplibs" && \
+	  func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+	libobj=$output
+	func_lo2o "$libobj"
+	obj=$func_lo2o_result
+	;;
+      *)
+	libobj=
+	obj="$output"
+	;;
+      esac
+
+      # Delete the old objects.
+      $opt_dry_run || $RM $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # reload_cmds runs $LD directly, so let us get rid of
+      # -Wl from whole_archive_flag_spec and hope we can get by with
+      # turning comma into space..
+      wl=
+
+      if test -n "$convenience"; then
+	if test -n "$whole_archive_flag_spec"; then
+	  eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+	  reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+	else
+	  gentop="$output_objdir/${obj}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $convenience
+	  reload_conv_objs="$reload_objs $func_extract_archives_result"
+	fi
+      fi
+
+      # If we're not building shared, we need to use non_pic_objs
+      test "$build_libtool_libs" != yes && libobjs="$non_pic_objects"
+
+      # Create the old-style object.
+      reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+      output="$obj"
+      func_execute_cmds "$reload_cmds" 'exit $?'
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$build_libtool_libs" != yes; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	# Create an invalid libtool object if no PIC, so that we don't
+	# accidentally link it into a program.
+	# $show "echo timestamp > $libobj"
+	# $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+	exit $EXIT_SUCCESS
+      fi
+
+      if test -n "$pic_flag" || test "$pic_mode" != default; then
+	# Only do commands if we really have different PIC objects.
+	reload_objs="$libobjs $reload_conv_objs"
+	output="$libobj"
+	func_execute_cmds "$reload_cmds" 'exit $?'
+      fi
+
+      if test -n "$gentop"; then
+	func_show_eval '${RM}r "$gentop"'
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+	*cygwin*) func_stripname '' '.exe' "$output"
+	          output=$func_stripname_result.exe;;
+      esac
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for programs"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for programs"
+
+      test "$preload" = yes \
+        && test "$dlopen_support" = unknown \
+	&& test "$dlopen_self" = unknown \
+	&& test "$dlopen_self_static" = unknown && \
+	  func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+	# On Rhapsody replace the C library is the System framework
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	;;
+      esac
+
+      case $host in
+      *-*-darwin*)
+	# Don't allow lazy linking, it breaks C++ global constructors
+	# But is supposedly fixed on 10.4 or later (yay!).
+	if test "$tagname" = CXX ; then
+	  case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+	    10.[0123])
+	      func_append compile_command " ${wl}-bind_at_load"
+	      func_append finalize_command " ${wl}-bind_at_load"
+	    ;;
+	  esac
+	fi
+	# Time to change all our "foo.ltframework" stuff back to "-framework foo"
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	;;
+      esac
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $compile_deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $compile_deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      compile_deplibs="$new_libs"
+
+
+      func_append compile_command " $compile_deplibs"
+      func_append finalize_command " $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	for libdir in $rpath $xrpath; do
+	  # This is the magic to use -rpath.
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append perm_rpath " $libdir" ;;
+	  esac
+	fi
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$libdir:"*) ;;
+	  ::) dllsearchpath=$libdir;;
+	  *) func_append dllsearchpath ":$libdir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath="$rpath"
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$finalize_perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_perm_rpath " $libdir" ;;
+	  esac
+	fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath="$rpath"
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+	# Transform all the library objects into standard objects.
+	compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+      fi
+
+      func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+      # template prelinking step
+      if test -n "$prelink_cmds"; then
+	func_execute_cmds "$prelink_cmds" 'exit $?'
+      fi
+
+      wrappers_required=yes
+      case $host in
+      *cegcc* | *mingw32ce*)
+        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+        wrappers_required=no
+        ;;
+      *cygwin* | *mingw* )
+        if test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      *)
+        if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      esac
+      if test "$wrappers_required" = no; then
+	# Replace the output file specification.
+	compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	link_command="$compile_command$compile_rpath"
+
+	# We have no uninstalled library dependencies, so finalize right now.
+	exit_status=0
+	func_show_eval "$link_command" 'exit_status=$?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	# Delete the generated files.
+	if test -f "$output_objdir/${outputname}S.${objext}"; then
+	  func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+	fi
+
+	exit $exit_status
+      fi
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+	compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+	finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+	if test -n "$perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+	if test -n "$finalize_perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $finalize_perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+      fi
+
+      if test "$no_install" = yes; then
+	# We don't need to create a wrapper script.
+	link_command="$compile_var$compile_command$compile_rpath"
+	# Replace the output file specification.
+	link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	# Delete the old output file.
+	$opt_dry_run || $RM $output
+	# Link the executable and exit
+	func_show_eval "$link_command" 'exit $?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$hardcode_action" = relink; then
+	# Fast installation is not supported
+	link_command="$compile_var$compile_command$compile_rpath"
+	relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+	func_warning "this platform does not like uninstalled shared libraries"
+	func_warning "\`$output' will be relinked during installation"
+      else
+	if test "$fast_install" != no; then
+	  link_command="$finalize_var$compile_command$finalize_rpath"
+	  if test "$fast_install" = yes; then
+	    relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+	  else
+	    # fast_install is set to needless
+	    relink_command=
+	  fi
+	else
+	  link_command="$compile_var$compile_command$compile_rpath"
+	  relink_command="$finalize_var$finalize_command$finalize_rpath"
+	fi
+      fi
+
+      # Replace the output file specification.
+      link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      func_show_eval "$link_command" 'exit $?'
+
+      if test -n "$postlink_cmds"; then
+	func_to_tool_file "$output_objdir/$outputname"
+	postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	func_execute_cmds "$postlink_cmds" 'exit $?'
+      fi
+
+      # Now create the wrapper script.
+      func_verbose "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+	# Preserve any variables that may affect compiler behavior
+	for var in $variables_saved_for_relink; do
+	  if eval test -z \"\${$var+set}\"; then
+	    relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	  elif eval var_value=\$$var; test -z "$var_value"; then
+	    relink_command="$var=; export $var; $relink_command"
+	  else
+	    func_quote_for_eval "$var_value"
+	    relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	  fi
+	done
+	relink_command="(cd `pwd`; $relink_command)"
+	relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if not in dry run mode.
+      $opt_dry_run || {
+	# win32 will think the script is a binary if it has
+	# a .exe suffix, so we strip it off here.
+	case $output in
+	  *.exe) func_stripname '' '.exe' "$output"
+	         output=$func_stripname_result ;;
+	esac
+	# test for cygwin because mv fails w/o .exe extensions
+	case $host in
+	  *cygwin*)
+	    exeext=.exe
+	    func_stripname '' '.exe' "$outputname"
+	    outputname=$func_stripname_result ;;
+	  *) exeext= ;;
+	esac
+	case $host in
+	  *cygwin* | *mingw* )
+	    func_dirname_and_basename "$output" "" "."
+	    output_name=$func_basename_result
+	    output_path=$func_dirname_result
+	    cwrappersource="$output_path/$objdir/lt-$output_name.c"
+	    cwrapper="$output_path/$output_name.exe"
+	    $RM $cwrappersource $cwrapper
+	    trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_cwrapperexe_src > $cwrappersource
+
+	    # The wrapper executable is built using the $host compiler,
+	    # because it contains $host paths and files. If cross-
+	    # compiling, it, like the target executable, must be
+	    # executed on the $host or under an emulation environment.
+	    $opt_dry_run || {
+	      $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+	      $STRIP $cwrapper
+	    }
+
+	    # Now, create the wrapper script for func_source use:
+	    func_ltwrapper_scriptname $cwrapper
+	    $RM $func_ltwrapper_scriptname_result
+	    trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+	    $opt_dry_run || {
+	      # note: this script will not be executed, so do not chmod.
+	      if test "x$build" = "x$host" ; then
+		$cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+	      else
+		func_emit_wrapper no > $func_ltwrapper_scriptname_result
+	      fi
+	    }
+	  ;;
+	  * )
+	    $RM $output
+	    trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_wrapper no > $output
+	    chmod +x $output
+	  ;;
+	esac
+      }
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      if test "$build_libtool_libs" = convenience; then
+	oldobjs="$libobjs_save $symfileobj"
+	addlibs="$convenience"
+	build_libtool_libs=no
+      else
+	if test "$build_libtool_libs" = module; then
+	  oldobjs="$libobjs_save"
+	  build_libtool_libs=no
+	else
+	  oldobjs="$old_deplibs $non_pic_objects"
+	  if test "$preload" = yes && test -f "$symfileobj"; then
+	    func_append oldobjs " $symfileobj"
+	  fi
+	fi
+	addlibs="$old_convenience"
+      fi
+
+      if test -n "$addlibs"; then
+	gentop="$output_objdir/${outputname}x"
+	func_append generated " $gentop"
+
+	func_extract_archives $gentop $addlibs
+	func_append oldobjs " $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+	cmds=$old_archive_from_new_cmds
+      else
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append oldobjs " $func_extract_archives_result"
+	fi
+
+	# POSIX demands no paths to be encoded in archives.  We have
+	# to avoid creating archives with duplicate basenames if we
+	# might have to extract them afterwards, e.g., when creating a
+	# static archive out of a convenience library, or when linking
+	# the entirety of a libtool archive into another (currently
+	# not supported by libtool).
+	if (for obj in $oldobjs
+	    do
+	      func_basename "$obj"
+	      $ECHO "$func_basename_result"
+	    done | sort | sort -uc >/dev/null 2>&1); then
+	  :
+	else
+	  echo "copying selected object files to avoid basename conflicts..."
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+	  func_mkdir_p "$gentop"
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  counter=1
+	  for obj in $save_oldobjs
+	  do
+	    func_basename "$obj"
+	    objbase="$func_basename_result"
+	    case " $oldobjs " in
+	    " ") oldobjs=$obj ;;
+	    *[\ /]"$objbase "*)
+	      while :; do
+		# Make sure we don't pick an alternate name that also
+		# overlaps.
+		newobj=lt$counter-$objbase
+		func_arith $counter + 1
+		counter=$func_arith_result
+		case " $oldobjs " in
+		*[\ /]"$newobj "*) ;;
+		*) if test ! -f "$gentop/$newobj"; then break; fi ;;
+		esac
+	      done
+	      func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+	      func_append oldobjs " $gentop/$newobj"
+	      ;;
+	    *) func_append oldobjs " $obj" ;;
+	    esac
+	  done
+	fi
+	func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+	tool_oldlib=$func_to_tool_file_result
+	eval cmds=\"$old_archive_cmds\"
+
+	func_len " $cmds"
+	len=$func_len_result
+	if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  cmds=$old_archive_cmds
+	elif test -n "$archiver_list_spec"; then
+	  func_verbose "using command file archive linking..."
+	  for obj in $oldobjs
+	  do
+	    func_to_tool_file "$obj"
+	    $ECHO "$func_to_tool_file_result"
+	  done > $output_objdir/$libname.libcmd
+	  func_to_tool_file "$output_objdir/$libname.libcmd"
+	  oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+	  cmds=$old_archive_cmds
+	else
+	  # the command line is too long to link in one step, link in parts
+	  func_verbose "using piecewise archive linking..."
+	  save_RANLIB=$RANLIB
+	  RANLIB=:
+	  objlist=
+	  concat_cmds=
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  # Is there a better way of finding the last object in the list?
+	  for obj in $save_oldobjs
+	  do
+	    last_oldobj=$obj
+	  done
+	  eval test_cmds=\"$old_archive_cmds\"
+	  func_len " $test_cmds"
+	  len0=$func_len_result
+	  len=$len0
+	  for obj in $save_oldobjs
+	  do
+	    func_len " $obj"
+	    func_arith $len + $func_len_result
+	    len=$func_arith_result
+	    func_append objlist " $obj"
+	    if test "$len" -lt "$max_cmd_len"; then
+	      :
+	    else
+	      # the above command should be used before it gets too long
+	      oldobjs=$objlist
+	      if test "$obj" = "$last_oldobj" ; then
+		RANLIB=$save_RANLIB
+	      fi
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+	      objlist=
+	      len=$len0
+	    fi
+	  done
+	  RANLIB=$save_RANLIB
+	  oldobjs=$objlist
+	  if test "X$oldobjs" = "X" ; then
+	    eval cmds=\"\$concat_cmds\"
+	  else
+	    eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+	  fi
+	fi
+      fi
+      func_execute_cmds "$cmds" 'exit $?'
+    done
+
+    test -n "$generated" && \
+      func_show_eval "${RM}r$generated"
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      func_verbose "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+	if eval test -z \"\${$var+set}\"; then
+	  relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	elif eval var_value=\$$var; test -z "$var_value"; then
+	  relink_command="$var=; export $var; $relink_command"
+	else
+	  func_quote_for_eval "$var_value"
+	  relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      if test "$hardcode_automatic" = yes ; then
+	relink_command=
+      fi
+
+      # Only create the output if not a dry run.
+      $opt_dry_run || {
+	for installed in no yes; do
+	  if test "$installed" = yes; then
+	    if test -z "$install_libdir"; then
+	      break
+	    fi
+	    output="$output_objdir/$outputname"i
+	    # Replace all uninstalled libtool libraries with the installed ones
+	    newdependency_libs=
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      *.la)
+		func_basename "$deplib"
+		name="$func_basename_result"
+		func_resolve_sysroot "$deplib"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$deplib' is not a valid libtool archive"
+		func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      -L*)
+		func_stripname -L '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -L$func_replace_sysroot_result"
+		;;
+	      -R*)
+		func_stripname -R '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -R$func_replace_sysroot_result"
+		;;
+	      *) func_append newdependency_libs " $deplib" ;;
+	      esac
+	    done
+	    dependency_libs="$newdependency_libs"
+	    newdlfiles=
+
+	    for lib in $dlfiles; do
+	      case $lib in
+	      *.la)
+	        func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      *) func_append newdlfiles " $lib" ;;
+	      esac
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+	      *.la)
+		# Only pass preopened files to the pseudo-archive (for
+		# eventual linking with the app. that links it) if we
+		# didn't already link the preopened objects directly into
+		# the library:
+		func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      esac
+	    done
+	    dlprefiles="$newdlprefiles"
+	  else
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlfiles " $abs"
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlprefiles " $abs"
+	    done
+	    dlprefiles="$newdlprefiles"
+	  fi
+	  $RM $output
+	  # place dlname in correct position for cygwin
+	  # In fact, it would be nice if we could use this code for all target
+	  # systems that can't hard-code library paths into their executables
+	  # and that have no shared library path variable independent of PATH,
+	  # but it turns out we can't easily determine that from inspecting
+	  # libtool variables, so we have to hard-code the OSs to which it
+	  # applies here; at the moment, that means platforms that use the PE
+	  # object format with DLL files.  See the long comment at the top of
+	  # tests/bindir.at for full details.
+	  tdlname=$dlname
+	  case $host,$output,$installed,$module,$dlname in
+	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+	      # If a -bindir argument was supplied, place the dll there.
+	      if test "x$bindir" != x ;
+	      then
+		func_relative_path "$install_libdir" "$bindir"
+		tdlname=$func_relative_path_result$dlname
+	      else
+		# Otherwise fall back on heuristic.
+		tdlname=../bin/$dlname
+	      fi
+	      ;;
+	  esac
+	  $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+	  if test "$installed" = no && test "$need_relink" = yes; then
+	    $ECHO >> $output "\
+relink_command=\"$relink_command\""
+	  fi
+	done
+      }
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+}
+
+{ test "$opt_mode" = link || test "$opt_mode" = relink; } &&
+    func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+    $opt_debug
+    RM="$nonopt"
+    files=
+    rmforce=
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    for arg
+    do
+      case $arg in
+      -f) func_append RM " $arg"; rmforce=yes ;;
+      -*) func_append RM " $arg" ;;
+      *) func_append files " $arg" ;;
+      esac
+    done
+
+    test -z "$RM" && \
+      func_fatal_help "you must specify an RM program"
+
+    rmdirs=
+
+    for file in $files; do
+      func_dirname "$file" "" "."
+      dir="$func_dirname_result"
+      if test "X$dir" = X.; then
+	odir="$objdir"
+      else
+	odir="$dir/$objdir"
+      fi
+      func_basename "$file"
+      name="$func_basename_result"
+      test "$opt_mode" = uninstall && odir="$dir"
+
+      # Remember odir for removal later, being careful to avoid duplicates
+      if test "$opt_mode" = clean; then
+	case " $rmdirs " in
+	  *" $odir "*) ;;
+	  *) func_append rmdirs " $odir" ;;
+	esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if { test -L "$file"; } >/dev/null 2>&1 ||
+	 { test -h "$file"; } >/dev/null 2>&1 ||
+	 test -f "$file"; then
+	:
+      elif test -d "$file"; then
+	exit_status=1
+	continue
+      elif test "$rmforce" = yes; then
+	continue
+      fi
+
+      rmfiles="$file"
+
+      case $name in
+      *.la)
+	# Possibly a libtool archive, so verify it.
+	if func_lalib_p "$file"; then
+	  func_source $dir/$name
+
+	  # Delete the libtool libraries and symlinks.
+	  for n in $library_names; do
+	    func_append rmfiles " $odir/$n"
+	  done
+	  test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+	  case "$opt_mode" in
+	  clean)
+	    case " $library_names " in
+	    *" $dlname "*) ;;
+	    *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+	    esac
+	    test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+	    ;;
+	  uninstall)
+	    if test -n "$library_names"; then
+	      # Do each command in the postuninstall commands.
+	      func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+
+	    if test -n "$old_library"; then
+	      # Do each command in the old_postuninstall commands.
+	      func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+	    # FIXME: should reinstall the best remaining shared library.
+	    ;;
+	  esac
+	fi
+	;;
+
+      *.lo)
+	# Possibly a libtool object, so verify it.
+	if func_lalib_p "$file"; then
+
+	  # Read the .lo file
+	  func_source $dir/$name
+
+	  # Add PIC object to the list of files to remove.
+	  if test -n "$pic_object" &&
+	     test "$pic_object" != none; then
+	    func_append rmfiles " $dir/$pic_object"
+	  fi
+
+	  # Add non-PIC object to the list of files to remove.
+	  if test -n "$non_pic_object" &&
+	     test "$non_pic_object" != none; then
+	    func_append rmfiles " $dir/$non_pic_object"
+	  fi
+	fi
+	;;
+
+      *)
+	if test "$opt_mode" = clean ; then
+	  noexename=$name
+	  case $file in
+	  *.exe)
+	    func_stripname '' '.exe' "$file"
+	    file=$func_stripname_result
+	    func_stripname '' '.exe' "$name"
+	    noexename=$func_stripname_result
+	    # $file with .exe has already been added to rmfiles,
+	    # add $file without .exe
+	    func_append rmfiles " $file"
+	    ;;
+	  esac
+	  # Do a test to see if this is a libtool program.
+	  if func_ltwrapper_p "$file"; then
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      relink_command=
+	      func_source $func_ltwrapper_scriptname_result
+	      func_append rmfiles " $func_ltwrapper_scriptname_result"
+	    else
+	      relink_command=
+	      func_source $dir/$noexename
+	    fi
+
+	    # note $name still contains .exe if it was in $file originally
+	    # as does the version of $file that was added into $rmfiles
+	    func_append rmfiles " $odir/$name $odir/${name}S.${objext}"
+	    if test "$fast_install" = yes && test -n "$relink_command"; then
+	      func_append rmfiles " $odir/lt-$name"
+	    fi
+	    if test "X$noexename" != "X$name" ; then
+	      func_append rmfiles " $odir/lt-${noexename}.c"
+	    fi
+	  fi
+	fi
+	;;
+      esac
+      func_show_eval "$RM $rmfiles" 'exit_status=1'
+    done
+
+    # Try to remove the ${objdir}s in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+	func_show_eval "rmdir $dir >/dev/null 2>&1"
+      fi
+    done
+
+    exit $exit_status
+}
+
+{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } &&
+    func_mode_uninstall ${1+"$@"}
+
+test -z "$opt_mode" && {
+  help="$generic_help"
+  func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+  func_fatal_help "invalid operation mode \`$opt_mode'"
+
+if test -n "$exec_cmd"; then
+  eval exec "$exec_cmd"
+  exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+
diff --git a/final/lib/External/ppcg/m4/ax_check_opencl.m4 b/final/lib/External/ppcg/m4/ax_check_opencl.m4
new file mode 100644
index 0000000..814bbb6
--- /dev/null
+++ b/final/lib/External/ppcg/m4/ax_check_opencl.m4
@@ -0,0 +1,25 @@
+# Check if OpenCL is available and that it supports a CPU device.
+# The check for a CPU device is the same check that is performed
+# by opencl_create_device in ocl_utilities.c
+AC_DEFUN([AX_CHECK_OPENCL], [
+	AC_SUBST(HAVE_OPENCL)
+	HAVE_OPENCL=no
+	AC_CHECK_HEADER([CL/opencl.h], [
+		AC_CHECK_LIB([OpenCL], [clGetPlatformIDs], [
+			SAVE_LIBS=$LIBS
+			LIBS="$LIBS -lOpenCL"
+			AC_MSG_CHECKING([for OpenCL CPU device])
+			AC_RUN_IFELSE([AC_LANG_PROGRAM(
+				[[#include <CL/opencl.h>]], [[
+	cl_platform_id platform;
+	cl_device_id dev;
+
+	if (clGetPlatformIDs(1, &platform, NULL) < 0)
+		return 1;
+	if (clGetDeviceIDs(platform, CL_DEVICE_TYPE_CPU, 1, &dev, NULL) < 0)
+		return 1;
+				]])], [HAVE_OPENCL=yes])
+			AC_MSG_RESULT($HAVE_OPENCL)
+			LIBS=$SAVE_LIBS
+			])])
+])
diff --git a/final/lib/External/ppcg/m4/ax_check_openmp.m4 b/final/lib/External/ppcg/m4/ax_check_openmp.m4
new file mode 100644
index 0000000..509861e
--- /dev/null
+++ b/final/lib/External/ppcg/m4/ax_check_openmp.m4
@@ -0,0 +1,10 @@
+# Check if $CC supports openmp.
+AC_DEFUN([AX_CHECK_OPENMP], [
+	AC_SUBST(HAVE_OPENMP)
+	HAVE_OPENMP=no
+	AC_MSG_CHECKING([for OpenMP support by $CC])
+	echo | $CC -x c - -fsyntax-only -fopenmp -Werror >/dev/null 2>/dev/null
+	if test $? -eq 0; then
+		HAVE_OPENMP=yes
+	fi
+])
diff --git a/final/lib/External/ppcg/m4/ax_detect_git_head.m4 b/final/lib/External/ppcg/m4/ax_detect_git_head.m4
new file mode 100644
index 0000000..5657da8
--- /dev/null
+++ b/final/lib/External/ppcg/m4/ax_detect_git_head.m4
@@ -0,0 +1,27 @@
+AC_DEFUN([AX_DETECT_GIT_HEAD], [
+	AC_SUBST(GIT_HEAD_ID)
+	AC_SUBST(GIT_HEAD)
+	AC_SUBST(GIT_HEAD_VERSION)
+	if test -f $srcdir/.git/HEAD; then
+		GIT_HEAD="$srcdir/.git/index"
+		GIT_REPO="$srcdir/.git"
+		GIT_HEAD_ID=`GIT_DIR=$GIT_REPO git describe --always`
+	elif test -f $srcdir/GIT_HEAD_ID; then
+		GIT_HEAD_ID=`cat $srcdir/GIT_HEAD_ID`
+	else
+		mysrcdir=`(cd $srcdir; pwd)`
+		head=`basename $mysrcdir | sed -e 's/.*-//'`
+		head2=`echo $head | sed -e 's/[^0-9a-f]//'`
+		head3=`echo $head2 | sed -e 's/........................................//'`
+		if test "x$head3" = "x" -a "x$head" = "x$head2"; then
+			GIT_HEAD_ID="$head"
+		else
+			GIT_HEAD_ID="UNKNOWN"
+		fi
+	fi
+	if test -z "$GIT_REPO" ; then
+		GIT_HEAD_VERSION="$GIT_HEAD_ID"
+	else
+		GIT_HEAD_VERSION="\`GIT_DIR=$GIT_REPO git describe --always\`"
+	fi
+])
diff --git a/final/lib/External/ppcg/m4/ax_submodule.m4 b/final/lib/External/ppcg/m4/ax_submodule.m4
new file mode 100644
index 0000000..8129312
--- /dev/null
+++ b/final/lib/External/ppcg/m4/ax_submodule.m4
@@ -0,0 +1,83 @@
+AC_DEFUN([_AX_SUBMODULE],
+[
+
+m4_if(m4_bregexp($3,|,choice),choice,
+	[AC_ARG_WITH($2,
+		[AS_HELP_STRING([--with-$1=$3],
+				[Which $1 to use [default=$4]])])])
+case "system" in
+$3)
+	AC_ARG_WITH($2_prefix,
+		    [AS_HELP_STRING([--with-$1-prefix=DIR],
+				    [Prefix of $1 installation])])
+	AC_ARG_WITH($2_exec_prefix,
+		    [AS_HELP_STRING([--with-$1-exec-prefix=DIR],
+				    [Exec prefix of $1 installation])])
+esac
+m4_if(m4_bregexp($3,build,build),build,
+	[AC_ARG_WITH($2_builddir,
+		[AS_HELP_STRING([--with-$1-builddir=DIR],
+				[Location of $1 builddir])])])
+if test "x$with_$2_prefix" != "x" -a "x$with_$2_exec_prefix" = "x"; then
+	with_$2_exec_prefix=$with_$2_prefix
+fi
+if test "x$with_$2_prefix" != "x" -o "x$with_$2_exec_prefix" != "x"; then
+	if test "x$with_$2" != "x" -a "x$with_$2" != "xsystem"; then
+		AC_MSG_ERROR([Setting $with_$2_prefix implies use of system $1])
+	fi
+	with_$2="system"
+fi
+if test "x$with_$2_builddir" != "x"; then
+	if test "x$with_$2" != "x" -a "x$with_$2" != "xbuild"; then
+		AC_MSG_ERROR([Setting $with_$2_builddir implies use of build $1])
+	fi
+	with_$2="build"
+	$2_srcdir=`echo @abs_srcdir@ | $with_$2_builddir/config.status --file=-`
+	AC_MSG_NOTICE($1 sources in $$2_srcdir)
+fi
+if test "x$with_$2_exec_prefix" != "x"; then
+	export PKG_CONFIG_PATH="$with_$2_exec_prefix/lib/pkgconfig${PKG_CONFIG_PATH+:$PKG_CONFIG_PATH}"
+fi
+case "$with_$2" in
+$3)
+	;;
+*)
+	case "$4" in
+	bundled)
+		if test -d $srcdir/.git -a \
+			-d $srcdir/$1 -a \
+			"`cd $srcdir; git submodule status $1 | cut -c1`" = '-'; then
+			AC_MSG_WARN([git repo detected, but submodule $1 not initialized])
+			AC_MSG_WARN([You may want to run])
+			AC_MSG_WARN([	git submodule init])
+			AC_MSG_WARN([	git submodule update])
+			AC_MSG_WARN([	sh autogen.sh])
+		fi
+		if test -f $srcdir/$1/configure; then
+			with_$2="bundled"
+		else
+			case "system" in
+			$3)
+				with_$2="system"
+				;;
+			*)
+				with_$2="no"
+				;;
+			esac
+		fi
+		;;
+	*)
+		with_$2="$4"
+		;;
+	esac
+	;;
+esac
+AC_MSG_CHECKING([which $1 to use])
+AC_MSG_RESULT($with_$2)
+
+])
+
+AC_DEFUN([AX_SUBMODULE], [
+	_AX_SUBMODULE($1, m4_bpatsubst([$1],
+			[[^_abcdefghijklmnopqrstuvwxyz0123456789]],[_]), $2, $3)
+])
diff --git a/final/lib/External/ppcg/m4/libtool.m4 b/final/lib/External/ppcg/m4/libtool.m4
new file mode 100644
index 0000000..02b4bbe
--- /dev/null
+++ b/final/lib/External/ppcg/m4/libtool.m4
@@ -0,0 +1,7991 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 57 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+       [m4_default([$3],
+		   [m4_fatal([Libtool version $1 or higher is required],
+		             63)])],
+       [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+  *\ * | *\	*)
+    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+  case $cc_temp in
+    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    _LT_PATH_MAGIC
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME.  Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+	[m4_ifval([$1], [$1], [$2])])
+    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+    m4_ifval([$4],
+	[lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+    lt_dict_add_subkey([lt_decl_dict], [$2],
+	[tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+  [0], [m4_fatal([$0: too few arguments: $#])],
+  [1], [m4_fatal([$0: too few arguments: $#: $1])],
+  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+     m4_if([$2], [],
+	   m4_quote(lt_decl_varnames),
+	m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+			lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'.  VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly.  In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+#    <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+#    # Some comment about what VAR is for.
+#    visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+					   [description])))[]dnl
+m4_pushdef([_libtool_name],
+    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+    [0], [_libtool_name=[$]$1],
+    [1], [_libtool_name=$lt_[]$1],
+    [2], [_libtool_name=$lt_[]$1],
+    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'.  Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+	dnl If the libtool generation code has been placed in $CONFIG_LT,
+	dnl instead of duplicating it all over again into config.status,
+	dnl then we will have config.status run $CONFIG_LT later, so it
+	dnl needs to know what name is stored there:
+        [AC_CONFIG_COMMANDS([libtool],
+            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+    dnl If the libtool generation code is destined for config.status,
+    dnl expand the accumulated commands and init code now:
+    [AC_CONFIG_COMMANDS([libtool],
+        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable.  If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins.  After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script.  The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+  echo
+  AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+  -h, --help      print this help, then exit
+  -V, --version   print version number, then exit
+  -q, --quiet     do not print progress messages
+  -d, --debug     don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+  case $[1] in
+    --version | --v* | -V )
+      echo "$lt_cl_version"; exit 0 ;;
+    --help | --h* | -h )
+      echo "$lt_cl_help"; exit 0 ;;
+    --debug | --d* | -d )
+      debug=: ;;
+    --quiet | --q* | --silent | --s* | -q )
+      lt_cl_silent=: ;;
+
+    -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+    *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+  esac
+  shift
+done
+
+if $lt_cl_silent; then
+  exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure.  Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test "$silent" = yes &&
+  lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars.  Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+  m4_if(_LT_TAG, [C], [
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+  _LT_PROG_LTMAIN
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+  _LT_PROG_REPLACE_SHELLFNS
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+  [C],			[_LT_LANG(C)],
+  [C++],		[_LT_LANG(CXX)],
+  [Go],			[_LT_LANG(GO)],
+  [Java],		[_LT_LANG(GCJ)],
+  [Fortran 77],		[_LT_LANG(F77)],
+  [Fortran],		[_LT_LANG(FC)],
+  [Windows Resource],	[_LT_LANG(RC)],
+  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+    [_LT_LANG($1)],
+    [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+  [LT_SUPPORTED_TAG([$1])dnl
+  m4_append([_LT_TAGS], [$1 ])dnl
+  m4_define([_LT_LANG_]$1[_enabled], [])dnl
+  _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_GO.  When it is available in    #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC],     [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+  fi
+fi
+if test -z "$GOC"; then
+  AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+  [LT_LANG(CXX)],
+  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+  [LT_LANG(F77)],
+  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+  [LT_LANG(FC)],
+  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+  [LT_LANG(GCJ)],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+    [LT_LANG(GCJ)],
+    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+      [LT_LANG(GCJ)],
+      [m4_ifdef([AC_PROG_GCJ],
+	[m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([A][M_PROG_GCJ],
+	[m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([LT_PROG_GCJ],
+	[m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+  [LT_LANG(GO)],
+  [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+  [LT_LANG(RC)],
+  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+  case $host_os in
+    rhapsody* | darwin*)
+    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+    AC_CHECK_TOOL([LIPO], [lipo], [:])
+    AC_CHECK_TOOL([OTOOL], [otool], [:])
+    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+    _LT_DECL([], [DSYMUTIL], [1],
+      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+    _LT_DECL([], [NMEDIT], [1],
+      [Tool to change global to local symbols on Mac OS X])
+    _LT_DECL([], [LIPO], [1],
+      [Tool to manipulate fat objects and archives on Mac OS X])
+    _LT_DECL([], [OTOOL], [1],
+      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+    _LT_DECL([], [OTOOL64], [1],
+      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+      [lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	# If there is a non-empty error log, and "single_module"
+	# appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	# Otherwise, if the output was created with a 0 exit code from
+	# the compiler, it worked.
+	elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi])
+
+    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+      [lt_cv_ld_exported_symbols_list],
+      [lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+	[lt_cv_ld_exported_symbols_list=yes],
+	[lt_cv_ld_exported_symbols_list=no])
+	LDFLAGS="$save_LDFLAGS"
+    ])
+
+    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+      [lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+      $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+    ])
+    case $host_os in
+    rhapsody* | darwin1.[[012]])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	10.[[012]]*)
+	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_automatic, $1)=yes
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+    m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+                  [FC],  [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+  else
+    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  fi
+  _LT_TAGVAR(link_all_deplibs, $1)=yes
+  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+    m4_if([$1], [CXX],
+[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+    fi
+],[])
+  else
+  _LT_TAGVAR(ld_shlibs, $1)=no
+  fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+  lt_aix_libpath_sed='[
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }]'
+  _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi],[])
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
+  fi
+  ])
+  aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*" 
+}
+
+case "$ECHO" in
+  printf*) AC_MSG_RESULT([printf]) ;;
+  print*) AC_MSG_RESULT([print -r]) ;;
+  *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test "X`printf %s $ECHO`" = "X$ECHO" \
+      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[  --with-sysroot[=DIR] Search for dependent libraries within DIR
+                        (or the compiler's sysroot if not specified).],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted.  We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+   if test "$GCC" = yes; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   AC_MSG_RESULT([${with_sysroot}])
+   AC_MSG_ERROR([The sysroot must be an absolute path.])
+   ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and in which our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+  [AS_HELP_STRING([--disable-libtool-lock],
+    [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE="32"
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE="64"
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    case `/usr/bin/file conftest.o` in
+	      *x86-64*)
+		LD="${LD-ld} -m elf32_x86_64"
+		;;
+	      *)
+		LD="${LD-ld} -m elf_i386"
+		;;
+	    esac
+	    ;;
+	  ppc64-*linux*|powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  ppc*-*linux*|powerpc*-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD="${LD-ld}_sol2"
+        fi
+        ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+  [lt_cv_ar_at_file=no
+   AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+     [echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([lt_ar_try])
+      if test "$ac_status" -eq 0; then
+	# Ensure the archiver fails upon bogus file names.
+	rm -f conftest.$ac_objext libconftest.a
+	AC_TRY_EVAL([lt_ar_try])
+	if test "$ac_status" -ne 0; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+     ])
+  ])
+
+if test "x$lt_cv_ar_at_file" = xno; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+  [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+    [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+    [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+    [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$5], , :, [$5])
+else
+    m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                  [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$4], , :, [$4])
+else
+    m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[	 ]]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len" && \
+	test undefined != "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+    [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}]
+_LT_EOF
+  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_dlunknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+    ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+	  [lt_cv_dlopen="shl_load"],
+      [AC_CHECK_LIB([dld], [shl_load],
+	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+	[AC_CHECK_FUNC([dlopen],
+	      [lt_cv_dlopen="dlopen"],
+	  [AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+	    [AC_CHECK_LIB([svld], [dlopen],
+		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+	      [AC_CHECK_LIB([dld], [dld_link],
+		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+	      ])
+	    ])
+	  ])
+	])
+      ])
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+	  lt_cv_dlopen_self, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+	  lt_cv_dlopen_self_static, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+	 [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+	 [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+	 [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+	[Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+         [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+  [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+    [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      AC_MSG_RESULT([yes])
+    else
+      AC_MSG_RESULT([no])
+    fi
+    ;;
+  *)
+    AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+	[], [
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[[4-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+m4_if([$1], [],[
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[[23]].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[[3-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+    [lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+	 LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+	 [lt_cv_shlibpath_overrides_runpath=yes])])
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+    ])
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsdelf*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='NetBSD ld.elf_so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+    [Variables whose values should be saved in libtool wrapper scripts and
+    restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+    [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+    [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+    [[List of archive names.  First name is the real one, the rest are links.
+    The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+    [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+    [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+    [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+    [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+    [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+    [[As "finish_cmds", except a single script fragment to be evaled but
+    not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+    [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+    [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+    [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="m4_if([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+	 [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+    [AS_HELP_STRING([--with-gnu-ld],
+	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test "$GCC" != yes; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[[3-9]]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd* | netbsdelf*-gnu)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+    [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+    [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+    [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+    [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+  AC_SUBST([DUMPBIN])
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+  [lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+  cat conftest.out >&AS_MESSAGE_LOG_FD
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+    [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+  [lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*])
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+  MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+  esac
+
+  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+	[Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris*)
+  symcode='[[BDRT]]'
+  ;;
+sco3.2v5*)
+  symcode='[[DT]]'
+  ;;
+sysv4.2uw2*)
+  symcode='[[DT]]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[[ABDT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK ['"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx]"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[	 ]]\($symcode$symcode*\)[[	 ]][[	 ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT@&t@_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT@&t@_DLSYM_CONST
+#else
+# define LT@&t@_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT@&t@_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_globsym_save_LIBS=$LIBS
+	  lt_globsym_save_CFLAGS=$CFLAGS
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS=$lt_globsym_save_LIBS
+	  CFLAGS=$lt_globsym_save_CFLAGS
+	else
+	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+    [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+    [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+    [lt_cv_sys_global_symbol_to_c_name_address], [1],
+    [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+    [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([], [nm_file_list_spec], [1],
+    [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[[4-9]]*)
+	# All AIX code is PIC.
+	if test "$host_cpu" = ia64; then
+	  # AIX 5 now supports IA64 processor
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	else
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      mingw* | cygwin* | os2* | pw32* | cegcc*)
+	# This hack is so that the source file can tell whether it is being
+	# built for inclusion in a dll (and should export symbols for example).
+	m4_if([$1], [GCJ], [],
+	  [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    if test "$host_cpu" != ia64; then
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    ;;
+	  ecpc* )
+	    # old Intel C++ for x86_64 which still supported -KPIC.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  icpc* )
+	    # Intel C++, used to be incompatible with GCC.
+	    # ICC 10 doesn't accept -KPIC any more.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+	    # IBM XL 8.0, 9.0 on PPC and BlueGene
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd* | netbsdelf*-gnu)
+	;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+	;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+      if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  ;;
+        *Intel*\ [[CF]]*Compiler*)
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	  ;;
+	*Portland\ Group*)
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    rdos*)
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    unicos*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+	[Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+	[How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+  $lt_tmp_static_flag,
+  [],
+  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+	[Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  case $host_os in
+  aix[[4-9]]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    # Also, AIX nm treats weak defined symbols like other global defined
+    # symbols, whereas GNU nm marks them as "W".
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+    ;;
+  cygwin* | mingw* | cegcc*)
+    case $cc_basename in
+    cl*)
+      _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+      ;;
+    *)
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+      ;;
+    esac
+    ;;
+  linux* | k*bsd*-gnu | gnu*)
+    _LT_TAGVAR(link_all_deplibs, $1)=no
+    ;;
+  *)
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+    ;;
+  esac
+], [
+  runpath_var=
+  _LT_TAGVAR(allow_undefined_flag, $1)=
+  _LT_TAGVAR(always_export_symbols, $1)=no
+  _LT_TAGVAR(archive_cmds, $1)=
+  _LT_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_TAGVAR(compiler_needs_object, $1)=no
+  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(hardcode_automatic, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_TAGVAR(inherit_rpath, $1)=no
+  _LT_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_TAGVAR(module_cmds, $1)=
+  _LT_TAGVAR(module_expsym_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  linux* | k*bsd*-gnu | gnu*)
+    _LT_TAGVAR(link_all_deplibs, $1)=no
+    ;;
+  esac
+
+  _LT_TAGVAR(ld_shlibs, $1)=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+	  *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[[3-9]]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=no
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    haiku*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    interix[[3-9]]*)
+      _LT_TAGVAR(hardcode_direct, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+	  tmp_sharedflag='--shared' ;;
+	xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+      runpath_var=
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	_LT_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix[[4-9]]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	# Also, AIX nm treats weak defined symbols like other global
+	# defined symbols, whereas GNU nm marks them as "W".
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_TAGVAR(archive_cmds, $1)=''
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[[012]]|aix4.[[012]].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+	_LT_TAGVAR(link_all_deplibs, $1)=no
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        _LT_SYS_MODULE_PATH_AIX([$1])
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	  _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 _LT_SYS_MODULE_PATH_AIX([$1])
+	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	  if test "$with_gnu_ld" = yes; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	  fi
+	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[[45]]*)
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	_LT_TAGVAR(always_export_symbols, $1)=yes
+	_LT_TAGVAR(file_list_spec, $1)='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	    sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	  else
+	    sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	  fi~
+	  $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	  linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	_LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+	_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+	  lt_tool_outputfile="@TOOL_OUTPUT@"~
+	  case $lt_outputfile in
+	    *.exe|*.EXE) ;;
+	    *)
+	      lt_outputfile="$lt_outputfile.exe"
+	      lt_tool_outputfile="$lt_tool_outputfile.exe"
+	      ;;
+	  esac~
+	  if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	    $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	    $RM "$lt_outputfile.manifest";
+	  fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	_LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	# FIXME: Should let the user specify the lib program.
+	_LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+      _LT_DARWIN_LINKER_FEATURES($1)
+      ;;
+
+    dgux*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	_LT_TAGVAR(hardcode_minus_L, $1)=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	m4_if($1, [], [
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  _LT_LINKER_OPTION([if $CC understands -b],
+	    _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+	    [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+	    [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+	  [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  ;;
+	*)
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+	  [lt_cv_irix_exported_symbol],
+	  [save_LDFLAGS="$LDFLAGS"
+	   LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+	   AC_LINK_IFELSE(
+	     [AC_LANG_SOURCE(
+	        [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+			      [C++], [[int foo (void) { return 0; }]],
+			      [Fortran 77], [[
+      subroutine foo
+      end]],
+			      [Fortran], [[
+      subroutine foo
+      end]])])],
+	      [lt_cv_irix_exported_symbol=yes],
+	      [lt_cv_irix_exported_symbol=no])
+           LDFLAGS="$save_LDFLAGS"])
+	if test "$lt_cv_irix_exported_symbol" = yes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+	fi
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(inherit_rpath, $1)=yes
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+	     _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	     ;;
+	   *)
+	     _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+        ;;
+	motorola)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	_LT_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+    [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+	[lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+	[$RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+	  pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+	  _LT_TAGVAR(allow_undefined_flag, $1)=
+	  if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+	  then
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	  else
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  fi
+	  _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+	])
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+    [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+    [enable_shared_with_static_runtimes], [0],
+    [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+    [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+    [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+    [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+    [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+    [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+    [Commands used to build a loadable module if different from building
+    a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+    [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+    [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+    [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+    [Flag to hardcode $libdir into a binary during linking.
+    This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+    [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary and the resulting library dependency is
+    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+    library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+    [Set to "yes" if building a shared library automatically hardcodes DIR
+    into the library and all subsequent libraries and executables linked
+    against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+    [Set to yes if linker adds runtime paths of dependent libraries
+    to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+    [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+    [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+    [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+    [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+    [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+    [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+    [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+    [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl    [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_SYS_DYNAMIC_LINKER($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+  LT_SYS_DLOPEN_SELF
+  _LT_CMD_STRIPLIB
+
+  # Report which library types will actually be built
+  AC_MSG_CHECKING([if libtool supports shared libraries])
+  AC_MSG_RESULT([$can_build_shared])
+
+  AC_MSG_CHECKING([whether to build shared libraries])
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[[4-9]]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  AC_MSG_RESULT([$enable_shared])
+
+  AC_MSG_CHECKING([whether to build static libraries])
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  AC_MSG_RESULT([$enable_static])
+
+  _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+else
+  _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_CFLAGS=$CFLAGS
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  CFLAGS=$CXXFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test "$GXX" = yes; then
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+    else
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+    fi
+
+    if test "$GXX" = yes; then
+      # Set up default GNU C++ configuration
+
+      LT_PATH_LD
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test "$with_gnu_ld" = yes; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='${wl}'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+	  $GREP 'no-whole-archive' > /dev/null; then
+          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+        else
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+    _LT_TAGVAR(ld_shlibs, $1)=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+      aix[[4-9]]*)
+        if test "$host_cpu" = ia64; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=""
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # need to do runtime linking.
+          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	    for ld_flag in $LDFLAGS; do
+	      case $ld_flag in
+	      *-brtl*)
+	        aix_use_runtimelinking=yes
+	        break
+	        ;;
+	      esac
+	    done
+	    ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        _LT_TAGVAR(archive_cmds, $1)=''
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+        if test "$GXX" = yes; then
+          case $host_os in aix4.[[012]]|aix4.[[012]].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	    # We have reworked collect2
+	    :
+	  else
+	    # We have old collect2
+	    _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	    # It fails to find uninstalled libraries when the uninstalled
+	    # path is not listed in the libpath.  Setting hardcode_minus_L
+	    # to unsupported forces relinking
+	    _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+          esac
+          shared_flag='-shared'
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag="$shared_flag "'${wl}-G'
+	  fi
+        else
+          # not using gcc
+          if test "$host_cpu" = ia64; then
+	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	  # chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+          else
+	    if test "$aix_use_runtimelinking" = yes; then
+	      shared_flag='${wl}-G'
+	    else
+	      shared_flag='${wl}-bM:SRE'
+	    fi
+          fi
+        fi
+
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+	# export.
+        _LT_TAGVAR(always_export_symbols, $1)=yes
+        if test "$aix_use_runtimelinking" = yes; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          _LT_SYS_MODULE_PATH_AIX([$1])
+          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        else
+          if test "$host_cpu" = ia64; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	    _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+          else
+	    # Determine the default libpath from the value encoded in an
+	    # empty executable.
+	    _LT_SYS_MODULE_PATH_AIX([$1])
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	    # Warning - without using the other run time loading flags,
+	    # -berok will link without error, but may produce a broken library.
+	    _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	    _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	    if test "$with_gnu_ld" = yes; then
+	      # We only use this code for GNU lds that support --whole-archive.
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    else
+	      # Exported symbols can be pulled into shared objects from archives
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	    fi
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	    # This is similar to how AIX traditionally builds its shared
+	    # libraries.
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+          fi
+        fi
+        ;;
+
+      beos*)
+	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	  # support --undefined.  This deserves some investigation.  FIXME
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+	  # FIXME: insert proper C++ library support
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	  ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+	case $GXX,$cc_basename in
+	,cl* | no,cl*)
+	  # Native MSVC
+	  # hardcode_libdir_flag_spec is actually meaningless, as there is
+	  # no search path for DLLs.
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  _LT_TAGVAR(always_export_symbols, $1)=yes
+	  _LT_TAGVAR(file_list_spec, $1)='@'
+	  # Tell ltmain to make .lib files, not .a files.
+	  libext=lib
+	  # Tell ltmain to make .dll files, not .so files.
+	  shrext_cmds=".dll"
+	  # FIXME: Setting linknames here is a bad hack.
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	      $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	    else
+	      $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	    fi~
+	    $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	    linknames='
+	  # The linker will not automatically build a static lib if we build a DLL.
+	  # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	  # Don't use ranlib
+	  _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+	  _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+	    lt_tool_outputfile="@TOOL_OUTPUT@"~
+	    case $lt_outputfile in
+	      *.exe|*.EXE) ;;
+	      *)
+		lt_outputfile="$lt_outputfile.exe"
+		lt_tool_outputfile="$lt_tool_outputfile.exe"
+		;;
+	    esac~
+	    func_to_tool_file "$lt_outputfile"~
+	    if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	      $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	      $RM "$lt_outputfile.manifest";
+	    fi'
+	  ;;
+	*)
+	  # g++
+	  # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+	  # as there is no search path for DLLs.
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  _LT_TAGVAR(always_export_symbols, $1)=no
+	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+	  if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    # If the export-symbols file already is a .def file (1st line
+	    # is EXPORTS), use it as is; otherwise, prepend...
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	      cp $export_symbols $output_objdir/$soname.def;
+	    else
+	      echo EXPORTS > $output_objdir/$soname.def;
+	      cat $export_symbols >> $output_objdir/$soname.def;
+	    fi~
+	    $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	  ;;
+	esac
+	;;
+      darwin* | rhapsody*)
+        _LT_DARWIN_LINKER_FEATURES($1)
+	;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          ghcx*)
+	    # Green Hills C++ Compiler
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      freebsd2.*)
+        # C++ shared libraries reported to be fairly broken before
+	# switch to ELF
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      freebsd-elf*)
+        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+        ;;
+
+      haiku*)
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        ;;
+
+      hpux9*)
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+				             # but as the default
+				             # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            _LT_TAGVAR(ld_shlibs, $1)=no
+            ;;
+          aCC*)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            ;;
+          *)
+            if test "$GXX" = yes; then
+              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              _LT_TAGVAR(ld_shlibs, $1)=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test $with_gnu_ld = no; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            _LT_TAGVAR(hardcode_direct, $1)=no
+            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+            ;;
+          *)
+            _LT_TAGVAR(hardcode_direct, $1)=yes
+            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+					         # but as the default
+					         # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          aCC*)
+	    case $host_cpu in
+	      hppa*64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      ia64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      *)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	    esac
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test $with_gnu_ld = no; then
+	        case $host_cpu in
+	          hppa*64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          ia64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          *)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	        esac
+	      fi
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      interix[[3-9]]*)
+	_LT_TAGVAR(hardcode_direct, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+	# Instead, shared libraries are loaded at an image base (0x10000000 by
+	# default) and relocated if they conflict, which is a slow very memory
+	# consuming and fragmenting process.  To avoid this, we pick a random,
+	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+	    # SGI C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test "$with_gnu_ld" = no; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	      else
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+	      fi
+	    fi
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+	    ;;
+        esac
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(inherit_rpath, $1)=yes
+        ;;
+
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+	    ;;
+	  icpc* | ecpc* )
+	    # Intel C++
+	    with_gnu_ld=yes
+	    # version 8.0 and above of icpc choke on multiply defined symbols
+	    # if we add $predep_objects and $postdep_objects, however 7.1 and
+	    # earlier do not add the objects themselves.
+	    case `$CC -V 2>&1` in
+	      *"Version 7."*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	      *)  # Version 8.0 or newer
+	        tmp_idyn=
+	        case $host_cpu in
+		  ia64*) tmp_idyn=' -i_dynamic';;
+		esac
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	    esac
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+	    case `$CC -V` in
+	    *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+	      _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+		compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+	      _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+		$RANLIB $oldlib'
+	      _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    *) # Version 6 and above use weak symbols
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+            ;;
+	  cxx*)
+	    # Compaq C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+	    runpath_var=LD_RUN_PATH
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+	    ;;
+	  xl* | mpixl* | bgxl*)
+	    # IBM XL 8.0 on PPC, with GNU ld
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    if test "x$supports_anon_versioning" = xyes; then
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+		echo "local: *; };" >> $output_objdir/$libname.ver~
+		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+	    fi
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	      _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+	      # Not sure whether something based on
+	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	      # would be better.
+	      output_verbose_link_cmd='func_echo_all'
+
+	      # Archives containing C++ object files must be created using
+	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	      # necessary to make sure instantiated templates are included
+	      # in the archive.
+	      _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	  *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	esac
+	;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+	  wlarc=
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	fi
+	# Workaround some broken pre-1.5 toolchains
+	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+	;;
+
+      *nto* | *qnx*)
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+	;;
+
+      openbsd2*)
+        # C++ shared libraries are fairly broken
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      openbsd*)
+	if test -f /usr/libexec/ld.so; then
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+	  fi
+	  output_verbose_link_cmd=func_echo_all
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Archives containing C++ object files must be created using
+	    # the KAI C++ compiler.
+	    case $host in
+	      osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+	      *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+	    esac
+	    ;;
+          RCC*)
+	    # Rational C++ 2.4.1
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          cxx*)
+	    case $host in
+	      osf3*)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+		;;
+	      *)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+	          echo "-hidden">> $lib.exp~
+	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+	          $RM $lib.exp'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+		;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+	  *)
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	      case $host in
+	        osf3*)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	        *)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	      esac
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	      # Commands to make compiler produce verbose output that lists
+	      # what "hidden" libraries, object files and flags are used when
+	      # linking a shared library.
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.x
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          lcc*)
+	    # Lucid
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+	    _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	    _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	    case $host_os in
+	      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+	      *)
+		# The compiler driver will combine and reorder linker options,
+		# but understands `-z linker_flag'.
+	        # Supported since Solaris 2.6 (maybe 2.5.1?)
+		_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	        ;;
+	    esac
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+	    output_verbose_link_cmd='func_echo_all'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	    ;;
+          gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+	    # The C++ compiler must be used to create the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    # GNU C++ compiler with Solaris linker
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      else
+	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	        # platform.
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      fi
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+	      case $host_os in
+		solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+		*)
+		  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+		  ;;
+	      esac
+	    fi
+	    ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+	# Note: We can NOT use -z defs as we might desire, because we do not
+	# link with -lc, and that would cause any symbols used from libc to
+	# always be unresolved, which means just about no library would
+	# ever link correctly.  If we're not using GNU ld we use -z text
+	# though, which does catch some bad symbols but isn't as heavy-handed
+	# as -z defs.
+	_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+	_LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+	_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+	_LT_TAGVAR(link_all_deplibs, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+	runpath_var='LD_RUN_PATH'
+
+	case $cc_basename in
+          CC*)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+	      '"$_LT_TAGVAR(old_archive_cmds, $1)"
+	    _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+	      '"$_LT_TAGVAR(reload_cmds, $1)"
+	    ;;
+	  *)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+	    # NonStop-UX NCC 3.20
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+    esac
+
+    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+    _LT_TAGVAR(GCC, $1)="$GXX"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+  case ${2} in
+  .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+  *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+  esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case ${prev}${p} in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" ||
+          test $p = "-R"; then
+	 prev=$p
+	 continue
+       fi
+
+       # Expand the sysroot to ease extracting the directories later.
+       if test -z "$prev"; then
+         case $p in
+         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+         esac
+       fi
+       case $p in
+       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+       esac
+       if test "$pre_test_object_deps_done" = no; then
+	 case ${prev} in
+	 -L | -R)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+	   else
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+	   _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+	 else
+	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+	 fi
+       fi
+       prev=
+       ;;
+
+    *.lto.$objext) ;; # Ignore GCC LTO objects
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+	   _LT_TAGVAR(predep_objects, $1)="$p"
+	 else
+	   _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+	 fi
+       else
+	 if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+	   _LT_TAGVAR(postdep_objects, $1)="$p"
+	 else
+	   _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  _LT_TAGVAR(predep_objects,$1)=
+  _LT_TAGVAR(postdep_objects,$1)=
+  _LT_TAGVAR(postdeps,$1)=
+  ;;
+
+linux*)
+  case `$CC -V 2>&1 | sed 5q` in
+  *Sun\ C*)
+    # Sun C++ 5.9
+
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+
+solaris*)
+  case $cc_basename in
+  CC* | sunCC*)
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+    [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+    [Dependencies to place before and after the objects being linked to
+    create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+    [The library search path used internally by the compiler when linking
+    a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+  _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${F77-"f77"}
+  CFLAGS=$FFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+  GCC=$G77
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$G77"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC="$lt_save_CC"
+  CFLAGS="$lt_save_CFLAGS"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+  _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${FC-"f95"}
+  CFLAGS=$FCFLAGS
+  compiler=$CC
+  GCC=$ac_cv_fc_compiler_gnu
+
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+  :
+  _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+    [AC_CHECK_TOOL(GCJ, gcj,)
+      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+      AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,b/c, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
+# ------------------------------------------------------
+# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
+# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
+m4_defun([_LT_PROG_FUNCTION_REPLACE],
+[dnl {
+sed -e '/^$1 ()$/,/^} # $1 /c\
+$1 ()\
+{\
+m4_bpatsubsts([$2], [$], [\\], [^\([	 ]\)], [\\\1])
+} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+])
+
+
+# _LT_PROG_REPLACE_SHELLFNS
+# -------------------------
+# Replace existing portable implementations of several shell functions with
+# equivalent extended shell implementations where those features are available..
+m4_defun([_LT_PROG_REPLACE_SHELLFNS],
+[if test x"$xsi_shell" = xyes; then
+  _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
+    case ${1} in
+      */*) func_dirname_result="${1%/*}${2}" ;;
+      *  ) func_dirname_result="${3}" ;;
+    esac])
+
+  _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
+    func_basename_result="${1##*/}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
+    case ${1} in
+      */*) func_dirname_result="${1%/*}${2}" ;;
+      *  ) func_dirname_result="${3}" ;;
+    esac
+    func_basename_result="${1##*/}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
+    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+    # positional parameters, so assign one to ordinary parameter first.
+    func_stripname_result=${3}
+    func_stripname_result=${func_stripname_result#"${1}"}
+    func_stripname_result=${func_stripname_result%"${2}"}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
+    func_split_long_opt_name=${1%%=*}
+    func_split_long_opt_arg=${1#*=}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
+    func_split_short_opt_arg=${1#??}
+    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
+    case ${1} in
+      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+      *)    func_lo2o_result=${1} ;;
+    esac])
+
+  _LT_PROG_FUNCTION_REPLACE([func_xform], [    func_xform_result=${1%.*}.lo])
+
+  _LT_PROG_FUNCTION_REPLACE([func_arith], [    func_arith_result=$(( $[*] ))])
+
+  _LT_PROG_FUNCTION_REPLACE([func_len], [    func_len_result=${#1}])
+fi
+
+if test x"$lt_shell_append" = xyes; then
+  _LT_PROG_FUNCTION_REPLACE([func_append], [    eval "${1}+=\\${2}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
+    func_quote_for_eval "${2}"
+dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
+    eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
+
+  # Save a `func_append' function call where possible by direct use of '+='
+  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+else
+  # Save a `func_append' function call even when '+=' is not available
+  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+  AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
+fi
+])
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine which file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path).  These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+         [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+         [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
diff --git a/final/lib/External/ppcg/m4/ltoptions.m4 b/final/lib/External/ppcg/m4/ltoptions.m4
new file mode 100644
index 0000000..5d9acd8
--- /dev/null
+++ b/final/lib/External/ppcg/m4/ltoptions.m4
@@ -0,0 +1,384 @@
+# Helper functions for option handling.                    -*- Autoconf -*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+#   Inc.
+#   Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 7 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+        _LT_MANGLE_DEFUN([$1], [$2]),
+    [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+	    [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+		      [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME.  If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+    [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+  dnl
+  dnl Simply set some default values (i.e off) if boolean options were not
+  dnl specified:
+  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+  ])
+  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+  ])
+  dnl
+  dnl If no reference was made to various pairs of opposing options, then
+  dnl we run the default mode handler for the pair.  For example, if neither
+  dnl `shared' nor `disable-shared' was passed, we enable building of shared
+  dnl archives by default:
+  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+  		   [_LT_ENABLE_FAST_INSTALL])
+  ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS],      [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+	[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+    _LT_DECL([build_libtool_libs], [enable_shared], [0],
+	[Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+	[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+    _LT_DECL([build_old_libs], [enable_static], [0],
+	[Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+	 [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+    [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for lt_pkg in $withval; do
+	IFS="$lt_save_ifs"
+	if test "X$lt_pkg" = "X$lt_p"; then
+	  pic_mode=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+		 [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+		 [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+		 [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+		 [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+		 [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/final/lib/External/ppcg/m4/ltsugar.m4 b/final/lib/External/ppcg/m4/ltsugar.m4
new file mode 100644
index 0000000..9000a05
--- /dev/null
+++ b/final/lib/External/ppcg/m4/ltsugar.m4
@@ -0,0 +1,123 @@
+# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+       [$#], [2], [[$2]],
+       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+       [$#], 1, [],
+       [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+	   m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+	     [m4_foreach([_Lt_suffix],
+		]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+	[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+	  [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+		 [lt_append([$1], [$2], [$3])$4],
+		 [$5])],
+	  [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+	m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+	[$5],
+    [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+  [lt_join(m4_quote(m4_default([$4], [[, ]])),
+           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+		      [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/final/lib/External/ppcg/m4/ltversion.m4 b/final/lib/External/ppcg/m4/ltversion.m4
new file mode 100644
index 0000000..07a8602
--- /dev/null
+++ b/final/lib/External/ppcg/m4/ltversion.m4
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers			-*- Autoconf -*-
+#
+#   Copyright (C) 2004 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 3337 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.2])
+m4_define([LT_PACKAGE_REVISION], [1.3337])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.2'
+macro_revision='1.3337'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/final/lib/External/ppcg/m4/lt~obsolete.m4 b/final/lib/External/ppcg/m4/lt~obsolete.m4
new file mode 100644
index 0000000..c573da9
--- /dev/null
+++ b/final/lib/External/ppcg/m4/lt~obsolete.m4
@@ -0,0 +1,98 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else.  This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION],	[AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP],		[AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT],		[AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],	[AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN],		[AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR],		[AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL],	[AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN],		[AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER],	[AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK],		[AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],	[AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],	[AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],	[AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR],		[AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR],		[AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],	[AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC],		[AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU],		[AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG],	[AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD],	[AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS],	[AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP],	[AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP],		[AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED],		[AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME],		[AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE],	[AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE],	[AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL],		[AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP],		[AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN],		[AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],	[AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG],		[AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL],	[AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX],		[AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77],		[AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ],		[AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG],	[AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG],	[AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG],	[AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],	[AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG],	[AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG],		[AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C],	[AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],	[AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP],		[AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],	[AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77],		[AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC],		[AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX],		[AC_DEFUN([_LT_PROG_CXX])])
diff --git a/final/lib/External/ppcg/missing b/final/lib/External/ppcg/missing
new file mode 100644
index 0000000..86a8fc3
--- /dev/null
+++ b/final/lib/External/ppcg/missing
@@ -0,0 +1,331 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2012-01-06.13; # UTC
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
+# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+run=:
+sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
+sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+  configure_ac=configure.ac
+else
+  configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case $1 in
+--run)
+  # Try to run requested program, and just exit if it succeeds.
+  run=
+  shift
+  "$@" && exit 0
+  # Exit code 63 means version mismatch.  This often happens
+  # when the user try to use an ancient version of a tool on
+  # a file that requires a minimum version.  In this case we
+  # we should proceed has if the program had been absent, or
+  # if --run hadn't been passed.
+  if test $? = 63; then
+    run=:
+    msg="probably too old"
+  fi
+  ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+  --run           try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  autom4te     touch the output file, or create a stub one
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  help2man     touch the output file
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
+\`g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+    exit $?
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit $?
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# normalize program name to check for.
+program=`echo "$1" | sed '
+  s/^gnu-//; t
+  s/^gnu//; t
+  s/^g//; t'`
+
+# Now exit if we have it, but it failed.  Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).  This is about non-GNU programs, so use $1 not
+# $program.
+case $1 in
+  lex*|yacc*)
+    # Not GNU programs, they don't have --version.
+    ;;
+
+  *)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+       # Could not run --version or --help.  This is probably someone
+       # running `$TOOL --version' or `$TOOL --help' to check whether
+       # $TOOL exists and not knowing $TOOL uses missing.
+       exit 1
+    fi
+    ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case $program in
+  aclocal*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acinclude.m4' or \`${configure_ac}'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`${configure_ac}'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acconfig.h' or \`${configure_ac}'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case $f in
+      *:*) touch_files="$touch_files "`echo "$f" |
+				       sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+	   sed 's/\.am$/.in/' |
+	   while read f; do touch "$f"; done
+    ;;
+
+  autom4te*)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.
+         You can get \`$1' as part of \`Autoconf' from any GNU
+         archive site."
+
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -f "$file"; then
+	touch $file
+    else
+	test -z "$file" || exec >$file
+	echo "#! /bin/sh"
+	echo "# Created by GNU Automake missing as a replacement of"
+	echo "#  $ $@"
+	echo "exit 0"
+	chmod +x $file
+	exit 1
+    fi
+    ;;
+
+  bison*|yacc*)
+    echo 1>&2 "\
+WARNING: \`$1' $msg.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if test $# -ne 1; then
+        eval LASTARG=\${$#}
+	case $LASTARG in
+	*.y)
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+	    if test -f "$SRCFILE"; then
+	         cp "$SRCFILE" y.tab.c
+	    fi
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+	    if test -f "$SRCFILE"; then
+	         cp "$SRCFILE" y.tab.h
+	    fi
+	  ;;
+	esac
+    fi
+    if test ! -f y.tab.h; then
+	echo >y.tab.h
+    fi
+    if test ! -f y.tab.c; then
+	echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex*|flex*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if test $# -ne 1; then
+        eval LASTARG=\${$#}
+	case $LASTARG in
+	*.l)
+	    SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+	    if test -f "$SRCFILE"; then
+	         cp "$SRCFILE" lex.yy.c
+	    fi
+	  ;;
+	esac
+    fi
+    if test ! -f lex.yy.c; then
+	echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  help2man*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+	 you modified a dependency of a manual page.  You may need the
+	 \`Help2man' package in order for those modifications to take
+	 effect.  You can get \`Help2man' from any GNU archive site."
+
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -f "$file"; then
+	touch $file
+    else
+	test -z "$file" || exec >$file
+	echo ".ab help2man is required to generate this page"
+	exit $?
+    fi
+    ;;
+
+  makeinfo*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    # The file to touch is that specified with -o ...
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -z "$file"; then
+      # ... or it is the one specified with @setfilename ...
+      infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '
+	/^@setfilename/{
+	  s/.* \([^ ]*\) *$/\1/
+	  p
+	  q
+	}' $infile`
+      # ... or it is derived from the source name (dir/f.texi becomes f.info)
+      test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+    fi
+    # If the file does not exist, the user really needs makeinfo;
+    # let's fail without touching anything.
+    test -f $file || exit 1
+    touch $file
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequisites for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/final/lib/External/ppcg/ocl_utilities.c b/final/lib/External/ppcg/ocl_utilities.c
new file mode 100644
index 0000000..c7a2156
--- /dev/null
+++ b/final/lib/External/ppcg/ocl_utilities.c
@@ -0,0 +1,174 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "ocl_utilities.h"
+
+/* Return the OpenCL error string for a given error number.
+ */
+const char *opencl_error_string(cl_int error)
+{
+	int errorCount;
+	int index;
+
+	static const char *errorString[] = {
+		[CL_SUCCESS] = "CL_SUCCESS",
+		[-CL_DEVICE_NOT_FOUND] = "CL_DEVICE_NOT_FOUND",
+		[-CL_DEVICE_NOT_AVAILABLE] = "CL_DEVICE_NOT_AVAILABLE",
+		[-CL_COMPILER_NOT_AVAILABLE] = "CL_COMPILER_NOT_AVAILABLE",
+		[-CL_MEM_OBJECT_ALLOCATION_FAILURE] =
+			"CL_MEM_OBJECT_ALLOCATION_FAILURE",
+		[-CL_OUT_OF_RESOURCES] = "CL_OUT_OF_RESOURCES",
+		[-CL_OUT_OF_HOST_MEMORY] = "CL_OUT_OF_HOST_MEMORY",
+		[-CL_PROFILING_INFO_NOT_AVAILABLE] =
+			"CL_PROFILING_INFO_NOT_AVAILABLE",
+		[-CL_MEM_COPY_OVERLAP] = "CL_MEM_COPY_OVERLAP",
+		[-CL_IMAGE_FORMAT_MISMATCH] = "CL_IMAGE_FORMAT_MISMATCH",
+		[-CL_IMAGE_FORMAT_NOT_SUPPORTED] =
+			"CL_IMAGE_FORMAT_NOT_SUPPORTED",
+		[-CL_BUILD_PROGRAM_FAILURE] = "CL_BUILD_PROGRAM_FAILURE",
+		[-CL_MAP_FAILURE] = "CL_MAP_FAILURE",
+		[-CL_INVALID_VALUE] = "CL_INVALID_VALUE",
+		[-CL_INVALID_DEVICE_TYPE] = "CL_INVALID_DEVICE_TYPE",
+		[-CL_INVALID_PLATFORM] = "CL_INVALID_PLATFORM",
+		[-CL_INVALID_DEVICE] = "CL_INVALID_DEVICE",
+		[-CL_INVALID_CONTEXT] = "CL_INVALID_CONTEXT",
+		[-CL_INVALID_QUEUE_PROPERTIES] = "CL_INVALID_QUEUE_PROPERTIES",
+		[-CL_INVALID_COMMAND_QUEUE] = "CL_INVALID_COMMAND_QUEUE",
+		[-CL_INVALID_HOST_PTR] = "CL_INVALID_HOST_PTR",
+		[-CL_INVALID_MEM_OBJECT] = "CL_INVALID_MEM_OBJECT",
+		[-CL_INVALID_IMAGE_FORMAT_DESCRIPTOR] =
+			"CL_INVALID_IMAGE_FORMAT_DESCRIPTOR",
+		[-CL_INVALID_IMAGE_SIZE] = "CL_INVALID_IMAGE_SIZE",
+		[-CL_INVALID_SAMPLER] = "CL_INVALID_SAMPLER",
+		[-CL_INVALID_BINARY] = "CL_INVALID_BINARY",
+		[-CL_INVALID_BUILD_OPTIONS] = "CL_INVALID_BUILD_OPTIONS",
+		[-CL_INVALID_PROGRAM] = "CL_INVALID_PROGRAM",
+		[-CL_INVALID_PROGRAM_EXECUTABLE] =
+			"CL_INVALID_PROGRAM_EXECUTABLE",
+		[-CL_INVALID_KERNEL_NAME] = "CL_INVALID_KERNEL_NAME",
+		[-CL_INVALID_KERNEL_DEFINITION] =
+			"CL_INVALID_KERNEL_DEFINITION",
+		[-CL_INVALID_KERNEL] = "CL_INVALID_KERNEL",
+		[-CL_INVALID_ARG_INDEX] = "CL_INVALID_ARG_INDEX",
+		[-CL_INVALID_ARG_VALUE] = "CL_INVALID_ARG_VALUE",
+		[-CL_INVALID_ARG_SIZE] = "CL_INVALID_ARG_SIZE",
+		[-CL_INVALID_KERNEL_ARGS] = "CL_INVALID_KERNEL_ARGS",
+		[-CL_INVALID_WORK_DIMENSION] = "CL_INVALID_WORK_DIMENSION",
+		[-CL_INVALID_WORK_GROUP_SIZE] = "CL_INVALID_WORK_GROUP_SIZE",
+		[-CL_INVALID_WORK_ITEM_SIZE] = "CL_INVALID_WORK_ITEM_SIZE",
+		[-CL_INVALID_GLOBAL_OFFSET] = "CL_INVALID_GLOBAL_OFFSET",
+		[-CL_INVALID_EVENT_WAIT_LIST] = "CL_INVALID_EVENT_WAIT_LIST",
+		[-CL_INVALID_EVENT] = "CL_INVALID_EVENT",
+		[-CL_INVALID_OPERATION] = "CL_INVALID_OPERATION",
+		[-CL_INVALID_GL_OBJECT] = "CL_INVALID_GL_OBJECT",
+		[-CL_INVALID_BUFFER_SIZE] = "CL_INVALID_BUFFER_SIZE",
+		[-CL_INVALID_MIP_LEVEL] = "CL_INVALID_MIP_LEVEL",
+		[-CL_INVALID_GLOBAL_WORK_SIZE] = "CL_INVALID_GLOBAL_WORK_SIZE",
+		[-CL_INVALID_PROPERTY] = "CL_INVALID_PROPERTY"
+	};
+
+	errorCount = sizeof(errorString) / sizeof(errorString[0]);
+	index = -error;
+
+	return (index >= 0 && index < errorCount) ?
+		errorString[index] : "Unspecified Error";
+}
+
+/* Find a GPU or a CPU associated with the first available platform.
+ * If use_gpu is set, then this function first tries to look for a GPU
+ * in the first available platform.
+ * If this fails or if use_gpu is not set, then it tries to use the CPU.
+ */
+cl_device_id opencl_create_device(int use_gpu)
+{
+	cl_platform_id platform;
+	cl_device_id dev;
+	int err;
+
+	err = clGetPlatformIDs(1, &platform, NULL);
+	if (err < 0) {
+		fprintf(stderr, "Error %s while looking for a platform.\n",
+				opencl_error_string(err));
+		exit(1);
+	}
+
+	err = CL_DEVICE_NOT_FOUND;
+	if (use_gpu)
+		err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &dev,
+				NULL);
+	if (err == CL_DEVICE_NOT_FOUND)
+		err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_CPU, 1, &dev,
+				NULL);
+	if (err < 0) {
+		fprintf(stderr, "Error %s while looking for a device.\n",
+				opencl_error_string(err));
+		exit(1);
+	}
+	return dev;
+}
+
+/* Create an OpenCL program from a string and compile it.
+ */
+cl_program opencl_build_program_from_string(cl_context ctx, cl_device_id dev,
+	const char *program_source, size_t program_size,
+	const char *opencl_options)
+{
+	int err;
+	cl_program program;
+	char *program_log;
+	size_t log_size;
+
+	program = clCreateProgramWithSource(ctx, 1,
+			&program_source, &program_size, &err);
+	if (err < 0) {
+		fprintf(stderr, "Could not create the program\n");
+		exit(1);
+	}
+	err = clBuildProgram(program, 0, NULL, opencl_options, NULL, NULL);
+	if (err < 0) {
+		fprintf(stderr, "Could not build the program.\n");
+		clGetProgramBuildInfo(program, dev, CL_PROGRAM_BUILD_LOG, 0,
+				NULL, &log_size);
+		program_log = (char *) malloc(log_size + 1);
+		program_log[log_size] = '\0';
+		clGetProgramBuildInfo(program, dev, CL_PROGRAM_BUILD_LOG,
+				log_size + 1, program_log, NULL);
+		fprintf(stderr, "%s\n", program_log);
+		free(program_log);
+		exit(1);
+	}
+	return program;
+}
+
+/* Create an OpenCL program from a source file and compile it.
+ */
+cl_program opencl_build_program_from_file(cl_context ctx, cl_device_id dev,
+	const char* filename, const char* opencl_options)
+{
+	cl_program program;
+	FILE *program_file;
+	char *program_source;
+	size_t program_size, read;
+
+	program_file = fopen(filename, "r");
+	if (program_file == NULL) {
+		fprintf(stderr, "Could not find the source file.\n");
+		exit(1);
+	}
+	fseek(program_file, 0, SEEK_END);
+	program_size = ftell(program_file);
+	rewind(program_file);
+	program_source = (char *) malloc(program_size + 1);
+	program_source[program_size] = '\0';
+	read = fread(program_source, sizeof(char), program_size, program_file);
+	if (read != program_size) {
+		fprintf(stderr, "Error while reading the kernel.\n");
+		exit(1);
+	}
+	fclose(program_file);
+
+	program = opencl_build_program_from_string(ctx, dev, program_source,
+						program_size, opencl_options);
+	free(program_source);
+
+	return program;
+}
diff --git a/final/lib/External/ppcg/ocl_utilities.h b/final/lib/External/ppcg/ocl_utilities.h
new file mode 100644
index 0000000..34a987e
--- /dev/null
+++ b/final/lib/External/ppcg/ocl_utilities.h
@@ -0,0 +1,32 @@
+#ifndef OCL_UTILITIES_H
+#define OCL_UTILITIES_H
+
+#if defined(__APPLE__)
+#include <OpenCL/opencl.h>
+#else
+#include <CL/opencl.h>
+#endif
+
+/* Return the OpenCL error string for a given error number.
+ */
+const char *opencl_error_string(cl_int error);
+
+/* Find a GPU or a CPU associated with the first available platform.
+ * If use_gpu is set, then this function first tries to look for a GPU
+ * in the first available platform.
+ * If this fails or if use_gpu is not set, then it tries to use the CPU.
+ */
+cl_device_id opencl_create_device(int use_gpu);
+
+/* Create an OpenCL program from a string and compile it.
+ */
+cl_program opencl_build_program_from_string(cl_context ctx, cl_device_id dev,
+	const char *program_source, size_t program_size,
+	const char *opencl_options);
+
+/* Create an OpenCL program from a source file and compile it.
+ */
+cl_program opencl_build_program_from_file(cl_context ctx, cl_device_id dev,
+	const char* filename, const char* opencl_options);
+
+#endif
diff --git a/final/lib/External/ppcg/opencl.h b/final/lib/External/ppcg/opencl.h
new file mode 100644
index 0000000..bf10f95
--- /dev/null
+++ b/final/lib/External/ppcg/opencl.h
@@ -0,0 +1,11 @@
+#ifndef _OPENCL_H
+#define _OPENCL_H
+
+#include <pet.h>
+#include "ppcg_options.h"
+#include "ppcg.h"
+
+int generate_opencl(isl_ctx *ctx, struct ppcg_options *options,
+	const char *input, const char *output);
+
+#endif
diff --git a/final/lib/External/ppcg/opencl_test.sh.in b/final/lib/External/ppcg/opencl_test.sh.in
new file mode 100644
index 0000000..b974d00
--- /dev/null
+++ b/final/lib/External/ppcg/opencl_test.sh.in
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+keep=no
+
+for option; do
+	case "$option" in
+		--keep)
+			keep=yes
+			;;
+	esac
+done
+
+EXEEXT=@EXEEXT@
+VERSION=@GIT_HEAD_VERSION@
+CC="@CC@"
+CFLAGS="--std=gnu99"
+srcdir="@srcdir@"
+
+if [ $keep = "yes" ]; then
+	OUTDIR="opencl_test.$VERSION"
+	mkdir "$OUTDIR" || exit 1
+else
+	if test "x$TMPDIR" = "x"; then
+		TMPDIR=/tmp
+	fi
+	OUTDIR=`mktemp -d $TMPDIR/ppcg.XXXXXXXXXX` || exit 1
+fi
+
+run_tests () {
+	subdir=$1
+	ppcg_options=$2
+
+	echo Test with PPCG options \'$ppcg_options\'
+	mkdir ${OUTDIR}/${subdir} || exit 1
+	for i in $srcdir/tests/*.c; do
+		echo $i
+		name=`basename $i`
+		name="${name%.c}"
+		out_c="${OUTDIR}/${subdir}/$name.ppcg.c"
+		out="${OUTDIR}/${subdir}/$name.ppcg$EXEEXT"
+		options="--target=opencl --opencl-no-use-gpu $ppcg_options"
+		functions="$srcdir/tests/${name}_opencl_functions.cl"
+		if test -f $functions; then
+			options="$options --opencl-include-file=$functions"
+			options="$options --opencl-compiler-options=-I."
+		fi
+		./ppcg$EXEEXT $options $i -o "$out_c" || exit
+		$CC $CFLAGS -I "$srcdir" "$srcdir/ocl_utilities.c" -lOpenCL \
+			-I. "$out_c" -o "$out" || exit
+		$out || exit
+	done
+}
+
+run_tests default
+run_tests embed --opencl-embed-kernel-code
+
+for i in $srcdir/examples/*.c; do
+	echo $i
+	name=`basename $i`
+	name="${name%.c}"
+	exe_ref="${OUTDIR}/$name.ref$EXEEXT"
+	gen_ocl="${OUTDIR}/$name.ppcg.c"
+	exe_ocl="${OUTDIR}/$name.ppcg$EXEEXT"
+	output_ref="${OUTDIR}/$name.ref.out"
+	output_ocl="${OUTDIR}/$name.ppcg.out"
+	$CC $CFLAGS $i -o $exe_ref || exit
+	./ppcg$EXEEXT --target=opencl --opencl-no-use-gpu $i -o "$gen_ocl" || \
+		exit
+	$CC $CFLAGS -I "$srcdir" "$srcdir/ocl_utilities.c" -lOpenCL \
+		"$gen_ocl" -o "$exe_ocl" || exit
+	$exe_ref > $output_ref || exit
+	$exe_ocl > $output_ocl || exit
+	cmp $output_ref $output_ocl || exit
+done
+
+if [ $keep = "no" ]; then
+	rm -r "${OUTDIR}"
+fi
diff --git a/final/lib/External/ppcg/polybench_test.sh.in b/final/lib/External/ppcg/polybench_test.sh.in
new file mode 100644
index 0000000..4d54cb9
--- /dev/null
+++ b/final/lib/External/ppcg/polybench_test.sh.in
@@ -0,0 +1,109 @@
+#!/bin/sh
+
+keep=no
+verbose=no
+
+for option; do
+	case "$option" in
+		--keep)
+			keep=yes
+			;;
+		--verbose)
+			verbose=yes
+			;;
+	esac
+done
+
+EXEEXT=@EXEEXT@
+DIR=@POLYBENCH_DIR@
+VERSION=@GIT_HEAD_VERSION@
+SIZE=-DMINI_DATASET
+CC="@CC@"
+HAVE_OPENCL=@HAVE_OPENCL@
+HAVE_OPENMP=@HAVE_OPENMP@
+srcdir="@srcdir@"
+if [ $keep = "yes" ]; then
+	OUTDIR="out.$VERSION"
+	mkdir "$OUTDIR" || exit 1
+else
+	if test "x$TMPDIR" = "x"; then
+		TMPDIR=/tmp
+	fi
+	OUTDIR=`mktemp -d $TMPDIR/ppcg.XXXXXXXXXX` || exit 1
+fi
+CPPFLAGS="-DPOLYBENCH_USE_C99_PROTO -DPOLYBENCH_DUMP_ARRAYS"
+CPPFLAGS="$CPPFLAGS $SIZE -I $DIR/utilities"
+CFLAGS="-lm --std=gnu99"
+
+echo "Running tests in folder ${OUTDIR}"
+
+run_tests () {
+	ext=$1
+
+	ppcg_options=$2
+	cc_options=$3
+
+	if [ "x$ppcg_options" = "x" ]; then
+		ppcg_option_str="none"
+	else
+		ppcg_option_str=$ppcg_options
+	fi
+
+	if [ "x$cc_options" = "x" ]; then
+		cc_option_str="none"
+	else
+		cc_option_str=$cc_options
+	fi
+
+	echo Test: $ext, ppcg options: $ppcg_option_str, CC options: $cc_option_str
+	for i in `cat $DIR/utilities/benchmark_list`; do
+		echo $i
+		name=`basename $i`
+		name=${name%.c}
+		source_opt="${OUTDIR}/$name.$ext.c"
+		prog_orig=${OUTDIR}/$name.orig${EXEEXT}
+		prog_opt=${OUTDIR}/$name.$ext${EXEEXT}
+		output_orig=${OUTDIR}/$name.orig.out
+		output_opt=${OUTDIR}/$name.$ext.out
+		dir=`dirname $i`
+		if [ $verbose = "yes" ]; then
+			echo ./ppcg$EXEEXT -I $DIR/$dir $DIR/$i \
+				$CPPFLAGS -o $source_opt $ppcg_options
+		fi
+		./ppcg$EXEEXT -I $DIR/$dir $DIR/$i $CPPFLAGS \
+			-o $source_opt $ppcg_options || exit
+		$CC -I $DIR/$dir $CPPFLAGS $DIR/$i -o $prog_orig \
+			$DIR/utilities/polybench.c $CFLAGS
+		$prog_orig 2> $output_orig
+		if [ $verbose = "yes" ]; then
+			echo $CC -I $DIR/$dir $CPPFLAGS $source_opt \
+				-o $prog_opt $DIR/utilities/polybench.c \
+				$CFLAGS $cc_options
+		fi
+		$CC -I $DIR/$dir $CPPFLAGS $source_opt -o $prog_opt \
+			$DIR/utilities/polybench.c $CFLAGS $cc_options || exit
+
+		$prog_opt 2> $output_opt
+		cmp $output_orig $output_opt || exit
+	done
+}
+
+run_tests ppcg "--target=c --tile"
+run_tests ppcg_live "--target=c --no-live-range-reordering --tile"
+
+# Test OpenMP code, if compiler supports openmp
+if [ $HAVE_OPENMP = "yes" ]; then
+	run_tests ppcg_omp "--target=c --openmp" -fopenmp
+	echo Introduced `grep -R 'omp parallel' "${OUTDIR}" | wc -l` '"pragma omp parallel for"'
+else
+	echo Compiler does not support OpenMP. Skipping OpenMP tests.
+fi
+
+if [ $HAVE_OPENCL = "yes" ]; then
+	run_tests ppcg_opencl "--target=opencl --opencl-no-use-gpu" \
+				"-I $srcdir $srcdir/ocl_utilities.c -lOpenCL"
+fi
+
+if [ $keep = "no" ]; then
+	rm -r "${OUTDIR}"
+fi
diff --git a/final/lib/External/ppcg/ppcg.c b/final/lib/External/ppcg/ppcg.c
new file mode 100644
index 0000000..ed5acec
--- /dev/null
+++ b/final/lib/External/ppcg/ppcg.c
@@ -0,0 +1,1067 @@
+/*
+ * Copyright 2011      INRIA Saclay
+ * Copyright 2013      Ecole Normale Superieure
+ * Copyright 2015      Sven Verdoolaege
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <isl/ctx.h>
+#include <isl/id.h>
+#include <isl/val.h>
+#include <isl/set.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl/aff.h>
+#include <isl/flow.h>
+#include <isl/options.h>
+#include <isl/schedule.h>
+#include <isl/ast.h>
+#include <isl/id_to_ast_expr.h>
+#include <isl/ast_build.h>
+#include <isl/schedule.h>
+#include <pet.h>
+#include "ppcg.h"
+#include "ppcg_options.h"
+#include "cuda.h"
+#include "opencl.h"
+#include "cpu.h"
+
+struct options {
+	struct pet_options *pet;
+	struct ppcg_options *ppcg;
+	char *input;
+	char *output;
+};
+
+const char *ppcg_version(void);
+static void print_version(void)
+{
+	printf("%s", ppcg_version());
+}
+
+ISL_ARGS_START(struct options, options_args)
+ISL_ARG_CHILD(struct options, pet, "pet", &pet_options_args, "pet options")
+ISL_ARG_CHILD(struct options, ppcg, NULL, &ppcg_options_args, "ppcg options")
+ISL_ARG_STR(struct options, output, 'o', NULL,
+	"filename", NULL, "output filename (c and opencl targets)")
+ISL_ARG_ARG(struct options, input, "input", NULL)
+ISL_ARG_VERSION(print_version)
+ISL_ARGS_END
+
+ISL_ARG_DEF(options, struct options, options_args)
+
+/* Return a pointer to the final path component of "filename" or
+ * to "filename" itself if it does not contain any components.
+ */
+const char *ppcg_base_name(const char *filename)
+{
+	const char *base;
+
+	base = strrchr(filename, '/');
+	if (base)
+		return ++base;
+	else
+		return filename;
+}
+
+/* Copy the base name of "input" to "name" and return its length.
+ * "name" is not NULL terminated.
+ *
+ * In particular, remove all leading directory components and
+ * the final extension, if any.
+ */
+int ppcg_extract_base_name(char *name, const char *input)
+{
+	const char *base;
+	const char *ext;
+	int len;
+
+	base = ppcg_base_name(input);
+	ext = strrchr(base, '.');
+	len = ext ? ext - base : strlen(base);
+
+	memcpy(name, base, len);
+
+	return len;
+}
+
+/* Does "scop" refer to any arrays that are declared, but not
+ * exposed to the code after the scop?
+ */
+int ppcg_scop_any_hidden_declarations(struct ppcg_scop *scop)
+{
+	int i;
+
+	if (!scop)
+		return 0;
+
+    // This is a pet feature not available in Polly.
+    return 0;
+
+	for (i = 0; i < scop->pet->n_array; ++i)
+		if (scop->pet->arrays[i]->declared &&
+		    !scop->pet->arrays[i]->exposed)
+			return 1;
+
+	return 0;
+}
+
+/* Collect all variable names that are in use in "scop".
+ * In particular, collect all parameters in the context and
+ * all the array names.
+ * Store these names in an isl_id_to_ast_expr by mapping
+ * them to a dummy value (0).
+ */
+static __isl_give isl_id_to_ast_expr *collect_names(struct pet_scop *scop)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_ast_expr *zero;
+	isl_id_to_ast_expr *names;
+
+	ctx = isl_set_get_ctx(scop->context);
+
+	n = isl_set_dim(scop->context, isl_dim_param);
+
+	names = isl_id_to_ast_expr_alloc(ctx, n + scop->n_array);
+	zero = isl_ast_expr_from_val(isl_val_zero(ctx));
+
+	for (i = 0; i < n; ++i) {
+		isl_id *id;
+
+		id = isl_set_get_dim_id(scop->context, isl_dim_param, i);
+		names = isl_id_to_ast_expr_set(names,
+						id, isl_ast_expr_copy(zero));
+	}
+
+	for (i = 0; i < scop->n_array; ++i) {
+		struct pet_array *array = scop->arrays[i];
+		isl_id *id;
+
+		id = isl_set_get_tuple_id(array->extent);
+		names = isl_id_to_ast_expr_set(names,
+						id, isl_ast_expr_copy(zero));
+	}
+
+	isl_ast_expr_free(zero);
+
+	return names;
+}
+
+/* Return an isl_id called "prefix%d", with "%d" set to "i".
+ * If an isl_id with such a name already appears among the variable names
+ * of "scop", then adjust the name to "prefix%d_%d".
+ */
+static __isl_give isl_id *generate_name(struct ppcg_scop *scop,
+	const char *prefix, int i)
+{
+	int j;
+	char name[16];
+	isl_ctx *ctx;
+	isl_id *id;
+	int has_name;
+
+	ctx = isl_set_get_ctx(scop->context);
+	snprintf(name, sizeof(name), "%s%d", prefix, i);
+	id = isl_id_alloc(ctx, name, NULL);
+
+	j = 0;
+	while ((has_name = isl_id_to_ast_expr_has(scop->names, id)) == 1) {
+		isl_id_free(id);
+		snprintf(name, sizeof(name), "%s%d_%d", prefix, i, j++);
+		id = isl_id_alloc(ctx, name, NULL);
+	}
+
+	return has_name < 0 ? isl_id_free(id) : id;
+}
+
+/* Return a list of "n" isl_ids of the form "prefix%d".
+ * If an isl_id with such a name already appears among the variable names
+ * of "scop", then adjust the name to "prefix%d_%d".
+ */
+__isl_give isl_id_list *ppcg_scop_generate_names(struct ppcg_scop *scop,
+	int n, const char *prefix)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_id_list *names;
+
+	ctx = isl_set_get_ctx(scop->context);
+	names = isl_id_list_alloc(ctx, n);
+	for (i = 0; i < n; ++i) {
+		isl_id *id;
+
+		id = generate_name(scop, prefix, i);
+		names = isl_id_list_add(names, id);
+	}
+
+	return names;
+}
+
+/* Is "stmt" not a kill statement?
+ */
+static int is_not_kill(struct pet_stmt *stmt)
+{
+	return !pet_stmt_is_kill(stmt);
+}
+
+/* Collect the iteration domains of the statements in "scop" that
+ * satisfy "pred".
+ */
+static __isl_give isl_union_set *collect_domains(struct pet_scop *scop,
+	int (*pred)(struct pet_stmt *stmt))
+{
+	int i;
+	isl_set *domain_i;
+	isl_union_set *domain;
+
+	if (!scop)
+		return NULL;
+
+	domain = isl_union_set_empty(isl_set_get_space(scop->context));
+
+	for (i = 0; i < scop->n_stmt; ++i) {
+		struct pet_stmt *stmt = scop->stmts[i];
+
+		if (!pred(stmt))
+			continue;
+
+		if (stmt->n_arg > 0)
+			isl_die(isl_union_set_get_ctx(domain),
+				isl_error_unsupported,
+				"data dependent conditions not supported",
+				return isl_union_set_free(domain));
+
+		domain_i = isl_set_copy(scop->stmts[i]->domain);
+		domain = isl_union_set_add_set(domain, domain_i);
+	}
+
+	return domain;
+}
+
+/* Collect the iteration domains of the statements in "scop",
+ * skipping kill statements.
+ */
+static __isl_give isl_union_set *collect_non_kill_domains(struct pet_scop *scop)
+{
+	return collect_domains(scop, &is_not_kill);
+}
+
+/* This function is used as a callback to pet_expr_foreach_call_expr
+ * to detect if there is any call expression in the input expression.
+ * Assign the value 1 to the integer that "user" points to and
+ * abort the search since we have found what we were looking for.
+ */
+static int set_has_call(__isl_keep pet_expr *expr, void *user)
+{
+	int *has_call = user;
+
+	*has_call = 1;
+
+	return -1;
+}
+
+/* Does "expr" contain any call expressions?
+ */
+static int expr_has_call(__isl_keep pet_expr *expr)
+{
+	int has_call = 0;
+
+	if (pet_expr_foreach_call_expr(expr, &set_has_call, &has_call) < 0 &&
+	    !has_call)
+		return -1;
+
+	return has_call;
+}
+
+/* This function is a callback for pet_tree_foreach_expr.
+ * If "expr" contains any call (sub)expressions, then set *has_call
+ * and abort the search.
+ */
+static int check_call(__isl_keep pet_expr *expr, void *user)
+{
+	int *has_call = user;
+
+	if (expr_has_call(expr))
+		*has_call = 1;
+
+	return *has_call ? -1 : 0;
+}
+
+/* Does "stmt" contain any call expressions?
+ */
+static int has_call(struct pet_stmt *stmt)
+{
+	int has_call = 0;
+
+	if (pet_tree_foreach_expr(stmt->body, &check_call, &has_call) < 0 &&
+	    !has_call)
+		return -1;
+
+	return has_call;
+}
+
+/* Collect the iteration domains of the statements in "scop"
+ * that contain a call expression.
+ */
+static __isl_give isl_union_set *collect_call_domains(struct pet_scop *scop)
+{
+	return collect_domains(scop, &has_call);
+}
+
+/* Given a union of "tagged" access relations of the form
+ *
+ *	[S_i[...] -> R_j[]] -> A_k[...]
+ *
+ * project out the "tags" (R_j[]).
+ * That is, return a union of relations of the form
+ *
+ *	S_i[...] -> A_k[...]
+ */
+static __isl_give isl_union_map *project_out_tags(
+	__isl_take isl_union_map *umap)
+{
+	return isl_union_map_domain_factor_domain(umap);
+}
+
+/* Construct a function from tagged iteration domains to the corresponding
+ * untagged iteration domains with as range of the wrapped map in the domain
+ * the reference tags that appear in any of the reads, writes or kills.
+ * Store the result in ps->tagger.
+ *
+ * For example, if the statement with iteration space S[i,j]
+ * contains two array references R_1[] and R_2[], then ps->tagger will contain
+ *
+ *	{ [S[i,j] -> R_1[]] -> S[i,j]; [S[i,j] -> R_2[]] -> S[i,j] }
+ */
+void compute_tagger(struct ppcg_scop *ps)
+{
+	isl_union_map *tagged;
+	isl_union_pw_multi_aff *tagger;
+
+	tagged = isl_union_map_copy(ps->tagged_reads);
+	tagged = isl_union_map_union(tagged,
+				isl_union_map_copy(ps->tagged_may_writes));
+	tagged = isl_union_map_union(tagged,
+				isl_union_map_copy(ps->tagged_must_kills));
+	tagged = isl_union_map_universe(tagged);
+	tagged = isl_union_set_unwrap(isl_union_map_domain(tagged));
+
+	tagger = isl_union_map_domain_map_union_pw_multi_aff(tagged);
+
+	ps->tagger = tagger;
+}
+
+/* Compute the live out accesses, i.e., the writes that are
+ * potentially not killed by any kills or any other writes, and
+ * store them in ps->live_out.
+ *
+ * We compute the "dependence" of any "kill" (an explicit kill
+ * or a must write) on any may write.
+ * The elements accessed by the may writes with a "depending" kill
+ * also accessing the element are definitely killed.
+ * The remaining may writes can potentially be live out.
+ *
+ * The result of the dependence analysis is
+ *
+ *	{ IW -> [IK -> A] }
+ *
+ * with IW the instance of the write statement, IK the instance of kill
+ * statement and A the element that was killed.
+ * The range factor range is
+ *
+ *	{ IW -> A }
+ *
+ * containing all such pairs for which there is a kill statement instance,
+ * i.e., all pairs that have been killed.
+ */
+static void compute_live_out(struct ppcg_scop *ps)
+{
+	isl_schedule *schedule;
+	isl_union_map *kills;
+	isl_union_map *exposed;
+	isl_union_map *covering;
+	isl_union_access_info *access;
+	isl_union_flow *flow;
+
+	schedule = isl_schedule_copy(ps->schedule);
+	kills = isl_union_map_union(isl_union_map_copy(ps->must_writes),
+				    isl_union_map_copy(ps->must_kills));
+	access = isl_union_access_info_from_sink(kills);
+	access = isl_union_access_info_set_may_source(access,
+				    isl_union_map_copy(ps->may_writes));
+	access = isl_union_access_info_set_schedule(access, schedule);
+	flow = isl_union_access_info_compute_flow(access);
+	covering = isl_union_flow_get_full_may_dependence(flow);
+	isl_union_flow_free(flow);
+
+	covering = isl_union_map_range_factor_range(covering);
+	exposed = isl_union_map_copy(ps->may_writes);
+	exposed = isl_union_map_subtract(exposed, covering);
+	ps->live_out = exposed;
+}
+
+/* Compute the tagged flow dependences and the live_in accesses and store
+ * the results in ps->tagged_dep_flow and ps->live_in.
+ *
+ * We allow both the must writes and the must kills to serve as
+ * definite sources such that a subsequent read would not depend
+ * on any earlier write.  The resulting flow dependences with
+ * a must kill as source reflect possibly uninitialized reads.
+ * No dependences need to be introduced to protect such reads
+ * (other than those imposed by potential flows from may writes
+ * that follow the kill).  We therefore remove those flow dependences.
+ * This is also useful for the dead code elimination, which assumes
+ * the flow sources are non-kill instances.
+ */
+static void compute_tagged_flow_dep_only(struct ppcg_scop *ps)
+{
+	isl_union_pw_multi_aff *tagger;
+	isl_schedule *schedule;
+	isl_union_map *live_in;
+	isl_union_access_info *access;
+	isl_union_flow *flow;
+	isl_union_map *must_source;
+	isl_union_map *kills;
+	isl_union_map *tagged_flow;
+
+	tagger = isl_union_pw_multi_aff_copy(ps->tagger);
+	schedule = isl_schedule_copy(ps->schedule);
+	schedule = isl_schedule_pullback_union_pw_multi_aff(schedule, tagger);
+	kills = isl_union_map_copy(ps->tagged_must_kills);
+	must_source = isl_union_map_copy(ps->tagged_must_writes);
+	must_source = isl_union_map_union(must_source,
+				isl_union_map_copy(kills));
+	access = isl_union_access_info_from_sink(
+				isl_union_map_copy(ps->tagged_reads));
+	access = isl_union_access_info_set_must_source(access, must_source);
+	access = isl_union_access_info_set_may_source(access,
+				isl_union_map_copy(ps->tagged_may_writes));
+	access = isl_union_access_info_set_schedule(access, schedule);
+	flow = isl_union_access_info_compute_flow(access);
+	tagged_flow = isl_union_flow_get_may_dependence(flow);
+	tagged_flow = isl_union_map_subtract_domain(tagged_flow,
+				isl_union_map_domain(kills));
+	ps->tagged_dep_flow = tagged_flow;
+	live_in = isl_union_flow_get_may_no_source(flow);
+	ps->live_in = project_out_tags(live_in);
+	isl_union_flow_free(flow);
+}
+
+/* Compute ps->dep_flow from ps->tagged_dep_flow
+ * by projecting out the reference tags.
+ */
+static void derive_flow_dep_from_tagged_flow_dep(struct ppcg_scop *ps)
+{
+	ps->dep_flow = isl_union_map_copy(ps->tagged_dep_flow);
+	ps->dep_flow = isl_union_map_factor_domain(ps->dep_flow);
+}
+
+/* Compute the flow dependences and the live_in accesses and store
+ * the results in ps->dep_flow and ps->live_in.
+ * A copy of the flow dependences, tagged with the reference tags
+ * is stored in ps->tagged_dep_flow.
+ *
+ * We first compute ps->tagged_dep_flow, i.e., the tagged flow dependences
+ * and then project out the tags.
+ */
+static void compute_tagged_flow_dep(struct ppcg_scop *ps)
+{
+	compute_tagged_flow_dep_only(ps);
+	derive_flow_dep_from_tagged_flow_dep(ps);
+}
+
+/* Compute the order dependences that prevent the potential live ranges
+ * from overlapping.
+ *
+ * In particular, construct a union of relations
+ *
+ *	[R[...] -> R_1[]] -> [W[...] -> R_2[]]
+ *
+ * where [R[...] -> R_1[]] is the range of one or more live ranges
+ * (i.e., a read) and [W[...] -> R_2[]] is the domain of one or more
+ * live ranges (i.e., a write).  Moreover, the read and the write
+ * access the same memory element and the read occurs before the write
+ * in the original schedule.
+ * The scheduler allows some of these dependences to be violated, provided
+ * the adjacent live ranges are all local (i.e., their domain and range
+ * are mapped to the same point by the current schedule band).
+ *
+ * Note that if a live range is not local, then we need to make
+ * sure it does not overlap with _any_ other live range, and not
+ * just with the "previous" and/or the "next" live range.
+ * We therefore add order dependences between reads and
+ * _any_ later potential write.
+ *
+ * We also need to be careful about writes without a corresponding read.
+ * They are already prevented from moving past non-local preceding
+ * intervals, but we also need to prevent them from moving past non-local
+ * following intervals.  We therefore also add order dependences from
+ * potential writes that do not appear in any intervals
+ * to all later potential writes.
+ * Note that dead code elimination should have removed most of these
+ * dead writes, but the dead code elimination may not remove all dead writes,
+ * so we need to consider them to be safe.
+ *
+ * The order dependences are computed by computing the "dataflow"
+ * from the above unmatched writes and the reads to the may writes.
+ * The unmatched writes and the reads are treated as may sources
+ * such that they would not kill order dependences from earlier
+ * such writes and reads.
+ */
+static void compute_order_dependences(struct ppcg_scop *ps)
+{
+	isl_union_map *reads;
+	isl_union_map *shared_access;
+	isl_union_set *matched;
+	isl_union_map *unmatched;
+	isl_union_pw_multi_aff *tagger;
+	isl_schedule *schedule;
+	isl_union_access_info *access;
+	isl_union_flow *flow;
+
+	tagger = isl_union_pw_multi_aff_copy(ps->tagger);
+	schedule = isl_schedule_copy(ps->schedule);
+	schedule = isl_schedule_pullback_union_pw_multi_aff(schedule, tagger);
+	reads = isl_union_map_copy(ps->tagged_reads);
+	matched = isl_union_map_domain(isl_union_map_copy(ps->tagged_dep_flow));
+	unmatched = isl_union_map_copy(ps->tagged_may_writes);
+	unmatched = isl_union_map_subtract_domain(unmatched, matched);
+	reads = isl_union_map_union(reads, unmatched);
+	access = isl_union_access_info_from_sink(
+				isl_union_map_copy(ps->tagged_may_writes));
+	access = isl_union_access_info_set_may_source(access, reads);
+	access = isl_union_access_info_set_schedule(access, schedule);
+	flow = isl_union_access_info_compute_flow(access);
+	shared_access = isl_union_flow_get_may_dependence(flow);
+	isl_union_flow_free(flow);
+
+	ps->tagged_dep_order = isl_union_map_copy(shared_access);
+	ps->dep_order = isl_union_map_factor_domain(shared_access);
+}
+
+/* Compute those validity dependences of the program represented by "scop"
+ * that should be unconditionally enforced even when live-range reordering
+ * is used.
+ *
+ * In particular, compute the external false dependences
+ * as well as order dependences between sources with the same sink.
+ * The anti-dependences are already taken care of by the order dependences.
+ * The external false dependences are only used to ensure that live-in and
+ * live-out data is not overwritten by any writes inside the scop.
+ * The independences are removed from the external false dependences,
+ * but not from the order dependences between sources with the same sink.
+ *
+ * In particular, the reads from live-in data need to precede any
+ * later write to the same memory element.
+ * As to live-out data, the last writes need to remain the last writes.
+ * That is, any earlier write in the original schedule needs to precede
+ * the last write to the same memory element in the computed schedule.
+ * The possible last writes have been computed by compute_live_out.
+ * They may include kills, but if the last access is a kill,
+ * then the corresponding dependences will effectively be ignored
+ * since we do not schedule any kill statements.
+ *
+ * Note that the set of live-in and live-out accesses may be
+ * an overapproximation.  There may therefore be potential writes
+ * before a live-in access and after a live-out access.
+ *
+ * In the presence of may-writes, there may be multiple live-ranges
+ * with the same sink, accessing the same memory element.
+ * The sources of these live-ranges need to be executed
+ * in the same relative order as in the original program
+ * since we do not know which of the may-writes will actually
+ * perform a write.  Consider all sources that share a sink and
+ * that may write to the same memory element and compute
+ * the order dependences among them.
+ */
+static void compute_forced_dependences(struct ppcg_scop *ps)
+{
+	isl_union_map *shared_access;
+	isl_union_map *exposed;
+	isl_union_map *live_in;
+	isl_union_map *sink_access;
+	isl_union_map *shared_sink;
+	isl_union_access_info *access;
+	isl_union_flow *flow;
+	isl_schedule *schedule;
+
+	exposed = isl_union_map_copy(ps->live_out);
+	schedule = isl_schedule_copy(ps->schedule);
+	access = isl_union_access_info_from_sink(exposed);
+	access = isl_union_access_info_set_may_source(access,
+				isl_union_map_copy(ps->may_writes));
+	access = isl_union_access_info_set_schedule(access, schedule);
+	flow = isl_union_access_info_compute_flow(access);
+	shared_access = isl_union_flow_get_may_dependence(flow);
+	isl_union_flow_free(flow);
+	ps->dep_forced = shared_access;
+
+	schedule = isl_schedule_copy(ps->schedule);
+	access = isl_union_access_info_from_sink(
+				isl_union_map_copy(ps->may_writes));
+	access = isl_union_access_info_set_may_source(access,
+				isl_union_map_copy(ps->live_in));
+	access = isl_union_access_info_set_schedule(access, schedule);
+	flow = isl_union_access_info_compute_flow(access);
+	live_in = isl_union_flow_get_may_dependence(flow);
+	isl_union_flow_free(flow);
+
+	ps->dep_forced = isl_union_map_union(ps->dep_forced, live_in);
+	ps->dep_forced = isl_union_map_subtract(ps->dep_forced,
+				isl_union_map_copy(ps->independence));
+
+	schedule = isl_schedule_copy(ps->schedule);
+	sink_access = isl_union_map_copy(ps->tagged_dep_flow);
+	sink_access = isl_union_map_range_product(sink_access,
+				isl_union_map_copy(ps->tagged_may_writes));
+	sink_access = isl_union_map_domain_factor_domain(sink_access);
+	access = isl_union_access_info_from_sink(
+				isl_union_map_copy(sink_access));
+	access = isl_union_access_info_set_may_source(access, sink_access);
+	access = isl_union_access_info_set_schedule(access, schedule);
+	flow = isl_union_access_info_compute_flow(access);
+	shared_sink = isl_union_flow_get_may_dependence(flow);
+	isl_union_flow_free(flow);
+	ps->dep_forced = isl_union_map_union(ps->dep_forced, shared_sink);
+}
+
+/* Remove independence from the tagged flow dependences.
+ * Since the user has guaranteed that source and sink of an independence
+ * can be executed in any order, there cannot be a flow dependence
+ * between them, so they can be removed from the set of flow dependences.
+ * However, if the source of such a flow dependence is a must write,
+ * then it may have killed other potential sources, which would have
+ * to be recovered if we were to remove those flow dependences.
+ * We therefore keep the flow dependences that originate in a must write,
+ * even if it corresponds to a known independence.
+ */
+static void remove_independences_from_tagged_flow(struct ppcg_scop *ps)
+{
+	isl_union_map *tf;
+	isl_union_set *indep;
+	isl_union_set *mw;
+
+	tf = isl_union_map_copy(ps->tagged_dep_flow);
+	tf = isl_union_map_zip(tf);
+	indep = isl_union_map_wrap(isl_union_map_copy(ps->independence));
+	tf = isl_union_map_intersect_domain(tf, indep);
+	tf = isl_union_map_zip(tf);
+	mw = isl_union_map_domain(isl_union_map_copy(ps->tagged_must_writes));
+	tf = isl_union_map_subtract_domain(tf, mw);
+	ps->tagged_dep_flow = isl_union_map_subtract(ps->tagged_dep_flow, tf);
+}
+
+/* Compute the dependences of the program represented by "scop"
+ * in case live range reordering is allowed.
+ *
+ * We compute the actual live ranges and the corresponding order
+ * false dependences.
+ *
+ * The independences are removed from the flow dependences
+ * (provided the source is not a must-write) as well as
+ * from the external false dependences (by compute_forced_dependences).
+ */
+static void compute_live_range_reordering_dependences(struct ppcg_scop *ps)
+{
+	compute_tagged_flow_dep_only(ps);
+	remove_independences_from_tagged_flow(ps);
+	derive_flow_dep_from_tagged_flow_dep(ps);
+	compute_order_dependences(ps);
+	compute_forced_dependences(ps);
+}
+
+/* Compute the potential flow dependences and the potential live in
+ * accesses.
+ */
+static void compute_flow_dep(struct ppcg_scop *ps)
+{
+	isl_union_access_info *access;
+	isl_union_flow *flow;
+
+	access = isl_union_access_info_from_sink(isl_union_map_copy(ps->reads));
+	access = isl_union_access_info_set_must_source(access,
+				isl_union_map_copy(ps->must_writes));
+	access = isl_union_access_info_set_may_source(access,
+				isl_union_map_copy(ps->may_writes));
+	access = isl_union_access_info_set_schedule(access,
+				isl_schedule_copy(ps->schedule));
+	flow = isl_union_access_info_compute_flow(access);
+
+	ps->dep_flow = isl_union_flow_get_may_dependence(flow);
+	ps->live_in = isl_union_flow_get_may_no_source(flow);
+	isl_union_flow_free(flow);
+}
+
+/* Compute the dependences of the program represented by "scop".
+ * Store the computed potential flow dependences
+ * in scop->dep_flow and the reads with potentially no corresponding writes in
+ * scop->live_in.
+ * Store the potential live out accesses in scop->live_out.
+ * Store the potential false (anti and output) dependences in scop->dep_false.
+ *
+ * If live range reordering is allowed, then we compute a separate
+ * set of order dependences and a set of external false dependences
+ * in compute_live_range_reordering_dependences.
+ */
+void compute_dependences(struct ppcg_scop *scop)
+{
+	isl_union_map *may_source;
+	isl_union_access_info *access;
+	isl_union_flow *flow;
+
+	if (!scop)
+		return;
+
+	compute_live_out(scop);
+
+	if (scop->options->live_range_reordering)
+		compute_live_range_reordering_dependences(scop);
+	else if (scop->options->target != PPCG_TARGET_C)
+		compute_tagged_flow_dep(scop);
+	else
+		compute_flow_dep(scop);
+
+	may_source = isl_union_map_union(isl_union_map_copy(scop->may_writes),
+					isl_union_map_copy(scop->reads));
+	access = isl_union_access_info_from_sink(
+				isl_union_map_copy(scop->may_writes));
+	access = isl_union_access_info_set_must_source(access,
+				isl_union_map_copy(scop->must_writes));
+	access = isl_union_access_info_set_may_source(access, may_source);
+	access = isl_union_access_info_set_schedule(access,
+				isl_schedule_copy(scop->schedule));
+	flow = isl_union_access_info_compute_flow(access);
+
+	scop->dep_false = isl_union_flow_get_may_dependence(flow);
+	scop->dep_false = isl_union_map_coalesce(scop->dep_false);
+	isl_union_flow_free(flow);
+}
+
+/* Eliminate dead code from ps->domain.
+ *
+ * In particular, intersect both ps->domain and the domain of
+ * ps->schedule with the (parts of) iteration
+ * domains that are needed to produce the output or for statement
+ * iterations that call functions.
+ * Also intersect the range of the dataflow dependences with
+ * this domain such that the removed instances will no longer
+ * be considered as targets of dataflow.
+ *
+ * We start with the iteration domains that call functions
+ * and the set of iterations that last write to an array
+ * (except those that are later killed).
+ *
+ * Then we add those statement iterations that produce
+ * something needed by the "live" statements iterations.
+ * We keep doing this until no more statement iterations can be added.
+ * To ensure that the procedure terminates, we compute the affine
+ * hull of the live iterations (bounded to the original iteration
+ * domains) each time we have added extra iterations.
+ */
+void eliminate_dead_code(struct ppcg_scop *ps)
+{
+	isl_union_set *live;
+	isl_union_map *dep;
+	isl_union_pw_multi_aff *tagger;
+
+	live = isl_union_map_domain(isl_union_map_copy(ps->live_out));
+	if (!isl_union_set_is_empty(ps->call)) {
+		live = isl_union_set_union(live, isl_union_set_copy(ps->call));
+		live = isl_union_set_coalesce(live);
+	}
+
+	dep = isl_union_map_copy(ps->dep_flow);
+	dep = isl_union_map_reverse(dep);
+
+	for (;;) {
+		isl_union_set *extra;
+
+		extra = isl_union_set_apply(isl_union_set_copy(live),
+					    isl_union_map_copy(dep));
+		if (isl_union_set_is_subset(extra, live)) {
+			isl_union_set_free(extra);
+			break;
+		}
+
+		live = isl_union_set_union(live, extra);
+		live = isl_union_set_affine_hull(live);
+		live = isl_union_set_intersect(live,
+					    isl_union_set_copy(ps->domain));
+	}
+
+	isl_union_map_free(dep);
+
+	ps->domain = isl_union_set_intersect(ps->domain,
+						isl_union_set_copy(live));
+	ps->schedule = isl_schedule_intersect_domain(ps->schedule,
+						isl_union_set_copy(live));
+	ps->dep_flow = isl_union_map_intersect_range(ps->dep_flow,
+						isl_union_set_copy(live));
+	tagger = isl_union_pw_multi_aff_copy(ps->tagger);
+	live = isl_union_set_preimage_union_pw_multi_aff(live, tagger);
+	ps->tagged_dep_flow = isl_union_map_intersect_range(ps->tagged_dep_flow,
+						live);
+}
+
+/* Intersect "set" with the set described by "str", taking the NULL
+ * string to represent the universal set.
+ */
+static __isl_give isl_set *set_intersect_str(__isl_take isl_set *set,
+	const char *str)
+{
+	isl_ctx *ctx;
+	isl_set *set2;
+
+	if (!str)
+		return set;
+
+	ctx = isl_set_get_ctx(set);
+	set2 = isl_set_read_from_str(ctx, str);
+	set = isl_set_intersect(set, set2);
+
+	return set;
+}
+
+void *ppcg_scop_free(struct ppcg_scop *ps)
+{
+	if (!ps)
+		return NULL;
+
+	isl_set_free(ps->context);
+	isl_union_set_free(ps->domain);
+	isl_union_set_free(ps->call);
+	isl_union_map_free(ps->tagged_reads);
+	isl_union_map_free(ps->reads);
+	isl_union_map_free(ps->live_in);
+	isl_union_map_free(ps->tagged_may_writes);
+	isl_union_map_free(ps->tagged_must_writes);
+	isl_union_map_free(ps->may_writes);
+	isl_union_map_free(ps->must_writes);
+	isl_union_map_free(ps->live_out);
+	isl_union_map_free(ps->tagged_must_kills);
+	isl_union_map_free(ps->must_kills);
+	isl_union_map_free(ps->tagged_dep_flow);
+	isl_union_map_free(ps->dep_flow);
+	isl_union_map_free(ps->dep_false);
+	isl_union_map_free(ps->dep_forced);
+	isl_union_map_free(ps->tagged_dep_order);
+	isl_union_map_free(ps->dep_order);
+	isl_schedule_free(ps->schedule);
+	isl_union_pw_multi_aff_free(ps->tagger);
+	isl_union_map_free(ps->independence);
+	isl_id_to_ast_expr_free(ps->names);
+
+	free(ps);
+
+	return NULL;
+}
+
+/* Extract a ppcg_scop from a pet_scop.
+ *
+ * The constructed ppcg_scop refers to elements from the pet_scop
+ * so the pet_scop should not be freed before the ppcg_scop.
+ */
+static struct ppcg_scop *ppcg_scop_from_pet_scop(struct pet_scop *scop,
+	struct ppcg_options *options)
+{
+	int i;
+	isl_ctx *ctx;
+	struct ppcg_scop *ps;
+
+	if (!scop)
+		return NULL;
+
+	ctx = isl_set_get_ctx(scop->context);
+
+	ps = isl_calloc_type(ctx, struct ppcg_scop);
+	if (!ps)
+		return NULL;
+
+	ps->names = collect_names(scop);
+	ps->options = options;
+	ps->start = pet_loc_get_start(scop->loc);
+	ps->end = pet_loc_get_end(scop->loc);
+	ps->context = isl_set_copy(scop->context);
+	ps->context = set_intersect_str(ps->context, options->ctx);
+	if (options->non_negative_parameters) {
+		isl_space *space = isl_set_get_space(ps->context);
+		isl_set *nn = isl_set_nat_universe(space);
+		ps->context = isl_set_intersect(ps->context, nn);
+	}
+	ps->domain = collect_non_kill_domains(scop);
+	ps->call = collect_call_domains(scop);
+	ps->tagged_reads = pet_scop_get_tagged_may_reads(scop);
+	ps->reads = pet_scop_get_may_reads(scop);
+	ps->tagged_may_writes = pet_scop_get_tagged_may_writes(scop);
+	ps->may_writes = pet_scop_get_may_writes(scop);
+	ps->tagged_must_writes = pet_scop_get_tagged_must_writes(scop);
+	ps->must_writes = pet_scop_get_must_writes(scop);
+	ps->tagged_must_kills = pet_scop_get_tagged_must_kills(scop);
+	ps->must_kills = pet_scop_get_must_kills(scop);
+	ps->schedule = isl_schedule_copy(scop->schedule);
+	ps->pet = scop;
+	ps->independence = isl_union_map_empty(isl_set_get_space(ps->context));
+	for (i = 0; i < scop->n_independence; ++i)
+		ps->independence = isl_union_map_union(ps->independence,
+			isl_union_map_copy(scop->independences[i]->filter));
+
+	compute_tagger(ps);
+	compute_dependences(ps);
+	eliminate_dead_code(ps);
+
+	if (!ps->context || !ps->domain || !ps->call || !ps->reads ||
+	    !ps->may_writes || !ps->must_writes || !ps->tagged_must_kills ||
+	    !ps->must_kills || !ps->schedule || !ps->independence || !ps->names)
+		return ppcg_scop_free(ps);
+
+	return ps;
+}
+
+/* Internal data structure for ppcg_transform.
+ */
+struct ppcg_transform_data {
+	struct ppcg_options *options;
+	__isl_give isl_printer *(*transform)(__isl_take isl_printer *p,
+		struct ppcg_scop *scop, void *user);
+	void *user;
+};
+
+/* Should we print the original code?
+ * That is, does "scop" involve any data dependent conditions or
+ * nested expressions that cannot be handled by pet_stmt_build_ast_exprs?
+ */
+static int print_original(struct pet_scop *scop, struct ppcg_options *options)
+{
+	if (!pet_scop_can_build_ast_exprs(scop)) {
+		if (options->debug->verbose)
+			fprintf(stdout, "Printing original code because "
+				"some index expressions cannot currently "
+				"be printed\n");
+		return 1;
+	}
+
+	if (pet_scop_has_data_dependent_conditions(scop)) {
+		if (options->debug->verbose)
+			fprintf(stdout, "Printing original code because "
+				"input involves data dependent conditions\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Callback for pet_transform_C_source that transforms
+ * the given pet_scop to a ppcg_scop before calling the
+ * ppcg_transform callback.
+ *
+ * If "scop" contains any data dependent conditions or if we may
+ * not be able to print the transformed program, then just print
+ * the original code.
+ */
+static __isl_give isl_printer *transform(__isl_take isl_printer *p,
+	struct pet_scop *scop, void *user)
+{
+	struct ppcg_transform_data *data = user;
+	struct ppcg_scop *ps;
+
+	if (print_original(scop, data->options)) {
+		p = pet_scop_print_original(scop, p);
+		pet_scop_free(scop);
+		return p;
+	}
+
+	scop = pet_scop_align_params(scop);
+	ps = ppcg_scop_from_pet_scop(scop, data->options);
+
+	p = data->transform(p, ps, data->user);
+
+	ppcg_scop_free(ps);
+	pet_scop_free(scop);
+
+	return p;
+}
+
+/* Transform the C source file "input" by rewriting each scop
+ * through a call to "transform".
+ * The transformed C code is written to "out".
+ *
+ * This is a wrapper around pet_transform_C_source that transforms
+ * the pet_scop to a ppcg_scop before calling "fn".
+ */
+int ppcg_transform(isl_ctx *ctx, const char *input, FILE *out,
+	struct ppcg_options *options,
+	__isl_give isl_printer *(*fn)(__isl_take isl_printer *p,
+		struct ppcg_scop *scop, void *user), void *user)
+{
+	struct ppcg_transform_data data = { options, fn, user };
+	return pet_transform_C_source(ctx, input, out, &transform, &data);
+}
+
+/* Check consistency of options.
+ *
+ * Return -1 on error.
+ */
+static int check_options(isl_ctx *ctx)
+{
+	struct options *options;
+
+	options = isl_ctx_peek_options(ctx, &options_args);
+	if (!options)
+		isl_die(ctx, isl_error_internal,
+			"unable to find options", return -1);
+
+	if (options->ppcg->openmp &&
+	    !isl_options_get_ast_build_atomic_upper_bound(ctx))
+		isl_die(ctx, isl_error_invalid,
+			"OpenMP requires atomic bounds", return -1);
+
+	return 0;
+}
+
+#if 0
+int main(int argc, char **argv)
+{
+	int r;
+	isl_ctx *ctx;
+	struct options *options;
+
+	options = options_new_with_defaults();
+	assert(options);
+
+	ctx = isl_ctx_alloc_with_options(&options_args, options);
+	ppcg_options_set_target_defaults(options->ppcg);
+	isl_options_set_ast_build_detect_min_max(ctx, 1);
+	isl_options_set_ast_print_macro_once(ctx, 1);
+	isl_options_set_schedule_whole_component(ctx, 0);
+	isl_options_set_schedule_maximize_band_depth(ctx, 1);
+	isl_options_set_schedule_maximize_coincidence(ctx, 1);
+	pet_options_set_encapsulate_dynamic_control(ctx, 1);
+	argc = options_parse(options, argc, argv, ISL_ARG_ALL);
+
+	if (check_options(ctx) < 0)
+		r = EXIT_FAILURE;
+	else if (options->ppcg->target == PPCG_TARGET_CUDA)
+		r = generate_cuda(ctx, options->ppcg, options->input);
+	else if (options->ppcg->target == PPCG_TARGET_OPENCL)
+		r = generate_opencl(ctx, options->ppcg, options->input,
+				options->output);
+	else
+		r = generate_cpu(ctx, options->ppcg, options->input,
+				options->output);
+
+	isl_ctx_free(ctx);
+
+	return r;
+}
+#endif
diff --git a/final/lib/External/ppcg/ppcg.h b/final/lib/External/ppcg/ppcg.h
new file mode 100644
index 0000000..ef89683
--- /dev/null
+++ b/final/lib/External/ppcg/ppcg.h
@@ -0,0 +1,128 @@
+#ifndef PPCG_H
+#define PPCG_H
+
+#include <isl/schedule.h>
+#include <isl/set.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
+#include <isl/id_to_ast_expr.h>
+#include <pet.h>
+
+#include "ppcg_options.h"
+
+const char *ppcg_base_name(const char *filename);
+int ppcg_extract_base_name(char *name, const char *input);
+
+/* Representation of the scop for use inside PPCG.
+ *
+ * "options" are the options specified by the user.
+ * Some fields in this structure may depend on some of the options.
+ *
+ * "start" and "end" are file offsets of the corresponding program text.
+ * "context" represents constraints on the parameters.
+ * "domain" is the union of all iteration domains.
+ * "call" contains the iteration domains of statements with a call expression.
+ * "reads" contains all potential read accesses.
+ * "tagged_reads" is the same as "reads", except that the domain is a wrapped
+ *	relation mapping an iteration domain to a reference identifier
+ * "live_in" contains the potential read accesses that potentially
+ *	have no corresponding writes in the scop.
+ * "may_writes" contains all potential write accesses.
+ * "tagged_may_writes" is the same as "may_writes", except that the domain
+ *	is a wrapped relation mapping an iteration domain
+ *	to a reference identifier
+ * "must_writes" contains all definite write accesses.
+ * "tagged_must_writes" is the same as "must_writes", except that the domain
+ *	is a wrapped relation mapping an iteration domain
+ *	to a reference identifier
+ * "live_out" contains the potential write accesses that are potentially
+ *	not killed by any kills or any other writes.
+ * "must_kills" contains all definite kill accesses.
+ * "tagged_must_kills" is the same as "must_kills", except that the domain
+ *	is a wrapped relation mapping an iteration domain
+ *	to a reference identifier.
+ *
+ * "tagger" maps tagged iteration domains to the corresponding untagged
+ *	iteration domain.
+ *
+ * "independence" is the union of all independence filters.
+ *
+ * "dep_flow" represents the potential flow dependences.
+ * "tagged_dep_flow" is the same as "dep_flow", except that both domain and
+ *	range are wrapped relations mapping an iteration domain to
+ *	a reference identifier.  May be NULL if not computed.
+ * "dep_false" represents the potential false (anti and output) dependences.
+ * "dep_forced" represents the validity constraints that should be enforced
+ *	even when live-range reordering is used.
+ *	In particular, these constraints ensure that all live-in
+ *	accesses remain live-in and that all live-out accesses remain live-out
+ *	and that multiple potential sources for the same read are
+ *	executed in the original order.
+ * "dep_order"/"tagged_dep_order" represents the order dependences between
+ *	the live range intervals in "dep_flow"/"tagged_dep_flow".
+ *	It is only used if the live_range_reordering
+ *	option is set.  Otherwise it is NULL.
+ *	If "dep_order" is used, then "dep_false" only contains a limited
+ *	set of anti and output dependences.
+ * "schedule" represents the (original) schedule.
+ *
+ * "names" contains all variable names that are in use by the scop.
+ * The names are mapped to a dummy value.
+ *
+ * "pet" is the original pet_scop.
+ */
+struct ppcg_scop {
+	struct ppcg_options *options;
+
+	unsigned start;
+	unsigned end;
+
+	isl_set *context;
+	isl_union_set *domain;
+	isl_union_set *call;
+	isl_union_map *tagged_reads;
+	isl_union_map *reads;
+	isl_union_map *live_in;
+	isl_union_map *tagged_may_writes;
+	isl_union_map *may_writes;
+	isl_union_map *tagged_must_writes;
+	isl_union_map *must_writes;
+	isl_union_map *live_out;
+	isl_union_map *tagged_must_kills;
+	isl_union_map *must_kills;
+
+	isl_union_pw_multi_aff *tagger;
+
+	isl_union_map *independence;
+
+	isl_union_map *dep_flow;
+	isl_union_map *tagged_dep_flow;
+	isl_union_map *dep_false;
+	isl_union_map *dep_forced;
+	isl_union_map *dep_order;
+	isl_union_map *tagged_dep_order;
+	isl_schedule *schedule;
+
+	isl_id_to_ast_expr *names;
+
+	struct pet_scop *pet;
+};
+
+int ppcg_scop_any_hidden_declarations(struct ppcg_scop *scop);
+__isl_give isl_id_list *ppcg_scop_generate_names(struct ppcg_scop *scop,
+	int n, const char *prefix);
+
+int ppcg_transform(isl_ctx *ctx, const char *input, FILE *out,
+	struct ppcg_options *options,
+	__isl_give isl_printer *(*fn)(__isl_take isl_printer *p,
+		struct ppcg_scop *scop, void *user), void *user);
+
+__isl_give isl_schedule *ppcg_compute_schedule(
+	__isl_take isl_schedule_constraints *sc,
+	__isl_keep isl_schedule *schedule, struct ppcg_options *options);
+
+void compute_tagger(struct ppcg_scop *ps);
+void compute_dependences(struct ppcg_scop *scop);
+void eliminate_dead_code(struct ppcg_scop *ps);
+void *ppcg_scop_free(struct ppcg_scop *ps);
+#endif
diff --git a/final/lib/External/ppcg/ppcg_options.c b/final/lib/External/ppcg/ppcg_options.c
new file mode 100644
index 0000000..77b0f29
--- /dev/null
+++ b/final/lib/External/ppcg/ppcg_options.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2010-2011 INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ */
+
+#include "ppcg_options.h"
+
+static struct isl_arg_choice target[] = {
+	{"c",		PPCG_TARGET_C},
+	{"cuda",	PPCG_TARGET_CUDA},
+	{"opencl",      PPCG_TARGET_OPENCL},
+	{0}
+};
+
+/* Set defaults that depend on the target.
+ * In particular, set --schedule-outer-coincidence iff target is a GPU.
+ */
+void ppcg_options_set_target_defaults(struct ppcg_options *options)
+{
+	char *argv[2] = { NULL };
+
+	argv[0] = "ppcg_options_set_target_defaults";
+	if (options->target == PPCG_TARGET_C)
+		argv[1] = "--no-schedule-outer-coincidence";
+	else
+		argv[1] = "--schedule-outer-coincidence";
+
+	isl_options_parse(options->isl, 2, argv, ISL_ARG_ALL);
+}
+
+/* Callback that is called whenever the "target" option is set (to "val").
+ * The callback is called after target has been updated.
+ *
+ * Call ppcg_options_set_target_defaults to reset the target-dependent options.
+ */
+static int set_target(void *opt, unsigned val)
+{
+	struct ppcg_options *options = opt;
+
+	ppcg_options_set_target_defaults(options);
+
+	return 0;
+}
+
+ISL_ARGS_START(struct ppcg_debug_options, ppcg_debug_options_args)
+ISL_ARG_BOOL(struct ppcg_debug_options, dump_schedule_constraints, 0,
+	"dump-schedule-constraints", 0, "dump schedule constraints")
+ISL_ARG_BOOL(struct ppcg_debug_options, dump_schedule, 0,
+	"dump-schedule", 0, "dump isl computed schedule")
+ISL_ARG_BOOL(struct ppcg_debug_options, dump_final_schedule, 0,
+	"dump-final-schedule", 0, "dump PPCG computed schedule")
+ISL_ARG_BOOL(struct ppcg_debug_options, dump_sizes, 0,
+	"dump-sizes", 0,
+	"dump effectively used per kernel tile, grid and block sizes")
+ISL_ARG_BOOL(struct ppcg_debug_options, verbose, 'v', "verbose", 0, NULL)
+ISL_ARGS_END
+
+ISL_ARGS_START(struct ppcg_options, ppcg_opencl_options_args)
+ISL_ARG_STR(struct ppcg_options, opencl_compiler_options, 0, "compiler-options",
+	"options", NULL, "options to pass to the OpenCL compiler")
+ISL_ARG_BOOL(struct ppcg_options, opencl_use_gpu, 0, "use-gpu", 1,
+	"use GPU device (if available)")
+ISL_ARG_STR_LIST(struct ppcg_options, opencl_n_include_file,
+	opencl_include_files, 0, "include-file", "filename",
+	"file to #include in generated OpenCL code")
+ISL_ARG_BOOL(struct ppcg_options, opencl_print_kernel_types, 0,
+	"print-kernel-types", 1,
+	"print definitions of types in the kernel file")
+ISL_ARG_BOOL(struct ppcg_options, opencl_embed_kernel_code, 0,
+	"embed-kernel-code", 0, "embed kernel code into host code")
+ISL_ARGS_END
+
+ISL_ARGS_START(struct ppcg_options, ppcg_options_args)
+ISL_ARG_CHILD(struct ppcg_options, isl, "isl", &isl_options_args, "isl options")
+ISL_ARG_CHILD(struct ppcg_options, debug, NULL, &ppcg_debug_options_args,
+	"debugging options")
+ISL_ARG_BOOL(struct ppcg_options, group_chains, 0, "group-chains", 1,
+	"group chains of interdependent statements that are executed "
+	"consecutively in the original schedule before scheduling")
+ISL_ARG_BOOL(struct ppcg_options, reschedule, 0, "reschedule", 1,
+	"replace original schedule by isl computed schedule")
+ISL_ARG_BOOL(struct ppcg_options, scale_tile_loops, 0,
+	"scale-tile-loops", 1, NULL)
+ISL_ARG_BOOL(struct ppcg_options, wrap, 0, "wrap", 1, NULL)
+ISL_ARG_BOOL(struct ppcg_options, use_shared_memory, 0, "shared-memory", 1,
+	"use shared memory in kernel code")
+ISL_ARG_BOOL(struct ppcg_options, use_private_memory, 0, "private-memory", 1,
+	"use private memory in kernel code")
+ISL_ARG_STR(struct ppcg_options, ctx, 0, "ctx", "context", NULL,
+    "Constraints on parameters")
+ISL_ARG_BOOL(struct ppcg_options, non_negative_parameters, 0,
+	"assume-non-negative-parameters", 0,
+	"assume all parameters are non-negative)")
+ISL_ARG_BOOL(struct ppcg_options, tile, 0, "tile", 0,
+	"perform tiling (C target)")
+ISL_ARG_INT(struct ppcg_options, tile_size, 'S', "tile-size", "size", 32, NULL)
+ISL_ARG_BOOL(struct ppcg_options, isolate_full_tiles, 0, "isolate-full-tiles",
+	0, "isolate full tiles from partial tiles (hybrid tiling)")
+ISL_ARG_STR(struct ppcg_options, sizes, 0, "sizes", "sizes", NULL,
+	"Per kernel tile, grid and block sizes")
+ISL_ARG_INT(struct ppcg_options, max_shared_memory, 0,
+	"max-shared-memory", "size", 8192, "maximal amount of shared memory")
+ISL_ARG_BOOL(struct ppcg_options, openmp, 0, "openmp", 0,
+	"Generate OpenMP macros (only for C target)")
+ISL_ARG_USER_OPT_CHOICE(struct ppcg_options, target, 0, "target", target,
+	&set_target, PPCG_TARGET_CUDA, PPCG_TARGET_CUDA,
+	"the target to generate code for")
+ISL_ARG_BOOL(struct ppcg_options, linearize_device_arrays, 0,
+	"linearize-device-arrays", 1,
+	"linearize all device arrays, even those of fixed size")
+ISL_ARG_BOOL(struct ppcg_options, allow_gnu_extensions, 0,
+	"allow-gnu-extensions", 1,
+	"allow the use of GNU extensions in generated code")
+ISL_ARG_BOOL(struct ppcg_options, live_range_reordering, 0,
+	"live-range-reordering", 1,
+	"allow successive live ranges on the same memory element "
+	"to be reordered")
+ISL_ARG_BOOL(struct ppcg_options, hybrid, 0, "hybrid", 0,
+	"apply hybrid tiling whenever a suitable input pattern is found "
+	"(GPU targets)")
+ISL_ARG_BOOL(struct ppcg_options, unroll_copy_shared, 0, "unroll-copy-shared",
+	0, "unroll code for copying to/from shared memory")
+ISL_ARG_BOOL(struct ppcg_options, unroll_gpu_tile, 0, "unroll-gpu-tile", 0,
+	"unroll code inside tile on GPU targets")
+ISL_ARG_GROUP("opencl", &ppcg_opencl_options_args, "OpenCL options")
+ISL_ARG_STR(struct ppcg_options, save_schedule_file, 0, "save-schedule",
+	"file", NULL, "save isl computed schedule to <file>")
+ISL_ARG_STR(struct ppcg_options, load_schedule_file, 0, "load-schedule",
+	"file", NULL, "load schedule from <file>, "
+	"using it instead of an isl computed schedule")
+ISL_ARGS_END
diff --git a/final/lib/External/ppcg/ppcg_options.h b/final/lib/External/ppcg/ppcg_options.h
new file mode 100644
index 0000000..56aa7cb
--- /dev/null
+++ b/final/lib/External/ppcg/ppcg_options.h
@@ -0,0 +1,100 @@
+#ifndef PPCG_OPTIONS_H
+#define PPCG_OPTIONS_H
+
+#include <isl/arg.h>
+#include <isl/options.h>
+
+struct ppcg_debug_options {
+	int dump_schedule_constraints;
+	int dump_schedule;
+	int dump_final_schedule;
+	int dump_sizes;
+	int verbose;
+};
+
+struct ppcg_options {
+	struct isl_options *isl;
+	struct ppcg_debug_options *debug;
+
+	/* Group chains of consecutive statements before scheduling. */
+	int group_chains;
+
+	/* Use isl to compute a schedule replacing the original schedule. */
+	int reschedule;
+	int scale_tile_loops;
+	int wrap;
+
+	/* Assume all parameters are non-negative. */
+	int non_negative_parameters;
+	char *ctx;
+	char *sizes;
+
+	/* Perform tiling (C target). */
+	int tile;
+	int tile_size;
+
+	/* Isolate full tiles from partial tiles. */
+	int isolate_full_tiles;
+
+	/* Take advantage of private memory. */
+	int use_private_memory;
+
+	/* Take advantage of shared memory. */
+	int use_shared_memory;
+
+	/* Maximal amount of shared memory. */
+	int max_shared_memory;
+
+	/* The target we generate code for. */
+	int target;
+
+	/* Generate OpenMP macros (C target only). */
+	int openmp;
+
+	/* Linearize all device arrays. */
+	int linearize_device_arrays;
+
+	/* Allow the use of GNU extensions in generated code. */
+	int allow_gnu_extensions;
+
+	/* Allow live range to be reordered. */
+	int live_range_reordering;
+
+	/* Allow hybrid tiling whenever a suitable input pattern is found. */
+	int hybrid;
+
+	/* Unroll the code for copying to/from shared memory. */
+	int unroll_copy_shared;
+	/* Unroll code inside tile on GPU targets. */
+	int unroll_gpu_tile;
+
+	/* Options to pass to the OpenCL compiler.  */
+	char *opencl_compiler_options;
+	/* Prefer GPU device over CPU. */
+	int opencl_use_gpu;
+	/* Number of files to include. */
+	int opencl_n_include_file;
+	/* Files to include. */
+	const char **opencl_include_files;
+	/* Print definitions of types in kernels. */
+	int opencl_print_kernel_types;
+	/* Embed OpenCL kernel code in host code. */
+	int opencl_embed_kernel_code;
+
+	/* Name of file for saving isl computed schedule or NULL. */
+	char *save_schedule_file;
+	/* Name of file for loading schedule or NULL. */
+	char *load_schedule_file;
+};
+
+ISL_ARG_DECL(ppcg_debug_options, struct ppcg_debug_options,
+	ppcg_debug_options_args)
+ISL_ARG_DECL(ppcg_options, struct ppcg_options, ppcg_options_args)
+
+#define		PPCG_TARGET_C		0
+#define		PPCG_TARGET_CUDA	1
+#define		PPCG_TARGET_OPENCL      2
+
+void ppcg_options_set_target_defaults(struct ppcg_options *options);
+
+#endif
diff --git a/final/lib/External/ppcg/print.c b/final/lib/External/ppcg/print.c
new file mode 100644
index 0000000..79aaf2b
--- /dev/null
+++ b/final/lib/External/ppcg/print.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <isl/aff.h>
+#include <isl/ast_build.h>
+
+#include "print.h"
+#include "util.h"
+
+__isl_give isl_printer *ppcg_start_block(__isl_take isl_printer *p)
+{
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "{");
+	p = isl_printer_end_line(p);
+	p = isl_printer_indent(p, 2);
+	return p;
+}
+
+__isl_give isl_printer *ppcg_end_block(__isl_take isl_printer *p)
+{
+	p = isl_printer_indent(p, -2);
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "}");
+	p = isl_printer_end_line(p);
+	return p;
+}
+
+/* Names of notes that keep track of whether min/max
+ * macro definitions have already been printed.
+ */
+static const char *ppcg_max_printed = "ppcg_max_printed";
+static const char *ppcg_min_printed = "ppcg_min_printed";
+
+/* Has the macro definition corresponding to "note_name" been printed
+ * to "p" before?
+ * That is, does "p" have an associated "note_name" note?
+ */
+static isl_bool printed_before(__isl_keep isl_printer *p, const char *note_name)
+{
+	isl_ctx *ctx;
+	isl_id *id;
+	isl_bool printed;
+
+	if (!p)
+		return isl_bool_error;
+
+	ctx = isl_printer_get_ctx(p);
+	id = isl_id_alloc(ctx, note_name, NULL);
+	printed = isl_printer_has_note(p, id);
+	isl_id_free(id);
+
+	return printed;
+}
+
+/* Keep track of the fact that the macro definition corresponding
+ * to "note_name" has been printed to "p" by attaching a note with
+ * that name.  The value of the note is of no importance, but it
+ * has to be a valid isl_id, so the note identifier is reused
+ * as the note.
+ */
+static __isl_give isl_printer *mark_printed(__isl_take isl_printer *p,
+	const char *note_name)
+{
+	isl_ctx *ctx;
+	isl_id *id;
+
+	if (!p)
+		return NULL;
+
+	ctx = isl_printer_get_ctx(p);
+	id = isl_id_alloc(ctx, note_name, NULL);
+	return isl_printer_set_note(p, id, isl_id_copy(id));
+}
+
+/* Print a macro definition "def" for the macro "name" to "p",
+ * unless such a macro definition has been printed to "p" before.
+ * "note_name" is used as the name of the note that keeps track
+ * of whether this printing has happened.
+ */
+static __isl_give isl_printer *print_ppcg_macro(__isl_take isl_printer *p,
+	const char *name, const char *def, const char *note_name)
+{
+	isl_bool printed;
+
+	printed = printed_before(p, note_name);
+	if (printed < 0)
+		return isl_printer_free(p);
+	if (printed)
+		return p;
+
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, "#define ");
+	p = isl_printer_print_str(p, name);
+	p = isl_printer_print_str(p, def);
+	p = isl_printer_end_line(p);
+
+	p = mark_printed(p, note_name);
+
+	return p;
+}
+
+/* Structure for keeping track of definitions of some macros.
+ */
+struct ppcg_macros {
+	const char *min;
+	const char *max;
+};
+
+/* Free the memory allocated by a struct ppcg_macros.
+ */
+static void ppcg_macros_free(void *user)
+{
+	free(user);
+}
+
+/* Default macro definitions (when GNU extensions are allowed).
+ */
+struct ppcg_macros ppcg_macros_default = {
+	.min = "(x,y)    "
+		"({ __typeof__(x) _x = (x); __typeof__(y) _y = (y); "
+		"_x < _y ? _x : _y; })",
+	.max = "(x,y)    "
+		"({ __typeof__(x) _x = (x); __typeof__(y) _y = (y); "
+		"_x > _y ? _x : _y; })",
+};
+
+/* Name used for the note that keeps track of macro definitions.
+ */
+static const char *ppcg_macros = "ppcg_macros";
+
+/* Set the macro definitions for isl_ast_op_min and isl_ast_op_max
+ * to "min" and "max" and store them in "p".
+ *
+ * In particular, create a ppcg_macros object and attach it
+ * as a note to the printer.
+ */
+__isl_give isl_printer *ppcg_set_macros(__isl_take isl_printer *p,
+	const char *min, const char *max)
+{
+	isl_ctx *ctx;
+	isl_id *id, *macros_id;
+	struct ppcg_macros *macros;
+
+	if (!p)
+		return NULL;
+
+	ctx = isl_printer_get_ctx(p);
+	macros = isl_alloc_type(ctx, struct ppcg_macros);
+	if (!macros)
+		return isl_printer_free(p);
+	macros->min = min;
+	macros->max = max;
+	id = isl_id_alloc(ctx, ppcg_macros, NULL);
+	macros_id = isl_id_alloc(ctx, NULL, macros);
+	if (!macros_id)
+		ppcg_macros_free(macros);
+	else
+		macros_id = isl_id_set_free_user(macros_id, &ppcg_macros_free);
+
+	p = isl_printer_set_note(p, id, macros_id);
+
+	return p;
+}
+
+/* Return the ppcg_macros object that holds the currently active
+ * macro definitions in "p".
+ * If "p" has a note with macro definitions, then return those.
+ * Otherwise, return the default macro definitions.
+ */
+static struct ppcg_macros *get_macros(__isl_keep isl_printer *p)
+{
+	isl_id *id;
+	isl_bool has_macros;
+	struct ppcg_macros *macros;
+
+	id = isl_id_alloc(isl_printer_get_ctx(p), ppcg_macros, NULL);
+	has_macros = isl_printer_has_note(p, id);
+	if (has_macros < 0 || !has_macros) {
+		isl_id_free(id);
+		if (has_macros < 0)
+			return NULL;
+		return &ppcg_macros_default;
+	}
+	id = isl_printer_get_note(p, id);
+	macros = isl_id_get_user(id);
+	isl_id_free(id);
+
+	return macros;
+}
+
+/* Print the currently active macro definition for ppcg_max.
+ */
+static __isl_give isl_printer *print_max(__isl_take isl_printer *p)
+{
+	struct ppcg_macros *macros;
+
+	macros = get_macros(p);
+	if (!macros)
+		return isl_printer_free(p);
+	return print_ppcg_macro(p, ppcg_max, macros->max, ppcg_max_printed);
+}
+
+/* Print the currently active macro definition for ppcg_min.
+ */
+static __isl_give isl_printer *print_min(__isl_take isl_printer *p)
+{
+	struct ppcg_macros *macros;
+
+	macros = get_macros(p);
+	if (!macros)
+		return isl_printer_free(p);
+	return print_ppcg_macro(p, ppcg_min, macros->min, ppcg_min_printed);
+}
+
+/* Print a macro definition for "type" to "p".
+ * If GNU extensions are allowed, then print a specialized definition
+ * for isl_ast_op_min and isl_ast_op_max.
+ * Otherwise, use the default isl definition.
+ */
+__isl_give isl_printer *ppcg_print_macro(enum isl_ast_op_type type,
+	__isl_take isl_printer *p)
+{
+	isl_ctx *ctx;
+	struct ppcg_options *options;
+
+	if (!p)
+		return NULL;
+
+	ctx = isl_printer_get_ctx(p);
+	options = isl_ctx_peek_options(ctx, &ppcg_options_args);
+	if (!options || !options->allow_gnu_extensions)
+		return isl_ast_op_type_print_macro(type, p);
+
+	switch (type) {
+	case isl_ast_op_max:
+		return print_max(p);
+	case isl_ast_op_min:
+		return print_min(p);
+	default:
+		return isl_ast_op_type_print_macro(type, p);
+	}
+}
+
+/* isl_ast_expr_foreach_ast_op_type or isl_ast_node_foreach_ast_op_type
+ * callback that prints a macro definition for "type".
+ */
+static isl_stat print_macro(enum isl_ast_op_type type, void *user)
+{
+	isl_printer **p = user;
+
+	*p = ppcg_print_macro(type, *p);
+	if (!*p)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Print the required macros for "expr".
+ */
+__isl_give isl_printer *ppcg_ast_expr_print_macros(
+	__isl_keep isl_ast_expr *expr, __isl_take isl_printer *p)
+{
+	if (isl_ast_expr_foreach_ast_op_type(expr, &print_macro, &p) < 0)
+		return isl_printer_free(p);
+	return p;
+}
+
+/* isl_id_to_ast_expr_foreach callback that prints the required
+ * macro definitions for "val".
+ */
+static isl_stat print_expr_macros(__isl_take isl_id *key,
+	__isl_take isl_ast_expr *val, void *user)
+{
+	isl_printer **p = user;
+
+	*p = ppcg_ast_expr_print_macros(val, *p);
+	isl_id_free(key);
+	isl_ast_expr_free(val);
+
+	if (!*p)
+		return isl_stat_error;
+	return isl_stat_ok;
+}
+
+/* Print the required macro definitions for the body of a statement in which
+ * the access expressions are replaced by the isl_ast_expr objects
+ * in "ref2expr".
+ */
+__isl_give isl_printer *ppcg_print_body_macros(__isl_take isl_printer *p,
+	__isl_keep isl_id_to_ast_expr *ref2expr)
+{
+	if (isl_id_to_ast_expr_foreach(ref2expr, &print_expr_macros, &p) < 0)
+		return isl_printer_free(p);
+	return p;
+}
+
+/* Print the required macros for "node".
+ */
+__isl_give isl_printer *ppcg_print_macros(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node)
+{
+	if (isl_ast_node_foreach_ast_op_type(node, &print_macro, &p) < 0)
+		return isl_printer_free(p);
+	return p;
+}
+
+/* Names used for the macros that may appear in a printed isl AST.
+ */
+const char *ppcg_min = "ppcg_min";
+const char *ppcg_max = "ppcg_max";
+const char *ppcg_fdiv_q = "ppcg_fdiv_q";
+
+/* Set the names of the macros that may appear in a printed isl AST.
+ */
+__isl_give isl_printer *ppcg_set_macro_names(__isl_take isl_printer *p)
+{
+	p = isl_ast_op_type_set_print_name(p, isl_ast_op_min, ppcg_min);
+	p = isl_ast_op_type_set_print_name(p, isl_ast_op_max, ppcg_max);
+	p = isl_ast_op_type_set_print_name(p, isl_ast_op_fdiv_q, ppcg_fdiv_q);
+
+	return p;
+}
+
+/* Given a multi affine expression "mpa" without domain, modify it to have
+ * the schedule space of "build" as domain.
+ *
+ * If the schedule space of "build" is a parameter space, then nothing
+ * needs to be done.
+ * Otherwise, "mpa" is first given a 0D domain and then it is combined
+ * with a mapping from the schedule space of "build" to the same 0D domain.
+ */
+__isl_give isl_multi_pw_aff *ppcg_attach_multi_pw_aff(
+	__isl_take isl_multi_pw_aff *mpa, __isl_keep isl_ast_build *build)
+{
+	isl_bool params;
+	isl_space *space;
+	isl_multi_aff *ma;
+
+	space = isl_ast_build_get_schedule_space(build);
+	params = isl_space_is_params(space);
+	if (params < 0 || params) {
+		isl_space_free(space);
+		if (params < 0)
+			return isl_multi_pw_aff_free(mpa);
+		return mpa;
+	}
+	space = isl_space_from_domain(space);
+	ma = isl_multi_aff_zero(space);
+	mpa = isl_multi_pw_aff_from_range(mpa);
+	mpa = isl_multi_pw_aff_pullback_multi_aff(mpa, ma);
+
+	return mpa;
+}
+
+/* Build an access AST expression from "size" using "build".
+ * "size" does not have a domain, but "build" may have a proper schedule space.
+ * First modify "size" to have that schedule space as domain.
+ */
+__isl_give isl_ast_expr *ppcg_build_size_expr(__isl_take isl_multi_pw_aff *size,
+	__isl_keep isl_ast_build *build)
+{
+	size = ppcg_attach_multi_pw_aff(size, build);
+	return isl_ast_build_access_from_multi_pw_aff(build, size);
+}
+
+/* Print a declaration for an array with element type "base_type" and
+ * size "size" to "p".
+ */
+__isl_give isl_printer *ppcg_print_declaration_with_size(
+	__isl_take isl_printer *p, const char *base_type,
+	__isl_keep isl_ast_expr *size)
+{
+	if (!base_type || !size)
+		return isl_printer_free(p);
+
+	p = ppcg_ast_expr_print_macros(size, p);
+	p = isl_printer_start_line(p);
+	p = isl_printer_print_str(p, base_type);
+	p = isl_printer_print_str(p, " ");
+	p = isl_printer_print_ast_expr(p, size);
+	p = isl_printer_print_str(p, ";");
+	p = isl_printer_end_line(p);
+
+	return p;
+}
+
+/* Print a declaration for array "array" to "p", using "build"
+ * to simplify any size expressions.
+ *
+ * The size is computed from the extent of the array and is
+ * subsequently converted to an "access expression" by "build".
+ */
+__isl_give isl_printer *ppcg_print_declaration(__isl_take isl_printer *p,
+	struct pet_array *array, __isl_keep isl_ast_build *build)
+{
+	isl_multi_pw_aff *size;
+	isl_ast_expr *expr;
+
+	if (!array)
+		return isl_printer_free(p);
+
+	size = ppcg_size_from_extent(isl_set_copy(array->extent));
+	expr = isl_ast_build_access_from_multi_pw_aff(build, size);
+	p = ppcg_print_declaration_with_size(p, array->element_type, expr);
+	isl_ast_expr_free(expr);
+
+	return p;
+}
+
+/* Print declarations for the arrays in "scop" that are declared
+ * and that are exposed (if exposed == 1) or not exposed (if exposed == 0).
+ */
+static __isl_give isl_printer *print_declarations(__isl_take isl_printer *p,
+	struct ppcg_scop *scop, int exposed)
+{
+	int i;
+	isl_ast_build *build;
+
+	if (!scop)
+		return isl_printer_free(p);
+
+	build = isl_ast_build_from_context(isl_set_copy(scop->context));
+	for (i = 0; i < scop->pet->n_array; ++i) {
+		struct pet_array *array = scop->pet->arrays[i];
+
+		if (!array->declared)
+			continue;
+		if (array->exposed != exposed)
+			continue;
+
+		p = ppcg_print_declaration(p, array, build);
+	}
+	isl_ast_build_free(build);
+
+	return p;
+}
+
+/* Print declarations for the arrays in "scop" that are declared
+ * and exposed to the code after the scop.
+ */
+__isl_give isl_printer *ppcg_print_exposed_declarations(
+	__isl_take isl_printer *p, struct ppcg_scop *scop)
+{
+	return print_declarations(p, scop, 1);
+}
+
+/* Print declarations for the arrays in "scop" that are declared,
+ * but not exposed to the code after the scop.
+ */
+__isl_give isl_printer *ppcg_print_hidden_declarations(
+	__isl_take isl_printer *p, struct ppcg_scop *scop)
+{
+	return print_declarations(p, scop, 0);
+}
diff --git a/final/lib/External/ppcg/print.h b/final/lib/External/ppcg/print.h
new file mode 100644
index 0000000..3b33b0c
--- /dev/null
+++ b/final/lib/External/ppcg/print.h
@@ -0,0 +1,40 @@
+#ifndef PRINT_H
+#define PRINT_H
+
+#include <isl/ast.h>
+
+#include "ppcg.h"
+
+extern const char *ppcg_min;
+extern const char *ppcg_max;
+extern const char *ppcg_fdiv_q;
+
+__isl_give isl_printer *ppcg_start_block(__isl_take isl_printer *p);
+__isl_give isl_printer *ppcg_end_block(__isl_take isl_printer *p);
+
+__isl_give isl_printer *ppcg_set_macro_names(__isl_take isl_printer *p);
+__isl_give isl_printer *ppcg_set_macros(__isl_take isl_printer *p,
+	const char *min, const char *max);
+__isl_give isl_printer *ppcg_print_macro(enum isl_ast_op_type type,
+	__isl_take isl_printer *p);
+__isl_give isl_printer *ppcg_ast_expr_print_macros(
+	__isl_keep isl_ast_expr *expr, __isl_take isl_printer *p);
+__isl_give isl_printer *ppcg_print_body_macros(__isl_take isl_printer *p,
+	__isl_keep isl_id_to_ast_expr *ref2expr);
+__isl_give isl_printer *ppcg_print_macros(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node);
+
+__isl_give isl_ast_expr *ppcg_build_size_expr(__isl_take isl_multi_pw_aff *size,
+	__isl_keep isl_ast_build *build);
+
+__isl_give isl_printer *ppcg_print_declaration_with_size(
+	__isl_take isl_printer *p, const char *base_type,
+	__isl_keep isl_ast_expr *size);
+__isl_give isl_printer *ppcg_print_declaration(__isl_take isl_printer *p,
+	struct pet_array *array, __isl_keep isl_ast_build *build);
+__isl_give isl_printer *ppcg_print_exposed_declarations(
+	__isl_take isl_printer *p, struct ppcg_scop *scop);
+__isl_give isl_printer *ppcg_print_hidden_declarations(
+	__isl_take isl_printer *p, struct ppcg_scop *scop);
+
+#endif
diff --git a/final/lib/External/ppcg/schedule.c b/final/lib/External/ppcg/schedule.c
new file mode 100644
index 0000000..7e65c31
--- /dev/null
+++ b/final/lib/External/ppcg/schedule.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2010-2011 INRIA Saclay
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/constraint.h>
+
+#include "schedule.h"
+
+/* Add parameters with identifiers "ids" to "set".
+ */
+static __isl_give isl_set *add_params(__isl_take isl_set *set,
+	__isl_keep isl_id_list *ids)
+{
+	int i, n;
+	unsigned nparam;
+
+	n = isl_id_list_n_id(ids);
+
+	nparam = isl_set_dim(set, isl_dim_param);
+	set = isl_set_add_dims(set, isl_dim_param, n);
+
+	for (i = 0; i < n; ++i) {
+		isl_id *id;
+
+		id = isl_id_list_get_id(ids, i);
+		set = isl_set_set_dim_id(set, isl_dim_param, nparam + i, id);
+	}
+
+	return set;
+}
+
+/* Equate the dimensions of "set" starting at "first" to
+ * freshly created parameters with identifiers "ids".
+ * The number of equated dimensions is equal to the number of elements in "ids".
+ */
+static __isl_give isl_set *parametrize(__isl_take isl_set *set,
+	int first, __isl_keep isl_id_list *ids)
+{
+	int i, n;
+	unsigned nparam;
+
+	nparam = isl_set_dim(set, isl_dim_param);
+
+	set = add_params(set, ids);
+
+	n = isl_id_list_n_id(ids);
+	for (i = 0; i < n; ++i)
+		set = isl_set_equate(set, isl_dim_param, nparam + i,
+					isl_dim_set, first + i);
+
+	return set;
+}
+
+/* Given a parameter space "space", create a set of dimension "len"
+ * of which the dimensions starting at "first" are equated to
+ * freshly created parameters with identifiers "ids".
+ */
+__isl_give isl_set *parametrization(__isl_take isl_space *space,
+	int len, int first, __isl_keep isl_id_list *ids)
+{
+	isl_set *set;
+
+	space = isl_space_set_from_params(space);
+	space = isl_space_add_dims(space, isl_dim_set, len);
+	set = isl_set_universe(space);
+
+	return parametrize(set, first, ids);
+}
+
+/* Load and return a schedule from a file called "filename".
+ */
+static __isl_give isl_schedule *load_schedule(isl_ctx *ctx,
+	const char *filename)
+{
+	FILE *file;
+	isl_schedule *schedule;
+
+	file = fopen(filename, "r");
+	if (!file) {
+		fprintf(stderr, "Unable to open '%s' for reading\n", filename);
+		return NULL;
+	}
+	schedule = isl_schedule_read_from_file(ctx, file);
+	fclose(file);
+
+	return schedule;
+}
+
+/* Save the schedule "schedule" to a file called "filename".
+ * The schedule is printed in block style.
+ */
+static void save_schedule(__isl_keep isl_schedule *schedule,
+	const char *filename)
+{
+	FILE *file;
+	isl_ctx *ctx;
+	isl_printer *p;
+
+	if (!schedule)
+		return;
+
+	file = fopen(filename, "w");
+	if (!file) {
+		fprintf(stderr, "Unable to open '%s' for writing\n", filename);
+		return;
+	}
+	ctx = isl_schedule_get_ctx(schedule);
+	p = isl_printer_to_file(ctx, file);
+	p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_BLOCK);
+	p = isl_printer_print_schedule(p, schedule);
+	isl_printer_free(p);
+	fclose(file);
+}
+
+/* Obtain a schedule, either by reading it form a file
+ * or by computing it using "compute".
+ * Also take care of saving the computed schedule and/or
+ * dumping the obtained schedule if requested by the user.
+ */
+__isl_give isl_schedule *ppcg_get_schedule(isl_ctx *ctx,
+	struct ppcg_options *options,
+	__isl_give isl_schedule *(*compute)(void *user), void *user)
+{
+	isl_schedule *schedule;
+
+	if (options->load_schedule_file) {
+		schedule = load_schedule(ctx, options->load_schedule_file);
+	} else {
+		schedule = compute(user);
+		if (options->save_schedule_file)
+			save_schedule(schedule, options->save_schedule_file);
+	}
+	if (options->debug->dump_schedule)
+		isl_schedule_dump(schedule);
+
+	return schedule;
+}
+
+/* Mark all dimensions in the band node "node" to be of "type".
+ */
+__isl_give isl_schedule_node *ppcg_set_schedule_node_type(
+	__isl_take isl_schedule_node *node, enum isl_ast_loop_type type)
+{
+	int i, n;
+
+	n = isl_schedule_node_band_n_member(node);
+	for (i = 0; i < n; ++i)
+		node = isl_schedule_node_band_member_set_ast_loop_type(node, i,
+							type);
+
+	return node;
+}
diff --git a/final/lib/External/ppcg/schedule.h b/final/lib/External/ppcg/schedule.h
new file mode 100644
index 0000000..7714665
--- /dev/null
+++ b/final/lib/External/ppcg/schedule.h
@@ -0,0 +1,21 @@
+#ifndef _SCHEDULE_H
+#define _SCHEDULE_H
+
+#include <isl/id.h>
+#include <isl/space.h>
+#include <isl/schedule.h>
+#include <isl/schedule_node.h>
+
+#include "ppcg_options.h"
+
+__isl_give isl_set *parametrization(__isl_take isl_space *space,
+	int len, int first, __isl_keep isl_id_list *names);
+
+__isl_give isl_schedule *ppcg_get_schedule(isl_ctx *ctx,
+	struct ppcg_options *options,
+	__isl_give isl_schedule *(*compute)(void *user), void *user);
+
+__isl_give isl_schedule_node *ppcg_set_schedule_node_type(
+	__isl_take isl_schedule_node *node, enum isl_ast_loop_type type);
+
+#endif
diff --git a/final/lib/External/ppcg/test-driver b/final/lib/External/ppcg/test-driver
new file mode 100755
index 0000000..d306056
--- /dev/null
+++ b/final/lib/External/ppcg/test-driver
@@ -0,0 +1,139 @@
+#! /bin/sh
+# test-driver - basic testsuite driver script.
+
+scriptversion=2013-07-13.22; # UTC
+
+# Copyright (C) 2011-2013 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+# Make unconditional expansion of undefined variables an error.  This
+# helps a lot in preventing typo-related bugs.
+set -u
+
+usage_error ()
+{
+  echo "$0: $*" >&2
+  print_usage >&2
+  exit 2
+}
+
+print_usage ()
+{
+  cat <<END
+Usage:
+  test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
+              [--expect-failure={yes|no}] [--color-tests={yes|no}]
+              [--enable-hard-errors={yes|no}] [--]
+              TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+END
+}
+
+test_name= # Used for reporting.
+log_file=  # Where to save the output of the test script.
+trs_file=  # Where to save the metadata of the test run.
+expect_failure=no
+color_tests=no
+enable_hard_errors=yes
+while test $# -gt 0; do
+  case $1 in
+  --help) print_usage; exit $?;;
+  --version) echo "test-driver $scriptversion"; exit $?;;
+  --test-name) test_name=$2; shift;;
+  --log-file) log_file=$2; shift;;
+  --trs-file) trs_file=$2; shift;;
+  --color-tests) color_tests=$2; shift;;
+  --expect-failure) expect_failure=$2; shift;;
+  --enable-hard-errors) enable_hard_errors=$2; shift;;
+  --) shift; break;;
+  -*) usage_error "invalid option: '$1'";;
+   *) break;;
+  esac
+  shift
+done
+
+missing_opts=
+test x"$test_name" = x && missing_opts="$missing_opts --test-name"
+test x"$log_file"  = x && missing_opts="$missing_opts --log-file"
+test x"$trs_file"  = x && missing_opts="$missing_opts --trs-file"
+if test x"$missing_opts" != x; then
+  usage_error "the following mandatory options are missing:$missing_opts"
+fi
+
+if test $# -eq 0; then
+  usage_error "missing argument"
+fi
+
+if test $color_tests = yes; then
+  # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
+  red='' # Red.
+  grn='' # Green.
+  lgn='' # Light green.
+  blu='' # Blue.
+  mgn='' # Magenta.
+  std=''     # No color.
+else
+  red= grn= lgn= blu= mgn= std=
+fi
+
+do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
+trap "st=129; $do_exit" 1
+trap "st=130; $do_exit" 2
+trap "st=141; $do_exit" 13
+trap "st=143; $do_exit" 15
+
+# Test script is run here.
+"$@" >$log_file 2>&1
+estatus=$?
+if test $enable_hard_errors = no && test $estatus -eq 99; then
+  estatus=1
+fi
+
+case $estatus:$expect_failure in
+  0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
+  0:*)   col=$grn res=PASS  recheck=no  gcopy=no;;
+  77:*)  col=$blu res=SKIP  recheck=no  gcopy=yes;;
+  99:*)  col=$mgn res=ERROR recheck=yes gcopy=yes;;
+  *:yes) col=$lgn res=XFAIL recheck=no  gcopy=yes;;
+  *:*)   col=$red res=FAIL  recheck=yes gcopy=yes;;
+esac
+
+# Report outcome to console.
+echo "${col}${res}${std}: $test_name"
+
+# Register the test result, and other relevant metadata.
+echo ":test-result: $res" > $trs_file
+echo ":global-test-result: $res" >> $trs_file
+echo ":recheck: $recheck" >> $trs_file
+echo ":copy-in-global-log: $gcopy" >> $trs_file
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/final/lib/External/ppcg/tests/allow-sparse-copy-in.c b/final/lib/External/ppcg/tests/allow-sparse-copy-in.c
new file mode 100644
index 0000000..620d825
--- /dev/null
+++ b/final/lib/External/ppcg/tests/allow-sparse-copy-in.c
@@ -0,0 +1,49 @@
+#include <stdlib.h>
+
+int main()
+{
+	int A[2][1000][1000];
+	int B[2][1000][1000];
+
+#pragma scop
+	{
+		for (int i = 0; i < 256; ++i)
+			for (int j = 0; j < 256; ++j)
+				if (j % 8 <= 2 || j % 8 >= 6)
+					A[1][i][j] = B[1][j][i];
+	}
+#pragma endscop
+
+/* 
+
+When compiled with:
+
+./ppcg tests/allow-sparse-copy-in.c --no-linearize-device-arrays
+	--on-error=abort --sizes='{kernel[i]->tile[8,8]; kernel[i]->block[1,8]}'
+	--max-shared-memory=-1  --unroll-copy-shared
+
+this originally resulted in the following copy-in code:
+
+      shared_B[0][0][t1] = B[1][8 * b1][8 * b0 + t1];
+      shared_B[0][1][t1] = B[1][8 * b1 + 1][8 * b0 + t1];
+      shared_B[0][2][t1] = B[1][8 * b1 + 2][8 * b0 + t1];
+      shared_B[0][3][t1] = B[1][8 * b1 + 3][8 * b0 + t1];
+      shared_B[0][4][t1] = B[1][8 * b1 + 4][8 * b0 + t1];
+      shared_B[0][5][t1] = B[1][8 * b1 + 5][8 * b0 + t1];
+      shared_B[0][6][t1] = B[1][8 * b1 + 6][8 * b0 + t1];
+      shared_B[0][7][t1] = B[1][8 * b1 + 7][8 * b0 + t1];
+
+whereas we only want to only perform copies that are actually needed:
+
+      shared_B[0][0][t1] = B[1][8 * b1][8 * b0 + t1];
+      shared_B[0][1][t1] = B[1][8 * b1 + 1][8 * b0 + t1];
+      shared_B[0][2][t1] = B[1][8 * b1 + 2][8 * b0 + t1];
+      shared_B[0][6][t1] = B[1][8 * b1 + 6][8 * b0 + t1];
+      shared_B[0][7][t1] = B[1][8 * b1 + 7][8 * b0 + t1];
+*/
+	for (int i = 0; i < 100; ++i)
+		if (A[1][0][i] != i)
+			return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/call.c b/final/lib/External/ppcg/tests/call.c
new file mode 100644
index 0000000..7f4f7c4
--- /dev/null
+++ b/final/lib/External/ppcg/tests/call.c
@@ -0,0 +1,29 @@
+#include <stdlib.h>
+
+void copy_summary(int b[1000], int a[1000], int pos)
+{
+	b[pos] = 0;
+	int c = a[pos];
+}
+
+#ifdef pencil_access
+__attribute__((pencil_access(copy_summary)))
+#endif
+void copy(int b[1000], int a[1000], int pos);
+
+int main()
+{
+	int a[1000], b[1000];
+
+	for (int i = 0; i < 1000; ++i)
+		a[i] = i;
+#pragma scop
+	for (int i = 0; i < 1000; ++i)
+		copy(b, a, i);
+#pragma endscop
+	for (int i = 0; i < 1000; ++i)
+		if (b[i] != a[i])
+			return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/call2.c b/final/lib/External/ppcg/tests/call2.c
new file mode 100644
index 0000000..1cfc85c
--- /dev/null
+++ b/final/lib/External/ppcg/tests/call2.c
@@ -0,0 +1,29 @@
+#include <stdlib.h>
+
+void copy_summary(int b[1000], int a[1000], int pos)
+{
+	b[pos] = 0;
+	int c = a[pos];
+}
+
+#ifdef pencil_access
+__attribute__((pencil_access(copy_summary)))
+#endif
+void copy(int b[1000], int a[1000], int pos);
+
+int main()
+{
+	int a[2][1000];
+
+	for (int i = 0; i < 1000; ++i)
+		a[0][i] = i;
+#pragma scop
+	for (int i = 0; i < 1000; ++i)
+		copy(a[1], a[0], i);
+#pragma endscop
+	for (int i = 0; i < 1000; ++i)
+		if (a[1][i] != a[0][i])
+			return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/call2_opencl_functions.cl b/final/lib/External/ppcg/tests/call2_opencl_functions.cl
new file mode 100644
index 0000000..6f72aea
--- /dev/null
+++ b/final/lib/External/ppcg/tests/call2_opencl_functions.cl
@@ -0,0 +1,4 @@
+void copy(__global int b[1000], __global int a[1000], int pos)
+{
+	b[pos] = a[pos];
+}
diff --git a/final/lib/External/ppcg/tests/call3.c b/final/lib/External/ppcg/tests/call3.c
new file mode 100644
index 0000000..51b1e29
--- /dev/null
+++ b/final/lib/External/ppcg/tests/call3.c
@@ -0,0 +1,32 @@
+#include <stdlib.h>
+
+void copy_summary(int b[100], int a[100])
+{
+	for (int i = 0; i < 100; ++i) {
+		b[i] = 0;
+		int c = a[i];
+	}
+}
+
+#ifdef pencil_access
+__attribute__((pencil_access(copy_summary)))
+#endif
+void copy(int b[100], int a[100]);
+
+int main()
+{
+	int A[100][100], B[100];
+
+	for (int i = 0; i < 100; ++i)
+		B[i] = i;
+#pragma scop
+	for (int i = 0; i < 100; ++i)
+		copy(A[i], B);
+#pragma endscop
+	for (int i = 0; i < 100; ++i)
+		for (int j = 0; j < 100; ++j)
+			if (A[j][i] != B[i])
+				return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/call3_opencl_functions.cl b/final/lib/External/ppcg/tests/call3_opencl_functions.cl
new file mode 100644
index 0000000..35c87a7
--- /dev/null
+++ b/final/lib/External/ppcg/tests/call3_opencl_functions.cl
@@ -0,0 +1,5 @@
+void copy(__global int b[100], __global int a[100])
+{
+	for (int i = 0; i < 100; ++i)
+		b[i] = a[i];
+}
diff --git a/final/lib/External/ppcg/tests/call_opencl_functions.cl b/final/lib/External/ppcg/tests/call_opencl_functions.cl
new file mode 100644
index 0000000..6f72aea
--- /dev/null
+++ b/final/lib/External/ppcg/tests/call_opencl_functions.cl
@@ -0,0 +1,4 @@
+void copy(__global int b[1000], __global int a[1000], int pos)
+{
+	b[pos] = a[pos];
+}
diff --git a/final/lib/External/ppcg/tests/dead.c b/final/lib/External/ppcg/tests/dead.c
new file mode 100644
index 0000000..3f70a33
--- /dev/null
+++ b/final/lib/External/ppcg/tests/dead.c
@@ -0,0 +1,23 @@
+#include <stdlib.h>
+
+int main()
+{
+	int a[1000], b[1000];
+
+	for (int i = 0; i < 1000; ++i)
+		a[i] = i;
+#pragma scop
+	for (int i = 0; i < 1000; ++i) {
+		int c;
+		int d;
+		c = a[i];
+		d = c;
+		b[i] = c;
+	}
+#pragma endscop
+	for (int i = 0; i < 1000; ++i)
+		if (b[i] != a[i])
+			return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/iterator.c b/final/lib/External/ppcg/tests/iterator.c
new file mode 100644
index 0000000..651f530
--- /dev/null
+++ b/final/lib/External/ppcg/tests/iterator.c
@@ -0,0 +1,18 @@
+#include <stdlib.h>
+
+int main()
+{
+	int i;
+	int a[101];
+
+	i = 0;
+#pragma scop
+	for (i = 0; i < 100; ++i)
+		a[i] = i;
+	a[i] = i;
+#pragma endscop
+	if (a[100] != 100)
+		return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/live_out.c b/final/lib/External/ppcg/tests/live_out.c
new file mode 100644
index 0000000..c13965e
--- /dev/null
+++ b/final/lib/External/ppcg/tests/live_out.c
@@ -0,0 +1,22 @@
+#include <stdlib.h>
+
+/* Check that a write access is not removed from the live-out
+ * accesses only because a strict subset of the (potentially)
+ * accessed elements are killed by a later write.
+ */
+int main()
+{
+	int A[10];
+
+	A[1] = 0;
+#pragma scop
+	int i = 1;
+	i = i * i;
+	A[i] = 1;
+	A[0] = 0;
+#pragma endscop
+	if (A[1] != 1)
+		return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/local.c b/final/lib/External/ppcg/tests/local.c
new file mode 100644
index 0000000..e8b3894
--- /dev/null
+++ b/final/lib/External/ppcg/tests/local.c
@@ -0,0 +1,22 @@
+#include <stdlib.h>
+
+int main()
+{
+	int A[100];
+
+#pragma scop
+	{
+		int B[100];
+		B[0] = 0;
+		for (int i = 1; i < 100; ++i)
+			B[i] = B[i - 1] + 1;
+		for (int i = 0; i < 100; ++i)
+			A[i] = B[i];
+	}
+#pragma endscop
+	for (int i = 0; i < 100; ++i)
+		if (A[i] != i)
+			return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/loop.c b/final/lib/External/ppcg/tests/loop.c
new file mode 100644
index 0000000..910425b
--- /dev/null
+++ b/final/lib/External/ppcg/tests/loop.c
@@ -0,0 +1,18 @@
+#include <stdlib.h>
+
+int main()
+{
+	int a[1000], b[1000];
+
+	for (int i = 0; i < 1000; ++i)
+		a[i] = i;
+#pragma scop
+	for (int i = 0; i < 1000; ++i)
+		b[i] = a[i];
+#pragma endscop
+	for (int i = 0; i < 1000; ++i)
+		if (b[i] != a[i])
+			return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/not_accessed.c b/final/lib/External/ppcg/tests/not_accessed.c
new file mode 100644
index 0000000..e5fb892
--- /dev/null
+++ b/final/lib/External/ppcg/tests/not_accessed.c
@@ -0,0 +1,29 @@
+#include <stdlib.h>
+
+void copy_summary(int b[1000], int a[1000], int pos, int c[1000])
+{
+	b[pos] = 0;
+	int d = a[pos];
+}
+
+#ifdef pencil_access
+__attribute__((pencil_access(copy_summary)))
+#endif
+void copy(int b[1000], int a[1000], int pos, int c[1000]);
+
+int main()
+{
+	int a[1000], b[1000], c[1000];
+
+	for (int i = 0; i < 1000; ++i)
+		a[i] = i;
+#pragma scop
+	for (int i = 0; i < 1000; ++i)
+		copy(b, a, i, c);
+#pragma endscop
+	for (int i = 0; i < 1000; ++i)
+		if (b[i] != a[i])
+			return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/not_accessed_opencl_functions.cl b/final/lib/External/ppcg/tests/not_accessed_opencl_functions.cl
new file mode 100644
index 0000000..e1588e0
--- /dev/null
+++ b/final/lib/External/ppcg/tests/not_accessed_opencl_functions.cl
@@ -0,0 +1,5 @@
+void copy(__global int b[1000], __global int a[1000], int pos,
+	__global int c[1000])
+{
+	b[pos] = a[pos];
+}
diff --git a/final/lib/External/ppcg/tests/scalar.c b/final/lib/External/ppcg/tests/scalar.c
new file mode 100644
index 0000000..ffd7797
--- /dev/null
+++ b/final/lib/External/ppcg/tests/scalar.c
@@ -0,0 +1,13 @@
+#include <stdlib.h>
+
+int main()
+{
+	int a;
+#pragma scop
+	a = 1;
+#pragma endscop
+	if (a != 1)
+		return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/shared_sink.c b/final/lib/External/ppcg/tests/shared_sink.c
new file mode 100644
index 0000000..ae3fac2
--- /dev/null
+++ b/final/lib/External/ppcg/tests/shared_sink.c
@@ -0,0 +1,25 @@
+#include <stdlib.h>
+
+/* Check that the sources of live ranges with the same sink
+ * are executed in order.
+ */
+int main()
+{
+	int A[128];
+	int n = 128;
+
+	A[0] = 0;
+#pragma scop
+	for (int i = 0; i < n; ++i) {
+		int set = 0;
+		if (A[i] < 2)
+			set = 1;
+		if (set)
+			A[i] = 2;
+	}
+#pragma endscop
+	if (A[0] != 2)
+		return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/struct.c b/final/lib/External/ppcg/tests/struct.c
new file mode 100644
index 0000000..c67b7bd
--- /dev/null
+++ b/final/lib/External/ppcg/tests/struct.c
@@ -0,0 +1,31 @@
+#include <stdlib.h>
+
+struct s {
+	int c[10][10];
+};
+
+int main()
+{
+	struct s a[10][10], b[10][10];
+
+	for (int i = 0; i < 10; ++i)
+		for (int j = 0; j < 10; ++j)
+			for (int k = 0; k < 10; ++k)
+				for (int l = 0; l < 10; ++l)
+					a[i][j].c[k][l] = i + j + k + l;
+#pragma scop
+	for (int i = 0; i < 10; ++i)
+		for (int j = 0; j < 10; ++j)
+			for (int k = 0; k < 10; ++k)
+				for (int l = 0; l < 10; ++l)
+					b[i][j].c[k][l] = i + j + k + l;
+#pragma endscop
+	for (int i = 0; i < 10; ++i)
+		for (int j = 0; j < 10; ++j)
+			for (int k = 0; k < 10; ++k)
+				for (int l = 0; l < 10; ++l)
+					if (b[i][j].c[k][l] != a[i][j].c[k][l])
+						return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/struct2.c b/final/lib/External/ppcg/tests/struct2.c
new file mode 100644
index 0000000..d7d6a9f
--- /dev/null
+++ b/final/lib/External/ppcg/tests/struct2.c
@@ -0,0 +1,21 @@
+#include <stdlib.h>
+
+struct s {
+	int a;
+};
+
+int main()
+{
+	struct s a, b[10];
+
+#pragma scop
+	a.a = 42;
+	for (int i = 0; i < 10; ++i)
+		b[i].a = a.a;
+#pragma endscop
+	for (int i = 0; i < 10; ++i)
+		if (b[i].a != 42)
+			return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/struct3.c b/final/lib/External/ppcg/tests/struct3.c
new file mode 100644
index 0000000..de383b6
--- /dev/null
+++ b/final/lib/External/ppcg/tests/struct3.c
@@ -0,0 +1,25 @@
+#include <stdlib.h>
+
+struct s {
+	int a;
+	int b;
+};
+
+int main()
+{
+	struct s a, b[10];
+
+	a.b = 57;
+#pragma scop
+	a.a = 42;
+	for (int i = 0; i < 10; ++i)
+		b[i] = a;
+#pragma endscop
+	for (int i = 0; i < 10; ++i)
+		if (b[i].a != 42)
+			return EXIT_FAILURE;
+	if (a.b != 57)
+		return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/tests/struct4.c b/final/lib/External/ppcg/tests/struct4.c
new file mode 100644
index 0000000..d249ff4
--- /dev/null
+++ b/final/lib/External/ppcg/tests/struct4.c
@@ -0,0 +1,27 @@
+#include <stdlib.h>
+
+struct s {
+	int a;
+	int b;
+};
+
+int main()
+{
+	int a[10];
+
+	for (int i = 0; i < 10; ++i)
+		a[i] = 0;
+#pragma scop
+	for (int i = 0; i < 10; ++i) {
+		struct s b;
+		b.a = 1;
+		b.b = i;
+		a[i] = b.a + b.b;
+	}
+#pragma endscop
+	for (int i = 0; i < 10; ++i)
+		if (a[i] != 1 + i)
+			return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/final/lib/External/ppcg/util.c b/final/lib/External/ppcg/util.c
new file mode 100644
index 0000000..0a67bc3
--- /dev/null
+++ b/final/lib/External/ppcg/util.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2012-2013 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the MIT license
+ *
+ * Written by Sven Verdoolaege,
+ * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
+ */
+
+#include <isl/space.h>
+#include <isl/val.h>
+#include <isl/aff.h>
+#include <isl/set.h>
+
+#include "util.h"
+
+/* Construct an isl_multi_val living in "space" with all values equal to "val".
+ */
+__isl_give isl_multi_val *ppcg_multi_val_from_int(__isl_take isl_space *space,
+	int val)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_val *v;
+	isl_multi_val *mv;
+
+	if (!space)
+		return NULL;
+
+	ctx = isl_space_get_ctx(space);
+	n = isl_space_dim(space, isl_dim_set);
+	mv = isl_multi_val_zero(space);
+	v = isl_val_int_from_si(ctx, val);
+	for (i = 0; i < n; ++i)
+		mv = isl_multi_val_set_val(mv, i, isl_val_copy(v));
+	isl_val_free(v);
+
+	return mv;
+}
+
+/* Construct an isl_multi_val living in "space" with values specified
+ * by "list".  "list" is assumed to have at least as many entries
+ * as the set dimension of "space".
+ */
+__isl_give isl_multi_val *ppcg_multi_val_from_int_list(
+	__isl_take isl_space *space, int *list)
+{
+	int i, n;
+	isl_ctx *ctx;
+	isl_multi_val *mv;
+
+	if (!space)
+		return NULL;
+
+	ctx = isl_space_get_ctx(space);
+	n = isl_space_dim(space, isl_dim_set);
+	mv = isl_multi_val_zero(space);
+	for (i = 0; i < n; ++i) {
+		isl_val *v;
+
+		v = isl_val_int_from_si(ctx, list[i]);
+		mv = isl_multi_val_set_val(mv, i, v);
+	}
+
+	return mv;
+}
+
+/* Compute the size of a bounding box around the origin and "set",
+ * where "set" is assumed to contain only non-negative elements.
+ * In particular, compute the maximal value of "set" in each direction
+ * and add one.
+ */
+__isl_give isl_multi_pw_aff *ppcg_size_from_extent(__isl_take isl_set *set)
+{
+	int i, n;
+	isl_multi_pw_aff *mpa;
+
+	n = isl_set_dim(set, isl_dim_set);
+	mpa = isl_multi_pw_aff_zero(isl_set_get_space(set));
+	for (i = 0; i < n; ++i) {
+		isl_space *space;
+		isl_aff *one;
+		isl_pw_aff *bound;
+
+		if (!isl_set_dim_has_upper_bound(set, isl_dim_set, i)) {
+			const char *name;
+			name = isl_set_get_tuple_name(set);
+			if (!name)
+				name = "";
+			fprintf(stderr, "unable to determine extent of '%s' "
+				"in dimension %d\n", name, i);
+			set = isl_set_free(set);
+		}
+		bound = isl_set_dim_max(isl_set_copy(set), i);
+
+		space = isl_pw_aff_get_domain_space(bound);
+		one = isl_aff_zero_on_domain(isl_local_space_from_space(space));
+		one = isl_aff_add_constant_si(one, 1);
+		bound = isl_pw_aff_add(bound, isl_pw_aff_from_aff(one));
+		mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, bound);
+	}
+	isl_set_free(set);
+
+	return mpa;
+}
diff --git a/final/lib/External/ppcg/util.h b/final/lib/External/ppcg/util.h
new file mode 100644
index 0000000..544d6ed
--- /dev/null
+++ b/final/lib/External/ppcg/util.h
@@ -0,0 +1,22 @@
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <string.h>
+
+#include <isl/space.h>
+#include <isl/val.h>
+
+/* Compare the prefix of "s" to "prefix" up to the length of "prefix".
+ */
+static inline int prefixcmp(const char *s, const char *prefix)
+{
+	return strncmp(s, prefix, strlen(prefix));
+}
+
+__isl_give isl_multi_val *ppcg_multi_val_from_int(__isl_take isl_space *space,
+	int val);
+__isl_give isl_multi_val *ppcg_multi_val_from_int_list(
+	__isl_take isl_space *space, int *list);
+__isl_give isl_multi_pw_aff *ppcg_size_from_extent(__isl_take isl_set *set);
+
+#endif
diff --git a/final/lib/External/ppcg/version.c b/final/lib/External/ppcg/version.c
new file mode 100644
index 0000000..cc19514
--- /dev/null
+++ b/final/lib/External/ppcg/version.c
@@ -0,0 +1,6 @@
+#include "gitversion.h"
+
+const char *ppcg_version(void)
+{
+	return GIT_HEAD_ID"\n";
+}
diff --git a/final/lib/External/update-isl.sh b/final/lib/External/update-isl.sh
new file mode 100755
index 0000000..5b78f7e
--- /dev/null
+++ b/final/lib/External/update-isl.sh
@@ -0,0 +1,33 @@
+#! /bin/sh
+set -e
+
+# Replace the content of the isl directory with a fresh clone from
+# http://repo.or.cz/isl.git
+
+SCRIPTPATH=`realpath --no-symlinks $(dirname $0)`
+ISL_SOURCE_DIR="${SCRIPTPATH}/isl"
+
+TMPDIR=`mktemp -d --tmpdir isl-XXX`
+GITDIR=$TMPDIR/src
+BUILDDIR=$TMPDIR/build
+
+git clone --recursive http://repo.or.cz/isl.git $GITDIR
+if [ -n "$1" ]; then
+  (cd $GITDIR && git checkout $1)
+  (cd $GITDIR && git submodule update --recursive)
+fi
+(cd $GITDIR && ./autogen.sh)
+mkdir -p $BUILDDIR
+(cd $BUILDDIR && $GITDIR/configure --with-int=imath-32)
+(cd $BUILDDIR && make dist)
+
+for DISTFILE in "$BUILDDIR/isl*.tar.gz"; do break; done
+
+cp $ISL_SOURCE_DIR/include/isl-noexceptions.h $TMPDIR/isl-noexceptions.h
+
+rm -rf $ISL_SOURCE_DIR
+mkdir -p $ISL_SOURCE_DIR
+tar -xf $DISTFILE --strip-components=1 --directory $ISL_SOURCE_DIR
+cp $TMPDIR/isl/isl-noexceptions.h $ISL_SOURCE_DIR/include/isl
+
+rm -rf $TMPDIR
diff --git a/final/lib/Polly.cpp b/final/lib/Polly.cpp
new file mode 100644
index 0000000..95903ab
--- /dev/null
+++ b/final/lib/Polly.cpp
@@ -0,0 +1,30 @@
+//===---------- Polly.cpp - Initialize the Polly Module -------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/RegisterPasses.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+
+namespace {
+
+/// Initialize Polly passes when library is loaded.
+///
+/// We use the constructor of a statically declared object to initialize the
+/// different Polly passes right after the Polly library is loaded. This ensures
+/// that the Polly passes are available e.g. in the 'opt' tool.
+class StaticInitializer {
+public:
+  StaticInitializer() {
+    llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
+    polly::initializePollyPasses(Registry);
+  }
+};
+static StaticInitializer InitializeEverything;
+} // end of anonymous namespace.
diff --git a/final/lib/Support/DumpModulePass.cpp b/final/lib/Support/DumpModulePass.cpp
new file mode 100644
index 0000000..77ad717
--- /dev/null
+++ b/final/lib/Support/DumpModulePass.cpp
@@ -0,0 +1,95 @@
+//===------ DumpModulePass.cpp ----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Write a module to a file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/Support/DumpModulePass.h"
+
+#include "polly/Options.h"
+#include "llvm/IR/LegacyPassManagers.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include <string.h>
+#define DEBUG_TYPE "polly-dump-module"
+
+using namespace llvm;
+using namespace polly;
+
+namespace {
+
+class DumpModule : public ModulePass {
+private:
+  DumpModule(const DumpModule &) = delete;
+  const DumpModule &operator=(const DumpModule &) = delete;
+
+  std::string Filename;
+  bool IsSuffix;
+
+public:
+  static char ID;
+
+  /// This constructor is used e.g. if using opt -polly-dump-module.
+  ///
+  /// Provide a default suffix to not overwrite the original file.
+  explicit DumpModule() : ModulePass(ID), Filename("-dump"), IsSuffix(true) {}
+
+  explicit DumpModule(llvm::StringRef Filename, bool IsSuffix)
+      : ModulePass(ID), Filename(Filename), IsSuffix(IsSuffix) {}
+
+  /// @name ModulePass interface
+  //@{
+  virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+    AU.setPreservesAll();
+  }
+
+  virtual bool runOnModule(llvm::Module &M) override {
+    std::string Dumpfile;
+    if (IsSuffix) {
+      auto ModuleName = M.getName();
+      auto Stem = sys::path::stem(ModuleName);
+      Dumpfile = (Twine(Stem) + Filename + ".ll").str();
+    } else {
+      Dumpfile = Filename;
+    }
+    DEBUG(dbgs() << "Dumping module to " << Dumpfile << '\n');
+
+    std::unique_ptr<ToolOutputFile> Out;
+    std::error_code EC;
+    Out.reset(new ToolOutputFile(Dumpfile, EC, sys::fs::F_None));
+    if (EC) {
+      errs() << EC.message() << '\n';
+      return false;
+    }
+
+    M.print(Out->os(), nullptr);
+    Out->keep();
+
+    return false;
+  }
+  //@}
+};
+
+char DumpModule::ID;
+} // namespace
+
+ModulePass *polly::createDumpModulePass(llvm::StringRef Filename,
+                                        bool IsSuffix) {
+  return new DumpModule(Filename, IsSuffix);
+}
+
+INITIALIZE_PASS_BEGIN(DumpModule, "polly-dump-module", "Polly - Dump Module",
+                      false, false)
+INITIALIZE_PASS_END(DumpModule, "polly-dump-module", "Polly - Dump Module",
+                    false, false)
diff --git a/final/lib/Support/GICHelper.cpp b/final/lib/Support/GICHelper.cpp
new file mode 100644
index 0000000..aec10ff
--- /dev/null
+++ b/final/lib/Support/GICHelper.cpp
@@ -0,0 +1,282 @@
+//===- GmpConv.cpp - Recreate LLVM IR from the Scop.  ---------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Functions for converting between gmp objects and llvm::APInt.
+//
+//===----------------------------------------------------------------------===//
+#include "polly/Support/GICHelper.h"
+#include "llvm/IR/Value.h"
+#include "isl/aff.h"
+#include "isl/map.h"
+#include "isl/schedule.h"
+#include "isl/set.h"
+#include "isl/space.h"
+#include "isl/union_map.h"
+#include "isl/union_set.h"
+#include "isl/val.h"
+
+#include <climits>
+
+using namespace llvm;
+
+__isl_give isl_val *polly::isl_valFromAPInt(isl_ctx *Ctx, const APInt Int,
+                                            bool IsSigned) {
+  APInt Abs;
+  isl_val *v;
+
+  // As isl is interpreting the input always as unsigned value, we need some
+  // additional pre and post processing to import signed values. The approach
+  // we take is to first obtain the absolute value of Int and then negate the
+  // value after it has been imported to isl.
+  //
+  // It should be noted that the smallest integer value represented in two's
+  // complement with a certain amount of bits does not have a corresponding
+  // positive representation in two's complement representation with the same
+  // number of bits. E.g. 110 (-2) does not have a corresponding value for (2).
+  // To ensure that there is always a corresponding value available we first
+  // sign-extend the input by one bit and only then take the absolute value.
+  if (IsSigned)
+    Abs = Int.sext(Int.getBitWidth() + 1).abs();
+  else
+    Abs = Int;
+
+  const uint64_t *Data = Abs.getRawData();
+  unsigned Words = Abs.getNumWords();
+
+  v = isl_val_int_from_chunks(Ctx, Words, sizeof(uint64_t), Data);
+
+  if (IsSigned && Int.isNegative())
+    v = isl_val_neg(v);
+
+  return v;
+}
+
+APInt polly::APIntFromVal(__isl_take isl_val *Val) {
+  uint64_t *Data;
+  int NumChunks;
+  const static int ChunkSize = sizeof(uint64_t);
+
+  assert(isl_val_is_int(Val) && "Only integers can be converted to APInt");
+
+  NumChunks = isl_val_n_abs_num_chunks(Val, ChunkSize);
+  Data = (uint64_t *)malloc(NumChunks * ChunkSize);
+  isl_val_get_abs_num_chunks(Val, ChunkSize, Data);
+  int NumBits = CHAR_BIT * ChunkSize * NumChunks;
+  APInt A(NumBits, NumChunks, Data);
+
+  // As isl provides only an interface to obtain data that describes the
+  // absolute value of an isl_val, A at this point always contains a positive
+  // number. In case Val was originally negative, we expand the size of A by
+  // one and negate the value (in two's complement representation). As a result,
+  // the new value in A corresponds now with Val.
+  if (isl_val_is_neg(Val)) {
+    A = A.zext(A.getBitWidth() + 1);
+    A = -A;
+  }
+
+  // isl may represent small numbers with more than the minimal number of bits.
+  // We truncate the APInt to the minimal number of bits needed to represent the
+  // signed value it contains, to ensure that the bitwidth is always minimal.
+  if (A.getMinSignedBits() < A.getBitWidth())
+    A = A.trunc(A.getMinSignedBits());
+
+  free(Data);
+  isl_val_free(Val);
+  return A;
+}
+
+template <typename ISLTy, typename ISL_CTX_GETTER, typename ISL_PRINTER>
+static inline std::string stringFromIslObjInternal(__isl_keep ISLTy *isl_obj,
+                                                   ISL_CTX_GETTER ctx_getter_fn,
+                                                   ISL_PRINTER printer_fn) {
+  if (!isl_obj)
+    return "null";
+  isl_ctx *ctx = ctx_getter_fn(isl_obj);
+  isl_printer *p = isl_printer_to_str(ctx);
+  p = printer_fn(p, isl_obj);
+  char *char_str = isl_printer_get_str(p);
+  std::string string;
+  if (char_str)
+    string = char_str;
+  else
+    string = "null";
+  free(char_str);
+  isl_printer_free(p);
+  return string;
+}
+
+std::string polly::stringFromIslObj(__isl_keep isl_map *map) {
+  return stringFromIslObjInternal(map, isl_map_get_ctx, isl_printer_print_map);
+}
+
+std::string polly::stringFromIslObj(__isl_keep isl_set *set) {
+  return stringFromIslObjInternal(set, isl_set_get_ctx, isl_printer_print_set);
+}
+
+std::string polly::stringFromIslObj(__isl_keep isl_union_map *umap) {
+  return stringFromIslObjInternal(umap, isl_union_map_get_ctx,
+                                  isl_printer_print_union_map);
+}
+
+std::string polly::stringFromIslObj(__isl_keep isl_union_set *uset) {
+  return stringFromIslObjInternal(uset, isl_union_set_get_ctx,
+                                  isl_printer_print_union_set);
+}
+
+std::string polly::stringFromIslObj(__isl_keep isl_schedule *schedule) {
+  return stringFromIslObjInternal(schedule, isl_schedule_get_ctx,
+                                  isl_printer_print_schedule);
+}
+
+std::string polly::stringFromIslObj(__isl_keep isl_multi_aff *maff) {
+  return stringFromIslObjInternal(maff, isl_multi_aff_get_ctx,
+                                  isl_printer_print_multi_aff);
+}
+
+std::string polly::stringFromIslObj(__isl_keep isl_pw_multi_aff *pma) {
+  return stringFromIslObjInternal(pma, isl_pw_multi_aff_get_ctx,
+                                  isl_printer_print_pw_multi_aff);
+}
+
+std::string polly::stringFromIslObj(__isl_keep isl_multi_pw_aff *mpa) {
+  return stringFromIslObjInternal(mpa, isl_multi_pw_aff_get_ctx,
+                                  isl_printer_print_multi_pw_aff);
+}
+
+std::string polly::stringFromIslObj(__isl_keep isl_union_pw_multi_aff *upma) {
+  return stringFromIslObjInternal(upma, isl_union_pw_multi_aff_get_ctx,
+                                  isl_printer_print_union_pw_multi_aff);
+}
+
+std::string polly::stringFromIslObj(__isl_keep isl_aff *aff) {
+  return stringFromIslObjInternal(aff, isl_aff_get_ctx, isl_printer_print_aff);
+}
+
+std::string polly::stringFromIslObj(__isl_keep isl_pw_aff *pwaff) {
+  return stringFromIslObjInternal(pwaff, isl_pw_aff_get_ctx,
+                                  isl_printer_print_pw_aff);
+}
+
+std::string polly::stringFromIslObj(__isl_keep isl_space *space) {
+  return stringFromIslObjInternal(space, isl_space_get_ctx,
+                                  isl_printer_print_space);
+}
+
+static void replace(std::string &str, const std::string &find,
+                    const std::string &replace) {
+  size_t pos = 0;
+  while ((pos = str.find(find, pos)) != std::string::npos) {
+    str.replace(pos, find.length(), replace);
+    pos += replace.length();
+  }
+}
+
+static void makeIslCompatible(std::string &str) {
+  replace(str, ".", "_");
+  replace(str, "\"", "_");
+  replace(str, " ", "__");
+  replace(str, "=>", "TO");
+  replace(str, "+", "_");
+}
+
+std::string polly::getIslCompatibleName(const std::string &Prefix,
+                                        const std::string &Middle,
+                                        const std::string &Suffix) {
+  std::string S = Prefix + Middle + Suffix;
+  makeIslCompatible(S);
+  return S;
+}
+
+std::string polly::getIslCompatibleName(const std::string &Prefix,
+                                        const std::string &Name, long Number,
+                                        const std::string &Suffix,
+                                        bool UseInstructionNames) {
+  std::string S = Prefix;
+
+  if (UseInstructionNames)
+    S += std::string("_") + Name;
+  else
+    S += std::to_string(Number);
+
+  S += Suffix;
+
+  makeIslCompatible(S);
+  return S;
+}
+
+std::string polly::getIslCompatibleName(const std::string &Prefix,
+                                        const Value *Val, long Number,
+                                        const std::string &Suffix,
+                                        bool UseInstructionNames) {
+  std::string ValStr;
+
+  if (UseInstructionNames && Val->hasName())
+    ValStr = std::string("_") + std::string(Val->getName());
+  else
+    ValStr = std::to_string(Number);
+
+  return getIslCompatibleName(Prefix, ValStr, Suffix);
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+/// To call a inline dump() method in a debugger, at it must have been
+/// instantiated in at least one translation unit. Because isl's dump() method
+/// are meant to be called from a debugger only, but not from code, no such
+/// instantiation would exist. We use this method to force an instantiation in
+/// this translation unit. Because it has non-static linking, the compiler does
+/// not know that it is never called, and therefore must ensure the existence of
+/// the dump functions.
+void neverCalled() {
+  isl::aff().dump();
+  isl::aff_list().dump();
+  isl::ast_expr().dump();
+  isl::ast_expr_list().dump();
+  isl::ast_node().dump();
+  isl::ast_node_list().dump();
+  isl::band_list().dump();
+  isl::basic_map().dump();
+  isl::basic_map_list().dump();
+  isl::basic_set().dump();
+  isl::basic_set_list().dump();
+  isl::constraint().dump();
+  isl::constraint_list().dump();
+  isl::id().dump();
+  isl::id_list().dump();
+  isl::id_to_ast_expr().dump();
+  isl::local_space().dump();
+  isl::map().dump();
+  isl::map_list().dump();
+  isl::multi_aff().dump();
+  isl::multi_pw_aff().dump();
+  isl::multi_union_pw_aff().dump();
+  isl::multi_val().dump();
+  isl::point().dump();
+  isl::pw_aff().dump();
+  isl::pw_aff_list().dump();
+  isl::pw_multi_aff().dump();
+  isl::pw_qpolynomial().dump();
+  isl::qpolynomial().dump();
+  isl::schedule().dump();
+  isl::schedule_constraints().dump();
+  isl::schedule_node().dump();
+  isl::set().dump();
+  isl::set_list().dump();
+  isl::space().dump();
+  isl::union_map().dump();
+  isl::union_map_list().dump();
+  isl::union_pw_aff().dump();
+  isl::union_pw_aff_list().dump();
+  isl::union_pw_multi_aff().dump();
+  isl::union_pw_multi_aff_list().dump();
+  isl::union_set().dump();
+  isl::union_set_list().dump();
+  isl::val().dump();
+  isl::val_list().dump();
+}
+#endif
diff --git a/final/lib/Support/ISLTools.cpp b/final/lib/Support/ISLTools.cpp
new file mode 100644
index 0000000..b280b7a
--- /dev/null
+++ b/final/lib/Support/ISLTools.cpp
@@ -0,0 +1,869 @@
+//===------ ISLTools.cpp ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tools, utilities, helpers and extensions useful in conjunction with the
+// Integer Set Library (isl).
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/Support/ISLTools.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace polly;
+
+namespace {
+/// Create a map that shifts one dimension by an offset.
+///
+/// Example:
+/// makeShiftDimAff({ [i0, i1] -> [o0, o1] }, 1, -2)
+///   = { [i0, i1] -> [i0, i1 - 1] }
+///
+/// @param Space  The map space of the result. Must have equal number of in- and
+///               out-dimensions.
+/// @param Pos    Position to shift.
+/// @param Amount Value added to the shifted dimension.
+///
+/// @return An isl_multi_aff for the map with this shifted dimension.
+isl::multi_aff makeShiftDimAff(isl::space Space, int Pos, int Amount) {
+  auto Identity = give(isl_multi_aff_identity(Space.take()));
+  if (Amount == 0)
+    return Identity;
+  auto ShiftAff = give(isl_multi_aff_get_aff(Identity.keep(), Pos));
+  ShiftAff = give(isl_aff_set_constant_si(ShiftAff.take(), Amount));
+  return give(isl_multi_aff_set_aff(Identity.take(), Pos, ShiftAff.take()));
+}
+
+/// Construct a map that swaps two nested tuples.
+///
+/// @param FromSpace1 { Space1[] }
+/// @param FromSpace2 { Space2[] }
+///
+/// @return { [Space1[] -> Space2[]] -> [Space2[] -> Space1[]] }
+isl::basic_map makeTupleSwapBasicMap(isl::space FromSpace1,
+                                     isl::space FromSpace2) {
+  assert(isl_space_is_set(FromSpace1.keep()) != isl_bool_false);
+  assert(isl_space_is_set(FromSpace2.keep()) != isl_bool_false);
+
+  auto Dims1 = isl_space_dim(FromSpace1.keep(), isl_dim_set);
+  auto Dims2 = isl_space_dim(FromSpace2.keep(), isl_dim_set);
+  auto FromSpace = give(isl_space_wrap(isl_space_map_from_domain_and_range(
+      FromSpace1.copy(), FromSpace2.copy())));
+  auto ToSpace = give(isl_space_wrap(isl_space_map_from_domain_and_range(
+      FromSpace2.take(), FromSpace1.take())));
+  auto MapSpace = give(
+      isl_space_map_from_domain_and_range(FromSpace.take(), ToSpace.take()));
+
+  auto Result = give(isl_basic_map_universe(MapSpace.take()));
+  for (auto i = Dims1 - Dims1; i < Dims1; i += 1) {
+    Result = give(isl_basic_map_equate(Result.take(), isl_dim_in, i,
+                                       isl_dim_out, Dims2 + i));
+  }
+  for (auto i = Dims2 - Dims2; i < Dims2; i += 1) {
+    Result = give(isl_basic_map_equate(Result.take(), isl_dim_in, Dims1 + i,
+                                       isl_dim_out, i));
+  }
+
+  return Result;
+}
+
+/// Like makeTupleSwapBasicMap(isl::space,isl::space), but returns
+/// an isl_map.
+isl::map makeTupleSwapMap(isl::space FromSpace1, isl::space FromSpace2) {
+  auto BMapResult =
+      makeTupleSwapBasicMap(std::move(FromSpace1), std::move(FromSpace2));
+  return give(isl_map_from_basic_map(BMapResult.take()));
+}
+} // anonymous namespace
+
+isl::map polly::beforeScatter(isl::map Map, bool Strict) {
+  auto RangeSpace = give(isl_space_range(isl_map_get_space(Map.keep())));
+  auto ScatterRel = give(Strict ? isl_map_lex_gt(RangeSpace.take())
+                                : isl_map_lex_ge(RangeSpace.take()));
+  return give(isl_map_apply_range(Map.take(), ScatterRel.take()));
+}
+
+isl::union_map polly::beforeScatter(isl::union_map UMap, bool Strict) {
+  auto Result = give(isl_union_map_empty(isl_union_map_get_space(UMap.keep())));
+  UMap.foreach_map([=, &Result](isl::map Map) -> isl::stat {
+    auto After = beforeScatter(Map, Strict);
+    Result = give(isl_union_map_add_map(Result.take(), After.take()));
+    return isl::stat::ok;
+  });
+  return Result;
+}
+
+isl::map polly::afterScatter(isl::map Map, bool Strict) {
+  auto RangeSpace = give(isl_space_range(isl_map_get_space(Map.keep())));
+  auto ScatterRel = give(Strict ? isl_map_lex_lt(RangeSpace.take())
+                                : isl_map_lex_le(RangeSpace.take()));
+  return give(isl_map_apply_range(Map.take(), ScatterRel.take()));
+}
+
+isl::union_map polly::afterScatter(const isl::union_map &UMap, bool Strict) {
+  auto Result = give(isl_union_map_empty(isl_union_map_get_space(UMap.keep())));
+  UMap.foreach_map([=, &Result](isl::map Map) -> isl::stat {
+    auto After = afterScatter(Map, Strict);
+    Result = give(isl_union_map_add_map(Result.take(), After.take()));
+    return isl::stat::ok;
+  });
+  return Result;
+}
+
+isl::map polly::betweenScatter(isl::map From, isl::map To, bool InclFrom,
+                               bool InclTo) {
+  auto AfterFrom = afterScatter(From, !InclFrom);
+  auto BeforeTo = beforeScatter(To, !InclTo);
+
+  return give(isl_map_intersect(AfterFrom.take(), BeforeTo.take()));
+}
+
+isl::union_map polly::betweenScatter(isl::union_map From, isl::union_map To,
+                                     bool InclFrom, bool InclTo) {
+  auto AfterFrom = afterScatter(From, !InclFrom);
+  auto BeforeTo = beforeScatter(To, !InclTo);
+
+  return give(isl_union_map_intersect(AfterFrom.take(), BeforeTo.take()));
+}
+
+isl::map polly::singleton(isl::union_map UMap, isl::space ExpectedSpace) {
+  if (!UMap)
+    return nullptr;
+
+  if (isl_union_map_n_map(UMap.keep()) == 0)
+    return isl::map::empty(ExpectedSpace);
+
+  isl::map Result = isl::map::from_union_map(UMap);
+  assert(!Result || Result.get_space().has_equal_tuples(ExpectedSpace));
+
+  return Result;
+}
+
+isl::set polly::singleton(isl::union_set USet, isl::space ExpectedSpace) {
+  if (!USet)
+    return nullptr;
+
+  if (isl_union_set_n_set(USet.keep()) == 0)
+    return isl::set::empty(ExpectedSpace);
+
+  isl::set Result(USet);
+  assert(!Result || Result.get_space().has_equal_tuples(ExpectedSpace));
+
+  return Result;
+}
+
+unsigned polly::getNumScatterDims(const isl::union_map &Schedule) {
+  unsigned Dims = 0;
+  Schedule.foreach_map([&Dims](isl::map Map) -> isl::stat {
+    Dims = std::max(Dims, isl_map_dim(Map.keep(), isl_dim_out));
+    return isl::stat::ok;
+  });
+  return Dims;
+}
+
+isl::space polly::getScatterSpace(const isl::union_map &Schedule) {
+  if (!Schedule)
+    return nullptr;
+  auto Dims = getNumScatterDims(Schedule);
+  auto ScatterSpace =
+      give(isl_space_set_from_params(isl_union_map_get_space(Schedule.keep())));
+  return give(isl_space_add_dims(ScatterSpace.take(), isl_dim_set, Dims));
+}
+
+isl::union_map polly::makeIdentityMap(const isl::union_set &USet,
+                                      bool RestrictDomain) {
+  auto Result = give(isl_union_map_empty(isl_union_set_get_space(USet.keep())));
+  USet.foreach_set([=, &Result](isl::set Set) -> isl::stat {
+    auto IdentityMap = give(isl_map_identity(
+        isl_space_map_from_set(isl_set_get_space(Set.keep()))));
+    if (RestrictDomain)
+      IdentityMap =
+          give(isl_map_intersect_domain(IdentityMap.take(), Set.take()));
+    Result = give(isl_union_map_add_map(Result.take(), IdentityMap.take()));
+    return isl::stat::ok;
+  });
+  return Result;
+}
+
+isl::map polly::reverseDomain(isl::map Map) {
+  auto DomSpace =
+      give(isl_space_unwrap(isl_space_domain(isl_map_get_space(Map.keep()))));
+  auto Space1 = give(isl_space_domain(DomSpace.copy()));
+  auto Space2 = give(isl_space_range(DomSpace.take()));
+  auto Swap = makeTupleSwapMap(std::move(Space1), std::move(Space2));
+  return give(isl_map_apply_domain(Map.take(), Swap.take()));
+}
+
+isl::union_map polly::reverseDomain(const isl::union_map &UMap) {
+  auto Result = give(isl_union_map_empty(isl_union_map_get_space(UMap.keep())));
+  UMap.foreach_map([=, &Result](isl::map Map) -> isl::stat {
+    auto Reversed = reverseDomain(std::move(Map));
+    Result = give(isl_union_map_add_map(Result.take(), Reversed.take()));
+    return isl::stat::ok;
+  });
+  return Result;
+}
+
+isl::set polly::shiftDim(isl::set Set, int Pos, int Amount) {
+  int NumDims = isl_set_dim(Set.keep(), isl_dim_set);
+  if (Pos < 0)
+    Pos = NumDims + Pos;
+  assert(Pos < NumDims && "Dimension index must be in range");
+  auto Space = give(isl_set_get_space(Set.keep()));
+  Space = give(isl_space_map_from_domain_and_range(Space.copy(), Space.copy()));
+  auto Translator = makeShiftDimAff(std::move(Space), Pos, Amount);
+  auto TranslatorMap = give(isl_map_from_multi_aff(Translator.take()));
+  return give(isl_set_apply(Set.take(), TranslatorMap.take()));
+}
+
+isl::union_set polly::shiftDim(isl::union_set USet, int Pos, int Amount) {
+  auto Result = give(isl_union_set_empty(isl_union_set_get_space(USet.keep())));
+  USet.foreach_set([=, &Result](isl::set Set) -> isl::stat {
+    auto Shifted = shiftDim(Set, Pos, Amount);
+    Result = give(isl_union_set_add_set(Result.take(), Shifted.take()));
+    return isl::stat::ok;
+  });
+  return Result;
+}
+
+isl::map polly::shiftDim(isl::map Map, isl::dim Dim, int Pos, int Amount) {
+  int NumDims = Map.dim(Dim);
+  if (Pos < 0)
+    Pos = NumDims + Pos;
+  assert(Pos < NumDims && "Dimension index must be in range");
+  auto Space = give(isl_map_get_space(Map.keep()));
+  switch (Dim) {
+  case isl::dim::in:
+    Space = std::move(Space).domain();
+    break;
+  case isl::dim::out:
+    Space = give(isl_space_range(Space.take()));
+    break;
+  default:
+    llvm_unreachable("Unsupported value for 'dim'");
+  }
+  Space = give(isl_space_map_from_domain_and_range(Space.copy(), Space.copy()));
+  auto Translator = makeShiftDimAff(std::move(Space), Pos, Amount);
+  auto TranslatorMap = give(isl_map_from_multi_aff(Translator.take()));
+  switch (Dim) {
+  case isl::dim::in:
+    return Map.apply_domain(TranslatorMap);
+  case isl::dim::out:
+    return Map.apply_range(TranslatorMap);
+  default:
+    llvm_unreachable("Unsupported value for 'dim'");
+  }
+}
+
+isl::union_map polly::shiftDim(isl::union_map UMap, isl::dim Dim, int Pos,
+                               int Amount) {
+  auto Result = isl::union_map::empty(UMap.get_space());
+
+  UMap.foreach_map([=, &Result](isl::map Map) -> isl::stat {
+    auto Shifted = shiftDim(Map, Dim, Pos, Amount);
+    Result = std::move(Result).add_map(Shifted);
+    return isl::stat::ok;
+  });
+  return Result;
+}
+
+void polly::simplify(isl::set &Set) {
+  Set = give(isl_set_compute_divs(Set.take()));
+  Set = give(isl_set_detect_equalities(Set.take()));
+  Set = give(isl_set_coalesce(Set.take()));
+}
+
+void polly::simplify(isl::union_set &USet) {
+  USet = give(isl_union_set_compute_divs(USet.take()));
+  USet = give(isl_union_set_detect_equalities(USet.take()));
+  USet = give(isl_union_set_coalesce(USet.take()));
+}
+
+void polly::simplify(isl::map &Map) {
+  Map = give(isl_map_compute_divs(Map.take()));
+  Map = give(isl_map_detect_equalities(Map.take()));
+  Map = give(isl_map_coalesce(Map.take()));
+}
+
+void polly::simplify(isl::union_map &UMap) {
+  UMap = give(isl_union_map_compute_divs(UMap.take()));
+  UMap = give(isl_union_map_detect_equalities(UMap.take()));
+  UMap = give(isl_union_map_coalesce(UMap.take()));
+}
+
+isl::union_map polly::computeReachingWrite(isl::union_map Schedule,
+                                           isl::union_map Writes, bool Reverse,
+                                           bool InclPrevDef, bool InclNextDef) {
+
+  // { Scatter[] }
+  isl::space ScatterSpace = getScatterSpace(Schedule);
+
+  // { ScatterRead[] -> ScatterWrite[] }
+  isl::map Relation;
+  if (Reverse)
+    Relation = InclPrevDef ? isl::map::lex_lt(ScatterSpace)
+                           : isl::map::lex_le(ScatterSpace);
+  else
+    Relation = InclNextDef ? isl::map::lex_gt(ScatterSpace)
+                           : isl::map::lex_ge(ScatterSpace);
+
+  // { ScatterWrite[] -> [ScatterRead[] -> ScatterWrite[]] }
+  isl::map RelationMap = Relation.range_map().reverse();
+
+  // { Element[] -> ScatterWrite[] }
+  isl::union_map WriteAction = Schedule.apply_domain(Writes);
+
+  // { ScatterWrite[] -> Element[] }
+  isl::union_map WriteActionRev = WriteAction.reverse();
+
+  // { Element[] -> [ScatterUse[] -> ScatterWrite[]] }
+  isl::union_map DefSchedRelation =
+      isl::union_map(RelationMap).apply_domain(WriteActionRev);
+
+  // For each element, at every point in time, map to the times of previous
+  // definitions. { [Element[] -> ScatterRead[]] -> ScatterWrite[] }
+  isl::union_map ReachableWrites = DefSchedRelation.uncurry();
+  if (Reverse)
+    ReachableWrites = ReachableWrites.lexmin();
+  else
+    ReachableWrites = ReachableWrites.lexmax();
+
+  // { [Element[] -> ScatterWrite[]] -> ScatterWrite[] }
+  isl::union_map SelfUse = WriteAction.range_map();
+
+  if (InclPrevDef && InclNextDef) {
+    // Add the Def itself to the solution.
+    ReachableWrites = ReachableWrites.unite(SelfUse).coalesce();
+  } else if (!InclPrevDef && !InclNextDef) {
+    // Remove Def itself from the solution.
+    ReachableWrites = ReachableWrites.subtract(SelfUse);
+  }
+
+  // { [Element[] -> ScatterRead[]] -> Domain[] }
+  return ReachableWrites.apply_range(Schedule.reverse());
+}
+
+isl::union_map
+polly::computeArrayUnused(isl::union_map Schedule, isl::union_map Writes,
+                          isl::union_map Reads, bool ReadEltInSameInst,
+                          bool IncludeLastRead, bool IncludeWrite) {
+  // { Element[] -> Scatter[] }
+  auto ReadActions =
+      give(isl_union_map_apply_domain(Schedule.copy(), Reads.take()));
+  auto WriteActions =
+      give(isl_union_map_apply_domain(Schedule.copy(), Writes.copy()));
+
+  // { [Element[] -> DomainWrite[]] -> Scatter[] }
+  auto EltDomWrites = give(isl_union_map_apply_range(
+      isl_union_map_range_map(isl_union_map_reverse(Writes.copy())),
+      Schedule.copy()));
+
+  // { [Element[] -> Scatter[]] -> DomainWrite[] }
+  auto ReachingOverwrite = computeReachingWrite(
+      Schedule, Writes, true, ReadEltInSameInst, !ReadEltInSameInst);
+
+  // { [Element[] -> Scatter[]] -> DomainWrite[] }
+  auto ReadsOverwritten = give(isl_union_map_intersect_domain(
+      ReachingOverwrite.take(), isl_union_map_wrap(ReadActions.take())));
+
+  // { [Element[] -> DomainWrite[]] -> Scatter[] }
+  auto ReadsOverwrittenRotated = give(isl_union_map_reverse(
+      isl_union_map_curry(reverseDomain(ReadsOverwritten).take())));
+  auto LastOverwrittenRead =
+      give(isl_union_map_lexmax(ReadsOverwrittenRotated.copy()));
+
+  // { [Element[] -> DomainWrite[]] -> Scatter[] }
+  auto BetweenLastReadOverwrite = betweenScatter(
+      LastOverwrittenRead, EltDomWrites, IncludeLastRead, IncludeWrite);
+
+  // { [Element[] -> Scatter[]] -> DomainWrite[] }
+  isl::union_map ReachingOverwriteZone = computeReachingWrite(
+      Schedule, Writes, true, IncludeLastRead, IncludeWrite);
+
+  // { [Element[] -> DomainWrite[]] -> Scatter[] }
+  isl::union_map ReachingOverwriteRotated =
+      reverseDomain(ReachingOverwriteZone).curry().reverse();
+
+  // { [Element[] -> DomainWrite[]] -> Scatter[] }
+  isl::union_map WritesWithoutReads = ReachingOverwriteRotated.subtract_domain(
+      ReadsOverwrittenRotated.domain());
+
+  return BetweenLastReadOverwrite.unite(WritesWithoutReads)
+      .domain_factor_domain();
+}
+
+isl::union_set polly::convertZoneToTimepoints(isl::union_set Zone,
+                                              bool InclStart, bool InclEnd) {
+  if (!InclStart && InclEnd)
+    return Zone;
+
+  auto ShiftedZone = shiftDim(Zone, -1, -1);
+  if (InclStart && !InclEnd)
+    return ShiftedZone;
+  else if (!InclStart && !InclEnd)
+    return give(isl_union_set_intersect(Zone.take(), ShiftedZone.take()));
+
+  assert(InclStart && InclEnd);
+  return give(isl_union_set_union(Zone.take(), ShiftedZone.take()));
+}
+
+isl::union_map polly::convertZoneToTimepoints(isl::union_map Zone, isl::dim Dim,
+                                              bool InclStart, bool InclEnd) {
+  if (!InclStart && InclEnd)
+    return Zone;
+
+  auto ShiftedZone = shiftDim(Zone, Dim, -1, -1);
+  if (InclStart && !InclEnd)
+    return ShiftedZone;
+  else if (!InclStart && !InclEnd)
+    return give(isl_union_map_intersect(Zone.take(), ShiftedZone.take()));
+
+  assert(InclStart && InclEnd);
+  return give(isl_union_map_union(Zone.take(), ShiftedZone.take()));
+}
+
+isl::map polly::convertZoneToTimepoints(isl::map Zone, isl::dim Dim,
+                                        bool InclStart, bool InclEnd) {
+  if (!InclStart && InclEnd)
+    return Zone;
+
+  auto ShiftedZone = shiftDim(Zone, Dim, -1, -1);
+  if (InclStart && !InclEnd)
+    return ShiftedZone;
+  else if (!InclStart && !InclEnd)
+    return give(isl_map_intersect(Zone.take(), ShiftedZone.take()));
+
+  assert(InclStart && InclEnd);
+  return give(isl_map_union(Zone.take(), ShiftedZone.take()));
+}
+
+isl::map polly::distributeDomain(isl::map Map) {
+  // Note that we cannot take Map apart into { Domain[] -> Range1[] } and {
+  // Domain[] -> Range2[] } and combine again. We would loose any relation
+  // between Range1[] and Range2[] that is not also a constraint to Domain[].
+
+  auto Space = give(isl_map_get_space(Map.keep()));
+  auto DomainSpace = give(isl_space_domain(Space.copy()));
+  auto DomainDims = isl_space_dim(DomainSpace.keep(), isl_dim_set);
+  auto RangeSpace = give(isl_space_unwrap(isl_space_range(Space.copy())));
+  auto Range1Space = give(isl_space_domain(RangeSpace.copy()));
+  auto Range1Dims = isl_space_dim(Range1Space.keep(), isl_dim_set);
+  auto Range2Space = give(isl_space_range(RangeSpace.copy()));
+  auto Range2Dims = isl_space_dim(Range2Space.keep(), isl_dim_set);
+
+  auto OutputSpace = give(isl_space_map_from_domain_and_range(
+      isl_space_wrap(isl_space_map_from_domain_and_range(DomainSpace.copy(),
+                                                         Range1Space.copy())),
+      isl_space_wrap(isl_space_map_from_domain_and_range(DomainSpace.copy(),
+                                                         Range2Space.copy()))));
+
+  auto Translator =
+      give(isl_basic_map_universe(isl_space_map_from_domain_and_range(
+          isl_space_wrap(Space.copy()), isl_space_wrap(OutputSpace.copy()))));
+
+  for (unsigned i = 0; i < DomainDims; i += 1) {
+    Translator = give(
+        isl_basic_map_equate(Translator.take(), isl_dim_in, i, isl_dim_out, i));
+    Translator =
+        give(isl_basic_map_equate(Translator.take(), isl_dim_in, i, isl_dim_out,
+                                  DomainDims + Range1Dims + i));
+  }
+  for (unsigned i = 0; i < Range1Dims; i += 1) {
+    Translator =
+        give(isl_basic_map_equate(Translator.take(), isl_dim_in, DomainDims + i,
+                                  isl_dim_out, DomainDims + i));
+  }
+  for (unsigned i = 0; i < Range2Dims; i += 1) {
+    Translator = give(isl_basic_map_equate(
+        Translator.take(), isl_dim_in, DomainDims + Range1Dims + i, isl_dim_out,
+        DomainDims + Range1Dims + DomainDims + i));
+  }
+
+  return give(isl_set_unwrap(isl_set_apply(
+      isl_map_wrap(Map.copy()), isl_map_from_basic_map(Translator.copy()))));
+}
+
+isl::union_map polly::distributeDomain(isl::union_map UMap) {
+  auto Result = give(isl_union_map_empty(isl_union_map_get_space(UMap.keep())));
+  isl::stat Success = UMap.foreach_map([=, &Result](isl::map Map) {
+    auto Distributed = distributeDomain(Map);
+    Result = give(isl_union_map_add_map(Result.take(), Distributed.copy()));
+    return isl::stat::ok;
+  });
+  if (Success != isl::stat::ok)
+    return {};
+  return Result;
+}
+
+isl::union_map polly::liftDomains(isl::union_map UMap, isl::union_set Factor) {
+
+  // { Factor[] -> Factor[] }
+  auto Factors = makeIdentityMap(std::move(Factor), true);
+
+  return std::move(Factors).product(std::move(UMap));
+}
+
+isl::union_map polly::applyDomainRange(isl::union_map UMap,
+                                       isl::union_map Func) {
+  // This implementation creates unnecessary cross products of the
+  // DomainDomain[] and Func. An alternative implementation could reverse
+  // domain+uncurry,apply Func to what now is the domain, then undo the
+  // preparing transformation. Another alternative implementation could create a
+  // translator map for each piece.
+
+  // { DomainDomain[] }
+  auto DomainDomain = UMap.domain().unwrap().domain();
+
+  // { [DomainDomain[] -> DomainRange[]] -> [DomainDomain[] -> NewDomainRange[]]
+  // }
+  auto LifetedFunc = liftDomains(std::move(Func), DomainDomain);
+
+  return std::move(UMap).apply_domain(std::move(LifetedFunc));
+}
+
+isl::map polly::intersectRange(isl::map Map, isl::union_set Range) {
+  isl::set RangeSet = Range.extract_set(Map.get_space().range());
+  return Map.intersect_range(RangeSet);
+}
+
+isl::val polly::getConstant(isl::pw_aff PwAff, bool Max, bool Min) {
+  assert(!Max || !Min); // Cannot return min and max at the same time.
+  isl::val Result;
+  PwAff.foreach_piece([=, &Result](isl::set Set, isl::aff Aff) -> isl::stat {
+    if (Result && Result.is_nan())
+      return isl::stat::ok;
+
+    // TODO: If Min/Max, we can also determine a minimum/maximum value if
+    // Set is constant-bounded.
+    if (!Aff.is_cst()) {
+      Result = isl::val::nan(Aff.get_ctx());
+      return isl::stat::error;
+    }
+
+    isl::val ThisVal = Aff.get_constant_val();
+    if (!Result) {
+      Result = ThisVal;
+      return isl::stat::ok;
+    }
+
+    if (Result.eq(ThisVal))
+      return isl::stat::ok;
+
+    if (Max && ThisVal.gt(Result)) {
+      Result = ThisVal;
+      return isl::stat::ok;
+    }
+
+    if (Min && ThisVal.lt(Result)) {
+      Result = ThisVal;
+      return isl::stat::ok;
+    }
+
+    // Not compatible
+    Result = isl::val::nan(Aff.get_ctx());
+    return isl::stat::error;
+  });
+  return Result;
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+static void foreachPoint(const isl::set &Set,
+                         const std::function<void(isl::point P)> &F) {
+  isl_set_foreach_point(
+      Set.keep(),
+      [](__isl_take isl_point *p, void *User) -> isl_stat {
+        auto &F = *static_cast<const std::function<void(isl::point)> *>(User);
+        F(give(p));
+        return isl_stat_ok;
+      },
+      const_cast<void *>(static_cast<const void *>(&F)));
+}
+
+static void foreachPoint(isl::basic_set BSet,
+                         const std::function<void(isl::point P)> &F) {
+  foreachPoint(give(isl_set_from_basic_set(BSet.take())), F);
+}
+
+/// Determine the sorting order of the sets @p A and @p B without considering
+/// the space structure.
+///
+/// Ordering is based on the lower bounds of the set's dimensions. First
+/// dimensions are considered first.
+static int flatCompare(const isl::basic_set &A, const isl::basic_set &B) {
+  int ALen = A.dim(isl::dim::set);
+  int BLen = B.dim(isl::dim::set);
+  int Len = std::min(ALen, BLen);
+
+  for (int i = 0; i < Len; i += 1) {
+    isl::basic_set ADim =
+        A.project_out(isl::dim::param, 0, A.dim(isl::dim::param))
+            .project_out(isl::dim::set, i + 1, ALen - i - 1)
+            .project_out(isl::dim::set, 0, i);
+    isl::basic_set BDim =
+        B.project_out(isl::dim::param, 0, B.dim(isl::dim::param))
+            .project_out(isl::dim::set, i + 1, BLen - i - 1)
+            .project_out(isl::dim::set, 0, i);
+
+    isl::basic_set AHull = isl::set(ADim).convex_hull();
+    isl::basic_set BHull = isl::set(BDim).convex_hull();
+
+    bool ALowerBounded =
+        bool(isl::set(AHull).dim_has_any_lower_bound(isl::dim::set, 0));
+    bool BLowerBounded =
+        bool(isl::set(BHull).dim_has_any_lower_bound(isl::dim::set, 0));
+
+    int BoundedCompare = BLowerBounded - ALowerBounded;
+    if (BoundedCompare != 0)
+      return BoundedCompare;
+
+    if (!ALowerBounded || !BLowerBounded)
+      continue;
+
+    isl::pw_aff AMin = isl::set(ADim).dim_min(0);
+    isl::pw_aff BMin = isl::set(BDim).dim_min(0);
+
+    isl::val AMinVal = polly::getConstant(AMin, false, true);
+    isl::val BMinVal = polly::getConstant(BMin, false, true);
+
+    int MinCompare = AMinVal.sub(BMinVal).sgn();
+    if (MinCompare != 0)
+      return MinCompare;
+  }
+
+  // If all the dimensions' lower bounds are equal or incomparable, sort based
+  // on the number of dimensions.
+  return ALen - BLen;
+}
+
+/// Compare the sets @p A and @p B according to their nested space structure. If
+/// the structure is the same, sort using the dimension lower bounds.
+static int recursiveCompare(const isl::basic_set &A, const isl::basic_set &B) {
+  isl::space ASpace = A.get_space();
+  isl::space BSpace = B.get_space();
+
+  int WrappingCompare = bool(ASpace.is_wrapping()) - bool(BSpace.is_wrapping());
+  if (WrappingCompare != 0)
+    return WrappingCompare;
+
+  if (ASpace.is_wrapping() && B.is_wrapping()) {
+    isl::basic_map AMap = A.unwrap();
+    isl::basic_map BMap = B.unwrap();
+
+    int FirstResult = recursiveCompare(AMap.domain(), BMap.domain());
+    if (FirstResult != 0)
+      return FirstResult;
+
+    return recursiveCompare(AMap.range(), BMap.range());
+  }
+
+  std::string AName = ASpace.has_tuple_name(isl::dim::set)
+                          ? ASpace.get_tuple_name(isl::dim::set)
+                          : std::string();
+  std::string BName = BSpace.has_tuple_name(isl::dim::set)
+                          ? BSpace.get_tuple_name(isl::dim::set)
+                          : std::string();
+
+  int NameCompare = AName.compare(BName);
+  if (NameCompare != 0)
+    return NameCompare;
+
+  return flatCompare(A, B);
+}
+
+/// Wrapper for recursiveCompare, convert a {-1,0,1} compare result to what
+/// std::sort expects.
+static bool orderComparer(const isl::basic_set &A, const isl::basic_set &B) {
+  return recursiveCompare(A, B) < 0;
+}
+
+/// Print a string representation of @p USet to @p OS.
+///
+/// The pieces of @p USet are printed in a sorted order. Spaces with equal or
+/// similar nesting structure are printed together. Compared to isl's own
+/// printing function the uses the structure itself as base of the sorting, not
+/// a hash of it. It ensures that e.g. maps spaces with same domain structure
+/// are printed together. Set pieces with same structure are printed in order of
+/// their lower bounds.
+///
+/// @param USet     Polyhedra to print.
+/// @param OS       Target stream.
+/// @param Simplify Whether to simplify the polyhedron before printing.
+/// @param IsMap    Whether @p USet is a wrapped map. If true, sets are
+///                 unwrapped before printing to again appear as a map.
+static void printSortedPolyhedra(isl::union_set USet, llvm::raw_ostream &OS,
+                                 bool Simplify, bool IsMap) {
+  if (!USet) {
+    OS << "<null>\n";
+    return;
+  }
+
+  if (Simplify)
+    simplify(USet);
+
+  // Get all the polyhedra.
+  std::vector<isl::basic_set> BSets;
+  USet.foreach_set([&BSets](isl::set Set) -> isl::stat {
+    Set.foreach_basic_set([&BSets](isl::basic_set BSet) -> isl::stat {
+      BSets.push_back(BSet);
+      return isl::stat::ok;
+    });
+    return isl::stat::ok;
+  });
+
+  if (BSets.empty()) {
+    OS << "{\n}\n";
+    return;
+  }
+
+  // Sort the polyhedra.
+  std::sort(BSets.begin(), BSets.end(), orderComparer);
+
+  // Print the polyhedra.
+  bool First = true;
+  for (const isl::basic_set &BSet : BSets) {
+    std::string Str;
+    if (IsMap)
+      Str = isl::map(BSet.unwrap()).to_str();
+    else
+      Str = isl::set(BSet).to_str();
+    size_t OpenPos = Str.find_first_of('{');
+    assert(OpenPos != std::string::npos);
+    size_t ClosePos = Str.find_last_of('}');
+    assert(ClosePos != std::string::npos);
+
+    if (First)
+      OS << llvm::StringRef(Str).substr(0, OpenPos + 1) << "\n ";
+    else
+      OS << ";\n ";
+
+    OS << llvm::StringRef(Str).substr(OpenPos + 1, ClosePos - OpenPos - 2);
+    First = false;
+  }
+  assert(!First);
+  OS << "\n}\n";
+}
+
+static void recursiveExpand(isl::basic_set BSet, int Dim, isl::set &Expanded) {
+  int Dims = BSet.dim(isl::dim::set);
+  if (Dim >= Dims) {
+    Expanded = Expanded.unite(BSet);
+    return;
+  }
+
+  isl::basic_set DimOnly =
+      BSet.project_out(isl::dim::param, 0, BSet.dim(isl::dim::param))
+          .project_out(isl::dim::set, Dim + 1, Dims - Dim - 1)
+          .project_out(isl::dim::set, 0, Dim);
+  if (!DimOnly.is_bounded()) {
+    recursiveExpand(BSet, Dim + 1, Expanded);
+    return;
+  }
+
+  foreachPoint(DimOnly, [&, Dim](isl::point P) {
+    isl::val Val = P.get_coordinate_val(isl::dim::set, 0);
+    isl::basic_set FixBSet = BSet.fix_val(isl::dim::set, Dim, Val);
+    recursiveExpand(FixBSet, Dim + 1, Expanded);
+  });
+}
+
+/// Make each point of a set explicit.
+///
+/// "Expanding" makes each point a set contains explicit. That is, the result is
+/// a set of singleton polyhedra. Unbounded dimensions are not expanded.
+///
+/// Example:
+///   { [i] : 0 <= i < 2 }
+/// is expanded to:
+///   { [0]; [1] }
+static isl::set expand(const isl::set &Set) {
+  isl::set Expanded = isl::set::empty(Set.get_space());
+  Set.foreach_basic_set([&](isl::basic_set BSet) -> isl::stat {
+    recursiveExpand(BSet, 0, Expanded);
+    return isl::stat::ok;
+  });
+  return Expanded;
+}
+
+/// Expand all points of a union set explicit.
+///
+/// @see expand(const isl::set)
+static isl::union_set expand(const isl::union_set &USet) {
+  isl::union_set Expanded =
+      give(isl_union_set_empty(isl_union_set_get_space(USet.keep())));
+  USet.foreach_set([&](isl::set Set) -> isl::stat {
+    isl::set SetExpanded = expand(Set);
+    Expanded = Expanded.add_set(SetExpanded);
+    return isl::stat::ok;
+  });
+  return Expanded;
+}
+
+LLVM_DUMP_METHOD void polly::dumpPw(const isl::set &Set) {
+  printSortedPolyhedra(Set, llvm::errs(), true, false);
+}
+
+LLVM_DUMP_METHOD void polly::dumpPw(const isl::map &Map) {
+  printSortedPolyhedra(Map.wrap(), llvm::errs(), true, true);
+}
+
+LLVM_DUMP_METHOD void polly::dumpPw(const isl::union_set &USet) {
+  printSortedPolyhedra(USet, llvm::errs(), true, false);
+}
+
+LLVM_DUMP_METHOD void polly::dumpPw(const isl::union_map &UMap) {
+  printSortedPolyhedra(UMap.wrap(), llvm::errs(), true, true);
+}
+
+LLVM_DUMP_METHOD void polly::dumpPw(__isl_keep isl_set *Set) {
+  dumpPw(isl::manage(isl_set_copy(Set)));
+}
+
+LLVM_DUMP_METHOD void polly::dumpPw(__isl_keep isl_map *Map) {
+  dumpPw(isl::manage(isl_map_copy(Map)));
+}
+
+LLVM_DUMP_METHOD void polly::dumpPw(__isl_keep isl_union_set *USet) {
+  dumpPw(isl::manage(isl_union_set_copy(USet)));
+}
+
+LLVM_DUMP_METHOD void polly::dumpPw(__isl_keep isl_union_map *UMap) {
+  dumpPw(isl::manage(isl_union_map_copy(UMap)));
+}
+
+LLVM_DUMP_METHOD void polly::dumpExpanded(const isl::set &Set) {
+  printSortedPolyhedra(expand(Set), llvm::errs(), false, false);
+}
+
+LLVM_DUMP_METHOD void polly::dumpExpanded(const isl::map &Map) {
+  printSortedPolyhedra(expand(Map.wrap()), llvm::errs(), false, true);
+}
+
+LLVM_DUMP_METHOD void polly::dumpExpanded(const isl::union_set &USet) {
+  printSortedPolyhedra(expand(USet), llvm::errs(), false, false);
+}
+
+LLVM_DUMP_METHOD void polly::dumpExpanded(const isl::union_map &UMap) {
+  printSortedPolyhedra(expand(UMap.wrap()), llvm::errs(), false, true);
+}
+
+LLVM_DUMP_METHOD void polly::dumpExpanded(__isl_keep isl_set *Set) {
+  dumpExpanded(isl::manage(isl_set_copy(Set)));
+}
+
+LLVM_DUMP_METHOD void polly::dumpExpanded(__isl_keep isl_map *Map) {
+  dumpExpanded(isl::manage(isl_map_copy(Map)));
+}
+
+LLVM_DUMP_METHOD void polly::dumpExpanded(__isl_keep isl_union_set *USet) {
+  dumpExpanded(isl::manage(isl_union_set_copy(USet)));
+}
+
+LLVM_DUMP_METHOD void polly::dumpExpanded(__isl_keep isl_union_map *UMap) {
+  dumpExpanded(isl::manage(isl_union_map_copy(UMap)));
+}
+#endif
diff --git a/final/lib/Support/Mainpage.h b/final/lib/Support/Mainpage.h
new file mode 100644
index 0000000..156c296
--- /dev/null
+++ b/final/lib/Support/Mainpage.h
@@ -0,0 +1,4 @@
+/*! \mainpage Polly main page
+ *
+ * This is the documentation of http://polly.llvm.org
+ */
diff --git a/final/lib/Support/PollyPasses.def b/final/lib/Support/PollyPasses.def
new file mode 100644
index 0000000..b07f928
--- /dev/null
+++ b/final/lib/Support/PollyPasses.def
@@ -0,0 +1,31 @@
+#ifndef FUNCTION_ANALYSIS
+#define FUNCTION_ANALYSIS(NAME, CREATE_PASS)
+#endif
+FUNCTION_ANALYSIS("polly-detect", ScopAnalysis())
+FUNCTION_ANALYSIS("polly-function-scops", ScopInfoAnalysis())
+#undef FUNCTION_ANALYSIS
+
+#ifndef FUNCTION_PASS
+#define FUNCTION_PASS(NAME, CREATE_PASS)
+#endif
+FUNCTION_PASS("polly-prepare", CodePreparationPass())
+FUNCTION_PASS("print<polly-detect>", ScopAnalysisPrinterPass(errs()))
+FUNCTION_PASS("print<polly-function-scops>", ScopInfoPrinterPass(errs()))
+#undef FUNCTION_PASS
+
+#ifndef SCOP_ANALYSIS
+#define SCOP_ANALYSIS(NAME, CREATE_PASS)
+#endif
+SCOP_ANALYSIS("polly-ast", IslAstAnalysis())
+SCOP_ANALYSIS("polly-dependences", DependenceAnalysis())
+#undef SCOP_ANALYSIS
+
+#ifndef SCOP_PASS
+#define SCOP_PASS(NAME, CREATE_PASS)
+#endif
+SCOP_PASS("polly-export-jscop", JSONExportPass())
+SCOP_PASS("polly-import-jscop", JSONImportPass())
+SCOP_PASS("print<polly-ast>", IslAstPrinterPass(outs()))
+SCOP_PASS("print<polly-dependences>", DependenceInfoPrinterPass(outs()))
+SCOP_PASS("polly-codegen", CodeGenerationPass())
+#undef SCOP_PASS
diff --git a/final/lib/Support/RegisterPasses.cpp b/final/lib/Support/RegisterPasses.cpp
new file mode 100644
index 0000000..6a86698
--- /dev/null
+++ b/final/lib/Support/RegisterPasses.cpp
@@ -0,0 +1,705 @@
+//===------ RegisterPasses.cpp - Add the Polly Passes to default passes  --===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file composes the individual LLVM-IR passes provided by Polly to a
+// functional polyhedral optimizer. The polyhedral optimizer is automatically
+// made available to LLVM based compilers by loading the Polly shared library
+// into such a compiler.
+//
+// The Polly optimizer is made available by executing a static constructor that
+// registers the individual Polly passes in the LLVM pass manager builder. The
+// passes are registered such that the default behaviour of the compiler is not
+// changed, but that the flag '-polly' provided at optimization level '-O3'
+// enables additional polyhedral optimizations.
+//===----------------------------------------------------------------------===//
+
+#include "polly/RegisterPasses.h"
+#include "polly/Canonicalization.h"
+#include "polly/CodeGen/CodeGeneration.h"
+#include "polly/CodeGen/CodegenCleanup.h"
+#include "polly/CodeGen/IslAst.h"
+#include "polly/CodeGen/PPCGCodeGeneration.h"
+#include "polly/CodePreparation.h"
+#include "polly/DeLICM.h"
+#include "polly/DependenceInfo.h"
+#include "polly/FlattenSchedule.h"
+#include "polly/ForwardOpTree.h"
+#include "polly/JSONExporter.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/PolyhedralInfo.h"
+#include "polly/ScopDetection.h"
+#include "polly/ScopInfo.h"
+#include "polly/Simplify.h"
+#include "polly/Support/DumpModulePass.h"
+#include "llvm/Analysis/CFGPrinter.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Vectorize.h"
+
+using namespace llvm;
+using namespace polly;
+
+cl::OptionCategory PollyCategory("Polly Options",
+                                 "Configure the polly loop optimizer");
+
+static cl::opt<bool>
+    PollyEnabled("polly", cl::desc("Enable the polly optimizer (only at -O3)"),
+                 cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> PollyDetectOnly(
+    "polly-only-scop-detection",
+    cl::desc("Only run scop detection, but no other optimizations"),
+    cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+enum PassPositionChoice {
+  POSITION_EARLY,
+  POSITION_AFTER_LOOPOPT,
+  POSITION_BEFORE_VECTORIZER
+};
+
+enum OptimizerChoice { OPTIMIZER_NONE, OPTIMIZER_ISL };
+
+static cl::opt<PassPositionChoice> PassPosition(
+    "polly-position", cl::desc("Where to run polly in the pass pipeline"),
+    cl::values(
+        clEnumValN(POSITION_EARLY, "early", "Before everything"),
+        clEnumValN(POSITION_AFTER_LOOPOPT, "after-loopopt",
+                   "After the loop optimizer (but within the inline cycle)"),
+        clEnumValN(POSITION_BEFORE_VECTORIZER, "before-vectorizer",
+                   "Right before the vectorizer")),
+    cl::Hidden, cl::init(POSITION_BEFORE_VECTORIZER), cl::ZeroOrMore,
+    cl::cat(PollyCategory));
+
+static cl::opt<OptimizerChoice>
+    Optimizer("polly-optimizer", cl::desc("Select the scheduling optimizer"),
+              cl::values(clEnumValN(OPTIMIZER_NONE, "none", "No optimizer"),
+                         clEnumValN(OPTIMIZER_ISL, "isl",
+                                    "The isl scheduling optimizer")),
+              cl::Hidden, cl::init(OPTIMIZER_ISL), cl::ZeroOrMore,
+              cl::cat(PollyCategory));
+
+enum CodeGenChoice { CODEGEN_FULL, CODEGEN_AST, CODEGEN_NONE };
+static cl::opt<CodeGenChoice> CodeGeneration(
+    "polly-code-generation", cl::desc("How much code-generation to perform"),
+    cl::values(clEnumValN(CODEGEN_FULL, "full", "AST and IR generation"),
+               clEnumValN(CODEGEN_AST, "ast", "Only AST generation"),
+               clEnumValN(CODEGEN_NONE, "none", "No code generation")),
+    cl::Hidden, cl::init(CODEGEN_FULL), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+enum TargetChoice { TARGET_CPU, TARGET_GPU, TARGET_HYBRID };
+static cl::opt<TargetChoice>
+    Target("polly-target", cl::desc("The hardware to target"),
+           cl::values(clEnumValN(TARGET_CPU, "cpu", "generate CPU code")
+#ifdef GPU_CODEGEN
+                          ,
+                      clEnumValN(TARGET_GPU, "gpu", "generate GPU code"),
+                      clEnumValN(TARGET_HYBRID, "hybrid",
+                                 "generate GPU code (preferably) or CPU code")
+#endif
+                          ),
+           cl::init(TARGET_CPU), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+#ifdef GPU_CODEGEN
+static cl::opt<GPURuntime> GPURuntimeChoice(
+    "polly-gpu-runtime", cl::desc("The GPU Runtime API to target"),
+    cl::values(clEnumValN(GPURuntime::CUDA, "libcudart",
+                          "use the CUDA Runtime API"),
+               clEnumValN(GPURuntime::OpenCL, "libopencl",
+                          "use the OpenCL Runtime API")),
+    cl::init(GPURuntime::CUDA), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<GPUArch>
+    GPUArchChoice("polly-gpu-arch", cl::desc("The GPU Architecture to target"),
+                  cl::values(clEnumValN(GPUArch::NVPTX64, "nvptx64",
+                                        "target NVIDIA 64-bit architecture"),
+                             clEnumValN(GPUArch::SPIR32, "spir32",
+                                        "target SPIR 32-bit architecture"),
+                             clEnumValN(GPUArch::SPIR64, "spir64",
+                                        "target SPIR 64-bit architecture")),
+                  cl::init(GPUArch::NVPTX64), cl::ZeroOrMore,
+                  cl::cat(PollyCategory));
+#endif
+
+VectorizerChoice polly::PollyVectorizerChoice;
+static cl::opt<polly::VectorizerChoice, true> Vectorizer(
+    "polly-vectorizer", cl::desc("Select the vectorization strategy"),
+    cl::values(
+        clEnumValN(polly::VECTORIZER_NONE, "none", "No Vectorization"),
+        clEnumValN(polly::VECTORIZER_POLLY, "polly",
+                   "Polly internal vectorizer"),
+        clEnumValN(
+            polly::VECTORIZER_STRIPMINE, "stripmine",
+            "Strip-mine outer loops for the loop-vectorizer to trigger")),
+    cl::location(PollyVectorizerChoice), cl::init(polly::VECTORIZER_NONE),
+    cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> ImportJScop(
+    "polly-import",
+    cl::desc("Import the polyhedral description of the detected Scops"),
+    cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> FullyIndexedStaticExpansion(
+    "polly-enable-mse",
+    cl::desc("Fully expand the memory accesses of the detected Scops"),
+    cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> ExportJScop(
+    "polly-export",
+    cl::desc("Export the polyhedral description of the detected Scops"),
+    cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> DeadCodeElim("polly-run-dce",
+                                  cl::desc("Run the dead code elimination"),
+                                  cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                                  cl::cat(PollyCategory));
+
+static cl::opt<bool> PollyViewer(
+    "polly-show",
+    cl::desc("Highlight the code regions that will be optimized in a "
+             "(CFG BBs and LLVM-IR instructions)"),
+    cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> PollyOnlyViewer(
+    "polly-show-only",
+    cl::desc("Highlight the code regions that will be optimized in "
+             "a (CFG only BBs)"),
+    cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    PollyPrinter("polly-dot", cl::desc("Enable the Polly DOT printer in -O3"),
+                 cl::Hidden, cl::value_desc("Run the Polly DOT printer at -O3"),
+                 cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<bool> PollyOnlyPrinter(
+    "polly-dot-only",
+    cl::desc("Enable the Polly DOT printer in -O3 (no BB content)"), cl::Hidden,
+    cl::value_desc("Run the Polly DOT printer at -O3 (no BB content"),
+    cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    CFGPrinter("polly-view-cfg",
+               cl::desc("Show the Polly CFG right after code generation"),
+               cl::Hidden, cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    EnablePolyhedralInfo("polly-enable-polyhedralinfo",
+                         cl::desc("Enable polyhedral interface of Polly"),
+                         cl::Hidden, cl::init(false), cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    EnableForwardOpTree("polly-enable-optree",
+                        cl::desc("Enable operand tree forwarding"), cl::Hidden,
+                        cl::init(true), cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    DumpBefore("polly-dump-before",
+               cl::desc("Dump module before Polly transformations into a file "
+                        "suffixed with \"-before\""),
+               cl::init(false), cl::cat(PollyCategory));
+
+static cl::list<std::string> DumpBeforeFile(
+    "polly-dump-before-file",
+    cl::desc("Dump module before Polly transformations to the given file"),
+    cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    DumpAfter("polly-dump-after",
+              cl::desc("Dump module after Polly transformations into a file "
+                       "suffixed with \"-after\""),
+              cl::init(false), cl::cat(PollyCategory));
+
+static cl::list<std::string> DumpAfterFile(
+    "polly-dump-after-file",
+    cl::desc("Dump module after Polly transformations to the given file"),
+    cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    EnableDeLICM("polly-enable-delicm",
+                 cl::desc("Eliminate scalar loop carried dependences"),
+                 cl::Hidden, cl::init(true), cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    EnableSimplify("polly-enable-simplify",
+                   cl::desc("Simplify SCoP after optimizations"),
+                   cl::init(true), cl::cat(PollyCategory));
+
+static cl::opt<bool> EnablePruneUnprofitable(
+    "polly-enable-prune-unprofitable",
+    cl::desc("Bail out on unprofitable SCoPs before rescheduling"), cl::Hidden,
+    cl::init(true), cl::cat(PollyCategory));
+
+namespace polly {
+void initializePollyPasses(PassRegistry &Registry) {
+  initializeCodeGenerationPass(Registry);
+
+#ifdef GPU_CODEGEN
+  initializePPCGCodeGenerationPass(Registry);
+  initializeManagedMemoryRewritePassPass(Registry);
+  LLVMInitializeNVPTXTarget();
+  LLVMInitializeNVPTXTargetInfo();
+  LLVMInitializeNVPTXTargetMC();
+  LLVMInitializeNVPTXAsmPrinter();
+#endif
+  initializeCodePreparationPass(Registry);
+  initializeDeadCodeElimPass(Registry);
+  initializeDependenceInfoPass(Registry);
+  initializeDependenceInfoWrapperPassPass(Registry);
+  initializeJSONExporterPass(Registry);
+  initializeJSONImporterPass(Registry);
+  initializeMaximalStaticExpanderPass(Registry);
+  initializeIslAstInfoWrapperPassPass(Registry);
+  initializeIslScheduleOptimizerPass(Registry);
+  initializePollyCanonicalizePass(Registry);
+  initializePolyhedralInfoPass(Registry);
+  initializeScopDetectionWrapperPassPass(Registry);
+  initializeScopInlinerPass(Registry);
+  initializeScopInfoRegionPassPass(Registry);
+  initializeScopInfoWrapperPassPass(Registry);
+  initializeRewriteByrefParamsPass(Registry);
+  initializeCodegenCleanupPass(Registry);
+  initializeFlattenSchedulePass(Registry);
+  initializeForwardOpTreePass(Registry);
+  initializeDeLICMPass(Registry);
+  initializeSimplifyPass(Registry);
+  initializeDumpModulePass(Registry);
+  initializePruneUnprofitablePass(Registry);
+}
+
+/// Register Polly passes such that they form a polyhedral optimizer.
+///
+/// The individual Polly passes are registered in the pass manager such that
+/// they form a full polyhedral optimizer. The flow of the optimizer starts with
+/// a set of preparing transformations that canonicalize the LLVM-IR such that
+/// the LLVM-IR is easier for us to understand and to optimizes. On the
+/// canonicalized LLVM-IR we first run the ScopDetection pass, which detects
+/// static control flow regions. Those regions are then translated by the
+/// ScopInfo pass into a polyhedral representation. As a next step, a scheduling
+/// optimizer is run on the polyhedral representation and finally the optimized
+/// polyhedral representation is code generated back to LLVM-IR.
+///
+/// Besides this core functionality, we optionally schedule passes that provide
+/// a graphical view of the scops (Polly[Only]Viewer, Polly[Only]Printer), that
+/// allow the export/import of the polyhedral representation
+/// (JSCON[Exporter|Importer]) or that show the cfg after code generation.
+///
+/// For certain parts of the Polly optimizer, several alternatives are provided:
+///
+/// As scheduling optimizer we support the isl scheduling optimizer
+/// (http://freecode.com/projects/isl).
+/// It is also possible to run Polly with no optimizer. This mode is mainly
+/// provided to analyze the run and compile time changes caused by the
+/// scheduling optimizer.
+///
+/// Polly supports the isl internal code generator.
+void registerPollyPasses(llvm::legacy::PassManagerBase &PM) {
+  if (DumpBefore)
+    PM.add(polly::createDumpModulePass("-before", true));
+  for (auto &Filename : DumpBeforeFile)
+    PM.add(polly::createDumpModulePass(Filename, false));
+
+  PM.add(polly::createScopDetectionWrapperPassPass());
+
+  if (PollyDetectOnly)
+    return;
+
+  if (PollyViewer)
+    PM.add(polly::createDOTViewerPass());
+  if (PollyOnlyViewer)
+    PM.add(polly::createDOTOnlyViewerPass());
+  if (PollyPrinter)
+    PM.add(polly::createDOTPrinterPass());
+  if (PollyOnlyPrinter)
+    PM.add(polly::createDOTOnlyPrinterPass());
+
+  PM.add(polly::createScopInfoRegionPassPass());
+  if (EnablePolyhedralInfo)
+    PM.add(polly::createPolyhedralInfoPass());
+
+  if (EnableSimplify)
+    PM.add(polly::createSimplifyPass(0));
+  if (EnableForwardOpTree)
+    PM.add(polly::createForwardOpTreePass());
+  if (EnableDeLICM)
+    PM.add(polly::createDeLICMPass());
+  if (EnableSimplify)
+    PM.add(polly::createSimplifyPass(1));
+
+  if (ImportJScop)
+    PM.add(polly::createJSONImporterPass());
+
+  if (DeadCodeElim)
+    PM.add(polly::createDeadCodeElimPass());
+
+  if (FullyIndexedStaticExpansion)
+    PM.add(polly::createMaximalStaticExpansionPass());
+
+  if (EnablePruneUnprofitable)
+    PM.add(polly::createPruneUnprofitablePass());
+
+#ifdef GPU_CODEGEN
+  if (Target == TARGET_HYBRID) {
+    PM.add(
+        polly::createPPCGCodeGenerationPass(GPUArchChoice, GPURuntimeChoice));
+    PM.add(polly::createManagedMemoryRewritePassPass(GPUArchChoice,
+                                                     GPURuntimeChoice));
+  }
+#endif
+  if (Target == TARGET_CPU || Target == TARGET_HYBRID)
+    switch (Optimizer) {
+    case OPTIMIZER_NONE:
+      break; /* Do nothing */
+
+    case OPTIMIZER_ISL:
+      PM.add(polly::createIslScheduleOptimizerPass());
+      break;
+    }
+
+  if (ExportJScop)
+    PM.add(polly::createJSONExporterPass());
+
+  if (Target == TARGET_CPU || Target == TARGET_HYBRID)
+    switch (CodeGeneration) {
+    case CODEGEN_AST:
+      PM.add(polly::createIslAstInfoWrapperPassPass());
+      break;
+    case CODEGEN_FULL:
+      PM.add(polly::createCodeGenerationPass());
+      break;
+    case CODEGEN_NONE:
+      break;
+    }
+#ifdef GPU_CODEGEN
+  else {
+    PM.add(
+        polly::createPPCGCodeGenerationPass(GPUArchChoice, GPURuntimeChoice));
+    PM.add(polly::createManagedMemoryRewritePassPass());
+  }
+#endif
+
+  // FIXME: This dummy ModulePass keeps some programs from miscompiling,
+  // probably some not correctly preserved analyses. It acts as a barrier to
+  // force all analysis results to be recomputed.
+  PM.add(createBarrierNoopPass());
+
+  if (DumpAfter)
+    PM.add(polly::createDumpModulePass("-after", true));
+  for (auto &Filename : DumpAfterFile)
+    PM.add(polly::createDumpModulePass(Filename, false));
+
+  if (CFGPrinter)
+    PM.add(llvm::createCFGPrinterLegacyPassPass());
+}
+
+static bool shouldEnablePolly() {
+  if (PollyOnlyPrinter || PollyPrinter || PollyOnlyViewer || PollyViewer)
+    PollyTrackFailures = true;
+
+  if (PollyOnlyPrinter || PollyPrinter || PollyOnlyViewer || PollyViewer ||
+      ExportJScop || ImportJScop)
+    PollyEnabled = true;
+
+  return PollyEnabled;
+}
+
+static void
+registerPollyEarlyAsPossiblePasses(const llvm::PassManagerBuilder &Builder,
+                                   llvm::legacy::PassManagerBase &PM) {
+  if (!polly::shouldEnablePolly())
+    return;
+
+  if (PassPosition != POSITION_EARLY)
+    return;
+
+  registerCanonicalicationPasses(PM);
+  polly::registerPollyPasses(PM);
+}
+
+static void
+registerPollyLoopOptimizerEndPasses(const llvm::PassManagerBuilder &Builder,
+                                    llvm::legacy::PassManagerBase &PM) {
+  if (!polly::shouldEnablePolly())
+    return;
+
+  if (PassPosition != POSITION_AFTER_LOOPOPT)
+    return;
+
+  PM.add(polly::createCodePreparationPass());
+  polly::registerPollyPasses(PM);
+  PM.add(createCodegenCleanupPass());
+}
+
+static void
+registerPollyScalarOptimizerLatePasses(const llvm::PassManagerBuilder &Builder,
+                                       llvm::legacy::PassManagerBase &PM) {
+  if (!polly::shouldEnablePolly())
+    return;
+
+  if (PassPosition != POSITION_BEFORE_VECTORIZER)
+    return;
+
+  PM.add(polly::createCodePreparationPass());
+  polly::registerPollyPasses(PM);
+  PM.add(createCodegenCleanupPass());
+}
+
+static void buildDefaultPollyPipeline(FunctionPassManager &PM,
+                                      PassBuilder::OptimizationLevel Level) {
+  if (!polly::shouldEnablePolly())
+    return;
+  PassBuilder PB;
+  ScopPassManager SPM;
+
+  // TODO add utility passes for the various command line options, once they're
+  // ported
+  assert(!DumpBefore && "This option is not implemented");
+  assert(DumpBeforeFile.empty() && "This option is not implemented");
+
+  if (PollyDetectOnly)
+    return;
+
+  assert(!PollyViewer && "This option is not implemented");
+  assert(!PollyOnlyViewer && "This option is not implemented");
+  assert(!PollyPrinter && "This option is not implemented");
+  assert(!PollyOnlyPrinter && "This option is not implemented");
+  assert(!EnablePolyhedralInfo && "This option is not implemented");
+  assert(!EnableDeLICM && "This option is not implemented");
+  assert(!EnableSimplify && "This option is not implemented");
+  if (ImportJScop)
+    SPM.addPass(JSONImportPass());
+  assert(!DeadCodeElim && "This option is not implemented");
+  assert(!EnablePruneUnprofitable && "This option is not implemented");
+  if (Target == TARGET_CPU || Target == TARGET_HYBRID)
+    switch (Optimizer) {
+    case OPTIMIZER_NONE:
+      break; /* Do nothing */
+    case OPTIMIZER_ISL:
+      llvm_unreachable("ISL optimizer is not implemented");
+      break;
+    }
+
+  assert(!ExportJScop && "This option is not implemented");
+
+  if (Target == TARGET_CPU || Target == TARGET_HYBRID) {
+    switch (CodeGeneration) {
+    case CODEGEN_FULL:
+      SPM.addPass(polly::CodeGenerationPass());
+      break;
+    case CODEGEN_AST:
+    default: // Does it actually make sense to distinguish IslAst codegen?
+      break;
+    }
+  }
+#ifdef GPU_CODEGEN
+  else
+    llvm_unreachable("Hybrid Target with GPU support is not implemented");
+#endif
+
+  PM.addPass(CodePreparationPass());
+  PM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
+  PM.addPass(PB.buildFunctionSimplificationPipeline(
+      Level, PassBuilder::ThinLTOPhase::None)); // Cleanup
+
+  assert(!DumpAfter && "This option is not implemented");
+  assert(DumpAfterFile.empty() && "This option is not implemented");
+
+  if (CFGPrinter)
+    PM.addPass(llvm::CFGPrinterPass());
+}
+
+/// Register Polly to be available as an optimizer
+///
+///
+/// We can currently run Polly at three different points int the pass manager.
+/// a) very early, b) after the canonicalizing loop transformations and c) right
+/// before the vectorizer.
+///
+/// The default is currently a), to register Polly such that it runs as early as
+/// possible. This has several implications:
+///
+///   1) We need to schedule more canonicalization passes
+///
+///   As nothing is run before Polly, it is necessary to run a set of preparing
+///   transformations before Polly to canonicalize the LLVM-IR and to allow
+///   Polly to detect and understand the code.
+///
+///   2) LICM and LoopIdiom pass have not yet been run
+///
+///   Loop invariant code motion as well as the loop idiom recognition pass make
+///   it more difficult for Polly to transform code. LICM may introduce
+///   additional data dependences that are hard to eliminate and the loop idiom
+///   recognition pass may introduce calls to memset that we currently do not
+///   understand. By running Polly early enough (meaning before these passes) we
+///   avoid difficulties that may be introduced by these passes.
+///
+///   3) We get the full -O3 optimization sequence after Polly
+///
+///   The LLVM-IR that is generated by Polly has been optimized on a high level,
+///   but it may be rather inefficient on the lower/scalar level. By scheduling
+///   Polly before all other passes, we have the full sequence of -O3
+///   optimizations behind us, such that inefficiencies on the low level can
+///   be optimized away.
+///
+/// We are currently evaluating the benefit or running Polly at position b) or
+/// c). b) is likely too early as it interacts with the inliner. c) is nice
+/// as everything is fully inlined and canonicalized, but we need to be able
+/// to handle LICMed code to make it useful.
+static llvm::RegisterStandardPasses RegisterPollyOptimizerEarly(
+    llvm::PassManagerBuilder::EP_ModuleOptimizerEarly,
+    registerPollyEarlyAsPossiblePasses);
+
+static llvm::RegisterStandardPasses
+    RegisterPollyOptimizerLoopEnd(llvm::PassManagerBuilder::EP_LoopOptimizerEnd,
+                                  registerPollyLoopOptimizerEndPasses);
+
+static llvm::RegisterStandardPasses RegisterPollyOptimizerScalarLate(
+    llvm::PassManagerBuilder::EP_VectorizerStart,
+    registerPollyScalarOptimizerLatePasses);
+
+static OwningScopAnalysisManagerFunctionProxy
+createScopAnalyses(FunctionAnalysisManager &FAM) {
+  OwningScopAnalysisManagerFunctionProxy Proxy;
+#define SCOP_ANALYSIS(NAME, CREATE_PASS)                                       \
+  Proxy.getManager().registerPass([] { return CREATE_PASS; });
+
+#include "PollyPasses.def"
+
+  Proxy.getManager().registerPass(
+      [&FAM] { return FunctionAnalysisManagerScopProxy(FAM); });
+  return Proxy;
+}
+
+static void registerFunctionAnalyses(FunctionAnalysisManager &FAM) {
+#define FUNCTION_ANALYSIS(NAME, CREATE_PASS)                                   \
+  FAM.registerPass([] { return CREATE_PASS; });
+
+#include "PollyPasses.def"
+
+  FAM.registerPass([&FAM] { return createScopAnalyses(FAM); });
+}
+
+static bool
+parseFunctionPipeline(StringRef Name, FunctionPassManager &FPM,
+                      ArrayRef<PassBuilder::PipelineElement> Pipeline) {
+  if (parseAnalysisUtilityPasses<OwningScopAnalysisManagerFunctionProxy>(
+          "polly-scop-analyses", Name, FPM))
+    return true;
+
+#define FUNCTION_ANALYSIS(NAME, CREATE_PASS)                                   \
+  if (parseAnalysisUtilityPasses<                                              \
+          std::remove_reference<decltype(CREATE_PASS)>::type>(NAME, Name,      \
+                                                              FPM))            \
+    return true;
+
+#define FUNCTION_PASS(NAME, CREATE_PASS)                                       \
+  if (Name == NAME) {                                                          \
+    FPM.addPass(CREATE_PASS);                                                  \
+    return true;                                                               \
+  }
+
+#include "PollyPasses.def"
+  return false;
+}
+
+static bool parseScopPass(StringRef Name, ScopPassManager &SPM) {
+#define SCOP_ANALYSIS(NAME, CREATE_PASS)                                       \
+  if (parseAnalysisUtilityPasses<                                              \
+          std::remove_reference<decltype(CREATE_PASS)>::type>(NAME, Name,      \
+                                                              SPM))            \
+    return true;
+
+#define SCOP_PASS(NAME, CREATE_PASS)                                           \
+  if (Name == NAME) {                                                          \
+    SPM.addPass(CREATE_PASS);                                                  \
+    return true;                                                               \
+  }
+
+#include "PollyPasses.def"
+
+  return false;
+}
+
+static bool parseScopPipeline(StringRef Name, FunctionPassManager &FPM,
+                              ArrayRef<PassBuilder::PipelineElement> Pipeline) {
+  if (Name != "scop")
+    return false;
+  if (!Pipeline.empty()) {
+    ScopPassManager SPM;
+    for (const auto &E : Pipeline)
+      if (!parseScopPass(E.Name, SPM))
+        return false;
+    FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
+  }
+  return true;
+}
+
+static bool isScopPassName(StringRef Name) {
+#define SCOP_ANALYSIS(NAME, CREATE_PASS)                                       \
+  if (Name == "require<" NAME ">")                                             \
+    return true;                                                               \
+  if (Name == "invalidate<" NAME ">")                                          \
+    return true;
+
+#define SCOP_PASS(NAME, CREATE_PASS)                                           \
+  if (Name == NAME)                                                            \
+    return true;
+
+#include "PollyPasses.def"
+
+  return false;
+}
+
+static bool
+parseTopLevelPipeline(ModulePassManager &MPM,
+                      ArrayRef<PassBuilder::PipelineElement> Pipeline,
+                      bool VerifyEachPass, bool DebugLogging) {
+  std::vector<PassBuilder::PipelineElement> FullPipeline;
+  StringRef FirstName = Pipeline.front().Name;
+
+  if (!isScopPassName(FirstName))
+    return false;
+
+  FunctionPassManager FPM(DebugLogging);
+  ScopPassManager SPM(DebugLogging);
+
+  for (auto &Element : Pipeline) {
+    auto &Name = Element.Name;
+    auto &InnerPipeline = Element.InnerPipeline;
+    if (!InnerPipeline.empty()) // Scop passes don't have inner pipelines
+      return false;
+    if (!parseScopPass(Name, SPM))
+      return false;
+  }
+
+  FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
+  if (VerifyEachPass)
+    FPM.addPass(VerifierPass());
+  MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
+  if (VerifyEachPass)
+    MPM.addPass(VerifierPass());
+
+  return true;
+}
+
+void RegisterPollyPasses(PassBuilder &PB) {
+  PB.registerAnalysisRegistrationCallback(registerFunctionAnalyses);
+  PB.registerPipelineParsingCallback(parseFunctionPipeline);
+  PB.registerPipelineParsingCallback(parseScopPipeline);
+  PB.registerParseTopLevelPipelineCallback(parseTopLevelPipeline);
+
+  if (PassPosition == POSITION_BEFORE_VECTORIZER)
+    PB.registerVectorizerStartEPCallback(buildDefaultPollyPipeline);
+  // FIXME else Error?
+}
+} // namespace polly
diff --git a/final/lib/Support/SCEVAffinator.cpp b/final/lib/Support/SCEVAffinator.cpp
new file mode 100644
index 0000000..5be900d
--- /dev/null
+++ b/final/lib/Support/SCEVAffinator.cpp
@@ -0,0 +1,534 @@
+//===--------- SCEVAffinator.cpp  - Create Scops from LLVM IR -------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Create a polyhedral description for a SCEV value.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/Support/SCEVAffinator.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/SCEVValidator.h"
+#include "polly/Support/ScopHelper.h"
+#include "isl/aff.h"
+#include "isl/local_space.h"
+#include "isl/set.h"
+#include "isl/val.h"
+
+using namespace llvm;
+using namespace polly;
+
+static cl::opt<bool> IgnoreIntegerWrapping(
+    "polly-ignore-integer-wrapping",
+    cl::desc("Do not build run-time checks to proof absence of integer "
+             "wrapping"),
+    cl::Hidden, cl::ZeroOrMore, cl::init(false), cl::cat(PollyCategory));
+
+// The maximal number of basic sets we allow during the construction of a
+// piecewise affine function. More complex ones will result in very high
+// compile time.
+static int const MaxDisjunctionsInPwAff = 100;
+
+// The maximal number of bits for which a general expression is modeled
+// precisely.
+static unsigned const MaxSmallBitWidth = 7;
+
+/// Add the number of basic sets in @p Domain to @p User
+static isl_stat addNumBasicSets(__isl_take isl_set *Domain,
+                                __isl_take isl_aff *Aff, void *User) {
+  auto *NumBasicSets = static_cast<unsigned *>(User);
+  *NumBasicSets += isl_set_n_basic_set(Domain);
+  isl_set_free(Domain);
+  isl_aff_free(Aff);
+  return isl_stat_ok;
+}
+
+/// Determine if @p PWAC is too complex to continue.
+static bool isTooComplex(PWACtx PWAC) {
+  unsigned NumBasicSets = 0;
+  isl_pw_aff_foreach_piece(PWAC.first.keep(), addNumBasicSets, &NumBasicSets);
+  if (NumBasicSets <= MaxDisjunctionsInPwAff)
+    return false;
+  return true;
+}
+
+/// Return the flag describing the possible wrapping of @p Expr.
+static SCEV::NoWrapFlags getNoWrapFlags(const SCEV *Expr) {
+  if (auto *NAry = dyn_cast<SCEVNAryExpr>(Expr))
+    return NAry->getNoWrapFlags();
+  return SCEV::NoWrapMask;
+}
+
+static PWACtx combine(PWACtx PWAC0, PWACtx PWAC1,
+                      __isl_give isl_pw_aff *(Fn)(__isl_take isl_pw_aff *,
+                                                  __isl_take isl_pw_aff *)) {
+  PWAC0.first = isl::manage(Fn(PWAC0.first.take(), PWAC1.first.take()));
+  PWAC0.second = PWAC0.second.unite(PWAC1.second);
+  return PWAC0;
+}
+
+static __isl_give isl_pw_aff *getWidthExpValOnDomain(unsigned Width,
+                                                     __isl_take isl_set *Dom) {
+  auto *Ctx = isl_set_get_ctx(Dom);
+  auto *WidthVal = isl_val_int_from_ui(Ctx, Width);
+  auto *ExpVal = isl_val_2exp(WidthVal);
+  return isl_pw_aff_val_on_domain(Dom, ExpVal);
+}
+
+SCEVAffinator::SCEVAffinator(Scop *S, LoopInfo &LI)
+    : S(S), Ctx(S->getIslCtx().get()), SE(*S->getSE()), LI(LI),
+      TD(S->getFunction().getParent()->getDataLayout()) {}
+
+Loop *SCEVAffinator::getScope() { return BB ? LI.getLoopFor(BB) : nullptr; }
+
+void SCEVAffinator::interpretAsUnsigned(PWACtx &PWAC, unsigned Width) {
+  auto *NonNegDom = isl_pw_aff_nonneg_set(PWAC.first.copy());
+  auto *NonNegPWA =
+      isl_pw_aff_intersect_domain(PWAC.first.copy(), isl_set_copy(NonNegDom));
+  auto *ExpPWA = getWidthExpValOnDomain(Width, isl_set_complement(NonNegDom));
+  PWAC.first = isl::manage(isl_pw_aff_union_add(
+      NonNegPWA, isl_pw_aff_add(PWAC.first.take(), ExpPWA)));
+}
+
+void SCEVAffinator::takeNonNegativeAssumption(PWACtx &PWAC) {
+  auto *NegPWA = isl_pw_aff_neg(PWAC.first.copy());
+  auto *NegDom = isl_pw_aff_pos_set(NegPWA);
+  PWAC.second =
+      isl::manage(isl_set_union(PWAC.second.take(), isl_set_copy(NegDom)));
+  auto *Restriction = BB ? NegDom : isl_set_params(NegDom);
+  auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc();
+  S->recordAssumption(UNSIGNED, isl::manage(Restriction), DL, AS_RESTRICTION,
+                      BB);
+}
+
+PWACtx SCEVAffinator::getPWACtxFromPWA(isl::pw_aff PWA) {
+  return std::make_pair(PWA, isl::set::empty(isl::space(Ctx, 0, NumIterators)));
+}
+
+PWACtx SCEVAffinator::getPwAff(const SCEV *Expr, BasicBlock *BB) {
+  this->BB = BB;
+
+  if (BB) {
+    auto *DC = S->getDomainConditions(BB).release();
+    NumIterators = isl_set_n_dim(DC);
+    isl_set_free(DC);
+  } else
+    NumIterators = 0;
+
+  return visit(Expr);
+}
+
+PWACtx SCEVAffinator::checkForWrapping(const SCEV *Expr, PWACtx PWAC) const {
+  // If the SCEV flags do contain NSW (no signed wrap) then PWA already
+  // represents Expr in modulo semantic (it is not allowed to overflow), thus we
+  // are done. Otherwise, we will compute:
+  //   PWA = ((PWA + 2^(n-1)) mod (2 ^ n)) - 2^(n-1)
+  // whereas n is the number of bits of the Expr, hence:
+  //   n = bitwidth(ExprType)
+
+  if (IgnoreIntegerWrapping || (getNoWrapFlags(Expr) & SCEV::FlagNSW))
+    return PWAC;
+
+  isl::pw_aff PWAMod = addModuloSemantic(PWAC.first, Expr->getType());
+
+  isl::set NotEqualSet = PWAC.first.ne_set(PWAMod);
+  PWAC.second = PWAC.second.unite(NotEqualSet).coalesce();
+
+  const DebugLoc &Loc = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc();
+  if (!BB)
+    NotEqualSet = NotEqualSet.params();
+  NotEqualSet = NotEqualSet.coalesce();
+
+  if (!NotEqualSet.is_empty())
+    S->recordAssumption(WRAPPING, NotEqualSet, Loc, AS_RESTRICTION, BB);
+
+  return PWAC;
+}
+
+isl::pw_aff SCEVAffinator::addModuloSemantic(isl::pw_aff PWA,
+                                             Type *ExprType) const {
+  unsigned Width = TD.getTypeSizeInBits(ExprType);
+
+  auto ModVal = isl::val::int_from_ui(Ctx, Width);
+  ModVal = ModVal.two_exp();
+
+  isl::set Domain = PWA.domain();
+  isl::pw_aff AddPW =
+      isl::manage(getWidthExpValOnDomain(Width - 1, Domain.take()));
+  return PWA.add(AddPW).mod(ModVal).sub(AddPW);
+}
+
+bool SCEVAffinator::hasNSWAddRecForLoop(Loop *L) const {
+  for (const auto &CachedPair : CachedExpressions) {
+    auto *AddRec = dyn_cast<SCEVAddRecExpr>(CachedPair.first.first);
+    if (!AddRec)
+      continue;
+    if (AddRec->getLoop() != L)
+      continue;
+    if (AddRec->getNoWrapFlags() & SCEV::FlagNSW)
+      return true;
+  }
+
+  return false;
+}
+
+bool SCEVAffinator::computeModuloForExpr(const SCEV *Expr) {
+  unsigned Width = TD.getTypeSizeInBits(Expr->getType());
+  // We assume nsw expressions never overflow.
+  if (auto *NAry = dyn_cast<SCEVNAryExpr>(Expr))
+    if (NAry->getNoWrapFlags() & SCEV::FlagNSW)
+      return false;
+  return Width <= MaxSmallBitWidth;
+}
+
+PWACtx SCEVAffinator::visit(const SCEV *Expr) {
+
+  auto Key = std::make_pair(Expr, BB);
+  PWACtx PWAC = CachedExpressions[Key];
+  if (PWAC.first)
+    return PWAC;
+
+  auto ConstantAndLeftOverPair = extractConstantFactor(Expr, SE);
+  auto *Factor = ConstantAndLeftOverPair.first;
+  Expr = ConstantAndLeftOverPair.second;
+
+  auto *Scope = getScope();
+  S->addParams(getParamsInAffineExpr(&S->getRegion(), Scope, Expr, SE));
+
+  // In case the scev is a valid parameter, we do not further analyze this
+  // expression, but create a new parameter in the isl_pw_aff. This allows us
+  // to treat subexpressions that we cannot translate into an piecewise affine
+  // expression, as constant parameters of the piecewise affine expression.
+  if (isl_id *Id = S->getIdForParam(Expr).release()) {
+    isl_space *Space = isl_space_set_alloc(Ctx.get(), 1, NumIterators);
+    Space = isl_space_set_dim_id(Space, isl_dim_param, 0, Id);
+
+    isl_set *Domain = isl_set_universe(isl_space_copy(Space));
+    isl_aff *Affine = isl_aff_zero_on_domain(isl_local_space_from_space(Space));
+    Affine = isl_aff_add_coefficient_si(Affine, isl_dim_param, 0, 1);
+
+    PWAC = getPWACtxFromPWA(isl::manage(isl_pw_aff_alloc(Domain, Affine)));
+  } else {
+    PWAC = SCEVVisitor<SCEVAffinator, PWACtx>::visit(Expr);
+    if (computeModuloForExpr(Expr))
+      PWAC.first = addModuloSemantic(PWAC.first, Expr->getType());
+    else
+      PWAC = checkForWrapping(Expr, PWAC);
+  }
+
+  if (!Factor->getType()->isIntegerTy(1)) {
+    PWAC = combine(PWAC, visitConstant(Factor), isl_pw_aff_mul);
+    if (computeModuloForExpr(Key.first))
+      PWAC.first = addModuloSemantic(PWAC.first, Expr->getType());
+  }
+
+  // For compile time reasons we need to simplify the PWAC before we cache and
+  // return it.
+  PWAC.first = PWAC.first.coalesce();
+  if (!computeModuloForExpr(Key.first))
+    PWAC = checkForWrapping(Key.first, PWAC);
+
+  CachedExpressions[Key] = PWAC;
+  return PWAC;
+}
+
+PWACtx SCEVAffinator::visitConstant(const SCEVConstant *Expr) {
+  ConstantInt *Value = Expr->getValue();
+  isl_val *v;
+
+  // LLVM does not define if an integer value is interpreted as a signed or
+  // unsigned value. Hence, without further information, it is unknown how
+  // this value needs to be converted to GMP. At the moment, we only support
+  // signed operations. So we just interpret it as signed. Later, there are
+  // two options:
+  //
+  // 1. We always interpret any value as signed and convert the values on
+  //    demand.
+  // 2. We pass down the signedness of the calculation and use it to interpret
+  //    this constant correctly.
+  v = isl_valFromAPInt(Ctx.get(), Value->getValue(), /* isSigned */ true);
+
+  isl_space *Space = isl_space_set_alloc(Ctx.get(), 0, NumIterators);
+  isl_local_space *ls = isl_local_space_from_space(Space);
+  return getPWACtxFromPWA(
+      isl::manage(isl_pw_aff_from_aff(isl_aff_val_on_domain(ls, v))));
+}
+
+PWACtx SCEVAffinator::visitTruncateExpr(const SCEVTruncateExpr *Expr) {
+  // Truncate operations are basically modulo operations, thus we can
+  // model them that way. However, for large types we assume the operand
+  // to fit in the new type size instead of introducing a modulo with a very
+  // large constant.
+
+  auto *Op = Expr->getOperand();
+  auto OpPWAC = visit(Op);
+
+  unsigned Width = TD.getTypeSizeInBits(Expr->getType());
+
+  if (computeModuloForExpr(Expr))
+    return OpPWAC;
+
+  auto *Dom = OpPWAC.first.domain().take();
+  auto *ExpPWA = getWidthExpValOnDomain(Width - 1, Dom);
+  auto *GreaterDom =
+      isl_pw_aff_ge_set(OpPWAC.first.copy(), isl_pw_aff_copy(ExpPWA));
+  auto *SmallerDom =
+      isl_pw_aff_lt_set(OpPWAC.first.copy(), isl_pw_aff_neg(ExpPWA));
+  auto *OutOfBoundsDom = isl_set_union(SmallerDom, GreaterDom);
+  OpPWAC.second =
+      OpPWAC.second.unite(isl::manage(isl_set_copy(OutOfBoundsDom)));
+
+  if (!BB) {
+    assert(isl_set_dim(OutOfBoundsDom, isl_dim_set) == 0 &&
+           "Expected a zero dimensional set for non-basic-block domains");
+    OutOfBoundsDom = isl_set_params(OutOfBoundsDom);
+  }
+
+  S->recordAssumption(UNSIGNED, isl::manage(OutOfBoundsDom), DebugLoc(),
+                      AS_RESTRICTION, BB);
+
+  return OpPWAC;
+}
+
+PWACtx SCEVAffinator::visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
+  // A zero-extended value can be interpreted as a piecewise defined signed
+  // value. If the value was non-negative it stays the same, otherwise it
+  // is the sum of the original value and 2^n where n is the bit-width of
+  // the original (or operand) type. Examples:
+  //   zext i8 127 to i32 -> { [127] }
+  //   zext i8  -1 to i32 -> { [256 + (-1)] } = { [255] }
+  //   zext i8  %v to i32 -> [v] -> { [v] | v >= 0; [256 + v] | v < 0 }
+  //
+  // However, LLVM/Scalar Evolution uses zero-extend (potentially lead by a
+  // truncate) to represent some forms of modulo computation. The left-hand side
+  // of the condition in the code below would result in the SCEV
+  // "zext i1 <false, +, true>for.body" which is just another description
+  // of the C expression "i & 1 != 0" or, equivalently, "i % 2 != 0".
+  //
+  //   for (i = 0; i < N; i++)
+  //     if (i & 1 != 0 /* == i % 2 */)
+  //       /* do something */
+  //
+  // If we do not make the modulo explicit but only use the mechanism described
+  // above we will get the very restrictive assumption "N < 3", because for all
+  // values of N >= 3 the SCEVAddRecExpr operand of the zero-extend would wrap.
+  // Alternatively, we can make the modulo in the operand explicit in the
+  // resulting piecewise function and thereby avoid the assumption on N. For the
+  // example this would result in the following piecewise affine function:
+  // { [i0] -> [(1)] : 2*floor((-1 + i0)/2) = -1 + i0;
+  //   [i0] -> [(0)] : 2*floor((i0)/2) = i0 }
+  // To this end we can first determine if the (immediate) operand of the
+  // zero-extend can wrap and, in case it might, we will use explicit modulo
+  // semantic to compute the result instead of emitting non-wrapping
+  // assumptions.
+  //
+  // Note that operands with large bit-widths are less likely to be negative
+  // because it would result in a very large access offset or loop bound after
+  // the zero-extend. To this end one can optimistically assume the operand to
+  // be positive and avoid the piecewise definition if the bit-width is bigger
+  // than some threshold (here MaxZextSmallBitWidth).
+  //
+  // We choose to go with a hybrid solution of all modeling techniques described
+  // above. For small bit-widths (up to MaxZextSmallBitWidth) we will model the
+  // wrapping explicitly and use a piecewise defined function. However, if the
+  // bit-width is bigger than MaxZextSmallBitWidth we will employ overflow
+  // assumptions and assume the "former negative" piece will not exist.
+
+  auto *Op = Expr->getOperand();
+  auto OpPWAC = visit(Op);
+
+  // If the width is to big we assume the negative part does not occur.
+  if (!computeModuloForExpr(Op)) {
+    takeNonNegativeAssumption(OpPWAC);
+    return OpPWAC;
+  }
+
+  // If the width is small build the piece for the non-negative part and
+  // the one for the negative part and unify them.
+  unsigned Width = TD.getTypeSizeInBits(Op->getType());
+  interpretAsUnsigned(OpPWAC, Width);
+  return OpPWAC;
+}
+
+PWACtx SCEVAffinator::visitSignExtendExpr(const SCEVSignExtendExpr *Expr) {
+  // As all values are represented as signed, a sign extension is a noop.
+  return visit(Expr->getOperand());
+}
+
+PWACtx SCEVAffinator::visitAddExpr(const SCEVAddExpr *Expr) {
+  PWACtx Sum = visit(Expr->getOperand(0));
+
+  for (int i = 1, e = Expr->getNumOperands(); i < e; ++i) {
+    Sum = combine(Sum, visit(Expr->getOperand(i)), isl_pw_aff_add);
+    if (isTooComplex(Sum))
+      return std::make_pair(nullptr, nullptr);
+  }
+
+  return Sum;
+}
+
+PWACtx SCEVAffinator::visitMulExpr(const SCEVMulExpr *Expr) {
+  PWACtx Prod = visit(Expr->getOperand(0));
+
+  for (int i = 1, e = Expr->getNumOperands(); i < e; ++i) {
+    Prod = combine(Prod, visit(Expr->getOperand(i)), isl_pw_aff_mul);
+    if (isTooComplex(Prod))
+      return std::make_pair(nullptr, nullptr);
+  }
+
+  return Prod;
+}
+
+PWACtx SCEVAffinator::visitAddRecExpr(const SCEVAddRecExpr *Expr) {
+  assert(Expr->isAffine() && "Only affine AddRecurrences allowed");
+
+  auto Flags = Expr->getNoWrapFlags();
+
+  // Directly generate isl_pw_aff for Expr if 'start' is zero.
+  if (Expr->getStart()->isZero()) {
+    assert(S->contains(Expr->getLoop()) &&
+           "Scop does not contain the loop referenced in this AddRec");
+
+    PWACtx Step = visit(Expr->getOperand(1));
+    isl_space *Space = isl_space_set_alloc(Ctx.get(), 0, NumIterators);
+    isl_local_space *LocalSpace = isl_local_space_from_space(Space);
+
+    unsigned loopDimension = S->getRelativeLoopDepth(Expr->getLoop());
+
+    isl_aff *LAff = isl_aff_set_coefficient_si(
+        isl_aff_zero_on_domain(LocalSpace), isl_dim_in, loopDimension, 1);
+    isl_pw_aff *LPwAff = isl_pw_aff_from_aff(LAff);
+
+    Step.first = Step.first.mul(isl::manage(LPwAff));
+    return Step;
+  }
+
+  // Translate AddRecExpr from '{start, +, inc}' into 'start + {0, +, inc}'
+  // if 'start' is not zero.
+  // TODO: Using the original SCEV no-wrap flags is not always safe, however
+  //       as our code generation is reordering the expression anyway it doesn't
+  //       really matter.
+  const SCEV *ZeroStartExpr =
+      SE.getAddRecExpr(SE.getConstant(Expr->getStart()->getType(), 0),
+                       Expr->getStepRecurrence(SE), Expr->getLoop(), Flags);
+
+  PWACtx Result = visit(ZeroStartExpr);
+  PWACtx Start = visit(Expr->getStart());
+  Result = combine(Result, Start, isl_pw_aff_add);
+  return Result;
+}
+
+PWACtx SCEVAffinator::visitSMaxExpr(const SCEVSMaxExpr *Expr) {
+  PWACtx Max = visit(Expr->getOperand(0));
+
+  for (int i = 1, e = Expr->getNumOperands(); i < e; ++i) {
+    Max = combine(Max, visit(Expr->getOperand(i)), isl_pw_aff_max);
+    if (isTooComplex(Max))
+      return std::make_pair(nullptr, nullptr);
+  }
+
+  return Max;
+}
+
+PWACtx SCEVAffinator::visitUMaxExpr(const SCEVUMaxExpr *Expr) {
+  llvm_unreachable("SCEVUMaxExpr not yet supported");
+}
+
+PWACtx SCEVAffinator::visitUDivExpr(const SCEVUDivExpr *Expr) {
+  // The handling of unsigned division is basically the same as for signed
+  // division, except the interpretation of the operands. As the divisor
+  // has to be constant in both cases we can simply interpret it as an
+  // unsigned value without additional complexity in the representation.
+  // For the dividend we could choose from the different representation
+  // schemes introduced for zero-extend operations but for now we will
+  // simply use an assumption.
+  auto *Dividend = Expr->getLHS();
+  auto *Divisor = Expr->getRHS();
+  assert(isa<SCEVConstant>(Divisor) &&
+         "UDiv is no parameter but has a non-constant RHS.");
+
+  auto DividendPWAC = visit(Dividend);
+  auto DivisorPWAC = visit(Divisor);
+
+  if (SE.isKnownNegative(Divisor)) {
+    // Interpret negative divisors unsigned. This is a special case of the
+    // piece-wise defined value described for zero-extends as we already know
+    // the actual value of the constant divisor.
+    unsigned Width = TD.getTypeSizeInBits(Expr->getType());
+    auto *DivisorDom = DivisorPWAC.first.domain().take();
+    auto *WidthExpPWA = getWidthExpValOnDomain(Width, DivisorDom);
+    DivisorPWAC.first = DivisorPWAC.first.add(isl::manage(WidthExpPWA));
+  }
+
+  // TODO: One can represent the dividend as piece-wise function to be more
+  //       precise but therefor a heuristic is needed.
+
+  // Assume a non-negative dividend.
+  takeNonNegativeAssumption(DividendPWAC);
+
+  DividendPWAC = combine(DividendPWAC, DivisorPWAC, isl_pw_aff_div);
+  DividendPWAC.first = DividendPWAC.first.floor();
+
+  return DividendPWAC;
+}
+
+PWACtx SCEVAffinator::visitSDivInstruction(Instruction *SDiv) {
+  assert(SDiv->getOpcode() == Instruction::SDiv && "Assumed SDiv instruction!");
+
+  auto *Scope = getScope();
+  auto *Divisor = SDiv->getOperand(1);
+  auto *DivisorSCEV = SE.getSCEVAtScope(Divisor, Scope);
+  auto DivisorPWAC = visit(DivisorSCEV);
+  assert(isa<SCEVConstant>(DivisorSCEV) &&
+         "SDiv is no parameter but has a non-constant RHS.");
+
+  auto *Dividend = SDiv->getOperand(0);
+  auto *DividendSCEV = SE.getSCEVAtScope(Dividend, Scope);
+  auto DividendPWAC = visit(DividendSCEV);
+  DividendPWAC = combine(DividendPWAC, DivisorPWAC, isl_pw_aff_tdiv_q);
+  return DividendPWAC;
+}
+
+PWACtx SCEVAffinator::visitSRemInstruction(Instruction *SRem) {
+  assert(SRem->getOpcode() == Instruction::SRem && "Assumed SRem instruction!");
+
+  auto *Scope = getScope();
+  auto *Divisor = SRem->getOperand(1);
+  auto *DivisorSCEV = SE.getSCEVAtScope(Divisor, Scope);
+  auto DivisorPWAC = visit(DivisorSCEV);
+  assert(isa<ConstantInt>(Divisor) &&
+         "SRem is no parameter but has a non-constant RHS.");
+
+  auto *Dividend = SRem->getOperand(0);
+  auto *DividendSCEV = SE.getSCEVAtScope(Dividend, Scope);
+  auto DividendPWAC = visit(DividendSCEV);
+  DividendPWAC = combine(DividendPWAC, DivisorPWAC, isl_pw_aff_tdiv_r);
+  return DividendPWAC;
+}
+
+PWACtx SCEVAffinator::visitUnknown(const SCEVUnknown *Expr) {
+  if (Instruction *I = dyn_cast<Instruction>(Expr->getValue())) {
+    switch (I->getOpcode()) {
+    case Instruction::IntToPtr:
+      return visit(SE.getSCEVAtScope(I->getOperand(0), getScope()));
+    case Instruction::PtrToInt:
+      return visit(SE.getSCEVAtScope(I->getOperand(0), getScope()));
+    case Instruction::SDiv:
+      return visitSDivInstruction(I);
+    case Instruction::SRem:
+      return visitSRemInstruction(I);
+    default:
+      break; // Fall through.
+    }
+  }
+
+  llvm_unreachable(
+      "Unknowns SCEV was neither parameter nor a valid instruction.");
+}
diff --git a/final/lib/Support/SCEVValidator.cpp b/final/lib/Support/SCEVValidator.cpp
new file mode 100644
index 0000000..a95eec9
--- /dev/null
+++ b/final/lib/Support/SCEVValidator.cpp
@@ -0,0 +1,779 @@
+
+#include "polly/Support/SCEVValidator.h"
+#include "polly/ScopInfo.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-scev-validator"
+
+namespace SCEVType {
+/// The type of a SCEV
+///
+/// To check for the validity of a SCEV we assign to each SCEV a type. The
+/// possible types are INT, PARAM, IV and INVALID. The order of the types is
+/// important. The subexpressions of SCEV with a type X can only have a type
+/// that is smaller or equal than X.
+enum TYPE {
+  // An integer value.
+  INT,
+
+  // An expression that is constant during the execution of the Scop,
+  // but that may depend on parameters unknown at compile time.
+  PARAM,
+
+  // An expression that may change during the execution of the SCoP.
+  IV,
+
+  // An invalid expression.
+  INVALID
+};
+} // namespace SCEVType
+
+/// The result the validator returns for a SCEV expression.
+class ValidatorResult {
+  /// The type of the expression
+  SCEVType::TYPE Type;
+
+  /// The set of Parameters in the expression.
+  ParameterSetTy Parameters;
+
+public:
+  /// The copy constructor
+  ValidatorResult(const ValidatorResult &Source) {
+    Type = Source.Type;
+    Parameters = Source.Parameters;
+  }
+
+  /// Construct a result with a certain type and no parameters.
+  ValidatorResult(SCEVType::TYPE Type) : Type(Type) {
+    assert(Type != SCEVType::PARAM && "Did you forget to pass the parameter");
+  }
+
+  /// Construct a result with a certain type and a single parameter.
+  ValidatorResult(SCEVType::TYPE Type, const SCEV *Expr) : Type(Type) {
+    Parameters.insert(Expr);
+  }
+
+  /// Get the type of the ValidatorResult.
+  SCEVType::TYPE getType() { return Type; }
+
+  /// Is the analyzed SCEV constant during the execution of the SCoP.
+  bool isConstant() { return Type == SCEVType::INT || Type == SCEVType::PARAM; }
+
+  /// Is the analyzed SCEV valid.
+  bool isValid() { return Type != SCEVType::INVALID; }
+
+  /// Is the analyzed SCEV of Type IV.
+  bool isIV() { return Type == SCEVType::IV; }
+
+  /// Is the analyzed SCEV of Type INT.
+  bool isINT() { return Type == SCEVType::INT; }
+
+  /// Is the analyzed SCEV of Type PARAM.
+  bool isPARAM() { return Type == SCEVType::PARAM; }
+
+  /// Get the parameters of this validator result.
+  const ParameterSetTy &getParameters() { return Parameters; }
+
+  /// Add the parameters of Source to this result.
+  void addParamsFrom(const ValidatorResult &Source) {
+    Parameters.insert(Source.Parameters.begin(), Source.Parameters.end());
+  }
+
+  /// Merge a result.
+  ///
+  /// This means to merge the parameters and to set the Type to the most
+  /// specific Type that matches both.
+  void merge(const ValidatorResult &ToMerge) {
+    Type = std::max(Type, ToMerge.Type);
+    addParamsFrom(ToMerge);
+  }
+
+  void print(raw_ostream &OS) {
+    switch (Type) {
+    case SCEVType::INT:
+      OS << "SCEVType::INT";
+      break;
+    case SCEVType::PARAM:
+      OS << "SCEVType::PARAM";
+      break;
+    case SCEVType::IV:
+      OS << "SCEVType::IV";
+      break;
+    case SCEVType::INVALID:
+      OS << "SCEVType::INVALID";
+      break;
+    }
+  }
+};
+
+raw_ostream &operator<<(raw_ostream &OS, class ValidatorResult &VR) {
+  VR.print(OS);
+  return OS;
+}
+
+bool polly::isConstCall(llvm::CallInst *Call) {
+  if (Call->mayReadOrWriteMemory())
+    return false;
+
+  for (auto &Operand : Call->arg_operands())
+    if (!isa<ConstantInt>(&Operand))
+      return false;
+
+  return true;
+}
+
+/// Check if a SCEV is valid in a SCoP.
+struct SCEVValidator
+    : public SCEVVisitor<SCEVValidator, class ValidatorResult> {
+private:
+  const Region *R;
+  Loop *Scope;
+  ScalarEvolution &SE;
+  InvariantLoadsSetTy *ILS;
+
+public:
+  SCEVValidator(const Region *R, Loop *Scope, ScalarEvolution &SE,
+                InvariantLoadsSetTy *ILS)
+      : R(R), Scope(Scope), SE(SE), ILS(ILS) {}
+
+  class ValidatorResult visitConstant(const SCEVConstant *Constant) {
+    return ValidatorResult(SCEVType::INT);
+  }
+
+  class ValidatorResult visitZeroExtendOrTruncateExpr(const SCEV *Expr,
+                                                      const SCEV *Operand) {
+    ValidatorResult Op = visit(Operand);
+    auto Type = Op.getType();
+
+    // If unsigned operations are allowed return the operand, otherwise
+    // check if we can model the expression without unsigned assumptions.
+    if (PollyAllowUnsignedOperations || Type == SCEVType::INVALID)
+      return Op;
+
+    if (Type == SCEVType::IV)
+      return ValidatorResult(SCEVType::INVALID);
+    return ValidatorResult(SCEVType::PARAM, Expr);
+  }
+
+  class ValidatorResult visitTruncateExpr(const SCEVTruncateExpr *Expr) {
+    return visitZeroExtendOrTruncateExpr(Expr, Expr->getOperand());
+  }
+
+  class ValidatorResult visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
+    return visitZeroExtendOrTruncateExpr(Expr, Expr->getOperand());
+  }
+
+  class ValidatorResult visitSignExtendExpr(const SCEVSignExtendExpr *Expr) {
+    return visit(Expr->getOperand());
+  }
+
+  class ValidatorResult visitAddExpr(const SCEVAddExpr *Expr) {
+    ValidatorResult Return(SCEVType::INT);
+
+    for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
+      ValidatorResult Op = visit(Expr->getOperand(i));
+      Return.merge(Op);
+
+      // Early exit.
+      if (!Return.isValid())
+        break;
+    }
+
+    return Return;
+  }
+
+  class ValidatorResult visitMulExpr(const SCEVMulExpr *Expr) {
+    ValidatorResult Return(SCEVType::INT);
+
+    bool HasMultipleParams = false;
+
+    for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
+      ValidatorResult Op = visit(Expr->getOperand(i));
+
+      if (Op.isINT())
+        continue;
+
+      if (Op.isPARAM() && Return.isPARAM()) {
+        HasMultipleParams = true;
+        continue;
+      }
+
+      if ((Op.isIV() || Op.isPARAM()) && !Return.isINT()) {
+        DEBUG(dbgs() << "INVALID: More than one non-int operand in MulExpr\n"
+                     << "\tExpr: " << *Expr << "\n"
+                     << "\tPrevious expression type: " << Return << "\n"
+                     << "\tNext operand (" << Op
+                     << "): " << *Expr->getOperand(i) << "\n");
+
+        return ValidatorResult(SCEVType::INVALID);
+      }
+
+      Return.merge(Op);
+    }
+
+    if (HasMultipleParams && Return.isValid())
+      return ValidatorResult(SCEVType::PARAM, Expr);
+
+    return Return;
+  }
+
+  class ValidatorResult visitAddRecExpr(const SCEVAddRecExpr *Expr) {
+    if (!Expr->isAffine()) {
+      DEBUG(dbgs() << "INVALID: AddRec is not affine");
+      return ValidatorResult(SCEVType::INVALID);
+    }
+
+    ValidatorResult Start = visit(Expr->getStart());
+    ValidatorResult Recurrence = visit(Expr->getStepRecurrence(SE));
+
+    if (!Start.isValid())
+      return Start;
+
+    if (!Recurrence.isValid())
+      return Recurrence;
+
+    auto *L = Expr->getLoop();
+    if (R->contains(L) && (!Scope || !L->contains(Scope))) {
+      DEBUG(dbgs() << "INVALID: Loop of AddRec expression boxed in an a "
+                      "non-affine subregion or has a non-synthesizable exit "
+                      "value.");
+      return ValidatorResult(SCEVType::INVALID);
+    }
+
+    if (R->contains(L)) {
+      if (Recurrence.isINT()) {
+        ValidatorResult Result(SCEVType::IV);
+        Result.addParamsFrom(Start);
+        return Result;
+      }
+
+      DEBUG(dbgs() << "INVALID: AddRec within scop has non-int"
+                      "recurrence part");
+      return ValidatorResult(SCEVType::INVALID);
+    }
+
+    assert(Recurrence.isConstant() && "Expected 'Recurrence' to be constant");
+
+    // Directly generate ValidatorResult for Expr if 'start' is zero.
+    if (Expr->getStart()->isZero())
+      return ValidatorResult(SCEVType::PARAM, Expr);
+
+    // Translate AddRecExpr from '{start, +, inc}' into 'start + {0, +, inc}'
+    // if 'start' is not zero.
+    const SCEV *ZeroStartExpr = SE.getAddRecExpr(
+        SE.getConstant(Expr->getStart()->getType(), 0),
+        Expr->getStepRecurrence(SE), Expr->getLoop(), Expr->getNoWrapFlags());
+
+    ValidatorResult ZeroStartResult =
+        ValidatorResult(SCEVType::PARAM, ZeroStartExpr);
+    ZeroStartResult.addParamsFrom(Start);
+
+    return ZeroStartResult;
+  }
+
+  class ValidatorResult visitSMaxExpr(const SCEVSMaxExpr *Expr) {
+    ValidatorResult Return(SCEVType::INT);
+
+    for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
+      ValidatorResult Op = visit(Expr->getOperand(i));
+
+      if (!Op.isValid())
+        return Op;
+
+      Return.merge(Op);
+    }
+
+    return Return;
+  }
+
+  class ValidatorResult visitUMaxExpr(const SCEVUMaxExpr *Expr) {
+    // We do not support unsigned max operations. If 'Expr' is constant during
+    // Scop execution we treat this as a parameter, otherwise we bail out.
+    for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
+      ValidatorResult Op = visit(Expr->getOperand(i));
+
+      if (!Op.isConstant()) {
+        DEBUG(dbgs() << "INVALID: UMaxExpr has a non-constant operand");
+        return ValidatorResult(SCEVType::INVALID);
+      }
+    }
+
+    return ValidatorResult(SCEVType::PARAM, Expr);
+  }
+
+  ValidatorResult visitGenericInst(Instruction *I, const SCEV *S) {
+    if (R->contains(I)) {
+      DEBUG(dbgs() << "INVALID: UnknownExpr references an instruction "
+                      "within the region\n");
+      return ValidatorResult(SCEVType::INVALID);
+    }
+
+    return ValidatorResult(SCEVType::PARAM, S);
+  }
+
+  ValidatorResult visitCallInstruction(Instruction *I, const SCEV *S) {
+    assert(I->getOpcode() == Instruction::Call && "Call instruction expected");
+
+    if (R->contains(I)) {
+      auto Call = cast<CallInst>(I);
+
+      if (!isConstCall(Call))
+        return ValidatorResult(SCEVType::INVALID, S);
+    }
+    return ValidatorResult(SCEVType::PARAM, S);
+  }
+
+  ValidatorResult visitLoadInstruction(Instruction *I, const SCEV *S) {
+    if (R->contains(I) && ILS) {
+      ILS->insert(cast<LoadInst>(I));
+      return ValidatorResult(SCEVType::PARAM, S);
+    }
+
+    return visitGenericInst(I, S);
+  }
+
+  ValidatorResult visitDivision(const SCEV *Dividend, const SCEV *Divisor,
+                                const SCEV *DivExpr,
+                                Instruction *SDiv = nullptr) {
+
+    // First check if we might be able to model the division, thus if the
+    // divisor is constant. If so, check the dividend, otherwise check if
+    // the whole division can be seen as a parameter.
+    if (isa<SCEVConstant>(Divisor) && !Divisor->isZero())
+      return visit(Dividend);
+
+    // For signed divisions use the SDiv instruction to check for a parameter
+    // division, for unsigned divisions check the operands.
+    if (SDiv)
+      return visitGenericInst(SDiv, DivExpr);
+
+    ValidatorResult LHS = visit(Dividend);
+    ValidatorResult RHS = visit(Divisor);
+    if (LHS.isConstant() && RHS.isConstant())
+      return ValidatorResult(SCEVType::PARAM, DivExpr);
+
+    DEBUG(dbgs() << "INVALID: unsigned division of non-constant expressions");
+    return ValidatorResult(SCEVType::INVALID);
+  }
+
+  ValidatorResult visitUDivExpr(const SCEVUDivExpr *Expr) {
+    if (!PollyAllowUnsignedOperations)
+      return ValidatorResult(SCEVType::INVALID);
+
+    auto *Dividend = Expr->getLHS();
+    auto *Divisor = Expr->getRHS();
+    return visitDivision(Dividend, Divisor, Expr);
+  }
+
+  ValidatorResult visitSDivInstruction(Instruction *SDiv, const SCEV *Expr) {
+    assert(SDiv->getOpcode() == Instruction::SDiv &&
+           "Assumed SDiv instruction!");
+
+    auto *Dividend = SE.getSCEV(SDiv->getOperand(0));
+    auto *Divisor = SE.getSCEV(SDiv->getOperand(1));
+    return visitDivision(Dividend, Divisor, Expr, SDiv);
+  }
+
+  ValidatorResult visitSRemInstruction(Instruction *SRem, const SCEV *S) {
+    assert(SRem->getOpcode() == Instruction::SRem &&
+           "Assumed SRem instruction!");
+
+    auto *Divisor = SRem->getOperand(1);
+    auto *CI = dyn_cast<ConstantInt>(Divisor);
+    if (!CI || CI->isZeroValue())
+      return visitGenericInst(SRem, S);
+
+    auto *Dividend = SRem->getOperand(0);
+    auto *DividendSCEV = SE.getSCEV(Dividend);
+    return visit(DividendSCEV);
+  }
+
+  ValidatorResult visitUnknown(const SCEVUnknown *Expr) {
+    Value *V = Expr->getValue();
+
+    if (!Expr->getType()->isIntegerTy() && !Expr->getType()->isPointerTy()) {
+      DEBUG(dbgs() << "INVALID: UnknownExpr is not an integer or pointer");
+      return ValidatorResult(SCEVType::INVALID);
+    }
+
+    if (isa<UndefValue>(V)) {
+      DEBUG(dbgs() << "INVALID: UnknownExpr references an undef value");
+      return ValidatorResult(SCEVType::INVALID);
+    }
+
+    if (Instruction *I = dyn_cast<Instruction>(Expr->getValue())) {
+      switch (I->getOpcode()) {
+      case Instruction::IntToPtr:
+        return visit(SE.getSCEVAtScope(I->getOperand(0), Scope));
+      case Instruction::PtrToInt:
+        return visit(SE.getSCEVAtScope(I->getOperand(0), Scope));
+      case Instruction::Load:
+        return visitLoadInstruction(I, Expr);
+      case Instruction::SDiv:
+        return visitSDivInstruction(I, Expr);
+      case Instruction::SRem:
+        return visitSRemInstruction(I, Expr);
+      case Instruction::Call:
+        return visitCallInstruction(I, Expr);
+      default:
+        return visitGenericInst(I, Expr);
+      }
+    }
+
+    return ValidatorResult(SCEVType::PARAM, Expr);
+  }
+};
+
+class SCEVHasIVParams {
+  bool HasIVParams = false;
+
+public:
+  SCEVHasIVParams() {}
+
+  bool follow(const SCEV *S) {
+    const SCEVUnknown *Unknown = dyn_cast<SCEVUnknown>(S);
+    if (!Unknown)
+      return true;
+
+    CallInst *Call = dyn_cast<CallInst>(Unknown->getValue());
+
+    if (!Call)
+      return true;
+
+    if (isConstCall(Call)) {
+      HasIVParams = true;
+      return false;
+    }
+
+    return true;
+  }
+
+  bool isDone() { return HasIVParams; }
+  bool hasIVParams() { return HasIVParams; }
+};
+
+/// Check whether a SCEV refers to an SSA name defined inside a region.
+class SCEVInRegionDependences {
+  const Region *R;
+  Loop *Scope;
+  const InvariantLoadsSetTy &ILS;
+  bool AllowLoops;
+  bool HasInRegionDeps = false;
+
+public:
+  SCEVInRegionDependences(const Region *R, Loop *Scope, bool AllowLoops,
+                          const InvariantLoadsSetTy &ILS)
+      : R(R), Scope(Scope), ILS(ILS), AllowLoops(AllowLoops) {}
+
+  bool follow(const SCEV *S) {
+    if (auto Unknown = dyn_cast<SCEVUnknown>(S)) {
+      Instruction *Inst = dyn_cast<Instruction>(Unknown->getValue());
+
+      CallInst *Call = dyn_cast<CallInst>(Unknown->getValue());
+
+      if (Call && isConstCall(Call))
+        return false;
+
+      if (Inst) {
+        // When we invariant load hoist a load, we first make sure that there
+        // can be no dependences created by it in the Scop region. So, we should
+        // not consider scalar dependences to `LoadInst`s that are invariant
+        // load hoisted.
+        //
+        // If this check is not present, then we create data dependences which
+        // are strictly not necessary by tracking the invariant load as a
+        // scalar.
+        LoadInst *LI = dyn_cast<LoadInst>(Inst);
+        if (LI && ILS.count(LI) > 0)
+          return false;
+      }
+
+      // Return true when Inst is defined inside the region R.
+      if (!Inst || !R->contains(Inst))
+        return true;
+
+      HasInRegionDeps = true;
+      return false;
+    }
+
+    if (auto AddRec = dyn_cast<SCEVAddRecExpr>(S)) {
+      if (AllowLoops)
+        return true;
+
+      auto *L = AddRec->getLoop();
+      if (R->contains(L) && !L->contains(Scope)) {
+        HasInRegionDeps = true;
+        return false;
+      }
+    }
+
+    return true;
+  }
+  bool isDone() { return false; }
+  bool hasDependences() { return HasInRegionDeps; }
+};
+
+namespace polly {
+/// Find all loops referenced in SCEVAddRecExprs.
+class SCEVFindLoops {
+  SetVector<const Loop *> &Loops;
+
+public:
+  SCEVFindLoops(SetVector<const Loop *> &Loops) : Loops(Loops) {}
+
+  bool follow(const SCEV *S) {
+    if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(S))
+      Loops.insert(AddRec->getLoop());
+    return true;
+  }
+  bool isDone() { return false; }
+};
+
+void findLoops(const SCEV *Expr, SetVector<const Loop *> &Loops) {
+  SCEVFindLoops FindLoops(Loops);
+  SCEVTraversal<SCEVFindLoops> ST(FindLoops);
+  ST.visitAll(Expr);
+}
+
+/// Find all values referenced in SCEVUnknowns.
+class SCEVFindValues {
+  ScalarEvolution &SE;
+  SetVector<Value *> &Values;
+
+public:
+  SCEVFindValues(ScalarEvolution &SE, SetVector<Value *> &Values)
+      : SE(SE), Values(Values) {}
+
+  bool follow(const SCEV *S) {
+    const SCEVUnknown *Unknown = dyn_cast<SCEVUnknown>(S);
+    if (!Unknown)
+      return true;
+
+    Values.insert(Unknown->getValue());
+    Instruction *Inst = dyn_cast<Instruction>(Unknown->getValue());
+    if (!Inst || (Inst->getOpcode() != Instruction::SRem &&
+                  Inst->getOpcode() != Instruction::SDiv))
+      return false;
+
+    auto *Dividend = SE.getSCEV(Inst->getOperand(1));
+    if (!isa<SCEVConstant>(Dividend))
+      return false;
+
+    auto *Divisor = SE.getSCEV(Inst->getOperand(0));
+    SCEVFindValues FindValues(SE, Values);
+    SCEVTraversal<SCEVFindValues> ST(FindValues);
+    ST.visitAll(Dividend);
+    ST.visitAll(Divisor);
+
+    return false;
+  }
+  bool isDone() { return false; }
+};
+
+void findValues(const SCEV *Expr, ScalarEvolution &SE,
+                SetVector<Value *> &Values) {
+  SCEVFindValues FindValues(SE, Values);
+  SCEVTraversal<SCEVFindValues> ST(FindValues);
+  ST.visitAll(Expr);
+}
+
+bool hasIVParams(const SCEV *Expr) {
+  SCEVHasIVParams HasIVParams;
+  SCEVTraversal<SCEVHasIVParams> ST(HasIVParams);
+  ST.visitAll(Expr);
+  return HasIVParams.hasIVParams();
+}
+
+bool hasScalarDepsInsideRegion(const SCEV *Expr, const Region *R,
+                               llvm::Loop *Scope, bool AllowLoops,
+                               const InvariantLoadsSetTy &ILS) {
+  SCEVInRegionDependences InRegionDeps(R, Scope, AllowLoops, ILS);
+  SCEVTraversal<SCEVInRegionDependences> ST(InRegionDeps);
+  ST.visitAll(Expr);
+  return InRegionDeps.hasDependences();
+}
+
+bool isAffineExpr(const Region *R, llvm::Loop *Scope, const SCEV *Expr,
+                  ScalarEvolution &SE, InvariantLoadsSetTy *ILS) {
+  if (isa<SCEVCouldNotCompute>(Expr))
+    return false;
+
+  SCEVValidator Validator(R, Scope, SE, ILS);
+  DEBUG({
+    dbgs() << "\n";
+    dbgs() << "Expr: " << *Expr << "\n";
+    dbgs() << "Region: " << R->getNameStr() << "\n";
+    dbgs() << " -> ";
+  });
+
+  ValidatorResult Result = Validator.visit(Expr);
+
+  DEBUG({
+    if (Result.isValid())
+      dbgs() << "VALID\n";
+    dbgs() << "\n";
+  });
+
+  return Result.isValid();
+}
+
+static bool isAffineExpr(Value *V, const Region *R, Loop *Scope,
+                         ScalarEvolution &SE, ParameterSetTy &Params) {
+  auto *E = SE.getSCEV(V);
+  if (isa<SCEVCouldNotCompute>(E))
+    return false;
+
+  SCEVValidator Validator(R, Scope, SE, nullptr);
+  ValidatorResult Result = Validator.visit(E);
+  if (!Result.isValid())
+    return false;
+
+  auto ResultParams = Result.getParameters();
+  Params.insert(ResultParams.begin(), ResultParams.end());
+
+  return true;
+}
+
+bool isAffineConstraint(Value *V, const Region *R, llvm::Loop *Scope,
+                        ScalarEvolution &SE, ParameterSetTy &Params,
+                        bool OrExpr) {
+  if (auto *ICmp = dyn_cast<ICmpInst>(V)) {
+    return isAffineConstraint(ICmp->getOperand(0), R, Scope, SE, Params,
+                              true) &&
+           isAffineConstraint(ICmp->getOperand(1), R, Scope, SE, Params, true);
+  } else if (auto *BinOp = dyn_cast<BinaryOperator>(V)) {
+    auto Opcode = BinOp->getOpcode();
+    if (Opcode == Instruction::And || Opcode == Instruction::Or)
+      return isAffineConstraint(BinOp->getOperand(0), R, Scope, SE, Params,
+                                false) &&
+             isAffineConstraint(BinOp->getOperand(1), R, Scope, SE, Params,
+                                false);
+    /* Fall through */
+  }
+
+  if (!OrExpr)
+    return false;
+
+  return isAffineExpr(V, R, Scope, SE, Params);
+}
+
+ParameterSetTy getParamsInAffineExpr(const Region *R, Loop *Scope,
+                                     const SCEV *Expr, ScalarEvolution &SE) {
+  if (isa<SCEVCouldNotCompute>(Expr))
+    return ParameterSetTy();
+
+  InvariantLoadsSetTy ILS;
+  SCEVValidator Validator(R, Scope, SE, &ILS);
+  ValidatorResult Result = Validator.visit(Expr);
+  assert(Result.isValid() && "Requested parameters for an invalid SCEV!");
+
+  return Result.getParameters();
+}
+
+std::pair<const SCEVConstant *, const SCEV *>
+extractConstantFactor(const SCEV *S, ScalarEvolution &SE) {
+  auto *ConstPart = cast<SCEVConstant>(SE.getConstant(S->getType(), 1));
+
+  if (auto *Constant = dyn_cast<SCEVConstant>(S))
+    return std::make_pair(Constant, SE.getConstant(S->getType(), 1));
+
+  auto *AddRec = dyn_cast<SCEVAddRecExpr>(S);
+  if (AddRec) {
+    auto *StartExpr = AddRec->getStart();
+    if (StartExpr->isZero()) {
+      auto StepPair = extractConstantFactor(AddRec->getStepRecurrence(SE), SE);
+      auto *LeftOverAddRec =
+          SE.getAddRecExpr(StartExpr, StepPair.second, AddRec->getLoop(),
+                           AddRec->getNoWrapFlags());
+      return std::make_pair(StepPair.first, LeftOverAddRec);
+    }
+    return std::make_pair(ConstPart, S);
+  }
+
+  if (auto *Add = dyn_cast<SCEVAddExpr>(S)) {
+    SmallVector<const SCEV *, 4> LeftOvers;
+    auto Op0Pair = extractConstantFactor(Add->getOperand(0), SE);
+    auto *Factor = Op0Pair.first;
+    if (SE.isKnownNegative(Factor)) {
+      Factor = cast<SCEVConstant>(SE.getNegativeSCEV(Factor));
+      LeftOvers.push_back(SE.getNegativeSCEV(Op0Pair.second));
+    } else {
+      LeftOvers.push_back(Op0Pair.second);
+    }
+
+    for (unsigned u = 1, e = Add->getNumOperands(); u < e; u++) {
+      auto OpUPair = extractConstantFactor(Add->getOperand(u), SE);
+      // TODO: Use something smarter than equality here, e.g., gcd.
+      if (Factor == OpUPair.first)
+        LeftOvers.push_back(OpUPair.second);
+      else if (Factor == SE.getNegativeSCEV(OpUPair.first))
+        LeftOvers.push_back(SE.getNegativeSCEV(OpUPair.second));
+      else
+        return std::make_pair(ConstPart, S);
+    }
+
+    auto *NewAdd = SE.getAddExpr(LeftOvers, Add->getNoWrapFlags());
+    return std::make_pair(Factor, NewAdd);
+  }
+
+  auto *Mul = dyn_cast<SCEVMulExpr>(S);
+  if (!Mul)
+    return std::make_pair(ConstPart, S);
+
+  SmallVector<const SCEV *, 4> LeftOvers;
+  for (auto *Op : Mul->operands())
+    if (isa<SCEVConstant>(Op))
+      ConstPart = cast<SCEVConstant>(SE.getMulExpr(ConstPart, Op));
+    else
+      LeftOvers.push_back(Op);
+
+  return std::make_pair(ConstPart, SE.getMulExpr(LeftOvers));
+}
+
+const SCEV *tryForwardThroughPHI(const SCEV *Expr, Region &R,
+                                 ScalarEvolution &SE, LoopInfo &LI,
+                                 const DominatorTree &DT) {
+  if (auto *Unknown = dyn_cast<SCEVUnknown>(Expr)) {
+    Value *V = Unknown->getValue();
+    auto *PHI = dyn_cast<PHINode>(V);
+    if (!PHI)
+      return Expr;
+
+    Value *Final = nullptr;
+
+    for (unsigned i = 0; i < PHI->getNumIncomingValues(); i++) {
+      BasicBlock *Incoming = PHI->getIncomingBlock(i);
+      if (isErrorBlock(*Incoming, R, LI, DT) && R.contains(Incoming))
+        continue;
+      if (Final)
+        return Expr;
+      Final = PHI->getIncomingValue(i);
+    }
+
+    if (Final)
+      return SE.getSCEV(Final);
+  }
+  return Expr;
+}
+
+Value *getUniqueNonErrorValue(PHINode *PHI, Region *R, LoopInfo &LI,
+                              const DominatorTree &DT) {
+  Value *V = nullptr;
+  for (unsigned i = 0; i < PHI->getNumIncomingValues(); i++) {
+    BasicBlock *BB = PHI->getIncomingBlock(i);
+    if (!isErrorBlock(*BB, *R, LI, DT)) {
+      if (V)
+        return nullptr;
+      V = PHI->getIncomingValue(i);
+    }
+  }
+
+  return V;
+}
+} // namespace polly
diff --git a/final/lib/Support/ScopHelper.cpp b/final/lib/Support/ScopHelper.cpp
new file mode 100644
index 0000000..87ac658
--- /dev/null
+++ b/final/lib/Support/ScopHelper.cpp
@@ -0,0 +1,607 @@
+//===- ScopHelper.cpp - Some Helper Functions for Scop.  ------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Small functions that help with Scop and LLVM-IR.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/Support/ScopHelper.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/SCEVValidator.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpander.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-scop-helper"
+
+static cl::opt<bool> PollyAllowErrorBlocks(
+    "polly-allow-error-blocks",
+    cl::desc("Allow to speculate on the execution of 'error blocks'."),
+    cl::Hidden, cl::init(true), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+// Ensures that there is just one predecessor to the entry node from outside the
+// region.
+// The identity of the region entry node is preserved.
+static void simplifyRegionEntry(Region *R, DominatorTree *DT, LoopInfo *LI,
+                                RegionInfo *RI) {
+  BasicBlock *EnteringBB = R->getEnteringBlock();
+  BasicBlock *Entry = R->getEntry();
+
+  // Before (one of):
+  //
+  //                       \    /            //
+  //                      EnteringBB         //
+  //                        |    \------>    //
+  //   \   /                |                //
+  //   Entry <--\         Entry <--\         //
+  //   /   \    /         /   \    /         //
+  //        ....               ....          //
+
+  // Create single entry edge if the region has multiple entry edges.
+  if (!EnteringBB) {
+    SmallVector<BasicBlock *, 4> Preds;
+    for (BasicBlock *P : predecessors(Entry))
+      if (!R->contains(P))
+        Preds.push_back(P);
+
+    BasicBlock *NewEntering =
+        SplitBlockPredecessors(Entry, Preds, ".region_entering", DT, LI);
+
+    if (RI) {
+      // The exit block of predecessing regions must be changed to NewEntering
+      for (BasicBlock *ExitPred : predecessors(NewEntering)) {
+        Region *RegionOfPred = RI->getRegionFor(ExitPred);
+        if (RegionOfPred->getExit() != Entry)
+          continue;
+
+        while (!RegionOfPred->isTopLevelRegion() &&
+               RegionOfPred->getExit() == Entry) {
+          RegionOfPred->replaceExit(NewEntering);
+          RegionOfPred = RegionOfPred->getParent();
+        }
+      }
+
+      // Make all ancestors use EnteringBB as entry; there might be edges to it
+      Region *AncestorR = R->getParent();
+      RI->setRegionFor(NewEntering, AncestorR);
+      while (!AncestorR->isTopLevelRegion() && AncestorR->getEntry() == Entry) {
+        AncestorR->replaceEntry(NewEntering);
+        AncestorR = AncestorR->getParent();
+      }
+    }
+
+    EnteringBB = NewEntering;
+  }
+  assert(R->getEnteringBlock() == EnteringBB);
+
+  // After:
+  //
+  //    \    /       //
+  //  EnteringBB     //
+  //      |          //
+  //      |          //
+  //    Entry <--\   //
+  //    /   \    /   //
+  //         ....    //
+}
+
+// Ensure that the region has a single block that branches to the exit node.
+static void simplifyRegionExit(Region *R, DominatorTree *DT, LoopInfo *LI,
+                               RegionInfo *RI) {
+  BasicBlock *ExitBB = R->getExit();
+  BasicBlock *ExitingBB = R->getExitingBlock();
+
+  // Before:
+  //
+  //   (Region)   ______/  //
+  //      \  |   /         //
+  //       ExitBB          //
+  //       /    \          //
+
+  if (!ExitingBB) {
+    SmallVector<BasicBlock *, 4> Preds;
+    for (BasicBlock *P : predecessors(ExitBB))
+      if (R->contains(P))
+        Preds.push_back(P);
+
+    //  Preds[0] Preds[1]      otherBB //
+    //         \  |  ________/         //
+    //          \ | /                  //
+    //           BB                    //
+    ExitingBB =
+        SplitBlockPredecessors(ExitBB, Preds, ".region_exiting", DT, LI);
+    // Preds[0] Preds[1]      otherBB  //
+    //        \  /           /         //
+    // BB.region_exiting    /          //
+    //                  \  /           //
+    //                   BB            //
+
+    if (RI)
+      RI->setRegionFor(ExitingBB, R);
+
+    // Change the exit of nested regions, but not the region itself,
+    R->replaceExitRecursive(ExitingBB);
+    R->replaceExit(ExitBB);
+  }
+  assert(ExitingBB == R->getExitingBlock());
+
+  // After:
+  //
+  //     \   /                //
+  //    ExitingBB     _____/  //
+  //          \      /        //
+  //           ExitBB         //
+  //           /    \         //
+}
+
+void polly::simplifyRegion(Region *R, DominatorTree *DT, LoopInfo *LI,
+                           RegionInfo *RI) {
+  assert(R && !R->isTopLevelRegion());
+  assert(!RI || RI == R->getRegionInfo());
+  assert((!RI || DT) &&
+         "RegionInfo requires DominatorTree to be updated as well");
+
+  simplifyRegionEntry(R, DT, LI, RI);
+  simplifyRegionExit(R, DT, LI, RI);
+  assert(R->isSimple());
+}
+
+// Split the block into two successive blocks.
+//
+// Like llvm::SplitBlock, but also preserves RegionInfo
+static BasicBlock *splitBlock(BasicBlock *Old, Instruction *SplitPt,
+                              DominatorTree *DT, llvm::LoopInfo *LI,
+                              RegionInfo *RI) {
+  assert(Old && SplitPt);
+
+  // Before:
+  //
+  //  \   /  //
+  //   Old   //
+  //  /   \  //
+
+  BasicBlock *NewBlock = llvm::SplitBlock(Old, SplitPt, DT, LI);
+
+  if (RI) {
+    Region *R = RI->getRegionFor(Old);
+    RI->setRegionFor(NewBlock, R);
+  }
+
+  // After:
+  //
+  //   \   /    //
+  //    Old     //
+  //     |      //
+  //  NewBlock  //
+  //   /   \    //
+
+  return NewBlock;
+}
+
+void polly::splitEntryBlockForAlloca(BasicBlock *EntryBlock, DominatorTree *DT,
+                                     LoopInfo *LI, RegionInfo *RI) {
+  // Find first non-alloca instruction. Every basic block has a non-alloca
+  // instruction, as every well formed basic block has a terminator.
+  BasicBlock::iterator I = EntryBlock->begin();
+  while (isa<AllocaInst>(I))
+    ++I;
+
+  // splitBlock updates DT, LI and RI.
+  splitBlock(EntryBlock, &*I, DT, LI, RI);
+}
+
+void polly::splitEntryBlockForAlloca(BasicBlock *EntryBlock, Pass *P) {
+  auto *DTWP = P->getAnalysisIfAvailable<DominatorTreeWrapperPass>();
+  auto *DT = DTWP ? &DTWP->getDomTree() : nullptr;
+  auto *LIWP = P->getAnalysisIfAvailable<LoopInfoWrapperPass>();
+  auto *LI = LIWP ? &LIWP->getLoopInfo() : nullptr;
+  RegionInfoPass *RIP = P->getAnalysisIfAvailable<RegionInfoPass>();
+  RegionInfo *RI = RIP ? &RIP->getRegionInfo() : nullptr;
+
+  // splitBlock updates DT, LI and RI.
+  polly::splitEntryBlockForAlloca(EntryBlock, DT, LI, RI);
+}
+
+/// The SCEVExpander will __not__ generate any code for an existing SDiv/SRem
+/// instruction but just use it, if it is referenced as a SCEVUnknown. We want
+/// however to generate new code if the instruction is in the analyzed region
+/// and we generate code outside/in front of that region. Hence, we generate the
+/// code for the SDiv/SRem operands in front of the analyzed region and then
+/// create a new SDiv/SRem operation there too.
+struct ScopExpander : SCEVVisitor<ScopExpander, const SCEV *> {
+  friend struct SCEVVisitor<ScopExpander, const SCEV *>;
+
+  explicit ScopExpander(const Region &R, ScalarEvolution &SE,
+                        const DataLayout &DL, const char *Name, ValueMapT *VMap,
+                        BasicBlock *RTCBB)
+      : Expander(SCEVExpander(SE, DL, Name)), SE(SE), Name(Name), R(R),
+        VMap(VMap), RTCBB(RTCBB) {}
+
+  Value *expandCodeFor(const SCEV *E, Type *Ty, Instruction *I) {
+    // If we generate code in the region we will immediately fall back to the
+    // SCEVExpander, otherwise we will stop at all unknowns in the SCEV and if
+    // needed replace them by copies computed in the entering block.
+    if (!R.contains(I))
+      E = visit(E);
+    return Expander.expandCodeFor(E, Ty, I);
+  }
+
+private:
+  SCEVExpander Expander;
+  ScalarEvolution &SE;
+  const char *Name;
+  const Region &R;
+  ValueMapT *VMap;
+  BasicBlock *RTCBB;
+
+  const SCEV *visitGenericInst(const SCEVUnknown *E, Instruction *Inst,
+                               Instruction *IP) {
+    if (!Inst || !R.contains(Inst))
+      return E;
+
+    assert(!Inst->mayThrow() && !Inst->mayReadOrWriteMemory() &&
+           !isa<PHINode>(Inst));
+
+    auto *InstClone = Inst->clone();
+    for (auto &Op : Inst->operands()) {
+      assert(SE.isSCEVable(Op->getType()));
+      auto *OpSCEV = SE.getSCEV(Op);
+      auto *OpClone = expandCodeFor(OpSCEV, Op->getType(), IP);
+      InstClone->replaceUsesOfWith(Op, OpClone);
+    }
+
+    InstClone->setName(Name + Inst->getName());
+    InstClone->insertBefore(IP);
+    return SE.getSCEV(InstClone);
+  }
+
+  const SCEV *visitUnknown(const SCEVUnknown *E) {
+
+    // If a value mapping was given try if the underlying value is remapped.
+    Value *NewVal = VMap ? VMap->lookup(E->getValue()) : nullptr;
+    if (NewVal) {
+      auto *NewE = SE.getSCEV(NewVal);
+
+      // While the mapped value might be different the SCEV representation might
+      // not be. To this end we will check before we go into recursion here.
+      if (E != NewE)
+        return visit(NewE);
+    }
+
+    Instruction *Inst = dyn_cast<Instruction>(E->getValue());
+    Instruction *IP;
+    if (Inst && !R.contains(Inst))
+      IP = Inst;
+    else if (Inst && RTCBB->getParent() == Inst->getFunction())
+      IP = RTCBB->getTerminator();
+    else
+      IP = RTCBB->getParent()->getEntryBlock().getTerminator();
+
+    if (!Inst || (Inst->getOpcode() != Instruction::SRem &&
+                  Inst->getOpcode() != Instruction::SDiv))
+      return visitGenericInst(E, Inst, IP);
+
+    const SCEV *LHSScev = SE.getSCEV(Inst->getOperand(0));
+    const SCEV *RHSScev = SE.getSCEV(Inst->getOperand(1));
+
+    if (!SE.isKnownNonZero(RHSScev))
+      RHSScev = SE.getUMaxExpr(RHSScev, SE.getConstant(E->getType(), 1));
+
+    Value *LHS = expandCodeFor(LHSScev, E->getType(), IP);
+    Value *RHS = expandCodeFor(RHSScev, E->getType(), IP);
+
+    Inst = BinaryOperator::Create((Instruction::BinaryOps)Inst->getOpcode(),
+                                  LHS, RHS, Inst->getName() + Name, IP);
+    return SE.getSCEV(Inst);
+  }
+
+  /// The following functions will just traverse the SCEV and rebuild it with
+  /// the new operands returned by the traversal.
+  ///
+  ///{
+  const SCEV *visitConstant(const SCEVConstant *E) { return E; }
+  const SCEV *visitTruncateExpr(const SCEVTruncateExpr *E) {
+    return SE.getTruncateExpr(visit(E->getOperand()), E->getType());
+  }
+  const SCEV *visitZeroExtendExpr(const SCEVZeroExtendExpr *E) {
+    return SE.getZeroExtendExpr(visit(E->getOperand()), E->getType());
+  }
+  const SCEV *visitSignExtendExpr(const SCEVSignExtendExpr *E) {
+    return SE.getSignExtendExpr(visit(E->getOperand()), E->getType());
+  }
+  const SCEV *visitUDivExpr(const SCEVUDivExpr *E) {
+    auto *RHSScev = visit(E->getRHS());
+    if (!SE.isKnownNonZero(RHSScev))
+      RHSScev = SE.getUMaxExpr(RHSScev, SE.getConstant(E->getType(), 1));
+    return SE.getUDivExpr(visit(E->getLHS()), RHSScev);
+  }
+  const SCEV *visitAddExpr(const SCEVAddExpr *E) {
+    SmallVector<const SCEV *, 4> NewOps;
+    for (const SCEV *Op : E->operands())
+      NewOps.push_back(visit(Op));
+    return SE.getAddExpr(NewOps);
+  }
+  const SCEV *visitMulExpr(const SCEVMulExpr *E) {
+    SmallVector<const SCEV *, 4> NewOps;
+    for (const SCEV *Op : E->operands())
+      NewOps.push_back(visit(Op));
+    return SE.getMulExpr(NewOps);
+  }
+  const SCEV *visitUMaxExpr(const SCEVUMaxExpr *E) {
+    SmallVector<const SCEV *, 4> NewOps;
+    for (const SCEV *Op : E->operands())
+      NewOps.push_back(visit(Op));
+    return SE.getUMaxExpr(NewOps);
+  }
+  const SCEV *visitSMaxExpr(const SCEVSMaxExpr *E) {
+    SmallVector<const SCEV *, 4> NewOps;
+    for (const SCEV *Op : E->operands())
+      NewOps.push_back(visit(Op));
+    return SE.getSMaxExpr(NewOps);
+  }
+  const SCEV *visitAddRecExpr(const SCEVAddRecExpr *E) {
+    SmallVector<const SCEV *, 4> NewOps;
+    for (const SCEV *Op : E->operands())
+      NewOps.push_back(visit(Op));
+    return SE.getAddRecExpr(NewOps, E->getLoop(), E->getNoWrapFlags());
+  }
+  ///}
+};
+
+Value *polly::expandCodeFor(Scop &S, ScalarEvolution &SE, const DataLayout &DL,
+                            const char *Name, const SCEV *E, Type *Ty,
+                            Instruction *IP, ValueMapT *VMap,
+                            BasicBlock *RTCBB) {
+  ScopExpander Expander(S.getRegion(), SE, DL, Name, VMap, RTCBB);
+  return Expander.expandCodeFor(E, Ty, IP);
+}
+
+bool polly::isErrorBlock(BasicBlock &BB, const Region &R, LoopInfo &LI,
+                         const DominatorTree &DT) {
+  if (!PollyAllowErrorBlocks)
+    return false;
+
+  if (isa<UnreachableInst>(BB.getTerminator()))
+    return true;
+
+  if (LI.isLoopHeader(&BB))
+    return false;
+
+  // Basic blocks that are always executed are not considered error blocks,
+  // as their execution can not be a rare event.
+  bool DominatesAllPredecessors = true;
+  if (R.isTopLevelRegion()) {
+    for (BasicBlock &I : *R.getEntry()->getParent())
+      if (isa<ReturnInst>(I.getTerminator()) && !DT.dominates(&BB, &I))
+        DominatesAllPredecessors = false;
+  } else {
+    for (auto Pred : predecessors(R.getExit()))
+      if (R.contains(Pred) && !DT.dominates(&BB, Pred))
+        DominatesAllPredecessors = false;
+  }
+
+  if (DominatesAllPredecessors)
+    return false;
+
+  // FIXME: This is a simple heuristic to determine if the load is executed
+  //        in a conditional. However, we actually would need the control
+  //        condition, i.e., the post dominance frontier. Alternatively we
+  //        could walk up the dominance tree until we find a block that is
+  //        not post dominated by the load and check if it is a conditional
+  //        or a loop header.
+  auto *DTNode = DT.getNode(&BB);
+  if (!DTNode)
+    return false;
+
+  DTNode = DTNode->getIDom();
+
+  if (!DTNode)
+    return false;
+
+  auto *IDomBB = DTNode->getBlock();
+  if (LI.isLoopHeader(IDomBB))
+    return false;
+
+  for (Instruction &Inst : BB)
+    if (CallInst *CI = dyn_cast<CallInst>(&Inst)) {
+      if (isIgnoredIntrinsic(CI))
+        continue;
+
+      // memset, memcpy and memmove are modeled intrinsics.
+      if (isa<MemSetInst>(CI) || isa<MemTransferInst>(CI))
+        continue;
+
+      if (!CI->doesNotAccessMemory())
+        return true;
+      if (CI->doesNotReturn())
+        return true;
+    }
+
+  return false;
+}
+
+Value *polly::getConditionFromTerminator(TerminatorInst *TI) {
+  if (BranchInst *BR = dyn_cast<BranchInst>(TI)) {
+    if (BR->isUnconditional())
+      return ConstantInt::getTrue(Type::getInt1Ty(TI->getContext()));
+
+    return BR->getCondition();
+  }
+
+  if (SwitchInst *SI = dyn_cast<SwitchInst>(TI))
+    return SI->getCondition();
+
+  return nullptr;
+}
+
+bool polly::isHoistableLoad(LoadInst *LInst, Region &R, LoopInfo &LI,
+                            ScalarEvolution &SE, const DominatorTree &DT) {
+  Loop *L = LI.getLoopFor(LInst->getParent());
+  auto *Ptr = LInst->getPointerOperand();
+  const SCEV *PtrSCEV = SE.getSCEVAtScope(Ptr, L);
+  while (L && R.contains(L)) {
+    if (!SE.isLoopInvariant(PtrSCEV, L))
+      return false;
+    L = L->getParentLoop();
+  }
+
+  for (auto *User : Ptr->users()) {
+    auto *UserI = dyn_cast<Instruction>(User);
+    if (!UserI || !R.contains(UserI))
+      continue;
+    if (!UserI->mayWriteToMemory())
+      continue;
+
+    auto &BB = *UserI->getParent();
+    if (DT.dominates(&BB, LInst->getParent()))
+      return false;
+
+    bool DominatesAllPredecessors = true;
+    if (R.isTopLevelRegion()) {
+      for (BasicBlock &I : *R.getEntry()->getParent())
+        if (isa<ReturnInst>(I.getTerminator()) && !DT.dominates(&BB, &I))
+          DominatesAllPredecessors = false;
+    } else {
+      for (auto Pred : predecessors(R.getExit()))
+        if (R.contains(Pred) && !DT.dominates(&BB, Pred))
+          DominatesAllPredecessors = false;
+    }
+
+    if (!DominatesAllPredecessors)
+      continue;
+
+    return false;
+  }
+
+  return true;
+}
+
+bool polly::isIgnoredIntrinsic(const Value *V) {
+  if (auto *IT = dyn_cast<IntrinsicInst>(V)) {
+    switch (IT->getIntrinsicID()) {
+    // Lifetime markers are supported/ignored.
+    case llvm::Intrinsic::lifetime_start:
+    case llvm::Intrinsic::lifetime_end:
+    // Invariant markers are supported/ignored.
+    case llvm::Intrinsic::invariant_start:
+    case llvm::Intrinsic::invariant_end:
+    // Some misc annotations are supported/ignored.
+    case llvm::Intrinsic::var_annotation:
+    case llvm::Intrinsic::ptr_annotation:
+    case llvm::Intrinsic::annotation:
+    case llvm::Intrinsic::donothing:
+    case llvm::Intrinsic::assume:
+    // Some debug info intrinsics are supported/ignored.
+    case llvm::Intrinsic::dbg_value:
+    case llvm::Intrinsic::dbg_declare:
+      return true;
+    default:
+      break;
+    }
+  }
+  return false;
+}
+
+bool polly::canSynthesize(const Value *V, const Scop &S, ScalarEvolution *SE,
+                          Loop *Scope) {
+  if (!V || !SE->isSCEVable(V->getType()))
+    return false;
+
+  const InvariantLoadsSetTy &ILS = S.getRequiredInvariantLoads();
+  if (const SCEV *Scev = SE->getSCEVAtScope(const_cast<Value *>(V), Scope))
+    if (!isa<SCEVCouldNotCompute>(Scev))
+      if (!hasScalarDepsInsideRegion(Scev, &S.getRegion(), Scope, false, ILS))
+        return true;
+
+  return false;
+}
+
+llvm::BasicBlock *polly::getUseBlock(const llvm::Use &U) {
+  Instruction *UI = dyn_cast<Instruction>(U.getUser());
+  if (!UI)
+    return nullptr;
+
+  if (PHINode *PHI = dyn_cast<PHINode>(UI))
+    return PHI->getIncomingBlock(U);
+
+  return UI->getParent();
+}
+
+std::tuple<std::vector<const SCEV *>, std::vector<int>>
+polly::getIndexExpressionsFromGEP(GetElementPtrInst *GEP, ScalarEvolution &SE) {
+  std::vector<const SCEV *> Subscripts;
+  std::vector<int> Sizes;
+
+  Type *Ty = GEP->getPointerOperandType();
+
+  bool DroppedFirstDim = false;
+
+  for (unsigned i = 1; i < GEP->getNumOperands(); i++) {
+
+    const SCEV *Expr = SE.getSCEV(GEP->getOperand(i));
+
+    if (i == 1) {
+      if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {
+        Ty = PtrTy->getElementType();
+      } else if (auto *ArrayTy = dyn_cast<ArrayType>(Ty)) {
+        Ty = ArrayTy->getElementType();
+      } else {
+        Subscripts.clear();
+        Sizes.clear();
+        break;
+      }
+      if (auto *Const = dyn_cast<SCEVConstant>(Expr))
+        if (Const->getValue()->isZero()) {
+          DroppedFirstDim = true;
+          continue;
+        }
+      Subscripts.push_back(Expr);
+      continue;
+    }
+
+    auto *ArrayTy = dyn_cast<ArrayType>(Ty);
+    if (!ArrayTy) {
+      Subscripts.clear();
+      Sizes.clear();
+      break;
+    }
+
+    Subscripts.push_back(Expr);
+    if (!(DroppedFirstDim && i == 2))
+      Sizes.push_back(ArrayTy->getNumElements());
+
+    Ty = ArrayTy->getElementType();
+  }
+
+  return std::make_tuple(Subscripts, Sizes);
+}
+
+llvm::Loop *polly::getFirstNonBoxedLoopFor(llvm::Loop *L, llvm::LoopInfo &LI,
+                                           const BoxedLoopsSetTy &BoxedLoops) {
+  while (BoxedLoops.count(L))
+    L = L->getParentLoop();
+  return L;
+}
+
+llvm::Loop *polly::getFirstNonBoxedLoopFor(llvm::BasicBlock *BB,
+                                           llvm::LoopInfo &LI,
+                                           const BoxedLoopsSetTy &BoxedLoops) {
+  Loop *L = LI.getLoopFor(BB);
+  return getFirstNonBoxedLoopFor(L, LI, BoxedLoops);
+}
diff --git a/final/lib/Support/ScopLocation.cpp b/final/lib/Support/ScopLocation.cpp
new file mode 100644
index 0000000..a4b3dec
--- /dev/null
+++ b/final/lib/Support/ScopLocation.cpp
@@ -0,0 +1,46 @@
+//=== ScopLocation.cpp - Debug location for ScopDetection ----- -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper function for extracting region debug information.
+//
+//===----------------------------------------------------------------------===//
+//
+#include "polly/Support/ScopLocation.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DebugLoc.h"
+
+using namespace llvm;
+
+namespace polly {
+
+void getDebugLocation(const Region *R, unsigned &LineBegin, unsigned &LineEnd,
+                      std::string &FileName) {
+  LineBegin = -1;
+  LineEnd = 0;
+
+  for (const BasicBlock *BB : R->blocks())
+    for (const Instruction &Inst : *BB) {
+      DebugLoc DL = Inst.getDebugLoc();
+      if (!DL)
+        continue;
+
+      auto *Scope = cast<DIScope>(DL.getScope());
+
+      if (FileName.empty())
+        FileName = Scope->getFilename();
+
+      unsigned NewLine = DL.getLine();
+
+      LineBegin = std::min(LineBegin, NewLine);
+      LineEnd = std::max(LineEnd, NewLine);
+    }
+}
+} // namespace polly
diff --git a/final/lib/Support/VirtualInstruction.cpp b/final/lib/Support/VirtualInstruction.cpp
new file mode 100644
index 0000000..0e47188
--- /dev/null
+++ b/final/lib/Support/VirtualInstruction.cpp
@@ -0,0 +1,401 @@
+//===------ VirtualInstruction.cpp ------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tools for determining which instructions are within a statement and the
+// nature of their operands.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/Support/VirtualInstruction.h"
+#include "polly/Support/SCEVValidator.h"
+
+using namespace polly;
+using namespace llvm;
+
+VirtualUse VirtualUse ::create(Scop *S, const Use &U, LoopInfo *LI,
+                               bool Virtual) {
+  auto *UserBB = getUseBlock(U);
+  Instruction *UI = dyn_cast<Instruction>(U.getUser());
+  ScopStmt *UserStmt = nullptr;
+  if (PHINode *PHI = dyn_cast<PHINode>(UI))
+    UserStmt = S->getLastStmtFor(PHI->getIncomingBlock(U));
+  else
+    UserStmt = S->getStmtFor(UI);
+  auto *UserScope = LI->getLoopFor(UserBB);
+  return create(S, UserStmt, UserScope, U.get(), Virtual);
+}
+
+VirtualUse VirtualUse::create(Scop *S, ScopStmt *UserStmt, Loop *UserScope,
+                              Value *Val, bool Virtual) {
+  assert(!isa<StoreInst>(Val) && "a StoreInst cannot be used");
+
+  if (isa<BasicBlock>(Val))
+    return VirtualUse(UserStmt, Val, Block, nullptr, nullptr);
+
+  if (isa<llvm::Constant>(Val) || isa<MetadataAsValue>(Val))
+    return VirtualUse(UserStmt, Val, Constant, nullptr, nullptr);
+
+  // Is the value synthesizable? If the user has been pruned
+  // (UserStmt == nullptr), it is either not used anywhere or is synthesizable.
+  // We assume synthesizable which practically should have the same effect.
+  auto *SE = S->getSE();
+  if (SE->isSCEVable(Val->getType())) {
+    auto *ScevExpr = SE->getSCEVAtScope(Val, UserScope);
+    if (!UserStmt || canSynthesize(Val, *UserStmt->getParent(), SE, UserScope))
+      return VirtualUse(UserStmt, Val, Synthesizable, ScevExpr, nullptr);
+  }
+
+  // FIXME: Inconsistency between lookupInvariantEquivClass and
+  // getRequiredInvariantLoads. Querying one of them should be enough.
+  auto &RIL = S->getRequiredInvariantLoads();
+  if (S->lookupInvariantEquivClass(Val) || RIL.count(dyn_cast<LoadInst>(Val)))
+    return VirtualUse(UserStmt, Val, Hoisted, nullptr, nullptr);
+
+  // ReadOnly uses may have MemoryAccesses that we want to associate with the
+  // use. This is why we look for a MemoryAccess here already.
+  MemoryAccess *InputMA = nullptr;
+  if (UserStmt && Virtual)
+    InputMA = UserStmt->lookupValueReadOf(Val);
+
+  // Uses are read-only if they have been defined before the SCoP, i.e., they
+  // cannot be written to inside the SCoP. Arguments are defined before any
+  // instructions, hence also before the SCoP. If the user has been pruned
+  // (UserStmt == nullptr) and is not SCEVable, assume it is read-only as it is
+  // neither an intra- nor an inter-use.
+  if (!UserStmt || isa<Argument>(Val))
+    return VirtualUse(UserStmt, Val, ReadOnly, nullptr, InputMA);
+
+  auto Inst = cast<Instruction>(Val);
+  if (!S->contains(Inst))
+    return VirtualUse(UserStmt, Val, ReadOnly, nullptr, InputMA);
+
+  // A use is inter-statement if either it is defined in another statement, or
+  // there is a MemoryAccess that reads its value that has been written by
+  // another statement.
+  if (InputMA || (!Virtual && UserStmt != S->getStmtFor(Inst)))
+    return VirtualUse(UserStmt, Val, Inter, nullptr, InputMA);
+
+  return VirtualUse(UserStmt, Val, Intra, nullptr, nullptr);
+}
+
+void VirtualUse::print(raw_ostream &OS, bool Reproducible) const {
+  OS << "User: [" << User->getBaseName() << "] ";
+  switch (Kind) {
+  case VirtualUse::Constant:
+    OS << "Constant Op:";
+    break;
+  case VirtualUse::Block:
+    OS << "BasicBlock Op:";
+    break;
+  case VirtualUse::Synthesizable:
+    OS << "Synthesizable Op:";
+    break;
+  case VirtualUse::Hoisted:
+    OS << "Hoisted load Op:";
+    break;
+  case VirtualUse::ReadOnly:
+    OS << "Read-Only Op:";
+    break;
+  case VirtualUse::Intra:
+    OS << "Intra Op:";
+    break;
+  case VirtualUse::Inter:
+    OS << "Inter Op:";
+    break;
+  }
+
+  if (Val) {
+    OS << ' ';
+    if (Reproducible)
+      OS << '"' << Val->getName() << '"';
+    else
+      Val->print(OS, true);
+  }
+  if (ScevExpr) {
+    OS << ' ';
+    ScevExpr->print(OS);
+  }
+  if (InputMA && !Reproducible)
+    OS << ' ' << InputMA;
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void VirtualUse::dump() const {
+  print(errs(), false);
+  errs() << '\n';
+}
+#endif
+
+void VirtualInstruction::print(raw_ostream &OS, bool Reproducible) const {
+  if (!Stmt || !Inst) {
+    OS << "[null VirtualInstruction]";
+    return;
+  }
+
+  OS << "[" << Stmt->getBaseName() << "]";
+  Inst->print(OS, !Reproducible);
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void VirtualInstruction::dump() const {
+  print(errs(), false);
+  errs() << '\n';
+}
+#endif
+
+/// Return true if @p Inst cannot be removed, even if it is nowhere referenced.
+static bool isRoot(const Instruction *Inst) {
+  // The store is handled by its MemoryAccess. The load must be reached from the
+  // roots in order to be marked as used.
+  if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
+    return false;
+
+  // Terminator instructions (in region statements) are required for control
+  // flow.
+  if (isa<TerminatorInst>(Inst))
+    return true;
+
+  // Writes to memory must be honored.
+  if (Inst->mayWriteToMemory())
+    return true;
+
+  return false;
+}
+
+/// Return true for MemoryAccesses that cannot be removed because it represents
+/// an llvm::Value that is used after the SCoP.
+static bool isEscaping(MemoryAccess *MA) {
+  assert(MA->isOriginalValueKind());
+  Scop *S = MA->getStatement()->getParent();
+  return S->isEscaping(cast<Instruction>(MA->getAccessValue()));
+}
+
+/// Add non-removable virtual instructions in @p Stmt to @p RootInsts.
+static void
+addInstructionRoots(ScopStmt *Stmt,
+                    SmallVectorImpl<VirtualInstruction> &RootInsts) {
+  if (!Stmt->isBlockStmt()) {
+    // In region statements the terminator statement and all statements that
+    // are not in the entry block cannot be eliminated and consequently must
+    // be roots.
+    RootInsts.emplace_back(Stmt,
+                           Stmt->getRegion()->getEntry()->getTerminator());
+    for (BasicBlock *BB : Stmt->getRegion()->blocks())
+      if (Stmt->getRegion()->getEntry() != BB)
+        for (Instruction &Inst : *BB)
+          RootInsts.emplace_back(Stmt, &Inst);
+    return;
+  }
+
+  for (Instruction *Inst : Stmt->getInstructions())
+    if (isRoot(Inst))
+      RootInsts.emplace_back(Stmt, Inst);
+}
+
+/// Add non-removable memory accesses in @p Stmt to @p RootInsts.
+///
+/// @param Local If true, all writes are assumed to escape. markAndSweep
+/// algorithms can use this to be applicable to a single ScopStmt only without
+/// the risk of removing definitions required by other statements.
+///              If false, only writes for SCoP-escaping values are roots.  This
+///              is global mode, where such writes must be marked by theirs uses
+///              in order to be reachable.
+static void addAccessRoots(ScopStmt *Stmt,
+                           SmallVectorImpl<MemoryAccess *> &RootAccs,
+                           bool Local) {
+  for (auto *MA : *Stmt) {
+    if (!MA->isWrite())
+      continue;
+
+    // Writes to arrays are always used.
+    if (MA->isLatestArrayKind())
+      RootAccs.push_back(MA);
+
+    // Values are roots if they are escaping.
+    else if (MA->isLatestValueKind()) {
+      if (Local || isEscaping(MA))
+        RootAccs.push_back(MA);
+    }
+
+    // Exit phis are, by definition, escaping.
+    else if (MA->isLatestExitPHIKind())
+      RootAccs.push_back(MA);
+
+    // phi writes are only roots if we are not visiting the statement
+    // containing the PHINode.
+    else if (Local && MA->isLatestPHIKind())
+      RootAccs.push_back(MA);
+  }
+}
+
+/// Determine all instruction and access roots.
+static void addRoots(ScopStmt *Stmt,
+                     SmallVectorImpl<VirtualInstruction> &RootInsts,
+                     SmallVectorImpl<MemoryAccess *> &RootAccs, bool Local) {
+  addInstructionRoots(Stmt, RootInsts);
+  addAccessRoots(Stmt, RootAccs, Local);
+}
+
+/// Mark accesses and instructions as used if they are reachable from a root,
+/// walking the operand trees.
+///
+/// @param S              The SCoP to walk.
+/// @param LI             The LoopInfo Analysis.
+/// @param RootInsts      List of root instructions.
+/// @param RootAccs       List of root accesses.
+/// @param UsesInsts[out] Receives all reachable instructions, including the
+/// roots.
+/// @param UsedAccs[out]  Receives all reachable accesses, including the roots.
+/// @param OnlyLocal      If non-nullptr, restricts walking to a single
+/// statement.
+static void walkReachable(Scop *S, LoopInfo *LI,
+                          ArrayRef<VirtualInstruction> RootInsts,
+                          ArrayRef<MemoryAccess *> RootAccs,
+                          DenseSet<VirtualInstruction> &UsedInsts,
+                          DenseSet<MemoryAccess *> &UsedAccs,
+                          ScopStmt *OnlyLocal = nullptr) {
+  UsedInsts.clear();
+  UsedAccs.clear();
+
+  SmallVector<VirtualInstruction, 32> WorklistInsts;
+  SmallVector<MemoryAccess *, 32> WorklistAccs;
+
+  WorklistInsts.append(RootInsts.begin(), RootInsts.end());
+  WorklistAccs.append(RootAccs.begin(), RootAccs.end());
+
+  auto AddToWorklist = [&](VirtualUse VUse) {
+    switch (VUse.getKind()) {
+    case VirtualUse::Block:
+    case VirtualUse::Constant:
+    case VirtualUse::Synthesizable:
+    case VirtualUse::Hoisted:
+      break;
+    case VirtualUse::ReadOnly:
+      // Read-only scalars only have MemoryAccesses if ModelReadOnlyScalars is
+      // enabled.
+      if (!VUse.getMemoryAccess())
+        break;
+      LLVM_FALLTHROUGH;
+    case VirtualUse::Inter:
+      assert(VUse.getMemoryAccess());
+      WorklistAccs.push_back(VUse.getMemoryAccess());
+      break;
+    case VirtualUse::Intra:
+      WorklistInsts.emplace_back(VUse.getUser(),
+                                 cast<Instruction>(VUse.getValue()));
+      break;
+    }
+  };
+
+  while (true) {
+    // We have two worklists to process: Only when the MemoryAccess worklist is
+    // empty, we process the instruction worklist.
+
+    while (!WorklistAccs.empty()) {
+      auto *Acc = WorklistAccs.pop_back_val();
+
+      ScopStmt *Stmt = Acc->getStatement();
+      if (OnlyLocal && Stmt != OnlyLocal)
+        continue;
+
+      auto Inserted = UsedAccs.insert(Acc);
+      if (!Inserted.second)
+        continue;
+
+      if (Acc->isRead()) {
+        const ScopArrayInfo *SAI = Acc->getScopArrayInfo();
+
+        if (Acc->isLatestValueKind()) {
+          MemoryAccess *DefAcc = S->getValueDef(SAI);
+
+          // Accesses to read-only values do not have a definition.
+          if (DefAcc)
+            WorklistAccs.push_back(S->getValueDef(SAI));
+        }
+
+        if (Acc->isLatestAnyPHIKind()) {
+          auto IncomingMAs = S->getPHIIncomings(SAI);
+          WorklistAccs.append(IncomingMAs.begin(), IncomingMAs.end());
+        }
+      }
+
+      if (Acc->isWrite()) {
+        if (Acc->isOriginalValueKind() ||
+            (Acc->isOriginalArrayKind() && Acc->getAccessValue())) {
+          Loop *Scope = Stmt->getSurroundingLoop();
+          VirtualUse VUse =
+              VirtualUse::create(S, Stmt, Scope, Acc->getAccessValue(), true);
+          AddToWorklist(VUse);
+        }
+
+        if (Acc->isOriginalAnyPHIKind()) {
+          for (auto Incoming : Acc->getIncoming()) {
+            VirtualUse VUse = VirtualUse::create(
+                S, Stmt, LI->getLoopFor(Incoming.first), Incoming.second, true);
+            AddToWorklist(VUse);
+          }
+        }
+
+        if (Acc->isOriginalArrayKind())
+          WorklistInsts.emplace_back(Stmt, Acc->getAccessInstruction());
+      }
+    }
+
+    // If both worklists are empty, stop walking.
+    if (WorklistInsts.empty())
+      break;
+
+    VirtualInstruction VInst = WorklistInsts.pop_back_val();
+    ScopStmt *Stmt = VInst.getStmt();
+    Instruction *Inst = VInst.getInstruction();
+
+    // Do not process statements other than the local.
+    if (OnlyLocal && Stmt != OnlyLocal)
+      continue;
+
+    auto InsertResult = UsedInsts.insert(VInst);
+    if (!InsertResult.second)
+      continue;
+
+    // Add all operands to the worklists.
+    PHINode *PHI = dyn_cast<PHINode>(Inst);
+    if (PHI && PHI->getParent() == Stmt->getEntryBlock()) {
+      if (MemoryAccess *PHIRead = Stmt->lookupPHIReadOf(PHI))
+        WorklistAccs.push_back(PHIRead);
+    } else {
+      for (VirtualUse VUse : VInst.operands())
+        AddToWorklist(VUse);
+    }
+
+    // If there is an array access, also add its MemoryAccesses to the worklist.
+    const MemoryAccessList *Accs = Stmt->lookupArrayAccessesFor(Inst);
+    if (!Accs)
+      continue;
+
+    for (MemoryAccess *Acc : *Accs)
+      WorklistAccs.push_back(Acc);
+  }
+}
+
+void polly::markReachable(Scop *S, LoopInfo *LI,
+                          DenseSet<VirtualInstruction> &UsedInsts,
+                          DenseSet<MemoryAccess *> &UsedAccs,
+                          ScopStmt *OnlyLocal) {
+  SmallVector<VirtualInstruction, 32> RootInsts;
+  SmallVector<MemoryAccess *, 32> RootAccs;
+
+  if (OnlyLocal) {
+    addRoots(OnlyLocal, RootInsts, RootAccs, true);
+  } else {
+    for (auto &Stmt : *S)
+      addRoots(&Stmt, RootInsts, RootAccs, false);
+  }
+
+  walkReachable(S, LI, RootInsts, RootAccs, UsedInsts, UsedAccs, OnlyLocal);
+}
diff --git a/final/lib/Transform/Canonicalization.cpp b/final/lib/Transform/Canonicalization.cpp
new file mode 100644
index 0000000..3387cf4
--- /dev/null
+++ b/final/lib/Transform/Canonicalization.cpp
@@ -0,0 +1,97 @@
+//===---- Canonicalization.cpp - Run canonicalization passes --------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Run the set of default canonicalization passes.
+//
+// This pass is mainly used for debugging.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/Canonicalization.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/Scalar.h"
+
+using namespace llvm;
+using namespace polly;
+
+static cl::opt<bool>
+    PollyInliner("polly-run-inliner",
+                 cl::desc("Run an early inliner pass before Polly"), cl::Hidden,
+                 cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+void polly::registerCanonicalicationPasses(llvm::legacy::PassManagerBase &PM) {
+  bool UseMemSSA = true;
+  PM.add(polly::createRewriteByrefParamsPass());
+  PM.add(llvm::createPromoteMemoryToRegisterPass());
+  PM.add(llvm::createEarlyCSEPass(UseMemSSA));
+  PM.add(llvm::createInstructionCombiningPass());
+  PM.add(llvm::createCFGSimplificationPass());
+  PM.add(llvm::createTailCallEliminationPass());
+  PM.add(llvm::createCFGSimplificationPass());
+  PM.add(llvm::createReassociatePass());
+  PM.add(llvm::createLoopRotatePass());
+  if (PollyInliner) {
+    PM.add(llvm::createFunctionInliningPass(200));
+    PM.add(llvm::createPromoteMemoryToRegisterPass());
+    PM.add(llvm::createCFGSimplificationPass());
+    PM.add(llvm::createInstructionCombiningPass());
+    PM.add(createBarrierNoopPass());
+  }
+  PM.add(llvm::createInstructionCombiningPass());
+  PM.add(llvm::createIndVarSimplifyPass());
+  PM.add(polly::createCodePreparationPass());
+}
+
+namespace {
+class PollyCanonicalize : public ModulePass {
+  PollyCanonicalize(const PollyCanonicalize &) = delete;
+  const PollyCanonicalize &operator=(const PollyCanonicalize &) = delete;
+
+public:
+  static char ID;
+
+  explicit PollyCanonicalize() : ModulePass(ID) {}
+  ~PollyCanonicalize();
+
+  /// @name FunctionPass interface.
+  //@{
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const;
+  virtual void releaseMemory();
+  virtual bool runOnModule(Module &M);
+  virtual void print(raw_ostream &OS, const Module *) const;
+  //@}
+};
+} // namespace
+
+PollyCanonicalize::~PollyCanonicalize() {}
+
+void PollyCanonicalize::getAnalysisUsage(AnalysisUsage &AU) const {}
+
+void PollyCanonicalize::releaseMemory() {}
+
+bool PollyCanonicalize::runOnModule(Module &M) {
+  legacy::PassManager PM;
+  registerCanonicalicationPasses(PM);
+  PM.run(M);
+
+  return true;
+}
+
+void PollyCanonicalize::print(raw_ostream &OS, const Module *) const {}
+
+char PollyCanonicalize::ID = 0;
+
+Pass *polly::createPollyCanonicalizePass() { return new PollyCanonicalize(); }
+
+INITIALIZE_PASS_BEGIN(PollyCanonicalize, "polly-canonicalize",
+                      "Polly - Run canonicalization passes", false, false)
+INITIALIZE_PASS_END(PollyCanonicalize, "polly-canonicalize",
+                    "Polly - Run canonicalization passes", false, false)
diff --git a/final/lib/Transform/CodePreparation.cpp b/final/lib/Transform/CodePreparation.cpp
new file mode 100644
index 0000000..299c141
--- /dev/null
+++ b/final/lib/Transform/CodePreparation.cpp
@@ -0,0 +1,122 @@
+//===---- CodePreparation.cpp - Code preparation for Scop Detection -------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The Polly code preparation pass is executed before SCoP detection. Its
+// currently only splits the entry block of the SCoP to make room for alloc
+// instructions as they are generated during code generation.
+//
+// XXX: In the future, we should remove the need for this pass entirely and
+// instead add this spitting to the code generation pass.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodePreparation.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/ScopDetection.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/Analysis/DominanceFrontier.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Transforms/Utils/Local.h"
+
+using namespace llvm;
+using namespace polly;
+
+namespace {
+
+/// Prepare the IR for the scop detection.
+///
+class CodePreparation : public FunctionPass {
+  CodePreparation(const CodePreparation &) = delete;
+  const CodePreparation &operator=(const CodePreparation &) = delete;
+
+  LoopInfo *LI;
+  ScalarEvolution *SE;
+
+  void clear();
+
+public:
+  static char ID;
+
+  explicit CodePreparation() : FunctionPass(ID) {}
+  ~CodePreparation();
+
+  /// @name FunctionPass interface.
+  //@{
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const;
+  virtual void releaseMemory();
+  virtual bool runOnFunction(Function &F);
+  virtual void print(raw_ostream &OS, const Module *) const;
+  //@}
+};
+} // namespace
+
+PreservedAnalyses CodePreparationPass::run(Function &F,
+                                           FunctionAnalysisManager &FAM) {
+
+  // Find first non-alloca instruction. Every basic block has a non-alloca
+  // instruction, as every well formed basic block has a terminator.
+  auto &EntryBlock = F.getEntryBlock();
+  BasicBlock::iterator I = EntryBlock.begin();
+  while (isa<AllocaInst>(I))
+    ++I;
+
+  auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
+  auto &LI = FAM.getResult<LoopAnalysis>(F);
+
+  // splitBlock updates DT, LI and RI.
+  splitEntryBlockForAlloca(&EntryBlock, &DT, &LI, nullptr);
+
+  PreservedAnalyses PA;
+  PA.preserve<DominatorTreeAnalysis>();
+  PA.preserve<LoopAnalysis>();
+  return PA;
+}
+
+void CodePreparation::clear() {}
+
+CodePreparation::~CodePreparation() { clear(); }
+
+void CodePreparation::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequired<LoopInfoWrapperPass>();
+  AU.addRequired<ScalarEvolutionWrapperPass>();
+
+  AU.addPreserved<LoopInfoWrapperPass>();
+  AU.addPreserved<RegionInfoPass>();
+  AU.addPreserved<DominatorTreeWrapperPass>();
+  AU.addPreserved<DominanceFrontierWrapperPass>();
+}
+
+bool CodePreparation::runOnFunction(Function &F) {
+  if (skipFunction(F))
+    return false;
+
+  LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+  SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
+
+  splitEntryBlockForAlloca(&F.getEntryBlock(), this);
+
+  return true;
+}
+
+void CodePreparation::releaseMemory() { clear(); }
+
+void CodePreparation::print(raw_ostream &OS, const Module *) const {}
+
+char CodePreparation::ID = 0;
+char &polly::CodePreparationID = CodePreparation::ID;
+
+Pass *polly::createCodePreparationPass() { return new CodePreparation(); }
+
+INITIALIZE_PASS_BEGIN(CodePreparation, "polly-prepare",
+                      "Polly - Prepare code for polly", false, false)
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
+INITIALIZE_PASS_END(CodePreparation, "polly-prepare",
+                    "Polly - Prepare code for polly", false, false)
diff --git a/final/lib/Transform/DeLICM.cpp b/final/lib/Transform/DeLICM.cpp
new file mode 100644
index 0000000..9709f42
--- /dev/null
+++ b/final/lib/Transform/DeLICM.cpp
@@ -0,0 +1,1458 @@
+//===------ DeLICM.cpp -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Undo the effect of Loop Invariant Code Motion (LICM) and
+// GVN Partial Redundancy Elimination (PRE) on SCoP-level.
+//
+// Namely, remove register/scalar dependencies by mapping them back to array
+// elements.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/DeLICM.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "polly/ScopPass.h"
+#include "polly/Support/ISLOStream.h"
+#include "polly/Support/ISLTools.h"
+#include "polly/ZoneAlgo.h"
+#include "llvm/ADT/Statistic.h"
+#define DEBUG_TYPE "polly-delicm"
+
+using namespace polly;
+using namespace llvm;
+
+namespace {
+
+cl::opt<int>
+    DelicmMaxOps("polly-delicm-max-ops",
+                 cl::desc("Maximum number of isl operations to invest for "
+                          "lifetime analysis; 0=no limit"),
+                 cl::init(1000000), cl::cat(PollyCategory));
+
+cl::opt<bool> DelicmOverapproximateWrites(
+    "polly-delicm-overapproximate-writes",
+    cl::desc(
+        "Do more PHI writes than necessary in order to avoid partial accesses"),
+    cl::init(false), cl::Hidden, cl::cat(PollyCategory));
+
+cl::opt<bool> DelicmPartialWrites("polly-delicm-partial-writes",
+                                  cl::desc("Allow partial writes"),
+                                  cl::init(true), cl::Hidden,
+                                  cl::cat(PollyCategory));
+
+cl::opt<bool>
+    DelicmComputeKnown("polly-delicm-compute-known",
+                       cl::desc("Compute known content of array elements"),
+                       cl::init(true), cl::Hidden, cl::cat(PollyCategory));
+
+STATISTIC(DeLICMAnalyzed, "Number of successfully analyzed SCoPs");
+STATISTIC(DeLICMOutOfQuota,
+          "Analyses aborted because max_operations was reached");
+STATISTIC(MappedValueScalars, "Number of mapped Value scalars");
+STATISTIC(MappedPHIScalars, "Number of mapped PHI scalars");
+STATISTIC(TargetsMapped, "Number of stores used for at least one mapping");
+STATISTIC(DeLICMScopsModified, "Number of SCoPs optimized");
+
+STATISTIC(NumValueWrites, "Number of scalar value writes after DeLICM");
+STATISTIC(NumValueWritesInLoops,
+          "Number of scalar value writes nested in affine loops after DeLICM");
+STATISTIC(NumPHIWrites, "Number of scalar phi writes after DeLICM");
+STATISTIC(NumPHIWritesInLoops,
+          "Number of scalar phi writes nested in affine loops after DeLICM");
+STATISTIC(NumSingletonWrites, "Number of singleton writes after DeLICM");
+STATISTIC(NumSingletonWritesInLoops,
+          "Number of singleton writes nested in affine loops after DeLICM");
+
+isl::union_map computeReachingOverwrite(isl::union_map Schedule,
+                                        isl::union_map Writes,
+                                        bool InclPrevWrite,
+                                        bool InclOverwrite) {
+  return computeReachingWrite(Schedule, Writes, true, InclPrevWrite,
+                              InclOverwrite);
+}
+
+/// Compute the next overwrite for a scalar.
+///
+/// @param Schedule      { DomainWrite[] -> Scatter[] }
+///                      Schedule of (at least) all writes. Instances not in @p
+///                      Writes are ignored.
+/// @param Writes        { DomainWrite[] }
+///                      The element instances that write to the scalar.
+/// @param InclPrevWrite Whether to extend the timepoints to include
+///                      the timepoint where the previous write happens.
+/// @param InclOverwrite Whether the reaching overwrite includes the timepoint
+///                      of the overwrite itself.
+///
+/// @return { Scatter[] -> DomainDef[] }
+isl::union_map computeScalarReachingOverwrite(isl::union_map Schedule,
+                                              isl::union_set Writes,
+                                              bool InclPrevWrite,
+                                              bool InclOverwrite) {
+
+  // { DomainWrite[] }
+  auto WritesMap = give(isl_union_map_from_domain(Writes.take()));
+
+  // { [Element[] -> Scatter[]] -> DomainWrite[] }
+  auto Result = computeReachingOverwrite(
+      std::move(Schedule), std::move(WritesMap), InclPrevWrite, InclOverwrite);
+
+  return give(isl_union_map_domain_factor_range(Result.take()));
+}
+
+/// Overload of computeScalarReachingOverwrite, with only one writing statement.
+/// Consequently, the result consists of only one map space.
+///
+/// @param Schedule      { DomainWrite[] -> Scatter[] }
+/// @param Writes        { DomainWrite[] }
+/// @param InclPrevWrite Include the previous write to result.
+/// @param InclOverwrite Include the overwrite to the result.
+///
+/// @return { Scatter[] -> DomainWrite[] }
+isl::map computeScalarReachingOverwrite(isl::union_map Schedule,
+                                        isl::set Writes, bool InclPrevWrite,
+                                        bool InclOverwrite) {
+  isl::space ScatterSpace = getScatterSpace(Schedule);
+  isl::space DomSpace = Writes.get_space();
+
+  isl::union_map ReachOverwrite = computeScalarReachingOverwrite(
+      Schedule, isl::union_set(Writes), InclPrevWrite, InclOverwrite);
+
+  isl::space ResultSpace = ScatterSpace.map_from_domain_and_range(DomSpace);
+  return singleton(std::move(ReachOverwrite), ResultSpace);
+}
+
+/// Try to find a 'natural' extension of a mapped to elements outside its
+/// domain.
+///
+/// @param Relevant The map with mapping that may not be modified.
+/// @param Universe The domain to which @p Relevant needs to be extended.
+///
+/// @return A map with that associates the domain elements of @p Relevant to the
+///         same elements and in addition the elements of @p Universe to some
+///         undefined elements. The function prefers to return simple maps.
+isl::union_map expandMapping(isl::union_map Relevant, isl::union_set Universe) {
+  Relevant = Relevant.coalesce();
+  isl::union_set RelevantDomain = Relevant.domain();
+  isl::union_map Simplified = Relevant.gist_domain(RelevantDomain);
+  Simplified = Simplified.coalesce();
+  return Simplified.intersect_domain(Universe);
+}
+
+/// Represent the knowledge of the contents of any array elements in any zone or
+/// the knowledge we would add when mapping a scalar to an array element.
+///
+/// Every array element at every zone unit has one of two states:
+///
+/// - Unused: Not occupied by any value so a transformation can change it to
+///   other values.
+///
+/// - Occupied: The element contains a value that is still needed.
+///
+/// The union of Unused and Unknown zones forms the universe, the set of all
+/// elements at every timepoint. The universe can easily be derived from the
+/// array elements that are accessed someway. Arrays that are never accessed
+/// also never play a role in any computation and can hence be ignored. With a
+/// given universe, only one of the sets needs to stored implicitly. Computing
+/// the complement is also an expensive operation, hence this class has been
+/// designed that only one of sets is needed while the other is assumed to be
+/// implicit. It can still be given, but is mostly ignored.
+///
+/// There are two use cases for the Knowledge class:
+///
+/// 1) To represent the knowledge of the current state of ScopInfo. The unused
+///    state means that an element is currently unused: there is no read of it
+///    before the next overwrite. Also called 'Existing'.
+///
+/// 2) To represent the requirements for mapping a scalar to array elements. The
+///    unused state means that there is no change/requirement. Also called
+///    'Proposed'.
+///
+/// In addition to these states at unit zones, Knowledge needs to know when
+/// values are written. This is because written values may have no lifetime (one
+/// reason is that the value is never read). Such writes would therefore never
+/// conflict, but overwrite values that might still be required. Another source
+/// of problems are multiple writes to the same element at the same timepoint,
+/// because their order is undefined.
+class Knowledge {
+private:
+  /// { [Element[] -> Zone[]] }
+  /// Set of array elements and when they are alive.
+  /// Can contain a nullptr; in this case the set is implicitly defined as the
+  /// complement of #Unused.
+  ///
+  /// The set of alive array elements is represented as zone, as the set of live
+  /// values can differ depending on how the elements are interpreted.
+  /// Assuming a value X is written at timestep [0] and read at timestep [1]
+  /// without being used at any later point, then the value is alive in the
+  /// interval ]0,1[. This interval cannot be represented by an integer set, as
+  /// it does not contain any integer point. Zones allow us to represent this
+  /// interval and can be converted to sets of timepoints when needed (e.g., in
+  /// isConflicting when comparing to the write sets).
+  /// @see convertZoneToTimepoints and this file's comment for more details.
+  isl::union_set Occupied;
+
+  /// { [Element[] -> Zone[]] }
+  /// Set of array elements when they are not alive, i.e. their memory can be
+  /// used for other purposed. Can contain a nullptr; in this case the set is
+  /// implicitly defined as the complement of #Occupied.
+  isl::union_set Unused;
+
+  /// { [Element[] -> Zone[]] -> ValInst[] }
+  /// Maps to the known content for each array element at any interval.
+  ///
+  /// Any element/interval can map to multiple known elements. This is due to
+  /// multiple llvm::Value referring to the same content. Examples are
+  ///
+  /// - A value stored and loaded again. The LoadInst represents the same value
+  /// as the StoreInst's value operand.
+  ///
+  /// - A PHINode is equal to any one of the incoming values. In case of
+  /// LCSSA-form, it is always equal to its single incoming value.
+  ///
+  /// Two Knowledges are considered not conflicting if at least one of the known
+  /// values match. Not known values are not stored as an unnamed tuple (as
+  /// #Written does), but maps to nothing.
+  ///
+  ///  Known values are usually just defined for #Occupied elements. Knowing
+  ///  #Unused contents has no advantage as it can be overwritten.
+  isl::union_map Known;
+
+  /// { [Element[] -> Scatter[]] -> ValInst[] }
+  /// The write actions currently in the scop or that would be added when
+  /// mapping a scalar. Maps to the value that is written.
+  ///
+  /// Written values that cannot be identified are represented by an unknown
+  /// ValInst[] (an unnamed tuple of 0 dimension). It conflicts with itself.
+  isl::union_map Written;
+
+  /// Check whether this Knowledge object is well-formed.
+  void checkConsistency() const {
+#ifndef NDEBUG
+    // Default-initialized object
+    if (!Occupied && !Unused && !Known && !Written)
+      return;
+
+    assert(Occupied || Unused);
+    assert(Known);
+    assert(Written);
+
+    // If not all fields are defined, we cannot derived the universe.
+    if (!Occupied || !Unused)
+      return;
+
+    assert(isl_union_set_is_disjoint(Occupied.keep(), Unused.keep()) ==
+           isl_bool_true);
+    auto Universe = give(isl_union_set_union(Occupied.copy(), Unused.copy()));
+
+    assert(!Known.domain().is_subset(Universe).is_false());
+    assert(!Written.domain().is_subset(Universe).is_false());
+#endif
+  }
+
+public:
+  /// Initialize a nullptr-Knowledge. This is only provided for convenience; do
+  /// not use such an object.
+  Knowledge() {}
+
+  /// Create a new object with the given members.
+  Knowledge(isl::union_set Occupied, isl::union_set Unused,
+            isl::union_map Known, isl::union_map Written)
+      : Occupied(std::move(Occupied)), Unused(std::move(Unused)),
+        Known(std::move(Known)), Written(std::move(Written)) {
+    checkConsistency();
+  }
+
+  /// Return whether this object was not default-constructed.
+  bool isUsable() const { return (Occupied || Unused) && Known && Written; }
+
+  /// Print the content of this object to @p OS.
+  void print(llvm::raw_ostream &OS, unsigned Indent = 0) const {
+    if (isUsable()) {
+      if (Occupied)
+        OS.indent(Indent) << "Occupied: " << Occupied << "\n";
+      else
+        OS.indent(Indent) << "Occupied: <Everything else not in Unused>\n";
+      if (Unused)
+        OS.indent(Indent) << "Unused:   " << Unused << "\n";
+      else
+        OS.indent(Indent) << "Unused:   <Everything else not in Occupied>\n";
+      OS.indent(Indent) << "Known:    " << Known << "\n";
+      OS.indent(Indent) << "Written : " << Written << '\n';
+    } else {
+      OS.indent(Indent) << "Invalid knowledge\n";
+    }
+  }
+
+  /// Combine two knowledges, this and @p That.
+  void learnFrom(Knowledge That) {
+    assert(!isConflicting(*this, That));
+    assert(Unused && That.Occupied);
+    assert(
+        !That.Unused &&
+        "This function is only prepared to learn occupied elements from That");
+    assert(!Occupied && "This function does not implement "
+                        "`this->Occupied = "
+                        "give(isl_union_set_union(this->Occupied.take(), "
+                        "That.Occupied.copy()));`");
+
+    Unused = give(isl_union_set_subtract(Unused.take(), That.Occupied.copy()));
+    Known = give(isl_union_map_union(Known.take(), That.Known.copy()));
+    Written = give(isl_union_map_union(Written.take(), That.Written.take()));
+
+    checkConsistency();
+  }
+
+  /// Determine whether two Knowledges conflict with each other.
+  ///
+  /// In theory @p Existing and @p Proposed are symmetric, but the
+  /// implementation is constrained by the implicit interpretation. That is, @p
+  /// Existing must have #Unused defined (use case 1) and @p Proposed must have
+  /// #Occupied defined (use case 1).
+  ///
+  /// A conflict is defined as non-preserved semantics when they are merged. For
+  /// instance, when for the same array and zone they assume different
+  /// llvm::Values.
+  ///
+  /// @param Existing One of the knowledges with #Unused defined.
+  /// @param Proposed One of the knowledges with #Occupied defined.
+  /// @param OS       Dump the conflict reason to this output stream; use
+  ///                 nullptr to not output anything.
+  /// @param Indent   Indention for the conflict reason.
+  ///
+  /// @return True, iff the two knowledges are conflicting.
+  static bool isConflicting(const Knowledge &Existing,
+                            const Knowledge &Proposed,
+                            llvm::raw_ostream *OS = nullptr,
+                            unsigned Indent = 0) {
+    assert(Existing.Unused);
+    assert(Proposed.Occupied);
+
+#ifndef NDEBUG
+    if (Existing.Occupied && Proposed.Unused) {
+      auto ExistingUniverse = give(isl_union_set_union(Existing.Occupied.copy(),
+                                                       Existing.Unused.copy()));
+      auto ProposedUniverse = give(isl_union_set_union(Proposed.Occupied.copy(),
+                                                       Proposed.Unused.copy()));
+      assert(isl_union_set_is_equal(ExistingUniverse.keep(),
+                                    ProposedUniverse.keep()) == isl_bool_true &&
+             "Both inputs' Knowledges must be over the same universe");
+    }
+#endif
+
+    // Do the Existing and Proposed lifetimes conflict?
+    //
+    // Lifetimes are described as the cross-product of array elements and zone
+    // intervals in which they are alive (the space { [Element[] -> Zone[]] }).
+    // In the following we call this "element/lifetime interval".
+    //
+    // In order to not conflict, one of the following conditions must apply for
+    // each element/lifetime interval:
+    //
+    // 1. If occupied in one of the knowledges, it is unused in the other.
+    //
+    //   - or -
+    //
+    // 2. Both contain the same value.
+    //
+    // Instead of partitioning the element/lifetime intervals into a part that
+    // both Knowledges occupy (which requires an expensive subtraction) and for
+    // these to check whether they are known to be the same value, we check only
+    // the second condition and ensure that it also applies when then first
+    // condition is true. This is done by adding a wildcard value to
+    // Proposed.Known and Existing.Unused such that they match as a common known
+    // value. We use the "unknown ValInst" for this purpose. Every
+    // Existing.Unused may match with an unknown Proposed.Occupied because these
+    // never are in conflict with each other.
+    auto ProposedOccupiedAnyVal = makeUnknownForDomain(Proposed.Occupied);
+    auto ProposedValues = Proposed.Known.unite(ProposedOccupiedAnyVal);
+
+    auto ExistingUnusedAnyVal = makeUnknownForDomain(Existing.Unused);
+    auto ExistingValues = Existing.Known.unite(ExistingUnusedAnyVal);
+
+    auto MatchingVals = ExistingValues.intersect(ProposedValues);
+    auto Matches = MatchingVals.domain();
+
+    // Any Proposed.Occupied must either have a match between the known values
+    // of Existing and Occupied, or be in Existing.Unused. In the latter case,
+    // the previously added "AnyVal" will match each other.
+    if (!Proposed.Occupied.is_subset(Matches)) {
+      if (OS) {
+        auto Conflicting = Proposed.Occupied.subtract(Matches);
+        auto ExistingConflictingKnown =
+            Existing.Known.intersect_domain(Conflicting);
+        auto ProposedConflictingKnown =
+            Proposed.Known.intersect_domain(Conflicting);
+
+        OS->indent(Indent) << "Proposed lifetime conflicting with Existing's\n";
+        OS->indent(Indent) << "Conflicting occupied: " << Conflicting << "\n";
+        if (!ExistingConflictingKnown.is_empty())
+          OS->indent(Indent)
+              << "Existing Known:       " << ExistingConflictingKnown << "\n";
+        if (!ProposedConflictingKnown.is_empty())
+          OS->indent(Indent)
+              << "Proposed Known:       " << ProposedConflictingKnown << "\n";
+      }
+      return true;
+    }
+
+    // Do the writes in Existing conflict with occupied values in Proposed?
+    //
+    // In order to not conflict, it must either write to unused lifetime or
+    // write the same value. To check, we remove the writes that write into
+    // Proposed.Unused (they never conflict) and then see whether the written
+    // value is already in Proposed.Known. If there are multiple known values
+    // and a written value is known under different names, it is enough when one
+    // of the written values (assuming that they are the same value under
+    // different names, e.g. a PHINode and one of the incoming values) matches
+    // one of the known names.
+    //
+    // We convert here the set of lifetimes to actual timepoints. A lifetime is
+    // in conflict with a set of write timepoints, if either a live timepoint is
+    // clearly within the lifetime or if a write happens at the beginning of the
+    // lifetime (where it would conflict with the value that actually writes the
+    // value alive). There is no conflict at the end of a lifetime, as the alive
+    // value will always be read, before it is overwritten again. The last
+    // property holds in Polly for all scalar values and we expect all users of
+    // Knowledge to check this property also for accesses to MemoryKind::Array.
+    auto ProposedFixedDefs =
+        convertZoneToTimepoints(Proposed.Occupied, true, false);
+    auto ProposedFixedKnown =
+        convertZoneToTimepoints(Proposed.Known, isl::dim::in, true, false);
+
+    auto ExistingConflictingWrites =
+        Existing.Written.intersect_domain(ProposedFixedDefs);
+    auto ExistingConflictingWritesDomain = ExistingConflictingWrites.domain();
+
+    auto CommonWrittenVal =
+        ProposedFixedKnown.intersect(ExistingConflictingWrites);
+    auto CommonWrittenValDomain = CommonWrittenVal.domain();
+
+    if (!ExistingConflictingWritesDomain.is_subset(CommonWrittenValDomain)) {
+      if (OS) {
+        auto ExistingConflictingWritten =
+            ExistingConflictingWrites.subtract_domain(CommonWrittenValDomain);
+        auto ProposedConflictingKnown = ProposedFixedKnown.subtract_domain(
+            ExistingConflictingWritten.domain());
+
+        OS->indent(Indent)
+            << "Proposed a lifetime where there is an Existing write into it\n";
+        OS->indent(Indent) << "Existing conflicting writes: "
+                           << ExistingConflictingWritten << "\n";
+        if (!ProposedConflictingKnown.is_empty())
+          OS->indent(Indent)
+              << "Proposed conflicting known:  " << ProposedConflictingKnown
+              << "\n";
+      }
+      return true;
+    }
+
+    // Do the writes in Proposed conflict with occupied values in Existing?
+    auto ExistingAvailableDefs =
+        convertZoneToTimepoints(Existing.Unused, true, false);
+    auto ExistingKnownDefs =
+        convertZoneToTimepoints(Existing.Known, isl::dim::in, true, false);
+
+    auto ProposedWrittenDomain = Proposed.Written.domain();
+    auto KnownIdentical = ExistingKnownDefs.intersect(Proposed.Written);
+    auto IdenticalOrUnused =
+        ExistingAvailableDefs.unite(KnownIdentical.domain());
+    if (!ProposedWrittenDomain.is_subset(IdenticalOrUnused)) {
+      if (OS) {
+        auto Conflicting = ProposedWrittenDomain.subtract(IdenticalOrUnused);
+        auto ExistingConflictingKnown =
+            ExistingKnownDefs.intersect_domain(Conflicting);
+        auto ProposedConflictingWritten =
+            Proposed.Written.intersect_domain(Conflicting);
+
+        OS->indent(Indent) << "Proposed writes into range used by Existing\n";
+        OS->indent(Indent) << "Proposed conflicting writes: "
+                           << ProposedConflictingWritten << "\n";
+        if (!ExistingConflictingKnown.is_empty())
+          OS->indent(Indent)
+              << "Existing conflicting known: " << ExistingConflictingKnown
+              << "\n";
+      }
+      return true;
+    }
+
+    // Does Proposed write at the same time as Existing already does (order of
+    // writes is undefined)? Writing the same value is permitted.
+    auto ExistingWrittenDomain =
+        isl::manage(isl_union_map_domain(Existing.Written.copy()));
+    auto BothWritten =
+        Existing.Written.domain().intersect(Proposed.Written.domain());
+    auto ExistingKnownWritten = filterKnownValInst(Existing.Written);
+    auto ProposedKnownWritten = filterKnownValInst(Proposed.Written);
+    auto CommonWritten =
+        ExistingKnownWritten.intersect(ProposedKnownWritten).domain();
+
+    if (!BothWritten.is_subset(CommonWritten)) {
+      if (OS) {
+        auto Conflicting = BothWritten.subtract(CommonWritten);
+        auto ExistingConflictingWritten =
+            Existing.Written.intersect_domain(Conflicting);
+        auto ProposedConflictingWritten =
+            Proposed.Written.intersect_domain(Conflicting);
+
+        OS->indent(Indent) << "Proposed writes at the same time as an already "
+                              "Existing write\n";
+        OS->indent(Indent) << "Conflicting writes: " << Conflicting << "\n";
+        if (!ExistingConflictingWritten.is_empty())
+          OS->indent(Indent)
+              << "Exiting write:      " << ExistingConflictingWritten << "\n";
+        if (!ProposedConflictingWritten.is_empty())
+          OS->indent(Indent)
+              << "Proposed write:     " << ProposedConflictingWritten << "\n";
+      }
+      return true;
+    }
+
+    return false;
+  }
+};
+
+/// Implementation of the DeLICM/DePRE transformation.
+class DeLICMImpl : public ZoneAlgorithm {
+private:
+  /// Knowledge before any transformation took place.
+  Knowledge OriginalZone;
+
+  /// Current knowledge of the SCoP including all already applied
+  /// transformations.
+  Knowledge Zone;
+
+  /// Number of StoreInsts something can be mapped to.
+  int NumberOfCompatibleTargets = 0;
+
+  /// The number of StoreInsts to which at least one value or PHI has been
+  /// mapped to.
+  int NumberOfTargetsMapped = 0;
+
+  /// The number of llvm::Value mapped to some array element.
+  int NumberOfMappedValueScalars = 0;
+
+  /// The number of PHIs mapped to some array element.
+  int NumberOfMappedPHIScalars = 0;
+
+  /// Determine whether two knowledges are conflicting with each other.
+  ///
+  /// @see Knowledge::isConflicting
+  bool isConflicting(const Knowledge &Proposed) {
+    raw_ostream *OS = nullptr;
+    DEBUG(OS = &llvm::dbgs());
+    return Knowledge::isConflicting(Zone, Proposed, OS, 4);
+  }
+
+  /// Determine whether @p SAI is a scalar that can be mapped to an array
+  /// element.
+  bool isMappable(const ScopArrayInfo *SAI) {
+    assert(SAI);
+
+    if (SAI->isValueKind()) {
+      auto *MA = S->getValueDef(SAI);
+      if (!MA) {
+        DEBUG(dbgs()
+              << "    Reject because value is read-only within the scop\n");
+        return false;
+      }
+
+      // Mapping if value is used after scop is not supported. The code
+      // generator would need to reload the scalar after the scop, but it
+      // does not have the information to where it is mapped to. Only the
+      // MemoryAccesses have that information, not the ScopArrayInfo.
+      auto Inst = MA->getAccessInstruction();
+      for (auto User : Inst->users()) {
+        if (!isa<Instruction>(User))
+          return false;
+        auto UserInst = cast<Instruction>(User);
+
+        if (!S->contains(UserInst)) {
+          DEBUG(dbgs() << "    Reject because value is escaping\n");
+          return false;
+        }
+      }
+
+      return true;
+    }
+
+    if (SAI->isPHIKind()) {
+      auto *MA = S->getPHIRead(SAI);
+      assert(MA);
+
+      // Mapping of an incoming block from before the SCoP is not supported by
+      // the code generator.
+      auto PHI = cast<PHINode>(MA->getAccessInstruction());
+      for (auto Incoming : PHI->blocks()) {
+        if (!S->contains(Incoming)) {
+          DEBUG(dbgs() << "    Reject because at least one incoming block is "
+                          "not in the scop region\n");
+          return false;
+        }
+      }
+
+      return true;
+    }
+
+    DEBUG(dbgs() << "    Reject ExitPHI or other non-value\n");
+    return false;
+  }
+
+  /// Compute the uses of a MemoryKind::Value and its lifetime (from its
+  /// definition to the last use).
+  ///
+  /// @param SAI The ScopArrayInfo representing the value's storage.
+  ///
+  /// @return { DomainDef[] -> DomainUse[] }, { DomainDef[] -> Zone[] }
+  ///         First element is the set of uses for each definition.
+  ///         The second is the lifetime of each definition.
+  std::tuple<isl::union_map, isl::map>
+  computeValueUses(const ScopArrayInfo *SAI) {
+    assert(SAI->isValueKind());
+
+    // { DomainRead[] }
+    auto Reads = makeEmptyUnionSet();
+
+    // Find all uses.
+    for (auto *MA : S->getValueUses(SAI))
+      Reads =
+          give(isl_union_set_add_set(Reads.take(), getDomainFor(MA).take()));
+
+    // { DomainRead[] -> Scatter[] }
+    auto ReadSchedule = getScatterFor(Reads);
+
+    auto *DefMA = S->getValueDef(SAI);
+    assert(DefMA);
+
+    // { DomainDef[] }
+    auto Writes = getDomainFor(DefMA);
+
+    // { DomainDef[] -> Scatter[] }
+    auto WriteScatter = getScatterFor(Writes);
+
+    // { Scatter[] -> DomainDef[] }
+    auto ReachDef = getScalarReachingDefinition(DefMA->getStatement());
+
+    // { [DomainDef[] -> Scatter[]] -> DomainUse[] }
+    auto Uses = give(
+        isl_union_map_apply_range(isl_union_map_from_map(isl_map_range_map(
+                                      isl_map_reverse(ReachDef.take()))),
+                                  isl_union_map_reverse(ReadSchedule.take())));
+
+    // { DomainDef[] -> Scatter[] }
+    auto UseScatter =
+        singleton(give(isl_union_set_unwrap(isl_union_map_domain(Uses.copy()))),
+                  give(isl_space_map_from_domain_and_range(
+                      isl_set_get_space(Writes.keep()), ScatterSpace.copy())));
+
+    // { DomainDef[] -> Zone[] }
+    auto Lifetime = betweenScatter(WriteScatter, UseScatter, false, true);
+
+    // { DomainDef[] -> DomainRead[] }
+    auto DefUses = give(isl_union_map_domain_factor_domain(Uses.take()));
+
+    return std::make_pair(DefUses, Lifetime);
+  }
+
+  /// Try to map a MemoryKind::Value to a given array element.
+  ///
+  /// @param SAI       Representation of the scalar's memory to map.
+  /// @param TargetElt { Scatter[] -> Element[] }
+  ///                  Suggestion where to map a scalar to when at a timepoint.
+  ///
+  /// @return true if the scalar was successfully mapped.
+  bool tryMapValue(const ScopArrayInfo *SAI, isl::map TargetElt) {
+    assert(SAI->isValueKind());
+
+    auto *DefMA = S->getValueDef(SAI);
+    assert(DefMA->isValueKind());
+    assert(DefMA->isMustWrite());
+    auto *V = DefMA->getAccessValue();
+    auto *DefInst = DefMA->getAccessInstruction();
+
+    // Stop if the scalar has already been mapped.
+    if (!DefMA->getLatestScopArrayInfo()->isValueKind())
+      return false;
+
+    // { DomainDef[] -> Scatter[] }
+    auto DefSched = getScatterFor(DefMA);
+
+    // Where each write is mapped to, according to the suggestion.
+    // { DomainDef[] -> Element[] }
+    auto DefTarget = give(isl_map_apply_domain(
+        TargetElt.copy(), isl_map_reverse(DefSched.copy())));
+    simplify(DefTarget);
+    DEBUG(dbgs() << "    Def Mapping: " << DefTarget << '\n');
+
+    auto OrigDomain = getDomainFor(DefMA);
+    auto MappedDomain = give(isl_map_domain(DefTarget.copy()));
+    if (!isl_set_is_subset(OrigDomain.keep(), MappedDomain.keep())) {
+      DEBUG(dbgs()
+            << "    Reject because mapping does not encompass all instances\n");
+      return false;
+    }
+
+    // { DomainDef[] -> Zone[] }
+    isl::map Lifetime;
+
+    // { DomainDef[] -> DomainUse[] }
+    isl::union_map DefUses;
+
+    std::tie(DefUses, Lifetime) = computeValueUses(SAI);
+    DEBUG(dbgs() << "    Lifetime: " << Lifetime << '\n');
+
+    /// { [Element[] -> Zone[]] }
+    auto EltZone = give(
+        isl_map_wrap(isl_map_apply_domain(Lifetime.copy(), DefTarget.copy())));
+    simplify(EltZone);
+
+    // When known knowledge is disabled, just return the unknown value. It will
+    // either get filtered out or conflict with itself.
+    // { DomainDef[] -> ValInst[] }
+    isl::map ValInst;
+    if (DelicmComputeKnown)
+      ValInst = makeValInst(V, DefMA->getStatement(),
+                            LI->getLoopFor(DefInst->getParent()));
+    else
+      ValInst = makeUnknownForDomain(DefMA->getStatement());
+
+    // { DomainDef[] -> [Element[] -> Zone[]] }
+    auto EltKnownTranslator =
+        give(isl_map_range_product(DefTarget.copy(), Lifetime.copy()));
+
+    // { [Element[] -> Zone[]] -> ValInst[] }
+    auto EltKnown =
+        give(isl_map_apply_domain(ValInst.copy(), EltKnownTranslator.take()));
+    simplify(EltKnown);
+
+    // { DomainDef[] -> [Element[] -> Scatter[]] }
+    auto WrittenTranslator =
+        give(isl_map_range_product(DefTarget.copy(), DefSched.take()));
+
+    // { [Element[] -> Scatter[]] -> ValInst[] }
+    auto DefEltSched =
+        give(isl_map_apply_domain(ValInst.copy(), WrittenTranslator.take()));
+    simplify(DefEltSched);
+
+    Knowledge Proposed(EltZone, nullptr, filterKnownValInst(EltKnown),
+                       DefEltSched);
+    if (isConflicting(Proposed))
+      return false;
+
+    // { DomainUse[] -> Element[] }
+    auto UseTarget = give(
+        isl_union_map_apply_range(isl_union_map_reverse(DefUses.take()),
+                                  isl_union_map_from_map(DefTarget.copy())));
+
+    mapValue(SAI, std::move(DefTarget), std::move(UseTarget),
+             std::move(Lifetime), std::move(Proposed));
+    return true;
+  }
+
+  /// After a scalar has been mapped, update the global knowledge.
+  void applyLifetime(Knowledge Proposed) {
+    Zone.learnFrom(std::move(Proposed));
+  }
+
+  /// Map a MemoryKind::Value scalar to an array element.
+  ///
+  /// Callers must have ensured that the mapping is valid and not conflicting.
+  ///
+  /// @param SAI       The ScopArrayInfo representing the scalar's memory to
+  ///                  map.
+  /// @param DefTarget { DomainDef[] -> Element[] }
+  ///                  The array element to map the scalar to.
+  /// @param UseTarget { DomainUse[] -> Element[] }
+  ///                  The array elements the uses are mapped to.
+  /// @param Lifetime  { DomainDef[] -> Zone[] }
+  ///                  The lifetime of each llvm::Value definition for
+  ///                  reporting.
+  /// @param Proposed  Mapping constraints for reporting.
+  void mapValue(const ScopArrayInfo *SAI, isl::map DefTarget,
+                isl::union_map UseTarget, isl::map Lifetime,
+                Knowledge Proposed) {
+    // Redirect the read accesses.
+    for (auto *MA : S->getValueUses(SAI)) {
+      // { DomainUse[] }
+      auto Domain = getDomainFor(MA);
+
+      // { DomainUse[] -> Element[] }
+      auto NewAccRel = give(isl_union_map_intersect_domain(
+          UseTarget.copy(), isl_union_set_from_set(Domain.take())));
+      simplify(NewAccRel);
+
+      assert(isl_union_map_n_map(NewAccRel.keep()) == 1);
+      MA->setNewAccessRelation(isl::map::from_union_map(NewAccRel));
+    }
+
+    auto *WA = S->getValueDef(SAI);
+    WA->setNewAccessRelation(DefTarget);
+    applyLifetime(Proposed);
+
+    MappedValueScalars++;
+    NumberOfMappedValueScalars += 1;
+  }
+
+  isl::map makeValInst(Value *Val, ScopStmt *UserStmt, Loop *Scope,
+                       bool IsCertain = true) {
+    // When known knowledge is disabled, just return the unknown value. It will
+    // either get filtered out or conflict with itself.
+    if (!DelicmComputeKnown)
+      return makeUnknownForDomain(UserStmt);
+    return ZoneAlgorithm::makeValInst(Val, UserStmt, Scope, IsCertain);
+  }
+
+  /// Express the incoming values of a PHI for each incoming statement in an
+  /// isl::union_map.
+  ///
+  /// @param SAI The PHI scalar represented by a ScopArrayInfo.
+  ///
+  /// @return { PHIWriteDomain[] -> ValInst[] }
+  isl::union_map determinePHIWrittenValues(const ScopArrayInfo *SAI) {
+    auto Result = makeEmptyUnionMap();
+
+    // Collect the incoming values.
+    for (auto *MA : S->getPHIIncomings(SAI)) {
+      // { DomainWrite[] -> ValInst[] }
+      isl::union_map ValInst;
+      auto *WriteStmt = MA->getStatement();
+
+      auto Incoming = MA->getIncoming();
+      assert(!Incoming.empty());
+      if (Incoming.size() == 1) {
+        ValInst = makeValInst(Incoming[0].second, WriteStmt,
+                              LI->getLoopFor(Incoming[0].first));
+      } else {
+        // If the PHI is in a subregion's exit node it can have multiple
+        // incoming values (+ maybe another incoming edge from an unrelated
+        // block). We cannot directly represent it as a single llvm::Value.
+        // We currently model it as unknown value, but modeling as the PHIInst
+        // itself could be OK, too.
+        ValInst = makeUnknownForDomain(WriteStmt);
+      }
+
+      Result = give(isl_union_map_union(Result.take(), ValInst.take()));
+    }
+
+    assert(isl_union_map_is_single_valued(Result.keep()) == isl_bool_true &&
+           "Cannot have multiple incoming values for same incoming statement");
+    return Result;
+  }
+
+  /// Try to map a MemoryKind::PHI scalar to a given array element.
+  ///
+  /// @param SAI       Representation of the scalar's memory to map.
+  /// @param TargetElt { Scatter[] -> Element[] }
+  ///                  Suggestion where to map the scalar to when at a
+  ///                  timepoint.
+  ///
+  /// @return true if the PHI scalar has been mapped.
+  bool tryMapPHI(const ScopArrayInfo *SAI, isl::map TargetElt) {
+    auto *PHIRead = S->getPHIRead(SAI);
+    assert(PHIRead->isPHIKind());
+    assert(PHIRead->isRead());
+
+    // Skip if already been mapped.
+    if (!PHIRead->getLatestScopArrayInfo()->isPHIKind())
+      return false;
+
+    // { DomainRead[] -> Scatter[] }
+    auto PHISched = getScatterFor(PHIRead);
+
+    // { DomainRead[] -> Element[] }
+    auto PHITarget =
+        give(isl_map_apply_range(PHISched.copy(), TargetElt.copy()));
+    simplify(PHITarget);
+    DEBUG(dbgs() << "    Mapping: " << PHITarget << '\n');
+
+    auto OrigDomain = getDomainFor(PHIRead);
+    auto MappedDomain = give(isl_map_domain(PHITarget.copy()));
+    if (!isl_set_is_subset(OrigDomain.keep(), MappedDomain.keep())) {
+      DEBUG(dbgs()
+            << "    Reject because mapping does not encompass all instances\n");
+      return false;
+    }
+
+    // { DomainRead[] -> DomainWrite[] }
+    auto PerPHIWrites = computePerPHI(SAI);
+
+    // { DomainWrite[] -> Element[] }
+    auto WritesTarget = give(isl_union_map_reverse(isl_union_map_apply_domain(
+        PerPHIWrites.copy(), isl_union_map_from_map(PHITarget.copy()))));
+    simplify(WritesTarget);
+
+    // { DomainWrite[] }
+    auto UniverseWritesDom = give(isl_union_set_empty(ParamSpace.copy()));
+
+    for (auto *MA : S->getPHIIncomings(SAI))
+      UniverseWritesDom = give(isl_union_set_add_set(UniverseWritesDom.take(),
+                                                     getDomainFor(MA).take()));
+
+    auto RelevantWritesTarget = WritesTarget;
+    if (DelicmOverapproximateWrites)
+      WritesTarget = expandMapping(WritesTarget, UniverseWritesDom);
+
+    auto ExpandedWritesDom = give(isl_union_map_domain(WritesTarget.copy()));
+    if (!DelicmPartialWrites &&
+        !isl_union_set_is_subset(UniverseWritesDom.keep(),
+                                 ExpandedWritesDom.keep())) {
+      DEBUG(dbgs() << "    Reject because did not find PHI write mapping for "
+                      "all instances\n");
+      if (DelicmOverapproximateWrites)
+        DEBUG(dbgs() << "      Relevant Mapping:    " << RelevantWritesTarget
+                     << '\n');
+      DEBUG(dbgs() << "      Deduced Mapping:     " << WritesTarget << '\n');
+      DEBUG(dbgs() << "      Missing instances:    "
+                   << give(isl_union_set_subtract(UniverseWritesDom.copy(),
+                                                  ExpandedWritesDom.copy()))
+                   << '\n');
+      return false;
+    }
+
+    //  { DomainRead[] -> Scatter[] }
+    auto PerPHIWriteScatter = give(isl_map_from_union_map(
+        isl_union_map_apply_range(PerPHIWrites.copy(), Schedule.copy())));
+
+    // { DomainRead[] -> Zone[] }
+    auto Lifetime = betweenScatter(PerPHIWriteScatter, PHISched, false, true);
+    simplify(Lifetime);
+    DEBUG(dbgs() << "    Lifetime: " << Lifetime << "\n");
+
+    // { DomainWrite[] -> Zone[] }
+    auto WriteLifetime = give(isl_union_map_apply_domain(
+        isl_union_map_from_map(Lifetime.copy()), PerPHIWrites.copy()));
+
+    // { DomainWrite[] -> ValInst[] }
+    auto WrittenValue = determinePHIWrittenValues(SAI);
+
+    // { DomainWrite[] -> [Element[] -> Scatter[]] }
+    auto WrittenTranslator =
+        give(isl_union_map_range_product(WritesTarget.copy(), Schedule.copy()));
+
+    // { [Element[] -> Scatter[]] -> ValInst[] }
+    auto Written = give(isl_union_map_apply_domain(WrittenValue.copy(),
+                                                   WrittenTranslator.copy()));
+    simplify(Written);
+
+    // { DomainWrite[] -> [Element[] -> Zone[]] }
+    auto LifetimeTranslator = give(
+        isl_union_map_range_product(WritesTarget.copy(), WriteLifetime.copy()));
+
+    // { DomainWrite[] -> ValInst[] }
+    auto WrittenKnownValue = filterKnownValInst(WrittenValue);
+
+    // { [Element[] -> Zone[]] -> ValInst[] }
+    auto EltLifetimeInst = give(isl_union_map_apply_domain(
+        WrittenKnownValue.copy(), LifetimeTranslator.copy()));
+    simplify(EltLifetimeInst);
+
+    // { [Element[] -> Zone[] }
+    auto Occupied = give(isl_union_map_range(LifetimeTranslator.copy()));
+    simplify(Occupied);
+
+    Knowledge Proposed(Occupied, nullptr, EltLifetimeInst, Written);
+    if (isConflicting(Proposed))
+      return false;
+
+    mapPHI(SAI, std::move(PHITarget), std::move(WritesTarget),
+           std::move(Lifetime), std::move(Proposed));
+    return true;
+  }
+
+  /// Map a MemoryKind::PHI scalar to an array element.
+  ///
+  /// Callers must have ensured that the mapping is valid and not conflicting
+  /// with the common knowledge.
+  ///
+  /// @param SAI         The ScopArrayInfo representing the scalar's memory to
+  ///                    map.
+  /// @param ReadTarget  { DomainRead[] -> Element[] }
+  ///                    The array element to map the scalar to.
+  /// @param WriteTarget { DomainWrite[] -> Element[] }
+  ///                    New access target for each PHI incoming write.
+  /// @param Lifetime    { DomainRead[] -> Zone[] }
+  ///                    The lifetime of each PHI for reporting.
+  /// @param Proposed    Mapping constraints for reporting.
+  void mapPHI(const ScopArrayInfo *SAI, isl::map ReadTarget,
+              isl::union_map WriteTarget, isl::map Lifetime,
+              Knowledge Proposed) {
+    // { Element[] }
+    isl::space ElementSpace = ReadTarget.get_space().range();
+
+    // Redirect the PHI incoming writes.
+    for (auto *MA : S->getPHIIncomings(SAI)) {
+      // { DomainWrite[] }
+      auto Domain = getDomainFor(MA);
+
+      // { DomainWrite[] -> Element[] }
+      auto NewAccRel = give(isl_union_map_intersect_domain(
+          WriteTarget.copy(), isl_union_set_from_set(Domain.copy())));
+      simplify(NewAccRel);
+
+      isl::space NewAccRelSpace =
+          Domain.get_space().map_from_domain_and_range(ElementSpace);
+      isl::map NewAccRelMap = singleton(NewAccRel, NewAccRelSpace);
+      MA->setNewAccessRelation(NewAccRelMap);
+    }
+
+    // Redirect the PHI read.
+    auto *PHIRead = S->getPHIRead(SAI);
+    PHIRead->setNewAccessRelation(ReadTarget);
+    applyLifetime(Proposed);
+
+    MappedPHIScalars++;
+    NumberOfMappedPHIScalars++;
+  }
+
+  /// Search and map scalars to memory overwritten by @p TargetStoreMA.
+  ///
+  /// Start trying to map scalars that are used in the same statement as the
+  /// store. For every successful mapping, try to also map scalars of the
+  /// statements where those are written. Repeat, until no more mapping
+  /// opportunity is found.
+  ///
+  /// There is currently no preference in which order scalars are tried.
+  /// Ideally, we would direct it towards a load instruction of the same array
+  /// element.
+  bool collapseScalarsToStore(MemoryAccess *TargetStoreMA) {
+    assert(TargetStoreMA->isLatestArrayKind());
+    assert(TargetStoreMA->isMustWrite());
+
+    auto TargetStmt = TargetStoreMA->getStatement();
+
+    // { DomTarget[] }
+    auto TargetDom = getDomainFor(TargetStmt);
+
+    // { DomTarget[] -> Element[] }
+    auto TargetAccRel = getAccessRelationFor(TargetStoreMA);
+
+    // { Zone[] -> DomTarget[] }
+    // For each point in time, find the next target store instance.
+    auto Target =
+        computeScalarReachingOverwrite(Schedule, TargetDom, false, true);
+
+    // { Zone[] -> Element[] }
+    // Use the target store's write location as a suggestion to map scalars to.
+    auto EltTarget =
+        give(isl_map_apply_range(Target.take(), TargetAccRel.take()));
+    simplify(EltTarget);
+    DEBUG(dbgs() << "    Target mapping is " << EltTarget << '\n');
+
+    // Stack of elements not yet processed.
+    SmallVector<MemoryAccess *, 16> Worklist;
+
+    // Set of scalars already tested.
+    SmallPtrSet<const ScopArrayInfo *, 16> Closed;
+
+    // Lambda to add all scalar reads to the work list.
+    auto ProcessAllIncoming = [&](ScopStmt *Stmt) {
+      for (auto *MA : *Stmt) {
+        if (!MA->isLatestScalarKind())
+          continue;
+        if (!MA->isRead())
+          continue;
+
+        Worklist.push_back(MA);
+      }
+    };
+
+    auto *WrittenVal = TargetStoreMA->getAccessInstruction()->getOperand(0);
+    if (auto *WrittenValInputMA = TargetStmt->lookupInputAccessOf(WrittenVal))
+      Worklist.push_back(WrittenValInputMA);
+    else
+      ProcessAllIncoming(TargetStmt);
+
+    auto AnyMapped = false;
+    auto &DL = S->getRegion().getEntry()->getModule()->getDataLayout();
+    auto StoreSize =
+        DL.getTypeAllocSize(TargetStoreMA->getAccessValue()->getType());
+
+    while (!Worklist.empty()) {
+      auto *MA = Worklist.pop_back_val();
+
+      auto *SAI = MA->getScopArrayInfo();
+      if (Closed.count(SAI))
+        continue;
+      Closed.insert(SAI);
+      DEBUG(dbgs() << "\n    Trying to map " << MA << " (SAI: " << SAI
+                   << ")\n");
+
+      // Skip non-mappable scalars.
+      if (!isMappable(SAI))
+        continue;
+
+      auto MASize = DL.getTypeAllocSize(MA->getAccessValue()->getType());
+      if (MASize > StoreSize) {
+        DEBUG(dbgs() << "    Reject because storage size is insufficient\n");
+        continue;
+      }
+
+      // Try to map MemoryKind::Value scalars.
+      if (SAI->isValueKind()) {
+        if (!tryMapValue(SAI, EltTarget))
+          continue;
+
+        auto *DefAcc = S->getValueDef(SAI);
+        ProcessAllIncoming(DefAcc->getStatement());
+
+        AnyMapped = true;
+        continue;
+      }
+
+      // Try to map MemoryKind::PHI scalars.
+      if (SAI->isPHIKind()) {
+        if (!tryMapPHI(SAI, EltTarget))
+          continue;
+        // Add inputs of all incoming statements to the worklist. Prefer the
+        // input accesses of the incoming blocks.
+        for (auto *PHIWrite : S->getPHIIncomings(SAI)) {
+          auto *PHIWriteStmt = PHIWrite->getStatement();
+          bool FoundAny = false;
+          for (auto Incoming : PHIWrite->getIncoming()) {
+            auto *IncomingInputMA =
+                PHIWriteStmt->lookupInputAccessOf(Incoming.second);
+            if (!IncomingInputMA)
+              continue;
+
+            Worklist.push_back(IncomingInputMA);
+            FoundAny = true;
+          }
+
+          if (!FoundAny)
+            ProcessAllIncoming(PHIWrite->getStatement());
+        }
+
+        AnyMapped = true;
+        continue;
+      }
+    }
+
+    if (AnyMapped) {
+      TargetsMapped++;
+      NumberOfTargetsMapped++;
+    }
+    return AnyMapped;
+  }
+
+  /// Compute when an array element is unused.
+  ///
+  /// @return { [Element[] -> Zone[]] }
+  isl::union_set computeLifetime() const {
+    // { Element[] -> Zone[] }
+    auto ArrayUnused = computeArrayUnused(Schedule, AllMustWrites, AllReads,
+                                          false, false, true);
+
+    auto Result = give(isl_union_map_wrap(ArrayUnused.copy()));
+
+    simplify(Result);
+    return Result;
+  }
+
+  /// Determine when an array element is written to, and which value instance is
+  /// written.
+  ///
+  /// @return { [Element[] -> Scatter[]] -> ValInst[] }
+  isl::union_map computeWritten() const {
+    // { [Element[] -> Scatter[]] -> ValInst[] }
+    auto EltWritten = applyDomainRange(AllWriteValInst, Schedule);
+
+    simplify(EltWritten);
+    return EltWritten;
+  }
+
+  /// Determine whether an access touches at most one element.
+  ///
+  /// The accessed element could be a scalar or accessing an array with constant
+  /// subscript, such that all instances access only that element.
+  ///
+  /// @param MA The access to test.
+  ///
+  /// @return True, if zero or one elements are accessed; False if at least two
+  ///         different elements are accessed.
+  bool isScalarAccess(MemoryAccess *MA) {
+    auto Map = getAccessRelationFor(MA);
+    auto Set = give(isl_map_range(Map.take()));
+    return isl_set_is_singleton(Set.keep()) == isl_bool_true;
+  }
+
+  /// Print mapping statistics to @p OS.
+  void printStatistics(llvm::raw_ostream &OS, int Indent = 0) const {
+    OS.indent(Indent) << "Statistics {\n";
+    OS.indent(Indent + 4) << "Compatible overwrites: "
+                          << NumberOfCompatibleTargets << "\n";
+    OS.indent(Indent + 4) << "Overwrites mapped to:  " << NumberOfTargetsMapped
+                          << '\n';
+    OS.indent(Indent + 4) << "Value scalars mapped:  "
+                          << NumberOfMappedValueScalars << '\n';
+    OS.indent(Indent + 4) << "PHI scalars mapped:    "
+                          << NumberOfMappedPHIScalars << '\n';
+    OS.indent(Indent) << "}\n";
+  }
+
+  /// Return whether at least one transformation been applied.
+  bool isModified() const { return NumberOfTargetsMapped > 0; }
+
+public:
+  DeLICMImpl(Scop *S, LoopInfo *LI) : ZoneAlgorithm("polly-delicm", S, LI) {}
+
+  /// Calculate the lifetime (definition to last use) of every array element.
+  ///
+  /// @return True if the computed lifetimes (#Zone) is usable.
+  bool computeZone() {
+    // Check that nothing strange occurs.
+    collectCompatibleElts();
+
+    isl::union_set EltUnused;
+    isl::union_map EltKnown, EltWritten;
+
+    {
+      IslMaxOperationsGuard MaxOpGuard(IslCtx.get(), DelicmMaxOps);
+
+      computeCommon();
+
+      EltUnused = computeLifetime();
+      EltKnown = computeKnown(true, false);
+      EltWritten = computeWritten();
+    }
+    DeLICMAnalyzed++;
+
+    if (!EltUnused || !EltKnown || !EltWritten) {
+      assert(isl_ctx_last_error(IslCtx.get()) == isl_error_quota &&
+             "The only reason that these things have not been computed should "
+             "be if the max-operations limit hit");
+      DeLICMOutOfQuota++;
+      DEBUG(dbgs() << "DeLICM analysis exceeded max_operations\n");
+      DebugLoc Begin, End;
+      getDebugLocations(getBBPairForRegion(&S->getRegion()), Begin, End);
+      OptimizationRemarkAnalysis R(DEBUG_TYPE, "OutOfQuota", Begin,
+                                   S->getEntry());
+      R << "maximal number of operations exceeded during zone analysis";
+      S->getFunction().getContext().diagnose(R);
+      return false;
+    }
+
+    Zone = OriginalZone = Knowledge(nullptr, EltUnused, EltKnown, EltWritten);
+    DEBUG(dbgs() << "Computed Zone:\n"; OriginalZone.print(dbgs(), 4));
+
+    assert(Zone.isUsable() && OriginalZone.isUsable());
+    return true;
+  }
+
+  /// Try to map as many scalars to unused array elements as possible.
+  ///
+  /// Multiple scalars might be mappable to intersecting unused array element
+  /// zones, but we can only chose one. This is a greedy algorithm, therefore
+  /// the first processed element claims it.
+  void greedyCollapse() {
+    bool Modified = false;
+
+    for (auto &Stmt : *S) {
+      for (auto *MA : Stmt) {
+        if (!MA->isLatestArrayKind())
+          continue;
+        if (!MA->isWrite())
+          continue;
+
+        if (MA->isMayWrite()) {
+          DEBUG(dbgs() << "Access " << MA
+                       << " pruned because it is a MAY_WRITE\n");
+          OptimizationRemarkMissed R(DEBUG_TYPE, "TargetMayWrite",
+                                     MA->getAccessInstruction());
+          R << "Skipped possible mapping target because it is not an "
+               "unconditional overwrite";
+          S->getFunction().getContext().diagnose(R);
+          continue;
+        }
+
+        if (Stmt.getNumIterators() == 0) {
+          DEBUG(dbgs() << "Access " << MA
+                       << " pruned because it is not in a loop\n");
+          OptimizationRemarkMissed R(DEBUG_TYPE, "WriteNotInLoop",
+                                     MA->getAccessInstruction());
+          R << "skipped possible mapping target because it is not in a loop";
+          S->getFunction().getContext().diagnose(R);
+          continue;
+        }
+
+        if (isScalarAccess(MA)) {
+          DEBUG(dbgs() << "Access " << MA
+                       << " pruned because it writes only a single element\n");
+          OptimizationRemarkMissed R(DEBUG_TYPE, "ScalarWrite",
+                                     MA->getAccessInstruction());
+          R << "skipped possible mapping target because the memory location "
+               "written to does not depend on its outer loop";
+          S->getFunction().getContext().diagnose(R);
+          continue;
+        }
+
+        if (!isa<StoreInst>(MA->getAccessInstruction())) {
+          DEBUG(dbgs() << "Access " << MA
+                       << " pruned because it is not a StoreInst\n");
+          OptimizationRemarkMissed R(DEBUG_TYPE, "NotAStore",
+                                     MA->getAccessInstruction());
+          R << "skipped possible mapping target because non-store instructions "
+               "are not supported";
+          S->getFunction().getContext().diagnose(R);
+          continue;
+        }
+
+        // Check for more than one element acces per statement instance.
+        // Currently we expect write accesses to be functional, eg. disallow
+        //
+        //   { Stmt[0] -> [i] : 0 <= i < 2 }
+        //
+        // This may occur when some accesses to the element write/read only
+        // parts of the element, eg. a single byte. Polly then divides each
+        // element into subelements of the smallest access length, normal access
+        // then touch multiple of such subelements. It is very common when the
+        // array is accesses with memset, memcpy or memmove which take i8*
+        // arguments.
+        isl::union_map AccRel = MA->getLatestAccessRelation();
+        if (!AccRel.is_single_valued().is_true()) {
+          DEBUG(dbgs() << "Access " << MA
+                       << " is incompatible because it writes multiple "
+                          "elements per instance\n");
+          OptimizationRemarkMissed R(DEBUG_TYPE, "NonFunctionalAccRel",
+                                     MA->getAccessInstruction());
+          R << "skipped possible mapping target because it writes more than "
+               "one element";
+          S->getFunction().getContext().diagnose(R);
+          continue;
+        }
+
+        isl::union_set TouchedElts = AccRel.range();
+        if (!TouchedElts.is_subset(CompatibleElts)) {
+          DEBUG(
+              dbgs()
+              << "Access " << MA
+              << " is incompatible because it touches incompatible elements\n");
+          OptimizationRemarkMissed R(DEBUG_TYPE, "IncompatibleElts",
+                                     MA->getAccessInstruction());
+          R << "skipped possible mapping target because a target location "
+               "cannot be reliably analyzed";
+          S->getFunction().getContext().diagnose(R);
+          continue;
+        }
+
+        assert(isCompatibleAccess(MA));
+        NumberOfCompatibleTargets++;
+        DEBUG(dbgs() << "Analyzing target access " << MA << "\n");
+        if (collapseScalarsToStore(MA))
+          Modified = true;
+      }
+    }
+
+    if (Modified)
+      DeLICMScopsModified++;
+  }
+
+  /// Dump the internal information about a performed DeLICM to @p OS.
+  void print(llvm::raw_ostream &OS, int Indent = 0) {
+    if (!Zone.isUsable()) {
+      OS.indent(Indent) << "Zone not computed\n";
+      return;
+    }
+
+    printStatistics(OS, Indent);
+    if (!isModified()) {
+      OS.indent(Indent) << "No modification has been made\n";
+      return;
+    }
+    printAccesses(OS, Indent);
+  }
+};
+
+class DeLICM : public ScopPass {
+private:
+  DeLICM(const DeLICM &) = delete;
+  const DeLICM &operator=(const DeLICM &) = delete;
+
+  /// The pass implementation, also holding per-scop data.
+  std::unique_ptr<DeLICMImpl> Impl;
+
+  void collapseToUnused(Scop &S) {
+    auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+    Impl = make_unique<DeLICMImpl>(&S, &LI);
+
+    if (!Impl->computeZone()) {
+      DEBUG(dbgs() << "Abort because cannot reliably compute lifetimes\n");
+      return;
+    }
+
+    DEBUG(dbgs() << "Collapsing scalars to unused array elements...\n");
+    Impl->greedyCollapse();
+
+    DEBUG(dbgs() << "\nFinal Scop:\n");
+    DEBUG(dbgs() << S);
+  }
+
+public:
+  static char ID;
+  explicit DeLICM() : ScopPass(ID) {}
+
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.addRequiredTransitive<ScopInfoRegionPass>();
+    AU.addRequired<LoopInfoWrapperPass>();
+    AU.setPreservesAll();
+  }
+
+  virtual bool runOnScop(Scop &S) override {
+    // Free resources for previous scop's computation, if not yet done.
+    releaseMemory();
+
+    collapseToUnused(S);
+
+    auto ScopStats = S.getStatistics();
+    NumValueWrites += ScopStats.NumValueWrites;
+    NumValueWritesInLoops += ScopStats.NumValueWritesInLoops;
+    NumPHIWrites += ScopStats.NumPHIWrites;
+    NumPHIWritesInLoops += ScopStats.NumPHIWritesInLoops;
+    NumSingletonWrites += ScopStats.NumSingletonWrites;
+    NumSingletonWritesInLoops += ScopStats.NumSingletonWritesInLoops;
+
+    return false;
+  }
+
+  virtual void printScop(raw_ostream &OS, Scop &S) const override {
+    if (!Impl)
+      return;
+    assert(Impl->getScop() == &S);
+
+    OS << "DeLICM result:\n";
+    Impl->print(OS);
+  }
+
+  virtual void releaseMemory() override { Impl.reset(); }
+};
+
+char DeLICM::ID;
+} // anonymous namespace
+
+Pass *polly::createDeLICMPass() { return new DeLICM(); }
+
+INITIALIZE_PASS_BEGIN(DeLICM, "polly-delicm", "Polly - DeLICM/DePRE", false,
+                      false)
+INITIALIZE_PASS_DEPENDENCY(ScopInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
+INITIALIZE_PASS_END(DeLICM, "polly-delicm", "Polly - DeLICM/DePRE", false,
+                    false)
+
+bool polly::isConflicting(
+    isl::union_set ExistingOccupied, isl::union_set ExistingUnused,
+    isl::union_map ExistingKnown, isl::union_map ExistingWrites,
+    isl::union_set ProposedOccupied, isl::union_set ProposedUnused,
+    isl::union_map ProposedKnown, isl::union_map ProposedWrites,
+    llvm::raw_ostream *OS, unsigned Indent) {
+  Knowledge Existing(std::move(ExistingOccupied), std::move(ExistingUnused),
+                     std::move(ExistingKnown), std::move(ExistingWrites));
+  Knowledge Proposed(std::move(ProposedOccupied), std::move(ProposedUnused),
+                     std::move(ProposedKnown), std::move(ProposedWrites));
+
+  return Knowledge::isConflicting(Existing, Proposed, OS, Indent);
+}
diff --git a/final/lib/Transform/DeadCodeElimination.cpp b/final/lib/Transform/DeadCodeElimination.cpp
new file mode 100644
index 0000000..0960da0
--- /dev/null
+++ b/final/lib/Transform/DeadCodeElimination.cpp
@@ -0,0 +1,181 @@
+//===- DeadCodeElimination.cpp - Eliminate dead iteration  ----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The polyhedral dead code elimination pass analyses a SCoP to eliminate
+// statement instances that can be proven dead.
+// As a consequence, the code generated for this SCoP may execute a statement
+// less often. This means, a statement may be executed only in certain loop
+// iterations or it may not even be part of the generated code at all.
+//
+// This code:
+//
+//    for (i = 0; i < N; i++)
+//        arr[i] = 0;
+//    for (i = 0; i < N; i++)
+//        arr[i] = 10;
+//    for (i = 0; i < N; i++)
+//        arr[i] = i;
+//
+// is e.g. simplified to:
+//
+//    for (i = 0; i < N; i++)
+//        arr[i] = i;
+//
+// The idea and the algorithm used was first implemented by Sven Verdoolaege in
+// the 'ppcg' tool.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "llvm/Support/CommandLine.h"
+#include "isl/flow.h"
+#include "isl/isl-noexceptions.h"
+#include "isl/map.h"
+#include "isl/set.h"
+#include "isl/union_map.h"
+#include "isl/union_set.h"
+
+using namespace llvm;
+using namespace polly;
+
+namespace {
+
+cl::opt<int> DCEPreciseSteps(
+    "polly-dce-precise-steps",
+    cl::desc("The number of precise steps between two approximating "
+             "iterations. (A value of -1 schedules another approximation stage "
+             "before the actual dead code elimination."),
+    cl::ZeroOrMore, cl::init(-1), cl::cat(PollyCategory));
+
+class DeadCodeElim : public ScopPass {
+public:
+  static char ID;
+  explicit DeadCodeElim() : ScopPass(ID) {}
+
+  /// Remove dead iterations from the schedule of @p S.
+  bool runOnScop(Scop &S) override;
+
+  /// Register all analyses and transformation required.
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  /// Return the set of live iterations.
+  ///
+  /// The set of live iterations are all iterations that write to memory and for
+  /// which we can not prove that there will be a later write that _must_
+  /// overwrite the same memory location and is consequently the only one that
+  /// is visible after the execution of the SCoP.
+  ///
+  isl::union_set getLiveOut(Scop &S);
+  bool eliminateDeadCode(Scop &S, int PreciseSteps);
+};
+} // namespace
+
+char DeadCodeElim::ID = 0;
+
+// To compute the live outs, we compute for the data-locations that are
+// must-written to the last statement that touches these locations. On top of
+// this we add all statements that perform may-write accesses.
+//
+// We could be more precise by removing may-write accesses for which we know
+// that they are overwritten by a must-write after. However, at the moment the
+// only may-writes we introduce access the full (unbounded) array, such that
+// bounded write accesses can not overwrite all of the data-locations. As
+// this means may-writes are in the current situation always live, there is
+// no point in trying to remove them from the live-out set.
+isl::union_set DeadCodeElim::getLiveOut(Scop &S) {
+  isl::union_map Schedule = S.getSchedule();
+  isl::union_map MustWrites = S.getMustWrites();
+  isl::union_map WriteIterations = MustWrites.reverse();
+  isl::union_map WriteTimes = WriteIterations.apply_range(Schedule);
+
+  isl::union_map LastWriteTimes = WriteTimes.lexmax();
+  isl::union_map LastWriteIterations =
+      LastWriteTimes.apply_range(Schedule.reverse());
+
+  isl::union_set Live = LastWriteIterations.range();
+  isl::union_map MayWrites = S.getMayWrites();
+  Live = Live.unite(MayWrites.domain());
+  return Live.coalesce();
+}
+
+/// Performs polyhedral dead iteration elimination by:
+/// o Assuming that the last write to each location is live.
+/// o Following each RAW dependency from a live iteration backwards and adding
+///   that iteration to the live set.
+///
+/// To ensure the set of live iterations does not get too complex we always
+/// combine a certain number of precise steps with one approximating step that
+/// simplifies the life set with an affine hull.
+bool DeadCodeElim::eliminateDeadCode(Scop &S, int PreciseSteps) {
+  DependenceInfo &DI = getAnalysis<DependenceInfo>();
+  const Dependences &D = DI.getDependences(Dependences::AL_Statement);
+
+  if (!D.hasValidDependences())
+    return false;
+
+  isl::union_set Live = getLiveOut(S);
+  isl::union_map Dep = isl::manage(
+      D.getDependences(Dependences::TYPE_RAW | Dependences::TYPE_RED));
+  Dep = Dep.reverse();
+
+  if (PreciseSteps == -1)
+    Live = Live.affine_hull();
+
+  isl::union_set OriginalDomain = S.getDomains();
+  int Steps = 0;
+  while (true) {
+    Steps++;
+
+    isl::union_set Extra = Live.apply(Dep);
+
+    if (Extra.is_subset(Live))
+      break;
+
+    Live = Live.unite(Extra);
+
+    if (Steps > PreciseSteps) {
+      Steps = 0;
+      Live = Live.affine_hull();
+    }
+
+    Live = Live.intersect(OriginalDomain);
+  }
+
+  Live = Live.coalesce();
+
+  bool Changed = S.restrictDomains(Live);
+
+  // FIXME: We can probably avoid the recomputation of all dependences by
+  // updating them explicitly.
+  if (Changed)
+    DI.recomputeDependences(Dependences::AL_Statement);
+  return Changed;
+}
+
+bool DeadCodeElim::runOnScop(Scop &S) {
+  return eliminateDeadCode(S, DCEPreciseSteps);
+}
+
+void DeadCodeElim::getAnalysisUsage(AnalysisUsage &AU) const {
+  ScopPass::getAnalysisUsage(AU);
+  AU.addRequired<DependenceInfo>();
+}
+
+Pass *polly::createDeadCodeElimPass() { return new DeadCodeElim(); }
+
+INITIALIZE_PASS_BEGIN(DeadCodeElim, "polly-dce",
+                      "Polly - Remove dead iterations", false, false)
+INITIALIZE_PASS_DEPENDENCY(DependenceInfo)
+INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass)
+INITIALIZE_PASS_END(DeadCodeElim, "polly-dce", "Polly - Remove dead iterations",
+                    false, false)
diff --git a/final/lib/Transform/FlattenAlgo.cpp b/final/lib/Transform/FlattenAlgo.cpp
new file mode 100644
index 0000000..0258722
--- /dev/null
+++ b/final/lib/Transform/FlattenAlgo.cpp
@@ -0,0 +1,342 @@
+//===------ FlattenAlgo.cpp ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Main algorithm of the FlattenSchedulePass. This is a separate file to avoid
+// the unittest for this requiring linking against LLVM.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/FlattenAlgo.h"
+#include "polly/Support/ISLOStream.h"
+#include "polly/Support/ISLTools.h"
+#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "polly-flatten-algo"
+
+using namespace polly;
+using namespace llvm;
+
+namespace {
+
+/// Whether a dimension of a set is bounded (lower and upper) by a constant,
+/// i.e. there are two constants Min and Max, such that every value x of the
+/// chosen dimensions is Min <= x <= Max.
+bool isDimBoundedByConstant(isl::set Set, unsigned dim) {
+  auto ParamDims = Set.dim(isl::dim::param);
+  Set = Set.project_out(isl::dim::param, 0, ParamDims);
+  Set = Set.project_out(isl::dim::set, 0, dim);
+  auto SetDims = Set.dim(isl::dim::set);
+  Set = Set.project_out(isl::dim::set, 1, SetDims - 1);
+  return bool(Set.is_bounded());
+}
+
+/// Whether a dimension of a set is (lower and upper) bounded by a constant or
+/// parameters, i.e. there are two expressions Min_p and Max_p of the parameters
+/// p, such that every value x of the chosen dimensions is
+/// Min_p <= x <= Max_p.
+bool isDimBoundedByParameter(isl::set Set, unsigned dim) {
+  Set = Set.project_out(isl::dim::set, 0, dim);
+  auto SetDims = Set.dim(isl::dim::set);
+  Set = Set.project_out(isl::dim::set, 1, SetDims - 1);
+  return bool(Set.is_bounded());
+}
+
+/// Whether BMap's first out-dimension is not a constant.
+bool isVariableDim(const isl::basic_map &BMap) {
+  auto FixedVal = BMap.plain_get_val_if_fixed(isl::dim::out, 0);
+  return !FixedVal || FixedVal.is_nan();
+}
+
+/// Whether Map's first out dimension is no constant nor piecewise constant.
+bool isVariableDim(const isl::map &Map) {
+  return Map.foreach_basic_map([](isl::basic_map BMap) -> isl::stat {
+    if (isVariableDim(BMap))
+      return isl::stat::error;
+    return isl::stat::ok;
+  }) == isl::stat::ok;
+}
+
+/// Whether UMap's first out dimension is no (piecewise) constant.
+bool isVariableDim(const isl::union_map &UMap) {
+  return UMap.foreach_map([](isl::map Map) -> isl::stat {
+    if (isVariableDim(Map))
+      return isl::stat::error;
+    return isl::stat::ok;
+  }) == isl::stat::ok;
+}
+
+/// Compute @p UPwAff - @p Val.
+isl::union_pw_aff subtract(isl::union_pw_aff UPwAff, isl::val Val) {
+  if (Val.is_zero())
+    return UPwAff;
+
+  auto Result = isl::union_pw_aff::empty(UPwAff.get_space());
+  UPwAff.foreach_pw_aff([=, &Result](isl::pw_aff PwAff) -> isl::stat {
+    auto ValAff =
+        isl::pw_aff(isl::set::universe(PwAff.get_space().domain()), Val);
+    auto Subtracted = PwAff.sub(ValAff);
+    Result = Result.union_add(isl::union_pw_aff(Subtracted));
+    return isl::stat::ok;
+  });
+  return Result;
+}
+
+/// Compute @UPwAff * @p Val.
+isl::union_pw_aff multiply(isl::union_pw_aff UPwAff, isl::val Val) {
+  if (Val.is_one())
+    return UPwAff;
+
+  auto Result = isl::union_pw_aff::empty(UPwAff.get_space());
+  UPwAff.foreach_pw_aff([=, &Result](isl::pw_aff PwAff) -> isl::stat {
+    auto ValAff =
+        isl::pw_aff(isl::set::universe(PwAff.get_space().domain()), Val);
+    auto Multiplied = PwAff.mul(ValAff);
+    Result = Result.union_add(Multiplied);
+    return isl::stat::ok;
+  });
+  return Result;
+}
+
+/// Remove @p n dimensions from @p UMap's range, starting at @p first.
+///
+/// It is assumed that all maps in the maps have at least the necessary number
+/// of out dimensions.
+isl::union_map scheduleProjectOut(const isl::union_map &UMap, unsigned first,
+                                  unsigned n) {
+  if (n == 0)
+    return UMap; /* isl_map_project_out would also reset the tuple, which should
+                    have no effect on schedule ranges */
+
+  auto Result = isl::union_map::empty(UMap.get_space());
+  UMap.foreach_map([=, &Result](isl::map Map) -> isl::stat {
+    auto Outprojected = Map.project_out(isl::dim::out, first, n);
+    Result = Result.add_map(Outprojected);
+    return isl::stat::ok;
+  });
+  return Result;
+}
+
+/// Return the number of dimensions in the input map's range.
+///
+/// Because this function takes an isl_union_map, the out dimensions could be
+/// different. We return the maximum number in this case. However, a different
+/// number of dimensions is not supported by the other code in this file.
+size_t scheduleScatterDims(const isl::union_map &Schedule) {
+  unsigned Dims = 0;
+  Schedule.foreach_map([&Dims](isl::map Map) -> isl::stat {
+    Dims = std::max(Dims, Map.dim(isl::dim::out));
+    return isl::stat::ok;
+  });
+  return Dims;
+}
+
+/// Return the @p pos' range dimension, converted to an isl_union_pw_aff.
+isl::union_pw_aff scheduleExtractDimAff(isl::union_map UMap, unsigned pos) {
+  auto SingleUMap = isl::union_map::empty(UMap.get_space());
+  UMap.foreach_map([=, &SingleUMap](isl::map Map) -> isl::stat {
+    auto MapDims = Map.dim(isl::dim::out);
+    auto SingleMap = Map.project_out(isl::dim::out, 0, pos);
+    SingleMap = SingleMap.project_out(isl::dim::out, 1, MapDims - pos - 1);
+    SingleUMap = SingleUMap.add_map(SingleMap);
+    return isl::stat::ok;
+  });
+
+  auto UAff = isl::union_pw_multi_aff(SingleUMap);
+  auto FirstMAff = isl::multi_union_pw_aff(UAff);
+  return FirstMAff.get_union_pw_aff(0);
+}
+
+/// Flatten a sequence-like first dimension.
+///
+/// A sequence-like scatter dimension is constant, or at least only small
+/// variation, typically the result of ordering a sequence of different
+/// statements. An example would be:
+///   { Stmt_A[] -> [0, X, ...]; Stmt_B[] -> [1, Y, ...] }
+/// to schedule all instances of Stmt_A before any instance of Stmt_B.
+///
+/// To flatten, first begin with an offset of zero. Then determine the lowest
+/// possible value of the dimension, call it "i" [In the example we start at 0].
+/// Considering only schedules with that value, consider only instances with
+/// that value and determine the extent of the next dimension. Let l_X(i) and
+/// u_X(i) its minimum (lower bound) and maximum (upper bound) value. Add them
+/// as "Offset + X - l_X(i)" to the new schedule, then add "u_X(i) - l_X(i) + 1"
+/// to Offset and remove all i-instances from the old schedule. Repeat with the
+/// remaining lowest value i' until there are no instances in the old schedule
+/// left.
+/// The example schedule would be transformed to:
+///   { Stmt_X[] -> [X - l_X, ...]; Stmt_B -> [l_X - u_X + 1 + Y - l_Y, ...] }
+isl::union_map tryFlattenSequence(isl::union_map Schedule) {
+  auto IslCtx = Schedule.get_ctx();
+  auto ScatterSet = isl::set(Schedule.range());
+
+  auto ParamSpace = Schedule.get_space().params();
+  auto Dims = ScatterSet.dim(isl::dim::set);
+  assert(Dims >= 2);
+
+  // Would cause an infinite loop.
+  if (!isDimBoundedByConstant(ScatterSet, 0)) {
+    DEBUG(dbgs() << "Abort; dimension is not of fixed size\n");
+    return nullptr;
+  }
+
+  auto AllDomains = Schedule.domain();
+  auto AllDomainsToNull = isl::union_pw_multi_aff(AllDomains);
+
+  auto NewSchedule = isl::union_map::empty(ParamSpace);
+  auto Counter = isl::pw_aff(isl::local_space(ParamSpace.set_from_params()));
+
+  while (!ScatterSet.is_empty()) {
+    DEBUG(dbgs() << "Next counter:\n  " << Counter << "\n");
+    DEBUG(dbgs() << "Remaining scatter set:\n  " << ScatterSet << "\n");
+    auto ThisSet = ScatterSet.project_out(isl::dim::set, 1, Dims - 1);
+    auto ThisFirst = ThisSet.lexmin();
+    auto ScatterFirst = ThisFirst.add_dims(isl::dim::set, Dims - 1);
+
+    auto SubSchedule = Schedule.intersect_range(ScatterFirst);
+    SubSchedule = scheduleProjectOut(SubSchedule, 0, 1);
+    SubSchedule = flattenSchedule(SubSchedule);
+
+    auto SubDims = scheduleScatterDims(SubSchedule);
+    auto FirstSubSchedule = scheduleProjectOut(SubSchedule, 1, SubDims - 1);
+    auto FirstScheduleAff = scheduleExtractDimAff(FirstSubSchedule, 0);
+    auto RemainingSubSchedule = scheduleProjectOut(SubSchedule, 0, 1);
+
+    auto FirstSubScatter = isl::set(FirstSubSchedule.range());
+    DEBUG(dbgs() << "Next step in sequence is:\n  " << FirstSubScatter << "\n");
+
+    if (!isDimBoundedByParameter(FirstSubScatter, 0)) {
+      DEBUG(dbgs() << "Abort; sequence step is not bounded\n");
+      return nullptr;
+    }
+
+    auto FirstSubScatterMap = isl::map::from_range(FirstSubScatter);
+
+    // isl_set_dim_max returns a strange isl_pw_aff with domain tuple_id of
+    // 'none'. It doesn't match with any space including a 0-dimensional
+    // anonymous tuple.
+    // Interesting, one can create such a set using
+    // isl_set_universe(ParamSpace). Bug?
+    auto PartMin = FirstSubScatterMap.dim_min(0);
+    auto PartMax = FirstSubScatterMap.dim_max(0);
+    auto One = isl::pw_aff(isl::set::universe(ParamSpace.set_from_params()),
+                           isl::val::one(IslCtx));
+    auto PartLen = PartMax.add(PartMin.neg()).add(One);
+
+    auto AllPartMin = isl::union_pw_aff(PartMin).pullback(AllDomainsToNull);
+    auto FirstScheduleAffNormalized = FirstScheduleAff.sub(AllPartMin);
+    auto AllCounter = isl::union_pw_aff(Counter).pullback(AllDomainsToNull);
+    auto FirstScheduleAffWithOffset =
+        FirstScheduleAffNormalized.add(AllCounter);
+
+    auto ScheduleWithOffset = isl::union_map(FirstScheduleAffWithOffset)
+                                  .flat_range_product(RemainingSubSchedule);
+    NewSchedule = NewSchedule.unite(ScheduleWithOffset);
+
+    ScatterSet = ScatterSet.subtract(ScatterFirst);
+    Counter = Counter.add(PartLen);
+  }
+
+  DEBUG(dbgs() << "Sequence-flatten result is:\n  " << NewSchedule << "\n");
+  return NewSchedule;
+}
+
+/// Flatten a loop-like first dimension.
+///
+/// A loop-like dimension is one that depends on a variable (usually a loop's
+/// induction variable). Let the input schedule look like this:
+///   { Stmt[i] -> [i, X, ...] }
+///
+/// To flatten, we determine the largest extent of X which may not depend on the
+/// actual value of i. Let l_X() the smallest possible value of X and u_X() its
+/// largest value. Then, construct a new schedule
+///   { Stmt[i] -> [i * (u_X() - l_X() + 1), ...] }
+isl::union_map tryFlattenLoop(isl::union_map Schedule) {
+  assert(scheduleScatterDims(Schedule) >= 2);
+
+  auto Remaining = scheduleProjectOut(Schedule, 0, 1);
+  auto SubSchedule = flattenSchedule(Remaining);
+  auto SubDims = scheduleScatterDims(SubSchedule);
+
+  auto SubExtent = isl::set(SubSchedule.range());
+  auto SubExtentDims = SubExtent.dim(isl::dim::param);
+  SubExtent = SubExtent.project_out(isl::dim::param, 0, SubExtentDims);
+  SubExtent = SubExtent.project_out(isl::dim::set, 1, SubDims - 1);
+
+  if (!isDimBoundedByConstant(SubExtent, 0)) {
+    DEBUG(dbgs() << "Abort; dimension not bounded by constant\n");
+    return nullptr;
+  }
+
+  auto Min = SubExtent.dim_min(0);
+  DEBUG(dbgs() << "Min bound:\n  " << Min << "\n");
+  auto MinVal = getConstant(Min, false, true);
+  auto Max = SubExtent.dim_max(0);
+  DEBUG(dbgs() << "Max bound:\n  " << Max << "\n");
+  auto MaxVal = getConstant(Max, true, false);
+
+  if (!MinVal || !MaxVal || MinVal.is_nan() || MaxVal.is_nan()) {
+    DEBUG(dbgs() << "Abort; dimension bounds could not be determined\n");
+    return nullptr;
+  }
+
+  auto FirstSubScheduleAff = scheduleExtractDimAff(SubSchedule, 0);
+  auto RemainingSubSchedule = scheduleProjectOut(std::move(SubSchedule), 0, 1);
+
+  auto LenVal = MaxVal.sub(MinVal).add_ui(1);
+  auto FirstSubScheduleNormalized = subtract(FirstSubScheduleAff, MinVal);
+
+  // TODO: Normalize FirstAff to zero (convert to isl_map, determine minimum,
+  // subtract it)
+  auto FirstAff = scheduleExtractDimAff(Schedule, 0);
+  auto Offset = multiply(FirstAff, LenVal);
+  auto Index = FirstSubScheduleNormalized.add(Offset);
+  auto IndexMap = isl::union_map(Index);
+
+  auto Result = IndexMap.flat_range_product(RemainingSubSchedule);
+  DEBUG(dbgs() << "Loop-flatten result is:\n  " << Result << "\n");
+  return Result;
+}
+} // anonymous namespace
+
+isl::union_map polly::flattenSchedule(isl::union_map Schedule) {
+  auto Dims = scheduleScatterDims(Schedule);
+  DEBUG(dbgs() << "Recursive schedule to process:\n  " << Schedule << "\n");
+
+  // Base case; no dimensions left
+  if (Dims == 0) {
+    // TODO: Add one dimension?
+    return Schedule;
+  }
+
+  // Base case; already one-dimensional
+  if (Dims == 1)
+    return Schedule;
+
+  // Fixed dimension; no need to preserve variabledness.
+  if (!isVariableDim(Schedule)) {
+    DEBUG(dbgs() << "Fixed dimension; try sequence flattening\n");
+    auto NewScheduleSequence = tryFlattenSequence(Schedule);
+    if (NewScheduleSequence)
+      return NewScheduleSequence;
+  }
+
+  // Constant stride
+  DEBUG(dbgs() << "Try loop flattening\n");
+  auto NewScheduleLoop = tryFlattenLoop(Schedule);
+  if (NewScheduleLoop)
+    return NewScheduleLoop;
+
+  // Try again without loop condition (may blow up the number of pieces!!)
+  DEBUG(dbgs() << "Try sequence flattening again\n");
+  auto NewScheduleSequence = tryFlattenSequence(Schedule);
+  if (NewScheduleSequence)
+    return NewScheduleSequence;
+
+  // Cannot flatten
+  return Schedule;
+}
diff --git a/final/lib/Transform/FlattenSchedule.cpp b/final/lib/Transform/FlattenSchedule.cpp
new file mode 100644
index 0000000..5bdb6ab
--- /dev/null
+++ b/final/lib/Transform/FlattenSchedule.cpp
@@ -0,0 +1,108 @@
+//===------ FlattenSchedule.cpp --------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Try to reduce the number of scatter dimension. Useful to make isl_union_map
+// schedules more understandable. This is only intended for debugging and
+// unittests, not for production use.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/FlattenSchedule.h"
+#include "polly/FlattenAlgo.h"
+#include "polly/ScopInfo.h"
+#include "polly/ScopPass.h"
+#include "polly/Support/ISLOStream.h"
+#define DEBUG_TYPE "polly-flatten-schedule"
+
+using namespace polly;
+using namespace llvm;
+
+namespace {
+
+/// Print a schedule to @p OS.
+///
+/// Prints the schedule for each statements on a new line.
+void printSchedule(raw_ostream &OS, const isl::union_map &Schedule,
+                   int indent) {
+  Schedule.foreach_map([&OS, indent](isl::map Map) -> isl::stat {
+    OS.indent(indent) << Map << "\n";
+    return isl::stat::ok;
+  });
+}
+
+/// Flatten the schedule stored in an polly::Scop.
+class FlattenSchedule : public ScopPass {
+private:
+  FlattenSchedule(const FlattenSchedule &) = delete;
+  const FlattenSchedule &operator=(const FlattenSchedule &) = delete;
+
+  std::shared_ptr<isl_ctx> IslCtx;
+  isl::union_map OldSchedule;
+
+public:
+  static char ID;
+  explicit FlattenSchedule() : ScopPass(ID) {}
+
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.addRequiredTransitive<ScopInfoRegionPass>();
+    AU.setPreservesAll();
+  }
+
+  virtual bool runOnScop(Scop &S) override {
+    // Keep a reference to isl_ctx to ensure that it is not freed before we free
+    // OldSchedule.
+    IslCtx = S.getSharedIslCtx();
+
+    DEBUG(dbgs() << "Going to flatten old schedule:\n");
+    OldSchedule = S.getSchedule();
+    DEBUG(printSchedule(dbgs(), OldSchedule, 2));
+
+    auto Domains = S.getDomains();
+    auto RestrictedOldSchedule = OldSchedule.intersect_domain(Domains);
+    DEBUG(dbgs() << "Old schedule with domains:\n");
+    DEBUG(printSchedule(dbgs(), RestrictedOldSchedule, 2));
+
+    auto NewSchedule = flattenSchedule(RestrictedOldSchedule);
+
+    DEBUG(dbgs() << "Flattened new schedule:\n");
+    DEBUG(printSchedule(dbgs(), NewSchedule, 2));
+
+    NewSchedule = NewSchedule.gist_domain(Domains);
+    DEBUG(dbgs() << "Gisted, flattened new schedule:\n");
+    DEBUG(printSchedule(dbgs(), NewSchedule, 2));
+
+    S.setSchedule(NewSchedule);
+    return false;
+  }
+
+  virtual void printScop(raw_ostream &OS, Scop &S) const override {
+    OS << "Schedule before flattening {\n";
+    printSchedule(OS, OldSchedule, 4);
+    OS << "}\n\n";
+
+    OS << "Schedule after flattening {\n";
+    printSchedule(OS, S.getSchedule(), 4);
+    OS << "}\n";
+  }
+
+  virtual void releaseMemory() override {
+    OldSchedule = nullptr;
+    IslCtx.reset();
+  }
+};
+
+char FlattenSchedule::ID;
+} // anonymous namespace
+
+Pass *polly::createFlattenSchedulePass() { return new FlattenSchedule(); }
+
+INITIALIZE_PASS_BEGIN(FlattenSchedule, "polly-flatten-schedule",
+                      "Polly - Flatten schedule", false, false)
+INITIALIZE_PASS_END(FlattenSchedule, "polly-flatten-schedule",
+                    "Polly - Flatten schedule", false, false)
diff --git a/final/lib/Transform/ForwardOpTree.cpp b/final/lib/Transform/ForwardOpTree.cpp
new file mode 100644
index 0000000..dbdf8fc
--- /dev/null
+++ b/final/lib/Transform/ForwardOpTree.cpp
@@ -0,0 +1,1019 @@
+//===- ForwardOpTree.h ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Move instructions between statements.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/ForwardOpTree.h"
+#include "polly/Options.h"
+#include "polly/ScopBuilder.h"
+#include "polly/ScopInfo.h"
+#include "polly/ScopPass.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/ISLOStream.h"
+#include "polly/Support/ISLTools.h"
+#include "polly/Support/VirtualInstruction.h"
+#include "polly/ZoneAlgo.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include "isl/ctx.h"
+#include "isl/isl-noexceptions.h"
+#include <cassert>
+#include <memory>
+
+#define DEBUG_TYPE "polly-optree"
+
+using namespace llvm;
+using namespace polly;
+
+static cl::opt<bool>
+    AnalyzeKnown("polly-optree-analyze-known",
+                 cl::desc("Analyze array contents for load forwarding"),
+                 cl::cat(PollyCategory), cl::init(true), cl::Hidden);
+
+static cl::opt<bool>
+    NormalizePHIs("polly-optree-normalize-phi",
+                  cl::desc("Replace PHIs by their incoming values"),
+                  cl::cat(PollyCategory), cl::init(false), cl::Hidden);
+
+static cl::opt<unsigned>
+    MaxOps("polly-optree-max-ops",
+           cl::desc("Maximum number of ISL operations to invest for known "
+                    "analysis; 0=no limit"),
+           cl::init(1000000), cl::cat(PollyCategory), cl::Hidden);
+
+STATISTIC(KnownAnalyzed, "Number of successfully analyzed SCoPs");
+STATISTIC(KnownOutOfQuota,
+          "Analyses aborted because max_operations was reached");
+
+STATISTIC(TotalInstructionsCopied, "Number of copied instructions");
+STATISTIC(TotalKnownLoadsForwarded,
+          "Number of forwarded loads because their value was known");
+STATISTIC(TotalReloads, "Number of reloaded values");
+STATISTIC(TotalReadOnlyCopied, "Number of copied read-only accesses");
+STATISTIC(TotalForwardedTrees, "Number of forwarded operand trees");
+STATISTIC(TotalModifiedStmts,
+          "Number of statements with at least one forwarded tree");
+
+STATISTIC(ScopsModified, "Number of SCoPs with at least one forwarded tree");
+
+STATISTIC(NumValueWrites, "Number of scalar value writes after OpTree");
+STATISTIC(NumValueWritesInLoops,
+          "Number of scalar value writes nested in affine loops after OpTree");
+STATISTIC(NumPHIWrites, "Number of scalar phi writes after OpTree");
+STATISTIC(NumPHIWritesInLoops,
+          "Number of scalar phi writes nested in affine loops after OpTree");
+STATISTIC(NumSingletonWrites, "Number of singleton writes after OpTree");
+STATISTIC(NumSingletonWritesInLoops,
+          "Number of singleton writes nested in affine loops after OpTree");
+
+namespace {
+
+/// The state of whether an operand tree was/can be forwarded.
+///
+/// The items apply to an instructions and its operand tree with the instruction
+/// as the root element. If the value in question is not an instruction in the
+/// SCoP, it can be a leaf of an instruction's operand tree.
+enum ForwardingDecision {
+  /// The root instruction or value cannot be forwarded at all.
+  FD_CannotForward,
+
+  /// The root instruction or value can be forwarded as a leaf of a larger
+  /// operand tree.
+  /// It does not make sense to move the value itself, it would just replace it
+  /// by a use of itself. For instance, a constant "5" used in a statement can
+  /// be forwarded, but it would just replace it by the same constant "5".
+  /// However, it makes sense to move as an operand of
+  ///
+  ///   %add = add 5, 5
+  ///
+  /// where "5" is moved as part of a larger operand tree. "5" would be placed
+  /// (disregarding for a moment that literal constants don't have a location
+  /// and can be used anywhere) into the same statement as %add would.
+  FD_CanForwardLeaf,
+
+  /// The root instruction can be forwarded and doing so avoids a scalar
+  /// dependency.
+  ///
+  /// This can be either because the operand tree can be moved to the target
+  /// statement, or a memory access is redirected to read from a different
+  /// location.
+  FD_CanForwardProfitably,
+
+  /// Used to indicate that a forwarding has be carried out successfully, and
+  /// the forwarded memory access can be deleted.
+  FD_DidForwardTree,
+
+  /// Used to indicate that a forwarding has be carried out successfully, and
+  /// the forwarded memory access is being reused.
+  FD_DidForwardLeaf,
+
+  /// A forwarding method cannot be applied to the operand tree.
+  /// The difference to FD_CannotForward is that there might be other methods
+  /// that can handle it.
+  /// The conditions that make an operand tree applicable must be checked even
+  /// with DoIt==true because a method following the one that returned
+  /// FD_NotApplicable might have returned FD_CanForwardTree.
+  FD_NotApplicable
+};
+
+/// Implementation of operand tree forwarding for a specific SCoP.
+///
+/// For a statement that requires a scalar value (through a value read
+/// MemoryAccess), see if its operand can be moved into the statement. If so,
+/// the MemoryAccess is removed and the all the operand tree instructions are
+/// moved into the statement. All original instructions are left in the source
+/// statements. The simplification pass can clean these up.
+class ForwardOpTreeImpl : ZoneAlgorithm {
+private:
+  /// Scope guard to limit the number of isl operations for this pass.
+  IslMaxOperationsGuard &MaxOpGuard;
+
+  /// How many instructions have been copied to other statements.
+  int NumInstructionsCopied = 0;
+
+  /// Number of loads forwarded because their value was known.
+  int NumKnownLoadsForwarded = 0;
+
+  /// Number of values reloaded from known array elements.
+  int NumReloads = 0;
+
+  /// How many read-only accesses have been copied.
+  int NumReadOnlyCopied = 0;
+
+  /// How many operand trees have been forwarded.
+  int NumForwardedTrees = 0;
+
+  /// Number of statements with at least one forwarded operand tree.
+  int NumModifiedStmts = 0;
+
+  /// Whether we carried out at least one change to the SCoP.
+  bool Modified = false;
+
+  /// Contains the zones where array elements are known to contain a specific
+  /// value.
+  /// { [Element[] -> Zone[]] -> ValInst[] }
+  /// @see computeKnown()
+  isl::union_map Known;
+
+  /// Translator for newly introduced ValInsts to already existing ValInsts such
+  /// that new introduced load instructions can reuse the Known analysis of its
+  /// original load. { ValInst[] -> ValInst[] }
+  isl::union_map Translator;
+
+  /// Get list of array elements that do contain the same ValInst[] at Domain[].
+  ///
+  /// @param ValInst { Domain[] -> ValInst[] }
+  ///                The values for which we search for alternative locations,
+  ///                per statement instance.
+  ///
+  /// @return { Domain[] -> Element[] }
+  ///         For each statement instance, the array elements that contain the
+  ///         same ValInst.
+  isl::union_map findSameContentElements(isl::union_map ValInst) {
+    assert(!ValInst.is_single_valued().is_false());
+
+    // { Domain[] }
+    isl::union_set Domain = ValInst.domain();
+
+    // { Domain[] -> Scatter[] }
+    isl::union_map Schedule = getScatterFor(Domain);
+
+    // { Element[] -> [Scatter[] -> ValInst[]] }
+    isl::union_map MustKnownCurried =
+        convertZoneToTimepoints(Known, isl::dim::in, false, true).curry();
+
+    // { [Domain[] -> ValInst[]] -> Scatter[] }
+    isl::union_map DomValSched = ValInst.domain_map().apply_range(Schedule);
+
+    // { [Scatter[] -> ValInst[]] -> [Domain[] -> ValInst[]] }
+    isl::union_map SchedValDomVal =
+        DomValSched.range_product(ValInst.range_map()).reverse();
+
+    // { Element[] -> [Domain[] -> ValInst[]] }
+    isl::union_map MustKnownInst = MustKnownCurried.apply_range(SchedValDomVal);
+
+    // { Domain[] -> Element[] }
+    isl::union_map MustKnownMap =
+        MustKnownInst.uncurry().domain().unwrap().reverse();
+    simplify(MustKnownMap);
+
+    return MustKnownMap;
+  }
+
+  /// Find a single array element for each statement instance, within a single
+  /// array.
+  ///
+  /// @param MustKnown { Domain[] -> Element[] }
+  ///                  Set of candidate array elements.
+  /// @param Domain    { Domain[] }
+  ///                  The statement instance for which we need elements for.
+  ///
+  /// @return { Domain[] -> Element[] }
+  ///         For each statement instance, an array element out of @p MustKnown.
+  ///         All array elements must be in the same array (Polly does not yet
+  ///         support reading from different accesses using the same
+  ///         MemoryAccess). If no mapping for all of @p Domain exists, returns
+  ///         null.
+  isl::map singleLocation(isl::union_map MustKnown, isl::set Domain) {
+    // { Domain[] -> Element[] }
+    isl::map Result;
+
+    // MemoryAccesses can read only elements from a single array
+    // (i.e. not: { Dom[0] -> A[0]; Dom[1] -> B[1] }).
+    // Look through all spaces until we find one that contains at least the
+    // wanted statement instance.s
+    MustKnown.foreach_map([&](isl::map Map) -> isl::stat {
+      // Get the array this is accessing.
+      isl::id ArrayId = Map.get_tuple_id(isl::dim::out);
+      ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(ArrayId.get_user());
+
+      // No support for generation of indirect array accesses.
+      if (SAI->getBasePtrOriginSAI())
+        return isl::stat::ok; // continue
+
+      // Determine whether this map contains all wanted values.
+      isl::set MapDom = Map.domain();
+      if (!Domain.is_subset(MapDom).is_true())
+        return isl::stat::ok; // continue
+
+      // There might be multiple array elements that contain the same value, but
+      // choose only one of them. lexmin is used because it returns a one-value
+      // mapping, we do not care about which one.
+      // TODO: Get the simplest access function.
+      Result = Map.lexmin();
+      return isl::stat::error; // break
+    });
+
+    return Result;
+  }
+
+public:
+  ForwardOpTreeImpl(Scop *S, LoopInfo *LI, IslMaxOperationsGuard &MaxOpGuard)
+      : ZoneAlgorithm("polly-optree", S, LI), MaxOpGuard(MaxOpGuard) {}
+
+  /// Compute the zones of known array element contents.
+  ///
+  /// @return True if the computed #Known is usable.
+  bool computeKnownValues() {
+    isl::union_map MustKnown, KnownFromLoad, KnownFromInit;
+
+    // Check that nothing strange occurs.
+    collectCompatibleElts();
+
+    {
+      IslQuotaScope QuotaScope = MaxOpGuard.enter();
+
+      computeCommon();
+      if (NormalizePHIs)
+        computeNormalizedPHIs();
+      Known = computeKnown(true, true);
+
+      // Preexisting ValInsts use the known content analysis of themselves.
+      Translator = makeIdentityMap(Known.range(), false);
+    }
+
+    if (!Known || !Translator || !NormalizeMap) {
+      assert(isl_ctx_last_error(IslCtx.get()) == isl_error_quota);
+      Known = nullptr;
+      Translator = nullptr;
+      NormalizeMap = nullptr;
+      DEBUG(dbgs() << "Known analysis exceeded max_operations\n");
+      return false;
+    }
+
+    KnownAnalyzed++;
+    DEBUG(dbgs() << "All known: " << Known << "\n");
+
+    return true;
+  }
+
+  void printStatistics(raw_ostream &OS, int Indent = 0) {
+    OS.indent(Indent) << "Statistics {\n";
+    OS.indent(Indent + 4) << "Instructions copied: " << NumInstructionsCopied
+                          << '\n';
+    OS.indent(Indent + 4) << "Known loads forwarded: " << NumKnownLoadsForwarded
+                          << '\n';
+    OS.indent(Indent + 4) << "Reloads: " << NumReloads << '\n';
+    OS.indent(Indent + 4) << "Read-only accesses copied: " << NumReadOnlyCopied
+                          << '\n';
+    OS.indent(Indent + 4) << "Operand trees forwarded: " << NumForwardedTrees
+                          << '\n';
+    OS.indent(Indent + 4) << "Statements with forwarded operand trees: "
+                          << NumModifiedStmts << '\n';
+    OS.indent(Indent) << "}\n";
+  }
+
+  void printStatements(raw_ostream &OS, int Indent = 0) const {
+    OS.indent(Indent) << "After statements {\n";
+    for (auto &Stmt : *S) {
+      OS.indent(Indent + 4) << Stmt.getBaseName() << "\n";
+      for (auto *MA : Stmt)
+        MA->print(OS);
+
+      OS.indent(Indent + 12);
+      Stmt.printInstructions(OS);
+    }
+    OS.indent(Indent) << "}\n";
+  }
+
+  /// Create a new MemoryAccess of type read and MemoryKind::Array.
+  ///
+  /// @param Stmt           The statement in which the access occurs.
+  /// @param LI             The instruction that does the access.
+  /// @param AccessRelation The array element that each statement instance
+  ///                       accesses.
+  ///
+  /// @param The newly created access.
+  MemoryAccess *makeReadArrayAccess(ScopStmt *Stmt, LoadInst *LI,
+                                    isl::map AccessRelation) {
+    isl::id ArrayId = AccessRelation.get_tuple_id(isl::dim::out);
+    ScopArrayInfo *SAI = reinterpret_cast<ScopArrayInfo *>(ArrayId.get_user());
+
+    // Create a dummy SCEV access, to be replaced anyway.
+    SmallVector<const SCEV *, 4> Sizes;
+    Sizes.reserve(SAI->getNumberOfDimensions());
+    SmallVector<const SCEV *, 4> Subscripts;
+    Subscripts.reserve(SAI->getNumberOfDimensions());
+    for (unsigned i = 0; i < SAI->getNumberOfDimensions(); i += 1) {
+      Sizes.push_back(SAI->getDimensionSize(i));
+      Subscripts.push_back(nullptr);
+    }
+
+    MemoryAccess *Access =
+        new MemoryAccess(Stmt, LI, MemoryAccess::READ, SAI->getBasePtr(),
+                         LI->getType(), true, {}, Sizes, LI, MemoryKind::Array);
+    S->addAccessFunction(Access);
+    Stmt->addAccess(Access, true);
+
+    Access->setNewAccessRelation(AccessRelation);
+
+    return Access;
+  }
+
+  /// For an llvm::Value defined in @p DefStmt, compute the RAW dependency for a
+  /// use in every instance of @p UseStmt.
+  ///
+  /// @param UseStmt Statement a scalar is used in.
+  /// @param DefStmt Statement a scalar is defined in.
+  ///
+  /// @return { DomainUse[] -> DomainDef[] }
+  isl::map computeUseToDefFlowDependency(ScopStmt *UseStmt, ScopStmt *DefStmt) {
+    // { DomainUse[] -> Scatter[] }
+    isl::map UseScatter = getScatterFor(UseStmt);
+
+    // { Zone[] -> DomainDef[] }
+    isl::map ReachDefZone = getScalarReachingDefinition(DefStmt);
+
+    // { Scatter[] -> DomainDef[] }
+    isl::map ReachDefTimepoints =
+        convertZoneToTimepoints(ReachDefZone, isl::dim::in, false, true);
+
+    // { DomainUse[] -> DomainDef[] }
+    return UseScatter.apply_range(ReachDefTimepoints);
+  }
+
+  /// Forward a load by reading from an array element that contains the same
+  /// value. Typically the location it was loaded from.
+  ///
+  /// @param TargetStmt  The statement the operand tree will be copied to.
+  /// @param Inst        The (possibly speculatable) instruction to forward.
+  /// @param UseStmt     The statement that uses @p Inst.
+  /// @param UseLoop     The loop @p Inst is used in.
+  /// @param UseToTarget { DomainUse[] -> DomainTarget[] }
+  ///                    A mapping from the statement instance @p Inst is used
+  ///                    to the statement instance it is forwarded to.
+  /// @param DefStmt     The statement @p Inst is defined in.
+  /// @param DefLoop     The loop which contains @p Inst.
+  /// @param DefToTarget { DomainDef[] -> DomainTarget[] }
+  ///                    A mapping from the statement instance @p Inst is
+  ///                    defined to the statement instance it is forwarded to.
+  /// @param DoIt        If false, only determine whether an operand tree can be
+  ///                    forwarded. If true, carry out the forwarding. Do not
+  ///                    use DoIt==true if an operand tree is not known to be
+  ///                    forwardable.
+  ///
+  /// @return FD_NotApplicable  if @p Inst cannot be forwarded by creating a new
+  ///                           load.
+  ///         FD_CannotForward  if the pointer operand cannot be forwarded.
+  ///         FD_CanForwardProfitably if @p Inst is forwardable.
+  ///         FD_DidForwardTree if @p DoIt was true.
+  ForwardingDecision forwardKnownLoad(ScopStmt *TargetStmt, Instruction *Inst,
+                                      ScopStmt *UseStmt, Loop *UseLoop,
+                                      isl::map UseToTarget, ScopStmt *DefStmt,
+                                      Loop *DefLoop, isl::map DefToTarget,
+                                      bool DoIt) {
+    // Cannot do anything without successful known analysis.
+    if (Known.is_null() || Translator.is_null() || UseToTarget.is_null() ||
+        DefToTarget.is_null() || MaxOpGuard.hasQuotaExceeded())
+      return FD_NotApplicable;
+
+    LoadInst *LI = dyn_cast<LoadInst>(Inst);
+    if (!LI)
+      return FD_NotApplicable;
+
+    // If the load is already in the statement, no forwarding is necessary.
+    // However, it might happen that the LoadInst is already present in the
+    // statement's instruction list. In that case we do as follows:
+    // - For the evaluation (DoIt==false), we can trivially forward it as it is
+    //   benefit of forwarding an already present instruction.
+    // - For the execution (DoIt==true), prepend the instruction (to make it
+    //   available to all instructions following in the instruction list), but
+    //   do not add another MemoryAccess.
+    MemoryAccess *Access = TargetStmt->getArrayAccessOrNULLFor(LI);
+    if (Access && !DoIt)
+      return FD_CanForwardProfitably;
+
+    ForwardingDecision OpDecision =
+        forwardTree(TargetStmt, LI->getPointerOperand(), DefStmt, DefLoop,
+                    DefToTarget, DoIt);
+    switch (OpDecision) {
+    case FD_CannotForward:
+      assert(!DoIt);
+      return OpDecision;
+
+    case FD_CanForwardLeaf:
+    case FD_CanForwardProfitably:
+      assert(!DoIt);
+      break;
+
+    case FD_DidForwardLeaf:
+    case FD_DidForwardTree:
+      assert(DoIt);
+      break;
+
+    default:
+      llvm_unreachable("Shouldn't return this");
+    }
+
+    IslQuotaScope QuotaScope = MaxOpGuard.enter(!DoIt);
+
+    // { DomainDef[] -> ValInst[] }
+    isl::map ExpectedVal = makeValInst(Inst, UseStmt, UseLoop);
+    assert(isNormalized(ExpectedVal) && "LoadInsts are always normalized");
+
+    // { DomainTarget[] -> ValInst[] }
+    isl::map TargetExpectedVal = ExpectedVal.apply_domain(UseToTarget);
+    isl::union_map TranslatedExpectedVal =
+        isl::union_map(TargetExpectedVal).apply_range(Translator);
+
+    // { DomainTarget[] -> Element[] }
+    isl::union_map Candidates = findSameContentElements(TranslatedExpectedVal);
+
+    isl::map SameVal = singleLocation(Candidates, getDomainFor(TargetStmt));
+    if (!SameVal)
+      return FD_NotApplicable;
+
+    if (DoIt)
+      TargetStmt->prependInstruction(LI);
+
+    if (!DoIt)
+      return FD_CanForwardProfitably;
+
+    if (Access) {
+      DEBUG(dbgs() << "    forwarded known load with preexisting MemoryAccess"
+                   << Access << "\n");
+    } else {
+      Access = makeReadArrayAccess(TargetStmt, LI, SameVal);
+      DEBUG(dbgs() << "    forwarded known load with new MemoryAccess" << Access
+                   << "\n");
+
+      // { ValInst[] }
+      isl::space ValInstSpace = ExpectedVal.get_space().range();
+
+      // After adding a new load to the SCoP, also update the Known content
+      // about it. The new load will have a known ValInst of
+      // { [DomainTarget[] -> Value[]] }
+      // but which -- because it is a copy of it -- has same value as the
+      // { [DomainDef[] -> Value[]] }
+      // that it replicates. Instead of  cloning the known content of
+      // [DomainDef[] -> Value[]]
+      // for DomainTarget[], we add a 'translator' that maps
+      // [DomainTarget[] -> Value[]] to [DomainDef[] -> Value[]]
+      // before comparing to the known content.
+      // TODO: 'Translator' could also be used to map PHINodes to their incoming
+      // ValInsts.
+      if (ValInstSpace.is_wrapping()) {
+        // { DefDomain[] -> Value[] }
+        isl::map ValInsts = ExpectedVal.range().unwrap();
+
+        // { DefDomain[] }
+        isl::set DefDomain = ValInsts.domain();
+
+        // { Value[] }
+        isl::space ValSpace = ValInstSpace.unwrap().range();
+
+        // { Value[] -> Value[] }
+        isl::map ValToVal =
+            isl::map::identity(ValSpace.map_from_domain_and_range(ValSpace));
+
+        // { [TargetDomain[] -> Value[]] -> [DefDomain[] -> Value] }
+        isl::map LocalTranslator = DefToTarget.reverse().product(ValToVal);
+
+        Translator = Translator.add_map(LocalTranslator);
+        DEBUG(dbgs() << "      local translator is " << LocalTranslator
+                     << "\n");
+      }
+    }
+    DEBUG(dbgs() << "      expected values where " << TargetExpectedVal
+                 << "\n");
+    DEBUG(dbgs() << "      candidate elements where " << Candidates << "\n");
+    assert(Access);
+
+    NumKnownLoadsForwarded++;
+    TotalKnownLoadsForwarded++;
+    return FD_DidForwardTree;
+  }
+
+  /// Forward a scalar by redirecting the access to an array element that stores
+  /// the same value.
+  ///
+  /// @param TargetStmt  The statement the operand tree will be copied to.
+  /// @param Inst        The scalar to forward.
+  /// @param UseStmt     The statement that uses @p Inst.
+  /// @param UseLoop     The loop @p Inst is used in.
+  /// @param UseToTarget { DomainUse[] -> DomainTarget[] }
+  ///                    A mapping from the statement instance @p Inst is used
+  ///                    in, to the statement instance it is forwarded to.
+  /// @param DefStmt     The statement @p Inst is defined in.
+  /// @param DefLoop     The loop which contains @p Inst.
+  /// @param DefToTarget { DomainDef[] -> DomainTarget[] }
+  ///                    A mapping from the statement instance @p Inst is
+  ///                    defined in, to the statement instance it is forwarded
+  ///                    to.
+  /// @param DoIt        If false, only determine whether an operand tree can be
+  ///                    forwarded. If true, carry out the forwarding. Do not
+  ///                    use DoIt==true if an operand tree is not known to be
+  ///                    forwardable.
+  ///
+  /// @return FD_NotApplicable        if @p Inst cannot be reloaded.
+  ///         FD_CanForwardLeaf       if @p Inst can be reloaded.
+  ///         FD_CanForwardProfitably if @p Inst has been reloaded.
+  ///         FD_DidForwardLeaf       if @p DoIt was true.
+  ForwardingDecision reloadKnownContent(ScopStmt *TargetStmt, Instruction *Inst,
+                                        ScopStmt *UseStmt, Loop *UseLoop,
+                                        isl::map UseToTarget, ScopStmt *DefStmt,
+                                        Loop *DefLoop, isl::map DefToTarget,
+                                        bool DoIt) {
+    // Cannot do anything without successful known analysis.
+    if (Known.is_null() || Translator.is_null() || UseToTarget.is_null() ||
+        DefToTarget.is_null() || MaxOpGuard.hasQuotaExceeded())
+      return FD_NotApplicable;
+
+    MemoryAccess *Access = TargetStmt->lookupInputAccessOf(Inst);
+    if (Access && Access->isLatestArrayKind()) {
+      if (DoIt)
+        return FD_DidForwardLeaf;
+      return FD_CanForwardLeaf;
+    }
+
+    // Don't spend too much time analyzing whether it can be reloaded. When
+    // carrying-out the forwarding, we cannot bail-out in the middle of the
+    // transformation. It also shouldn't take as long because some results are
+    // cached.
+    IslQuotaScope QuotaScope = MaxOpGuard.enter(!DoIt);
+
+    // { DomainDef[] -> ValInst[] }
+    isl::union_map ExpectedVal = makeNormalizedValInst(Inst, UseStmt, UseLoop);
+
+    // { DomainTarget[] -> ValInst[] }
+    isl::union_map TargetExpectedVal = ExpectedVal.apply_domain(UseToTarget);
+    isl::union_map TranslatedExpectedVal =
+        TargetExpectedVal.apply_range(Translator);
+
+    // { DomainTarget[] -> Element[] }
+    isl::union_map Candidates = findSameContentElements(TranslatedExpectedVal);
+
+    isl::map SameVal = singleLocation(Candidates, getDomainFor(TargetStmt));
+    if (!SameVal)
+      return FD_NotApplicable;
+
+    if (!DoIt)
+      return FD_CanForwardProfitably;
+
+    if (!Access)
+      Access = TargetStmt->ensureValueRead(Inst);
+
+    simplify(SameVal);
+    Access->setNewAccessRelation(SameVal);
+
+    TotalReloads++;
+    NumReloads++;
+    return FD_DidForwardLeaf;
+  }
+
+  /// Forwards a speculatively executable instruction.
+  ///
+  /// @param TargetStmt  The statement the operand tree will be copied to.
+  /// @param UseInst     The (possibly speculatable) instruction to forward.
+  /// @param DefStmt     The statement @p UseInst is defined in.
+  /// @param DefLoop     The loop which contains @p UseInst.
+  /// @param DefToTarget { DomainDef[] -> DomainTarget[] }
+  ///                    A mapping from the statement instance @p UseInst is
+  ///                    defined to the statement instance it is forwarded to.
+  /// @param DoIt        If false, only determine whether an operand tree can be
+  ///                    forwarded. If true, carry out the forwarding. Do not
+  ///                    use DoIt==true if an operand tree is not known to be
+  ///                    forwardable.
+  ///
+  /// @return FD_NotApplicable  if @p UseInst is not speculatable.
+  ///         FD_CannotForward  if one of @p UseInst's operands is not
+  ///                           forwardable.
+  ///         FD_CanForwardTree if @p UseInst is forwardable.
+  ///         FD_DidForward     if @p DoIt was true.
+  ForwardingDecision forwardSpeculatable(ScopStmt *TargetStmt,
+                                         Instruction *UseInst,
+                                         ScopStmt *DefStmt, Loop *DefLoop,
+                                         isl::map DefToTarget, bool DoIt) {
+    // PHIs, unless synthesizable, are not yet supported.
+    if (isa<PHINode>(UseInst))
+      return FD_NotApplicable;
+
+    // Compatible instructions must satisfy the following conditions:
+    // 1. Idempotent (instruction will be copied, not moved; although its
+    //    original instance might be removed by simplification)
+    // 2. Not access memory (There might be memory writes between)
+    // 3. Not cause undefined behaviour (we might copy to a location when the
+    //    original instruction was no executed; this is currently not possible
+    //    because we do not forward PHINodes)
+    // 4. Not leak memory if executed multiple times (i.e. malloc)
+    //
+    // Instruction::mayHaveSideEffects is not sufficient because it considers
+    // malloc to not have side-effects. llvm::isSafeToSpeculativelyExecute is
+    // not sufficient because it allows memory accesses.
+    if (mayBeMemoryDependent(*UseInst))
+      return FD_NotApplicable;
+
+    if (DoIt) {
+      // To ensure the right order, prepend this instruction before its
+      // operands. This ensures that its operands are inserted before the
+      // instruction using them.
+      // TODO: The operand tree is not really a tree, but a DAG. We should be
+      // able to handle DAGs without duplication.
+      TargetStmt->prependInstruction(UseInst);
+      NumInstructionsCopied++;
+      TotalInstructionsCopied++;
+    }
+
+    for (Value *OpVal : UseInst->operand_values()) {
+      ForwardingDecision OpDecision =
+          forwardTree(TargetStmt, OpVal, DefStmt, DefLoop, DefToTarget, DoIt);
+      switch (OpDecision) {
+      case FD_CannotForward:
+        assert(!DoIt);
+        return FD_CannotForward;
+
+      case FD_CanForwardLeaf:
+      case FD_CanForwardProfitably:
+        assert(!DoIt);
+        break;
+
+      case FD_DidForwardLeaf:
+      case FD_DidForwardTree:
+        assert(DoIt);
+        break;
+
+      case FD_NotApplicable:
+        llvm_unreachable("forwardTree should never return FD_NotApplicable");
+      }
+    }
+
+    if (DoIt)
+      return FD_DidForwardTree;
+    return FD_CanForwardProfitably;
+  }
+
+  /// Determines whether an operand tree can be forwarded or carries out a
+  /// forwarding, depending on the @p DoIt flag.
+  ///
+  /// @param TargetStmt  The statement the operand tree will be copied to.
+  /// @param UseVal      The value (usually an instruction) which is root of an
+  ///                    operand tree.
+  /// @param UseStmt     The statement that uses @p UseVal.
+  /// @param UseLoop     The loop @p UseVal is used in.
+  /// @param UseToTarget { DomainUse[] -> DomainTarget[] }
+  ///                    A mapping from the statement instance @p UseVal is used
+  ///                    to the statement instance it is forwarded to.
+  /// @param DoIt        If false, only determine whether an operand tree can be
+  ///                    forwarded. If true, carry out the forwarding. Do not
+  ///                    use DoIt==true if an operand tree is not known to be
+  ///                    forwardable.
+  ///
+  /// @return If DoIt==false, return whether the operand tree can be forwarded.
+  ///         If DoIt==true, return FD_DidForward.
+  ForwardingDecision forwardTree(ScopStmt *TargetStmt, Value *UseVal,
+                                 ScopStmt *UseStmt, Loop *UseLoop,
+                                 isl::map UseToTarget, bool DoIt) {
+    ScopStmt *DefStmt = nullptr;
+    Loop *DefLoop = nullptr;
+
+    // { DefDomain[] -> TargetDomain[] }
+    isl::map DefToTarget;
+
+    VirtualUse VUse = VirtualUse::create(UseStmt, UseLoop, UseVal, true);
+    switch (VUse.getKind()) {
+    case VirtualUse::Constant:
+    case VirtualUse::Block:
+    case VirtualUse::Hoisted:
+      // These can be used anywhere without special considerations.
+      if (DoIt)
+        return FD_DidForwardTree;
+      return FD_CanForwardLeaf;
+
+    case VirtualUse::Synthesizable: {
+      // ScopExpander will take care for of generating the code at the new
+      // location.
+      if (DoIt)
+        return FD_DidForwardTree;
+
+      // Check if the value is synthesizable at the new location as well. This
+      // might be possible when leaving a loop for which ScalarEvolution is
+      // unable to derive the exit value for.
+      // TODO: If there is a LCSSA PHI at the loop exit, use that one.
+      // If the SCEV contains a SCEVAddRecExpr, we currently depend on that we
+      // do not forward past its loop header. This would require us to use a
+      // previous loop induction variable instead the current one. We currently
+      // do not allow forwarding PHI nodes, thus this should never occur (the
+      // only exception where no phi is necessary being an unreachable loop
+      // without edge from the outside).
+      VirtualUse TargetUse = VirtualUse::create(
+          S, TargetStmt, TargetStmt->getSurroundingLoop(), UseVal, true);
+      if (TargetUse.getKind() == VirtualUse::Synthesizable)
+        return FD_CanForwardLeaf;
+
+      DEBUG(dbgs() << "    Synthesizable would not be synthesizable anymore: "
+                   << *UseVal << "\n");
+      return FD_CannotForward;
+    }
+
+    case VirtualUse::ReadOnly:
+      // Note that we cannot return FD_CanForwardTree here. With a operand tree
+      // depth of 0, UseVal is the use in TargetStmt that we try to replace.
+      // With -polly-analyze-read-only-scalars=true we would ensure the
+      // existence of a MemoryAccess (which already exists for a leaf) and be
+      // removed again by tryForwardTree because it's goal is to remove this
+      // scalar MemoryAccess. It interprets FD_CanForwardTree as the permission
+      // to do so.
+      if (!DoIt)
+        return FD_CanForwardLeaf;
+
+      // If we model read-only scalars, we need to create a MemoryAccess for it.
+      if (ModelReadOnlyScalars)
+        TargetStmt->ensureValueRead(UseVal);
+
+      NumReadOnlyCopied++;
+      TotalReadOnlyCopied++;
+      return FD_DidForwardLeaf;
+
+    case VirtualUse::Intra:
+      // Knowing that UseStmt and DefStmt are the same statement instance, just
+      // reuse the information about UseStmt for DefStmt
+      DefStmt = UseStmt;
+      DefToTarget = UseToTarget;
+
+      LLVM_FALLTHROUGH;
+    case VirtualUse::Inter:
+      Instruction *Inst = cast<Instruction>(UseVal);
+
+      if (!DefStmt) {
+        DefStmt = S->getStmtFor(Inst);
+        if (!DefStmt)
+          return FD_CannotForward;
+      }
+
+      DefLoop = LI->getLoopFor(Inst->getParent());
+
+      if (DefToTarget.is_null() && !Known.is_null()) {
+        IslQuotaScope QuotaScope = MaxOpGuard.enter(!DoIt);
+
+        // { UseDomain[] -> DefDomain[] }
+        isl::map UseToDef = computeUseToDefFlowDependency(UseStmt, DefStmt);
+
+        // { DefDomain[] -> UseDomain[] -> TargetDomain[] } shortened to
+        // { DefDomain[] -> TargetDomain[] }
+        DefToTarget = UseToTarget.apply_domain(UseToDef);
+        simplify(DefToTarget);
+      }
+
+      ForwardingDecision SpeculativeResult = forwardSpeculatable(
+          TargetStmt, Inst, DefStmt, DefLoop, DefToTarget, DoIt);
+      if (SpeculativeResult != FD_NotApplicable)
+        return SpeculativeResult;
+
+      ForwardingDecision KnownResult =
+          forwardKnownLoad(TargetStmt, Inst, UseStmt, UseLoop, UseToTarget,
+                           DefStmt, DefLoop, DefToTarget, DoIt);
+      if (KnownResult != FD_NotApplicable)
+        return KnownResult;
+
+      ForwardingDecision ReloadResult =
+          reloadKnownContent(TargetStmt, Inst, UseStmt, UseLoop, UseToTarget,
+                             DefStmt, DefLoop, DefToTarget, DoIt);
+      if (ReloadResult != FD_NotApplicable)
+        return ReloadResult;
+
+      // When no method is found to forward the operand tree, we effectively
+      // cannot handle it.
+      DEBUG(dbgs() << "    Cannot forward instruction: " << *Inst << "\n");
+      return FD_CannotForward;
+    }
+
+    llvm_unreachable("Case unhandled");
+  }
+
+  /// Try to forward an operand tree rooted in @p RA.
+  bool tryForwardTree(MemoryAccess *RA) {
+    assert(RA->isLatestScalarKind());
+    DEBUG(dbgs() << "Trying to forward operand tree " << RA << "...\n");
+
+    ScopStmt *Stmt = RA->getStatement();
+    Loop *InLoop = Stmt->getSurroundingLoop();
+
+    isl::map TargetToUse;
+    if (!Known.is_null()) {
+      isl::space DomSpace = Stmt->getDomainSpace();
+      TargetToUse =
+          isl::map::identity(DomSpace.map_from_domain_and_range(DomSpace));
+    }
+
+    ForwardingDecision Assessment = forwardTree(
+        Stmt, RA->getAccessValue(), Stmt, InLoop, TargetToUse, false);
+    assert(Assessment != FD_DidForwardTree && Assessment != FD_DidForwardLeaf);
+    if (Assessment != FD_CanForwardProfitably)
+      return false;
+
+    ForwardingDecision Execution = forwardTree(Stmt, RA->getAccessValue(), Stmt,
+                                               InLoop, TargetToUse, true);
+    assert(((Execution == FD_DidForwardTree) ||
+            (Execution == FD_DidForwardLeaf)) &&
+           "A previous positive assessment must also be executable");
+
+    if (Execution == FD_DidForwardTree)
+      Stmt->removeSingleMemoryAccess(RA);
+    return true;
+  }
+
+  /// Return which SCoP this instance is processing.
+  Scop *getScop() const { return S; }
+
+  /// Run the algorithm: Use value read accesses as operand tree roots and try
+  /// to forward them into the statement.
+  bool forwardOperandTrees() {
+    for (ScopStmt &Stmt : *S) {
+      bool StmtModified = false;
+
+      // Because we are modifying the MemoryAccess list, collect them first to
+      // avoid iterator invalidation.
+      SmallVector<MemoryAccess *, 16> Accs;
+      for (MemoryAccess *RA : Stmt) {
+        if (!RA->isRead())
+          continue;
+        if (!RA->isLatestScalarKind())
+          continue;
+
+        Accs.push_back(RA);
+      }
+
+      for (MemoryAccess *RA : Accs) {
+        if (tryForwardTree(RA)) {
+          Modified = true;
+          StmtModified = true;
+          NumForwardedTrees++;
+          TotalForwardedTrees++;
+        }
+      }
+
+      if (StmtModified) {
+        NumModifiedStmts++;
+        TotalModifiedStmts++;
+      }
+    }
+
+    if (Modified)
+      ScopsModified++;
+    return Modified;
+  }
+
+  /// Print the pass result, performed transformations and the SCoP after the
+  /// transformation.
+  void print(raw_ostream &OS, int Indent = 0) {
+    printStatistics(OS, Indent);
+
+    if (!Modified) {
+      // This line can easily be checked in regression tests.
+      OS << "ForwardOpTree executed, but did not modify anything\n";
+      return;
+    }
+
+    printStatements(OS, Indent);
+  }
+};
+
+/// Pass that redirects scalar reads to array elements that are known to contain
+/// the same value.
+///
+/// This reduces the number of scalar accesses and therefore potentially
+/// increases the freedom of the scheduler. In the ideal case, all reads of a
+/// scalar definition are redirected (We currently do not care about removing
+/// the write in this case).  This is also useful for the main DeLICM pass as
+/// there are less scalars to be mapped.
+class ForwardOpTree : public ScopPass {
+private:
+  /// The pass implementation, also holding per-scop data.
+  std::unique_ptr<ForwardOpTreeImpl> Impl;
+
+public:
+  static char ID;
+
+  explicit ForwardOpTree() : ScopPass(ID) {}
+  ForwardOpTree(const ForwardOpTree &) = delete;
+  ForwardOpTree &operator=(const ForwardOpTree &) = delete;
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.addRequiredTransitive<ScopInfoRegionPass>();
+    AU.addRequired<LoopInfoWrapperPass>();
+    AU.setPreservesAll();
+  }
+
+  bool runOnScop(Scop &S) override {
+    // Free resources for previous SCoP's computation, if not yet done.
+    releaseMemory();
+
+    LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+
+    {
+      IslMaxOperationsGuard MaxOpGuard(S.getIslCtx().get(), MaxOps, false);
+      Impl = llvm::make_unique<ForwardOpTreeImpl>(&S, &LI, MaxOpGuard);
+
+      if (AnalyzeKnown) {
+        DEBUG(dbgs() << "Prepare forwarders...\n");
+        Impl->computeKnownValues();
+      }
+
+      DEBUG(dbgs() << "Forwarding operand trees...\n");
+      Impl->forwardOperandTrees();
+
+      if (MaxOpGuard.hasQuotaExceeded()) {
+        DEBUG(dbgs() << "Not all operations completed because of "
+                        "max_operations exceeded\n");
+        KnownOutOfQuota++;
+      }
+    }
+
+    DEBUG(dbgs() << "\nFinal Scop:\n");
+    DEBUG(dbgs() << S);
+
+    // Update statistics
+    auto ScopStats = S.getStatistics();
+    NumValueWrites += ScopStats.NumValueWrites;
+    NumValueWritesInLoops += ScopStats.NumValueWritesInLoops;
+    NumPHIWrites += ScopStats.NumPHIWrites;
+    NumPHIWritesInLoops += ScopStats.NumPHIWritesInLoops;
+    NumSingletonWrites += ScopStats.NumSingletonWrites;
+    NumSingletonWritesInLoops += ScopStats.NumSingletonWritesInLoops;
+
+    return false;
+  }
+
+  void printScop(raw_ostream &OS, Scop &S) const override {
+    if (!Impl)
+      return;
+
+    assert(Impl->getScop() == &S);
+    Impl->print(OS);
+  }
+
+  void releaseMemory() override { Impl.reset(); }
+}; // class ForwardOpTree
+
+char ForwardOpTree::ID;
+
+} // namespace
+
+ScopPass *polly::createForwardOpTreePass() { return new ForwardOpTree(); }
+
+INITIALIZE_PASS_BEGIN(ForwardOpTree, "polly-optree",
+                      "Polly - Forward operand tree", false, false)
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
+INITIALIZE_PASS_END(ForwardOpTree, "polly-optree",
+                    "Polly - Forward operand tree", false, false)
diff --git a/final/lib/Transform/MaximalStaticExpansion.cpp b/final/lib/Transform/MaximalStaticExpansion.cpp
new file mode 100644
index 0000000..2a14721
--- /dev/null
+++ b/final/lib/Transform/MaximalStaticExpansion.cpp
@@ -0,0 +1,536 @@
+//===- MaximalStaticExpansion.cpp -----------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass fully expand the memory accesses of a Scop to get rid of
+// dependencies.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/ScopInfo.h"
+#include "polly/ScopPass.h"
+#include "polly/Support/GICHelper.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/Pass.h"
+#include "isl/isl-noexceptions.h"
+#include "isl/union_map.h"
+#include <cassert>
+#include <limits>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-mse"
+
+namespace {
+
+class MaximalStaticExpander : public ScopPass {
+public:
+  static char ID;
+
+  explicit MaximalStaticExpander() : ScopPass(ID) {}
+
+  ~MaximalStaticExpander() override = default;
+
+  /// Expand the accesses of the SCoP.
+  ///
+  /// @param S The SCoP that must be expanded.
+  bool runOnScop(Scop &S) override;
+
+  /// Print the SCoP.
+  ///
+  /// @param OS The stream where to print.
+  /// @param S The SCop that must be printed.
+  void printScop(raw_ostream &OS, Scop &S) const override;
+
+  /// Register all analyses and transformations required.
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  /// OptimizationRemarkEmitter object for displaying diagnostic remarks.
+  OptimizationRemarkEmitter *ORE;
+
+  /// Emit remark
+  void emitRemark(StringRef Msg, Instruction *Inst);
+
+  /// Return true if the SAI in parameter is expandable.
+  ///
+  /// @param SAI the SAI that need to be checked.
+  /// @param Writes A set that will contains all the write accesses.
+  /// @param Reads A set that will contains all the read accesses.
+  /// @param S The SCop in which the SAI is in.
+  /// @param Dependences The RAW dependences of the SCop.
+  bool isExpandable(const ScopArrayInfo *SAI,
+                    SmallPtrSetImpl<MemoryAccess *> &Writes,
+                    SmallPtrSetImpl<MemoryAccess *> &Reads, Scop &S,
+                    const isl::union_map &Dependences);
+
+  /// Expand the MemoryAccess according to its domain.
+  ///
+  /// @param S The SCop in which the memory access appears in.
+  /// @param MA The memory access that need to be expanded.
+  ScopArrayInfo *expandAccess(Scop &S, MemoryAccess *MA);
+
+  /// Filter the dependences to have only one related to current memory access.
+  ///
+  /// @param S The SCop in which the memory access appears in.
+  /// @param MapDependences The dependences to filter.
+  /// @param MA The memory access that need to be expanded.
+  isl::union_map filterDependences(Scop &S,
+                                   const isl::union_map &MapDependences,
+                                   MemoryAccess *MA);
+
+  /// Expand the MemoryAccess according to Dependences and already expanded
+  /// MemoryAccesses.
+  ///
+  /// @param The SCop in which the memory access appears in.
+  /// @param The memory access that need to be expanded.
+  /// @param Dependences The RAW dependences of the SCop.
+  /// @param ExpandedSAI The expanded SAI created during write expansion.
+  /// @param Reverse if true, the Dependences union_map is reversed before
+  /// intersection.
+  void mapAccess(Scop &S, SmallPtrSetImpl<MemoryAccess *> &Accesses,
+                 const isl::union_map &Dependences, ScopArrayInfo *ExpandedSAI,
+                 bool Reverse);
+
+  /// Expand PHI memory accesses.
+  ///
+  /// @param The SCop in which the memory access appears in.
+  /// @param The ScopArrayInfo representing the PHI accesses to expand.
+  /// @param Dependences The RAW dependences of the SCop.
+  void expandPhi(Scop &S, const ScopArrayInfo *SAI,
+                 const isl::union_map &Dependences);
+};
+
+} // namespace
+
+#ifndef NDEBUG
+/// Whether a dimension of a set is bounded (lower and upper) by a constant,
+/// i.e. there are two constants Min and Max, such that every value x of the
+/// chosen dimensions is Min <= x <= Max.
+static bool isDimBoundedByConstant(isl::set Set, unsigned dim) {
+  auto ParamDims = Set.dim(isl::dim::param);
+  Set = Set.project_out(isl::dim::param, 0, ParamDims);
+  Set = Set.project_out(isl::dim::set, 0, dim);
+  auto SetDims = Set.dim(isl::dim::set);
+  Set = Set.project_out(isl::dim::set, 1, SetDims - 1);
+  return bool(Set.is_bounded());
+}
+#endif
+
+/// If @p PwAff maps to a constant, return said constant. If @p Max/@p Min, it
+/// can also be a piecewise constant and it would return the minimum/maximum
+/// value. Otherwise, return NaN.
+static isl::val getConstant(isl::pw_aff PwAff, bool Max, bool Min) {
+  assert(!Max || !Min);
+  isl::val Result;
+  PwAff.foreach_piece([=, &Result](isl::set Set, isl::aff Aff) -> isl::stat {
+    if (Result && Result.is_nan())
+      return isl::stat::ok;
+
+    // TODO: If Min/Max, we can also determine a minimum/maximum value if
+    // Set is constant-bounded.
+    if (!Aff.is_cst()) {
+      Result = isl::val::nan(Aff.get_ctx());
+      return isl::stat::error;
+    }
+
+    auto ThisVal = Aff.get_constant_val();
+    if (!Result) {
+      Result = ThisVal;
+      return isl::stat::ok;
+    }
+
+    if (Result.eq(ThisVal))
+      return isl::stat::ok;
+
+    if (Max && ThisVal.gt(Result)) {
+      Result = ThisVal;
+      return isl::stat::ok;
+    }
+
+    if (Min && ThisVal.lt(Result)) {
+      Result = ThisVal;
+      return isl::stat::ok;
+    }
+
+    // Not compatible
+    Result = isl::val::nan(Aff.get_ctx());
+    return isl::stat::error;
+  });
+  return Result;
+}
+
+char MaximalStaticExpander::ID = 0;
+
+isl::union_map MaximalStaticExpander::filterDependences(
+    Scop &S, const isl::union_map &Dependences, MemoryAccess *MA) {
+  auto SAI = MA->getLatestScopArrayInfo();
+
+  auto AccessDomainSet = MA->getAccessRelation().domain();
+  auto AccessDomainId = AccessDomainSet.get_tuple_id();
+
+  isl::union_map MapDependences = isl::union_map::empty(S.getParamSpace());
+
+  Dependences.foreach_map([&MapDependences, &AccessDomainId,
+                           &SAI](isl::map Map) -> isl::stat {
+    // Filter out Statement to Statement dependences.
+    if (!Map.can_curry())
+      return isl::stat::ok;
+
+    // Intersect with the relevant SAI.
+    auto TmpMapDomainId =
+        Map.get_space().domain().unwrap().range().get_tuple_id(isl::dim::set);
+
+    ScopArrayInfo *UserSAI =
+        static_cast<ScopArrayInfo *>(TmpMapDomainId.get_user());
+
+    if (SAI != UserSAI)
+      return isl::stat::ok;
+
+    // Get the correct S1[] -> S2[] dependence.
+    auto NewMap = Map.factor_domain();
+    auto NewMapDomainId = NewMap.domain().get_tuple_id();
+
+    if (AccessDomainId.keep() != NewMapDomainId.keep())
+      return isl::stat::ok;
+
+    // Add the corresponding map to MapDependences.
+    MapDependences = MapDependences.add_map(NewMap);
+
+    return isl::stat::ok;
+  });
+
+  return MapDependences;
+}
+
+bool MaximalStaticExpander::isExpandable(
+    const ScopArrayInfo *SAI, SmallPtrSetImpl<MemoryAccess *> &Writes,
+    SmallPtrSetImpl<MemoryAccess *> &Reads, Scop &S,
+    const isl::union_map &Dependences) {
+  if (SAI->isValueKind()) {
+    Writes.insert(S.getValueDef(SAI));
+    for (auto MA : S.getValueUses(SAI))
+      Reads.insert(MA);
+    return true;
+  } else if (SAI->isPHIKind()) {
+    auto Read = S.getPHIRead(SAI);
+
+    auto StmtDomain = isl::union_set(Read->getStatement()->getDomain());
+
+    auto Writes = S.getPHIIncomings(SAI);
+
+    // Get the domain where all the writes are writing to.
+    auto WriteDomain = isl::union_set::empty(S.getParamSpace());
+
+    for (auto Write : Writes) {
+      auto MapDeps = filterDependences(S, Dependences, Write);
+      MapDeps.foreach_map([&WriteDomain](isl::map Map) -> isl::stat {
+        WriteDomain = WriteDomain.add_set(Map.range());
+        return isl::stat::ok;
+      });
+    }
+
+    // For now, read from original scalar is not possible.
+    if (!StmtDomain.is_equal(WriteDomain)) {
+      emitRemark(SAI->getName() + " read from its original value.",
+                 Read->getAccessInstruction());
+      return false;
+    }
+
+    return true;
+  } else if (SAI->isExitPHIKind()) {
+    // For now, we are not able to expand ExitPhi.
+    emitRemark(SAI->getName() + " is a ExitPhi node.",
+               S.getEnteringBlock()->getFirstNonPHI());
+    return false;
+  }
+
+  int NumberWrites = 0;
+  for (ScopStmt &Stmt : S) {
+    auto StmtReads = isl::union_map::empty(S.getParamSpace());
+    auto StmtWrites = isl::union_map::empty(S.getParamSpace());
+
+    for (MemoryAccess *MA : Stmt) {
+      // Check if the current MemoryAccess involved the current SAI.
+      if (SAI != MA->getLatestScopArrayInfo())
+        continue;
+
+      // For now, we are not able to expand array where read come after write
+      // (to the same location) in a same statement.
+      auto AccRel = isl::union_map(MA->getAccessRelation());
+      if (MA->isRead()) {
+        // Reject load after store to same location.
+        if (!StmtWrites.is_disjoint(AccRel)) {
+          emitRemark(SAI->getName() + " has read after write to the same "
+                                      "element in same statement. The "
+                                      "dependences found during analysis may "
+                                      "be wrong because Polly is not able to "
+                                      "handle such case for now.",
+                     MA->getAccessInstruction());
+          return false;
+        }
+
+        StmtReads = give(isl_union_map_union(StmtReads.take(), AccRel.take()));
+      } else {
+        StmtWrites =
+            give(isl_union_map_union(StmtWrites.take(), AccRel.take()));
+      }
+
+      // For now, we are not able to expand MayWrite.
+      if (MA->isMayWrite()) {
+        emitRemark(SAI->getName() + " has a maywrite access.",
+                   MA->getAccessInstruction());
+        return false;
+      }
+
+      // For now, we are not able to expand SAI with more than one write.
+      if (MA->isMustWrite()) {
+        Writes.insert(MA);
+        NumberWrites++;
+        if (NumberWrites > 1) {
+          emitRemark(SAI->getName() + " has more than 1 write access.",
+                     MA->getAccessInstruction());
+          return false;
+        }
+      }
+
+      // Check if it is possible to expand this read.
+      if (MA->isRead()) {
+        // Get the domain of the current ScopStmt.
+        auto StmtDomain = Stmt.getDomain();
+
+        // Get the domain of the future Read access.
+        auto ReadDomainSet = MA->getAccessRelation().domain();
+        auto ReadDomain = isl::union_set(ReadDomainSet);
+
+        // Get the dependences relevant for this MA
+        auto MapDependences = filterDependences(S, Dependences.reverse(), MA);
+        unsigned NumberElementMap = isl_union_map_n_map(MapDependences.get());
+
+        if (NumberElementMap == 0) {
+          emitRemark("The expansion of " + SAI->getName() +
+                         " would lead to a read from the original array.",
+                     MA->getAccessInstruction());
+          return false;
+        }
+
+        auto DepsDomain = MapDependences.domain();
+
+        // If there are multiple maps in the Deps, we cannot handle this case
+        // for now.
+        if (NumberElementMap != 1) {
+          emitRemark(SAI->getName() +
+                         " has too many dependences to be handle for now.",
+                     MA->getAccessInstruction());
+          return false;
+        }
+
+        auto DepsDomainSet = isl::set(DepsDomain);
+
+        // For now, read from the original array is not possible.
+        if (!StmtDomain.is_subset(DepsDomainSet)) {
+          emitRemark("The expansion of " + SAI->getName() +
+                         " would lead to a read from the original array.",
+                     MA->getAccessInstruction());
+          return false;
+        }
+
+        Reads.insert(MA);
+      }
+    }
+  }
+
+  // No need to expand SAI with no write.
+  if (NumberWrites == 0) {
+    emitRemark(SAI->getName() + " has 0 write access.",
+               S.getEnteringBlock()->getFirstNonPHI());
+    return false;
+  }
+
+  return true;
+}
+
+void MaximalStaticExpander::mapAccess(Scop &S,
+                                      SmallPtrSetImpl<MemoryAccess *> &Accesses,
+                                      const isl::union_map &Dependences,
+                                      ScopArrayInfo *ExpandedSAI,
+                                      bool Reverse) {
+  for (auto MA : Accesses) {
+    // Get the current AM.
+    auto CurrentAccessMap = MA->getAccessRelation();
+
+    // Get RAW dependences for the current WA.
+    auto DomainSet = MA->getAccessRelation().domain();
+    auto Domain = isl::union_set(DomainSet);
+
+    // Get the dependences relevant for this MA.
+    isl::union_map MapDependences =
+        filterDependences(S, Reverse ? Dependences.reverse() : Dependences, MA);
+
+    // If no dependences, no need to modify anything.
+    if (MapDependences.is_empty())
+      return;
+
+    assert(isl_union_map_n_map(MapDependences.get()) == 1 &&
+           "There are more than one RAW dependencies in the union map.");
+    auto NewAccessMap = isl::map::from_union_map(MapDependences);
+
+    auto Id = ExpandedSAI->getBasePtrId();
+
+    // Replace the out tuple id with the one of the access array.
+    NewAccessMap = NewAccessMap.set_tuple_id(isl::dim::out, Id);
+
+    // Set the new access relation.
+    MA->setNewAccessRelation(NewAccessMap);
+  }
+}
+
+ScopArrayInfo *MaximalStaticExpander::expandAccess(Scop &S, MemoryAccess *MA) {
+  // Get the current AM.
+  auto CurrentAccessMap = MA->getAccessRelation();
+
+  unsigned in_dimensions = CurrentAccessMap.dim(isl::dim::in);
+
+  // Get domain from the current AM.
+  auto Domain = CurrentAccessMap.domain();
+
+  // Create a new AM from the domain.
+  auto NewAccessMap = isl::map::from_domain(Domain);
+
+  // Add dimensions to the new AM according to the current in_dim.
+  NewAccessMap = NewAccessMap.add_dims(isl::dim::out, in_dimensions);
+
+  // Create the string representing the name of the new SAI.
+  // One new SAI for each statement so that each write go to a different memory
+  // cell.
+  auto CurrentStmtDomain = MA->getStatement()->getDomain();
+  auto CurrentStmtName = CurrentStmtDomain.get_tuple_name();
+  auto CurrentOutId = CurrentAccessMap.get_tuple_id(isl::dim::out);
+  std::string CurrentOutIdString =
+      MA->getScopArrayInfo()->getName() + "_" + CurrentStmtName + "_expanded";
+
+  // Set the tuple id for the out dimension.
+  NewAccessMap = NewAccessMap.set_tuple_id(isl::dim::out, CurrentOutId);
+
+  // Create the size vector.
+  std::vector<unsigned> Sizes;
+  for (unsigned i = 0; i < in_dimensions; i++) {
+    assert(isDimBoundedByConstant(CurrentStmtDomain, i) &&
+           "Domain boundary are not constant.");
+    auto UpperBound = getConstant(CurrentStmtDomain.dim_max(i), true, false);
+    assert(!UpperBound.is_null() && UpperBound.is_pos() &&
+           !UpperBound.is_nan() &&
+           "The upper bound is not a positive integer.");
+    assert(UpperBound.le(isl::val(CurrentAccessMap.get_ctx(),
+                                  std::numeric_limits<int>::max() - 1)) &&
+           "The upper bound overflow a int.");
+    Sizes.push_back(UpperBound.get_num_si() + 1);
+  }
+
+  // Get the ElementType of the current SAI.
+  auto ElementType = MA->getLatestScopArrayInfo()->getElementType();
+
+  // Create (or get if already existing) the new expanded SAI.
+  auto ExpandedSAI =
+      S.createScopArrayInfo(ElementType, CurrentOutIdString, Sizes);
+  ExpandedSAI->setIsOnHeap(true);
+
+  // Get the out Id of the expanded Array.
+  auto NewOutId = ExpandedSAI->getBasePtrId();
+
+  // Set the out id of the new AM to the new SAI id.
+  NewAccessMap = NewAccessMap.set_tuple_id(isl::dim::out, NewOutId);
+
+  // Add constraints to linked output with input id.
+  auto SpaceMap = NewAccessMap.get_space();
+  auto ConstraintBasicMap =
+      isl::basic_map::equal(SpaceMap, SpaceMap.dim(isl::dim::in));
+  NewAccessMap = isl::map(ConstraintBasicMap);
+
+  // Set the new access relation map.
+  MA->setNewAccessRelation(NewAccessMap);
+
+  return ExpandedSAI;
+}
+
+void MaximalStaticExpander::expandPhi(Scop &S, const ScopArrayInfo *SAI,
+                                      const isl::union_map &Dependences) {
+  SmallPtrSet<MemoryAccess *, 4> Writes;
+  for (auto MA : S.getPHIIncomings(SAI))
+    Writes.insert(MA);
+  auto Read = S.getPHIRead(SAI);
+  auto ExpandedSAI = expandAccess(S, Read);
+
+  mapAccess(S, Writes, Dependences, ExpandedSAI, false);
+}
+
+void MaximalStaticExpander::emitRemark(StringRef Msg, Instruction *Inst) {
+  ORE->emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "ExpansionRejection", Inst)
+            << Msg);
+}
+
+bool MaximalStaticExpander::runOnScop(Scop &S) {
+  // Get the ORE from OptimizationRemarkEmitterWrapperPass.
+  ORE = &(getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE());
+
+  // Get the RAW Dependences.
+  auto &DI = getAnalysis<DependenceInfo>();
+  auto &D = DI.getDependences(Dependences::AL_Reference);
+  auto Dependences = isl::give(D.getDependences(Dependences::TYPE_RAW));
+
+  SmallVector<ScopArrayInfo *, 4> CurrentSAI(S.arrays().begin(),
+                                             S.arrays().end());
+
+  for (auto SAI : CurrentSAI) {
+    SmallPtrSet<MemoryAccess *, 4> AllWrites;
+    SmallPtrSet<MemoryAccess *, 4> AllReads;
+    if (!isExpandable(SAI, AllWrites, AllReads, S, Dependences))
+      continue;
+
+    if (SAI->isValueKind() || SAI->isArrayKind()) {
+      assert(AllWrites.size() == 1 || SAI->isValueKind());
+
+      auto TheWrite = *(AllWrites.begin());
+      ScopArrayInfo *ExpandedArray = expandAccess(S, TheWrite);
+
+      mapAccess(S, AllReads, Dependences, ExpandedArray, true);
+    } else if (SAI->isPHIKind()) {
+      expandPhi(S, SAI, Dependences);
+    }
+  }
+
+  return false;
+}
+
+void MaximalStaticExpander::printScop(raw_ostream &OS, Scop &S) const {
+  S.print(OS, false);
+}
+
+void MaximalStaticExpander::getAnalysisUsage(AnalysisUsage &AU) const {
+  ScopPass::getAnalysisUsage(AU);
+  AU.addRequired<DependenceInfo>();
+  AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
+}
+
+Pass *polly::createMaximalStaticExpansionPass() {
+  return new MaximalStaticExpander();
+}
+
+INITIALIZE_PASS_BEGIN(MaximalStaticExpander, "polly-mse",
+                      "Polly - Maximal static expansion of SCoP", false, false);
+INITIALIZE_PASS_DEPENDENCY(DependenceInfo);
+INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass);
+INITIALIZE_PASS_END(MaximalStaticExpander, "polly-mse",
+                    "Polly - Maximal static expansion of SCoP", false, false)
diff --git a/final/lib/Transform/RewriteByReferenceParameters.cpp b/final/lib/Transform/RewriteByReferenceParameters.cpp
new file mode 100644
index 0000000..1b9f852
--- /dev/null
+++ b/final/lib/Transform/RewriteByReferenceParameters.cpp
@@ -0,0 +1,99 @@
+//===------ RewriteByReferenceParameters.cpp --------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass introduces separate 'alloca' instructions for read-only
+// by-reference function parameters to indicate that these paramters are
+// read-only. After this transformation -mem2reg has more freedom to promote
+// variables to registers, which allows SCEV to work in more cases.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/LinkAllPasses.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/PassManager.h"
+
+#define DEBUG_TYPE "polly-rewrite-byref-params"
+
+using namespace llvm;
+
+namespace {
+
+class RewriteByrefParams : public FunctionPass {
+private:
+  RewriteByrefParams(const RewriteByrefParams &) = delete;
+  const RewriteByrefParams &operator=(const RewriteByrefParams &) = delete;
+
+public:
+  static char ID;
+  explicit RewriteByrefParams() : FunctionPass(ID) {}
+
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const override {}
+
+  void tryRewriteInstruction(Instruction &Inst) {
+    BasicBlock *Entry = &Inst.getParent()->getParent()->getEntryBlock();
+
+    auto *Call = dyn_cast<CallInst>(&Inst);
+
+    if (!Call)
+      return;
+
+    llvm::Function *F = Call->getCalledFunction();
+
+    if (!F)
+      return;
+
+    // We currently match for a very specific function. In case this proves
+    // useful, we can make this code dependent on readonly metadata.
+    if (!F->hasName() || F->getName() != "_gfortran_transfer_integer_write")
+      return;
+
+    auto *BitCast = dyn_cast<BitCastInst>(Call->getOperand(1));
+
+    if (!BitCast)
+      return;
+
+    auto *Alloca = dyn_cast<AllocaInst>(BitCast->getOperand(0));
+
+    if (!Alloca)
+      return;
+
+    std::string InstName = Alloca->getName();
+
+    auto NewAlloca =
+        new AllocaInst(Alloca->getType()->getElementType(), 0,
+                       "polly_byref_alloca_" + InstName, &*Entry->begin());
+
+    auto *LoadedVal =
+        new LoadInst(Alloca, "polly_byref_load_" + InstName, &Inst);
+
+    new StoreInst(LoadedVal, NewAlloca, &Inst);
+    auto *NewBitCast = new BitCastInst(NewAlloca, BitCast->getType(),
+                                       "polly_byref_cast_" + InstName, &Inst);
+    Call->setOperand(1, NewBitCast);
+  }
+
+  virtual bool runOnFunction(Function &F) override {
+    for (BasicBlock &BB : F)
+      for (Instruction &Inst : BB)
+        tryRewriteInstruction(Inst);
+
+    return true;
+  }
+};
+
+char RewriteByrefParams::ID;
+} // anonymous namespace
+
+Pass *polly::createRewriteByrefParamsPass() { return new RewriteByrefParams(); }
+
+INITIALIZE_PASS_BEGIN(RewriteByrefParams, "polly-rewrite-byref-params",
+                      "Polly - Rewrite by reference parameters", false, false)
+INITIALIZE_PASS_END(RewriteByrefParams, "polly-rewrite-byref-params",
+                    "Polly - Rewrite by reference parameters", false, false)
diff --git a/final/lib/Transform/ScheduleOptimizer.cpp b/final/lib/Transform/ScheduleOptimizer.cpp
new file mode 100644
index 0000000..3f9c495
--- /dev/null
+++ b/final/lib/Transform/ScheduleOptimizer.cpp
@@ -0,0 +1,1683 @@
+//===- Schedule.cpp - Calculate an optimized schedule ---------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass generates an entirely new schedule tree from the data dependences
+// and iteration domains. The new schedule tree is computed in two steps:
+//
+// 1) The isl scheduling optimizer is run
+//
+// The isl scheduling optimizer creates a new schedule tree that maximizes
+// parallelism and tileability and minimizes data-dependence distances. The
+// algorithm used is a modified version of the ``Pluto'' algorithm:
+//
+//   U. Bondhugula, A. Hartono, J. Ramanujam, and P. Sadayappan.
+//   A Practical Automatic Polyhedral Parallelizer and Locality Optimizer.
+//   In Proceedings of the 2008 ACM SIGPLAN Conference On Programming Language
+//   Design and Implementation, PLDI ’08, pages 101–113. ACM, 2008.
+//
+// 2) A set of post-scheduling transformations is applied on the schedule tree.
+//
+// These optimizations include:
+//
+//  - Tiling of the innermost tilable bands
+//  - Prevectorization - The choice of a possible outer loop that is strip-mined
+//                       to the innermost level to enable inner-loop
+//                       vectorization.
+//  - Some optimizations for spatial locality are also planned.
+//
+// For a detailed description of the schedule tree itself please see section 6
+// of:
+//
+// Polyhedral AST generation is more than scanning polyhedra
+// Tobias Grosser, Sven Verdoolaege, Albert Cohen
+// ACM Transactions on Programming Languages and Systems (TOPLAS),
+// 37(4), July 2015
+// http://www.grosser.es/#pub-polyhedral-AST-generation
+//
+// This publication also contains a detailed discussion of the different options
+// for polyhedral loop unrolling, full/partial tile separation and other uses
+// of the schedule tree.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/ScheduleOptimizer.h"
+#include "polly/CodeGen/CodeGeneration.h"
+#include "polly/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "polly/ScopPass.h"
+#include "polly/Simplify.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/ISLOStream.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "isl/constraint.h"
+#include "isl/ctx.h"
+#include "isl/map.h"
+#include "isl/options.h"
+#include "isl/printer.h"
+#include "isl/schedule.h"
+#include "isl/schedule_node.h"
+#include "isl/space.h"
+#include "isl/union_map.h"
+#include "isl/union_set.h"
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstdint>
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-opt-isl"
+
+static cl::opt<std::string>
+    OptimizeDeps("polly-opt-optimize-only",
+                 cl::desc("Only a certain kind of dependences (all/raw)"),
+                 cl::Hidden, cl::init("all"), cl::ZeroOrMore,
+                 cl::cat(PollyCategory));
+
+static cl::opt<std::string>
+    SimplifyDeps("polly-opt-simplify-deps",
+                 cl::desc("Dependences should be simplified (yes/no)"),
+                 cl::Hidden, cl::init("yes"), cl::ZeroOrMore,
+                 cl::cat(PollyCategory));
+
+static cl::opt<int> MaxConstantTerm(
+    "polly-opt-max-constant-term",
+    cl::desc("The maximal constant term allowed (-1 is unlimited)"), cl::Hidden,
+    cl::init(20), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> MaxCoefficient(
+    "polly-opt-max-coefficient",
+    cl::desc("The maximal coefficient allowed (-1 is unlimited)"), cl::Hidden,
+    cl::init(20), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<std::string> FusionStrategy(
+    "polly-opt-fusion", cl::desc("The fusion strategy to choose (min/max)"),
+    cl::Hidden, cl::init("min"), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<std::string>
+    MaximizeBandDepth("polly-opt-maximize-bands",
+                      cl::desc("Maximize the band depth (yes/no)"), cl::Hidden,
+                      cl::init("yes"), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<std::string> OuterCoincidence(
+    "polly-opt-outer-coincidence",
+    cl::desc("Try to construct schedules where the outer member of each band "
+             "satisfies the coincidence constraints (yes/no)"),
+    cl::Hidden, cl::init("no"), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> PrevectorWidth(
+    "polly-prevect-width",
+    cl::desc(
+        "The number of loop iterations to strip-mine for pre-vectorization"),
+    cl::Hidden, cl::init(4), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> FirstLevelTiling("polly-tiling",
+                                      cl::desc("Enable loop tiling"),
+                                      cl::init(true), cl::ZeroOrMore,
+                                      cl::cat(PollyCategory));
+
+static cl::opt<int> LatencyVectorFma(
+    "polly-target-latency-vector-fma",
+    cl::desc("The minimal number of cycles between issuing two "
+             "dependent consecutive vector fused multiply-add "
+             "instructions."),
+    cl::Hidden, cl::init(8), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> ThroughputVectorFma(
+    "polly-target-throughput-vector-fma",
+    cl::desc("A throughput of the processor floating-point arithmetic units "
+             "expressed in the number of vector fused multiply-add "
+             "instructions per clock cycle."),
+    cl::Hidden, cl::init(1), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+// This option, along with --polly-target-2nd-cache-level-associativity,
+// --polly-target-1st-cache-level-size, and --polly-target-2st-cache-level-size
+// represent the parameters of the target cache, which do not have typical
+// values that can be used by default. However, to apply the pattern matching
+// optimizations, we use the values of the parameters of Intel Core i7-3820
+// SandyBridge in case the parameters are not specified or not provided by the
+// TargetTransformInfo.
+static cl::opt<int> FirstCacheLevelAssociativity(
+    "polly-target-1st-cache-level-associativity",
+    cl::desc("The associativity of the first cache level."), cl::Hidden,
+    cl::init(-1), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> FirstCacheLevelDefaultAssociativity(
+    "polly-target-1st-cache-level-default-associativity",
+    cl::desc("The default associativity of the first cache level"
+             " (if not enough were provided by the TargetTransformInfo)."),
+    cl::Hidden, cl::init(8), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> SecondCacheLevelAssociativity(
+    "polly-target-2nd-cache-level-associativity",
+    cl::desc("The associativity of the second cache level."), cl::Hidden,
+    cl::init(-1), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> SecondCacheLevelDefaultAssociativity(
+    "polly-target-2nd-cache-level-default-associativity",
+    cl::desc("The default associativity of the second cache level"
+             " (if not enough were provided by the TargetTransformInfo)."),
+    cl::Hidden, cl::init(8), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> FirstCacheLevelSize(
+    "polly-target-1st-cache-level-size",
+    cl::desc("The size of the first cache level specified in bytes."),
+    cl::Hidden, cl::init(-1), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> FirstCacheLevelDefaultSize(
+    "polly-target-1st-cache-level-default-size",
+    cl::desc("The default size of the first cache level specified in bytes"
+             " (if not enough were provided by the TargetTransformInfo)."),
+    cl::Hidden, cl::init(32768), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> SecondCacheLevelSize(
+    "polly-target-2nd-cache-level-size",
+    cl::desc("The size of the second level specified in bytes."), cl::Hidden,
+    cl::init(-1), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> SecondCacheLevelDefaultSize(
+    "polly-target-2nd-cache-level-default-size",
+    cl::desc("The default size of the second cache level specified in bytes"
+             " (if not enough were provided by the TargetTransformInfo)."),
+    cl::Hidden, cl::init(262144), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> VectorRegisterBitwidth(
+    "polly-target-vector-register-bitwidth",
+    cl::desc("The size in bits of a vector register (if not set, this "
+             "information is taken from LLVM's target information."),
+    cl::Hidden, cl::init(-1), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> FirstLevelDefaultTileSize(
+    "polly-default-tile-size",
+    cl::desc("The default tile size (if not enough were provided by"
+             " --polly-tile-sizes)"),
+    cl::Hidden, cl::init(32), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::list<int>
+    FirstLevelTileSizes("polly-tile-sizes",
+                        cl::desc("A tile size for each loop dimension, filled "
+                                 "with --polly-default-tile-size"),
+                        cl::Hidden, cl::ZeroOrMore, cl::CommaSeparated,
+                        cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    SecondLevelTiling("polly-2nd-level-tiling",
+                      cl::desc("Enable a 2nd level loop of loop tiling"),
+                      cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> SecondLevelDefaultTileSize(
+    "polly-2nd-level-default-tile-size",
+    cl::desc("The default 2nd-level tile size (if not enough were provided by"
+             " --polly-2nd-level-tile-sizes)"),
+    cl::Hidden, cl::init(16), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::list<int>
+    SecondLevelTileSizes("polly-2nd-level-tile-sizes",
+                         cl::desc("A tile size for each loop dimension, filled "
+                                  "with --polly-default-tile-size"),
+                         cl::Hidden, cl::ZeroOrMore, cl::CommaSeparated,
+                         cl::cat(PollyCategory));
+
+static cl::opt<bool> RegisterTiling("polly-register-tiling",
+                                    cl::desc("Enable register tiling"),
+                                    cl::init(false), cl::ZeroOrMore,
+                                    cl::cat(PollyCategory));
+
+static cl::opt<int> RegisterDefaultTileSize(
+    "polly-register-tiling-default-tile-size",
+    cl::desc("The default register tile size (if not enough were provided by"
+             " --polly-register-tile-sizes)"),
+    cl::Hidden, cl::init(2), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<int> PollyPatternMatchingNcQuotient(
+    "polly-pattern-matching-nc-quotient",
+    cl::desc("Quotient that is obtained by dividing Nc, the parameter of the"
+             "macro-kernel, by Nr, the parameter of the micro-kernel"),
+    cl::Hidden, cl::init(256), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::list<int>
+    RegisterTileSizes("polly-register-tile-sizes",
+                      cl::desc("A tile size for each loop dimension, filled "
+                               "with --polly-register-tile-size"),
+                      cl::Hidden, cl::ZeroOrMore, cl::CommaSeparated,
+                      cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    PMBasedOpts("polly-pattern-matching-based-opts",
+                cl::desc("Perform optimizations based on pattern matching"),
+                cl::init(true), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> OptimizedScops(
+    "polly-optimized-scops",
+    cl::desc("Polly - Dump polyhedral description of Scops optimized with "
+             "the isl scheduling optimizer and the set of post-scheduling "
+             "transformations is applied on the schedule tree"),
+    cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+STATISTIC(ScopsProcessed, "Number of scops processed");
+STATISTIC(ScopsRescheduled, "Number of scops rescheduled");
+STATISTIC(ScopsOptimized, "Number of scops optimized");
+
+STATISTIC(NumAffineLoopsOptimized, "Number of affine loops optimized");
+STATISTIC(NumBoxedLoopsOptimized, "Number of boxed loops optimized");
+
+#define THREE_STATISTICS(VARNAME, DESC)                                        \
+  static Statistic VARNAME[3] = {                                              \
+      {DEBUG_TYPE, #VARNAME "0", DESC " (original)", {0}, false},              \
+      {DEBUG_TYPE, #VARNAME "1", DESC " (after scheduler)", {0}, false},       \
+      {DEBUG_TYPE, #VARNAME "2", DESC " (after optimizer)", {0}, false}}
+
+THREE_STATISTICS(NumBands, "Number of bands");
+THREE_STATISTICS(NumBandMembers, "Number of band members");
+THREE_STATISTICS(NumCoincident, "Number of coincident band members");
+THREE_STATISTICS(NumPermutable, "Number of permutable bands");
+THREE_STATISTICS(NumFilters, "Number of filter nodes");
+THREE_STATISTICS(NumExtension, "Number of extension nodes");
+
+STATISTIC(FirstLevelTileOpts, "Number of first level tiling applied");
+STATISTIC(SecondLevelTileOpts, "Number of second level tiling applied");
+STATISTIC(RegisterTileOpts, "Number of register tiling applied");
+STATISTIC(PrevectOpts, "Number of strip-mining for prevectorization applied");
+STATISTIC(MatMulOpts,
+          "Number of matrix multiplication patterns detected and optimized");
+
+/// Create an isl::union_set, which describes the isolate option based on
+/// IsolateDomain.
+///
+/// @param IsolateDomain An isl::set whose @p OutDimsNum last dimensions should
+///                      belong to the current band node.
+/// @param OutDimsNum    A number of dimensions that should belong to
+///                      the current band node.
+static isl::union_set getIsolateOptions(isl::set IsolateDomain,
+                                        unsigned OutDimsNum) {
+  unsigned Dims = IsolateDomain.dim(isl::dim::set);
+  assert(OutDimsNum <= Dims &&
+         "The isl::set IsolateDomain is used to describe the range of schedule "
+         "dimensions values, which should be isolated. Consequently, the "
+         "number of its dimensions should be greater than or equal to the "
+         "number of the schedule dimensions.");
+  isl::map IsolateRelation = isl::map::from_domain(IsolateDomain);
+  IsolateRelation = IsolateRelation.move_dims(isl::dim::out, 0, isl::dim::in,
+                                              Dims - OutDimsNum, OutDimsNum);
+  isl::set IsolateOption = IsolateRelation.wrap();
+  isl::id Id = isl::id::alloc(IsolateOption.get_ctx(), "isolate", nullptr);
+  IsolateOption = IsolateOption.set_tuple_id(Id);
+  return isl::union_set(IsolateOption);
+}
+
+namespace {
+/// Create an isl::union_set, which describes the specified option for the
+/// dimension of the current node.
+///
+/// @param Ctx    An isl::ctx, which is used to create the isl::union_set.
+/// @param Option The name of the option.
+isl::union_set getDimOptions(isl::ctx Ctx, const char *Option) {
+  isl::space Space(Ctx, 0, 1);
+  auto DimOption = isl::set::universe(Space);
+  auto Id = isl::id::alloc(Ctx, Option, nullptr);
+  DimOption = DimOption.set_tuple_id(Id);
+  return isl::union_set(DimOption);
+}
+} // namespace
+
+/// Create an isl::union_set, which describes the option of the form
+/// [isolate[] -> unroll[x]].
+///
+/// @param Ctx An isl::ctx, which is used to create the isl::union_set.
+static isl::union_set getUnrollIsolatedSetOptions(isl::ctx Ctx) {
+  isl::space Space = isl::space(Ctx, 0, 0, 1);
+  isl::map UnrollIsolatedSetOption = isl::map::universe(Space);
+  isl::id DimInId = isl::id::alloc(Ctx, "isolate", nullptr);
+  isl::id DimOutId = isl::id::alloc(Ctx, "unroll", nullptr);
+  UnrollIsolatedSetOption =
+      UnrollIsolatedSetOption.set_tuple_id(isl::dim::in, DimInId);
+  UnrollIsolatedSetOption =
+      UnrollIsolatedSetOption.set_tuple_id(isl::dim::out, DimOutId);
+  return UnrollIsolatedSetOption.wrap();
+}
+
+/// Make the last dimension of Set to take values from 0 to VectorWidth - 1.
+///
+/// @param Set         A set, which should be modified.
+/// @param VectorWidth A parameter, which determines the constraint.
+static isl::set addExtentConstraints(isl::set Set, int VectorWidth) {
+  unsigned Dims = Set.dim(isl::dim::set);
+  isl::space Space = Set.get_space();
+  isl::local_space LocalSpace = isl::local_space(Space);
+  isl::constraint ExtConstr = isl::constraint::alloc_inequality(LocalSpace);
+  ExtConstr = ExtConstr.set_constant_si(0);
+  ExtConstr = ExtConstr.set_coefficient_si(isl::dim::set, Dims - 1, 1);
+  Set = Set.add_constraint(ExtConstr);
+  ExtConstr = isl::constraint::alloc_inequality(LocalSpace);
+  ExtConstr = ExtConstr.set_constant_si(VectorWidth - 1);
+  ExtConstr = ExtConstr.set_coefficient_si(isl::dim::set, Dims - 1, -1);
+  return Set.add_constraint(ExtConstr);
+}
+
+isl::set getPartialTilePrefixes(isl::set ScheduleRange, int VectorWidth) {
+  unsigned Dims = ScheduleRange.dim(isl::dim::set);
+  isl::set LoopPrefixes =
+      ScheduleRange.drop_constraints_involving_dims(isl::dim::set, Dims - 1, 1);
+  auto ExtentPrefixes = addExtentConstraints(LoopPrefixes, VectorWidth);
+  isl::set BadPrefixes = ExtentPrefixes.subtract(ScheduleRange);
+  BadPrefixes = BadPrefixes.project_out(isl::dim::set, Dims - 1, 1);
+  LoopPrefixes = LoopPrefixes.project_out(isl::dim::set, Dims - 1, 1);
+  return LoopPrefixes.subtract(BadPrefixes);
+}
+
+isl::schedule_node
+ScheduleTreeOptimizer::isolateFullPartialTiles(isl::schedule_node Node,
+                                               int VectorWidth) {
+  assert(isl_schedule_node_get_type(Node.get()) == isl_schedule_node_band);
+  Node = Node.child(0).child(0);
+  isl::union_map SchedRelUMap = Node.get_prefix_schedule_relation();
+  isl::map ScheduleRelation = isl::map::from_union_map(SchedRelUMap);
+  isl::set ScheduleRange = ScheduleRelation.range();
+  isl::set IsolateDomain = getPartialTilePrefixes(ScheduleRange, VectorWidth);
+  auto AtomicOption = getDimOptions(IsolateDomain.get_ctx(), "atomic");
+  isl::union_set IsolateOption = getIsolateOptions(IsolateDomain, 1);
+  Node = Node.parent().parent();
+  isl::union_set Options = IsolateOption.unite(AtomicOption);
+  Node = Node.band_set_ast_build_options(Options);
+  return Node;
+}
+
+isl::schedule_node ScheduleTreeOptimizer::prevectSchedBand(
+    isl::schedule_node Node, unsigned DimToVectorize, int VectorWidth) {
+  assert(isl_schedule_node_get_type(Node.get()) == isl_schedule_node_band);
+
+  auto Space = isl::manage(isl_schedule_node_band_get_space(Node.get()));
+  auto ScheduleDimensions = Space.dim(isl::dim::set);
+  assert(DimToVectorize < ScheduleDimensions);
+
+  if (DimToVectorize > 0) {
+    Node = isl::manage(
+        isl_schedule_node_band_split(Node.release(), DimToVectorize));
+    Node = Node.child(0);
+  }
+  if (DimToVectorize < ScheduleDimensions - 1)
+    Node = isl::manage(isl_schedule_node_band_split(Node.release(), 1));
+  Space = isl::manage(isl_schedule_node_band_get_space(Node.get()));
+  auto Sizes = isl::multi_val::zero(Space);
+  Sizes = Sizes.set_val(0, isl::val(Node.get_ctx(), VectorWidth));
+  Node =
+      isl::manage(isl_schedule_node_band_tile(Node.release(), Sizes.release()));
+  Node = isolateFullPartialTiles(Node, VectorWidth);
+  Node = Node.child(0);
+  // Make sure the "trivially vectorizable loop" is not unrolled. Otherwise,
+  // we will have troubles to match it in the backend.
+  Node = Node.band_set_ast_build_options(
+      isl::union_set(Node.get_ctx(), "{ unroll[x]: 1 = 0 }"));
+  Node = isl::manage(isl_schedule_node_band_sink(Node.release()));
+  Node = Node.child(0);
+  if (isl_schedule_node_get_type(Node.get()) == isl_schedule_node_leaf)
+    Node = Node.parent();
+  auto LoopMarker = isl::id::alloc(Node.get_ctx(), "SIMD", nullptr);
+  PrevectOpts++;
+  return Node.insert_mark(LoopMarker);
+}
+
+isl::schedule_node ScheduleTreeOptimizer::tileNode(isl::schedule_node Node,
+                                                   const char *Identifier,
+                                                   ArrayRef<int> TileSizes,
+                                                   int DefaultTileSize) {
+  auto Space = isl::manage(isl_schedule_node_band_get_space(Node.get()));
+  auto Dims = Space.dim(isl::dim::set);
+  auto Sizes = isl::multi_val::zero(Space);
+  std::string IdentifierString(Identifier);
+  for (unsigned i = 0; i < Dims; i++) {
+    auto tileSize = i < TileSizes.size() ? TileSizes[i] : DefaultTileSize;
+    Sizes = Sizes.set_val(i, isl::val(Node.get_ctx(), tileSize));
+  }
+  auto TileLoopMarkerStr = IdentifierString + " - Tiles";
+  auto TileLoopMarker =
+      isl::id::alloc(Node.get_ctx(), TileLoopMarkerStr, nullptr);
+  Node = Node.insert_mark(TileLoopMarker);
+  Node = Node.child(0);
+  Node =
+      isl::manage(isl_schedule_node_band_tile(Node.release(), Sizes.release()));
+  Node = Node.child(0);
+  auto PointLoopMarkerStr = IdentifierString + " - Points";
+  auto PointLoopMarker =
+      isl::id::alloc(Node.get_ctx(), PointLoopMarkerStr, nullptr);
+  Node = Node.insert_mark(PointLoopMarker);
+  return Node.child(0);
+}
+
+isl::schedule_node ScheduleTreeOptimizer::applyRegisterTiling(
+    isl::schedule_node Node, ArrayRef<int> TileSizes, int DefaultTileSize) {
+  Node = tileNode(Node, "Register tiling", TileSizes, DefaultTileSize);
+  auto Ctx = Node.get_ctx();
+  return Node.band_set_ast_build_options(isl::union_set(Ctx, "{unroll[x]}"));
+}
+
+static bool isSimpleInnermostBand(const isl::schedule_node &Node) {
+  assert(isl_schedule_node_get_type(Node.keep()) == isl_schedule_node_band);
+  assert(isl_schedule_node_n_children(Node.keep()) == 1);
+
+  auto ChildType = isl_schedule_node_get_type(Node.child(0).keep());
+
+  if (ChildType == isl_schedule_node_leaf)
+    return true;
+
+  if (ChildType != isl_schedule_node_sequence)
+    return false;
+
+  auto Sequence = Node.child(0);
+
+  for (int c = 0, nc = isl_schedule_node_n_children(Sequence.keep()); c < nc;
+       ++c) {
+    auto Child = Sequence.child(c);
+    if (isl_schedule_node_get_type(Child.keep()) != isl_schedule_node_filter)
+      return false;
+    if (isl_schedule_node_get_type(Child.child(0).keep()) !=
+        isl_schedule_node_leaf)
+      return false;
+  }
+  return true;
+}
+
+bool ScheduleTreeOptimizer::isTileableBandNode(isl::schedule_node Node) {
+  if (isl_schedule_node_get_type(Node.get()) != isl_schedule_node_band)
+    return false;
+
+  if (isl_schedule_node_n_children(Node.get()) != 1)
+    return false;
+
+  if (!isl_schedule_node_band_get_permutable(Node.get()))
+    return false;
+
+  auto Space = isl::manage(isl_schedule_node_band_get_space(Node.get()));
+  auto Dims = Space.dim(isl::dim::set);
+
+  if (Dims <= 1)
+    return false;
+
+  return isSimpleInnermostBand(Node);
+}
+
+__isl_give isl::schedule_node
+ScheduleTreeOptimizer::standardBandOpts(isl::schedule_node Node, void *User) {
+  if (FirstLevelTiling) {
+    Node = tileNode(Node, "1st level tiling", FirstLevelTileSizes,
+                    FirstLevelDefaultTileSize);
+    FirstLevelTileOpts++;
+  }
+
+  if (SecondLevelTiling) {
+    Node = tileNode(Node, "2nd level tiling", SecondLevelTileSizes,
+                    SecondLevelDefaultTileSize);
+    SecondLevelTileOpts++;
+  }
+
+  if (RegisterTiling) {
+    Node =
+        applyRegisterTiling(Node, RegisterTileSizes, RegisterDefaultTileSize);
+    RegisterTileOpts++;
+  }
+
+  if (PollyVectorizerChoice == VECTORIZER_NONE)
+    return Node;
+
+  auto Space = isl::manage(isl_schedule_node_band_get_space(Node.get()));
+  auto Dims = Space.dim(isl::dim::set);
+
+  for (int i = Dims - 1; i >= 0; i--)
+    if (Node.band_member_get_coincident(i)) {
+      Node = prevectSchedBand(Node, i, PrevectorWidth);
+      break;
+    }
+
+  return Node;
+}
+
+/// Permute the two dimensions of the isl map.
+///
+/// Permute @p DstPos and @p SrcPos dimensions of the isl map @p Map that
+/// have type @p DimType.
+///
+/// @param Map     The isl map to be modified.
+/// @param DimType The type of the dimensions.
+/// @param DstPos  The first dimension.
+/// @param SrcPos  The second dimension.
+/// @return        The modified map.
+isl::map permuteDimensions(isl::map Map, isl::dim DimType, unsigned DstPos,
+                           unsigned SrcPos) {
+  assert(DstPos < Map.dim(DimType) && SrcPos < Map.dim(DimType));
+  if (DstPos == SrcPos)
+    return Map;
+  isl::id DimId;
+  if (Map.has_tuple_id(DimType))
+    DimId = Map.get_tuple_id(DimType);
+  auto FreeDim = DimType == isl::dim::in ? isl::dim::out : isl::dim::in;
+  isl::id FreeDimId;
+  if (Map.has_tuple_id(FreeDim))
+    FreeDimId = Map.get_tuple_id(FreeDim);
+  auto MaxDim = std::max(DstPos, SrcPos);
+  auto MinDim = std::min(DstPos, SrcPos);
+  Map = Map.move_dims(FreeDim, 0, DimType, MaxDim, 1);
+  Map = Map.move_dims(FreeDim, 0, DimType, MinDim, 1);
+  Map = Map.move_dims(DimType, MinDim, FreeDim, 1, 1);
+  Map = Map.move_dims(DimType, MaxDim, FreeDim, 0, 1);
+  if (DimId)
+    Map = Map.set_tuple_id(DimType, DimId);
+  if (FreeDimId)
+    Map = Map.set_tuple_id(FreeDim, FreeDimId);
+  return Map;
+}
+
+/// Check the form of the access relation.
+///
+/// Check that the access relation @p AccMap has the form M[i][j], where i
+/// is a @p FirstPos and j is a @p SecondPos.
+///
+/// @param AccMap    The access relation to be checked.
+/// @param FirstPos  The index of the input dimension that is mapped to
+///                  the first output dimension.
+/// @param SecondPos The index of the input dimension that is mapped to the
+///                  second output dimension.
+/// @return          True in case @p AccMap has the expected form and false,
+///                  otherwise.
+static bool isMatMulOperandAcc(isl::set Domain, isl::map AccMap, int &FirstPos,
+                               int &SecondPos) {
+  isl::space Space = AccMap.get_space();
+  isl::map Universe = isl::map::universe(Space);
+
+  if (Space.dim(isl::dim::out) != 2)
+    return false;
+
+  // MatMul has the form:
+  // for (i = 0; i < N; i++)
+  //   for (j = 0; j < M; j++)
+  //     for (k = 0; k < P; k++)
+  //       C[i, j] += A[i, k] * B[k, j]
+  //
+  // Permutation of three outer loops: 3! = 6 possibilities.
+  int FirstDims[] = {0, 0, 1, 1, 2, 2};
+  int SecondDims[] = {1, 2, 2, 0, 0, 1};
+  for (int i = 0; i < 6; i += 1) {
+    auto PossibleMatMul =
+        Universe.equate(isl::dim::in, FirstDims[i], isl::dim::out, 0)
+            .equate(isl::dim::in, SecondDims[i], isl::dim::out, 1);
+
+    AccMap = AccMap.intersect_domain(Domain);
+    PossibleMatMul = PossibleMatMul.intersect_domain(Domain);
+
+    // If AccMap spans entire domain (Non-partial write),
+    // compute FirstPos and SecondPos.
+    // If AccMap != PossibleMatMul here (the two maps have been gisted at
+    // this point), it means that the writes are not complete, or in other
+    // words, it is a Partial write and Partial writes must be rejected.
+    if (AccMap.is_equal(PossibleMatMul)) {
+      if (FirstPos != -1 && FirstPos != FirstDims[i])
+        continue;
+      FirstPos = FirstDims[i];
+      if (SecondPos != -1 && SecondPos != SecondDims[i])
+        continue;
+      SecondPos = SecondDims[i];
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/// Does the memory access represent a non-scalar operand of the matrix
+/// multiplication.
+///
+/// Check that the memory access @p MemAccess is the read access to a non-scalar
+/// operand of the matrix multiplication or its result.
+///
+/// @param MemAccess The memory access to be checked.
+/// @param MMI       Parameters of the matrix multiplication operands.
+/// @return          True in case the memory access represents the read access
+///                  to a non-scalar operand of the matrix multiplication and
+///                  false, otherwise.
+static bool isMatMulNonScalarReadAccess(MemoryAccess *MemAccess,
+                                        MatMulInfoTy &MMI) {
+  if (!MemAccess->isLatestArrayKind() || !MemAccess->isRead())
+    return false;
+  auto AccMap = MemAccess->getLatestAccessRelation();
+  isl::set StmtDomain = MemAccess->getStatement()->getDomain();
+  if (isMatMulOperandAcc(StmtDomain, AccMap, MMI.i, MMI.j) && !MMI.ReadFromC) {
+    MMI.ReadFromC = MemAccess;
+    return true;
+  }
+  if (isMatMulOperandAcc(StmtDomain, AccMap, MMI.i, MMI.k) && !MMI.A) {
+    MMI.A = MemAccess;
+    return true;
+  }
+  if (isMatMulOperandAcc(StmtDomain, AccMap, MMI.k, MMI.j) && !MMI.B) {
+    MMI.B = MemAccess;
+    return true;
+  }
+  return false;
+}
+
+/// Check accesses to operands of the matrix multiplication.
+///
+/// Check that accesses of the SCoP statement, which corresponds to
+/// the partial schedule @p PartialSchedule, are scalar in terms of loops
+/// containing the matrix multiplication, in case they do not represent
+/// accesses to the non-scalar operands of the matrix multiplication or
+/// its result.
+///
+/// @param  PartialSchedule The partial schedule of the SCoP statement.
+/// @param  MMI             Parameters of the matrix multiplication operands.
+/// @return                 True in case the corresponding SCoP statement
+///                         represents matrix multiplication and false,
+///                         otherwise.
+static bool containsOnlyMatrMultAcc(isl::map PartialSchedule,
+                                    MatMulInfoTy &MMI) {
+  auto InputDimId = PartialSchedule.get_tuple_id(isl::dim::in);
+  auto *Stmt = static_cast<ScopStmt *>(InputDimId.get_user());
+  unsigned OutDimNum = PartialSchedule.dim(isl::dim::out);
+  assert(OutDimNum > 2 && "In case of the matrix multiplication the loop nest "
+                          "and, consequently, the corresponding scheduling "
+                          "functions have at least three dimensions.");
+  auto MapI =
+      permuteDimensions(PartialSchedule, isl::dim::out, MMI.i, OutDimNum - 1);
+  auto MapJ =
+      permuteDimensions(PartialSchedule, isl::dim::out, MMI.j, OutDimNum - 1);
+  auto MapK =
+      permuteDimensions(PartialSchedule, isl::dim::out, MMI.k, OutDimNum - 1);
+
+  auto Accesses = getAccessesInOrder(*Stmt);
+  for (auto *MemA = Accesses.begin(); MemA != Accesses.end() - 1; MemA++) {
+    auto *MemAccessPtr = *MemA;
+    if (MemAccessPtr->isLatestArrayKind() && MemAccessPtr != MMI.WriteToC &&
+        !isMatMulNonScalarReadAccess(MemAccessPtr, MMI) &&
+        !(MemAccessPtr->isStrideZero(MapI)) &&
+        MemAccessPtr->isStrideZero(MapJ) && MemAccessPtr->isStrideZero(MapK))
+      return false;
+  }
+  return true;
+}
+
+/// Check for dependencies corresponding to the matrix multiplication.
+///
+/// Check that there is only true dependence of the form
+/// S(..., k, ...) -> S(..., k + 1, …), where S is the SCoP statement
+/// represented by @p Schedule and k is @p Pos. Such a dependence corresponds
+/// to the dependency produced by the matrix multiplication.
+///
+/// @param  Schedule The schedule of the SCoP statement.
+/// @param  D The SCoP dependencies.
+/// @param  Pos The parameter to describe an acceptable true dependence.
+///             In case it has a negative value, try to determine its
+///             acceptable value.
+/// @return True in case dependencies correspond to the matrix multiplication
+///         and false, otherwise.
+static bool containsOnlyMatMulDep(isl::map Schedule, const Dependences *D,
+                                  int &Pos) {
+  auto Dep = isl::manage(D->getDependences(Dependences::TYPE_RAW));
+  auto Red = isl::manage(D->getDependences(Dependences::TYPE_RED));
+  if (Red)
+    Dep = Dep.unite(Red);
+  auto DomainSpace = Schedule.get_space().domain();
+  auto Space = DomainSpace.map_from_domain_and_range(DomainSpace);
+  auto Deltas = Dep.extract_map(Space).deltas();
+  int DeltasDimNum = Deltas.dim(isl::dim::set);
+  for (int i = 0; i < DeltasDimNum; i++) {
+    auto Val = Deltas.plain_get_val_if_fixed(isl::dim::set, i);
+    Pos = Pos < 0 && Val.is_one() ? i : Pos;
+    if (Val.is_nan() || !(Val.is_zero() || (i == Pos && Val.is_one())))
+      return false;
+  }
+  if (DeltasDimNum == 0 || Pos < 0)
+    return false;
+  return true;
+}
+
+/// Check if the SCoP statement could probably be optimized with analytical
+/// modeling.
+///
+/// containsMatrMult tries to determine whether the following conditions
+/// are true:
+/// 1. The last memory access modeling an array, MA1, represents writing to
+///    memory and has the form S(..., i1, ..., i2, ...) -> M(i1, i2) or
+///    S(..., i2, ..., i1, ...) -> M(i1, i2), where S is the SCoP statement
+///    under consideration.
+/// 2. There is only one loop-carried true dependency, and it has the
+///    form S(..., i3, ...) -> S(..., i3 + 1, ...), and there are no
+///    loop-carried or anti dependencies.
+/// 3. SCoP contains three access relations, MA2, MA3, and MA4 that represent
+///    reading from memory and have the form S(..., i3, ...) -> M(i1, i3),
+///    S(..., i3, ...) -> M(i3, i2), S(...) -> M(i1, i2), respectively,
+///    and all memory accesses of the SCoP that are different from MA1, MA2,
+///    MA3, and MA4 have stride 0, if the innermost loop is exchanged with any
+///    of loops i1, i2 and i3.
+///
+/// @param PartialSchedule The PartialSchedule that contains a SCoP statement
+///        to check.
+/// @D     The SCoP dependencies.
+/// @MMI   Parameters of the matrix multiplication operands.
+static bool containsMatrMult(isl::map PartialSchedule, const Dependences *D,
+                             MatMulInfoTy &MMI) {
+  auto InputDimsId = PartialSchedule.get_tuple_id(isl::dim::in);
+  auto *Stmt = static_cast<ScopStmt *>(InputDimsId.get_user());
+  if (Stmt->size() <= 1)
+    return false;
+
+  auto Accesses = getAccessesInOrder(*Stmt);
+  for (auto *MemA = Accesses.end() - 1; MemA != Accesses.begin(); MemA--) {
+    auto *MemAccessPtr = *MemA;
+    if (!MemAccessPtr->isLatestArrayKind())
+      continue;
+    if (!MemAccessPtr->isWrite())
+      return false;
+    auto AccMap = MemAccessPtr->getLatestAccessRelation();
+    if (!isMatMulOperandAcc(Stmt->getDomain(), AccMap, MMI.i, MMI.j))
+      return false;
+    MMI.WriteToC = MemAccessPtr;
+    break;
+  }
+
+  if (!containsOnlyMatMulDep(PartialSchedule, D, MMI.k))
+    return false;
+
+  if (!MMI.WriteToC || !containsOnlyMatrMultAcc(PartialSchedule, MMI))
+    return false;
+
+  if (!MMI.A || !MMI.B || !MMI.ReadFromC)
+    return false;
+  return true;
+}
+
+/// Permute two dimensions of the band node.
+///
+/// Permute FirstDim and SecondDim dimensions of the Node.
+///
+/// @param Node The band node to be modified.
+/// @param FirstDim The first dimension to be permuted.
+/// @param SecondDim The second dimension to be permuted.
+static isl::schedule_node permuteBandNodeDimensions(isl::schedule_node Node,
+                                                    unsigned FirstDim,
+                                                    unsigned SecondDim) {
+  assert(isl_schedule_node_get_type(Node.get()) == isl_schedule_node_band &&
+         isl_schedule_node_band_n_member(Node.get()) >
+             std::max(FirstDim, SecondDim));
+  auto PartialSchedule =
+      isl::manage(isl_schedule_node_band_get_partial_schedule(Node.get()));
+  auto PartialScheduleFirstDim = PartialSchedule.get_union_pw_aff(FirstDim);
+  auto PartialScheduleSecondDim = PartialSchedule.get_union_pw_aff(SecondDim);
+  PartialSchedule =
+      PartialSchedule.set_union_pw_aff(SecondDim, PartialScheduleFirstDim);
+  PartialSchedule =
+      PartialSchedule.set_union_pw_aff(FirstDim, PartialScheduleSecondDim);
+  Node = isl::manage(isl_schedule_node_delete(Node.release()));
+  return Node.insert_partial_schedule(PartialSchedule);
+}
+
+isl::schedule_node ScheduleTreeOptimizer::createMicroKernel(
+    isl::schedule_node Node, MicroKernelParamsTy MicroKernelParams) {
+  Node = applyRegisterTiling(Node, {MicroKernelParams.Mr, MicroKernelParams.Nr},
+                             1);
+  Node = Node.parent().parent();
+  return permuteBandNodeDimensions(Node, 0, 1).child(0).child(0);
+}
+
+isl::schedule_node ScheduleTreeOptimizer::createMacroKernel(
+    isl::schedule_node Node, MacroKernelParamsTy MacroKernelParams) {
+  assert(isl_schedule_node_get_type(Node.get()) == isl_schedule_node_band);
+  if (MacroKernelParams.Mc == 1 && MacroKernelParams.Nc == 1 &&
+      MacroKernelParams.Kc == 1)
+    return Node;
+  int DimOutNum = isl_schedule_node_band_n_member(Node.get());
+  std::vector<int> TileSizes(DimOutNum, 1);
+  TileSizes[DimOutNum - 3] = MacroKernelParams.Mc;
+  TileSizes[DimOutNum - 2] = MacroKernelParams.Nc;
+  TileSizes[DimOutNum - 1] = MacroKernelParams.Kc;
+  Node = tileNode(Node, "1st level tiling", TileSizes, 1);
+  Node = Node.parent().parent();
+  Node = permuteBandNodeDimensions(Node, DimOutNum - 2, DimOutNum - 1);
+  Node = permuteBandNodeDimensions(Node, DimOutNum - 3, DimOutNum - 1);
+  return Node.child(0).child(0);
+}
+
+/// Get the size of the widest type of the matrix multiplication operands
+/// in bytes, including alignment padding.
+///
+/// @param MMI Parameters of the matrix multiplication operands.
+/// @return The size of the widest type of the matrix multiplication operands
+///         in bytes, including alignment padding.
+static uint64_t getMatMulAlignTypeSize(MatMulInfoTy MMI) {
+  auto *S = MMI.A->getStatement()->getParent();
+  auto &DL = S->getFunction().getParent()->getDataLayout();
+  auto ElementSizeA = DL.getTypeAllocSize(MMI.A->getElementType());
+  auto ElementSizeB = DL.getTypeAllocSize(MMI.B->getElementType());
+  auto ElementSizeC = DL.getTypeAllocSize(MMI.WriteToC->getElementType());
+  return std::max({ElementSizeA, ElementSizeB, ElementSizeC});
+}
+
+/// Get the size of the widest type of the matrix multiplication operands
+/// in bits.
+///
+/// @param MMI Parameters of the matrix multiplication operands.
+/// @return The size of the widest type of the matrix multiplication operands
+///         in bits.
+static uint64_t getMatMulTypeSize(MatMulInfoTy MMI) {
+  auto *S = MMI.A->getStatement()->getParent();
+  auto &DL = S->getFunction().getParent()->getDataLayout();
+  auto ElementSizeA = DL.getTypeSizeInBits(MMI.A->getElementType());
+  auto ElementSizeB = DL.getTypeSizeInBits(MMI.B->getElementType());
+  auto ElementSizeC = DL.getTypeSizeInBits(MMI.WriteToC->getElementType());
+  return std::max({ElementSizeA, ElementSizeB, ElementSizeC});
+}
+
+/// Get parameters of the BLIS micro kernel.
+///
+/// We choose the Mr and Nr parameters of the micro kernel to be large enough
+/// such that no stalls caused by the combination of latencies and dependencies
+/// are introduced during the updates of the resulting matrix of the matrix
+/// multiplication. However, they should also be as small as possible to
+/// release more registers for entries of multiplied matrices.
+///
+/// @param TTI Target Transform Info.
+/// @param MMI Parameters of the matrix multiplication operands.
+/// @return The structure of type MicroKernelParamsTy.
+/// @see MicroKernelParamsTy
+static struct MicroKernelParamsTy
+getMicroKernelParams(const TargetTransformInfo *TTI, MatMulInfoTy MMI) {
+  assert(TTI && "The target transform info should be provided.");
+
+  // Nvec - Number of double-precision floating-point numbers that can be hold
+  // by a vector register. Use 2 by default.
+  long RegisterBitwidth = VectorRegisterBitwidth;
+
+  if (RegisterBitwidth == -1)
+    RegisterBitwidth = TTI->getRegisterBitWidth(true);
+  auto ElementSize = getMatMulTypeSize(MMI);
+  assert(ElementSize > 0 && "The element size of the matrix multiplication "
+                            "operands should be greater than zero.");
+  auto Nvec = RegisterBitwidth / ElementSize;
+  if (Nvec == 0)
+    Nvec = 2;
+  int Nr =
+      ceil(sqrt(Nvec * LatencyVectorFma * ThroughputVectorFma) / Nvec) * Nvec;
+  int Mr = ceil(Nvec * LatencyVectorFma * ThroughputVectorFma / Nr);
+  return {Mr, Nr};
+}
+
+namespace {
+/// Determine parameters of the target cache.
+///
+/// @param TTI Target Transform Info.
+void getTargetCacheParameters(const llvm::TargetTransformInfo *TTI) {
+  auto L1DCache = llvm::TargetTransformInfo::CacheLevel::L1D;
+  auto L2DCache = llvm::TargetTransformInfo::CacheLevel::L2D;
+  if (FirstCacheLevelSize == -1) {
+    if (TTI->getCacheSize(L1DCache).hasValue())
+      FirstCacheLevelSize = TTI->getCacheSize(L1DCache).getValue();
+    else
+      FirstCacheLevelSize = static_cast<int>(FirstCacheLevelDefaultSize);
+  }
+  if (SecondCacheLevelSize == -1) {
+    if (TTI->getCacheSize(L2DCache).hasValue())
+      SecondCacheLevelSize = TTI->getCacheSize(L2DCache).getValue();
+    else
+      SecondCacheLevelSize = static_cast<int>(SecondCacheLevelDefaultSize);
+  }
+  if (FirstCacheLevelAssociativity == -1) {
+    if (TTI->getCacheAssociativity(L1DCache).hasValue())
+      FirstCacheLevelAssociativity =
+          TTI->getCacheAssociativity(L1DCache).getValue();
+    else
+      FirstCacheLevelAssociativity =
+          static_cast<int>(FirstCacheLevelDefaultAssociativity);
+  }
+  if (SecondCacheLevelAssociativity == -1) {
+    if (TTI->getCacheAssociativity(L2DCache).hasValue())
+      SecondCacheLevelAssociativity =
+          TTI->getCacheAssociativity(L2DCache).getValue();
+    else
+      SecondCacheLevelAssociativity =
+          static_cast<int>(SecondCacheLevelDefaultAssociativity);
+  }
+}
+} // namespace
+
+/// Get parameters of the BLIS macro kernel.
+///
+/// During the computation of matrix multiplication, blocks of partitioned
+/// matrices are mapped to different layers of the memory hierarchy.
+/// To optimize data reuse, blocks should be ideally kept in cache between
+/// iterations. Since parameters of the macro kernel determine sizes of these
+/// blocks, there are upper and lower bounds on these parameters.
+///
+/// @param TTI Target Transform Info.
+/// @param MicroKernelParams Parameters of the micro-kernel
+///                          to be taken into account.
+/// @param MMI Parameters of the matrix multiplication operands.
+/// @return The structure of type MacroKernelParamsTy.
+/// @see MacroKernelParamsTy
+/// @see MicroKernelParamsTy
+static struct MacroKernelParamsTy
+getMacroKernelParams(const llvm::TargetTransformInfo *TTI,
+                     const MicroKernelParamsTy &MicroKernelParams,
+                     MatMulInfoTy MMI) {
+  getTargetCacheParameters(TTI);
+  // According to www.cs.utexas.edu/users/flame/pubs/TOMS-BLIS-Analytical.pdf,
+  // it requires information about the first two levels of a cache to determine
+  // all the parameters of a macro-kernel. It also checks that an associativity
+  // degree of a cache level is greater than two. Otherwise, another algorithm
+  // for determination of the parameters should be used.
+  if (!(MicroKernelParams.Mr > 0 && MicroKernelParams.Nr > 0 &&
+        FirstCacheLevelSize > 0 && SecondCacheLevelSize > 0 &&
+        FirstCacheLevelAssociativity > 2 && SecondCacheLevelAssociativity > 2))
+    return {1, 1, 1};
+  // The quotient should be greater than zero.
+  if (PollyPatternMatchingNcQuotient <= 0)
+    return {1, 1, 1};
+  int Car = floor(
+      (FirstCacheLevelAssociativity - 1) /
+      (1 + static_cast<double>(MicroKernelParams.Nr) / MicroKernelParams.Mr));
+
+  // Car can be computed to be zero since it is floor to int.
+  // On Mac OS, division by 0 does not raise a signal. This causes negative
+  // tile sizes to be computed. Prevent division by Cac==0 by early returning
+  // if this happens.
+  if (Car == 0)
+    return {1, 1, 1};
+
+  auto ElementSize = getMatMulAlignTypeSize(MMI);
+  assert(ElementSize > 0 && "The element size of the matrix multiplication "
+                            "operands should be greater than zero.");
+  int Kc = (Car * FirstCacheLevelSize) /
+           (MicroKernelParams.Mr * FirstCacheLevelAssociativity * ElementSize);
+  double Cac =
+      static_cast<double>(Kc * ElementSize * SecondCacheLevelAssociativity) /
+      SecondCacheLevelSize;
+  int Mc = floor((SecondCacheLevelAssociativity - 2) / Cac);
+  int Nc = PollyPatternMatchingNcQuotient * MicroKernelParams.Nr;
+
+  assert(Mc > 0 && Nc > 0 && Kc > 0 &&
+         "Matrix block sizes should be  greater than zero");
+  return {Mc, Nc, Kc};
+}
+
+/// Create an access relation that is specific to
+///        the matrix multiplication pattern.
+///
+/// Create an access relation of the following form:
+/// [O0, O1, O2, O3, O4, O5, O6, O7, O8] -> [OI, O5, OJ]
+/// where I is @p FirstDim, J is @p SecondDim.
+///
+/// It can be used, for example, to create relations that helps to consequently
+/// access elements of operands of a matrix multiplication after creation of
+/// the BLIS micro and macro kernels.
+///
+/// @see ScheduleTreeOptimizer::createMicroKernel
+/// @see ScheduleTreeOptimizer::createMacroKernel
+///
+/// Subsequently, the described access relation is applied to the range of
+/// @p MapOldIndVar, that is used to map original induction variables to
+/// the ones, which are produced by schedule transformations. It helps to
+/// define relations using a new space and, at the same time, keep them
+/// in the original one.
+///
+/// @param MapOldIndVar The relation, which maps original induction variables
+///                     to the ones, which are produced by schedule
+///                     transformations.
+/// @param FirstDim, SecondDim The input dimensions that are used to define
+///        the specified access relation.
+/// @return The specified access relation.
+isl::map getMatMulAccRel(isl::map MapOldIndVar, unsigned FirstDim,
+                         unsigned SecondDim) {
+  auto AccessRelSpace = isl::space(MapOldIndVar.get_ctx(), 0, 9, 3);
+  auto AccessRel = isl::map::universe(AccessRelSpace);
+  AccessRel = AccessRel.equate(isl::dim::in, FirstDim, isl::dim::out, 0);
+  AccessRel = AccessRel.equate(isl::dim::in, 5, isl::dim::out, 1);
+  AccessRel = AccessRel.equate(isl::dim::in, SecondDim, isl::dim::out, 2);
+  return MapOldIndVar.apply_range(AccessRel);
+}
+
+isl::schedule_node createExtensionNode(isl::schedule_node Node,
+                                       isl::map ExtensionMap) {
+  auto Extension = isl::union_map(ExtensionMap);
+  auto NewNode = isl::schedule_node::from_extension(Extension);
+  return Node.graft_before(NewNode);
+}
+
+/// Apply the packing transformation.
+///
+/// The packing transformation can be described as a data-layout
+/// transformation that requires to introduce a new array, copy data
+/// to the array, and change memory access locations to reference the array.
+/// It can be used to ensure that elements of the new array are read in-stride
+/// access, aligned to cache lines boundaries, and preloaded into certain cache
+/// levels.
+///
+/// As an example let us consider the packing of the array A that would help
+/// to read its elements with in-stride access. An access to the array A
+/// is represented by an access relation that has the form
+/// S[i, j, k] -> A[i, k]. The scheduling function of the SCoP statement S has
+/// the form S[i,j, k] -> [floor((j mod Nc) / Nr), floor((i mod Mc) / Mr),
+/// k mod Kc, j mod Nr, i mod Mr].
+///
+/// To ensure that elements of the array A are read in-stride access, we add
+/// a new array Packed_A[Mc/Mr][Kc][Mr] to the SCoP, using
+/// Scop::createScopArrayInfo, change the access relation
+/// S[i, j, k] -> A[i, k] to
+/// S[i, j, k] -> Packed_A[floor((i mod Mc) / Mr), k mod Kc, i mod Mr], using
+/// MemoryAccess::setNewAccessRelation, and copy the data to the array, using
+/// the copy statement created by Scop::addScopStmt.
+///
+/// @param Node The schedule node to be optimized.
+/// @param MapOldIndVar The relation, which maps original induction variables
+///                     to the ones, which are produced by schedule
+///                     transformations.
+/// @param MicroParams, MacroParams Parameters of the BLIS kernel
+///                                 to be taken into account.
+/// @param MMI Parameters of the matrix multiplication operands.
+/// @return The optimized schedule node.
+static isl::schedule_node
+optimizeDataLayoutMatrMulPattern(isl::schedule_node Node, isl::map MapOldIndVar,
+                                 MicroKernelParamsTy MicroParams,
+                                 MacroKernelParamsTy MacroParams,
+                                 MatMulInfoTy &MMI) {
+  auto InputDimsId = MapOldIndVar.get_tuple_id(isl::dim::in);
+  auto *Stmt = static_cast<ScopStmt *>(InputDimsId.get_user());
+
+  // Create a copy statement that corresponds to the memory access to the
+  // matrix B, the second operand of the matrix multiplication.
+  Node = Node.parent().parent().parent().parent().parent().parent();
+  Node = isl::manage(isl_schedule_node_band_split(Node.release(), 2)).child(0);
+  auto AccRel = getMatMulAccRel(isl::manage(MapOldIndVar.copy()), 3, 7);
+  unsigned FirstDimSize = MacroParams.Nc / MicroParams.Nr;
+  unsigned SecondDimSize = MacroParams.Kc;
+  unsigned ThirdDimSize = MicroParams.Nr;
+  auto *SAI = Stmt->getParent()->createScopArrayInfo(
+      MMI.B->getElementType(), "Packed_B",
+      {FirstDimSize, SecondDimSize, ThirdDimSize});
+  AccRel = AccRel.set_tuple_id(isl::dim::out, SAI->getBasePtrId());
+  auto OldAcc = MMI.B->getLatestAccessRelation();
+  MMI.B->setNewAccessRelation(AccRel);
+  auto ExtMap = MapOldIndVar.project_out(isl::dim::out, 2,
+                                         MapOldIndVar.dim(isl::dim::out) - 2);
+  ExtMap = ExtMap.reverse();
+  ExtMap = ExtMap.fix_si(isl::dim::out, MMI.i, 0);
+  auto Domain = Stmt->getDomain();
+
+  // Restrict the domains of the copy statements to only execute when also its
+  // originating statement is executed.
+  auto DomainId = Domain.get_tuple_id();
+  auto *NewStmt = Stmt->getParent()->addScopStmt(
+      OldAcc, MMI.B->getLatestAccessRelation(), Domain);
+  ExtMap = ExtMap.set_tuple_id(isl::dim::out, isl::manage(DomainId.copy()));
+  ExtMap = ExtMap.intersect_range(isl::manage(Domain.copy()));
+  ExtMap = ExtMap.set_tuple_id(isl::dim::out, NewStmt->getDomainId());
+  Node = createExtensionNode(Node, ExtMap);
+
+  // Create a copy statement that corresponds to the memory access
+  // to the matrix A, the first operand of the matrix multiplication.
+  Node = Node.child(0);
+  AccRel = getMatMulAccRel(isl::manage(MapOldIndVar.copy()), 4, 6);
+  FirstDimSize = MacroParams.Mc / MicroParams.Mr;
+  ThirdDimSize = MicroParams.Mr;
+  SAI = Stmt->getParent()->createScopArrayInfo(
+      MMI.A->getElementType(), "Packed_A",
+      {FirstDimSize, SecondDimSize, ThirdDimSize});
+  AccRel = AccRel.set_tuple_id(isl::dim::out, SAI->getBasePtrId());
+  OldAcc = MMI.A->getLatestAccessRelation();
+  MMI.A->setNewAccessRelation(AccRel);
+  ExtMap = MapOldIndVar.project_out(isl::dim::out, 3,
+                                    MapOldIndVar.dim(isl::dim::out) - 3);
+  ExtMap = ExtMap.reverse();
+  ExtMap = ExtMap.fix_si(isl::dim::out, MMI.j, 0);
+  NewStmt = Stmt->getParent()->addScopStmt(
+      OldAcc, MMI.A->getLatestAccessRelation(), Domain);
+
+  // Restrict the domains of the copy statements to only execute when also its
+  // originating statement is executed.
+  ExtMap = ExtMap.set_tuple_id(isl::dim::out, DomainId);
+  ExtMap = ExtMap.intersect_range(Domain);
+  ExtMap = ExtMap.set_tuple_id(isl::dim::out, NewStmt->getDomainId());
+  Node = createExtensionNode(Node, ExtMap);
+  return Node.child(0).child(0).child(0).child(0).child(0);
+}
+
+/// Get a relation mapping induction variables produced by schedule
+/// transformations to the original ones.
+///
+/// @param Node The schedule node produced as the result of creation
+///        of the BLIS kernels.
+/// @param MicroKernelParams, MacroKernelParams Parameters of the BLIS kernel
+///                                             to be taken into account.
+/// @return  The relation mapping original induction variables to the ones
+///          produced by schedule transformation.
+/// @see ScheduleTreeOptimizer::createMicroKernel
+/// @see ScheduleTreeOptimizer::createMacroKernel
+/// @see getMacroKernelParams
+isl::map
+getInductionVariablesSubstitution(isl::schedule_node Node,
+                                  MicroKernelParamsTy MicroKernelParams,
+                                  MacroKernelParamsTy MacroKernelParams) {
+  auto Child = Node.child(0);
+  auto UnMapOldIndVar = Child.get_prefix_schedule_union_map();
+  auto MapOldIndVar = isl::map::from_union_map(UnMapOldIndVar);
+  if (MapOldIndVar.dim(isl::dim::out) > 9)
+    return MapOldIndVar.project_out(isl::dim::out, 0,
+                                    MapOldIndVar.dim(isl::dim::out) - 9);
+  return MapOldIndVar;
+}
+
+/// Isolate a set of partial tile prefixes and unroll the isolated part.
+///
+/// The set should ensure that it contains only partial tile prefixes that have
+/// exactly Mr x Nr iterations of the two innermost loops produced by
+/// the optimization of the matrix multiplication. Mr and Nr are parameters of
+/// the micro-kernel.
+///
+/// In case of parametric bounds, this helps to auto-vectorize the unrolled
+/// innermost loops, using the SLP vectorizer.
+///
+/// @param Node              The schedule node to be modified.
+/// @param MicroKernelParams Parameters of the micro-kernel
+///                          to be taken into account.
+/// @return The modified isl_schedule_node.
+static isl::schedule_node
+isolateAndUnrollMatMulInnerLoops(isl::schedule_node Node,
+                                 struct MicroKernelParamsTy MicroKernelParams) {
+  isl::schedule_node Child = Node.get_child(0);
+  isl::union_map UnMapOldIndVar = Child.get_prefix_schedule_relation();
+  isl::set Prefix = isl::map::from_union_map(UnMapOldIndVar).range();
+  unsigned Dims = Prefix.dim(isl::dim::set);
+  Prefix = Prefix.project_out(isl::dim::set, Dims - 1, 1);
+  Prefix = getPartialTilePrefixes(Prefix, MicroKernelParams.Nr);
+  Prefix = getPartialTilePrefixes(Prefix, MicroKernelParams.Mr);
+
+  isl::union_set IsolateOption =
+      getIsolateOptions(Prefix.add_dims(isl::dim::set, 3), 3);
+  isl::ctx Ctx = Node.get_ctx();
+  auto Options = IsolateOption.unite(getDimOptions(Ctx, "unroll"));
+  Options = Options.unite(getUnrollIsolatedSetOptions(Ctx));
+  Node = Node.band_set_ast_build_options(Options);
+  Node = Node.parent().parent().parent();
+  IsolateOption = getIsolateOptions(Prefix, 3);
+  Options = IsolateOption.unite(getDimOptions(Ctx, "separate"));
+  Node = Node.band_set_ast_build_options(Options);
+  Node = Node.child(0).child(0).child(0);
+  return Node;
+}
+
+/// Mark @p BasePtr with "Inter iteration alias-free" mark node.
+///
+/// @param Node The child of the mark node to be inserted.
+/// @param BasePtr The pointer to be marked.
+/// @return The modified isl_schedule_node.
+static isl::schedule_node markInterIterationAliasFree(isl::schedule_node Node,
+                                                      Value *BasePtr) {
+  if (!BasePtr)
+    return Node;
+
+  auto Id =
+      isl::id::alloc(Node.get_ctx(), "Inter iteration alias-free", BasePtr);
+  return Node.insert_mark(Id).child(0);
+}
+
+/// Insert "Loop Vectorizer Disabled" mark node.
+///
+/// @param Node The child of the mark node to be inserted.
+/// @return The modified isl_schedule_node.
+static isl::schedule_node markLoopVectorizerDisabled(isl::schedule_node Node) {
+  auto Id = isl::id::alloc(Node.get_ctx(), "Loop Vectorizer Disabled", nullptr);
+  return Node.insert_mark(Id).child(0);
+}
+
+/// Restore the initial ordering of dimensions of the band node
+///
+/// In case the band node represents all the dimensions of the iteration
+/// domain, recreate the band node to restore the initial ordering of the
+/// dimensions.
+///
+/// @param Node The band node to be modified.
+/// @return The modified schedule node.
+static isl::schedule_node
+getBandNodeWithOriginDimOrder(isl::schedule_node Node) {
+  assert(isl_schedule_node_get_type(Node.keep()) == isl_schedule_node_band);
+  if (isl_schedule_node_get_type(Node.child(0).keep()) !=
+      isl_schedule_node_leaf)
+    return Node;
+  auto Domain = Node.get_universe_domain();
+  assert(isl_union_set_n_set(Domain.keep()) == 1);
+  if (Node.get_schedule_depth() != 0 ||
+      (isl::set(isl::manage(Domain.copy())).dim(isl::dim::set) !=
+       isl_schedule_node_band_n_member(Node.keep())))
+    return Node;
+  Node = isl::manage(isl_schedule_node_delete(Node.take()));
+  auto PartialSchedulePwAff = Domain.identity_union_pw_multi_aff();
+  auto PartialScheduleMultiPwAff =
+      isl::multi_union_pw_aff(PartialSchedulePwAff);
+  PartialScheduleMultiPwAff =
+      PartialScheduleMultiPwAff.reset_tuple_id(isl::dim::set);
+  return Node.insert_partial_schedule(PartialScheduleMultiPwAff);
+}
+
+isl::schedule_node
+ScheduleTreeOptimizer::optimizeMatMulPattern(isl::schedule_node Node,
+                                             const TargetTransformInfo *TTI,
+                                             MatMulInfoTy &MMI) {
+  assert(TTI && "The target transform info should be provided.");
+  Node = markInterIterationAliasFree(
+      Node, MMI.WriteToC->getLatestScopArrayInfo()->getBasePtr());
+  int DimOutNum = isl_schedule_node_band_n_member(Node.get());
+  assert(DimOutNum > 2 && "In case of the matrix multiplication the loop nest "
+                          "and, consequently, the corresponding scheduling "
+                          "functions have at least three dimensions.");
+  Node = getBandNodeWithOriginDimOrder(Node);
+  Node = permuteBandNodeDimensions(Node, MMI.i, DimOutNum - 3);
+  int NewJ = MMI.j == DimOutNum - 3 ? MMI.i : MMI.j;
+  int NewK = MMI.k == DimOutNum - 3 ? MMI.i : MMI.k;
+  Node = permuteBandNodeDimensions(Node, NewJ, DimOutNum - 2);
+  NewK = NewK == DimOutNum - 2 ? NewJ : NewK;
+  Node = permuteBandNodeDimensions(Node, NewK, DimOutNum - 1);
+  auto MicroKernelParams = getMicroKernelParams(TTI, MMI);
+  auto MacroKernelParams = getMacroKernelParams(TTI, MicroKernelParams, MMI);
+  Node = createMacroKernel(Node, MacroKernelParams);
+  Node = createMicroKernel(Node, MicroKernelParams);
+  if (MacroKernelParams.Mc == 1 || MacroKernelParams.Nc == 1 ||
+      MacroKernelParams.Kc == 1)
+    return Node;
+  auto MapOldIndVar = getInductionVariablesSubstitution(Node, MicroKernelParams,
+                                                        MacroKernelParams);
+  if (!MapOldIndVar)
+    return Node;
+  Node = markLoopVectorizerDisabled(Node.parent()).child(0);
+  Node = isolateAndUnrollMatMulInnerLoops(Node, MicroKernelParams);
+  return optimizeDataLayoutMatrMulPattern(Node, MapOldIndVar, MicroKernelParams,
+                                          MacroKernelParams, MMI);
+}
+
+bool ScheduleTreeOptimizer::isMatrMultPattern(isl::schedule_node Node,
+                                              const Dependences *D,
+                                              MatMulInfoTy &MMI) {
+  auto PartialSchedule = isl::manage(
+      isl_schedule_node_band_get_partial_schedule_union_map(Node.get()));
+  Node = Node.child(0);
+  auto LeafType = isl_schedule_node_get_type(Node.get());
+  Node = Node.parent();
+  if (LeafType != isl_schedule_node_leaf ||
+      isl_schedule_node_band_n_member(Node.get()) < 3 ||
+      Node.get_schedule_depth() != 0 ||
+      isl_union_map_n_map(PartialSchedule.get()) != 1)
+    return false;
+  auto NewPartialSchedule = isl::map::from_union_map(PartialSchedule);
+  if (containsMatrMult(NewPartialSchedule, D, MMI))
+    return true;
+  return false;
+}
+
+__isl_give isl_schedule_node *
+ScheduleTreeOptimizer::optimizeBand(__isl_take isl_schedule_node *Node,
+                                    void *User) {
+  if (!isTileableBandNode(isl::manage(isl_schedule_node_copy(Node))))
+    return Node;
+
+  const OptimizerAdditionalInfoTy *OAI =
+      static_cast<const OptimizerAdditionalInfoTy *>(User);
+
+  MatMulInfoTy MMI;
+  if (PMBasedOpts && User &&
+      isMatrMultPattern(isl::manage(isl_schedule_node_copy(Node)), OAI->D,
+                        MMI)) {
+    DEBUG(dbgs() << "The matrix multiplication pattern was detected\n");
+    MatMulOpts++;
+    return optimizeMatMulPattern(isl::manage(Node), OAI->TTI, MMI).release();
+  }
+
+  return standardBandOpts(isl::manage(Node), User).release();
+}
+
+isl::schedule
+ScheduleTreeOptimizer::optimizeSchedule(isl::schedule Schedule,
+                                        const OptimizerAdditionalInfoTy *OAI) {
+  auto Root = Schedule.get_root();
+  Root = optimizeScheduleNode(Root, OAI);
+  return Root.get_schedule();
+}
+
+isl::schedule_node ScheduleTreeOptimizer::optimizeScheduleNode(
+    isl::schedule_node Node, const OptimizerAdditionalInfoTy *OAI) {
+  Node = isl::manage(isl_schedule_node_map_descendant_bottom_up(
+      Node.release(), optimizeBand,
+      const_cast<void *>(static_cast<const void *>(OAI))));
+  return Node;
+}
+
+bool ScheduleTreeOptimizer::isProfitableSchedule(Scop &S,
+                                                 isl::schedule NewSchedule) {
+  // To understand if the schedule has been optimized we check if the schedule
+  // has changed at all.
+  // TODO: We can improve this by tracking if any necessarily beneficial
+  // transformations have been performed. This can e.g. be tiling, loop
+  // interchange, or ...) We can track this either at the place where the
+  // transformation has been performed or, in case of automatic ILP based
+  // optimizations, by comparing (yet to be defined) performance metrics
+  // before/after the scheduling optimizer
+  // (e.g., #stride-one accesses)
+  if (S.containsExtensionNode(NewSchedule))
+    return true;
+  auto NewScheduleMap = NewSchedule.get_map();
+  auto OldSchedule = S.getSchedule();
+  assert(OldSchedule && "Only IslScheduleOptimizer can insert extension nodes "
+                        "that make Scop::getSchedule() return nullptr.");
+  bool changed = !OldSchedule.is_equal(NewScheduleMap);
+  return changed;
+}
+
+namespace {
+
+class IslScheduleOptimizer : public ScopPass {
+public:
+  static char ID;
+
+  explicit IslScheduleOptimizer() : ScopPass(ID) {}
+
+  ~IslScheduleOptimizer() override { isl_schedule_free(LastSchedule); }
+
+  /// Optimize the schedule of the SCoP @p S.
+  bool runOnScop(Scop &S) override;
+
+  /// Print the new schedule for the SCoP @p S.
+  void printScop(raw_ostream &OS, Scop &S) const override;
+
+  /// Register all analyses and transformation required.
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+  /// Release the internal memory.
+  void releaseMemory() override {
+    isl_schedule_free(LastSchedule);
+    LastSchedule = nullptr;
+  }
+
+private:
+  isl_schedule *LastSchedule = nullptr;
+};
+
+} // namespace
+
+char IslScheduleOptimizer::ID = 0;
+
+/// Collect statistics for the schedule tree.
+///
+/// @param Schedule The schedule tree to analyze. If not a schedule tree it is
+/// ignored.
+/// @param Version  The version of the schedule tree that is analyzed.
+///                 0 for the original schedule tree before any transformation.
+///                 1 for the schedule tree after isl's rescheduling.
+///                 2 for the schedule tree after optimizations are applied
+///                 (tiling, pattern matching)
+static void walkScheduleTreeForStatistics(isl::schedule Schedule, int Version) {
+  auto Root = Schedule.get_root();
+  if (!Root)
+    return;
+
+  isl_schedule_node_foreach_descendant_top_down(
+      Root.get(),
+      [](__isl_keep isl_schedule_node *nodeptr, void *user) -> isl_bool {
+        isl::schedule_node Node = isl::manage(isl_schedule_node_copy(nodeptr));
+        int Version = *static_cast<int *>(user);
+
+        switch (isl_schedule_node_get_type(Node.get())) {
+        case isl_schedule_node_band: {
+          NumBands[Version]++;
+          if (isl_schedule_node_band_get_permutable(Node.get()) ==
+              isl_bool_true)
+            NumPermutable[Version]++;
+
+          int CountMembers = isl_schedule_node_band_n_member(Node.get());
+          NumBandMembers[Version] += CountMembers;
+          for (int i = 0; i < CountMembers; i += 1) {
+            if (Node.band_member_get_coincident(i))
+              NumCoincident[Version]++;
+          }
+          break;
+        }
+
+        case isl_schedule_node_filter:
+          NumFilters[Version]++;
+          break;
+
+        case isl_schedule_node_extension:
+          NumExtension[Version]++;
+          break;
+
+        default:
+          break;
+        }
+
+        return isl_bool_true;
+      },
+      &Version);
+}
+
+bool IslScheduleOptimizer::runOnScop(Scop &S) {
+  // Skip SCoPs in case they're already optimised by PPCGCodeGeneration
+  if (S.isToBeSkipped())
+    return false;
+
+  // Skip empty SCoPs but still allow code generation as it will delete the
+  // loops present but not needed.
+  if (S.getSize() == 0) {
+    S.markAsOptimized();
+    return false;
+  }
+
+  const Dependences &D =
+      getAnalysis<DependenceInfo>().getDependences(Dependences::AL_Statement);
+
+  if (D.getSharedIslCtx() != S.getSharedIslCtx()) {
+    DEBUG(dbgs() << "DependenceInfo for another SCoP/isl_ctx\n");
+    return false;
+  }
+
+  if (!D.hasValidDependences())
+    return false;
+
+  isl_schedule_free(LastSchedule);
+  LastSchedule = nullptr;
+
+  // Build input data.
+  int ValidityKinds =
+      Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW;
+  int ProximityKinds;
+
+  if (OptimizeDeps == "all")
+    ProximityKinds =
+        Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW;
+  else if (OptimizeDeps == "raw")
+    ProximityKinds = Dependences::TYPE_RAW;
+  else {
+    errs() << "Do not know how to optimize for '" << OptimizeDeps << "'"
+           << " Falling back to optimizing all dependences.\n";
+    ProximityKinds =
+        Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW;
+  }
+
+  isl::union_set Domain = S.getDomains();
+
+  if (!Domain)
+    return false;
+
+  ScopsProcessed++;
+  walkScheduleTreeForStatistics(S.getScheduleTree(), 0);
+
+  isl::union_map Validity = give(D.getDependences(ValidityKinds));
+  isl::union_map Proximity = give(D.getDependences(ProximityKinds));
+
+  // Simplify the dependences by removing the constraints introduced by the
+  // domains. This can speed up the scheduling time significantly, as large
+  // constant coefficients will be removed from the dependences. The
+  // introduction of some additional dependences reduces the possible
+  // transformations, but in most cases, such transformation do not seem to be
+  // interesting anyway. In some cases this option may stop the scheduler to
+  // find any schedule.
+  if (SimplifyDeps == "yes") {
+    Validity = Validity.gist_domain(Domain);
+    Validity = Validity.gist_range(Domain);
+    Proximity = Proximity.gist_domain(Domain);
+    Proximity = Proximity.gist_range(Domain);
+  } else if (SimplifyDeps != "no") {
+    errs() << "warning: Option -polly-opt-simplify-deps should either be 'yes' "
+              "or 'no'. Falling back to default: 'yes'\n";
+  }
+
+  DEBUG(dbgs() << "\n\nCompute schedule from: ");
+  DEBUG(dbgs() << "Domain := " << Domain << ";\n");
+  DEBUG(dbgs() << "Proximity := " << Proximity << ";\n");
+  DEBUG(dbgs() << "Validity := " << Validity << ";\n");
+
+  unsigned IslSerializeSCCs;
+
+  if (FusionStrategy == "max") {
+    IslSerializeSCCs = 0;
+  } else if (FusionStrategy == "min") {
+    IslSerializeSCCs = 1;
+  } else {
+    errs() << "warning: Unknown fusion strategy. Falling back to maximal "
+              "fusion.\n";
+    IslSerializeSCCs = 0;
+  }
+
+  int IslMaximizeBands;
+
+  if (MaximizeBandDepth == "yes") {
+    IslMaximizeBands = 1;
+  } else if (MaximizeBandDepth == "no") {
+    IslMaximizeBands = 0;
+  } else {
+    errs() << "warning: Option -polly-opt-maximize-bands should either be 'yes'"
+              " or 'no'. Falling back to default: 'yes'\n";
+    IslMaximizeBands = 1;
+  }
+
+  int IslOuterCoincidence;
+
+  if (OuterCoincidence == "yes") {
+    IslOuterCoincidence = 1;
+  } else if (OuterCoincidence == "no") {
+    IslOuterCoincidence = 0;
+  } else {
+    errs() << "warning: Option -polly-opt-outer-coincidence should either be "
+              "'yes' or 'no'. Falling back to default: 'no'\n";
+    IslOuterCoincidence = 0;
+  }
+
+  isl_ctx *Ctx = S.getIslCtx().get();
+
+  isl_options_set_schedule_outer_coincidence(Ctx, IslOuterCoincidence);
+  isl_options_set_schedule_serialize_sccs(Ctx, IslSerializeSCCs);
+  isl_options_set_schedule_maximize_band_depth(Ctx, IslMaximizeBands);
+  isl_options_set_schedule_max_constant_term(Ctx, MaxConstantTerm);
+  isl_options_set_schedule_max_coefficient(Ctx, MaxCoefficient);
+  isl_options_set_tile_scale_tile_loops(Ctx, 0);
+
+  auto OnErrorStatus = isl_options_get_on_error(Ctx);
+  isl_options_set_on_error(Ctx, ISL_ON_ERROR_CONTINUE);
+
+  auto SC = isl::schedule_constraints::on_domain(Domain);
+  SC = SC.set_proximity(Proximity);
+  SC = SC.set_validity(Validity);
+  SC = SC.set_coincidence(Validity);
+  auto Schedule = SC.compute_schedule();
+  isl_options_set_on_error(Ctx, OnErrorStatus);
+
+  walkScheduleTreeForStatistics(Schedule, 1);
+
+  // In cases the scheduler is not able to optimize the code, we just do not
+  // touch the schedule.
+  if (!Schedule)
+    return false;
+
+  ScopsRescheduled++;
+
+  DEBUG({
+    auto *P = isl_printer_to_str(Ctx);
+    P = isl_printer_set_yaml_style(P, ISL_YAML_STYLE_BLOCK);
+    P = isl_printer_print_schedule(P, Schedule.get());
+    auto *str = isl_printer_get_str(P);
+    dbgs() << "NewScheduleTree: \n" << str << "\n";
+    free(str);
+    isl_printer_free(P);
+  });
+
+  Function &F = S.getFunction();
+  auto *TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
+  const OptimizerAdditionalInfoTy OAI = {TTI, const_cast<Dependences *>(&D)};
+  auto NewSchedule = ScheduleTreeOptimizer::optimizeSchedule(Schedule, &OAI);
+  walkScheduleTreeForStatistics(NewSchedule, 2);
+
+  if (!ScheduleTreeOptimizer::isProfitableSchedule(S, NewSchedule))
+    return false;
+
+  auto ScopStats = S.getStatistics();
+  ScopsOptimized++;
+  NumAffineLoopsOptimized += ScopStats.NumAffineLoops;
+  NumBoxedLoopsOptimized += ScopStats.NumBoxedLoops;
+
+  S.setScheduleTree(NewSchedule);
+  S.markAsOptimized();
+
+  if (OptimizedScops)
+    errs() << S;
+
+  return false;
+}
+
+void IslScheduleOptimizer::printScop(raw_ostream &OS, Scop &) const {
+  isl_printer *p;
+  char *ScheduleStr;
+
+  OS << "Calculated schedule:\n";
+
+  if (!LastSchedule) {
+    OS << "n/a\n";
+    return;
+  }
+
+  p = isl_printer_to_str(isl_schedule_get_ctx(LastSchedule));
+  p = isl_printer_print_schedule(p, LastSchedule);
+  ScheduleStr = isl_printer_get_str(p);
+  isl_printer_free(p);
+
+  OS << ScheduleStr << "\n";
+}
+
+void IslScheduleOptimizer::getAnalysisUsage(AnalysisUsage &AU) const {
+  ScopPass::getAnalysisUsage(AU);
+  AU.addRequired<DependenceInfo>();
+  AU.addRequired<TargetTransformInfoWrapperPass>();
+
+  AU.addPreserved<DependenceInfo>();
+}
+
+Pass *polly::createIslScheduleOptimizerPass() {
+  return new IslScheduleOptimizer();
+}
+
+INITIALIZE_PASS_BEGIN(IslScheduleOptimizer, "polly-opt-isl",
+                      "Polly - Optimize schedule of SCoP", false, false);
+INITIALIZE_PASS_DEPENDENCY(DependenceInfo);
+INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass);
+INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass);
+INITIALIZE_PASS_END(IslScheduleOptimizer, "polly-opt-isl",
+                    "Polly - Optimize schedule of SCoP", false, false)
diff --git a/final/lib/Transform/ScopInliner.cpp b/final/lib/Transform/ScopInliner.cpp
new file mode 100644
index 0000000..064e8d3
--- /dev/null
+++ b/final/lib/Transform/ScopInliner.cpp
@@ -0,0 +1,121 @@
+//===---- ScopInliner.cpp - Polyhedral based inliner ----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+/// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Take a SCC and:
+// 1. If it has more than one component, bail out (contains cycles)
+// 2. If it has just one component, and if the function is entirely a scop,
+//    inline it.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/LinkAllPasses.h"
+#include "polly/RegisterPasses.h"
+#include "polly/ScopDetection.h"
+#include "llvm/Analysis/CallGraphSCCPass.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Transforms/IPO/AlwaysInliner.h"
+
+#define DEBUG_TYPE "polly-scop-inliner"
+
+using namespace polly;
+extern bool polly::PollyAllowFullFunction;
+
+namespace {
+class ScopInliner : public CallGraphSCCPass {
+  using llvm::Pass::doInitialization;
+
+public:
+  static char ID;
+
+  ScopInliner() : CallGraphSCCPass(ID) {}
+
+  bool doInitialization(CallGraph &CG) override {
+    if (!polly::PollyAllowFullFunction) {
+      report_fatal_error(
+          "Aborting from ScopInliner because it only makes sense to run with "
+          "-polly-allow-full-function. "
+          "The heurtistic for ScopInliner checks that the full function is a "
+          "Scop, which happens if and only if polly-allow-full-function is "
+          " enabled. "
+          " If not, the entry block is not included in the Scop");
+    }
+    return true;
+  }
+
+  bool runOnSCC(CallGraphSCC &SCC) override {
+    // We do not try to inline non-trivial SCCs because this would lead to
+    // "infinite" inlining if we are not careful.
+    if (SCC.size() > 1)
+      return false;
+    assert(SCC.size() == 1 && "found empty SCC");
+    Function *F = (*SCC.begin())->getFunction();
+
+    // If the function is a nullptr, or the function is a declaration.
+    if (!F)
+      return false;
+    if (F->isDeclaration()) {
+      DEBUG(dbgs() << "Skipping " << F->getName()
+                   << "because it is a declaration.\n");
+      return false;
+    }
+
+    PassBuilder PB;
+    FunctionAnalysisManager FAM;
+    FAM.registerPass([] { return ScopAnalysis(); });
+    PB.registerFunctionAnalyses(FAM);
+
+    RegionInfo &RI = FAM.getResult<RegionInfoAnalysis>(*F);
+    ScopDetection &SD = FAM.getResult<ScopAnalysis>(*F);
+
+    const bool HasScopAsTopLevelRegion =
+        SD.ValidRegions.count(RI.getTopLevelRegion()) > 0;
+
+    if (HasScopAsTopLevelRegion) {
+      DEBUG(dbgs() << "Skipping " << F->getName()
+                   << " has scop as top level region");
+      F->addFnAttr(llvm::Attribute::AlwaysInline);
+
+      ModuleAnalysisManager MAM;
+      PB.registerModuleAnalyses(MAM);
+      ModulePassManager MPM;
+      MPM.addPass(AlwaysInlinerPass());
+      Module *M = F->getParent();
+      assert(M && "Function has illegal module");
+      MPM.run(*M, MAM);
+    } else {
+      DEBUG(dbgs() << F->getName()
+                   << " does NOT have scop as top level region\n");
+    }
+
+    return false;
+  };
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    CallGraphSCCPass::getAnalysisUsage(AU);
+  }
+};
+
+} // namespace
+char ScopInliner::ID;
+
+Pass *polly::createScopInlinerPass() {
+  ScopInliner *pass = new ScopInliner();
+  return pass;
+}
+
+INITIALIZE_PASS_BEGIN(
+    ScopInliner, "polly-scop-inliner",
+    "inline functions based on how much of the function is a scop.", false,
+    false)
+INITIALIZE_PASS_END(
+    ScopInliner, "polly-scop-inliner",
+    "inline functions based on how much of the function is a scop.", false,
+    false)
diff --git a/final/lib/Transform/Simplify.cpp b/final/lib/Transform/Simplify.cpp
new file mode 100644
index 0000000..183acee
--- /dev/null
+++ b/final/lib/Transform/Simplify.cpp
@@ -0,0 +1,729 @@
+//===------ Simplify.cpp ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Simplify a SCoP by removing unnecessary statements and accesses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/Simplify.h"
+#include "polly/ScopInfo.h"
+#include "polly/ScopPass.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/ISLOStream.h"
+#include "polly/Support/ISLTools.h"
+#include "polly/Support/VirtualInstruction.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "polly-simplify"
+
+using namespace llvm;
+using namespace polly;
+
+namespace {
+
+#define TWO_STATISTICS(VARNAME, DESC)                                          \
+  static llvm::Statistic VARNAME[2] = {                                        \
+      {DEBUG_TYPE, #VARNAME "0", DESC " (first)", {0}, false},                 \
+      {DEBUG_TYPE, #VARNAME "1", DESC " (second)", {0}, false}}
+
+/// Number of max disjuncts we allow in removeOverwrites(). This is to avoid
+/// that the analysis of accesses in a statement is becoming too complex. Chosen
+/// to be relatively small because all the common cases should access only few
+/// array elements per statement.
+static int const SimplifyMaxDisjuncts = 4;
+
+TWO_STATISTICS(ScopsProcessed, "Number of SCoPs processed");
+TWO_STATISTICS(ScopsModified, "Number of SCoPs simplified");
+
+TWO_STATISTICS(TotalOverwritesRemoved, "Number of removed overwritten writes");
+TWO_STATISTICS(TotalWritesCoalesced, "Number of writes coalesced with another");
+TWO_STATISTICS(TotalRedundantWritesRemoved,
+               "Number of writes of same value removed in any SCoP");
+TWO_STATISTICS(TotalEmptyPartialAccessesRemoved,
+               "Number of empty partial accesses removed");
+TWO_STATISTICS(TotalDeadAccessesRemoved, "Number of dead accesses removed");
+TWO_STATISTICS(TotalDeadInstructionsRemoved,
+               "Number of unused instructions removed");
+TWO_STATISTICS(TotalStmtsRemoved, "Number of statements removed in any SCoP");
+
+TWO_STATISTICS(NumValueWrites, "Number of scalar value writes after Simplify");
+TWO_STATISTICS(
+    NumValueWritesInLoops,
+    "Number of scalar value writes nested in affine loops after Simplify");
+TWO_STATISTICS(NumPHIWrites,
+               "Number of scalar phi writes after the first simplification");
+TWO_STATISTICS(
+    NumPHIWritesInLoops,
+    "Number of scalar phi writes nested in affine loops after Simplify");
+TWO_STATISTICS(NumSingletonWrites, "Number of singleton writes after Simplify");
+TWO_STATISTICS(
+    NumSingletonWritesInLoops,
+    "Number of singleton writes nested in affine loops after Simplify");
+
+static bool isImplicitRead(MemoryAccess *MA) {
+  return MA->isRead() && MA->isOriginalScalarKind();
+}
+
+static bool isExplicitAccess(MemoryAccess *MA) {
+  return MA->isOriginalArrayKind();
+}
+
+static bool isImplicitWrite(MemoryAccess *MA) {
+  return MA->isWrite() && MA->isOriginalScalarKind();
+}
+
+/// Like isl::union_map::add_map, but may also return an underapproximated
+/// result if getting too complex.
+///
+/// This is implemented by adding disjuncts to the results until the limit is
+/// reached.
+static isl::union_map underapproximatedAddMap(isl::union_map UMap,
+                                              isl::map Map) {
+  if (UMap.is_null() || Map.is_null())
+    return {};
+
+  isl::map PrevMap = UMap.extract_map(Map.get_space());
+
+  // Fast path: If known that we cannot exceed the disjunct limit, just add
+  // them.
+  if (isl_map_n_basic_map(PrevMap.get()) + isl_map_n_basic_map(Map.get()) <=
+      SimplifyMaxDisjuncts)
+    return UMap.add_map(Map);
+
+  isl::map Result = isl::map::empty(PrevMap.get_space());
+  PrevMap.foreach_basic_map([&Result](isl::basic_map BMap) -> isl::stat {
+    if (isl_map_n_basic_map(Result.get()) > SimplifyMaxDisjuncts)
+      return isl::stat::error;
+    Result = Result.unite(BMap);
+    return isl::stat::ok;
+  });
+  Map.foreach_basic_map([&Result](isl::basic_map BMap) -> isl::stat {
+    if (isl_map_n_basic_map(Result.get()) > SimplifyMaxDisjuncts)
+      return isl::stat::error;
+    Result = Result.unite(BMap);
+    return isl::stat::ok;
+  });
+
+  isl::union_map UResult =
+      UMap.subtract(isl::map::universe(PrevMap.get_space()));
+  UResult.add_map(Result);
+
+  return UResult;
+}
+
+class Simplify : public ScopPass {
+private:
+  /// The invocation id (if there are multiple instances in the pass manager's
+  /// pipeline) to determine which statistics to update.
+  int CallNo;
+
+  /// The last/current SCoP that is/has been processed.
+  Scop *S;
+
+  /// Number of writes that are overwritten anyway.
+  int OverwritesRemoved = 0;
+
+  /// Number of combined writes.
+  int WritesCoalesced = 0;
+
+  /// Number of redundant writes removed from this SCoP.
+  int RedundantWritesRemoved = 0;
+
+  /// Number of writes with empty access domain removed.
+  int EmptyPartialAccessesRemoved = 0;
+
+  /// Number of unused accesses removed from this SCoP.
+  int DeadAccessesRemoved = 0;
+
+  /// Number of unused instructions removed from this SCoP.
+  int DeadInstructionsRemoved = 0;
+
+  /// Number of unnecessary statements removed from the SCoP.
+  int StmtsRemoved = 0;
+
+  /// Return whether at least one simplification has been applied.
+  bool isModified() const {
+    return OverwritesRemoved > 0 || WritesCoalesced > 0 ||
+           RedundantWritesRemoved > 0 || EmptyPartialAccessesRemoved > 0 ||
+           DeadAccessesRemoved > 0 || DeadInstructionsRemoved > 0 ||
+           StmtsRemoved > 0;
+  }
+
+  /// Remove writes that are overwritten unconditionally later in the same
+  /// statement.
+  ///
+  /// There must be no read of the same value between the write (that is to be
+  /// removed) and the overwrite.
+  void removeOverwrites() {
+    for (auto &Stmt : *S) {
+      isl::set Domain = Stmt.getDomain();
+      isl::union_map WillBeOverwritten =
+          isl::union_map::empty(S->getParamSpace());
+
+      SmallVector<MemoryAccess *, 32> Accesses(getAccessesInOrder(Stmt));
+
+      // Iterate in reverse order, so the overwrite comes before the write that
+      // is to be removed.
+      for (auto *MA : reverse(Accesses)) {
+
+        // In region statements, the explicit accesses can be in blocks that are
+        // can be executed in any order. We therefore process only the implicit
+        // writes and stop after that.
+        if (Stmt.isRegionStmt() && isExplicitAccess(MA))
+          break;
+
+        auto AccRel = MA->getAccessRelation();
+        AccRel = AccRel.intersect_domain(Domain);
+        AccRel = AccRel.intersect_params(S->getContext());
+
+        // If a value is read in-between, do not consider it as overwritten.
+        if (MA->isRead()) {
+          // Invalidate all overwrites for the array it accesses to avoid too
+          // complex isl sets.
+          isl::map AccRelUniv = isl::map::universe(AccRel.get_space());
+          WillBeOverwritten = WillBeOverwritten.subtract(AccRelUniv);
+          continue;
+        }
+
+        // If all of a write's elements are overwritten, remove it.
+        isl::union_map AccRelUnion = AccRel;
+        if (AccRelUnion.is_subset(WillBeOverwritten)) {
+          DEBUG(dbgs() << "Removing " << MA
+                       << " which will be overwritten anyway\n");
+
+          Stmt.removeSingleMemoryAccess(MA);
+          OverwritesRemoved++;
+          TotalOverwritesRemoved[CallNo]++;
+        }
+
+        // Unconditional writes overwrite other values.
+        if (MA->isMustWrite()) {
+          // Avoid too complex isl sets. If necessary, throw away some of the
+          // knowledge.
+          WillBeOverwritten =
+              underapproximatedAddMap(WillBeOverwritten, AccRel);
+        }
+      }
+    }
+  }
+
+  /// Combine writes that write the same value if possible.
+  ///
+  /// This function is able to combine:
+  /// - Partial writes with disjoint domain.
+  /// - Writes that write to the same array element.
+  ///
+  /// In all cases, both writes must write the same values.
+  void coalesceWrites() {
+    for (auto &Stmt : *S) {
+      isl::set Domain = Stmt.getDomain().intersect_params(S->getContext());
+
+      // We let isl do the lookup for the same-value condition. For this, we
+      // wrap llvm::Value into an isl::set such that isl can do the lookup in
+      // its hashtable implementation. llvm::Values are only compared within a
+      // ScopStmt, so the map can be local to this scope. TODO: Refactor with
+      // ZoneAlgorithm::makeValueSet()
+      SmallDenseMap<Value *, isl::set> ValueSets;
+      auto makeValueSet = [&ValueSets, this](Value *V) -> isl::set {
+        assert(V);
+        isl::set &Result = ValueSets[V];
+        if (Result.is_null()) {
+          isl::ctx Ctx = S->getIslCtx();
+          std::string Name =
+              getIslCompatibleName("Val", V, ValueSets.size() - 1,
+                                   std::string(), UseInstructionNames);
+          isl::id Id = isl::id::alloc(Ctx, Name, V);
+          Result = isl::set::universe(
+              isl::space(Ctx, 0, 0).set_tuple_id(isl::dim::set, Id));
+        }
+        return Result;
+      };
+
+      // List of all eligible (for coalescing) writes of the future.
+      // { [Domain[] -> Element[]] -> [Value[] -> MemoryAccess[]] }
+      isl::union_map FutureWrites = isl::union_map::empty(S->getParamSpace());
+
+      // Iterate over accesses from the last to the first.
+      SmallVector<MemoryAccess *, 32> Accesses(getAccessesInOrder(Stmt));
+      for (MemoryAccess *MA : reverse(Accesses)) {
+        // In region statements, the explicit accesses can be in blocks that can
+        // be executed in any order. We therefore process only the implicit
+        // writes and stop after that.
+        if (Stmt.isRegionStmt() && isExplicitAccess(MA))
+          break;
+
+        // { Domain[] -> Element[] }
+        isl::map AccRel =
+            MA->getLatestAccessRelation().intersect_domain(Domain);
+
+        // { [Domain[] -> Element[]] }
+        isl::set AccRelWrapped = AccRel.wrap();
+
+        // { Value[] }
+        isl::set ValSet;
+
+        if (MA->isMustWrite() && (MA->isOriginalScalarKind() ||
+                                  isa<StoreInst>(MA->getAccessInstruction()))) {
+          // Normally, tryGetValueStored() should be used to determine which
+          // element is written, but it can return nullptr; For PHI accesses,
+          // getAccessValue() returns the PHI instead of the PHI's incoming
+          // value. In this case, where we only compare values of a single
+          // statement, this is fine, because within a statement, a PHI in a
+          // successor block has always the same value as the incoming write. We
+          // still preferably use the incoming value directly so we also catch
+          // direct uses of that.
+          Value *StoredVal = MA->tryGetValueStored();
+          if (!StoredVal)
+            StoredVal = MA->getAccessValue();
+          ValSet = makeValueSet(StoredVal);
+
+          // { Domain[] }
+          isl::set AccDomain = AccRel.domain();
+
+          // Parts of the statement's domain that is not written by this access.
+          isl::set UndefDomain = Domain.subtract(AccDomain);
+
+          // { Element[] }
+          isl::set ElementUniverse =
+              isl::set::universe(AccRel.get_space().range());
+
+          // { Domain[] -> Element[] }
+          isl::map UndefAnything =
+              isl::map::from_domain_and_range(UndefDomain, ElementUniverse);
+
+          // We are looking a compatible write access. The other write can
+          // access these elements...
+          isl::map AllowedAccesses = AccRel.unite(UndefAnything);
+
+          // ... and must write the same value.
+          // { [Domain[] -> Element[]] -> Value[] }
+          isl::map Filter =
+              isl::map::from_domain_and_range(AllowedAccesses.wrap(), ValSet);
+
+          // Lookup future write that fulfills these conditions.
+          // { [[Domain[] -> Element[]] -> Value[]] -> MemoryAccess[] }
+          isl::union_map Filtered =
+              FutureWrites.uncurry().intersect_domain(Filter.wrap());
+
+          // Iterate through the candidates.
+          Filtered.foreach_map([&, this](isl::map Map) -> isl::stat {
+            MemoryAccess *OtherMA = (MemoryAccess *)Map.get_space()
+                                        .get_tuple_id(isl::dim::out)
+                                        .get_user();
+
+            isl::map OtherAccRel =
+                OtherMA->getLatestAccessRelation().intersect_domain(Domain);
+
+            // The filter only guaranteed that some of OtherMA's accessed
+            // elements are allowed. Verify that it only accesses allowed
+            // elements. Otherwise, continue with the next candidate.
+            if (!OtherAccRel.is_subset(AllowedAccesses).is_true())
+              return isl::stat::ok;
+
+            // The combined access relation.
+            // { Domain[] -> Element[] }
+            isl::map NewAccRel = AccRel.unite(OtherAccRel);
+            simplify(NewAccRel);
+
+            // Carry out the coalescing.
+            Stmt.removeSingleMemoryAccess(MA);
+            OtherMA->setNewAccessRelation(NewAccRel);
+
+            // We removed MA, OtherMA takes its role.
+            MA = OtherMA;
+
+            TotalWritesCoalesced[CallNo]++;
+            WritesCoalesced++;
+
+            // Don't look for more candidates.
+            return isl::stat::error;
+          });
+        }
+
+        // Two writes cannot be coalesced if there is another access (to some of
+        // the written elements) between them. Remove all visited write accesses
+        // from the list of eligible writes. Don't just remove the accessed
+        // elements, but any MemoryAccess that touches any of the invalidated
+        // elements.
+        SmallPtrSet<MemoryAccess *, 2> TouchedAccesses;
+        FutureWrites.intersect_domain(AccRelWrapped)
+            .foreach_map([&TouchedAccesses](isl::map Map) -> isl::stat {
+              MemoryAccess *MA = (MemoryAccess *)Map.get_space()
+                                     .range()
+                                     .unwrap()
+                                     .get_tuple_id(isl::dim::out)
+                                     .get_user();
+              TouchedAccesses.insert(MA);
+              return isl::stat::ok;
+            });
+        isl::union_map NewFutureWrites =
+            isl::union_map::empty(FutureWrites.get_space());
+        FutureWrites.foreach_map([&TouchedAccesses, &NewFutureWrites](
+                                     isl::map FutureWrite) -> isl::stat {
+          MemoryAccess *MA = (MemoryAccess *)FutureWrite.get_space()
+                                 .range()
+                                 .unwrap()
+                                 .get_tuple_id(isl::dim::out)
+                                 .get_user();
+          if (!TouchedAccesses.count(MA))
+            NewFutureWrites = NewFutureWrites.add_map(FutureWrite);
+          return isl::stat::ok;
+        });
+        FutureWrites = NewFutureWrites;
+
+        if (MA->isMustWrite() && !ValSet.is_null()) {
+          // { MemoryAccess[] }
+          auto AccSet =
+              isl::set::universe(isl::space(S->getIslCtx(), 0, 0)
+                                     .set_tuple_id(isl::dim::set, MA->getId()));
+
+          // { Val[] -> MemoryAccess[] }
+          isl::map ValAccSet = isl::map::from_domain_and_range(ValSet, AccSet);
+
+          // { [Domain[] -> Element[]] -> [Value[] -> MemoryAccess[]] }
+          isl::map AccRelValAcc =
+              isl::map::from_domain_and_range(AccRelWrapped, ValAccSet.wrap());
+          FutureWrites = FutureWrites.add_map(AccRelValAcc);
+        }
+      }
+    }
+  }
+
+  /// Remove writes that just write the same value already stored in the
+  /// element.
+  void removeRedundantWrites() {
+    for (auto &Stmt : *S) {
+      SmallDenseMap<Value *, isl::set> ValueSets;
+      auto makeValueSet = [&ValueSets, this](Value *V) -> isl::set {
+        assert(V);
+        isl::set &Result = ValueSets[V];
+        if (Result.is_null()) {
+          isl_ctx *Ctx = S->getIslCtx().get();
+          std::string Name =
+              getIslCompatibleName("Val", V, ValueSets.size() - 1,
+                                   std::string(), UseInstructionNames);
+          isl::id Id = give(isl_id_alloc(Ctx, Name.c_str(), V));
+          Result = isl::set::universe(
+              isl::space(Ctx, 0, 0).set_tuple_id(isl::dim::set, Id));
+        }
+        return Result;
+      };
+
+      isl::set Domain = Stmt.getDomain();
+      Domain = Domain.intersect_params(S->getContext());
+
+      // List of element reads that still have the same value while iterating
+      // through the MemoryAccesses.
+      // { [Domain[] -> Element[]] -> Val[] }
+      isl::union_map Known = isl::union_map::empty(S->getParamSpace());
+
+      SmallVector<MemoryAccess *, 32> Accesses(getAccessesInOrder(Stmt));
+      for (MemoryAccess *MA : Accesses) {
+        // Is the memory access in a defined order relative to the other
+        // accesses? In region statements, only the first and the last accesses
+        // have defined order. Execution of those in the middle may depend on
+        // runtime conditions an therefore cannot be modified.
+        bool IsOrdered =
+            Stmt.isBlockStmt() || MA->isOriginalScalarKind() ||
+            (!S->getBoxedLoops().size() && MA->getAccessInstruction() &&
+             Stmt.getEntryBlock() == MA->getAccessInstruction()->getParent());
+
+        isl::map AccRel = MA->getAccessRelation();
+        AccRel = AccRel.intersect_domain(Domain);
+        isl::set AccRelWrapped = AccRel.wrap();
+
+        // Determine whether a write is redundant (stores only values that are
+        // already present in the written array elements) and remove it if this
+        // is the case.
+        if (IsOrdered && MA->isMustWrite() &&
+            (isa<StoreInst>(MA->getAccessInstruction()) ||
+             MA->isOriginalScalarKind())) {
+          Value *StoredVal = MA->tryGetValueStored();
+          if (!StoredVal)
+            StoredVal = MA->getAccessValue();
+
+          if (StoredVal) {
+            // Lookup in the set of known values.
+            isl::map AccRelStoredVal = isl::map::from_domain_and_range(
+                AccRelWrapped, makeValueSet(StoredVal));
+            if (isl::union_map(AccRelStoredVal).is_subset(Known)) {
+              DEBUG(dbgs() << "Cleanup of " << MA << ":\n");
+              DEBUG(dbgs() << "      Scalar: " << *StoredVal << "\n");
+              DEBUG(dbgs() << "      AccRel: " << AccRel << "\n");
+
+              Stmt.removeSingleMemoryAccess(MA);
+
+              RedundantWritesRemoved++;
+              TotalRedundantWritesRemoved[CallNo]++;
+            }
+          }
+        }
+
+        // Update the know values set.
+        if (MA->isRead()) {
+          // Loaded values are the currently known values of the array element
+          // it was loaded from.
+          Value *LoadedVal = MA->getAccessValue();
+          if (LoadedVal && IsOrdered) {
+            isl::map AccRelVal = isl::map::from_domain_and_range(
+                AccRelWrapped, makeValueSet(LoadedVal));
+
+            Known = Known.add_map(AccRelVal);
+          }
+        } else if (MA->isWrite()) {
+          // Remove (possibly) overwritten values from the known elements set.
+          // We remove all elements of the accessed array to avoid too complex
+          // isl sets.
+          isl::set AccRelUniv = isl::set::universe(AccRelWrapped.get_space());
+          Known = Known.subtract_domain(AccRelUniv);
+
+          // At this point, we could add the written value of must-writes.
+          // However, writing same values is already handled by
+          // coalesceWrites().
+        }
+      }
+    }
+  }
+
+  /// Remove statements without side effects.
+  void removeUnnecessaryStmts() {
+    auto NumStmtsBefore = S->getSize();
+    S->simplifySCoP(true);
+    assert(NumStmtsBefore >= S->getSize());
+    StmtsRemoved = NumStmtsBefore - S->getSize();
+    DEBUG(dbgs() << "Removed " << StmtsRemoved << " (of " << NumStmtsBefore
+                 << ") statements\n");
+    TotalStmtsRemoved[CallNo] += StmtsRemoved;
+  }
+
+  /// Remove accesses that have an empty domain.
+  void removeEmptyPartialAccesses() {
+    for (ScopStmt &Stmt : *S) {
+      // Defer the actual removal to not invalidate iterators.
+      SmallVector<MemoryAccess *, 8> DeferredRemove;
+
+      for (MemoryAccess *MA : Stmt) {
+        if (!MA->isWrite())
+          continue;
+
+        isl::map AccRel = MA->getAccessRelation();
+        if (!AccRel.is_empty().is_true())
+          continue;
+
+        DEBUG(dbgs() << "Removing " << MA
+                     << " because it's a partial access that never occurs\n");
+        DeferredRemove.push_back(MA);
+      }
+
+      for (MemoryAccess *MA : DeferredRemove) {
+        Stmt.removeSingleMemoryAccess(MA);
+        EmptyPartialAccessesRemoved++;
+        TotalEmptyPartialAccessesRemoved[CallNo]++;
+      }
+    }
+  }
+
+  /// Mark all reachable instructions and access, and sweep those that are not
+  /// reachable.
+  void markAndSweep(LoopInfo *LI) {
+    DenseSet<MemoryAccess *> UsedMA;
+    DenseSet<VirtualInstruction> UsedInsts;
+
+    // Get all reachable instructions and accesses.
+    markReachable(S, LI, UsedInsts, UsedMA);
+
+    // Remove all non-reachable accesses.
+    // We need get all MemoryAccesses first, in order to not invalidate the
+    // iterators when removing them.
+    SmallVector<MemoryAccess *, 64> AllMAs;
+    for (ScopStmt &Stmt : *S)
+      AllMAs.append(Stmt.begin(), Stmt.end());
+
+    for (MemoryAccess *MA : AllMAs) {
+      if (UsedMA.count(MA))
+        continue;
+      DEBUG(dbgs() << "Removing " << MA << " because its value is not used\n");
+      ScopStmt *Stmt = MA->getStatement();
+      Stmt->removeSingleMemoryAccess(MA);
+
+      DeadAccessesRemoved++;
+      TotalDeadAccessesRemoved[CallNo]++;
+    }
+
+    // Remove all non-reachable instructions.
+    for (ScopStmt &Stmt : *S) {
+      // Note that for region statements, we can only remove the non-terminator
+      // instructions of the entry block. All other instructions are not in the
+      // instructions list, but implicitly always part of the statement.
+
+      SmallVector<Instruction *, 32> AllInsts(Stmt.insts_begin(),
+                                              Stmt.insts_end());
+      SmallVector<Instruction *, 32> RemainInsts;
+
+      for (Instruction *Inst : AllInsts) {
+        auto It = UsedInsts.find({&Stmt, Inst});
+        if (It == UsedInsts.end()) {
+          DEBUG(dbgs() << "Removing "; Inst->print(dbgs());
+                dbgs() << " because it is not used\n");
+          DeadInstructionsRemoved++;
+          TotalDeadInstructionsRemoved[CallNo]++;
+          continue;
+        }
+
+        RemainInsts.push_back(Inst);
+
+        // If instructions appear multiple times, keep only the first.
+        UsedInsts.erase(It);
+      }
+
+      // Set the new instruction list to be only those we did not remove.
+      Stmt.setInstructions(RemainInsts);
+    }
+  }
+
+  /// Print simplification statistics to @p OS.
+  void printStatistics(llvm::raw_ostream &OS, int Indent = 0) const {
+    OS.indent(Indent) << "Statistics {\n";
+    OS.indent(Indent + 4) << "Overwrites removed: " << OverwritesRemoved
+                          << '\n';
+    OS.indent(Indent + 4) << "Partial writes coalesced: " << WritesCoalesced
+                          << "\n";
+    OS.indent(Indent + 4) << "Redundant writes removed: "
+                          << RedundantWritesRemoved << "\n";
+    OS.indent(Indent + 4) << "Accesses with empty domains removed: "
+                          << EmptyPartialAccessesRemoved << "\n";
+    OS.indent(Indent + 4) << "Dead accesses removed: " << DeadAccessesRemoved
+                          << '\n';
+    OS.indent(Indent + 4) << "Dead instructions removed: "
+                          << DeadInstructionsRemoved << '\n';
+    OS.indent(Indent + 4) << "Stmts removed: " << StmtsRemoved << "\n";
+    OS.indent(Indent) << "}\n";
+  }
+
+  /// Print the current state of all MemoryAccesses to @p OS.
+  void printAccesses(llvm::raw_ostream &OS, int Indent = 0) const {
+    OS.indent(Indent) << "After accesses {\n";
+    for (auto &Stmt : *S) {
+      OS.indent(Indent + 4) << Stmt.getBaseName() << "\n";
+      for (auto *MA : Stmt)
+        MA->print(OS);
+    }
+    OS.indent(Indent) << "}\n";
+  }
+
+public:
+  static char ID;
+  explicit Simplify(int CallNo = 0) : ScopPass(ID), CallNo(CallNo) {}
+
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.addRequiredTransitive<ScopInfoRegionPass>();
+    AU.addRequired<LoopInfoWrapperPass>();
+    AU.setPreservesAll();
+  }
+
+  virtual bool runOnScop(Scop &S) override {
+    // Reset statistics of last processed SCoP.
+    releaseMemory();
+    assert(!isModified());
+
+    // Prepare processing of this SCoP.
+    this->S = &S;
+    ScopsProcessed[CallNo]++;
+
+    DEBUG(dbgs() << "Removing partial writes that never happen...\n");
+    removeEmptyPartialAccesses();
+
+    DEBUG(dbgs() << "Removing overwrites...\n");
+    removeOverwrites();
+
+    DEBUG(dbgs() << "Coalesce partial writes...\n");
+    coalesceWrites();
+
+    DEBUG(dbgs() << "Removing redundant writes...\n");
+    removeRedundantWrites();
+
+    DEBUG(dbgs() << "Cleanup unused accesses...\n");
+    LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+    markAndSweep(LI);
+
+    DEBUG(dbgs() << "Removing statements without side effects...\n");
+    removeUnnecessaryStmts();
+
+    if (isModified())
+      ScopsModified[CallNo]++;
+    DEBUG(dbgs() << "\nFinal Scop:\n");
+    DEBUG(dbgs() << S);
+
+    auto ScopStats = S.getStatistics();
+    NumValueWrites[CallNo] += ScopStats.NumValueWrites;
+    NumValueWritesInLoops[CallNo] += ScopStats.NumValueWritesInLoops;
+    NumPHIWrites[CallNo] += ScopStats.NumPHIWrites;
+    NumPHIWritesInLoops[CallNo] += ScopStats.NumPHIWritesInLoops;
+    NumSingletonWrites[CallNo] += ScopStats.NumSingletonWrites;
+    NumSingletonWritesInLoops[CallNo] += ScopStats.NumSingletonWritesInLoops;
+
+    return false;
+  }
+
+  virtual void printScop(raw_ostream &OS, Scop &S) const override {
+    assert(&S == this->S &&
+           "Can only print analysis for the last processed SCoP");
+    printStatistics(OS);
+
+    if (!isModified()) {
+      OS << "SCoP could not be simplified\n";
+      return;
+    }
+    printAccesses(OS);
+  }
+
+  virtual void releaseMemory() override {
+    S = nullptr;
+
+    OverwritesRemoved = 0;
+    WritesCoalesced = 0;
+    RedundantWritesRemoved = 0;
+    EmptyPartialAccessesRemoved = 0;
+    DeadAccessesRemoved = 0;
+    DeadInstructionsRemoved = 0;
+    StmtsRemoved = 0;
+  }
+};
+
+char Simplify::ID;
+} // anonymous namespace
+
+namespace polly {
+SmallVector<MemoryAccess *, 32> getAccessesInOrder(ScopStmt &Stmt) {
+
+  SmallVector<MemoryAccess *, 32> Accesses;
+
+  for (MemoryAccess *MemAcc : Stmt)
+    if (isImplicitRead(MemAcc))
+      Accesses.push_back(MemAcc);
+
+  for (MemoryAccess *MemAcc : Stmt)
+    if (isExplicitAccess(MemAcc))
+      Accesses.push_back(MemAcc);
+
+  for (MemoryAccess *MemAcc : Stmt)
+    if (isImplicitWrite(MemAcc))
+      Accesses.push_back(MemAcc);
+
+  return Accesses;
+}
+} // namespace polly
+
+Pass *polly::createSimplifyPass(int CallNo) { return new Simplify(CallNo); }
+
+INITIALIZE_PASS_BEGIN(Simplify, "polly-simplify", "Polly - Simplify", false,
+                      false)
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
+INITIALIZE_PASS_END(Simplify, "polly-simplify", "Polly - Simplify", false,
+                    false)
diff --git a/final/lib/Transform/ZoneAlgo.cpp b/final/lib/Transform/ZoneAlgo.cpp
new file mode 100644
index 0000000..f31a748
--- /dev/null
+++ b/final/lib/Transform/ZoneAlgo.cpp
@@ -0,0 +1,1095 @@
+//===------ ZoneAlgo.cpp ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Derive information about array elements between statements ("Zones").
+//
+// The algorithms here work on the scatter space - the image space of the
+// schedule returned by Scop::getSchedule(). We call an element in that space a
+// "timepoint". Timepoints are lexicographically ordered such that we can
+// defined ranges in the scatter space. We use two flavors of such ranges:
+// Timepoint sets and zones. A timepoint set is simply a subset of the scatter
+// space and is directly stored as isl_set.
+//
+// Zones are used to describe the space between timepoints as open sets, i.e.
+// they do not contain the extrema. Using isl rational sets to express these
+// would be overkill. We also cannot store them as the integer timepoints they
+// contain; the (nonempty) zone between 1 and 2 would be empty and
+// indistinguishable from e.g. the zone between 3 and 4. Also, we cannot store
+// the integer set including the extrema; the set ]1,2[ + ]3,4[ could be
+// coalesced to ]1,3[, although we defined the range [2,3] to be not in the set.
+// Instead, we store the "half-open" integer extrema, including the lower bound,
+// but excluding the upper bound. Examples:
+//
+// * The set { [i] : 1 <= i <= 3 } represents the zone ]0,3[ (which contains the
+//   integer points 1 and 2, but not 0 or 3)
+//
+// * { [1] } represents the zone ]0,1[
+//
+// * { [i] : i = 1 or i = 3 } represents the zone ]0,1[ + ]2,3[
+//
+// Therefore, an integer i in the set represents the zone ]i-1,i[, i.e. strictly
+// speaking the integer points never belong to the zone. However, depending an
+// the interpretation, one might want to include them. Part of the
+// interpretation may not be known when the zone is constructed.
+//
+// Reads are assumed to always take place before writes, hence we can think of
+// reads taking place at the beginning of a timepoint and writes at the end.
+//
+// Let's assume that the zone represents the lifetime of a variable. That is,
+// the zone begins with a write that defines the value during its lifetime and
+// ends with the last read of that value. In the following we consider whether a
+// read/write at the beginning/ending of the lifetime zone should be within the
+// zone or outside of it.
+//
+// * A read at the timepoint that starts the live-range loads the previous
+//   value. Hence, exclude the timepoint starting the zone.
+//
+// * A write at the timepoint that starts the live-range is not defined whether
+//   it occurs before or after the write that starts the lifetime. We do not
+//   allow this situation to occur. Hence, we include the timepoint starting the
+//   zone to determine whether they are conflicting.
+//
+// * A read at the timepoint that ends the live-range reads the same variable.
+//   We include the timepoint at the end of the zone to include that read into
+//   the live-range. Doing otherwise would mean that the two reads access
+//   different values, which would mean that the value they read are both alive
+//   at the same time but occupy the same variable.
+//
+// * A write at the timepoint that ends the live-range starts a new live-range.
+//   It must not be included in the live-range of the previous definition.
+//
+// All combinations of reads and writes at the endpoints are possible, but most
+// of the time only the write->read (for instance, a live-range from definition
+// to last use) and read->write (for instance, an unused range from last use to
+// overwrite) and combinations are interesting (half-open ranges). write->write
+// zones might be useful as well in some context to represent
+// output-dependencies.
+//
+// @see convertZoneToTimepoints
+//
+//
+// The code makes use of maps and sets in many different spaces. To not loose
+// track in which space a set or map is expected to be in, variables holding an
+// isl reference are usually annotated in the comments. They roughly follow isl
+// syntax for spaces, but only the tuples, not the dimensions. The tuples have a
+// meaning as follows:
+//
+// * Space[] - An unspecified tuple. Used for function parameters such that the
+//             function caller can use it for anything they like.
+//
+// * Domain[] - A statement instance as returned by ScopStmt::getDomain()
+//     isl_id_get_name: Stmt_<NameOfBasicBlock>
+//     isl_id_get_user: Pointer to ScopStmt
+//
+// * Element[] - An array element as in the range part of
+//               MemoryAccess::getAccessRelation()
+//     isl_id_get_name: MemRef_<NameOfArrayVariable>
+//     isl_id_get_user: Pointer to ScopArrayInfo
+//
+// * Scatter[] - Scatter space or space of timepoints
+//     Has no tuple id
+//
+// * Zone[] - Range between timepoints as described above
+//     Has no tuple id
+//
+// * ValInst[] - An llvm::Value as defined at a specific timepoint.
+//
+//     A ValInst[] itself can be structured as one of:
+//
+//     * [] - An unknown value.
+//         Always zero dimensions
+//         Has no tuple id
+//
+//     * Value[] - An llvm::Value that is read-only in the SCoP, i.e. its
+//                 runtime content does not depend on the timepoint.
+//         Always zero dimensions
+//         isl_id_get_name: Val_<NameOfValue>
+//         isl_id_get_user: A pointer to an llvm::Value
+//
+//     * SCEV[...] - A synthesizable llvm::SCEV Expression.
+//         In contrast to a Value[] is has at least one dimension per
+//         SCEVAddRecExpr in the SCEV.
+//
+//     * [Domain[] -> Value[]] - An llvm::Value that may change during the
+//                               Scop's execution.
+//         The tuple itself has no id, but it wraps a map space holding a
+//         statement instance which defines the llvm::Value as the map's domain
+//         and llvm::Value itself as range.
+//
+// @see makeValInst()
+//
+// An annotation "{ Domain[] -> Scatter[] }" therefore means: A map from a
+// statement instance to a timepoint, aka a schedule. There is only one scatter
+// space, but most of the time multiple statements are processed in one set.
+// This is why most of the time isl_union_map has to be used.
+//
+// The basic algorithm works as follows:
+// At first we verify that the SCoP is compatible with this technique. For
+// instance, two writes cannot write to the same location at the same statement
+// instance because we cannot determine within the polyhedral model which one
+// comes first. Once this was verified, we compute zones at which an array
+// element is unused. This computation can fail if it takes too long. Then the
+// main algorithm is executed. Because every store potentially trails an unused
+// zone, we start at stores. We search for a scalar (MemoryKind::Value or
+// MemoryKind::PHI) that we can map to the array element overwritten by the
+// store, preferably one that is used by the store or at least the ScopStmt.
+// When it does not conflict with the lifetime of the values in the array
+// element, the map is applied and the unused zone updated as it is now used. We
+// continue to try to map scalars to the array element until there are no more
+// candidates to map. The algorithm is greedy in the sense that the first scalar
+// not conflicting will be mapped. Other scalars processed later that could have
+// fit the same unused zone will be rejected. As such the result depends on the
+// processing order.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/ZoneAlgo.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/ISLTools.h"
+#include "polly/Support/VirtualInstruction.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUG_TYPE "polly-zone"
+
+STATISTIC(NumIncompatibleArrays, "Number of not zone-analyzable arrays");
+STATISTIC(NumCompatibleArrays, "Number of zone-analyzable arrays");
+STATISTIC(NumRecursivePHIs, "Number of recursive PHIs");
+STATISTIC(NumNormalizablePHIs, "Number of normalizable PHIs");
+STATISTIC(NumPHINormialization, "Number of PHI executed normalizations");
+
+using namespace polly;
+using namespace llvm;
+
+static isl::union_map computeReachingDefinition(isl::union_map Schedule,
+                                                isl::union_map Writes,
+                                                bool InclDef, bool InclRedef) {
+  return computeReachingWrite(Schedule, Writes, false, InclDef, InclRedef);
+}
+
+/// Compute the reaching definition of a scalar.
+///
+/// Compared to computeReachingDefinition, there is just one element which is
+/// accessed and therefore only a set if instances that accesses that element is
+/// required.
+///
+/// @param Schedule  { DomainWrite[] -> Scatter[] }
+/// @param Writes    { DomainWrite[] }
+/// @param InclDef   Include the timepoint of the definition to the result.
+/// @param InclRedef Include the timepoint of the overwrite into the result.
+///
+/// @return { Scatter[] -> DomainWrite[] }
+static isl::union_map computeScalarReachingDefinition(isl::union_map Schedule,
+                                                      isl::union_set Writes,
+                                                      bool InclDef,
+                                                      bool InclRedef) {
+  // { DomainWrite[] -> Element[] }
+  isl::union_map Defs = isl::union_map::from_domain(Writes);
+
+  // { [Element[] -> Scatter[]] -> DomainWrite[] }
+  auto ReachDefs =
+      computeReachingDefinition(Schedule, Defs, InclDef, InclRedef);
+
+  // { Scatter[] -> DomainWrite[] }
+  return ReachDefs.curry().range().unwrap();
+}
+
+/// Compute the reaching definition of a scalar.
+///
+/// This overload accepts only a single writing statement as an isl_map,
+/// consequently the result also is only a single isl_map.
+///
+/// @param Schedule  { DomainWrite[] -> Scatter[] }
+/// @param Writes    { DomainWrite[] }
+/// @param InclDef   Include the timepoint of the definition to the result.
+/// @param InclRedef Include the timepoint of the overwrite into the result.
+///
+/// @return { Scatter[] -> DomainWrite[] }
+static isl::map computeScalarReachingDefinition(isl::union_map Schedule,
+                                                isl::set Writes, bool InclDef,
+                                                bool InclRedef) {
+  isl::space DomainSpace = Writes.get_space();
+  isl::space ScatterSpace = getScatterSpace(Schedule);
+
+  //  { Scatter[] -> DomainWrite[] }
+  isl::union_map UMap = computeScalarReachingDefinition(
+      Schedule, isl::union_set(Writes), InclDef, InclRedef);
+
+  isl::space ResultSpace = ScatterSpace.map_from_domain_and_range(DomainSpace);
+  return singleton(UMap, ResultSpace);
+}
+
+isl::union_map polly::makeUnknownForDomain(isl::union_set Domain) {
+  return give(isl_union_map_from_domain(Domain.take()));
+}
+
+/// Create a domain-to-unknown value mapping.
+///
+/// @see makeUnknownForDomain(isl::union_set)
+///
+/// @param Domain { Domain[] }
+///
+/// @return { Domain[] -> ValInst[] }
+static isl::map makeUnknownForDomain(isl::set Domain) {
+  return give(isl_map_from_domain(Domain.take()));
+}
+
+/// Return whether @p Map maps to an unknown value.
+///
+/// @param { [] -> ValInst[] }
+static bool isMapToUnknown(const isl::map &Map) {
+  isl::space Space = Map.get_space().range();
+  return Space.has_tuple_id(isl::dim::set).is_false() &&
+         Space.is_wrapping().is_false() && Space.dim(isl::dim::set) == 0;
+}
+
+isl::union_map polly::filterKnownValInst(const isl::union_map &UMap) {
+  isl::union_map Result = isl::union_map::empty(UMap.get_space());
+  isl::stat Success = UMap.foreach_map([=, &Result](isl::map Map) -> isl::stat {
+    if (!isMapToUnknown(Map))
+      Result = Result.add_map(Map);
+    return isl::stat::ok;
+  });
+  if (Success != isl::stat::ok)
+    return {};
+  return Result;
+}
+
+ZoneAlgorithm::ZoneAlgorithm(const char *PassName, Scop *S, LoopInfo *LI)
+    : PassName(PassName), IslCtx(S->getSharedIslCtx()), S(S), LI(LI),
+      Schedule(S->getSchedule()) {
+  auto Domains = S->getDomains();
+
+  Schedule =
+      give(isl_union_map_intersect_domain(Schedule.take(), Domains.take()));
+  ParamSpace = give(isl_union_map_get_space(Schedule.keep()));
+  ScatterSpace = getScatterSpace(Schedule);
+}
+
+/// Check if all stores in @p Stmt store the very same value.
+///
+/// This covers a special situation occurring in Polybench's
+/// covariance/correlation (which is typical for algorithms that cover symmetric
+/// matrices):
+///
+/// for (int i = 0; i < n; i += 1)
+/// 	for (int j = 0; j <= i; j += 1) {
+/// 		double x = ...;
+/// 		C[i][j] = x;
+/// 		C[j][i] = x;
+/// 	}
+///
+/// For i == j, the same value is written twice to the same element.Double
+/// writes to the same element are not allowed in DeLICM because its algorithm
+/// does not see which of the writes is effective.But if its the same value
+/// anyway, it doesn't matter.
+///
+/// LLVM passes, however, cannot simplify this because the write is necessary
+/// for i != j (unless it would add a condition for one of the writes to occur
+/// only if i != j).
+///
+/// TODO: In the future we may want to extent this to make the checks
+///       specific to different memory locations.
+static bool onlySameValueWrites(ScopStmt *Stmt) {
+  Value *V = nullptr;
+
+  for (auto *MA : *Stmt) {
+    if (!MA->isLatestArrayKind() || !MA->isMustWrite() ||
+        !MA->isOriginalArrayKind())
+      continue;
+
+    if (!V) {
+      V = MA->getAccessValue();
+      continue;
+    }
+
+    if (V != MA->getAccessValue())
+      return false;
+  }
+  return true;
+}
+
+void ZoneAlgorithm::collectIncompatibleElts(ScopStmt *Stmt,
+                                            isl::union_set &IncompatibleElts,
+                                            isl::union_set &AllElts) {
+  auto Stores = makeEmptyUnionMap();
+  auto Loads = makeEmptyUnionMap();
+
+  // This assumes that the MemoryKind::Array MemoryAccesses are iterated in
+  // order.
+  for (auto *MA : *Stmt) {
+    if (!MA->isOriginalArrayKind())
+      continue;
+
+    isl::map AccRelMap = getAccessRelationFor(MA);
+    isl::union_map AccRel = AccRelMap;
+
+    // To avoid solving any ILP problems, always add entire arrays instead of
+    // just the elements that are accessed.
+    auto ArrayElts = isl::set::universe(AccRelMap.get_space().range());
+    AllElts = AllElts.add_set(ArrayElts);
+
+    if (MA->isRead()) {
+      // Reject load after store to same location.
+      if (!isl_union_map_is_disjoint(Stores.keep(), AccRel.keep())) {
+        DEBUG(dbgs() << "Load after store of same element in same statement\n");
+        OptimizationRemarkMissed R(PassName, "LoadAfterStore",
+                                   MA->getAccessInstruction());
+        R << "load after store of same element in same statement";
+        R << " (previous stores: " << Stores;
+        R << ", loading: " << AccRel << ")";
+        S->getFunction().getContext().diagnose(R);
+
+        IncompatibleElts = IncompatibleElts.add_set(ArrayElts);
+      }
+
+      Loads = give(isl_union_map_union(Loads.take(), AccRel.take()));
+
+      continue;
+    }
+
+    // In region statements the order is less clear, eg. the load and store
+    // might be in a boxed loop.
+    if (Stmt->isRegionStmt() &&
+        !isl_union_map_is_disjoint(Loads.keep(), AccRel.keep())) {
+      DEBUG(dbgs() << "WRITE in non-affine subregion not supported\n");
+      OptimizationRemarkMissed R(PassName, "StoreInSubregion",
+                                 MA->getAccessInstruction());
+      R << "store is in a non-affine subregion";
+      S->getFunction().getContext().diagnose(R);
+
+      IncompatibleElts = IncompatibleElts.add_set(ArrayElts);
+    }
+
+    // Do not allow more than one store to the same location.
+    if (!isl_union_map_is_disjoint(Stores.keep(), AccRel.keep()) &&
+        !onlySameValueWrites(Stmt)) {
+      DEBUG(dbgs() << "WRITE after WRITE to same element\n");
+      OptimizationRemarkMissed R(PassName, "StoreAfterStore",
+                                 MA->getAccessInstruction());
+      R << "store after store of same element in same statement";
+      R << " (previous stores: " << Stores;
+      R << ", storing: " << AccRel << ")";
+      S->getFunction().getContext().diagnose(R);
+
+      IncompatibleElts = IncompatibleElts.add_set(ArrayElts);
+    }
+
+    Stores = give(isl_union_map_union(Stores.take(), AccRel.take()));
+  }
+}
+
+void ZoneAlgorithm::addArrayReadAccess(MemoryAccess *MA) {
+  assert(MA->isLatestArrayKind());
+  assert(MA->isRead());
+  ScopStmt *Stmt = MA->getStatement();
+
+  // { DomainRead[] -> Element[] }
+  auto AccRel = intersectRange(getAccessRelationFor(MA), CompatibleElts);
+  AllReads = give(isl_union_map_add_map(AllReads.take(), AccRel.copy()));
+
+  if (LoadInst *Load = dyn_cast_or_null<LoadInst>(MA->getAccessInstruction())) {
+    // { DomainRead[] -> ValInst[] }
+    isl::map LoadValInst = makeValInst(
+        Load, Stmt, LI->getLoopFor(Load->getParent()), Stmt->isBlockStmt());
+
+    // { DomainRead[] -> [Element[] -> DomainRead[]] }
+    isl::map IncludeElement =
+        give(isl_map_curry(isl_map_domain_map(AccRel.take())));
+
+    // { [Element[] -> DomainRead[]] -> ValInst[] }
+    isl::map EltLoadValInst =
+        give(isl_map_apply_domain(LoadValInst.take(), IncludeElement.take()));
+
+    AllReadValInst = give(
+        isl_union_map_add_map(AllReadValInst.take(), EltLoadValInst.take()));
+  }
+}
+
+isl::union_map ZoneAlgorithm::getWrittenValue(MemoryAccess *MA,
+                                              isl::map AccRel) {
+  if (!MA->isMustWrite())
+    return {};
+
+  Value *AccVal = MA->getAccessValue();
+  ScopStmt *Stmt = MA->getStatement();
+  Instruction *AccInst = MA->getAccessInstruction();
+
+  // Write a value to a single element.
+  auto L = MA->isOriginalArrayKind() ? LI->getLoopFor(AccInst->getParent())
+                                     : Stmt->getSurroundingLoop();
+  if (AccVal &&
+      AccVal->getType() == MA->getLatestScopArrayInfo()->getElementType() &&
+      AccRel.is_single_valued().is_true())
+    return makeNormalizedValInst(AccVal, Stmt, L);
+
+  // memset(_, '0', ) is equivalent to writing the null value to all touched
+  // elements. isMustWrite() ensures that all of an element's bytes are
+  // overwritten.
+  if (auto *Memset = dyn_cast<MemSetInst>(AccInst)) {
+    auto *WrittenConstant = dyn_cast<Constant>(Memset->getValue());
+    Type *Ty = MA->getLatestScopArrayInfo()->getElementType();
+    if (WrittenConstant && WrittenConstant->isZeroValue()) {
+      Constant *Zero = Constant::getNullValue(Ty);
+      return makeNormalizedValInst(Zero, Stmt, L);
+    }
+  }
+
+  return {};
+}
+
+void ZoneAlgorithm::addArrayWriteAccess(MemoryAccess *MA) {
+  assert(MA->isLatestArrayKind());
+  assert(MA->isWrite());
+  auto *Stmt = MA->getStatement();
+
+  // { Domain[] -> Element[] }
+  isl::map AccRel = intersectRange(getAccessRelationFor(MA), CompatibleElts);
+
+  if (MA->isMustWrite())
+    AllMustWrites = AllMustWrites.add_map(AccRel);
+
+  if (MA->isMayWrite())
+    AllMayWrites = AllMayWrites.add_map(AccRel);
+
+  // { Domain[] -> ValInst[] }
+  isl::union_map WriteValInstance = getWrittenValue(MA, AccRel);
+  if (!WriteValInstance)
+    WriteValInstance = makeUnknownForDomain(Stmt);
+
+  // { Domain[] -> [Element[] -> Domain[]] }
+  isl::map IncludeElement = AccRel.domain_map().curry();
+
+  // { [Element[] -> DomainWrite[]] -> ValInst[] }
+  isl::union_map EltWriteValInst =
+      WriteValInstance.apply_domain(IncludeElement);
+
+  AllWriteValInst = AllWriteValInst.unite(EltWriteValInst);
+}
+
+/// Return whether @p PHI refers (also transitively through other PHIs) to
+/// itself.
+///
+/// loop:
+///   %phi1 = phi [0, %preheader], [%phi1, %loop]
+///   br i1 %c, label %loop, label %exit
+///
+/// exit:
+///   %phi2 = phi [%phi1, %bb]
+///
+/// In this example, %phi1 is recursive, but %phi2 is not.
+static bool isRecursivePHI(const PHINode *PHI) {
+  SmallVector<const PHINode *, 8> Worklist;
+  SmallPtrSet<const PHINode *, 8> Visited;
+  Worklist.push_back(PHI);
+
+  while (!Worklist.empty()) {
+    const PHINode *Cur = Worklist.pop_back_val();
+
+    if (Visited.count(Cur))
+      continue;
+    Visited.insert(Cur);
+
+    for (const Use &Incoming : Cur->incoming_values()) {
+      Value *IncomingVal = Incoming.get();
+      auto *IncomingPHI = dyn_cast<PHINode>(IncomingVal);
+      if (!IncomingPHI)
+        continue;
+
+      if (IncomingPHI == PHI)
+        return true;
+      Worklist.push_back(IncomingPHI);
+    }
+  }
+  return false;
+}
+
+isl::union_map ZoneAlgorithm::computePerPHI(const ScopArrayInfo *SAI) {
+  // TODO: If the PHI has an incoming block from before the SCoP, it is not
+  // represented in any ScopStmt.
+
+  auto *PHI = cast<PHINode>(SAI->getBasePtr());
+  auto It = PerPHIMaps.find(PHI);
+  if (It != PerPHIMaps.end())
+    return It->second;
+
+  assert(SAI->isPHIKind());
+
+  // { DomainPHIWrite[] -> Scatter[] }
+  isl::union_map PHIWriteScatter = makeEmptyUnionMap();
+
+  // Collect all incoming block timepoints.
+  for (MemoryAccess *MA : S->getPHIIncomings(SAI)) {
+    isl::map Scatter = getScatterFor(MA);
+    PHIWriteScatter = PHIWriteScatter.add_map(Scatter);
+  }
+
+  // { DomainPHIRead[] -> Scatter[] }
+  isl::map PHIReadScatter = getScatterFor(S->getPHIRead(SAI));
+
+  // { DomainPHIRead[] -> Scatter[] }
+  isl::map BeforeRead = beforeScatter(PHIReadScatter, true);
+
+  // { Scatter[] }
+  isl::set WriteTimes = singleton(PHIWriteScatter.range(), ScatterSpace);
+
+  // { DomainPHIRead[] -> Scatter[] }
+  isl::map PHIWriteTimes = BeforeRead.intersect_range(WriteTimes);
+  isl::map LastPerPHIWrites = PHIWriteTimes.lexmax();
+
+  // { DomainPHIRead[] -> DomainPHIWrite[] }
+  isl::union_map Result =
+      isl::union_map(LastPerPHIWrites).apply_range(PHIWriteScatter.reverse());
+  assert(!Result.is_single_valued().is_false());
+  assert(!Result.is_injective().is_false());
+
+  PerPHIMaps.insert({PHI, Result});
+  return Result;
+}
+
+isl::union_set ZoneAlgorithm::makeEmptyUnionSet() const {
+  return give(isl_union_set_empty(ParamSpace.copy()));
+}
+
+isl::union_map ZoneAlgorithm::makeEmptyUnionMap() const {
+  return give(isl_union_map_empty(ParamSpace.copy()));
+}
+
+void ZoneAlgorithm::collectCompatibleElts() {
+  // First find all the incompatible elements, then take the complement.
+  // We compile the list of compatible (rather than incompatible) elements so
+  // users can intersect with the list, not requiring a subtract operation. It
+  // also allows us to define a 'universe' of all elements and makes it more
+  // explicit in which array elements can be used.
+  isl::union_set AllElts = makeEmptyUnionSet();
+  isl::union_set IncompatibleElts = makeEmptyUnionSet();
+
+  for (auto &Stmt : *S)
+    collectIncompatibleElts(&Stmt, IncompatibleElts, AllElts);
+
+  NumIncompatibleArrays += isl_union_set_n_set(IncompatibleElts.keep());
+  CompatibleElts = AllElts.subtract(IncompatibleElts);
+  NumCompatibleArrays += isl_union_set_n_set(CompatibleElts.keep());
+}
+
+isl::map ZoneAlgorithm::getScatterFor(ScopStmt *Stmt) const {
+  isl::space ResultSpace = give(isl_space_map_from_domain_and_range(
+      Stmt->getDomainSpace().release(), ScatterSpace.copy()));
+  return give(isl_union_map_extract_map(Schedule.keep(), ResultSpace.take()));
+}
+
+isl::map ZoneAlgorithm::getScatterFor(MemoryAccess *MA) const {
+  return getScatterFor(MA->getStatement());
+}
+
+isl::union_map ZoneAlgorithm::getScatterFor(isl::union_set Domain) const {
+  return give(isl_union_map_intersect_domain(Schedule.copy(), Domain.take()));
+}
+
+isl::map ZoneAlgorithm::getScatterFor(isl::set Domain) const {
+  auto ResultSpace = give(isl_space_map_from_domain_and_range(
+      isl_set_get_space(Domain.keep()), ScatterSpace.copy()));
+  auto UDomain = give(isl_union_set_from_set(Domain.copy()));
+  auto UResult = getScatterFor(std::move(UDomain));
+  auto Result = singleton(std::move(UResult), std::move(ResultSpace));
+  assert(!Result || isl_set_is_equal(give(isl_map_domain(Result.copy())).keep(),
+                                     Domain.keep()) == isl_bool_true);
+  return Result;
+}
+
+isl::set ZoneAlgorithm::getDomainFor(ScopStmt *Stmt) const {
+  return Stmt->getDomain().remove_redundancies();
+}
+
+isl::set ZoneAlgorithm::getDomainFor(MemoryAccess *MA) const {
+  return getDomainFor(MA->getStatement());
+}
+
+isl::map ZoneAlgorithm::getAccessRelationFor(MemoryAccess *MA) const {
+  auto Domain = getDomainFor(MA);
+  auto AccRel = MA->getLatestAccessRelation();
+  return give(isl_map_intersect_domain(AccRel.take(), Domain.take()));
+}
+
+isl::map ZoneAlgorithm::getScalarReachingDefinition(ScopStmt *Stmt) {
+  auto &Result = ScalarReachDefZone[Stmt];
+  if (Result)
+    return Result;
+
+  auto Domain = getDomainFor(Stmt);
+  Result = computeScalarReachingDefinition(Schedule, Domain, false, true);
+  simplify(Result);
+
+  return Result;
+}
+
+isl::map ZoneAlgorithm::getScalarReachingDefinition(isl::set DomainDef) {
+  auto DomId = give(isl_set_get_tuple_id(DomainDef.keep()));
+  auto *Stmt = static_cast<ScopStmt *>(isl_id_get_user(DomId.keep()));
+
+  auto StmtResult = getScalarReachingDefinition(Stmt);
+
+  return give(isl_map_intersect_range(StmtResult.take(), DomainDef.take()));
+}
+
+isl::map ZoneAlgorithm::makeUnknownForDomain(ScopStmt *Stmt) const {
+  return ::makeUnknownForDomain(getDomainFor(Stmt));
+}
+
+isl::id ZoneAlgorithm::makeValueId(Value *V) {
+  if (!V)
+    return nullptr;
+
+  auto &Id = ValueIds[V];
+  if (Id.is_null()) {
+    auto Name = getIslCompatibleName("Val_", V, ValueIds.size() - 1,
+                                     std::string(), UseInstructionNames);
+    Id = give(isl_id_alloc(IslCtx.get(), Name.c_str(), V));
+  }
+  return Id;
+}
+
+isl::space ZoneAlgorithm::makeValueSpace(Value *V) {
+  auto Result = give(isl_space_set_from_params(ParamSpace.copy()));
+  return give(isl_space_set_tuple_id(Result.take(), isl_dim_set,
+                                     makeValueId(V).take()));
+}
+
+isl::set ZoneAlgorithm::makeValueSet(Value *V) {
+  auto Space = makeValueSpace(V);
+  return give(isl_set_universe(Space.take()));
+}
+
+isl::map ZoneAlgorithm::makeValInst(Value *Val, ScopStmt *UserStmt, Loop *Scope,
+                                    bool IsCertain) {
+  // If the definition/write is conditional, the value at the location could
+  // be either the written value or the old value. Since we cannot know which
+  // one, consider the value to be unknown.
+  if (!IsCertain)
+    return makeUnknownForDomain(UserStmt);
+
+  auto DomainUse = getDomainFor(UserStmt);
+  auto VUse = VirtualUse::create(S, UserStmt, Scope, Val, true);
+  switch (VUse.getKind()) {
+  case VirtualUse::Constant:
+  case VirtualUse::Block:
+  case VirtualUse::Hoisted:
+  case VirtualUse::ReadOnly: {
+    // The definition does not depend on the statement which uses it.
+    auto ValSet = makeValueSet(Val);
+    return give(isl_map_from_domain_and_range(DomainUse.take(), ValSet.take()));
+  }
+
+  case VirtualUse::Synthesizable: {
+    auto *ScevExpr = VUse.getScevExpr();
+    auto UseDomainSpace = give(isl_set_get_space(DomainUse.keep()));
+
+    // Construct the SCEV space.
+    // TODO: Add only the induction variables referenced in SCEVAddRecExpr
+    // expressions, not just all of them.
+    auto ScevId = give(isl_id_alloc(UseDomainSpace.get_ctx().get(), nullptr,
+                                    const_cast<SCEV *>(ScevExpr)));
+    auto ScevSpace =
+        give(isl_space_drop_dims(UseDomainSpace.copy(), isl_dim_set, 0, 0));
+    ScevSpace = give(
+        isl_space_set_tuple_id(ScevSpace.take(), isl_dim_set, ScevId.copy()));
+
+    // { DomainUse[] -> ScevExpr[] }
+    auto ValInst = give(isl_map_identity(isl_space_map_from_domain_and_range(
+        UseDomainSpace.copy(), ScevSpace.copy())));
+    return ValInst;
+  }
+
+  case VirtualUse::Intra: {
+    // Definition and use is in the same statement. We do not need to compute
+    // a reaching definition.
+
+    // { llvm::Value }
+    auto ValSet = makeValueSet(Val);
+
+    // {  UserDomain[] -> llvm::Value }
+    auto ValInstSet =
+        give(isl_map_from_domain_and_range(DomainUse.take(), ValSet.take()));
+
+    // { UserDomain[] -> [UserDomain[] - >llvm::Value] }
+    auto Result = give(isl_map_reverse(isl_map_domain_map(ValInstSet.take())));
+    simplify(Result);
+    return Result;
+  }
+
+  case VirtualUse::Inter: {
+    // The value is defined in a different statement.
+
+    auto *Inst = cast<Instruction>(Val);
+    auto *ValStmt = S->getStmtFor(Inst);
+
+    // If the llvm::Value is defined in a removed Stmt, we cannot derive its
+    // domain. We could use an arbitrary statement, but this could result in
+    // different ValInst[] for the same llvm::Value.
+    if (!ValStmt)
+      return ::makeUnknownForDomain(DomainUse);
+
+    // { DomainDef[] }
+    auto DomainDef = getDomainFor(ValStmt);
+
+    // { Scatter[] -> DomainDef[] }
+    auto ReachDef = getScalarReachingDefinition(DomainDef);
+
+    // { DomainUse[] -> Scatter[] }
+    auto UserSched = getScatterFor(DomainUse);
+
+    // { DomainUse[] -> DomainDef[] }
+    auto UsedInstance =
+        give(isl_map_apply_range(UserSched.take(), ReachDef.take()));
+
+    // { llvm::Value }
+    auto ValSet = makeValueSet(Val);
+
+    // { DomainUse[] -> llvm::Value[] }
+    auto ValInstSet =
+        give(isl_map_from_domain_and_range(DomainUse.take(), ValSet.take()));
+
+    // { DomainUse[] -> [DomainDef[] -> llvm::Value]  }
+    auto Result =
+        give(isl_map_range_product(UsedInstance.take(), ValInstSet.take()));
+
+    simplify(Result);
+    return Result;
+  }
+  }
+  llvm_unreachable("Unhandled use type");
+}
+
+/// Remove all computed PHIs out of @p Input and replace by their incoming
+/// value.
+///
+/// @param Input        { [] -> ValInst[] }
+/// @param ComputedPHIs Set of PHIs that are replaced. Its ValInst must appear
+///                     on the LHS of @p NormalizeMap.
+/// @param NormalizeMap { ValInst[] -> ValInst[] }
+static isl::union_map normalizeValInst(isl::union_map Input,
+                                       const DenseSet<PHINode *> &ComputedPHIs,
+                                       isl::union_map NormalizeMap) {
+  isl::union_map Result = isl::union_map::empty(Input.get_space());
+  Input.foreach_map(
+      [&Result, &ComputedPHIs, &NormalizeMap](isl::map Map) -> isl::stat {
+        isl::space Space = Map.get_space();
+        isl::space RangeSpace = Space.range();
+
+        // Instructions within the SCoP are always wrapped. Non-wrapped tuples
+        // are therefore invariant in the SCoP and don't need normalization.
+        if (!RangeSpace.is_wrapping()) {
+          Result = Result.add_map(Map);
+          return isl::stat::ok;
+        }
+
+        auto *PHI = dyn_cast<PHINode>(static_cast<Value *>(
+            RangeSpace.unwrap().get_tuple_id(isl::dim::out).get_user()));
+
+        // If no normalization is necessary, then the ValInst stands for itself.
+        if (!ComputedPHIs.count(PHI)) {
+          Result = Result.add_map(Map);
+          return isl::stat::ok;
+        }
+
+        // Otherwise, apply the normalization.
+        isl::union_map Mapped = isl::union_map(Map).apply_range(NormalizeMap);
+        Result = Result.unite(Mapped);
+        NumPHINormialization++;
+        return isl::stat::ok;
+      });
+  return Result;
+}
+
+isl::union_map ZoneAlgorithm::makeNormalizedValInst(llvm::Value *Val,
+                                                    ScopStmt *UserStmt,
+                                                    llvm::Loop *Scope,
+                                                    bool IsCertain) {
+  isl::map ValInst = makeValInst(Val, UserStmt, Scope, IsCertain);
+  isl::union_map Normalized =
+      normalizeValInst(ValInst, ComputedPHIs, NormalizeMap);
+  return Normalized;
+}
+
+bool ZoneAlgorithm::isCompatibleAccess(MemoryAccess *MA) {
+  if (!MA)
+    return false;
+  if (!MA->isLatestArrayKind())
+    return false;
+  Instruction *AccInst = MA->getAccessInstruction();
+  return isa<StoreInst>(AccInst) || isa<LoadInst>(AccInst);
+}
+
+bool ZoneAlgorithm::isNormalizable(MemoryAccess *MA) {
+  assert(MA->isRead());
+
+  // Exclude ExitPHIs, we are assuming that a normalizable PHI has a READ
+  // MemoryAccess.
+  if (!MA->isOriginalPHIKind())
+    return false;
+
+  // Exclude recursive PHIs, normalizing them would require a transitive
+  // closure.
+  auto *PHI = cast<PHINode>(MA->getAccessInstruction());
+  if (RecursivePHIs.count(PHI))
+    return false;
+
+  // Ensure that each incoming value can be represented by a ValInst[].
+  // We do represent values from statements associated to multiple incoming
+  // value by the PHI itself, but we do not handle this case yet (especially
+  // isNormalized()) when normalizing.
+  const ScopArrayInfo *SAI = MA->getOriginalScopArrayInfo();
+  auto Incomings = S->getPHIIncomings(SAI);
+  for (MemoryAccess *Incoming : Incomings) {
+    if (Incoming->getIncoming().size() != 1)
+      return false;
+  }
+
+  return true;
+}
+
+bool ZoneAlgorithm::isNormalized(isl::map Map) {
+  isl::space Space = Map.get_space();
+  isl::space RangeSpace = Space.range();
+
+  if (!RangeSpace.is_wrapping())
+    return true;
+
+  auto *PHI = dyn_cast<PHINode>(static_cast<Value *>(
+      RangeSpace.unwrap().get_tuple_id(isl::dim::out).get_user()));
+  if (!PHI)
+    return true;
+
+  auto *IncomingStmt = static_cast<ScopStmt *>(
+      RangeSpace.unwrap().get_tuple_id(isl::dim::in).get_user());
+  MemoryAccess *PHIRead = IncomingStmt->lookupPHIReadOf(PHI);
+  if (!isNormalizable(PHIRead))
+    return true;
+
+  return false;
+}
+
+bool ZoneAlgorithm::isNormalized(isl::union_map UMap) {
+  auto Result = UMap.foreach_map([this](isl::map Map) -> isl::stat {
+    if (isNormalized(Map))
+      return isl::stat::ok;
+    return isl::stat::error;
+  });
+  return Result == isl::stat::ok;
+}
+
+void ZoneAlgorithm::computeCommon() {
+  AllReads = makeEmptyUnionMap();
+  AllMayWrites = makeEmptyUnionMap();
+  AllMustWrites = makeEmptyUnionMap();
+  AllWriteValInst = makeEmptyUnionMap();
+  AllReadValInst = makeEmptyUnionMap();
+
+  // Default to empty, i.e. no normalization/replacement is taking place. Call
+  // computeNormalizedPHIs() to initialize.
+  NormalizeMap = makeEmptyUnionMap();
+  ComputedPHIs.clear();
+
+  for (auto &Stmt : *S) {
+    for (auto *MA : Stmt) {
+      if (!MA->isLatestArrayKind())
+        continue;
+
+      if (MA->isRead())
+        addArrayReadAccess(MA);
+
+      if (MA->isWrite())
+        addArrayWriteAccess(MA);
+    }
+  }
+
+  // { DomainWrite[] -> Element[] }
+  AllWrites =
+      give(isl_union_map_union(AllMustWrites.copy(), AllMayWrites.copy()));
+
+  // { [Element[] -> Zone[]] -> DomainWrite[] }
+  WriteReachDefZone =
+      computeReachingDefinition(Schedule, AllWrites, false, true);
+  simplify(WriteReachDefZone);
+}
+
+void ZoneAlgorithm::computeNormalizedPHIs() {
+  // Determine which PHIs can reference themselves. They are excluded from
+  // normalization to avoid problems with transitive closures.
+  for (ScopStmt &Stmt : *S) {
+    for (MemoryAccess *MA : Stmt) {
+      if (!MA->isPHIKind())
+        continue;
+      if (!MA->isRead())
+        continue;
+
+      // TODO: Can be more efficient since isRecursivePHI can theoretically
+      // determine recursiveness for multiple values and/or cache results.
+      auto *PHI = cast<PHINode>(MA->getAccessInstruction());
+      if (isRecursivePHI(PHI)) {
+        NumRecursivePHIs++;
+        RecursivePHIs.insert(PHI);
+      }
+    }
+  }
+
+  // { PHIValInst[] -> IncomingValInst[] }
+  isl::union_map AllPHIMaps = makeEmptyUnionMap();
+
+  // Discover new PHIs and try to normalize them.
+  DenseSet<PHINode *> AllPHIs;
+  for (ScopStmt &Stmt : *S) {
+    for (MemoryAccess *MA : Stmt) {
+      if (!MA->isOriginalPHIKind())
+        continue;
+      if (!MA->isRead())
+        continue;
+      if (!isNormalizable(MA))
+        continue;
+
+      auto *PHI = cast<PHINode>(MA->getAccessInstruction());
+      const ScopArrayInfo *SAI = MA->getOriginalScopArrayInfo();
+
+      // { PHIDomain[] -> PHIValInst[] }
+      isl::map PHIValInst = makeValInst(PHI, &Stmt, Stmt.getSurroundingLoop());
+
+      // { IncomingDomain[] -> IncomingValInst[] }
+      isl::union_map IncomingValInsts = makeEmptyUnionMap();
+
+      // Get all incoming values.
+      for (MemoryAccess *MA : S->getPHIIncomings(SAI)) {
+        ScopStmt *IncomingStmt = MA->getStatement();
+
+        auto Incoming = MA->getIncoming();
+        assert(Incoming.size() == 1 && "The incoming value must be "
+                                       "representable by something else than "
+                                       "the PHI itself");
+        Value *IncomingVal = Incoming[0].second;
+
+        // { IncomingDomain[] -> IncomingValInst[] }
+        isl::map IncomingValInst = makeValInst(
+            IncomingVal, IncomingStmt, IncomingStmt->getSurroundingLoop());
+
+        IncomingValInsts = IncomingValInsts.add_map(IncomingValInst);
+      }
+
+      // Determine which instance of the PHI statement corresponds to which
+      // incoming value.
+      // { PHIDomain[] -> IncomingDomain[] }
+      isl::union_map PerPHI = computePerPHI(SAI);
+
+      // { PHIValInst[] -> IncomingValInst[] }
+      isl::union_map PHIMap =
+          PerPHI.apply_domain(PHIValInst).apply_range(IncomingValInsts);
+      assert(!PHIMap.is_single_valued().is_false());
+
+      // Resolve transitiveness: The incoming value of the newly discovered PHI
+      // may reference a previously normalized PHI. At the same time, already
+      // normalized PHIs might be normalized to the new PHI. At the end, none of
+      // the PHIs may appear on the right-hand-side of the normalization map.
+      PHIMap = normalizeValInst(PHIMap, AllPHIs, AllPHIMaps);
+      AllPHIs.insert(PHI);
+      AllPHIMaps = normalizeValInst(AllPHIMaps, AllPHIs, PHIMap);
+
+      AllPHIMaps = AllPHIMaps.unite(PHIMap);
+      NumNormalizablePHIs++;
+    }
+  }
+  simplify(AllPHIMaps);
+
+  // Apply the normalization.
+  ComputedPHIs = AllPHIs;
+  NormalizeMap = AllPHIMaps;
+
+  assert(!NormalizeMap || isNormalized(NormalizeMap));
+}
+
+void ZoneAlgorithm::printAccesses(llvm::raw_ostream &OS, int Indent) const {
+  OS.indent(Indent) << "After accesses {\n";
+  for (auto &Stmt : *S) {
+    OS.indent(Indent + 4) << Stmt.getBaseName() << "\n";
+    for (auto *MA : Stmt)
+      MA->print(OS);
+  }
+  OS.indent(Indent) << "}\n";
+}
+
+isl::union_map ZoneAlgorithm::computeKnownFromMustWrites() const {
+  // { [Element[] -> Zone[]] -> [Element[] -> DomainWrite[]] }
+  isl::union_map EltReachdDef = distributeDomain(WriteReachDefZone.curry());
+
+  // { [Element[] -> DomainWrite[]] -> ValInst[] }
+  isl::union_map AllKnownWriteValInst = filterKnownValInst(AllWriteValInst);
+
+  // { [Element[] -> Zone[]] -> ValInst[] }
+  return EltReachdDef.apply_range(AllKnownWriteValInst);
+}
+
+isl::union_map ZoneAlgorithm::computeKnownFromLoad() const {
+  // { Element[] }
+  isl::union_set AllAccessedElts = AllReads.range().unite(AllWrites.range());
+
+  // { Element[] -> Scatter[] }
+  isl::union_map EltZoneUniverse = isl::union_map::from_domain_and_range(
+      AllAccessedElts, isl::set::universe(ScatterSpace));
+
+  // This assumes there are no "holes" in
+  // isl_union_map_domain(WriteReachDefZone); alternatively, compute the zone
+  // before the first write or that are not written at all.
+  // { Element[] -> Scatter[] }
+  isl::union_set NonReachDef =
+      EltZoneUniverse.wrap().subtract(WriteReachDefZone.domain());
+
+  // { [Element[] -> Zone[]] -> ReachDefId[] }
+  isl::union_map DefZone =
+      WriteReachDefZone.unite(isl::union_map::from_domain(NonReachDef));
+
+  // { [Element[] -> Scatter[]] -> Element[] }
+  isl::union_map EltZoneElt = EltZoneUniverse.domain_map();
+
+  // { [Element[] -> Zone[]] -> [Element[] -> ReachDefId[]] }
+  isl::union_map DefZoneEltDefId = EltZoneElt.range_product(DefZone);
+
+  // { Element[] -> [Zone[] -> ReachDefId[]] }
+  isl::union_map EltDefZone = DefZone.curry();
+
+  // { [Element[] -> Zone[] -> [Element[] -> ReachDefId[]] }
+  isl::union_map EltZoneEltDefid = distributeDomain(EltDefZone);
+
+  // { [Element[] -> Scatter[]] -> DomainRead[] }
+  isl::union_map Reads = AllReads.range_product(Schedule).reverse();
+
+  // { [Element[] -> Scatter[]] -> [Element[] -> DomainRead[]] }
+  isl::union_map ReadsElt = EltZoneElt.range_product(Reads);
+
+  // { [Element[] -> Scatter[]] -> ValInst[] }
+  isl::union_map ScatterKnown = ReadsElt.apply_range(AllReadValInst);
+
+  // { [Element[] -> ReachDefId[]] -> ValInst[] }
+  isl::union_map DefidKnown =
+      DefZoneEltDefId.apply_domain(ScatterKnown).reverse();
+
+  // { [Element[] -> Zone[]] -> ValInst[] }
+  return DefZoneEltDefId.apply_range(DefidKnown);
+}
+
+isl::union_map ZoneAlgorithm::computeKnown(bool FromWrite,
+                                           bool FromRead) const {
+  isl::union_map Result = makeEmptyUnionMap();
+
+  if (FromWrite)
+    Result = Result.unite(computeKnownFromMustWrites());
+
+  if (FromRead)
+    Result = Result.unite(computeKnownFromLoad());
+
+  simplify(Result);
+  return Result;
+}
diff --git a/final/test/CMakeLists.txt b/final/test/CMakeLists.txt
new file mode 100644
index 0000000..0cc33c3
--- /dev/null
+++ b/final/test/CMakeLists.txt
@@ -0,0 +1,112 @@
+set(LLVM_SHLIBEXT "${CMAKE_SHARED_MODULE_SUFFIX}")
+
+add_custom_target(check-polly)
+set_target_properties(check-polly PROPERTIES FOLDER "Polly")
+
+if(NOT LLVM_MAIN_SRC_DIR)
+  find_program(LLVM_OPT NAMES opt HINTS ${LLVM_TOOLS_BINARY_DIR})
+  find_program(LLVM_FILECHECK NAMES FileCheck HINTS ${LLVM_TOOLS_BINARY_DIR})
+  find_program(LLVM_NOT NAMES not HINTS ${LLVM_TOOLS_BINARY_DIR})
+  if (NOT LLVM_OPT)
+    message(WARNING "LLVM's opt program could not be found. Please set LLVM_OPT.")
+  endif()
+  if (NOT LLVM_FILECHECK)
+    message(WARNING "LLVM's FileCheck program could not be found. "
+      "Please set LLVM_FILECHECK. Please set LLVM_FILECHECK.")
+  endif()
+  if (NOT LLVM_NOT)
+    message(WARNING "LLVM's not program could not be found. Please set LLVM_NOT.")
+  endif()
+  get_filename_component(EXTRA_PATHS ${LLVM_OPT} DIRECTORY)
+  list(APPEND POLLY_TEST_EXTRA_PATHS "${EXTRA_PATHS}")
+  get_filename_component(EXTRA_PATHS ${LLVM_FILECHECK} DIRECTORY)
+  list(APPEND POLLY_TEST_EXTRA_PATHS "${EXTRA_PATHS}")
+  get_filename_component(EXTRA_PATHS ${LLVM_NOT} DIRECTORY)
+  list(APPEND POLLY_TEST_EXTRA_PATHS "${EXTRA_PATHS}")
+  list(REMOVE_DUPLICATES POLLY_TEST_EXTRA_PATHS)
+  message(STATUS "Extra paths: ${POLLY_TEST_EXTRA_PATHS}")
+  if ("${POLLY_TEST_EXTRA_PATHS}" STREQUAL "${LLVM_TOOLS_BINARY_DIR}")
+    set(POLLY_TEST_EXTRA_PATHS "")
+  endif()
+  set(POLLY_TEST_DEPS LLVMPolly)
+else ()
+  set(LLVM_OPT "${LLVM_TOOLS_BINARY_DIR}/opt")
+  set(LLVM_FILECHECK "${LLVM_TOOLS_BINARY_DIR}/FileCheck")
+  set(LLVM_NOT "${LLVM_TOOLS_BINARY_DIR}/not")
+  set(POLLY_TEST_EXTRA_PATHS "")
+  set(POLLY_TEST_DEPS llvm-config opt LLVMPolly FileCheck not)
+endif()
+
+if (POLLY_BUNDLED_ISL)
+  list(APPEND POLLY_TEST_DEPS polly-isl-test)
+endif()
+if (POLLY_GTEST_AVAIL)
+  list(APPEND POLLY_TEST_DEPS PollyUnitTests)
+endif ()
+
+set(LLVM_BINARY_DIR "${LLVM_BINARY_DIR}")
+set(LLVM_TOOLS_DIR "${LLVM_TOOLS_BINARY_DIR}")
+set(LLVM_LIBS_DIR "${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}")
+set(POLLY_LIB_DIR "${POLLY_BINARY_DIR}/lib")
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+
+# Run regression and unit tests
+add_lit_testsuite(check-polly-tests "Running polly regression tests"
+  ${CMAKE_CURRENT_BINARY_DIR}
+  PARAMS polly_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+  polly_unit_site_config=${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
+  DEPENDS ${POLLY_TEST_DEPS}
+  )
+set_target_properties(check-polly-tests PROPERTIES FOLDER "Polly")
+add_dependencies(check-polly check-polly-tests)
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
+  )
+
+if (POLLY_GTEST_AVAIL)
+  # Run only unit tests
+  add_lit_testsuite(check-polly-unittests "Running polly unit tests only"
+    ${CMAKE_CURRENT_BINARY_DIR}/Unit
+    PARAMS polly_site_config=${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
+    DEPENDS PollyUnitTests
+    )
+  set_target_properties(check-polly-unittests PROPERTIES FOLDER "Polly")
+endif ()
+
+configure_file(
+  ${CMAKE_CURRENT_SOURCE_DIR}/UnitIsl/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/UnitIsl/lit.site.cfg)
+
+if (POLLY_BUNDLED_ISL)
+  add_lit_testsuite(check-polly-isl "Running isl unit tests only"
+    ${CMAKE_CURRENT_BINARY_DIR}/UnitIsl
+    PARAMS polly_site_config=${CMAKE_CURRENT_BINARY_DIR}/UnitIsl/lit.site.cfg
+    DEPENDS polly-isl-test
+    )
+  set_target_properties(check-polly-isl PROPERTIES FOLDER "Polly")
+endif (POLLY_BUNDLED_ISL)
+
+# Run polly-check-format as part of polly-check only if we are compiling with
+# clang, so clang-format is available.
+# if (TARGET clang-format) would be preferable, but this target is only added
+# after Polly, i.e. there is no such target yet at this point. The CMake cache
+# entry LLVM_TOOL_CLANG_BUILD will only be defined after clang has been
+# configured at least once, i.e. format will be checked only after a rerun of
+# CMake's configure.
+if (LLVM_TOOL_CLANG_BUILD)
+  add_dependencies(check-polly polly-check-format)
+endif ()
+
+configure_file(
+  ${CMAKE_CURRENT_SOURCE_DIR}/update_check.py
+  ${CMAKE_CURRENT_BINARY_DIR}/update_check.py)
+
+# Add a legacy target spelling: polly-test
+add_custom_target(polly-test)
+set_target_properties(polly-test PROPERTIES FOLDER "Polly")
+add_dependencies(polly-test check-polly)
diff --git a/final/test/CodeGen/Intrinsics/llvm-expect.ll b/final/test/CodeGen/Intrinsics/llvm-expect.ll
new file mode 100644
index 0000000..84057e2
--- /dev/null
+++ b/final/test/CodeGen/Intrinsics/llvm-expect.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+;
+; Check that we generate code without crashing.
+;
+; CHECK: polly.start
+;
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+; Function Attrs: nounwind uwtable
+define void @quux() unnamed_addr #0 {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb
+  %tmp = icmp eq i64 0, 0
+  br i1 %tmp, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp3 = icmp ult i64 4, 12
+  %tmp4 = zext i1 %tmp3 to i64
+  %tmp5 = tail call i64 @llvm.expect.i64(i64 %tmp4, i64 0)
+  %tmp6 = trunc i64 %tmp5 to i32
+  br label %bb7
+
+bb7:                                              ; preds = %bb2, %bb1
+  %tmp8 = phi i32 [ undef, %bb2 ], [ 0, %bb1 ]
+  ret void
+}
+
+; Function Attrs: nounwind readnone
+declare i64 @llvm.expect.i64(i64, i64) #1
+
+attributes #0 = { nounwind uwtable }
+attributes #1 = { nounwind readnone }
diff --git a/final/test/CodeGen/OpenMP/floord-as-argument-to-subfunction.ll b/final/test/CodeGen/OpenMP/floord-as-argument-to-subfunction.ll
new file mode 100644
index 0000000..0149756
--- /dev/null
+++ b/final/test/CodeGen/OpenMP/floord-as-argument-to-subfunction.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-opt-max-coefficient=-1 -polly-parallel -polly-codegen -S < %s | FileCheck %s
+;
+; Check that we do not crash but generate parallel code
+;
+; CHECK: polly.par.setup
+;
+; ModuleID = 'bugpoint-reduced-simplified.bc'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @III_hybrid([32 x double]* %tsOut) #0 {
+entry:
+  %0 = getelementptr inbounds [32 x double], [32 x double]* %tsOut, i64 0, i64 0
+  br label %if.end
+
+if.end:                                           ; preds = %entry
+  br i1 undef, label %for.body42, label %for.cond66.preheader
+
+for.cond39.for.cond66.preheader.loopexit67_crit_edge: ; preds = %for.body42
+  %add.ptr62.lcssa = phi double* [ undef, %for.body42 ]
+  br label %for.cond66.preheader
+
+for.cond66.preheader:                             ; preds = %for.cond39.for.cond66.preheader.loopexit67_crit_edge, %if.end
+  %rawout1.3.ph = phi double* [ %add.ptr62.lcssa, %for.cond39.for.cond66.preheader.loopexit67_crit_edge ], [ undef, %if.end ]
+  %sb.3.ph = phi i32 [ 0, %for.cond39.for.cond66.preheader.loopexit67_crit_edge ], [ 0, %if.end ]
+  %tspnt.3.ph = phi double* [ undef, %for.cond39.for.cond66.preheader.loopexit67_crit_edge ], [ %0, %if.end ]
+  br label %for.cond69.preheader
+
+for.body42:                                       ; preds = %if.end
+  br label %for.cond39.for.cond66.preheader.loopexit67_crit_edge
+
+for.cond69.preheader:                             ; preds = %for.end76, %for.cond66.preheader
+  %tspnt.375 = phi double* [ %incdec.ptr79, %for.end76 ], [ %tspnt.3.ph, %for.cond66.preheader ]
+  %sb.374 = phi i32 [ %inc78, %for.end76 ], [ %sb.3.ph, %for.cond66.preheader ]
+  %rawout1.373 = phi double* [ undef, %for.end76 ], [ %rawout1.3.ph, %for.cond66.preheader ]
+  br label %for.body71
+
+for.body71:                                       ; preds = %for.body71, %for.cond69.preheader
+  %indvars.iv = phi i64 [ 0, %for.cond69.preheader ], [ %indvars.iv.next, %for.body71 ]
+  %rawout1.469 = phi double* [ %rawout1.373, %for.cond69.preheader ], [ undef, %for.body71 ]
+  %1 = bitcast double* %rawout1.469 to i64*
+  %2 = load i64, i64* %1, align 8
+  %3 = shl nsw i64 %indvars.iv, 5
+  %arrayidx73 = getelementptr inbounds double, double* %tspnt.375, i64 %3
+  %4 = bitcast double* %arrayidx73 to i64*
+  store i64 %2, i64* %4, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 18
+  br i1 %exitcond, label %for.body71, label %for.end76
+
+for.end76:                                        ; preds = %for.body71
+  %inc78 = add nsw i32 %sb.374, 1
+  %incdec.ptr79 = getelementptr inbounds double, double* %tspnt.375, i64 1
+  %exitcond95 = icmp ne i32 %inc78, 32
+  br i1 %exitcond95, label %for.cond69.preheader, label %for.end80
+
+for.end80:                                        ; preds = %for.end76
+  ret void
+}
diff --git a/final/test/DeLICM/confused_order.ll b/final/test/DeLICM/confused_order.ll
new file mode 100644
index 0000000..1e5fd20
--- /dev/null
+++ b/final/test/DeLICM/confused_order.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-delicm -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-delicm -disable-output -pass-remarks-missed=polly-delicm < %s 2>&1 | FileCheck %s -check-prefix=REMARKS
+;
+; ForwardOptree changes the SCoP and may already map some accesses.
+; DeLICM must be prepared to encounter implicit reads
+; (isOriginalScalarKind()) that occur at the beginning of the SCoP
+; to an array (isLatestArrayKind()). Otherwise it may confuse the
+; MemoryAccess execution order.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @confused_order(double* nocapture %C, i32 %rows, i32 %cols) {
+entry:
+  %0 = sext i32 %cols to i64
+  %1 = sext i32 %rows to i64
+  %cmp108 = icmp slt i64 0, %0
+  br i1 undef, label %for.body7.lr.ph, label %for.end103
+
+for.body7.lr.ph:
+  br label %for.end103
+
+for.end103:
+  %a_dot_b_domain.0.lcssa = phi double [ 0.000000e+00, %entry ], [ undef, %for.body7.lr.ph ]
+  %arrayidx107 = getelementptr inbounds double, double* %C, i64 0
+  store double %a_dot_b_domain.0.lcssa, double* %arrayidx107
+  %cmp109 = icmp slt i64 0, %1
+  %or.cond = and i1 %cmp108, %cmp109
+  br i1 %or.cond, label %if.then110, label %for.inc116
+
+if.then110:
+  %arrayidx114 = getelementptr inbounds double, double* %C, i64 0
+  store double %a_dot_b_domain.0.lcssa, double* %arrayidx114
+  br label %for.inc116
+
+for.inc116:
+  ret void
+}
+
+
+; REMARKS-NOT: load after store of same element in same statement
+; CHECK: No modification has been made
diff --git a/final/test/DeLICM/confused_order___%for.end103---%for.inc116.jscop b/final/test/DeLICM/confused_order___%for.end103---%for.inc116.jscop
new file mode 100644
index 0000000..ce8b7e0
--- /dev/null
+++ b/final/test/DeLICM/confused_order___%for.end103---%for.inc116.jscop
@@ -0,0 +1,47 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[cols, rows] -> {  : -2147483648 <= cols <= 2147483647 and -2147483648 <= rows <= 2147483647 }",
+   "name" : "%for.end103---%for.inc116",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[cols, rows] -> { Stmt_for_end103[] -> MemRef_a_dot_b_domain_0_lcssa__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[cols, rows] -> { Stmt_for_end103[] -> MemRef_C[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[cols, rows] -> { Stmt_for_end103[] -> MemRef_a_dot_b_domain_0_lcssa[] }"
+            }
+         ],
+         "domain" : "[cols, rows] -> { Stmt_for_end103[] }",
+         "name" : "Stmt_for_end103",
+         "schedule" : "[cols, rows] -> { Stmt_for_end103[] -> [0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[cols, rows] -> { Stmt_if_then110[] -> MemRef_C[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[cols, rows] -> { Stmt_if_then110[] -> MemRef_a_dot_b_domain_0_lcssa[] }"
+            }
+         ],
+         "domain" : "[cols, rows] -> { Stmt_if_then110[] : cols > 0 and rows > 0 }",
+         "name" : "Stmt_if_then110",
+         "schedule" : "[cols, rows] -> { Stmt_if_then110[] -> [1] }"
+      }
+   ]
+}
diff --git a/final/test/DeLICM/confused_order___%for.end103---%for.inc116.jscop.transformed b/final/test/DeLICM/confused_order___%for.end103---%for.inc116.jscop.transformed
new file mode 100644
index 0000000..3f52de2
--- /dev/null
+++ b/final/test/DeLICM/confused_order___%for.end103---%for.inc116.jscop.transformed
@@ -0,0 +1,47 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[cols, rows] -> {  : -2147483648 <= cols <= 2147483647 and -2147483648 <= rows <= 2147483647 }",
+   "name" : "%for.end103---%for.inc116",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[cols, rows] -> { Stmt_for_end103[] -> MemRef_a_dot_b_domain_0_lcssa__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[cols, rows] -> { Stmt_for_end103[] -> MemRef_C[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[cols, rows] -> { Stmt_for_end103[] -> MemRef_a_dot_b_domain_0_lcssa[] }"
+            }
+         ],
+         "domain" : "[cols, rows] -> { Stmt_for_end103[] }",
+         "name" : "Stmt_for_end103",
+         "schedule" : "[cols, rows] -> { Stmt_for_end103[] -> [0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[cols, rows] -> { Stmt_if_then110[] -> MemRef_C[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[cols, rows] -> { Stmt_if_then110[] -> MemRef_C[0] }"
+            }
+         ],
+         "domain" : "[cols, rows] -> { Stmt_if_then110[] : cols > 0 and rows > 0 }",
+         "name" : "Stmt_if_then110",
+         "schedule" : "[cols, rows] -> { Stmt_if_then110[] -> [1] }"
+      }
+   ]
+}
diff --git a/final/test/DeLICM/map_memset_zero.ll b/final/test/DeLICM/map_memset_zero.ll
new file mode 100644
index 0000000..c96eedb
--- /dev/null
+++ b/final/test/DeLICM/map_memset_zero.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck -match-full-lines %s
+;
+; Check that PHI mapping works even in presence of a memset whose'
+; zero value is used.
+;
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1)
+
+define void @func(i8* noalias nonnull %A) {
+entry:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %entry], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %bodyA, label %outer.exit
+
+
+    bodyA:
+      %A_idx = getelementptr inbounds i8, i8* %A, i32 %j
+      %cond = icmp eq i32 21, 21
+      br i1 %cond, label %bodyB, label %bodyC
+
+    bodyB:
+      call void @llvm.memset.p0i8.i64(i8* %A_idx, i8 0, i64 1, i32 1, i1 false)
+      br label %bodyC
+
+    bodyC:
+      %phi = phi i8 [1, %bodyA], [0, %bodyB]
+      %a = load i8, i8* %A_idx
+      store i8 %phi, i8* %A_idx
+      br label %outer.inc
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK:     Overwrites mapped to:  1
+; CHECK:     PHI scalars mapped:    1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_bodyA[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_bodyA[i0] -> MemRef_A[o0] : 1 = 0 };
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_bodyB[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_bodyC
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_bodyC[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_bodyC[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_bodyC[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_bodyC[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/nomap_alreadymapped.ll b/final/test/DeLICM/nomap_alreadymapped.ll
new file mode 100644
index 0000000..bd0eef1
--- /dev/null
+++ b/final/test/DeLICM/nomap_alreadymapped.ll
@@ -0,0 +1,79 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi1 = 0.0, phi2 = 0.0;
+;        for (int i = 0; i < 4; i += 1) { /* reduction */
+;          phi1 += 4.2;
+;          phi2 += 29.0;
+;        }
+;        A[j] = phi1 + phi2;
+;      }
+;    }
+;
+; Check that we cannot map both, %phi1 and %phi2 to A[j] (conflict).
+; Note that it is undefined which one will be mapped. We keep the test
+; symmetric so it passes if either one is mapped.
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi1 = phi double [0.0, %reduction.preheader], [%add1, %reduction.inc]
+      %phi2 = phi double [0.0, %reduction.preheader], [%add2, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add1 = fadd double %phi1, 4.2
+          %add2 = fadd double %phi2, 29.0
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %sum = fadd double %phi1, %phi2
+      store double %sum, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK:     Overwrites mapped to:  1
+; CHECK:     Value scalars mapped:  2
+; CHECK:     PHI scalars mapped:    1
+; CHECK: }
diff --git a/final/test/DeLICM/nomap_escaping.ll b/final/test/DeLICM/nomap_escaping.ll
new file mode 100644
index 0000000..1a5fc80
--- /dev/null
+++ b/final/test/DeLICM/nomap_escaping.ll
@@ -0,0 +1,78 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        fsomeval = 21.0 + 21.0;
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = fsomeval;
+;      }
+;      g(fsomeval);
+;    }
+;
+; Check that fsomeval is not mapped to A[j] because it is escaping the SCoP.
+; Supporting this would require reloading the scalar from A[j], and/or
+; identifying the last instance of fsomeval that escapes.
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  %fsomeval = fadd double 21.0, 21.0
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %fsomeval, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  call void @g(double %fsomeval)
+  ret void
+}
+
+declare void @g(double)
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK: }
+; CHECK: No modification has been made
diff --git a/final/test/DeLICM/nomap_occupied.ll b/final/test/DeLICM/nomap_occupied.ll
new file mode 100644
index 0000000..52e177b
--- /dev/null
+++ b/final/test/DeLICM/nomap_occupied.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        dummy = A[j];
+;        A[j] = phi;
+;      }
+;    }
+;
+; Check that A[j] is not used for mapping as it is still in use.
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  %fsomeval = fadd double 21.0, 21.0
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %dummy = load double, double* %A_idx
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK: }
+; CHECK: No modification has been made
diff --git a/final/test/DeLICM/nomap_readonly.ll b/final/test/DeLICM/nomap_readonly.ll
new file mode 100644
index 0000000..3239632
--- /dev/null
+++ b/final/test/DeLICM/nomap_readonly.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(double *A) {
+;      fsomeval = 21.0 + 21.0;
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = fsomeval;
+;      }
+;    }
+;
+; Check that fsomeval is not mapped to A[j] because it is read-only.
+; There is no advantage in mapping values not modified within the SCoP.
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  %fsomeval = fadd double 21.0, 21.0
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %fsomeval, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK: }
+; CHECK: No modification has been made
diff --git a/final/test/DeLICM/nomap_spuriouswrite.ll b/final/test/DeLICM/nomap_spuriouswrite.ll
new file mode 100644
index 0000000..fb3db8e
--- /dev/null
+++ b/final/test/DeLICM/nomap_spuriouswrite.ll
@@ -0,0 +1,84 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        if (phi < 0.0)
+;          A[j] = undef;
+;        A[j] = phi;
+;      }
+;    }
+;
+; The MAY_WRITE in reduction.exit.true avoids that anything can be mapped to
+; A[j] because it would be overwritten by that MAY_WRITE just before the final
+; MUST_WRITE. Also nothing can be map to the MAY_WRITE itself because it is a
+; MAY_WRITE.
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  %fsomeval = fadd double 21.0, 21.0
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %phi.cmp = fcmp ogt double %phi, 0.0
+      br i1 %phi.cmp, label %reduction.exit.true, label %reduction.exit.unconditional
+
+    reduction.exit.true:
+       store double undef, double* %A_idx
+       br label %reduction.exit.unconditional
+
+    reduction.exit.unconditional:
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK: }
+; CHECK: No modification has been made
diff --git a/final/test/DeLICM/nomap_storagesize.ll b/final/test/DeLICM/nomap_storagesize.ll
new file mode 100644
index 0000000..5f96d12
--- /dev/null
+++ b/final/test/DeLICM/nomap_storagesize.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(float *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = fsomeval;
+;      }
+;    }
+;
+; Check that %fphi is not mapped to A[j] because it is double-sized,
+; but A[j] stores only floats.
+;
+define void @func(float* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds float, float* %A, i32 %j
+      %fphi = fptrunc double %phi to float
+      store float %fphi, float* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK: }
+; CHECK: No modification has been made
diff --git a/final/test/DeLICM/nomap_writewrite.ll b/final/test/DeLICM/nomap_writewrite.ll
new file mode 100644
index 0000000..3d2b1a4
--- /dev/null
+++ b/final/test/DeLICM/nomap_writewrite.ll
@@ -0,0 +1,88 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          if (phi < 0.0)
+;            A[j] = undef;
+;          phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+;
+; The MAY_WRITE in reduction.for.true conflict with a write of %phi to
+; A[j] if %phi would be mapped to it. Being a MAY_WRITE avoids being target
+; of a mapping itself.
+;
+; TODO: There is actually no reason why these conflict. The MAY_WRITE is an
+; explicit write, defined to occur always before all implicit writes as the
+; write of %phi would be. There is currently no differentiation between
+; implicit and explicit writes in Polly.
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  %fsomeval = fadd double 21.0, 21.0
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %phi.cmp = fcmp ogt double %phi, 0.0
+      br i1 %phi.cmp, label %reduction.for.true, label %reduction.for.unconditional
+
+    reduction.for.true:
+       store double undef, double* %A_idx
+       br label %reduction.for.unconditional
+
+    reduction.for.unconditional:
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK: }
+; CHECK: No modification has been made
diff --git a/final/test/DeLICM/pass_existence.ll b/final/test/DeLICM/pass_existence.ll
new file mode 100644
index 0000000..dcec39c
--- /dev/null
+++ b/final/test/DeLICM/pass_existence.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s
+;
+; Simple test for the existence of the DeLICM pass.
+;
+; // Simplest detected SCoP to run DeLICM on.
+; for (int j = 0; j < n; j += 1) {
+;   body: A[0] = 0.0;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 0.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; Verify that the DeLICM has a custom printScop() function.
+; CHECK: DeLICM result:
diff --git a/final/test/DeLICM/reduction.ll b/final/test/DeLICM/reduction.ll
new file mode 100644
index 0000000..c8b5504
--- /dev/null
+++ b/final/test/DeLICM/reduction.ll
@@ -0,0 +1,91 @@
+; RUN: opt %loadPolly -polly-delicm-partial-writes=true -polly-delicm -analyze < %s | FileCheck -match-full-lines %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %entry], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.for, label %outer.exit
+
+
+    reduction.for:
+      %i = phi i32 [0, %outer.for], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %outer.for], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_outer_for
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_outer_for[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_outer_for[i0] -> MemRef_A[i0] : i0 <= 1 };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_constant_selfconflict.ll b/final/test/DeLICM/reduction_constant_selfconflict.ll
new file mode 100644
index 0000000..97426d1
--- /dev/null
+++ b/final/test/DeLICM/reduction_constant_selfconflict.ll
@@ -0,0 +1,102 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm-compute-known=true -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) { /* reduction */
+;          phi += 4.2;
+;          A[j] = phi;
+;        }
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          store double %add, double* %A_idx
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: {  Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i1 <= 7 - 5i0; Stmt_reduction_inc[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate.ll b/final/test/DeLICM/reduction_looprotate.ll
new file mode 100644
index 0000000..521829b
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        for (int i = 0; i < 4; i += 1) { /* reduction */
+;          double phi = A[j];
+;          phi += 4.2;
+;          A[j] = phi;
+;        }
+;      }
+;    }
+;
+; There is nothing to do in this case. All accesses are in %body.
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %A_idx = getelementptr inbounds double, double* %A, i32 %j
+          %val = load double, double* %A_idx
+          %add = fadd double %val, 4.2
+          store double %add, double* %A_idx
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: No modification has been made
diff --git a/final/test/DeLICM/reduction_looprotate_alwaystaken.ll b/final/test/DeLICM/reduction_looprotate_alwaystaken.ll
new file mode 100644
index 0000000..fbb20e1
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_alwaystaken.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm-overapproximate-writes=true -polly-delicm-compute-known=true -polly-delicm -analyze < %s | FileCheck %s
+;
+; Verify that delicm can cope with never taken PHI incoming edges.
+; The edge %body -> %body_phi is never taken, hence the access MemoryKind::PHI,
+; WRITE in %body for %phi is never used.
+; When mapping %phi, the write's access relation is the empty set.
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        for (int i = 0; i < 4; i += 1) { /* reduction */
+;          double phi = 21.0;
+;          if (j < 10) // Tautology, since 0<=j<2
+;            phi = 42.0;
+;        }
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A, double* noalias nonnull %dummy) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %cond = icmp slt i32 %j, 10
+          br i1 %cond, label %alwaystaken, label %body_phi
+
+        alwaystaken:
+          store double 0.0, double* %dummy
+          br label %body_phi
+
+        body_phi:
+          %phi = phi double [21.0, %body], [42.0, %alwaystaken]
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     PHI scalars mapped:    1
+; CHECK: }
diff --git a/final/test/DeLICM/reduction_looprotate_gvnpre.ll b/final/test/DeLICM/reduction_looprotate_gvnpre.ll
new file mode 100644
index 0000000..0ad3e3c
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_gvnpre.ll
@@ -0,0 +1,126 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm-overapproximate-writes=true -polly-delicm-compute-known=true -polly-delicm -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm-partial-writes=true -polly-delicm-compute-known=true -polly-delicm -analyze < %s | FileCheck -check-prefix=PARTIAL %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) { /* reduction */
+;          phi += 4.2;
+;          A[j] = phi;
+;        }
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          %A_idx = getelementptr inbounds double, double* %A, i32 %j
+          store double %add, double* %A_idx
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      After accesses {
+; CHECK-NEXT:    Stmt_reduction_preheader
+; CHECK-NEXT:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] : 3i1 <= 21 - 13i0; Stmt_body[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : 3i1 <= 21 - 13i0; Stmt_reduction_inc[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+
+
+; PARTIAL:      After accesses {
+; PARTIAL-NEXT:     Stmt_reduction_preheader
+; PARTIAL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; PARTIAL-NEXT:     Stmt_reduction_for
+; PARTIAL-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; PARTIAL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; PARTIAL-NEXT:     Stmt_body
+; PARTIAL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; PARTIAL-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; PARTIAL-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; PARTIAL-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] : 3i1 <= 21 - 13i0; Stmt_body[1, 3] -> MemRef_A[1] };
+; PARTIAL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; PARTIAL-NEXT:                 { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; PARTIAL-NEXT:     Stmt_reduction_inc
+; PARTIAL-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : 3i1 <= 21 - 13i0; Stmt_reduction_inc[1, 3] -> MemRef_A[1] };
+; PARTIAL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i1 <= 2 };
+; PARTIAL-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_gvnpre_cond1.ll b/final/test/DeLICM/reduction_looprotate_gvnpre_cond1.ll
new file mode 100644
index 0000000..65fb4a9
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_gvnpre_cond1.ll
@@ -0,0 +1,126 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s -match-full-lines
+;
+; Load (but not store) of A[j] hoisted, reduction only over some iterations.
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) { /* reduction */
+;          if (i != 2)
+;            phi += 4.2;
+;          A[j] = phi;
+;        }
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%join, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %cond = icmp ne i32 %i, 2
+          br i1 %cond, label %body_true, label %body_join
+
+        body_true:
+          %add = fadd double %phi, 4.2
+          br label %body_join
+
+        body_join:
+          %join = phi double [%phi, %body], [%add, %body_true]
+          %A_idx = getelementptr inbounds double, double* %A, i32 %j
+          store double %join, double* %A_idx
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK:     Overwrites mapped to:  1
+; CHECK:     Value scalars mapped:  2
+; CHECK:     PHI scalars mapped:    2
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_join__phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, 2] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body_true
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body_true[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body_true[i0, i1] -> MemRef_A[i0] : i1 <= 1; Stmt_body_true[i0, 3] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body_true[i0, i1] -> MemRef_join__phi[] };
+; CHECK-NEXT:            new: { Stmt_body_true[i0, i1] -> MemRef_A[i0] : i1 <= 1; Stmt_body_true[i0, 3] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body_join
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body_join[i0, i1] -> MemRef_join[] };
+; CHECK-NEXT:            new: { Stmt_body_join[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body_join[i0, i1] -> MemRef_join__phi[] };
+; CHECK-NEXT:            new: { Stmt_body_join[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_body_join[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_join[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i1 <= 2 };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_gvnpre_cond2.ll b/final/test/DeLICM/reduction_looprotate_gvnpre_cond2.ll
new file mode 100644
index 0000000..4f3def1
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_gvnpre_cond2.ll
@@ -0,0 +1,127 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s -match-full-lines
+;
+; Load (but not store) of A[j] hoisted, reduction not written in all iterations.
+; FIXME: %join is not mapped because the MemoryKind::Value mapping does not
+;        encompass all iterations (last iteration is unused)
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) { /* reduction */
+;          if (i != 2) {
+;            phi += 4.2;
+;            A[j] = phi;
+;          }
+;        }
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %init = load double, double* %A_idx
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [%init, %reduction.preheader], [%join, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %cond = icmp ne i32 %i, 2
+          br i1 %cond, label %body_true, label %body_join
+
+        body_true:
+          %add = fadd double %phi, 4.2
+          store double %add, double* %A_idx
+          br label %body_join
+
+        body_join:
+          %join = phi double [%phi, %body], [%add, %body_true]
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK:     Overwrites mapped to:  1
+; CHECK:     Value scalars mapped:  1
+; CHECK:     PHI scalars mapped:    1
+; CHECK: }
+
+; CHECK-NEXT: After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_join__phi[] };
+; CHECK-NEXT:     Stmt_body_true
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body_true[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body_true[i0, i1] -> MemRef_A[i0] : i1 <= 1; Stmt_body_true[i0, 3] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_body_true[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body_true[i0, i1] -> MemRef_join__phi[] };
+; CHECK-NEXT:     Stmt_body_join
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body_join[i0, i1] -> MemRef_join[] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body_join[i0, i1] -> MemRef_join__phi[] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_join[] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i1 <= 2 };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_gvnpre_nopreheader.ll b/final/test/DeLICM/reduction_looprotate_gvnpre_nopreheader.ll
new file mode 100644
index 0000000..fdc6c4c
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_gvnpre_nopreheader.ll
@@ -0,0 +1,100 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s -match-full-lines
+;
+; Hosted reduction load (but not the store) without preheader.
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) { /* reduction */
+;          phi += 4.2;
+;          A[j] = phi;
+;        }
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.for, label %outer.exit
+
+
+    reduction.for:
+      %i = phi i32 [0, %outer.for], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %outer.for], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          %A_idx = getelementptr inbounds double, double* %A, i32 %j
+          store double %add, double* %A_idx
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK:     Overwrites mapped to:  1
+; CHECK:     Value scalars mapped:  2
+; CHECK:     PHI scalars mapped:    1
+; CHECK: }
+
+; CHECK-NEXT: After accesses {
+; CHECK-NEXT:     Stmt_outer_for
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_outer_for[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_outer_for[i0] -> MemRef_A[i0] : i0 <= 1 };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i1 <= 2 };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_hoisted.ll b/final/test/DeLICM/reduction_looprotate_hoisted.ll
new file mode 100644
index 0000000..750ff7d
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_hoisted.ll
@@ -0,0 +1,101 @@
+; RUN: opt %loadPolly -polly-invariant-load-hoisting -polly-flatten-schedule -polly-delicm-overapproximate-writes=true -polly-delicm-compute-known=true -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(int *A, int* StartPtr) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        int Start = *Startptr;
+;        int phi = Start;
+;        for (int i = Start; i < 4; i += 1) /* reduction */
+;          phi += 42;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(i32* noalias nonnull %A, i32* noalias nonnull %StartPtr) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      %Start = load i32, i32* %StartPtr
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [%Start, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi i32 [%Start, %reduction.preheader], [%mul, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %mul = mul i32 %phi, 2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds i32, i32* %A, i32 %j
+      store i32 %mul, i32* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+; FIXME: The accesses for %i should not be there because, with
+; load-hoisting %Start is an affine loop. To be fixed in ScopBuilder.
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [Start] -> { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [Start] -> { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [Start] -> { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [Start] -> { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] : -i0 < i1 <= 3 - Start; Stmt_reduction_for[1, 0] -> MemRef_A[1] : Start >= 4; Stmt_reduction_for[0, 0] -> MemRef_A[0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [Start] -> { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: [Start] -> { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] : i0 <= i1 <= 3 - Start; Stmt_reduction_for[i0, 0] -> MemRef_A[i0] : i0 <= -4 + Start; Stmt_reduction_for[1, 0] -> MemRef_A[1] : Start <= 4 }
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [Start] -> { Stmt_body[i0, i1] -> MemRef_mul[] };
+; CHECK-NEXT:            new: [Start] -> { Stmt_body[i0, i1] -> MemRef_A[i0] : i0 <= i1 <= 3 - Start; Stmt_body[i0, 0] -> MemRef_A[i0] : i0 <= -4 + Start; Stmt_body[1, 0] -> MemRef_A[1] : Start <= 4 }
+; CHECK-NEXT:             ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [Start] -> { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: [Start] -> { Stmt_body[i0, i1] -> MemRef_A[i0] : i0 <= i1 <= 3 - Start; Stmt_body[1, 0] -> MemRef_A[1]; Stmt_body[0, 0] -> MemRef_A[0] : Start >= 4 };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [Start] -> { Stmt_reduction_inc[i0, i1] -> MemRef_mul[] };
+; CHECK-NEXT:            new: [Start] -> { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i0 <= i1 <= 3 - Start; Stmt_reduction_inc[1, 0] -> MemRef_A[1]; Stmt_reduction_inc[0, 0] -> MemRef_A[0] : Start >= 4 };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [Start] -> { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [Start] -> { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : 0 < i1 <= 3 - Start; Stmt_reduction_inc[i0, 0] -> MemRef_A[i0] }
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [Start] -> { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [Start] -> { Stmt_reduction_exit[i0] -> MemRef_mul[] };
+; CHECK-NEXT:            new: [Start] -> { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_licm.ll b/final/test/DeLICM/reduction_looprotate_licm.ll
new file mode 100644
index 0000000..dd73c5e
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_licm.ll
@@ -0,0 +1,100 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm-overapproximate-writes=true -polly-delicm-compute-known=true -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = A[j];
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %init = load double, double* %A_idx
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [%init, %reduction.preheader], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      store double %add, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_body[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_reduction_inc[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_licm2.ll b/final/test/DeLICM/reduction_looprotate_licm2.ll
new file mode 100644
index 0000000..1c909aa
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_licm2.ll
@@ -0,0 +1,112 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm -analyze < %s | FileCheck %s
+;
+; Use %phi instead of the normal %add; that is, the last last iteration will
+; be ignored such the %phi cannot be written to A[3] in %body.
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi;
+;        double incoming = A[j];
+;        for (int i = 0; i < 4; i += 1) { /* reduction */
+;          phi = incoming;
+;          add = phi + 4.2;
+;          incoming =  add;
+;        }
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %init = load double, double* %A_idx
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [%init, %reduction.preheader], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK:     Overwrites mapped to:  1
+; CHECK:     Value scalars mapped:  1
+; CHECK:     PHI scalars mapped:    1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_body[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i1 <= 2 };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_licm_double_write.ll b/final/test/DeLICM/reduction_looprotate_licm_double_write.ll
new file mode 100644
index 0000000..3fedca0
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_licm_double_write.ll
@@ -0,0 +1,108 @@
+; RUN: opt %loadPolly -polly-flatten-schedule \
+; RUN: -polly-delicm-overapproximate-writes=true \
+; RUN: -polly-delicm-compute-known=true -polly-delicm \
+; RUN: -analyze < %s | FileCheck %s
+;
+; Make sure delicm works even in case two stores that store the same value.
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = A[j];
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %init = load double, double* %A_idx
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [%init, %reduction.preheader], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      store double %add, double* %A_idx
+      store double %add, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_body[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_reduction_inc[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_licm_nopreheader.ll b/final/test/DeLICM/reduction_looprotate_licm_nopreheader.ll
new file mode 100644
index 0000000..53b179a
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_licm_nopreheader.ll
@@ -0,0 +1,107 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s
+;
+; Register-promoted reduction but without preheader.
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = A[j];
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  %A_idx = getelementptr inbounds double, double* %A, i32 %j
+  %init = load double, double* %A_idx
+  br i1 %j.cmp, label %reduction.for, label %outer.exit
+
+
+
+    reduction.for:
+      %i = phi i32 [0, %outer.for], [%i.inc, %reduction.inc]
+      %phi = phi double [%init, %outer.for], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      store double %add, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK:     Overwrites mapped to:  1
+; CHECK:     Value scalars mapped:  2
+; CHECK:     PHI scalars mapped:    1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_outer_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_outer_for[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_outer_for[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_outer_for[i0] -> MemRef_A[i0] : i0 <= 1 };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i1 <= 2 };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_load.ll b/final/test/DeLICM/reduction_looprotate_load.ll
new file mode 100644
index 0000000..1e9c8ef
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_load.ll
@@ -0,0 +1,99 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm-overapproximate-writes=true -polly-delicm-compute-known=true -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(int *A, double* StartPtr) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        int phi = *StartPtr;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A, double* noalias nonnull %StartPtr) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      %Start = load double, double* %StartPtr
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [%Start, %reduction.preheader], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %add, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_StartPtr[0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_body[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_reduction_inc[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_loopguard_gvnpre.ll b/final/test/DeLICM/reduction_looprotate_loopguard_gvnpre.ll
new file mode 100644
index 0000000..0c27af5
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_loopguard_gvnpre.ll
@@ -0,0 +1,105 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s -match-full-lines
+;
+; Reduction over parametric number of elements and a loopguard if the
+; reduction loop is not executed at all. Load hoisted before loop.
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < n; i += 1) { /* reduction */
+;          phi += 4.2;
+;          A[j] = phi;
+;        }
+;      }
+;    }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      %guard.cmp = icmp sle i32 %n,0
+      br i1 %guard.cmp, label %reduction.exit, label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          %A_idx = getelementptr inbounds double, double* %A, i32 %j
+          store double %add, double* %A_idx
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, %n
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK:     Overwrites mapped to:  1
+; CHECK:     Value scalars mapped:  2
+; CHECK:     PHI scalars mapped:    1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_preheader[i0] -> MemRef_A[i0] : n > 0 };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i1 <= -2 + n };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_loopguard_licm1.ll b/final/test/DeLICM/reduction_looprotate_loopguard_licm1.ll
new file mode 100644
index 0000000..4f441e4
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_loopguard_licm1.ll
@@ -0,0 +1,119 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s -match-full-lines
+;
+; Reduction over parametric number of elements and a loopguard if the
+; reduction loop is not executed at all.
+; Reduction variable promoted to register.
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = A[j];
+;        for (int i = 0; i < n; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.guard, label %outer.exit
+
+
+    reduction.guard:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %init = load double, double* %A_idx
+      %guard.cmp = icmp sle i32 %n,0
+      br i1 %guard.cmp, label %reduction.exit, label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.guard], [%i.inc, %reduction.inc]
+      %phi = phi double [%init, %reduction.guard], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, %n
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      %result = phi double [%init, %reduction.guard], [%add, %reduction.inc]
+      store double %result, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK:     Overwrites mapped to:  1
+; CHECK:     Value scalars mapped:  2
+; CHECK:     PHI scalars mapped:    2
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_guard
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_guard[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_guard[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_guard[i0] -> MemRef_A[i0] : n > 0 };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_guard[i0] -> MemRef_result__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_guard[i0] -> MemRef_A[i0] : n <= 0 };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i1 <= -2 + n };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_result__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_inc[i0, -1 + n] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_exit[i0] -> MemRef_result__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_loopguard_licm2.ll b/final/test/DeLICM/reduction_looprotate_loopguard_licm2.ll
new file mode 100644
index 0000000..672593c
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_loopguard_licm2.ll
@@ -0,0 +1,117 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s -match-full-lines
+;
+; Reduction over parametric number of elements and a loopguard if the
+; reduction loop is not executed at all, such that A[j] is also not written to.
+; Reduction variable promoted to register.
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = A[j];
+;        if (i > 0) {
+;          for (int i = 0; i < n; i += 1) /* reduction */
+;            phi += 4.2;
+;          A[j] = phi;
+;        }
+;      }
+;    }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.guard, label %outer.exit
+
+
+    reduction.guard:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %init = load double, double* %A_idx
+      %guard.cmp = icmp sle i32 %n,0
+      br i1 %guard.cmp, label %reduction.skip, label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.guard], [%i.inc, %reduction.inc]
+      %phi = phi double [%init, %reduction.guard], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, %n
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      store double %add, double* %A_idx
+      br label %reduction.skip
+
+    reduction.skip:
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK:     Overwrites mapped to:  1
+; CHECK:     Value scalars mapped:  2
+; CHECK:     PHI scalars mapped:    1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_guard
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_guard[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_guard[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_guard[i0] -> MemRef_A[i0] : n > 0 };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i1 <= -2 + n };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_exit[i0] -> MemRef_add[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_loopguard_licm3.ll b/final/test/DeLICM/reduction_looprotate_loopguard_licm3.ll
new file mode 100644
index 0000000..61c34a6
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_loopguard_licm3.ll
@@ -0,0 +1,120 @@
+; RUN: opt %loadPolly -polly-delicm -analyze < %s | FileCheck %s -match-full-lines
+;
+; Reduction over parametric number of elements and a loopguard if the
+; reduction loop is not executed at all, such that A[j] is also not accessed.
+; Reduction variable promoted to register.
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        if (i > 0) {
+;          double phi = A[j];
+;          for (int i = 0; i < n; i += 1) /* reduction */
+;            phi += 4.2;
+;          A[j] = phi;
+;        }
+;      }
+;    }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.guard, label %outer.exit
+
+
+    reduction.guard:
+      %guard.cmp = icmp sle i32 %n,0
+      br i1 %guard.cmp, label %reduction.skip, label %reduction.preheader
+
+    reduction.preheader:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %init = load double, double* %A_idx
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [%init, %reduction.preheader], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, %n
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      store double %add, double* %A_idx
+      br label %reduction.skip
+
+    reduction.skip:
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Compatible overwrites: 1
+; CHECK:     Overwrites mapped to:  1
+; CHECK:     Value scalars mapped:  2
+; CHECK:     PHI scalars mapped:    1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i1 <= -2 + n };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_reduction_exit[i0] -> MemRef_add[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_readonly.ll b/final/test/DeLICM/reduction_looprotate_readonly.ll
new file mode 100644
index 0000000..f7751fa
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_readonly.ll
@@ -0,0 +1,98 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm-overapproximate-writes=true -polly-delicm-compute-known=true -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(double *A, double Start) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = Start;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A, double %Start) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [%Start, %reduction.preheader], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %add, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_Start[] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: {  Stmt_body[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_body[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_reduction_inc[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_synthesizable.ll b/final/test/DeLICM/reduction_looprotate_synthesizable.ll
new file mode 100644
index 0000000..445164c
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_synthesizable.ll
@@ -0,0 +1,97 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm-overapproximate-writes=true -polly-delicm-compute-known=true -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(int *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        int phi = j;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 42;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(i32* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi i32 [%j, %reduction.preheader], [%mul, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %mul = mul i32 %phi, 42
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds i32, i32* %A, i32 %j
+      store i32 %mul, i32* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_mul[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_body[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_mul[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_reduction_inc[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_mul[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_looprotate_undef.ll b/final/test/DeLICM/reduction_looprotate_undef.ll
new file mode 100644
index 0000000..343eb21
--- /dev/null
+++ b/final/test/DeLICM/reduction_looprotate_undef.ll
@@ -0,0 +1,98 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm-overapproximate-writes=true -polly-delicm-compute-known=true -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(int *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        int phi;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 42;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(i32* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi i32 [undef, %reduction.preheader], [%conv, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %fval = sitofp i32 %phi to double
+          %add = fadd double %fval, 4.2
+          %conv = fptosi double %add to i32
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 4
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds i32, i32* %A, i32 %j
+      store i32 %conv, i32* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_conv[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_body[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_conv[] };
+; CHECK-NEXT:            new: {  Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : 3i1 <= 22 - 14i0; Stmt_reduction_inc[1, 3] -> MemRef_A[1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_conv[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reduction_overapproximate.ll b/final/test/DeLICM/reduction_overapproximate.ll
new file mode 100644
index 0000000..8e20e29
--- /dev/null
+++ b/final/test/DeLICM/reduction_overapproximate.ll
@@ -0,0 +1,158 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm-compute-known=true -polly-delicm-overapproximate-writes=true -polly-delicm-partial-writes=false -polly-delicm -analyze < %s | FileCheck %s --check-prefix=APPROX
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm-compute-known=true -polly-delicm-overapproximate-writes=false -polly-delicm-partial-writes=false  -polly-delicm -analyze < %s | FileCheck %s --check-prefix=EXACT
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm-compute-known=true -polly-delicm-partial-writes=true -polly-delicm -analyze < %s | FileCheck %s --check-prefix=PARTIAL
+;
+;    void func(double *A {
+;      for (int j = -1; j < 3; j += 1) { /* outer */
+;        double phi = 0.0;
+;        if (0 < j)
+;          for (int i = 0; i < j; i += 1) /* reduction */
+;            phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [-1, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 3
+  br i1 %j.cmp, label %reduction.checkloop, label %outer.exit
+
+
+
+    reduction.checkloop:
+      %j2.cmp = icmp slt i32 0, %j
+      br i1 %j2.cmp, label %reduction.preheader, label %reduction.exit
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      br label %body
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, %j
+      br i1 %i.cmp, label %reduction.for, label %reduction.exit
+
+    reduction.exit:
+      %val = phi double [%add, %reduction.inc], [0.0, %reduction.checkloop]
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; APPROX:      After accesses {
+; APPROX-NEXT:     Stmt_reduction_checkloop
+; APPROX-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; APPROX-NEXT:                 { Stmt_reduction_checkloop[i0] -> MemRef_val__phi[] };
+; APPROX-NEXT:            new: { Stmt_reduction_checkloop[i0] -> MemRef_A[-1 + i0] };
+; APPROX-NEXT:     Stmt_reduction_preheader
+; APPROX-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; APPROX-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; APPROX-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[-1 + i0] };
+; APPROX-NEXT:     Stmt_reduction_for
+; APPROX-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; APPROX-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; APPROX-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[-1 + i0] };
+; APPROX-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; APPROX-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; APPROX-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[-1 + i0] };
+; APPROX-NEXT:     Stmt_body
+; APPROX-NEXT:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; APPROX-NEXT:                { Stmt_body[i0, i1] -> MemRef_add[] };
+; APPROX-NEXT:           new: { Stmt_body[i0, i1] -> MemRef_A[-1 + i0] };
+; APPROX-NEXT:            ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; APPROX-NEXT:                { Stmt_body[i0, i1] -> MemRef_phi[] };
+; APPROX-NEXT:           new: { Stmt_body[i0, i1] -> MemRef_A[-1 + i0] };
+; APPROX-NEXT:     Stmt_reduction_inc
+; APPROX-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; APPROX-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; APPROX-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[-1 + i0] };
+; APPROX-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; APPROX-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; APPROX-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[2] };
+; APPROX-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; APPROX-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_val__phi[] };
+; APPROX-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[-1 + i0] };
+; APPROX-NEXT:     Stmt_reduction_exit
+; APPROX-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; APPROX-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_val__phi[] };
+; APPROX-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[-1 + i0] };
+; APPROX-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; APPROX-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[-1 + i0] };
+; APPROX-NEXT: }
+
+
+; EXACT: No modification has been made
+
+
+; PARTIAL:      After accesses {
+; PARTIAL-NEXT:     Stmt_reduction_checkloop
+; PARTIAL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_checkloop[i0] -> MemRef_val__phi[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_checkloop[i0] -> MemRef_A[-1 + i0] : i0 <= 1 };
+; PARTIAL-NEXT:     Stmt_reduction_preheader
+; PARTIAL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[-1 + i0] };
+; PARTIAL-NEXT:     Stmt_reduction_for
+; PARTIAL-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[-1 + i0] };
+; PARTIAL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[-1 + i0] };
+; PARTIAL-NEXT:     Stmt_body
+; PARTIAL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; PARTIAL-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[-1 + i0] };
+; PARTIAL-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; PARTIAL-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[-1 + i0] };
+; PARTIAL-NEXT:     Stmt_reduction_inc
+; PARTIAL-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[-1 + i0] };
+; PARTIAL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_inc[3, 0] -> MemRef_A[2] };
+; PARTIAL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_val__phi[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_inc[i0, -2 + i0] -> MemRef_A[-1 + i0] };
+; PARTIAL-NEXT:     Stmt_reduction_exit
+; PARTIAL-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; PARTIAL-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_val__phi[] };
+; PARTIAL-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[-1 + i0] };
+; PARTIAL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; PARTIAL-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[-1 + i0] };
+; PARTIAL-NEXT: }
diff --git a/final/test/DeLICM/reduction_preheader.ll b/final/test/DeLICM/reduction_preheader.ll
new file mode 100644
index 0000000..a644c85
--- /dev/null
+++ b/final/test/DeLICM/reduction_preheader.ll
@@ -0,0 +1,130 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -polly-delicm -analyze < %s | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; Unrolled flattened schedule:
+; [0] Stmt_reduction_preheader[0]
+; [1] Stmt_reduction_for[0, 0]
+; [2] Stmt_body[0, 0]
+; [3] Stmt_reduction_inc[0, 0]
+; [4] Stmt_reduction_for[0, 1]
+; [5] Stmt_body[0, 1]
+; [6] Stmt_reduction_inc[0, 1]
+; [7] Stmt_reduction_for[0, 2]
+; [8] Stmt_body[0, 2]
+; [9] Stmt_reduction_inc[0, 2]
+; [10] Stmt_reduction_for[0, 3]
+; [11] Stmt_body[0, 3]
+; [12] Stmt_reduction_inc[0, 3]
+; [13] Stmt_reduction_for[0, 4]
+; [14] Stmt_reduction_exit[0]
+; [15] Stmt_reduction_preheader[0]
+; [16] Stmt_reduction_for[1, 0]
+; [17] Stmt_body[1, 0]
+; [18] Stmt_reduction_inc[1, 0]
+; [19] Stmt_reduction_for[1, 1]
+; [20] Stmt_body[1, 1]
+; [21] Stmt_reduction_inc[1, 1]
+; [22] Stmt_reduction_for[1, 2]
+; [23] Stmt_body[1, 2]
+; [24] Stmt_reduction_inc[1, 2]
+; [25] Stmt_reduction_for[1, 3]
+; [26] Stmt_body[1, 3]
+; [27] Stmt_reduction_inc[1, 3]
+; [28] Stmt_reduction_for[1, 4]
+; [29] Stmt_reduction_exit[1]
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_reduction_preheader
+; CHECK-NEXT:             MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_preheader[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] : i1 <= 7 - 5i0; Stmt_reduction_inc[1, 3] -> MemRef_A[1]  };
+; CHECK-NEXT:             MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+
diff --git a/final/test/DeLICM/reduction_unrelatedunusual.ll b/final/test/DeLICM/reduction_unrelatedunusual.ll
new file mode 100644
index 0000000..49e22fc
--- /dev/null
+++ b/final/test/DeLICM/reduction_unrelatedunusual.ll
@@ -0,0 +1,103 @@
+; RUN: opt %loadPolly -polly-delicm-partial-writes=true -polly-delicm -analyze < %s | FileCheck -match-full-lines %s
+;
+; Map %add and %phi to A[j].
+; The non-analyzable store to C[0] is unrelated and can be ignored.
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) { /* reduction */
+;          phi += 4.2;
+;          C[0] = 21.0;
+;          C[0] = 42.0;
+;        }
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A, double* noalias nonnull %C) {
+entry:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %entry], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.for, label %outer.exit
+
+
+    reduction.for:
+      %i = phi i32 [0, %outer.for], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %outer.for], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          store double 21.0, double* %C
+          store double 41.0, double* %C
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_outer_for
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_outer_for[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_outer_for[i0] -> MemRef_A[i0] : i0 <= 1 };
+; CHECK-NEXT:     Stmt_reduction_for
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_C[0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_C[0] };
+; CHECK-NEXT:     Stmt_reduction_inc
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_reduction_exit
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/DeLICM/reject_loadafterstore.ll b/final/test/DeLICM/reject_loadafterstore.ll
new file mode 100644
index 0000000..9f1a05d
--- /dev/null
+++ b/final/test/DeLICM/reject_loadafterstore.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-delicm -analyze -pass-remarks-missed=polly-delicm < %s 2>&1 | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = phi;
+;        (void)A[j];
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %phi, double* %A_idx
+      %dummy = load double, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: load after store of same element in same statement
diff --git a/final/test/DeLICM/reject_outofquota.ll b/final/test/DeLICM/reject_outofquota.ll
new file mode 100644
index 0000000..95ac67a
--- /dev/null
+++ b/final/test/DeLICM/reject_outofquota.ll
@@ -0,0 +1,79 @@
+; RUN: opt %loadPolly -polly-delicm -analyze -pass-remarks-analysis=polly-delicm -polly-delicm-max-ops=1 < %s 2>&1 | FileCheck %s
+; RUN: opt %loadPolly -polly-delicm -polly-dependences -analyze -polly-delicm-max-ops=1 -polly-dependences-computeout=0 < %s | FileCheck %s -check-prefix=DEP
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: maximal number of operations exceeded during zone analysis
+
+; Check that even if the quota was exceeded in DeLICM, DependenceInfo is still
+; successfull since it uses a different operations counter.
+;
+; DEP:     RAW dependences:
+; DEP-NOT:        n/a
+; DEP:     WAR dependences:
+; DEP-NOT:        n/a
+; DEP:     WAW dependences:
+; DEP-NOT:        n/a
+; DEP:     Reduction dependences:
+; DEP-NOT:        n/a
+; DEP:     Transitive closure of reduction dependences:
diff --git a/final/test/DeLICM/reject_storeafterstore.ll b/final/test/DeLICM/reject_storeafterstore.ll
new file mode 100644
index 0000000..f3f8955
--- /dev/null
+++ b/final/test/DeLICM/reject_storeafterstore.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-delicm -analyze -pass-remarks-missed=polly-delicm < %s 2>&1 | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = 0.0;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double 0.0, double* %A_idx
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: store after store of same element in same statement
diff --git a/final/test/DeLICM/reject_storeinsubregion.ll b/final/test/DeLICM/reject_storeinsubregion.ll
new file mode 100644
index 0000000..4a96ace
--- /dev/null
+++ b/final/test/DeLICM/reject_storeinsubregion.ll
@@ -0,0 +1,79 @@
+; RUN: opt %loadPolly -polly-delicm -analyze -pass-remarks-missed=polly-delicm < %s 2>&1 | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;          if (phi > 42.0)
+;            (void)A[j];
+;          else
+;            A[j] = 0.0;
+;        A[j] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          %A_idxp = getelementptr inbounds double, double* %A, i32 %j
+          %add.cmp = fcmp ogt double %add, 42.0
+          br i1 %add.cmp , label %body_true, label %body_false
+
+        body_true:
+          %dummy = load double, double* %A_idxp
+          br label %reduction.inc
+
+        body_false:
+          store double 0.0, double* %A_idxp
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: store is in a non-affine subregion
diff --git a/final/test/DeLICM/reject_unusualstore.ll b/final/test/DeLICM/reject_unusualstore.ll
new file mode 100644
index 0000000..cdbfcc1
--- /dev/null
+++ b/final/test/DeLICM/reject_unusualstore.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-delicm -analyze< %s | FileCheck %s
+; RUN: opt %loadPolly -polly-delicm -disable-output -stats < %s 2>&1 | FileCheck %s --check-prefix=STATS
+; REQUIRES: asserts
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        A[j] = 21.0;
+;        A[j] = 42.0;
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+;
+
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double 21.0, double* %A_idx
+      store double 42.0, double* %A_idx
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: No modification has been made
+; STATS: 1 polly-zone       - Number of not zone-analyzable arrays
diff --git a/final/test/DeLICM/skip_maywrite.ll b/final/test/DeLICM/skip_maywrite.ll
new file mode 100644
index 0000000..e3ab287
--- /dev/null
+++ b/final/test/DeLICM/skip_maywrite.ll
@@ -0,0 +1,74 @@
+; RUN: opt %loadPolly -polly-delicm -analyze -pass-remarks-missed=polly-delicm < %s 2>&1 | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        memset(A[j], 0, sizeof(double));
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        if (phi >= 0.0)
+;          A[j] = phi;
+;      }
+;    }
+;
+
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %phi.cmp = fcmp ogt double %phi, 0.0
+      br i1 %phi.cmp , label %reduction.exit_true, label %reduction.exit_false
+
+    reduction.exit_true:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+    reduction.exit_false:
+      br label %outer.inc
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Skipped possible mapping target because it is not an unconditional overwrite
diff --git a/final/test/DeLICM/skip_multiaccess.ll b/final/test/DeLICM/skip_multiaccess.ll
new file mode 100644
index 0000000..92c0b12
--- /dev/null
+++ b/final/test/DeLICM/skip_multiaccess.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-delicm -pass-remarks-missed=polly-delicm -disable-output < %s 2>&1 | FileCheck %s
+;
+; llvm.org/PR34485
+; llvm.org/PR34989
+;
+; The memset causes the array A to be divided into i8-sized subelements.
+; The the regular store then writes multiple of these subelements, which
+; we do not support currently.
+;
+;    void func(double *A) {
+;      memset(A, 0, 4);
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[j] = phi;
+;      }
+;    }
+
+declare void @llvm.memset.p0f64.i64(double* nocapture, i8, i64, i32, i1)
+
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %entry], [%j.inc, %outer.inc]
+  call void @llvm.memset.p0f64.i64(double* %A, i8 0, i64 4, i32 1, i1 false)
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.for, label %outer.exit
+
+
+    reduction.for:
+      %i = phi i32 [0, %outer.for], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %outer.for], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: skipped possible mapping target because it writes more than one element
diff --git a/final/test/DeLICM/skip_notinloop.ll b/final/test/DeLICM/skip_notinloop.ll
new file mode 100644
index 0000000..0dd9054
--- /dev/null
+++ b/final/test/DeLICM/skip_notinloop.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-delicm -analyze -pass-remarks-missed=polly-delicm < %s 2>&1 | FileCheck %s
+;
+;    void func(double *A) {
+;      double phi = 0.0;
+;      for (int i = 0; i < 4; i += 1) /* reduction */
+;        phi += 4.2;
+;      A[0] = phi;
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %reduction.preheader
+
+  reduction.preheader:
+    br label %reduction.for
+
+  reduction.for:
+    %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+    %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+    %i.cmp = icmp slt i32 %i, 4
+    br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+      body:
+        %add = fadd double %phi, 4.2
+        br label %reduction.inc
+
+
+
+  reduction.inc:
+    %i.inc = add nuw nsw i32 %i, 1
+    br label %reduction.for
+
+  reduction.exit:
+    store double %phi, double* %A
+    br label %return
+
+
+return:
+  ret void
+}
+
+
+; CHECK: skipped possible mapping target because it is not in a loop
diff --git a/final/test/DeLICM/skip_scalaraccess.ll b/final/test/DeLICM/skip_scalaraccess.ll
new file mode 100644
index 0000000..93919ad
--- /dev/null
+++ b/final/test/DeLICM/skip_scalaraccess.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-delicm -analyze -pass-remarks-missed=polly-delicm < %s 2>&1 | FileCheck %s
+;
+;    void func(double *A) {
+;      for (int j = 0; j < 2; j += 1) { /* outer */
+;        double phi = 0.0;
+;        for (int i = 0; i < 4; i += 1) /* reduction */
+;          phi += 4.2;
+;        A[0] = phi;
+;      }
+;    }
+;
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %outer.preheader
+
+outer.preheader:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %outer.preheader], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 2
+  br i1 %j.cmp, label %reduction.preheader, label %outer.exit
+
+
+    reduction.preheader:
+      br label %reduction.for
+
+    reduction.for:
+      %i = phi i32 [0, %reduction.preheader], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %reduction.preheader], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+
+
+        body:
+          %add = fadd double %phi, 4.2
+          br label %reduction.inc
+
+
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      store double %phi, double* %A
+      br label %outer.inc
+
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: skipped possible mapping target because the memory location written to does not depend on its outer loop
diff --git a/final/test/DeadCodeElimination/chained_iterations.ll b/final/test/DeadCodeElimination/chained_iterations.ll
new file mode 100644
index 0000000..26ffc3c
--- /dev/null
+++ b/final/test/DeadCodeElimination/chained_iterations.ll
@@ -0,0 +1,61 @@
+; RUN: opt -S %loadPolly -basicaa -polly-dependences-analysis-type=value-based -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt -S %loadPolly -basicaa -polly-dependences-analysis-type=value-based -polly-dce -polly-ast -analyze < %s | FileCheck %s -check-prefix=CHECK-DCE
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+;
+; for(i = 0; i < 200; i++ )
+;   A[i] = 2;
+;
+; for (i = 0; i < 200; i++ )
+;   A[i]  = 5;
+;
+; for (i = 0; i < 200; i++ )
+;   A[i] = 5;
+define void @main() nounwind uwtable {
+entry:
+  %A = alloca [200 x i32], align 16
+  br label %for.body.1
+
+for.body.1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %for.body.1 ]
+  %arrayidx.1 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.1
+  store i32 2, i32* %arrayidx.1, align 4
+  %indvar.next.1 = add i64 %indvar.1, 1
+  %exitcond.1 = icmp ne i64 %indvar.next.1, 200
+  br i1 %exitcond.1, label %for.body.1, label %exit.1
+
+exit.1:
+  br label %for.body.2
+
+for.body.2:
+  %indvar.2 = phi i64 [ 0, %exit.1 ], [ %indvar.next.2, %for.body.2 ]
+  %arrayidx.2 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.2
+  store i32 5, i32* %arrayidx.2, align 4
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %exitcond.2 = icmp ne i64 %indvar.next.2, 200
+  br i1 %exitcond.2, label %for.body.2, label %exit.2
+
+exit.2:
+  br label %for.body.3
+
+for.body.3:
+  %indvar.3 = phi i64 [ 0, %exit.2 ], [ %indvar.next.3, %for.body.3 ]
+  %arrayidx.3 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.3
+  store i32 7, i32* %arrayidx.3, align 4
+  %indvar.next.3 = add i64 %indvar.3, 1
+  %exitcond.3 = icmp ne i64 %indvar.next.3, 200
+  br i1 %exitcond.3, label %for.body.3 , label %exit.3
+
+exit.3:
+  ret void
+}
+
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_1(c0);
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_2(c0);
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_3(c0);
+
+; CHECK-DCE: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK-DCE:   Stmt_for_body_3(c0);
+
diff --git a/final/test/DeadCodeElimination/chained_iterations_2.ll b/final/test/DeadCodeElimination/chained_iterations_2.ll
new file mode 100644
index 0000000..42e0617
--- /dev/null
+++ b/final/test/DeadCodeElimination/chained_iterations_2.ll
@@ -0,0 +1,65 @@
+; RUN: opt -S %loadPolly -basicaa -polly-dependences-analysis-type=value-based -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt -S %loadPolly -basicaa -polly-dependences-analysis-type=value-based -polly-dce -polly-ast -analyze < %s | FileCheck %s -check-prefix=CHECK-DCE
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+;
+; for(i = 0; i < 200; i++ )
+;   A[i] = 2;
+;
+; for (i = 0; i < 200; i++ )
+;   B[i] = A[i];
+;
+; for (i = 0; i < 200; i++ )
+;   B[i] = A[i] = 5;
+define void @main() nounwind uwtable {
+entry:
+  %A = alloca [200 x i32], align 16
+  %B = alloca [200 x i32], align 16
+  br label %for.body.1
+
+for.body.1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %for.body.1 ]
+  %arrayidx.1 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.1
+  store i32 2, i32* %arrayidx.1, align 4
+  %indvar.next.1 = add i64 %indvar.1, 1
+  %exitcond.1 = icmp ne i64 %indvar.next.1, 200
+  br i1 %exitcond.1, label %for.body.1, label %exit.1
+
+exit.1:
+  br label %for.body.2
+
+for.body.2:
+  %indvar.2 = phi i64 [ 0, %exit.1 ], [ %indvar.next.2, %for.body.2 ]
+  %arrayidx.2.a = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.2
+  %val = load i32, i32* %arrayidx.2.a, align 4
+  %arrayidx.2.b = getelementptr [200 x i32], [200 x i32]* %B, i64 0, i64 %indvar.2
+  store i32 %val, i32* %arrayidx.2.b, align 4
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %exitcond.2 = icmp ne i64 %indvar.next.2, 200
+  br i1 %exitcond.2, label %for.body.2, label %exit.2
+
+exit.2:
+  br label %for.body.3
+
+for.body.3:
+  %indvar.3 = phi i64 [ 0, %exit.2 ], [ %indvar.next.3, %for.body.3 ]
+  %arrayidx.3.a = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.3
+  %arrayidx.3.b = getelementptr [200 x i32], [200 x i32]* %B, i64 0, i64 %indvar.3
+  store i32 5, i32* %arrayidx.3.a, align 4
+  store i32 5, i32* %arrayidx.3.b, align 4
+  %indvar.next.3 = add i64 %indvar.3, 1
+  %exitcond.3 = icmp ne i64 %indvar.next.3, 200
+  br i1 %exitcond.3, label %for.body.3 , label %exit.3
+
+exit.3:
+  ret void
+}
+
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_1(c0);
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_2(c0);
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_3(c0);
+
+; CHECK-DCE: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK-DCE:   Stmt_for_body_3(c0);
diff --git a/final/test/DeadCodeElimination/computeout.ll b/final/test/DeadCodeElimination/computeout.ll
new file mode 100644
index 0000000..21d3c02
--- /dev/null
+++ b/final/test/DeadCodeElimination/computeout.ll
@@ -0,0 +1,63 @@
+; RUN: opt -S %loadPolly -basicaa -polly-dce -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt -S %loadPolly -basicaa -polly-dce -polly-ast -analyze -polly-dependences-computeout=1 < %s | FileCheck %s -check-prefix=TIMEOUT
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+;     for(i = 0; i < 100; i++ )
+; S1:   A[i] = 2;
+;
+;     for (i = 0; i < 10; i++ )
+; S2:   A[i]  = 5;
+;
+;     for (i = 0; i < 200; i++ )
+; S3:   A[i] = 5;
+
+define void @sequential_writes() {
+entry:
+  %A = alloca [200 x i32]
+  br label %S1
+
+S1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %S1 ]
+  %arrayidx.1 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.1
+  store i32 2, i32* %arrayidx.1
+  %indvar.next.1 = add i64 %indvar.1, 1
+  %exitcond.1 = icmp ne i64 %indvar.next.1, 100
+  br i1 %exitcond.1, label %S1, label %exit.1
+
+exit.1:
+  br label %S2
+
+S2:
+  %indvar.2 = phi i64 [ 0, %exit.1 ], [ %indvar.next.2, %S2 ]
+  %arrayidx.2 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.2
+  store i32 5, i32* %arrayidx.2
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %exitcond.2 = icmp ne i64 %indvar.next.2, 10
+  br i1 %exitcond.2, label %S2, label %exit.2
+
+exit.2:
+  br label %S3
+
+S3:
+  %indvar.3 = phi i64 [ 0, %exit.2 ], [ %indvar.next.3, %S3 ]
+  %arrayidx.3 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.3
+  store i32 7, i32* %arrayidx.3
+  %indvar.next.3 = add i64 %indvar.3, 1
+  %exitcond.3 = icmp ne i64 %indvar.next.3, 200
+  br i1 %exitcond.3, label %S3 , label %exit.3
+
+exit.3:
+  ret void
+}
+
+; CHECK-NOT: Stmt_S
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK: Stmt_S3(c0);
+
+; TIMEOUT: for (int c0 = 0; c0 <= 99; c0 += 1)
+; TIMEOUT: Stmt_S1(c0);
+; TIMEOUT: for (int c0 = 0; c0 <= 9; c0 += 1)
+; TIMEOUT: Stmt_S2(c0);
+; TIMEOUT: for (int c0 = 0; c0 <= 199; c0 += 1)
+; TIMEOUT: Stmt_S3(c0);
+
diff --git a/final/test/DeadCodeElimination/dead_iteration_elimination.ll b/final/test/DeadCodeElimination/dead_iteration_elimination.ll
new file mode 100644
index 0000000..b9d935c
--- /dev/null
+++ b/final/test/DeadCodeElimination/dead_iteration_elimination.ll
@@ -0,0 +1,78 @@
+; RUN: opt -S %loadPolly -basicaa -polly-dependences-analysis-type=value-based -polly-dce -polly-dce-precise-steps=2 -polly-ast -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+;
+; for(i = 0; i < 200; i++ )
+;   A[i] = 2;
+;
+; for (i = 0; i < 50; i++ )
+;   A[i]  = 5;
+;
+; for (i = 0; i < 70; i++ )
+;   A[i] = A[i] + 5;
+;
+; for (i = 100; i < 110; i++ )
+;   A[i] = i;
+;
+define void @main() nounwind uwtable {
+entry:
+  %A = alloca [200 x i32], align 16
+  br label %for.body.1
+
+for.body.1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %for.body.1 ]
+  %arrayidx.1 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.1
+  store i32 2, i32* %arrayidx.1, align 4
+  %indvar.next.1 = add i64 %indvar.1, 1
+  %exitcond.1 = icmp ne i64 %indvar.next.1, 200
+  br i1 %exitcond.1, label %for.body.1, label %exit.1
+
+exit.1:
+  br label %for.body.2
+
+for.body.2:
+  %indvar.2 = phi i64 [ 0, %exit.1 ], [ %indvar.next.2, %for.body.2 ]
+  %arrayidx.2 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.2
+  store i32 5, i32* %arrayidx.2, align 4
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %exitcond.2 = icmp ne i64 %indvar.next.2, 50
+  br i1 %exitcond.2, label %for.body.2, label %exit.2
+
+exit.2:
+  br label %for.body.3
+
+for.body.3:
+  %indvar.3 = phi i64 [ 0, %exit.2 ], [ %indvar.next.3, %for.body.3 ]
+  %arrayidx.3 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.3
+  %val = load i32, i32* %arrayidx.3, align 4
+  %add = add nsw i32 %val, 5
+  store i32 %add, i32* %arrayidx.3, align 4
+  %indvar.next.3 = add i64 %indvar.3, 1
+  %exitcond.3 = icmp ne i64 %indvar.next.3, 70
+  br i1 %exitcond.3, label %for.body.3 , label %exit.3
+
+exit.3:
+  br label %for.body.4
+
+for.body.4:
+  %indvar.4 = phi i64 [ 0, %exit.3 ], [ %indvar.next.4, %for.body.4 ]
+  %indvar.plus = add i64 %indvar.4, 100
+  %trunc = trunc i64 %indvar.plus to i32
+  %arrayidx.4 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.plus
+  store i32 %trunc, i32* %arrayidx.4, align 4
+  %indvar.next.4 = add i64 %indvar.4, 1
+  %exitcond.4 = icmp ne i64 %indvar.next.4, 10
+  br i1 %exitcond.4, label %for.body.4, label %exit.4
+
+exit.4:
+  ret void
+}
+
+; CHECK: for (int c0 = 50; c0 <= 99; c0 += 1)
+; CHECK:   Stmt_for_body_1(c0);
+; CHECK: for (int c0 = 110; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_1(c0);
+; CHECK: for (int c0 = 0; c0 <= 49; c0 += 1)
+; CHECK:   Stmt_for_body_2(c0);
+; CHECK: for (int c0 = 0; c0 <= 69; c0 += 1)
+; CHECK:   Stmt_for_body_3(c0);
+; CHECK: for (int c0 = 0; c0 <= 9; c0 += 1)
diff --git a/final/test/DeadCodeElimination/non-affine-affine-mix.ll b/final/test/DeadCodeElimination/non-affine-affine-mix.ll
new file mode 100644
index 0000000..f0f6ac4
--- /dev/null
+++ b/final/test/DeadCodeElimination/non-affine-affine-mix.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-allow-nonaffine -polly-dce -polly-ast -analyze < %s | FileCheck %s
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++)
+; S1:    A[bar(i)] = i;
+;      for (int i = 0; i < 1024; i++)
+; S2:    A[i2] = i;
+;    }
+
+; We unfortunately do need to execute all iterations of S1, as we do not know
+; the size of A and as a result S1 may write for example to A[1024], which
+; is not overwritten by S2.
+
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK:   Stmt_S1(c0);
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK:   Stmt_S2(c0);
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+declare i32 @bar(i32) #1
+
+define void @f(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %S1, label %next
+
+S1:
+  %nonaff = call i32 @bar(i32 %i.0)
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %nonaff
+  store i32 %i.0, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+next:
+ br label %for.cond.2
+
+for.cond.2:
+  %i.2 = phi i32 [ 0, %next ], [ %inc.2, %for.inc.2 ]
+  %exitcond.2 = icmp ne i32 %i.2, 1024
+  br i1 %exitcond.2, label %S2, label %for.end
+
+S2:
+  %arrayidx.2 = getelementptr inbounds i32, i32* %A, i32 %i.2
+  store i32 %i.2, i32* %arrayidx.2, align 4
+  br label %for.inc.2
+
+for.inc.2:
+  %inc.2 = add nsw i32 %i.2, 1
+  br label %for.cond.2
+
+for.end:
+  ret void
+}
+
+attributes #1 = { nounwind readnone }
+
diff --git a/final/test/DeadCodeElimination/non-affine.ll b/final/test/DeadCodeElimination/non-affine.ll
new file mode 100644
index 0000000..4bc33eb
--- /dev/null
+++ b/final/test/DeadCodeElimination/non-affine.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-allow-nonaffine -polly-dce -polly-ast -analyze < %s | FileCheck %s
+;
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1)
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        A[bar(i)] = i;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+declare i32 @bar(i32) #1
+
+define void @f(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %nonaff = call i32 @bar(i32 %i.0)
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %nonaff
+  store i32 %i.0, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+attributes #1 = { nounwind readnone }
diff --git a/final/test/DeadCodeElimination/null_schedule.ll b/final/test/DeadCodeElimination/null_schedule.ll
new file mode 100644
index 0000000..26d7b4f
--- /dev/null
+++ b/final/test/DeadCodeElimination/null_schedule.ll
@@ -0,0 +1,56 @@
+; RUN: opt -S %loadPolly -basicaa -polly-dependences-analysis-type=value-based -polly-dce -polly-ast -analyze < %s | FileCheck %s -check-prefix=CHECK-DCE
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+; A[0] = 1;
+;
+; for(i = 0; i < 100; i++ )
+;   A[i+1] = A[i] * 2;
+;
+; for (i = 0; i < 200; i++ )
+;   A[i] = B[i] * 2;
+
+define void @main() nounwind uwtable {
+
+entry:
+  %A = alloca [200 x i32], align 16
+  %B = alloca [200 x i32], align 16
+
+  %A.zero = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 0
+  store i32 1, i32* %A.zero, align 4
+
+  br label %for.body.1
+
+for.body.1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %for.body.1 ]
+  %indvar.next.1 = add i64 %indvar.1, 1
+
+  %A.current.1 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.1
+  %val1.1 = load i32, i32* %A.current.1, align 4
+  %val2.1 = mul i32 %val1.1, 2
+  %A.next.1 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.next.1
+  store i32 %val2.1, i32* %A.next.1, align 4
+
+  %exitcond.1 = icmp ne i64 %indvar.next.1, 100
+  br i1 %exitcond.1, label %for.body.1, label %exit.1
+
+exit.1:
+  br label %for.body.2
+
+for.body.2:
+  %indvar.2 = phi i64 [ 0, %exit.1 ], [ %indvar.next.2, %for.body.2 ]
+
+  %B.current.2 = getelementptr [200 x i32], [200 x i32]* %B, i64 0, i64 %indvar.2
+  %val1.2 = load i32, i32* %B.current.2, align 4
+  %val2.2 = mul i32 %val1.2, 2
+  %A.current.2 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.2
+  store i32 %val2.2, i32* %A.current.2, align 4
+
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %exitcond.2 = icmp ne i64 %indvar.next.2, 200
+  br i1 %exitcond.2, label %for.body.2, label %exit.3
+
+exit.3:
+  ret void
+}
+
+; CHECK-DCE: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK-DCE:   Stmt_for_body_2(c0);
diff --git a/final/test/DependenceInfo/computeout.ll b/final/test/DependenceInfo/computeout.ll
new file mode 100644
index 0000000..5f7fd37
--- /dev/null
+++ b/final/test/DependenceInfo/computeout.ll
@@ -0,0 +1,74 @@
+; RUN: opt -S %loadPolly -polly-dependences -analyze < %s | FileCheck %s -check-prefix=VALUE
+; RUN: opt -S %loadPolly -polly-function-dependences -analyze < %s | FileCheck %s -check-prefix=FUNC-VALUE
+; RUN: opt -S %loadPolly -polly-dependences -analyze -polly-dependences-computeout=1 < %s | FileCheck %s -check-prefix=TIMEOUT
+; RUN: opt -S %loadPolly -polly-function-dependences -analyze -polly-dependences-computeout=1 < %s | FileCheck %s -check-prefix=TIMEOUT
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+;     for(i = 0; i < 100; i++ )
+; S1:   A[i] = 2;
+;
+;     for (i = 0; i < 10; i++ )
+; S2:   A[i]  = 5;
+;
+;     for (i = 0; i < 200; i++ )
+; S3:   A[i] = 5;
+
+define void @sequential_writes() {
+entry:
+  %A = alloca [200 x i32]
+  br label %S1
+
+S1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %S1 ]
+  %arrayidx.1 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.1
+  store i32 2, i32* %arrayidx.1
+  %indvar.next.1 = add i64 %indvar.1, 1
+  %exitcond.1 = icmp ne i64 %indvar.next.1, 100
+  br i1 %exitcond.1, label %S1, label %exit.1
+
+exit.1:
+  br label %S2
+
+S2:
+  %indvar.2 = phi i64 [ 0, %exit.1 ], [ %indvar.next.2, %S2 ]
+  %arrayidx.2 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.2
+  store i32 5, i32* %arrayidx.2
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %exitcond.2 = icmp ne i64 %indvar.next.2, 10
+  br i1 %exitcond.2, label %S2, label %exit.2
+
+exit.2:
+  br label %S3
+
+S3:
+  %indvar.3 = phi i64 [ 0, %exit.2 ], [ %indvar.next.3, %S3 ]
+  %arrayidx.3 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.3
+  store i32 7, i32* %arrayidx.3
+  %indvar.next.3 = add i64 %indvar.3, 1
+  %exitcond.3 = icmp ne i64 %indvar.next.3, 200
+  br i1 %exitcond.3, label %S3 , label %exit.3
+
+exit.3:
+  ret void
+}
+
+; VALUE:      RAW dependences:
+; VALUE-NEXT:     {  }
+; VALUE-NEXT: WAR dependences:
+; VALUE-NEXT:     {  }
+; VALUE-NEXT: WAW dependences:
+; VALUE-NEXT:     { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 }
+
+; FUNC-VALUE:      RAW dependences:
+; FUNC-VALUE-NEXT:     {  }
+; FUNC-VALUE-NEXT: WAR dependences:
+; FUNC-VALUE-NEXT:     {  }
+; FUNC-VALUE-NEXT: WAW dependences:
+; FUNC-VALUE-NEXT:     { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; [Stmt_S1[i0] -> Stmt_S1_Write0[]] -> [Stmt_S2[i0] -> Stmt_S2_Write0[]] : 0 <= i0 <= 9; Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; [Stmt_S2[i0] -> Stmt_S2_Write0[]] -> [Stmt_S3[i0] ->  Stmt_S3_Write0[]] : 0 <= i0 <= 9; [Stmt_S1[i0] -> Stmt_S1_Write0[]] ->  [Stmt_S3[i0] -> Stmt_S3_Write0[]] : 10 <= i0 <= 99; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 }
+
+; TIMEOUT:      RAW dependences:
+; TIMEOUT-NEXT:     n/a
+; TIMEOUT-NEXT: WAR dependences:
+; TIMEOUT-NEXT:     n/a
+; TIMEOUT-NEXT: WAW dependences:
+; TIMEOUT-NEXT:     n/a
diff --git a/final/test/DependenceInfo/different_schedule_dimensions.ll b/final/test/DependenceInfo/different_schedule_dimensions.ll
new file mode 100644
index 0000000..a9b818f
--- /dev/null
+++ b/final/test/DependenceInfo/different_schedule_dimensions.ll
@@ -0,0 +1,61 @@
+; RUN: opt -S %loadPolly -polly-dependences \
+; RUN:                   -analyze < %s | FileCheck %s
+; RUN: opt -S %loadPolly -polly-function-dependences \
+; RUN:                   -analyze < %s | FileCheck %s -check-prefix=FUNC
+
+; CHECK: RAW dependences:
+; CHECK:   { Stmt_bb9[0] -> Stmt_bb10[0] }
+; CHECK: WAR dependences:
+; CHECK:   { Stmt_bb3[0] -> Stmt_bb10[0] }
+; CHECK: WAW dependences:
+; CHECK:   { Stmt_bb3[0] -> Stmt_bb10[0] }
+; CHECK: Reduction dependences:
+; CHECK:   {  }
+
+; FUNC: RAW dependences:
+; FUNC-NEXT:   { Stmt_bb9[0] -> Stmt_bb10[0]; [Stmt_bb9[0] -> Stmt_bb9_Write0[]] -> [Stmt_bb10[0] -> Stmt_bb10_Read0[]] }
+; FUNC-NEXT: WAR dependences:
+; FUNC-NEXT:   { [Stmt_bb3[0] -> Stmt_bb3_Read0[]] -> [Stmt_bb10[0] -> Stmt_bb10_Write1[]]; Stmt_bb3[0] -> Stmt_bb10[0] }
+; FUNC-NEXT: WAW dependences:
+; FUNC-NEXT:   { Stmt_bb3[0] -> Stmt_bb10[0]; [Stmt_bb3[0] -> Stmt_bb3_Write1[]] -> [Stmt_bb10[0] -> Stmt_bb10_Write1[]] }
+; FUNC-NEXT: Reduction dependences:
+; FUNC-NEXT:   {  }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @hoge(i32 %arg, [1024 x double]* %arg1) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb
+  br label %bb3
+
+bb3:                                              ; preds = %bb10, %bb2
+  %tmp = phi i64 [ 0, %bb10 ], [ 0, %bb2 ]
+  %tmp4 = icmp sgt i32 %arg, 0
+  %tmp5 = getelementptr inbounds [1024 x double], [1024 x double]* %arg1, i64 0, i64 0
+  %tmp6 = load double, double* %tmp5, align 8
+  %tmp7 = fadd double undef, %tmp6
+  store double %tmp7, double* %tmp5, align 8
+  br i1 false, label %bb8, label %bb9
+
+bb8:                                              ; preds = %bb3
+  br label %bb10
+
+bb9:                                              ; preds = %bb3
+  br label %bb10
+
+bb10:                                             ; preds = %bb9, %bb8
+  %tmp11 = phi double [ undef, %bb8 ], [ undef, %bb9 ]
+  %tmp12 = getelementptr inbounds [1024 x double], [1024 x double]* %arg1, i64 %tmp, i64 0
+  store double %tmp11, double* %tmp12, align 8
+  %tmp13 = add nuw nsw i64 0, 1
+  %tmp14 = trunc i64 %tmp13 to i32
+  br i1 false, label %bb3, label %bb15
+
+bb15:                                             ; preds = %bb10
+  br label %bb16
+
+bb16:                                             ; preds = %bb15
+  ret void
+}
diff --git a/final/test/DependenceInfo/do_pluto_matmult.ll b/final/test/DependenceInfo/do_pluto_matmult.ll
new file mode 100644
index 0000000..20cc90e
--- /dev/null
+++ b/final/test/DependenceInfo/do_pluto_matmult.ll
@@ -0,0 +1,95 @@
+; RUN: opt %loadPolly -basicaa -polly-dependences -analyze -polly-dependences-analysis-type=value-based < %s | FileCheck %s -check-prefix=VALUE
+; RUN: opt %loadPolly -basicaa -polly-dependences -analyze -polly-dependences-analysis-type=memory-based < %s | FileCheck %s -check-prefix=MEMORY
+; RUN: opt %loadPolly -basicaa -polly-function-dependences -analyze -polly-dependences-analysis-type=value-based < %s | FileCheck %s -check-prefix=FUNC-VALUE
+; RUN: opt %loadPolly -basicaa -polly-function-dependences -analyze -polly-dependences-analysis-type=memory-based < %s | FileCheck %s -check-prefix=FUNC-MEMORY
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker = type { %struct._IO_marker*, %struct._IO_FILE*, i32 }
+
+@A = common global [36 x [49 x double]] zeroinitializer, align 8 ; <[36 x [49 x double]]*> [#uses=3]
+@B = common global [36 x [49 x double]] zeroinitializer, align 8 ; <[36 x [49 x double]]*> [#uses=3]
+@C = common global [36 x [49 x double]] zeroinitializer, align 8 ; <[36 x [49 x double]]*> [#uses=4]
+
+define void @do_pluto_matmult() nounwind {
+entry:
+  fence seq_cst
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond42, %entry
+  %indvar3 = phi i64 [ %indvar.next4, %do.cond42 ], [ 0, %entry ] ; <i64> [#uses=3]
+  br label %do.body1
+
+do.body1:                                         ; preds = %do.cond36, %do.body
+  %indvar1 = phi i64 [ %indvar.next2, %do.cond36 ], [ 0, %do.body ] ; <i64> [#uses=3]
+  %arrayidx5 = getelementptr [36 x [49 x double]], [36 x [49 x double]]* @C, i64 0, i64 %indvar3, i64 %indvar1 ; <double*> [#uses=2]
+  br label %do.body2
+
+do.body2:                                         ; preds = %do.cond, %do.body1
+  %indvar = phi i64 [ %indvar.next, %do.cond ], [ 0, %do.body1 ] ; <i64> [#uses=3]
+  %arrayidx13 = getelementptr [36 x [49 x double]], [36 x [49 x double]]* @A, i64 0, i64 %indvar3, i64 %indvar ; <double*> [#uses=1]
+  %arrayidx22 = getelementptr [36 x [49 x double]], [36 x [49 x double]]* @B, i64 0, i64 %indvar, i64 %indvar1 ; <double*> [#uses=1]
+  %tmp6 = load double, double* %arrayidx5                 ; <double> [#uses=1]
+  %mul = fmul double 1.000000e+00, %tmp6          ; <double> [#uses=1]
+  %tmp14 = load double, double* %arrayidx13               ; <double> [#uses=1]
+  %mul15 = fmul double 1.000000e+00, %tmp14       ; <double> [#uses=1]
+  %tmp23 = load double, double* %arrayidx22               ; <double> [#uses=1]
+  %mul24 = fmul double %mul15, %tmp23             ; <double> [#uses=1]
+  %add = fadd double %mul, %mul24                 ; <double> [#uses=1]
+  store double %add, double* %arrayidx5
+  br label %do.cond
+
+do.cond:                                          ; preds = %do.body2
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=2]
+  %exitcond = icmp ne i64 %indvar.next, 36        ; <i1> [#uses=1]
+  br i1 %exitcond, label %do.body2, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  br label %do.cond36
+
+do.cond36:                                        ; preds = %do.end
+  %indvar.next2 = add i64 %indvar1, 1             ; <i64> [#uses=2]
+  %exitcond5 = icmp ne i64 %indvar.next2, 36      ; <i1> [#uses=1]
+  br i1 %exitcond5, label %do.body1, label %do.end39
+
+do.end39:                                         ; preds = %do.cond36
+  br label %do.cond42
+
+do.cond42:                                        ; preds = %do.end39
+  %indvar.next4 = add i64 %indvar3, 1             ; <i64> [#uses=2]
+  %exitcond6 = icmp ne i64 %indvar.next4, 36      ; <i1> [#uses=1]
+  br i1 %exitcond6, label %do.body, label %do.end45
+
+do.end45:                                         ; preds = %do.cond42
+  fence seq_cst
+  ret void
+}
+
+; VALUE:      RAW dependences:
+; VALUE-NEXT:     { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, 1 + i2] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and 0 <= i2 <= 34 }
+; VALUE-NEXT: WAR dependences:
+; VALUE-NEXT: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, 1 + i2] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and 0 <= i2 <= 34 }
+; VALUE-NEXT: WAW dependences:
+; VALUE-NEXT:     { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, 1 + i2] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and 0 <= i2 <= 34 }
+
+; MEMORY:      RAW dependences:
+; MEMORY-NEXT:     { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and i2 >= 0 and i2 < o2 <= 35 }
+; MEMORY-NEXT: WAR dependences:
+; MEMORY-NEXT:     { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and i2 >= 0 and i2 < o2 <= 35 }
+; MEMORY-NEXT: WAW dependences:
+; MEMORY-NEXT:     { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and i2 >= 0 and i2 < o2 <= 35 }
+
+; FUNC-VALUE:      RAW dependences:
+; FUNC-VALUE-NEXT:     { [Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2_Write3[]] -> [Stmt_do_body2[i0, i1, 1 + i2] -> Stmt_do_body2_Read0[]] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and 0 <= i2 <= 34; Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, 1 + i2] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and 0 <= i2 <= 34 }
+; FUNC-VALUE-NEXT: WAR dependences:
+; FUNC-VALUE-NEXT:     { [Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2_Read0[]] -> [Stmt_do_body2[i0, i1, 1 + i2] -> Stmt_do_body2_Write3[]] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and 0 <= i2 <= 34; Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, 1 + i2] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and 0 <= i2 <= 34 }
+; FUNC-VALUE-NEXT: WAW dependences:
+; FUNC-VALUE-NEXT:     { [Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2_Write3[]] -> [Stmt_do_body2[i0, i1, 1 + i2] -> Stmt_do_body2_Write3[]] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and 0 <= i2 <= 34; Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, 1 + i2] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and 0 <= i2 <= 34 }
+
+; FUNC-MEMORY:      RAW dependences:
+; FUNC-MEMORY-NEXT:     { [Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2_Write3[]] -> [Stmt_do_body2[i0, i1, o2] -> Stmt_do_body2_Read0[]] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and i2 >= 0 and i2 < o2 <= 35; Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and i2 >= 0 and i2 < o2 <= 35 }
+; FUNC-MEMORY-NEXT: WAR dependences:
+; FUNC-MEMORY-NEXT:     { [Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2_Read0[]] -> [Stmt_do_body2[i0, i1, o2] -> Stmt_do_body2_Write3[]] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and i2 >= 0 and i2 < o2 <= 35; Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and i2 >= 0 and i2 < o2 <= 35 }
+; FUNC-MEMORY-NEXT: WAW dependences:
+; FUNC-MEMORY-NEXT:     { [Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2_Write3[]] -> [Stmt_do_body2[i0, i1, o2] -> Stmt_do_body2_Write3[]] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and i2 >= 0 and i2 < o2 <= 35; Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : 0 <= i0 <= 35 and 0 <= i1 <= 35 and i2 >= 0 and i2 < o2 <= 35 }
diff --git a/final/test/DependenceInfo/fine_grain_dep_0.ll b/final/test/DependenceInfo/fine_grain_dep_0.ll
new file mode 100644
index 0000000..0679c25
--- /dev/null
+++ b/final/test/DependenceInfo/fine_grain_dep_0.ll
@@ -0,0 +1,75 @@
+; RUN: opt %loadPolly -polly-dependences -polly-dependences-analysis-type=value-based -polly-dependences-analysis-level=reference-wise -analyze < %s | FileCheck %s --check-prefix=REF
+; RUN: opt %loadPolly -polly-dependences -polly-dependences-analysis-type=value-based -polly-dependences-analysis-level=access-wise -analyze < %s | FileCheck %s --check-prefix=ACC
+; RUN: opt %loadPolly -polly-function-dependences -polly-dependences-analysis-type=value-based -polly-dependences-analysis-level=access-wise -analyze < %s | FileCheck %s --check-prefix=ACC
+;
+; REF:      RAW dependences:
+; REF-NEXT:     [N] -> { Stmt_for_body[i0] -> Stmt_for_body[6 + i0] : 0 <= i0 <= -13 + N; Stmt_for_body[i0] -> Stmt_for_body[4 + i0] : 0 <= i0 <= -11 + N; [Stmt_for_body[i0] -> MemRef_a[]] -> [Stmt_for_body[4 + i0] -> MemRef_a[]] : 0 <= i0 <= -11 + N; [Stmt_for_body[i0] -> MemRef_b[]] -> [Stmt_for_body[6 + i0] -> MemRef_b[]] : 0 <= i0 <= -13 + N }
+; REF-NEXT: WAR dependences:
+; REF-NEXT:     {  }
+; REF-NEXT: WAW dependences:
+; REF-NEXT:     {  }
+; REF-NEXT: Reduction dependences:
+; REF-NEXT:     {  }
+
+; ACC:      RAW dependences:
+; ACC-NEXT:   [N] -> { Stmt_for_body[i0] -> Stmt_for_body[6 + i0] : 0 <= i0 <= -13 + N; Stmt_for_body[i0] -> Stmt_for_body[4 + i0] : 0 <= i0 <= -11 + N; [Stmt_for_body[i0] -> Stmt_for_body_Write1[]] -> [Stmt_for_body[4 + i0] -> Stmt_for_body_Read0[]] : 0 <= i0 <= -11 + N; [Stmt_for_body[i0] -> Stmt_for_body_Write3[]] -> [Stmt_for_body[6 + i0] -> Stmt_for_body_Read2[]] : 0 <= i0 <= -13 + N }
+
+; ACC-NEXT: WAR dependences:
+; ACC-NEXT:   [N] -> {  }
+; ACC-NEXT: WAW dependences:
+; ACC-NEXT:   [N] -> {  }
+; ACC-NEXT: Reduction dependences:
+; ACC-NEXT:   [N] -> {  }
+
+; void test(char a[], char b[], long N) {
+;   for (long i = 6; i < N; ++i) {
+;     a[i] = a[i - 4] + i;
+;     b[i] = b[i - 6] + i;
+;   }
+; }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @test(i8* %a, i8* %b, i64 %N) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 6, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp slt i64 %i.0, %N
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %sub = sub nsw i64 %i.0, 4
+  %arrayidx = getelementptr inbounds i8, i8* %a, i64 %sub
+  %0 = load i8, i8* %arrayidx, align 1
+  %conv = sext i8 %0 to i64
+  %add = add nsw i64 %conv, %i.0
+  %conv1 = trunc i64 %add to i8
+  %arrayidx2 = getelementptr inbounds i8, i8* %a, i64 %i.0
+  store i8 %conv1, i8* %arrayidx2, align 1
+  %sub3 = sub nsw i64 %i.0, 6
+  %arrayidx4 = getelementptr inbounds i8, i8* %b, i64 %sub3
+  %1 = load i8, i8* %arrayidx4, align 1
+  %conv5 = sext i8 %1 to i64
+  %add6 = add nsw i64 %conv5, %i.0
+  %conv7 = trunc i64 %add6 to i8
+  %arrayidx8 = getelementptr inbounds i8, i8* %b, i64 %i.0
+  store i8 %conv7, i8* %arrayidx8, align 1
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.9.0 (http://llvm.org/git/clang.git 3d5d4c39659f11dfbe8e11c857cadf5c449b559b) (http://llvm.org/git/llvm.git 801561e2bba12f2aa0285feb1105e110df443761)"}
diff --git a/final/test/DependenceInfo/generate_may_write_dependence_info.ll b/final/test/DependenceInfo/generate_may_write_dependence_info.ll
new file mode 100644
index 0000000..38274e2
--- /dev/null
+++ b/final/test/DependenceInfo/generate_may_write_dependence_info.ll
@@ -0,0 +1,67 @@
+; RUN: opt -S %loadPolly -polly-dependences -analyze < %s | FileCheck %s -check-prefix=VALUE
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+;                     for (int i = 0; i < N; i++) {
+; A.must.write.20:      A[i] = 20;
+;
+; compute.i.square:    if (i * i)
+; A.may.write.90:         A[i] = 90;
+;
+; B.write.from.A:       B[i] = A[i];
+; A.must.write.42:      A[i] = 42;
+;                     }
+define void @f(i32* %A, i32* %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 3000
+  br i1 %exitcond, label %A.must.write.20, label %for.end
+
+A.must.write.20:
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 20, i32* %arrayidx, align 4
+  br label %compute.i.square
+
+compute.i.square:
+  %tmp = mul nsw i64 %indvars.iv, %indvars.iv
+  %tmp2 = trunc i64 %tmp to i32
+  %tobool = icmp eq i32 %tmp2, 0
+  br i1 %tobool, label %B.write.from.A, label %A.may.write.90
+
+A.may.write.90:
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 90, i32* %arrayidx2, align 4
+  br label %B.write.from.A
+
+B.write.from.A:
+  %arrayidx4 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %arrayidx4, align 4
+  %arrayidx6 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  store i32 %tmp3, i32* %arrayidx6, align 4
+  br label %A.must.write.42
+  ; br label %for.inc
+
+A.must.write.42:
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 42, i32* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+; VALUE: RAW dependences:
+; VALUE-NEXT:   { Stmt_A_must_write_20[i0] -> Stmt_B_write_from_A[i0] : 0 <= i0 <= 2999; Stmt_compute_i_square__TO__B_write_from_A[i0] -> Stmt_B_write_from_A[i0] : 0 <= i0 <= 2999 }
+; VALUE-NEXT: WAR dependences:
+; VALUE-NEXT:   { Stmt_B_write_from_A[i0] -> Stmt_A_must_write_42[i0] : 0 <= i0 <= 2999 }
+; VALUE-NEXT: WAW dependences:
+; VALUE-NEXT:   { Stmt_compute_i_square__TO__B_write_from_A[i0] -> Stmt_A_must_write_42[i0] : 0 <= i0 <= 2999; Stmt_A_must_write_20[i0] -> Stmt_A_must_write_42[i0] : 0 <= i0 <= 2999; Stmt_A_must_write_20[i0] -> Stmt_compute_i_square__TO__B_write_from_A[i0] : 0 <= i0 <= 2999 }
+; VALUE-NEXT: Reduction dependences:
+; VALUE-NEXT:   {  }
+; VALUE-NEXT: Transitive closure of reduction dependences:
+; VALUE-NEXT:   {  }
diff --git a/final/test/DependenceInfo/infeasible_context.ll b/final/test/DependenceInfo/infeasible_context.ll
new file mode 100644
index 0000000..a111ed0
--- /dev/null
+++ b/final/test/DependenceInfo/infeasible_context.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-function-scops -analyze < %s \
+; RUN:  | FileCheck %s -check-prefix=FUNC-SCOP
+; RUN: opt %loadPolly -polly-function-dependences -analyze < %s \
+; RUN:  | FileCheck %s -check-prefix=FUNC-DEPS
+;
+; FUNC-SCOP-NOT: Statement
+; FUNC-DEPS-LABEL: Printing analysis 'Polly - Calculate dependences for all the SCoPs of a function' for function 'readgeo'
+; FUNC-DEPS-NOT: RAW dependences
+;
+; Due to an infeasible run-time check, scop object is empty and we do not compute dependences.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739 = type { i32, i32, %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, i32, i32, %struct.plist.0.6.12.66.120.174.216.306.324.336.348.366.378.390.432.444.666.726.732.738* }
+%struct.plist.0.6.12.66.120.174.216.306.324.336.348.366.378.390.432.444.666.726.732.738 = type { i32, %struct.plist.0.6.12.66.120.174.216.306.324.336.348.366.378.390.432.444.666.726.732.738* }
+
+@vFixedEdgeRoot = external global %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, align 8
+@hEdgeRoot = external global %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, align 8
+
+; Function Attrs: nounwind uwtable
+define void @readgeo() #0 {
+entry:
+  %vx = alloca i32, align 4
+  br label %if.end64
+
+if.end64:                                         ; preds = %entry
+  br label %for.body73
+
+for.body73:                                       ; preds = %for.inc216, %if.end64
+  %v.0101 = phi i32 [ 0, %for.inc216 ], [ 1, %if.end64 ]
+  br i1 undef, label %if.then93, label %if.else
+
+if.then93:                                        ; preds = %for.body73
+  br label %for.inc216
+
+if.else:                                          ; preds = %for.body73
+  br i1 undef, label %if.then111, label %if.end116
+
+if.then111:                                       ; preds = %if.else
+  br label %if.end116
+
+if.end116:                                        ; preds = %if.then111, %if.else
+  %rippleCount.2 = phi i32 [ 1, %if.then111 ], [ undef, %if.else ]
+  %rem11790 = and i32 %v.0101, 1
+  %cmp118 = icmp eq i32 %rem11790, 0
+  br i1 %cmp118, label %if.then120, label %if.else154
+
+if.then120:                                       ; preds = %if.end116
+  call void @tinsert()
+  br label %if.end193
+
+if.else154:                                       ; preds = %if.end116
+  call void @tinsert()
+  br label %if.end193
+
+if.end193:                                        ; preds = %if.else154, %if.then120
+  %0 = load i32, i32* %vx, align 4
+  br label %for.inc216
+
+for.inc216:                                       ; preds = %if.end193, %if.then93
+  %rippleCount.3 = phi i32 [ undef, %if.then93 ], [ %rippleCount.2, %if.end193 ]
+  %ux.2 = phi i32 [ undef, %if.then93 ], [ %0, %if.end193 ]
+  br i1 undef, label %for.body73, label %for.end218
+
+for.end218:                                       ; preds = %for.inc216
+  unreachable
+}
+
+declare void @tinsert()
diff --git a/final/test/DependenceInfo/may_writes_do_not_block_must_writes_for_war.ll b/final/test/DependenceInfo/may_writes_do_not_block_must_writes_for_war.ll
new file mode 100644
index 0000000..858743b
--- /dev/null
+++ b/final/test/DependenceInfo/may_writes_do_not_block_must_writes_for_war.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+;
+; Verify that the presence of a may-write (S1) between a read (S0) and a
+; must-write (S2) does not block the generation of RAW dependences. This makes
+; sure that we capture as many RAW dependences as possible.
+;
+; For this example, we want both (S0(Read) -> S1 (May-Write)) as well as
+; (S0(Read) -> S2(Must-Write)).
+;
+; CHECK: WAR dependences:
+; CHECK-NEXT:     { Stmt_S0[i0] -> Stmt_S2[i0] : 0 < i0 <= 2; Stmt_S0[i0] -> Stmt_if_end__TO__S2[i0] : 0 < i0 <= 2 }
+;
+;
+;    static const int N = 3000;
+;
+;    void f(int *sum, int *A, int *B, int *out) {
+;      for (int i = 0; i <= 2; i++) {
+;        if (i) {
+; S0:          *out += *sum;
+;        }
+;
+;        if (i * i) {
+; S1:          *sum = *A;
+;        }
+; S2:        *sum = *B;
+;      }
+;    }
+;
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %sum, i32* %A, i32* %B, i32* %out) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 3
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tobool = icmp eq i32 %i.0, 0
+  br i1 %tobool, label %if.end, label %S0
+
+S0:                                          ; preds = %for.body
+  %tmp = load i32, i32* %sum, align 4
+  %tmp1 = load i32, i32* %out, align 4
+  %add = add nsw i32 %tmp1, %tmp
+  store i32 %add, i32* %out, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %for.body, %S0
+  %mul = mul nsw i32 %i.0, %i.0
+  %tobool1 = icmp eq i32 %mul, 0
+  br i1 %tobool1, label %S2, label %S1
+
+S1:                                         ; preds = %if.end
+  %tmp2 = load i32, i32* %A, align 4
+  store i32 %tmp2, i32* %sum, align 4
+  br label %S2
+
+S2:                                          ; preds = %if.end, %S1
+  %tmp3 = load i32, i32* %B, align 4
+  store i32 %tmp3, i32* %sum, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S2
+  %inc = add nuw nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
diff --git a/final/test/DependenceInfo/nonaffine-condition-buildMemoryAccess.ll b/final/test/DependenceInfo/nonaffine-condition-buildMemoryAccess.ll
new file mode 100644
index 0000000..a228ca4
--- /dev/null
+++ b/final/test/DependenceInfo/nonaffine-condition-buildMemoryAccess.ll
@@ -0,0 +1,74 @@
+; RUN: opt %loadPolly -polly-codegen -polly-allow-nonaffine-loops -polly-allow-nonaffine -debug-only=polly-dependence < %s 2>&1 | FileCheck %s 
+; REQUIRES: asserts
+
+; CHECK:        MayWriteAccess :=   [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       { Stmt_for_body__TO__for_inc11[i0] -> MemRef_A[o0] : 0 <= o0 <= 699 };
+; CHECK-NEXT:   MayWriteAccess :=   [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       { Stmt_for_body__TO__for_inc11[i0] -> MemRef_B[700] };
+
+; The if condition C[i] is a non-affine condition, which make the nested loop boxed. The memory access for A should be a range A[0...699]. The memory access for B should be simplified to B[700].
+;
+; int A[1000], B[1000], C[1000];
+;
+; void foo(int n, int m, int N) {
+;   for (int i = 0; i < 500; i+=1) { /* affine loop */
+;      C[i] += i;
+;      if (C[i]) { /* non-affine subregion */
+;          int j;
+;          for (j = 0; j < 700; j+=1) { /* boxed loop */
+;            A[j] = 1;
+;          }
+;          B[j] = 2;
+;      }
+;    }
+; }
+
+
+target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
+
+@C = common global [1000 x i32] zeroinitializer, align 4
+@A = common global [1000 x i32] zeroinitializer, align 4
+@B = common global [1000 x i32] zeroinitializer, align 4
+
+; Function Attrs: norecurse nounwind
+define void @foo(i32 %n, i32 %m, i32 %N) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.cond.cleanup:                                 ; preds = %for.inc11
+  ret void
+
+for.body:                                         ; preds = %for.inc11, %entry.split
+  %indvars.iv25 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next26, %for.inc11 ]
+  %arrayidx = getelementptr inbounds [1000 x i32], [1000 x i32]* @C, i64 0, i64 %indvars.iv25
+  %0 = load i32, i32* %arrayidx, align 4
+  %1 = trunc i64 %indvars.iv25 to i32
+  %add = add nsw i32 %0, %1
+  store i32 %add, i32* %arrayidx, align 4
+  %tobool = icmp eq i32 %add, 0
+  br i1 %tobool, label %for.inc11, label %for.body5.preheader
+
+for.body5.preheader:                              ; preds = %for.body
+  br label %for.body5
+
+for.body5:                                        ; preds = %for.body5.preheader, %for.body5
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.body5 ], [ 0, %for.body5.preheader ]
+  %arrayidx7 = getelementptr inbounds [1000 x i32], [1000 x i32]* @A, i64 0, i64 %indvars.iv
+  store i32 1, i32* %arrayidx7, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv, 699
+  br i1 %exitcond, label %for.end, label %for.body5
+
+for.end:                                          ; preds = %for.body5
+  store i32 2, i32* getelementptr inbounds ([1000 x i32], [1000 x i32]* @B, i64 0, i64 700), align 4
+  br label %for.inc11
+
+for.inc11:                                        ; preds = %for.body, %for.end
+  %indvars.iv.next26 = add nuw nsw i64 %indvars.iv25, 1
+  %exitcond27 = icmp eq i64 %indvars.iv25, 499
+  br i1 %exitcond27, label %for.cond.cleanup, label %for.body
+}
+
diff --git a/final/test/DependenceInfo/reduction_complex_location.ll b/final/test/DependenceInfo/reduction_complex_location.ll
new file mode 100644
index 0000000..7d0f263
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_complex_location.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-dependences -polly-dependences-analysis-level=reference-wise -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-dependences -polly-dependences-analysis-level=access-wise -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_for_body3[i0, i1] -> Stmt_for_body3[2 + i0, -1 + i1] : 0 <= i0 <= 97 and 0 < i1 <= 99 }
+;
+; void f(int *sum) {
+;   for (int i = 0; i < 100; i++)
+;     for (int j = 0; j < 100; j++)
+;       sum[i+j*2] += j * i;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc6, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc7, %for.inc6 ]
+  %exitcond1 = icmp ne i32 %i.0, 100
+  br i1 %exitcond1, label %for.body, label %for.end8
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 100
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %mul = mul nsw i32 %j.0, %i.0
+  %mul4 = shl nsw i32 %j.0, 1
+  %add = add nsw i32 %i.0, %mul4
+  %arrayidx = getelementptr inbounds i32, i32* %sum, i32 %add
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add5 = add nsw i32 %tmp, %mul
+  store i32 %add5, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc6
+
+for.inc6:                                         ; preds = %for.end
+  %inc7 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end8:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_dependences_equal_non_reduction_dependences.ll b/final/test/DependenceInfo/reduction_dependences_equal_non_reduction_dependences.ll
new file mode 100644
index 0000000..1353616
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_dependences_equal_non_reduction_dependences.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -basicaa -polly-dependences -analyze < %s | FileCheck %s
+;
+; This loopnest contains a reduction which imposes the same dependences as the
+; accesses to the array A. We need to ensure we keep the dependences of A.
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     { Stmt_for_body[i0] -> Stmt_for_body[1 + i0] : 0 <= i0 <= 1022 }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     { Stmt_for_body[i0] -> Stmt_for_body[1 + i0] : 0 <= i0 <= 1022 }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     { Stmt_for_body[i0] -> Stmt_for_body[1 + i0] : 0 <= i0 <= 1022 }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_for_body[i0] -> Stmt_for_body[1 + i0] : 0 <= i0 <= 1022 }
+;
+;
+;    void AandSum(int *restrict sum, int *restrict A) {
+;      for (int i = 0; i < 1024; i++) {
+;        A[i] = A[i] + A[i - 1];
+;        A[i - 1] = A[i] + A[i - 2];
+;        *sum += i;
+;      }
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @AandSum(i32* noalias %sum, i32* noalias %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %sub = add nsw i32 %i.0, -1
+  %arrayidx1 = getelementptr inbounds i32, i32* %A, i32 %sub
+  %tmp1 = load i32, i32* %arrayidx1, align 4
+  %add = add nsw i32 %tmp, %tmp1
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i32 %i.0
+  store i32 %add, i32* %arrayidx2, align 4
+  %sub4 = add nsw i32 %i.0, -2
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i32 %sub4
+  %tmp2 = load i32, i32* %arrayidx5, align 4
+  %add6 = add nsw i32 %add, %tmp2
+  %sub7 = add nsw i32 %i.0, -1
+  %arrayidx8 = getelementptr inbounds i32, i32* %A, i32 %sub7
+  store i32 %add6, i32* %arrayidx8, align 4
+  %tmp3 = load i32, i32* %sum, align 4
+  %add9 = add nsw i32 %tmp3, %i.0
+  store i32 %add9, i32* %sum, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_dependences_not_null.ll b/final/test/DependenceInfo/reduction_dependences_not_null.ll
new file mode 100644
index 0000000..f8e67af
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_dependences_not_null.ll
@@ -0,0 +1,34 @@
+; Test that the reduction dependences are always initialised, even in a case
+; where we have no reduction. If this object is NULL, then isl operations on
+; it will fail.
+; RUN: opt -S %loadPolly -polly-dependences -analyze < %s | FileCheck %s -check-prefix=VALUE
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+;     for(i = 0; i < 100; i++ )
+; S1:   A[i] = 2;
+
+define void @sequential_writes() {
+entry:
+  %A = alloca [200 x i32]
+  br label %S1
+
+S1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %S1 ]
+  %arrayidx.1 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.1
+  store i32 2, i32* %arrayidx.1
+  %indvar.next.1 = add i64 %indvar.1, 1
+  %exitcond.1 = icmp ne i64 %indvar.next.1, 100
+  br i1 %exitcond.1, label %S1, label %exit.1
+
+exit.1:
+  ret void
+}
+
+; VALUE:      RAW dependences:
+; VALUE-NEXT:     {  }
+; VALUE-NEXT: WAR dependences:
+; VALUE-NEXT:     {  }
+; VALUE-NEXT: WAW dependences:
+; VALUE-NEXT:     {  }
+; VALUE-NEXT: Reduction dependences:
+; VALUE-NEXT:     {  }
diff --git a/final/test/DependenceInfo/reduction_mixed_reduction_and_non_reduction_dependences.ll b/final/test/DependenceInfo/reduction_mixed_reduction_and_non_reduction_dependences.ll
new file mode 100644
index 0000000..11bd167
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_mixed_reduction_and_non_reduction_dependences.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     { Stmt_for_body3[i0, i1] -> Stmt_for_body3[i0 + i1, o1] : i0 >= 0 and 0 <= i1 <= 1023 - i0 and i1 <= 1 and 0 < o1 <= 511 }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     { Stmt_for_body3[i0, i1] -> Stmt_for_body3[1 + i0, -1 + i1] : 0 <= i0 <= 1022 and 2 <= i1 <= 511; Stmt_for_body3[i0, 2] -> Stmt_for_body3[2 + i0, 0] : 0 <= i0 <= 1021 }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_for_body3[i0, 1] -> Stmt_for_body3[1 + i0, 0] : 0 <= i0 <= 1022 }
+;
+; void f(int *sum) {
+;   for (int i = 0; i < 1024; i++)
+;     for (int j = 0; j < 512; j++)
+;       sum[i + j] = sum[i] + 3;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc6, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc7, %for.inc6 ]
+  %exitcond1 = icmp ne i32 %i.0, 1024
+  br i1 %exitcond1, label %for.body, label %for.end8
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 512
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %sum, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 3
+  %add4 = add nsw i32 %i.0, %j.0
+  %arrayidx5 = getelementptr inbounds i32, i32* %sum, i32 %add4
+  store i32 %add, i32* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc6
+
+for.inc6:                                         ; preds = %for.end
+  %inc7 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end8:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_multiple_loops_array_sum.ll b/final/test/DependenceInfo/reduction_multiple_loops_array_sum.ll
new file mode 100644
index 0000000..db1bdca
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_multiple_loops_array_sum.ll
@@ -0,0 +1,79 @@
+; RUN: opt -basicaa %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+; RUN: opt -basicaa %loadPolly -polly-dependences -polly-dependences-analysis-level=reference-wise -analyze < %s | FileCheck %s
+; RUN: opt -basicaa %loadPolly -polly-dependences -polly-dependences-analysis-level=access-wise -analyze < %s | FileCheck %s
+;
+; Verify that only the inner reduction like accesses cause reduction dependences
+;
+; CHECK:      Reduction dependences:
+; CHECK-NEXT:     { Stmt_for_body3[i0, i1] -> Stmt_for_body3[i0, 1 + i1] : 0 <= i0 <= 99 and 0 <= i1 <= 98 }
+;
+; void f(int * restrict A, int * restrict sum) {
+;   int i, j, k;
+;   for (i = 0; i < 100; i++) {
+;     *sum *= 7;
+;     for (j = 0; j < 100; j++) {
+;       *sum += A[i+j];
+;       for (k = 0; k< 100; k++) {}
+;     }
+;   }
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* noalias %A, i32* noalias %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc11, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc12, %for.inc11 ]
+  %exitcond2 = icmp ne i32 %i.0, 100
+  br i1 %exitcond2, label %for.body, label %for.end13
+
+for.body:                                         ; preds = %for.cond
+  %tmp = load i32, i32* %sum, align 4
+  %mul = mul nsw i32 %tmp, 7
+  store i32 %mul, i32* %sum, align 4
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc8, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc9, %for.inc8 ]
+  %exitcond1 = icmp ne i32 %j.0, 100
+  br i1 %exitcond1, label %for.body3, label %for.end10
+
+for.body3:                                        ; preds = %for.cond1
+  %add = add nsw i32 %i.0, %j.0
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %add
+  %tmp3 = load i32, i32* %arrayidx, align 4
+  %tmp4 = load i32, i32* %sum, align 4
+  %add4 = add nsw i32 %tmp4, %tmp3
+  store i32 %add4, i32* %sum, align 4
+  br label %for.cond5
+
+for.cond5:                                        ; preds = %for.inc, %for.body3
+  %k.0 = phi i32 [ 0, %for.body3 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %k.0, 100
+  br i1 %exitcond, label %for.body7, label %for.end
+
+for.body7:                                        ; preds = %for.cond5
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body7
+  %inc = add nsw i32 %k.0, 1
+  br label %for.cond5
+
+for.end:                                          ; preds = %for.cond5
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %for.end
+  %inc9 = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end10:                                        ; preds = %for.cond1
+  br label %for.inc11
+
+for.inc11:                                        ; preds = %for.end10
+  %inc12 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end13:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_multiple_loops_array_sum_2.ll b/final/test/DependenceInfo/reduction_multiple_loops_array_sum_2.ll
new file mode 100644
index 0000000..3b641a1
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_multiple_loops_array_sum_2.ll
@@ -0,0 +1,78 @@
+; RUN: opt %loadPolly -polly-dependences -analyze -basicaa < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_for_body3[i0, i1] -> Stmt_for_body3[i0, 1 + i1] : 0 <= i0 <= 99 and 0 <= i1 <= 98; Stmt_for_body3[i0, 99] -> Stmt_for_body3[1 + i0, 0] : 0 <= i0 <= 98 }
+;
+; int f(int * restrict A, int * restrict sum) {
+;   int i, j, k;
+;   for (i = 0; i < 100; i++) {
+;     for (j = 0; j < 100; j++) {
+;       sum += A[i+j];
+;       for (k = 0; k< 100; k++) {}
+;     }
+;   }
+;   return sum;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* noalias %A, i32* noalias %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc11, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc12, %for.inc11 ]
+  %exitcond2 = icmp ne i32 %i.0, 100
+  br i1 %exitcond2, label %for.body, label %for.end13
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc8, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc9, %for.inc8 ]
+  %exitcond1 = icmp ne i32 %j.0, 100
+  br i1 %exitcond1, label %for.body3, label %for.end10
+
+for.body3:                                        ; preds = %for.cond1
+  %add = add nsw i32 %i.0, %j.0
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %add
+  %tmp3 = load i32, i32* %arrayidx, align 4
+  %tmp4 = load i32, i32* %sum, align 4
+  %add4 = add nsw i32 %tmp4, %tmp3
+  store i32 %add4, i32* %sum, align 4
+  br label %for.cond5
+
+for.cond5:                                        ; preds = %for.inc, %for.body3
+  %k.0 = phi i32 [ 0, %for.body3 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %k.0, 100
+  br i1 %exitcond, label %for.body7, label %for.end
+
+for.body7:                                        ; preds = %for.cond5
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body7
+  %inc = add nsw i32 %k.0, 1
+  br label %for.cond5
+
+for.end:                                          ; preds = %for.cond5
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %for.end
+  %inc9 = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end10:                                        ; preds = %for.cond1
+  br label %for.inc11
+
+for.inc11:                                        ; preds = %for.end10
+  %inc12 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end13:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_multiple_loops_array_sum_3.ll b/final/test/DependenceInfo/reduction_multiple_loops_array_sum_3.ll
new file mode 100644
index 0000000..2ccb6e7
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_multiple_loops_array_sum_3.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-dependences -analyze -basicaa < %s | FileCheck %s
+;
+; CHECK:      Reduction dependences:
+; CHECK-NEXT:     { Stmt_for_inc[i0, i1] -> Stmt_for_inc[i0, 1 + i1] : 0 <= i0 <= 99 and 0 <= i1 <= 98 }
+;
+; int f(int * __restrict__ A) {
+;   int i, j, sum = 0;
+;   for (k = 0; k < 37; k = g(k)) {
+;     for (i = 0; i < 100; i++) {
+;       sum *= 2;
+;       for (j = 0; j < 100; j++) {
+;         sum += A[i+j];
+;       }
+;     }
+;   }
+;   return sum;
+; }
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare i64 @g(i64)
+
+define i32 @f(i32* noalias %A) {
+entry:
+  %sum.04.reg2mem = alloca i32
+  %sum.12.reg2mem = alloca i32
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  store i32 0, i32* %sum.04.reg2mem
+  br label %for.body_outer_split
+
+for.body_outer_split:                             ; preds = %entry.split, %for.inc5
+  %indvars.ivK = phi i64 [ 0, %entry.split ], [ %incK, %for.bos2 ]
+  br label %for.body_outer
+
+for.body_outer:                                   ; preds = %for.body_outer_split
+  %incK = call i64 @g(i64 %indvars.ivK)
+  %exitcondK = icmp eq i64 %incK, 100
+  br i1 %exitcondK, label %for.end7, label %for.body
+
+for.body:                                         ; preds = %for.inc5, %for.body_outer
+  %indvars.iv23 = phi i64 [ 0, %for.body_outer ], [ %3, %for.inc5 ]
+  %sum.04.reload = load i32, i32* %sum.04.reg2mem
+  %mul = shl nsw i32 %sum.04.reload, 1
+  store i32 %mul, i32* %sum.12.reg2mem
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.inc, %for.body
+  %indvars.iv1 = phi i64 [ 0, %for.body ], [ %1, %for.inc ]
+  %sum.12.reload = load i32, i32* %sum.12.reg2mem
+  %0 = add i64 %indvars.iv23, %indvars.iv1
+  %arrayidx = getelementptr i32, i32* %A, i64 %0
+  %tmp5 = load i32, i32* %arrayidx, align 4
+  %add4 = add nsw i32 %tmp5, %sum.12.reload
+  %1 = add nuw nsw i64 %indvars.iv1, 1
+  %exitcond1 = icmp eq i64 %1, 100
+  store i32 %add4, i32* %sum.12.reg2mem
+  br i1 %exitcond1, label %for.inc5, label %for.inc
+
+for.inc5:                                         ; preds = %for.inc
+  %2 = load i32, i32* %sum.12.reg2mem
+  %3 = add nuw nsw i64 %indvars.iv23, 1
+  %exitcond2 = icmp eq i64 %3, 100
+  store i32 %2, i32* %sum.04.reg2mem
+  br i1 %exitcond2, label %for.bos2, label %for.body
+
+for.bos2:
+  br label %for.body_outer_split
+
+for.end7:                                         ; preds = %for.inc5
+  %4 = load i32, i32* %sum.04.reg2mem
+  ret i32 %4
+}
diff --git a/final/test/DependenceInfo/reduction_multiple_reductions.ll b/final/test/DependenceInfo/reduction_multiple_reductions.ll
new file mode 100644
index 0000000..b838d78
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_multiple_reductions.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -basicaa -polly-dependences -analyze < %s | FileCheck %s
+;
+; Verify we do not have dependences between the if and the else clause
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_if_then[i0] -> Stmt_if_then[1 + i0] : 0 <= i0 <= 510; Stmt_if_else[i0] -> Stmt_if_else[1 + i0] : 512 <= i0 <= 1022 }
+;
+; void f(int *restrict sum, int *restrict prod) {
+;   for (int i = 0; i < 1024; i++)
+;     if (i < 512)
+;       *sum += i;
+;     else
+;       *prod *= i;
+; }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* noalias %sum, i32* noalias %prod)  {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %cmp1 = icmp slt i32 %i.0, 512
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:                                          ; preds = %for.body
+  %tmp = load i32, i32* %sum, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %sum, align 4
+  br label %if.end
+
+if.else:                                          ; preds = %for.body
+  %tmp1 = load i32, i32* %prod, align 4
+  %mul = mul nsw i32 %tmp1, %i.0
+  store i32 %mul, i32* %prod, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_multiple_reductions_2.ll b/final/test/DependenceInfo/reduction_multiple_reductions_2.ll
new file mode 100644
index 0000000..98c3ee6
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_multiple_reductions_2.ll
@@ -0,0 +1,108 @@
+; RUN: opt %loadPolly -basicaa -polly-dependences -analyze < %s | FileCheck %s
+;
+;
+; These are the important RAW dependences, as they need to originate/end in only one iteration:
+;   Stmt_S1[i0, 1023] -> Stmt_S2[i0, o1]
+;   Stmt_S1[i0, i1] -> Stmt_S2[i0, 0]
+;
+; These are the important WAW dependences, as they need to originate/end in only one iteration:
+;   Stmt_S1[i0, 1023] -> Stmt_S2[i0, o1]
+;   Stmt_S1[i0, i1] -> Stmt_S2[i0, 0]
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     { Stmt_S0[i0] -> Stmt_S1[i0, o1] : 0 <= i0 <= 1023 and 0 <= o1 <= 1023; Stmt_S2[i0, i1] -> Stmt_S3[i0] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023; Stmt_S3[i0] -> Stmt_S0[1 + i0] : 0 <= i0 <= 1022; Stmt_S1[i0, 1023] -> Stmt_S2[i0, o1] : 0 <= i0 <= 1023 and 0 <= o1 <= 1023; Stmt_S1[i0, i1] -> Stmt_S2[i0, 0] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022 }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     { Stmt_S0[i0] -> Stmt_S1[i0, o1] : 0 <= i0 <= 1023 and 0 <= o1 <= 1023; Stmt_S2[i0, i1] -> Stmt_S3[i0] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023; Stmt_S3[i0] -> Stmt_S0[1 + i0] : 0 <= i0 <= 1022; Stmt_S1[i0, 1023] -> Stmt_S2[i0, o1] : 0 <= i0 <= 1023 and 0 <= o1 <= 1023; Stmt_S1[i0, i1] -> Stmt_S2[i0, 0] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022 }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     { Stmt_S0[i0] -> Stmt_S1[i0, o1] : 0 <= i0 <= 1023 and 0 <= o1 <= 1023; Stmt_S2[i0, i1] -> Stmt_S3[i0] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023; Stmt_S3[i0] -> Stmt_S0[1 + i0] : 0 <= i0 <= 1022; Stmt_S1[i0, 1023] -> Stmt_S2[i0, o1] : 0 <= i0 <= 1023 and 0 <= o1 <= 1023; Stmt_S1[i0, i1] -> Stmt_S2[i0, 0] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022 }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_S1[i0, i1] -> Stmt_S1[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_S2[i0, i1] -> Stmt_S2[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022 }
+;
+;    void f(int *restrict red) {
+;      for (int j = 0; j < 1024; j++) {
+; S0:    *red = 42 + *red * 5;
+;        for (int i = 0; i < 1024; i++)
+; S1:      *red *= i;
+;        for (int i = 0; i < 1024; i++)
+; S2:      *red += i;
+; S3:    *red = 42 + *red * 7;
+;      }
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* noalias %red)  {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc15, %entry
+  %j.0 = phi i32 [ 0, %entry ], [ %inc16, %for.inc15 ]
+  %exitcond2 = icmp ne i32 %j.0, 1024
+  br i1 %exitcond2, label %for.body, label %for.end17
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %red, align 4
+  %mul = mul nsw i32 %tmp, 5
+  %add = add nsw i32 %mul, 42
+  store i32 %add, i32* %red, align 4
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %S0
+  %i.0 = phi i32 [ 0, %S0 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  br label %S1
+
+S1:                                               ; preds = %for.body3
+  %tmp3 = load i32, i32* %red, align 4
+  %mul4 = mul nsw i32 %tmp3, %i.0
+  store i32 %mul4, i32* %red, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S1
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.cond6
+
+for.cond6:                                        ; preds = %for.inc10, %for.end
+  %i5.0 = phi i32 [ 0, %for.end ], [ %inc11, %for.inc10 ]
+  %exitcond1 = icmp ne i32 %i5.0, 1024
+  br i1 %exitcond1, label %for.body8, label %for.end12
+
+for.body8:                                        ; preds = %for.cond6
+  br label %S2
+
+S2:                                               ; preds = %for.body8
+  %tmp4 = load i32, i32* %red, align 4
+  %add9 = add nsw i32 %tmp4, %i5.0
+  store i32 %add9, i32* %red, align 4
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %S2
+  %inc11 = add nsw i32 %i5.0, 1
+  br label %for.cond6
+
+for.end12:                                        ; preds = %for.cond6
+  br label %S3
+
+S3:                                               ; preds = %for.end12
+  %tmp5 = load i32, i32* %red, align 4
+  %mul13 = mul nsw i32 %tmp5, 7
+  %add14 = add nsw i32 %mul13, 42
+  store i32 %add14, i32* %red, align 4
+  br label %for.inc15
+
+for.inc15:                                        ; preds = %S3
+  %inc16 = add nsw i32 %j.0, 1
+  br label %for.cond
+
+for.end17:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_only_reduction_like_access.ll b/final/test/DependenceInfo/reduction_only_reduction_like_access.ll
new file mode 100644
index 0000000..a4eca1c
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_only_reduction_like_access.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+;
+; FIXME: Change the comment once we allow different pointers
+; The statement is "almost" reduction like but should not yield any reduction dependences
+;
+; We are limited to binary reductions at the moment and this is not one.
+; There are never at least two iterations which read __and__ write to the same
+; location, thus we won't find the RAW and WAW dependences of a reduction,
+; thus we should not find Reduction dependences.
+;
+; CHECK:  Reduction dependences:
+; CHECK:    {  }
+;
+; void f(int *sum) {
+;   for (int i = 0; i < 100; i++)
+;     sum[i] = sum[99-i] + i;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %sub = sub nsw i32 99, %i.0
+  %arrayidx = getelementptr inbounds i32, i32* %sum, i32 %sub
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  %arrayidx1 = getelementptr inbounds i32, i32* %sum, i32 %i.0
+  store i32 %add, i32* %arrayidx1, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_partially_escaping_intermediate_in_other_stmt.ll b/final/test/DependenceInfo/reduction_partially_escaping_intermediate_in_other_stmt.ll
new file mode 100644
index 0000000..8019928
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_partially_escaping_intermediate_in_other_stmt.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-dependences -analyze -basicaa < %s | FileCheck %s
+;
+; CHECK:      Reduction dependences:
+; CHECK-NEXT:     [N] -> { Stmt_for_body3[i0, i1] -> Stmt_for_body3[i0, 1 + i1] : 0 <= i0 <= 1023 and i1 >= 0 and 1024 - N + i0 <= i1 <= 1022 }
+;
+; void f(int N, int * restrict sums, int * restrict escape) {
+;   for (int i = 0; i < 1024; i++) {
+;     for (int j = 0; j < 1024; j++) {
+;       sums[i] += 5;
+;       if (N - i + j < 1024)
+;         escape[N - i + j] = sums[i];
+;     }
+;   }
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32 %N, i32* noalias %sums, i32* noalias %escape) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc10, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc11, %for.inc10 ]
+  %exitcond1 = icmp ne i32 %i.0, 1024
+  br i1 %exitcond1, label %for.body, label %for.end12
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %sums, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 5
+  store i32 %add, i32* %arrayidx, align 4
+  %sub = sub nsw i32 %N, %i.0
+  %add4 = add nsw i32 %sub, %j.0
+  %cmp5 = icmp slt i32 %add4, 1024
+  br i1 %cmp5, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body3
+  %arrayidx6 = getelementptr inbounds i32, i32* %sums, i32 %i.0
+  %tmp2 = load i32, i32* %arrayidx6, align 4
+  %sub7 = sub nsw i32 %N, %i.0
+  %add8 = add nsw i32 %sub7, %j.0
+  %arrayidx9 = getelementptr inbounds i32, i32* %escape, i32 %add8
+  store i32 %tmp2, i32* %arrayidx9, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body3
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.end
+  %inc11 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end12:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_privatization_deps.ll b/final/test/DependenceInfo/reduction_privatization_deps.ll
new file mode 100644
index 0000000..e51357a
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_privatization_deps.ll
@@ -0,0 +1,108 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     { Stmt_S0[i0] -> Stmt_S1[o0, i0 - o0] : i0 <= 1023 and 0 <= o0 <= i0; Stmt_S1[i0, i1] -> Stmt_S2[-1 + i0 + i1] : 0 <= i0 <= 1023 and i1 >= 0 and -i0 < i1 <= 1024 - i0 and i1 <= 1023 }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     { Stmt_S2[i0] -> Stmt_S2[1 + i0] : 0 <= i0 <= 1022; Stmt_S1[i0, i1] -> Stmt_S2[i0 + i1] : i0 >= 0 and 0 <= i1 <= 1023 - i0 }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     { Stmt_S0[i0] -> Stmt_S1[o0, i0 - o0] : i0 <= 1023 and 0 <= o0 <= i0; Stmt_S1[i0, i1] -> Stmt_S2[i0 + i1] : i0 >= 0 and 0 <= i1 <= 1023 - i0 }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_S1[i0, i1] -> Stmt_S1[1 + i0, -1 + i1] : 0 <= i0 <= 1022 and 0 < i1 <= 1023 }
+;
+;    void f(int *sum) {
+;      for (int i = 0; i < 1024; i++)
+; S0:    sum[i] = 0;
+;      for (int i = 0; i < 1024; i++)
+;        for (int j = 0; j < 1024; j++)
+; S1:      sum[i + j] += i;
+;      for (int i = 0; i < 1024; i++)
+; S2:    sum[i] = sum[i + 1] * 3;
+;    }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum)  {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond3 = icmp ne i32 %i.0, 1024
+  br i1 %exitcond3, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %sum, i32 %i.0
+  store i32 0, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc13, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc14, %for.inc13 ]
+  %exitcond2 = icmp ne i32 %i1.0, 1024
+  br i1 %exitcond2, label %for.body4, label %for.end15
+
+for.body4:                                        ; preds = %for.cond2
+  br label %for.cond5
+
+for.cond5:                                        ; preds = %for.inc10, %for.body4
+  %j.0 = phi i32 [ 0, %for.body4 ], [ %inc11, %for.inc10 ]
+  %exitcond1 = icmp ne i32 %j.0, 1024
+  br i1 %exitcond1, label %for.body7, label %for.end12
+
+for.body7:                                        ; preds = %for.cond5
+  br label %S1
+
+S1:                                               ; preds = %for.body7
+  %add = add nsw i32 %i1.0, %j.0
+  %arrayidx8 = getelementptr inbounds i32, i32* %sum, i32 %add
+  %tmp = load i32, i32* %arrayidx8, align 4
+  %add9 = add nsw i32 %tmp, %i1.0
+  store i32 %add9, i32* %arrayidx8, align 4
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %S1
+  %inc11 = add nsw i32 %j.0, 1
+  br label %for.cond5
+
+for.end12:                                        ; preds = %for.cond5
+  br label %for.inc13
+
+for.inc13:                                        ; preds = %for.end12
+  %inc14 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end15:                                        ; preds = %for.cond2
+  br label %for.cond17
+
+for.cond17:                                       ; preds = %for.inc23, %for.end15
+  %i16.0 = phi i32 [ 0, %for.end15 ], [ %inc24, %for.inc23 ]
+  %exitcond = icmp ne i32 %i16.0, 1024
+  br i1 %exitcond, label %for.body19, label %for.end25
+
+for.body19:                                       ; preds = %for.cond17
+  br label %S2
+
+S2:                                               ; preds = %for.body19
+  %add20 = add nsw i32 %i16.0, 1
+  %arrayidx21 = getelementptr inbounds i32, i32* %sum, i32 %add20
+  %tmp4 = load i32, i32* %arrayidx21, align 4
+  %mul = mul nsw i32 %tmp4, 3
+  %arrayidx22 = getelementptr inbounds i32, i32* %sum, i32 %i16.0
+  store i32 %mul, i32* %arrayidx22, align 4
+  br label %for.inc23
+
+for.inc23:                                        ; preds = %S2
+  %inc24 = add nsw i32 %i16.0, 1
+  br label %for.cond17
+
+for.end25:                                        ; preds = %for.cond17
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_privatization_deps_2.ll b/final/test/DependenceInfo/reduction_privatization_deps_2.ll
new file mode 100644
index 0000000..fed2376
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_privatization_deps_2.ll
@@ -0,0 +1,84 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+;
+; We have privatization dependences from a textually later statement to a
+; textually earlier one, but the dependences still go forward in time.
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     { Stmt_S3[i0] -> Stmt_S2[1 + i0, o1] : 0 <= i0 <= 97 and 0 <= o1 <= 99; Stmt_S1[i0] -> Stmt_S3[i0] : 0 <= i0 <= 98 }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     { Stmt_S3[i0] -> Stmt_S2[1 + i0, o1] : 0 <= i0 <= 97 and 0 <= o1 <= 99; Stmt_S1[i0] -> Stmt_S3[i0] : 0 <= i0 <= 98 }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     { Stmt_S3[i0] -> Stmt_S2[1 + i0, o1] : 0 <= i0 <= 97 and 0 <= o1 <= 99; Stmt_S1[i0] -> Stmt_S3[i0] : 0 <= i0 <= 98 }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_S2[i0, i1] -> Stmt_S2[i0, 1 + i1] : 0 <= i0 <= 98 and 0 <= i1 <= 98 }
+;
+;    void f(int *sum) {
+;      int i, j;
+;      for (i = 0; i < 99; i++) {
+; S1:    sum[i + 1] += 42;
+;        for (j = 0; j < 100; j++)
+; S2:      sum[i] += i * j;
+; S3:    sum[i + 1] += 7;
+;      }
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum)  {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc10, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc11, %for.inc10 ]
+  %exitcond1 = icmp ne i32 %i.0, 99
+  br i1 %exitcond1, label %for.body, label %for.end12
+
+for.body:                                         ; preds = %for.cond
+  br label %S1
+
+S1:                                               ; preds = %for.body
+  %add = add nsw i32 %i.0, 1
+  %arrayidx = getelementptr inbounds i32, i32* %sum, i32 %add
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add1 = add nsw i32 %tmp, 42
+  store i32 %add1, i32* %arrayidx, align 4
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc, %S1
+  %j.0 = phi i32 [ 0, %S1 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 100
+  br i1 %exitcond, label %for.body4, label %for.end
+
+for.body4:                                        ; preds = %for.cond2
+  br label %S2
+
+S2:                                               ; preds = %for.body4
+  %mul = mul nsw i32 %i.0, %j.0
+  %arrayidx5 = getelementptr inbounds i32, i32* %sum, i32 %i.0
+  %tmp2 = load i32, i32* %arrayidx5, align 4
+  %add6 = add nsw i32 %tmp2, %mul
+  store i32 %add6, i32* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S2
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond2
+
+for.end:                                          ; preds = %for.cond2
+  br label %S3
+
+S3:                                               ; preds = %for.end
+  %add7 = add nsw i32 %i.0, 1
+  %arrayidx8 = getelementptr inbounds i32, i32* %sum, i32 %add7
+  %tmp3 = load i32, i32* %arrayidx8, align 4
+  %add9 = add nsw i32 %tmp3, 7
+  store i32 %add9, i32* %arrayidx8, align 4
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %S3
+  %inc11 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end12:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_privatization_deps_3.ll b/final/test/DependenceInfo/reduction_privatization_deps_3.ll
new file mode 100644
index 0000000..0cf6fc6
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_privatization_deps_3.ll
@@ -0,0 +1,82 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     { Stmt_S2[i0, i1] -> Stmt_S3[o0] : i1 <= 1 - i0 and -i1 < o0 <= 1 and o0 <= 1 + i0 - i1; Stmt_S3[i0] -> Stmt_S2[o0, 1 - i0] : 0 <= i0 <= 1 and i0 < o0 <= 98; Stmt_S1[i0] -> Stmt_S3[2 + i0] : 0 <= i0 <= 96 }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:   { Stmt_S2[i0, i1] -> Stmt_S3[o0] : i1 <= 1 - i0 and -i1 < o0 <= 1 and o0 <= 1 + i0 - i1; Stmt_S3[i0] -> Stmt_S2[o0, 1 - i0] : 0 <= i0 <= 1 and i0 < o0 <= 98; Stmt_S1[i0] -> Stmt_S3[2 + i0] : 0 <= i0 <= 96 }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     { Stmt_S2[i0, i1] -> Stmt_S3[o0] : i1 <= 1 - i0 and -i1 < o0 <= 1 and o0 <= 1 + i0 - i1; Stmt_S3[i0] -> Stmt_S2[o0, 1 - i0] : 0 <= i0 <= 1 and i0 < o0 <= 98; Stmt_S1[i0] -> Stmt_S3[2 + i0] : 0 <= i0 <= 96 }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_S2[i0, i1] -> Stmt_S2[1 + i0, i1] : 0 <= i0 <= 97 and i1 >= 0 and 2 - i0 <= i1 <= 98 - i0; Stmt_S2[0, 0] -> Stmt_S2[1, 0] }
+;
+;    void f(int *sum) {
+;      int i, j;
+;      for (i = 0; i < 99; i++) {
+; S1:    sum[i + 1] += 42;
+;        for (j = i; j < 100; j++)
+; S2:      sum[i - j] += i * j;
+; S3:    sum[i - 1] += 7;
+;      }
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum)  {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc10, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc11, %for.inc10 ]
+  %exitcond1 = icmp ne i32 %i.0, 99
+  br i1 %exitcond1, label %for.body, label %for.end12
+
+for.body:                                         ; preds = %for.cond
+  br label %S1
+
+S1:                                               ; preds = %for.body
+  %add = add nsw i32 %i.0, 1
+  %arrayidx = getelementptr inbounds i32, i32* %sum, i32 %add
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add1 = add nsw i32 %tmp, 42
+  store i32 %add1, i32* %arrayidx, align 4
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc, %S1
+  %j.0 = phi i32 [ %i.0, %S1 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 100
+  br i1 %exitcond, label %for.body4, label %for.end
+
+for.body4:                                        ; preds = %for.cond2
+  br label %S2
+
+S2:                                               ; preds = %for.body4
+  %mul = mul nsw i32 %i.0, %j.0
+  %sub = sub nsw i32 %i.0, %j.0
+  %arrayidx5 = getelementptr inbounds i32, i32* %sum, i32 %sub
+  %tmp2 = load i32, i32* %arrayidx5, align 4
+  %add6 = add nsw i32 %tmp2, %mul
+  store i32 %add6, i32* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S2
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond2
+
+for.end:                                          ; preds = %for.cond2
+  br label %S3
+
+S3:                                               ; preds = %for.end
+  %sub7 = add nsw i32 %i.0, -1
+  %arrayidx8 = getelementptr inbounds i32, i32* %sum, i32 %sub7
+  %tmp3 = load i32, i32* %arrayidx8, align 4
+  %add9 = add nsw i32 %tmp3, 7
+  store i32 %add9, i32* %arrayidx8, align 4
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %S3
+  %inc11 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end12:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_privatization_deps_4.ll b/final/test/DependenceInfo/reduction_privatization_deps_4.ll
new file mode 100644
index 0000000..68fbd08
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_privatization_deps_4.ll
@@ -0,0 +1,78 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     { Stmt_S2[i0, i1] -> Stmt_S1[i1] : i0 >= 0 and i0 < i1 <= 98; Stmt_S1[i0] -> Stmt_S2[i0, i0] : 0 <= i0 <= 98; Stmt_S2[i0, i0] -> Stmt_S3[i0] : 0 <= i0 <= 98; Stmt_S3[i0] -> Stmt_S2[o0, i0] : i0 >= 0 and i0 < o0 <= 98 }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:   { Stmt_S2[i0, i1] -> Stmt_S1[i1] : i0 >= 0 and i0 < i1 <= 98; Stmt_S1[i0] -> Stmt_S2[i0, i0] : 0 <= i0 <= 98; Stmt_S2[i0, i0] -> Stmt_S3[i0] : 0 <= i0 <= 98; Stmt_S3[i0] -> Stmt_S2[o0, i0] : i0 >= 0 and i0 < o0 <= 98 }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     { Stmt_S2[i0, i1] -> Stmt_S1[i1] : i0 >= 0 and i0 < i1 <= 98; Stmt_S1[i0] -> Stmt_S2[i0, i0] : 0 <= i0 <= 98; Stmt_S2[i0, i0] -> Stmt_S3[i0] : 0 <= i0 <= 98; Stmt_S3[i0] -> Stmt_S2[o0, i0] : i0 >= 0 and i0 < o0 <= 98 }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_S2[i0, i1] -> Stmt_S2[1 + i0, i1] : (i0 >= 0 and 2 + i0 <= i1 <= 99) or (i0 <= 97 and 0 <= i1 < i0) }
+;
+;    void f(int *sum) {
+;      for (int i = 0; i < 99; i++) {
+; S1:    sum[i] += 42;
+;        for (int j = 0; j < 100; j++)
+; S2:      sum[j] += i * j;
+; S3:    sum[i] += 7;
+;      }
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum)  {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc8, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc9, %for.inc8 ]
+  %exitcond1 = icmp ne i32 %i.0, 99
+  br i1 %exitcond1, label %for.body, label %for.end10
+
+for.body:                                         ; preds = %for.cond
+  br label %S1
+
+S1:                                               ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %sum, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 42
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %S1
+  %j.0 = phi i32 [ 0, %S1 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 100
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  br label %S2
+
+S2:                                               ; preds = %for.body3
+  %mul = mul nsw i32 %i.0, %j.0
+  %arrayidx4 = getelementptr inbounds i32, i32* %sum, i32 %j.0
+  %tmp2 = load i32, i32* %arrayidx4, align 4
+  %add5 = add nsw i32 %tmp2, %mul
+  store i32 %add5, i32* %arrayidx4, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S2
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %S3
+
+S3:                                               ; preds = %for.end
+  %arrayidx6 = getelementptr inbounds i32, i32* %sum, i32 %i.0
+  %tmp3 = load i32, i32* %arrayidx6, align 4
+  %add7 = add nsw i32 %tmp3, 7
+  store i32 %add7, i32* %arrayidx6, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S3
+  %inc9 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end10:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_privatization_deps_5.ll b/final/test/DependenceInfo/reduction_privatization_deps_5.ll
new file mode 100644
index 0000000..9c002b4
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_privatization_deps_5.ll
@@ -0,0 +1,86 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     { Stmt_S2[i0, 0] -> Stmt_S1[1 + i0, 0] : 0 <= i0 <= 97; Stmt_S1[i0, 0] -> Stmt_S2[i0, 0] : 0 <= i0 <= 98 }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     { Stmt_S2[i0, 0] -> Stmt_S1[1 + i0, 0] : 0 <= i0 <= 97; Stmt_S1[i0, 0] -> Stmt_S2[i0, 0] : 0 <= i0 <= 98 }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     { Stmt_S2[i0, 0] -> Stmt_S1[1 + i0, 0] : 0 <= i0 <= 97; Stmt_S1[i0, 0] -> Stmt_S2[i0, 0] : 0 <= i0 <= 98 }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_S2[i0, i1] -> Stmt_S2[1 + i0, i1] : 0 <= i0 <= 97 and 0 < i1 <= 99 }
+;
+;    void f(int *sum) {
+;      for (int i = 0; i < 99; i++) {
+;        for (int j = 0; j < 1; j++)
+; S1:      sum[j] += 42;
+;        for (int j = 0; j < 100; j++)
+; S2:      sum[j] += i * j;
+;      }
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum)  {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc12, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc13, %for.inc12 ]
+  %exitcond2 = icmp ne i32 %i.0, 99
+  br i1 %exitcond2, label %for.body, label %for.end14
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  br label %S1
+
+S1:                                               ; preds = %for.body3
+  %arrayidx = getelementptr inbounds i32, i32* %sum, i32 %j.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 42
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S1
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc9, %for.end
+  %j.1 = phi i32 [ 0, %for.end ], [ %inc10, %for.inc9 ]
+  %exitcond1 = icmp ne i32 %j.1, 100
+  br i1 %exitcond1, label %for.body6, label %for.end11
+
+for.body6:                                        ; preds = %for.cond4
+  br label %S2
+
+S2:                                               ; preds = %for.body6
+  %mul = mul nsw i32 %i.0, %j.1
+  %arrayidx7 = getelementptr inbounds i32, i32* %sum, i32 %j.1
+  %tmp3 = load i32, i32* %arrayidx7, align 4
+  %add8 = add nsw i32 %tmp3, %mul
+  store i32 %add8, i32* %arrayidx7, align 4
+  br label %for.inc9
+
+for.inc9:                                         ; preds = %S2
+  %inc10 = add nsw i32 %j.1, 1
+  br label %for.cond4
+
+for.end11:                                        ; preds = %for.cond4
+  br label %for.inc12
+
+for.inc12:                                        ; preds = %for.end11
+  %inc13 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end14:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_sequence.ll b/final/test/DependenceInfo/reduction_sequence.ll
new file mode 100644
index 0000000..05d8697
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_sequence.ll
@@ -0,0 +1,541 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+
+;    void manyreductions(long *A) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          *A += 42;
+;    }
+
+; CHECK: 	RAW dependences:
+; CHECK-NEXT: 		{ Stmt_bb150[1023, 1023] -> Stmt_bb162[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb150[i0, i1] -> Stmt_bb162[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb150[1023, 1023] -> Stmt_bb162[0, 0]; Stmt_bb174[1023, 1023] -> Stmt_bb186[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb174[i0, i1] -> Stmt_bb186[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb174[1023, 1023] -> Stmt_bb186[0, 0]; Stmt_bb102[1023, 1023] -> Stmt_bb114[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb102[i0, i1] -> Stmt_bb114[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb102[1023, 1023] -> Stmt_bb114[0, 0]; Stmt_bb42[1023, 1023] -> Stmt_bb54[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb42[i0, i1] -> Stmt_bb54[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb42[1023, 1023] -> Stmt_bb54[0, 0]; Stmt_bb54[1023, 1023] -> Stmt_bb66[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb54[i0, i1] -> Stmt_bb66[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb54[1023, 1023] -> Stmt_bb66[0, 0]; Stmt_bb31[1023, 1023] -> Stmt_bb42[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb31[i0, i1] -> Stmt_bb42[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb31[1023, 1023] -> Stmt_bb42[0, 0]; Stmt_bb162[1023, 1023] -> Stmt_bb174[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb162[i0, i1] -> Stmt_bb174[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb162[1023, 1023] -> Stmt_bb174[0, 0]; Stmt_bb126[1023, 1023] -> Stmt_bb138[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb126[i0, i1] -> Stmt_bb138[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb126[1023, 1023] -> Stmt_bb138[0, 0]; Stmt_bb90[1023, 1023] -> Stmt_bb102[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb90[i0, i1] -> Stmt_bb102[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb90[1023, 1023] -> Stmt_bb102[0, 0]; Stmt_bb138[1023, 1023] -> Stmt_bb150[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb138[i0, i1] -> Stmt_bb150[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb138[1023, 1023] -> Stmt_bb150[0, 0]; Stmt_bb66[1023, 1023] -> Stmt_bb78[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb66[i0, i1] -> Stmt_bb78[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb66[1023, 1023] -> Stmt_bb78[0, 0]; Stmt_bb78[1023, 1023] -> Stmt_bb90[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb78[i0, i1] -> Stmt_bb90[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb78[1023, 1023] -> Stmt_bb90[0, 0]; Stmt_bb114[1023, 1023] -> Stmt_bb126[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb114[i0, i1] -> Stmt_bb126[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb114[1023, 1023] -> Stmt_bb126[0, 0] }
+; CHECK-NEXT: 	WAR dependences:
+; CHECK-NEXT:     { Stmt_bb150[1023, 1023] -> Stmt_bb162[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb150[i0, i1] -> Stmt_bb162[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb150[1023, 1023] -> Stmt_bb162[0, 0]; Stmt_bb174[1023, 1023] -> Stmt_bb186[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb174[i0, i1] -> Stmt_bb186[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb174[1023, 1023] -> Stmt_bb186[0, 0]; Stmt_bb102[1023, 1023] -> Stmt_bb114[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb102[i0, i1] -> Stmt_bb114[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb102[1023, 1023] -> Stmt_bb114[0, 0]; Stmt_bb42[1023, 1023] -> Stmt_bb54[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb42[i0, i1] -> Stmt_bb54[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb42[1023, 1023] -> Stmt_bb54[0, 0]; Stmt_bb54[1023, 1023] -> Stmt_bb66[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb54[i0, i1] -> Stmt_bb66[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb54[1023, 1023] -> Stmt_bb66[0, 0]; Stmt_bb31[1023, 1023] -> Stmt_bb42[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb31[i0, i1] -> Stmt_bb42[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb31[1023, 1023] -> Stmt_bb42[0, 0]; Stmt_bb162[1023, 1023] -> Stmt_bb174[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb162[i0, i1] -> Stmt_bb174[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb162[1023, 1023] -> Stmt_bb174[0, 0]; Stmt_bb126[1023, 1023] -> Stmt_bb138[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb126[i0, i1] -> Stmt_bb138[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb126[1023, 1023] -> Stmt_bb138[0, 0]; Stmt_bb90[1023, 1023] -> Stmt_bb102[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb90[i0, i1] -> Stmt_bb102[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb90[1023, 1023] -> Stmt_bb102[0, 0]; Stmt_bb138[1023, 1023] -> Stmt_bb150[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb138[i0, i1] -> Stmt_bb150[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb138[1023, 1023] -> Stmt_bb150[0, 0]; Stmt_bb66[1023, 1023] -> Stmt_bb78[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb66[i0, i1] -> Stmt_bb78[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb66[1023, 1023] -> Stmt_bb78[0, 0]; Stmt_bb78[1023, 1023] -> Stmt_bb90[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb78[i0, i1] -> Stmt_bb90[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb78[1023, 1023] -> Stmt_bb90[0, 0]; Stmt_bb114[1023, 1023] -> Stmt_bb126[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb114[i0, i1] -> Stmt_bb126[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb114[1023, 1023] -> Stmt_bb126[0, 0] }
+; CHECK-NEXT: 	WAW dependences:
+; CHECK-NEXT: 		{ Stmt_bb150[1023, 1023] -> Stmt_bb162[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb150[i0, i1] -> Stmt_bb162[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb150[1023, 1023] -> Stmt_bb162[0, 0]; Stmt_bb174[1023, 1023] -> Stmt_bb186[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb174[i0, i1] -> Stmt_bb186[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb174[1023, 1023] -> Stmt_bb186[0, 0]; Stmt_bb102[1023, 1023] -> Stmt_bb114[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb102[i0, i1] -> Stmt_bb114[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb102[1023, 1023] -> Stmt_bb114[0, 0]; Stmt_bb42[1023, 1023] -> Stmt_bb54[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb42[i0, i1] -> Stmt_bb54[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb42[1023, 1023] -> Stmt_bb54[0, 0]; Stmt_bb54[1023, 1023] -> Stmt_bb66[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb54[i0, i1] -> Stmt_bb66[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb54[1023, 1023] -> Stmt_bb66[0, 0]; Stmt_bb31[1023, 1023] -> Stmt_bb42[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb31[i0, i1] -> Stmt_bb42[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb31[1023, 1023] -> Stmt_bb42[0, 0]; Stmt_bb162[1023, 1023] -> Stmt_bb174[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb162[i0, i1] -> Stmt_bb174[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb162[1023, 1023] -> Stmt_bb174[0, 0]; Stmt_bb126[1023, 1023] -> Stmt_bb138[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb126[i0, i1] -> Stmt_bb138[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb126[1023, 1023] -> Stmt_bb138[0, 0]; Stmt_bb90[1023, 1023] -> Stmt_bb102[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb90[i0, i1] -> Stmt_bb102[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb90[1023, 1023] -> Stmt_bb102[0, 0]; Stmt_bb138[1023, 1023] -> Stmt_bb150[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb138[i0, i1] -> Stmt_bb150[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb138[1023, 1023] -> Stmt_bb150[0, 0]; Stmt_bb66[1023, 1023] -> Stmt_bb78[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb66[i0, i1] -> Stmt_bb78[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb66[1023, 1023] -> Stmt_bb78[0, 0]; Stmt_bb78[1023, 1023] -> Stmt_bb90[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb78[i0, i1] -> Stmt_bb90[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb78[1023, 1023] -> Stmt_bb90[0, 0]; Stmt_bb114[1023, 1023] -> Stmt_bb126[o0, o1] : o0 <= 1023 and o1 >= 0 and -1024o0 < o1 <= 1023; Stmt_bb114[i0, i1] -> Stmt_bb126[0, 0] : i0 >= 0 and 0 <= i1 <= 1048574 - 1024i0 and i1 <= 1023; Stmt_bb114[1023, 1023] -> Stmt_bb126[0, 0] }
+; CHECK-NEXT: 	Reduction dependences:
+; CHECK-NEXT: 		{ Stmt_bb102[i0, i1] -> Stmt_bb102[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb102[i0, 1023] -> Stmt_bb102[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb90[i0, i1] -> Stmt_bb90[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb90[i0, 1023] -> Stmt_bb90[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb186[i0, i1] -> Stmt_bb186[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb186[i0, 1023] -> Stmt_bb186[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb66[i0, i1] -> Stmt_bb66[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb66[i0, 1023] -> Stmt_bb66[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb31[i0, i1] -> Stmt_bb31[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb31[i0, 1023] -> Stmt_bb31[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb138[i0, i1] -> Stmt_bb138[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb138[i0, 1023] -> Stmt_bb138[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb126[i0, i1] -> Stmt_bb126[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb126[i0, 1023] -> Stmt_bb126[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb42[i0, i1] -> Stmt_bb42[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb42[i0, 1023] -> Stmt_bb42[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb150[i0, i1] -> Stmt_bb150[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb150[i0, 1023] -> Stmt_bb150[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb78[i0, i1] -> Stmt_bb78[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb78[i0, 1023] -> Stmt_bb78[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb174[i0, i1] -> Stmt_bb174[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb174[i0, 1023] -> Stmt_bb174[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb114[i0, i1] -> Stmt_bb114[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb114[i0, 1023] -> Stmt_bb114[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb162[i0, i1] -> Stmt_bb162[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb162[i0, 1023] -> Stmt_bb162[1 + i0, 0] : 0 <= i0 <= 1022; Stmt_bb54[i0, i1] -> Stmt_bb54[i0, 1 + i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1022; Stmt_bb54[i0, 1023] -> Stmt_bb54[1 + i0, 0] : 0 <= i0 <= 1022 }
+
+; CHECK-NEXT: 	Transitive closure of reduction dependences:
+; CHECK-NEXT:  { Stmt_bb102[i0, i1] -> Stmt_bb102[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb90[i0, i1] -> Stmt_bb90[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb186[i0, i1] -> Stmt_bb186[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb66[i0, i1] -> Stmt_bb66[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb31[i0, i1] -> Stmt_bb31[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb138[i0, i1] -> Stmt_bb138[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb126[i0, i1] -> Stmt_bb126[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb42[i0, i1] -> Stmt_bb42[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb150[i0, i1] -> Stmt_bb150[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb78[i0, i1] -> Stmt_bb78[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb174[i0, i1] -> Stmt_bb174[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb114[i0, i1] -> Stmt_bb114[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb162[i0, i1] -> Stmt_bb162[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)); Stmt_bb54[i0, i1] -> Stmt_bb54[o0, o1] : 0 <= i1 <= 1023 and 0 <= o1 <= 1023 and ((i0 >= 0 and o0 <= 1023 and o1 > 1024i0 + i1 - 1024o0) or (i0 <= 1023 and o0 >= 0 and o1 < 1024i0 + i1 - 1024o0)) }
+
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @manyreductions(i64* %A) {
+bb:
+  br label %bb28
+
+bb28:                                             ; preds = %bb36, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp37, %bb36 ]
+  %exitcond27 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond27, label %bb29, label %bb38
+
+bb29:                                             ; preds = %bb28
+  br label %bb30
+
+bb30:                                             ; preds = %bb33, %bb29
+  %j.0 = phi i64 [ 0, %bb29 ], [ %tmp34, %bb33 ]
+  %exitcond26 = icmp ne i64 %j.0, 1024
+  br i1 %exitcond26, label %bb31, label %bb35
+
+bb31:                                             ; preds = %bb30
+  %tmp = load i64, i64* %A, align 8
+  %tmp32 = add nsw i64 %tmp, 42
+  store i64 %tmp32, i64* %A, align 8
+  br label %bb33
+
+bb33:                                             ; preds = %bb31
+  %tmp34 = add nuw nsw i64 %j.0, 1
+  br label %bb30
+
+bb35:                                             ; preds = %bb30
+  br label %bb36
+
+bb36:                                             ; preds = %bb35
+  %tmp37 = add nuw nsw i64 %i.0, 1
+  br label %bb28
+
+bb38:                                             ; preds = %bb28
+  br label %bb39
+
+bb39:                                             ; preds = %bb48, %bb38
+  %i1.0 = phi i64 [ 0, %bb38 ], [ %tmp49, %bb48 ]
+  %exitcond25 = icmp ne i64 %i1.0, 1024
+  br i1 %exitcond25, label %bb40, label %bb50
+
+bb40:                                             ; preds = %bb39
+  br label %bb41
+
+bb41:                                             ; preds = %bb45, %bb40
+  %j2.0 = phi i64 [ 0, %bb40 ], [ %tmp46, %bb45 ]
+  %exitcond24 = icmp ne i64 %j2.0, 1024
+  br i1 %exitcond24, label %bb42, label %bb47
+
+bb42:                                             ; preds = %bb41
+  %tmp43 = load i64, i64* %A, align 8
+  %tmp44 = add nsw i64 %tmp43, 42
+  store i64 %tmp44, i64* %A, align 8
+  br label %bb45
+
+bb45:                                             ; preds = %bb42
+  %tmp46 = add nuw nsw i64 %j2.0, 1
+  br label %bb41
+
+bb47:                                             ; preds = %bb41
+  br label %bb48
+
+bb48:                                             ; preds = %bb47
+  %tmp49 = add nuw nsw i64 %i1.0, 1
+  br label %bb39
+
+bb50:                                             ; preds = %bb39
+  br label %bb51
+
+bb51:                                             ; preds = %bb60, %bb50
+  %i3.0 = phi i64 [ 0, %bb50 ], [ %tmp61, %bb60 ]
+  %exitcond23 = icmp ne i64 %i3.0, 1024
+  br i1 %exitcond23, label %bb52, label %bb62
+
+bb52:                                             ; preds = %bb51
+  br label %bb53
+
+bb53:                                             ; preds = %bb57, %bb52
+  %j4.0 = phi i64 [ 0, %bb52 ], [ %tmp58, %bb57 ]
+  %exitcond22 = icmp ne i64 %j4.0, 1024
+  br i1 %exitcond22, label %bb54, label %bb59
+
+bb54:                                             ; preds = %bb53
+  %tmp55 = load i64, i64* %A, align 8
+  %tmp56 = add nsw i64 %tmp55, 42
+  store i64 %tmp56, i64* %A, align 8
+  br label %bb57
+
+bb57:                                             ; preds = %bb54
+  %tmp58 = add nuw nsw i64 %j4.0, 1
+  br label %bb53
+
+bb59:                                             ; preds = %bb53
+  br label %bb60
+
+bb60:                                             ; preds = %bb59
+  %tmp61 = add nuw nsw i64 %i3.0, 1
+  br label %bb51
+
+bb62:                                             ; preds = %bb51
+  br label %bb63
+
+bb63:                                             ; preds = %bb72, %bb62
+  %i5.0 = phi i64 [ 0, %bb62 ], [ %tmp73, %bb72 ]
+  %exitcond21 = icmp ne i64 %i5.0, 1024
+  br i1 %exitcond21, label %bb64, label %bb74
+
+bb64:                                             ; preds = %bb63
+  br label %bb65
+
+bb65:                                             ; preds = %bb69, %bb64
+  %j6.0 = phi i64 [ 0, %bb64 ], [ %tmp70, %bb69 ]
+  %exitcond20 = icmp ne i64 %j6.0, 1024
+  br i1 %exitcond20, label %bb66, label %bb71
+
+bb66:                                             ; preds = %bb65
+  %tmp67 = load i64, i64* %A, align 8
+  %tmp68 = add nsw i64 %tmp67, 42
+  store i64 %tmp68, i64* %A, align 8
+  br label %bb69
+
+bb69:                                             ; preds = %bb66
+  %tmp70 = add nuw nsw i64 %j6.0, 1
+  br label %bb65
+
+bb71:                                             ; preds = %bb65
+  br label %bb72
+
+bb72:                                             ; preds = %bb71
+  %tmp73 = add nuw nsw i64 %i5.0, 1
+  br label %bb63
+
+bb74:                                             ; preds = %bb63
+  br label %bb75
+
+bb75:                                             ; preds = %bb84, %bb74
+  %i7.0 = phi i64 [ 0, %bb74 ], [ %tmp85, %bb84 ]
+  %exitcond19 = icmp ne i64 %i7.0, 1024
+  br i1 %exitcond19, label %bb76, label %bb86
+
+bb76:                                             ; preds = %bb75
+  br label %bb77
+
+bb77:                                             ; preds = %bb81, %bb76
+  %j8.0 = phi i64 [ 0, %bb76 ], [ %tmp82, %bb81 ]
+  %exitcond18 = icmp ne i64 %j8.0, 1024
+  br i1 %exitcond18, label %bb78, label %bb83
+
+bb78:                                             ; preds = %bb77
+  %tmp79 = load i64, i64* %A, align 8
+  %tmp80 = add nsw i64 %tmp79, 42
+  store i64 %tmp80, i64* %A, align 8
+  br label %bb81
+
+bb81:                                             ; preds = %bb78
+  %tmp82 = add nuw nsw i64 %j8.0, 1
+  br label %bb77
+
+bb83:                                             ; preds = %bb77
+  br label %bb84
+
+bb84:                                             ; preds = %bb83
+  %tmp85 = add nuw nsw i64 %i7.0, 1
+  br label %bb75
+
+bb86:                                             ; preds = %bb75
+  br label %bb87
+
+bb87:                                             ; preds = %bb96, %bb86
+  %i9.0 = phi i64 [ 0, %bb86 ], [ %tmp97, %bb96 ]
+  %exitcond17 = icmp ne i64 %i9.0, 1024
+  br i1 %exitcond17, label %bb88, label %bb98
+
+bb88:                                             ; preds = %bb87
+  br label %bb89
+
+bb89:                                             ; preds = %bb93, %bb88
+  %j10.0 = phi i64 [ 0, %bb88 ], [ %tmp94, %bb93 ]
+  %exitcond16 = icmp ne i64 %j10.0, 1024
+  br i1 %exitcond16, label %bb90, label %bb95
+
+bb90:                                             ; preds = %bb89
+  %tmp91 = load i64, i64* %A, align 8
+  %tmp92 = add nsw i64 %tmp91, 42
+  store i64 %tmp92, i64* %A, align 8
+  br label %bb93
+
+bb93:                                             ; preds = %bb90
+  %tmp94 = add nuw nsw i64 %j10.0, 1
+  br label %bb89
+
+bb95:                                             ; preds = %bb89
+  br label %bb96
+
+bb96:                                             ; preds = %bb95
+  %tmp97 = add nuw nsw i64 %i9.0, 1
+  br label %bb87
+
+bb98:                                             ; preds = %bb87
+  br label %bb99
+
+bb99:                                             ; preds = %bb108, %bb98
+  %i11.0 = phi i64 [ 0, %bb98 ], [ %tmp109, %bb108 ]
+  %exitcond15 = icmp ne i64 %i11.0, 1024
+  br i1 %exitcond15, label %bb100, label %bb110
+
+bb100:                                            ; preds = %bb99
+  br label %bb101
+
+bb101:                                            ; preds = %bb105, %bb100
+  %j12.0 = phi i64 [ 0, %bb100 ], [ %tmp106, %bb105 ]
+  %exitcond14 = icmp ne i64 %j12.0, 1024
+  br i1 %exitcond14, label %bb102, label %bb107
+
+bb102:                                            ; preds = %bb101
+  %tmp103 = load i64, i64* %A, align 8
+  %tmp104 = add nsw i64 %tmp103, 42
+  store i64 %tmp104, i64* %A, align 8
+  br label %bb105
+
+bb105:                                            ; preds = %bb102
+  %tmp106 = add nuw nsw i64 %j12.0, 1
+  br label %bb101
+
+bb107:                                            ; preds = %bb101
+  br label %bb108
+
+bb108:                                            ; preds = %bb107
+  %tmp109 = add nuw nsw i64 %i11.0, 1
+  br label %bb99
+
+bb110:                                            ; preds = %bb99
+  br label %bb111
+
+bb111:                                            ; preds = %bb120, %bb110
+  %i13.0 = phi i64 [ 0, %bb110 ], [ %tmp121, %bb120 ]
+  %exitcond13 = icmp ne i64 %i13.0, 1024
+  br i1 %exitcond13, label %bb112, label %bb122
+
+bb112:                                            ; preds = %bb111
+  br label %bb113
+
+bb113:                                            ; preds = %bb117, %bb112
+  %j14.0 = phi i64 [ 0, %bb112 ], [ %tmp118, %bb117 ]
+  %exitcond12 = icmp ne i64 %j14.0, 1024
+  br i1 %exitcond12, label %bb114, label %bb119
+
+bb114:                                            ; preds = %bb113
+  %tmp115 = load i64, i64* %A, align 8
+  %tmp116 = add nsw i64 %tmp115, 42
+  store i64 %tmp116, i64* %A, align 8
+  br label %bb117
+
+bb117:                                            ; preds = %bb114
+  %tmp118 = add nuw nsw i64 %j14.0, 1
+  br label %bb113
+
+bb119:                                            ; preds = %bb113
+  br label %bb120
+
+bb120:                                            ; preds = %bb119
+  %tmp121 = add nuw nsw i64 %i13.0, 1
+  br label %bb111
+
+bb122:                                            ; preds = %bb111
+  br label %bb123
+
+bb123:                                            ; preds = %bb132, %bb122
+  %i15.0 = phi i64 [ 0, %bb122 ], [ %tmp133, %bb132 ]
+  %exitcond11 = icmp ne i64 %i15.0, 1024
+  br i1 %exitcond11, label %bb124, label %bb134
+
+bb124:                                            ; preds = %bb123
+  br label %bb125
+
+bb125:                                            ; preds = %bb129, %bb124
+  %j16.0 = phi i64 [ 0, %bb124 ], [ %tmp130, %bb129 ]
+  %exitcond10 = icmp ne i64 %j16.0, 1024
+  br i1 %exitcond10, label %bb126, label %bb131
+
+bb126:                                            ; preds = %bb125
+  %tmp127 = load i64, i64* %A, align 8
+  %tmp128 = add nsw i64 %tmp127, 42
+  store i64 %tmp128, i64* %A, align 8
+  br label %bb129
+
+bb129:                                            ; preds = %bb126
+  %tmp130 = add nuw nsw i64 %j16.0, 1
+  br label %bb125
+
+bb131:                                            ; preds = %bb125
+  br label %bb132
+
+bb132:                                            ; preds = %bb131
+  %tmp133 = add nuw nsw i64 %i15.0, 1
+  br label %bb123
+
+bb134:                                            ; preds = %bb123
+  br label %bb135
+
+bb135:                                            ; preds = %bb144, %bb134
+  %i17.0 = phi i64 [ 0, %bb134 ], [ %tmp145, %bb144 ]
+  %exitcond9 = icmp ne i64 %i17.0, 1024
+  br i1 %exitcond9, label %bb136, label %bb146
+
+bb136:                                            ; preds = %bb135
+  br label %bb137
+
+bb137:                                            ; preds = %bb141, %bb136
+  %j18.0 = phi i64 [ 0, %bb136 ], [ %tmp142, %bb141 ]
+  %exitcond8 = icmp ne i64 %j18.0, 1024
+  br i1 %exitcond8, label %bb138, label %bb143
+
+bb138:                                            ; preds = %bb137
+  %tmp139 = load i64, i64* %A, align 8
+  %tmp140 = add nsw i64 %tmp139, 42
+  store i64 %tmp140, i64* %A, align 8
+  br label %bb141
+
+bb141:                                            ; preds = %bb138
+  %tmp142 = add nuw nsw i64 %j18.0, 1
+  br label %bb137
+
+bb143:                                            ; preds = %bb137
+  br label %bb144
+
+bb144:                                            ; preds = %bb143
+  %tmp145 = add nuw nsw i64 %i17.0, 1
+  br label %bb135
+
+bb146:                                            ; preds = %bb135
+  br label %bb147
+
+bb147:                                            ; preds = %bb156, %bb146
+  %i19.0 = phi i64 [ 0, %bb146 ], [ %tmp157, %bb156 ]
+  %exitcond7 = icmp ne i64 %i19.0, 1024
+  br i1 %exitcond7, label %bb148, label %bb158
+
+bb148:                                            ; preds = %bb147
+  br label %bb149
+
+bb149:                                            ; preds = %bb153, %bb148
+  %j20.0 = phi i64 [ 0, %bb148 ], [ %tmp154, %bb153 ]
+  %exitcond6 = icmp ne i64 %j20.0, 1024
+  br i1 %exitcond6, label %bb150, label %bb155
+
+bb150:                                            ; preds = %bb149
+  %tmp151 = load i64, i64* %A, align 8
+  %tmp152 = add nsw i64 %tmp151, 42
+  store i64 %tmp152, i64* %A, align 8
+  br label %bb153
+
+bb153:                                            ; preds = %bb150
+  %tmp154 = add nuw nsw i64 %j20.0, 1
+  br label %bb149
+
+bb155:                                            ; preds = %bb149
+  br label %bb156
+
+bb156:                                            ; preds = %bb155
+  %tmp157 = add nuw nsw i64 %i19.0, 1
+  br label %bb147
+
+bb158:                                            ; preds = %bb147
+  br label %bb159
+
+bb159:                                            ; preds = %bb168, %bb158
+  %i21.0 = phi i64 [ 0, %bb158 ], [ %tmp169, %bb168 ]
+  %exitcond5 = icmp ne i64 %i21.0, 1024
+  br i1 %exitcond5, label %bb160, label %bb170
+
+bb160:                                            ; preds = %bb159
+  br label %bb161
+
+bb161:                                            ; preds = %bb165, %bb160
+  %j22.0 = phi i64 [ 0, %bb160 ], [ %tmp166, %bb165 ]
+  %exitcond4 = icmp ne i64 %j22.0, 1024
+  br i1 %exitcond4, label %bb162, label %bb167
+
+bb162:                                            ; preds = %bb161
+  %tmp163 = load i64, i64* %A, align 8
+  %tmp164 = add nsw i64 %tmp163, 42
+  store i64 %tmp164, i64* %A, align 8
+  br label %bb165
+
+bb165:                                            ; preds = %bb162
+  %tmp166 = add nuw nsw i64 %j22.0, 1
+  br label %bb161
+
+bb167:                                            ; preds = %bb161
+  br label %bb168
+
+bb168:                                            ; preds = %bb167
+  %tmp169 = add nuw nsw i64 %i21.0, 1
+  br label %bb159
+
+bb170:                                            ; preds = %bb159
+  br label %bb171
+
+bb171:                                            ; preds = %bb180, %bb170
+  %i23.0 = phi i64 [ 0, %bb170 ], [ %tmp181, %bb180 ]
+  %exitcond3 = icmp ne i64 %i23.0, 1024
+  br i1 %exitcond3, label %bb172, label %bb182
+
+bb172:                                            ; preds = %bb171
+  br label %bb173
+
+bb173:                                            ; preds = %bb177, %bb172
+  %j24.0 = phi i64 [ 0, %bb172 ], [ %tmp178, %bb177 ]
+  %exitcond2 = icmp ne i64 %j24.0, 1024
+  br i1 %exitcond2, label %bb174, label %bb179
+
+bb174:                                            ; preds = %bb173
+  %tmp175 = load i64, i64* %A, align 8
+  %tmp176 = add nsw i64 %tmp175, 42
+  store i64 %tmp176, i64* %A, align 8
+  br label %bb177
+
+bb177:                                            ; preds = %bb174
+  %tmp178 = add nuw nsw i64 %j24.0, 1
+  br label %bb173
+
+bb179:                                            ; preds = %bb173
+  br label %bb180
+
+bb180:                                            ; preds = %bb179
+  %tmp181 = add nuw nsw i64 %i23.0, 1
+  br label %bb171
+
+bb182:                                            ; preds = %bb171
+  br label %bb183
+
+bb183:                                            ; preds = %bb192, %bb182
+  %i25.0 = phi i64 [ 0, %bb182 ], [ %tmp193, %bb192 ]
+  %exitcond1 = icmp ne i64 %i25.0, 1024
+  br i1 %exitcond1, label %bb184, label %bb194
+
+bb184:                                            ; preds = %bb183
+  br label %bb185
+
+bb185:                                            ; preds = %bb189, %bb184
+  %j26.0 = phi i64 [ 0, %bb184 ], [ %tmp190, %bb189 ]
+  %exitcond = icmp ne i64 %j26.0, 1024
+  br i1 %exitcond, label %bb186, label %bb191
+
+bb186:                                            ; preds = %bb185
+  %tmp187 = load i64, i64* %A, align 8
+  %tmp188 = add nsw i64 %tmp187, 42
+  store i64 %tmp188, i64* %A, align 8
+  br label %bb189
+
+bb189:                                            ; preds = %bb186
+  %tmp190 = add nuw nsw i64 %j26.0, 1
+  br label %bb185
+
+bb191:                                            ; preds = %bb185
+  br label %bb192
+
+bb192:                                            ; preds = %bb191
+  %tmp193 = add nuw nsw i64 %i25.0, 1
+  br label %bb183
+
+bb194:                                            ; preds = %bb183
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_simple_iv.ll b/final/test/DependenceInfo/reduction_simple_iv.ll
new file mode 100644
index 0000000..53553b2
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_simple_iv.ll
@@ -0,0 +1,40 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_for_cond[i0] -> Stmt_for_cond[1 + i0] : 0 <= i0 <= 99 }
+;
+; void f(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_simple_iv_debug_wrapped_dependences.ll b/final/test/DependenceInfo/reduction_simple_iv_debug_wrapped_dependences.ll
new file mode 100644
index 0000000..4e78380
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_simple_iv_debug_wrapped_dependences.ll
@@ -0,0 +1,95 @@
+; RUN: opt %loadPolly -polly-dependences -analyze -debug-only=polly-dependence 2>&1 < %s | FileCheck %s
+;
+; REQUIRES: asserts
+;
+; CHECK:      Read: { [Stmt_for_cond[i0] -> MemRef_sum[0{{\]\]}} -> MemRef_sum[0] : 0 <= i0 <= 100 }
+; CHECK-NEXT: Write: { [Stmt_for_cond[i0] -> MemRef_sum[0{{\]\]}} -> MemRef_sum[0] : 0 <= i0 <= 100 }
+; CHECK-NEXT: MayWrite: {  }
+;
+; CHECK:      Wrapped Dependences:
+; CHECK-NEXT:     RAW dependences:
+; CHECK-NEXT:         { [Stmt_for_cond[i0] -> MemRef_sum[0{{\]\]}} -> [Stmt_for_cond[1 + i0] -> MemRef_sum[0{{\]\]}} : 0 <= i0 <= 99 }
+; CHECK-NEXT:     WAR dependences:
+; CHECK-NEXT:         { [Stmt_for_cond[i0] -> MemRef_sum[0{{\]\]}} -> [Stmt_for_cond[1 + i0] -> MemRef_sum[0{{\]\]}} : 0 <= i0 <= 99 }
+; CHECK-NEXT:     WAW dependences:
+; CHECK-NEXT:         { [Stmt_for_cond[i0] -> MemRef_sum[0{{\]\]}} -> [Stmt_for_cond[1 + i0] -> MemRef_sum[0{{\]\]}} : 0 <= i0 <= 99 }
+; CHECK-NEXT:     Reduction dependences:
+; CHECK-NEXT:         n/a
+;
+; CHECK:      Final Wrapped Dependences:
+; CHECK-NEXT:     RAW dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     WAR dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     WAW dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     Reduction dependences:
+; CHECK-NEXT:         { [Stmt_for_cond[i0] -> MemRef_sum[0{{\]\]}} -> [Stmt_for_cond[1 + i0] -> MemRef_sum[0{{\]\]}} : 0 <= i0 <= 99 }
+;
+; CHECK:      Zipped Dependences:
+; CHECK-NEXT:     RAW dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     WAR dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     WAW dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     Reduction dependences:
+; CHECK-NEXT:         { [Stmt_for_cond[i0] -> Stmt_for_cond[1 + i0{{\]\]}} -> [MemRef_sum[0] -> MemRef_sum[0{{\]\]}} : 0 <= i0 <= 99 }
+;
+; CHECK:      Unwrapped Dependences:
+; CHECK-NEXT:     RAW dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     WAR dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     WAW dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     Reduction dependences:
+; CHECK-NEXT:         { Stmt_for_cond[i0] -> Stmt_for_cond[1 + i0] : 0 <= i0 <= 99 }
+;
+; CHECK:          RAW dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     WAR dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     WAW dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     Reduction dependences:
+; CHECK-NEXT:         { Stmt_for_cond[i0] -> Stmt_for_cond[1 + i0] : 0 <= i0 <= 99 }
+;
+; CHECK:          RAW dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     WAR dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     WAW dependences:
+; CHECK-NEXT:         {  }
+; CHECK-NEXT:     Reduction dependences:
+; CHECK-NEXT:         { Stmt_for_cond[i0] -> Stmt_for_cond[1 + i0] : 0 <= i0 <= 99 }
+;
+; void f(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_simple_privatization_deps_2.ll b/final/test/DependenceInfo/reduction_simple_privatization_deps_2.ll
new file mode 100644
index 0000000..215abc9
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_simple_privatization_deps_2.ll
@@ -0,0 +1,75 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     { Stmt_S0[i0] -> Stmt_S1[i0, o1] : 0 <= i0 <= 99 and 0 <= o1 <= 99; Stmt_S2[i0] -> Stmt_S0[1 + i0] : 0 <= i0 <= 98; Stmt_S1[i0, i1] -> Stmt_S2[i0] : 0 <= i0 <= 99 and 0 <= i1 <= 99 }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     { Stmt_S0[i0] -> Stmt_S1[i0, o1] : 0 <= i0 <= 99 and 0 <= o1 <= 99; Stmt_S2[i0] -> Stmt_S0[1 + i0] : 0 <= i0 <= 98; Stmt_S1[i0, i1] -> Stmt_S2[i0] : 0 <= i0 <= 99 and 0 <= i1 <= 99 }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     { Stmt_S0[i0] -> Stmt_S1[i0, o1] : 0 <= i0 <= 99 and 0 <= o1 <= 99; Stmt_S2[i0] -> Stmt_S0[1 + i0] : 0 <= i0 <= 98; Stmt_S1[i0, i1] -> Stmt_S2[i0] : 0 <= i0 <= 99 and 0 <= i1 <= 99 }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_S1[i0, i1] -> Stmt_S1[i0, 1 + i1] : 0 <= i0 <= 99 and 0 <= i1 <= 98 }
+;
+;    void f(int *sum) {
+;      for (int i = 0; i < 100; i++) {
+; S0:    *sum *= 42;
+;        for (int j = 0; j < 100; j++)
+; S1:      *sum += i * j;
+; S2:    *sum *= 7;
+;      }
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum)  {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc6, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc7, %for.inc6 ]
+  %exitcond1 = icmp ne i32 %i.0, 100
+  br i1 %exitcond1, label %for.body, label %for.end8
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %sum, align 4
+  %mul = mul nsw i32 %tmp, 42
+  store i32 %mul, i32* %sum, align 4
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %S0
+  %j.0 = phi i32 [ 0, %S0 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 100
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  br label %S1
+
+S1:                                               ; preds = %for.body3
+  %mul4 = mul nsw i32 %i.0, %j.0
+  %tmp2 = load i32, i32* %sum, align 4
+  %add = add nsw i32 %tmp2, %mul4
+  store i32 %add, i32* %sum, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S1
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %S2
+
+S2:                                               ; preds = %for.end
+  %tmp3 = load i32, i32* %sum, align 4
+  %mul5 = mul nsw i32 %tmp3, 7
+  store i32 %mul5, i32* %sum, align 4
+  br label %for.inc6
+
+for.inc6:                                         ; preds = %S2
+  %inc7 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end8:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_simple_privatization_deps_w_parameter.ll b/final/test/DependenceInfo/reduction_simple_privatization_deps_w_parameter.ll
new file mode 100644
index 0000000..9ef1d74
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_simple_privatization_deps_w_parameter.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     [N] -> { Stmt_S0[] -> Stmt_S1[o0] : N >= 11 and 0 <= o0 <= 1023; Stmt_S1[i0] -> Stmt_S2[] : N >= 11 and 0 <= i0 <= 1023 }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     [N] -> { Stmt_S1[i0] -> Stmt_S2[] : N >= 11 and 0 <= i0 <= 1023 }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     [N] -> { Stmt_S0[] -> Stmt_S1[o0] : N >= 11 and 0 <= o0 <= 1023; Stmt_S1[i0] -> Stmt_S2[] : N >= 11 and 0 <= i0 <= 1023 }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     [N] -> { Stmt_S1[i0] -> Stmt_S1[1 + i0] : N >= 11 and 0 <= i0 <= 1022 }
+;
+;    void f(int *sum, int N) {
+;      if (N >= 10) {
+; S0:    *sum = 0;
+;        for (int i = 0; i < 1024; i++)
+; S1:      *sum += i;
+; S2:    *sum = *sum * 3;
+;      }
+;    }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum, i32 %N) {
+entry:
+  br label %entry.1
+
+entry.1:
+  %excond = icmp sgt i32 %N, 10
+  br i1 %excond, label %S0, label %f.end
+
+S0:
+  store i32 0, i32* %sum, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %S0
+  %i.0 = phi i32 [ 0, %S0 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %S1, label %S2
+
+S1:                                               ; preds = %for.cond
+  %tmp = load i32, i32* %sum, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %sum, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S1
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+S2:                                               ; preds = %for.cond
+  %tmp1 = load i32, i32* %sum, align 4
+  %mul = mul nsw i32 %tmp1, 3
+  store i32 %mul, i32* %sum, align 4
+  br label %f.end
+
+f.end:
+  ret void
+}
diff --git a/final/test/DependenceInfo/reduction_two_reductions_different_rloops.ll b/final/test/DependenceInfo/reduction_two_reductions_different_rloops.ll
new file mode 100644
index 0000000..1404d15
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_two_reductions_different_rloops.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -basicaa -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: WAR dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: WAW dependences:
+; CHECK-NEXT:     {  }
+; CHECK-NEXT: Reduction dependences:
+; CHECK-NEXT:     { Stmt_for_body3[i0, i1] -> Stmt_for_body3[o0, 1 + i0 + i1 - o0] : i0 >= 0 and i1 >= 0 and o0 >= -1022 + i0 + i1 and i0 <= o0 <= 1023 and o0 <= 1 + i0 }
+;
+; void f(int *restrict A, int *restrict B, int *restrict Values) {
+;   for (int i = 0; i < 1024; i++) {
+;     for (int j = 0; j < 1024; j++) {
+;       A[i] += Values[i + j - 1];
+;       B[j] += Values[i + j + 42];
+;     }
+;   }
+; }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* noalias %A, i32* noalias %B, i32* noalias %Values)  {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc11, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc12, %for.inc11 ]
+  %exitcond1 = icmp ne i32 %i.0, 1024
+  br i1 %exitcond1, label %for.body, label %for.end13
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %add = add nsw i32 %i.0, %j.0
+  %sub = add nsw i32 %add, -1
+  %arrayidx = getelementptr inbounds i32, i32* %Values, i32 %sub
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx4 = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp2 = load i32, i32* %arrayidx4, align 4
+  %add5 = add nsw i32 %tmp2, %tmp
+  store i32 %add5, i32* %arrayidx4, align 4
+  %add6 = add nsw i32 %i.0, %j.0
+  %add7 = add nsw i32 %add6, 42
+  %arrayidx8 = getelementptr inbounds i32, i32* %Values, i32 %add7
+  %tmp3 = load i32, i32* %arrayidx8, align 4
+  %arrayidx9 = getelementptr inbounds i32, i32* %B, i32 %j.0
+  %tmp4 = load i32, i32* %arrayidx9, align 4
+  %add10 = add nsw i32 %tmp4, %tmp3
+  store i32 %add10, i32* %arrayidx9, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc11
+
+for.inc11:                                        ; preds = %for.end
+  %inc12 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end13:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/DependenceInfo/sequential_loops.ll b/final/test/DependenceInfo/sequential_loops.ll
new file mode 100644
index 0000000..1e81ec8
--- /dev/null
+++ b/final/test/DependenceInfo/sequential_loops.ll
@@ -0,0 +1,295 @@
+; RUN: opt -S %loadPolly -basicaa -polly-dependences -analyze -polly-dependences-analysis-type=value-based < %s | FileCheck %s -check-prefix=VALUE
+; RUN: opt -S %loadPolly -basicaa -polly-dependences -analyze -polly-dependences-analysis-type=memory-based < %s | FileCheck %s -check-prefix=MEMORY
+; RUN: opt -S %loadPolly -basicaa -polly-dependences -analyze -polly-dependences-analysis-type=value-based -polly-dependences-analysis-level=access-wise < %s | FileCheck %s -check-prefix=VALUE_ACCESS
+
+; VALUE-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'sequential_writes':
+; VALUE-NEXT:      RAW dependences:
+; VALUE-NEXT:          {  }
+; VALUE-NEXT:      WAR dependences:
+; VALUE-NEXT:          {  }
+; VALUE-NEXT:      WAW dependences:
+; VALUE-NEXT:          { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 }
+;
+;VALUE_ACCESS-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'sequential_writes':
+;VALUE_ACCESS-NEXT:        RAW dependences:
+;VALUE_ACCESS-NEXT:                {  }
+;VALUE_ACCESS-NEXT:        WAR dependences:
+;VALUE_ACCESS-NEXT:                {  }
+;VALUE_ACCESS-NEXT:        WAW dependences:
+;VALUE_ACCESS-NEXT:                { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; [Stmt_S1[i0] -> Stmt_S1_Write0[]] -> [Stmt_S2[i0] -> Stmt_S2_Write0[]] : 0 <= i0 <= 9; Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; [Stmt_S2[i0] -> Stmt_S2_Write0[]] -> [Stmt_S3[i0] -> Stmt_S3_Write0[]] : 0 <= i0 <= 9; [Stmt_S1[i0] -> Stmt_S1_Write0[]] -> [Stmt_S3[i0] -> Stmt_S3_Write0[]] : 10 <= i0 <= 99; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 }
+
+;
+; VALUE-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'read_after_writes':
+; VALUE-NEXT:      RAW dependences:
+; VALUE-NEXT:          { Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 }
+; VALUE-NEXT:      WAR dependences:
+; VALUE-NEXT:          {  }
+; VALUE-NEXT:      WAW dependences:
+; VALUE-NEXT:          { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9 }
+;
+;VALUE_ACCESS-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'read_after_writes':
+;VALUE_ACCESS-NEXT:        RAW dependences:
+;VALUE_ACCESS-NEXT:                { [Stmt_S1[i0] -> Stmt_S1_Write0[]] -> [Stmt_S3[i0] -> Stmt_S3_Read0[]] : 10 <= i0 <= 99; [Stmt_S2[i0] -> Stmt_S2_Write0[]] -> [Stmt_S3[i0] -> Stmt_S3_Read0[]] : 0 <= i0 <= 9; Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 }
+
+;VALUE_ACCESS-NEXT:        WAR dependences:
+;VALUE_ACCESS-NEXT:                {  }
+;VALUE_ACCESS-NEXT:        WAW dependences:
+;VALUE_ACCESS-NEXT:                { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; [Stmt_S1[i0] -> Stmt_S1_Write0[]] -> [Stmt_S2[i0] -> Stmt_S2_Write0[]] : 0 <= i0 <= 9 }
+;
+; VALUE-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'write_after_read':
+; VALUE-NEXT:      RAW dependences:
+; VALUE-NEXT:          {  }
+; VALUE-NEXT:      WAR dependences:
+; VALUE-NEXT:          { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 }
+; VALUE-NEXT:      WAW dependences:
+; VALUE-NEXT:          { Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9 }
+;
+;VALUE_ACCESS-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'write_after_read':
+;VALUE_ACCESS-NEXT:         RAW dependences:
+;VALUE_ACCESS-NEXT:                 {  }
+;VALUE_ACCESS-NEXT:         WAR dependences:
+;VALUE_ACCESS-NEXT:                { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; [Stmt_S1[i0] -> Stmt_S1_Read0[]] -> [Stmt_S2[i0] -> Stmt_S2_Write0[]] : 0 <= i0 <= 9; [Stmt_S1[i0] -> Stmt_S1_Read0[]] -> [Stmt_S3[i0] -> Stmt_S3_Write0[]] : 10 <= i0 <= 99; Stmt_S1[i0] -> Stmt_S3[i0] : 10 <= i0 <= 99 }
+;VALUE_ACCESS-NEXT:         WAW dependences:
+;VALUE_ACCESS-NEXT:                { Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; [Stmt_S2[i0] -> Stmt_S2_Write0[]] -> [Stmt_S3[i0] -> Stmt_S3_Write0[]] : 0 <= i0 <= 9 }
+;
+; VALUE-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.2' in function 'parametric_offset':
+; VALUE-NEXT:      RAW dependences:
+; VALUE-NEXT:          [p] -> { Stmt_S1[i0] -> Stmt_S2[-p + i0] : i0 >= p and 0 <= i0 <= 99 and i0 <= 9 + p }
+; VALUE-NEXT:      WAR dependences:
+; VALUE-NEXT:          [p] -> {  }
+; VALUE-NEXT:      WAW dependences:
+; VALUE-NEXT:          [p] -> {  }
+;
+;VALUE_ACCESS-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.2' in function 'parametric_offset':
+;VALUE_ACCESS-NEXT:        RAW dependences:
+;VALUE_ACCESS-NEXT:                [p] -> { [Stmt_S1[i0] -> Stmt_S1_Write0[]] -> [Stmt_S2[-p + i0] -> Stmt_S2_Read0[]] : i0 >= p and 0 <= i0 <= 99 and i0 <= 9 + p; Stmt_S1[i0] -> Stmt_S2[-p + i0] : i0 >= p and 0 <= i0 <= 99 and i0 <= 9 + p }
+;VALUE_ACCESS-NEXT:        WAR dependences:
+;VALUE_ACCESS-NEXT:                [p] -> {  }
+;VALUE_ACCESS-NEXT:        WAW dependences:
+;VALUE_ACCESS-NEXT:                [p] -> {  }
+
+; MEMORY-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'sequential_writes':
+; MEMORY-NEXT:      RAW dependences:
+; MEMORY-NEXT:          {  }
+; MEMORY-NEXT:      WAR dependences:
+; MEMORY-NEXT:          {  }
+; MEMORY-NEXT:      WAW dependences:
+; MEMORY-NEXT:          { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; Stmt_S1[i0] -> Stmt_S3[i0] : 0 <= i0 <= 99 }
+;
+; MEMORY-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'read_after_writes':
+; MEMORY-NEXT:      RAW dependences:
+; MEMORY-NEXT:          { Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9; Stmt_S1[i0] -> Stmt_S3[i0] : 0 <= i0 <= 99 }
+; MEMORY-NEXT:      WAR dependences:
+; MEMORY-NEXT:          {  }
+; MEMORY-NEXT:      WAW dependences:
+; MEMORY-NEXT:          { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9 }
+;
+; MEMORY-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.3' in function 'write_after_read':
+; MEMORY-NEXT:      RAW dependences:
+; MEMORY-NEXT:          {  }
+; MEMORY-NEXT:      WAR dependences:
+; MEMORY-NEXT:          { Stmt_S1[i0] -> Stmt_S2[i0] : 0 <= i0 <= 9; Stmt_S1[i0] -> Stmt_S3[i0] : 0 <= i0 <= 99 }
+; MEMORY-NEXT:      WAW dependences:
+; MEMORY-NEXT:          { Stmt_S2[i0] -> Stmt_S3[i0] : 0 <= i0 <= 9 }
+;
+; MEMORY-LABEL: Printing analysis 'Polly - Calculate dependences' for region: 'S1 => exit.2' in function 'parametric_offset':
+; MEMORY-NEXT:      RAW dependences:
+; MEMORY-NEXT:          [p] -> { Stmt_S1[i0] -> Stmt_S2[-p + i0] : i0 >= p and 0 <= i0 <= 99 and i0 <= 9 + p }
+; MEMORY-NEXT:      WAR dependences:
+; MEMORY-NEXT:          [p] -> {  }
+; MEMORY-NEXT:      WAW dependences:
+; MEMORY-NEXT:          [p] -> {  }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+;     for(i = 0; i < 100; i++ )
+; S1:   A[i] = 2;
+;
+;     for (i = 0; i < 10; i++ )
+; S2:   A[i]  = 5;
+;
+;     for (i = 0; i < 200; i++ )
+; S3:   A[i] = 5;
+
+define void @sequential_writes() {
+entry:
+  %A = alloca [200 x i32]
+  br label %S1
+
+S1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %S1 ]
+  %arrayidx.1 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.1
+  store i32 2, i32* %arrayidx.1
+  %indvar.next.1 = add i64 %indvar.1, 1
+  %exitcond.1 = icmp ne i64 %indvar.next.1, 100
+  br i1 %exitcond.1, label %S1, label %exit.1
+
+exit.1:
+  br label %S2
+
+S2:
+  %indvar.2 = phi i64 [ 0, %exit.1 ], [ %indvar.next.2, %S2 ]
+  %arrayidx.2 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.2
+  store i32 5, i32* %arrayidx.2
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %exitcond.2 = icmp ne i64 %indvar.next.2, 10
+  br i1 %exitcond.2, label %S2, label %exit.2
+
+exit.2:
+  br label %S3
+
+S3:
+  %indvar.3 = phi i64 [ 0, %exit.2 ], [ %indvar.next.3, %S3 ]
+  %arrayidx.3 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.3
+  store i32 7, i32* %arrayidx.3
+  %indvar.next.3 = add i64 %indvar.3, 1
+  %exitcond.3 = icmp ne i64 %indvar.next.3, 200
+  br i1 %exitcond.3, label %S3 , label %exit.3
+
+exit.3:
+  ret void
+}
+
+
+;     for(i = 0; i < 100; i++ )
+; S1:   A[i] = 2;
+;
+;     for (i = 0; i < 10; i++ )
+; S2:   A[i]  = 5;
+;
+;     for (i = 0; i < 200; i++ )
+; S3:   B[i] = A[i];
+
+define void @read_after_writes() {
+entry:
+  %A = alloca [200 x i32]
+  %B = alloca [200 x i32]
+  br label %S1
+
+S1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %S1 ]
+  %arrayidx.1 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.1
+  store i32 2, i32* %arrayidx.1
+  %indvar.next.1 = add i64 %indvar.1, 1
+  %exitcond.1 = icmp ne i64 %indvar.next.1, 100
+  br i1 %exitcond.1, label %S1, label %exit.1
+
+exit.1:
+  br label %S2
+
+S2:
+  %indvar.2 = phi i64 [ 0, %exit.1 ], [ %indvar.next.2, %S2 ]
+  %arrayidx.2 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.2
+  store i32 5, i32* %arrayidx.2
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %exitcond.2 = icmp ne i64 %indvar.next.2, 10
+  br i1 %exitcond.2, label %S2, label %exit.2
+
+exit.2:
+  br label %S3
+
+S3:
+  %indvar.3 = phi i64 [ 0, %exit.2 ], [ %indvar.next.3, %S3 ]
+  %arrayidx.3.a = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.3
+  %arrayidx.3.b = getelementptr [200 x i32], [200 x i32]* %B, i64 0, i64 %indvar.3
+  %val = load i32, i32* %arrayidx.3.a
+  store i32 %val, i32* %arrayidx.3.b
+  %indvar.next.3 = add i64 %indvar.3, 1
+  %exitcond.3 = icmp ne i64 %indvar.next.3, 200
+  br i1 %exitcond.3, label %S3 , label %exit.3
+
+exit.3:
+  ret void
+}
+
+
+;     for(i = 0; i < 100; i++ )
+; S1:   B[i] = A[i];
+;
+;     for (i = 0; i < 10; i++ )
+; S2:   A[i]  = 5;
+;
+;     for (i = 0; i < 200; i++ )
+; S3:   A[i]  = 10;
+
+define void @write_after_read() {
+entry:
+  %A = alloca [200 x i32]
+  %B = alloca [200 x i32]
+  br label %S1
+
+S1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %S1 ]
+  %arrayidx.1.a = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.1
+  %arrayidx.1.b = getelementptr [200 x i32], [200 x i32]* %B, i64 0, i64 %indvar.1
+  %val = load i32, i32* %arrayidx.1.a
+  store i32 %val, i32* %arrayidx.1.b
+  %indvar.next.1 = add i64 %indvar.1, 1
+  %exitcond.1 = icmp ne i64 %indvar.next.1, 100
+  br i1 %exitcond.1, label %S1, label %exit.1
+
+exit.1:
+  br label %S2
+
+S2:
+  %indvar.2 = phi i64 [ 0, %exit.1 ], [ %indvar.next.2, %S2 ]
+  %arrayidx.2 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.2
+  store i32 5, i32* %arrayidx.2
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %exitcond.2 = icmp ne i64 %indvar.next.2, 10
+  br i1 %exitcond.2, label %S2, label %exit.2
+
+exit.2:
+  br label %S3
+
+S3:
+  %indvar.3 = phi i64 [ 0, %exit.2 ], [ %indvar.next.3, %S3 ]
+  %arrayidx.3 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.3
+  store i32 10, i32* %arrayidx.3
+  %indvar.next.3 = add i64 %indvar.3, 1
+  %exitcond.3 = icmp ne i64 %indvar.next.3, 200
+  br i1 %exitcond.3, label %S3 , label %exit.3
+
+exit.3:
+  ret void
+}
+
+
+;     for(i = 0; i < 100; i++ )
+; S1:   A[i] = 10
+;
+;     for(i = 0; i < 100; i++ )
+; S2:   B[i] = A[i + p];
+
+define void @parametric_offset(i64 %p) {
+entry:
+  %A = alloca [200 x i32]
+  %B = alloca [200 x i32]
+  br label %S1
+
+S1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %S1 ]
+  %arrayidx.1 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.1
+  store i32 10, i32* %arrayidx.1
+  %indvar.next.1 = add i64 %indvar.1, 1
+  %exitcond.1 = icmp ne i64 %indvar.next.1, 100
+  br i1 %exitcond.1, label %S1, label %exit.1
+
+exit.1:
+  br label %S2
+
+S2:
+  %indvar.2 = phi i64 [ 0, %exit.1 ], [ %indvar.next.2, %S2 ]
+  %sum = add i64 %indvar.2, %p
+  %arrayidx.2.a = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %sum
+  %arrayidx.2.b = getelementptr [200 x i32], [200 x i32]* %B, i64 0, i64 %indvar.2
+  %val = load i32, i32* %arrayidx.2.a
+  store i32 %val, i32* %arrayidx.2.b
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %exitcond.2 = icmp ne i64 %indvar.next.2, 10
+  br i1 %exitcond.2, label %S2, label %exit.2
+
+exit.2:
+  ret void
+}
+
diff --git a/final/test/FlattenSchedule/gemm.ll b/final/test/FlattenSchedule/gemm.ll
new file mode 100644
index 0000000..bff0b05
--- /dev/null
+++ b/final/test/FlattenSchedule/gemm.ll
@@ -0,0 +1,98 @@
+; RUN: opt %loadPolly -polly-flatten-schedule -analyze < %s | FileCheck %s
+;
+; dgemm kernel
+; C := alpha*A*B + beta*C
+; C[ni][nj]
+; A[ni][nk]
+; B[nk][nj]
+
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+
+define void @gemm(i32 %ni, i32 %nj, i32 %nk, double %alpha, double %beta, double* noalias nonnull %C, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %ni.for
+
+ni.for:
+  %i = phi i32 [0, %entry], [%i.inc, %ni.inc]
+  %i.cmp = icmp slt i32 %i, 3
+  br i1 %i.cmp, label %nj.for, label %ni.exit
+
+  nj.for:
+    %j = phi i32 [0, %ni.for], [%j.inc, %nj.inc]
+    %j.cmp = icmp slt i32 %j, 7
+    br i1 %j.cmp, label %nj_beta, label %nj.exit
+
+    nj_beta:
+     %c_stride = mul nsw i32 %i, 3; %nj
+     %c_idx_i = getelementptr inbounds double, double* %C, i32 %c_stride
+     %c_idx_ij = getelementptr inbounds double, double* %c_idx_i, i32 %j
+
+     ; C[i][j] *= beta
+     %c = load double, double* %c_idx_ij
+     %c_beta = fmul double %c, %beta
+     store double %c_beta, double* %c_idx_ij
+
+     br label %nk.for
+
+    nk.for:
+      %k = phi i32 [0, %nj_beta], [%k.inc, %nk.inc]
+      %k.cmp = icmp slt i32 %k, 3 ; %nk
+      br i1 %k.cmp, label %nk_alpha, label %nk.exit
+
+      nk_alpha:
+        %a_stride = mul nsw i32 %i, 3; %nk
+        %a_idx_i = getelementptr inbounds double, double* %A, i32 %a_stride
+        %a_idx_ik = getelementptr inbounds double, double* %a_idx_i, i32 %k
+
+        %b_stride = mul nsw i32 %k, 3; %nj
+        %b_idx_k = getelementptr inbounds double, double* %B, i32 %b_stride
+        %b_idx_kj = getelementptr inbounds double, double* %b_idx_k, i32 %j
+
+        ; C[i][j] += alpha * A[i][k] * B[k][j]
+        %a = load double, double* %a_idx_ik
+        %b = load double, double* %b_idx_kj
+        %beta_c = load double, double* %c_idx_ij
+
+        %alpha_a = fmul double %a, %alpha
+        %alpha_a_b = fmul double %alpha_a, %b
+        %beta_c_alpha_a_b = fadd double %beta_c, %alpha_a_b
+
+        store double %beta_c_alpha_a_b, double* %c_idx_ij
+
+        br label %nk.inc
+
+    nk.inc:
+      %k.inc = add nuw nsw i32 %k, 1
+      br label %nk.for
+
+    nk.exit:
+      ; store double %c, double* %c_idx_ij
+      br label %nj.inc
+
+  nj.inc:
+    %j.inc = add nuw nsw i32 %j, 1
+    br label %nj.for
+
+  nj.exit:
+    br label %ni.inc
+
+ni.inc:
+  %i.inc = add nuw nsw i32 %i, 1
+  br label %ni.for
+
+ni.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      Schedule before flattening {
+; CHECK-NEXT:     { Stmt_nk_alpha[i0, i1, i2] -> [i0, i1, 1, i2] }
+; CHECK-NEXT:     { Stmt_nj_beta[i0, i1] -> [i0, i1, 0, 0] }
+; CHECK-NEXT: }
+; CHECK:      Schedule after flattening {
+; CHECK-NEXT:     { Stmt_nj_beta[i0, i1] -> [28i0 + 4i1] }
+; CHECK-NEXT:     { Stmt_nk_alpha[i0, i1, i2] -> [1 + 28i0 + 4i1 + i2] }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/atax.ll b/final/test/ForwardOpTree/atax.ll
new file mode 100644
index 0000000..12b2b20
--- /dev/null
+++ b/final/test/ForwardOpTree/atax.ll
@@ -0,0 +1,154 @@
+; RUN: opt %loadPolly -polly-optree-normalize-phi=true -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define internal fastcc void @kernel_atax([2100 x double]* nocapture readonly %A, double* nocapture readonly %x, double* nocapture %y, double* nocapture %tmp) unnamed_addr #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %y15 = bitcast double* %y to i8*
+  call void @llvm.memset.p0i8.i64(i8* %y15, i8 0, i64 16800, i32 8, i1 false)
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.inc40, %entry.split
+  %indvars.iv8 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next9, %for.inc40 ]
+  %arrayidx5 = getelementptr inbounds double, double* %tmp, i64 %indvars.iv8
+  store double 0.000000e+00, double* %arrayidx5, align 8, !tbaa !6
+  br label %for.body8
+
+for.body8:                                        ; preds = %for.body8, %for.body3
+  %0 = phi double [ 0.000000e+00, %for.body3 ], [ %add, %for.body8 ]
+  %indvars.iv = phi i64 [ 0, %for.body3 ], [ %indvars.iv.next, %for.body8 ]
+  %arrayidx14 = getelementptr inbounds [2100 x double], [2100 x double]* %A, i64 %indvars.iv8, i64 %indvars.iv
+  %1 = load double, double* %arrayidx14, align 8, !tbaa !6
+  %arrayidx16 = getelementptr inbounds double, double* %x, i64 %indvars.iv
+  %2 = load double, double* %arrayidx16, align 8, !tbaa !6
+  %mul = fmul double %1, %2
+  %add = fadd double %0, %mul
+  store double %add, double* %arrayidx5, align 8, !tbaa !6
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 2
+  br i1 %exitcond, label %for.end21, label %for.body8
+
+for.end21:                                        ; preds = %for.body8
+  br label %for.body24
+
+for.body24:                                       ; preds = %for.body24.for.body24_crit_edge, %for.end21
+  %3 = phi double [ %add, %for.end21 ], [ %.pre, %for.body24.for.body24_crit_edge ]
+  %indvars.iv5 = phi i64 [ 0, %for.end21 ], [ %indvars.iv.next6, %for.body24.for.body24_crit_edge ]
+  %arrayidx26 = getelementptr inbounds double, double* %y, i64 %indvars.iv5
+  %4 = load double, double* %arrayidx26, align 8, !tbaa !6
+  %arrayidx30 = getelementptr inbounds [2100 x double], [2100 x double]* %A, i64 %indvars.iv8, i64 %indvars.iv5
+  %5 = load double, double* %arrayidx30, align 8, !tbaa !6
+  %mul33 = fmul double %5, %3
+  %add34 = fadd double %4, %mul33
+  store double %add34, double* %arrayidx26, align 8, !tbaa !6
+  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1
+  %exitcond7 = icmp eq i64 %indvars.iv.next6, 2
+  br i1 %exitcond7, label %for.inc40, label %for.body24.for.body24_crit_edge
+
+for.body24.for.body24_crit_edge:                  ; preds = %for.body24
+  %.pre = load double, double* %arrayidx5, align 8, !tbaa !6
+  br label %for.body24
+
+for.inc40:                                        ; preds = %for.body24
+  %indvars.iv.next9 = add nuw nsw i64 %indvars.iv8, 1
+  %exitcond10 = icmp eq i64 %indvars.iv.next9, 2
+  br i1 %exitcond10, label %for.end42, label %for.body3
+
+for.end42:                                        ; preds = %for.inc40
+  ret void
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) #1
+
+attributes #0 = { noinline norecurse nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { argmemonly nounwind }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang version 6.0.0 (trunk 312565) (llvm/trunk 312564)"}
+!2 = !{!3, !3, i64 0}
+!3 = !{!"any pointer", !4, i64 0}
+!4 = !{!"omnipotent char", !5, i64 0}
+!5 = !{!"Simple C/C++ TBAA"}
+!6 = !{!7, !7, i64 0}
+!7 = !{!"double", !4, i64 0}
+
+
+; CHECK: Statistics {
+; CHECK:     Operand trees forwarded: 2
+; CHECK:     Statements with forwarded operand trees: 2
+; CHECK: }
+
+; CHECK-NEXT: After statements {
+; CHECK-NEXT:     Stmt_for_body3
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_for_body3[i0] -> MemRef_tmp[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body3[i0] -> MemRef1__phi[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   store double 0.000000e+00, double* %arrayidx5, align 8, !tbaa !2
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_for_body8
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body8[i0, i1] -> MemRef1__phi[] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body8[i0, i1] -> MemRef1__phi[] };
+; CHECK-NEXT:            new: { Stmt_for_body8[i0, i1] -> MemRef_tmp[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_for_body8[i0, i1] -> MemRef_A[i0, i1] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_for_body8[i0, i1] -> MemRef_x[i1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_for_body8[i0, i1] -> MemRef_tmp[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body8[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %0 = phi double [ 0.000000e+00, %for.body3 ], [ %add, %for.body8 ]
+; CHECK-NEXT:                   %1 = load double, double* %arrayidx14, align 8, !tbaa !2
+; CHECK-NEXT:                   %2 = load double, double* %arrayidx16, align 8, !tbaa !2
+; CHECK-NEXT:                   %mul = fmul double %1, %2
+; CHECK-NEXT:                   %add = fadd double %0, %mul
+; CHECK-NEXT:                   store double %add, double* %arrayidx5, align 8, !tbaa !2
+; CHECK-NEXT:                   %exitcond = icmp eq i64 %indvars.iv.next, 2
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_for_end21
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_end21[i0] -> MemRef_add[] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_end21[i0] -> MemRef5__phi[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_for_body24
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body24[i0, i1] -> MemRef5__phi[] };
+; CHECK-NEXT:            new: { Stmt_for_body24[i0, i1] -> MemRef_tmp[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_for_body24[i0, i1] -> MemRef_y[i1] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_for_body24[i0, i1] -> MemRef_A[i0, i1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_for_body24[i0, i1] -> MemRef_y[i1] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %3 = phi double [ %add, %for.end21 ], [ %.pre, %for.body24.for.body24_crit_edge ]
+; CHECK-NEXT:                   %4 = load double, double* %arrayidx26, align 8, !tbaa !2
+; CHECK-NEXT:                   %5 = load double, double* %arrayidx30, align 8, !tbaa !2
+; CHECK-NEXT:                   %mul33 = fmul double %5, %3
+; CHECK-NEXT:                   %add34 = fadd double %4, %mul33
+; CHECK-NEXT:                   store double %add34, double* %arrayidx26, align 8, !tbaa !2
+; CHECK-NEXT:                   %exitcond7 = icmp eq i64 %indvars.iv.next6, 2
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_for_body24_for_body24_crit_edge
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body24_for_body24_crit_edge[i0, i1] -> MemRef5__phi[] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_for_body24_for_body24_crit_edge[i0, i1] -> MemRef_tmp[i0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %.pre = load double, double* %arrayidx5, align 8, !tbaa !2
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_from_region.ll b/final/test/ForwardOpTree/forward_from_region.ll
new file mode 100644
index 0000000..351758c
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_from_region.ll
@@ -0,0 +1,78 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Move instructions from region statements.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = 21.0 + 21.0;
+;   if (cond)
+;
+; bodyA_true:
+;     A[0] = 42;
+;
+; bodyB:
+;     A[0] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val = fadd double 21.0, 21.0
+      %cond = fcmp oeq double 21.0, 21.0
+      br i1 %cond, label %bodyA_true, label %bodyB
+
+    bodyA_true:
+      store double 42.0, double* %A
+      br label %bodyB
+
+    bodyB:
+      store double %val, double* %A
+      br label %bodyB_exit
+
+    bodyB_exit:
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+; CHECK:      Statistics {
+; CHECK:     Instructions copied: 1
+; CHECK:     Known loads forwarded: 0
+; CHECK:     Read-only accesses copied: 0
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+; CHECK: After statements {
+; CHECK:     Stmt_bodyA__TO__bodyB
+; CHECK:             MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:                 [n] -> { Stmt_bodyA__TO__bodyB[i0] -> MemRef_A[0] };
+; CHECK:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK:                 [n] -> { Stmt_bodyA__TO__bodyB[i0] -> MemRef_val[] };
+; CHECK:             Instructions {
+; CHECK:                   %val = fadd double 2.100000e+01, 2.100000e+01
+; CHECK:                   %cond = fcmp oeq double 2.100000e+01, 2.100000e+01
+; CHECK:             }
+; CHECK:     Stmt_bodyB
+; CHECK:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:                 [n] -> { Stmt_bodyB[i0] -> MemRef_A[0] };
+; CHECK:             Instructions {
+; CHECK:                   %val = fadd double 2.100000e+01, 2.100000e+01
+; CHECK:                   store double %val, double* %A
+; CHECK:             }
+; CHECK: }
+
diff --git a/final/test/ForwardOpTree/forward_hoisted.ll b/final/test/ForwardOpTree/forward_hoisted.ll
new file mode 100644
index 0000000..3241f07
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_hoisted.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -polly-invariant-load-hoisting=true -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Move %val to %bodyB, so %bodyA can be removed (by -polly-simplify).
+; This involves making the load-hoisted %val1 to be made available in %bodyB.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = B[0] + 21.0;
+;
+; bodyB:
+;   A[0] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val1 = load double, double* %B
+      %val2 = fadd double %val1, 21.0
+      br label %bodyB
+
+    bodyB:
+      store double %val2, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Instructions copied: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val2[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val1 = load double, double* %B
+; CHECK-NEXT:                   %val2 = fadd double %val1, 2.100000e+01
+; CHECK-NEXT:                 }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_A[0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val2 = fadd double %val1, 2.100000e+01
+; CHECK-NEXT:                   store double %val2, double* %A
+; CHECK-NEXT:                 }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_instruction.ll b/final/test/ForwardOpTree/forward_instruction.ll
new file mode 100644
index 0000000..4180ca2
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_instruction.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Move %val to %bodyB, so %bodyA can be removed (by -polly-simplify)
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = 21.0 + 21.0;
+;
+; bodyB:
+;   A[0] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val = fadd double 21.0, 21.0
+      br label %bodyB
+
+    bodyB:
+      store double %val, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Instructions copied: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = fadd double 2.100000e+01, 2.100000e+01
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_A[0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = fadd double 2.100000e+01, 2.100000e+01
+; CHECK-NEXT:                   store double %val, double* %A
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_into_region.ll b/final/test/ForwardOpTree/forward_into_region.ll
new file mode 100644
index 0000000..a79f1e4
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_into_region.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Move instructions to region statements.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = 21.0 + 21.0;
+;
+; bodyB:
+;   if (cond)
+; body_true:
+;     A[0] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val = fadd double 21.0, 21.0
+      br label %bodyB
+
+    bodyB:
+      %cond = fcmp oeq double 21.0, 21.0
+      br i1 %cond, label %bodyB_true, label %bodyB_exit
+
+    bodyB_true:
+      store double %val, double* %A
+      br label %bodyB_exit
+
+    bodyB_exit:
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+; CHECK: Statistics {
+; CHECK:     Instructions copied: 1
+; CHECK:     Known loads forwarded: 0
+; CHECK:     Read-only accesses copied: 0
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK: After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = fadd double 2.100000e+01, 2.100000e+01
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB__TO__bodyB_exit
+; CHECK-NEXT:             MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB__TO__bodyB_exit[i0] -> MemRef_A[0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = fadd double 2.100000e+01, 2.100000e+01
+; CHECK-NEXT:                   %cond = fcmp oeq double 2.100000e+01, 2.100000e+01
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_into_region_redundant_use.ll b/final/test/ForwardOpTree/forward_into_region_redundant_use.ll
new file mode 100644
index 0000000..c6d51fd
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_into_region_redundant_use.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-invariant-load-hoisting=true -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+
+define void @foo(float* %A, i32 %p, float* %B) {
+start:
+  br label %branch
+
+branch:
+  %cmp = icmp eq i32 %p, 1024
+  br i1 %cmp, label %next, label %end
+
+next:
+  %val = load float, float* %A
+  %fcmp = fcmp oeq float %val, 41.0
+  br label %nonaffine
+
+nonaffine:
+  br i1 %fcmp, label %a, label %b
+
+a:
+  store float %val, float* %A
+  br label %end
+
+b:
+  store float 1.0, float* %A
+  br label %end
+
+end:
+  ret void
+}
+
+; CHECK:      After statements {
+; CHECK-NEXT:     Stmt_next
+; CHECK-NEXT:             ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [p] -> { Stmt_next[] -> MemRef_A[0] };
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [p] -> { Stmt_next[] -> MemRef_fcmp[] };
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [p] -> { Stmt_next[] -> MemRef_val[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = load float, float* %A
+; CHECK-NEXT:                   %fcmp = fcmp oeq float %val, 4.100000e+01
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_nonaffine__TO__end
+; CHECK-NEXT:             ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 ;
+; CHECK-NEXT:            new: [p] -> { Stmt_nonaffine__TO__end[] -> MemRef_A[0] };
+; CHECK-NEXT:             MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [p] -> { Stmt_nonaffine__TO__end[] -> MemRef_A[0] };
+; CHECK-NEXT:             MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [p] -> { Stmt_nonaffine__TO__end[] -> MemRef_A[0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = load float, float* %A
+; CHECK-NEXT:                   %val = load float, float* %A
+; CHECK-NEXT:                   %fcmp = fcmp oeq float %val, 4.100000e+01
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_load.ll b/final/test/ForwardOpTree/forward_load.ll
new file mode 100644
index 0000000..b0c29fa
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_load.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Rematerialize a load.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = B[j];
+;
+; bodyB:
+;   A[j] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      %val = load double, double* %B_idx
+      br label %bodyB
+
+    bodyB:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Known loads forwarded: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      Stmt_bodyB
+; CHECK-NEXT:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             ;
+; CHECK-NEXT:        new: [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         Instructions {
+; CHECK-NEXT:               %val = load double, double* %B_idx
+; CHECK-NEXT:               store double %val, double* %A_idx
+; CHECK-NEXT:         }
diff --git a/final/test/ForwardOpTree/forward_load_differentarray.ll b/final/test/ForwardOpTree/forward_load_differentarray.ll
new file mode 100644
index 0000000..9663cc7
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_load_differentarray.ll
@@ -0,0 +1,93 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; To forward %val, B[j] cannot be reused in bodyC because it is overwritten
+; between. Verify that instead the alternative C[j] is used.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = B[j];
+;
+; bodyB:
+;   B[j] = 0;
+;   C[j] = val;
+;
+; bodyC:
+;   A[j] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B, double* noalias nonnull %C) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      %val = load double, double* %B_idx
+      br label %bodyB
+
+    bodyB:
+      store double 0.0, double* %B_idx
+      %C_idx = getelementptr inbounds double, double* %C, i32 %j
+      store double %val, double* %C_idx
+      br label %bodyC
+
+    bodyC:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Known loads forwarded: 2
+; CHECK:     Operand trees forwarded: 2
+; CHECK:     Statements with forwarded operand trees: 2
+; CHECK: }
+
+; CHECK-NEXT: After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = load double, double* %B_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 ;
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_C[i0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = load double, double* %B_idx
+; CHECK-NEXT:                   store double 0.000000e+00, double* %B_idx
+; CHECK-NEXT:                   store double %val, double* %C_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyC
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 ;
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyC[i0] -> MemRef_C[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyC[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = load double, double* %B_idx
+; CHECK-NEXT:                   store double %val, double* %A_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_load_double_write.ll b/final/test/ForwardOpTree/forward_load_double_write.ll
new file mode 100644
index 0000000..5b988e1
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_load_double_write.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Rematerialize a load even in case two writes of identical values are in
+; one scop statement.
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      %val = load double, double* %B_idx
+      br label %bodyB
+
+    bodyB:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Known loads forwarded: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      Stmt_bodyB
+; CHECK-NEXT:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             ;
+; CHECK-NEXT:        new: [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         Instructions {
+; CHECK-NEXT:               %val = load double, double* %B_idx
+; CHECK-NEXT:               store double %val, double* %A_idx
+; CHECK-NEXT:               store double %val, double* %A_idx
+; CHECK-NEXT:         }
diff --git a/final/test/ForwardOpTree/forward_load_fromloop.ll b/final/test/ForwardOpTree/forward_load_fromloop.ll
new file mode 100644
index 0000000..eb650a7
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_load_fromloop.ll
@@ -0,0 +1,77 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Forward a the LoadInst %val into %bodyB. %val is executed multiple times,
+; we must get the last loaded values.
+;
+; for (int j = 0; j < n; j += 1) {
+;   double val;
+;   for (int i = 0; i < n; i += 1) {
+; bodyA:
+;     val = B[j];
+;   }
+;
+; bodyB:
+;   A[j] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp sle i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %i = phi i32 [0, %for], [%i.inc, %bodyA]
+      %B_idx = getelementptr inbounds double, double* %B, i32 %i
+      %val = load double, double* %B_idx
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i, %n
+      br i1 %i.cmp, label %bodyA, label %bodyB
+
+    bodyB:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Known loads forwarded: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0, i1] -> MemRef_B[i1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0, i1] -> MemRef_val[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = load double, double* %B_idx
+; CHECK-NEXT:                   %i.cmp = icmp slt i32 %i, %n
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 ;
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyB[i0] -> MemRef_B[n] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = load double, double* %B_idx
+; CHECK-NEXT:                   store double %val, double* %A_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_load_indirect.ll b/final/test/ForwardOpTree/forward_load_indirect.ll
new file mode 100644
index 0000000..e526ba7
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_load_indirect.ll
@@ -0,0 +1,75 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Forward an operand tree consisting of a speculatable instruction (%add)
+; and a load (%val).
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = B[j];
+;   double add = val + 42.0;
+;
+; bodyB:
+;   A[j] = add;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      %val = load double, double* %B_idx
+      %add = fadd double %val, 42.0
+      br label %bodyB
+
+    bodyB:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %add, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Instructions copied: 1
+; CHECK:     Known loads forwarded: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_add[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = load double, double* %B_idx
+; CHECK-NEXT:                   %add = fadd double %val, 4.200000e+01
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 ;
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = load double, double* %B_idx
+; CHECK-NEXT:                   %add = fadd double %val, 4.200000e+01
+; CHECK-NEXT:                   store double %add, double* %A_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_load_memset_after.ll b/final/test/ForwardOpTree/forward_load_memset_after.ll
new file mode 100644
index 0000000..b8ef089
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_load_memset_after.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Rematerialize a load in the presence of a non-store WRITE access.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = B[j];
+;
+; bodyB:
+;   A[j] = val;
+;
+; bodyC:
+;   memset(A, 0, 16);
+;   memset(B, 0, 16);
+; }
+;
+
+declare void @llvm.memset.p0f64.i64(double* nocapture, i8, i64, i32, i1)
+
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      %val = load double, double* %B_idx
+      br label %bodyB
+
+    bodyB:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %bodyC
+
+    bodyC:
+      call void @llvm.memset.p0f64.i64(double* %A, i8 0, i64 16, i32 1, i1 false)
+      call void @llvm.memset.p0f64.i64(double* %B, i8 0, i64 16, i32 1, i1 false)
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Known loads forwarded: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
diff --git a/final/test/ForwardOpTree/forward_load_memset_before.ll b/final/test/ForwardOpTree/forward_load_memset_before.ll
new file mode 100644
index 0000000..7eb11a7
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_load_memset_before.ll
@@ -0,0 +1,81 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Rematerialize a load in the presence of a non-store WRITE access.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   memset(A, 0, 16);
+;   memset(B, 0, 16);
+;
+; bodyB:
+;   double val = B[j];
+;
+; bodyC:
+;   A[j] = val;
+; }
+;
+
+declare void @llvm.memset.p0f64.i64(double* nocapture, i8, i64, i32, i1)
+
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      call void @llvm.memset.p0f64.i64(double* %A, i8 0, i64 16, i32 1, i1 false)
+      call void @llvm.memset.p0f64.i64(double* %B, i8 0, i64 16, i32 1, i1 false)
+      br label %bodyB
+
+    bodyB:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      %val = load double, double* %B_idx
+      br label %bodyC
+
+    bodyC:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Known loads forwarded: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK-NEXT: After statements {
+; CHECK:          Stmt_bodyB
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_B[o0] : 8i0 <= o0 <= 7 + 8i0 };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_val[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = load double, double* %B_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyC
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 ;
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyC[i0] -> MemRef_B[8i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyC[i0] -> MemRef_A[o0] : 8i0 <= o0 <= 7 + 8i0 };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = load double, double* %B_idx
+; CHECK-NEXT:                   store double %val, double* %A_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_load_tripleuse.ll b/final/test/ForwardOpTree/forward_load_tripleuse.ll
new file mode 100644
index 0000000..504bac3
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_load_tripleuse.ll
@@ -0,0 +1,161 @@
+; RUN: opt %loadPolly -polly-optree -polly-codegen -analyze < %s | FileCheck %s -match-full-lines
+;
+; %val1 is used three times: Twice by its own operand tree of %val2 and once
+; more by the store in %bodyB.
+; Verify that we can handle multiple uses by the same instruction and uses
+; in multiple statements as well.
+; The result processing may depend on the order in which the values are used,
+; hence we check both orderings.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val1 = A[j];
+;   double val2 = val1 + val1;
+;
+; bodyB:
+;   B[j] = val1;
+;   C[j] = val2;
+; }
+;
+define void @func1(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B, double* noalias nonnull %C) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %val1 = load double, double* %A_idx
+      %val2 = fadd double %val1, %val1
+      br label %bodyB
+
+    bodyB:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      store double %val1, double* %B_idx
+      %C_idx = getelementptr inbounds double, double* %C, i32 %j
+      store double %val2, double* %C_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Instructions copied: 1
+; CHECK:     Known loads forwarded: 3
+; CHECK:     Operand trees forwarded: 2
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val1[] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val2[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val1 = load double, double* %A_idx
+; CHECK-NEXT:                   %val2 = fadd double %val1, %val1
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 ;
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_C[i0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val1 = load double, double* %A_idx
+; CHECK-NEXT:                   %val1 = load double, double* %A_idx
+; CHECK-NEXT:                   %val2 = fadd double %val1, %val1
+; CHECK-NEXT:                   %val1 = load double, double* %A_idx
+; CHECK-NEXT:                   store double %val1, double* %B_idx
+; CHECK-NEXT:                   store double %val2, double* %C_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
+
+
+define void @func2(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B, double* noalias nonnull %C) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %val1 = load double, double* %A_idx
+      %val2 = fadd double %val1, %val1
+      br label %bodyB
+
+    bodyB:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      store double %val2, double* %B_idx
+      %C_idx = getelementptr inbounds double, double* %C, i32 %j
+      store double %val1, double* %C_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Instructions copied: 1
+; CHECK:     Known loads forwarded: 3
+; CHECK:     Operand trees forwarded: 2
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val2[] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val1[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val1 = load double, double* %A_idx
+; CHECK-NEXT:                   %val2 = fadd double %val1, %val1
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 ;
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_C[i0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val1 = load double, double* %A_idx
+; CHECK-NEXT:                   %val1 = load double, double* %A_idx
+; CHECK-NEXT:                   %val1 = load double, double* %A_idx
+; CHECK-NEXT:                   %val2 = fadd double %val1, %val1
+; CHECK-NEXT:                   store double %val2, double* %B_idx
+; CHECK-NEXT:                   store double %val1, double* %C_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_load_unrelatedunusual.ll b/final/test/ForwardOpTree/forward_load_unrelatedunusual.ll
new file mode 100644
index 0000000..42e775d
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_load_unrelatedunusual.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Rematerialize a load.
+; The non-analyzable store to C[0] is unrelated and can be ignored.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = B[j];
+;   C[0] = 21.0;
+;   C[0] = 42.0;
+;
+; bodyB:
+;   A[j] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B, double *noalias %C) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      %val = load double, double* %B_idx
+      store double 21.0, double* %C
+      store double 41.0, double* %C
+      br label %bodyB
+
+    bodyB:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Known loads forwarded: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      Stmt_bodyB
+; CHECK-NEXT:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             ;
+; CHECK-NEXT:        new: [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         Instructions {
+; CHECK-NEXT:               %val = load double, double* %B_idx
+; CHECK-NEXT:               store double %val, double* %A_idx
+; CHECK-NEXT:         }
diff --git a/final/test/ForwardOpTree/forward_phi_load.ll b/final/test/ForwardOpTree/forward_phi_load.ll
new file mode 100644
index 0000000..639d946
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_phi_load.ll
@@ -0,0 +1,82 @@
+; RUN: opt %loadPolly -polly-optree-normalize-phi=true -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Rematerialize a load.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = B[j];
+;
+; bodyB:
+;   double phi = val;
+;
+; bodyC:
+;   A[j] = phi;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      %val = load double, double* %B_idx
+      br label %bodyB
+
+    bodyB:
+      %phi = phi double [%val, %bodyA]
+      br label %bodyC
+
+    bodyC:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %phi, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Reloads: 2
+; CHECK: }
+
+; CHECK-NEXT: After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = load double, double* %B_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_phi[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %phi = phi double [ %val, %bodyA ]
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyC
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyC[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyC[i0] -> MemRef_phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyC[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   store double %phi, double* %A_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_readonly.ll b/final/test/ForwardOpTree/forward_readonly.ll
new file mode 100644
index 0000000..ca514cf
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_readonly.ll
@@ -0,0 +1,84 @@
+; RUN: opt %loadPolly -polly-analyze-read-only-scalars=true  -polly-optree -analyze < %s | FileCheck %s -match-full-lines -check-prefixes=STATS,MODEL
+; RUN: opt %loadPolly -polly-analyze-read-only-scalars=false -polly-optree -analyze < %s | FileCheck %s -match-full-lines -check-prefixes=STATS,NOMODEL
+;
+; Move %val to %bodyB, so %bodyA can be removed (by -polly-simplify)
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = arg + 21.0;
+;
+; bodyB:
+;   A[0] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double %arg) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val = fadd double %arg, 21.0
+      br label %bodyB
+
+    bodyB:
+      store double %val, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; STATS: Statistics {
+; STATS:     Instructions copied: 1
+; STATS:     Read-only accesses copied: 1
+; STATS:     Operand trees forwarded: 1
+; STATS:     Statements with forwarded operand trees: 1
+; STATS: }
+
+; MODEL:      After statements {
+; MODEL-NEXT:     Stmt_bodyA
+; MODEL-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; MODEL-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_arg[] };
+; MODEL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; MODEL-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val[] };
+; MODEL-NEXT:             Instructions {
+; MODEL-NEXT:                   %val = fadd double %arg, 2.100000e+01
+; MODEL-NEXT:                 }
+; MODEL-NEXT:     Stmt_bodyB
+; MODEL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; MODEL-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_A[0] };
+; MODEL-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; MODEL-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_arg[] };
+; MODEL-NEXT:             Instructions {
+; MODEL-NEXT:                   %val = fadd double %arg, 2.100000e+01
+; MODEL-NEXT:                   store double %val, double* %A
+; MODEL-NEXT:                 }
+; MODEL-NEXT: }
+
+; NOMODEL:      After statements {
+; NOMODEL-NEXT:     Stmt_bodyA
+; NOMODEL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; NOMODEL-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val[] };
+; NOMODEL-NEXT:             Instructions {
+; NOMODEL-NEXT:                   %val = fadd double %arg, 2.100000e+01
+; NOMODEL-NEXT:                 }
+; NOMODEL-NEXT:     Stmt_bodyB
+; NOMODEL-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; NOMODEL-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_A[0] };
+; NOMODEL-NEXT:             Instructions {
+; NOMODEL-NEXT:                   %val = fadd double %arg, 2.100000e+01
+; NOMODEL-NEXT:                   store double %val, double* %A
+; NOMODEL-NEXT:                 }
+; NOMODEL-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_store.ll b/final/test/ForwardOpTree/forward_store.ll
new file mode 100644
index 0000000..96a91cf
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_store.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Rematerialize a load.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = B[j];
+;
+; bodyB:
+;   A[j] = val;
+; }
+;
+
+declare double @f() #0
+
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val = call double @f()
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %bodyB
+
+    bodyB:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      store double %val, double* %B_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+attributes #0 = { nounwind readnone }
+
+
+; CHECK: Statistics {
+; CHECK:     Reloads: 1
+; CHECK: }
+
+; CHECK:      After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = call double @f()
+; CHECK-NEXT:                   store double %val, double* %A_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_val[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   store double %val, double* %B_idx
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_synthesizable_definloop.ll b/final/test/ForwardOpTree/forward_synthesizable_definloop.ll
new file mode 100644
index 0000000..05d375a
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_synthesizable_definloop.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Copy %val to bodyB, assuming the exit value of %i.
+;
+; for (int j = 0; j < n; j += 1) {
+;   double val;
+;   for (int i = 0; i < 128; i += 1) {
+; bodyA:
+;     val = j;
+;   }
+;
+; bodyB:
+;   A[0] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %inner.for, label %exit
+
+    inner.for:
+      %i = phi i32 [0, %for], [%i.inc, %inner.inc]
+      br label %bodyA
+
+
+        bodyA:
+          %val = sitofp i32 %i to double
+          br label %inner.inc
+
+
+    inner.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      %i.cmp = icmp slt i32 %i.inc, 128
+      br i1 %i.cmp, label %inner.for, label %inner.exit
+
+    inner.exit:
+       br label %bodyB
+
+
+    bodyB:
+      store double %val, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Instructions copied: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0, i1] -> MemRef_val[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = sitofp i32 %i to double
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_A[0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = sitofp i32 %i to double
+; CHECK-NEXT:                   store double %val, double* %A
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_synthesizable_indvar.ll b/final/test/ForwardOpTree/forward_synthesizable_indvar.ll
new file mode 100644
index 0000000..b034cd1
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_synthesizable_indvar.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Test support for (synthesizable) inducation variables.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = j;
+;
+; bodyB:
+;   A[0] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val = sitofp i32 %j to double
+      br label %bodyB
+
+    bodyB:
+      store double %val, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Instructions copied: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = sitofp i32 %j to double
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_A[0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = sitofp i32 %j to double
+; CHECK-NEXT:                   store double %val, double* %A
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_synthesizable_useinloop.ll b/final/test/ForwardOpTree/forward_synthesizable_useinloop.ll
new file mode 100644
index 0000000..c43787d
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_synthesizable_useinloop.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Synthesizable values defined outside of a loop can be used
+; inside the loop.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = j;
+;
+;   for (int i = 0; i < n; i += 1) {
+; bodyB:
+;     A[0] = val;
+;   }
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val = sitofp i32 %j to double
+      br label %inner.for
+
+
+    inner.for:
+      %i = phi i32 [0, %bodyA], [%i.inc, %inner.inc]
+      %i.cmp = icmp slt i32 %i, %n
+      br i1 %i.cmp, label %bodyB, label %inner.exit
+
+
+        bodyB:
+          store double %val, double* %A
+          br label %inner.inc
+
+
+    inner.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %inner.for
+
+    inner.exit:
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Instructions copied: 1
+; CHECK:     Operand trees forwarded: 1
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK:      After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = sitofp i32 %j to double
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0, i1] -> MemRef_A[0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val = sitofp i32 %j to double
+; CHECK-NEXT:                   store double %val, double* %A
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/forward_transitive.ll b/final/test/ForwardOpTree/forward_transitive.ll
new file mode 100644
index 0000000..b45b466
--- /dev/null
+++ b/final/test/ForwardOpTree/forward_transitive.ll
@@ -0,0 +1,77 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Move %v and %val to %bodyB, so %bodyA can be removed (by -polly-simplify)
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val1 = 12.5 + 12.5;
+;
+; bodyB:
+;   double val2 = 21.0 + 21.0;
+;
+; bodyC:
+;   A[0] = val2;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val1 = fadd double 12.5, 12.5
+      br label %bodyB
+
+    bodyB:
+      %val2 = fadd double %val1, 21.0
+      br label %bodyC
+
+    bodyC:
+      store double %val2, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Instructions copied: 3
+; CHECK:     Operand trees forwarded: 2
+; CHECK:     Statements with forwarded operand trees: 2
+; CHECK: }
+
+; CHECK:      After statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_val1[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val1 = fadd double 1.250000e+01, 1.250000e+01
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_val2[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val1 = fadd double 1.250000e+01, 1.250000e+01
+; CHECK-NEXT:                   %val2 = fadd double %val1, 2.100000e+01
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_bodyC
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyC[i0] -> MemRef_A[0] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %val1 = fadd double 1.250000e+01, 1.250000e+01
+; CHECK-NEXT:                   %val2 = fadd double %val1, 2.100000e+01
+; CHECK-NEXT:                   store double %val2, double* %A
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/jacobi-1d.ll b/final/test/ForwardOpTree/jacobi-1d.ll
new file mode 100644
index 0000000..0825ea0
--- /dev/null
+++ b/final/test/ForwardOpTree/jacobi-1d.ll
@@ -0,0 +1,108 @@
+; RUN: opt %loadPolly -polly-optree-normalize-phi=true -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define internal fastcc void @kernel_jacobi_1d(double* noalias nocapture %A, double* noalias nocapture %B) unnamed_addr #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %arrayidx6.phi.trans.insert = getelementptr inbounds double, double* %A, i64 1
+  %arrayidx21.phi.trans.insert = getelementptr inbounds double, double* %B, i64 1
+  br label %for.body
+
+for.body:                                         ; preds = %for.inc33, %entry.split
+  %t.03 = phi i32 [ 0, %entry.split ], [ %inc34, %for.inc33 ]
+  %.pre = load double, double* %A, align 8, !tbaa !6
+  %.pre10 = load double, double* %arrayidx6.phi.trans.insert, align 8, !tbaa !6
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.body3, %for.body
+  %0 = phi double [ %.pre10, %for.body ], [ %2, %for.body3 ]
+  %1 = phi double [ %.pre, %for.body ], [ %0, %for.body3 ]
+  %indvars.iv = phi i64 [ 1, %for.body ], [ %indvars.iv.next, %for.body3 ]
+  %add = fadd double %1, %0
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %arrayidx9 = getelementptr inbounds double, double* %A, i64 %indvars.iv.next
+  %2 = load double, double* %arrayidx9, align 8, !tbaa !6
+  %add10 = fadd double %add, %2
+  %mul = fmul double %add10, 3.333300e-01
+  %arrayidx12 = getelementptr inbounds double, double* %B, i64 %indvars.iv
+  store double %mul, double* %arrayidx12, align 8, !tbaa !6
+  %exitcond = icmp eq i64 %indvars.iv.next, 3
+  br i1 %exitcond, label %for.end, label %for.body3
+
+for.end:                                          ; preds = %for.body3
+  %.pre11 = load double, double* %B, align 8, !tbaa !6
+  %.pre12 = load double, double* %arrayidx21.phi.trans.insert, align 8, !tbaa !6
+  br label %for.inc33
+
+for.inc33:                                        ; preds = %for.body16
+  %inc34 = add nuw nsw i32 %t.03, 1
+  %exitcond9 = icmp eq i32 %inc34, 2
+  br i1 %exitcond9, label %for.end35, label %for.body
+
+for.end35:                                        ; preds = %for.inc33
+  ret void
+}
+
+attributes #0 = { noinline norecurse nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang version 6.0.0  (llvm/trunk 312874)"}
+!2 = !{!3, !3, i64 0}
+!3 = !{!"any pointer", !4, i64 0}
+!4 = !{!"omnipotent char", !5, i64 0}
+!5 = !{!"Simple C/C++ TBAA"}
+!6 = !{!7, !7, i64 0}
+!7 = !{!"double", !4, i64 0}
+
+
+; CHECK: Statistics {
+; CHECK:     Operand trees forwarded: 2
+; CHECK:     Statements with forwarded operand trees: 1
+; CHECK: }
+
+; CHECK-NEXT: After statements {
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_for_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_for_body[i0] -> MemRef_A[1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body[i0] -> MemRef1__phi[] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body[i0] -> MemRef2__phi[] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %.pre = load double, double* %A, align 8, !tbaa !2
+; CHECK-NEXT:                   %.pre10 = load double, double* %arrayidx6.phi.trans.insert, align 8, !tbaa !2
+; CHECK-NEXT:             }
+; CHECK-NEXT:     Stmt_for_body3
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body3[i0, i1] -> MemRef1__phi[] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body3[i0, i1] -> MemRef1__phi[] };
+; CHECK-NEXT:            new: { Stmt_for_body3[i0, i1] -> MemRef_A[1 + i1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body3[i0, i1] -> MemRef2__phi[] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body3[i0, i1] -> MemRef2__phi[] };
+; CHECK-NEXT:            new: { Stmt_for_body3[i0, i1] -> MemRef_A[i1] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_for_body3[i0, i1] -> MemRef_A[2 + i1] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_for_body3[i0, i1] -> MemRef_B[1 + i1] };
+; CHECK-NEXT:             Instructions {
+; CHECK-NEXT:                   %0 = phi double [ %.pre10, %for.body ], [ %2, %for.body3 ]
+; CHECK-NEXT:                   %1 = phi double [ %.pre, %for.body ], [ %0, %for.body3 ]
+; CHECK-NEXT:                   %add = fadd double %1, %0
+; CHECK-NEXT:                   %2 = load double, double* %arrayidx9, align 8, !tbaa !2
+; CHECK-NEXT:                   %add10 = fadd double %add, %2
+; CHECK-NEXT:                   %mul = fmul double %add10, 3.333300e-01
+; CHECK-NEXT:                   store double %mul, double* %arrayidx12, align 8, !tbaa !2
+; CHECK-NEXT:                   %exitcond = icmp eq i64 %indvars.iv.next, 3
+; CHECK-NEXT:             }
+; CHECK-NEXT: }
diff --git a/final/test/ForwardOpTree/noforward_from_region.ll b/final/test/ForwardOpTree/noforward_from_region.ll
new file mode 100644
index 0000000..9994b82
--- /dev/null
+++ b/final/test/ForwardOpTree/noforward_from_region.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Ensure we do not move instructions from region statements in case the
+; instruction to move loads from an array which is also written to from
+; within the region. This is necessary as complex region statements may prevent
+; us from detecting possible memory conflicts.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = A[0];
+;   if (cond)
+;
+; bodyA_true:
+;     A[0] = 42;
+;
+; bodyB:
+;     A[0] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val = load double, double* %A
+      %cond = fcmp oeq double 21.0, 21.0
+      br i1 %cond, label %bodyA_true, label %bodyB
+
+    bodyA_true:
+      store double 42.0, double* %A
+      br label %bodyB
+
+    bodyB:
+      store double %val, double* %A
+      br label %bodyB_exit
+
+    bodyB_exit:
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+; CHECK: ForwardOpTree executed, but did not modify anything
diff --git a/final/test/ForwardOpTree/noforward_load_conditional.ll b/final/test/ForwardOpTree/noforward_load_conditional.ll
new file mode 100644
index 0000000..95bec95
--- /dev/null
+++ b/final/test/ForwardOpTree/noforward_load_conditional.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; B[j] is overwritten by at least one statement between the
+; definition of %val and its use. Hence, it cannot be forwarded.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = B[j];
+;   if (j < 1) {
+; bodyA_true:
+;     B[j] = 0.0;
+;   }
+;
+; bodyB:
+;   A[j] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      %val = load double, double* %B_idx
+      %cond = icmp slt i32 %j, 1
+      br i1 %cond, label %bodyA_true, label %bodyB
+
+    bodyA_true:
+      store double 0.0, double* %B_idx
+      br label %bodyB
+
+    bodyB:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: ForwardOpTree executed, but did not modify anything
diff --git a/final/test/ForwardOpTree/noforward_load_writebetween.ll b/final/test/ForwardOpTree/noforward_load_writebetween.ll
new file mode 100644
index 0000000..3c84d5f
--- /dev/null
+++ b/final/test/ForwardOpTree/noforward_load_writebetween.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Cannot rematerialize %val from B[0] at bodyC because B[0] has been
+; overwritten in bodyB.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = B[j];
+;
+; bodyB:
+;   B[j] = 0.0;
+;
+; bodyC:
+;   A[j] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      %val = load double, double* %B_idx
+      br label %bodyB
+
+    bodyB:
+      store double 0.0, double* %B_idx
+      br label %bodyC
+
+    bodyC:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: ForwardOpTree executed, but did not modify anything
diff --git a/final/test/ForwardOpTree/noforward_outofquota.ll b/final/test/ForwardOpTree/noforward_outofquota.ll
new file mode 100644
index 0000000..d430250
--- /dev/null
+++ b/final/test/ForwardOpTree/noforward_outofquota.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-optree-max-ops=1 -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+; RUN: opt %loadPolly -polly-optree-max-ops=1 -polly-optree -disable-output -stats < %s 2>&1 | FileCheck %s -match-full-lines -check-prefix=STATS
+; REQUIRES: asserts
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = B[j];
+;
+; bodyB:
+;   A[j] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      %val = load double, double* %B_idx
+      br label %bodyB
+
+    bodyB:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: ForwardOpTree executed, but did not modify anything
+
+; STATS-NOT: IMPLEMENTATION ERROR: Unhandled error state
+; STATS: 1 polly-optree     - Analyses aborted because max_operations was reached
+; STATS-NOT: IMPLEMENTATION ERROR: Unhandled error state
diff --git a/final/test/ForwardOpTree/noforward_partial.ll b/final/test/ForwardOpTree/noforward_partial.ll
new file mode 100644
index 0000000..ac49266
--- /dev/null
+++ b/final/test/ForwardOpTree/noforward_partial.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Not the entire operand tree can be forwarded,
+; some scalar dependencies would remain.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = f() + 21.0;
+;
+; bodyB:
+;   A[0] = val;
+; }
+;
+declare double @f(...) #1
+
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %v = call double (...) @f()
+      %val = fadd double %v, 21.0
+      br label %bodyB
+
+    bodyB:
+      store double %val, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+attributes #1 = { nounwind readnone }
+
+
+; CHECK: ForwardOpTree executed, but did not modify anything
diff --git a/final/test/ForwardOpTree/noforward_phi.ll b/final/test/ForwardOpTree/noforward_phi.ll
new file mode 100644
index 0000000..ccdf6c7
--- /dev/null
+++ b/final/test/ForwardOpTree/noforward_phi.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Do not move PHI nodes.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = 42.0;
+;
+; bodyB:
+;   A[0] = val;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val =  phi double [42.0, %for]
+      br label %bodyB
+
+    bodyB:
+      store double %val, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: ForwardOpTree executed, but did not modify anything
diff --git a/final/test/ForwardOpTree/noforward_selfrefphi.ll b/final/test/ForwardOpTree/noforward_selfrefphi.ll
new file mode 100644
index 0000000..722343a
--- /dev/null
+++ b/final/test/ForwardOpTree/noforward_selfrefphi.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-optree-normalize-phi=true -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Contains a self-referencing PHINode that would require a
+; transitive closure to handle.
+;
+; for (int j = 0; j < n; j += 1) {
+;   double phi = 0.0;
+;   for (int i = 0; i < m; i += 1)
+;     phi = phi;
+;   A[j] = phi;
+; }
+;
+define void @func(i32 %n, i32 %m, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %for.preheader, label %exit
+
+  for.preheader:
+    br label %for.inner
+
+  for.inner:
+    %i = phi i32 [0, %for.preheader], [%i.inc, %for.inner]
+    %phi = phi double [0.0, %for.preheader], [%phi, %for.inner]
+    %i.inc = add nuw nsw i32 %i, 1
+    %i.cmp = icmp slt i32 %i.inc, %m
+    br i1 %i.cmp, label %for.inner, label %for.exit
+
+  for.exit:
+    %A_idx = getelementptr inbounds double, double* %A, i32 %j
+    store double %phi, double* %A_idx
+    br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: ForwardOpTree executed, but did not modify anything
diff --git a/final/test/ForwardOpTree/noforward_sideffects.ll b/final/test/ForwardOpTree/noforward_sideffects.ll
new file mode 100644
index 0000000..6a68808
--- /dev/null
+++ b/final/test/ForwardOpTree/noforward_sideffects.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly  -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Do not forward instructions with side-effects (here: function call).
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = f();
+;
+; bodyB:
+;   A[0] = val;
+; }
+;
+declare double @f(double* %A) #1
+
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val = call double (double*) @f(double* %A)
+      br label %bodyB
+
+    bodyB:
+      store double %val, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+attributes #1 = { nounwind readnone }
+
+
+; CHECK: ForwardOpTree executed, but did not modify anything
diff --git a/final/test/ForwardOpTree/noforward_synthesizable_unknownit.ll b/final/test/ForwardOpTree/noforward_synthesizable_unknownit.ll
new file mode 100644
index 0000000..0a7c80a
--- /dev/null
+++ b/final/test/ForwardOpTree/noforward_synthesizable_unknownit.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-optree -analyze < %s | FileCheck %s -match-full-lines
+;
+; Do not try to forward %i.trunc, it is not synthesizable in %body.
+;
+define void @func(i32 %n, i32* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  %zero = sext i32 0 to i64
+  br i1 %j.cmp, label %inner.for, label %exit
+
+
+    ; This loop has some unusual properties:
+    ; * It has a known iteration count (8), therefore SCoP-compatible.
+    ; * %i.trunc is synthesizable within the loop ({1,+,1}<%while.body>).
+    ; * %i.trunc is not synthesizable outside of the loop, because its value is
+    ;   unknown when exiting.
+    ;   (should be 8, but ScalarEvolution currently seems unable to derive that)
+    ;
+    ; ScalarEvolution currently seems to not able to handle the %zero.
+    ; If it becomes more intelligent, there might be other such loop constructs.
+    inner.for:
+      %i = phi i64 [%zero, %for], [%i.inc, %inner.for]
+      %i.inc = add nuw nsw i64 %i, 1
+      %i.trunc = trunc i64 %i.inc to i32
+      %i.and = and i32 %i.trunc, 7
+      %inner.cond = icmp eq i32 %i.and, 0
+      br i1 %inner.cond, label %body, label %inner.for
+
+    body:
+      store i32 %i.trunc, i32* %A
+      br label %inc
+
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: ForwardOpTree executed, but did not modify anything
diff --git a/final/test/GPGPU/Inputs/libdevice-functions-copied-into-kernel_libdevice.ll b/final/test/GPGPU/Inputs/libdevice-functions-copied-into-kernel_libdevice.ll
new file mode 100644
index 0000000..3f4c4a0
--- /dev/null
+++ b/final/test/GPGPU/Inputs/libdevice-functions-copied-into-kernel_libdevice.ll
@@ -0,0 +1,9 @@
+define float @__nv_expf(float %a) {
+  ret float %a
+}
+define float @__nv_cosf(float %a) {
+  ret float %a
+}
+define float @__nv_logf(float %a) {
+  ret float %a
+}
diff --git a/final/test/GPGPU/add-scalars-in-scop-to-kills.ll b/final/test/GPGPU/add-scalars-in-scop-to-kills.ll
new file mode 100644
index 0000000..f3272de
--- /dev/null
+++ b/final/test/GPGPU/add-scalars-in-scop-to-kills.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s -check-prefix=SCOP
+; RUN: opt %loadPolly -S -polly-codegen-ppcg < %s | FileCheck %s -check-prefix=HOST-IR
+
+; REQUIRES: pollyacc
+
+; Check that we detect a scop.
+; SCOP:       Function: checkScalarKill
+; SCOP-NEXT: Region: %XLoopInit---%for.end
+; SCOP-NEXT: Max Loop Depth:  1
+
+; Check that we have a scalar that is not a phi node in the scop.
+; SCOP: i32 MemRef_x_0; // Element size 4
+
+; Check that kernel launch is generated in host IR.
+; the declare would not be generated unless a call to a kernel exists.
+; HOST-IR: declare void @polly_launchKernel(i8*, i32, i32, i32, i32, i32, i8*)
+
+; Check that we add variables that are local to a scop into the kills that we
+; pass to PPCG. This should enable PPCG to codegen this example.
+; void checkScalarKill(int A[], int B[], int C[], const int control1, int control2) {
+; int x;
+; #pragma scop
+;     for(int i = 0; i < 1000; i++) {
+; XLoopInit:        x = 0;
+; 
+;         if (control1 > 2)
+;             C1Add: x += 10;
+;         if (control2 > 3)
+;             C2Add: x += A[i];
+; 
+; BLoopAccumX:        B[i] += x;
+;     }
+; 
+; #pragma endscop
+; }
+; ModuleID = 'test.ll'
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @checkScalarKill(i32* %A, i32* %B, i32* %C, i32 %control1, i32 %control2) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %XLoopInit
+
+XLoopInit:                                        ; preds = %entry.split, %BLoopAccumX
+  %indvars.iv = phi i64 [ 0, %entry.split ], [ %indvars.iv.next, %BLoopAccumX ]
+  %cmp1 = icmp sgt i32 %control1, 2
+  %x.0 = select i1 %cmp1, i32 10, i32 0
+  %cmp2 = icmp sgt i32 %control2, 3
+  br i1 %cmp2, label %C2Add, label %BLoopAccumX
+
+C2Add:                                            ; preds = %XLoopInit
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp6 = load i32, i32* %arrayidx, align 4
+  %add4 = add nsw i32 %tmp6, %x.0
+  br label %BLoopAccumX
+
+BLoopAccumX:                                      ; preds = %XLoopInit, %C2Add
+  %x.1 = phi i32 [ %add4, %C2Add ], [ %x.0, %XLoopInit ]
+  %arrayidx7 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  %tmp11 = load i32, i32* %arrayidx7, align 4
+  %add8 = add nsw i32 %tmp11, %x.1
+  store i32 %add8, i32* %arrayidx7, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1000
+  br i1 %exitcond, label %XLoopInit, label %for.end
+
+for.end:                                          ; preds = %BLoopAccumX
+  ret void
+}
diff --git a/final/test/GPGPU/align-params-in-schedule.ll b/final/test/GPGPU/align-params-in-schedule.ll
new file mode 100644
index 0000000..da9dc35
--- /dev/null
+++ b/final/test/GPGPU/align-params-in-schedule.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -S -polly-process-unprofitable -polly-codegen-ppcg \
+; RUN: -polly-invariant-load-hoisting -polly-ignore-parameter-bounds < %s | \
+; RUN: FileCheck %s
+
+; REQUIRES: pollyacc
+
+; CHECK: polly_launchKernel
+
+; Verify that this program compiles. At some point, this compilation crashed
+; due to insufficient parameters being available.
+
+source_filename = "bugpoint-output-4d01492.bc"
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.barney = type { i8*, i64, i64, [2 x %struct.widget] }
+%struct.widget = type { i64, i64, i64 }
+
+@global = external unnamed_addr global %struct.barney, align 32
+
+; Function Attrs: nounwind uwtable
+define void @wobble(i32* noalias %arg) #0 {
+bb:
+  %tmp = load i32, i32* %arg, align 4
+  br label %bb1
+
+bb1:                                              ; preds = %bb13, %bb
+  %tmp2 = phi i32 [ %tmp15, %bb13 ], [ 1, %bb ]
+  br label %bb3
+
+bb3:                                              ; preds = %bb3, %bb1
+  %tmp4 = load i32*, i32** bitcast (%struct.barney* @global to i32**), align 32
+  %tmp5 = sext i32 %tmp2 to i64
+  %tmp6 = load i64, i64* getelementptr inbounds (%struct.barney, %struct.barney* @global, i64 0, i32 3, i64 1, i32 0), align 8
+  %tmp7 = mul i64 %tmp6, %tmp5
+  %tmp8 = add i64 %tmp7, 0
+  %tmp9 = load i64, i64* getelementptr inbounds (%struct.barney, %struct.barney* @global, i64 0, i32 1), align 8
+  %tmp10 = add i64 %tmp8, %tmp9
+  %tmp11 = getelementptr i32, i32* %tmp4, i64 %tmp10
+  store i32 undef, i32* %tmp11, align 4
+  %tmp12 = icmp eq i32 0, 0
+  br i1 %tmp12, label %bb13, label %bb3
+
+bb13:                                             ; preds = %bb3
+  %tmp14 = icmp eq i32 %tmp2, %tmp
+  %tmp15 = add i32 %tmp2, 1
+  br i1 %tmp14, label %bb16, label %bb1
+
+bb16:                                             ; preds = %bb13
+  ret void
+}
+
+attributes #0 = { nounwind uwtable }
diff --git a/final/test/GPGPU/array-with-elem-type-smaller-than-byte.ll b/final/test/GPGPU/array-with-elem-type-smaller-than-byte.ll
new file mode 100644
index 0000000..5985c7a
--- /dev/null
+++ b/final/test/GPGPU/array-with-elem-type-smaller-than-byte.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -S -polly-codegen-ppcg \
+; RUN: -polly-use-llvm-names < %s
+; ModuleID = 'test/GPGPU/zero-size-array.ll'
+
+; REQUIRES: pollyacc
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+
+; We used to divide the element size by 8 to arrive at the 'actual' size
+; of an array element. This used to cause arrays that have an element size
+; of less than 8 to collapse to size 0. This test makes sure that it does
+; not happen anymore.
+
+; f(int *niters_ptr, int *arr[0]) {
+;     const int inters = *niters_ptr;
+;     for(int i = 0; i < niters; i++) {
+;       arr[0][i + 1] = 0
+;     }
+; }
+
+; Function Attrs: nounwind uwtable
+define void @f(i32* noalias %niters.ptr, [0 x i32]* noalias %arr) #0 {
+entry:
+  %niters = load i32, i32* %niters.ptr, align 4
+  br label %loop.body
+
+loop.body:                                             ; preds = %loop.body, %entry
+  %indvar = phi i32 [ %indvar.next, %loop.body ], [ 1, %entry ]
+  %indvar.sext = sext i32 %indvar to i64
+  %arr.slot = getelementptr [0 x i32], [0 x i32]* %arr, i64 0, i64 %indvar.sext
+  store i32 0, i32* %arr.slot, align 4
+  %tmp8 = icmp eq i32 %indvar, %niters
+  %indvar.next = add i32 %indvar, 1
+  br i1 %tmp8, label %loop.exit, label %loop.body
+
+loop.exit:                                    ; preds = %loop.body
+  %tmp10 = icmp sgt i32 undef, 0
+  br label %auxiliary.loop
+
+auxiliary.loop:                                            ; preds = %"101", %loop.exit
+  %tmp11 = phi i1 [ %tmp10, %loop.exit ], [ undef, %auxiliary.loop ]
+  br i1 undef, label %auxiliary.loop, label %exit
+
+exit:                              ; preds = %auxiliary.loop
+  ret void
+}
+
+attributes #0 = { nounwind uwtable }
diff --git a/final/test/GPGPU/bounds-construction-with-ignore-param-bounds.ll b/final/test/GPGPU/bounds-construction-with-ignore-param-bounds.ll
new file mode 100644
index 0000000..d47ba79
--- /dev/null
+++ b/final/test/GPGPU/bounds-construction-with-ignore-param-bounds.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -S -polly-codegen-ppcg \
+; RUN: -polly-ignore-parameter-bounds \
+; RUN: -polly-invariant-load-hoisting < %s| FileCheck %s -check-prefix=HOST-IR
+;
+; REQUIRES: pollyacc
+
+; When we have `-polly-ignore-parameter-bounds`, `Scop::Context` does not contain
+; all the parameters present in the program.
+;
+; The construction of the `isl_multi_pw_aff` requires all the indivisual `pw_aff`
+; to have the same parameter dimensions. To achieve this, we used to realign
+; every `pw_aff` with `Scop::Context`. However, in conjunction with
+; `-polly-ignore-parameter-bounds`, this is now incorrect, since `Scop::Context`
+; does not contain all parameters.
+;
+; We check that Polly does the right thing in this case and sets up the parameter
+; dimensions correctly.
+
+
+; Check that kernel launch is generated in host IR.
+; the declare would not be generated unless a call to a kernel exists.
+; HOST-IR: declare void @polly_launchKernel(i8*, i32, i32, i32, i32, i32, i8*)
+; ModuleID = 'test/GPGPU/bounds-construction-with-ignore-param-bounds.ll'
+
+; C pseudocode
+; ------------
+; void f(int *arr, long niters, long stride) {
+;     for(int i = 0; i < niters; i++) {
+;       arr[i * stride] = 1;
+;     }
+; }
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @f(i32 *%arr, i64 %niters, i64 %stride) unnamed_addr #1 {
+entry:
+  br label %loop
+
+loop:                                             ; preds = %loop, %entry
+  %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %loop ]
+  %idx = mul nuw nsw i64 %indvar, %stride
+  %slot = getelementptr i32, i32* %arr, i64 %idx
+  store i32 1, i32* %slot, align 4
+  %indvar.next = add nuw nsw i64 %indvar, 1
+  %check = icmp sgt i64 %indvar.next, %niters
+  br i1 %check, label %exit, label %loop
+
+exit:                                             ; preds = %loop
+  ret void
+}
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind uwtable }
diff --git a/final/test/GPGPU/check-unused-fortran-array-size-param-offloaded-to-kernel.ll b/final/test/GPGPU/check-unused-fortran-array-size-param-offloaded-to-kernel.ll
new file mode 100644
index 0000000..587b940
--- /dev/null
+++ b/final/test/GPGPU/check-unused-fortran-array-size-param-offloaded-to-kernel.ll
@@ -0,0 +1,102 @@
+; RUN: opt %loadPolly -analyze -polly-scops \
+; RUN:     -polly-detect-fortran-arrays \
+; RUN:     -polly-invariant-load-hoisting \
+; RUN:     -polly-use-llvm-names \
+; RUN:     < %s | FileCheck %s --check-prefix=SCOP
+
+; RUN: opt %loadPolly -S \
+; RUN:     -polly-detect-fortran-arrays \
+; RUN:     -polly-codegen-ppcg \
+; RUN:     -polly-invariant-load-hoisting \
+; RUN:     -polly-use-llvm-names \
+; RUN:     -polly-acc-fail-on-verify-module-failure \
+; RUN:     < %s | FileCheck %s --check-prefix=HOST-IR
+
+; REQUIRES: pollyacc
+
+; In Polly, we specifically add a parameter to represent the outermost dimension
+; size of fortran arrays. We do this because this information is statically
+; available from the fortran metadata generated by dragonegg.
+; However, we were only materializing these parameters (meaning, creating an
+; llvm::Value to back the isl_id) from *memory accesses*. This is wrong,
+; we should materialize parameters from *scop array info*.
+
+; It is wrong because if there is a case where we detect 2 fortran arrays,
+; but only one of them is accessed, we may not materialize the other array's
+; dimensions at all.
+
+; This test case checks that we do not fail if there is an array that does
+; not have an access (In this case, `memory`), we still generate the
+; parameter.
+
+; Check that we detect the function as a Scop.
+; SCOP:      Function: f
+; SCOP-NEXT: Region: %loop.prepare---%for.exit
+; SCOP-NEXT: Max Loop Depth:  1
+
+; Check that we detect fortran arrays.
+; SCOP:    Arrays (Bounds as pw_affs) {
+; SCOP:             double* MemRef_global_arr[*]; // Element size 8
+; SCOP-NEXT:        double MemRef_memory[ [MemRef_memory_fortranarr_size] -> { [] -> [(MemRef_memory_fortranarr_size)] } ]; [BasePtrOrigin: MemRef_global_arr] // Element size 8
+; SCOP-NEXT:        double MemRef_memory2[ [MemRef_memory2_fortranarr_size] -> { [] -> [(MemRef_memory2_fortranarr_size)] } ]; [BasePtrOrigin: MemRef_global_arr] // Element size 8
+; SCOP-NEXT:    }
+
+; Check that we have writes *only* into memory2, not into memory.
+; SCOP:    Statements {
+; SCOP:    	Stmt_for_body
+; SCOP:            MustWriteAccess :=	[Reduction Type: NONE] [Fortran array descriptor: global_arr] [Scalar: 0]
+; SCOP-NEXT:                [start_val, end_val, offset, MemRef_memory_fortranarr_size, MemRef_memory2_fortranarr_size] -> { Stmt_for_body[i0] -> MemRef_memory2[start_val + offset + i0] };
+; SCOP-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Fortran array descriptor: global_arr] [Scalar: 0]
+; SCOP-NEXT:                [start_val, end_val, offset, MemRef_memory_fortranarr_size, MemRef_memory2_fortranarr_size] -> { Stmt_for_body[i0] -> MemRef_memory2[start_val + offset + i0] };
+; SCOP-NEXT:    }
+
+; Check that we materialize the sizes and send it across to the kernel.
+; HOST-IR: store i64 %MemRef_memory_size, i64* %polly_launch_0_param_4
+; HOST-IR: store i64 %MemRef_memory2_size, i64* %polly_launch_0_param_5
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
+
+%"struct.array1_real(kind=8)" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
+%struct.descriptor_dimension = type { i64, i64, i64 }
+
+@global_arr = external unnamed_addr global %"struct.array1_real(kind=8)", align 32
+
+; Function Attrs: nounwind uwtable
+define void @f(i32* noalias %ipstart, i32* noalias %ipend) unnamed_addr #0 {
+entry:
+  br label %loop.prepare
+
+
+loop.prepare:                                              ; preds = %"6", %"3.preheader"
+  %start.val = load i32, i32* %ipstart, align 4
+  %end.val = load i32, i32* %ipend, align 4
+  %should.loop = icmp sgt i32 %start.val, %end.val
+  br i1 %should.loop, label %for.exit, label %for.body
+
+
+for.body:                                              ; preds = %for.body, %"4.preheader"
+  %i = phi i32 [ %i.next, %for.body ], [ %start.val, %loop.prepare ]
+  %i.sext = sext i32 %i to i64
+  %memory = load double*, double** bitcast (%"struct.array1_real(kind=8)"* @global_arr to double**), align 32
+  %offset = load i64, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @global_arr, i64 0, i32 1), align 8
+  %idx = add i64 %offset, %i.sext
+  %slot = getelementptr double, double* %memory, i64 %idx
+  store double 1.0, double* %slot, align 8
+
+  %memory2 = load double*, double** bitcast (%"struct.array1_real(kind=8)"* @global_arr to double**), align 32
+  %offset2 = load i64, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @global_arr, i64 0, i32 1), align 8
+  %idx2 = add i64 %offset2, %i.sext
+  %slot2 = getelementptr double, double* %memory2, i64 %idx2
+  %val = load double, double* %slot2, align 8
+
+  %should.loopexit = icmp eq i32 %i, %end.val
+  %i.next = add i32 %i, 1
+  br i1 %should.loopexit, label %for.exit, label %for.body
+
+for.exit:                                     ; preds = %for.body
+  ret void
+}
+
+attributes #0 = { nounwind uwtable }
diff --git a/final/test/GPGPU/cuda-annotations.ll b/final/test/GPGPU/cuda-annotations.ll
new file mode 100644
index 0000000..9a66279
--- /dev/null
+++ b/final/test/GPGPU/cuda-annotations.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=KERNEL %s
+
+; REQUIRES: pollyacc
+
+; KERNEL: define ptx_kernel void @FUNC_foo_SCOP_0_KERNEL_0(i8 addrspace(1)* %MemRef_A, i64 %n) #0 {
+
+; KERNEL: !nvvm.annotations = !{!0}
+
+; KERNEL: !0 = !{void (i8 addrspace(1)*, i64)* @FUNC_foo_SCOP_0_KERNEL_0, !"maxntidx", i32 32, !"maxntidy", i32 1, !"maxntidz", i32 1}
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64* %A, i64 %n) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %tmp = icmp slt i64 %i.0, %n
+  br i1 %tmp, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp3 = getelementptr inbounds i64, i64* %A, i64 %i.0
+  %tmp4 = load i64, i64* %tmp3, align 8
+  %tmp5 = add nsw i64 %tmp4, 100
+  store i64 %tmp5, i64* %tmp3, align 8
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/GPGPU/cuda-managed-memory-simple.ll b/final/test/GPGPU/cuda-managed-memory-simple.ll
new file mode 100644
index 0000000..6931bc7
--- /dev/null
+++ b/final/test/GPGPU/cuda-managed-memory-simple.ll
@@ -0,0 +1,118 @@
+; RUN: opt %loadPolly -S  -polly-process-unprofitable -polly-acc-mincompute=0 -polly-target=gpu  -polly-codegen-ppcg -polly-acc-codegen-managed-memory < %s | \
+; RUN: FileCheck %s
+
+; REQUIRES: pollyacc
+
+;
+;    #include <cuda_runtime.h>
+;
+;    static const int N = 45;
+;
+;    void copy(int *R, int *A) {
+;      for (int i = 0; i < N; i++) {
+;        R[i] = A[i] * 10;
+;      }
+;    }
+;
+;    int main() {
+;      int *A, *R;
+;
+;      cudaMallocManaged((void **)(&A), sizeof(int) * N, cudaMemAttachGlobal);
+;      cudaMallocManaged((void **)(&R), sizeof(int) * N, cudaMemAttachGlobal);
+;
+;      for (int i = 0; i < N; i++) {
+;        A[i] = i;
+;        R[i] = 0;
+;      }
+;      copy(R, A);
+;
+;      return 0;
+;    }
+;
+
+; CHECK-NOT: polly_copyFromHostToDevice
+; CHECK-NOT: polly_copyFromDeviceToHost
+; CHECK-NOT: polly_freeDeviceMemory
+; CHECK-NOT: polly_allocateMemoryForDevice
+
+; CHECK:       %[[REGCTX:[0-9]+]] = call i8* @polly_initContextCUDA()
+; CHECK-NEXT:  %[[REGCA:[0-9]+]] = bitcast i32* %A to i8*
+; CHECK-NEXT:  %[[REGCR:[0-9]+]] = bitcast i32* %R to i8*
+; CHECK-NEXT:  %[[REGGEP0:[0-9]+]] = getelementptr [2 x i8*], [2 x i8*]* %polly_launch_0_params, i64 0, i64 0
+; CHECK-NEXT:  store i8* %[[REGCA]], i8** %polly_launch_0_param_0
+; CHECK-NEXT:  %[[REGCP0:[0-9]+]] = bitcast i8** %polly_launch_0_param_0 to i8*
+; CHECK-NEXT:  store i8* %[[REGCP0]], i8** %[[REGGEP0]]
+; CHECK-NEXT:  %[[REGGEP1:[0-9]+]] = getelementptr [2 x i8*], [2 x i8*]* %polly_launch_0_params, i64 0, i64 1
+; CHECK-NEXT:  store i8* %[[REGCR]], i8** %polly_launch_0_param_1
+; CHECK-NEXT:  %[[REGCP1:[0-9]+]] = bitcast i8** %polly_launch_0_param_1 to i8*
+; CHECK-NEXT:  store i8* %[[REGCP1]], i8** %[[REGGEP1]]
+; CHECK-NEXT:  %[[REGKERNEL:[0-9]+]] = call i8* @polly_getKernel(i8* getelementptr inbounds ([852 x i8], [852 x i8]* @FUNC_copy_SCOP_0_KERNEL_0, i32 0, i32 0), i8* getelementptr inbounds ([26 x i8], [26 x i8]* @FUNC_copy_SCOP_0_KERNEL_0_name, i32 0, i32 0))
+; CHECK-NEXT:  call void @polly_launchKernel(i8* %[[REGKERNEL]], i32 2, i32 1, i32 32, i32 1, i32 1, i8* %polly_launch_0_params_i8ptr)
+; CHECK-NEXT:  call void @polly_freeKernel(i8* %[[REGKERNEL]])
+; CHECK-NEXT:  call void @polly_synchronizeDevice()
+; CHECK-NEXT:  call void @polly_freeContext(i8* %[[REGCTX]])
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @copy(i32* %R, i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 45
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4
+  %mul = mul nsw i32 %tmp, 10
+  %arrayidx2 = getelementptr inbounds i32, i32* %R, i64 %indvars.iv
+  store i32 %mul, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+define i32 @main() {
+entry:
+  %A = alloca i32*, align 8
+  %R = alloca i32*, align 8
+  %tmp = bitcast i32** %A to i8**
+  %call = call i32 @cudaMallocManaged(i8** nonnull %tmp, i64 180, i32 1) #2
+  %tmp1 = bitcast i32** %R to i8**
+  %call1 = call i32 @cudaMallocManaged(i8** nonnull %tmp1, i64 180, i32 1) #2
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 45
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp2 = load i32*, i32** %A, align 8
+  %arrayidx = getelementptr inbounds i32, i32* %tmp2, i64 %indvars.iv
+  %tmp3 = trunc i64 %indvars.iv to i32
+  store i32 %tmp3, i32* %arrayidx, align 4
+  %tmp4 = load i32*, i32** %R, align 8
+  %arrayidx3 = getelementptr inbounds i32, i32* %tmp4, i64 %indvars.iv
+  store i32 0, i32* %arrayidx3, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  %tmp5 = load i32*, i32** %R, align 8
+  %tmp6 = load i32*, i32** %A, align 8
+  call void @copy(i32* %tmp5, i32* %tmp6)
+  ret i32 0
+}
+
+declare i32 @cudaMallocManaged(i8**, i64, i32) #1
diff --git a/final/test/GPGPU/debug-metadata-leak.ll b/final/test/GPGPU/debug-metadata-leak.ll
new file mode 100644
index 0000000..e0ad4d4
--- /dev/null
+++ b/final/test/GPGPU/debug-metadata-leak.ll
@@ -0,0 +1,104 @@
+; RUN: opt %loadPolly %s -polly-process-unprofitable -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: | FileCheck --check-prefix=KERNEL-IR %s
+
+; REQUIRES: pollyacc
+
+; KERNEL-IR: define ptx_kernel void @FUNC_vec_add_1_SCOP_0_KERNEL_0(i8 addrspace(1)* %MemRef_arr, i32 %N) #0 {
+
+; The instruction marked <<<LeakyInst>>> is copied into the GPUModule,
+; with changes only to the parameters to access data on the device instead of
+; the host, i.e., MemRef_arr becomes polly.access.cast.MemRef_arr. Since the
+; instruction is annotated with a DILocation, copying the instruction also copies
+; the metadata into the GPUModule. This stops codegenerating the ptx_kernel by
+; failing the verification of the Module in GPUNodeBuilder::finalize, due to the
+; copied DICompileUnit not being listed in a llvm.dbg.cu which was neither copied
+; nor created.
+;
+; https://reviews.llvm.org/D35630 removes this debug metadata before the
+; instruction is copied to the GPUModule.
+; 
+; vec_add_1.c:
+;      void vec_add_1(int N, int arr[N]) {
+;        int i=0;
+;        for( i=0 ; i<N ; i++) arr[i] += 1;
+;      }
+;
+source_filename = "vec_add_1.c"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @vec_add_1(i32 %N, i32* %arr) !dbg !7 {
+entry:
+  call void @llvm.dbg.value(metadata i32 %N, i64 0, metadata !13, metadata !16), !dbg !17
+  call void @llvm.dbg.value(metadata i32* %arr, i64 0, metadata !14, metadata !16), !dbg !18
+  call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !15, metadata !16), !dbg !19
+  %tmp = sext i32 %N to i64, !dbg !20
+  br label %for.cond, !dbg !20
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  call void @llvm.dbg.value(metadata i32 undef, i64 0, metadata !15, metadata !16), !dbg !19
+  %cmp = icmp slt i64 %indvars.iv, %tmp, !dbg !22
+  br i1 %cmp, label %for.body, label %for.end, !dbg !24
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %arr, i64 %indvars.iv, !dbg !25
+  %tmp1 = load i32, i32* %arrayidx, align 4, !dbg !26, !tbaa !27
+  %add = add nsw i32 %tmp1, 1, !dbg !26    ;   <<<LeakyInst>>>
+  store i32 %add, i32* %arrayidx, align 4, !dbg !26, !tbaa !27
+  br label %for.inc, !dbg !25
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1, !dbg !31
+  call void @llvm.dbg.value(metadata !2, i64 0, metadata !15, metadata !16), !dbg !19
+  br label %for.cond, !dbg !32, !llvm.loop !33
+
+for.end:                                          ; preds = %for.cond
+  ret void, !dbg !35
+}
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
+
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.0 (http://llvm.org/git/clang.git 23e042ffe07a923db2dbebf4d2a3692c5a454fee) (http://llvm.org/git/llvm.git 39c5686a1f54884f12120927b1753a750fdb5e02)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "vec_add_1.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 5.0.0 (http://llvm.org/git/clang.git 23e042ffe07a923db2dbebf4d2a3692c5a454fee) (http://llvm.org/git/llvm.git 39c5686a1f54884f12120927b1753a750fdb5e02)"}
+!7 = distinct !DISubprogram(name: "vec_add_1", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
+!8 = !DISubroutineType(types: !9)
+!9 = !{null, !10, !11}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64)
+!12 = !{!13, !14, !15}
+!13 = !DILocalVariable(name: "N", arg: 1, scope: !7, file: !1, line: 1, type: !10)
+!14 = !DILocalVariable(name: "arr", arg: 2, scope: !7, file: !1, line: 1, type: !11)
+!15 = !DILocalVariable(name: "i", scope: !7, file: !1, line: 2, type: !10)
+!16 = !DIExpression()
+!17 = !DILocation(line: 1, column: 20, scope: !7)
+!18 = !DILocation(line: 1, column: 27, scope: !7)
+!19 = !DILocation(line: 2, column: 7, scope: !7)
+!20 = !DILocation(line: 3, column: 8, scope: !21)
+!21 = distinct !DILexicalBlock(scope: !7, file: !1, line: 3, column: 3)
+!22 = !DILocation(line: 3, column: 15, scope: !23)
+!23 = distinct !DILexicalBlock(scope: !21, file: !1, line: 3, column: 3)
+!24 = !DILocation(line: 3, column: 3, scope: !21)
+!25 = !DILocation(line: 3, column: 25, scope: !23)
+!26 = !DILocation(line: 3, column: 32, scope: !23)
+!27 = !{!28, !28, i64 0}
+!28 = !{!"int", !29, i64 0}
+!29 = !{!"omnipotent char", !30, i64 0}
+!30 = !{!"Simple C/C++ TBAA"}
+!31 = !DILocation(line: 3, column: 21, scope: !23)
+!32 = !DILocation(line: 3, column: 3, scope: !23)
+!33 = distinct !{!33, !24, !34}
+!34 = !DILocation(line: 3, column: 35, scope: !21)
+!35 = !DILocation(line: 4, column: 1, scope: !7)
diff --git a/final/test/GPGPU/double-parallel-loop.ll b/final/test/GPGPU/double-parallel-loop.ll
new file mode 100644
index 0000000..b52d351
--- /dev/null
+++ b/final/test/GPGPU/double-parallel-loop.ll
@@ -0,0 +1,256 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-schedule \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=SCHED %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -S < %s | \
+; RUN: FileCheck %s -check-prefix=IR
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck %s -check-prefix=KERNEL-IR
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-asm \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck %s -check-prefix=KERNEL-ASM
+
+; REQUIRES: pollyacc,nvptx
+
+; CHECK: Stmt_bb5
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_bb5[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_bb5[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:       ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_bb5[i0, i1] -> MemRef_A[i0, i1] };
+; CHECK-NEXT:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_bb5[i0, i1] -> MemRef_A[i0, i1] };
+
+; SCHED: domain: "{ Stmt_bb5[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 }"
+; SCHED-NEXT: child:
+; SCHED-NEXT:   context: "{ [] }"
+; SCHED-NEXT:   child:
+; SCHED-NEXT:     extension: "{ [] -> from_device_MemRef_A[]; [] -> to_device_MemRef_A[] }"
+; SCHED-NEXT:     child:
+; SCHED-NEXT:       sequence:
+; SCHED-NEXT:       - filter: "{ to_device_MemRef_A[] }"
+; SCHED-NEXT:         child:
+; SCHED-NEXT:           set:
+; SCHED-NEXT:           - filter: "{ to_device_MemRef_A[] }"
+; SCHED-NEXT:             child:
+; SCHED-NEXT:               guard: "{ [] }"
+; SCHED-NEXT:       - filter: "{ Stmt_bb5[i0, i1] }"
+; SCHED-NEXT:         child:
+; SCHED-NEXT:           guard: "{ [] }"
+; SCHED-NEXT:           child:
+; SCHED-NEXT:             mark: "kernel"
+; SCHED-NEXT:             child:
+; SCHED-NEXT:               context: "[b0, b1, t0, t1] -> { [] : 0 <= b0 <= 31 and 0 <= b1 <= 31 and 0 <= t0 <= 31 and 0 <= t1 <= 15 }"
+; SCHED-NEXT:               child:
+; SCHED-NEXT:                 filter: "[b0, b1] -> { Stmt_bb5[i0, i1] : -31 - 32b0 + i0 <= 8192*floor((i0)/8192) <= -32b0 + i0 and -31 - 32b1 + i1 <= 8192*floor((i1)/8192) <= -32b1 + i1 }"
+; SCHED-NEXT:                 child:
+; SCHED-NEXT:                   schedule: "[{ Stmt_bb5[i0, i1] -> [(floor((i0)/8192))] }, { Stmt_bb5[i0, i1] -> [(floor((i1)/8192))] }]"
+; SCHED-NEXT:                   permutable: 1
+; SCHED-NEXT:                   coincident: [ 1, 1 ]
+; SCHED-NEXT:                   child:
+; SCHED-NEXT:                     filter: "[t0, t1] -> { Stmt_bb5[i0, i1] : 32*floor((-t0 + i0)/32) = -t0 + i0 and 16*floor((-t1 + i1)/16) = -t1 + i1 and 0 <= t0 <= 31 and 0 <= t1 <= 15 }"
+; SCHED-NEXT:                     child:
+; SCHED-NEXT:                       schedule: "[{ Stmt_bb5[i0, i1] -> [(0)] }, { Stmt_bb5[i0, i1] -> [(floor((i1)/16) - 2*floor((i1)/32))] }]"
+; SCHED-NEXT:                       permutable: 1
+; SCHED-NEXT:                       coincident: [ 1, 1 ]
+; SCHED-NEXT:       - filter: "{ from_device_MemRef_A[] }"
+; SCHED-NEXT:         child:
+; SCHED-NEXT:           set:
+; SCHED-NEXT:           - filter: "{ from_device_MemRef_A[] }"
+; SCHED-NEXT:             child:
+; SCHED-NEXT:               guard: "{ [] }"
+
+; CODE: Code
+; CODE-NEXT: ====
+; CODE-NEXT: # host
+; CODE-NEXT: {
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (1024) * (1024) * sizeof(float), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(16, 32);
+; CODE-NEXT:     dim3 k0_dimGrid(32, 32);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (1024) * (1024) * sizeof(float), cudaMemcpyDeviceToHost));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: for (int c3 = 0; c3 <= 1; c3 += 1)
+; CODE-NEXT:   Stmt_bb5(32 * b0 + t0, 32 * b1 + t1 + 16 * c3);
+
+; IR: polly.split_new_and_old:
+; IR-NEXT:   %0 = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 1024)
+; IR-NEXT:   %.obit = extractvalue { i64, i1 } %0, 1
+; IR-NEXT:   %polly.overflow.state = or i1 false, %.obit
+; IR-NEXT:   %.res = extractvalue { i64, i1 } %0, 0
+; IR-NEXT:   %1 = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 %.res, i64 1024)
+; IR-NEXT:   %.obit1 = extractvalue { i64, i1 } %1, 1
+; IR-NEXT:   %polly.overflow.state2 = or i1 %polly.overflow.state, %.obit1
+; IR-NEXT:   %.res3 = extractvalue { i64, i1 } %1, 0
+; IR-NEXT:   %2 = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 7, i64 %.res3)
+; IR-NEXT:   %.obit4 = extractvalue { i64, i1 } %2, 1
+; IR-NEXT:   %polly.overflow.state5 = or i1 %polly.overflow.state2, %.obit4
+; IR-NEXT:   %.res6 = extractvalue { i64, i1 } %2, 0
+; IR-NEXT:   %3 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 0, i64 %.res6)
+; IR-NEXT:   %.obit7 = extractvalue { i64, i1 } %3, 1
+; IR-NEXT:   %polly.overflow.state8 = or i1 %polly.overflow.state5, %.obit7
+; IR-NEXT:   %.res9 = extractvalue { i64, i1 } %3, 0
+; IR-NEXT:   %4 = icmp sge i64 %.res9, 2621440
+; IR-NEXT:   %5 = and i1 true, %4
+; IR-NEXT:   %polly.rtc.overflown = xor i1 %polly.overflow.state8, true
+; IR-NEXT:   %polly.rtc.result = and i1 %5, %polly.rtc.overflown
+; IR-NEXT:   br i1 %polly.rtc.result, label %polly.start, label %bb2
+
+; IR: polly.start:
+; IR-NEXT: br label %polly.acc.initialize
+
+; IR: polly.acc.initialize:
+; IR-NEXT:    [[GPUContext:%.*]] = call i8* @polly_initContext()
+; IR-NEXT:    %p_dev_array_MemRef_A = call i8* @polly_allocateMemoryForDevice(i64 4194304)
+; IR-NEXT:    [[HostPtr:%.*]] = bitcast [1024 x float]* %A to i8*
+; IR-NEXT:    call void @polly_copyFromHostToDevice(i8* [[HostPtr]], i8* %p_dev_array_MemRef_A, i64 4194304)
+; IR-NEXT:    [[DevPtr:%.*]]  = call i8* @polly_getDevicePtr(i8* %p_dev_array_MemRef_A)
+; IR-NEXT:    [[ParamSlot:%.*]] = getelementptr [1 x i8*], [1 x i8*]* %polly_launch_0_params, i64 0, i64 0
+; IR-NEXT:    store i8* [[DevPtr]], i8** %polly_launch_0_param_0
+; IR-NEXT:    [[ParamTyped:%.*]] = bitcast i8** %polly_launch_0_param_0 to i8*
+; IR-NEXT:    store i8* [[ParamTyped]], i8** [[ParamSlot]]
+; IR-NEXT:    call i8* @polly_getKernel
+; IR-NEXT:    call void @polly_launchKernel(i8* %11, i32 32, i32 32, i32 32, i32 16, i32 1, i8* %polly_launch_0_params_i8ptr)
+; IR-NEXT:    call void @polly_freeKernel
+; IR-NEXT:    [[HostPtr2:%.*]] = bitcast [1024 x float]* %A to i8*
+; IR-NEXT:    call void @polly_copyFromDeviceToHost(i8* %p_dev_array_MemRef_A, i8* [[HostPtr2]], i64 4194304)
+; IR-NEXT:    call void @polly_freeDeviceMemory(i8* %p_dev_array_MemRef_A)
+; IR-NEXT:    call void @polly_freeContext(i8* [[GPUContext]])
+; IR-NEXT:    br label %polly.exiting
+
+; IR: polly.exiting:
+; IR-NEXT:    br label %polly.merge_new_and_old
+
+; KERNEL-IR-LABEL: define ptx_kernel void @kernel_0(i8* %MemRef_A) #0 {
+; KERNEL-IR-NEXT: entry:
+; KERNEL-IR-NEXT:   %0 = call i32 @llvm.nvvm.read.ptx.sreg.ctaid.x()
+; KERNEL-IR-NEXT:   %b0 = zext i32 %0 to i64
+; KERNEL-IR-NEXT:   %1 = call i32 @llvm.nvvm.read.ptx.sreg.ctaid.y()
+; KERNEL-IR-NEXT:   %b1 = zext i32 %1 to i64
+; KERNEL-IR-NEXT:   %2 = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
+; KERNEL-IR-NEXT:   %t0 = zext i32 %2 to i64
+; KERNEL-IR-NEXT:   %3 = call i32 @llvm.nvvm.read.ptx.sreg.tid.y()
+; KERNEL-IR-NEXT:   %t1 = zext i32 %3 to i64
+; KERNEL-IR-NEXT:   br label %polly.loop_preheader
+
+; KERNEL-IR-LABEL: polly.loop_exit:                                  ; preds = %polly.stmt.bb5
+; KERNEL-IR-NEXT:   ret void
+
+; KERNEL-IR-LABEL: polly.loop_header:                                ; preds = %polly.stmt.bb5, %polly.loop_preheader
+; KERNEL-IR-NEXT:   %polly.indvar = phi i64 [ 0, %polly.loop_preheader ], [ %polly.indvar_next, %polly.stmt.bb5 ]
+; KERNEL-IR-NEXT:   %4 = mul nsw i64 32, %b0
+; KERNEL-IR-NEXT:   %5 = add nsw i64 %4, %t0
+; KERNEL-IR-NEXT:   %6 = mul nsw i64 32, %b1
+; KERNEL-IR-NEXT:   %7 = add nsw i64 %6, %t1
+; KERNEL-IR-NEXT:   %8 = mul nsw i64 16, %polly.indvar
+; KERNEL-IR-NEXT:   %9 = add nsw i64 %7, %8
+; KERNEL-IR-NEXT:   br label %polly.stmt.bb5
+
+; KERNEL-IR-LABEL: polly.stmt.bb5:                                   ; preds = %polly.loop_header
+; KERNEL-IR-NEXT:   %10 = mul i64 %5, %9
+; KERNEL-IR-NEXT:   %p_tmp6 = sitofp i64 %10 to float
+; KERNEL-IR-NEXT:   %polly.access.cast.MemRef_A = bitcast i8* %MemRef_A to float*
+; KERNEL-IR-NEXT:   %11 = mul nsw i64 32, %b0
+; KERNEL-IR-NEXT:   %12 = add nsw i64 %11, %t0
+; KERNEL-IR-NEXT:   %polly.access.mul.MemRef_A = mul nsw i64 %12, 1024
+; KERNEL-IR-NEXT:   %13 = mul nsw i64 32, %b1
+; KERNEL-IR-NEXT:   %14 = add nsw i64 %13, %t1
+; KERNEL-IR-NEXT:   %15 = mul nsw i64 16, %polly.indvar
+; KERNEL-IR-NEXT:   %16 = add nsw i64 %14, %15
+; KERNEL-IR-NEXT:   %polly.access.add.MemRef_A = add nsw i64 %polly.access.mul.MemRef_A, %16
+; KERNEL-IR-NEXT:   %polly.access.MemRef_A = getelementptr float, float* %polly.access.cast.MemRef_A, i64 %polly.access.add.MemRef_A
+; KERNEL-IR-NEXT:   %tmp8_p_scalar_ = load float, float* %polly.access.MemRef_A, align 4
+; KERNEL-IR-NEXT:   %p_tmp9 = fadd float %tmp8_p_scalar_, %p_tmp6
+; KERNEL-IR-NEXT:   %polly.access.cast.MemRef_A1 = bitcast i8* %MemRef_A to float*
+; KERNEL-IR-NEXT:   %17 = mul nsw i64 32, %b0
+; KERNEL-IR-NEXT:   %18 = add nsw i64 %17, %t0
+; KERNEL-IR-NEXT:   %polly.access.mul.MemRef_A2 = mul nsw i64 %18, 1024
+; KERNEL-IR-NEXT:   %19 = mul nsw i64 32, %b1
+; KERNEL-IR-NEXT:   %20 = add nsw i64 %19, %t1
+; KERNEL-IR-NEXT:   %21 = mul nsw i64 16, %polly.indvar
+; KERNEL-IR-NEXT:   %22 = add nsw i64 %20, %21
+; KERNEL-IR-NEXT:   %polly.access.add.MemRef_A3 = add nsw i64 %polly.access.mul.MemRef_A2, %22
+; KERNEL-IR-NEXT:   %polly.access.MemRef_A4 = getelementptr float, float* %polly.access.cast.MemRef_A1, i64 %polly.access.add.MemRef_A3
+; KERNEL-IR-NEXT:   store float %p_tmp9, float* %polly.access.MemRef_A4, align 4
+; KERNEL-IR-NEXT:   %polly.indvar_next = add nsw i64 %polly.indvar, 1
+; KERNEL-IR-NEXT:   %polly.loop_cond = icmp sle i64 %polly.indvar, 0
+; KERNEL-IR-NEXT:   br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit
+
+; KERNEL-IR-LABEL: polly.loop_preheader:                             ; preds = %entry
+; KERNEL-IR-NEXT:   br label %polly.loop_header
+
+; KERNEL-IR: attributes #0 = { "polly.skip.fn" }
+
+; KERNEL-ASM: .version 3.2
+; KERNEL-ASM-NEXT: .target sm_30
+; KERNEL-ASM-NEXT: .address_size 64
+
+; KERNEL-ASM:   // .globl     kernel_0
+
+; KERNEL-ASM: .visible .entry kernel_0(
+; KERNEL-ASM-NEXT:   .param .u64 kernel_0_param_0
+; KERNEL-ASM-NEXT: )
+
+;    void double_parallel_loop(float A[][1024]) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          A[i][j] += i * j;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @double_parallel_loop([1024 x float]* %A) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb13, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp14, %bb13 ]
+  %exitcond1 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond1, label %bb3, label %bb15
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb10, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp11, %bb10 ]
+  %exitcond = icmp ne i64 %j.0, 1024
+  br i1 %exitcond, label %bb5, label %bb12
+
+bb5:                                              ; preds = %bb4
+  %tmp = mul nuw nsw i64 %i.0, %j.0
+  %tmp6 = sitofp i64 %tmp to float
+  %tmp7 = getelementptr inbounds [1024 x float], [1024 x float]* %A, i64 %i.0, i64 %j.0
+  %tmp8 = load float, float* %tmp7, align 4
+  %tmp9 = fadd float %tmp8, %tmp6
+  store float %tmp9, float* %tmp7, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb5
+  %tmp11 = add nuw nsw i64 %j.0, 1
+  br label %bb4
+
+bb12:                                             ; preds = %bb4
+  br label %bb13
+
+bb13:                                             ; preds = %bb12
+  %tmp14 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb15:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/GPGPU/failing-invariant-load-handling.ll b/final/test/GPGPU/failing-invariant-load-handling.ll
new file mode 100644
index 0000000..314928b
--- /dev/null
+++ b/final/test/GPGPU/failing-invariant-load-handling.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly < %s -analyze -polly-scops -polly-process-unprofitable -polly-invariant-load-hoisting | FileCheck %s -check-prefix=SCOPS
+; RUN: opt %loadPolly -S < %s -polly-codegen-ppcg -polly-process-unprofitable -polly-invariant-load-hoisting | FileCheck %s -check-prefix=CODEGEN
+
+; REQUIRES: pollyacc
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n8:16:32-S64"
+
+%S = type { i32, i32, [12 x %L] }
+%L = type { i32, i32, double, i32, i32, i32, i32, i32 }
+
+define void @test(%S* %cpi, i1 %b) {
+; SCOPS-LABEL: Region: %if.then14---%exit
+; SCOPS:         Invariant Accesses: {
+; SCOPS-NEXT:            ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; SCOPS-NEXT:                [l2, l1] -> { Stmt_for_body_i[i0] -> MemRef_cpi[0, 0] };
+; SCOPS-NEXT:            Execution Context: [l2, l1] -> {  :  }
+; SCOPS-NEXT:            ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; SCOPS-NEXT:                [l2, l1] -> { Stmt_for_body_lr_ph_i[] -> MemRef_cpi[0, 1] };
+; SCOPS-NEXT:            Execution Context: [l2, l1] -> {  : l2 > 0 }
+; SCOPS-NEXT:    }
+; SCOPS:         Arrays {
+; SCOPS-NEXT:        i32 MemRef_cpi[*][(10 * %l1)]; // Element size 4
+; SCOPS-NEXT:    }
+
+; Check that we gracefully handle failing invariant loads.
+; This test case is taken from:
+; test/Isl/CodeGen/invariant-load-dimension.ll
+
+; FIXME: Figure out how to actually generate code for this loop.
+; CODEGEN-NOT: LLVM ERROR: preloading invariant loads failed in function
+
+entry:
+  %nt = getelementptr inbounds %S, %S* %cpi, i32 0, i32 1
+  br i1 %b, label %if.then14, label %exit
+
+if.then14:
+  %ns = getelementptr inbounds %S, %S* %cpi, i32 0, i32 0
+  %l0 = load i32, i32* %ns, align 8
+  %cmp12.i = icmp sgt i32 %l0, 0
+  br i1 %cmp12.i, label %for.body.lr.ph.i, label %exit
+
+for.body.lr.ph.i:
+  %l1 = load i32, i32* %nt, align 4
+  br label %for.body.i
+
+for.body.i:
+  %phi = phi i32 [ 0, %for.body.lr.ph.i ], [ %inc, %for.body.i ]
+  %mul.i163 = mul nsw i32 %phi, %l1
+  %cv = getelementptr inbounds %S, %S* %cpi, i32 0, i32 2, i32 %mul.i163, i32 0
+  store i32 0, i32* %cv, align 8
+  %inc = add nuw nsw i32 %phi, 1
+  %l2 = load i32, i32* %ns, align 8
+  %cmp.i164 = icmp slt i32 %inc, %l2
+  br i1 %cmp.i164, label %for.body.i, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/GPGPU/failing-invariant-load-hoisting.ll b/final/test/GPGPU/failing-invariant-load-hoisting.ll
new file mode 100644
index 0000000..cfdd666
--- /dev/null
+++ b/final/test/GPGPU/failing-invariant-load-hoisting.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -S < %s -polly-codegen-ppcg \
+; RUN: -polly-invariant-load-hoisting | FileCheck %s -check-prefix=CODEGEN
+
+; REQUIRES: pollyacc
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n8:16:32-S64"
+
+%S = type { i32, i32, [12 x %L] }
+%L = type { i32, i32, double, i32, i32, i32, i32, i32 }
+
+define void @test(%S* %cpi, i1 %b) {
+; CODEGEN-LABEL: @test(
+; CODEGEN:    polly.preload.begin:
+; CODEGEN-NEXT:  br i1 false
+
+entry:
+  %nt = getelementptr inbounds %S, %S* %cpi, i32 0, i32 1
+  br i1 %b, label %if.then14, label %exit
+
+if.then14:
+  %ns = getelementptr inbounds %S, %S* %cpi, i32 0, i32 0
+  %l0 = load i32, i32* %ns, align 8
+  %cmp12.i = icmp sgt i32 %l0, 0
+  br i1 %cmp12.i, label %for.body.lr.ph.i, label %exit
+
+for.body.lr.ph.i:
+  %l1 = load i32, i32* %nt, align 4
+  br label %for.body.i
+
+for.body.i:
+  %phi = phi i32 [ 0, %for.body.lr.ph.i ], [ %inc, %for.body.i ]
+  %mul.i163 = mul nsw i32 %phi, %l1
+  %cv = getelementptr inbounds %S, %S* %cpi, i32 0, i32 2, i32 %mul.i163, i32 0
+  store i32 0, i32* %cv, align 8
+  %inc = add nuw nsw i32 %phi, 1
+  %l2 = load i32, i32* %ns, align 8
+  %cmp.i164 = icmp slt i32 %inc, %l2
+  br i1 %cmp.i164, label %for.body.i, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/GPGPU/host-control-flow.ll b/final/test/GPGPU/host-control-flow.ll
new file mode 100644
index 0000000..e401fb2
--- /dev/null
+++ b/final/test/GPGPU/host-control-flow.ll
@@ -0,0 +1,176 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -disable-output \
+; RUN: -polly-acc-dump-code < %s | FileCheck %s -check-prefix=CODE
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -disable-output \
+; RUN: -polly-acc-dump-kernel-ir < %s | FileCheck %s -check-prefix=KERNEL-IR
+
+; RUN: opt %loadPolly -polly-codegen-ppcg \
+; RUN: -S < %s | FileCheck %s -check-prefix=IR
+;    void foo(float A[2][100]) {
+;      for (long t = 0; t < 100; t++)
+;        for (long i = 1; i < 99; i++)
+;          A[(t + 1) % 2][i] += A[t % 2][i - 1] + A[t % 2][i] + A[t % 2][i + 1];
+;    }
+
+; REQUIRES: pollyacc
+
+; CODE:        cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (2) * (100) * sizeof(float), cudaMemcpyHostToDevice));
+; CODE-NEXT:   for (int c0 = 0; c0 <= 99; c0 += 1)
+; CODE-NEXT:     {
+; CODE-NEXT:       dim3 k0_dimBlock(32);
+; CODE-NEXT:       dim3 k0_dimGrid(4);
+; CODE-NEXT:       kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A, c0);
+; CODE-NEXT:       cudaCheckKernel();
+; CODE-NEXT:     }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (2) * (100) * sizeof(float), cudaMemcpyDeviceToHost));
+; CODE-NEXT: cudaCheckReturn(cudaFree(dev_MemRef_A));
+; CODE-NEXT: }
+
+; IR-LABEL: polly.loop_header:                                ; preds = %polly.loop_header, %polly.loop_preheader
+; IR-NEXT:   %polly.indvar = phi i64 [ 0, %polly.loop_preheader ], [ %polly.indvar_next, %polly.loop_header ]
+; ...
+; IR:  store i64 %polly.indvar, i64* %polly_launch_0_param_1
+; IR-NEXT:  [[REGA:%.+]] = getelementptr [2 x i8*], [2 x i8*]* %polly_launch_0_params, i64 0, i64 1
+; IR-NEXT:  [[REGB:%.+]] = bitcast i64* %polly_launch_0_param_1 to i8*
+; IR-NEXT:  store i8* [[REGB]], i8** [[REGA]]
+; IR: call i8* @polly_getKernel
+; ...
+; IR: call void @polly_freeKernel
+; IR-NEXT:   %polly.indvar_next = add nsw i64 %polly.indvar, 1
+; IR-NEXT:   %polly.loop_cond = icmp sle i64 %polly.indvar_next, 99
+; IR-NEXT:   br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit
+
+; KERNEL-IR: define ptx_kernel void @FUNC_foo_SCOP_0_KERNEL_0(i8 addrspace(1)* %MemRef_A, i64 %c0)
+; KERNEL-IR-LABEL: entry:
+; KERNEL-IR-NEXT:   %0 = call i32 @llvm.nvvm.read.ptx.sreg.ctaid.x()
+; KERNEL-IR-NEXT:   %b0 = zext i32 %0 to i64
+; KERNEL-IR-NEXT:   %1 = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
+; KERNEL-IR-NEXT:   %t0 = zext i32 %1 to i64
+; KERNEL-IR-NEXT:   br label %polly.cond
+
+; KERNEL-IR-LABEL: polly.cond:                                       ; preds = %entry
+; KERNEL-IR-NEXT:   %2 = mul nsw i64 32, %b0
+; KERNEL-IR-NEXT:   %3 = add nsw i64 %2, %t0
+; KERNEL-IR-NEXT:   %4 = icmp sle i64 %3, 97
+; KERNEL-IR-NEXT:   br i1 %4, label %polly.then, label %polly.else
+
+; KERNEL-IR-LABEL: polly.merge:                                      ; preds = %polly.else, %polly.stmt.for.body3
+; KERNEL-IR-NEXT:   ret void
+
+; KERNEL-IR-LABEL: polly.then:                                       ; preds = %polly.cond
+; KERNEL-IR-NEXT:   %5 = mul nsw i64 32, %b0
+; KERNEL-IR-NEXT:   %6 = add nsw i64 %5, %t0
+; KERNEL-IR-NEXT:   br label %polly.stmt.for.body3
+
+; KERNEL-IR-LABEL: polly.stmt.for.body3:                             ; preds = %polly.then
+; KERNEL-IR-NEXT:   %polly.access.cast.MemRef_A = bitcast i8 addrspace(1)* %MemRef_A to float addrspace(1)*
+; KERNEL-IR-NEXT:   %pexp.pdiv_r = urem i64 %c0, 2
+; KERNEL-IR-NEXT:   %polly.access.mul.MemRef_A = mul nsw i64 %pexp.pdiv_r, 100
+; KERNEL-IR-NEXT:   %7 = mul nsw i64 32, %b0
+; KERNEL-IR-NEXT:   %8 = add nsw i64 %7, %t0
+; KERNEL-IR-NEXT:   %polly.access.add.MemRef_A = add nsw i64 %polly.access.mul.MemRef_A, %8
+; KERNEL-IR-NEXT:   %polly.access.MemRef_A = getelementptr float, float addrspace(1)* %polly.access.cast.MemRef_A, i64 %polly.access.add.MemRef_A
+; KERNEL-IR-NEXT:   %tmp_p_scalar_ = load float, float addrspace(1)* %polly.access.MemRef_A, align 4
+; KERNEL-IR-NEXT:   %polly.access.cast.MemRef_A1 = bitcast i8 addrspace(1)* %MemRef_A to float addrspace(1)*
+; KERNEL-IR-NEXT:   %pexp.pdiv_r2 = urem i64 %c0, 2
+; KERNEL-IR-NEXT:   %polly.access.mul.MemRef_A3 = mul nsw i64 %pexp.pdiv_r2, 100
+; KERNEL-IR-NEXT:   %9 = mul nsw i64 32, %b0
+; KERNEL-IR-NEXT:   %10 = add nsw i64 %9, %t0
+; KERNEL-IR-NEXT:   %11 = add nsw i64 %10, 1
+; KERNEL-IR-NEXT:   %polly.access.add.MemRef_A4 = add nsw i64 %polly.access.mul.MemRef_A3, %11
+; KERNEL-IR-NEXT:   %polly.access.MemRef_A5 = getelementptr float, float addrspace(1)* %polly.access.cast.MemRef_A1, i64 %polly.access.add.MemRef_A4
+; KERNEL-IR-NEXT:   %tmp2_p_scalar_ = load float, float addrspace(1)* %polly.access.MemRef_A5, align 4
+; KERNEL-IR-NEXT:   %p_add = fadd float %tmp_p_scalar_, %tmp2_p_scalar_
+; KERNEL-IR-NEXT:   %polly.access.cast.MemRef_A6 = bitcast i8 addrspace(1)* %MemRef_A to float addrspace(1)*
+; KERNEL-IR-NEXT:   %pexp.pdiv_r7 = urem i64 %c0, 2
+; KERNEL-IR-NEXT:   %polly.access.mul.MemRef_A8 = mul nsw i64 %pexp.pdiv_r7, 100
+; KERNEL-IR-NEXT:   %12 = mul nsw i64 32, %b0
+; KERNEL-IR-NEXT:   %13 = add nsw i64 %12, %t0
+; KERNEL-IR-NEXT:   %14 = add nsw i64 %13, 2
+; KERNEL-IR-NEXT:   %polly.access.add.MemRef_A9 = add nsw i64 %polly.access.mul.MemRef_A8, %14
+; KERNEL-IR-NEXT:   %polly.access.MemRef_A10 = getelementptr float, float addrspace(1)* %polly.access.cast.MemRef_A6, i64 %polly.access.add.MemRef_A9
+; KERNEL-IR-NEXT:   %tmp3_p_scalar_ = load float, float addrspace(1)* %polly.access.MemRef_A10, align 4
+; KERNEL-IR-NEXT:   %p_add12 = fadd float %p_add, %tmp3_p_scalar_
+; KERNEL-IR-NEXT:   %polly.access.cast.MemRef_A11 = bitcast i8 addrspace(1)* %MemRef_A to float addrspace(1)*
+; KERNEL-IR-NEXT:   %15 = add nsw i64 %c0, 1
+; KERNEL-IR-NEXT:   %pexp.pdiv_r12 = urem i64 %15, 2
+; KERNEL-IR-NEXT:   %polly.access.mul.MemRef_A13 = mul nsw i64 %pexp.pdiv_r12, 100
+; KERNEL-IR-NEXT:   %16 = mul nsw i64 32, %b0
+; KERNEL-IR-NEXT:   %17 = add nsw i64 %16, %t0
+; KERNEL-IR-NEXT:   %18 = add nsw i64 %17, 1
+; KERNEL-IR-NEXT:   %polly.access.add.MemRef_A14 = add nsw i64 %polly.access.mul.MemRef_A13, %18
+; KERNEL-IR-NEXT:   %polly.access.MemRef_A15 = getelementptr float, float addrspace(1)* %polly.access.cast.MemRef_A11, i64 %polly.access.add.MemRef_A14
+; KERNEL-IR-NEXT:   %tmp4_p_scalar_ = load float, float addrspace(1)* %polly.access.MemRef_A15, align 4
+; KERNEL-IR-NEXT:   %p_add17 = fadd float %tmp4_p_scalar_, %p_add12
+; KERNEL-IR-NEXT:   %polly.access.cast.MemRef_A16 = bitcast i8 addrspace(1)* %MemRef_A to float addrspace(1)*
+; KERNEL-IR-NEXT:   %19 = add nsw i64 %c0, 1
+; KERNEL-IR-NEXT:   %pexp.pdiv_r17 = urem i64 %19, 2
+; KERNEL-IR-NEXT:   %polly.access.mul.MemRef_A18 = mul nsw i64 %pexp.pdiv_r17, 100
+; KERNEL-IR-NEXT:   %20 = mul nsw i64 32, %b0
+; KERNEL-IR-NEXT:   %21 = add nsw i64 %20, %t0
+; KERNEL-IR-NEXT:   %22 = add nsw i64 %21, 1
+; KERNEL-IR-NEXT:   %polly.access.add.MemRef_A19 = add nsw i64 %polly.access.mul.MemRef_A18, %22
+; KERNEL-IR-NEXT:   %polly.access.MemRef_A20 = getelementptr float, float addrspace(1)* %polly.access.cast.MemRef_A16, i64 %polly.access.add.MemRef_A19
+; KERNEL-IR-NEXT:   store float %p_add17, float addrspace(1)* %polly.access.MemRef_A20, align 4
+; KERNEL-IR-NEXT:   br label %polly.merge
+
+; KERNEL-IR-LABEL: polly.else:                                       ; preds = %polly.cond
+; KERNEL-IR-NEXT:   br label %polly.merge
+; KERNEL-IR-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo([100 x float]* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc18, %entry
+  %t.0 = phi i64 [ 0, %entry ], [ %inc19, %for.inc18 ]
+  %exitcond1 = icmp ne i64 %t.0, 100
+  br i1 %exitcond1, label %for.body, label %for.end20
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %i.0 = phi i64 [ 1, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %i.0, 99
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %sub = add nsw i64 %i.0, -1
+  %rem = srem i64 %t.0, 2
+  %arrayidx4 = getelementptr inbounds [100 x float], [100 x float]* %A, i64 %rem, i64 %sub
+  %tmp = load float, float* %arrayidx4, align 4
+  %rem5 = srem i64 %t.0, 2
+  %arrayidx7 = getelementptr inbounds [100 x float], [100 x float]* %A, i64 %rem5, i64 %i.0
+  %tmp2 = load float, float* %arrayidx7, align 4
+  %add = fadd float %tmp, %tmp2
+  %add8 = add nuw nsw i64 %i.0, 1
+  %rem9 = srem i64 %t.0, 2
+  %arrayidx11 = getelementptr inbounds [100 x float], [100 x float]* %A, i64 %rem9, i64 %add8
+  %tmp3 = load float, float* %arrayidx11, align 4
+  %add12 = fadd float %add, %tmp3
+  %add13 = add nuw nsw i64 %t.0, 1
+  %rem14 = srem i64 %add13, 2
+  %arrayidx16 = getelementptr inbounds [100 x float], [100 x float]* %A, i64 %rem14, i64 %i.0
+  %tmp4 = load float, float* %arrayidx16, align 4
+  %add17 = fadd float %tmp4, %add12
+  store float %add17, float* %arrayidx16, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc18
+
+for.inc18:                                        ; preds = %for.end
+  %inc19 = add nuw nsw i64 %t.0, 1
+  br label %for.cond
+
+for.end20:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/GPGPU/host-statement.ll b/final/test/GPGPU/host-statement.ll
new file mode 100644
index 0000000..e54d368
--- /dev/null
+++ b/final/test/GPGPU/host-statement.ll
@@ -0,0 +1,204 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -polly-invariant-load-hoisting=false \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -polly-invariant-load-hoisting=false \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=KERNEL-IR %s
+
+; REQUIRES: pollyacc
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @llvm.lifetime.start(i64, i8* nocapture) #0
+
+; This test case tests that we can correctly handle a ScopStmt that is
+; scheduled on the host, instead of within a kernel.
+
+; CODE:        cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (512) * (512) * sizeof(double), cudaMemcpyHostToDevice));
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_R, MemRef_R, (p_0 + 1) * (512) * sizeof(double), cudaMemcpyHostToDevice));
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_Q, MemRef_Q, (512) * (512) * sizeof(double), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(16);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A, dev_MemRef_R, dev_MemRef_Q, p_0, p_1);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   if (p_0 <= 510 && p_1 <= 510) {
+; CODE-NEXT:     {
+; CODE-NEXT:       dim3 k1_dimBlock(32);
+; CODE-NEXT:       dim3 k1_dimGrid(p_1 <= -1048034 ? 32768 : -p_1 + floord(31 * p_1 + 30, 32) + 16);
+; CODE-NEXT:       kernel1 <<<k1_dimGrid, k1_dimBlock>>> (dev_MemRef_A, dev_MemRef_R, dev_MemRef_Q, p_0, p_1);
+; CODE-NEXT:       cudaCheckKernel();
+; CODE-NEXT:     }
+
+; CODE:     {
+; CODE-NEXT:       dim3 k2_dimBlock(16, 32);
+; CODE-NEXT:       dim3 k2_dimGrid(16, p_1 <= -7650 ? 256 : -p_1 + floord(31 * p_1 + 30, 32) + 16);
+; CODE-NEXT:       kernel2 <<<k2_dimGrid, k2_dimBlock>>> (dev_MemRef_A, dev_MemRef_R, dev_MemRef_Q, p_0, p_1);
+; CODE-NEXT:       cudaCheckKernel();
+; CODE-NEXT:     }
+
+; CODE:   }
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (512) * (512) * sizeof(double), cudaMemcpyDeviceToHost));
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(MemRef_R, dev_MemRef_R, (p_0 + 1) * (512) * sizeof(double), cudaMemcpyDeviceToHost));
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(MemRef_Q, dev_MemRef_Q, (512) * (512) * sizeof(double), cudaMemcpyDeviceToHost));
+; CODE-NEXT:     Stmt_for_cond33_preheader();
+
+; CODE: }
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_for_body16(32 * b0 + t0);
+
+; CODE: # kernel1
+; CODE-NEXT: for (int c0 = 0; c0 <= (-p_1 - 32 * b0 + 510) / 1048576; c0 += 1)
+; CODE-NEXT:   for (int c1 = 0; c1 <= 15; c1 += 1) {
+; CODE-NEXT:     if (p_1 + 32 * b0 + t0 + 1048576 * c0 <= 510 && c1 == 0)
+; CODE-NEXT:       Stmt_for_body35(32 * b0 + t0 + 1048576 * c0);
+; CODE-NEXT:     if (p_1 + 32 * b0 + t0 + 1048576 * c0 <= 510)
+; CODE-NEXT:       for (int c3 = 0; c3 <= 31; c3 += 1)
+; CODE-NEXT:         Stmt_for_body42(32 * b0 + t0 + 1048576 * c0, 32 * c1 + c3);
+; CODE-NEXT:     sync0();
+; CODE-NEXT:   }
+
+; CODE: # kernel2
+; CODE-NEXT: for (int c0 = 0; c0 <= (-p_1 - 32 * b0 + 510) / 8192; c0 += 1)
+; CODE-NEXT:   if (p_1 + 32 * b0 + t0 + 8192 * c0 <= 510)
+; CODE-NEXT:     for (int c3 = 0; c3 <= 1; c3 += 1)
+; CODE-NEXT:       Stmt_for_body62(32 * b0 + t0 + 8192 * c0, 32 * b1 + t1 + 16 * c3);
+
+; KERNEL-IR: call void @llvm.nvvm.barrier0()
+
+; Function Attrs: nounwind uwtable
+define internal void @kernel_gramschmidt(i32 %ni, i32 %nj, [512 x double]* %A, [512 x double]* %R, [512 x double]* %Q) #1 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %entry.split, %for.inc86
+  %indvars.iv24 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next25, %for.inc86 ]
+  %indvars.iv19 = phi i64 [ 1, %entry.split ], [ %indvars.iv.next20, %for.inc86 ]
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.cond1.preheader, %for.inc
+  %indvars.iv = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next, %for.inc ]
+  %nrm.02 = phi double [ 0.000000e+00, %for.cond1.preheader ], [ %add, %for.inc ]
+  %arrayidx5 = getelementptr inbounds [512 x double], [512 x double]* %A, i64 %indvars.iv, i64 %indvars.iv24
+  %tmp = load double, double* %arrayidx5, align 8, !tbaa !1
+  %arrayidx9 = getelementptr inbounds [512 x double], [512 x double]* %A, i64 %indvars.iv, i64 %indvars.iv24
+  %tmp27 = load double, double* %arrayidx9, align 8, !tbaa !1
+  %mul = fmul double %tmp, %tmp27
+  %add = fadd double %nrm.02, %mul
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 512
+  br i1 %exitcond, label %for.inc, label %for.end
+
+for.end:                                          ; preds = %for.inc
+  %add.lcssa = phi double [ %add, %for.inc ]
+  %call = tail call double @sqrt(double %add.lcssa) #2
+  %arrayidx13 = getelementptr inbounds [512 x double], [512 x double]* %R, i64 %indvars.iv24, i64 %indvars.iv24
+  store double %call, double* %arrayidx13, align 8, !tbaa !1
+  br label %for.body16
+
+for.cond33.preheader:                             ; preds = %for.body16
+  %indvars.iv.next25 = add nuw nsw i64 %indvars.iv24, 1
+  %cmp347 = icmp slt i64 %indvars.iv.next25, 512
+  br i1 %cmp347, label %for.body35.lr.ph, label %for.inc86
+
+for.body35.lr.ph:                                 ; preds = %for.cond33.preheader
+  br label %for.body35
+
+for.body16:                                       ; preds = %for.end, %for.body16
+  %indvars.iv10 = phi i64 [ 0, %for.end ], [ %indvars.iv.next11, %for.body16 ]
+  %arrayidx20 = getelementptr inbounds [512 x double], [512 x double]* %A, i64 %indvars.iv10, i64 %indvars.iv24
+  %tmp28 = load double, double* %arrayidx20, align 8, !tbaa !1
+  %arrayidx24 = getelementptr inbounds [512 x double], [512 x double]* %R, i64 %indvars.iv24, i64 %indvars.iv24
+  %tmp29 = load double, double* %arrayidx24, align 8, !tbaa !1
+  %div = fdiv double %tmp28, %tmp29
+  %arrayidx28 = getelementptr inbounds [512 x double], [512 x double]* %Q, i64 %indvars.iv10, i64 %indvars.iv24
+  store double %div, double* %arrayidx28, align 8, !tbaa !1
+  %indvars.iv.next11 = add nuw nsw i64 %indvars.iv10, 1
+  %exitcond12 = icmp ne i64 %indvars.iv.next11, 512
+  br i1 %exitcond12, label %for.body16, label %for.cond33.preheader
+
+for.cond33.loopexit:                              ; preds = %for.body62
+  %indvars.iv.next22 = add nuw nsw i64 %indvars.iv21, 1
+  %lftr.wideiv = trunc i64 %indvars.iv.next22 to i32
+  %exitcond23 = icmp ne i32 %lftr.wideiv, 512
+  br i1 %exitcond23, label %for.body35, label %for.cond33.for.inc86_crit_edge
+
+for.body35:                                       ; preds = %for.body35.lr.ph, %for.cond33.loopexit
+  %indvars.iv21 = phi i64 [ %indvars.iv19, %for.body35.lr.ph ], [ %indvars.iv.next22, %for.cond33.loopexit ]
+  %arrayidx39 = getelementptr inbounds [512 x double], [512 x double]* %R, i64 %indvars.iv24, i64 %indvars.iv21
+  store double 0.000000e+00, double* %arrayidx39, align 8, !tbaa !1
+  br label %for.body42
+
+for.cond60.preheader:                             ; preds = %for.body42
+  br label %for.body62
+
+for.body42:                                       ; preds = %for.body35, %for.body42
+  %indvars.iv13 = phi i64 [ 0, %for.body35 ], [ %indvars.iv.next14, %for.body42 ]
+  %arrayidx46 = getelementptr inbounds [512 x double], [512 x double]* %Q, i64 %indvars.iv13, i64 %indvars.iv24
+  %tmp30 = load double, double* %arrayidx46, align 8, !tbaa !1
+  %arrayidx50 = getelementptr inbounds [512 x double], [512 x double]* %A, i64 %indvars.iv13, i64 %indvars.iv21
+  %tmp31 = load double, double* %arrayidx50, align 8, !tbaa !1
+  %mul51 = fmul double %tmp30, %tmp31
+  %arrayidx55 = getelementptr inbounds [512 x double], [512 x double]* %R, i64 %indvars.iv24, i64 %indvars.iv21
+  %tmp32 = load double, double* %arrayidx55, align 8, !tbaa !1
+  %add56 = fadd double %tmp32, %mul51
+  store double %add56, double* %arrayidx55, align 8, !tbaa !1
+  %indvars.iv.next14 = add nuw nsw i64 %indvars.iv13, 1
+  %exitcond15 = icmp ne i64 %indvars.iv.next14, 512
+  br i1 %exitcond15, label %for.body42, label %for.cond60.preheader
+
+for.body62:                                       ; preds = %for.cond60.preheader, %for.body62
+  %indvars.iv16 = phi i64 [ 0, %for.cond60.preheader ], [ %indvars.iv.next17, %for.body62 ]
+  %arrayidx66 = getelementptr inbounds [512 x double], [512 x double]* %A, i64 %indvars.iv16, i64 %indvars.iv21
+  %tmp33 = load double, double* %arrayidx66, align 8, !tbaa !1
+  %arrayidx70 = getelementptr inbounds [512 x double], [512 x double]* %Q, i64 %indvars.iv16, i64 %indvars.iv24
+  %tmp34 = load double, double* %arrayidx70, align 8, !tbaa !1
+  %arrayidx74 = getelementptr inbounds [512 x double], [512 x double]* %R, i64 %indvars.iv24, i64 %indvars.iv21
+  %tmp35 = load double, double* %arrayidx74, align 8, !tbaa !1
+  %mul75 = fmul double %tmp34, %tmp35
+  %sub = fsub double %tmp33, %mul75
+  %arrayidx79 = getelementptr inbounds [512 x double], [512 x double]* %A, i64 %indvars.iv16, i64 %indvars.iv21
+  store double %sub, double* %arrayidx79, align 8, !tbaa !1
+  %indvars.iv.next17 = add nuw nsw i64 %indvars.iv16, 1
+  %exitcond18 = icmp ne i64 %indvars.iv.next17, 512
+  br i1 %exitcond18, label %for.body62, label %for.cond33.loopexit
+
+for.cond33.for.inc86_crit_edge:                   ; preds = %for.cond33.loopexit
+  br label %for.inc86
+
+for.inc86:                                        ; preds = %for.cond33.for.inc86_crit_edge, %for.cond33.preheader
+  %indvars.iv.next20 = add nuw nsw i64 %indvars.iv19, 1
+  %exitcond26 = icmp ne i64 %indvars.iv.next25, 512
+  br i1 %exitcond26, label %for.cond1.preheader, label %for.end88
+
+for.end88:                                        ; preds = %for.inc86
+  ret void
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end(i64, i8* nocapture) #0
+
+; Function Attrs: nounwind
+declare double @sqrt(double) #2
+
+attributes #0 = { argmemonly nounwind }
+attributes #1 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.9.0 (trunk 275267) (llvm/trunk 275268)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"double", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/GPGPU/ignore-parameter-bounds.ll b/final/test/GPGPU/ignore-parameter-bounds.ll
new file mode 100644
index 0000000..638c1ea
--- /dev/null
+++ b/final/test/GPGPU/ignore-parameter-bounds.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; REQUIRES: pollyacc
+
+; CODE: Code
+; CODE: ====
+; CODE: No code generated
+
+source_filename = "bugpoint-output-83bcdeb.bc"
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+@__data_radiation_MOD_cobi = external global [168 x double], align 32
+
+; Function Attrs: nounwind uwtable
+define void @__radiation_rg_MOD_coe_so() #0 {
+entry:
+  %polly.access.kspec.load = load i32, i32* undef, align 4
+  %0 = or i1 undef, undef
+  br label %polly.preload.cond29
+
+polly.preload.cond29:                             ; preds = %entry
+  br i1 %0, label %polly.preload.exec31, label %polly.preload.merge30
+
+polly.preload.merge30:                            ; preds = %polly.preload.exec31, %polly.preload.cond29
+  %polly.preload..merge32 = phi double [ %polly.access.__data_radiation_MOD_cobi.load, %polly.preload.exec31 ], [ 0.000000e+00, %polly.preload.cond29 ]
+  ret void
+
+polly.preload.exec31:                             ; preds = %polly.preload.cond29
+  %1 = sext i32 %polly.access.kspec.load to i64
+  %2 = mul nsw i64 7, %1
+  %3 = add nsw i64 0, %2
+  %4 = add nsw i64 %3, 48
+  %polly.access.__data_radiation_MOD_cobi = getelementptr double, double* getelementptr inbounds ([168 x double], [168 x double]* @__data_radiation_MOD_cobi, i32 0, i32 0), i64 %4
+  %polly.access.__data_radiation_MOD_cobi.load = load double, double* %polly.access.__data_radiation_MOD_cobi, align 8
+  br label %polly.preload.merge30
+}
+
+attributes #0 = { nounwind uwtable }
diff --git a/final/test/GPGPU/intrinsic-copied-into-kernel.ll b/final/test/GPGPU/intrinsic-copied-into-kernel.ll
new file mode 100644
index 0000000..402a70c
--- /dev/null
+++ b/final/test/GPGPU/intrinsic-copied-into-kernel.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s --check-prefix=SCOP
+; RUN: opt %loadPolly -analyze -polly-codegen-ppcg -polly-acc-dump-kernel-ir < %s | FileCheck %s --check-prefix=KERNEL-IR
+; RUN: opt %loadPolly -S -polly-codegen-ppcg  < %s | FileCheck %s --check-prefix=HOST-IR
+
+; Test that we do recognise and codegen a kernel that has intrinsics.
+
+; REQUIRES: pollyacc
+
+; Check that we model the kernel as a scop.
+; SCOP:      Function: f
+; SCOP-NEXT:       Region: %entry.split---%for.end
+
+; Check that the intrinsic call is present in the kernel IR.
+; KERNEL-IR:   %p_sqrt = tail call float @llvm.sqrt.f32(float %A.arr.i.val_p_scalar_)
+; KERNEL-IR:   declare float @llvm.sqrt.f32(float)
+; KERNEL-IR:   declare float @llvm.fabs.f32(float)
+
+
+; Check that kernel launch is generated in host IR.
+; the declare would not be generated unless a call to a kernel exists.
+; HOST-IR: declare void @polly_launchKernel(i8*, i32, i32, i32, i32, i32, i8*)
+
+
+; void f(float *A, float *B, int N) {
+;   for(int i = 0; i < N; i++) {
+;       float tmp0 = A[i];
+;       float tmp1 = sqrt(tmp1);
+;       float tmp2 = fabs(tmp2);
+;       float tmp3 = copysignf(tmp1, tmp2);
+;       B[i] = tmp4;
+;   }
+; }
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(float* %A, float* %B, i32 %N) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %cmp1 = icmp sgt i32 %N, 0
+  br i1 %cmp1, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.lr.ph, %for.body
+  %indvars.iv = phi i64 [ 0, %for.body.lr.ph ], [ %indvars.iv.next, %for.body ]
+  %A.arr.i = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %A.arr.i.val = load float, float* %A.arr.i, align 4
+  ; Call to intrinsics that should be part of the kernel.
+  %sqrt = tail call float @llvm.sqrt.f32(float %A.arr.i.val)
+  %fabs = tail call float @llvm.fabs.f32(float %sqrt);
+  %copysign = tail call float @llvm.copysign.f32(float %sqrt, float %fabs);
+  %B.arr.i = getelementptr inbounds float, float* %B, i64 %indvars.iv
+  store float %copysign, float* %B.arr.i, align 4
+
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %wide.trip.count = zext i32 %N to i64
+  %exitcond = icmp ne i64 %indvars.iv.next, %wide.trip.count
+  br i1 %exitcond, label %for.body, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  ret void
+}
+
+; Function Attrs: nounwind readnone
+declare float @llvm.sqrt.f32(float) #0
+declare float @llvm.fabs.f32(float) #0
+declare float @llvm.copysign.f32(float, float) #0
+
+attributes #0 = { nounwind readnone }
+
diff --git a/final/test/GPGPU/invalid-kernel-assert-verifymodule.ll b/final/test/GPGPU/invalid-kernel-assert-verifymodule.ll
new file mode 100644
index 0000000..7bc1436
--- /dev/null
+++ b/final/test/GPGPU/invalid-kernel-assert-verifymodule.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg  -polly-acc-fail-on-verify-module-failure \
+; RUN: -disable-output < %s
+
+; Make sure that if -polly-acc-fail-on-verify-module-failure is on, we actually
+; fail on an illegal module.
+
+; REQUIRES: pollyacc, asserts
+; XFAIL: *
+;
+;    void foo(long A[1024], long B[1024]) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += (B[i] + (long)&B[i]);
+;    }
+
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -S < %s 
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64* %A, i64* %B) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb10, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp11, %bb10 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb12
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i64, i64* %B, i64 %i.0
+  %tmp3 = load i64, i64* %tmp, align 8
+  %tmp4 = getelementptr inbounds i64, i64* %B, i64 %i.0
+  %tmp5 = ptrtoint i64* %tmp4 to i64
+  %tmp6 = add nsw i64 %tmp3, %tmp5
+  %tmp7 = getelementptr inbounds i64, i64* %A, i64 %i.0
+  %tmp8 = load i64, i64* %tmp7, align 8
+  %tmp9 = add nsw i64 %tmp8, %tmp6
+  store i64 %tmp9, i64* %tmp7, align 8
+  br label %bb10
+
+bb10:                                             ; preds = %bb2
+  %tmp11 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb12:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/GPGPU/invalid-kernel.ll b/final/test/GPGPU/invalid-kernel.ll
new file mode 100644
index 0000000..ad5e00e
--- /dev/null
+++ b/final/test/GPGPU/invalid-kernel.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -disable-output < %s | \
+; RUN: not FileCheck %s -check-prefix=KERNEL-IR
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -S < %s | \
+; RUN: FileCheck %s -check-prefix=IR
+
+; REQUIRES: pollyacc
+;
+;    void foo(long A[1024], long B[1024]) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += (B[i] + (long)&B[i]);
+;    }
+
+; This kernel loads/stores a pointer address we model. This is a rare case,
+; were we still lack proper code-generation support. We check here that we
+; detect the invalid IR and bail out gracefully.
+
+; CODE:        cudaCheckReturn(cudaMemcpy(dev_MemRef_B, MemRef_B, (1024) * sizeof(i64), cudaMemcpyHostToDevice));
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (1024) * sizeof(i64), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(32);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_B, dev_MemRef_A);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (1024) * sizeof(i64), cudaMemcpyDeviceToHost));
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_bb2(32 * b0 + t0);
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -S < %s | \
+; RUN: FileCheck %s -check-prefix=IR
+
+; KERNEL-IR: kernel
+
+; IR: br i1 false, label %polly.start, label %bb1
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64* %A, i64* %B) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb10, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp11, %bb10 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb12
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i64, i64* %B, i64 %i.0
+  %tmp3 = load i64, i64* %tmp, align 8
+  %tmp4 = getelementptr inbounds i64, i64* %B, i64 %i.0
+  %tmp5 = ptrtoint i64* %tmp4 to i64
+  %tmp6 = add nsw i64 %tmp3, %tmp5
+  %tmp7 = getelementptr inbounds i64, i64* %A, i64 %i.0
+  %tmp8 = load i64, i64* %tmp7, align 8
+  %tmp9 = add nsw i64 %tmp8, %tmp6
+  store i64 %tmp9, i64* %tmp7, align 8
+  br label %bb10
+
+bb10:                                             ; preds = %bb2
+  %tmp11 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb12:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/GPGPU/invariant-load-array-access.ll b/final/test/GPGPU/invariant-load-array-access.ll
new file mode 100644
index 0000000..792b2ae
--- /dev/null
+++ b/final/test/GPGPU/invariant-load-array-access.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -analyze -polly-scops \
+; RUN: -polly-invariant-load-hoisting < %s| FileCheck %s -check-prefix=SCOP
+
+; RUN: opt %loadPolly -S -polly-codegen-ppcg \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=HOST-IR
+
+
+; REQUIRES: pollyacc
+
+; Check that we detect a scop.
+; SCOP:      Function: f
+; SCOP-NEXT: Region: %for.body---%for.end
+; SCOP-NEXT: Max Loop Depth:  1
+; SCOP-NEXT: Invariant Accesses: {
+; SCOP-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:             [tmp] -> { Stmt_for_body[i0] -> MemRef_control[0] };
+; SCOP-NEXT:         Execution Context: [tmp] -> {  :  }
+; SCOP-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:             [tmp] -> { Stmt_if_then[i0] -> MemRef_readarr[0] };
+; SCOP-NEXT:         Execution Context: [tmp] -> {  : tmp >= 4 }
+; SCOP-NEXT: }
+
+; Check that kernel launch is generated in host IR.
+; the declare would not be generated unless a call to a kernel exists.
+; HOST-IR: declare void @polly_launchKernel(i8*, i32, i32, i32, i32, i32, i8*)
+
+; This test makes sure that such an access pattern is handled correctly
+; by PPCGCodeGeneration. It appears that not calling `preloadInvariantLoads`
+; was the main reason that caused this test case to crash.
+;
+; void f(int *arr, const int *control, const int *readarr) {
+;     for(int i = 0; i < 1000; i++) {
+;         int t = 0;
+;         if (*control > 3) {
+;             t += *readarr;
+;         }
+;         arr[i] = t;
+;     }
+; }
+
+
+target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"
+target triple = "i386-apple-macosx10.12.0"
+define void @f(i32* %arr, i32* %control, i32* %readarr) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %if.end
+  %i.01 = phi i32 [ 0, %entry.split ], [ %inc, %if.end ]
+  %tmp = load i32, i32* %control, align 4
+  %cmp1 = icmp sgt i32 %tmp, 3
+  br i1 %cmp1, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %tmp1 = load i32, i32* %readarr, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  %t.0 = phi i32 [ %tmp1, %if.then ], [ 0, %for.body ]
+  %arrayidx = getelementptr inbounds i32, i32* %arr, i32 %i.01
+  store i32 %t.0, i32* %arrayidx, align 4
+  %inc = add nuw nsw i32 %i.01, 1
+  %exitcond = icmp eq i32 %inc, 1000
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %if.end
+  ret void
+}
diff --git a/final/test/GPGPU/invariant-load-escaping-values.ll b/final/test/GPGPU/invariant-load-escaping-values.ll
new file mode 100644
index 0000000..b4898ab
--- /dev/null
+++ b/final/test/GPGPU/invariant-load-escaping-values.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -S -polly-codegen-ppcg \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s
+
+; REQUIRES: pollyacc
+
+; CHECK: store i64 %polly.access.B.load, i64* %invariant.preload.s2a
+; CHECK: %invariant.final_reload = load i64, i64* %invariant.preload.s2a
+
+; Verify that the final reload of an invariant scalar memory access uses the
+; same stack slot that into which the invariant memory access was stored
+; originally. Earlier, this was broken as we introduce a new stack slot aside
+; of the preload stack slot, which remained uninitialized and caused our escaping
+; loads to contain garbage.
+
+define i64 @foo(float* %A, i64* %B) {
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %entry], [%indvar.next, %loop]
+  %indvar.next = add nsw i64 %indvar, 1
+  %idx = getelementptr float, float* %A, i64 %indvar
+  store float 42.0, float* %idx
+  %invariant = load i64, i64* %B
+  %cmp = icmp sle i64 %indvar, 1024
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret i64 %invariant
+}
diff --git a/final/test/GPGPU/invariant-load-hoisting-of-array.ll b/final/test/GPGPU/invariant-load-hoisting-of-array.ll
new file mode 100644
index 0000000..3aaa4ae
--- /dev/null
+++ b/final/test/GPGPU/invariant-load-hoisting-of-array.ll
@@ -0,0 +1,102 @@
+; RUN: opt %loadPolly -analyze -polly-scops \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=SCOP
+
+; RUN: opt %loadPolly -S -polly-codegen-ppcg \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=HOST-IR
+
+; REQUIRES: pollyacc
+
+; Entry: Contains (%loaded.ptr.preload.s2a = alloca double*) which is
+;   |    invariant load hoisted `%loaded.ptr`
+;   v
+; Run-time check --(failure branch)--> { old code - contains `%loaded.ptr` }
+;   |
+;  (success branch)
+;   |
+;   v
+; New Code: Should refer to `%loaded.ptr.preload.s2a`, which is
+;           the invariant load hoisted value, NOT `%loaded.ptr`.
+
+; In Polly, we preserve the old code and create a separate branch that executes
+; the GPU code if a run-time check succeeds.
+
+; We need to make sure that in the new branch, we pick up invariant load hoisted
+; values. The old values will belong to the old code branch.
+
+; In this case, we use to try to load the 'original' %loaded.ptr in the
+; 'New Code' branch,which is wrong. Check that this does not happen.
+
+; Check that we have a Scop with an invariant load of the array.
+; SCOP:       Function: f
+; SCOP-NEXT:  Region: %arrload---%for.exit
+; SCOP-NEXT:  Max Loop Depth:  1
+; SCOP-NEXT:  Invariant Accesses: {
+; SCOP-NEXT:          ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:              { Stmt_arrload[] -> MemRef_arr_of_ptrs[0] };
+
+
+
+; Check that we have the preloaded array.
+; HOST-IR: entry:
+; HOST-IR-NEXT:  %loaded.ptr.preload.s2a = alloca double*
+
+; Chek that we store the correct value in the preload.
+; polly.preload.begin:                              ; preds = %polly.split_new_and_old
+; HOST-IR: %polly.access.arr.of.ptrs = getelementptr double*, double** %arr.of.ptrs, i64 0
+; HOST-IR-NEXT: %polly.access.arr.of.ptrs.load = load double*, double** %polly.access.arr.of.ptrs
+; HOST-IR-NEXT: store double* %polly.access.arr.of.ptrs.load, double** %loaded.ptr.preload.s2a
+
+; Check that we get back data from the kernel.
+; HOST-IR: polly.acc.initialize:                             ; preds = %polly.start
+; HOST-IR: [[FIRSTINDEX:%.+]] = getelementptr double, double* %polly.access.arr.of.ptrs.load, i64 1
+; HOST-IR: [[BITCASTED:%.+]] = bitcast double* [[FIRSTINDEX]] to i8*
+; HOST-IR: call void @polly_copyFromDeviceToHost(i8* %p_dev_array_MemRef_loaded_ptr, i8* [[BITCASTED]], i64 800)
+
+; Check that the kernel launch is generated in the host IR.
+; This declaration would not have been generated unless a kernel launch exists.
+; HOST-IR: declare void @polly_launchKernel(i8*, i32, i32, i32, i32, i32, i8*)
+
+
+; C pseudocode equivalent
+; void f(double **arr_of_ptrs) {
+;     double *loaded_ptr = arr_of_ptrs[0];
+;     if (false) { return; }
+;     else {
+;         for(int i = 1; i < 100; i++) {
+;             loaded_ptr[i] = 42.0;
+;         }
+;     }
+; }
+
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+
+; Function Attrs: nounwind uwtable
+define void @f(double **%arr.of.ptrs) #0 {
+entry:
+  br label %arrload
+
+arrload:                                             ; preds = %"7"
+  %loaded.ptr = load double*, double** %arr.of.ptrs, align 8
+  br i1 false, label %"for.exit", label %"for.preheader"
+
+"for.preheader":                                       ; preds = %"51"
+  br label %"for.body"
+
+"for.body":                                             ; preds = %"53", %"53.lr.ph"
+  %indvar = phi i64 [ 1, %"for.preheader" ], [ %indvar.next, %"for.body" ]
+  %slot = getelementptr double, double* %loaded.ptr, i64 %indvar
+  store double 42.0, double* %slot, align 8
+
+  %indvar.next = add nuw nsw i64 %indvar, 1
+
+  %check = icmp sgt i64 %indvar.next, 100
+  br i1 %check, label %"for.exit", label %"for.body"
+
+"for.exit":                                             ; preds = %"52.54_crit_edge", %"51"
+    ret void
+}
+
+attributes #0 = { nounwind uwtable }
diff --git a/final/test/GPGPU/invariant-load-hoisting-read-in-kernel.ll b/final/test/GPGPU/invariant-load-hoisting-read-in-kernel.ll
new file mode 100644
index 0000000..4277237
--- /dev/null
+++ b/final/test/GPGPU/invariant-load-hoisting-read-in-kernel.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -disable-output -polly-acc-dump-kernel-ir \
+; RUN: -polly-codegen-ppcg -polly-scops \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s
+
+; REQUIRES: pollyacc
+
+; Verify that invariant loads used in a kernel statement are correctly forwarded
+; as subtree value to the GPU kernel.
+
+; CHECK:  define ptx_kernel void @FUNC_foo_SCOP_0_KERNEL_0({{.*}} float %polly.access.p.load)
+; CHECK:   store float %polly.access.p.load, float* %indvar2f.phiops
+
+define void @foo(float* %A, float* %p) {
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %entry], [%indvar.next, %loop]
+  %indvar.next = add i64 %indvar, 1
+  %invariant = load float, float* %p
+  %ptr = getelementptr float, float* %A, i64 %indvar
+  store float 42.0, float* %ptr
+  %cmp = icmp sle i64 %indvar, 1024
+  br i1 %cmp, label %loop, label %loop2
+
+loop2:
+  %indvar2 = phi i64 [0, %loop], [%indvar2.next, %loop2]
+  %indvar2f = phi float [%invariant, %loop], [%indvar2f, %loop2]
+  %indvar2.next = add i64 %indvar2, 1
+  store float %indvar2f, float* %A
+  %cmp2 = icmp sle i64 %indvar2, 1024
+  br i1 %cmp2, label %loop2, label %end
+
+end:
+  ret void
+
+}
diff --git a/final/test/GPGPU/invariant-load-hoisting-with-variable-bounds.ll b/final/test/GPGPU/invariant-load-hoisting-with-variable-bounds.ll
new file mode 100644
index 0000000..4b6db51
--- /dev/null
+++ b/final/test/GPGPU/invariant-load-hoisting-with-variable-bounds.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -analyze -polly-use-llvm-names -polly-scops \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=SCOP
+
+
+; RUN: opt %loadPolly -S -polly-use-llvm-names -polly-codegen-ppcg \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=HOST-IR
+
+; REQUIRES: pollyacc
+
+; SCOP:      Function: f
+; SCOP-NEXT: Region: %entry.split---%for.end
+; SCOP-NEXT: Max Loop Depth:  1
+; SCOP-NEXT: Invariant Accesses: {
+; SCOP-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:             [tmp1, tmp4] -> { Stmt_entry_split[] -> MemRef_begin[0] };
+; SCOP-NEXT:         Execution Context: [tmp1, tmp4] -> {  :  }
+; SCOP-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:             [tmp1, tmp4] -> { Stmt_for_body[i0] -> MemRef_end[0] };
+; SCOP-NEXT:         Execution Context: [tmp1, tmp4] -> {  :  }
+; SCOP-NEXT: }
+
+
+; Check that the kernel launch is generated in the host IR.
+; This declaration would not have been generated unless a kernel launch exists.
+; HOST-IR: declare void @polly_launchKernel(i8*, i32, i32, i32, i32, i32, i8*)
+
+;    void f(int *begin, int *end, int *arr) {
+;      for (int i = *begin; i < *end; i++) {
+;        arr[i] = 0;
+;      }
+;    }
+;
+
+target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"
+
+define void @f(i32* %begin, i32* %end, i32* %arr) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %tmp1 = load i32, i32* %begin, align 4
+  %tmp41 = load i32, i32* %end, align 4
+  %cmp2 = icmp slt i32 %tmp1, %tmp41
+  br i1 %cmp2, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.lr.ph, %for.body
+  %i.03 = phi i32 [ %tmp1, %for.body.lr.ph ], [ %inc, %for.body ]
+  %arrayidx = getelementptr inbounds i32, i32* %arr, i32 %i.03
+  store i32 0, i32* %arrayidx, align 4
+  %inc = add nsw i32 %i.03, 1
+  %tmp4 = load i32, i32* %end, align 4
+  %cmp = icmp slt i32 %inc, %tmp4
+  br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  ret void
+}
diff --git a/final/test/GPGPU/invariant-load-hoisting-with-variable-lower-bound.ll b/final/test/GPGPU/invariant-load-hoisting-with-variable-lower-bound.ll
new file mode 100644
index 0000000..547aa8b
--- /dev/null
+++ b/final/test/GPGPU/invariant-load-hoisting-with-variable-lower-bound.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -analyze -polly-use-llvm-names -polly-scops \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=SCOP
+
+
+; RUN: opt %loadPolly -S -polly-use-llvm-names -polly-codegen-ppcg \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=HOST-IR
+
+; REQUIRES: pollyacc
+
+; Check that we detect a scop with invariant accesses.
+; SCOP:      Function: f
+; SCOP-NEXT: Region: %entry.split---%for.end
+; SCOP-NEXT: Max Loop Depth:  1
+; SCOP-NEXT: Invariant Accesses: {
+; SCOP-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:             [beginval] -> { Stmt_entry_split[] -> MemRef_begin[0] };
+; SCOP-NEXT:         Execution Context: [beginval] -> {  :  }
+; SCOP-NEXT: }
+
+; Check that the kernel launch is generated in the host IR.
+; This declaration would not have been generated unless a kernel launch exists.
+; HOST-IR: declare void @polly_launchKernel(i8*, i32, i32, i32, i32, i32, i8*)
+
+; 
+; void f(int *begin, int *arr) {
+;     for (int i = *begin; i < 100; i++) {
+;         arr[i] = 0;
+;     }
+; }
+
+target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"
+
+define void @f(i32* %begin, i32* %arr) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %beginval = load i32, i32* %begin, align 4
+  %cmp1 = icmp slt i32 %beginval, 100
+  br i1 %cmp1, label %for.body, label %for.end
+
+
+
+for.body:                                         ; preds = %for.body.lr.ph, %for.body
+  %ival = phi i32 [ %beginval, %entry.split ], [ %inc, %for.body ]
+  %arrayidx = getelementptr inbounds i32, i32* %arr, i32 %ival
+  store i32 0, i32* %arrayidx, align 4
+  %inc = add nsw i32 %ival, 1
+  %cmp = icmp slt i32 %ival, 99
+  br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  ret void
+}
diff --git a/final/test/GPGPU/invariant-load-hoisting-with-variable-upper-bound.ll b/final/test/GPGPU/invariant-load-hoisting-with-variable-upper-bound.ll
new file mode 100644
index 0000000..ab5be4f
--- /dev/null
+++ b/final/test/GPGPU/invariant-load-hoisting-with-variable-upper-bound.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -analyze -polly-use-llvm-names -polly-scops -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=SCOP
+; RUN: opt %loadPolly -S -polly-use-llvm-names -polly-codegen-ppcg -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=HOST-IR
+
+; REQUIRES: pollyacc
+
+; Check that we detect a scop with invariant accesses.
+; SCOP:      Function: f
+; SCOP-NEXT: Region: %entry.split---%for.end
+; SCOP-NEXT: Max Loop Depth:  1
+; SCOP-NEXT: Invariant Accesses: {
+; SCOP-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:             [tmp2] -> { Stmt_for_body[i0] -> MemRef_idx[0] };
+; SCOP-NEXT:         Execution Context: [tmp2] -> {  :  }
+; SCOP-NEXT: }
+
+; Check that kernel launch is generated in host IR.
+; the declare would not be generated unless a call to a kernel exists.
+; HOST-IR: declare void @polly_launchKernel(i8*, i32, i32, i32, i32, i32, i8*)
+
+; Check if we generate GPU code for simple loop with variable upper bound.
+; This always worked, but have this test to prevent regressions.
+;    void f(int *idx, int *arr) {
+;      for (int i = 0; i < *idx; i++) {
+;        arr[i] = 0;
+;      }
+;    }
+;
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %idx, i32* %arr) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %tmp21 = load i32, i32* %idx, align 4
+  %cmp2 = icmp sgt i32 %tmp21, 0
+  br i1 %cmp2, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.lr.ph, %for.body
+  %indvars.iv = phi i64 [ 0, %for.body.lr.ph ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds i32, i32* %arr, i64 %indvars.iv
+  store i32 0, i32* %arrayidx, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %tmp2 = load i32, i32* %idx, align 4
+  %0 = sext i32 %tmp2 to i64
+  %cmp = icmp slt i64 %indvars.iv.next, %0
+  br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  ret void
+}
diff --git a/final/test/GPGPU/invariant-load-hoisting.ll b/final/test/GPGPU/invariant-load-hoisting.ll
new file mode 100644
index 0000000..110c34d
--- /dev/null
+++ b/final/test/GPGPU/invariant-load-hoisting.ll
@@ -0,0 +1,118 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=SCOP
+;
+; RUN: opt %loadPolly -polly-scops -S  -polly-invariant-load-hoisting \
+; RUN: -polly-codegen-ppcg < %s | FileCheck %s -check-prefix=HOST-IR
+;
+; RUN: opt %loadPolly -polly-scops -analyze  -polly-invariant-load-hoisting \
+; RUN: -polly-codegen-ppcg -polly-acc-dump-kernel-ir < %s | FileCheck %s -check-prefix=KERNEL-IR
+;
+; REQUIRES: pollyacc
+;
+; SCOP:       Function: f
+; SCOP-NEXT:  Region: %entry.split---%for.end26
+; SCOP-NEXT:  Max Loop Depth:  3
+; SCOP-NEXT:  Invariant Accesses: {
+; SCOP-NEXT:          ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:              [n, tmp12] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_invariant[0] };
+; SCOP-NEXT:          Execution Context: [n, tmp12] -> {  : n > 0 }
+; SCOP-NEXT:  }
+; HOST-IR:      call void @polly_launchKernel(i8* %[[REGC:[0-9]+]], i32 %{{[0-9]+}}, i32 1, i32 32, i32 1, i32 1, i8* %polly_launch_0_params_i8ptr)
+; HOST-IR-NEXT: call void @polly_freeKernel(i8* %[[REGC]])
+
+; KERNEL-IR: define ptx_kernel void @FUNC_f_SCOP_0_KERNEL_0(i8 addrspace(1)* %MemRef_B, i8 addrspace(1)* %MemRef_A, i32 %n, i32 %tmp12, i32 %polly.preload.tmp21.merge)
+
+
+; Check that we generate correct GPU code in case of invariant load hoisting.
+;
+;
+;    static const int N = 3000;
+;
+;    void f(int A[N][N], int *invariant, int B[N][N], int n) {
+;      for (int i = 0; i < n; i++) {
+;        for (int j = 0; j < n; j++) {
+;          for (int k = 0; k < n; k++) {
+;
+;            A[*invariant][k] = B[k][k];
+;            A[k][*invariant] += B[k][k];
+;          }
+;        }
+;      }
+;    }
+;
+
+define void @f([3000 x i32]* %A, i32* %invariant, [3000 x i32]* %B, i32 %n) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %cmp6 = icmp sgt i32 %n, 0
+  br i1 %cmp6, label %for.cond1.preheader.lr.ph, label %for.end26
+
+for.cond1.preheader.lr.ph:                        ; preds = %entry.split
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.cond1.preheader.lr.ph, %for.inc24
+  %i.07 = phi i32 [ 0, %for.cond1.preheader.lr.ph ], [ %inc25, %for.inc24 ]
+  %cmp23 = icmp sgt i32 %n, 0
+  br i1 %cmp23, label %for.cond4.preheader.lr.ph, label %for.inc24
+
+for.cond4.preheader.lr.ph:                        ; preds = %for.cond1.preheader
+  br label %for.cond4.preheader
+
+for.cond4.preheader:                              ; preds = %for.cond4.preheader.lr.ph, %for.inc21
+  %j.04 = phi i32 [ 0, %for.cond4.preheader.lr.ph ], [ %inc22, %for.inc21 ]
+  %cmp51 = icmp sgt i32 %n, 0
+  br i1 %cmp51, label %for.body6.lr.ph, label %for.inc21
+
+for.body6.lr.ph:                                  ; preds = %for.cond4.preheader
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6.lr.ph, %for.body6
+  %k.02 = phi i32 [ 0, %for.body6.lr.ph ], [ %inc, %for.body6 ]
+  %idxprom = sext i32 %k.02 to i64
+  %idxprom7 = sext i32 %k.02 to i64
+  %arrayidx8 = getelementptr inbounds [3000 x i32], [3000 x i32]* %B, i64 %idxprom, i64 %idxprom7
+  %tmp9 = load i32, i32* %arrayidx8, align 4
+  %tmp12 = load i32, i32* %invariant, align 4
+  %idxprom9 = sext i32 %tmp12 to i64
+  %idxprom11 = sext i32 %k.02 to i64
+  %arrayidx12 = getelementptr inbounds [3000 x i32], [3000 x i32]* %A, i64 %idxprom9, i64 %idxprom11
+  store i32 %tmp9, i32* %arrayidx12, align 4
+  %idxprom13 = sext i32 %k.02 to i64
+  %idxprom15 = sext i32 %k.02 to i64
+  %arrayidx16 = getelementptr inbounds [3000 x i32], [3000 x i32]* %B, i64 %idxprom13, i64 %idxprom15
+  %tmp17 = load i32, i32* %arrayidx16, align 4
+  %idxprom17 = sext i32 %k.02 to i64
+  %tmp21 = load i32, i32* %invariant, align 4
+  %idxprom19 = sext i32 %tmp21 to i64
+  %arrayidx20 = getelementptr inbounds [3000 x i32], [3000 x i32]* %A, i64 %idxprom17, i64 %idxprom19
+  %tmp22 = load i32, i32* %arrayidx20, align 4
+  %add = add nsw i32 %tmp22, %tmp17
+  store i32 %add, i32* %arrayidx20, align 4
+  %inc = add nuw nsw i32 %k.02, 1
+  %cmp5 = icmp slt i32 %inc, %n
+  br i1 %cmp5, label %for.body6, label %for.cond4.for.inc21_crit_edge
+
+for.cond4.for.inc21_crit_edge:                    ; preds = %for.body6
+  br label %for.inc21
+
+for.inc21:                                        ; preds = %for.cond4.for.inc21_crit_edge, %for.cond4.preheader
+  %inc22 = add nuw nsw i32 %j.04, 1
+  %cmp2 = icmp slt i32 %inc22, %n
+  br i1 %cmp2, label %for.cond4.preheader, label %for.cond1.for.inc24_crit_edge
+
+for.cond1.for.inc24_crit_edge:                    ; preds = %for.inc21
+  br label %for.inc24
+
+for.inc24:                                        ; preds = %for.cond1.for.inc24_crit_edge, %for.cond1.preheader
+  %inc25 = add nuw nsw i32 %i.07, 1
+  %cmp = icmp slt i32 %inc25, %n
+  br i1 %cmp, label %for.cond1.preheader, label %for.cond.for.end26_crit_edge
+
+for.cond.for.end26_crit_edge:                     ; preds = %for.inc24
+  br label %for.end26
+
+for.end26:                                        ; preds = %for.cond.for.end26_crit_edge, %entry.split
+  ret void
+}
diff --git a/final/test/GPGPU/invariant-load-of-scalar.ll b/final/test/GPGPU/invariant-load-of-scalar.ll
new file mode 100644
index 0000000..900bdac
--- /dev/null
+++ b/final/test/GPGPU/invariant-load-of-scalar.ll
@@ -0,0 +1,84 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting \
+; RUN: -analyze < %s | \
+; RUN: FileCheck -check-prefix=SCOP %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-invariant-load-hoisting \
+; RUN: -S < %s | \
+; RUN: FileCheck -check-prefix=HOST-IR %s
+
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-invariant-load-hoisting \
+; RUN: -disable-output -polly-acc-dump-kernel-ir < %s | \
+; RUN: FileCheck -check-prefix=KERNEL-IR %s
+
+; REQUIRES: pollyacc
+
+; Check that we offload invariant loads of scalars correctly.
+
+; Check that invariant loads are present.
+; SCOP:      Function: checkPrivatization
+; SCOP-NEXT: Region: %entry.split---%for.end
+; SCOP-NEXT: Max Loop Depth:  1
+; SCOP-NEXT: Invariant Accesses: {
+; SCOP-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:             [tmp, tmp2] -> { Stmt_entry_split[] -> MemRef_begin[0] };
+; SCOP-NEXT:         Execution Context: [tmp, tmp2] -> {  :  }
+; SCOP-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:             [tmp, tmp2] -> { Stmt_for_body[i0] -> MemRef_end[0] };
+; SCOP-NEXT:         Execution Context: [tmp, tmp2] -> {  :  }
+; SCOP-NEXT: }
+;
+
+; Check that we do not actually allocate arrays for %begin, %end, since they are
+; invariant load hoisted.
+; HOST-IR: %p_dev_array_MemRef_A = call i8* @polly_allocateMemoryForDevice
+; HOST-IR-NOT: call i8* @polly_allocateMemoryForDevice
+
+; Check that we send the invariant loaded scalars as parameters to the
+; kernel function.
+; KERNEL-IR: define ptx_kernel void @FUNC_checkPrivatization_SCOP_0_KERNEL_0
+; KERNEL-IR-SAME: (i8 addrspace(1)* %MemRef_A, i32 %tmp,
+; KERNEL-IR-SAME: i32 %tmp2, i32 %polly.access.begin.load,
+; KERNEL-IR-SAME: i32 %polly.access.end.load)
+
+
+; void checkScalarPointerOffload(int A[], int *begin, int *end) {
+;     for(int i = *begin; i < *end; i++) {
+;         A[i] = 10;
+;     }
+; }
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.12.0"
+
+define void @checkPrivatization(i32* %A, i32* %begin, i32* %end) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %tmp = load i32, i32* %begin, align 4
+  %tmp21 = load i32, i32* %end, align 4
+  %cmp3 = icmp slt i32 %tmp, %tmp21
+  br i1 %cmp3, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  %tmp1 = sext i32 %tmp to i64
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.lr.ph, %for.body
+  %indvars.iv4 = phi i64 [ %tmp1, %for.body.lr.ph ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv4
+  store i32 10, i32* %arrayidx, align 4
+  %indvars.iv.next = add i64 %indvars.iv4, 1
+  %tmp2 = load i32, i32* %end, align 4
+  %tmp3 = sext i32 %tmp2 to i64
+  %cmp = icmp slt i64 %indvars.iv.next, %tmp3
+  br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  ret void
+}
+
diff --git a/final/test/GPGPU/kernel-params-only-some-arrays.ll b/final/test/GPGPU/kernel-params-only-some-arrays.ll
new file mode 100644
index 0000000..6f28b7b
--- /dev/null
+++ b/final/test/GPGPU/kernel-params-only-some-arrays.ll
@@ -0,0 +1,106 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=KERNEL %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg \
+; RUN: -S < %s | \
+; RUN: FileCheck -check-prefix=IR %s
+
+; REQUIRES: pollyacc
+;
+;    void kernel_params_only_some_arrays(float A[], float B[]) {
+;      for (long i = 0; i < 32; i++)
+;        A[i] += 42;
+;
+;      for (long i = 0; i < 32; i++)
+;        B[i] += 42;
+;    }
+
+; KERNEL: ; ModuleID = 'FUNC_kernel_params_only_some_arrays_SCOP_0_KERNEL_0'
+; KERNEL-NEXT: source_filename = "FUNC_kernel_params_only_some_arrays_SCOP_0_KERNEL_0"
+; KERNEL-NEXT: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
+; KERNEL-NEXT: target triple = "nvptx64-nvidia-cuda"
+
+; KERNEL: define ptx_kernel void @FUNC_kernel_params_only_some_arrays_SCOP_0_KERNEL_0(i8 addrspace(1)* %MemRef_B)
+; KERNEL-NEXT:   entry:
+; KERNEL-NEXT:     %0 = call i32 @llvm.nvvm.read.ptx.sreg.ctaid.x()
+; KERNEL-NEXT:     %b0 = zext i32 %0 to i64
+; KERNEL-NEXT:     %1 = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
+; KERNEL-NEXT:     %t0 = zext i32 %1 to i64
+
+; KERNEL:     ret void
+; KERNEL-NEXT: }
+
+; KERNEL: ; ModuleID = 'FUNC_kernel_params_only_some_arrays_SCOP_0_KERNEL_1'
+; KERNEL-NEXT: source_filename = "FUNC_kernel_params_only_some_arrays_SCOP_0_KERNEL_1"
+; KERNEL-NEXT: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
+; KERNEL-NEXT: target triple = "nvptx64-nvidia-cuda"
+
+; KERNEL: define ptx_kernel void @FUNC_kernel_params_only_some_arrays_SCOP_0_KERNEL_1(i8 addrspace(1)* %MemRef_A)
+; KERNEL-NEXT:   entry:
+; KERNEL-NEXT:     %0 = call i32 @llvm.nvvm.read.ptx.sreg.ctaid.x()
+; KERNEL-NEXT:     %b0 = zext i32 %0 to i64
+; KERNEL-NEXT:     %1 = call i32 @llvm.nvvm.read.ptx.sreg.tid.x()
+; KERNEL-NEXT:     %t0 = zext i32 %1 to i64
+
+; KERNEL:     ret void
+; KERNEL-NEXT: }
+
+
+; IR:       [[DEVPTR:%.*]] = call i8* @polly_getDevicePtr(i8* %p_dev_array_MemRef_B)
+; IR-NEXT:  [[SLOT:%.*]] = getelementptr [1 x i8*], [1 x i8*]* %polly_launch_0_params, i64 0, i64 0
+; IR-NEXT:  store i8* [[DEVPTR]], i8** %polly_launch_0_param_0
+; IR-NEXT:  [[DATA:%.*]] = bitcast i8** %polly_launch_0_param_0 to i8*
+; IR-NEXT:  store i8* [[DATA]], i8** [[SLOT]]
+
+; IR:       [[DEVPTR:%.*]] = call i8* @polly_getDevicePtr(i8* %p_dev_array_MemRef_A)
+; IR-NEXT:  [[SLOT:%.*]] = getelementptr [1 x i8*], [1 x i8*]* %polly_launch_1_params, i64 0, i64 0
+; IR-NEXT:  store i8* [[DEVPTR]], i8** %polly_launch_1_param_0
+; IR-NEXT:  [[DATA:%.*]] = bitcast i8** %polly_launch_1_param_0 to i8*
+; IR-NEXT:  store i8* [[DATA]], i8** [[SLOT]]
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @kernel_params_only_some_arrays(float* %A, float* %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond1 = icmp ne i64 %i.0, 32
+  br i1 %exitcond1, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp = load float, float* %arrayidx, align 4
+  %add = fadd float %tmp, 4.200000e+01
+  store float %add, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc7, %for.end
+  %i1.0 = phi i64 [ 0, %for.end ], [ %inc8, %for.inc7 ]
+  %exitcond = icmp ne i64 %i1.0, 32
+  br i1 %exitcond, label %for.body4, label %for.end9
+
+for.body4:                                        ; preds = %for.cond2
+  %arrayidx5 = getelementptr inbounds float, float* %B, i64 %i1.0
+  %tmp2 = load float, float* %arrayidx5, align 4
+  %add6 = fadd float %tmp2, 4.200000e+01
+  store float %add6, float* %arrayidx5, align 4
+  br label %for.inc7
+
+for.inc7:                                         ; preds = %for.body4
+  %inc8 = add nuw nsw i64 %i1.0, 1
+  br label %for.cond2
+
+for.end9:                                         ; preds = %for.cond2
+  ret void
+}
diff --git a/final/test/GPGPU/kernel-params-scop-parameter.ll b/final/test/GPGPU/kernel-params-scop-parameter.ll
new file mode 100644
index 0000000..3cbd404
--- /dev/null
+++ b/final/test/GPGPU/kernel-params-scop-parameter.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=KERNEL-IR %s
+
+; REQUIRES: pollyacc
+
+;    void kernel_params_scop_parameter(float A[], long n) {
+;      for (long i = 0; i < n; i++)
+;        A[i] += 42;
+;    }
+
+; KERNEL-IR: define ptx_kernel void @FUNC_kernel_params_scop_parameter_SCOP_0_KERNEL_0(i8 addrspace(1)* %MemRef_A, i64 %n)
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @kernel_params_scop_parameter(float* %A, i64 %n) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %tmp = icmp slt i64 %i.0, %n
+  br i1 %tmp, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp3 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, 4.200000e+01
+  store float %tmp5, float* %tmp3, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/GPGPU/kernels-names-across-scops-funcs.ll b/final/test/GPGPU/kernels-names-across-scops-funcs.ll
new file mode 100644
index 0000000..22ad3f5
--- /dev/null
+++ b/final/test/GPGPU/kernels-names-across-scops-funcs.ll
@@ -0,0 +1,124 @@
+; RUN: opt %loadPolly -polly-process-unprofitable -polly-codegen-ppcg \
+; RUN: -polly-acc-dump-kernel-ir -disable-output < %s | \
+; RUN: FileCheck -check-prefix=KERNEL %s
+
+; REQUIRES: pollyacc
+
+; KERNEL: define ptx_kernel void @FUNC_foo_SCOP_0_KERNEL_0(i8 addrspace(1)* %MemRef_arg1, i32 %arg) #0 {
+; KERNEL: define ptx_kernel void @FUNC_foo_SCOP_1_KERNEL_0(i8 addrspace(1)* %MemRef_arg1, i32 %arg) #0 {
+; KERNEL: define ptx_kernel void @FUNC_foo2_SCOP_0_KERNEL_0(i8 addrspace(1)* %MemRef_arg1, i32 %arg) #0 {
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @foo(i32 %arg, i32* %arg1) #0 {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb
+  %tmp = icmp sgt i32 %arg, 0
+  br i1 %tmp, label %bb3, label %bb13
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb4, %bb3
+  %tmp5 = phi i64 [ 0, %bb3 ], [ %tmp9, %bb4 ]
+  %tmp6 = getelementptr inbounds i32, i32* %arg1, i64 %tmp5
+  %tmp7 = load i32, i32* %tmp6, align 4, !tbaa !2
+  %tmp8 = add nsw i32 %tmp7, 1
+  store i32 %tmp8, i32* %tmp6, align 4, !tbaa !2
+  %tmp9 = add nuw nsw i64 %tmp5, 1
+  %tmp10 = zext i32 %arg to i64
+  %tmp11 = icmp ne i64 %tmp9, %tmp10
+  br i1 %tmp11, label %bb4, label %bb12
+
+bb12:                                             ; preds = %bb4
+  br label %bb13
+
+bb13:                                             ; preds = %bb12, %bb2
+  %tmp14 = tail call i64 @clock() #3
+  %tmp15 = icmp eq i64 %tmp14, 0
+  br i1 %tmp15, label %bb16, label %bb29
+
+bb16:                                             ; preds = %bb13
+  %tmp17 = icmp sgt i32 %arg, 0
+  br i1 %tmp17, label %bb18, label %bb28
+
+bb18:                                             ; preds = %bb16
+  br label %bb19
+
+bb19:                                             ; preds = %bb19, %bb18
+  %tmp20 = phi i64 [ 0, %bb18 ], [ %tmp24, %bb19 ]
+  %tmp21 = getelementptr inbounds i32, i32* %arg1, i64 %tmp20
+  %tmp22 = load i32, i32* %tmp21, align 4, !tbaa !2
+  %tmp23 = add nsw i32 %tmp22, 1
+  store i32 %tmp23, i32* %tmp21, align 4, !tbaa !2
+  %tmp24 = add nuw nsw i64 %tmp20, 1
+  %tmp25 = zext i32 %arg to i64
+  %tmp26 = icmp ne i64 %tmp24, %tmp25
+  br i1 %tmp26, label %bb19, label %bb27
+
+bb27:                                             ; preds = %bb19
+  br label %bb28
+
+bb28:                                             ; preds = %bb27, %bb16
+  br label %bb29
+
+bb29:                                             ; preds = %bb28, %bb13
+  ret void
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind
+declare i64 @clock() #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind uwtable
+define void @foo2(i32 %arg, i32* %arg1) #0 {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb
+  %tmp = icmp sgt i32 %arg, 0
+  br i1 %tmp, label %bb3, label %bb13
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb4, %bb3
+  %tmp5 = phi i64 [ 0, %bb3 ], [ %tmp9, %bb4 ]
+  %tmp6 = getelementptr inbounds i32, i32* %arg1, i64 %tmp5
+  %tmp7 = load i32, i32* %tmp6, align 4, !tbaa !2
+  %tmp8 = add nsw i32 %tmp7, 1
+  store i32 %tmp8, i32* %tmp6, align 4, !tbaa !2
+  %tmp9 = add nuw nsw i64 %tmp5, 1
+  %tmp10 = zext i32 %arg to i64
+  %tmp11 = icmp ne i64 %tmp9, %tmp10
+  br i1 %tmp11, label %bb4, label %bb12
+
+bb12:                                             ; preds = %bb4
+  br label %bb13
+
+bb13:                                             ; preds = %bb12, %bb2
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { argmemonly nounwind }
+attributes #2 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang version 5.0.0 (http://llvm.org/git/clang 98cf823022d1d71065c71e9338226ebf8bfa36ba) (http://llvm.org/git/llvm.git 4efa61f12928015bad233274ffa2e60c918e9a10)"}
+!2 = !{!3, !3, i64 0}
+!3 = !{!"int", !4, i64 0}
+!4 = !{!"omnipotent char", !5, i64 0}
+!5 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/GPGPU/libdevice-functions-copied-into-kernel.ll b/final/test/GPGPU/libdevice-functions-copied-into-kernel.ll
new file mode 100644
index 0000000..62fc6ba
--- /dev/null
+++ b/final/test/GPGPU/libdevice-functions-copied-into-kernel.ll
@@ -0,0 +1,93 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s \
+; RUN: -polly-acc-libdevice=%S/Inputs/libdevice-functions-copied-into-kernel_libdevice.ll \
+; RUN:     | FileCheck %s --check-prefix=SCOP
+; RUN: opt %loadPolly -analyze -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -polly-acc-libdevice=%S/Inputs/libdevice-functions-copied-into-kernel_libdevice.ll \
+; RUN:     < %s | FileCheck %s --check-prefix=KERNEL-IR
+; RUN: opt %loadPolly -S -polly-codegen-ppcg  < %s \
+; RUN: -polly-acc-libdevice=%S/Inputs/libdevice-functions-copied-into-kernel_libdevice.ll \
+; RUN:     | FileCheck %s --check-prefix=HOST-IR
+
+; Test that we do recognise and codegen a kernel that has functions that can
+; be mapped to NVIDIA's libdevice
+
+; REQUIRES: pollyacc
+
+; Check that we model the kernel as a scop.
+; SCOP:      Function: f
+; SCOP-NEXT:       Region: %entry.split---%for.end
+
+; Check that the intrinsic call is present in the kernel IR.
+; KERNEL-IR:   %p_expf = tail call float @__nv_expf(float %A.arr.i.val_p_scalar_)
+; KERNEL-IR:   %p_cosf = tail call float @__nv_cosf(float %p_expf)
+; KERNEL-IR:   %p_logf = tail call float @__nv_logf(float %p_cosf)
+
+; Powi and exp cannot be lowered directly. Rather, we expect them to be
+; lowered by libdevice.
+; KERNEL-IR: %p_powi = tail call float @__nv_powif(float %p_logf, i32 2)
+; KERNEL-IR: %p_exp = tail call float @__nv_expf(float %p_powi)
+
+; Check that kernel launch is generated in host IR.
+; the declare would not be generated unless a call to a kernel exists.
+; HOST-IR: declare void @polly_launchKernel(i8*, i32, i32, i32, i32, i32, i8*)
+
+
+; void f(float *A, float *B, int N) {
+;   for(int i = 0; i < N; i++) {
+;       float tmp0 = A[i];
+;       float expf  = expf(tmp1);
+;       cosf = cosf(expf);
+;       logf = logf(cosf);
+;       powi = powi(logf, 2);
+;       exp = exp(powi);
+;       B[i] = logf;
+;   }
+; }
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(float* %A, float* %B, i32 %N) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %cmp1 = icmp sgt i32 %N, 0
+  br i1 %cmp1, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.lr.ph, %for.body
+  %indvars.iv = phi i64 [ 0, %for.body.lr.ph ], [ %indvars.iv.next, %for.body ]
+  %A.arr.i = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %A.arr.i.val = load float, float* %A.arr.i, align 4
+  ; Call to intrinsics that should be part of the kernel.
+  %expf = tail call float @expf(float %A.arr.i.val)
+  %cosf = tail call float @cosf(float %expf)
+  %logf = tail call float @logf(float %cosf)
+  %powi = tail call float @llvm.powi.f32(float %logf, i32 2)
+  %exp = tail call float @llvm.exp.f32(float %powi)
+  %B.arr.i = getelementptr inbounds float, float* %B, i64 %indvars.iv
+  store float %exp, float* %B.arr.i, align 4
+
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %wide.trip.count = zext i32 %N to i64
+  %exitcond = icmp ne i64 %indvars.iv.next, %wide.trip.count
+  br i1 %exitcond, label %for.body, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  ret void
+}
+
+; Function Attrs: nounwind readnone
+declare float @expf(float) #0
+declare float @cosf(float) #0
+declare float @logf(float) #0
+declare float @llvm.powi.f32(float, i32) #0
+declare float @llvm.exp.f32(float) #0
+
+attributes #0 = { nounwind readnone }
+
diff --git a/final/test/GPGPU/live-range-reordering-with-privatization.ll b/final/test/GPGPU/live-range-reordering-with-privatization.ll
new file mode 100644
index 0000000..9fcaed3
--- /dev/null
+++ b/final/test/GPGPU/live-range-reordering-with-privatization.ll
@@ -0,0 +1,78 @@
+  ; RUN: opt %loadPolly -polly-use-llvm-names -polly-scops \
+; RUN: -polly-invariant-load-hoisting -polly-codegen-ppcg \
+; RUN: -polly-acc-dump-code -disable-output \
+; RUN:   < %s | FileCheck %s -check-prefix=CODE
+
+; RUN: opt %loadPolly -polly-use-llvm-names -polly-scops \
+; RUN: -polly-invariant-load-hoisting -polly-codegen-ppcg \
+; RUN: -polly-acc-dump-kernel-ir -disable-output \
+; RUN:   < %s | FileCheck %s -check-prefix=KERNELIR
+
+; REQUIRES: pollyacc
+
+;    void f(const int *end, int *arr, const int *control, const int *readarr) {
+;      for (int i = 0; i < *end; i++) {
+;        int t = 0;
+;        if (*control > 3) {
+;          t += readarr[i];
+;        }
+;        arr[i] = t;
+;      }
+;    }
+
+; This test case tests the ability to infer that `t` is local to each loop
+; iteration, and can therefore be privatized.
+
+; CODE: # kernel0
+; CODE-NEXT: for (int c0 = 0; c0 <= (tmp - 32 * b0 - 1) / 1048576; c0 += 1)
+; CODE-NEXT:   if (tmp >= 32 * b0 + t0 + 1048576 * c0 + 1) {
+; CODE-NEXT:     Stmt_for_body(32 * b0 + t0 + 1048576 * c0);
+; CODE-NEXT:     if (tmp1 >= 4)
+; CODE-NEXT:       Stmt_if_then(32 * b0 + t0 + 1048576 * c0);
+; CODE-NEXT:     Stmt_if_end(32 * b0 + t0 + 1048576 * c0);
+; CODE-NEXT:   }
+
+; KERNELIR: %private_array = alloca i32
+
+target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"
+target triple = "i386-apple-macosx10.12.0"
+
+define void @f(i32* %end, i32* %arr, i32* %control, i32* %readarr) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %tmp3 = load i32, i32* %end, align 4
+  %cmp4 = icmp sgt i32 %tmp3, 0
+  br i1 %cmp4, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.lr.ph, %if.end
+  %i.05 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %if.end ]
+  %tmp1 = load i32, i32* %control, align 4
+  %cmp1 = icmp sgt i32 %tmp1, 3
+  br i1 %cmp1, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %readarr, i32 %i.05
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  %t.0 = phi i32 [ %tmp2, %if.then ], [ 0, %for.body ]
+  %arrayidx2 = getelementptr inbounds i32, i32* %arr, i32 %i.05
+  store i32 %t.0, i32* %arrayidx2, align 4
+  %inc = add nuw nsw i32 %i.05, 1
+  %tmp = load i32, i32* %end, align 4
+  %cmp = icmp slt i32 %inc, %tmp
+  br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %if.end
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  ret void
+}
+
diff --git a/final/test/GPGPU/loops-outside-scop.ll b/final/test/GPGPU/loops-outside-scop.ll
new file mode 100644
index 0000000..2159485
--- /dev/null
+++ b/final/test/GPGPU/loops-outside-scop.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s -check-prefix=SCOP
+
+; There is no FileCheck because we want to make sure that this doesn't crash.
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-fail-on-verify-module-failure \
+; RUN: -disable-output < %s
+
+; REQUIRES: pollyacc
+
+; Due to the existence of the `fence` call, We can only detect the inner loop
+; and not the outer loop. PPCGCodeGeneration had not implemented this case.
+; The fix was to pull the implementation from `IslNodeBuilder.
+
+; Make sure that we only capture the inner loop
+; SCOP:      Function: f
+; SCOP-NEXT: Region: %for2.body---%for2.body.fence
+; SCOP-NEXT: Max Loop Depth:  1
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @fn_to_fence(i32 *%val)
+
+; void f(int *arr, bool shouldcont) {
+;     for(int i = 0; ; i++) {
+;         for(int j = 0; j < 10; j++) {
+;             arr[j] = i;
+;         }
+;         fence(arr);
+;         if (!shouldcont) break;
+;     }
+; }
+
+
+; Function Attrs: nounwind uwtable
+define void @f(i32 *%arr, i1 %shouldcont) #1 {
+entry:
+  br label %for.init
+
+for.init:                                             ; preds = %for.end, %entry.split
+  %i = phi i32 [ %i.next, %for.end ], [ 0, %entry ]
+  br label %for2.body
+
+for2.body:                                             ; preds = %"65", %"64"
+  %j = phi i32 [ %j.next, %for2.body ], [ 0, %for.init ]
+  %j.sext = sext i32 %j to i64
+  %arr.slot = getelementptr i32, i32* %arr, i64 %j.sext
+  store i32 %i, i32* %arr.slot, align 4
+  %exitcond = icmp eq i32 %j, 10
+  %j.next = add i32 %j, 1
+  br i1 %exitcond, label %for2.body.fence, label %for2.body
+
+for2.body.fence:                                             ; preds = %"65"
+  call void @fn_to_fence(i32* %arr) #2
+  br i1 %shouldcont, label %for.end, label %exit
+for.end:                                             ; preds = %"69"
+  %i.next = add i32 %i, 1
+  br label %for.init
+
+exit:                                             ; preds = %"69"
+  ret void
+
+}
+
+
+attributes #0 = { argmemonly nounwind }
+attributes #1 = { nounwind uwtable }
+attributes #2 = { nounwind }
diff --git a/final/test/GPGPU/managed-memory-rewrite-alloca.ll b/final/test/GPGPU/managed-memory-rewrite-alloca.ll
new file mode 100644
index 0000000..3f64e08
--- /dev/null
+++ b/final/test/GPGPU/managed-memory-rewrite-alloca.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -analyze  -polly-process-unprofitable \
+; RUN: -polly-scops -polly-use-llvm-names < %s |  FileCheck %s --check-prefix=SCOP
+
+; RUN: opt %loadPolly -S  -polly-process-unprofitable -polly-acc-mincompute=0 \
+; RUN: -polly-target=gpu  -polly-codegen-ppcg -polly-acc-codegen-managed-memory \
+; RUN: -polly-acc-rewrite-managed-memory  -polly-acc-rewrite-allocas < %s | FileCheck %s --check-prefix=HOST-IR
+
+; REQUIRES: pollyacc
+
+; SCOP:      Function: f
+; SCOP-NEXT: Region: %for.body---%for.end
+; SCOP-NEXT: Max Loop Depth:  1
+; SCOP: i32 MemRef_arr[*];
+
+; Check that we generate a constructor call for @A.toptr
+; HOST-IR-NOT:   %arr = alloca [100 x i32]
+
+source_filename = "test.c"
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.12.0"
+
+
+define void @f() {
+entry:
+  %arr = alloca [100 x i32]
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %indvars.iv1 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds [100 x i32], [100 x i32]* %arr, i64 0, i64 %indvars.iv1
+  store i32 42, i32* %arrayidx, align 4, !tbaa !3
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv1, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 100
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.body
+  ret void
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #0
+
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #0
+
+attributes #0 = { argmemonly nounwind }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 7, !"PIC Level", i32 2}
+!2 = !{!"clang version 6.0.0 (http://llvm.org/git/clang.git 6660f0d30ef23b3142a6b08f9f41aad3d47c084f) (http://llvm.org/git/llvm.git 052dd78cb30f77a05dc8bb06b851402c4b6c6587)"}
+!3 = !{!4, !4, i64 0}
+!4 = !{!"int", !5, i64 0}
+!5 = !{!"omnipotent char", !6, i64 0}
+!6 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/GPGPU/managed-memory-rewrite-malloc-free-inside-constexpr.ll b/final/test/GPGPU/managed-memory-rewrite-malloc-free-inside-constexpr.ll
new file mode 100644
index 0000000..0d747e5
--- /dev/null
+++ b/final/test/GPGPU/managed-memory-rewrite-malloc-free-inside-constexpr.ll
@@ -0,0 +1,95 @@
+; RUN: opt %loadPolly -polly-scops \
+; RUN: -analyze < %s | FileCheck %s --check-prefix=SCOP
+
+; RUN: opt %loadPolly -polly-codegen-ppcg \
+; RUN: -S -polly-acc-codegen-managed-memory \
+; RUN: -polly-acc-rewrite-managed-memory < %s | FileCheck %s --check-prefix=HOST-IR
+;
+; REQUIRES: pollyacc
+;
+; Check that we can correctly rewrite `malloc` to `polly_mallocManaged`, and
+; `free` to `polly_freeManaged` with the `polly-acc-rewrite-managed-memory`
+; pass, even inside `constantExpr`. This is necessary because a cookie cutter
+; Inst->replaceUsesOfWith(...) call does not actually work, because this does
+; not replace the instruction within a ConstantExpr.
+;
+; #include <memory.h>
+;
+; static const int N = 100;
+; int* f(int *ToFree) {
+;     free(ToFree);
+;     int *A = (int *)malloc(sizeof(int) * N);
+;     for(int i = 0; i < N; i++) {
+;         A[i] = 42;
+;     }
+;     return A;
+;
+; }
+
+; SCOP:      Function: f
+; SCOP-NEXT: Region: %for.body---%for.end
+; SCOP-NEXT: Max Loop Depth:  1
+
+; SCOP:      Arrays {
+; SCOP-NEXT:     i32 MemRef_tmp[*]; // Element size 4
+; SCOP-NEXT: }
+
+; // Check that polly_mallocManaged is declared and used correctly.
+; HOST-IR: %1 = bitcast i8* (i64)* @polly_mallocManaged to i32* (i64)*
+; HOST-IR: declare i8* @polly_mallocManaged(i64)
+
+; // Check that polly_freeManaged is declared and used correctly.
+; HOST-IR  call void @polly_freeManaged(i8* %toFree)
+; HOST-IR: declare void @polly_freeManaged(i8*)
+
+; // Check that we remove the original malloc,free
+; HOST-IR-NOT: declare i8* @malloc(i64)
+; HOST-IR-NOT: declare void @free(i8*)
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.12.0"
+
+define i32* @f(i32 *%toFree) {
+entry:
+  ; Free inside bitcast
+  call void bitcast (void (i8*)* @free to void (i32 *)*) (i32 * %toFree)
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  ; malloc inside bitcast.
+  %tmp = call i32* bitcast (i8* (i64)* @malloc to i32* (i64)*) (i64 400)
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %indvars.iv1 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds i32, i32* %tmp, i64 %indvars.iv1
+  store i32 42, i32* %arrayidx, align 4, !tbaa !3
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv1, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 100
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.body
+  ret i32* %tmp
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #0
+
+declare i8* @malloc(i64)
+declare void @free(i8*)
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #0
+
+attributes #0 = { argmemonly nounwind }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 7, !"PIC Level", i32 2}
+!2 = !{!"clang version 6.0.0 (http://llvm.org/git/clang.git 6660f0d30ef23b3142a6b08f9f41aad3d47c084f) (http://llvm.org/git/llvm.git 052dd78cb30f77a05dc8bb06b851402c4b6c6587)"}
+!3 = !{!4, !4, i64 0}
+!4 = !{!"int", !5, i64 0}
+!5 = !{!"omnipotent char", !6, i64 0}
+!6 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/GPGPU/managed-memory-rewrite-malloc-free.ll b/final/test/GPGPU/managed-memory-rewrite-malloc-free.ll
new file mode 100644
index 0000000..f646427
--- /dev/null
+++ b/final/test/GPGPU/managed-memory-rewrite-malloc-free.ll
@@ -0,0 +1,94 @@
+; RUN: opt %loadPolly -polly-scops \
+; RUN: -analyze < %s | FileCheck %s --check-prefix=SCOP
+
+; RUN: opt %loadPolly -polly-codegen-ppcg \
+; RUN: -S -polly-acc-codegen-managed-memory \
+; RUN: -polly-acc-rewrite-managed-memory < %s | FileCheck %s --check-prefix=HOST-IR
+;
+; REQUIRES: pollyacc
+;
+; Check that we can correctly rewrite `malloc` to `polly_mallocManaged`, and
+; `free` to `polly_freeManaged` with the `polly-acc-rewrite-managed-memory`
+; pass.
+;
+; #include <memory.h>
+;
+; static const int N = 100;
+; int* f(int *ToFree) {
+;     free(ToFree);
+;     int *A = (int *)malloc(sizeof(int) * N);
+;     for(int i = 0; i < N; i++) {
+;         A[i] = 42;
+;     }
+;     return A;
+;
+; }
+
+; SCOP:      Function: f
+; SCOP-NEXT: Region: %for.body---%for.end
+; SCOP-NEXT: Max Loop Depth:  1
+
+; SCOP:      Arrays {
+; SCOP-NEXT:     i32 MemRef_call[*]; // Element size 4
+; SCOP-NEXT: }
+
+; // Check that polly_mallocManaged is declared and used correctly.
+; HOST-IR: %call = tail call i8* @polly_mallocManaged(i64 400)
+; HOST-IR: declare i8* @polly_mallocManaged(i64)
+
+; // Check that polly_freeManaged is declared and used correctly.
+; HOST-IR  %toFreeBitcast = bitcast i32* %toFree to i8*
+; HOST-IR  call void @polly_freeManaged(i8* %toFreeBitcast)
+; HOST-IR: declare void @polly_freeManaged(i8*)
+
+; // Check that we remove the original malloc,free
+; HOST-IR-NOT: declare i8* @malloc(i64)
+; HOST-IR-NOT: declare void @free(i8*)
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.12.0"
+
+define i32* @f(i32 *%toFree) {
+entry:
+  %toFreeBitcast = bitcast i32* %toFree to i8*
+  call void @free(i8* %toFreeBitcast)
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %call = tail call i8* @malloc(i64 400)
+  %tmp = bitcast i8* %call to i32*
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %indvars.iv1 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds i32, i32* %tmp, i64 %indvars.iv1
+  store i32 42, i32* %arrayidx, align 4, !tbaa !3
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv1, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 100
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.body
+  ret i32* %tmp
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #0
+
+declare i8* @malloc(i64)
+declare void @free(i8*)
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #0
+
+attributes #0 = { argmemonly nounwind }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 7, !"PIC Level", i32 2}
+!2 = !{!"clang version 6.0.0 (http://llvm.org/git/clang.git 6660f0d30ef23b3142a6b08f9f41aad3d47c084f) (http://llvm.org/git/llvm.git 052dd78cb30f77a05dc8bb06b851402c4b6c6587)"}
+!3 = !{!4, !4, i64 0}
+!4 = !{!"int", !5, i64 0}
+!5 = !{!"omnipotent char", !6, i64 0}
+!6 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/GPGPU/managed-pointers-preparation.ll b/final/test/GPGPU/managed-pointers-preparation.ll
new file mode 100644
index 0000000..4a22e48
--- /dev/null
+++ b/final/test/GPGPU/managed-pointers-preparation.ll
@@ -0,0 +1,107 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -polly-invariant-load-hoisting \
+; RUN: -S -polly-acc-codegen-managed-memory < %s | FileCheck %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -polly-invariant-load-hoisting \
+; RUN: -S -polly-acc-codegen-managed-memory -disable-output \
+; RUN: -polly-acc-dump-code < %s | FileCheck %s -check-prefix=CODE
+
+; REQUIRES: pollyacc
+
+; CHECK: @polly_launchKernel
+; CHECK: @polly_launchKernel
+; CHECK: @polly_launchKernel
+; CHECK: @polly_launchKernel
+; CHECK: @polly_launchKernel
+; CHECK-NOT: @polly_launchKernel
+
+
+; CODE:  if (p_0_loaded_from___data_runcontrol_MOD_lmulti_layer == 0) {
+; CODE-NEXT:    {
+; CODE-NEXT:      dim3 k0_dimBlock;
+; CODE-NEXT:      dim3 k0_dimGrid;
+; CODE-NEXT:      kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef__pn__phi, p_0_loaded_from___data_runcontrol_MOD_lmulti_layer);
+; CODE-NEXT:      cudaCheckKernel();
+; CODE-NEXT:    }
+
+; CODE:  } else {
+; CODE-NEXT:    {
+; CODE-NEXT:      dim3 k1_dimBlock;
+; CODE-NEXT:      dim3 k1_dimGrid;
+; CODE-NEXT:      kernel1 <<<k1_dimGrid, k1_dimBlock>>> (dev_MemRef__pn__phi, p_0_loaded_from___data_runcontrol_MOD_lmulti_layer);
+; CODE-NEXT:      cudaCheckKernel();
+; CODE-NEXT:    }
+
+; CHECK that this program is correctly code generated and does not result in
+; 'instruction does not dominate use' errors. At an earlier point, such errors
+; have been generated as the preparation of the managed memory pointers was
+; performed right before kernel0, which does not dominate all other kernels.
+; Now the preparation is performed at the very beginning of the scop.
+
+source_filename = "bugpoint-output-c78f41e.bc"
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+@__data_radiation_MOD_rad_csalbw = external global [10 x double], align 32
+@__data_radiation_MOD_coai = external global [168 x double], align 32
+@__data_runcontrol_MOD_lmulti_layer = external global i32
+
+; Function Attrs: nounwind uwtable
+define void @__radiation_interface_MOD_radiation_init() #0 {
+entry:
+  br label %"94"
+
+"94":                                             ; preds = %"97", %entry
+  br label %"95"
+
+"95":                                             ; preds = %"95", %"94"
+  br i1 undef, label %"97", label %"95"
+
+"97":                                             ; preds = %"95"
+  br i1 undef, label %"99", label %"94"
+
+"99":                                             ; preds = %"97"
+  br label %"102"
+
+"102":                                            ; preds = %"102", %"99"
+  %indvars.iv17 = phi i64 [ %indvars.iv.next18, %"102" ], [ 1, %"99" ]
+  %0 = getelementptr [168 x double], [168 x double]* @__data_radiation_MOD_coai, i64 0, i64 0
+  store double 1.000000e+00, double* %0, align 8
+  %1 = icmp eq i64 %indvars.iv17, 3
+  %indvars.iv.next18 = add nuw nsw i64 %indvars.iv17, 1
+  br i1 %1, label %"110", label %"102"
+
+"110":                                            ; preds = %"102"
+  %2 = load i32, i32* @__data_runcontrol_MOD_lmulti_layer, align 4, !range !0
+  %3 = icmp eq i32 %2, 0
+  br i1 %3, label %"112", label %"111"
+
+"111":                                            ; preds = %"110"
+  br label %"115"
+
+"112":                                            ; preds = %"110"
+  br label %"115"
+
+"115":                                            ; preds = %"112", %"111"
+  %.pn = phi double [ undef, %"112" ], [ undef, %"111" ]
+  %4 = fdiv double 1.000000e+00, %.pn
+  br label %"116"
+
+"116":                                            ; preds = %"116", %"115"
+  %indvars.iv = phi i64 [ %indvars.iv.next, %"116" ], [ 1, %"115" ]
+  %5 = add nsw i64 %indvars.iv, -1
+  %6 = fmul double %4, undef
+  %7 = getelementptr [10 x double], [10 x double]* @__data_radiation_MOD_rad_csalbw, i64 0, i64 %5
+  store double %6, double* %7, align 8
+  %8 = icmp eq i64 %indvars.iv, 10
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br i1 %8, label %return, label %"116"
+
+return:                                           ; preds = %"116"
+  ret void
+}
+
+attributes #0 = { nounwind uwtable }
+
+!0 = !{i32 0, i32 2}
diff --git a/final/test/GPGPU/memory-only-referenced-from-access.ll b/final/test/GPGPU/memory-only-referenced-from-access.ll
new file mode 100644
index 0000000..93107b9
--- /dev/null
+++ b/final/test/GPGPU/memory-only-referenced-from-access.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -polly-invariant-load-hoisting -polly-ignore-aliasing \
+; RUN: -polly-process-unprofitable -polly-ignore-parameter-bounds \
+; RUN: -polly-acc-fail-on-verify-module-failure \
+; RUN: -polly-acc-codegen-managed-memory \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck %s
+
+; REQUIRES: pollyacc
+
+; Verify that we correctly generate a kernel even if certain invariant load
+; hoisted parameters appear only in memory accesses, but not domain elements.
+
+; CHECK: @FUNC_quux_SCOP_0_KERNEL_0(i8 addrspace(1)* %MemRef_tmp4, i32 %tmp3, i32 %tmp, i32 %tmp31, i32 %tmp2)
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.hoge = type { i8*, i64, i64, [1 x %struct.widget] }
+%struct.widget = type { i64, i64, i64 }
+
+@global = external unnamed_addr global %struct.hoge, align 32
+
+define void @quux(i32* noalias %arg, i32* noalias %arg1) {
+bb:
+  %tmp = load i32, i32* %arg, align 4
+  %tmp2 = sext i32 %tmp to i64
+  %tmp3 = load i32, i32* %arg1, align 4
+  %tmp4 = load [0 x double]*, [0 x double]** bitcast (%struct.hoge* @global to [0 x double]**), align 32
+  br label %bb5
+
+bb5:                                              ; preds = %bb5, %bb
+  %tmp6 = phi i32 [ %tmp11, %bb5 ], [ 0, %bb ]
+  %tmp7 = sext i32 %tmp6 to i64
+  %tmp8 = sub nsw i64 %tmp7, %tmp2
+  %tmp9 = getelementptr [0 x double], [0 x double]* %tmp4, i64 0, i64 %tmp8
+  store double undef, double* %tmp9, align 8
+  %tmp10 = icmp eq i32 %tmp6, %tmp3
+  %tmp11 = add i32 %tmp6, 1
+  br i1 %tmp10, label %bb12, label %bb5
+
+bb12:                                             ; preds = %bb5
+  ret void
+}
diff --git a/final/test/GPGPU/mostly-sequential.ll b/final/test/GPGPU/mostly-sequential.ll
new file mode 100644
index 0000000..c0574f7
--- /dev/null
+++ b/final/test/GPGPU/mostly-sequential.ll
@@ -0,0 +1,105 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; REQUIRES: pollyacc
+
+;    void foo(float A[]) {
+;      for (long i = 0; i < 128; i++)
+;        A[i] += i;
+;
+;      for (long i = 0; i < 128; i++)
+;        for (long j = 0; j < 128; j++)
+;          A[42] += i + j;
+;    }
+
+; CODE:        cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (128) * sizeof(float), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(4);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:            {
+; CODE-NEXT:         dim3 k1_dimBlock;
+; CODE-NEXT:         dim3 k1_dimGrid;
+; CODE-NEXT:         kernel1 <<<k1_dimGrid, k1_dimBlock>>> (dev_MemRef_A);
+; CODE-NEXT:         cudaCheckKernel();
+; CODE-NEXT:       }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (128) * sizeof(float), cudaMemcpyDeviceToHost));
+; CODE-NEXT: cudaCheckReturn(cudaFree(dev_MemRef_A));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_bb4(32 * b0 + t0);
+
+; CODE: # kernel1
+; CODE-NEXT: for (int c0 = 0; c0 <= 127; c0 += 1)
+; CODE-NEXT:   for (int c1 = 0; c1 <= 127; c1 += 1)
+; CODE-NEXT:     Stmt_bb14(c0, c1);
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A) {
+bb:
+  br label %bb3
+
+bb3:                                              ; preds = %bb8, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp9, %bb8 ]
+  %exitcond2 = icmp ne i64 %i.0, 128
+  br i1 %exitcond2, label %bb4, label %bb10
+
+bb4:                                              ; preds = %bb3
+  %tmp = sitofp i64 %i.0 to float
+  %tmp5 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp6 = load float, float* %tmp5, align 4
+  %tmp7 = fadd float %tmp6, %tmp
+  store float %tmp7, float* %tmp5, align 4
+  br label %bb8
+
+bb8:                                              ; preds = %bb4
+  %tmp9 = add nuw nsw i64 %i.0, 1
+  br label %bb3
+
+bb10:                                             ; preds = %bb3
+  br label %bb11
+
+bb11:                                             ; preds = %bb23, %bb10
+  %i1.0 = phi i64 [ 0, %bb10 ], [ %tmp24, %bb23 ]
+  %exitcond1 = icmp ne i64 %i1.0, 128
+  br i1 %exitcond1, label %bb12, label %bb25
+
+bb12:                                             ; preds = %bb11
+  br label %bb13
+
+bb13:                                             ; preds = %bb20, %bb12
+  %j.0 = phi i64 [ 0, %bb12 ], [ %tmp21, %bb20 ]
+  %exitcond = icmp ne i64 %j.0, 128
+  br i1 %exitcond, label %bb14, label %bb22
+
+bb14:                                             ; preds = %bb13
+  %tmp15 = add nuw nsw i64 %i1.0, %j.0
+  %tmp16 = sitofp i64 %tmp15 to float
+  %tmp17 = getelementptr inbounds float, float* %A, i64 42
+  %tmp18 = load float, float* %tmp17, align 4
+  %tmp19 = fadd float %tmp18, %tmp16
+  store float %tmp19, float* %tmp17, align 4
+  br label %bb20
+
+bb20:                                             ; preds = %bb14
+  %tmp21 = add nuw nsw i64 %j.0, 1
+  br label %bb13
+
+bb22:                                             ; preds = %bb13
+  br label %bb23
+
+bb23:                                             ; preds = %bb22
+  %tmp24 = add nuw nsw i64 %i1.0, 1
+  br label %bb11
+
+bb25:                                             ; preds = %bb11
+  ret void
+}
diff --git a/final/test/GPGPU/non-read-only-scalars.ll b/final/test/GPGPU/non-read-only-scalars.ll
new file mode 100644
index 0000000..022fa92
--- /dev/null
+++ b/final/test/GPGPU/non-read-only-scalars.ll
@@ -0,0 +1,169 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck %s -check-prefix=KERNEL-IR
+;
+; REQUIRES: pollyacc
+;
+; #include <stdio.h>
+;
+; float foo(float A[]) {
+;   float sum = 0;
+;
+;   for (long i = 0; i < 32; i++)
+;     A[i] = i;
+;
+;   for (long i = 0; i < 32; i++)
+;     A[i] += i;
+;
+;   for (long i = 0; i < 32; i++)
+;     sum += A[i];
+;
+;   return sum;
+; }
+;
+; int main() {
+;   float A[32];
+;   float sum = foo(A);
+;   printf("%f\n", sum);
+; }
+
+; CODE:          dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(1);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   {
+; CODE-NEXT:     dim3 k1_dimBlock;
+; CODE-NEXT:     dim3 k1_dimGrid;
+; CODE-NEXT:     kernel1 <<<k1_dimGrid, k1_dimBlock>>> (dev_MemRef_sum_0__phi);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:          {
+; CODE-NEXT:       dim3 k2_dimBlock;
+; CODE-NEXT:       dim3 k2_dimGrid;
+; CODE-NEXT:       kernel2 <<<k2_dimGrid, k2_dimBlock>>> (dev_MemRef_A, dev_MemRef_sum_0__phi, dev_MemRef_sum_0);
+; CODE-NEXT:       cudaCheckKernel();
+; CODE-NEXT:     }
+
+; CODE:        cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (32) * sizeof(float), cudaMemcpyDeviceToHost));
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(&MemRef_sum_0, dev_MemRef_sum_0, sizeof(float), cudaMemcpyDeviceToHost));
+; CODE-NEXT:   cudaCheckReturn(cudaFree(dev_MemRef_A));
+; CODE-NEXT:   cudaCheckReturn(cudaFree(dev_MemRef_sum_0__phi));
+; CODE-NEXT:   cudaCheckReturn(cudaFree(dev_MemRef_sum_0));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: {
+; CODE-NEXT:   Stmt_bb4(t0);
+; CODE-NEXT:   Stmt_bb10(t0);
+; CODE-NEXT: }
+
+; CODE: # kernel1
+; CODE-NEXT: Stmt_bb17();
+
+; CODE: # kernel2
+; CODE_NEXT: {
+; CODE_NEXT:   read();
+; CODE_NEXT:   for (int c0 = 0; c0 <= 32; c0 += 1) {
+; CODE_NEXT:     Stmt_bb18(c0);
+; CODE_NEXT:     if (c0 <= 31)
+; CODE_NEXT:       Stmt_bb20(c0);
+; CODE_NEXT:   }
+; CODE_NEXT:   write();
+; CODE_NEXT: }
+
+
+; KERNEL-IR: define ptx_kernel void @FUNC_foo_SCOP_0_KERNEL_1(i8 addrspace(1)* %MemRef_sum_0__phi)
+; KERNEL-IR:  store float 0.000000e+00, float* %sum.0.phiops
+; KERNEL-IR:  [[REGA:%.+]] = addrspacecast i8 addrspace(1)* %MemRef_sum_0__phi to float*
+; KERNEL-IR:  [[REGB:%.+]] = load float, float* %sum.0.phiops
+; KERNEL-IR:  store float [[REGB]], float* [[REGA]]
+
+; KERNEL-IR: define ptx_kernel void @FUNC_foo_SCOP_0_KERNEL_2(i8 addrspace(1)* %MemRef_A, i8 addrspace(1)* %MemRef_sum_0__phi, i8 addrspace(1)* %MemRef_sum_0)
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@.str = private unnamed_addr constant [4 x i8] c"%f\0A\00", align 1
+
+define float @foo(float* %A) {
+bb:
+  br label %bb3
+
+bb3:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %exitcond2 = icmp ne i64 %i.0, 32
+  br i1 %exitcond2, label %bb4, label %bb8
+
+bb4:                                              ; preds = %bb3
+  %tmp = sitofp i64 %i.0 to float
+  %tmp5 = getelementptr inbounds float, float* %A, i64 %i.0
+  store float %tmp, float* %tmp5, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb4
+  %tmp7 = add nuw nsw i64 %i.0, 1
+  br label %bb3
+
+bb8:                                              ; preds = %bb3
+  br label %bb9
+
+bb9:                                              ; preds = %bb15, %bb8
+  %i1.0 = phi i64 [ 0, %bb8 ], [ %tmp16, %bb15 ]
+  %exitcond1 = icmp ne i64 %i1.0, 32
+  br i1 %exitcond1, label %bb10, label %bb17
+
+bb10:                                             ; preds = %bb9
+  %tmp11 = sitofp i64 %i1.0 to float
+  %tmp12 = getelementptr inbounds float, float* %A, i64 %i1.0
+  %tmp13 = load float, float* %tmp12, align 4
+  %tmp14 = fadd float %tmp13, %tmp11
+  store float %tmp14, float* %tmp12, align 4
+  br label %bb15
+
+bb15:                                             ; preds = %bb10
+  %tmp16 = add nuw nsw i64 %i1.0, 1
+  br label %bb9
+
+bb17:                                             ; preds = %bb9
+  br label %bb18
+
+bb18:                                             ; preds = %bb20, %bb17
+  %sum.0 = phi float [ 0.000000e+00, %bb17 ], [ %tmp23, %bb20 ]
+  %i2.0 = phi i64 [ 0, %bb17 ], [ %tmp24, %bb20 ]
+  %exitcond = icmp ne i64 %i2.0, 32
+  br i1 %exitcond, label %bb19, label %bb25
+
+bb19:                                             ; preds = %bb18
+  br label %bb20
+
+bb20:                                             ; preds = %bb19
+  %tmp21 = getelementptr inbounds float, float* %A, i64 %i2.0
+  %tmp22 = load float, float* %tmp21, align 4
+  %tmp23 = fadd float %sum.0, %tmp22
+  %tmp24 = add nuw nsw i64 %i2.0, 1
+  br label %bb18
+
+bb25:                                             ; preds = %bb18
+  %sum.0.lcssa = phi float [ %sum.0, %bb18 ]
+  ret float %sum.0.lcssa
+}
+
+define i32 @main() {
+bb:
+  %A = alloca [32 x float], align 16
+  %tmp = getelementptr inbounds [32 x float], [32 x float]* %A, i64 0, i64 0
+  %tmp1 = call float @foo(float* %tmp)
+  %tmp2 = fpext float %tmp1 to double
+  %tmp3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), double %tmp2) #2
+  ret i32 0
+}
+
+declare i32 @printf(i8*, ...) #1
+
diff --git a/final/test/GPGPU/non-zero-array-offset.ll b/final/test/GPGPU/non-zero-array-offset.ll
new file mode 100644
index 0000000..dcab25e
--- /dev/null
+++ b/final/test/GPGPU/non-zero-array-offset.ll
@@ -0,0 +1,119 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -S < %s | \
+; RUN: FileCheck %s -check-prefix=IR
+;
+; REQUIRES: pollyacc
+
+; CODE:      cudaCheckReturn(cudaMemcpy(dev_MemRef_B, MemRef_B, (16) * sizeof(float), cudaMemcpyHostToDevice));
+; CODE-NEXT: cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (8) * sizeof(float), cudaMemcpyHostToDevice));
+
+; CODE:          dim3 k0_dimBlock(8);
+; CODE-NEXT:     dim3 k0_dimGrid(1);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:        {
+; CODE-NEXT:     dim3 k1_dimBlock(8);
+; CODE-NEXT:     dim3 k1_dimGrid(1);
+; CODE-NEXT:     kernel1 <<<k1_dimGrid, k1_dimBlock>>> (dev_MemRef_B);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_B, dev_MemRef_B, (16) * sizeof(float), cudaMemcpyDeviceToHost));
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (8) * sizeof(float), cudaMemcpyDeviceToHost));
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_bb11(t0);
+
+; CODE: # kernel1
+; CODE-NEXT: Stmt_bb3(t0);
+
+; IR:       %p_dev_array_MemRef_B = call i8* @polly_allocateMemoryForDevice(i64 32)
+; IR-NEXT:  %p_dev_array_MemRef_A = call i8* @polly_allocateMemoryForDevice(i64 32)
+; IR-NEXT:  [[REG0:%.+]] = getelementptr float, float* %B, i64 8
+; IR-NEXT:  [[REG1:%.+]] = bitcast float* [[REG0]] to i8*
+; IR-NEXT:  call void @polly_copyFromHostToDevice(i8* [[REG1]], i8* %p_dev_array_MemRef_B, i64 32)
+
+; IR:      [[REGA:%.+]] = call i8* @polly_getDevicePtr(i8* %p_dev_array_MemRef_B)
+; IR-NEXT: [[REGB:%.+]]  = bitcast i8* [[REGA]] to float*
+; IR-NEXT: [[REGC:%.+]]  = getelementptr float, float* [[REGB]], i64 -8
+; IR-NEXT: [[REGD:%.+]]  = bitcast float* [[REGC]] to i8*
+
+;    void foo(float A[], float B[]) {
+;      for (long i = 0; i < 8; i++)
+;        B[i + 8] *= 4;
+;
+;      for (long i = 0; i < 8; i++)
+;        A[i] *= 12;
+;    }
+;
+;    #ifdef OUTPUT
+;    int main() {
+;      float A[16];
+;
+;      for (long i = 0; i < 16; i++) {
+;        __sync_synchronize();
+;        A[i] = i;
+;      }
+;
+;      foo(A, A);
+;
+;      float sum = 0;
+;      for (long i = 0; i < 16; i++) {
+;        __sync_synchronize();
+;        sum += A[i];
+;      }
+;
+;      printf("%f\n", sum);
+;    }
+;    #endif
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A, float* %B) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb7, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp8, %bb7 ]
+  %exitcond1 = icmp ne i64 %i.0, 8
+  br i1 %exitcond1, label %bb3, label %bb9
+
+bb3:                                              ; preds = %bb2
+  %tmp = add nuw nsw i64 %i.0, 8
+  %tmp4 = getelementptr inbounds float, float* %B, i64 %tmp
+  %tmp5 = load float, float* %tmp4, align 4
+  %tmp6 = fmul float %tmp5, 4.000000e+00
+  store float %tmp6, float* %tmp4, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb3
+  %tmp8 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb9:                                              ; preds = %bb2
+  br label %bb10
+
+bb10:                                             ; preds = %bb15, %bb9
+  %i1.0 = phi i64 [ 0, %bb9 ], [ %tmp16, %bb15 ]
+  %exitcond = icmp ne i64 %i1.0, 8
+  br i1 %exitcond, label %bb11, label %bb17
+
+bb11:                                             ; preds = %bb10
+  %tmp12 = getelementptr inbounds float, float* %A, i64 %i1.0
+  %tmp13 = load float, float* %tmp12, align 4
+  %tmp14 = fmul float %tmp13, 1.200000e+01
+  store float %tmp14, float* %tmp12, align 4
+  br label %bb15
+
+bb15:                                             ; preds = %bb11
+  %tmp16 = add nuw nsw i64 %i1.0, 1
+  br label %bb10
+
+bb17:                                             ; preds = %bb10
+  ret void
+}
diff --git a/final/test/GPGPU/only-part-of-array-modified.ll b/final/test/GPGPU/only-part-of-array-modified.ll
new file mode 100644
index 0000000..241a3b1
--- /dev/null
+++ b/final/test/GPGPU/only-part-of-array-modified.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+;
+; REQUIRES: pollyacc
+;
+;    void foo(float A[], float B[]) {
+;      for (long i = 0; i < 1024; i++)
+;        A[2 * i] = B[i];
+;    }
+
+; CODE: cudaCheckReturn(cudaMemcpy(dev_MemRef_B, MemRef_B, (1024) * sizeof(i32), cudaMemcpyHostToDevice));
+; CODE-NEXT: cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (2047) * sizeof(i32), cudaMemcpyHostToDevice));
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A, float* %B) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb8, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp9, %bb8 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb10
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds float, float* %B, i64 %i.0
+  %tmp3 = bitcast float* %tmp to i32*
+  %tmp4 = load i32, i32* %tmp3, align 4
+  %tmp5 = shl nsw i64 %i.0, 1
+  %tmp6 = getelementptr inbounds float, float* %A, i64 %tmp5
+  %tmp7 = bitcast float* %tmp6 to i32*
+  store i32 %tmp4, i32* %tmp7, align 4
+  br label %bb8
+
+bb8:                                              ; preds = %bb2
+  %tmp9 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb10:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/GPGPU/parametric-loop-bound.ll b/final/test/GPGPU/parametric-loop-bound.ll
new file mode 100644
index 0000000..6e8842d
--- /dev/null
+++ b/final/test/GPGPU/parametric-loop-bound.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg \
+; RUN: -S < %s | \
+; RUN: FileCheck -check-prefix=IR %s
+
+; REQUIRES: pollyacc
+
+;    void foo(long A[], long n) {
+;      for (long i = 0; i < n; i++)
+;        A[i] += 100;
+;    }
+
+; CODE: if (n >= 1) {
+; CODE:        cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (n) * sizeof(i64), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(n >= 1048546 ? 32768 : (n + 31) / 32);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A, n);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:        cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (n) * sizeof(i64), cudaMemcpyDeviceToHost));
+; CODE-NEXT:   cudaCheckReturn(cudaFree(dev_MemRef_A));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: for (int c0 = 0; c0 <= (n - 32 * b0 - 1) / 1048576; c0 += 1)
+; CODE-NEXT:   if (n >= 32 * b0 + t0 + 1048576 * c0 + 1)
+; CODE-NEXT:     Stmt_bb2(32 * b0 + t0 + 1048576 * c0);
+
+; IR: store i64 %n, i64* %polly_launch_0_param_1
+; IR-NEXT: [[REGA:%.+]] = getelementptr [2 x i8*], [2 x i8*]* %polly_launch_0_params, i64 0, i64 1
+; IR-NEXT: [[REGB:%.+]] = bitcast i64* %polly_launch_0_param_1 to i8*
+; IR-NEXT: store i8* [[REGB]], i8** [[REGA]]
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64* %A, i64 %n) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %tmp = icmp slt i64 %i.0, %n
+  br i1 %tmp, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp3 = getelementptr inbounds i64, i64* %A, i64 %i.0
+  %tmp4 = load i64, i64* %tmp3, align 8
+  %tmp5 = add nsw i64 %tmp4, 100
+  store i64 %tmp5, i64* %tmp3, align 8
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/GPGPU/partial_writes.ll b/final/test/GPGPU/partial_writes.ll
new file mode 100644
index 0000000..0fc4851
--- /dev/null
+++ b/final/test/GPGPU/partial_writes.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-codegen-ppcg -S < %s \
+; RUN: | FileCheck %s
+
+; REQUIRES: pollyacc
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK: polly_launchKernel
+
+; Function Attrs: nounwind uwtable
+define void @partial_writes() {
+bb:
+  %tmp = tail call i8* @wibble() #2
+  %tmp1 = bitcast i8* %tmp to [1200 x double]*
+  br label %bb2
+
+bb2:                                              ; preds = %bb11, %bb
+  %tmp3 = phi i64 [ 0, %bb ], [ %tmp12, %bb11 ]
+  %tmp4 = getelementptr inbounds [1200 x double], [1200 x double]* %tmp1, i64 0, i64 %tmp3
+  %tmp5 = load double, double* %tmp4, align 8, !tbaa !1
+  br label %bb6
+
+bb6:                                              ; preds = %bb6, %bb2
+  %tmp7 = phi double [ undef, %bb2 ], [ undef, %bb6 ]
+  %tmp8 = phi i64 [ 0, %bb2 ], [ %tmp9, %bb6 ]
+  store double undef, double* %tmp4, align 8, !tbaa !1
+  %tmp9 = add nuw nsw i64 %tmp8, 1
+  %tmp10 = icmp eq i64 %tmp9, 900
+  br i1 %tmp10, label %bb11, label %bb6
+
+bb11:                                             ; preds = %bb6
+  %tmp12 = add nuw nsw i64 %tmp3, 1
+  %tmp13 = icmp eq i64 %tmp12, 1200
+  br i1 %tmp13, label %bb14, label %bb2
+
+bb14:                                             ; preds = %bb11
+  ret void
+}
+
+declare i8* @wibble()
+
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 6.0.0 (trunk 309912) (llvm/trunk 309933)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"double", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/GPGPU/partial_writes___%bb2---%bb14.jscop b/final/test/GPGPU/partial_writes___%bb2---%bb14.jscop
new file mode 100644
index 0000000..d5b537e
--- /dev/null
+++ b/final/test/GPGPU/partial_writes___%bb2---%bb14.jscop
@@ -0,0 +1,47 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_tmp",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb2---%bb14",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2[i0] -> MemRef_tmp[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb2[i0] -> MemRef_tmp[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb2[i0] : 0 <= i0 <= 1199 }",
+         "name" : "Stmt_bb2",
+         "schedule" : "{ Stmt_bb2[i0] -> [i0, 0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb6[i0, i1] -> MemRef_tmp[i0] : i1 <= 898 }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb6[i0, i1] -> MemRef_tmp[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb6[i0, i1] -> MemRef_tmp[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb6[i0, i1] : 0 <= i0 <= 1199 and 0 <= i1 <= 899 }",
+         "name" : "Stmt_bb6",
+         "schedule" : "{ Stmt_bb6[i0, i1] -> [i0, 1, i1] }"
+      }
+   ]
+}
diff --git a/final/test/GPGPU/phi-nodes-in-kernel.ll b/final/test/GPGPU/phi-nodes-in-kernel.ll
new file mode 100644
index 0000000..687afcc
--- /dev/null
+++ b/final/test/GPGPU/phi-nodes-in-kernel.ll
@@ -0,0 +1,86 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -S < %s | \
+; RUN: FileCheck %s -check-prefix=IR
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck %s -check-prefix=KERNEL-IR
+
+; REQUIRES: pollyacc
+
+; Approximate C source:
+; void kernel_dynprog(int c[50]) {
+;     int iter = 0;
+;     int outl = 0;
+;
+;      while(1) {
+;         for(int indvar = 1 ; indvar <= 49; indvar++) {
+;             c[indvar] = undef;
+;         }
+;         add78 = c[49] + outl;
+;         inc80 = iter + 1;
+;
+;         if (true) break;
+;
+;         outl = add78;
+;         iter = inc80;
+;      }
+;}
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CODE:       cudaCheckReturn(cudaMalloc((void **) &dev_MemRef_c, (50) * sizeof(i32)));
+
+; CODE:       {
+; CODE-NEXT:    dim3 k0_dimBlock(32);
+; CODE-NEXT:    dim3 k0_dimGrid(2);
+; CODE-NEXT:    kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_c);
+; CODE-NEXT:    cudaCheckKernel();
+; CODE-NEXT:  }
+
+; CODE:       cudaCheckReturn(cudaMemcpy(MemRef_c, dev_MemRef_c, (50) * sizeof(i32), cudaMemcpyDeviceToHost));
+; CODE-NEXT:  cudaCheckReturn(cudaFree(dev_MemRef_c));
+
+; CODE: # kernel0
+; CODE-NEXT: if (32 * b0 + t0 <= 48)
+; CODE-NEXT:     Stmt_for_body17(0, 32 * b0 + t0);
+
+; IR-LABEL: call void @polly_freeKernel
+; IR:       [[REGC:%.+]] =   bitcast i32* %{{[0-9]+}} to i8*
+; IR-NEXT:  call void @polly_copyFromDeviceToHost(i8* %p_dev_array_MemRef_c, i8* [[REGC]], i64 196)
+
+; KERNEL-IR: define ptx_kernel void @FUNC_kernel_dynprog_SCOP_0_KERNEL_0(i8 addrspace(1)* %MemRef_c, i32) #0 {
+; KERNEL-IR: %polly.access.MemRef_c = getelementptr i32, i32 addrspace(1)* %polly.access.cast.MemRef_c, i64 %10
+; KERNEL-IR-NEXT: store i32 %0, i32 addrspace(1)* %polly.access.MemRef_c, align 4
+
+define void @kernel_dynprog([50 x i32]* %c) {
+entry:
+  %arrayidx77 = getelementptr inbounds [50 x i32], [50 x i32]* %c, i64 0, i64 49
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.cond15.for.cond12.loopexit_crit_edge, %entry
+  %out_l.055 = phi i32 [ 0, %entry ], [ %add78, %for.cond15.for.cond12.loopexit_crit_edge ]
+  %iter.054 = phi i32 [ 0, %entry ], [ %inc80, %for.cond15.for.cond12.loopexit_crit_edge ]
+  br label %for.body17
+
+for.cond15.for.cond12.loopexit_crit_edge:         ; preds = %for.body17
+  %tmp = load i32, i32* %arrayidx77, align 4
+  %add78 = add nsw i32 %tmp, %out_l.055
+  %inc80 = add nuw nsw i32 %iter.054, 1
+  br i1 false, label %for.cond1.preheader, label %for.end81
+
+for.body17:                                       ; preds = %for.body17, %for.cond1.preheader
+  %indvars.iv71 = phi i64 [ 1, %for.cond1.preheader ], [ %indvars.iv.next72, %for.body17 ]
+  %arrayidx69 = getelementptr inbounds [50 x i32], [50 x i32]* %c, i64 0, i64 %indvars.iv71
+  store i32 undef, i32* %arrayidx69, align 4
+  %indvars.iv.next72 = add nuw nsw i64 %indvars.iv71, 1
+  %lftr.wideiv74 = trunc i64 %indvars.iv.next72 to i32
+  %exitcond75 = icmp ne i32 %lftr.wideiv74, 50
+  br i1 %exitcond75, label %for.body17, label %for.cond15.for.cond12.loopexit_crit_edge
+
+for.end81:                                        ; preds = %for.cond15.for.cond12.loopexit_crit_edge
+  ret void
+}
diff --git a/final/test/GPGPU/private-memory.ll b/final/test/GPGPU/private-memory.ll
new file mode 100644
index 0000000..2a34a1f
--- /dev/null
+++ b/final/test/GPGPU/private-memory.ll
@@ -0,0 +1,82 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -polly-acc-use-private \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg \
+; RUN: -polly-acc-use-private \
+; RUN: -disable-output -polly-acc-dump-kernel-ir < %s | \
+; RUN: FileCheck -check-prefix=KERNEL %s
+
+; REQUIRES: pollyacc
+
+;    void add(float *A) {
+;      for (long i = 0; i < 32; i++)
+;        for (long j = 0; j < 10; j++)
+;          A[i] += 1;
+;    }
+
+; CODE: # kernel0
+; CODE: {
+; CODE:     read(t0);
+; CODE:     for (int c3 = 0; c3 <= 9; c3 += 1)
+; CODE:       Stmt_bb5(t0, c3);
+; CODE:     write(t0);
+; CODE: }
+
+; KERNEL: %private_array = alloca [1 x float]
+
+; KERNEL:   %polly.access.cast.private_array = bitcast [1 x float]* %private_array to float*
+; KERNEL-NEXT:   %polly.access.private_array = getelementptr float, float* %polly.access.cast.private_array, i64 0
+; KERNEL-NEXT:   %polly.access.cast.MemRef_A = bitcast i8 addrspace(1)* %MemRef_A to float addrspace(1)*
+; KERNEL-NEXT:   %polly.access.MemRef_A = getelementptr float, float addrspace(1)* %polly.access.cast.MemRef_A, i64 %t0
+; KERNEL-NEXT:   %shared.read = load float, float addrspace(1)* %polly.access.MemRef_A
+; KERNEL-NEXT:   store float %shared.read, float* %polly.access.private_array
+
+; KERNEL:   %polly.access.cast.private_array5 = bitcast [1 x float]* %private_array to float*
+; KERNEL-NEXT:   %polly.access.private_array6 = getelementptr float, float* %polly.access.cast.private_array5, i64 0
+; KERNEL-NEXT:   %polly.access.cast.MemRef_A7 = bitcast i8 addrspace(1)* %MemRef_A to float addrspace(1)*
+; KERNEL-NEXT:   %polly.access.MemRef_A8 = getelementptr float, float addrspace(1)* %polly.access.cast.MemRef_A7, i64 %t0
+; KERNEL-NEXT:   %shared.write = load float, float* %polly.access.private_array6
+; KERNEL-NEXT:   store float %shared.write, float addrspace(1)* %polly.access.MemRef_A8
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @add(float* %A) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb11, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp12, %bb11 ]
+  %exitcond1 = icmp ne i64 %i.0, 32
+  br i1 %exitcond1, label %bb3, label %bb13
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb8, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp9, %bb8 ]
+  %exitcond = icmp ne i64 %j.0, 10
+  br i1 %exitcond, label %bb5, label %bb10
+
+bb5:                                              ; preds = %bb4
+  %tmp = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp6 = load float, float* %tmp, align 4
+  %tmp7 = fadd float %tmp6, 1.000000e+00
+  store float %tmp7, float* %tmp, align 4
+  br label %bb8
+
+bb8:                                              ; preds = %bb5
+  %tmp9 = add nuw nsw i64 %j.0, 1
+  br label %bb4
+
+bb10:                                             ; preds = %bb4
+  br label %bb11
+
+bb11:                                             ; preds = %bb10
+  %tmp12 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb13:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/GPGPU/privatization-simple.ll b/final/test/GPGPU/privatization-simple.ll
new file mode 100644
index 0000000..34f5437
--- /dev/null
+++ b/final/test/GPGPU/privatization-simple.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s -check-prefix=SCOP
+; RUN: opt %loadPolly -S -polly-codegen-ppcg < %s | FileCheck %s -check-prefix=HOST-IR
+
+; REQUIRES: pollyacc
+
+; SCOP:      Function: f
+; SCOP-NEXT: Region: %for.body---%for.end
+; SCOP-NEXT: Max Loop Depth:  1
+
+; Check that kernel launch is generated in host IR.
+; the declare would not be generated unless a call to a kernel exists.
+; HOST-IR: declare void @polly_launchKernel(i8*, i32, i32, i32, i32, i32, i8*)
+
+; void f(int A[], int B[], int control, int C[]) {
+;     int x;
+; #pragma scop
+;     for(int i = 0; i < 1000; i ++) {
+;         x = 0;
+;         if(control) x = C[i];
+;         B[i] = x * A[i];
+; 
+;     }
+; #pragma endscop
+; }
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %B, i32 %control, i32* %C) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %if.end
+  %indvars.iv = phi i64 [ 0, %entry.split ], [ %indvars.iv.next, %if.end ]
+  %tobool = icmp eq i32 %control, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %C, i64 %indvars.iv
+  %tmp4 = load i32, i32* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %for.body, %if.then
+  %x.0 = phi i32 [ %tmp4, %if.then ], [ 0, %for.body ]
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp8 = load i32, i32* %arrayidx2, align 4
+  %mul = mul nsw i32 %tmp8, %x.0
+  %arrayidx4 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  store i32 %mul, i32* %arrayidx4, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1000
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.end:                                          ; preds = %if.end
+  ret void
+}
diff --git a/final/test/GPGPU/privatization.ll b/final/test/GPGPU/privatization.ll
new file mode 100644
index 0000000..0b67b0b
--- /dev/null
+++ b/final/test/GPGPU/privatization.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s -check-prefix=SCOP
+; RUN: opt %loadPolly -S -polly-codegen-ppcg < %s | FileCheck %s -check-prefix=HOST-IR
+
+; REQUIRES: pollyacc
+
+; SCOP:      Function: checkPrivatization
+; SCOP-NEXT: Region: %for.body---%for.end
+; SCOP-NEXT: Max Loop Depth:  1
+
+
+; Check that kernel launch is generated in host IR.
+; the declare would not be generated unless a call to a kernel exists.
+; HOST-IR: declare void @polly_launchKernel(i8*, i32, i32, i32, i32, i32, i8*)
+
+; 
+;
+;    void checkPrivatization(int A[], int B[], int C[], int control) {
+;      int x;
+;    #pragma scop
+;      for (int i = 0; i < 1000; i++) {
+;        x = 0;
+;        if (control)
+;          x += C[i];
+;
+;        B[i] = x * A[i];
+;      }
+;    #pragma endscop
+;    }
+;
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @checkPrivatization(i32* %A, i32* %B, i32* %C, i32 %control) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %if.end
+  %indvars.iv = phi i64 [ 0, %entry.split ], [ %indvars.iv.next, %if.end ]
+  %tobool = icmp eq i32 %control, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %C, i64 %indvars.iv
+  %tmp4 = load i32, i32* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %for.body, %if.then
+  %x.0 = phi i32 [ %tmp4, %if.then ], [ 0, %for.body ]
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp9 = load i32, i32* %arrayidx2, align 4
+  %mul = mul nsw i32 %tmp9, %x.0
+  %arrayidx4 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  store i32 %mul, i32* %arrayidx4, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1000
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.end:                                          ; preds = %if.end
+  ret void
+}
diff --git a/final/test/GPGPU/region-stmt.ll b/final/test/GPGPU/region-stmt.ll
new file mode 100644
index 0000000..990a395
--- /dev/null
+++ b/final/test/GPGPU/region-stmt.ll
@@ -0,0 +1,81 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -S < %s | \
+; RUN: FileCheck %s -check-prefix=IR
+
+; CODE:        cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (128) * sizeof(float), cudaMemcpyHostToDevice));
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_B, MemRef_B, (128) * sizeof(float), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(4);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A, dev_MemRef_B);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_B, dev_MemRef_B, (128) * sizeof(float), cudaMemcpyDeviceToHost));
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_for_body__TO__if_end(32 * b0 + t0);
+
+; IR: @polly_initContext
+
+; KERNEL-IR: kernel_0
+
+; REQUIRES: pollyacc
+
+;    void foo(float A[], float B[]) {
+;      for (long i = 0; i < 128; i++)
+;        if (A[i] == 42)
+;          B[i] += 2 * i;
+;        else
+;          B[i] += 4 * i;
+;    }
+;
+source_filename = "/tmp/test.c"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A, float* %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %i.0, 128
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp = load float, float* %arrayidx, align 4
+  %cmp1 = fcmp oeq float %tmp, 4.200000e+01
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:                                          ; preds = %for.body
+  %mul = shl nsw i64 %i.0, 1
+  %conv = sitofp i64 %mul to float
+  %arrayidx2 = getelementptr inbounds float, float* %B, i64 %i.0
+  %tmp1 = load float, float* %arrayidx2, align 4
+  %add = fadd float %tmp1, %conv
+  store float %add, float* %arrayidx2, align 4
+  br label %if.end
+
+if.else:                                          ; preds = %for.body
+  %mul3 = shl nsw i64 %i.0, 2
+  %conv4 = sitofp i64 %mul3 to float
+  %arrayidx5 = getelementptr inbounds float, float* %B, i64 %i.0
+  %tmp2 = load float, float* %arrayidx5, align 4
+  %add6 = fadd float %tmp2, %conv4
+  store float %add6, float* %arrayidx5, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/GPGPU/remove-dead-instructions-in-stmt-2.ll b/final/test/GPGPU/remove-dead-instructions-in-stmt-2.ll
new file mode 100644
index 0000000..fba959c
--- /dev/null
+++ b/final/test/GPGPU/remove-dead-instructions-in-stmt-2.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck %s -check-prefix=KERNEL-IR
+
+; REQUIRES: pollyacc
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; KERNEL-IR: store i32 0, i32 addrspace(1)* %polly.access.MemRef_sum_c, align 4
+; KERNEL-IR-NEXT: br label %polly.merge
+
+define void @kernel_dynprog([50 x [50 x i32]]* %sum_c) {
+entry:
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %entry
+  br label %for.body3
+
+for.cond1.loopexit:                               ; preds = %for.end
+  %indvars.iv.next49 = add nuw nsw i64 %indvars.iv48, 1
+  %exitcond57 = icmp ne i64 %indvars.iv.next56, 49
+  br i1 %exitcond57, label %for.body3, label %for.inc55
+
+for.body3:                                        ; preds = %for.cond1.loopexit, %for.cond1.preheader
+  %indvars.iv55 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next56, %for.cond1.loopexit ]
+  %indvars.iv48 = phi i64 [ 1, %for.cond1.preheader ], [ %indvars.iv.next49, %for.cond1.loopexit ]
+  %indvars.iv.next56 = add nuw nsw i64 %indvars.iv55, 1
+  %arrayidx10 = getelementptr inbounds [50 x [50 x i32]], [50 x [50 x i32]]* %sum_c, i64 %indvars.iv55, i64 %indvars.iv48, i64 %indvars.iv55
+  store i32 0, i32* %arrayidx10, align 4
+  %cmp1334 = icmp slt i64 %indvars.iv.next56, %indvars.iv48
+  br label %for.end
+
+for.end:                                          ; preds = %for.body3
+  br label %for.cond1.loopexit
+
+for.inc55:                                        ; preds = %for.cond1.loopexit
+  ret void
+}
diff --git a/final/test/GPGPU/remove-dead-instructions-in-stmt.ll b/final/test/GPGPU/remove-dead-instructions-in-stmt.ll
new file mode 100644
index 0000000..9a0a1cd
--- /dev/null
+++ b/final/test/GPGPU/remove-dead-instructions-in-stmt.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck %s -check-prefix=KERNEL-IR
+
+; REQUIRES: pollyacc
+
+; Ensure that no dead instructions are emitted between the store and the
+; branch instruction of the ScopStmt. At some point, our dead-code-elimination
+; did not remove code that was inserted to compute the old (unused) branch
+; condition. This code referred to CPU registers and consequently resulted
+; in invalid bitcode.
+
+; KERNEL-IR: store i32 0, i32 addrspace(1)* %polly.access.MemRef_sum_c, align 4
+; KERNEL-IR-NEXT: br label %polly.merge
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @kernel_dynprog([50 x [50 x i32]]* %sum_c) {
+entry:
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %entry
+  br label %for.body3
+
+for.cond4.for.cond1.loopexit_crit_edge:           ; preds = %for.end
+  br label %for.cond1.loopexit
+
+for.cond1.loopexit:                               ; preds = %for.cond4.for.cond1.loopexit_crit_edge
+  br i1 undef, label %for.body3, label %for.inc55
+
+for.body3:                                        ; preds = %for.cond1.loopexit, %for.cond1.preheader
+  %indvars.iv55 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next56, %for.cond1.loopexit ]
+  %indvars.iv.next56 = add nuw nsw i64 %indvars.iv55, 1
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.end, %for.body3
+  %indvars.iv50 = phi i64 [ 0, %for.body3 ], [ %indvars.iv.next51, %for.end ]
+  %arrayidx10 = getelementptr inbounds [50 x [50 x i32]], [50 x [50 x i32]]* %sum_c, i64 %indvars.iv55, i64 %indvars.iv50, i64 %indvars.iv55
+  store i32 0, i32* %arrayidx10, align 4
+  %cmp1334 = icmp slt i64 %indvars.iv.next56, %indvars.iv50
+  br i1 %cmp1334, label %for.body14.lr.ph, label %for.end
+
+for.body14.lr.ph:                                 ; preds = %for.body6
+  br label %for.body14
+
+for.body14:                                       ; preds = %for.body14, %for.body14.lr.ph
+  %arrayidx32 = getelementptr inbounds [50 x [50 x i32]], [50 x [50 x i32]]* %sum_c, i64 %indvars.iv55, i64 %indvars.iv50, i64 0
+  br i1 false, label %for.body14, label %for.cond12.for.end_crit_edge
+
+for.cond12.for.end_crit_edge:                     ; preds = %for.body14
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond12.for.end_crit_edge, %for.body6
+  %indvars.iv.next51 = add nuw nsw i64 %indvars.iv50, 1
+  %lftr.wideiv53 = trunc i64 %indvars.iv.next51 to i32
+  %exitcond54 = icmp ne i32 %lftr.wideiv53, 50
+  br i1 %exitcond54, label %for.body6, label %for.cond4.for.cond1.loopexit_crit_edge
+
+for.inc55:                                        ; preds = %for.cond1.loopexit
+  unreachable
+}
diff --git a/final/test/GPGPU/run-time-check.ll b/final/test/GPGPU/run-time-check.ll
new file mode 100644
index 0000000..eb20867
--- /dev/null
+++ b/final/test/GPGPU/run-time-check.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -S < %s | \
+; RUN: FileCheck %s -check-prefix=IR
+;
+; REQUIRES: pollyacc
+;
+;    void foo(long n, float A[][32]) {
+;      for (long i = 0; i < n; i++)
+;        for (long j = 0; j < n; j++)
+;          A[i][j] += A[i + 1][j + 1];
+;    }
+
+; IR:       %tmp = icmp slt i64 %i.0, %n
+; IR-NEXT:  br i1 %tmp, label %bb2, label %polly.merge_new_and_old
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %n, [32 x float]* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb15, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp16, %bb15 ]
+  %tmp = icmp slt i64 %i.0, %n
+  br i1 %tmp, label %bb2, label %bb17
+
+bb2:                                              ; preds = %bb1
+  br label %bb3
+
+bb3:                                              ; preds = %bb12, %bb2
+  %j.0 = phi i64 [ 0, %bb2 ], [ %tmp13, %bb12 ]
+  %exitcond = icmp ne i64 %j.0, %n
+  br i1 %exitcond, label %bb4, label %bb14
+
+bb4:                                              ; preds = %bb3
+  %tmp5 = add nuw nsw i64 %j.0, 1
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  %tmp7 = getelementptr inbounds [32 x float], [32 x float]* %A, i64 %tmp6, i64 %tmp5
+  %tmp8 = load float, float* %tmp7, align 4
+  %tmp9 = getelementptr inbounds [32 x float], [32 x float]* %A, i64 %i.0, i64 %j.0
+  %tmp10 = load float, float* %tmp9, align 4
+  %tmp11 = fadd float %tmp10, %tmp8
+  store float %tmp11, float* %tmp9, align 4
+  br label %bb12
+
+bb12:                                             ; preds = %bb4
+  %tmp13 = add nuw nsw i64 %j.0, 1
+  br label %bb3
+
+bb14:                                             ; preds = %bb3
+  br label %bb15
+
+bb15:                                             ; preds = %bb14
+  %tmp16 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb17:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/GPGPU/scalar-param-and-value-32-bit.ll b/final/test/GPGPU/scalar-param-and-value-32-bit.ll
new file mode 100644
index 0000000..7aabde0
--- /dev/null
+++ b/final/test/GPGPU/scalar-param-and-value-32-bit.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck %s
+
+; REQUIRES: pollyacc,nvptx
+;
+;    void foo(float A[], int n) {
+;      for (long j = 0; j < n; j++)
+;        A[j + n] += 42;
+;    }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK: define ptx_kernel void @kernel_0(i8* %MemRef_A, i32 %n)
+
+define void @foo(float* %A, i32 %n) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb9, %bb
+  %j.0 = phi i64 [ 0, %bb ], [ %tmp10, %bb9 ]
+  %tmp = sext i32 %n to i64
+  %tmp2 = icmp slt i64 %j.0, %tmp
+  br i1 %tmp2, label %bb3, label %bb11
+
+bb3:                                              ; preds = %bb1
+  %tmp4 = sext i32 %n to i64
+  %tmp5 = add nsw i64 %j.0, %tmp4
+  %tmp6 = getelementptr inbounds float, float* %A, i64 %tmp5
+  %tmp7 = load float, float* %tmp6, align 4
+  %tmp8 = fadd float %tmp7, 4.200000e+01
+  store float %tmp8, float* %tmp6, align 4
+  br label %bb9
+
+bb9:                                              ; preds = %bb3
+  %tmp10 = add nuw nsw i64 %j.0, 1
+  br label %bb1
+
+bb11:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/GPGPU/scalar-param-and-value-use.ll b/final/test/GPGPU/scalar-param-and-value-use.ll
new file mode 100644
index 0000000..6853fcf
--- /dev/null
+++ b/final/test/GPGPU/scalar-param-and-value-use.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-kernel-ir \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=IR %s
+
+; REQUIRES: pollyacc,nvptx
+
+;    void foo(long n, float A[][n]) {
+;      for (long i = 0; i < 32; i++)
+;        for (long j = 0; j < 32; j++)
+;          A[i][j] += A[i + 1][j + 1];
+;    }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; This test case failed at some point as %n was only available in this kernel
+; when referenced through an isl_id in an isl ast expression, but not when
+; it was referenced from a SCEV  or instruction that not part of any loop
+; bound.
+
+; IR: %polly.access.mul.MemRef_A6 = mul nsw i64 {{.*}}, %n
+
+define void @foo(i64 %n, float* %A) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb19, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp20, %bb19 ]
+  %exitcond1 = icmp ne i64 %i.0, 32
+  br i1 %exitcond1, label %bb3, label %bb21
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb16, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp17, %bb16 ]
+  %exitcond = icmp ne i64 %j.0, 32
+  br i1 %exitcond, label %bb5, label %bb18
+
+bb5:                                              ; preds = %bb4
+  %tmp = add nuw nsw i64 %j.0, 1
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  %tmp7 = mul nsw i64 %tmp6, %n
+  %tmp8 = getelementptr inbounds float, float* %A, i64 %tmp7
+  %tmp9 = getelementptr inbounds float, float* %tmp8, i64 %tmp
+  %tmp10 = load float, float* %tmp9, align 4
+  %tmp11 = mul nsw i64 %i.0, %n
+  %tmp12 = getelementptr inbounds float, float* %A, i64 %tmp11
+  %tmp13 = getelementptr inbounds float, float* %tmp12, i64 %j.0
+  %tmp14 = load float, float* %tmp13, align 4
+  %tmp15 = fadd float %tmp14, %tmp10
+  store float %tmp15, float* %tmp13, align 4
+  br label %bb16
+
+bb16:                                             ; preds = %bb5
+  %tmp17 = add nuw nsw i64 %j.0, 1
+  br label %bb4
+
+bb18:                                             ; preds = %bb4
+  br label %bb19
+
+bb19:                                             ; preds = %bb18
+  %tmp20 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb21:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/GPGPU/scalar-parameter-fp128.ll b/final/test/GPGPU/scalar-parameter-fp128.ll
new file mode 100644
index 0000000..d43de16
--- /dev/null
+++ b/final/test/GPGPU/scalar-parameter-fp128.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code -disable-output %s
+
+; XFAIL: *
+
+; REQUIRES: pollyacc,nvptx
+
+; This fails today with "type mismatch between callee prototype and arguments"
+
+;    void foo(fp128 A[], fp128 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @fp128(fp128* %A, fp128 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds fp128, fp128* %A, i64 %i.0
+  %tmp3 = load fp128, fp128* %tmp, align 4
+  %tmp4 = fadd fp128 %tmp3, %b
+  store fp128 %tmp4, fp128* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
+
diff --git a/final/test/GPGPU/scalar-parameter-half.ll b/final/test/GPGPU/scalar-parameter-half.ll
new file mode 100644
index 0000000..d55ae1a
--- /dev/null
+++ b/final/test/GPGPU/scalar-parameter-half.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code -disable-output %s
+
+; REQUIRES: pollyacc,nvptx
+
+; This fails today with "unexpected type" in the LLVM PTX backend.
+
+;    void foo(half A[], half b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @half(half* %A, half %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds half, half* %A, i64 %i.0
+  %tmp3 = load half, half* %tmp, align 4
+  %tmp4 = fadd half %tmp3, %b
+  store half %tmp4, half* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
+
diff --git a/final/test/GPGPU/scalar-parameter-i120.ll b/final/test/GPGPU/scalar-parameter-i120.ll
new file mode 100644
index 0000000..087857a
--- /dev/null
+++ b/final/test/GPGPU/scalar-parameter-i120.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code -disable-output %s
+
+; XFAIL: *
+
+; REQUIRES: pollyacc,nvptx
+
+; This fails today with "type mismatch between callee prototype and arguments"
+
+;    void foo(i120 A[], i120 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @i120(i120* %A, i120 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i120 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i120 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i120, i120* %A, i120 %i.0
+  %tmp3 = load i120, i120* %tmp, align 4
+  %tmp4 = add i120 %tmp3, %b
+  store i120 %tmp4, i120* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i120 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
+
diff --git a/final/test/GPGPU/scalar-parameter-i128.ll b/final/test/GPGPU/scalar-parameter-i128.ll
new file mode 100644
index 0000000..55c1273
--- /dev/null
+++ b/final/test/GPGPU/scalar-parameter-i128.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code -disable-output %s
+
+; XFAIL: *
+
+; REQUIRES: pollyacc,nvptx
+
+; This fails today with "LowerFormalArguments didn't emit the correct number of
+;                        values!"
+
+;    void foo(i128 A[], i128 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @i128(i128* %A, i128 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i128 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i128 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i128, i128* %A, i128 %i.0
+  %tmp3 = load i128, i128* %tmp, align 4
+  %tmp4 = add i128 %tmp3, %b
+  store i128 %tmp4, i128* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i128 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/GPGPU/scalar-parameter-i3000.ll b/final/test/GPGPU/scalar-parameter-i3000.ll
new file mode 100644
index 0000000..4203c2f
--- /dev/null
+++ b/final/test/GPGPU/scalar-parameter-i3000.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code -disable-output %s
+
+; XFAIL: *
+
+; REQUIRES: pollyacc,nvptx
+
+; This fails today with "LowerFormalArguments didn't emit the correct number of
+;                        values!"
+
+;    void foo(i3000 A[], i3000 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @i3000(i3000* %A, i3000 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i3000 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i3000 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i3000, i3000* %A, i3000 %i.0
+  %tmp3 = load i3000, i3000* %tmp, align 4
+  %tmp4 = add i3000 %tmp3, %b
+  store i3000 %tmp4, i3000* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i3000 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/GPGPU/scalar-parameter-i80.ll b/final/test/GPGPU/scalar-parameter-i80.ll
new file mode 100644
index 0000000..b2f8f2c
--- /dev/null
+++ b/final/test/GPGPU/scalar-parameter-i80.ll
@@ -0,0 +1,40 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code -disable-output %s
+
+; XFAIL: *
+
+; REQUIRES: pollyacc,nvptx
+
+; This fails today with "LowerFormalArguments didn't emit the correct number of
+;                        values!"
+
+;    void foo(i80 A[], i80 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @i80(i80* %A, i80 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i80 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i80 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i80, i80* %A, i80 %i.0
+  %tmp3 = load i80, i80* %tmp, align 4
+  %tmp4 = add i80 %tmp3, %b
+  store i80 %tmp4, i80* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i80 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
+
diff --git a/final/test/GPGPU/scalar-parameter-ppc_fp128.ll b/final/test/GPGPU/scalar-parameter-ppc_fp128.ll
new file mode 100644
index 0000000..6290b18
--- /dev/null
+++ b/final/test/GPGPU/scalar-parameter-ppc_fp128.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code -disable-output %s
+
+; XFAIL: *
+
+; REQUIRES: pollyacc,nvptx
+
+; This fails today with "type mismatch between callee prototype and arguments"
+
+;    void foo(fp128 A[], fp128 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @ppc_fp128(ppc_fp128* %A, ppc_fp128 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds ppc_fp128, ppc_fp128* %A, i64 %i.0
+  %tmp3 = load ppc_fp128, ppc_fp128* %tmp, align 4
+  %tmp4 = fadd ppc_fp128 %tmp3, %b
+  store ppc_fp128 %tmp4, ppc_fp128* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/GPGPU/scalar-parameter-x86_fp80.ll b/final/test/GPGPU/scalar-parameter-x86_fp80.ll
new file mode 100644
index 0000000..d43de16
--- /dev/null
+++ b/final/test/GPGPU/scalar-parameter-x86_fp80.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code -disable-output %s
+
+; XFAIL: *
+
+; REQUIRES: pollyacc,nvptx
+
+; This fails today with "type mismatch between callee prototype and arguments"
+
+;    void foo(fp128 A[], fp128 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @fp128(fp128* %A, fp128 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds fp128, fp128* %A, i64 %i.0
+  %tmp3 = load fp128, fp128* %tmp, align 4
+  %tmp4 = fadd fp128 %tmp3, %b
+  store fp128 %tmp4, fp128* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
+
diff --git a/final/test/GPGPU/scalar-parameter.ll b/final/test/GPGPU/scalar-parameter.ll
new file mode 100644
index 0000000..73a51e8
--- /dev/null
+++ b/final/test/GPGPU/scalar-parameter.ll
@@ -0,0 +1,425 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg \
+; RUN: -S < %s | \
+; RUN: FileCheck -check-prefix=IR %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg \
+; RUN: -disable-output -polly-acc-dump-kernel-ir < %s | \
+; RUN: FileCheck -check-prefix=KERNEL %s
+
+; REQUIRES: pollyacc,nvptx
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; KERNEL: define ptx_kernel void @kernel_0(i8* %MemRef_A, float %MemRef_b)
+
+; CODE: Code
+; CODE-NEXT: ====
+; CODE-NEXT: # host
+; CODE-NEXT: {
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (1024) * sizeof(float), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(32);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A, MemRef_b);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (1024) * sizeof(float), cudaMemcpyDeviceToHost));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_bb2(32 * b0 + t0);
+
+;    void foo(float A[], float b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @float(float* %A, float %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp3 = load float, float* %tmp, align 4
+  %tmp4 = fadd float %tmp3, %b
+  store float %tmp4, float* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
+
+; KERNEL: define ptx_kernel void @kernel_0(i8* %MemRef_A, double %MemRef_b)
+; KERNEL-NEXT: entry:
+; KERNEL-NEXT:   %b.s2a = alloca double
+; KERNEL-NEXT:   store double %MemRef_b, double* %b.s2a
+
+; CODE: Code
+; CODE-NEXT: ====
+; CODE-NEXT: # host
+; CODE-NEXT: {
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (1024) * sizeof(double), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(32);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A, MemRef_b);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (1024) * sizeof(double), cudaMemcpyDeviceToHost));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_bb2(32 * b0 + t0);
+
+;    void foo(double A[], double b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @double(double* %A, double %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds double, double* %A, i64 %i.0
+  %tmp3 = load double, double* %tmp, align 4
+  %tmp4 = fadd double %tmp3, %b
+  store double %tmp4, double* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
+
+; CODE: Code
+; CODE-NEXT: ====
+; CODE-NEXT: # host
+; CODE-NEXT: {
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (1024) * sizeof(i1), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(32);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (1024) * sizeof(i1), cudaMemcpyDeviceToHost));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_bb2(32 * b0 + t0);
+
+;    void foo(i1 A[], i1 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @i1(i1* %A, i1 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i1, i1* %A, i64 %i.0
+  %tmp3 = load i1, i1* %tmp, align 4
+  %tmp4 = add i1 %tmp3, %b
+  store i1 %tmp4, i1* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
+
+; CODE: Code
+; CODE-NEXT: ====
+; CODE-NEXT: # host
+; CODE-NEXT: {
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (1024) * sizeof(i3), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(32);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (1024) * sizeof(i3), cudaMemcpyDeviceToHost));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_bb2(32 * b0 + t0);
+
+;    void foo(i3 A[], i3 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @i3(i3* %A, i3 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i3, i3* %A, i64 %i.0
+  %tmp3 = load i3, i3* %tmp, align 4
+  %tmp4 = add i3 %tmp3, %b
+  store i3 %tmp4, i3* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
+
+; CODE: Code
+; CODE-NEXT: ====
+; CODE-NEXT: # host
+; CODE-NEXT: {
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (1024) * sizeof(i8), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(32);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (1024) * sizeof(i8), cudaMemcpyDeviceToHost));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_bb2(32 * b0 + t0);
+
+;    void foo(i8 A[], i32 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @i8(i8* %A, i8 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i8, i8* %A, i64 %i.0
+  %tmp3 = load i8, i8* %tmp, align 4
+  %tmp4 = add i8 %tmp3, %b
+  store i8 %tmp4, i8* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
+
+; IR-LABEL: @i8
+
+; IR: [[REGA:%.+]] = call i8* @polly_getDevicePtr(i8* %p_dev_array_MemRef_A)
+; IR-NEXT: [[REGB:%.+]] = getelementptr [2 x i8*], [2 x i8*]* %polly_launch_0_params, i64 0, i64 0
+; IR-NEXT: store i8* [[REGA:%.+]], i8** %polly_launch_0_param_0
+; IR-NEXT: [[REGC:%.+]] = bitcast i8** %polly_launch_0_param_0 to i8*
+; IR-NEXT: store i8* [[REGC]], i8** [[REGB]]
+; IR-NEXT: store i8 %b, i8* %polly_launch_0_param_1
+; IR-NEXT: [[REGD:%.+]] = getelementptr [2 x i8*], [2 x i8*]* %polly_launch_0_params, i64 0, i64 1
+; IR-NEXT: store i8* %polly_launch_0_param_1, i8** [[REGD]]
+
+; CODE: Code
+; CODE-NEXT: ====
+; CODE-NEXT: # host
+; CODE-NEXT: {
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (1024) * sizeof(i32), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(32);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (1024) * sizeof(i32), cudaMemcpyDeviceToHost));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_bb2(32 * b0 + t0);
+
+;    void foo(i32 A[], i32 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @i32(i32* %A, i32 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %i.0
+  %tmp3 = load i32, i32* %tmp, align 4
+  %tmp4 = add i32 %tmp3, %b
+  store i32 %tmp4, i32* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
+
+; CODE: Code
+; CODE-NEXT: ====
+; CODE-NEXT: # host
+; CODE-NEXT: {
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (1024) * sizeof(i60), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(32);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (1024) * sizeof(i60), cudaMemcpyDeviceToHost));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_bb2(32 * b0 + t0);
+
+;    void foo(i60 A[], i60 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @i60(i60* %A, i60 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i60, i60* %A, i64 %i.0
+  %tmp3 = load i60, i60* %tmp, align 4
+  %tmp4 = add i60 %tmp3, %b
+  store i60 %tmp4, i60* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
+
+; CODE: Code
+; CODE-NEXT: ====
+; CODE-NEXT: # host
+; CODE-NEXT: {
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (1024) * sizeof(i64), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(32);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_A);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_A, dev_MemRef_A, (1024) * sizeof(i64), cudaMemcpyDeviceToHost));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_bb2(32 * b0 + t0);
+
+;    void foo(i64 A[], i64 b) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += b;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @i64(i64* %A, i64 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp6, %bb5 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i64, i64* %A, i64 %i.0
+  %tmp3 = load i64, i64* %tmp, align 4
+  %tmp4 = add i64 %tmp3, %b
+  store i64 %tmp4, i64* %tmp, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/GPGPU/scalar-writes-in-scop-requires-abort.ll b/final/test/GPGPU/scalar-writes-in-scop-requires-abort.ll
new file mode 100644
index 0000000..4d0b7c2
--- /dev/null
+++ b/final/test/GPGPU/scalar-writes-in-scop-requires-abort.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -S -polly-use-llvm-names -polly-scops  \
+; RUN: -polly-acc-dump-code -analyze \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=SCOP
+
+; RUN: opt %loadPolly -S -polly-use-llvm-names -polly-codegen-ppcg \
+; RUN: -polly-acc-dump-code \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=CODE
+
+; RUN: opt %loadPolly -S -polly-use-llvm-names -polly-codegen-ppcg \
+; RUN: -polly-invariant-load-hoisting < %s | FileCheck %s -check-prefix=HOST-IR
+
+; REQUIRES: pollyacc
+
+; SCOP:      Invariant Accesses: {
+; SCOP-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:             { Stmt_loop[i0] -> MemRef_p[0] };
+; SCOP-NEXT:         Execution Context: {  :  }
+; SCOP-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: {
+; CODE-NEXT:   if (32 * b0 + t0 <= 1025) {
+; CODE-NEXT:     Stmt_loop(32 * b0 + t0);
+; CODE-NEXT:     write(0);
+; CODE-NEXT:   }
+; CODE-NEXT:   sync0();
+; CODE-NEXT: }
+
+; Check that we generate a correct "always false" branch.
+; HOST-IR:  br i1 false, label %polly.start, label %loop.pre_entry_bb
+
+; This test case checks that we generate correct code if PPCGCodeGeneration
+; decides a build is unsuccessful with invariant load hoisting enabled.
+;
+; There is a conditional branch which switches between the original code and
+; the new code. We try to set this conditional branch to branch on false.
+; However, invariant load hoisting changes the structure of the scop, so we
+; need to change the way we *locate* this instruction.
+
+target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"
+target triple = "i386-apple-macosx10.12.0"
+
+define void @foo(float* %A, float* %p) {
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %entry], [%indvar.next, %loop]
+  %indvar.next = add i64 %indvar, 1
+  %invariant = load float, float* %p
+  %ptr = getelementptr float, float* %A, i64 %indvar
+  store float 42.0, float* %ptr
+  %cmp = icmp sle i64 %indvar, 1024
+  br i1 %cmp, label %loop, label %loop2
+
+loop2:
+  %indvar2 = phi i64 [0, %loop], [%indvar2.next, %loop2]
+  %indvar2f = phi float [%invariant, %loop], [%indvar2f, %loop2]
+  %indvar2.next = add i64 %indvar2, 1
+  store float %indvar2f, float* %A
+  %cmp2 = icmp sle i64 %indvar2, 1024
+  br i1 %cmp2, label %loop2, label %end
+
+end:
+  ret void
+}
diff --git a/final/test/GPGPU/scheduler-timeout.ll b/final/test/GPGPU/scheduler-timeout.ll
new file mode 100644
index 0000000..1c41eb3
--- /dev/null
+++ b/final/test/GPGPU/scheduler-timeout.ll
@@ -0,0 +1,174 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; REQUIRES: pollyacc
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; This test case took at some point forever to schedule, as the isl scheduler
+; seems to have problems if domain constraints appear in the dependences
+; provided to the scheduler.
+
+;   /* D := alpha*A*B*C + beta*D */
+;   for (i = 0; i < _PB_NI; i++)
+;     for (j = 0; j < _PB_NJ; j++)
+;       {
+;   tmp[i][j] = 0;
+;   for (k = 0; k < _PB_NK; ++k)
+;     tmp[i][j] += alpha * A[i][k] * B[k][j];
+;       }
+;   for (i = 0; i < _PB_NI; i++)
+;     for (j = 0; j < _PB_NL; j++)
+;       {
+;   D[i][j] *= beta;
+;   for (k = 0; k < _PB_NJ; ++k)
+;     D[i][j] += tmp[i][k] * C[k][j];
+;       }
+
+; CODE:        cudaCheckReturn(cudaMemcpy(dev_MemRef_A, MemRef_A, (4096) * (4096) * sizeof(float), cudaMemcpyHostToDevice));
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_B, MemRef_B, (4096) * (4096) * sizeof(float), cudaMemcpyHostToDevice));
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_D, MemRef_D, (4096) * (4096) * sizeof(float), cudaMemcpyHostToDevice));
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(dev_MemRef_C, MemRef_C, (4096) * (4096) * sizeof(float), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(16, 32);
+; CODE-NEXT:     dim3 k0_dimGrid(128, 128);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_tmp, dev_MemRef_A, MemRef_alpha, dev_MemRef_B);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   {
+; CODE-NEXT:     dim3 k1_dimBlock(16, 32);
+; CODE-NEXT:     dim3 k1_dimGrid(128, 128);
+; CODE-NEXT:     kernel1 <<<k1_dimGrid, k1_dimBlock>>> (dev_MemRef_tmp, dev_MemRef_D, MemRef_beta, dev_MemRef_C);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_tmp, dev_MemRef_tmp, (4096) * (4096) * sizeof(float), cudaMemcpyDeviceToHost));
+; CODE-NEXT:   cudaCheckReturn(cudaMemcpy(MemRef_D, dev_MemRef_D, (4096) * (4096) * sizeof(float), cudaMemcpyDeviceToHost));
+
+; CODE: # kernel0
+; CODE-NEXT: for (int c2 = 0; c2 <= 127; c2 += 1)
+; CODE-NEXT:   for (int c4 = 0; c4 <= 1; c4 += 1) {
+; CODE-NEXT:     if (c2 == 0)
+; CODE-NEXT:       Stmt_for_body6(32 * b0 + t0, 32 * b1 + t1 + 16 * c4);
+; CODE-NEXT:     for (int c5 = 0; c5 <= 31; c5 += 1)
+; CODE-NEXT:       Stmt_for_body11(32 * b0 + t0, 32 * b1 + t1 + 16 * c4, 32 * c2 + c5);
+; CODE-NEXT:   }
+
+; CODE: # kernel1
+; CODE-NEXT: for (int c2 = 0; c2 <= 127; c2 += 1)
+; CODE-NEXT:   for (int c4 = 0; c4 <= 1; c4 += 1) {
+; CODE-NEXT:     if (c2 == 0)
+; CODE-NEXT:       Stmt_for_body36(32 * b0 + t0, 32 * b1 + t1 + 16 * c4);
+; CODE-NEXT:     for (int c5 = 0; c5 <= 31; c5 += 1)
+; CODE-NEXT:       Stmt_for_body44(32 * b0 + t0, 32 * b1 + t1 + 16 * c4, 32 * c2 + c5);
+; CODE-NEXT:   }
+
+
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start(i64, i8* nocapture) #0
+
+; Function Attrs: nounwind uwtable
+define internal void @kernel_2mm(i32 %ni, i32 %nj, i32 %nk, i32 %nl, float %alpha, float %beta, [4096 x float]* %tmp, [4096 x float]* %A, [4096 x float]* %B, [4096 x float]* %C, [4096 x float]* %D) #1 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond4.preheader
+
+for.cond4.preheader:                              ; preds = %entry.split, %for.inc28
+  %indvars.iv19 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next20, %for.inc28 ]
+  br label %for.body6
+
+for.cond31.preheader:                             ; preds = %for.inc28
+  br label %for.cond34.preheader
+
+for.body6:                                        ; preds = %for.cond4.preheader, %for.inc25
+  %indvars.iv16 = phi i64 [ 0, %for.cond4.preheader ], [ %indvars.iv.next17, %for.inc25 ]
+  %arrayidx8 = getelementptr inbounds [4096 x float], [4096 x float]* %tmp, i64 %indvars.iv19, i64 %indvars.iv16
+  store float 0.000000e+00, float* %arrayidx8, align 4, !tbaa !1
+  br label %for.body11
+
+for.body11:                                       ; preds = %for.body6, %for.body11
+  %indvars.iv13 = phi i64 [ 0, %for.body6 ], [ %indvars.iv.next14, %for.body11 ]
+  %arrayidx15 = getelementptr inbounds [4096 x float], [4096 x float]* %A, i64 %indvars.iv19, i64 %indvars.iv13
+  %tmp22 = load float, float* %arrayidx15, align 4, !tbaa !1
+  %mul = fmul float %tmp22, %alpha
+  %arrayidx19 = getelementptr inbounds [4096 x float], [4096 x float]* %B, i64 %indvars.iv13, i64 %indvars.iv16
+  %tmp23 = load float, float* %arrayidx19, align 4, !tbaa !1
+  %mul20 = fmul float %mul, %tmp23
+  %arrayidx24 = getelementptr inbounds [4096 x float], [4096 x float]* %tmp, i64 %indvars.iv19, i64 %indvars.iv16
+  %tmp24 = load float, float* %arrayidx24, align 4, !tbaa !1
+  %add = fadd float %tmp24, %mul20
+  store float %add, float* %arrayidx24, align 4, !tbaa !1
+  %indvars.iv.next14 = add nuw nsw i64 %indvars.iv13, 1
+  %exitcond15 = icmp ne i64 %indvars.iv.next14, 4096
+  br i1 %exitcond15, label %for.body11, label %for.inc25
+
+for.inc25:                                        ; preds = %for.body11
+  %indvars.iv.next17 = add nuw nsw i64 %indvars.iv16, 1
+  %exitcond18 = icmp ne i64 %indvars.iv.next17, 4096
+  br i1 %exitcond18, label %for.body6, label %for.inc28
+
+for.inc28:                                        ; preds = %for.inc25
+  %indvars.iv.next20 = add nuw nsw i64 %indvars.iv19, 1
+  %exitcond21 = icmp ne i64 %indvars.iv.next20, 4096
+  br i1 %exitcond21, label %for.cond4.preheader, label %for.cond31.preheader
+
+for.cond34.preheader:                             ; preds = %for.cond31.preheader, %for.inc65
+  %indvars.iv10 = phi i64 [ 0, %for.cond31.preheader ], [ %indvars.iv.next11, %for.inc65 ]
+  br label %for.body36
+
+for.body36:                                       ; preds = %for.cond34.preheader, %for.inc62
+  %indvars.iv7 = phi i64 [ 0, %for.cond34.preheader ], [ %indvars.iv.next8, %for.inc62 ]
+  %arrayidx40 = getelementptr inbounds [4096 x float], [4096 x float]* %D, i64 %indvars.iv10, i64 %indvars.iv7
+  %tmp25 = load float, float* %arrayidx40, align 4, !tbaa !1
+  %mul41 = fmul float %tmp25, %beta
+  store float %mul41, float* %arrayidx40, align 4, !tbaa !1
+  br label %for.body44
+
+for.body44:                                       ; preds = %for.body36, %for.body44
+  %indvars.iv = phi i64 [ 0, %for.body36 ], [ %indvars.iv.next, %for.body44 ]
+  %arrayidx48 = getelementptr inbounds [4096 x float], [4096 x float]* %tmp, i64 %indvars.iv10, i64 %indvars.iv
+  %tmp26 = load float, float* %arrayidx48, align 4, !tbaa !1
+  %arrayidx52 = getelementptr inbounds [4096 x float], [4096 x float]* %C, i64 %indvars.iv, i64 %indvars.iv7
+  %tmp27 = load float, float* %arrayidx52, align 4, !tbaa !1
+  %mul53 = fmul float %tmp26, %tmp27
+  %arrayidx57 = getelementptr inbounds [4096 x float], [4096 x float]* %D, i64 %indvars.iv10, i64 %indvars.iv7
+  %tmp28 = load float, float* %arrayidx57, align 4, !tbaa !1
+  %add58 = fadd float %tmp28, %mul53
+  store float %add58, float* %arrayidx57, align 4, !tbaa !1
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 4096
+  br i1 %exitcond, label %for.body44, label %for.inc62
+
+for.inc62:                                        ; preds = %for.body44
+  %indvars.iv.next8 = add nuw nsw i64 %indvars.iv7, 1
+  %exitcond9 = icmp ne i64 %indvars.iv.next8, 4096
+  br i1 %exitcond9, label %for.body36, label %for.inc65
+
+for.inc65:                                        ; preds = %for.inc62
+  %indvars.iv.next11 = add nuw nsw i64 %indvars.iv10, 1
+  %exitcond12 = icmp ne i64 %indvars.iv.next11, 4096
+  br i1 %exitcond12, label %for.cond34.preheader, label %for.end67
+
+for.end67:                                        ; preds = %for.inc65
+  ret void
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end(i64, i8* nocapture) #0
+
+attributes #0 = { argmemonly nounwind }
+attributes #1 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.9.0 (trunk 275267) (llvm/trunk 275268)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"float", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/GPGPU/shared-memory-scalar.ll b/final/test/GPGPU/shared-memory-scalar.ll
new file mode 100644
index 0000000..f28be87
--- /dev/null
+++ b/final/test/GPGPU/shared-memory-scalar.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -polly-acc-use-shared \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; REQUIRES: pollyacc
+
+;    void add(float *A, float alpha) {
+;      for (long i = 0; i < 32; i++)
+;        for (long j = 0; j < 10; j++)
+;          A[i] += alpha;
+;    }
+
+; CODE:       read(t0);
+; CODE-NEXT:  sync0();
+; CODE-NEXT:  for (int c3 = 0; c3 <= 9; c3 += 1)
+; CODE-NEXT:    Stmt_bb5(t0, c3);
+; CODE-NEXT:  sync1();
+; CODE-NEXT:  write(t0);
+
+; This test case was intended to test code generation for scalars stored
+; in shared memory. However, after properly marking the scalar as read-only
+; the scalar is not stored any more in shared memory. We still leave this
+; test case as documentation if we every forget to mark scalars as read-only.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @add(float* %A, float %alpha) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb11, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp12, %bb11 ]
+  %exitcond1 = icmp ne i64 %i.0, 32
+  br i1 %exitcond1, label %bb3, label %bb13
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb8, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp9, %bb8 ]
+  %exitcond = icmp ne i64 %j.0, 10
+  br i1 %exitcond, label %bb5, label %bb10
+
+bb5:                                              ; preds = %bb4
+  %tmp = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp6 = load float, float* %tmp, align 4
+  %tmp7 = fadd float %tmp6, %alpha
+  store float %tmp7, float* %tmp, align 4
+  br label %bb8
+
+bb8:                                              ; preds = %bb5
+  %tmp9 = add nuw nsw i64 %j.0, 1
+  br label %bb4
+
+bb10:                                             ; preds = %bb4
+  br label %bb11
+
+bb11:                                             ; preds = %bb10
+  %tmp12 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb13:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/GPGPU/shared-memory-two-dimensional.ll b/final/test/GPGPU/shared-memory-two-dimensional.ll
new file mode 100644
index 0000000..0fe60bd
--- /dev/null
+++ b/final/test/GPGPU/shared-memory-two-dimensional.ll
@@ -0,0 +1,103 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -polly-acc-use-shared \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg \
+; RUN: -polly-acc-use-shared \
+; RUN: -disable-output -polly-acc-dump-kernel-ir < %s | \
+; RUN: FileCheck -check-prefix=KERNEL %s
+
+; REQUIRES: pollyacc
+
+;    void foo(float A[], float b[][8]) {
+;      for (long i = 0; i < 32; i++)
+;        for (long j = 0; j < 16; j++)
+;          for (long k = 0; k < 8; k++)
+;            A[i] += j * k * b[j][k];
+;    }
+
+
+; CODE:      # kernel0
+; CODE-NEXT: {
+; CODE-NEXT:   if (t0 <= 7)
+; CODE-NEXT:     for (int c0 = 0; c0 <= 15; c0 += 1)
+; CODE-NEXT:       read(c0, t0);
+; CODE-NEXT:   read(t0);
+; CODE-NEXT:   sync0();
+; CODE-NEXT:   for (int c3 = 0; c3 <= 15; c3 += 1)
+; CODE-NEXT:     for (int c4 = 0; c4 <= 7; c4 += 1)
+; CODE-NEXT:       Stmt_bb8(t0, c3, c4);
+; CODE-NEXT:   sync1();
+; CODE-NEXT:   write(t0);
+; CODE-NEXT: }
+
+; KERNEL: @shared_MemRef_b = internal addrspace(3) global [16 x [8 x float]] zeroinitializer, align 4
+
+; KERNEL:        %polly.access.mul.MemRef_b = mul nsw i64 %polly.indvar, 8
+; KERNEL-NEXT:   %polly.access.add.MemRef_b = add nsw i64 %polly.access.mul.MemRef_b, %t0
+; KERNEL-NEXT:   %polly.access.MemRef_b = getelementptr float, float addrspace(1)* %polly.access.cast.MemRef_b, i64 %polly.access.add.MemRef_b
+; KERNEL-NEXT:   %shared.read = load float, float addrspace(1)* %polly.access.MemRef_b
+; KERNEL-NEXT:   store float %shared.read, float addrspace(3)* %polly.access.shared_MemRef_b
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A, [8 x float]* %b) {
+bb:
+  br label %bb3
+
+bb3:                                              ; preds = %bb22, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp23, %bb22 ]
+  %exitcond2 = icmp ne i64 %i.0, 32
+  br i1 %exitcond2, label %bb4, label %bb24
+
+bb4:                                              ; preds = %bb3
+  br label %bb5
+
+bb5:                                              ; preds = %bb19, %bb4
+  %j.0 = phi i64 [ 0, %bb4 ], [ %tmp20, %bb19 ]
+  %exitcond1 = icmp ne i64 %j.0, 16
+  br i1 %exitcond1, label %bb6, label %bb21
+
+bb6:                                              ; preds = %bb5
+  br label %bb7
+
+bb7:                                              ; preds = %bb16, %bb6
+  %k.0 = phi i64 [ 0, %bb6 ], [ %tmp17, %bb16 ]
+  %exitcond = icmp ne i64 %k.0, 8
+  br i1 %exitcond, label %bb8, label %bb18
+
+bb8:                                              ; preds = %bb7
+  %tmp = mul nuw nsw i64 %j.0, %k.0
+  %tmp9 = sitofp i64 %tmp to float
+  %tmp10 = getelementptr inbounds [8 x float], [8 x float]* %b, i64 %j.0, i64 %k.0
+  %tmp11 = load float, float* %tmp10, align 4
+  %tmp12 = fmul float %tmp9, %tmp11
+  %tmp13 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp14 = load float, float* %tmp13, align 4
+  %tmp15 = fadd float %tmp14, %tmp12
+  store float %tmp15, float* %tmp13, align 4
+  br label %bb16
+
+bb16:                                             ; preds = %bb8
+  %tmp17 = add nuw nsw i64 %k.0, 1
+  br label %bb7
+
+bb18:                                             ; preds = %bb7
+  br label %bb19
+
+bb19:                                             ; preds = %bb18
+  %tmp20 = add nuw nsw i64 %j.0, 1
+  br label %bb5
+
+bb21:                                             ; preds = %bb5
+  br label %bb22
+
+bb22:                                             ; preds = %bb21
+  %tmp23 = add nuw nsw i64 %i.0, 1
+  br label %bb3
+
+bb24:                                             ; preds = %bb3
+  ret void
+}
diff --git a/final/test/GPGPU/shared-memory.ll b/final/test/GPGPU/shared-memory.ll
new file mode 100644
index 0000000..bdcfb0c
--- /dev/null
+++ b/final/test/GPGPU/shared-memory.ll
@@ -0,0 +1,83 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -polly-acc-use-shared \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg \
+; RUN: -polly-acc-use-shared \
+; RUN: -disable-output -polly-acc-dump-kernel-ir < %s | \
+; RUN: FileCheck -check-prefix=KERNEL %s
+
+; REQUIRES: pollyacc
+
+;    void add(float *A) {
+;      for (long i = 0; i < 32; i++)
+;        for (long j = 0; j < 10; j++)
+;          A[i] += 1;
+;    }
+
+; CODE: # kernel0
+; CODE: {
+; CODE:   read(t0);
+; CODE:   sync0();
+; CODE:   for (int c3 = 0; c3 <= 9; c3 += 1)
+; CODE:     Stmt_bb5(t0, c3);
+; CODE:   sync1();
+; CODE:   write(t0);
+; CODE: }
+
+; KERNEL: @shared_MemRef_A = internal addrspace(3) global [32 x float] zeroinitializer, align 4
+
+; KERNEL:   %polly.access.shared_MemRef_A = getelementptr float, float addrspace(3)* getelementptr inbounds ([32 x float], [32 x float] addrspace(3)* @shared_MemRef_A, i32 0, i32 0), i64 %t0
+; KERNEL-NEXT:   %polly.access.cast.MemRef_A = bitcast i8 addrspace(1)* %MemRef_A to float addrspace(1)*
+; KERNEL-NEXT:   %polly.access.MemRef_A = getelementptr float, float addrspace(1)* %polly.access.cast.MemRef_A, i64 %t0
+; KERNEL-NEXT:   %shared.read = load float, float addrspace(1)* %polly.access.MemRef_A
+; KERNEL-NEXT:   store float %shared.read, float addrspace(3)* %polly.access.shared_MemRef_A
+
+; KERNEL:   %polly.access.shared_MemRef_A3 = getelementptr float, float addrspace(3)* getelementptr inbounds ([32 x float], [32 x float] addrspace(3)* @shared_MemRef_A, i32 0, i32 0), i64 %t0
+; KERNEL-NEXT:   %polly.access.cast.MemRef_A4 = bitcast i8 addrspace(1)* %MemRef_A to float addrspace(1)*
+; KERNEL-NEXT:   %polly.access.MemRef_A5 = getelementptr float, float addrspace(1)* %polly.access.cast.MemRef_A4, i64 %t0
+; KERNEL-NEXT:   %shared.write = load float, float addrspace(3)* %polly.access.shared_MemRef_A3
+; KERNEL-NEXT:   store float %shared.write, float addrspace(1)* %polly.access.MemRef_A5
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @add(float* %A) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb11, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp12, %bb11 ]
+  %exitcond1 = icmp ne i64 %i.0, 32
+  br i1 %exitcond1, label %bb3, label %bb13
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb8, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp9, %bb8 ]
+  %exitcond = icmp ne i64 %j.0, 10
+  br i1 %exitcond, label %bb5, label %bb10
+
+bb5:                                              ; preds = %bb4
+  %tmp = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp6 = load float, float* %tmp, align 4
+  %tmp7 = fadd float %tmp6, 1.000000e+00
+  store float %tmp7, float* %tmp, align 4
+  br label %bb8
+
+bb8:                                              ; preds = %bb5
+  %tmp9 = add nuw nsw i64 %j.0, 1
+  br label %bb4
+
+bb10:                                             ; preds = %bb4
+  br label %bb11
+
+bb11:                                             ; preds = %bb10
+  %tmp12 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb13:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/GPGPU/simple-managed-memory-rewrite.ll b/final/test/GPGPU/simple-managed-memory-rewrite.ll
new file mode 100644
index 0000000..5b28f59
--- /dev/null
+++ b/final/test/GPGPU/simple-managed-memory-rewrite.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -analyze  -polly-process-unprofitable \
+; RUN: -polly-scops -polly-use-llvm-names < %s |  FileCheck %s --check-prefix=SCOP
+
+; RUN: opt %loadPolly -S  -polly-process-unprofitable -polly-acc-mincompute=0 \
+; RUN: -polly-target=gpu  -polly-codegen-ppcg -polly-acc-codegen-managed-memory \
+; RUN: -polly-acc-rewrite-managed-memory < %s | FileCheck %s --check-prefix=HOST-IR
+
+; REQUIRES: pollyacc
+
+; SCOP:      Function: f
+; SCOP-NEXT: Region: %for.body---%for.end
+; SCOP-NEXT: Max Loop Depth:  1
+; SCOP: i32 MemRef_A[*];
+
+; Check that we generate a constructor call for @A.toptr
+; HOST-IR: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* {{.*}}, i8* bitcast (i32** @A.toptr to i8*) }]
+
+; Check that we generate a constructor
+; 4 bytes * 100 = 400
+; HOST-IR: define void {{.*}}constructor() {
+; HOST-IR-NEXT: entry:
+; HOST-IR-NEXT:   %mem.raw = call i8* @polly_mallocManaged(i64 400)
+; HOST-IR-NEXT:   %mem.typed = bitcast i8* %mem.raw to i32*
+; HOST-IR-NEXT:   store i32* %mem.typed, i32** @A.toptr
+; HOST-IR-NEXT:   ret void
+; HOST-IR-NEXT: }
+
+; HOST-IR-NOT: @A
+
+source_filename = "test.c"
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.12.0"
+
+@A = internal global [100 x i32] zeroinitializer, align 16
+
+define void @f() {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %indvars.iv1 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds [100 x i32], [100 x i32]* @A, i64 0, i64 %indvars.iv1
+  store i32 42, i32* %arrayidx, align 4, !tbaa !3
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv1, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 100
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.body
+  ret void
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #0
+
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #0
+
+attributes #0 = { argmemonly nounwind }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 7, !"PIC Level", i32 2}
+!2 = !{!"clang version 6.0.0 (http://llvm.org/git/clang.git 6660f0d30ef23b3142a6b08f9f41aad3d47c084f) (http://llvm.org/git/llvm.git 052dd78cb30f77a05dc8bb06b851402c4b6c6587)"}
+!3 = !{!4, !4, i64 0}
+!4 = !{!"int", !5, i64 0}
+!5 = !{!"omnipotent char", !6, i64 0}
+!6 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/GPGPU/size-cast.ll b/final/test/GPGPU/size-cast.ll
new file mode 100644
index 0000000..0312dc8
--- /dev/null
+++ b/final/test/GPGPU/size-cast.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; RUN: opt %loadPolly -polly-codegen-ppcg -S < %s | \
+; RUN: FileCheck %s -check-prefix=IR
+
+; REQUIRES: pollyacc
+
+; This test case ensures that we properly sign-extend the types we are using.
+
+; CODE:      if (arg >= 1 && arg1 == 0) {
+; CODE:        cudaCheckReturn(cudaMemcpy(dev_MemRef_arg3, MemRef_arg3, (arg) * sizeof(double), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(32);
+; CODE-NEXT:     dim3 k0_dimGrid(arg >= 1048546 ? 32768 : (arg + 31) / 32);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_arg3, dev_MemRef_arg2, arg, arg1);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_arg2, dev_MemRef_arg2, (arg) * sizeof(double), cudaMemcpyDeviceToHost));
+; CODE-NEXT  cudaCheckReturn(cudaFree(dev_MemRef_arg3));
+; CODE-NEXT  cudaCheckReturn(cudaFree(dev_MemRef_arg2));
+
+; CODE: # kernel0
+; CODE-NEXT: for (int c0 = 0; c0 <= (arg - 32 * b0 - 1) / 1048576; c0 += 1)
+; CODE-NEXT:   if (arg >= 32 * b0 + t0 + 1048576 * c0 + 1)
+; CODE-NEXT:     Stmt_bb6(0, 32 * b0 + t0 + 1048576 * c0);
+
+; IR-LABEL:  call i8* @polly_initContextCUDA()
+; IR:        sext i32 %arg to i64
+; IR-NEXT:   mul i64
+; IR-NEXT:   @polly_allocateMemoryForDevice
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @hoge(i32 %arg, i32 %arg1, [1000 x double]* %arg2, double* %arg3) {
+bb:
+  br label %bb4
+
+bb4:                                              ; preds = %bb13, %bb
+  br label %bb6
+
+bb5:                                              ; preds = %bb13
+  ret void
+
+bb6:                                              ; preds = %bb6, %bb4
+  %tmp = phi i64 [ 0, %bb4 ], [ %tmp10, %bb6 ]
+  %tmp7 = getelementptr inbounds double, double* %arg3, i64 %tmp
+  %tmp8 = load double, double* %tmp7, align 8
+  %tmp9 = getelementptr inbounds [1000 x double], [1000 x double]* %arg2, i64 0, i64 %tmp
+  store double undef, double* %tmp9, align 8
+  %tmp10 = add nuw nsw i64 %tmp, 1
+  %tmp11 = zext i32 %arg to i64
+  %tmp12 = icmp ne i64 %tmp10, %tmp11
+  br i1 %tmp12, label %bb6, label %bb13
+
+bb13:                                             ; preds = %bb6
+  %tmp14 = zext i32 %arg1 to i64
+  %tmp15 = icmp ne i64 0, %tmp14
+  br i1 %tmp15, label %bb4, label %bb5
+}
diff --git a/final/test/GPGPU/spir-codegen.ll b/final/test/GPGPU/spir-codegen.ll
new file mode 100644
index 0000000..e6188e8
--- /dev/null
+++ b/final/test/GPGPU/spir-codegen.ll
@@ -0,0 +1,118 @@
+; RUN: opt %loadPolly -O3 -polly -polly-target=gpu \
+; RUN: -polly-gpu-arch=spir32 \
+; RUN: -polly-acc-dump-kernel-ir -polly-process-unprofitable -disable-output < %s | \
+; RUN: FileCheck %s
+
+; REQUIRES: pollyacc
+
+; CHECK:      target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024"
+; CHECK-NEXT: target triple = "spir-unknown-unknown"
+
+; CHECK-LABEL: define spir_kernel void @FUNC_double_parallel_loop_SCOP_0_KERNEL_0(i8 addrspace(1)* %MemRef_A) #0 !kernel_arg_addr_space !0 !kernel_arg_name !1 !kernel_arg_access_qual !1 !kernel_arg_type !1 !kernel_arg_type_qual !1 !kernel_arg_base_type !1 {
+; CHECK-NEXT: entry:
+; CHECK-NEXT:   %0 = call i32 @__gen_ocl_get_group_id0()
+; CHECK-NEXT:   %__gen_ocl_get_group_id0 = zext i32 %0 to i64
+; CHECK-NEXT:   %1 = call i32 @__gen_ocl_get_group_id1()
+; CHECK-NEXT:   %__gen_ocl_get_group_id1 = zext i32 %1 to i64
+; CHECK-NEXT:   %2 = call i32 @__gen_ocl_get_local_id0()
+; CHECK-NEXT:   %__gen_ocl_get_local_id0 = zext i32 %2 to i64
+; CHECK-NEXT:   %3 = call i32 @__gen_ocl_get_local_id1()
+; CHECK-NEXT:   %__gen_ocl_get_local_id1 = zext i32 %3 to i64
+; CHECK-NEXT:   br label %polly.loop_preheader
+
+; CHECK-LABEL: polly.loop_exit:                                  ; preds = %polly.stmt.bb5
+; CHECK-NEXT:   ret void
+
+; CHECK-LABEL: polly.loop_header:                                ; preds = %polly.stmt.bb5, %polly.loop_preheader
+; CHECK-NEXT:   %polly.indvar = phi i64 [ 0, %polly.loop_preheader ], [ %polly.indvar_next, %polly.stmt.bb5 ]
+; CHECK-NEXT:   %4 = mul nsw i64 32, %__gen_ocl_get_group_id0
+; CHECK-NEXT:   %5 = add nsw i64 %4, %__gen_ocl_get_local_id0
+; CHECK-NEXT:   %6 = mul nsw i64 32, %__gen_ocl_get_group_id1
+; CHECK-NEXT:   %7 = add nsw i64 %6, %__gen_ocl_get_local_id1
+; CHECK-NEXT:   %8 = mul nsw i64 16, %polly.indvar
+; CHECK-NEXT:   %9 = add nsw i64 %7, %8
+; CHECK-NEXT:   br label %polly.stmt.bb5
+
+; CHECK-LABEL: polly.stmt.bb5:                                   ; preds = %polly.loop_header
+; CHECK-NEXT:   %10 = mul i64 %5, %9
+; CHECK-NEXT:   %p_tmp6 = sitofp i64 %10 to float
+; CHECK-NEXT:   %polly.access.cast.MemRef_A = bitcast i8 addrspace(1)* %MemRef_A to float addrspace(1)*
+; CHECK-NEXT:   %11 = mul nsw i64 32, %__gen_ocl_get_group_id0
+; CHECK-NEXT:   %12 = add nsw i64 %11, %__gen_ocl_get_local_id0
+; CHECK-NEXT:   %polly.access.mul.MemRef_A = mul nsw i64 %12, 1024
+; CHECK-NEXT:   %13 = mul nsw i64 32, %__gen_ocl_get_group_id1
+; CHECK-NEXT:   %14 = add nsw i64 %13, %__gen_ocl_get_local_id1
+; CHECK-NEXT:   %15 = mul nsw i64 16, %polly.indvar
+; CHECK-NEXT:   %16 = add nsw i64 %14, %15
+; CHECK-NEXT:   %polly.access.add.MemRef_A = add nsw i64 %polly.access.mul.MemRef_A, %16
+; CHECK-NEXT:   %polly.access.MemRef_A = getelementptr float, float addrspace(1)* %polly.access.cast.MemRef_A, i64 %polly.access.add.MemRef_A
+; CHECK-NEXT:   %tmp8_p_scalar_ = load float, float addrspace(1)* %polly.access.MemRef_A, align 4
+; CHECK-NEXT:   %p_tmp9 = fadd float %tmp8_p_scalar_, %p_tmp6
+; CHECK-NEXT:   %polly.access.cast.MemRef_A1 = bitcast i8 addrspace(1)* %MemRef_A to float addrspace(1)*
+; CHECK-NEXT:   %17 = mul nsw i64 32, %__gen_ocl_get_group_id0
+; CHECK-NEXT:   %18 = add nsw i64 %17, %__gen_ocl_get_local_id0
+; CHECK-NEXT:   %polly.access.mul.MemRef_A2 = mul nsw i64 %18, 1024
+; CHECK-NEXT:   %19 = mul nsw i64 32, %__gen_ocl_get_group_id1
+; CHECK-NEXT:   %20 = add nsw i64 %19, %__gen_ocl_get_local_id1
+; CHECK-NEXT:   %21 = mul nsw i64 16, %polly.indvar
+; CHECK-NEXT:   %22 = add nsw i64 %20, %21
+; CHECK-NEXT:   %polly.access.add.MemRef_A3 = add nsw i64 %polly.access.mul.MemRef_A2, %22
+; CHECK-NEXT:   %polly.access.MemRef_A4 = getelementptr float, float addrspace(1)* %polly.access.cast.MemRef_A1, i64 %polly.access.add.MemRef_A3
+; CHECK-NEXT:   store float %p_tmp9, float addrspace(1)* %polly.access.MemRef_A4, align 4
+; CHECK-NEXT:   %polly.indvar_next = add nsw i64 %polly.indvar, 1
+; CHECK-NEXT:   %polly.loop_cond = icmp sle i64 %polly.indvar_next, 1
+; CHECK-NEXT:   br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit
+
+; CHECK-LABEL: polly.loop_preheader:                             ; preds = %entry
+; CHECK-NEXT:   br label %polly.loop_header
+
+; CHECK: attributes #0 = { "polly.skip.fn" }
+
+;    void double_parallel_loop(float A[][1024]) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          A[i][j] += i * j;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @double_parallel_loop([1024 x float]* %A) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb13, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp14, %bb13 ]
+  %exitcond1 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond1, label %bb3, label %bb15
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb10, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp11, %bb10 ]
+  %exitcond = icmp ne i64 %j.0, 1024
+  br i1 %exitcond, label %bb5, label %bb12
+
+bb5:                                              ; preds = %bb4
+  %tmp = mul nuw nsw i64 %i.0, %j.0
+  %tmp6 = sitofp i64 %tmp to float
+  %tmp7 = getelementptr inbounds [1024 x float], [1024 x float]* %A, i64 %i.0, i64 %j.0
+  %tmp8 = load float, float* %tmp7, align 4
+  %tmp9 = fadd float %tmp8, %tmp6
+  store float %tmp9, float* %tmp7, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb5
+  %tmp11 = add nuw nsw i64 %j.0, 1
+  br label %bb4
+
+bb12:                                             ; preds = %bb4
+  br label %bb13
+
+bb13:                                             ; preds = %bb12
+  %tmp14 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb15:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/GPGPU/unknown-fn-call-not-copied-into-kernel.ll b/final/test/GPGPU/unknown-fn-call-not-copied-into-kernel.ll
new file mode 100644
index 0000000..0d501ed
--- /dev/null
+++ b/final/test/GPGPU/unknown-fn-call-not-copied-into-kernel.ll
@@ -0,0 +1,82 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s --check-prefix=SCOP
+; RUN: opt %loadPolly -S -polly-codegen-ppcg < %s | FileCheck %s
+
+; Check that we do not create a kernel if there is an
+; unknown function call in a candidate kernel.
+
+; Check that we model the kernel as a scop.
+; SCOP:      Function: f
+; SCOP-NEXT:     Region: %entry.split---%for.end13
+
+; If a kernel were generated, then this code would have been part of the kernel
+; and not the `.ll` file that is generated.
+; CHECK:       %conv = fpext float %0 to double
+; CHECK-NEXT:  %1 = tail call double @extern.fn(double %conv)
+; CHECK-NEXT:  %conv6 = fptrunc double %1 to float
+
+; REQUIRES: pollyacc
+
+; static const int N = 1000;
+; void f(float A[N][N], int n, float B[N][N]) {
+;   for(int i = 0; i < n; i++) {
+;     for(int j = 0; j < n; j++) {
+;       B[i][j] = extern_fn(A[i][j], 3);
+;     }
+;
+;   }
+; }
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+define void @f([1000 x float]* %A, i32 %n, [1000 x float]* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %cmp3 = icmp sgt i32 %n, 0
+  br i1 %cmp3, label %for.cond1.preheader.lr.ph, label %for.end13
+
+for.cond1.preheader.lr.ph:                        ; preds = %entry.split
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.cond1.preheader.lr.ph, %for.inc11
+  %indvars.iv5 = phi i64 [ 0, %for.cond1.preheader.lr.ph ], [ %indvars.iv.next6, %for.inc11 ]
+  %cmp21 = icmp sgt i32 %n, 0
+  br i1 %cmp21, label %for.body3.lr.ph, label %for.inc11
+
+for.body3.lr.ph:                                  ; preds = %for.cond1.preheader
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.body3.lr.ph, %for.body3
+  %indvars.iv = phi i64 [ 0, %for.body3.lr.ph ], [ %indvars.iv.next, %for.body3 ]
+  %arrayidx5 = getelementptr inbounds [1000 x float], [1000 x float]* %A, i64 %indvars.iv5, i64 %indvars.iv
+  %0 = load float, float* %arrayidx5, align 4
+  %conv = fpext float %0 to double
+  %1 = tail call double @extern.fn(double %conv)
+  %conv6 = fptrunc double %1 to float
+  %arrayidx10 = getelementptr inbounds [1000 x float], [1000 x float]* %B, i64 %indvars.iv5, i64 %indvars.iv
+  store float %conv6, float* %arrayidx10, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %wide.trip.count = zext i32 %n to i64
+  %exitcond = icmp ne i64 %indvars.iv.next, %wide.trip.count
+  br i1 %exitcond, label %for.body3, label %for.cond1.for.inc11_crit_edge
+
+for.cond1.for.inc11_crit_edge:                    ; preds = %for.body3
+  br label %for.inc11
+
+for.inc11:                                        ; preds = %for.cond1.for.inc11_crit_edge, %for.cond1.preheader
+  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1
+  %wide.trip.count7 = zext i32 %n to i64
+  %exitcond8 = icmp ne i64 %indvars.iv.next6, %wide.trip.count7
+  br i1 %exitcond8, label %for.cond1.preheader, label %for.cond.for.end13_crit_edge
+
+for.cond.for.end13_crit_edge:                     ; preds = %for.inc11
+  br label %for.end13
+
+for.end13:                                        ; preds = %for.cond.for.end13_crit_edge, %entry.split
+  ret void
+}
+
+declare double @extern.fn(double) #0
+attributes #0 = { readnone }
diff --git a/final/test/GPGPU/untouched-arrays.ll b/final/test/GPGPU/untouched-arrays.ll
new file mode 100644
index 0000000..77a9c81
--- /dev/null
+++ b/final/test/GPGPU/untouched-arrays.ll
@@ -0,0 +1,271 @@
+; RUN: opt %loadPolly -polly-codegen-ppcg -polly-acc-dump-code \
+; RUN: -disable-output < %s | \
+; RUN: FileCheck -check-prefix=CODE %s
+
+; REQUIRES: pollyacc
+
+; CODE:        cudaCheckReturn(cudaMemcpy(dev_MemRef_global_1, MemRef_global_1, (142) * sizeof(i32), cudaMemcpyHostToDevice));
+; CODE-NEXT:   {
+; CODE-NEXT:     dim3 k0_dimBlock(10);
+; CODE-NEXT:     dim3 k0_dimGrid(1);
+; CODE-NEXT:     kernel0 <<<k0_dimGrid, k0_dimBlock>>> (dev_MemRef_global_1);
+; CODE-NEXT:     cudaCheckKernel();
+; CODE-NEXT:   }
+
+; CODE:   cudaCheckReturn(cudaMemcpy(MemRef_global_1, dev_MemRef_global_1, (142) * sizeof(i32), cudaMemcpyDeviceToHost));
+; CODE:   cudaCheckReturn(cudaFree(dev_MemRef_global_1));
+; CODE-NEXT: }
+
+; CODE: # kernel0
+; CODE-NEXT: Stmt_bb33(t0, 0);
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.hoge = type { [23 x i16], [22 x i16], [14 x i16], [13 x i16] }
+
+@global = external global [9 x %struct.hoge], align 16
+@global.1 = external global [9 x [152 x i32]], align 16
+
+; Function Attrs: nounwind uwtable
+define void @widget() #0 {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb1, %bb
+  br i1 undef, label %bb1, label %bb2
+
+bb2:                                              ; preds = %bb2, %bb1
+  br i1 undef, label %bb2, label %bb3
+
+bb3:                                              ; preds = %bb3, %bb2
+  br i1 undef, label %bb3, label %bb4
+
+bb4:                                              ; preds = %bb4, %bb3
+  br i1 undef, label %bb4, label %bb5
+
+bb5:                                              ; preds = %bb5, %bb4
+  br i1 undef, label %bb5, label %bb6
+
+bb6:                                              ; preds = %bb6, %bb5
+  br i1 undef, label %bb6, label %bb7
+
+bb7:                                              ; preds = %bb7, %bb6
+  br i1 undef, label %bb7, label %bb8
+
+bb8:                                              ; preds = %bb8, %bb7
+  br i1 undef, label %bb8, label %bb9
+
+bb9:                                              ; preds = %bb8
+  br label %bb10
+
+bb10:                                             ; preds = %bb12, %bb9
+  br label %bb11
+
+bb11:                                             ; preds = %bb11, %bb10
+  br i1 undef, label %bb11, label %bb12
+
+bb12:                                             ; preds = %bb11
+  br i1 undef, label %bb10, label %bb13
+
+bb13:                                             ; preds = %bb18, %bb12
+  br i1 undef, label %bb16, label %bb14
+
+bb14:                                             ; preds = %bb16, %bb13
+  br i1 undef, label %bb15, label %bb18
+
+bb15:                                             ; preds = %bb14
+  br label %bb17
+
+bb16:                                             ; preds = %bb16, %bb13
+  br i1 undef, label %bb16, label %bb14
+
+bb17:                                             ; preds = %bb17, %bb15
+  br i1 undef, label %bb17, label %bb18
+
+bb18:                                             ; preds = %bb17, %bb14
+  br i1 undef, label %bb13, label %bb19
+
+bb19:                                             ; preds = %bb25, %bb18
+  br label %bb20
+
+bb20:                                             ; preds = %bb24, %bb19
+  br i1 undef, label %bb21, label %bb24
+
+bb21:                                             ; preds = %bb20
+  br i1 undef, label %bb23, label %bb22
+
+bb22:                                             ; preds = %bb21
+  br label %bb24
+
+bb23:                                             ; preds = %bb21
+  br label %bb24
+
+bb24:                                             ; preds = %bb23, %bb22, %bb20
+  br i1 undef, label %bb20, label %bb25
+
+bb25:                                             ; preds = %bb24
+  br i1 undef, label %bb19, label %bb26
+
+bb26:                                             ; preds = %bb56, %bb25
+  %tmp = phi [9 x [152 x i32]]* [ undef, %bb56 ], [ bitcast (i32* getelementptr inbounds ([9 x [152 x i32]], [9 x [152 x i32]]* @global.1, i64 0, i64 0, i64 32) to [9 x [152 x i32]]*), %bb25 ]
+  br label %bb27
+
+bb27:                                             ; preds = %bb27, %bb26
+  br i1 undef, label %bb27, label %bb28
+
+bb28:                                             ; preds = %bb27
+  %tmp29 = bitcast [9 x [152 x i32]]* %tmp to i32*
+  br label %bb30
+
+bb30:                                             ; preds = %bb38, %bb28
+  %tmp31 = phi i32 [ 3, %bb28 ], [ %tmp40, %bb38 ]
+  %tmp32 = phi i32* [ %tmp29, %bb28 ], [ %tmp39, %bb38 ]
+  br label %bb33
+
+bb33:                                             ; preds = %bb33, %bb30
+  %tmp34 = phi i32 [ 0, %bb30 ], [ %tmp37, %bb33 ]
+  %tmp35 = phi i32* [ %tmp32, %bb30 ], [ undef, %bb33 ]
+  %tmp36 = getelementptr inbounds i32, i32* %tmp35, i64 1
+  store i32 undef, i32* %tmp36, align 4, !tbaa !1
+  %tmp37 = add nuw nsw i32 %tmp34, 1
+  br i1 false, label %bb33, label %bb38
+
+bb38:                                             ; preds = %bb33
+  %tmp39 = getelementptr i32, i32* %tmp32, i64 12
+  %tmp40 = add nuw nsw i32 %tmp31, 1
+  %tmp41 = icmp ne i32 %tmp40, 13
+  br i1 %tmp41, label %bb30, label %bb42
+
+bb42:                                             ; preds = %bb38
+  %tmp43 = getelementptr inbounds [9 x %struct.hoge], [9 x %struct.hoge]* @global, i64 0, i64 0, i32 3, i64 0
+  br label %bb44
+
+bb44:                                             ; preds = %bb51, %bb42
+  %tmp45 = phi i32 [ 0, %bb42 ], [ %tmp52, %bb51 ]
+  %tmp46 = phi i16* [ %tmp43, %bb42 ], [ undef, %bb51 ]
+  %tmp47 = load i16, i16* %tmp46, align 2, !tbaa !5
+  br label %bb48
+
+bb48:                                             ; preds = %bb48, %bb44
+  %tmp49 = phi i32 [ 0, %bb44 ], [ %tmp50, %bb48 ]
+  %tmp50 = add nuw nsw i32 %tmp49, 1
+  br i1 false, label %bb48, label %bb51
+
+bb51:                                             ; preds = %bb48
+  %tmp52 = add nuw nsw i32 %tmp45, 1
+  %tmp53 = icmp ne i32 %tmp52, 13
+  br i1 %tmp53, label %bb44, label %bb54
+
+bb54:                                             ; preds = %bb51
+  br label %bb55
+
+bb55:                                             ; preds = %bb55, %bb54
+  br i1 undef, label %bb55, label %bb56
+
+bb56:                                             ; preds = %bb55
+  br i1 undef, label %bb26, label %bb57
+
+bb57:                                             ; preds = %bb60, %bb56
+  br label %bb58
+
+bb58:                                             ; preds = %bb58, %bb57
+  br i1 undef, label %bb58, label %bb59
+
+bb59:                                             ; preds = %bb59, %bb58
+  br i1 undef, label %bb59, label %bb60
+
+bb60:                                             ; preds = %bb59
+  br i1 undef, label %bb57, label %bb61
+
+bb61:                                             ; preds = %bb65, %bb60
+  br label %bb62
+
+bb62:                                             ; preds = %bb64, %bb61
+  br label %bb63
+
+bb63:                                             ; preds = %bb63, %bb62
+  br i1 undef, label %bb63, label %bb64
+
+bb64:                                             ; preds = %bb63
+  br i1 undef, label %bb62, label %bb65
+
+bb65:                                             ; preds = %bb64
+  br i1 undef, label %bb61, label %bb66
+
+bb66:                                             ; preds = %bb70, %bb65
+  br label %bb67
+
+bb67:                                             ; preds = %bb69, %bb66
+  br label %bb68
+
+bb68:                                             ; preds = %bb68, %bb67
+  br i1 undef, label %bb68, label %bb69
+
+bb69:                                             ; preds = %bb68
+  br i1 undef, label %bb67, label %bb70
+
+bb70:                                             ; preds = %bb69
+  br i1 undef, label %bb66, label %bb71
+
+bb71:                                             ; preds = %bb73, %bb70
+  br label %bb72
+
+bb72:                                             ; preds = %bb72, %bb71
+  br i1 undef, label %bb72, label %bb73
+
+bb73:                                             ; preds = %bb72
+  br i1 undef, label %bb71, label %bb74
+
+bb74:                                             ; preds = %bb80, %bb73
+  br label %bb75
+
+bb75:                                             ; preds = %bb79, %bb74
+  br label %bb76
+
+bb76:                                             ; preds = %bb78, %bb75
+  br label %bb77
+
+bb77:                                             ; preds = %bb77, %bb76
+  br i1 undef, label %bb77, label %bb78
+
+bb78:                                             ; preds = %bb77
+  br i1 undef, label %bb76, label %bb79
+
+bb79:                                             ; preds = %bb78
+  br i1 undef, label %bb75, label %bb80
+
+bb80:                                             ; preds = %bb79
+  br i1 undef, label %bb74, label %bb81
+
+bb81:                                             ; preds = %bb85, %bb80
+  br label %bb82
+
+bb82:                                             ; preds = %bb84, %bb81
+  br label %bb83
+
+bb83:                                             ; preds = %bb83, %bb82
+  br i1 undef, label %bb83, label %bb84
+
+bb84:                                             ; preds = %bb83
+  br i1 undef, label %bb82, label %bb85
+
+bb85:                                             ; preds = %bb84
+  br i1 undef, label %bb81, label %bb86
+
+bb86:                                             ; preds = %bb85
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 4.0.0 (http://llvm.org/git/clang.git 359c45534e46a8ef263db1a8b855740bbeca6998) (http://llvm.org/git/llvm.git 2628aff56683b7652abe9f9eb9e54a82d1716aa7)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"int", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!6, !6, i64 0}
+!6 = !{!"short", !3, i64 0}
diff --git a/final/test/Isl/Ast/OpenMP/multiple_loops_outer_parallel.ll b/final/test/Isl/Ast/OpenMP/multiple_loops_outer_parallel.ll
new file mode 100644
index 0000000..9c8b219
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/multiple_loops_outer_parallel.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-ast -polly-parallel -polly-parallel-force -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+;
+;       void jd(int *A) {
+; CHECK:  #pragma omp parallel for
+; PINFO:  for.cond2: Loop is parallel.
+;         for (int i = 0; i < 1024; i++)
+;           A[i] = 1;
+; CHECK:  #pragma omp parallel for
+; PINFO:  for.cond: Loop is parallel.
+;         for (int i = 0; i < 1024; i++)
+;           A[i] = A[i] * 2;
+;       }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc ], [ 0, %entry ]
+  %exitcond3 = icmp ne i64 %indvars.iv1, 1024
+  br i1 %exitcond3, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv1
+  store i32 1, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc9, %for.end
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc9 ], [ 0, %for.end ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body4, label %for.end11
+
+for.body4:                                        ; preds = %for.cond2
+  %arrayidx6 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx6, align 4
+  %mul = shl nsw i32 %tmp, 1
+  %arrayidx8 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %mul, i32* %arrayidx8, align 4
+  br label %for.inc9
+
+for.inc9:                                         ; preds = %for.body4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond2
+
+for.end11:                                        ; preds = %for.cond2
+  ret void
+}
diff --git a/final/test/Isl/Ast/OpenMP/nested_loop_both_parallel.ll b/final/test/Isl/Ast/OpenMP/nested_loop_both_parallel.ll
new file mode 100644
index 0000000..be5df96
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/nested_loop_both_parallel.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-ast -polly-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+; for (i = 0; i < 1024; i++)
+;   for (j = 0; j < 1024; j++)
+;     A[i][j] = 1;
+
+@A = common global [1024 x [1024 x i32]] zeroinitializer
+define void @bar() {
+start:
+  fence seq_cst
+  br label %loop.i
+
+loop.i:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.i.backedge ]
+  %exitcond.i = icmp ne i64 %i, 1024
+  br i1 %exitcond.i, label %loop.j, label %ret
+
+loop.j:
+  %j = phi i64 [ 0, %loop.i], [ %j.next, %loop.j.backedge ]
+  %exitcond.j = icmp ne i64 %j, 1024
+  br i1 %exitcond.j, label %loop.body, label %loop.i.backedge
+
+loop.body:
+  %scevgep = getelementptr [1024 x [1024 x i32] ], [1024 x [1024 x i32] ]* @A, i64 0, i64 %j, i64 %i
+  store i32 1, i32* %scevgep
+  br label %loop.j.backedge
+
+loop.j.backedge:
+  %j.next = add nsw i64 %j, 1
+  br label %loop.j
+
+loop.i.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.i
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; Make sure we do not accidentally generate nested openmp parallel for
+; annotations.
+
+; CHECK:     #pragma omp parallel for
+; CHECK:     for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK-NOT:   #pragma omp parallel for
+; CHECK:       #pragma simd
+; CHECK-NOT:   #pragma omp parallel for
+; CHECK:       for (int c1 = 0; c1 <= 1023; c1 += 1)
+; CHECK:         Stmt_loop_body(c0, c1);
+;
+; PINFO:      loop.i: Loop is parallel.
+; PINFO-NEXT: loop.j: Loop is parallel.
diff --git a/final/test/Isl/Ast/OpenMP/nested_loop_both_parallel_parametric.ll b/final/test/Isl/Ast/OpenMP/nested_loop_both_parallel_parametric.ll
new file mode 100644
index 0000000..5d2a2fa
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/nested_loop_both_parallel_parametric.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-ast -polly-parallel -polly-parallel-force -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+; int A[1024][1024];
+; void bar(int n) {
+;   for (i = 0; i < n; i++)
+;     for (j = 0; j < n; j++)
+;       A[i][j] = 1;
+; }
+@A = common global [1024 x [1024 x i32]] zeroinitializer
+define void @bar(i64 %n) {
+start:
+  fence seq_cst
+  br label %loop.i
+
+loop.i:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.i.backedge ]
+  %exitcond.i = icmp ne i64 %i, %n
+  br i1 %exitcond.i, label %loop.j, label %ret
+
+loop.j:
+  %j = phi i64 [ 0, %loop.i], [ %j.next, %loop.j.backedge ]
+  %exitcond.j = icmp ne i64 %j, %n
+  br i1 %exitcond.j, label %loop.body, label %loop.i.backedge
+
+loop.body:
+  %scevgep = getelementptr [1024 x [1024 x i32] ], [1024 x [1024 x i32] ]* @A, i64 0, i64 %j, i64 %i
+  store i32 1, i32* %scevgep
+  br label %loop.j.backedge
+
+loop.j.backedge:
+  %j.next = add nsw i64 %j, 1
+  br label %loop.j
+
+loop.i.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.i
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: if (n <= 1024)
+; CHECK:   #pragma omp parallel for
+; CHECK:   for (int c0 = 0; c0 < n; c0 += 1)
+; CHECK:     #pragma simd
+; CHECK:     for (int c1 = 0; c1 < n; c1 += 1)
+; CHECK:       Stmt_loop_body(c0, c1);
+
+; PINFO:      loop.i: Loop is parallel.
+; PINFO-NEXT: loop.j: Loop is parallel.
diff --git a/final/test/Isl/Ast/OpenMP/nested_loop_inner_parallel.ll b/final/test/Isl/Ast/OpenMP/nested_loop_inner_parallel.ll
new file mode 100644
index 0000000..615c101
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/nested_loop_inner_parallel.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-ast -polly-parallel -polly-parallel-force -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+; for (i = 0; i < n; i++)
+;   for (j = 0; j < n; j++)
+;     A[j] = 1;
+
+@A = common global [1024 x i32] zeroinitializer
+define void @bar(i64 %n) {
+start:
+  fence seq_cst
+  br label %loop.i
+
+loop.i:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.i.backedge ]
+  %exitcond.i = icmp ne i64 %i, %n
+  br i1 %exitcond.i, label %loop.j, label %ret
+
+loop.j:
+  %j = phi i64 [ 0, %loop.i], [ %j.next, %loop.j.backedge ]
+  %exitcond.j = icmp ne i64 %j, %n
+  br i1 %exitcond.j, label %loop.body, label %loop.i.backedge
+
+loop.body:
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %j
+  store i32 1, i32* %scevgep
+  br label %loop.j.backedge
+
+loop.j.backedge:
+  %j.next = add nsw i64 %j, 1
+  br label %loop.j
+
+loop.i.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.i
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: for (int c0 = 0; c0 < n; c0 += 1)
+; CHECK:   #pragma simd
+; CHECK:   #pragma omp parallel for
+; CHECK:   for (int c1 = 0; c1 < n; c1 += 1)
+; CHECK:     Stmt_loop_body(c0, c1);
+
+; PINFO:      loop.i: Loop is not parallel.
+; PINFO-NEXT: loop.j: Loop is parallel.
diff --git a/final/test/Isl/Ast/OpenMP/nested_loop_outer_parallel.ll b/final/test/Isl/Ast/OpenMP/nested_loop_outer_parallel.ll
new file mode 100644
index 0000000..148933f
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/nested_loop_outer_parallel.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-ast -polly-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+; for (i = 0; i < n; i++)
+;   for (j = 0; j < n; j++)
+;     A[i] = 1;
+
+@A = common global [1024 x i32] zeroinitializer
+define void @bar(i64 %n) {
+start:
+  fence seq_cst
+  br label %loop.i
+
+loop.i:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.i.backedge ]
+  %exitcond.i = icmp ne i64 %i, %n
+  br i1 %exitcond.i, label %loop.j, label %ret
+
+loop.j:
+  %j = phi i64 [ 0, %loop.i], [ %j.next, %loop.j.backedge ]
+  %exitcond.j = icmp ne i64 %j, %n
+  br i1 %exitcond.j, label %loop.body, label %loop.i.backedge
+
+loop.body:
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %i
+  store i32 1, i32* %scevgep
+  br label %loop.j.backedge
+
+loop.j.backedge:
+  %j.next = add nsw i64 %j, 1
+  br label %loop.j
+
+loop.i.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.i
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: #pragma omp parallel for
+; CHECK: for (int c0 = 0; c0 < n; c0 += 1)
+; CHECK:   for (int c1 = 0; c1 < n; c1 += 1)
+; CHECK:     Stmt_loop_body(c0, c1);
+
+; PINFO:      loop.i: Loop is parallel.
+; PINFO-NEXT: loop.j: Loop is not parallel.
diff --git a/final/test/Isl/Ast/OpenMP/single_loop_param_non_parallel.ll b/final/test/Isl/Ast/OpenMP/single_loop_param_non_parallel.ll
new file mode 100644
index 0000000..a69c891
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/single_loop_param_non_parallel.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-ast -polly-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+; for (i = 0; i < n; i++)
+;   A[0] = i;
+
+@A = common global [1024 x i32] zeroinitializer
+define void @bar(i64 %n) {
+start:
+  fence seq_cst
+  br label %loop.header
+
+loop.header:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.backedge ]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 0
+  %exitcond = icmp ne i64 %i, %n
+  br i1 %exitcond, label %loop.body, label %ret
+
+loop.body:
+  store i32 1, i32* %scevgep
+  br label %loop.backedge
+
+loop.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.header
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: for (int c0 = 0; c0 < n; c0 += 1)
+; CHECK:   Stmt_loop_body(c0)
+; PINFO: loop.header: Loop is not parallel.
diff --git a/final/test/Isl/Ast/OpenMP/single_loop_param_parallel.ll b/final/test/Isl/Ast/OpenMP/single_loop_param_parallel.ll
new file mode 100644
index 0000000..382a287
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/single_loop_param_parallel.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-ast -polly-parallel -polly-parallel-force -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+; for (i = 0; i < n; i++)
+;   A[i] = 1;
+
+@A = common global [1024 x i32] zeroinitializer
+define void @bar(i64 %n) {
+start:
+  fence seq_cst
+  br label %loop.header
+
+loop.header:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.backedge ]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %i
+  %exitcond = icmp ne i64 %i, %n
+  br i1 %exitcond, label %loop.body, label %ret
+
+loop.body:
+  store i32 1, i32* %scevgep
+  br label %loop.backedge
+
+loop.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.header
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: #pragma simd
+; CHECK: #pragma omp parallel for
+; CHECK: for (int c0 = 0; c0 < n; c0 += 1)
+; CHECK:   Stmt_loop_body(c0)
+; PINFO: loop.header: Loop is parallel.
diff --git a/final/test/Isl/Ast/OpenMP/single_loop_param_parallel_computeout.ll b/final/test/Isl/Ast/OpenMP/single_loop_param_parallel_computeout.ll
new file mode 100644
index 0000000..8439500
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/single_loop_param_parallel_computeout.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-ast -polly-parallel -polly-dependences-computeout=1 -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+; for (i = 0; i < n; i++)
+;   A[i] = 1;
+
+@A = common global [1024 x i32] zeroinitializer
+define void @bar(i64 %n) {
+start:
+  fence seq_cst
+  br label %loop.header
+
+loop.header:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.backedge ]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %i
+  %exitcond = icmp ne i64 %i, %n
+  br i1 %exitcond, label %loop.body, label %ret
+
+loop.body:
+  store i32 1, i32* %scevgep
+  br label %loop.backedge
+
+loop.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.header
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; CHECK-NOT: #pragma simd
+; CHECK-NOT: #pragma omp parallel for
+; CHECK: for (int c0 = 0; c0 < n; c0 += 1)
+; CHECK:   Stmt_loop_body(c0)
+; PINFO: loop.header: Loop is parallel.
diff --git a/final/test/Isl/Ast/alias_checks_with_empty_context.ll b/final/test/Isl/Ast/alias_checks_with_empty_context.ll
new file mode 100644
index 0000000..2372deb
--- /dev/null
+++ b/final/test/Isl/Ast/alias_checks_with_empty_context.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s \
+; RUN:     | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@global = external local_unnamed_addr global i32, align 4
+@global.1 = external local_unnamed_addr global i32, align 4
+
+define void @hoge() local_unnamed_addr {
+bb:
+  %tmp = alloca i8, align 8
+  br label %bb1
+
+bb1:                                              ; preds = %bb19, %bb
+  %tmp2 = phi i32 [ undef, %bb ], [ %tmp5, %bb19 ]
+  %tmp3 = phi i32* [ @global, %bb ], [ %tmp20, %bb19 ]
+  %tmp4 = icmp ugt i32 %tmp2, 5
+  %tmp5 = select i1 %tmp4, i32 %tmp2, i32 5
+  br label %bb6
+
+bb6:                                              ; preds = %bb1
+  br label %bb7
+
+bb7:                                              ; preds = %bb10, %bb6
+  %tmp8 = phi i8 [ 7, %bb6 ], [ %tmp11, %bb10 ]
+  store i32 2, i32* %tmp3, align 4
+  %tmp9 = load i8, i8* %tmp, align 8
+  br label %bb10
+
+bb10:                                             ; preds = %bb7
+  store i32 undef, i32* @global.1, align 4
+  %tmp11 = add nuw nsw i8 %tmp8, 1
+  %tmp12 = icmp eq i8 %tmp11, 72
+  br i1 %tmp12, label %bb13, label %bb7
+
+bb13:                                             ; preds = %bb10
+  %tmp14 = icmp eq i32 %tmp5, 0
+  br i1 %tmp14, label %bb15, label %bb16
+
+bb15:                                             ; preds = %bb13
+  store i8 0, i8* %tmp, align 8
+  br label %bb16
+
+bb16:                                             ; preds = %bb15, %bb13
+  br label %bb17
+
+bb17:                                             ; preds = %bb16
+  br i1 undef, label %bb19, label %bb18
+
+bb18:                                             ; preds = %bb17
+  br label %bb19
+
+bb19:                                             ; preds = %bb18, %bb17
+  %tmp20 = phi i32* [ %tmp3, %bb17 ], [ bitcast (void ()* @hoge to i32*), %bb18 ]
+  br label %bb1
+}
+
+; CHECK: if (1 && (&MemRef_global_1[1] <= &MemRef_tmp3[0] || &MemRef_tmp3[1] <= &MemRef_global_1[0]) && 1 && 1)
+
+; CHECK:     {
+; CHECK-NEXT:       for (int c0 = 0; c0 <= 64; c0 += 1) {
+; CHECK-NEXT:         Stmt_bb7(c0);
+; CHECK-NEXT:         Stmt_bb10(c0);
+; CHECK-NEXT:       }
+; CHECK-NEXT:       if (p_0 == 0)
+; CHECK-NEXT:         Stmt_bb15();
+; CHECK-NEXT:     }
+
+; CHECK: else
+; CHECK-NEXT:     {  /* original code */ }
+
diff --git a/final/test/Isl/Ast/alias_simple_1.ll b/final/test/Isl/Ast/alias_simple_1.ll
new file mode 100644
index 0000000..1903749
--- /dev/null
+++ b/final/test/Isl/Ast/alias_simple_1.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa < %s | FileCheck %s --check-prefix=NOAA
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=BASI
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa -tbaa < %s | FileCheck %s --check-prefix=TBAA
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa -scev-aa < %s | FileCheck %s --check-prefix=SCEV
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa -globals-aa < %s | FileCheck %s --check-prefix=GLOB
+;
+;    int A[1024];
+;
+;
+;    void jd(float *B, int N) {
+;      for (int i = 0; i < N; i++)
+;        A[i] = B[i];
+;    }
+;
+; NOAA: if (1 && 0 == N <= 0 && (&MemRef_B[N] <= &MemRef_A[0] || &MemRef_A[N] <= &MemRef_B[0]))
+; BASI: if (1 && 0 == N <= 0 && (&MemRef_B[N] <= &MemRef_A[0] || &MemRef_A[N] <= &MemRef_B[0]))
+; TBAA: if (1 && 0 == N <= 0)
+; SCEV: if (1 && 0 == N <= 0 && (&MemRef_B[N] <= &MemRef_A[0] || &MemRef_A[N] <= &MemRef_B[0]))
+; GLOB: if (1 && 0 == N <= 0 && (&MemRef_B[N] <= &MemRef_A[0] || &MemRef_A[N] <= &MemRef_B[0]))
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@A = common global [1024 x i32] zeroinitializer, align 16
+
+define void @jd(float* nocapture readonly %B, i32 %N) {
+entry:
+  %cmp6 = icmp sgt i32 %N, 0
+  br i1 %cmp6, label %for.body.preheader, label %for.end
+
+for.body.preheader:                               ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.preheader, %for.body
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.body ], [ 0, %for.body.preheader ]
+  %arrayidx = getelementptr inbounds float, float* %B, i64 %indvars.iv
+  %tmp = load float, float* %arrayidx, align 4, !tbaa !1
+  %conv = fptosi float %tmp to i32
+  %arrayidx2 = getelementptr inbounds [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvars.iv
+  store i32 %conv, i32* %arrayidx2, align 4, !tbaa !5
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %lftr.wideiv1 = trunc i64 %indvars.iv.next to i32
+  %exitcond2 = icmp eq i32 %lftr.wideiv1, %N
+  br i1 %exitcond2, label %for.end.loopexit, label %for.body
+
+for.end.loopexit:                                 ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.end.loopexit, %entry
+  ret void
+}
+
+!0 = !{!""}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"float", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!6, !6, i64 0}
+!6 = !{!"int", !3, i64 0}
diff --git a/final/test/Isl/Ast/alias_simple_2.ll b/final/test/Isl/Ast/alias_simple_2.ll
new file mode 100644
index 0000000..b0d9573
--- /dev/null
+++ b/final/test/Isl/Ast/alias_simple_2.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa < %s | FileCheck %s --check-prefix=NOAA
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=BASI
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa -tbaa < %s | FileCheck %s --check-prefix=TBAA
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa -scev-aa < %s | FileCheck %s --check-prefix=SCEV
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa -globals-aa < %s | FileCheck %s --check-prefix=GLOB
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa -globals-aa -polly-allow-nonaffine < %s | FileCheck %s --check-prefix=NONAFFINE
+;
+;    int A[1024], B[1024];
+;
+;
+;    void jd(int N) {
+;      for (int i = 0; i < N; i++)
+;        A[i] = B[i];
+;    }
+;
+; NOAA: if (1 && 0 == N <= 0 && (&MemRef_B[N] <= &MemRef_A[0] || &MemRef_A[N] <= &MemRef_B[0]))
+; BASI: if (1 && 0 == N <= 0)
+; TBAA: if (1 && 0 == N <= 0 && (&MemRef_B[N] <= &MemRef_A[0] || &MemRef_A[N] <= &MemRef_B[0]))
+; SCEV: if (1 && 0 == N <= 0 && (&MemRef_B[N] <= &MemRef_A[0] || &MemRef_A[N] <= &MemRef_B[0]))
+; GLOB: if (1 && 0 == N <= 0 && (&MemRef_B[N] <= &MemRef_A[0] || &MemRef_A[N] <= &MemRef_B[0]))
+; NONAFFINE: if (1 && 0 == N <= 0 && (&MemRef_B[N] <= &MemRef_A[0] || &MemRef_A[N] <= &MemRef_B[0]))
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@A = common global [1024 x i32] zeroinitializer, align 16
+@B = common global [1024 x i32] zeroinitializer, align 16
+
+define void @jd(i32 %N) {
+entry:
+  %cmp6 = icmp sgt i32 %N, 0
+  br i1 %cmp6, label %for.body.preheader, label %for.end
+
+for.body.preheader:                               ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.preheader, %for.body
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.body ], [ 0, %for.body.preheader ]
+  %arrayidx = getelementptr inbounds  [1024 x i32],  [1024 x i32]* @B, i64 0, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4, !tbaa !5
+  %arrayidx2 = getelementptr inbounds [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvars.iv
+  store i32 %tmp, i32* %arrayidx2, align 4, !tbaa !5
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %lftr.wideiv1 = trunc i64 %indvars.iv.next to i32
+  %exitcond2 = icmp eq i32 %lftr.wideiv1, %N
+  br i1 %exitcond2, label %for.end.loopexit, label %for.body
+
+for.end.loopexit:                                 ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.end.loopexit, %entry
+  ret void
+}
+
+!0 = !{!""}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"float", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!6, !6, i64 0}
+!6 = !{!"int", !3, i64 0}
diff --git a/final/test/Isl/Ast/alias_simple_3.ll b/final/test/Isl/Ast/alias_simple_3.ll
new file mode 100644
index 0000000..a2c0624
--- /dev/null
+++ b/final/test/Isl/Ast/alias_simple_3.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa < %s | FileCheck %s --check-prefix=NOAA
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=BASI
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa -tbaa < %s | FileCheck %s --check-prefix=TBAA
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa -scev-aa < %s | FileCheck %s --check-prefix=SCEV
+; RUN: opt %loadPolly -polly-ast -analyze -disable-basicaa -globals-aa < %s | FileCheck %s --check-prefix=GLOB
+;
+;    int A[1024];
+;    float B[1024];
+;
+;    void jd(int N) {
+;      for (int i = 0; i < N; i++)
+;        A[i] = B[i];
+;    }
+;
+; NOAA: if (1 && 0 == N <= 0 && (&MemRef_B[N] <= &MemRef_A[0] || &MemRef_A[N] <= &MemRef_B[0]))
+; BASI: if (1 && 0 == N <= 0)
+; TBAA: if (1 && 0 == N <= 0)
+; SCEV: if (1 && 0 == N <= 0 && (&MemRef_B[N] <= &MemRef_A[0] || &MemRef_A[N] <= &MemRef_B[0]))
+; GLOB: if (1 && 0 == N <= 0 && (&MemRef_B[N] <= &MemRef_A[0] || &MemRef_A[N] <= &MemRef_B[0]))
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@A = common global [1024 x i32] zeroinitializer, align 16
+@B = common global [1024 x float] zeroinitializer, align 16
+
+define void @jd(i32 %N) {
+entry:
+  %cmp6 = icmp sgt i32 %N, 0
+  br i1 %cmp6, label %for.body.preheader, label %for.end
+
+for.body.preheader:                               ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.preheader, %for.body
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.body ], [ 0, %for.body.preheader ]
+  %arrayidx = getelementptr inbounds  [1024 x float],  [1024 x float]* @B, i64 0, i64 %indvars.iv
+  %tmp = load float, float* %arrayidx, align 4, !tbaa !1
+  %conv = fptosi float %tmp to i32
+  %arrayidx2 = getelementptr inbounds [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvars.iv
+  store i32 %conv, i32* %arrayidx2, align 4, !tbaa !5
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %lftr.wideiv1 = trunc i64 %indvars.iv.next to i32
+  %exitcond2 = icmp eq i32 %lftr.wideiv1, %N
+  br i1 %exitcond2, label %for.end.loopexit, label %for.body
+
+for.end.loopexit:                                 ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.end.loopexit, %entry
+  ret void
+}
+
+!0 = !{!""}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"float", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!6, !6, i64 0}
+!6 = !{!"int", !3, i64 0}
diff --git a/final/test/Isl/Ast/aliasing_arrays_with_identical_base.ll b/final/test/Isl/Ast/aliasing_arrays_with_identical_base.ll
new file mode 100644
index 0000000..9afc5c6
--- /dev/null
+++ b/final/test/Isl/Ast/aliasing_arrays_with_identical_base.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s \
+; RUN:   -polly-invariant-load-hoisting \
+; RUN:   | FileCheck %s
+
+; CHECK: if (1 && 1 && (&MemRef_X[1] <= &MemRef_BaseA[0] || &MemRef_BaseA[1024] <= &MemRef_X[0]) && (&MemRef_X[1] <= &MemRef_BaseB[0] || &MemRef_BaseB[1024] <= &MemRef_X[0]))
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @foo(float** nocapture readonly %X) {
+entry:
+  br label %for.body
+
+for.cond.cleanup:
+  ret void
+
+for.body:
+  %i.011 = phi i64 [ 0, %entry ], [ %inc, %for.body ]
+  %conv = sitofp i64 %i.011 to float
+  %BaseA = load float*, float** %X, align 8
+  %BaseB = load float*, float** %X, align 8
+  %arrayidx = getelementptr inbounds float, float* %BaseA, i64 %i.011
+  %A = load float, float* %arrayidx, align 4
+  %add = fadd float %A, %conv
+  store float %add, float* %arrayidx, align 4
+  %arrayidxB = getelementptr inbounds float, float* %BaseB, i64 %i.011
+  %B = load float, float* %arrayidxB, align 4
+  %addB = fadd float %B, %conv
+  store float %addB, float* %arrayidxB, align 4
+  %inc = add nuw nsw i64 %i.011, 1
+  %exitcond = icmp eq i64 %inc, 1024
+  br i1 %exitcond, label %for.cond.cleanup, label %for.body
+}
diff --git a/final/test/Isl/Ast/aliasing_multiple_alias_groups.ll b/final/test/Isl/Ast/aliasing_multiple_alias_groups.ll
new file mode 100644
index 0000000..3a24570
--- /dev/null
+++ b/final/test/Isl/Ast/aliasing_multiple_alias_groups.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-ast -analyze          < %s | FileCheck %s --check-prefix=NOAA
+; RUN: opt %loadPolly -polly-ast -analyze -tbaa    < %s | FileCheck %s --check-prefix=TBAA
+;
+;    void jd(int *Int0, int *Int1, float *Float0, float *Float1) {
+;      for (int i = 0; i < 1024; i++) {
+;        Int0[i] = Int1[i];
+;        Float0[i] = Float1[i];
+;      }
+;    }
+;
+; NOAA:      if (1 && (
+; NOAA-DAG:    &MemRef_Int0[1024] <= &MemRef_Float0[0] || &MemRef_Float0[1024] <= &MemRef_Int0[0]
+; NOAA-DAG:    &MemRef_Int1[1024] <= &MemRef_Float0[0] || &MemRef_Float0[1024] <= &MemRef_Int1[0]
+; NOAA-DAG:    &MemRef_Float1[1024] <= &MemRef_Float0[0] || &MemRef_Float0[1024] <= &MemRef_Float1[0]
+; NOAA-DAG:    &MemRef_Int1[1024] <= &MemRef_Int0[0] || &MemRef_Int0[1024] <= &MemRef_Int1[0]
+; NOAA-DAG:    &MemRef_Float1[1024] <= &MemRef_Int0[0] || &MemRef_Int0[1024] <= &MemRef_Float1[0]
+; NOAA:      ))
+;
+; TBAA:      if (1 && (
+; TBAA-DAG:    &MemRef_Int1[1024] <= &MemRef_Int0[0] || &MemRef_Int0[1024] <= &MemRef_Int1[0]
+; TBAA-DAG:    &MemRef_Float1[1024] <= &MemRef_Float0[0] || &MemRef_Float0[1024] <= &MemRef_Float1[0]
+; TBAA:      ))
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* nocapture %Int0, i32* nocapture readonly %Int1, float* nocapture %Float0, float* nocapture readonly %Float1) {
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %for.body, %entry
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds i32, i32* %Int1, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4, !tbaa !0
+  %arrayidx2 = getelementptr inbounds i32, i32* %Int0, i64 %indvars.iv
+  store i32 %tmp, i32* %arrayidx2, align 4, !tbaa !0
+  %arrayidx4 = getelementptr inbounds float, float* %Float1, i64 %indvars.iv
+  %tmp1 = load float, float* %arrayidx4, align 4, !tbaa !4
+  %arrayidx6 = getelementptr inbounds float, float* %Float0, i64 %indvars.iv
+  store float %tmp1, float* %arrayidx6, align 4, !tbaa !4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 1024
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.body
+  ret void
+}
+
+!0 = !{!1, !1, i64 0}
+!1 = !{!"int", !2, i64 0}
+!2 = !{!"omnipotent char", !3, i64 0}
+!3 = !{!"Simple C/C++ TBAA"}
+!4 = !{!5, !5, i64 0}
+!5 = !{!"float", !2, i64 0}
diff --git a/final/test/Isl/Ast/aliasing_parametric_simple_1.ll b/final/test/Isl/Ast/aliasing_parametric_simple_1.ll
new file mode 100644
index 0000000..c5e5461
--- /dev/null
+++ b/final/test/Isl/Ast/aliasing_parametric_simple_1.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-ast -analyze %s | FileCheck %s
+;
+;    void jd(int *A, int *B, int c) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = B[c];
+;    }
+;
+; CHECK: if (1 && (&MemRef_B[c + 1] <= &MemRef_A[0] || &MemRef_A[1024] <= &MemRef_B[c]))
+; CHECK:     for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK:       Stmt_for_body(c0);
+; CHECK: else
+; CHECK:     /* original code */
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %B, i32 %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %idxprom = sext i32 %c to i64
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %idxprom
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/aliasing_parametric_simple_2.ll b/final/test/Isl/Ast/aliasing_parametric_simple_2.ll
new file mode 100644
index 0000000..16f536b
--- /dev/null
+++ b/final/test/Isl/Ast/aliasing_parametric_simple_2.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s
+;
+;    void jd(int *A, int *B, int c) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = B[c - 10] + B[5];
+;    }
+;
+; CHECK: if (1 && 0 == c <= -{{[0-9]*}} && (&MemRef_B[max(6, c - 9)] <= &MemRef_A[0] || &MemRef_A[1024] <= &MemRef_B[min(5, c - 10)]))
+; CHECK:     for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK:       Stmt_for_body(c0);
+; CHECK: else
+; CHECK:    /* original code */
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %B, i32 %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %sub = add nsw i32 %c, -10
+  %idxprom = sext i32 %sub to i64
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %idxprom
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds i32, i32* %B, i64 5
+  %tmp1 = load i32, i32* %arrayidx1, align 4
+  %add = add nsw i32 %tmp, %tmp1
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %add, i32* %arrayidx3, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/dependence_distance_constant.ll b/final/test/Isl/Ast/dependence_distance_constant.ll
new file mode 100644
index 0000000..ffa8cd1
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_constant.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+;
+;        void f(int *A, int N) {
+; CHECK:   #pragma minimal dependence distance: 1
+; PINFO:   for.cond: Loop is not parallel.
+;          for (int j = 0; j < N; j++)
+; CHECK:      #pragma minimal dependence distance: 8
+; PINFO-NEXT: for.cond1: Loop is not parallel.
+;             for (int i = 0; i < N; i++)
+;               A[i + 8] = A[i] + 1;
+;        }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc6, %entry
+  %j.0 = phi i32 [ 0, %entry ], [ %inc7, %for.inc6 ]
+  %cmp = icmp slt i32 %j.0, %N
+  br i1 %cmp, label %for.body, label %for.end8
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %i.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, %N
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 1
+  %add4 = add nsw i32 %i.0, 8
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i32 %add4
+  store i32 %add, i32* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc6
+
+for.inc6:                                         ; preds = %for.end
+  %inc7 = add nsw i32 %j.0, 1
+  br label %for.cond
+
+for.end8:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/dependence_distance_multiple_constant.ll b/final/test/Isl/Ast/dependence_distance_multiple_constant.ll
new file mode 100644
index 0000000..fdb1902
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_multiple_constant.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -basicaa -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+;
+;        void f(int *restrict A, int *restrict B, int N) {
+; CHECK:   #pragma minimal dependence distance: 5
+; PINFO:   for.cond: Loop is not parallel.
+;          for (int i = 0; i < N; i++) {
+;            A[i + 7] = A[i] + 1;
+;            B[i + 5] = B[i] + 1;
+;          }
+;        }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* noalias %A, i32* noalias %B, i32 %N) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp slt i32 %i.0, %N
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 1
+  %add1 = add nsw i32 %i.0, 7
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i32 %add1
+  store i32 %add, i32* %arrayidx2, align 4
+  %arrayidx3 = getelementptr inbounds i32, i32* %B, i32 %i.0
+  %tmp1 = load i32, i32* %arrayidx3, align 4
+  %add4 = add nsw i32 %tmp1, 1
+  %add5 = add nsw i32 %i.0, 5
+  %arrayidx6 = getelementptr inbounds i32, i32* %B, i32 %add5
+  store i32 %add4, i32* %arrayidx6, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/dependence_distance_parametric.ll b/final/test/Isl/Ast/dependence_distance_parametric.ll
new file mode 100644
index 0000000..e979a9f
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_parametric.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+;
+;        void f(int *A, int N, int c) {
+; CHECK:   #pragma minimal dependence distance: 1
+; PINFO:   for.cond: Loop is not parallel.
+;          for (int j = 0; j < N; j++)
+; CHECK:      #pragma minimal dependence distance: max(-c, c)
+; PINFO-NEXT: for.cond1: Loop is not parallel.
+;             for (int i = 0; i < N; i++)
+;               A[i + c] = A[i] + 1;
+;        }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %A, i32 %N, i32 %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc6, %entry
+  %j.0 = phi i32 [ 0, %entry ], [ %inc7, %for.inc6 ]
+  %cmp = icmp slt i32 %j.0, %N
+  br i1 %cmp, label %for.body, label %for.end8
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %i.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, %N
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 1
+  %add4 = add nsw i32 %i.0, %c
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i32 %add4
+  store i32 %add, i32* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc6
+
+for.inc6:                                         ; preds = %for.end
+  %inc7 = add nsw i32 %j.0, 1
+  br label %for.cond
+
+for.end8:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/dependence_distance_parametric_expr.ll b/final/test/Isl/Ast/dependence_distance_parametric_expr.ll
new file mode 100644
index 0000000..1b5aad3
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_parametric_expr.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+;
+;        void f(int *A, int N, int c, int v) {
+; CHECK:   #pragma minimal dependence distance: 1
+; PINFO:   for.cond: Loop is not parallel.
+;          for (int j = 0; j < N; j++)
+; CHECK:      #pragma minimal dependence distance: max(-c - v, c + v)
+; PINFO-NEXT: for.cond1: Loop is not parallel.
+;             for (int i = 0; i < N; i++)
+;               A[i + c + v] = A[i] + 1;
+;        }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %A, i32 %N, i32 %c, i32 %v) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc7, %entry
+  %j.0 = phi i32 [ 0, %entry ], [ %inc8, %for.inc7 ]
+  %cmp = icmp slt i32 %j.0, %N
+  br i1 %cmp, label %for.body, label %for.end9
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %i.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, %N
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 1
+  %add4 = add nsw i32 %i.0, %c
+  %add5 = add nsw i32 %add4, %v
+  %arrayidx6 = getelementptr inbounds i32, i32* %A, i32 %add5
+  store i32 %add, i32* %arrayidx6, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc7
+
+for.inc7:                                         ; preds = %for.end
+  %inc8 = add nsw i32 %j.0, 1
+  br label %for.cond
+
+for.end9:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/dependence_distance_varying.ll b/final/test/Isl/Ast/dependence_distance_varying.ll
new file mode 100644
index 0000000..ff524d9
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_varying.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+;
+;         void f(int *A, int N) {
+; CHECK:    #pragma minimal dependence distance: ((N - 1) % 2) + 1
+; PINFO:    for.cond: Loop is not parallel.
+;           for (int i = 0; i < N; i++)
+;             A[i] = A[N - i] + 1;
+;         }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp slt i32 %i.0, %N
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %sub = sub nsw i32 %N, %i.0
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %sub
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 1
+  %arrayidx1 = getelementptr inbounds i32, i32* %A, i32 %i.0
+  store i32 %add, i32* %arrayidx1, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/dependence_distance_varying_in_outer_loop.ll b/final/test/Isl/Ast/dependence_distance_varying_in_outer_loop.ll
new file mode 100644
index 0000000..3b07f64
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_varying_in_outer_loop.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-canonicalize -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+;
+;        void f(int *restrict A, int *restrict sum) {
+; CHECK:   #pragma minimal dependence distance: 1
+; PINFO:    for.cond: Loop is not parallel.
+;          for (int j = 0; j < 1024; j++)
+; CHECK:      #pragma minimal dependence distance: 1
+; PINFO-NEXT: for.cond1: Loop is not parallel.
+;             for (int i = j; i < 1024; i++)
+;               A[i - 3] = A[j] * 2 + A[j] + 2;
+;        }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* noalias %A, i32* noalias %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc7, %entry
+  %j.0 = phi i32 [ 0, %entry ], [ %inc8, %for.inc7 ]
+  %exitcond1 = icmp ne i32 %j.0, 1024
+  br i1 %exitcond1, label %for.body, label %for.end9
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %i.0 = phi i32 [ %j.0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %j.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = mul nsw i32 %tmp, 3
+  %add5 = add nsw i32 %add, 2
+  %sub = add nsw i32 %i.0, -3
+  %arrayidx6 = getelementptr inbounds i32, i32* %A, i32 %sub
+  store i32 %add5, i32* %arrayidx6, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc7
+
+for.inc7:                                         ; preds = %for.end
+  %inc8 = add nsw i32 %j.0, 1
+  br label %for.cond
+
+for.end9:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/dependence_distance_varying_multiple.ll b/final/test/Isl/Ast/dependence_distance_varying_multiple.ll
new file mode 100644
index 0000000..3bad27c
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_varying_multiple.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -basicaa -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+;
+;        void f(int *restrict A, int *restrict B, int *restrict C, int *restrict D,
+;               int *restrict E, int N) {
+; CHECK:   #pragma minimal dependence distance: N >= 35 ? 1 : N >= 17 && N <= 34 ? 2 : 5
+; PINFO:   for.cond: Loop is not parallel.
+;          for (int i = 0; i < N; i++) {
+;            A[i] = A[100 - 2 * i] + 1;
+;            B[i] = B[100 - 3 * i] + 1;
+;            C[i] = C[100 - 4 * i] + 1;
+;            D[i] = D[100 - 5 * i] + 1;
+;            E[i] = E[100 - 6 * i] + 1;
+;          }
+;        }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* noalias %A, i32* noalias %B, i32* noalias %C, i32* noalias %D, i32* noalias %E, i32 %N) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp slt i32 %i.0, %N
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %mul = shl nsw i32 %i.0, 1
+  %sub = sub nsw i32 100, %mul
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %sub
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 1
+  %arrayidx1 = getelementptr inbounds i32, i32* %A, i32 %i.0
+  store i32 %add, i32* %arrayidx1, align 4
+  %tmp1 = mul i32 %i.0, -3
+  %sub3 = add i32 %tmp1, 100
+  %arrayidx4 = getelementptr inbounds i32, i32* %B, i32 %sub3
+  %tmp2 = load i32, i32* %arrayidx4, align 4
+  %add5 = add nsw i32 %tmp2, 1
+  %arrayidx6 = getelementptr inbounds i32, i32* %B, i32 %i.0
+  store i32 %add5, i32* %arrayidx6, align 4
+  %mul7 = shl nsw i32 %i.0, 2
+  %sub8 = sub nsw i32 100, %mul7
+  %arrayidx9 = getelementptr inbounds i32, i32* %C, i32 %sub8
+  %tmp3 = load i32, i32* %arrayidx9, align 4
+  %add10 = add nsw i32 %tmp3, 1
+  %arrayidx11 = getelementptr inbounds i32, i32* %C, i32 %i.0
+  store i32 %add10, i32* %arrayidx11, align 4
+  %tmp4 = mul i32 %i.0, -5
+  %sub13 = add i32 %tmp4, 100
+  %arrayidx14 = getelementptr inbounds i32, i32* %D, i32 %sub13
+  %tmp5 = load i32, i32* %arrayidx14, align 4
+  %add15 = add nsw i32 %tmp5, 1
+  %arrayidx16 = getelementptr inbounds i32, i32* %D, i32 %i.0
+  store i32 %add15, i32* %arrayidx16, align 4
+  %tmp6 = mul i32 %i.0, -6
+  %sub18 = add i32 %tmp6, 100
+  %arrayidx19 = getelementptr inbounds i32, i32* %E, i32 %sub18
+  %tmp7 = load i32, i32* %arrayidx19, align 4
+  %add20 = add nsw i32 %tmp7, 1
+  %arrayidx21 = getelementptr inbounds i32, i32* %E, i32 %i.0
+  store i32 %add20, i32* %arrayidx21, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/domain_bounded_only_with_context.ll b/final/test/Isl/Ast/domain_bounded_only_with_context.ll
new file mode 100644
index 0000000..1925add
--- /dev/null
+++ b/final/test/Isl/Ast/domain_bounded_only_with_context.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s
+
+; CHECK:      {
+; CHECK-NEXT:    if (p <= -1 || p >= 1)
+; CHECK-NEXT:      Stmt_preheader();
+; CHECK-NEXT:    for (int c0 = 0; c0 < 2 * p; c0 += 1)
+; CHECK-NEXT:      Stmt_loop(c0);
+; CHECK-NEXT:    if (p <= -1) {
+; CHECK-NEXT:      for (int c0 = 0; c0 <= 2 * p + 255; c0 += 1)
+; CHECK-NEXT:        Stmt_loop(c0);
+; CHECK-NEXT:    } else if (p == 0) {
+; CHECK-NEXT:      Stmt_side();
+; CHECK-NEXT:    }
+; CHECK-NEXT:  }
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+
+define void @zot(float* %A, i32 %arg) {
+bb:
+  %p = ashr i32 %arg, 25
+  %tmpEven = shl nsw i32 %p, 1
+  %tmp3 = and i32 %tmpEven, 254
+  br label %cond
+
+cond:
+  %tmpEvenTrunc = trunc i32 %tmpEven to i8
+  %br.cmp = icmp eq i8 %tmpEvenTrunc, 0
+  br i1 %br.cmp, label %side, label %preheader
+
+preheader:
+  store float 1.0, float* %A
+  br label %loop
+
+loop:
+  %indvar = phi i32 [ %indvar.next, %loop ], [ 1, %preheader ]
+  store float 1.0, float* %A
+  %indvar.next = add nuw nsw i32 %indvar, 1
+  %cmp = icmp eq i32 %indvar, %tmp3
+  br i1 %cmp, label %exit, label %loop
+
+side:
+  store float 1.0, float* %A
+  br label %ret
+
+exit:
+  br label %ret
+
+ret:
+  ret void
+}
diff --git a/final/test/Isl/Ast/non_affine_access.ll b/final/test/Isl/Ast/non_affine_access.ll
new file mode 100644
index 0000000..7131c81
--- /dev/null
+++ b/final/test/Isl/Ast/non_affine_access.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-print-accesses -analyze \
+; RUN:   -polly-allow-nonaffine < %s \
+; RUN:   | FileCheck %s
+;
+;    void non_affine_access(float A[]) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i * i] = 1;
+;    }
+
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK:   Stmt_bb3(
+; CHECK:     /* write */  MemRef_A[*]
+; CHECK:   );
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+define void @non_affine_access(float* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb3, label %bb2
+
+bb2:                                              ; preds = %bb1
+  br label %bb8
+
+bb3:                                              ; preds = %bb1
+  %prod = mul i64 %i.0, %i.0
+  %tmp5 = getelementptr inbounds float, float* %A, i64 %prod
+  store float 1.000000e+00, float* %tmp5, align 4, !tbaa !5
+  br label %bb6
+
+bb6:                                              ; preds = %bb3
+  %tmp7 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb2
+  ret void
+}
+
+!llvm.ident = !{!0}
+
+!0 = !{!"Ubuntu clang version 3.7.1-3ubuntu4 (tags/RELEASE_371/final) (based on LLVM 3.7.1)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"long", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!6, !6, i64 0}
+!6 = !{!"float", !3, i64 0}
diff --git a/final/test/Isl/Ast/reduction_clauses_multidimensional_access.ll b/final/test/Isl/Ast/reduction_clauses_multidimensional_access.ll
new file mode 100644
index 0000000..499a843
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_clauses_multidimensional_access.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+;
+; CHECK: #pragma known-parallel reduction (^ : MemRef_sum)
+;        void f(int N, int M, int P, int sum[P][M]) {
+; PINFO:   for.cond: Loop is not parallel.
+;          for (int i = 0; i < N; i++)
+; PINFO-NEXT: for.cond1: Loop is parallel.
+;             for (int j = 0; j < P; j++)
+; CHECK:        #pragma simd
+; PINFO-NEXT:   for.cond4: Loop is parallel.
+;               for (int k = 0; k < M; k++)
+;                 sum[j][k] ^= j;
+;        }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32 %N, i32 %M, i32 %P, i32* %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc11, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc12, %for.inc11 ]
+  %cmp = icmp slt i32 %i.0, %N
+  br i1 %cmp, label %for.body, label %for.end13
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc8, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc9, %for.inc8 ]
+  %cmp2 = icmp slt i32 %j.0, %P
+  br i1 %cmp2, label %for.body3, label %for.end10
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc, %for.body3
+  %k.0 = phi i32 [ 0, %for.body3 ], [ %inc, %for.inc ]
+  %cmp5 = icmp slt i32 %k.0, %M
+  br i1 %cmp5, label %for.body6, label %for.end
+
+for.body6:                                        ; preds = %for.cond4
+  %tmp = mul nsw i32 %j.0, %M
+  %arrayidx.sum = add i32 %tmp, %k.0
+  %arrayidx7 = getelementptr inbounds i32, i32* %sum, i32 %arrayidx.sum
+  %tmp1 = load i32, i32* %arrayidx7, align 4
+  %xor = xor i32 %tmp1, %j.0
+  store i32 %xor, i32* %arrayidx7, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body6
+  %inc = add nsw i32 %k.0, 1
+  br label %for.cond4
+
+for.end:                                          ; preds = %for.cond4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %for.end
+  %inc9 = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end10:                                        ; preds = %for.cond1
+  br label %for.inc11
+
+for.inc11:                                        ; preds = %for.end10
+  %inc12 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end13:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_clauses_onedimensional_access.ll b/final/test/Isl/Ast/reduction_clauses_onedimensional_access.ll
new file mode 100644
index 0000000..2f2c2ab
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_clauses_onedimensional_access.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK: #pragma known-parallel reduction (^ : MemRef_sum)
+;        void f(int N, int M, int *sum) {
+;          for (int i = 0; i < N; i++)
+; CHECK:    #pragma simd
+;            for (int j = 0; j < M; j++)
+;              sum[j] ^= j;
+;        }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32 %N, i32 %M, i32* %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc5, %for.inc4 ]
+  %cmp = icmp slt i32 %i.0, %N
+  br i1 %cmp, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %cmp2 = icmp slt i32 %j.0, %M
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %sum, i32 %j.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %xor = xor i32 %tmp, %j.0
+  store i32 %xor, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %inc5 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_dependences_equal_non_reduction_dependences.ll b/final/test/Isl/Ast/reduction_dependences_equal_non_reduction_dependences.ll
new file mode 100644
index 0000000..ad39f43
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_dependences_equal_non_reduction_dependences.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -basicaa -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; This loopnest contains a reduction which imposes the same dependences as the
+; accesses to the array A. We need to ensure we do __not__ parallelize anything
+; here.
+;
+; CHECK: #pragma minimal dependence distance: 1
+; CHECK-NOT: pragma
+; CHECK-NOT: reduction
+;
+;    void AandSum(int *restrict sum, int *restrict A) {
+;      for (int i = 0; i < 1024; i++) {
+;        A[i] = A[i] + A[i - 1];
+;        A[i - 1] = A[i] + A[i - 2];
+;        *sum += i;
+;      }
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @AandSum(i32* noalias %sum, i32* noalias %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %sub = add nsw i32 %i.0, -1
+  %arrayidx1 = getelementptr inbounds i32, i32* %A, i32 %sub
+  %tmp1 = load i32, i32* %arrayidx1, align 4
+  %add = add nsw i32 %tmp, %tmp1
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i32 %i.0
+  store i32 %add, i32* %arrayidx2, align 4
+  %sub4 = add nsw i32 %i.0, -2
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i32 %sub4
+  %tmp2 = load i32, i32* %arrayidx5, align 4
+  %add6 = add nsw i32 %add, %tmp2
+  %sub7 = add nsw i32 %i.0, -1
+  %arrayidx8 = getelementptr inbounds i32, i32* %A, i32 %sub7
+  store i32 %add6, i32* %arrayidx8, align 4
+  %tmp3 = load i32, i32* %sum, align 4
+  %add9 = add nsw i32 %tmp3, %i.0
+  store i32 %add9, i32* %sum, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_different_reduction_clauses.ll b/final/test/Isl/Ast/reduction_different_reduction_clauses.ll
new file mode 100644
index 0000000..b423a47
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_different_reduction_clauses.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -basicaa -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK: #pragma simd reduction (+ : MemRef_sum{{[1,2]}}, MemRef_sum{{[1,2]}}) reduction (* : MemRef_prod) reduction (| : MemRef_or) reduction (& : MemRef_and)
+; CHECK: #pragma known-parallel reduction (+ : MemRef_sum{{[1,2]}}, MemRef_sum{{[1,2]}}) reduction (* : MemRef_prod) reduction (| : MemRef_or) reduction (& : MemRef_and)
+; CHECK: for (int c0 = 0; c0 < N; c0 += 1)
+; CHECK:   Stmt_for_body(c0);
+;
+;    void f(int N, int *restrict sum1, int *restrict sum2, int *restrict prod,
+;           int *restrict and, int *restrict or ) {
+;      for (int i = 0; i < N; i++) {
+;        *sum1 += i;
+;        *sum2 += i + 1;
+;        *prod *= i;
+;        *and &= i;
+;        * or |= i;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32 %N, i32* noalias %sum1, i32* noalias %sum2, i32* noalias %prod, i32* noalias %and, i32* noalias %or) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp slt i32 %i.0, %N
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = load i32, i32* %sum1, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %sum1, align 4
+  %add1 = add nsw i32 %i.0, 1
+  %tmp1 = load i32, i32* %sum2, align 4
+  %add2 = add nsw i32 %tmp1, %add1
+  store i32 %add2, i32* %sum2, align 4
+  %tmp2 = load i32, i32* %prod, align 4
+  %mul = mul nsw i32 %tmp2, %i.0
+  store i32 %mul, i32* %prod, align 4
+  %tmp3 = load i32, i32* %and, align 4
+  %and3 = and i32 %tmp3, %i.0
+  store i32 %and3, i32* %and, align 4
+  %tmp4 = load i32, i32* %or, align 4
+  %or4 = or i32 %tmp4, %i.0
+  store i32 %or4, i32* %or, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_in_one_dimension.ll b/final/test/Isl/Ast/reduction_in_one_dimension.ll
new file mode 100644
index 0000000..70f3c7a
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_in_one_dimension.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+;
+; Verify that we won't privatize anything in the outer dimension
+;
+; CHECK:    #pragma known-parallel
+; PINFO:    for.cond: Loop is parallel.
+; CHECK:    for (int c0 = 0; c0 < 2 * n; c0 += 1)
+; CHECK:      #pragma simd reduction
+; PINFO-NEXT: for.cond1: Loop is not parallel.
+; CHECK:      for (int c1 = 0; c1 <= 1023; c1 += 1)
+; CHECK:        Stmt_for_body3(c0, c1);
+;
+;    void foo(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+;        for (long j = 0; j < 1024; j++)
+;          A[i] += i;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @foo(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc5, %for.inc4 ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %inc5 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_loop_reversal.ll b/final/test/Isl/Ast/reduction_loop_reversal.ll
new file mode 100644
index 0000000..ce80dc4
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_loop_reversal.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+;
+; CHECK-NOT: #pragma simd{{\s*$}}
+; CHECK: #pragma simd reduction
+; CHECK: Stmt_S0(n - c1)
+; CHECK: #pragma simd{{\s*$}}
+; CHECK: Stmt_S1(n - c1)
+;
+; PINFO:       for.cond2: Loop is parallel.
+; PINFO-NEXT:  for.cond: Loop is not parallel.
+;
+;    void rlr(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rlr(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/Isl/Ast/reduction_modulo_and_loop_reversal_schedule.ll b/final/test/Isl/Ast/reduction_modulo_and_loop_reversal_schedule.ll
new file mode 100644
index 0000000..f67de2d
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_and_loop_reversal_schedule.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK:          #pragma known-parallel reduction (+ : MemRef_A)
+; CHECK-NEXT:     for (int c0 = 0; c0 <= 2; c0 += 1) {
+; CHECK-NEXT:       if (c0 == 1) {
+; CHECK-NEXT:         #pragma simd
+; CHECK-NEXT:         for (int c1 = 0; c1 < 2 * n; c1 += 1)
+; CHECK-NEXT:           Stmt_S1(c1);
+; CHECK-NEXT:       } else
+; CHECK-NEXT:         #pragma simd reduction (+ : MemRef_A)
+; CHECK-NEXT:         for (int c1 = (-c0 / 2) + 2; c1 <= 2 * n; c1 += 2)
+; CHECK-NEXT:           Stmt_S0(2 * n - c1);
+; CHECK-NEXT:     }
+;
+;    void rmalrs(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rmalrs(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/Isl/Ast/reduction_modulo_and_loop_reversal_schedule_2.ll b/final/test/Isl/Ast/reduction_modulo_and_loop_reversal_schedule_2.ll
new file mode 100644
index 0000000..ada7700
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_and_loop_reversal_schedule_2.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK:    #pragma known-parallel reduction
+; CHECK:    for (int c0 = 0; c0 <= 2; c0 += 1) {
+; CHECK:      if (c0 == 2) {
+; CHECK:        #pragma simd reduction
+; CHECK:        for (int c1 = 1; c1 < 2 * n; c1 += 2)
+; CHECK:          Stmt_S0(c1);
+; CHECK:      } else if (c0 == 1) {
+; CHECK:        #pragma simd
+; CHECK:        for (int c1 = 0; c1 < 2 * n; c1 += 1)
+; CHECK:          Stmt_S1(c1);
+; CHECK:      } else
+; CHECK:        #pragma simd reduction
+; CHECK:        for (int c1 = -2 * n + 2; c1 <= 0; c1 += 2)
+; CHECK:          Stmt_S0(-c1);
+; CHECK:    }
+;
+;    void rmalrs2(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rmalrs2(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/Isl/Ast/reduction_modulo_schedule.ll b/final/test/Isl/Ast/reduction_modulo_schedule.ll
new file mode 100644
index 0000000..4cdfbad
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_schedule.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polyhedral-info -polly-check-parallel -analyze < %s | FileCheck %s -check-prefix=PINFO
+;
+; CHECK:          #pragma known-parallel reduction (+ : MemRef_A)
+; CHECK-NEXT:     for (int c0 = 0; c0 <= 2; c0 += 1) {
+; CHECK-NEXT:       if (c0 == 1) {
+; CHECK-NEXT:         #pragma simd
+; CHECK-NEXT:         for (int c1 = 0; c1 < 2 * n; c1 += 1)
+; CHECK-NEXT:           Stmt_S1(c1);
+; CHECK-NEXT:       } else
+; CHECK-NEXT:         #pragma simd reduction (+ : MemRef_A)
+; CHECK-NEXT:         for (int c1 = c0 / 2; c1 < 2 * n; c1 += 2)
+; CHECK-NEXT:           Stmt_S0(c1);
+; CHECK-NEXT:     }
+;
+; PINFO:      for.cond2: Loop is parallel.
+; PINFO-NEXT: for.cond: Loop is not parallel.
+;
+;    void rms(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rms(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions.ll b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions.ll
new file mode 100644
index 0000000..807cce0
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK:    #pragma known-parallel
+; CHECK:    for (int c0 = 0; c0 <= 1; c0 += 1)
+; CHECK:      for (int c1 = c0; c1 < 2 * n; c1 += 2)
+; CHECK:        #pragma simd reduction
+; CHECK:        for (int c3 = 0; c3 <= 1023; c3 += 1)
+; CHECK:          Stmt_for_body3(c1, c3);
+;
+;    void rmsmd(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+;        for (long j = 0; j < 1024; j++)
+;          A[i] += i;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rmsmd(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc5, %for.inc4 ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %inc5 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_2.ll b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_2.ll
new file mode 100644
index 0000000..ca108fc
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_2.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; Verify that the outer dimension doesnt't carry reduction dependences
+;
+; CHECK-NOT:#pragma known-parallel reduction
+; CHECK:    #pragma known-parallel
+; CHECK:    for (int c1 = 0; c1 < 2 * n; c1 += 1)
+; CHECK:      #pragma simd reduction
+; CHECK:      for (int c3 = 0; c3 <= 1023; c3 += 1)
+; CHECK:        Stmt_for_body3(c1, c3);
+;
+;    void rmsmd2(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+;        for (long j = 0; j < 1024; j++)
+;          A[i] += i;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rmsmd2(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc5, %for.inc4 ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %inc5 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_3.ll b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_3.ll
new file mode 100644
index 0000000..a43349f
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_3.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; Verify that the outer dimension doesnt't carry reduction dependences
+;
+; CHECK-NOT:#pragma known-parallel reduction
+; CHECK:    #pragma known-parallel
+; CHECK:    for (int c1 = 0; c1 < 2 * n; c1 += 1)
+; CHECK:      #pragma simd reduction
+; CHECK:      for (int c3 = 0; c3 <= 1023; c3 += 1)
+; CHECK:        Stmt_for_body3(c1, c3);
+;
+;    void rmsmd3(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+;        for (long j = 0; j < 1024; j++)
+;          A[i] += i;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rmsmd3(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc5, %for.inc4 ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %inc5 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_4.ll b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_4.ll
new file mode 100644
index 0000000..2fb966e
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_4.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; Verify that the outer dimension doesnt't carry reduction dependences
+;
+; CHECK-NOT:#pragma known-parallel reduction
+; CHECK:    #pragma known-parallel
+; CHECK:    for (int c1 = 0; c1 < 2 * n; c1 += 1)
+; CHECK:      #pragma simd reduction
+; CHECK:      for (int c3 = -1023; c3 <= 1023; c3 += 1) {
+; CHECK:        if (c3 >= 1 && (c3 + 1) % 2 == 0) {
+; CHECK:          Stmt_for_body3(c1, c3);
+; CHECK:        } else if (c3 <= 0 && c3 % 2 == 0) {
+; CHECK:          Stmt_for_body3(c1, -c3);
+; CHECK:        }
+; CHECK:      }
+;
+;    void rmsmd4(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+;        for (long j = 0; j < 1024; j++)
+;          A[i] += i;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rmsmd4(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc5, %for.inc4 ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %inc5 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_5.ll b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_5.ll
new file mode 100644
index 0000000..cb801f8
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_5.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; Verify that only the outer dimension needs privatization
+;
+; CHECK:    #pragma known-parallel reduction
+; CHECK:    for (int c1 = 0; c1 <= 1023; c1 += 1) {
+; CHECK:      if ((c1 + 1) % 2 == 0) {
+; CHECK-NOT:    #pragma simd reduction
+; CHECK:        #pragma simd
+; CHECK:        for (int c3 = -2 * n + 1; c3 <= 0; c3 += 1)
+; CHECK:          Stmt_for_body3(-c3, c1);
+; CHECK:      } else {
+; CHECK-NOT:    #pragma simd reduction
+; CHECK:        #pragma simd
+; CHECK:        for (int c3 = 0; c3 < 2 * n; c3 += 1)
+; CHECK:          Stmt_for_body3(c3, c1);
+; CHECK:      }
+; CHECK:    }
+;
+;    void rmsmd5(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+;        for (long j = 0; j < 1024; j++)
+;          A[i] += i;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rmsmd5(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc5, %for.inc4 ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %inc5 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_multiple_dimensions.ll b/final/test/Isl/Ast/reduction_multiple_dimensions.ll
new file mode 100644
index 0000000..6a6a6f6
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_multiple_dimensions.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK-NOT:#pragma known-parallel reduction
+; CHECK:    #pragma known-parallel
+; CHECK:    for (int c0 = 0; c0 <= 2047; c0 += 1)
+; CHECK:      for (int c1 = 0; c1 <= 1023; c1 += 1)
+; CHECK:        #pragma simd reduction
+; CHECK:        for (int c2 = 0; c2 <= 511; c2 += 1)
+; CHECK:          Stmt_for_body6(c0, c1, c2);
+;
+;    void rmd(int *A) {
+;      for (long i = 0; i < 2048; i++)
+;        for (long j = 0; j < 1024; j++)
+;          for (long k = 0; k < 512; k++)
+;            A[i] += i;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rmd(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc10, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc11, %for.inc10 ]
+  %exitcond2 = icmp ne i32 %i.0, 2048
+  br i1 %exitcond2, label %for.body, label %for.end12
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc7, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc8, %for.inc7 ]
+  %exitcond1 = icmp ne i32 %j.0, 1024
+  br i1 %exitcond1, label %for.body3, label %for.end9
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc, %for.body3
+  %k.0 = phi i32 [ 0, %for.body3 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %k.0, 512
+  br i1 %exitcond, label %for.body6, label %for.end
+
+for.body6:                                        ; preds = %for.cond4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body6
+  %inc = add nsw i32 %k.0, 1
+  br label %for.cond4
+
+for.end:                                          ; preds = %for.cond4
+  br label %for.inc7
+
+for.inc7:                                         ; preds = %for.end
+  %inc8 = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end9:                                         ; preds = %for.cond1
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.end9
+  %inc11 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end12:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_multiple_dimensions_2.ll b/final/test/Isl/Ast/reduction_multiple_dimensions_2.ll
new file mode 100644
index 0000000..40bb6c7
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_multiple_dimensions_2.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK-NOT:#pragma known-parallel reduction
+; CHECK:    #pragma known-parallel
+; CHECK:    for (int c0 = 0; c0 <= 2047; c0 += 1)
+; CHECK:      for (int c1 = 0; c1 <= 1023; c1 += 1)
+; CHECK:        #pragma simd reduction
+; CHECK:        for (int c2 = 0; c2 <= 511; c2 += 1)
+; CHECK:          Stmt_for_body6(c0, c1, c2);
+;
+;    void rmd2(int *A) {
+;      for (long i = 0; i < 2048; i++)
+;        for (long j = 0; j < 1024; j++)
+;          for (long k = 0; k < 512; k++)
+;            A[i] += i;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rmd2(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc10, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc11, %for.inc10 ]
+  %exitcond2 = icmp ne i32 %i.0, 2048
+  br i1 %exitcond2, label %for.body, label %for.end12
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc7, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc8, %for.inc7 ]
+  %exitcond1 = icmp ne i32 %j.0, 1024
+  br i1 %exitcond1, label %for.body3, label %for.end9
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc, %for.body3
+  %k.0 = phi i32 [ 0, %for.body3 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %k.0, 512
+  br i1 %exitcond, label %for.body6, label %for.end
+
+for.body6:                                        ; preds = %for.cond4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body6
+  %inc = add nsw i32 %k.0, 1
+  br label %for.cond4
+
+for.end:                                          ; preds = %for.cond4
+  br label %for.inc7
+
+for.inc7:                                         ; preds = %for.end
+  %inc8 = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end9:                                         ; preds = %for.cond1
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.end9
+  %inc11 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end12:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_multiple_dimensions_3.ll b/final/test/Isl/Ast/reduction_multiple_dimensions_3.ll
new file mode 100644
index 0000000..9f799c1
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_multiple_dimensions_3.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK-NOT:#pragma known-parallel reduction
+; CHECK:    #pragma known-parallel
+; CHECK:    for (int c0 = 0; c0 <= 2047; c0 += 1)
+; CHECK:      for (int c1 = 0; c1 <= 1023; c1 += 1)
+; CHECK:        #pragma simd reduction
+; CHECK:        for (int c2 = 0; c2 <= 511; c2 += 1)
+; CHECK:          Stmt_for_body6(c0, c1, c2);
+;
+;    void rmd3(int *A) {
+;      for (long i = 0; i < 2048; i++)
+;        for (long j = 0; j < 1024; j++)
+;          for (long k = 0; k < 512; k++)
+;            A[i] += i;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rmd3(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc10, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc11, %for.inc10 ]
+  %exitcond2 = icmp ne i32 %i.0, 2048
+  br i1 %exitcond2, label %for.body, label %for.end12
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc7, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc8, %for.inc7 ]
+  %exitcond1 = icmp ne i32 %j.0, 1024
+  br i1 %exitcond1, label %for.body3, label %for.end9
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc, %for.body3
+  %k.0 = phi i32 [ 0, %for.body3 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %k.0, 512
+  br i1 %exitcond, label %for.body6, label %for.end
+
+for.body6:                                        ; preds = %for.cond4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body6
+  %inc = add nsw i32 %k.0, 1
+  br label %for.cond4
+
+for.end:                                          ; preds = %for.cond4
+  br label %for.inc7
+
+for.inc7:                                         ; preds = %for.end
+  %inc8 = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end9:                                         ; preds = %for.cond1
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.end9
+  %inc11 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end12:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/reduction_multiple_dimensions_4.ll b/final/test/Isl/Ast/reduction_multiple_dimensions_4.ll
new file mode 100644
index 0000000..bb46b9e
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_multiple_dimensions_4.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK-NOT:#pragma known-parallel reduction
+; CHECK:    #pragma known-parallel
+; CHECK:    for (int c0 = 0; c0 <= 2047; c0 += 1)
+; CHECK:      for (int c1 = 0; c1 <= 1023; c1 += 1)
+; CHECK:        #pragma simd reduction
+; CHECK:        for (int c2 = 0; c2 <= 511; c2 += 1)
+; CHECK:          Stmt_for_body6(c0, c1, c2);
+;
+;    void rmd4(int *A) {
+;      for (long i = 0; i < 2048; i++)
+;        for (long j = 0; j < 1024; j++)
+;          for (long k = 0; k < 512; k++)
+;            A[i] += i;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @rmd4(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc10, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc11, %for.inc10 ]
+  %exitcond2 = icmp ne i32 %i.0, 2048
+  br i1 %exitcond2, label %for.body, label %for.end12
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc7, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc8, %for.inc7 ]
+  %exitcond1 = icmp ne i32 %j.0, 1024
+  br i1 %exitcond1, label %for.body3, label %for.end9
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc, %for.body3
+  %k.0 = phi i32 [ 0, %for.body3 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %k.0, 512
+  br i1 %exitcond, label %for.body6, label %for.end
+
+for.body6:                                        ; preds = %for.cond4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body6
+  %inc = add nsw i32 %k.0, 1
+  br label %for.cond4
+
+for.end:                                          ; preds = %for.cond4
+  br label %for.inc7
+
+for.inc7:                                         ; preds = %for.end
+  %inc8 = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end9:                                         ; preds = %for.cond1
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.end9
+  %inc11 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end12:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/Ast/rlr___%for.cond---%for.end10.jscop b/final/test/Isl/Ast/rlr___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..70e0203
--- /dev/null
+++ b/final/test/Isl/Ast/rlr___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/rmalrs2___%for.cond---%for.end10.jscop b/final/test/Isl/Ast/rmalrs2___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..4cdd690
--- /dev/null
+++ b/final/test/Isl/Ast/rmalrs2___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, -i0, 0]: i0 % 2 = 0; Stmt_S0[i0] -> [2, i0, 0]: i0 % 2 = 1 }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/rmalrs___%for.cond---%for.end10.jscop b/final/test/Isl/Ast/rmalrs___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..74d4252
--- /dev/null
+++ b/final/test/Isl/Ast/rmalrs___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, 2 * n - i0, 0]: i0 % 2 = 0; Stmt_S0[i0] -> [2, 2  * n - i0, 0]: i0 % 2 = 1 }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/rmd2___%for.cond---%for.end12.jscop b/final/test/Isl/Ast/rmd2___%for.cond---%for.end12.jscop
new file mode 100644
index 0000000..f1a2856
--- /dev/null
+++ b/final/test/Isl/Ast/rmd2___%for.cond---%for.end12.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end12",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body6[i0, i1, i2] : i0 >= 0 and i0 <= 2047 and i1 >= 0 and i1 <= 1023 and i2 >= 0 and i2 <= 511 }",
+         "name" : "Stmt_for_body6",
+         "schedule" : "{ Stmt_for_body6[i0, i1, i2] -> [0, i1, 0, i0, 0, i2, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/rmd3___%for.cond---%for.end12.jscop b/final/test/Isl/Ast/rmd3___%for.cond---%for.end12.jscop
new file mode 100644
index 0000000..c2a7899
--- /dev/null
+++ b/final/test/Isl/Ast/rmd3___%for.cond---%for.end12.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end12",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body6[i0, i1, i2] : i0 >= 0 and i0 <= 2047 and i1 >= 0 and i1 <= 1023 and i2 >= 0 and i2 <= 511 }",
+         "name" : "Stmt_for_body6",
+         "schedule" : "{ Stmt_for_body6[i0, i1, i2] -> [0, i2, 0, i1, 0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/rmd4___%for.cond---%for.end12.jscop b/final/test/Isl/Ast/rmd4___%for.cond---%for.end12.jscop
new file mode 100644
index 0000000..456c4c5
--- /dev/null
+++ b/final/test/Isl/Ast/rmd4___%for.cond---%for.end12.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end12",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body6[i0, i1, i2] : i0 >= 0 and i0 <= 2047 and i1 >= 0 and i1 <= 1023 and i2 >= 0 and i2 <= 511 }",
+         "name" : "Stmt_for_body6",
+         "schedule" : "{ Stmt_for_body6[i0, i1, i2] -> [0, i2, 0, i0, 0, i1, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/rmd___%for.cond---%for.end12.jscop b/final/test/Isl/Ast/rmd___%for.cond---%for.end12.jscop
new file mode 100644
index 0000000..dfb0e2e
--- /dev/null
+++ b/final/test/Isl/Ast/rmd___%for.cond---%for.end12.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end12",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body6[i0, i1, i2] : i0 >= 0 and i0 <= 2047 and i1 >= 0 and i1 <= 1023 and i2 >= 0 and i2 <= 511 }",
+         "name" : "Stmt_for_body6",
+         "schedule" : "{ Stmt_for_body6[i0, i1, i2] -> [0, i0, 0, i1, 0, i2, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/rms___%for.cond---%for.end10.jscop b/final/test/Isl/Ast/rms___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..6388163
--- /dev/null
+++ b/final/test/Isl/Ast/rms___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, i0, 0]: i0 % 2 = 0; Stmt_S0[i0] -> [2, i0, 0]: i0 % 2 = 1 }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/rmsmd2___%for.cond---%for.end6.jscop b/final/test/Isl/Ast/rmsmd2___%for.cond---%for.end6.jscop
new file mode 100644
index 0000000..e875ef6
--- /dev/null
+++ b/final/test/Isl/Ast/rmsmd2___%for.cond---%for.end6.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end6",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_for_body3[i0, i1] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 and i1 >= 0 and i1 <= 1023 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "[n] -> { Stmt_for_body3[i0, i1] -> [0, i0, 0, i1, 0]: i0 % 2 = 0; Stmt_for_body3[i0, i1] -> [0, i0, 1, i1, 0]: i0 % 2 = 1 }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/rmsmd3___%for.cond---%for.end6.jscop b/final/test/Isl/Ast/rmsmd3___%for.cond---%for.end6.jscop
new file mode 100644
index 0000000..5f89385
--- /dev/null
+++ b/final/test/Isl/Ast/rmsmd3___%for.cond---%for.end6.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end6",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_for_body3[i0, i1] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 and i1 >= 0 and i1 <= 1023 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "[n] -> { Stmt_for_body3[i0, i1] -> [0, i0, 0, i1, 0]: i1 % 2 = 0; Stmt_for_body3[i0, i1] -> [0, i0, 0, i1, 1]: i1 % 2 = 1 }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/rmsmd4___%for.cond---%for.end6.jscop b/final/test/Isl/Ast/rmsmd4___%for.cond---%for.end6.jscop
new file mode 100644
index 0000000..49310ba
--- /dev/null
+++ b/final/test/Isl/Ast/rmsmd4___%for.cond---%for.end6.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end6",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_for_body3[i0, i1] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 and i1 >= 0 and i1 <= 1023 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "[n] -> { Stmt_for_body3[i0, i1] -> [0, i0, 0, -i1, 0]: i1 % 2 = 0; Stmt_for_body3[i0, i1] -> [0, i0, 0, i1, 1]: i1 % 2 = 1 }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/rmsmd5___%for.cond---%for.end6.jscop b/final/test/Isl/Ast/rmsmd5___%for.cond---%for.end6.jscop
new file mode 100644
index 0000000..e77750a
--- /dev/null
+++ b/final/test/Isl/Ast/rmsmd5___%for.cond---%for.end6.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end6",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_for_body3[i0, i1] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 and i1 >= 0 and i1 <= 1023 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "[n] -> { Stmt_for_body3[i0, i1] -> [0, i1, 0, i0, 0]: i1 % 2 = 0; Stmt_for_body3[i0, i1] -> [0, i1, 1, -i0, 0]: i1 % 2 = 1 }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/rmsmd___%for.cond---%for.end6.jscop b/final/test/Isl/Ast/rmsmd___%for.cond---%for.end6.jscop
new file mode 100644
index 0000000..57baa66
--- /dev/null
+++ b/final/test/Isl/Ast/rmsmd___%for.cond---%for.end6.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end6",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_for_body3[i0, i1] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 and i1 >= 0 and i1 <= 1023 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "[n] -> { Stmt_for_body3[i0, i1] -> [0, i0, 0, i1, 0]: i0 % 2 = 0; Stmt_for_body3[i0, i1] -> [1, i0, 0, i1, 0]: i0 % 2 = 1 }"
+      }
+   ]
+}
diff --git a/final/test/Isl/Ast/run-time-condition.ll b/final/test/Isl/Ast/run-time-condition.ll
new file mode 100644
index 0000000..def7d91
--- /dev/null
+++ b/final/test/Isl/Ast/run-time-condition.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -basicaa -polly-ast -analyze < %s | FileCheck %s
+
+; for (i = 0; i < 1024; i++)
+;   A[i] = B[i];
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+define void @run-time-condition(i16* noalias %A, i16* noalias %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.body, %entry
+  %indvar = phi i64 [ 0, %entry ], [ %inc, %for.body ]
+  %cmp = icmp slt i64 %indvar, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i16, i16* %B, i64 0
+  %load = load i16, i16* %arrayidx
+  %add10 = add nsw i16 %load, 1
+  %arrayidx13 = getelementptr inbounds i16, i16* %A, i64 %indvar
+  store i16 %add10, i16* %arrayidx13, align 2
+  %inc = add nsw i64 %indvar, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+; CHECK: if (1)
+; CHECK:     for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK:       Stmt_for_body(c0);
+; CHECK: else
+; CHECK:     {  /* original code */ }
+
diff --git a/final/test/Isl/Ast/runtime_context_with_error_blocks.ll b/final/test/Isl/Ast/runtime_context_with_error_blocks.ll
new file mode 100644
index 0000000..97f5d04
--- /dev/null
+++ b/final/test/Isl/Ast/runtime_context_with_error_blocks.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -polly-ast -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+; Verify we do not simplify the runtime check to "true" due to the domain
+; constraints as the test contains an error block that influenced the domains
+; already.
+;
+; CHECK: if (p_0_loaded_from_this <= -1 || p_0_loaded_from_this >= 1)
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%"class.std::ctype" = type <{ %"class.std::locale::facet.base", [4 x i8], %struct.__locale_struct*, i8, [7 x i8], i32*, i32*, i16*, i8, [256 x i8], [256 x i8], i8, [6 x i8] }>
+%"class.std::locale::facet.base" = type <{ i32 (...)**, i32 }>
+%struct.__locale_struct = type { [13 x %struct.__locale_data*], i16*, i32*, i32*, [13 x i8*] }
+%struct.__locale_data = type opaque
+
+$_ZNKSt5ctypeIcE5widenEc = comdat any
+
+; Function Attrs: uwtable
+define weak_odr signext i8 @_ZNKSt5ctypeIcE5widenEc(%"class.std::ctype"* %this, i8 signext %__c) #0 comdat align 2 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %_M_widen_ok = getelementptr inbounds %"class.std::ctype", %"class.std::ctype"* %this, i64 0, i32 8
+  %0 = load i8, i8* %_M_widen_ok, align 8, !tbaa !1
+  %tobool = icmp eq i8 %0, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %entry.split
+  %idxprom = zext i8 %__c to i64
+  %arrayidx = getelementptr inbounds %"class.std::ctype", %"class.std::ctype"* %this, i64 0, i32 9, i64 %idxprom
+  %1 = load i8, i8* %arrayidx, align 1, !tbaa !7
+  br label %return
+
+if.end:                                           ; preds = %entry.split
+  tail call void @_ZNKSt5ctypeIcE13_M_widen_initEv(%"class.std::ctype"* %this)
+  %2 = bitcast %"class.std::ctype"* %this to i8 (%"class.std::ctype"*, i8)***
+  %vtable = load i8 (%"class.std::ctype"*, i8)**, i8 (%"class.std::ctype"*, i8)*** %2, align 8, !tbaa !8
+  %vfn = getelementptr inbounds i8 (%"class.std::ctype"*, i8)*, i8 (%"class.std::ctype"*, i8)** %vtable, i64 6
+  %3 = load i8 (%"class.std::ctype"*, i8)*, i8 (%"class.std::ctype"*, i8)** %vfn, align 8
+  %call = tail call signext i8 %3(%"class.std::ctype"* %this, i8 signext %__c)
+  br label %return
+
+return:                                           ; preds = %if.end, %if.then
+  %retval.0 = phi i8 [ %1, %if.then ], [ %call, %if.end ]
+  ret i8 %retval.0
+}
+
+declare void @_ZNKSt5ctypeIcE13_M_widen_initEv(%"class.std::ctype"*) #1
+
+attributes #0 = { uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (http://llvm.org/git/clang.git 97e5436f69f1bfa7f3e7fd2ecd80cdee0ae95bef)"}
+!1 = !{!2, !4, i64 56}
+!2 = !{!"_ZTSSt5ctypeIcE", !3, i64 16, !6, i64 24, !3, i64 32, !3, i64 40, !3, i64 48, !4, i64 56, !4, i64 57, !4, i64 313, !4, i64 569}
+!3 = !{!"any pointer", !4, i64 0}
+!4 = !{!"omnipotent char", !5, i64 0}
+!5 = !{!"Simple C/C++ TBAA"}
+!6 = !{!"bool", !4, i64 0}
+!7 = !{!4, !4, i64 0}
+!8 = !{!9, !9, i64 0}
+!9 = !{!"vtable pointer", !5, i64 0}
diff --git a/final/test/Isl/Ast/simple-run-time-condition.ll b/final/test/Isl/Ast/simple-run-time-condition.ll
new file mode 100644
index 0000000..aba5d9e
--- /dev/null
+++ b/final/test/Isl/Ast/simple-run-time-condition.ll
@@ -0,0 +1,96 @@
+; RUN: opt %loadPolly -polly-ast -analyze -polly-precise-inbounds < %s \
+; RUN:                -polly-precise-fold-accesses \
+; RUN:   | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; void foo(long n, long m, int o, double A[n][m], long p, long q) {
+;
+; if (o >= 0)
+;   for (long i = 0; i < n; i++)
+;     for (long j = 0; j < m; j++)
+;         A[i+p][j+q] = 1.0;
+; else
+;   for (long i = 0; i < n; i++)
+;     for (long j = 0; j < m; j++)
+;         A[i+p][j+q-100] = 1.0;
+;
+
+; This test case is meant to verify that the run-time condition generated
+; for the delinearization is simplified such that conditions that would not
+; cause any code to be executed are not generated.
+
+; CHECK: if (((o >= 1 && q <= 0 && m + q >= 0) || (o <= 0 && m + q >= 100 && q <= 100)) && 0 == ((m >= 1 && n + p >= 9223372036854775809) || (o <= 0 && n >= 1 && m + q >= 9223372036854775909) || (o <= 0 && m >= 1 && n >= 1 && q <= -9223372036854775709)))
+
+; CHECK:     if (o <= 0) {
+; CHECK:       for (int c0 = 0; c0 < n; c0 += 1)
+; CHECK:         for (int c1 = 0; c1 < m; c1 += 1)
+; CHECK:           Stmt_for_j_1(c0, c1);
+; CHECK:     } else
+; CHECK:       for (int c0 = 0; c0 < n; c0 += 1)
+; CHECK:         for (int c1 = 0; c1 < m; c1 += 1)
+; CHECK:           Stmt_for_j(c0, c1);
+
+; CHECK: else
+; CHECK:     {  /* original code */ }
+
+define void @foo(i64 %n, i64 %m, i64 %o, double* %A, i64 %p, i64 %q) {
+entry:
+  br label %cond
+
+cond:
+  %cmp = icmp sgt i64 %o, 0
+  br i1 %cmp, label %for.i, label %for.i.1
+
+for.i:
+  %i = phi i64 [ 0, %cond ], [ %i.inc, %for.i.inc ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j.inc ]
+  %offset0 = add nsw i64 %i, %p
+  %subscript0 = mul i64 %offset0, %m
+  %offset1 = add nsw i64 %j, %q
+  %subscript1 = add i64 %offset1, %subscript0
+  %idx = getelementptr inbounds double, double* %A, i64 %subscript1
+  store double 1.0, double* %idx
+  br label %for.j.inc
+
+for.j.inc:
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, %m
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %i.exitcond = icmp eq i64 %i.inc, %n
+  br i1 %i.exitcond, label %end, label %for.i
+
+for.i.1:
+  %i.1 = phi i64 [ 0, %cond ], [ %i.inc.1, %for.i.inc.1 ]
+  br label %for.j.1
+
+for.j.1:
+  %j.1 = phi i64 [ 0, %for.i.1 ], [ %j.inc.1, %for.j.inc.1 ]
+  %offset0.1 = add nsw i64 %i.1, %p
+  %subscript0.1 = mul i64 %offset0.1, %m
+  %offset1.1 = add nsw i64 %j.1, %q
+  %subscript1.1 = add i64 %offset1.1, %subscript0.1
+  %subscript1.2 = sub i64 %subscript1.1, 100
+  %idx.1 = getelementptr inbounds double, double* %A, i64 %subscript1.2
+  store double 1.0, double* %idx.1
+  br label %for.j.inc.1
+
+for.j.inc.1:
+  %j.inc.1 = add nsw i64 %j.1, 1
+  %j.exitcond.1 = icmp eq i64 %j.inc.1, %m
+  br i1 %j.exitcond.1, label %for.i.inc.1, label %for.j.1
+
+for.i.inc.1:
+  %i.inc.1 = add nsw i64 %i.1, 1
+  %i.exitcond.1 = icmp eq i64 %i.inc.1, %n
+  br i1 %i.exitcond.1, label %end, label %for.i.1
+
+end:
+  ret void
+}
diff --git a/final/test/Isl/Ast/single_loop_strip_mine.ll b/final/test/Isl/Ast/single_loop_strip_mine.ll
new file mode 100644
index 0000000..e4e7574
--- /dev/null
+++ b/final/test/Isl/Ast/single_loop_strip_mine.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -basicaa -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -polly-import-jscop \
+; RUN:   -polly-ast-print-accesses \
+; RUN:   -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s \
+; RUN:   -check-prefix=CHECK-VECTOR
+
+; for (i = 0; i < 1024; i++)
+;   A[i] = B[i];
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+define void @single_loop_strip_mine(i16* noalias %A, i16* noalias %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.body, %entry
+  %indvar = phi i64 [ 0, %entry ], [ %inc, %for.body ]
+  %cmp = icmp slt i64 %indvar, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i16, i16* %B, i64 0
+  %load = load i16, i16* %arrayidx
+  %add10 = add nsw i16 %load, 1
+  %arrayidx13 = getelementptr inbounds i16, i16* %A, i64 %indvar
+  store i16 %add10, i16* %arrayidx13, align 2
+  %inc = add nsw i64 %indvar, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK:     Stmt_for_body(c0);
+
+; CHECK-VECTOR: #pragma known-parallel
+; CHECK-VECTOR: for (int c0 = 0; c0 <= 1023; c0 += 4)
+; CHECK-VECTOR:     #pragma simd
+; CHECK-VECTOR:     for (int c1 = c0; c1 <= c0 + 3; c1 += 1)
+; CHECK-VECTOR:       Stmt_for_body(
+; CHECK-VECTOR:         /* read  */ &MemRef_B[0]
+; CHECK-VECTOR:         /* write */  MemRef_A[c1]
+; CHECK-VECTOR:       );
+
diff --git a/final/test/Isl/Ast/single_loop_strip_mine___%for.cond---%for.end.jscop b/final/test/Isl/Ast/single_loop_strip_mine___%for.cond---%for.end.jscop
new file mode 100644
index 0000000..7dcf837
--- /dev/null
+++ b/final/test/Isl/Ast/single_loop_strip_mine___%for.cond---%for.end.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_B[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body[i0] : i0 >= 0 and i0 <= 1023 }",
+         "name" : "Stmt_for_body",
+         "schedule" : "{ Stmt_for_body[i0] -> [o0, i0] : exists (e0 = [(o0)/4]: 4e0 = o0 and o0 <= i0 and o0 >= -3 + i0 and i0 >= 0 and i0 <= 1023) }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/20100617.ll b/final/test/Isl/CodeGen/20100617.ll
new file mode 100644
index 0000000..71a889f
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100617.ll
@@ -0,0 +1,18 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @init_array() nounwind {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond1, %entry
+  %indvar1 = phi i64 [ %indvar.next2, %for.cond1 ], [ 0, %entry ] ; <i64> [#uses=1]
+  br i1 false, label %for.cond1, label %for.end32
+
+for.cond1:                                        ; preds = %for.cond
+  %indvar.next2 = add i64 %indvar1, 1             ; <i64> [#uses=1]
+  br label %for.cond
+
+for.end32:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20100622.ll b/final/test/Isl/CodeGen/20100622.ll
new file mode 100644
index 0000000..ef997cf
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100622.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+; RUN: opt %loadPolly -polly-detect -analyze  < %s | not FileCheck %s
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
+
+define void @MAIN__() nounwind {
+entry:
+  br i1 undef, label %bb6.preheader, label %bb3
+
+bb3:                                              ; preds = %bb3, %entry
+  br i1 undef, label %bb6.preheader, label %bb3
+
+bb6.preheader:                                    ; preds = %bb3, %entry
+  br i1 undef, label %bb11, label %bb9.preheader
+
+bb9.preheader:                                    ; preds = %bb6.preheader
+  br label %bb11
+
+bb11:                                             ; preds = %bb9.preheader, %bb6.preheader
+  br label %bb15
+
+bb15:                                             ; preds = %bb15, %bb11
+  br i1 undef, label %bb26.loopexit, label %bb15
+
+bb26.loopexit:                                    ; preds = %bb15
+  br i1 undef, label %bb31, label %bb29.preheader
+
+bb29.preheader:                                   ; preds = %bb26.loopexit
+  br label %bb29
+
+bb29:                                             ; preds = %bb29, %bb29.preheader
+  %indvar47 = phi i32 [ 0, %bb29.preheader ], [ %indvar.next48, %bb29 ] ; <i32> [#uses=1]
+  %indvar.next48 = add i32 %indvar47, 1           ; <i32> [#uses=2]
+  %exitcond50 = icmp eq i32 %indvar.next48, undef ; <i1> [#uses=1]
+  br i1 %exitcond50, label %bb31, label %bb29
+
+bb31:                                             ; preds = %bb29, %bb26.loopexit
+  %errtot.3 = phi float [ undef, %bb26.loopexit ], [ undef, %bb29 ] ; <float> [#uses=0]
+  ret void
+}
+
+; CHECK: SCOP:
diff --git a/final/test/Isl/CodeGen/20100707.ll b/final/test/Isl/CodeGen/20100707.ll
new file mode 100644
index 0000000..3381980
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100707.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @clause_SetSplitField(i32 %Length) nounwind inlinehint {
+entry:
+  br i1 undef, label %bb1, label %bb6
+
+bb1:                                              ; preds = %entry
+  unreachable
+
+bb6:                                              ; preds = %entry
+  %tmp = zext i32 %Length to i64                  ; <i64> [#uses=1]
+  br label %bb8
+
+bb7:                                              ; preds = %bb8
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %bb8
+
+bb8:                                              ; preds = %bb7, %bb6
+  %indvar = phi i64 [ %indvar.next, %bb7 ], [ 0, %bb6 ] ; <i64> [#uses=2]
+  %exitcond = icmp ne i64 %indvar, %tmp           ; <i1> [#uses=1]
+  br i1 %exitcond, label %bb7, label %return
+
+return:                                           ; preds = %bb8
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20100707_2.ll b/final/test/Isl/CodeGen/20100707_2.ll
new file mode 100644
index 0000000..adbfd2b
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100707_2.ll
@@ -0,0 +1,114 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@win193 = external global [4 x [36 x double]], align 32 ; <[4 x [36 x double]]*> [#uses=3]
+@sb_sample = external global [2 x [2 x [18 x [32 x double]]]], align 32 ; <[2 x [2 x [18 x [32 x double]]]]*> [#uses=2]
+
+define void @mdct_sub48() nounwind {
+entry:
+  br i1 undef, label %bb, label %bb54
+
+bb:                                               ; preds = %entry
+  br label %bb54
+
+bb3:                                              ; preds = %bb50
+  br label %bb8
+
+bb4:                                              ; preds = %bb8
+  br label %bb8
+
+bb8:                                              ; preds = %bb4, %bb3
+  br i1 undef, label %bb4, label %bb9
+
+bb9:                                              ; preds = %bb8
+  br label %bb48
+
+bb25:                                             ; preds = %bb48
+  br i1 false, label %bb26, label %bb27
+
+bb26:                                             ; preds = %bb48, %bb25
+  br label %bb37
+
+bb27:                                             ; preds = %bb25
+  br i1 undef, label %bb32, label %bb35
+
+bb32:                                             ; preds = %bb27
+  br label %bb37
+
+bb34:                                             ; preds = %bb35
+  %0 = getelementptr inbounds [36 x double], [36 x double]* undef, i64 0, i64 0 ; <double*> [#uses=0]
+  %1 = getelementptr inbounds [18 x [32 x double]], [18 x [32 x double]]* undef, i64 0, i64 0 ; <[32 x double]*> [#uses=1]
+  %2 = getelementptr inbounds [32 x double], [32 x double]* %1, i64 0, i64 0 ; <double*> [#uses=0]
+  %3 = getelementptr inbounds [36 x double], [36 x double]* undef, i64 0, i64 0 ; <double*> [#uses=0]
+  %4 = sub nsw i32 17, %k.4                       ; <i32> [#uses=1]
+  %5 = getelementptr inbounds [2 x [2 x [18 x [32 x double]]]], [2 x [2 x [18 x [32 x double]]]]* @sb_sample, i64 0, i64 0 ; <[2 x [18 x [32 x double]]]*> [#uses=1]
+  %6 = getelementptr inbounds [2 x [18 x [32 x double]]], [2 x [18 x [32 x double]]]* %5, i64 0, i64 0 ; <[18 x [32 x double]]*> [#uses=1]
+  %7 = sext i32 %4 to i64                         ; <i64> [#uses=1]
+  %8 = getelementptr inbounds [18 x [32 x double]], [18 x [32 x double]]* %6, i64 0, i64 %7 ; <[32 x double]*> [#uses=1]
+  %9 = getelementptr inbounds [32 x double], [32 x double]* %8, i64 0, i64 0 ; <double*> [#uses=1]
+  %10 = load double, double* %9, align 8                  ; <double> [#uses=0]
+  %11 = fsub double 0.000000e+00, undef           ; <double> [#uses=1]
+  %12 = getelementptr inbounds double, double* getelementptr inbounds ([4 x [36 x double]], [4 x [36 x double]]* @win193, i64 0, i64 2, i64 4), i64 0 ; <double*> [#uses=1]
+  store double %11, double* %12, align 8
+  %13 = add nsw i32 %k.4, 9                       ; <i32> [#uses=1]
+  %14 = add nsw i32 %k.4, 18                      ; <i32> [#uses=1]
+  %15 = getelementptr inbounds [4 x [36 x double]], [4 x [36 x double]]* @win193, i64 0, i64 0 ; <[36 x double]*> [#uses=1]
+  %16 = sext i32 %14 to i64                       ; <i64> [#uses=1]
+  %17 = getelementptr inbounds [36 x double], [36 x double]* %15, i64 0, i64 %16 ; <double*> [#uses=1]
+  %18 = load double, double* %17, align 8                 ; <double> [#uses=0]
+  %19 = sext i32 %k.4 to i64                      ; <i64> [#uses=1]
+  %20 = getelementptr inbounds [18 x [32 x double]], [18 x [32 x double]]* undef, i64 0, i64 %19 ; <[32 x double]*> [#uses=1]
+  %21 = sext i32 %band.2 to i64                   ; <i64> [#uses=1]
+  %22 = getelementptr inbounds [32 x double], [32 x double]* %20, i64 0, i64 %21 ; <double*> [#uses=1]
+  %23 = load double, double* %22, align 8                 ; <double> [#uses=0]
+  %24 = sext i32 %39 to i64                       ; <i64> [#uses=1]
+  %25 = getelementptr inbounds [4 x [36 x double]], [4 x [36 x double]]* @win193, i64 0, i64 %24 ; <[36 x double]*> [#uses=1]
+  %26 = getelementptr inbounds [36 x double], [36 x double]* %25, i64 0, i64 0 ; <double*> [#uses=1]
+  %27 = load double, double* %26, align 8                 ; <double> [#uses=0]
+  %28 = sub nsw i32 17, %k.4                      ; <i32> [#uses=1]
+  %29 = getelementptr inbounds [2 x [2 x [18 x [32 x double]]]], [2 x [2 x [18 x [32 x double]]]]* @sb_sample, i64 0, i64 0 ; <[2 x [18 x [32 x double]]]*> [#uses=1]
+  %30 = getelementptr inbounds [2 x [18 x [32 x double]]], [2 x [18 x [32 x double]]]* %29, i64 0, i64 0 ; <[18 x [32 x double]]*> [#uses=1]
+  %31 = sext i32 %28 to i64                       ; <i64> [#uses=1]
+  %32 = getelementptr inbounds [18 x [32 x double]], [18 x [32 x double]]* %30, i64 0, i64 %31 ; <[32 x double]*> [#uses=1]
+  %33 = getelementptr inbounds [32 x double], [32 x double]* %32, i64 0, i64 0 ; <double*> [#uses=1]
+  %34 = load double, double* %33, align 8                 ; <double> [#uses=0]
+  %35 = sext i32 %13 to i64                       ; <i64> [#uses=1]
+  %36 = getelementptr inbounds double, double* getelementptr inbounds ([4 x [36 x double]], [4 x [36 x double]]* @win193, i64 0, i64 2, i64 4), i64 %35 ; <double*> [#uses=1]
+  store double 0.000000e+00, double* %36, align 8
+  %37 = sub nsw i32 %k.4, 1                       ; <i32> [#uses=1]
+  br label %bb35
+
+bb35:                                             ; preds = %bb34, %bb27
+  %k.4 = phi i32 [ %37, %bb34 ], [ 8, %bb27 ]     ; <i32> [#uses=6]
+  br i1 undef, label %bb34, label %bb36
+
+bb36:                                             ; preds = %bb35
+  unreachable
+
+bb37:                                             ; preds = %bb32, %bb26
+  %38 = add nsw i32 %band.2, 1                    ; <i32> [#uses=1]
+  br label %bb48
+
+bb48:                                             ; preds = %bb37, %bb9
+  %band.2 = phi i32 [ %38, %bb37 ], [ 0, %bb9 ]   ; <i32> [#uses=2]
+  %39 = load i32, i32* null, align 8                   ; <i32> [#uses=1]
+  br i1 undef, label %bb26, label %bb25
+
+bb50:                                             ; preds = %bb54
+  br i1 undef, label %bb3, label %bb51
+
+bb51:                                             ; preds = %bb50
+  br i1 undef, label %bb52, label %bb53
+
+bb52:                                             ; preds = %bb51
+  unreachable
+
+bb53:                                             ; preds = %bb51
+  br label %bb54
+
+bb54:                                             ; preds = %bb53, %bb, %entry
+  br i1 undef, label %bb50, label %return
+
+return:                                           ; preds = %bb54
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20100708.ll b/final/test/Isl/CodeGen/20100708.ll
new file mode 100644
index 0000000..50b8e38
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100708.ll
@@ -0,0 +1,17 @@
+; RUN: opt %loadPolly -polly-detect < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define fastcc void @execute() nounwind {
+entry:
+  br i1 undef, label %check_stack.exit456.thread, label %bb.i451.preheader
+
+bb.i451.preheader:                                ; preds = %bb116
+  br label %bb.i451
+
+bb.i451:                                          ; preds = %bb.i451, %bb.i451.preheader
+  br label %bb.i451
+
+check_stack.exit456.thread:                       ; preds = %bb116
+  unreachable
+
+}
diff --git a/final/test/Isl/CodeGen/20100708_2.ll b/final/test/Isl/CodeGen/20100708_2.ll
new file mode 100644
index 0000000..58ef5a4
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100708_2.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @init_array() nounwind {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb4, %bb
+  br i1 undef, label %bb2, label %bb5
+
+bb2:                                              ; preds = %bb3, %bb1
+  %indvar = phi i64 [ %indvar.next, %bb3 ], [ 0, %bb1 ] ; <i64> [#uses=1]
+  %tmp3 = trunc i64 undef to i32                  ; <i32> [#uses=1]
+  br i1 false, label %bb3, label %bb4
+
+bb3:                                              ; preds = %bb2
+  %tmp = srem i32 %tmp3, 1024                     ; <i32> [#uses=0]
+  store double undef, double* undef
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %bb2
+
+bb4:                                              ; preds = %bb2
+  br label %bb1
+
+bb5:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20100713.ll b/final/test/Isl/CodeGen/20100713.ll
new file mode 100644
index 0000000..c322db1
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100713.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @fft_float(i32 %NumSamples) nounwind {
+  br label %bb18
+
+bb18:                                             ; preds = %bb17
+  br i1 false, label %bb19, label %bb22
+
+bb19:                                             ; preds = %bb18
+  %a = uitofp i32 %NumSamples to double           ; <double> [#uses=1]
+  br label %bb21
+
+bb20:                                             ; preds = %bb21
+  %1 = load float, float* undef, align 4                 ; <float> [#uses=0]
+  %2 = fpext float undef to double                ; <double> [#uses=1]
+  %3 = fdiv double %2, %a ; <double> [#uses=0]
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %bb21
+
+bb21:                                             ; preds = %bb20, %bb19
+  %indvar = phi i64 [ %indvar.next, %bb20 ], [ 0, %bb19 ] ; <i64> [#uses=1]
+  br i1 false, label %bb20, label %bb22.loopexit
+
+bb22.loopexit:                                    ; preds = %bb21
+  br label %bb22
+
+bb22:                                             ; preds = %bb22.loopexit, %bb18
+  br label %return
+
+return:                                           ; preds = %bb22
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20100713_2.ll b/final/test/Isl/CodeGen/20100713_2.ll
new file mode 100644
index 0000000..62cbc67
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100713_2.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define hidden void @luaD_callhook() nounwind {
+entry:
+  br i1 undef, label %bb, label %return
+
+bb:                                               ; preds = %entry
+  br i1 undef, label %bb1, label %return
+
+bb1:                                              ; preds = %bb
+  %0 = sub nsw i64 undef, undef                   ; <i64> [#uses=1]
+  br i1 false, label %bb2, label %bb3
+
+bb2:                                              ; preds = %bb1
+  br label %bb4
+
+bb3:                                              ; preds = %bb1
+  br label %bb4
+
+bb4:                                              ; preds = %bb3, %bb2
+  br i1 undef, label %bb5, label %bb6
+
+bb5:                                              ; preds = %bb4
+  unreachable
+
+bb6:                                              ; preds = %bb4
+  %1 = getelementptr inbounds i8, i8* undef, i64 %0   ; <i8*> [#uses=0]
+  ret void
+
+return:                                           ; preds = %bb, %entry
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20100717.ll b/final/test/Isl/CodeGen/20100717.ll
new file mode 100644
index 0000000..36ca35e
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100717.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly  -polly-codegen -disable-output < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @matrixTranspose(double** %A) nounwind {
+entry:
+  br label %bb4
+
+bb:                                               ; preds = %bb4
+  %0 = add nsw i32 %i.0, 1                        ; <i32> [#uses=1]
+  br label %bb2
+
+bb1:                                              ; preds = %bb2
+  %1 = getelementptr inbounds double*, double** %A, i64 0  ; <double**> [#uses=0]
+  %2 = getelementptr inbounds double*, double** %A, i64 0  ; <double**> [#uses=0]
+  %3 = getelementptr inbounds double*, double** %A, i64 0  ; <double**> [#uses=0]
+  %4 = sext i32 %j.0 to i64                       ; <i64> [#uses=1]
+  %5 = getelementptr inbounds double*, double** %A, i64 %4 ; <double**> [#uses=1]
+  %6 = load double*, double** %5, align 8                  ; <double*> [#uses=0]
+  %7 = add nsw i32 %j.0, 1                        ; <i32> [#uses=1]
+  br label %bb2
+
+bb2:                                              ; preds = %bb1, %bb
+  %j.0 = phi i32 [ %0, %bb ], [ %7, %bb1 ]        ; <i32> [#uses=3]
+  %8 = icmp sle i32 %j.0, 50                      ; <i1> [#uses=1]
+  br i1 %8, label %bb1, label %bb3
+
+bb3:                                              ; preds = %bb2
+  %9 = add nsw i32 %i.0, 1                        ; <i32> [#uses=1]
+  br label %bb4
+
+bb4:                                              ; preds = %bb3, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %9, %bb3 ]      ; <i32> [#uses=3]
+  %10 = icmp sle i32 %i.0, 50                     ; <i1> [#uses=1]
+  br i1 %10, label %bb, label %return
+
+return:                                           ; preds = %bb4
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20100718-DomInfo-2.ll b/final/test/Isl/CodeGen/20100718-DomInfo-2.ll
new file mode 100644
index 0000000..512b4c5
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100718-DomInfo-2.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -polly-codegen -verify-dom-info -disable-output < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @getNonAffNeighbour() nounwind {
+entry:
+  br i1 undef, label %bb, label %bb6
+
+bb:                                               ; preds = %entry
+  br i1 false, label %bb1, label %bb2
+
+bb1:                                              ; preds = %bb
+  br label %bb16
+
+bb2:                                              ; preds = %bb
+  br i1 false, label %bb3, label %bb4
+
+bb3:                                              ; preds = %bb2
+  br label %bb16
+
+bb4:                                              ; preds = %bb2
+  br label %bb16
+
+bb6:                                              ; preds = %entry
+  br i1 false, label %bb7, label %bb9
+
+bb7:                                              ; preds = %bb6
+  br label %bb16
+
+bb9:                                              ; preds = %bb6
+  br label %bb16
+
+bb16:                                             ; preds = %bb9, %bb7, %bb4, %bb3, %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20100718-DomInfo.ll b/final/test/Isl/CodeGen/20100718-DomInfo.ll
new file mode 100644
index 0000000..e123343
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100718-DomInfo.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -polly-codegen -verify-dom-info -disable-output < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @intrapred_luma_16x16(i32 %predmode) nounwind {
+entry:
+  switch i32 %predmode, label %bb81 [
+    i32 0, label %bb25
+    i32 1, label %bb26
+  ]
+
+bb23:                                             ; preds = %bb25
+  %indvar.next95 = add i64 %indvar94, 1           ; <i64> [#uses=1]
+  br label %bb25
+
+bb25:                                             ; preds = %bb23, %entry
+  %indvar94 = phi i64 [ %indvar.next95, %bb23 ], [ 0, %entry ] ; <i64> [#uses=1]
+  br i1 false, label %bb23, label %return
+
+bb26:                                             ; preds = %entry
+  ret void
+
+bb81:                                             ; preds = %entry
+  ret void
+
+return:                                           ; preds = %bb25
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20100720-MultipleConditions.ll b/final/test/Isl/CodeGen/20100720-MultipleConditions.ll
new file mode 100644
index 0000000..425bcf1
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100720-MultipleConditions.ll
@@ -0,0 +1,95 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s
+
+;int bar1();
+;int bar2();
+;int bar3();
+;int k;
+;#define N 100
+;int A[N];
+;
+;int main() {
+;  int i, j, z;
+;
+;  __sync_synchronize();
+;  for (i = 0; i < N; i++) {
+;    if (i < 50)
+;      A[i] = 8;
+;    if (i < 4)
+;      A[i] = 9;
+;    if (i < 3)
+;      A[i] = 10;
+;  }
+;  __sync_synchronize();
+;
+;  return A[z];
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [100 x i32] zeroinitializer, align 16 ; <[100 x i32]*> [#uses=2]
+@k = common global i32 0, align 4                 ; <i32*> [#uses=0]
+
+define i32 @main() nounwind {
+; <label>:0
+  fence seq_cst
+  br label %1
+
+; <label>:1                                       ; preds = %12, %0
+  %indvar = phi i64 [ %indvar.next, %12 ], [ 0, %0 ] ; <i64> [#uses=4]
+  %scevgep = getelementptr [100 x i32], [100 x i32]* @A, i64 0, i64 %indvar ; <i32*> [#uses=3]
+  %i.0 = trunc i64 %indvar to i32                 ; <i32> [#uses=3]
+  %exitcond = icmp ne i64 %indvar, 100            ; <i1> [#uses=1]
+  br i1 %exitcond, label %2, label %13
+
+; <label>:2                                       ; preds = %1
+  %3 = icmp slt i32 %i.0, 50                      ; <i1> [#uses=1]
+  br i1 %3, label %4, label %5
+
+; <label>:4                                       ; preds = %2
+  store i32 8, i32* %scevgep
+  br label %5
+
+; <label>:5                                       ; preds = %4, %2
+  %6 = icmp slt i32 %i.0, 4                       ; <i1> [#uses=1]
+  br i1 %6, label %7, label %8
+
+; <label>:7                                       ; preds = %5
+  store i32 9, i32* %scevgep
+  br label %8
+
+; <label>:8                                       ; preds = %7, %5
+  %9 = icmp slt i32 %i.0, 3                       ; <i1> [#uses=1]
+  br i1 %9, label %10, label %11
+
+; <label>:10                                      ; preds = %8
+  store i32 10, i32* %scevgep
+  br label %11
+
+; <label>:11                                      ; preds = %10, %8
+  br label %12
+
+; <label>:12                                      ; preds = %11
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %1
+
+; <label>:13                                      ; preds = %1
+  fence seq_cst
+  %14 = sext i32 undef to i64                     ; <i64> [#uses=1]
+  %15 = getelementptr inbounds i32, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0), i64 %14 ; <i32*> [#uses=1]
+  %16 = load i32, i32* %15                             ; <i32> [#uses=1]
+  ret i32 %16
+}
+
+; CHECK: for (c2=0;c2<=2;c2++) {
+; CHECK:     S0(c2);
+; CHECK:       S1(c2);
+; CHECK:         S2(c2);
+; CHECK: }
+; CHECK: S0(3);
+; CHECK: S1(3);
+; CHECK: for (c2=4;c2<=49;c2++) {
+; CHECK:     S0(c2);
+; CHECK: }
+; CHECK: S0: Stmt_4
+; CHECK: S1: Stmt_7
+; CHECK: S2: Stmt_10
diff --git a/final/test/Isl/CodeGen/20100809-IndependentBlock.ll b/final/test/Isl/CodeGen/20100809-IndependentBlock.ll
new file mode 100644
index 0000000..4d143e1
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100809-IndependentBlock.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -polly-codegen -disable-output < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+define void @cfft2([2 x float]* %x) nounwind {
+entry:
+  %d.1.reg2mem = alloca [2 x float]*              ; <[2 x float]**> [#uses=3]
+  br i1 undef, label %bb2, label %bb34
+
+bb2:                                              ; preds = %bb34, %entry
+  ret void
+
+bb20:                                             ; preds = %bb34
+  store [2 x float]* undef, [2 x float]** %d.1.reg2mem
+  br i1 false, label %bb21, label %bb23
+
+bb21:                                             ; preds = %bb20
+  %0 = getelementptr inbounds [2 x float], [2 x float]* %x, i64 undef ; <[2 x float]*> [#uses=1]
+  store [2 x float]* %0, [2 x float]** %d.1.reg2mem
+  br label %bb23
+
+bb23:                                             ; preds = %bb21, %bb20
+  %d.1.reload = load [2 x float]*, [2 x float]** %d.1.reg2mem   ; <[2 x float]*> [#uses=1]
+  br i1 undef, label %bb29, label %bb34
+
+bb29:                                             ; preds = %bb23
+  %1 = getelementptr inbounds [2 x float], [2 x float]* %d.1.reload, i64 undef ; <[2 x float]*> [#uses=0]
+  br label %bb34
+
+bb34:                                             ; preds = %bb29, %bb23, %entry
+  br i1 undef, label %bb20, label %bb2
+}
diff --git a/final/test/Isl/CodeGen/20100811-ScalarDependencyBetweenBrAndCnd.ll b/final/test/Isl/CodeGen/20100811-ScalarDependencyBetweenBrAndCnd.ll
new file mode 100644
index 0000000..261a205
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100811-ScalarDependencyBetweenBrAndCnd.ll
@@ -0,0 +1,29 @@
+; RUN: opt %loadPolly -polly-codegen -disable-output < %s
+target datalayout =
+"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @main() nounwind {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvar1 = phi i64 [ %indvar.next2, %for.inc ], [ 0, %entry ] ; <i64> [#uses=2]
+  %exitcond = icmp ne i64 %indvar1, 1024          ; <i1> [#uses=1]
+  br label %a
+
+a:                                                ; preds = %for.cond
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %a
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvar.next2 = add i64 %indvar1, 1             ; <i64> [#uses=1]
+  br label %for.cond
+
+for.end:                                          ; preds = %a
+  br label %for.cond5
+
+for.cond5:                                        ; preds = %for.inc07, %for.end
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20101030-Overflow.ll b/final/test/Isl/CodeGen/20101030-Overflow.ll
new file mode 100644
index 0000000..6ea83e3
--- /dev/null
+++ b/final/test/Isl/CodeGen/20101030-Overflow.ll
@@ -0,0 +1,21 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @compdecomp() nounwind {
+entry:
+  %max = alloca i64
+  %i = load i64, i64* undef
+  br label %bb37
+
+bb37:                                             ; preds = %bb36, %bb28
+  %tmp = icmp ugt i64 %i, 0
+  br i1 %tmp, label %bb38, label %bb39
+
+bb38:                                             ; preds = %bb37
+  store i64 %i, i64* %max
+  br label %bb39
+
+bb39:                                             ; preds = %bb38, %bb37
+  unreachable
+
+}
diff --git a/final/test/Isl/CodeGen/20101103-Overflow3.ll b/final/test/Isl/CodeGen/20101103-Overflow3.ll
new file mode 100644
index 0000000..e81d772
--- /dev/null
+++ b/final/test/Isl/CodeGen/20101103-Overflow3.ll
@@ -0,0 +1,23 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+define void @Reflection_coefficients(i16* %r) nounwind {
+bb20:
+  %indvar3.lcssa20.reload = load i64, i64* undef
+  %tmp = mul i64 %indvar3.lcssa20.reload, -1
+  %tmp5 = add i64 %tmp, 8
+  br label %bb22
+
+bb21:                                             ; preds = %bb22
+  %r_addr.1.moved.to.bb21 = getelementptr i16, i16* %r, i64 0
+  store i16 0, i16* %r_addr.1.moved.to.bb21, align 2
+  %indvar.next = add i64 %indvar, 1
+  br label %bb22
+
+bb22:                                             ; preds = %bb21, %bb20
+  %indvar = phi i64 [ %indvar.next, %bb21 ], [ 0, %bb20 ]
+  %exitcond = icmp ne i64 %indvar, %tmp5
+  br i1 %exitcond, label %bb21, label %return
+
+return:                                           ; preds = %bb22
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20101103-signmissmatch.ll b/final/test/Isl/CodeGen/20101103-signmissmatch.ll
new file mode 100644
index 0000000..4f32a6b
--- /dev/null
+++ b/final/test/Isl/CodeGen/20101103-signmissmatch.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @CleanNet() nounwind {
+entry:
+  %firstVia.0.reg2mem = alloca i64
+  br label %bb7
+
+bb7:                                              ; preds = %bb7, %entry
+  br i1 undef, label %bb7, label %bb8
+
+bb8:                                              ; preds = %bb7
+  %indvar5.lcssa.reload = load i64, i64* undef
+  %tmp17 = mul i64 %indvar5.lcssa.reload, -1
+  %tmp18 = add i64 0, %tmp17
+  br label %bb18
+
+bb13:                                             ; preds = %bb18
+  %0 = icmp ult i64 %i.1, 0
+  br i1 %0, label %bb14, label %bb17
+
+bb14:                                             ; preds = %bb13
+  store i64 %i.1, i64* %firstVia.0.reg2mem
+  br label %bb17
+
+bb17:                                             ; preds = %bb14, %bb13
+  %indvar.next16 = add i64 %indvar15, 1
+  br label %bb18
+
+bb18:                                             ; preds = %bb17, %bb8
+  %indvar15 = phi i64 [ %indvar.next16, %bb17 ], [ 0, %bb8 ]
+  %i.1 = add i64 %tmp18, %indvar15
+  br i1 undef, label %bb13, label %bb25
+
+bb25:                                             ; preds = %bb18
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20110226-Ignore-Dead-Code.ll b/final/test/Isl/CodeGen/20110226-Ignore-Dead-Code.ll
new file mode 100644
index 0000000..c792d8c
--- /dev/null
+++ b/final/test/Isl/CodeGen/20110226-Ignore-Dead-Code.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @main() nounwind {
+.split:
+  br label %0
+
+.loopexit.loopexit:                               ; preds = %.preheader.us
+  br label %.loopexit.simregexit
+
+.loopexit.simregexit:                             ; preds = %.loopexit.loopexit, %._crit_edge
+  br label %.loopexit
+
+.loopexit:                                        ; preds = %.loopexit.simregexit
+  %indvar.next16 = add i64 %indvar15, 1
+  %exitcond53 = icmp eq i64 %indvar.next16, 2048
+  br i1 %exitcond53, label %2, label %0
+
+; <label>:0                                       ; preds = %.loopexit, %.split
+  %indvar15 = phi i64 [ 0, %.split ], [ %indvar.next16, %.loopexit ]
+  br label %.simregentry
+
+.simregentry:                                     ; preds = %0
+  %indvar15.ph = phi i64 [ %indvar15, %0 ]
+  %tmp67 = add i64 %indvar15, 1
+  %i.06 = trunc i64 %tmp67 to i32
+  %tmp25 = add i64 undef, 1
+  %1 = icmp slt i32 %i.06, 2048
+  br i1 %1, label %.lr.ph.preheader, label %._crit_edge.simregexit
+
+.lr.ph.preheader:                                 ; preds = %.simregentry
+  br label %.lr.ph
+
+.lr.ph:                                           ; preds = %.lr.ph, %.lr.ph.preheader
+  %indvar33 = phi i64 [ %indvar.next34, %.lr.ph ], [ 0, %.lr.ph.preheader ]
+  %indvar.next34 = add i64 %indvar33, 1
+  %exitcond40 = icmp eq i64 %indvar.next34, 0
+  br i1 %exitcond40, label %._crit_edge.loopexit, label %.lr.ph
+
+._crit_edge.loopexit:                             ; preds = %.lr.ph
+  br label %._crit_edge.simregexit
+
+._crit_edge.simregexit:                           ; preds = %.simregentry, %._crit_edge.loopexit
+  br label %._crit_edge
+
+._crit_edge:                                      ; preds = %._crit_edge.simregexit
+  br i1 false, label %.loopexit.simregexit, label %.preheader.us.preheader
+
+.preheader.us.preheader:                          ; preds = %._crit_edge
+  br label %.preheader.us
+
+.preheader.us:                                    ; preds = %.preheader.us, %.preheader.us.preheader
+  %exitcond26.old = icmp eq i64 undef, %tmp25
+  br i1 false, label %.loopexit.loopexit, label %.preheader.us
+
+; <label>:2                                       ; preds = %.loopexit
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20110226-PHI-Node-removed.ll b/final/test/Isl/CodeGen/20110226-PHI-Node-removed.ll
new file mode 100644
index 0000000..3458d75
--- /dev/null
+++ b/final/test/Isl/CodeGen/20110226-PHI-Node-removed.ll
@@ -0,0 +1,29 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @main() nounwind {
+.split:
+  br label %0
+
+.loopexit:                                        ; preds = %.lr.ph, %0
+  %indvar.next16 = add i64 %indvar15, 1
+  %exitcond53 = icmp eq i64 %indvar.next16, 2048
+  br i1 %exitcond53, label %1, label %0
+
+; <label>:0                                       ; preds = %.loopexit, %.split
+  %indvar15 = phi i64 [ 0, %.split ], [ %indvar.next16, %.loopexit ]
+  %tmp59 = sub i64 2046, %indvar15
+  %tmp38 = and i64 %tmp59, 4294967295
+  %tmp39 = add i64 %tmp38, 1
+  br i1 false, label %.lr.ph, label %.loopexit
+
+.lr.ph:                                           ; preds = %.lr.ph, %0
+  %indvar33 = phi i64 [ %indvar.next34, %.lr.ph ], [ 0, %0 ]
+  %indvar.next34 = add i64 %indvar33, 1
+  %exitcond40 = icmp eq i64 %indvar.next34, %tmp39
+  br i1 %exitcond40, label %.loopexit, label %.lr.ph
+
+; <label>:1                                       ; preds = %.loopexit
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20120316-InvalidCast.ll b/final/test/Isl/CodeGen/20120316-InvalidCast.ll
new file mode 100644
index 0000000..165b910
--- /dev/null
+++ b/final/test/Isl/CodeGen/20120316-InvalidCast.ll
@@ -0,0 +1,21 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+
+; CHECK: polly.start
+
+target datalayout = "e-p:32:32:32-i64:64:64-i32:32:32-i16:16:16-i1:32:32-f64:64:64-f32:32:32-a0:0-n32"
+
+define void @fixup_gotos(i32* %A, i32* %data) nounwind {
+entry:
+  br label %if
+
+if:
+  %cond = icmp eq i32* %A, null
+  br i1 %cond, label %last, label %then
+
+then:
+  store i32 1, i32* %data, align 4
+  br label %last
+
+last:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20120403-RHS-type-mismatch.ll b/final/test/Isl/CodeGen/20120403-RHS-type-mismatch.ll
new file mode 100644
index 0000000..f612d44
--- /dev/null
+++ b/final/test/Isl/CodeGen/20120403-RHS-type-mismatch.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+
+; We just check that this compilation does not crash.
+
+target datalayout = "e-p:32:32:32-i64:64:64-i32:32:32-i16:16:16-i1:32:32-f64:64:64-f32:32:32-a0:0-n32"
+
+define void @init() nounwind {
+entry:
+  %hi.129.reg2mem = alloca i64
+  br label %for.body
+
+for.cond5.preheader:                              ; preds = %for.body
+  br label %for.body7
+
+for.body:                                         ; preds = %for.body, %entry
+  br i1 undef, label %for.body, label %for.cond5.preheader
+
+for.body7:                                        ; preds = %for.body7, %for.cond5.preheader
+  %i.128 = phi i64 [ 0, %for.cond5.preheader ], [ %inc07, %for.body7 ]
+  %inc07 = add nsw i64 %i.128, 1
+  store i64 undef, i64* %hi.129.reg2mem
+  br i1 false, label %for.body7, label %for.end18
+
+for.end18:                                        ; preds = %for.body7
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20130211-getNumberOfIterations.ll b/final/test/Isl/CodeGen/20130211-getNumberOfIterations.ll
new file mode 100644
index 0000000..fda164b
--- /dev/null
+++ b/final/test/Isl/CodeGen/20130211-getNumberOfIterations.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -polly-codegen -polly-vectorizer=polly < %s
+
+; This test case checks that the polly vectorizer does not crash when
+; calculating the number of iterations.
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+@b = external global [2048 x i64], align 16
+
+define void @foo(i64 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.body, %entry
+  %indvar = phi i64 [ 0, %entry ], [ %inc, %for.body ]
+  %cmp = icmp slt i64 %indvar, %n
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds [2048 x i64], [2048 x i64]* @b, i64 0, i64 %indvar
+  store i64 1, i64* %arrayidx
+  %inc = add nsw i64 %indvar, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
diff --git a/final/test/Isl/CodeGen/20130221.ll b/final/test/Isl/CodeGen/20130221.ll
new file mode 100644
index 0000000..1714048
--- /dev/null
+++ b/final/test/Isl/CodeGen/20130221.ll
@@ -0,0 +1,20 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+define void @list_sequence(i32* %A) {
+entry:
+  br label %for.body
+
+for.body:
+  %i = phi i32 [ 0, %entry ], [ %i.inc, %for.body ]
+  %i.inc = add nsw i32 %i, 1
+  %cmp5 = icmp slt i32 %i.inc, 2
+  br i1 %cmp5, label %for.body, label %for.next
+
+for.next:
+  store i32 %i.inc, i32* %A
+  br label %for.end
+
+for.end:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/20150328-SCEVExpanderIntroducesNewIV.ll b/final/test/Isl/CodeGen/20150328-SCEVExpanderIntroducesNewIV.ll
new file mode 100644
index 0000000..7460e30
--- /dev/null
+++ b/final/test/Isl/CodeGen/20150328-SCEVExpanderIntroducesNewIV.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+
+@A = common global [1536 x float] zeroinitializer
+
+; CHECK: polly
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo() {
+entry:
+  br label %while.header
+
+while.cond.loopexit3:
+  br label %while.header
+
+while.header:
+  br label %switchbb
+
+switchbb:
+  switch i32 undef, label %while.header [
+    i32 1, label %for.body121
+    i32 2, label %unreachableA
+    i32 3, label %unreachableB
+  ]
+
+unreachableA:
+  unreachable
+
+for.body121:
+  %indvar = phi i32 [ 0, %switchbb ], [ %indvar.next, %for.body121 ]
+  %ptr = getelementptr [1536 x float], [1536 x float]* @A, i64 0, i32 %indvar
+  store float undef, float* %ptr
+  %indvar.next = add nsw i32 %indvar, 1
+  br i1 false, label %for.body121, label %while.cond.loopexit3
+
+unreachableB:
+  unreachable
+}
diff --git a/final/test/Isl/CodeGen/LoopParallelMD/do_not_mutate_debug_info.ll b/final/test/Isl/CodeGen/LoopParallelMD/do_not_mutate_debug_info.ll
new file mode 100644
index 0000000..dc743b6
--- /dev/null
+++ b/final/test/Isl/CodeGen/LoopParallelMD/do_not_mutate_debug_info.ll
@@ -0,0 +1,69 @@
+; This test checks that we do not accidently mutate the debug info when
+; inserting loop parallel metadata.
+; RUN: opt %loadPolly < %s  -S -polly -polly-codegen -polly-ast-detect-parallel | FileCheck %s
+; CHECK-NOT: !7 = !{!7}
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@A = common global i32* null, align 8
+
+; Function Attrs: nounwind uwtable
+define void @foo() !dbg !4 {
+entry:
+  tail call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !9, metadata !19), !dbg !20
+  %0 = load i32*, i32** @A, align 8, !dbg !21, !tbaa !23
+  br label %for.body, !dbg !27
+
+for.body:                                         ; preds = %for.body, %entry
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds i32, i32* %0, i64 %indvars.iv, !dbg !21
+  %1 = load i32, i32* %arrayidx, align 4, !dbg !21, !tbaa !30
+  %add = add nsw i32 %1, 1, !dbg !21
+  store i32 %add, i32* %arrayidx, align 4, !dbg !21, !tbaa !30
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1, !dbg !27
+  %exitcond = icmp eq i64 %indvars.iv, 1, !dbg !27
+  br i1 %exitcond, label %for.end, label %for.body, !dbg !27
+
+for.end:                                          ; preds = %for.body
+  ret void, !dbg !32
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
+
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!15, !16}
+!llvm.ident = !{!17}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.6.0 ", isOptimized: true, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, globals: !12, imports: !2)
+!1 = !DIFile(filename: "t2.c", directory: "/local/mnt/workspace/build/tip-Release")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "foo", line: 3, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, scopeLine: 3, file: !1, scope: !5, type: !6, variables: !8)
+!5 = !DIFile(filename: "t2.c", directory: "/local/mnt/workspace/build/tip-Release")
+!6 = !DISubroutineType(types: !7)
+!7 = !{null}
+!8 = !{!9}
+!9 = !DILocalVariable(name: "i", line: 4, scope: !10, file: !5, type: !11)
+!10 = distinct !DILexicalBlock(line: 4, column: 3, file: !1, scope: !4)
+!11 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!12 = !{!13}
+!13 = !DIGlobalVariableExpression(var: !DIGlobalVariable(name: "A", line: 2, isLocal: false, isDefinition: true, scope: null, file: !5, type: !14), expr: !DIExpression())
+!14 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, baseType: !11)
+!15 = !{i32 2, !"Dwarf Version", i32 4}
+!16 = !{i32 2, !"Debug Info Version", i32 3}
+!17 = !{!"clang version 3.6.0 "}
+!18 = !{i32 0}
+!19 = !DIExpression()
+!20 = !DILocation(line: 4, column: 12, scope: !10)
+!21 = !DILocation(line: 5, column: 5, scope: !22)
+!22 = distinct !DILexicalBlock(line: 4, column: 3, file: !1, scope: !10)
+!23 = !{!24, !24, i64 0}
+!24 = !{!"any pointer", !25, i64 0}
+!25 = !{!"omnipotent char", !26, i64 0}
+!26 = !{!"Simple C/C++ TBAA"}
+!27 = !DILocation(line: 4, column: 3, scope: !28)
+!28 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !29)
+!29 = !DILexicalBlockFile(discriminator: 1, file: !1, scope: !22)
+!30 = !{!31, !31, i64 0}
+!31 = !{!"int", !25, i64 0}
+!32 = !DILocation(line: 6, column: 1, scope: !4)
diff --git a/final/test/Isl/CodeGen/LoopParallelMD/loop_nest_param_parallel.ll b/final/test/Isl/CodeGen/LoopParallelMD/loop_nest_param_parallel.ll
new file mode 100644
index 0000000..49798ba
--- /dev/null
+++ b/final/test/Isl/CodeGen/LoopParallelMD/loop_nest_param_parallel.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-codegen -polly-ast-detect-parallel -S < %s | FileCheck %s
+;
+; Check that we mark multiple parallel loops correctly including the memory instructions.
+;
+; CHECK-DAG:  %polly.loop_cond[[COuter:[0-9]*]] = icmp sle i64 %polly.indvar_next{{[0-9]*}}, 1023
+; CHECK-DAG:  br i1 %polly.loop_cond[[COuter]], label %polly.loop_header{{[0-9]*}}, label %polly.loop_exit{{[0-9]*}}, !llvm.loop ![[IDOuter:[0-9]*]]
+;
+; CHECK-DAG:  %polly.loop_cond[[CInner:[0-9]*]] = icmp sle i64 %polly.indvar_next{{[0-9]*}}, 511
+; CHECK-DAG:  br i1 %polly.loop_cond[[CInner]], label %polly.loop_header{{[0-9]*}}, label %polly.loop_exit{{[0-9]*}}, !llvm.loop ![[IDInner:[0-9]*]]
+;
+; CHECK-DAG: store i32 %{{[a-z_0-9]*}}, i32* %{{[a-z_0-9]*}}, {{[ ._!,a-zA-Z0-9]*}}, !llvm.mem.parallel_loop_access !4
+;
+; CHECK-DAG: ![[IDOuter]] = distinct !{![[IDOuter]]}
+; CHECK-DAG: ![[IDInner]] = distinct !{![[IDInner]]}
+; CHECK-DAG: !4 = !{![[IDOuter]], ![[IDInner]]}
+;
+;    void jd(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        for (int j = 0; j < 512; j++)
+;          A[i * 512 + j] = i + j;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc5, %entry
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc5 ], [ 0, %entry ]
+  %exitcond6 = icmp ne i64 %indvars.iv3, 1024
+  br i1 %exitcond6, label %for.body, label %for.end7
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %for.body ]
+  %exitcond = icmp ne i64 %indvars.iv, 512
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %tmp = add nsw i64 %indvars.iv3, %indvars.iv
+  %tmp7 = shl nsw i64 %indvars.iv3, 9
+  %tmp8 = add nsw i64 %tmp7, %indvars.iv
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %tmp8
+  %tmp9 = trunc i64 %tmp to i32
+  store i32 %tmp9, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc5
+
+for.inc5:                                         ; preds = %for.end
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  br label %for.cond
+
+for.end7:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/LoopParallelMD/single_loop_param_parallel.ll b/final/test/Isl/CodeGen/LoopParallelMD/single_loop_param_parallel.ll
new file mode 100644
index 0000000..7555d84
--- /dev/null
+++ b/final/test/Isl/CodeGen/LoopParallelMD/single_loop_param_parallel.ll
@@ -0,0 +1,86 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s -check-prefix=SEQUENTIAL
+; RUN: opt %loadPolly -polly-codegen -polly-ast-detect-parallel -S < %s | FileCheck %s -check-prefix=PARALLEL
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+; This is a trivially parallel loop. We just use it to ensure that we actually
+; emit the right information.
+;
+; for (i = 0; i < n; i++)
+;   A[i] = 1;
+;
+@A = common global [1024 x i32] zeroinitializer
+define void @test-one(i64 %n) {
+start:
+  fence seq_cst
+  br label %loop.header
+
+loop.header:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.backedge ]
+  %exitcond = icmp ne i64 %i, %n
+  br i1 %exitcond, label %loop.body, label %ret
+
+loop.body:
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %i
+  store i32 1, i32* %scevgep
+  br label %loop.backedge
+
+loop.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.header
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; SEQUENTIAL: @test-one
+; SEQUENTIAL-NOT: !llvm.mem.parallel_loop_access
+; SEQUENTIAL-NOT: !llvm.loop
+
+; PARALLEL: @test-one
+; PARALLEL: store i32 1, i32* %scevgep1, {{[ ._!,a-zA-Z0-9]*}}, !llvm.mem.parallel_loop_access ![[LoopID:[0-9]*]]
+; PARALLEL:  br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit, !llvm.loop ![[LoopID]]
+
+; This loop has memory dependences that require at least a simple dependence
+; analysis to detect the parallelism.
+;
+; for (i = 0; i < n; i++)
+;   A[2 * i] = A[2 * i + 1];
+;
+define void @test-two(i64 %n) {
+start:
+  fence seq_cst
+  br label %loop.header
+
+loop.header:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.backedge ]
+  %exitcond = icmp ne i64 %i, %n
+  br i1 %exitcond, label %loop.body, label %ret
+
+loop.body:
+  %loadoffset1 = mul nsw i64 %i, 2
+  %loadoffset2 = add nsw i64 %loadoffset1, 1
+  %scevgepload = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %loadoffset2
+  %val = load i32, i32* %scevgepload
+  %storeoffset = mul i64 %i, 2
+  %scevgepstore = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %storeoffset
+  store i32 %val, i32* %scevgepstore
+  br label %loop.backedge
+
+loop.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.header
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; SEQUENTIAL: @test-two
+; SEQUENTIAL-NOT: !llvm.mem.parallel_loop_access
+; SEQUENTIAL-NOT: !llvm.loop
+
+; PARALLEL: @test-two
+; PARALLEL: %val_p_scalar_ = load i32, i32* %scevgep, {{[ ._!,a-zA-Z0-9]*}}, !llvm.mem.parallel_loop_access ![[LoopID:[0-9]*]]
+; PARALLEL: store i32 %val_p_scalar_, i32* %scevgep1, {{[ ._!,a-zA-Z0-9]*}}, !llvm.mem.parallel_loop_access ![[LoopID]]
+; PARALLEL:  br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit, !llvm.loop ![[LoopID]]
diff --git a/final/test/Isl/CodeGen/MemAccess/bad_alignment.ll b/final/test/Isl/CodeGen/MemAccess/bad_alignment.ll
new file mode 100644
index 0000000..e6d71e2
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/bad_alignment.ll
@@ -0,0 +1,36 @@
+; RUN: not opt %loadPolly -polly-import-jscop -analyze 2>&1 < %s | FileCheck %s
+;
+; Check that we do not allow to access elements not accessed before because the
+; alignment information would become invalid.
+;
+; CHECK: JScop file changes the accessed memory
+;
+;    void bad_alignment(int *A) {
+;      for (int i = 0; i < 1024; i += 2)
+;        A[i] = i;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @bad_alignment(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = trunc i64 %indvars.iv to i32
+  store i32 %tmp, i32* %arrayidx, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 2
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/bad_alignment___%for.cond---%for.end.jscop b/final/test/Isl/CodeGen/MemAccess/bad_alignment___%for.cond---%for.end.jscop
new file mode 100644
index 0000000..d29a49d
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/bad_alignment___%for.cond---%for.end.jscop
@@ -0,0 +1,17 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => polly.merge_new_and_old",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body[i0] : i0 >= 0 and i0 <= 511 }",
+         "name" : "Stmt_for_body",
+         "schedule" : "{ Stmt_for_body[i0] -> [0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_address_space.ll b/final/test/Isl/CodeGen/MemAccess/codegen_address_space.ll
new file mode 100644
index 0000000..a013e1b
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_address_space.ll
@@ -0,0 +1,44 @@
+;RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -instnamer < %s -S | FileCheck %s
+
+;int A[100];
+;
+;int codegen_simple () {
+;  for (int i = 0; i < 12; i++)
+;    A[13] = A[i] + A[i-1];
+;
+;  return 0;
+;}
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
+
+define i32 @codegen_simple([100 x i32] addrspace(5)* %A) nounwind {
+entry:
+  %arrayidx.write = getelementptr [100 x i32], [100 x i32] addrspace(5)* %A, i32 0, i32 13
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %tmp1 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %tmp = add i32 %tmp1, -1
+  %arrayidx4 = getelementptr [100 x i32], [100 x i32] addrspace(5)* %A, i32 0, i32 %tmp
+  %arrayidx = getelementptr [100 x i32], [100 x i32] addrspace(5)* %A, i32 0, i32 %tmp1
+  %exitcond = icmp ne i32 %tmp1, 12
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp2 = load i32, i32 addrspace(5)* %arrayidx, align 4
+  %tmp5 = load i32, i32 addrspace(5)* %arrayidx4, align 4
+  %add = add nsw i32 %tmp2, %tmp5
+  store i32 %add, i32 addrspace(5)* %arrayidx.write
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %tmp1, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret i32 0
+}
+
+; CHECK: %polly.access.cast.A = bitcast [100 x i32] addrspace(5)* %A to i32 addrspace(5)*
+; CHECK: %polly.access.A = getelementptr i32, i32 addrspace(5)* %polly.access.cast.A, i64 0
+; CHECK: %tmp2_p_scalar_ = load i32, i32 addrspace(5)* %polly.access.A, align 4, !alias.scope !0, !noalias !2
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_constant_offset.ll b/final/test/Isl/CodeGen/MemAccess/codegen_constant_offset.ll
new file mode 100644
index 0000000..e3a4a22
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_constant_offset.ll
@@ -0,0 +1,42 @@
+;RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -instnamer < %s -S | FileCheck %s
+
+;int A[100];
+;
+;int codegen_constant_offset() {
+;  for (int i = 0; i < 12; i++)
+;    A[13] = A[i] + A[i-1];
+;
+;  return 0;
+;}
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
+
+@A = common global [100 x i32] zeroinitializer, align 4
+
+define i32 @codegen_constant_offset() nounwind {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %tmp1 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %tmp = add i32 %tmp1, -1
+  %arrayidx4 = getelementptr [100 x i32], [100 x i32]* @A, i32 0, i32 %tmp
+  %arrayidx = getelementptr [100 x i32], [100 x i32]* @A, i32 0, i32 %tmp1
+  %exitcond = icmp ne i32 %tmp1, 12
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %tmp5 = load i32, i32* %arrayidx4, align 4
+  %add = add nsw i32 %tmp2, %tmp5
+  store i32 %add, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 13), align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %tmp1, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret i32 0
+}
+; CHECK: load i32, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i{{(32|64)}} 0, i{{(32|64)}} 10)
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_constant_offset___%for.cond---%for.end.jscop b/final/test/Isl/CodeGen/MemAccess/codegen_constant_offset___%for.cond---%for.end.jscop
new file mode 100644
index 0000000..78903fb
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_constant_offset___%for.cond---%for.end.jscop
@@ -0,0 +1,25 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[-1 + i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[13] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body[i0] : i0 >= 0 and i0 <= 11 }",
+         "name" : "Stmt_for_body",
+         "schedule" : "{ Stmt_for_body[i0] -> [0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_constant_offset___%for.cond---%for.end.jscop.transformed b/final/test/Isl/CodeGen/MemAccess/codegen_constant_offset___%for.cond---%for.end.jscop.transformed
new file mode 100644
index 0000000..38cd08d
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_constant_offset___%for.cond---%for.end.jscop.transformed
@@ -0,0 +1,25 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[10] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[-1 + i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[13] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body[i0] : i0 >= 0 and i0 <= 11 }",
+         "name" : "Stmt_for_body",
+         "schedule" : "{ Stmt_for_body[i0] -> [0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_simple.ll b/final/test/Isl/CodeGen/MemAccess/codegen_simple.ll
new file mode 100644
index 0000000..4aa414f
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple.ll
@@ -0,0 +1,42 @@
+;RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -instnamer < %s -S | FileCheck %s
+
+;int A[100];
+;
+;int codegen_simple () {
+;  for (int i = 0; i < 12; i++)
+;    A[13] = A[i] + A[i-1];
+;
+;  return 0;
+;}
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
+
+@A = common global [100 x i32] zeroinitializer, align 4
+
+define i32 @codegen_simple() nounwind {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %tmp1 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %tmp = add i32 %tmp1, -1
+  %arrayidx4 = getelementptr [100 x i32], [100 x i32]* @A, i32 0, i32 %tmp
+  %arrayidx = getelementptr [100 x i32], [100 x i32]* @A, i32 0, i32 %tmp1
+  %exitcond = icmp ne i32 %tmp1, 12
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %tmp5 = load i32, i32* %arrayidx4, align 4
+  %add = add nsw i32 %tmp2, %tmp5
+  store i32 %add, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 13), align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %tmp1, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret i32 0
+}
+; CHECK: load i32, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0)
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_simple___%for.cond---%for.end.jscop b/final/test/Isl/CodeGen/MemAccess/codegen_simple___%for.cond---%for.end.jscop
new file mode 100644
index 0000000..78903fb
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple___%for.cond---%for.end.jscop
@@ -0,0 +1,25 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[-1 + i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[13] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body[i0] : i0 >= 0 and i0 <= 11 }",
+         "name" : "Stmt_for_body",
+         "schedule" : "{ Stmt_for_body[i0] -> [0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_simple___%for.cond---%for.end.jscop.transformed b/final/test/Isl/CodeGen/MemAccess/codegen_simple___%for.cond---%for.end.jscop.transformed
new file mode 100644
index 0000000..7ca7b67
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple___%for.cond---%for.end.jscop.transformed
@@ -0,0 +1,25 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[-1 + i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[13] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body[i0] : i0 >= 0 and i0 <= 11 }",
+         "name" : "Stmt_for_body",
+         "schedule" : "{ Stmt_for_body[i0] -> [0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_simple_float.ll b/final/test/Isl/CodeGen/MemAccess/codegen_simple_float.ll
new file mode 100644
index 0000000..bdd80a0
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple_float.ll
@@ -0,0 +1,41 @@
+;RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -instnamer < %s -S | FileCheck %s
+;
+;float A[100];
+;
+;int codegen_simple () {
+;  for (int i = 0; i < 12; i++)
+;    A[13] = A[i] + A[i-1];
+;
+;  return 0;
+;}
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
+
+@A = common global [100 x float] zeroinitializer, align 4
+
+define i32 @codegen_simple() nounwind {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %tmp1 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %tmp = add i32 %tmp1, -1
+  %arrayidx4 = getelementptr [100 x float], [100 x float]* @A, i32 0, i32 %tmp
+  %arrayidx = getelementptr [100 x float], [100 x float]* @A, i32 0, i32 %tmp1
+  %exitcond = icmp ne i32 %tmp1, 12
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp2 = load float, float* %arrayidx, align 4
+  %tmp5 = load float, float* %arrayidx4, align 4
+  %add = fadd float %tmp2, %tmp5
+  store float %add, float* getelementptr inbounds ([100 x float], [100 x float]* @A, i32 0, i32 13), align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %tmp1, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret i32 0
+}
+; CHECK: load float, float* getelementptr inbounds ([100 x float], [100 x float]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0)
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_simple_md.ll b/final/test/Isl/CodeGen/MemAccess/codegen_simple_md.ll
new file mode 100644
index 0000000..1c15810
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple_md.ll
@@ -0,0 +1,72 @@
+;RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed+withconst -polly-codegen < %s -S | FileCheck -check-prefix=WITHCONST %s
+;RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed+withoutconst -polly-codegen < %s -S | FileCheck -check-prefix=WITHOUTCONST %s
+
+;int A[1040];
+;
+;int codegen_simple_md() {
+;  for (int i = 0; i < 32; ++i)
+;    for (int j = 0; j < 32; ++j)
+;      A[32*i+j] = 100;
+;
+;  return 0;
+;}
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
+
+@A = common global [1040 x i32] zeroinitializer, align 4
+
+define i32 @codegen_simple_md() nounwind {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc5, %for.inc4 ]
+  %exitcond1 = icmp ne i32 %i.0, 32
+  br i1 %exitcond1, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 32
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %mul = shl nsw i32 %i.0, 5
+  %add = add nsw i32 %mul, %j.0
+  %arrayidx = getelementptr inbounds [1040 x i32], [1040 x i32]* @A, i32 0, i32 %add
+  store i32 100, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %inc5 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret i32 0
+}
+
+; WITHCONST:  %[[IVOut:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ]
+; WITHCONST:  %[[IVIn:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ]
+; WITHCONST:  %[[MUL1:[._a-zA-Z0-9]+]] = mul nsw i64 16, %[[IVOut]]
+; WITHCONST:  %[[MUL2:[._a-zA-Z0-9]+]] = mul nsw i64 2, %[[IVIn]]
+; WITHCONST:  %[[SUM1:[._a-zA-Z0-9]+]] = add nsw i64 %[[MUL1]], %[[MUL2]]
+; WITHCONST:  %[[SUM2:[._a-zA-Z0-9]+]] = add nsw i64 %[[SUM1]], 5
+; WITHCONST:  %[[ACC:[._a-zA-Z0-9]*]] = getelementptr i32, i32* getelementptr inbounds ([1040 x i32], [1040 x i32]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0), i64 %[[SUM2]]
+; WITHCONST:  store i32 100, i32* %[[ACC]]
+
+; WITHOUTCONST:  %[[IVOut:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ]
+; WITHOUTCONST:  %[[IVIn:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ]
+; WITHOUTCONST:  %[[MUL1:[._a-zA-Z0-9]+]] = mul nsw i64 16, %[[IVOut]]
+; WITHOUTCONST:  %[[MUL2:[._a-zA-Z0-9]+]] = mul nsw i64 2, %[[IVIn]]
+; WITHOUTCONST:  %[[SUM1:[._a-zA-Z0-9]+]] = add nsw i64 %[[MUL1]], %[[MUL2]]
+; WITHOUTCONST:  %[[ACC:[._a-zA-Z0-9]*]] = getelementptr i32, i32* getelementptr inbounds ([1040 x i32], [1040 x i32]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0), i64 %[[SUM1]]
+; WITHOUTCONST:  store i32 100, i32* %[[ACC]]
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_simple_md___%for.cond---%for.end6.jscop b/final/test/Isl/CodeGen/MemAccess/codegen_simple_md___%for.cond---%for.end6.jscop
new file mode 100644
index 0000000..c34536b
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple_md___%for.cond---%for.end6.jscop
@@ -0,0 +1,17 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end6",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_A[32i0 + i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body3[i0, i1] : i0 >= 0 and i0 <= 31 and i1 >= 0 and i1 <= 31 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "{ Stmt_for_body3[i0, i1] -> [0, i0, 0, i1, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_simple_md___%for.cond---%for.end6.jscop.transformed+withconst b/final/test/Isl/CodeGen/MemAccess/codegen_simple_md___%for.cond---%for.end6.jscop.transformed+withconst
new file mode 100644
index 0000000..1e36572
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple_md___%for.cond---%for.end6.jscop.transformed+withconst
@@ -0,0 +1,17 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end6",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_A[16i0 + 2i1 + 5] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body3[i0, i1] : i0 >= 0 and i0 <= 31 and i1 >= 0 and i1 <= 31 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "{ Stmt_for_body3[i0, i1] -> [0, i0, 0, i1, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_simple_md___%for.cond---%for.end6.jscop.transformed+withoutconst b/final/test/Isl/CodeGen/MemAccess/codegen_simple_md___%for.cond---%for.end6.jscop.transformed+withoutconst
new file mode 100644
index 0000000..1620b50
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple_md___%for.cond---%for.end6.jscop.transformed+withoutconst
@@ -0,0 +1,17 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end6",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_A[16i0 + 2i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body3[i0, i1] : i0 >= 0 and i0 <= 31 and i1 >= 0 and i1 <= 31 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "{ Stmt_for_body3[i0, i1] -> [0, i0, 0, i1, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/codegen_simple_md_float.ll b/final/test/Isl/CodeGen/MemAccess/codegen_simple_md_float.ll
new file mode 100644
index 0000000..8fdace5
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple_md_float.ll
@@ -0,0 +1,69 @@
+;RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed+withconst -polly-codegen < %s -S | FileCheck -check-prefix=WITHCONST %s
+;RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed+withoutconst -polly-codegen < %s -S | FileCheck -check-prefix=WITHOUTCONST %s
+;
+;float A[1040];
+;
+;int codegen_simple_md() {
+;  for (int i = 0; i < 32; ++i)
+;    for (int j = 0; j < 32; ++j)
+;      A[32*i+j] = 100;
+;}
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
+
+@A = common global [1040 x float] zeroinitializer, align 4
+
+define void @codegen_simple_md() nounwind {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc5, %for.inc4 ]
+  %exitcond1 = icmp ne i32 %i.0, 32
+  br i1 %exitcond1, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 32
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %mul = shl nsw i32 %i.0, 5
+  %add = add nsw i32 %mul, %j.0
+  %arrayidx = getelementptr inbounds [1040 x float], [1040 x float]* @A, i32 0, i32 %add
+  store float 100.0, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %inc5 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret void
+}
+
+; WITHCONST:  %[[IVOut:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ]
+; WITHCONST:  %[[IVIn:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ]
+; WITHCONST:  %[[MUL1:[._a-zA-Z0-9]+]] = mul nsw i64 16, %[[IVOut]]
+; WITHCONST:  %[[MUL2:[._a-zA-Z0-9]+]] = mul nsw i64 2, %[[IVIn]]
+; WITHCONST:  %[[SUM1:[._a-zA-Z0-9]+]] = add nsw i64 %[[MUL1]], %[[MUL2]]
+; WITHCONST:  %[[SUM2:[._a-zA-Z0-9]+]] = add nsw i64 %[[SUM1]], 5
+; WITHCONST:  %[[ACC:[._a-zA-Z0-9]*]] = getelementptr float, float* getelementptr inbounds ([1040 x float], [1040 x float]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0), i64 %[[SUM2]]
+; WITHCONST:  store float 1.000000e+02, float* %[[ACC]]
+
+; WITHOUTCONST:  %[[IVOut:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ]
+; WITHOUTCONST:  %[[IVIn:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ]
+; WITHOUTCONST:  %[[MUL1:[._a-zA-Z0-9]+]] = mul nsw i64 16, %[[IVOut]]
+; WITHOUTCONST:  %[[MUL2:[._a-zA-Z0-9]+]] = mul nsw i64 2, %[[IVIn]]
+; WITHOUTCONST:  %[[SUM1:[._a-zA-Z0-9]+]] = add nsw i64 %[[MUL1]], %[[MUL2]]
+; WITHOUTCONST:  %[[ACC:[._a-zA-Z0-9]*]] = getelementptr float, float* getelementptr inbounds ([1040 x float], [1040 x float]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0), i64 %[[SUM1]]
+; WITHOUTCONST:  store float 1.000000e+02, float* %[[ACC]]
diff --git a/final/test/Isl/CodeGen/MemAccess/create_arrays.ll b/final/test/Isl/CodeGen/MemAccess/create_arrays.ll
new file mode 100644
index 0000000..97e5860
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/create_arrays.ll
@@ -0,0 +1,88 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-import-jscop -polly-import-jscop-postfix=transformed < %s 2>&1 | FileCheck %s
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -S < %s 2>&1 | FileCheck %s --check-prefix=CODEGEN
+;
+;  for (i = 0; i < _PB_NI; i++)
+;    for (j = 0; j < _PB_NJ; j++)
+;      for (k = 0; k < _PB_NK; ++k)
+;        B[i][j] = beta * A[i][k];
+;
+;
+; CHECK:    Arrays {
+; CHECK:        double MemRef_B[*][1024]; // Element size 8
+; CHECK:        double MemRef_beta; // Element size 8
+; CHECK:        double MemRef_A[*][1056]; // Element size 8
+; CHECK:        double D[270336]; // Element size 8
+; CHECK:        double E[270336][200000]; // Element size 8
+; CHECK:        i64 F[270336]; // Element size 8
+;
+; CHECK:New access function '{ Stmt_bb12[i0, i1, i2] -> E[i2, i0] }' detected in JSCOP file
+;
+; CODEGEN:define internal void @create_arrays(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %beta, [1056 x double]* %A, [1024 x double]* %B, [1056 x double]* %arg7) #0 {
+; CODEGEN:bb:
+; CODEGEN:  %beta.s2a = alloca double
+; CODEGEN:  %D = alloca [270336 x double]
+; CODEGEN:  %E = alloca [270336 x [200000 x double]]
+; CODEGEN:  %F = alloca [270336 x i64]
+; CODEGEN:  br label %bb8
+;
+; CODEGEN:  %beta.s2a.reload = load double, double* %beta.s2a
+; CODEGEN:  %polly.access.cast.E = bitcast [270336 x [200000 x double]]* %E to double*
+; CODEGEN:  %polly.access.mul.E = mul nsw i64 %polly.indvar33, 200000
+; CODEGEN:  %polly.access.add.E = add nsw i64 %polly.access.mul.E, %polly.indvar
+; CODEGEN:  {{%.*}} = load double, double* %polly.access.E, align 8, !alias.scope [[TAG0:![0-9]+]], !noalias [[TAG2:![0-9]+]]
+; CODEGEN:  store double {{%.*}}, double* %scevgep36, align 8, !alias.scope [[TAG5:![0-9]+]], !noalias [[TAG8:![0-9]+]]
+;
+; CODEGEN: [[TAG0]] = distinct !{[[TAG0]], [[TAG1:![0-9]+]], !"polly.alias.scope.E"}
+; CODEGEN: [[TAG1]] = distinct !{[[TAG1]], !"polly.alias.scope.domain"}
+; CODEGEN: [[TAG2]] = !{[[TAG3:![0-9]+]], [[TAG4:![0-9]+]], [[TAG5:![0-9]+]], [[TAG6:![0-9]+]]}
+; CODEGEN: [[TAG3]] = distinct !{[[TAG3]], [[TAG1]], !"polly.alias.scope.MemRef_B"}
+; CODEGEN: [[TAG4]] = distinct !{[[TAG4]], [[TAG1]], !"polly.alias.scope.MemRef_A"}
+; CODEGEN: [[TAG5]] = distinct !{[[TAG5]], [[TAG1]], !"polly.alias.scope.D"}
+; CODEGEN: [[TAG6]] = distinct !{[[TAG6]], [[TAG1]], !"polly.alias.scope.F"}
+; CODEGEN: [[TAG7:![0-9]+]] = !{[[TAG3]], [[TAG5]], [[TAG0]], [[TAG6]]}
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+; Function Attrs: nounwind uwtable
+define internal void @create_arrays(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %beta, [1056 x double]* %A, [1024 x double]* %B, [1056 x double]* %arg7) #0 {
+bb:
+  br label %bb8
+
+bb8:                                              ; preds = %bb
+  br label %bb9
+
+bb9:                                              ; preds = %bb23, %bb8
+  %tmp = phi i64 [ 0, %bb8 ], [ %tmp24, %bb23 ]
+  br label %bb10
+
+bb10:                                             ; preds = %bb20, %bb9
+  %tmp11 = phi i64 [ 0, %bb9 ], [ %tmp21, %bb20 ]
+  br label %bb12
+
+bb12:                                             ; preds = %bb12, %bb10
+  %tmp13 = phi i64 [ 0, %bb10 ], [ %tmp18, %bb12 ]
+  %tmp14 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %tmp, i64 %tmp13
+  %tmp15 = load double, double* %tmp14, align 8
+  %tmp16 = fmul double %tmp15, %beta
+  %tmp17 = getelementptr inbounds [1056 x double], [1056 x double]* %A, i64 %tmp, i64 %tmp11
+  store double %tmp16, double* %tmp17, align 8
+  %tmp18 = add nuw nsw i64 %tmp13, 1
+  %tmp19 = icmp ne i64 %tmp18, 1024
+  br i1 %tmp19, label %bb12, label %bb20
+
+bb20:                                             ; preds = %bb12
+  %tmp21 = add nuw nsw i64 %tmp11, 1
+  %tmp22 = icmp ne i64 %tmp21, 1056
+  br i1 %tmp22, label %bb10, label %bb23
+
+bb23:                                             ; preds = %bb20
+  %tmp24 = add nuw nsw i64 %tmp, 1
+  %tmp25 = icmp ne i64 %tmp24, 1056
+  br i1 %tmp25, label %bb9, label %bb26
+
+bb26:                                             ; preds = %bb23
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+aes,+avx,+cmov,+cx16,+fxsr,+mmx,+pclmul,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" }
diff --git a/final/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop b/final/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop
new file mode 100644
index 0000000..82f3e7a
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop
@@ -0,0 +1,37 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1056" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb9---%bb26",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_B[i0, i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_beta[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_A[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb12[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 1023 }",
+         "name" : "Stmt_bb12",
+         "schedule" : "{ Stmt_bb12[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop.transformed b/final/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop.transformed
new file mode 100644
index 0000000..0ed3e59
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop.transformed
@@ -0,0 +1,52 @@
+{
+   "arrays" : [
+       {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1056" ],
+         "type" : "double"
+      },
+      {
+         "name" : "D",
+         "sizes" : [ "270336" ],
+         "type" : "double"
+      },
+      {
+         "name" : "E",
+         "sizes" : [ "270336", "200000" ],
+         "type" : "double"
+      },
+      {
+         "name" : "F",
+         "sizes" : [ "270336" ],
+         "type" : "i64"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb9---%bb26",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> E[i2, i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_beta[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_A[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb12[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 1023 }",
+         "name" : "Stmt_bb12",
+         "schedule" : "{ Stmt_bb12[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/create_arrays_heap.ll b/final/test/Isl/CodeGen/MemAccess/create_arrays_heap.ll
new file mode 100644
index 0000000..ca49829
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/create_arrays_heap.ll
@@ -0,0 +1,113 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-import-jscop -polly-import-jscop-postfix=transformed < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -S < %s | FileCheck %s --check-prefix=CODEGEN
+;
+; #define Ni 1056
+; #define Nj 1056
+; #define Nk 1024
+;
+; void create_arrays_heap(double beta, double A[Ni][Nk], double B[Ni][Nj]) {
+;   int i,j,k;
+;
+;   for (i = 0; i < Ni; i++) {
+;     for (j = 0; j < Nj; j++) {
+;       for (k = 0; k < Nk; ++k) {
+; 	B[i][j] = beta * A[i][k];
+;       }
+;     }
+;   }
+; }
+;
+; Check if the info from the JSON file has been analysed without errors.
+; CHECK: Arrays {
+; CHECK: double MemRef_A[*][1024]; // Element size 8
+; CHECK: double MemRef_beta; // Element size 8
+; CHECK: double MemRef_B[*][1056]; // Element size 8
+; CHECK: double D[270336]; // Element size 8
+; CHECK: double E[270336][200000]; // Element size 8
+; CHECK: i64 F[270336]; // Element size 8
+;
+; Check if there are the 3 expected malloc calls with the right parameters at polly.start.
+; 	%D : size(D) = product_all_dimensions*sizeof(type) = 270336*8 = 2162688 cast to double*
+;	%E : size(E) = 270336*200000*8 = 432537600000 cast to double*
+; 	%F : size(F) = 270336*8 = 2162688 cast to i64*
+; CODEGEN: polly.start:
+; CODEGEN: %malloccall = tail call i8* @malloc(i64 2162688)
+; CODEGEN: %D = bitcast i8* %malloccall to double*
+; CODEGEN: %malloccall1 = tail call i8* @malloc(i64 432537600000)
+; CODEGEN: %E = bitcast i8* %malloccall1 to double*
+; CODEGEN: %malloccall2 = tail call i8* @malloc(i64 2162688)
+; CODEGEN: %F = bitcast i8* %malloccall2 to i64*
+;
+; Check if there are the 3 expected malloc calls with the right parameters at polly.exiting.
+; 	Cast to i8* before freeing because malloc give us a i8 and free is waiting for a i8*
+; CODEGEN: polly.exiting:
+; CODEGEN: %12 = bitcast double* %D to i8*
+; CODEGEN: tail call void @free(i8* %12)
+; CODEGEN: %13 = bitcast double* %E to i8*
+; CODEGEN: tail call void @free(i8* %13)
+; CODEGEN: %14 = bitcast i64* %F to i8*
+; CODEGEN: tail call void @free(i8* %14)
+;
+; Check if the new access for array E is present.
+; CODEGEN: %polly.access.mul.E = mul nsw i64 %polly.indvar, 200000
+; CODEGEN: %polly.access.add.E = add nsw i64 %polly.access.mul.E, %
+; CODEGEN: %polly.access.E = getelementptr double, double* %E, i64 %polly.access.add.E
+;
+; ModuleID = 'create_arrays_heap.ll'
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @create_arrays_heap(double %beta, [1024 x double]* nocapture readonly %A, [1056 x double]* nocapture %B) local_unnamed_addr {
+entry:
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.inc16, %entry
+  %indvars.iv35 = phi i64 [ 0, %entry ], [ %indvars.iv.next36, %for.inc16 ]
+  br label %for.cond4.preheader
+
+for.cond4.preheader:                              ; preds = %for.inc13, %for.cond1.preheader
+  %indvars.iv32 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next33, %for.inc13 ]
+  %arrayidx12 = getelementptr inbounds [1056 x double], [1056 x double]* %B, i64 %indvars.iv35, i64 %indvars.iv32
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.cond4.preheader
+  %indvars.iv = phi i64 [ 0, %for.cond4.preheader ], [ %indvars.iv.next.3, %for.body6 ]
+  %arrayidx8 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 %indvars.iv35, i64 %indvars.iv
+  %0 = load double, double* %arrayidx8, align 8
+  %mul = fmul double %0, %beta
+  store double %mul, double* %arrayidx12, align 8
+  %indvars.iv.next = or i64 %indvars.iv, 1
+  %arrayidx8.1 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 %indvars.iv35, i64 %indvars.iv.next
+  %1 = load double, double* %arrayidx8.1, align 8
+  %mul.1 = fmul double %1, %beta
+  store double %mul.1, double* %arrayidx12, align 8
+  %indvars.iv.next.1 = or i64 %indvars.iv, 2
+  %arrayidx8.2 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 %indvars.iv35, i64 %indvars.iv.next.1
+  %2 = load double, double* %arrayidx8.2, align 8
+  %mul.2 = fmul double %2, %beta
+  store double %mul.2, double* %arrayidx12, align 8
+  %indvars.iv.next.2 = or i64 %indvars.iv, 3
+  %arrayidx8.3 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 %indvars.iv35, i64 %indvars.iv.next.2
+  %3 = load double, double* %arrayidx8.3, align 8
+  %mul.3 = fmul double %3, %beta
+  store double %mul.3, double* %arrayidx12, align 8
+  %indvars.iv.next.3 = add nsw i64 %indvars.iv, 4
+  %exitcond.3 = icmp eq i64 %indvars.iv.next.3, 1024
+  br i1 %exitcond.3, label %for.inc13, label %for.body6
+
+for.inc13:                                        ; preds = %for.body6
+  %indvars.iv.next33 = add nuw nsw i64 %indvars.iv32, 1
+  %exitcond34 = icmp eq i64 %indvars.iv.next33, 1056
+  br i1 %exitcond34, label %for.inc16, label %for.cond4.preheader
+
+for.inc16:                                        ; preds = %for.inc13
+  %indvars.iv.next36 = add nuw nsw i64 %indvars.iv35, 1
+  %exitcond37 = icmp eq i64 %indvars.iv.next36, 1056
+  br i1 %exitcond37, label %for.end18, label %for.cond1.preheader
+
+for.end18:                                        ; preds = %for.inc16
+  ret void
+}
+
diff --git a/final/test/Isl/CodeGen/MemAccess/create_arrays_heap___%for.cond1.preheader---%for.end18.jscop b/final/test/Isl/CodeGen/MemAccess/create_arrays_heap___%for.cond1.preheader---%for.end18.jscop
new file mode 100644
index 0000000..69dd236
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/create_arrays_heap___%for.cond1.preheader---%for.end18.jscop
@@ -0,0 +1,62 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1056" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "location" : "pure_c_main.c:11-16",
+   "name" : "%for.cond1.preheader---%for.end18",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_A[i0, 4i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_beta[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_A[i0, 1 + 4i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_A[i0, 2 + 4i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_A[i0, 3 + 4i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt2[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 255 }",
+         "name" : "Stmt2",
+         "schedule" : "{ Stmt2[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/create_arrays_heap___%for.cond1.preheader---%for.end18.jscop.transformed b/final/test/Isl/CodeGen/MemAccess/create_arrays_heap___%for.cond1.preheader---%for.end18.jscop.transformed
new file mode 100644
index 0000000..4d529ec
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/create_arrays_heap___%for.cond1.preheader---%for.end18.jscop.transformed
@@ -0,0 +1,80 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1056" ],
+         "type" : "double"
+      },
+      {
+         "name" : "D",
+         "sizes" : [ "270336" ],
+         "type" : "double",
+	 "allocation" : "heap"
+      },
+      {
+         "name" : "E",
+         "sizes" : [ "270336", "200000" ],
+         "type" : "double",
+	 "allocation" : "heap"
+      },
+      {
+         "name" : "F",
+         "sizes" : [ "270336" ],
+         "type" : "i64",
+	 "allocation" : "heap"
+      }
+   ],
+   "context" : "{  :  }",
+   "location" : "pure_c_main.c:11-16",
+   "name" : "%for.cond1.preheader---%for.end18",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt2[i0, i1, i2] -> E[i0, 4i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_beta[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt2[i0, i1, i2] -> E[i0, 1 + 4i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt2[i0, i1, i2] -> E[i0, 2 + 4i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt2[i0, i1, i2] -> E[i0, 3 + 4i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt2[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt2[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 255 }",
+         "name" : "Stmt2",
+         "schedule" : "{ Stmt2[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/default_aligned_new_access_function.ll b/final/test/Isl/CodeGen/MemAccess/default_aligned_new_access_function.ll
new file mode 100644
index 0000000..25f1c4d
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/default_aligned_new_access_function.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -basicaa -polly-import-jscop -analyze < %s | FileCheck %s
+;
+; Check that we allow the new access functions even though they access
+; different locations than the original ones (but the alignment is the
+; default, thus there is no problem).
+;
+; CHECK-DAG: New access function '{ Stmt_for_body[i0] -> MemRef_B[0] }' detected in JSCOP file
+; CHECK-DAG: New access function '{ Stmt_for_body[i0] -> MemRef_A[i0] }' detected in JSCOP file
+;
+;    void simple_stride(int *restrict A, int *restrict B) {
+;      for (int i = 0; i < 16; i++)
+;        A[i * 2] = B[i * 2];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @simple_stride(i32* noalias %A, i32* noalias %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 16
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = shl nsw i64 %indvars.iv, 1
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %tmp
+  %tmp4 = load i32, i32* %arrayidx, align 4
+  %tmp5 = shl nsw i64 %indvars.iv, 1
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %tmp5
+  store i32 %tmp4, i32* %arrayidx3, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/different_types.ll b/final/test/Isl/CodeGen/MemAccess/different_types.ll
new file mode 100644
index 0000000..35836b6
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/different_types.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN: \
+; RUN: -polly-codegen -S < %s | FileCheck %s
+;
+;    void foo(float A[], float B[]) {
+;      for (long i = 0; i < 100; i++)
+;        *(int *)(&A[i]) = *(int *)(&B[i]);
+;      for (long i = 0; i < 100; i++)
+;        A[i] += 10;
+;    }
+
+; CHECK: %polly.access.cast.A14 = bitcast float* %A to i32*
+; CHECK: %[[R1:[._0-9]*]] = sub nsw i64 0, %polly.indvar11
+; CHECK: %[[R2:[._0-9]*]] = add nsw i64 %[[R1]], 99
+; CHECK: %polly.access.A15 = getelementptr i32, i32* %polly.access.cast.A14, i64 %[[R2]]
+; CHECK: %[[R3:[._0-9]*]] = bitcast i32* %polly.access.A15 to float*
+; CHECK: %tmp14_p_scalar_ = load float, float* %[[R3]], align 4, !alias.scope !3, !noalias !4
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @different_types(float* %A, float* %B) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb8, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp9, %bb8 ]
+  %exitcond1 = icmp ne i64 %i.0, 100
+  br i1 %exitcond1, label %bb3, label %bb10
+
+bb3:                                              ; preds = %bb2
+  %tmp = getelementptr inbounds float, float* %B, i64 %i.0
+  %tmp4 = bitcast float* %tmp to i32*
+  %tmp5 = load i32, i32* %tmp4, align 4
+  %tmp6 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp7 = bitcast float* %tmp6 to i32*
+  store i32 %tmp5, i32* %tmp7, align 4
+  br label %bb8
+
+bb8:                                              ; preds = %bb3
+  %tmp9 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb10:                                             ; preds = %bb2
+  br label %bb11
+
+bb11:                                             ; preds = %bb16, %bb10
+  %i1.0 = phi i64 [ 0, %bb10 ], [ %tmp17, %bb16 ]
+  %exitcond = icmp ne i64 %i1.0, 100
+  br i1 %exitcond, label %bb12, label %bb18
+
+bb12:                                             ; preds = %bb11
+  %tmp13 = getelementptr inbounds float, float* %A, i64 %i1.0
+  %tmp14 = load float, float* %tmp13, align 4
+  %tmp15 = fadd float %tmp14, 1.000000e+01
+  store float %tmp15, float* %tmp13, align 4
+  br label %bb16
+
+bb16:                                             ; preds = %bb12
+  %tmp17 = add nuw nsw i64 %i1.0, 1
+  br label %bb11
+
+bb18:                                             ; preds = %bb11
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/different_types___%bb2---%bb18.jscop b/final/test/Isl/CodeGen/MemAccess/different_types___%bb2---%bb18.jscop
new file mode 100644
index 0000000..49f6b96
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/different_types___%bb2---%bb18.jscop
@@ -0,0 +1,36 @@
+{
+   "context" : "{  :  }",
+   "name" : "bb2 => bb18",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb3[i0] -> MemRef_B[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb3[i0] -> MemRef_A[99 - i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb3[i0] : i0 <= 99 and i0 >= 0 }",
+         "name" : "Stmt_bb3",
+         "schedule" : "{ Stmt_bb3[i0] -> [0, i0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0] -> MemRef_A[99 - i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb12[i0] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb12[i0] : i0 <= 99 and i0 >= 0 }",
+         "name" : "Stmt_bb12",
+         "schedule" : "{ Stmt_bb12[i0] -> [1, i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/generate-all.ll b/final/test/Isl/CodeGen/MemAccess/generate-all.ll
new file mode 100644
index 0000000..a3253ef
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/generate-all.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-codegen -polly-codegen-generate-expressions=false \
+; RUN:     -S < %s | FileCheck %s -check-prefix=SCEV
+; RUN: opt %loadPolly -polly-codegen -polly-codegen-generate-expressions=true \
+; RUN:     -S < %s | FileCheck %s -check-prefix=ASTEXPR
+;
+;    void foo(float A[]) {
+;      for (long i = 0; i < 100; i++)
+;        A[i % 4] += 10;
+;    }
+
+; SCEV:      polly.stmt.bb2:                                   ; preds = %polly.loop_header
+; SCEV-NEXT:   %p_tmp = srem i64 %polly.indvar, 4
+; SCEV-NEXT:   %p_tmp3 = getelementptr inbounds float, float* %A, i64 %p_tmp
+; SCEV-NEXT:   %tmp4_p_scalar_ = load float, float* %p_tmp3, align 4, !alias.scope !0, !noalias !2
+; SCEV-NEXT:   %p_tmp5 = fadd float %tmp4_p_scalar_, 1.000000e+01
+; SCEV-NEXT:   store float %p_tmp5, float* %p_tmp3, align 4, !alias.scope !0, !noalias !2
+; SCEV-NEXT:   %polly.indvar_next = add nsw i64 %polly.indvar, 1
+; SCEV-NEXT:   %polly.loop_cond = icmp sle i64 %polly.indvar_next, 99
+; SCEV-NEXT:   br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit
+
+; ASTEXPR: 	polly.stmt.bb2:                                   ; preds = %polly.loop_header
+; ASTEXPR-NEXT:   %pexp.pdiv_r = urem i64 %polly.indvar, 4
+; ASTEXPR-NEXT:   %polly.access.A = getelementptr float, float* %A, i64 %pexp.pdiv_r
+; ASTEXPR-NEXT:   %tmp4_p_scalar_ = load float, float* %polly.access.A, align 4, !alias.scope !0, !noalias !2
+; ASTEXPR-NEXT:   %p_tmp5 = fadd float %tmp4_p_scalar_, 1.000000e+01
+; ASTEXPR-NEXT:   %pexp.pdiv_r1 = urem i64 %polly.indvar, 4
+; ASTEXPR-NEXT:   %polly.access.A2 = getelementptr float, float* %A, i64 %pexp.pdiv_r1
+; ASTEXPR-NEXT:   store float %p_tmp5, float* %polly.access.A2, align 4, !alias.scope !0, !noalias !2
+; ASTEXPR-NEXT:   %polly.indvar_next = add nsw i64 %polly.indvar, 1
+; ASTEXPR-NEXT:   %polly.loop_cond = icmp sle i64 %polly.indvar_next, 99
+; ASTEXPR-NEXT:   br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = srem i64 %i.0, 4
+  %tmp3 = getelementptr inbounds float, float* %A, i64 %tmp
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, 1.000000e+01
+  store float %tmp5, float* %tmp3, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/invariant_base_ptr.ll b/final/test/Isl/CodeGen/MemAccess/invariant_base_ptr.ll
new file mode 100644
index 0000000..b684210
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/invariant_base_ptr.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN:   -polly-codegen -polly-invariant-load-hoisting -S \
+; RUN:   2>&1 < %s | FileCheck %s
+
+; Setting new access functions where the base pointer of the array that is newly
+; accessed is only loaded within the scop itself caused incorrect code to be
+; generated when invariant load hoisting is disabled. This test case checks
+; that in case invariant load hoisting is enabled, we generate correct code.
+
+; CHECK: %polly.access.polly.access.X.load = getelementptr float, float* %polly.access.X.load, i64 %polly.indvar
+
+define void @invariant_base_ptr(float* noalias %Array, float** noalias %X,
+                                float* noalias %C) {
+
+start:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
+  %indvar.next = add i64 %indvar, 1
+  %cmp = icmp slt i64 %indvar, 1024
+  br i1 %cmp, label %body, label %exit
+
+body:
+  %gep= getelementptr float, float* %Array, i64 %indvar
+  store float 42.0, float* %gep
+  br label %body2
+
+body2:
+  %Base = load float*, float** %X
+  %gep2 = getelementptr float, float* %Base, i64 %indvar
+  %val2 = load float, float* %gep2
+  store float %val2, float* %C
+  br label %latch
+
+latch:
+  br label %loop
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/invariant_base_ptr___%loop---%exit.jscop b/final/test/Isl/CodeGen/MemAccess/invariant_base_ptr___%loop---%exit.jscop
new file mode 100644
index 0000000..94bfb2f
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/invariant_base_ptr___%loop---%exit.jscop
@@ -0,0 +1,54 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_Array",
+         "sizes" : [ "*" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_X",
+         "sizes" : [ "*" ],
+         "type" : "float*"
+      },
+      {
+         "name" : "MemRef_Base",
+         "sizes" : [ "*" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%loop---%exit",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_body[i0] -> MemRef_Base[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_body[i0] : 0 <= i0 <= 1023 }",
+         "name" : "Stmt_body",
+         "schedule" : "{ Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_body2[i0] -> MemRef_Base[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_body2[i0] -> MemRef_C[0] }"
+            }
+         ],
+         "domain" : "{ Stmt_body2[i0] : 0 <= i0 <= 1023 }",
+         "name" : "Stmt_body2",
+         "schedule" : "{ Stmt_body2[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/map_scalar_access.ll b/final/test/Isl/CodeGen/MemAccess/map_scalar_access.ll
new file mode 100644
index 0000000..04c1fbb
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/map_scalar_access.ll
@@ -0,0 +1,149 @@
+; RUN: opt %loadPolly -polly-import-jscop-postfix=transformed -polly-import-jscop -analyze          < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-import-jscop-postfix=transformed -polly-import-jscop -polly-codegen -S < %s | FileCheck %s --check-prefix=CODEGEN
+
+define void @map_scalar_access(double* noalias nonnull %A) {
+entry:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %entry], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, 1
+  br i1 %j.cmp, label %reduction.for, label %outer.exit
+
+
+    reduction.for:
+      %i = phi i32 [0, %outer.for], [%i.inc, %reduction.inc]
+      %phi = phi double [0.0, %outer.for], [%add, %reduction.inc]
+      %i.cmp = icmp slt i32 %i, 4
+      br i1 %i.cmp, label %body, label %reduction.exit
+
+    body:
+      %add = fadd double %phi, 4.2
+      br label %reduction.inc
+
+    reduction.inc:
+      %i.inc = add nuw nsw i32 %i, 1
+      br label %reduction.for
+
+    reduction.exit:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %phi, double* %A_idx
+      br label %outer.inc
+
+
+outer.inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+
+; CHECK:          Arrays {
+; CHECK-NEXT:         double MemRef_phi__phi; // Element size 8
+; CHECK-NEXT:         double MemRef_phi; // Element size 8
+; CHECK-NEXT:         double MemRef_add; // Element size 8
+; CHECK-NEXT:         double MemRef_A[*]; // Element size 8
+; CHECK-NEXT:     }
+; CHECK:          Statements {
+; CHECK-NEXT:         Stmt_outer_for
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 { Stmt_outer_for[i0] : 0 <= i0 <= 1 };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 { Stmt_outer_for[i0] -> [i0, 0, 0, 0] };
+; CHECK-NEXT:             MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_outer_for[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_outer_for[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         Stmt_reduction_for
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 { Stmt_reduction_for[0, i1] : 0 <= i1 <= 4 };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> [0, 1, i1, 0] };
+; CHECK-NEXT:             ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[0] };
+; CHECK-NEXT:             MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_for[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_for[i0, i1] -> MemRef_A[0] };
+; CHECK-NEXT:         Stmt_body
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 { Stmt_body[0, i1] : 0 <= i1 <= 3 };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> [0, 1, i1, 1] };
+; CHECK-NEXT:             MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[0] };
+; CHECK-NEXT:             ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body[i0, i1] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_body[i0, i1] -> MemRef_A[0] };
+; CHECK-NEXT:         Stmt_reduction_inc
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 { Stmt_reduction_inc[0, i1] : 0 <= i1 <= 3 };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> [0, 1, i1, 2] };
+; CHECK-NEXT:             ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_add[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[0] };
+; CHECK-NEXT:             MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_inc[i0, i1] -> MemRef_A[0] };
+; CHECK-NEXT:         Stmt_reduction_exit
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 { Stmt_reduction_exit[0] };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> [0, 2, 0, 0] };
+; CHECK-NEXT:             MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_A[0] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[0] };
+; CHECK-NEXT:             ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_reduction_exit[i0] -> MemRef_phi[] };
+; CHECK-NEXT:            new: { Stmt_reduction_exit[i0] -> MemRef_A[0] };
+; CHECK-NEXT:     }
+; CHECK:      New access function '{ Stmt_outer_for[i0] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_reduction_for[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_reduction_for[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_body[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_body[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_reduction_exit[i0] -> MemRef_A[i0] }' detected in JSCOP file
+; CHECK-NEXT: New access function '{ Stmt_reduction_exit[i0] -> MemRef_A[i0] }' detected in JSCOP file
+
+; CODEGEN:      polly.stmt.outer.for:
+; CODEGEN-NEXT:   %polly.access.A[[R0:[0-9]*]] = getelementptr double, double* %A, i64 %polly.indvar
+; CODEGEN-NEXT:   store double 0.000000e+00, double* %polly.access.A[[R0]]
+; CODEGEN-NEXT:   br label %polly.cond
+
+; CODEGEN:      polly.stmt.reduction.exit:
+; CODEGEN-NEXT:   %polly.access.A[[R1:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT:   %polly.access.A[[R1]].reload = load double, double* %polly.access.A[[R1]]
+; CODEGEN-NEXT:   %polly.access.A[[R2:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT:   store double %polly.access.A[[R1]].reload, double* %polly.access.A[[R2]]
+; CODEGEN-NEXT:   br label %polly.merge
+
+; CODEGEN:      polly.stmt.reduction.for:
+; CODEGEN-NEXT:   %polly.access.A[[R3:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT:   %polly.access.A[[R3]].reload = load double, double* %polly.access.A[[R3]]
+; CODEGEN-NEXT:   %polly.access.A[[R4:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT:   store double %polly.access.A[[R3]].reload, double* %polly.access.A[[R4]]
+; CODEGEN-NEXT:   br label %polly.cond9
+
+; CODEGEN:      polly.stmt.body:
+; CODEGEN-NEXT:   %polly.access.A[[R5:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT:   %polly.access.A[[R5]].reload = load double, double* %polly.access.A[[R5]]
+; CODEGEN-NEXT:   %p_add = fadd double %polly.access.A13.reload, 4.200000e+00
+; CODEGEN-NEXT:   %polly.access.A[[R6:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT:   store double %p_add, double* %polly.access.A[[R6]]
+; CODEGEN-NEXT:   br label %polly.stmt.reduction.inc
+
+; CODEGEN:      polly.stmt.reduction.inc:
+; CODEGEN-NEXT:   %polly.access.A[[R7:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT:   %polly.access.A[[R7]].reload = load double, double* %polly.access.A[[R7]]
+; CODEGEN-NEXT:   %polly.access.A[[R8:[0-9]*]] = getelementptr double, double* %A, i64 0
+; CODEGEN-NEXT:   store double %polly.access.A[[R7]].reload, double* %polly.access.A[[R8]]
+; CODEGEN-NEXT:   br label %polly.merge10
diff --git a/final/test/Isl/CodeGen/MemAccess/map_scalar_access___%outer.for---%return.jscop b/final/test/Isl/CodeGen/MemAccess/map_scalar_access___%outer.for---%return.jscop
new file mode 100644
index 0000000..3e99198
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/map_scalar_access___%outer.for---%return.jscop
@@ -0,0 +1,84 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%outer.for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_outer_for[i0] -> MemRef_phi__phi[] }"
+            }
+         ],
+         "domain" : "{ Stmt_outer_for[i0] : 0 <= i0 <= 1 }",
+         "name" : "Stmt_outer_for",
+         "schedule" : "{ Stmt_outer_for[i0] -> [i0, 0, 0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_reduction_for[i0, i1] -> MemRef_phi[] }"
+            }
+         ],
+         "domain" : "{ Stmt_reduction_for[0, i1] : 0 <= i1 <= 4 }",
+         "name" : "Stmt_reduction_for",
+         "schedule" : "{ Stmt_reduction_for[i0, i1] -> [0, 1, i1, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_body[i0, i1] -> MemRef_add[] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_body[i0, i1] -> MemRef_phi[] }"
+            }
+         ],
+         "domain" : "{ Stmt_body[0, i1] : 0 <= i1 <= 3 }",
+         "name" : "Stmt_body",
+         "schedule" : "{ Stmt_body[i0, i1] -> [0, 1, i1, 1] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_reduction_inc[i0, i1] -> MemRef_add[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_reduction_inc[i0, i1] -> MemRef_phi__phi[] }"
+            }
+         ],
+         "domain" : "{ Stmt_reduction_inc[0, i1] : 0 <= i1 <= 3 }",
+         "name" : "Stmt_reduction_inc",
+         "schedule" : "{ Stmt_reduction_inc[i0, i1] -> [0, 1, i1, 2] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_reduction_exit[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_reduction_exit[i0] -> MemRef_phi[] }"
+            }
+         ],
+         "domain" : "{ Stmt_reduction_exit[0] }",
+         "name" : "Stmt_reduction_exit",
+         "schedule" : "{ Stmt_reduction_exit[i0] -> [0, 2, 0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/map_scalar_access___%outer.for---%return.jscop.transformed b/final/test/Isl/CodeGen/MemAccess/map_scalar_access___%outer.for---%return.jscop.transformed
new file mode 100644
index 0000000..d495694
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/map_scalar_access___%outer.for---%return.jscop.transformed
@@ -0,0 +1,84 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%outer.for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_outer_for[i0] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_outer_for[i0] : 0 <= i0 <= 1 }",
+         "name" : "Stmt_outer_for",
+         "schedule" : "{ Stmt_outer_for[i0] -> [i0, 0, 0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_reduction_for[i0, i1] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_reduction_for[i0, i1] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_reduction_for[0, i1] : 0 <= i1 <= 4 }",
+         "name" : "Stmt_reduction_for",
+         "schedule" : "{ Stmt_reduction_for[i0, i1] -> [0, 1, i1, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_body[i0, i1] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_body[i0, i1] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_body[0, i1] : 0 <= i1 <= 3 }",
+         "name" : "Stmt_body",
+         "schedule" : "{ Stmt_body[i0, i1] -> [0, 1, i1, 1] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_reduction_inc[i0, i1] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_reduction_inc[0, i1] : 0 <= i1 <= 3 }",
+         "name" : "Stmt_reduction_inc",
+         "schedule" : "{ Stmt_reduction_inc[i0, i1] -> [0, 1, i1, 2] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_reduction_exit[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_reduction_exit[i0] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_reduction_exit[0] }",
+         "name" : "Stmt_reduction_exit",
+         "schedule" : "{ Stmt_reduction_exit[i0] -> [0, 2, 0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/multiple_types.ll b/final/test/Isl/CodeGen/MemAccess/multiple_types.ll
new file mode 100644
index 0000000..d958df6
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/multiple_types.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN: -polly-allow-differing-element-types \
+; RUN:   -polly-codegen -S    < %s | FileCheck %s
+;
+;    // Check that accessing one array with different types works.
+;    void multiple_types(char *Short, char *Float, char *Double) {
+;      for (long i = 0; i < 100; i++) {
+;        Short[i] = *(short *)&Short[2 * i];
+;        Float[i] = *(float *)&Float[4 * i];
+;        Double[i] = *(double *)&Double[8 * i];
+;      }
+;    }
+
+; Short[0]
+; CHECK: %polly.access.Short10 = getelementptr i8, i8* %Short, i64 0
+; CHECK: %24 = bitcast i8* %polly.access.Short10 to i16*
+; CHECK: %tmp5_p_scalar_ = load i16, i16* %24
+
+; Float[8 * i]
+; CHECK: %25 = mul nsw i64 8, %polly.indvar
+; CHECK: %polly.access.Float11 = getelementptr i8, i8* %Float, i64 %25
+; CHECK: %26 = bitcast i8* %polly.access.Float11 to float*
+; CHECK: %tmp11_p_scalar_ = load float, float* %26
+
+; Double[8]
+; CHECK: %polly.access.Double13 = getelementptr i8, i8* %Double, i64 8
+; CHECK: %27 = bitcast i8* %polly.access.Double13 to double*
+; CHECK: %tmp17_p_scalar_ = load double, double* %27
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @multiple_types(i8* %Short, i8* %Float, i8* %Double) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb20, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp21, %bb20 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb2, label %bb22
+
+bb2:                                              ; preds = %bb1
+  %tmp = shl nsw i64 %i.0, 1
+  %tmp3 = getelementptr inbounds i8, i8* %Short, i64 %tmp
+  %tmp4 = bitcast i8* %tmp3 to i16*
+  %tmp5 = load i16, i16* %tmp4, align 2
+  %tmp6 = trunc i16 %tmp5 to i8
+  %tmp7 = getelementptr inbounds i8, i8* %Short, i64 %i.0
+  store i8 %tmp6, i8* %tmp7, align 1
+  %tmp8 = shl nsw i64 %i.0, 2
+  %tmp9 = getelementptr inbounds i8, i8* %Float, i64 %tmp8
+  %tmp10 = bitcast i8* %tmp9 to float*
+  %tmp11 = load float, float* %tmp10, align 4
+  %tmp12 = fptosi float %tmp11 to i8
+  %tmp13 = getelementptr inbounds i8, i8* %Float, i64 %i.0
+  store i8 %tmp12, i8* %tmp13, align 1
+  %tmp14 = shl nsw i64 %i.0, 3
+  %tmp15 = getelementptr inbounds i8, i8* %Double, i64 %tmp14
+  %tmp16 = bitcast i8* %tmp15 to double*
+  %tmp17 = load double, double* %tmp16, align 8
+  %tmp18 = fptosi double %tmp17 to i8
+  %tmp19 = getelementptr inbounds i8, i8* %Double, i64 %i.0
+  store i8 %tmp18, i8* %tmp19, align 1
+  br label %bb20
+
+bb20:                                             ; preds = %bb2
+  %tmp21 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb22:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/multiple_types___%bb1---%bb22.jscop b/final/test/Isl/CodeGen/MemAccess/multiple_types___%bb1---%bb22.jscop
new file mode 100644
index 0000000..3e0ffca
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/multiple_types___%bb1---%bb22.jscop
@@ -0,0 +1,37 @@
+{
+   "context" : "{  :  }",
+   "name" : "bb1 => bb22",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2[i0] -> MemRef_Short[0]}"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb2[i0] -> MemRef_Short[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2[i0] -> MemRef_Float[o0] : 8i0 <=  o0 <= 3 + 8i0 }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb2[i0] -> MemRef_Float[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2[i0] -> MemRef_Double[8]}"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb2[i0] -> MemRef_Double[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb2[i0] : 0 <= i0 <= 99 }",
+         "name" : "Stmt_bb2",
+         "schedule" : "{ Stmt_bb2[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/simple.ll b/final/test/Isl/CodeGen/MemAccess/simple.ll
new file mode 100644
index 0000000..0b01310
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple.ll
@@ -0,0 +1,65 @@
+;RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -stats < %s 2>&1  | FileCheck %s
+; REQUIRES: asserts
+
+;int A[100];
+;int B[100];
+;
+;int simple()
+;{
+;  int i, j;
+;  for (i = 0; i < 12; i++) {
+;      A[i] = i;
+;  }
+;
+;  for (i = 0; i < 12; i++) {
+;      B[i] = i;
+;  }
+;
+;  return 0;
+;}
+;
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
+
+@A = common global [100 x i32] zeroinitializer, align 4
+@B = common global [100 x i32] zeroinitializer, align 4
+
+define i32 @simple() nounwind {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %arrayidx = getelementptr [100 x i32], [100 x i32]* @A, i32 0, i32 %0
+  %exitcond1 = icmp ne i32 %0, 12
+  br i1 %exitcond1, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  store i32 %0, i32* %arrayidx
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc11, %for.end
+  %1 = phi i32 [ 0, %for.end ], [ %inc13, %for.inc11 ]
+  %arrayidx10 = getelementptr [100 x i32], [100 x i32]* @B, i32 0, i32 %1
+  %exitcond = icmp ne i32 %1, 12
+  br i1 %exitcond, label %for.body7, label %for.end14
+
+for.body7:                                        ; preds = %for.cond4
+  store i32 %1, i32* %arrayidx10
+  br label %for.inc11
+
+for.inc11:                                        ; preds = %for.body7
+  %inc13 = add nsw i32 %1, 1
+  br label %for.cond4
+
+for.end14:                                        ; preds = %for.cond4
+  ret i32 0
+}
+; CHECK: 2 polly-import-jscop
diff --git a/final/test/Isl/CodeGen/MemAccess/simple___%for.cond---%for.end.jscop b/final/test/Isl/CodeGen/MemAccess/simple___%for.cond---%for.end.jscop
new file mode 100644
index 0000000..3014bb1
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple___%for.cond---%for.end.jscop
@@ -0,0 +1,17 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body[i0] : i0 >= 0 and i0 <= 11 }",
+         "name" : "Stmt_for_body",
+         "schedule" : "{ Stmt_for_body[i0] -> [0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/simple___%for.cond---%for.end.jscop.transformed b/final/test/Isl/CodeGen/MemAccess/simple___%for.cond---%for.end.jscop.transformed
new file mode 100644
index 0000000..e6c89ce
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple___%for.cond---%for.end.jscop.transformed
@@ -0,0 +1,17 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body[i0] : i0 >= 0 and i0 <= 11 }",
+         "name" : "Stmt_for_body",
+         "schedule" : "{ Stmt_for_body[i0] -> [0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/simple___%for.cond---%for.end14.jscop b/final/test/Isl/CodeGen/MemAccess/simple___%for.cond---%for.end14.jscop
new file mode 100644
index 0000000..1e59614
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple___%for.cond---%for.end14.jscop
@@ -0,0 +1,28 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end14",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body[i0] : i0 >= 0 and i0 <= 11 }",
+         "name" : "Stmt_for_body",
+         "schedule" : "{ Stmt_for_body[i0] -> [0, i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body7[i0] -> MemRef_B[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body7[i0] : i0 >= 0 and i0 <= 11 }",
+         "name" : "Stmt_for_body7",
+         "schedule" : "{ Stmt_for_body7[i0] -> [0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/simple___%for.cond---%for.end14.jscop.transformed b/final/test/Isl/CodeGen/MemAccess/simple___%for.cond---%for.end14.jscop.transformed
new file mode 100644
index 0000000..7aa970c
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple___%for.cond---%for.end14.jscop.transformed
@@ -0,0 +1,28 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end14",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body[i0] : i0 >= 0 and i0 <= 11 }",
+         "name" : "Stmt_for_body",
+         "schedule" : "{ Stmt_for_body[i0] -> [0, i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body7[i0] -> MemRef_B[0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body7[i0] : i0 >= 0 and i0 <= 11 }",
+         "name" : "Stmt_for_body7",
+         "schedule" : "{ Stmt_for_body7[i0] -> [0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/simple___%for.cond4---%for.end14.jscop b/final/test/Isl/CodeGen/MemAccess/simple___%for.cond4---%for.end14.jscop
new file mode 100644
index 0000000..5c3293b
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple___%for.cond4---%for.end14.jscop
@@ -0,0 +1,17 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond4 => for.end14",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body7[i0] -> MemRef_B[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body7[i0] : i0 >= 0 and i0 <= 11 }",
+         "name" : "Stmt_for_body7",
+         "schedule" : "{ Stmt_for_body7[i0] -> [0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/simple___%for.cond4---%for.end14.jscop.transformed b/final/test/Isl/CodeGen/MemAccess/simple___%for.cond4---%for.end14.jscop.transformed
new file mode 100644
index 0000000..fcaa561
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple___%for.cond4---%for.end14.jscop.transformed
@@ -0,0 +1,17 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond4 => for.end14",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body7[i0] -> MemRef_B[0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body7[i0] : i0 >= 0 and i0 <= 11 }",
+         "name" : "Stmt_for_body7",
+         "schedule" : "{ Stmt_for_body7[i0] -> [0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/simple_analyze.ll b/final/test/Isl/CodeGen/MemAccess/simple_analyze.ll
new file mode 100644
index 0000000..d9676bb
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple_analyze.ll
@@ -0,0 +1,76 @@
+;RUN: opt %loadPolly -polly-import-jscop -analyze -polly-import-jscop-postfix=transformed < %s | FileCheck %s
+;RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -polly-vectorizer=polly -S < %s | FileCheck %s --check-prefix=JSCOPVEC
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
+
+@A = common global [100 x i32] zeroinitializer, align 4
+@B = common global [100 x i32] zeroinitializer, align 4
+
+define i32 @simple() nounwind {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %arrayidx = getelementptr [100 x i32], [100 x i32]* @A, i32 0, i32 %0
+  %exitcond1 = icmp ne i32 %0, 12
+  br i1 %exitcond1, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  store i32 %0, i32* %arrayidx
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  fence seq_cst
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc11, %for.end
+  %1 = phi i32 [ 0, %for.end ], [ %inc13, %for.inc11 ]
+  %arrayidx10 = getelementptr [100 x i32], [100 x i32]* @B, i32 0, i32 %1
+  %exitcond = icmp ne i32 %1, 12
+  br i1 %exitcond, label %for.body7, label %for.end14
+
+for.body7:                                        ; preds = %for.cond4
+  store i32 %1, i32* %arrayidx10
+  br label %for.inc11
+
+for.inc11:                                        ; preds = %for.body7
+  %inc13 = add nsw i32 %1, 1
+  br label %for.cond4
+
+for.end14:                                        ; preds = %for.cond4
+  ret i32 0
+}
+; CHECK-DAG: New access function '{ Stmt_for_body7[i0] -> MemRef_B[0] }' detected in JSCOP file
+; CHECK-DAG: New access function '{ Stmt_for_body[i0] -> MemRef_A[0] }' detected in JSCOP file
+
+; Verify that the new access function (see above) is actually used during vector code generation.
+
+; JSCOPVEC:  store i32 0, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @B, i32 0, i32 0)
+; JSCOPVEC:  store i32 1, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @B, i32 0, i32 0)
+; JSCOPVEC:  store i32 2, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @B, i32 0, i32 0)
+; JSCOPVEC:  store i32 3, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @B, i32 0, i32 0)
+; JSCOPVEC:  store i32 4, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @B, i32 0, i32 0)
+; JSCOPVEC:  store i32 5, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @B, i32 0, i32 0)
+; JSCOPVEC:  store i32 6, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @B, i32 0, i32 0)
+; JSCOPVEC:  store i32 7, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @B, i32 0, i32 0)
+; JSCOPVEC:  store i32 8, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @B, i32 0, i32 0)
+; JSCOPVEC:  store i32 9, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @B, i32 0, i32 0)
+; JSCOPVEC:  store i32 10, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @B, i32 0, i32 0)
+; JSCOPVEC:  store i32 11, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @B, i32 0, i32 0)
+
+; JSCOPVEC:  store i32 0, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0)
+; JSCOPVEC:  store i32 1, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0)
+; JSCOPVEC:  store i32 2, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0)
+; JSCOPVEC:  store i32 3, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0)
+; JSCOPVEC:  store i32 4, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0)
+; JSCOPVEC:  store i32 5, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0)
+; JSCOPVEC:  store i32 6, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0)
+; JSCOPVEC:  store i32 7, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0)
+; JSCOPVEC:  store i32 8, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0)
+; JSCOPVEC:  store i32 9, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0)
+; JSCOPVEC:  store i32 10, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0)
+; JSCOPVEC:  store i32 11, i32* getelementptr inbounds ([100 x i32], [100 x i32]* @A, i32 0, i32 0)
diff --git a/final/test/Isl/CodeGen/MemAccess/simple_stride___%for.cond---%for.end.jscop b/final/test/Isl/CodeGen/MemAccess/simple_stride___%for.cond---%for.end.jscop
new file mode 100644
index 0000000..d78df95
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple_stride___%for.cond---%for.end.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_B[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body[i0] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body[i0] : i0 >= 0 and i0 <= 15 }",
+         "name" : "Stmt_for_body",
+         "schedule" : "{ Stmt_for_body[i0] -> [0, i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/simple_stride_test.ll b/final/test/Isl/CodeGen/MemAccess/simple_stride_test.ll
new file mode 100644
index 0000000..e82b7de
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple_stride_test.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -basicaa -polly-import-jscop -polly-codegen -polly-vectorizer=polly -S < %s | FileCheck %s
+;
+; Check that we use the correct __new__ strides:
+;    stride zero for B
+;    stride one for A
+;
+; CHECK:  %polly.access.B = getelementptr i32, i32* %B, i64 0
+; CHECK:  %[[BC:[._a-zA-Z0-9]*]] = bitcast i32* %polly.access.B to <1 x i32>*
+; CHECK:  %[[LD:[._a-zA-Z0-9]*]] = load <1 x i32>, <1 x i32>* %[[BC]], align 8
+; CHECK:  %[[SV:[._a-zA-Z0-9]*]] = shufflevector <1 x i32> %[[LD]], <1 x i32> %[[LD]], <16 x i32> zeroinitializer
+;
+; CHECK:  %polly.access.A = getelementptr i32, i32* %A, i64 0
+; CHECK:  %[[VP:[._a-zA-Z0-9]*]] = bitcast i32* %polly.access.A to <16 x i32>*
+; CHECK:  store <16 x i32> %[[SV]], <16 x i32>* %[[VP]], align 8
+;
+;    void simple_stride(int *restrict A, int *restrict B) {
+;      for (int i = 0; i < 16; i++)
+;        A[i * 2] = B[i * 2];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @simple_stride(i32* noalias %A, i32* noalias %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 16
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = shl nsw i64 %indvars.iv, 1
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %tmp
+  %tmp4 = load i32, i32* %arrayidx, align 4
+  %tmp5 = shl nsw i64 %indvars.iv, 1
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %tmp5
+  store i32 %tmp4, i32* %arrayidx3, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/update_access_functions.ll b/final/test/Isl/CodeGen/MemAccess/update_access_functions.ll
new file mode 100644
index 0000000..969b8e2
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/update_access_functions.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN:                -polly-import-jscop-postfix=transformed -polly-codegen \
+; RUN:                 < %s -S | FileCheck %s
+
+; CHECK-LABEL: polly.stmt.loop1:
+; CHECK-NEXT:   %3 = mul nsw i64 5, %polly.indvar{{[0-9]*}}
+; CHECK-NEXT:   %4 = sub nsw i64 %3, 10
+; CHECK-NEXT:   %polly.access.A = getelementptr double, double* %A, i64 %4
+; CHECK-NEXT:   store double 4.200000e+01, double* %polly.access.A, align 8
+
+; CHECK-LABEL: polly.stmt.loop2:
+; CHECK-NEXT:   %polly.access.A[[Num0:[0-9]*]] = getelementptr double, double* %A, i64 42
+; CHECK-NEXT:   %val_p_scalar_ = load double, double* %polly.access.A[[Num0]], align 8
+
+; CHECK-LABEL: polly.stmt.loop3:
+; CHECK-NEXT:   %val.s2a.reload = load double, double* %val.s2a
+; CHECK-NEXT:   [[REG0:%.*]] = mul nsw i64 13, %polly.indvar{{[0-9]*}}
+; CHECK-NEXT:   [[REG1:%.*]] = add nsw i64 [[REG0]], 5
+; CHECK-NEXT:   %polly.access.A[[Num1:[0-9]*]] = getelementptr double, double* %A, i64 [[REG1]]
+; CHECK-NEXT:   store double %val.s2a.reload, double* %polly.access.A[[Num1]], align 8,
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @update_access_functions(i64 %arg, double* %A) {
+bb3:
+  br label %loop1
+
+loop1:
+  %indvar = phi i64 [ %indvar.next, %loop1 ], [ 1, %bb3 ]
+  %ptr1 = getelementptr inbounds double, double* %A, i64 %indvar
+  store double 42.0, double* %ptr1, align 8
+  %indvar.next = add nuw nsw i64 %indvar, 1
+  %cmp = icmp ne i64 %indvar.next, %arg
+  br i1 %cmp, label %loop1, label %loop2
+
+loop2:
+  %indvar.2 = phi i64 [ %indvar.2.next, %loop2 ], [ 1, %loop1 ]
+  %ptr2 = getelementptr inbounds double, double* %A, i64 %indvar.2
+  %val = load double, double* %ptr2, align 8
+  %indvar.2.next = add nuw nsw i64 %indvar.2, 1
+  %cmp.2 = icmp ne i64 %indvar.2.next, %arg
+  br i1 %cmp.2, label %loop2, label %loop3
+
+loop3:
+  %indvar.3 = phi i64 [ %indvar.3.next, %loop3 ], [ 1, %loop2 ]
+  %ptr3 = getelementptr inbounds double, double* %A, i64 %indvar.3
+  store double %val, double* %ptr3, align 8
+  %indvar.3.next = add nuw nsw i64 %indvar.3, 1
+  %cmp.3 = icmp ne i64 %indvar.3.next, %arg
+  br i1 %cmp.3, label %loop3, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/update_access_functions___%loop1---%exit.jscop b/final/test/Isl/CodeGen/MemAccess/update_access_functions___%loop1---%exit.jscop
new file mode 100644
index 0000000..93bfb7b
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/update_access_functions___%loop1---%exit.jscop
@@ -0,0 +1,47 @@
+{
+   "context" : "[arg] -> {  : -9223372036854775808 <= arg <= 9223372036854775807 }",
+   "name" : "%loop1---%exit",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[arg] -> { Stmt_loop1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[arg] -> { Stmt_loop1[i0] : 0 <= i0 <= -2 + arg }",
+         "name" : "Stmt_loop1",
+         "schedule" : "[arg] -> { Stmt_loop1[i0] -> [0, i0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[arg] -> { Stmt_loop2[i0] -> MemRef_A[1 + i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[arg] -> { Stmt_loop2[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[arg] -> { Stmt_loop2[i0] : 0 <= i0 <= -2 + arg }",
+         "name" : "Stmt_loop2",
+         "schedule" : "[arg] -> { Stmt_loop2[i0] -> [1, i0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[arg] -> { Stmt_loop3[i0] -> MemRef_A[1 + i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[arg] -> { Stmt_loop3[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[arg] -> { Stmt_loop3[i0] : 0 <= i0 <= -2 + arg }",
+         "name" : "Stmt_loop3",
+         "schedule" : "[arg] -> { Stmt_loop3[i0] -> [2, i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/MemAccess/update_access_functions___%loop1---%exit.jscop.transformed b/final/test/Isl/CodeGen/MemAccess/update_access_functions___%loop1---%exit.jscop.transformed
new file mode 100644
index 0000000..6f694c6
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/update_access_functions___%loop1---%exit.jscop.transformed
@@ -0,0 +1,47 @@
+{
+   "context" : "[arg] -> {  : arg >= -9223372036854775808 and arg <= 9223372036854775807 }",
+   "name" : "loop1 => exit",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[arg] -> { Stmt_loop1[i0] -> MemRef_A[5 * i0 - 10]  }"
+            }
+         ],
+         "domain" : "[arg] -> { Stmt_loop1[i0] : i0 >= 0 and i0 <= -2 + arg }",
+         "name" : "Stmt_loop1",
+         "schedule" : "[arg] -> { Stmt_loop1[i0] -> [0, i0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[arg] -> { Stmt_loop2[i0] -> MemRef_A[42] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[arg] -> { Stmt_loop2[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[arg] -> { Stmt_loop2[i0] : i0 >= 0 and i0 <= -2 + arg }",
+         "name" : "Stmt_loop2",
+         "schedule" : "[arg] -> { Stmt_loop2[i0] -> [1, i0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[arg] -> { Stmt_loop3[i0] -> MemRef_A[13 * i0 + 5] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[arg] -> { Stmt_loop3[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[arg] -> { Stmt_loop3[i0] : i0 >= 0 and i0 <= -2 + arg }",
+         "name" : "Stmt_loop3",
+         "schedule" : "[arg] -> { Stmt_loop3[i0] -> [2, i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/alias-metadata.ll b/final/test/Isl/CodeGen/OpenMP/alias-metadata.ll
new file mode 100644
index 0000000..fcb6bd5
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/alias-metadata.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-codegen -polly-parallel -S < %s | FileCheck %s
+;
+;    void foo(float *A, float *B) {
+;      for (long i = 0; i < 1000; i++)
+;        for (long j = 0; j < 1000; j++)
+;          A[i] = B[i];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK: define internal void @foo_polly_subfn
+
+define void @foo(float* %A, float* %B) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb11, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp12, %bb11 ]
+  %exitcond1 = icmp ne i64 %i.0, 1000
+  br i1 %exitcond1, label %bb3, label %bb13
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb8, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp9, %bb8 ]
+  %exitcond = icmp ne i64 %j.0, 1000
+  br i1 %exitcond, label %bb5, label %bb10
+
+bb5:                                              ; preds = %bb4
+  %tmp = getelementptr inbounds float, float* %B, i64 %i.0
+  %tmp7 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp6 = load float, float* %tmp, align 4
+  store float %tmp6, float* %tmp7, align 4
+; CHECK: %tmp6_p_scalar_ = load float, float* %scevgep, align 4, !alias.scope !0, !noalias !2
+; CHECK: store float %tmp6_p_scalar_, float* %scevgep8, align 4, !alias.scope !3, !noalias !4
+  br label %bb8
+
+bb8:                                              ; preds = %bb5
+  %tmp9 = add nsw i64 %j.0, 1
+  br label %bb4
+
+bb10:                                             ; preds = %bb4
+  br label %bb11
+
+bb11:                                             ; preds = %bb10
+  %tmp12 = add nsw i64 %i.0, 1
+  br label %bb2
+
+bb13:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/invariant_base_pointer_preloaded.ll b/final/test/Isl/CodeGen/OpenMP/invariant_base_pointer_preloaded.ll
new file mode 100644
index 0000000..91d956d
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/invariant_base_pointer_preloaded.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -polly-parallel \
+; RUN: -polly-parallel-force -S < %s | FileCheck %s
+;
+; Test to verify that we hand down the preloaded A[0] to the OpenMP subfunction.
+;
+;    void f(float *A) {
+;      for (int i = 1; i < 1000; i++)
+;        A[i] += A[0];
+;    }
+;
+; CHECK:  %polly.subfn.storeaddr.polly.access.A.load = getelementptr inbounds { float, float* }, { float, float* }* %polly.par.userContext, i32 0
+; CHECK:  store float %polly.access.A.load, float* %polly.subfn.storeaddr.polly.access.A.load
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(float* nocapture %A) {
+entry:
+  br label %for.body
+
+for.cond.cleanup:                                 ; preds = %for.body
+  ret void
+
+for.body:                                         ; preds = %for.body, %entry
+  %indvars.iv = phi i64 [ 1, %entry ], [ %indvars.iv.next, %for.body ]
+  %tmp = load float, float* %A, align 4
+  %arrayidx1 = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp1 = load float, float* %arrayidx1, align 4
+  %add = fadd float %tmp, %tmp1
+  store float %add, float* %arrayidx1, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 1000
+  br i1 %exitcond, label %for.cond.cleanup, label %for.body
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/invariant_base_pointer_preloaded_different_bb.ll b/final/test/Isl/CodeGen/OpenMP/invariant_base_pointer_preloaded_different_bb.ll
new file mode 100644
index 0000000..aabaad4
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/invariant_base_pointer_preloaded_different_bb.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -polly-parallel \
+; RUN: -polly-parallel-force -S < %s | FileCheck %s
+;
+; Test to verify that we hand down the preloaded A[0] to the OpenMP subfunction.
+;
+;    void f(float *A) {
+;      for (int i = 1; i < 1000; i++)
+;        A[i] += /* split bb */ A[0];
+;    }
+;                                           A[0]  tmp (unused)      A
+; CHECK: %polly.par.userContext = alloca { float,    float*,     float* }
+;
+; CHECK:  %polly.subfn.storeaddr.polly.access.A.load = getelementptr inbounds
+; CHECK:  store float %polly.access.A.load, float* %polly.subfn.storeaddr.polly.access.A.load
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(float* nocapture %A) {
+entry:
+  br label %for.body
+
+for.cond.cleanup:                                 ; preds = %for.body
+  ret void
+
+for.body:                                         ; preds = %for.body, %entry
+  %indvars.iv = phi i64 [ 1, %entry ], [ %indvars.iv.next, %for.body.split ]
+  %tmp = load float, float* %A, align 4
+  br label %for.body.split
+
+for.body.split:
+  %arrayidx1 = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp1 = load float, float* %arrayidx1, align 4
+  %add = fadd float %tmp, %tmp1
+  store float %add, float* %arrayidx1, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 1000
+  br i1 %exitcond, label %for.cond.cleanup, label %for.body
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/invariant_base_pointer_preloaded_pass_only_needed.ll b/final/test/Isl/CodeGen/OpenMP/invariant_base_pointer_preloaded_pass_only_needed.ll
new file mode 100644
index 0000000..b668c84
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/invariant_base_pointer_preloaded_pass_only_needed.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -polly-parallel \
+; RUN: -polly-parallel-force -S < %s | FileCheck %s
+;
+; Test to verify that we hand down the preloaded A[0] to the OpenMP subfunction but
+; not B[0] as it is not needed
+;
+;    void f(float *A, float *B) {
+;      // Not parallel
+;      for (int i = 1; i < 1000; i++) {
+;        B[i] = B[i+1] + B[0];
+;        // Parallel
+;        for (int j = 1; j < 1000; j++)
+;          A[j] += A[0];
+;      }
+;    }
+;
+;                                           i    A[0]    A
+; CHECK: %polly.par.userContext = alloca { i64, float, float* }
+;
+; CHECK:  %polly.access.B.load =
+; CHECK:  %polly.subfn.storeaddr.polly.access.A.load = getelementptr inbounds
+; CHECK:  store float %polly.access.A.load, float* %polly.subfn.storeaddr.polly.access.A.load
+; CHECK-NOT:  store float %polly.access.B.load, float* %polly.subfn.storeaddr.polly.access.B.load
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(float* %A, float* %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.9, %entry
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc.9 ], [ 1, %entry ]
+  %exitcond3 = icmp ne i64 %indvars.iv1, 1000
+  br i1 %exitcond3, label %for.body, label %for.end.11
+
+for.body:                                         ; preds = %for.cond
+  %tmp = load float, float* %B, align 4
+  %arrayidx1 = getelementptr inbounds float, float* %B, i64 %indvars.iv1
+  %iv.add = add nsw i64 %indvars.iv1, 1
+  %arrayidx2 = getelementptr inbounds float, float* %B, i64 %iv.add
+  %tmp4 = load float, float* %arrayidx2, align 4
+  %add = fadd float %tmp4, %tmp
+  store float %add, float* %arrayidx1, align 4
+  br label %for.cond.2
+
+for.cond.2:                                       ; preds = %for.inc, %for.body
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 1, %for.body ]
+  %exitcond = icmp ne i64 %indvars.iv, 1000
+  br i1 %exitcond, label %for.body.4, label %for.end
+
+for.body.4:                                       ; preds = %for.cond.2
+  %tmp5 = load float, float* %A, align 4
+  %arrayidx7 = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp6 = load float, float* %arrayidx7, align 4
+  %add8 = fadd float %tmp6, %tmp5
+  store float %add8, float* %arrayidx7, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body.4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond.2
+
+for.end:                                          ; preds = %for.cond.2
+  br label %for.inc.9
+
+for.inc.9:                                        ; preds = %for.end
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %for.cond
+
+for.end.11:                                       ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/invariant_base_pointers_preloaded.ll b/final/test/Isl/CodeGen/OpenMP/invariant_base_pointers_preloaded.ll
new file mode 100644
index 0000000..6dcdf9e
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/invariant_base_pointers_preloaded.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -polly-parallel \
+; RUN: -polly-parallel-force -S < %s | FileCheck %s
+;
+; Test to verify that we hand down the preloaded A[0] to the OpenMP subfunction.
+;
+;    void f(float *A) {
+;      for (int i = 1; i < 1000; i++)
+;        A[i] += A[0] + A[0];
+;    }
+;
+; CHECK:  %polly.subfn.storeaddr.polly.access.A.load = getelementptr inbounds 
+; CHECK:  store float %polly.access.A.load, float* %polly.subfn.storeaddr.polly.access.A.load
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(float* nocapture %A) {
+entry:
+  br label %for.body
+
+for.cond.cleanup:                                 ; preds = %for.body
+  ret void
+
+for.body:                                         ; preds = %for.body, %entry
+  %indvars.iv = phi i64 [ 1, %entry ], [ %indvars.iv.next, %for.body ]
+  %tmp = load float, float* %A, align 4
+  %tmp2 = load float, float* %A, align 4
+  %tmpadd = fadd float %tmp, %tmp2
+  %arrayidx1 = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp1 = load float, float* %arrayidx1, align 4
+  %add = fadd float %tmp2, %tmp1
+  store float %add, float* %arrayidx1, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 1000
+  br i1 %exitcond, label %for.cond.cleanup, label %for.body
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-iv.ll b/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-iv.ll
new file mode 100644
index 0000000..54ccee8
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-iv.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-codegen -S -verify-dom-info < %s | FileCheck %s -check-prefix=IR
+
+; This code has failed the scev based code generation as the scev in the scop
+; contains an AddRecExpr of an outer loop. When generating code, we did not
+; properly forward the value of this expression to the subfunction.
+
+; AST: #pragma omp parallel for
+; AST: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; AST:  Stmt_for_j(c0);
+
+; IR: @single_parallel_loop_polly_subfn
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float] zeroinitializer, align 16
+
+define void @single_parallel_loop() nounwind {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc], [ 0, %entry ]
+  br label %for.j
+
+for.j:
+  %indvar.j = phi i64 [ %indvar.j.next, %for.j], [ 0, %for.i ]
+  %sum = add i64 %indvar.j, %indvar.i
+  %scevgep = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %sum
+  store float 0.0, float *%scevgep
+  %indvar.j.next = add i64 %indvar.j, 1
+  %exitcond.j = icmp slt i64 %indvar.j.next, 1024
+  br i1 %exitcond.j, label %for.j, label %for.i.inc
+
+for.i.inc:
+  fence seq_cst
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, 1024
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-values-2.ll b/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-values-2.ll
new file mode 100644
index 0000000..124f05c
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-values-2.ll
@@ -0,0 +1,31 @@
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-codegen -S -verify-dom-info < %s | FileCheck %s -check-prefix=IR
+
+; AST: #pragma simd
+; AST: #pragma omp parallel for
+; AST: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; AST:   Stmt_for_i(c0);
+
+; IR: getelementptr inbounds { [1024 x double]* }, { [1024 x double]* }* %polly.par.userContext, i32 0, i32 0
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @kernel_trmm([1024 x double]* %B) {
+entry:
+  br label %for.cond1.preheader
+
+for.cond1.preheader:
+  %extern = add i64 1, 0
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i ], [ 0, %for.cond1.preheader ]
+  %getelementptr = getelementptr [1024 x double], [1024 x double]* %B, i64 %extern, i64 %indvar.i
+  store double 0.000000e+00, double* %getelementptr
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, 1024
+  br i1 %exitcond.i, label %for.i, label %end
+
+end:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-values-3.ll b/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-values-3.ll
new file mode 100644
index 0000000..d64855a
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-values-3.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -basicaa -polly-parallel -polly-parallel-force -polly-invariant-load-hoisting=true -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -basicaa -polly-parallel -polly-parallel-force -polly-invariant-load-hoisting=true -polly-codegen -S -verify-dom-info < %s | FileCheck %s -check-prefix=IR
+
+; The interesting part of this test case is the instruction:
+;   %tmp = bitcast i8* %call to i64**
+; which is not part of the scop. In the SCEV based code generation not '%tmp',
+; but %call is a parameter of the SCoP and we need to make sure its value is
+; properly forwarded to the subfunction.
+
+; AST: #pragma omp parallel for
+; AST: for (int c0 = 0; c0 < cols; c0 += 1)
+; AST:   Stmt_for_body(c0);
+; AST: if (cols <= 0)
+; AST:   Stmt_for_body(0);
+
+; IR: @foo_polly_subfn
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %cols, i8* noalias %call) {
+entry:
+  %tmp = bitcast i8* %call to i64**
+  br label %for.body
+
+for.body:
+  %indvar = phi i64 [ %indvar.next, %for.body ], [ 0, %entry ]
+  %arrayidx = getelementptr inbounds i64*, i64** %tmp, i64 0
+  %tmp1 = load i64*, i64** %arrayidx, align 8
+  %arrayidx.2 = getelementptr inbounds i64, i64* %tmp1, i64 %indvar
+  store i64 1, i64* %arrayidx.2, align 4
+  %indvar.next = add nsw i64 %indvar, 1
+  %cmp = icmp slt i64 %indvar.next, %cols
+  br i1 %cmp, label %for.body, label %end
+
+end:
+  ret void
+}
+
+; Another variation of this test case, now with even more of the index
+; expression defined outside of the scop.
+
+; AST: #pragma omp parallel for
+; AST: for (int c0 = 0; c0 < cols; c0 += 1)
+; AST:   Stmt_for_body(c0);
+; AST: if (cols <= 0)
+; AST:   Stmt_for_body(0);
+
+; IR: @bar_polly_subfn
+
+define void @bar(i64 %cols, i8* noalias %call) {
+entry:
+  %tmp = bitcast i8* %call to i64**
+  %arrayidx = getelementptr inbounds i64*, i64** %tmp, i64 0
+  br label %for.body
+
+for.body:
+  %indvar = phi i64 [ %indvar.next, %for.body ], [ 0, %entry ]
+  %tmp1 = load i64*, i64** %arrayidx, align 8
+  %arrayidx.2 = getelementptr inbounds i64, i64* %tmp1, i64 %indvar
+  store i64 1, i64* %arrayidx.2, align 4
+  %indvar.next = add nsw i64 %indvar, 1
+  %cmp = icmp slt i64 %indvar.next, %cols
+  br i1 %cmp, label %for.body, label %end
+
+end:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-values.ll b/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-values.ll
new file mode 100644
index 0000000..9bbc125
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-values.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-codegen -S < %s | FileCheck %s -check-prefix=IR
+
+; Make sure we correctly forward the reference to 'A' to the OpenMP subfunction.
+;
+; void loop_references_outer_ids(float *A) {
+;   for (long i = 0; i < 100; i++)
+;     A[i] = i;
+; }
+
+
+; AST: #pragma simd
+; AST: #pragma omp parallel for
+; AST: for (int c0 = 0; c0 <= 99; c0 += 1)
+; AST:   Stmt_for_body(c0);
+
+; IR-LABEL: polly.parallel.for:
+; IR-NEXT:  %polly.subfn.storeaddr.A = getelementptr inbounds { float* }, { float* }* %polly.par.userContext, i32 0, i32 0
+; IR-NEXT:  store float* %A, float** %polly.subfn.storeaddr.A
+; IR-NEXT:  %polly.par.userContext1 = bitcast { float* }* %polly.par.userContext to i8*
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @loop_references_outer_ids(float* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %conv = sitofp i64 %i.0 to float
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  store float %conv, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/loop-bounds-reference-outer-ids.ll b/final/test/Isl/CodeGen/OpenMP/loop-bounds-reference-outer-ids.ll
new file mode 100644
index 0000000..f72e893
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/loop-bounds-reference-outer-ids.ll
@@ -0,0 +1,99 @@
+; RUN: opt %loadPolly -polly-parallel -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-parallel -polly-codegen -S < %s | FileCheck %s -check-prefix=IR
+;
+; float A[100];
+;
+; void loop_references_outer_ids(long n) {
+;   for (long i = 0; i < 100; i++)
+;     for (long j = 0; j < 100; j++)
+;       for (long k = 0; k < n + i; k++)
+;         A[j] += i + j + k;
+; }
+
+; In this test case we verify that the j-loop is generated as OpenMP parallel
+; loop and that the values of 'i' and 'n', needed in the loop bounds of the
+; k-loop, are correctly passed to the subfunction.
+
+; AST: #pragma minimal dependence distance: 1
+; AST: for (int c0 = max(0, -n + 1); c0 <= 99; c0 += 1)
+; AST:   #pragma omp parallel for
+; AST:   for (int c1 = 0; c1 <= 99; c1 += 1)
+; AST:     #pragma minimal dependence distance: 1
+; AST:     for (int c2 = 0; c2 < n + c0; c2 += 1)
+; AST:       Stmt_for_body6(c0, c1, c2);
+
+; IR:      %polly.par.userContext = alloca { i64, i64 }
+; IR: %[[R1:[0-9a-z.]+]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* %polly.par.userContext, i32 0, i32 0
+; IR-NEXT: store i64 %n, i64* %[[R1]]
+; IR-NEXT: %[[R2:[0-9a-z.]+]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* %polly.par.userContext, i32 0, i32 1
+; IR-NEXT: store i64 %polly.indvar, i64* %[[R2]]
+; IR-NEXT: %polly.par.userContext1 = bitcast { i64, i64 }* %polly.par.userContext to i8*
+
+; IR-LABEL: @loop_references_outer_ids_polly_subfn(i8* %polly.par.userContext)
+; IR:       %polly.par.userContext1 = bitcast i8* %polly.par.userContext to { i64, i64 }*
+; IR-NEXT:  %[[R3:[0-9a-z.]+]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* %polly.par.userContext1, i32 0, i32 0
+; IR-NEXT:  %[[R4:[0-9a-z.]+]] = load i64, i64* %[[R3]]
+; IR-NEXT:  %[[R5:[0-9a-z.]+]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* %polly.par.userContext1, i32 0, i32 1
+; IR-NEXT:  %[[R6:[0-9a-z.]+]] = load i64, i64* %[[R5]]
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@A = common global [100 x float] zeroinitializer, align 16
+
+define void @loop_references_outer_ids(i64 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc03, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc04, %for.inc03 ]
+  %exitcond1 = icmp ne i64 %i.0, 100
+  br i1 %exitcond1, label %for.body, label %for.end15
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc00, %for.body
+  %j.0 = phi i64 [ 0, %for.body ], [ %inc01, %for.inc00 ]
+  %exitcond = icmp ne i64 %j.0, 100
+  br i1 %exitcond, label %for.body3, label %for.end12
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc, %for.body3
+  %k.0 = phi i64 [ 0, %for.body3 ], [ %inc, %for.inc ]
+  %add = add nsw i64 %i.0, %n
+  %cmp5 = icmp slt i64 %k.0, %add
+  br i1 %cmp5, label %for.body6, label %for.end
+
+for.body6:                                        ; preds = %for.cond4
+  %add7 = add nsw i64 %i.0, %j.0
+  %add8 = add nsw i64 %add7, %k.0
+  %conv = sitofp i64 %add8 to float
+  %arrayidx = getelementptr inbounds [100 x float], [100 x float]* @A, i64 0, i64 %j.0
+  %tmp = load float, float* %arrayidx, align 4
+  %add9 = fadd float %tmp, %conv
+  store float %add9, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body6
+  %inc = add nsw i64 %k.0, 1
+  br label %for.cond4
+
+for.end:                                          ; preds = %for.cond4
+  br label %for.inc00
+
+for.inc00:                                        ; preds = %for.end
+  %inc01 = add nsw i64 %j.0, 1
+  br label %for.cond1
+
+for.end12:                                        ; preds = %for.cond1
+  br label %for.inc03
+
+for.inc03:                                        ; preds = %for.end12
+  %inc04 = add nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end15:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/mapped-phi-access.ll b/final/test/Isl/CodeGen/OpenMP/mapped-phi-access.ll
new file mode 100644
index 0000000..5968840
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/mapped-phi-access.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-parallel -polly-delicm -polly-codegen -S < %s | FileCheck %s
+;
+; Verify that -polly-parallel can handle mapped scalar MemoryAccesses.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @main() local_unnamed_addr #0 {
+entry:
+  %0 = load i8*, i8** undef, align 8, !tbaa !1
+  %1 = load i8*, i8** undef, align 8, !tbaa !1
+  %arraydecay16 = bitcast i8* %1 to double*
+  %arraydecay20 = bitcast i8* %0 to [4000 x double]*
+  br label %for.body65.i226
+
+for.body65.i226:                                  ; preds = %for.inc85.i238, %entry
+  %indvars.iv8.i223 = phi i64 [ 0, %entry ], [ %indvars.iv.next9.i236, %for.inc85.i238 ]
+  %arrayidx70.i224 = getelementptr inbounds double, double* %arraydecay16, i64 %indvars.iv8.i223
+  br label %for.body68.i235
+
+for.body68.i235:                                  ; preds = %for.body68.i235, %for.body65.i226
+  %2 = phi double [ undef, %for.body65.i226 ], [ undef, %for.body68.i235 ]
+  %indvars.iv.i227 = phi i64 [ 0, %for.body65.i226 ], [ %indvars.iv.next.i233, %for.body68.i235 ]
+  %arrayidx74.i228 = getelementptr inbounds [4000 x double], [4000 x double]* %arraydecay20, i64 %indvars.iv8.i223, i64 %indvars.iv.i227
+  %3 = load double, double* %arrayidx74.i228, align 8, !tbaa !5
+  store double undef, double* %arrayidx70.i224, align 8, !tbaa !5
+  %indvars.iv.next.i233 = add nuw nsw i64 %indvars.iv.i227, 1
+  %exitcond.i234 = icmp eq i64 %indvars.iv.next.i233, 4000
+  br i1 %exitcond.i234, label %for.inc85.i238, label %for.body68.i235
+
+for.inc85.i238:                                   ; preds = %for.body68.i235
+  %indvars.iv.next9.i236 = add nuw nsw i64 %indvars.iv8.i223, 1
+  %exitcond10.i237 = icmp eq i64 %indvars.iv.next9.i236, 4000
+  br i1 %exitcond10.i237, label %kernel_gemver_StrictFP.exit, label %for.body65.i226
+
+kernel_gemver_StrictFP.exit:                      ; preds = %for.inc85.i238
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 6.0.0 "}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"any pointer", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!6, !6, i64 0}
+!6 = !{!"double", !3, i64 0}
+
+
+; CHECK-LABEL: define internal void @main_polly_subfn(i8* %polly.par.userContext)
+;
+; CHECK:       polly.stmt.for.body65.i226:
+; CHECK-NEXT:    %polly.access.cast.polly.subfunc.arg.[[R0:[0-9]*]] = bitcast i8* %polly.subfunc.arg.{{[0-9]*}} to double*
+; CHECK-NEXT:    %polly.access.polly.subfunc.arg.[[R1:[0-9]*]] = getelementptr double, double* %polly.access.cast.polly.subfunc.arg.[[R0]], i64 %polly.indvar
+; CHECK-NEXT:    store double undef, double* %polly.access.polly.subfunc.arg.[[R1]]
diff --git a/final/test/Isl/CodeGen/OpenMP/new_multidim_access.ll b/final/test/Isl/CodeGen/OpenMP/new_multidim_access.ll
new file mode 100644
index 0000000..02dce82
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/new_multidim_access.ll
@@ -0,0 +1,77 @@
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN:                -analyze < %s | FileCheck %s
+
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN:                -polly-codegen -S < %s \
+; RUN:                -polly-parallel \
+; RUN:                | FileCheck %s -check-prefix=IR
+
+;    void new_multidim_access(long n, long m, float A[][m]) {
+;      for (long i = 0; i < n; i++)
+;        for (long j = 0; j < 100; j++)
+;          A[i][2 * j] += i + j;
+;    }
+
+; CHECK:  ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:         [n, m] -> { Stmt_bb4[i0, i1] -> MemRef_A[i0, 2i1] };
+; CHECK:    new: [n, m] -> { Stmt_bb4[i0, i1] -> MemRef_A[i0, 13 + i1] };
+; CHECK:  MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:         [n, m] -> { Stmt_bb4[i0, i1] -> MemRef_A[i0, 2i1] };
+; CHECK:    new: [n, m] -> { Stmt_bb4[i0, i1] -> MemRef_A[i0, 43 + i1] };
+
+; IR: %polly.access.mul.polly.subfunc.arg.A = mul nsw i64 %polly.indvar, %polly.subfunc.arg.m
+; IR: %6 = add nsw i64 %polly.indvar5, 13
+; IR: %polly.access.add.polly.subfunc.arg.A = add nsw i64 %polly.access.mul.polly.subfunc.arg.A, %6
+; IR: %polly.access.polly.subfunc.arg.A = getelementptr float, float* %polly.subfunc.arg.A, i64 %polly.access.add.polly.subfunc.arg.A
+; IR: %tmp10_p_scalar_ = load float, float* %polly.access.polly.subfunc.arg.A, align 4, !alias.scope !0, !noalias !2, !llvm.mem.parallel_loop_access !3
+
+; IR: %polly.access.mul.polly.subfunc.arg.A8 = mul nsw i64 %polly.indvar, %polly.subfunc.arg.m
+; IR: %7 = add nsw i64 %polly.indvar5, 43
+; IR: %polly.access.add.polly.subfunc.arg.A9 = add nsw i64 %polly.access.mul.polly.subfunc.arg.A8, %7
+; IR: %polly.access.polly.subfunc.arg.A10 = getelementptr float, float* %polly.subfunc.arg.A, i64 %polly.access.add.polly.subfunc.arg.A9
+; IR: store float %p_tmp11, float* %polly.access.polly.subfunc.arg.A10, align 4, !alias.scope !0, !noalias !2, !llvm.mem.parallel_
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @new_multidim_access(i64 %n, i64 %m, float* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb15, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp16, %bb15 ]
+  %tmp = icmp slt i64 %i.0, %n
+  br i1 %tmp, label %bb2, label %bb17
+
+bb2:                                              ; preds = %bb1
+  br label %bb3
+
+bb3:                                              ; preds = %bb12, %bb2
+  %j.0 = phi i64 [ 0, %bb2 ], [ %tmp13, %bb12 ]
+  %exitcond = icmp ne i64 %j.0, 100
+  br i1 %exitcond, label %bb4, label %bb14
+
+bb4:                                              ; preds = %bb3
+  %tmp5 = add nsw i64 %i.0, %j.0
+  %tmp6 = sitofp i64 %tmp5 to float
+  %tmp7 = shl nsw i64 %j.0, 1
+  %tmp8 = mul nsw i64 %i.0, %m
+  %.sum = add i64 %tmp8, %tmp7
+  %tmp9 = getelementptr inbounds float, float* %A, i64 %.sum
+  %tmp10 = load float, float* %tmp9, align 4
+  %tmp11 = fadd float %tmp10, %tmp6
+  store float %tmp11, float* %tmp9, align 4
+  br label %bb12
+
+bb12:                                             ; preds = %bb4
+  %tmp13 = add nsw i64 %j.0, 1
+  br label %bb3
+
+bb14:                                             ; preds = %bb3
+  br label %bb15
+
+bb15:                                             ; preds = %bb14
+  %tmp16 = add nsw i64 %i.0, 1
+  br label %bb1
+
+bb17:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/new_multidim_access___%bb1---%bb17.jscop b/final/test/Isl/CodeGen/OpenMP/new_multidim_access___%bb1---%bb17.jscop
new file mode 100644
index 0000000..5ef5c7c
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/new_multidim_access___%bb1---%bb17.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "[n, m] -> {  : n <= 9223372036854775807 and n >= -9223372036854775808 and m <= 9223372036854775807 and m >= -9223372036854775808 }",
+   "name" : "bb1 => bb17",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n, m] -> { Stmt_bb4[i0, i1] -> MemRef_A[i0, i1 + 13] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n, m] -> { Stmt_bb4[i0, i1] -> MemRef_A[i0, i1 + 43] }"
+            }
+         ],
+         "domain" : "[n, m] -> { Stmt_bb4[i0, i1] : i0 >= 0 and n >= 1 and i0 <= -1 + n and i1 >= 0 and i1 <= 99 }",
+         "name" : "Stmt_bb4",
+         "schedule" : "[n, m] -> { Stmt_bb4[i0, i1] -> [i0, i1] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/recomputed-srem.ll b/final/test/Isl/CodeGen/OpenMP/recomputed-srem.ll
new file mode 100644
index 0000000..c05830c
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/recomputed-srem.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-codegen -polly-parallel \
+; RUN: -polly-parallel-force -S < %s | FileCheck %s
+;
+; Test to verify that we pass %rem96 to the parallel subfunction.
+;
+; CHECK:       %[[R:[0-9]*]] = getelementptr inbounds { i32, i32, i64, float*, float*, i32 }, { i32, i32, i64, float*, float*, i32 }* %polly.par.userContext1, i32 0, i32 5
+; CHECK-NEXT:  %polly.subfunc.arg.rem96 = load i32, i32* %[[R]]
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @dmxpy(i32 %n1, float* %y, i32 %n2, float* %x) #0 {
+entry:
+  %rem96 = srem i32 %n2, 16
+  %0 = sext i32 %rem96 to i64
+  %1 = add i64 %0, 15
+  br label %for.cond195.preheader
+
+for.cond195.preheader:                            ; preds = %for.inc363, %entry
+  %indvars.iv262 = phi i64 [ %1, %entry ], [ %indvars.iv.next263, %for.inc363 ]
+  %j.0236 = phi i32 [ 0, %entry ], [ %add364, %for.inc363 ]
+  br label %for.body197
+
+for.body197:                                      ; preds = %for.body197, %for.cond195.preheader
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.body197 ], [ 0, %for.cond195.preheader ]
+  %arrayidx199 = getelementptr inbounds float, float* %y, i64 %indvars.iv
+  %2 = add nsw i64 %indvars.iv262, -6
+  %arrayidx292 = getelementptr inbounds float, float* %x, i64 %2
+  %3 = load float, float* %arrayidx292, align 4
+  store float undef, float* %arrayidx199, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %lftr.wideiv = trunc i64 %indvars.iv.next to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, %n1
+  br i1 %exitcond, label %for.body197, label %for.inc363
+
+for.inc363:                                       ; preds = %for.body197
+  %add364 = add nsw i32 %j.0236, 16
+  %cmp193 = icmp slt i32 %add364, %n2
+  %indvars.iv.next263 = add i64 %indvars.iv262, 16
+  br i1 %cmp193, label %for.cond195.preheader, label %for.end365
+
+for.end365:                                       ; preds = %for.inc363
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/reference-argument-from-non-affine-region.ll b/final/test/Isl/CodeGen/OpenMP/reference-argument-from-non-affine-region.ll
new file mode 100644
index 0000000..ce30395
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/reference-argument-from-non-affine-region.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-parallel \
+; RUN: -polly-parallel-force -polly-codegen -S -verify-dom-info < %s \
+; RUN: | FileCheck %s -check-prefix=IR
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; IR: @GOMP_parallel_loop_runtime_start
+
+@longLimit = external global [9 x [23 x i32]], align 16
+@shortLimit = external global [9 x [14 x i32]], align 16
+
+define void @init_layer3(i32 %down_sample_sblimit) #0 {
+entry:
+  br label %for.cond.463.preheader
+
+for.cond.463.preheader:                           ; preds = %entry
+  br label %for.cond.499.preheader
+
+for.cond.533.preheader:                           ; preds = %for.inc.530
+  ret void
+
+for.cond.499.preheader:                           ; preds = %for.inc.530, %for.cond.463.preheader
+  %indvars.iv140 = phi i64 [ 0, %for.cond.463.preheader ], [ %indvars.iv.next141, %for.inc.530 ]
+  %arrayidx483 = getelementptr inbounds [9 x [23 x i32]], [9 x [23 x i32]]* @longLimit, i64 0, i64 %indvars.iv140, i64 0
+  store i32 undef, i32* %arrayidx483, align 4, !tbaa !1
+  %arrayidx487 = getelementptr inbounds [9 x [23 x i32]], [9 x [23 x i32]]* @longLimit, i64 0, i64 %indvars.iv140, i64 0
+  %tmp = load i32, i32* %arrayidx487, align 4, !tbaa !1
+  %indvars.iv.next135 = add nuw nsw i64 0, 1
+  br label %for.body.502
+
+for.body.502:                                     ; preds = %for.inc.527, %for.cond.499.preheader
+  %indvars.iv137 = phi i64 [ 0, %for.cond.499.preheader ], [ %indvars.iv.next138, %for.inc.527 ]
+  %arrayidx518 = getelementptr inbounds [9 x [14 x i32]], [9 x [14 x i32]]* @shortLimit, i64 0, i64 %indvars.iv140, i64 %indvars.iv137
+  %tmp1 = load i32, i32* %arrayidx518, align 4, !tbaa !1
+  %cmp519 = icmp sgt i32 %tmp1, %down_sample_sblimit
+  br i1 %cmp519, label %if.then.521, label %for.inc.527
+
+if.then.521:                                      ; preds = %for.body.502
+  br label %for.inc.527
+
+for.inc.527:                                      ; preds = %if.then.521, %for.body.502
+  %indvars.iv.next138 = add nuw nsw i64 %indvars.iv137, 1
+  %exitcond139 = icmp ne i64 %indvars.iv.next138, 14
+  br i1 %exitcond139, label %for.body.502, label %for.inc.530
+
+for.inc.530:                                      ; preds = %for.inc.527
+  %indvars.iv.next141 = add nuw nsw i64 %indvars.iv140, 1
+  %exitcond142 = icmp ne i64 %indvars.iv.next141, 9
+  br i1 %exitcond142, label %for.cond.499.preheader, label %for.cond.533.preheader
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 246359)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"int", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/Isl/CodeGen/OpenMP/reference-other-bb.ll b/final/test/Isl/CodeGen/OpenMP/reference-other-bb.ll
new file mode 100644
index 0000000..b5370d8
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/reference-other-bb.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-codegen -S -verify-dom-info < %s | FileCheck %s -check-prefix=IR
+
+; IR: @foo_polly_subfn
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i32 %sendcount, i8* %recvbuf) {
+entry:
+  br label %sw.bb3
+
+sw.bb3:
+  %tmp = bitcast i8* %recvbuf to double*
+  %cmp75 = icmp sgt i32 %sendcount, 0
+  br i1 %cmp75, label %for.body, label %end
+
+for.body:
+  %i.16 = phi i32 [ %inc04, %for.body ], [ 0, %sw.bb3 ]
+  %idxprom11 = sext i32 %i.16 to i64
+  %arrayidx12 = getelementptr inbounds double, double* %tmp, i64 %idxprom11
+  store double 1.0, double* %arrayidx12, align 8
+  %inc04 = add nsw i32 %i.16, 1
+  %cmp7 = icmp slt i32 %inc04, %sendcount
+  br i1 %cmp7, label %for.body, label %end
+
+end:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/reference-preceeding-loop.ll b/final/test/Isl/CodeGen/OpenMP/reference-preceeding-loop.ll
new file mode 100644
index 0000000..939b115
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/reference-preceeding-loop.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-codegen -S -verify-dom-info < %s | FileCheck %s -check-prefix=IR
+
+
+; - Test the case where scalar evolution references a loop that is outside
+;   of the scop, but does not contain the scop.
+
+; AST:         {
+; AST-NEXT:    #pragma simd
+; AST-NEXT:    #pragma omp parallel for
+; AST-NEXT:    for (int c0 = 0; c0 < -p_0 + symbol; c0 += 1)
+; AST-NEXT:      Stmt_while_body(c0);
+; AST-NEXT:    if (p_0 >= symbol)
+; AST-NEXT:      Stmt_while_body(0);
+; AST-NEXT:    }
+
+; IR: @update_model_polly_subfn
+; IR-NOT: @update_model_polly_subfn_1
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@cum_freq = external global [258 x i64], align 16
+
+define void @update_model(i64 %symbol) {
+entry:
+  br label %for.one
+
+for.one:
+  %i.1 = phi i64 [ %dec07, %for.one ], [ %symbol, %entry ]
+  %dec07 = add nsw i64 %i.1, -1
+  br i1 undef, label %for.one, label %while.body
+
+while.body:
+  %indvar = phi i64 [ %sub42, %while.body ], [ %i.1, %for.one ]
+  %sub42 = add nsw i64 %indvar, -1
+  %arrayidx44 = getelementptr inbounds [258 x i64], [258 x i64]* @cum_freq, i64 0, i64 %sub42
+  store i64 1, i64* %arrayidx44, align 4
+  %cmp40 = icmp sgt i64 %sub42, 0
+  br i1 %cmp40, label %while.body, label %while.end
+
+while.end:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/reference_latest.ll b/final/test/Isl/CodeGen/OpenMP/reference_latest.ll
new file mode 100644
index 0000000..4622fbf
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/reference_latest.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-delicm -polly-simplify -polly-parallel -polly-codegen -S < %s | FileCheck %s
+;
+; Test that parallel codegen handles scalars mapped to other arrays.
+; After mapping "store double %add10" references the array "MemRef2".
+; Its base pointer therefore needs to be made available in the subfunction.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @reference_latest(float* nocapture readonly %data, i32 %n, i32 %m) {
+entry:
+  %0 = alloca double, i64 undef, align 16
+  %conv1 = sext i32 %m to i64
+  br label %while.body
+
+while.body:
+  %indvars.iv211 = phi i64 [ %conv1, %entry ], [ %indvars.iv.next212, %for.end ]
+  br label %for.body
+
+for.body:
+  %indvars.iv207 = phi i64 [ %indvars.iv211, %while.body ], [ %indvars.iv.next208, %for.body ]
+  %arrayidx7 = getelementptr inbounds float, float* %data, i64 0
+  %1 = load float, float* %arrayidx7, align 4
+  %add10 = fadd double undef, undef
+  %indvars.iv.next208 = add nsw i64 %indvars.iv207, 1
+  %lftr.wideiv = trunc i64 %indvars.iv.next208 to i32
+  %exitcond210 = icmp eq i32 %lftr.wideiv, %n
+  br i1 %exitcond210, label %for.end, label %for.body
+
+for.end:
+  %arrayidx12 = getelementptr inbounds double, double* %0, i64 %indvars.iv211
+  store double %add10, double* %arrayidx12, align 8
+  %indvars.iv.next212 = add nsw i64 %indvars.iv211, -1
+  %2 = trunc i64 %indvars.iv211 to i32
+  %tobool = icmp eq i32 %2, 0
+  br i1 %tobool, label %while.end, label %while.body
+
+while.end:
+  ret void
+}
+
+; CHECK-LABEL: define internal void @reference_latest_polly_subfn(i8* %polly.par.userContext)
+
+; CHECK:      %polly.access.polly.subfunc.arg. = getelementptr double, double* %polly.subfunc.arg., i64 %{{[0-9]+}}
+; CHECK-NEXT: store double %p_add{{[0-9]*}}, double* %polly.access.polly.subfunc.arg.
diff --git a/final/test/Isl/CodeGen/OpenMP/single_loop.ll b/final/test/Isl/CodeGen/OpenMP/single_loop.ll
new file mode 100644
index 0000000..6aeda25
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/single_loop.ll
@@ -0,0 +1,110 @@
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-codegen -S -verify-dom-info < %s | FileCheck %s -check-prefix=IR
+
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-import-jscop -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST-STRIDE4
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-import-jscop -polly-codegen -S < %s | FileCheck %s -check-prefix=IR-STRIDE4
+
+; This extensive test case tests the creation of the full set of OpenMP calls
+; as well as the subfunction creation using a trivial loop as example.
+
+; #define N 1024
+; float A[N];
+;
+; void single_parallel_loop(void) {
+;   for (long i = 0; i < N; i++)
+;     A[i] = 1;
+; }
+
+; AST: #pragma simd
+; AST: #pragma omp parallel for
+; AST: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; AST:   Stmt_S(c0);
+
+; AST-STRIDE4: #pragma omp parallel for
+; AST-STRIDE4: for (int c0 = 0; c0 <= 1023; c0 += 4)
+; AST-STRIDE4:   #pragma simd
+; AST-STRIDE4:   for (int c1 = c0; c1 <= c0 + 3; c1 += 1)
+; AST-STRIDE4:     Stmt_S(c1);
+
+; IR-LABEL: single_parallel_loop()
+; IR-NEXT: entry
+; IR-NEXT:   %polly.par.userContext = alloca
+
+; IR-LABEL: polly.parallel.for:
+; IR-NEXT:   %polly.par.userContext1 = bitcast {}* %polly.par.userContext to i8*
+; IR-NEXT:   call void @GOMP_parallel_loop_runtime_start(void (i8*)* @single_parallel_loop_polly_subfn, i8* %polly.par.userContext1, i32 0, i64 0, i64 1024, i64 1)
+; IR-NEXT:   call void @single_parallel_loop_polly_subfn(i8* %polly.par.userContext1)
+; IR-NEXT:   call void @GOMP_parallel_end()
+; IR-NEXT:   br label %polly.exiting
+
+; IR: define internal void @single_parallel_loop_polly_subfn(i8* %polly.par.userContext) #1
+; IR-LABEL: polly.par.setup:
+; IR-NEXT:   %polly.par.LBPtr = alloca i64
+; IR-NEXT:   %polly.par.UBPtr = alloca i64
+; IR-NEXT:   %polly.par.userContext1 =
+; IR:   br label %polly.par.checkNext
+
+; IR-LABEL: polly.par.exit:
+; IR-NEXT:   call void @GOMP_loop_end_nowait()
+; IR-NEXT:   ret void
+
+; IR-LABEL: polly.par.checkNext:
+; IR-NEXT:   %[[parnext:[._a-zA-Z0-9]*]] = call i8 @GOMP_loop_runtime_next(i64* %polly.par.LBPtr, i64* %polly.par.UBPtr)
+; IR-NEXT:   %[[cmp:[._a-zA-Z0-9]*]] = icmp ne i8 %[[parnext]], 0
+; IR-NEXT:   br i1 %[[cmp]], label %polly.par.loadIVBounds, label %polly.par.exit
+
+; IR-LABEL: polly.par.loadIVBounds:
+; IR-NEXT:   %polly.par.LB = load i64, i64* %polly.par.LBPtr
+; IR-NEXT:   %polly.par.UB = load i64, i64* %polly.par.UBPtr
+; IR-NEXT:   %polly.par.UBAdjusted = sub i64 %polly.par.UB, 1
+; IR-NEXT:   br label %polly.loop_preheader
+
+; IR-LABEL: polly.loop_exit:
+; IR-NEXT:   br label %polly.par.checkNext
+
+; IR-LABEL: polly.loop_header:
+; IR-NEXT:   %polly.indvar = phi i64 [ %polly.par.LB, %polly.loop_preheader ], [ %polly.indvar_next, %polly.stmt.S ]
+; IR-NEXT:   br label %polly.stmt.S
+
+; IR-LABEL: polly.stmt.S:
+; IR-NEXT:   %[[gep:[._a-zA-Z0-9]*]] = getelementptr [1024 x float], [1024 x float]* {{.*}}, i64 0, i64 %polly.indvar
+; IR-NEXT:   store float 1.000000e+00, float* %[[gep]]
+; IR-NEXT:   %polly.indvar_next = add nsw i64 %polly.indvar, 1
+; IR-NEXT:   %polly.loop_cond = icmp sle i64 %polly.indvar_next, %polly.par.UBAdjusted
+; IR-NEXT:   br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit
+
+; IR-LABEL: polly.loop_preheader:
+; IR-NEXT:   br label %polly.loop_header
+
+; IR: attributes #1 = { "polly.skip.fn" }
+
+; IR-STRIDE4:   call void @GOMP_parallel_loop_runtime_start(void (i8*)* @single_parallel_loop_polly_subfn, i8* %polly.par.userContext1, i32 0, i64 0, i64 1024, i64 4)
+; IR-STRIDE4:  add nsw i64 %polly.indvar, 3
+; IR-STRIDE4:  %polly.indvar_next = add nsw i64 %polly.indvar, 4
+; IR-STRIDE4   %polly.adjust_ub = sub i64 %polly.par.UBAdjusted, 4
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float] zeroinitializer, align 16
+
+define void @single_parallel_loop() nounwind {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar = phi i64 [ %indvar.next, %for.inc], [ 0, %entry ]
+  %scevgep = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  %exitcond = icmp ne i64 %indvar, 1024
+  br i1 %exitcond, label %S, label %exit
+
+S:
+  store float 1.0, float* %scevgep
+  br label %for.inc
+
+for.inc:
+  %indvar.next = add i64 %indvar, 1
+  br label %for.i
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/single_loop_with_loop_invariant_baseptr.ll b/final/test/Isl/CodeGen/OpenMP/single_loop_with_loop_invariant_baseptr.ll
new file mode 100644
index 0000000..cbd1f1f
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/single_loop_with_loop_invariant_baseptr.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -tbaa -polly-parallel -polly-parallel-force -polly-parallel-force -polly-invariant-load-hoisting=true -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -tbaa -polly-parallel -polly-parallel-force -polly-parallel-force -polly-invariant-load-hoisting=true -polly-codegen -S -verify-dom-info < %s | FileCheck %s -check-prefix=IR
+
+; #define N 1024
+; float A[N];
+;
+; void single_parallel_loop(void) {
+;   for (long i = 0; i < N; i++)
+;     A[i] = 1;
+; }
+
+; AST: #pragma simd
+; AST: #pragma omp parallel for
+; AST: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; AST:   Stmt_S(c0);
+
+; IR: @single_parallel_loop_polly_subfn
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @single_parallel_loop(float** %A) nounwind {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar = phi i64 [ %indvar.next, %for.inc], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvar, 1024
+  br i1 %exitcond, label %S, label %exit
+
+S:
+  %ptr = load float*, float** %A,  !tbaa !2
+  %scevgep = getelementptr float, float* %ptr, i64 %indvar
+  %val = load float, float* %scevgep, !tbaa !6
+  %sum = fadd float %val, 1.0
+  store float %sum, float* %scevgep, !tbaa !6
+  br label %for.inc
+
+for.inc:
+  %indvar.next = add i64 %indvar, 1
+  br label %for.i
+
+exit:
+  ret void
+}
+
+!2 = !{!"float", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!6 = !{!"float *ptr", !3, i64 0}
diff --git a/final/test/Isl/CodeGen/OpenMP/single_loop_with_param.ll b/final/test/Isl/CodeGen/OpenMP/single_loop_with_param.ll
new file mode 100644
index 0000000..f518319
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/single_loop_with_param.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-parallel \
+; RUN: -polly-parallel-force -polly-codegen -S -verify-dom-info < %s \
+; RUN: | FileCheck %s -check-prefix=IR
+
+; #define N 1024
+; float A[N];
+;
+; void single_parallel_loop(float alpha) {
+;   for (long i = 0; i < N; i++)
+;     A[i] = alpha;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+; Ensure the scalars are initialized before the OpenMP code is launched.
+
+; IR-LABEL: polly.start:
+; IR-NEXT:    store float %alpha, float* %alpha.s2a
+
+; IR: GOMP_parallel_loop_runtime_start
+
+@A = common global [1024 x float] zeroinitializer, align 16
+
+define void @single_parallel_loop(float %alpha) nounwind {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar = phi i64 [ %indvar.next, %for.inc], [ 0, %entry ]
+  %scevgep = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  %exitcond = icmp ne i64 %indvar, 1024
+  br i1 %exitcond, label %S, label %exit
+
+S:
+  %alphaplus = fadd float 1.0, %alpha
+  store float %alphaplus, float* %scevgep
+  br label %for.inc
+
+for.inc:
+  %indvar.next = add i64 %indvar, 1
+  br label %for.i
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/single_parallel_loop___%for.i---%exit.jscop b/final/test/Isl/CodeGen/OpenMP/single_parallel_loop___%for.i---%exit.jscop
new file mode 100644
index 0000000..7c0742e
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/single_parallel_loop___%for.i---%exit.jscop
@@ -0,0 +1,17 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.i => exit",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_S[i0] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "{ Stmt_S[i0] : i0 >= 0 and i0 <= 1023 }",
+         "name" : "Stmt_S",
+         "schedule" : "{ Stmt_S[i0] -> [floor(i0/4) * 4, i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/OpenMP/two-parallel-loops-reference-outer-indvar.ll b/final/test/Isl/CodeGen/OpenMP/two-parallel-loops-reference-outer-indvar.ll
new file mode 100644
index 0000000..8e85ce4
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/two-parallel-loops-reference-outer-indvar.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-parallel -polly-parallel-force -polly-codegen -S -verify-dom-info < %s | FileCheck %s -check-prefix=IR
+
+; This test case verifies that we create correct code even if two OpenMP loops
+; share common outer variables.
+
+; AST:   Stmt_for_body35(0);
+; AST:   #pragma simd
+; AST:   #pragma omp parallel for
+; AST:   for (int c0 = 1; c0 < -p_0 + nj - 1; c0 += 1)
+; AST:     Stmt_for_body35(c0);
+
+; IR: @foo_polly_subfn
+; IR-NOT: @foo_polly_subfn_1
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %nj, [512 x double]* %R) {
+entry:
+  br label %for.cond1.preheader
+
+for.cond1.preheader:
+  %k.014 = phi i64 [ %inc87, %for.inc86 ], [ 0, %entry ]
+  %j.010 = add nsw i64 %k.014, 1
+  br i1 undef, label %for.body35, label %for.inc86
+
+for.body35:
+  %j.012 = phi i64 [ %j.0, %for.body35 ], [ %j.010, %for.cond1.preheader ]
+  %arrayidx39 = getelementptr inbounds [512 x double], [512 x double]* %R, i64 0, i64 %j.012
+  store double 0.000000e+00, double* %arrayidx39
+  %j.0 = add nsw i64 %j.012, 1
+  %cmp34 = icmp slt i64 %j.0, %nj
+  br i1 %cmp34, label %for.body35, label %for.inc86
+
+for.inc86:
+  %inc87 = add nsw i64 %k.014, 1
+  br i1 undef, label %for.cond1.preheader, label %for.end88
+
+for.end88:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/PHIInExit.ll b/final/test/Isl/CodeGen/PHIInExit.ll
new file mode 100644
index 0000000..84ecaf3
--- /dev/null
+++ b/final/test/Isl/CodeGen/PHIInExit.ll
@@ -0,0 +1,103 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+%struct..0__pthread_mutex_s = type { i32, i32, i32, i32, i32, i32, %struct.__pthread_list_t }
+%struct.__pthread_list_t = type { %struct.__pthread_list_t*, %struct.__pthread_list_t* }
+%union.pthread_attr_t = type { i64, [12 x i32] }
+%union.pthread_mutex_t = type { %struct..0__pthread_mutex_s }
+%union.pthread_mutexattr_t = type { i32 }
+
+@_ZL20__gthrw_pthread_oncePiPFvvE = weak alias i32 (i32*, void ()*), i32 (i32*, void ()*)* @pthread_once ; <i32 (i32*, void ()*)*> [#uses=0]
+@_ZL27__gthrw_pthread_getspecificj = weak alias i8* (i32), i8* (i32)* @pthread_getspecific ; <i8* (i32)*> [#uses=0]
+@_ZL27__gthrw_pthread_setspecificjPKv = weak alias i32 (i32, i8*), i32 (i32, i8*)* @pthread_setspecific ; <i32 (i32, i8*)*> [#uses=0]
+@_ZL22__gthrw_pthread_createPmPK14pthread_attr_tPFPvS3_ES3_ = weak alias i32 (i64*, %union.pthread_attr_t*, i8* (i8*)*, i8*), i32 (i64*, %union.pthread_attr_t*, i8* (i8*)*, i8*)* @pthread_create ; <i32 (i64*, %union.pthread_attr_t*, i8* (i8*)*, i8*)*> [#uses=0]
+@_ZL22__gthrw_pthread_cancelm = weak alias i32 (i64), i32 (i64)* @pthread_cancel ; <i32 (i64)*> [#uses=0]
+@_ZL26__gthrw_pthread_mutex_lockP15pthread_mutex_t = weak alias i32 (%union.pthread_mutex_t*), i32 (%union.pthread_mutex_t*)* @pthread_mutex_lock ; <i32 (%union.pthread_mutex_t*)*> [#uses=0]
+@_ZL29__gthrw_pthread_mutex_trylockP15pthread_mutex_t = weak alias i32 (%union.pthread_mutex_t*), i32 (%union.pthread_mutex_t*)* @pthread_mutex_trylock ; <i32 (%union.pthread_mutex_t*)*> [#uses=0]
+@_ZL28__gthrw_pthread_mutex_unlockP15pthread_mutex_t = weak alias i32 (%union.pthread_mutex_t*), i32 (%union.pthread_mutex_t*)* @pthread_mutex_unlock ; <i32 (%union.pthread_mutex_t*)*> [#uses=0]
+@_ZL26__gthrw_pthread_mutex_initP15pthread_mutex_tPK19pthread_mutexattr_t = weak alias i32 (%union.pthread_mutex_t*, %union.pthread_mutexattr_t*), i32 (%union.pthread_mutex_t*, %union.pthread_mutexattr_t*)* @pthread_mutex_init ; <i32 (%union.pthread_mutex_t*, %union.pthread_mutexattr_t*)*> [#uses=0]
+@_ZL26__gthrw_pthread_key_createPjPFvPvE = weak alias i32 (i32*, void (i8*)*), i32 (i32*, void (i8*)*)* @pthread_key_create ; <i32 (i32*, void (i8*)*)*> [#uses=0]
+@_ZL26__gthrw_pthread_key_deletej = weak alias i32 (i32), i32 (i32)* @pthread_key_delete ; <i32 (i32)*> [#uses=0]
+@_ZL30__gthrw_pthread_mutexattr_initP19pthread_mutexattr_t = weak alias i32 (%union.pthread_mutexattr_t*), i32 (%union.pthread_mutexattr_t*)* @pthread_mutexattr_init ; <i32 (%union.pthread_mutexattr_t*)*> [#uses=0]
+@_ZL33__gthrw_pthread_mutexattr_settypeP19pthread_mutexattr_ti = weak alias i32 (%union.pthread_mutexattr_t*, i32), i32 (%union.pthread_mutexattr_t*, i32)* @pthread_mutexattr_settype ; <i32 (%union.pthread_mutexattr_t*, i32)*> [#uses=0]
+@_ZL33__gthrw_pthread_mutexattr_destroyP19pthread_mutexattr_t = weak alias i32 (%union.pthread_mutexattr_t*), i32 (%union.pthread_mutexattr_t*)* @pthread_mutexattr_destroy ; <i32 (%union.pthread_mutexattr_t*)*> [#uses=0]
+
+define void @_ZL6createP6node_tii3v_tS1_d() {
+entry:
+  br i1 undef, label %bb, label %bb5
+
+bb:                                               ; preds = %entry
+  br i1 false, label %bb1, label %bb3
+
+bb1:                                              ; preds = %bb
+  br label %bb3
+
+bb3:                                              ; preds = %bb1, %bb
+  %iftmp.99.0 = phi i64 [ undef, %bb1 ], [ 1, %bb ] ; <i64> [#uses=0]
+  br label %bb5
+
+bb5:                                              ; preds = %bb3, %entry
+  br i1 undef, label %return, label %bb7
+
+bb7:                                              ; preds = %bb5
+  unreachable
+
+return:                                           ; preds = %bb5
+  ret void
+}
+
+define i32 @pthread_once(i32*, void ()*) {
+  ret i32 0
+}
+
+define i8* @pthread_getspecific(i32) {
+  ret i8* null
+}
+
+define i32 @pthread_setspecific(i32, i8*) {
+  ret i32 0
+}
+
+define i32 @pthread_create(i64*, %union.pthread_attr_t*, i8* (i8*)*, i8*) {
+  ret i32 0
+}
+
+define i32 @pthread_cancel(i64) {
+  ret i32 0
+}
+
+define i32 @pthread_mutex_lock(%union.pthread_mutex_t*) {
+  ret i32 0
+}
+
+define i32 @pthread_mutex_trylock(%union.pthread_mutex_t*) {
+  ret i32 0
+}
+
+define i32 @pthread_mutex_unlock(%union.pthread_mutex_t*) {
+  ret i32 0
+}
+
+define i32 @pthread_mutex_init(%union.pthread_mutex_t*, %union.pthread_mutexattr_t*) {
+  ret i32 0
+}
+
+define i32 @pthread_key_create(i32*, void (i8*)*) {
+  ret i32 0
+}
+
+define i32 @pthread_key_delete(i32) {
+  ret i32 0
+}
+
+define i32 @pthread_mutexattr_init(%union.pthread_mutexattr_t*) {
+  ret i32 0
+}
+
+define i32 @pthread_mutexattr_settype(%union.pthread_mutexattr_t*, i32) {
+  ret i32 0
+}
+
+define i32 @pthread_mutexattr_destroy(%union.pthread_mutexattr_t*) {
+  ret i32 0
+}
diff --git a/final/test/Isl/CodeGen/RuntimeDebugBuilder/combine_different_values.c b/final/test/Isl/CodeGen/RuntimeDebugBuilder/combine_different_values.c
new file mode 100644
index 0000000..c910987
--- /dev/null
+++ b/final/test/Isl/CodeGen/RuntimeDebugBuilder/combine_different_values.c
@@ -0,0 +1,23 @@
+#define N 10
+void foo(float A[restrict], double B[restrict], char C[restrict],
+         int D[restrict], long E[restrict]) {
+  for (long i = 0; i < N; i++)
+    A[i] += B[i] + C[i] + D[i] + E[i];
+}
+
+int main() {
+  float A[N];
+  double B[N];
+  char C[N];
+  int D[N];
+  long E[N];
+
+  for (long i = 0; i < N; i++) {
+    __sync_synchronize();
+    A[i] = B[i] = C[i] = D[i] = E[i] = 42;
+  }
+
+  foo(A, B, C, D, E);
+
+  return A[8];
+}
diff --git a/final/test/Isl/CodeGen/RuntimeDebugBuilder/combine_different_values.ll b/final/test/Isl/CodeGen/RuntimeDebugBuilder/combine_different_values.ll
new file mode 100644
index 0000000..0555f5b
--- /dev/null
+++ b/final/test/Isl/CodeGen/RuntimeDebugBuilder/combine_different_values.ll
@@ -0,0 +1,179 @@
+; RUN: opt %loadPolly -polly-codegen -S \
+; RUN: -polly-codegen-add-debug-printing \
+; RUN: -polly-ignore-aliasing < %s | FileCheck %s
+
+;    #define N 10
+;    void foo(float A[restrict], double B[restrict], char C[restrict],
+;             int D[restrict], long E[restrict]) {
+;      for (long i = 0; i < N; i++)
+;        A[i] += B[i] + C[i] + D[i] + E[i];
+;    }
+;
+;    int main() {
+;      float A[N];
+;      double B[N];
+;      char C[N];
+;      int D[N];
+;      long E[N];
+;
+;      for (long i = 0; i < N; i++) {
+;        __sync_synchronize();
+;        A[i] = B[i] = C[i] = D[i] = E[i] = 42;
+;      }
+;
+;      foo(A, B, C, D, E);
+;
+;      return A[8];
+;    }
+
+; CHECK: @0 = private unnamed_addr addrspace(4) constant [11 x i8] c"Load from \00"
+; CHECK: @1 = private unnamed_addr addrspace(4) constant [3 x i8] c": \00"
+; CHECK: @2 = private unnamed_addr addrspace(4) constant [2 x i8] c"\0A\00"
+; CHECK: @3 = private unnamed_addr constant [12 x i8] c"%s%ld%s%f%s\00"
+; CHECK: @4 = private unnamed_addr addrspace(4) constant [11 x i8] c"Load from \00"
+; CHECK: @5 = private unnamed_addr addrspace(4) constant [3 x i8] c": \00"
+; CHECK: @6 = private unnamed_addr addrspace(4) constant [2 x i8] c"\0A\00"
+; CHECK: @7 = private unnamed_addr constant [13 x i8] c"%s%ld%s%ld%s\00"
+; CHECK: @8 = private unnamed_addr addrspace(4) constant [11 x i8] c"Load from \00"
+; CHECK: @9 = private unnamed_addr addrspace(4) constant [3 x i8] c": \00"
+; CHECK: @10 = private unnamed_addr addrspace(4) constant [2 x i8] c"\0A\00"
+; CHECK: @11 = private unnamed_addr constant [13 x i8] c"%s%ld%s%ld%s\00"
+; CHECK: @12 = private unnamed_addr addrspace(4) constant [11 x i8] c"Load from \00"
+; CHECK: @13 = private unnamed_addr addrspace(4) constant [3 x i8] c": \00"
+; CHECK: @14 = private unnamed_addr addrspace(4) constant [2 x i8] c"\0A\00"
+; CHECK: @15 = private unnamed_addr constant [13 x i8] c"%s%ld%s%ld%s\00"
+; CHECK: @16 = private unnamed_addr addrspace(4) constant [11 x i8] c"Load from \00"
+; CHECK: @17 = private unnamed_addr addrspace(4) constant [3 x i8] c": \00"
+; CHECK: @18 = private unnamed_addr addrspace(4) constant [2 x i8] c"\0A\00"
+; CHECK: @19 = private unnamed_addr constant [12 x i8] c"%s%ld%s%f%s\00"
+; CHECK: @20 = private unnamed_addr addrspace(4) constant [11 x i8] c"Store to  \00"
+; CHECK: @21 = private unnamed_addr addrspace(4) constant [3 x i8] c": \00"
+; CHECK: @22 = private unnamed_addr addrspace(4) constant [2 x i8] c"\0A\00"
+; CHECK: @23 = private unnamed_addr constant [12 x i8] c"%s%ld%s%f%s\00"
+
+; CHECK: %0 = ptrtoint double* %scevgep to i64
+; CHECK: %1 = call i32 (...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @3, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([11 x i8], [11 x i8] addrspace(4)* @0, i32 0, i32 0), i64 %0, i8 addrspace(4)* getelementptr inbounds ([3 x i8], [3 x i8] addrspace(4)* @1, i32 0, i32 0), double %tmp3_p_scalar_, i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* @2, i32 0, i32 0))
+; CHECK: %2 = call i32 @fflush(i8* null)
+; CHECK: %scevgep1 = getelementptr i8, i8* %C, i64 %polly.indvar
+; CHECK: %tmp5_p_scalar_ = load i8, i8* %scevgep1
+; CHECK: %3 = ptrtoint i8* %scevgep1 to i64
+; CHECK: %4 = sext i8 %tmp5_p_scalar_ to i64
+; CHECK: %5 = call i32 (...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @7, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([11 x i8], [11 x i8] addrspace(4)* @4, i32 0, i32 0), i64 %3, i8 addrspace(4)* getelementptr inbounds ([3 x i8], [3 x i8] addrspace(4)* @5, i32 0, i32 0), i64 %4, i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* @6, i32 0, i32 0))
+; CHECK: %6 = call i32 @fflush(i8* null)
+; CHECK: %p_tmp6 = sitofp i8 %tmp5_p_scalar_ to double
+; CHECK: %p_tmp7 = fadd double %tmp3_p_scalar_, %p_tmp6
+; CHECK: %scevgep2 = getelementptr i32, i32* %D, i64 %polly.indvar
+; CHECK: %tmp9_p_scalar_ = load i32, i32* %scevgep2
+; CHECK: %7 = ptrtoint i32* %scevgep2 to i64
+; CHECK: %8 = sext i32 %tmp9_p_scalar_ to i64
+; CHECK: %9 = call i32 (...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @11, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([11 x i8], [11 x i8] addrspace(4)* @8, i32 0, i32 0), i64 %7, i8 addrspace(4)* getelementptr inbounds ([3 x i8], [3 x i8] addrspace(4)* @9, i32 0, i32 0), i64 %8, i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* @10, i32 0, i32 0))
+; CHECK: %10 = call i32 @fflush(i8* null)
+; CHECK: %p_tmp10 = sitofp i32 %tmp9_p_scalar_ to double
+; CHECK: %p_tmp11 = fadd double %p_tmp7, %p_tmp10
+; CHECK: %scevgep3 = getelementptr i64, i64* %E, i64 %polly.indvar
+; CHECK: %tmp13_p_scalar_ = load i64, i64* %scevgep3
+; CHECK: %11 = ptrtoint i64* %scevgep3 to i64
+; CHECK: %12 = call i32 (...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @15, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([11 x i8], [11 x i8] addrspace(4)* @12, i32 0, i32 0), i64 %11, i8 addrspace(4)* getelementptr inbounds ([3 x i8], [3 x i8] addrspace(4)* @13, i32 0, i32 0), i64 %tmp13_p_scalar_, i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* @14, i32 0, i32 0))
+; CHECK: %13 = call i32 @fflush(i8* null)
+; CHECK: %p_tmp14 = sitofp i64 %tmp13_p_scalar_ to double
+; CHECK: %p_tmp15 = fadd double %p_tmp11, %p_tmp14
+; CHECK: %scevgep4 = getelementptr float, float* %A, i64 %polly.indvar
+; CHECK: %tmp17_p_scalar_ = load float, float* %scevgep4
+; CHECK: %14 = ptrtoint float* %scevgep4 to i64
+; CHECK: %15 = fpext float %tmp17_p_scalar_ to double
+; CHECK: %16 = call i32 (...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @19, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([11 x i8], [11 x i8] addrspace(4)* @16, i32 0, i32 0), i64 %14, i8 addrspace(4)* getelementptr inbounds ([3 x i8], [3 x i8] addrspace(4)* @17, i32 0, i32 0), double %15, i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* @18, i32 0, i32 0))
+; CHECK: %17 = call i32 @fflush(i8* null)
+; CHECK: %p_tmp18 = fpext float %tmp17_p_scalar_ to double
+; CHECK: %p_tmp19 = fadd double %p_tmp18, %p_tmp15
+; CHECK: %p_tmp20 = fptrunc double %p_tmp19 to float
+; CHECK: %18 = ptrtoint float* %scevgep4 to i64
+; CHECK: %19 = fpext float %p_tmp20 to double
+; CHECK: %20 = call i32 (...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @23, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([11 x i8], [11 x i8] addrspace(4)* @20, i32 0, i32 0), i64 %18, i8 addrspace(4)* getelementptr inbounds ([3 x i8], [3 x i8] addrspace(4)* @21, i32 0, i32 0), double %19, i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* @22, i32 0, i32 0))
+; CHECK: %21 = call i32 @fflush(i8* null)
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* noalias %A, double* noalias %B, i8* noalias %C, i32* noalias %D, i64* noalias %E) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb21, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp22, %bb21 ]
+  %exitcond = icmp ne i64 %i.0, 10
+  br i1 %exitcond, label %bb2, label %bb23
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds double, double* %B, i64 %i.0
+  %tmp3 = load double, double* %tmp, align 8
+  %tmp4 = getelementptr inbounds i8, i8* %C, i64 %i.0
+  %tmp5 = load i8, i8* %tmp4, align 1
+  %tmp6 = sitofp i8 %tmp5 to double
+  %tmp7 = fadd double %tmp3, %tmp6
+  %tmp8 = getelementptr inbounds i32, i32* %D, i64 %i.0
+  %tmp9 = load i32, i32* %tmp8, align 4
+  %tmp10 = sitofp i32 %tmp9 to double
+  %tmp11 = fadd double %tmp7, %tmp10
+  %tmp12 = getelementptr inbounds i64, i64* %E, i64 %i.0
+  %tmp13 = load i64, i64* %tmp12, align 8
+  %tmp14 = sitofp i64 %tmp13 to double
+  %tmp15 = fadd double %tmp11, %tmp14
+  %tmp16 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp17 = load float, float* %tmp16, align 4
+  %tmp18 = fpext float %tmp17 to double
+  %tmp19 = fadd double %tmp18, %tmp15
+  %tmp20 = fptrunc double %tmp19 to float
+  store float %tmp20, float* %tmp16, align 4
+  br label %bb21
+
+bb21:                                             ; preds = %bb2
+  %tmp22 = add nsw i64 %i.0, 1
+  br label %bb1
+
+bb23:                                             ; preds = %bb1
+  ret void
+}
+
+define i32 @main() {
+bb:
+  %A = alloca [10 x float], align 16
+  %B = alloca [10 x double], align 16
+  %C = alloca [10 x i8], align 1
+  %D = alloca [10 x i32], align 16
+  %E = alloca [10 x i64], align 16
+  br label %bb1
+
+bb1:                                              ; preds = %bb7, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp8, %bb7 ]
+  %exitcond = icmp ne i64 %i.0, 10
+  br i1 %exitcond, label %bb2, label %bb9
+
+bb2:                                              ; preds = %bb1
+  fence seq_cst
+  %tmp = getelementptr inbounds [10 x i64], [10 x i64]* %E, i64 0, i64 %i.0
+  store i64 42, i64* %tmp, align 8
+  %tmp3 = getelementptr inbounds [10 x i32], [10 x i32]* %D, i64 0, i64 %i.0
+  store i32 42, i32* %tmp3, align 4
+  %tmp4 = getelementptr inbounds [10 x i8], [10 x i8]* %C, i64 0, i64 %i.0
+  store i8 42, i8* %tmp4, align 1
+  %tmp5 = getelementptr inbounds [10 x double], [10 x double]* %B, i64 0, i64 %i.0
+  store double 4.200000e+01, double* %tmp5, align 8
+  %tmp6 = getelementptr inbounds [10 x float], [10 x float]* %A, i64 0, i64 %i.0
+  store float 4.200000e+01, float* %tmp6, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb2
+  %tmp8 = add nsw i64 %i.0, 1
+  br label %bb1
+
+bb9:                                              ; preds = %bb1
+  %tmp10 = getelementptr inbounds [10 x float], [10 x float]* %A, i64 0, i64 0
+  %tmp11 = getelementptr inbounds [10 x double], [10 x double]* %B, i64 0, i64 0
+  %tmp12 = getelementptr inbounds [10 x i8], [10 x i8]* %C, i64 0, i64 0
+  %tmp13 = getelementptr inbounds [10 x i32], [10 x i32]* %D, i64 0, i64 0
+  %tmp14 = getelementptr inbounds [10 x i64], [10 x i64]* %E, i64 0, i64 0
+  call void @foo(float* %tmp10, double* %tmp11, i8* %tmp12, i32* %tmp13, i64* %tmp14)
+  %tmp15 = getelementptr inbounds [10 x float], [10 x float]* %A, i64 0, i64 8
+  %tmp16 = load float, float* %tmp15, align 16
+  %tmp17 = fptosi float %tmp16 to i32
+  ret i32 %tmp17
+}
diff --git a/final/test/Isl/CodeGen/alias-check-multi-dim.ll b/final/test/Isl/CodeGen/alias-check-multi-dim.ll
new file mode 100644
index 0000000..8dddb99
--- /dev/null
+++ b/final/test/Isl/CodeGen/alias-check-multi-dim.ll
@@ -0,0 +1,25 @@
+; RUN: opt %loadPolly -polly-codegen \
+; RUN:     -S < %s | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK: sext i32 %indvar.init to i64
+
+define void @foo(double* %A, double* %B, i32 %p, i32 %indvar.init) {
+preheader:
+  br label %for.body
+
+for.body:
+  %indvar = phi i32 [ %indvar.next, %for.body ], [ %indvar.init, %preheader ]
+  %B.ptr0 = getelementptr inbounds double, double* %B, i64 0
+  %tmp1 = load double, double* %B.ptr0
+  %A.ptr = getelementptr inbounds double, double* %A, i64 0
+  store double undef, double* %A.ptr
+  %idxprom1329 = sext i32 %indvar to i64
+  %B.ptr1 = getelementptr inbounds double, double* %B, i64 %idxprom1329
+  store double 0.000000e+00, double* %B.ptr1
+  %indvar.next = add nsw i32 %indvar, %p
+  br i1 false, label %for.body, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/alias_metadata_too_many_arrays.ll b/final/test/Isl/CodeGen/alias_metadata_too_many_arrays.ll
new file mode 100644
index 0000000..89b91ec
--- /dev/null
+++ b/final/test/Isl/CodeGen/alias_metadata_too_many_arrays.ll
@@ -0,0 +1,200 @@
+; RUN: opt %loadPolly -polly-codegen -polly-ignore-aliasing -S < %s \
+; RUN:   | FileCheck %s
+;
+;    void manyarrays(float A1[], float A2[], float A3[], float A4[], float A5[],
+;                    float A6[], float A7[], float A8[], float A9[]) {
+;      for (long i = 0; i <= 1024; i++) {
+;        A1[i] += i;
+;        A2[i] += i;
+;        A3[i] += i;
+;        A4[i] += i;
+;        A5[i] += i;
+;        A6[i] += i;
+;        A7[i] += i;
+;        A8[i] += i;
+;        A9[i] += i;
+;      }
+;    }
+;
+; CHECK-LABEL @manyarrays
+; CHECK: load{{.*}}!alias.scope
+; CHECK: store{{.*}}!alias.scope
+; CHECK: load{{.*}}!alias.scope
+; CHECK: store{{.*}}!alias.scope
+; CHECK: load{{.*}}!alias.scope
+; CHECK: store{{.*}}!alias.scope
+; CHECK: load{{.*}}!alias.scope
+; CHECK: store{{.*}}!alias.scope
+; CHECK: load{{.*}}!alias.scope
+; CHECK: store{{.*}}!alias.scope
+; CHECK: load{{.*}}!alias.scope
+; CHECK: store{{.*}}!alias.scope
+; CHECK: load{{.*}}!alias.scope
+; CHECK: store{{.*}}!alias.scope
+; CHECK: load{{.*}}!alias.scope
+; CHECK: store{{.*}}!alias.scope
+; CHECK: load{{.*}}!alias.scope
+; CHECK: store{{.*}}!alias.scope
+;
+;    void toomanyarrays(float A1[], float A2[], float A3[], float A4[], float A5[],
+;                       float A6[], float A7[], float A8[], float A9[], float A10[],
+;                       float A11[]) {
+;      for (long i = 0; i <= 1024; i++) {
+;        A1[i] += i;
+;        A2[i] += i;
+;        A3[i] += i;
+;        A4[i] += i;
+;        A5[i] += i;
+;        A6[i] += i;
+;        A7[i] += i;
+;        A8[i] += i;
+;        A9[i] += i;
+;        A10[i] += i;
+;        A11[i] += i;
+;      }
+;    }
+;
+; CHECK-LABEL: @toomanyarrays
+; CHECK-NOT: !alias.scope
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @manyarrays(float* %A1, float* %A2, float* %A3, float* %A4, float* %A5, float* %A6, float* %A7, float* %A8, float* %A9) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb38, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp39, %bb38 ]
+  %exitcond = icmp ne i64 %i.0, 1025
+  br i1 %exitcond, label %bb2, label %bb40
+
+bb2:                                              ; preds = %bb1
+  %tmp = sitofp i64 %i.0 to float
+  %tmp3 = getelementptr inbounds float, float* %A1, i64 %i.0
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, %tmp
+  store float %tmp5, float* %tmp3, align 4
+  %tmp6 = sitofp i64 %i.0 to float
+  %tmp7 = getelementptr inbounds float, float* %A2, i64 %i.0
+  %tmp8 = load float, float* %tmp7, align 4
+  %tmp9 = fadd float %tmp8, %tmp6
+  store float %tmp9, float* %tmp7, align 4
+  %tmp10 = sitofp i64 %i.0 to float
+  %tmp11 = getelementptr inbounds float, float* %A3, i64 %i.0
+  %tmp12 = load float, float* %tmp11, align 4
+  %tmp13 = fadd float %tmp12, %tmp10
+  store float %tmp13, float* %tmp11, align 4
+  %tmp14 = sitofp i64 %i.0 to float
+  %tmp15 = getelementptr inbounds float, float* %A4, i64 %i.0
+  %tmp16 = load float, float* %tmp15, align 4
+  %tmp17 = fadd float %tmp16, %tmp14
+  store float %tmp17, float* %tmp15, align 4
+  %tmp18 = sitofp i64 %i.0 to float
+  %tmp19 = getelementptr inbounds float, float* %A5, i64 %i.0
+  %tmp20 = load float, float* %tmp19, align 4
+  %tmp21 = fadd float %tmp20, %tmp18
+  store float %tmp21, float* %tmp19, align 4
+  %tmp22 = sitofp i64 %i.0 to float
+  %tmp23 = getelementptr inbounds float, float* %A6, i64 %i.0
+  %tmp24 = load float, float* %tmp23, align 4
+  %tmp25 = fadd float %tmp24, %tmp22
+  store float %tmp25, float* %tmp23, align 4
+  %tmp26 = sitofp i64 %i.0 to float
+  %tmp27 = getelementptr inbounds float, float* %A7, i64 %i.0
+  %tmp28 = load float, float* %tmp27, align 4
+  %tmp29 = fadd float %tmp28, %tmp26
+  store float %tmp29, float* %tmp27, align 4
+  %tmp30 = sitofp i64 %i.0 to float
+  %tmp31 = getelementptr inbounds float, float* %A8, i64 %i.0
+  %tmp32 = load float, float* %tmp31, align 4
+  %tmp33 = fadd float %tmp32, %tmp30
+  store float %tmp33, float* %tmp31, align 4
+  %tmp34 = sitofp i64 %i.0 to float
+  %tmp35 = getelementptr inbounds float, float* %A9, i64 %i.0
+  %tmp36 = load float, float* %tmp35, align 4
+  %tmp37 = fadd float %tmp36, %tmp34
+  store float %tmp37, float* %tmp35, align 4
+  br label %bb38
+
+bb38:                                             ; preds = %bb2
+  %tmp39 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb40:                                             ; preds = %bb1
+  ret void
+}
+
+define void @toomanyarrays(float* %A1, float* %A2, float* %A3, float* %A4, float* %A5, float* %A6, float* %A7, float* %A8, float* %A9, float* %A10, float* %A11) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb46, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp47, %bb46 ]
+  %exitcond = icmp ne i64 %i.0, 1025
+  br i1 %exitcond, label %bb2, label %bb48
+
+bb2:                                              ; preds = %bb1
+  %tmp = sitofp i64 %i.0 to float
+  %tmp3 = getelementptr inbounds float, float* %A1, i64 %i.0
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, %tmp
+  store float %tmp5, float* %tmp3, align 4
+  %tmp6 = sitofp i64 %i.0 to float
+  %tmp7 = getelementptr inbounds float, float* %A2, i64 %i.0
+  %tmp8 = load float, float* %tmp7, align 4
+  %tmp9 = fadd float %tmp8, %tmp6
+  store float %tmp9, float* %tmp7, align 4
+  %tmp10 = sitofp i64 %i.0 to float
+  %tmp11 = getelementptr inbounds float, float* %A3, i64 %i.0
+  %tmp12 = load float, float* %tmp11, align 4
+  %tmp13 = fadd float %tmp12, %tmp10
+  store float %tmp13, float* %tmp11, align 4
+  %tmp14 = sitofp i64 %i.0 to float
+  %tmp15 = getelementptr inbounds float, float* %A4, i64 %i.0
+  %tmp16 = load float, float* %tmp15, align 4
+  %tmp17 = fadd float %tmp16, %tmp14
+  store float %tmp17, float* %tmp15, align 4
+  %tmp18 = sitofp i64 %i.0 to float
+  %tmp19 = getelementptr inbounds float, float* %A5, i64 %i.0
+  %tmp20 = load float, float* %tmp19, align 4
+  %tmp21 = fadd float %tmp20, %tmp18
+  store float %tmp21, float* %tmp19, align 4
+  %tmp22 = sitofp i64 %i.0 to float
+  %tmp23 = getelementptr inbounds float, float* %A6, i64 %i.0
+  %tmp24 = load float, float* %tmp23, align 4
+  %tmp25 = fadd float %tmp24, %tmp22
+  store float %tmp25, float* %tmp23, align 4
+  %tmp26 = sitofp i64 %i.0 to float
+  %tmp27 = getelementptr inbounds float, float* %A7, i64 %i.0
+  %tmp28 = load float, float* %tmp27, align 4
+  %tmp29 = fadd float %tmp28, %tmp26
+  store float %tmp29, float* %tmp27, align 4
+  %tmp30 = sitofp i64 %i.0 to float
+  %tmp31 = getelementptr inbounds float, float* %A8, i64 %i.0
+  %tmp32 = load float, float* %tmp31, align 4
+  %tmp33 = fadd float %tmp32, %tmp30
+  store float %tmp33, float* %tmp31, align 4
+  %tmp34 = sitofp i64 %i.0 to float
+  %tmp35 = getelementptr inbounds float, float* %A9, i64 %i.0
+  %tmp36 = load float, float* %tmp35, align 4
+  %tmp37 = fadd float %tmp36, %tmp34
+  store float %tmp37, float* %tmp35, align 4
+  %tmp38 = sitofp i64 %i.0 to float
+  %tmp39 = getelementptr inbounds float, float* %A10, i64 %i.0
+  %tmp40 = load float, float* %tmp39, align 4
+  %tmp41 = fadd float %tmp40, %tmp38
+  store float %tmp41, float* %tmp39, align 4
+  %tmp42 = sitofp i64 %i.0 to float
+  %tmp43 = getelementptr inbounds float, float* %A11, i64 %i.0
+  %tmp44 = load float, float* %tmp43, align 4
+  %tmp45 = fadd float %tmp44, %tmp42
+  store float %tmp45, float* %tmp43, align 4
+  br label %bb46
+
+bb46:                                             ; preds = %bb2
+  %tmp47 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb48:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/aliasing_different_base_and_access_type.ll b/final/test/Isl/CodeGen/aliasing_different_base_and_access_type.ll
new file mode 100644
index 0000000..a5d2f7a
--- /dev/null
+++ b/final/test/Isl/CodeGen/aliasing_different_base_and_access_type.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+;
+; We have to cast %B to "short *" before we create RTCs.
+;
+; CHECK:   %polly.access.cast.B = bitcast i32* %B to i16*
+; CHECK-NEXT:   %polly.access.B = getelementptr i16, i16* %polly.access.cast.B, i64 1024
+;
+; We should never access %B as an i32 pointer:
+;
+; CHECK-NOT: getelementptr i32, i32* %B
+;
+;    void jd(int *A, int *B) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = ((short *)B)[i];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = bitcast i32* %B to i16*
+  %arrayidx = getelementptr inbounds i16, i16* %tmp, i64 %indvars.iv
+  %tmp1 = load i16, i16* %arrayidx, align 2
+  %conv = sext i16 %tmp1 to i32
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %conv, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/aliasing_different_pointer_types.ll b/final/test/Isl/CodeGen/aliasing_different_pointer_types.ll
new file mode 100644
index 0000000..43a06bf
--- /dev/null
+++ b/final/test/Isl/CodeGen/aliasing_different_pointer_types.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; Check that we cast the different pointer types correctly before we compare
+; them in the RTC's. We use i8* as max pointer type.
+;
+; CHECK:   polly.split_new_and_old:
+; CHECK:   %polly.access.B = getelementptr float*, float** %B, i64 1024
+; CHECK:   %polly.access.A = getelementptr double*, double** %A, i64 0
+; CHECK:   %[[paBb:[._a-zA-Z0-9]]] = ptrtoint float** %polly.access.B to i64
+; CHECK:   %[[paAb:[._a-zA-Z0-9]]] = ptrtoint double** %polly.access.A to i64
+; CHECK:   %[[ALeB:[._a-zA-Z0-9]]] = icmp ule i64 %[[paBb]], %[[paAb]]
+; CHECK:   %polly.access.A1 = getelementptr double*, double** %A, i64 1024
+; CHECK:   %polly.access.B2 = getelementptr float*, float** %B, i64 0
+; CHECK:   %[[paA1b:[._a-zA-Z0-9]]] = ptrtoint double** %polly.access.A1 to i64
+; CHECK:   %[[paB2b:[._a-zA-Z0-9]]] = ptrtoint float** %polly.access.B2 to i64
+; CHECK:   %[[A1LeB2:[._a-zA-Z0-9]]] = icmp ule i64 %[[paA1b]], %[[paB2b]]
+; CHECK:   %[[le1OrLe2:[._a-zA-Z0-9]]] = or i1 %[[ALeB]], %[[A1LeB2]]
+; CHECK:   %[[orAndTrue:[._a-zA-Z0-9]]] = and i1 true, %[[le1OrLe2]]
+;
+;    void jd(double **A, float **B) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = (double *)B[i];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(double** %A, float** %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds float*, float** %B, i64 %indvars.iv
+  %tmp = load float*, float** %arrayidx, align 8
+  %tmp1 = bitcast float* %tmp to double*
+  %arrayidx2 = getelementptr inbounds double*, double** %A, i64 %indvars.iv
+  store double* %tmp1, double** %arrayidx2, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/aliasing_multidimensional_access.ll b/final/test/Isl/CodeGen/aliasing_multidimensional_access.ll
new file mode 100644
index 0000000..9048c75
--- /dev/null
+++ b/final/test/Isl/CodeGen/aliasing_multidimensional_access.ll
@@ -0,0 +1,94 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+;
+; Check that we calculate the maximal access into array A correctly and track the overflow state.
+;
+; CHECK:  %[[TMP0:[._0-9a-zA-Z]*]]  = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 99, i64 %m)
+; CHECK:  %[[TMP0O:[._0-9a-zA-Z]*]] = extractvalue { i64, i1 } %[[TMP0]], 1
+; CHECK:  %[[OS0:[._0-9a-zA-Z]*]]   = or i1 {{[^,]*}}, %[[TMP0O]]
+; CHECK:  %[[TMP0R:[._0-9a-zA-Z]*]] = extractvalue { i64, i1 } %[[TMP0]], 0
+; CHECK:  %[[TMP1:[._0-9a-zA-Z]*]]  = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %[[TMP0R]], i64 149)
+; CHECK:  %[[TMP1O:[._0-9a-zA-Z]*]] = extractvalue { i64, i1 } %[[TMP1]], 1
+; CHECK:  %[[OS1:[._0-9a-zA-Z]*]]   = or i1 %[[OS0]], %[[TMP1O]]
+; CHECK:  %[[TMP1R:[._0-9a-zA-Z]*]] = extractvalue { i64, i1 } %[[TMP1]], 0
+; CHECK:  %[[TMP2:[._0-9a-zA-Z]*]]  = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 %[[TMP1R]], i64 %p)
+; CHECK:  %[[TMP2O:[._0-9a-zA-Z]*]] = extractvalue { i64, i1 } %[[TMP2]], 1
+; CHECK:  %[[OS2:[._0-9a-zA-Z]*]]   = or i1 %[[OS1]], %[[TMP2O]]
+; CHECK:  %[[TMP2R:[._0-9a-zA-Z]*]] = extractvalue { i64, i1 } %[[TMP2]], 0
+; CHECK:  %[[TMP3:[._0-9a-zA-Z]*]]  = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %[[TMP2R]], i64 150)
+; CHECK:  %[[TMP3O:[._0-9a-zA-Z]*]] = extractvalue { i64, i1 } %[[TMP3]], 1
+; CHECK:  %[[OS3:[._0-9a-zA-Z]*]]   = or i1 %[[OS2]], %[[TMP3O]]
+; CHECK:  %[[TMP3R:[._0-9a-zA-Z]*]] = extractvalue { i64, i1 } %[[TMP3]], 0
+; CHECK:  %polly.access.A{{[0-9]*}} = getelementptr double, double* %A, i64 %[[TMP3R]]
+;
+; CHECK:  %polly.rtc.overflown = xor i1 %[[OS3]], true
+; CHECK:  %polly.rtc.result = and i1 %{{[^,]*}}, %polly.rtc.overflown
+; CHECK:  br i1 %polly.rtc.result,
+;
+;    void foo(long n, long m, long p, double A[n][m][p], int *B) {
+;      for (long i = 0; i < 100; i++)
+;        for (long j = 0; j < 150; j++)
+;          for (long k = 0; k < 150; k++)
+;            A[i][j][k] = B[k];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %n, i64 %m, i64 %p, double* %A, i32* %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc03, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc04, %for.inc03 ]
+  %exitcond2 = icmp ne i64 %i.0, 100
+  br i1 %exitcond2, label %for.body, label %for.end15
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc00, %for.body
+  %j.0 = phi i64 [ 0, %for.body ], [ %inc01, %for.inc00 ]
+  %exitcond1 = icmp ne i64 %j.0, 150
+  br i1 %exitcond1, label %for.body3, label %for.end12
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc, %for.body3
+  %k.0 = phi i64 [ 0, %for.body3 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %k.0, 150
+  br i1 %exitcond, label %for.body6, label %for.end
+
+for.body6:                                        ; preds = %for.cond4
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %k.0
+  %tmp3 = load i32, i32* %arrayidx, align 2
+  %conv = sitofp i32 %tmp3 to double
+  %tmp4 = mul nuw i64 %m, %p
+  %tmp5 = mul nsw i64 %i.0, %tmp4
+  %tmp6 = mul nsw i64 %j.0, %p
+  %arrayidx7.sum = add i64 %tmp5, %tmp6
+  %arrayidx8.sum = add i64 %arrayidx7.sum, %k.0
+  %arrayidx9 = getelementptr inbounds double, double* %A, i64 %arrayidx8.sum
+  store double %conv, double* %arrayidx9, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body6
+  %inc = add nsw i64 %k.0, 1
+  br label %for.cond4
+
+for.end:                                          ; preds = %for.cond4
+  br label %for.inc00
+
+for.inc00:                                        ; preds = %for.end
+  %inc01 = add nsw i64 %j.0, 1
+  br label %for.cond1
+
+for.end12:                                        ; preds = %for.cond1
+  br label %for.inc03
+
+for.inc03:                                        ; preds = %for.end12
+  %inc04 = add nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end15:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/aliasing_parametric_simple_1.ll b/final/test/Isl/CodeGen/aliasing_parametric_simple_1.ll
new file mode 100644
index 0000000..eaf5c7f
--- /dev/null
+++ b/final/test/Isl/CodeGen/aliasing_parametric_simple_1.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+;    void jd(int *A, int *B, int c) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = B[c];
+;    }
+;
+; CHECK:  %[[Cext:[._a-zA-Z0-9]*]] = sext i32 %c to i64
+; CHECK:  %[[Cp1:[._a-zA-Z0-9]*]]  = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %[[Cext]], i64 1)
+; CHECK:  %[[Cp1O:[._a-zA-Z0-9]*]] = extractvalue { i64, i1 } %[[Cp1]], 1
+; CHECK:  %[[OS:[._a-zA-Z0-9]*]]   = or i1 false, %[[Cp1O]]
+; CHECK:  %[[Cp1R:[._a-zA-Z0-9]*]] = extractvalue { i64, i1 } %[[Cp1]], 0
+; CHECK:  %[[BMax:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %B, i64 %[[Cp1R]]
+; CHECK:  %[[AMin:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %A, i64 0
+; CHECK:  %[[BMaxI:[._a-zA-Z0-9]*]] = ptrtoint i32* %[[BMax]] to i64
+; CHECK:  %[[AMinI:[._a-zA-Z0-9]*]] = ptrtoint i32* %[[AMin]] to i64
+; CHECK:  %[[BltA:[._a-zA-Z0-9]*]] = icmp ule i64 %[[BMaxI]], %[[AMinI]]
+; CHECK:  %[[AMax:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %A, i64 1024
+; CHECK:  %[[BMin:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %B, i32 %c
+; CHECK:  %[[AMaxI:[._a-zA-Z0-9]*]] = ptrtoint i32* %[[AMax]] to i64
+; CHECK:  %[[BMinI:[._a-zA-Z0-9]*]] = ptrtoint i32* %[[BMin]] to i64
+; CHECK:  %[[AltB:[._a-zA-Z0-9]*]] = icmp ule i64 %[[AMaxI]], %[[BMinI]]
+; CHECK:  %[[NoAlias:[._a-zA-Z0-9]*]] = or i1 %[[BltA]], %[[AltB]]
+; CHECK:  %[[RTC:[._a-zA-Z0-9]*]] = and i1 true, %[[NoAlias]]
+; CHECK:  %[[NOV:[._a-zA-Z0-9]*]] = xor i1 %[[OS]], true
+; CHECK:  %[[RTCV:[._a-zA-Z0-9]*]] = and i1 %[[RTC]], %[[NOV]]
+; CHECK:  br i1 %[[RTCV]], label %polly.start, label %for.cond
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %B, i32 %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %idxprom = sext i32 %c to i64
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %idxprom
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/aliasing_parametric_simple_2.ll b/final/test/Isl/CodeGen/aliasing_parametric_simple_2.ll
new file mode 100644
index 0000000..24b52ce
--- /dev/null
+++ b/final/test/Isl/CodeGen/aliasing_parametric_simple_2.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+;    void jd(int *A, int *B, int c) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = B[c - 10] + B[5];
+;    }
+;
+; CHECK:  %[[Ctx:[._a-zA-Z0-9]*]] = and i1 true
+; CHECK-NEXT:  %[[M0:[._a-zA-Z0-9]*]] = sext i32 %c to i64
+; CHECK-NEXT:  %[[M3:[._a-zA-Z0-9]*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 %[[M0]], i64 9)
+; CHECK-NEXT:  %[[M3O:[._a-zA-Z0-9]*]] = extractvalue { i64, i1 } %[[M3]], 1
+; CHECK-NEXT:  %[[OS0:[._a-zA-Z0-9]*]]   = or i1 false, %[[M3O]]
+; CHECK-NEXT:  %[[M3R:[._a-zA-Z0-9]*]] = extractvalue { i64, i1 } %[[M3]], 0
+; CHECK-NEXT:  %[[M1:[._a-zA-Z0-9]*]] = icmp sgt i64 6, %[[M3R]]
+; CHECK-NEXT:  %[[M4:[._a-zA-Z0-9]*]] = select i1 %[[M1]], i64 6, i64 %[[M3R]]
+; CHECK-NEXT:  %[[BMax:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %B, i64 %[[M4]]
+; CHECK-NEXT:  %[[AMin:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %A, i64 0
+; CHECK-NEXT:  %[[BMaxI:[._a-zA-Z0-9]*]] = ptrtoint i32* %[[BMax]] to i64
+; CHECK-NEXT:  %[[AMinI:[._a-zA-Z0-9]*]] = ptrtoint i32* %[[AMin]] to i64
+; CHECK-NEXT:  %[[BltA:[._a-zA-Z0-9]*]] = icmp ule i64 %[[BMaxI]], %[[AMinI]]
+; CHECK-NEXT:  %[[AMax:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %A, i64 1024
+; CHECK-NEXT:  %[[m0:[._a-zA-Z0-9]*]] = sext i32 %c to i64
+; CHECK-NEXT:  %[[m3:[._a-zA-Z0-9]*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 %[[m0]], i64 10)
+; CHECK-NEXT:  %[[m3O:[._a-zA-Z0-9]*]] = extractvalue { i64, i1 } %[[m3]], 1
+; CHECK-NEXT:  %[[OS1:[._a-zA-Z0-9]*]]   = or i1 %[[OS0]], %[[m3O]]
+; CHECK-NEXT:  %[[m3R:[._a-zA-Z0-9]*]] = extractvalue { i64, i1 } %[[m3]], 0
+; CHECK-NEXT:  %[[m1:[._a-zA-Z0-9]*]] = icmp slt i64 5, %[[m3R]]
+; CHECK-NEXT:  %[[m4:[._a-zA-Z0-9]*]] = select i1 %[[m1]], i64 5, i64 %[[m3R]]
+; CHECK-NEXT:  %[[BMin:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %B, i64 %[[m4]]
+; CHECK-NEXT:  %[[AMaxI:[._a-zA-Z0-9]*]] = ptrtoint i32* %[[AMax]] to i64
+; CHECK-NEXT:  %[[BMinI:[._a-zA-Z0-9]*]] = ptrtoint i32* %[[BMin]] to i64
+; CHECK-NEXT:  %[[AltB:[._a-zA-Z0-9]*]] = icmp ule i64 %[[AMaxI]], %[[BMinI]]
+; CHECK-NEXT:  %[[NoAlias:[._a-zA-Z0-9]*]] = or i1 %[[BltA]], %[[AltB]]
+; CHECK-NEXT:  %[[RTC:[._a-zA-Z0-9]*]] = and i1 %[[Ctx]], %[[NoAlias]]
+; CHECK-NEXT:  %[[NOV:[._a-zA-Z0-9]*]] = xor i1 %[[OS1]], true
+; CHECK-NEXT:  %[[RTCV:[._a-zA-Z0-9]*]] = and i1 %[[RTC]], %[[NOV]]
+; CHECK-NEXT:  br i1 %[[RTCV]], label %polly.start, label %for.cond
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %B, i32 %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %sub = add nsw i32 %c, -10
+  %idxprom = sext i32 %sub to i64
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %idxprom
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds i32, i32* %B, i64 5
+  %tmp1 = load i32, i32* %arrayidx1, align 4
+  %add = add nsw i32 %tmp, %tmp1
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %add, i32* %arrayidx3, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/aliasing_struct_element.ll b/final/test/Isl/CodeGen/aliasing_struct_element.ll
new file mode 100644
index 0000000..ceec5ee
--- /dev/null
+++ b/final/test/Isl/CodeGen/aliasing_struct_element.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+;
+; We should only access (or compute the address of) "the first element" of %S
+; as it is a single struct not a struct array. The maximal access to S, thus
+; S->B[1023] is for ScalarEvolution an access with offset of 1423, 1023 for the
+; index inside the B part of S and 400 to skip the Dummy array in S. Note that
+; these numbers are relative to the actual type of &S->B[i] (char*) not to the
+; type of S (struct st *) or something else.
+;
+; Verify that we do not use the offset 1423 into a non existent S array when we
+; compute runtime alias checks but treat it as if it was a char array.
+;
+; CHECK: %polly.access.cast.S = bitcast %struct.st* %S to i8*
+; CHECK: %polly.access.S = getelementptr i8, i8* %polly.access.cast.S, i64 1424
+;
+;    struct st {
+;      int Dummy[100];
+;      char B[100];
+;    };
+;
+;    void jd(int *A, struct st *S) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = S->B[i];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.st = type { [100 x i32], [100 x i8] }
+
+define void @jd(i32* %A, %struct.st* %S) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds %struct.st, %struct.st* %S, i64 0, i32 1, i64 %indvars.iv
+  %tmp = load i8, i8* %arrayidx, align 1
+  %conv = sext i8 %tmp to i32
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %conv, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/alignment.ll b/final/test/Isl/CodeGen/alignment.ll
new file mode 100644
index 0000000..5a54fff
--- /dev/null
+++ b/final/test/Isl/CodeGen/alignment.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; Check that the special alignment information is kept
+;
+; CHECK: align 8
+; CHECK: align 8
+;
+;    void jd(int *A) {
+;      for (int i = 0; i < 1024; i += 2)
+;        A[i] = i;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = trunc i64 %indvars.iv to i32
+  store i32 %tmp, i32* %arrayidx, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 2
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/annotated_alias_scopes.ll b/final/test/Isl/CodeGen/annotated_alias_scopes.ll
new file mode 100644
index 0000000..c209d9e
--- /dev/null
+++ b/final/test/Isl/CodeGen/annotated_alias_scopes.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s --check-prefix=SCOPES
+;
+; Check that we create alias scopes that indicate the accesses to A, B and C cannot alias in any way.
+;
+; SCOPES-LABEL: polly.stmt.for.body:
+; SCOPES:      %[[BIdx:[._a-zA-Z0-9]*]] = getelementptr{{.*}} i32* %B, i64 %polly.indvar
+; SCOPES:      load i32, i32* %[[BIdx]], align 4, !alias.scope ![[AliasScopeB:[0-9]*]], !noalias ![[NoAliasB:[0-9]*]]
+; SCOPES:      %[[CIdx:[._a-zA-Z0-9]*]] = getelementptr{{.*}} float* %C, i64 %polly.indvar
+; SCOPES:      load float, float* %[[CIdx]], align 4, !alias.scope ![[AliasScopeC:[0-9]*]], !noalias ![[NoAliasC:[0-9]*]]
+; SCOPES:      %[[AIdx:[._a-zA-Z0-9]*]] = getelementptr{{.*}} i32* %A, i64 %polly.indvar
+; SCOPES:      store i32 %{{[._a-zA-Z0-9]*}}, i32* %[[AIdx]], align 4, !alias.scope ![[AliasScopeA:[0-9]*]], !noalias ![[NoAliasA:[0-9]*]]
+;
+; SCOPES:      ![[AliasScopeB]] = distinct !{![[AliasScopeB]], !{{[0-9]*}}, !"polly.alias.scope.MemRef_B"}
+; SCOPES:      ![[NoAliasB]] = !{
+; SCOPES-DAG:     ![[AliasScopeA]]
+; SCOPES-DAG:     ![[AliasScopeC]]
+; SCOPES:       }
+; SCOPES-DAG:  ![[AliasScopeA]] = distinct !{![[AliasScopeA]], !{{[0-9]*}}, !"polly.alias.scope.MemRef_A"}
+; SCOPES-DAG:  ![[AliasScopeC]] = distinct !{![[AliasScopeC]], !{{[0-9]*}}, !"polly.alias.scope.MemRef_C"}
+; SCOPES:      ![[NoAliasC]] = !{
+; SCOPES-DAG:     ![[AliasScopeA]]
+; SCOPES-DAG:     ![[AliasScopeB]]
+; SCOPES:       }
+; SCOPES:      ![[NoAliasA]] = !{
+; SCOPES-DAG:     ![[AliasScopeB]]
+; SCOPES-DAG:     ![[AliasScopeC]]
+; SCOPES:       }
+;
+;    void jd(int *A, int *B, float *C) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = B[i] + C[i];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %B, float* %C) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4
+  %conv = sitofp i32 %tmp to float
+  %arrayidx2 = getelementptr inbounds float, float* %C, i64 %indvars.iv
+  %tmp1 = load float, float* %arrayidx2, align 4
+  %add = fadd fast float %conv, %tmp1
+  %conv3 = fptosi float %add to i32
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %conv3, i32* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/blas_sscal_simplified.ll b/final/test/Isl/CodeGen/blas_sscal_simplified.ll
new file mode 100644
index 0000000..6ad954b
--- /dev/null
+++ b/final/test/Isl/CodeGen/blas_sscal_simplified.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+;
+; Regression test for a bug in the runtime check generation.
+
+; This was extracted from the blas testcase. It crashed in one
+; part of the runtime check generation at some point. To be
+; precise, we couldn't find a suitable block to put the RTC code in.
+;
+; int sscal(int n, float sa, float *sx) {
+;   for(int i=0; i<n; i++, sx++)
+;     *sx *= sa;
+;   return 0;
+; }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @sscal(i32 %n, float %sa, float* %sx) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %cmp1 = icmp sgt i32 %n, 0
+  br i1 %cmp1, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  %0 = zext i32 %n to i64
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.lr.ph, %for.body
+  %indvar = phi i64 [ 0, %for.body.lr.ph ], [ %indvar.next, %for.body ]
+  %sx.addr.02 = getelementptr float, float* %sx, i64 %indvar
+  %tmp = load float, float* %sx.addr.02, align 4
+  %mul = fmul float %tmp, %sa
+  store float %mul, float* %sx.addr.02, align 4
+  %indvar.next = add i64 %indvar, 1
+  %exitcond = icmp ne i64 %indvar.next, %0
+  br i1 %exitcond, label %for.body, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  ret i32 0
+}
diff --git a/final/test/Isl/CodeGen/conflict-between-loop-invariant-code-hosting-and-escape-map-computation.ll b/final/test/Isl/CodeGen/conflict-between-loop-invariant-code-hosting-and-escape-map-computation.ll
new file mode 100644
index 0000000..94d1427
--- /dev/null
+++ b/final/test/Isl/CodeGen/conflict-between-loop-invariant-code-hosting-and-escape-map-computation.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-process-unprofitable -analyze -polly-codegen < %s
+;
+; CHECK: store i32 %tmp14_p_scalar_, i32* %tmp14.s2a
+; CHECK: %tmp14.final_reload = load i32, i32* %tmp14.s2a
+; CHECK: %tmp17b.final_reload = load i32, i32* %tmp17b.preload.s2a
+; CHECK: %tmp17.final_reload = load i32, i32* %tmp17.preload.s2a
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @hoge(i8* %arg, i32 %arg4) #0 {
+bb:
+  br label %bb5
+
+bb5:                                              ; preds = %bb
+  br i1 undef, label %bb6, label %bb18
+
+bb6:                                              ; preds = %bb5
+  %tmp7 = getelementptr i8, i8* %arg, i64 0
+  %tmp8 = getelementptr inbounds i8, i8* %tmp7, i64 4
+  %tmp9 = getelementptr inbounds i8, i8* %tmp8, i64 20
+  br label %bb10
+
+bb10:                                             ; preds = %bb10, %bb6
+  %tmp11 = phi i32 [ %tmp12, %bb10 ], [ 2, %bb6 ]
+  %tmp12 = add nuw nsw i32 %tmp11, 1
+  br i1 false, label %bb10, label %bb13
+
+bb13:                                             ; preds = %bb10
+  %tmp = bitcast i8* %tmp9 to i32*
+  %tmp14 = load i32, i32* %tmp, align 4
+  %tmp15 = getelementptr inbounds i8, i8* %tmp9, i64 4
+  %tmp16 = bitcast i8* %tmp15 to i32*
+  %tmp17 = load i32, i32* %tmp16, align 4
+  store i32 %tmp17, i32* %tmp, align 4
+  %tmp15b = getelementptr inbounds i8, i8* %tmp9, i64 8
+  %tmp16b = bitcast i8* %tmp15b to i32*
+  %tmp17b = load i32, i32* %tmp16b, align 4
+  store i32 %tmp17b, i32* %tmp, align 4
+  br label %bb19
+
+bb18:                                             ; preds = %bb5
+  br label %bb19
+
+bb19:                                             ; preds = %bb18, %bb13
+  %tmp20 = phi i32 [ %tmp14, %bb13 ], [ %arg4, %bb18 ]
+  %tmp21 = phi i32 [ %tmp17, %bb13 ], [ %arg4, %bb18 ]
+  %tmp22 = phi i32 [ %tmp17b, %bb13 ], [ %arg4, %bb18 ]
+  unreachable
+}
diff --git a/final/test/Isl/CodeGen/constant_condition.ll b/final/test/Isl/CodeGen/constant_condition.ll
new file mode 100644
index 0000000..3c6bf4d
--- /dev/null
+++ b/final/test/Isl/CodeGen/constant_condition.ll
@@ -0,0 +1,55 @@
+;RUN: opt %loadPolly -polly-prepare -polly-ast -analyze < %s | FileCheck %s
+
+;#include <string.h>
+;int A[1];
+;
+;void constant_condition () {
+;  int a = 0;
+;  int b = 0;
+;
+;  if (a == b)
+;    A[0] = 0;
+;  else
+;    A[0] = 1;
+;}
+;
+;int main () {
+;  int i;
+;
+;  A[0] = 2;
+;
+;  constant_condition();
+;
+;  return A[0];
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+@A = common global [1 x i32] zeroinitializer, align 4 ; <[1 x i32]*> [#uses=1]
+
+define void @constant_condition() nounwind {
+bb:
+  %tmp = icmp eq i32 0, 0                         ; <i1> [#uses=0]
+  br i1 true, label %bb1, label %bb2
+
+bb1:                                              ; preds = %bb
+  store i32 0, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @A, i32 0, i32 0)
+  br label %bb3
+
+bb2:                                              ; preds = %bb
+  store i32 1, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @A, i32 0, i32 0)
+  br label %bb3
+
+bb3:                                              ; preds = %bb2, %bb1
+  ret void
+}
+
+define i32 @main() nounwind {
+bb:
+  store i32 2, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @A, i32 0, i32 0)
+  call void @constant_condition()
+  %tmp = load i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @A, i32 0, i32 0) ; <i32> [#uses=1]
+  ret i32 %tmp
+}
+
+
+; CHECK: Stmt_bb1();
diff --git a/final/test/Isl/CodeGen/create-conditional-scop.ll b/final/test/Isl/CodeGen/create-conditional-scop.ll
new file mode 100644
index 0000000..44b2042
--- /dev/null
+++ b/final/test/Isl/CodeGen/create-conditional-scop.ll
@@ -0,0 +1,32 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -verify-loop-info < %s -S | FileCheck %s
+
+target datalayout = "e-p:32:32:32-i64:64:64-i32:32:32-i16:16:16-i1:32:32-f64:64:64-f32:32:32-a0:0-n32"
+
+@A = common global [1536 x float] zeroinitializer
+
+; This test case used to fail, because we did not add the newly generated basic
+; block %polly.start as a basic block to the surrounding loop.
+define void @foo() nounwind {
+entry:
+  br i1 undef, label %while.cond14.preheader, label %for.body7.single_entry.single_entry
+
+while.cond14.preheader:                           ; preds = %for.inc02, %for.body7.single_entry.single_entry, %entry
+  ret void
+
+for.body7.single_entry.single_entry:              ; preds = %for.inc02, %entry
+  br i1 undef, label %while.cond14.preheader, label %while.body
+
+while.body:                                       ; preds = %while.body, %for.body7.single_entry.single_entry
+  %indvar35 = phi i32 [ %0, %while.body ], [ 0, %for.body7.single_entry.single_entry ]
+  %ptr = getelementptr [1536 x float], [1536 x float]* @A, i64 0, i32 %indvar35
+  store float undef, float* %ptr
+  %0 = add i32 %indvar35, 1
+  %exitcond2 = icmp eq i32 %0, 42
+  br i1 %exitcond2, label %for.inc02, label %while.body
+
+for.inc02:                                        ; preds = %while.body
+  br i1 undef, label %while.cond14.preheader, label %for.body7.single_entry.single_entry
+}
+
+; CHECK: polly.split_new_and_old
+; CHECK: br i1 true, label %polly.start, label %while.body
diff --git a/final/test/Isl/CodeGen/dead_invariant_load_instruction_referenced_by_parameter_1.ll b/final/test/Isl/CodeGen/dead_invariant_load_instruction_referenced_by_parameter_1.ll
new file mode 100644
index 0000000..87c09a7
--- /dev/null
+++ b/final/test/Isl/CodeGen/dead_invariant_load_instruction_referenced_by_parameter_1.ll
@@ -0,0 +1,127 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+;
+; Check we do not crash even though the dead %tmp8 is referenced by a parameter
+; and we do not pre-load it (as it is dead).
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.hoge = type { %struct.widget*, i32, i32, i32, %struct.hoge*, %struct.hoge*, %struct.barney, %struct.ham, %struct.wombat }
+%struct.widget = type { i32, i32, i32, i32, %struct.quux* }
+%struct.quux = type { i8*, i32, i32, i32, %struct.hoge.0 }
+%struct.hoge.0 = type { [2 x i64] }
+%struct.barney = type { %struct.hoge* }
+%struct.ham = type { i32 }
+%struct.wombat = type { %struct.hoge** }
+%struct.foo = type { %struct.wibble*, %struct.wibble*, i32, i32, i32, %struct.hoge.2, %struct.blam, %struct.wombat.5, i16, i8*, i8*, i16, i8*, i16, i16*, i16, %struct.blam.6**, i16, %struct.foo.7**, i8*, i16, i8**, i8* }
+%struct.wibble = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct.foo.1*, %struct.wibble*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] }
+%struct.foo.1 = type { %struct.foo.1*, %struct.wibble*, i32 }
+%struct.hoge.2 = type { i16, i16 }
+%struct.blam = type { i16, %struct.barney.3* }
+%struct.barney.3 = type { i8, %struct.foo.4 }
+%struct.foo.4 = type { i64 }
+%struct.wombat.5 = type { i16 }
+%struct.blam.6 = type <{ %struct.wombat.5, [6 x i8], i8*, i8*, i32, i16, [2 x i8] }>
+%struct.foo.7 = type { %struct.wombat.5, i8*, i8*, i8, i8, i32, i8*, i16, %struct.bar*, i16, %struct.barney.9*, i16, %struct.hoge.10*, i8**, i8**, i32*, i32*, i8*, i32, i32, i32* }
+%struct.bar = type { i32, i16, i16, %struct.wibble.8, i16, %struct.hoge* }
+%struct.wibble.8 = type { i32 }
+%struct.barney.9 = type { i16, i16 }
+%struct.hoge.10 = type { i16, i16, i16, i16, i16 }
+%struct.bar.11 = type { i64, i64 }
+
+@global = external global i32, align 4
+@global1 = external global i32, align 4
+@global2 = external global i8*, align 8
+@global3 = external global %struct.hoge**, align 8
+@global4 = external global %struct.hoge**, align 8
+
+; Function Attrs: uwtable
+define i32 @foo(%struct.foo* %arg) #0 personality i8* bitcast (i32 (...)* @blam to i8*) {
+bb:
+  br label %bb3
+
+bb3:                                              ; preds = %bb
+  %tmp = load i32, i32* @global, align 4, !tbaa !1
+  %tmp4 = add i32 %tmp, -1
+  %tmp5 = icmp eq i32 0, 0
+  br i1 %tmp5, label %bb12, label %bb6
+
+bb6:                                              ; preds = %bb3
+  br label %bb7
+
+bb7:                                              ; preds = %bb7, %bb6
+  %tmp8 = load i32, i32* @global, align 4, !tbaa !1
+  %tmp9 = and i32 %tmp8, 3
+  %tmp10 = icmp eq i32 %tmp9, 0
+  br i1 %tmp10, label %bb11, label %bb7
+
+bb11:                                             ; preds = %bb7
+  br label %bb12
+
+bb12:                                             ; preds = %bb11, %bb3
+  invoke void @zot(%struct.hoge* nonnull undef, i32 %tmp4, i32 undef, i32 9, i32 0, i32 39, %struct.hoge* undef, i32 undef, i32 undef, %struct.bar.11* nonnull undef)
+          to label %bb13 unwind label %bb17
+
+bb13:                                             ; preds = %bb12
+  br i1 undef, label %bb16, label %bb14
+
+bb14:                                             ; preds = %bb13
+  br label %bb19
+
+bb15:                                             ; preds = %bb19
+  br label %bb16
+
+bb16:                                             ; preds = %bb15, %bb13
+  ret i32 0
+
+bb17:                                             ; preds = %bb12
+  %tmp18 = landingpad { i8*, i32 }
+          cleanup
+  resume { i8*, i32 } %tmp18
+
+bb19:                                             ; preds = %bb19, %bb14
+  br i1 undef, label %bb15, label %bb19
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone
+declare { i64, i1 } @llvm.umul.with.overflow.i64(i64, i64) #2
+
+; Function Attrs: nobuiltin
+declare noalias i8* @eggs(i64) #3
+
+; Function Attrs: nobuiltin
+declare noalias i8* @bar(i64) #3
+
+; Function Attrs: uwtable
+declare void @zot(%struct.hoge*, i32, i32, i32, i32, i32, %struct.hoge*, i32, i32, %struct.bar.11*) unnamed_addr #0 align 2
+
+declare i32 @blam(...)
+
+; Function Attrs: nobuiltin nounwind
+declare void @zot5(i8*) #4
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end(i64, i8* nocapture) #1
+
+; Function Attrs: uwtable
+declare i32 @eggs6(%struct.foo*) #0
+
+; Function Attrs: nounwind uwtable
+declare void @eggs7(%struct.widget*, i32, i32, i32) unnamed_addr #5 align 2
+
+attributes #0 = { uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { argmemonly nounwind }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nobuiltin "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #4 = { nobuiltin nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #5 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 252700) (llvm/trunk 252705)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"int", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/Isl/CodeGen/dead_invariant_load_instruction_referenced_by_parameter_2.ll b/final/test/Isl/CodeGen/dead_invariant_load_instruction_referenced_by_parameter_2.ll
new file mode 100644
index 0000000..4aac027
--- /dev/null
+++ b/final/test/Isl/CodeGen/dead_invariant_load_instruction_referenced_by_parameter_2.ll
@@ -0,0 +1,186 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+;
+; Check we do not crash even though there is a dead load that is referenced by
+; a parameter and we do not pre-load it (as it is dead).
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@REGISTER = external global [10 x i32], align 16
+
+; Function Attrs: nounwind uwtable
+define void @FORMAT3_4() #0 {
+entry:
+  %INSTR = alloca [32 x i32], align 16
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %0 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @REGISTER, i64 0, i64 8), align 16
+  %add = add nsw i32 %0, 2
+  %cmp = icmp sgt i32 %add, 1048575
+  br i1 %cmp, label %if.end.36, label %if.else
+
+if.else:                                          ; preds = %entry.split
+  call void (i32, i32, i32*, ...) bitcast (void (...)* @BYTES_TO_BITS to void (i32, i32, i32*, ...)*)(i32 undef, i32 1, i32* undef) #2
+  %1 = load i32, i32* undef, align 4
+  %cmp14 = icmp eq i32 %1, 1
+  br i1 %cmp14, label %land.lhs.true, label %if.end.36
+
+land.lhs.true:                                    ; preds = %if.else
+  %arrayidx16 = getelementptr inbounds [32 x i32], [32 x i32]* %INSTR, i64 0, i64 6
+  br i1 false, label %land.lhs.true.19, label %if.then.23
+
+land.lhs.true.19:                                 ; preds = %land.lhs.true
+  %arrayidx20 = getelementptr inbounds [32 x i32], [32 x i32]* %INSTR, i64 0, i64 7
+  br i1 false, label %if.end.36, label %if.then.23
+
+if.then.23:                                       ; preds = %land.lhs.true.19, %land.lhs.true
+  br i1 false, label %if.end.36, label %if.else.28
+
+if.else.28:                                       ; preds = %if.then.23
+  br label %if.end.36
+
+if.end.36:                                        ; preds = %if.else.28, %if.then.23, %land.lhs.true.19, %if.else, %entry.split
+  %RANGE_ERROR.0 = phi i1 [ false, %land.lhs.true.19 ], [ false, %if.else.28 ], [ false, %if.else ], [ true, %entry.split ], [ true, %if.then.23 ]
+  br i1 %RANGE_ERROR.0, label %if.then.37, label %if.end.38
+
+if.then.37:                                       ; preds = %if.end.36
+  br label %return
+
+if.end.38:                                        ; preds = %if.end.36
+  br i1 undef, label %land.lhs.true.43, label %if.else.50
+
+land.lhs.true.43:                                 ; preds = %if.end.38
+  br i1 undef, label %if.then.47, label %if.else.50
+
+if.then.47:                                       ; preds = %land.lhs.true.43
+  br label %if.end.107
+
+if.else.50:                                       ; preds = %land.lhs.true.43, %if.end.38
+  br i1 undef, label %if.then.53, label %if.else.89
+
+if.then.53:                                       ; preds = %if.else.50
+  br i1 undef, label %land.lhs.true.59, label %if.end.64
+
+land.lhs.true.59:                                 ; preds = %if.then.53
+  br i1 undef, label %if.then.63, label %if.end.64
+
+if.then.63:                                       ; preds = %land.lhs.true.59
+  br label %return
+
+if.end.64:                                        ; preds = %land.lhs.true.59, %if.then.53
+  br i1 undef, label %if.then.80, label %if.end.107
+
+if.then.80:                                       ; preds = %if.end.64
+  br i1 undef, label %if.then.83, label %if.else.85
+
+if.then.83:                                       ; preds = %if.then.80
+  br label %if.end.107
+
+if.else.85:                                       ; preds = %if.then.80
+  br label %if.end.107
+
+if.else.89:                                       ; preds = %if.else.50
+  br i1 undef, label %if.then.96, label %lor.lhs.false
+
+lor.lhs.false:                                    ; preds = %if.else.89
+  br i1 undef, label %if.then.96, label %if.end.97
+
+if.then.96:                                       ; preds = %lor.lhs.false, %if.else.89
+  br label %return
+
+if.end.97:                                        ; preds = %lor.lhs.false
+  br i1 undef, label %if.then.103, label %if.end.107
+
+if.then.103:                                      ; preds = %if.end.97
+  br label %if.end.107
+
+if.end.107:                                       ; preds = %if.then.103, %if.end.97, %if.else.85, %if.then.83, %if.end.64, %if.then.47
+  br i1 undef, label %land.lhs.true.111, label %if.end.142
+
+land.lhs.true.111:                                ; preds = %if.end.107
+  br i1 undef, label %if.then.115, label %if.end.142
+
+if.then.115:                                      ; preds = %land.lhs.true.111
+  br i1 undef, label %if.then.118, label %return
+
+if.then.118:                                      ; preds = %if.then.115
+  br i1 undef, label %if.then.125, label %for.cond.preheader
+
+for.cond.preheader:                               ; preds = %if.then.118
+  br i1 undef, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:                                   ; preds = %for.cond.preheader
+  br label %for.body
+
+if.then.125:                                      ; preds = %if.then.118
+  br label %return
+
+for.body:                                         ; preds = %for.body, %for.body.lr.ph
+  br i1 undef, label %for.body, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %for.cond.preheader
+  br label %return
+
+if.end.142:                                       ; preds = %land.lhs.true.111, %if.end.107
+  br i1 undef, label %land.lhs.true.146, label %if.end.206
+
+land.lhs.true.146:                                ; preds = %if.end.142
+  br i1 undef, label %if.then.150, label %if.end.206
+
+if.then.150:                                      ; preds = %land.lhs.true.146
+  br i1 undef, label %if.then.157, label %lor.lhs.false.153
+
+lor.lhs.false.153:                                ; preds = %if.then.150
+  br i1 undef, label %if.then.157, label %if.end.158
+
+if.then.157:                                      ; preds = %lor.lhs.false.153, %if.then.150
+  br label %return
+
+if.end.158:                                       ; preds = %lor.lhs.false.153
+  br i1 undef, label %if.then.179, label %return
+
+if.then.179:                                      ; preds = %if.end.158
+  br i1 undef, label %if.then.183, label %for.cond.185.preheader
+
+for.cond.185.preheader:                           ; preds = %if.then.179
+  br i1 undef, label %for.body.188.lr.ph, label %for.end.198
+
+for.body.188.lr.ph:                               ; preds = %for.cond.185.preheader
+  br label %for.body.188
+
+if.then.183:                                      ; preds = %if.then.179
+  br label %return
+
+for.body.188:                                     ; preds = %for.body.188, %for.body.188.lr.ph
+  br i1 undef, label %for.body.188, label %for.cond.185.for.end.198_crit_edge
+
+for.cond.185.for.end.198_crit_edge:               ; preds = %for.body.188
+  br label %for.end.198
+
+for.end.198:                                      ; preds = %for.cond.185.for.end.198_crit_edge, %for.cond.185.preheader
+  br label %return
+
+if.end.206:                                       ; preds = %land.lhs.true.146, %if.end.142
+  br i1 undef, label %land.lhs.true.210, label %return
+
+land.lhs.true.210:                                ; preds = %if.end.206
+  br i1 undef, label %if.then.214, label %return
+
+if.then.214:                                      ; preds = %land.lhs.true.210
+  br i1 undef, label %if.then.219, label %return
+
+if.then.219:                                      ; preds = %if.then.214
+  br label %return
+
+return:                                           ; preds = %if.then.219, %if.then.214, %land.lhs.true.210, %if.end.206, %for.end.198, %if.then.183, %if.end.158, %if.then.157, %for.end, %if.then.125, %if.then.115, %if.then.96, %if.then.63, %if.then.37
+  ret void
+}
+
+declare void @BYTES_TO_BITS(...) #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="haswell" "target-features"="+aes,+avx,+avx2,+bmi,+bmi2,+cmov,+cx16,+f16c,+fma,+fsgsbase,+fxsr,+hle,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+rdrnd,+rtm,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+xsave,+xsaveopt,-adx,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512pf,-avx512vl,-fma4,-prfchw,-rdseed,-sha,-sse4a,-tbm,-xop,-xsavec,-xsaves" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="haswell" "target-features"="+aes,+avx,+avx2,+bmi,+bmi2,+cmov,+cx16,+f16c,+fma,+fsgsbase,+fxsr,+hle,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+rdrnd,+rtm,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+xsave,+xsaveopt,-adx,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512pf,-avx512vl,-fma4,-prfchw,-rdseed,-sha,-sse4a,-tbm,-xop,-xsavec,-xsaves" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind }
diff --git a/final/test/Isl/CodeGen/debug-intrinsics.ll b/final/test/Isl/CodeGen/debug-intrinsics.ll
new file mode 100644
index 0000000..a769f9e
--- /dev/null
+++ b/final/test/Isl/CodeGen/debug-intrinsics.ll
@@ -0,0 +1,85 @@
+; RUN: opt %loadPolly \
+; RUN: -polly-analyze-read-only-scalars=false -polly-codegen -S < %s | \
+; RUN: FileCheck %s
+
+; RUN: opt %loadPolly \
+; RUN: -polly-analyze-read-only-scalars=true -polly-codegen -S < %s | \
+; RUN: FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @foo(float* %A, i64 %N) #0 !dbg !4 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  tail call void @llvm.dbg.value(metadata float* %A, metadata !14, metadata !DIExpression()), !dbg !15
+  tail call void @llvm.dbg.value(metadata i64 %N, metadata !16, metadata !DIExpression()), !dbg !15
+  tail call void @llvm.dbg.value(metadata i64 0, metadata !18, metadata !DIExpression()), !dbg !20
+  %cmp1 = icmp sgt i64 %N, 0, !dbg !20
+  br i1 %cmp1, label %for.body.lr.ph, label %for.end, !dbg !20
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  br label %for.body, !dbg !20
+
+for.body:                                         ; preds = %for.body.lr.ph, %for.body
+  %0 = phi i64 [ 0, %for.body.lr.ph ], [ %1, %for.body ], !dbg !21
+  %arrayidx = getelementptr float, float* %A, i64 %0, !dbg !21
+  %conv = sitofp i64 %0 to float, !dbg !21
+  store float %conv, float* %arrayidx, align 4, !dbg !21
+  %1 = add nsw i64 %0, 1, !dbg !20
+  tail call void @llvm.dbg.value(metadata i64 %1, metadata !18, metadata !DIExpression()), !dbg !20
+  %exitcond = icmp ne i64 %1, %N, !dbg !20
+  br i1 %exitcond, label %for.body, label %for.cond.for.end_crit_edge, !dbg !20
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end, !dbg !20
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  ret void, !dbg !22
+}
+
+; CHECK: polly.split_new_and_old:
+
+; CHECK: tail call void @llvm.dbg.value
+; CHECK: tail call void @llvm.dbg.value
+; CHECK: tail call void @llvm.dbg.value
+; CHECK: tail call void @llvm.dbg.value
+; CHECK-NOT: tail call void @llvm.dbg.value
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!11, !12}
+!llvm.ident = !{!13}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.5 ", isOptimized: false, emissionKind: 0, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!1 = !DIFile(filename: "loop.c", directory: "/home/grosser/Projects/polly/git/tools/polly")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "foo", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 1, file: !1, scope: !5, type: !6, variables: !2)
+!5 = !DIFile(filename: "loop.c", directory: "/home/grosser/Projects/polly/git/tools/polly")
+!6 = !DISubroutineType(types: !7)
+!7 = !{null, !8, !10}
+!8 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, baseType: !9)
+!9 = !DIBasicType(tag: DW_TAG_base_type, name: "float", size: 32, align: 32, encoding: DW_ATE_float)
+!10 = !DIBasicType(tag: DW_TAG_base_type, name: "long int", size: 64, align: 64, encoding: DW_ATE_signed)
+!11 = !{i32 2, !"Dwarf Version", i32 4}
+!12 = !{i32 1, !"Debug Info Version", i32 3}
+!13 = !{!"clang version 3.5 "}
+!14 = !DILocalVariable(name: "A", line: 1, arg: 1, scope: !4, file: !5, type: !8)
+!15 = !DILocation(line: 1, scope: !4)
+!16 = !DILocalVariable(name: "N", line: 1, arg: 2, scope: !4, file: !5, type: !10)
+!17 = !{i64 0}
+!18 = !DILocalVariable(name: "i", line: 2, scope: !19, file: !5, type: !10)
+!19 = distinct !DILexicalBlock(line: 2, column: 0, file: !1, scope: !4)
+!20 = !DILocation(line: 2, scope: !19)
+!21 = !DILocation(line: 3, scope: !19)
+!22 = !DILocation(line: 4, scope: !4)
diff --git a/final/test/Isl/CodeGen/dominance_problem_after_early_codegen_bailout.ll b/final/test/Isl/CodeGen/dominance_problem_after_early_codegen_bailout.ll
new file mode 100644
index 0000000..2d1f6c4
--- /dev/null
+++ b/final/test/Isl/CodeGen/dominance_problem_after_early_codegen_bailout.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-codegen -analyze < %s
+;
+; This caused dominance problems at some point as we do bail out during
+; code generation. Just verify it runs through.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.hashheader.0.5.10.165.180.185 = type { i16, i16, i16, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, [5 x i8], [13 x i8], i8, i8, i8, [228 x i16], [228 x i8], [228 x i8], [228 x i8], [228 x i8], [228 x i8], [228 x i8], [128 x i8], [100 x [11 x i8]], [100 x i32], [100 x i32], i16 }
+
+@hashheader = external global %struct.hashheader.0.5.10.165.180.185, align 4
+
+; Function Attrs: nounwind uwtable
+define void @strtoichar(i8* %in) #0 {
+entry:
+  br i1 undef, label %land.rhs, label %for.end
+
+land.rhs:                                         ; preds = %for.inc, %entry
+  %in.addr.012 = phi i8* [ undef, %for.inc ], [ %in, %entry ]
+  %0 = load i8, i8* %in.addr.012, align 1
+  br i1 undef, label %for.end, label %for.body
+
+for.body:                                         ; preds = %land.rhs
+  %idxprom = zext i8 %0 to i64
+  %arrayidx = getelementptr inbounds %struct.hashheader.0.5.10.165.180.185, %struct.hashheader.0.5.10.165.180.185* @hashheader, i64 0, i32 27, i64 %idxprom
+  %1 = load i8, i8* %arrayidx, align 1
+  %tobool = icmp eq i8 %1, 0
+  br i1 %tobool, label %if.else, label %land.rhs.7
+
+land.rhs.7:                                       ; preds = %for.body
+  tail call void @stringcharlen()
+  br i1 undef, label %if.then, label %if.else
+
+if.then:                                          ; preds = %land.rhs.7
+  br label %for.inc
+
+if.else:                                          ; preds = %land.rhs.7, %for.body
+  %2 = load i8, i8* %in.addr.012, align 1
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.else, %if.then
+  %len.1 = phi i32 [ 0, %if.else ], [ undef, %if.then ]
+  br i1 undef, label %land.rhs, label %for.end
+
+for.end:                                          ; preds = %for.inc, %land.rhs, %entry
+  ret void
+}
+
+; Function Attrs: nounwind uwtable
+declare void @stringcharlen() #0
diff --git a/final/test/Isl/CodeGen/empty_domain_in_context.ll b/final/test/Isl/CodeGen/empty_domain_in_context.ll
new file mode 100644
index 0000000..57b583d
--- /dev/null
+++ b/final/test/Isl/CodeGen/empty_domain_in_context.ll
@@ -0,0 +1,86 @@
+; RUN: opt %loadPolly -polly-optree -polly-opt-isl -polly-codegen -S < %s | FileCheck %s
+;
+; llvm.org/PR35362
+; isl codegen does not allow to generate isl_ast_expr from pw_aff which have an
+; empty domain. This happens in this case because the pw_aff's domain is
+; excluded by the SCoP's parameter context.
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+
+@c = external local_unnamed_addr global i8
+@a = external local_unnamed_addr global i16
+@b = external local_unnamed_addr global i8
+
+define void @fn1() {
+entry:
+  %a.promoted = load i16, i16* @a
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond3.for.end_crit_edge, %entry
+  %inc.lcssa17 = phi i16 [ 0, %for.cond3.for.end_crit_edge ], [ %a.promoted, %entry ]
+  br label %for.body
+
+for.body:                                         ; preds = %for.cond
+  %conv = zext i16 %inc.lcssa17 to i32
+  %div = udiv i32 -286702568, %conv
+  br i1 undef, label %if.end, label %if.then
+
+if.then:                                          ; preds = %for.body
+  unreachable
+
+if.end:                                           ; preds = %for.body
+  br label %for.body5.lr.ph
+
+for.body5.lr.ph:                                  ; preds = %if.end
+  %tmp = load i8, i8* @b, align 1
+  %cmp = icmp eq i32 %div, 1
+  br i1 %cmp, label %for.body5.lr.ph.split.us, label %for.body5.lr.ph.split
+
+for.body5.lr.ph.split.us:                         ; preds = %for.body5.lr.ph
+  br label %lor.end.us.peel
+
+lor.end.us.peel:                                  ; preds = %for.body5.lr.ph.split.us
+  %inc.us.peel = add i16 %inc.lcssa17, 1
+  br i1 false, label %for.cond3.for.end_crit_edge, label %for.body5.us.peel.next
+
+for.body5.us.peel.next:                           ; preds = %lor.end.us.peel
+  br label %lor.end.us
+
+lor.end.us:                                       ; preds = %lor.end.us, %for.body5.us.peel.next
+  %tmp1 = phi i16 [ %inc.us.peel, %for.body5.us.peel.next ], [ %inc.us, %lor.end.us ]
+  %inc.us = add i16 %tmp1, 1
+  %tobool4.us = icmp eq i16 %inc.us, 0
+  br i1 %tobool4.us, label %for.cond3.for.end_crit_edge, label %lor.end.us
+
+for.body5.lr.ph.split:                            ; preds = %for.body5.lr.ph
+  br label %lor.end.peel
+
+lor.end.peel:                                     ; preds = %for.body5.lr.ph.split
+  %inc.peel = add i16 %inc.lcssa17, 1
+  br i1 false, label %for.cond3.for.end_crit_edge, label %for.body5.peel.next
+
+for.body5.peel.next:                              ; preds = %lor.end.peel
+  br label %lor.end
+
+lor.end:                                          ; preds = %lor.end, %for.body5.peel.next
+  %tmp2 = phi i16 [ %inc.peel, %for.body5.peel.next ], [ %inc, %lor.end ]
+  %inc = add i16 %tmp2, 1
+  %tobool4 = icmp eq i16 %inc, 0
+  br i1 %tobool4, label %for.cond3.for.end_crit_edge, label %lor.end
+
+for.cond3.for.end_crit_edge:                      ; preds = %lor.end, %lor.end.peel, %lor.end.us, %lor.end.us.peel
+  %tmp3 = phi i8 [ %tmp, %lor.end.us.peel ], [ %tmp, %lor.end.peel ], [ %tmp, %lor.end.us ], [ %tmp, %lor.end ]
+  store i8 4, i8* @c
+  br label %for.cond
+}
+
+
+; The reference to @b should have been generated from an isl_ast_expr.
+; Because isl is unable to generate it in this case, the code generator
+; resorted to use the pointer argument of %tmp = load ... .
+; It is not important since this code will never be executed.
+
+; CHECK:      polly.stmt.lor.end.us.peel:
+; CHECK-NEXT:   %tmp_p_scalar_1 = load i8, i8* @b
+; CHECK-NEXT:   store i8 %tmp_p_scalar_1, i8* %tmp3.phiops
+; CHECK-NEXT:   br label %polly.merge
diff --git a/final/test/Isl/CodeGen/entry_with_trivial_phi.ll b/final/test/Isl/CodeGen/entry_with_trivial_phi.ll
new file mode 100644
index 0000000..4398d15
--- /dev/null
+++ b/final/test/Isl/CodeGen/entry_with_trivial_phi.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s
+;
+; The entry of this scop's simple region (entry.split => for.end) has an trivial
+; PHI node. LCSSA may create such PHI nodes. This is a breakdown of this case in
+; the function 'Laguerre_With_Deflation' of oggenc from LLVM's test-suite.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @test(i64 %n, float* noalias nonnull %A, float %a) {
+entry:
+  br label %entry.split
+
+; CHECK-LABEL: %polly.split_new_and_old
+; CHECK-NEXT:    store float %a, float* %b.phiops
+
+; CHECK-LABEL: polly.stmt.entry.split
+; CHECK-NEXT:    %b.phiops.reload = load float, float* %b.phiops
+
+entry.split:
+  %b = phi float [ %a, %entry ]
+  store float %b, float* %A, align 4
+  %cmp2 = icmp slt i64 %n, 5
+  br i1 %cmp2, label %for.cond, label %for.end
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry.split ], [ %add, %for.inc ]
+  %cmp = icmp slt i64 %i.0, %n
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  store float %a, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %add = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/entry_with_trivial_phi_other_bb.ll b/final/test/Isl/CodeGen/entry_with_trivial_phi_other_bb.ll
new file mode 100644
index 0000000..6d83a0a
--- /dev/null
+++ b/final/test/Isl/CodeGen/entry_with_trivial_phi_other_bb.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; The entry of this scop's simple region (entry.split => for.end) has an trivial
+; PHI node that is used in a different of the scop region. LCSSA may create such
+; PHI nodes. This is a breakdown of this case in the function 'mp_unexp_sub' of
+; pifft from LLVM's test-suite.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @test(i64 %n, float* noalias nonnull %A, float %a) {
+entry:
+  br label %entry.split
+
+; CHECK-LABEL: polly.start:
+; CHECK:         store float %a, float* %b.phiops
+
+entry.split:
+  %b = phi float [ %a, %entry ]
+  %cmp2 = icmp slt i64 %n, 5
+  br i1 %cmp2, label %for.cond, label %for.end
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry.split ], [ %add, %for.inc ]
+  %cmp = icmp slt i64 %i.0, %n
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  store float %b, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %add = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/error-stmt-in-non-affine-region.ll b/final/test/Isl/CodeGen/error-stmt-in-non-affine-region.ll
new file mode 100644
index 0000000..a386718
--- /dev/null
+++ b/final/test/Isl/CodeGen/error-stmt-in-non-affine-region.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+; XFAIL: *
+;
+; CHECK-LABEL: polly.stmt.if.then:
+; CHECK-NEXT:   unreachable
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < 1024; i++)
+;        if (i == N) {
+;          if (A[i])
+;            abort();
+;          else
+;            A[i] = i;
+;        }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i64 %N) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4
+  %cmp.outer = icmp eq i64 %indvars.iv, %N
+  br i1 %cmp.outer, label %if.then.outer, label %for.inc
+
+if.then.outer:
+  %tobool = icmp eq i32 %tmp, 0
+  br i1 %tobool, label %if.else, label %if.then
+
+if.then:                                          ; preds = %for.body
+  call void @abort()
+  unreachable
+
+if.else:                                          ; preds = %for.body
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = trunc i64 %indvars.iv to i32
+  store i32 %tmp1, i32* %arrayidx2, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare void @abort()
diff --git a/final/test/Isl/CodeGen/error_block_contains_invalid_memory_access.ll b/final/test/Isl/CodeGen/error_block_contains_invalid_memory_access.ll
new file mode 100644
index 0000000..365c3d1
--- /dev/null
+++ b/final/test/Isl/CodeGen/error_block_contains_invalid_memory_access.ll
@@ -0,0 +1,78 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.img_par.12.33.54.243.348.558.600.852.999.1209.2070.2154.2175.2238.2259.2280.2322 = type { i32, i32, i32, i32, i32*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [16 x [16 x i16]], [6 x [32 x i32]], [16 x [16 x i32]], [4 x [12 x [4 x [4 x i32]]]], [16 x i32], i8**, i32*, i32***, i32**, i32, i32, i32, i32, %struct.Slice.8.29.50.239.344.554.596.848.995.1205.2066.2150.2171.2234.2255.2276.2318*, %struct.macroblock.9.30.51.240.345.555.597.849.996.1206.2067.2151.2172.2235.2256.2277.2319*, i32, i32, i32, i32, i32, i32, %struct.DecRefPicMarking_s.10.31.52.241.346.556.598.850.997.1207.2068.2152.2173.2236.2257.2278.2320*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [3 x i32], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32***, i32***, i32****, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [3 x [2 x i32]], [3 x [2 x i32]], i32, i32, i64, i64, %struct.timeb.11.32.53.242.347.557.599.851.998.1208.2069.2153.2174.2237.2258.2279.2321, %struct.timeb.11.32.53.242.347.557.599.851.998.1208.2069.2153.2174.2237.2258.2279.2321, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }
+%struct.Slice.8.29.50.239.344.554.596.848.995.1205.2066.2150.2171.2234.2255.2276.2318 = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, %struct.datapartition.3.24.45.234.339.549.591.843.990.1200.2061.2145.2166.2229.2250.2271.2313*, %struct.MotionInfoContexts.5.26.47.236.341.551.593.845.992.1202.2063.2147.2168.2231.2252.2273.2315*, %struct.TextureInfoContexts.6.27.48.237.342.552.594.846.993.1203.2064.2148.2169.2232.2253.2274.2316*, i32, i32*, i32*, i32*, i32, i32*, i32*, i32*, i32 (%struct.img_par.12.33.54.243.348.558.600.852.999.1209.2070.2154.2175.2238.2259.2280.2322*, %struct.inp_par.7.28.49.238.343.553.595.847.994.1204.2065.2149.2170.2233.2254.2275.2317*)*, i32, i32, i32, i32 }
+%struct.datapartition.3.24.45.234.339.549.591.843.990.1200.2061.2145.2166.2229.2250.2271.2313 = type { %struct.Bitstream.0.21.42.231.336.546.588.840.987.1197.2058.2142.2163.2226.2247.2268.2310*, %struct.DecodingEnvironment.1.22.43.232.337.547.589.841.988.1198.2059.2143.2164.2227.2248.2269.2311, i32 (%struct.syntaxelement.2.23.44.233.338.548.590.842.989.1199.2060.2144.2165.2228.2249.2270.2312*, %struct.img_par.12.33.54.243.348.558.600.852.999.1209.2070.2154.2175.2238.2259.2280.2322*, %struct.datapartition.3.24.45.234.339.549.591.843.990.1200.2061.2145.2166.2229.2250.2271.2313*)* }
+%struct.Bitstream.0.21.42.231.336.546.588.840.987.1197.2058.2142.2163.2226.2247.2268.2310 = type { i32, i32, i32, i32, i8*, i32 }
+%struct.DecodingEnvironment.1.22.43.232.337.547.589.841.988.1198.2059.2143.2164.2227.2248.2269.2311 = type { i32, i32, i32, i32, i32, i8*, i32* }
+%struct.syntaxelement.2.23.44.233.338.548.590.842.989.1199.2060.2144.2165.2228.2249.2270.2312 = type { i32, i32, i32, i32, i32, i32, i32, i32, void (i32, i32, i32*, i32*)*, void (%struct.syntaxelement.2.23.44.233.338.548.590.842.989.1199.2060.2144.2165.2228.2249.2270.2312*, %struct.img_par.12.33.54.243.348.558.600.852.999.1209.2070.2154.2175.2238.2259.2280.2322*, %struct.DecodingEnvironment.1.22.43.232.337.547.589.841.988.1198.2059.2143.2164.2227.2248.2269.2311*)* }
+%struct.MotionInfoContexts.5.26.47.236.341.551.593.845.992.1202.2063.2147.2168.2231.2252.2273.2315 = type { [4 x [11 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314]], [2 x [9 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314]], [2 x [10 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314]], [2 x [6 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314]], [4 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314], [4 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314], [3 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314] }
+%struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314 = type { i16, i8 }
+%struct.TextureInfoContexts.6.27.48.237.342.552.594.846.993.1203.2064.2148.2169.2232.2253.2274.2316 = type { [2 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314], [4 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314], [3 x [4 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314]], [10 x [4 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314]], [10 x [15 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314]], [10 x [15 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314]], [10 x [5 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314]], [10 x [5 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314]], [10 x [15 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314]], [10 x [15 x %struct.BiContextType.4.25.46.235.340.550.592.844.991.1201.2062.2146.2167.2230.2251.2272.2314]] }
+%struct.inp_par.7.28.49.238.343.553.595.847.994.1204.2065.2149.2170.2233.2254.2275.2317 = type { [1000 x i8], [1000 x i8], [1000 x i8], i32, i32, i32, i32, i32, i32, i32, i32 }
+%struct.macroblock.9.30.51.240.345.555.597.849.996.1206.2067.2151.2172.2235.2256.2277.2319 = type { i32, [2 x i32], i32, i32, %struct.macroblock.9.30.51.240.345.555.597.849.996.1206.2067.2151.2172.2235.2256.2277.2319*, %struct.macroblock.9.30.51.240.345.555.597.849.996.1206.2067.2151.2172.2235.2256.2277.2319*, i32, [2 x [4 x [4 x [2 x i32]]]], i32, i64, i64, i32, i32, [4 x i8], [4 x i8], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }
+%struct.DecRefPicMarking_s.10.31.52.241.346.556.598.850.997.1207.2068.2152.2173.2236.2257.2278.2320 = type { i32, i32, i32, i32, i32, %struct.DecRefPicMarking_s.10.31.52.241.346.556.598.850.997.1207.2068.2152.2173.2236.2257.2278.2320* }
+%struct.timeb.11.32.53.242.347.557.599.851.998.1208.2069.2153.2174.2237.2258.2279.2321 = type { i64, i16, i16, i16 }
+%struct.pix_pos.13.34.55.244.349.559.601.853.1000.1210.2071.2155.2176.2239.2260.2281.2323 = type { i32, i32, i32, i32, i32, i32 }
+
+declare void @getLuma4x4Neighbour() #0
+
+; Function Attrs: nounwind uwtable
+define void @readCBP_CABAC(%struct.img_par.12.33.54.243.348.558.600.852.999.1209.2070.2154.2175.2238.2259.2280.2322* %img) #1 {
+entry:
+  %block_a = alloca %struct.pix_pos.13.34.55.244.349.559.601.853.1000.1210.2071.2155.2176.2239.2260.2281.2323, align 4
+  %mb_data = getelementptr inbounds %struct.img_par.12.33.54.243.348.558.600.852.999.1209.2070.2154.2175.2238.2259.2280.2322, %struct.img_par.12.33.54.243.348.558.600.852.999.1209.2070.2154.2175.2238.2259.2280.2322* %img, i64 0, i32 39
+  br label %for.cond.1.preheader
+
+for.cond.1.preheader:                             ; preds = %for.inc.84, %entry
+  br label %for.body.3
+
+for.body.3:                                       ; preds = %if.end.72, %for.cond.1.preheader
+  %mb_x.056 = phi i32 [ 0, %for.cond.1.preheader ], [ undef, %if.end.72 ]
+  br i1 undef, label %if.end.35, label %if.else.14
+
+if.else.14:                                       ; preds = %for.body.3
+  br i1 undef, label %if.end.35, label %if.else.19
+
+if.else.19:                                       ; preds = %if.else.14
+  br label %if.end.35
+
+if.end.35:                                        ; preds = %if.else.19, %if.else.14, %for.body.3
+  %b.0 = zext i1 undef to i64
+  %cmp36 = icmp eq i32 %mb_x.056, 0
+  br i1 %cmp36, label %if.then.38, label %if.else.66
+
+if.then.38:                                       ; preds = %if.end.35
+  call void @getLuma4x4Neighbour() #2
+  %0 = load i32, i32* null, align 4
+  %tobool = icmp eq i32 %0, 0
+  br i1 %tobool, label %if.end.72, label %if.then.42
+
+if.then.42:                                       ; preds = %if.then.38
+  %mb_addr = getelementptr inbounds %struct.pix_pos.13.34.55.244.349.559.601.853.1000.1210.2071.2155.2176.2239.2260.2281.2323, %struct.pix_pos.13.34.55.244.349.559.601.853.1000.1210.2071.2155.2176.2239.2260.2281.2323* %block_a, i64 0, i32 1
+  %1 = load %struct.macroblock.9.30.51.240.345.555.597.849.996.1206.2067.2151.2172.2235.2256.2277.2319*, %struct.macroblock.9.30.51.240.345.555.597.849.996.1206.2067.2151.2172.2235.2256.2277.2319** %mb_data, align 8
+  %mb_type46 = getelementptr inbounds %struct.macroblock.9.30.51.240.345.555.597.849.996.1206.2067.2151.2172.2235.2256.2277.2319, %struct.macroblock.9.30.51.240.345.555.597.849.996.1206.2067.2151.2172.2235.2256.2277.2319* %1, i64 0, i32 6
+  br i1 false, label %if.end.72, label %if.else.50
+
+if.else.50:                                       ; preds = %if.then.42
+  br label %if.end.72
+
+if.else.66:                                       ; preds = %if.end.35
+  br label %if.end.72
+
+if.end.72:                                        ; preds = %if.else.66, %if.else.50, %if.then.42, %if.then.38
+  %mul73 = shl nuw nsw i64 %b.0, 1
+  br i1 undef, label %for.body.3, label %for.inc.84
+
+for.inc.84:                                       ; preds = %if.end.72
+  br i1 undef, label %for.cond.1.preheader, label %for.end.86
+
+for.end.86:                                       ; preds = %for.inc.84
+  ret void
+}
+
+attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="haswell" "target-features"="+aes,+avx,+avx2,+bmi,+bmi2,+cmov,+cx16,+f16c,+fma,+fsgsbase,+fxsr,+hle,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+rdrnd,+rtm,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+xsave,+xsaveopt,-adx,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512pf,-avx512vl,-fma4,-prfchw,-rdseed,-sha,-sse4a,-tbm,-xop,-xsavec,-xsaves" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="haswell" "target-features"="+aes,+avx,+avx2,+bmi,+bmi2,+cmov,+cx16,+f16c,+fma,+fsgsbase,+fxsr,+hle,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+rdrnd,+rtm,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+xsave,+xsaveopt,-adx,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512pf,-avx512vl,-fma4,-prfchw,-rdseed,-sha,-sse4a,-tbm,-xop,-xsavec,-xsaves" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind }
diff --git a/final/test/Isl/CodeGen/exprModDiv.ll b/final/test/Isl/CodeGen/exprModDiv.ll
new file mode 100644
index 0000000..ace61fe
--- /dev/null
+++ b/final/test/Isl/CodeGen/exprModDiv.ll
@@ -0,0 +1,91 @@
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN:     -polly-codegen -S < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN:     -polly-codegen -polly-import-jscop-postfix=pow2 \
+; RUN:     -S < %s | FileCheck %s -check-prefix=POW2
+;
+;    void exprModDiv(float *A, float *B, float *C, long N, long p) {
+;      for (long i = 0; i < N; i++)
+;        C[i] += A[i] + B[i] + A[i] + B[i + p];
+;    }
+;
+;
+; This test case changes the access functions such that the resulting index
+; expressions are modulo or division operations. We test that the code we
+; generate takes advantage of knowledge about unsigned numerators. This is
+; useful as LLVM will translate urem and udiv operations with power-of-two
+; denominators to fast bitwise and or shift operations.
+
+; A[i % 127]
+; CHECK:  %pexp.pdiv_r = urem i64 %polly.indvar, 127
+; CHECK:  %polly.access.A9 = getelementptr float, float* %A, i64 %pexp.pdiv_r
+
+; A[floor(i / 127)]
+;
+; Note: without the floor, we would create a map i -> i/127, which only contains
+;       values of i that are divisible by 127. All other values of i would not
+;       be mapped to any value. However, to generate correct code we require
+;       each value of i to indeed be mapped to a value.
+;
+; CHECK:  %pexp.p_div_q = udiv i64 %polly.indvar, 127
+; CHECK:  %polly.access.B10 = getelementptr float, float* %B, i64 %pexp.p_div_q
+
+; A[p % 128]
+; CHECK:  %polly.access.A11 = getelementptr float, float* %A, i64 0
+
+; A[p / 127]
+; CHECK:  %pexp.div = sdiv exact i64 %p, 127
+; CHECK:  %polly.access.B12 = getelementptr float, float* %B, i64 %pexp.div
+
+; A[i % 128]
+; POW2:  %pexp.pdiv_r = urem i64 %polly.indvar, 128
+; POW2:  %polly.access.A9 = getelementptr float, float* %A, i64 %pexp.pdiv_r
+
+; A[floor(i / 128)]
+; POW2:  %pexp.p_div_q = udiv i64 %polly.indvar, 128
+; POW2:  %polly.access.B10 = getelementptr float, float* %B, i64 %pexp.p_div_q
+
+; A[p % 128]
+; POW2:  %polly.access.A11 = getelementptr float, float* %A, i64 0
+
+; A[p / 128]
+; POW2:  %pexp.div = sdiv exact i64 %p, 128
+; POW2:  %polly.access.B12 = getelementptr float, float* %B, i64 %pexp.div
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @exprModDiv(float* %A, float* %B, float* %C, i64 %N, i64 %p) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp slt i64 %i.0, %N
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp = load float, float* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds float, float* %B, i64 %i.0
+  %tmp1 = load float, float* %arrayidx1, align 4
+  %add = fadd float %tmp, %tmp1
+  %arrayidx2 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp2 = load float, float* %arrayidx2, align 4
+  %add3 = fadd float %add, %tmp2
+  %padd = add nsw i64 %p, %i.0
+  %arrayidx4 = getelementptr inbounds float, float* %B, i64 %padd
+  %tmp3 = load float, float* %arrayidx4, align 4
+  %add5 = fadd float %add3, %tmp3
+  %arrayidx6 = getelementptr inbounds float, float* %C, i64 %i.0
+  %tmp4 = load float, float* %arrayidx6, align 4
+  %add7 = fadd float %tmp4, %add5
+  store float %add7, float* %arrayidx6, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/exprModDiv___%for.cond---%for.end.jscop b/final/test/Isl/CodeGen/exprModDiv___%for.cond---%for.end.jscop
new file mode 100644
index 0000000..8075513
--- /dev/null
+++ b/final/test/Isl/CodeGen/exprModDiv___%for.cond---%for.end.jscop
@@ -0,0 +1,37 @@
+{
+   "context" : "[N, p] -> {  : N >= -9223372036854775808 and N <= 9223372036854775807 and p >= -9223372036854775808 and p <= 9223372036854775807 and (p % 127) = 0}",
+   "name" : "for.cond => for.end",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[N, p] -> { Stmt_for_body[i0] -> MemRef_A[i0 % 127] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[N, p] -> { Stmt_for_body[i0] -> MemRef_B[floor(i0 / 127)] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[N, p] -> { Stmt_for_body[i0] -> MemRef_A[p % 127] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[N, p] -> { Stmt_for_body[i0] -> MemRef_B[p / 127] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[N, p] -> { Stmt_for_body[i0] -> MemRef_C[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[N, p] -> { Stmt_for_body[i0] -> MemRef_C[i0] }"
+            }
+         ],
+         "domain" : "[N, p] -> { Stmt_for_body[i0] : i0 >= 0 and N >= 1 and i0 <= -1 + N }",
+         "name" : "Stmt_for_body",
+         "schedule" : "[N, p] -> { Stmt_for_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/exprModDiv___%for.cond---%for.end.jscop.pow2 b/final/test/Isl/CodeGen/exprModDiv___%for.cond---%for.end.jscop.pow2
new file mode 100644
index 0000000..f8c14ef
--- /dev/null
+++ b/final/test/Isl/CodeGen/exprModDiv___%for.cond---%for.end.jscop.pow2
@@ -0,0 +1,37 @@
+{
+   "context" : "[N, p] -> {  : N >= -9223372036854775808 and N <= 9223372036854775807 and p >= -9223372036854775808 and p <= 9223372036854775807 and p % 128 = 0}",
+   "name" : "for.cond => for.end",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[N, p] -> { Stmt_for_body[i0] -> MemRef_A[i0 % 128] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[N, p] -> { Stmt_for_body[i0] -> MemRef_B[floor(i0 / 128)] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[N, p] -> { Stmt_for_body[i0] -> MemRef_A[p % 128] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[N, p] -> { Stmt_for_body[i0] -> MemRef_B[p / 128] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[N, p] -> { Stmt_for_body[i0] -> MemRef_C[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[N, p] -> { Stmt_for_body[i0] -> MemRef_C[i0] }"
+            }
+         ],
+         "domain" : "[N, p] -> { Stmt_for_body[i0] : i0 >= 0 and N >= 1 and i0 <= -1 + N }",
+         "name" : "Stmt_for_body",
+         "schedule" : "[N, p] -> { Stmt_for_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/fortran_array_runtime_size_generation.ll b/final/test/Isl/CodeGen/fortran_array_runtime_size_generation.ll
new file mode 100644
index 0000000..29eeb1c
--- /dev/null
+++ b/final/test/Isl/CodeGen/fortran_array_runtime_size_generation.ll
@@ -0,0 +1,77 @@
+; Check that the runtime size computation is generated for Fortran arrays.
+
+; Regular code generation backend:
+; RUN: opt %loadPolly -S -polly-detect-fortran-arrays \
+; RUN: -polly-codegen < %s | FileCheck %s
+
+; What the input fortran code should look like. NOTE: this is fake, the
+; .ll file was hand-written.
+;
+; MODULE testmod
+; USE data_parameters, ONLY : &
+; IMPLICIT NONE
+;
+; INTEGER (KIND=iintegers), ALLOCATABLE, PRIVATE  :: &
+;   arrin(:), arrout(:)
+; CONTAINS
+;
+; SUBROUTINE test()
+;   INTEGER (KIND=iintegers) :: i
+;
+;   DO i = 1, 100
+;       arrout(i) = arrin(i) * arrin(i)
+;   END DO
+; END SUBROUTINE test
+; END MODULE testmod
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i32:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
+
+%"struct.array1_real(kind=8)" = type { i8*, i32, i32, [1 x %struct.descriptor_dimension] }
+%struct.descriptor_dimension = type { i32, i32, i32 }
+
+@arrin = unnamed_addr global %"struct.array1_real(kind=8)" zeroinitializer, align 32
+@arrout = unnamed_addr global %"struct.array1_real(kind=8)" zeroinitializer, align 32
+
+; Function Attrs: nounwind uwtable
+define void @__src_soil_MOD_terra1() unnamed_addr #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %rawmemin1 = load i32*, i32** bitcast (%"struct.array1_real(kind=8)"* @arrin to i32**), align 32, !tbaa !0
+  %rawmemout2 = load i32*, i32** bitcast (%"struct.array1_real(kind=8)"* @arrout to i32**), align 32, !tbaa !0
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %indvars.iv = phi i64 [ 1, %entry.split ], [ %indvars.iv.next4, %for.body ]
+  %inslot = getelementptr inbounds i32, i32* %rawmemin1, i64 %indvars.iv
+  %inval = load i32, i32* %inslot, align 8
+  %outslot = getelementptr inbounds i32, i32* %rawmemout2, i64 %indvars.iv
+  %out = mul nsw i32 %inval, %inval
+  store i32 %out, i32* %outslot, align 8
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next4, 100
+  br i1 %exitcond, label %return, label %for.body
+
+return:                                           ; preds = %for.body
+  ret void
+}
+
+attributes #0 = { nounwind uwtable }
+
+!0 = !{!1, !1, i32 0}
+!1 = !{!"alias set 3: void*", !2}
+!2 = distinct !{!2}
+
+
+; CHECK:       %MemRef_rawmemin1_end = load i32, i32* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @arrin, i64 0, i32 3, i64 0, i32 2)
+; CHECK-NEXT:  %MemRef_rawmemin1_begin = load i32, i32* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @arrin, i64 0, i32 3, i64 0, i32 1)
+; CHECK-NEXT:  %MemRef_rawmemin1_end_begin_delta = sub nsw i32 %MemRef_rawmemin1_end, %MemRef_rawmemin1_begin
+; CHECK-NEXT:  %MemRef_rawmemin1_size = add nsw i32 %MemRef_rawmemin1_end, 1
+; CHECK-NEXT:  %MemRef_rawmemout2_end = load i32, i32* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @arrout, i64 0, i32 3, i64 0, i32 2)
+; CHECK-NEXT:  %MemRef_rawmemout2_begin = load i32, i32* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @arrout, i64 0, i32 3, i64 0, i32 1)
+; CHECK-NEXT:  %MemRef_rawmemout2_end_begin_delta = sub nsw i32 %MemRef_rawmemout2_end, %MemRef_rawmemout2_begin
+; CHECK-NEXT:  %MemRef_rawmemout2_size = add nsw i32 %MemRef_rawmemout2_end, 1
diff --git a/final/test/Isl/CodeGen/getNumberOfIterations.ll b/final/test/Isl/CodeGen/getNumberOfIterations.ll
new file mode 100644
index 0000000..dc7ad9d
--- /dev/null
+++ b/final/test/Isl/CodeGen/getNumberOfIterations.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-vectorizer=polly -polly-codegen \
+; RUN:      < %s -S | FileCheck %s
+
+; #pragma known-parallel
+; for (int c0 = 0; c0 <= min(15, N - 1); c0 += 1)
+;   Stmt_if_then(c0);
+
+; CHECK: polly.stmt.if.then:                               ; preds = %polly.loop_header
+; CHECK:   %p_conv = sitofp i64 %polly.indvar to float
+; CHECK:   %scevgep = getelementptr float, float* %A, i64 %polly.indvar
+; CHECK:   %_p_scalar_ = load float, float* %scevgep, align 4, !alias.scope !0, !noalias !2, !llvm.mem.parallel_loop_access !3
+; CHECK:   %p_add = fadd float %p_conv, %_p_scalar_
+; CHECK:   store float %p_add, float* %scevgep, align 4, !alias.scope !0, !noalias !2, !llvm.mem.parallel_loop_access !3
+
+define void @foo(float* %A, i64 %N) #0 {
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %entry, %for.inc
+  %i.02 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp1 = icmp slt i64 %i.02, %N
+  br i1 %cmp1, label %if.then, label %for.inc
+
+if.then:                                          ; preds = %for.body
+  %conv = sitofp i64 %i.02 to float
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.02
+  %0 = load float, float* %arrayidx, align 4
+  %add = fadd float %conv, %0
+  store float %add, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body, %if.then
+  %inc = add nuw nsw i64 %i.02, 1
+  %exitcond = icmp ne i64 %inc, 16
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.inc
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/hoisted_load_escapes_through_phi.ll b/final/test/Isl/CodeGen/hoisted_load_escapes_through_phi.ll
new file mode 100644
index 0000000..e8fa688
--- /dev/null
+++ b/final/test/Isl/CodeGen/hoisted_load_escapes_through_phi.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -S -polly-codegen \
+; RUN: -polly-invariant-load-hoisting=false < %s | FileCheck %s
+; RUN: opt %loadPolly -S -polly-codegen \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+; Check that we generate valid code even if the load of cont_STACKPOINTER is
+; hoisted in one SCoP and used (through the phi node %tmp2).
+;
+; CHECK: polly.start
+; CHECK: polly.start
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct1 = type { i32, %union1, %struct.2*, i32, i32 }
+%union1 = type { %struct.2* }
+%struct.2 = type { %struct.2*, i8* }
+
+@cont_STACKPOINTER = external global i32, align 4
+@cont_STACK = external global [1000 x i32], align 16
+
+define fastcc void @subs_InternIdcEq() {
+entry:
+  br label %if.else.i.i
+
+if.else.i.i:                                      ; preds = %entry
+  %tmp = load %struct1*, %struct1** undef, align 8
+  br label %while.body.i99.i.i
+
+while.body.i99.i.i:                               ; preds = %while.body.i99.i.i, %if.else.i.i
+  br i1 false, label %while.body.i99.i.i, label %while.end.i103.i.i
+
+while.end.i103.i.i:                               ; preds = %while.body.i99.i.i
+  %tmp1 = load i32, i32* @cont_STACKPOINTER, align 4
+  %dec.i.i102.i.i = add nsw i32 %tmp1, -1
+  br i1 false, label %cont_BackTrack.exit107.i.i, label %if.then.i106.i.i
+
+if.then.i106.i.i:                                 ; preds = %while.end.i103.i.i
+  br label %cont_BackTrack.exit107.i.i
+
+cont_BackTrack.exit107.i.i:                       ; preds = %if.then.i106.i.i, %while.end.i103.i.i
+  %tmp2 = phi i32 [ %dec.i.i102.i.i, %if.then.i106.i.i ], [ 0, %while.end.i103.i.i ]
+  %symbol.i.i.i = getelementptr inbounds %struct1, %struct1* %tmp, i64 0, i32 0
+  br i1 undef, label %land.lhs.true23.i.i, label %for.inc.i.i
+
+land.lhs.true23.i.i:                              ; preds = %cont_BackTrack.exit107.i.i
+  %idxprom.i.i57.i.i = sext i32 %tmp2 to i64
+  %arrayidx.i.i58.i.i = getelementptr inbounds [1000 x i32], [1000 x i32]* @cont_STACK, i64 0, i64 %idxprom.i.i57.i.i
+  store i32 undef, i32* %arrayidx.i.i58.i.i, align 4
+  br i1 false, label %if.then.i45.i.i, label %fol_Atom.exit47.i.i
+
+if.then.i45.i.i:                                  ; preds = %land.lhs.true23.i.i
+  br label %fol_Atom.exit47.i.i
+
+fol_Atom.exit47.i.i:                              ; preds = %if.then.i45.i.i, %land.lhs.true23.i.i
+  unreachable
+
+for.inc.i.i:                                      ; preds = %cont_BackTrack.exit107.i.i
+  br label %for.end.i.i
+
+for.end.i.i:                                      ; preds = %for.inc.i.i
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/hoisting_1.ll b/final/test/Isl/CodeGen/hoisting_1.ll
new file mode 100644
index 0000000..d9d809d
--- /dev/null
+++ b/final/test/Isl/CodeGen/hoisting_1.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -tbaa -polly-codegen -polly-allow-differing-element-types -disable-output %s
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.hoge = type { %struct.widget*, %struct.barney*, %struct.foo*, i32, i32, %struct.wibble*, i32, i32, i32, i32, double, i32, i32, i32, %struct.foo.1*, [4 x %struct.hoge.2*], [4 x %struct.blam*], [4 x %struct.blam*], [16 x i8], [16 x i8], [16 x i8], i32, %struct.barney.3*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i8, i16, i16, i32, i32, i32, i32, i32, i32, i32, [4 x %struct.foo.1*], i32, i32, i32, [10 x i32], i32, i32, i32, i32, %struct.foo.4*, %struct.wombat.5*, %struct.blam.6*, %struct.foo.7*, %struct.bar*, %struct.wibble.8*, %struct.barney.9*, %struct.hoge.10*, %struct.bar.11* }
+%struct.widget = type { void (%struct.quux*)*, void (%struct.quux*, i32)*, void (%struct.quux*)*, void (%struct.quux*, i8*)*, void (%struct.quux*)*, i32, %struct.hoge.0, i32, i64, i8**, i32, i8**, i32, i32 }
+%struct.quux = type { %struct.widget*, %struct.barney*, %struct.foo*, i32, i32 }
+%struct.hoge.0 = type { [8 x i32], [48 x i8] }
+%struct.barney = type { i8* (%struct.quux*, i32, i64)*, i8* (%struct.quux*, i32, i64)*, i8** (%struct.quux*, i32, i32, i32)*, [64 x i16]** (%struct.quux*, i32, i32, i32)*, %struct.ham* (%struct.quux*, i32, i32, i32, i32, i32)*, %struct.wombat* (%struct.quux*, i32, i32, i32, i32, i32)*, {}*, i8** (%struct.quux*, %struct.ham*, i32, i32, i32)*, [64 x i16]** (%struct.quux*, %struct.wombat*, i32, i32, i32)*, void (%struct.quux*, i32)*, {}*, i64 }
+%struct.ham = type opaque
+%struct.wombat = type opaque
+%struct.foo = type { {}*, i64, i64, i32, i32 }
+%struct.wibble = type { i8*, i64, void (%struct.hoge*)*, i32 (%struct.hoge*)*, void (%struct.hoge*)* }
+%struct.foo.1 = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, %struct.hoge.2*, i8* }
+%struct.hoge.2 = type { [64 x i16], i32 }
+%struct.blam = type { [17 x i8], [256 x i8], i32 }
+%struct.barney.3 = type { i32, [4 x i32], i32, i32, i32, i32 }
+%struct.foo.4 = type { void (%struct.hoge*)*, void (%struct.hoge*)*, void (%struct.hoge*)*, i32, i32 }
+%struct.wombat.5 = type { void (%struct.hoge*, i32)*, void (%struct.hoge*, i8**, i32*, i32)* }
+%struct.blam.6 = type { void (%struct.hoge*, i32)*, void (%struct.hoge*, i8**, i32*, i32, i8***, i32*, i32)* }
+%struct.foo.7 = type { void (%struct.hoge*, i32)*, i32 (%struct.hoge*, i8***)* }
+%struct.bar = type { void (%struct.hoge*, i32, i8*, i32)*, void (%struct.hoge*)*, void (%struct.hoge*)*, void (%struct.hoge*)*, void (%struct.hoge*)*, void (%struct.hoge*)* }
+%struct.wibble.8 = type { void (%struct.hoge*)*, void (%struct.hoge*, i8**, i8***, i32, i32)* }
+%struct.barney.9 = type { void (%struct.hoge*)*, void (%struct.hoge*, i8***, i32, i8***, i32)*, i32 }
+%struct.hoge.10 = type { void (%struct.hoge*)*, void (%struct.hoge*, %struct.foo.1*, i8**, [64 x i16]*, i32, i32, i32)* }
+%struct.bar.11 = type { {}*, i32 (%struct.hoge*, [64 x i16]**)*, void (%struct.hoge*)* }
+
+; Function Attrs: nounwind uwtable
+define void @foo(%struct.hoge* %arg) #0 {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb
+  %tmp3 = getelementptr inbounds %struct.hoge, %struct.hoge* %arg, i32 0, i32 42
+  %tmp4 = getelementptr inbounds [4 x %struct.foo.1*], [4 x %struct.foo.1*]* %tmp3, i64 0, i64 0
+  %tmp = load %struct.foo.1*, %struct.foo.1** %tmp4, align 8, !tbaa !1
+  %tmp5 = getelementptr inbounds %struct.foo.1, %struct.foo.1* %tmp, i32 0, i32 7
+  %tmp6 = load i32, i32* %tmp5, align 4, !tbaa !5
+  %tmp7 = getelementptr inbounds %struct.hoge, %struct.hoge* %arg, i32 0, i32 43
+  store i32 %tmp6, i32* %tmp7, align 8, !tbaa !8
+  br i1 false, label %bb8, label %bb9
+
+bb8:                                              ; preds = %bb2
+  br label %bb9
+
+bb9:                                              ; preds = %bb8, %bb2
+  br label %bb10
+
+bb10:                                             ; preds = %bb9
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.9.0 (trunk 259751) (llvm/trunk 259869)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"any pointer", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!6, !7, i64 28}
+!6 = !{!"", !7, i64 0, !7, i64 4, !7, i64 8, !7, i64 12, !7, i64 16, !7, i64 20, !7, i64 24, !7, i64 28, !7, i64 32, !7, i64 36, !7, i64 40, !7, i64 44, !7, i64 48, !7, i64 52, !7, i64 56, !7, i64 60, !7, i64 64, !7, i64 68, !7, i64 72, !2, i64 80, !2, i64 88}
+!7 = !{!"int", !3, i64 0}
+!8 = !{!9, !7, i64 352}
+!9 = !{!"jpeg_compress_struct", !2, i64 0, !2, i64 8, !2, i64 16, !7, i64 24, !7, i64 28, !2, i64 32, !7, i64 40, !7, i64 44, !7, i64 48, !3, i64 52, !10, i64 56, !7, i64 64, !7, i64 68, !3, i64 72, !2, i64 80, !3, i64 88, !3, i64 120, !3, i64 152, !3, i64 184, !3, i64 200, !3, i64 216, !7, i64 232, !2, i64 240, !7, i64 248, !7, i64 252, !7, i64 256, !7, i64 260, !7, i64 264, !3, i64 268, !7, i64 272, !7, i64 276, !7, i64 280, !3, i64 284, !11, i64 286, !11, i64 288, !7, i64 292, !7, i64 296, !7, i64 300, !7, i64 304, !7, i64 308, !7, i64 312, !7, i64 316, !3, i64 320, !7, i64 352, !7, i64 356, !7, i64 360, !3, i64 364, !7, i64 404, !7, i64 408, !7, i64 412, !7, i64 416, !2, i64 424, !2, i64 432, !2, i64 440, !2, i64 448, !2, i64 456, !2, i64 464, !2, i64 472, !2, i64 480, !2, i64 488}
+!10 = !{!"double", !3, i64 0}
+!11 = !{!"short", !3, i64 0}
diff --git a/final/test/Isl/CodeGen/hoisting_2.ll b/final/test/Isl/CodeGen/hoisting_2.ll
new file mode 100644
index 0000000..66fd452
--- /dev/null
+++ b/final/test/Isl/CodeGen/hoisting_2.ll
@@ -0,0 +1,87 @@
+; RUN: opt %loadPolly -tbaa -polly-codegen -polly-allow-differing-element-types -disable-output %s
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.hoge = type { %struct.widget*, %struct.barney*, %struct.foo*, i32, i32, %struct.wibble*, i32, i32, i32, i32, double, i32, i32, i32, %struct.foo.1*, [4 x %struct.hoge.2*], [4 x %struct.blam*], [4 x %struct.blam*], [16 x i8], [16 x i8], [16 x i8], i32, %struct.barney.3*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i8, i16, i16, i32, i32, i32, i32, i32, i32, i32, [4 x %struct.foo.1*], i32, i32, i32, [10 x i32], i32, i32, i32, i32, %struct.foo.4*, %struct.wombat.5*, %struct.blam.6*, %struct.foo.7*, %struct.bar*, %struct.wibble.8*, %struct.barney.9*, %struct.hoge.10*, %struct.bar.11* }
+%struct.widget = type { void (%struct.quux*)*, void (%struct.quux*, i32)*, void (%struct.quux*)*, void (%struct.quux*, i8*)*, void (%struct.quux*)*, i32, %struct.hoge.0, i32, i64, i8**, i32, i8**, i32, i32 }
+%struct.quux = type { %struct.widget*, %struct.barney*, %struct.foo*, i32, i32 }
+%struct.hoge.0 = type { [8 x i32], [48 x i8] }
+%struct.barney = type { i8* (%struct.quux*, i32, i64)*, i8* (%struct.quux*, i32, i64)*, i8** (%struct.quux*, i32, i32, i32)*, [64 x i16]** (%struct.quux*, i32, i32, i32)*, %struct.ham* (%struct.quux*, i32, i32, i32, i32, i32)*, %struct.wombat* (%struct.quux*, i32, i32, i32, i32, i32)*, {}*, i8** (%struct.quux*, %struct.ham*, i32, i32, i32)*, [64 x i16]** (%struct.quux*, %struct.wombat*, i32, i32, i32)*, void (%struct.quux*, i32)*, {}*, i64 }
+%struct.ham = type opaque
+%struct.wombat = type opaque
+%struct.foo = type { {}*, i64, i64, i32, i32 }
+%struct.wibble = type { i8*, i64, void (%struct.hoge*)*, i32 (%struct.hoge*)*, void (%struct.hoge*)* }
+%struct.foo.1 = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, %struct.hoge.2*, i8* }
+%struct.hoge.2 = type { [64 x i16], i32 }
+%struct.blam = type { [17 x i8], [256 x i8], i32 }
+%struct.barney.3 = type { i32, [4 x i32], i32, i32, i32, i32 }
+%struct.foo.4 = type { void (%struct.hoge*)*, void (%struct.hoge*)*, void (%struct.hoge*)*, i32, i32 }
+%struct.wombat.5 = type { void (%struct.hoge*, i32)*, void (%struct.hoge*, i8**, i32*, i32)* }
+%struct.blam.6 = type { void (%struct.hoge*, i32)*, void (%struct.hoge*, i8**, i32*, i32, i8***, i32*, i32)* }
+%struct.foo.7 = type { void (%struct.hoge*, i32)*, i32 (%struct.hoge*, i8***)* }
+%struct.bar = type { void (%struct.hoge*, i32, i8*, i32)*, void (%struct.hoge*)*, void (%struct.hoge*)*, void (%struct.hoge*)*, void (%struct.hoge*)*, void (%struct.hoge*)* }
+%struct.wibble.8 = type { void (%struct.hoge*)*, void (%struct.hoge*, i8**, i8***, i32, i32)* }
+%struct.barney.9 = type { void (%struct.hoge*)*, void (%struct.hoge*, i8***, i32, i8***, i32)*, i32 }
+%struct.hoge.10 = type { void (%struct.hoge*)*, void (%struct.hoge*, %struct.foo.1*, i8**, [64 x i16]*, i32, i32, i32)* }
+%struct.bar.11 = type { {}*, i32 (%struct.hoge*, [64 x i16]**)*, void (%struct.hoge*)* }
+%struct.foo.12 = type { %struct.foo.4, i32, i32, i32, i32 }
+
+; Function Attrs: nounwind uwtable
+define void @eggs(%struct.hoge* %arg) #0 {
+bb:
+  %tmp = load %struct.barney.3*, %struct.barney.3** undef, align 8, !tbaa !1
+  br label %bb5
+
+bb5:                                              ; preds = %bb
+  %tmp6 = getelementptr inbounds %struct.hoge, %struct.hoge* %arg, i32 0, i32 51
+  %tmp7 = load %struct.foo.4*, %struct.foo.4** %tmp6, align 8, !tbaa !9
+  %tmp8 = bitcast %struct.foo.4* %tmp7 to %struct.foo.12*
+  %tmp9 = getelementptr inbounds %struct.foo.12, %struct.foo.12* %tmp8, i32 0, i32 4
+  %tmp10 = load i32, i32* %tmp9, align 4, !tbaa !10
+  %tmp11 = getelementptr inbounds %struct.barney.3, %struct.barney.3* %tmp, i64 0
+  %tmp12 = getelementptr inbounds %struct.barney.3, %struct.barney.3* %tmp11, i32 0, i32 0
+  %tmp151 = load i32, i32* %tmp12, align 4, !tbaa !13
+  %tmp162 = icmp slt i32 0, %tmp151
+  br i1 %tmp162, label %bb17.lr.ph, label %bb22
+
+bb17.lr.ph:                                       ; preds = %bb5
+  br label %bb17
+
+bb17:                                             ; preds = %bb17.lr.ph, %bb17
+  %tmp143 = phi i32 [ 0, %bb17.lr.ph ], [ %tmp21, %bb17 ]
+  %tmp18 = sext i32 %tmp143 to i64
+  %tmp19 = getelementptr inbounds %struct.hoge, %struct.hoge* %arg, i32 0, i32 42
+  %tmp20 = getelementptr inbounds [4 x %struct.foo.1*], [4 x %struct.foo.1*]* %tmp19, i64 0, i64 %tmp18
+  store %struct.foo.1* undef, %struct.foo.1** %tmp20, align 8, !tbaa !15
+  %tmp21 = add nsw i32 %tmp143, 1
+  %tmp15 = load i32, i32* %tmp12, align 4, !tbaa !13
+  %tmp16 = icmp slt i32 %tmp21, %tmp15
+  br i1 %tmp16, label %bb17, label %bb13.bb22_crit_edge
+
+bb13.bb22_crit_edge:                              ; preds = %bb17
+  br label %bb22
+
+bb22:                                             ; preds = %bb13.bb22_crit_edge, %bb5
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.9.0 (trunk 259751) (llvm/trunk 259869)"}
+!1 = !{!2, !3, i64 240}
+!2 = !{!"jpeg_compress_struct", !3, i64 0, !3, i64 8, !3, i64 16, !6, i64 24, !6, i64 28, !3, i64 32, !6, i64 40, !6, i64 44, !6, i64 48, !4, i64 52, !7, i64 56, !6, i64 64, !6, i64 68, !4, i64 72, !3, i64 80, !4, i64 88, !4, i64 120, !4, i64 152, !4, i64 184, !4, i64 200, !4, i64 216, !6, i64 232, !3, i64 240, !6, i64 248, !6, i64 252, !6, i64 256, !6, i64 260, !6, i64 264, !4, i64 268, !6, i64 272, !6, i64 276, !6, i64 280, !4, i64 284, !8, i64 286, !8, i64 288, !6, i64 292, !6, i64 296, !6, i64 300, !6, i64 304, !6, i64 308, !6, i64 312, !6, i64 316, !4, i64 320, !6, i64 352, !6, i64 356, !6, i64 360, !4, i64 364, !6, i64 404, !6, i64 408, !6, i64 412, !6, i64 416, !3, i64 424, !3, i64 432, !3, i64 440, !3, i64 448, !3, i64 456, !3, i64 464, !3, i64 472, !3, i64 480, !3, i64 488}
+!3 = !{!"any pointer", !4, i64 0}
+!4 = !{!"omnipotent char", !5, i64 0}
+!5 = !{!"Simple C/C++ TBAA"}
+!6 = !{!"int", !4, i64 0}
+!7 = !{!"double", !4, i64 0}
+!8 = !{!"short", !4, i64 0}
+!9 = !{!2, !3, i64 424}
+!10 = !{!11, !6, i64 44}
+!11 = !{!"", !12, i64 0, !4, i64 32, !6, i64 36, !6, i64 40, !6, i64 44}
+!12 = !{!"jpeg_comp_master", !3, i64 0, !3, i64 8, !3, i64 16, !6, i64 24, !6, i64 28}
+!13 = !{!14, !6, i64 0}
+!14 = !{!"", !6, i64 0, !4, i64 4, !6, i64 20, !6, i64 24, !6, i64 28, !6, i64 32}
+!15 = !{!3, !3, i64 0}
diff --git a/final/test/Isl/CodeGen/if-conditions-in-vector-code.ll b/final/test/Isl/CodeGen/if-conditions-in-vector-code.ll
new file mode 100644
index 0000000..ca0489e
--- /dev/null
+++ b/final/test/Isl/CodeGen/if-conditions-in-vector-code.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -analyze -polly-ast -polly-vectorizer=polly < %s | \
+; RUN:     FileCheck %s -check-prefix=AST
+
+; RUN: opt %loadPolly -polly-codegen -polly-vectorizer=polly -S < %s | \
+; RUN:     FileCheck %s
+;
+;    void foo(float *A) {
+;      for (long i = 0; i < 16; i++) {
+;        if (i % 2)
+;          A[i] += 2;
+;        if (i % 3)
+;          A[i] += 3;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; AST: #pragma simd
+; AST: #pragma known-parallel
+; AST: for (int c0 = 0; c0 <= 15; c0 += 1) {
+; AST:   if ((c0 + 1) % 2 == 0)
+; AST:     Stmt_bb4(c0);
+; AST:   if (c0 % 3 >= 1)
+; AST:     Stmt_bb11(c0);
+; AST: }
+
+; CHECK: polly.split_new_and_old
+
+define void @foo(float* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb16, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp17, %bb16 ]
+  %exitcond = icmp ne i64 %i.0, 16
+  br i1 %exitcond, label %bb2, label %bb18
+
+bb2:                                              ; preds = %bb1
+  %tmp = srem i64 %i.0, 2
+  %tmp3 = icmp eq i64 %tmp, 0
+  br i1 %tmp3, label %bb8, label %bb4
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp6 = load float, float* %tmp5, align 4
+  %tmp7 = fadd float %tmp6, 2.000000e+00
+  store float %tmp7, float* %tmp5, align 4
+  br label %bb8
+
+bb8:                                              ; preds = %bb2, %bb4
+  %tmp9 = srem i64 %i.0, 3
+  %tmp10 = icmp eq i64 %tmp9, 0
+  br i1 %tmp10, label %bb15, label %bb11
+
+bb11:                                             ; preds = %bb8
+  %tmp12 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp13 = load float, float* %tmp12, align 4
+  %tmp14 = fadd float %tmp13, 3.000000e+00
+  store float %tmp14, float* %tmp12, align 4
+  br label %bb15
+
+bb15:                                             ; preds = %bb8, %bb11
+  br label %bb16
+
+bb16:                                             ; preds = %bb15
+  %tmp17 = add nsw i64 %i.0, 1
+  br label %bb1
+
+bb18:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/inner_scev_sdiv_1.ll b/final/test/Isl/CodeGen/inner_scev_sdiv_1.ll
new file mode 100644
index 0000000..29c8dc2
--- /dev/null
+++ b/final/test/Isl/CodeGen/inner_scev_sdiv_1.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s
+;
+; Excerpt from the test-suite's oggenc reduced using bugpoint.
+;
+; It features a SCEV value using %div44 for the inner loop (for.body.51 =>
+; for.cond.60.preheader) that is computed within the body of the outer loop
+; (for.cond.30.preheader => for.cond.60.preheader). CodeGenerator would add a
+; computation of the SCEV to before the scop that references %div44, which is
+; not available then.
+;
+; CHECK:      polly.split_new_and_old:
+; CHECK-NEXT:   %div23.neg.polly.copy = sdiv i64 0, -4
+;
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_vorbis_apply_window(float* %d) {
+entry:
+  %0 = load float*, float** undef, align 8
+  %div23.neg = sdiv i64 0, -4
+  %sub24 = add i64 0, %div23.neg
+  br label %for.cond.30.preheader
+
+for.cond.30.preheader:                            ; preds = %for.body, %entry
+  %sext = shl i64 %sub24, 32
+  %conv48.74 = ashr exact i64 %sext, 32
+  %cmp49.75 = icmp slt i64 %conv48.74, 0
+  br i1 %cmp49.75, label %for.body.51.lr.ph, label %for.cond.60.preheader
+
+for.body.51.lr.ph:                                ; preds = %for.cond.30.preheader
+  %div44 = sdiv i64 0, 2
+  %sub45 = add nsw i64 %div44, 4294967295
+  %1 = trunc i64 %sub45 to i32
+  %2 = sext i32 %1 to i64
+  br label %for.body.51
+
+for.cond.60.preheader:                            ; preds = %for.body.51, %for.cond.30.preheader
+  ret void
+
+for.body.51:                                      ; preds = %for.body.51, %for.body.51.lr.ph
+  %indvars.iv86 = phi i64 [ %2, %for.body.51.lr.ph ], [ undef, %for.body.51 ]
+  %arrayidx53 = getelementptr inbounds float, float* %0, i64 %indvars.iv86
+  %3 = load float, float* %arrayidx53, align 4
+  %arrayidx55 = getelementptr inbounds float, float* %d, i64 0
+  %mul56 = fmul float %3, undef
+  store float %mul56, float* %arrayidx55, align 4
+  br i1 false, label %for.body.51, label %for.cond.60.preheader
+}
diff --git a/final/test/Isl/CodeGen/inner_scev_sdiv_2.ll b/final/test/Isl/CodeGen/inner_scev_sdiv_2.ll
new file mode 100644
index 0000000..9b92544
--- /dev/null
+++ b/final/test/Isl/CodeGen/inner_scev_sdiv_2.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+;
+; The SCEV expression in this test case refers to a sequence of sdiv
+; instructions, which are part of different bbs in the SCoP. When code
+; generating the parameter expressions, the code that is generated by the SCEV
+; expander has still references to the in-scop instructions, which was invalid.
+;
+; CHECK: polly.start
+;
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_vorbis_apply_window(float* %d, i64 %param) {
+entry:
+  %0 = load float*, float** undef, align 8
+  %div23.neg = sdiv i64 0, -4
+  %sub24 = add i64 0, %div23.neg
+  br label %for.cond.30.preheader
+
+for.cond.30.preheader:                            ; preds = %for.body, %entry
+  %sext = shl i64 %sub24, 32
+  %conv48.74 = ashr exact i64 %sext, 32
+  %div43 = sdiv i64 %param, 2
+  %cmp49.75 = icmp slt i64 %conv48.74, 0
+  br i1 %cmp49.75, label %for.body.51.lr.ph, label %for.cond.60.preheader
+
+for.body.51.lr.ph:                                ; preds = %for.cond.30.preheader
+  %div44 = sdiv i64 %div43, 2
+  %sub45 = add nsw i64 %div44, 4294967295
+  %1 = trunc i64 %sub45 to i32
+  %2 = sext i32 %1 to i64
+  br label %for.body.51
+
+for.cond.60.preheader:                            ; preds = %for.body.51, %for.cond.30.preheader
+  ret void
+
+for.body.51:                                      ; preds = %for.body.51, %for.body.51.lr.ph
+  %indvars.iv86 = phi i64 [ %2, %for.body.51.lr.ph ], [ undef, %for.body.51 ]
+  %arrayidx53 = getelementptr inbounds float, float* %0, i64 %indvars.iv86
+  %3 = load float, float* %arrayidx53, align 4
+  %arrayidx55 = getelementptr inbounds float, float* %d, i64 0
+  %mul56 = fmul float %3, undef
+  store float %mul56, float* %arrayidx55, align 4
+  br i1 false, label %for.body.51, label %for.cond.60.preheader
+}
diff --git a/final/test/Isl/CodeGen/inner_scev_sdiv_3.ll b/final/test/Isl/CodeGen/inner_scev_sdiv_3.ll
new file mode 100644
index 0000000..50e9861
--- /dev/null
+++ b/final/test/Isl/CodeGen/inner_scev_sdiv_3.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+;
+; This test case has a inner SCEV sdiv that will escape the SCoP. Just check we
+; do not crash and generate valid code.
+;
+; CHECK:    polly.split_new_and_old:
+;
+target triple = "x86_64-unknown-linux-gnu"
+
+define i64 @_vorbis_apply_window(float* %d, i64 %param) {
+entry:
+  %0 = load float*, float** undef, align 8
+  %div23.neg = sdiv i64 0, -4
+  %sub24 = add i64 0, %div23.neg
+  br label %for.cond.30.preheader
+
+for.cond.30.preheader:                            ; preds = %for.body, %entry
+  %sext = shl i64 %sub24, 32
+  %conv48.74 = ashr exact i64 %sext, 32
+  %div43 = sdiv i64 %param, 2
+  %cmp49.75 = icmp slt i64 %conv48.74, 0
+  br i1 %cmp49.75, label %for.body.51.lr.ph, label %for.cond.60.preheader
+
+for.body.51.lr.ph:                                ; preds = %for.cond.30.preheader
+  %div44 = sdiv i64 %div43, 2
+  %sub45 = add nsw i64 %div44, 4294967295
+  %1 = trunc i64 %sub45 to i32
+  %2 = sext i32 %1 to i64
+  br label %for.body.51
+
+for.cond.60.preheader:                            ; preds = %for.body.51, %for.cond.30.preheader
+  %div44.m = phi i64 [%div44, %for.body.51], [ 0, %for.cond.30.preheader]
+  br i1 true, label %end, label %for.cond.30.preheader
+
+end:
+  ret i64 %div44.m
+
+for.body.51:                                      ; preds = %for.body.51, %for.body.51.lr.ph
+  %indvars.iv86 = phi i64 [ %2, %for.body.51.lr.ph ], [ undef, %for.body.51 ]
+  %arrayidx53 = getelementptr inbounds float, float* %0, i64 %indvars.iv86
+  %3 = load float, float* %arrayidx53, align 4
+  %arrayidx55 = getelementptr inbounds float, float* %d, i64 0
+  %mul56 = fmul float %3, undef
+  store float %mul56, float* %arrayidx55, align 4
+  br i1 false, label %for.body.51, label %for.cond.60.preheader
+}
diff --git a/final/test/Isl/CodeGen/inner_scev_sdiv_in_lb.ll b/final/test/Isl/CodeGen/inner_scev_sdiv_in_lb.ll
new file mode 100644
index 0000000..c2306d8
--- /dev/null
+++ b/final/test/Isl/CodeGen/inner_scev_sdiv_in_lb.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly \
+; RUN:     -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly \
+; RUN:      -S -polly-codegen < %s | FileCheck %s --check-prefix=CODEGEN
+;
+; CHECK: [N] -> { Stmt_bb11[i0, i1] : i0 < N and i1 >= 0 and 3i1 <= -3 + i0 };
+; CODEGEN: polly
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        for (int j = 0; j < i / 3; j++)
+;          A[i] += A[j];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  br label %bb3
+
+bb3:                                              ; preds = %bb19, %bb
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %bb19 ], [ 0, %bb ]
+  %tmp4 = icmp slt i64 %indvars.iv1, %tmp
+  br i1 %tmp4, label %bb5, label %bb20
+
+bb5:                                              ; preds = %bb3
+  br label %bb6
+
+bb6:                                              ; preds = %bb17, %bb5
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb17 ], [ 0, %bb5 ]
+  %tmp7 = trunc i64 %indvars.iv1 to i32
+  %tmp8 = sdiv i32 %tmp7, 3
+  %tmp9 = sext i32 %tmp8 to i64
+  %tmp10 = icmp slt i64 %indvars.iv, %tmp9
+  br i1 %tmp10, label %bb11, label %bb18
+
+bb11:                                             ; preds = %bb6
+  %tmp12 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp13 = load i32, i32* %tmp12, align 4
+  %tmp14 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv1
+  %tmp15 = load i32, i32* %tmp14, align 4
+  %tmp16 = add nsw i32 %tmp15, %tmp13
+  store i32 %tmp16, i32* %tmp14, align 4
+  br label %bb17
+
+bb17:                                             ; preds = %bb11
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb6
+
+bb18:                                             ; preds = %bb6
+  br label %bb19
+
+bb19:                                             ; preds = %bb18
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %bb3
+
+bb20:                                             ; preds = %bb3
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/inner_scev_sdiv_in_lb_invariant.ll b/final/test/Isl/CodeGen/inner_scev_sdiv_in_lb_invariant.ll
new file mode 100644
index 0000000..dff1653
--- /dev/null
+++ b/final/test/Isl/CodeGen/inner_scev_sdiv_in_lb_invariant.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -S -polly-codegen \
+; RUN:     < %s | FileCheck %s
+;
+; Check that this will not crash our code generation.
+;
+; CHECK: polly.start:
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N / 4; i++)
+;        A[i] += A[i - 1];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+bb:
+  %tmp = sdiv i32 %N, 4
+  %tmp2 = sext i32 %tmp to i64
+  br label %bb1
+
+bb1:                                              ; preds = %bb11, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb11 ], [ 0, %bb ]
+  %tmp3 = icmp slt i64 %indvars.iv, %tmp2
+  br i1 %tmp3, label %bb4, label %bb12
+
+bb4:                                              ; preds = %bb1
+  %tmp5 = add nsw i64 %indvars.iv, -1
+  %tmp6 = getelementptr inbounds i32, i32* %A, i64 %tmp5
+  %tmp7 = load i32, i32* %tmp6, align 4
+  %tmp8 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp9 = load i32, i32* %tmp8, align 4
+  %tmp10 = add nsw i32 %tmp9, %tmp7
+  store i32 %tmp10, i32* %tmp8, align 4
+  br label %bb11
+
+bb11:                                             ; preds = %bb4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb12:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/inner_scev_sdiv_in_rtc.ll b/final/test/Isl/CodeGen/inner_scev_sdiv_in_rtc.ll
new file mode 100644
index 0000000..9481a4b
--- /dev/null
+++ b/final/test/Isl/CodeGen/inner_scev_sdiv_in_rtc.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-codegen \
+; RUN:     -S < %s | FileCheck %s
+;
+; This will just check that we generate valid code here.
+;
+; CHECK: polly.start:
+;
+;    void f(int *A, int *B) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i % 3] = B[i / 42];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %B, i32 %N) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb9, %bb
+  %i.0 = phi i32 [ 0, %bb ], [ %tmp10, %bb9 ]
+  %exitcond = icmp ne i32 %i.0, %N
+  br i1 %exitcond, label %bb2, label %bb11
+
+bb2:                                              ; preds = %bb1
+  %tmp = sdiv i32 %i.0, 42
+  %tmp3 = sext i32 %tmp to i64
+  %tmp4 = getelementptr inbounds i32, i32* %B, i64 %tmp3
+  %tmp5 = load i32, i32* %tmp4, align 4
+  %tmp6 = srem i32 %i.0, 3
+  %tmp7 = sext i32 %tmp6 to i64
+  %tmp8 = getelementptr inbounds i32, i32* %A, i64 %tmp7
+  store i32 %tmp5, i32* %tmp8, align 4
+  br label %bb9
+
+bb9:                                              ; preds = %bb2
+  %tmp10 = add nuw nsw i32 %i.0, 1
+  br label %bb1
+
+bb11:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/intrinsics_lifetime.ll b/final/test/Isl/CodeGen/intrinsics_lifetime.ll
new file mode 100644
index 0000000..1a9b5cb
--- /dev/null
+++ b/final/test/Isl/CodeGen/intrinsics_lifetime.ll
@@ -0,0 +1,81 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -S < %s | FileCheck %s
+;
+; Verify that we remove the lifetime markers from everywhere.
+;
+; CHECK-NOT: call void @llvm.lifetime.start
+; CHECK-NOT: call void @llvm.lifetime.end
+;
+;    int A[1024];
+;    void jd() {
+;      for (int i = 0; i < 1024; i++) {
+;        int tmp[1024];
+;        for (int j = i; j < 1024; j++)
+;          tmp[i] += A[j];
+;        A[i] = tmp[i];
+;      }
+;    }
+;
+; ModuleID = 'test/Isl/CodeGen/lifetime_intrinsics.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@A = common global [1024 x i32] zeroinitializer, align 16
+
+; Function Attrs: nounwind uwtable
+define void @jd() #0 {
+entry:
+  %tmp = alloca [1024 x i32], align 16
+  %tmp3 = bitcast [1024 x i32]* %tmp to i8*
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc11, %entry
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc11 ], [ 0, %entry ]
+  %exitcond5 = icmp ne i64 %indvars.iv3, 1024
+  br i1 %exitcond5, label %for.body, label %for.end13
+
+for.body:                                         ; preds = %for.cond
+  call void @llvm.lifetime.start(i64 4096, i8* %tmp3) #1
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc, %for.body
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc ], [ %indvars.iv3, %for.body ]
+  %lftr.wideiv = trunc i64 %indvars.iv1 to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, 1024
+  br i1 %exitcond, label %for.body4, label %for.end
+
+for.body4:                                        ; preds = %for.cond2
+  %arrayidx = getelementptr inbounds [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvars.iv1
+  %tmp6 = load i32, i32* %arrayidx, align 4
+  %arrayidx6 = getelementptr inbounds [1024 x i32], [1024 x i32]* %tmp, i64 0, i64 %indvars.iv3
+  %tmp7 = load i32, i32* %arrayidx6, align 4
+  %add = add nsw i32 %tmp7, %tmp6
+  store i32 %add, i32* %arrayidx6, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body4
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %for.cond2
+
+for.end:                                          ; preds = %for.cond2
+  %arrayidx8 = getelementptr inbounds [1024 x i32], [1024 x i32]* %tmp, i64 0, i64 %indvars.iv3
+  %tmp8 = load i32, i32* %arrayidx8, align 4
+  %arrayidx10 = getelementptr inbounds [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvars.iv3
+  store i32 %tmp8, i32* %arrayidx10, align 4
+  call void @llvm.lifetime.end(i64 4096, i8* %tmp3) #1
+  br label %for.inc11
+
+for.inc11:                                        ; preds = %for.end
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  br label %for.cond
+
+for.end13:                                        ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: nounwind
+declare void @llvm.lifetime.start(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind
+declare void @llvm.lifetime.end(i64, i8* nocapture) #1
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="true" "use-soft-float"="false" }
+attributes #1 = { nounwind }
diff --git a/final/test/Isl/CodeGen/intrinsics_misc.ll b/final/test/Isl/CodeGen/intrinsics_misc.ll
new file mode 100644
index 0000000..f755b08
--- /dev/null
+++ b/final/test/Isl/CodeGen/intrinsics_misc.ll
@@ -0,0 +1,100 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -S < %s | FileCheck %s
+;
+; Verify that we remove the misc intrinsics  from the optimized SCoP.
+;
+; CHECK: for.body:
+; CHECK:   call {}* @llvm.invariant.start
+; CHECK: for.body4:
+; CHECK:   call void @llvm.assume
+; CHECK:   call i1 @llvm.expect.i1
+; CHECK:   call void @llvm.donothing
+; CHECK: for.end:
+; CHECK:   call void @llvm.invariant.end
+; CHECK-NOT: call void @llvm.{{.*}}
+;
+;    int A[1024];
+;    void jd() {
+;      for (int i = 0; i < 1024; i++) {
+;        int tmp[1024];
+;        for (int j = i; j < 1024; j++)
+;          tmp[i] += A[j];
+;        A[i] = tmp[i];
+;      }
+;    }
+;
+; ModuleID = 'test/Isl/CodeGen/lifetime_intrinsics.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@A = common global [1024 x i32] zeroinitializer, align 16
+
+; Function Attrs: nounwind uwtable
+define void @jd() #0 {
+entry:
+  %tmp = alloca [1024 x i32], align 16
+  %tmp3 = bitcast [1024 x i32]* @A to i8*
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc11, %entry
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc11 ], [ 0, %entry ]
+  %exitcond5 = icmp ne i64 %indvars.iv3, 1024
+  br i1 %exitcond5, label %for.body, label %for.end13
+
+for.body:                                         ; preds = %for.cond
+  %lis = call {}* @llvm.invariant.start(i64 4096, i8* %tmp3) #1
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc, %for.body
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc ], [ %indvars.iv3, %for.body ]
+  %lftr.wideiv = trunc i64 %indvars.iv1 to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, 1024
+  br i1 %exitcond, label %for.body4, label %for.end
+
+for.body4:                                        ; preds = %for.cond2
+  call void @llvm.assume(i1 %exitcond)
+  call i1 @llvm.expect.i1(i1 %exitcond, i1 1)
+  %arrayidx = getelementptr inbounds [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvars.iv1
+  %tmp6 = load i32, i32* %arrayidx, align 4
+  %arrayidx6 = getelementptr inbounds [1024 x i32], [1024 x i32]* %tmp, i64 0, i64 %indvars.iv3
+  call void @llvm.donothing()
+  %tmp7 = load i32, i32* %arrayidx6, align 4
+  %add = add nsw i32 %tmp7, %tmp6
+  store i32 %add, i32* %arrayidx6, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body4
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %for.cond2
+
+for.end:                                          ; preds = %for.cond2
+  %arrayidx8 = getelementptr inbounds [1024 x i32], [1024 x i32]* %tmp, i64 0, i64 %indvars.iv3
+  %tmp8 = load i32, i32* %arrayidx8, align 4
+  %arrayidx10 = getelementptr inbounds [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvars.iv3
+  call void @llvm.invariant.end({}* %lis, i64 4096, i8* %tmp3) #1
+  store i32 %tmp8, i32* %arrayidx10, align 4
+  br label %for.inc11
+
+for.inc11:                                        ; preds = %for.end
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  br label %for.cond
+
+for.end13:                                        ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: nounwind
+declare void @llvm.donothing() #1
+
+; Function Attrs: nounwind
+declare void @llvm.assume(i1) #1
+
+; Function Attrs: nounwind
+declare i1 @llvm.expect.i1(i1, i1) #1
+
+; Function Attrs: nounwind
+declare {}* @llvm.invariant.start(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind
+declare void @llvm.invariant.end({}*, i64, i8* nocapture) #1
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="true" "use-soft-float"="false" }
+attributes #1 = { nounwind }
diff --git a/final/test/Isl/CodeGen/inv-load-lnt-crash-wrong-order-2.ll b/final/test/Isl/CodeGen/inv-load-lnt-crash-wrong-order-2.ll
new file mode 100644
index 0000000..1c81d64
--- /dev/null
+++ b/final/test/Isl/CodeGen/inv-load-lnt-crash-wrong-order-2.ll
@@ -0,0 +1,92 @@
+; RUN: opt %loadPolly -polly-codegen -S \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+; This crashed our codegen at some point, verify it runs through
+;
+; CHECK: polly.start
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.EqState.41.74.107.272.602.635.701.734.767.899.998.1229.2449.2482.2647.2680.2779.2911.3010.3036 = type { %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035*, %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018*, %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035* }
+%struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018 = type { i32, %struct.Production.29.62.95.260.590.623.689.722.755.887.986.1217.2437.2470.2635.2668.2767.2899.2998.3014*, i32, i32, i32, i32, %struct.anon.0.30.63.96.261.591.624.690.723.756.888.987.1218.2438.2471.2636.2669.2768.2900.2999.3015, %struct.Elem.12.45.78.243.573.606.672.705.738.870.969.1200.2420.2453.2618.2651.2750.2882.2981.3021*, %struct.Code.31.64.97.262.592.625.691.724.757.889.988.1219.2439.2472.2637.2670.2769.2901.3000.3016, %struct.Code.31.64.97.262.592.625.691.724.757.889.988.1219.2439.2472.2637.2670.2769.2901.3000.3016, %struct.anon.1.32.65.98.263.593.626.692.725.758.890.989.1220.2440.2473.2638.2671.2770.2902.3001.3017, i32, %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018* }
+%struct.Production.29.62.95.260.590.623.689.722.755.887.986.1217.2437.2470.2635.2668.2767.2899.2998.3014 = type { i8*, i32, %struct.anon.9.42.75.240.570.603.669.702.735.867.966.1197.2417.2450.2615.2648.2747.2879.2978.3011, i32, i8, %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018*, [8 x %struct.Production.29.62.95.260.590.623.689.722.755.887.986.1217.2437.2470.2635.2668.2767.2899.2998.3014*], [8 x %struct.Declaration.13.46.79.244.574.607.673.706.739.871.970.1201.2421.2454.2619.2652.2751.2883.2982.3012*], %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035*, %struct.Elem.12.45.78.243.573.606.672.705.738.870.969.1200.2420.2453.2618.2651.2750.2882.2981.3021*, %struct.Term.18.51.84.249.579.612.678.711.744.876.975.1206.2426.2459.2624.2657.2756.2888.2987.3013*, %struct.Production.29.62.95.260.590.623.689.722.755.887.986.1217.2437.2470.2635.2668.2767.2899.2998.3014* }
+%struct.anon.9.42.75.240.570.603.669.702.735.867.966.1197.2417.2450.2615.2648.2747.2879.2978.3011 = type { i32, i32, %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018**, [3 x %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018*] }
+%struct.Declaration.13.46.79.244.574.607.673.706.739.871.970.1201.2421.2454.2619.2652.2751.2883.2982.3012 = type { %struct.Elem.12.45.78.243.573.606.672.705.738.870.969.1200.2420.2453.2618.2651.2750.2882.2981.3021*, i32, i32 }
+%struct.Term.18.51.84.249.579.612.678.711.744.876.975.1206.2426.2459.2624.2657.2756.2888.2987.3013 = type { i32, i32, i32, i32, i32, i8*, i32, i8, %struct.Production.29.62.95.260.590.623.689.722.755.887.986.1217.2437.2470.2635.2668.2767.2899.2998.3014* }
+%struct.anon.0.30.63.96.261.591.624.690.723.756.888.987.1218.2438.2471.2636.2669.2768.2900.2999.3015 = type { i32, i32, %struct.Elem.12.45.78.243.573.606.672.705.738.870.969.1200.2420.2453.2618.2651.2750.2882.2981.3021**, [3 x %struct.Elem.12.45.78.243.573.606.672.705.738.870.969.1200.2420.2453.2618.2651.2750.2882.2981.3021*] }
+%struct.Elem.12.45.78.243.573.606.672.705.738.870.969.1200.2420.2453.2618.2651.2750.2882.2981.3021 = type { i32, i32, %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018*, %union.anon.11.44.77.242.572.605.671.704.737.869.968.1199.2419.2452.2617.2650.2749.2881.2980.3020 }
+%union.anon.11.44.77.242.572.605.671.704.737.869.968.1199.2419.2452.2617.2650.2749.2881.2980.3020 = type { %struct.Unresolved.10.43.76.241.571.604.670.703.736.868.967.1198.2418.2451.2616.2649.2748.2880.2979.3019 }
+%struct.Unresolved.10.43.76.241.571.604.670.703.736.868.967.1198.2418.2451.2616.2649.2748.2880.2979.3019 = type { i8*, i32 }
+%struct.Code.31.64.97.262.592.625.691.724.757.889.988.1219.2439.2472.2637.2670.2769.2901.3000.3016 = type { i8*, i32 }
+%struct.anon.1.32.65.98.263.593.626.692.725.758.890.989.1220.2440.2473.2638.2671.2770.2902.3001.3017 = type { i32, i32, %struct.Code.31.64.97.262.592.625.691.724.757.889.988.1219.2439.2472.2637.2670.2769.2901.3000.3016**, [3 x %struct.Code.31.64.97.262.592.625.691.724.757.889.988.1219.2439.2472.2637.2670.2769.2901.3000.3016*] }
+%struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035 = type { i32, i64, %struct.anon.2.14.47.80.245.575.608.674.707.740.872.971.1202.2422.2455.2620.2653.2752.2884.2983.3022, %struct.anon.3.15.48.81.246.576.609.675.708.741.873.972.1203.2423.2456.2621.2654.2753.2885.2984.3023, %struct.VecGoto.17.50.83.248.578.611.677.710.743.875.974.1205.2425.2458.2623.2656.2755.2887.2986.3025, %struct.VecAction.20.53.86.251.581.614.680.713.746.878.977.1208.2428.2461.2626.2659.2758.2890.2989.3027, %struct.VecAction.20.53.86.251.581.614.680.713.746.878.977.1208.2428.2461.2626.2659.2758.2890.2989.3027, %struct.VecHint.22.55.88.253.583.616.682.715.748.880.979.1210.2430.2463.2628.2661.2760.2892.2991.3029, %struct.VecHint.22.55.88.253.583.616.682.715.748.880.979.1210.2430.2463.2628.2661.2760.2892.2991.3029, %struct.Scanner.27.60.93.258.588.621.687.720.753.885.984.1215.2435.2468.2633.2666.2765.2897.2996.3034, i8, i8*, i32, %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035*, %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035*, %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018*, %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018* }
+%struct.anon.2.14.47.80.245.575.608.674.707.740.872.971.1202.2422.2455.2620.2653.2752.2884.2983.3022 = type { i32, i32, %struct.Elem.12.45.78.243.573.606.672.705.738.870.969.1200.2420.2453.2618.2651.2750.2882.2981.3021**, [3 x %struct.Elem.12.45.78.243.573.606.672.705.738.870.969.1200.2420.2453.2618.2651.2750.2882.2981.3021*] }
+%struct.anon.3.15.48.81.246.576.609.675.708.741.873.972.1203.2423.2456.2621.2654.2753.2885.2984.3023 = type { i32, i32, %struct.Elem.12.45.78.243.573.606.672.705.738.870.969.1200.2420.2453.2618.2651.2750.2882.2981.3021**, [3 x %struct.Elem.12.45.78.243.573.606.672.705.738.870.969.1200.2420.2453.2618.2651.2750.2882.2981.3021*] }
+%struct.VecGoto.17.50.83.248.578.611.677.710.743.875.974.1205.2425.2458.2623.2656.2755.2887.2986.3025 = type { i32, i32, %struct.Goto.16.49.82.247.577.610.676.709.742.874.973.1204.2424.2457.2622.2655.2754.2886.2985.3024**, [3 x %struct.Goto.16.49.82.247.577.610.676.709.742.874.973.1204.2424.2457.2622.2655.2754.2886.2985.3024*] }
+%struct.Goto.16.49.82.247.577.610.676.709.742.874.973.1204.2424.2457.2622.2655.2754.2886.2985.3024 = type { %struct.Elem.12.45.78.243.573.606.672.705.738.870.969.1200.2420.2453.2618.2651.2750.2882.2981.3021*, %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035* }
+%struct.VecAction.20.53.86.251.581.614.680.713.746.878.977.1208.2428.2461.2626.2659.2758.2890.2989.3027 = type { i32, i32, %struct.Action.19.52.85.250.580.613.679.712.745.877.976.1207.2427.2460.2625.2658.2757.2889.2988.3026**, [3 x %struct.Action.19.52.85.250.580.613.679.712.745.877.976.1207.2427.2460.2625.2658.2757.2889.2988.3026*] }
+%struct.Action.19.52.85.250.580.613.679.712.745.877.976.1207.2427.2460.2625.2658.2757.2889.2988.3026 = type { i32, %struct.Term.18.51.84.249.579.612.678.711.744.876.975.1206.2426.2459.2624.2657.2756.2888.2987.3013*, %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018*, %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035*, i32, i8* }
+%struct.VecHint.22.55.88.253.583.616.682.715.748.880.979.1210.2430.2463.2628.2661.2760.2892.2991.3029 = type { i32, i32, %struct.Hint.21.54.87.252.582.615.681.714.747.879.978.1209.2429.2462.2627.2660.2759.2891.2990.3028**, [3 x %struct.Hint.21.54.87.252.582.615.681.714.747.879.978.1209.2429.2462.2627.2660.2759.2891.2990.3028*] }
+%struct.Hint.21.54.87.252.582.615.681.714.747.879.978.1209.2429.2462.2627.2660.2759.2891.2990.3028 = type { i32, %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035*, %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018* }
+%struct.Scanner.27.60.93.258.588.621.687.720.753.885.984.1215.2435.2468.2633.2666.2765.2897.2996.3034 = type { %struct.VecScanState.25.58.91.256.586.619.685.718.751.883.982.1213.2433.2466.2631.2664.2763.2895.2994.3032, %struct.VecScanStateTransition.26.59.92.257.587.620.686.719.752.884.983.1214.2434.2467.2632.2665.2764.2896.2995.3033 }
+%struct.VecScanState.25.58.91.256.586.619.685.718.751.883.982.1213.2433.2466.2631.2664.2763.2895.2994.3032 = type { i32, i32, %struct.ScanState.24.57.90.255.585.618.684.717.750.882.981.1212.2432.2465.2630.2663.2762.2894.2993.3031**, [3 x %struct.ScanState.24.57.90.255.585.618.684.717.750.882.981.1212.2432.2465.2630.2663.2762.2894.2993.3031*] }
+%struct.ScanState.24.57.90.255.585.618.684.717.750.882.981.1212.2432.2465.2630.2663.2762.2894.2993.3031 = type { i32, [256 x %struct.ScanState.24.57.90.255.585.618.684.717.750.882.981.1212.2432.2465.2630.2663.2762.2894.2993.3031*], %struct.VecAction.20.53.86.251.581.614.680.713.746.878.977.1208.2428.2461.2626.2659.2758.2890.2989.3027, %struct.VecAction.20.53.86.251.581.614.680.713.746.878.977.1208.2428.2461.2626.2659.2758.2890.2989.3027, [256 x %struct.ScanStateTransition.23.56.89.254.584.617.683.716.749.881.980.1211.2431.2464.2629.2662.2761.2893.2992.3030*] }
+%struct.ScanStateTransition.23.56.89.254.584.617.683.716.749.881.980.1211.2431.2464.2629.2662.2761.2893.2992.3030 = type { i32, %struct.VecAction.20.53.86.251.581.614.680.713.746.878.977.1208.2428.2461.2626.2659.2758.2890.2989.3027, %struct.VecAction.20.53.86.251.581.614.680.713.746.878.977.1208.2428.2461.2626.2659.2758.2890.2989.3027 }
+%struct.VecScanStateTransition.26.59.92.257.587.620.686.719.752.884.983.1214.2434.2467.2632.2665.2764.2896.2995.3033 = type { i32, i32, %struct.ScanStateTransition.23.56.89.254.584.617.683.716.749.881.980.1211.2431.2464.2629.2662.2761.2893.2992.3030**, [3 x %struct.ScanStateTransition.23.56.89.254.584.617.683.716.749.881.980.1211.2431.2464.2629.2662.2761.2893.2992.3030*] }
+
+; Function Attrs: nounwind
+declare noalias i8* @malloc() #0
+
+; Function Attrs: nounwind uwtable
+define void @build_eq() #1 {
+entry:
+  %call = tail call noalias i8* @malloc() #2
+  %0 = bitcast i8* %call to %struct.EqState.41.74.107.272.602.635.701.734.767.899.998.1229.2449.2482.2647.2680.2779.2911.3010.3036*
+  br label %for.cond.preheader
+
+for.cond.preheader:                               ; preds = %for.cond.preheader, %entry
+  br i1 undef, label %for.cond.260.preheader, label %for.cond.preheader
+
+for.cond.260.preheader:                           ; preds = %for.cond.preheader
+  br i1 undef, label %for.cond.316.preheader, label %for.body.265
+
+for.cond.316.preheader:                           ; preds = %for.cond.260.preheader
+  br i1 undef, label %for.cond.400.preheader, label %for.body.321
+
+for.body.265:                                     ; preds = %for.cond.260.preheader
+  unreachable
+
+for.cond.400.preheader:                           ; preds = %for.inc.397, %for.cond.316.preheader
+  ret void
+
+for.body.321:                                     ; preds = %for.inc.397, %for.cond.316.preheader
+  %1 = load %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035*, %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035** undef, align 8
+  %eq329 = getelementptr inbounds %struct.EqState.41.74.107.272.602.635.701.734.767.899.998.1229.2449.2482.2647.2680.2779.2911.3010.3036, %struct.EqState.41.74.107.272.602.635.701.734.767.899.998.1229.2449.2482.2647.2680.2779.2911.3010.3036* %0, i64 0, i32 0
+  br i1 undef, label %for.inc.397, label %land.lhs.true.331
+
+land.lhs.true.331:                                ; preds = %for.body.321
+  br i1 undef, label %for.inc.397, label %if.then.334
+
+if.then.334:                                      ; preds = %land.lhs.true.331
+  %2 = load %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018*, %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018** undef, align 8
+  br i1 undef, label %for.inc.397, label %land.lhs.true.369
+
+land.lhs.true.369:                                ; preds = %if.then.334
+  %n380 = getelementptr inbounds %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018, %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018* %2, i64 0, i32 6, i32 0
+  %3 = load i32, i32* %n380, align 8
+  br i1 true, label %if.then.383, label %for.inc.397
+
+if.then.383:                                      ; preds = %land.lhs.true.369
+  %reduces_with387 = getelementptr inbounds %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035, %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035* %1, i64 0, i32 15
+  %4 = bitcast %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018** %reduces_with387 to i64*
+  %5 = load %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035*, %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035** %eq329, align 8
+  %index389 = getelementptr inbounds %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035, %struct.State.28.61.94.259.589.622.688.721.754.886.985.1216.2436.2469.2634.2667.2766.2898.2997.3035* %5, i64 0, i32 0
+  %6 = load i32, i32* %index389, align 8
+  store i32 0, i32* %index389, align 8
+  %diff_rule392 = getelementptr inbounds %struct.EqState.41.74.107.272.602.635.701.734.767.899.998.1229.2449.2482.2647.2680.2779.2911.3010.3036, %struct.EqState.41.74.107.272.602.635.701.734.767.899.998.1229.2449.2482.2647.2680.2779.2911.3010.3036* %0, i64 0, i32 1
+  %7 = bitcast %struct.Rule.33.66.99.264.594.627.693.726.759.891.990.1221.2441.2474.2639.2672.2771.2903.3002.3018** %diff_rule392 to i64*
+  br label %for.inc.397
+
+for.inc.397:                                      ; preds = %if.then.383, %land.lhs.true.369, %if.then.334, %land.lhs.true.331, %for.body.321
+  br i1 undef, label %for.body.321, label %for.cond.400.preheader
+}
diff --git a/final/test/Isl/CodeGen/inv-load-lnt-crash-wrong-order-3.ll b/final/test/Isl/CodeGen/inv-load-lnt-crash-wrong-order-3.ll
new file mode 100644
index 0000000..426b59f
--- /dev/null
+++ b/final/test/Isl/CodeGen/inv-load-lnt-crash-wrong-order-3.ll
@@ -0,0 +1,74 @@
+; RUN: opt %loadPolly -polly-codegen -S \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+; This crashed our codegen at some point, verify it runs through
+;
+; CHECK: polly.start
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.colocated_params = type { i32, i32, i32, [6 x [33 x i64]], i8***, i64***, i16****, i8**, [6 x [33 x i64]], i8***, i64***, i16****, i8**, [6 x [33 x i64]], i8***, i64***, i16****, i8**, i8, i8** }
+%struct.storable_picture9 = type { i32, i32, i32, i32, i32, [50 x [6 x [33 x i64]]], [50 x [6 x [33 x i64]]], [50 x [6 x [33 x i64]]], [50 x [6 x [33 x i64]]], i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i16**, i16***, i8*, i16**, i8***, i64***, i64***, i16****, i8**, i8**, %struct.storable_picture9*, %struct.storable_picture9*, %struct.storable_picture9*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [2 x i32], i32, %struct.DecRefPicMarking_s*, i32 }
+%struct.DecRefPicMarking_s = type { i32, i32, i32, i32, i32, %struct.DecRefPicMarking_s* }
+
+; Function Attrs: nounwind uwtable
+define void @compute_colocated(%struct.colocated_params* %p) #0 {
+entry:
+  %tmp = load %struct.storable_picture9*, %struct.storable_picture9** undef, align 8
+  br label %for.body.393
+
+for.body.393:                                     ; preds = %if.end.549, %entry
+  br i1 undef, label %if.then.397, label %if.else.643
+
+if.then.397:                                      ; preds = %for.body.393
+  %ref_idx456 = getelementptr inbounds %struct.storable_picture9, %struct.storable_picture9* %tmp, i64 0, i32 36
+  %tmp1 = load i8***, i8**** %ref_idx456, align 8
+  %tmp2 = load i8**, i8*** %tmp1, align 8
+  %arrayidx458 = getelementptr inbounds i8*, i8** %tmp2, i64 0
+  %tmp3 = load i8*, i8** %arrayidx458, align 8
+  %arrayidx459 = getelementptr inbounds i8, i8* %tmp3, i64 0
+  %tmp4 = load i8, i8* %arrayidx459, align 1
+  %cmp461 = icmp eq i8 %tmp4, -1
+  br i1 %cmp461, label %if.then.463, label %if.else.476
+
+if.then.463:                                      ; preds = %if.then.397
+  br label %if.end.501
+
+if.else.476:                                      ; preds = %if.then.397
+  %ref_id491 = getelementptr inbounds %struct.storable_picture9, %struct.storable_picture9* %tmp, i64 0, i32 38
+  %tmp5 = load i64***, i64**** %ref_id491, align 8
+  br label %if.end.501
+
+if.end.501:                                       ; preds = %if.else.476, %if.then.463
+  %tmp6 = load i8***, i8**** %ref_idx456, align 8
+  %arrayidx505 = getelementptr inbounds i8**, i8*** %tmp6, i64 1
+  %tmp7 = load i8**, i8*** %arrayidx505, align 8
+  %arrayidx506 = getelementptr inbounds i8*, i8** %tmp7, i64 0
+  %tmp8 = load i8*, i8** %arrayidx506, align 8
+  %arrayidx507 = getelementptr inbounds i8, i8* %tmp8, i64 0
+  %tmp9 = load i8, i8* %arrayidx507, align 1
+  %cmp509 = icmp eq i8 %tmp9, -1
+  %ref_idx514 = getelementptr inbounds %struct.colocated_params, %struct.colocated_params* %p, i64 0, i32 4
+  %tmp10 = load i8***, i8**** %ref_idx514, align 8
+  %arrayidx515 = getelementptr inbounds i8**, i8*** %tmp10, i64 1
+  %tmp11 = load i8**, i8*** %arrayidx515, align 8
+  %arrayidx516 = getelementptr inbounds i8*, i8** %tmp11, i64 0
+  %tmp12 = load i8*, i8** %arrayidx516, align 8
+  %arrayidx517 = getelementptr inbounds i8, i8* %tmp12, i64 0
+  br i1 %cmp509, label %if.then.511, label %if.else.524
+
+if.then.511:                                      ; preds = %if.end.501
+  br label %if.end.549
+
+if.else.524:                                      ; preds = %if.end.501
+  store i8 %tmp9, i8* %arrayidx517, align 1
+  %ref_id539 = getelementptr inbounds %struct.storable_picture9, %struct.storable_picture9* %tmp, i64 0, i32 38
+  %tmp13 = load i64***, i64**** %ref_id539, align 8
+  br label %if.end.549
+
+if.end.549:                                       ; preds = %if.else.524, %if.then.511
+  br label %for.body.393
+
+if.else.643:                                      ; preds = %for.body.393
+  unreachable
+}
diff --git a/final/test/Isl/CodeGen/inv-load-lnt-crash-wrong-order.ll b/final/test/Isl/CodeGen/inv-load-lnt-crash-wrong-order.ll
new file mode 100644
index 0000000..bcc504c
--- /dev/null
+++ b/final/test/Isl/CodeGen/inv-load-lnt-crash-wrong-order.ll
@@ -0,0 +1,91 @@
+; RUN: opt %loadPolly -polly-codegen -S \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+; This crashed our codegen at some point, verify it runs through
+;
+; CHECK: polly.start
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.EqState.41.74.107.338.503.866.932.965.998.1064.2052.2151.2184.2606 = type { %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605*, %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588*, %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605* }
+%struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588 = type { i32, %struct.Production.29.62.95.326.491.854.920.953.986.1052.2040.2139.2172.2584*, i32, i32, i32, i32, %struct.anon.0.30.63.96.327.492.855.921.954.987.1053.2041.2140.2173.2585, %struct.Elem.12.45.78.309.474.837.903.936.969.1035.2023.2122.2155.2591*, %struct.Code.31.64.97.328.493.856.922.955.988.1054.2042.2141.2174.2586, %struct.Code.31.64.97.328.493.856.922.955.988.1054.2042.2141.2174.2586, %struct.anon.1.32.65.98.329.494.857.923.956.989.1055.2043.2142.2175.2587, i32, %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588* }
+%struct.Production.29.62.95.326.491.854.920.953.986.1052.2040.2139.2172.2584 = type { i8*, i32, %struct.anon.9.42.75.306.471.834.900.933.966.1032.2020.2119.2152.2581, i32, i8, %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588*, [8 x %struct.Production.29.62.95.326.491.854.920.953.986.1052.2040.2139.2172.2584*], [8 x %struct.Declaration.13.46.79.310.475.838.904.937.970.1036.2024.2123.2156.2582*], %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605*, %struct.Elem.12.45.78.309.474.837.903.936.969.1035.2023.2122.2155.2591*, %struct.Term.18.51.84.315.480.843.909.942.975.1041.2029.2128.2161.2583*, %struct.Production.29.62.95.326.491.854.920.953.986.1052.2040.2139.2172.2584* }
+%struct.anon.9.42.75.306.471.834.900.933.966.1032.2020.2119.2152.2581 = type { i32, i32, %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588**, [3 x %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588*] }
+%struct.Declaration.13.46.79.310.475.838.904.937.970.1036.2024.2123.2156.2582 = type { %struct.Elem.12.45.78.309.474.837.903.936.969.1035.2023.2122.2155.2591*, i32, i32 }
+%struct.Term.18.51.84.315.480.843.909.942.975.1041.2029.2128.2161.2583 = type { i32, i32, i32, i32, i32, i8*, i32, i8, %struct.Production.29.62.95.326.491.854.920.953.986.1052.2040.2139.2172.2584* }
+%struct.anon.0.30.63.96.327.492.855.921.954.987.1053.2041.2140.2173.2585 = type { i32, i32, %struct.Elem.12.45.78.309.474.837.903.936.969.1035.2023.2122.2155.2591**, [3 x %struct.Elem.12.45.78.309.474.837.903.936.969.1035.2023.2122.2155.2591*] }
+%struct.Elem.12.45.78.309.474.837.903.936.969.1035.2023.2122.2155.2591 = type { i32, i32, %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588*, %union.anon.11.44.77.308.473.836.902.935.968.1034.2022.2121.2154.2590 }
+%union.anon.11.44.77.308.473.836.902.935.968.1034.2022.2121.2154.2590 = type { %struct.Unresolved.10.43.76.307.472.835.901.934.967.1033.2021.2120.2153.2589 }
+%struct.Unresolved.10.43.76.307.472.835.901.934.967.1033.2021.2120.2153.2589 = type { i8*, i32 }
+%struct.Code.31.64.97.328.493.856.922.955.988.1054.2042.2141.2174.2586 = type { i8*, i32 }
+%struct.anon.1.32.65.98.329.494.857.923.956.989.1055.2043.2142.2175.2587 = type { i32, i32, %struct.Code.31.64.97.328.493.856.922.955.988.1054.2042.2141.2174.2586**, [3 x %struct.Code.31.64.97.328.493.856.922.955.988.1054.2042.2141.2174.2586*] }
+%struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605 = type { i32, i64, %struct.anon.2.14.47.80.311.476.839.905.938.971.1037.2025.2124.2157.2592, %struct.anon.3.15.48.81.312.477.840.906.939.972.1038.2026.2125.2158.2593, %struct.VecGoto.17.50.83.314.479.842.908.941.974.1040.2028.2127.2160.2595, %struct.VecAction.20.53.86.317.482.845.911.944.977.1043.2031.2130.2163.2597, %struct.VecAction.20.53.86.317.482.845.911.944.977.1043.2031.2130.2163.2597, %struct.VecHint.22.55.88.319.484.847.913.946.979.1045.2033.2132.2165.2599, %struct.VecHint.22.55.88.319.484.847.913.946.979.1045.2033.2132.2165.2599, %struct.Scanner.27.60.93.324.489.852.918.951.984.1050.2038.2137.2170.2604, i8, i8*, i32, %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605*, %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605*, %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588*, %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588* }
+%struct.anon.2.14.47.80.311.476.839.905.938.971.1037.2025.2124.2157.2592 = type { i32, i32, %struct.Elem.12.45.78.309.474.837.903.936.969.1035.2023.2122.2155.2591**, [3 x %struct.Elem.12.45.78.309.474.837.903.936.969.1035.2023.2122.2155.2591*] }
+%struct.anon.3.15.48.81.312.477.840.906.939.972.1038.2026.2125.2158.2593 = type { i32, i32, %struct.Elem.12.45.78.309.474.837.903.936.969.1035.2023.2122.2155.2591**, [3 x %struct.Elem.12.45.78.309.474.837.903.936.969.1035.2023.2122.2155.2591*] }
+%struct.VecGoto.17.50.83.314.479.842.908.941.974.1040.2028.2127.2160.2595 = type { i32, i32, %struct.Goto.16.49.82.313.478.841.907.940.973.1039.2027.2126.2159.2594**, [3 x %struct.Goto.16.49.82.313.478.841.907.940.973.1039.2027.2126.2159.2594*] }
+%struct.Goto.16.49.82.313.478.841.907.940.973.1039.2027.2126.2159.2594 = type { %struct.Elem.12.45.78.309.474.837.903.936.969.1035.2023.2122.2155.2591*, %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605* }
+%struct.VecAction.20.53.86.317.482.845.911.944.977.1043.2031.2130.2163.2597 = type { i32, i32, %struct.Action.19.52.85.316.481.844.910.943.976.1042.2030.2129.2162.2596**, [3 x %struct.Action.19.52.85.316.481.844.910.943.976.1042.2030.2129.2162.2596*] }
+%struct.Action.19.52.85.316.481.844.910.943.976.1042.2030.2129.2162.2596 = type { i32, %struct.Term.18.51.84.315.480.843.909.942.975.1041.2029.2128.2161.2583*, %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588*, %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605*, i32, i8* }
+%struct.VecHint.22.55.88.319.484.847.913.946.979.1045.2033.2132.2165.2599 = type { i32, i32, %struct.Hint.21.54.87.318.483.846.912.945.978.1044.2032.2131.2164.2598**, [3 x %struct.Hint.21.54.87.318.483.846.912.945.978.1044.2032.2131.2164.2598*] }
+%struct.Hint.21.54.87.318.483.846.912.945.978.1044.2032.2131.2164.2598 = type { i32, %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605*, %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588* }
+%struct.Scanner.27.60.93.324.489.852.918.951.984.1050.2038.2137.2170.2604 = type { %struct.VecScanState.25.58.91.322.487.850.916.949.982.1048.2036.2135.2168.2602, %struct.VecScanStateTransition.26.59.92.323.488.851.917.950.983.1049.2037.2136.2169.2603 }
+%struct.VecScanState.25.58.91.322.487.850.916.949.982.1048.2036.2135.2168.2602 = type { i32, i32, %struct.ScanState.24.57.90.321.486.849.915.948.981.1047.2035.2134.2167.2601**, [3 x %struct.ScanState.24.57.90.321.486.849.915.948.981.1047.2035.2134.2167.2601*] }
+%struct.ScanState.24.57.90.321.486.849.915.948.981.1047.2035.2134.2167.2601 = type { i32, [256 x %struct.ScanState.24.57.90.321.486.849.915.948.981.1047.2035.2134.2167.2601*], %struct.VecAction.20.53.86.317.482.845.911.944.977.1043.2031.2130.2163.2597, %struct.VecAction.20.53.86.317.482.845.911.944.977.1043.2031.2130.2163.2597, [256 x %struct.ScanStateTransition.23.56.89.320.485.848.914.947.980.1046.2034.2133.2166.2600*] }
+%struct.ScanStateTransition.23.56.89.320.485.848.914.947.980.1046.2034.2133.2166.2600 = type { i32, %struct.VecAction.20.53.86.317.482.845.911.944.977.1043.2031.2130.2163.2597, %struct.VecAction.20.53.86.317.482.845.911.944.977.1043.2031.2130.2163.2597 }
+%struct.VecScanStateTransition.26.59.92.323.488.851.917.950.983.1049.2037.2136.2169.2603 = type { i32, i32, %struct.ScanStateTransition.23.56.89.320.485.848.914.947.980.1046.2034.2133.2166.2600**, [3 x %struct.ScanStateTransition.23.56.89.320.485.848.914.947.980.1046.2034.2133.2166.2600*] }
+
+; Function Attrs: nounwind
+declare noalias i8* @malloc() #0
+
+; Function Attrs: nounwind uwtable
+define void @build_eq() #1 {
+entry:
+  %call = tail call noalias i8* @malloc() #2
+  %0 = bitcast i8* %call to %struct.EqState.41.74.107.338.503.866.932.965.998.1064.2052.2151.2184.2606*
+  br label %for.cond.preheader
+
+for.cond.preheader:                               ; preds = %for.cond.preheader, %entry
+  br i1 undef, label %for.cond.316.preheader, label %for.cond.preheader
+
+for.cond.316.preheader:                           ; preds = %for.cond.preheader
+  br i1 undef, label %for.cond.400.preheader, label %for.body.321
+
+for.cond.400.preheader:                           ; preds = %for.inc.397, %for.cond.316.preheader
+  br i1 undef, label %for.end.423, label %for.body.405
+
+for.body.321:                                     ; preds = %for.inc.397, %for.cond.316.preheader
+  %eq329 = getelementptr inbounds %struct.EqState.41.74.107.338.503.866.932.965.998.1064.2052.2151.2184.2606, %struct.EqState.41.74.107.338.503.866.932.965.998.1064.2052.2151.2184.2606* %0, i64 0, i32 0
+  br i1 undef, label %for.inc.397, label %land.lhs.true.331
+
+land.lhs.true.331:                                ; preds = %for.body.321
+  br i1 undef, label %for.inc.397, label %if.then.334
+
+if.then.334:                                      ; preds = %land.lhs.true.331
+  %1 = load %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605*, %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605** %eq329, align 8
+  %2 = load %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588*, %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588** undef, align 8
+  br i1 undef, label %for.inc.397, label %land.lhs.true.369
+
+land.lhs.true.369:                                ; preds = %if.then.334
+  %n380 = getelementptr inbounds %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588, %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588* %2, i64 0, i32 6, i32 0
+  %3 = load i32, i32* %n380, align 8
+  %cmp381 = icmp eq i32 %3, 2
+  br i1 %cmp381, label %if.then.383, label %for.inc.397
+
+if.then.383:                                      ; preds = %land.lhs.true.369
+  %reduces_to385 = getelementptr inbounds %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605, %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605* %1, i64 0, i32 14
+  store %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605* undef, %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605** %reduces_to385, align 8
+  %diff_rule386 = getelementptr inbounds %struct.EqState.41.74.107.338.503.866.932.965.998.1064.2052.2151.2184.2606, %struct.EqState.41.74.107.338.503.866.932.965.998.1064.2052.2151.2184.2606* %0, i64 0, i32 1
+  %4 = bitcast %struct.Rule.33.66.99.330.495.858.924.957.990.1056.2044.2143.2176.2588** %diff_rule386 to i64*
+  %5 = load i64, i64* %4, align 8
+  %6 = load %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605*, %struct.State.28.61.94.325.490.853.919.952.985.1051.2039.2138.2171.2605** %eq329, align 8
+  br label %for.inc.397
+
+for.inc.397:                                      ; preds = %if.then.383, %land.lhs.true.369, %if.then.334, %land.lhs.true.331, %for.body.321
+  br i1 undef, label %for.body.321, label %for.cond.400.preheader
+
+for.body.405:                                     ; preds = %for.cond.400.preheader
+  unreachable
+
+for.end.423:                                      ; preds = %for.cond.400.preheader
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant-load-dimension.ll b/final/test/Isl/CodeGen/invariant-load-dimension.ll
new file mode 100644
index 0000000..b65c7e4
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant-load-dimension.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly < %s -analyze -polly-scops -polly-process-unprofitable -polly-invariant-load-hoisting | FileCheck %s -check-prefix=SCOPS
+; RUN: opt %loadPolly -S < %s -polly-codegen -polly-process-unprofitable -polly-invariant-load-hoisting | FileCheck %s -check-prefix=CODEGEN
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n8:16:32-S64"
+
+%S = type { i32, i32, [12 x %L] }
+%L = type { i32, i32, double, i32, i32, i32, i32, i32 }
+
+define void @test(%S* %cpi, i1 %b) {
+; SCOPS-LABEL: Region: %if.then14---%exit
+; SCOPS:         Invariant Accesses: {
+; SCOPS-NEXT:            ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; SCOPS-NEXT:                [l2, l1] -> { Stmt_for_body_i[i0] -> MemRef_cpi[0, 0] };
+; SCOPS-NEXT:            Execution Context: [l2, l1] -> {  :  }
+; SCOPS-NEXT:            ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; SCOPS-NEXT:                [l2, l1] -> { Stmt_for_body_lr_ph_i[] -> MemRef_cpi[0, 1] };
+; SCOPS-NEXT:            Execution Context: [l2, l1] -> {  : l2 > 0 }
+; SCOPS-NEXT:    }
+; SCOPS:         Arrays {
+; SCOPS-NEXT:        i32 MemRef_cpi[*][(10 * %l1)]; // Element size 4
+; SCOPS-NEXT:    }
+
+; FIXME: Figure out how to actually generate code for this loop.
+; CODEGEN-LABEL: @test(
+; CODEGEN:    polly.preload.begin:
+; CODEGEN-NEXT:  br i1 false
+
+entry:
+  %nt = getelementptr inbounds %S, %S* %cpi, i32 0, i32 1
+  br i1 %b, label %if.then14, label %exit
+
+if.then14:
+  %ns = getelementptr inbounds %S, %S* %cpi, i32 0, i32 0
+  %l0 = load i32, i32* %ns, align 8
+  %cmp12.i = icmp sgt i32 %l0, 0
+  br i1 %cmp12.i, label %for.body.lr.ph.i, label %exit
+
+for.body.lr.ph.i:
+  %l1 = load i32, i32* %nt, align 4
+  br label %for.body.i
+
+for.body.i:
+  %phi = phi i32 [ 0, %for.body.lr.ph.i ], [ %inc, %for.body.i ]
+  %mul.i163 = mul nsw i32 %phi, %l1
+  %cv = getelementptr inbounds %S, %S* %cpi, i32 0, i32 2, i32 %mul.i163, i32 0
+  store i32 0, i32* %cv, align 8
+  %inc = add nuw nsw i32 %phi, 1
+  %l2 = load i32, i32* %ns, align 8
+  %cmp.i164 = icmp slt i32 %inc, %l2
+  br i1 %cmp.i164, label %for.body.i, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant-load-preload-base-pointer-origin-first.ll b/final/test/Isl/CodeGen/invariant-load-preload-base-pointer-origin-first.ll
new file mode 100644
index 0000000..f905495
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant-load-preload-base-pointer-origin-first.ll
@@ -0,0 +1,91 @@
+; RUN: opt %loadPolly -S -polly-codegen -polly-invariant-load-hoisting=true < %s
+;
+; Check that we generate valid code as we did non preload the base pointer
+; origin of %tmp4 at some point.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@TOP = external global i64*, align 8
+@BOT = external global i64*, align 8
+
+define void @RemoveConstraintVCG() {
+entry:
+  br i1 undef, label %for.end.161, label %for.cond.2.preheader
+
+for.cond.2.preheader:                             ; preds = %entry
+  br i1 undef, label %for.end.128, label %for.body.4
+
+for.body.4:                                       ; preds = %for.inc.126, %for.cond.2.preheader
+  br i1 undef, label %for.cond.8.preheader, label %for.inc.126
+
+for.cond.8.preheader:                             ; preds = %for.body.4
+  br i1 undef, label %for.inc.126, label %for.body.11
+
+for.body.11:                                      ; preds = %for.inc, %for.cond.8.preheader
+  br i1 undef, label %land.lhs.true, label %for.inc
+
+land.lhs.true:                                    ; preds = %for.body.11
+  br i1 undef, label %if.then.20, label %for.inc
+
+if.then.20:                                       ; preds = %land.lhs.true
+  %tmp = load i64*, i64** @TOP, align 8
+  %tmp1 = load i64, i64* %tmp, align 8
+  %cmp25 = icmp eq i64 %tmp1, 1
+  %cmp47 = icmp eq i64 %tmp1, 0
+  br i1 false, label %if.end.117, label %lor.lhs.false.85
+
+lor.lhs.false.85:                                 ; preds = %if.then.20
+  %add94 = add i64 %tmp1, 1
+  %tmp2 = load i64*, i64** @TOP, align 8
+  %arrayidx95 = getelementptr inbounds i64, i64* %tmp2, i64 %add94
+  %tmp3 = load i64, i64* %arrayidx95, align 8
+  br i1 false, label %if.else.103, label %land.lhs.true.97
+
+land.lhs.true.97:                                 ; preds = %lor.lhs.false.85
+  %tmp4 = load i64*, i64** @BOT, align 8
+  %arrayidx99 = getelementptr inbounds i64, i64* %tmp4, i64 %add94
+  %tmp5 = load i64, i64* %arrayidx99, align 8
+  %tobool100 = icmp eq i64 %tmp5, 0
+  br i1 %tobool100, label %if.else.103, label %if.then.101
+
+if.then.101:                                      ; preds = %land.lhs.true.97
+  br label %if.end.117
+
+if.else.103:                                      ; preds = %land.lhs.true.97, %lor.lhs.false.85
+  %tmp6 = load i64*, i64** @TOP, align 8
+  %arrayidx105 = getelementptr inbounds i64, i64* %tmp6, i64 %add94
+  %tmp7 = load i64, i64* %arrayidx105, align 8
+  br i1 false, label %lor.lhs.false.107, label %if.else.112
+
+lor.lhs.false.107:                                ; preds = %if.else.103
+  %tmp8 = load i64*, i64** @BOT, align 8
+  %arrayidx109 = getelementptr inbounds i64, i64* %tmp8, i64 %add94
+  br i1 false, label %if.end.117, label %if.else.112
+
+if.else.112:                                      ; preds = %lor.lhs.false.107, %if.else.103
+  br label %if.end.117
+
+if.end.117:                                       ; preds = %if.else.112, %lor.lhs.false.107, %if.then.101, %if.then.20
+  br i1 undef, label %if.then.119, label %for.inc
+
+if.then.119:                                      ; preds = %if.end.117
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.then.119, %if.end.117, %land.lhs.true, %for.body.11
+  br i1 false, label %for.body.11, label %for.inc.126
+
+for.inc.126:                                      ; preds = %for.inc, %for.cond.8.preheader, %for.body.4
+  br i1 undef, label %for.end.128, label %for.body.4
+
+for.end.128:                                      ; preds = %for.inc.126, %for.cond.2.preheader
+  br i1 false, label %cond.false, label %cond.end
+
+cond.false:                                       ; preds = %for.end.128
+  unreachable
+
+cond.end:                                         ; preds = %for.end.128
+  unreachable
+
+for.end.161:                                      ; preds = %entry
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_cannot_handle_void.ll b/final/test/Isl/CodeGen/invariant_cannot_handle_void.ll
new file mode 100644
index 0000000..23663a4
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_cannot_handle_void.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -analyze -polly-scops -polly-invariant-load-hoisting=true %s | FileCheck %s --check-prefix=SCOP
+; RUN: opt %loadPolly -S -polly-codegen -polly-invariant-load-hoisting=true %s | FileCheck %s
+;
+; The offset of the %tmp1 load wrt. to %buff (62 bytes) is not divisible
+; by the type size (i32 = 4 bytes), thus we will have to represent %buff
+; with a smaller type. In this case i16 is sufficient to represent the
+; 62 byte offset accurately.
+;
+; SCOP:    Invariant Accesses: {
+; SCOP:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP:                { Stmt_if_end_6[] -> MemRef_buff[o0] : 31 <= o0 <= 32 };
+; SCOP:            Execution Context: {  :  }
+; SCOP:    }
+; SCOP:    Arrays {
+; SCOP:        i16 MemRef_buff[*]; // Element size 2
+; SCOP:        i32 MemRef_key_0; // Element size 4
+; SCOP:    }
+;
+; CHECK-LABEL: polly.preload.begin:
+; CHECK-NEXT:    %polly.access.cast.buff = bitcast i8* %buff to i16*
+; CHECK-NEXT:    %polly.access.buff = getelementptr i16, i16* %polly.access.cast.buff, i64 31
+; CHECK-NEXT:    %polly.access.buff.cast = bitcast i16* %polly.access.buff to i32*
+; CHECK-NEXT:    %polly.access.buff.load = load i32, i32* %polly.access.buff.cast, align 4
+; CHECK-NEXT:    store i32 %polly.access.buff.load, i32* %tmp1.preload.s2a
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @sudecrypt(i8* %buff) #0 {
+entry:
+  br i1 undef, label %cleanup, label %if.end
+
+if.end:                                           ; preds = %entry
+  br i1 undef, label %if.end.6, label %if.then.5
+
+if.then.5:                                        ; preds = %if.end
+  unreachable
+
+if.end.6:                                         ; preds = %if.end
+  %add.ptr = getelementptr inbounds i8, i8* %buff, i64 62
+  %tmp = bitcast i8* %add.ptr to i32*
+  %tmp1 = load i32, i32* %tmp, align 4, !tbaa !1
+  br i1 false, label %if.then.13, label %switch.early.test
+
+switch.early.test:                                ; preds = %if.end.6
+  switch i32 0, label %if.end.16 [
+    i32 956, label %if.then.13
+    i32 520, label %if.then.13
+  ]
+
+if.then.13:                                       ; preds = %switch.early.test, %switch.early.test, %if.end.6
+  br label %if.end.16
+
+if.end.16:                                        ; preds = %if.then.13, %switch.early.test
+  %key.0 = phi i32 [ undef, %if.then.13 ], [ 0, %switch.early.test ]
+  br i1 undef, label %if.end.34, label %if.then.19
+
+if.then.19:                                       ; preds = %if.end.16
+  unreachable
+
+if.end.34:                                        ; preds = %if.end.16
+  unreachable
+
+cleanup:                                          ; preds = %entry
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 250010) (llvm/trunk 250018)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"int", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/Isl/CodeGen/invariant_load.ll b/final/test/Isl/CodeGen/invariant_load.ll
new file mode 100644
index 0000000..163c3f3
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s
+;
+; CHECK-LABEL: polly.preload.begin:
+; CHECK-NEXT:    %polly.access.B = getelementptr i32, i32* %B, i64 0
+; CHECK-NEXT:    %polly.access.B.load = load i32, i32* %polly.access.B
+;
+; CHECK-LABEL: polly.stmt.bb2:
+; CHECK-NEXT:    %scevgep = getelementptr i32, i32* %A, i64 %polly.indvar
+; CHECK-NEXT:    store i32 %polly.access.B.load, i32* %scevgep, align 4
+;
+;    void f(int *restrict A, int *restrict B) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = *B;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* noalias %A, i32* noalias %B) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb4, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb4 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb5
+
+bb2:                                              ; preds = %bb1
+  %tmp = load i32, i32* %B, align 4
+  %tmp3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp, i32* %tmp3, align 4
+  br label %bb4
+
+bb4:                                              ; preds = %bb2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb5:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_address_space.ll b/final/test/Isl/CodeGen/invariant_load_address_space.ll
new file mode 100644
index 0000000..5ed73dc
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_address_space.ll
@@ -0,0 +1,40 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s
+;
+; CHECK-LABEL: polly.preload.begin:
+; CHECK-NEXT:    %polly.access.B = getelementptr i32, i32 addrspace(1)* %B, i64 0
+; CHECK-NOT:     addrspacecast 
+; CHECK-NEXT:    %polly.access.B.load = load i32, i32 addrspace(1)* %polly.access.B
+;
+; CHECK-LABEL: polly.stmt.bb2:
+; CHECK-NEXT:    %scevgep = getelementptr i32, i32* %A, i64 %polly.indvar
+; CHECK-NEXT:    store i32 %polly.access.B.load, i32* %scevgep, align 4
+;
+;    void f(int *restrict A, int *restrict B) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = *B;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* noalias %A, i32 addrspace(1)* noalias %B) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb4, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb4 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb5
+
+bb2:                                              ; preds = %bb1
+  %tmp = load i32, i32 addrspace(1)* %B, align 4
+  %tmp3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp, i32* %tmp3, align 4
+  br label %bb4
+
+bb4:                                              ; preds = %bb2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb5:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_alias_metadata.ll b/final/test/Isl/CodeGen/invariant_load_alias_metadata.ll
new file mode 100644
index 0000000..a21d993
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_alias_metadata.ll
@@ -0,0 +1,32 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true \
+; RUN: -S < %s | FileCheck %s
+;
+; This test case checks whether Polly generates alias metadata in case of
+; the ublas gemm kernel and polly-invariant-load-hoisting.
+;
+; CHECK: store float 4.200000e+01, float* %polly.access.A.load, !alias.scope !3, !noalias !4
+;
+; CHECK: !0 = distinct !{!0, !1, !"polly.alias.scope.MemRef_A"}
+; CHECK-NEXT: !1 = distinct !{!1, !"polly.alias.scope.domain"}
+; CHECK-NEXT: !2 = !{!3}
+; CHECK-NEXT: !3 = distinct !{!3, !1, !"polly.alias.scope.MemRef_ptrA"}
+; CHECK-NEXT: !4 = !{!0}
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @nometadata(float** %A) {
+  entry:
+    br label %for
+
+  for:
+    %indvar = phi i64 [0, %entry], [%indvar.next, %for]
+    %indvar.next = add i64 %indvar, 1
+    %ptrA = load float*, float** %A
+    store float 42.0, float* %ptrA
+    %icmp = icmp sle i64 %indvar, 1024
+    br i1 %icmp, label %for, label %exit
+
+  exit:
+    ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_base_pointer.ll b/final/test/Isl/CodeGen/invariant_load_base_pointer.ll
new file mode 100644
index 0000000..6ec27d1
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_base_pointer.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly  -polly-codegen -polly-invariant-load-hoisting=true -polly-ignore-aliasing -polly-process-unprofitable -S < %s | FileCheck %s
+;
+; CHECK-LABEL: polly.preload.begin:
+; CHECK-NEXT:    %polly.access.BPLoc = getelementptr i32*, i32** %BPLoc, i64 0
+; CHECK-NEXT:    %polly.access.BPLoc.load = load i32*, i32** %polly.access.BPLoc
+;
+; CHECK-LABEL: polly.stmt.bb2:
+; CHECK-NEXT:    %scevgep = getelementptr i32, i32* %polly.access.BPLoc.load, i64 %polly.indvar
+;
+;    void f(int **BPLoc) {
+;      for (int i = 0; i < 1024; i++)
+;        (*BPLoc)[i] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32** %BPLoc) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb4, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb4 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb5
+
+bb2:                                              ; preds = %bb1
+  %tmp = load i32*, i32** %BPLoc, align 8
+  %tmp3 = getelementptr inbounds i32, i32* %tmp, i64 %indvars.iv
+  store i32 0, i32* %tmp3, align 4
+  br label %bb4
+
+bb4:                                              ; preds = %bb2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb5:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_base_pointer_conditional.ll b/final/test/Isl/CodeGen/invariant_load_base_pointer_conditional.ll
new file mode 100644
index 0000000..987a3ba
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_base_pointer_conditional.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly  -polly-codegen -polly-invariant-load-hoisting=true -polly-ignore-aliasing -polly-process-unprofitable -S < %s | FileCheck %s
+;
+; CHECK-LABEL: polly.preload.begin:
+; CHECK-NEXT:    %0 = sext i32 %N to i64
+; CHECK-NEXT:    %1 = icmp sge i64 %0, 514
+; CHECK-NEXT:    br label %polly.preload.cond
+;
+; CHECK-LABEL: polly.preload.cond:
+; CHECK-NEXT:    br i1 %1, label %polly.preload.exec, label %polly.preload.merge
+;
+; CHECK-LABEL: polly.preload.merge:
+; CHECK-NEXT:    %polly.preload.tmp6.merge = phi i32* [ %polly.access.BPLoc.load, %polly.preload.exec ], [ null, %polly.preload.cond ]
+;
+; CHECK-LABEL: polly.stmt.bb5:
+; CHECK-NEXT:    %scevgep9 = getelementptr i32, i32* %polly.preload.tmp6.merge, i64 %polly.indvar6
+;
+;    void f(int **BPLoc, int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        if (i > 512)
+;          (*BPLoc)[i] = 0;
+;        else
+;          A[i] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32** %BPLoc, i32* %A, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  br label %bb1
+
+bb1:                                              ; preds = %bb11, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb11 ], [ 0, %bb ]
+  %tmp2 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp2, label %bb3, label %bb12
+
+bb3:                                              ; preds = %bb1
+  %tmp4 = icmp sgt i64 %indvars.iv, 512
+  br i1 %tmp4, label %bb5, label %bb8
+
+bb5:                                              ; preds = %bb3
+  %tmp6 = load i32*, i32** %BPLoc, align 8
+  %tmp7 = getelementptr inbounds i32, i32* %tmp6, i64 %indvars.iv
+  store i32 0, i32* %tmp7, align 4
+  br label %bb10
+
+bb8:                                              ; preds = %bb3
+  %tmp9 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 0, i32* %tmp9, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb8, %bb5
+  br label %bb11
+
+bb11:                                             ; preds = %bb10
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb12:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_base_pointer_conditional_2.ll b/final/test/Isl/CodeGen/invariant_load_base_pointer_conditional_2.ll
new file mode 100644
index 0000000..e2397c9
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_base_pointer_conditional_2.ll
@@ -0,0 +1,112 @@
+; RUN: opt %loadPolly -analyze -polly-scops -polly-invariant-load-hoisting=true < %s | FileCheck %s
+; RUN: opt %loadPolly -S -polly-codegen -polly-invariant-load-hoisting=true < %s | FileCheck %s --check-prefix=IR
+; RUN: opt %loadPolly -S -polly-codegen -polly-invariant-load-hoisting=true --polly-overflow-tracking=always < %s | FileCheck %s --check-prefix=IRA
+;
+; As (p + q) can overflow we have to check that we load from
+; I[p + q] only if it does not.
+;
+; CHECK:         Invariant Accesses: {
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [N, p, q] -> { Stmt_for_body[i0] -> MemRef_I[p + q] };
+; CHECK-NEXT:            Execution Context: [N, p, q] -> {  : N > 0 and -2147483648 - p <= q <= 2147483647 - p }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [N, p, q] -> { Stmt_for_body[i0] -> MemRef_tmp1[0] };
+; CHECK-NEXT:            Execution Context: [N, p, q] -> {  : N > 0 }
+; CHECK-NEXT:    }
+;
+; IR:      polly.preload.merge:
+; IR-NEXT:   %polly.preload.tmp1.merge = phi i32* [ %polly.access.I.load, %polly.preload.exec ], [ null, %polly.preload.cond ]
+; IR-NEXT:   store i32* %polly.preload.tmp1.merge, i32** %tmp1.preload.s2a
+; IR-NEXT:   %12 = sext i32 %N to i64
+; IR-NEXT:   %13 = icmp sge i64 %12, 1
+; IR-NEXT:   %14 = sext i32 %q to i64
+; IR-NEXT:   %15 = sext i32 %p to i64
+; IR-NEXT:   %16 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %15, i64 %14)
+; IR-NEXT:   %.obit4 = extractvalue { i64, i1 } %16, 1
+; IR-NEXT:   %polly.overflow.state5 = or i1 false, %.obit4
+; IR-NEXT:   %.res6 = extractvalue { i64, i1 } %16, 0
+; IR-NEXT:   %17 = icmp sle i64 %.res6, 2147483647
+; IR-NEXT:   %18 = and i1 %13, %17
+; IR-NEXT:   %19 = sext i32 %q to i64
+; IR-NEXT:   %20 = sext i32 %p to i64
+; IR-NEXT:   %21 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %20, i64 %19)
+; IR-NEXT:   %.obit7 = extractvalue { i64, i1 } %21, 1
+; IR-NEXT:   %polly.overflow.state8 = or i1 %polly.overflow.state5, %.obit7
+; IR-NEXT:   %.res9 = extractvalue { i64, i1 } %21, 0
+; IR-NEXT:   %22 = icmp sge i64 %.res9, -2147483648
+; IR-NEXT:   %23 = and i1 %18, %22
+; IR-NEXT:   %polly.preload.cond.overflown10 = xor i1 %polly.overflow.state8, true
+; IR-NEXT:   %polly.preload.cond.result11 = and i1 %23, %polly.preload.cond.overflown10
+; IR-NEXT:   br label %polly.preload.cond12
+;
+; IR:      polly.preload.cond12:
+; IR-NEXT:   br i1 %polly.preload.cond.result11
+;
+; IR:      polly.preload.exec14:
+; IR-NEXT:   %polly.access.polly.preload.tmp1.merge = getelementptr i32, i32* %polly.preload.tmp1.merge, i64 0
+; IR-NEXT:   %polly.access.polly.preload.tmp1.merge.load = load i32, i32* %polly.access.polly.preload.tmp1.merge, align 4
+;
+; IRA:      polly.preload.merge:
+; IRA-NEXT:   %polly.preload.tmp1.merge = phi i32* [ %polly.access.I.load, %polly.preload.exec ], [ null, %polly.preload.cond ]
+; IRA-NEXT:   store i32* %polly.preload.tmp1.merge, i32** %tmp1.preload.s2a
+; IRA-NEXT:   %12 = sext i32 %N to i64
+; IRA-NEXT:   %13 = icmp sge i64 %12, 1
+; IRA-NEXT:   %14 = sext i32 %q to i64
+; IRA-NEXT:   %15 = sext i32 %p to i64
+; IRA-NEXT:   %16 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %15, i64 %14)
+; IRA-NEXT:   %.obit5 = extractvalue { i64, i1 } %16, 1
+; IRA-NEXT:   %.res6 = extractvalue { i64, i1 } %16, 0
+; IRA-NEXT:   %17 = icmp sle i64 %.res6, 2147483647
+; IRA-NEXT:   %18 = and i1 %13, %17
+; IRA-NEXT:   %19 = sext i32 %q to i64
+; IRA-NEXT:   %20 = sext i32 %p to i64
+; IRA-NEXT:   %21 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %20, i64 %19)
+; IRA-NEXT:   %.obit7 = extractvalue { i64, i1 } %21, 1
+; IRA-NEXT:   %.res8 = extractvalue { i64, i1 } %21, 0
+; IRA-NEXT:   %22 = icmp sge i64 %.res8, -2147483648
+; IRA-NEXT:   %23 = and i1 %18, %22
+; IRA-NEXT:   %polly.preload.cond.overflown9 = xor i1 %.obit7, true
+; IRA-NEXT:   %polly.preload.cond.result10 = and i1 %23, %polly.preload.cond.overflown9
+; IRA-NEXT:   br label %polly.preload.cond11
+;
+; IRA:      polly.preload.cond11:
+; IRA-NEXT:   br i1 %polly.preload.cond.result10
+;
+; IRA:      polly.preload.exec13:
+; IRA-NEXT:   %polly.access.polly.preload.tmp1.merge = getelementptr i32, i32* %polly.preload.tmp1.merge, i64 0
+; IRA-NEXT:   %polly.access.polly.preload.tmp1.merge.load = load i32, i32* %polly.access.polly.preload.tmp1.merge, align 4
+;
+;    void f(int **I, int *A, int N, int p, int q) {
+;      for (int i = 0; i < N; i++)
+;        A[i] = *(I[p + q]);
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32** %I, i32* %A, i32 %N, i32 %p, i32 %q) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add = add i32 %p, %q
+  %idxprom = sext i32 %add to i64
+  %arrayidx = getelementptr inbounds i32*, i32** %I, i64 %idxprom
+  %tmp1 = load i32*, i32** %arrayidx, align 8
+  %tmp2 = load i32, i32* %tmp1, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp2, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_canonicalize_array_baseptrs.ll b/final/test/Isl/CodeGen/invariant_load_canonicalize_array_baseptrs.ll
new file mode 100644
index 0000000..e22e04b
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_canonicalize_array_baseptrs.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s \
+; RUN:  -polly-invariant-load-hoisting \
+; RUN:  | FileCheck %s
+
+; CHECK: %polly.access.A = getelementptr float*, float** %A, i64 0
+; CHECK: %polly.access.A.load = load float*, float** %polly.access.A
+; CHECK: store float 4.200000e+01, float* %polly.access.A.load
+; CHECK: store float 4.800000e+01, float* %polly.access.A.load
+
+define void @foo(float** %A) {
+start:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
+  %indvar.next = add nsw i64 %indvar, 1
+  %icmp = icmp slt i64 %indvar.next, 1024
+  br i1 %icmp, label %body1, label %exit
+
+body1:
+  %baseA = load float*, float** %A
+  store float 42.0, float* %baseA
+  br label %body2
+
+body2:
+  %baseB = load float*, float** %A
+  store float 48.0, float* %baseB
+  br label %latch
+
+latch:
+  br label %loop
+
+exit:
+  ret void
+
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_condition.ll b/final/test/Isl/CodeGen/invariant_load_condition.ll
new file mode 100644
index 0000000..7a2fa6b
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_condition.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-process-unprofitable -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s
+;
+; CHECK-LABEL: polly.preload.begin:
+; CHECK-NEXT:     %polly.access.C = getelementptr i32, i32* %C, i64 0
+; CHECK-NEXT:     %polly.access.C.load = load i32, i32* %polly.access.C
+; CHECK-NOT:      %polly.access.C.load = load i32, i32* %polly.access.C
+;
+; CHECK-LABEL: polly.cond:
+; CHECK-NEXT:   %[[R0:[0-9]*]] = sext i32 %polly.access.C.load to i64
+; CHECK-NEXT:   %[[R1:[0-9]*]] = icmp sle i64 %[[R0]], -1
+; CHECK-NEXT:   %[[R2:[0-9]*]] = sext i32 %polly.access.C.load to i64
+; CHECK-NEXT:   %[[R3:[0-9]*]] = icmp sge i64 %[[R2]], 1
+; CHECK-NEXT:   %[[R4:[0-9]*]] = or i1 %[[R1]], %[[R3]]
+; CHECK-NEXT:   br i1 %[[R4]]
+;
+; CHECK-NOT:  polly.stmt.bb2
+;
+;    void f(int *A, int *C) {
+;      for (int i = 0; i < 1024; i++)
+;        if (*C)
+;          A[i] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %C) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb7, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb7 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = load i32, i32* %C, align 4
+  %tmp3 = icmp eq i32 %tmp, 0
+  br i1 %tmp3, label %bb6, label %bb4
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 0, i32* %tmp5, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2, %bb4
+  br label %bb7
+
+bb7:                                              ; preds = %bb6
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_different_sized_types.ll b/final/test/Isl/CodeGen/invariant_load_different_sized_types.ll
new file mode 100644
index 0000000..a08ecfa
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_different_sized_types.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S \
+; RUN: -polly-allow-differing-element-types < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK: polly.preload.begin:  ; preds = %polly.split_new_and_old
+; CHECK-NEXT:   %polly.access.cast.tmp2 = bitcast %struct.hoge* %tmp2 to i32*
+; CHECK-NEXT:   %polly.access.tmp2 = getelementptr i32, i32* %polly.access.cast.tmp2, i64 1
+; CHECK-NEXT:   %polly.access.tmp2.load = load i32, i32* %polly.access.tmp2, align 1
+; CHECK-NEXT:   store i32 %polly.access.tmp2.load, i32* %tmp.preload.s2a
+
+
+%struct.hoge = type { [4 x i8], i32, i32, i32, i32, i32, [16 x i8], [16 x i8], i64, i64, i64, i64, i64 }
+
+; Function Attrs: nounwind uwtable
+define void @widget() #0 {
+bb:
+  %tmp2 = alloca %struct.hoge, align 1
+  br label %bb3
+
+bb3:                                              ; preds = %bb
+  %tmp4 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp2, i64 0, i32 10
+  %tmp5 = add nsw i32 undef, 1
+  %tmp6 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp2, i64 0, i32 1
+  %tmp = load i32, i32* %tmp6, align 1, !tbaa !1
+  %tmp7 = icmp slt i32 %tmp, 3
+  br i1 %tmp7, label %bb8, label %bb10
+
+bb8:                                              ; preds = %bb3
+  %tmp9 = load i64, i64* %tmp4, align 1, !tbaa !7
+  br label %bb10
+
+bb10:                                             ; preds = %bb8, %bb3
+  %tmp11 = icmp eq i32 %tmp5, 0
+  br i1 %tmp11, label %bb13, label %bb12
+
+bb12:                                             ; preds = %bb10
+  ret void
+
+bb13:                                             ; preds = %bb10
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.9.0 (trunk 259751) (llvm/trunk 259771)"}
+!1 = !{!2, !5, i64 4}
+!2 = !{!"itsf_header_tag", !3, i64 0, !5, i64 4, !5, i64 8, !5, i64 12, !5, i64 16, !5, i64 20, !3, i64 24, !3, i64 40, !6, i64 56, !6, i64 64, !6, i64 72, !6, i64 80, !6, i64 88}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!"int", !3, i64 0}
+!6 = !{!"long", !3, i64 0}
+!7 = !{!2, !6, i64 72}
diff --git a/final/test/Isl/CodeGen/invariant_load_escaping.ll b/final/test/Isl/CodeGen/invariant_load_escaping.ll
new file mode 100644
index 0000000..9c1fbfb
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_escaping.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s
+;
+;    int f(int *A, int *B) {
+;      // Possible aliasing between A and B but if not then *B would be
+;      // invariant. We assume this and hoist *B but need to use a merged 
+;      // version in the return.
+;      int i = 0;
+;      int x = 0;
+;
+;      do {
+;        x = *B;
+;        A[i] += x;
+;      } while (i++ < 100);
+;
+;      return x;
+;    }
+;
+; CHECK: polly.preload.begin:
+; CHECK:   %polly.access.B = getelementptr i32, i32* %B, i64 0
+; CHECK:   %polly.access.B.load = load i32, i32* %polly.access.B
+; CHECK:   store i32 %polly.access.B.load, i32* %tmp.preload.s2a
+;
+; CHECK: polly.merge_new_and_old:
+; CHECK:   %tmp.merge = phi i32 [ %tmp.final_reload, %polly.exiting ], [ %tmp, %do.cond ]
+; CHECK:   br label %do.end
+;
+; CHECK: do.end:
+; CHECK:   ret i32 %tmp.merge
+;
+; CHECK: polly.loop_exit:
+; CHECK:   %tmp.final_reload = load i32, i32* %tmp.preload.s2a
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @f(i32* %A, i32* %B) {
+entry:
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %do.cond ], [ 0, %entry ]
+  %tmp = load i32, i32* %B, align 4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp1, %tmp
+  store i32 %add, i32* %arrayidx, align 4
+  br label %do.cond
+
+do.cond:                                          ; preds = %do.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 101
+  br i1 %exitcond, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  ret i32 %tmp
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_escaping_second_scop.ll b/final/test/Isl/CodeGen/invariant_load_escaping_second_scop.ll
new file mode 100644
index 0000000..4e042ec
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_escaping_second_scop.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true  -polly-process-unprofitable -S < %s | FileCheck %s
+;
+;    void fence(void);
+;
+;    void f(int *A, int *B) {
+;      int i = 0;
+;      int x = 0;
+;
+;      do {
+;        x = *B;
+; S:     A[i] += x;
+;      } while (i++ < 100);
+;
+;      fence();
+;
+;      do {
+; P:     A[i]++;
+;      } while (i++ < x / 2);
+;    }
+;
+; CHECK: polly.stmt.stmt.P:
+; CHECK:   sext i32 %tmp.merge to i64
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %B) {
+entry:
+  br label %stmt.S
+
+stmt.S:                                          ; preds = %do.cond, %entry
+  %indvars.iv2 = phi i64 [ %indvars.iv.next3, %do.cond ], [ 0, %entry ]
+  %tmp = load i32, i32* %B, align 4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv2
+  %tmp4 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp4, %tmp
+  store i32 %add, i32* %arrayidx, align 4
+  br label %do.cond
+
+do.cond:                                          ; preds = %do.body
+  %indvars.iv.next3 = add nuw nsw i64 %indvars.iv2, 1
+  %exitcond = icmp ne i64 %indvars.iv.next3, 101
+  br i1 %exitcond, label %stmt.S, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  %tmp5 = trunc i64 101 to i32
+  call void @fence() #2
+  %tmp6 = sext i32 %tmp5 to i64
+  br label %stmt.P
+
+stmt.P:                                        ; preds = %do.cond.5, %do.end
+  %indvars.iv = phi i64 [ %indvars.iv.next, %do.cond.5 ], [ %tmp6, %do.end ]
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp7 = load i32, i32* %arrayidx3, align 4
+  %inc4 = add nsw i32 %tmp7, 1
+  store i32 %inc4, i32* %arrayidx3, align 4
+  br label %do.cond.5
+
+do.cond.5:                                        ; preds = %do.body.1
+  %div = sdiv i32 %tmp, 2
+  %tmp8 = sext i32 %div to i64
+  %cmp7 = icmp slt i64 %indvars.iv, %tmp8
+  %indvars.iv.next = add i64 %indvars.iv, 1
+  br i1 %cmp7, label %stmt.P, label %do.end.8
+
+do.end.8:                                         ; preds = %do.cond.5
+  ret void
+}
+
+declare void @fence()
diff --git a/final/test/Isl/CodeGen/invariant_load_hoist_alignment.ll b/final/test/Isl/CodeGen/invariant_load_hoist_alignment.ll
new file mode 100644
index 0000000..d96a9b4
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_hoist_alignment.ll
@@ -0,0 +1,31 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -polly-vectorizer=polly -S \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+@A = common global [1024 x i32] zeroinitializer, align 16
+@B = common global [1024 x i32] zeroinitializer, align 16
+
+declare i32 @foo(i32) readnone
+
+define void @force_alignment() nounwind {
+;CHECK: @force_alignment
+entry:
+  br label %body
+
+body:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar_next, %body ]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvar
+; CHECK: [[T2:%.load]] = load i32, i32* getelementptr inbounds ([1024 x i32], [1024 x i32]* @A, i32 0, i32 0), align 4
+; CHECK: %value_p.splatinsert = insertelement <4 x i32> undef, i32 [[T2]], i32 0
+  %value = load i32, i32* getelementptr inbounds ([1024 x i32], [1024 x i32]* @A, i64 0, i64 0), align 4
+  %result = tail call i32 @foo(i32 %value) nounwind
+  store i32 %result, i32* %scevgep, align 4
+  %indvar_next = add i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar_next, 4
+  br i1 %exitcond, label %return, label %body
+
+return:
+  ret void
+}
+
diff --git a/final/test/Isl/CodeGen/invariant_load_in_non_affine_subregion.ll b/final/test/Isl/CodeGen/invariant_load_in_non_affine_subregion.ll
new file mode 100644
index 0000000..241252b
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_in_non_affine_subregion.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s
+;
+; This crashed at some point as the invariant load is in a non-affine
+; subregion. Just check it does not anymore.
+;
+; CHECK: polly.start
+;
+; ModuleID = 'bugpoint-reduced-simplified.bc'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.d = type { i32, i32, i32, i32, float, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }
+
+@board = external global [421 x i8], align 16
+@output_flags = external global i32, align 4
+@dragon = external global [400 x %struct.d], align 16
+
+; Function Attrs: nounwind uwtable
+define void @sgffile_add_debuginfo() #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %0 = getelementptr inbounds [24 x i8], [24 x i8]* undef, i64 0, i64 0
+  br i1 false, label %cleanup, label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %entry.split
+  br i1 false, label %if.then7, label %land.lhs.true49
+
+if.then7:                                         ; preds = %for.cond1.preheader
+  %arrayidx = getelementptr inbounds [421 x i8], [421 x i8]* @board, i64 0, i64 0
+  %crude_status = getelementptr inbounds [400 x %struct.d], [400 x %struct.d]* @dragon, i64 0, i64 0, i32 5
+  switch i32 0, label %if.end15 [
+    i32 0, label %sw.bb
+    i32 2, label %sw.bb13
+  ]
+
+sw.bb:                                            ; preds = %if.then7
+  br label %if.end15
+
+sw.bb13:                                          ; preds = %if.then7
+  br label %if.end15
+
+if.end15:                                         ; preds = %sw.bb13, %sw.bb, %if.then7
+  %cmp21 = fcmp ogt float undef, 0.000000e+00
+  br i1 %cmp21, label %land.lhs.true23, label %for.cond1.for.inc44_crit_edge
+
+land.lhs.true23:                                  ; preds = %if.end15
+  %1 = load i32, i32* @output_flags, align 4
+  %and24 = and i32 %1, 2
+  %tobool25 = icmp eq i32 %and24, 0
+  br i1 %tobool25, label %for.cond1.for.inc44_crit_edge, label %if.else
+
+if.else:                                          ; preds = %land.lhs.true23
+  br label %for.cond1.for.inc44_crit_edge
+
+for.cond1.for.inc44_crit_edge:                    ; preds = %if.else, %land.lhs.true23, %if.end15
+  br label %land.lhs.true49
+
+land.lhs.true49:                                  ; preds = %for.cond1.for.inc44_crit_edge, %for.cond1.preheader
+  %2 = load i32, i32* @output_flags, align 4
+  %and50 = and i32 %2, 2
+  %tobool51 = icmp eq i32 %and50, 0
+  br i1 %tobool51, label %cleanup, label %if.then52
+
+if.then52:                                        ; preds = %land.lhs.true49
+  br label %cleanup
+
+cleanup:                                          ; preds = %if.then52, %land.lhs.true49, %entry.split
+  call void @llvm.lifetime.end(i64 24, i8* %0)
+  ret void
+}
+
+declare void @llvm.lifetime.end(i64, i8* nocapture)
diff --git a/final/test/Isl/CodeGen/invariant_load_loop_ub.ll b/final/test/Isl/CodeGen/invariant_load_loop_ub.ll
new file mode 100644
index 0000000..0bd1927
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_loop_ub.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -polly-process-unprofitable -S < %s | FileCheck %s
+;
+; CHECK: polly.start
+;
+;    void f(int *A, int *UB) {
+;      for (int i = 0; i < *UB; i++)
+;        A[i] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %UB) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb6 ], [ 0, %bb ]
+  %tmp = load i32, i32* %UB, align 4
+  %tmp2 = sext i32 %tmp to i64
+  %tmp3 = icmp slt i64 %indvars.iv, %tmp2
+  br i1 %tmp3, label %bb4, label %bb7
+
+bb4:                                              ; preds = %bb1
+  %tmp5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 0, i32* %tmp5, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_not_executed_but_in_parameters.ll b/final/test/Isl/CodeGen/invariant_load_not_executed_but_in_parameters.ll
new file mode 100644
index 0000000..571c5fa
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_not_executed_but_in_parameters.ll
@@ -0,0 +1,115 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -analyze < %s
+;
+; Check that this does not crash as the invariant load is not executed (thus
+; not preloaded) but still referenced by one of the parameters.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.Exp.204.248.358 = type { %struct.Exp_.200.244.354*, i32, i32, i32, %struct.Exp.204.248.358*, %struct.Exp.204.248.358*, %union.anon.2.201.245.355, %union.anon.3.202.246.356, %union.anon.4.203.247.357 }
+%struct.Exp_.200.244.354 = type { i32, i32, i32, i32, %struct.Id.199.243.353* }
+%struct.Id.199.243.353 = type { i8*, i32, i32, i32, %union.anon.1.198.242.352 }
+%union.anon.1.198.242.352 = type { [2 x i64] }
+%union.anon.2.201.245.355 = type { %struct.Exp.204.248.358* }
+%union.anon.3.202.246.356 = type { i32 }
+%union.anon.4.203.247.357 = type { %struct.Exp.204.248.358** }
+%struct.Classfile.218.262.372 = type { %struct._IO_FILE.206.250.360*, %struct._IO_FILE.206.250.360*, i32, i32, i32, %struct.ClassVersion.207.251.361, %struct.ConstPool.210.254.364, %struct.AccessFlags.211.255.365, i16, i8*, i8*, i16, i8*, i16, i16*, i16, %struct.field_info.212.256.366**, i16, %struct.method_info.217.261.371**, i8*, i16, i8**, i8* }
+%struct._IO_FILE.206.250.360 = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker.205.249.359*, %struct._IO_FILE.206.250.360*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker.205.249.359 = type { %struct._IO_marker.205.249.359*, %struct._IO_FILE.206.250.360*, i32 }
+%struct.ClassVersion.207.251.361 = type { i16, i16 }
+%struct.ConstPool.210.254.364 = type { i16, %struct.cp_info.209.253.363* }
+%struct.cp_info.209.253.363 = type { i8, %union.anon.208.252.362 }
+%union.anon.208.252.362 = type { i64 }
+%struct.AccessFlags.211.255.365 = type { i16 }
+%struct.field_info.212.256.366 = type <{ %struct.AccessFlags.211.255.365, [6 x i8], i8*, i8*, i32, i16, [2 x i8] }>
+%struct.method_info.217.261.371 = type { %struct.AccessFlags.211.255.365, i8*, i8*, i8, i8, i32, i8*, i16, %struct.Block.214.258.368*, i16, %struct.LineNumberTableEntry.215.259.369*, i16, %struct.LocalVariableTableEntry.216.260.370*, i8**, i8**, i32*, i32*, i8*, i32, i32, i32* }
+%struct.Block.214.258.368 = type { i32, i16, i16, %union.anon.0.213.257.367, i16, %struct.Exp.204.248.358* }
+%union.anon.0.213.257.367 = type { i32 }
+%struct.LineNumberTableEntry.215.259.369 = type { i16, i16 }
+%struct.LocalVariableTableEntry.216.260.370 = type { i16, i16, i16, i16, i16 }
+%struct.Case.219.263.373 = type { i64, i64 }
+
+@currpc = external global i32, align 4
+@bufflength = external global i32, align 4
+@inbuff = external global i8*, align 8
+@stkptr = external global %struct.Exp.204.248.358**, align 8
+@donestkptr = external global %struct.Exp.204.248.358**, align 8
+
+; Function Attrs: uwtable
+define i32 @_Z13dotableswitchP9Classfile(%struct.Classfile.218.262.372* %c) #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %sub = add i32 0, -1
+  %tobool.5 = icmp eq i32 0, 0
+  br i1 %tobool.5, label %while.end, label %while.body.lr.ph
+
+while.body.lr.ph:                                 ; preds = %entry.split
+  br label %while.body
+
+while.body:                                       ; preds = %while.body, %while.body.lr.ph
+  %0 = load i32, i32* @currpc, align 4
+  %rem = and i32 %0, 3
+  %tobool = icmp eq i32 %rem, 0
+  br i1 %tobool, label %while.cond.while.end_crit_edge, label %while.body
+
+while.cond.while.end_crit_edge:                   ; preds = %while.body
+  br label %while.end
+
+while.end:                                        ; preds = %while.cond.while.end_crit_edge, %entry.split
+  invoke void @_ZN3ExpC2Ejj7Exptype4Type2OpPS_jjP4Case(%struct.Exp.204.248.358* nonnull undef, i32 %sub, i32 undef, i32 9, i32 0, i32 39, %struct.Exp.204.248.358* undef, i32 undef, i32 undef, %struct.Case.219.263.373* nonnull undef)
+          to label %invoke.cont unwind label %lpad
+
+invoke.cont:                                      ; preds = %while.end
+  br i1 undef, label %for.end, label %for.body.lr.ph
+
+for.body.lr.ph:                                   ; preds = %invoke.cont
+  br label %for.body
+
+for.body:                                         ; preds = %for.body, %for.body.lr.ph
+  br i1 undef, label %for.cond.for.end_crit_edge, label %for.body
+
+lpad:                                             ; preds = %while.end
+  %1 = landingpad { i8*, i32 }
+          cleanup
+  resume { i8*, i32 } undef
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %invoke.cont
+  ret i32 0
+}
+
+; Function Attrs: nounwind readnone
+declare { i64, i1 } @llvm.umul.with.overflow.i64(i64, i64) #1
+
+; Function Attrs: nobuiltin
+declare noalias i8* @_Znam(i64) #2
+
+; Function Attrs: nobuiltin
+declare noalias i8* @_Znwm(i64) #2
+
+; Function Attrs: uwtable
+declare void @_ZN3ExpC2Ejj7Exptype4Type2OpPS_jjP4Case(%struct.Exp.204.248.358*, i32, i32, i32, i32, i32, %struct.Exp.204.248.358*, i32, i32, %struct.Case.219.263.373*) unnamed_addr #0 align 2
+
+declare i32 @__gxx_personality_v0(...)
+
+; Function Attrs: nobuiltin nounwind
+declare void @_ZdlPv(i8*) #3
+
+; Function Attrs: uwtable
+declare i32 @_Z10doluswitchP9Classfile(%struct.Classfile.218.262.372*) #0
+
+; Function Attrs: nounwind uwtable
+declare void @_ZN4Exp_C2E7Exptype4Type2Op(%struct.Exp_.200.244.354*, i32, i32, i32) unnamed_addr #4 align 2
+
+attributes #0 = { uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nobuiltin "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nobuiltin nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #4 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (http://llvm.org/git/clang.git 02f36bd65b1133fbfa8bf1470105c02d9bda35e7) (http://llvm.org/git/llvm.git 01eac645064dde04ea609a8a742b1b996ef79179)"}
diff --git a/final/test/Isl/CodeGen/invariant_load_outermost.ll b/final/test/Isl/CodeGen/invariant_load_outermost.ll
new file mode 100644
index 0000000..eadd6ec
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_outermost.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s
+
+; CHECK: polly.start
+
+;    void f(int *A) {
+;      if (*A > 42)
+;        *A = *A + 1;
+;      else
+;        *A = *A - 1;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+entry:
+  br label %entry.split
+
+entry.split:
+  %tmp = load i32, i32* %A, align 4
+  %cmp = icmp sgt i32 %tmp, 42
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  %tmp1 = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp1, 1
+  br label %if.end
+
+if.else:                                          ; preds = %entry
+  %tmp2 = load i32, i32* %A, align 4
+  %sub = add nsw i32 %tmp2, -1
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  %storemerge = phi i32 [ %sub, %if.else ], [ %add, %if.then ]
+  store i32 %storemerge, i32* %A, align 4
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_parameters_cyclic_dependence.ll b/final/test/Isl/CodeGen/invariant_load_parameters_cyclic_dependence.ll
new file mode 100644
index 0000000..00f0cd5
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_parameters_cyclic_dependence.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s --check-prefix=SCOP
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s
+;
+; SCOP:         Assumed Context:
+; SCOP-NEXT:    [p_0, tmp4] -> {  :  }
+; SCOP-NEXT:    Invalid Context:
+; SCOP-NEXT:    [p_0, tmp4] -> {  : p_0 > 0 and tmp4 < 0 }
+; SCOP-NEXT:    p0: (%N * %M)
+; SCOP-NEXT:    p1: %tmp4
+;
+; CHECK:      polly.preload.merge:
+;
+;    void f(int *restrict A, int *restrict B, int N, int M) {
+;
+;      for (int i = 0; i < N * M; i++)
+;        for (int j = 0; j < A[N * M] / 2; j++)
+;          B[i + j]++;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* noalias %A, i32* noalias %B, i32 %N, i32 %M) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.8, %entry
+  %indvars.iv2 = phi i64 [ %indvars.iv.next3, %for.inc.8 ], [ 0, %entry ]
+  %mul = mul nsw i32 %N, %M
+  %tmp = sext i32 %mul to i64
+  %cmp = icmp slt i64 %indvars.iv2, %tmp
+  br i1 %cmp, label %for.body, label %for.end.10
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond.1
+
+for.cond.1:                                       ; preds = %for.inc, %for.body
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %for.body ]
+  %mul2 = mul nsw i32 %N, %M
+  %idxprom = sext i32 %mul2 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  %tmp4 = load i32, i32* %arrayidx, align 4
+  %div = udiv i32 %tmp4, 2
+  %tmp5 = sext i32 %div to i64
+  %cmp3 = icmp slt i64 %indvars.iv, %tmp5
+  br i1 %cmp3, label %for.body.4, label %for.end
+
+for.body.4:                                       ; preds = %for.cond.1
+  %tmp6 = add nsw i64 %indvars.iv2, %indvars.iv
+  %arrayidx6 = getelementptr inbounds i32, i32* %B, i64 %tmp6
+  %tmp7 = load i32, i32* %arrayidx6, align 4
+  %inc = add nsw i32 %tmp7, 1
+  store i32 %inc, i32* %arrayidx6, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body.4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond.1
+
+for.end:                                          ; preds = %for.cond.1
+  br label %for.inc.8
+
+for.inc.8:                                        ; preds = %for.end
+  %indvars.iv.next3 = add nuw nsw i64 %indvars.iv2, 1
+  br label %for.cond
+
+for.end.10:                                       ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_ptr_ptr_noalias.ll b/final/test/Isl/CodeGen/invariant_load_ptr_ptr_noalias.ll
new file mode 100644
index 0000000..5b84a91
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_ptr_ptr_noalias.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-process-unprofitable -polly-codegen -polly-invariant-load-hoisting=true -polly-ignore-aliasing -S  < %s | FileCheck %s
+;
+; CHECK-LABEL: polly.preload.begin:
+; CHECK:   %polly.access.A = getelementptr i32**, i32*** %A, i64 42
+; CHECK:   %polly.access.A.load = load i32**, i32*** %polly.access.A
+; CHECK:   %polly.access.polly.access.A.load = getelementptr i32*, i32** %polly.access.A.load, i64 32
+; CHECK:   %polly.access.polly.access.A.load.load = load i32*, i32** %polly.access.polly.access.A.load
+;
+; CHECK: polly.stmt.bb2:
+; CHECK: %scevgep = getelementptr i32, i32* %polly.access.polly.access.A.load.load, i64 %polly.indvar
+; CHECK:   store i32 0, i32* %scevgep, align 4
+;
+;    void f(int ***A) {
+;      for (int i = 0; i < 1024; i++)
+;        A[42][32][i] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32*** %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb7, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb7 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i32**, i32*** %A, i64 42
+  %tmp3 = load i32**, i32*** %tmp, align 8
+  %tmp4 = getelementptr inbounds i32*, i32** %tmp3, i64 32
+  %tmp5 = load i32*, i32** %tmp4, align 8
+  %tmp6 = getelementptr inbounds i32, i32* %tmp5, i64 %indvars.iv
+  store i32 0, i32* %tmp6, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_scalar_dep.ll b/final/test/Isl/CodeGen/invariant_load_scalar_dep.ll
new file mode 100644
index 0000000..1b1de4d
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_scalar_dep.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly  -polly-codegen -polly-invariant-load-hoisting=true -polly-ignore-aliasing -polly-process-unprofitable -S < %s | FileCheck %s
+;
+; CHECK-LABEL: polly.preload.begin:
+; CHECK:    %polly.access.B = getelementptr i32, i32* %B, i64 0
+; CHECK:    %polly.access.B.load = load i32, i32* %polly.access.B
+;
+; CHECK-LABEL: polly.stmt.bb2.split:
+; CHECK:    %scevgep = getelementptr i32, i32* %A, i64 %polly.indvar
+; CHECK:    store i32 %polly.access.B.load, i32* %scevgep, align 4
+;
+;    void f(int *restrict A, int *restrict B) {
+;      for (int i = 0; i < 1024; i++)
+;        auto tmp = *B;
+;        // Split BB
+;        A[i] = tmp;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* noalias %A, i32* noalias %B) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb4, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb4 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb5
+
+bb2:                                              ; preds = %bb1
+  %tmp = load i32, i32* %B, align 4
+  br label %bb2.split
+
+bb2.split:
+  %tmp3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp, i32* %tmp3, align 4
+  br label %bb4
+
+bb4:                                              ; preds = %bb2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb5:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_load_scalar_escape_alloca_sharing.ll b/final/test/Isl/CodeGen/invariant_load_scalar_escape_alloca_sharing.ll
new file mode 100644
index 0000000..212792a
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_load_scalar_escape_alloca_sharing.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s
+;
+; Verify the preloaded %tmp0 is stored and communicated in the same alloca.
+; In this case, we do not reload %ncol.load from the scalar stack slot, but
+; instead use directly the preloaded value stored in GlobalMap.
+;
+; CHECK-NOT: alloca
+; CHECK:     %tmp0.preload.s2a = alloca i32
+; CHECK-NOT: alloca
+;
+; CHECK:       %ncol.load = load i32, i32* @ncol
+; CHECK-NEXT:  store i32 %ncol.load, i32* %tmp0.preload.s2a
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@ncol = external global i32, align 4
+
+define void @melt_data(i32* %data1, i32* %data2) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %tmp0 = load i32, i32* @ncol, align 4
+  %tobool.2 = icmp eq i32 %tmp0, 0
+  br i1 %tobool.2, label %while.end, label %while.body.lr.ph
+
+while.body.lr.ph:                                 ; preds = %entry.split
+  br label %while.body
+
+while.body:                                       ; preds = %while.body.lr.ph, %while.cond.backedge
+  %dec3.in = phi i32 [ %tmp0, %while.body.lr.ph ], [ %dec3, %while.cond.backedge ]
+  %dec3 = add nsw i32 %dec3.in, -1
+  %idxprom = sext i32 %dec3 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %data1, i64 %idxprom
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %idxprom1 = sext i32 %dec3 to i64
+  %arrayidx2 = getelementptr inbounds i32, i32* %data2, i64 %idxprom1
+  %tmp2 = load i32, i32* %arrayidx2, align 4
+  %cmp = icmp sgt i32 %tmp1, %tmp2
+  br i1 %cmp, label %if.then, label %while.cond.backedge
+
+if.then:                                          ; preds = %while.body
+  %idxprom3 = sext i32 %dec3 to i64
+  %arrayidx4 = getelementptr inbounds i32, i32* %data2, i64 %idxprom3
+  %tmp3 = load i32, i32* %arrayidx4, align 4
+  %idxprom5 = sext i32 %dec3 to i64
+  %arrayidx6 = getelementptr inbounds i32, i32* %data1, i64 %idxprom5
+  store i32 %tmp3, i32* %arrayidx6, align 4
+  br label %while.cond.backedge
+
+while.cond.backedge:                              ; preds = %if.then, %while.body
+  %tobool = icmp eq i32 %dec3, 0
+  br i1 %tobool, label %while.cond.while.end_crit_edge, label %while.body
+
+while.cond.while.end_crit_edge:                   ; preds = %while.cond.backedge
+  br label %while.end
+
+while.end:                                        ; preds = %while.cond.while.end_crit_edge, %entry.split
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_loads_from_struct_with_different_types_1.ll b/final/test/Isl/CodeGen/invariant_loads_from_struct_with_different_types_1.ll
new file mode 100644
index 0000000..4d0639c
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_loads_from_struct_with_different_types_1.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true < %s
+;
+; Check we do not crash even though we pre-load values with different types
+; from the same base pointer.
+;
+target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"
+
+%struct.FFIIRFilterCoeffs.0.3.6.12.15.27.36.54.57.84.87.90 = type { i32, float, i32*, float* }
+
+; Function Attrs: nounwind ssp
+define void @ff_iir_filter(%struct.FFIIRFilterCoeffs.0.3.6.12.15.27.36.54.57.84.87.90* %c, i16* %dst, i32 %dstep) #0 {
+entry:
+  br i1 undef, label %if.end.325, label %for.body.38
+
+for.body.38:                                      ; preds = %for.body.38, %entry
+  %dst034.0180 = phi i16* [ undef, %for.body.38 ], [ %dst, %entry ]
+  %gain42 = getelementptr inbounds %struct.FFIIRFilterCoeffs.0.3.6.12.15.27.36.54.57.84.87.90, %struct.FFIIRFilterCoeffs.0.3.6.12.15.27.36.54.57.84.87.90* %c, i32 0, i32 1
+  %cy44 = getelementptr inbounds %struct.FFIIRFilterCoeffs.0.3.6.12.15.27.36.54.57.84.87.90, %struct.FFIIRFilterCoeffs.0.3.6.12.15.27.36.54.57.84.87.90* %c, i32 0, i32 3
+  %add.ptr88 = getelementptr inbounds i16, i16* %dst034.0180, i32 %dstep
+  store i16 undef, i16* %add.ptr88, align 2
+  %0 = load float, float* %gain42, align 4
+  %1 = load float*, float** %cy44, align 4
+  br i1 false, label %for.body.38, label %if.end.325
+
+if.end.325:                                       ; preds = %for.body.38, %entry
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_loads_from_struct_with_different_types_2.ll b/final/test/Isl/CodeGen/invariant_loads_from_struct_with_different_types_2.ll
new file mode 100644
index 0000000..6312e39
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_loads_from_struct_with_different_types_2.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true < %s
+;
+; Check we do not crash even though we pre-load values with different types
+; from the same base pointer.
+;
+target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"
+
+%struct.FFIIRFilterCoeffs.0.3.6.63.78.81.87.102.150.162.165.168.171 = type { i32, float, i32*, float* }
+
+; Function Attrs: nounwind ssp
+define void @butterworth_init_coeffs(%struct.FFIIRFilterCoeffs.0.3.6.63.78.81.87.102.150.162.165.168.171* %c) #0 {
+entry:
+  br i1 undef, label %if.end, label %if.then
+
+if.then:                                          ; preds = %entry
+  unreachable
+
+if.end:                                           ; preds = %entry
+  br i1 undef, label %if.end.2, label %if.then.1
+
+if.then.1:                                        ; preds = %if.end
+  br label %return
+
+if.end.2:                                         ; preds = %if.end
+  br i1 undef, label %for.body.35, label %for.end.126
+
+for.body.35:                                      ; preds = %if.end.2
+  unreachable
+
+for.end.126:                                      ; preds = %if.end.2
+  %gain = getelementptr inbounds %struct.FFIIRFilterCoeffs.0.3.6.63.78.81.87.102.150.162.165.168.171, %struct.FFIIRFilterCoeffs.0.3.6.63.78.81.87.102.150.162.165.168.171* %c, i32 0, i32 1
+  br i1 undef, label %for.body.133, label %for.end.169
+
+for.body.133:                                     ; preds = %for.body.133, %for.end.126
+  store float undef, float* %gain, align 4
+  %cy = getelementptr inbounds %struct.FFIIRFilterCoeffs.0.3.6.63.78.81.87.102.150.162.165.168.171, %struct.FFIIRFilterCoeffs.0.3.6.63.78.81.87.102.150.162.165.168.171* %c, i32 0, i32 3
+  %0 = load float*, float** %cy, align 4
+  br i1 false, label %for.body.133, label %for.end.169
+
+for.end.169:                                      ; preds = %for.body.133, %for.end.126
+  br label %return
+
+return:                                           ; preds = %for.end.169, %if.then.1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_loads_ignore_parameter_bounds.ll b/final/test/Isl/CodeGen/invariant_loads_ignore_parameter_bounds.ll
new file mode 100644
index 0000000..684bb14
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_loads_ignore_parameter_bounds.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting \
+; RUN:     -polly-ignore-parameter-bounds -S < %s | FileCheck %s
+
+; CHECK: polly.preload.begin:
+; CHECK-NEXT: %global.load = load i32, i32* @global, align 4, !alias.scope !0, !noalias !2
+; CHECK-NEXT: store i32 %global.load, i32* %tmp24.preload.s2a
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@global = external global i32
+
+define void @hoge() {
+bb:
+  %tmp = alloca [4 x double], align 8
+  br label %bb18
+
+bb18:                                             ; preds = %bb16
+  %tmp19 = load i32, i32* @global, align 4
+  br label %bb20
+
+bb20:                                             ; preds = %bb21, %bb18
+  %tmp22 = icmp eq i32 0, %tmp19
+  br i1 %tmp22, label %bb23, label %bb20
+
+bb23:                                             ; preds = %bb21
+  %tmp24 = load i32, i32* @global, align 4
+  %tmp25 = add i32 %tmp24, 1
+  %tmp26 = sext i32 %tmp25 to i64
+  %tmp27 = add nsw i64 %tmp26, -1
+  %tmp28 = getelementptr [4 x double], [4 x double]* %tmp, i64 0, i64 %tmp27
+  store double undef, double* %tmp28
+  br label %bb29
+
+bb29:                                             ; preds = %bb23
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/invariant_verify_function_failed.ll b/final/test/Isl/CodeGen/invariant_verify_function_failed.ll
new file mode 100644
index 0000000..df6ca8d
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_verify_function_failed.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-detect -polly-codegen -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; This crashed at some point as the pointer returned by the call
+; to @__errno_location is invariant and defined in the SCoP but not
+; loaded. Therefore it is not hoisted and consequently not available
+; at the beginning of the SCoP where we would need it if we would try
+; to hoist %tmp. We don't try to hoist %tmp anymore but this test still
+; checks that this passes to code generation and produces valid code.
+;
+; This SCoP is currently rejected because %call9 is not considered a valid
+; base pointer.
+;
+; CHECK-NOT: Valid Region for Scop
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @fileblobSetFilename() #0 {
+entry:
+  br i1 undef, label %if.end, label %cleanup
+
+if.end:                                           ; preds = %entry
+  br i1 undef, label %land.lhs.true, label %if.end.18
+
+land.lhs.true:                                    ; preds = %if.end
+  %call9 = tail call i32* @__errno_location() #2
+  %tmp = load i32, i32* %call9, align 4, !tbaa !1
+  br i1 false, label %if.then.12, label %if.end.18
+
+if.then.12:                                       ; preds = %land.lhs.true
+  br label %if.end.18
+
+if.end.18:                                        ; preds = %if.then.12, %land.lhs.true, %if.end
+  %fd.0 = phi i32 [ undef, %if.then.12 ], [ undef, %land.lhs.true ], [ undef, %if.end ]
+  br i1 undef, label %if.then.21, label %if.end.27
+
+if.then.21:                                       ; preds = %if.end.18
+  unreachable
+
+if.end.27:                                        ; preds = %if.end.18
+  br label %cleanup
+
+cleanup:                                          ; preds = %if.end.27, %entry
+  ret void
+}
+
+; Function Attrs: nounwind readnone
+declare i32* @__errno_location() #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 250010) (llvm/trunk 250018)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"int", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/Isl/CodeGen/invariant_verify_function_failed_2.ll b/final/test/Isl/CodeGen/invariant_verify_function_failed_2.ll
new file mode 100644
index 0000000..9d35253
--- /dev/null
+++ b/final/test/Isl/CodeGen/invariant_verify_function_failed_2.ll
@@ -0,0 +1,100 @@
+; RUN: opt %loadPolly -S -polly-scops -analyze \
+; RUN:   -polly-invariant-load-hoisting=true %s \
+; RUN: | FileCheck %s -check-prefix=SCOPS
+; RUN: opt %loadPolly -S -polly-codegen -polly-invariant-load-hoisting=true %s | FileCheck %s
+;
+; Check we generate valid code.
+
+; SCOPS:         Statements {
+; SCOPS-NEXT:     	Stmt_if_then2457
+; SCOPS-NEXT:             Domain :=
+; SCOPS-NEXT:                 [p_0] -> { Stmt_if_then2457[] : p_0 = 1 };
+; SCOPS-NEXT:             Schedule :=
+; SCOPS-NEXT:                 [p_0] -> { Stmt_if_then2457[] -> [1] };
+; SCOPS-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; SCOPS-NEXT:                 [p_0] -> { Stmt_if_then2457[] -> MemRef_sub2464[] };
+; SCOPS-NEXT:     	Stmt_cond_false2468
+; SCOPS-NEXT:             Domain :=
+; SCOPS-NEXT:                 [p_0] -> { Stmt_cond_false2468[] : p_0 = 1 };
+; SCOPS-NEXT:             Schedule :=
+; SCOPS-NEXT:                 [p_0] -> { Stmt_cond_false2468[] -> [2] };
+; SCOPS-NEXT:             ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; SCOPS-NEXT:                 [p_0] -> { Stmt_cond_false2468[] -> MemRef_sub2464[] };
+; SCOPS-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOPS-NEXT:                 [p_0] -> { Stmt_cond_false2468[] -> MemRef_A[0] };
+; SCOPS-NEXT:     	Stmt_if_else2493
+; SCOPS-NEXT:             Domain :=
+; SCOPS-NEXT:                 [p_0] -> { Stmt_if_else2493[] : p_0 >= 2 or p_0 = 0 };
+; SCOPS-NEXT:             Schedule :=
+; SCOPS-NEXT:                 [p_0] -> { Stmt_if_else2493[] -> [0] : p_0 >= 2 or p_0 = 0 };
+; SCOPS-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOPS-NEXT:                 [p_0] -> { Stmt_if_else2493[] -> MemRef_B[0] };
+; SCOPS-NEXT:     }
+
+; CHECK: polly.start
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.s = type { i32, i32, i32, i32, i32, i32, [6 x [33 x i64]], [6 x [33 x i64]], [6 x [33 x i64]], [6 x [33 x i64]], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i16**, i16*, i16*, i16**, i16**, i16***, i8*, i16***, i64***, i64***, i16****, i8**, i8**, %struct.s*, %struct.s*, %struct.s*, i32, i32, i32, i32, i32, i32, i32 }
+
+@enc_picture = external global %struct.s*, align 8
+
+; Function Attrs: nounwind uwtable
+define void @compute_colocated(%struct.s*** %listX, i1* %A, i32* %B) #0 {
+entry:
+  br label %for.body2414
+
+for.body2414:                                     ; preds = %for.inc2621, %entry
+  %indvars.iv902 = phi i64 [ %indvars.iv.next903, %for.inc2621 ], [ 0, %entry ]
+  br label %if.else2454
+
+if.else2454:                                      ; preds = %for.body2414
+  %cmp2455 = icmp eq i64 %indvars.iv902, 2
+  br i1 %cmp2455, label %if.then2457, label %if.else2493
+
+if.then2457:                                      ; preds = %if.else2454
+  %arrayidx2461 = getelementptr inbounds %struct.s**, %struct.s*** %listX, i64 %indvars.iv902
+  %tmp1 = load %struct.s**, %struct.s*** %arrayidx2461, align 8, !tbaa !1
+  %arrayidx2462 = getelementptr inbounds %struct.s*, %struct.s** %tmp1, i64 0
+  %tmp2 = load %struct.s*, %struct.s** %arrayidx2462, align 8, !tbaa !1
+  %poc2463 = getelementptr inbounds %struct.s, %struct.s* %tmp2, i64 0, i32 1
+  %tmp3 = load i32, i32* %poc2463, align 4, !tbaa !5
+  %sub2464 = sub nsw i32 0, %tmp3
+  br label %cond.false2468
+
+cond.false2468:                                   ; preds = %if.then2457
+  %cmp2477 = icmp sgt i32 %sub2464, 127
+  store i1 %cmp2477, i1* %A
+  br label %for.inc2621
+
+if.else2493:                                      ; preds = %if.else2454
+  %arrayidx2497 = getelementptr inbounds %struct.s**, %struct.s*** %listX, i64 %indvars.iv902
+  %tmp4 = load %struct.s**, %struct.s*** %arrayidx2497, align 8, !tbaa !1
+  %arrayidx2498 = getelementptr inbounds %struct.s*, %struct.s** %tmp4, i64 0
+  %tmp5 = load %struct.s*, %struct.s** %arrayidx2498, align 8, !tbaa !1
+  %poc2499 = getelementptr inbounds %struct.s, %struct.s* %tmp5, i64 0, i32 1
+  %tmp6 = load i32, i32* %poc2499, align 4, !tbaa !5
+  store i32 %tmp6, i32* %B
+  br label %for.inc2621
+
+for.inc2621:                                      ; preds = %if.else2493, %cond.false2468
+  %indvars.iv.next903 = add nuw nsw i64 %indvars.iv902, 2
+  br i1 undef, label %for.body2414, label %if.end2624
+
+if.end2624:                                       ; preds = %for.inc2621
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.9.0 (http://llvm.org/git/clang.git 8518d88c3151548eb6d8a7a0bb28c73f65acd897)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"any pointer", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!6, !7, i64 4}
+!6 = !{!"storable_picture", !3, i64 0, !7, i64 4, !7, i64 8, !7, i64 12, !7, i64 16, !7, i64 20, !3, i64 24, !3, i64 1608, !3, i64 3192, !3, i64 4776, !7, i64 6360, !7, i64 6364, !7, i64 6368, !7, i64 6372, !7, i64 6376, !7, i64 6380, !7, i64 6384, !7, i64 6388, !7, i64 6392, !7, i64 6396, !7, i64 6400, !7, i64 6404, !7, i64 6408, !7, i64 6412, !7, i64 6416, !2, i64 6424, !2, i64 6432, !2, i64 6440, !2, i64 6448, !2, i64 6456, !2, i64 6464, !2, i64 6472, !2, i64 6480, !2, i64 6488, !2, i64 6496, !2, i64 6504, !2, i64 6512, !2, i64 6520, !2, i64 6528, !2, i64 6536, !2, i64 6544, !7, i64 6552, !7, i64 6556, !7, i64 6560, !7, i64 6564, !7, i64 6568, !7, i64 6572, !7, i64 6576}
+!7 = !{!"int", !3, i64 0}
diff --git a/final/test/Isl/CodeGen/large-numbers-in-boundary-context.ll b/final/test/Isl/CodeGen/large-numbers-in-boundary-context.ll
new file mode 100644
index 0000000..9db7a0e
--- /dev/null
+++ b/final/test/Isl/CodeGen/large-numbers-in-boundary-context.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+; XFAIL: *
+;
+; The boundary context contains a constant that does not fit in 64 bits. Hence,
+; make sure we bail out. On certain systems, e.g. AOSP, no runtime support for
+; 128bit operations is available and consequently the code generation of large
+; values might cause linker errors.
+;
+; CHECK: br i1 false, label %polly.start, label %bb11.pre_entry_bb
+
+target triple = "x86_64-unknown-linux-gnu"
+
+@global = external global i32, align 4
+@global1 = external global i32, align 4
+
+; Function Attrs: nounwind uwtable
+define void @hoge(i8* %arg) #0 {
+bb:
+  br label %bb5
+
+bb5:                                              ; preds = %bb
+  %tmp = load i32, i32* @global, align 4
+  %tmp6 = sext i32 %tmp to i64
+  br label %bb11
+
+bb7:                                              ; preds = %bb19
+  %tmp8 = load i32, i32* @global1, align 4
+  %tmp9 = sext i32 %tmp8 to i64
+  %tmp10 = icmp slt i64 %tmp13, %tmp9
+  br i1 %tmp10, label %bb11, label %bb20
+
+bb11:                                             ; preds = %bb7, %bb5
+  %tmp12 = phi i64 [ %tmp6, %bb5 ], [ %tmp13, %bb7 ]
+  %tmp13 = add i64 %tmp12, 1
+  %tmp14 = getelementptr inbounds i8, i8* %arg, i64 %tmp13
+  %tmp15 = load i8, i8* %tmp14, align 1
+  br i1 false, label %bb16, label %bb17
+
+bb16:                                             ; preds = %bb11
+  br label %bb18
+
+bb17:                                             ; preds = %bb11
+  br label %bb18
+
+bb18:                                             ; preds = %bb17, %bb16
+  br label %bb19
+
+bb19:                                             ; preds = %bb19, %bb18
+  br i1 undef, label %bb19, label %bb7
+
+bb20:                                             ; preds = %bb7
+  br label %bb21
+
+bb21:                                             ; preds = %bb20
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/loop-invariant-load-type-mismatch.ll b/final/test/Isl/CodeGen/loop-invariant-load-type-mismatch.ll
new file mode 100644
index 0000000..74f3f48
--- /dev/null
+++ b/final/test/Isl/CodeGen/loop-invariant-load-type-mismatch.ll
@@ -0,0 +1,129 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Just make sure this test passes correctly.
+
+define void @kernel_ludcmp(double* %b, double* %y) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.cond.30.for.cond.loopexit_crit_edge:          ; preds = %for.end.54
+  br label %for.cond.loopexit
+
+for.cond.loopexit:                                ; preds = %for.cond.30.preheader, %for.cond.30.for.cond.loopexit_crit_edge
+  %indvars.iv.next131 = add nuw nsw i32 %indvars.iv130, 1
+  br i1 false, label %for.body, label %for.end.65
+
+for.body:                                         ; preds = %for.cond.loopexit, %entry.split
+  %indvars.iv130 = phi i32 [ 1, %entry.split ], [ %indvars.iv.next131, %for.cond.loopexit ]
+  br i1 true, label %for.body.3.lr.ph, label %for.cond.30.preheader
+
+for.body.3.lr.ph:                                 ; preds = %for.body
+  br label %for.body.3
+
+for.cond.1.for.cond.30.preheader_crit_edge:       ; preds = %for.end
+  br label %for.cond.30.preheader
+
+for.cond.30.preheader:                            ; preds = %for.cond.1.for.cond.30.preheader_crit_edge, %for.body
+  br i1 true, label %for.body.32.lr.ph, label %for.cond.loopexit
+
+for.body.32.lr.ph:                                ; preds = %for.cond.30.preheader
+  br label %for.body.32
+
+for.body.3:                                       ; preds = %for.end, %for.body.3.lr.ph
+  br i1 false, label %for.body.9.lr.ph, label %for.end
+
+for.body.9.lr.ph:                                 ; preds = %for.body.3
+  br label %for.body.9
+
+for.body.9:                                       ; preds = %for.body.9, %for.body.9.lr.ph
+  br i1 false, label %for.body.9, label %for.cond.7.for.end_crit_edge
+
+for.cond.7.for.end_crit_edge:                     ; preds = %for.body.9
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.7.for.end_crit_edge, %for.body.3
+  br i1 false, label %for.body.3, label %for.cond.1.for.cond.30.preheader_crit_edge
+
+for.body.32:                                      ; preds = %for.end.54, %for.body.32.lr.ph
+  %indvars.iv136 = phi i64 [ 0, %for.body.32.lr.ph ], [ %indvars.iv.next137, %for.end.54 ]
+  br i1 false, label %for.end.54, label %for.body.40.lr.ph
+
+for.body.40.lr.ph:                                ; preds = %for.body.32
+  br label %for.body.40
+
+for.body.40:                                      ; preds = %for.body.40, %for.body.40.lr.ph
+  %indvars.iv.next129 = add nuw nsw i64 0, 1
+  %lftr.wideiv132 = trunc i64 %indvars.iv.next129 to i32
+  br i1 false, label %for.body.40, label %for.cond.38.for.end.54_crit_edge
+
+for.cond.38.for.end.54_crit_edge:                 ; preds = %for.body.40
+  br label %for.end.54
+
+for.end.54:                                       ; preds = %for.cond.38.for.end.54_crit_edge, %for.body.32
+  %indvars.iv.next137 = add nuw nsw i64 %indvars.iv136, 1
+  %lftr.wideiv138 = trunc i64 %indvars.iv.next137 to i32
+  br i1 false, label %for.body.32, label %for.cond.30.for.cond.loopexit_crit_edge
+
+for.end.65:                                       ; preds = %for.cond.loopexit
+  %tmp1 = bitcast double* %b to i64*
+  %tmp2 = load i64, i64* %tmp1, align 8, !tbaa !1
+  %tmp3 = bitcast double* %y to i64*
+  store i64 %tmp2, i64* %tmp3, align 8, !tbaa !1
+  br label %for.body.70
+
+for.body.70:                                      ; preds = %for.end.86, %for.end.65
+  %arrayidx72 = getelementptr inbounds double, double* %b, i64 0
+  %tmp4 = load double, double* %arrayidx72, align 8, !tbaa !1
+  br i1 true, label %for.body.75.lr.ph, label %for.end.86
+
+for.body.75.lr.ph:                                ; preds = %for.body.70
+  br label %for.body.75
+
+for.body.75:                                      ; preds = %for.body.75, %for.body.75.lr.ph
+  %w.284 = phi double [ %tmp4, %for.body.75.lr.ph ], [ %sub83, %for.body.75 ]
+  %sub83 = fsub double %w.284, undef
+  br i1 false, label %for.body.75, label %for.cond.73.for.end.86_crit_edge
+
+for.cond.73.for.end.86_crit_edge:                 ; preds = %for.body.75
+  br label %for.end.86
+
+for.end.86:                                       ; preds = %for.cond.73.for.end.86_crit_edge, %for.body.70
+  br i1 false, label %for.body.70, label %for.end.91
+
+for.end.91:                                       ; preds = %for.end.86
+  br label %for.body.99
+
+for.body.99:                                      ; preds = %for.end.118, %for.end.91
+  br i1 true, label %for.body.106.lr.ph, label %for.end.118
+
+for.body.106.lr.ph:                               ; preds = %for.body.99
+  br label %for.body.106
+
+for.body.106:                                     ; preds = %for.body.106, %for.body.106.lr.ph
+  br i1 undef, label %for.body.106, label %for.cond.104.for.end.118_crit_edge
+
+for.cond.104.for.end.118_crit_edge:               ; preds = %for.body.106
+  br label %for.end.118
+
+for.end.118:                                      ; preds = %for.cond.104.for.end.118_crit_edge, %for.body.99
+  br i1 undef, label %for.body.99, label %for.end.131
+
+for.end.131:                                      ; preds = %for.end.118
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 250010) (llvm/trunk 250018)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"double", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/Isl/CodeGen/loop_with_condition.ll b/final/test/Isl/CodeGen/loop_with_condition.ll
new file mode 100644
index 0000000..a5a53ea
--- /dev/null
+++ b/final/test/Isl/CodeGen/loop_with_condition.ll
@@ -0,0 +1,174 @@
+; RUN: opt %loadPolly -basicaa -polly-ast -analyze < %s | FileCheck %s
+
+;#include <string.h>
+;#define N 1024
+;int A[N];
+;int B[N];
+;
+;void loop_with_condition() {
+;  int i;
+;
+;  __sync_synchronize();
+;  for (i = 0; i < N; i++) {
+;    if (i <= N / 2)
+;      A[i] = 1;
+;    else
+;      A[i] = 2;
+;    B[i] = 3;
+;  }
+;  __sync_synchronize();
+;}
+;
+;int main () {
+;  int i;
+;
+;  memset(A, 0, sizeof(int) * N);
+;  memset(B, 0, sizeof(int) * N);
+;
+;  loop_with_condition();
+;
+;  for (i = 0; i < N; i++)
+;    if (B[i] != 3)
+;      return 1;
+;
+;  for (i = 0; i < N; i++)
+;    if (i <= N / 2 && A[i] != 1)
+;      return 1;
+;    else if (i > N / 2 && A[i] != 2)
+;      return 1;
+;  return 0;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x i32] zeroinitializer, align 16 ; <[1024 x i32]*> [#uses=4]
+@B = common global [1024 x i32] zeroinitializer, align 16 ; <[1024 x i32]*> [#uses=4]
+
+define void @loop_with_condition() nounwind {
+bb0:
+  fence seq_cst
+  br label %bb1
+
+bb1:
+  %indvar = phi i64 [ %indvar.next, %bb7 ], [ 0, %bb0 ] ; <i64> [#uses=5]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvar ; <i32*> [#uses=2]
+  %scevgep1 = getelementptr [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvar ; <i32*> [#uses=1]
+  %i.0 = trunc i64 %indvar to i32                 ; <i32> [#uses=1]
+  %exitcond = icmp ne i64 %indvar, 1024           ; <i1> [#uses=1]
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:
+  %var3 = icmp sle i32 %i.0, 512                     ; <i1> [#uses=1]
+  br i1 %var3, label %bb4, label %bb5
+
+bb4:
+  store i32 1, i32* %scevgep
+  br label %bb6
+
+bb5:
+  store i32 2, i32* %scevgep
+  br label %bb6
+
+bb6:
+  store i32 3, i32* %scevgep1
+  br label %bb7
+
+bb7:
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %bb1
+
+bb8:
+  fence seq_cst
+  ret void
+}
+
+define i32 @main() nounwind {
+; <label>:0
+  call void @llvm.memset.p0i8.i64(i8* bitcast ([1024 x i32]* @A to i8*), i8 0, i64 4096, i32 1, i1 false)
+  call void @llvm.memset.p0i8.i64(i8* bitcast ([1024 x i32]* @B to i8*), i8 0, i64 4096, i32 1, i1 false)
+  call void @loop_with_condition()
+  br label %1
+
+; <label>:1                                       ; preds = %8, %0
+  %indvar1 = phi i64 [ %indvar.next2, %8 ], [ 0, %0 ] ; <i64> [#uses=3]
+  %scevgep3 = getelementptr [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvar1 ; <i32*> [#uses=1]
+  %i.0 = trunc i64 %indvar1 to i32                ; <i32> [#uses=1]
+  %2 = icmp slt i32 %i.0, 1024                    ; <i1> [#uses=1]
+  br i1 %2, label %3, label %9
+
+; <label>:3                                       ; preds = %1
+  %4 = load i32, i32* %scevgep3                        ; <i32> [#uses=1]
+  %5 = icmp ne i32 %4, 3                          ; <i1> [#uses=1]
+  br i1 %5, label %6, label %7
+
+; <label>:6                                       ; preds = %3
+  br label %28
+
+; <label>:7                                       ; preds = %3
+  br label %8
+
+; <label>:8                                       ; preds = %7
+  %indvar.next2 = add i64 %indvar1, 1             ; <i64> [#uses=1]
+  br label %1
+
+; <label>:9                                       ; preds = %1
+  br label %10
+
+; <label>:10                                      ; preds = %26, %9
+  %indvar = phi i64 [ %indvar.next, %26 ], [ 0, %9 ] ; <i64> [#uses=3]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvar ; <i32*> [#uses=2]
+  %i.1 = trunc i64 %indvar to i32                 ; <i32> [#uses=3]
+  %11 = icmp slt i32 %i.1, 1024                   ; <i1> [#uses=1]
+  br i1 %11, label %12, label %27
+
+; <label>:12                                      ; preds = %10
+  %13 = icmp sle i32 %i.1, 512                    ; <i1> [#uses=1]
+  br i1 %13, label %14, label %18
+
+; <label>:14                                      ; preds = %12
+  %15 = load i32, i32* %scevgep                        ; <i32> [#uses=1]
+  %16 = icmp ne i32 %15, 1                        ; <i1> [#uses=1]
+  br i1 %16, label %17, label %18
+
+; <label>:17                                      ; preds = %14
+  br label %28
+
+; <label>:18                                      ; preds = %14, %12
+  %19 = icmp sgt i32 %i.1, 512                    ; <i1> [#uses=1]
+  br i1 %19, label %20, label %24
+
+; <label>:20                                      ; preds = %18
+  %21 = load i32, i32* %scevgep                        ; <i32> [#uses=1]
+  %22 = icmp ne i32 %21, 2                        ; <i1> [#uses=1]
+  br i1 %22, label %23, label %24
+
+; <label>:23                                      ; preds = %20
+  br label %28
+
+; <label>:24                                      ; preds = %20, %18
+  br label %25
+
+; <label>:25                                      ; preds = %24
+  br label %26
+
+; <label>:26                                      ; preds = %25
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %10
+
+; <label>:27                                      ; preds = %10
+  br label %28
+
+; <label>:28                                      ; preds = %27, %23, %17, %6
+  %.0 = phi i32 [ 1, %6 ], [ 1, %17 ], [ 1, %23 ], [ 0, %27 ] ; <i32> [#uses=1]
+  ret i32 %.0
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
+
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1) {
+; CHECK:   if (c0 >= 513) {
+; CHECK:     Stmt_bb5(c0);
+; CHECK:   } else
+; CHECK:     Stmt_bb4(c0);
+; CHECK:   Stmt_bb6(c0)
+; CHECK: }
diff --git a/final/test/Isl/CodeGen/loop_with_condition_2.ll b/final/test/Isl/CodeGen/loop_with_condition_2.ll
new file mode 100644
index 0000000..9398e1d
--- /dev/null
+++ b/final/test/Isl/CodeGen/loop_with_condition_2.ll
@@ -0,0 +1,140 @@
+; RUN: opt %loadPolly -basicaa -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+
+; Verify that we actually detect this loop as the innermost loop even though
+; there is a conditional inside.
+
+; CHECK: #pragma simd
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1) {
+; CHECK:   if (c0 >= m + 1025) {
+; CHECK:     Stmt_if_else(c0);
+; CHECK:   } else
+; CHECK:     Stmt_if_then(c0);
+; CHECK:   Stmt_if_end(c0);
+; CHECK: }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x i32] zeroinitializer, align 16
+@B = common global [1024 x i32] zeroinitializer, align 16
+
+define void @loop_with_condition(i32 %m) nounwind {
+entry:
+  fence seq_cst
+  %tmp = sub i32 0, %m
+  %tmp1 = zext i32 %tmp to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %entry ]
+  %arrayidx = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvar
+  %arrayidx10 = getelementptr [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvar
+  %tmp2 = add i64 %tmp1, %indvar
+  %sub = trunc i64 %tmp2 to i32
+  %exitcond = icmp ne i64 %indvar, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %cmp3 = icmp sle i32 %sub, 1024
+  br i1 %cmp3, label %if.then, label %if.else
+
+if.then:                                          ; preds = %for.body
+  store i32 1, i32* %arrayidx
+  br label %if.end
+
+if.else:                                          ; preds = %for.body
+  store i32 2, i32* %arrayidx
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  store i32 3, i32* %arrayidx10
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  fence seq_cst
+  ret void
+}
+
+define i32 @main() nounwind {
+entry:
+  call void @llvm.memset.p0i8.i64(i8* bitcast ([1024 x i32]* @A to i8*), i8 0, i64 4096, i32 1, i1 false)
+  call void @llvm.memset.p0i8.i64(i8* bitcast ([1024 x i32]* @B to i8*), i8 0, i64 4096, i32 1, i1 false)
+  call void @loop_with_condition(i32 5)
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvar1 = phi i64 [ %indvar.next2, %for.inc ], [ 0, %entry ]
+  %arrayidx = getelementptr [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvar1
+  %i.0 = trunc i64 %indvar1 to i32
+  %cmp = icmp slt i32 %i.0, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp3 = load i32, i32* %arrayidx
+  %cmp4 = icmp ne i32 %tmp3, 3
+  br i1 %cmp4, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  br label %return
+
+if.end:                                           ; preds = %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvar.next2 = add i64 %indvar1, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond6
+
+for.cond6:                                        ; preds = %for.inc12, %for.end
+  %indvar = phi i64 [ %indvar.next, %for.inc12 ], [ 0, %for.end ]
+  %arrayidx15 = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvar
+  %i.1 = trunc i64 %indvar to i32
+  %cmp8 = icmp slt i32 %i.1, 1024
+  br i1 %cmp8, label %for.body9, label %for.end35
+
+for.body9:                                        ; preds = %for.cond6
+  br i1 true, label %land.lhs.true, label %if.else
+
+land.lhs.true:                                    ; preds = %for.body9
+  %tmp16 = load i32, i32* %arrayidx15
+  %cmp17 = icmp ne i32 %tmp16, 1
+  br i1 %cmp17, label %if.then18, label %if.else
+
+if.then18:                                        ; preds = %land.lhs.true
+  br label %return
+
+if.else:                                          ; preds = %land.lhs.true, %for.body9
+  br i1 false, label %land.lhs.true23, label %if.end30
+
+land.lhs.true23:                                  ; preds = %if.else
+  %tmp27 = load i32, i32* %arrayidx15
+  %cmp28 = icmp ne i32 %tmp27, 2
+  br i1 %cmp28, label %if.then29, label %if.end30
+
+if.then29:                                        ; preds = %land.lhs.true23
+  br label %return
+
+if.end30:                                         ; preds = %land.lhs.true23, %if.else
+  br label %if.end31
+
+if.end31:                                         ; preds = %if.end30
+  br label %for.inc12
+
+for.inc12:                                        ; preds = %if.end31
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond6
+
+for.end35:                                        ; preds = %for.cond6
+  br label %return
+
+return:                                           ; preds = %for.end35, %if.then29, %if.then18, %if.then
+  %retval.0 = phi i32 [ 1, %if.then ], [ 1, %if.then18 ], [ 1, %if.then29 ], [ 0, %for.end35 ]
+  ret i32 %retval.0
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
diff --git a/final/test/Isl/CodeGen/loop_with_condition_ineq.ll b/final/test/Isl/CodeGen/loop_with_condition_ineq.ll
new file mode 100644
index 0000000..f7f6831
--- /dev/null
+++ b/final/test/Isl/CodeGen/loop_with_condition_ineq.ll
@@ -0,0 +1,174 @@
+; RUN: opt %loadPolly -basicaa -polly-ast -analyze < %s | FileCheck %s
+
+;#include <string.h>
+;#define N 1024
+;int A[N];
+;int B[N];
+;
+;void loop_with_condition_ineq() {
+;  int i;
+;
+;  __sync_synchronize();
+;  for (i = 0; i < N; i++) {
+;    if (i != N / 2)
+;      A[i] = 1;
+;    else
+;      A[i] = 2;
+;    B[i] = 3;
+;  }
+;  __sync_synchronize();
+;}
+;
+;int main () {
+;  int i;
+;
+;  memset(A, 0, sizeof(int) * N);
+;  memset(B, 0, sizeof(int) * N);
+;
+;  loop_with_condition_ineq();
+;
+;  for (i = 0; i < N; i++)
+;    if (B[i] != 3)
+;      return 1;
+;
+;  for (i = 0; i < N; i++)
+;    if (i != N / 2 && A[i] != 1)
+;      return 1;
+;    else if (i == N && A[i] != 2)
+;      return 1;
+;  return 0;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x i32] zeroinitializer, align 16 ; <[1024 x i32]*> [#uses=4]
+@B = common global [1024 x i32] zeroinitializer, align 16 ; <[1024 x i32]*> [#uses=4]
+
+define void @loop_with_condition_ineq() nounwind {
+bb0:
+  fence seq_cst
+  br label %bb1
+
+bb1:
+  %indvar = phi i64 [ %indvar.next, %bb7 ], [ 0, %bb0 ] ; <i64> [#uses=5]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvar ; <i32*> [#uses=2]
+  %scevgep1 = getelementptr [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvar ; <i32*> [#uses=1]
+  %i.0 = trunc i64 %indvar to i32                 ; <i32> [#uses=1]
+  %exitcond = icmp ne i64 %indvar, 1024           ; <i1> [#uses=1]
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:
+  %var3 = icmp ne i32 %i.0, 512                      ; <i1> [#uses=1]
+  br i1 %var3, label %bb4, label %bb5
+
+bb4:
+  store i32 1, i32* %scevgep
+  br label %bb6
+
+bb5:
+  store i32 2, i32* %scevgep
+  br label %bb6
+
+bb6:
+  store i32 3, i32* %scevgep1
+  br label %bb7
+
+bb7:
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %bb1
+
+bb8:
+  fence seq_cst
+  ret void
+}
+
+define i32 @main() nounwind {
+; <label>:0
+  call void @llvm.memset.p0i8.i64(i8* bitcast ([1024 x i32]* @A to i8*), i8 0, i64 4096, i32 1, i1 false)
+  call void @llvm.memset.p0i8.i64(i8* bitcast ([1024 x i32]* @B to i8*), i8 0, i64 4096, i32 1, i1 false)
+  call void @loop_with_condition_ineq()
+  br label %1
+
+; <label>:1                                       ; preds = %8, %0
+  %indvar1 = phi i64 [ %indvar.next2, %8 ], [ 0, %0 ] ; <i64> [#uses=3]
+  %scevgep3 = getelementptr [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvar1 ; <i32*> [#uses=1]
+  %i.0 = trunc i64 %indvar1 to i32                ; <i32> [#uses=1]
+  %2 = icmp slt i32 %i.0, 1024                    ; <i1> [#uses=1]
+  br i1 %2, label %3, label %9
+
+; <label>:3                                       ; preds = %1
+  %4 = load i32, i32* %scevgep3                        ; <i32> [#uses=1]
+  %5 = icmp ne i32 %4, 3                          ; <i1> [#uses=1]
+  br i1 %5, label %6, label %7
+
+; <label>:6                                       ; preds = %3
+  br label %28
+
+; <label>:7                                       ; preds = %3
+  br label %8
+
+; <label>:8                                       ; preds = %7
+  %indvar.next2 = add i64 %indvar1, 1             ; <i64> [#uses=1]
+  br label %1
+
+; <label>:9                                       ; preds = %1
+  br label %10
+
+; <label>:10                                      ; preds = %26, %9
+  %indvar = phi i64 [ %indvar.next, %26 ], [ 0, %9 ] ; <i64> [#uses=3]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvar ; <i32*> [#uses=2]
+  %i.1 = trunc i64 %indvar to i32                 ; <i32> [#uses=3]
+  %11 = icmp slt i32 %i.1, 1024                   ; <i1> [#uses=1]
+  br i1 %11, label %12, label %27
+
+; <label>:12                                      ; preds = %10
+  %13 = icmp ne i32 %i.1, 512                     ; <i1> [#uses=1]
+  br i1 %13, label %14, label %18
+
+; <label>:14                                      ; preds = %12
+  %15 = load i32, i32* %scevgep                        ; <i32> [#uses=1]
+  %16 = icmp ne i32 %15, 1                        ; <i1> [#uses=1]
+  br i1 %16, label %17, label %18
+
+; <label>:17                                      ; preds = %14
+  br label %28
+
+; <label>:18                                      ; preds = %14, %12
+  %19 = icmp eq i32 %i.1, 1024                    ; <i1> [#uses=1]
+  br i1 %19, label %20, label %24
+
+; <label>:20                                      ; preds = %18
+  %21 = load i32, i32* %scevgep                        ; <i32> [#uses=1]
+  %22 = icmp ne i32 %21, 2                        ; <i1> [#uses=1]
+  br i1 %22, label %23, label %24
+
+; <label>:23                                      ; preds = %20
+  br label %28
+
+; <label>:24                                      ; preds = %20, %18
+  br label %25
+
+; <label>:25                                      ; preds = %24
+  br label %26
+
+; <label>:26                                      ; preds = %25
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %10
+
+; <label>:27                                      ; preds = %10
+  br label %28
+
+; <label>:28                                      ; preds = %27, %23, %17, %6
+  %.0 = phi i32 [ 1, %6 ], [ 1, %17 ], [ 1, %23 ], [ 0, %27 ] ; <i32> [#uses=1]
+  ret i32 %.0
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
+
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1) {
+; CHECK:   if (c0 == 512) {
+; CHECK:     Stmt_bb5(512);
+; CHECK:   } else
+; CHECK:     Stmt_bb4(c0);
+; CHECK:   Stmt_bb6(c0);
+; CHECK: }
diff --git a/final/test/Isl/CodeGen/loop_with_condition_nested.ll b/final/test/Isl/CodeGen/loop_with_condition_nested.ll
new file mode 100644
index 0000000..38ce558
--- /dev/null
+++ b/final/test/Isl/CodeGen/loop_with_condition_nested.ll
@@ -0,0 +1,215 @@
+; RUN: opt %loadPolly -basicaa -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -polly-codegen -loops -analyze < %s | FileCheck %s -check-prefix=LOOPS
+
+
+;#include <string.h>
+;#define N 1024
+;int A[N];
+;int B[N];
+;
+;void loop_with_condition() {
+;  int i;
+;
+;  __sync_synchronize();
+;  for (i = 0; i < N; i++) {
+;    if (i <= N / 2) {
+;      if (i > 20)
+;        A[i] = 1;
+;      else
+;        A[i] = 2;
+;    }
+;    B[i] = 3;
+;  }
+;  __sync_synchronize();
+;}
+;
+;int main () {
+;  int i;
+;
+;  memset(A, 0, sizeof(int) * N);
+;  memset(B, 0, sizeof(int) * N);
+;
+;  loop_with_condition();
+;
+;  for (i = 0; i < N; i++)
+;    if (B[i] != 3)
+;      return 1;
+;
+;  for (i = 0; i < N; i++)
+;    if (i <= N / 2  && i > 20 && A[i] != 1)
+;      return 1;
+;    else if (i > N / 2) {
+;      if (i <= 20 && A[i] != 2)
+;        return 1;
+;      if (i > 20 && A[i] != 0)
+;        return 1;
+;    }
+;  return 0;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x i32] zeroinitializer, align 16 ; <[1024 x i32]*> [#uses=4]
+@B = common global [1024 x i32] zeroinitializer, align 16 ; <[1024 x i32]*> [#uses=4]
+
+define void @loop_with_condition() nounwind {
+bb0:
+  fence seq_cst
+  br label %bb1
+
+bb1:
+  %indvar = phi i64 [ %indvar.next, %bb10 ], [ 0, %bb0 ] ; <i64> [#uses=5]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvar ; <i32*> [#uses=2]
+  %scevgep1 = getelementptr [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvar ; <i32*> [#uses=1]
+  %i.0 = trunc i64 %indvar to i32                 ; <i32> [#uses=2]
+  %exitcond = icmp ne i64 %indvar, 1024           ; <i1> [#uses=1]
+  br i1 %exitcond, label %bb2, label %bb11
+
+bb2:
+  %var3 = icmp sle i32 %i.0, 512                     ; <i1> [#uses=1]
+  br i1 %var3, label %bb4, label %bb9
+
+bb4:
+  %var5 = icmp sgt i32 %i.0, 20                      ; <i1> [#uses=1]
+  br i1 %var5, label %bb6, label %bb7
+
+bb6:
+  store i32 1, i32* %scevgep
+  br label %bb8
+
+bb7:
+  store i32 2, i32* %scevgep
+  br label %bb8
+
+bb8:
+  br label %bb9
+
+bb9:
+  store i32 3, i32* %scevgep1
+  br label %bb10
+
+bb10:
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %bb1
+
+bb11:
+  fence seq_cst
+  ret void
+}
+
+define i32 @main() nounwind {
+; <label>:0
+  call void @llvm.memset.p0i8.i64(i8* bitcast ([1024 x i32]* @A to i8*), i8 0, i64 4096, i32 1, i1 false)
+  call void @llvm.memset.p0i8.i64(i8* bitcast ([1024 x i32]* @B to i8*), i8 0, i64 4096, i32 1, i1 false)
+  call void @loop_with_condition()
+  br label %1
+
+; <label>:1                                       ; preds = %8, %0
+  %indvar1 = phi i64 [ %indvar.next2, %8 ], [ 0, %0 ] ; <i64> [#uses=3]
+  %scevgep3 = getelementptr [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvar1 ; <i32*> [#uses=1]
+  %i.0 = trunc i64 %indvar1 to i32                ; <i32> [#uses=1]
+  %2 = icmp slt i32 %i.0, 1024                    ; <i1> [#uses=1]
+  br i1 %2, label %3, label %9
+
+; <label>:3                                       ; preds = %1
+  %4 = load i32, i32* %scevgep3                        ; <i32> [#uses=1]
+  %5 = icmp ne i32 %4, 3                          ; <i1> [#uses=1]
+  br i1 %5, label %6, label %7
+
+; <label>:6                                       ; preds = %3
+  br label %39
+
+; <label>:7                                       ; preds = %3
+  br label %8
+
+; <label>:8                                       ; preds = %7
+  %indvar.next2 = add i64 %indvar1, 1             ; <i64> [#uses=1]
+  br label %1
+
+; <label>:9                                       ; preds = %1
+  br label %10
+
+; <label>:10                                      ; preds = %37, %9
+  %indvar = phi i64 [ %indvar.next, %37 ], [ 0, %9 ] ; <i64> [#uses=3]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvar ; <i32*> [#uses=3]
+  %i.1 = trunc i64 %indvar to i32                 ; <i32> [#uses=6]
+  %11 = icmp slt i32 %i.1, 1024                   ; <i1> [#uses=1]
+  br i1 %11, label %12, label %38
+
+; <label>:12                                      ; preds = %10
+  %13 = icmp sle i32 %i.1, 512                    ; <i1> [#uses=1]
+  br i1 %13, label %14, label %20
+
+; <label>:14                                      ; preds = %12
+  %15 = icmp sgt i32 %i.1, 20                     ; <i1> [#uses=1]
+  br i1 %15, label %16, label %20
+
+; <label>:16                                      ; preds = %14
+  %17 = load i32, i32* %scevgep                        ; <i32> [#uses=1]
+  %18 = icmp ne i32 %17, 1                        ; <i1> [#uses=1]
+  br i1 %18, label %19, label %20
+
+; <label>:19                                      ; preds = %16
+  br label %39
+
+; <label>:20                                      ; preds = %16, %14, %12
+  %21 = icmp sgt i32 %i.1, 512                    ; <i1> [#uses=1]
+  br i1 %21, label %22, label %35
+
+; <label>:22                                      ; preds = %20
+  %23 = icmp sle i32 %i.1, 20                     ; <i1> [#uses=1]
+  br i1 %23, label %24, label %28
+
+; <label>:24                                      ; preds = %22
+  %25 = load i32, i32* %scevgep                        ; <i32> [#uses=1]
+  %26 = icmp ne i32 %25, 2                        ; <i1> [#uses=1]
+  br i1 %26, label %27, label %28
+
+; <label>:27                                      ; preds = %24
+  br label %39
+
+; <label>:28                                      ; preds = %24, %22
+  %29 = icmp sgt i32 %i.1, 20                     ; <i1> [#uses=1]
+  br i1 %29, label %30, label %34
+
+; <label>:30                                      ; preds = %28
+  %31 = load i32, i32* %scevgep                        ; <i32> [#uses=1]
+  %32 = icmp ne i32 %31, 0                        ; <i1> [#uses=1]
+  br i1 %32, label %33, label %34
+
+; <label>:33                                      ; preds = %30
+  br label %39
+
+; <label>:34                                      ; preds = %30, %28
+  br label %35
+
+; <label>:35                                      ; preds = %34, %20
+  br label %36
+
+; <label>:36                                      ; preds = %35
+  br label %37
+
+; <label>:37                                      ; preds = %36
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %10
+
+; <label>:38                                      ; preds = %10
+  br label %39
+
+; <label>:39                                      ; preds = %38, %33, %27, %19, %6
+  %.0 = phi i32 [ 1, %6 ], [ 1, %19 ], [ 1, %27 ], [ 1, %33 ], [ 0, %38 ] ; <i32> [#uses=1]
+  ret i32 %.0
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
+
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1) {
+; CHECK:   if (c0 <= 20) {
+; CHECK:     Stmt_bb7(c0);
+; CHECK:   } else if (c0 <= 512)
+; CHECK:     Stmt_bb6(c0);
+; CHECK:   Stmt_bb9(c0);
+; CHECK: }
+
+; LOOPS-DAG: Loop at depth 1 containing: %bb1<header><exiting>,%bb2,%bb4,%bb7,%bb6,%bb8,%bb9,%bb10<latch>
+; LOOPS-DAG: Loop at depth 1 containing: %polly.loop_header<header>,%polly.cond,%polly.merge,%polly.then,%polly.else,%polly.stmt.bb7,%polly.cond3,%polly.merge4,%polly.then5,%polly.else6,%polly.stmt.bb6,%polly.stmt.bb9<latch><exiting>
diff --git a/final/test/Isl/CodeGen/loop_with_conditional_entry_edge_split_hard_case.ll b/final/test/Isl/CodeGen/loop_with_conditional_entry_edge_split_hard_case.ll
new file mode 100644
index 0000000..a0679c2
--- /dev/null
+++ b/final/test/Isl/CodeGen/loop_with_conditional_entry_edge_split_hard_case.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; Test case to trigger the hard way of creating a unique entering
+; edge for the SCoP. It is triggered because the entering edge
+; here: %while.begin --> %if is __not__ critical.
+;
+;    int f(void);
+;    void jd(int b, int *A) {
+;      while (f()) {
+;        if (b)
+;          for (int i = 0; i < 1024; i++)
+;            A[i] = i;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32 %b, i32* %A) {
+entry:
+  br label %while.begin
+
+; CHECK-LABEL: while.begin.region_exiting:
+; CHECK:         br label %polly.merge_new_and_old
+
+; CHECK-LABEL: while.begin:
+while.begin:
+; CHECK:  %call = call i32 @f()
+  %call = call i32 @f()
+; CHECK:  %tobool = icmp eq i32 %call, 0
+  %tobool = icmp eq i32 %call, 0
+; CHECK:  br i1 %tobool, label %while.end, label %polly.split_new_and_old
+  br i1 %tobool, label %while.end, label %if
+
+; CHECK: polly.split_new_and_old:
+; CHECK:   br i1 true, label %polly.start, label %if
+
+; CHECK: if:
+if:                                               ; preds = %while.begin
+; CHECK: %tobool2 = icmp eq i32 %b, 0
+  %tobool2 = icmp eq i32 %b, 0
+; CHECK: br i1 %tobool2, label %while.begin{{[a-zA-Z._]*}}, label %for.cond
+  br i1 %tobool2, label %while.begin, label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %if
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %if ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %while.begin
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = trunc i64 %indvars.iv to i32
+  store i32 %tmp, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+while.end:                                        ; preds = %entry, %for.cond
+  ret void
+}
+
+declare i32 @f()
diff --git a/final/test/Isl/CodeGen/memcpy_annotations.ll b/final/test/Isl/CodeGen/memcpy_annotations.ll
new file mode 100644
index 0000000..6507ecb
--- /dev/null
+++ b/final/test/Isl/CodeGen/memcpy_annotations.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; Verify that @llvm.memcpy does not get a !alias.scope annotation.
+; @llvm.memcpy takes two pointers, it is ambiguous to which the
+; annotation applies.
+;
+; for (int j = 0; j < n; j += 1) {
+;   memcpy(A, B, 8);
+; }
+;
+
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1)
+
+define void @func(i32 %n, i8* noalias nonnull %A, i8* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull %A, i8* %B, i64 8, i32 4, i1 false)
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK-LABEL: polly.start:
+; CHECK:         call void @llvm.memcpy
+; CHECK-NOT:     !alias.scope
diff --git a/final/test/Isl/CodeGen/multidim-non-matching-typesize-2.ll b/final/test/Isl/CodeGen/multidim-non-matching-typesize-2.ll
new file mode 100644
index 0000000..3206d92
--- /dev/null
+++ b/final/test/Isl/CodeGen/multidim-non-matching-typesize-2.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -disable-basicaa -polly-codegen \
+; RUN:     -S < %s | FileCheck %s
+; CHECK: polly
+target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"
+
+define void @hoge(i16* %arg, i32 %arg1, i16* %arg2) {
+bb:
+  %tmp = alloca i32
+  %tmp3 = load i32, i32* undef
+  br label %bb7
+
+bb7:
+  %tmp8 = phi i32 [ %tmp3, %bb ], [ %tmp13, %bb7 ]
+  %tmp9 = getelementptr inbounds i16, i16* %arg2, i32 0
+  %tmp10 = load i16, i16* %tmp9, align 2
+  %tmp11 = mul nsw i32 %tmp8, %arg1
+  %tmp12 = getelementptr inbounds i16, i16* %arg, i32 %tmp11
+  store i16 undef, i16* %tmp12, align 2
+  %tmp13 = add nsw i32 %tmp8, 1
+  store i32 undef, i32* %tmp
+  br i1 false, label %bb7, label %bb5
+
+bb5:
+  ret void
+
+}
diff --git a/final/test/Isl/CodeGen/multidim-non-matching-typesize.ll b/final/test/Isl/CodeGen/multidim-non-matching-typesize.ll
new file mode 100644
index 0000000..86661ec
--- /dev/null
+++ b/final/test/Isl/CodeGen/multidim-non-matching-typesize.ll
@@ -0,0 +1,24 @@
+; RUN: opt %loadPolly -disable-basicaa -polly-codegen \
+; RUN:     -S < %s | FileCheck %s
+
+target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"
+
+; CHECK: polly
+
+define void @hoge(i16* %arg, i32 %arg1) {
+bb:
+  %tmp = alloca i16
+  br label %bb2
+
+bb2:
+  %tmp3 = phi i32 [ %tmp7, %bb2 ], [ 0, %bb ]
+  %tmp4 = mul nsw i32 %tmp3, %arg1
+  %tmp5 = getelementptr inbounds i16, i16* %arg, i32 %tmp4
+  %tmp6 = load i16, i16* %tmp5, align 2
+  store i16 %tmp6, i16* %tmp
+  %tmp7 = add nsw i32 %tmp3, 1
+  br i1 false, label %bb2, label %bb8
+
+bb8:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/multidim_2d_parametric_array_static_loop_bounds.ll b/final/test/Isl/CodeGen/multidim_2d_parametric_array_static_loop_bounds.ll
new file mode 100644
index 0000000..43b08cd
--- /dev/null
+++ b/final/test/Isl/CodeGen/multidim_2d_parametric_array_static_loop_bounds.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; Derived from the following code:
+;
+; void foo(long n, long m, double A[n][m]) {
+;   for (long i = 0; i < 100; i++)
+;     for (long j = 0; j < 150; j++)
+;       A[i][j] = 1.0;
+; }
+;
+; CHECK: entry:
+; CHECK: polly.split_new_and_old:
+; CHECK: %0 = icmp sge i64 %m, 150
+; CHECK: br i1 %0, label %polly.start, label %for.i
+
+define void @foo(i64 %n, i64 %m, double* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+  %tmp = mul nsw i64 %i, %m
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j ]
+  %vlaarrayidx.sum = add i64 %j, %tmp
+  %arrayidx = getelementptr inbounds double, double* %A, i64 %vlaarrayidx.sum
+  store double 1.0, double* %arrayidx
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, 150
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %i.exitcond = icmp eq i64 %i.inc, 100
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/multidim_alias_check.ll b/final/test/Isl/CodeGen/multidim_alias_check.ll
new file mode 100644
index 0000000..063aa19
--- /dev/null
+++ b/final/test/Isl/CodeGen/multidim_alias_check.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-codegen < %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK: %polly.access.sext.A = sext i32 %n to i64
+; CHECK: %polly.access.mul.A = mul i64 %polly.access.sext.A, %0
+; CHECK: %polly.access.add.A = add i64 %polly.access.mul.A, 1
+; CHECK: %polly.access.A = getelementptr double, double* %A, i64 %polly.access.add.A
+; CHECK: %polly.access.y = getelementptr double, double* %y, i64 0
+; CHECK: icmp ule double* %polly.access.A, %polly.access.y
+
+
+define void @init_array(i32 %n, double* %A, double* %y) {
+entry:
+  %add3 = add nsw i32 %n, 1
+  %tmp = zext i32 %add3 to i64
+  br label %for.body
+
+for.body:
+  %i.04 = phi i32 [ %inc39, %for.cond.loopexit ], [ 0, %entry ]
+  %arrayidx16 = getelementptr inbounds double, double* %y, i64 0
+  store double 1.0, double* %arrayidx16
+  %cmp251 = icmp slt i32 %n, 0
+  %inc39 = add nsw i32 %i.04, 1
+  br i1 %cmp251, label %for.cond.loopexit, label %for.body27
+
+for.body27:
+  %idxprom35 = sext i32 %i.04 to i64
+  %tmp1 = mul nsw i64 %idxprom35, %tmp
+  %arrayidx36.sum = add i64 0, %tmp1
+  %arrayidx37 = getelementptr inbounds double, double* %A, i64 %arrayidx36.sum
+  store double 1.0, double* %arrayidx37
+  br label %for.cond.loopexit
+
+for.cond.loopexit:
+  %cmp = icmp slt i32 %i.04, %n
+  br i1 %cmp, label %for.body, label %for.end40
+
+
+for.end40:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/multiple-codegens.ll b/final/test/Isl/CodeGen/multiple-codegens.ll
new file mode 100644
index 0000000..b9bfb55
--- /dev/null
+++ b/final/test/Isl/CodeGen/multiple-codegens.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-scops -polly-opt-isl -polly-codegen -polly-scops -polly-codegen -S < %s | FileCheck %s
+;
+; llvm.org/PR34441
+; Properly handle multiple -polly-scops/-polly-codegen in the same
+; RegionPassManager. -polly-codegen must not reuse the -polly-ast analysis the
+; was created for the first -polly-scops pass.
+; The current solution is that only the first -polly-codegen is allowed to
+; generate code, the second detects it is re-using an IslAst that belongs to a
+; different ScopInfo.
+;
+; int a, b, c;
+;
+; int main () {
+;  while (a++)
+;    while (b) {
+;        c = 0;
+;        break;
+;      }
+;  return 0;
+; }
+;
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+
+@a = common global i32 0, align 4
+@b = common global i32 0, align 4
+@c = common global i32 0, align 4
+
+; Function Attrs: nounwind uwtable
+define i32 @main() {
+entry:
+  %retval = alloca i32, align 4
+  store i32 0, i32* %retval, align 4
+  %.pre = load i32, i32* @a, align 4
+  br label %while.cond
+
+while.cond:                                       ; preds = %while.end, %entry
+  %0 = phi i32 [ %inc, %while.end ], [ %.pre, %entry ]
+  %inc = add nsw i32 %0, 1
+  store i32 %inc, i32* @a, align 4
+  %tobool = icmp ne i32 %0, 0
+  br i1 %tobool, label %while.body, label %while.end4
+
+while.body:                                       ; preds = %while.cond
+  %1 = load i32, i32* @b, align 4
+  %tobool2 = icmp ne i32 %1, 0
+  br i1 %tobool2, label %while.body3, label %while.end
+
+while.body3:                                      ; preds = %while.body
+  store i32 0, i32* @c, align 4
+  br label %while.end
+
+while.end:                                        ; preds = %while.body3, %while.body
+  br label %while.cond
+
+while.end4:                                       ; preds = %while.cond
+  ret i32 0
+}
+
+
+; CHECK: polly.start:
+; CHECK-NOT: polly.start:
diff --git a/final/test/Isl/CodeGen/multiple-scops-in-a-row.ll b/final/test/Isl/CodeGen/multiple-scops-in-a-row.ll
new file mode 100644
index 0000000..376044e
--- /dev/null
+++ b/final/test/Isl/CodeGen/multiple-scops-in-a-row.ll
@@ -0,0 +1,51 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+
+; This test case has two scops in a row. When code generating the first scop,
+; the second scop is invalidated. This test case verifies that we do not crash
+; due to incorrectly assuming the second scop is still valid.
+
+; We explicitly check here that the second scop is not code generated. Later
+; improvements may make this possible (e.g., Polly gaining support for
+; parameteric conditional expressions or a changed code generation order).
+; However, in case this happens, we want to ensure this test case is been
+; reasoned about and updated accordingly.
+
+; CHECK: polly.start:
+; CHECK-NOT: polly.start:
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @hoge(i8* %arg) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb
+  %tmp = getelementptr inbounds i8, i8* %arg, i64 5
+  %tmp2 = getelementptr inbounds i8, i8* %arg, i64 6
+  br i1 false, label %bb3, label %bb4
+
+bb3:                                              ; preds = %bb1
+  br label %bb4
+
+bb4:                                              ; preds = %bb3, %bb1
+  %tmp5 = icmp eq i32 0, 1
+  br label %bb6
+
+bb6:                                              ; preds = %bb4
+  br i1 undef, label %bb7, label %bb8
+
+bb7:                                              ; preds = %bb6
+  unreachable
+
+bb8:                                              ; preds = %bb6
+  br i1 %tmp5, label %bb9, label %bb10
+
+bb9:                                              ; preds = %bb8
+  br label %bb11
+
+bb10:                                             ; preds = %bb8
+  br label %bb11
+
+bb11:                                             ; preds = %bb10, %bb9
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/multiple-types-invariant-load-2.ll b/final/test/Isl/CodeGen/multiple-types-invariant-load-2.ll
new file mode 100644
index 0000000..4f3ffb5
--- /dev/null
+++ b/final/test/Isl/CodeGen/multiple-types-invariant-load-2.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-codegen -S \
+; RUN: -polly-allow-differing-element-types < %s | FileCheck %s
+
+; CHECK: polly
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @hoge(i8* %arg) #0 {
+bb:
+  br label %bb3
+
+bb3:                                              ; preds = %bb
+  %tmp = load i8, i8* %arg, align 1, !tbaa !1
+  br i1 false, label %bb7, label %bb4
+
+bb4:                                              ; preds = %bb3
+  %tmp5 = bitcast i8* %arg to i32*
+  %tmp6 = load i32, i32* %tmp5, align 4, !tbaa !4
+  br label %bb7
+
+bb7:                                              ; preds = %bb4, %bb3
+  %tmp8 = phi i8 [ 1, %bb3 ], [ undef, %bb4 ]
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.9.0 (trunk 259751) (llvm/trunk 259869)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"omnipotent char", !3, i64 0}
+!3 = !{!"Simple C/C++ TBAA"}
+!4 = !{!5, !5, i64 0}
+!5 = !{!"int", !2, i64 0}
diff --git a/final/test/Isl/CodeGen/multiple-types-invariant-load.ll b/final/test/Isl/CodeGen/multiple-types-invariant-load.ll
new file mode 100644
index 0000000..da00230
--- /dev/null
+++ b/final/test/Isl/CodeGen/multiple-types-invariant-load.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-allow-differing-element-types -polly-codegen -S \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+
+; CHECK: %polly.access.cast.global.load = bitcast %struct.hoge* %global.load to i32*
+; CHECK: %polly.access.global.load = getelementptr i32, i32* %polly.access.cast.global.load, i64 0
+; CHECK: %polly.access.global.load.load = load i32, i32* %polly.access.global.load
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.hoge = type { i32, double }
+
+@global = external global %struct.hoge*, align 8
+
+; Function Attrs: nounwind uwtable
+define void @widget(double* %A) #0 {
+bb:
+  br label %bb4
+
+bb4:
+  %tmp = load %struct.hoge*, %struct.hoge** @global
+  %tmp5 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp, i64 0, i32 0
+  %tmp6 = load i32, i32* %tmp5
+  %tmp7 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp, i64 0, i32 1
+  %tmp8 = load double, double* %tmp7
+  store double %tmp8, double* %A
+  br i1 false, label %bb11, label %bb12
+
+bb11:
+  br label %bb12
+
+bb12:
+  %tmp13 = phi float [ undef, %bb11 ], [ 1.000000e+00, %bb4 ]
+  ret void
+}
+
diff --git a/final/test/Isl/CodeGen/multiple_sai_fro_same_base_address.ll b/final/test/Isl/CodeGen/multiple_sai_fro_same_base_address.ll
new file mode 100644
index 0000000..eda2f3c
--- /dev/null
+++ b/final/test/Isl/CodeGen/multiple_sai_fro_same_base_address.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-position=before-vectorizer -polly-scops -analyze < %s | FileCheck %s --check-prefix=SCOP
+; RUN: opt %loadPolly -polly-position=before-vectorizer -polly-codegen -S < %s | FileCheck %s --check-prefix=IR
+
+; The IR has two ScopArrayInfo for the value %next.0. This used to produce two
+; phi nodes in polly.merge_new_and_old, one illegaly using the result of the
+; other. There must be only one merge phi, no need to generate them for arrays
+; of type MK_Array.
+; Derived from test-suite/MultiSource/Applications/siod/slib.c
+
+%struct.obj.2.290.322.338.354.482.546.594.626.818.898.914.962 = type { i16, i16, %union.anon.1.289.321.337.353.481.545.593.625.817.897.913.961 }
+%union.anon.1.289.321.337.353.481.545.593.625.817.897.913.961 = type { %struct.anon.0.288.320.336.352.480.544.592.624.816.896.912.960 }
+%struct.anon.0.288.320.336.352.480.544.592.624.816.896.912.960 = type { %struct.obj.2.290.322.338.354.482.546.594.626.818.898.914.962*, %struct.obj.2.290.322.338.354.482.546.594.626.818.898.914.962* }
+
+define void @leval_or() {
+entry:
+  br label %while.cond
+
+while.cond:                                       ; preds = %sw.bb1.i30, %cond.end.i28, %entry
+  %next.0 = phi %struct.obj.2.290.322.338.354.482.546.594.626.818.898.914.962* [ null, %entry ], [ %1, %sw.bb1.i30 ], [ null, %cond.end.i28 ]
+  br i1 undef, label %cond.end.i28, label %if.then
+
+if.then:                                          ; preds = %while.cond
+  ret void
+
+cond.end.i28:                                     ; preds = %while.cond
+  %type.i24 = getelementptr inbounds %struct.obj.2.290.322.338.354.482.546.594.626.818.898.914.962, %struct.obj.2.290.322.338.354.482.546.594.626.818.898.914.962* %next.0, i64 0, i32 1
+  %0 = load i16, i16* %type.i24, align 2
+  br i1 false, label %sw.bb1.i30, label %while.cond
+
+sw.bb1.i30:                                       ; preds = %cond.end.i28
+  %cdr.i29 = getelementptr inbounds %struct.obj.2.290.322.338.354.482.546.594.626.818.898.914.962, %struct.obj.2.290.322.338.354.482.546.594.626.818.898.914.962* %next.0, i64 0, i32 2, i32 0, i32 1
+  %1 = load %struct.obj.2.290.322.338.354.482.546.594.626.818.898.914.962*, %struct.obj.2.290.322.338.354.482.546.594.626.818.898.914.962** %cdr.i29, align 8
+  br label %while.cond
+}
+
+; SCOP:      Arrays {
+; SCOP-NEXT:     %struct.obj.2.290.322.338.354.482.546.594.626.818.898.914.962* MemRef_next_0;
+; SCOP-NEXT:     i16 MemRef_next_0[*];
+; SCOP-NEXT: }
+
+; IR:      polly.merge_new_and_old:
+; IR-NEXT:   %next.0.ph.merge = phi %struct.obj.2.290.322.338.354.482.546.594.626.818.898.914.962* [ %next.0.ph.final_reload, %polly.exiting ], [ %next.0.ph, %while.cond.region_exiting ]
+; IR-NEXT:   %indvar.next = add i64 %indvar, 1
+; IR-NEXT:   br label %while.cond
diff --git a/final/test/Isl/CodeGen/new_multidim_access___%bb1---%bb17.jscop b/final/test/Isl/CodeGen/new_multidim_access___%bb1---%bb17.jscop
new file mode 100644
index 0000000..5ef5c7c
--- /dev/null
+++ b/final/test/Isl/CodeGen/new_multidim_access___%bb1---%bb17.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "[n, m] -> {  : n <= 9223372036854775807 and n >= -9223372036854775808 and m <= 9223372036854775807 and m >= -9223372036854775808 }",
+   "name" : "bb1 => bb17",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n, m] -> { Stmt_bb4[i0, i1] -> MemRef_A[i0, i1 + 13] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n, m] -> { Stmt_bb4[i0, i1] -> MemRef_A[i0, i1 + 43] }"
+            }
+         ],
+         "domain" : "[n, m] -> { Stmt_bb4[i0, i1] : i0 >= 0 and n >= 1 and i0 <= -1 + n and i1 >= 0 and i1 <= 99 }",
+         "name" : "Stmt_bb4",
+         "schedule" : "[n, m] -> { Stmt_bb4[i0, i1] -> [i0, i1] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/no-overflow-tracking.ll b/final/test/Isl/CodeGen/no-overflow-tracking.ll
new file mode 100644
index 0000000..697587b
--- /dev/null
+++ b/final/test/Isl/CodeGen/no-overflow-tracking.ll
@@ -0,0 +1,75 @@
+; RUN: opt %loadPolly -analyze -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+; RUN: opt %loadPolly -S -polly-codegen -polly-overflow-tracking=never \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s --check-prefix=IR
+;
+; As (p + q) can overflow we have to check that we load from
+; I[p + q] only if it does not.
+;
+; CHECK:         Invariant Accesses: {
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [N, p, q] -> { Stmt_for_body[i0] -> MemRef_I[p + q] };
+; CHECK-NEXT:            Execution Context: [N, p, q] -> {  : N > 0 and -2147483648 - p <= q <= 2147483647 - p }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [N, p, q] -> { Stmt_for_body[i0] -> MemRef_tmp1[0] };
+; CHECK-NEXT:            Execution Context: [N, p, q] -> {  : N > 0 }
+; CHECK-NEXT:    }
+;
+; IR:      polly.preload.merge:
+; IR-NEXT:   %polly.preload.tmp1.merge = phi i32* [ %polly.access.I.load, %polly.preload.exec ], [ null, %polly.preload.cond ]
+; IR-NEXT:   store i32* %polly.preload.tmp1.merge, i32** %tmp1.preload.s2a
+; IR-NEXT:   %12 = sext i32 %N to i64
+; IR-NEXT:   %13 = icmp sge i64 %12, 1
+; IR-NEXT:   %14 = sext i32 %q to i64
+; IR-NEXT:   %15 = sext i32 %p to i64
+; IR-NEXT:   %16 = add nsw i64 %15, %14
+; IR-NEXT:   %17 = icmp sle i64 %16, 2147483647
+; IR-NEXT:   %18 = and i1 %13, %17
+; IR-NEXT:   %19 = sext i32 %q to i64
+; IR-NEXT:   %20 = sext i32 %p to i64
+; IR-NEXT:   %21 = add nsw i64 %20, %19
+; IR-NEXT:   %22 = icmp sge i64 %21, -2147483648
+; IR-NEXT:   %23 = and i1 %18, %22
+; IR-NEXT:   br label %polly.preload.cond1
+;
+; IR:      polly.preload.cond1:
+; IR-NEXT:   br i1 %23
+;
+; IR:      polly.preload.exec3:
+; IR-NEXT:   %polly.access.polly.preload.tmp1.merge = getelementptr i32, i32* %polly.preload.tmp1.merge, i64 0
+; IR-NEXT:   %polly.access.polly.preload.tmp1.merge.load = load i32, i32* %polly.access.polly.preload.tmp1.merge, align 4
+;
+;    void f(int **I, int *A, int N, int p, int q) {
+;      for (int i = 0; i < N; i++)
+;        A[i] = *(I[p + q]);
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32** %I, i32* %A, i32 %N, i32 %p, i32 %q) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add = add i32 %p, %q
+  %idxprom = sext i32 %add to i64
+  %arrayidx = getelementptr inbounds i32*, i32** %I, i64 %idxprom
+  %tmp1 = load i32*, i32** %arrayidx, align 8
+  %tmp2 = load i32, i32* %tmp1, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp2, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/no_guard_bb.ll b/final/test/Isl/CodeGen/no_guard_bb.ll
new file mode 100644
index 0000000..6d2bebb
--- /dev/null
+++ b/final/test/Isl/CodeGen/no_guard_bb.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-codegen -S -verify-dom-info < %s | FileCheck %s
+;
+; CHECK-NOT: br i1 true, label %polly.{{.*}}, label %polly.{{.*}}
+;
+;    void jd(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = i;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = trunc i64 %indvars.iv to i32
+  store i32 %tmp, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/non-affine-dominance-generated-entering.ll b/final/test/Isl/CodeGen/non-affine-dominance-generated-entering.ll
new file mode 100644
index 0000000..4ca7d7b
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-dominance-generated-entering.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; llvm.org/PR25439
+; Scalar reloads in the generated entering block were not recognized as
+; dominating the subregion blocks when there were multiple entering nodes. This
+; resulted in values defined in there (here: %cond used in subregionB_entry) not
+; being copied. We check whether it is reusing the reloaded scalar.
+;
+; CHECK-LABEL: polly.stmt.subregionB_entry.exit:
+; CHECK:         store i1 %polly.cond, i1* %cond.s2a
+;
+; CHECK-LABEL: polly.stmt.subregionB_entry.entry:
+; CHECK:         %cond.s2a.reload = load i1, i1* %cond.s2a
+;
+; CHECK-LABEL: polly.stmt.subregionB_entry:
+; CHECK:         br i1 %cond.s2a.reload
+
+define void @func(i32* %A) {
+entry:
+  br label %subregionA_entry
+
+subregionA_entry:
+  %cond = phi i1 [ false, %entry ], [ true, %subregionB_exit ]
+  br i1 %cond, label %subregionA_if, label %subregionA_else
+
+subregionA_if:
+  br label %subregionB_entry
+
+subregionA_else:
+  br label %subregionB_entry
+
+subregionB_entry:
+  store i32 0, i32* %A
+  br i1 %cond, label %subregionB_if, label %subregionB_exit
+
+subregionB_if:
+  br label %subregionB_exit
+
+subregionB_exit:
+  br i1 false, label %subregionA_entry, label %return
+
+return:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/non-affine-exit-node-dominance.ll b/final/test/Isl/CodeGen/non-affine-exit-node-dominance.ll
new file mode 100644
index 0000000..077dd2d
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-exit-node-dominance.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; llvm.org/PR25439
+; The dominance of the generated non-affine subregion block was based on the
+; scop's merge block, therefore resulted in an invalid DominanceTree.
+; It resulted in some values as assumed to be unusable in the actual generated
+; exit block. Here we check whether the value %escaping is taken from the
+; generated block.
+;
+; CHECK-LABEL: polly.stmt.subregion_entry:
+; CHECK:         %p_escaping = select i1 undef, i32 undef, i32 undef
+;
+; CHECK-LABEL: polly.stmt.polly.merge_new_and_old.exit:
+; CHECK:         store i32 %p_escaping, i32* %escaping.s2a
+
+define i32 @func() {
+entry:
+  br label %subregion_entry
+
+subregion_entry:
+  %escaping = select i1 undef, i32 undef, i32 undef
+  %cond = or i1 undef, undef
+  br i1 %cond, label %subregion_exit, label %subregion_if
+
+subregion_if:
+  br label %subregion_exit
+
+subregion_exit:
+  ret i32 %escaping
+}
diff --git a/final/test/Isl/CodeGen/non-affine-phi-node-expansion-2.ll b/final/test/Isl/CodeGen/non-affine-phi-node-expansion-2.ll
new file mode 100644
index 0000000..645b65c
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-phi-node-expansion-2.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-codegen \
+; RUN:     -S < %s | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+
+; CHECK: polly.stmt.bb3:                                   ; preds = %polly.stmt.bb3.entry
+; CHECK:   %tmp6_p_scalar_ = load double, double* %arg1{{[0-9]*}}, !alias.scope !0, !noalias !2
+; CHECK:   %p_tmp7 = fadd double 1.000000e+00, %tmp6_p_scalar_
+; CHECK:   %p_tmp8 = fcmp olt double 1.400000e+01, %p_tmp7
+; CHECK:   br i1 %p_tmp8, label %polly.stmt.bb9, label %polly.stmt.bb10
+
+; CHECK: polly.stmt.bb9:                                   ; preds = %polly.stmt.bb3
+; CHECK:   br label %polly.stmt.bb11.exit
+
+; CHECK: polly.stmt.bb10:                                  ; preds = %polly.stmt.bb3
+; CHECK:   br label %polly.stmt.bb11.exit
+
+; CHECK: polly.stmt.bb11.exit:                             ; preds = %polly.stmt.bb10, %polly.stmt.bb9
+; CHECK:   %polly.tmp12 = phi double [ 1.000000e+00, %polly.stmt.bb9 ], [ 2.000000e+00, %polly.stmt.bb10 ]
+; CHECK:   store double %polly.tmp12, double* %tmp12.phiops
+
+define void @hoge(i32 %arg, [1024 x double]* %arg1) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb
+  br label %bb3
+
+bb3:                                              ; preds = %bb11, %bb2
+  %tmp = phi i64 [ 0, %bb11 ], [ 0, %bb2 ]
+  %tmp4 = icmp sgt i32 %arg, 0
+  %tmp5 = getelementptr inbounds [1024 x double], [1024 x double]* %arg1, i64 0, i64 0
+  %tmp6 = load double, double* %tmp5
+  %tmp7 = fadd double 1.0, %tmp6
+  %tmp8 = fcmp olt double 14.0, %tmp7
+  br i1 %tmp8, label %bb9, label %bb10
+
+bb9:                                              ; preds = %bb3
+  br label %bb11
+
+bb10:                                             ; preds = %bb3
+  br label %bb11
+
+bb11:                                             ; preds = %bb10, %bb9
+  %tmp12 = phi double [ 1.0, %bb9 ], [ 2.0, %bb10 ]
+  %tmp13 = getelementptr inbounds [1024 x double], [1024 x double]* %arg1, i64 %tmp, i64 0
+  store double %tmp12, double* %tmp13
+  %tmp14 = add nuw nsw i64 0, 1
+  %tmp15 = trunc i64 %tmp14 to i32
+  br i1 false, label %bb3, label %bb16
+
+bb16:                                             ; preds = %bb11
+  br label %bb17
+
+bb17:                                             ; preds = %bb16
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/non-affine-phi-node-expansion-3.ll b/final/test/Isl/CodeGen/non-affine-phi-node-expansion-3.ll
new file mode 100644
index 0000000..3296bff
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-phi-node-expansion-3.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-codegen \
+; RUN:     -S < %s | FileCheck %s
+
+define void @foo(float* %A, i1 %cond0, i1 %cond1) {
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %entry], [%indvar.next, %backedge]
+  %val0 = fadd float 1.0, 2.0
+  %val1 = fadd float 1.0, 2.0
+  %val2 = fadd float 1.0, 2.0
+  br i1 %cond0, label %branch1, label %backedge
+
+; CHECK-LABEL: polly.stmt.loop:
+; CHECK-NEXT: %p_val0 = fadd float 1.000000e+00, 2.000000e+00
+; CHECK-NEXT: %p_val1 = fadd float 1.000000e+00, 2.000000e+00
+; CHECK-NEXT: %p_val2 = fadd float 1.000000e+00, 2.000000e+00
+; CHECK-NEXT: br i1
+
+branch1:
+  br i1 %cond1, label %branch2, label %backedge
+
+; CHECK-LABEL: polly.stmt.branch1:
+; CHECK-NEXT: br i1
+
+branch2:
+  br label %backedge
+
+; CHECK-LABEL: polly.stmt.branch2:
+; CHECK-NEXT:    br label
+
+; CHECK-LABEL: polly.stmt.backedge.exit:
+; CHECK:         %polly.merge = phi float [ %p_val0, %polly.stmt.loop ], [ %p_val1, %polly.stmt.branch1 ], [ %p_val2, %polly.stmt.branch2 ]
+
+backedge:
+  %merge = phi float [%val0, %loop], [%val1, %branch1], [%val2, %branch2]
+  %indvar.next = add i64 %indvar, 1
+  store float %merge, float* %A
+  %cmp = icmp sle i64 %indvar.next, 100
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/non-affine-phi-node-expansion-4.ll b/final/test/Isl/CodeGen/non-affine-phi-node-expansion-4.ll
new file mode 100644
index 0000000..6943711
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-phi-node-expansion-4.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-codegen \
+; RUN:     -S < %s | FileCheck %s
+
+define void @foo(float* %A, i1 %cond0, i1 %cond1) {
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %entry], [%indvar.next, %backedge]
+  %val0 = fadd float 1.0, 2.0
+  %val1 = fadd float 1.0, 2.0
+  br i1 %cond0, label %branch1, label %backedge
+
+; CHECK-LABEL: polly.stmt.loop:
+; CHECK-NEXT:    %p_val0 = fadd float 1.000000e+00, 2.000000e+00
+; CHECK-NEXT:    %p_val1 = fadd float 1.000000e+00, 2.000000e+00
+; CHECK-NEXT:    br i1
+
+; The interesting instruction here is %val2, which does not dominate the exit of
+; the non-affine region. Care needs to be taken when code-generating this write.
+; Specifically, at some point we modeled this scalar write, which we tried to
+; code generate in the exit block of the non-affine region.
+branch1:
+  %val2 = fadd float 1.0, 2.0
+  br i1 %cond1, label %branch2, label %backedge
+
+; CHECK-LABEL: polly.stmt.branch1:
+; CHECK-NEXT:    %p_val2 = fadd float 1.000000e+00, 2.000000e+00
+; CHECK-NEXT:    br i1
+
+branch2:
+  br label %backedge
+
+; CHECK-LABEL: polly.stmt.branch2:
+; CHECK-NEXT:    br label
+
+; CHECK-LABEL: polly.stmt.backedge.exit:
+; CHECK:         %polly.merge = phi float [ %p_val0, %polly.stmt.loop ], [ %p_val1, %polly.stmt.branch1 ], [ %p_val2, %polly.stmt.branch2 ]
+
+backedge:
+  %merge = phi float [%val0, %loop], [%val1, %branch1], [%val2, %branch2]
+  %indvar.next = add i64 %indvar, 1
+  store float %merge, float* %A
+  %cmp = icmp sle i64 %indvar.next, 100
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/non-affine-phi-node-expansion.ll b/final/test/Isl/CodeGen/non-affine-phi-node-expansion.ll
new file mode 100644
index 0000000..246cd8c
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-phi-node-expansion.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-codegen \
+; RUN:     -S < %s | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.wombat = type {[4 x i32]}
+
+; CHECK-NOT:  polly.preload.begin:
+; CHECK-NOT:    %polly.access.B
+; CHECK-NOT:    %polly.access.B.load
+
+; CHECK: polly.split_new_and_old
+
+; CHECK: polly.stmt.bb3.entry:                             ; preds = %polly.start
+; CHECK:   br label %polly.stmt.bb3
+
+; CHECK: polly.stmt.bb3:                                   ; preds = %polly.stmt.bb3.entry
+; CHECK:   br i1 true, label %polly.stmt.bb4, label %polly.stmt.bb5
+
+; CHECK: polly.stmt.bb4:                                   ; preds = %polly.stmt.bb3
+; CHECK:   br label %polly.stmt.bb13.exit
+
+; CHECK: polly.stmt.bb5:                                   ; preds = %polly.stmt.bb3
+; CHECK:   load i32, i32* %B
+
+; Function Attrs: nounwind uwtable
+define void @quux(%struct.wombat* %arg, i32* %B) {
+bb:
+  br i1 undef, label %bb2, label %bb1
+
+bb1:                                              ; preds = %bb
+  br label %bb2
+
+bb2:                                              ; preds = %bb1, %bb
+  %tmp = phi i1 [ true, %bb ], [ undef, %bb1 ]
+  br label %bb3
+
+bb3:                                              ; preds = %bb13, %bb2
+  br i1 %tmp, label %bb4, label %bb5
+
+bb4:                                              ; preds = %bb3
+  br label %bb13
+
+bb5:                                              ; preds = %bb3
+  %tmp7 = load i32, i32* %B
+  %tmp12 = getelementptr inbounds %struct.wombat, %struct.wombat* %arg, i64 0, i32 0, i64 0
+  store i32 %tmp7, i32* %tmp12
+  br label %bb13
+
+bb13:                                             ; preds = %bb5, %bb4
+  br i1 false, label %bb3, label %bb14
+
+bb14:                                             ; preds = %bb13
+  br label %bb15
+
+bb15:                                             ; preds = %bb14
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/non-affine-region-exit-phi-incoming-synthesize-2.ll b/final/test/Isl/CodeGen/non-affine-region-exit-phi-incoming-synthesize-2.ll
new file mode 100644
index 0000000..1a6fb4d
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-region-exit-phi-incoming-synthesize-2.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; This caused the code generation to generate invalid code as the same operand
+; of the PHI node in the non-affine region was synthesized at the wrong place.
+; Check we do not generate wrong code.
+;
+; CHECK: polly.start
+;
+; ModuleID = 'bugpoint-reduced-simplified.bc'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@connected_passed = external global [256 x i8], align 16
+
+; Function Attrs: norecurse nounwind uwtable
+define void @InitializeZeroMasks() {
+entry:
+  br label %for.end20
+
+for.end20:                                        ; preds = %entry
+  br label %for.body24
+
+for.body24:                                       ; preds = %for.body61.preheader, %for.end20
+  %indvars.iv = phi i64 [ 0, %for.end20 ], [ %indvars.iv.next, %for.body61.preheader ]
+  %arrayidx26 = getelementptr inbounds [256 x i8], [256 x i8]* @connected_passed, i64 0, i64 %indvars.iv
+  store i8 0, i8* %arrayidx26, align 1
+  %0 = trunc i64 %indvars.iv to i32
+  br i1 false, label %for.inc56.4, label %if.then51
+
+if.then51:                                        ; preds = %for.inc56.5, %for.body24
+  %j.342.lcssa = phi i8 [ 7, %for.body24 ], [ %.mux, %for.inc56.5 ]
+  br label %for.body61.preheader
+
+for.body61.preheader:                             ; preds = %for.inc56.5, %if.then51
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 256
+  br i1 %exitcond, label %for.end79, label %for.body24
+
+for.end79:                                        ; preds = %for.body61.preheader
+  ret void
+
+for.inc56.4:                                      ; preds = %for.body24
+  br label %for.inc56.5
+
+for.inc56.5:                                      ; preds = %for.inc56.4
+  %and49.6 = and i32 %0, 64
+  %brmerge = or i1 undef, undef
+  %and49.6.lobit = lshr exact i32 %and49.6, 6
+  %.mux = trunc i32 %and49.6.lobit to i8
+  br i1 %brmerge, label %if.then51, label %for.body61.preheader
+}
diff --git a/final/test/Isl/CodeGen/non-affine-region-exit-phi-incoming-synthesize.ll b/final/test/Isl/CodeGen/non-affine-region-exit-phi-incoming-synthesize.ll
new file mode 100644
index 0000000..036bf34
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-region-exit-phi-incoming-synthesize.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; This caused the code generation to generate invalid code as the same BBMap was
+; used for the whole non-affine region. When %add is synthesized for the
+; incoming value of subregion_if first, the code for it was generated into
+; subregion_if, but reused for the incoming value of subregion_exit, although it
+; is not dominated by subregion_if.
+;
+; CHECK-LABEL: polly.stmt.subregion_entry:
+; CHECK:         %[[R0:[0-9]*]] = add i32 %n, -2
+;
+; CHECK-LABEL: polly.stmt.subregion_if:
+; CHECK:         %[[R1:[0-9]*]] = add i32 %n, -2
+;
+; CHECK-LABEL: polly.stmt.subregion_exit.region_exiting:
+; CHECK:         %polly.retval = phi i32 [ %[[R1]], %polly.stmt.subregion_if ], [ %[[R0]], %polly.stmt.subregion_entry ]
+
+define i32 @func(i32 %n){
+entry:
+  br label %subregion_entry
+
+subregion_entry:
+  %add = add nsw i32 %n, -2
+  %cmp = fcmp ogt float undef, undef
+  br i1 %cmp, label %subregion_if, label %subregion_exit
+
+subregion_if:
+  br label %subregion_exit
+
+subregion_exit:
+  %retval = phi i32 [ %add, %subregion_if ], [ %add, %subregion_entry ]
+  ret i32 %retval
+}
diff --git a/final/test/Isl/CodeGen/non-affine-region-implicit-store.ll b/final/test/Isl/CodeGen/non-affine-region-implicit-store.ll
new file mode 100644
index 0000000..e31b872
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-region-implicit-store.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; llvm.org/PR25438
+; After loop versioning, a dominance check of a non-affine subregion's exit node
+; causes the dominance check to always fail any block in the scop. The
+; subregion's exit block has become polly_merge_new_and_old, which also receives
+; the control flow of the generated code. This would cause that any value for
+; implicit stores is assumed to be not from the scop.
+;
+; This checks that the stored value is indeed from the generated code.
+;
+; CHECK-LABEL: polly.stmt.do.body.entry:
+; CHECK:        a.phiops.reload = load i32, i32* %a.phiops
+;
+; CHECK-LABEL: polly.stmt.polly.merge_new_and_old.exit:
+; CHECK:         store i32 %polly.a, i32* %a.s2a
+
+define void @func() {
+entry:
+  br label %while.body
+
+while.body:
+  br label %do.body
+
+do.body:
+  %a = phi i32 [ undef, %while.body ], [ %b, %end_b ]
+  %cond = or i1 undef, undef
+  br i1 %cond, label %end_a, label %if_a
+
+if_a:
+  br label %end_a
+
+end_a:
+  br i1 undef, label %if_b, label %end_b
+
+if_b:
+  br label %end_b
+
+end_b:
+  %b = phi i32 [ undef, %if_b ], [ %a, %end_a ]
+  br i1 false, label %do.body, label %do.end
+
+do.end:
+  br label %return
+
+return:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/non-affine-region-phi-references-in-scop-value.ll b/final/test/Isl/CodeGen/non-affine-region-phi-references-in-scop-value.ll
new file mode 100644
index 0000000..6c28208
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-region-phi-references-in-scop-value.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-codegen -polly-allow-nonaffine-loops \
+; RUN: -S < %s | FileCheck %s
+
+; This test verifies that values defined in another scop statement and used by
+; PHI-nodes in non-affine regions are code generated correctly.
+
+; CHECK: polly.stmt.bb3.entry:
+; CHECK-NEXT:   %j.0.phiops.reload = load i64, i64* %j.0.phiops
+; CHECK-NEXT:   br label %polly.stmt.bb3
+
+; CHECK: polly.stmt.bb3:
+; CHECK-NEXT:   %polly.subregion.iv = phi i32 [ %polly.subregion.iv.inc, %polly.stmt.bb9 ], [ 0, %polly.stmt.bb3.entry ]
+; CHECK-NEXT:   %polly.j.0 = phi i64 [ %j.0.phiops.reload, %polly.stmt.bb3.entry ], [ %p_tmp10, %polly.stmt.bb9 ]
+
+;    void foo(long A[], float B[], long *x) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = *x; j < i * i; j++)
+;          B[42]++;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64* %A, float* %B, i64* %xptr) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb12, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp13, %bb12 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb14
+
+bb2:                                              ; preds = %bb1
+  %x = load i64, i64* %xptr
+  br label %bb3
+
+bb3:                                              ; preds = %bb9, %bb2
+  %j.0 = phi i64 [ %x, %bb2 ], [ %tmp10, %bb9 ]
+  %tmp = mul nsw i64 %i.0, %i.0
+  %tmp4 = icmp slt i64 %j.0, %tmp
+  br i1 %tmp4, label %bb5, label %bb11
+
+bb5:                                              ; preds = %bb3
+  %tmp6 = getelementptr inbounds float, float* %B, i64 42
+  %tmp7 = load float, float* %tmp6, align 4
+  %tmp8 = fadd float %tmp7, 1.000000e+00
+  store float %tmp8, float* %tmp6, align 4
+  br label %bb9
+
+bb9:                                              ; preds = %bb5
+  %tmp10 = add nuw nsw i64 %j.0, 1
+  br label %bb3
+
+bb11:                                             ; preds = %bb3
+  br label %bb12
+
+bb12:                                             ; preds = %bb11
+  %tmp13 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb14:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/non-affine-subregion-dominance-reuse.ll b/final/test/Isl/CodeGen/non-affine-subregion-dominance-reuse.ll
new file mode 100644
index 0000000..f93aa37
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-subregion-dominance-reuse.ll
@@ -0,0 +1,75 @@
+; RUN: opt %loadPolly -polly-codegen -S -verify-dom-info \
+; RUN:     < %s | FileCheck %s
+;
+; Check that we do not reuse the B[i-1] GEP created in block S again in
+; block Q. Hence, we create two GEPs for B[i-1]:
+;
+; CHECK:  %scevgep{{.}} = getelementptr i32, i32* %B, i64 -1
+; CHECK:  %scevgep{{.}} = getelementptr i32, i32* %B, i64 -1
+;
+;    void f(int *A, int *B) {
+;      int x = 0;
+;      for (int i = 0; i < 1024; i++) {
+;        if (A[i]) {
+;          if (i > 512)
+; S:         A[i] = B[i - 1];
+; Q:       A[i] += B[i - 1];
+;        }
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %B) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb22, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb22 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb23
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %tmp, align 4
+  %tmp4 = icmp eq i32 %tmp3, 0
+  br i1 %tmp4, label %bb21, label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = icmp sgt i64 %indvars.iv, 512
+  br i1 %tmp6, label %bb7, label %bb13
+
+bb7:                                              ; preds = %bb5
+  br label %bb8
+
+bb8:                                              ; preds = %bb7
+  %tmp9 = add nsw i64 %indvars.iv, -1
+  %tmp10 = getelementptr inbounds i32, i32* %B, i64 %tmp9
+  %tmp11 = load i32, i32* %tmp10, align 4
+  %tmp12 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp11, i32* %tmp12, align 4
+  br label %bb13
+
+bb13:                                             ; preds = %bb8, %bb5
+  br label %bb14
+
+bb14:                                             ; preds = %bb13
+  %tmp15 = add nsw i64 %indvars.iv, -1
+  %tmp16 = getelementptr inbounds i32, i32* %B, i64 %tmp15
+  %tmp17 = load i32, i32* %tmp16, align 4
+  %tmp18 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp19 = load i32, i32* %tmp18, align 4
+  %tmp20 = add nsw i32 %tmp19, %tmp17
+  store i32 %tmp20, i32* %tmp18, align 4
+  br label %bb21
+
+bb21:                                             ; preds = %bb2, %bb14
+  br label %bb22
+
+bb22:                                             ; preds = %bb21
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb23:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/non-affine-switch.ll b/final/test/Isl/CodeGen/non-affine-switch.ll
new file mode 100644
index 0000000..d180f51
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-switch.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly \
+; RUN: -S -polly-codegen < %s | FileCheck %s
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        switch (A[i]) {
+;        case 0:
+;          A[i] += 1;
+;          break;
+;        case 1:
+;          A[i] += 2;
+;          break;
+;        }
+;    }
+;
+; CHECK: polly.stmt.for.body:
+; CHECK:   %scevgep = getelementptr i32, i32* %A, i64 %polly.indvar
+; CHECK:   %tmp1_p_scalar_ = load i32, i32* %scevgep, align 4
+; CHECK:   switch i32 %tmp1_p_scalar_, label %polly.stmt.sw.epilog.exit [
+; CHECK:     i32 0, label %polly.stmt.sw.bb
+; CHECK:     i32 1, label %polly.stmt.sw.bb.3
+; CHECK:   ]
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  switch i32 %tmp1, label %sw.epilog [
+    i32 0, label %sw.bb
+    i32 1, label %sw.bb.3
+  ]
+
+sw.bb:                                            ; preds = %for.body
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx2, align 4
+  %add = add nsw i32 %tmp2, 1
+  store i32 %add, i32* %arrayidx2, align 4
+  br label %sw.epilog
+
+sw.bb.3:                                          ; preds = %for.body
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %arrayidx5, align 4
+  %add6 = add nsw i32 %tmp3, 2
+  store i32 %add6, i32* %arrayidx5, align 4
+  br label %sw.epilog
+
+sw.epilog:                                        ; preds = %sw.bb.3, %sw.bb, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %sw.epilog
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/non-affine-synthesized-in-branch.ll b/final/test/Isl/CodeGen/non-affine-synthesized-in-branch.ll
new file mode 100644
index 0000000..3d5633c
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-synthesized-in-branch.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -polly-process-unprofitable -polly-codegen -S < %s | FileCheck %s
+;
+; llvm.org/PR25412
+; %synthgep caused %gep to be synthesized in subregion_if which was reused for
+; %retval in subregion_exit, even though it is not dominating subregion_exit.
+;
+; CHECK-LABEL: polly.stmt.polly.merge_new_and_old.exit:
+; CHECK:         %scevgep[[R1:[0-9]*]] = getelementptr %struct.hoge, %struct.hoge* %arg, i64 0, i32 2
+; CHECK:         store double* %scevgep[[R1]], double** %gep.s2a
+; CHECK:         br label
+
+%struct.hoge = type { double, double, double }
+
+define double @func(%struct.hoge* %arg) {
+entry:
+  br label %subregion_entry
+
+subregion_entry:
+  %gep = getelementptr inbounds %struct.hoge, %struct.hoge* %arg, i64 0, i32 2
+  %cond = fcmp ogt double undef, undef
+  br i1 %cond, label %subregion_if, label %subregion_exit
+
+subregion_if:
+  %synthgep = load double, double* %gep
+  br label %subregion_exit
+
+subregion_exit:
+  %retval = load double, double* %gep
+  ret double %retval
+}
diff --git a/final/test/Isl/CodeGen/non-affine-update.ll b/final/test/Isl/CodeGen/non-affine-update.ll
new file mode 100644
index 0000000..ff1d630
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-update.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN:     -polly-codegen -S < %s | FileCheck %s
+;
+;    void non-affine-update(double A[], double C[], double B[]) {
+;      for (int i = 0; i < 10; i++) {
+;        if (A[i] >= 6)
+;          B[i] += 42;
+;        else
+;          C[i] += 3;
+;      }
+;    }
+
+; Verify that all changed memory access functions are corectly code generated.
+; At some point this did not work due to memory access identifiers not being
+; unique within non-affine scop statements.
+
+; CHECK: polly.stmt.bb2:
+; CHECK:   %scevgep = getelementptr double, double* %A, i64 %polly.indvar
+
+; CHECK: polly.stmt.bb9:
+; CHECK:   %polly.access.C{{.*}} = getelementptr double, double* %C, i64 42
+; CHECK:   %polly.access.C{{.*}} = getelementptr double, double* %C, i64 42
+
+; CHECK: polly.stmt.bb5:
+; CHECK:   %polly.access.B{{.*}} = getelementptr double, double* %B, i64 113
+; CHECK:   %polly.access.B{{.*}} = getelementptr double, double* %B, i64 113
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @non-affine-update(double* %A, double* %C, double* %B) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb14, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb14 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 10
+  br i1 %exitcond, label %bb2, label %bb15
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds double, double* %A, i64 %indvars.iv
+  %tmp3 = load double, double* %tmp, align 8
+  %tmp4 = fcmp ult double %tmp3, 6.000000e+00
+  br i1 %tmp4, label %bb9, label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = getelementptr inbounds double, double* %B, i64 %indvars.iv
+  %tmp7 = load double, double* %tmp6, align 8
+  %tmp8 = fadd double %tmp7, 4.200000e+01
+  store double %tmp8, double* %tmp6, align 8
+  br label %bb13
+
+bb9:                                              ; preds = %bb2
+  %tmp10 = getelementptr inbounds double, double* %C, i64 %indvars.iv
+  %tmp11 = load double, double* %tmp10, align 8
+  %tmp12 = fadd double %tmp11, 3.000000e+00
+  store double %tmp12, double* %tmp10, align 8
+  br label %bb13
+
+bb13:                                             ; preds = %bb9, %bb5
+  br label %bb14
+
+bb14:                                             ; preds = %bb13
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb15:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/non-affine-update___%bb1---%bb15.jscop b/final/test/Isl/CodeGen/non-affine-update___%bb1---%bb15.jscop
new file mode 100644
index 0000000..72a24ad
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-update___%bb1---%bb15.jscop
@@ -0,0 +1,33 @@
+{
+   "context" : "{  :  }",
+   "name" : "bb1 => bb15",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2__TO__bb13[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2__TO__bb13[i0] -> MemRef_C[42] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb2__TO__bb13[i0] -> MemRef_C[42] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2__TO__bb13[i0] -> MemRef_B[113] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb2__TO__bb13[i0] -> MemRef_B[113] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb2__TO__bb13[i0] : i0 <= 9 and i0 >= 0 }",
+         "name" : "Stmt_bb2__TO__bb13",
+         "schedule" : "{ Stmt_bb2__TO__bb13[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/non-hoisted-load-needed-as-base-ptr.ll b/final/test/Isl/CodeGen/non-hoisted-load-needed-as-base-ptr.ll
new file mode 100644
index 0000000..265363c
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-hoisted-load-needed-as-base-ptr.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -tbaa -polly-codegen -disable-output %s
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.1 = type { %struct.2*, %struct.2*, %struct.3*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i8*, i8*, i8*, i8*, i8*, i32, [38 x i8], [128 x i8], [38 x i32], [256 x i8], [256 x i8], [256 x i8], %struct.4, [25 x [16 x %struct.4]], [128 x [64 x i16]] }
+%struct.2 = type { i16, i16, i32, i32 }
+%struct.3 = type { i8, i8, i16, i16 }
+%struct.4 = type { i16, i8, i8 }
+
+define void @AllocUnitsRare(%struct.1* %p, i32 %indx) {
+entry:
+  br label %do.body
+
+do.body:                                          ; preds = %do.body, %entry
+  %i.0 = phi i32 [ %inc, %do.body ], [ %indx, %entry ]
+  %inc = add i32 %i.0, 1
+  br i1 undef, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.body
+  %Base.i = getelementptr inbounds %struct.1, %struct.1* %p, i32 0, i32 12
+  %tmp.i = load i8*, i8** %Base.i, align 8, !tbaa !0
+  %idxprom.i = zext i32 %inc to i64
+  %FreeList.i = getelementptr inbounds %struct.1, %struct.1* %p, i32 0, i32 20
+  %arrayidx.i = getelementptr inbounds [38 x i32], [38 x i32]* %FreeList.i, i64 0, i64 %idxprom.i
+  %tmp1.i = bitcast i8* %tmp.i to i32*
+  %tmp2.i = load i32, i32* %tmp1.i, align 4, !tbaa !8
+  store i32 %tmp2.i, i32* %arrayidx.i, align 4, !tbaa !8
+  %Indx2Units.i = getelementptr inbounds %struct.1, %struct.1* %p, i32 0, i32 18
+  %arrayidx.i1 = getelementptr inbounds [38 x i8], [38 x i8]* %Indx2Units.i, i64 0, i64 0
+  %cmp.i = icmp ne i32 0, 3
+  br i1 %cmp.i, label %if.then.i, label %SplitBlock.exit
+
+if.then.i:                                        ; preds = %do.end
+  br label %SplitBlock.exit
+
+SplitBlock.exit:                                  ; preds = %if.then.i, %do.end
+  ret void
+}
+
+!0 = !{!1, !2, i64 64}
+!1 = !{!"", !2, i64 0, !2, i64 8, !2, i64 16, !5, i64 24, !5, i64 28, !5, i64 32, !5, i64 36, !5, i64 40, !5, i64 44, !5, i64 48, !5, i64 52, !5, i64 56, !2, i64 64, !2, i64 72, !2, i64 80, !2, i64 88, !2, i64 96, !5, i64 104, !3, i64 108, !3, i64 146, !3, i64 276, !3, i64 428, !3, i64 684, !3, i64 940, !6, i64 1196, !3, i64 1200, !3, i64 2800}
+!2 = !{!"any pointer", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!"int", !3, i64 0}
+!6 = !{!"", !7, i64 0, !3, i64 2, !3, i64 3}
+!7 = !{!"short", !3, i64 0}
+!8 = !{!5, !5, i64 0}
diff --git a/final/test/Isl/CodeGen/non_affine_float_compare.ll b/final/test/Isl/CodeGen/non_affine_float_compare.ll
new file mode 100644
index 0000000..138da01
--- /dev/null
+++ b/final/test/Isl/CodeGen/non_affine_float_compare.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-codegen \
+; RUN:     -polly-allow-nonaffine-branches -S -verify-dom-info \
+; RUN:     < %s | FileCheck %s
+;
+;    void f(float *A) {
+;      for (int i = 0; i < 1024; i++)
+;        if (A[i] == A[i - 1])
+;          A[i]++;
+;       A[i]++;
+;    }
+;
+;
+; CHECK: polly.stmt.bb2:
+; CHECK:   %scevgep[[R0:[0-9]*]] = getelementptr float, float* %A, i64 %polly.indvar
+; CHECK:   %tmp3_p_scalar_ = load float, float* %scevgep[[R0]], align 4, !alias.scope !0, !noalias !2
+; CHECK:   %scevgep[[R2:[0-9]*]] = getelementptr float, float* %scevgep{{[0-9]*}}, i64 %polly.indvar
+; CHECK:   %tmp6_p_scalar_ = load float, float* %scevgep[[R2]], align 4, !alias.scope !0, !noalias !2
+; CHECK:   %p_tmp7 = fcmp oeq float %tmp3_p_scalar_, %tmp6_p_scalar_
+; CHECK:   br i1 %p_tmp7, label %polly.stmt.bb8, label %polly.stmt.bb12.[[R:[a-zA-Z_.0-9]*]]
+
+; CHECK: polly.stmt.bb8:
+; CHECK:   %scevgep[[R3:[0-9]*]] = getelementptr float, float* %A, i64 %polly.indvar
+; CHECK:   %tmp10_p_scalar_ = load float, float* %scevgep[[R3]], align 4, !alias.scope !0, !noalias !2
+; CHECK:   %p_tmp11 = fadd float %tmp10_p_scalar_, 1.000000e+00
+; CHECK:   store float %p_tmp11, float* %scevgep[[R3]], align 4, !alias.scope !0, !noalias !2
+; CHECK:   br label %polly.stmt.bb12.[[R]]
+
+; CHECK: polly.stmt.bb12.[[R]]:
+; CHECK:   br label %polly.stmt.bb12
+
+; CHECK: polly.stmt.bb12:
+; CHECK:   %scevgep[[R4:[0-9]*]] = getelementptr float, float* %A, i64 %polly.indvar
+; CHECK:   %tmp10b_p_scalar_ = load float, float* %scevgep[[R4]], align 4, !alias.scope !0, !noalias !2
+; CHECK:   %p_tmp11b = fadd float %tmp10b_p_scalar_, 1.000000e+00
+; CHECK:   store float %p_tmp11b, float* %scevgep[[R4]], align 4, !alias.scope !0, !noalias !2
+; CHECK:   %polly.indvar_next = add nsw i64 %polly.indvar, 1
+; CHECK:   %polly.loop_cond = icmp sle i64 %polly.indvar_next, 1023
+; CHECK:   br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(float* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb13, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb13 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb14
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp3 = load float, float* %tmp, align 4
+  %tmp4 = add nsw i64 %indvars.iv, -1
+  %tmp5 = getelementptr inbounds float, float* %A, i64 %tmp4
+  %tmp6 = load float, float* %tmp5, align 4
+  %tmp7 = fcmp oeq float %tmp3, %tmp6
+  br i1 %tmp7, label %bb8, label %bb12
+
+bb8:                                              ; preds = %bb2
+  %tmp9 = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp10 = load float, float* %tmp9, align 4
+  %tmp11 = fadd float %tmp10, 1.000000e+00
+  store float %tmp11, float* %tmp9, align 4
+  br label %bb12
+
+bb12:                                             ; preds = %bb8, %bb2
+  %tmp9b = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp10b = load float, float* %tmp9b, align 4
+  %tmp11b = fadd float %tmp10b, 1.000000e+00
+  store float %tmp11b, float* %tmp9b, align 4
+  br label %bb13
+
+bb13:                                             ; preds = %bb12
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb14:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/only_non_affine_error_region.ll b/final/test/Isl/CodeGen/only_non_affine_error_region.ll
new file mode 100644
index 0000000..e8ba768
--- /dev/null
+++ b/final/test/Isl/CodeGen/only_non_affine_error_region.ll
@@ -0,0 +1,31 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; CHECK-NOT: polly.start
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @f(i32 %argc, i32* %A) #0 {
+entry:
+  br i1 undef, label %for.end, label %for.body
+
+for.body:                                         ; preds = %entry
+  br label %for.end
+
+for.end:                                          ; preds = %for.body, %entry
+  %i.2 = phi i32 [ 1, %entry ], [ 1, %for.body ]
+  %cmp170 = icmp eq i32 %i.2, %argc
+  br i1 %cmp170, label %if.then172, label %if.end174
+
+if.then172:                                       ; preds = %for.end
+  %0 = load i32, i32* %A
+  tail call void @usage()
+  br label %if.end174
+
+if.end174:                                        ; preds = %if.then172, %for.end
+  %idxprom175 = sext i32 %i.2 to i64
+  ret void
+}
+
+; Function Attrs: nounwind uwtable
+declare void @usage()
diff --git a/final/test/Isl/CodeGen/openmp_limit_threads.ll b/final/test/Isl/CodeGen/openmp_limit_threads.ll
new file mode 100644
index 0000000..82b9f8d
--- /dev/null
+++ b/final/test/Isl/CodeGen/openmp_limit_threads.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-codegen -polly-parallel -S < %s | FileCheck %s --check-prefix=AUTO
+; RUN: opt %loadPolly -polly-codegen -polly-parallel -polly-num-threads=1 -S < %s | FileCheck %s --check-prefix=ONE
+; RUN: opt %loadPolly -polly-codegen -polly-parallel -polly-num-threads=4 -S < %s | FileCheck %s --check-prefix=FOUR
+;
+; AUTO: call void @GOMP_parallel_loop_runtime_start(void (i8*)* @jd_polly_subfn, i8* %polly.par.userContext{{[0-9]*}}, i32 0, i64 0, i64 1024, i64 1)
+; ONE: call void @GOMP_parallel_loop_runtime_start(void (i8*)* @jd_polly_subfn, i8* %polly.par.userContext{{[0-9]*}}, i32 1, i64 0, i64 1024, i64 1)
+; FOUR: call void @GOMP_parallel_loop_runtime_start(void (i8*)* @jd_polly_subfn, i8* %polly.par.userContext{{[0-9]*}}, i32 4, i64 0, i64 1024, i64 1)
+;
+;    void jd(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        for (int j = 0; j < 1024; j++)
+;          A[i + j * 1024] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc4 ], [ 0, %entry ]
+  %exitcond5 = icmp ne i64 %indvars.iv3, 1024
+  br i1 %exitcond5, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %for.body ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %tmp = shl nsw i64 %indvars.iv, 10
+  %tmp6 = add nsw i64 %indvars.iv3, %tmp
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %tmp6
+  store i32 0, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/out-of-scop-phi-node-use.ll b/final/test/Isl/CodeGen/out-of-scop-phi-node-use.ll
new file mode 100644
index 0000000..d07e7b5
--- /dev/null
+++ b/final/test/Isl/CodeGen/out-of-scop-phi-node-use.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK-LABEL: polly.merge_new_and_old:
+; CHECK-NEXT: %_s.sroa.343.0.ph5161118.ph.merge = phi i32 [ %_s.sroa.343.0.ph5161118.ph.final_reload, %polly.exiting ], [ %_s.sroa.343.0.ph516.lcssa2357, %for.cond.981.region_exiting ]
+
+; CHECK-LABEL: for.cond.981:
+; CHECK-NEXT:  %_s.sroa.343.0.ph5161118 = phi i32 [ undef, %for.cond ], [ %_s.sroa.343.0.ph5161118.ph.merge, %polly.merge_new_and_old ]
+
+; CHECK-LABEL: polly.exiting:
+; CHECK-NEXT: %_s.sroa.343.0.ph5161118.ph.final_reload = load i32, i32* %_s.sroa.343.0.ph5161118.s2a
+
+; Function Attrs: nounwind uwtable
+define void @lzmaDecode() #0 {
+entry:
+  br label %for.cond.outer.outer.outer
+
+for.cond:                                         ; preds = %for.cond.outer.outer.outer
+  switch i32 undef, label %cleanup.1072 [
+    i32 23, label %for.cond.981
+    i32 4, label %_LZMA_C_RDBD
+    i32 19, label %sw.bb.956
+    i32 26, label %saveStateAndReturn
+  ]
+
+_LZMA_C_RDBD:                                     ; preds = %for.cond
+  ret void
+
+sw.bb.956:                                        ; preds = %for.cond
+  %_s.sroa.294.0.ph519.lcssa2388 = phi i32 [ undef, %for.cond ]
+  %_s.sroa.343.0.ph516.lcssa2357 = phi i32 [ undef, %for.cond ]
+  %cmp958 = icmp eq i32 %_s.sroa.294.0.ph519.lcssa2388, 0
+  br i1 %cmp958, label %if.then.960, label %if.else.969
+
+if.then.960:                                      ; preds = %sw.bb.956
+  br label %for.cond.981
+
+if.else.969:                                      ; preds = %sw.bb.956
+  br label %for.cond.981
+
+for.cond.981:                                     ; preds = %if.else.969, %if.then.960, %for.cond
+  %_s.sroa.343.0.ph5161118 = phi i32 [ %_s.sroa.343.0.ph516.lcssa2357, %if.then.960 ], [ %_s.sroa.343.0.ph516.lcssa2357, %if.else.969 ], [ undef, %for.cond ]
+  ret void
+
+for.cond.outer.outer.outer:                       ; preds = %entry
+  br label %for.cond
+
+saveStateAndReturn:                               ; preds = %for.cond
+  ret void
+
+cleanup.1072:                                     ; preds = %for.cond
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 250010) (llvm/trunk 250018)"}
diff --git a/final/test/Isl/CodeGen/param_div_div_div_2.ll b/final/test/Isl/CodeGen/param_div_div_div_2.ll
new file mode 100644
index 0000000..117687b
--- /dev/null
+++ b/final/test/Isl/CodeGen/param_div_div_div_2.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s --check-prefix=IR
+;
+; Check that we guard the divisions because we moved them and thereby increased
+; their domain.
+;
+; CHECK:         Invalid Context:
+; CHECK-NEXT:    [p_0] -> {  : p_0 < 0 }
+; CHECK-NEXT:    p0: ((%a /u %b) /u (%c /u %d))
+;
+;    void f(unsigned *A, unsigned a, unsigned b, unsigned c, unsigned d) {
+;      for (unsigned i; i < 100; i++)
+;        A[i] += A[(a / b) / (c / d)];
+;    }
+;
+; IR:       %[[R0:[.a-zA-Z0-9]*]] = icmp ugt i32 %b, 1
+; IR-NEXT:  %[[R1:[.a-zA-Z0-9]*]] = select i1 %[[R0]], i32 %b, i32 1
+; IR-NEXT:  %[[R2:[.a-zA-Z0-9]*]] = udiv i32 %a, %[[R1]]
+; IR-NEXT:  %[[R5:[.a-zA-Z0-9]*]] = icmp ugt i32 %d, 1
+; IR-NEXT:  %[[R6:[.a-zA-Z0-9]*]] = select i1 %[[R5]], i32 %d, i32 1
+; IR-NEXT:  %[[R7:[.a-zA-Z0-9]*]] = udiv i32 %c, %[[R6]]
+; IR-NEXT:  %[[R3:[.a-zA-Z0-9]*]] = icmp ugt i32 %[[R7]], 1
+; IR-NEXT:  %[[R4:[.a-zA-Z0-9]*]] = select i1 %[[R3]], i32 %[[R7]], i32 1
+; IR-NEXT:  %[[R8:[.a-zA-Z0-9]*]] = udiv i32 %[[R2]], %[[R4]]
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %a, i32 %b, i32 %c, i32 %d) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp ult i64 %indvars.iv, 100
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %div = udiv i32 %a, %b
+  %div1 = udiv i32 %c, %d
+  %div2 = udiv i32 %div, %div1
+  %idxprom = zext i32 %div2 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx4 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx4, align 4
+  %add = add i32 %tmp1, %tmp
+  store i32 %add, i32* %arrayidx4, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/partial_write_array.ll b/final/test/Isl/CodeGen/partial_write_array.ll
new file mode 100644
index 0000000..09fe054
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_array.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -S < %s | FileCheck %s
+;
+; Partial write of an array access.
+;
+; for (int j = 0; j < n; j += 1)
+;   A[0] = 42.0
+;
+
+define void @partial_write_array(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      polly.stmt.body:
+; CHECK-NEXT:   %1 = icmp sge i64 %polly.indvar, 5
+; CHECK-NEXT:   %polly.Stmt_body_Write0.cond = icmp ne i1 %1, false
+; CHECK-NEXT:   br i1 %polly.Stmt_body_Write0.cond, label %polly.stmt.body.Stmt_body_Write0.partial, label %polly.stmt.body.cont
+
+; CHECK:      polly.stmt.body.Stmt_body_Write0.partial:
+; CHECK-NEXT:   %polly.access.A = getelementptr double, double* %A, i64 0
+; CHECK-NEXT:   store double 4.200000e+01, double* %polly.access.A, !alias.scope !0, !noalias !2
+; CHECK-NEXT:   br label %polly.stmt.body.cont
+
+; CHECK:      polly.stmt.body.cont:
diff --git a/final/test/Isl/CodeGen/partial_write_array___%for---%return.jscop b/final/test/Isl/CodeGen/partial_write_array___%for---%return.jscop
new file mode 100644
index 0000000..a0472bc
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_array___%for---%return.jscop
@@ -0,0 +1,24 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_array___%for---%return.jscop.transformed b/final/test/Isl/CodeGen/partial_write_array___%for---%return.jscop.transformed
new file mode 100644
index 0000000..59a76cb
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_array___%for---%return.jscop.transformed
@@ -0,0 +1,24 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[j] -> MemRef_A[0] : j >= 5 }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_emptyset.ll b/final/test/Isl/CodeGen/partial_write_emptyset.ll
new file mode 100644
index 0000000..4624976
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_emptyset.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -S < %s | FileCheck %s
+;
+; Partial write, where "partial" is the empty set.
+; The store is never executed in this case and we do generate it in the
+; first place.
+;
+; for (int j = 0; j < n; j += 1)
+;   A[0] = 42.0
+;
+
+define void @partial_write_emptyset(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK-LABEL: polly.stmt.body:
+; CHECK-NOT:     store
diff --git a/final/test/Isl/CodeGen/partial_write_emptyset___%for---%return.jscop b/final/test/Isl/CodeGen/partial_write_emptyset___%for---%return.jscop
new file mode 100644
index 0000000..a0472bc
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_emptyset___%for---%return.jscop
@@ -0,0 +1,24 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_emptyset___%for---%return.jscop.transformed b/final/test/Isl/CodeGen/partial_write_emptyset___%for---%return.jscop.transformed
new file mode 100644
index 0000000..8f7f2a0
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_emptyset___%for---%return.jscop.transformed
@@ -0,0 +1,24 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[j] -> MemRef_A[0] : 1 = 0 }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_full_write_that_appears_partial.ll b/final/test/Isl/CodeGen/partial_write_full_write_that_appears_partial.ll
new file mode 100644
index 0000000..9df38ff
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_full_write_that_appears_partial.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+
+; CHECK:      polly.stmt.if.then81:                             ; preds = %polly.stmt.if.end75
+; CHECK-NEXT:   %scevgep = getelementptr [2 x %S], [2 x %S]* %tmp, i64 0, i64 %.147
+; CHECK-NEXT:   %scevgep1 = bitcast %S* %scevgep to float*
+; CHECK-NEXT:   store float undef, float* %scevgep1, align 4, !alias.scope !0, !noalias !2
+; CHECK-NEXT:   br label %polly.stmt.if.end87.region_exiting
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64--linux-android"
+
+%S = type { float, float }
+
+define void @f() {
+entry:
+  %tmp = alloca [2 x %S], align 4
+  %cmp52 = fcmp olt float undef, undef
+  %not.cmp52 = xor i1 %cmp52, true
+  %.147 = zext i1 %not.cmp52 to i64
+  %fX64 = getelementptr inbounds [2 x %S], [2 x %S]* %tmp, i64 0, i64 %.147, i32 0
+  br label %if.end75
+
+if.end75:
+  %cmp80 = fcmp olt float undef, undef
+  br i1 %cmp80, label %if.then81, label %if.end87
+
+if.then81:
+  store float undef, float* %fX64, align 4
+  br label %if.end87
+
+if.end87:
+  %0 = phi float [ undef, %if.then81 ], [ undef, %if.end75 ]
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/partial_write_impossible_restriction.ll b/final/test/Isl/CodeGen/partial_write_impossible_restriction.ll
new file mode 100644
index 0000000..2819b31
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_impossible_restriction.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -S < %s | FileCheck %s
+;
+; The isl scheduler isolates %cond.false into two instances.
+; A partial write access in one of the instances was never executed,
+; which caused problems when querying for its index expression, which
+; is not available in that case.
+;
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+
+define void @partial_write_impossible_restriction() {
+entry:
+  br i1 undef, label %invoke.cont258, label %cond.true.i.i.i.i1007
+
+cond.true.i.i.i.i1007:
+  br label %invoke.cont258
+
+invoke.cont258:
+  %.pn = phi i32* [ null, %cond.true.i.i.i.i1007 ], [ null, %entry ]
+  br label %invoke.cont274
+
+invoke.cont274:                                   ; preds = %invoke.cont258
+  %tmp4 = load i32*, i32** undef
+  %tmp5 = load i32, i32* undef
+  %tmp6 = zext i32 %tmp5 to i64
+  %tmp7 = sext i32 %tmp5 to i64
+  br label %for.body344
+
+for.body344:                                      ; preds = %cond.end, %invoke.cont274
+  %indvars.iv1602 = phi i64 [ 0, %invoke.cont274 ], [ %indvars.iv.next1603, %cond.end ]
+  %indvars.iv.next1603 = add nuw nsw i64 %indvars.iv1602, 1
+  %cmp347 = icmp eq i64 %indvars.iv.next1603, %tmp6
+  br i1 %cmp347, label %cond.end, label %cond.false
+
+cond.false:                                       ; preds = %for.body344
+  %add.ptr.i1128 = getelementptr inbounds i32, i32* %tmp4, i64 %indvars.iv.next1603
+  %cond.in.sroa.speculate.load.cond.false = load i32, i32* %add.ptr.i1128
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %for.body344
+  %cond.in.sroa.speculated = phi i32 [ %cond.in.sroa.speculate.load.cond.false, %cond.false ], [ undef, %for.body344 ]
+  %add.ptr.i1132 = getelementptr inbounds i32, i32* %.pn, i64 %indvars.iv1602
+  store i32 undef, i32* %add.ptr.i1132
+  %cmp342 = icmp slt i64 %indvars.iv.next1603, %tmp7
+  br i1 %cmp342, label %for.body344, label %if.then.i.i1141.loopexit
+
+if.then.i.i1141.loopexit:                         ; preds = %cond.end
+  ret void
+}
+
+
+; CHECK-LABEL: polly.stmt.cond.false:
+; CHECK:         %polly.access..pn2 = getelementptr i32, i32* %.pn, i64 %polly.indvar
+; CHECK:         store i32 %cond.in.sroa.speculate.load.cond.false_p_scalar_, i32* %polly.access..pn2, !alias.scope !0, !noalias !2
+; CHECK:         br label %polly.merge
+
+; CHECK-LABEL: polly.stmt.cond.false11:
+; CHECK:         %polly.access..pn14 = getelementptr i32, i32* %.pn, i64 0
+; CHECK:         store i32 %cond.in.sroa.speculate.load.cond.false_p_scalar_13, i32* %polly.access..pn14, !alias.scope !0, !noalias !2
+; CHECK:         br label %polly.stmt.cond.end15
diff --git a/final/test/Isl/CodeGen/partial_write_impossible_restriction___%for.body344---%if.then.i.i1141.loopexit.jscop b/final/test/Isl/CodeGen/partial_write_impossible_restriction___%for.body344---%if.then.i.i1141.loopexit.jscop
new file mode 100644
index 0000000..e4f6e7f
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_impossible_restriction___%for.body344---%if.then.i.i1141.loopexit.jscop
@@ -0,0 +1,59 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_tmp4",
+         "sizes" : [ "*" ],
+         "type" : "i32"
+      },
+      {
+         "name" : "MemRef__pn",
+         "sizes" : [ "*" ],
+         "type" : "i32"
+      }
+   ],
+   "context" : "[tmp5] -> {  : -2147483648 <= tmp5 <= 2147483647 }",
+   "name" : "%for.body344---%if.then.i.i1141.loopexit",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[tmp5] -> { Stmt_for_body344[i0] -> MemRef_cond_in_sroa_speculated__phi[] }"
+            }
+         ],
+         "domain" : "[tmp5] -> { Stmt_for_body344[i0] : 0 <= i0 < tmp5; Stmt_for_body344[0] : tmp5 <= 0 }",
+         "name" : "Stmt_for_body344",
+         "schedule" : "[tmp5] -> { Stmt_for_body344[i0] -> [i0, 0] : i0 < tmp5; Stmt_for_body344[0] -> [0, 0] : tmp5 <= 0 }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[tmp5] -> { Stmt_cond_false[i0] -> MemRef_tmp4[1 + i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[tmp5] -> { Stmt_cond_false[i0] -> MemRef_cond_in_sroa_speculated__phi[] }"
+            }
+         ],
+         "domain" : "[tmp5] -> { Stmt_cond_false[i0] : 0 <= i0 <= -2 + tmp5; Stmt_cond_false[0] : tmp5 <= 0 }",
+         "name" : "Stmt_cond_false",
+         "schedule" : "[tmp5] -> { Stmt_cond_false[i0] -> [i0, 1] : i0 <= -2 + tmp5; Stmt_cond_false[0] -> [0, 1] : tmp5 <= 0 }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[tmp5] -> { Stmt_cond_end[i0] -> MemRef_cond_in_sroa_speculated__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[tmp5] -> { Stmt_cond_end[i0] -> MemRef__pn[i0] }"
+            }
+         ],
+         "domain" : "[tmp5] -> { Stmt_cond_end[i0] : 0 <= i0 < tmp5; Stmt_cond_end[0] : tmp5 <= 0 }",
+         "name" : "Stmt_cond_end",
+         "schedule" : "[tmp5] -> { Stmt_cond_end[i0] -> [i0, 2] : i0 < tmp5; Stmt_cond_end[0] -> [0, 2] : tmp5 <= 0 }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_impossible_restriction___%for.body344---%if.then.i.i1141.loopexit.jscop.transformed b/final/test/Isl/CodeGen/partial_write_impossible_restriction___%for.body344---%if.then.i.i1141.loopexit.jscop.transformed
new file mode 100644
index 0000000..c0a6f13
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_impossible_restriction___%for.body344---%if.then.i.i1141.loopexit.jscop.transformed
@@ -0,0 +1,59 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_tmp4",
+         "sizes" : [ "*" ],
+         "type" : "i32"
+      },
+      {
+         "name" : "MemRef__pn",
+         "sizes" : [ "*" ],
+         "type" : "i32"
+      }
+   ],
+   "context" : "[tmp5] -> {  : -2147483648 <= tmp5 <= 2147483647 }",
+   "name" : "%for.body344---%if.then.i.i1141.loopexit",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[tmp5] -> { Stmt_for_body344[-1 + tmp5] -> MemRef__pn[-1 + tmp5] }"
+            }
+         ],
+         "domain" : "[tmp5] -> { Stmt_for_body344[i0] : 0 <= i0 < tmp5; Stmt_for_body344[0] : tmp5 <= 0 }",
+         "name" : "Stmt_for_body344",
+         "schedule" : "[tmp5] -> { Stmt_for_body344[i0] -> [i0, 0] : i0 < tmp5; Stmt_for_body344[0] -> [0, 0] : tmp5 <= 0 }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[tmp5] -> { Stmt_cond_false[i0] -> MemRef_tmp4[1 + i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[tmp5] -> { Stmt_cond_false[i0] -> MemRef__pn[i0] : i0 <= -2 + tmp5; Stmt_cond_false[0] -> MemRef__pn[0] : tmp5 <= 0 }"
+            }
+         ],
+         "domain" : "[tmp5] -> { Stmt_cond_false[i0] : 0 <= i0 <= -2 + tmp5; Stmt_cond_false[0] : tmp5 <= 0 }",
+         "name" : "Stmt_cond_false",
+         "schedule" : "[tmp5] -> { Stmt_cond_false[i0] -> [i0, 1] : i0 <= -2 + tmp5; Stmt_cond_false[0] -> [0, 1] : tmp5 <= 0 }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[tmp5] -> { Stmt_cond_end[i0] -> MemRef__pn[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[tmp5] -> { Stmt_cond_end[i0] -> MemRef__pn[i0] }"
+            }
+         ],
+         "domain" : "[tmp5] -> { Stmt_cond_end[i0] : 0 <= i0 < tmp5; Stmt_cond_end[0] : tmp5 <= 0 }",
+         "name" : "Stmt_cond_end",
+         "schedule" : "[tmp5] -> { Stmt_cond_end[i0] -> [i0, 2] : i0 < tmp5; Stmt_cond_end[0] -> [0, 2] : tmp5 <= 0 }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_in_region.ll b/final/test/Isl/CodeGen/partial_write_in_region.ll
new file mode 100644
index 0000000..d93226d
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_in_region.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN: -polly-import-jscop-postfix=transformed -polly-codegen \
+; RUN: -verify-dom-info \
+; RUN: -S < %s | FileCheck %s
+;
+;    void foo(long A[], float B[], float C[]) {
+;      for (long i = 0; i < 1024; i++) {
+;        if (A[i]) {
+; S:         B[i]++;
+; T:         C[42] = 1;
+;        }
+;      }
+;    }
+
+; CHECK: polly.stmt.bb5:                                   ; preds = %polly.stmt.bb2
+; CHECK-NEXT:   %scevgep10 = getelementptr float, float* %B, i64 %polly.indvar
+; CHECK-NEXT:   %tmp7_p_scalar_ = load float, float* %scevgep10
+; CHECK-NEXT:   %p_tmp8 = fadd float %tmp7_p_scalar_, 1.000000e+00
+; CHECK-NEXT:   %24 = icmp sle i64 %polly.indvar, 9
+; CHECK-NEXT:   %polly.Stmt_bb2__TO__bb9_MayWrite2.cond = icmp ne i1 %24, false
+; CHECK-NEXT:   br i1 %polly.Stmt_bb2__TO__bb9_MayWrite2.cond, label %polly.stmt.bb5.Stmt_bb2__TO__bb9_MayWrite2.partial, label %polly.stmt.bb5.cont
+
+; CHECK: polly.stmt.bb5.Stmt_bb2__TO__bb9_MayWrite2.partial: ; preds = %polly.stmt.bb5
+; CHECK-NEXT:   %polly.access.B11 = getelementptr float, float* %B, i64 %polly.indvar
+; CHECK-NEXT:   store float %p_tmp8, float* %polly.access.B11
+; CHECK-NEXT:   br label %polly.stmt.bb5.cont
+
+; CHECK: polly.stmt.bb5.cont:                              ; preds = %polly.stmt.bb5, %polly.stmt.bb5.Stmt_bb2__TO__bb9_MayWrite2.partial
+; CHECK-NEXT:   br label %polly.stmt.bb9b
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @partial_write_in_region(i64* %A, float* %B, float* %C) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb10, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp11, %bb10 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb12
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i64, i64* %A, i64 %i.0
+  %tmp3 = load i64, i64* %tmp, align 8
+  %tmp4 = icmp eq i64 %tmp3, 0
+  br i1 %tmp4, label %bb9, label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = getelementptr inbounds float, float* %B, i64 %i.0
+  %tmp7 = load float, float* %tmp6, align 4
+  %tmp8 = fadd float %tmp7, 1.000000e+00
+  store float %tmp8, float* %tmp6, align 4
+  br label %bb9b
+
+bb9b:
+  store float 42.0, float* %C
+  br label %bb9
+
+bb9:                                              ; preds = %bb2, %bb5
+  br label %bb10
+
+bb10:                                             ; preds = %bb9
+  %tmp11 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb12:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/partial_write_in_region___%bb1---%bb12.jscop b/final/test/Isl/CodeGen/partial_write_in_region___%bb1---%bb12.jscop
new file mode 100644
index 0000000..0198054
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_in_region___%bb1---%bb12.jscop
@@ -0,0 +1,46 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "i64"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb1---%bb12",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_B[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_B[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_C[0] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb2__TO__bb9[i0] : 0 <= i0 <= 1023 }",
+         "name" : "Stmt_bb2__TO__bb9",
+         "schedule" : "{ Stmt_bb2__TO__bb9[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_in_region___%bb1---%bb12.jscop.transformed b/final/test/Isl/CodeGen/partial_write_in_region___%bb1---%bb12.jscop.transformed
new file mode 100644
index 0000000..7b6ee97
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_in_region___%bb1---%bb12.jscop.transformed
@@ -0,0 +1,46 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "i64"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb1---%bb12",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_B[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_B[i0] : i0 < 10}"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb2__TO__bb9[i0] -> MemRef_C[0] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb2__TO__bb9[i0] : 0 <= i0 <= 1023 }",
+         "name" : "Stmt_bb2__TO__bb9",
+         "schedule" : "{ Stmt_bb2__TO__bb9[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_in_region_with_loop.ll b/final/test/Isl/CodeGen/partial_write_in_region_with_loop.ll
new file mode 100644
index 0000000..6b2f91a
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_in_region_with_loop.ll
@@ -0,0 +1,87 @@
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN: -polly-import-jscop-postfix=transformed -polly-codegen \
+; RUN: -verify-dom-info -polly-allow-nonaffine-loops \
+; RUN: -S < %s | FileCheck %s
+
+; This test verifies that partial writes within non-affine loops are code
+; generated correctly.
+
+; CHECK:polly.stmt.bb3:
+; CHECK-NEXT:  %polly.subregion.iv = phi i32 [ %polly.subregion.iv.inc, %polly.stmt.bb5.cont ], [ 0, %polly.stmt.bb3.entry ]
+; CHECK-NEXT:  %polly.j.0 = phi i64 [ %j.0.phiops.reload, %polly.stmt.bb3.entry ], [ %p_tmp10, %polly.stmt.bb5.cont ]
+; CHECK-NEXT:  %8 = zext i64 %polly.indvar to i65
+; CHECK-NEXT:  %9 = add i64 %polly.indvar, -1
+; CHECK-NEXT:  %10 = zext i64 %9 to i65
+; CHECK-NEXT:  %11 = mul i65 %8, %10
+; CHECK-NEXT:  %12 = lshr i65 %11, 1
+; CHECK-NEXT:  %13 = trunc i65 %12 to i64
+; CHECK-NEXT:  %14 = shl i64 %13, 1
+; CHECK-NEXT:  %15 = add i64 %polly.indvar, %14
+; CHECK-NEXT:  %p_tmp4 = icmp slt i64 %polly.j.0, %15
+; CHECK-NEXT:  %polly.subregion.iv.inc = add i32 %polly.subregion.iv, 1
+; CHECK-NEXT:  br i1 %p_tmp4, label %polly.stmt.bb5, label %polly.stmt.bb11.exit
+
+; CHECK:polly.stmt.bb5:
+; CHECK-NEXT:  %p_tmp6 = getelementptr inbounds float, float* %B, i64 42
+; CHECK-NEXT:  %tmp7_p_scalar_ = load float, float* %p_tmp6
+; CHECK-NEXT:  %p_tmp8 = fadd float %tmp7_p_scalar_, 1.000000e+00
+; CHECK-NEXT:  %16 = icmp sle i64 %polly.indvar, 9
+; CHECK-NEXT:  %polly.Stmt_bb3__TO__bb11_MayWrite2.cond = icmp ne i1 %16, false
+; CHECK-NEXT:  br i1 %polly.Stmt_bb3__TO__bb11_MayWrite2.cond, label %polly.stmt.bb5.Stmt_bb3__TO__bb11_MayWrite2.partial, label %polly.stmt.bb5.cont
+
+; CHECK:polly.stmt.bb5.Stmt_bb3__TO__bb11_MayWrite2.partial: ; preds = %polly.stmt.bb5
+; CHECK-NEXT:  %polly.access.B3 = getelementptr float, float* %B, i64 42
+; CHECK-NEXT:  store float %p_tmp8, float* %polly.access.B3
+; CHECK-NEXT:  br label %polly.stmt.bb5.cont
+
+; CHECK:polly.stmt.bb5.cont:
+; CHECK-NEXT:  %p_tmp10 = add nuw nsw i64 %polly.j.0, 1
+; CHECK-NEXT:  br label %polly.stmt.bb3
+
+
+
+;    void foo(long A[], float B[], long *x) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = *x; j < i * i; j++)
+;          B[42]++;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @partial_write_in_region_with_loop(i64* %A, float* %B, i64* %xptr) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb12, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp13, %bb12 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb14
+
+bb2:                                              ; preds = %bb1
+  %x = load i64, i64* %xptr
+  br label %bb3
+
+bb3:                                              ; preds = %bb9, %bb2
+  %j.0 = phi i64 [ %x, %bb2 ], [ %tmp10, %bb5 ]
+  %tmp = mul nsw i64 %i.0, %i.0
+  %tmp4 = icmp slt i64 %j.0, %tmp
+  br i1 %tmp4, label %bb5, label %bb11
+
+bb5:                                              ; preds = %bb3
+  %tmp6 = getelementptr inbounds float, float* %B, i64 42
+  %tmp7 = load float, float* %tmp6, align 4
+  %tmp8 = fadd float %tmp7, 1.000000e+00
+  store float %tmp8, float* %tmp6, align 4
+  %tmp10 = add nuw nsw i64 %j.0, 1
+  br label %bb3
+
+bb11:                                             ; preds = %bb3
+  br label %bb12
+
+bb12:                                             ; preds = %bb11
+  %tmp13 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb14:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/partial_write_in_region_with_loop___%bb1---%bb14.jscop b/final/test/Isl/CodeGen/partial_write_in_region_with_loop___%bb1---%bb14.jscop
new file mode 100644
index 0000000..c276376
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_in_region_with_loop___%bb1---%bb14.jscop
@@ -0,0 +1,52 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_xptr",
+         "sizes" : [ "*" ],
+         "type" : "i64"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb1---%bb14",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2[i0] -> MemRef_xptr[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb2[i0] -> MemRef_j_0__phi[] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb2[i0] : 0 <= i0 <= 1023 }",
+         "name" : "Stmt_bb2",
+         "schedule" : "{ Stmt_bb2[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb3__TO__bb11[i0] -> MemRef_j_0__phi[] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb3__TO__bb11[i0] -> MemRef_B[42] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb3__TO__bb11[i0] -> MemRef_B[42] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb3__TO__bb11[i0] : 0 <= i0 <= 1023 }",
+         "name" : "Stmt_bb3__TO__bb11",
+         "schedule" : "{ Stmt_bb3__TO__bb11[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_in_region_with_loop___%bb1---%bb14.jscop.transformed b/final/test/Isl/CodeGen/partial_write_in_region_with_loop___%bb1---%bb14.jscop.transformed
new file mode 100644
index 0000000..d9424cc
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_in_region_with_loop___%bb1---%bb14.jscop.transformed
@@ -0,0 +1,52 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_xptr",
+         "sizes" : [ "*" ],
+         "type" : "i64"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb1---%bb14",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb2[i0] -> MemRef_xptr[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb2[i0] -> MemRef_j_0__phi[] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb2[i0] : 0 <= i0 <= 1023 }",
+         "name" : "Stmt_bb2",
+         "schedule" : "{ Stmt_bb2[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb3__TO__bb11[i0] -> MemRef_j_0__phi[] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb3__TO__bb11[i0] -> MemRef_B[42] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb3__TO__bb11[i0] -> MemRef_B[42] : i0 < 10 }"
+            }
+         ],
+         "domain" : "{ Stmt_bb3__TO__bb11[i0] : 0 <= i0 <= 1023 }",
+         "name" : "Stmt_bb3__TO__bb11",
+         "schedule" : "{ Stmt_bb3__TO__bb11[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_mapped_scalar.ll b/final/test/Isl/CodeGen/partial_write_mapped_scalar.ll
new file mode 100644
index 0000000..53b17b2
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_mapped_scalar.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -S < %s | FileCheck %s
+;
+; Partial write of a (mapped) scalar.
+;
+; for (int j = 0; j < n; j += 1) {
+;body:
+;   val = 21.0 + 21.0;
+;   if (j >= 5)
+;user:
+;     A[0] = val;
+; }
+
+define void @partial_write_mapped_scalar(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = fadd double 21.0, 21.0
+      %if.cond = icmp sgt i32 %j, 5
+      br i1 %if.cond, label %user, label %inc
+
+    user:
+      store double %val, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      polly.stmt.body:
+; CHECK-NEXT:   %p_val = fadd double 2.100000e+01, 2.100000e+01
+; CHECK-NEXT:   %1 = trunc i64 %polly.indvar to i32
+; CHECK-NEXT:   %p_if.cond = icmp sgt i32 %1, 5
+; CHECK-NEXT:   %2 = icmp sge i64 %polly.indvar, 5
+; CHECK-NEXT:   %polly.Stmt_body_Write0.cond = icmp ne i1 %2, false
+; CHECK-NEXT:   br i1 %polly.Stmt_body_Write0.cond, label %polly.stmt.body.Stmt_body_Write0.partial, label %polly.stmt.body.cont
+
+; CHECK:      polly.stmt.body.Stmt_body_Write0.partial:
+; CHECK-NEXT:   %polly.access.A = getelementptr double, double* %A, i64 1
+; CHECK-NEXT:   store double %p_val, double* %polly.access.A
+; CHECK-NEXT:   br label %polly.stmt.body.cont
+
+; CHECK:      polly.stmt.body.cont:
+; CHECK-NEXT:   br label %polly.cond
diff --git a/final/test/Isl/CodeGen/partial_write_mapped_scalar___%for---%return.jscop b/final/test/Isl/CodeGen/partial_write_mapped_scalar___%for---%return.jscop
new file mode 100644
index 0000000..87b05b3
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_mapped_scalar___%for---%return.jscop
@@ -0,0 +1,39 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 6 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_mapped_scalar___%for---%return.jscop.transformed b/final/test/Isl/CodeGen/partial_write_mapped_scalar___%for---%return.jscop.transformed
new file mode 100644
index 0000000..6e446d7
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_mapped_scalar___%for---%return.jscop.transformed
@@ -0,0 +1,39 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[j] -> MemRef_A[1] : j >= 5 }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[j] -> MemRef_A[1] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 6 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_mapped_scalar_subregion.ll b/final/test/Isl/CodeGen/partial_write_mapped_scalar_subregion.ll
new file mode 100644
index 0000000..0d41046
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_mapped_scalar_subregion.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -S < %s | FileCheck %s
+;
+; Partial write of a (mapped) scalar in a non-affine subregion.
+;
+; for (int j = 0; j < n; j += 1) {
+;subregion:
+;   val = 21.0 + 21.0;
+;   if (undef > undef)
+;subregion_true: ;
+;
+;subregion_exit:
+;   if (j >= 5)
+;user:
+;     A[0] = val;
+; }
+
+define void @partial_write_mapped_scalar_subregion(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %subregion, label %exit
+
+    subregion:
+      %val = fadd double 21.0, 21.0
+      %nonaffine.cond = fcmp ogt double undef, undef
+      br i1 %nonaffine.cond, label %subregion_true, label %subregion_exit
+
+    subregion_true:
+      br label %subregion_exit
+
+    subregion_exit:
+      %if.cond = icmp sgt i32 %j, 5
+      br i1 %if.cond, label %user, label %inc
+
+    user:
+      store double %val, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK-LABEL: polly.stmt.subregion_exit.exit:
+; CHECK-NEXT:    %1 = icmp sge i64 %polly.indvar, 5
+; CHECK-NEXT:    %polly.Stmt_subregion__TO__subregion_exit_Write0.cond = icmp ne i1 %1, false
+; CHECK-NEXT:    br i1 %polly.Stmt_subregion__TO__subregion_exit_Write0.cond, label %polly.stmt.subregion_exit.exit.Stmt_subregion__TO__subregion_exit_Write0.partial, label %polly.stmt.subregion_exit.exit.cont
+
+; CHECK-LABEL: polly.stmt.subregion_exit.exit.Stmt_subregion__TO__subregion_exit_Write0.partial:
+; CHECK-NEXT:    %polly.access.A = getelementptr double, double* %A, i64 1
+; CHECK-NEXT:    store double %p_val, double* %polly.access.A
+; CHECK-NEXT:    br label %polly.stmt.subregion_exit.exit.cont
+
+; CHECK-LABEL: polly.stmt.subregion_exit.exit.cont:
diff --git a/final/test/Isl/CodeGen/partial_write_mapped_scalar_subregion___%for---%return.jscop b/final/test/Isl/CodeGen/partial_write_mapped_scalar_subregion___%for---%return.jscop
new file mode 100644
index 0000000..9c0b684
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_mapped_scalar_subregion___%for---%return.jscop
@@ -0,0 +1,39 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body__TO__subregion_exit[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body__TO__subregion_exit[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body__TO__subregion_exit",
+         "schedule" : "[n] -> { Stmt_body__TO__subregion_exit[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 6 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_mapped_scalar_subregion___%for---%return.jscop.transformed b/final/test/Isl/CodeGen/partial_write_mapped_scalar_subregion___%for---%return.jscop.transformed
new file mode 100644
index 0000000..e76755d
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_mapped_scalar_subregion___%for---%return.jscop.transformed
@@ -0,0 +1,39 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body__TO__subregion_exit[j] -> MemRef_A[1] : j >= 5 }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body__TO__subregion_exit[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body__TO__subregion_exit",
+         "schedule" : "[n] -> { Stmt_body__TO__subregion_exit[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[1] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 6 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_mapped_vector.ll b/final/test/Isl/CodeGen/partial_write_mapped_vector.ll
new file mode 100644
index 0000000..cfb21ca
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_mapped_vector.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -basicaa -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-vectorizer=polly -polly-opt-isl -polly-ast -polly-codegen -S < %s | FileCheck %s
+;
+; Polly's vectorizer does not support partial accesses.
+;
+; for (int j = 0; j < 4; j += 1) {
+;body:
+;   val = 21.0 + 21.0;
+;   if (j > 1)
+;user:
+;     A[0] = val;
+; }
+
+define void @partial_write_mapped_vector(double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, 4
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = fadd double 21.0, 21.0
+      %if.cond = icmp sgt i32 %j, 1
+      br i1 %if.cond, label %user, label %inc
+
+    user:
+      %elt= getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %elt
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK-LABEL: polly.stmt.body:
+; CHECK-NEXT:    %p_val = fadd double 2.100000e+01, 2.100000e+01
+; CHECK-NEXT:    %0 = trunc i64 %polly.indvar to i32
+; CHECK-NEXT:    %p_if.cond = icmp sgt i32 %0, 1
+; CHECK-NEXT:    %1 = icmp sge i64 %polly.indvar, 2
+; CHECK-NEXT:    %polly.Stmt_body_Write0.cond = icmp ne i1 %1, false
+; CHECK-NEXT:    br i1 %polly.Stmt_body_Write0.cond, label %polly.stmt.body.Stmt_body_Write0.partial, label %polly.stmt.body.cont
+
+; CHECK-LABEL:  polly.stmt.body.Stmt_body_Write0.partial:
+; CHECK-NEXT:    %polly.access.A = getelementptr double, double* %A, i64 1
+; CHECK-NEXT:    store double %p_val, double* %polly.access.A
+; CHECK-NEXT:    br label %polly.stmt.body.cont
+
+; CHECK-LABEL:  polly.stmt.body.cont:
diff --git a/final/test/Isl/CodeGen/partial_write_mapped_vector___%for---%return.jscop b/final/test/Isl/CodeGen/partial_write_mapped_vector___%for---%return.jscop
new file mode 100644
index 0000000..2aadaf1
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_mapped_vector___%for---%return.jscop
@@ -0,0 +1,39 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_body[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "{ Stmt_body[i0] : 0 <= i0 <= 3 }",
+         "name" : "Stmt_body",
+         "schedule" : "{ Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_user[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_user[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "{ Stmt_user[i0] : 2 <= i0 <= 3 }",
+         "name" : "Stmt_user",
+         "schedule" : "{ Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/partial_write_mapped_vector___%for---%return.jscop.transformed b/final/test/Isl/CodeGen/partial_write_mapped_vector___%for---%return.jscop.transformed
new file mode 100644
index 0000000..39f97f0
--- /dev/null
+++ b/final/test/Isl/CodeGen/partial_write_mapped_vector___%for---%return.jscop.transformed
@@ -0,0 +1,39 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_body[j] -> MemRef_A[1] : j > 1 }"
+            }
+         ],
+         "domain" : "{ Stmt_body[i0] : 0 <= i0 <= 3 }",
+         "name" : "Stmt_body",
+         "schedule" : "{ Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_user[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_user[j] -> MemRef_A[1] }"
+            }
+         ],
+         "domain" : "{ Stmt_user[i0] : 2 <= i0 <= 3 }",
+         "name" : "Stmt_user",
+         "schedule" : "{ Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Isl/CodeGen/perf_monitoring.ll b/final/test/Isl/CodeGen/perf_monitoring.ll
new file mode 100644
index 0000000..b63958b
--- /dev/null
+++ b/final/test/Isl/CodeGen/perf_monitoring.ll
@@ -0,0 +1,84 @@
+; RUN: opt %loadPolly -polly-codegen -polly-codegen-perf-monitoring \
+; RUN:   -S < %s | FileCheck %s
+
+; void f(long A[], long N) {
+;   long i;
+;   if (true)
+;     for (i = 0; i < N; ++i)
+;       A[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br label %next
+
+next:
+  br i1 true, label %for.i, label %return
+
+for.i:
+  %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK:      @__polly_perf_cycles_total_start = weak thread_local(initialexec) constant i64 0
+; CHECK-NEXT: @__polly_perf_initialized = weak thread_local(initialexec) constant i1 false
+; CHECK-NEXT: @__polly_perf_cycles_in_scops = weak thread_local(initialexec) constant i64 0
+; CHECK-NEXT: @__polly_perf_cycles_in_scop_start = weak thread_local(initialexec) constant i64 0
+; CHECK-NEXT: @__polly_perf_write_loation = weak thread_local(initialexec) constant i32 0
+
+; CHECK:      polly.split_new_and_old:                          ; preds = %entry
+; CHECK-NEXT:   %0 = call i64 @llvm.x86.rdtscp(i8* bitcast (i32* @__polly_perf_write_loation to i8*))
+; CHECK-NEXT:   store volatile i64 %0, i64* @__polly_perf_cycles_in_scop_start
+
+; CHECK:      polly.merge_new_and_old:                          ; preds = %polly.exiting, %return.region_exiting
+; CHECK-NEXT:   %5 = load volatile i64, i64* @__polly_perf_cycles_in_scop_start
+; CHECK-NEXT:   %6 = call i64 @llvm.x86.rdtscp(i8* bitcast (i32* @__polly_perf_write_loation to i8*))
+; CHECK-NEXT:   %7 = sub i64 %6, %5
+; CHECK-NEXT:   %8 = load volatile i64, i64* @__polly_perf_cycles_in_scops
+; CHECK-NEXT:   %9 = add i64 %8, %7
+; CHECK-NEXT:   store volatile i64 %9, i64* @__polly_perf_cycles_in_scops
+
+
+; CHECK:      define weak_odr void @__polly_perf_final() {
+; CHECK-NEXT: start:
+; CHECK-NEXT:   %0 = call i64 @llvm.x86.rdtscp(i8* bitcast (i32* @__polly_perf_write_loation to i8*))
+; CHECK-NEXT:   %1 = load volatile i64, i64* @__polly_perf_cycles_total_start
+; CHECK-NEXT:   %2 = sub i64 %0, %1
+; CHECK-NEXT:   %3 = load volatile i64, i64* @__polly_perf_cycles_in_scops
+; CHECK-NEXT:   %4 = call i32 (...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @1, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([27 x i8], [27 x i8] addrspace(4)* @0, i32 0, i32 0))
+; CHECK-NEXT:   %5 = call i32 @fflush(i8* null)
+; CHECK-NEXT:   %6 = call i32 (...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @3, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([27 x i8], [27 x i8] addrspace(4)* @2, i32 0, i32 0))
+; CHECK-NEXT:   %7 = call i32 @fflush(i8* null)
+; CHECK-NEXT:   %8 = call i32 (...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @6, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([8 x i8], [8 x i8] addrspace(4)* @4, i32 0, i32 0), i64 %2, i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* @5, i32 0, i32 0))
+; CHECK-NEXT:   %9 = call i32 @fflush(i8* null)
+; CHECK-NEXT:   %10 = call i32 (...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @9, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([8 x i8], [8 x i8] addrspace(4)* @7, i32 0, i32 0), i64 %3, i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* @8, i32 0, i32 0))
+; CHECK-NEXT:   %11 = call i32 @fflush(i8* null)
+
+
+; CHECK:      define weak_odr void @__polly_perf_init() {
+; CHECK-NEXT: start:
+; CHECK-NEXT:   %0 = load i1, i1* @__polly_perf_initialized
+; CHECK-NEXT:   br i1 %0, label %earlyreturn, label %initbb
+
+; CHECK:      earlyreturn:                                      ; preds = %start
+; CHECK-NEXT:   ret void
+
+; CHECK:      initbb:                                           ; preds = %start
+; CHECK-NEXT:   store i1 true, i1* @__polly_perf_initialized
+; CHECK-NEXT:   %1 = call i32 @atexit(i8* bitcast (void ()* @__polly_perf_final to i8*))
+; CHECK-NEXT:   %2 = call i64 @llvm.x86.rdtscp(i8* bitcast (i32* @__polly_perf_write_loation to i8*))
+; CHECK-NEXT:   store volatile i64 %2, i64* @__polly_perf_cycles_total_start
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
diff --git a/final/test/Isl/CodeGen/perf_monitoring_cycles_per_scop.ll b/final/test/Isl/CodeGen/perf_monitoring_cycles_per_scop.ll
new file mode 100644
index 0000000..6aec10c
--- /dev/null
+++ b/final/test/Isl/CodeGen/perf_monitoring_cycles_per_scop.ll
@@ -0,0 +1,75 @@
+; RUN: opt %loadPolly -polly-codegen -polly-codegen-perf-monitoring \
+; RUN:   -S < %s | FileCheck %s
+
+; void f(long A[], long N) {
+;   long i;
+;   if (true)
+;     for (i = 0; i < N; ++i)
+;       A[i] = i;
+; }
+; void g(long A[], long N) {
+;   long i;
+;   if (true)
+;     for (i = 0; i < N; ++i)
+;       A[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br label %next
+
+next:
+  br i1 true, label %for.i, label %return
+
+for.i:
+  %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+
+define void @g(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br label %next
+
+next:
+  br i1 true, label %for.i, label %return
+
+for.i:
+  %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; Declaration of globals - Check for cycles declaration.
+; @"__polly_perf_in_f_from__%next__to__%polly.merge_new_and_old_cycles" = weak thread_local(initialexec) constant i64 0
+; @"__polly_perf_in_g_from__%next__to__%polly.merge_new_and_old_cycles" = weak thread_local(initialexec) constant i64 0
+
+; Bumping up number of cycles in f
+; CHECK:      %10 = load volatile i64, i64* @"__polly_perf_in_f_from__%next__to__%polly.merge_new_and_old_cycles"
+; CHECK-NEXT: %11 = add i64 %10, %7
+; CHECK-NEXT: store volatile i64 %11, i64* @"__polly_perf_in_f_from__%next__to__%polly.merge_new_and_old_cycles"
+
+; Bumping up number of cycles in g
+; CHECK:      %10 = load volatile i64, i64* @"__polly_perf_in_g_from__%next__to__%polly.merge_new_and_old_cycles"
+; CHECK-NEXT: %11 = add i64 %10, %7
+; CHECK-NEXT: store volatile i64 %11, i64* @"__polly_perf_in_g_from__%next__to__%polly.merge_new_and_old_cycles"
diff --git a/final/test/Isl/CodeGen/perf_monitoring_trip_counts_per_scop.ll b/final/test/Isl/CodeGen/perf_monitoring_trip_counts_per_scop.ll
new file mode 100644
index 0000000..c751913
--- /dev/null
+++ b/final/test/Isl/CodeGen/perf_monitoring_trip_counts_per_scop.ll
@@ -0,0 +1,75 @@
+; RUN: opt %loadPolly -polly-codegen -polly-codegen-perf-monitoring \
+; RUN:   -S < %s | FileCheck %s
+
+; void f(long A[], long N) {
+;   long i;
+;   if (true)
+;     for (i = 0; i < N; ++i)
+;       A[i] = i;
+; }
+; void g(long A[], long N) {
+;   long i;
+;   if (true)
+;     for (i = 0; i < N; ++i)
+;       A[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br label %next
+
+next:
+  br i1 true, label %for.i, label %return
+
+for.i:
+  %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+
+define void @g(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br label %next
+
+next:
+  br i1 true, label %for.i, label %return
+
+for.i:
+  %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; Declaration of globals - Check for cycles declaration.
+; CHECK: @"__polly_perf_in_f_from__%next__to__%polly.merge_new_and_old_trip_count" = weak thread_local(initialexec) constant i64 0
+; CHECK: @"__polly_perf_in_g_from__%next__to__%polly.merge_new_and_old_trip_count" = weak thread_local(initialexec) constant i64 0
+
+; Bumping up number of cycles in f
+; CHECK:        %12 = load volatile i64, i64* @"__polly_perf_in_f_from__%next__to__%polly.merge_new_and_old_trip_count"
+; CHECK-NEXT:   %13 = add i64 %12, 1
+; CHECK-NEXT:   store volatile i64 %13, i64* @"__polly_perf_in_f_from__%next__to__%polly.merge_new_and_old_trip_count"
+
+; Bumping up number of cycles in g
+; CHECK:       %12 = load volatile i64, i64* @"__polly_perf_in_g_from__%next__to__%polly.merge_new_and_old_trip_count"
+; CHECK-NEXT:  %13 = add i64 %12, 1
+; CHECK-NEXT:  store volatile i64 %13, i64* @"__polly_perf_in_g_from__%next__to__%polly.merge_new_and_old_trip_count"
diff --git a/final/test/Isl/CodeGen/phi-defined-before-scop.ll b/final/test/Isl/CodeGen/phi-defined-before-scop.ll
new file mode 100644
index 0000000..a04af64
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi-defined-before-scop.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+
+; CHECK-LABEL: polly.merge_new_and_old:
+; CHECK-NEXT: %tmp7.ph.merge = phi %struct.wibble* [ %tmp7.ph.final_reload, %polly.exiting ], [ %tmp7.ph, %bb6.region_exiting ]
+
+; CHECK-LABEL: polly.stmt.bb3:
+; CHECK-NEXT: store %struct.wibble* %tmp2, %struct.wibble** %tmp7.s2a
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.blam = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }
+%struct.wibble = type { i32, %struct.wibble*, %struct.wibble* }
+
+@global = external global %struct.blam*, align 8
+
+; Function Attrs: nounwind uwtable
+define void @wobble() #0 {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %tmp2 = phi %struct.wibble* [ %tmp7, %bb6 ], [ undef, %bb ]
+  %tmp = load %struct.blam*, %struct.blam** @global, align 8, !tbaa !1
+  br label %bb3
+
+bb3:                                              ; preds = %bb1
+  %tmp4 = getelementptr inbounds %struct.blam, %struct.blam* %tmp, i64 0, i32 1
+  br i1 false, label %bb6, label %bb5
+
+bb5:                                              ; preds = %bb3
+  br label %bb6
+
+bb6:                                              ; preds = %bb5, %bb3
+  %tmp7 = phi %struct.wibble* [ %tmp2, %bb3 ], [ undef, %bb5 ]
+  br i1 undef, label %bb8, label %bb1
+
+bb8:                                              ; preds = %bb6
+  br label %bb9
+
+bb9:                                              ; preds = %bb8
+  unreachable
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 250010) (llvm/trunk 250018)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"any pointer", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/Isl/CodeGen/phi_after_error_block_outside_of_scop.ll b/final/test/Isl/CodeGen/phi_after_error_block_outside_of_scop.ll
new file mode 100644
index 0000000..fd198ed
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_after_error_block_outside_of_scop.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+
+; Make sure code generation does not break in case an 'error block' is detected
+; outside of the scope. In this situation, we should not affect code generation.
+
+; CHECK:        polly.cond:
+; CHECK-NEXT:   ptrtoint float* %tmp8 to i64
+; CHECK-NEXT:   icmp sle i64
+; CHECK-NEXT:   ptrtoint float* %tmp8 to i64
+; CHECK-NEXT:   icmp sge i64
+; CHECK-NEXT:   or i1
+; CHECK-NEXT:   label %polly.then, label %polly.else
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare void @widget()
+
+define void @baz() {
+bb:
+  br label %bb1
+
+bb1:
+  br i1 undef, label %bb5, label %bb2
+
+bb2:
+  %tmp = call i8* @pluto()
+  %tmp4 = bitcast i8* %tmp to float*
+  br label %bb6
+
+bb5:
+  call void @widget()
+  br label %bb7
+
+bb6:
+  br label %bb7
+
+bb7:
+  %tmp8 = phi float* [ %tmp4, %bb6 ], [ null, %bb5 ]
+  br label %bb9
+
+bb9:
+  %tmp10 = icmp eq float* %tmp8, null
+  br i1 %tmp10, label %bb12, label %bb11
+
+bb11:
+  br label %bb12
+
+bb12:
+  %tmp13 = phi float* [ undef, %bb9 ], [ undef, %bb11 ]
+  ret void
+}
+
+declare i8* @pluto()
diff --git a/final/test/Isl/CodeGen/phi_condition_modeling_1.ll b/final/test/Isl/CodeGen/phi_condition_modeling_1.ll
new file mode 100644
index 0000000..92dd161
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_condition_modeling_1.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+;
+;    void f(int *A, int c, int N) {
+;      int tmp;
+;      for (int i = 0; i < N; i++) {
+;        if (i > c)
+;          tmp = 3;
+;        else
+;          tmp = 5;
+;        A[i] = tmp;
+;      }
+;    }
+;
+; CHECK-LABEL: bb:
+; CHECK:       %tmp.0.phiops = alloca i32
+; CHECK-LABEL: polly.stmt.bb8:
+; CHECK:       %tmp.0.phiops.reload = load i32, i32* %tmp.0.phiops
+; CHECK:       store i32 %tmp.0.phiops.reload, i32*
+; CHECK-LABEL: polly.stmt.bb7:
+; CHECK:       store i32 5, i32* %tmp.0.phiops
+; CHECK-LABEL: polly.stmt.bb6:
+; CHECK:       store i32 3, i32* %tmp.0.phiops
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %c, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  %tmp1 = sext i32 %c to i64
+  br label %bb2
+
+bb2:                                              ; preds = %bb10, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb10 ], [ 0, %bb ]
+  %tmp3 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp3, label %bb4, label %bb11
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = icmp sgt i64 %indvars.iv, %tmp1
+  br i1 %tmp5, label %bb6, label %bb7
+
+bb6:                                              ; preds = %bb4
+  br label %bb8
+
+bb7:                                              ; preds = %bb4
+  br label %bb8
+
+bb8:                                              ; preds = %bb7, %bb6
+  %tmp.0 = phi i32 [ 3, %bb6 ], [ 5, %bb7 ]
+  %tmp9 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp.0, i32* %tmp9, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb2
+
+bb11:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/phi_condition_modeling_2.ll b/final/test/Isl/CodeGen/phi_condition_modeling_2.ll
new file mode 100644
index 0000000..1b30e4d
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_condition_modeling_2.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -S  -polly-codegen < %s | FileCheck %s
+;
+;    void f(int *A, int c, int N) {
+;      int tmp;
+;      for (int i = 0; i < N; i++) {
+;        if (i > c)
+;          tmp = 3;
+;        else
+;          tmp = 5;
+;        A[i] = tmp;
+;      }
+;    }
+;
+; CHECK-LABEL: bb:
+; CHECK-DAG:   %tmp.0.s2a = alloca i32
+; CHECK-DAG:   %tmp.0.phiops = alloca i32
+; CHECK-LABEL: polly.stmt.bb8:
+; CHECK:       %tmp.0.phiops.reload = load i32, i32* %tmp.0.phiops
+; CHECK:       store i32 %tmp.0.phiops.reload, i32* %tmp.0.s2a
+; CHECK-LABEL: polly.stmt.bb8b:
+; CHECK:       %tmp.0.s2a.reload = load i32, i32* %tmp.0.s2a
+; CHECK:       store i32 %tmp.0.s2a.reload,
+; CHECK-LABEL: polly.stmt.bb7:
+; CHECK:       store i32 5, i32* %tmp.0.phiops
+; CHECK-LABEL: polly.stmt.bb6:
+; CHECK:       store i32 3, i32* %tmp.0.phiops
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %c, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  %tmp1 = sext i32 %c to i64
+  br label %bb2
+
+bb2:                                              ; preds = %bb10, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb10 ], [ 0, %bb ]
+  %tmp3 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp3, label %bb4, label %bb11
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = icmp sgt i64 %indvars.iv, %tmp1
+  br i1 %tmp5, label %bb6, label %bb7
+
+bb6:                                              ; preds = %bb4
+  br label %bb8
+
+bb7:                                              ; preds = %bb4
+  br label %bb8
+
+bb8:                                              ; preds = %bb7, %bb6
+  %tmp.0 = phi i32 [ 3, %bb6 ], [ 5, %bb7 ]
+  br label %bb8b
+
+bb8b:
+  %tmp9 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp.0, i32* %tmp9, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb2
+
+bb11:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/phi_conditional_simple_1.ll b/final/test/Isl/CodeGen/phi_conditional_simple_1.ll
new file mode 100644
index 0000000..88699d3
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_conditional_simple_1.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -analyze -polly-ast < %s | FileCheck %s --check-prefix=AST
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+;
+;    void jd(int *A, int c) {
+;      for (int i = 0; i < 1024; i++) {
+;        if (c)
+;          A[i] = 1;
+;        else
+;          A[i] = 2;
+;      }
+;    }
+
+; AST:    for (int c0 = 0; c0 <= 1023; c0 += 1) {
+; AST:      if (c <= -1 || c >= 1) {
+; AST:        Stmt_if_then(c0);
+; AST:      } else
+; AST:        Stmt_if_else(c0);
+; AST:      Stmt_if_end(c0);
+; AST:    }
+;
+; CHECK-LABEL:  entry:
+; CHECK-NEXT:     %phi.phiops = alloca i32
+; CHECK-LABEL:  polly.stmt.if.end:
+; CHECK-NEXT:     %phi.phiops.reload = load i32, i32* %phi.phiops
+; CHECK-NEXT:     %scevgep
+; CHECK-NEXT:     store i32 %phi.phiops.reload, i32*
+; CHECK-LABEL:  polly.stmt.if.then:
+; CHECK-NEXT:     store i32 1, i32* %phi.phiops
+; CHECK-NEXT:     br label %polly.merge{{[.]?}}
+; CHECK-LABEL:  polly.stmt.if.else:
+; CHECK-NEXT:     store i32 2, i32* %phi.phiops
+; CHECK-NEXT:     br label %polly.merge{{[.]?}}
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32 %c) {
+entry:
+  br label %for.cond
+
+for.cond:
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:
+  %tobool = icmp eq i32 %c, 0
+  br i1 %tobool, label %if.else, label %if.then
+
+if.then:
+  br label %if.end
+
+if.else:
+  br label %if.end
+
+if.end:
+  %phi = phi i32 [ 1, %if.then], [ 2, %if.else ]
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %phi, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/phi_in_exit_early_lnt_failure_1.ll b/final/test/Isl/CodeGen/phi_in_exit_early_lnt_failure_1.ll
new file mode 100644
index 0000000..549a504
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_in_exit_early_lnt_failure_1.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; This caused an lnt crash at some point, just verify it will run through.
+;
+; CHECK-LABEL: polly.merge_new_and_old:
+; CHECK-NEXT:    br label %for.body.6
+;
+; CHECK-LABEL: for.body.6:
+; CHECK-NEXT:    %i.14 = phi i32 [ undef, %for.body.6 ], [ 0, %polly.merge_new_and_old ]
+;
+@recd = external hidden global [255 x i32], align 16
+
+define void @rsdec_204(i8* %data_in) {
+entry:
+  br i1 undef, label %if.then, label %for.body
+
+if.then:                                          ; preds = %entry
+  unreachable
+
+for.body:                                         ; preds = %for.body, %entry
+  %i.05 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
+  %arrayidx = getelementptr inbounds i8, i8* %data_in, i64 0
+  %0 = load i8, i8* %arrayidx, align 1
+  %conv = zext i8 %0 to i32
+  %arrayidx2 = getelementptr inbounds [255 x i32], [255 x i32]* @recd, i64 0, i64 0
+  store i32 %conv, i32* %arrayidx2, align 4
+  %inc = add nuw nsw i32 %i.05, 1
+  br i1 false, label %for.body, label %for.body.6
+
+for.body.6:                                       ; preds = %for.body.6, %for.body
+  %i.14 = phi i32 [ undef, %for.body.6 ], [ 0, %for.body ]
+  br i1 undef, label %for.body.6, label %for.body.16
+
+for.body.16:                                      ; preds = %for.body.16, %for.body.6
+  br i1 undef, label %for.body.16, label %for.body.29
+
+for.body.29:                                      ; preds = %for.body.29, %for.body.16
+  br i1 undef, label %for.body.29, label %for.end.38
+
+for.end.38:                                       ; preds = %for.body.29
+  unreachable
+}
diff --git a/final/test/Isl/CodeGen/phi_in_exit_early_lnt_failure_2.ll b/final/test/Isl/CodeGen/phi_in_exit_early_lnt_failure_2.ll
new file mode 100644
index 0000000..939b8a7
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_in_exit_early_lnt_failure_2.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; This caused an lnt crash at some point, just verify it will run through and
+; produce the PHI node in the exit we are looking for.
+;
+; CHECK:       %eps1.addr.0.s2a = alloca double
+; CHECK-NOT:   %eps1.addr.0.ph.s2a = alloca double
+;
+; CHECK-LABEL: polly.merge_new_and_old:
+; CHECK:          %eps1.addr.0.ph.merge = phi double [ %eps1.addr.0.ph.final_reload, %polly.exiting ], [ %eps1.addr.0.ph, %if.end.47.region_exiting ]
+;
+; CHECK-LABEL: polly.start:
+; CHECK-NEXT:    store double %eps1, double* %eps1.s2a
+;
+; CHECK-LABEL: polly.exiting:
+; CHECK-NEXT:     %eps1.addr.0.ph.final_reload = load double, double* %eps1.addr.0.s2a
+;
+define void @dbisect(double* %c, double* %b, double %eps1, double* %eps2) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  store double 0.000000e+00, double* %b, align 8
+  br i1 false, label %for.inc, label %for.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  %arrayidx33 = getelementptr inbounds double, double* %c, i64 0
+  %0 = load double, double* %arrayidx33, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.then.36, %if.end
+  br i1 false, label %if.end, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %for.inc
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  %cmp45 = fcmp ugt double %eps1, 0.000000e+00
+  br i1 %cmp45, label %if.end.47, label %if.then.46
+
+if.then.46:                                       ; preds = %for.end
+  %1 = load double, double* %eps2, align 8
+  br label %if.end.47
+
+if.end.47:                                        ; preds = %if.then.46, %for.end
+  %eps1.addr.0 = phi double [ %1, %if.then.46 ], [ %eps1, %for.end ]
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/phi_in_exit_early_lnt_failure_3.ll b/final/test/Isl/CodeGen/phi_in_exit_early_lnt_failure_3.ll
new file mode 100644
index 0000000..45a765b
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_in_exit_early_lnt_failure_3.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; This caused an lnt crash at some point, just verify it will run through and
+; produce the PHI node in the exit we are looking for.
+;
+; CHECK-LABEL: polly.merge_new_and_old:
+; CHECK-NEXT:     %n2ptr.2.ph.merge = phi i8* [ %n2ptr.2.ph.final_reload, %polly.exiting ], [ %n2ptr.2.ph, %if.end.45.region_exiting ]
+;
+; CHECK-LABEL: if.end.45:
+; CHECK-NEXT:     %n2ptr.2 = phi i8* [ %add.ptr25, %entry ], [ %add.ptr25, %while.cond.preheader ], [ %n2ptr.2.ph.merge, %polly.merge_new_and_old ]
+
+%struct.bc_struct.0.2.4.6.8.15.24.27.29.32.38.46.48.92.93.94.95.97.99.100.102.105.107.111.118.119.121 = type { i32, i32, i32, i32, [1024 x i8] }
+
+; Function Attrs: nounwind uwtable
+declare %struct.bc_struct.0.2.4.6.8.15.24.27.29.32.38.46.48.92.93.94.95.97.99.100.102.105.107.111.118.119.121* @new_num() #0
+
+; Function Attrs: nounwind uwtable
+define void @_do_add(%struct.bc_struct.0.2.4.6.8.15.24.27.29.32.38.46.48.92.93.94.95.97.99.100.102.105.107.111.118.119.121* %n2) #0 {
+entry:
+  %call = tail call %struct.bc_struct.0.2.4.6.8.15.24.27.29.32.38.46.48.92.93.94.95.97.99.100.102.105.107.111.118.119.121* @new_num()
+  %0 = load i32, i32* undef, align 4
+  %add.ptr22 = getelementptr inbounds %struct.bc_struct.0.2.4.6.8.15.24.27.29.32.38.46.48.92.93.94.95.97.99.100.102.105.107.111.118.119.121, %struct.bc_struct.0.2.4.6.8.15.24.27.29.32.38.46.48.92.93.94.95.97.99.100.102.105.107.111.118.119.121* %n2, i64 0, i32 4, i64 0
+  %add.ptr24 = getelementptr inbounds i8, i8* %add.ptr22, i64 0
+  %add.ptr25 = getelementptr inbounds i8, i8* %add.ptr24, i64 -1
+  %add.ptr29 = getelementptr inbounds %struct.bc_struct.0.2.4.6.8.15.24.27.29.32.38.46.48.92.93.94.95.97.99.100.102.105.107.111.118.119.121, %struct.bc_struct.0.2.4.6.8.15.24.27.29.32.38.46.48.92.93.94.95.97.99.100.102.105.107.111.118.119.121* %call, i64 0, i32 4, i64 0
+  %add.ptr31 = getelementptr inbounds i8, i8* %add.ptr29, i64 0
+  %add.ptr32 = getelementptr inbounds i8, i8* %add.ptr31, i64 -1
+  br i1 undef, label %if.end.45, label %if.then
+
+if.then:                                          ; preds = %entry
+  br i1 undef, label %while.cond.preheader, label %while.cond.38.preheader
+
+while.cond.38.preheader:                          ; preds = %if.then
+  %cmp39.39 = icmp sgt i32 %0, 0
+  br i1 %cmp39.39, label %while.body.40.lr.ph, label %if.end.45
+
+while.body.40.lr.ph:                              ; preds = %while.cond.38.preheader
+  br label %while.body.40
+
+while.cond.preheader:                             ; preds = %if.then
+  br i1 undef, label %while.body.lr.ph, label %if.end.45
+
+while.body.lr.ph:                                 ; preds = %while.cond.preheader
+  br label %while.body
+
+while.body:                                       ; preds = %while.body, %while.body.lr.ph
+  br label %while.body
+
+while.body.40:                                    ; preds = %while.body.40, %while.body.40.lr.ph
+  %sumptr.141 = phi i8* [ %add.ptr32, %while.body.40.lr.ph ], [ %incdec.ptr42, %while.body.40 ]
+  %n2ptr.040 = phi i8* [ %add.ptr25, %while.body.40.lr.ph ], [ %incdec.ptr41, %while.body.40 ]
+  %incdec.ptr41 = getelementptr inbounds i8, i8* %n2ptr.040, i64 -1
+  %1 = load i8, i8* %n2ptr.040, align 1
+  %incdec.ptr42 = getelementptr inbounds i8, i8* %sumptr.141, i64 -1
+  store i8 %1, i8* %sumptr.141, align 1
+  br i1 false, label %while.body.40, label %while.cond.38.if.end.45.loopexit9_crit_edge
+
+while.cond.38.if.end.45.loopexit9_crit_edge:      ; preds = %while.body.40
+  br label %if.end.45
+
+if.end.45:                                        ; preds = %while.cond.38.if.end.45.loopexit9_crit_edge, %while.cond.preheader, %while.cond.38.preheader, %entry
+  %n2ptr.2 = phi i8* [ %add.ptr25, %entry ], [ %add.ptr25, %while.cond.preheader ], [ undef, %while.cond.38.if.end.45.loopexit9_crit_edge ], [ %add.ptr25, %while.cond.38.preheader ]
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/phi_in_exit_early_lnt_failure_5.ll b/final/test/Isl/CodeGen/phi_in_exit_early_lnt_failure_5.ll
new file mode 100644
index 0000000..bbf62e4
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_in_exit_early_lnt_failure_5.ll
@@ -0,0 +1,139 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; This caused an lnt crash at some point, just verify it will run through and
+; produce the PHI node in the exit we are looking for.
+;
+; CHECK-LABEL: polly.merge_new_and_old:
+; CHECK-NEXT:    %eps1.addr.0.ph.merge = phi double [ %eps1.addr.0.ph.final_reload, %polly.exiting ], [ %eps1.addr.0.ph, %if.end.47.region_exiting ]
+; CHECK-NEXT:      br label %if.end.47
+;
+; CHECK-LABEL: if.end.47:
+; CHECK-NEXT:        %eps1.addr.0 = phi double [ %eps1.addr.0.ph.merge, %polly.merge_new_and_old ]
+;
+define void @dbisect(double* %c, double* %b, double %eps1, double* %eps2) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  store double 0.000000e+00, double* %b, align 8
+  %arrayidx9 = getelementptr inbounds double, double* %c, i64 0
+  %0 = load double, double* %arrayidx9, align 8
+  br i1 false, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  br label %for.body
+
+for.body:                                         ; preds = %for.inc, %for.body.lr.ph
+  br i1 false, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  br i1 false, label %if.then.36, label %for.inc
+
+if.then.36:                                       ; preds = %if.end
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.then.36, %if.end
+  br i1 false, label %for.body, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %for.inc
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  store double undef, double* %eps2, align 8
+  %cmp45 = fcmp ugt double %eps1, 0.000000e+00
+  br i1 %cmp45, label %if.end.47, label %if.then.46
+
+if.then.46:                                       ; preds = %for.end
+  br label %if.end.47
+
+if.end.47:                                        ; preds = %if.then.46, %for.end
+  %eps1.addr.0 = phi double [ undef, %if.then.46 ], [ %eps1, %for.end ]
+  br i1 undef, label %if.then.55, label %for.cond.58.preheader
+
+for.cond.58.preheader:                            ; preds = %if.end.47
+  br i1 undef, label %for.end.68, label %for.body.61.lr.ph
+
+for.body.61.lr.ph:                                ; preds = %for.cond.58.preheader
+  br label %for.body.61
+
+if.then.55:                                       ; preds = %if.end.47
+  unreachable
+
+for.body.61:                                      ; preds = %for.body.61, %for.body.61.lr.ph
+  br i1 undef, label %for.body.61, label %for.cond.58.for.end.68_crit_edge
+
+for.cond.58.for.end.68_crit_edge:                 ; preds = %for.body.61
+  br label %for.end.68
+
+for.end.68:                                       ; preds = %for.cond.58.for.end.68_crit_edge, %for.cond.58.preheader
+  br i1 undef, label %for.end.137, label %for.cond.73.preheader.lr.ph
+
+for.cond.73.preheader.lr.ph:                      ; preds = %for.end.68
+  br label %for.cond.73.preheader
+
+for.cond.73.preheader:                            ; preds = %while.end, %for.cond.73.preheader.lr.ph
+  br i1 undef, label %for.end.87.loopexit, label %for.body.76.lr.ph
+
+for.body.76.lr.ph:                                ; preds = %for.cond.73.preheader
+  br label %for.body.76
+
+for.body.76:                                      ; preds = %for.inc.85, %for.body.76.lr.ph
+  br i1 undef, label %if.then.81, label %for.inc.85
+
+if.then.81:                                       ; preds = %for.body.76
+  br label %for.end.87
+
+for.inc.85:                                       ; preds = %for.body.76
+  br i1 undef, label %for.body.76, label %for.cond.73.for.end.87.loopexit_crit_edge
+
+for.cond.73.for.end.87.loopexit_crit_edge:        ; preds = %for.inc.85
+  br label %for.end.87.loopexit
+
+for.end.87.loopexit:                              ; preds = %for.cond.73.for.end.87.loopexit_crit_edge, %for.cond.73.preheader
+  br label %for.end.87
+
+for.end.87:                                       ; preds = %for.end.87.loopexit, %if.then.81
+  br i1 undef, label %if.then.92, label %if.end.95
+
+if.then.92:                                       ; preds = %for.end.87
+  br label %if.end.95
+
+if.end.95:                                        ; preds = %if.then.92, %for.end.87
+  br i1 undef, label %while.body.lr.ph, label %while.end
+
+while.body.lr.ph:                                 ; preds = %if.end.95
+  br label %while.body
+
+while.body:                                       ; preds = %if.end.128, %while.body.lr.ph
+  br i1 undef, label %if.then.109, label %if.end.128
+
+if.then.109:                                      ; preds = %while.body
+  br i1 undef, label %if.then.112, label %if.else
+
+if.then.112:                                      ; preds = %if.then.109
+  br label %if.end.128
+
+if.else:                                          ; preds = %if.then.109
+  br i1 undef, label %if.then.122, label %if.end.128
+
+if.then.122:                                      ; preds = %if.else
+  br label %if.end.128
+
+if.end.128:                                       ; preds = %if.then.122, %if.else, %if.then.112, %while.body
+  br i1 undef, label %while.body, label %while.cond.while.end_crit_edge
+
+while.cond.while.end_crit_edge:                   ; preds = %if.end.128
+  br label %while.end
+
+while.end:                                        ; preds = %while.cond.while.end_crit_edge, %if.end.95
+  br i1 undef, label %for.cond.73.preheader, label %for.cond.69.for.end.137_crit_edge
+
+for.cond.69.for.end.137_crit_edge:                ; preds = %while.end
+  br label %for.end.137
+
+for.end.137:                                      ; preds = %for.cond.69.for.end.137_crit_edge, %for.end.68
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/phi_loop_carried_float.ll b/final/test/Isl/CodeGen/phi_loop_carried_float.ll
new file mode 100644
index 0000000..ff86e38
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_loop_carried_float.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -S  -polly-codegen < %s | FileCheck %s
+;
+;    float f(float *A, int N) {
+;      float tmp = 0;
+;      for (int i = 0; i < N; i++)
+;        tmp += A[i];
+;    }
+;
+; CHECK:      bb:
+; CHECK-NOT:    %tmp7{{[.*]}} = alloca float
+; CHECK-DAG:    %tmp.0.s2a = alloca float
+; CHECK-NOT:    %tmp7{{[.*]}} = alloca float
+; CHECK-DAG:    %tmp.0.phiops = alloca float
+; CHECK-NOT:    %tmp7{{[.*]}} = alloca float
+
+; CHECK-LABEL: exit:
+; CHECK-NEXT:    ret
+
+; CHECK-LABEL: polly.start:
+; CHECK-NEXT:    store float 0.000000e+00, float* %tmp.0.phiops
+; CHECK-NEXT:    sext
+
+; CHECK-LABEL: polly.exiting:
+; CHECK-NEXT:    br label %polly.merge_new_and_old
+
+; CHECK-LABEL: polly.stmt.bb1{{[0-9]*}}:
+; CHECK-NEXT:    %tmp.0.phiops.reload[[R1:[0-9]*]] = load float, float* %tmp.0.phiops
+; CHECK:         store float %tmp.0.phiops.reload[[R1]], float* %tmp.0.s2a
+
+; CHECK-LABEL: polly.stmt.bb4:
+; CHECK:         %tmp.0.s2a.reload[[R3:[0-9]*]] = load float, float* %tmp.0.s2a
+; CHECK:         %tmp[[R5:[0-9]*]]_p_scalar_ = load float, float* %scevgep, align 4, !alias.scope !0, !noalias !2
+; CHECK:         %p_tmp[[R4:[0-9]*]] = fadd float %tmp.0.s2a.reload[[R3]], %tmp[[R5]]_p_scalar_
+; CHECK:         store float %p_tmp[[R4]], float* %tmp.0.phiops
+
+; CHECK-LABEL: polly.stmt.bb1{{[0-9]*}}:
+; CHECK-NEXT:    %tmp.0.phiops.reload[[R2:[0-9]*]] = load float, float* %tmp.0.phiops
+; CHECK:         store float %tmp.0.phiops.reload[[R2]], float* %tmp.0.s2a
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(float* %A, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  br label %bb1
+
+bb1:                                              ; preds = %bb4, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb4 ], [ 0, %bb ]
+  %tmp.0 = phi float [ 0.000000e+00, %bb ], [ %tmp7, %bb4 ]
+  %tmp2 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp2, label %bb3, label %bb8
+
+bb3:                                              ; preds = %bb1
+  br label %bb4
+
+bb4:                                              ; preds = %bb3
+  %tmp5 = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp6 = load float, float* %tmp5, align 4
+  %tmp7 = fadd float %tmp.0, %tmp6
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  br label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/phi_loop_carried_float_escape.ll b/final/test/Isl/CodeGen/phi_loop_carried_float_escape.ll
new file mode 100644
index 0000000..c039a0b
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_loop_carried_float_escape.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -S \
+; RUN: -polly-analyze-read-only-scalars=false -polly-codegen < %s | FileCheck %s
+
+; RUN: opt %loadPolly -S \
+; RUN: -polly-analyze-read-only-scalars=true -polly-codegen < %s | FileCheck %s
+;
+;    float f(float *A, int N) {
+;      float tmp = 0;
+;      for (int i = 0; i < N; i++)
+;        tmp += A[i];
+;      return tmp;
+;    }
+
+; CHECK-LABEL: polly.merge_new_and_old:
+; CHECK-NEXT:    %tmp.0.merge = phi float [ %tmp.0.final_reload, %polly.exiting ], [ %tmp.0, %bb8 ]
+; CHECK-NEXT:    br label %exit
+
+; CHECK-LABEL: polly.start:
+; CHECK-NEXT:    store float 0.000000e+00, float* %tmp.0.phiops
+; CHECK-NEXT:    sext
+
+; CHECK-LABEL: polly.exiting:
+; CHECK-NEXT:    %tmp.0.final_reload = load float, float* %tmp.0.s2a
+; CHECK-NEXT:    br label %polly.merge_new_and_old
+
+; CHECK-LABEL: polly.stmt.bb1{{[0-9]*}}:
+; CHECK-NEXT:    %tmp.0.phiops.reload[[R1:[0-9]*]] = load float, float* %tmp.0.phiops
+; CHECK-:        store float %tmp.0.phiops.reload[[R1]], float* %tmp.0.s2a
+
+; CHECK-LABEL: polly.stmt.bb4:
+; CHECK:         %tmp.0.s2a.reload[[R3:[0-9]*]] = load float, float* %tmp.0.s2a
+; CHECK:         %tmp[[R5:[0-9]*]]_p_scalar_ = load float, float* %scevgep, align 4, !alias.scope !0, !noalias !2
+; CHECK:         %p_tmp[[R4:[0-9]*]] = fadd float %tmp.0.s2a.reload[[R3]], %tmp[[R5]]_p_scalar_
+; CHECK:         store float %p_tmp[[R4]], float* %tmp.0.phiops
+
+; CHECK-LABEL: polly.stmt.bb1{{[0-9]*}}:
+; CHECK-NEXT:    %tmp.0.phiops.reload[[R2:[0-9]*]] = load float, float* %tmp.0.phiops
+; CHECK:         store float %tmp.0.phiops.reload[[R2]], float* %tmp.0.s2a
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define float @f(float* %A, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  br label %bb1
+
+bb1:                                              ; preds = %bb4, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb4 ], [ 0, %bb ]
+  %tmp.0 = phi float [ 0.000000e+00, %bb ], [ %tmp7, %bb4 ]
+  %tmp2 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp2, label %bb3, label %bb8
+
+bb3:                                              ; preds = %bb1
+  br label %bb4
+
+bb4:                                              ; preds = %bb3
+  %tmp5 = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp6 = load float, float* %tmp5, align 4
+  %tmp7 = fadd float %tmp.0, %tmp6
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  br label %exit
+
+exit:
+  ret float %tmp.0
+}
diff --git a/final/test/Isl/CodeGen/phi_scalar_simple_1.ll b/final/test/Isl/CodeGen/phi_scalar_simple_1.ll
new file mode 100644
index 0000000..895d329
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_scalar_simple_1.ll
@@ -0,0 +1,89 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+;
+;    int jd(int *restrict A, int x, int N) {
+;      for (int i = 1; i < N; i++)
+;        for (int j = 3; j < N; j++)
+;          x += A[i];
+;      return x;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @jd(i32* noalias %A, i32 %x, i32 %N) {
+entry:
+; CHECK-LABEL: entry:
+; CHECK-DAG:     %x.addr.1.lcssa.s2a = alloca i32
+; CHECK-DAG:     %x.addr.1.lcssa.phiops = alloca i32
+; CHECK-DAG:     %x.addr.1.s2a = alloca i32
+; CHECK-DAG:     %x.addr.1.phiops = alloca i32
+; CHECK-DAG:     %x.addr.0.s2a = alloca i32
+; CHECK-DAG:     %x.addr.0.phiops = alloca i32
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+; CHECK-LABEL: polly.merge_new_and_old:
+; CHECK:         %x.addr.0.merge = phi i32 [ %x.addr.0.final_reload, %polly.exiting ], [ %x.addr.0, %for.cond ]
+; CHECK:         ret i32 %x.addr.0.merge
+
+; CHECK-LABEL: polly.start:
+; CHECK:         store i32 %x, i32* %x.addr.0.phiops
+
+; CHECK-LABEL: polly.exiting:
+; CHECK:         %x.addr.0.final_reload = load i32, i32* %x.addr.0.s2a
+
+for.cond:                                         ; preds = %for.inc4, %entry
+; CHECK-LABEL: polly.stmt.for.cond{{[0-9]*}}:
+; CHECK:         %x.addr.0.phiops.reload[[R1:[0-9]*]] = load i32, i32* %x.addr.0.phiops
+; CHECK:         store i32 %x.addr.0.phiops.reload[[R1]], i32* %x.addr.0.s2a
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc4 ], [ 1, %entry ]
+  %x.addr.0 = phi i32 [ %x, %entry ], [ %x.addr.1.lcssa, %for.inc4 ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+; CHECK-LABEL: polly.stmt.for.body:
+; CHECK:         %x.addr.0.s2a.reload[[R2:[0-9]*]] = load i32, i32* %x.addr.0.s2a
+; CHECK:         store i32 %x.addr.0.s2a.reload[[R2]], i32* %x.addr.1.phiops
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+; CHECK-LABEL: polly.stmt.for.cond1:
+; CHECK:         %x.addr.1.phiops.reload = load i32, i32* %x.addr.1.phiops
+; CHECK:         store i32 %x.addr.1.phiops.reload, i32* %x.addr.1.s2a[[R6:[0-9]*]]
+; CHECK:         store i32 %x.addr.1.phiops.reload, i32* %x.addr.1.lcssa.phiops
+  %x.addr.1 = phi i32 [ %x.addr.0, %for.body ], [ %add, %for.inc ]
+  %j.0 = phi i32 [ 3, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, %N
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.inc:                                          ; preds = %for.body3
+; CHECK-LABEL: polly.stmt.for.inc:
+; CHECK:         %x.addr.1.s2a.reload[[R3:[0-9]*]] = load i32, i32* %x.addr.1.s2a
+; CHECK:         %p_add = add nsw i32 %x.addr.1.s2a.reload[[R3]], %tmp1_p_scalar_
+; CHECK:         store i32 %p_add, i32* %x.addr.1.phiops
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %x.addr.1, %tmp1
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+; CHECK-LABEL: polly.stmt.for.end:
+; CHECK-NEXT:    %x.addr.1.lcssa.phiops.reload = load i32, i32* %x.addr.1.lcssa.phiops
+; CHECK-NEXT:    store i32 %x.addr.1.lcssa.phiops.reload, i32* %x.addr.1.lcssa.s2a[[R4:[0-9]*]]
+  %x.addr.1.lcssa = phi i32 [ %x.addr.1, %for.cond1 ]
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+; CHECK-LABEL: polly.stmt.for.inc4:
+; CHECK:         %x.addr.1.lcssa.s2a.reload[[R5:[0-9]*]] = load i32, i32* %x.addr.1.lcssa.s2a[[R4]]
+; CHECK:         store i32 %x.addr.1.lcssa.s2a.reload[[R5]], i32* %x.addr.0.phiops
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.inc
+
+for.end6:                                         ; preds = %for.cond
+  ret i32 %x.addr.0
+}
diff --git a/final/test/Isl/CodeGen/phi_scalar_simple_2.ll b/final/test/Isl/CodeGen/phi_scalar_simple_2.ll
new file mode 100644
index 0000000..941bd2c
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_scalar_simple_2.ll
@@ -0,0 +1,105 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+;
+;    int jd(int *restrict A, int x, int N, int c) {
+;      for (int i = 0; i < N; i++)
+;        for (int j = 0; j < N; j++)
+;          if (i < c)
+;            x += A[i];
+;      return x;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @jd(i32* noalias %A, i32 %x, i32 %N, i32 %c) {
+entry:
+; CHECK-LABEL: entry:
+; CHECK-DAG:     %x.addr.2.s2a = alloca i32
+; CHECK-DAG:     %x.addr.2.phiops = alloca i32
+; CHECK-DAG:     %x.addr.1.s2a = alloca i32
+; CHECK-DAG:     %x.addr.1.phiops = alloca i32
+; CHECK-DAG:     %x.addr.0.s2a = alloca i32
+; CHECK-DAG:     %x.addr.0.phiops = alloca i32
+  %tmp = sext i32 %N to i64
+  %tmp1 = sext i32 %c to i64
+  br label %for.cond
+
+; CHECK-LABEL: polly.merge_new_and_old:
+; CHECK:         %x.addr.0.merge = phi i32 [ %x.addr.0.final_reload, %polly.exiting ], [ %x.addr.0, %for.cond ]
+; CHECK:         ret i32 %x.addr.0.merge
+
+; CHECK-LABEL: polly.start:
+; CHECK-NEXT:    store i32 %x, i32* %x.addr.0.phiops
+; CHECK-NEXT:    sext
+
+; CHECK-LABEL: polly.merge{{[a-z_0-9]*}}:
+; CHECK:         %x.addr.0.final_reload = load i32, i32* %x.addr.0.s2a
+
+for.cond:                                         ; preds = %for.inc5, %entry
+; CHECK-LABEL: polly.stmt.for.cond{{[0-9]*}}:
+; CHECK:         %x.addr.0.phiops.reload[[R1:[0-9]*]] = load i32, i32* %x.addr.0.phiops
+; CHECK:         store i32 %x.addr.0.phiops.reload[[R1]], i32* %x.addr.0.s2a
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc5 ], [ 0, %entry ]
+  %x.addr.0 = phi i32 [ %x, %entry ], [ %x.addr.1, %for.inc5 ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end7
+
+for.body:                                         ; preds = %for.cond
+; CHECK-LABEL: polly.stmt.for.body:
+; CHECK:         %x.addr.0.s2a.reload[[R2:[0-9]*]] = load i32, i32* %x.addr.0.s2a
+; CHECK:         store i32 %x.addr.0.s2a.reload[[R2]], i32* %x.addr.1.phiops
+  br label %for.cond1
+
+for.inc5:                                         ; preds = %for.end
+; CHECK-LABEL: polly.stmt.for.inc5:
+; CHECK:         %x.addr.1.s2a.reload[[R5:[0-9]*]] = load i32, i32* %x.addr.1.s2a
+; CHECK:         store i32 %x.addr.1.s2a.reload[[R5]], i32* %x.addr.0.phiops
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+; CHECK-LABEL: polly.stmt.for.cond1:
+; CHECK:         %x.addr.1.phiops.reload = load i32, i32* %x.addr.1.phiops
+; CHECK:         store i32 %x.addr.1.phiops.reload, i32* %x.addr.1.s2a
+  %x.addr.1 = phi i32 [ %x.addr.0, %for.body ], [ %x.addr.2, %for.inc ]
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, %N
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+; CHECK-LABEL: polly.stmt.for.body3:
+; CHECK:  %x.addr.1.s2a.reload = load i32, i32* %x.addr.1.s2a
+; CHECK:  store i32 %x.addr.1.s2a.reload, i32* %x.addr.2.phiops
+  %cmp4 = icmp slt i64 %indvars.iv, %tmp1
+  br i1 %cmp4, label %if.then, label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body3
+; CHECK-LABEL: polly.stmt.if.end:
+; CHECK:         %x.addr.2.phiops.reload = load i32, i32* %x.addr.2.phiops
+; CHECK:         store i32 %x.addr.2.phiops.reload, i32* %x.addr.2.s2a
+  %x.addr.2 = phi i32 [ %add, %if.then ], [ %x.addr.1, %for.body3 ]
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+; CHECK-LABEL: polly.stmt.for.inc:
+; CHECK:         %x.addr.2.s2a.reload[[R3:[0-9]*]] = load i32, i32* %x.addr.2.s2a
+; CHECK:         store i32 %x.addr.2.s2a.reload[[R3]], i32* %x.addr.1.phiops
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+if.then:                                          ; preds = %for.body3
+; CHECK-LABEL: polly.stmt.if.then:
+; CHECK:         %x.addr.1.s2a.reload[[R5:[0-9]*]] = load i32, i32* %x.addr.1.s2a
+; CHECK:         %p_add = add nsw i32 %x.addr.1.s2a.reload[[R5]], %tmp2_p_scalar_
+; CHECK:         store i32 %p_add, i32* %x.addr.2.phiops
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %x.addr.1, %tmp2
+  br label %if.end
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc5
+
+for.end7:                                         ; preds = %for.cond
+  ret i32 %x.addr.0
+}
+
diff --git a/final/test/Isl/CodeGen/phi_with_multi_exiting_edges_2.ll b/final/test/Isl/CodeGen/phi_with_multi_exiting_edges_2.ll
new file mode 100644
index 0000000..dd02de1
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_with_multi_exiting_edges_2.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; CHECK: polly.merge_new_and_old:
+; CHECK:   %result.ph.merge = phi float [ %result.ph.final_reload, %polly.exiting ], [ %result.ph, %next.region_exiting ]
+; CHECK:   br label %next
+;
+; CHECK: next:
+; CHECK:   %result = phi float [ %result.ph.merge, %polly.merge_new_and_old ]
+; CHECK:   ret float %result
+
+define float @foo(float* %A, i64 %param) {
+entry:
+  br label %entry.split
+
+entry.split:
+  %branchcond = icmp slt i64 %param, 64
+  br i1 %branchcond, label %loopA, label %loopB
+
+loopA:
+  %indvarA = phi i64 [0, %entry.split], [%indvar.nextA, %loopA]
+  %indvar.nextA = add i64 %indvarA, 1
+  %valA = load float, float* %A
+  %sumA = fadd float %valA, %valA
+  store float %valA, float* %A
+  %cndA = icmp eq i64 %indvar.nextA, 100
+  br i1 %cndA, label %next, label %loopA
+
+loopB:
+  %indvarB = phi i64 [0, %entry.split], [%indvar.nextB, %loopB]
+  %indvar.nextB = add i64 %indvarB, 1
+  %valB = load float, float* %A
+  %sumB = fadd float %valB, %valB
+  store float %valB, float* %A
+  %cndB = icmp eq i64 %indvar.nextB, 100
+  br i1 %cndB, label %next, label %loopB
+
+next:
+  %result = phi float [%sumA, %loopA], [%sumB, %loopB]
+  ret float %result
+
+}
diff --git a/final/test/Isl/CodeGen/phi_with_one_exit_edge.ll b/final/test/Isl/CodeGen/phi_with_one_exit_edge.ll
new file mode 100644
index 0000000..129e0ff
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_with_one_exit_edge.ll
@@ -0,0 +1,32 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+;
+; CHECK: polly.merge_new_and_old:
+; CHECK:   %sumA.merge = phi float [ %sumA.final_reload, %polly.exiting ], [ %sumA, %loopA ]
+; CHECK:   br label %next
+;
+; CHECK: next:
+; CHECK:   %result = phi float [ %sumA.merge, %polly.merge_new_and_old ]
+; CHECK:   ret float %result
+;
+define float @foo(float* %A, i64 %param) {
+entry:
+  br label %entry.split
+
+entry.split:
+  br label %loopA
+
+loopA:
+  %indvarA = phi i64 [0, %entry.split], [%indvar.nextA, %loopA]
+  %indvar.nextA = add i64 %indvarA, 1
+  %valA = load float, float* %A
+  %sumA = fadd float %valA, %valA
+  store float %valA, float* %A
+  %cndA = icmp eq i64 %indvar.nextA, 100
+  br i1 %cndA, label %next, label %loopA
+
+next:
+  %result = phi float [%sumA, %loopA]
+  ret float %result
+
+}
diff --git a/final/test/Isl/CodeGen/pointer-type-expressions-2.ll b/final/test/Isl/CodeGen/pointer-type-expressions-2.ll
new file mode 100644
index 0000000..4e27800
--- /dev/null
+++ b/final/test/Isl/CodeGen/pointer-type-expressions-2.ll
@@ -0,0 +1,29 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s -check-prefix=CODEGEN
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i8* %start, i8* %end) {
+entry:
+  %A = alloca i32
+  br label %body
+
+body:
+  %ptr = phi i8* [ %start, %entry ], [ %ptr2, %body ]
+  %ptr2 = getelementptr inbounds i8, i8* %ptr, i64 1
+  %cmp = icmp eq i8* %ptr2, %end
+  store i32 42, i32* %A
+  br i1 %cmp, label %exit, label %body
+
+exit:
+  ret void
+}
+
+; CHECK: for (int c0 = 0; c0 < -start + end; c0 += 1)
+; CHECK:   Stmt_body(c0);
+
+; CODEGEN-LABEL: polly.start:
+; CODEGEN-NEXT:   %[[r0:[._a-zA-Z0-9]*]] = ptrtoint i8* %start to i64
+; CODEGEN-NEXT:   %[[r1:[._a-zA-Z0-9]*]] = sub nsw i64 0, %[[r0]]
+; CODEGEN-NEXT:   %[[r2:[._a-zA-Z0-9]*]] = ptrtoint i8* %end to i64
+; CODEGEN-NEXT:   %[[r4:[._a-zA-Z0-9]*]] = add nsw i64 %[[r1]], %[[r2]]
+
diff --git a/final/test/Isl/CodeGen/pointer-type-expressions.ll b/final/test/Isl/CodeGen/pointer-type-expressions.ll
new file mode 100644
index 0000000..2558c9c
--- /dev/null
+++ b/final/test/Isl/CodeGen/pointer-type-expressions.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s -check-prefix=CODEGEN
+
+; void f(int a[], int N, float *P) {
+;   int i;
+;   for (i = 0; i < N; ++i)
+;     if (P != 0)
+;       a[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* nocapture %a, i64 %N, float * %P) nounwind {
+entry:
+  br label %bb
+
+bb:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %bb.backedge ]
+  %brcond = icmp ne float* %P, null
+  br i1 %brcond, label %store, label %bb.backedge
+
+store:
+  %scevgep = getelementptr i64, i64* %a, i64 %i
+  store i64 %i, i64* %scevgep
+  br label %bb.backedge
+
+bb.backedge:
+  %i.inc = add nsw i64 %i, 1
+  %exitcond = icmp eq i64 %i.inc, %N
+  br i1 %exitcond, label %return, label %bb
+
+return:
+  ret void
+}
+
+; CHECK:      if (P <= -1 || P >= 1)
+; CHECK-NEXT:   for (int c0 = 0; c0 < N; c0 += 1)
+; CHECK-NEXT:     Stmt_store(c0);
+
+; CODEGEN-LABEL: polly.cond:
+; CODEGEN-NEXT:   %[[R1:[0-9]*]] = ptrtoint float* %P to i64
+; CODEGEN-NEXT:   %[[R2:[0-9]*]] = icmp sle i64 %[[R1]], -1
+; CODEGEN-NEXT:   %[[R3:[0-9]*]] = ptrtoint float* %P to i64
+; CODEGEN-NEXT:   %[[R4:[0-9]*]] = icmp sge i64 %[[R3]], 1
+; CODEGEN-NEXT:   %[[R5:[0-9]*]] = or i1 %[[R2]], %[[R4]]
+; CODEGEN-NEXT:   br i1 %[[R5]]
+
diff --git a/final/test/Isl/CodeGen/pointer-type-pointer-type-comparison.ll b/final/test/Isl/CodeGen/pointer-type-pointer-type-comparison.ll
new file mode 100644
index 0000000..08a1c11
--- /dev/null
+++ b/final/test/Isl/CodeGen/pointer-type-pointer-type-comparison.ll
@@ -0,0 +1,51 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s -check-prefix=CODEGEN
+;
+
+;    void f(int a[], int N, float *P, float *Q) {
+;      int i;
+;      for (i = 0; i < N; ++i)
+;        if (P != Q)
+;          a[i] = i;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i64* nocapture %a, i64 %N, float * %P, float * %Q) nounwind {
+entry:
+  br label %bb
+
+bb:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %bb.backedge ]
+  %brcond = icmp ne float* %P, %Q
+  br i1 %brcond, label %store, label %bb.backedge
+
+store:
+  %scevgep = getelementptr inbounds i64, i64* %a, i64 %i
+  store i64 %i, i64* %scevgep
+  br label %bb.backedge
+
+bb.backedge:
+  %i.inc = add nsw i64 %i, 1
+  %exitcond = icmp eq i64 %i.inc, %N
+  br i1 %exitcond, label %return, label %bb
+
+return:
+  ret void
+}
+
+; CHECK:      if (Q >= P + 1 || P >= Q + 1)
+; CHECK-NEXT:   for (int c0 = 0; c0 < N; c0 += 1)
+; CHECK-NEXT:     Stmt_store(c0);
+
+; CODEGEN:       polly.cond:
+; CODEGEN-NEXT:  %[[Q:[_a-zA-Z0-9]+]] = ptrtoint float* %Q to i64
+; CODEGEN-NEXT:  %[[P:[_a-zA-Z0-9]+]] = ptrtoint float* %P to i64
+; CODEGEN-NEXT:  %[[PInc:[_a-zA-Z0-9]+]] = add nsw i64 %[[P]], 1
+; CODEGEN-NEXT:  %[[CMP:[_a-zA-Z0-9]+]] = icmp sge i64 %[[Q]], %[[PInc]]
+; CODEGEN-NEXT:  %[[P2:[_a-zA-Z0-9]+]] = ptrtoint float* %P to i64
+; CODEGEN-NEXT:  %[[Q2:[_a-zA-Z0-9]+]] = ptrtoint float* %Q to i64
+; CODEGEN-NEXT:  %[[QInc:[_a-zA-Z0-9]+]] = add nsw i64 %[[Q2]], 1
+; CODEGEN-NEXT:  %[[CMP2:[_a-zA-Z0-9]+]] = icmp sge i64 %[[P2]], %[[QInc]]
+; CODEGEN-NEXT:  %[[CMP3:[_a-zA-Z0-9]+]] = or i1 %[[CMP]], %[[CMP2]]
+; CODEGEN-NEXT:  br i1 %[[CMP3]]
diff --git a/final/test/Isl/CodeGen/pointer_rem.ll b/final/test/Isl/CodeGen/pointer_rem.ll
new file mode 100644
index 0000000..e12d236
--- /dev/null
+++ b/final/test/Isl/CodeGen/pointer_rem.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-process-unprofitable -polly-scops -polly-ast -analyze -S < %s | FileCheck %s --check-prefix=AST
+; RUN: opt %loadPolly -polly-process-unprofitable -polly-scops -polly-codegen -S < %s | FileCheck %s --check-prefix=CODEGEN
+
+target datalayout = "e-m:e-i64:64-i128:128-n8:16:32:64-S128"
+target triple = "aarch64--linux-gnu"
+
+; This test is to ensure that for we generate signed remainder for
+; the polly.cond check.
+
+; AST: isl ast :: foo1
+; AST: if ((a1 - b1) % 24 == 0)
+
+; CODEGEN: define void @foo1
+; CODEGEN: polly.cond:
+; CODEGEN: %pexp.zdiv_r = srem {{.*}}, 24
+
+%struct.A = type { i32, i64, i8 }
+
+; Function Attrs: norecurse nounwind
+define void @foo1(%struct.A* %a1, %struct.A* readnone %b1) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %cmp4 = icmp eq %struct.A* %a1, %b1
+  br i1 %cmp4, label %for.cond.cleanup, label %for.body.preheader
+
+for.body.preheader:                               ; preds = %entry.split
+  br label %for.body
+
+for.cond.cleanup.loopexit:                        ; preds = %for.body
+  br label %for.cond.cleanup
+
+for.cond.cleanup:                                 ; preds = %for.cond.cleanup.loopexit, %entry.split
+  ret void
+
+for.body:                                         ; preds = %for.body.preheader, %for.body
+  %start.05 = phi %struct.A* [ %incdec.ptr, %for.body ], [ %a1, %for.body.preheader ]
+  %a = getelementptr inbounds %struct.A, %struct.A* %start.05, i64 0, i32 0
+  %0 = load i32, i32* %a, align 8
+  %add = add nsw i32 %0, 1
+  store i32 %add, i32* %a, align 8
+  %incdec.ptr = getelementptr inbounds %struct.A, %struct.A* %start.05, i64 1
+  %cmp = icmp eq %struct.A* %incdec.ptr, %b1
+  br i1 %cmp, label %for.cond.cleanup.loopexit, label %for.body
+}
+
+
diff --git a/final/test/Isl/CodeGen/pr25241.ll b/final/test/Isl/CodeGen/pr25241.ll
new file mode 100644
index 0000000..7431af3
--- /dev/null
+++ b/final/test/Isl/CodeGen/pr25241.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+
+; PR25241 (https://llvm.org/bugs/show_bug.cgi?id=25241)
+; Ensure that synthesized values of a PHI node argument are generated in the
+; incoming block, not in the PHI's block.
+
+; CHECK-LABEL: polly.stmt.if.then.862:
+; CHECK:         %[[R1:[0-9]+]] = add i32 %tmp, 1
+; CHECK:         br label
+
+; CHECK-LABEL: polly.stmt.while.body.740.region_exiting:
+; CHECK:         %polly.curr.3 = phi i32 [ %[[R1]], %polly.stmt.if.then.862 ], [ undef, %polly.stmt.if.else.864 ]
+; CHECK:         br label %polly.stmt.polly.merge_new_and_old.exit
+
+; CHECK-LABEL: polly.stmt.polly.merge_new_and_old.exit:
+; CHECK:         store i32 %polly.curr.3, i32* %curr.3.s2a
+; CHECK:         br label %polly.exiting
+
+; CHECK-LABEL: polly.exiting:
+; CHECK:         %curr.3.ph.final_reload = load i32, i32* %curr.3.s2a
+; CHECK:         br label
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @BZ2_decompress() #0 {
+entry:
+  %tmp = load i32, i32* undef, align 4, !tbaa !1
+  switch i32 undef, label %save_state_and_return [
+    i32 34, label %sw.bb.748
+    i32 35, label %if.then.813
+  ]
+
+while.body.740:                                   ; preds = %if.else.864, %if.then.862
+  %curr.3 = phi i32 [ %inc863, %if.then.862 ], [ undef, %if.else.864 ]
+  ret void
+
+sw.bb.748:                                        ; preds = %entry
+  ret void
+
+if.then.813:                                      ; preds = %entry
+  %conv823903 = and i32 undef, undef
+  %cmp860 = icmp eq i32 %conv823903, 0
+  br i1 %cmp860, label %if.then.862, label %if.else.864
+
+if.then.862:                                      ; preds = %if.then.813
+  %inc863 = add nsw i32 %tmp, 1
+  br label %while.body.740
+
+if.else.864:                                      ; preds = %if.then.813
+  br label %while.body.740
+
+save_state_and_return:                            ; preds = %entry
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 250010) (llvm/trunk 250018)"}
+!1 = !{!2, !6, i64 64092}
+!2 = !{!"", !3, i64 0, !6, i64 8, !4, i64 12, !6, i64 16, !4, i64 20, !6, i64 24, !6, i64 28, !6, i64 32, !6, i64 36, !6, i64 40, !4, i64 44, !6, i64 48, !6, i64 52, !6, i64 56, !6, i64 60, !6, i64 64, !4, i64 68, !6, i64 1092, !4, i64 1096, !4, i64 2124, !3, i64 3152, !3, i64 3160, !3, i64 3168, !6, i64 3176, !6, i64 3180, !6, i64 3184, !6, i64 3188, !6, i64 3192, !4, i64 3196, !4, i64 3452, !4, i64 3468, !4, i64 3724, !4, i64 7820, !4, i64 7884, !4, i64 25886, !4, i64 43888, !4, i64 45436, !4, i64 51628, !4, i64 57820, !4, i64 64012, !6, i64 64036, !6, i64 64040, !6, i64 64044, !6, i64 64048, !6, i64 64052, !6, i64 64056, !6, i64 64060, !6, i64 64064, !6, i64 64068, !6, i64 64072, !6, i64 64076, !6, i64 64080, !6, i64 64084, !6, i64 64088, !6, i64 64092, !6, i64 64096, !6, i64 64100, !6, i64 64104, !6, i64 64108, !6, i64 64112, !6, i64 64116, !3, i64 64120, !3, i64 64128, !3, i64 64136}
+!3 = !{!"any pointer", !4, i64 0}
+!4 = !{!"omnipotent char", !5, i64 0}
+!5 = !{!"Simple C/C++ TBAA"}
+!6 = !{!"int", !4, i64 0}
diff --git a/final/test/Isl/CodeGen/ptrtoint_as_parameter.ll b/final/test/Isl/CodeGen/ptrtoint_as_parameter.ll
new file mode 100644
index 0000000..a673ac7
--- /dev/null
+++ b/final/test/Isl/CodeGen/ptrtoint_as_parameter.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; CHECK:      polly.split_new_and_old:
+; CHECK-NEXT:   %pollysub.ptr.lhs.cast263 = ptrtoint i8* inttoptr (i64 1 to i8*) to i64
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @XS_MIME__QuotedPrint_encode_qp() {
+entry:
+  %Perl_sv_len = alloca i64, align 8
+  br label %if.end
+
+if.end:                                           ; preds = %entry
+  br label %while.cond
+
+while.cond:                                       ; preds = %cond.true270, %if.then260, %if.end
+  %p.0 = phi i8* [ null, %if.end ], [ %p.4, %if.then260 ], [ %p.4, %cond.true270 ]
+  br i1 undef, label %if.then260, label %while.body210
+
+while.body210:                                    ; preds = %while.cond
+  ret void
+
+if.then260:                                       ; preds = %while.cond
+  %p.4 = getelementptr inbounds i8, i8* null, i64 1
+  %sub.ptr.lhs.cast263 = ptrtoint i8* %p.4 to i64
+  %sub.ptr.sub265 = sub i64 %sub.ptr.lhs.cast263, 0
+  %div = udiv i64 0, %sub.ptr.sub265
+  %cmp268 = icmp ult i64 0, %div
+  br i1 %cmp268, label %cond.true270, label %while.cond
+
+cond.true270:                                     ; preds = %if.then260
+  br label %while.cond
+}
diff --git a/final/test/Isl/CodeGen/read-only-scalars.ll b/final/test/Isl/CodeGen/read-only-scalars.ll
new file mode 100644
index 0000000..f27ec6b
--- /dev/null
+++ b/final/test/Isl/CodeGen/read-only-scalars.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-analyze-read-only-scalars=false -polly-codegen \
+; RUN:     \
+; RUN:     -S < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-analyze-read-only-scalars=true -polly-codegen \
+; RUN:     \
+; RUN:     -S < %s | FileCheck %s -check-prefix=SCALAR
+
+; CHECK-NOT: alloca
+
+; SCALAR-LABEL: entry:
+; SCALAR-NEXT: %scalar.s2a = alloca float
+
+; SCALAR-LABEL: polly.start:
+; SCALAR-NEXT:  store float %scalar, float* %scalar.s2a
+
+; SCALAR-LABEL: polly.stmt.stmt1:
+; SCALAR-NEXT:  %scalar.s2a.reload = load float, float* %scalar.s2a
+; SCALAR-NEXT:  %val_p_scalar_ = load float, float* %A,
+; SCALAR-NEXT:  %p_sum = fadd float %val_p_scalar_, %scalar.s2a.reload
+
+define void @foo(float* noalias %A, float %scalar) {
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %entry], [%indvar.next, %loop.backedge]
+  br label %stmt1
+
+stmt1:
+  %val = load float, float* %A
+  %sum = fadd float %val, %scalar
+  store float %sum, float* %A
+  br label %loop.backedge
+
+loop.backedge:
+  %indvar.next = add i64 %indvar, 1
+  %cond = icmp sle i64 %indvar, 100
+  br i1 %cond, label %loop, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/reduction.ll b/final/test/Isl/CodeGen/reduction.ll
new file mode 100644
index 0000000..e9ed141
--- /dev/null
+++ b/final/test/Isl/CodeGen/reduction.ll
@@ -0,0 +1,88 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s 2>&1 | not FileCheck %s
+
+;#include <string.h>
+;#include <stdio.h>
+;#define N 1021
+;
+;int main () {
+;  int i;
+;  int A[N];
+;  int red;
+;
+;  memset(A, 0, sizeof(int) * N);
+;
+;  A[0] = 1;
+;  A[1] = 1;
+;  red = 0;
+;
+;  __sync_synchronize();
+;
+;  for (i = 2; i < N; i++) {
+;    A[i] = A[i-1] + A[i-2];
+;    red += A[i-2];
+;  }
+;
+;  __sync_synchronize();
+;
+;  if (red != 382399368)
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define i32 @main() nounwind {
+; <label>:0
+  %A = alloca [1021 x i32], align 16              ; <[1021 x i32]*> [#uses=6]
+  %1 = getelementptr inbounds [1021 x i32], [1021 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %2 = bitcast i32* %1 to i8*                     ; <i8*> [#uses=1]
+  call void @llvm.memset.p0i8.i64(i8* %2, i8 0, i64 4084, i32 1, i1 false)
+  %3 = getelementptr inbounds [1021 x i32], [1021 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %4 = getelementptr inbounds i32, i32* %3, i64 0      ; <i32*> [#uses=1]
+  store i32 1, i32* %4
+  %5 = getelementptr inbounds [1021 x i32], [1021 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %6 = getelementptr inbounds i32, i32* %5, i64 1      ; <i32*> [#uses=1]
+  store i32 1, i32* %6
+  fence seq_cst
+  br label %7
+
+; <label>:7                                       ; preds = %14, %0
+  %indvar = phi i64 [ %indvar.next, %14 ], [ 0, %0 ] ; <i64> [#uses=5]
+  %red.0 = phi i32 [ 0, %0 ], [ %13, %14 ]        ; <i32> [#uses=2]
+  %scevgep = getelementptr [1021 x i32], [1021 x i32]* %A, i64 0, i64 %indvar ; <i32*> [#uses=2]
+  %tmp = add i64 %indvar, 2                       ; <i64> [#uses=1]
+  %scevgep1 = getelementptr [1021 x i32], [1021 x i32]* %A, i64 0, i64 %tmp ; <i32*> [#uses=1]
+  %tmp2 = add i64 %indvar, 1                      ; <i64> [#uses=1]
+  %scevgep3 = getelementptr [1021 x i32], [1021 x i32]* %A, i64 0, i64 %tmp2 ; <i32*> [#uses=1]
+  %exitcond = icmp ne i64 %indvar, 1019           ; <i1> [#uses=1]
+  br i1 %exitcond, label %8, label %15
+
+; <label>:8                                       ; preds = %7
+  %9 = load i32, i32* %scevgep3                        ; <i32> [#uses=1]
+  %10 = load i32, i32* %scevgep                        ; <i32> [#uses=1]
+  %11 = add nsw i32 %9, %10                       ; <i32> [#uses=1]
+  store i32 %11, i32* %scevgep1
+  %12 = load i32, i32* %scevgep                        ; <i32> [#uses=1]
+  %13 = add nsw i32 %red.0, %12                   ; <i32> [#uses=1]
+  br label %14
+
+; <label>:14                                      ; preds = %8
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %7
+
+; <label>:15                                      ; preds = %7
+  %red.0.lcssa = phi i32 [ %red.0, %7 ]           ; <i32> [#uses=1]
+  fence seq_cst
+  %16 = icmp ne i32 %red.0.lcssa, 382399368       ; <i1> [#uses=1]
+  br i1 %16, label %17, label %18
+
+; <label>:17                                      ; preds = %15
+  br label %18
+
+; <label>:18                                      ; preds = %17, %15
+  %.0 = phi i32 [ 1, %17 ], [ 0, %15 ]            ; <i32> [#uses=1]
+  ret i32 %.0
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
+
+; CHECK:  Could not generate independent blocks
diff --git a/final/test/Isl/CodeGen/reduction_2.ll b/final/test/Isl/CodeGen/reduction_2.ll
new file mode 100644
index 0000000..13cd32e
--- /dev/null
+++ b/final/test/Isl/CodeGen/reduction_2.ll
@@ -0,0 +1,98 @@
+; RUN: opt %loadPolly -basicaa -polly-ast -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+
+;#include <string.h>
+;#include <stdio.h>
+;#define N 1021
+;
+;int main () {
+;  int i;
+;  int A[N];
+;  int RED[1];
+;
+;  memset(A, 0, sizeof(int) * N);
+;
+;  A[0] = 1;
+;  A[1] = 1;
+;  RED[0] = 0;
+;
+;  for (i = 2; i < N; i++) {
+;    A[i] = A[i-1] + A[i-2];
+;    RED[0] += A[i-2];
+;  }
+;
+;  if (RED[0] != 382399368)
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define i32 @main() nounwind {
+entry:
+  %A = alloca [1021 x i32], align 4               ; <[1021 x i32]*> [#uses=6]
+  %RED = alloca [1 x i32], align 4                ; <[1 x i32]*> [#uses=3]
+  %arraydecay = getelementptr inbounds [1021 x i32], [1021 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %conv = bitcast i32* %arraydecay to i8*         ; <i8*> [#uses=1]
+  call void @llvm.memset.p0i8.i64(i8* %conv, i8 0, i64 4084, i32 1, i1 false)
+  %arraydecay1 = getelementptr inbounds [1021 x i32], [1021 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx = getelementptr inbounds i32, i32* %arraydecay1, i64 0 ; <i32*> [#uses=1]
+  store i32 1, i32* %arrayidx
+  %arraydecay2 = getelementptr inbounds [1021 x i32], [1021 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx3 = getelementptr inbounds i32, i32* %arraydecay2, i64 1 ; <i32*> [#uses=1]
+  store i32 1, i32* %arrayidx3
+  %arraydecay4 = getelementptr inbounds [1 x i32], [1 x i32]* %RED, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx5 = getelementptr inbounds i32, i32* %arraydecay4, i64 0 ; <i32*> [#uses=1]
+  store i32 0, i32* %arrayidx5
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %entry ] ; <i64> [#uses=5]
+  %arrayidx15 = getelementptr [1021 x i32], [1021 x i32]* %A, i64 0, i64 %indvar ; <i32*> [#uses=2]
+  %tmp = add i64 %indvar, 2                       ; <i64> [#uses=1]
+  %arrayidx20 = getelementptr [1021 x i32], [1021 x i32]* %A, i64 0, i64 %tmp ; <i32*> [#uses=1]
+  %tmp1 = add i64 %indvar, 1                      ; <i64> [#uses=1]
+  %arrayidx9 = getelementptr [1021 x i32], [1021 x i32]* %A, i64 0, i64 %tmp1 ; <i32*> [#uses=1]
+  %exitcond = icmp ne i64 %indvar, 1019           ; <i1> [#uses=1]
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp10 = load i32, i32* %arrayidx9                   ; <i32> [#uses=1]
+  %tmp16 = load i32, i32* %arrayidx15                  ; <i32> [#uses=1]
+  %add = add nsw i32 %tmp10, %tmp16               ; <i32> [#uses=1]
+  store i32 %add, i32* %arrayidx20
+  %tmp26 = load i32, i32* %arrayidx15                  ; <i32> [#uses=1]
+  %arraydecay27 = getelementptr inbounds [1 x i32], [1 x i32]* %RED, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx28 = getelementptr inbounds i32, i32* %arraydecay27, i64 0 ; <i32*> [#uses=2]
+  %tmp29 = load i32, i32* %arrayidx28                  ; <i32> [#uses=1]
+  %add30 = add nsw i32 %tmp29, %tmp26             ; <i32> [#uses=1]
+  store i32 %add30, i32* %arrayidx28
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  %arraydecay32 = getelementptr inbounds [1 x i32], [1 x i32]* %RED, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx33 = getelementptr inbounds i32, i32* %arraydecay32, i64 0 ; <i32*> [#uses=1]
+  %tmp34 = load i32, i32* %arrayidx33                  ; <i32> [#uses=1]
+  %cmp35 = icmp ne i32 %tmp34, 382399368          ; <i1> [#uses=1]
+  br i1 %cmp35, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.end
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.end
+  %retval.0 = phi i32 [ 1, %if.then ], [ 0, %for.end ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
+
+; This is a negative test. We can prove that RED[0] in the conditional after
+; the loop is dereferencable and consequently expand the SCoP from the
+; loop to include the conditional. However, during SCoP generation we realize
+; that, while RED[0] is invariant, it is written to as part of the same scop
+; and can consequently not be hoisted. Hence, we invalidate the scop.
+;
+; CHECK-NOT: for (int c0 = 0; c0 <= 1018; c0 += 1)
diff --git a/final/test/Isl/CodeGen/reduction_simple_binary.ll b/final/test/Isl/CodeGen/reduction_simple_binary.ll
new file mode 100644
index 0000000..a09801e
--- /dev/null
+++ b/final/test/Isl/CodeGen/reduction_simple_binary.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK: pragma simd reduction
+;
+; int prod;
+; void f() {
+;   for (int i = 0; i < 100; i++)
+;     prod *= i;
+; }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+@prod = common global i32 0, align 4
+
+define void @f() {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i1.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i1.0, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add2 = add nsw i32 %i1.0, 3
+  %tmp1 = load i32, i32* @prod, align 4
+  %mul3 = mul nsw i32 %tmp1, %add2
+  store i32 %mul3, i32* @prod, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i1.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/region-with-instructions.ll b/final/test/Isl/CodeGen/region-with-instructions.ll
new file mode 100644
index 0000000..c277f60
--- /dev/null
+++ b/final/test/Isl/CodeGen/region-with-instructions.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+
+; CHECK-LABEL:   polly.stmt.bb48:
+; CHECK-NEXT:   %scevgep = getelementptr i64, i64* %A, i64 %polly.indvar
+; CHECK-NEXT:   %tmp51_p_scalar_ = load i64, i64* %scevgep,
+; CHECK-NEXT:   %p_tmp52 = and i64 %tmp51_p_scalar_, %tmp26
+; CHECK-NEXT:   %p_tmp53 = icmp eq i64 %p_tmp52, %tmp26
+; CHECK-NEXT:   store i64 42, i64* %scevgep, align 8
+; CHECK-NEXT:   br i1 %p_tmp53, label %polly.stmt.bb54, label %polly.stmt.bb56.exit
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @quux(i32 %arg, i32 %arg1, i64* %A, i64 %tmp9, i64 %tmp24, i64 %tmp14, i64 %tmp22, i64 %tmp44) {
+bb:
+  %tmp26 = or i64 %tmp22, %tmp24
+  br label %bb39
+
+bb39:                                             ; preds = %bb39, %bb38
+  %tmp45 = icmp eq i64 %tmp44, %tmp9
+  br i1 %tmp45, label %bb46, label %bb81
+
+bb46:                                             ; preds = %bb39
+  %tmp47 = or i64 1, %tmp14
+  br label %bb48
+
+bb48:                                             ; preds = %bb56, %bb46
+  %tmp49 = phi i64 [ 0, %bb46 ], [ %tmp57, %bb56 ]
+  %tmp50 = getelementptr inbounds i64, i64* %A, i64 %tmp49
+  %tmp51 = load i64, i64* %tmp50, align 8
+  %tmp52 = and i64 %tmp51, %tmp26
+  %tmp53 = icmp eq i64 %tmp52, %tmp26
+  store i64 42, i64* %tmp50, align 8
+  br i1 %tmp53, label %bb54, label %bb56
+
+bb54:                                             ; preds = %bb48
+  %tmp55 = xor i64 %tmp51, %tmp47
+  store i64 %tmp55, i64* %tmp50, align 8
+  br label %bb56
+
+bb56:                                             ; preds = %bb54, %bb48
+  %tmp57 = add nuw nsw i64 %tmp49, 1
+  %tmp58 = icmp eq i64 %tmp57, %tmp9
+  br i1 %tmp58, label %bb81, label %bb48
+
+bb81:                                             ; preds = %bb74, %bb56
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/region_exiting-domtree.ll b/final/test/Isl/CodeGen/region_exiting-domtree.ll
new file mode 100644
index 0000000..cef5206
--- /dev/null
+++ b/final/test/Isl/CodeGen/region_exiting-domtree.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-codegen -verify-dom-info -analyze < %s
+
+; Verify that the DominatorTree is preserved correctly for the inserted
+; %polly.stmt.exit.exit block, which serves as new exit block for the generated
+; subregion. In particulat, it must be dominated by %polly.stmt.subregion.enter,
+; the generated subregion's entry block.
+
+define void @func(i32 %n, i32* noalias nonnull %A) {
+entry:
+  br label %loop
+
+loop:
+  %i = phi i32 [0, %entry], [%i.inc, %loop.inc]
+  %i.cmp = icmp slt i32 %i, %n
+  br i1 %i.cmp, label %body, label %return
+
+body:
+  %skipcond = icmp slt i32 %i, 5
+  br i1 %skipcond, label %subregion.enter, label %subregion.skip
+
+subregion.skip:
+  br label %exit
+
+subregion.enter:
+  %sqr = mul i32 %i, %i
+  %cond = icmp eq i32 %sqr, 0
+  store i32 %i, i32* %A
+  br i1 %cond, label %subregion.true, label %subregion.false
+
+subregion.true:
+  br label %exit
+
+subregion.false:
+  br label %exit
+
+exit:
+  br label %loop.inc
+
+loop.inc:
+  %i.inc = add nuw nsw i32 %i, 1
+  br label %loop
+
+return:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/run-time-condition-with-scev-parameters.ll b/final/test/Isl/CodeGen/run-time-condition-with-scev-parameters.ll
new file mode 100644
index 0000000..abbda0e
--- /dev/null
+++ b/final/test/Isl/CodeGen/run-time-condition-with-scev-parameters.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=AST
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+
+; TODO: FIXME: Simplify the context.
+; AST: if (n >= 1 && 0 == n <= -1)
+
+; CHECK: entry:
+; CHECK-NEXT: %0 = zext i32 %n to i64
+
+; CHECK: polly.split_new_and_old:
+; CHECK-NEXT:  %1 = sext i32 %n to i64
+; CHECK-NEXT:  %2 = icmp sge i64 %1, 1
+; CHECK-NEXT:  %3 = sext i32 %n to i64
+; CHECK-NEXT:  %4 = icmp sle i64 %3, -1
+; CHECK-NEXT:  %5 = sext i1 %4 to i64
+; CHECK-NEXT:  %6 = icmp eq i64 0, %5
+; CHECK-NEXT:  %7 = and i1 %2, %6
+; CHECK-NEXT:  br i1 %7, label %polly.start, label %for.body4
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @init_array(i32 %n, double* %data) {
+entry:
+  %0 = zext i32 %n to i64
+  br label %for.body4
+
+for.body4:                                        ; preds = %for.body4, %entry
+  %indvar1 = phi i64 [ %indvar.next2, %for.body4 ], [ 0, %entry ]
+  %.moved.to.for.body4 = mul i64 %0, %indvar1
+  %1 = add i64 %.moved.to.for.body4, 0
+  %arrayidx7 = getelementptr double, double* %data, i64 %1
+  store double undef, double* %arrayidx7, align 8
+  %indvar.next2 = add i64 %indvar1, 1
+  br i1 false, label %for.body4, label %for.end10
+
+for.end10:                                        ; preds = %for.body4
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/run-time-condition.ll b/final/test/Isl/CodeGen/run-time-condition.ll
new file mode 100644
index 0000000..0cf4aa2
--- /dev/null
+++ b/final/test/Isl/CodeGen/run-time-condition.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -S < %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+define void @run-time-condition(i16* noalias %A, i16* noalias %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.body, %entry
+  %indvar = phi i64 [ 0, %entry ], [ %inc, %for.body ]
+  %cmp = icmp slt i64 %indvar, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i16, i16* %B, i64 0
+  %load = load i16, i16* %arrayidx
+  %add10 = add nsw i16 %load, 1
+  %arrayidx13 = getelementptr inbounds i16, i16* %A, i64 %indvar
+  store i16 %add10, i16* %arrayidx13, align 2
+  %inc = add nsw i64 %indvar, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+; The trivial case, no run-time checks required.
+;
+; CHECK: polly.split_new_and_old:
+; CHECK:  br i1 true, label %polly.start, label %for.cond
diff --git a/final/test/Isl/CodeGen/scalar-references-used-in-scop-compute.ll b/final/test/Isl/CodeGen/scalar-references-used-in-scop-compute.ll
new file mode 100644
index 0000000..fe32e64
--- /dev/null
+++ b/final/test/Isl/CodeGen/scalar-references-used-in-scop-compute.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+
+; Test the code generation in the presence of a scalar out-of-scop value being
+; used from within the SCoP.
+
+; CHECH-LABEL: @scalar-function-argument
+; CHECK: polly.split_new_and_old
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @scalar-function-argument(float* %A, float %sqrinv) {
+entry:
+  br label %for.body
+
+for.body:
+  %indvar = phi i64 [ %indvar.next, %for.body ], [ 0, %entry ]
+  %mul104 = fmul float 1.0, %sqrinv
+  %rp107 = getelementptr float, float* %A, i64 %indvar
+  store float %mul104, float* %rp107, align 4
+  %indvar.next = add nsw i64 %indvar, 1
+  %cmp = icmp slt i64 1024, %indvar.next
+  br i1 %cmp, label %for.end, label %for.body
+
+for.end:
+  ret void
+}
+
+; CHECH-LABEL: @scalar-outside-of-scop
+; CHECK: polly.split_new_and_old
+
+define void @scalar-outside-of-scop(float* %A) {
+entry:
+  %sqrinv = call float @getFloat()
+  br label %for.body
+
+for.body:
+  %indvar = phi i64 [ %indvar.next, %for.body ], [ 0, %entry ]
+  %mul104 = fmul float 1.0, %sqrinv
+  %rp107 = getelementptr float, float* %A, i64 %indvar
+  store float %mul104, float* %rp107, align 4
+  %indvar.next = add nsw i64 %indvar, 1
+  %cmp = icmp slt i64 1024, %indvar.next
+  br i1 %cmp, label %for.end, label %for.body
+
+for.end:
+  ret void
+}
+
+declare float @getFloat()
diff --git a/final/test/Isl/CodeGen/scalar-store-from-same-bb.ll b/final/test/Isl/CodeGen/scalar-store-from-same-bb.ll
new file mode 100644
index 0000000..74e854f
--- /dev/null
+++ b/final/test/Isl/CodeGen/scalar-store-from-same-bb.ll
@@ -0,0 +1,32 @@
+; RUN: opt %loadPolly \
+; RUN: -polly-codegen -S < %s | FileCheck %s
+
+; This test ensures that the expression N + 1 that is stored in the phi-node
+; alloca, is directly computed and not incorrectly transfered through memory.
+
+; CHECK: store i64 [[REG:%.*]], i64* %res.phiops
+; CHECK: [[REG]] = add i64 %N, 1
+
+define i64 @foo(float* %A, i64 %N) {
+entry:
+  br label %next
+
+next:
+  %cond = icmp eq i64 %N, 0
+  br i1 %cond, label %loop, label %merge
+
+loop:
+  %indvar = phi i64 [0, %next], [%indvar.next, %loop]
+  %indvar.next = add i64 %indvar, 1
+  %sum = add i64 %N, 1
+  store float 4.0, float* %A
+  %cmp = icmp sle i64 %indvar.next, 100
+  br i1 %cmp, label %loop, label %merge
+
+merge:
+  %res = phi i64 [%sum, %loop], [0, %next]
+  br label %exit
+
+exit:
+  ret i64 %res
+}
diff --git a/final/test/Isl/CodeGen/scalar_codegen_crash.ll b/final/test/Isl/CodeGen/scalar_codegen_crash.ll
new file mode 100644
index 0000000..8eb3817
--- /dev/null
+++ b/final/test/Isl/CodeGen/scalar_codegen_crash.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly \
+; RUN:     -polly-codegen -S < %s | FileCheck %s
+
+; This test cases used to crash the scalar code generation. Check that we
+; can generate code for it.
+
+; CHECK: polly.start
+@endposition = external global i32, align 4
+@Bit = external global [0 x i32], align 4
+@Init = external global [0 x i32], align 4
+
+define void @maskgen() {
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %for.body, %entry
+  br i1 undef, label %for.end.310, label %for.body
+
+for.end.310:                                      ; preds = %for.body
+  store i32 undef, i32* @endposition, align 4
+  %sub325 = sub i32 33, 0
+  %0 = load i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @Init, i64 0, i64 0), align 4
+  br i1 false, label %for.cond.347.preheader, label %for.body.328.lr.ph
+
+for.body.328.lr.ph:                               ; preds = %for.end.310
+  %1 = sub i32 34, 0
+  br label %for.body.328
+
+for.body.328:                                     ; preds = %for.body.328, %for.body.328.lr.ph
+  %indvars.iv546 = phi i64 [ %indvars.iv.next547, %for.body.328 ], [ 1, %for.body.328.lr.ph ]
+  %2 = phi i32 [ %or331, %for.body.328 ], [ %0, %for.body.328.lr.ph ]
+  %arrayidx330 = getelementptr inbounds [0 x i32], [0 x i32]* @Bit, i64 0, i64 %indvars.iv546
+  %3 = load i32, i32* %arrayidx330, align 4
+  %or331 = or i32 %3, %2
+  %indvars.iv.next547 = add nuw nsw i64 %indvars.iv546, 1
+  %lftr.wideiv = trunc i64 %indvars.iv.next547 to i32
+  %exitcond14 = icmp eq i32 %lftr.wideiv, %1
+  br i1 %exitcond14, label %for.cond.347.preheader, label %for.body.328
+
+for.cond.347.preheader:                           ; preds = %for.cond.347.preheader, %for.body.328, %for.end.310
+  br i1 undef, label %if.end.471, label %for.cond.347.preheader
+
+if.end.471:                                       ; preds = %for.cond.347.preheader
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/scev-division-invariant-load.ll b/final/test/Isl/CodeGen/scev-division-invariant-load.ll
new file mode 100644
index 0000000..3af47b6
--- /dev/null
+++ b/final/test/Isl/CodeGen/scev-division-invariant-load.ll
@@ -0,0 +1,51 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s
+;
+; Check that we generate valid code as we did not use the preloaded
+; value of %tmp1 for the access function of the preloaded %tmp4.
+;
+; ModuleID = 'bug.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.frame_store = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, %struct.picture*, %struct.picture*, %struct.picture* }
+%struct.picture = type { i32, i32, i32, i32, i32, i32, [6 x [33 x i64]], [6 x [33 x i64]], [6 x [33 x i64]], [6 x [33 x i64]], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i16**, i16*, i16*, i16**, i16**, i16***, i8*, i16***, i64***, i64***, i16****, i8**, i8**, %struct.picture*, %struct.picture*, %struct.picture*, i32, i32, i32, i32, i32, i32, i32 }
+
+define void @dpb_split_field(%struct.frame_store* %fs) {
+entry:
+  br label %for.body544
+
+for.body544:                                      ; preds = %if.end908, %for.body544.lr.ph
+  %indvars.iv87 = phi i64 [ 0, %entry ], [ %indvars.iv.next88, %if.end908 ]
+  %tmp = phi %struct.picture* [ undef, %entry ], [ %tmp6, %if.end908 ]
+  br label %land.lhs.true563
+
+land.lhs.true563:                                 ; preds = %for.body544
+  %size_x551 = getelementptr inbounds %struct.picture, %struct.picture* %tmp, i64 0, i32 18
+  %tmp1 = load i32, i32* %size_x551, align 8
+  %div552 = sdiv i32 %tmp1, 16
+  %tmp2 = trunc i64 %indvars.iv87 to i32
+  %div554 = sdiv i32 %tmp2, 4
+  %mul555 = mul i32 %div552, %div554
+  %tmp9 = add i32 %mul555, 0
+  %tmp10 = shl i32 %tmp9, 1
+  %add559 = add i32 %tmp10, 0
+  %idxprom564 = sext i32 %add559 to i64
+  %mb_field566 = getelementptr inbounds %struct.picture, %struct.picture* %tmp, i64 0, i32 31
+  %tmp3 = load i8*, i8** %mb_field566, align 8
+  %arrayidx567 = getelementptr inbounds i8, i8* %tmp3, i64 %idxprom564
+  %tmp4 = load i8, i8* %arrayidx567, align 1
+  %tobool569 = icmp eq i8 %tmp4, 0
+  br i1 %tobool569, label %if.end908, label %if.then570
+
+if.then570:                                       ; preds = %land.lhs.true563
+  %frame = getelementptr inbounds %struct.frame_store, %struct.frame_store* %fs, i64 0, i32 10
+  %tmp5 = load %struct.picture*, %struct.picture** %frame, align 8
+  br label %if.end908
+
+if.end908:                                        ; preds = %if.then570, %land.lhs.true563
+  %tmp6 = phi %struct.picture* [ %tmp, %land.lhs.true563 ], [ undef, %if.then570 ]
+  %indvars.iv.next88 = add nuw nsw i64 %indvars.iv87, 1
+  br i1 undef, label %for.body544, label %for.inc912
+
+for.inc912:                                       ; preds = %if.end908
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/scev.ll b/final/test/Isl/CodeGen/scev.ll
new file mode 100644
index 0000000..07d726d
--- /dev/null
+++ b/final/test/Isl/CodeGen/scev.ll
@@ -0,0 +1,21 @@
+; RUN: opt %loadPolly -polly-detect < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define fastcc void @f () inlinehint align 2 {
+entry:
+  %0 = fmul double undef, 1.250000e+00            ; <double> [#uses=1]
+  %1 = fptoui double %0 to i32                    ; <i32> [#uses=0]
+  br i1 false, label %bb5.i, label %bb.nph.i
+
+bb.nph.i:                                         ; preds = %bb.i1
+  br label %bb3.i2
+
+bb3.i2:                                           ; preds = %bb3.i2, %bb.nph.i
+  br i1 undef, label %bb3.i2, label %bb5.i
+
+bb5.i:                                            ; preds = %bb3.i2, %bb.i1
+  br label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/scev_expansion_in_nonaffine.ll b/final/test/Isl/CodeGen/scev_expansion_in_nonaffine.ll
new file mode 100644
index 0000000..b2edacd
--- /dev/null
+++ b/final/test/Isl/CodeGen/scev_expansion_in_nonaffine.ll
@@ -0,0 +1,90 @@
+; RUN: opt %loadPolly -polly-codegen -S \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+
+; bugpoint-reduced testcase of MiBench/consumer-lame/quantize-pvt.c from the
+; test-suite.
+; It features a SCEV that is used in two BasicBlock within a non-affine
+; subregion where none of the blocks dominate the other. We check that the SCEV
+; is expanded independently for both BasicBlocks instead of just once for the
+; whole subregion.
+
+; CHECK-LABEL:  polly.stmt.if.then.110:
+; CHECK:          %[[R1_1:[0-9]*]] = mul i64 %polly.indvar[[R0_1:[0-9]*]], 30
+; CHECK:          %scevgep[[R1_2:[0-9]*]] = getelementptr i32, i32* %scevgep{{[0-9]*}}, i64 %[[R1_1]]
+; CHECK:          store i32 0, i32* %scevgep[[R1_2]], align 8
+
+; CHECK-LABEL:  polly.stmt.if.else:
+; CHECK:          %[[R2_1:[0-9]*]] = mul i64 %polly.indvar[[R0_1]], 30
+; CHECK:          %scevgep[[R2_2:[0-9]*]] = getelementptr i32, i32* %scevgep{{[0-9]*}}, i64 %[[R2_1]]
+; CHECK:          store i32 21, i32* %scevgep[[R2_2]], align 8
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.gr_info.4.59.136.224.290 = type { i32, i32, i32, i32, i32, i32, i32, i32, [3 x i32], [3 x i32], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32*, [4 x i32] }
+%struct.gr_info_ss.5.60.137.225.291 = type { %struct.gr_info.4.59.136.224.290 }
+%struct.anon.6.61.138.226.292 = type { [2 x %struct.gr_info_ss.5.60.137.225.291] }
+%struct.III_side_info_t.7.62.139.227.293 = type { i32, i32, i32, [2 x [4 x i32]], [2 x %struct.anon.6.61.138.226.292] }
+%struct.lame_global_flags.3.58.135.223.289 = type { i64, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, float, i32, i32, i32, i64, i64, i32, i32, i32, i32, i32, i32, i32, i32, float, i32, i32, i32, float, float, float, float, i32, i32, i32, i32, i32, i32, i32, i32 }
+
+@convert_mdct = external global i32, align 4
+@reduce_sidechannel = external global i32, align 4
+
+; Function Attrs: nounwind uwtable
+define void @iteration_init(%struct.lame_global_flags.3.58.135.223.289* %gfp, %struct.III_side_info_t.7.62.139.227.293* %l3_side, [2 x [576 x i32]]* %l3_enc) #0 {
+entry:
+  %resvDrain = getelementptr inbounds %struct.III_side_info_t.7.62.139.227.293, %struct.III_side_info_t.7.62.139.227.293* %l3_side, i64 0, i32 2
+  store i32 0, i32* %resvDrain, align 8
+  store i32 0, i32* @convert_mdct, align 4
+  store i32 0, i32* @reduce_sidechannel, align 4
+  %mode_gr = getelementptr inbounds %struct.lame_global_flags.3.58.135.223.289, %struct.lame_global_flags.3.58.135.223.289* %gfp, i64 0, i32 45
+  %0 = load i32, i32* %mode_gr, align 8
+  %cmp95.145 = icmp sgt i32 %0, 0
+  br i1 %cmp95.145, label %for.cond.98.preheader, label %for.cond.120.preheader
+
+for.cond.98.preheader:                            ; preds = %for.inc.117, %entry
+  %indvars.iv157 = phi i64 [ %indvars.iv.next158, %for.inc.117 ], [ 0, %entry ]
+  %stereo = getelementptr inbounds %struct.lame_global_flags.3.58.135.223.289, %struct.lame_global_flags.3.58.135.223.289* %gfp, i64 0, i32 46
+  %1 = load i32, i32* %stereo, align 4
+  %cmp99.143 = icmp sgt i32 %1, 0
+  br i1 %cmp99.143, label %for.body.101, label %for.inc.117
+
+for.cond.120.preheader:                           ; preds = %for.inc.117, %entry
+  ret void
+
+for.body.101:                                     ; preds = %for.inc.114, %for.cond.98.preheader
+  %indvars.iv155 = phi i64 [ %indvars.iv.next156, %for.inc.114 ], [ 0, %for.cond.98.preheader ]
+  %block_type = getelementptr inbounds %struct.III_side_info_t.7.62.139.227.293, %struct.III_side_info_t.7.62.139.227.293* %l3_side, i64 0, i32 4, i64 %indvars.iv157, i32 0, i64 %indvars.iv155, i32 0, i32 6
+  %2 = load i32, i32* %block_type, align 8
+  %cmp108 = icmp eq i32 %2, 2
+  %sfb_lmax = getelementptr inbounds %struct.III_side_info_t.7.62.139.227.293, %struct.III_side_info_t.7.62.139.227.293* %l3_side, i64 0, i32 4, i64 %indvars.iv157, i32 0, i64 %indvars.iv155, i32 0, i32 16
+  br i1 %cmp108, label %if.then.110, label %if.else
+
+if.then.110:                                      ; preds = %for.body.101
+  store i32 0, i32* %sfb_lmax, align 8
+  %sfb_smax = getelementptr inbounds %struct.III_side_info_t.7.62.139.227.293, %struct.III_side_info_t.7.62.139.227.293* %l3_side, i64 0, i32 4, i64 %indvars.iv157, i32 0, i64 %indvars.iv155, i32 0, i32 17
+  store i32 0, i32* %sfb_smax, align 4
+  br label %for.inc.114
+
+if.else:                                          ; preds = %for.body.101
+  store i32 21, i32* %sfb_lmax, align 8
+  %sfb_smax112 = getelementptr inbounds %struct.III_side_info_t.7.62.139.227.293, %struct.III_side_info_t.7.62.139.227.293* %l3_side, i64 0, i32 4, i64 %indvars.iv157, i32 0, i64 %indvars.iv155, i32 0, i32 17
+  store i32 12, i32* %sfb_smax112, align 4
+  br label %for.inc.114
+
+for.inc.114:                                      ; preds = %if.else, %if.then.110
+  %indvars.iv.next156 = add nuw nsw i64 %indvars.iv155, 1
+  %3 = load i32, i32* %stereo, align 4
+  %4 = sext i32 %3 to i64
+  %cmp99 = icmp slt i64 %indvars.iv.next156, %4
+  br i1 %cmp99, label %for.body.101, label %for.inc.117
+
+for.inc.117:                                      ; preds = %for.inc.114, %for.cond.98.preheader
+  %indvars.iv.next158 = add nuw nsw i64 %indvars.iv157, 1
+  %5 = load i32, i32* %mode_gr, align 8
+  %6 = sext i32 %5 to i64
+  %cmp95 = icmp slt i64 %indvars.iv.next158, %6
+  br i1 %cmp95, label %for.cond.98.preheader, label %for.cond.120.preheader
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
diff --git a/final/test/Isl/CodeGen/scev_looking_through_bitcasts.ll b/final/test/Isl/CodeGen/scev_looking_through_bitcasts.ll
new file mode 100644
index 0000000..1012e23
--- /dev/null
+++ b/final/test/Isl/CodeGen/scev_looking_through_bitcasts.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; Scalar write of bitcasted value. Instead of writing %b of type
+; %structty, the SCEV expression looks through the bitcast such that
+; SCEVExpander returns %add.ptr81.i of type i8* to be the new value
+; of %b.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%structty = type { %structty*, %structty*, i32, [2 x i64] }
+
+define void @bitmap_set_range() {
+entry:
+  %a = ptrtoint i8* undef to i64
+  br label %cond.end32.i
+
+cond.end32.i:
+  br i1 false, label %cond.true67.i, label %cond.end73.i
+
+cond.true67.i:
+  br label %cond.end73.i
+
+cond.end73.i:
+  %add.ptr81.i = getelementptr inbounds i8, i8* null, i64 %a
+  %b = bitcast i8* %add.ptr81.i to %structty*
+  br label %bitmap_element_allocate.exit
+
+bitmap_element_allocate.exit:
+  %tobool43 = icmp eq %structty* %b, null
+  ret void
+}
+
+
+; CHECK:       polly.stmt.cond.end73.i:
+; CHECK-NEXT:   %0 = bitcast %structty** %b.s2a to i8**
+; CHECK-NEXT:   store i8* undef, i8** %0
+; CHECK-NEXT:   br label %polly.exiting
diff --git a/final/test/Isl/CodeGen/scop_expander_insert_point.ll b/final/test/Isl/CodeGen/scop_expander_insert_point.ll
new file mode 100644
index 0000000..f050c16
--- /dev/null
+++ b/final/test/Isl/CodeGen/scop_expander_insert_point.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-codegen -S \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+; CHECK:      entry:
+; CHECK-NEXT:   %outvalue.141.phiops = alloca i64
+; CHECK-NEXT:   %.preload.s2a = alloca i8
+; CHECK-NEXT:   %divpolly = sdiv i32 undef, 1
+; CHECK-NEXT:   %div = sdiv i32 undef, undef
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @int_downsample() #0 {
+entry:
+  %div = sdiv i32 undef, undef
+  br label %for.cond10.preheader.lr.ph
+
+for.cond10.preheader.lr.ph:                       ; preds = %entry
+  br label %for.body17.lr.ph
+
+for.body17.lr.ph:                                 ; preds = %for.end22, %for.cond10.preheader.lr.ph
+  %outcol_h.048 = phi i32 [ 0, %for.cond10.preheader.lr.ph ], [ %add31, %for.end22 ]
+  %0 = load i8*, i8** undef
+  %idx.ext = zext i32 %outcol_h.048 to i64
+  %add.ptr = getelementptr inbounds i8, i8* %0, i64 %idx.ext
+  br label %for.body17
+
+for.body17:                                       ; preds = %for.body17, %for.body17.lr.ph
+  %outvalue.141 = phi i64 [ undef, %for.body17.lr.ph ], [ %add19, %for.body17 ]
+  %inptr.040 = phi i8* [ %add.ptr, %for.body17.lr.ph ], [ undef, %for.body17 ]
+  %1 = load i8, i8* %inptr.040
+  %add19 = mul nsw i64 0, %outvalue.141
+  br i1 false, label %for.body17, label %for.end22
+
+for.end22:                                        ; preds = %for.body17
+  %add31 = add i32 %outcol_h.048, %div
+  br i1 undef, label %for.body17.lr.ph, label %for.end32
+
+for.end32:                                        ; preds = %for.end22
+  br label %for.end36
+
+for.end36:                                        ; preds = %for.end32
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/scop_expander_segfault.ll b/final/test/Isl/CodeGen/scop_expander_segfault.ll
new file mode 100644
index 0000000..1049153
--- /dev/null
+++ b/final/test/Isl/CodeGen/scop_expander_segfault.ll
@@ -0,0 +1,31 @@
+; RUN: opt %loadPolly -polly-codegen -S %s | FileCheck %s
+;
+; This test was extracted from gcc in SPEC2006 and it crashed our code
+; generation, or to be more precise, the ScopExpander due to a endless
+; recursion. It was fixed in r261474 (git: 61cba205ca59).
+;
+; CHECK: polly.start:
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @lex_number(i8* %str) {
+entry:
+  br label %for.end
+
+for.end:                                          ; preds = %entry
+  %0 = load i8, i8* %str, align 1
+  %cmp17 = icmp eq i8 %0, 48
+  br i1 %cmp17, label %land.lhs.true34, label %lor.lhs.false81
+
+land.lhs.true34:                                  ; preds = %for.end
+  %arrayidx35 = getelementptr inbounds i8, i8* %str, i64 1
+  %str.arrayidx35 = select i1 undef, i8* %str, i8* %arrayidx35
+  br label %lor.lhs.false81
+
+lor.lhs.false81:                                  ; preds = %land.lhs.true34, %for.end
+  %p.0 = phi i8* [ %str.arrayidx35, %land.lhs.true34 ], [ %str, %for.end ]
+  br label %do.body172
+
+do.body172:                                       ; preds = %lor.lhs.false81
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/scop_never_executed_runtime_check_location.ll b/final/test/Isl/CodeGen/scop_never_executed_runtime_check_location.ll
new file mode 100644
index 0000000..07c92e5
--- /dev/null
+++ b/final/test/Isl/CodeGen/scop_never_executed_runtime_check_location.ll
@@ -0,0 +1,31 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+
+; Verify that we generate the runtime check code after the conditional branch
+; in the SCoP region entering block (here %entry).
+;
+; CHECK:      entry:
+; CHECK-NEXT:   %0 = zext i32 %n to i64
+; CHECK-NEXT:   br i1 false
+;
+; CHECK:       %[[T0:[._a-zA-Z0-9]]] = sext i32 %n to i64
+; CHECK:       %[[T1:[._a-zA-Z0-9]]] = icmp sge i64 %[[T0]], 1
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @init_array(i32 %n, double* %data) {
+entry:
+  %0 = zext i32 %n to i64
+  br i1 false, label %for.end10, label %for.body4
+
+for.body4:                                        ; preds = %for.body4, %entry
+  %indvar1 = phi i64 [ %indvar.next2, %for.body4 ], [ 0, %entry ]
+  %.moved.to.for.body4 = mul i64 %0, %indvar1
+  %1 = add i64 %.moved.to.for.body4, 0
+  %arrayidx7 = getelementptr double, double* %data, i64 %1
+  store double undef, double* %arrayidx7, align 8
+  %indvar.next2 = add i64 %indvar1, 1
+  br i1 false, label %for.body4, label %for.end10
+
+for.end10:                                        ; preds = %for.body4
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/select-base-pointer.ll b/final/test/Isl/CodeGen/select-base-pointer.ll
new file mode 100644
index 0000000..5b53baa
--- /dev/null
+++ b/final/test/Isl/CodeGen/select-base-pointer.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -tbaa -polly-codegen -disable-output %s
+;
+; Check that we do not crash here.
+;
+; ModuleID = 'bugpoint-reduced-simplified.bc'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%"DOMParentNode" = type { %"DOMNode"*, %"DOMNode"*, %"DOMNodeListImpl" }
+%"DOMDocumentRange" = type { i32 (...)** }
+%"DOMXPathEvaluator" = type { i32 (...)** }
+%"DOMDocumentTraversal" = type { i32 (...)** }
+%"DOMNode" = type { i32 (...)** }
+%"DOMNodeListImpl" = type { %"DOMNodeList", %"DOMNode"* }
+%"DOMNodeList" = type { i32 (...)** }
+%"DOMElementImpl" = type { %"DOMElement", %"DOMNodeImpl", %"DOMParentNode", %"DOMChildNode", %"DOMAttrMapImpl"*, %"DOMAttrMapImpl"*, i16* }
+%"DOMElement" = type { %"DOMNode" }
+%"DOMNodeImpl" = type <{ %"DOMNode"*, i16, [6 x i8] }>
+%"DOMChildNode" = type { %"DOMNode"*, %"DOMNode"* }
+%"DOMAttrMapImpl" = type <{ %"DOMNamedNodeMapImpl", i8, [7 x i8] }>
+%"DOMNamedNodeMapImpl" = type { %"DOMNamedNodeMap", %"DOMNode"* }
+%"DOMNamedNodeMap" = type { i32 (...)** }
+%"DOMTextImpl" = type { %"DOMText", %"DOMNodeImpl", %"DOMChildNode" }
+%"DOMText" = type { %"DOMCharacterData" }
+%"DOMCharacterData" = type { %"DOMNode" }
+
+; Function Attrs: uwtable
+define void @_ZN11xercesc_2_513DOMParentNode9lastChildEPNS_7DOMNodeE(%"DOMParentNode"* %this, %"DOMNode"* %node) #0 align 2 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %fFirstChild = getelementptr inbounds %"DOMParentNode", %"DOMParentNode"* %this, i32 0, i32 1
+  %0 = load %"DOMNode"*, %"DOMNode"** %fFirstChild, align 8, !tbaa !1
+  %cmp = icmp ne %"DOMNode"* %0, null
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry.split
+  %1 = bitcast %"DOMNode"* %0 to %"DOMElementImpl"*
+  %fNode.i = getelementptr inbounds %"DOMElementImpl", %"DOMElementImpl"* %1, i32 0, i32 1
+  %flags.i.i = getelementptr inbounds %"DOMNodeImpl", %"DOMNodeImpl"* %fNode.i, i32 0, i32 1
+  %2 = load i16, i16* %flags.i.i, align 8, !tbaa !7
+  %3 = bitcast %"DOMNode"* %0 to %"DOMTextImpl"*
+  %fChild.i = getelementptr inbounds %"DOMTextImpl", %"DOMTextImpl"* %3, i32 0, i32 2
+  %fChild1.i = getelementptr inbounds %"DOMElementImpl", %"DOMElementImpl"* %1, i32 0, i32 3
+  %retval.0.i = select i1 undef, %"DOMChildNode"* %fChild.i, %"DOMChildNode"* %fChild1.i
+  %previousSibling = getelementptr inbounds %"DOMChildNode", %"DOMChildNode"* %retval.0.i, i32 0, i32 0
+  store %"DOMNode"* %node, %"DOMNode"** %previousSibling, align 8, !tbaa !10
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry.split
+  ret void
+}
+
+!0 = !{!"clang version 3.9.0 (http://llvm.org/git/clang.git 8518d88c3151548eb6d8a7a0bb28c73f65acd897)"}
+!1 = !{!2, !3, i64 8}
+!2 = !{!"_ZTSN11xercesc_2_513DOMParentNodeE", !3, i64 0, !3, i64 8, !6, i64 16}
+!3 = !{!"any pointer", !4, i64 0}
+!4 = !{!"omnipotent char", !5, i64 0}
+!5 = !{!"Simple C++ TBAA"}
+!6 = !{!"_ZTSN11xercesc_2_515DOMNodeListImplE", !3, i64 8}
+!7 = !{!8, !9, i64 8}
+!8 = !{!"_ZTSN11xercesc_2_511DOMNodeImplE", !3, i64 0, !9, i64 8}
+!9 = !{!"short", !4, i64 0}
+!10 = !{!11, !3, i64 0}
+!11 = !{!"_ZTSN11xercesc_2_512DOMChildNodeE", !3, i64 0, !3, i64 8}
diff --git a/final/test/Isl/CodeGen/sequential_loops.ll b/final/test/Isl/CodeGen/sequential_loops.ll
new file mode 100644
index 0000000..b43dd25
--- /dev/null
+++ b/final/test/Isl/CodeGen/sequential_loops.ll
@@ -0,0 +1,137 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s
+
+;#include <string.h>
+;#define N 1024
+;
+;int A[N];
+;
+;void sequential_loops() {
+;  int i;
+;  for (i = 0; i < N/2; i++) {
+;    A[i] = 1;
+;  }
+;  for (i = N/2 ; i < N; i++) {
+;    A[i] = 2;
+;  }
+;}
+;
+;int main () {
+;  int i;
+;  memset(A, 0, sizeof(int) * N);
+;
+;  sequential_loops();
+;
+;  for (i = 0; i < N; i++) {
+;    if (A[i] != 1 && i < N/2)
+;      return 1;
+;    if (A[i] !=  2 && i >= N/2)
+;      return 1;
+;  }
+;
+;  return 0;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x i32] zeroinitializer, align 4 ; <[1024 x i32]*> [#uses=5]
+
+define void @sequential_loops() nounwind {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb3, %bb
+  %indvar1 = phi i64 [ %indvar.next2, %bb3 ], [ 0, %bb ]
+  %scevgep4 = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvar1
+  %exitcond3 = icmp ne i64 %indvar1, 512
+  br i1 %exitcond3, label %bb2, label %bb4
+
+bb2:                                              ; preds = %bb1
+  store i32 1, i32* %scevgep4
+  br label %bb3
+
+bb3:                                              ; preds = %bb2
+  %indvar.next2 = add i64 %indvar1, 1
+  br label %bb1
+
+bb4:                                              ; preds = %bb1
+  br label %bb5
+
+bb5:                                              ; preds = %bb7, %bb4
+  %indvar = phi i64 [ %indvar.next, %bb7 ], [ 0, %bb4 ]
+  %tmp = add i64 %indvar, 512
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %tmp
+  %exitcond = icmp ne i64 %indvar, 512
+  br i1 %exitcond, label %bb6, label %bb8
+
+bb6:                                              ; preds = %bb5
+  store i32 2, i32* %scevgep
+  br label %bb7
+
+bb7:                                              ; preds = %bb6
+  %indvar.next = add i64 %indvar, 1
+  br label %bb5
+
+bb8:                                              ; preds = %bb5
+  ret void
+}
+
+define i32 @main() nounwind {
+bb:
+  call void @llvm.memset.p0i8.i64(i8* bitcast ([1024 x i32]* @A to i8*), i8 0, i64 4096, i32 1, i1 false)
+  call void @sequential_loops()
+  br label %bb1
+
+bb1:                                              ; preds = %bb15, %bb
+  %indvar = phi i64 [ %indvar.next, %bb15 ], [ 0, %bb ]
+  %i.0 = trunc i64 %indvar to i32
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvar
+  %tmp = icmp slt i32 %i.0, 1024
+  br i1 %tmp, label %bb2, label %bb16
+
+bb2:                                              ; preds = %bb1
+  %tmp3 = load i32, i32* %scevgep
+  %tmp4 = icmp ne i32 %tmp3, 1
+  br i1 %tmp4, label %bb5, label %bb8
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = icmp slt i32 %i.0, 512
+  br i1 %tmp6, label %bb7, label %bb8
+
+bb7:                                              ; preds = %bb5
+  br label %bb17
+
+bb8:                                              ; preds = %bb5, %bb2
+  %tmp9 = load i32, i32* %scevgep
+  %tmp10 = icmp ne i32 %tmp9, 2
+  br i1 %tmp10, label %bb11, label %bb14
+
+bb11:                                             ; preds = %bb8
+  %tmp12 = icmp sge i32 %i.0, 512
+  br i1 %tmp12, label %bb13, label %bb14
+
+bb13:                                             ; preds = %bb11
+  br label %bb17
+
+bb14:                                             ; preds = %bb11, %bb8
+  br label %bb15
+
+bb15:                                             ; preds = %bb14
+  %indvar.next = add i64 %indvar, 1
+  br label %bb1
+
+bb16:                                             ; preds = %bb1
+  br label %bb17
+
+bb17:                                             ; preds = %bb16, %bb13, %bb7
+  %.0 = phi i32 [ 1, %bb7 ], [ 1, %bb13 ], [ 0, %bb16 ]
+  ret i32 %.0
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
+
+; CHECK: {
+; CHECK:   for (int c0 = 0; c0 <= 511; c0 += 1)
+; CHECK:     Stmt_bb2(c0);
+; CHECK:   for (int c0 = 0; c0 <= 511; c0 += 1)
+; CHECK:     Stmt_bb6(c0);
+; CHECK: }
diff --git a/final/test/Isl/CodeGen/simple_loop_non_single_exit.ll b/final/test/Isl/CodeGen/simple_loop_non_single_exit.ll
new file mode 100644
index 0000000..00bed09
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_loop_non_single_exit.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s -check-prefix=CHECK-CODE
+
+; void f(long A[], long N) {
+;   long i;
+;   if (true)
+;     for (i = 0; i < N; ++i)
+;       A[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br label %next
+
+next:
+  br i1 true, label %for.i, label %return
+
+for.i:
+  %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK-CODE: polly.split_new_and_old
+; CHECK-CODE: polly.merge_new_and_old
diff --git a/final/test/Isl/CodeGen/simple_loop_non_single_exit_2.ll b/final/test/Isl/CodeGen/simple_loop_non_single_exit_2.ll
new file mode 100644
index 0000000..e9d155c
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_loop_non_single_exit_2.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s -check-prefix=CHECK-CODE
+
+; void f(long A[], long N) {
+;   long i;
+;   if (true)
+;     if (true)
+;       for (i = 0; i < N; ++i)
+;         A[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br i1 true, label %next, label %return
+
+next:
+  br i1 true, label %for.i, label %return
+
+for.i:
+  %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK-CODE: polly.split_new_and_old
+; CHECK-CODE: polly.merge_new_and_old
diff --git a/final/test/Isl/CodeGen/simple_non_single_entry.ll b/final/test/Isl/CodeGen/simple_non_single_entry.ll
new file mode 100644
index 0000000..154764e
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_non_single_entry.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s -check-prefix=CHECK-CODE
+
+; void f(long A[], long N) {
+;   long i;
+;
+;  if (true){
+;    i = 0;
+;    goto next;
+;  }else{
+;    i = 1;
+;    goto next;
+; }
+;
+; next:
+;  if (true)
+;    goto for.i;
+;  else
+;    goto for.i;
+;
+; for.i:
+;   for (i = 0; i < N; ++i)
+;     A[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br i1 true, label %then1, label %else1
+
+then1:
+  br label %next
+
+else1:
+  br label %next
+
+next:
+  %sg = getelementptr i64, i64* %A, i64 42
+  store i64 undef, i64* %sg
+  br i1 true, label %then, label %else
+
+then:
+  br label %for.i.head
+
+else:
+  br label %for.i.head
+
+for.i.head:
+  br label %for.i.head1
+
+for.i.head1:
+  br label %for.i
+
+for.i:
+  %indvar = phi i64 [ 0, %for.i.head1], [ %indvar.next, %for.i ]
+  fence seq_cst
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK-CODE: polly.split_new_and_old
+; CHECK-CODE: polly.merge_new_and_old
diff --git a/final/test/Isl/CodeGen/simple_nonaffine_loop.ll b/final/test/Isl/CodeGen/simple_nonaffine_loop.ll
new file mode 100644
index 0000000..6de600b
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_nonaffine_loop.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-ast -polly-allow-nonaffine -analyze < %s | FileCheck %s
+
+;#include <stdio.h>
+;#include <stdlib.h>
+;#include <math.h>
+;
+;int main()
+;{
+;	int A[1024*1024];
+;	int i;
+;	for (i = 0; i < 1024; i++)
+;		A[i*i] = 2*i;
+;
+;	printf("Random Value: %d", A[rand() % 1024*1024]);
+;
+;	return 0;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+@.str = private unnamed_addr constant [17 x i8] c"Random Value: %d\00", align 1
+
+define i32 @main() nounwind uwtable ssp {
+entry:
+  %A = alloca [1048576 x i32], align 16
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %0 = phi i32 [ 0, %entry.split ], [ %1, %for.body ]
+  %mul = mul i32 %0, 2
+  %mul1 = mul nsw i32 %0, %0
+  %idxprom1 = zext i32 %mul1 to i64
+  %arrayidx = getelementptr inbounds [1048576 x i32], [1048576 x i32]* %A, i64 0, i64 %idxprom1
+  store i32 %mul, i32* %arrayidx, align 4
+  %1 = add nsw i32 %0, 1
+  %exitcond = icmp ne i32 %1, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body
+  %call = call i32 @rand() nounwind
+  %rem = srem i32 %call, 1024
+  %mul2 = shl nsw i32 %rem, 10
+  %idxprom3 = sext i32 %mul2 to i64
+  %arrayidx4 = getelementptr inbounds [1048576 x i32], [1048576 x i32]* %A, i64 0, i64 %idxprom3
+  %2 = load i32, i32* %arrayidx4, align 16
+  %call5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str, i64 0, i64 0), i32 %2) nounwind
+  ret i32 0
+}
+
+declare i32 @printf(i8*, ...)
+
+declare i32 @rand()
+
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK:   Stmt_for_body(c0);
diff --git a/final/test/Isl/CodeGen/simple_vec_assign_scalar.ll b/final/test/Isl/CodeGen/simple_vec_assign_scalar.ll
new file mode 100644
index 0000000..0210684
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_assign_scalar.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen \
+; RUN: -polly-vectorizer=polly -dce -S < %s | FileCheck %s
+
+; RUN: opt %loadPolly -basicaa -polly-codegen -polly-vectorizer=stripmine -dce -S < %s | FileCheck %s --check-prefix=STRIPMINE
+
+;#define N 1024
+;float A[N];
+;float B[N];
+;
+;void simple_vec_const(void) {
+;  int i;
+;
+;  for (i = 0; i < 4; i++)
+;    B[i] = A[i] + 1;
+;}
+;int main()
+;{
+;  simple_vec_const();
+;  return A[42];
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float] zeroinitializer, align 16
+@B = common global [1024 x float] zeroinitializer, align 16
+
+define void @simple_vec_const() nounwind {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb5, %bb
+  %indvar = phi i64 [ %indvar.next, %bb5 ], [ 0, %bb ]
+  %scevgep = getelementptr [1024 x float], [1024 x float]* @B, i64 0, i64 %indvar
+  %scevgep1 = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  %exitcond = icmp ne i64 %indvar, 4
+  br i1 %exitcond, label %bb3, label %bb6
+
+bb3:                                              ; preds = %bb2
+  %tmp = load float, float* %scevgep1, align 4
+  %tmp4 = fadd float %tmp, 1.000000e+00
+  store float %tmp4, float* %scevgep, align 4
+  br label %bb5
+
+bb5:                                              ; preds = %bb3
+  %indvar.next = add i64 %indvar, 1
+  br label %bb2
+
+bb6:                                              ; preds = %bb2
+  ret void
+}
+
+define i32 @main() nounwind {
+bb:
+  call void @simple_vec_const()
+  %tmp = load float, float* getelementptr inbounds ([1024 x float], [1024 x float]* @A, i64 0, i64 42), align 8
+  %tmp1 = fptosi float %tmp to i32
+  ret i32 %tmp1
+}
+
+; STRIPMINE-NOT: <4 x float>
+
+; CHECK: %tmp_p_vec_full = load <4 x float>, <4 x float>* bitcast ([1024 x float]* @A to <4 x float>*), align 8, !alias.scope !0, !noalias !2
+; CHECK: %tmp4p_vec = fadd <4 x float> %tmp_p_vec_full, <float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
+; CHECK: store <4 x float> %tmp4p_vec, <4 x float>* bitcast ([1024 x float]* @B to <4 x float>*)
diff --git a/final/test/Isl/CodeGen/simple_vec_assign_scalar_2.ll b/final/test/Isl/CodeGen/simple_vec_assign_scalar_2.ll
new file mode 100644
index 0000000..8cdbd20
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_assign_scalar_2.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -polly-vectorizer=polly -dce -S < %s | FileCheck %s
+
+;#define N 1024
+;float A[N];
+;float B[N];
+;
+;void simple_vec_const(void) {
+;  int i;
+;
+;  for (i = 0; i < 4; i++)
+;    B[i] = A[i] + i;
+;}
+;int main()
+;{
+;  simple_vec_const();
+;  return A[42];
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float] zeroinitializer, align 16
+@B = common global [1024 x float] zeroinitializer, align 16
+
+define void @simple_vec_const() nounwind {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb6, %bb
+  %indvar = phi i64 [ %indvar.next, %bb6 ], [ 0, %bb ]
+  %scevgep = getelementptr [1024 x float], [1024 x float]* @B, i64 0, i64 %indvar
+  %i.0 = trunc i64 %indvar to i32
+  %scevgep1 = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  %exitcond = icmp ne i64 %indvar, 4
+  br i1 %exitcond, label %bb3, label %bb7
+
+bb3:                                              ; preds = %bb2
+  %tmp = load float, float* %scevgep1, align 4
+  %tmp4 = sitofp i32 %i.0 to float
+  %tmp5 = fadd float %tmp, %tmp4
+  store float %tmp5, float* %scevgep, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb3
+  %indvar.next = add i64 %indvar, 1
+  br label %bb2
+
+bb7:                                              ; preds = %bb2
+  ret void
+}
+
+define i32 @main() nounwind {
+bb:
+  call void @simple_vec_const()
+  %tmp = load float, float* getelementptr inbounds ([1024 x float], [1024 x float]* @A, i64 0, i64 42), align 8
+  %tmp1 = fptosi float %tmp to i32
+  ret i32 %tmp1
+}
+
+
+; CHECK: insertelement <4 x float> undef, float %{{[^,]+}}, i32 0
+; CHECK: insertelement <4 x float> %0, float %{{[^,]+}}, i32 1
+; CHECK: insertelement <4 x float> %1, float %{{[^,]+}}, i32 2
+; CHECK: insertelement <4 x float> %2, float %{{[^,]+}}, i32 3
+; CHECK: fadd <4 x float> %tmp_p_vec_full, %3
+
diff --git a/final/test/Isl/CodeGen/simple_vec_call.ll b/final/test/Isl/CodeGen/simple_vec_call.ll
new file mode 100644
index 0000000..d672f54
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_call.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -polly-vectorizer=polly -S \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float] zeroinitializer, align 16
+@B = common global [1024 x float] zeroinitializer, align 16
+
+declare float @foo(float) readnone
+
+define void @simple_vec_call() nounwind {
+entry:
+  br label %body
+
+body:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar_next, %body ]
+  %scevgep = getelementptr [1024 x float], [1024 x float]* @B, i64 0, i64 %indvar
+  %value = load float, float* getelementptr inbounds ([1024 x float], [1024 x float]* @A, i64 0, i64 0), align 16
+  %result = tail call float @foo(float %value) nounwind
+  store float %result, float* %scevgep, align 4
+  %indvar_next = add i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar_next, 4
+  br i1 %exitcond, label %return, label %body
+
+return:
+  ret void
+}
+
+; CHECK: [[RES1:%[a-zA-Z0-9_]+]] = tail call float @foo(float %.load) [[NUW:#[0-9]+]]
+; CHECK: [[RES2:%[a-zA-Z0-9_]+]] = tail call float @foo(float %.load) [[NUW]]
+; CHECK: [[RES3:%[a-zA-Z0-9_]+]] = tail call float @foo(float %.load) [[NUW]]
+; CHECK: [[RES4:%[a-zA-Z0-9_]+]] = tail call float @foo(float %.load) [[NUW]]
+; CHECK: [[RES5:%[a-zA-Z0-9_]+]] = insertelement <4 x float> undef, float [[RES1]], i32 0
+; CHECK: [[RES6:%[a-zA-Z0-9_]+]] = insertelement <4 x float> [[RES5]], float [[RES2]], i32 1
+; CHECK: [[RES7:%[a-zA-Z0-9_]+]] = insertelement <4 x float> [[RES6]], float [[RES3]], i32 2
+; CHECK: [[RES8:%[a-zA-Z0-9_]+]] = insertelement <4 x float> [[RES7]], float [[RES4]], i32 3
+; CHECK:  store <4 x float> [[RES8]]
+; CHECK: attributes [[NUW]] = { nounwind }
diff --git a/final/test/Isl/CodeGen/simple_vec_call_2.ll b/final/test/Isl/CodeGen/simple_vec_call_2.ll
new file mode 100644
index 0000000..0ba1226
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_call_2.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -polly-vectorizer=polly -dce \
+; RUN: -polly-invariant-load-hoisting=true -S < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float] zeroinitializer, align 16
+@B = common global [1024 x float**] zeroinitializer, align 16
+
+declare float** @foo(float) readnone
+
+define void @simple_vec_call() nounwind {
+entry:
+  br label %body
+
+body:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar_next, %body ]
+  %scevgep = getelementptr [1024 x float**], [1024 x float**]* @B, i64 0, i64 %indvar
+  %value = load float, float* getelementptr inbounds ([1024 x float], [1024 x float]* @A, i64 0, i64 0), align 16
+  %result = tail call float** @foo(float %value) nounwind
+  store float** %result, float*** %scevgep, align 4
+  %indvar_next = add i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar_next, 4
+  br i1 %exitcond, label %return, label %body
+
+return:
+  ret void
+}
+
+; CHECK: [[RES1:%[a-zA-Z0-9_]+]] = tail call float** @foo(float %.load) [[NUW:#[0-9]+]]
+; CHECK: [[RES2:%[a-zA-Z0-9_]+]] = tail call float** @foo(float %.load) [[NUW]]
+; CHECK: [[RES3:%[a-zA-Z0-9_]+]] = tail call float** @foo(float %.load) [[NUW]]
+; CHECK: [[RES4:%[a-zA-Z0-9_]+]] = tail call float** @foo(float %.load) [[NUW]]
+; CHECK: %0 = insertelement <4 x float**> undef, float** %p_result, i32 0
+; CHECK: %1 = insertelement <4 x float**> %0, float** %p_result1, i32 1
+; CHECK: %2 = insertelement <4 x float**> %1, float** %p_result2, i32 2
+; CHECK: %3 = insertelement <4 x float**> %2, float** %p_result3, i32 3
+; CHECK: store <4 x float**> %3, <4 x float**>* bitcast ([1024 x float**]* @B to <4 x float**>*), align
+; CHECK: attributes [[NUW]] = { nounwind }
diff --git a/final/test/Isl/CodeGen/simple_vec_cast.ll b/final/test/Isl/CodeGen/simple_vec_cast.ll
new file mode 100644
index 0000000..69df1e1
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_cast.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -polly-vectorizer=polly \
+; RUN: -polly-invariant-load-hoisting=true -dce -S < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float] zeroinitializer, align 16
+@B = common global [1024 x double] zeroinitializer, align 16
+
+define void @simple_vec_const() nounwind {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb3, %bb
+  %indvar = phi i64 [ %indvar.next, %bb3 ], [ 0, %bb ]
+  %scevgep = getelementptr [1024 x double], [1024 x double]* @B, i64 0, i64 %indvar
+  %exitcond = icmp ne i64 %indvar, 4
+  br i1 %exitcond, label %bb2, label %bb4
+
+bb2:                                              ; preds = %bb1
+  %tmp = load float, float* getelementptr inbounds ([1024 x float], [1024 x float]* @A, i64 0, i64 0), align 16
+  %tmp2 = fpext float %tmp to double
+  store double %tmp2, double* %scevgep, align 4
+  br label %bb3
+
+bb3:                                              ; preds = %bb2
+  %indvar.next = add i64 %indvar, 1
+  br label %bb1
+
+bb4:                                              ; preds = %bb1
+  ret void
+}
+
+; CHECK:   %.load = load float, float* getelementptr inbounds ([1024 x float], [1024 x float]* @A, i32 0, i32 0)
+
+; CHECK: polly.stmt.bb2:                                   ; preds = %polly.start
+; CHECK:   %tmp_p.splatinsert = insertelement <4 x float> undef, float %.load, i32 0
+; CHECK:   %tmp_p.splat = shufflevector <4 x float> %tmp_p.splatinsert, <4 x float> undef, <4 x i32> zeroinitializer
+; CHECK:   %0 = fpext <4 x float> %tmp_p.splat to <4 x double>
+; CHECK:   store <4 x double> %0, <4 x double>*
diff --git a/final/test/Isl/CodeGen/simple_vec_const.ll b/final/test/Isl/CodeGen/simple_vec_const.ll
new file mode 100644
index 0000000..c271639
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_const.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -polly-vectorizer=polly -S \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+
+;#define N 1024
+;float A[N];
+;float B[N];
+;
+;void simple_vec_const(void) {
+;  int i;
+;
+;  for (i = 0; i < 4; i++)
+;    B[i] = A[0];
+;}
+;int main()
+;{
+;  simple_vec_const();
+;  return A[42];
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float] zeroinitializer, align 16
+@B = common global [1024 x float] zeroinitializer, align 16
+
+define void @simple_vec_const() nounwind {
+; <label>:0
+  br label %1
+
+; <label>:1                                       ; preds = %4, %0
+  %indvar = phi i64 [ %indvar.next, %4 ], [ 0, %0 ]
+  %scevgep = getelementptr [1024 x float], [1024 x float]* @B, i64 0, i64 %indvar
+  %exitcond = icmp ne i64 %indvar, 4
+  br i1 %exitcond, label %2, label %5
+
+; <label>:2                                       ; preds = %1
+  %3 = load float, float* getelementptr inbounds ([1024 x float], [1024 x float]* @A, i64 0, i64 0), align 16
+  store float %3, float* %scevgep, align 4
+  br label %4
+
+; <label>:4                                       ; preds = %2
+  %indvar.next = add i64 %indvar, 1
+  br label %1
+
+; <label>:5                                       ; preds = %1
+  ret void
+}
+
+define i32 @main() nounwind {
+  call void @simple_vec_const()
+  %1 = load float, float* getelementptr inbounds ([1024 x float], [1024 x float]* @A, i64 0, i64 42), align 8
+  %2 = fptosi float %1 to i32
+  ret i32 %2
+}
+
+
+; CHECK:   %.load = load float, float* getelementptr inbounds ([1024 x float], [1024 x float]* @A, i32 0, i32 0)
+
+; CHECK: polly.stmt.:                                      ; preds = %polly.start
+; CHECK:   %_p.splatinsert = insertelement <4 x float> undef, float %.load, i32 0
+; CHECK:   %_p.splat = shufflevector <4 x float> %_p.splatinsert, <4 x float> undef, <4 x i32> zeroinitializer
diff --git a/final/test/Isl/CodeGen/simple_vec_large_width.ll b/final/test/Isl/CodeGen/simple_vec_large_width.ll
new file mode 100644
index 0000000..75f5d20
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_large_width.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -polly-vectorizer=polly -dce -S < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float] zeroinitializer, align 16
+@B = common global [1024 x float] zeroinitializer, align 16
+
+define void @simple_vec_large_width() nounwind {
+; <label>:0
+  br label %1
+
+; <label>:1                                       ; preds = %4, %0
+  %indvar = phi i64 [ %indvar.next, %4 ], [ 0, %0 ]
+  %scevgep = getelementptr [1024 x float], [1024 x float]* @B, i64 0, i64 %indvar
+  %scevgep1 = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  %exitcond = icmp ne i64 %indvar, 15
+  br i1 %exitcond, label %2, label %5
+
+; <label>:2                                       ; preds = %1
+  %3 = load float, float* %scevgep1, align 4
+  store float %3, float* %scevgep, align 4
+  br label %4
+
+; <label>:4                                       ; preds = %2
+  %indvar.next = add i64 %indvar, 1
+  br label %1
+
+; <label>:5                                       ; preds = %1
+  ret void
+}
+
+define i32 @main() nounwind {
+  call void @simple_vec_large_width()
+  %1 = load float, float* getelementptr inbounds ([1024 x float], [1024 x float]* @A, i64 0, i64 42), align 8
+  %2 = fptosi float %1 to i32
+  ret i32 %2
+}
+
+; CHECK: [[VEC1:%[a-zA-Z0-9_]+_full]] = load <15 x float>, <15 x float>*
+; CHECK: store <15 x float> [[VEC1]]
diff --git a/final/test/Isl/CodeGen/simple_vec_ptr_ptr_ty.ll b/final/test/Isl/CodeGen/simple_vec_ptr_ptr_ty.ll
new file mode 100644
index 0000000..d8806dc
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_ptr_ptr_ty.ll
@@ -0,0 +1,31 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -polly-vectorizer=polly -S \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float**] zeroinitializer, align 16
+@B = common global [1024 x float**] zeroinitializer, align 16
+
+declare float @foo(float) readnone
+
+define void @simple_vec_call() nounwind {
+entry:
+  br label %body
+
+body:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar_next, %body ]
+  %scevgep = getelementptr [1024 x float**], [1024 x float**]* @B, i64 0, i64 %indvar
+  %value = load float**, float*** getelementptr inbounds ([1024 x float**], [1024 x float**]* @A, i64 0, i64 0), align 16
+  store float** %value, float*** %scevgep, align 4
+  %indvar_next = add i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar_next, 4
+  br i1 %exitcond, label %return, label %body
+
+return:
+  ret void
+}
+; CHECK:   %.load = load float**, float*** getelementptr inbounds ([1024 x float**], [1024 x float**]* @A, i32 0, i32 0)
+
+; CHECK-NOT: load <1 x float**>
+; CHECK: %value_p.splatinsert = insertelement <4 x float**> undef, float** %.load, i32 0
+; CHECK: %value_p.splat = shufflevector <4 x float**> %value_p.splatinsert, <4 x float**> undef, <4 x i32> zeroinitializer
+; CHECK: store <4 x float**> %value_p.splat, <4 x float**>* bitcast ([1024 x float**]* @B to <4 x float**>*), align 8
diff --git a/final/test/Isl/CodeGen/simple_vec_stride_negative_one.ll b/final/test/Isl/CodeGen/simple_vec_stride_negative_one.ll
new file mode 100644
index 0000000..59890c1
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_stride_negative_one.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-codegen -polly-vectorizer=polly -S < %s | FileCheck %s
+
+; ModuleID = 'reverse.c'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+;int A[100];
+;void foo() {
+;  for (int i=3; i >= 0; i--)
+;    A[i]+=1;
+;}
+
+
+@A = common global [100 x i32] zeroinitializer, align 16
+
+; Function Attrs: nounwind uwtable
+define void @foo() #0 {
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %entry, %for.body
+  %indvars.iv = phi i64 [ 3, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds [100 x i32], [100 x i32]* @A, i64 0, i64 %indvars.iv
+  %0 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %0, 1
+  store i32 %add, i32* %arrayidx, align 4
+  %indvars.iv.next = add nsw i64 %indvars.iv, -1
+  %1 = trunc i64 %indvars.iv to i32
+  %cmp = icmp sgt i32 %1, 0
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body
+  ret void
+}
+
+; CHECK: @foo
+; CHECK: [[LOAD:%[a-zA-Z0-9_]+]] = load <4 x i32>, <4 x i32>*
+; CHECK: [[REVERSE_LOAD:%[a-zA-Z0-9_]+reverse]] = shufflevector <4 x i32> [[LOAD]], <4 x i32> [[LOAD]], <4 x i32> <i32 3, i32 2, i32 1, i32 0>
diff --git a/final/test/Isl/CodeGen/simple_vec_stride_one.ll b/final/test/Isl/CodeGen/simple_vec_stride_one.ll
new file mode 100644
index 0000000..de3f371
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_stride_one.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-codegen -polly-vectorizer=polly \
+; RUN:                 < %s -S | FileCheck %s
+
+; CHECK: store <4 x double> %val.s2a_p_splat, <4 x double>* %vector_ptr
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @update_access_functions(i64 %arg, double* %A, double* %B) {
+bb3:
+  br label %loop1
+
+loop1:
+  %indvar = phi i64 [ %indvar.next, %loop1 ], [ 0, %bb3 ]
+  %ptr1 = getelementptr inbounds double, double* %A, i64 %indvar
+  store double 42.0, double* %ptr1, align 8
+  %indvar.next = add nuw nsw i64 %indvar, 1
+  %cmp = icmp ne i64 %indvar.next, 4
+  br i1 %cmp, label %loop1, label %loop2
+
+loop2:
+  %indvar.2 = phi i64 [ %indvar.2.next, %loop2 ], [ 0, %loop1 ]
+  %ptr2 = getelementptr inbounds double, double* %A, i64 %indvar.2
+  %val = load double, double* %ptr2, align 8
+  %indvar.2.next = add nuw nsw i64 %indvar.2, 1
+  %cmp.2 = icmp ne i64 %indvar.2.next, 4
+  br i1 %cmp.2, label %loop2, label %loop3
+
+loop3:
+  %indvar.3 = phi i64 [ %indvar.3.next, %loop3 ], [ 0, %loop2 ]
+  %ptr3 = getelementptr inbounds double, double* %A, i64 %indvar.3
+  store double %val, double* %ptr3, align 8
+  %indvar.3.next = add nuw nsw i64 %indvar.3, 1
+  %cmp.3 = icmp ne i64 %indvar.3.next, 4
+  br i1 %cmp.3, label %loop3, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/simple_vec_stride_x.ll b/final/test/Isl/CodeGen/simple_vec_stride_x.ll
new file mode 100644
index 0000000..50b0fef
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_stride_x.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -polly-vectorizer=polly  -dce -S < %s | FileCheck %s
+
+;#define N 1024
+;float A[N];
+;float B[N];
+;
+;void simple_vec_stride_x(void) {
+;  int i;
+;
+;  for (i = 0; i < 4; i++)
+;    B[2 * i] = A[2 * i];
+;}
+;int main()
+;{
+;  simple_vec_stride_x();
+;  return A[42];
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float] zeroinitializer, align 16
+@B = common global [1024 x float] zeroinitializer, align 16
+
+define void @simple_vec_stride_x() nounwind {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb5, %bb
+  %indvar = phi i64 [ %indvar.next, %bb5 ], [ 0, %bb ]
+  %tmp = mul i64 %indvar, 2
+  %scevgep = getelementptr [1024 x float], [1024 x float]* @B, i64 0, i64 %tmp
+  %scevgep1 = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %tmp
+  %exitcond = icmp ne i64 %indvar, 4
+  br i1 %exitcond, label %bb3, label %bb6
+
+bb3:                                              ; preds = %bb2
+  %tmp4 = load float, float* %scevgep1, align 8
+  store float %tmp4, float* %scevgep, align 8
+  br label %bb5
+
+bb5:                                              ; preds = %bb3
+  %indvar.next = add i64 %indvar, 1
+  br label %bb2
+
+bb6:                                              ; preds = %bb2
+  ret void
+}
+
+define i32 @main() nounwind {
+bb:
+  call void @simple_vec_stride_x()
+  %tmp = load float, float* getelementptr inbounds ([1024 x float], [1024 x float]* @A, i64 0, i64 42), align 8
+  %tmp1 = fptosi float %tmp to i32
+  ret i32 %tmp1
+}
+
+; CHECK: [[LOAD1:%[a-zA-Z0-9_]+_scalar_]] = load float, float*
+; CHECK: [[VEC1:%[a-zA-Z0-9_]+]] = insertelement <4 x float> undef, float [[LOAD1]], i32 0
+; CHECK: [[LOAD2:%[a-zA-Z0-9_]+]] = load float, float*
+; CHECK: [[VEC2:%[a-zA-Z0-9_]+]] = insertelement <4 x float> [[VEC1]], float [[LOAD2]], i32 1
+; CHECK: [[LOAD3:%[a-zA-Z0-9_]+]] = load float, float*
+; CHECK: [[VEC3:%[a-zA-Z0-9_]+]] = insertelement <4 x float> [[VEC2]], float [[LOAD3]], i32 2
+; CHECK: [[LOAD4:%[a-zA-Z0-9_]+]] = load float, float*
+; CHECK: [[VEC4:%[a-zA-Z0-9_]+]] = insertelement <4 x float> [[VEC3]], float [[LOAD4]], i32 3
+; CHECK: [[EL1:%[a-zA-Z0-9_]+]] = extractelement <4 x float> [[VEC4]], i32 0
+; CHECK: store float [[EL1]]
+; CHECK: [[EL2:%[a-zA-Z0-9_]+]] = extractelement <4 x float> [[VEC4]], i32 1
+; CHECK: store float [[EL2]]
+; CHECK: [[EL3:%[a-zA-Z0-9_]+]] = extractelement <4 x float> [[VEC4]], i32 2
+; CHECK: store float [[EL3]]
+; CHECK: [[EL4:%[a-zA-Z0-9_]+]] = extractelement <4 x float> [[VEC4]], i32 3
+; CHECK: store float [[EL4]]
diff --git a/final/test/Isl/CodeGen/simple_vec_strides_multidim.ll b/final/test/Isl/CodeGen/simple_vec_strides_multidim.ll
new file mode 100644
index 0000000..6c8cc46
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_strides_multidim.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-codegen -polly-vectorizer=polly -polly-prevect-width=8 -S -dce < %s | FileCheck %s
+;
+;    void foo(long n, float A[restrict][n], float B[restrict][n],
+;             float C[restrict][n], float D[restrict][n]) {
+;      for (long i = 0; i < 8; i++)
+;        for (long j = 0; j < 8; j++)
+;          A[i][j] += B[i][0] + C[i][2 * j] + D[j][0];
+;    }
+;
+
+; CHECK: shufflevector
+; CHECK: insertelement
+; CHECK: insertelement
+; CHECK: insertelement
+; CHECK: insertelement
+; CHECK: insertelement
+; CHECK: insertelement
+; CHECK: insertelement
+; CHECK: insertelement
+; CHECK: store <8 x float>
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %n, float* noalias %A, float* noalias %B, float* noalias %C, float* noalias %D) {
+bb:
+  br label %bb3
+
+bb3:                                              ; preds = %bb25, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp26, %bb25 ]
+  %exitcond2 = icmp ne i64 %i.0, 8
+  br i1 %exitcond2, label %bb4, label %bb27
+
+bb4:                                              ; preds = %bb3
+  br label %bb5
+
+bb5:                                              ; preds = %bb22, %bb4
+  %j.0 = phi i64 [ 0, %bb4 ], [ %tmp23, %bb22 ]
+  %exitcond = icmp ne i64 %j.0, 8
+  br i1 %exitcond, label %bb6, label %bb24
+
+bb6:                                              ; preds = %bb5
+  %tmp = mul nsw i64 %i.0, %n
+  %tmp7 = getelementptr inbounds float, float* %B, i64 %tmp
+  %tmp8 = load float, float* %tmp7, align 4
+  %tmp9 = shl nsw i64 %j.0, 1
+  %tmp10 = mul nsw i64 %i.0, %n
+  %.sum = add i64 %tmp10, %tmp9
+  %tmp11 = getelementptr inbounds float, float* %C, i64 %.sum
+  %tmp12 = load float, float* %tmp11, align 4
+  %tmp13 = fadd float %tmp8, %tmp12
+  %tmp14 = mul nsw i64 %j.0, %n
+  %tmp15 = getelementptr inbounds float, float* %D, i64 %tmp14
+  %tmp16 = load float, float* %tmp15, align 4
+  %tmp17 = fadd float %tmp13, %tmp16
+  %tmp18 = mul nsw i64 %i.0, %n
+  %.sum1 = add i64 %tmp18, %j.0
+  %tmp19 = getelementptr inbounds float, float* %A, i64 %.sum1
+  %tmp20 = load float, float* %tmp19, align 4
+  %tmp21 = fadd float %tmp20, %tmp17
+  store float %tmp21, float* %tmp19, align 4
+  br label %bb22
+
+bb22:                                             ; preds = %bb6
+  %tmp23 = add nsw i64 %j.0, 1
+  br label %bb5
+
+bb24:                                             ; preds = %bb5
+  br label %bb25
+
+bb25:                                             ; preds = %bb24
+  %tmp26 = add nsw i64 %i.0, 1
+  br label %bb3
+
+bb27:                                             ; preds = %bb3
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/simple_vec_two_stmts.ll b/final/test/Isl/CodeGen/simple_vec_two_stmts.ll
new file mode 100644
index 0000000..81f15ae
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_two_stmts.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -basicaa -polly-codegen -polly-vectorizer=polly -dce -S < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float] zeroinitializer, align 16
+@B = common global [1024 x float] zeroinitializer, align 16
+@C = common global [1024 x float] zeroinitializer, align 16
+
+define void @simple_vec_stride_one() nounwind {
+bb0:
+  br label %bb1
+
+bb1:
+  %indvar = phi i64 [ %indvar.next, %bb4 ], [ 0, %bb0 ]
+  %scevgep = getelementptr [1024 x float], [1024 x float]* @B, i64 0, i64 %indvar
+  %scevgep2 = getelementptr [1024 x float], [1024 x float]* @C, i64 0, i64 %indvar
+  %scevgep1 = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  %exitcond = icmp ne i64 %indvar, 4
+  br i1 %exitcond, label %bb2a, label %bb5
+
+bb2a:
+  %tmp1 = load float, float* %scevgep1, align 4
+  store float %tmp1, float* %scevgep, align 4
+  br label %bb2b
+
+bb2b:
+  %tmp2 = load float, float* %scevgep1, align 4
+  store float %tmp2, float* %scevgep2, align 4
+  br label %bb4
+
+bb4:
+  %indvar.next = add i64 %indvar, 1
+  br label %bb1
+
+bb5:
+  ret void
+}
+
+define i32 @main() nounwind {
+  call void @simple_vec_stride_one()
+  %1 = load float, float* getelementptr inbounds ([1024 x float], [1024 x float]* @A, i64 0, i64 42), align 8
+  %2 = fptosi float %1 to i32
+  ret i32 %2
+}
+
+; CHECK: [[LOAD1:%[a-zA-Z0-9_]+_full]] = load <4 x float>, <4 x float>*
+; CHECK: store <4 x float> [[LOAD1]]
+; CHECK: [[LOAD2:%[a-zA-Z0-9_]+_full]] = load <4 x float>, <4 x float>*
+; CHECK: store <4 x float> [[LOAD2]]
+
diff --git a/final/test/Isl/CodeGen/single_do_loop_int_max_iterations.ll b/final/test/Isl/CodeGen/single_do_loop_int_max_iterations.ll
new file mode 100644
index 0000000..c784d27
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_do_loop_int_max_iterations.ll
@@ -0,0 +1,92 @@
+; RUN: opt %loadPolly -polly-ast -analyze  -S < %s | FileCheck %s
+
+;#define N 20
+;#include "limits.h"
+;#include <stdio.h>
+;int A[N];
+;
+;void single_do_loop_int_max_iterations() {
+;  int i;
+;
+;  __sync_synchronize();
+;
+;  i = 0;
+;
+;  do {
+;    A[0] = i;
+;    ++i;
+;  } while (i < INT_MAX);
+;
+;  __sync_synchronize();
+;}
+;
+;int main () {
+;  int i;
+;
+;  A[0] = 0;
+;
+;  single_do_loop_int_max_iterations();
+;
+;  fprintf(stdout, "Output %d\n", A[0]);
+;
+;  if (A[0] == INT_MAX - 1)
+;    return 0;
+;  else
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker = type { %struct._IO_marker*, %struct._IO_FILE*, i32 }
+
+@A = common global [20 x i32] zeroinitializer, align 4 ; <[20 x i32]*> [#uses=1]
+@stdout = external global %struct._IO_FILE*       ; <%struct._IO_FILE**> [#uses=1]
+@.str = private constant [11 x i8] c"Output %d\0A\00" ; <[11 x i8]*> [#uses=1]
+
+define void @single_do_loop_int_max_iterations() nounwind {
+entry:
+  fence seq_cst
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond, %entry
+  %0 = phi i32 [ 0, %entry ], [ %inc, %do.cond ]  ; <i32> [#uses=2]
+  store i32 %0, i32* getelementptr inbounds ([20 x i32], [20 x i32]* @A, i32 0, i32 0)
+  %inc = add nsw i32 %0, 1                        ; <i32> [#uses=2]
+  br label %do.cond
+
+do.cond:                                          ; preds = %do.body
+  %exitcond = icmp ne i32 %inc, 2147483647        ; <i1> [#uses=1]
+  br i1 %exitcond, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  fence seq_cst
+  ret void
+}
+
+define i32 @main() nounwind {
+entry:
+  store i32 0, i32* getelementptr inbounds ([20 x i32], [20 x i32]* @A, i32 0, i32 0)
+  call void @single_do_loop_int_max_iterations()
+  %tmp = load %struct._IO_FILE*, %struct._IO_FILE** @stdout          ; <%struct._IO_FILE*> [#uses=1]
+  %tmp1 = load i32, i32* getelementptr inbounds ([20 x i32], [20 x i32]* @A, i32 0, i32 0) ; <i32> [#uses=1]
+  %call = call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %tmp, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), i32 %tmp1) ; <i32> [#uses=0]
+  %tmp2 = load i32, i32* getelementptr inbounds ([20 x i32], [20 x i32]* @A, i32 0, i32 0) ; <i32> [#uses=1]
+  %cmp = icmp eq i32 %tmp2, 2147483646            ; <i1> [#uses=1]
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  br label %return
+
+if.else:                                          ; preds = %entry
+  br label %return
+
+return:                                           ; preds = %if.else, %if.then
+  %retval.0 = phi i32 [ 0, %if.then ], [ 1, %if.else ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+
+declare i32 @fprintf(%struct._IO_FILE*, i8*, ...)
+
+; CHECK: for (int c0 = 0; c0 <= 2147483646; c0 += 1)
+; CHECK:   Stmt_do_body(c0);
diff --git a/final/test/Isl/CodeGen/single_do_loop_int_max_iterations___%do.body---%do.end.jscop b/final/test/Isl/CodeGen/single_do_loop_int_max_iterations___%do.body---%do.end.jscop
new file mode 100644
index 0000000..c3ba880
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_do_loop_int_max_iterations___%do.body---%do.end.jscop
@@ -0,0 +1,13 @@
+{
+	"name": "do.body => do.end",
+	"context": "{ [] }",
+	"statements": [{
+		"name": "Stmt_do_body",
+		"domain": "{ Stmt_do_body[i0] : i0 >= 0 and i0 <= 2147483646 }",
+		"schedule": "{ Stmt_do_body[i0] -> [0, o1, i0, o3, 0] : 64o3 = o1 and o1 <= i0 and o1 >= -63 + i0 }",
+		"accesses": [{
+			"kind": "write",
+			"relation": "{ Stmt_do_body[i0] -> MemRef_A[0] }"
+		}]
+	}]
+}
\ No newline at end of file
diff --git a/final/test/Isl/CodeGen/single_do_loop_int_param_iterations.ll b/final/test/Isl/CodeGen/single_do_loop_int_param_iterations.ll
new file mode 100644
index 0000000..fe1964f
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_do_loop_int_param_iterations.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -polly-ast -S -analyze  < %s | FileCheck %s
+; XFAIL: *
+
+;define N 20
+;#include "limits.h"
+;int A[N];
+;
+;void bar (int n) {
+;  int i;
+;  __sync_synchronize();
+;  i = 0;
+;
+;  do {
+;    A[0] = i;
+;    ++i;
+;  } while (i < 2 * n);
+;  __sync_synchronize();
+;}
+;
+;int main () {
+;  A[0] = 0;
+;  bar (N/2);
+;
+;  if (A[0] == N - 1 )
+;    return 0;
+;  else
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [20 x i32] zeroinitializer, align 4 ; <[20 x i32]*> [#uses=1]
+
+define void @bar(i32 %n) nounwind {
+entry:
+  fence seq_cst
+  %tmp = mul i32 %n, 2                            ; <i32> [#uses=2]
+  %tmp1 = icmp sgt i32 %tmp, 1                    ; <i1> [#uses=1]
+  %smax = select i1 %tmp1, i32 %tmp, i32 1        ; <i32> [#uses=1]
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond, %entry
+  %0 = phi i32 [ 0, %entry ], [ %inc, %do.cond ]  ; <i32> [#uses=2]
+  store i32 %0, i32* getelementptr inbounds ([20 x i32], [20 x i32]* @A, i32 0, i32 0)
+  %inc = add nsw i32 %0, 1                        ; <i32> [#uses=2]
+  br label %do.cond
+
+do.cond:                                          ; preds = %do.body
+  %exitcond = icmp ne i32 %inc, %smax             ; <i1> [#uses=1]
+  br i1 %exitcond, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  fence seq_cst
+  ret void
+}
+
+define i32 @main() nounwind {
+entry:
+  store i32 0, i32* getelementptr inbounds ([20 x i32], [20 x i32]* @A, i32 0, i32 0)
+  call void @bar(i32 10)
+  %tmp = load i32, i32* getelementptr inbounds ([20 x i32], [20 x i32]* @A, i32 0, i32 0) ; <i32> [#uses=1]
+  %cmp = icmp eq i32 %tmp, 19                     ; <i1> [#uses=1]
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  br label %return
+
+if.else:                                          ; preds = %entry
+  br label %return
+
+return:                                           ; preds = %if.else, %if.then
+  %retval.0 = phi i32 [ 0, %if.then ], [ 1, %if.else ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+; CHECK: Scop: do.body => do.end
+
diff --git a/final/test/Isl/CodeGen/single_do_loop_ll_max_iterations.ll b/final/test/Isl/CodeGen/single_do_loop_ll_max_iterations.ll
new file mode 100644
index 0000000..8478737
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_do_loop_ll_max_iterations.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-ast -analyze  -S < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen < %s
+
+;#define N 20
+;#include "limits.h"
+;long long A[N];
+;
+;int main () {
+;  long long i;
+;
+;  A[0] = 0;
+;
+;  __sync_synchronize();
+;
+;  i = 0;
+;
+;  do {
+;    A[0] = i;
+;    ++i;
+;  } while (i < LLONG_MAX);
+;
+;  __sync_synchronize();
+;
+;  if (A[0] == LLONG_MAX - 1)
+;    return 0;
+;  else
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [20 x i64] zeroinitializer, align 8 ; <[20 x i64]*> [#uses=1]
+
+define i32 @main() nounwind {
+entry:
+  store i64 0, i64* getelementptr inbounds ([20 x i64], [20 x i64]* @A, i32 0, i32 0)
+  fence seq_cst
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond, %entry
+  %0 = phi i64 [ 0, %entry ], [ %inc, %do.cond ]  ; <i64> [#uses=2]
+  store i64 %0, i64* getelementptr inbounds ([20 x i64], [20 x i64]* @A, i32 0, i32 0)
+  %inc = add nsw i64 %0, 1                        ; <i64> [#uses=2]
+  br label %do.cond
+
+do.cond:                                          ; preds = %do.body
+  %exitcond = icmp ne i64 %inc, 9223372036854775807 ; <i1> [#uses=1]
+  br i1 %exitcond, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  fence seq_cst
+  %tmp3 = load i64, i64* getelementptr inbounds ([20 x i64], [20 x i64]* @A, i32 0, i32 0) ; <i64> [#uses=1]
+  %cmp4 = icmp eq i64 %tmp3, 9223372036854775806  ; <i1> [#uses=1]
+  br i1 %cmp4, label %if.then, label %if.else
+
+if.then:                                          ; preds = %do.end
+  br label %return
+
+if.else:                                          ; preds = %do.end
+  br label %return
+
+return:                                           ; preds = %if.else, %if.then
+  %retval.0 = phi i32 [ 0, %if.then ], [ 1, %if.else ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+
+; CHECK: for (int c0 = 0; c0 <= 9223372036854775806; c0 += 1)
+; CHECK:   Stmt_do_body(c0);
diff --git a/final/test/Isl/CodeGen/single_do_loop_one_iteration.ll b/final/test/Isl/CodeGen/single_do_loop_one_iteration.ll
new file mode 100644
index 0000000..90144b8
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_do_loop_one_iteration.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-ast -S -analyze  < %s | FileCheck %s
+; XFAIL: *
+
+;#define N 20
+;#include "limits.h"
+;
+;int main () {
+;  int i;
+;  int A[N];
+;
+;  A[0] = 1;
+;
+;  __sync_synchronize();
+;
+;  i = 0;
+;
+;  do {
+;    A[0] = 0;
+;    ++i;
+;  } while (i < 1);
+;
+;  __sync_synchronize();
+;
+;  if (A[0] == 0)
+;    return 0;
+;  else
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define i32 @main() nounwind {
+entry:
+  %A = alloca [20 x i32], align 4                 ; <[20 x i32]*> [#uses=3]
+  %arraydecay = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx = getelementptr inbounds i32, i32* %arraydecay, i64 0 ; <i32*> [#uses=1]
+  store i32 1, i32* %arrayidx
+  fence seq_cst
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond, %entry
+  %arraydecay1 = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx2 = getelementptr inbounds i32, i32* %arraydecay1, i64 0 ; <i32*> [#uses=1]
+  store i32 0, i32* %arrayidx2
+  br label %do.cond
+
+do.cond:                                          ; preds = %do.body
+  br i1 false, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  fence seq_cst
+  %arraydecay4 = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx5 = getelementptr inbounds i32, i32* %arraydecay4, i64 0 ; <i32*> [#uses=1]
+  %tmp6 = load i32, i32* %arrayidx5                    ; <i32> [#uses=1]
+  %cmp7 = icmp eq i32 %tmp6, 0                    ; <i1> [#uses=1]
+  br i1 %cmp7, label %if.then, label %if.else
+
+if.then:                                          ; preds = %do.end
+  br label %return
+
+if.else:                                          ; preds = %do.end
+  br label %return
+
+return:                                           ; preds = %if.else, %if.then
+  %retval.0 = phi i32 [ 0, %if.then ], [ 1, %if.else ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+
+; CHECK: S0(0)
diff --git a/final/test/Isl/CodeGen/single_do_loop_scev_replace.ll b/final/test/Isl/CodeGen/single_do_loop_scev_replace.ll
new file mode 100644
index 0000000..de97973
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_do_loop_scev_replace.ll
@@ -0,0 +1,94 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s
+
+;#define N 20
+;#include "limits.h"
+;#include <stdio.h>
+;int A[2 * N];
+;
+;void single_do_loop_scev_replace() {
+;  int i;
+;
+;  __sync_synchronize();
+;
+;  i = 0;
+;
+;  do {
+;    A[2 * i] = i;
+;    ++i;
+;  } while (i < N);
+;
+;  __sync_synchronize();
+;}
+;
+;int main () {
+;  int i;
+;
+;  single_do_loop_scev_replace();
+;
+;  fprintf(stdout, "Output %d\n", A[0]);
+;
+;  if (A[2 * N - 2] == N - 1)
+;    return 0;
+;  else
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker = type { %struct._IO_marker*, %struct._IO_FILE*, i32 }
+
+@A = common global [40 x i32] zeroinitializer, align 4 ; <[40 x i32]*> [#uses=3]
+@stdout = external global %struct._IO_FILE*       ; <%struct._IO_FILE**> [#uses=1]
+@.str = private constant [11 x i8] c"Output %d\0A\00" ; <[11 x i8]*> [#uses=1]
+
+define void @single_do_loop_scev_replace() nounwind {
+entry:
+  fence seq_cst
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond, %entry
+  %indvar = phi i64 [ %indvar.next, %do.cond ], [ 0, %entry ] ; <i64> [#uses=3]
+  %tmp = mul i64 %indvar, 2                       ; <i64> [#uses=1]
+  %arrayidx = getelementptr [40 x i32], [40 x i32]* @A, i64 0, i64 %tmp ; <i32*> [#uses=1]
+  %i.0 = trunc i64 %indvar to i32                 ; <i32> [#uses=1]
+  br label %do.cond
+
+do.cond:                                          ; preds = %do.body
+  store i32 %i.0, i32* %arrayidx
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=2]
+  %exitcond = icmp ne i64 %indvar.next, 20        ; <i1> [#uses=1]
+  br i1 %exitcond, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  fence seq_cst
+  ret void
+}
+
+define i32 @main() nounwind {
+entry:
+  call void @single_do_loop_scev_replace()
+  %tmp = load %struct._IO_FILE*, %struct._IO_FILE** @stdout          ; <%struct._IO_FILE*> [#uses=1]
+  %tmp1 = load i32, i32* getelementptr inbounds ([40 x i32], [40 x i32]* @A, i32 0, i32 0) ; <i32> [#uses=1]
+  %call = call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %tmp, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), i32 %tmp1) ; <i32> [#uses=0]
+  %tmp2 = load i32, i32* getelementptr inbounds ([40 x i32], [40 x i32]* @A, i32 0, i64 38) ; <i32> [#uses=1]
+  %cmp = icmp eq i32 %tmp2, 19                    ; <i1> [#uses=1]
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  br label %return
+
+if.else:                                          ; preds = %entry
+  br label %return
+
+return:                                           ; preds = %if.else, %if.then
+  %retval.0 = phi i32 [ 0, %if.then ], [ 1, %if.else ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+
+declare i32 @fprintf(%struct._IO_FILE*, i8*, ...)
+
+; CHECK: for (int c0 = 0; c0 <= 19; c0 += 1)
+; CHECK:   Stmt_do_cond(c0);
+
+
diff --git a/final/test/Isl/CodeGen/single_loop.ll b/final/test/Isl/CodeGen/single_loop.ll
new file mode 100644
index 0000000..0eb5d97
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_loop.ll
@@ -0,0 +1,84 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s
+
+;#include <string.h>
+;#define N 1024
+;
+;int main () {
+;  int i;
+;  int A[N];
+;
+;  memset(A, 0, sizeof(int) * N);
+;
+;  for (i = 0; i < N; i++) {
+;    A[i] = 1;
+;  }
+;
+;  for (i = 0; i < N; i++)
+;    if (A[i] != 1)
+;      return 1;
+;
+;  return 0;
+;}
+;
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define i32 @main() nounwind {
+entry:
+  %A = alloca [1024 x i32], align 4               ; <[1024 x i32]*> [#uses=3]
+  %arraydecay = getelementptr inbounds [1024 x i32], [1024 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %conv = bitcast i32* %arraydecay to i8*         ; <i8*> [#uses=1]
+  call void @llvm.memset.p0i8.i64(i8* %conv, i8 0, i64 4096, i32 1, i1 false)
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvar1 = phi i64 [ %indvar.next2, %for.inc ], [ 0, %entry ] ; <i64> [#uses=3]
+  %arrayidx = getelementptr [1024 x i32], [1024 x i32]* %A, i64 0, i64 %indvar1 ; <i32*> [#uses=1]
+  %exitcond = icmp ne i64 %indvar1, 1024          ; <i1> [#uses=1]
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  store i32 1, i32* %arrayidx
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvar.next2 = add i64 %indvar1, 1             ; <i64> [#uses=1]
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond5
+
+for.cond5:                                        ; preds = %for.inc07, %for.end
+  %indvar = phi i64 [ %indvar.next, %for.inc07 ], [ 0, %for.end ] ; <i64> [#uses=3]
+  %arrayidx13 = getelementptr [1024 x i32], [1024 x i32]* %A, i64 0, i64 %indvar ; <i32*> [#uses=1]
+  %i.1 = trunc i64 %indvar to i32                 ; <i32> [#uses=1]
+  %cmp7 = icmp slt i32 %i.1, 1024                 ; <i1> [#uses=1]
+  br i1 %cmp7, label %for.body9, label %for.end20
+
+for.body9:                                        ; preds = %for.cond5
+  %tmp14 = load i32, i32* %arrayidx13                  ; <i32> [#uses=1]
+  %cmp15 = icmp ne i32 %tmp14, 1                  ; <i1> [#uses=1]
+  br i1 %cmp15, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body9
+  br label %return
+
+if.end:                                           ; preds = %for.body9
+  br label %for.inc07
+
+for.inc07:                                        ; preds = %if.end
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %for.cond5
+
+for.end20:                                        ; preds = %for.cond5
+  br label %return
+
+return:                                           ; preds = %for.end20, %if.then
+  %retval.0 = phi i32 [ 1, %if.then ], [ 0, %for.end20 ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
+
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK:   Stmt_for_body(c0);
diff --git a/final/test/Isl/CodeGen/single_loop_int_max_iterations.ll b/final/test/Isl/CodeGen/single_loop_int_max_iterations.ll
new file mode 100644
index 0000000..1982188
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_loop_int_max_iterations.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-ast -analyze  -S < %s | FileCheck %s
+
+;#define N 20
+;#include "limits.h"
+;
+;int main () {
+;  int i;
+;  int A[N];
+;
+;  A[0] = 0;
+;
+;  __sync_synchronize();
+;
+;  for (i = 0; i < INT_MAX; i++)
+;    A[0] = i;
+;
+;  __sync_synchronize();
+;
+;  if (A[0] == INT_MAX - 1)
+;    return 0;
+;  else
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define i32 @main() nounwind {
+entry:
+  %A = alloca [20 x i32], align 4                 ; <[20 x i32]*> [#uses=3]
+  %arraydecay = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx = getelementptr inbounds i32, i32* %arraydecay, i64 0 ; <i32*> [#uses=1]
+  store i32 0, i32* %arrayidx
+  fence seq_cst
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]  ; <i32> [#uses=3]
+  %exitcond = icmp ne i32 %0, 2147483647          ; <i1> [#uses=1]
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arraydecay2 = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx3 = getelementptr inbounds i32, i32* %arraydecay2, i64 0 ; <i32*> [#uses=1]
+  store i32 %0, i32* %arrayidx3
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %0, 1                        ; <i32> [#uses=1]
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  fence seq_cst
+  %arraydecay5 = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx6 = getelementptr inbounds i32, i32* %arraydecay5, i64 0 ; <i32*> [#uses=1]
+  %tmp7 = load i32, i32* %arrayidx6                    ; <i32> [#uses=1]
+  %cmp8 = icmp eq i32 %tmp7, 2147483646           ; <i1> [#uses=1]
+  br i1 %cmp8, label %if.then, label %if.else
+
+if.then:                                          ; preds = %for.end
+  br label %return
+
+if.else:                                          ; preds = %for.end
+  br label %return
+
+return:                                           ; preds = %if.else, %if.then
+  %retval.0 = phi i32 [ 0, %if.then ], [ 1, %if.else ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+
+; CHECK: for (int c0 = 0; c0 <= 2147483646; c0 += 1)
+; CHECK:   Stmt_for_body(c0);
diff --git a/final/test/Isl/CodeGen/single_loop_ll_max_iterations.ll b/final/test/Isl/CodeGen/single_loop_ll_max_iterations.ll
new file mode 100644
index 0000000..3218de1
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_loop_ll_max_iterations.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-ast -analyze  -S < %s | FileCheck %s
+
+;#include "limits.h"
+;#define N 20
+;
+;int main () {
+;  long long i;
+;  long long A[N];
+;
+;  A[0] = 0;
+;
+;  __sync_synchronize();
+;
+;  for (i = 0; i < LLONG_MAX; i++)
+;    A[0] = i;
+;
+;  __sync_synchronize();
+;
+;  if (A[0] == LLONG_MAX - 1)
+;    return 0;
+;  else
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define i32 @main() nounwind {
+entry:
+  %A = alloca [20 x i64], align 8                 ; <[20 x i64]*> [#uses=3]
+  %arraydecay = getelementptr inbounds [20 x i64], [20 x i64]* %A, i32 0, i32 0 ; <i64*> [#uses=1]
+  %arrayidx = getelementptr inbounds i64, i64* %arraydecay, i64 0 ; <i64*> [#uses=1]
+  store i64 0, i64* %arrayidx
+  fence seq_cst
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]  ; <i64> [#uses=3]
+  %exitcond = icmp ne i64 %0, 9223372036854775807 ; <i1> [#uses=1]
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arraydecay2 = getelementptr inbounds [20 x i64], [20 x i64]* %A, i32 0, i32 0 ; <i64*> [#uses=1]
+  %arrayidx3 = getelementptr inbounds i64, i64* %arraydecay2, i64 0 ; <i64*> [#uses=1]
+  store i64 %0, i64* %arrayidx3
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i64 %0, 1                        ; <i64> [#uses=1]
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  fence seq_cst
+  %arraydecay5 = getelementptr inbounds [20 x i64], [20 x i64]* %A, i32 0, i32 0 ; <i64*> [#uses=1]
+  %arrayidx6 = getelementptr inbounds i64, i64* %arraydecay5, i64 0 ; <i64*> [#uses=1]
+  %tmp7 = load i64, i64* %arrayidx6                    ; <i64> [#uses=1]
+  %cmp8 = icmp eq i64 %tmp7, 9223372036854775806  ; <i1> [#uses=1]
+  br i1 %cmp8, label %if.then, label %if.else
+
+if.then:                                          ; preds = %for.end
+  br label %return
+
+if.else:                                          ; preds = %for.end
+  br label %return
+
+return:                                           ; preds = %if.else, %if.then
+  %retval.0 = phi i32 [ 0, %if.then ], [ 1, %if.else ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+
+; CHECK: for (int c0 = 0; c0 <= 9223372036854775806; c0 += 1)
+; CHECK:   Stmt_for_body(c0);
diff --git a/final/test/Isl/CodeGen/single_loop_one_iteration.ll b/final/test/Isl/CodeGen/single_loop_one_iteration.ll
new file mode 100644
index 0000000..92012cb
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_loop_one_iteration.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s
+
+;#define N 20
+;
+;int main () {
+;  int i;
+;  int A[N];
+;
+;  A[0] = 0;
+;
+;  __sync_synchronize();
+;
+;  for (i = 0; i < 1; i++)
+;    A[i] = 1;
+;
+;  __sync_synchronize();
+;
+;  if (A[0] == 1)
+;    return 0;
+;  else
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define i32 @main() nounwind {
+entry:
+  %A = alloca [20 x i32], align 4                 ; <[20 x i32]*> [#uses=3]
+  %arraydecay = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx = getelementptr inbounds i32, i32* %arraydecay, i64 0 ; <i32*> [#uses=1]
+  store i32 0, i32* %arrayidx
+  fence seq_cst
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %entry ] ; <i64> [#uses=3]
+  %arrayidx3 = getelementptr [20 x i32], [20 x i32]* %A, i64 0, i64 %indvar ; <i32*> [#uses=1]
+  %exitcond = icmp ne i64 %indvar, 1              ; <i1> [#uses=1]
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  store i32 1, i32* %arrayidx3
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  fence seq_cst
+  %arraydecay5 = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx6 = getelementptr inbounds i32, i32* %arraydecay5, i64 0 ; <i32*> [#uses=1]
+  %tmp7 = load i32, i32* %arrayidx6                    ; <i32> [#uses=1]
+  %cmp8 = icmp eq i32 %tmp7, 1                    ; <i1> [#uses=1]
+  br i1 %cmp8, label %if.then, label %if.else
+
+if.then:                                          ; preds = %for.end
+  br label %return
+
+if.else:                                          ; preds = %for.end
+  br label %return
+
+return:                                           ; preds = %if.else, %if.then
+  %retval.0 = phi i32 [ 0, %if.then ], [ 1, %if.else ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+
+; CHECK: Stmt_for_body(0);
diff --git a/final/test/Isl/CodeGen/single_loop_param.ll b/final/test/Isl/CodeGen/single_loop_param.ll
new file mode 100644
index 0000000..c06bd3d
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_loop_param.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x i32] zeroinitializer, align 16 ; <[1024 x i32]*> [#uses=3]
+
+define void @bar(i64 %n) nounwind {
+bb:
+  fence seq_cst
+  br label %bb1
+
+bb1:                                              ; preds = %bb3, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp, %bb3 ]       ; <i64> [#uses=3]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %i.0 ; <i32*> [#uses=1]
+  %exitcond = icmp ne i64 %i.0, %n                ; <i1> [#uses=1]
+  br i1 %exitcond, label %bb2, label %bb4
+
+bb2:                                              ; preds = %bb1
+  store i32 1, i32* %scevgep
+  br label %bb3
+
+bb3:                                              ; preds = %bb2
+  %tmp = add nsw i64 %i.0, 1                      ; <i64> [#uses=1]
+  br label %bb1
+
+bb4:                                              ; preds = %bb1
+  fence seq_cst
+  ret void
+}
+
+define i32 @main() nounwind {
+bb:
+  call void @llvm.memset.p0i8.i64(i8* bitcast ([1024 x i32]* @A to i8*), i8 0, i64 4096, i32 1, i1 false)
+  call void @bar(i64 1024)
+  br label %bb1
+
+bb1:                                              ; preds = %bb7, %bb
+  %indvar = phi i64 [ %indvar.next, %bb7 ], [ 0, %bb ] ; <i64> [#uses=3]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvar ; <i32*> [#uses=1]
+  %i.0 = trunc i64 %indvar to i32                 ; <i32> [#uses=1]
+  %tmp = icmp slt i32 %i.0, 1024                  ; <i1> [#uses=1]
+  br i1 %tmp, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp3 = load i32, i32* %scevgep                      ; <i32> [#uses=1]
+  %tmp4 = icmp ne i32 %tmp3, 1                    ; <i1> [#uses=1]
+  br i1 %tmp4, label %bb5, label %bb6
+
+bb5:                                              ; preds = %bb2
+  br label %bb9
+
+bb6:                                              ; preds = %bb2
+  br label %bb7
+
+bb7:                                              ; preds = %bb6
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  br label %bb9
+
+bb9:                                              ; preds = %bb8, %bb5
+  %.0 = phi i32 [ 1, %bb5 ], [ 0, %bb8 ]          ; <i32> [#uses=1]
+  ret i32 %.0
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
+
+; CHECK: for (int c0 = 0; c0 < n; c0 += 1)
+; CHECK:   Stmt_bb2(c0);
+
diff --git a/final/test/Isl/CodeGen/single_loop_zero_iterations.ll b/final/test/Isl/CodeGen/single_loop_zero_iterations.ll
new file mode 100644
index 0000000..0c17a0c
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_loop_zero_iterations.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-ast -analyze -S < %s | FileCheck %s -check-prefix=SCALAR
+
+;#define N 20
+;
+;int main () {
+;  int i;
+;  int A[N];
+;
+;  A[0] = 0;
+;
+;  __sync_synchronize();
+;
+;  for (i = 0; i < 0; i++)
+;    A[i] = 1;
+;
+;  __sync_synchronize();
+;
+;  if (A[0] == 0)
+;    return 0;
+;  else
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define i32 @main() nounwind {
+entry:
+  %A = alloca [20 x i32], align 4                 ; <[20 x i32]*> [#uses=3]
+  %arraydecay = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx = getelementptr inbounds i32, i32* %arraydecay, i64 0 ; <i32*> [#uses=1]
+  store i32 0, i32* %arrayidx
+  fence seq_cst
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %entry ] ; <i64> [#uses=2]
+  %arrayidx3 = getelementptr [20 x i32], [20 x i32]* %A, i64 0, i64 %indvar ; <i32*> [#uses=1]
+  br i1 false, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  store i32 1, i32* %arrayidx3
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  fence seq_cst
+  %arraydecay5 = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx6 = getelementptr inbounds i32, i32* %arraydecay5, i64 0 ; <i32*> [#uses=1]
+  %tmp7 = load i32, i32* %arrayidx6                    ; <i32> [#uses=1]
+  %cmp8 = icmp eq i32 %tmp7, 0                    ; <i1> [#uses=1]
+  br i1 %cmp8, label %if.then, label %if.else
+
+if.then:                                          ; preds = %for.end
+  br label %return
+
+if.else:                                          ; preds = %for.end
+  br label %return
+
+return:                                           ; preds = %if.else, %if.then
+  %retval.0 = phi i32 [ 0, %if.then ], [ 1, %if.else ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+
+; SCALAR-NOT:   Stmt_for_body(0);
diff --git a/final/test/Isl/CodeGen/split_edge_of_exit.ll b/final/test/Isl/CodeGen/split_edge_of_exit.ll
new file mode 100644
index 0000000..14ffff2
--- /dev/null
+++ b/final/test/Isl/CodeGen/split_edge_of_exit.ll
@@ -0,0 +1,31 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -verify-region-info -analyze < %s
+;
+; This is a scop directly precedented by a region, i.e. the scop's entry is the
+; region's exit block. This test is to ensure that the RegionInfo is correctly
+; preserved.
+;
+; CHECK: Valid Region for Scop: region2 => return
+;
+define void @f1(i64* %A, i64 %N) nounwind {
+entry:
+  br label %region1
+
+region1:
+  %indvar1 = phi i64 [ 0, %entry ], [ %indvar1.next, %region1 ]
+  fence seq_cst
+  %indvar1.next = add nsw i64 %indvar1, 1
+  %exitcond1 = icmp eq i64 %indvar1.next, %N
+  br i1 %exitcond1, label %region2, label %region1
+
+region2:
+  %indvar2 = phi i64 [ 0, %region1 ], [ %indvar2.next, %region2 ]
+  %scevgep2 = getelementptr i64, i64* %A, i64 %indvar2
+  store i64 %indvar2, i64* %scevgep2
+  %indvar2.next = add nsw i64 %indvar2, 1
+  %exitcond2 = icmp eq i64 %indvar2.next, %N
+  br i1 %exitcond2, label %return, label %region2
+
+return:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/split_edges.ll b/final/test/Isl/CodeGen/split_edges.ll
new file mode 100644
index 0000000..db370ff
--- /dev/null
+++ b/final/test/Isl/CodeGen/split_edges.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-codegen -verify-region-info -verify-dom-info -S < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1536 x float] zeroinitializer
+
+define void @loop_with_condition() nounwind {
+bb0:
+  fence seq_cst
+  br label %bb1
+
+bb1:
+  br i1 true, label %bb2, label %bb3
+
+bb2:
+  %ind1 = phi i32 [0, %bb1], [ %inc0, %bb2]
+  %ptr = getelementptr [1536 x float], [1536 x float]* @A, i64 0, i32 %ind1
+  store float undef, float* %ptr
+  %inc0 = add i32 %ind1, 1
+  %cond1 = icmp eq i32 %ind1, 32
+  br i1 %cond1, label %bb4, label %bb2
+
+bb3:
+  %ind2 = phi i32 [0, %bb1], [ %inc2, %bb3]
+  %inc2 = add i32 %ind2, 1
+  br i1 true, label %bb4, label %bb3
+
+bb4:
+  br label %bb5
+
+bb5:
+  fence seq_cst
+  ret void
+
+}
+
+; CHECK: polly.split_new_and_old
+; CHECK: polly.merge_new_and_old
diff --git a/final/test/Isl/CodeGen/split_edges_2.ll b/final/test/Isl/CodeGen/split_edges_2.ll
new file mode 100644
index 0000000..ffa6b78
--- /dev/null
+++ b/final/test/Isl/CodeGen/split_edges_2.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-codegen -verify-region-info -verify-dom-info -S < %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1536 x float] zeroinitializer
+
+define void @loop_with_condition() nounwind {
+bb0:
+  fence seq_cst
+  br label %bb1
+
+bb1:
+  br label %bb2
+
+bb2:
+  %ind1 = phi i32 [0, %bb1], [ %inc0, %bb2]
+  %ptr = getelementptr [1536 x float], [1536 x float]* @A, i64 0, i32 %ind1
+  store float undef, float* %ptr
+  %inc0 = add i32 %ind1, 1
+  %cond1 = icmp eq i32 %ind1, 32
+  br i1 %cond1, label %bb4, label %bb2
+
+bb4:
+  br label %bb5
+
+bb5:
+  fence seq_cst
+  ret void
+
+}
+
+; CHECK: polly.split_new_and_old
+; CHECK: polly.merge_new_and_old
+
+
+
diff --git a/final/test/Isl/CodeGen/srem-in-other-bb.ll b/final/test/Isl/CodeGen/srem-in-other-bb.ll
new file mode 100644
index 0000000..77ec863
--- /dev/null
+++ b/final/test/Isl/CodeGen/srem-in-other-bb.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-codegen -S \
+; RUN:     < %s | FileCheck %s
+;
+;    void pos(float *A, long n) {
+;      for (long i = 0; i < 100; i++)
+;        A[n % 42] += 1;
+;    }
+;
+; CHECK:      polly.stmt.bb2:
+; CHECK-NEXT:   %p_tmp = srem i64 %n, 42
+; CHECK-NEXT:   store i64 %p_tmp, i64* %tmp.s2a
+;
+; CHECK:      polly.stmt.bb3:
+; CHECK:        %tmp.s2a.reload = load i64, i64* %tmp.s2a
+; CHECK:        %p_tmp3 = getelementptr inbounds float, float* %A, i64 %tmp.s2a.reload
+
+define void @pos(float* %A, i64 %n) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = srem i64 %n, 42
+  br label %bb3
+
+bb3:
+  %tmp3 = getelementptr inbounds float, float* %A, i64 %tmp
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, 1.000000e+00
+  store float %tmp5, float* %tmp3, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/stack-overflow-in-load-hoisting.ll b/final/test/Isl/CodeGen/stack-overflow-in-load-hoisting.ll
new file mode 100644
index 0000000..709e510
--- /dev/null
+++ b/final/test/Isl/CodeGen/stack-overflow-in-load-hoisting.ll
@@ -0,0 +1,74 @@
+; RUN: opt %loadPolly -verify-dom-info -polly-codegen -S < %s \
+; RUN: -polly-invariant-load-hoisting=true | FileCheck %s
+;
+; This caused an infinite recursion during invariant load hoisting at some
+; point. Check it does not and we add a "false" runtime check.
+;
+; CHECK:       polly.preload.begin:
+; CHECK-NEXT:    br i1 false, label %polly.start, label %for.body.14.lr.ph
+;
+target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"
+
+%struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573 = type { %struct.AVClass.10.32.868.1198.1286.1308.1566*, %struct.AVFrame.5.27.863.1193.1281.1303.1572*, i32, i32, i32, i32, i32, [4 x i32], [4 x i32], double, %struct.AVRational.0.22.858.1188.1276.1298.1567 }
+%struct.AVClass.10.32.868.1198.1286.1308.1566 = type { i8*, i8* (i8*)*, %struct.AVOption.7.29.865.1195.1283.1305.1563*, i32, i32, i32, i8* (i8*, i8*)*, %struct.AVClass.10.32.868.1198.1286.1308.1566* (%struct.AVClass.10.32.868.1198.1286.1308.1566*)*, i32, i32 (i8*)*, i32 (%struct.AVOptionRanges.9.31.867.1197.1285.1307.1565**, i8*, i8*, i32)* }
+%struct.AVOption.7.29.865.1195.1283.1305.1563 = type { i8*, i8*, i32, i32, %union.anon.6.28.864.1194.1282.1304.1562, double, double, i32, i8* }
+%union.anon.6.28.864.1194.1282.1304.1562 = type { i64 }
+%struct.AVOptionRanges.9.31.867.1197.1285.1307.1565 = type { %struct.AVOptionRange.8.30.866.1196.1284.1306.1564**, i32, i32 }
+%struct.AVOptionRange.8.30.866.1196.1284.1306.1564 = type { i8*, double, double, double, double, i32 }
+%struct.AVFrame.5.27.863.1193.1281.1303.1572 = type { [8 x i8*], [8 x i32], i8**, i32, i32, i32, i32, i32, i32, %struct.AVRational.0.22.858.1188.1276.1298.1567, i64, i64, i64, i32, i32, i32, i8*, [8 x i64], i32, i32, i32, i32, i64, i32, i64, [8 x %struct.AVBufferRef.2.24.860.1190.1278.1300.1569*], %struct.AVBufferRef.2.24.860.1190.1278.1300.1569**, i32, %struct.AVFrameSideData.4.26.862.1192.1280.1302.1571**, i32, i32, i32, i32, i32, i32, i32, i64, i64, i64, %struct.AVDictionary.3.25.861.1191.1279.1301.1570*, i32, i32, i32, i8*, i32, i32, %struct.AVBufferRef.2.24.860.1190.1278.1300.1569* }
+%struct.AVFrameSideData.4.26.862.1192.1280.1302.1571 = type { i32, i8*, i32, %struct.AVDictionary.3.25.861.1191.1279.1301.1570*, %struct.AVBufferRef.2.24.860.1190.1278.1300.1569* }
+%struct.AVDictionary.3.25.861.1191.1279.1301.1570 = type opaque
+%struct.AVBufferRef.2.24.860.1190.1278.1300.1569 = type { %struct.AVBuffer.1.23.859.1189.1277.1299.1568*, i8*, i32 }
+%struct.AVBuffer.1.23.859.1189.1277.1299.1568 = type opaque
+%struct.AVRational.0.22.858.1188.1276.1298.1567 = type { i32, i32 }
+
+; Function Attrs: nounwind ssp
+define void @fade(%struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573* %s) #0 {
+entry:
+  br label %for.cond.12.preheader.lr.ph
+
+for.cond.12.preheader.lr.ph:                      ; preds = %entry
+  %outpicref = getelementptr inbounds %struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573, %struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573* %s, i32 0, i32 1
+  %arrayidx2 = getelementptr inbounds %struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573, %struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573* %s, i32 0, i32 8, i32 0
+  %tobool = icmp eq i32 0, 0
+  %arrayidx4 = getelementptr inbounds %struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573, %struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573* %s, i32 0, i32 8, i32 1
+  %tmp = load i32, i32* %arrayidx4, align 4
+  %tobool5 = icmp eq i32 %tmp, 0
+  %h = getelementptr inbounds %struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573, %struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573* %s, i32 0, i32 3
+  %tmp1 = load i32, i32* %h, align 4
+  %cmp.48 = icmp sgt i32 %tmp1, 0
+  %tmp2 = load %struct.AVFrame.5.27.863.1193.1281.1303.1572*, %struct.AVFrame.5.27.863.1193.1281.1303.1572** %outpicref, align 4
+  %arrayidx11 = getelementptr inbounds %struct.AVFrame.5.27.863.1193.1281.1303.1572, %struct.AVFrame.5.27.863.1193.1281.1303.1572* %tmp2, i32 0, i32 0, i32 0
+  %tmp3 = load i8*, i8** %arrayidx11, align 4
+  br label %for.body.14.lr.ph
+
+for.body.14.lr.ph:                                ; preds = %for.end, %for.cond.12.preheader.lr.ph
+  %d.050 = phi i8* [ %tmp3, %for.cond.12.preheader.lr.ph ], [ undef, %for.end ]
+  %w = getelementptr inbounds %struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573, %struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573* %s, i32 0, i32 2
+  %tmp4 = load i32, i32* %w, align 4
+  %cmp13.46 = icmp sgt i32 %tmp4, 0
+  br label %for.body.14
+
+for.body.14:                                      ; preds = %for.body.14, %for.body.14.lr.ph
+  %arrayidx30 = getelementptr inbounds i8, i8* %d.050, i32 0
+  store i8 undef, i8* %arrayidx30, align 1
+  %arrayidx54 = getelementptr inbounds %struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573, %struct.AudioVectorScopeContext.21.43.879.1209.1297.1319.1573* %s, i32 0, i32 8, i32 2
+  %tmp5 = load i32, i32* %arrayidx54, align 4
+  %add92 = add nuw nsw i32 0, 4
+  %tmp6 = load i32, i32* %w, align 4
+  %mul = shl nsw i32 %tmp6, 2
+  %cmp13 = icmp slt i32 %add92, %mul
+  br i1 %cmp13, label %for.body.14, label %for.end
+
+for.end:                                          ; preds = %for.body.14
+  %inc = add nuw nsw i32 0, 1
+  %tmp7 = load i32, i32* %h, align 4
+  %cmp = icmp slt i32 %inc, %tmp7
+  br i1 %cmp, label %for.body.14.lr.ph, label %if.end.loopexit
+
+if.end.loopexit:                                  ; preds = %for.end
+  br label %if.end
+
+if.end:                                           ; preds = %if.end.loopexit
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/stmt_split_no_dependence.ll b/final/test/Isl/CodeGen/stmt_split_no_dependence.ll
new file mode 100644
index 0000000..539c406
--- /dev/null
+++ b/final/test/Isl/CodeGen/stmt_split_no_dependence.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; CHECK:   store i32 %8, i32* %scevgep, align 4, !alias.scope !1, !noalias !3
+; CHECK:   store i32 %9, i32* %scevgep4, align 4, !alias.scope !4, !noalias !5
+;
+;      void func(int *A, int *B){
+;        for (int i = 0; i < 1024; i+=1) {
+;      Stmt:
+;          A[i] = i;
+;          B[i] = i;
+;        }
+;      }
+;
+; Function Attrs: noinline nounwind uwtable
+define void @func(i32* %A, i32* %B) #0 {
+entry:
+  br label %for.cond
+
+for.cond: 					 ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ]
+  %cmp = icmp slt i32 %i.0, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body: 					 ; preds = %for.cond
+  br label %Stmt
+
+Stmt: 						 ; preds = %for.body
+  %idxprom = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+  %idxprom1 = sext i32 %i.0 to i64
+  %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %idxprom1
+  store i32 %i.0, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc: 					 ; preds = %Stmt
+  %add = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end: 					 ; preds = %for.cond
+  ret void
+}
+
+!0 = !{!"polly_split_after"} 
diff --git a/final/test/Isl/CodeGen/switch-in-non-affine-region.ll b/final/test/Isl/CodeGen/switch-in-non-affine-region.ll
new file mode 100644
index 0000000..4887f89
--- /dev/null
+++ b/final/test/Isl/CodeGen/switch-in-non-affine-region.ll
@@ -0,0 +1,77 @@
+; RUN: opt %loadPolly \
+; RUN: -S -polly-codegen < %s | FileCheck %s
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        if (A[i])
+;          switch (i % 4) {
+;          case 0:
+;            A[i] += 1;
+;            break;
+;          case 1:
+;            A[i] += 2;
+;            break;
+;          }
+;    }
+;
+; CHECK: polly.stmt.if.then:
+; CHECK:   %1 = trunc i64 %polly.indvar to i32
+; CHECK:   %p_rem = srem i32 %1, 4
+; CHECK:   switch i32 %p_rem, label %polly.stmt.sw.epilog [
+; CHECK:     i32 0, label %polly.stmt.sw.bb
+; CHECK:     i32 1, label %polly.stmt.sw.bb.3
+; CHECK:   ]
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %tobool = icmp eq i32 %tmp1, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %for.body
+  %tmp2 = trunc i64 %indvars.iv to i32
+  %rem = srem i32 %tmp2, 4
+  switch i32 %rem, label %sw.epilog [
+    i32 0, label %sw.bb
+    i32 1, label %sw.bb.3
+  ]
+
+sw.bb:                                            ; preds = %if.then
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %arrayidx2, align 4
+  %add = add nsw i32 %tmp3, 1
+  store i32 %add, i32* %arrayidx2, align 4
+  br label %sw.epilog
+
+sw.bb.3:                                          ; preds = %if.then
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp4 = load i32, i32* %arrayidx5, align 4
+  %add6 = add nsw i32 %tmp4, 2
+  store i32 %add6, i32* %arrayidx5, align 4
+  br label %sw.epilog
+
+sw.epilog:                                        ; preds = %sw.bb.3, %sw.bb, %if.then
+  br label %if.end
+
+if.end:                                           ; preds = %for.body, %sw.epilog
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/synthesizable_phi_write_after_loop.ll b/final/test/Isl/CodeGen/synthesizable_phi_write_after_loop.ll
new file mode 100644
index 0000000..9cd72a8
--- /dev/null
+++ b/final/test/Isl/CodeGen/synthesizable_phi_write_after_loop.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; Check for the correct written value of a scalar phi write whose value is
+; defined within the loop, but its effective value is its last definition when
+; leaving the loop (in this test it is the value 2 for %i.inc). This can be
+; either computed:
+; - Using SCEVExpander:
+;         In this case the Loop passed to the expander must NOT be the loop
+; - Overwriting the same alloca in each iteration s.t. the last value will
+;         retain in %i.inc.s2a
+; The first is currently generated by Polly and tested here.
+
+; CHECK:      polly.stmt.next:
+; CHECK-NEXT:   store i32 2, i32* %phi.phiops
+; CHECK-NEXT:   br label %polly.stmt.join
+
+define i32 @func() {
+entry:
+  br label %start
+
+start:
+  br i1 true, label %loop, label %join
+
+loop:
+  %i = phi i32 [ 0, %start ], [ %i.inc, %loop ]
+  %i.inc = add nsw i32 %i, 1
+  %cond = icmp slt i32 %i.inc, 2
+  br i1 %cond, label %loop, label %next
+
+next:
+  br label %join
+
+join:
+  %phi = phi i32 [%i.inc, %next], [0, %start]
+  br label %return
+
+return:
+  ret i32 %phi
+}
diff --git a/final/test/Isl/CodeGen/test-invalid-operands-for-select-2.ll b/final/test/Isl/CodeGen/test-invalid-operands-for-select-2.ll
new file mode 100644
index 0000000..6985fb7
--- /dev/null
+++ b/final/test/Isl/CodeGen/test-invalid-operands-for-select-2.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -S -polly-codegen -verify-loop-info < %s | FileCheck %s
+;
+; Check that we do not crash as described here: http://llvm.org/bugs/show_bug.cgi?id=21167
+;
+; CHECK: polly.split_new_and_old
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @kernel_fdtd_apml(i32 %cxm, i32 %cym, [65 x [65 x double]]* %Bza, [65 x [65 x double]]* %Hz, double* %czp) #0 {
+entry:
+  br i1 false, label %for.cond4.preheader, label %for.end451
+
+for.cond4.preheader:                              ; preds = %for.inc449, %entry
+  %iz.08 = phi i32 [ undef, %for.inc449 ], [ 0, %entry ]
+  %cmp55 = icmp sgt i32 %cym, 0
+  br i1 %cmp55, label %for.cond7.preheader, label %for.inc449
+
+for.cond7.preheader:                              ; preds = %for.end, %for.cond4.preheader
+  %iy.06 = phi i32 [ %inc447, %for.end ], [ 0, %for.cond4.preheader ]
+  %cmp81 = icmp sgt i32 %cxm, 0
+  br i1 %cmp81, label %for.body9, label %for.end
+
+for.body9:                                        ; preds = %for.body9, %for.cond7.preheader
+  %ix.02 = phi i32 [ %inc, %for.body9 ], [ 0, %for.cond7.preheader ]
+  %idxprom74 = sext i32 %iz.08 to i64
+  %arrayidx75 = getelementptr inbounds double, double* %czp, i64 %idxprom74
+  %0 = load double, double* %arrayidx75, align 8
+  %idxprom102 = sext i32 %iz.08 to i64
+  %arrayidx105 = getelementptr inbounds [65 x [65 x double]], [65 x [65 x double]]* %Hz, i64 %idxprom102, i64 0, i64 0
+  store double undef, double* %arrayidx105, align 8
+  %inc = add nsw i32 %ix.02, 1
+  br i1 false, label %for.body9, label %for.end
+
+for.end:                                          ; preds = %for.body9, %for.cond7.preheader
+  %idxprom209 = sext i32 %cxm to i64
+  %idxprom211 = sext i32 %iz.08 to i64
+  %arrayidx214 = getelementptr inbounds [65 x [65 x double]], [65 x [65 x double]]* %Hz, i64 %idxprom211, i64 0, i64 %idxprom209
+  store double undef, double* %arrayidx214, align 8
+  %idxprom430 = sext i32 %cxm to i64
+  %idxprom431 = sext i32 %cym to i64
+  %idxprom432 = sext i32 %iz.08 to i64
+  %arrayidx435 = getelementptr inbounds [65 x [65 x double]], [65 x [65 x double]]* %Hz, i64 %idxprom432, i64 %idxprom431, i64 %idxprom430
+  store double undef, double* %arrayidx435, align 8
+  %arrayidx445 = getelementptr inbounds [65 x [65 x double]], [65 x [65 x double]]* %Bza, i64 0, i64 0, i64 0
+  store double undef, double* %arrayidx445, align 8
+  %inc447 = add nsw i32 %iy.06, 1
+  %cmp5 = icmp slt i32 %inc447, %cym
+  br i1 %cmp5, label %for.cond7.preheader, label %for.inc449
+
+for.inc449:                                       ; preds = %for.end, %for.cond4.preheader
+  br i1 undef, label %for.cond4.preheader, label %for.end451
+
+for.end451:                                       ; preds = %for.inc449, %entry
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/test-invalid-operands-for-select.ll b/final/test/Isl/CodeGen/test-invalid-operands-for-select.ll
new file mode 100644
index 0000000..7507542
--- /dev/null
+++ b/final/test/Isl/CodeGen/test-invalid-operands-for-select.ll
@@ -0,0 +1,81 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+;
+; Check that we do not crash as described here: http://llvm.org/PR21167
+;
+; In case the pieceweise affine function used to create an isl_ast_expr
+; had empty cases (e.g., with contradicting constraints on the
+; parameters), it was possible that the condition of the isl_ast_expr
+; select was not a comparison but a constant (thus of type i64).
+; However, we shouldn't crash in such a case :)
+;
+; CHECK: polly.split_new_and_old
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @dradb4(i32 %ido, i32 %l1, float* %cc, float* %ch, float* %wa1, float* %wa3) #0 {
+entry:
+  %mul = mul nsw i32 %l1, %ido
+  br i1 undef, label %for.end256, label %if.end
+
+if.end:                                           ; preds = %entry
+  br i1 undef, label %L105, label %for.cond45.preheader
+
+for.cond45.preheader:                             ; preds = %if.end
+  br i1 undef, label %for.body47, label %for.end198
+
+for.body47:                                       ; preds = %for.inc096, %for.cond45.preheader
+  br i1 undef, label %for.body53.lr.ph, label %for.inc096
+
+for.body53.lr.ph:                                 ; preds = %for.body47
+  br label %for.body53
+
+for.body53:                                       ; preds = %for.body53, %for.body53.lr.ph
+  %t7.014 = phi i32 [ 0, %for.body53.lr.ph ], [ %add58, %for.body53 ]
+  %i.013 = phi i32 [ 2, %for.body53.lr.ph ], [ %add193, %for.body53 ]
+  %add58 = add nsw i32 %t7.014, 2
+  %arrayidx70 = getelementptr inbounds float, float* %cc, i64 0
+  %arrayidx72 = getelementptr inbounds float, float* %cc, i64 0
+  %arrayidx77 = getelementptr inbounds float, float* %cc, i64 0
+  %arrayidx81 = getelementptr inbounds float, float* %cc, i64 0
+  %arrayidx84 = getelementptr inbounds float, float* %cc, i64 0
+  %arrayidx95 = getelementptr inbounds float, float* %cc, i64 0
+  %arrayidx105 = getelementptr inbounds float, float* %cc, i64 0
+  %arrayidx110 = getelementptr inbounds float, float* %ch, i64 0
+  store float undef, float* %arrayidx110, align 4
+  %arrayidx122 = getelementptr inbounds float, float* %wa1, i64 0
+  %add129 = add nsw i32 %add58, %mul
+  %idxprom142 = sext i32 %add129 to i64
+  %arrayidx143 = getelementptr inbounds float, float* %ch, i64 %idxprom142
+  store float undef, float* %arrayidx143, align 4
+  %add153 = add nsw i32 %add129, %mul
+  %arrayidx170 = getelementptr inbounds float, float* %wa3, i64 0
+  %arrayidx174 = getelementptr inbounds float, float* %wa3, i64 0
+  %add177 = add nsw i32 %add153, %mul
+  %sub178 = add nsw i32 %add177, -1
+  %idxprom179 = sext i32 %sub178 to i64
+  %arrayidx180 = getelementptr inbounds float, float* %ch, i64 %idxprom179
+  store float undef, float* %arrayidx180, align 4
+  %arrayidx183 = getelementptr inbounds float, float* %wa3, i64 0
+  %0 = load float, float* %arrayidx183, align 4
+  %mul184 = fmul float undef, %0
+  %add189 = fadd float %mul184, 0.000000e+00
+  %idxprom190 = sext i32 %add177 to i64
+  %arrayidx191 = getelementptr inbounds float, float* %ch, i64 %idxprom190
+  store float %add189, float* %arrayidx191, align 4
+  %add193 = add nsw i32 %i.013, 2
+  %cmp52 = icmp slt i32 %add193, %ido
+  br i1 %cmp52, label %for.body53, label %for.inc096
+
+for.inc096:                                       ; preds = %for.body53, %for.body47
+  br i1 undef, label %for.body47, label %for.end198
+
+for.end198:                                       ; preds = %for.inc096, %for.cond45.preheader
+  br i1 false, label %for.end256, label %L105
+
+L105:                                             ; preds = %for.end198, %if.end
+  br label %for.end256
+
+for.end256:                                       ; preds = %L105, %for.end198, %entry
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/test.ll b/final/test/Isl/CodeGen/test.ll
new file mode 100644
index 0000000..b8b9b88
--- /dev/null
+++ b/final/test/Isl/CodeGen/test.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-ast -analyze  -S < %s | FileCheck %s
+; XFAIL: *
+
+;int bar1();
+;int bar2();
+;int bar3();
+;int k;
+;#define N 100
+;int A[N];
+;
+;int foo (int z) {
+;  int i, j;
+;
+;  for (i = 0; i < N; i++) {
+;    A[i] = i;
+;
+;      for (j = 0; j < N * 2; j++)
+;        A[i] = j * A[i];
+;  }
+;
+;  return A[z];
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [100 x i32] zeroinitializer, align 4 ; <[100 x i32]*> [#uses=2]
+@k = common global i32 0, align 4                 ; <i32*> [#uses=0]
+
+define i32 @foo(i32 %z) nounwind {
+bb.nph31.split.us:
+  br label %bb.nph.us
+
+for.inc06.us:                                     ; preds = %for.body6.us
+  store i32 %mul.us, i32* %arrayidx.us
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=2]
+  %exitcond32 = icmp eq i64 %indvar.next, 100     ; <i1> [#uses=1]
+  br i1 %exitcond32, label %for.end19, label %bb.nph.us
+
+for.body6.us:                                     ; preds = %for.body6.us, %bb.nph.us
+  %arrayidx10.tmp.0.us = phi i32 [ %i.027.us, %bb.nph.us ], [ %mul.us, %for.body6.us ] ; <i32> [#uses=1]
+  %0 = phi i32 [ 0, %bb.nph.us ], [ %inc.us, %for.body6.us ] ; <i32> [#uses=2]
+  %mul.us = mul i32 %arrayidx10.tmp.0.us, %0      ; <i32> [#uses=2]
+  %inc.us = add nsw i32 %0, 1                     ; <i32> [#uses=2]
+  %exitcond = icmp eq i32 %inc.us, 200            ; <i1> [#uses=1]
+  br i1 %exitcond, label %for.inc06.us, label %for.body6.us
+
+bb.nph.us:                                        ; preds = %bb.nph31.split.us, %for.inc06.us
+  %indvar = phi i64 [ %indvar.next, %for.inc06.us ], [ 0, %bb.nph31.split.us ] ; <i64> [#uses=3]
+  %arrayidx.us = getelementptr [100 x i32], [100 x i32]* @A, i64 0, i64 %indvar ; <i32*> [#uses=2]
+  %i.027.us = trunc i64 %indvar to i32            ; <i32> [#uses=2]
+  store i32 %i.027.us, i32* %arrayidx.us
+  br label %for.body6.us
+
+for.end19:                                        ; preds = %for.inc06.us
+  %idxprom21 = sext i32 %z to i64                 ; <i64> [#uses=1]
+  %arrayidx22 = getelementptr inbounds [100 x i32], [100 x i32]* @A, i64 0, i64 %idxprom21 ; <i32*> [#uses=1]
+  %tmp23 = load i32, i32* %arrayidx22                  ; <i32> [#uses=1]
+  ret i32 %tmp23
+}
+; CHECK: for (c2=0;c2<=99;c2++) {
+; CHECK:   S{{[0-4]}}(c2);
+; CHECK:   for (c4=0;c4<=199;c4++) {
+; CHECK:     S{{[[0-4]}}(c2,c4);
+; CHECK:   }
+; CHECK:   S{{[0-4]}}(c2);
+; CHECK: }
+
diff --git a/final/test/Isl/CodeGen/two-loops-right-after-each-other-2.ll b/final/test/Isl/CodeGen/two-loops-right-after-each-other-2.ll
new file mode 100644
index 0000000..b81eaeb
--- /dev/null
+++ b/final/test/Isl/CodeGen/two-loops-right-after-each-other-2.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+
+; CHECK:       polly.merge_new_and_old:
+; CHECK-NEXT:    merge = phi
+
+%struct.ImageParameters = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, float, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i8**, i8**, i32, i32***, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [9 x [16 x [16 x i16]]], [5 x [16 x [16 x i16]]], [9 x [8 x [8 x i16]]], [2 x [4 x [16 x [16 x i16]]]], [16 x [16 x i16]], [16 x [16 x i32]], i32****, i32***, i32***, i32***, i32****, i32****, %struct.Picture*, %struct.Slice*, %struct.macroblock*, i32*, i32*, i32, i32, i32, i32, [4 x [4 x i32]], i32, i32, i32, i32, i32, double, i32, i32, i32, i32, i16******, i16******, i16******, i16******, [15 x i16], i32, i32, i32, i32, i32, i32, i32, i32, [6 x [32 x i32]], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [1 x i32], i32, i32, [2 x i32], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, %struct.DecRefPicMarking*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, double**, double***, i32***, double**, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [3 x [2 x i32]], [2 x i32], i32, i32, i16, i32, i32, i32, i32, i32 }
+%struct.Picture = type { i32, i32, [100 x %struct.Slice*], i32, float, float, float }
+%struct.Slice = type { i32, i32, i32, i32, i32, i32, %struct.datapartition*, %struct.MotionInfoContexts*, %struct.TextureInfoContexts*, i32, i32*, i32*, i32*, i32, i32*, i32*, i32*, i32 (i32)*, [3 x [2 x i32]] }
+%struct.datapartition = type { %struct.Bitstream*, %struct.EncodingEnvironment, %struct.EncodingEnvironment }
+%struct.Bitstream = type { i32, i32, i8, i32, i32, i8, i8, i32, i32, i8*, i32 }
+%struct.EncodingEnvironment = type { i32, i32, i32, i32, i32, i8*, i32*, i32, i32 }
+%struct.MotionInfoContexts = type { [3 x [11 x %struct.BiContextType]], [2 x [9 x %struct.BiContextType]], [2 x [10 x %struct.BiContextType]], [2 x [6 x %struct.BiContextType]], [4 x %struct.BiContextType], [4 x %struct.BiContextType], [3 x %struct.BiContextType] }
+%struct.BiContextType = type { i16, i8, i64 }
+%struct.TextureInfoContexts = type { [2 x %struct.BiContextType], [3 x [4 x %struct.BiContextType]], [10 x [4 x %struct.BiContextType]], [10 x [15 x %struct.BiContextType]], [10 x [15 x %struct.BiContextType]], [10 x [5 x %struct.BiContextType]], [10 x [5 x %struct.BiContextType]], [10 x [15 x %struct.BiContextType]], [10 x [15 x %struct.BiContextType]] }
+%struct.macroblock = type { i32, i32, i32, [2 x i32], i32, [8 x i32], %struct.macroblock*, i32, [2 x [4 x [4 x [2 x i32]]]], [16 x i8], [16 x i8], i32, i64, [4 x i32], [4 x i32], i64, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, double, i32, i32, i32, i32, i32, i32, i32, i32, i32 }
+%struct.DecRefPicMarking = type { i32, i32, i32, i32, i32, %struct.DecRefPicMarking* }
+
+@img = external global %struct.ImageParameters*, align 8
+
+define void @intrapred_luma() {
+entry:
+  %PredPel = alloca [13 x i16], align 16
+  br label %for.body
+
+for.body:                                         ; preds = %for.body, %entry
+  br i1 undef, label %for.body, label %for.body.262
+
+for.body.262:                                     ; preds = %for.body
+  %0 = load %struct.ImageParameters*, %struct.ImageParameters** @img, align 8
+  br label %for.body.280
+
+for.body.280:                                     ; preds = %for.body.280, %for.body.262
+  %indvars.iv66 = phi i64 [ 0, %for.body.262 ], [ %indvars.iv.next67, %for.body.280 ]
+  %arrayidx282 = getelementptr inbounds [13 x i16], [13 x i16]* %PredPel, i64 0, i64 1
+  %arrayidx283 = getelementptr inbounds i16, i16* %arrayidx282, i64 %indvars.iv66
+  %1 = load i16, i16* %arrayidx283, align 2
+  %arrayidx289 = getelementptr inbounds %struct.ImageParameters, %struct.ImageParameters* %0, i64 0, i32 47, i64 0, i64 2, i64 %indvars.iv66
+  store i16 %1, i16* %arrayidx289, align 2
+  %indvars.iv.next67 = add nuw nsw i64 %indvars.iv66, 1
+  br i1 false, label %for.body.280, label %for.end.298
+
+for.end.298:                                      ; preds = %for.body.280
+  %2 = load %struct.ImageParameters*, %struct.ImageParameters** @img, align 8
+  br label %for.body.310
+
+for.body.310:                                     ; preds = %for.body.310, %for.end.298
+  %indvars.iv = phi i64 [ 0, %for.end.298 ], [ %indvars.iv.next, %for.body.310 ]
+  %InterScopSext = sext i16 %1 to i64
+  %arrayidx312 = getelementptr inbounds [13 x i16], [13 x i16]* %PredPel, i64 0, i64 %InterScopSext
+  %arrayidx313 = getelementptr inbounds i16, i16* %arrayidx312, i64 %indvars.iv
+  %3 = load i16, i16* %arrayidx313, align 2
+  %arrayidx322 = getelementptr inbounds %struct.ImageParameters, %struct.ImageParameters* %2, i64 0, i32 47, i64 1, i64 %indvars.iv, i64 1
+  store i16 %3, i16* %arrayidx322, align 2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br i1 false, label %for.body.310, label %for.end.328
+
+for.end.328:                                      ; preds = %for.body.310
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/two-scops-in-row-invalidate-scevs.ll b/final/test/Isl/CodeGen/two-scops-in-row-invalidate-scevs.ll
new file mode 100644
index 0000000..238014e
--- /dev/null
+++ b/final/test/Isl/CodeGen/two-scops-in-row-invalidate-scevs.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; CHECK-LABEL: for.cond:
+; CHECK:         %num.0 = phi i32 [ %add, %for.body15 ], [ 0, %for.cond.pre_entry_bb ]
+; CHECK:         br i1 false, label %for.body15, label %for.end22
+
+; CHECK-LABEL: polly.merge_new_and_old:
+; CHECK:         %num.0.merge = phi i32 [ %num.0.final_reload, %polly.exiting ], [ %num.0, %for.end22 ]
+; CHECK:         br label %for.end44
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @func(i32* %p) {
+entry:
+  %counters = alloca [64 x i32], align 16
+  %lenCounters = alloca [17 x i32], align 16
+  br label %for.cond
+
+for.cond:                                       ; preds = %for.body15, %for.cond
+  %num.0 = phi i32 [ 0, %entry ], [ %add, %for.body15 ]
+  br i1 false, label %for.body15, label %for.end22
+
+for.body15:                                       ; preds = %for.cond
+  %arrayidx17 = getelementptr inbounds [64 x i32], [64 x i32]* %counters, i64 0, i64 0
+  %0 = load i32, i32* %arrayidx17, align 4
+  %add = add i32 %num.0, %0
+  br label %for.cond
+
+for.end22:                                        ; preds = %for.cond
+  br label %for.end44
+
+for.end44:                                        ; preds = %for.end22
+  br i1 undef, label %if.then50, label %if.end67
+
+if.then50:                                        ; preds = %for.end44
+  br label %cleanup
+
+if.end67:                                         ; preds = %for.end44
+  br label %do.body
+
+do.body:                                          ; preds = %cond.end109, %if.end67
+  %e.0 = phi i32 [ 0, %if.end67 ], [ %inc128, %cond.end109 ]
+  br label %cond.end109
+
+cond.end109:                                      ; preds = %do.body
+  %idxprom122 = zext i32 %e.0 to i64
+  %arrayidx123 = getelementptr inbounds i32, i32* %p, i64 %idxprom122
+  %inc128 = add i32 %e.0, 1
+  %sub129 = sub i32 %num.0, %inc128
+  %cmp130 = icmp ugt i32 %sub129, 1
+  br i1 %cmp130, label %do.body, label %do.end
+
+do.end:                                           ; preds = %cond.end109
+  %1 = load i32, i32* %arrayidx123, align 4
+  %arrayidx142 = getelementptr inbounds [17 x i32], [17 x i32]* %lenCounters, i64 0, i64 1
+  store i32 2, i32* %arrayidx142, align 4
+  br label %for.cond201
+
+for.cond201:                                      ; preds = %for.body204, %do.end
+  br i1 undef, label %for.body204, label %for.end214
+
+for.body204:                                      ; preds = %for.cond201
+  br label %for.cond201
+
+for.end214:                                       ; preds = %for.cond201
+  br label %cleanup
+
+cleanup:                                          ; preds = %for.end214, %if.then50
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/two-scops-in-row.ll b/final/test/Isl/CodeGen/two-scops-in-row.ll
new file mode 100644
index 0000000..f2c4326
--- /dev/null
+++ b/final/test/Isl/CodeGen/two-scops-in-row.ll
@@ -0,0 +1,41 @@
+
+; RUN: opt %loadPolly -polly-ast -analyze -polly-ignore-aliasing < %s | FileCheck %s -check-prefix=SCALAR
+; RUN: opt %loadPolly -polly-codegen -polly-ignore-aliasing -disable-output < %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; SCALAR: if (
+; SCALAR:     {
+; SCALAR:       Stmt_for_1(0);
+; SCALAR:       for (int c0 = 1; c0 <= -Scalar0_val + 99; c0 += 1)
+; SCALAR:         Stmt_for_1(c0);
+; SCALAR:     }
+
+; SCALAR: if (1)
+; SCALAR:     Stmt_for_0(0);
+
+
+define void @foo(i32* %A) {
+entry:
+  %Scalar0 = alloca i32
+  br label %for.0
+
+for.0:
+  %Scalar0.val = load i32, i32* %Scalar0
+  store i32 1, i32* %Scalar0
+  br i1 false, label %for.0, label %for.1.preheader
+
+for.1.preheader:
+  fence seq_cst
+  br label %for.1
+
+for.1:
+  %indvar.1 = phi i32 [ %Scalar0.val, %for.1.preheader ], [ %indvar.1.next, %for.1]
+  %arrayidx.1 = getelementptr inbounds i32, i32* %A, i32 %indvar.1
+  store i32 1, i32* %arrayidx.1
+  %indvar.1.next = add nsw i32 %indvar.1, 1
+  %cmp.1 = icmp slt i32 %indvar.1.next, 100
+  br i1 %cmp.1, label %for.1, label %end
+
+end:
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/udiv_expansion_position.ll b/final/test/Isl/CodeGen/udiv_expansion_position.ll
new file mode 100644
index 0000000..cd2a05d
--- /dev/null
+++ b/final/test/Isl/CodeGen/udiv_expansion_position.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; Verify we do not crash when we synthezise code for the udiv in the SCoP.
+;
+; CHECK: polly.start
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @RestartModel() #0 {
+entry:
+  br label %for.cond32.preheader
+
+for.cond32.preheader:                             ; preds = %entry, %for.body50.7
+  %i.13 = phi i32 [ 0, %entry ], [ %inc60, %for.body50.7 ]
+  %add = add i32 %i.13, 2
+  %div44 = udiv i32 undef, %add
+  %sub45 = sub i32 16384, %div44
+  %conv46 = trunc i32 %sub45 to i16
+  br label %for.body35
+
+for.body35:                                       ; preds = %for.cond32.preheader
+  br label %for.body50
+
+for.body50:                                       ; preds = %for.body35
+  br label %for.body50.1
+
+for.cond62:                                       ; preds = %for.body50.7
+  %conv46.lcssa = phi i16 [ %conv46, %for.body50.7 ]
+  store i16 %conv46.lcssa, i16* undef, align 2
+  br label %for.end83
+
+for.end83:                                        ; preds = %for.cond62
+  ret void
+
+for.body50.1:                                     ; preds = %for.body50
+  br label %for.body50.2
+
+for.body50.2:                                     ; preds = %for.body50.1
+  br label %for.body50.3
+
+for.body50.3:                                     ; preds = %for.body50.2
+  br label %for.body50.4
+
+for.body50.4:                                     ; preds = %for.body50.3
+  br label %for.body50.5
+
+for.body50.5:                                     ; preds = %for.body50.4
+  br label %for.body50.6
+
+for.body50.6:                                     ; preds = %for.body50.5
+  br label %for.body50.7
+
+for.body50.7:                                     ; preds = %for.body50.6
+  %inc60 = add i32 %i.13, 1
+  %cmp29 = icmp ult i32 %inc60, 128
+  br i1 %cmp29, label %for.cond32.preheader, label %for.cond62
+}
diff --git a/final/test/Isl/CodeGen/uninitialized_scalar_memory.ll b/final/test/Isl/CodeGen/uninitialized_scalar_memory.ll
new file mode 100644
index 0000000..18e1848
--- /dev/null
+++ b/final/test/Isl/CodeGen/uninitialized_scalar_memory.ll
@@ -0,0 +1,87 @@
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s
+;
+; Verify we initialize the scalar locations reserved for the incoming phi
+; values.
+;
+; CHECK:      polly.start:
+; CHECK-NEXT:   store float %ebig.0, float* %ebig.0.s2a
+; CHECK-NEXT:   br label %polly.stmt.if.end.entry
+;
+;    int g(void);
+;    float M;
+;    int max(float *restrict xbig, int eres, int bres, float *restrict indx) {
+;      int i, iebig;
+;      float ebig;
+;      for (i = 0; i < 4 + eres; i++) {
+;        if (g())
+;          break;
+;
+;        if (xbig[i] > ebig) {
+;          ebig = xbig[i];
+;          iebig = (int)(indx[i] + bres);
+;        }
+;      }
+;      return (iebig);
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@M = common global float 0.000000e+00, align 4
+
+define i32 @max(float* noalias %xbig, i32 %eres, i32 %bres, float* noalias %indx) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %iebig.0 = phi i32 [ undef, %entry ], [ %iebig.1, %for.inc ]
+  %ebig.0 = phi float [ undef, %entry ], [ %ebig.1, %for.inc ]
+  %add = add nsw i32 %eres, 4
+  %tmp = sext i32 %add to i64
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end.loopexit
+
+for.body:                                         ; preds = %for.cond
+  %call = call i32 @g() #2
+  %tobool = icmp eq i32 %call, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %for.body
+  %iebig.0.lcssa1 = phi i32 [ %iebig.0, %for.body ]
+  br label %for.end
+
+if.end:                                           ; preds = %for.body
+  %arrayidx = getelementptr inbounds float, float* %xbig, i64 %indvars.iv
+  %tmp3 = load float, float* %arrayidx, align 4
+  %cmp1 = fcmp ogt float %tmp3, %ebig.0
+  br i1 %cmp1, label %if.then.2, label %if.end.9
+
+if.then.2:                                        ; preds = %if.end
+  %arrayidx4 = getelementptr inbounds float, float* %xbig, i64 %indvars.iv
+  %tmp4 = load float, float* %arrayidx4, align 4
+  %arrayidx6 = getelementptr inbounds float, float* %indx, i64 %indvars.iv
+  %tmp5 = load float, float* %arrayidx6, align 4
+  %conv = sitofp i32 %bres to float
+  %add7 = fadd float %tmp5, %conv
+  %conv8 = fptosi float %add7 to i32
+  br label %if.end.9
+
+if.end.9:                                         ; preds = %if.then.2, %if.end
+  %iebig.1 = phi i32 [ %conv8, %if.then.2 ], [ %iebig.0, %if.end ]
+  %ebig.1 = phi float [ %tmp4, %if.then.2 ], [ %ebig.0, %if.end ]
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end.9
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end.loopexit:                                 ; preds = %for.cond
+  %iebig.0.lcssa = phi i32 [ %iebig.0, %for.cond ]
+  br label %for.end
+
+for.end:                                          ; preds = %for.end.loopexit, %if.then
+  %iebig.02 = phi i32 [ %iebig.0.lcssa, %for.end.loopexit ], [ %iebig.0.lcssa1, %if.then ]
+  ret i32 %iebig.02
+}
+
+declare i32 @g() #1
diff --git a/final/test/Isl/CodeGen/unpredictable-loop-unsynthesizable.ll b/final/test/Isl/CodeGen/unpredictable-loop-unsynthesizable.ll
new file mode 100644
index 0000000..5d5aa01
--- /dev/null
+++ b/final/test/Isl/CodeGen/unpredictable-loop-unsynthesizable.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s
+
+; The loop for.body is a scop with invariant load hoisting, but does not
+; terminate predictably for ScalarEvolution. The scalar %1 therefore is not
+; synthesizable using SCEVExpander. We therefore must have Stmt_for_end_loopexit
+; to catch the induction variable at loop exit. We also check for not crashing
+; at codegen because SCEVExpander would use the original induction variable in
+; generated code.
+
+%struct.bit_stream_struc.3.43.51.71.83.91.99.107.154 = type { i8*, i32, %struct._IO_FILE.1.41.49.69.81.89.97.105.153*, i8*, i32, i64, i32, i32 }
+%struct._IO_FILE.1.41.49.69.81.89.97.105.153 = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker.0.40.48.68.80.88.96.104.152*, %struct._IO_FILE.1.41.49.69.81.89.97.105.153*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker.0.40.48.68.80.88.96.104.152 = type { %struct._IO_marker.0.40.48.68.80.88.96.104.152*, %struct._IO_FILE.1.41.49.69.81.89.97.105.153*, i32 }
+
+define i32 @copy_buffer(%struct.bit_stream_struc.3.43.51.71.83.91.99.107.154* nocapture %bs) {
+entry:
+  %buf_byte_idx5.phi.trans.insert = getelementptr inbounds %struct.bit_stream_struc.3.43.51.71.83.91.99.107.154, %struct.bit_stream_struc.3.43.51.71.83.91.99.107.154* %bs, i64 0, i32 6
+  br i1 undef, label %for.body, label %cleanup
+
+for.body:
+  %indvars.iv28 = phi i64 [ %indvars.iv.next29, %for.body ], [ 0, %entry ]
+  %indvars.iv.next29 = add nuw nsw i64 %indvars.iv28, 1
+  %0 = load i32, i32* %buf_byte_idx5.phi.trans.insert, align 8
+  %cmp6 = icmp sgt i32 0, %0
+  br i1 %cmp6, label %for.body, label %for.end.loopexit
+
+for.end.loopexit:
+  %var1 = trunc i64 %indvars.iv.next29 to i32
+  br label %cleanup
+
+cleanup:
+  %retval.0 = phi i32 [ 0, %entry ], [ %var1, %for.end.loopexit ]
+  ret i32 %retval.0
+}
+
+
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_body[i0] -> MemRef_bs[11] };
+; CHECK-NEXT:         Execution Context: [p_0_loaded_from_bs] -> {  :  }
+; CHECK-NEXT: }
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_body[0] : p_0_loaded_from_bs >= 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_body[i0] -> [0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_body[i0] -> MemRef_indvars_iv_next29[] };
+; CHECK-NEXT:     Stmt_for_end_loopexit
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_end_loopexit[] : p_0_loaded_from_bs >= 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_end_loopexit[] -> [1, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_end_loopexit[] -> MemRef_indvars_iv_next29[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_end_loopexit[] -> MemRef_var1[] };
+; CHECK-NEXT: }
diff --git a/final/test/Isl/CodeGen/variant_load_empty_domain.ll b/final/test/Isl/CodeGen/variant_load_empty_domain.ll
new file mode 100644
index 0000000..cad283c
--- /dev/null
+++ b/final/test/Isl/CodeGen/variant_load_empty_domain.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-codegen -analyze < %s
+;
+;
+;    void f(int *A) {
+;      for (int i = 1; i < 10; i++) {
+;        A[i]++;
+;        if (i > 10)
+;          A[i] += A[0];
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 1, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 10
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br i1 false, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %tmp1 = load i32, i32* %A, align 4
+  %arrayidx4 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx4, align 4
+  %add = add nsw i32 %tmp2, %tmp1
+  store i32 %add, i32* %arrayidx4, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/Isl/CodeGen/whole-scop-non-affine-subregion.ll b/final/test/Isl/CodeGen/whole-scop-non-affine-subregion.ll
new file mode 100644
index 0000000..552fc91
--- /dev/null
+++ b/final/test/Isl/CodeGen/whole-scop-non-affine-subregion.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly \
+; RUN: -polly-codegen -S < %s | FileCheck %s
+
+; CHECK: polly.start
+;    int /* pure */ g()
+;    void f(int *A) {
+;      if (g())
+;        *A = *A + 1;
+;      else
+;        *A = *A - 1;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+entry:
+  br label %entry.split
+
+entry.split:
+  %call = call i32 @g()
+  %cmp = icmp eq i32 %call, 0
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  %tmp1 = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp1, 1
+  store i32 %add, i32* %A, align 4
+  br label %if.end
+
+if.else:                                          ; preds = %entry
+  %tmp2 = load i32, i32* %A, align 4
+  %sub = add nsw i32 %tmp2, -1
+  store i32 %sub, i32* %A, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  ret void
+}
+
+declare i32 @g() #0
+
+attributes #0 = { nounwind readnone }
diff --git a/final/test/Isl/single_loop_param_less_equal.ll b/final/test/Isl/single_loop_param_less_equal.ll
new file mode 100644
index 0000000..02013b8
--- /dev/null
+++ b/final/test/Isl/single_loop_param_less_equal.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen  -S < %s | FileCheck %s -check-prefix=CODEGEN
+; RUN: opt %loadPolly -polly-codegen -loops -analyze < %s | FileCheck %s -check-prefix=LOOPS
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x i32] zeroinitializer
+
+define void @bar(i64 %n) {
+start:
+  %n_plus_one = add i64 %n, 1
+  fence seq_cst
+  br label %loop.header
+
+loop.header:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.backedge ]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %i
+  %exitcond = icmp ne i64 %i, %n_plus_one
+  br i1 %exitcond, label %loop.body, label %ret
+
+loop.body:
+  store i32 1, i32* %scevgep
+  br label %loop.backedge
+
+loop.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.header
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: for (int c0 = 0; c0 <= n; c0 += 1)
+; CHECK:   Stmt_loop_body(c0)
+
+; CODEGEN: polly.start:
+; CODEGEN:   br label %polly.loop_if
+
+; CODEGEN: polly.loop_exit:
+; CODEGEN:   br label %polly.merge_new_and_old
+
+; CODEGEN: polly.loop_if:
+; CODEGEN:   %polly.loop_guard = icmp sle i64 0, %n
+; CODEGEN:   br i1 %polly.loop_guard, label %polly.loop_preheader, label %polly.loop_exit
+
+; CODEGEN: polly.loop_header:
+; CODEGEN:   %polly.indvar = phi i64 [ 0, %polly.loop_preheader ], [ %polly.indvar_next, %polly.stmt.loop.body ]
+; CODEGEN:   br label %polly.stmt.loop.body
+
+; CODEGEN: polly.stmt.loop.body:
+; CODEGEN:   [[PTR:%[a-zA-Z0-9_\.]+]] = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %polly.indvar
+; CODEGEN:   store i32 1, i32* [[PTR]]
+; CODEGEN:   %polly.indvar_next = add nsw i64 %polly.indvar, 1
+; CODEGEN:   %polly.loop_cond = icmp sle i64 %polly.indvar_next, %n
+; CODEGEN:   br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit
+
+; CODEGEN: polly.loop_preheader:
+; CODEGEN:   br label %polly.loop_header
+
+; LOOPS-DAG: Loop at depth 1 containing: %loop.header<header><exiting>,%loop.body,%loop.backedge<latch>
+; LOOPS-DAG: Loop at depth 1 containing: %polly.loop_header<header>,%polly.stmt.loop.body<latch><exiting>
diff --git a/final/test/Isl/single_loop_param_less_than.ll b/final/test/Isl/single_loop_param_less_than.ll
new file mode 100644
index 0000000..0a18857
--- /dev/null
+++ b/final/test/Isl/single_loop_param_less_than.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen  -S < %s | FileCheck %s -check-prefix=CODEGEN
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x i32] zeroinitializer
+
+define void @bar(i64 %n) {
+start:
+  fence seq_cst
+  br label %loop.header
+
+loop.header:
+  %i = phi i64 [ 0, %start ], [ %i.next, %loop.backedge ]
+  %scevgep = getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %i
+  %exitcond = icmp ne i64 %i, %n
+  br i1 %exitcond, label %loop.body, label %ret
+
+loop.body:
+  store i32 1, i32* %scevgep
+  br label %loop.backedge
+
+loop.backedge:
+  %i.next = add nsw i64 %i, 1
+  br label %loop.header
+
+ret:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: for (int c0 = 0; c0 < n; c0 += 1)
+; CHECK:   Stmt_loop_body(c0)
+
+; CODEGEN: polly.start:
+; CODEGEN:   br label %polly.loop_if
+
+; CODEGEN: polly.loop_exit:
+; CODEGEN:   br label %polly.merge_new_and_old
+
+; CODEGEN: polly.loop_if:
+; CODEGEN:   %polly.loop_guard = icmp slt i64 0, %n
+; CODEGEN:   br i1 %polly.loop_guard, label %polly.loop_preheader, label %polly.loop_exit
+
+; CODEGEN: polly.loop_header:
+; CODEGEN:   %polly.indvar = phi i64 [ 0, %polly.loop_preheader ], [ %polly.indvar_next, %polly.stmt.loop.body ]
+; CODEGEN:   br label %polly.stmt.loop.body
+
+; CODEGEN: polly.stmt.loop.body:
+; CODEGEN:   [[PTR:%[a-zA-Z0-9_\.]+]] =  getelementptr [1024 x i32], [1024 x i32]* @A, i64 0, i64 %polly.indvar
+; CODEGEN:   store i32 1, i32* [[PTR]]
+; CODEGEN:   %polly.indvar_next = add nsw i64 %polly.indvar, 1
+; CODEGEN:   %polly.loop_cond = icmp slt i64 %polly.indvar_next, %n
+; CODEGEN:   br i1 %polly.loop_cond, label %polly.loop_header, label %polly.loop_exit
+
+; CODEGEN: polly.loop_preheader:
+; CODEGEN:   br label %polly.loop_header
diff --git a/final/test/Isl/single_loop_uint_max_iterations.ll b/final/test/Isl/single_loop_uint_max_iterations.ll
new file mode 100644
index 0000000..495b7c1
--- /dev/null
+++ b/final/test/Isl/single_loop_uint_max_iterations.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-ast -S -analyze  < %s | FileCheck %s
+; XFAIL: *
+
+;#include "limits.h"
+;#define N 20
+;
+;int main () {
+;  unsigned int i;
+;  unsigned int A[N];
+;
+;  A[0] = 0;
+;
+;  __sync_synchronize();
+;
+;  for (i = 0; i < UINT_MAX; i++)
+;    A[0] = i;
+;
+;  __sync_synchronize();
+;
+;  if (A[0] == UINT_MAX - 1)
+;    return 0;
+;  else
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define i32 @main() nounwind {
+entry:
+  %A = alloca [20 x i32], align 4                 ; <[20 x i32]*> [#uses=3]
+  %arraydecay = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx = getelementptr inbounds i32, i32* %arraydecay, i64 0 ; <i32*> [#uses=1]
+  store i32 0, i32* %arrayidx
+  fence seq_cst
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]  ; <i32> [#uses=3]
+  %exitcond = icmp ne i32 %0, -1                  ; <i1> [#uses=1]
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arraydecay2 = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx3 = getelementptr inbounds i32, i32* %arraydecay2, i64 0 ; <i32*> [#uses=1]
+  store i32 %0, i32* %arrayidx3
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add i32 %0, 1                            ; <i32> [#uses=1]
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  fence seq_cst
+  %arraydecay5 = getelementptr inbounds [20 x i32], [20 x i32]* %A, i32 0, i32 0 ; <i32*> [#uses=1]
+  %arrayidx6 = getelementptr inbounds i32, i32* %arraydecay5, i64 0 ; <i32*> [#uses=1]
+  %tmp7 = load i32, i32* %arrayidx6                    ; <i32> [#uses=1]
+  %cmp8 = icmp eq i32 %tmp7, -2                   ; <i1> [#uses=1]
+  br i1 %cmp8, label %if.then, label %if.else
+
+if.then:                                          ; preds = %for.end
+  br label %return
+
+if.else:                                          ; preds = %for.end
+  br label %return
+
+return:                                           ; preds = %if.else, %if.then
+  %retval.0 = phi i32 [ 0, %if.then ], [ 1, %if.else ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+
+; CHECK:for (c2=0;
diff --git a/final/test/Isl/single_loop_ull_max_iterations.ll b/final/test/Isl/single_loop_ull_max_iterations.ll
new file mode 100644
index 0000000..2b7320c
--- /dev/null
+++ b/final/test/Isl/single_loop_ull_max_iterations.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-ast -S -analyze  < %s | FileCheck %s
+; XFAIL: *
+
+;#include "limits.h"
+;#define N 20
+;
+;int main () {
+;  unsigned long long i;
+;  unsigned long long A[N];
+;
+;  A[0] = 0;
+;
+;  __sync_synchronize();
+;
+;  for (i = 0; i < ULLONG_MAX; i++)
+;    A[0] = i;
+;
+;  __sync_synchronize();
+;
+;  if (A[0] == ULLONG_MAX - 1)
+;    return 0;
+;  else
+;    return 1;
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define i32 @main() nounwind {
+entry:
+  %A = alloca [20 x i64], align 8                 ; <[20 x i64]*> [#uses=3]
+  %arraydecay = getelementptr inbounds [20 x i64], [20 x i64]* %A, i32 0, i32 0 ; <i64*> [#uses=1]
+  %arrayidx = getelementptr inbounds i64, i64* %arraydecay, i64 0 ; <i64*> [#uses=1]
+  store i64 0, i64* %arrayidx
+  fence seq_cst
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]  ; <i64> [#uses=3]
+  %exitcond = icmp ne i64 %0, -1                  ; <i1> [#uses=1]
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arraydecay2 = getelementptr inbounds [20 x i64], [20 x i64]* %A, i32 0, i32 0 ; <i64*> [#uses=1]
+  %arrayidx3 = getelementptr inbounds i64, i64* %arraydecay2, i64 0 ; <i64*> [#uses=1]
+  store i64 %0, i64* %arrayidx3
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add i64 %0, 1                            ; <i64> [#uses=1]
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  fence seq_cst
+  %arraydecay5 = getelementptr inbounds [20 x i64], [20 x i64]* %A, i32 0, i32 0 ; <i64*> [#uses=1]
+  %arrayidx6 = getelementptr inbounds i64, i64* %arraydecay5, i64 0 ; <i64*> [#uses=1]
+  %tmp7 = load i64, i64* %arrayidx6                    ; <i64> [#uses=1]
+  %cmp8 = icmp eq i64 %tmp7, -2                   ; <i1> [#uses=1]
+  br i1 %cmp8, label %if.then, label %if.else
+
+if.then:                                          ; preds = %for.end
+  br label %return
+
+if.else:                                          ; preds = %for.end
+  br label %return
+
+return:                                           ; preds = %if.else, %if.then
+  %retval.0 = phi i32 [ 0, %if.then ], [ 1, %if.else ] ; <i32> [#uses=1]
+  ret i32 %retval.0
+}
+
+; CHECK:for (c2=0;
diff --git a/final/test/JSONExporter/ImportAccesses/ImportAccesses-Bad-relation.ll b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Bad-relation.ll
new file mode 100644
index 0000000..3b3e841
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Bad-relation.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel  < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: The access was not parsed successfully by ISL.
+;
+; Verify that the JSONImporter checks if the relation is valid.
+;
+;    void ia6(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @ia6(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportAccesses/ImportAccesses-No-accesses-key.ll b/final/test/JSONExporter/ImportAccesses/ImportAccesses-No-accesses-key.ll
new file mode 100644
index 0000000..981466b
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ImportAccesses-No-accesses-key.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel  < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: Statement from JScop file has no key name 'accesses' for index 1.
+;
+; Verify that the JSONImporter checks if there is a key name "accesses" for each statement.
+;
+;    void ia3(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @ia3(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportAccesses/ImportAccesses-Not-enough-MemAcc.ll b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Not-enough-MemAcc.ll
new file mode 100644
index 0000000..7145aea
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Not-enough-MemAcc.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel  < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: The number of memory accesses in the JSop file and the number of memory accesses differ for index 0.
+;
+; Verify that the JSONImporter checks if there is the correct number of memory accesses.
+;
+;    void ia4(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @ia4(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportAccesses/ImportAccesses-Not-enough-statements.ll b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Not-enough-statements.ll
new file mode 100644
index 0000000..0e0073e
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Not-enough-statements.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel  < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: The number of indices and the number of statements differ.
+;
+; Verify that the JSONImporter checks if the number of indices and the number of statements differ.
+;
+;    void ia2(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @ia2(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportAccesses/ImportAccesses-Relation-mispelled.ll b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Relation-mispelled.ll
new file mode 100644
index 0000000..ac75a3f
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Relation-mispelled.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel  < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: Memory access number 0 has no key name 'relation' for statement number 1.
+;
+; Verify that the JSONImporter checks if there is a key name 'relation' for each MemAcc.
+;
+;    void ia5(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @ia5(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportAccesses/ImportAccesses-Statements-mispelled.ll b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Statements-mispelled.ll
new file mode 100644
index 0000000..70c0b31
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Statements-mispelled.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel  < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: JScop file has no key name 'statements'.
+;
+; Verify that the JSONImporter checks if there is a key name 'statements'.
+;
+;    void ia(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @ia(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportAccesses/ImportAccesses-Undeclared-ScopArrayInfo.ll b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Undeclared-ScopArrayInfo.ll
new file mode 100644
index 0000000..c2bd35e
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Undeclared-ScopArrayInfo.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel  < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: JScop file contains access function with undeclared ScopArrayInfo
+;
+; Verify that the JSONImporter checks if the access function have a declared ScopArrayInfo.
+;
+;    void ia8(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @ia8(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportAccesses/ImportAccesses-Wrong-number-dimensions.ll b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Wrong-number-dimensions.ll
new file mode 100644
index 0000000..6c5ee41
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ImportAccesses-Wrong-number-dimensions.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel  < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: JScop file changes the number of parameter dimensions.
+;
+; Verify that the JSONImporter checks if there is the right parameter dimensions.
+;
+;    void ia7(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @ia7(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportAccesses/ia2___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportAccesses/ia2___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..1199995
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ia2___%for.cond---%for.end10.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportAccesses/ia3___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportAccesses/ia3___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..a592c85
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ia3___%for.cond---%for.end10.jscop
@@ -0,0 +1,26 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportAccesses/ia4___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportAccesses/ia4___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..5c38777
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ia4___%for.cond---%for.end10.jscop
@@ -0,0 +1,28 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportAccesses/ia5___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportAccesses/ia5___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..47ed037
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ia5___%for.cond---%for.end10.jscop
@@ -0,0 +1,31 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportAccesses/ia6___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportAccesses/ia6___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..5cd919a
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ia6___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportAccesses/ia7___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportAccesses/ia7___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..1b7826e
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ia7___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n, m] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportAccesses/ia8___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportAccesses/ia8___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..0680d3c
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ia8___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> Memef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportAccesses/ia___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportAccesses/ia___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..b341786
--- /dev/null
+++ b/final/test/JSONExporter/ImportAccesses/ia___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "sttements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportArrays/ImportArrays-Mispelled-type.ll b/final/test/JSONExporter/ImportArrays/ImportArrays-Mispelled-type.ll
new file mode 100644
index 0000000..bed324e
--- /dev/null
+++ b/final/test/JSONExporter/ImportArrays/ImportArrays-Mispelled-type.ll
@@ -0,0 +1,58 @@
+  ; RUN: not opt %loadPolly -polly-scops -analyze -polly-import-jscop -polly-import-jscop-postfix=transformed < %s 2>&1 | FileCheck %s
+;
+; CHECK: Array has not a valid type.
+;
+; Verify if the JSONImporter checks if the parsed type is valid.
+;
+;  for (i = 0; i < _PB_NI; i++)
+;    for (j = 0; j < _PB_NJ; j++)
+;      for (k = 0; k < _PB_NK; ++k)
+;        B[i][j] = beta * A[i][k];
+;
+;
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+; Function Attrs: nounwind uwtable
+define internal void @ia4(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %beta, [1056 x double]* %A, [1024 x double]* %B, [1056 x double]* %arg7) #0 {
+bb:
+  br label %bb8
+
+bb8:                                              ; preds = %bb
+  br label %bb9
+
+bb9:                                              ; preds = %bb23, %bb8
+  %tmp = phi i64 [ 0, %bb8 ], [ %tmp24, %bb23 ]
+  br label %bb10
+
+bb10:                                             ; preds = %bb20, %bb9
+  %tmp11 = phi i64 [ 0, %bb9 ], [ %tmp21, %bb20 ]
+  br label %bb12
+
+bb12:                                             ; preds = %bb12, %bb10
+  %tmp13 = phi i64 [ 0, %bb10 ], [ %tmp18, %bb12 ]
+  %tmp14 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %tmp, i64 %tmp13
+  %tmp15 = load double, double* %tmp14, align 8
+  %tmp16 = fmul double %tmp15, %beta
+  %tmp17 = getelementptr inbounds [1056 x double], [1056 x double]* %A, i64 %tmp, i64 %tmp11
+  store double %tmp16, double* %tmp17, align 8
+  %tmp18 = add nuw nsw i64 %tmp13, 1
+  %tmp19 = icmp ne i64 %tmp18, 1024
+  br i1 %tmp19, label %bb12, label %bb20
+
+bb20:                                             ; preds = %bb12
+  %tmp21 = add nuw nsw i64 %tmp11, 1
+  %tmp22 = icmp ne i64 %tmp21, 1056
+  br i1 %tmp22, label %bb10, label %bb23
+
+bb23:                                             ; preds = %bb20
+  %tmp24 = add nuw nsw i64 %tmp, 1
+  %tmp25 = icmp ne i64 %tmp24, 1056
+  br i1 %tmp25, label %bb9, label %bb26
+
+bb26:                                             ; preds = %bb23
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+aes,+avx,+cmov,+cx16,+fxsr,+mmx,+pclmul,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" }
diff --git a/final/test/JSONExporter/ImportArrays/ImportArrays-Negative-size.ll b/final/test/JSONExporter/ImportArrays/ImportArrays-Negative-size.ll
new file mode 100644
index 0000000..16e5071
--- /dev/null
+++ b/final/test/JSONExporter/ImportArrays/ImportArrays-Negative-size.ll
@@ -0,0 +1,77 @@
+; RUN: not opt %loadPolly -polly-scops -analyze -polly-import-jscop -polly-import-jscop-postfix=transformed < %s 2>&1 | FileCheck %s
+;
+; #define Ni 1056
+; #define Nj 1056
+; #define Nk 1024
+;
+; void ImportArray_Negative_size(double beta, double A[Ni][Nk], double B[Ni][Nj]) {
+;   int i,j,k;
+;
+;   for (i = 0; i < Ni; i++) {
+;     for (j = 0; j < Nj; j++) {
+;       for (k = 0; k < Nk; ++k) {
+;         B[i][j] = beta * A[i][k];
+;       }
+;     }
+;   }
+; }
+;
+; Verify if the JSONImporter checks if the size of the new array is positive.
+; CHECK: The size at index 0 is =< 0.
+;
+; ModuleID = 'ImportArrays-Negative-size.ll'
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @ImportArrays_Negative_Size(double %beta, [1024 x double]* nocapture readonly %A, [1056 x double]* nocapture %B) local_unnamed_addr {
+entry:
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.inc16, %entry
+  %indvars.iv35 = phi i64 [ 0, %entry ], [ %indvars.iv.next36, %for.inc16 ]
+  br label %for.cond4.preheader
+
+for.cond4.preheader:                              ; preds = %for.inc13, %for.cond1.preheader
+  %indvars.iv32 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next33, %for.inc13 ]
+  %arrayidx12 = getelementptr inbounds [1056 x double], [1056 x double]* %B, i64 %indvars.iv35, i64 %indvars.iv32
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.cond4.preheader
+  %indvars.iv = phi i64 [ 0, %for.cond4.preheader ], [ %indvars.iv.next.3, %for.body6 ]
+  %arrayidx8 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 %indvars.iv35, i64 %indvars.iv
+  %0 = load double, double* %arrayidx8, align 8
+  %mul = fmul double %0, %beta
+  store double %mul, double* %arrayidx12, align 8
+  %indvars.iv.next = or i64 %indvars.iv, 1
+  %arrayidx8.1 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 %indvars.iv35, i64 %indvars.iv.next
+  %1 = load double, double* %arrayidx8.1, align 8
+  %mul.1 = fmul double %1, %beta
+  store double %mul.1, double* %arrayidx12, align 8
+  %indvars.iv.next.1 = or i64 %indvars.iv, 2
+  %arrayidx8.2 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 %indvars.iv35, i64 %indvars.iv.next.1
+  %2 = load double, double* %arrayidx8.2, align 8
+  %mul.2 = fmul double %2, %beta
+  store double %mul.2, double* %arrayidx12, align 8
+  %indvars.iv.next.2 = or i64 %indvars.iv, 3
+  %arrayidx8.3 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 %indvars.iv35, i64 %indvars.iv.next.2
+  %3 = load double, double* %arrayidx8.3, align 8
+  %mul.3 = fmul double %3, %beta
+  store double %mul.3, double* %arrayidx12, align 8
+  %indvars.iv.next.3 = add nsw i64 %indvars.iv, 4
+  %exitcond.3 = icmp eq i64 %indvars.iv.next.3, 1024
+  br i1 %exitcond.3, label %for.inc13, label %for.body6
+
+for.inc13:                                        ; preds = %for.body6
+  %indvars.iv.next33 = add nuw nsw i64 %indvars.iv32, 1
+  %exitcond34 = icmp eq i64 %indvars.iv.next33, 1056
+  br i1 %exitcond34, label %for.inc16, label %for.cond4.preheader
+
+for.inc16:                                        ; preds = %for.inc13
+  %indvars.iv.next36 = add nuw nsw i64 %indvars.iv35, 1
+  %exitcond37 = icmp eq i64 %indvars.iv.next36, 1056
+  br i1 %exitcond37, label %for.end18, label %for.cond1.preheader
+
+for.end18:                                        ; preds = %for.inc16
+  ret void
+}
diff --git a/final/test/JSONExporter/ImportArrays/ImportArrays-No-name.ll b/final/test/JSONExporter/ImportArrays/ImportArrays-No-name.ll
new file mode 100644
index 0000000..2dbdc8e
--- /dev/null
+++ b/final/test/JSONExporter/ImportArrays/ImportArrays-No-name.ll
@@ -0,0 +1,58 @@
+; RUN: not opt %loadPolly -polly-scops -analyze -polly-import-jscop -polly-import-jscop-postfix=transformed < %s 2>&1 | FileCheck %s
+;
+; CHECK: Array has no key 'name'.
+;
+; Verify if the JSONImporter checks if the arrays have a key name 'name'.
+;
+;  for (i = 0; i < _PB_NI; i++)
+;    for (j = 0; j < _PB_NJ; j++)
+;      for (k = 0; k < _PB_NK; ++k)
+;        B[i][j] = beta * A[i][k];
+;
+;
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+; Function Attrs: nounwind uwtable
+define internal void @ia3(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %beta, [1056 x double]* %A, [1024 x double]* %B, [1056 x double]* %arg7) #0 {
+bb:
+  br label %bb8
+
+bb8:                                              ; preds = %bb
+  br label %bb9
+
+bb9:                                              ; preds = %bb23, %bb8
+  %tmp = phi i64 [ 0, %bb8 ], [ %tmp24, %bb23 ]
+  br label %bb10
+
+bb10:                                             ; preds = %bb20, %bb9
+  %tmp11 = phi i64 [ 0, %bb9 ], [ %tmp21, %bb20 ]
+  br label %bb12
+
+bb12:                                             ; preds = %bb12, %bb10
+  %tmp13 = phi i64 [ 0, %bb10 ], [ %tmp18, %bb12 ]
+  %tmp14 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %tmp, i64 %tmp13
+  %tmp15 = load double, double* %tmp14, align 8
+  %tmp16 = fmul double %tmp15, %beta
+  %tmp17 = getelementptr inbounds [1056 x double], [1056 x double]* %A, i64 %tmp, i64 %tmp11
+  store double %tmp16, double* %tmp17, align 8
+  %tmp18 = add nuw nsw i64 %tmp13, 1
+  %tmp19 = icmp ne i64 %tmp18, 1024
+  br i1 %tmp19, label %bb12, label %bb20
+
+bb20:                                             ; preds = %bb12
+  %tmp21 = add nuw nsw i64 %tmp11, 1
+  %tmp22 = icmp ne i64 %tmp21, 1056
+  br i1 %tmp22, label %bb10, label %bb23
+
+bb23:                                             ; preds = %bb20
+  %tmp24 = add nuw nsw i64 %tmp, 1
+  %tmp25 = icmp ne i64 %tmp24, 1056
+  br i1 %tmp25, label %bb9, label %bb26
+
+bb26:                                             ; preds = %bb23
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+aes,+avx,+cmov,+cx16,+fxsr,+mmx,+pclmul,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" }
diff --git a/final/test/JSONExporter/ImportArrays/ImportArrays-No-sizes-key.ll b/final/test/JSONExporter/ImportArrays/ImportArrays-No-sizes-key.ll
new file mode 100644
index 0000000..e96ddea
--- /dev/null
+++ b/final/test/JSONExporter/ImportArrays/ImportArrays-No-sizes-key.ll
@@ -0,0 +1,58 @@
+; RUN: not opt %loadPolly -polly-scops -analyze -polly-import-jscop -polly-import-jscop-postfix=transformed < %s 2>&1 | FileCheck %s
+;
+; CHECK: Array has no key 'sizes'.
+;
+; Verify if the JSONImporter checks if the arrays have a key name 'sizes'.
+;
+;  for (i = 0; i < _PB_NI; i++)
+;    for (j = 0; j < _PB_NJ; j++)
+;      for (k = 0; k < _PB_NK; ++k)
+;        B[i][j] = beta * A[i][k];
+;
+;
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+; Function Attrs: nounwind uwtable
+define internal void @ia2(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %beta, [1056 x double]* %A, [1024 x double]* %B, [1056 x double]* %arg7) #0 {
+bb:
+  br label %bb8
+
+bb8:                                              ; preds = %bb
+  br label %bb9
+
+bb9:                                              ; preds = %bb23, %bb8
+  %tmp = phi i64 [ 0, %bb8 ], [ %tmp24, %bb23 ]
+  br label %bb10
+
+bb10:                                             ; preds = %bb20, %bb9
+  %tmp11 = phi i64 [ 0, %bb9 ], [ %tmp21, %bb20 ]
+  br label %bb12
+
+bb12:                                             ; preds = %bb12, %bb10
+  %tmp13 = phi i64 [ 0, %bb10 ], [ %tmp18, %bb12 ]
+  %tmp14 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %tmp, i64 %tmp13
+  %tmp15 = load double, double* %tmp14, align 8
+  %tmp16 = fmul double %tmp15, %beta
+  %tmp17 = getelementptr inbounds [1056 x double], [1056 x double]* %A, i64 %tmp, i64 %tmp11
+  store double %tmp16, double* %tmp17, align 8
+  %tmp18 = add nuw nsw i64 %tmp13, 1
+  %tmp19 = icmp ne i64 %tmp18, 1024
+  br i1 %tmp19, label %bb12, label %bb20
+
+bb20:                                             ; preds = %bb12
+  %tmp21 = add nuw nsw i64 %tmp11, 1
+  %tmp22 = icmp ne i64 %tmp21, 1056
+  br i1 %tmp22, label %bb10, label %bb23
+
+bb23:                                             ; preds = %bb20
+  %tmp24 = add nuw nsw i64 %tmp, 1
+  %tmp25 = icmp ne i64 %tmp24, 1056
+  br i1 %tmp25, label %bb9, label %bb26
+
+bb26:                                             ; preds = %bb23
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+aes,+avx,+cmov,+cx16,+fxsr,+mmx,+pclmul,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" }
diff --git a/final/test/JSONExporter/ImportArrays/ImportArrays-No-type-key.ll b/final/test/JSONExporter/ImportArrays/ImportArrays-No-type-key.ll
new file mode 100644
index 0000000..84b3ab6
--- /dev/null
+++ b/final/test/JSONExporter/ImportArrays/ImportArrays-No-type-key.ll
@@ -0,0 +1,58 @@
+; RUN: not opt %loadPolly -polly-scops -analyze -polly-import-jscop -polly-import-jscop-postfix=transformed < %s 2>&1 | FileCheck %s
+;
+; CHECK: Array has no key 'type'.
+;
+; Verify if the JSONImporter checks if the arrays have a key name 'type'.
+;
+;  for (i = 0; i < _PB_NI; i++)
+;    for (j = 0; j < _PB_NJ; j++)
+;      for (k = 0; k < _PB_NK; ++k)
+;        B[i][j] = beta * A[i][k];
+;
+;
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+; Function Attrs: nounwind uwtable
+define internal void @ia(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %beta, [1056 x double]* %A, [1024 x double]* %B, [1056 x double]* %arg7) #0 {
+bb:
+  br label %bb8
+
+bb8:                                              ; preds = %bb
+  br label %bb9
+
+bb9:                                              ; preds = %bb23, %bb8
+  %tmp = phi i64 [ 0, %bb8 ], [ %tmp24, %bb23 ]
+  br label %bb10
+
+bb10:                                             ; preds = %bb20, %bb9
+  %tmp11 = phi i64 [ 0, %bb9 ], [ %tmp21, %bb20 ]
+  br label %bb12
+
+bb12:                                             ; preds = %bb12, %bb10
+  %tmp13 = phi i64 [ 0, %bb10 ], [ %tmp18, %bb12 ]
+  %tmp14 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %tmp, i64 %tmp13
+  %tmp15 = load double, double* %tmp14, align 8
+  %tmp16 = fmul double %tmp15, %beta
+  %tmp17 = getelementptr inbounds [1056 x double], [1056 x double]* %A, i64 %tmp, i64 %tmp11
+  store double %tmp16, double* %tmp17, align 8
+  %tmp18 = add nuw nsw i64 %tmp13, 1
+  %tmp19 = icmp ne i64 %tmp18, 1024
+  br i1 %tmp19, label %bb12, label %bb20
+
+bb20:                                             ; preds = %bb12
+  %tmp21 = add nuw nsw i64 %tmp11, 1
+  %tmp22 = icmp ne i64 %tmp21, 1056
+  br i1 %tmp22, label %bb10, label %bb23
+
+bb23:                                             ; preds = %bb20
+  %tmp24 = add nuw nsw i64 %tmp, 1
+  %tmp25 = icmp ne i64 %tmp24, 1056
+  br i1 %tmp25, label %bb9, label %bb26
+
+bb26:                                             ; preds = %bb23
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+aes,+avx,+cmov,+cx16,+fxsr,+mmx,+pclmul,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" }
diff --git a/final/test/JSONExporter/ImportArrays/ImportArrays_Negative_Size___%for.cond1.preheader---%for.end18.jscop b/final/test/JSONExporter/ImportArrays/ImportArrays_Negative_Size___%for.cond1.preheader---%for.end18.jscop
new file mode 100644
index 0000000..9ed06bb
--- /dev/null
+++ b/final/test/JSONExporter/ImportArrays/ImportArrays_Negative_Size___%for.cond1.preheader---%for.end18.jscop
@@ -0,0 +1,61 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1056" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.cond1.preheader---%for.end18",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 4i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_beta[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 1 + 4i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 2 + 4i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 3 + 4i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body6[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 255 }",
+         "name" : "Stmt_for_body6",
+         "schedule" : "{ Stmt_for_body6[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportArrays/ImportArrays_Negative_Size___%for.cond1.preheader---%for.end18.jscop.transformed b/final/test/JSONExporter/ImportArrays/ImportArrays_Negative_Size___%for.cond1.preheader---%for.end18.jscop.transformed
new file mode 100644
index 0000000..35c23ab
--- /dev/null
+++ b/final/test/JSONExporter/ImportArrays/ImportArrays_Negative_Size___%for.cond1.preheader---%for.end18.jscop.transformed
@@ -0,0 +1,67 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1056" ],
+         "type" : "double"
+      },
+      {
+         "name" : "D",
+         "sizes" : [ "-270336" ],
+         "type" : "double",
+         "allocation" : "heap"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.cond1.preheader---%for.end18",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 4i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_beta[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 1 + 4i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 2 + 4i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 3 + 4i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt2[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 255 }",
+         "name" : "Stmt2",
+         "schedule" : "{ Stmt2[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportArrays/ia2___%bb9---%bb26.jscop.transformed b/final/test/JSONExporter/ImportArrays/ia2___%bb9---%bb26.jscop.transformed
new file mode 100644
index 0000000..e702919
--- /dev/null
+++ b/final/test/JSONExporter/ImportArrays/ia2___%bb9---%bb26.jscop.transformed
@@ -0,0 +1,51 @@
+{
+   "arrays" : [
+       {
+         "name" : "MemRef_B",
+	 "type" : "double"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1056" ],
+         "type" : "double"
+      },
+      {
+         "name" : "D",
+         "sizes" : [ "270336" ],
+         "type" : "double"
+      },
+      {
+         "name" : "E",
+         "sizes" : [ "270336", "200000" ],
+         "type" : "double"
+      },
+      {
+         "name" : "F",
+         "sizes" : [ "270336" ],
+         "type" : "i64"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb9---%bb26",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> E[i2, i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_beta[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_A[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb12[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 1023 }",
+         "name" : "Stmt_bb12",
+         "schedule" : "{ Stmt_bb12[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportArrays/ia3___%bb9---%bb26.jscop.transformed b/final/test/JSONExporter/ImportArrays/ia3___%bb9---%bb26.jscop.transformed
new file mode 100644
index 0000000..b3e968f
--- /dev/null
+++ b/final/test/JSONExporter/ImportArrays/ia3___%bb9---%bb26.jscop.transformed
@@ -0,0 +1,51 @@
+{
+   "arrays" : [
+       {
+         "sizes" : [ "*", "1024" ],
+	 "type" : "double"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1056" ],
+         "type" : "double"
+      },
+      {
+         "name" : "D",
+         "sizes" : [ "270336" ],
+         "type" : "double"
+      },
+      {
+         "name" : "E",
+         "sizes" : [ "270336", "200000" ],
+         "type" : "double"
+      },
+      {
+         "name" : "F",
+         "sizes" : [ "270336" ],
+         "type" : "i64"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb9---%bb26",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> E[i2, i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_beta[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_A[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb12[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 1023 }",
+         "name" : "Stmt_bb12",
+         "schedule" : "{ Stmt_bb12[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportArrays/ia4___%bb9---%bb26.jscop.transformed b/final/test/JSONExporter/ImportArrays/ia4___%bb9---%bb26.jscop.transformed
new file mode 100644
index 0000000..066294b
--- /dev/null
+++ b/final/test/JSONExporter/ImportArrays/ia4___%bb9---%bb26.jscop.transformed
@@ -0,0 +1,52 @@
+{
+   "arrays" : [
+       {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1024" ],
+	 "type" : "doble"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1056" ],
+         "type" : "double"
+      },
+      {
+         "name" : "D",
+         "sizes" : [ "270336" ],
+         "type" : "double"
+      },
+      {
+         "name" : "E",
+         "sizes" : [ "270336", "200000" ],
+         "type" : "double"
+      },
+      {
+         "name" : "F",
+         "sizes" : [ "270336" ],
+         "type" : "i64"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb9---%bb26",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> E[i2, i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_beta[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_A[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb12[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 1023 }",
+         "name" : "Stmt_bb12",
+         "schedule" : "{ Stmt_bb12[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportArrays/ia___%bb9---%bb26.jscop.transformed b/final/test/JSONExporter/ImportArrays/ia___%bb9---%bb26.jscop.transformed
new file mode 100644
index 0000000..5015e4e
--- /dev/null
+++ b/final/test/JSONExporter/ImportArrays/ia___%bb9---%bb26.jscop.transformed
@@ -0,0 +1,51 @@
+{
+   "arrays" : [
+       {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1024" ]
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1056" ],
+         "type" : "double"
+      },
+      {
+         "name" : "D",
+         "sizes" : [ "270336" ],
+         "type" : "double"
+      },
+      {
+         "name" : "E",
+         "sizes" : [ "270336", "200000" ],
+         "type" : "double"
+      },
+      {
+         "name" : "F",
+         "sizes" : [ "270336" ],
+         "type" : "i64"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb9---%bb26",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> E[i2, i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_beta[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_A[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb12[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 1023 }",
+         "name" : "Stmt_bb12",
+         "schedule" : "{ Stmt_bb12[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportContext/ImportContext-Context-mispelled.ll b/final/test/JSONExporter/ImportContext/ImportContext-Context-mispelled.ll
new file mode 100644
index 0000000..b9fed3b
--- /dev/null
+++ b/final/test/JSONExporter/ImportContext/ImportContext-Context-mispelled.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel  < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: JScop file has no key named 'context'.
+;
+; Verify if the JSONImporter check if there is a key name 'context'.
+;
+;    void ic(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @ic(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportContext/ImportContext-Not-parameter-set.ll b/final/test/JSONExporter/ImportContext/ImportContext-Not-parameter-set.ll
new file mode 100644
index 0000000..3d6cf88
--- /dev/null
+++ b/final/test/JSONExporter/ImportContext/ImportContext-Not-parameter-set.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: The isl_set is not a parameter set.
+;
+; Verify if the JSONImporter check if the imported set is a parameter one.
+;
+;    void ic3(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @ic3(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportContext/ImportContext-Unvalid-Context.ll b/final/test/JSONExporter/ImportContext/ImportContext-Unvalid-Context.ll
new file mode 100644
index 0000000..7762113
--- /dev/null
+++ b/final/test/JSONExporter/ImportContext/ImportContext-Unvalid-Context.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: The context was not parsed successfully by ISL.
+;
+; Verify if the JSONImporter check if the context is parsed successfully.
+;
+;    void ic2(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @ic2(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportContext/ImportContext-Wrong-dimension.ll b/final/test/JSONExporter/ImportContext/ImportContext-Wrong-dimension.ll
new file mode 100644
index 0000000..4a28415
--- /dev/null
+++ b/final/test/JSONExporter/ImportContext/ImportContext-Wrong-dimension.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: Imported context has the wrong number of parameters : Found 2 Expected 1
+;
+; Verify if the JSONImporter check if there is the right number of parameters.
+;
+;    void ic4(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @ic4(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportContext/ic2___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportContext/ic2___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..1461958
--- /dev/null
+++ b/final/test/JSONExporter/ImportContext/ic2___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "[n] -> {  :  >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportContext/ic3___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportContext/ic3___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..0046db8
--- /dev/null
+++ b/final/test/JSONExporter/ImportContext/ic3___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "{ S[n] : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportContext/ic4___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportContext/ic4___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..536b23e
--- /dev/null
+++ b/final/test/JSONExporter/ImportContext/ic4___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "[n, m] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportContext/ic___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportContext/ic___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..d083809
--- /dev/null
+++ b/final/test/JSONExporter/ImportContext/ic___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "cntext" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportSchedule/ImportSchedule-No-schedule-key.ll b/final/test/JSONExporter/ImportSchedule/ImportSchedule-No-schedule-key.ll
new file mode 100644
index 0000000..1cd439f
--- /dev/null
+++ b/final/test/JSONExporter/ImportSchedule/ImportSchedule-No-schedule-key.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: Statement 0 has no 'schedule' key.
+;
+; Verify if the JSONImporter check if there is a key name 'schedule'.
+;
+;    void is3(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @is3(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportSchedule/ImportSchedule-Schedule-not-valid.ll b/final/test/JSONExporter/ImportSchedule/ImportSchedule-Schedule-not-valid.ll
new file mode 100644
index 0000000..08788b8
--- /dev/null
+++ b/final/test/JSONExporter/ImportSchedule/ImportSchedule-Schedule-not-valid.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: The schedule was not parsed successfully (index = 1).
+;
+; Verify if the JSONImporter check if the parsed schedule is valid.
+;
+;    void is4(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @is4(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportSchedule/ImportSchedule-Statements-mispelled.ll b/final/test/JSONExporter/ImportSchedule/ImportSchedule-Statements-mispelled.ll
new file mode 100644
index 0000000..0738a76
--- /dev/null
+++ b/final/test/JSONExporter/ImportSchedule/ImportSchedule-Statements-mispelled.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: JScop file has no key name 'statements'.
+;
+; Verify if the JSONImporter check if there is a key name 'statements'.
+;
+;    void is(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @is(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportSchedule/ImportSchedule-Wrong-number-statements.ll b/final/test/JSONExporter/ImportSchedule/ImportSchedule-Wrong-number-statements.ll
new file mode 100644
index 0000000..7e2ff9e
--- /dev/null
+++ b/final/test/JSONExporter/ImportSchedule/ImportSchedule-Wrong-number-statements.ll
@@ -0,0 +1,64 @@
+; RUN: not opt %loadPolly -polly-import-jscop -polly-ast -polly-ast-detect-parallel < %s 2>&1 >/dev/null | FileCheck %s
+;
+; CHECK: The number of indices and the number of statements differ.
+;
+; Verify if the JSONImporter check if there is the right number of statements.
+;
+;    void is2(int *A, long n) {
+;      for (long i = 0; i < 2 * n; i++)
+; S0:    A[0] += i;
+;      for (long i = 0; i < 2 * n; i++)
+; S1:    A[i + 1] = 1;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @is2(i32* %A, i32 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %mul = shl nsw i32 %n, 1
+  %cmp = icmp slt i32 %i.0, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %S0
+
+S0:                                               ; preds = %for.body
+  %tmp = load i32, i32* %A, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %A, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S0
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc8, %for.end
+  %i1.0 = phi i32 [ 0, %for.end ], [ %inc9, %for.inc8 ]
+  %mul3 = shl nsw i32 %n, 1
+  %cmp4 = icmp slt i32 %i1.0, %mul3
+  br i1 %cmp4, label %for.body5, label %for.end10
+
+for.body5:                                        ; preds = %for.cond2
+  br label %S1
+
+S1:                                               ; preds = %for.body5
+  %add6 = add nsw i32 %i1.0, 1
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i32 %add6
+  store i32 1, i32* %arrayidx7, align 4
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %S1
+  %inc9 = add nsw i32 %i1.0, 1
+  br label %for.cond2
+
+for.end10:                                        ; preds = %for.cond2
+  ret void
+}
+
diff --git a/final/test/JSONExporter/ImportSchedule/is2___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportSchedule/is2___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..1199995
--- /dev/null
+++ b/final/test/JSONExporter/ImportSchedule/is2___%for.cond---%for.end10.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportSchedule/is3___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportSchedule/is3___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..39d0f67
--- /dev/null
+++ b/final/test/JSONExporter/ImportSchedule/is3___%for.cond---%for.end10.jscop
@@ -0,0 +1,31 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportSchedule/is4___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportSchedule/is4___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..9073b01
--- /dev/null
+++ b/final/test/JSONExporter/ImportSchedule/is4___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/JSONExporter/ImportSchedule/is___%for.cond---%for.end10.jscop b/final/test/JSONExporter/ImportSchedule/is___%for.cond---%for.end10.jscop
new file mode 100644
index 0000000..28e9c20
--- /dev/null
+++ b/final/test/JSONExporter/ImportSchedule/is___%for.cond---%for.end10.jscop
@@ -0,0 +1,32 @@
+{
+   "context" : "[n] -> {  : n >= -2147483648 and n <= 2147483647 }",
+   "name" : "for.cond => for.end10",
+   "staements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S0[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S0[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S0",
+         "schedule" : "[n] -> { Stmt_S0[i0] -> [0, n - i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_A[1 + i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + 2n and n >= 1 }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [1, n - i0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/MaximalStaticExpansion/load_after_store_same_statement.ll b/final/test/MaximalStaticExpansion/load_after_store_same_statement.ll
new file mode 100644
index 0000000..cad2475
--- /dev/null
+++ b/final/test/MaximalStaticExpansion/load_after_store_same_statement.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-mse -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-mse -pass-remarks-analysis="polly-mse" -analyze < %s 2>&1| FileCheck %s --check-prefix=MSE
+;
+; Verify that the expansion of an array with load after store in a same statement is not done.
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 3000
+;
+; void mse(double A[Ni], double B[Nj], double C[Nj], double D[Nj]) {
+;   int i,j;
+;   for (i = 0; i < Ni; i++) {
+;     for (int j = 0; j<Nj; j++) {
+;       B[j] = j;
+;       C[j] = B[j];
+;     }
+;   }
+; }
+;
+; Check that C is expanded
+;
+; CHECK: i64 MemRef_C_Stmt_for_body4_expanded[10000][10000]; // Element size 8
+; CHECK: new: { Stmt_for_body4[i0, i1] -> MemRef_C_Stmt_for_body4_expanded[i0, i1] };
+;
+; Check that B is not expanded
+;
+; CHECK-NOT: double MemRef_B_Stmt_for_body4_expanded[10000][10000]; // Element size 8
+; MSE: MemRef_B has read after write to the same element in same statement. The dependences found during analysis may be wrong because Polly is not able to handle such case for now.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @mse(double* %A, double* %B, double* %C, double* %D) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.inc9
+  %i.02 = phi i32 [ 0, %entry.split ], [ %inc10, %for.inc9 ]
+  br label %for.body4
+
+for.body4:                                        ; preds = %for.body, %for.body4
+  %indvars.iv = phi i64 [ 0, %for.body ], [ %indvars.iv.next, %for.body4 ]
+  %0 = trunc i64 %indvars.iv to i32
+  %conv = sitofp i32 %0 to double
+  %arrayidx = getelementptr inbounds double, double* %B, i64 %indvars.iv
+  store double %conv, double* %arrayidx, align 8
+  %arrayidx6 = getelementptr inbounds double, double* %B, i64 %indvars.iv
+  %1 = bitcast double* %arrayidx6 to i64*
+  %2 = load i64, i64* %1, align 8
+  %arrayidx8 = getelementptr inbounds double, double* %C, i64 %indvars.iv
+  %3 = bitcast double* %arrayidx8 to i64*
+  store i64 %2, i64* %3, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 10000
+  br i1 %exitcond, label %for.body4, label %for.inc9
+
+for.inc9:                                         ; preds = %for.body4
+  %inc10 = add nuw nsw i32 %i.02, 1
+  %exitcond3 = icmp ne i32 %inc10, 10000
+  br i1 %exitcond3, label %for.body, label %for.end11
+
+for.end11:                                        ; preds = %for.inc9
+  ret void
+}
diff --git a/final/test/MaximalStaticExpansion/read_from_original.ll b/final/test/MaximalStaticExpansion/read_from_original.ll
new file mode 100644
index 0000000..c46b25c
--- /dev/null
+++ b/final/test/MaximalStaticExpansion/read_from_original.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-mse -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-mse -pass-remarks-analysis="polly-mse" -analyze < %s 2>&1| FileCheck %s --check-prefix=MSE
+;
+; Verify that Polly detects problems and does not expand the array
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 3000
+; 
+; double mse(double A[Ni], double B[Nj]) {
+;   int i;
+;   double tmp = 6;
+;   for (i = 0; i < Ni; i++) {
+;     for (int j = 2; j<Nj; j++) {
+;       B[j-1] = j;
+;     }
+;     A[i] = B[i]; 
+;   }
+;   return tmp;
+; }
+;
+; Check that the pass detects the problem of read from original array after expansion.
+;
+; MSE: The expansion of MemRef_B would lead to a read from the original array.
+;
+; CHECK-NOT: double MemRef_B2_expanded[2000][3000]; // Element size 8
+;
+; Check that the  memory accesses are not modified
+;
+; CHECK-NOT: new: { Stmt_for_body3[i0, i1] -> MemRef_B_Stmt_for_body3_expanded[i0, i1] };
+; CHECK-NOT: new: { Stmt_for_end[i0] -> MemRef_B_Stmt_for_body3_expanded
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define double @mse(double* %A, double* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.end
+  %indvars.iv4 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next5, %for.end ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.body, %for.body3
+  %indvars.iv = phi i64 [ 2, %for.body ], [ %indvars.iv.next, %for.body3 ]
+  %0 = trunc i64 %indvars.iv to i32
+  %conv = sitofp i32 %0 to double
+  %1 = add nsw i64 %indvars.iv, -1
+  %arrayidx = getelementptr inbounds double, double* %B, i64 %1
+  store double %conv, double* %arrayidx, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 3000
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.end:                                          ; preds = %for.body3
+  %arrayidx5 = getelementptr inbounds double, double* %B, i64 %indvars.iv4
+  %2 = bitcast double* %arrayidx5 to i64*
+  %3 = load i64, i64* %2, align 8
+  %arrayidx7 = getelementptr inbounds double, double* %A, i64 %indvars.iv4
+  %4 = bitcast double* %arrayidx7 to i64*
+  store i64 %3, i64* %4, align 8
+  %indvars.iv.next5 = add nuw nsw i64 %indvars.iv4, 1
+  %exitcond6 = icmp ne i64 %indvars.iv.next5, 2000
+  br i1 %exitcond6, label %for.body, label %for.end10
+
+for.end10:                                        ; preds = %for.end
+  ret double 6.000000e+00
+}
diff --git a/final/test/MaximalStaticExpansion/too_many_writes.ll b/final/test/MaximalStaticExpansion/too_many_writes.ll
new file mode 100644
index 0000000..1dac814
--- /dev/null
+++ b/final/test/MaximalStaticExpansion/too_many_writes.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -polly-mse -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-mse -pass-remarks-analysis="polly-mse" -analyze < %s 2>&1 | FileCheck %s --check-prefix=MSE
+;
+; Verify that Polly detects problems and does not expand the array
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 2000
+; 
+; double mse(double A[Ni], double B[Nj]) {
+;   int i;
+;   double tmp = 6;
+;   for (i = 0; i < Ni; i++) {
+;     B[i] = 2; 
+;     for (int j = 0; j<Nj; j++) {
+;       B[j] = j;
+;     }
+;     A[i] = B[i]; 
+;   }
+;   return tmp;
+; }
+;
+; Check that the pass detects that there are more than 1 write access per array.
+;
+; MSE: MemRef_B has more than 1 write access.
+;
+; Check that the SAI is not expanded
+;
+; CHECK-NOT: double MemRef_B2_expanded[2000][3000]; // Element size 8
+;
+; Check that the  memory accesses are not modified
+;
+; CHECK-NOT: new: { Stmt_for_body3[i0, i1] -> MemRef_B_Stmt_for_body3_expanded[i0, i1] };
+; CHECK-NOT: new: { Stmt_for_end[i0] -> MemRef_B_Stmt_for_body3_expanded
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define double @mse(double* %A, double* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.end
+  %indvars.iv3 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next4, %for.end ]
+  %arrayidx = getelementptr inbounds double, double* %B, i64 %indvars.iv3
+  store double 2.000000e+00, double* %arrayidx, align 8
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.body, %for.body3
+  %indvars.iv = phi i64 [ 0, %for.body ], [ %indvars.iv.next, %for.body3 ]
+  %0 = trunc i64 %indvars.iv to i32
+  %conv = sitofp i32 %0 to double
+  %arrayidx5 = getelementptr inbounds double, double* %B, i64 %indvars.iv
+  store double %conv, double* %arrayidx5, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 2000
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.end:                                          ; preds = %for.body3
+  %arrayidx7 = getelementptr inbounds double, double* %B, i64 %indvars.iv3
+  %1 = bitcast double* %arrayidx7 to i64*
+  %2 = load i64, i64* %1, align 8
+  %arrayidx9 = getelementptr inbounds double, double* %A, i64 %indvars.iv3
+  %3 = bitcast double* %arrayidx9 to i64*
+  store i64 %2, i64* %3, align 8
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  %exitcond5 = icmp ne i64 %indvars.iv.next4, 2000
+  br i1 %exitcond5, label %for.body, label %for.end12
+
+for.end12:                                        ; preds = %for.end
+  ret double 6.000000e+00
+}
diff --git a/final/test/MaximalStaticExpansion/working_deps_between_inners.ll b/final/test/MaximalStaticExpansion/working_deps_between_inners.ll
new file mode 100644
index 0000000..7cf5f33
--- /dev/null
+++ b/final/test/MaximalStaticExpansion/working_deps_between_inners.ll
@@ -0,0 +1,97 @@
+; RUN: opt %loadPolly -polly-mse -analyze < %s | FileCheck %s
+;
+; Verify that the accesses are correctly expanded for MemoryKind::Array
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 3000
+; 
+; void tmp3(double A[Ni], double B[Nj]) {
+;   int i,j;
+;   double tmp = 6;
+;   for (i = 0; i < Ni; i++) {
+;
+;     for(int h = 0; h<Nj; h++)
+;      B[h] = h; 
+;    
+;     for(j = 0; j < Nj; j++) {
+;      for(int k=0; k<Nj; k++) {
+; 	tmp = i+k+j;
+; 	A[i+j] = tmp*B[k];
+;       }
+;     }
+;   }
+; }
+;
+; Check if the expanded SAI are created
+;
+; CHECK: double MemRef_B_Stmt_for_body3_expanded[10000][10000]; // Element size 8
+; CHECK: double MemRef_A_Stmt_for_body11_expanded[10000][10000][10000]; // Element size 8
+;
+; Check if the memory accesses are modified
+;
+; CHECK: new: { Stmt_for_body3[i0, i1] -> MemRef_B_Stmt_for_body3_expanded[i0, i1] };
+; CHECK: new: { Stmt_for_body11[i0, i1, i2] -> MemRef_B_Stmt_for_body3_expanded[i0, i2] };
+; CHECK: new: { Stmt_for_body11[i0, i1, i2] -> MemRef_A_Stmt_for_body11_expanded[i0, i1, i2] };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @mse(double* %A, double* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.inc25
+  %indvars.iv14 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next15, %for.inc25 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.body, %for.body3
+  %indvars.iv = phi i64 [ 0, %for.body ], [ %indvars.iv.next, %for.body3 ]
+  %0 = trunc i64 %indvars.iv to i32
+  %conv = sitofp i32 %0 to double
+  %arrayidx = getelementptr inbounds double, double* %B, i64 %indvars.iv
+  store double %conv, double* %arrayidx, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 10000
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.end:                                          ; preds = %for.body3
+  br label %for.body7
+
+for.body7:                                        ; preds = %for.end, %for.inc22
+  %indvars.iv9 = phi i64 [ 0, %for.end ], [ %indvars.iv.next10, %for.inc22 ]
+  br label %for.body11
+
+for.body11:                                       ; preds = %for.body7, %for.body11
+  %indvars.iv5 = phi i64 [ 0, %for.body7 ], [ %indvars.iv.next6, %for.body11 ]
+  %1 = add nuw nsw i64 %indvars.iv9, %indvars.iv14
+  %2 = add nuw nsw i64 %1, %indvars.iv5
+  %3 = trunc i64 %2 to i32
+  %conv13 = sitofp i32 %3 to double
+  %arrayidx15 = getelementptr inbounds double, double* %B, i64 %indvars.iv5
+  %4 = load double, double* %arrayidx15, align 8
+  %mul = fmul double %4, %conv13
+  %5 = add nuw nsw i64 %indvars.iv9, %indvars.iv14
+  %arrayidx18 = getelementptr inbounds double, double* %A, i64 %5
+  store double %mul, double* %arrayidx18, align 8
+  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1
+  %exitcond8 = icmp ne i64 %indvars.iv.next6, 10000
+  br i1 %exitcond8, label %for.body11, label %for.inc22
+
+for.inc22:                                        ; preds = %for.body11
+  %indvars.iv.next10 = add nuw nsw i64 %indvars.iv9, 1
+  %exitcond13 = icmp ne i64 %indvars.iv.next10, 10000
+  br i1 %exitcond13, label %for.body7, label %for.inc25
+
+for.inc25:                                        ; preds = %for.inc22
+  %indvars.iv.next15 = add nuw nsw i64 %indvars.iv14, 1
+  %exitcond16 = icmp ne i64 %indvars.iv.next15, 10000
+  br i1 %exitcond16, label %for.body, label %for.end27
+
+for.end27:                                        ; preds = %for.inc25
+  ret void
+}
diff --git a/final/test/MaximalStaticExpansion/working_deps_between_inners_phi.ll b/final/test/MaximalStaticExpansion/working_deps_between_inners_phi.ll
new file mode 100644
index 0000000..828c5a0
--- /dev/null
+++ b/final/test/MaximalStaticExpansion/working_deps_between_inners_phi.ll
@@ -0,0 +1,131 @@
+; RUN: opt %loadPolly -polly-mse -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-mse -pass-remarks-analysis="polly-mse" -analyze < %s 2>&1| FileCheck %s --check-prefix=MSE
+;
+; Verify that the accesses are correctly expanded for MemoryKind::Array and MemoryKind::PHI.
+; tmp_06_phi is not expanded because it need copy in.
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 3000
+; 
+; void tmp3(double A[Ni], double B[Nj]) {
+;   int i,j;
+;   double tmp = 6;
+;   for (i = 0; i < Ni; i++) {
+; 
+;     for(int h = 0; h<Nj; h++)
+;       B[h] = h;
+;     
+;     for(j = 0; j < Nj; j++) {
+;       for(int k=0; k<Nj; k++) {
+; 	tmp = tmp+i+k+j;
+; 	A[i+j] = tmp*B[k];
+;       }
+;     }
+;   }
+; }
+;
+; Check if the expanded SAI are created except for tmp_06_phi
+;
+; MSE: MemRef_tmp_06__phi read from its original value.
+;
+; CHECK-DAG: double MemRef_A_Stmt_for_body11_expanded[10000][10000][10000]; // Element size 8
+; CHECK-DAG: double MemRef_add16_lcssa__phi_Stmt_for_inc25_expanded[10000][10000]; // Element size 8
+; CHECK-DAG: double MemRef_B_Stmt_for_body3_expanded[10000][10000]; // Element size 8
+; CHECK-DAG: double MemRef_tmp_06_Stmt_for_body_expanded[10000]; // Element size 8
+; CHECK-DAG: double MemRef_add16_lcssa_lcssa__phi_Stmt_for_inc28_expanded[10000]; // Element size 8
+; CHECK-DAG: double MemRef_tmp_14__phi_Stmt_for_body7_expanded[10000][10000]; // Element size 8
+; CHECK-DAG: double MemRef_tmp_22__phi_Stmt_for_body11_expanded[10000][10000][10000]; // Element size 8
+; CHECK-NOT: double MemRef_tmp_06__phi_Stmt_for_body_expanded[10000]; // Element size 8
+;
+; Check if the memory accesses are modified except those of tmp_06_phi
+;
+; CHECK-NOT: new: { Stmt_for_body[i0] -> MemRef_tmp_06__phi_Stmt_for_body_expanded[i0] };
+; CHECK-DAG: new: { Stmt_for_body[i0] -> MemRef_tmp_06_Stmt_for_body_expanded[i0] };
+; CHECK-DAG: new: { Stmt_for_body3[i0, i1] -> MemRef_B_Stmt_for_body3_expanded[i0, i1] };
+; CHECK-DAG: new: { Stmt_for_end[i0] -> MemRef_tmp_06_Stmt_for_body_expanded[i0] };
+; CHECK-DAG: new: { Stmt_for_end[i0] -> MemRef_tmp_14__phi_Stmt_for_body7_expanded[i0, 0] };
+; CHECK-DAG: new: { Stmt_for_body7[i0, i1] -> MemRef_tmp_14__phi_Stmt_for_body7_expanded[i0, i1] };
+; CHECK-DAG: new: { Stmt_for_body7[i0, i1] -> MemRef_tmp_22__phi_Stmt_for_body11_expanded[i0, i1, 0] };
+; CHECK-DAG: new: { Stmt_for_body11[i0, i1, i2] -> MemRef_tmp_22__phi_Stmt_for_body11_expanded[i0, i1, 1 + i2] : i2 <= 9998 };
+; CHECK-DAG: new: { Stmt_for_body11[i0, i1, i2] -> MemRef_tmp_22__phi_Stmt_for_body11_expanded[i0, i1, i2] };
+; CHECK-DAG: new: { Stmt_for_body11[i0, i1, i2] -> MemRef_B_Stmt_for_body3_expanded[i0, i2] };
+; CHECK-DAG: new: { Stmt_for_body11[i0, i1, i2] -> MemRef_A_Stmt_for_body11_expanded[i0, i1, i2] };
+; CHECK-DAG: new: { Stmt_for_body11[i0, i1, 9999] -> MemRef_add16_lcssa__phi_Stmt_for_inc25_expanded[i0, i1] };
+; CHECK-DAG: new: { Stmt_for_inc25[i0, i1] -> MemRef_tmp_14__phi_Stmt_for_body7_expanded[i0, 1 + i1] : i1 <= 9998 };
+; CHECK-DAG: new: { Stmt_for_inc25[i0, i1] -> MemRef_add16_lcssa__phi_Stmt_for_inc25_expanded[i0, i1] };
+; CHECK-DAG: new: { Stmt_for_inc25[i0, 9999] -> MemRef_add16_lcssa_lcssa__phi_Stmt_for_inc28_expanded[i0] };
+; CHECK-DAG: new: { Stmt_for_inc28[i0] -> MemRef_add16_lcssa_lcssa__phi_Stmt_for_inc28_expanded[i0] };
+; CHECK-NOT: new: { Stmt_for_inc28[i0] -> MemRef_tmp_06__phi_Stmt_for_body_expanded[1 + i0] : i0 <= 9998 };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @mse(double* %A, double* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.inc28
+  %indvars.iv15 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next16, %for.inc28 ]
+  %tmp.06 = phi double [ 6.000000e+00, %entry.split ], [ %add16.lcssa.lcssa, %for.inc28 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.body, %for.body3
+  %indvars.iv = phi i64 [ 0, %for.body ], [ %indvars.iv.next, %for.body3 ]
+  %0 = trunc i64 %indvars.iv to i32
+  %conv = sitofp i32 %0 to double
+  %arrayidx = getelementptr inbounds double, double* %B, i64 %indvars.iv
+  store double %conv, double* %arrayidx, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 10000
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.end:                                          ; preds = %for.body3
+  br label %for.body7
+
+for.body7:                                        ; preds = %for.end, %for.inc25
+  %indvars.iv11 = phi i64 [ 0, %for.end ], [ %indvars.iv.next12, %for.inc25 ]
+  %tmp.14 = phi double [ %tmp.06, %for.end ], [ %add16.lcssa, %for.inc25 ]
+  br label %for.body11
+
+for.body11:                                       ; preds = %for.body7, %for.body11
+  %indvars.iv8 = phi i64 [ 0, %for.body7 ], [ %indvars.iv.next9, %for.body11 ]
+  %tmp.22 = phi double [ %tmp.14, %for.body7 ], [ %add16, %for.body11 ]
+  %1 = trunc i64 %indvars.iv15 to i32
+  %conv12 = sitofp i32 %1 to double
+  %add = fadd double %tmp.22, %conv12
+  %2 = trunc i64 %indvars.iv8 to i32
+  %conv13 = sitofp i32 %2 to double
+  %add14 = fadd double %add, %conv13
+  %3 = trunc i64 %indvars.iv11 to i32
+  %conv15 = sitofp i32 %3 to double
+  %add16 = fadd double %add14, %conv15
+  %arrayidx18 = getelementptr inbounds double, double* %B, i64 %indvars.iv8
+  %4 = load double, double* %arrayidx18, align 8
+  %mul = fmul double %add16, %4
+  %5 = add nuw nsw i64 %indvars.iv11, %indvars.iv15
+  %arrayidx21 = getelementptr inbounds double, double* %A, i64 %5
+  store double %mul, double* %arrayidx21, align 8
+  %indvars.iv.next9 = add nuw nsw i64 %indvars.iv8, 1
+  %exitcond10 = icmp ne i64 %indvars.iv.next9, 10000
+  br i1 %exitcond10, label %for.body11, label %for.inc25
+
+for.inc25:                                        ; preds = %for.body11
+  %add16.lcssa = phi double [ %add16, %for.body11 ]
+  %indvars.iv.next12 = add nuw nsw i64 %indvars.iv11, 1
+  %exitcond14 = icmp ne i64 %indvars.iv.next12, 10000
+  br i1 %exitcond14, label %for.body7, label %for.inc28
+
+for.inc28:                                        ; preds = %for.inc25
+  %add16.lcssa.lcssa = phi double [ %add16.lcssa, %for.inc25 ]
+  %indvars.iv.next16 = add nuw nsw i64 %indvars.iv15, 1
+  %exitcond17 = icmp ne i64 %indvars.iv.next16, 10000
+  br i1 %exitcond17, label %for.body, label %for.end30
+
+for.end30:                                        ; preds = %for.inc28
+  ret void
+}
diff --git a/final/test/MaximalStaticExpansion/working_expansion.ll b/final/test/MaximalStaticExpansion/working_expansion.ll
new file mode 100644
index 0000000..02e08b9
--- /dev/null
+++ b/final/test/MaximalStaticExpansion/working_expansion.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-mse -analyze < %s | FileCheck %s
+;
+; Verify that the accesses are correctly expanded for MemoryKind::Array
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 3000
+; 
+; double mse(double A[Ni], double B[Nj]) {
+;   int i;
+;   double tmp = 6;
+;   for (i = 0; i < Ni; i++) {
+;     for (int j = 0; j<Nj; j++) {
+;       B[j] = j;
+;     }
+;     A[i] = B[i]; 
+;   }
+;   return tmp;
+; }
+;
+; Check if the expanded SAI are created
+;
+; CHECK: double MemRef_B_Stmt_for_body3_expanded[2000][3000]; // Element size 8
+;
+; Check if the memory accesses are modified
+;
+; CHECK: new: { Stmt_for_body3[i0, i1] -> MemRef_B_Stmt_for_body3_expanded[i0, i1] };
+; CHECK: new: { Stmt_for_end[i0] -> MemRef_B_Stmt_for_body3_expanded[i0, i0] };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define double @mse(double* %A, double* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.end
+  %indvars.iv3 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next4, %for.end ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.body, %for.body3
+  %indvars.iv = phi i64 [ 0, %for.body ], [ %indvars.iv.next, %for.body3 ]
+  %0 = trunc i64 %indvars.iv to i32
+  %conv = sitofp i32 %0 to double
+  %arrayidx = getelementptr inbounds double, double* %B, i64 %indvars.iv
+  store double %conv, double* %arrayidx, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 3000
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.end:                                          ; preds = %for.body3
+  %arrayidx5 = getelementptr inbounds double, double* %B, i64 %indvars.iv3
+  %1 = bitcast double* %arrayidx5 to i64*
+  %2 = load i64, i64* %1, align 8
+  %arrayidx7 = getelementptr inbounds double, double* %A, i64 %indvars.iv3
+  %3 = bitcast double* %arrayidx7 to i64*
+  store i64 %2, i64* %3, align 8
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  %exitcond5 = icmp ne i64 %indvars.iv.next4, 2000
+  br i1 %exitcond5, label %for.body, label %for.end10
+
+for.end10:                                        ; preds = %for.end
+  ret double 6.000000e+00
+}
diff --git a/final/test/MaximalStaticExpansion/working_expansion_multiple_dependences_per_statement.ll b/final/test/MaximalStaticExpansion/working_expansion_multiple_dependences_per_statement.ll
new file mode 100644
index 0000000..ad86962
--- /dev/null
+++ b/final/test/MaximalStaticExpansion/working_expansion_multiple_dependences_per_statement.ll
@@ -0,0 +1,95 @@
+; RUN: opt %loadPolly -polly-mse -analyze < %s | FileCheck %s
+;
+; Verify that the accesses are correctly expanded
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 3000
+;
+; void mse(double A[Ni], double B[Nj], double C[Nj], double D[Nj]) {
+;   int i,j;
+;   for (j = 0; j < Ni; j++) {
+;     for (int i = 0; i<Nj; i++)
+;       B[i] = i;
+; 
+;     for (int i = 0; i<Nj; i++)
+;       D[i] = i;
+; 
+;     A[j] = B[j];
+;     C[j] = D[j];
+;   }
+; }
+;
+; Check that expanded SAI are created
+;
+; CHECK: double MemRef_B_Stmt_for_body4_expanded[10000][10000]; // Element size 8
+; CHECK: double MemRef_D_Stmt_for_body9_expanded[10000][10000]; // Element size 8
+; CHECK: i64 MemRef_A_Stmt_for_end15_expanded[10000]; // Element size 8
+; CHECK: i64 MemRef_C_Stmt_for_end15_expanded[10000]; // Element size 8
+;
+; Check that the memory accesses are modified
+; CHECK: new: { Stmt_for_body4[i0, i1] -> MemRef_B_Stmt_for_body4_expanded[i0, i1] };
+; CHECK: new: { Stmt_for_body9[i0, i1] -> MemRef_D_Stmt_for_body9_expanded[i0, i1] };
+; CHECK: new: { Stmt_for_end15[i0] -> MemRef_B_Stmt_for_body4_expanded[i0, i0] };
+; CHECK: new: { Stmt_for_end15[i0] -> MemRef_A_Stmt_for_end15_expanded[i0] };
+; CHECK: new: { Stmt_for_end15[i0] -> MemRef_D_Stmt_for_body9_expanded[i0, i0] };
+; CHECK: new: { Stmt_for_end15[i0] -> MemRef_C_Stmt_for_end15_expanded[i0] };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @mse(double* %A, double* %B, double* %C, double* %D) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.end15
+  %indvars.iv7 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next8, %for.end15 ]
+  br label %for.body4
+
+for.body4:                                        ; preds = %for.body, %for.body4
+  %indvars.iv = phi i64 [ 0, %for.body ], [ %indvars.iv.next, %for.body4 ]
+  %0 = trunc i64 %indvars.iv to i32
+  %conv = sitofp i32 %0 to double
+  %arrayidx = getelementptr inbounds double, double* %B, i64 %indvars.iv
+  store double %conv, double* %arrayidx, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 10000
+  br i1 %exitcond, label %for.body4, label %for.end
+
+for.end:                                          ; preds = %for.body4
+  br label %for.body9
+
+for.body9:                                        ; preds = %for.end, %for.body9
+  %indvars.iv4 = phi i64 [ 0, %for.end ], [ %indvars.iv.next5, %for.body9 ]
+  %1 = trunc i64 %indvars.iv4 to i32
+  %conv10 = sitofp i32 %1 to double
+  %arrayidx12 = getelementptr inbounds double, double* %D, i64 %indvars.iv4
+  store double %conv10, double* %arrayidx12, align 8
+  %indvars.iv.next5 = add nuw nsw i64 %indvars.iv4, 1
+  %exitcond6 = icmp ne i64 %indvars.iv.next5, 10000
+  br i1 %exitcond6, label %for.body9, label %for.end15
+
+for.end15:                                        ; preds = %for.body9
+  %arrayidx17 = getelementptr inbounds double, double* %B, i64 %indvars.iv7
+  %2 = bitcast double* %arrayidx17 to i64*
+  %3 = load i64, i64* %2, align 8
+  %arrayidx19 = getelementptr inbounds double, double* %A, i64 %indvars.iv7
+  %4 = bitcast double* %arrayidx19 to i64*
+  store i64 %3, i64* %4, align 8
+  %arrayidx21 = getelementptr inbounds double, double* %D, i64 %indvars.iv7
+  %5 = bitcast double* %arrayidx21 to i64*
+  %6 = load i64, i64* %5, align 8
+  %arrayidx23 = getelementptr inbounds double, double* %C, i64 %indvars.iv7
+  %7 = bitcast double* %arrayidx23 to i64*
+  store i64 %6, i64* %7, align 8
+  %indvars.iv.next8 = add nuw nsw i64 %indvars.iv7, 1
+  %exitcond9 = icmp ne i64 %indvars.iv.next8, 10000
+  br i1 %exitcond9, label %for.body, label %for.end26
+
+for.end26:                                        ; preds = %for.end15
+  ret void
+}
diff --git a/final/test/MaximalStaticExpansion/working_expansion_multiple_instruction_per_statement.ll b/final/test/MaximalStaticExpansion/working_expansion_multiple_instruction_per_statement.ll
new file mode 100644
index 0000000..6416d16
--- /dev/null
+++ b/final/test/MaximalStaticExpansion/working_expansion_multiple_instruction_per_statement.ll
@@ -0,0 +1,84 @@
+; RUN: opt %loadPolly -polly-mse -analyze < %s | FileCheck %s
+;
+; Verify that the accesses are correctly expanded 
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 3000
+;
+; void mse(double A[Ni], double B[Nj], double C[Nj], double D[Nj]) {
+;   int i,j;
+;   for (j = 0; j < Nj; j++) {
+;     for (int i = 0; i<Ni; i++) {
+;       B[i] = i;
+;       D[i] = i;
+;     }
+;     A[j] = B[j];
+;     C[j] = D[j];
+;   }
+; }
+;
+; Check that expanded SAI are created
+; CHECK: double MemRef_B_Stmt_for_body4_expanded[10000][10000]; // Element size 8
+; CHECK: double MemRef_D_Stmt_for_body4_expanded[10000][10000]; // Element size 8
+; CHECK: i64 MemRef_A_Stmt_for_end_expanded[10000]; // Element size 8
+; CHECK: i64 MemRef_C_Stmt_for_end_expanded[10000]; // Element size 8
+;
+; Check that the memory access are modified
+;
+; CHECK: new: { Stmt_for_body4[i0, i1] -> MemRef_B_Stmt_for_body4_expanded[i0, i1] };
+; CHECK: new: { Stmt_for_body4[i0, i1] -> MemRef_D_Stmt_for_body4_expanded[i0, i1] };
+; CHECK: new: { Stmt_for_end[i0] -> MemRef_B_Stmt_for_body4_expanded[i0, i0] };
+; CHECK: new: { Stmt_for_end[i0] -> MemRef_A_Stmt_for_end_expanded[i0] };
+; CHECK: new: { Stmt_for_end[i0] -> MemRef_D_Stmt_for_body4_expanded[i0, i0] };
+; CHECK: new: { Stmt_for_end[i0] -> MemRef_C_Stmt_for_end_expanded[i0] };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @mse(double* %A, double* %B, double* %C, double* %D) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.end
+  %indvars.iv3 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next4, %for.end ]
+  br label %for.body4
+
+for.body4:                                        ; preds = %for.body, %for.body4
+  %indvars.iv = phi i64 [ 0, %for.body ], [ %indvars.iv.next, %for.body4 ]
+  %0 = trunc i64 %indvars.iv to i32
+  %conv = sitofp i32 %0 to double
+  %arrayidx = getelementptr inbounds double, double* %B, i64 %indvars.iv
+  store double %conv, double* %arrayidx, align 8
+  %1 = trunc i64 %indvars.iv to i32
+  %conv5 = sitofp i32 %1 to double
+  %arrayidx7 = getelementptr inbounds double, double* %D, i64 %indvars.iv
+  store double %conv5, double* %arrayidx7, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 10000
+  br i1 %exitcond, label %for.body4, label %for.end
+
+for.end:                                          ; preds = %for.body4
+  %arrayidx9 = getelementptr inbounds double, double* %B, i64 %indvars.iv3
+  %2 = bitcast double* %arrayidx9 to i64*
+  %3 = load i64, i64* %2, align 8
+  %arrayidx11 = getelementptr inbounds double, double* %A, i64 %indvars.iv3
+  %4 = bitcast double* %arrayidx11 to i64*
+  store i64 %3, i64* %4, align 8
+  %arrayidx13 = getelementptr inbounds double, double* %D, i64 %indvars.iv3
+  %5 = bitcast double* %arrayidx13 to i64*
+  %6 = load i64, i64* %5, align 8
+  %arrayidx15 = getelementptr inbounds double, double* %C, i64 %indvars.iv3
+  %7 = bitcast double* %arrayidx15 to i64*
+  store i64 %6, i64* %7, align 8
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  %exitcond5 = icmp ne i64 %indvars.iv.next4, 10000
+  br i1 %exitcond5, label %for.body, label %for.end18
+
+for.end18:                                        ; preds = %for.end
+  ret void
+}
diff --git a/final/test/MaximalStaticExpansion/working_phi_expansion.ll b/final/test/MaximalStaticExpansion/working_phi_expansion.ll
new file mode 100644
index 0000000..2cbf345
--- /dev/null
+++ b/final/test/MaximalStaticExpansion/working_phi_expansion.ll
@@ -0,0 +1,77 @@
+; RUN: opt %loadPolly -polly-mse -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-mse -pass-remarks-analysis="polly-mse" -analyze < %s 2>&1 | FileCheck %s --check-prefix=MSE
+;
+; Verify that the accesses are correctly expanded for MemoryKind::PHI
+; tmp_04 is not expanded because it need copy-in.
+;
+; Original source code :
+;
+; #define Ni 10000
+; #define Nj 10000
+;
+; void mse(double A[Ni], double B[Nj]) {
+;   int i,j;
+;   double tmp = 6;
+;   for (i = 0; i < Ni; i++) {
+;     for (int j = 0; j<Nj; j++) {
+;       tmp = tmp + 2;
+;     }
+;     B[i] = tmp;
+;   }
+;
+; Check that the pass detects that tmp_04 reads from original value.
+;
+; MSE: MemRef_tmp_04__phi read from its original value.
+;
+; Check that the SAI are created except the expanded SAI of tmp_04.
+;
+; CHECK-NOT: double MemRef_tmp_04__phi_Stmt_for_body_expanded[10000]; // Element size 8
+; CHECK: double MemRef_tmp_11__phi_Stmt_for_inc_expanded[10000][10000]; // Element size
+; CHECK: double MemRef_add_lcssa__phi_Stmt_for_end_expanded[10000]; // Element size 8
+; CHECK: double MemRef_B_Stmt_for_end_expanded[10000]; // Element size 8
+;
+; Check that the memory accesses are modified except those related to tmp_04.
+;
+; CHECK-NOT: new: { Stmt_for_body[i0] -> MemRef_tmp_04__phi_Stmt_for_body_expanded[i0] };
+; CHECK: new: { Stmt_for_body[i0] -> MemRef_tmp_11__phi_Stmt_for_inc_expanded[i0, 0] };
+; CHECK: new: { Stmt_for_inc[i0, i1] -> MemRef_tmp_11__phi_Stmt_for_inc_expanded[i0, 1 + i1] : i1 <= 9998 };
+; CHECK: new: { Stmt_for_inc[i0, i1] -> MemRef_tmp_11__phi_Stmt_for_inc_expanded[i0, i1] };
+; CHECK: new: { Stmt_for_inc[i0, 9999] -> MemRef_add_lcssa__phi_Stmt_for_end_expanded[i0] };
+; CHECK-NOT: new: { Stmt_for_end[i0] -> MemRef_tmp_04__phi_Stmt_for_body_expanded[1 + i0] : i0 <= 9998 };
+; CHECK: new: { Stmt_for_end[i0] -> MemRef_add_lcssa__phi_Stmt_for_end_expanded[i0] };
+; CHECK: new: { Stmt_for_end[i0] -> MemRef_B_Stmt_for_end_expanded[i0] };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @tmp(double* %A, double* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.end
+  %indvars.iv = phi i64 [ 0, %entry.split ], [ %indvars.iv.next, %for.end ]
+  %tmp.04 = phi double [ 6.000000e+00, %entry.split ], [ %add.lcssa, %for.end ]
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body, %for.inc
+  %j1.02 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %tmp.11 = phi double [ %tmp.04, %for.body ], [ %add, %for.inc ]
+  %add = fadd double %tmp.11, 2.000000e+00
+  %inc = add nuw nsw i32 %j1.02, 1
+  %exitcond = icmp ne i32 %inc, 10000
+  br i1 %exitcond, label %for.inc, label %for.end
+
+for.end:                                          ; preds = %for.inc
+  %add.lcssa = phi double [ %add, %for.inc ]
+  %arrayidx = getelementptr inbounds double, double* %B, i64 %indvars.iv
+  store double %add.lcssa, double* %arrayidx, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond5 = icmp ne i64 %indvars.iv.next, 10000
+  br i1 %exitcond5, label %for.body, label %for.end7
+
+for.end7:                                         ; preds = %for.end
+  ret void
+}
diff --git a/final/test/MaximalStaticExpansion/working_phi_two_scalars.ll b/final/test/MaximalStaticExpansion/working_phi_two_scalars.ll
new file mode 100644
index 0000000..0e02ea0
--- /dev/null
+++ b/final/test/MaximalStaticExpansion/working_phi_two_scalars.ll
@@ -0,0 +1,91 @@
+; RUN: opt %loadPolly -polly-mse -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-mse -pass-remarks-analysis="polly-mse" -analyze < %s 2>&1 | FileCheck %s --check-prefix=MSE
+;
+; Verify that the accesses are correctly expanded for MemoryKind::PHI
+; tmp_05 and tmp2_06 are not expanded because they need copy-in.
+;
+; Original source code :
+;
+; #define Ni 10000
+; #define Nj 10000
+;
+; void mse(double A[Ni], double B[Nj]) {
+;   int i,j;
+;   double tmp = 6;
+;   double tmp2 = 9;
+;   for (i = 0; i < Ni; i++) {
+;     for(j = 0; j < Nj; j++) {
+;       tmp = tmp + tmp2;
+;       tmp2 = i*j;
+;     }
+;   }
+; }
+;
+; Check that the pass detects that tmp_05 and tmp2_06 read from their original values.
+;
+; MSE-DAG: MemRef_tmp_05__phi read from its original value.
+; MSE-DAG: MemRef_tmp2_06__phi read from its original value.
+;
+; Check that the SAI are created except the expanded SAI of tmp_05 and tmp2_06.
+;
+; CHECK-DAG: double MemRef_add_lcssa__phi_Stmt_for_inc4_expanded[10000]; // Element size 8
+; CHECK-DAG: double MemRef_tmp2_13__phi_Stmt_for_inc_expanded[10000][10000]; // Element size
+; CHECK-DAG: double MemRef_conv_lcssa__phi_Stmt_for_inc4_expanded[10000]; // Element size 8
+; CHECK-DAG: double MemRef_tmp_12__phi_Stmt_for_inc_expanded[10000][10000]; // Element size 8
+; CHECK-NOT: double MemRef_tmp_05__phi_Stmt_for_body_expanded[10000]; // Element size 8
+; CHECK-NOT: double MemRef_tmp2_06__phi_Stmt_for_body_expanded[10000]; // Element size 8
+;
+; Check that the memory accesses are modified except those related to tmp_05 and tmp_06.
+;
+; CHECK-NOT: new: { Stmt_for_body[i0] -> MemRef_tmp2_06__phi_Stmt_for_body_expanded[i0] };
+; CHECK-NOT: new: { Stmt_for_body[i0] -> MemRef_tmp_05__phi_Stmt_for_body_expanded[i0] };
+; CHECK: new: { Stmt_for_body[i0] -> MemRef_tmp2_13__phi_Stmt_for_inc_expanded[i0, 0] };
+; CHECK: new: { Stmt_for_body[i0] -> MemRef_tmp_12__phi_Stmt_for_inc_expanded[i0, 0] };
+; CHECK: new: { Stmt_for_inc[i0, i1] -> MemRef_tmp2_13__phi_Stmt_for_inc_expanded[i0, 1 + i1] : i1 <= 9998 };
+; CHECK: new: { Stmt_for_inc[i0, i1] -> MemRef_tmp2_13__phi_Stmt_for_inc_expanded[i0, i1] };
+; CHECK: new: { Stmt_for_inc[i0, i1] -> MemRef_tmp_12__phi_Stmt_for_inc_expanded[i0, 1 + i1] : i1 <= 9998 };
+; CHECK: new: { Stmt_for_inc[i0, i1] -> MemRef_tmp_12__phi_Stmt_for_inc_expanded[i0, i1] };
+; CHECK: new: { Stmt_for_inc[i0, 9999] -> MemRef_conv_lcssa__phi_Stmt_for_inc4_expanded[i0] };
+; CHECK: new: { Stmt_for_inc[i0, 9999] -> MemRef_add_lcssa__phi_Stmt_for_inc4_expanded[i0] };
+; CHECK-NOT: new: { Stmt_for_inc4[i0] -> MemRef_tmp2_06__phi_Stmt_for_body_expanded[1 + i0] : i0 <= 9998 };
+; CHECK-NOT: new: { Stmt_for_inc4[i0] -> MemRef_tmp_05__phi_Stmt_for_body_expanded[1 + i0] : i0 <= 9998 };
+; CHECK: new: { Stmt_for_inc4[i0] -> MemRef_conv_lcssa__phi_Stmt_for_inc4_expanded[i0] };
+; CHECK: new: { Stmt_for_inc4[i0] -> MemRef_add_lcssa__phi_Stmt_for_inc4_expanded[i0] };
+; 
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @tmp(double* %A, double* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.inc4
+  %tmp2.06 = phi double [ 9.000000e+00, %entry.split ], [ %conv.lcssa, %for.inc4 ]
+  %tmp.05 = phi double [ 6.000000e+00, %entry.split ], [ %add.lcssa, %for.inc4 ]
+  %i.04 = phi i32 [ 0, %entry.split ], [ %inc5, %for.inc4 ]
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body, %for.inc
+  %tmp2.13 = phi double [ %tmp2.06, %for.body ], [ %conv, %for.inc ]
+  %tmp.12 = phi double [ %tmp.05, %for.body ], [ %add, %for.inc ]
+  %j.01 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %mul = mul nuw nsw i32 %j.01, %i.04
+  %conv = sitofp i32 %mul to double
+  %add = fadd double %tmp.12, %tmp2.13
+  %inc = add nuw nsw i32 %j.01, 1
+  %exitcond = icmp ne i32 %inc, 10000
+  br i1 %exitcond, label %for.inc, label %for.inc4
+
+for.inc4:                                         ; preds = %for.inc
+  %conv.lcssa = phi double [ %conv, %for.inc ]
+  %add.lcssa = phi double [ %add, %for.inc ]
+  %inc5 = add nuw nsw i32 %i.04, 1
+  %exitcond7 = icmp ne i32 %inc5, 10000
+  br i1 %exitcond7, label %for.body, label %for.end6
+
+for.end6:                                         ; preds = %for.inc4
+  ret void
+}
diff --git a/final/test/MaximalStaticExpansion/working_value_expansion.ll b/final/test/MaximalStaticExpansion/working_value_expansion.ll
new file mode 100644
index 0000000..71a355f
--- /dev/null
+++ b/final/test/MaximalStaticExpansion/working_value_expansion.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -polly-mse -analyze < %s | FileCheck %s
+;
+; Verify that the accesses are correctly expanded for MemoryKind::Value
+;
+; Original source code :
+;
+; #define Ni 10000
+; #define Nj 10000
+;
+; void mse(double A[Ni], double B[Nj]) {
+;   int i,j;
+;   double tmp = 6;
+;   for (i = 0; i < Ni; i++) {
+;     tmp = i;
+;     for (int j = 0; j<Nj; j++) {
+;       A[j] = tmp+3;
+;     }
+;     B[i] = tmp;
+;   }
+; }
+;
+; Check if the expanded SAI are created
+;
+; CHECK: double MemRef_conv_Stmt_for_body_expanded[10000]; // Element size 8
+;
+; Check if the memory accesses are modified
+;
+; CHECK: new: { Stmt_for_body[i0] -> MemRef_conv_Stmt_for_body_expanded[i0] };
+; CHECK: new: { Stmt_for_body5[i0, i1] -> MemRef_conv_Stmt_for_body_expanded[i0] };
+; CHECK: new: { Stmt_for_end[i0] -> MemRef_conv_Stmt_for_body_expanded[i0] };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @mse(double* %A, double* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.end
+  %indvars.iv3 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next4, %for.end ]
+  %0 = trunc i64 %indvars.iv3 to i32
+  %conv = sitofp i32 %0 to double
+  br label %for.body5
+
+for.body5:                                        ; preds = %for.body, %for.body5
+  %indvars.iv = phi i64 [ 0, %for.body ], [ %indvars.iv.next, %for.body5 ]
+  %add = fadd double %conv, 3.000000e+00
+  %arrayidx = getelementptr inbounds double, double* %A, i64 %indvars.iv
+  store double %add, double* %arrayidx, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 10000
+  br i1 %exitcond, label %for.body5, label %for.end
+
+for.end:                                          ; preds = %for.body5
+  %arrayidx7 = getelementptr inbounds double, double* %B, i64 %indvars.iv3
+  store double %conv, double* %arrayidx7, align 8
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  %exitcond5 = icmp ne i64 %indvars.iv.next4, 10000
+  br i1 %exitcond5, label %for.body, label %for.end10
+
+for.end10:                                        ; preds = %for.end
+  ret void
+}
diff --git a/final/test/PruneUnprofitable/prune_only_scalardeps.ll b/final/test/PruneUnprofitable/prune_only_scalardeps.ll
new file mode 100644
index 0000000..b42292e
--- /dev/null
+++ b/final/test/PruneUnprofitable/prune_only_scalardeps.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-process-unprofitable=false -polly-unprofitable-scalar-accs=false -polly-prune-unprofitable -disable-output -stats < %s 2>&1 | FileCheck -match-full-lines %s
+; REQUIRES: asserts
+;
+; Skip this SCoP for having scalar dependencies between all statements,
+; but only after ScopInfo (because optimization passes using ScopInfo such
+; as DeLICM might remove these scalar dependencies).
+;
+; double x = 0;
+; for (int i = 0; i < n; i += 1)
+;   for (int j = 0; j < m; j += 1) {
+;      B[0] = x;
+;      x = A[0];
+;   }
+; return x;
+;
+define double @func(i32 %n, i32 %m, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %outer.for
+
+outer.for:
+  %outer.phi = phi double [0.0, %entry], [%inner.phi, %outer.inc]
+  %i = phi i32 [0, %entry], [%i.inc, %outer.inc]
+  %i.cmp = icmp slt i32 %i, %n
+  br i1 %i.cmp, label %inner.for, label %outer.exit
+
+    inner.for:
+      %inner.phi = phi double [%outer.phi, %outer.for], [%load, %inner.inc]
+      %j = phi i32 [0, %outer.for], [%j.inc, %inner.inc]
+      %j.cmp = icmp slt i32 %j, %m
+      br i1 %j.cmp, label %body, label %inner.exit
+
+        body:
+          store double %inner.phi, double* %B
+          %load = load double, double* %A
+          br label %inner.inc
+
+    inner.inc:
+      %j.inc = add nuw nsw i32 %j, 1
+      br label %inner.for
+
+    inner.exit:
+      br label %outer.inc
+
+outer.inc:
+  %i.inc = add nuw nsw i32 %i, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret double %outer.phi
+}
+
+
+; CHECK: 1 polly-prune-unprofitable - Number of pruned SCoPs because it they cannot be optimized in a significant way
diff --git a/final/test/README b/final/test/README
new file mode 100644
index 0000000..e8470c6
--- /dev/null
+++ b/final/test/README
@@ -0,0 +1 @@
+place tests here
\ No newline at end of file
diff --git a/final/test/RewriteByReferenceParameters/fortran_io.ll b/final/test/RewriteByReferenceParameters/fortran_io.ll
new file mode 100644
index 0000000..bc372c4
--- /dev/null
+++ b/final/test/RewriteByReferenceParameters/fortran_io.ll
@@ -0,0 +1,40 @@
+; RUN: opt %loadPolly -polly-rewrite-byref-params -S < %s \
+; RUN: | FileCheck %s
+
+
+; Verify that we rewrite the read-only by-reference into a separate alloca slot.
+; This is useful in case %j3 is an induction variable, which should be promoted
+; by -mem2reg into a register.
+
+; CHECK: define void @foo(%struct.__st_parameter_dt* %p) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT:   %polly_byref_alloca_j3 = alloca i32
+; CHECK-NEXT:   %j3 = alloca i32, align 4
+; CHECK-NEXT:   %tmp = bitcast i32* %j3 to i8*
+; CHECK-NEXT:   br label %bb
+
+; CHECK: bb:                                               ; preds = %entry
+; CHECK-NEXT:   %polly_byref_load_j3 = load i32, i32* %j3
+; CHECK-NEXT:   store i32 %polly_byref_load_j3, i32* %polly_byref_alloca_j3
+; CHECK-NEXT:   %polly_byref_cast_j3 = bitcast i32* %polly_byref_alloca_j3 to i8*
+; CHECK-NEXT:   call void @_gfortran_transfer_integer_write(%struct.__st_parameter_dt* %p, i8* %polly_byref_cast_j3, i32 4)
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.__st_parameter_dt = type { }
+
+declare void @_gfortran_transfer_integer_write(%struct.__st_parameter_dt*, i8*, i32)
+
+define void @foo(%struct.__st_parameter_dt* %p) {
+entry:
+  %j3 = alloca i32, align 4
+  %tmp = bitcast i32* %j3 to i8*
+  br label %bb
+
+bb:
+  call void @_gfortran_transfer_integer_write(%struct.__st_parameter_dt* %p, i8* %tmp, i32 4)
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/2012-03-16-Empty-Domain.ll b/final/test/ScheduleOptimizer/2012-03-16-Empty-Domain.ll
new file mode 100644
index 0000000..5acc353
--- /dev/null
+++ b/final/test/ScheduleOptimizer/2012-03-16-Empty-Domain.ll
@@ -0,0 +1,16 @@
+; RUN: opt %loadPolly -polly-opt-isl -S < %s
+target datalayout = "e-p:32:32:32-i64:64:64-i32:32:32-i16:16:16-i1:32:32-f64:64:64-f32:32:32-a0:0-n32"
+
+define void @sdbout_label() nounwind {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry
+  %0 = phi i32 [ 0, %entry ], [ %1, %for.cond ]
+  %1 = add nsw i32 %0, 1
+  %exitcond72 = icmp eq i32 %1, 7
+  br i1 %exitcond72, label %sw.epilog66, label %for.cond
+
+sw.epilog66:                                      ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/2012-04-16-Trivially-vectorizable-loops.ll b/final/test/ScheduleOptimizer/2012-04-16-Trivially-vectorizable-loops.ll
new file mode 100644
index 0000000..af33ff7
--- /dev/null
+++ b/final/test/ScheduleOptimizer/2012-04-16-Trivially-vectorizable-loops.ll
@@ -0,0 +1,204 @@
+; RUN: opt %loadPolly -basicaa -polly-opt-isl -polly-vectorizer=polly < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker = type { %struct._IO_marker*, %struct._IO_FILE*, i32 }
+
+@A = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@B = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@stdout = external global %struct._IO_FILE*
+@.str = private unnamed_addr constant [5 x i8] c"%lf \00", align 1
+@C = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@.str1 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
+
+define void @init_array() nounwind uwtable {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc17, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc18, %for.inc17 ]
+  %cmp = icmp slt i32 %i.0, 1536
+  br i1 %cmp, label %for.body, label %for.end19
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %cmp2 = icmp slt i32 %j.0, 1536
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %mul = mul nsw i32 %i.0, %j.0
+  %rem = srem i32 %mul, 1024
+  %add = add nsw i32 1, %rem
+  %conv = sitofp i32 %add to double
+  %div = fdiv double %conv, 2.000000e+00
+  %conv4 = fptrunc double %div to float
+  %idxprom = sext i32 %j.0 to i64
+  %idxprom5 = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @A, i32 0, i64 %idxprom5
+  %arrayidx6 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx, i32 0, i64 %idxprom
+  store float %conv4, float* %arrayidx6, align 4
+  %mul7 = mul nsw i32 %i.0, %j.0
+  %rem8 = srem i32 %mul7, 1024
+  %add9 = add nsw i32 1, %rem8
+  %conv10 = sitofp i32 %add9 to double
+  %div11 = fdiv double %conv10, 2.000000e+00
+  %conv12 = fptrunc double %div11 to float
+  %idxprom13 = sext i32 %j.0 to i64
+  %idxprom14 = sext i32 %i.0 to i64
+  %arrayidx15 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @B, i32 0, i64 %idxprom14
+  %arrayidx16 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx15, i32 0, i64 %idxprom13
+  store float %conv12, float* %arrayidx16, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc17
+
+for.inc17:                                        ; preds = %for.end
+  %inc18 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end19:                                        ; preds = %for.cond
+  ret void
+}
+
+define void @print_array() nounwind uwtable {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc10, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc11, %for.inc10 ]
+  %cmp = icmp slt i32 %i.0, 1536
+  br i1 %cmp, label %for.body, label %for.end12
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %cmp2 = icmp slt i32 %j.0, 1536
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %0 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
+  %idxprom = sext i32 %j.0 to i64
+  %idxprom4 = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i32 0, i64 %idxprom4
+  %arrayidx5 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx, i32 0, i64 %idxprom
+  %1 = load float, float* %arrayidx5, align 4
+  %conv = fpext float %1 to double
+  %call = call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %0, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i32 0, i32 0), double %conv)
+  %rem = srem i32 %j.0, 80
+  %cmp6 = icmp eq i32 %rem, 79
+  br i1 %cmp6, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body3
+  %2 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
+  %call8 = call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %2, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str1, i32 0, i32 0))
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body3
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  %3 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
+  %call9 = call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %3, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str1, i32 0, i32 0))
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.end
+  %inc11 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end12:                                        ; preds = %for.cond
+  ret void
+}
+
+declare i32 @fprintf(%struct._IO_FILE*, i8*, ...)
+
+define i32 @main() nounwind uwtable {
+entry:
+  call void @init_array()
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc28, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc29, %for.inc28 ]
+  %cmp = icmp slt i32 %i.0, 1536
+  br i1 %cmp, label %for.body, label %for.end30
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc25, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc26, %for.inc25 ]
+  %cmp2 = icmp slt i32 %j.0, 1536
+  br i1 %cmp2, label %for.body3, label %for.end27
+
+for.body3:                                        ; preds = %for.cond1
+  %idxprom = sext i32 %j.0 to i64
+  %idxprom4 = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i32 0, i64 %idxprom4
+  %arrayidx5 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx, i32 0, i64 %idxprom
+  store float 0.000000e+00, float* %arrayidx5, align 4
+  br label %for.cond6
+
+for.cond6:                                        ; preds = %for.inc, %for.body3
+  %k.0 = phi i32 [ 0, %for.body3 ], [ %inc, %for.inc ]
+  %cmp7 = icmp slt i32 %k.0, 1536
+  br i1 %cmp7, label %for.body8, label %for.end
+
+for.body8:                                        ; preds = %for.cond6
+  %idxprom9 = sext i32 %j.0 to i64
+  %idxprom10 = sext i32 %i.0 to i64
+  %arrayidx11 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i32 0, i64 %idxprom10
+  %arrayidx12 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx11, i32 0, i64 %idxprom9
+  %0 = load float, float* %arrayidx12, align 4
+  %idxprom13 = sext i32 %k.0 to i64
+  %idxprom14 = sext i32 %i.0 to i64
+  %arrayidx15 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @A, i32 0, i64 %idxprom14
+  %arrayidx16 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx15, i32 0, i64 %idxprom13
+  %1 = load float, float* %arrayidx16, align 4
+  %idxprom17 = sext i32 %j.0 to i64
+  %idxprom18 = sext i32 %k.0 to i64
+  %arrayidx19 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @B, i32 0, i64 %idxprom18
+  %arrayidx20 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx19, i32 0, i64 %idxprom17
+  %2 = load float, float* %arrayidx20, align 4
+  %mul = fmul float %1, %2
+  %add = fadd float %0, %mul
+  %idxprom21 = sext i32 %j.0 to i64
+  %idxprom22 = sext i32 %i.0 to i64
+  %arrayidx23 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i32 0, i64 %idxprom22
+  %arrayidx24 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx23, i32 0, i64 %idxprom21
+  store float %add, float* %arrayidx24, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body8
+  %inc = add nsw i32 %k.0, 1
+  br label %for.cond6
+
+for.end:                                          ; preds = %for.cond6
+  br label %for.inc25
+
+for.inc25:                                        ; preds = %for.end
+  %inc26 = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end27:                                        ; preds = %for.cond1
+  br label %for.inc28
+
+for.inc28:                                        ; preds = %for.end27
+  %inc29 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end30:                                        ; preds = %for.cond
+  ret i32 0
+}
diff --git a/final/test/ScheduleOptimizer/2013-04-11-Empty-Domain-two.ll b/final/test/ScheduleOptimizer/2013-04-11-Empty-Domain-two.ll
new file mode 100644
index 0000000..3eef93c
--- /dev/null
+++ b/final/test/ScheduleOptimizer/2013-04-11-Empty-Domain-two.ll
@@ -0,0 +1,23 @@
+; RUN: opt %loadPolly -polly-opt-isl -S < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; Check that we handle statements with an empty iteration domain correctly.
+
+define void @f() {
+entry:
+  %A = alloca double
+  br label %for
+
+for:
+  %indvar = phi i32 [ %indvar.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i32 %indvar, -1
+  br i1 %exitcond, label %for.inc, label %return
+
+for.inc:
+  %indvar.next = add i32 %indvar, 1
+  store double 1.0, double* %A
+  br label %for
+
+return:
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/computeout.ll b/final/test/ScheduleOptimizer/computeout.ll
new file mode 100644
index 0000000..107a362
--- /dev/null
+++ b/final/test/ScheduleOptimizer/computeout.ll
@@ -0,0 +1,69 @@
+; RUN: opt -S %loadPolly -basicaa -polly-opt-isl -polly-opt-fusion=max -polly-ast -analyze < %s | FileCheck %s 
+; RUN: opt -S %loadPolly -basicaa -polly-opt-isl -polly-opt-fusion=max -polly-ast -analyze -polly-dependences-computeout=1 < %s | FileCheck %s -check-prefix=TIMEOUT
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+;     for(i = 0; i < 100; i++ )
+; S1:   A[i] = 2;
+;
+;     for (i = 0; i < 10; i++ )
+; S2:   A[i]  = 5;
+;
+;     for (i = 0; i < 200; i++ )
+; S3:   A[i] = 5;
+
+define void @sequential_writes() {
+entry:
+  %A = alloca [200 x i32]
+  br label %S1
+
+S1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %S1 ]
+  %arrayidx.1 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.1
+  store i32 2, i32* %arrayidx.1
+  %indvar.next.1 = add i64 %indvar.1, 1
+  %exitcond.1 = icmp ne i64 %indvar.next.1, 100
+  br i1 %exitcond.1, label %S1, label %exit.1
+
+exit.1:
+  br label %S2
+
+S2:
+  %indvar.2 = phi i64 [ 0, %exit.1 ], [ %indvar.next.2, %S2 ]
+  %arrayidx.2 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.2
+  store i32 5, i32* %arrayidx.2
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %exitcond.2 = icmp ne i64 %indvar.next.2, 10
+  br i1 %exitcond.2, label %S2, label %exit.2
+
+exit.2:
+  br label %S3
+
+S3:
+  %indvar.3 = phi i64 [ 0, %exit.2 ], [ %indvar.next.3, %S3 ]
+  %arrayidx.3 = getelementptr [200 x i32], [200 x i32]* %A, i64 0, i64 %indvar.3
+  store i32 7, i32* %arrayidx.3
+  %indvar.next.3 = add i64 %indvar.3, 1
+  %exitcond.3 = icmp ne i64 %indvar.next.3, 200
+  br i1 %exitcond.3, label %S3 , label %exit.3
+
+exit.3:
+  ret void
+}
+
+
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1) {
+; CHECK:   if (c0 <= 99) {
+; CHECK:     Stmt_S1(c0);
+; CHECK:     if (c0 <= 9)
+; CHECK:       Stmt_S2(c0);
+; CHECK:   }
+; CHECK:   Stmt_S3(c0);
+; CHECK: }
+
+; TIMEOUT: for (int c0 = 0; c0 <= 99; c0 += 1)
+; TIMEOUT: Stmt_S1(c0);
+; TIMEOUT: for (int c0 = 0; c0 <= 9; c0 += 1)
+; TIMEOUT: Stmt_S2(c0);
+; TIMEOUT: for (int c0 = 0; c0 <= 199; c0 += 1)
+; TIMEOUT: Stmt_S3(c0);
+
diff --git a/final/test/ScheduleOptimizer/ensure-correct-tile-sizes.ll b/final/test/ScheduleOptimizer/ensure-correct-tile-sizes.ll
new file mode 100644
index 0000000..a7d47d4
--- /dev/null
+++ b/final/test/ScheduleOptimizer/ensure-correct-tile-sizes.ll
@@ -0,0 +1,234 @@
+; RUN: opt %loadPolly -analyze -polly-process-unprofitable  -polly-remarks-minimal \
+; RUN:     -polly-opt-isl  -polly-pattern-matching-based-opts=true \
+; RUN:     -polly-target-throughput-vector-fma=1 \
+; RUN:     -polly-target-latency-vector-fma=1 \
+; RUN:     -polly-ast -polly-target-vector-register-bitwidth=4096 \
+; RUN:     -polly-target-1st-cache-level-associativity=3 < %s | FileCheck %s
+;
+;     /* Test that Polly does not crash due to configurations that can lead to
+;    incorrect tile size computations.
+;    The parameters are setup such that Car in `getMacroKernelParams`
+;    is evaluated to 0. */
+;
+;    static const int N = 3000;
+;
+;    void f(int A[N][N], int B[N][N], int C[N][N]) {
+;      for (int i = 0; i < N; i++) {
+;        for (int j = 0; j < N; j++) {
+;          A[i][j] = 0;
+;          for (int k = 0; k < N; k++) {
+;            A[i][j] += B[i][k] * C[k][j];
+;          }
+;        }
+;      }
+;    }
+;
+; CHECK:           // 1st level tiling - Tiles
+; CHECK-NEXT:      for (int c0 = 0; c0 <= 93; c0 += 1)
+; CHECK-NEXT:        for (int c1 = 0; c1 <= 93; c1 += 1) {
+; CHECK-NEXT:          // 1st level tiling - Points
+; CHECK-NEXT:          for (int c2 = 0; c2 <= min(31, -32 * c0 + 2999); c2 += 1)
+; CHECK-NEXT:            for (int c3 = 0; c3 <= min(31, -32 * c1 + 2999); c3 += 1)
+; CHECK-NEXT:              Stmt_for_body3(32 * c0 + c2, 32 * c1 + c3);
+; CHECK-NEXT:        }
+; CHECK-NEXT:      // Inter iteration alias-free
+; CHECK-NEXT:      // Register tiling - Tiles
+; CHECK-NEXT:      for (int c0 = 0; c0 <= 23; c0 += 1)
+; CHECK-NEXT:        for (int c1 = 0; c1 <= 2999; c1 += 1)
+; CHECK-NEXT:          for (int c2 = 0; c2 <= 2999; c2 += 1) {
+; CHECK-NEXT:            // Register tiling - Points
+; CHECK-NEXT:            {
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 1, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 2, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 3, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 4, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 5, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 6, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 7, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 8, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 9, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 10, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 11, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 12, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 13, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 14, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 15, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 16, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 17, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 18, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 19, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 20, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 21, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 22, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 23, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 24, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 25, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 26, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 27, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 28, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 29, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 30, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 31, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 32, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 33, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 34, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 35, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 36, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 37, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 38, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 39, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 40, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 41, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 42, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 43, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 44, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 45, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 46, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 47, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 48, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 49, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 50, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 51, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 52, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 53, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 54, c2);
+; CHECK-NEXT:              Stmt_for_body8(c1, 128 * c0 + 55, c2);
+; CHECK-NEXT:              if (c0 <= 22) {
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 56, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 57, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 58, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 59, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 60, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 61, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 62, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 63, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 64, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 65, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 66, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 67, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 68, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 69, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 70, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 71, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 72, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 73, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 74, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 75, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 76, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 77, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 78, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 79, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 80, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 81, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 82, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 83, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 84, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 85, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 86, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 87, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 88, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 89, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 90, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 91, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 92, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 93, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 94, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 95, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 96, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 97, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 98, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 99, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 100, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 101, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 102, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 103, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 104, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 105, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 106, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 107, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 108, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 109, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 110, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 111, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 112, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 113, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 114, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 115, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 116, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 117, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 118, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 119, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 120, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 121, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 122, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 123, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 124, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 125, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 126, c2);
+; CHECK-NEXT:                Stmt_for_body8(c1, 128 * c0 + 127, c2);
+; CHECK-NEXT:              }
+; CHECK-NEXT:            }
+; CHECK-NEXT:          }
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f([3000 x i32]* %A, [3000 x i32]* %B, [3000 x i32]* %C) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc24, %entry
+  %indvars.iv4 = phi i64 [ %indvars.iv.next5, %for.inc24 ], [ 0, %entry ]
+  %exitcond6 = icmp ne i64 %indvars.iv4, 3000
+  br i1 %exitcond6, label %for.body, label %for.end26
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc21, %for.body
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc21 ], [ 0, %for.body ]
+  %exitcond3 = icmp ne i64 %indvars.iv1, 3000
+  br i1 %exitcond3, label %for.body3, label %for.end23
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx5 = getelementptr inbounds [3000 x i32], [3000 x i32]* %A, i64 %indvars.iv4, i64 %indvars.iv1
+  store i32 0, i32* %arrayidx5, align 4
+  br label %for.cond6
+
+for.cond6:                                        ; preds = %for.inc, %for.body3
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %for.body3 ]
+  %exitcond = icmp ne i64 %indvars.iv, 3000
+  br i1 %exitcond, label %for.body8, label %for.end
+
+for.body8:                                        ; preds = %for.cond6
+  %arrayidx12 = getelementptr inbounds [3000 x i32], [3000 x i32]* %B, i64 %indvars.iv4, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx12, align 4
+  %arrayidx16 = getelementptr inbounds [3000 x i32], [3000 x i32]* %C, i64 %indvars.iv, i64 %indvars.iv1
+  %tmp7 = load i32, i32* %arrayidx16, align 4
+  %mul = mul nsw i32 %tmp, %tmp7
+  %arrayidx20 = getelementptr inbounds [3000 x i32], [3000 x i32]* %A, i64 %indvars.iv4, i64 %indvars.iv1
+  %tmp8 = load i32, i32* %arrayidx20, align 4
+  %add = add nsw i32 %tmp8, %mul
+  store i32 %add, i32* %arrayidx20, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond6
+
+for.end:                                          ; preds = %for.cond6
+  br label %for.inc21
+
+for.inc21:                                        ; preds = %for.end
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %for.cond1
+
+for.end23:                                        ; preds = %for.cond1
+  br label %for.inc24
+
+for.inc24:                                        ; preds = %for.end23
+  %indvars.iv.next5 = add nuw nsw i64 %indvars.iv4, 1
+  br label %for.cond
+
+for.end26:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/full_partial_tile_separation.ll b/final/test/ScheduleOptimizer/full_partial_tile_separation.ll
new file mode 100644
index 0000000..ede09e7
--- /dev/null
+++ b/final/test/ScheduleOptimizer/full_partial_tile_separation.ll
@@ -0,0 +1,91 @@
+; RUN: opt -S %loadPolly -polly-pattern-matching-based-opts=false \
+; RUN: -polly-vectorizer=stripmine -polly-opt-isl -polly-ast -analyze \
+; RUN: < %s | FileCheck %s
+; CHECK:          // 1st level tiling - Tiles
+; CHECK-NEXT:    #pragma known-parallel
+; CHECK-NEXT:    for (int c0 = 0; c0 <= floord(ni - 1, 32); c0 += 1)
+; CHECK-NEXT:      for (int c1 = 0; c1 <= floord(nj - 1, 32); c1 += 1)
+; CHECK-NEXT:        for (int c2 = 0; c2 <= floord(nk - 1, 32); c2 += 1) {
+; CHECK-NEXT:          // 1st level tiling - Points
+; CHECK-NEXT:          for (int c3 = 0; c3 <= min(31, ni - 32 * c0 - 1); c3 += 1) {
+; CHECK-NEXT:            for (int c4 = 0; c4 <= min(7, -8 * c1 + nj / 4 - 1); c4 += 1)
+; CHECK-NEXT:              for (int c5 = 0; c5 <= min(31, nk - 32 * c2 - 1); c5 += 1) {
+; CHECK-NEXT:                // SIMD
+; CHECK-NEXT:                for (int c6 = 0; c6 <= 3; c6 += 1)
+; CHECK-NEXT:                  Stmt_for_body_6(32 * c0 + c3, 32 * c1 + 4 * c4 + c6, 32 * c2 + c5);
+; CHECK-NEXT:              }
+; CHECK-NEXT:            if (32 * c1 + 31 >= nj)
+; CHECK-NEXT:              #pragma minimal dependence distance: 1
+; CHECK-NEXT:              for (int c5 = 0; c5 <= min(31, nk - 32 * c2 - 1); c5 += 1) {
+; CHECK-NEXT:                // SIMD
+; CHECK-NEXT:                for (int c6 = 0; c6 < nj % 4; c6 += 1)
+; CHECK-NEXT:                  Stmt_for_body_6(32 * c0 + c3, -(nj % 4) + nj + c6, 32 * c2 + c5);
+; CHECK-NEXT:              }
+; CHECK-NEXT:          }
+; CHECK-NEXT:        }
+
+; Function Attrs: nounwind uwtable
+define void @kernel_gemm(i32 %ni, i32 %nj, i32 %nk, double %alpha, double %beta, [1024 x double]* %C, [1024 x double]* %A, [1024 x double]* %B) #0 {
+entry:
+  %cmp.27 = icmp sgt i32 %ni, 0
+  br i1 %cmp.27, label %for.cond.1.preheader.lr.ph, label %for.end.22
+
+for.cond.1.preheader.lr.ph:                       ; preds = %entry
+  br label %for.cond.1.preheader
+
+for.cond.1.preheader:                             ; preds = %for.cond.1.preheader.lr.ph, %for.inc.20
+  %indvars.iv33 = phi i64 [ 0, %for.cond.1.preheader.lr.ph ], [ %indvars.iv.next34, %for.inc.20 ]
+  %cmp2.25 = icmp sgt i32 %nj, 0
+  br i1 %cmp2.25, label %for.cond.4.preheader.lr.ph, label %for.inc.20
+
+for.cond.4.preheader.lr.ph:                       ; preds = %for.cond.1.preheader
+  br label %for.cond.4.preheader
+
+for.cond.4.preheader:                             ; preds = %for.cond.4.preheader.lr.ph, %for.inc.17
+  %indvars.iv29 = phi i64 [ 0, %for.cond.4.preheader.lr.ph ], [ %indvars.iv.next30, %for.inc.17 ]
+  %cmp5.23 = icmp sgt i32 %nk, 0
+  br i1 %cmp5.23, label %for.body.6.lr.ph, label %for.inc.17
+
+for.body.6.lr.ph:                                 ; preds = %for.cond.4.preheader
+  br label %for.body.6
+
+for.body.6:                                       ; preds = %for.body.6.lr.ph, %for.body.6
+  %indvars.iv = phi i64 [ 0, %for.body.6.lr.ph ], [ %indvars.iv.next, %for.body.6 ]
+  %arrayidx8 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 %indvars.iv33, i64 %indvars.iv
+  %0 = load double, double* %arrayidx8, align 8
+  %arrayidx12 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %indvars.iv, i64 %indvars.iv29
+  %1 = load double, double* %arrayidx12, align 8
+  %mul = fmul double %0, %1
+  %arrayidx16 = getelementptr inbounds [1024 x double], [1024 x double]* %C, i64 %indvars.iv33, i64 %indvars.iv29
+  %2 = load double, double* %arrayidx16, align 8
+  %add = fadd double %2, %mul
+  store double %add, double* %arrayidx16, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %lftr.wideiv = trunc i64 %indvars.iv.next to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, %nk
+  br i1 %exitcond, label %for.body.6, label %for.cond.4.for.inc.17_crit_edge
+
+for.cond.4.for.inc.17_crit_edge:                  ; preds = %for.body.6
+  br label %for.inc.17
+
+for.inc.17:                                       ; preds = %for.cond.4.for.inc.17_crit_edge, %for.cond.4.preheader
+  %indvars.iv.next30 = add nuw nsw i64 %indvars.iv29, 1
+  %lftr.wideiv31 = trunc i64 %indvars.iv.next30 to i32
+  %exitcond32 = icmp ne i32 %lftr.wideiv31, %nj
+  br i1 %exitcond32, label %for.cond.4.preheader, label %for.cond.1.for.inc.20_crit_edge
+
+for.cond.1.for.inc.20_crit_edge:                  ; preds = %for.inc.17
+  br label %for.inc.20
+
+for.inc.20:                                       ; preds = %for.cond.1.for.inc.20_crit_edge, %for.cond.1.preheader
+  %indvars.iv.next34 = add nuw nsw i64 %indvars.iv33, 1
+  %lftr.wideiv35 = trunc i64 %indvars.iv.next34 to i32
+  %exitcond36 = icmp ne i32 %lftr.wideiv35, %ni
+  br i1 %exitcond36, label %for.cond.1.preheader, label %for.cond.for.end.22_crit_edge
+
+for.cond.for.end.22_crit_edge:                    ; preds = %for.inc.20
+  br label %for.end.22
+
+for.end.22:                                       ; preds = %for.cond.for.end.22_crit_edge, %entry
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/kernel_gemm___%for.body---%for.end24.jscop b/final/test/ScheduleOptimizer/kernel_gemm___%for.body---%for.end24.jscop
new file mode 100644
index 0000000..41f7a70
--- /dev/null
+++ b/final/test/ScheduleOptimizer/kernel_gemm___%for.body---%for.end24.jscop
@@ -0,0 +1,55 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_C1",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.body---%for.end24",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_C1[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i2, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body6[i0, i1, i2] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 and 0 <= i2 <= 1023 }",
+         "name" : "Stmt_for_body6",
+         "schedule" : "{ Stmt_for_body6[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/ScheduleOptimizer/kernel_gemm___%for.body---%for.end24.jscop.transformed b/final/test/ScheduleOptimizer/kernel_gemm___%for.body---%for.end24.jscop.transformed
new file mode 100644
index 0000000..1b0e4de
--- /dev/null
+++ b/final/test/ScheduleOptimizer/kernel_gemm___%for.body---%for.end24.jscop.transformed
@@ -0,0 +1,55 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_C1",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.body---%for.end24",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i2, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_C1[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body6[i0, i1, i2] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 and 0 <= i2 <= 1023 }",
+         "name" : "Stmt_for_body6",
+         "schedule" : "{ Stmt_for_body6[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/ScheduleOptimizer/kernel_gemm___%for.cond1.preheader---%for.end18.jscop.transformed b/final/test/ScheduleOptimizer/kernel_gemm___%for.cond1.preheader---%for.end18.jscop.transformed
new file mode 100644
index 0000000..d26e1a7
--- /dev/null
+++ b/final/test/ScheduleOptimizer/kernel_gemm___%for.cond1.preheader---%for.end18.jscop.transformed
@@ -0,0 +1,46 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*", "1024" ],
+         "type" : "double"
+      },
+      {
+         "name" : "New_MemRef_A",
+         "sizes" : [ "1024", "1024" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.cond1.preheader---%for.end18",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i2, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> New_MemRef_A[i0, i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body6[i0, i1, i2] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 and 0 <= i2 <= 1023 }",
+         "name" : "Stmt_for_body6",
+         "schedule" : "{ Stmt_for_body6[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/ScheduleOptimizer/line-tiling-2.ll b/final/test/ScheduleOptimizer/line-tiling-2.ll
new file mode 100644
index 0000000..d99683b
--- /dev/null
+++ b/final/test/ScheduleOptimizer/line-tiling-2.ll
@@ -0,0 +1,40 @@
+; RUN: opt %loadPolly -polly-opt-isl -analyze \
+; RUN:                -polly-ast -polly-tile-sizes=1,64 < %s | FileCheck %s
+
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK:   for (int c1 = 0; c1 <= 7; c1 += 1)
+; CHECK:     for (int c3 = 0; c3 <= 63; c3 += 1)
+; CHECK:       Stmt_for_body3(c0, 64 * c1 + c3);
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+; Function Attrs: nounwind
+define void @line([512 x i32]* %A) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body3.lr.ph
+
+for.body3.lr.ph:                                  ; preds = %for.inc5, %entry.split
+  %i.0 = phi i32 [ 0, %entry.split ], [ %inc6, %for.inc5 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.body3.lr.ph, %for.body3
+  %j.0 = phi i32 [ 0, %for.body3.lr.ph ], [ %inc, %for.body3 ]
+  %mul = mul nsw i32 %j.0, %i.0
+  %rem = srem i32 %mul, 42
+  %arrayidx4 = getelementptr inbounds [512 x i32], [512 x i32]* %A, i32 %i.0, i32 %j.0
+  store i32 %rem, i32* %arrayidx4, align 4
+  %inc = add nsw i32 %j.0, 1
+  %cmp2 = icmp slt i32 %inc, 512
+  br i1 %cmp2, label %for.body3, label %for.inc5
+
+for.inc5:                                         ; preds = %for.body3
+  %inc6 = add nsw i32 %i.0, 1
+  %cmp = icmp slt i32 %inc6, 1024
+  br i1 %cmp, label %for.body3.lr.ph, label %for.end7
+
+for.end7:                                         ; preds = %for.inc5
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/line-tiling.ll b/final/test/ScheduleOptimizer/line-tiling.ll
new file mode 100644
index 0000000..96f4161
--- /dev/null
+++ b/final/test/ScheduleOptimizer/line-tiling.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-opt-isl -analyze -polly-ast -polly-tile-sizes=64,1 < %s | FileCheck %s
+
+; CHECK: for (int c0 = 0; c0 <= 15; c0 += 1)
+; CHECK:   for (int c1 = 0; c1 <= 511; c1 += 1)
+; CHECK:     for (int c2 = 0; c2 <= 63; c2 += 1)
+; CHECK:       Stmt_for_body3(64 * c0 + c2, c1);
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+; Function Attrs: nounwind
+define void @line([512 x i32]* %A) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body3.lr.ph
+
+for.body3.lr.ph:                                  ; preds = %for.inc5, %entry.split
+  %i.0 = phi i32 [ 0, %entry.split ], [ %inc6, %for.inc5 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.body3.lr.ph, %for.body3
+  %j.0 = phi i32 [ 0, %for.body3.lr.ph ], [ %inc, %for.body3 ]
+  %mul = mul nsw i32 %j.0, %i.0
+  %rem = srem i32 %mul, 42
+  %arrayidx4 = getelementptr inbounds [512 x i32], [512 x i32]* %A, i32 %i.0, i32 %j.0
+  store i32 %rem, i32* %arrayidx4, align 4
+  %inc = add nsw i32 %j.0, 1
+  %cmp2 = icmp slt i32 %inc, 512
+  br i1 %cmp2, label %for.body3, label %for.inc5
+
+for.inc5:                                         ; preds = %for.body3
+  %inc6 = add nsw i32 %i.0, 1
+  %cmp = icmp slt i32 %inc6, 1024
+  br i1 %cmp, label %for.body3.lr.ph, label %for.end7
+
+for.end7:                                         ; preds = %for.inc5
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/mat_mul_pattern_data_layout.ll b/final/test/ScheduleOptimizer/mat_mul_pattern_data_layout.ll
new file mode 100644
index 0000000..699361a
--- /dev/null
+++ b/final/test/ScheduleOptimizer/mat_mul_pattern_data_layout.ll
@@ -0,0 +1,101 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-2nd-cache-level-size=262144 \
+; RUN: -polly-optimized-scops \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: -disable-output < %s 2>&1 | FileCheck %s
+;
+;    /* C := alpha*A*B + beta*C */
+;    for (i = 0; i < _PB_NI; i++)
+;      for (j = 0; j < _PB_NJ; j++)
+;        {
+;	   C[i][j] *= beta;
+;	   for (k = 0; k < _PB_NK; ++k)
+;	     C[i][j] += alpha * A[i][k] * B[k][j];
+;        }
+;
+; CHECK:        double Packed_B[ { [] -> [(256)] } ][ { [] -> [(256)] } ][ { [] -> [(8)] } ];
+; CHECK-NEXT:        double Packed_A[ { [] -> [(24)] } ][ { [] -> [(256)] } ][ { [] -> [(4)] } ]; // Element size 8
+;
+; CHECK:                { Stmt_Copy_0[i0, i1, i2] -> MemRef_arg6[i0, i2] };
+; CHECK-NEXT:           new: { Stmt_Copy_0[i0, i1, i2] -> Packed_A[o0, o1, o2] : 256*floor((-i2 + o1)/256) = -i2 + o1 and 96*floor((-i0 + 4o0 + o2)/96) = -i0 + 4o0 + o2 and 0 <= o1 <= 255 and o2 >= 0 and -4o0 <= o2 <= 95 - 4o0 and o2 <= 3 };
+;
+; CHECK:                { Stmt_Copy_0[i0, i1, i2] -> MemRef_arg7[i2, i1] };
+; CHECK-NEXT:           new: { Stmt_Copy_0[i0, i1, i2] -> Packed_B[o0, o1, i1 - 8o0] : 256*floor((-i2 + o1)/256) = -i2 + o1 and -7 + i1 <= 8o0 <= i1 and 0 <= o1 <= 255 };
+;
+; CHECK:    	CopyStmt_0
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                { CopyStmt_0[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 1023 };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                ;
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                ;
+; CHECK-NEXT:           new: { CopyStmt_0[i0, i1, i2] -> Packed_B[o0, o1, i1 - 8o0] : 256*floor((-i2 + o1)/256) = -i2 + o1 and -7 + i1 <= 8o0 <= i1 and 0 <= o1 <= 255 };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                ;
+; CHECK-NEXT:           new: { CopyStmt_0[i0, i1, i2] -> MemRef_arg7[i2, i1] };
+; CHECK-NEXT:    	CopyStmt_1
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                { CopyStmt_1[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 1023 };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                ;
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                ;
+; CHECK-NEXT:           new: { CopyStmt_1[i0, i1, i2] -> Packed_A[o0, o1, o2] : 256*floor((-i2 + o1)/256) = -i2 + o1 and 96*floor((-i0 + 4o0 + o2)/96) = -i0 + 4o0 + o2 and 0 <= o1 <= 255 and o2 >= 0 and -4o0 <= o2 <= 95 - 4o0 and o2 <= 3 };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                ;
+; CHECK-NEXT:           new: { CopyStmt_1[i0, i1, i2] -> MemRef_arg6[i0, i2] };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+define internal void @kernel_gemm(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %arg4, [1056 x double]* %arg5, [1024 x double]* %arg6, [1056 x double]* %arg7) #0 {
+bb:
+  br label %bb8
+
+bb8:                                              ; preds = %bb29, %bb
+  %tmp = phi i64 [ 0, %bb ], [ %tmp30, %bb29 ]
+  br label %bb9
+
+bb9:                                              ; preds = %bb26, %bb8
+  %tmp10 = phi i64 [ 0, %bb8 ], [ %tmp27, %bb26 ]
+  %tmp11 = getelementptr inbounds [1056 x double], [1056 x double]* %arg5, i64 %tmp, i64 %tmp10
+  %tmp12 = load double, double* %tmp11, align 8
+  %tmp13 = fmul double %tmp12, %arg4
+  store double %tmp13, double* %tmp11, align 8
+  br label %Copy_0
+
+Copy_0:                                             ; preds = %Copy_0, %bb9
+  %tmp15 = phi i64 [ 0, %bb9 ], [ %tmp24, %Copy_0 ]
+  %tmp16 = getelementptr inbounds [1024 x double], [1024 x double]* %arg6, i64 %tmp, i64 %tmp15
+  %tmp17 = load double, double* %tmp16, align 8
+  %tmp18 = fmul double %tmp17, %arg3
+  %tmp19 = getelementptr inbounds [1056 x double], [1056 x double]* %arg7, i64 %tmp15, i64 %tmp10
+  %tmp20 = load double, double* %tmp19, align 8
+  %tmp21 = fmul double %tmp18, %tmp20
+  %tmp22 = load double, double* %tmp11, align 8
+  %tmp23 = fadd double %tmp22, %tmp21
+  store double %tmp23, double* %tmp11, align 8
+  %tmp24 = add nuw nsw i64 %tmp15, 1
+  %tmp25 = icmp ne i64 %tmp24, 1024
+  br i1 %tmp25, label %Copy_0, label %bb26
+
+bb26:                                             ; preds = %Copy_0
+  %tmp27 = add nuw nsw i64 %tmp10, 1
+  %tmp28 = icmp ne i64 %tmp27, 1056
+  br i1 %tmp28, label %bb9, label %bb29
+
+bb29:                                             ; preds = %bb26
+  %tmp30 = add nuw nsw i64 %tmp, 1
+  %tmp31 = icmp ne i64 %tmp30, 1056
+  br i1 %tmp31, label %bb8, label %bb32
+
+bb32:                                             ; preds = %bb29
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+aes,+avx,+cmov,+cx16,+fxsr,+mmx,+pclmul,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" }
diff --git a/final/test/ScheduleOptimizer/mat_mul_pattern_data_layout_2.ll b/final/test/ScheduleOptimizer/mat_mul_pattern_data_layout_2.ll
new file mode 100644
index 0000000..7a64536
--- /dev/null
+++ b/final/test/ScheduleOptimizer/mat_mul_pattern_data_layout_2.ll
@@ -0,0 +1,134 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-2nd-cache-level-size=262144 -polly-ast \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN:  -analyze < %s | FileCheck %s
+;
+;    /* C := alpha*A*B + beta*C */
+;    /* _PB_NK % Kc != 0 */
+;    for (i = 0; i < _PB_NI; i++)
+;      for (j = 0; j < _PB_NJ; j++)
+;        {
+;	   C[i][j] *= beta;
+;	   for (k = 0; k < _PB_NK; ++k)
+;	     C[i][j] += alpha * A[i][k] * B[k][j];
+;        }
+;
+; CHECK:    {
+; CHECK-NEXT:      // 1st level tiling - Tiles
+; CHECK-NEXT:      for (int c0 = 0; c0 <= 32; c0 += 1)
+; CHECK-NEXT:        for (int c1 = 0; c1 <= 32; c1 += 1) {
+; CHECK-NEXT:          // 1st level tiling - Points
+; CHECK-NEXT:          for (int c2 = 0; c2 <= 31; c2 += 1)
+; CHECK-NEXT:            for (int c3 = 0; c3 <= 31; c3 += 1)
+; CHECK-NEXT:              Stmt_bb9(32 * c0 + c2, 32 * c1 + c3);
+; CHECK-NEXT:        }
+; CHECK-NEXT:      // Inter iteration alias-free
+; CHECK-NEXT:      // 1st level tiling - Tiles
+; CHECK-NEXT:      for (int c1 = 0; c1 <= 3; c1 += 1) {
+; CHECK-NEXT:        for (int c3 = 0; c3 <= 1055; c3 += 1)
+; CHECK-NEXT:          for (int c4 = 256 * c1; c4 <= min(1022, 256 * c1 + 255); c4 += 1)
+; CHECK-NEXT:            CopyStmt_0(0, c3, c4);
+; CHECK-NEXT:        for (int c2 = 0; c2 <= 10; c2 += 1) {
+; CHECK-NEXT:          for (int c3 = 96 * c2; c3 <= 96 * c2 + 95; c3 += 1)
+; CHECK-NEXT:            for (int c5 = 256 * c1; c5 <= min(1022, 256 * c1 + 255); c5 += 1)
+; CHECK-NEXT:              CopyStmt_1(c3, 0, c5);
+; CHECK-NEXT:          // 1st level tiling - Points
+; CHECK-NEXT:          // Register tiling - Tiles
+; CHECK-NEXT:          for (int c3 = 0; c3 <= 131; c3 += 1)
+; CHECK-NEXT:            for (int c4 = 0; c4 <= 23; c4 += 1)
+; CHECK-NEXT:              for (int c5 = 0; c5 <= min(255, -256 * c1 + 1022); c5 += 1) {
+; CHECK-NEXT:                // Loop Vectorizer Disabled
+; CHECK-NEXT:                // Register tiling - Points
+; CHECK-NEXT:                {
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                }
+; CHECK-NEXT:              }
+; CHECK-NEXT:        }
+; CHECK-NEXT:      }
+; CHECK-NEXT:    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+define internal void @kernel_gemm(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %arg4, [1056 x double]* %arg5, [1023 x double]* %arg6, [1056 x double]* %arg7) #0 {
+bb:
+  br label %bb8
+
+bb8:                                              ; preds = %bb29, %bb
+  %tmp = phi i64 [ 0, %bb ], [ %tmp30, %bb29 ]
+  br label %bb9
+
+bb9:                                              ; preds = %bb26, %bb8
+  %tmp10 = phi i64 [ 0, %bb8 ], [ %tmp27, %bb26 ]
+  %tmp11 = getelementptr inbounds [1056 x double], [1056 x double]* %arg5, i64 %tmp, i64 %tmp10
+  %tmp12 = load double, double* %tmp11, align 8
+  %tmp13 = fmul double %tmp12, %arg4
+  store double %tmp13, double* %tmp11, align 8
+  br label %Copy_0
+
+Copy_0:                                             ; preds = %Copy_0, %bb9
+  %tmp15 = phi i64 [ 0, %bb9 ], [ %tmp24, %Copy_0 ]
+  %tmp16 = getelementptr inbounds [1023 x double], [1023 x double]* %arg6, i64 %tmp, i64 %tmp15
+  %tmp17 = load double, double* %tmp16, align 8
+  %tmp18 = fmul double %tmp17, %arg3
+  %tmp19 = getelementptr inbounds [1056 x double], [1056 x double]* %arg7, i64 %tmp15, i64 %tmp10
+  %tmp20 = load double, double* %tmp19, align 8
+  %tmp21 = fmul double %tmp18, %tmp20
+  %tmp22 = load double, double* %tmp11, align 8
+  %tmp23 = fadd double %tmp22, %tmp21
+  store double %tmp23, double* %tmp11, align 8
+  %tmp24 = add nuw nsw i64 %tmp15, 1
+  %tmp25 = icmp ne i64 %tmp24, 1023
+  br i1 %tmp25, label %Copy_0, label %bb26
+
+bb26:                                             ; preds = %Copy_0
+  %tmp27 = add nuw nsw i64 %tmp10, 1
+  %tmp28 = icmp ne i64 %tmp27, 1056
+  br i1 %tmp28, label %bb9, label %bb29
+
+bb29:                                             ; preds = %bb26
+  %tmp30 = add nuw nsw i64 %tmp, 1
+  %tmp31 = icmp ne i64 %tmp30, 1056
+  br i1 %tmp31, label %bb8, label %bb32
+
+bb32:                                             ; preds = %bb29
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+aes,+avx,+cmov,+cx16,+fxsr,+mmx,+pclmul,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" }
diff --git a/final/test/ScheduleOptimizer/one-dimensional-band.ll b/final/test/ScheduleOptimizer/one-dimensional-band.ll
new file mode 100644
index 0000000..1247861
--- /dev/null
+++ b/final/test/ScheduleOptimizer/one-dimensional-band.ll
@@ -0,0 +1,107 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-ast -analyze < %s | FileCheck %s
+;
+;    void jacobi1d(long T, long N, float *A, float *B) {
+;      long t, i, j;
+;      for (t = 0; t < T; t++) {
+;        for (i = 1; i < N - 1; i++)
+;          B[i] = 0.33333 * (A[i - 1] + A[i] + A[i + 1]);
+;        for (j = 1; j < N - 1; j++)
+;          A[j] = 0.33333 * (B[i - 1] + B[i] + B[i + 1]);
+;      }
+;    }
+
+; Verify that we do not tile bands that have just a single dimension.
+
+; CHECK: for (int c0 = 0; c0 < T; c0 += 1) {
+; CHECK:   for (int c1 = 0; c1 < N - 2; c1 += 1)
+; CHECK:     Stmt_for_body3(c0, c1);
+; CHECK:   for (int c1 = 0; c1 < N - 2; c1 += 1)
+; CHECK:     Stmt_for_body15(c0, c1);
+; CHECK: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jacobi1d(i64 %T, i64 %N, float* %A, float* %B) {
+entry:
+  %tmp = add i64 %N, -1
+  %tmp1 = icmp sgt i64 %tmp, 1
+  %smax = select i1 %tmp1, i64 %tmp, i64 1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc30, %entry
+  %t.0 = phi i64 [ 0, %entry ], [ %inc31, %for.inc30 ]
+  %cmp = icmp slt i64 %t.0, %T
+  br i1 %cmp, label %for.body, label %for.end32
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %i.0 = phi i64 [ 1, %for.body ], [ %inc, %for.inc ]
+  %sub = add nsw i64 %N, -1
+  %cmp2 = icmp slt i64 %i.0, %sub
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %sub4 = add nsw i64 %i.0, -1
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %sub4
+  %tmp2 = load float, float* %arrayidx, align 4
+  %arrayidx5 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp3 = load float, float* %arrayidx5, align 4
+  %add = fadd float %tmp2, %tmp3
+  %add6 = add nuw nsw i64 %i.0, 1
+  %arrayidx7 = getelementptr inbounds float, float* %A, i64 %add6
+  %tmp4 = load float, float* %arrayidx7, align 4
+  %add8 = fadd float %add, %tmp4
+  %conv = fpext float %add8 to double
+  %mul = fmul double %conv, 3.333300e-01
+  %conv9 = fptrunc double %mul to float
+  %arrayidx10 = getelementptr inbounds float, float* %B, i64 %i.0
+  store float %conv9, float* %arrayidx10, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.cond11
+
+for.cond11:                                       ; preds = %for.inc27, %for.end
+  %j.0 = phi i64 [ 1, %for.end ], [ %inc28, %for.inc27 ]
+  %sub12 = add nsw i64 %N, -1
+  %cmp13 = icmp slt i64 %j.0, %sub12
+  br i1 %cmp13, label %for.body15, label %for.end29
+
+for.body15:                                       ; preds = %for.cond11
+  %sub16 = add nsw i64 %smax, -1
+  %arrayidx17 = getelementptr inbounds float, float* %B, i64 %sub16
+  %tmp5 = load float, float* %arrayidx17, align 4
+  %arrayidx18 = getelementptr inbounds float, float* %B, i64 %smax
+  %tmp6 = load float, float* %arrayidx18, align 4
+  %add19 = fadd float %tmp5, %tmp6
+  %add20 = add nsw i64 %smax, 1
+  %arrayidx21 = getelementptr inbounds float, float* %B, i64 %add20
+  %tmp7 = load float, float* %arrayidx21, align 4
+  %add22 = fadd float %add19, %tmp7
+  %conv23 = fpext float %add22 to double
+  %mul24 = fmul double %conv23, 3.333300e-01
+  %conv25 = fptrunc double %mul24 to float
+  %arrayidx26 = getelementptr inbounds float, float* %A, i64 %j.0
+  store float %conv25, float* %arrayidx26, align 4
+  br label %for.inc27
+
+for.inc27:                                        ; preds = %for.body15
+  %inc28 = add nuw nsw i64 %j.0, 1
+  br label %for.cond11
+
+for.end29:                                        ; preds = %for.cond11
+  br label %for.inc30
+
+for.inc30:                                        ; preds = %for.end29
+  %inc31 = add nuw nsw i64 %t.0, 1
+  br label %for.cond
+
+for.end32:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/outer_coincidence.ll b/final/test/ScheduleOptimizer/outer_coincidence.ll
new file mode 100644
index 0000000..85533e2
--- /dev/null
+++ b/final/test/ScheduleOptimizer/outer_coincidence.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-ast -polly-tiling=0 -polly-parallel -polly-opt-outer-coincidence=no -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-opt-isl -polly-ast -polly-tiling=0 -polly-parallel -polly-opt-outer-coincidence=yes -analyze < %s | FileCheck %s --check-prefix=OUTER
+
+; By skewing, the diagonal can be made parallel. ISL does this when the Check
+; the 'outer_coincidence' option is enabled.
+;
+; void func(int m, int n, float A[static const restrict m][n]) {
+;  for (int i = 1; i < m; i+=1)
+;    for (int j = 1; j < n; j+=1)
+;      A[i][j] = A[i-1][j] + A[i][j-1];
+;}
+
+define void @func(i64 %m, i64 %n, float* noalias nonnull %A) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc11, %entry
+  %i.0 = phi i64 [ 1, %entry ], [ %add12, %for.inc11 ]
+  %cmp = icmp slt i64 %i.0, %m
+  br i1 %cmp, label %for.cond1.preheader, label %for.end13
+
+for.cond1.preheader:                              ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.cond1.preheader, %for.body3
+  %j.0 = phi i64 [ %add10, %for.body3 ], [ 1, %for.cond1.preheader ]
+  %cmp2 = icmp slt i64 %j.0, %n
+  br i1 %cmp2, label %for.body3, label %for.inc11
+
+for.body3:                                        ; preds = %for.cond1
+  %sub = add nsw i64 %i.0, -1
+  %tmp = mul nsw i64 %sub, %n
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %tmp
+  %arrayidx4 = getelementptr inbounds float, float* %arrayidx, i64 %j.0
+  %tmp13 = load float, float* %arrayidx4, align 4
+  %sub5 = add nsw i64 %j.0, -1
+  %tmp14 = mul nsw i64 %i.0, %n
+  %arrayidx6 = getelementptr inbounds float, float* %A, i64 %tmp14
+  %arrayidx7 = getelementptr inbounds float, float* %arrayidx6, i64 %sub5
+  %tmp15 = load float, float* %arrayidx7, align 4
+  %add = fadd float %tmp13, %tmp15
+  %tmp16 = mul nsw i64 %i.0, %n
+  %arrayidx8 = getelementptr inbounds float, float* %A, i64 %tmp16
+  %arrayidx9 = getelementptr inbounds float, float* %arrayidx8, i64 %j.0
+  store float %add, float* %arrayidx9, align 4
+  %add10 = add nuw nsw i64 %j.0, 1
+  br label %for.cond1
+
+for.inc11:                                        ; preds = %for.cond1
+  %add12 = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end13:                                        ; preds = %for.cond
+  ret void
+}
+
+
+; CHECK:      #pragma minimal dependence distance: 1
+; CHECK-NEXT: for (int c0 = 0; c0 < m - 1; c0 += 1)
+; CHECK-NEXT:   #pragma minimal dependence distance: 1
+; CHECK-NEXT:   for (int c1 = 0; c1 < n - 1; c1 += 1)
+; CHECK-NEXT:     Stmt_for_body3(c0, c1);
+
+; OUTER:      #pragma minimal dependence distance: 1
+; OUTER-NEXT: for (int c0 = 0; c0 < m + n - 3; c0 += 1)
+; OUTER-NEXT:   #pragma simd
+; OUTER-NEXT:   #pragma known-parallel
+; OUTER-NEXT:   for (int c1 = max(0, -n + c0 + 2); c1 <= min(m - 2, c0); c1 += 1)
+; OUTER-NEXT:     Stmt_for_body3(c1, c0 - c1);
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts-after-delicm.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts-after-delicm.ll
new file mode 100644
index 0000000..7beafbc
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts-after-delicm.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly \
+; RUN: -polly-pattern-matching-based-opts=true \
+; RUN: -polly-optree -polly-delicm -polly-simplify \
+; RUN: -polly-opt-isl -debug < %s 2>&1 \
+; RUN: | FileCheck %s
+; REQUIRES: asserts
+
+; Check that the pattern matching detects the matrix multiplication pattern
+; after a full run of -polly-optree and -polly-delicm, where the write access
+; is not through the original memory access, but trough a PHI node that was
+; delicmed. This test covers the polybench 2mm and 3mm cases.
+;
+; CHECK: The matrix multiplication pattern was detected
+;
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: norecurse nounwind uwtable
+define void @kernel_2mm(i32 %ni, i32 %nj, i32 %nk, i32 %nl, double %alpha, double %beta, [1800 x double]* nocapture %tmp, [2200 x double]* nocapture readonly %A, [1800 x double]* nocapture readonly %B, [2400 x double]* nocapture readnone %C, [2400 x double]* nocapture readnone %D) local_unnamed_addr #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %for.inc25, %entry.split
+  %indvars.iv50 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next51, %for.inc25 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.inc22, %for.body
+  %indvars.iv46 = phi i64 [ 0, %for.body ], [ %indvars.iv.next47, %for.inc22 ]
+  %arrayidx5 = getelementptr inbounds [1800 x double], [1800 x double]* %tmp, i64 %indvars.iv50, i64 %indvars.iv46
+  store double 0.000000e+00, double* %arrayidx5, align 8, !tbaa !2
+  br label %for.body8
+
+for.body8:                                        ; preds = %for.body8, %for.body3
+  %0 = phi double [ 0.000000e+00, %for.body3 ], [ %add, %for.body8 ]
+  %indvars.iv = phi i64 [ 0, %for.body3 ], [ %indvars.iv.next, %for.body8 ]
+  %arrayidx12 = getelementptr inbounds [2200 x double], [2200 x double]* %A, i64 %indvars.iv50, i64 %indvars.iv
+  %1 = load double, double* %arrayidx12, align 8, !tbaa !2
+  %mul = fmul double %1, %alpha
+  %arrayidx16 = getelementptr inbounds [1800 x double], [1800 x double]* %B, i64 %indvars.iv, i64 %indvars.iv46
+  %2 = load double, double* %arrayidx16, align 8, !tbaa !2
+  %mul17 = fmul double %mul, %2
+  %add = fadd double %0, %mul17
+  store double %add, double* %arrayidx5, align 8, !tbaa !2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 2200
+  br i1 %exitcond, label %for.inc22, label %for.body8
+
+for.inc22:                                        ; preds = %for.body8
+  %indvars.iv.next47 = add nuw nsw i64 %indvars.iv46, 1
+  %exitcond48 = icmp eq i64 %indvars.iv.next47, 1800
+  br i1 %exitcond48, label %for.inc25, label %for.body3
+
+for.inc25:                                        ; preds = %for.inc22
+  %indvars.iv.next51 = add nuw nsw i64 %indvars.iv50, 1
+  %exitcond52 = icmp eq i64 %indvars.iv.next51, 1600
+  br i1 %exitcond52, label %for.end27, label %for.body
+
+for.end27:                                        ; preds = %for.inc25
+  ret void
+}
+
+attributes #0 = { norecurse nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="haswell" "target-features"="+aes,+avx,+avx2,+bmi,+bmi2,+cmov,+cx16,+f16c,+fma,+fsgsbase,+fxsr,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+rdrnd,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt,-adx,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512ifma,-avx512pf,-avx512vbmi,-avx512vl,-avx512vpopcntdq,-clflushopt,-clwb,-clzero,-fma4,-lwp,-mwaitx,-pku,-prefetchwt1,-prfchw,-rdseed,-rtm,-sgx,-sha,-sse4a,-tbm,-xop,-xsavec,-xsaves" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang version 6.0.0 (trunk 309912) (llvm/trunk 309933)"}
+!2 = !{!3, !3, i64 0}
+!3 = !{!"double", !4, i64 0}
+!4 = !{!"omnipotent char", !5, i64 0}
+!5 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts.ll
new file mode 100644
index 0000000..a7d7705
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=false \
+; RUN: -debug < %s 2>&1| FileCheck %s
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true -debug < %s 2>&1| FileCheck %s --check-prefix=PATTERN-MATCHING-OPTS
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true -stats -disable-output < %s 2>&1| FileCheck %s --check-prefix=STATS -match-full-lines
+; REQUIRES: asserts
+;
+;    /* C := alpha*A*B + beta*C */
+;    for (i = 0; i < _PB_NI; i++)
+;      for (j = 0; j < _PB_NJ; j++)
+;        {
+;	   C[i][j] *= beta;
+;	   for (k = 0; k < _PB_NK; ++k)
+;	     C[i][j] += alpha * A[i][k] * B[k][j];
+;        }
+;
+; CHECK-NOT: The matrix multiplication pattern was detected
+; PATTERN-MATCHING-OPTS: The matrix multiplication pattern was detected
+; STATS:  1 polly-opt-isl    - Number of matrix multiplication patterns detected and optimized
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+define internal void @kernel_gemm(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %arg4, [1056 x double]* %arg5, [1024 x double]* %arg6, [1056 x double]* %arg7) #0 {
+bb:
+  br label %bb8
+
+bb8:                                              ; preds = %bb29, %bb
+  %tmp = phi i64 [ 0, %bb ], [ %tmp30, %bb29 ]
+  br label %bb9
+
+bb9:                                              ; preds = %bb26, %bb8
+  %tmp10 = phi i64 [ 0, %bb8 ], [ %tmp27, %bb26 ]
+  %tmp11 = getelementptr inbounds [1056 x double], [1056 x double]* %arg5, i64 %tmp, i64 %tmp10
+  %tmp12 = load double, double* %tmp11, align 8
+  %tmp13 = fmul double %tmp12, %arg4
+  store double %tmp13, double* %tmp11, align 8
+  br label %Copy_0
+
+Copy_0:                                             ; preds = %Copy_0, %bb9
+  %tmp15 = phi i64 [ 0, %bb9 ], [ %tmp24, %Copy_0 ]
+  %tmp16 = getelementptr inbounds [1024 x double], [1024 x double]* %arg6, i64 %tmp, i64 %tmp15
+  %tmp17 = load double, double* %tmp16, align 8
+  %tmp18 = fmul double %tmp17, %arg3
+  %tmp19 = getelementptr inbounds [1056 x double], [1056 x double]* %arg7, i64 %tmp15, i64 %tmp10
+  %tmp20 = load double, double* %tmp19, align 8
+  %tmp21 = fmul double %tmp18, %tmp20
+  %tmp22 = load double, double* %tmp11, align 8
+  %tmp23 = fadd double %tmp22, %tmp21
+  store double %tmp23, double* %tmp11, align 8
+  %tmp24 = add nuw nsw i64 %tmp15, 1
+  %tmp25 = icmp ne i64 %tmp24, 1024
+  br i1 %tmp25, label %Copy_0, label %bb26
+
+bb26:                                             ; preds = %Copy_0
+  %tmp27 = add nuw nsw i64 %tmp10, 1
+  %tmp28 = icmp ne i64 %tmp27, 1056
+  br i1 %tmp28, label %bb9, label %bb29
+
+bb29:                                             ; preds = %bb26
+  %tmp30 = add nuw nsw i64 %tmp, 1
+  %tmp31 = icmp ne i64 %tmp30, 1056
+  br i1 %tmp31, label %bb8, label %bb32
+
+bb32:                                             ; preds = %bb29
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_10.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_10.ll
new file mode 100644
index 0000000..c7b7d4f
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_10.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-invariant-load-hoisting=true \
+; RUN: -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=1 \
+; RUN: -polly-codegen -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: -polly-target-2nd-cache-level-size=262144 -S < %s \
+; RUN: | FileCheck %s
+;
+; This test case checks whether Polly generates second level alias metadata
+; to distinguish the specific accesses in case of the ublas gemm kernel.
+;
+; CHECK: !11 = distinct !{!11, !0, !"second level alias metadata"}
+; CHECK: !12 = distinct !{!12, !0, !"second level alias metadata"}
+; CHECK: !13 = !{!3, !4, !5, !6, !11}
+; CHECK: !14 = distinct !{!14, !0, !"second level alias metadata"}
+; CHECK: !15 = !{!3, !4, !5, !6, !11, !12}
+; CHECK: !16 = distinct !{!16, !0, !"second level alias metadata"}
+; CHECK: !17 = !{!3, !4, !5, !6, !11, !12, !14}
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+define internal void @kernel_gemm(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %arg4, [1056 x double]* %arg5, [1024 x double]* %arg6, [1056 x double]* %arg7) {
+bb:
+  br label %bb8
+
+bb8:                                              ; preds = %bb29, %bb
+  %tmp = phi i64 [ 0, %bb ], [ %tmp30, %bb29 ]
+  br label %bb9
+
+bb9:                                              ; preds = %bb26, %bb8
+  %tmp10 = phi i64 [ 0, %bb8 ], [ %tmp27, %bb26 ]
+  %tmp11 = getelementptr inbounds [1056 x double], [1056 x double]* %arg5, i64 %tmp, i64 %tmp10
+  %tmp12 = load double, double* %tmp11, align 8
+  %tmp13 = fmul double %tmp12, %arg4
+  store double %tmp13, double* %tmp11, align 8
+  br label %Copy_0
+
+Copy_0:                                             ; preds = %Copy_0, %bb9
+  %tmp15 = phi i64 [ 0, %bb9 ], [ %tmp24, %Copy_0 ]
+  %tmp16 = getelementptr inbounds [1024 x double], [1024 x double]* %arg6, i64 %tmp, i64 %tmp15
+  %tmp17 = load double, double* %tmp16, align 8
+  %tmp18 = fmul double %tmp17, %arg3
+  %tmp19 = getelementptr inbounds [1056 x double], [1056 x double]* %arg7, i64 %tmp15, i64 %tmp10
+  %tmp20 = load double, double* %tmp19, align 8
+  %tmp21 = fmul double %tmp18, %tmp20
+  %tmp22 = load double, double* %tmp11, align 8
+  %tmp23 = fadd double %tmp22, %tmp21
+  store double %tmp23, double* %tmp11, align 8
+  %tmp24 = add nuw nsw i64 %tmp15, 1
+  %tmp25 = icmp ne i64 %tmp24, 1024
+  br i1 %tmp25, label %Copy_0, label %bb26
+
+bb26:                                             ; preds = %Copy_0
+  %tmp27 = add nuw nsw i64 %tmp10, 1
+  %tmp28 = icmp ne i64 %tmp27, 1056
+  br i1 %tmp28, label %bb9, label %bb29
+
+bb29:                                             ; preds = %bb26
+  %tmp30 = add nuw nsw i64 %tmp, 1
+  %tmp31 = icmp ne i64 %tmp30, 1056
+  br i1 %tmp31, label %bb8, label %bb32
+
+bb32:                                             ; preds = %bb29
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_11.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_11.ll
new file mode 100644
index 0000000..a2d11fb
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_11.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN: -polly-import-jscop-postfix=transformed \
+; RUN: -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: -polly-target-2nd-cache-level-size=262144 \
+; RUN: -polly-opt-isl -debug < %s 2>&1 \
+; RUN: | FileCheck %s
+; REQUIRES: asserts
+;
+; Check that the pattern matching detects the matrix multiplication pattern
+; in case scalar memory accesses were replaced by accesses to newly created
+; arrays.
+;
+; CHECK: The matrix multiplication pattern was detected
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+define void @kernel_gemm(i32 %ni, i32 %nj, i32 %nk, double %A, [1024 x double]* %B, [1024 x double]* %C) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.inc16, %entry.split
+  %indvars.iv35 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next36, %for.inc16 ]
+  br label %for.cond4.preheader
+
+for.cond4.preheader:                              ; preds = %for.inc13, %for.cond1.preheader
+  %indvars.iv32 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next33, %for.inc13 ]
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.cond4.preheader
+  %indvars.iv = phi i64 [ 0, %for.cond4.preheader ], [ %indvars.iv.next, %for.body6 ]
+  %arrayidx8 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %indvars.iv, i64 %indvars.iv32
+  %tmp = load double, double* %arrayidx8, align 8
+  %mul = fmul double %tmp, %A
+  %arrayidx12 = getelementptr inbounds [1024 x double], [1024 x double]* %C, i64 %indvars.iv35, i64 %indvars.iv32
+  %tmp1 = load double, double* %arrayidx12, align 8
+  %add = fadd double %tmp1, %mul
+  store double %add, double* %arrayidx12, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1024
+  br i1 %exitcond, label %for.body6, label %for.inc13
+
+for.inc13:                                        ; preds = %for.body6
+  %indvars.iv.next33 = add nuw nsw i64 %indvars.iv32, 1
+  %exitcond34 = icmp ne i64 %indvars.iv.next33, 1024
+  br i1 %exitcond34, label %for.cond4.preheader, label %for.inc16
+
+for.inc16:                                        ; preds = %for.inc13
+  %indvars.iv.next36 = add nuw nsw i64 %indvars.iv35, 1
+  %exitcond37 = icmp ne i64 %indvars.iv.next36, 1024
+  br i1 %exitcond37, label %for.cond1.preheader, label %for.end18
+
+for.end18:                                        ; preds = %for.inc16
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_12.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_12.ll
new file mode 100644
index 0000000..a14ec10
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_12.ll
@@ -0,0 +1,708 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -analyze -polly-ast -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: -polly-target-2nd-cache-level-size=262144 < %s \
+; RUN: | FileCheck %s
+;
+; Test whether isolation works as expected.
+;
+; CHECK:    // Inter iteration alias-free
+; CHECK-NEXT:    // 1st level tiling - Tiles
+; CHECK-NEXT:    for (int c1 = 0; c1 <= 1; c1 += 1) {
+; CHECK-NEXT:      for (int c3 = 0; c3 <= 1019; c3 += 1)
+; CHECK-NEXT:        for (int c4 = 512 * c1; c4 <= min(1019, 512 * c1 + 511); c4 += 1)
+; CHECK-NEXT:          CopyStmt_0(0, c3, c4);
+; CHECK-NEXT:      for (int c2 = 0; c2 <= 2; c2 += 1) {
+; CHECK-NEXT:        for (int c3 = 384 * c2; c3 <= min(1019, 384 * c2 + 383); c3 += 1)
+; CHECK-NEXT:          for (int c5 = 512 * c1; c5 <= min(1019, 512 * c1 + 511); c5 += 1)
+; CHECK-NEXT:            CopyStmt_1(c3, 0, c5);
+; CHECK-NEXT:        // 1st level tiling - Points
+; CHECK-NEXT:        // Register tiling - Tiles
+; CHECK-NEXT:        {
+; CHECK-NEXT:          for (int c3 = 0; c3 <= 30; c3 += 1) {
+; CHECK-NEXT:            for (int c4 = 0; c4 <= min(47, -48 * c2 + 126); c4 += 1)
+; CHECK-NEXT:              for (int c5 = 0; c5 <= min(511, -512 * c1 + 1019); c5 += 1) {
+; CHECK-NEXT:                // Loop Vectorizer Disabled
+; CHECK-NEXT:                // Register tiling - Points
+; CHECK-NEXT:                {
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                }
+; CHECK-NEXT:              }
+; CHECK-NEXT:                if (c2 == 2)
+; CHECK-NEXT:                  for (int c5 = 0; c5 <= min(511, -512 * c1 + 1019); c5 += 1) {
+; CHECK-NEXT:                    // Loop Vectorizer Disabled
+; CHECK-NEXT:                    // Register tiling - Points
+; CHECK-NEXT:                    {
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1016, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1017, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1018, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(1019, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                    }
+; CHECK-NEXT:                  }
+; CHECK-NEXT:              }
+; CHECK-NEXT:              for (int c4 = 0; c4 <= min(47, -48 * c2 + 127); c4 += 1)
+; CHECK-NEXT:                for (int c5 = 0; c5 <= min(511, -512 * c1 + 1019); c5 += 1) {
+; CHECK-NEXT:                  // Loop Vectorizer Disabled
+; CHECK-NEXT:                  // Register tiling - Points
+; CHECK-NEXT:                  {
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 992, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 993, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 994, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 995, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 996, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 997, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 998, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 999, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1000, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1001, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1002, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1003, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1004, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1005, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1006, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1007, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1008, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1009, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1010, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1011, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1012, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1013, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1014, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1015, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1016, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1017, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1018, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4, 1019, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 992, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 993, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 994, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 995, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 996, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 997, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 998, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 999, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1000, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1001, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1002, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1003, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1004, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1005, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1006, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1007, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1008, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1009, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1010, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1011, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1012, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1013, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1014, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1015, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1016, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1017, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1018, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 1, 1019, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 992, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 993, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 994, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 995, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 996, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 997, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 998, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 999, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1000, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1001, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1002, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1003, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1004, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1005, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1006, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1007, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1008, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1009, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1010, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1011, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1012, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1013, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1014, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1015, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1016, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1017, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1018, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 2, 1019, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 992, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 993, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 994, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 995, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 996, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 997, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 998, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 999, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1000, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1001, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1002, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1003, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1004, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1005, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1006, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1007, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1008, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1009, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1010, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1011, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1012, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1013, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1014, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1015, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1016, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1017, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1018, 512 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(384 * c2 + 8 * c4 + 3, 1019, 512 * c1 + c5);
+; CHECK-NEXT:                    if (48 * c2 + c4 <= 126) {
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 992, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 993, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 994, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 995, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 996, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 997, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 998, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 999, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1000, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1001, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1002, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1003, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1004, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1005, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1006, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1007, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1008, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1009, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1010, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1011, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1012, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1013, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1014, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1015, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1016, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1017, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1018, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 4, 1019, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 992, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 993, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 994, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 995, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 996, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 997, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 998, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 999, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1000, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1001, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1002, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1003, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1004, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1005, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1006, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1007, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1008, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1009, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1010, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1011, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1012, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1013, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1014, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1015, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1016, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1017, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1018, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 5, 1019, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 992, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 993, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 994, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 995, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 996, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 997, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 998, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 999, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1000, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1001, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1002, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1003, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1004, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1005, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1006, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1007, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1008, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1009, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1010, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1011, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1012, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1013, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1014, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1015, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1016, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1017, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1018, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 6, 1019, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 992, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 993, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 994, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 995, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 996, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 997, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 998, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 999, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1000, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1001, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1002, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1003, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1004, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1005, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1006, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1007, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1008, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1009, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1010, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1011, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1012, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1013, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1014, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1015, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1016, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1017, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1018, 512 * c1 + c5);
+; CHECK-NEXT:                      Stmt_for_body6(384 * c2 + 8 * c4 + 7, 1019, 512 * c1 + c5);
+; CHECK-NEXT:                    }
+; CHECK-NEXT:                  }
+; CHECK-NEXT:                }
+; CHECK-NEXT:            }
+; CHECK-NEXT:          }
+; CHECK-NEXT:        }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define internal void @kernel_gemm(i32 %ni, i32 %nj, i32 %nk, i8 signext %alpha, i8 signext %beta, [1020 x i8]* %C, [1020 x i8]* %A, [1020 x i8]* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %for.inc23, %entry.split
+  %indvars.iv45 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next46, %for.inc23 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.inc20, %for.body
+  %indvars.iv42 = phi i64 [ 0, %for.body ], [ %indvars.iv.next43, %for.inc20 ]
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.body3
+  %indvars.iv = phi i64 [ 0, %for.body3 ], [ %indvars.iv.next, %for.body6 ]
+  %arrayidx8 = getelementptr inbounds [1020 x i8], [1020 x i8]* %A, i64 %indvars.iv45, i64 %indvars.iv
+  %tmp = load i8, i8* %arrayidx8, align 1
+  %arrayidx12 = getelementptr inbounds [1020 x i8], [1020 x i8]* %B, i64 %indvars.iv, i64 %indvars.iv42
+  %tmp1 = load i8, i8* %arrayidx12, align 1
+  %mul = mul i8 %tmp1, %tmp
+  %arrayidx17 = getelementptr inbounds [1020 x i8], [1020 x i8]* %C, i64 %indvars.iv45, i64 %indvars.iv42
+  %tmp2 = load i8, i8* %arrayidx17, align 1
+  %add = add i8 %mul, %tmp2
+  store i8 %add, i8* %arrayidx17, align 1
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1020
+  br i1 %exitcond, label %for.body6, label %for.inc20
+
+for.inc20:                                        ; preds = %for.body6
+  %indvars.iv.next43 = add nuw nsw i64 %indvars.iv42, 1
+  %exitcond44 = icmp ne i64 %indvars.iv.next43, 1020
+  br i1 %exitcond44, label %for.body3, label %for.inc23
+
+for.inc23:                                        ; preds = %for.inc20
+  %indvars.iv.next46 = add nuw nsw i64 %indvars.iv45, 1
+  %exitcond47 = icmp ne i64 %indvars.iv.next46, 1020
+  br i1 %exitcond47, label %for.body, label %for.end25
+
+for.end25:                                        ; preds = %for.inc23
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_13.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_13.ll
new file mode 100644
index 0000000..12ba8f0
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_13.ll
@@ -0,0 +1,133 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=2 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -analyze -polly-ast -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-vector-register-bitwidth=128 \
+; RUN: -polly-target-2nd-cache-level-size=262144 < %s \
+; RUN: | FileCheck %s
+;
+; Test whether isolation works as expected.
+;
+; CHECK:   // Inter iteration alias-free
+; CHECK-NEXT:          // 1st level tiling - Tiles
+; CHECK-NEXT:          for (int c0 = 0; c0 <= 1; c0 += 1)
+; CHECK-NEXT:            for (int c1 = 0; c1 <= 6; c1 += 1) {
+; CHECK-NEXT:              for (int c3 = 1536 * c0; c3 <= min(1999, 1536 * c0 + 1535); c3 += 1)
+; CHECK-NEXT:                for (int c4 = 307 * c1; c4 <= min(1999, 307 * c1 + 306); c4 += 1)
+; CHECK-NEXT:                  CopyStmt_0(0, c3, c4);
+; CHECK-NEXT:              for (int c2 = 0; c2 <= 24; c2 += 1) {
+; CHECK-NEXT:                if (c0 == 0)
+; CHECK-NEXT:                  for (int c3 = 80 * c2; c3 <= 80 * c2 + 79; c3 += 1)
+; CHECK-NEXT:                    for (int c5 = 307 * c1; c5 <= min(1999, 307 * c1 + 306); c5 += 1)
+; CHECK-NEXT:                      CopyStmt_1(c3, 0, c5);
+; CHECK-NEXT:                // 1st level tiling - Points
+; CHECK-NEXT:                // Register tiling - Tiles
+; CHECK-NEXT:                {
+; CHECK-NEXT:                  for (int c3 = 0; c3 <= min(255, -256 * c0 + 332); c3 += 1)
+; CHECK-NEXT:                    for (int c4 = 0; c4 <= 15; c4 += 1)
+; CHECK-NEXT:                      for (int c5 = 0; c5 <= min(306, -307 * c1 + 1999); c5 += 1) {
+; CHECK-NEXT:                        // Loop Vectorizer Disabled
+; CHECK-NEXT:                        // Register tiling - Points
+; CHECK-NEXT:                        {
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4, 1536 * c0 + 6 * c3, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4, 1536 * c0 + 6 * c3 + 1, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4, 1536 * c0 + 6 * c3 + 2, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4, 1536 * c0 + 6 * c3 + 3, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4, 1536 * c0 + 6 * c3 + 4, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4, 1536 * c0 + 6 * c3 + 5, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 1, 1536 * c0 + 6 * c3, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 1, 1536 * c0 + 6 * c3 + 1, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 1, 1536 * c0 + 6 * c3 + 2, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 1, 1536 * c0 + 6 * c3 + 3, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 1, 1536 * c0 + 6 * c3 + 4, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 1, 1536 * c0 + 6 * c3 + 5, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 2, 1536 * c0 + 6 * c3, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 2, 1536 * c0 + 6 * c3 + 1, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 2, 1536 * c0 + 6 * c3 + 2, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 2, 1536 * c0 + 6 * c3 + 3, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 2, 1536 * c0 + 6 * c3 + 4, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 2, 1536 * c0 + 6 * c3 + 5, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 3, 1536 * c0 + 6 * c3, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 3, 1536 * c0 + 6 * c3 + 1, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 3, 1536 * c0 + 6 * c3 + 2, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 3, 1536 * c0 + 6 * c3 + 3, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 3, 1536 * c0 + 6 * c3 + 4, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 3, 1536 * c0 + 6 * c3 + 5, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 4, 1536 * c0 + 6 * c3, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 4, 1536 * c0 + 6 * c3 + 1, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 4, 1536 * c0 + 6 * c3 + 2, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 4, 1536 * c0 + 6 * c3 + 3, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 4, 1536 * c0 + 6 * c3 + 4, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 4, 1536 * c0 + 6 * c3 + 5, 307 * c1 + c5);
+; CHECK-NEXT:                        }
+; CHECK-NEXT:                      }
+; CHECK-NEXT:                  if (c0 == 1)
+; CHECK-NEXT:                    for (int c4 = 0; c4 <= 15; c4 += 1)
+; CHECK-NEXT:                      for (int c5 = 0; c5 <= min(306, -307 * c1 + 1999); c5 += 1) {
+; CHECK-NEXT:                        // Loop Vectorizer Disabled
+; CHECK-NEXT:                        // Register tiling - Points
+; CHECK-NEXT:                        {
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4, 1998, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4, 1999, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 1, 1998, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 1, 1999, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 2, 1998, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 2, 1999, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 3, 1998, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 3, 1999, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 4, 1998, 307 * c1 + c5);
+; CHECK-NEXT:                          Stmt_for_body6(80 * c2 + 5 * c4 + 4, 1999, 307 * c1 + c5);
+; CHECK-NEXT:                        }
+; CHECK-NEXT:                      }
+; CHECK-NEXT:                }
+; CHECK-NEXT:              }
+; CHECK-NEXT:            }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define internal void @kernel_gemm(i32 %ni, i32 %nj, i32 %nk, double %alpha, double %beta, [2000 x double]* %C, [2000 x double]* %A, [2000 x double]* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %for.inc20, %entry.split
+  %indvars.iv41 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next42, %for.inc20 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.inc17, %for.body
+  %indvars.iv38 = phi i64 [ 0, %for.body ], [ %indvars.iv.next39, %for.inc17 ]
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.body3
+  %indvars.iv = phi i64 [ 0, %for.body3 ], [ %indvars.iv.next, %for.body6 ]
+  %arrayidx8 = getelementptr inbounds [2000 x double], [2000 x double]* %A, i64 %indvars.iv41, i64 %indvars.iv
+  %tmp = load double, double* %arrayidx8, align 8
+  %arrayidx12 = getelementptr inbounds [2000 x double], [2000 x double]* %B, i64 %indvars.iv, i64 %indvars.iv38
+  %tmp1 = load double, double* %arrayidx12, align 8
+  %mul = fmul double %tmp, %tmp1
+  %arrayidx16 = getelementptr inbounds [2000 x double], [2000 x double]* %C, i64 %indvars.iv41, i64 %indvars.iv38
+  %tmp2 = load double, double* %arrayidx16, align 8
+  %add = fadd double %tmp2, %mul
+  store double %add, double* %arrayidx16, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 2000
+  br i1 %exitcond, label %for.body6, label %for.inc17
+
+for.inc17:                                        ; preds = %for.body6
+  %indvars.iv.next39 = add nuw nsw i64 %indvars.iv38, 1
+  %exitcond40 = icmp ne i64 %indvars.iv.next39, 2000
+  br i1 %exitcond40, label %for.body3, label %for.inc20
+
+for.inc20:                                        ; preds = %for.inc17
+  %indvars.iv.next42 = add nuw nsw i64 %indvars.iv41, 1
+  %exitcond43 = icmp ne i64 %indvars.iv.next42, 2000
+  br i1 %exitcond43, label %for.body, label %for.end22
+
+for.end22:                                        ; preds = %for.inc20
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_14.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_14.ll
new file mode 100644
index 0000000..82bdcbb
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_14.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-opt-isl  \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: -polly-target-2nd-cache-level-size=262144 \
+; RUN: -polly-import-jscop-postfix=transformed -polly-codegen -S < %s \
+; RUN: | FileCheck %s
+;
+; Check that we do not create different alias sets for locations represented by
+; different raw pointers.
+;
+; Also check that we disable the Loop Vectorizer.
+;
+; CHECK-NOT: !76 = distinct !{!76, !5, !"second level alias metadata"}
+; CHECK: !{!"llvm.loop.vectorize.enable", i1 false}
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+define void @kernel_gemm(i32 %ni, i32 %nj, i32 %nk, [1024 x double]* %A, [1024 x double]* %B, [1024 x double]* %C, double* %C1) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %for.inc22, %entry.split
+  %indvars.iv43 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next44, %for.inc22 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.inc19, %for.body
+  %indvars.iv40 = phi i64 [ 0, %for.body ], [ %indvars.iv.next41, %for.inc19 ]
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.body3
+  %indvars.iv = phi i64 [ 0, %for.body3 ], [ %indvars.iv.next, %for.body6 ]
+  %tmp = load double, double* %C1, align 8
+  %arrayidx9 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 %indvars.iv43, i64 %indvars.iv
+  %tmp1 = load double, double* %arrayidx9, align 8
+  %arrayidx13 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %indvars.iv, i64 %indvars.iv40
+  %tmp2 = load double, double* %arrayidx13, align 8
+  %mul = fmul double %tmp1, %tmp2
+  %add = fadd double %tmp, %mul
+  %arrayidx17 = getelementptr inbounds [1024 x double], [1024 x double]* %C, i64 %indvars.iv43, i64 %indvars.iv40
+  %tmp3 = load double, double* %arrayidx17, align 8
+  %add18 = fadd double %tmp3, %add
+  store double %add18, double* %arrayidx17, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1024
+  br i1 %exitcond, label %for.body6, label %for.inc19
+
+for.inc19:                                        ; preds = %for.body6
+  %indvars.iv.next41 = add nuw nsw i64 %indvars.iv40, 1
+  %exitcond42 = icmp ne i64 %indvars.iv.next41, 1024
+  br i1 %exitcond42, label %for.body3, label %for.inc22
+
+for.inc22:                                        ; preds = %for.inc19
+  %indvars.iv.next44 = add nuw nsw i64 %indvars.iv43, 1
+  %exitcond45 = icmp ne i64 %indvars.iv.next44, 1024
+  br i1 %exitcond45, label %for.body, label %for.end24
+
+for.end24:                                        ; preds = %for.inc22
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_2.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_2.ll
new file mode 100644
index 0000000..5498f84
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_2.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true -debug < %s 2>&1 | FileCheck %s
+; REQUIRES: asserts
+;
+;    /* C := alpha*A*B + beta*C */
+;    for (i = 0; i < _PB_NI; i++)
+;      for (j = 0; j < _PB_NJ; j += 2)
+;        {
+;	   C[i][j] *= beta;
+;	   for (k = 0; k < _PB_NK; ++k)
+;	     C[i][j] += alpha * A[i][k] * B[k][j];
+;        }
+;
+; Check that we won’t detect the matrix multiplication pattern,
+; if, for example, there are memory accesses that have stride 2
+; after the interchanging of loops.
+;
+; CHECK-NOT: The matrix multiplication pattern was detected
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+define internal void @kernel_gemm(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %arg4, [1056 x double]* %arg5, [1024 x double]* %arg6, [1056 x double]* %arg7) #0 {
+bb:
+  br label %bb8
+
+bb8:                                              ; preds = %bb29, %bb
+  %tmp = phi i64 [ 0, %bb ], [ %tmp30, %bb29 ]
+  br label %bb9
+
+bb9:                                              ; preds = %bb26, %bb8
+  %tmp10 = phi i64 [ 0, %bb8 ], [ %tmp27, %bb26 ]
+  %tmp11 = getelementptr inbounds [1056 x double], [1056 x double]* %arg5, i64 %tmp, i64 %tmp10
+  %tmp12 = load double, double* %tmp11, align 8
+  %tmp13 = fmul double %tmp12, %arg4
+  store double %tmp13, double* %tmp11, align 8
+  br label %Copy_0
+
+Copy_0:                                             ; preds = %Copy_0, %bb9
+  %tmp15 = phi i64 [ 0, %bb9 ], [ %tmp24, %Copy_0 ]
+  %tmp16 = getelementptr inbounds [1024 x double], [1024 x double]* %arg6, i64 %tmp, i64 %tmp15
+  %tmp17 = load double, double* %tmp16, align 8
+  %tmp18 = fmul double %tmp17, %arg3
+  %tmp19 = getelementptr inbounds [1056 x double], [1056 x double]* %arg7, i64 %tmp15, i64 %tmp10
+  %tmp20 = load double, double* %tmp19, align 8
+  %tmp21 = fmul double %tmp18, %tmp20
+  %tmp22 = load double, double* %tmp11, align 8
+  %tmp23 = fadd double %tmp22, %tmp21
+  store double %tmp23, double* %tmp11, align 8
+  %tmp24 = add nuw nsw i64 %tmp15, 1
+  %tmp25 = icmp ne i64 %tmp24, 1024
+  br i1 %tmp25, label %Copy_0, label %bb26
+
+bb26:                                             ; preds = %Copy_0
+  %tmp27 = add nuw nsw i64 %tmp10, 2
+  %tmp28 = icmp ne i64 %tmp27, 1056
+  br i1 %tmp28, label %bb9, label %bb29
+
+bb29:                                             ; preds = %bb26
+  %tmp30 = add nuw nsw i64 %tmp, 1
+  %tmp31 = icmp ne i64 %tmp30, 1056
+  br i1 %tmp31, label %bb8, label %bb32
+
+bb32:                                             ; preds = %bb29
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_3.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_3.ll
new file mode 100644
index 0000000..76341cb
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_3.ll
@@ -0,0 +1,190 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -analyze -polly-ast -polly-target-1st-cache-level-size=0 \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: < %s 2>&1 | FileCheck %s
+
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -analyze -polly-ast -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: -polly-target-2nd-cache-level-size=262144 < %s 2>&1 \
+; RUN: | FileCheck %s --check-prefix=EXTRACTION-OF-MACRO-KERNEL
+;
+;    /* C := alpha*A*B + beta*C */
+;    for (i = 0; i < _PB_NI; i++)
+;      for (j = 0; j < _PB_NJ; j++)
+;        {
+;	   C[i][j] *= beta;
+;	   for (k = 0; k < _PB_NK; ++k)
+;	     C[i][j] += alpha * A[i][k] * B[k][j];
+;        }
+;
+; CHECK:    {
+; CHECK-NEXT:      // 1st level tiling - Tiles
+; CHECK-NEXT:      for (int c0 = 0; c0 <= 32; c0 += 1)
+; CHECK-NEXT:        for (int c1 = 0; c1 <= 32; c1 += 1) {
+; CHECK-NEXT:          // 1st level tiling - Points
+; CHECK-NEXT:          for (int c2 = 0; c2 <= 31; c2 += 1)
+; CHECK-NEXT:            for (int c3 = 0; c3 <= 31; c3 += 1)
+; CHECK-NEXT:              Stmt_bb9(32 * c0 + c2, 32 * c1 + c3);
+; CHECK-NEXT:        }
+; CHECK-NEXT:      // Inter iteration alias-free
+; CHECK-NEXT:      // Register tiling - Tiles
+; CHECK-NEXT:      for (int c0 = 0; c0 <= 131; c0 += 1)
+; CHECK-NEXT:        for (int c1 = 0; c1 <= 263; c1 += 1)
+; CHECK-NEXT:          for (int c2 = 0; c2 <= 1023; c2 += 1) {
+; CHECK-NEXT:            // Register tiling - Points
+; CHECK-NEXT:            {
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1, 8 * c0, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1, 8 * c0 + 1, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1, 8 * c0 + 2, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1, 8 * c0 + 3, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1, 8 * c0 + 4, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1, 8 * c0 + 5, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1, 8 * c0 + 6, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1, 8 * c0 + 7, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 1, 8 * c0, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 1, 8 * c0 + 1, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 1, 8 * c0 + 2, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 1, 8 * c0 + 3, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 1, 8 * c0 + 4, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 1, 8 * c0 + 5, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 1, 8 * c0 + 6, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 1, 8 * c0 + 7, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 2, 8 * c0, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 2, 8 * c0 + 1, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 2, 8 * c0 + 2, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 2, 8 * c0 + 3, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 2, 8 * c0 + 4, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 2, 8 * c0 + 5, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 2, 8 * c0 + 6, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 2, 8 * c0 + 7, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 3, 8 * c0, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 3, 8 * c0 + 1, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 3, 8 * c0 + 2, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 3, 8 * c0 + 3, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 3, 8 * c0 + 4, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 3, 8 * c0 + 5, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 3, 8 * c0 + 6, c2);
+; CHECK-NEXT:              Stmt_Copy_0(4 * c1 + 3, 8 * c0 + 7, c2);
+; CHECK-NEXT:            }
+; CHECK-NEXT:          }
+; CHECK-NEXT:    }
+;
+; EXTRACTION-OF-MACRO-KERNEL:    {
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:      // 1st level tiling - Tiles
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:      for (int c0 = 0; c0 <= 32; c0 += 1)
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:        for (int c1 = 0; c1 <= 32; c1 += 1) {
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:          // 1st level tiling - Points
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:          for (int c2 = 0; c2 <= 31; c2 += 1)
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:            for (int c3 = 0; c3 <= 31; c3 += 1)
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:              Stmt_bb9(32 * c0 + c2, 32 * c1 + c3);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:        }
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:      // Inter iteration alias-free
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:      // 1st level tiling - Tiles
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:      for (int c1 = 0; c1 <= 3; c1 += 1) {
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:        for (int c3 = 0; c3 <= 1055; c3 += 1)
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:          for (int c4 = 256 * c1; c4 <= 256 * c1 + 255; c4 += 1)
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:            CopyStmt_0(0, c3, c4);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:        for (int c2 = 0; c2 <= 10; c2 += 1) {
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:          for (int c3 = 96 * c2; c3 <= 96 * c2 + 95; c3 += 1)
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:            for (int c5 = 256 * c1; c5 <= 256 * c1 + 255; c5 += 1)
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:              CopyStmt_1(c3, 0, c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:          // 1st level tiling - Points
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:          // Register tiling - Tiles
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:          for (int c3 = 0; c3 <= 131; c3 += 1)
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:            for (int c4 = 0; c4 <= 23; c4 += 1)
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:              for (int c5 = 0; c5 <= 255; c5 += 1) {
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                // Loop Vectorizer Disabled
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                // Register tiling - Points
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                {
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 1, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 2, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 3, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 4, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 5, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 6, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4, 8 * c3 + 7, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 1, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 2, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 3, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 4, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 5, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 6, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 1, 8 * c3 + 7, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 1, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 2, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 3, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 4, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 5, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 6, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 2, 8 * c3 + 7, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 1, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 2, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 3, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 4, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 5, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 6, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                  Stmt_Copy_0(96 * c2 + 4 * c4 + 3, 8 * c3 + 7, 256 * c1 + c5);
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:                }
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:              }
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:        }
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:      }
+; EXTRACTION-OF-MACRO-KERNEL-NEXT:    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+define internal void @kernel_gemm(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %arg4, [1056 x double]* %arg5, [1024 x double]* %arg6, [1056 x double]* %arg7) #0 {
+bb:
+  br label %bb8
+
+bb8:                                              ; preds = %bb29, %bb
+  %tmp = phi i64 [ 0, %bb ], [ %tmp30, %bb29 ]
+  br label %bb9
+
+bb9:                                              ; preds = %bb26, %bb8
+  %tmp10 = phi i64 [ 0, %bb8 ], [ %tmp27, %bb26 ]
+  %tmp11 = getelementptr inbounds [1056 x double], [1056 x double]* %arg5, i64 %tmp, i64 %tmp10
+  %tmp12 = load double, double* %tmp11, align 8
+  %tmp13 = fmul double %tmp12, %arg4
+  store double %tmp13, double* %tmp11, align 8
+  br label %Copy_0
+
+Copy_0:                                             ; preds = %Copy_0, %bb9
+  %tmp15 = phi i64 [ 0, %bb9 ], [ %tmp24, %Copy_0 ]
+  %tmp16 = getelementptr inbounds [1024 x double], [1024 x double]* %arg6, i64 %tmp, i64 %tmp15
+  %tmp17 = load double, double* %tmp16, align 8
+  %tmp18 = fmul double %tmp17, %arg3
+  %tmp19 = getelementptr inbounds [1056 x double], [1056 x double]* %arg7, i64 %tmp15, i64 %tmp10
+  %tmp20 = load double, double* %tmp19, align 8
+  %tmp21 = fmul double %tmp18, %tmp20
+  %tmp22 = load double, double* %tmp11, align 8
+  %tmp23 = fadd double %tmp22, %tmp21
+  store double %tmp23, double* %tmp11, align 8
+  %tmp24 = add nuw nsw i64 %tmp15, 1
+  %tmp25 = icmp ne i64 %tmp24, 1024
+  br i1 %tmp25, label %Copy_0, label %bb26
+
+bb26:                                             ; preds = %Copy_0
+  %tmp27 = add nuw nsw i64 %tmp10, 1
+  %tmp28 = icmp ne i64 %tmp27, 1056
+  br i1 %tmp28, label %bb9, label %bb29
+
+bb29:                                             ; preds = %bb26
+  %tmp30 = add nuw nsw i64 %tmp, 1
+  %tmp31 = icmp ne i64 %tmp30, 1056
+  br i1 %tmp31, label %bb8, label %bb32
+
+bb32:                                             ; preds = %bb29
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_4.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_4.ll
new file mode 100644
index 0000000..bdaa301
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_4.ll
@@ -0,0 +1,124 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -debug < %s 2>&1| FileCheck %s
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: -polly-target-2nd-cache-level-size=262144 -polly-ast \
+; RUN: -analyze < %s | FileCheck %s --check-prefix=PATTERN-MATCHING-OPTS
+; REQUIRES: asserts
+;
+;    C := A * B + C
+;    Check that the pattern matching optimizations can detect different
+;    permutations of GEMM loop and produce the correct ISL AST. In this case,
+;    dimensions of band nodes can be implicitly permuted by the algorithm
+;    applied during the schedule generation. It should be taken into the
+;    account during the pattern matching optimizations.
+;    for (i = 0; i < _PB_NI; i++)
+;      for (k = 0; k < _PB_NK; ++k)
+;        for (j = 0; j < _PB_NJ; j++)
+;	   C[i][j] += A[i][k] * B[k][j];
+;
+; CHECK: The matrix multiplication pattern was detected
+;
+; PATTERN-MATCHING-OPTS:    // 1st level tiling - Tiles
+; PATTERN-MATCHING-OPTS-NEXT:    for (int c1 = 0; c1 <= 3; c1 += 1) {
+; PATTERN-MATCHING-OPTS-NEXT:      for (int c3 = 256 * c1; c3 <= 256 * c1 + 255; c3 += 1)
+; PATTERN-MATCHING-OPTS-NEXT:        for (int c4 = 0; c4 <= 1023; c4 += 1)
+; PATTERN-MATCHING-OPTS-NEXT:          CopyStmt_0(0, c3, c4);
+; PATTERN-MATCHING-OPTS-NEXT:      for (int c2 = 0; c2 <= 10; c2 += 1) {
+; PATTERN-MATCHING-OPTS-NEXT:        for (int c3 = 96 * c2; c3 <= min(1023, 96 * c2 + 95); c3 += 1)
+; PATTERN-MATCHING-OPTS-NEXT:          for (int c4 = 256 * c1; c4 <= 256 * c1 + 255; c4 += 1)
+; PATTERN-MATCHING-OPTS-NEXT:            CopyStmt_1(c3, c4, 0);
+; PATTERN-MATCHING-OPTS-NEXT:        // 1st level tiling - Points
+; PATTERN-MATCHING-OPTS-NEXT:        // Register tiling - Tiles
+; PATTERN-MATCHING-OPTS-NEXT:        for (int c3 = 0; c3 <= 127; c3 += 1)
+; PATTERN-MATCHING-OPTS-NEXT:          for (int c4 = 0; c4 <= min(23, -24 * c2 + 255); c4 += 1)
+; PATTERN-MATCHING-OPTS-NEXT:            for (int c5 = 0; c5 <= 255; c5 += 1) {
+; PATTERN-MATCHING-OPTS-NEXT:              // Loop Vectorizer Disabled
+; PATTERN-MATCHING-OPTS-NEXT:              // Register tiling - Points
+; PATTERN-MATCHING-OPTS-NEXT:              {
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 256 * c1 + c5, 8 * c3);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 256 * c1 + c5, 8 * c3 + 1);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 256 * c1 + c5, 8 * c3 + 2);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 256 * c1 + c5, 8 * c3 + 3);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 256 * c1 + c5, 8 * c3 + 4);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 256 * c1 + c5, 8 * c3 + 5);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 256 * c1 + c5, 8 * c3 + 6);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 256 * c1 + c5, 8 * c3 + 7);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 256 * c1 + c5, 8 * c3);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 256 * c1 + c5, 8 * c3 + 1);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 256 * c1 + c5, 8 * c3 + 2);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 256 * c1 + c5, 8 * c3 + 3);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 256 * c1 + c5, 8 * c3 + 4);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 256 * c1 + c5, 8 * c3 + 5);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 256 * c1 + c5, 8 * c3 + 6);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 256 * c1 + c5, 8 * c3 + 7);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 256 * c1 + c5, 8 * c3);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 256 * c1 + c5, 8 * c3 + 1);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 256 * c1 + c5, 8 * c3 + 2);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 256 * c1 + c5, 8 * c3 + 3);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 256 * c1 + c5, 8 * c3 + 4);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 256 * c1 + c5, 8 * c3 + 5);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 256 * c1 + c5, 8 * c3 + 6);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 256 * c1 + c5, 8 * c3 + 7);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 256 * c1 + c5, 8 * c3);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 256 * c1 + c5, 8 * c3 + 1);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 256 * c1 + c5, 8 * c3 + 2);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 256 * c1 + c5, 8 * c3 + 3);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 256 * c1 + c5, 8 * c3 + 4);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 256 * c1 + c5, 8 * c3 + 5);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 256 * c1 + c5, 8 * c3 + 6);
+; PATTERN-MATCHING-OPTS-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 256 * c1 + c5, 8 * c3 + 7);
+; PATTERN-MATCHING-OPTS-NEXT:              }
+; PATTERN-MATCHING-OPTS-NEXT:            }
+; PATTERN-MATCHING-OPTS-NEXT:      }
+; PATTERN-MATCHING-OPTS-NEXT:    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+define internal void @kernel_gemm(i32 %ni, i32 %nj, i32 %nk, double %alpha, double %beta, [1024 x double]* %C, [1024 x double]* %A, [1024 x double]* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.inc20, %entry.split
+  %indvars.iv41 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next42, %for.inc20 ]
+  br label %for.cond4.preheader
+
+for.cond4.preheader:                              ; preds = %for.inc17, %for.cond1.preheader
+  %indvars.iv38 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next39, %for.inc17 ]
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.cond4.preheader
+  %indvars.iv = phi i64 [ 0, %for.cond4.preheader ], [ %indvars.iv.next, %for.body6 ]
+  %arrayidx8 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 %indvars.iv41, i64 %indvars.iv38
+  %tmp = load double, double* %arrayidx8, align 8
+  %arrayidx12 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %indvars.iv38, i64 %indvars.iv
+  %tmp1 = load double, double* %arrayidx12, align 8
+  %mul = fmul double %tmp, %tmp1
+  %arrayidx16 = getelementptr inbounds [1024 x double], [1024 x double]* %C, i64 %indvars.iv41, i64 %indvars.iv
+  %tmp2 = load double, double* %arrayidx16, align 8
+  %add = fadd double %tmp2, %mul
+  store double %add, double* %arrayidx16, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1024
+  br i1 %exitcond, label %for.body6, label %for.inc17
+
+for.inc17:                                        ; preds = %for.body6
+  %indvars.iv.next39 = add nuw nsw i64 %indvars.iv38, 1
+  %exitcond40 = icmp ne i64 %indvars.iv.next39, 1024
+  br i1 %exitcond40, label %for.cond4.preheader, label %for.inc20
+
+for.inc20:                                        ; preds = %for.inc17
+  %indvars.iv.next42 = add nuw nsw i64 %indvars.iv41, 1
+  %exitcond43 = icmp ne i64 %indvars.iv.next42, 1024
+  br i1 %exitcond43, label %for.cond1.preheader, label %for.end22
+
+for.end22:                                        ; preds = %for.inc20
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_5.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_5.ll
new file mode 100644
index 0000000..55aa0dc
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_5.ll
@@ -0,0 +1,381 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -analyze -polly-ast -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: -polly-target-2nd-cache-level-size=262144 < %s \
+; RUN: | FileCheck %s
+;
+; opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; -polly-target-throughput-vector-fma=1 \
+; -polly-target-latency-vector-fma=8 \
+; -polly-codegen -polly-target-1st-cache-level-associativity=8 \
+; -polly-target-2nd-cache-level-associativity=8 \
+; -polly-target-1st-cache-level-size=32768 \
+; -polly-target-vector-register-bitwidth=256 \
+; -polly-target-2nd-cache-level-size=262144 -gvn -licm -slp-vectorizer \
+; -mcpu=corei7 -stats -S < %s 2>&1 | FileCheck %s --check-prefix=AUTO-VECTORIZATION
+;
+;
+;    /* We isolate a set of partial tile prefixes, which contains only partial
+;       tile prefixes that have exactly Mr x Nr iterations of the two innermost
+;       loops produced by the optimization of the matrix multiplication. Mr and
+;       Nr are parameters of the micro-kernel (see getMicroKernelParams and
+;       getMacroKernelParams from lib/Transform/ScheduleOptimizer.cpp for
+;       details). This test check that in case of parametric bounds it helps to
+;       get rid of the conditional expressions of the unrolled innermost loops,
+;       which prevents stores and loads of the unrolled loops from being sunk
+;       and hoisted. Otherwise, it causes a run-time regression in comparison
+;       to the vectorized code with sunk and hoisted memory accesses. */
+;
+;    /* C := A * B + C */
+;    for (i = 0; i < _PB_NI; i++)
+;      for (j = 0; j < _PB_NJ; j++)
+;	 for (k = 0; k < _PB_NK; ++k)
+;	   C[i][j] += A[i][k] * B[k][j];
+;
+; CHECK:          if (ni >= 1) {
+; CHECK-NEXT:            // Inter iteration alias-free
+; CHECK-NEXT:            // 1st level tiling - Tiles
+; CHECK-NEXT:            for (int c0 = 0; c0 <= floord(nj - 1, 2048); c0 += 1)
+; CHECK-NEXT:              for (int c1 = 0; c1 <= floord(nk - 1, 256); c1 += 1) {
+; CHECK-NEXT:                for (int c3 = 2048 * c0; c3 <= min(nj - 1, 2048 * c0 + 2047); c3 += 1)
+; CHECK-NEXT:                  for (int c4 = 256 * c1; c4 <= min(nk - 1, 256 * c1 + 255); c4 += 1)
+; CHECK-NEXT:                    CopyStmt_0(0, c3, c4);
+; CHECK-NEXT:                for (int c2 = 0; c2 <= floord(ni - 1, 96); c2 += 1) {
+; CHECK-NEXT:                  if (c0 == 0)
+; CHECK-NEXT:                    for (int c3 = 96 * c2; c3 <= min(ni - 1, 96 * c2 + 95); c3 += 1)
+; CHECK-NEXT:                      for (int c5 = 256 * c1; c5 <= min(nk - 1, 256 * c1 + 255); c5 += 1)
+; CHECK-NEXT:                        CopyStmt_1(c3, 0, c5);
+; CHECK-NEXT:                  // 1st level tiling - Points
+; CHECK-NEXT:                  // Register tiling - Tiles
+; CHECK-NEXT:                  {
+; CHECK-NEXT:                    if (ni >= 96 * c2 + 4)
+; CHECK-NEXT:                      for (int c3 = 0; c3 <= min(255, -256 * c0 + nj / 8 - 1); c3 += 1) {
+; CHECK-NEXT:                        for (int c4 = 0; c4 <= min(23, -24 * c2 + ni / 4 - 1); c4 += 1)
+; CHECK-NEXT:                          for (int c5 = 0; c5 <= min(255, nk - 256 * c1 - 1); c5 += 1) {
+; CHECK-NEXT:                            // Loop Vectorizer Disabled
+; CHECK-NEXT:                            // Register tiling - Points
+; CHECK-NEXT:                            {
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4, 2048 * c0 + 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4, 2048 * c0 + 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4, 2048 * c0 + 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4, 2048 * c0 + 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4, 2048 * c0 + 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4, 2048 * c0 + 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4, 2048 * c0 + 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4, 2048 * c0 + 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 1, 2048 * c0 + 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 1, 2048 * c0 + 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 1, 2048 * c0 + 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 1, 2048 * c0 + 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 1, 2048 * c0 + 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 1, 2048 * c0 + 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 1, 2048 * c0 + 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 1, 2048 * c0 + 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 2, 2048 * c0 + 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 2, 2048 * c0 + 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 2, 2048 * c0 + 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 2, 2048 * c0 + 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 2, 2048 * c0 + 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 2, 2048 * c0 + 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 2, 2048 * c0 + 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 2, 2048 * c0 + 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 3, 2048 * c0 + 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 3, 2048 * c0 + 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 3, 2048 * c0 + 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 3, 2048 * c0 + 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 3, 2048 * c0 + 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 3, 2048 * c0 + 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 3, 2048 * c0 + 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4 + 3, 2048 * c0 + 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                            }
+; CHECK-NEXT:                          }
+; CHECK-NEXT:                        if (96 * c2 + 95 >= ni && ni % 4 >= 1)
+; CHECK-NEXT:                          for (int c5 = 0; c5 <= min(255, nk - 256 * c1 - 1); c5 += 1) {
+; CHECK-NEXT:                            // Loop Vectorizer Disabled
+; CHECK-NEXT:                            // Register tiling - Points
+; CHECK-NEXT:                            {
+; CHECK-NEXT:                              Stmt_for_body6(-((ni + 4) % 4) + ni, 2048 * c0 + 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(-((ni + 4) % 4) + ni, 2048 * c0 + 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(-((ni + 4) % 4) + ni, 2048 * c0 + 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(-((ni + 4) % 4) + ni, 2048 * c0 + 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(-((ni + 4) % 4) + ni, 2048 * c0 + 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(-((ni + 4) % 4) + ni, 2048 * c0 + 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(-((ni + 4) % 4) + ni, 2048 * c0 + 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                              Stmt_for_body6(-((ni + 4) % 4) + ni, 2048 * c0 + 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                              if (ni % 4 >= 2) {
+; CHECK-NEXT:                                Stmt_for_body6(-((ni + 4) % 4) + ni + 1, 2048 * c0 + 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                                Stmt_for_body6(-((ni + 4) % 4) + ni + 1, 2048 * c0 + 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                                Stmt_for_body6(-((ni + 4) % 4) + ni + 1, 2048 * c0 + 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                                Stmt_for_body6(-((ni + 4) % 4) + ni + 1, 2048 * c0 + 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                                Stmt_for_body6(-((ni + 4) % 4) + ni + 1, 2048 * c0 + 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                                Stmt_for_body6(-((ni + 4) % 4) + ni + 1, 2048 * c0 + 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                                Stmt_for_body6(-((ni + 4) % 4) + ni + 1, 2048 * c0 + 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                                Stmt_for_body6(-((ni + 4) % 4) + ni + 1, 2048 * c0 + 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                                if ((ni + 1) % 4 == 0) {
+; CHECK-NEXT:                                  Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                                  Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                                  Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                                  Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                                  Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                                  Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                                  Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                                  Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                                }
+; CHECK-NEXT:                              }
+; CHECK-NEXT:                            }
+; CHECK-NEXT:                          }
+; CHECK-NEXT:                      }
+; CHECK-NEXT:                    if (96 * c2 + 3 >= ni || (2048 * c0 + 2047 >= nj && nj % 8 >= 1)) {
+; CHECK-NEXT:                      if (96 * c2 + 3 >= ni) {
+; CHECK-NEXT:                        for (int c3 = 0; c3 <= min(255, -256 * c0 + (nj - 1) / 8); c3 += 1)
+; CHECK-NEXT:                          for (int c5 = 0; c5 <= min(255, nk - 256 * c1 - 1); c5 += 1) {
+; CHECK-NEXT:                            // Loop Vectorizer Disabled
+; CHECK-NEXT:                            // Register tiling - Points
+; CHECK-NEXT:                            {
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2, 2048 * c0 + 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                              if (nj >= 2048 * c0 + 8 * c3 + 2) {
+; CHECK-NEXT:                                Stmt_for_body6(96 * c2, 2048 * c0 + 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                                if (nj >= 2048 * c0 + 8 * c3 + 3) {
+; CHECK-NEXT:                                  Stmt_for_body6(96 * c2, 2048 * c0 + 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                                  if (nj >= 2048 * c0 + 8 * c3 + 4) {
+; CHECK-NEXT:                                    Stmt_for_body6(96 * c2, 2048 * c0 + 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                                    if (nj >= 2048 * c0 + 8 * c3 + 5) {
+; CHECK-NEXT:                                      Stmt_for_body6(96 * c2, 2048 * c0 + 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                                      if (nj >= 2048 * c0 + 8 * c3 + 6) {
+; CHECK-NEXT:                                        Stmt_for_body6(96 * c2, 2048 * c0 + 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                                        if (nj >= 2048 * c0 + 8 * c3 + 7) {
+; CHECK-NEXT:                                          Stmt_for_body6(96 * c2, 2048 * c0 + 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                                          if (nj >= 2048 * c0 + 8 * c3 + 8)
+; CHECK-NEXT:                                            Stmt_for_body6(96 * c2, 2048 * c0 + 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                                        }
+; CHECK-NEXT:                                      }
+; CHECK-NEXT:                                    }
+; CHECK-NEXT:                                  }
+; CHECK-NEXT:                                }
+; CHECK-NEXT:                              }
+; CHECK-NEXT:                              if (ni >= 96 * c2 + 2) {
+; CHECK-NEXT:                                Stmt_for_body6(96 * c2 + 1, 2048 * c0 + 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                                if (nj >= 2048 * c0 + 8 * c3 + 2) {
+; CHECK-NEXT:                                  Stmt_for_body6(96 * c2 + 1, 2048 * c0 + 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                                  if (nj >= 2048 * c0 + 8 * c3 + 3) {
+; CHECK-NEXT:                                    Stmt_for_body6(96 * c2 + 1, 2048 * c0 + 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                                    if (nj >= 2048 * c0 + 8 * c3 + 4) {
+; CHECK-NEXT:                                      Stmt_for_body6(96 * c2 + 1, 2048 * c0 + 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                                      if (nj >= 2048 * c0 + 8 * c3 + 5) {
+; CHECK-NEXT:                                        Stmt_for_body6(96 * c2 + 1, 2048 * c0 + 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                                        if (nj >= 2048 * c0 + 8 * c3 + 6) {
+; CHECK-NEXT:                                          Stmt_for_body6(96 * c2 + 1, 2048 * c0 + 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                                          if (nj >= 2048 * c0 + 8 * c3 + 7) {
+; CHECK-NEXT:                                            Stmt_for_body6(96 * c2 + 1, 2048 * c0 + 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                                            if (nj >= 2048 * c0 + 8 * c3 + 8)
+; CHECK-NEXT:                                              Stmt_for_body6(96 * c2 + 1, 2048 * c0 + 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                                          }
+; CHECK-NEXT:                                        }
+; CHECK-NEXT:                                      }
+; CHECK-NEXT:                                    }
+; CHECK-NEXT:                                  }
+; CHECK-NEXT:                                }
+; CHECK-NEXT:                                if (96 * c2 + 3 == ni) {
+; CHECK-NEXT:                                  Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                                  if (nj >= 2048 * c0 + 8 * c3 + 2) {
+; CHECK-NEXT:                                    Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                                    if (nj >= 2048 * c0 + 8 * c3 + 3) {
+; CHECK-NEXT:                                      Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                                      if (nj >= 2048 * c0 + 8 * c3 + 4) {
+; CHECK-NEXT:                                        Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                                        if (nj >= 2048 * c0 + 8 * c3 + 5) {
+; CHECK-NEXT:                                          Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                                          if (nj >= 2048 * c0 + 8 * c3 + 6) {
+; CHECK-NEXT:                                            Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                                            if (nj >= 2048 * c0 + 8 * c3 + 7) {
+; CHECK-NEXT:                                              Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                                              if (nj >= 2048 * c0 + 8 * c3 + 8)
+; CHECK-NEXT:                                                Stmt_for_body6(ni - 1, 2048 * c0 + 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                                            }
+; CHECK-NEXT:                                          }
+; CHECK-NEXT:                                        }
+; CHECK-NEXT:                                      }
+; CHECK-NEXT:                                    }
+; CHECK-NEXT:                                  }
+; CHECK-NEXT:                                }
+; CHECK-NEXT:                              }
+; CHECK-NEXT:                            }
+; CHECK-NEXT:                          }
+; CHECK-NEXT:                      } else {
+; CHECK-NEXT:                        for (int c4 = 0; c4 <= min(23, -24 * c2 + (ni - 1) / 4); c4 += 1)
+; CHECK-NEXT:                          for (int c5 = 0; c5 <= min(255, nk - 256 * c1 - 1); c5 += 1) {
+; CHECK-NEXT:                            // Loop Vectorizer Disabled
+; CHECK-NEXT:                            // Register tiling - Points
+; CHECK-NEXT:                            {
+; CHECK-NEXT:                              Stmt_for_body6(96 * c2 + 4 * c4, -(nj % 8) + nj, 256 * c1 + c5);
+; CHECK-NEXT:                              if (nj % 8 >= 2) {
+; CHECK-NEXT:                                Stmt_for_body6(96 * c2 + 4 * c4, -(nj % 8) + nj + 1, 256 * c1 + c5);
+; CHECK-NEXT:                                if (nj % 8 >= 3) {
+; CHECK-NEXT:                                  Stmt_for_body6(96 * c2 + 4 * c4, -(nj % 8) + nj + 2, 256 * c1 + c5);
+; CHECK-NEXT:                                  if (nj % 8 >= 4) {
+; CHECK-NEXT:                                    Stmt_for_body6(96 * c2 + 4 * c4, -(nj % 8) + nj + 3, 256 * c1 + c5);
+; CHECK-NEXT:                                    if (nj % 8 >= 5) {
+; CHECK-NEXT:                                      Stmt_for_body6(96 * c2 + 4 * c4, -(nj % 8) + nj + 4, 256 * c1 + c5);
+; CHECK-NEXT:                                      if (nj % 8 >= 6) {
+; CHECK-NEXT:                                        Stmt_for_body6(96 * c2 + 4 * c4, -(nj % 8) + nj + 5, 256 * c1 + c5);
+; CHECK-NEXT:                                        if ((nj + 1) % 8 == 0)
+; CHECK-NEXT:                                          Stmt_for_body6(96 * c2 + 4 * c4, nj - 1, 256 * c1 + c5);
+; CHECK-NEXT:                                      }
+; CHECK-NEXT:                                    }
+; CHECK-NEXT:                                  }
+; CHECK-NEXT:                                }
+; CHECK-NEXT:                              }
+; CHECK-NEXT:                              if (ni >= 96 * c2 + 4 * c4 + 2) {
+; CHECK-NEXT:                                Stmt_for_body6(96 * c2 + 4 * c4 + 1, -(nj % 8) + nj, 256 * c1 + c5);
+; CHECK-NEXT:                                if (nj % 8 >= 2) {
+; CHECK-NEXT:                                  Stmt_for_body6(96 * c2 + 4 * c4 + 1, -(nj % 8) + nj + 1, 256 * c1 + c5);
+; CHECK-NEXT:                                  if (nj % 8 >= 3) {
+; CHECK-NEXT:                                    Stmt_for_body6(96 * c2 + 4 * c4 + 1, -(nj % 8) + nj + 2, 256 * c1 + c5);
+; CHECK-NEXT:                                    if (nj % 8 >= 4) {
+; CHECK-NEXT:                                      Stmt_for_body6(96 * c2 + 4 * c4 + 1, -(nj % 8) + nj + 3, 256 * c1 + c5);
+; CHECK-NEXT:                                      if (nj % 8 >= 5) {
+; CHECK-NEXT:                                        Stmt_for_body6(96 * c2 + 4 * c4 + 1, -(nj % 8) + nj + 4, 256 * c1 + c5);
+; CHECK-NEXT:                                        if (nj % 8 >= 6) {
+; CHECK-NEXT:                                          Stmt_for_body6(96 * c2 + 4 * c4 + 1, -(nj % 8) + nj + 5, 256 * c1 + c5);
+; CHECK-NEXT:                                          if ((nj + 1) % 8 == 0)
+; CHECK-NEXT:                                            Stmt_for_body6(96 * c2 + 4 * c4 + 1, nj - 1, 256 * c1 + c5);
+; CHECK-NEXT:                                        }
+; CHECK-NEXT:                                      }
+; CHECK-NEXT:                                    }
+; CHECK-NEXT:                                  }
+; CHECK-NEXT:                                }
+; CHECK-NEXT:                                if (ni >= 96 * c2 + 4 * c4 + 3) {
+; CHECK-NEXT:                                  Stmt_for_body6(96 * c2 + 4 * c4 + 2, -(nj % 8) + nj, 256 * c1 + c5);
+; CHECK-NEXT:                                  if (nj % 8 >= 2) {
+; CHECK-NEXT:                                    Stmt_for_body6(96 * c2 + 4 * c4 + 2, -(nj % 8) + nj + 1, 256 * c1 + c5);
+; CHECK-NEXT:                                    if (nj % 8 >= 3) {
+; CHECK-NEXT:                                      Stmt_for_body6(96 * c2 + 4 * c4 + 2, -(nj % 8) + nj + 2, 256 * c1 + c5);
+; CHECK-NEXT:                                      if (nj % 8 >= 4) {
+; CHECK-NEXT:                                        Stmt_for_body6(96 * c2 + 4 * c4 + 2, -(nj % 8) + nj + 3, 256 * c1 + c5);
+; CHECK-NEXT:                                        if (nj % 8 >= 5) {
+; CHECK-NEXT:                                          Stmt_for_body6(96 * c2 + 4 * c4 + 2, -(nj % 8) + nj + 4, 256 * c1 + c5);
+; CHECK-NEXT:                                          if (nj % 8 >= 6) {
+; CHECK-NEXT:                                            Stmt_for_body6(96 * c2 + 4 * c4 + 2, -(nj % 8) + nj + 5, 256 * c1 + c5);
+; CHECK-NEXT:                                            if ((nj + 1) % 8 == 0)
+; CHECK-NEXT:                                              Stmt_for_body6(96 * c2 + 4 * c4 + 2, nj - 1, 256 * c1 + c5);
+; CHECK-NEXT:                                          }
+; CHECK-NEXT:                                        }
+; CHECK-NEXT:                                      }
+; CHECK-NEXT:                                    }
+; CHECK-NEXT:                                  }
+; CHECK-NEXT:                                  if (ni >= 96 * c2 + 4 * c4 + 4) {
+; CHECK-NEXT:                                    Stmt_for_body6(96 * c2 + 4 * c4 + 3, -(nj % 8) + nj, 256 * c1 + c5);
+; CHECK-NEXT:                                    if (nj % 8 >= 2) {
+; CHECK-NEXT:                                      Stmt_for_body6(96 * c2 + 4 * c4 + 3, -(nj % 8) + nj + 1, 256 * c1 + c5);
+; CHECK-NEXT:                                      if (nj % 8 >= 3) {
+; CHECK-NEXT:                                        Stmt_for_body6(96 * c2 + 4 * c4 + 3, -(nj % 8) + nj + 2, 256 * c1 + c5);
+; CHECK-NEXT:                                        if (nj % 8 >= 4) {
+; CHECK-NEXT:                                          Stmt_for_body6(96 * c2 + 4 * c4 + 3, -(nj % 8) + nj + 3, 256 * c1 + c5);
+; CHECK-NEXT:                                          if (nj % 8 >= 5) {
+; CHECK-NEXT:                                            Stmt_for_body6(96 * c2 + 4 * c4 + 3, -(nj % 8) + nj + 4, 256 * c1 + c5);
+; CHECK-NEXT:                                            if (nj % 8 >= 6) {
+; CHECK-NEXT:                                              Stmt_for_body6(96 * c2 + 4 * c4 + 3, -(nj % 8) + nj + 5, 256 * c1 + c5);
+; CHECK-NEXT:                                              if ((nj + 1) % 8 == 0)
+; CHECK-NEXT:                                                Stmt_for_body6(96 * c2 + 4 * c4 + 3, nj - 1, 256 * c1 + c5);
+; CHECK-NEXT:                                            }
+; CHECK-NEXT:                                          }
+; CHECK-NEXT:                                        }
+; CHECK-NEXT:                                      }
+; CHECK-NEXT:                                    }
+; CHECK-NEXT:                                  }
+; CHECK-NEXT:                                }
+; CHECK-NEXT:                              }
+; CHECK-NEXT:                            }
+; CHECK-NEXT:                          }
+; CHECK-NEXT:                      }
+; CHECK-NEXT:                    }
+; CHECK-NEXT:                  }
+; CHECK-NEXT:                }
+; CHECK-NEXT:              }
+; CHECK-NEXT:          }
+;
+
+; AUTO-VECTORIZATION:  fmul <4 x double>
+; AUTO-VECTORIZATION:  fadd <4 x double>
+
+; AUTO-VECTORIZATION: 36 SLP              - Number of vector instructions generated
+; AUTO-VECTORIZATION:  453 licm             - Number of instructions hoisted out of loop
+; AUTO-VECTORIZATION:    2 licm             - Number of load insts hoisted or sunk
+; AUTO-VECTORIZATION:   32 licm             - Number of memory locations promoted to registers
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+define internal void @kernel_gemm(i32 %ni, i32 %nj, i32 %nk, double %alpha, double %beta, [1024 x double]* %C, [1024 x double]* %A, [1024 x double]* %B) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %cmp39 = icmp sgt i32 %ni, 0
+  br i1 %cmp39, label %for.cond1.preheader.lr.ph, label %for.end22
+
+for.cond1.preheader.lr.ph:                        ; preds = %entry.split
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.inc20, %for.cond1.preheader.lr.ph
+  %indvars.iv45 = phi i64 [ 0, %for.cond1.preheader.lr.ph ], [ %indvars.iv.next46, %for.inc20 ]
+  %cmp237 = icmp sgt i32 %nj, 0
+  br i1 %cmp237, label %for.cond4.preheader.lr.ph, label %for.inc20
+
+for.cond4.preheader.lr.ph:                        ; preds = %for.cond1.preheader
+  br label %for.cond4.preheader
+
+for.cond4.preheader:                              ; preds = %for.inc17, %for.cond4.preheader.lr.ph
+  %indvars.iv41 = phi i64 [ 0, %for.cond4.preheader.lr.ph ], [ %indvars.iv.next42, %for.inc17 ]
+  %cmp535 = icmp sgt i32 %nk, 0
+  br i1 %cmp535, label %for.body6.lr.ph, label %for.inc17
+
+for.body6.lr.ph:                                  ; preds = %for.cond4.preheader
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.body6.lr.ph
+  %indvars.iv = phi i64 [ 0, %for.body6.lr.ph ], [ %indvars.iv.next, %for.body6 ]
+  %arrayidx8 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 %indvars.iv45, i64 %indvars.iv
+  %tmp = load double, double* %arrayidx8, align 8
+  %arrayidx12 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %indvars.iv, i64 %indvars.iv41
+  %tmp1 = load double, double* %arrayidx12, align 8
+  %mul = fmul double %tmp, %tmp1
+  %arrayidx16 = getelementptr inbounds [1024 x double], [1024 x double]* %C, i64 %indvars.iv45, i64 %indvars.iv41
+  %tmp2 = load double, double* %arrayidx16, align 8
+  %add = fadd double %tmp2, %mul
+  store double %add, double* %arrayidx16, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %wide.trip.count = zext i32 %nk to i64
+  %exitcond = icmp ne i64 %indvars.iv.next, %wide.trip.count
+  br i1 %exitcond, label %for.body6, label %for.cond4.for.inc17_crit_edge
+
+for.cond4.for.inc17_crit_edge:                    ; preds = %for.body6
+  br label %for.inc17
+
+for.inc17:                                        ; preds = %for.cond4.for.inc17_crit_edge, %for.cond4.preheader
+  %indvars.iv.next42 = add nuw nsw i64 %indvars.iv41, 1
+  %wide.trip.count43 = zext i32 %nj to i64
+  %exitcond44 = icmp ne i64 %indvars.iv.next42, %wide.trip.count43
+  br i1 %exitcond44, label %for.cond4.preheader, label %for.cond1.for.inc20_crit_edge
+
+for.cond1.for.inc20_crit_edge:                    ; preds = %for.inc17
+  br label %for.inc20
+
+for.inc20:                                        ; preds = %for.cond1.for.inc20_crit_edge, %for.cond1.preheader
+  %indvars.iv.next46 = add nuw nsw i64 %indvars.iv45, 1
+  %wide.trip.count47 = zext i32 %ni to i64
+  %exitcond48 = icmp ne i64 %indvars.iv.next46, %wide.trip.count47
+  br i1 %exitcond48, label %for.cond1.preheader, label %for.cond.for.end22_crit_edge
+
+for.cond.for.end22_crit_edge:                     ; preds = %for.inc20
+  br label %for.end22
+
+for.end22:                                        ; preds = %for.cond.for.end22_crit_edge, %entry.split
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+aes,+avx,+cmov,+cx16,+fxsr,+mmx,+pclmul,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" }
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_6.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_6.ll
new file mode 100644
index 0000000..c098bb1
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_6.ll
@@ -0,0 +1,175 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -analyze -polly-ast -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: -polly-target-2nd-cache-level-size=262144 < %s \
+; RUN: | FileCheck %s
+;
+;  opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+;  -polly-target-throughput-vector-fma=1 \
+;  -polly-target-latency-vector-fma=8 \
+;  -polly-codegen -polly-target-1st-cache-level-associativity=8 \
+;  -polly-target-2nd-cache-level-associativity=8 \
+;  -polly-target-1st-cache-level-size=32768 \
+;  -polly-target-vector-register-bitwidth=256 \
+;  -polly-target-2nd-cache-level-size=262144 -gvn -licm -slp-vectorizer \
+;  -mcpu=corei7 -stats -S < %s 2>&1 | FileCheck %s \
+; --check-prefix=AUTO-VECTORIZATION
+;
+;
+;    /* We isolate a set of partial tile prefixes, which contains only partial
+;       tile prefixes that have exactly Mr x Nr iterations of the two innermost
+;       loops produced by the optimization of the matrix multiplication. Mr and
+;       Nr are parameters of the micro-kernel (see getMicroKernelParams and
+;       getMacroKernelParams from lib/Transform/ScheduleOptimizer.cpp for
+;       details). This test check that in case it cannot be proved that
+;       the number of loop iterations can be evenly divided by tile sizes
+;       and we tile and unroll the point loops, it helps to get rid of
+;       the conditional expressions of the unrolled innermost loops, which
+;       prevents stores and loads of the unrolled loops from being sunk
+;       and hoisted. Otherwise, it causes a run-time regression in comparison
+;       to the vectorized code with sunk and hoisted memory accesses. */
+;    /* C := A * B + C */
+;    for (i = 0; i < 1020; i++)
+;      for (j = 0; j < 1020; j++)
+;	 for (k = 0; k < 1020; ++k)
+;	   C[i][j] += A[i][k] * B[k][j];
+;
+; CHECK:    // 1st level tiling - Tiles
+; CHECK-NEXT:    for (int c1 = 0; c1 <= 3; c1 += 1) {
+; CHECK-NEXT:      for (int c3 = 0; c3 <= 1019; c3 += 1)
+; CHECK-NEXT:        for (int c4 = 256 * c1; c4 <= min(1019, 256 * c1 + 255); c4 += 1)
+; CHECK-NEXT:          CopyStmt_0(0, c3, c4);
+; CHECK-NEXT:      for (int c2 = 0; c2 <= 10; c2 += 1) {
+; CHECK-NEXT:        for (int c3 = 96 * c2; c3 <= min(1019, 96 * c2 + 95); c3 += 1)
+; CHECK-NEXT:          for (int c5 = 256 * c1; c5 <= min(1019, 256 * c1 + 255); c5 += 1)
+; CHECK-NEXT:            CopyStmt_1(c3, 0, c5);
+; CHECK-NEXT:        // 1st level tiling - Points
+; CHECK-NEXT:        // Register tiling - Tiles
+; CHECK-NEXT:        {
+; CHECK-NEXT:          for (int c3 = 0; c3 <= 126; c3 += 1)
+; CHECK-NEXT:            for (int c4 = 0; c4 <= min(23, -24 * c2 + 254); c4 += 1)
+; CHECK-NEXT:              for (int c5 = 0; c5 <= min(255, -256 * c1 + 1019); c5 += 1) {
+; CHECK-NEXT:                // Loop Vectorizer Disabled
+; CHECK-NEXT:                // Register tiling - Points
+; CHECK-NEXT:                {
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                  Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                }
+; CHECK-NEXT:              }
+; CHECK-NEXT:              for (int c4 = 0; c4 <= min(23, -24 * c2 + 254); c4 += 1)
+; CHECK-NEXT:                for (int c5 = 0; c5 <= min(255, -256 * c1 + 1019); c5 += 1) {
+; CHECK-NEXT:                  // Loop Vectorizer Disabled
+; CHECK-NEXT:                  // Register tiling - Points
+; CHECK-NEXT:                  {
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4, 1016, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4, 1017, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4, 1018, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4, 1019, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4 + 1, 1016, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4 + 1, 1017, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4 + 1, 1018, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4 + 1, 1019, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4 + 2, 1016, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4 + 2, 1017, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4 + 2, 1018, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4 + 2, 1019, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4 + 3, 1016, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4 + 3, 1017, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4 + 3, 1018, 256 * c1 + c5);
+; CHECK-NEXT:                    Stmt_for_body6(96 * c2 + 4 * c4 + 3, 1019, 256 * c1 + c5);
+; CHECK-NEXT:                  }
+; CHECK-NEXT:                }
+; CHECK-NEXT:            }
+; CHECK-NEXT:          }
+; CHECK-NEXT:        }
+;
+; AUTO-VECTORIZATION:  fmul <4 x double>
+; AUTO-VECTORIZATION:  fadd <4 x double>
+
+; AUTO-VECTORIZATION: 36 SLP              - Number of vector instructions generated
+; AUTO-VECTORIZATION: 146 licm             - Number of instructions hoisted out of loop
+; AUTO-VECTORIZATION: 1 licm             - Number of load insts hoisted or sunk
+; AUTO-VECTORIZATION: 32 licm             - Number of memory locations promoted to registers
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+define internal void @kernel_gemm(i32 %ni, i32 %nj, i32 %nk, double %alpha, double %beta, [1020 x double]* %C, [1020 x double]* %A, [1020 x double]* %B) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.inc20, %entry.split
+  %indvars.iv41 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next42, %for.inc20 ]
+  br label %for.cond4.preheader
+
+for.cond4.preheader:                              ; preds = %for.inc17, %for.cond1.preheader
+  %indvars.iv38 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next39, %for.inc17 ]
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.cond4.preheader
+  %indvars.iv = phi i64 [ 0, %for.cond4.preheader ], [ %indvars.iv.next, %for.body6 ]
+  %arrayidx8 = getelementptr inbounds [1020 x double], [1020 x double]* %A, i64 %indvars.iv41, i64 %indvars.iv
+  %tmp = load double, double* %arrayidx8, align 8
+  %arrayidx12 = getelementptr inbounds [1020 x double], [1020 x double]* %B, i64 %indvars.iv, i64 %indvars.iv38
+  %tmp1 = load double, double* %arrayidx12, align 8
+  %mul = fmul double %tmp, %tmp1
+  %arrayidx16 = getelementptr inbounds [1020 x double], [1020 x double]* %C, i64 %indvars.iv41, i64 %indvars.iv38
+  %tmp2 = load double, double* %arrayidx16, align 8
+  %add = fadd double %tmp2, %mul
+  store double %add, double* %arrayidx16, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1020
+  br i1 %exitcond, label %for.body6, label %for.inc17
+
+for.inc17:                                        ; preds = %for.body6
+  %indvars.iv.next39 = add nuw nsw i64 %indvars.iv38, 1
+  %exitcond40 = icmp ne i64 %indvars.iv.next39, 1020
+  br i1 %exitcond40, label %for.cond4.preheader, label %for.inc20
+
+for.inc20:                                        ; preds = %for.inc17
+  %indvars.iv.next42 = add nuw nsw i64 %indvars.iv41, 1
+  %exitcond43 = icmp ne i64 %indvars.iv.next42, 1020
+  br i1 %exitcond43, label %for.cond1.preheader, label %for.end22
+
+for.end22:                                        ; preds = %for.inc20
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+aes,+avx,+cmov,+cx16,+fxsr,+mmx,+pclmul,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" }
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_7.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_7.ll
new file mode 100644
index 0000000..8eb090c
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_7.ll
@@ -0,0 +1,157 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -analyze -polly-ast -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: -polly-target-2nd-cache-level-size=262144 < %s \
+; RUN: | FileCheck %s
+;
+;    /* C := A * B + C */
+;    /* Elements of the matrices A, B, C have the float type. */
+;    /* The type size of elements of the matrix multiplication operands is used
+;       to determine the parameters of the code produced by the optimization
+;       of the matrix multiplication (e.g. bounds of the loops of the loop
+;       nest, the innermost loop body). This test checks the form of
+;       the generated loop nest. See getMicroKernelParams and
+;       getMacroKernelParams from lib/Transform/ScheduleOptimizer.cpp
+;       for details. */
+;    for (i = 0; i < _PB_NI; i++)
+;      for (j = 0; j < _PB_NJ; j++)
+;	 for (k = 0; k < _PB_NK; ++k)
+;	   C[i][j] += A[i][k] * B[k][j];
+;
+; CHECK:    // 1st level tiling - Tiles
+; CHECK-NEXT:    for (int c1 = 0; c1 <= 2; c1 += 1) {
+; CHECK-NEXT:      for (int c3 = 0; c3 <= 1023; c3 += 1)
+; CHECK-NEXT:        for (int c4 = 384 * c1; c4 <= min(1023, 384 * c1 + 383); c4 += 1)
+; CHECK-NEXT:          CopyStmt_0(0, c3, c4);
+; CHECK-NEXT:      for (int c2 = 0; c2 <= 7; c2 += 1) {
+; CHECK-NEXT:        for (int c3 = 128 * c2; c3 <= 128 * c2 + 127; c3 += 1)
+; CHECK-NEXT:          for (int c5 = 384 * c1; c5 <= min(1023, 384 * c1 + 383); c5 += 1)
+; CHECK-NEXT:            CopyStmt_1(c3, 0, c5);
+; CHECK-NEXT:        // 1st level tiling - Points
+; CHECK-NEXT:        // Register tiling - Tiles
+; CHECK-NEXT:        for (int c3 = 0; c3 <= 127; c3 += 1)
+; CHECK-NEXT:          for (int c4 = 0; c4 <= 15; c4 += 1)
+; CHECK-NEXT:            for (int c5 = 0; c5 <= min(383, -384 * c1 + 1023); c5 += 1) {
+; CHECK-NEXT:              // Loop Vectorizer Disabled
+; CHECK-NEXT:              // Register tiling - Points
+; CHECK-NEXT:              {
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4, 8 * c3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4, 8 * c3 + 1, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4, 8 * c3 + 2, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4, 8 * c3 + 3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4, 8 * c3 + 4, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4, 8 * c3 + 5, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4, 8 * c3 + 6, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4, 8 * c3 + 7, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 1, 8 * c3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 1, 8 * c3 + 1, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 1, 8 * c3 + 2, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 1, 8 * c3 + 3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 1, 8 * c3 + 4, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 1, 8 * c3 + 5, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 1, 8 * c3 + 6, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 1, 8 * c3 + 7, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 2, 8 * c3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 2, 8 * c3 + 1, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 2, 8 * c3 + 2, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 2, 8 * c3 + 3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 2, 8 * c3 + 4, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 2, 8 * c3 + 5, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 2, 8 * c3 + 6, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 2, 8 * c3 + 7, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 3, 8 * c3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 3, 8 * c3 + 1, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 3, 8 * c3 + 2, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 3, 8 * c3 + 3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 3, 8 * c3 + 4, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 3, 8 * c3 + 5, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 3, 8 * c3 + 6, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 3, 8 * c3 + 7, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 4, 8 * c3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 4, 8 * c3 + 1, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 4, 8 * c3 + 2, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 4, 8 * c3 + 3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 4, 8 * c3 + 4, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 4, 8 * c3 + 5, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 4, 8 * c3 + 6, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 4, 8 * c3 + 7, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 5, 8 * c3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 5, 8 * c3 + 1, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 5, 8 * c3 + 2, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 5, 8 * c3 + 3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 5, 8 * c3 + 4, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 5, 8 * c3 + 5, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 5, 8 * c3 + 6, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 5, 8 * c3 + 7, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 6, 8 * c3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 6, 8 * c3 + 1, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 6, 8 * c3 + 2, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 6, 8 * c3 + 3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 6, 8 * c3 + 4, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 6, 8 * c3 + 5, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 6, 8 * c3 + 6, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 6, 8 * c3 + 7, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 7, 8 * c3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 7, 8 * c3 + 1, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 7, 8 * c3 + 2, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 7, 8 * c3 + 3, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 7, 8 * c3 + 4, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 7, 8 * c3 + 5, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 7, 8 * c3 + 6, 384 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(128 * c2 + 8 * c4 + 7, 8 * c3 + 7, 384 * c1 + c5);
+; CHECK-NEXT:              }
+; CHECK-NEXT:            }
+; CHECK-NEXT:      }
+; CHECK-NEXT:    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+; Function Attrs: noinline nounwind uwtable
+define internal void @kernel_gemm(i32 %ni, i32 %nj, i32 %nk, float %alpha, float %beta, [1024 x float]* %C, [1024 x float]* %A, [1024 x float]* %B) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.inc20, %entry.split
+  %indvars.iv41 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next42, %for.inc20 ]
+  br label %for.cond4.preheader
+
+for.cond4.preheader:                              ; preds = %for.inc17, %for.cond1.preheader
+  %indvars.iv38 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next39, %for.inc17 ]
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.cond4.preheader
+  %indvars.iv = phi i64 [ 0, %for.cond4.preheader ], [ %indvars.iv.next, %for.body6 ]
+  %arrayidx8 = getelementptr inbounds [1024 x float], [1024 x float]* %A, i64 %indvars.iv41, i64 %indvars.iv
+  %tmp = load float, float* %arrayidx8, align 4
+  %arrayidx12 = getelementptr inbounds [1024 x float], [1024 x float]* %B, i64 %indvars.iv, i64 %indvars.iv38
+  %tmp1 = load float, float* %arrayidx12, align 4
+  %mul = fmul float %tmp, %tmp1
+  %arrayidx16 = getelementptr inbounds [1024 x float], [1024 x float]* %C, i64 %indvars.iv41, i64 %indvars.iv38
+  %tmp2 = load float, float* %arrayidx16, align 4
+  %add = fadd float %tmp2, %mul
+  store float %add, float* %arrayidx16, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1024
+  br i1 %exitcond, label %for.body6, label %for.inc17
+
+for.inc17:                                        ; preds = %for.body6
+  %indvars.iv.next39 = add nuw nsw i64 %indvars.iv38, 1
+  %exitcond40 = icmp ne i64 %indvars.iv.next39, 1024
+  br i1 %exitcond40, label %for.cond4.preheader, label %for.inc20
+
+for.inc20:                                        ; preds = %for.inc17
+  %indvars.iv.next42 = add nuw nsw i64 %indvars.iv41, 1
+  %exitcond43 = icmp ne i64 %indvars.iv.next42, 1024
+  br i1 %exitcond43, label %for.cond1.preheader, label %for.end22
+
+for.end22:                                        ; preds = %for.inc20
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_8.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_8.ll
new file mode 100644
index 0000000..7515658
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_8.ll
@@ -0,0 +1,127 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -analyze -polly-ast -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: -polly-target-2nd-cache-level-size=262144 < %s \
+; RUN: | FileCheck %s
+;
+;    /* C := A * B + C */
+;    /* Elements of the matrices B, C have the double type. */
+;    /* Elements of the matrix A have the float type. */
+;    /* The type size of elements of the matrix multiplication operands is used
+;       to determine the parameters of the code produced by the optimization
+;       of the matrix multiplication (e.g. bounds of the loops of the loop
+;       nest, the innermost loop body). This test checks the form of
+;       the generated loop nest. See getMicroKernelParams and
+;       getMacroKernelParams from lib/Transform/ScheduleOptimizer.cpp
+;       for details. */
+;    for (i = 0; i < _PB_NI; i++)
+;      for (j = 0; j < _PB_NJ; j++)
+;	 for (k = 0; k < _PB_NK; ++k)
+;	   C[i][j] += A[i][k] * B[k][j];
+;
+; CHECK:    // 1st level tiling - Tiles
+; CHECK-NEXT:    for (int c1 = 0; c1 <= 3; c1 += 1) {
+; CHECK-NEXT:      for (int c3 = 0; c3 <= 1023; c3 += 1)
+; CHECK-NEXT:        for (int c4 = 256 * c1; c4 <= 256 * c1 + 255; c4 += 1)
+; CHECK-NEXT:          CopyStmt_0(0, c3, c4);
+; CHECK-NEXT:      for (int c2 = 0; c2 <= 10; c2 += 1) {
+; CHECK-NEXT:        for (int c3 = 96 * c2; c3 <= min(1023, 96 * c2 + 95); c3 += 1)
+; CHECK-NEXT:          for (int c5 = 256 * c1; c5 <= 256 * c1 + 255; c5 += 1)
+; CHECK-NEXT:            CopyStmt_1(c3, 0, c5);
+; CHECK-NEXT:        // 1st level tiling - Points
+; CHECK-NEXT:        // Register tiling - Tiles
+; CHECK-NEXT:        for (int c3 = 0; c3 <= 127; c3 += 1)
+; CHECK-NEXT:          for (int c4 = 0; c4 <= min(23, -24 * c2 + 255); c4 += 1)
+; CHECK-NEXT:            for (int c5 = 0; c5 <= 255; c5 += 1) {
+; CHECK-NEXT:              // Loop Vectorizer Disabled
+; CHECK-NEXT:              // Register tiling - Points
+; CHECK-NEXT:              {
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4, 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 1, 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 2, 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 1, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 2, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 3, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 4, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 5, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 6, 256 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(96 * c2 + 4 * c4 + 3, 8 * c3 + 7, 256 * c1 + c5);
+; CHECK-NEXT:              }
+; CHECK-NEXT:            }
+; CHECK-NEXT:      }
+; CHECK-NEXT:    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+; Function Attrs: noinline nounwind uwtable
+define internal void @kernel_gemm(i32 %ni, i32 %nj, i32 %nk, double %alpha, double %beta, [1024 x double]* %C, [1024 x float]* %A, [1024 x double]* %B) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.inc20, %entry.split
+  %indvars.iv41 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next42, %for.inc20 ]
+  br label %for.cond4.preheader
+
+for.cond4.preheader:                              ; preds = %for.inc17, %for.cond1.preheader
+  %indvars.iv38 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next39, %for.inc17 ]
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.cond4.preheader
+  %indvars.iv = phi i64 [ 0, %for.cond4.preheader ], [ %indvars.iv.next, %for.body6 ]
+  %arrayidx8 = getelementptr inbounds [1024 x float], [1024 x float]* %A, i64 %indvars.iv41, i64 %indvars.iv
+  %tmp = load float, float* %arrayidx8, align 4
+  %conv = fpext float %tmp to double
+  %arrayidx12 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %indvars.iv, i64 %indvars.iv38
+  %tmp1 = load double, double* %arrayidx12, align 8
+  %mul = fmul double %conv, %tmp1
+  %arrayidx16 = getelementptr inbounds [1024 x double], [1024 x double]* %C, i64 %indvars.iv41, i64 %indvars.iv38
+  %tmp2 = load double, double* %arrayidx16, align 8
+  %add = fadd double %tmp2, %mul
+  store double %add, double* %arrayidx16, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1024
+  br i1 %exitcond, label %for.body6, label %for.inc17
+
+for.inc17:                                        ; preds = %for.body6
+  %indvars.iv.next39 = add nuw nsw i64 %indvars.iv38, 1
+  %exitcond40 = icmp ne i64 %indvars.iv.next39, 1024
+  br i1 %exitcond40, label %for.cond4.preheader, label %for.inc20
+
+for.inc20:                                        ; preds = %for.inc17
+  %indvars.iv.next42 = add nuw nsw i64 %indvars.iv41, 1
+  %exitcond43 = icmp ne i64 %indvars.iv.next42, 1024
+  br i1 %exitcond43, label %for.cond1.preheader, label %for.end22
+
+for.end22:                                        ; preds = %for.inc20
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/pattern-matching-based-opts_9.ll b/final/test/ScheduleOptimizer/pattern-matching-based-opts_9.ll
new file mode 100644
index 0000000..a34bf00
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern-matching-based-opts_9.ll
@@ -0,0 +1,366 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-pattern-matching-based-opts=true \
+; RUN: -polly-target-throughput-vector-fma=1 \
+; RUN: -polly-target-latency-vector-fma=8 \
+; RUN: -analyze -polly-ast -polly-target-1st-cache-level-associativity=8 \
+; RUN: -polly-target-2nd-cache-level-associativity=8 \
+; RUN: -polly-target-1st-cache-level-size=32768 \
+; RUN: -polly-target-vector-register-bitwidth=256 \
+; RUN: -polly-target-2nd-cache-level-size=262144 < %s \
+; RUN: | FileCheck %s
+;
+; RUN: opt %loadPolly -analyze -polly-dependences < %s | FileCheck %s \
+; RUN: --check-prefix=DEPENDENCES
+;
+;    /* C := A * B + C */
+;    /* Elements of the matrices A, B, C have the char type. */
+;    /* The type size of elements of the matrix multiplication operands is used
+;       to determine the parameters of the code produced by the optimization
+;       of the matrix multiplication (e.g. bounds of the loops of the loop
+;       nest, the innermost loop body). This test checks the form of
+;       the generated loop nest. See getMicroKernelParams and
+;       getMacroKernelParams from lib/Transform/ScheduleOptimizer.cpp
+;       for details.
+;
+;       This patch also checks that we can detect matrix multiplication
+;       in case there are reduction dependencies and there are not RAW
+;       dependencies. */
+;    for (i = 0; i < _PB_NI; i++)
+;      for (j = 0; j < _PB_NJ; j++)
+;   for (k = 0; k < _PB_NK; ++k)
+;     C[i][j] += A[i][k] * B[k][j];
+;
+; CHECK:    // 1st level tiling - Tiles
+; CHECK-NEXT:    for (int c1 = 0; c1 <= 1; c1 += 1) {
+; CHECK-NEXT:      for (int c3 = 0; c3 <= 1023; c3 += 1)
+; CHECK-NEXT:        for (int c4 = 512 * c1; c4 <= 512 * c1 + 511; c4 += 1)
+; CHECK-NEXT:          CopyStmt_0(0, c3, c4);
+; CHECK-NEXT:      for (int c2 = 0; c2 <= 2; c2 += 1) {
+; CHECK-NEXT:        for (int c3 = 384 * c2; c3 <= min(1023, 384 * c2 + 383); c3 += 1)
+; CHECK-NEXT:          for (int c5 = 512 * c1; c5 <= 512 * c1 + 511; c5 += 1)
+; CHECK-NEXT:            CopyStmt_1(c3, 0, c5);
+; CHECK-NEXT:        // 1st level tiling - Points
+; CHECK-NEXT:        // Register tiling - Tiles
+; CHECK-NEXT:        for (int c3 = 0; c3 <= 31; c3 += 1)
+; CHECK-NEXT:          for (int c4 = 0; c4 <= min(47, -48 * c2 + 127); c4 += 1)
+; CHECK-NEXT:            for (int c5 = 0; c5 <= 511; c5 += 1) {
+; CHECK-NEXT:              // Loop Vectorizer Disabled
+; CHECK-NEXT:              // Register tiling - Points
+; CHECK-NEXT:              {
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 1, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 2, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 3, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 4, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 5, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 6, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 1, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 2, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 3, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 4, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 5, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 6, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 7, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 8, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 9, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 10, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 11, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 12, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 13, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 14, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 15, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 16, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 17, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 18, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 19, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 20, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 21, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 22, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 23, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 24, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 25, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 26, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 27, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 28, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 29, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 30, 512 * c1 + c5);
+; CHECK-NEXT:                Stmt_for_body6(384 * c2 + 8 * c4 + 7, 32 * c3 + 31, 512 * c1 + c5);
+; CHECK-NEXT:              }
+; CHECK-NEXT:            }
+; CHECK-NEXT:      }
+; CHECK-NEXT:    }
+;
+; DEPENDENCES:  RAW dependences:
+; DEPENDENCES-NEXT:    {  }
+; DEPENDENCES-NEXT:  WAR dependences:
+; DEPENDENCES-NEXT:    {  }
+; DEPENDENCES-NEXT:  WAW dependences:
+; DEPENDENCES-NEXT:    {  }
+; DEPENDENCES-NEXT:  Reduction dependences:
+; DEPENDENCES-NEXT:    { Stmt_for_body6[i0, i1, i2] -> Stmt_for_body6[i0, i1, 1 + i2] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 and 0 <= i2 <= 1022 }
+; DEPENDENCES-NEXT:  Transitive closure of reduction dependences:
+; DEPENDENCES-NEXT:    { Stmt_for_body6[i0, i1, i2] -> Stmt_for_body6[i0, i1, o2] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 and ((i2 >= 0 and i2 < o2 <= 1023) or (i2 <= 1023 and 0 <= o2 < i2)) }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-unknown"
+
+define internal void @kernel_gemm(i32 %ni, i32 %nj, i32 %nk, i8 signext %alpha, i8 signext %beta, [1024 x i8]* %C, [1024 x i8]* %A, [1024 x i8]* %B) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.inc23, %entry.split
+  %indvars.iv45 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next46, %for.inc23 ]
+  br label %for.cond4.preheader
+
+for.cond4.preheader:                              ; preds = %for.inc20, %for.cond1.preheader
+  %indvars.iv42 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next43, %for.inc20 ]
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.cond4.preheader
+  %indvars.iv = phi i64 [ 0, %for.cond4.preheader ], [ %indvars.iv.next, %for.body6 ]
+  %arrayidx8 = getelementptr inbounds [1024 x i8], [1024 x i8]* %A, i64 %indvars.iv45, i64 %indvars.iv
+  %tmp = load i8, i8* %arrayidx8, align 1
+  %arrayidx12 = getelementptr inbounds [1024 x i8], [1024 x i8]* %B, i64 %indvars.iv, i64 %indvars.iv42
+  %tmp1 = load i8, i8* %arrayidx12, align 1
+  %mul = mul i8 %tmp1, %tmp
+  %arrayidx17 = getelementptr inbounds [1024 x i8], [1024 x i8]* %C, i64 %indvars.iv45, i64 %indvars.iv42
+  %tmp2 = load i8, i8* %arrayidx17, align 1
+  %add = add i8 %mul, %tmp2
+  store i8 %add, i8* %arrayidx17, align 1
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1024
+  br i1 %exitcond, label %for.body6, label %for.inc20
+
+for.inc20:                                        ; preds = %for.body6
+  %indvars.iv.next43 = add nuw nsw i64 %indvars.iv42, 1
+  %exitcond44 = icmp ne i64 %indvars.iv.next43, 1024
+  br i1 %exitcond44, label %for.cond4.preheader, label %for.inc23
+
+for.inc23:                                        ; preds = %for.inc20
+  %indvars.iv.next46 = add nuw nsw i64 %indvars.iv45, 1
+  %exitcond47 = icmp ne i64 %indvars.iv.next46, 1024
+  br i1 %exitcond47, label %for.cond1.preheader, label %for.end25
+
+for.end25:                                        ; preds = %for.inc23
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/pattern_matching_based_opts_splitmap.ll b/final/test/ScheduleOptimizer/pattern_matching_based_opts_splitmap.ll
new file mode 100644
index 0000000..6433e2c
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern_matching_based_opts_splitmap.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-opt-isl -debug-only=polly-opt-isl -disable-output < %s 2>&1 | FileCheck %s
+; REQUIRES: asserts
+;
+; void pattern_matching_based_opts_splitmap(double C[static const restrict 2][2], double A[static const restrict 2][784], double B[static const restrict 784][2]) {
+;  for (int i = 0; i < 2; i+=1)
+;    for (int j = 0; j < 2; j+=1)
+;      for (int k = 0; k < 784; k+=1)
+;        C[i][j] += A[i][k] * B[k][j];
+;}
+;
+; Check that the pattern matching detects the matrix multiplication pattern
+; when the AccMap cannot be reduced to a single disjunct.
+;
+; CHECK: The matrix multiplication pattern was detected
+;
+; ModuleID = 'pattern_matching_based_opts_splitmap.ll'
+;
+; Function Attrs: noinline nounwind uwtable
+define void @pattern_matching_based_opts_splitmap([2 x double]* noalias dereferenceable(32) %C, [784 x double]* noalias dereferenceable(12544) %A, [2 x double]* noalias dereferenceable(12544) %B) {
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %entry, %for.inc21
+  %i = phi i64 [ 0, %entry ], [ %add22, %for.inc21 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.body, %for.inc18
+  %j = phi i64 [ 0, %for.body ], [ %add19, %for.inc18 ]
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body3, %for.body6
+  %k = phi i64 [ 0, %for.body3 ], [ %add17, %for.body6 ]
+  %arrayidx8 = getelementptr inbounds [784 x double], [784 x double]* %A, i64 %i, i64 %k
+  %tmp6 = load double, double* %arrayidx8, align 8
+  %arrayidx12 = getelementptr inbounds [2 x double], [2 x double]* %B, i64 %k, i64 %j
+  %tmp10 = load double, double* %arrayidx12, align 8
+  %mul = fmul double %tmp6, %tmp10
+  %arrayidx16 = getelementptr inbounds [2 x double], [2 x double]* %C, i64 %i, i64 %j
+  %tmp14 = load double, double* %arrayidx16, align 8
+  %add = fadd double %tmp14, %mul
+  store double %add, double* %arrayidx16, align 8
+  %add17 = add nsw i64 %k, 1
+  %cmp5 = icmp slt i64 %add17, 784
+  br i1 %cmp5, label %for.body6, label %for.inc18
+
+for.inc18:                                        ; preds = %for.body6
+  %add19 = add nsw i64 %j, 1
+  %cmp2 = icmp slt i64 %add19, 2
+  br i1 %cmp2, label %for.body3, label %for.inc21
+
+for.inc21:                                        ; preds = %for.inc18
+  %add22 = add nsw i64 %i, 1
+  %cmp = icmp slt i64 %add22, 2
+  br i1 %cmp, label %for.body, label %for.end23
+
+for.end23:                                        ; preds = %for.inc21
+  ret void
+}
+
diff --git a/final/test/ScheduleOptimizer/pattern_matching_based_opts_splitmap___%for.body---%for.end23.jscop b/final/test/ScheduleOptimizer/pattern_matching_based_opts_splitmap___%for.body---%for.end23.jscop
new file mode 100644
index 0000000..f64e2a9
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern_matching_based_opts_splitmap___%for.body---%for.end23.jscop
@@ -0,0 +1,46 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "784" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "2" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*", "2" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.body---%for.end23",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i2, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body6[i0, i1, i2] : 0 <= i0 <= 1 and 0 <= i1 <= 1 and 0 <= i2 <= 783 }",
+         "name" : "Stmt_for_body6",
+         "schedule" : "{ Stmt_for_body6[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/ScheduleOptimizer/pattern_matching_based_opts_splitmap___%for.body---%for.end23.jscop.transformed b/final/test/ScheduleOptimizer/pattern_matching_based_opts_splitmap___%for.body---%for.end23.jscop.transformed
new file mode 100644
index 0000000..ffd63af
--- /dev/null
+++ b/final/test/ScheduleOptimizer/pattern_matching_based_opts_splitmap___%for.body---%for.end23.jscop.transformed
@@ -0,0 +1,46 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "784" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "2" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*", "2" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.body---%for.end23",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_B[i2, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body6[i0, i1, i2] -> MemRef_C[i0, i1] : i2 <= 784 - i0 - i1; Stmt_for_body6[1, 1, 783] -> MemRef_C[1, 1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body6[i0, i1, i2] : 0 <= i0 <= 1 and 0 <= i1 <= 1 and 0 <= i2 <= 783 }",
+         "name" : "Stmt_for_body6",
+         "schedule" : "{ Stmt_for_body6[i0, i1, i2] -> [i0, i1, i2] }"
+      }
+   ]
+}
diff --git a/final/test/ScheduleOptimizer/prevectorization-without-tiling.ll b/final/test/ScheduleOptimizer/prevectorization-without-tiling.ll
new file mode 100644
index 0000000..4c752c0
--- /dev/null
+++ b/final/test/ScheduleOptimizer/prevectorization-without-tiling.ll
@@ -0,0 +1,74 @@
+; RUN: opt -S %loadPolly -basicaa -polly-opt-isl -polly-tiling=false \
+; RUN: -polly-pattern-matching-based-opts=false -polly-vectorizer=polly \
+; RUN: -polly-ast -analyze < %s | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@C = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@A = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@B = common global [1536 x [1536 x float]] zeroinitializer, align 16
+
+; Function Attrs: nounwind uwtable
+define void @foo() #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %entry.split, %for.inc28
+  %indvar4 = phi i64 [ 0, %entry.split ], [ %indvar.next5, %for.inc28 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.cond1.preheader, %for.inc25
+  %indvar6 = phi i64 [ 0, %for.cond1.preheader ], [ %indvar.next7, %for.inc25 ]
+  %arrayidx24 = getelementptr [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i64 0, i64 %indvar4, i64 %indvar6
+  store float 0.000000e+00, float* %arrayidx24, align 4
+  br label %for.body8
+
+for.body8:                                        ; preds = %for.body3, %for.body8
+  %indvar = phi i64 [ 0, %for.body3 ], [ %indvar.next, %for.body8 ]
+  %arrayidx16 = getelementptr [1536 x [1536 x float]], [1536 x [1536 x float]]* @A, i64 0, i64 %indvar4, i64 %indvar
+  %arrayidx20 = getelementptr [1536 x [1536 x float]], [1536 x [1536 x float]]* @B, i64 0, i64 %indvar, i64 %indvar6
+  %0 = load float, float* %arrayidx24, align 4
+  %1 = load float, float* %arrayidx16, align 4
+  %2 = load float, float* %arrayidx20, align 4
+  %mul = fmul float %1, %2
+  %add = fadd float %0, %mul
+  store float %add, float* %arrayidx24, align 4
+  %indvar.next = add i64 %indvar, 1
+  %exitcond = icmp ne i64 %indvar.next, 1536
+  br i1 %exitcond, label %for.body8, label %for.inc25
+
+for.inc25:                                        ; preds = %for.body8
+  %indvar.next7 = add i64 %indvar6, 1
+  %exitcond8 = icmp ne i64 %indvar.next7, 1536
+  br i1 %exitcond8, label %for.body3, label %for.inc28
+
+for.inc28:                                        ; preds = %for.inc25
+  %indvar.next5 = add i64 %indvar4, 1
+  %exitcond9 = icmp ne i64 %indvar.next5, 1536
+  br i1 %exitcond9, label %for.cond1.preheader, label %for.end30
+
+for.end30:                                        ; preds = %for.inc28
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+; CHECK: #pragma known-parallel
+; CHECK: for (int c0 = 0; c0 <= 1535; c0 += 1)
+; CHECK:   for (int c1 = 0; c1 <= 383; c1 += 1)
+; CHECK:       // SIMD
+; CHECK:     for (int c2 = 0; c2 <= 3; c2 += 1)
+; CHECK:       Stmt_for_body3(c0, 4 * c1 + c2);
+; CHECK: #pragma known-parallel
+; CHECK: for (int c0 = 0; c0 <= 1535; c0 += 1)
+; CHECK:   for (int c1 = 0; c1 <= 383; c1 += 1)
+; CHECK:     for (int c2 = 0; c2 <= 1535; c2 += 1)
+; CHECK:       // SIMD
+; CHECK:       for (int c3 = 0; c3 <= 3; c3 += 1)
+; CHECK:         Stmt_for_body8(c0, 4 * c1 + c3, c2);
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.5.0 "}
diff --git a/final/test/ScheduleOptimizer/prevectorization.ll b/final/test/ScheduleOptimizer/prevectorization.ll
new file mode 100644
index 0000000..1888ae0
--- /dev/null
+++ b/final/test/ScheduleOptimizer/prevectorization.ll
@@ -0,0 +1,110 @@
+; RUN: opt -S %loadPolly -basicaa -polly-opt-isl \
+; RUN: -polly-pattern-matching-based-opts=false -polly-vectorizer=polly \
+; RUN: -polly-ast -analyze < %s | FileCheck %s 
+; RUN: opt -S %loadPolly -basicaa -polly-opt-isl \
+; RUN: -polly-pattern-matching-based-opts=false -polly-vectorizer=stripmine \
+; RUN: -polly-ast -analyze < %s | FileCheck %s
+
+; RUN: opt -S %loadPolly -basicaa -polly-opt-isl \
+; RUN: -polly-vectorizer=polly -polly-pattern-matching-based-opts=false \
+; RUN: -polly-ast -analyze -polly-prevect-width=16 < %s | \
+; RUN: FileCheck %s -check-prefix=VEC16
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@C = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@A = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@B = common global [1536 x [1536 x float]] zeroinitializer, align 16
+
+; Function Attrs: nounwind uwtable
+define void @foo() #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %entry.split, %for.inc28
+  %indvar4 = phi i64 [ 0, %entry.split ], [ %indvar.next5, %for.inc28 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.cond1.preheader, %for.inc25
+  %indvar6 = phi i64 [ 0, %for.cond1.preheader ], [ %indvar.next7, %for.inc25 ]
+  %arrayidx24 = getelementptr [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i64 0, i64 %indvar4, i64 %indvar6
+  store float 0.000000e+00, float* %arrayidx24, align 4
+  br label %for.body8
+
+for.body8:                                        ; preds = %for.body3, %for.body8
+  %indvar = phi i64 [ 0, %for.body3 ], [ %indvar.next, %for.body8 ]
+  %arrayidx16 = getelementptr [1536 x [1536 x float]], [1536 x [1536 x float]]* @A, i64 0, i64 %indvar4, i64 %indvar
+  %arrayidx20 = getelementptr [1536 x [1536 x float]], [1536 x [1536 x float]]* @B, i64 0, i64 %indvar, i64 %indvar6
+  %0 = load float, float* %arrayidx24, align 4
+  %1 = load float, float* %arrayidx16, align 4
+  %2 = load float, float* %arrayidx20, align 4
+  %mul = fmul float %1, %2
+  %add = fadd float %0, %mul
+  store float %add, float* %arrayidx24, align 4
+  %indvar.next = add i64 %indvar, 1
+  %exitcond = icmp ne i64 %indvar.next, 1536
+  br i1 %exitcond, label %for.body8, label %for.inc25
+
+for.inc25:                                        ; preds = %for.body8
+  %indvar.next7 = add i64 %indvar6, 1
+  %exitcond8 = icmp ne i64 %indvar.next7, 1536
+  br i1 %exitcond8, label %for.body3, label %for.inc28
+
+for.inc28:                                        ; preds = %for.inc25
+  %indvar.next5 = add i64 %indvar4, 1
+  %exitcond9 = icmp ne i64 %indvar.next5, 1536
+  br i1 %exitcond9, label %for.cond1.preheader, label %for.end30
+
+for.end30:                                        ; preds = %for.inc28
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+; CHECK: #pragma known-parallel
+; CHECK: for (int c0 = 0; c0 <= 47; c0 += 1)
+; CHECK:   for (int c1 = 0; c1 <= 47; c1 += 1)
+; CHECK:     for (int c2 = 0; c2 <= 31; c2 += 1)
+; CHECK:       for (int c3 = 0; c3 <= 7; c3 += 1)
+; CHECK:         // SIMD
+; CHECK:         for (int c4 = 0; c4 <= 3; c4 += 1)
+; CHECK:           Stmt_for_body3(32 * c0 + c2, 32 * c1 + 4 * c3 + c4);
+; CHECK: #pragma known-parallel
+; CHECK: for (int c0 = 0; c0 <= 47; c0 += 1)
+; CHECK:   for (int c1 = 0; c1 <= 47; c1 += 1)
+; CHECK:     for (int c2 = 0; c2 <= 47; c2 += 1)
+; CHECK:       for (int c3 = 0; c3 <= 31; c3 += 1)
+; CHECK:         for (int c4 = 0; c4 <= 7; c4 += 1)
+; CHECK:           for (int c5 = 0; c5 <= 31; c5 += 1)
+; CHECK:             // SIMD
+; CHECK:             for (int c6 = 0; c6 <= 3; c6 += 1)
+; CHECK:               Stmt_for_body8(32 * c0 + c3, 32 * c1 + 4 * c4 + c6, 32 * c2 + c5);
+
+; VEC16: {
+; VEC16:   #pragma known-parallel
+; VEC16:   for (int c0 = 0; c0 <= 47; c0 += 1)
+; VEC16:     for (int c1 = 0; c1 <= 47; c1 += 1)
+; VEC16:       for (int c2 = 0; c2 <= 31; c2 += 1)
+; VEC16:         for (int c3 = 0; c3 <= 1; c3 += 1)
+; VEC16:           // SIMD
+; VEC16:           for (int c4 = 0; c4 <= 15; c4 += 1)
+; VEC16:             Stmt_for_body3(32 * c0 + c2, 32 * c1 + 16 * c3 + c4);
+; VEC16:   #pragma known-parallel
+; VEC16:   for (int c0 = 0; c0 <= 47; c0 += 1)
+; VEC16:     for (int c1 = 0; c1 <= 47; c1 += 1)
+; VEC16:       for (int c2 = 0; c2 <= 47; c2 += 1)
+; VEC16:         for (int c3 = 0; c3 <= 31; c3 += 1)
+; VEC16:           for (int c4 = 0; c4 <= 1; c4 += 1)
+; VEC16:             for (int c5 = 0; c5 <= 31; c5 += 1)
+; VEC16:               // SIMD
+; VEC16:               for (int c6 = 0; c6 <= 15; c6 += 1)
+; VEC16:                 Stmt_for_body8(32 * c0 + c3, 32 * c1 + 16 * c4 + c6, 32 * c2 + c5);
+; VEC16: }
+
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.5.0 "}
diff --git a/final/test/ScheduleOptimizer/rectangular-tiling.ll b/final/test/ScheduleOptimizer/rectangular-tiling.ll
new file mode 100644
index 0000000..ccac86f
--- /dev/null
+++ b/final/test/ScheduleOptimizer/rectangular-tiling.ll
@@ -0,0 +1,116 @@
+; RUN: opt %loadPolly -polly-opt-isl -analyze -polly-ast -polly-tile-sizes=256,16 < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-opt-isl -analyze -polly-tiling=false -polly-ast -polly-tile-sizes=256,16 < %s | FileCheck %s --check-prefix=NOTILING
+
+; RUN: opt %loadPolly -polly-opt-isl -analyze \
+; RUN:                -polly-2nd-level-tiling -polly-ast \
+; RUN:                -polly-tile-sizes=256,16 \
+; RUN:                -polly-2nd-level-tile-sizes=16,8 < %s | \
+; RUN: FileCheck %s --check-prefix=TWOLEVEL
+
+; RUN: opt %loadPolly -polly-opt-isl -analyze \
+; RUN:                -polly-2nd-level-tiling -polly-ast \
+; RUN:                -polly-tile-sizes=256,16 \
+; RUN:                -polly-register-tiling \
+; RUN:                -polly-2nd-level-tile-sizes=16,8 < %s | \
+; RUN: FileCheck %s --check-prefix=TWO-PLUS-REGISTER
+
+; RUN: opt %loadPolly -polly-opt-isl -analyze \
+; RUN:                -polly-2nd-level-tiling -polly-ast \
+; RUN:                -polly-tile-sizes=256,16 \
+; RUN:                -polly-register-tiling -polly-register-tile-sizes=2,4 \
+; RUN:                -polly-vectorizer=polly \
+; RUN:                -polly-2nd-level-tile-sizes=16,8 < %s | \
+; RUN: FileCheck %s --check-prefix=TWO-PLUS-REGISTER-PLUS-VECTORIZATION
+
+; CHECK: // 1st level tiling - Tiles
+; CHECK: for (int c0 = 0; c0 <= 3; c0 += 1)
+; CHECK:   for (int c1 = 0; c1 <= 31; c1 += 1)
+; CHECK:     // 1st level tiling - Points
+; CHECK:     for (int c2 = 0; c2 <= 255; c2 += 1)
+; CHECK:       for (int c3 = 0; c3 <= 15; c3 += 1)
+; CHECK:         Stmt_for_body3(256 * c0 + c2, 16 * c1 + c3);
+
+; NOTILING: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; NOTILING:   for (int c1 = 0; c1 <= 511; c1 += 1)
+; NOTILING:     Stmt_for_body3(c0, c1);
+
+
+; TWOLEVEL: // 1st level tiling - Tiles
+; TWOLEVEL: for (int c0 = 0; c0 <= 3; c0 += 1)
+; TWOLEVEL:   for (int c1 = 0; c1 <= 31; c1 += 1)
+; TWOLEVEL:     // 1st level tiling - Points
+; TWOLEVEL:     // 2nd level tiling - Tiles
+; TWOLEVEL:     for (int c2 = 0; c2 <= 15; c2 += 1)
+; TWOLEVEL:       for (int c3 = 0; c3 <= 1; c3 += 1)
+; TWOLEVEL:         // 2nd level tiling - Points
+; TWOLEVEL:         for (int c4 = 0; c4 <= 15; c4 += 1)
+; TWOLEVEL:           for (int c5 = 0; c5 <= 7; c5 += 1)
+; TWOLEVEL:             Stmt_for_body3(256 * c0 + 16 * c2 + c4, 16 * c1 + 8 * c3 + c5);
+
+
+; TWO-PLUS-REGISTER: // 1st level tiling - Tiles
+; TWO-PLUS-REGISTER: for (int c0 = 0; c0 <= 3; c0 += 1)
+; TWO-PLUS-REGISTER:   for (int c1 = 0; c1 <= 31; c1 += 1)
+; TWO-PLUS-REGISTER:     // 1st level tiling - Points
+; TWO-PLUS-REGISTER:     // 2nd level tiling - Tiles
+; TWO-PLUS-REGISTER:     for (int c2 = 0; c2 <= 15; c2 += 1)
+; TWO-PLUS-REGISTER:       for (int c3 = 0; c3 <= 1; c3 += 1)
+; TWO-PLUS-REGISTER:         // 2nd level tiling - Points
+; TWO-PLUS-REGISTER:         // Register tiling - Tiles
+; TWO-PLUS-REGISTER:         for (int c4 = 0; c4 <= 7; c4 += 1)
+; TWO-PLUS-REGISTER:           for (int c5 = 0; c5 <= 3; c5 += 1)
+; TWO-PLUS-REGISTER:             // Register tiling - Points
+; TWO-PLUS-REGISTER:             {
+; TWO-PLUS-REGISTER:               Stmt_for_body3(256 * c0 + 16 * c2 + 2 * c4, 16 * c1 + 8 * c3 + 2 * c5);
+; TWO-PLUS-REGISTER:               Stmt_for_body3(256 * c0 + 16 * c2 + 2 * c4, 16 * c1 + 8 * c3 + 2 * c5 + 1);
+; TWO-PLUS-REGISTER:               Stmt_for_body3(256 * c0 + 16 * c2 + 2 * c4 + 1, 16 * c1 + 8 * c3 + 2 * c5);
+; TWO-PLUS-REGISTER:               Stmt_for_body3(256 * c0 + 16 * c2 + 2 * c4 + 1, 16 * c1 + 8 * c3 + 2 * c5 + 1);
+; TWO-PLUS-REGISTER:             }
+
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION: #pragma known-parallel
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION: for (int c0 = 0; c0 <= 3; c0 += 1)
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION:   for (int c1 = 0; c1 <= 31; c1 += 1)
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION:     for (int c2 = 0; c2 <= 15; c2 += 1)
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION:       for (int c3 = 0; c3 <= 1; c3 += 1)
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION:         for (int c4 = 0; c4 <= 7; c4 += 1)
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION:           for (int c5 = 0; c5 <= 1; c5 += 1) {
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION:             // SIMD
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION:             for (int c8 = 0; c8 <= 3; c8 += 1)
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION:               Stmt_for_body3(256 * c0 + 16 * c2 + 2 * c4, 16 * c1 + 8 * c3 + 4 * c5 + c8);
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION:             // SIMD
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION:             for (int c8 = 0; c8 <= 3; c8 += 1)
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION:               Stmt_for_body3(256 * c0 + 16 * c2 + 2 * c4 + 1, 16 * c1 + 8 * c3 + 4 * c5 + c8);
+; TWO-PLUS-REGISTER-PLUS-VECTORIZATION:           }
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+; Function Attrs: nounwind
+define void @rect([512 x i32]* %A) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body3.lr.ph
+
+for.body3.lr.ph:                                  ; preds = %for.inc5, %entry.split
+  %i.0 = phi i32 [ 0, %entry.split ], [ %inc6, %for.inc5 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.body3.lr.ph, %for.body3
+  %j.0 = phi i32 [ 0, %for.body3.lr.ph ], [ %inc, %for.body3 ]
+  %mul = mul nsw i32 %j.0, %i.0
+  %rem = srem i32 %mul, 42
+  %arrayidx4 = getelementptr inbounds [512 x i32], [512 x i32]* %A, i32 %i.0, i32 %j.0
+  store i32 %rem, i32* %arrayidx4, align 4
+  %inc = add nsw i32 %j.0, 1
+  %cmp2 = icmp slt i32 %inc, 512
+  br i1 %cmp2, label %for.body3, label %for.inc5
+
+for.inc5:                                         ; preds = %for.body3
+  %inc6 = add nsw i32 %i.0, 1
+  %cmp = icmp slt i32 %inc6, 1024
+  br i1 %cmp, label %for.body3.lr.ph, label %for.end7
+
+for.end7:                                         ; preds = %for.inc5
+  ret void
+}
diff --git a/final/test/ScheduleOptimizer/statistics.ll b/final/test/ScheduleOptimizer/statistics.ll
new file mode 100644
index 0000000..086d968
--- /dev/null
+++ b/final/test/ScheduleOptimizer/statistics.ll
@@ -0,0 +1,279 @@
+; RUN: opt %loadPolly -polly-opt-isl -stats -disable-output < %s 2>&1 | FileCheck %s -match-full-lines
+
+; REQUIRES: asserts
+
+;    void foo_1d(float *A) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += i;
+;    }
+;
+;    void foo_2d(float *A) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          A[i + j] += i + j;
+;    }
+;
+;    void foo_3d(float *A) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          for (long k = 0; k < 1024; k++)
+;            A[i + j + k] += i + j + k;
+;    }
+;
+;    void foo_4d(float *A) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          for (long k = 0; k < 1024; k++)
+;            for (long l = 0; l < 1024; l++)
+;              A[i + j + k + l] += i + j + k + l;
+;    }
+;
+;    void foo_zero_iterations(float *S) {
+;      for (long i = 0; i < 0; i++)
+;        A[i] += i;
+;    }
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo_1d(float* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = sitofp i64 %i.0 to float
+  %tmp3 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, %tmp
+  store float %tmp5, float* %tmp3, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
+
+define void @foo_2d(float* %A) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb14, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp15, %bb14 ]
+  %exitcond1 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond1, label %bb3, label %bb16
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb11, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp12, %bb11 ]
+  %exitcond = icmp ne i64 %j.0, 1024
+  br i1 %exitcond, label %bb5, label %bb13
+
+bb5:                                              ; preds = %bb4
+  %tmp = add nuw nsw i64 %i.0, %j.0
+  %tmp6 = sitofp i64 %tmp to float
+  %tmp7 = add nuw nsw i64 %i.0, %j.0
+  %tmp8 = getelementptr inbounds float, float* %A, i64 %tmp7
+  %tmp9 = load float, float* %tmp8, align 4
+  %tmp10 = fadd float %tmp9, %tmp6
+  store float %tmp10, float* %tmp8, align 4
+  br label %bb11
+
+bb11:                                             ; preds = %bb5
+  %tmp12 = add nuw nsw i64 %j.0, 1
+  br label %bb4
+
+bb13:                                             ; preds = %bb4
+  br label %bb14
+
+bb14:                                             ; preds = %bb13
+  %tmp15 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb16:                                             ; preds = %bb2
+  ret void
+}
+
+define void @foo_3d(float* %A) {
+bb:
+  br label %bb3
+
+bb3:                                              ; preds = %bb22, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp23, %bb22 ]
+  %exitcond2 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond2, label %bb4, label %bb24
+
+bb4:                                              ; preds = %bb3
+  br label %bb5
+
+bb5:                                              ; preds = %bb19, %bb4
+  %j.0 = phi i64 [ 0, %bb4 ], [ %tmp20, %bb19 ]
+  %exitcond1 = icmp ne i64 %j.0, 1024
+  br i1 %exitcond1, label %bb6, label %bb21
+
+bb6:                                              ; preds = %bb5
+  br label %bb7
+
+bb7:                                              ; preds = %bb16, %bb6
+  %k.0 = phi i64 [ 0, %bb6 ], [ %tmp17, %bb16 ]
+  %exitcond = icmp ne i64 %k.0, 1024
+  br i1 %exitcond, label %bb8, label %bb18
+
+bb8:                                              ; preds = %bb7
+  %tmp = add nuw nsw i64 %i.0, %j.0
+  %tmp9 = add nuw nsw i64 %tmp, %k.0
+  %tmp10 = sitofp i64 %tmp9 to float
+  %tmp11 = add nuw nsw i64 %i.0, %j.0
+  %tmp12 = add nuw nsw i64 %tmp11, %k.0
+  %tmp13 = getelementptr inbounds float, float* %A, i64 %tmp12
+  %tmp14 = load float, float* %tmp13, align 4
+  %tmp15 = fadd float %tmp14, %tmp10
+  store float %tmp15, float* %tmp13, align 4
+  br label %bb16
+
+bb16:                                             ; preds = %bb8
+  %tmp17 = add nuw nsw i64 %k.0, 1
+  br label %bb7
+
+bb18:                                             ; preds = %bb7
+  br label %bb19
+
+bb19:                                             ; preds = %bb18
+  %tmp20 = add nuw nsw i64 %j.0, 1
+  br label %bb5
+
+bb21:                                             ; preds = %bb5
+  br label %bb22
+
+bb22:                                             ; preds = %bb21
+  %tmp23 = add nuw nsw i64 %i.0, 1
+  br label %bb3
+
+bb24:                                             ; preds = %bb3
+  ret void
+}
+
+define void @foo_4d(float* %A) {
+bb:
+  br label %bb4
+
+bb4:                                              ; preds = %bb30, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp31, %bb30 ]
+  %exitcond3 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond3, label %bb5, label %bb32
+
+bb5:                                              ; preds = %bb4
+  br label %bb6
+
+bb6:                                              ; preds = %bb27, %bb5
+  %j.0 = phi i64 [ 0, %bb5 ], [ %tmp28, %bb27 ]
+  %exitcond2 = icmp ne i64 %j.0, 1024
+  br i1 %exitcond2, label %bb7, label %bb29
+
+bb7:                                              ; preds = %bb6
+  br label %bb8
+
+bb8:                                              ; preds = %bb24, %bb7
+  %k.0 = phi i64 [ 0, %bb7 ], [ %tmp25, %bb24 ]
+  %exitcond1 = icmp ne i64 %k.0, 1024
+  br i1 %exitcond1, label %bb9, label %bb26
+
+bb9:                                              ; preds = %bb8
+  br label %bb10
+
+bb10:                                             ; preds = %bb21, %bb9
+  %l.0 = phi i64 [ 0, %bb9 ], [ %tmp22, %bb21 ]
+  %exitcond = icmp ne i64 %l.0, 1024
+  br i1 %exitcond, label %bb11, label %bb23
+
+bb11:                                             ; preds = %bb10
+  %tmp = add nuw nsw i64 %i.0, %j.0
+  %tmp12 = add nuw nsw i64 %tmp, %k.0
+  %tmp13 = add nuw nsw i64 %tmp12, %l.0
+  %tmp14 = sitofp i64 %tmp13 to float
+  %tmp15 = add nuw nsw i64 %i.0, %j.0
+  %tmp16 = add nuw nsw i64 %tmp15, %k.0
+  %tmp17 = add nuw nsw i64 %tmp16, %l.0
+  %tmp18 = getelementptr inbounds float, float* %A, i64 %tmp17
+  %tmp19 = load float, float* %tmp18, align 4
+  %tmp20 = fadd float %tmp19, %tmp14
+  store float %tmp20, float* %tmp18, align 4
+  br label %bb21
+
+bb21:                                             ; preds = %bb11
+  %tmp22 = add nuw nsw i64 %l.0, 1
+  br label %bb10
+
+bb23:                                             ; preds = %bb10
+  br label %bb24
+
+bb24:                                             ; preds = %bb23
+  %tmp25 = add nuw nsw i64 %k.0, 1
+  br label %bb8
+
+bb26:                                             ; preds = %bb8
+  br label %bb27
+
+bb27:                                             ; preds = %bb26
+  %tmp28 = add nuw nsw i64 %j.0, 1
+  br label %bb6
+
+bb29:                                             ; preds = %bb6
+  br label %bb30
+
+bb30:                                             ; preds = %bb29
+  %tmp31 = add nuw nsw i64 %i.0, 1
+  br label %bb4
+
+bb32:                                             ; preds = %bb4
+  ret void
+}
+
+define void @foo_zero_iterations(float* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %exitcond = icmp ne i64 %i.0, 0
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = sitofp i64 %i.0 to float
+  %tmp3 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, %tmp
+  store float %tmp5, float* %tmp3, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
+
+
+; CHECK-DAG:  1 polly-opt-isl    - Number of first level tiling applied
+; CHECK-DAG:  9 polly-opt-isl    - Number of affine loops optimized
+; CHECK-DAG: 10 polly-opt-isl    - Number of band members (original)
+; CHECK-DAG: 10 polly-opt-isl    - Number of band members (after scheduler)
+; CHECK-DAG: 12 polly-opt-isl    - Number of band members (after optimizer)
+; CHECK-DAG: 10 polly-opt-isl    - Number of bands (original)
+; CHECK-DAG:  7 polly-opt-isl    - Number of bands (after scheduler)
+; CHECK-DAG:  8 polly-opt-isl    - Number of bands (after optimizer)
+; CHECK-DAG:  4 polly-opt-isl    - Number of coincident band members (after scheduler)
+; CHECK-DAG:  5 polly-opt-isl    - Number of coincident band members (after optimizer)
+; CHECK-DAG:  7 polly-opt-isl    - Number of permutable bands (after scheduler)
+; CHECK-DAG:  8 polly-opt-isl    - Number of permutable bands (after optimizer)
+; CHECK-DAG:  3 polly-opt-isl    - Number of scops optimized
+; CHECK-DAG:  4 polly-opt-isl    - Number of scops processed
+; CHECK-DAG:  4 polly-opt-isl    - Number of scops rescheduled
diff --git a/final/test/ScheduleOptimizer/tile_after_fusion.ll b/final/test/ScheduleOptimizer/tile_after_fusion.ll
new file mode 100644
index 0000000..42833ef
--- /dev/null
+++ b/final/test/ScheduleOptimizer/tile_after_fusion.ll
@@ -0,0 +1,139 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-ast -polly-opt-fusion=max -analyze < %s | FileCheck %s
+;
+;
+;    void tf(int C[256][256][256], int A0[256][256][256], int A1[256][256][256]) {
+;      for (int i = 0; i < 256; ++i)
+;        for (int j = 0; j < 256; ++j)
+;          for (int k = 0; k < 256; ++k)
+;            C[i][j][k] += A0[i][j][k];
+;
+;      for (int i = 0; i < 256; ++i)
+;        for (int j = 0; j < 256; ++j)
+;          for (int k = 0; k < 256; ++k)
+;            C[i][j][k] += A1[i][j][k];
+;    }
+;
+; The tile_after_fusion.ll test has two statements in separate loop nests and
+; checks whether they are tiled after being fused when polly-opt-fusion equals
+; "max".
+;
+; CHECK:       1st level tiling - Tiles
+; CHECK-NEXT:     for (int c0 = 0; c0 <= 7; c0 += 1)
+; CHECK-NEXT:       for (int c1 = 0; c1 <= 7; c1 += 1)
+; CHECK-NEXT:         for (int c2 = 0; c2 <= 7; c2 += 1) {
+; CHECK-NEXT:           // 1st level tiling - Points
+; CHECK-NEXT:           for (int c3 = 0; c3 <= 31; c3 += 1)
+; CHECK-NEXT:             for (int c4 = 0; c4 <= 31; c4 += 1)
+; CHECK-NEXT:               for (int c5 = 0; c5 <= 31; c5 += 1) {
+; CHECK-NEXT:                 Stmt_for_body6(32 * c0 + c3, 32 * c1 + c4, 32 * c2 + c5);
+; CHECK-NEXT:                 Stmt_for_body34(32 * c0 + c3, 32 * c1 + c4, 32 * c2 + c5);
+
+source_filename = "tile_after_fusion.c"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @tf([256 x [256 x i32]]* %C, [256 x [256 x i32]]* %A0, [256 x [256 x i32]]* %A1) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc20, %entry
+  %indvars.iv13 = phi i64 [ %indvars.iv.next14, %for.inc20 ], [ 0, %entry ]
+  %exitcond15 = icmp ne i64 %indvars.iv13, 256
+  br i1 %exitcond15, label %for.body, label %for.end22
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc17, %for.body
+  %indvars.iv10 = phi i64 [ %indvars.iv.next11, %for.inc17 ], [ 0, %for.body ]
+  %exitcond12 = icmp ne i64 %indvars.iv10, 256
+  br i1 %exitcond12, label %for.body3, label %for.end19
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc, %for.body3
+  %indvars.iv7 = phi i64 [ %indvars.iv.next8, %for.inc ], [ 0, %for.body3 ]
+  %exitcond9 = icmp ne i64 %indvars.iv7, 256
+  br i1 %exitcond9, label %for.body6, label %for.end
+
+for.body6:                                        ; preds = %for.cond4
+  %arrayidx10 = getelementptr inbounds [256 x [256 x i32]], [256 x [256 x i32]]* %A0, i64 %indvars.iv13, i64 %indvars.iv10, i64 %indvars.iv7
+  %tmp = load i32, i32* %arrayidx10, align 4
+  %arrayidx16 = getelementptr inbounds [256 x [256 x i32]], [256 x [256 x i32]]* %C, i64 %indvars.iv13, i64 %indvars.iv10, i64 %indvars.iv7
+  %tmp16 = load i32, i32* %arrayidx16, align 4
+  %add = add nsw i32 %tmp16, %tmp
+  store i32 %add, i32* %arrayidx16, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body6
+  %indvars.iv.next8 = add nuw nsw i64 %indvars.iv7, 1
+  br label %for.cond4
+
+for.end:                                          ; preds = %for.cond4
+  br label %for.inc17
+
+for.inc17:                                        ; preds = %for.end
+  %indvars.iv.next11 = add nuw nsw i64 %indvars.iv10, 1
+  br label %for.cond1
+
+for.end19:                                        ; preds = %for.cond1
+  br label %for.inc20
+
+for.inc20:                                        ; preds = %for.end19
+  %indvars.iv.next14 = add nuw nsw i64 %indvars.iv13, 1
+  br label %for.cond
+
+for.end22:                                        ; preds = %for.cond
+  br label %for.cond24
+
+for.cond24:                                       ; preds = %for.inc54, %for.end22
+  %indvars.iv4 = phi i64 [ %indvars.iv.next5, %for.inc54 ], [ 0, %for.end22 ]
+  %exitcond6 = icmp ne i64 %indvars.iv4, 256
+  br i1 %exitcond6, label %for.body26, label %for.end56
+
+for.body26:                                       ; preds = %for.cond24
+  br label %for.cond28
+
+for.cond28:                                       ; preds = %for.inc51, %for.body26
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc51 ], [ 0, %for.body26 ]
+  %exitcond3 = icmp ne i64 %indvars.iv1, 256
+  br i1 %exitcond3, label %for.body30, label %for.end53
+
+for.body30:                                       ; preds = %for.cond28
+  br label %for.cond32
+
+for.cond32:                                       ; preds = %for.inc48, %for.body30
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc48 ], [ 0, %for.body30 ]
+  %exitcond = icmp ne i64 %indvars.iv, 256
+  br i1 %exitcond, label %for.body34, label %for.end50
+
+for.body34:                                       ; preds = %for.cond32
+  %arrayidx40 = getelementptr inbounds [256 x [256 x i32]], [256 x [256 x i32]]* %A1, i64 %indvars.iv4, i64 %indvars.iv1, i64 %indvars.iv
+  %tmp17 = load i32, i32* %arrayidx40, align 4
+  %arrayidx46 = getelementptr inbounds [256 x [256 x i32]], [256 x [256 x i32]]* %C, i64 %indvars.iv4, i64 %indvars.iv1, i64 %indvars.iv
+  %tmp18 = load i32, i32* %arrayidx46, align 4
+  %add47 = add nsw i32 %tmp18, %tmp17
+  store i32 %add47, i32* %arrayidx46, align 4
+  br label %for.inc48
+
+for.inc48:                                        ; preds = %for.body34
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond32
+
+for.end50:                                        ; preds = %for.cond32
+  br label %for.inc51
+
+for.inc51:                                        ; preds = %for.end50
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %for.cond28
+
+for.end53:                                        ; preds = %for.cond28
+  br label %for.inc54
+
+for.inc54:                                        ; preds = %for.end53
+  %indvars.iv.next5 = add nuw nsw i64 %indvars.iv4, 1
+  br label %for.cond24
+
+for.end56:                                        ; preds = %for.cond24
+  ret void
+}
diff --git a/final/test/ScopDetect/aliasing_parametric_simple_1.ll b/final/test/ScopDetect/aliasing_parametric_simple_1.ll
new file mode 100644
index 0000000..a92ef0f
--- /dev/null
+++ b/final/test/ScopDetect/aliasing_parametric_simple_1.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+;
+; CHECK: Valid Region for Scop:
+;
+;    void jd(int *A, int *B, int c) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = B[c];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %B, i32 %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %idxprom = sext i32 %c to i64
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %idxprom
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopDetect/aliasing_parametric_simple_2.ll b/final/test/ScopDetect/aliasing_parametric_simple_2.ll
new file mode 100644
index 0000000..da353a3
--- /dev/null
+++ b/final/test/ScopDetect/aliasing_parametric_simple_2.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+;
+; CHECK: Valid Region for Scop:
+;
+;    void jd(int *A, int *B, int c) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = B[c - 10] + B[5];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %B, i32 %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %sub = add nsw i32 %c, -10
+  %idxprom = sext i32 %sub to i64
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %idxprom
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds i32, i32* %B, i64 5
+  %tmp1 = load i32, i32* %arrayidx1, align 4
+  %add = add nsw i32 %tmp, %tmp1
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %add, i32* %arrayidx3, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopDetect/aliasing_simple_1.ll b/final/test/ScopDetect/aliasing_simple_1.ll
new file mode 100644
index 0000000..6b73228
--- /dev/null
+++ b/final/test/ScopDetect/aliasing_simple_1.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+;
+; CHECK: Valid Region for Scop:
+;
+;    void jd(int *A, int *B) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = B[0];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = load i32, i32* %B, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopDetect/aliasing_simple_2.ll b/final/test/ScopDetect/aliasing_simple_2.ll
new file mode 100644
index 0000000..5b7da9b
--- /dev/null
+++ b/final/test/ScopDetect/aliasing_simple_2.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+;
+; CHECK: Valid Region for Scop:
+;
+;    void jd(int *A, int *B) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = B[0] + B[1023];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = load i32, i32* %B, align 4
+  %arrayidx1 = getelementptr inbounds i32, i32* %B, i64 1023
+  %tmp1 = load i32, i32* %arrayidx1, align 4
+  %add = add nsw i32 %tmp, %tmp1
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %add, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopDetect/base_pointer.ll b/final/test/ScopDetect/base_pointer.ll
new file mode 100644
index 0000000..09fdf02
--- /dev/null
+++ b/final/test/ScopDetect/base_pointer.ll
@@ -0,0 +1,296 @@
+; RUN: opt %loadPolly -disable-basicaa -polly-detect -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @base_pointer_in_condition(i64** noalias %A_ptr, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br label %pre
+
+pre:
+  %A = load i64*, i64** %A_ptr
+  br i1 true, label %for.i, label %then
+
+for.i:
+  %indvar = phi i64 [ 0, %pre ], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %then, label %for.i
+
+then:
+  br label %return
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK-LABEL: base_pointer_in_condition
+; CHECK: Valid Region for Scop: pre => return
+
+define void @base_pointer_is_argument(float* %A, i64 %n) {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc ], [ 0, %entry ]
+  br label %S1
+
+S1:
+  %conv = sitofp i64 %indvar.i to float
+  %arrayidx5 = getelementptr float, float* %A, i64 %indvar.i
+  store float %conv, float* %arrayidx5, align 4
+  br label %for.i.inc
+
+for.i.inc:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, %n
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
+
+; CHECK-LABEL: base_pointer_is_argument
+; CHECK: Valid Region for Scop: for.i => exit
+
+define void @base_pointer_is_const_expr(i64 %n) {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc ], [ 0, %entry ]
+  br label %S1
+
+S1:
+  %conv = sitofp i64 %indvar.i to float
+  %arrayidx5 = getelementptr float, float* inttoptr (i64 100 to float*), i64 %indvar.i
+  store float %conv, float* %arrayidx5, align 4
+  br label %for.i.inc
+
+for.i.inc:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, %n
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
+
+; CHECK-LABEL: base_pointer_is_const_expr
+; CHECK-LABEL: Valid Region for Scop: for.i => exit
+
+@A = external global float
+
+define void @base_pointer_is_global(i64 %n) {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc ], [ 0, %entry ]
+  br label %S1
+
+S1:
+  %conv = sitofp i64 %indvar.i to float
+  %arrayidx5 = getelementptr float, float* @A, i64 %indvar.i
+  store float %conv, float* %arrayidx5, align 4
+  br label %for.i.inc
+
+for.i.inc:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, %n
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
+
+; CHECK-LABEL: base_pointer_is_global
+; CHECK: Valid Region for Scop: for.i => exit
+
+declare float *@foo()
+
+define void @base_pointer_is_inst_outside(i64 %n) {
+entry:
+  %A = call float *@foo()
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc ], [ 0, %entry ]
+  br label %S1
+
+S1:
+  %conv = sitofp i64 %indvar.i to float
+  %arrayidx5 = getelementptr float, float* %A, i64 %indvar.i
+  store float %conv, float* %arrayidx5, align 4
+  br label %for.i.inc
+
+for.i.inc:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, %n
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
+
+; CHECK-LABEL: base_pointer_is_inst_outside
+; CHECK: Valid Region for Scop: for.i => exit
+
+declare float* @getNextBasePtr(float*) readnone nounwind
+
+define void @base_pointer_is_phi_node(i64 %n, float* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc ], [ 0, %entry ]
+  %ptr = phi float* [ %ptr.next, %for.i.inc ], [ %A, %entry ]
+; To get a PHI node inside a SCoP that can not be analyzed but
+; for which the surrounding SCoP is normally still valid we use a function
+; without any side effects.
+  %ptr.next = call float* @getNextBasePtr(float* %ptr)
+  br label %S1
+
+S1:
+  %conv = sitofp i64 %indvar.i to float
+  %arrayidx5 = getelementptr float, float* %ptr, i64 %indvar.i
+  store float %conv, float* %arrayidx5, align 4
+  br label %for.i.inc
+
+for.i.inc:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, %n
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
+
+; CHECK-LABEL: base_pointer_is_phi_node
+; CHECK-NOT: Valid Region for Scop
+
+define void @base_pointer_is_inst_inside_invariant_1(i64 %n, float* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc ], [ 0, %entry ]
+; A function return value, even with readnone nounwind attributes, is not
+; considered a valid base pointer because it can return a pointer that aliases
+; with something else (e.g. %A or a global) or return a different pointer at
+; every call (e.g. malloc)
+  %ptr = call float* @getNextBasePtr(float* %A)
+  br label %S1
+
+S1:
+  %conv = sitofp i64 %indvar.i to float
+  %arrayidx5 = getelementptr float, float* %ptr, i64 %indvar.i
+  store float %conv, float* %arrayidx5, align 4
+  br label %for.i.inc
+
+for.i.inc:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, %n
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
+
+; CHECK-LABEL: base_pointer_is_inst_inside_invariant_1
+; CHECK-NOT: Valid Region for Scop
+
+declare float* @getNextBasePtr2(float*) readnone nounwind
+
+define void @base_pointer_is_inst_inside_invariant_2(i64 %n, float* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc ], [ 0, %entry ]
+  %ptr = call float* @getNextBasePtr2(float* %A)
+  %ptr2 = call float* @getNextBasePtr(float* %ptr)
+  br label %S1
+
+S1:
+  %conv = sitofp i64 %indvar.i to float
+  %arrayidx5 = getelementptr float, float* %ptr2, i64 %indvar.i
+  store float %conv, float* %arrayidx5, align 4
+  br label %for.i.inc
+
+for.i.inc:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, %n
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
+
+; CHECK-LABEL: base_pointer_is_inst_inside_invariant_2
+; CHECK-NOT: Valid Region for Scop
+
+declare float* @getNextBasePtr3(float*, i64) readnone nounwind
+
+define void @base_pointer_is_inst_inside_variant(i64 %n, float* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc ], [ 0, %entry ]
+  %ptr = call float* @getNextBasePtr3(float* %A, i64 %indvar.i)
+  %ptr2 = call float* @getNextBasePtr(float* %ptr)
+  br label %S1
+
+S1:
+  %conv = sitofp i64 %indvar.i to float
+  %arrayidx5 = getelementptr float, float* %ptr2, i64 %indvar.i
+  store float %conv, float* %arrayidx5, align 4
+  br label %for.i.inc
+
+for.i.inc:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, %n
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
+
+; CHECK: base_pointer_is_inst_inside_variant
+; CHECK-NOT: Valid Region for Scop
+
+define void @base_pointer_is_ptr2ptr(float** noalias %A, i64 %n) {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc ], [ 0, %entry ]
+  %arrayidx = getelementptr float*, float** %A, i64 %indvar.i
+  br label %for.j
+
+for.j:
+  %indvar.j = phi i64 [ 0, %for.i ], [ %indvar.j.next, %for.j ]
+  %conv = sitofp i64 %indvar.i to float
+  %basepointer = load float*, float** %arrayidx, align 8
+  %arrayidx5 = getelementptr float, float* %basepointer, i64 %indvar.j
+  store float %conv, float* %arrayidx5, align 4
+  %indvar.j.next = add i64 %indvar.j, 1
+  %exitcond.j = icmp ne i64 %indvar.j.next, %n
+  br i1 %exitcond.j, label %for.j, label %for.i.inc
+
+for.i.inc:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, %n
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
+
+; CHECK: base_pointer_is_ptr2ptr
+; CHECK: Valid Region for Scop: for.j => for.i.inc
diff --git a/final/test/ScopDetect/base_pointer_is_inst_inside_invariant_1___%for.i---%exit.jscop b/final/test/ScopDetect/base_pointer_is_inst_inside_invariant_1___%for.i---%exit.jscop
new file mode 100644
index 0000000..c8ebd8e
--- /dev/null
+++ b/final/test/ScopDetect/base_pointer_is_inst_inside_invariant_1___%for.i---%exit.jscop
@@ -0,0 +1,24 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_ptr",
+         "sizes" : [ "*" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "[n] -> {  : -9223372036854775808 <= n <= 9223372036854775807 }",
+   "name" : "%for.i---%exit",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_ptr[i0+1] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/ScopDetect/base_pointer_load_is_inst_inside_invariant_1___%for.i---%exit.jscop b/final/test/ScopDetect/base_pointer_load_is_inst_inside_invariant_1___%for.i---%exit.jscop
new file mode 100644
index 0000000..bcc3c30
--- /dev/null
+++ b/final/test/ScopDetect/base_pointer_load_is_inst_inside_invariant_1___%for.i---%exit.jscop
@@ -0,0 +1,29 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "float*"
+      },
+      {
+         "name" : "MemRef_ptr",
+         "sizes" : [ "*" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "[n] -> {  : -9223372036854775808 <= n <= 9223372036854775807 }",
+   "name" : "%for.i---%exit",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_S1[i0] -> MemRef_ptr[i0+1] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_S1[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_S1",
+         "schedule" : "[n] -> { Stmt_S1[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/ScopDetect/base_pointer_load_setNewAccessRelation.ll b/final/test/ScopDetect/base_pointer_load_setNewAccessRelation.ll
new file mode 100644
index 0000000..3561a49
--- /dev/null
+++ b/final/test/ScopDetect/base_pointer_load_setNewAccessRelation.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-ignore-aliasing -polly-invariant-load-hoisting=true -polly-scops -polly-import-jscop -polly-codegen -analyze < %s | FileCheck %s
+;
+; This violated an assertion in setNewAccessRelation that assumed base pointers
+; to be load-hoisted. Without this assertion, it codegen would generate invalid
+; code.
+;
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @base_pointer_load_is_inst_inside_invariant_1(i64 %n, float** %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc ], [ 0, %entry ]
+  br label %S1
+
+S1:
+  %ptr = load float*, float** %A
+  %conv = sitofp i64 %indvar.i to float
+  %arrayidx5 = getelementptr float, float* %ptr, i64 %indvar.i
+  store float %conv, float* %arrayidx5, align 4
+  br label %for.i.inc
+
+for.i.inc:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, %n
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
+
+
+; Detected by -polly-detect with required load hoist.
+; CHECK-NOT: Valid Region for Scop: for.i => exit
+;
+; Load hoist if %ptr by -polly-scops.
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:     ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:         [n] -> { Stmt_S1[i0] -> MemRef_A[0] };
+; CHECK-NEXT:     Execution Context: [n] -> {  : n > 0 }
+; CHECK-NEXT: }
diff --git a/final/test/ScopDetect/base_pointer_setNewAccessRelation.ll b/final/test/ScopDetect/base_pointer_setNewAccessRelation.ll
new file mode 100644
index 0000000..a7afa74
--- /dev/null
+++ b/final/test/ScopDetect/base_pointer_setNewAccessRelation.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -disable-basicaa -polly-detect -polly-import-jscop -polly-codegen -analyze < %s | FileCheck %s
+;
+; Polly codegen used to generate invalid code (referring to %ptr from the
+; original region) when regeneration of the access function is necessary.
+; The SCoP is now rejected as a whole because %ptr is not considered a valid
+; base pointer.
+;
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+declare float* @getNextBasePtr(float*) readnone nounwind
+
+define void @base_pointer_is_inst_inside_invariant_1(i64 %n, float* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc ], [ 0, %entry ]
+  br label %S1
+
+S1:
+  %ptr = call float* @getNextBasePtr(float* %A)
+  %conv = sitofp i64 %indvar.i to float
+  %arrayidx5 = getelementptr float, float* %ptr, i64 %indvar.i
+  store float %conv, float* %arrayidx5, align 4
+  br label %for.i.inc
+
+for.i.inc:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, %n
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
+
+
+; CHECK-NOT: Valid Region for Scop
diff --git a/final/test/ScopDetect/cross_loop_non_single_exit.ll b/final/test/ScopDetect/cross_loop_non_single_exit.ll
new file mode 100644
index 0000000..f98aa54
--- /dev/null
+++ b/final/test/ScopDetect/cross_loop_non_single_exit.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+; void f(long A[], long N) {
+;   long i;
+;   if (true)
+;     for (i = 0; i < N; ++i)
+;       A[i] = i;
+;   else
+;     for (j = 0; j < N; ++j)
+;        A[j] = j;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br i1 true, label %next, label %next2
+
+next2:
+  br i1 true, label %for.j, label %return
+
+for.j:
+  %indvar2 = phi i64 [ 0, %next2], [ %indvar2.next2, %for.j]
+  %scevgep2 = getelementptr i64, i64* %A, i64 %indvar2
+  store i64 %indvar2, i64* %scevgep2
+  %indvar2.next2 = add nsw i64 %indvar2, 1
+  %exitcond2 = icmp eq i64 %indvar2.next2, %N
+  br i1 %exitcond2, label %return, label %for.j
+
+next:
+  br i1 true, label %for.i, label %return
+
+for.i:
+  %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: Valid Region for Scop: next => return
+; CHECK: Valid Region for Scop: next2 => return
diff --git a/final/test/ScopDetect/cross_loop_non_single_exit_2.ll b/final/test/ScopDetect/cross_loop_non_single_exit_2.ll
new file mode 100644
index 0000000..5aa50ec
--- /dev/null
+++ b/final/test/ScopDetect/cross_loop_non_single_exit_2.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+; void f(long A[], long N) {
+;   long i;
+;   if (true)
+;     for (i = 0; i < N; ++i)
+;       A[i] = i;
+;   else
+;     for (j = 0; j < N; ++j)
+;        A[j] = j;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+declare i64 @foo()
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br i1 true, label %next, label %next2
+
+next2:
+  br i1 true, label %for.j, label %return
+
+for.j:
+  %indvar2 = phi i64 [ 0, %next2], [ %indvar2.next2, %for.j]
+  %scevgep2 = getelementptr i64, i64* %A, i64 %indvar2
+  store i64 %indvar2, i64* %scevgep2
+  %indvar2.next2 = add nsw i64 %indvar2, 1
+  %exitcond2 = icmp eq i64 %indvar2.next2, %N
+  br i1 %exitcond2, label %return, label %for.j
+
+next:
+  br i1 true, label %for.i, label %return
+
+for.i:
+  %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %i = call i64 @foo()
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  br i1 true, label %return_a, label %return_b
+
+return_a:
+  br label %return_join
+
+return_b:
+  br label %return_join
+
+return_join:
+  fence seq_cst
+  ret void
+}
+
+; CHECK-NOT: Valid Region for Scop: next => return
+; CHECK: Valid Region for Scop: next2 => return
diff --git a/final/test/ScopDetect/dependency_to_phi_node_outside_of_region.ll b/final/test/ScopDetect/dependency_to_phi_node_outside_of_region.ll
new file mode 100644
index 0000000..9574f93
--- /dev/null
+++ b/final/test/ScopDetect/dependency_to_phi_node_outside_of_region.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect -disable-output < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N, i64 %M) nounwind {
+entry:
+  fence seq_cst
+  br label %for.i
+
+for.i:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %next, label %for.i
+
+next:
+  fence seq_cst
+  br label %for.j
+
+for.j:
+  %indvar.j = phi i64 [ %indvar, %next ], [ %indvar.j.next, %for.j ]
+  %scevgep.j = getelementptr i64, i64* %A, i64 %indvar.j
+  store i64 %indvar.j, i64* %scevgep.j
+  fence seq_cst
+  %indvar.j.next = add nsw i64 %indvar.j, 1
+  %exitcond.j = icmp eq i64 %indvar.j.next, %M
+  br i1 %exitcond.j, label %return, label %for.j
+
+return:
+  fence seq_cst
+  ret void
+}
diff --git a/final/test/ScopDetect/dot-scops.ll b/final/test/ScopDetect/dot-scops.ll
new file mode 100644
index 0000000..2e9f844
--- /dev/null
+++ b/final/test/ScopDetect/dot-scops.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-scops -dot-scops -analyze < %s
+;
+; Check that the ScopPrinter does not crash.
+; ScopPrinter needs the ScopDetection pass, which should depend on
+; ScalarEvolution transitively.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @func(i32 %n, i32 %m, double* noalias nonnull %A) {
+entry:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %entry], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %inner.for, label %outer.exit
+
+  inner.for:
+    %i = phi i32 [1, %outer.for], [%i.inc, %inner.inc]
+    %b = phi double [0.0, %outer.for], [%a, %inner.inc]
+    %i.cmp = icmp slt i32 %i, %m
+    br i1 %i.cmp, label %body1, label %inner.exit
+
+    body1:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %i
+      %a = load double, double* %A_idx
+      store double %a, double* %A_idx
+      br label %inner.inc
+
+  inner.inc:
+    %i.inc = add nuw nsw i32 %i, 1
+    br label %inner.for
+
+  inner.exit:
+    br label %outer.inc
+
+outer.inc:
+  store double %b, double* %A
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
diff --git a/final/test/ScopDetect/error-block-always-executed.ll b/final/test/ScopDetect/error-block-always-executed.ll
new file mode 100644
index 0000000..c4cdb2f
--- /dev/null
+++ b/final/test/ScopDetect/error-block-always-executed.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s \
+; RUN:     | FileCheck %s
+;
+; CHECK-NOT: Valid Region for Scop:
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.hoge = type { i32, i32, i32, i32 }
+
+; Function Attrs: nounwind uwtable
+define void @widget() #0 {
+bb13:
+  %tmp1 = alloca %struct.hoge, align 4
+  br i1 undef, label %bb14, label %bb19
+
+bb14:                                             ; preds = %bb13
+  %tmp = load i32, i32* undef, align 4, !tbaa !1
+  call void @quux() #2
+  br i1 false, label %bb15, label %bb18
+
+bb15:                                             ; preds = %bb14
+  %tmp16 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp1, i64 0, i32 1
+  %tmp17 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp1, i64 0, i32 2
+  br label %bb19
+
+bb18:                                             ; preds = %bb14
+  br label %bb19
+
+bb19:                                             ; preds = %bb18, %bb15, %bb13
+  %tmp20 = phi i32 [ undef, %bb13 ], [ %tmp, %bb15 ], [ %tmp, %bb18 ]
+  unreachable
+
+bb21:                                             ; preds = %bb8
+  unreachable
+
+bb22:                                             ; preds = %bb8, %bb8, %bb8, %bb8
+  br label %bb23
+
+bb23:                                             ; preds = %bb22
+  unreachable
+
+bb24:                                             ; preds = %bb8, %bb8
+  unreachable
+
+bb25:                                             ; preds = %bb2
+  unreachable
+}
+
+declare void @quux() #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 252700) (llvm/trunk 252705)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"int", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/ScopDetect/error-block-referenced-from-scop.ll b/final/test/ScopDetect/error-block-referenced-from-scop.ll
new file mode 100644
index 0000000..77e7a15
--- /dev/null
+++ b/final/test/ScopDetect/error-block-referenced-from-scop.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s \
+; RUN:     | FileCheck %s
+;
+; CHECK-NOT: Valid Region for Scop:
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @hoge() #0 {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb
+  br i1 undef, label %bb2, label %bb7
+
+bb2:                                              ; preds = %bb1
+  %tmp = load i32, i32* undef, align 8, !tbaa !1
+  %tmp3 = tail call i32 @widget() #2
+  br i1 false, label %bb4, label %bb5
+
+bb4:                                              ; preds = %bb2
+  br label %bb8
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = sub i32 %tmp, %tmp3
+  br label %bb8
+
+bb7:                                              ; preds = %bb1
+  br label %bb8
+
+bb8:                                              ; preds = %bb7, %bb5, %bb4
+  ret void
+}
+
+; Function Attrs: inlinehint nounwind readonly uwtable
+declare i32 @widget() #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { inlinehint nounwind readonly uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readonly }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 252700) (llvm/trunk 252705)"}
+!1 = !{!2, !7, i64 8}
+!2 = !{!"cli_target_info", !3, i64 0, !6, i64 8, !4, i64 32}
+!3 = !{!"long", !4, i64 0}
+!4 = !{!"omnipotent char", !5, i64 0}
+!5 = !{!"Simple C/C++ TBAA"}
+!6 = !{!"cli_exe_info", !7, i64 0, !8, i64 4, !3, i64 8, !9, i64 16}
+!7 = !{!"int", !4, i64 0}
+!8 = !{!"short", !4, i64 0}
+!9 = !{!"any pointer", !4, i64 0}
diff --git a/final/test/ScopDetect/error-block-unreachable.ll b/final/test/ScopDetect/error-block-unreachable.ll
new file mode 100644
index 0000000..311d216
--- /dev/null
+++ b/final/test/ScopDetect/error-block-unreachable.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s
+
+; Verify that the scop detection does not crash on inputs with unreachable
+; blocks. Earlier we crashed when detecting error blocks.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @foo() {
+entry:
+  br label %while.cond
+
+while.cond:                                       ; preds = %for.end, %entry
+  br i1 false, label %for.end, label %while.end8
+
+while.cond1:                                      ; preds = %while.cond4
+  br i1 undef, label %while.body3, label %for.inc
+
+while.body3:                                      ; preds = %while.cond1
+  br label %while.cond4
+
+while.cond4:                                      ; preds = %while.cond4, %while.body3
+  br i1 undef, label %while.cond4, label %while.cond1
+
+for.inc:                                          ; preds = %while.cond1
+  %conv = zext i16 undef to i32
+  br label %for.end
+
+for.end:                                          ; preds = %for.inc, %while.cond
+  %conv.sink = phi i32 [ %conv, %for.inc ], [ 0, %while.cond ]
+  br label %while.cond
+
+while.end8:                                       ; preds = %while.cond
+  ret void
+}
diff --git a/final/test/ScopDetect/expand-region-correctly-2.ll b/final/test/ScopDetect/expand-region-correctly-2.ll
new file mode 100644
index 0000000..2ae08bd
--- /dev/null
+++ b/final/test/ScopDetect/expand-region-correctly-2.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-detect \
+; RUN:     -analyze < %s | FileCheck %s
+;
+; CHECK: Valid Region for Scop: if.end.1631 => for.cond.1647.outer
+;
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @qtm_decompress() #0 {
+entry:
+  br label %if.end.1631
+
+if.end.1631:                                      ; preds = %entry
+  br i1 false, label %for.cond.1647.preheader, label %if.then.1635
+
+if.then.1635:                                     ; preds = %if.end.1631
+  br label %for.cond.1647.preheader
+
+for.cond.1647.preheader:                          ; preds = %if.then.1635, %if.end.1631
+  br label %for.cond.1647.outer
+
+for.cond.1647.outer:                              ; preds = %do.end.1685, %for.cond.1647.preheader
+  %bits_needed.5.ph = phi i8 [ 8, %for.cond.1647.preheader ], [ undef, %do.end.1685 ]
+  br label %for.cond.1647
+
+for.cond.1647:                                    ; preds = %do.cond.1718, %for.cond.1647.outer
+  %bits_needed.5 = phi i8 [ 8, %do.cond.1718 ], [ %bits_needed.5.ph, %for.cond.1647.outer ]
+  br i1 undef, label %do.cond.1718, label %if.then.1659
+
+if.then.1659:                                     ; preds = %for.cond.1647
+  br i1 false, label %do.end.1685, label %cleanup.1785
+
+do.end.1685:                                      ; preds = %if.then.1659
+  br label %for.cond.1647.outer
+
+do.cond.1718:                                     ; preds = %for.cond.1647
+  br i1 false, label %land.lhs.true.1736, label %for.cond.1647
+
+land.lhs.true.1736:                               ; preds = %do.cond.1718
+  br label %if.then.1742
+
+if.then.1742:                                     ; preds = %land.lhs.true.1736
+  unreachable
+
+cleanup.1785:                                     ; preds = %if.then.1659
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 250010) (llvm/trunk 250018)"}
diff --git a/final/test/ScopDetect/expand-region-correctly.ll b/final/test/ScopDetect/expand-region-correctly.ll
new file mode 100644
index 0000000..ec1e7a7
--- /dev/null
+++ b/final/test/ScopDetect/expand-region-correctly.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-detect \
+; RUN:     -analyze < %s | FileCheck %s
+
+; CHECK: Valid Region for Scop: if.end.1631 => for.cond.1647.outer
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @qtm_decompress() {
+entry:
+  br label %while.cond.outer.outer
+
+while.cond.outer.outer:                           ; preds = %entry
+  br label %if.end.1631
+
+if.end.1631:                                      ; preds = %do.end.1721, %while.cond.outer.outer
+  br i1 false, label %for.cond.1647.preheader, label %if.then.1635
+
+if.then.1635:                                     ; preds = %if.end.1631
+  br label %for.cond.1647.preheader
+
+for.cond.1647.preheader:                          ; preds = %if.then.1635, %if.end.1631
+  br label %for.cond.1647.outer
+
+for.cond.1647.outer:                              ; preds = %do.end.1685, %for.cond.1647.preheader
+  %bits_needed.5.ph = phi i8 [ 8, %for.cond.1647.preheader ], [ 0, %do.end.1685 ]
+  br label %for.cond.1647
+
+for.cond.1647:                                    ; preds = %do.cond.1718, %for.cond.1647.outer
+  br i1 undef, label %do.cond.1718, label %if.then.1659
+
+if.then.1659:                                     ; preds = %for.cond.1647
+  br i1 false, label %do.end.1685, label %if.then.1662
+
+if.then.1662:                                     ; preds = %if.then.1659
+  unreachable
+
+do.end.1685:                                      ; preds = %if.then.1659
+  br label %for.cond.1647.outer
+
+do.cond.1718:                                     ; preds = %for.cond.1647
+  br i1 false, label %do.end.1721, label %for.cond.1647
+
+do.end.1721:                                      ; preds = %do.cond.1718
+  br label %if.end.1631
+}
diff --git a/final/test/ScopDetect/ignore_func_flag_regex.ll b/final/test/ScopDetect/ignore_func_flag_regex.ll
new file mode 100644
index 0000000..824cd40
--- /dev/null
+++ b/final/test/ScopDetect/ignore_func_flag_regex.ll
@@ -0,0 +1,124 @@
+; RUN: opt %loadPolly -polly-scops  -analyze -polly-ignore-func=f.*,g.* < %s | FileCheck %s
+;
+; Check that the flag `-polly-ignore-func` works with regexes.
+;
+; CHECK:      Function: h
+; CHECK-NEXT:    Region: %for.cond---%for.end
+;
+; CHECK-NOT:      Function:
+;
+; void f1(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+; void f2(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+; void g1(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+; void h(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f1(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+
+define void @f2(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+define void @g1(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+define void @h(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
diff --git a/final/test/ScopDetect/index_from_unpredictable_loop.ll b/final/test/ScopDetect/index_from_unpredictable_loop.ll
new file mode 100644
index 0000000..b9265ea
--- /dev/null
+++ b/final/test/ScopDetect/index_from_unpredictable_loop.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s --check-prefix=AFFINE
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s --check-prefix=NONAFFINE
+
+; The loop for.body => for.inc has an unpredictable iteration count could due to
+; the undef start value that it is compared to. Therefore the array element
+; %arrayidx101 that depends on that exit value cannot be affine.
+; Derived from test-suite/MultiSource/Benchmarks/BitBench/uuencode/uuencode.c
+
+define void @encode_line(i8* nocapture readonly %input, i32 %octets, i64 %p) {
+entry:
+  br i1 undef, label %for.body, label %for.end
+
+for.body:
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ %p, %entry ]
+  %octets.addr.02 = phi i32 [ undef, %for.inc ], [ %octets, %entry ]
+  br i1 false, label %for.inc, label %if.else
+
+if.else:
+  %cond = icmp eq i32 %octets.addr.02, 2
+  br i1 %cond, label %if.then84, label %for.end
+
+if.then84:
+  %0 = add nsw i64 %indvars.iv, 1
+  %arrayidx101 = getelementptr inbounds i8, i8* %input, i64 %0
+  store i8 42, i8* %arrayidx101, align 1
+  br label %for.end
+
+for.inc:
+  %cmp = icmp sgt i32 %octets.addr.02, 3
+  %indvars.iv.next = add nsw i64 %indvars.iv, 3
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+  ret void
+}
+
+; AFFINE:       Region: %if.else---%for.end
+
+; AFFINE:       Statements {
+; AFFINE-NEXT:  	Stmt_if_then84
+; AFFINE-NEXT:          Domain :=
+; AFFINE-NEXT:              [octets, p_1, p] -> { Stmt_if_then84[] : octets = 2 };
+; AFFINE-NEXT:          Schedule :=
+; AFFINE-NEXT:              [octets, p_1, p] -> { Stmt_if_then84[] -> [] };
+; AFFINE-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; AFFINE-NEXT:              [octets, p_1, p] -> { Stmt_if_then84[] -> MemRef_input[1 + p] };
+; AFFINE-NEXT:  }
+
+; NONAFFINE:      Region: %for.body---%for.end
+
+; NONAFFINE:      Statements {
+; NONAFFINE-NEXT: 	Stmt_for_body
+; NONAFFINE-NEXT:         Domain :=
+; NONAFFINE-NEXT:             [octets] -> { Stmt_for_body[0] };
+; NONAFFINE-NEXT:         Schedule :=
+; NONAFFINE-NEXT:             [octets] -> { Stmt_for_body[i0] -> [0, 0] };
+; NONAFFINE-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:             [octets] -> { Stmt_for_body[i0] -> MemRef_indvars_iv[] };
+; NONAFFINE-NEXT: 	Stmt_if_then84
+; NONAFFINE-NEXT:         Domain :=
+; NONAFFINE-NEXT:             [octets] -> { Stmt_if_then84[] : octets = 2 };
+; NONAFFINE-NEXT:         Schedule :=
+; NONAFFINE-NEXT:             [octets] -> { Stmt_if_then84[] -> [1, 0] };
+; NONAFFINE-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:             [octets] -> { Stmt_if_then84[] -> MemRef_indvars_iv[] };
+; NONAFFINE-NEXT:         MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:             [octets] -> { Stmt_if_then84[] -> MemRef_input[o0] };
+; NONAFFINE-NEXT: }
diff --git a/final/test/ScopDetect/index_from_unpredictable_loop2.ll b/final/test/ScopDetect/index_from_unpredictable_loop2.ll
new file mode 100644
index 0000000..2020fdf
--- /dev/null
+++ b/final/test/ScopDetect/index_from_unpredictable_loop2.ll
@@ -0,0 +1,86 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s --check-prefix=AFFINE
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s --check-prefix=NONAFFINE
+
+; The loop for.body => for.inc has an unpredictable iteration count could due to
+; the undef start value that it is compared to. Therefore the array element
+; %arrayidx101 that depends on that exit value cannot be affine.
+; Derived from test-suite/MultiSource/Benchmarks/BitBench/uuencode/uuencode.c
+
+define void @encode_line(i8* nocapture readonly %input, i32 %octets, i64 %p, i32 %n) {
+entry:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %entry], [%j.inc, %for.end]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %for.body, label %exit
+
+
+
+for.body:
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ %p, %outer.for ]
+  %octets.addr.02 = phi i32 [ undef, %for.inc ], [ %octets, %outer.for ]
+  br i1 false, label %for.inc, label %if.else
+
+if.else:
+  %cond = icmp eq i32 %octets.addr.02, 2
+  br i1 %cond, label %if.then84, label %for.end
+
+if.then84:
+  %0 = add nsw i64 %indvars.iv, 1
+  %arrayidx101 = getelementptr inbounds i8, i8* %input, i64 %0
+  store i8 42, i8* %arrayidx101, align 1
+  br label %for.end
+
+for.inc:
+  %cmp = icmp sgt i32 %octets.addr.02, 3
+  %indvars.iv.next = add nsw i64 %indvars.iv, 3
+  br i1 %cmp, label %for.body, label %for.end
+
+
+
+for.end:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; AFFINE:       Region: %if.else---%for.end
+
+; AFFINE:       Statements {
+; AFFINE-NEXT:  	Stmt_if_then84
+; AFFINE-NEXT:          Domain :=
+; AFFINE-NEXT:              [octets, p_1, p] -> { Stmt_if_then84[] : octets = 2 };
+; AFFINE-NEXT:          Schedule :=
+; AFFINE-NEXT:              [octets, p_1, p] -> { Stmt_if_then84[] -> [] };
+; AFFINE-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; AFFINE-NEXT:              [octets, p_1, p] -> { Stmt_if_then84[] -> MemRef_input[1 + p] };
+; AFFINE-NEXT:  }
+
+
+; NONAFFINE:      Region: %outer.for---%return
+
+; NONAFFINE:      Statements {
+; NONAFFINE-NEXT: 	Stmt_for_body
+; NONAFFINE-NEXT:         Domain :=
+; NONAFFINE-NEXT:             [n, octets] -> { Stmt_for_body[i0, 0] : 0 <= i0 < n };
+; NONAFFINE-NEXT:         Schedule :=
+; NONAFFINE-NEXT:             [n, octets] -> { Stmt_for_body[i0, i1] -> [i0, 0, 0] };
+; NONAFFINE-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:             [n, octets] -> { Stmt_for_body[i0, i1] -> MemRef_indvars_iv[] };
+; NONAFFINE-NEXT: 	Stmt_if_then84
+; NONAFFINE-NEXT:         Domain :=
+; NONAFFINE-NEXT:             [n, octets] -> { Stmt_if_then84[i0] : octets = 2 and 0 <= i0 < n };
+; NONAFFINE-NEXT:         Schedule :=
+; NONAFFINE-NEXT:             [n, octets] -> { Stmt_if_then84[i0] -> [i0, 1, 0] };
+; NONAFFINE-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:             [n, octets] -> { Stmt_if_then84[i0] -> MemRef_indvars_iv[] };
+; NONAFFINE-NEXT:         MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:             [n, octets] -> { Stmt_if_then84[i0] -> MemRef_input[o0] };
+; NONAFFINE-NEXT: }
diff --git a/final/test/ScopDetect/indvars.ll b/final/test/ScopDetect/indvars.ll
new file mode 100644
index 0000000..d089b0f
--- /dev/null
+++ b/final/test/ScopDetect/indvars.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -analyze -polly-detect -polly-codegen < %s | FileCheck %s
+;
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @main(i64* %A, i64* %B) nounwind {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ 0, %entry ], [ %indvar.next.i, %for.i.backedge ]
+  %indvar.next.i = add i64 %indvar.i, 1
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar.i
+  store i64 %indvar.i, i64* %scevgep, align 4
+  br i1 true, label %for.j.preheader, label %for.j2
+
+for.j.preheader:
+  br label %for.j
+
+for.j:
+  %indvar.j = phi i64 [ %indvar.next.j, %for.j ], [ 0, %for.j.preheader ]
+  %indvar.next.j = add i64 %indvar.j, 1
+  %scevgep2 = getelementptr i64, i64* %B, i64 %indvar.j
+  store i64 %indvar.j, i64* %scevgep2, align 4
+  %exitcond.j = icmp eq i64 %indvar.next.j, 10
+  br i1 %exitcond.j, label %for.j2, label %for.j
+
+for.j2:
+  fence seq_cst
+  br label %for.i.backedge
+
+for.i.backedge:
+  %exitcond.i = icmp eq i64 %indvar.next.i, 2048
+  br i1 %exitcond.i, label %for.i, label %.end
+
+.end:
+  ret void
+}
+
+; CHECK: Valid Region for Scop: for.i => for.j2
diff --git a/final/test/ScopDetect/intrinsics_1.ll b/final/test/ScopDetect/intrinsics_1.ll
new file mode 100644
index 0000000..592c29d
--- /dev/null
+++ b/final/test/ScopDetect/intrinsics_1.ll
@@ -0,0 +1,106 @@
+; RUN: opt %loadPolly -basicaa -polly-detect -analyze < %s | FileCheck %s
+;
+; CHECK: Valid Region for Scop: for.cond => for.end
+;
+;    #include "math.h"
+;
+;    void jd(int *restrict A, float *restrict B) {
+;      for (int i = 0; i < 1024; i++) {
+;        A[i] = pow(ceil(log10(sqrt(i))), floor(log2(i)));
+;        B[i] = fabs(log(sin(i)) + exp2(cos(i))) + exp(i);
+;      }
+;    }
+;
+; ModuleID = '/home/johannes/repos/polly/test/ScopDetect/intrinsics.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @jd(i32* noalias %A, float* noalias %B) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = trunc i64 %indvars.iv to i32
+  %conv = sitofp i32 %tmp to double
+  %tmp1 = call double @llvm.sqrt.f64(double %conv)
+  %call = call double @__log10_finite(double %tmp1) #2
+  %call1 = call double @ceil(double %call) #2
+  %tmp2 = trunc i64 %indvars.iv to i32
+  %conv2 = sitofp i32 %tmp2 to double
+  %call3 = call double @__log2_finite(double %conv2) #2
+  %call4 = call double @floor(double %call3) #2
+  %tmp3 = call double @llvm.pow.f64(double %call1, double %call4)
+  %conv5 = fptosi double %tmp3 to i32
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %conv5, i32* %arrayidx, align 4
+  %tmp4 = trunc i64 %indvars.iv to i32
+  %conv6 = sitofp i32 %tmp4 to double
+  %call7 = call double @sin(double %conv6) #2
+  %call8 = call double @__log_finite(double %call7) #2
+  %tmp5 = trunc i64 %indvars.iv to i32
+  %conv9 = sitofp i32 %tmp5 to double
+  %call10 = call double @cos(double %conv9) #2
+  %call11 = call double @__exp2_finite(double %call10) #2
+  %add = fadd fast double %call8, %call11
+  %call12 = call double @fabs(double %add) #2
+  %tmp6 = trunc i64 %indvars.iv to i32
+  %conv13 = sitofp i32 %tmp6 to double
+  %call14 = call double @__exp_finite(double %conv13) #2
+  %add15 = fadd fast double %call12, %call14
+  %conv16 = fptrunc double %add15 to float
+  %arrayidx18 = getelementptr inbounds float, float* %B, i64 %indvars.iv
+  store float %conv16, float* %arrayidx18, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: nounwind readnone
+declare double @ceil(double) #1
+
+; Function Attrs: nounwind readnone
+declare double @__log10_finite(double) #1
+
+; Function Attrs: nounwind readnone
+declare double @llvm.sqrt.f64(double) #2
+
+; Function Attrs: nounwind readnone
+declare double @floor(double) #1
+
+; Function Attrs: nounwind readnone
+declare double @__log2_finite(double) #1
+
+; Function Attrs: nounwind readnone
+declare double @llvm.pow.f64(double, double) #2
+
+; Function Attrs: nounwind readnone
+declare double @fabs(double) #1
+
+; Function Attrs: nounwind readnone
+declare double @__log_finite(double) #1
+
+; Function Attrs: nounwind readnone
+declare double @sin(double) #1
+
+; Function Attrs: nounwind readnone
+declare double @__exp2_finite(double) #1
+
+; Function Attrs: nounwind readnone
+declare double @cos(double) #1
+
+; Function Attrs: nounwind readnone
+declare double @__exp_finite(double) #1
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="true" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="true" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
diff --git a/final/test/ScopDetect/intrinsics_2.ll b/final/test/ScopDetect/intrinsics_2.ll
new file mode 100644
index 0000000..3a2ad3a
--- /dev/null
+++ b/final/test/ScopDetect/intrinsics_2.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -basicaa -polly-detect -analyze < %s | FileCheck %s
+;
+; Verify that we allow the lifetime markers for the tmp array.
+;
+; CHECK: Valid Region for Scop: for.cond => for.end13
+;
+;    int A[1024];
+;    void jd() {
+;      for (int i = 0; i < 1024; i++) {
+;        int tmp[1024];
+;        for (int j = i; j < 1024; j++)
+;          tmp[i] += A[j];
+;        A[i] = tmp[i];
+;      }
+;    }
+;
+; ModuleID = 'test/Isl/CodeGen/lifetime_intrinsics.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@A = common global [1024 x i32] zeroinitializer, align 16
+
+; Function Attrs: nounwind uwtable
+define void @jd() #0 {
+entry:
+  %tmp = alloca [1024 x i32], align 16
+  %tmp3 = bitcast [1024 x i32]* %tmp to i8*
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc11, %entry
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc11 ], [ 0, %entry ]
+  %exitcond5 = icmp ne i64 %indvars.iv3, 1024
+  br i1 %exitcond5, label %for.body, label %for.end13
+
+for.body:                                         ; preds = %for.cond
+  call void @llvm.lifetime.start(i64 4096, i8* %tmp3) #1
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc, %for.body
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc ], [ %indvars.iv3, %for.body ]
+  %lftr.wideiv = trunc i64 %indvars.iv1 to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, 1024
+  br i1 %exitcond, label %for.body4, label %for.end
+
+for.body4:                                        ; preds = %for.cond2
+  %arrayidx = getelementptr inbounds [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvars.iv1
+  %tmp6 = load i32, i32* %arrayidx, align 4
+  %arrayidx6 = getelementptr inbounds [1024 x i32], [1024 x i32]* %tmp, i64 0, i64 %indvars.iv3
+  %tmp7 = load i32, i32* %arrayidx6, align 4
+  %add = add nsw i32 %tmp7, %tmp6
+  store i32 %add, i32* %arrayidx6, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body4
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %for.cond2
+
+for.end:                                          ; preds = %for.cond2
+  %arrayidx8 = getelementptr inbounds [1024 x i32], [1024 x i32]* %tmp, i64 0, i64 %indvars.iv3
+  %tmp8 = load i32, i32* %arrayidx8, align 4
+  %arrayidx10 = getelementptr inbounds [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvars.iv3
+  store i32 %tmp8, i32* %arrayidx10, align 4
+  br label %for.inc11
+
+for.inc11:                                        ; preds = %for.end
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  call void @llvm.lifetime.end(i64 4096, i8* %tmp3) #1
+  br label %for.cond
+
+for.end13:                                        ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: nounwind
+declare void @llvm.lifetime.start(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind
+declare void @llvm.lifetime.end(i64, i8* nocapture) #1
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="true" "use-soft-float"="false" }
+attributes #1 = { nounwind }
diff --git a/final/test/ScopDetect/intrinsics_3.ll b/final/test/ScopDetect/intrinsics_3.ll
new file mode 100644
index 0000000..8509dff
--- /dev/null
+++ b/final/test/ScopDetect/intrinsics_3.ll
@@ -0,0 +1,92 @@
+; RUN: opt %loadPolly -basicaa -polly-detect -analyze < %s | FileCheck %s
+;
+; Verify that we allow the misc intrinsics.
+;
+; CHECK: Valid Region for Scop: for.cond => for.end13
+;
+;    int A[1024];
+;    void jd() {
+;      for (int i = 0; i < 1024; i++) {
+;        int tmp[1024];
+;        for (int j = i; j < 1024; j++)
+;          tmp[i] += A[j];
+;        A[i] = tmp[i];
+;      }
+;    }
+;
+; ModuleID = 'test/Isl/CodeGen/lifetime_intrinsics.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@A = common global [1024 x i32] zeroinitializer, align 16
+
+; Function Attrs: nounwind uwtable
+define void @jd() #0 {
+entry:
+  %tmp = alloca [1024 x i32], align 16
+  %tmp3 = bitcast [1024 x i32]* @A to i8*
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc11, %entry
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc11 ], [ 0, %entry ]
+  %exitcond5 = icmp ne i64 %indvars.iv3, 1024
+  br i1 %exitcond5, label %for.body, label %for.end13
+
+for.body:                                         ; preds = %for.cond
+  %lis = call {}* @llvm.invariant.start(i64 4096, i8* %tmp3) #1
+  br label %for.cond2
+
+for.cond2:                                        ; preds = %for.inc, %for.body
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc ], [ %indvars.iv3, %for.body ]
+  %lftr.wideiv = trunc i64 %indvars.iv1 to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, 1024
+  br i1 %exitcond, label %for.body4, label %for.end
+
+for.body4:                                        ; preds = %for.cond2
+  call void @llvm.assume(i1 %exitcond)
+  call i1 @llvm.expect.i1(i1 %exitcond, i1 1)
+  %arrayidx = getelementptr inbounds [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvars.iv1
+  %tmp6 = load i32, i32* %arrayidx, align 4
+  %arrayidx6 = getelementptr inbounds [1024 x i32], [1024 x i32]* %tmp, i64 0, i64 %indvars.iv3
+  call void @llvm.donothing()
+  %tmp7 = load i32, i32* %arrayidx6, align 4
+  %add = add nsw i32 %tmp7, %tmp6
+  store i32 %add, i32* %arrayidx6, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body4
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %for.cond2
+
+for.end:                                          ; preds = %for.cond2
+  %arrayidx8 = getelementptr inbounds [1024 x i32], [1024 x i32]* %tmp, i64 0, i64 %indvars.iv3
+  %tmp8 = load i32, i32* %arrayidx8, align 4
+  %arrayidx10 = getelementptr inbounds [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvars.iv3
+  call void @llvm.invariant.end({}* %lis, i64 4096, i8* %tmp3) #1
+  store i32 %tmp8, i32* %arrayidx10, align 4
+  br label %for.inc11
+
+for.inc11:                                        ; preds = %for.end
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  br label %for.cond
+
+for.end13:                                        ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: nounwind
+declare void @llvm.donothing() #1
+
+; Function Attrs: nounwind
+declare void @llvm.assume(i1) #1
+
+; Function Attrs: nounwind
+declare i1 @llvm.expect.i1(i1, i1) #1
+
+; Function Attrs: nounwind
+declare {}* @llvm.invariant.start(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind
+declare void @llvm.invariant.end({}*, i64, i8* nocapture) #1
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="true" "use-soft-float"="false" }
+attributes #1 = { nounwind }
diff --git a/final/test/ScopDetect/invalid-latch-conditions.ll b/final/test/ScopDetect/invalid-latch-conditions.ll
new file mode 100644
index 0000000..debec14
--- /dev/null
+++ b/final/test/ScopDetect/invalid-latch-conditions.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-process-unprofitable=false \
+; RUN:     -polly-detect -analyze < %s | FileCheck %s
+
+; RUN: opt %loadPolly -polly-allow-nonaffine-loops \
+; RUN:     -polly-detect -analyze < %s | FileCheck %s --check-prefix=NALOOPS
+
+; RUN: opt %loadPolly -polly-allow-nonaffine-loops -polly-detect -analyze \
+; RUN:     -polly-process-unprofitable=false < %s | \
+; RUN:     FileCheck %s --check-prefix=PROFIT
+
+; The latch conditions of the outer loop are not affine, thus the loop cannot
+; handled by the domain generation and needs to be overapproximated.
+
+; CHECK-NOT:  Valid
+; NALOOPS:    Valid Region for Scop: for.body.6 => for.end.45
+; PROFIT-NOT: Valid
+
+; ModuleID = '/home/johannes/Downloads/bug.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @kernel_reg_detect([6 x i32]* %path) #0 {
+entry:
+  br label %for.body.6
+
+for.body.6:                                       ; preds = %for.inc.43, %for.body.6, %entry
+  %indvars.iv9 = phi i64 [ %indvars.iv.next10, %for.body.6 ], [ 0, %for.inc.43 ], [ 0, %entry ]
+  %indvars.iv.next10 = add nuw nsw i64 %indvars.iv9, 1
+  %lftr.wideiv = trunc i64 %indvars.iv.next10 to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, 6
+  br i1 %exitcond, label %for.body.6, label %for.inc.40
+
+for.inc.40:                                       ; preds = %for.inc.40, %for.body.6
+  %arrayidx28 = getelementptr inbounds [6 x i32], [6 x i32]* %path, i64 0, i64 0
+  %tmp = load i32, i32* %arrayidx28, align 4
+  %arrayidx36 = getelementptr inbounds [6 x i32], [6 x i32]* %path, i64 0, i64 0
+  store i32 0, i32* %arrayidx36, align 4
+  %exitcond22 = icmp ne i64 0, 6
+  br i1 %exitcond22, label %for.inc.40, label %for.inc.43
+
+for.inc.43:                                       ; preds = %for.inc.40
+  %exitcond23 = icmp ne i32 0, 10000
+  br i1 %exitcond23, label %for.body.6, label %for.end.45
+
+for.end.45:                                       ; preds = %for.inc.43
+  ret void
+}
diff --git a/final/test/ScopDetect/invalidate_scalar_evolution.ll b/final/test/ScopDetect/invalidate_scalar_evolution.ll
new file mode 100644
index 0000000..357a62e
--- /dev/null
+++ b/final/test/ScopDetect/invalidate_scalar_evolution.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-detect -analyze  < %s | FileCheck %s -check-prefix=PHI
+
+; void f(long A[], long N) {
+;   long i;
+;   for (i = 0; i < N; ++i)
+;     A[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N, i64 %p) nounwind {
+entry:
+  fence seq_cst
+  br label %pre
+
+pre:
+  %p_tmp = srem i64 %p, 5
+  br i1 true, label %for.i, label %then
+
+for.i:
+  %indvar = phi i64 [ 0, %pre ], [ %indvar.next, %for.i ]
+  %indvar.p1 = phi i64 [ 0, %pre ], [ %indvar.p1.next, %for.i ]
+  %indvar.p2 = phi i64 [ 0, %pre ], [ %indvar.p2.next, %for.i ]
+  %sum = add i64 %indvar, %indvar.p1
+  %sum2 = sub i64 %sum, %indvar.p2
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %indvar.p1.next = add nsw i64 %indvar.p1, %p_tmp
+  %indvar.p2.next = add nsw i64 %indvar.p2, %p_tmp
+  %exitcond = icmp eq i64 %sum2, %N
+  br i1 %exitcond, label %then, label %for.i
+
+then:
+  br label %return
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; PHI: Valid Region for Scop: pre => return
diff --git a/final/test/ScopDetect/invariant-load-before-scop.ll b/final/test/ScopDetect/invariant-load-before-scop.ll
new file mode 100644
index 0000000..feed0d0
--- /dev/null
+++ b/final/test/ScopDetect/invariant-load-before-scop.ll
@@ -0,0 +1,84 @@
+; RUN: opt %loadPolly -polly-detect -polly-scops -analyze < %s | FileCheck %s -match-full-lines
+;
+; The LoadInst %.b761 is defined outside the SCoP, hence is always constant
+; within it. It is no "required invariant load".
+; This test is designed to ensure that %.b761 is not added to the list of
+; "required invariant loads" which causes an assertion fail in ScopInfo.
+; ScopInfo rejects the SCoP, so we cannot check the list if invariant loads.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%"struct.pov::Frame_Struct.37.89.245.349.401.505.557.713.817.869.1129.1493.1649.2013.2065.2117.2325.3312.36.110.184.258.332.1072" = type { %"struct.pov::Camera_Struct.12.64.220.324.376.480.532.688.792.844.1104.1468.1624.1988.2040.2092.2300.3287.11.85.159.233.307.1047"*, i32, i32, i32, %"struct.pov::Light_Source_Struct.31.83.239.343.395.499.551.707.811.863.1123.1487.1643.2007.2059.2111.2319.3306.30.104.178.252.326.1066"*, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, double, double, double, [5 x float], [5 x float], [5 x float], %"struct.pov::Media_Struct.20.72.228.332.384.488.540.696.800.852.1112.1476.1632.1996.2048.2100.2308.3295.19.93.167.241.315.1055"*, %"struct.pov::Fog_Struct.33.85.241.345.397.501.553.709.813.865.1125.1489.1645.2009.2061.2113.2321.3308.32.106.180.254.328.1068"*, %"struct.pov::Rainbow_Struct.34.86.242.346.398.502.554.710.814.866.1126.1490.1646.2010.2062.2114.2322.3309.33.107.181.255.329.1069"*, %"struct.pov::Skysphere_Struct.35.87.243.347.399.503.555.711.815.867.1127.1491.1647.2011.2063.2115.2323.3310.34.108.182.256.330.1070"*, %"struct.pov::light_group_light_struct.36.88.244.348.400.504.556.712.816.868.1128.1492.1648.2012.2064.2116.2324.3311.35.109.183.257.331.1071"* }
+%"struct.pov::Camera_Struct.12.64.220.324.376.480.532.688.792.844.1104.1468.1624.1988.2040.2092.2300.3287.11.85.159.233.307.1047" = type { [3 x double], [3 x double], [3 x double], [3 x double], [3 x double], [3 x double], [3 x double], double, double, i32, double, double, i32, double, double, double, %"struct.pov::Tnormal_Struct.10.62.218.322.374.478.530.686.790.842.1102.1466.1622.1986.2038.2090.2298.3285.9.83.157.231.305.1045"*, %"struct.pov::Transform_Struct.11.63.219.323.375.479.531.687.791.843.1103.1467.1623.1987.2039.2091.2299.3286.10.84.158.232.306.1046"* }
+%"struct.pov::Tnormal_Struct.10.62.218.322.374.478.530.686.790.842.1102.1466.1622.1986.2038.2090.2298.3285.9.83.157.231.305.1045" = type { i16, i16, i16, i32, float, float, float, %"struct.pov::Warps_Struct.1.53.209.313.365.469.521.677.781.833.1093.1457.1613.1977.2029.2081.2289.3276.0.74.148.222.296.1036"*, %"struct.pov::Pattern_Struct.7.59.215.319.371.475.527.683.787.839.1099.1463.1619.1983.2035.2087.2295.3282.6.80.154.228.302.1042"*, %"struct.pov::Blend_Map_Struct.4.56.212.316.368.472.524.680.784.836.1096.1460.1616.1980.2032.2084.2292.3279.3.77.151.225.299.1039"*, %union.anon.25.9.61.217.321.373.477.529.685.789.841.1101.1465.1621.1985.2037.2089.2297.3284.8.82.156.230.304.1044, float, float }
+%"struct.pov::Warps_Struct.1.53.209.313.365.469.521.677.781.833.1093.1457.1613.1977.2029.2081.2289.3276.0.74.148.222.296.1036" = type { i16, %"struct.pov::Warps_Struct.1.53.209.313.365.469.521.677.781.833.1093.1457.1613.1977.2029.2081.2289.3276.0.74.148.222.296.1036"*, %"struct.pov::Warps_Struct.1.53.209.313.365.469.521.677.781.833.1093.1457.1613.1977.2029.2081.2289.3276.0.74.148.222.296.1036"* }
+%"struct.pov::Pattern_Struct.7.59.215.319.371.475.527.683.787.839.1099.1463.1619.1983.2035.2087.2295.3282.6.80.154.228.302.1042" = type { i16, i16, i16, i32, float, float, float, %"struct.pov::Warps_Struct.1.53.209.313.365.469.521.677.781.833.1093.1457.1613.1977.2029.2081.2289.3276.0.74.148.222.296.1036"*, %"struct.pov::Pattern_Struct.7.59.215.319.371.475.527.683.787.839.1099.1463.1619.1983.2035.2087.2295.3282.6.80.154.228.302.1042"*, %"struct.pov::Blend_Map_Struct.4.56.212.316.368.472.524.680.784.836.1096.1460.1616.1980.2032.2084.2292.3279.3.77.151.225.299.1039"*, %union.anon.17.6.58.214.318.370.474.526.682.786.838.1098.1462.1618.1982.2034.2086.2294.3281.5.79.153.227.301.1041 }
+%union.anon.17.6.58.214.318.370.474.526.682.786.838.1098.1462.1618.1982.2034.2086.2294.3281.5.79.153.227.301.1041 = type { %struct.anon.21.5.57.213.317.369.473.525.681.785.837.1097.1461.1617.1981.2033.2085.2293.3280.4.78.152.226.300.1040 }
+%struct.anon.21.5.57.213.317.369.473.525.681.785.837.1097.1461.1617.1981.2033.2085.2293.3280.4.78.152.226.300.1040 = type { [3 x double], [3 x double], double, double, i16, [3 x double]*, i32, [3 x double] }
+%"struct.pov::Blend_Map_Struct.4.56.212.316.368.472.524.680.784.836.1096.1460.1616.1980.2032.2084.2292.3279.3.77.151.225.299.1039" = type { i32, i16, i8, i8, %"struct.pov::Blend_Map_Entry.3.55.211.315.367.471.523.679.783.835.1095.1459.1615.1979.2031.2083.2291.3278.2.76.150.224.298.1038"* }
+%"struct.pov::Blend_Map_Entry.3.55.211.315.367.471.523.679.783.835.1095.1459.1615.1979.2031.2083.2291.3278.2.76.150.224.298.1038" = type { float, i8, %union.anon.2.54.210.314.366.470.522.678.782.834.1094.1458.1614.1978.2030.2082.2290.3277.1.75.149.223.297.1037 }
+%union.anon.2.54.210.314.366.470.522.678.782.834.1094.1458.1614.1978.2030.2082.2290.3277.1.75.149.223.297.1037 = type { [2 x double], [8 x i8] }
+%union.anon.25.9.61.217.321.373.477.529.685.789.841.1101.1465.1621.1985.2037.2089.2297.3284.8.82.156.230.304.1044 = type { %struct.anon.29.8.60.216.320.372.476.528.684.788.840.1100.1464.1620.1984.2036.2088.2296.3283.7.81.155.229.303.1043 }
+%struct.anon.29.8.60.216.320.372.476.528.684.788.840.1100.1464.1620.1984.2036.2088.2296.3283.7.81.155.229.303.1043 = type { [3 x double], [3 x double], double, double, i16, [3 x double]*, i32, [3 x double] }
+%"struct.pov::Transform_Struct.11.63.219.323.375.479.531.687.791.843.1103.1467.1623.1987.2039.2091.2299.3286.10.84.158.232.306.1046" = type { [4 x [4 x double]], [4 x [4 x double]] }
+%"struct.pov::Light_Source_Struct.31.83.239.343.395.499.551.707.811.863.1123.1487.1643.2007.2059.2111.2319.3306.30.104.178.252.326.1066" = type { %"struct.pov::Method_Struct.27.79.235.339.391.495.547.703.807.859.1119.1483.1639.2003.2055.2107.2315.3302.26.100.174.248.322.1062"*, i32, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, %"struct.pov::Texture_Struct.19.71.227.331.383.487.539.695.799.851.1111.1475.1631.1995.2047.2099.2307.3294.18.92.166.240.314.1054"*, %"struct.pov::Texture_Struct.19.71.227.331.383.487.539.695.799.851.1111.1475.1631.1995.2047.2099.2307.3294.18.92.166.240.314.1054"*, %"struct.pov::Interior_Struct.21.73.229.333.385.489.541.697.801.853.1113.1477.1633.1997.2049.2101.2309.3296.20.94.168.242.316.1056"*, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, %"struct.pov::Light_Source_Struct.31.83.239.343.395.499.551.707.811.863.1123.1487.1643.2007.2059.2111.2319.3306.30.104.178.252.326.1066"*, %"struct.pov::Bounding_Box_Struct.22.74.230.334.386.490.542.698.802.854.1114.1478.1634.1998.2050.2102.2310.3297.21.95.169.243.317.1057", %"struct.pov::Transform_Struct.11.63.219.323.375.479.531.687.791.843.1103.1467.1623.1987.2039.2091.2299.3286.10.84.158.232.306.1046"*, %"struct.pov::Transform_Struct.11.63.219.323.375.479.531.687.791.843.1103.1467.1623.1987.2039.2091.2299.3286.10.84.158.232.306.1046"*, float, i32, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, [5 x float], [3 x double], [3 x double], [3 x double], [3 x double], [3 x double], double, double, double, double, double, %"struct.pov::Light_Source_Struct.31.83.239.343.395.499.551.707.811.863.1123.1487.1643.2007.2059.2111.2319.3306.30.104.178.252.326.1066"*, i8, i8, i8, i8, i8, i8, i8, i8, i32, i32, i32, i32, i32, [5 x float]**, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, %"struct.pov::Blend_Map_Struct.4.56.212.316.368.472.524.680.784.836.1096.1460.1616.1980.2032.2084.2292.3279.3.77.151.225.299.1039"*, [6 x %"struct.pov::Project_Tree_Node_Struct.30.82.238.342.394.498.550.706.810.862.1122.1486.1642.2006.2058.2110.2318.3305.29.103.177.251.325.1065"*] }
+%"struct.pov::Method_Struct.27.79.235.339.391.495.547.703.807.859.1119.1483.1639.2003.2055.2107.2315.3302.26.100.174.248.322.1062" = type { i32 (%"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, %"struct.pov::Ray_Struct.24.76.232.336.388.492.544.700.804.856.1116.1480.1636.2000.2052.2104.2312.3299.23.97.171.245.319.1059"*, %"struct.pov::istack_struct.26.78.234.338.390.494.546.702.806.858.1118.1482.1638.2002.2054.2106.2314.3301.25.99.173.247.321.1061"*)*, i32 (double*, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*)*, void (double*, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, %"struct.pov::istk_entry.25.77.233.337.389.493.545.701.805.857.1117.1481.1637.2001.2053.2105.2313.3300.24.98.172.246.320.1060"*)*, void (double*, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, %"struct.pov::istk_entry.25.77.233.337.389.493.545.701.805.857.1117.1481.1637.2001.2053.2105.2313.3300.24.98.172.246.320.1060"*)*, i8* (%"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*)*, void (%"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, double*, %"struct.pov::Transform_Struct.11.63.219.323.375.479.531.687.791.843.1103.1467.1623.1987.2039.2091.2299.3286.10.84.158.232.306.1046"*)*, void (%"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, double*, %"struct.pov::Transform_Struct.11.63.219.323.375.479.531.687.791.843.1103.1467.1623.1987.2039.2091.2299.3286.10.84.158.232.306.1046"*)*, void (%"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, double*, %"struct.pov::Transform_Struct.11.63.219.323.375.479.531.687.791.843.1103.1467.1623.1987.2039.2091.2299.3286.10.84.158.232.306.1046"*)*, void (%"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, %"struct.pov::Transform_Struct.11.63.219.323.375.479.531.687.791.843.1103.1467.1623.1987.2039.2091.2299.3286.10.84.158.232.306.1046"*)*, void (%"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*)*, void (%"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*)* }
+%"struct.pov::Ray_Struct.24.76.232.336.388.492.544.700.804.856.1116.1480.1636.2000.2052.2104.2312.3299.23.97.171.245.319.1059" = type { [3 x double], [3 x double], i32, i32, [100 x %"struct.pov::Interior_Struct.21.73.229.333.385.489.541.697.801.853.1113.1477.1633.1997.2049.2101.2309.3296.20.94.168.242.316.1056"*] }
+%"struct.pov::istack_struct.26.78.234.338.390.494.546.702.806.858.1118.1482.1638.2002.2054.2106.2314.3301.25.99.173.247.321.1061" = type { %"struct.pov::istack_struct.26.78.234.338.390.494.546.702.806.858.1118.1482.1638.2002.2054.2106.2314.3301.25.99.173.247.321.1061"*, %"struct.pov::istk_entry.25.77.233.337.389.493.545.701.805.857.1117.1481.1637.2001.2053.2105.2313.3300.24.98.172.246.320.1060"*, i32, i32 }
+%"struct.pov::istk_entry.25.77.233.337.389.493.545.701.805.857.1117.1481.1637.2001.2053.2105.2313.3300.24.98.172.246.320.1060" = type { double, [3 x double], [3 x double], [3 x double], [2 x double], %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, i32, i32, double, double, double, double, double, double, double, double, double, i8*, i8* }
+%"struct.pov::Texture_Struct.19.71.227.331.383.487.539.695.799.851.1111.1475.1631.1995.2047.2099.2307.3294.18.92.166.240.314.1054" = type { i16, i16, i16, i32, float, float, float, %"struct.pov::Warps_Struct.1.53.209.313.365.469.521.677.781.833.1093.1457.1613.1977.2029.2081.2289.3276.0.74.148.222.296.1036"*, %"struct.pov::Pattern_Struct.7.59.215.319.371.475.527.683.787.839.1099.1463.1619.1983.2035.2087.2295.3282.6.80.154.228.302.1042"*, %"struct.pov::Blend_Map_Struct.4.56.212.316.368.472.524.680.784.836.1096.1460.1616.1980.2032.2084.2292.3279.3.77.151.225.299.1039"*, %union.anon.9.14.66.222.326.378.482.534.690.794.846.1106.1470.1626.1990.2042.2094.2302.3289.13.87.161.235.309.1049, %"struct.pov::Texture_Struct.19.71.227.331.383.487.539.695.799.851.1111.1475.1631.1995.2047.2099.2307.3294.18.92.166.240.314.1054"*, %"struct.pov::Pigment_Struct.17.69.225.329.381.485.537.693.797.849.1109.1473.1629.1993.2045.2097.2305.3292.16.90.164.238.312.1052"*, %"struct.pov::Tnormal_Struct.10.62.218.322.374.478.530.686.790.842.1102.1466.1622.1986.2038.2090.2298.3285.9.83.157.231.305.1045"*, %"struct.pov::Finish_Struct.18.70.226.330.382.486.538.694.798.850.1110.1474.1630.1994.2046.2098.2306.3293.17.91.165.239.313.1053"*, %"struct.pov::Texture_Struct.19.71.227.331.383.487.539.695.799.851.1111.1475.1631.1995.2047.2099.2307.3294.18.92.166.240.314.1054"*, i32 }
+%union.anon.9.14.66.222.326.378.482.534.690.794.846.1106.1470.1626.1990.2042.2094.2302.3289.13.87.161.235.309.1049 = type { %struct.anon.13.13.65.221.325.377.481.533.689.793.845.1105.1469.1625.1989.2041.2093.2301.3288.12.86.160.234.308.1048 }
+%struct.anon.13.13.65.221.325.377.481.533.689.793.845.1105.1469.1625.1989.2041.2093.2301.3288.12.86.160.234.308.1048 = type { [3 x double], [3 x double], double, double, i16, [3 x double]*, i32, [3 x double] }
+%"struct.pov::Pigment_Struct.17.69.225.329.381.485.537.693.797.849.1109.1473.1629.1993.2045.2097.2305.3292.16.90.164.238.312.1052" = type { i16, i16, i16, i32, float, float, float, %"struct.pov::Warps_Struct.1.53.209.313.365.469.521.677.781.833.1093.1457.1613.1977.2029.2081.2289.3276.0.74.148.222.296.1036"*, %"struct.pov::Pattern_Struct.7.59.215.319.371.475.527.683.787.839.1099.1463.1619.1983.2035.2087.2295.3282.6.80.154.228.302.1042"*, %"struct.pov::Blend_Map_Struct.4.56.212.316.368.472.524.680.784.836.1096.1460.1616.1980.2032.2084.2292.3279.3.77.151.225.299.1039"*, %union.anon.0.16.68.224.328.380.484.536.692.796.848.1108.1472.1628.1992.2044.2096.2304.3291.15.89.163.237.311.1051, [5 x float] }
+%union.anon.0.16.68.224.328.380.484.536.692.796.848.1108.1472.1628.1992.2044.2096.2304.3291.15.89.163.237.311.1051 = type { %struct.anon.5.15.67.223.327.379.483.535.691.795.847.1107.1471.1627.1991.2043.2095.2303.3290.14.88.162.236.310.1050 }
+%struct.anon.5.15.67.223.327.379.483.535.691.795.847.1107.1471.1627.1991.2043.2095.2303.3290.14.88.162.236.310.1050 = type { [3 x double], [3 x double], double, double, i16, [3 x double]*, i32, [3 x double] }
+%"struct.pov::Finish_Struct.18.70.226.330.382.486.538.694.798.850.1110.1474.1630.1994.2046.2098.2306.3293.17.91.165.239.313.1053" = type { float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, [3 x float], [3 x float], [3 x float], float, i32, float, i32 }
+%"struct.pov::Interior_Struct.21.73.229.333.385.489.541.697.801.853.1113.1477.1633.1997.2049.2101.2309.3296.20.94.168.242.316.1056" = type { i32, i32, i32, float, float, float, float, float, float, [5 x float], %"struct.pov::Media_Struct.20.72.228.332.384.488.540.696.800.852.1112.1476.1632.1996.2048.2100.2308.3295.19.93.167.241.315.1055"* }
+%"struct.pov::Bounding_Box_Struct.22.74.230.334.386.490.542.698.802.854.1114.1478.1634.1998.2050.2102.2310.3297.21.95.169.243.317.1057" = type { [3 x float], [3 x float] }
+%"struct.pov::Project_Tree_Node_Struct.30.82.238.342.394.498.550.706.810.862.1122.1486.1642.2006.2058.2110.2318.3305.29.103.177.251.325.1065" = type { i16, %"struct.pov::BBox_Tree_Struct.28.80.236.340.392.496.548.704.808.860.1120.1484.1640.2004.2056.2108.2316.3303.27.101.175.249.323.1063"*, %"struct.pov::Project_Struct.29.81.237.341.393.497.549.705.809.861.1121.1485.1641.2005.2057.2109.2317.3304.28.102.176.250.324.1064", i16, %"struct.pov::Project_Tree_Node_Struct.30.82.238.342.394.498.550.706.810.862.1122.1486.1642.2006.2058.2110.2318.3305.29.103.177.251.325.1065"** }
+%"struct.pov::BBox_Tree_Struct.28.80.236.340.392.496.548.704.808.860.1120.1484.1640.2004.2056.2108.2316.3303.27.101.175.249.323.1063" = type { i16, i16, %"struct.pov::Bounding_Box_Struct.22.74.230.334.386.490.542.698.802.854.1114.1478.1634.1998.2050.2102.2310.3297.21.95.169.243.317.1057", %"struct.pov::BBox_Tree_Struct.28.80.236.340.392.496.548.704.808.860.1120.1484.1640.2004.2056.2108.2316.3303.27.101.175.249.323.1063"** }
+%"struct.pov::Project_Struct.29.81.237.341.393.497.549.705.809.861.1121.1485.1641.2005.2057.2109.2317.3304.28.102.176.250.324.1064" = type { i32, i32, i32, i32 }
+%"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058" = type { %"struct.pov::Method_Struct.27.79.235.339.391.495.547.703.807.859.1119.1483.1639.2003.2055.2107.2315.3302.26.100.174.248.322.1062"*, i32, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, %"struct.pov::Texture_Struct.19.71.227.331.383.487.539.695.799.851.1111.1475.1631.1995.2047.2099.2307.3294.18.92.166.240.314.1054"*, %"struct.pov::Texture_Struct.19.71.227.331.383.487.539.695.799.851.1111.1475.1631.1995.2047.2099.2307.3294.18.92.166.240.314.1054"*, %"struct.pov::Interior_Struct.21.73.229.333.385.489.541.697.801.853.1113.1477.1633.1997.2049.2101.2309.3296.20.94.168.242.316.1056"*, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, %"struct.pov::Object_Struct.23.75.231.335.387.491.543.699.803.855.1115.1479.1635.1999.2051.2103.2311.3298.22.96.170.244.318.1058"*, %"struct.pov::Light_Source_Struct.31.83.239.343.395.499.551.707.811.863.1123.1487.1643.2007.2059.2111.2319.3306.30.104.178.252.326.1066"*, %"struct.pov::Bounding_Box_Struct.22.74.230.334.386.490.542.698.802.854.1114.1478.1634.1998.2050.2102.2310.3297.21.95.169.243.317.1057", %"struct.pov::Transform_Struct.11.63.219.323.375.479.531.687.791.843.1103.1467.1623.1987.2039.2091.2299.3286.10.84.158.232.306.1046"*, %"struct.pov::Transform_Struct.11.63.219.323.375.479.531.687.791.843.1103.1467.1623.1987.2039.2091.2299.3286.10.84.158.232.306.1046"*, float, i32 }
+%"struct.pov::Media_Struct.20.72.228.332.384.488.540.696.800.852.1112.1476.1632.1996.2048.2100.2308.3295.19.93.167.241.315.1055" = type { i32, i32, i32, i32, i32, double, i32, double, double, i32, i32, i32, i32, [5 x float], [5 x float], [5 x float], [5 x float], double, double, double, double*, double, i32, i32, %"struct.pov::Pigment_Struct.17.69.225.329.381.485.537.693.797.849.1109.1473.1629.1993.2045.2097.2305.3292.16.90.164.238.312.1052"*, %"struct.pov::Media_Struct.20.72.228.332.384.488.540.696.800.852.1112.1476.1632.1996.2048.2100.2308.3295.19.93.167.241.315.1055"* }
+%"struct.pov::Fog_Struct.33.85.241.345.397.501.553.709.813.865.1125.1489.1645.2009.2061.2113.2321.3308.32.106.180.254.328.1068" = type { i32, double, double, double, [5 x float], [3 x double], %"struct.pov::Turb_Struct.32.84.240.344.396.500.552.708.812.864.1124.1488.1644.2008.2060.2112.2320.3307.31.105.179.253.327.1067"*, float, %"struct.pov::Fog_Struct.33.85.241.345.397.501.553.709.813.865.1125.1489.1645.2009.2061.2113.2321.3308.32.106.180.254.328.1068"* }
+%"struct.pov::Turb_Struct.32.84.240.344.396.500.552.708.812.864.1124.1488.1644.2008.2060.2112.2320.3307.31.105.179.253.327.1067" = type { i16, %"struct.pov::Warps_Struct.1.53.209.313.365.469.521.677.781.833.1093.1457.1613.1977.2029.2081.2289.3276.0.74.148.222.296.1036"*, %"struct.pov::Warps_Struct.1.53.209.313.365.469.521.677.781.833.1093.1457.1613.1977.2029.2081.2289.3276.0.74.148.222.296.1036"*, [3 x double], i32, float, float }
+%"struct.pov::Rainbow_Struct.34.86.242.346.398.502.554.710.814.866.1126.1490.1646.2010.2062.2114.2322.3309.33.107.181.255.329.1069" = type { double, double, double, double, double, double, double, [3 x double], [3 x double], [3 x double], %"struct.pov::Pigment_Struct.17.69.225.329.381.485.537.693.797.849.1109.1473.1629.1993.2045.2097.2305.3292.16.90.164.238.312.1052"*, %"struct.pov::Rainbow_Struct.34.86.242.346.398.502.554.710.814.866.1126.1490.1646.2010.2062.2114.2322.3309.33.107.181.255.329.1069"* }
+%"struct.pov::Skysphere_Struct.35.87.243.347.399.503.555.711.815.867.1127.1491.1647.2011.2063.2115.2323.3310.34.108.182.256.330.1070" = type { i32, %"struct.pov::Pigment_Struct.17.69.225.329.381.485.537.693.797.849.1109.1473.1629.1993.2045.2097.2305.3292.16.90.164.238.312.1052"**, %"struct.pov::Transform_Struct.11.63.219.323.375.479.531.687.791.843.1103.1467.1623.1987.2039.2091.2299.3286.10.84.158.232.306.1046"* }
+%"struct.pov::light_group_light_struct.36.88.244.348.400.504.556.712.816.868.1128.1492.1648.2012.2064.2116.2324.3311.35.109.183.257.331.1071" = type { %"struct.pov::Light_Source_Struct.31.83.239.343.395.499.551.707.811.863.1123.1487.1643.2007.2059.2111.2319.3306.30.104.178.252.326.1066"*, %"struct.pov::light_group_light_struct.36.88.244.348.400.504.556.712.816.868.1128.1492.1648.2012.2064.2116.2324.3311.35.109.183.257.331.1071"* }
+
+@_ZN3pov5FrameE = external global %"struct.pov::Frame_Struct.37.89.245.349.401.505.557.713.817.869.1129.1493.1649.2013.2065.2117.2325.3312.36.110.184.258.332.1072", align 8
+@_ZN3povL27Precompute_Camera_ConstantsE = external unnamed_addr global i1, align 4
+
+; Function Attrs: uwtable
+define fastcc void @_ZN3povL10create_rayEPNS_10Ray_StructEddi() unnamed_addr {
+entry:
+  %0 = load %"struct.pov::Camera_Struct.12.64.220.324.376.480.532.688.792.844.1104.1468.1624.1988.2040.2092.2300.3287.11.85.159.233.307.1047"*, %"struct.pov::Camera_Struct.12.64.220.324.376.480.532.688.792.844.1104.1468.1624.1988.2040.2092.2300.3287.11.85.159.233.307.1047"** getelementptr inbounds (%"struct.pov::Frame_Struct.37.89.245.349.401.505.557.713.817.869.1129.1493.1649.2013.2065.2117.2325.3312.36.110.184.258.332.1072", %"struct.pov::Frame_Struct.37.89.245.349.401.505.557.713.817.869.1129.1493.1649.2013.2065.2117.2325.3312.36.110.184.258.332.1072"* @_ZN3pov5FrameE, i64 0, i32 0), align 8
+  %.b761 = load i1, i1* @_ZN3povL27Precompute_Camera_ConstantsE, align 4
+  br label %if.end79
+
+if.end79:                                         ; preds = %entry
+  %arraydecay89 = getelementptr inbounds %"struct.pov::Camera_Struct.12.64.220.324.376.480.532.688.792.844.1104.1468.1624.1988.2040.2092.2300.3287.11.85.159.233.307.1047", %"struct.pov::Camera_Struct.12.64.220.324.376.480.532.688.792.844.1104.1468.1624.1988.2040.2092.2300.3287.11.85.159.233.307.1047"* %0, i64 0, i32 3, i64 0
+  %1 = load double, double* %arraydecay89, align 8
+  br i1 %.b761, label %if.then87, label %if.end79.if.end100_crit_edge
+
+if.end79.if.end100_crit_edge:                     ; preds = %if.end79
+  br label %if.end100
+
+if.then87:                                        ; preds = %if.end79
+  br label %if.end100
+
+if.end100:                                        ; preds = %if.then87, %if.end79.if.end100_crit_edge
+  tail call void @_ZN3pov30initialize_ray_container_stateEPNS_10Ray_StructEi()
+  br label %sw.epilog
+
+sw.epilog:                                        ; preds = %if.end100
+  unreachable
+}
+
+; Function Attrs: uwtable
+declare void @_ZN3pov30initialize_ray_container_stateEPNS_10Ray_StructEi() local_unnamed_addr #0
+
+
+; CHECK: Valid Region for Scop: if.end79 => if.end100
+
+; CHECK-NOT: Invariant Accesses:
diff --git a/final/test/ScopDetect/keep_going_expansion.ll b/final/test/ScopDetect/keep_going_expansion.ll
new file mode 100644
index 0000000..ef88ce1
--- /dev/null
+++ b/final/test/ScopDetect/keep_going_expansion.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -basicaa -polly-detect-track-failures -polly-detect-keep-going -polly-detect -analyze < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @a(i32 %n, i32* noalias %A, i32* noalias %B) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.cond2.preheader:                              ; preds = %for.body
+  br label %for.body4
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %indvar = phi i64 [ 0, %entry.split ], [ %indvar.next, %for.body ]
+  %j.02 = trunc i64 %indvar to i32
+  %arrayidx = getelementptr i32, i32* %B, i64 %indvar
+  store i32 %j.02, i32* %arrayidx, align 4
+  %indvar.next = add i64 %indvar, 1
+  %exitcond3 = icmp ne i64 %indvar.next, 32
+  br i1 %exitcond3, label %for.body, label %for.cond2.preheader
+
+for.body4:                                        ; preds = %for.cond2.preheader, %for.body4
+  %0 = phi i32 [ 0, %for.cond2.preheader ], [ %1, %for.body4 ]
+  %mul = mul i32 %n, %0
+  %idxprom5 = sext i32 %mul to i64
+  %arrayidx6 = getelementptr inbounds i32, i32* %A, i64 %idxprom5
+  store i32 %0, i32* %arrayidx6, align 4
+  %1 = add nsw i32 %0, 1
+  %exitcond = icmp ne i32 %1, 32
+  br i1 %exitcond, label %for.body4, label %for.end9
+
+for.end9:                                         ; preds = %for.body4
+  %idxprom10 = sext i32 %n to i64
+  %arrayidx11 = getelementptr inbounds i32, i32* %A, i64 %idxprom10
+  %2 = load i32, i32* %arrayidx11, align 4
+  %idxprom12 = sext i32 %n to i64
+  %arrayidx13 = getelementptr inbounds i32, i32* %B, i64 %idxprom12
+  %3 = load i32, i32* %arrayidx13, align 4
+  %add = add nsw i32 %3, %2
+  ret i32 %add
+}
+
+; CHECK: Valid Region for Scop: for.body => for.body4
diff --git a/final/test/ScopDetect/mod_ref_read_pointer.ll b/final/test/ScopDetect/mod_ref_read_pointer.ll
new file mode 100644
index 0000000..bdb38ea
--- /dev/null
+++ b/final/test/ScopDetect/mod_ref_read_pointer.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -basicaa -polly-detect -analyze \
+; RUN:  -polly-allow-modref-calls < %s | FileCheck %s -check-prefix=MODREF
+; RUN: opt %loadPolly -basicaa -polly-detect -analyze \
+; RUN:  < %s | FileCheck %s
+;
+; CHECK-NOT: Valid Region for Scop: for.cond => for.end
+; MODREF: Valid Region for Scop: for.cond => for.end
+;
+;    #pragma readonly
+;    int func(int *A);
+;
+;    void jd(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i + 2] = func(A);
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare i32 @func(i32* %A) #1
+
+define void @jd(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %call = call i32 @func(i32* %A)
+  %tmp = add nsw i64 %indvars.iv, 2
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %tmp
+  store i32 %call, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+attributes #1 = { nounwind readonly }
diff --git a/final/test/ScopDetect/more-than-one-loop.ll b/final/test/ScopDetect/more-than-one-loop.ll
new file mode 100644
index 0000000..8048f8f
--- /dev/null
+++ b/final/test/ScopDetect/more-than-one-loop.ll
@@ -0,0 +1,78 @@
+; RUN: opt %loadPolly -polly-process-unprofitable=false \
+; RUN: \
+; RUN: -polly-detect -analyze < %s | FileCheck %s
+
+; RUN: opt %loadPolly -polly-process-unprofitable=true \
+; RUN: \
+; RUN: -polly-detect -analyze < %s | FileCheck %s
+
+; CHECK: Valid Region for Scop:
+
+;    void foo(float *A, float *B, long N) {
+;      if (N > 100)
+;        for (long i = 0; i < 100; i++)
+;          A[i] += i;
+;      else
+;        for (long i = 0; i < 100; i++)
+;          B[i] += i;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A, float* %B, i64 %N) {
+entry:
+  br label %bb
+
+bb:
+  %tmp = icmp sgt i64 %N, 100
+  br i1 %tmp, label %bb2, label %bb12
+
+bb2:                                              ; preds = %bb
+  br label %bb3
+
+bb3:                                              ; preds = %bb9, %bb2
+  %i.0 = phi i64 [ 0, %bb2 ], [ %tmp10, %bb9 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb4, label %bb11
+
+bb4:                                              ; preds = %bb3
+  %tmp5 = sitofp i64 %i.0 to float
+  %tmp6 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp7 = load float, float* %tmp6, align 4
+  %tmp8 = fadd float %tmp7, %tmp5
+  store float %tmp8, float* %tmp6, align 4
+  br label %bb9
+
+bb9:                                              ; preds = %bb4
+  %tmp10 = add nsw i64 %i.0, 1
+  br label %bb3
+
+bb11:                                             ; preds = %bb3
+  br label %bb22
+
+bb12:                                             ; preds = %bb
+  br label %bb13
+
+bb13:                                             ; preds = %bb19, %bb12
+  %i1.0 = phi i64 [ 0, %bb12 ], [ %tmp20, %bb19 ]
+  %exitcond1 = icmp ne i64 %i1.0, 100
+  br i1 %exitcond1, label %bb14, label %bb21
+
+bb14:                                             ; preds = %bb13
+  %tmp15 = sitofp i64 %i1.0 to float
+  %tmp16 = getelementptr inbounds float, float* %B, i64 %i1.0
+  %tmp17 = load float, float* %tmp16, align 4
+  %tmp18 = fadd float %tmp17, %tmp15
+  store float %tmp18, float* %tmp16, align 4
+  br label %bb19
+
+bb19:                                             ; preds = %bb14
+  %tmp20 = add nsw i64 %i1.0, 1
+  br label %bb13
+
+bb21:                                             ; preds = %bb13
+  br label %bb22
+
+bb22:                                             ; preds = %bb21, %bb11
+  ret void
+}
diff --git a/final/test/ScopDetect/multidim-with-undef-size.ll b/final/test/ScopDetect/multidim-with-undef-size.ll
new file mode 100644
index 0000000..e0227eb
--- /dev/null
+++ b/final/test/ScopDetect/multidim-with-undef-size.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK: Valid Region for Scop: bb14 => bb17
+
+; Make sure we do not detect the larger region bb14->bb19 that contains
+; a multi-dimensional memory access with a size of 'undef * undef'.
+
+define void @hoge(i8* %arg) {
+bb:
+  br label %bb6
+
+bb6:                                              ; preds = %bb
+  %tmp = mul i64 undef, undef
+  %tmp7 = add i64 %tmp, undef
+  %tmp8 = add i64 %tmp7, 0
+  %tmp9 = add i64 %tmp8, 8
+  %tmp10 = sub i64 %tmp9, undef
+  %tmp11 = getelementptr i8, i8* %arg, i64 %tmp10
+  %tmp12 = getelementptr inbounds i8, i8* %tmp11, i64 4
+  %tmp13 = getelementptr inbounds i8, i8* %tmp12, i64 20
+  br label %bb14
+
+bb14:                                             ; preds = %bb14, %bb6
+  %tmp15 = phi i32 [ %tmp16, %bb14 ], [ 2, %bb6 ]
+  %tmp16 = add nuw nsw i32 %tmp15, 1
+  br i1 false, label %bb14, label %bb17
+
+bb17:                                             ; preds = %bb14
+  %tmp18 = bitcast i8* %tmp13 to i32*
+  store i32 undef, i32* %tmp18, align 4
+  br label %bb19
+
+bb19:                                             ; preds = %bb17
+  unreachable
+}
diff --git a/final/test/ScopDetect/multidim.ll b/final/test/ScopDetect/multidim.ll
new file mode 100644
index 0000000..940993d
--- /dev/null
+++ b/final/test/ScopDetect/multidim.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK: Valid Region for Scop: bb19 => bb20
+
+; Make sure we do not crash in this test case.
+
+define void @hoge(i8* %arg)  {
+bb:
+  br label %bb9
+
+bb9:                                              ; preds = %bb
+  %tmp = add i64 undef, 4
+  %tmp10 = zext i32 undef to i64
+  %tmp11 = mul i64 %tmp, %tmp10
+  %tmp12 = add i64 %tmp11, undef
+  %tmp13 = add i64 %tmp12, undef
+  %tmp14 = add i64 %tmp13, 8
+  %tmp15 = sub i64 %tmp14, undef
+  %tmp16 = getelementptr i8, i8* %arg, i64 %tmp15
+  %tmp17 = getelementptr inbounds i8, i8* %tmp16, i64 4
+  %tmp18 = getelementptr inbounds i8, i8* %tmp17, i64 20
+  br label %bb19
+
+bb19:                                             ; preds = %bb19, %bb9
+  br i1 false, label %bb19, label %bb20
+
+bb20:                                             ; preds = %bb19
+  %tmp21 = getelementptr inbounds i8, i8* %tmp18, i64 4
+  %tmp22 = bitcast i8* %tmp21 to i32*
+  %tmp23 = load i32, i32* %tmp22
+  br label %bb24
+
+bb24:                                             ; preds = %bb20
+  unreachable
+}
diff --git a/final/test/ScopDetect/multidim_indirect_access.ll b/final/test/ScopDetect/multidim_indirect_access.ll
new file mode 100644
index 0000000..9848c76
--- /dev/null
+++ b/final/test/ScopDetect/multidim_indirect_access.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+;
+; Check that we will recognize this SCoP.
+;
+;    void f(int *A, long N) {
+;      int j = 0;
+;      while (N > j) {
+;        int x = A[0];
+;        int i = 1;
+;        do {
+;          A[x] = 42;
+;          A += x;
+;        } while (i++ < N);
+;      }
+;    }
+;
+; CHECK: Valid Region for Scop: bb1 => bb0
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i64 %N) {
+bb:
+  br label %bb0
+
+bb0:
+  %j = phi i64 [ %j.next, %bb1 ], [ 1, %bb ]
+  %tmp = load i32, i32* %A, align 4
+  %exitcond0 = icmp sgt i64 %N, %j
+  %j.next = add nuw nsw i64 %j, 1
+  br i1 %exitcond0, label %bb1, label %bb13
+
+bb1:                                              ; preds = %bb7, %bb0
+  %i = phi i64 [ %i.next, %bb1 ], [ 1, %bb0 ]
+  %.0 = phi i32* [ %A, %bb0 ], [ %tmp12, %bb1 ]
+  %tmp8 = sext i32 %tmp to i64
+  %tmp9 = getelementptr inbounds i32, i32* %.0, i64 %tmp8
+  store i32 42, i32* %tmp9, align 4
+  %tmp11 = sext i32 %tmp to i64
+  %tmp12 = getelementptr inbounds i32, i32* %.0, i64 %tmp11
+  %i.next = add nuw nsw i64 %i, 1
+  %exitcond = icmp ne i64 %i, %N
+  br i1 %exitcond, label %bb1, label %bb0
+
+bb13:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopDetect/multidim_two_accesses_different_delinearization.ll b/final/test/ScopDetect/multidim_two_accesses_different_delinearization.ll
new file mode 100644
index 0000000..c93d930
--- /dev/null
+++ b/final/test/ScopDetect/multidim_two_accesses_different_delinearization.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; Derived from the following code:
+;
+; void foo(long n, long m, double *A) {
+;   for (long i = 0; i < n; i++)
+;     for (long j = 0; j < m; j++)
+;       *(A + i * n + j) = 1.0;
+;       *(A + j * m + i) = 2.0;
+; }
+
+; CHECK-NOT: Valid Region for Scop
+
+define void @foo(i64 %n, i64 %m, double* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j ]
+  %tmp = mul nsw i64 %i, %m
+  %vlaarrayidx.sum = add i64 %j, %tmp
+  %arrayidx = getelementptr inbounds double, double* %A, i64 %vlaarrayidx.sum
+  store double 1.0, double* %arrayidx
+  %tmp1 = mul nsw i64 %j, %n
+  %vlaarrayidx.sum1 = add i64 %i, %tmp1
+  %arrayidx1 = getelementptr inbounds double, double* %A, i64 %vlaarrayidx.sum1
+  store double 1.0, double* %arrayidx1
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, %m
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %i.exitcond = icmp eq i64 %i.inc, %n
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopDetect/nested_loop_single_exit.ll b/final/test/ScopDetect/nested_loop_single_exit.ll
new file mode 100644
index 0000000..b0b6780
--- /dev/null
+++ b/final/test/ScopDetect/nested_loop_single_exit.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -analyze < %s
+
+; void f(long A[], long N) {
+;   long i, j;
+;   if (true)
+;     for (j = 0; j < N; ++j)
+;       for (i = 0; i < N; ++i)
+;         A[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br label %next
+
+next:
+  br i1 true, label %for.j, label %return
+
+for.j:
+  %j.015 = phi i64 [ %inc5, %for.inc8 ], [ 0, %next ]
+  br label %for.i
+
+for.i:
+  %indvar = phi i64 [ 0, %for.j], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %for.inc8, label %for.i
+
+for.inc8:                                         ; preds = %for.body3
+  %inc5 = add nsw i64 %j.015, 1
+  %exitcond16 = icmp eq i64 %inc5, %N
+  br i1 %exitcond16, label %return, label %for.j
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: Valid Region for Scop: next => return
diff --git a/final/test/ScopDetect/non-affine-conditional.ll b/final/test/ScopDetect/non-affine-conditional.ll
new file mode 100644
index 0000000..5e5897f
--- /dev/null
+++ b/final/test/ScopDetect/non-affine-conditional.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-allow-nonaffine-branches -polly-detect \
+; RUN:     -analyze < %s | FileCheck %s
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        if (A[i])
+;          A[i] = 0;
+;    }
+;
+; CHECK: Valid Region for Scop: bb1 => bb9
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb8, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb8 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb9
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %tmp, align 4
+  %tmp4 = icmp eq i32 %tmp3, 0
+  br i1 %tmp4, label %bb7, label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 0, i32* %tmp6, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb2, %bb5
+  br label %bb8
+
+bb8:                                              ; preds = %bb7
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb9:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopDetect/non-affine-float-compare.ll b/final/test/ScopDetect/non-affine-float-compare.ll
new file mode 100644
index 0000000..656754e
--- /dev/null
+++ b/final/test/ScopDetect/non-affine-float-compare.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches \
+; RUN:     -analyze < %s | FileCheck %s
+;
+;    void f(float *A) {
+;      for (int i = 0; i < 1024; i++)
+;        if (A[i] == A[i - 1])
+;          A[i]++;
+;    }
+;
+; CHECK: Valid Region for Scop: bb1 => bb14
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(float* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb13, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb13 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb14
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp3 = load float, float* %tmp, align 4
+  %tmp4 = add nsw i64 %indvars.iv, -1
+  %tmp5 = getelementptr inbounds float, float* %A, i64 %tmp4
+  %tmp6 = load float, float* %tmp5, align 4
+  %tmp7 = fcmp oeq float %tmp3, %tmp6
+  br i1 %tmp7, label %bb8, label %bb12
+
+bb8:                                              ; preds = %bb2
+  %tmp9 = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp10 = load float, float* %tmp9, align 4
+  %tmp11 = fadd float %tmp10, 1.000000e+00
+  store float %tmp11, float* %tmp9, align 4
+  br label %bb12
+
+bb12:                                             ; preds = %bb8, %bb2
+  br label %bb13
+
+bb13:                                             ; preds = %bb12
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb14:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopDetect/non-affine-loop-condition-dependent-access.ll b/final/test/ScopDetect/non-affine-loop-condition-dependent-access.ll
new file mode 100644
index 0000000..6140992
--- /dev/null
+++ b/final/test/ScopDetect/non-affine-loop-condition-dependent-access.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -basicaa -polly-detect -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=false -analyze < %s | FileCheck %s --check-prefix=REJECTNONAFFINELOOPS
+; RUN: opt %loadPolly -basicaa -polly-detect -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -analyze < %s | FileCheck %s --check-prefix=ALLOWNONAFFINELOOPS
+; RUN: opt %loadPolly -basicaa -polly-detect -polly-allow-nonaffine -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -analyze < %s | FileCheck %s --check-prefix=ALLOWNONAFFINELOOPSANDACCESSES
+; RUN: opt %loadPolly -basicaa -polly-detect -polly-process-unprofitable=false \
+; RUN:    -polly-allow-nonaffine -polly-allow-nonaffine-branches \
+; RUN:    -polly-allow-nonaffine-loops=true -analyze < %s \
+; RUN:    | FileCheck %s --check-prefix=PROFIT
+;
+; Here we have a non-affine loop but also a non-affine access which should
+; be rejected as long as -polly-allow-nonaffine isn't given.
+;
+; REJECTNONAFFINELOOPS-NOT:       Valid
+; ALLOWNONAFFINELOOPS-NOT:        Valid
+; ALLOWNONAFFINELOOPSANDACCESSES: Valid Region for Scop: bb1 => bb13
+; PROFIT-NOT:                     Valid
+;
+;    void f(int * restrict A, int * restrict C) {
+;      int j = 0;
+;      for (int i = 0; i < 1024; i++) {
+;        while ((j = C[j]))
+;          A[j]++;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* noalias %A, i32* noalias %C) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb12, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb12 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb13
+
+bb2:                                              ; preds = %bb1
+  br label %bb3
+
+bb3:                                              ; preds = %bb6, %bb2
+  %indvars.j = phi i32 [ %tmp4, %bb6 ], [ 0, %bb2 ]
+  %tmp = getelementptr inbounds i32, i32* %C, i32 %indvars.j
+  %tmp4 = load i32, i32* %tmp, align 4
+  %tmp5 = icmp eq i32 %tmp4, 0
+  br i1 %tmp5, label %bb11, label %bb6
+
+bb6:                                              ; preds = %bb3
+  %tmp7 = sext i32 %tmp4 to i64
+  %tmp8 = getelementptr inbounds i32, i32* %A, i64 %tmp7
+  %tmp9 = load i32, i32* %tmp8, align 4
+  %tmp10 = add nsw i32 %tmp9, 1
+  store i32 %tmp10, i32* %tmp8, align 4
+  br label %bb3
+
+bb11:                                             ; preds = %bb3
+  br label %bb12
+
+bb12:                                             ; preds = %bb11
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb13:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopDetect/non-affine-loop-condition-dependent-access_2.ll b/final/test/ScopDetect/non-affine-loop-condition-dependent-access_2.ll
new file mode 100644
index 0000000..477a80a
--- /dev/null
+++ b/final/test/ScopDetect/non-affine-loop-condition-dependent-access_2.ll
@@ -0,0 +1,93 @@
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=false \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=REJECTNONAFFINELOOPS
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=ALLOWNONAFFINELOOPS
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine \
+; RUN:     -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s \
+; RUN:     | FileCheck %s --check-prefix=ALLOWNONAFFINELOOPSANDACCESSES
+;
+; Here we have a non-affine loop (in the context of the loop nest)
+; and also a non-affine access (A[k]). While we can always detect the
+; innermost loop as a SCoP of depth 1, we have to reject the loop nest if not
+; both, non-affine loops as well as non-affine accesses are allowed.
+;
+; REJECTNONAFFINELOOPS:           Valid Region for Scop: bb15 => bb13
+; REJECTNONAFFINELOOPS-NOT:       Valid
+; ALLOWNONAFFINELOOPS:            Valid Region for Scop: bb15 => bb13
+; ALLOWNONAFFINELOOPS-NOT:        Valid
+; ALLOWNONAFFINELOOPSANDACCESSES: Valid Region for Scop: bb11 => bb29
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        for (int j = 0; j < 1024; j++)
+;          for (int k = i *j;  k < 1024; k++)
+;            A[k] += A[i] + A[j];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+bb:
+  br label %bb11
+
+bb11:                                             ; preds = %bb28, %bb
+  %indvars.iv8 = phi i64 [ %indvars.iv.next9, %bb28 ], [ 0, %bb ]
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %bb28 ], [ 0, %bb ]
+  %exitcond10 = icmp ne i64 %indvars.iv8, 1024
+  br i1 %exitcond10, label %bb12, label %bb29
+
+bb12:                                             ; preds = %bb11
+  br label %bb13
+
+bb13:                                             ; preds = %bb26, %bb12
+  %indvars.iv5 = phi i64 [ %indvars.iv.next6, %bb26 ], [ 0, %bb12 ]
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %bb26 ], [ 0, %bb12 ]
+  %exitcond7 = icmp ne i64 %indvars.iv5, 1024
+  br i1 %exitcond7, label %bb14, label %bb27
+
+bb14:                                             ; preds = %bb13
+  br label %bb15
+
+bb15:                                             ; preds = %bb24, %bb14
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb24 ], [ %indvars.iv3, %bb14 ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb16, label %bb25
+
+bb16:                                             ; preds = %bb15
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %indvars.iv8
+  %tmp17 = load i32, i32* %tmp, align 4
+  %tmp18 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv5
+  %tmp19 = load i32, i32* %tmp18, align 4
+  %tmp20 = add nsw i32 %tmp17, %tmp19
+  %tmp21 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp22 = load i32, i32* %tmp21, align 4
+  %tmp23 = add nsw i32 %tmp22, %tmp20
+  store i32 %tmp23, i32* %tmp21, align 4
+  br label %bb24
+
+bb24:                                             ; preds = %bb16
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb15
+
+bb25:                                             ; preds = %bb15
+  br label %bb26
+
+bb26:                                             ; preds = %bb25
+  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, %indvars.iv1
+  br label %bb13
+
+bb27:                                             ; preds = %bb13
+  br label %bb28
+
+bb28:                                             ; preds = %bb27
+  %indvars.iv.next9 = add nuw nsw i64 %indvars.iv8, 1
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %bb11
+
+bb29:                                             ; preds = %bb11
+  ret void
+}
diff --git a/final/test/ScopDetect/non-affine-loop-condition-dependent-access_3.ll b/final/test/ScopDetect/non-affine-loop-condition-dependent-access_3.ll
new file mode 100644
index 0000000..e5121d5
--- /dev/null
+++ b/final/test/ScopDetect/non-affine-loop-condition-dependent-access_3.ll
@@ -0,0 +1,94 @@
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=false \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=REJECTNONAFFINELOOPS
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=ALLOWNONAFFINELOOPS
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine \
+; RUN:     -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s \
+; RUN:     --check-prefix=ALLOWNONAFFINELOOPSANDACCESSES
+;
+; Here we have a non-affine loop (in the context of the loop nest)
+; and also a non-affine access (A[k]). While we can always detect the
+; innermost loop as a SCoP of depth 1, we have to reject the loop nest if not
+; both, non-affine loops as well as non-affine accesses are allowed.
+;
+; REJECTNONAFFINELOOPS:           Valid Region for Scop: bb15 => bb13
+; REJECTNONAFFINELOOPS-NOT:       Valid
+; ALLOWNONAFFINELOOPS:            Valid Region for Scop: bb15 => bb13
+; ALLOWNONAFFINELOOPS-NOT:        Valid
+; ALLOWNONAFFINELOOPSANDACCESSES: Valid Region for Scop: bb11 => bb29
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        for (int j = 0; j < 1024; j++)
+;          for (int k = 0; k < i * j; k++)
+;            A[k] += A[i] + A[j];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+bb:
+  br label %bb11
+
+bb11:                                             ; preds = %bb28, %bb
+  %indvars.iv8 = phi i64 [ %indvars.iv.next9, %bb28 ], [ 0, %bb ]
+  %indvars.iv1 = phi i32 [ %indvars.iv.next2, %bb28 ], [ 0, %bb ]
+  %exitcond10 = icmp ne i64 %indvars.iv8, 1024
+  br i1 %exitcond10, label %bb12, label %bb29
+
+bb12:                                             ; preds = %bb11
+  br label %bb13
+
+bb13:                                             ; preds = %bb26, %bb12
+  %indvars.iv5 = phi i64 [ %indvars.iv.next6, %bb26 ], [ 0, %bb12 ]
+  %indvars.iv3 = phi i32 [ %indvars.iv.next4, %bb26 ], [ 0, %bb12 ]
+  %exitcond7 = icmp ne i64 %indvars.iv5, 1024
+  br i1 %exitcond7, label %bb14, label %bb27
+
+bb14:                                             ; preds = %bb13
+  br label %bb15
+
+bb15:                                             ; preds = %bb24, %bb14
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb24 ], [ 0, %bb14 ]
+  %lftr.wideiv = trunc i64 %indvars.iv to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, %indvars.iv3
+  br i1 %exitcond, label %bb16, label %bb25
+
+bb16:                                             ; preds = %bb15
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %indvars.iv8
+  %tmp17 = load i32, i32* %tmp, align 4
+  %tmp18 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv5
+  %tmp19 = load i32, i32* %tmp18, align 4
+  %tmp20 = add nsw i32 %tmp17, %tmp19
+  %tmp21 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp22 = load i32, i32* %tmp21, align 4
+  %tmp23 = add nsw i32 %tmp22, %tmp20
+  store i32 %tmp23, i32* %tmp21, align 4
+  br label %bb24
+
+bb24:                                             ; preds = %bb16
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb15
+
+bb25:                                             ; preds = %bb15
+  br label %bb26
+
+bb26:                                             ; preds = %bb25
+  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1
+  %indvars.iv.next4 = add nuw nsw i32 %indvars.iv3, %indvars.iv1
+  br label %bb13
+
+bb27:                                             ; preds = %bb13
+  br label %bb28
+
+bb28:                                             ; preds = %bb27
+  %indvars.iv.next9 = add nuw nsw i64 %indvars.iv8, 1
+  %indvars.iv.next2 = add nuw nsw i32 %indvars.iv1, 1
+  br label %bb11
+
+bb29:                                             ; preds = %bb11
+  ret void
+}
diff --git a/final/test/ScopDetect/non-affine-loop.ll b/final/test/ScopDetect/non-affine-loop.ll
new file mode 100644
index 0000000..5ec0187
--- /dev/null
+++ b/final/test/ScopDetect/non-affine-loop.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=false \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=REJECTNONAFFINELOOPS
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=ALLOWNONAFFINELOOPS
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=false -polly-allow-nonaffine \
+; RUN:     -analyze < %s | FileCheck %s \
+; RUN:     --check-prefix=ALLOWNONAFFINEREGIONSANDACCESSES
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=true -polly-allow-nonaffine \
+; RUN:     -analyze < %s | FileCheck %s \
+; RUN:     --check-prefix=ALLOWNONAFFINELOOPSANDACCESSES
+; RUN: opt %loadPolly -polly-process-unprofitable=false \
+; RUN:     -polly-detect -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=true -polly-allow-nonaffine \
+; RUN:     -analyze < %s | FileCheck %s \
+; RUN:     --check-prefix=PROFIT
+;
+; This function/region does contain a loop, however it is non-affine, hence the access
+; A[i] is also. Furthermore, it is the only loop, thus when we over approximate
+; non-affine loops __and__ accesses __and__ allow regins without a (affine) loop we will
+; detect it, otherwise we won't.
+;
+;    void f(int *A) {
+;      for (int i = 0; i < A[i]; i++)
+;        A[-1]++;
+;    }
+;
+; REJECTNONAFFINELOOPS-NOT:              Valid
+; ALLOWNONAFFINELOOPS-NOT:               Valid
+; ALLOWNONAFFINEREGIONSANDACCESSES-NOT:  Valid
+; ALLOWNONAFFINELOOPSANDACCESSES:        Valid
+; PROFIT-NOT:                            Valid
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb9, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb9 ], [ 0, %bb ]
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %tmp, align 4
+  %tmp3 = sext i32 %tmp2 to i64
+  %tmp4 = icmp slt i64 %indvars.iv, %tmp3
+  br i1 %tmp4, label %bb5, label %bb10
+
+bb5:                                              ; preds = %bb1
+  %tmp6 = getelementptr inbounds i32, i32* %A, i64 -1
+  %tmp7 = load i32, i32* %tmp6, align 4
+  %tmp8 = add nsw i32 %tmp7, 1
+  store i32 %tmp8, i32* %tmp6, align 4
+  br label %bb9
+
+bb9:                                              ; preds = %bb5
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb10:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopDetect/non-beneficial-loops-small-trip-count.ll b/final/test/ScopDetect/non-beneficial-loops-small-trip-count.ll
new file mode 100644
index 0000000..3911b66
--- /dev/null
+++ b/final/test/ScopDetect/non-beneficial-loops-small-trip-count.ll
@@ -0,0 +1,96 @@
+; RUN: opt %loadPolly -polly-process-unprofitable=false -polly-detect \
+; RUN:   -analyze < %s | FileCheck %s
+;
+; CHECK-NOT: Valid
+;
+; Do not consider this a SCoP as we do not perform any optimizations for
+; loops with a small trip count.
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 4; i++)
+;        for (int j = 0; j < 4; j++)
+;          for (int k = 0; k < 4; k++)
+;            for (int l = 0; l < 4; l++)
+;              A[i] += A[i] * A[i - 1] + A[i + 1];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.24, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc.24 ], [ 0, %entry ]
+  %exitcond5 = icmp ne i64 %indvars.iv, 4
+  br i1 %exitcond5, label %for.body, label %for.end.26
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond.1
+
+for.cond.1:                                       ; preds = %for.inc.21, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc22, %for.inc.21 ]
+  %exitcond2 = icmp ne i32 %j.0, 4
+  br i1 %exitcond2, label %for.body.3, label %for.end.23
+
+for.body.3:                                       ; preds = %for.cond.1
+  br label %for.cond.4
+
+for.cond.4:                                       ; preds = %for.inc.18, %for.body.3
+  %k.0 = phi i32 [ 0, %for.body.3 ], [ %inc19, %for.inc.18 ]
+  %exitcond1 = icmp ne i32 %k.0, 4
+  br i1 %exitcond1, label %for.body.6, label %for.end.20
+
+for.body.6:                                       ; preds = %for.cond.4
+  br label %for.cond.7
+
+for.cond.7:                                       ; preds = %for.inc, %for.body.6
+  %l.0 = phi i32 [ 0, %for.body.6 ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %l.0, 4
+  br i1 %exitcond, label %for.body.9, label %for.end
+
+for.body.9:                                       ; preds = %for.cond.7
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4
+  %tmp6 = add nsw i64 %indvars.iv, -1
+  %arrayidx11 = getelementptr inbounds i32, i32* %A, i64 %tmp6
+  %tmp7 = load i32, i32* %arrayidx11, align 4
+  %mul = mul nsw i32 %tmp, %tmp7
+  %tmp8 = add nuw nsw i64 %indvars.iv, 1
+  %arrayidx13 = getelementptr inbounds i32, i32* %A, i64 %tmp8
+  %tmp9 = load i32, i32* %arrayidx13, align 4
+  %add14 = add nsw i32 %mul, %tmp9
+  %arrayidx16 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp10 = load i32, i32* %arrayidx16, align 4
+  %add17 = add nsw i32 %tmp10, %add14
+  store i32 %add17, i32* %arrayidx16, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body.9
+  %inc = add nuw nsw i32 %l.0, 1
+  br label %for.cond.7
+
+for.end:                                          ; preds = %for.cond.7
+  br label %for.inc.18
+
+for.inc.18:                                       ; preds = %for.end
+  %inc19 = add nuw nsw i32 %k.0, 1
+  br label %for.cond.4
+
+for.end.20:                                       ; preds = %for.cond.4
+  br label %for.inc.21
+
+for.inc.21:                                       ; preds = %for.end.20
+  %inc22 = add nuw nsw i32 %j.0, 1
+  br label %for.cond.1
+
+for.end.23:                                       ; preds = %for.cond.1
+  br label %for.inc.24
+
+for.inc.24:                                       ; preds = %for.end.23
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end.26:                                       ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopDetect/non-constant-add-rec-start-expr.ll b/final/test/ScopDetect/non-constant-add-rec-start-expr.ll
new file mode 100644
index 0000000..121f72f
--- /dev/null
+++ b/final/test/ScopDetect/non-constant-add-rec-start-expr.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-detect -\
+; RUN:     -analyze < %s | FileCheck %s
+
+; CHECK: Valid Region for Scop: bb11 => bb25
+
+; Ensure that this test case does not trigger an assertion. At some point,
+; we asserted on scops containing accesses where the access function contained
+; an AddRec expression with a non-constant step expression. This got missed, as
+; this very specific pattern does not seem too common. Even in this test case,
+; it disappears as soon as we turn the infinite loop into a finite loop.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @hoge() local_unnamed_addr {
+bb:
+  %tmp = alloca [18 x [16 x i32]]
+  %tmp1 = alloca [17 x i32]
+  br label %bb2
+
+bb2:
+  %tmp3 = phi i64 [ 0, %bb ], [ %tmp5, %bb2 ]
+  %tmp4 = add nuw nsw i64 %tmp3, 2
+  %tmp5 = add nuw nsw i64 %tmp3, 1
+  br i1 undef, label %bb2, label %bb11
+
+bb11:
+  %tmp12 = phi i64 [ %tmp23, %bb24 ], [ 1, %bb2 ]
+  %tmp14 = getelementptr inbounds [17 x i32], [17 x i32]* %tmp1, i64 0, i64 1
+  br label %bb15
+
+bb15:
+  %tmp16 = sub nsw i64 %tmp12, 1
+  %tmp17 = shl i64 %tmp16, 32
+  %tmp18 = ashr exact i64 %tmp17, 32
+  %tmp19 = getelementptr inbounds [18 x [16 x i32]], [18 x [16 x i32]]* %tmp, i64 0, i64 %tmp4, i64 %tmp18
+  %tmp20 = load i32, i32* %tmp19, align 4
+  store i32 4, i32* %tmp19
+  br label %bb21
+
+bb21:
+  %tmp23 = add nuw nsw i64 %tmp12, 1
+  br i1 true, label %bb24, label %bb25
+
+bb24:
+  br label %bb11
+
+bb25:
+  ret void
+}
diff --git a/final/test/ScopDetect/non-simple-memory-accesses.ll b/final/test/ScopDetect/non-simple-memory-accesses.ll
new file mode 100644
index 0000000..73b4e76
--- /dev/null
+++ b/final/test/ScopDetect/non-simple-memory-accesses.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -polly-detect \
+; RUN:   -analyze < %s | FileCheck %s
+;
+; Verify that we do not model atomic memory accesses. We did not reason about
+; how to handle them correctly and the Alias Set Tracker models some of them
+; only as Unknown Instructions, which we do not know how to handle either.;
+;
+; CHECK-NOT: Valid
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@global = external global i64, align 8
+
+declare void @foo55()
+
+define void @blam107() {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb
+  %tmp = load atomic i8, i8* bitcast (i64* @global to i8*) acquire, align 8
+  br i1 false, label %bb2, label %bb3
+
+bb2:                                              ; preds = %bb1
+  tail call void @foo55() #6
+  br label %bb3
+
+bb3:                                              ; preds = %bb2, %bb1
+  unreachable
+}
+
diff --git a/final/test/ScopDetect/non_affine_loop_condition.ll b/final/test/ScopDetect/non_affine_loop_condition.ll
new file mode 100644
index 0000000..2f40a47
--- /dev/null
+++ b/final/test/ScopDetect/non_affine_loop_condition.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly \
+; RUN:   -polly-detect -polly-allow-nonaffine-loops -analyze \
+; RUN:   < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-process-unprofitable=false \
+; RUN:   -polly-detect -polly-allow-nonaffine-loops -analyze \
+; RUN:   < %s | FileCheck %s --check-prefix=PROFIT
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++) {
+;        while (A[i])
+;          A[i]--;
+;      }
+;    }
+;
+; PROFIT-NOT: Valid
+;
+; CHECK: Valid Region for Scop: bb1 => bb12
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb11, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb11 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb12
+
+bb2:                                              ; preds = %bb1
+  br label %bb3
+
+bb3:                                              ; preds = %bb6, %bb2
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp4 = load i32, i32* %tmp, align 4
+  %tmp5 = icmp eq i32 %tmp4, 0
+  br i1 %tmp5, label %bb10, label %bb6
+
+bb6:                                              ; preds = %bb3
+  %tmp7 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp8 = load i32, i32* %tmp7, align 4
+  %tmp9 = add nsw i32 %tmp8, -1
+  store i32 %tmp9, i32* %tmp7, align 4
+  br label %bb3
+
+bb10:                                             ; preds = %bb3
+  br label %bb11
+
+bb11:                                             ; preds = %bb10
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb12:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopDetect/only-one-affine-loop.ll b/final/test/ScopDetect/only-one-affine-loop.ll
new file mode 100644
index 0000000..0cfad0d
--- /dev/null
+++ b/final/test/ScopDetect/only-one-affine-loop.ll
@@ -0,0 +1,167 @@
+; RUN: opt %loadPolly -polly-detect -polly-process-unprofitable=false -analyze \
+; RUN:     -polly-allow-nonaffine-loops < %s | FileCheck %s
+;
+; Even if we allow non-affine loops we can only model the outermost loop, all
+; other loops are boxed in non-affine regions. However, the inner loops can be
+; distributed as black-boxes, thus we will recognize the outer loop as profitable.
+;
+; CHECK:  Valid Region for Scop: for.cond => for.end.51
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 100; i++) {
+;        // Non-affine
+;        for (int j = 0; j < i * i; j++)
+;          for (int k = 0; k < i; k++)
+;            A[i]++;
+;        // Non-affine
+;        for (int j = 0; j < i * i; j++)
+;          // Non-affine
+;          for (int k = 0; k < j; k++)
+;            A[i]++;
+;        // Non-affine
+;        if (A[i])
+;          for (int j = 0; j < 100; j++)
+;            for (int k = 0; k < j * j; k++)
+;              A[i]++;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.49, %entry
+  %indvars.iv5 = phi i64 [ %indvars.iv.next6, %for.inc.49 ], [ 0, %entry ]
+  %indvars.iv = phi i32 [ %indvars.iv.next, %for.inc.49 ], [ 0, %entry ]
+  %exitcond9 = icmp ne i64 %indvars.iv5, 100
+  br i1 %exitcond9, label %for.body, label %for.end.51
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond.1
+
+for.cond.1:                                       ; preds = %for.inc.8, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc9, %for.inc.8 ]
+  %tmp = mul nsw i64 %indvars.iv5, %indvars.iv5
+  %tmp10 = sext i32 %j.0 to i64
+  %cmp2 = icmp slt i64 %tmp10, %tmp
+  br i1 %cmp2, label %for.body.3, label %for.end.10
+
+for.body.3:                                       ; preds = %for.cond.1
+  br label %for.cond.4
+
+for.cond.4:                                       ; preds = %for.inc, %for.body.3
+  %k.0 = phi i32 [ 0, %for.body.3 ], [ %inc7, %for.inc ]
+  %exitcond = icmp ne i32 %k.0, %indvars.iv
+  br i1 %exitcond, label %for.body.6, label %for.end
+
+for.body.6:                                       ; preds = %for.cond.4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv5
+  %tmp11 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp11, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body.6
+  %inc7 = add nuw nsw i32 %k.0, 1
+  br label %for.cond.4
+
+for.end:                                          ; preds = %for.cond.4
+  br label %for.inc.8
+
+for.inc.8:                                        ; preds = %for.end
+  %inc9 = add nuw nsw i32 %j.0, 1
+  br label %for.cond.1
+
+for.end.10:                                       ; preds = %for.cond.1
+  br label %for.cond.12
+
+for.cond.12:                                      ; preds = %for.inc.26, %for.end.10
+  %indvars.iv1 = phi i32 [ %indvars.iv.next2, %for.inc.26 ], [ 0, %for.end.10 ]
+  %tmp12 = mul nsw i64 %indvars.iv5, %indvars.iv5
+  %tmp13 = sext i32 %indvars.iv1 to i64
+  %cmp14 = icmp slt i64 %tmp13, %tmp12
+  br i1 %cmp14, label %for.body.15, label %for.end.28
+
+for.body.15:                                      ; preds = %for.cond.12
+  br label %for.cond.17
+
+for.cond.17:                                      ; preds = %for.inc.23, %for.body.15
+  %k16.0 = phi i32 [ 0, %for.body.15 ], [ %inc24, %for.inc.23 ]
+  %exitcond3 = icmp ne i32 %k16.0, %indvars.iv1
+  br i1 %exitcond3, label %for.body.19, label %for.end.25
+
+for.body.19:                                      ; preds = %for.cond.17
+  %arrayidx21 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv5
+  %tmp14 = load i32, i32* %arrayidx21, align 4
+  %inc22 = add nsw i32 %tmp14, 1
+  store i32 %inc22, i32* %arrayidx21, align 4
+  br label %for.inc.23
+
+for.inc.23:                                       ; preds = %for.body.19
+  %inc24 = add nuw nsw i32 %k16.0, 1
+  br label %for.cond.17
+
+for.end.25:                                       ; preds = %for.cond.17
+  br label %for.inc.26
+
+for.inc.26:                                       ; preds = %for.end.25
+  %indvars.iv.next2 = add nuw nsw i32 %indvars.iv1, 1
+  br label %for.cond.12
+
+for.end.28:                                       ; preds = %for.cond.12
+  %arrayidx30 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv5
+  %tmp15 = load i32, i32* %arrayidx30, align 4
+  %tobool = icmp eq i32 %tmp15, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %for.end.28
+  br label %for.cond.32
+
+for.cond.32:                                      ; preds = %for.inc.46, %if.then
+  %j31.0 = phi i32 [ 0, %if.then ], [ %inc47, %for.inc.46 ]
+  %exitcond4 = icmp ne i32 %j31.0, 100
+  br i1 %exitcond4, label %for.body.34, label %for.end.48
+
+for.body.34:                                      ; preds = %for.cond.32
+  br label %for.cond.36
+
+for.cond.36:                                      ; preds = %for.inc.43, %for.body.34
+  %k35.0 = phi i32 [ 0, %for.body.34 ], [ %inc44, %for.inc.43 ]
+  %mul37 = mul nsw i32 %j31.0, %j31.0
+  %cmp38 = icmp slt i32 %k35.0, %mul37
+  br i1 %cmp38, label %for.body.39, label %for.end.45
+
+for.body.39:                                      ; preds = %for.cond.36
+  %arrayidx41 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv5
+  %tmp16 = load i32, i32* %arrayidx41, align 4
+  %inc42 = add nsw i32 %tmp16, 1
+  store i32 %inc42, i32* %arrayidx41, align 4
+  br label %for.inc.43
+
+for.inc.43:                                       ; preds = %for.body.39
+  %inc44 = add nuw nsw i32 %k35.0, 1
+  br label %for.cond.36
+
+for.end.45:                                       ; preds = %for.cond.36
+  br label %for.inc.46
+
+for.inc.46:                                       ; preds = %for.end.45
+  %inc47 = add nuw nsw i32 %j31.0, 1
+  br label %for.cond.32
+
+for.end.48:                                       ; preds = %for.cond.32
+  br label %if.end
+
+if.end:                                           ; preds = %for.end.28, %for.end.48
+  br label %for.inc.49
+
+for.inc.49:                                       ; preds = %if.end
+  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1
+  %indvars.iv.next = add nuw nsw i32 %indvars.iv, 1
+  br label %for.cond
+
+for.end.51:                                       ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopDetect/only_func_flag.ll b/final/test/ScopDetect/only_func_flag.ll
new file mode 100644
index 0000000..4a070a6
--- /dev/null
+++ b/final/test/ScopDetect/only_func_flag.ll
@@ -0,0 +1,100 @@
+; RUN: opt %loadPolly -polly-scops  -analyze -polly-only-func=f,g < %s | FileCheck %s
+;
+; Check that the flag `-polly-only-func` limits analysis to `f` and `g`.
+;
+; CHECK:      Function: f
+; CHECK-NEXT:    Region: %for.cond---%for.end
+;
+; CHECK:      Function: g
+; CHECK-NEXT:    Region: %for.cond---%for.end
+;
+; CHECK-NOT:      Function: h
+;
+; void f(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+; void g(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+; void h(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+
+define void @g(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+
+define void @h(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
diff --git a/final/test/ScopDetect/only_func_flag_regex.ll b/final/test/ScopDetect/only_func_flag_regex.ll
new file mode 100644
index 0000000..da612f2
--- /dev/null
+++ b/final/test/ScopDetect/only_func_flag_regex.ll
@@ -0,0 +1,130 @@
+; RUN: opt %loadPolly -polly-scops  -analyze -polly-only-func=f.*,g.* < %s | FileCheck %s
+;
+; Check that the flag `-polly-only-func` works with regexes.
+;
+; CHECK:      Function: f1
+; CHECK-NEXT:    Region: %for.cond---%for.end
+;
+; CHECK:      Function: f2
+; CHECK-NEXT:    Region: %for.cond---%for.end
+;
+; CHECK:      Function: g1
+; CHECK-NEXT:    Region: %for.cond---%for.end
+;
+; CHECK-NOT:      Function: h
+;
+; void f1(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+; void f2(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+; void g1(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+; void h(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f1(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+
+define void @f2(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+define void @g1(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+define void @h(i32* %sum) {
+entry:
+  br label %entry.split1
+
+entry.split1:                                     ; preds = %entry
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry.split1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i1.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
diff --git a/final/test/ScopDetect/parametric-multiply-in-scev-2.ll b/final/test/ScopDetect/parametric-multiply-in-scev-2.ll
new file mode 100644
index 0000000..c66a9ff
--- /dev/null
+++ b/final/test/ScopDetect/parametric-multiply-in-scev-2.ll
@@ -0,0 +1,28 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+
+; CHECK-NOT: Valid Region
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @blam(float* %A, float* %B) {
+bb:
+  %tmp1 = alloca i64
+  %tmp2 = shl i64 2, undef
+  %tmp3 = shl i64 2, undef
+  %tmp4 = mul nsw i64 %tmp2, %tmp3
+  br label %loop
+
+loop:
+  %indvar = phi i64 [ %indvar.next, %loop ], [ 0, %bb ]
+  %gep = getelementptr inbounds i64, i64* %tmp1, i64 %indvar
+  %tmp12 = load i64, i64* %gep
+  %tmp13 = mul nsw i64 %tmp12, %tmp4
+  %ptr = getelementptr inbounds float, float* %B, i64 %tmp13
+  %val = load float, float* %ptr
+  store float %val, float* %A
+  %indvar.next = add nsw i64 %indvar, 1
+  br i1 false, label %loop, label %bb21
+
+bb21:
+  ret void
+}
diff --git a/final/test/ScopDetect/parametric-multiply-in-scev.ll b/final/test/ScopDetect/parametric-multiply-in-scev.ll
new file mode 100644
index 0000000..c590d1e
--- /dev/null
+++ b/final/test/ScopDetect/parametric-multiply-in-scev.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+;  foo(float *A, long n, long k) {
+;    if (true)
+;      A[n * k] = 0;
+;  }
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+define void @foo(float* %A, i64 %n, i64 %k) {
+entry:
+  br label %for.j
+
+for.j:
+  br i1 true, label %if.then, label %return
+
+if.then:
+  %mul = mul nsw i64 %n, %k
+  %arrayidx = getelementptr float, float* %A, i64 %mul
+  store float 0.000000e+00, float* %arrayidx
+  br label %return
+
+return:
+  ret void
+}
+
+; CHECK: Valid Region for Scop: for.j => return
diff --git a/final/test/ScopDetect/phi_with_multi_exiting_edges.ll b/final/test/ScopDetect/phi_with_multi_exiting_edges.ll
new file mode 100644
index 0000000..3790b7a
--- /dev/null
+++ b/final/test/ScopDetect/phi_with_multi_exiting_edges.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-detect -analyze -S < %s | FileCheck %s
+;
+; Region with an exit node that has a PHI node multiple incoming edges from
+; inside the region. Motivation for supporting such cases in Polly.
+;
+;    float test(long n, float A[static const restrict n]) {
+;      float sum = 0;
+;      for (long i = 0; i < n; i += 1)
+;        sum += A[i];
+;      for (long i = 0; i < n; i += 1)
+;        sum += A[i];
+;      return sum;
+;    }
+;
+;
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define float @test(i64 %n, float* noalias nonnull %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %sum.0 = phi float [ 0.000000e+00, %entry ], [ %add, %for.inc ]
+  %i.0 = phi i64 [ 0, %entry ], [ %add1, %for.inc ]
+  %cmp = icmp slt i64 %i.0, %n
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp = load float, float* %arrayidx, align 4
+  %add = fadd float %sum.0, %tmp
+  %add1 = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  %sum.0.lcssa = phi float [ %sum.0, %for.cond ]
+  br label %for.cond.3
+
+for.cond.3:                                       ; preds = %for.inc.8, %for.end
+  %sum.1 = phi float [ %sum.0.lcssa, %for.end ], [ %add7, %for.inc.8 ]
+  %i2.0 = phi i64 [ 0, %for.end ], [ %add9, %for.inc.8 ]
+  %cmp4 = icmp slt i64 %i2.0, %n
+  br i1 %cmp4, label %for.body.5, label %for.end.10
+
+for.body.5:                                       ; preds = %for.cond.3
+  br label %for.inc.8
+
+for.inc.8:                                        ; preds = %for.body.5
+  %arrayidx6 = getelementptr inbounds float, float* %A, i64 %i2.0
+  %tmp1 = load float, float* %arrayidx6, align 4
+  %add7 = fadd float %sum.1, %tmp1
+  %add9 = add nuw nsw i64 %i2.0, 1
+  br label %for.cond.3
+
+for.end.10:                                       ; preds = %for.cond.3
+  %sum.1.lcssa = phi float [ %sum.1, %for.cond.3 ]
+  ret float %sum.1.lcssa
+}
+
+; CHECK: Valid Region for Scop: for.cond => for.end.10
diff --git a/final/test/ScopDetect/profitability-large-basic-blocks.ll b/final/test/ScopDetect/profitability-large-basic-blocks.ll
new file mode 100644
index 0000000..268731e
--- /dev/null
+++ b/final/test/ScopDetect/profitability-large-basic-blocks.ll
@@ -0,0 +1,83 @@
+; RUN: opt %loadPolly -polly-process-unprofitable=false \
+; RUN:                -polly-detect-profitability-min-per-loop-insts=40 \
+; RUN: -polly-detect -analyze < %s | FileCheck %s -check-prefix=PROFITABLE
+
+; RUN: opt %loadPolly -polly-process-unprofitable=true \
+; RUN: -polly-detect -analyze < %s | FileCheck %s -check-prefix=PROFITABLE
+
+; RUN: opt %loadPolly -polly-process-unprofitable=false \
+; RUN: \
+; RUN: -polly-detect -analyze < %s | FileCheck %s -check-prefix=UNPROFITABLE
+
+; UNPROFITABLE-NOT: Valid Region for Scop:
+; PROFITABLE: Valid Region for Scop:
+
+;    void foo(float *A, float *B, long N) {
+;      for (long i = 0; i < 100; i++)
+;          A[i] += .... / * a  lot of compute */
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A, float* %B, i64 %N) {
+entry:
+  br label %header
+
+header:
+  %i.0 = phi i64 [ 0, %entry ], [ %tmp10, %header ]
+  %tmp5 = sitofp i64 %i.0 to float
+  %tmp6 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp7 = load float, float* %tmp6, align 4
+  %tmp8 = fadd float %tmp7, %tmp5
+  %val0 = fadd float %tmp7, 1.0
+  %val1 = fadd float %val0, 1.0
+  %val2 = fadd float %val1, 1.0
+  %val3 = fadd float %val2, 1.0
+  %val4 = fadd float %val3, 1.0
+  %val5 = fadd float %val4, 1.0
+  %val6 = fadd float %val5, 1.0
+  %val7 = fadd float %val6, 1.0
+  %val8 = fadd float %val7, 1.0
+  %val9 = fadd float %val8, 1.0
+  %val10 = fadd float %val9, 1.0
+  %val11 = fadd float %val10, 1.0
+  %val12 = fadd float %val11, 1.0
+  %val13 = fadd float %val12, 1.0
+  %val14 = fadd float %val13, 1.0
+  %val15 = fadd float %val14, 1.0
+  %val16 = fadd float %val15, 1.0
+  %val17 = fadd float %val16, 1.0
+  %val18 = fadd float %val17, 1.0
+  %val19 = fadd float %val18, 1.0
+  %val20 = fadd float %val19, 1.0
+  %val21 = fadd float %val20, 1.0
+  %val22 = fadd float %val21, 1.0
+  %val23 = fadd float %val22, 1.0
+  %val24 = fadd float %val23, 1.0
+  %val25 = fadd float %val24, 1.0
+  %val26 = fadd float %val25, 1.0
+  %val27 = fadd float %val26, 1.0
+  %val28 = fadd float %val27, 1.0
+  %val29 = fadd float %val28, 1.0
+  %val30 = fadd float %val29, 1.0
+  %val31 = fadd float %val30, 1.0
+  %val32 = fadd float %val31, 1.0
+  %val33 = fadd float %val32, 1.0
+  %val34 = fadd float %val33, 1.0
+  %val35 = fadd float %val34, 1.0
+  %val36 = fadd float %val35, 1.0
+  %val37 = fadd float %val36, 1.0
+  %val38 = fadd float %val37, 1.0
+  %val39 = fadd float %val38, 1.0
+  %val40 = fadd float %val39, 1.0
+  %val41 = fadd float %val40, 1.0
+  %val42 = fadd float %val41, 1.0
+  %val43 = fadd float %val42, 1.0
+  store float %val34, float* %tmp6, align 4
+  %exitcond = icmp ne i64 %i.0, 100
+  %tmp10 = add nsw i64 %i.0, 1
+  br i1 %exitcond, label %header, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopDetect/profitability-two-nested-loops.ll b/final/test/ScopDetect/profitability-two-nested-loops.ll
new file mode 100644
index 0000000..8871893
--- /dev/null
+++ b/final/test/ScopDetect/profitability-two-nested-loops.ll
@@ -0,0 +1,94 @@
+; RUN: opt %loadPolly -polly-detect -analyze \
+; RUN:     -polly-process-unprofitable=false < %s | FileCheck %s
+
+; CHECK: Valid Region for Scop: next => bb3
+;
+;    void foo(float A[], long p) {
+;      for (long x = 0; x < 1024; x++) {
+;        __sync_synchronize();
+;        if (p >= 0) {
+;          for (long i = 0; i < 1024; i++)
+;            for (long j = 0; j < 1024; j++)
+;              A[i + j] += j;
+;        }
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+define void @foo(float* %A, i64 %p) {
+bb:
+  br label %bb3
+
+bb3:                                              ; preds = %bb25, %bb
+  %x.0 = phi i64 [ 0, %bb ], [ %tmp26, %bb25 ]
+  %exitcond2 = icmp ne i64 %x.0, 1024
+  br i1 %exitcond2, label %bb5, label %bb4
+
+bb4:                                              ; preds = %bb3
+  br label %bb27
+
+bb5:                                              ; preds = %bb3
+  fence seq_cst
+  br label %next
+
+next:
+  %tmp = icmp sgt i64 %p, -1
+  br i1 %tmp, label %bb6, label %bb24
+
+bb6:                                              ; preds = %bb5
+  br label %bb7
+
+bb7:                                              ; preds = %bb21, %bb6
+  %i.0 = phi i64 [ 0, %bb6 ], [ %tmp22, %bb21 ]
+  %exitcond1 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond1, label %bb9, label %bb8
+
+bb8:                                              ; preds = %bb7
+  br label %bb23
+
+bb9:                                              ; preds = %bb7
+  br label %bb10
+
+bb10:                                             ; preds = %bb18, %bb9
+  %j.0 = phi i64 [ 0, %bb9 ], [ %tmp19, %bb18 ]
+  %exitcond = icmp ne i64 %j.0, 1024
+  br i1 %exitcond, label %bb12, label %bb11
+
+bb11:                                             ; preds = %bb10
+  br label %bb20
+
+bb12:                                             ; preds = %bb10
+  %tmp13 = sitofp i64 %j.0 to float
+  %tmp14 = add nuw nsw i64 %i.0, %j.0
+  %tmp15 = getelementptr inbounds float, float* %A, i64 %tmp14
+  %tmp16 = load float, float* %tmp15, align 4
+  %tmp17 = fadd float %tmp16, %tmp13
+  store float %tmp17, float* %tmp15, align 4
+  br label %bb18
+
+bb18:                                             ; preds = %bb12
+  %tmp19 = add nuw nsw i64 %j.0, 1
+  br label %bb10
+
+bb20:                                             ; preds = %bb11
+  br label %bb21
+
+bb21:                                             ; preds = %bb20
+  %tmp22 = add nuw nsw i64 %i.0, 1
+  br label %bb7
+
+bb23:                                             ; preds = %bb8
+  br label %bb24
+
+bb24:                                             ; preds = %bb23, %bb5
+  br label %bb25
+
+bb25:                                             ; preds = %bb24
+  %tmp26 = add nuw nsw i64 %x.0, 1
+  br label %bb3
+
+bb27:                                             ; preds = %bb4
+  ret void
+}
diff --git a/final/test/ScopDetect/remove_all_children.ll b/final/test/ScopDetect/remove_all_children.ll
new file mode 100644
index 0000000..5a433de
--- /dev/null
+++ b/final/test/ScopDetect/remove_all_children.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+define void @remove_all_children(i32* %eclass) {
+entry:
+  br label %while.body
+
+while.cond.loopexit:                              ; preds = %while.body50, %while.end44
+  fence seq_cst
+  br label %while.cond.backedge
+
+while.body:                                       ; preds = %while.cond.backedge, %entry
+  br label %if.end33
+
+while.cond.backedge:                              ; preds = %while.end30, %while.cond.loopexit
+  br i1 false, label %while.body, label %while.end60
+
+if.end33:                                         ; preds = %while.end30
+  br i1 false, label %while.body36, label %while.end44
+
+while.body36:                                     ; preds = %while.body36, %while.body36.lr.ph
+  %indvar77 = phi i64 [ 0, %if.end33 ], [ %indvar.next78, %while.body36 ]
+  %arrayidx40 = getelementptr i32, i32* %eclass, i64 0
+  %indvar.next78 = add i64 %indvar77, 1
+  br i1 false, label %while.body36, label %while.end44
+
+while.end44:                                      ; preds = %while.body36, %if.end33
+  br i1 false, label %while.body50, label %while.cond.loopexit
+
+while.body50:                                     ; preds = %while.body50, %while.body50.lr.ph
+  %indvar79 = phi i64 [ 0, %while.end44 ], [ %indvar.next80, %while.body50 ]
+  %arrayidx55 = getelementptr i32, i32* %eclass, i64 0
+  store i32 0, i32* %arrayidx55, align 4
+  %indvar.next80 = add i64 %indvar79, 1
+  br i1 false, label %while.body50, label %while.cond.loopexit
+
+while.end60:                                      ; preds = %while.cond.backedge
+  ret void
+}
+; remove_all_children
+; CHECK-NOT: Valid Region
+; CHECK: Valid Region for Scop: if.end33 => while.cond.loopexit
+; CHECK-NOT: Valid Region
diff --git a/final/test/ScopDetect/report-scop-location.ll b/final/test/ScopDetect/report-scop-location.ll
new file mode 100644
index 0000000..20db813
--- /dev/null
+++ b/final/test/ScopDetect/report-scop-location.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-detect -polly-report -disable-output < %s  2>&1 | FileCheck %s
+target datalayout = "e-i64:64-f80:128-s:64-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @foo(float* %A) #0 !dbg !4 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body, !dbg !11
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %indvar = phi i64 [ 0, %entry.split ], [ %indvar.next, %for.body ]
+  %i.01 = trunc i64 %indvar to i32, !dbg !13
+  %arrayidx = getelementptr float, float* %A, i64 %indvar, !dbg !13
+  %conv = sitofp i32 %i.01 to float, !dbg !13
+  store float %conv, float* %arrayidx, align 4, !dbg !13
+  %indvar.next = add i64 %indvar, 1, !dbg !11
+  %exitcond = icmp ne i64 %indvar.next, 100, !dbg !11
+  br i1 %exitcond, label %for.body, label %for.end, !dbg !11
+
+for.end:                                          ; preds = %for.body
+  ret void, !dbg !14
+}
+
+; CHECK: note: Polly detected an optimizable loop region (scop) in function 'foo'
+; CHECK: test.c:2: Start of scop
+; CHECK: test.c:3: End of scop
+
+; Function Attrs: nounwind uwtable
+define void @bar(float* %A) #0 !dbg !7 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body, !dbg !15
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %indvar = phi i64 [ 0, %entry.split ], [ %indvar.next, %for.body ]
+  %i.01 = trunc i64 %indvar to i32, !dbg !17
+  %arrayidx = getelementptr float, float* %A, i64 %indvar, !dbg !17
+  %conv = sitofp i32 %i.01 to float, !dbg !17
+  store float %conv, float* %arrayidx, align 4, !dbg !17
+  %indvar.next = add i64 %indvar, 1, !dbg !15
+  %exitcond = icmp ne i64 %indvar.next, 100, !dbg !15
+  br i1 %exitcond, label %for.body, label %for.end, !dbg !15
+
+for.end:                                          ; preds = %for.body
+  ret void, !dbg !18
+}
+
+; CHECK: note: Polly detected an optimizable loop region (scop) in function 'bar'
+; CHECK: test.c:9: Start of scop
+; CHECK: test.c:13: End of scop
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.5 ", isOptimized: false, emissionKind: 0, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!1 = !DIFile(filename: "test.c", directory: "/home/grosser/Projects/polly/git/tools/polly")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "foo", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 1, file: !1, scope: !5, type: !6, variables: !2)
+!5 = !DIFile(filename: "test.c", directory: "/home/grosser/Projects/polly/git/tools/polly")
+!6 = !DISubroutineType(types: !{null})
+!7 = distinct !DISubprogram(name: "bar", line: 6, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 6, file: !1, scope: !5, type: !6, variables: !2)
+!8 = !{i32 2, !"Dwarf Version", i32 4}
+!9 = !{i32 1, !"Debug Info Version", i32 3}
+!10 = !{!"clang version 3.5 "}
+!11 = !DILocation(line: 2, scope: !12)
+!12 = distinct !DILexicalBlock(line: 2, column: 0, file: !1, scope: !4)
+!13 = !DILocation(line: 3, scope: !12)
+!14 = !DILocation(line: 4, scope: !4)
+!15 = !DILocation(line: 9, scope: !16)
+!16 = distinct !DILexicalBlock(line: 9, column: 0, file: !1, scope: !7)
+!17 = !DILocation(line: 13, scope: !16)
+!18 = !DILocation(line: 14, scope: !7)
+
diff --git a/final/test/ScopDetect/restrict-undef-size-scopdetect.ll b/final/test/ScopDetect/restrict-undef-size-scopdetect.ll
new file mode 100644
index 0000000..4918e58
--- /dev/null
+++ b/final/test/ScopDetect/restrict-undef-size-scopdetect.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect -analyze  < %s | FileCheck %s
+; CHECK-NOT: Valid Region for Scop:
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.bar = type { i32, [4 x i32] }
+
+define void @f(%struct.bar* %arg) {
+bb:
+  %tmp = alloca [4 x i32], align 16
+  br label %bb1
+
+bb1:                                              ; preds = %bb8, %bb
+  %tmp2 = phi i64 [ 0, %bb ], [ %tmp9, %bb8 ]
+  br i1 false, label %bb3, label %bb6
+
+bb3:                                              ; preds = %bb1
+  %tmp4 = getelementptr inbounds [4 x i32], [4 x i32]* %tmp, i64 0, i64 0
+  %tmp5 = load i32, i32* %tmp4
+  br label %bb8
+
+bb6:                                              ; preds = %bb1
+  %tmp7 = getelementptr inbounds %struct.bar, %struct.bar* %arg, i64 0, i32 1, i64 undef
+  store i32 42, i32* %tmp7
+  br label %bb8
+
+bb8:                                              ; preds = %bb6, %bb3
+  %tmp9 = add nuw nsw i64 %tmp2, 1
+  br i1 false, label %bb1, label %bb10
+
+bb10:                                             ; preds = %bb8
+  ret void
+}
diff --git a/final/test/ScopDetect/run_time_alias_check.ll b/final/test/ScopDetect/run_time_alias_check.ll
new file mode 100644
index 0000000..3210d63
--- /dev/null
+++ b/final/test/ScopDetect/run_time_alias_check.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+declare float* @getNextBasePtr(float*) readnone nounwind
+
+define void @base_pointer_is_inst_inside_invariant_1(i64 %n, float* %A, float* %B) {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ %indvar.i.next, %for.i.inc ], [ 0, %entry ]
+  br label %S1
+
+S1:
+; To get an instruction inside a region, we use a function without side
+; effects on which SCEV blocks, but for which it is still clear that the
+; return value remains invariant throughout the whole loop.
+  %ptr = call float* @getNextBasePtr(float* %A)
+  %conv = sitofp i64 %indvar.i to float
+  %arrayidx5 = getelementptr float, float* %ptr, i64 %indvar.i
+  store float %conv, float* %arrayidx5, align 4
+  store float 1.0, float* %B
+  br label %for.i.inc
+
+for.i.inc:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %exitcond.i = icmp ne i64 %indvar.i.next, %n
+  br i1 %exitcond.i, label %for.i, label %exit
+
+exit:
+  ret void
+}
+
+; CHECK-NOT: Valid Region for Scop
diff --git a/final/test/ScopDetect/scev_remove_max.ll b/final/test/ScopDetect/scev_remove_max.ll
new file mode 100644
index 0000000..18342a4
--- /dev/null
+++ b/final/test/ScopDetect/scev_remove_max.ll
@@ -0,0 +1,40 @@
+; RUN: opt %loadPolly -polly-detect < %s
+
+; This test case helps to determine wether SCEVRemoveMax::remove produces
+; an infinite loop and a segmentation fault, if it processes, for example,
+; '((-1 + (-1 * %b1)) umax {(-1 + (-1 * %yStart)),+,-1}<%.preheader>)'.
+;
+; In this case, the SCoP is invalid. However, SCoP detection failed when
+; running over it.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@vertPlane = external global i8*, align 8
+
+define fastcc void @Maze2Mech(i64 %i, i64 %b1, i64 %yStart) {
+.split:
+  br i1 undef, label %DrawSegment.exit, label %DrawSegment.exit34
+
+DrawSegment.exit34:                               ; preds = %.split
+  %tmp = icmp ugt i64 %yStart, %b1
+  %tmp1 = select i1 %tmp, i64 %b1, i64 %yStart
+  %tmp2 = load i8*, i8** @vertPlane, align 8
+  %y.04.i21 = add i64 %tmp1, 1
+  br label %.lr.ph.i24
+
+.lr.ph.i24:                                       ; preds = %.lr.ph.i24, %DrawSegment.exit34
+  %y.05.i22 = phi i64 [ %y.0.i23, %.lr.ph.i24 ], [ %y.04.i21, %DrawSegment.exit34 ]
+  %tmp3 = mul i64 %y.05.i22, undef
+  %tmp4 = add i64 %tmp3, %i
+  %tmp5 = getelementptr inbounds i8, i8* %tmp2, i64 %tmp4
+  %tmp6 = load i8, i8* %tmp5, align 1
+  %y.0.i23 = add nuw i64 %y.05.i22, 1
+  br i1 false, label %bb, label %.lr.ph.i24
+
+bb:                                               ; preds = %.lr.ph.i24
+  unreachable
+
+DrawSegment.exit:                                 ; preds = %.split
+  ret void
+}
diff --git a/final/test/ScopDetect/sequential_loops.ll b/final/test/ScopDetect/sequential_loops.ll
new file mode 100644
index 0000000..8362979
--- /dev/null
+++ b/final/test/ScopDetect/sequential_loops.ll
@@ -0,0 +1,92 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+; Two sequential loops right after each other.
+;
+; void f(long A[], long N) {
+;   long i;
+;   for (i = 0; i < N; ++i)
+;     A[i] = i;
+;   for (i = 0; i < N; ++i)
+;     A[i] = i;
+; }
+
+define void @f1(i64* %A, i64 %N) nounwind {
+; CHECK-LABEL: 'Polly - Detect static control parts (SCoPs)' for function 'f1'
+entry:
+  fence seq_cst
+  br label %for.i.1
+
+for.i.1:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %for.i.1 ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %for.i.2, label %for.i.1
+
+for.i.2:
+  %indvar.2 = phi i64 [ 0, %for.i.1 ], [ %indvar.next.2, %for.i.2 ]
+  %scevgep.2 = getelementptr i64, i64* %A, i64 %indvar.2
+  store i64 %indvar.2, i64* %scevgep.2
+  %indvar.next.2 = add nsw i64 %indvar.2, 1
+  %exitcond.2 = icmp eq i64 %indvar.next.2, %N
+  br i1 %exitcond.2, label %return, label %for.i.2
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; C-H-E-C-K: Valid Region for Scop: for.i.1 => return
+; This one is currently not completely detected due to the PHI node in
+; for.i.2 causing a 'PHI node in exit BB' error for the first loop. This should
+; be fixed at some point. Such test cases do not really show up for us, as
+; the -loop-simplify pass always inserts a preheader as in the test case below.
+
+; Two sequential loops with a basic block in between.
+;
+;     void f(long A[], long N) {
+;       long i;
+;
+;       for (i = 0; i < N; ++i)
+;         A[i] = i;
+; preheader:
+;       ;
+;
+;       for (i = 0; i < N; ++i)
+;         A[i] = i;
+;     }
+
+define void @f2(i64* %A, i64 %N) nounwind {
+; CHECK-LABEL: 'Polly - Detect static control parts (SCoPs)' for function 'f2'
+entry:
+  fence seq_cst
+  br label %for.i.1
+
+for.i.1:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %for.i.1 ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %preheader, label %for.i.1
+
+preheader:
+  br label %for.i.2
+
+for.i.2:
+  %indvar.2 = phi i64 [ 0, %preheader ], [ %indvar.next.2, %for.i.2 ]
+  %scevgep.2 = getelementptr i64, i64* %A, i64 %indvar.2
+  store i64 %indvar.2, i64* %scevgep.2
+  %indvar.next.2 = add nsw i64 %indvar.2, 1
+  %exitcond.2 = icmp eq i64 %indvar.next.2, %N
+  br i1 %exitcond.2, label %return, label %for.i.2
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: Valid Region for Scop: for.i.1 => return
diff --git a/final/test/ScopDetect/simple_loop.ll b/final/test/ScopDetect/simple_loop.ll
new file mode 100644
index 0000000..9ef41a6
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop.ll
@@ -0,0 +1,29 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+; void f(long A[], long N) {
+;   long i;
+;   for (i = 0; i < N; ++i)
+;     A[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br label %for.i
+
+for.i:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: Valid Region for Scop: for.i => return
diff --git a/final/test/ScopDetect/simple_loop_non_single_entry.ll b/final/test/ScopDetect/simple_loop_non_single_entry.ll
new file mode 100644
index 0000000..ccf5c67
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop_non_single_entry.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+; void f(long A[], long N) {
+;   long i;
+;
+;  if (true)
+;    goto loop;
+;  else
+;    goto loop;
+;
+; loop:
+;   for (i = 0; i < N; ++i)
+;     A[i] = i;
+; }
+
+; We will detect this scop even if the loop is not in lcssa form
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br i1 true, label %then, label %else
+
+then:
+  br label %for.i
+
+else:
+  br label %for.i
+
+for.i:
+  %indvar = phi i64 [ 0, %then ], [ 0, %else], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: Valid Region for Scop
diff --git a/final/test/ScopDetect/simple_loop_non_single_exit.ll b/final/test/ScopDetect/simple_loop_non_single_exit.ll
new file mode 100644
index 0000000..434b203
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop_non_single_exit.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+; void f(long A[], long N) {
+;   long i;
+;   if (true)
+;     for (i = 0; i < N; ++i)
+;       A[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br label %next
+
+next:
+  br i1 true, label %for.i, label %return
+
+for.i:
+  %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: Valid Region for Scop: next => return
diff --git a/final/test/ScopDetect/simple_loop_non_single_exit_2.ll b/final/test/ScopDetect/simple_loop_non_single_exit_2.ll
new file mode 100644
index 0000000..7a9b9aa
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop_non_single_exit_2.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+; void f(long A[], long N) {
+;   long i;
+;   if (true)
+;     if (true)
+;       for (i = 0; i < N; ++i)
+;         A[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br i1 true, label %next, label %return
+
+next:
+  br i1 true, label %for.i, label %return
+
+for.i:
+  %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: Valid Region for Scop: next => return
diff --git a/final/test/ScopDetect/simple_loop_two_phi_nodes.ll b/final/test/ScopDetect/simple_loop_two_phi_nodes.ll
new file mode 100644
index 0000000..93acd65
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop_two_phi_nodes.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect  -analyze < %s | FileCheck %s
+
+; void f(long A[], long N) {
+;   long i;
+;   long i_non_canonical = 1;
+;   for (i = 0; i < N; ++i) {
+;     A[i] = i_non_canonical;
+;     i_non_canonical += 1;
+;   }
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  %cmp = icmp sgt i64 %N, 0
+  br i1 %cmp, label %for.i, label %return
+
+for.i:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %for.i ]
+  %indvar_non_canonical = phi i64 [ 1, %entry ], [ %indvar_non_canonical.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar_non_canonical, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %indvar_non_canonical.next = add nsw i64 %indvar_non_canonical, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  ret void
+}
+
+; CHECK: Valid Region for Scop: for.i => return
diff --git a/final/test/ScopDetect/simple_loop_with_param.ll b/final/test/ScopDetect/simple_loop_with_param.ll
new file mode 100644
index 0000000..69177a4
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop_with_param.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -basicaa -polly-detect -analyze  < %s | FileCheck %s -check-prefix=PHI
+
+; void f(long A[], long N, long *init_ptr) {
+;   long i, j;
+;   long i_non_canonical;
+;
+;   for (i = 0; i < N; ++i) {
+;     init = *init_ptr;
+;     i_non_canonical = init;
+;     for (i = 0; i < N; ++i) {
+;       A[i] = i_non_canonical;
+;       i_non_canonical += 1;
+;     }
+;   }
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* noalias %A, i64 %N, i64* noalias %init_ptr) nounwind {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ 0, %entry ], [ %indvar.i.next, %for.i.end ]
+  %indvar.i.next = add nsw i64 %indvar.i, 1
+  br label %entry.next
+
+entry.next:
+  %init = load i64, i64* %init_ptr
+  br label %for.j
+
+for.j:
+  %indvar.j = phi i64 [ 0, %entry.next ], [ %indvar.j.next, %for.j ]
+  %indvar.j.non_canonical = phi i64 [ %init, %entry.next ], [ %indvar.j.non_canonical.next, %for.j ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar.j
+  store i64 %indvar.j.non_canonical, i64* %scevgep
+  %indvar.j.next = add nsw i64 %indvar.j, 1
+  %indvar.j.non_canonical.next = add nsw i64 %indvar.j.non_canonical, 1
+  %exitcond.j = icmp eq i64 %indvar.j.next, %N
+  br i1 %exitcond.j, label %for.i.end, label %for.j
+
+for.i.end:
+  %exitcond.i = icmp eq i64 %indvar.i.next, %N
+  br i1 %exitcond.i, label %return, label %for.i
+
+return:
+  ret void
+}
+
+; PHI: Valid Region for Scop: for.i => return
diff --git a/final/test/ScopDetect/simple_loop_with_param_2.ll b/final/test/ScopDetect/simple_loop_with_param_2.ll
new file mode 100644
index 0000000..c619958
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop_with_param_2.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -basicaa -polly-detect -analyze < %s | FileCheck %s
+
+; void f(long A[], int N, int *init_ptr) {
+;   long i, j;
+;
+;   for (i = 0; i < N; ++i) {
+;     init = *init_ptr;
+;     for (i = 0; i < N; ++i) {
+;       A[i] = init + 2;
+;     }
+;   }
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* noalias %A, i64 %N, i64* noalias %init_ptr) nounwind {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ 0, %entry ], [ %indvar.i.next, %for.i.end ]
+  %indvar.i.next = add nsw i64 %indvar.i, 1
+  br label %entry.next
+
+entry.next:
+  %init = load i64, i64* %init_ptr
+  br label %for.j
+
+for.j:
+  %indvar.j = phi i64 [ 0, %entry.next ], [ %indvar.j.next, %for.j ]
+  %init_plus_two = add i64 %init, 2
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar.j
+  store i64 %init_plus_two, i64* %scevgep
+  %indvar.j.next = add nsw i64 %indvar.j, 1
+  %exitcond.j = icmp eq i64 %indvar.j.next, %N
+  br i1 %exitcond.j, label %for.i.end, label %for.j
+
+for.i.end:
+  %exitcond.i = icmp eq i64 %indvar.i.next, %N
+  br i1 %exitcond.i, label %return, label %for.i
+
+return:
+  ret void
+}
+
+; CHECK: Valid Region for Scop: for.i => return
diff --git a/final/test/ScopDetect/simple_non_single_entry.ll b/final/test/ScopDetect/simple_non_single_entry.ll
new file mode 100644
index 0000000..f154d5c
--- /dev/null
+++ b/final/test/ScopDetect/simple_non_single_entry.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+; void f(long A[], long N) {
+;   long i;
+;
+;  if (true){
+;    i = 0;
+;    goto next;
+;  }else{
+;    i = 1;
+;    goto next;
+; }
+;
+; next:
+;  if (true)
+;    goto for.i;
+;  else
+;    goto for.i;
+;
+; for.i:
+;   for (i = 0; i < N; ++i)
+;     A[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br i1 true, label %then1, label %else1
+
+then1:
+  br label %next
+
+else1:
+  br label %next
+
+next:
+  br i1 true, label %then, label %else
+
+then:
+  br label %for.i.head
+
+else:
+  br label %for.i.head
+
+for.i.head:
+  br label %for.i.head1
+
+for.i.head1:
+  br label %for.i
+
+for.i:
+  %indvar = phi i64 [ 0, %for.i.head1], [ %indvar.next, %for.i ]
+  fence seq_cst
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  ret void
+}
+
+; CHECK: Valid Region for Scop: next => for.i
diff --git a/final/test/ScopDetect/skip_function_attribute.ll b/final/test/ScopDetect/skip_function_attribute.ll
new file mode 100644
index 0000000..0e219d9
--- /dev/null
+++ b/final/test/ScopDetect/skip_function_attribute.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+;
+; Verify polly skips this function
+;
+; CHECK-NOT: Valid Region for Scop
+;
+;    void polly_skip_me(int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        A[i] = A[i] * A[i] + A[i];
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @polly_skip_me(i32* %A, i32 %N) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %cmp1 = icmp sgt i32 %N, 0
+  br i1 %cmp1, label %for.body.preheader, label %for.end
+
+for.body.preheader:                               ; preds = %entry.split
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.preheader, %for.body
+  %i.02 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ]
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.02
+  %tmp = load i32, i32* %arrayidx, align 4
+  %mul = mul nsw i32 %tmp, %tmp
+  %add = add nsw i32 %mul, %tmp
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i32 %i.02
+  store i32 %add, i32* %arrayidx3, align 4
+  %inc = add nsw i32 %i.02, 1
+  %cmp = icmp slt i32 %inc, %N
+  br i1 %cmp, label %for.body, label %for.end.loopexit
+
+for.end.loopexit:                                 ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.end.loopexit, %entry.split
+  ret void
+}
+
+attributes #0 = { "polly.skip.fn" }
diff --git a/final/test/ScopDetect/srem_with_parametric_divisor.ll b/final/test/ScopDetect/srem_with_parametric_divisor.ll
new file mode 100644
index 0000000..757a4da
--- /dev/null
+++ b/final/test/ScopDetect/srem_with_parametric_divisor.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+;
+; CHECK-NOT: Valid Region for Scop:
+;
+;    void foo(float *A, long n, long p) {
+;      for (long i = 0; i < 100; i++)
+;        A[n % p] += 1;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A, i64 %n, i64 %p) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = srem i64 %n, %p
+  %tmp3 = getelementptr inbounds float, float* %A, i64 %tmp
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, 1.000000e+00
+  store float %tmp5, float* %tmp3, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopDetect/statistics.ll b/final/test/ScopDetect/statistics.ll
new file mode 100644
index 0000000..da78821
--- /dev/null
+++ b/final/test/ScopDetect/statistics.ll
@@ -0,0 +1,278 @@
+; RUN: opt %loadPolly -polly-detect -stats -disable-output < %s 2>&1 | FileCheck %s
+
+; REQUIRES: asserts
+
+; CHECK-DAG:  4 polly-detect     - Maximal number of loops in scops (profitable scops only)
+; CHECK-DAG:  4 polly-detect     - Maximal number of loops in scops
+; CHECK-DAG: 11 polly-detect     - Number of loops in scops (profitable scops only)
+; CHECK-DAG: 11 polly-detect     - Number of loops in scops
+; CHECK-DAG: 11 polly-detect     - Number of total loops
+; CHECK-DAG:  5 polly-detect     - Number of scops (profitable scops only)
+; CHECK-DAG:  1 polly-detect     - Number of scops with maximal loop depth 4 (profitable scops only)
+; CHECK-DAG:  2 polly-detect     - Number of scops with maximal loop depth 1 (profitable scops only)
+; CHECK-DAG:  1 polly-detect     - Number of scops with maximal loop depth 3 (profitable scops only)
+; CHECK-DAG:  1 polly-detect     - Number of scops with maximal loop depth 2 (profitable scops only)
+; CHECK-DAG:  5 polly-detect     - Number of scops
+; CHECK-DAG:  1 polly-detect     - Number of scops with maximal loop depth 4
+; CHECK-DAG:  2 polly-detect     - Number of scops with maximal loop depth 1
+; CHECK-DAG:  1 polly-detect     - Number of scops with maximal loop depth 3
+; CHECK-DAG:  1 polly-detect     - Number of scops with maximal loop depth 2
+
+;    void foo_1d(float *A) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += i;
+;    }
+;
+;    void foo_2d(float *A) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          A[i + j] += i + j;
+;    }
+;
+;    void foo_3d(float *A) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          for (long k = 0; k < 1024; k++)
+;            A[i + j + k] += i + j + k;
+;    }
+;
+;    void foo_4d(float *A) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          for (long k = 0; k < 1024; k++)
+;            for (long l = 0; l < 1024; l++)
+;              A[i + j + k + l] += i + j + k + l;
+;    }
+;
+;    void foo_zero_iterations(float *S) {
+;      for (long i = 0; i < 0; i++)
+;        A[i] += i;
+;    }
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo_1d(float* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = sitofp i64 %i.0 to float
+  %tmp3 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, %tmp
+  store float %tmp5, float* %tmp3, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
+
+define void @foo_2d(float* %A) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb14, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp15, %bb14 ]
+  %exitcond1 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond1, label %bb3, label %bb16
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb11, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp12, %bb11 ]
+  %exitcond = icmp ne i64 %j.0, 1024
+  br i1 %exitcond, label %bb5, label %bb13
+
+bb5:                                              ; preds = %bb4
+  %tmp = add nuw nsw i64 %i.0, %j.0
+  %tmp6 = sitofp i64 %tmp to float
+  %tmp7 = add nuw nsw i64 %i.0, %j.0
+  %tmp8 = getelementptr inbounds float, float* %A, i64 %tmp7
+  %tmp9 = load float, float* %tmp8, align 4
+  %tmp10 = fadd float %tmp9, %tmp6
+  store float %tmp10, float* %tmp8, align 4
+  br label %bb11
+
+bb11:                                             ; preds = %bb5
+  %tmp12 = add nuw nsw i64 %j.0, 1
+  br label %bb4
+
+bb13:                                             ; preds = %bb4
+  br label %bb14
+
+bb14:                                             ; preds = %bb13
+  %tmp15 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb16:                                             ; preds = %bb2
+  ret void
+}
+
+define void @foo_3d(float* %A) {
+bb:
+  br label %bb3
+
+bb3:                                              ; preds = %bb22, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp23, %bb22 ]
+  %exitcond2 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond2, label %bb4, label %bb24
+
+bb4:                                              ; preds = %bb3
+  br label %bb5
+
+bb5:                                              ; preds = %bb19, %bb4
+  %j.0 = phi i64 [ 0, %bb4 ], [ %tmp20, %bb19 ]
+  %exitcond1 = icmp ne i64 %j.0, 1024
+  br i1 %exitcond1, label %bb6, label %bb21
+
+bb6:                                              ; preds = %bb5
+  br label %bb7
+
+bb7:                                              ; preds = %bb16, %bb6
+  %k.0 = phi i64 [ 0, %bb6 ], [ %tmp17, %bb16 ]
+  %exitcond = icmp ne i64 %k.0, 1024
+  br i1 %exitcond, label %bb8, label %bb18
+
+bb8:                                              ; preds = %bb7
+  %tmp = add nuw nsw i64 %i.0, %j.0
+  %tmp9 = add nuw nsw i64 %tmp, %k.0
+  %tmp10 = sitofp i64 %tmp9 to float
+  %tmp11 = add nuw nsw i64 %i.0, %j.0
+  %tmp12 = add nuw nsw i64 %tmp11, %k.0
+  %tmp13 = getelementptr inbounds float, float* %A, i64 %tmp12
+  %tmp14 = load float, float* %tmp13, align 4
+  %tmp15 = fadd float %tmp14, %tmp10
+  store float %tmp15, float* %tmp13, align 4
+  br label %bb16
+
+bb16:                                             ; preds = %bb8
+  %tmp17 = add nuw nsw i64 %k.0, 1
+  br label %bb7
+
+bb18:                                             ; preds = %bb7
+  br label %bb19
+
+bb19:                                             ; preds = %bb18
+  %tmp20 = add nuw nsw i64 %j.0, 1
+  br label %bb5
+
+bb21:                                             ; preds = %bb5
+  br label %bb22
+
+bb22:                                             ; preds = %bb21
+  %tmp23 = add nuw nsw i64 %i.0, 1
+  br label %bb3
+
+bb24:                                             ; preds = %bb3
+  ret void
+}
+
+define void @foo_4d(float* %A) {
+bb:
+  br label %bb4
+
+bb4:                                              ; preds = %bb30, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp31, %bb30 ]
+  %exitcond3 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond3, label %bb5, label %bb32
+
+bb5:                                              ; preds = %bb4
+  br label %bb6
+
+bb6:                                              ; preds = %bb27, %bb5
+  %j.0 = phi i64 [ 0, %bb5 ], [ %tmp28, %bb27 ]
+  %exitcond2 = icmp ne i64 %j.0, 1024
+  br i1 %exitcond2, label %bb7, label %bb29
+
+bb7:                                              ; preds = %bb6
+  br label %bb8
+
+bb8:                                              ; preds = %bb24, %bb7
+  %k.0 = phi i64 [ 0, %bb7 ], [ %tmp25, %bb24 ]
+  %exitcond1 = icmp ne i64 %k.0, 1024
+  br i1 %exitcond1, label %bb9, label %bb26
+
+bb9:                                              ; preds = %bb8
+  br label %bb10
+
+bb10:                                             ; preds = %bb21, %bb9
+  %l.0 = phi i64 [ 0, %bb9 ], [ %tmp22, %bb21 ]
+  %exitcond = icmp ne i64 %l.0, 1024
+  br i1 %exitcond, label %bb11, label %bb23
+
+bb11:                                             ; preds = %bb10
+  %tmp = add nuw nsw i64 %i.0, %j.0
+  %tmp12 = add nuw nsw i64 %tmp, %k.0
+  %tmp13 = add nuw nsw i64 %tmp12, %l.0
+  %tmp14 = sitofp i64 %tmp13 to float
+  %tmp15 = add nuw nsw i64 %i.0, %j.0
+  %tmp16 = add nuw nsw i64 %tmp15, %k.0
+  %tmp17 = add nuw nsw i64 %tmp16, %l.0
+  %tmp18 = getelementptr inbounds float, float* %A, i64 %tmp17
+  %tmp19 = load float, float* %tmp18, align 4
+  %tmp20 = fadd float %tmp19, %tmp14
+  store float %tmp20, float* %tmp18, align 4
+  br label %bb21
+
+bb21:                                             ; preds = %bb11
+  %tmp22 = add nuw nsw i64 %l.0, 1
+  br label %bb10
+
+bb23:                                             ; preds = %bb10
+  br label %bb24
+
+bb24:                                             ; preds = %bb23
+  %tmp25 = add nuw nsw i64 %k.0, 1
+  br label %bb8
+
+bb26:                                             ; preds = %bb8
+  br label %bb27
+
+bb27:                                             ; preds = %bb26
+  %tmp28 = add nuw nsw i64 %j.0, 1
+  br label %bb6
+
+bb29:                                             ; preds = %bb6
+  br label %bb30
+
+bb30:                                             ; preds = %bb29
+  %tmp31 = add nuw nsw i64 %i.0, 1
+  br label %bb4
+
+bb32:                                             ; preds = %bb4
+  ret void
+}
+
+define void @foo_zero_iterations(float* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %exitcond = icmp ne i64 %i.0, 0
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = sitofp i64 %i.0 to float
+  %tmp3 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, %tmp
+  store float %tmp5, float* %tmp3, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopDetect/switch-in-loop-patch.ll b/final/test/ScopDetect/switch-in-loop-patch.ll
new file mode 100644
index 0000000..6694446
--- /dev/null
+++ b/final/test/ScopDetect/switch-in-loop-patch.ll
@@ -0,0 +1,21 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+
+; CHECK-NOT: Valid
+
+; Verify that we do not detect loops where the loop latch is a switch statement.
+; Such loops are not yet supported by Polly.
+
+define void @f() {
+b:
+  br label %d
+
+d:
+  switch i8 0, label %e [
+    i8 71, label %d
+    i8 56, label %d
+  ]
+
+e:
+ ret void
+}
+
diff --git a/final/test/ScopDetect/tlr_is_hoistable_load.ll b/final/test/ScopDetect/tlr_is_hoistable_load.ll
new file mode 100644
index 0000000..7581798
--- /dev/null
+++ b/final/test/ScopDetect/tlr_is_hoistable_load.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -analyze -polly-scops -polly-invariant-load-hoisting \
+; RUN:     -polly-detect-full-functions < %s | FileCheck %s
+;
+; This testcase checks for compatibility of the -detect-full-functions
+; flag in combination with the -invariant-load-hoisting option. More
+; specifically, ScopHelper.cpp::isHoistableLoad only gets called if
+; -invariant-load-hoisting is enabled. This function, however, had a bug
+; which caused a crash if the region argument was top-level. This test
+; is a minimal example that hits this specific code path.
+;
+; Also note that this file's IR is in no way optimized, i.e. it was
+; generated with clang -O0 from the following C-code:
+;
+;    void test() {
+;      int A[] = {1, 2, 3, 4, 5};
+;      int len = (sizeof A) / sizeof(int);
+;      for (int i = 0; i < len; ++i) {
+;        A[i] = A[i] * 2;
+;      }
+;    }
+;
+; This is also the reason why polly does not detect any scops (the loop
+; variable i is loaded from and stored to memory in each iteration):
+;
+; CHECK:      region: 'for.cond => for.end' in function 'test':
+; CHECK-NEXT: Invalid Scop!
+; CHECK-NEXT: region: 'entry => <Function Return>' in function 'test':
+; CHECK-NEXT: Invalid Scop!
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@test.A = private unnamed_addr constant [5 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5], align 16
+
+define void @test() {
+entry:
+  %A = alloca [5 x i32], align 16
+  %len = alloca i32, align 4
+  %i = alloca i32, align 4
+  %0 = bitcast [5 x i32]* %A to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* bitcast ([5 x i32]* @test.A to i8*), i64 20, i32 16, i1 false)
+  store i32 5, i32* %len, align 4
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %1 = load i32, i32* %i, align 4
+  %2 = load i32, i32* %len, align 4
+  %cmp = icmp slt i32 %1, %2
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %3 = load i32, i32* %i, align 4
+  %idxprom = sext i32 %3 to i64
+  %arrayidx = getelementptr inbounds [5 x i32], [5 x i32]* %A, i64 0, i64 %idxprom
+  %4 = load i32, i32* %arrayidx, align 4
+  %mul = mul nsw i32 %4, 2
+  %5 = load i32, i32* %i, align 4
+  %idxprom1 = sext i32 %5 to i64
+  %arrayidx2 = getelementptr inbounds [5 x i32], [5 x i32]* %A, i64 0, i64 %idxprom1
+  store i32 %mul, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %6 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %6, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1)
diff --git a/final/test/ScopDetectionDiagnostics/ReportAlias-01.ll b/final/test/ScopDetectionDiagnostics/ReportAlias-01.ll
new file mode 100644
index 0000000..119afdc
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportAlias-01.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-use-runtime-alias-checks=false -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -analyze < %s 2>&1| FileCheck %s
+
+;void f(int A[], int B[]) {
+;  for (int i=0; i<42; i++)
+;    A[i] = B[i];
+;}
+
+; CHECK: remark: ReportAlias-01.c:2:8: The following errors keep this region from being a Scop.
+; CHECK: remark: ReportAlias-01.c:3:5: Accesses to the arrays "B", "A" may access the same memory.
+; CHECK: remark: ReportAlias-01.c:3:5: Invalid Scop candidate ends here.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %B) !dbg !4 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  tail call void @llvm.dbg.value(metadata i32* %A, i64 0, metadata !13, metadata !DIExpression()), !dbg !14
+  tail call void @llvm.dbg.value(metadata i32* %B, i64 0, metadata !15, metadata !DIExpression()), !dbg !16
+  tail call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !18, metadata !DIExpression()), !dbg !20
+  br label %for.body, !dbg !21
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %indvar = phi i64 [ 0, %entry.split ], [ %indvar.next, %for.body ]
+  %arrayidx = getelementptr i32, i32* %B, i64 %indvar, !dbg !22
+  %arrayidx2 = getelementptr i32, i32* %A, i64 %indvar, !dbg !22
+  %0 = load i32, i32* %arrayidx, align 4, !dbg !22
+  store i32 %0, i32* %arrayidx2, align 4, !dbg !22
+  tail call void @llvm.dbg.value(metadata !{null}, i64 0, metadata !18, metadata !DIExpression()), !dbg !20
+  %indvar.next = add i64 %indvar, 1, !dbg !21
+  %exitcond = icmp ne i64 %indvar.next, 42, !dbg !21
+  br i1 %exitcond, label %for.body, label %for.end, !dbg !21
+
+for.end:                                          ; preds = %for.body
+  ret void, !dbg !23
+}
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!10, !11}
+!llvm.ident = !{!12}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.6.0 ", isOptimized: false, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!1 = !DIFile(filename: "ReportAlias-01.c", directory: "test/ScopDetectionDiagnostic/")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "f", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 1, file: !1, scope: !5, type: !6, variables: !2)
+!5 = !DIFile(filename: "ReportAlias-01.c", directory: "test/ScopDetectionDiagnostic/")
+!6 = !DISubroutineType(types: !7)
+!7 = !{null, !8, !8}
+!8 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, baseType: !9)
+!9 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!10 = !{i32 2, !"Dwarf Version", i32 4}
+!11 = !{i32 2, !"Debug Info Version", i32 3}
+!12 = !{!"clang version 3.6.0 "}
+!13 = !DILocalVariable(name: "A", line: 1, arg: 1, scope: !4, file: !5, type: !8)
+!14 = !DILocation(line: 1, column: 12, scope: !4)
+!15 = !DILocalVariable(name: "B", line: 1, arg: 2, scope: !4, file: !5, type: !8)
+!16 = !DILocation(line: 1, column: 21, scope: !4)
+!17 = !{i32 0}
+!18 = !DILocalVariable(name: "i", line: 2, scope: !19, file: !5, type: !9)
+!19 = distinct !DILexicalBlock(line: 2, column: 3, file: !1, scope: !4)
+!20 = !DILocation(line: 2, column: 12, scope: !19)
+!21 = !DILocation(line: 2, column: 8, scope: !19)
+!22 = !DILocation(line: 3, column: 5, scope: !19)
+!23 = !DILocation(line: 4, column: 1, scope: !4)
diff --git a/final/test/ScopDetectionDiagnostics/ReportEntry.ll b/final/test/ScopDetectionDiagnostics/ReportEntry.ll
new file mode 100644
index 0000000..fac0bd9
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportEntry.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -analyze -polly-detect \
+; RUN:     -pass-remarks-missed="polly-detect" \
+; RUN:     < %s 2>&1| FileCheck %s
+
+; CHECK: remark: <unknown>:0:0: Scop contains function entry (not yet supported).
+
+define void @hoge(i8* %arg)  {
+bb1:
+  br i1 false, label %bb2, label %bb3
+
+bb2:
+  br i1 false, label %bb4, label %bb5
+
+bb4:
+  br i1 false, label %bb3, label %bb5
+
+bb5:
+  br label %bb6
+
+bb6:
+  br label %bb4
+
+bb3:
+  ret void
+}
+
diff --git a/final/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll b/final/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll
new file mode 100644
index 0000000..9595129
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -analyze < %s 2>&1 | FileCheck %s
+
+; #define N 1024
+; double invalidCall(double A[N]);
+;
+; void a(double A[N], int n) {
+;   for (int i=0; i<n; ++i) {
+;     A[i] = invalidCall(A);
+;   }
+; }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @a(double* %A, i32 %n) #0 !dbg !4 {
+entry:
+  %cmp1 = icmp sgt i32 %n, 0, !dbg !10
+  br i1 %cmp1, label %for.body.lr.ph, label %for.end, !dbg !10
+
+for.body.lr.ph:                                   ; preds = %entry
+  %0 = zext i32 %n to i64
+  br label %for.body, !dbg !10
+
+for.body:                                         ; preds = %for.body, %for.body.lr.ph
+  %indvar = phi i64 [ 0, %for.body.lr.ph ], [ %indvar.next, %for.body ]
+  %arrayidx = getelementptr double, double* %A, i64 %indvar, !dbg !12
+  %call = tail call double @invalidCall(double* %A) #2, !dbg !12
+  store double %call, double* %arrayidx, align 8, !dbg !12, !tbaa !14
+  %indvar.next = add i64 %indvar, 1, !dbg !10
+  %exitcond = icmp eq i64 %indvar.next, %0, !dbg !10
+  br i1 %exitcond, label %for.end.loopexit, label %for.body, !dbg !10
+
+for.end.loopexit:                                 ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.end.loopexit, %entry
+  ret void, !dbg !18
+}
+
+declare double @invalidCall(double*) #1
+
+; CHECK: remark: ReportFuncCall.c:4:8: The following errors keep this region from being a Scop.
+; CHECK: remark: ReportFuncCall.c:5:12: This function call cannot be handled. Try to inline it.
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.5.0 ", isOptimized: true, emissionKind: 2, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!1 = !DIFile(filename: "ReportFuncCall.c", directory: "/home/simbuerg/Projekte/llvm/tools/polly/test/ScopDetectionDiagnostics")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "a", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, scopeLine: 3, file: !1, scope: !5, type: !6, variables: !2)
+!5 = !DIFile(filename: "ReportFuncCall.c", directory: "/home/simbuerg/Projekte/llvm/tools/polly/test/ScopDetectionDiagnostics")
+!6 = !DISubroutineType(types: !2)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{!"clang version 3.5.0 "}
+!10 = !DILocation(line: 4, column: 8, scope: !11)
+!11 = distinct !DILexicalBlock(line: 4, column: 3, file: !1, scope: !4)
+!12 = !DILocation(line: 5, column: 12, scope: !13)
+!13 = distinct !DILexicalBlock(line: 4, column: 27, file: !1, scope: !11)
+!14 = !{!15, !15, i64 0}
+!15 = !{!"double", !16, i64 0}
+!16 = !{!"omnipotent char", !17, i64 0}
+!17 = !{!"Simple C/C++ TBAA"}
+!18 = !DILocation(line: 7, column: 1, scope: !4)
diff --git a/final/test/ScopDetectionDiagnostics/ReportIrreducibleRegion.ll b/final/test/ScopDetectionDiagnostics/ReportIrreducibleRegion.ll
new file mode 100644
index 0000000..8138c3c
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportIrreducibleRegion.ll
@@ -0,0 +1,119 @@
+; RUN: opt %loadPolly -analyze -polly-detect \
+; RUN:     -pass-remarks-missed="polly-detect" \
+; RUN:     < %s 2>&1| FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+;void foo(int a, int b) {
+;  if(b == 42) {
+;    if (a > 0) {
+;      LABEL1:
+;      a--;
+;    }
+;
+;    if (a > 0) {
+;      goto LABEL1;
+;    }
+;    b = b + 42;
+;  }
+;}
+
+; CHECK: remark: ReportIrreducibleRegion.c:3:7: The following errors keep this region from being a Scop.
+; CHECK-NEXT: remark: ReportIrreducibleRegion.c:9:4: Irreducible region encountered in control flow.
+; CHECK-NEXT: remark: ReportIrreducibleRegion.c:9:4: Invalid Scop candidate ends here.
+
+
+; Function Attrs: nounwind uwtable
+define void @foo(i32 %a, i32 %b) #0 !dbg !4 {
+entry:
+  %a.addr = alloca i32, align 4
+  %b.addr = alloca i32, align 4
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !11, metadata !12), !dbg !13
+  store i32 %b, i32* %b.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !14, metadata !12), !dbg !15
+  %0 = load i32, i32* %b.addr, align 4, !dbg !16
+  %cmp = icmp eq i32 %0, 42, !dbg !18
+  br i1 %cmp, label %if.then, label %if.end6, !dbg !19
+
+if.then:                                          ; preds = %entry
+  %1 = load i32, i32* %a.addr, align 4, !dbg !20
+  %cmp1 = icmp sgt i32 %1, 0, !dbg !23
+  br i1 %cmp1, label %if.then2, label %if.end, !dbg !24
+
+if.then2:                                         ; preds = %if.then
+  br label %LABEL1, !dbg !25
+
+LABEL1:                                           ; preds = %if.then4, %if.then2
+  %2 = load i32, i32* %a.addr, align 4, !dbg !27
+  %dec = add nsw i32 %2, -1, !dbg !27
+  store i32 %dec, i32* %a.addr, align 4, !dbg !27
+  br label %if.end, !dbg !29
+
+if.end:                                           ; preds = %LABEL1, %if.then
+  %3 = load i32, i32* %a.addr, align 4, !dbg !30
+  %cmp3 = icmp sgt i32 %3, 0, !dbg !32
+  br i1 %cmp3, label %if.then4, label %if.end5, !dbg !33
+
+if.then4:                                         ; preds = %if.end
+  br label %LABEL1, !dbg !34
+
+if.end5:                                          ; preds = %if.end
+  %4 = load i32, i32* %b.addr, align 4, !dbg !36
+  %add = add nsw i32 %4, 42, !dbg !37
+  store i32 %add, i32* %b.addr, align 4, !dbg !38
+  br label %if.end6, !dbg !39
+
+if.end6:                                          ; preds = %if.end5, %entry
+  ret void, !dbg !40
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (http://llvm.org/git/clang.git a9b56346a9fa49b176872a2068b479d4ff759ae4) (http://llvm.org/git/llvm.git 82a04b17aeffdf31b7665f927ac42d81e80c07f0)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2)
+!1 = !DIFile(filename: "ReportIrreducibleRegion.c", directory: "llvm/tools/polly/test/ScopDetectionDiagnostics")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null, !7, !7}
+!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!8 = !{i32 2, !"Dwarf Version", i32 4}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{!"clang version 3.8.0 (http://llvm.org/git/clang.git a9b56346a9fa49b176872a2068b479d4ff759ae4) (http://llvm.org/git/llvm.git 82a04b17aeffdf31b7665f927ac42d81e80c07f0)"}
+!11 = !DILocalVariable(name: "a", arg: 1, scope: !4, file: !1, line: 1, type: !7)
+!12 = !DIExpression()
+!13 = !DILocation(line: 1, column: 14, scope: !4)
+!14 = !DILocalVariable(name: "b", arg: 2, scope: !4, file: !1, line: 1, type: !7)
+!15 = !DILocation(line: 1, column: 21, scope: !4)
+!16 = !DILocation(line: 2, column: 5, scope: !17)
+!17 = distinct !DILexicalBlock(scope: !4, file: !1, line: 2, column: 5)
+!18 = !DILocation(line: 2, column: 7, scope: !17)
+!19 = !DILocation(line: 2, column: 5, scope: !4)
+!20 = !DILocation(line: 3, column: 7, scope: !21)
+!21 = distinct !DILexicalBlock(scope: !22, file: !1, line: 3, column: 7)
+!22 = distinct !DILexicalBlock(scope: !17, file: !1, line: 2, column: 14)
+!23 = !DILocation(line: 3, column: 9, scope: !21)
+!24 = !DILocation(line: 3, column: 7, scope: !22)
+!25 = !DILocation(line: 3, column: 14, scope: !26)
+!26 = !DILexicalBlockFile(scope: !21, file: !1, discriminator: 1)
+!27 = !DILocation(line: 5, column: 5, scope: !28)
+!28 = distinct !DILexicalBlock(scope: !21, file: !1, line: 3, column: 14)
+!29 = !DILocation(line: 6, column: 3, scope: !28)
+!30 = !DILocation(line: 8, column: 7, scope: !31)
+!31 = distinct !DILexicalBlock(scope: !22, file: !1, line: 8, column: 7)
+!32 = !DILocation(line: 8, column: 9, scope: !31)
+!33 = !DILocation(line: 8, column: 7, scope: !22)
+!34 = !DILocation(line: 9, column: 4, scope: !35)
+!35 = distinct !DILexicalBlock(scope: !31, file: !1, line: 8, column: 14)
+!36 = !DILocation(line: 11, column: 7, scope: !22)
+!37 = !DILocation(line: 11, column: 9, scope: !22)
+!38 = !DILocation(line: 11, column: 5, scope: !22)
+!39 = !DILocation(line: 12, column: 2, scope: !22)
+!40 = !DILocation(line: 13, column: 1, scope: !4)
diff --git a/final/test/ScopDetectionDiagnostics/ReportIrreducibleRegionWithoutDebugLoc.ll b/final/test/ScopDetectionDiagnostics/ReportIrreducibleRegionWithoutDebugLoc.ll
new file mode 100644
index 0000000..612de83
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportIrreducibleRegionWithoutDebugLoc.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -analyze -polly-detect \
+; RUN:     -pass-remarks-missed="polly-detect" \
+; RUN:     < %s 2>&1| FileCheck %s
+
+; CHECK: remark: <unknown>:0:0: Irreducible region encountered in control flow.
+
+define void @hoge(i8* %arg)  {
+bb1:
+  br i1 false, label %bb2, label %bb3
+
+bb2:
+  br i1 false, label %bb4, label %bb5
+
+bb4:
+  br i1 false, label %bb3, label %bb5
+
+bb5:
+  br label %bb6
+
+bb6:
+  br label %bb4
+
+bb3:
+  ret void
+}
+
diff --git a/final/test/ScopDetectionDiagnostics/ReportLoopBound-01.ll b/final/test/ScopDetectionDiagnostics/ReportLoopBound-01.ll
new file mode 100644
index 0000000..e81bce5
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportLoopBound-01.ll
@@ -0,0 +1,115 @@
+; RUN: opt %loadPolly \
+; RUN:     -pass-remarks-missed="polly-detect" -polly-detect-track-failures \
+; RUN:     -polly-allow-nonaffine-loops=false -polly-detect -analyze \
+; RUN:     < %s 2>&1| FileCheck %s --check-prefix=REJECTNONAFFINELOOPS
+; RUN: opt %loadPolly \
+; RUN:     -pass-remarks-missed="polly-detect" -polly-detect-track-failures \
+; RUN:     -polly-allow-nonaffine-loops=true -polly-detect -analyze \
+; RUN:     < %s 2>&1| FileCheck %s --check-prefix=ALLOWNONAFFINELOOPS
+; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" \
+; RUN:     -polly-process-unprofitable=false \
+; RUN:     -polly-detect-track-failures -polly-allow-nonaffine-loops=true \
+; RUN:     -polly-allow-nonaffine -polly-detect -analyze < %s 2>&1 \
+; RUN:     | FileCheck %s --check-prefix=ALLOWNONAFFINEALL
+
+; void f(int A[], int n) {
+;   for (int i = 0; i < A[n+i]; i++)
+;     A[i] = 0;
+; }
+
+; If we reject non-affine loops the non-affine loop bound will be reported:
+;
+; REJECTNONAFFINELOOPS: remark: ReportLoopBound-01.c:1:12: The following errors keep this region from being a Scop.
+; REJECTNONAFFINELOOPS: remark: ReportLoopBound-01.c:2:8: Failed to derive an affine function from the loop bounds.
+; REJECTNONAFFINELOOPS: remark: ReportLoopBound-01.c:3:5: Invalid Scop candidate ends here.
+
+; If we allow non-affine loops the non-affine access will be reported:
+;
+; ALLOWNONAFFINELOOPS: remark: ReportLoopBound-01.c:1:12: The following errors keep this region from being a Scop.
+; ALLOWNONAFFINELOOPS: remark: ReportLoopBound-01.c:3:5: The array subscript of "A" is not affine
+; ALLOWNONAFFINELOOPS: remark: ReportLoopBound-01.c:3:5: Invalid Scop candidate ends here.
+
+; If we allow non-affine loops and non-affine accesses the region will be reported as not profitable:
+;
+; ALLOWNONAFFINEALL: remark: ReportLoopBound-01.c:1:12: The following errors keep this region from being a Scop.
+; ALLOWNONAFFINEALL: remark: ReportLoopBound-01.c:1:12: No profitable polyhedral optimization found
+; ALLOWNONAFFINEALL: remark: ReportLoopBound-01.c:3:5: Invalid Scop candidate ends here.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %n) !dbg !4 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  tail call void @llvm.dbg.value(metadata i32* %A, i64 0, metadata !13, metadata !DIExpression()), !dbg !14
+  tail call void @llvm.dbg.value(metadata i32* %A, i64 0, metadata !13, metadata !DIExpression()), !dbg !14
+  tail call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !15, metadata !DIExpression()), !dbg !16
+  tail call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !18, metadata !DIExpression()), !dbg !20
+  %idxprom = sext i32 %n to i64, !dbg !21
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom, !dbg !21
+  %0 = load i32, i32* %arrayidx, align 4, !dbg !21
+  %cmp3 = icmp sgt i32 %0, 0, !dbg !21
+  br i1 %cmp3, label %for.body.lr.ph, label %for.end, !dbg !21
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  br label %for.body, !dbg !22
+
+for.body:                                         ; preds = %for.body.lr.ph, %for.body
+  %indvar = phi i64 [ 0, %for.body.lr.ph ], [ %indvar.next, %for.body ]
+  %arrayidx2 = getelementptr i32, i32* %A, i64 %indvar, !dbg !24
+  %1 = add i64 %indvar, 1, !dbg !24
+  %inc = trunc i64 %1 to i32, !dbg !21
+  store i32 0, i32* %arrayidx2, align 4, !dbg !24
+  tail call void @llvm.dbg.value(metadata !{null}, i64 0, metadata !18, metadata !DIExpression()), !dbg !20
+  %arrayidx3 = getelementptr inbounds i32, i32* %arrayidx, i64 %indvar, !dbg !21
+  %2 = load i32, i32* %arrayidx3, align 4, !dbg !21
+  %cmp = icmp slt i32 %inc, %2, !dbg !21
+  %indvar.next = add i64 %indvar, 1, !dbg !21
+  br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge, !dbg !21
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end, !dbg !25
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  ret void, !dbg !27
+}
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!10, !11}
+!llvm.ident = !{!12}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.6.0 ", isOptimized: false, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!1 = !DIFile(filename: "ReportLoopBound-01.c", directory: "test/ScopDetectionDiagnostic/")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "f", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 1, file: !1, scope: !5, type: !6, variables: !2)
+!5 = !DIFile(filename: "ReportLoopBound-01.c", directory: "test/ScopDetectionDiagnostic/")
+!6 = !DISubroutineType(types: !7)
+!7 = !{null, !8, !9}
+!8 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, baseType: !9)
+!9 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!10 = !{i32 2, !"Dwarf Version", i32 4}
+!11 = !{i32 2, !"Debug Info Version", i32 3}
+!12 = !{!"clang version 3.6.0 "}
+!13 = !DILocalVariable(name: "A", line: 1, arg: 1, scope: !4, file: !5, type: !8)
+!14 = !DILocation(line: 1, column: 12, scope: !4)
+!15 = !DILocalVariable(name: "n", line: 1, arg: 2, scope: !4, file: !5, type: !9)
+!16 = !DILocation(line: 1, column: 21, scope: !4)
+!17 = !{i32 0}
+!18 = !DILocalVariable(name: "i", line: 2, scope: !19, file: !5, type: !9)
+!19 = distinct !DILexicalBlock(line: 2, column: 3, file: !1, scope: !4)
+!20 = !DILocation(line: 2, column: 12, scope: !19)
+!21 = !DILocation(line: 2, column: 8, scope: !19)
+!22 = !DILocation(line: 2, column: 8, scope: !23)
+!23 = distinct !DILexicalBlock(line: 2, column: 8, file: !1, scope: !19)
+!24 = !DILocation(line: 3, column: 5, scope: !19)
+!25 = !DILocation(line: 2, column: 8, scope: !26)
+!26 = distinct !DILexicalBlock(line: 2, column: 8, file: !1, scope: !19)
+!27 = !DILocation(line: 4, column: 1, scope: !4)
diff --git a/final/test/ScopDetectionDiagnostics/ReportLoopHasNoExit.ll b/final/test/ScopDetectionDiagnostics/ReportLoopHasNoExit.ll
new file mode 100644
index 0000000..5ec99cf
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportLoopHasNoExit.ll
@@ -0,0 +1,107 @@
+; XFAIL: *
+
+; The test case stopped making sense after r310940 that added infinite loops to
+; the PostDominatorTree. Infinite loops are postdominated ony by the virtual
+; root, which causes them not to appear in regions in ScopDetection anymore.
+
+; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" -polly-allow-nonaffine-loops -analyze  -polly-detect < %s 2>&1 | FileCheck %s
+; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" -polly-allow-nonaffine-loops=false -analyze  -polly-detect < %s 2>&1 | FileCheck %s
+
+; void func (int param0, int N, int *A)
+; {
+;   for (int i = 0; i < N; i++)
+;     if (param0)
+;       while (1)
+;         A[i] = 1;
+;     else
+;      A[i] = 2;
+; }
+
+; CHECK: remark: ReportLoopHasNoExit.c:7:7: Loop cannot be handled because it has no exit.
+
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @func(i32 %param0, i32 %N, i32* %A) #0 !dbg !6 {
+entry:
+  %param0.addr = alloca i32, align 4
+  %N.addr = alloca i32, align 4
+  %A.addr = alloca i32*, align 8
+  %i = alloca i32, align 4
+  store i32 %param0, i32* %param0.addr, align 4
+  store i32 %N, i32* %N.addr, align 4
+  store i32* %A, i32** %A.addr, align 8
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %1 = load i32, i32* %N.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %for.body, label %for.end, !dbg !27
+
+for.body:                                         ; preds = %for.cond
+  %2 = load i32, i32* %param0.addr, align 4
+  %tobool = icmp ne i32 %2, 0
+  br i1 %tobool, label %if.then, label %if.else
+
+if.then:                                          ; preds = %for.body
+  br label %while.body
+
+while.body:                                       ; preds = %if.then, %while.body
+  %3 = load i32, i32* %i, align 4
+  %idxprom = sext i32 %3 to i64
+  %4 = load i32*, i32** %A.addr, align 8
+  %arrayidx = getelementptr inbounds i32, i32* %4, i64 %idxprom
+  store i32 1, i32* %arrayidx, align 4
+  br label %while.body, !dbg !37
+
+if.else:                                          ; preds = %for.body
+  %5 = load i32, i32* %i, align 4
+  %idxprom1 = sext i32 %5 to i64
+  %6 = load i32*, i32** %A.addr, align 8
+  %arrayidx2 = getelementptr inbounds i32, i32* %6, i64 %idxprom1
+  store i32 2, i32* %arrayidx2, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %7 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %7, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4}
+!llvm.ident = !{!5}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.9.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "ReportLoopHasNoExit.c", directory: "test/ScopDetectionDiagnostics/")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{!"clang version 3.9.0 "}
+!6 = distinct !DISubprogram(name: "func", scope: !1, file: !1, line: 1,  isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!19 = distinct !DILexicalBlock(scope: !6, file: !1, line: 3, column: 3)
+!23 = !DILexicalBlockFile(scope: !24, file: !1, discriminator: 1)
+!24 = distinct !DILexicalBlock(scope: !19, file: !1, line: 3, column: 3)
+!27 = !DILocation(line: 3, column: 3, scope: !23)
+!29 = distinct !DILexicalBlock(scope: !30, file: !1, line: 5, column: 9)
+!30 = distinct !DILexicalBlock(scope: !24, file: !1, line: 4, column: 3)
+!33 = distinct !DILexicalBlock(scope: !29, file: !1, line: 6, column: 5)
+!37 = !DILocation(line: 7, column: 7, scope: !38)
+!38 = !DILexicalBlockFile(scope: !33, file: !1, discriminator: 1)
diff --git a/final/test/ScopDetectionDiagnostics/ReportMultipleNonAffineAccesses.ll b/final/test/ScopDetectionDiagnostics/ReportMultipleNonAffineAccesses.ll
new file mode 100644
index 0000000..2fc2fca
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportMultipleNonAffineAccesses.ll
@@ -0,0 +1,153 @@
+; RUN: opt %loadPolly -basicaa -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -analyze < %s 2>&1| FileCheck %s
+; RUN: opt %loadPolly -basicaa -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -polly-delinearize=false -polly-detect-keep-going -analyze < %s 2>&1| FileCheck %s -check-prefix=ALL
+; RUN: opt %loadPolly -basicaa -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -analyze < %s 2>&1| FileCheck %s -check-prefix=DELIN
+; RUN: opt %loadPolly -basicaa -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -polly-detect-keep-going -analyze < %s 2>&1| FileCheck %s -check-prefix=DELIN-ALL
+; RUN: opt %loadPolly -basicaa -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -polly-allow-nonaffine -analyze < %s 2>&1| FileCheck %s -check-prefix=NONAFFINE
+; RUN: opt %loadPolly -basicaa -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -polly-allow-nonaffine -analyze < %s 2>&1| FileCheck %s -check-prefix=NONAFFINE
+
+;  1 void manyaccesses(float A[restrict], long n, float B[restrict][n])
+;  2 {
+;  3   for (long i = 0; i < 1024; ++i) {
+;  4     float a1 = A[2 * i * i];
+;  5     float a2 = A[2 * i * i + 1];
+;  6     float b1 = B[0][0];
+;  7     float b2 = B[i][i];
+;  8     float b3 = B[i * i][i];
+;  9     float b4 = B[i][0];
+; 10     float b5 = B[0][i];
+; 11     float b6 = B[0][i*i];
+; 12
+; 13     A[i * i] = a1 + a2 + b1 + b2 + b3 + b4 + b5 + b6;
+; 14   }
+; 15 }
+
+; CHECK: remark: /tmp/test.c:3:20: The following errors keep this region from being a Scop.
+; CHECK-NEXT: remark: /tmp/test.c:4:16: The array subscript of "A" is not affine
+; CHECK-NEXT: remark: /tmp/test.c:13:51: Invalid Scop candidate ends here.
+
+; ALL: remark: /tmp/test.c:3:20: The following errors keep this region from being a Scop.
+; ALL-NEXT: remark: /tmp/test.c:4:16: The array subscript of "A" is not affine
+; ALL-NEXT: remark: /tmp/test.c:5:16: The array subscript of "A" is not affine
+; -> B[0][0] is affine
+; ALL-NEXT: remark: /tmp/test.c:7:16: The array subscript of "B" is not affine
+; ALL-NEXT: remark: /tmp/test.c:8:16: The array subscript of "B" is not affine
+; ALL-NEXT: remark: /tmp/test.c:9:16: The array subscript of "B" is not affine
+; -> B[0][i] is affine
+; ALL-NEXT: remark: /tmp/test.c:11:16: The array subscript of "B" is not affine
+; ALL-NEXT: remark: /tmp/test.c:13:5: The array subscript of "A" is not affine
+; ALL-NEXT: remark: /tmp/test.c:13:51: Invalid Scop candidate ends here.
+
+; DELIN: remark: /tmp/test.c:3:20: The following errors keep this region from being a Scop.
+; DELIN-NEXT: remark: /tmp/test.c:4:16: The array subscript of "A" is not affine
+; DELIN-NEXT: remark: /tmp/test.c:13:51: Invalid Scop candidate ends here.
+
+; DELIN-ALL: remark: /tmp/test.c:3:20: The following errors keep this region from being a Scop.
+; DELIN-ALL-NEXT: remark: /tmp/test.c:4:16: The array subscript of "A" is not affine
+; DELIN-ALL-NEXT: remark: /tmp/test.c:5:16: The array subscript of "A" is not affine
+; DELIN-ALL-NEXT: remark: /tmp/test.c:13:5: The array subscript of "A" is not affine
+; -> B[0][0] is affine if delinearized
+; -> B[i][i] is affine if delinearized
+; DELIN-ALL-NEXT: remark: /tmp/test.c:8:16: The array subscript of "B" is not affine
+; -> B[i][0] is affine if delinearized
+; -> B[0][i] is affine if delinearized
+; DELIN-ALL-NEXT: remark: /tmp/test.c:11:16: The array subscript of "B" is not affine
+; DELIN-ALL-NEXT: remark: /tmp/test.c:13:51: Invalid Scop candidate ends here.
+
+; NONAFFINE-NOT: remark: The following errors keep this region from being a Scop.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @manyaccesses(float* noalias %A, i64 %n, float* noalias %B) !dbg !4 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %tmp = add i64 %n, 1, !dbg !10
+  br label %for.body, !dbg !10
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %tmp3 = phi i64 [ 0, %entry.split ], [ %tmp14, %for.body ], !dbg !15
+  %mul = mul i64 %tmp3, 2, !dbg !17
+  %tmp4 = mul i64 %tmp, %tmp3, !dbg !18
+  %arrayidx8 = getelementptr float, float* %B, i64 %tmp4, !dbg !19
+  %mul9 = mul i64 %n, %tmp3, !dbg !15
+  %arrayidx12 = getelementptr float, float* %B, i64 %mul9, !dbg !20
+  %arrayidx15 = getelementptr float, float* %B, i64 %tmp3, !dbg !21
+  %mul1 = mul nsw i64 %mul, %tmp3, !dbg !17
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %mul1, !dbg !22
+  %tmp5 = load float, float* %arrayidx, align 4, !dbg !22
+  %mul3 = mul nsw i64 %mul, %tmp3, !dbg !27
+  %add1 = or i64 %mul3, 1, !dbg !27
+  %arrayidx4 = getelementptr inbounds float, float* %A, i64 %add1, !dbg !28
+  %tmp6 = load float, float* %arrayidx4, align 4, !dbg !28
+  %tmp7 = load float, float* %B, align 4, !dbg !29
+  %tmp8 = load float, float* %arrayidx8, align 4, !dbg !19
+  %tmp9 = mul i64 %mul9, %tmp3, !dbg !15
+  %arrayidx10.sum = add i64 %tmp9, %tmp3, !dbg !15
+  %arrayidx11 = getelementptr inbounds float, float* %B, i64 %arrayidx10.sum, !dbg !15
+  %tmp10 = load float, float* %arrayidx11, align 4, !dbg !15
+  %tmp11 = load float, float* %arrayidx12, align 4, !dbg !20
+  %tmp12 = load float, float* %arrayidx15, align 4, !dbg !21
+  %mul16 = mul nsw i64 %tmp3, %tmp3, !dbg !30
+  %arrayidx18 = getelementptr inbounds float, float* %B, i64 %mul16, !dbg !31
+  %tmp13 = load float, float* %arrayidx18, align 4, !dbg !31
+  %add19 = fadd float %tmp5, %tmp6, !dbg !32
+  %add20 = fadd float %add19, %tmp7, !dbg !33
+  %add21 = fadd float %add20, %tmp8, !dbg !34
+  %add22 = fadd float %add21, %tmp10, !dbg !35
+  %add23 = fadd float %add22, %tmp11, !dbg !36
+  %add24 = fadd float %add23, %tmp12, !dbg !37
+  %add25 = fadd float %add24, %tmp13, !dbg !38
+  %mul26 = mul nsw i64 %tmp3, %tmp3, !dbg !39
+  %arrayidx27 = getelementptr inbounds float, float* %A, i64 %mul26, !dbg !40
+  store float %add25, float* %arrayidx27, align 4, !dbg !40
+  %tmp14 = add nsw i64 %tmp3, 1, !dbg !41
+  %exitcond = icmp ne i64 %tmp14, 1024, !dbg !10
+  br i1 %exitcond, label %for.body, label %for.end, !dbg !10
+
+for.end:                                          ; preds = %for.body
+  ret void, !dbg !42
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.6.0 ", isOptimized: true, emissionKind: 2, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!1 = !DIFile(filename: "/tmp/test.c", directory: "/home/grosser/Projects/polly/git/tools/polly/test")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "manyaccesses", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, scopeLine: 2, file: !1, scope: !5, type: !6, variables: !2)
+!5 = !DIFile(filename: "/tmp/test.c", directory: "/home/grosser/Projects/polly/git/tools/polly/test")
+!6 = !DISubroutineType(types: !2)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{!"clang version 3.6.0 "}
+!10 = !DILocation(line: 3, column: 20, scope: !11)
+!11 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !12)
+!12 = !DILexicalBlockFile(discriminator: 1, file: !1, scope: !13)
+!13 = distinct !DILexicalBlock(line: 3, column: 3, file: !1, scope: !14)
+!14 = distinct !DILexicalBlock(line: 3, column: 3, file: !1, scope: !4)
+!15 = !DILocation(line: 8, column: 16, scope: !16)
+!16 = distinct !DILexicalBlock(line: 3, column: 35, file: !1, scope: !13)
+!17 = !DILocation(line: 4, column: 26, scope: !16)
+!18 = !DILocation(line: 4, column: 22, scope: !16)
+!19 = !DILocation(line: 7, column: 16, scope: !16)
+!20 = !DILocation(line: 9, column: 16, scope: !16)
+!21 = !DILocation(line: 10, column: 16, scope: !16)
+!22 = !DILocation(line: 4, column: 16, scope: !16)
+!27 = !DILocation(line: 5, column: 26, scope: !16)
+!28 = !DILocation(line: 5, column: 16, scope: !16)
+!29 = !DILocation(line: 6, column: 16, scope: !16)
+!30 = !DILocation(line: 11, column: 23, scope: !16) ; [ DW_TAG_lexical_block ] [/]
+!31 = !DILocation(line: 11, column: 16, scope: !16) ; [ DW_TAG_lexical_block ] [/]
+!32 = !DILocation(line: 13, column: 21, scope: !16)
+!33 = !DILocation(line: 13, column: 26, scope: !16)
+!34 = !DILocation(line: 13, column: 31, scope: !16)
+!35 = !DILocation(line: 13, column: 36, scope: !16)
+!36 = !DILocation(line: 13, column: 41, scope: !16)
+!37 = !DILocation(line: 13, column: 46, scope: !16)
+!38 = !DILocation(line: 13, column: 51, scope: !16)
+!39 = !DILocation(line: 13, column: 11, scope: !16)
+!40 = !DILocation(line: 13, column: 5, scope: !16)
+!41 = !DILocation(line: 3, column: 30, scope: !13)
+!42 = !DILocation(line: 15, column: 1, scope: !4)
diff --git a/final/test/ScopDetectionDiagnostics/ReportNonAffineAccess-01.ll b/final/test/ScopDetectionDiagnostics/ReportNonAffineAccess-01.ll
new file mode 100644
index 0000000..84b3b10
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportNonAffineAccess-01.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -analyze < %s 2>&1| FileCheck %s
+
+; void f(int A[]) {
+;   for(int i=0; i<42; ++i)
+;     A[i*i] = 0;
+; }
+
+
+; CHECK: remark: ReportNonAffineAccess-01.c:2:7: The following errors keep this region from being a Scop.
+; CHECK: remark: ReportNonAffineAccess-01.c:3:5: The array subscript of "A" is not affine
+; CHECK: remark: ReportNonAffineAccess-01.c:3:5: Invalid Scop candidate ends here.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) !dbg !4 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  tail call void @llvm.dbg.value(metadata i32* %A, i64 0, metadata !13, metadata !DIExpression()), !dbg !14
+  tail call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !16, metadata !DIExpression()), !dbg !18
+  br label %for.body, !dbg !19
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %0 = phi i32 [ 0, %entry.split ], [ %1, %for.body ], !dbg !20
+  %mul = mul nsw i32 %0, %0, !dbg !20
+  %idxprom1 = zext i32 %mul to i64, !dbg !20
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom1, !dbg !20
+  store i32 0, i32* %arrayidx, align 4, !dbg !20
+  %1 = add nsw i32 %0, 1, !dbg !21
+  tail call void @llvm.dbg.value(metadata i32 %1, i64 0, metadata !16, metadata !DIExpression()), !dbg !18
+  %exitcond = icmp ne i32 %1, 42, !dbg !19
+  br i1 %exitcond, label %for.body, label %for.end, !dbg !19
+
+for.end:                                          ; preds = %for.body
+  ret void, !dbg !22
+}
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!10, !11}
+!llvm.ident = !{!12}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.6.0 ", isOptimized: false, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!1 = !DIFile(filename: "ReportNonAffineAccess-01.c", directory: "test/ScopDetectionDiagnostic/")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "f", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 1, file: !1, scope: !5, type: !6, variables: !2)
+!5 = !DIFile(filename: "ReportNonAffineAccess-01.c", directory: "test/ScopDetectionDiagnostic/")
+!6 = !DISubroutineType(types: !7)
+!7 = !{null, !8}
+!8 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, baseType: !9)
+!9 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!10 = !{i32 2, !"Dwarf Version", i32 4}
+!11 = !{i32 2, !"Debug Info Version", i32 3}
+!12 = !{!"clang version 3.6.0 "}
+!13 = !DILocalVariable(name: "A", line: 1, arg: 1, scope: !4, file: !5, type: !8)
+!14 = !DILocation(line: 1, column: 12, scope: !4)
+!15 = !{i32 0}
+!16 = !DILocalVariable(name: "i", line: 2, scope: !17, file: !5, type: !9)
+!17 = distinct !DILexicalBlock(line: 2, column: 3, file: !1, scope: !4)
+!18 = !DILocation(line: 2, column: 11, scope: !17)
+!19 = !DILocation(line: 2, column: 7, scope: !17)
+!20 = !DILocation(line: 3, column: 5, scope: !17)
+!21 = !DILocation(line: 2, column: 22, scope: !17)
+!22 = !DILocation(line: 4, column: 1, scope: !4)
diff --git a/final/test/ScopDetectionDiagnostics/ReportUnprofitable.ll b/final/test/ScopDetectionDiagnostics/ReportUnprofitable.ll
new file mode 100644
index 0000000..4ea1aee
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportUnprofitable.ll
@@ -0,0 +1,183 @@
+; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" \
+; RUN:     -polly-detect-track-failures -polly-detect -analyze \
+; RUN:     -polly-process-unprofitable=false < %s 2>&1| FileCheck %s
+
+; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" \
+; RUN:     -polly-detect-track-failures -polly-detect -analyze \
+; RUN:     -polly-process-unprofitable=false < %s 2>&1 -pass-remarks-output=%t.yaml
+; RUN: cat %t.yaml | FileCheck -check-prefix=YAML %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; void onlyWrite(float *A) {
+;   for (long i = 0; i < 100; i++)
+;     A[i] = 0;
+; }
+;
+; void onlyRead(float *A) {
+;   for (long i = 0; i < 100; i++)
+;     A[i];
+; }
+
+; CHECK: remark: /tmp/test.c:2:3: The following errors keep this region from being a Scop.
+; CHECK: remark: /tmp/test.c:2:3: No profitable polyhedral optimization found
+; CHECK: remark: /tmp/test.c:3:10: Invalid Scop candidate ends here.
+
+; CHECK: remark: /tmp/test.c:7:3: The following errors keep this region from being a Scop.
+; CHECK: remark: /tmp/test.c:7:3: No profitable polyhedral optimization found
+; CHECK: remark: /tmp/test.c:8:10: Invalid Scop candidate ends here.
+
+; YAML: --- !Missed
+; YAML: Pass:            polly-detect
+; YAML: Name:            RejectionErrors
+; YAML: DebugLoc:        { File: /tmp/test.c, Line: 2, Column: 3 }
+; YAML: Function:        onlyWrite
+; YAML: Args:
+; YAML:   - String:          The following errors keep this region from being a Scop.
+; YAML: ...
+; YAML: --- !Missed
+; YAML: Pass:            polly-detect
+; YAML: Name:            Unprofitable
+; YAML: DebugLoc:        { File: /tmp/test.c, Line: 2, Column: 3 }
+; YAML: Function:        onlyWrite
+; YAML: Args:
+; YAML:   - String:          No profitable polyhedral optimization found
+; YAML: ...
+; YAML: --- !Missed
+; YAML: Pass:            polly-detect
+; YAML: Name:            InvalidScopEnd
+; YAML: DebugLoc:        { File: /tmp/test.c, Line: 3, Column: 10 }
+; YAML: Function:        onlyWrite
+; YAML: Args:
+; YAML:   - String:          Invalid Scop candidate ends here.
+; YAML: ...
+; YAML: --- !Missed
+; YAML: Pass:            polly-detect
+; YAML: Name:            RejectionErrors
+; YAML: DebugLoc:        { File: /tmp/test.c, Line: 7, Column: 3 }
+; YAML: Function:        onlyRead
+; YAML: Args:
+; YAML:   - String:          The following errors keep this region from being a Scop.
+; YAML: ...
+; YAML: --- !Missed
+; YAML: Pass:            polly-detect
+; YAML: Name:            Unprofitable
+; YAML: DebugLoc:        { File: /tmp/test.c, Line: 7, Column: 3 }
+; YAML: Function:        onlyRead
+; YAML: Args:
+; YAML:   - String:          No profitable polyhedral optimization found
+; YAML: ...
+; YAML: --- !Missed
+; YAML: Pass:            polly-detect
+; YAML: Name:            InvalidScopEnd
+; YAML: DebugLoc:        { File: /tmp/test.c, Line: 8, Column: 10 }
+; YAML: Function:        onlyRead
+; YAML: Args:
+; YAML:   - String:          Invalid Scop candidate ends here.
+
+
+; Function Attrs: nounwind uwtable
+define void @onlyWrite(float* %A) #0 !dbg !4 {
+entry:
+  call void @llvm.dbg.value(metadata float* %A, i64 0, metadata !14, metadata !15), !dbg !16
+  call void @llvm.dbg.value(metadata i64 0, i64 0, metadata !17, metadata !15), !dbg !20
+  br label %for.cond, !dbg !21
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %i.0, 100, !dbg !22
+  br i1 %exitcond, label %for.body, label %for.end, !dbg !22
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0, !dbg !23
+  store float 0.000000e+00, float* %arrayidx, align 4, !dbg !25
+  br label %for.inc, !dbg !23
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nuw nsw i64 %i.0, 1, !dbg !26
+  call void @llvm.dbg.value(metadata i64 %inc, i64 0, metadata !17, metadata !15), !dbg !20
+  br label %for.cond, !dbg !27
+
+for.end:                                          ; preds = %for.cond
+  ret void, !dbg !28
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: nounwind uwtable
+define void @onlyRead(float* %A) #0 !dbg !10 {
+entry:
+  call void @llvm.dbg.value(metadata float* %A, i64 0, metadata !29, metadata !15), !dbg !30
+  call void @llvm.dbg.value(metadata i64 0, i64 0, metadata !31, metadata !15), !dbg !33
+  br label %for.cond, !dbg !34
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %i.0, 100, !dbg !35
+  br i1 %exitcond, label %for.body, label %for.end, !dbg !35
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0, !dbg !36
+  %val = load float, float* %arrayidx, align 4, !dbg !38
+  br label %for.inc, !dbg !36
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nuw nsw i64 %i.0, 1, !dbg !39
+  call void @llvm.dbg.value(metadata i64 %inc, i64 0, metadata !31, metadata !15), !dbg !33
+  br label %for.cond, !dbg !40
+
+for.end:                                          ; preds = %for.cond
+  ret void, !dbg !41
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!11, !12}
+!llvm.ident = !{!13}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.7.0  (llvm/trunk 229257)", isOptimized: false, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!1 = !DIFile(filename: "/tmp/test.c", directory: "/home/grosser/Projects/polly/git/tools/polly")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "onlyWrite", line: 1, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 1, file: !1, scope: !5, type: !6, variables: !2)
+!5 = !DIFile(filename: "/tmp/test.c", directory: "/home/grosser/Projects/polly/git/tools/polly")
+!6 = !DISubroutineType(types: !7)
+!7 = !{null, !8}
+!8 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, baseType: !9)
+!9 = !DIBasicType(tag: DW_TAG_base_type, name: "float", size: 32, align: 32, encoding: DW_ATE_float)
+!10 = distinct !DISubprogram(name: "onlyRead", line: 6, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 6, file: !1, scope: !5, type: !6, variables: !2)
+!11 = !{i32 2, !"Dwarf Version", i32 4}
+!12 = !{i32 2, !"Debug Info Version", i32 3}
+!13 = !{!"clang version 3.7.0  (llvm/trunk 229257)"}
+!14 = !DILocalVariable(name: "A", line: 1, arg: 1, scope: !4, file: !5, type: !8)
+!15 = !DIExpression()
+!16 = !DILocation(line: 1, column: 23, scope: !4)
+!17 = !DILocalVariable(name: "i", line: 2, scope: !18, file: !5, type: !19)
+!18 = distinct !DILexicalBlock(line: 2, column: 3, file: !1, scope: !4)
+!19 = !DIBasicType(tag: DW_TAG_base_type, name: "long int", size: 64, align: 64, encoding: DW_ATE_signed)
+!20 = !DILocation(line: 2, column: 13, scope: !18)
+!21 = !DILocation(line: 2, column: 8, scope: !18)
+!22 = !DILocation(line: 2, column: 3, scope: !18)
+!23 = !DILocation(line: 3, column: 5, scope: !24)
+!24 = distinct !DILexicalBlock(line: 2, column: 3, file: !1, scope: !18)
+!25 = !DILocation(line: 3, column: 10, scope: !24)
+!26 = !DILocation(line: 2, column: 30, scope: !24)
+!27 = !DILocation(line: 2, column: 3, scope: !24)
+!28 = !DILocation(line: 4, column: 1, scope: !4)
+!29 = !DILocalVariable(name: "A", line: 6, arg: 1, scope: !10, file: !5, type: !8)
+!30 = !DILocation(line: 6, column: 22, scope: !10)
+!31 = !DILocalVariable(name: "i", line: 7, scope: !32, file: !5, type: !19)
+!32 = distinct !DILexicalBlock(line: 7, column: 3, file: !1, scope: !10)
+!33 = !DILocation(line: 7, column: 13, scope: !32)
+!34 = !DILocation(line: 7, column: 8, scope: !32)
+!35 = !DILocation(line: 7, column: 3, scope: !32)
+!36 = !DILocation(line: 8, column: 5, scope: !37)
+!37 = distinct !DILexicalBlock(line: 7, column: 3, file: !1, scope: !32)
+!38 = !DILocation(line: 8, column: 10, scope: !37)
+!39 = !DILocation(line: 7, column: 30, scope: !37)
+!40 = !DILocation(line: 7, column: 3, scope: !37)
+!41 = !DILocation(line: 9, column: 1, scope: !10)
diff --git a/final/test/ScopDetectionDiagnostics/ReportUnreachableInExit.ll b/final/test/ScopDetectionDiagnostics/ReportUnreachableInExit.ll
new file mode 100644
index 0000000..b775d28
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportUnreachableInExit.ll
@@ -0,0 +1,31 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s \
+; RUN:     -pass-remarks-missed="polly-detect" 2>&1 | FileCheck %s
+
+; void f(long A[], long N) {
+;   long i;
+;   for (i = 0; i < N; ++i)
+;     A[i] = i;
+;   unreachable()
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %A, i64 %N) nounwind {
+entry:
+  fence seq_cst
+  br label %for.i
+
+for.i:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %for.i ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar
+  store i64 %indvar, i64* %scevgep
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for.i
+
+return:
+  fence seq_cst
+  unreachable
+}
+
+; CHECK: Unreachable in exit block
diff --git a/final/test/ScopDetectionDiagnostics/ReportVariantBasePtr-01.ll b/final/test/ScopDetectionDiagnostics/ReportVariantBasePtr-01.ll
new file mode 100644
index 0000000..327a58d
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportVariantBasePtr-01.ll
@@ -0,0 +1,102 @@
+; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -analyze < %s 2>&1| FileCheck %s
+
+; struct b {
+;   double **b;
+; };
+;
+; void a(struct b *A) {
+;   for (int i=0; i<32; i++)
+;     A[i].b[i] = 0;
+; }
+
+; The loads are currently just adds %7 to the list of required invariant loads
+; and only -polly-scops checks whether it is actionally possible the be load
+; hoisted. The SCoP is still rejected by -polly-detect because it may alias
+; with %A and is not considered to be eligble for runtime alias checking.
+
+; CHECK: remark: ReportVariantBasePtr01.c:6:8: The following errors keep this region from being a Scop.
+; CHECK: remark: ReportVariantBasePtr01.c:7:5: Accesses to the arrays "A", " <unknown> " may access the same memory.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.b = type { double** }
+
+define void @a(%struct.b* nocapture readonly %A) #0 !dbg !4 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  tail call void @llvm.dbg.value(metadata %struct.b* %A, i64 0, metadata !16, metadata !DIExpression()), !dbg !23
+  tail call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !17, metadata !DIExpression()), !dbg !25
+  br label %for.body, !dbg !27
+
+for.body:                                         ; preds = %for.body, %entry.split
+  %indvar4 = phi i64 [ %indvar.next, %for.body ], [ 0, %entry.split ]
+  %b = getelementptr inbounds %struct.b, %struct.b* %A, i64 %indvar4, i32 0, !dbg !26
+  %0 = mul i64 %indvar4, 4, !dbg !26
+  %1 = add i64 %0, 3, !dbg !26
+  %2 = add i64 %0, 2, !dbg !26
+  %3 = add i64 %0, 1, !dbg !26
+  %4 = load double**, double*** %b, align 8, !dbg !26, !tbaa !28
+  %arrayidx = getelementptr double*, double** %4, i64 %0, !dbg !26
+  store double* null, double** %arrayidx, align 8, !dbg !26, !tbaa !33
+  %5 = load double**, double*** %b, align 8, !dbg !26, !tbaa !28
+  %arrayidx.1 = getelementptr double*, double** %5, i64 %3, !dbg !26
+  store double* null, double** %arrayidx.1, align 8, !dbg !26, !tbaa !33
+  %6 = load double**, double*** %b, align 8, !dbg !26, !tbaa !28
+  %arrayidx.2 = getelementptr double*, double** %6, i64 %2, !dbg !26
+  store double* null, double** %arrayidx.2, align 8, !dbg !26, !tbaa !33
+  %7 = load double**, double*** %b, align 8, !dbg !26, !tbaa !28
+  %arrayidx.3 = getelementptr double*, double** %7, i64 %1, !dbg !26
+  store double* null, double** %arrayidx.3, align 8, !dbg !26, !tbaa !33
+  %indvar.next = add i64 %indvar4, 1, !dbg !27
+  %exitcond = icmp eq i64 %indvar.next, 8, !dbg !27
+  br i1 %exitcond, label %for.end, label %for.body, !dbg !27
+
+for.end:                                          ; preds = %for.body
+  ret void, !dbg !34
+}
+
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!20, !21}
+!llvm.ident = !{!22}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.5.0 ", isOptimized: true, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!1 = !DIFile(filename: "ReportVariantBasePtr01.c", directory: "test/ScopDetectionDiagnostics")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "a", line: 5, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, scopeLine: 5, file: !1, scope: !5, type: !6, variables: !15)
+!5 = !DIFile(filename: "ReportVariantBasePtr01.c", directory: "test/ScopDetectionDiagnostics")
+!6 = !DISubroutineType(types: !7)
+!7 = !{null, !8}
+!8 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, baseType: !9)
+!9 = !DICompositeType(tag: DW_TAG_structure_type, name: "b", line: 1, size: 64, align: 64, file: !1, elements: !10)
+!10 = !{!11}
+!11 = !DIDerivedType(tag: DW_TAG_member, name: "b", line: 2, size: 64, align: 64, file: !1, scope: !9, baseType: !12)
+!12 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, baseType: !13)
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, baseType: !14)
+!14 = !DIBasicType(tag: DW_TAG_base_type, name: "double", size: 64, align: 64, encoding: DW_ATE_float)
+!15 = !{!16, !17}
+!16 = !DILocalVariable(name: "A", line: 5, arg: 1, scope: !4, file: !5, type: !8)
+!17 = !DILocalVariable(name: "i", line: 6, scope: !18, file: !5, type: !19)
+!18 = distinct !DILexicalBlock(line: 6, column: 3, file: !1, scope: !4)
+!19 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!20 = !{i32 2, !"Dwarf Version", i32 4}
+!21 = !{i32 2, !"Debug Info Version", i32 3}
+!22 = !{!"clang version 3.5.0 "}
+!23 = !DILocation(line: 5, column: 18, scope: !4)
+!24 = !{i32 0}
+!25 = !DILocation(line: 6, column: 12, scope: !18)
+!26 = !DILocation(line: 7, column: 5, scope: !18)
+!27 = !DILocation(line: 6, column: 8, scope: !18)
+!28 = !{!29, !30, i64 0}
+!29 = !{!"b", !30, i64 0}
+!30 = !{!"any pointer", !31, i64 0}
+!31 = !{!"omnipotent char", !32, i64 0}
+!32 = !{!"Simple C/C++ TBAA"}
+!33 = !{!30, !30, i64 0}
+!34 = !DILocation(line: 8, column: 1, scope: !4)
diff --git a/final/test/ScopDetectionDiagnostics/loop_partially_in_scop-2.ll b/final/test/ScopDetectionDiagnostics/loop_partially_in_scop-2.ll
new file mode 100644
index 0000000..2eb039c
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/loop_partially_in_scop-2.ll
@@ -0,0 +1,24 @@
+; RUN: opt %loadPolly -analyze -polly-detect \
+; RUN:     -pass-remarks-missed="polly-detect" \
+; RUN:     < %s 2>&1| FileCheck %s
+
+; CHECK: remark: <unknown>:0:0: Loop cannot be handled because not all latches are part of loop region.
+
+define void @foo(i8* %str0) {
+if.end32:
+  br label %while.cond
+
+while.cond:
+  %str.1 = phi i8* [%str0, %if.end32], [%incdec.ptr58364, %lor.end], [%incdec.ptr58364, %while.cond]
+  %tmp5 = load i8, i8* %str.1, align 1
+  %.off367 = add i8 %tmp5, -48
+  %tmp6 = icmp ult i8 %.off367, 10
+  %incdec.ptr58364 = getelementptr inbounds i8, i8* %str.1, i64 1
+  br i1 %tmp6, label %while.cond, label %lor.end
+
+lor.end:
+  br i1 false, label %exit, label %while.cond
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopDetectionDiagnostics/loop_partially_in_scop.ll b/final/test/ScopDetectionDiagnostics/loop_partially_in_scop.ll
new file mode 100644
index 0000000..af01cad
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/loop_partially_in_scop.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -analyze -polly-detect \
+; RUN:     -pass-remarks-missed="polly-detect" \
+; RUN:     < %s 2>&1| FileCheck %s
+
+; CHECK: remark: <unknown>:0:0: Loop cannot be handled because not all latches are part of loop region.
+; CHECK: remark: <unknown>:0:0: Loop cannot be handled because not all latches are part of loop region.
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @baz(i32 %before) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb
+  br label %bb2
+
+bb2:                                              ; preds = %bb8, %bb7, %bb2, %bb1
+  %tmp = phi i32 [ %before, %bb1 ], [ 0, %bb8 ], [ %tmp4, %bb7 ], [ %tmp4, %bb2 ]
+  %tmp3 = or i32 undef, undef
+  %tmp4 = udiv i32 %tmp3, 10
+  %tmp5 = trunc i32 undef to i8
+  %tmp6 = icmp eq i8 %tmp5, 0
+  br i1 %tmp6, label %bb7, label %bb2
+
+bb7:                                              ; preds = %bb2
+  br i1 undef, label %bb8, label %bb2
+
+bb8:                                              ; preds = %bb7
+  br i1 undef, label %bb9, label %bb2
+
+bb9:                                              ; preds = %bb8
+  unreachable
+}
diff --git a/final/test/ScopInfo/20110312-Fail-without-basicaa.ll b/final/test/ScopInfo/20110312-Fail-without-basicaa.ll
new file mode 100644
index 0000000..838c491
--- /dev/null
+++ b/final/test/ScopInfo/20110312-Fail-without-basicaa.ll
@@ -0,0 +1,26 @@
+; This should be run without alias analysis enabled.
+;RUN: opt %loadPolly -polly-scops < %s
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
+
+define i32 @main() nounwind {
+entry:
+  %t.02.reg2mem = alloca float
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  store float 0.000000e+00, float* %t.02.reg2mem
+  br label %for.body
+
+for.body:                                         ; preds = %for.body, %entry.split
+  %j.01 = phi i32 [ 0, %entry.split ], [ %inc1, %for.body ]
+  %t.02.reload = load float, float* %t.02.reg2mem
+  %inc = fadd float %t.02.reload, 1.000000e+00
+  %inc1 = add nsw i32 %j.01, 1
+  %exitcond = icmp eq i32 %inc1, 5000001
+  store float %inc, float* %t.02.reg2mem
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.body
+  %conv = fptosi float %inc to i32
+  ret i32 %conv
+}
diff --git a/final/test/ScopInfo/20111108-Parameter-not-detected.ll b/final/test/ScopInfo/20111108-Parameter-not-detected.ll
new file mode 100644
index 0000000..f584817
--- /dev/null
+++ b/final/test/ScopInfo/20111108-Parameter-not-detected.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+declare void @foo()
+
+define i32 @main(i8* %A) nounwind uwtable {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc5, %entry
+  %indvar_out = phi i64 [ %indvar_out.next, %for.inc5 ], [ 0, %entry ]
+  call void @foo()
+  %tmp = add i64 %indvar_out, 2
+  %exitcond5 = icmp ne i64 %indvar_out, 1023
+  br i1 %exitcond5, label %for.body, label %for.end7
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %for.body ]
+  %exitcond = icmp ne i64 %indvar, 1023
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %tmp1 = add i64 %tmp, %indvar
+  %cmp4 = icmp sgt i64 %tmp1, 1000
+  br i1 %cmp4, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body3
+  %arrayidx = getelementptr i8, i8* %A, i64 %indvar
+  store i8 5, i8* %arrayidx
+  br label %if.end
+
+if.end:                                           ; preds = %if.end.single_exit
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc5
+
+for.inc5:                                         ; preds = %for.end
+  %indvar_out.next = add i64 %indvar_out, 1
+  br label %for.cond
+
+for.end7:                                         ; preds = %for.cond
+  ret i32 0
+}
+
+; CHECK:      p0: {0,+,1}<%for.cond>
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_if_then
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p_0] -> { Stmt_if_then[i0] : i0 >= 0 and 999 - p_0 <= i0 <= 1022 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p_0] -> { Stmt_if_then[i0] -> [0, i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [p_0] -> { Stmt_if_then[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_for_inc5
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p_0] -> { Stmt_for_inc5[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p_0] -> { Stmt_for_inc5[] -> [1, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p_0] -> { Stmt_for_inc5[] -> MemRef_indvar_out_next[] };
+; CHECK-NEXT: }
+
diff --git a/final/test/ScopInfo/2012-03-16-Crash-because-of-unsigned-in-scev.ll b/final/test/ScopInfo/2012-03-16-Crash-because-of-unsigned-in-scev.ll
new file mode 100644
index 0000000..76ca84b
--- /dev/null
+++ b/final/test/ScopInfo/2012-03-16-Crash-because-of-unsigned-in-scev.ll
@@ -0,0 +1,31 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+target datalayout = "e-p:32:32:32-i64:64:64-i32:32:32-i16:16:16-i1:32:32-f64:64:64-f32:32:32-a0:0-n32"
+
+@array = external global [64 x i8], align 8
+
+define void @foo(i32* %A) nounwind {
+entry:
+  br label %if.then132
+
+if.then132:
+  %loaded = load i32, i32* %A
+  %0 = icmp ugt i32 %loaded, 10
+  %umax = select i1 %0, i32 %loaded, i32 10
+  br label %do.body
+
+do.body:
+  %indvar = phi i32 [ %3, %do.body ], [ 0, %if.then132 ]
+  %1 = add i32 0, %umax
+  %2 = sub i32 %1, %indvar
+  %arrayidx = getelementptr [64 x i8], [64 x i8]* @array, i32 0, i32 %2
+  store i8 1, i8* %arrayidx, align 1
+  %3 = add i32 %indvar, 1
+  %exitcond = icmp eq i32 %3, 20
+  br i1 %exitcond, label %for.end, label %do.body
+
+for.end:
+  ret void
+}
+
+;CHECK: p0: (10 umax %loaded)
diff --git a/final/test/ScopInfo/2015-10-04-Crash-in-domain-generation.ll b/final/test/ScopInfo/2015-10-04-Crash-in-domain-generation.ll
new file mode 100644
index 0000000..1c78a71
--- /dev/null
+++ b/final/test/ScopInfo/2015-10-04-Crash-in-domain-generation.ll
@@ -0,0 +1,32 @@
+; RUN: opt %loadPolly -polly-allow-nonaffine-loops -polly-scops -analyze < %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @kernel_reg_detect([6 x i32]* %path) {
+entry:
+  br label %for.body.6
+
+for.body.6:                                       ; preds = %for.inc.43, %for.body.6, %entry
+  %indvars.iv9 = phi i64 [ %indvars.iv.next10, %for.body.6 ], [ 0, %entry ]
+  %indvars.iv.next10 = add nuw nsw i64 %indvars.iv9, 1
+  %exitcond = icmp ne i64 %indvars.iv.next10, 6
+  br i1 %exitcond, label %for.body.6, label %for.inc.40
+
+for.inc.40:                                       ; preds = %for.inc.40, %for.body.6
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc.40 ], [ 0, %for.body.6 ]
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %arrayidx28 = getelementptr inbounds [6 x i32], [6 x i32]* %path, i64 0, i64 0
+  %tmp = load i32, i32* %arrayidx28, align 4
+  %arrayidx36 = getelementptr inbounds [6 x i32], [6 x i32]* %path, i64 0, i64 0
+  store i32 0, i32* %arrayidx36, align 4
+  %mul = mul i64 %indvars.iv, %indvars.iv
+  %exitcond22 = icmp ne i64 %mul, 6
+  br i1 %exitcond22, label %for.inc.40, label %for.inc.43
+
+for.inc.43:                                       ; preds = %for.inc.40
+  br label %for.end.45
+
+for.end.45:                                       ; preds = %for.inc.43
+  ret void
+}
diff --git a/final/test/ScopInfo/Alias-0.ll b/final/test/ScopInfo/Alias-0.ll
new file mode 100644
index 0000000..d63d7b7
--- /dev/null
+++ b/final/test/ScopInfo/Alias-0.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=RTA
+; RUN: opt %loadPolly -polly-scops -polly-use-runtime-alias-checks=false -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=NORTA
+; REQUIRES: asserts
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @f(i32* nocapture %a, i32* nocapture %b) nounwind {
+bb.nph:
+  %0 = tail call i32 (...) @rnd() nounwind       ; <i32> [#uses=1]
+  %1 = icmp eq i32 %0, 0                          ; <i1> [#uses=1]
+  %iftmp.0.0 = select i1 %1, i32* %b, i32* %a     ; <i32*> [#uses=2]
+  br label %bb3
+
+bb3:                                              ; preds = %bb3, %bb.nph
+  %i.06 = phi i64 [ 0, %bb.nph ], [ %tmp, %bb3 ]  ; <i64> [#uses=3]
+  %scevgep = getelementptr i32, i32* %a, i64 %i.06     ; <i32*> [#uses=1]
+  %scevgep7 = getelementptr i32, i32* %iftmp.0.0, i64 %i.06 ; <i32*> [#uses=1]
+  %tmp = add i64 %i.06, 1                         ; <i64> [#uses=3]
+  %scevgep8 = getelementptr i32, i32* %iftmp.0.0, i64 %tmp ; <i32*> [#uses=1]
+  %2 = load i32, i32* %scevgep, align 4                ; <i32> [#uses=1]
+  %3 = load i32, i32* %scevgep8, align 4               ; <i32> [#uses=1]
+  %4 = shl i32 %3, 1                              ; <i32> [#uses=1]
+  %5 = add nsw i32 %4, %2                         ; <i32> [#uses=1]
+  store i32 %5, i32* %scevgep7, align 4
+  %exitcond = icmp eq i64 %tmp, 64                ; <i1> [#uses=1]
+  br i1 %exitcond, label %return, label %bb3
+
+return:                                           ; preds = %bb3
+  ret void
+}
+
+declare i32 @rnd(...)
+
+
+; RTA:   1 polly-detect     - Number of scops
+; NORTA: 1 polly-detect     - Number of rejected regions: Base address aliasing
diff --git a/final/test/ScopInfo/Alias-1.ll b/final/test/ScopInfo/Alias-1.ll
new file mode 100644
index 0000000..e592990
--- /dev/null
+++ b/final/test/ScopInfo/Alias-1.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=RTA
+; RUN: opt %loadPolly -polly-scops -polly-use-runtime-alias-checks=false -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=NORTA
+; REQUIRES: asserts
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @f(i32* nocapture %a, i32* nocapture %b) nounwind {
+bb.nph:
+  %0 = tail call i32 (...) @rnd() nounwind       ; <i32> [#uses=1]
+  %1 = icmp eq i32 %0, 0                          ; <i1> [#uses=1]
+  %sel.b = getelementptr inbounds i32, i32* %b, i64 4 
+  %iftmp.0.0 = select i1 %1, i32* %sel.b, i32* %a     ; <i32*> [#uses=2]
+  br label %bb3
+
+bb3:                                              ; preds = %bb3, %bb.nph
+  %i.06 = phi i64 [ 0, %bb.nph ], [ %tmp, %bb3 ]  ; <i64> [#uses=3]
+  %scevgep = getelementptr i32, i32* %a, i64 %i.06     ; <i32*> [#uses=1]
+  %scevgep7 = getelementptr i32, i32* %iftmp.0.0, i64 %i.06 ; <i32*> [#uses=1]
+  %tmp = add i64 %i.06, 1                         ; <i64> [#uses=3]
+  %scevgep8 = getelementptr i32, i32* %iftmp.0.0, i64 %tmp ; <i32*> [#uses=1]
+  %2 = load i32, i32* %scevgep, align 4                ; <i32> [#uses=1]
+  %3 = load i32, i32* %scevgep8, align 4               ; <i32> [#uses=1]
+  %4 = shl i32 %3, 1                              ; <i32> [#uses=1]
+  %5 = add nsw i32 %4, %2                         ; <i32> [#uses=1]
+  store i32 %5, i32* %scevgep7, align 4
+  %exitcond = icmp eq i64 %tmp, 64                ; <i1> [#uses=1]
+  br i1 %exitcond, label %return, label %bb3
+
+return:                                           ; preds = %bb3
+  ret void
+}
+
+declare i32 @rnd(...)
+
+
+; RTA:   1 polly-detect     - Number of scops
+; NORTA: 1 polly-detect     - Number of rejected regions: Base address aliasing
diff --git a/final/test/ScopInfo/Alias-2.ll b/final/test/ScopInfo/Alias-2.ll
new file mode 100644
index 0000000..5bd6080
--- /dev/null
+++ b/final/test/ScopInfo/Alias-2.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=RTA
+; RUN: opt %loadPolly -polly-scops -polly-use-runtime-alias-checks=false -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=NORTA
+; REQUIRES: asserts
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @f(i32** nocapture %ptrs, i64 %p0, i64 %p1, i64 %p2) nounwind {
+bb.nph:
+  %0 = getelementptr inbounds i32*, i32** %ptrs, i64 %p0 ; <i32**> [#uses=1]
+  %1 = load i32*, i32** %0, align 8                     ; <i32*> [#uses=1]
+  %2 = getelementptr inbounds i32*, i32** %ptrs, i64 %p1 ; <i32**> [#uses=1]
+  %3 = load i32*, i32** %2, align 8                     ; <i32*> [#uses=1]
+  %4 = getelementptr inbounds i32*, i32** %ptrs, i64 %p2 ; <i32**> [#uses=1]
+  %5 = load i32*, i32** %4, align 8                     ; <i32*> [#uses=1]
+  br label %bb
+
+bb:                                               ; preds = %bb, %bb.nph
+  %i.03 = phi i64 [ 0, %bb.nph ], [ %tmp, %bb ]   ; <i64> [#uses=3]
+  %scevgep = getelementptr i32, i32* %3, i64 %i.03     ; <i32*> [#uses=1]
+  %scevgep4 = getelementptr i32, i32* %5, i64 %i.03    ; <i32*> [#uses=1]
+  %tmp = add i64 %i.03, 1                         ; <i64> [#uses=3]
+  %scevgep5 = getelementptr i32, i32* %1, i64 %tmp     ; <i32*> [#uses=1]
+  %6 = load i32, i32* %scevgep, align 4                ; <i32> [#uses=1]
+  %7 = load i32, i32* %scevgep4, align 4               ; <i32> [#uses=1]
+  %8 = add nsw i32 %7, %6                         ; <i32> [#uses=1]
+  store i32 %8, i32* %scevgep5, align 4
+  %exitcond = icmp eq i64 %tmp, 64                ; <i1> [#uses=1]
+  br i1 %exitcond, label %return, label %bb
+
+return:                                           ; preds = %bb
+  ret void
+}
+
+; RTA:   1 polly-detect     - Number of scops
+; NORTA: 1 polly-detect     - Number of rejected regions: Base address aliasing
diff --git a/final/test/ScopInfo/Alias-3.ll b/final/test/ScopInfo/Alias-3.ll
new file mode 100644
index 0000000..b3b476a
--- /dev/null
+++ b/final/test/ScopInfo/Alias-3.ll
@@ -0,0 +1,28 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=RTA
+; RUN: opt %loadPolly -polly-scops -polly-use-runtime-alias-checks=false -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=NORTA
+; REQUIRES: asserts
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @f(i32* nocapture %a, i32* nocapture %b) nounwind {
+bb.nph:
+  br label %bb
+
+bb:                                               ; preds = %bb, %bb.nph
+  %i.03 = phi i64 [ 0, %bb.nph ], [ %2, %bb ]     ; <i64> [#uses=3]
+  %scevgep = getelementptr i32, i32* %b, i64 %i.03     ; <i32*> [#uses=1]
+  %scevgep4 = getelementptr i32, i32* %a, i64 %i.03    ; <i32*> [#uses=1]
+  %0 = load i32, i32* %scevgep, align 4                ; <i32> [#uses=1]
+  %1 = add nsw i32 %0, 2                          ; <i32> [#uses=1]
+  store i32 %1, i32* %scevgep4, align 4
+  %2 = add nsw i64 %i.03, 1                       ; <i64> [#uses=2]
+  %exitcond = icmp eq i64 %2, 128                 ; <i1> [#uses=1]
+  br i1 %exitcond, label %return, label %bb
+
+return:                                           ; preds = %bb
+  ret void
+}
+
+
+; RTA:   1 polly-detect     - Number of scops
+; NORTA: 1 polly-detect     - Number of rejected regions: Base address aliasing
diff --git a/final/test/ScopInfo/Alias-4.ll b/final/test/ScopInfo/Alias-4.ll
new file mode 100644
index 0000000..1955a86
--- /dev/null
+++ b/final/test/ScopInfo/Alias-4.ll
@@ -0,0 +1,28 @@
+; RUN: opt %loadPolly -disable-basicaa -polly-scops -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=RTA
+; RUN: opt %loadPolly -disable-basicaa -polly-scops -polly-use-runtime-alias-checks=false -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=NORTA
+; REQUIRES: asserts
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @f(i32* noalias nocapture %a, i32* noalias nocapture %b) nounwind {
+bb.nph:
+  br label %bb
+
+bb:                                               ; preds = %bb, %bb.nph
+  %i.03 = phi i64 [ 0, %bb.nph ], [ %2, %bb ]     ; <i64> [#uses=3]
+  %scevgep = getelementptr i32, i32* %b, i64 %i.03     ; <i32*> [#uses=1]
+  %scevgep4 = getelementptr i32, i32* %a, i64 %i.03    ; <i32*> [#uses=1]
+  %0 = load i32, i32* %scevgep, align 4                ; <i32> [#uses=1]
+  %1 = add nsw i32 %0, 2                          ; <i32> [#uses=1]
+  store i32 %1, i32* %scevgep4, align 4
+  %2 = add nsw i64 %i.03, 1                       ; <i64> [#uses=2]
+  %exitcond = icmp eq i64 %2, 128                 ; <i1> [#uses=1]
+  br i1 %exitcond, label %return, label %bb
+
+return:                                           ; preds = %bb
+  ret void
+}
+
+
+; RTA:   1 polly-detect     - Number of scops
+; NORTA: 1 polly-detect     - Number of rejected regions: Base address aliasing
diff --git a/final/test/ScopInfo/BoundChecks/single-loop.ll b/final/test/ScopInfo/BoundChecks/single-loop.ll
new file mode 100644
index 0000000..42d2e45
--- /dev/null
+++ b/final/test/ScopInfo/BoundChecks/single-loop.ll
@@ -0,0 +1,90 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=AST
+;
+; This only works after the post-dominator tree has been fixed.
+;
+; XFAIL: *
+;
+;    void exception() __attribute__((noreturn));
+;
+;    void foo(long n, float A[100]) {
+;      for (long i = 0; i < n; i++) {
+;        if (i < 0)
+;          exception();
+;
+;        if (i >= 100)
+;          exception();
+;
+;        A[i] += i;
+;      }
+;    }
+
+; We should detect this kernel as a SCoP and derive run-time conditions such
+; that the bound-checked blocks are not part of the optimized SCoP.
+
+; CHECK: Invalid Context:
+; CHECK:  [n] -> {  : n >= 101 }
+
+; AST: if (1 && 0 == n >= 101)
+; AST:     for (int c0 = 0; c0 < n; c0 += 1)
+; AST:       Stmt_if_end_4(c0);
+;
+; AST-NOT: for
+; AST-NOT: Stmt
+;
+; AST: else
+; AST:     {  /* original code */ }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @foo(i64 %n, float* %A) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp slt i64 %i.0, %n
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br i1 false, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  call void (...) @exception() #2
+  unreachable
+
+if.end:                                           ; preds = %for.body
+  %cmp2 = icmp sgt i64 %i.0, 99
+  br i1 %cmp2, label %if.then.3, label %if.end.4
+
+if.then.3:                                        ; preds = %if.end
+  call void (...) @exception() #2
+  unreachable
+
+if.end.4:                                         ; preds = %if.end
+  %conv = sitofp i64 %i.0 to float
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp = load float, float* %arrayidx, align 4
+  %add = fadd float %tmp, %conv
+  store float %add, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end.4
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: noreturn
+declare void @exception(...) #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { noreturn "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { noreturn nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 246853)"}
diff --git a/final/test/ScopInfo/BoundChecks/two-loops.ll b/final/test/ScopInfo/BoundChecks/two-loops.ll
new file mode 100644
index 0000000..472a231
--- /dev/null
+++ b/final/test/ScopInfo/BoundChecks/two-loops.ll
@@ -0,0 +1,101 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=AST
+;
+; This only works after the post-dominator tree has fixed.
+; XFAIL: *
+;
+;    void exception() __attribute__((noreturn));
+;
+;    void foo(long n, float A[100]) {
+;      for (long j = 0; j < n; j++) {
+;        for (long i = j; i < n; i++) {
+;          if (i < 0)
+;            exception();
+;
+;          if (i >= 100)
+;            exception();
+;
+;          A[i] += i;
+;        }
+;      }
+;    }
+;
+; CHECK: Assumed Context:
+; CHECK:  [n] -> {  : n >= 101 }
+
+; AST: if (1 && 0 == n >= 101)
+; AST:     for (int c0 = 0; c0 < n; c0 += 1)
+; AST:       for (int c1 = 0; c1 < n - c0; c1 += 1)
+; AST:         Stmt_if_end_7(c0, c1);
+;
+; AST-NOT: for
+; AST-NOT: Stmt
+;
+; AST: else
+; AST:     {  /* original code */ }
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %n, float* %A) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.8, %entry
+  %j.0 = phi i64 [ 0, %entry ], [ %inc9, %for.inc.8 ]
+  %cmp = icmp slt i64 %j.0, %n
+  br i1 %cmp, label %for.body, label %for.end.10
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond.1
+
+for.cond.1:                                       ; preds = %for.inc, %for.body
+  %i.0 = phi i64 [ %j.0, %for.body ], [ %inc, %for.inc ]
+  %cmp2 = icmp slt i64 %i.0, %n
+  br i1 %cmp2, label %for.body.3, label %for.end
+
+for.body.3:                                       ; preds = %for.cond.1
+  br i1 false, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body.3
+  call void (...) @exception() #2
+  unreachable
+
+if.end:                                           ; preds = %for.body.3
+  %cmp5 = icmp sgt i64 %i.0, 99
+  br i1 %cmp5, label %if.then.6, label %if.end.7
+
+if.then.6:                                        ; preds = %if.end
+  call void (...) @exception() #2
+  unreachable
+
+if.end.7:                                         ; preds = %if.end
+  %conv = sitofp i64 %i.0 to float
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp = load float, float* %arrayidx, align 4
+  %add = fadd float %tmp, %conv
+  store float %add, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end.7
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond.1
+
+for.end:                                          ; preds = %for.cond.1
+  br label %for.inc.8
+
+for.inc.8:                                        ; preds = %for.end
+  %inc9 = add nuw nsw i64 %j.0, 1
+  br label %for.cond
+
+for.end.10:                                       ; preds = %for.cond
+  ret void
+}
+
+declare void @exception(...) #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { noreturn "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { noreturn nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 246853)"}
diff --git a/final/test/ScopInfo/NonAffine/div_backedge.ll b/final/test/ScopInfo/NonAffine/div_backedge.ll
new file mode 100644
index 0000000..86b619f
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/div_backedge.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly  -polly-scops -analyze < %s | FileCheck %s
+;
+;    void foo(float *A) {
+;      for (long i = 1;; i++) {
+;        A[i] += 1;
+;        if (i / 7 == 4)
+;          break;
+;      }
+;    }
+;
+; CHECK:  Domain :=
+; CHECK:    { Stmt_for_body[i0] : 0 <= i0 <= 27 };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 1, %entry ], [ %inc, %for.inc ]
+  br label %for.body
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx0 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp0 = load float, float* %arrayidx0, align 4
+  %add0 = fadd float %tmp0, 2.000000e+00
+  store float %add0, float* %arrayidx0, align 4
+  %rem1 = sdiv i64 %i.0, 7
+  %tobool = icmp eq i64 %rem1, 4
+  br i1 %tobool, label %for.end, label %if.end
+
+if.end:                                           ; preds = %for.body, %if.then
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/div_domain.ll b/final/test/ScopInfo/NonAffine/div_domain.ll
new file mode 100644
index 0000000..b0d9769
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/div_domain.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void foo(float *A) {
+;      for (long i = 0; i < 16; i++) {
+;        A[i] += 1;
+;        if (i / 2 == 3)
+;          A[i] += 2;
+;      }
+;    }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_for_body[i0] : 0 <= i0 <= 15 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_for_body[i0] -> [i0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_if_then
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_if_then[i0] : 6 <= i0 <= 7 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_if_then[i0] -> [i0, 1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_if_then[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_if_then[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %i.0, 16
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx0 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp0 = load float, float* %arrayidx0, align 4
+  %add0 = fadd float %tmp0, 2.000000e+00
+  store float %add0, float* %arrayidx0, align 4
+  %rem1 = sdiv i64 %i.0, 2
+  %tobool = icmp ne i64 %rem1, 3
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp = load float, float* %arrayidx, align 4
+  %add = fadd float %tmp, 2.000000e+00
+  store float %add, float* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %for.body, %if.then
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/invariant_loads_dependent_in_non_affine_region.ll b/final/test/ScopInfo/NonAffine/invariant_loads_dependent_in_non_affine_region.ll
new file mode 100644
index 0000000..f131d12
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/invariant_loads_dependent_in_non_affine_region.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+;    void f(int *A, int *B, int *C) {
+;      for (int i = 0; i < 1000; i++)
+;        if (A[i] == *B)
+;          A[i] = *C;
+;    }
+;
+; Check that only the access to *B is hoisted but not the one to *C.
+;
+; CHECK: Invariant Accesses: {
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:         { Stmt_for_body__TO__if_end[i0] -> MemRef_B[0] };
+; CHECK:     Execution Context: {  :  }
+; CHECK: }
+;
+; CHECK: Statements {
+; CHECK:   Stmt_for_body__TO__if_end
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:         { Stmt_for_body__TO__if_end[i0] -> MemRef_C[0] };
+; CHECK: }
+
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %B, i32* %C) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1000
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4
+  %tmp1 = load i32, i32* %B, align 4
+  %cmp1 = icmp eq i32 %tmp, %tmp1
+  br i1 %cmp1, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %tmp2 = load i32, i32* %C, align 4
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp2, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/modulo_backedge.ll b/final/test/ScopInfo/NonAffine/modulo_backedge.ll
new file mode 100644
index 0000000..de6983f
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/modulo_backedge.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Domain :=
+; CHECK:   { Stmt_for_body[i0] : 0 <= i0 <= 6 };
+;
+;    void foo(float *A) {
+;      for (long i = 1;; i++) {
+;        A[i] += 1;
+;        if (i % 7 == 0)
+;          break;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 1, %entry ], [ %inc, %for.inc ]
+  br label %for.body
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx0 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp0 = load float, float* %arrayidx0, align 4
+  %add0 = fadd float %tmp0, 2.000000e+00
+  store float %add0, float* %arrayidx0, align 4
+  %rem1 = srem i64 %i.0, 7
+  %tobool = icmp eq i64 %rem1, 0
+  br i1 %tobool, label %for.end, label %if.end
+
+if.end:                                           ; preds = %for.body, %if.then
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/modulo_domain.ll b/final/test/ScopInfo/NonAffine/modulo_domain.ll
new file mode 100644
index 0000000..b0fe3af
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/modulo_domain.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; TODO: The new domain generation cannot handle modulo domain constraints,
+;       hence modulo handling has been disabled completely. Once this is
+;       resolved this test should work again. Until then we approximate the
+;       whole loop body.
+;
+; CHECK:   Domain :=
+; CHECK:       { Stmt_for_body[i0] : 0 <= i0 <= 15 };
+;
+;    void foo(float *A) {
+;      for (long i = 0; i < 16; i++) {
+;        A[i] += 1;
+;        if (i % 2)
+;          A[i] += 2;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %i.0, 16
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx0 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp0 = load float, float* %arrayidx0, align 4
+  %add0 = fadd float %tmp0, 2.000000e+00
+  store float %add0, float* %arrayidx0, align 4
+  %rem1 = srem i64 %i.0, 2
+  %tobool = icmp eq i64 %rem1, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp = load float, float* %arrayidx, align 4
+  %add = fadd float %tmp, 2.000000e+00
+  store float %add, float* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %for.body, %if.then
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_1.ll b/final/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_1.ll
new file mode 100644
index 0000000..185cca3
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_1.ll
@@ -0,0 +1,94 @@
+; RUN: opt %loadPolly -basicaa -polly-scops \
+; RUN:     -polly-allow-nonaffine -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=true -analyze < %s | FileCheck %s \
+; RUN:     -check-prefix=SCALAR
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine \
+; RUN:     -polly-process-unprofitable=false \
+; RUN:     -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s -check-prefix=PROFIT
+;
+; SCALAR:      Function: f
+; SCALAR-NEXT: Region: %bb1---%bb13
+; SCALAR-NEXT: Max Loop Depth:  1
+; SCALAR-NEXT: Invariant Accesses: {
+; SCALAR-NEXT: }
+; SCALAR-NEXT: Context:
+; SCALAR-NEXT: {  :  }
+; SCALAR-NEXT: Assumed Context:
+; SCALAR-NEXT: {  :  }
+; SCALAR-NEXT: Invalid Context:
+; SCALAR-NEXT: {  : 1 = 0 }
+; SCALAR-NEXT: Arrays {
+; SCALAR-NEXT:     i32 MemRef_C[*]; // Element size 4
+; SCALAR-NEXT:     i32 MemRef_A[*]; // Element size 4
+; SCALAR-NEXT: }
+; SCALAR-NEXT: Arrays (Bounds as pw_affs) {
+; SCALAR-NEXT:     i32 MemRef_C[*]; // Element size 4
+; SCALAR-NEXT:     i32 MemRef_A[*]; // Element size 4
+; SCALAR-NEXT: }
+; SCALAR-NEXT: Alias Groups (0):
+; SCALAR-NEXT:     n/a
+; SCALAR-NEXT: Statements {
+; SCALAR-NEXT:     Stmt_bb3__TO__bb11
+; SCALAR-NEXT:         Domain :=
+; SCALAR-NEXT:             { Stmt_bb3__TO__bb11[i0] : 0 <= i0 <= 1023 };
+; SCALAR-NEXT:         Schedule :=
+; SCALAR-NEXT:             { Stmt_bb3__TO__bb11[i0] -> [i0] };
+; SCALAR-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; SCALAR-NEXT:             { Stmt_bb3__TO__bb11[i0] -> MemRef_C[i0] };
+; SCALAR-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; SCALAR-NEXT:             { Stmt_bb3__TO__bb11[i0] -> MemRef_A[o0] };
+; SCALAR-NEXT:         MayWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; SCALAR-NEXT:             { Stmt_bb3__TO__bb11[i0] -> MemRef_A[o0] };
+; SCALAR-NEXT: }
+
+; PROFIT-NOT: Statements
+;
+;    void f(int * restrict A, int * restrict C) {
+;      int j;
+;      for (int i = 0; i < 1024; i++) {
+;        while ((j = C[i++])) {
+;          A[j]++;
+;          if (true) break;
+;        }
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* noalias %A, i32* noalias %C) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb12, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb12 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb13
+
+bb2:                                              ; preds = %bb1
+  br label %bb3
+
+bb3:                                              ; preds = %bb6, %bb2
+  %tmp = getelementptr inbounds i32, i32* %C, i64 %indvars.iv
+  %tmp4 = load i32, i32* %tmp, align 4
+  %tmp5 = icmp eq i32 %tmp4, 0
+  br i1 %tmp5, label %bb11, label %bb6
+
+bb6:                                              ; preds = %bb3
+  %tmp7 = sext i32 %tmp4 to i64
+  %tmp8 = getelementptr inbounds i32, i32* %A, i64 %tmp7
+  %tmp9 = load i32, i32* %tmp8, align 4
+  %tmp10 = add nsw i32 %tmp9, 1
+  store i32 %tmp10, i32* %tmp8, align 4
+  br i1 true, label %bb11, label %bb3
+
+bb11:                                             ; preds = %bb3
+  br label %bb12
+
+bb12:                                             ; preds = %bb11
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb13:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_2.ll b/final/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_2.ll
new file mode 100644
index 0000000..70b7084
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_2.ll
@@ -0,0 +1,174 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=false \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=INNERMOST
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=INNERMOST
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine \
+; RUN:     -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s \
+; RUN:     --check-prefix=ALL
+;
+; Here we have a non-affine loop (in the context of the loop nest)
+; and also a non-affine access (A[k]). While we can always model the
+; innermost loop as a SCoP of depth 1, we can overapproximate the
+; innermost loop in the whole loop nest and model A[k] as a non-affine
+; access.
+;
+; INNERMOST:      Function: f
+; INNERMOST-NEXT: Region: %bb15---%bb13
+; INNERMOST-NEXT: Max Loop Depth:  1
+; INNERMOST-NEXT: Invariant Accesses: {
+; INNERMOST-NEXT: }
+; INNERMOST-NEXT: Context:
+; INNERMOST-NEXT: [p_0, p_1, p_2] -> {  : 0 <= p_0 <= 1048576 and 0 <= p_1 <= 1024 and 0 <= p_2 <= 1024 }
+; INNERMOST-NEXT: Assumed Context:
+; INNERMOST-NEXT: [p_0, p_1, p_2] -> {  :  }
+; INNERMOST-NEXT: Invalid Context:
+; INNERMOST-NEXT: [p_0, p_1, p_2] -> {  : 1 = 0 }
+; INNERMOST-NEXT: p0: {0,+,{0,+,1}<nuw><nsw><%bb11>}<nuw><nsw><%bb13>
+; INNERMOST-NEXT: p1: {0,+,1}<nuw><nsw><%bb11>
+; INNERMOST-NEXT: p2: {0,+,1}<nuw><nsw><%bb13>
+; INNERMOST-NEXT: Arrays {
+; INNERMOST-NEXT:     i32 MemRef_A[*]; // Element size 4
+; INNERMOST-NEXT:     i64 MemRef_indvars_iv_next6; // Element size 8
+; INNERMOST-NEXT:     i64 MemRef_indvars_iv_next4; // Element size 8
+; INNERMOST-NEXT: }
+; INNERMOST-NEXT: Arrays (Bounds as pw_affs) {
+; INNERMOST-NEXT:     i32 MemRef_A[*]; // Element size 4
+; INNERMOST-NEXT:     i64 MemRef_indvars_iv_next6; // Element size 8
+; INNERMOST-NEXT:     i64 MemRef_indvars_iv_next4; // Element size 8
+; INNERMOST-NEXT: }
+; INNERMOST-NEXT: Alias Groups (0):
+; INNERMOST-NEXT:     n/a
+; INNERMOST-NEXT: Statements {
+; INNERMOST-NEXT:     Stmt_bb16
+; INNERMOST-NEXT:         Domain :=
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb16[i0] : 0 <= i0 <= 1023 - p_0 };
+; INNERMOST-NEXT:         Schedule :=
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> [0, i0] };
+; INNERMOST-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> MemRef_A[p_1] };
+; INNERMOST-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> MemRef_A[p_2] };
+; INNERMOST-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> MemRef_A[p_0 + i0] };
+; INNERMOST-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> MemRef_A[p_0 + i0] };
+; INNERMOST-NEXT:     Stmt_bb26
+; INNERMOST-NEXT:         Domain :=
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb26[] : p_0 <= 1024 };
+; INNERMOST-NEXT:         Schedule :=
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb26[] -> [1, 0] };
+; INNERMOST-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb26[] -> MemRef_indvars_iv_next6[] };
+; INNERMOST-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb26[] -> MemRef_indvars_iv_next4[] };
+; INNERMOST-NEXT: }
+
+; ALL:      Function: f
+; ALL-NEXT: Region: %bb11---%bb29
+; ALL-NEXT: Max Loop Depth:  2
+; ALL-NEXT: Invariant Accesses: {
+; ALL-NEXT: }
+; ALL-NEXT: Context:
+; ALL-NEXT: {  :  }
+; ALL-NEXT: Assumed Context:
+; ALL-NEXT: {  :  }
+; ALL-NEXT: Invalid Context:
+; ALL-NEXT: {  : 1 = 0 }
+; ALL-NEXT: Arrays {
+; ALL-NEXT:     i32 MemRef_A[*]; // Element size 4
+; ALL-NEXT: }
+; ALL-NEXT: Arrays (Bounds as pw_affs) {
+; ALL-NEXT:     i32 MemRef_A[*]; // Element size 4
+; ALL-NEXT: }
+; ALL-NEXT: Alias Groups (0):
+; ALL-NEXT:     n/a
+; ALL-NEXT: Statements {
+; ALL-NEXT:     Stmt_bb15__TO__bb25
+; ALL-NEXT:         Domain :=
+; ALL-NEXT:             { Stmt_bb15__TO__bb25[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 };
+; ALL-NEXT:         Schedule :=
+; ALL-NEXT:             { Stmt_bb15__TO__bb25[i0, i1] -> [i0, i1] };
+; ALL-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[i0] };
+; ALL-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[i1] };
+; ALL-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[o0] : 0 <= o0 <= 2305843009213693951 };
+; ALL-NEXT:         MayWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[o0] : 0 <= o0 <= 2305843009213693951 };
+; ALL-NEXT: }
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        for (int j = 0; j < 1024; j++)
+;          for (int k = i *j;  k < 1024; k++)
+;            A[k] += A[i] + A[j];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+bb:
+  br label %bb11
+
+bb11:                                             ; preds = %bb28, %bb
+  %indvars.iv8 = phi i64 [ %indvars.iv.next9, %bb28 ], [ 0, %bb ]
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %bb28 ], [ 0, %bb ]
+  %exitcond10 = icmp ne i64 %indvars.iv8, 1024
+  br i1 %exitcond10, label %bb12, label %bb29
+
+bb12:                                             ; preds = %bb11
+  br label %bb13
+
+bb13:                                             ; preds = %bb26, %bb12
+  %indvars.iv5 = phi i64 [ %indvars.iv.next6, %bb26 ], [ 0, %bb12 ]
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %bb26 ], [ 0, %bb12 ]
+  %exitcond7 = icmp ne i64 %indvars.iv5, 1024
+  br i1 %exitcond7, label %bb14, label %bb27
+
+bb14:                                             ; preds = %bb13
+  br label %bb15
+
+bb15:                                             ; preds = %bb24, %bb14
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb24 ], [ %indvars.iv3, %bb14 ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb16, label %bb25
+
+bb16:                                             ; preds = %bb15
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %indvars.iv8
+  %tmp17 = load i32, i32* %tmp, align 4
+  %tmp18 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv5
+  %tmp19 = load i32, i32* %tmp18, align 4
+  %tmp20 = add nsw i32 %tmp17, %tmp19
+  %tmp21 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp22 = load i32, i32* %tmp21, align 4
+  %tmp23 = add nsw i32 %tmp22, %tmp20
+  store i32 %tmp23, i32* %tmp21, align 4
+  br label %bb24
+
+bb24:                                             ; preds = %bb16
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb15
+
+bb25:                                             ; preds = %bb15
+  br label %bb26
+
+bb26:                                             ; preds = %bb25
+  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, %indvars.iv1
+  br label %bb13
+
+bb27:                                             ; preds = %bb13
+  br label %bb28
+
+bb28:                                             ; preds = %bb27
+  %indvars.iv.next9 = add nuw nsw i64 %indvars.iv8, 1
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %bb11
+
+bb29:                                             ; preds = %bb11
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_3.ll b/final/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_3.ll
new file mode 100644
index 0000000..b305398
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_3.ll
@@ -0,0 +1,174 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=false \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=INNERMOST
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops=true \
+; RUN:      -analyze < %s | FileCheck %s --check-prefix=INNERMOST
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine \
+; RUN:     -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=ALL
+;
+; Here we have a non-affine loop (in the context of the loop nest)
+; and also a non-affine access (A[k]). While we can always model the
+; innermost loop as a SCoP of depth 1, we can overapproximate the
+; innermost loop in the whole loop nest and model A[k] as a non-affine
+; access.
+;
+; INNERMOST:      Function: f
+; INNERMOST-NEXT: Region: %bb15---%bb13
+; INNERMOST-NEXT: Max Loop Depth:  1
+; INNERMOST-NEXT: Invariant Accesses: {
+; INNERMOST-NEXT: }
+; INNERMOST-NEXT: Context:
+; INNERMOST-NEXT: [p_0, p_1, p_2] -> {  : 0 <= p_0 <= 2147483647 and 0 <= p_1 <= 1024 and 0 <= p_2 <= 1024 }
+; INNERMOST-NEXT: Assumed Context:
+; INNERMOST-NEXT: [p_0, p_1, p_2] -> {  :  }
+; INNERMOST-NEXT: Invalid Context:
+; INNERMOST-NEXT: [p_0, p_1, p_2] -> {  : 1 = 0 }
+; INNERMOST-NEXT: p0: {0,+,{0,+,1}<nuw><nsw><%bb11>}<nuw><nsw><%bb13>
+; INNERMOST-NEXT: p1: {0,+,1}<nuw><nsw><%bb11>
+; INNERMOST-NEXT: p2: {0,+,1}<nuw><nsw><%bb13>
+; INNERMOST-NEXT: Arrays {
+; INNERMOST-NEXT:     i32 MemRef_A[*]; // Element size 4
+; INNERMOST-NEXT:     i64 MemRef_indvars_iv_next6; // Element size 8
+; INNERMOST-NEXT:     i32 MemRef_indvars_iv_next4; // Element size 4
+; INNERMOST-NEXT: }
+; INNERMOST-NEXT: Arrays (Bounds as pw_affs) {
+; INNERMOST-NEXT:     i32 MemRef_A[*]; // Element size 4
+; INNERMOST-NEXT:     i64 MemRef_indvars_iv_next6; // Element size 8
+; INNERMOST-NEXT:     i32 MemRef_indvars_iv_next4; // Element size 4
+; INNERMOST-NEXT: }
+; INNERMOST-NEXT: Alias Groups (0):
+; INNERMOST-NEXT:     n/a
+; INNERMOST-NEXT: Statements {
+; INNERMOST-NEXT:     Stmt_bb16
+; INNERMOST-NEXT:         Domain :=
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb16[i0] : 0 <= i0 < p_0 };
+; INNERMOST-NEXT:         Schedule :=
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> [0, i0] };
+; INNERMOST-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> MemRef_A[p_1] };
+; INNERMOST-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> MemRef_A[p_2] };
+; INNERMOST-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> MemRef_A[i0] };
+; INNERMOST-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> MemRef_A[i0] };
+; INNERMOST-NEXT:     Stmt_bb26
+; INNERMOST-NEXT:         Domain :=
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb26[] };
+; INNERMOST-NEXT:         Schedule :=
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb26[] -> [1, 0] };
+; INNERMOST-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb26[] -> MemRef_indvars_iv_next6[] };
+; INNERMOST-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; INNERMOST-NEXT:             [p_0, p_1, p_2] -> { Stmt_bb26[] -> MemRef_indvars_iv_next4[] };
+; INNERMOST-NEXT: }
+
+; ALL:      Function: f
+; ALL-NEXT: Region: %bb11---%bb29
+; ALL-NEXT: Max Loop Depth:  2
+; ALL-NEXT: Invariant Accesses: {
+; ALL-NEXT: }
+; ALL-NEXT: Context:
+; ALL-NEXT: {  :  }
+; ALL-NEXT: Assumed Context:
+; ALL-NEXT: {  :  }
+; ALL-NEXT: Invalid Context:
+; ALL-NEXT: {  : 1 = 0 }
+; ALL-NEXT: Arrays {
+; ALL-NEXT:     i32 MemRef_A[*]; // Element size 4
+; ALL-NEXT: }
+; ALL-NEXT: Arrays (Bounds as pw_affs) {
+; ALL-NEXT:     i32 MemRef_A[*]; // Element size 4
+; ALL-NEXT: }
+; ALL-NEXT: Alias Groups (0):
+; ALL-NEXT:     n/a
+; ALL-NEXT: Statements {
+; ALL-NEXT:     Stmt_bb15__TO__bb25
+; ALL-NEXT:         Domain :=
+; ALL-NEXT:             { Stmt_bb15__TO__bb25[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 };
+; ALL-NEXT:         Schedule :=
+; ALL-NEXT:             { Stmt_bb15__TO__bb25[i0, i1] -> [i0, i1] };
+; ALL-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[i0] };
+; ALL-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[i1] };
+; ALL-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[o0] : 0 <= o0 <= 2147483647 };
+; ALL-NEXT:         MayWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[o0] : 0 <= o0 <= 2147483647 };
+; ALL-NEXT: }
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        for (int j = 0; j < 1024; j++)
+;          for (int k = 0; k < i * j; k++)
+;            A[k] += A[i] + A[j];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+bb:
+  br label %bb11
+
+bb11:                                             ; preds = %bb28, %bb
+  %indvars.iv8 = phi i64 [ %indvars.iv.next9, %bb28 ], [ 0, %bb ]
+  %indvars.iv1 = phi i32 [ %indvars.iv.next2, %bb28 ], [ 0, %bb ]
+  %exitcond10 = icmp ne i64 %indvars.iv8, 1024
+  br i1 %exitcond10, label %bb12, label %bb29
+
+bb12:                                             ; preds = %bb11
+  br label %bb13
+
+bb13:                                             ; preds = %bb26, %bb12
+  %indvars.iv5 = phi i64 [ %indvars.iv.next6, %bb26 ], [ 0, %bb12 ]
+  %indvars.iv3 = phi i32 [ %indvars.iv.next4, %bb26 ], [ 0, %bb12 ]
+  %exitcond7 = icmp ne i64 %indvars.iv5, 1024
+  br i1 %exitcond7, label %bb14, label %bb27
+
+bb14:                                             ; preds = %bb13
+  br label %bb15
+
+bb15:                                             ; preds = %bb24, %bb14
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb24 ], [ 0, %bb14 ]
+  %lftr.wideiv = trunc i64 %indvars.iv to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, %indvars.iv3
+  br i1 %exitcond, label %bb16, label %bb25
+
+bb16:                                             ; preds = %bb15
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %indvars.iv8
+  %tmp17 = load i32, i32* %tmp, align 4
+  %tmp18 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv5
+  %tmp19 = load i32, i32* %tmp18, align 4
+  %tmp20 = add nsw i32 %tmp17, %tmp19
+  %tmp21 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp22 = load i32, i32* %tmp21, align 4
+  %tmp23 = add nsw i32 %tmp22, %tmp20
+  store i32 %tmp23, i32* %tmp21, align 4
+  br label %bb24
+
+bb24:                                             ; preds = %bb16
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb15
+
+bb25:                                             ; preds = %bb15
+  br label %bb26
+
+bb26:                                             ; preds = %bb25
+  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1
+  %indvars.iv.next4 = add nuw nsw i32 %indvars.iv3, %indvars.iv1
+  br label %bb13
+
+bb27:                                             ; preds = %bb13
+  br label %bb28
+
+bb28:                                             ; preds = %bb27
+  %indvars.iv.next9 = add nuw nsw i64 %indvars.iv8, 1
+  %indvars.iv.next2 = add nuw nsw i32 %indvars.iv1, 1
+  br label %bb11
+
+bb29:                                             ; preds = %bb11
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non_affine_access_with_range_2.ll b/final/test/ScopInfo/NonAffine/non_affine_access_with_range_2.ll
new file mode 100644
index 0000000..7a2c802
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_access_with_range_2.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 128; i++)
+;        for (int j = 0; j < 16; j++)
+;          A[i * j]++;
+;    }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb7
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] : 0 <= i0 <= 127 and 0 <= i1 <= 15 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> MemRef_A[o0] : 0 <= o0 <= 2048 };
+; CHECK-NEXT:         MayWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> MemRef_A[o0] : 0 <= o0 <= 2048 };
+; CHECK-NEXT: }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+bb:
+  br label %bb4
+
+bb4:                                              ; preds = %bb13, %bb
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %bb13 ], [ 0, %bb ]
+  %exitcond3 = icmp ne i64 %indvars.iv1, 128
+  br i1 %exitcond3, label %bb5, label %bb14
+
+bb5:                                              ; preds = %bb4
+  br label %bb6
+
+bb6:                                              ; preds = %bb11, %bb5
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb11 ], [ 0, %bb5 ]
+  %exitcond = icmp ne i64 %indvars.iv, 16
+  br i1 %exitcond, label %bb7, label %bb12
+
+bb7:                                              ; preds = %bb6
+  %tmp = mul nsw i64 %indvars.iv1, %indvars.iv
+  %tmp8 = getelementptr inbounds i32, i32* %A, i64 %tmp
+  %tmp9 = load i32, i32* %tmp8, align 4
+  %tmp10 = add nsw i32 %tmp9, 1
+  store i32 %tmp10, i32* %tmp8, align 4
+  br label %bb11
+
+bb11:                                             ; preds = %bb7
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb6
+
+bb12:                                             ; preds = %bb6
+  br label %bb13
+
+bb13:                                             ; preds = %bb12
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %bb4
+
+bb14:                                             ; preds = %bb4
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non_affine_but_sdiv.ll b/final/test/ScopInfo/NonAffine/non_affine_but_sdiv.ll
new file mode 100644
index 0000000..3087462
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_but_sdiv.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_for_body[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_for_body[i0] -> [i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_for_body[i0] -> MemRef_A[o0] : -4 + N + 5i0 <= 5o0 <= N + 5i0 };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_for_body[i0] -> MemRef_A[o0] : -N + 5i0 <= 5o0 <= 4 - N + 5i0 };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_for_body[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        A[i] = A[i + (N / 5)] + A[i + (N / -5)];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %div = sdiv i32 %N, 5
+  %tmp1 = trunc i64 %indvars.iv to i32
+  %add = add nsw i32 %tmp1, %div
+  %idxprom = sext i32 %add to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %div1 = sdiv i32 %N, -5
+  %tmp3 = trunc i64 %indvars.iv to i32
+  %add2 = add nsw i32 %tmp3, %div1
+  %idxprom3 = sext i32 %add2 to i64
+  %arrayidx4 = getelementptr inbounds i32, i32* %A, i64 %idxprom3
+  %tmp4 = load i32, i32* %arrayidx4, align 4
+  %add5 = add nsw i32 %tmp2, %tmp4
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %add5, i32* %arrayidx7, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non_affine_but_srem.ll b/final/test/ScopInfo/NonAffine/non_affine_but_srem.ll
new file mode 100644
index 0000000..24f7953
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_but_srem.ll
@@ -0,0 +1,89 @@
+; RUN: opt %loadPolly -polly-scops \
+; RUN:                -analyze < %s | FileCheck %s
+;
+;    void pos(float *A, long n) {
+;      for (long i = 0; i < 100; i++)
+;        A[n % 42] += 1;
+;    }
+;
+;
+;    void neg(float *A, long n) {
+;      for (long i = 0; i < 100; i++)
+;        A[n % (-42)] += 1;
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_bb2[i0] : 0 <= i0 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_bb2[i0] -> [i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bb2[i0] -> MemRef_A[o0] : 42*floor((-n + o0)/42) = -n + o0 and -41 <= o0 <= 41 and ((n < 0 and o0 <= 0) or (n >= 0 and o0 >= 0)) }
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bb2[i0] -> MemRef_A[o0] : 42*floor((-n + o0)/42) = -n + o0 and -41 <= o0 <= 41 and ((n < 0 and o0 <= 0) or (n >= 0 and o0 >= 0)) }
+; CHECK-NEXT: }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_bb2[i0] : 0 <= i0 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_bb2[i0] -> [i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bb2[i0] -> MemRef_A[o0] : 42*floor((-n + o0)/42) = -n + o0 and -41 <= o0 <= 41 and ((n > 0 and o0 >= 0) or (n <= 0 and o0 <= 0)) }
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bb2[i0] -> MemRef_A[o0] : 42*floor((-n + o0)/42) = -n + o0 and -41 <= o0 <= 41 and ((n > 0 and o0 >= 0) or (n <= 0 and o0 <= 0)) }
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @pos(float* %A, i64 %n) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = srem i64 %n, 42
+  %tmp3 = getelementptr inbounds float, float* %A, i64 %tmp
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, 1.000000e+00
+  store float %tmp5, float* %tmp3, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
+
+define void @neg(float* %A, i64 %n) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = srem i64 %n, -42
+  %tmp3 = getelementptr inbounds float, float* %A, i64 %tmp
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, 1.000000e+00
+  store float %tmp5, float* %tmp3, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non_affine_conditional_nested.ll b/final/test/ScopInfo/NonAffine/non_affine_conditional_nested.ll
new file mode 100644
index 0000000..199988a
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_conditional_nested.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine-branches \
+; RUN:                -analyze < %s | FileCheck %s
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        if (A[i])
+;          if (A[i - 1])
+;            A[i] = A[i - 2];
+;    }
+;
+; CHECK:    Region: %bb1---%bb18
+; CHECK:    Max Loop Depth:  1
+; CHECK:    Statements {
+; CHECK:      Stmt_bb2__TO__bb16
+; CHECK:            Schedule :=
+; CHECK:                { Stmt_bb2__TO__bb16[i0] -> [i0] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2__TO__bb16[i0] -> MemRef_A[i0] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2__TO__bb16[i0] -> MemRef_A[-1 + i0] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2__TO__bb16[i0] -> MemRef_A[-2 + i0] };
+; CHECK:            MayWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2__TO__bb16[i0] -> MemRef_A[i0] };
+; CHECK:    }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb17, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb17 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb18
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %tmp, align 4
+  %tmp4 = icmp eq i32 %tmp3, 0
+  br i1 %tmp4, label %bb16, label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = add nsw i64 %indvars.iv, -1
+  %tmp7 = getelementptr inbounds i32, i32* %A, i64 %tmp6
+  %tmp8 = load i32, i32* %tmp7, align 4
+  %tmp9 = icmp eq i32 %tmp8, 0
+  br i1 %tmp9, label %bb15, label %bb10
+
+bb10:                                             ; preds = %bb5
+  %tmp11 = add nsw i64 %indvars.iv, -2
+  %tmp12 = getelementptr inbounds i32, i32* %A, i64 %tmp11
+  %tmp13 = load i32, i32* %tmp12, align 4
+  %tmp14 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp13, i32* %tmp14, align 4
+  br label %bb15
+
+bb15:                                             ; preds = %bb5, %bb10
+  br label %bb16
+
+bb16:                                             ; preds = %bb2, %bb15
+  br label %bb17
+
+bb17:                                             ; preds = %bb16
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb18:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_affine_loop.ll b/final/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_affine_loop.ll
new file mode 100644
index 0000000..0b5bfff
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_affine_loop.ll
@@ -0,0 +1,157 @@
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine-branches \
+; RUN:     -polly-invariant-load-hoisting=true \
+; RUN:     -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=INNERMOST
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine \
+; RUN:     -polly-invariant-load-hoisting=true \
+; RUN:     -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s \
+; RUN:     --check-prefix=ALL
+;
+; Negative test for INNERMOST.
+; At the moment we will optimistically assume A[i] in the conditional before the inner
+; loop might be invariant and expand the SCoP from the loop to include the conditional. However,
+; during SCoP generation we will realize that A[i] is in not always invariant.
+;
+; Possible solutions could be:
+;   - Do not optimistically assume it to be invariant (as before this commit), however we would loose
+;     a lot of invariant cases due to possible aliasing.
+;   - Reduce the size of the SCoP if an assumed invariant access is in fact not invariant instead of
+;     rejecting the whole region.
+;
+; INNERMOST:         Function: f
+; INNERMOST-NEXT:    Region: %bb4---%bb3
+; INNERMOST-NEXT:    Max Loop Depth:  1
+; INNERMOST-NEXT:    Invariant Accesses: {
+; INNERMOST-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; INNERMOST-NEXT:                [tmp6, N, p_2] -> { Stmt_bb4[] -> MemRef_A[p_2] };
+; INNERMOST-NEXT:            Execution Context: [tmp6, N, p_2] -> { : (tmp6 > 0 and p_2 >= N) or (tmp6 < 0 and p_2 >= N) or tmp6 = 0 }
+; INNERMOST-NEXT:    }
+; INNERMOST-NEXT:    Context:
+; INNERMOST-NEXT:    [tmp6, N, p_2] -> {  : -2147483648 <= tmp6 <= 2147483647 and -2147483648 <= N <= 2147483647 and 0 <= p_2 <= 1024 }
+; INNERMOST-NEXT:    Assumed Context:
+; INNERMOST-NEXT:    [tmp6, N, p_2] -> {  :  }
+; INNERMOST-NEXT:    Invalid Context:
+; INNERMOST-NEXT:    [tmp6, N, p_2] -> {  : p_2 < N and (tmp6 < 0 or tmp6 > 0) }
+; INNERMOST-NEXT:    p0: %tmp6
+; INNERMOST-NEXT:    p1: %N
+; INNERMOST-NEXT:    p2: {0,+,1}<nuw><nsw><%bb3>
+; INNERMOST-NEXT:    Arrays {
+; INNERMOST-NEXT:        i32 MemRef_A[*]; // Element size 4
+; INNERMOST-NEXT:        i64 MemRef_indvars_iv_next2; // Element size 8
+; INNERMOST-NEXT:    }
+; INNERMOST-NEXT:    Arrays (Bounds as pw_affs) {
+; INNERMOST-NEXT:        i32 MemRef_A[*]; // Element size 4
+; INNERMOST-NEXT:        i64 MemRef_indvars_iv_next2; // Element size 8
+; INNERMOST-NEXT:    }
+; INNERMOST-NEXT:    Alias Groups (0):
+; INNERMOST-NEXT:        n/a
+; INNERMOST-NEXT:    Statements {
+; INNERMOST-NEXT:    	Stmt_bb11
+; INNERMOST-NEXT:            Domain :=
+; INNERMOST-NEXT:                [tmp6, N, p_2] -> { Stmt_bb11[i0] : 0 <= i0 < N and (tmp6 < 0 or tmp6 > 0) };
+; INNERMOST-NEXT:            Schedule :=
+; INNERMOST-NEXT:                [tmp6, N, p_2] -> { Stmt_bb11[i0] -> [0, i0] : tmp6 < 0 or tmp6 > 0 };
+; INNERMOST-NEXT:            ReadAccess :=	[Reduction Type: +] [Scalar: 0]
+; INNERMOST-NEXT:                [tmp6, N, p_2] -> { Stmt_bb11[i0] -> MemRef_A[i0] };
+; INNERMOST-NEXT:            MustWriteAccess :=	[Reduction Type: +] [Scalar: 0]
+; INNERMOST-NEXT:                [tmp6, N, p_2] -> { Stmt_bb11[i0] -> MemRef_A[i0] };
+; INNERMOST-NEXT:    	Stmt_bb18
+; INNERMOST-NEXT:            Domain :=
+; INNERMOST-NEXT:                [tmp6, N, p_2] -> { Stmt_bb18[] };
+; INNERMOST-NEXT:            Schedule :=
+; INNERMOST-NEXT:                [tmp6, N, p_2] -> { Stmt_bb18[] -> [1, 0] };
+; INNERMOST-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; INNERMOST-NEXT:                [tmp6, N, p_2] -> { Stmt_bb18[] -> MemRef_indvars_iv_next2[] };
+; INNERMOST-NEXT:    }
+;
+; ALL:      Function: f
+; ALL-NEXT: Region: %bb3---%bb19
+; ALL-NEXT: Max Loop Depth:  1
+; ALL-NEXT: Invariant Accesses: {
+; ALL-NEXT: }
+; ALL-NEXT: Context:
+; ALL-NEXT: {  :  }
+; ALL-NEXT: Assumed Context:
+; ALL-NEXT: {  :  }
+; ALL-NEXT: Invalid Context:
+; ALL-NEXT: {  : 1 = 0 }
+; ALL-NEXT: Arrays {
+; ALL-NEXT:     i32 MemRef_A[*]; // Element size 4
+; ALL-NEXT: }
+; ALL-NEXT: Arrays (Bounds as pw_affs) {
+; ALL-NEXT:     i32 MemRef_A[*]; // Element size 4
+; ALL-NEXT: }
+; ALL-NEXT: Alias Groups (0):
+; ALL-NEXT:     n/a
+; ALL-NEXT: Statements {
+; ALL-NEXT:     Stmt_bb4__TO__bb17
+; ALL-NEXT:         Domain :=
+; ALL-NEXT:             { Stmt_bb4__TO__bb17[i0] : 0 <= i0 <= 1023 };
+; ALL-NEXT:         Schedule :=
+; ALL-NEXT:             { Stmt_bb4__TO__bb17[i0] -> [i0] };
+; ALL-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb4__TO__bb17[i0] -> MemRef_A[i0] };
+; ALL-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb4__TO__bb17[i0] -> MemRef_A[o0] : 0 <= o0 <= 2147483647 };
+; ALL-NEXT:         MayWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb4__TO__bb17[i0] -> MemRef_A[o0] : 0 <= o0 <= 2147483647 };
+; ALL-NEXT: }
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < 1024; i++)
+;        if (A[i])
+;          for (int j = 0; j < N; j++)
+;            A[j]++;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  br label %bb3
+
+bb3:                                              ; preds = %bb18, %bb
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %bb18 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv1, 1024
+  br i1 %exitcond, label %bb4, label %bb19
+
+bb4:                                              ; preds = %bb3
+  %tmp5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv1
+  %tmp6 = load i32, i32* %tmp5, align 4
+  %tmp7 = icmp eq i32 %tmp6, 0
+  br i1 %tmp7, label %bb17, label %bb8
+
+bb8:                                              ; preds = %bb4
+  br label %bb9
+
+bb9:                                              ; preds = %bb15, %bb8
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb15 ], [ 0, %bb8 ]
+  %tmp10 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp10, label %bb11, label %bb16
+
+bb11:                                             ; preds = %bb9
+  %tmp12 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp13 = load i32, i32* %tmp12, align 4
+  %tmp14 = add nsw i32 %tmp13, 1
+  store i32 %tmp14, i32* %tmp12, align 4
+  br label %bb15
+
+bb15:                                             ; preds = %bb11
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb9
+
+bb16:                                             ; preds = %bb9
+  br label %bb17
+
+bb17:                                             ; preds = %bb4, %bb16
+  br label %bb18
+
+bb18:                                             ; preds = %bb17
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %bb3
+
+bb19:                                             ; preds = %bb3
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_non_affine_loop.ll b/final/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_non_affine_loop.ll
new file mode 100644
index 0000000..b6f5c98
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_non_affine_loop.ll
@@ -0,0 +1,164 @@
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine-branches \
+; RUN:     -polly-invariant-load-hoisting=true \
+; RUN:     -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=INNERMOST
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine \
+; RUN:     -polly-invariant-load-hoisting=true \
+; RUN:     -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=ALL
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine \
+; RUN:     -polly-invariant-load-hoisting=true \
+; RUN:     -polly-process-unprofitable=false \
+; RUN:     -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=PROFIT
+;
+; Negative test for INNERMOST.
+; At the moment we will optimistically assume A[i] in the conditional before the inner
+; loop might be invariant and expand the SCoP from the loop to include the conditional. However,
+; during SCoP generation we will realize that A[i] is only sometimes invariant.
+;
+; Possible solutions could be:
+;   - Do not optimistically assume it to be invariant (as before this commit), however we would loose
+;     a lot of invariant cases due to possible aliasing.
+;   - Reduce the size of the SCoP if an assumed invariant access is in fact not invariant instead of
+;     rejecting the whole region.
+;
+; INNERMOST:         Function: f
+; INNERMOST-NEXT:    Region: %bb4---%bb3
+; INNERMOST-NEXT:    Max Loop Depth:  1
+; INNERMOST-NEXT:    Invariant Accesses: {
+; INNERMOST-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; INNERMOST-NEXT:                [tmp6, p_1, p_2] -> { Stmt_bb4[] -> MemRef_A[p_2] };
+; INNERMOST-NEXT:            Execution Context: [tmp6, p_1, p_2] -> { : (tmp6 > 0 and p_2 >= p_1) or (tmp6 < 0 and p_2 >= p_1) or tmp6 = 0 }
+; INNERMOST-NEXT:    }
+; INNERMOST-NEXT:    Context:
+; INNERMOST-NEXT:    [tmp6, p_1, p_2] -> {  : -2147483648 <= tmp6 <= 2147483647 and -2199023255552 <= p_1 <= 2199023254528 and 0 <= p_2 <= 1024 }
+; INNERMOST-NEXT:    Assumed Context:
+; INNERMOST-NEXT:    [tmp6, p_1, p_2] -> {  :  }
+; INNERMOST-NEXT:    Invalid Context:
+; INNERMOST-NEXT:    [tmp6, p_1, p_2] -> {  : p_2 < p_1 and (tmp6 < 0 or tmp6 > 0) }
+; INNERMOST-NEXT:    p0: %tmp6
+; INNERMOST-NEXT:    p1: {0,+,(sext i32 %N to i64)}<%bb3>
+; INNERMOST-NEXT:    p2: {0,+,1}<nuw><nsw><%bb3>
+; INNERMOST-NEXT:    Arrays {
+; INNERMOST-NEXT:        i32 MemRef_A[*]; // Element size 4
+; INNERMOST-NEXT:        i64 MemRef_indvars_iv_next2; // Element size 8
+; INNERMOST-NEXT:    }
+; INNERMOST-NEXT:    Arrays (Bounds as pw_affs) {
+; INNERMOST-NEXT:        i32 MemRef_A[*]; // Element size 4
+; INNERMOST-NEXT:        i64 MemRef_indvars_iv_next2; // Element size 8
+; INNERMOST-NEXT:    }
+; INNERMOST-NEXT:    Alias Groups (0):
+; INNERMOST-NEXT:        n/a
+; INNERMOST-NEXT:    Statements {
+; INNERMOST-NEXT:    	Stmt_bb12
+; INNERMOST-NEXT:            Domain :=
+; INNERMOST-NEXT:                [tmp6, p_1, p_2] -> { Stmt_bb12[i0] : 0 <= i0 < p_1 and (tmp6 < 0 or tmp6 > 0) };
+; INNERMOST-NEXT:            Schedule :=
+; INNERMOST-NEXT:                [tmp6, p_1, p_2] -> { Stmt_bb12[i0] -> [0, i0] : tmp6 < 0 or tmp6 > 0 };
+; INNERMOST-NEXT:            ReadAccess :=	[Reduction Type: +] [Scalar: 0]
+; INNERMOST-NEXT:                [tmp6, p_1, p_2] -> { Stmt_bb12[i0] -> MemRef_A[i0] };
+; INNERMOST-NEXT:            MustWriteAccess :=	[Reduction Type: +] [Scalar: 0]
+; INNERMOST-NEXT:                [tmp6, p_1, p_2] -> { Stmt_bb12[i0] -> MemRef_A[i0] };
+; INNERMOST-NEXT:    	Stmt_bb19
+; INNERMOST-NEXT:            Domain :=
+; INNERMOST-NEXT:                [tmp6, p_1, p_2] -> { Stmt_bb19[] };
+; INNERMOST-NEXT:            Schedule :=
+; INNERMOST-NEXT:                [tmp6, p_1, p_2] -> { Stmt_bb19[] -> [1, 0] };
+; INNERMOST-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; INNERMOST-NEXT:                [tmp6, p_1, p_2] -> { Stmt_bb19[] -> MemRef_indvars_iv_next2[] };
+; INNERMOST-NEXT:    }
+;
+; ALL:      Function: f
+; ALL-NEXT: Region: %bb3---%bb20
+; ALL-NEXT: Max Loop Depth:  1
+; ALL-NEXT: Invariant Accesses: {
+; ALL-NEXT: }
+; ALL-NEXT: Context:
+; ALL-NEXT: {  :  }
+; ALL-NEXT: Assumed Context:
+; ALL-NEXT: {  :  }
+; ALL-NEXT: Invalid Context:
+; ALL-NEXT: {  : 1 = 0 }
+; ALL-NEXT: Arrays {
+; ALL-NEXT:     i32 MemRef_A[*]; // Element size 4
+; ALL-NEXT: }
+; ALL-NEXT: Arrays (Bounds as pw_affs) {
+; ALL-NEXT:     i32 MemRef_A[*]; // Element size 4
+; ALL-NEXT: }
+; ALL-NEXT: Alias Groups (0):
+; ALL-NEXT:     n/a
+; ALL-NEXT: Statements {
+; ALL-NEXT:     Stmt_bb4__TO__bb18
+; ALL-NEXT:         Domain :=
+; ALL-NEXT:             { Stmt_bb4__TO__bb18[i0] : 0 <= i0 <= 1023 };
+; ALL-NEXT:         Schedule :=
+; ALL-NEXT:             { Stmt_bb4__TO__bb18[i0] -> [i0] };
+; ALL-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb4__TO__bb18[i0] -> MemRef_A[i0] };
+; ALL-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb4__TO__bb18[i0] -> MemRef_A[o0] : 0 <= o0 <= 2199023254528 };
+; ALL-NEXT:         MayWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; ALL-NEXT:             { Stmt_bb4__TO__bb18[i0] -> MemRef_A[o0] : 0 <= o0 <= 2199023254528 };
+; ALL-NEXT: }
+;
+; PROFIT-NOT: Statements
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < 1024; i++)
+;        if (A[i])
+;          for (int j = 0; j < N * i; j++)
+;            A[j]++;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  br label %bb3
+
+bb3:                                              ; preds = %bb19, %bb
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %bb19 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv1, 1024
+  br i1 %exitcond, label %bb4, label %bb20
+
+bb4:                                              ; preds = %bb3
+  %tmp5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv1
+  %tmp6 = load i32, i32* %tmp5, align 4
+  %tmp7 = icmp eq i32 %tmp6, 0
+  br i1 %tmp7, label %bb18, label %bb8
+
+bb8:                                              ; preds = %bb4
+  br label %bb9
+
+bb9:                                              ; preds = %bb16, %bb8
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb16 ], [ 0, %bb8 ]
+  %tmp10 = mul nsw i64 %indvars.iv1, %tmp
+  %tmp11 = icmp slt i64 %indvars.iv, %tmp10
+  br i1 %tmp11, label %bb12, label %bb17
+
+bb12:                                             ; preds = %bb9
+  %tmp13 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp14 = load i32, i32* %tmp13, align 4
+  %tmp15 = add nsw i32 %tmp14, 1
+  store i32 %tmp15, i32* %tmp13, align 4
+  br label %bb16
+
+bb16:                                             ; preds = %bb12
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb9
+
+bb17:                                             ; preds = %bb9
+  br label %bb18
+
+bb18:                                             ; preds = %bb4, %bb17
+  br label %bb19
+
+bb19:                                             ; preds = %bb18
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %bb3
+
+bb20:                                             ; preds = %bb3
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non_affine_float_compare.ll b/final/test/ScopInfo/NonAffine/non_affine_float_compare.ll
new file mode 100644
index 0000000..84573f6
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_float_compare.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine-branches \
+; RUN:                -analyze < %s | FileCheck %s
+;
+;    void f(float *A) {
+;      for (int i = 0; i < 1024; i++)
+;        if (A[i] == A[i - 1])
+;          A[i]++;
+;    }
+;
+; CHECK:      Function: f
+; CHECK-NEXT: Region: %bb1---%bb14
+; CHECK-NEXT: Max Loop Depth:  1
+; CHECK-NEXT: Invariant Accesses: {
+; CHECK-NEXT: }
+; CHECK-NEXT: Context:
+; CHECK-NEXT: {  :  }
+; CHECK-NEXT: Assumed Context:
+; CHECK-NEXT: {  :  }
+; CHECK-NEXT: Invalid Context:
+; CHECK-NEXT: {  : 1 = 0 }
+; CHECK-NEXT: Arrays {
+; CHECK-NEXT:     float MemRef_A[*]; // Element size 4
+; CHECK-NEXT: }
+; CHECK-NEXT: Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:     float MemRef_A[*]; // Element size 4
+; CHECK-NEXT: }
+; CHECK-NEXT: Alias Groups (0):
+; CHECK-NEXT:     n/a
+; CHECK-NEXT: Statements {
+; CHECK-NEXT:     Stmt_bb2__TO__bb12
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb2__TO__bb12[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb2__TO__bb12[i0] -> [i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb2__TO__bb12[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb2__TO__bb12[i0] -> MemRef_A[-1 + i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb2__TO__bb12[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MayWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb2__TO__bb12[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(float* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb13, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb13 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb14
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp3 = load float, float* %tmp, align 4
+  %tmp4 = add nsw i64 %indvars.iv, -1
+  %tmp5 = getelementptr inbounds float, float* %A, i64 %tmp4
+  %tmp6 = load float, float* %tmp5, align 4
+  %tmp7 = fcmp oeq float %tmp3, %tmp6
+  br i1 %tmp7, label %bb8, label %bb12
+
+bb8:                                              ; preds = %bb2
+  %tmp9 = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp10 = load float, float* %tmp9, align 4
+  %tmp11 = fadd float %tmp10, 1.000000e+00
+  store float %tmp11, float* %tmp9, align 4
+  br label %bb12
+
+bb12:                                             ; preds = %bb8, %bb2
+  br label %bb13
+
+bb13:                                             ; preds = %bb12
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb14:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non_affine_loop_condition.ll b/final/test/ScopInfo/NonAffine/non_affine_loop_condition.ll
new file mode 100644
index 0000000..7222858
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_loop_condition.ll
@@ -0,0 +1,99 @@
+; RUN: opt %loadPolly -polly-scops \
+; RUN:     -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops \
+; RUN:     -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine-branches \
+; RUN:     -polly-process-unprofitable=false \
+; RUN:     -polly-allow-nonaffine-loops -analyze < %s | FileCheck %s \
+; RUN:     --check-prefix=PROFIT
+
+
+; RUN: opt %loadPolly -polly-scops -polly-detect-reductions \
+; RUN:                -polly-allow-nonaffine-branches \
+; RUN:                \
+; RUN:                -polly-allow-nonaffine-loops -analyze < %s \
+; RUN:                -polly-detect-reductions=false \
+; RUN: | FileCheck %s -check-prefix=NO-REDUCTION
+;
+;    void f(int *A, int *C) {
+;      for (int i = 0; i < 1024; i++) {
+;        while (C[i])
+;          A[i]++;
+;      }
+;    }
+;
+; CHECK:      Function: f
+; CHECK-NEXT: Region: %bb1---%bb12
+; CHECK-NEXT: Max Loop Depth:  1
+; CHECK-NEXT: Invariant Accesses: {
+; CHECK-NEXT: }
+; CHECK-NEXT: Context:
+; CHECK-NEXT: {  :  }
+; CHECK-NEXT: Assumed Context:
+; CHECK-NEXT: {  :  }
+; CHECK-NEXT: Invalid Context:
+; CHECK-NEXT: {  : 1 = 0 }
+; CHECK-NEXT: Arrays {
+; CHECK-NEXT:     i32 MemRef_C[*]; // Element size 4
+; CHECK-NEXT:     i32 MemRef_A[*]; // Element size 4
+; CHECK-NEXT: }
+; CHECK-NEXT: Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:     i32 MemRef_C[*]; // Element size 4
+; CHECK-NEXT:     i32 MemRef_A[*]; // Element size 4
+; CHECK-NEXT: }
+; CHECK-NEXT: Alias Groups (1):
+; CHECK-NEXT:     {{\[\[}} <{ MemRef_C[(0)] }, { MemRef_C[(1024)] }> <{ MemRef_A[(0)] }, { MemRef_A[(1024)] }> {{\]\]}}
+; CHECK-NEXT: Statements {
+; CHECK-NEXT:     Stmt_bb3__TO__bb10
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb3__TO__bb10[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb3__TO__bb10[i0] -> [i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb3__TO__bb10[i0] -> MemRef_C[i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb3__TO__bb10[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MayWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb3__TO__bb10[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+
+; PROFIT-NOT: Statements
+
+; NO-REDUCTION-NOT: Reduction Type: +
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %C) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb11, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb11 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb12
+
+bb2:                                              ; preds = %bb1
+  br label %bb3
+
+bb3:                                              ; preds = %bb6, %bb2
+  %tmp = getelementptr inbounds i32, i32* %C, i64 %indvars.iv
+  %tmp4 = load i32, i32* %tmp, align 4
+  %tmp5 = icmp eq i32 %tmp4, 0
+  br i1 %tmp5, label %bb10, label %bb6
+
+bb6:                                              ; preds = %bb3
+  %tmp7 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp8 = load i32, i32* %tmp7, align 4
+  %tmp9 = add nsw i32 %tmp8, 1
+  store i32 %tmp9, i32* %tmp7, align 4
+  br label %bb3
+
+bb10:                                             ; preds = %bb3
+  br label %bb11
+
+bb11:                                             ; preds = %bb10
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb12:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non_affine_loop_used_later.ll b/final/test/ScopInfo/NonAffine/non_affine_loop_used_later.ll
new file mode 100644
index 0000000..61d7134
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_loop_used_later.ll
@@ -0,0 +1,162 @@
+; RUN: opt %loadPolly -polly-scops \
+; RUN:     -polly-allow-nonaffine -polly-allow-nonaffine-branches \
+; RUN:     -polly-allow-nonaffine-loops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine \
+; RUN:     -polly-unprofitable-scalar-accs=true \
+; RUN:     -polly-process-unprofitable=false \
+; RUN:     -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops \
+; RUN:     -analyze < %s | FileCheck %s --check-prefix=PROFIT
+;
+; Verify that we over approximate the read acces of A[j] in the last statement as j is
+; computed in a non-affine loop we do not model.
+;
+; CHECK:      Function: f
+; CHECK-NEXT: Region: %bb2---%bb24
+; CHECK-NEXT: Max Loop Depth:  1
+; CHECK-NEXT: Invariant Accesses: {
+; CHECK-NEXT: }
+; CHECK-NEXT: Context:
+; CHECK-NEXT: [N] -> {  : -2147483648 <= N <= 2147483647 }
+; CHECK-NEXT: Assumed Context:
+; CHECK-NEXT: [N] -> {  :  }
+; CHECK-NEXT: Invalid Context:
+; CHECK-NEXT: [N] -> {  : 1 = 0 }
+; CHECK-NEXT: p0: %N
+; CHECK-NEXT: Arrays {
+; CHECK-NEXT:     i32 MemRef_j_0__phi; // Element size 4
+; CHECK-NEXT:     i32 MemRef_j_0; // Element size 4
+; CHECK-NEXT:     i32 MemRef_A[*]; // Element size 4
+; CHECK-NEXT:     i32 MemRef_j_2__phi; // Element size 4
+; CHECK-NEXT:     i32 MemRef_j_2; // Element size 4
+; CHECK-NEXT: }
+; CHECK-NEXT: Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:     i32 MemRef_j_0__phi; // Element size 4
+; CHECK-NEXT:     i32 MemRef_j_0; // Element size 4
+; CHECK-NEXT:     i32 MemRef_A[*]; // Element size 4
+; CHECK-NEXT:     i32 MemRef_j_2__phi; // Element size 4
+; CHECK-NEXT:     i32 MemRef_j_2; // Element size 4
+; CHECK-NEXT: }
+; CHECK-NEXT: Alias Groups (0):
+; CHECK-NEXT:     n/a
+; CHECK-NEXT: Statements {
+; CHECK-NEXT:     Stmt_bb2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_bb2[i0] : 0 <= i0 <= N; Stmt_bb2[0] : N < 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_bb2[i0] -> [i0, 0] : i0 <= N; Stmt_bb2[0] -> [0, 0] : N < 0 };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_bb2[i0] -> MemRef_j_0__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_bb2[i0] -> MemRef_j_0[] };
+; CHECK-NEXT:     Stmt_bb4__TO__bb18
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_bb4__TO__bb18[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_bb4__TO__bb18[i0] -> [i0, 1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MayWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_j_2__phi[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_j_0[] };
+; CHECK-NEXT:     Stmt_bb18
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_bb18[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_bb18[i0] -> [i0, 2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_bb18[i0] -> MemRef_j_2[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_bb18[i0] -> MemRef_j_2__phi[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_bb18[i0] -> MemRef_A[o0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_bb18[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_bb23
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_bb23[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_bb23[i0] -> [i0, 3] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_bb23[i0] -> MemRef_j_2[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_bb23[i0] -> MemRef_j_0__phi[] };
+; CHECK-NEXT: }
+;
+; Due to the scalar accesses we are not able to distribute the outer loop, thus we do not consider the region profitable.
+;
+; PROFIT-NOT: Statements
+;
+;    void f(int *A, int N, int M) {
+;      int i = 0, j = 0;
+;      for (i = 0; i < N; i++) {
+;        if (A[i])
+;          for (j = 0; j < M; j++)
+;            A[i]++;
+;        A[i] = A[j];
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N, i32 %M) {
+bb:
+  %tmp = icmp sgt i32 %M, 0
+  %smax = select i1 %tmp, i32 %M, i32 0
+  %tmp1 = sext i32 %N to i64
+  br label %bb2
+
+bb2:                                              ; preds = %bb23, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb23 ], [ 0, %bb ]
+  %j.0 = phi i32 [ 0, %bb ], [ %j.2, %bb23 ]
+  %tmp3 = icmp slt i64 %indvars.iv, %tmp1
+  br i1 %tmp3, label %bb4, label %bb24
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp6 = load i32, i32* %tmp5, align 4
+  %tmp7 = icmp eq i32 %tmp6, 0
+  br i1 %tmp7, label %bb18, label %bb8
+
+bb8:                                              ; preds = %bb4
+  br label %bb9
+
+bb9:                                              ; preds = %bb15, %bb8
+  %j.1 = phi i32 [ 0, %bb8 ], [ %tmp16, %bb15 ]
+  %tmp10 = icmp slt i32 %j.1, %M
+  br i1 %tmp10, label %bb11, label %bb17
+
+bb11:                                             ; preds = %bb9
+  %tmp12 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp13 = load i32, i32* %tmp12, align 4
+  %tmp14 = add nsw i32 %tmp13, 1
+  store i32 %tmp14, i32* %tmp12, align 4
+  br label %bb15
+
+bb15:                                             ; preds = %bb11
+  %tmp16 = add nuw nsw i32 %j.1, 1
+  br label %bb9
+
+bb17:                                             ; preds = %bb9
+  br label %bb18
+
+bb18:                                             ; preds = %bb4, %bb17
+  %j.2 = phi i32 [ %smax, %bb17 ], [ %j.0, %bb4 ]
+  %tmp19 = sext i32 %j.2 to i64
+  %tmp20 = getelementptr inbounds i32, i32* %A, i64 %tmp19
+  %tmp21 = load i32, i32* %tmp20, align 4
+  %tmp22 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp21, i32* %tmp22, align 4
+  br label %bb23
+
+bb23:                                             ; preds = %bb18
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb2
+
+bb24:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/non_affine_parametric_loop.ll b/final/test/ScopInfo/NonAffine/non_affine_parametric_loop.ll
new file mode 100644
index 0000000..18e08e6
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_parametric_loop.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze -polly-allow-nonaffine < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; void foo(long n, double A[], int INDEX[]) {
+;   for (long i = 0; i < n; i++)
+;     A[INDEX[i]] = i;
+; }
+
+define void @foo(i64 %n, double* noalias %A, i64* noalias %INDEX) {
+entry:
+  br label %for.body
+
+for.body:
+  %i = phi i64 [ %inc, %for.body ], [ 0, %entry ]
+  %arrayidx = getelementptr inbounds i64, i64* %INDEX, i64 %i
+  %val = load i64, i64* %arrayidx
+  %arrayidx1 = getelementptr inbounds double, double* %A, i64 %val
+  store double 1.0, double* %arrayidx1
+  %inc = add nsw i64 %i, 1
+  %exitcond = icmp eq i64 %inc, %n
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:
+  ret void
+}
+
+; CHECK:      p0: %n
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_for_body[i0] : 0 <= i0 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_for_body[i0] -> [i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_for_body[i0] -> MemRef_INDEX[i0] };
+; CHECK-NEXT:         MayWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_for_body[i0] -> MemRef_A[o0] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/NonAffine/non_affine_region_guaranteed_non-entry.ll b/final/test/ScopInfo/NonAffine/non_affine_region_guaranteed_non-entry.ll
new file mode 100644
index 0000000..f17cea4
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_region_guaranteed_non-entry.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-detect -polly-scops -analyze \
+; RUN:                -polly-allow-nonaffine-loops < %s | FileCheck %s
+
+; The BasicBlock "guaranteed" is always executed inside the non-affine subregion
+; region_entry->region_exit. As such, writes accesses in blocks that always
+; execute are MustWriteAccesses. Before Polly commit r255473, we only assumed
+; that the subregion's entry block is guaranteed to execute.
+
+; CHECK-NOT: MayWriteAccess
+; CHECK:      MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] };
+; CHECK-NOT: MayWriteAccess
+
+define void @f(i32* %A, i32* %B, i32* %C, float %b) {
+entry:
+  br label %for.cond
+
+for.cond:
+  %indvar = phi i32 [ %indvar.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i32 %indvar, 1024
+  br i1 %exitcond, label %region_entry, label %return
+
+region_entry:
+  br label %bb2
+
+bb2:
+  br label %guaranteed
+
+bb3:
+  br label %bb3
+
+guaranteed:
+  %ptr = getelementptr i32, i32* %B, i32 %indvar
+  %val = load i32, i32* %ptr
+  %cmp = icmp eq i32 %val, 0
+  store i32 0, i32* %A
+  br i1 %cmp, label %bb5, label %bb6
+
+bb5:
+  br label %region_exit
+
+bb6:
+  %ptr2 = getelementptr i32, i32* %C, i32 %indvar
+  %val2 = load i32, i32* %ptr2
+  %cmp2 = icmp eq i32 %val2, 0
+  br i1 %cmp2, label %region_exit, label %region_entry
+
+region_exit:
+  br label %for.inc
+
+for.inc:
+  %indvar.next = add i32 %indvar, 1
+  br label %for.cond
+
+return:
+  ret void
+}
diff --git a/final/test/ScopInfo/NonAffine/whole-scop-non-affine-subregion-in-loop.ll b/final/test/ScopInfo/NonAffine/whole-scop-non-affine-subregion-in-loop.ll
new file mode 100644
index 0000000..a14b8f4
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/whole-scop-non-affine-subregion-in-loop.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s
+;
+; Regression test that triggered a memory leak at some point (24947).
+;
+define void @snrm2() {
+entry:
+  br label %for.body.56.lr.ph
+
+for.body.56.lr.ph:                                ; preds = %entry
+  br label %for.body.56
+
+for.body.56:                                      ; preds = %for.inc.106, %for.body.56.lr.ph
+  br label %if.end.73
+
+if.end.73:                                        ; preds = %for.body.56
+  %cmp82 = fcmp ogt float undef, undef
+  br i1 %cmp82, label %if.then.84, label %if.end.100
+
+if.then.84:                                       ; preds = %if.end.73
+  br label %for.inc.106
+
+if.end.100:                                       ; preds = %if.end.73
+  br label %for.inc.106
+
+for.inc.106:                                      ; preds = %if.end.100, %if.then.84
+  br i1 undef, label %for.body.56, label %for.end.110
+
+for.end.110:                                      ; preds = %for.inc.106
+  ret void
+}
diff --git a/final/test/ScopInfo/aliasing_conditional_alias_groups_1.ll b/final/test/ScopInfo/aliasing_conditional_alias_groups_1.ll
new file mode 100644
index 0000000..2513068
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_conditional_alias_groups_1.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that there is no alias group because we either access A or B never both.
+;
+; CHECK: Alias Groups (0):
+;
+;    void jd(int b, int *A, int *B) {
+;      for (int i = 0; i < 1024; i++) {
+;        if (b)
+;          A[i] = A[i - 1];
+;        else
+;          B[i] = B[i - 1];
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32 %b, i32* %A, i32* %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tobool = icmp eq i32 %b, 0
+  br i1 %tobool, label %if.else, label %if.then
+
+if.then:                                          ; preds = %for.body
+  %tmp = add nsw i64 %indvars.iv, -1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %tmp
+  %tmp3 = load i32, i32* %arrayidx, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp3, i32* %arrayidx2, align 4
+  br label %if.end
+
+if.else:                                          ; preds = %for.body
+  %tmp4 = add nsw i64 %indvars.iv, -1
+  %arrayidx5 = getelementptr inbounds i32, i32* %B, i64 %tmp4
+  %tmp5 = load i32, i32* %arrayidx5, align 4
+  %arrayidx7 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  store i32 %tmp5, i32* %arrayidx7, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/aliasing_conditional_alias_groups_2.ll b/final/test/ScopInfo/aliasing_conditional_alias_groups_2.ll
new file mode 100644
index 0000000..8988044
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_conditional_alias_groups_2.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that we create two alias groups since the mininmal/maximal accesses
+; depend on %b.
+;
+; CHECK: Alias Groups (2):
+;
+;    void jd(int b, int *A, int *B) {
+;      for (int i = 0; i < 1024; i++) {
+;        if (b)
+;          A[i] = B[5];
+;        else
+;          B[i] = A[7];
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32 %b, i32* %A, i32* %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tobool = icmp eq i32 %b, 0
+  br i1 %tobool, label %if.else, label %if.then
+
+if.then:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 5
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp, i32* %arrayidx1, align 4
+  br label %if.end
+
+if.else:                                          ; preds = %for.body
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 7
+  %tmp1 = load i32, i32* %arrayidx2, align 4
+  %arrayidx4 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  store i32 %tmp1, i32* %arrayidx4, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/aliasing_dead_access.ll b/final/test/ScopInfo/aliasing_dead_access.ll
new file mode 100644
index 0000000..4c467d9
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_dead_access.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s
+;
+; Check that we do not create a SCoP if there is no statement executed.
+;
+; CHECK-NOT: Context
+;
+;    void jd(int *A, int *B) {
+;      for (int i = 0; i < 1024; i++)
+;        for (int j = i; j < 0; j++)
+;          A[i] = B[i];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc6, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc6 ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end8
+
+for.body:                                         ; preds = %for.cond
+  %tmp = trunc i64 %indvars.iv to i32
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ %tmp, %for.body ], [ %inc, %for.inc ]
+  %cmp2 = icmp slt i32 %j.0, 0
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp1, i32* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc6
+
+for.inc6:                                         ; preds = %for.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end8:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/aliasing_many_arrays_to_compare.ll b/final/test/ScopInfo/aliasing_many_arrays_to_compare.ll
new file mode 100644
index 0000000..7168a6a
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_many_arrays_to_compare.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN:                < %s | FileCheck %s --check-prefix=FOUND
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN:                -polly-rtc-max-arrays-per-group=3 < %s | FileCheck %s \
+; RUN:                --check-prefix=IGNORED
+;
+; FOUND: Function: foo
+; IGNORED-NOT: Function: foo
+;
+;    void foo(float *A, float *B, float *C, float *D) {
+;      for (long i = 0; i < 100; i++) {
+;        A[i]++;
+;        B[i]++;
+;        C[i]++;
+;        D[i]++;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A, float* %B, float* %C, float* %D) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc7, %for.inc ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp = load float, float* %arrayidx, align 4
+  %inc = fadd float %tmp, 1.000000e+00
+  store float %inc, float* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds float, float* %B, i64 %i.0
+  %tmp1 = load float, float* %arrayidx1, align 4
+  %inc2 = fadd float %tmp1, 1.000000e+00
+  store float %inc2, float* %arrayidx1, align 4
+  %arrayidx3 = getelementptr inbounds float, float* %C, i64 %i.0
+  %tmp2 = load float, float* %arrayidx3, align 4
+  %inc4 = fadd float %tmp2, 1.000000e+00
+  store float %inc4, float* %arrayidx3, align 4
+  %arrayidx5 = getelementptr inbounds float, float* %D, i64 %i.0
+  %tmp3 = load float, float* %arrayidx5, align 4
+  %inc6 = fadd float %tmp3, 1.000000e+00
+  store float %inc6, float* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc7 = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/aliasing_many_parameters_not_all_involved.ll b/final/test/ScopInfo/aliasing_many_parameters_not_all_involved.ll
new file mode 100644
index 0000000..ccf0b85
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_many_parameters_not_all_involved.ll
@@ -0,0 +1,90 @@
+; RUN: opt %loadPolly -polly-scops -polly-rtc-max-parameters=8 -analyze < %s | FileCheck %s --check-prefix=MAX8
+; RUN: opt %loadPolly -polly-scops -polly-rtc-max-parameters=7 -analyze < %s | FileCheck %s --check-prefix=MAX7
+;
+; Check that we allow this SCoP even though it has 10 parameters involved in posisbly aliasing accesses.
+; However, only 7 are involved in accesses through B, 8 through C and none in accesses through A.
+;
+; MAX8-LABEL:  Function: jd
+; MAX8-NEXT: Region: %for.cond---%for.end
+
+; MAX7:  Invalid Scop!
+;
+;    void jd(int *A, int *B, int *C, long p1, long p2, long p3, long p4, long p5,
+;            long p6, long p7, long p8, long p9, long p10) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = B[p1] - B[p2] + B[-p3] - B[p4] + B[p5] - B[-p6] + B[p7] - C[p3] +
+;               C[-p4] - C[p5] + C[p6] - C[-p7] + C[p8] - C[p9] + C[-p10];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %B, i32* %C, i64 %p1, i64 %p2, i64 %p3, i64 %p4, i64 %p5, i64 %p6, i64 %p7, i64 %p8, i64 %p9, i64 %p10) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %p1
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds i32, i32* %B, i64 %p2
+  %tmp1 = load i32, i32* %arrayidx1, align 4
+  %sub = sub nsw i32 %tmp, %tmp1
+  %sub2 = sub nsw i64 0, %p3
+  %arrayidx3 = getelementptr inbounds i32, i32* %B, i64 %sub2
+  %tmp2 = load i32, i32* %arrayidx3, align 4
+  %add = add nsw i32 %sub, %tmp2
+  %arrayidx4 = getelementptr inbounds i32, i32* %B, i64 %p4
+  %tmp3 = load i32, i32* %arrayidx4, align 4
+  %sub5 = sub nsw i32 %add, %tmp3
+  %arrayidx6 = getelementptr inbounds i32, i32* %B, i64 %p5
+  %tmp4 = load i32, i32* %arrayidx6, align 4
+  %add7 = add nsw i32 %sub5, %tmp4
+  %sub8 = sub nsw i64 0, %p6
+  %arrayidx9 = getelementptr inbounds i32, i32* %B, i64 %sub8
+  %tmp5 = load i32, i32* %arrayidx9, align 4
+  %sub10 = sub nsw i32 %add7, %tmp5
+  %arrayidx11 = getelementptr inbounds i32, i32* %B, i64 %p7
+  %tmp6 = load i32, i32* %arrayidx11, align 4
+  %add12 = add nsw i32 %sub10, %tmp6
+  %arrayidx13 = getelementptr inbounds i32, i32* %C, i64 %p3
+  %tmp7 = load i32, i32* %arrayidx13, align 4
+  %sub14 = sub nsw i32 %add12, %tmp7
+  %sub15 = sub nsw i64 0, %p4
+  %arrayidx16 = getelementptr inbounds i32, i32* %C, i64 %sub15
+  %tmp8 = load i32, i32* %arrayidx16, align 4
+  %add17 = add nsw i32 %sub14, %tmp8
+  %arrayidx18 = getelementptr inbounds i32, i32* %C, i64 %p5
+  %tmp9 = load i32, i32* %arrayidx18, align 4
+  %sub19 = sub nsw i32 %add17, %tmp9
+  %arrayidx20 = getelementptr inbounds i32, i32* %C, i64 %p6
+  %tmp10 = load i32, i32* %arrayidx20, align 4
+  %add21 = add nsw i32 %sub19, %tmp10
+  %sub22 = sub nsw i64 0, %p7
+  %arrayidx23 = getelementptr inbounds i32, i32* %C, i64 %sub22
+  %tmp11 = load i32, i32* %arrayidx23, align 4
+  %sub24 = sub nsw i32 %add21, %tmp11
+  %arrayidx25 = getelementptr inbounds i32, i32* %C, i64 %p8
+  %tmp12 = load i32, i32* %arrayidx25, align 4
+  %add26 = add nsw i32 %sub24, %tmp12
+  %arrayidx27 = getelementptr inbounds i32, i32* %C, i64 %p9
+  %tmp13 = load i32, i32* %arrayidx27, align 4
+  %sub28 = sub nsw i32 %add26, %tmp13
+  %sub29 = sub nsw i64 0, %p10
+  %arrayidx30 = getelementptr inbounds i32, i32* %C, i64 %sub29
+  %tmp14 = load i32, i32* %arrayidx30, align 4
+  %add31 = add nsw i32 %sub28, %tmp14
+  %arrayidx32 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %add31, i32* %arrayidx32, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/aliasing_many_read_only_acesses.ll b/final/test/ScopInfo/aliasing_many_read_only_acesses.ll
new file mode 100644
index 0000000..906c23e
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_many_read_only_acesses.ll
@@ -0,0 +1,224 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Assumed Context:
+; CHECK-NEXT: { : }
+;
+; Make sure the large number of read-only accesses does not cause make us
+; invalidate the scop.
+;
+;    void many_read_only_accesses(float A[], float B[]) {
+;      for (long i = 0; i < 1024; i++) {
+;        for (long j = 0; j < 1024; j++) {
+;          A[j] += B[i] + B[i + 1] + B[i + 2] + B[i + 3] + B[i + 4] + B[i + 5] +
+;                  B[i + 6] + B[i + 7] + B[i + 8] + B[i + 9] + B[i + 0] + B[i + 11] +
+;                  B[i + 12] + B[i + 13] + B[i + 14] + B[i + 15] + B[i + 16] +
+;                  B[i + 17] + B[i + 18] + B[i + 19] + B[i + 10] + B[i + 21] +
+;                  B[i + 22] + B[i + 23] + B[i + 24] + B[i + 25] + B[i + 26] +
+;                  B[i + 27] + B[i + 28] + B[i + 29] + B[i + 20] + B[i + 31] +
+;                  B[i + 32] + B[i + 33] + B[i + 34] + B[i + 35] + B[i + 36] +
+;                  B[i + 37] + B[i + 38] + B[i + 39] + B[i + 30];
+;        }
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @many_read_only_accesses(float* %A, float* %B) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb172, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp173, %bb172 ]
+  %exitcond1 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond1, label %bb3, label %bb174
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb169, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp170, %bb169 ]
+  %exitcond = icmp ne i64 %j.0, 1024
+  br i1 %exitcond, label %bb5, label %bb171
+
+bb5:                                              ; preds = %bb4
+  %tmp = getelementptr inbounds float, float* %B, i64 %i.0
+  %tmp6 = load float, float* %tmp, align 4
+  %tmp7 = add nuw nsw i64 %i.0, 1
+  %tmp8 = getelementptr inbounds float, float* %B, i64 %tmp7
+  %tmp9 = load float, float* %tmp8, align 4
+  %tmp10 = fadd float %tmp6, %tmp9
+  %tmp11 = add nuw nsw i64 %i.0, 2
+  %tmp12 = getelementptr inbounds float, float* %B, i64 %tmp11
+  %tmp13 = load float, float* %tmp12, align 4
+  %tmp14 = fadd float %tmp10, %tmp13
+  %tmp15 = add nuw nsw i64 %i.0, 3
+  %tmp16 = getelementptr inbounds float, float* %B, i64 %tmp15
+  %tmp17 = load float, float* %tmp16, align 4
+  %tmp18 = fadd float %tmp14, %tmp17
+  %tmp19 = add nuw nsw i64 %i.0, 4
+  %tmp20 = getelementptr inbounds float, float* %B, i64 %tmp19
+  %tmp21 = load float, float* %tmp20, align 4
+  %tmp22 = fadd float %tmp18, %tmp21
+  %tmp23 = add nuw nsw i64 %i.0, 5
+  %tmp24 = getelementptr inbounds float, float* %B, i64 %tmp23
+  %tmp25 = load float, float* %tmp24, align 4
+  %tmp26 = fadd float %tmp22, %tmp25
+  %tmp27 = add nuw nsw i64 %i.0, 6
+  %tmp28 = getelementptr inbounds float, float* %B, i64 %tmp27
+  %tmp29 = load float, float* %tmp28, align 4
+  %tmp30 = fadd float %tmp26, %tmp29
+  %tmp31 = add nuw nsw i64 %i.0, 7
+  %tmp32 = getelementptr inbounds float, float* %B, i64 %tmp31
+  %tmp33 = load float, float* %tmp32, align 4
+  %tmp34 = fadd float %tmp30, %tmp33
+  %tmp35 = add nuw nsw i64 %i.0, 8
+  %tmp36 = getelementptr inbounds float, float* %B, i64 %tmp35
+  %tmp37 = load float, float* %tmp36, align 4
+  %tmp38 = fadd float %tmp34, %tmp37
+  %tmp39 = add nuw nsw i64 %i.0, 9
+  %tmp40 = getelementptr inbounds float, float* %B, i64 %tmp39
+  %tmp41 = load float, float* %tmp40, align 4
+  %tmp42 = fadd float %tmp38, %tmp41
+  %tmp43 = getelementptr inbounds float, float* %B, i64 %i.0
+  %tmp44 = load float, float* %tmp43, align 4
+  %tmp45 = fadd float %tmp42, %tmp44
+  %tmp46 = add nuw nsw i64 %i.0, 11
+  %tmp47 = getelementptr inbounds float, float* %B, i64 %tmp46
+  %tmp48 = load float, float* %tmp47, align 4
+  %tmp49 = fadd float %tmp45, %tmp48
+  %tmp50 = add nuw nsw i64 %i.0, 12
+  %tmp51 = getelementptr inbounds float, float* %B, i64 %tmp50
+  %tmp52 = load float, float* %tmp51, align 4
+  %tmp53 = fadd float %tmp49, %tmp52
+  %tmp54 = add nuw nsw i64 %i.0, 13
+  %tmp55 = getelementptr inbounds float, float* %B, i64 %tmp54
+  %tmp56 = load float, float* %tmp55, align 4
+  %tmp57 = fadd float %tmp53, %tmp56
+  %tmp58 = add nuw nsw i64 %i.0, 14
+  %tmp59 = getelementptr inbounds float, float* %B, i64 %tmp58
+  %tmp60 = load float, float* %tmp59, align 4
+  %tmp61 = fadd float %tmp57, %tmp60
+  %tmp62 = add nuw nsw i64 %i.0, 15
+  %tmp63 = getelementptr inbounds float, float* %B, i64 %tmp62
+  %tmp64 = load float, float* %tmp63, align 4
+  %tmp65 = fadd float %tmp61, %tmp64
+  %tmp66 = add nuw nsw i64 %i.0, 16
+  %tmp67 = getelementptr inbounds float, float* %B, i64 %tmp66
+  %tmp68 = load float, float* %tmp67, align 4
+  %tmp69 = fadd float %tmp65, %tmp68
+  %tmp70 = add nuw nsw i64 %i.0, 17
+  %tmp71 = getelementptr inbounds float, float* %B, i64 %tmp70
+  %tmp72 = load float, float* %tmp71, align 4
+  %tmp73 = fadd float %tmp69, %tmp72
+  %tmp74 = add nuw nsw i64 %i.0, 18
+  %tmp75 = getelementptr inbounds float, float* %B, i64 %tmp74
+  %tmp76 = load float, float* %tmp75, align 4
+  %tmp77 = fadd float %tmp73, %tmp76
+  %tmp78 = add nuw nsw i64 %i.0, 19
+  %tmp79 = getelementptr inbounds float, float* %B, i64 %tmp78
+  %tmp80 = load float, float* %tmp79, align 4
+  %tmp81 = fadd float %tmp77, %tmp80
+  %tmp82 = add nuw nsw i64 %i.0, 10
+  %tmp83 = getelementptr inbounds float, float* %B, i64 %tmp82
+  %tmp84 = load float, float* %tmp83, align 4
+  %tmp85 = fadd float %tmp81, %tmp84
+  %tmp86 = add nuw nsw i64 %i.0, 21
+  %tmp87 = getelementptr inbounds float, float* %B, i64 %tmp86
+  %tmp88 = load float, float* %tmp87, align 4
+  %tmp89 = fadd float %tmp85, %tmp88
+  %tmp90 = add nuw nsw i64 %i.0, 22
+  %tmp91 = getelementptr inbounds float, float* %B, i64 %tmp90
+  %tmp92 = load float, float* %tmp91, align 4
+  %tmp93 = fadd float %tmp89, %tmp92
+  %tmp94 = add nuw nsw i64 %i.0, 23
+  %tmp95 = getelementptr inbounds float, float* %B, i64 %tmp94
+  %tmp96 = load float, float* %tmp95, align 4
+  %tmp97 = fadd float %tmp93, %tmp96
+  %tmp98 = add nuw nsw i64 %i.0, 24
+  %tmp99 = getelementptr inbounds float, float* %B, i64 %tmp98
+  %tmp100 = load float, float* %tmp99, align 4
+  %tmp101 = fadd float %tmp97, %tmp100
+  %tmp102 = add nuw nsw i64 %i.0, 25
+  %tmp103 = getelementptr inbounds float, float* %B, i64 %tmp102
+  %tmp104 = load float, float* %tmp103, align 4
+  %tmp105 = fadd float %tmp101, %tmp104
+  %tmp106 = add nuw nsw i64 %i.0, 26
+  %tmp107 = getelementptr inbounds float, float* %B, i64 %tmp106
+  %tmp108 = load float, float* %tmp107, align 4
+  %tmp109 = fadd float %tmp105, %tmp108
+  %tmp110 = add nuw nsw i64 %i.0, 27
+  %tmp111 = getelementptr inbounds float, float* %B, i64 %tmp110
+  %tmp112 = load float, float* %tmp111, align 4
+  %tmp113 = fadd float %tmp109, %tmp112
+  %tmp114 = add nuw nsw i64 %i.0, 28
+  %tmp115 = getelementptr inbounds float, float* %B, i64 %tmp114
+  %tmp116 = load float, float* %tmp115, align 4
+  %tmp117 = fadd float %tmp113, %tmp116
+  %tmp118 = add nuw nsw i64 %i.0, 29
+  %tmp119 = getelementptr inbounds float, float* %B, i64 %tmp118
+  %tmp120 = load float, float* %tmp119, align 4
+  %tmp121 = fadd float %tmp117, %tmp120
+  %tmp122 = add nuw nsw i64 %i.0, 20
+  %tmp123 = getelementptr inbounds float, float* %B, i64 %tmp122
+  %tmp124 = load float, float* %tmp123, align 4
+  %tmp125 = fadd float %tmp121, %tmp124
+  %tmp126 = add nuw nsw i64 %i.0, 31
+  %tmp127 = getelementptr inbounds float, float* %B, i64 %tmp126
+  %tmp128 = load float, float* %tmp127, align 4
+  %tmp129 = fadd float %tmp125, %tmp128
+  %tmp130 = add nuw nsw i64 %i.0, 32
+  %tmp131 = getelementptr inbounds float, float* %B, i64 %tmp130
+  %tmp132 = load float, float* %tmp131, align 4
+  %tmp133 = fadd float %tmp129, %tmp132
+  %tmp134 = add nuw nsw i64 %i.0, 33
+  %tmp135 = getelementptr inbounds float, float* %B, i64 %tmp134
+  %tmp136 = load float, float* %tmp135, align 4
+  %tmp137 = fadd float %tmp133, %tmp136
+  %tmp138 = add nuw nsw i64 %i.0, 34
+  %tmp139 = getelementptr inbounds float, float* %B, i64 %tmp138
+  %tmp140 = load float, float* %tmp139, align 4
+  %tmp141 = fadd float %tmp137, %tmp140
+  %tmp142 = add nuw nsw i64 %i.0, 35
+  %tmp143 = getelementptr inbounds float, float* %B, i64 %tmp142
+  %tmp144 = load float, float* %tmp143, align 4
+  %tmp145 = fadd float %tmp141, %tmp144
+  %tmp146 = add nuw nsw i64 %i.0, 36
+  %tmp147 = getelementptr inbounds float, float* %B, i64 %tmp146
+  %tmp148 = load float, float* %tmp147, align 4
+  %tmp149 = fadd float %tmp145, %tmp148
+  %tmp150 = add nuw nsw i64 %i.0, 37
+  %tmp151 = getelementptr inbounds float, float* %B, i64 %tmp150
+  %tmp152 = load float, float* %tmp151, align 4
+  %tmp153 = fadd float %tmp149, %tmp152
+  %tmp154 = add nuw nsw i64 %i.0, 38
+  %tmp155 = getelementptr inbounds float, float* %B, i64 %tmp154
+  %tmp156 = load float, float* %tmp155, align 4
+  %tmp157 = fadd float %tmp153, %tmp156
+  %tmp158 = add nuw nsw i64 %i.0, 39
+  %tmp159 = getelementptr inbounds float, float* %B, i64 %tmp158
+  %tmp160 = load float, float* %tmp159, align 4
+  %tmp161 = fadd float %tmp157, %tmp160
+  %tmp162 = add nuw nsw i64 %i.0, 30
+  %tmp163 = getelementptr inbounds float, float* %B, i64 %tmp162
+  %tmp164 = load float, float* %tmp163, align 4
+  %tmp165 = fadd float %tmp161, %tmp164
+  %tmp166 = getelementptr inbounds float, float* %A, i64 %j.0
+  %tmp167 = load float, float* %tmp166, align 4
+  %tmp168 = fadd float %tmp167, %tmp165
+  store float %tmp168, float* %tmp166, align 4
+  br label %bb169
+
+bb169:                                            ; preds = %bb5
+  %tmp170 = add nuw nsw i64 %j.0, 1
+  br label %bb4
+
+bb171:                                            ; preds = %bb4
+  br label %bb172
+
+bb172:                                            ; preds = %bb171
+  %tmp173 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb174:                                            ; preds = %bb2
+  ret void
+}
diff --git a/final/test/ScopInfo/aliasing_multiple_alias_groups.ll b/final/test/ScopInfo/aliasing_multiple_alias_groups.ll
new file mode 100644
index 0000000..00540d8
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_multiple_alias_groups.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-scops -analyze          < %s | FileCheck %s --check-prefix=NOAA
+; RUN: opt %loadPolly -polly-scops -analyze -tbaa    < %s | FileCheck %s --check-prefix=TBAA
+;
+;    void jd(int *Int0, int *Int1, float *Float0, float *Float1) {
+;      for (int i = 0; i < 1024; i++) {
+;        Int0[i] = Int1[i];
+;        Float0[i] = Float1[i];
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* nocapture %Int0, i32* nocapture readonly %Int1, float* nocapture %Float0, float* nocapture readonly %Float1) {
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %for.body, %entry
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds i32, i32* %Int1, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4, !tbaa !0
+  %arrayidx2 = getelementptr inbounds i32, i32* %Int0, i64 %indvars.iv
+  store i32 %tmp, i32* %arrayidx2, align 4, !tbaa !0
+  %arrayidx4 = getelementptr inbounds float, float* %Float1, i64 %indvars.iv
+  %tmp1 = load float, float* %arrayidx4, align 4, !tbaa !4
+  %arrayidx6 = getelementptr inbounds float, float* %Float0, i64 %indvars.iv
+  store float %tmp1, float* %arrayidx6, align 4, !tbaa !4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 1024
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.body
+  ret void
+}
+
+!0 = !{!1, !1, i64 0}
+!1 = !{!"int", !2, i64 0}
+!2 = !{!"omnipotent char", !3, i64 0}
+!3 = !{!"Simple C/C++ TBAA"}
+!4 = !{!5, !5, i64 0}
+!5 = !{!"float", !2, i64 0}
+
+; NOAA: Alias Groups (2):
+; NOAA-NEXT: {{\[\[}}
+; NOAA-DAG:      <{ MemRef_Int0[(0)] }, { MemRef_Int0[(1024)] }>
+; NOAA-DAG:      <{ MemRef_{{(Int|Float)}}1[(0)] }, { MemRef_{{(Int|Float)}}1[(1024)] }>
+; NOAA-DAG:      <{ MemRef_Float0[(0)] }, { MemRef_Float0[(1024)] }>
+; NOAA:      {{\]\]}}
+; NOAA-NEXT: {{\[\[}}
+; NOAA-DAG:      <{ MemRef_Int0[(0)] }, { MemRef_Int0[(1024)] }>
+; NOAA-DAG:      <{ MemRef_Float0[(0)] }, { MemRef_Float0[(1024)] }>
+; NOAA-DAG:      <{ MemRef_{{(Int|Float)}}1[(0)] }, { MemRef_{{(Int|Float)}}1[(1024)] }>
+; NOAA:      {{\]\]}}
+
+
+; TBAA: Alias Groups (2):
+; TBAA-NEXT: {{\[\[}}
+; TBAA-DAG:      <{ MemRef_Int0[(0)] }, { MemRef_Int0[(1024)] }>
+; TBAA-DAG:      <{ MemRef_Int1[(0)] }, { MemRef_Int1[(1024)] }>
+; TBAA:      {{\]\]}}
+; TBAA-NEXT: {{\[\[}}
+; TBAA-DAG:      <{ MemRef_Float0[(0)] }, { MemRef_Float0[(1024)] }>
+; TBAA-DAG:      <{ MemRef_Float1[(0)] }, { MemRef_Float1[(1024)] }>
+; TBBA:      {{\]\]}}
diff --git a/final/test/ScopInfo/aliasing_with_non_affine_access.ll b/final/test/ScopInfo/aliasing_with_non_affine_access.ll
new file mode 100644
index 0000000..3bae83f
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_with_non_affine_access.ll
@@ -0,0 +1,97 @@
+; RUN: opt %loadPolly -analyze -polly-ast -polly-process-unprofitable -polly-allow-nonaffine < %s | FileCheck %s
+;
+; @test1
+; Make sure we generate the correct aliasing check for a fixed-size memset operation.
+; CHECK: if (1 && (&MemRef_tmp0[15] <= &MemRef_tmp1[0] || &MemRef_tmp1[32] <= &MemRef_tmp0[14]))
+;
+; @test2
+; Make sure we generate the correct aliasing check for a variable-size memset operation.
+; CHECK: if (1 && (&MemRef_tmp0[15] <= &MemRef_tmp1[0] || &MemRef_tmp1[n] <= &MemRef_tmp0[14]))
+;
+; @test3
+; We can't do anything interesting with a non-affine memset; just make sure it doesn't crash.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.info = type { i32, %struct.ctr*, i32, %struct.ord*, %struct.ctr*, i32, i8*, i32, i32, double }
+%struct.ctr = type { i32, i8, i8, i32 }
+%struct.ord = type { i32, i8 }
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) #0
+
+define void @test1(%struct.info** %ppIdxInfo) {
+entry:
+  %tmp0 = load %struct.info*, %struct.info** %ppIdxInfo, align 8
+  br label %if.end125
+
+if.end125:                                        ; preds = %entry
+  %tmp1 = load %struct.ctr*, %struct.ctr** undef, align 8
+  br label %for.end143
+
+for.end143:                                       ; preds = %if.end125
+  %tmp2 = bitcast %struct.ctr* %tmp1 to i8*
+  tail call void @llvm.memset.p0i8.i64(i8* %tmp2, i8 0, i64 32, i32 4, i1 false)
+  %needToFreeIdxStr = getelementptr inbounds %struct.info, %struct.info* %tmp0, i64 0, i32 7
+  %tmp3 = load i32, i32* %needToFreeIdxStr, align 8
+  br i1 false, label %if.end149, label %if.then148
+
+if.then148:                                       ; preds = %for.end143
+  br label %if.end149
+
+if.end149:                                        ; preds = %if.then148, %for.end143
+  ret void
+}
+
+define void @test2(%struct.info** %ppIdxInfo, i64 %n) {
+entry:
+  %tmp0 = load %struct.info*, %struct.info** %ppIdxInfo, align 8
+  br label %if.end125
+
+if.end125:                                        ; preds = %entry
+  %tmp1 = load %struct.ctr*, %struct.ctr** undef, align 8
+  br label %for.end143
+
+for.end143:                                       ; preds = %if.end125
+  %tmp2 = bitcast %struct.ctr* %tmp1 to i8*
+  tail call void @llvm.memset.p0i8.i64(i8* %tmp2, i8 0, i64 %n, i32 4, i1 false)
+  %needToFreeIdxStr = getelementptr inbounds %struct.info, %struct.info* %tmp0, i64 0, i32 7
+  %tmp3 = load i32, i32* %needToFreeIdxStr, align 8
+  br i1 false, label %if.end149, label %if.then148
+
+if.then148:                                       ; preds = %for.end143
+  br label %if.end149
+
+if.end149:                                        ; preds = %if.then148, %for.end143
+  ret void
+}
+
+define i32 @test3(i32* %x, i32 %n) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %conv = sext i32 %n to i64
+  %cmp8 = icmp sgt i32 %n, 0
+  br i1 %cmp8, label %for.body.lr.ph, label %for.cond.cleanup
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  %tmp0 = bitcast i32* %x to i8*
+  br label %for.body
+
+for.cond.cleanup:                                 ; preds = %for.body, %entry.split
+  ret i32 0
+
+for.body:                                         ; preds = %for.body, %for.body.lr.ph
+  %i.09 = phi i64 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]
+  %mul = mul nsw i64 %i.09, %i.09
+  tail call void @llvm.memset.p0i8.i64(i8* %tmp0, i8 0, i64 %mul, i32 4, i1 false)
+  %add = add nuw nsw i64 %i.09, 1000
+  %arrayidx = getelementptr inbounds i32, i32* %x, i64 %add
+  store i32 5, i32* %arrayidx, align 4
+  %inc = add nuw nsw i64 %i.09, 1
+  %exitcond = icmp eq i64 %inc, %conv
+  br i1 %exitcond, label %for.cond.cleanup, label %for.body
+}
+
+attributes #0 = { argmemonly nounwind }
diff --git a/final/test/ScopInfo/allow-all-parameters-dereferencable.ll b/final/test/ScopInfo/allow-all-parameters-dereferencable.ll
new file mode 100644
index 0000000..426186e
--- /dev/null
+++ b/final/test/ScopInfo/allow-all-parameters-dereferencable.ll
@@ -0,0 +1,98 @@
+; RUN: opt %loadPolly -analyze -polly-invariant-load-hoisting \
+; RUN: -polly-allow-dereference-of-all-function-parameters \
+; RUN: -polly-scops < %s | FileCheck %s --check-prefix=SCOP
+
+; RUN: opt %loadPolly -S -polly-invariant-load-hoisting \
+; RUN: -polly-codegen < %s | FileCheck %s --check-prefix=CODE-RTC
+
+
+; RUN: opt %loadPolly -S -polly-invariant-load-hoisting \
+; RUN: -polly-allow-dereference-of-all-function-parameters \
+; RUN: -polly-codegen < %s | FileCheck %s --check-prefix=CODE
+
+; SCOP:      Function: hoge
+; SCOP-NEXT: Region: %bb15---%bb37
+; SCOP-NEXT: Max Loop Depth:  2
+; SCOP-NEXT: Invariant Accesses: {
+; SCOP-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:             [tmp, tmp17, tmp28] -> { Stmt_bb29[i0] -> MemRef_arg1[0] };
+; SCOP-NEXT:         Execution Context: [tmp, tmp17, tmp28] -> {  :  }
+; SCOP-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:             [tmp, tmp17, tmp28] -> { Stmt_bb27[] -> MemRef_arg[0] };
+; SCOP-NEXT:         Execution Context: [tmp, tmp17, tmp28] -> {  :  }
+; SCOP-NEXT: }
+
+; Check that without the option `-pollt-allow-dereference-of-all-function-parameters`
+; we do generate the runtime check.
+; CODE-RTC: polly.preload.cond:                               ; preds = %polly.preload.begin
+; CODE-RTC-NEXT: br i1 %{{[a-zA-Z0-9]*}}, label %polly.preload.exec, label %polly.preload.merge
+
+; Check that we don't generate a runtime check because we treat all
+; parameters as dereferencable.
+; CODE-NOT: polly.preload.cond:                               ; preds = %polly.preload.begin
+; CODE-NOT: br i1 %{{r1:[a-zA-Z0-9]*}}, label %polly.preload.exec, label %polly.preload.merge
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+@global = external global i32
+
+; Function Attrs: nounwind uwtable
+define void @hoge(i32* noalias %arg, i32* noalias %arg1, [0 x double]* noalias %arg2, float* %A) #0 {
+bb:
+  %tmp = load i32, i32* @global, align 4
+  %tmp3 = icmp sgt i32 %tmp, 1
+  br label %bb14
+
+bb14:                                             ; preds = %bb
+  br label %bb15
+
+bb15:                                             ; preds = %bb14
+  br i1 %tmp3, label %bb16, label %bb27
+
+bb16:                                             ; preds = %bb15
+  %tmp17 = load i32, i32* %arg1, align 4
+  br label %bb18
+
+bb18:                                             ; preds = %bb18, %bb16
+  %tmp19 = phi i32 [ %tmp25, %bb18 ], [ 1, %bb16 ]
+  %tmp20 = sext i32 %tmp19 to i64
+  %tmp21 = add nsw i64 %tmp20, -1
+  %tmp22 = getelementptr [0 x double], [0 x double]* %arg2, i64 0, i64 %tmp21
+  %tmp23 = bitcast double* %tmp22 to i64*
+  store i64 undef, i64* %tmp23, align 8
+  %tmp24 = icmp eq i32 %tmp19, %tmp17
+  %tmp25 = add i32 %tmp19, 1
+  br i1 %tmp24, label %bb26, label %bb18
+
+bb26:                                             ; preds = %bb18
+  br label %bb27
+
+bb27:                                             ; preds = %bb26, %bb15
+  %tmp28 = load i32, i32* %arg, align 4
+  store float 42.0, float* %A
+  br label %bb29
+
+bb29:                                             ; preds = %bb35, %bb27
+  %tmp30 = load i32, i32* %arg1, align 4
+  store float 42.0, float* %A
+  br label %bb31
+
+bb31:                                             ; preds = %bb31, %bb29
+  %tmp32 = phi i32 [ undef, %bb31 ], [ 1, %bb29 ]
+  store float 42.0, float* %A
+  %tmp33 = icmp eq i32 %tmp32, %tmp30
+  br i1 %tmp33, label %bb34, label %bb31
+
+bb34:                                             ; preds = %bb31
+  br label %bb35
+
+bb35:                                             ; preds = %bb34
+  %tmp36 = icmp eq i32 0, %tmp28
+  br i1 %tmp36, label %bb37, label %bb29
+
+bb37:                                             ; preds = %bb35
+  ret void
+}
+
+attributes #0 = { nounwind uwtable }
diff --git a/final/test/ScopInfo/assume_gep_bounds.ll b/final/test/ScopInfo/assume_gep_bounds.ll
new file mode 100644
index 0000000..f1bad85
--- /dev/null
+++ b/final/test/ScopInfo/assume_gep_bounds.ll
@@ -0,0 +1,81 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-function-scops -analyze < %s | FileCheck %s
+
+;    void foo(float A[][20][30], long n, long m, long p) {
+;      for (long i = 0; i < n; i++)
+;        for (long j = 0; j < m; j++)
+;          for (long k = 0; k < p; k++)
+;            A[i][j][k] = i + j + k;
+;    }
+
+; For the above code we want to assume that all memory accesses are within the
+; bounds of the array A. In C (and LLVM-IR) this is not required, such that out
+; of bounds accesses are valid. However, as such accesses are uncommon, cause
+; complicated dependence pattern and as a result make dependence analysis more
+; costly and may prevent or hinder useful program transformations, we assume
+; absence of out-of-bound accesses. To do so we derive the set of parameter
+; values for which our assumption holds.
+
+; CHECK: Assumed Context
+; CHECK-NEXT: [n, m, p] -> {  :
+; CHECK-DAG:                    p <= 30
+; CHECK-DAG:                     and
+; CHECK-DAG:                    m <= 20
+; CHECK:                   }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo([20 x [30 x float]]* %A, i64 %n, i64 %m, i64 %p) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc13, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc14, %for.inc13 ]
+  %cmp = icmp slt i64 %i.0, %n
+  br i1 %cmp, label %for.body, label %for.end15
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc10, %for.body
+  %j.0 = phi i64 [ 0, %for.body ], [ %inc11, %for.inc10 ]
+  %cmp2 = icmp slt i64 %j.0, %m
+  br i1 %cmp2, label %for.body3, label %for.end12
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc, %for.body3
+  %k.0 = phi i64 [ 0, %for.body3 ], [ %inc, %for.inc ]
+  %cmp5 = icmp slt i64 %k.0, %p
+  br i1 %cmp5, label %for.body6, label %for.end
+
+for.body6:                                        ; preds = %for.cond4
+  %add = add nsw i64 %i.0, %j.0
+  %add7 = add nsw i64 %add, %k.0
+  %conv = sitofp i64 %add7 to float
+  %arrayidx9 = getelementptr inbounds [20 x [30 x float]], [20 x [30 x float]]* %A, i64 %i.0, i64 %j.0, i64 %k.0
+  store float %conv, float* %arrayidx9, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body6
+  %inc = add nsw i64 %k.0, 1
+  br label %for.cond4
+
+for.end:                                          ; preds = %for.cond4
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.end
+  %inc11 = add nsw i64 %j.0, 1
+  br label %for.cond1
+
+for.end12:                                        ; preds = %for.cond1
+  br label %for.inc13
+
+for.inc13:                                        ; preds = %for.end12
+  %inc14 = add nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end15:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/assume_gep_bounds_2.ll b/final/test/ScopInfo/assume_gep_bounds_2.ll
new file mode 100644
index 0000000..d364211
--- /dev/null
+++ b/final/test/ScopInfo/assume_gep_bounds_2.ll
@@ -0,0 +1,95 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze < %s \
+; RUN:  -polly-precise-inbounds | FileCheck %s
+;
+;    void foo(float A[restrict][20], float B[restrict][20], long n, long m,
+;             long p) {
+;      for (long i = 0; i < n; i++)
+;        for (long j = 0; j < m; j++)
+;          A[i][j] = i + j;
+;      for (long i = 0; i < m; i++)
+;        for (long j = 0; j < p; j++)
+;          B[i][j] = i + j;
+;    }
+
+; This code is within bounds either if m and p are smaller than the array sizes,
+; but also if only p is smaller than the size of the second B dimension and n
+; is such that the first loop is never executed and consequently A is never
+; accessed. In this case the value of m does not matter.
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [n, m, p] -> {  : p <= 20 and (n <= 0 or (n > 0 and m <= 20)) }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo([20 x float]* noalias %A, [20 x float]* noalias %B, i64 %n, i64 %m, i64 %p) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc5, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc6, %for.inc5 ]
+  %cmp = icmp slt i64 %i.0, %n
+  br i1 %cmp, label %for.body, label %for.end7
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i64 [ 0, %for.body ], [ %inc, %for.inc ]
+  %cmp2 = icmp slt i64 %j.0, %m
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %add = add nsw i64 %i.0, %j.0
+  %conv = sitofp i64 %add to float
+  %arrayidx4 = getelementptr inbounds [20 x float], [20 x float]* %A, i64 %i.0, i64 %j.0
+  store float %conv, float* %arrayidx4, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i64 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc5
+
+for.inc5:                                         ; preds = %for.end
+  %inc6 = add nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end7:                                         ; preds = %for.cond
+  br label %for.cond9
+
+for.cond9:                                        ; preds = %for.inc25, %for.end7
+  %i8.0 = phi i64 [ 0, %for.end7 ], [ %inc26, %for.inc25 ]
+  %cmp10 = icmp slt i64 %i8.0, %m
+  br i1 %cmp10, label %for.body12, label %for.end27
+
+for.body12:                                       ; preds = %for.cond9
+  br label %for.cond14
+
+for.cond14:                                       ; preds = %for.inc22, %for.body12
+  %j13.0 = phi i64 [ 0, %for.body12 ], [ %inc23, %for.inc22 ]
+  %cmp15 = icmp slt i64 %j13.0, %p
+  br i1 %cmp15, label %for.body17, label %for.end24
+
+for.body17:                                       ; preds = %for.cond14
+  %add18 = add nsw i64 %i8.0, %j13.0
+  %conv19 = sitofp i64 %add18 to float
+  %arrayidx21 = getelementptr inbounds [20 x float], [20 x float]* %B, i64 %i8.0, i64 %j13.0
+  store float %conv19, float* %arrayidx21, align 4
+  br label %for.inc22
+
+for.inc22:                                        ; preds = %for.body17
+  %inc23 = add nsw i64 %j13.0, 1
+  br label %for.cond14
+
+for.end24:                                        ; preds = %for.cond14
+  br label %for.inc25
+
+for.inc25:                                        ; preds = %for.end24
+  %inc26 = add nsw i64 %i8.0, 1
+  br label %for.cond9
+
+for.end27:                                        ; preds = %for.cond9
+  ret void
+}
diff --git a/final/test/ScopInfo/assume_gep_bounds_many.ll b/final/test/ScopInfo/assume_gep_bounds_many.ll
new file mode 100644
index 0000000..39e63b7
--- /dev/null
+++ b/final/test/ScopInfo/assume_gep_bounds_many.ll
@@ -0,0 +1,771 @@
+; RUN: opt %loadPolly -analyze -polly-scops -polly-ignore-aliasing \
+; RUN:    < %s | FileCheck %s
+
+; CHECK: Assumed Context:
+; CHECK-NEXT: [n1_a, n1_b, n1_c, n1_d, n2_a, n2_b, n2_c, n2_d, n3_a, n3_b, n3_c, n3_d, n4_a, n4_b, n4_c, n4_d, n5_a, n5_b, n5_c, n5_d, n6_a, n6_b, n6_c, n6_d, n7_a, n7_b, n7_c, n7_d, n8_a, n8_b, n8_c, n8_d, n9_a, n9_b, n9_c, n9_d, p1_b, p1_c, p1_d, p2_b, p2_c, p2_d, p3_b, p3_c, p3_d, p4_b, p4_c, p4_d, p5_b, p5_c, p5_d, p6_b, p6_c, p6_d, p7_b, p7_c, p7_d, p8_b, p8_c, p8_d, p9_b, p9_c, p9_d] -> {  : p1_b >= n1_b and p1_c >= n1_c and p1_d >= n1_d and p2_b >= n2_b and p2_c >= n2_c and p2_d >= n2_d and p3_b >= n3_b and p3_c >= n3_c and p3_d >= n3_d and p4_b >= n4_b and p4_c >= n4_c and p4_d >= n4_d and p5_b >= n5_b and p5_c >= n5_c and p5_d >= n5_d and p6_b >= n6_b and p6_c >= n6_c and p6_d >= n6_d and p7_b >= n7_b and p7_c >= n7_c and p7_d >= n7_d and p8_b >= n8_b and p8_c >= n8_c and p8_d >= n8_d and p9_b >= n9_b and p9_c >= n9_c and p9_d >= n9_d }
+; CHECK-NEXT: Invalid Context:
+; CHECK-NEXT: [n1_a, n1_b, n1_c, n1_d, n2_a, n2_b, n2_c, n2_d, n3_a, n3_b, n3_c, n3_d, n4_a, n4_b, n4_c, n4_d, n5_a, n5_b, n5_c, n5_d, n6_a, n6_b, n6_c, n6_d, n7_a, n7_b, n7_c, n7_d, n8_a, n8_b, n8_c, n8_d, n9_a, n9_b, n9_c, n9_d, p1_b, p1_c, p1_d, p2_b, p2_c, p2_d, p3_b, p3_c, p3_d, p4_b, p4_c, p4_d, p5_b, p5_c, p5_d, p6_b, p6_c, p6_d, p7_b, p7_c, p7_d, p8_b, p8_c, p8_d, p9_b, p9_c, p9_d] -> {  : 1 = 0 }
+
+
+;
+;    void foo(long n1_a, long n1_b, long n1_c, long n1_d, long n2_a, long n2_b,
+;             long n2_c, long n2_d, long n3_a, long n3_b, long n3_c, long n3_d,
+;             long n4_a, long n4_b, long n4_c, long n4_d, long n5_a, long n5_b,
+;             long n5_c, long n5_d, long n6_a, long n6_b, long n6_c, long n6_d,
+;             long n7_a, long n7_b, long n7_c, long n7_d, long n8_a, long n8_b,
+;             long n8_c, long n8_d, long n9_a, long n9_b, long n9_c, long n9_d,
+;             long p1_b, long p1_c, long p1_d, long p2_b, long p2_c, long p2_d,
+;             long p3_b, long p3_c, long p3_d, long p4_b, long p4_c, long p4_d,
+;             long p5_b, long p5_c, long p5_d, long p6_b, long p6_c, long p6_d,
+;             long p7_b, long p7_c, long p7_d, long p8_b, long p8_c, long p8_d,
+;             long p9_b, long p9_c, long p9_d, float A_1[][p1_b][p1_c][p1_d],
+;             float A_2[][p2_b][p2_c][p2_d], float A_3[][p3_b][p3_c][p3_d],
+;             float A_4[][p4_b][p4_c][p4_d], float A_5[][p5_b][p5_c][p5_d],
+;             float A_6[][p6_b][p6_c][p6_d], float A_7[][p7_b][p7_c][p7_d],
+;             float A_8[][p8_b][p8_c][p8_d], float A_9[][p9_b][p9_c][p9_d]) {
+;      for (long i = 0; i < n1_a; i++)
+;        for (long j = 0; j < n1_b; j++)
+;          for (long k = 0; k < n1_c; k++)
+;            for (long l = 0; l < n1_d; l++)
+;              A_1[i][j][k][l] += i + j + k + l;
+;      for (long i = 0; i < n2_a; i++)
+;        for (long j = 0; j < n2_b; j++)
+;          for (long k = 0; k < n2_c; k++)
+;            for (long l = 0; l < n2_d; l++)
+;              A_2[i][j][k][l] += i + j + k + l;
+;      for (long i = 0; i < n3_a; i++)
+;        for (long j = 0; j < n3_b; j++)
+;          for (long k = 0; k < n3_c; k++)
+;            for (long l = 0; l < n3_d; l++)
+;              A_3[i][j][k][l] += i + j + k + l;
+;      for (long i = 0; i < n4_a; i++)
+;        for (long j = 0; j < n4_b; j++)
+;          for (long k = 0; k < n4_c; k++)
+;            for (long l = 0; l < n4_d; l++)
+;              A_4[i][j][k][l] += i + j + k + l;
+;      for (long i = 0; i < n5_a; i++)
+;        for (long j = 0; j < n5_b; j++)
+;          for (long k = 0; k < n5_c; k++)
+;            for (long l = 0; l < n5_d; l++)
+;              A_5[i][j][k][l] += i + j + k + l;
+;      for (long i = 0; i < n6_a; i++)
+;        for (long j = 0; j < n6_b; j++)
+;          for (long k = 0; k < n6_c; k++)
+;            for (long l = 0; l < n6_d; l++)
+;              A_6[i][j][k][l] += i + j + k + l;
+;      for (long i = 0; i < n7_a; i++)
+;        for (long j = 0; j < n7_b; j++)
+;          for (long k = 0; k < n7_c; k++)
+;            for (long l = 0; l < n7_d; l++)
+;              A_7[i][j][k][l] += i + j + k + l;
+;      for (long i = 0; i < n8_a; i++)
+;        for (long j = 0; j < n8_b; j++)
+;          for (long k = 0; k < n8_c; k++)
+;            for (long l = 0; l < n8_d; l++)
+;              A_8[i][j][k][l] += i + j + k + l;
+;      for (long i = 0; i < n9_a; i++)
+;        for (long j = 0; j < n9_b; j++)
+;          for (long k = 0; k < n9_c; k++)
+;            for (long l = 0; l < n9_d; l++)
+;              A_9[i][j][k][l] += i + j + k + l;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %n1_a, i64 %n1_b, i64 %n1_c, i64 %n1_d, i64 %n2_a, i64 %n2_b, i64 %n2_c, i64 %n2_d, i64 %n3_a, i64 %n3_b, i64 %n3_c, i64 %n3_d, i64 %n4_a, i64 %n4_b, i64 %n4_c, i64 %n4_d, i64 %n5_a, i64 %n5_b, i64 %n5_c, i64 %n5_d, i64 %n6_a, i64 %n6_b, i64 %n6_c, i64 %n6_d, i64 %n7_a, i64 %n7_b, i64 %n7_c, i64 %n7_d, i64 %n8_a, i64 %n8_b, i64 %n8_c, i64 %n8_d, i64 %n9_a, i64 %n9_b, i64 %n9_c, i64 %n9_d, i64 %p1_b, i64 %p1_c, i64 %p1_d, i64 %p2_b, i64 %p2_c, i64 %p2_d, i64 %p3_b, i64 %p3_c, i64 %p3_d, i64 %p4_b, i64 %p4_c, i64 %p4_d, i64 %p5_b, i64 %p5_c, i64 %p5_d, i64 %p6_b, i64 %p6_c, i64 %p6_d, i64 %p7_b, i64 %p7_c, i64 %p7_d, i64 %p8_b, i64 %p8_c, i64 %p8_d, i64 %p9_b, i64 %p9_c, i64 %p9_d, float* %A_1, float* %A_2, float* %A_3, float* %A_4, float* %A_5, float* %A_6, float* %A_7, float* %A_8, float* %A_9) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb37, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp38, %bb37 ]
+  %tmp = icmp slt i64 %i.0, %n1_a
+  br i1 %tmp, label %bb2, label %bb39
+
+bb2:                                              ; preds = %bb1
+  br label %bb3
+
+bb3:                                              ; preds = %bb34, %bb2
+  %j.0 = phi i64 [ 0, %bb2 ], [ %tmp35, %bb34 ]
+  %tmp4 = icmp slt i64 %j.0, %n1_b
+  br i1 %tmp4, label %bb5, label %bb36
+
+bb5:                                              ; preds = %bb3
+  br label %bb6
+
+bb6:                                              ; preds = %bb31, %bb5
+  %k.0 = phi i64 [ 0, %bb5 ], [ %tmp32, %bb31 ]
+  %tmp7 = icmp slt i64 %k.0, %n1_c
+  br i1 %tmp7, label %bb8, label %bb33
+
+bb8:                                              ; preds = %bb6
+  br label %bb9
+
+bb9:                                              ; preds = %bb28, %bb8
+  %l.0 = phi i64 [ 0, %bb8 ], [ %tmp29, %bb28 ]
+  %tmp10 = icmp slt i64 %l.0, %n1_d
+  br i1 %tmp10, label %bb11, label %bb30
+
+bb11:                                             ; preds = %bb9
+  %tmp12 = add nuw nsw i64 %i.0, %j.0
+  %tmp13 = add nsw i64 %tmp12, %k.0
+  %tmp14 = add nsw i64 %tmp13, %l.0
+  %tmp15 = sitofp i64 %tmp14 to float
+  %tmp16 = mul nuw i64 %p1_b, %p1_c
+  %tmp17 = mul nuw i64 %tmp16, %p1_d
+  %tmp18 = mul nsw i64 %i.0, %tmp17
+  %tmp19 = getelementptr inbounds float, float* %A_1, i64 %tmp18
+  %tmp20 = mul nuw i64 %p1_c, %p1_d
+  %tmp21 = mul nsw i64 %j.0, %tmp20
+  %tmp22 = getelementptr inbounds float, float* %tmp19, i64 %tmp21
+  %tmp23 = mul nsw i64 %k.0, %p1_d
+  %tmp24 = getelementptr inbounds float, float* %tmp22, i64 %tmp23
+  %tmp25 = getelementptr inbounds float, float* %tmp24, i64 %l.0
+  %tmp26 = load float, float* %tmp25, align 4
+  %tmp27 = fadd float %tmp26, %tmp15
+  store float %tmp27, float* %tmp25, align 4
+  br label %bb28
+
+bb28:                                             ; preds = %bb11
+  %tmp29 = add nuw nsw i64 %l.0, 1
+  br label %bb9
+
+bb30:                                             ; preds = %bb9
+  br label %bb31
+
+bb31:                                             ; preds = %bb30
+  %tmp32 = add nuw nsw i64 %k.0, 1
+  br label %bb6
+
+bb33:                                             ; preds = %bb6
+  br label %bb34
+
+bb34:                                             ; preds = %bb33
+  %tmp35 = add nuw nsw i64 %j.0, 1
+  br label %bb3
+
+bb36:                                             ; preds = %bb3
+  br label %bb37
+
+bb37:                                             ; preds = %bb36
+  %tmp38 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb39:                                             ; preds = %bb1
+  br label %bb40
+
+bb40:                                             ; preds = %bb77, %bb39
+  %i1.0 = phi i64 [ 0, %bb39 ], [ %tmp78, %bb77 ]
+  %tmp41 = icmp slt i64 %i1.0, %n2_a
+  br i1 %tmp41, label %bb42, label %bb79
+
+bb42:                                             ; preds = %bb40
+  br label %bb43
+
+bb43:                                             ; preds = %bb74, %bb42
+  %j2.0 = phi i64 [ 0, %bb42 ], [ %tmp75, %bb74 ]
+  %tmp44 = icmp slt i64 %j2.0, %n2_b
+  br i1 %tmp44, label %bb45, label %bb76
+
+bb45:                                             ; preds = %bb43
+  br label %bb46
+
+bb46:                                             ; preds = %bb71, %bb45
+  %k3.0 = phi i64 [ 0, %bb45 ], [ %tmp72, %bb71 ]
+  %tmp47 = icmp slt i64 %k3.0, %n2_c
+  br i1 %tmp47, label %bb48, label %bb73
+
+bb48:                                             ; preds = %bb46
+  br label %bb49
+
+bb49:                                             ; preds = %bb68, %bb48
+  %l4.0 = phi i64 [ 0, %bb48 ], [ %tmp69, %bb68 ]
+  %tmp50 = icmp slt i64 %l4.0, %n2_d
+  br i1 %tmp50, label %bb51, label %bb70
+
+bb51:                                             ; preds = %bb49
+  %tmp52 = add nuw nsw i64 %i1.0, %j2.0
+  %tmp53 = add nsw i64 %tmp52, %k3.0
+  %tmp54 = add nsw i64 %tmp53, %l4.0
+  %tmp55 = sitofp i64 %tmp54 to float
+  %tmp56 = mul nuw i64 %p2_b, %p2_c
+  %tmp57 = mul nuw i64 %tmp56, %p2_d
+  %tmp58 = mul nsw i64 %i1.0, %tmp57
+  %tmp59 = getelementptr inbounds float, float* %A_2, i64 %tmp58
+  %tmp60 = mul nuw i64 %p2_c, %p2_d
+  %tmp61 = mul nsw i64 %j2.0, %tmp60
+  %tmp62 = getelementptr inbounds float, float* %tmp59, i64 %tmp61
+  %tmp63 = mul nsw i64 %k3.0, %p2_d
+  %tmp64 = getelementptr inbounds float, float* %tmp62, i64 %tmp63
+  %tmp65 = getelementptr inbounds float, float* %tmp64, i64 %l4.0
+  %tmp66 = load float, float* %tmp65, align 4
+  %tmp67 = fadd float %tmp66, %tmp55
+  store float %tmp67, float* %tmp65, align 4
+  br label %bb68
+
+bb68:                                             ; preds = %bb51
+  %tmp69 = add nuw nsw i64 %l4.0, 1
+  br label %bb49
+
+bb70:                                             ; preds = %bb49
+  br label %bb71
+
+bb71:                                             ; preds = %bb70
+  %tmp72 = add nuw nsw i64 %k3.0, 1
+  br label %bb46
+
+bb73:                                             ; preds = %bb46
+  br label %bb74
+
+bb74:                                             ; preds = %bb73
+  %tmp75 = add nuw nsw i64 %j2.0, 1
+  br label %bb43
+
+bb76:                                             ; preds = %bb43
+  br label %bb77
+
+bb77:                                             ; preds = %bb76
+  %tmp78 = add nuw nsw i64 %i1.0, 1
+  br label %bb40
+
+bb79:                                             ; preds = %bb40
+  br label %bb80
+
+bb80:                                             ; preds = %bb117, %bb79
+  %i5.0 = phi i64 [ 0, %bb79 ], [ %tmp118, %bb117 ]
+  %tmp81 = icmp slt i64 %i5.0, %n3_a
+  br i1 %tmp81, label %bb82, label %bb119
+
+bb82:                                             ; preds = %bb80
+  br label %bb83
+
+bb83:                                             ; preds = %bb114, %bb82
+  %j6.0 = phi i64 [ 0, %bb82 ], [ %tmp115, %bb114 ]
+  %tmp84 = icmp slt i64 %j6.0, %n3_b
+  br i1 %tmp84, label %bb85, label %bb116
+
+bb85:                                             ; preds = %bb83
+  br label %bb86
+
+bb86:                                             ; preds = %bb111, %bb85
+  %k7.0 = phi i64 [ 0, %bb85 ], [ %tmp112, %bb111 ]
+  %tmp87 = icmp slt i64 %k7.0, %n3_c
+  br i1 %tmp87, label %bb88, label %bb113
+
+bb88:                                             ; preds = %bb86
+  br label %bb89
+
+bb89:                                             ; preds = %bb108, %bb88
+  %l8.0 = phi i64 [ 0, %bb88 ], [ %tmp109, %bb108 ]
+  %tmp90 = icmp slt i64 %l8.0, %n3_d
+  br i1 %tmp90, label %bb91, label %bb110
+
+bb91:                                             ; preds = %bb89
+  %tmp92 = add nuw nsw i64 %i5.0, %j6.0
+  %tmp93 = add nsw i64 %tmp92, %k7.0
+  %tmp94 = add nsw i64 %tmp93, %l8.0
+  %tmp95 = sitofp i64 %tmp94 to float
+  %tmp96 = mul nuw i64 %p3_b, %p3_c
+  %tmp97 = mul nuw i64 %tmp96, %p3_d
+  %tmp98 = mul nsw i64 %i5.0, %tmp97
+  %tmp99 = getelementptr inbounds float, float* %A_3, i64 %tmp98
+  %tmp100 = mul nuw i64 %p3_c, %p3_d
+  %tmp101 = mul nsw i64 %j6.0, %tmp100
+  %tmp102 = getelementptr inbounds float, float* %tmp99, i64 %tmp101
+  %tmp103 = mul nsw i64 %k7.0, %p3_d
+  %tmp104 = getelementptr inbounds float, float* %tmp102, i64 %tmp103
+  %tmp105 = getelementptr inbounds float, float* %tmp104, i64 %l8.0
+  %tmp106 = load float, float* %tmp105, align 4
+  %tmp107 = fadd float %tmp106, %tmp95
+  store float %tmp107, float* %tmp105, align 4
+  br label %bb108
+
+bb108:                                            ; preds = %bb91
+  %tmp109 = add nuw nsw i64 %l8.0, 1
+  br label %bb89
+
+bb110:                                            ; preds = %bb89
+  br label %bb111
+
+bb111:                                            ; preds = %bb110
+  %tmp112 = add nuw nsw i64 %k7.0, 1
+  br label %bb86
+
+bb113:                                            ; preds = %bb86
+  br label %bb114
+
+bb114:                                            ; preds = %bb113
+  %tmp115 = add nuw nsw i64 %j6.0, 1
+  br label %bb83
+
+bb116:                                            ; preds = %bb83
+  br label %bb117
+
+bb117:                                            ; preds = %bb116
+  %tmp118 = add nuw nsw i64 %i5.0, 1
+  br label %bb80
+
+bb119:                                            ; preds = %bb80
+  br label %bb120
+
+bb120:                                            ; preds = %bb157, %bb119
+  %i9.0 = phi i64 [ 0, %bb119 ], [ %tmp158, %bb157 ]
+  %tmp121 = icmp slt i64 %i9.0, %n4_a
+  br i1 %tmp121, label %bb122, label %bb159
+
+bb122:                                            ; preds = %bb120
+  br label %bb123
+
+bb123:                                            ; preds = %bb154, %bb122
+  %j10.0 = phi i64 [ 0, %bb122 ], [ %tmp155, %bb154 ]
+  %tmp124 = icmp slt i64 %j10.0, %n4_b
+  br i1 %tmp124, label %bb125, label %bb156
+
+bb125:                                            ; preds = %bb123
+  br label %bb126
+
+bb126:                                            ; preds = %bb151, %bb125
+  %k11.0 = phi i64 [ 0, %bb125 ], [ %tmp152, %bb151 ]
+  %tmp127 = icmp slt i64 %k11.0, %n4_c
+  br i1 %tmp127, label %bb128, label %bb153
+
+bb128:                                            ; preds = %bb126
+  br label %bb129
+
+bb129:                                            ; preds = %bb148, %bb128
+  %l12.0 = phi i64 [ 0, %bb128 ], [ %tmp149, %bb148 ]
+  %tmp130 = icmp slt i64 %l12.0, %n4_d
+  br i1 %tmp130, label %bb131, label %bb150
+
+bb131:                                            ; preds = %bb129
+  %tmp132 = add nuw nsw i64 %i9.0, %j10.0
+  %tmp133 = add nsw i64 %tmp132, %k11.0
+  %tmp134 = add nsw i64 %tmp133, %l12.0
+  %tmp135 = sitofp i64 %tmp134 to float
+  %tmp136 = mul nuw i64 %p4_b, %p4_c
+  %tmp137 = mul nuw i64 %tmp136, %p4_d
+  %tmp138 = mul nsw i64 %i9.0, %tmp137
+  %tmp139 = getelementptr inbounds float, float* %A_4, i64 %tmp138
+  %tmp140 = mul nuw i64 %p4_c, %p4_d
+  %tmp141 = mul nsw i64 %j10.0, %tmp140
+  %tmp142 = getelementptr inbounds float, float* %tmp139, i64 %tmp141
+  %tmp143 = mul nsw i64 %k11.0, %p4_d
+  %tmp144 = getelementptr inbounds float, float* %tmp142, i64 %tmp143
+  %tmp145 = getelementptr inbounds float, float* %tmp144, i64 %l12.0
+  %tmp146 = load float, float* %tmp145, align 4
+  %tmp147 = fadd float %tmp146, %tmp135
+  store float %tmp147, float* %tmp145, align 4
+  br label %bb148
+
+bb148:                                            ; preds = %bb131
+  %tmp149 = add nuw nsw i64 %l12.0, 1
+  br label %bb129
+
+bb150:                                            ; preds = %bb129
+  br label %bb151
+
+bb151:                                            ; preds = %bb150
+  %tmp152 = add nuw nsw i64 %k11.0, 1
+  br label %bb126
+
+bb153:                                            ; preds = %bb126
+  br label %bb154
+
+bb154:                                            ; preds = %bb153
+  %tmp155 = add nuw nsw i64 %j10.0, 1
+  br label %bb123
+
+bb156:                                            ; preds = %bb123
+  br label %bb157
+
+bb157:                                            ; preds = %bb156
+  %tmp158 = add nuw nsw i64 %i9.0, 1
+  br label %bb120
+
+bb159:                                            ; preds = %bb120
+  br label %bb160
+
+bb160:                                            ; preds = %bb197, %bb159
+  %i13.0 = phi i64 [ 0, %bb159 ], [ %tmp198, %bb197 ]
+  %tmp161 = icmp slt i64 %i13.0, %n5_a
+  br i1 %tmp161, label %bb162, label %bb199
+
+bb162:                                            ; preds = %bb160
+  br label %bb163
+
+bb163:                                            ; preds = %bb194, %bb162
+  %j14.0 = phi i64 [ 0, %bb162 ], [ %tmp195, %bb194 ]
+  %tmp164 = icmp slt i64 %j14.0, %n5_b
+  br i1 %tmp164, label %bb165, label %bb196
+
+bb165:                                            ; preds = %bb163
+  br label %bb166
+
+bb166:                                            ; preds = %bb191, %bb165
+  %k15.0 = phi i64 [ 0, %bb165 ], [ %tmp192, %bb191 ]
+  %tmp167 = icmp slt i64 %k15.0, %n5_c
+  br i1 %tmp167, label %bb168, label %bb193
+
+bb168:                                            ; preds = %bb166
+  br label %bb169
+
+bb169:                                            ; preds = %bb188, %bb168
+  %l16.0 = phi i64 [ 0, %bb168 ], [ %tmp189, %bb188 ]
+  %tmp170 = icmp slt i64 %l16.0, %n5_d
+  br i1 %tmp170, label %bb171, label %bb190
+
+bb171:                                            ; preds = %bb169
+  %tmp172 = add nuw nsw i64 %i13.0, %j14.0
+  %tmp173 = add nsw i64 %tmp172, %k15.0
+  %tmp174 = add nsw i64 %tmp173, %l16.0
+  %tmp175 = sitofp i64 %tmp174 to float
+  %tmp176 = mul nuw i64 %p5_b, %p5_c
+  %tmp177 = mul nuw i64 %tmp176, %p5_d
+  %tmp178 = mul nsw i64 %i13.0, %tmp177
+  %tmp179 = getelementptr inbounds float, float* %A_5, i64 %tmp178
+  %tmp180 = mul nuw i64 %p5_c, %p5_d
+  %tmp181 = mul nsw i64 %j14.0, %tmp180
+  %tmp182 = getelementptr inbounds float, float* %tmp179, i64 %tmp181
+  %tmp183 = mul nsw i64 %k15.0, %p5_d
+  %tmp184 = getelementptr inbounds float, float* %tmp182, i64 %tmp183
+  %tmp185 = getelementptr inbounds float, float* %tmp184, i64 %l16.0
+  %tmp186 = load float, float* %tmp185, align 4
+  %tmp187 = fadd float %tmp186, %tmp175
+  store float %tmp187, float* %tmp185, align 4
+  br label %bb188
+
+bb188:                                            ; preds = %bb171
+  %tmp189 = add nuw nsw i64 %l16.0, 1
+  br label %bb169
+
+bb190:                                            ; preds = %bb169
+  br label %bb191
+
+bb191:                                            ; preds = %bb190
+  %tmp192 = add nuw nsw i64 %k15.0, 1
+  br label %bb166
+
+bb193:                                            ; preds = %bb166
+  br label %bb194
+
+bb194:                                            ; preds = %bb193
+  %tmp195 = add nuw nsw i64 %j14.0, 1
+  br label %bb163
+
+bb196:                                            ; preds = %bb163
+  br label %bb197
+
+bb197:                                            ; preds = %bb196
+  %tmp198 = add nuw nsw i64 %i13.0, 1
+  br label %bb160
+
+bb199:                                            ; preds = %bb160
+  br label %bb200
+
+bb200:                                            ; preds = %bb237, %bb199
+  %i17.0 = phi i64 [ 0, %bb199 ], [ %tmp238, %bb237 ]
+  %tmp201 = icmp slt i64 %i17.0, %n6_a
+  br i1 %tmp201, label %bb202, label %bb239
+
+bb202:                                            ; preds = %bb200
+  br label %bb203
+
+bb203:                                            ; preds = %bb234, %bb202
+  %j18.0 = phi i64 [ 0, %bb202 ], [ %tmp235, %bb234 ]
+  %tmp204 = icmp slt i64 %j18.0, %n6_b
+  br i1 %tmp204, label %bb205, label %bb236
+
+bb205:                                            ; preds = %bb203
+  br label %bb206
+
+bb206:                                            ; preds = %bb231, %bb205
+  %k19.0 = phi i64 [ 0, %bb205 ], [ %tmp232, %bb231 ]
+  %tmp207 = icmp slt i64 %k19.0, %n6_c
+  br i1 %tmp207, label %bb208, label %bb233
+
+bb208:                                            ; preds = %bb206
+  br label %bb209
+
+bb209:                                            ; preds = %bb228, %bb208
+  %l20.0 = phi i64 [ 0, %bb208 ], [ %tmp229, %bb228 ]
+  %tmp210 = icmp slt i64 %l20.0, %n6_d
+  br i1 %tmp210, label %bb211, label %bb230
+
+bb211:                                            ; preds = %bb209
+  %tmp212 = add nuw nsw i64 %i17.0, %j18.0
+  %tmp213 = add nsw i64 %tmp212, %k19.0
+  %tmp214 = add nsw i64 %tmp213, %l20.0
+  %tmp215 = sitofp i64 %tmp214 to float
+  %tmp216 = mul nuw i64 %p6_b, %p6_c
+  %tmp217 = mul nuw i64 %tmp216, %p6_d
+  %tmp218 = mul nsw i64 %i17.0, %tmp217
+  %tmp219 = getelementptr inbounds float, float* %A_6, i64 %tmp218
+  %tmp220 = mul nuw i64 %p6_c, %p6_d
+  %tmp221 = mul nsw i64 %j18.0, %tmp220
+  %tmp222 = getelementptr inbounds float, float* %tmp219, i64 %tmp221
+  %tmp223 = mul nsw i64 %k19.0, %p6_d
+  %tmp224 = getelementptr inbounds float, float* %tmp222, i64 %tmp223
+  %tmp225 = getelementptr inbounds float, float* %tmp224, i64 %l20.0
+  %tmp226 = load float, float* %tmp225, align 4
+  %tmp227 = fadd float %tmp226, %tmp215
+  store float %tmp227, float* %tmp225, align 4
+  br label %bb228
+
+bb228:                                            ; preds = %bb211
+  %tmp229 = add nuw nsw i64 %l20.0, 1
+  br label %bb209
+
+bb230:                                            ; preds = %bb209
+  br label %bb231
+
+bb231:                                            ; preds = %bb230
+  %tmp232 = add nuw nsw i64 %k19.0, 1
+  br label %bb206
+
+bb233:                                            ; preds = %bb206
+  br label %bb234
+
+bb234:                                            ; preds = %bb233
+  %tmp235 = add nuw nsw i64 %j18.0, 1
+  br label %bb203
+
+bb236:                                            ; preds = %bb203
+  br label %bb237
+
+bb237:                                            ; preds = %bb236
+  %tmp238 = add nuw nsw i64 %i17.0, 1
+  br label %bb200
+
+bb239:                                            ; preds = %bb200
+  br label %bb240
+
+bb240:                                            ; preds = %bb277, %bb239
+  %i21.0 = phi i64 [ 0, %bb239 ], [ %tmp278, %bb277 ]
+  %tmp241 = icmp slt i64 %i21.0, %n7_a
+  br i1 %tmp241, label %bb242, label %bb279
+
+bb242:                                            ; preds = %bb240
+  br label %bb243
+
+bb243:                                            ; preds = %bb274, %bb242
+  %j22.0 = phi i64 [ 0, %bb242 ], [ %tmp275, %bb274 ]
+  %tmp244 = icmp slt i64 %j22.0, %n7_b
+  br i1 %tmp244, label %bb245, label %bb276
+
+bb245:                                            ; preds = %bb243
+  br label %bb246
+
+bb246:                                            ; preds = %bb271, %bb245
+  %k23.0 = phi i64 [ 0, %bb245 ], [ %tmp272, %bb271 ]
+  %tmp247 = icmp slt i64 %k23.0, %n7_c
+  br i1 %tmp247, label %bb248, label %bb273
+
+bb248:                                            ; preds = %bb246
+  br label %bb249
+
+bb249:                                            ; preds = %bb268, %bb248
+  %l24.0 = phi i64 [ 0, %bb248 ], [ %tmp269, %bb268 ]
+  %tmp250 = icmp slt i64 %l24.0, %n7_d
+  br i1 %tmp250, label %bb251, label %bb270
+
+bb251:                                            ; preds = %bb249
+  %tmp252 = add nuw nsw i64 %i21.0, %j22.0
+  %tmp253 = add nsw i64 %tmp252, %k23.0
+  %tmp254 = add nsw i64 %tmp253, %l24.0
+  %tmp255 = sitofp i64 %tmp254 to float
+  %tmp256 = mul nuw i64 %p7_b, %p7_c
+  %tmp257 = mul nuw i64 %tmp256, %p7_d
+  %tmp258 = mul nsw i64 %i21.0, %tmp257
+  %tmp259 = getelementptr inbounds float, float* %A_7, i64 %tmp258
+  %tmp260 = mul nuw i64 %p7_c, %p7_d
+  %tmp261 = mul nsw i64 %j22.0, %tmp260
+  %tmp262 = getelementptr inbounds float, float* %tmp259, i64 %tmp261
+  %tmp263 = mul nsw i64 %k23.0, %p7_d
+  %tmp264 = getelementptr inbounds float, float* %tmp262, i64 %tmp263
+  %tmp265 = getelementptr inbounds float, float* %tmp264, i64 %l24.0
+  %tmp266 = load float, float* %tmp265, align 4
+  %tmp267 = fadd float %tmp266, %tmp255
+  store float %tmp267, float* %tmp265, align 4
+  br label %bb268
+
+bb268:                                            ; preds = %bb251
+  %tmp269 = add nuw nsw i64 %l24.0, 1
+  br label %bb249
+
+bb270:                                            ; preds = %bb249
+  br label %bb271
+
+bb271:                                            ; preds = %bb270
+  %tmp272 = add nuw nsw i64 %k23.0, 1
+  br label %bb246
+
+bb273:                                            ; preds = %bb246
+  br label %bb274
+
+bb274:                                            ; preds = %bb273
+  %tmp275 = add nuw nsw i64 %j22.0, 1
+  br label %bb243
+
+bb276:                                            ; preds = %bb243
+  br label %bb277
+
+bb277:                                            ; preds = %bb276
+  %tmp278 = add nuw nsw i64 %i21.0, 1
+  br label %bb240
+
+bb279:                                            ; preds = %bb240
+  br label %bb280
+
+bb280:                                            ; preds = %bb317, %bb279
+  %i25.0 = phi i64 [ 0, %bb279 ], [ %tmp318, %bb317 ]
+  %tmp281 = icmp slt i64 %i25.0, %n8_a
+  br i1 %tmp281, label %bb282, label %bb319
+
+bb282:                                            ; preds = %bb280
+  br label %bb283
+
+bb283:                                            ; preds = %bb314, %bb282
+  %j26.0 = phi i64 [ 0, %bb282 ], [ %tmp315, %bb314 ]
+  %tmp284 = icmp slt i64 %j26.0, %n8_b
+  br i1 %tmp284, label %bb285, label %bb316
+
+bb285:                                            ; preds = %bb283
+  br label %bb286
+
+bb286:                                            ; preds = %bb311, %bb285
+  %k27.0 = phi i64 [ 0, %bb285 ], [ %tmp312, %bb311 ]
+  %tmp287 = icmp slt i64 %k27.0, %n8_c
+  br i1 %tmp287, label %bb288, label %bb313
+
+bb288:                                            ; preds = %bb286
+  br label %bb289
+
+bb289:                                            ; preds = %bb308, %bb288
+  %l28.0 = phi i64 [ 0, %bb288 ], [ %tmp309, %bb308 ]
+  %tmp290 = icmp slt i64 %l28.0, %n8_d
+  br i1 %tmp290, label %bb291, label %bb310
+
+bb291:                                            ; preds = %bb289
+  %tmp292 = add nuw nsw i64 %i25.0, %j26.0
+  %tmp293 = add nsw i64 %tmp292, %k27.0
+  %tmp294 = add nsw i64 %tmp293, %l28.0
+  %tmp295 = sitofp i64 %tmp294 to float
+  %tmp296 = mul nuw i64 %p8_b, %p8_c
+  %tmp297 = mul nuw i64 %tmp296, %p8_d
+  %tmp298 = mul nsw i64 %i25.0, %tmp297
+  %tmp299 = getelementptr inbounds float, float* %A_8, i64 %tmp298
+  %tmp300 = mul nuw i64 %p8_c, %p8_d
+  %tmp301 = mul nsw i64 %j26.0, %tmp300
+  %tmp302 = getelementptr inbounds float, float* %tmp299, i64 %tmp301
+  %tmp303 = mul nsw i64 %k27.0, %p8_d
+  %tmp304 = getelementptr inbounds float, float* %tmp302, i64 %tmp303
+  %tmp305 = getelementptr inbounds float, float* %tmp304, i64 %l28.0
+  %tmp306 = load float, float* %tmp305, align 4
+  %tmp307 = fadd float %tmp306, %tmp295
+  store float %tmp307, float* %tmp305, align 4
+  br label %bb308
+
+bb308:                                            ; preds = %bb291
+  %tmp309 = add nuw nsw i64 %l28.0, 1
+  br label %bb289
+
+bb310:                                            ; preds = %bb289
+  br label %bb311
+
+bb311:                                            ; preds = %bb310
+  %tmp312 = add nuw nsw i64 %k27.0, 1
+  br label %bb286
+
+bb313:                                            ; preds = %bb286
+  br label %bb314
+
+bb314:                                            ; preds = %bb313
+  %tmp315 = add nuw nsw i64 %j26.0, 1
+  br label %bb283
+
+bb316:                                            ; preds = %bb283
+  br label %bb317
+
+bb317:                                            ; preds = %bb316
+  %tmp318 = add nuw nsw i64 %i25.0, 1
+  br label %bb280
+
+bb319:                                            ; preds = %bb280
+  br label %bb320
+
+bb320:                                            ; preds = %bb357, %bb319
+  %i29.0 = phi i64 [ 0, %bb319 ], [ %tmp358, %bb357 ]
+  %tmp321 = icmp slt i64 %i29.0, %n9_a
+  br i1 %tmp321, label %bb322, label %bb359
+
+bb322:                                            ; preds = %bb320
+  br label %bb323
+
+bb323:                                            ; preds = %bb354, %bb322
+  %j30.0 = phi i64 [ 0, %bb322 ], [ %tmp355, %bb354 ]
+  %tmp324 = icmp slt i64 %j30.0, %n9_b
+  br i1 %tmp324, label %bb325, label %bb356
+
+bb325:                                            ; preds = %bb323
+  br label %bb326
+
+bb326:                                            ; preds = %bb351, %bb325
+  %k31.0 = phi i64 [ 0, %bb325 ], [ %tmp352, %bb351 ]
+  %tmp327 = icmp slt i64 %k31.0, %n9_c
+  br i1 %tmp327, label %bb328, label %bb353
+
+bb328:                                            ; preds = %bb326
+  br label %bb329
+
+bb329:                                            ; preds = %bb348, %bb328
+  %l32.0 = phi i64 [ 0, %bb328 ], [ %tmp349, %bb348 ]
+  %tmp330 = icmp slt i64 %l32.0, %n9_d
+  br i1 %tmp330, label %bb331, label %bb350
+
+bb331:                                            ; preds = %bb329
+  %tmp332 = add nuw nsw i64 %i29.0, %j30.0
+  %tmp333 = add nsw i64 %tmp332, %k31.0
+  %tmp334 = add nsw i64 %tmp333, %l32.0
+  %tmp335 = sitofp i64 %tmp334 to float
+  %tmp336 = mul nuw i64 %p9_b, %p9_c
+  %tmp337 = mul nuw i64 %tmp336, %p9_d
+  %tmp338 = mul nsw i64 %i29.0, %tmp337
+  %tmp339 = getelementptr inbounds float, float* %A_9, i64 %tmp338
+  %tmp340 = mul nuw i64 %p9_c, %p9_d
+  %tmp341 = mul nsw i64 %j30.0, %tmp340
+  %tmp342 = getelementptr inbounds float, float* %tmp339, i64 %tmp341
+  %tmp343 = mul nsw i64 %k31.0, %p9_d
+  %tmp344 = getelementptr inbounds float, float* %tmp342, i64 %tmp343
+  %tmp345 = getelementptr inbounds float, float* %tmp344, i64 %l32.0
+  %tmp346 = load float, float* %tmp345, align 4
+  %tmp347 = fadd float %tmp346, %tmp335
+  store float %tmp347, float* %tmp345, align 4
+  br label %bb348
+
+bb348:                                            ; preds = %bb331
+  %tmp349 = add nuw nsw i64 %l32.0, 1
+  br label %bb329
+
+bb350:                                            ; preds = %bb329
+  br label %bb351
+
+bb351:                                            ; preds = %bb350
+  %tmp352 = add nuw nsw i64 %k31.0, 1
+  br label %bb326
+
+bb353:                                            ; preds = %bb326
+  br label %bb354
+
+bb354:                                            ; preds = %bb353
+  %tmp355 = add nuw nsw i64 %j30.0, 1
+  br label %bb323
+
+bb356:                                            ; preds = %bb323
+  br label %bb357
+
+bb357:                                            ; preds = %bb356
+  %tmp358 = add nuw nsw i64 %i29.0, 1
+  br label %bb320
+
+bb359:                                            ; preds = %bb320
+  ret void
+}
diff --git a/final/test/ScopInfo/avoid_new_parameters_from_geps.ll b/final/test/ScopInfo/avoid_new_parameters_from_geps.ll
new file mode 100644
index 0000000..8b00f2a
--- /dev/null
+++ b/final/test/ScopInfo/avoid_new_parameters_from_geps.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that we do no introduce a parameter here that is actually not needed.
+;
+; CHECK:      Region: %for.body58---%land.lhs.true
+; CHECK-NEXT:     Max Loop Depth:  0
+; CHECK-NEXT:     Invariant Accesses: {
+; CHECK-NEXT:     }
+; CHECK-NEXT:     Context:
+; CHECK-NEXT:     {  :  }
+; CHECK-NEXT:     Assumed Context:
+; CHECK-NEXT:     {  :  }
+; CHECK-NEXT:     Invalid Context:
+; CHECK-NEXT:     {  : 1 = 0 }
+; CHECK-NEXT:     Arrays {
+; CHECK-NEXT:         i32* MemRef_team2_0_in; // Element size 8
+; CHECK-NEXT:     }
+; CHECK-NEXT:     Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:         i32* MemRef_team2_0_in; // Element size 8
+; CHECK-NEXT:     }
+; CHECK-NEXT:     Alias Groups (0):
+; CHECK-NEXT:         n/a
+; CHECK-NEXT:     Statements {
+; CHECK-NEXT:     	Stmt_if_then60
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 { Stmt_if_then60[] };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 { Stmt_if_then60[] -> [] };
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_if_then60[] -> MemRef_team2_0_in[] };
+; CHECK-NEXT:     }
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@sched = external global [18 x [15 x [3 x i32]]], align 16
+
+; Function Attrs: nounwind uwtable
+define void @common() #0 {
+entry:
+  br label %for.body36
+
+for.body36:                                       ; preds = %entry
+  br label %for.cond56.preheader
+
+for.cond56.preheader:                             ; preds = %for.inc158, %for.body36
+  %indvars.iv78 = phi i64 [ 0, %for.inc158 ], [ 1, %for.body36 ]
+  br label %for.body58
+
+for.body58:                                       ; preds = %for.cond56.preheader
+  %cmp59 = icmp eq i32 1, 1
+  br i1 %cmp59, label %if.then60, label %if.else71
+
+if.then60:                                        ; preds = %for.body58
+  %arrayidx70 = getelementptr inbounds [18 x [15 x [3 x i32]]], [18 x [15 x [3 x i32]]]* @sched, i64 0, i64 1, i64 %indvars.iv78, i64 1
+  br label %land.lhs.true
+
+if.else71:                                        ; preds = %for.body58
+  br label %land.lhs.true
+
+land.lhs.true:                                    ; preds = %if.else71, %if.then60
+  %team2.0.in = phi i32* [ %arrayidx70, %if.then60 ], [ undef, %if.else71 ]
+  br i1 undef, label %for.inc158, label %if.then86
+
+if.then86:                                        ; preds = %land.lhs.true
+  unreachable
+
+for.inc158:                                       ; preds = %land.lhs.true
+  br label %for.cond56.preheader
+}
diff --git a/final/test/ScopInfo/bool-addrec.ll b/final/test/ScopInfo/bool-addrec.ll
new file mode 100644
index 0000000..7588a88
--- /dev/null
+++ b/final/test/ScopInfo/bool-addrec.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -analyze -polly-ast -polly-process-unprofitable < %s | FileCheck %s
+
+; CHECK:      for (int c0 = 0; c0 <= 19999; c0 += 1) {
+; CHECK-NEXT:   if (c0 % 2 == 0)
+; CHECK-NEXT:     Stmt_if_then(c0);
+; CHECK-NEXT:   Stmt_if_end(c0);
+; CHECK-NEXT:   if (c0 % 2 == 0)
+; CHECK-NEXT:     Stmt_if_then5(c0);
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n8:16:32-S64"
+
+define void @f(i32* %a, i32 %x) {
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %entry, %for.inc
+  %i.03 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %rem1 = and i32 %i.03, 1
+  %cmp1 = icmp eq i32 %rem1, 0
+  br i1 %cmp1, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %a, i32 %i.03
+  store i32 3, i32* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  %mul = shl nsw i32 %i.03, 1
+  %arrayidx2 = getelementptr inbounds i32, i32* %a, i32 %mul
+  store i32 3, i32* %arrayidx2, align 4
+  %rem32 = and i32 %i.03, 1
+  %cmp4 = icmp eq i32 %rem32, 0
+  br i1 %cmp4, label %if.then5, label %for.inc
+
+if.then5:                                         ; preds = %if.end
+  %mul6 = mul nsw i32 %i.03, 3
+  %arrayidx7 = getelementptr inbounds i32, i32* %a, i32 %mul6
+  store i32 3, i32* %arrayidx7, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end, %if.then5
+  %inc = add nsw i32 %i.03, 1
+  %cmp = icmp slt i32 %inc, 20000
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.inc
+  ret void
+}
diff --git a/final/test/ScopInfo/bounded_loop_assumptions.ll b/final/test/ScopInfo/bounded_loop_assumptions.ll
new file mode 100644
index 0000000..d150ee5
--- /dev/null
+++ b/final/test/ScopInfo/bounded_loop_assumptions.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; The assumed context is tricky here as the equality test for the inner loop
+; allows an "unbounded" loop trip count. We assume that does not happen, thus
+; if N <= 1 the outer loop is not executed and we are done, if N >= 3 the
+; equality test in the inner exit condition will trigger at some point and,
+; finally, if N == 2 we would have an unbounded inner loop.
+;
+; CHECK:      Assumed Context:
+; CHECK-NEXT:   [N] -> {  :  }
+; CHECK:      Invalid Context:
+; CHECK-NEXT:   [N] -> {  : N = 2 }
+;
+;    int jd(int *restrict A, int x, int N) {
+;      for (int i = 1; i < N; i++)
+;        for (int j = 3; j < N; j++)
+;          x += A[i];
+;      return x;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @jd(i32* noalias %A, i32 %x, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc4 ], [ 1, %entry ]
+  %x.addr.0 = phi i32 [ %x, %entry ], [ %x.addr.1.lcssa, %for.inc4 ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %x.addr.1 = phi i32 [ %x.addr.0, %for.body ], [ %add, %for.inc ]
+  %j.0 = phi i32 [ 3, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, %N
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %x.addr.1, %tmp1
+  %inc = add i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  %x.addr.1.lcssa = phi i32 [ %x.addr.1, %for.cond1 ]
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %indvars.iv.next = add i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret i32 %x.addr.0
+}
diff --git a/final/test/ScopInfo/branch-references-loop-scev-with-unknown-iterations-2.ll b/final/test/ScopInfo/branch-references-loop-scev-with-unknown-iterations-2.ll
new file mode 100644
index 0000000..5f4c867
--- /dev/null
+++ b/final/test/ScopInfo/branch-references-loop-scev-with-unknown-iterations-2.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | \
+; RUN:     FileCheck %s -check-prefix=DETECT
+
+; RUN: opt %loadPolly -polly-scops -analyze < %s | \
+; RUN:     FileCheck %s -check-prefix=SCOP
+
+; DETECT: Valid Region for Scop: loop => barrier
+; DETECT-NEXT: Valid Region for Scop: branch => end
+
+; SCOP: Statements {
+; SCOP-NEXT: 	Stmt_then
+; SCOP-NEXT:         Domain :=
+; SCOP-NEXT:             [p_0] -> { Stmt_then[] : p_0 <= -2 or p_0 >= 0 };
+; SCOP-NEXT:         Schedule :=
+; SCOP-NEXT:             [p_0] -> { Stmt_then[] -> [] };
+; SCOP-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; SCOP-NEXT:             [p_0] -> { Stmt_then[] -> MemRef_A[0] };
+; SCOP-NEXT: }
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64--linux-android"
+
+define void @f(i16 %event, float* %A) {
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i8 [ 0, %entry ], [ %indvar.next, %loop ]
+  %indvar.next = add i8 %indvar, -1
+  store float 1.0, float* %A
+  %cmp = icmp eq i8 %indvar.next, 0
+  br i1 false, label %barrier, label %loop
+
+barrier:
+  fence seq_cst
+  br label %branch
+
+branch:
+  br i1 %cmp, label %branch, label %then
+
+then:
+  store float 1.0, float* %A
+  br label %end
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/branch-references-loop-scev-with-unknown-iterations-3.ll b/final/test/ScopInfo/branch-references-loop-scev-with-unknown-iterations-3.ll
new file mode 100644
index 0000000..604bb4a
--- /dev/null
+++ b/final/test/ScopInfo/branch-references-loop-scev-with-unknown-iterations-3.ll
@@ -0,0 +1,83 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | \
+; RUN:     FileCheck %s -check-prefix=NONAFFINE
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN:     -polly-allow-nonaffine-branches=false < %s | \
+; RUN:     FileCheck %s -check-prefix=NO-NONEAFFINE
+
+; NONAFFINE:      Statements {
+; NONAFFINE-NEXT: 	Stmt_loop
+; NONAFFINE-NEXT:         Domain :=
+; NONAFFINE-NEXT:             [p] -> { Stmt_loop[0] : p = 100 };
+; NONAFFINE-NEXT:         Schedule :=
+; NONAFFINE-NEXT:             [p] -> { Stmt_loop[i0] -> [0, 0] };
+; NONAFFINE-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:             [p] -> { Stmt_loop[i0] -> MemRef_A[0] };
+; NONAFFINE-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:             [p] -> { Stmt_loop[i0] -> MemRef_cmp[] };
+; NONAFFINE-NEXT: 	Stmt_branch__TO__end
+; NONAFFINE-NEXT:         Domain :=
+; NONAFFINE-NEXT:             [p] -> { Stmt_branch__TO__end[] : p = 100 };
+; NONAFFINE-NEXT:         Schedule :=
+; NONAFFINE-NEXT:             [p] -> { Stmt_branch__TO__end[] -> [1, 0] };
+; NONAFFINE-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:             [p] -> { Stmt_branch__TO__end[] -> MemRef_cmp[] };
+; NONAFFINE-NEXT:         MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:             [p] -> { Stmt_branch__TO__end[] -> MemRef_A[0] };
+; NONAFFINE-NEXT: }
+
+; NO-NONEAFFINE:      Statements {
+; NO-NONEAFFINE-NEXT:    	Stmt_then
+; NO-NONEAFFINE-NEXT:            Domain :=
+; NO-NONEAFFINE-NEXT:                [p_0, p] -> { Stmt_then[] : p >= 2 + p_0 or p <= p_0 };
+; NO-NONEAFFINE-NEXT:            Schedule :=
+; NO-NONEAFFINE-NEXT:                [p_0, p] -> { Stmt_then[] -> [] };
+; NO-NONEAFFINE-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NO-NONEAFFINE-NEXT:                [p_0, p] -> { Stmt_then[] -> MemRef_A[0] };
+; NO-NONEAFFINE-NEXT:    }
+
+; NO-NONEAFFINE:      Statements {
+; NO-NONEAFFINE-NEXT: 	Stmt_loop
+; NO-NONEAFFINE-NEXT:         Domain :=
+; NO-NONEAFFINE-NEXT:             [p] -> { Stmt_loop[0] : p = 100 };
+; NO-NONEAFFINE-NEXT:         Schedule :=
+; NO-NONEAFFINE-NEXT:             [p] -> { Stmt_loop[i0] -> [0] };
+; NO-NONEAFFINE-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NO-NONEAFFINE-NEXT:             [p] -> { Stmt_loop[i0] -> MemRef_A[0] };
+; NO-NONEAFFINE-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NO-NONEAFFINE-NEXT:             [p] -> { Stmt_loop[i0] -> MemRef_cmp[] };
+; NO-NONEAFFINE-NEXT: }
+
+; Verify that this test case does not crash -polly-scops. The problem in
+; this test case is that the branch instruction in %branch references
+; a scalar evolution expression for which no useful value can be computed at the
+; location %branch, as the loop %loop does not terminate. At some point, we
+; did not identify the branch condition as non-affine during scop detection.
+; This test verifies that we either model the branch condition as non-affine
+; region or only detect a smaller region if non-affine conditions are not
+; allowed.
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64--linux-android"
+
+define void @f(i16 %event, i8 %p, float* %A) {
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i8 [ 0, %entry ], [ %indvar.next, %loop ]
+  %indvar.next = add i8 %indvar, 1
+  store float 1.0, float* %A
+  %cmp = icmp eq i8 %indvar.next, %p
+  %possibly_infinite = icmp eq i8 100, %p
+  br i1 %possibly_infinite, label %branch, label %loop
+
+branch:
+  br i1 %cmp, label %end, label %then
+
+then:
+  store float 1.0, float* %A
+  br label %end
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/branch-references-loop-scev-with-unknown-iterations.ll b/final/test/ScopInfo/branch-references-loop-scev-with-unknown-iterations.ll
new file mode 100644
index 0000000..62c7e71
--- /dev/null
+++ b/final/test/ScopInfo/branch-references-loop-scev-with-unknown-iterations.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | \
+; RUN:     FileCheck %s -check-prefix=NONAFFINE
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN:     -polly-allow-nonaffine-branches=false < %s | \
+; RUN:     FileCheck %s -check-prefix=NO-NONEAFFINE
+
+; NONAFFINE-NOT: Statements
+
+; NO-NONEAFFINE: Statements {
+; NO-NONEAFFINE-NEXT: 	Stmt_then
+; NO-NONEAFFINE-NEXT:         Domain :=
+; NO-NONEAFFINE-NEXT:             [p_0] -> { Stmt_then[] : p_0 <= -2 or p_0 >= 0 };
+; NO-NONEAFFINE-NEXT:         Schedule :=
+; NO-NONEAFFINE-NEXT:             [p_0] -> { Stmt_then[] -> [] };
+; NO-NONEAFFINE-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NO-NONEAFFINE-NEXT:             [p_0] -> { Stmt_then[] -> MemRef_A[0] };
+; NO-NONEAFFINE-NEXT: }
+
+; Verify that this test case does not crash -polly-scops. The problem in
+; this test case is that the branch instruction in %branch references
+; a scalar evolution expression for which no useful value can be computed at the
+; location %branch, as the loop %loop does not terminate. At some point, we
+; did not identify the branch condition as non-affine during scop detection.
+; This test verifies that we either model the branch condition as non-affine
+; region (and return an empty scop) or only detect a smaller region if
+; non-affine conditions are not allowed.
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64--linux-android"
+
+define void @f(i16 %event, float* %A) {
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i8 [ 0, %entry ], [ %indvar.next, %loop ]
+  %indvar.next = add i8 %indvar, 1
+  %cmp = icmp eq i8 %indvar.next, 0
+  br i1 false, label %branch, label %loop
+
+branch:
+  br i1 %cmp, label %end, label %then
+
+then:
+  store float 1.0, float* %A
+  br label %end
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/bug_2010_10_22.ll b/final/test/ScopInfo/bug_2010_10_22.ll
new file mode 100644
index 0000000..687319e
--- /dev/null
+++ b/final/test/ScopInfo/bug_2010_10_22.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-scops < %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define fastcc void @_Z8wavModelR5Mixer() {
+entry:
+  br label %bb230
+
+bb230:                                            ; preds = %bb233, %bb.nph433
+  %indvar600 = phi i64 [ 0, %entry ], [ %tmp610, %bb233 ]
+  %tmp217 = add i64 %indvar600, -1
+  %tmp204 = trunc i64 %tmp217 to i32
+  %tmp205 = zext i32 %tmp204 to i64
+  %tmp206 = add i64 %tmp205, 1
+  %tmp610 = add i64 %indvar600, 1
+  br i1 false, label %bb231.preheader, label %bb233
+
+bb231.preheader:                                  ; preds = %bb230
+  br label %bb231
+
+bb231:                                            ; preds = %bb231, %bb231.preheader
+  %indvar589 = phi i64 [ %tmp611, %bb231 ], [ 0, %bb231.preheader ]
+  %tmp611 = add i64 %indvar589, 1
+  %exitcond207 = icmp eq i64 %tmp611, %tmp206
+  br i1 %exitcond207, label %bb233.loopexit, label %bb231
+
+bb233.loopexit:                                   ; preds = %bb231
+  br label %bb233
+
+bb233:                                            ; preds = %bb233.loopexit, %bb230
+  %exitcond213 = icmp eq i64 %tmp610, 0
+  br i1 %exitcond213, label %bb241, label %bb230
+
+bb241:                                            ; preds = %bb233, %bb228
+  br label %bb244.preheader
+
+bb244.preheader:                                  ; preds = %bb241, %bb176
+  br i1 undef, label %bb245, label %bb.nph416
+
+bb.nph416:                                        ; preds = %bb244.preheader
+  unreachable
+
+bb245:                                            ; preds = %bb244.preheader
+  ret void
+}
diff --git a/final/test/ScopInfo/bug_2011_1_5.ll b/final/test/ScopInfo/bug_2011_1_5.ll
new file mode 100644
index 0000000..8e36180
--- /dev/null
+++ b/final/test/ScopInfo/bug_2011_1_5.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s
+
+; Bug description: Alias Analysis thinks IntToPtrInst aliases with alloca instructions created by IndependentBlocks Pass.
+;                  This will trigger the assertion when we are verifying the SCoP after IndependentBlocks.
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+%struct.precisionType = type { i16, i16, i16, i8, [1 x i16] }
+
+define void @main() nounwind {
+entry:
+ br label %bb1.i198.i
+
+bb1.i198.i:                                       ; preds = %bb.i197.i, %psetq.exit196.i
+  %tmp51.i = inttoptr i64 0 to %struct.precisionType*
+  br i1 undef, label %bb1.i210.i, label %bb.i209.i
+
+bb.i209.i:                                        ; preds = %bb1.i198.i
+  br label %bb1.i210.i
+
+bb1.i210.i:                                       ; preds = %bb.i209.i, %bb1.i198.i
+  %0 = icmp eq i64 0, 0
+  br i1 %0, label %bb1.i216.i, label %bb.i215.i
+
+bb.i215.i:                                        ; preds = %bb1.i210.i
+  %1 = getelementptr inbounds %struct.precisionType, %struct.precisionType* %tmp51.i, i64 0, i32 0
+  store i16 undef, i16* %1, align 2
+  br label %bb1.i216.i
+
+bb1.i216.i:                                       ; preds = %bb.i215.i, %bb1.i210.i
+  br i1 undef, label %psetq.exit220.i, label %bb2.i217.i
+
+bb2.i217.i:                                       ; preds = %bb1.i216.i
+  br i1 undef, label %bb3.i218.i, label %psetq.exit220.i
+
+bb3.i218.i:                                       ; preds = %bb2.i217.i
+  br label %psetq.exit220.i
+
+psetq.exit220.i:                                  ; preds = %bb3.i218.i, %bb2.i217.i, %bb1.i216.i
+  br i1 undef, label %bb14.i76, label %bb15.i77
+
+bb14.i76:                                         ; preds = %psetq.exit220.i
+  unreachable
+
+bb15.i77:                                         ; preds = %psetq.exit220.i
+  br i1 %0, label %psetq.exit238.i, label %bb2.i235.i
+
+bb2.i235.i:                                       ; preds = %bb15.i77
+  br i1 undef, label %bb3.i236.i, label %psetq.exit238.i
+
+bb3.i236.i:                                       ; preds = %bb2.i235.i
+  unreachable
+
+psetq.exit238.i:                                  ; preds = %bb2.i235.i, %bb15.i77
+  unreachable
+
+bb56.i.loopexit:                                  ; preds = %psetq.exit172.i
+  unreachable
+}
diff --git a/final/test/ScopInfo/bug_scev_not_fully_eval.ll b/final/test/ScopInfo/bug_scev_not_fully_eval.ll
new file mode 100644
index 0000000..8f98a92
--- /dev/null
+++ b/final/test/ScopInfo/bug_scev_not_fully_eval.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -polly-detect -analyze  < %s | not FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@edge.8265 = external global [72 x i32], align 32 ; <[72 x i32]*> [#uses=1]
+
+define void @compact_unitcell_edges() nounwind {
+bb.nph19:
+  br label %bb4
+
+bb4:                                              ; preds = %bb4, %bb.nph19
+  %e.118 = phi i32 [ 0, %bb.nph19 ], [ %tmp23, %bb4 ] ; <i32> [#uses=1]
+  %i.017 = phi i32 [ 0, %bb.nph19 ], [ %0, %bb4 ] ; <i32> [#uses=1]
+  %tmp23 = add i32 %e.118, 8                      ; <i32> [#uses=2]
+  %0 = add nsw i32 %i.017, 1                      ; <i32> [#uses=2]
+  %exitcond42 = icmp eq i32 %0, 6                 ; <i1> [#uses=1]
+  br i1 %exitcond42, label %bb.nph, label %bb4
+
+bb.nph:                                           ; preds = %bb4
+  %tmp = sext i32 %tmp23 to i64                   ; <i64> [#uses=1]
+  br label %bb7
+
+bb7:                                              ; preds = %bb7, %bb.nph
+  %indvar = phi i64 [ 0, %bb.nph ], [ %indvar.next, %bb7 ] ; <i64> [#uses=2]
+  %tmp21 = add i64 %tmp, %indvar                  ; <i64> [#uses=1]
+  %scevgep = getelementptr [72 x i32], [72 x i32]* @edge.8265, i64 0, i64 %tmp21 ; <i32*> [#uses=1]
+  store i32 undef, i32* %scevgep, align 4
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br i1 undef, label %bb10, label %bb7
+
+bb10:                                             ; preds = %bb7
+  ret void
+}
+
+; CHECK: SCOP:
diff --git a/final/test/ScopInfo/cfg_consequences.ll b/final/test/ScopInfo/cfg_consequences.ll
new file mode 100644
index 0000000..30b2537
--- /dev/null
+++ b/final/test/ScopInfo/cfg_consequences.ll
@@ -0,0 +1,329 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s
+;
+; void consequences(int *A, int bool_cond, int lhs, int rhs) {
+;
+;   BC: *A = 0;
+;     if (bool_cond)
+;   S_BC:     *A = 0;
+;   M_BC: *A = 0;
+;
+;   NEG_BC: *A = 0;
+;     if (!bool_cond)
+;   S_NEG_BC: *A = 0;
+;   M_NEG_BC: *A = 0;
+;
+;   SLT: *A = 0;
+;     if (lhs < rhs)
+;   S_SLT:    *A = 0;
+;   M_SLT: *A = 0;
+;
+;   SLE: *A = 0;
+;     if (lhs <= rhs)
+;   S_SLE:    *A = 0;
+;   M_SLE: *A = 0;
+;
+;   SGT: *A = 0;
+;     if (lhs > rhs)
+;   S_SGT:    *A = 0;
+;   M_SGT: *A = 0;
+;
+;   SGE: *A = 0;
+;     if (lhs >= rhs)
+;   S_SGE:    *A = 0;
+;   M_SGE: *A = 0;
+;
+;   EQ: *A = 0;
+;     if (lhs == rhs)
+;   S_EQ:    *A = 0;
+;   M_EQ: *A = 0;
+;
+;   NEQ: *A = 0;
+;     if (lhs != rhs)
+;   S_NEQ:   *A = 0;
+;   M_NEQ: *A = 0;
+;
+; }
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_BC
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_BC[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_BC[] -> [0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_BC[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_S_BC
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_BC[] : bool_cond < 0 or bool_cond > 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_BC[] -> [1] : bool_cond < 0 or bool_cond > 0 };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_BC[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_M_BC
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_BC[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_BC[] -> [2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_BC[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_NEG_BC
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_NEG_BC[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_NEG_BC[] -> [3] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_NEG_BC[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_S_NEG_BC
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_NEG_BC[] : bool_cond = 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_NEG_BC[] -> [4] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_NEG_BC[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_M_NEG_BC
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_NEG_BC[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_NEG_BC[] -> [5] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_NEG_BC[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_SLT
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_SLT[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_SLT[] -> [6] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_SLT[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_S_SLT
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_SLT[] : rhs > lhs };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_SLT[] -> [7] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_SLT[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_M_SLT
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_SLT[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_SLT[] -> [8] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_SLT[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_SLE
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_SLE[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_SLE[] -> [9] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_SLE[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_S_SLE
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_SLE[] : rhs >= lhs };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_SLE[] -> [10] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_SLE[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_M_SLE
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_SLE[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_SLE[] -> [11] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_SLE[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_SGT
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_SGT[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_SGT[] -> [12] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_SGT[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_S_SGT
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_SGT[] : rhs < lhs };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_SGT[] -> [13] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_SGT[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_M_SGT
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_SGT[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_SGT[] -> [14] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_SGT[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_SGE
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_SGE[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_SGE[] -> [15] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_SGE[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_S_SGE
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_SGE[] : rhs <= lhs };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_SGE[] -> [16] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_SGE[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_M_SGE
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_SGE[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_SGE[] -> [17] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_SGE[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_EQ
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_EQ[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_EQ[] -> [18] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_EQ[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_S_EQ
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_EQ[] : rhs = lhs };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_EQ[] -> [19] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_EQ[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_M_EQ
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_EQ[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_EQ[] -> [20] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_EQ[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_NEQ
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_NEQ[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_NEQ[] -> [21] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_NEQ[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_S_NEQ
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_NEQ[] : rhs > lhs or rhs < lhs };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_NEQ[] -> [22] : rhs > lhs or rhs < lhs };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_S_NEQ[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_M_NEQ
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_NEQ[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_NEQ[] -> [23] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bool_cond, lhs, rhs] -> { Stmt_M_NEQ[] -> MemRef_A[0] };
+; CHECK-NEXT: }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @consequences(i32* %A, i32 %bool_cond, i32 %lhs, i32 %rhs) {
+entry:
+  br label %BC
+
+BC:                                               ; preds = %entry
+  store i32 0, i32* %A, align 4
+  %tobool = icmp eq i32 %bool_cond, 0
+  br i1 %tobool, label %M_BC, label %S_BC
+
+S_BC:                                             ; preds = %if.then
+  store i32 0, i32* %A, align 4
+  br label %M_BC
+
+M_BC:                                           ; preds = %BC, %S_BC
+  store i32 0, i32* %A, align 4
+  br label %NEG_BC
+
+NEG_BC:                                           ; preds = %if.end
+  store i32 0, i32* %A, align 4
+  %tobool1 = icmp eq i32 %bool_cond, 0
+  br i1 %tobool1, label %S_NEG_BC, label %M_NEG_BC
+
+S_NEG_BC:                                         ; preds = %if.then.2
+  store i32 0, i32* %A, align 4
+  br label %M_NEG_BC
+
+M_NEG_BC:                                         ; preds = %NEG_BC, %S_NEG_BC
+  store i32 0, i32* %A, align 4
+  br label %SLT
+
+SLT:                                              ; preds = %if.end.3
+  store i32 0, i32* %A, align 4
+  %cmp = icmp slt i32 %lhs, %rhs
+  br i1 %cmp, label %S_SLT, label %M_SLT
+
+S_SLT:                                            ; preds = %if.then.4
+  store i32 0, i32* %A, align 4
+  br label %M_SLT
+
+M_SLT:                                         ; preds = %S_SLT, %SLT
+  store i32 0, i32* %A, align 4
+  br label %SLE
+
+SLE:                                              ; preds = %if.end.5
+  store i32 0, i32* %A, align 4
+  %cmp6 = icmp sgt i32 %lhs, %rhs
+  br i1 %cmp6, label %M_SLE, label %S_SLE
+
+S_SLE:                                            ; preds = %if.then.7
+  store i32 0, i32* %A, align 4
+  br label %M_SLE
+
+M_SLE:                                         ; preds = %SLE, %S_SLE
+  store i32 0, i32* %A, align 4
+  br label %SGT
+
+SGT:                                              ; preds = %if.end.8
+  store i32 0, i32* %A, align 4
+  %cmp9 = icmp sgt i32 %lhs, %rhs
+  br i1 %cmp9, label %S_SGT, label %M_SGT
+
+S_SGT:                                            ; preds = %if.then.10
+  store i32 0, i32* %A, align 4
+  br label %M_SGT
+
+M_SGT:                                        ; preds = %S_SGT, %SGT
+  store i32 0, i32* %A, align 4
+  br label %SGE
+
+SGE:                                              ; preds = %if.end.11
+  store i32 0, i32* %A, align 4
+  %cmp12 = icmp slt i32 %lhs, %rhs
+  br i1 %cmp12, label %M_SGE, label %S_SGE
+
+S_SGE:                                            ; preds = %if.then.13
+  store i32 0, i32* %A, align 4
+  br label %M_SGE
+
+M_SGE:                                        ; preds = %SGE, %S_SGE
+  store i32 0, i32* %A, align 4
+  br label %EQ
+
+EQ:                                               ; preds = %if.end.14
+  store i32 0, i32* %A, align 4
+  %cmp15 = icmp eq i32 %lhs, %rhs
+  br i1 %cmp15, label %S_EQ, label %M_EQ
+
+S_EQ:                                             ; preds = %if.then.16
+  store i32 0, i32* %A, align 4
+  br label %M_EQ
+
+M_EQ:                                        ; preds = %S_EQ, %EQ
+  store i32 0, i32* %A, align 4
+  br label %NEQ
+
+NEQ:                                              ; preds = %if.end.17
+  store i32 0, i32* %A, align 4
+  %cmp18 = icmp eq i32 %lhs, %rhs
+  br i1 %cmp18, label %M_NEQ, label %S_NEQ
+
+S_NEQ:                                            ; preds = %if.then.19
+  store i32 0, i32* %A, align 4
+  br label %M_NEQ
+
+M_NEQ:                                        ; preds = %NEQ, %S_NEQ
+  store i32 0, i32* %A, align 4
+  br label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/complex-branch-structure.ll b/final/test/ScopInfo/complex-branch-structure.ll
new file mode 100644
index 0000000..1e08789
--- /dev/null
+++ b/final/test/ScopInfo/complex-branch-structure.ll
@@ -0,0 +1,195 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops \
+; RUN:     < %s 2>&1 | FileCheck %s
+
+; We build a scop of the following form to check that the domain construction
+; does not take a huge amount of time, but that we instead just bail out.
+;
+;       loop.header
+;      /    |    \ \
+;    A0    A2    A4 \
+;      \  /  \  /    \
+;       A1    A3      \
+;      /  \  /  \     |
+;    B0    B2    B4   |
+;      \  /  \  /     |
+;       B1    B3      ^
+;      /  \  /  \     |
+;    C0    C2    C4   |
+;      \  /  \  /    /
+;       C1    C3    /
+;        \   /     /
+;     loop backedge
+
+; CHECK: Low complexity assumption: {  : 1 = 0 }
+
+define void @foo(float* %A, float* %B, float* %C, float* %D, float* %E,
+                 i64 %A1.p, i64 %A2.p, i64 %A3.p,
+                 i64 %B1.p, i64 %B2.p, i64 %B3.p,
+                 i64 %C1.p, i64 %C2.p, i64 %C3.p,
+                 i64 %D1.p, i64 %D2.p, i64 %D3.p,
+                 i64 %E1.p, i64 %E2.p, i64 %E3.p) {
+entry:
+  br label %loop.header
+
+loop.header:
+  %indvar = phi i64 [0, %entry], [%indvar.next, %loop.backedge]
+  switch i2 0, label %A0 [i2 1, label %A2 i2 2, label %A4]
+
+A0:
+  %val.A0 = load float, float* %A
+  store float %val.A0, float* %A
+  br label %A1
+
+A2:
+  %val.A2 = load float, float* %A
+  store float %val.A2, float* %A
+  %A2.cmp = icmp eq i64 %A2.p, 0
+  br i1 %A2.cmp, label %A1, label %A3
+
+A4:
+  %val.A4 = load float, float* %A
+  store float %val.A4, float* %A
+  br label %A3
+
+A1:
+  %val.A1 = load float, float* %A
+  store float %val.A1, float* %A
+  %A1.cmp = icmp eq i64 %A1.p, 0
+  br i1 %A1.cmp, label %B0, label %B2
+
+A3:
+  %val.A3 = load float, float* %A
+  store float %val.A3, float* %A
+  %A3.cmp = icmp eq i64 %A3.p, 0
+  br i1 %A3.cmp, label %B2, label %B4
+
+B0:
+  %val.B0 = load float, float* %B
+  store float %val.B0, float* %B
+  br label %B1
+
+B2:
+  %val.B2 = load float, float* %B
+  store float %val.B2, float* %B
+  %B2.cmp = icmp eq i64 %B2.p, 0
+  br i1 %B2.cmp, label %B1, label %B3
+
+B4:
+  %val.B4 = load float, float* %B
+  store float %val.B4, float* %B
+  br label %B3
+
+B1:
+  %val.B1 = load float, float* %B
+  store float %val.B1, float* %B
+  %B1.cmp = icmp eq i64 %B1.p, 0
+  br i1 %B1.cmp, label %C0, label %C2
+
+B3:
+  %val.B3 = load float, float* %A
+  store float %val.B3, float* %A
+  %B3.cmp = icmp eq i64 %A3.p, 0
+  br i1 %B3.cmp, label %C2, label %C4
+
+C0:
+  %val.C0 = load float, float* %C
+  store float %val.C0, float* %C
+  br label %C1
+
+C2:
+  %val.C2 = load float, float* %C
+  store float %val.C2, float* %C
+  %C2.cmp = icmp eq i64 %C2.p, 0
+  br i1 %C2.cmp, label %C1, label %C3
+
+C4:
+  %val.C4 = load float, float* %C
+  store float %val.C4, float* %C
+  br label %C3
+
+C1:
+  %val.C1 = load float, float* %C
+  store float %val.C1, float* %C
+  %C1.cmp = icmp eq i64 %C1.p, 0
+  br i1 %C1.cmp, label %D0, label %D2
+
+C3:
+  %val.C3 = load float, float* %C
+  store float %val.C3, float* %C
+  %C3.cmp = icmp eq i64 %C3.p, 0
+  br i1 %C3.cmp, label %D2, label %D4
+
+D0:
+  %val.D0 = load float, float* %D
+  store float %val.D0, float* %D
+  br label %D1
+
+D2:
+  %val.D2 = load float, float* %D
+  store float %val.D2, float* %D
+  %D2.cmp = icmp eq i64 %D2.p, 0
+  br i1 %D2.cmp, label %D1, label %D3
+
+D4:
+  %val.D4 = load float, float* %D
+  store float %val.D4, float* %D
+  br label %D3
+
+D1:
+  %val.D1 = load float, float* %D
+  store float %val.D1, float* %D
+  %D1.cmp = icmp eq i64 %D1.p, 0
+  br i1 %D1.cmp, label %E0, label %E2
+
+D3:
+  %val.D3 = load float, float* %D
+  store float %val.D3, float* %D
+  %D3.cmp = icmp eq i64 %D3.p, 0
+  br i1 %D3.cmp, label %E2, label %E4
+
+E0:
+  %val.E0 = load float, float* %E
+  store float %val.E0, float* %E
+  br label %E1
+
+E2:
+  %val.E2 = load float, float* %E
+  store float %val.E2, float* %E
+  %E2.cmp = icmp eq i64 %E2.p, 0
+  br i1 %E2.cmp, label %E1, label %E3
+
+E4:
+  %val.E4 = load float, float* %E
+  store float %val.E4, float* %E
+  br label %E3
+
+E1:
+  %val.E1 = load float, float* %E
+  store float %val.E1, float* %E
+  %E1.cmp = icmp eq i64 %E1.p, 0
+  br i1 %E1.cmp, label %F0, label %F2
+
+E3:
+  %val.E3 = load float, float* %E
+  store float %val.E3, float* %E
+  %E3.cmp = icmp eq i64 %E3.p, 0
+  br i1 %E3.cmp, label %F2, label %F4
+
+F0:
+  br label %loop.backedge
+
+F2:
+  br label %loop.backedge
+
+F4:
+  br label %loop.backedge
+
+loop.backedge:
+  %indvar.next = add i64 %indvar, 1
+  %cmp = icmp ne i64 %indvar, 1000
+  br i1 %cmp, label %loop.header, label %exit
+
+exit:
+  ret void
+
+}
diff --git a/final/test/ScopInfo/complex-condition.ll b/final/test/ScopInfo/complex-condition.ll
new file mode 100644
index 0000000..45166c4
--- /dev/null
+++ b/final/test/ScopInfo/complex-condition.ll
@@ -0,0 +1,146 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN:     < %s 2>&1 | FileCheck %s
+;
+; CHECK: Low complexity assumption: {  : 1 = 0 }
+;
+; The IR is a modified version of the following C:
+;
+;    void f(int *A) {
+;    Begin:
+;      if (A[0] == 1 | A[1] == 1 | A[2] == 1 | A[3] == 1 | A[4] == 1 | A[5] == 1 |
+;          A[6] == 1 | A[7] == 1 | A[8] == 1 | A[9] == 1 | A[10] == 1 | A[11] == 1 |
+;          A[12] == 1 | A[13] == 1 | A[14] == 1 | A[15] == 1 | A[16] == 1 |
+;          A[17] == 1 | A[18] == 1 | A[19] == 1 | A[20] == 1 | A[21] == 1 |
+;          A[22] == 1 | A[23]) {
+;        A[-1]++;
+;      } else {
+;        A[-1]--;
+;      }
+;    End:
+;      return;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+entry:
+  br label %Begin
+
+Begin:                                            ; preds = %entry
+  %tmp = load i32, i32* %A, align 4
+  %cmp = icmp eq i32 %tmp, 1
+  %arrayidx1 = getelementptr inbounds i32, i32* %A, i64 1
+  %tmp1 = load i32, i32* %arrayidx1, align 4
+  %cmp2 = icmp eq i32 %tmp1, 1
+  %or = or i1 %cmp, %cmp2
+  %arrayidx4 = getelementptr inbounds i32, i32* %A, i64 2
+  %tmp2 = load i32, i32* %arrayidx4, align 4
+  %cmp5 = icmp eq i32 %tmp2, 1
+  %or7 = or i1 %or, %cmp5
+  %arrayidx8 = getelementptr inbounds i32, i32* %A, i64 3
+  %tmp3 = load i32, i32* %arrayidx8, align 4
+  %cmp9 = icmp eq i32 %tmp3, 1
+  %or11 = or i1 %or7, %cmp9
+  %arrayidx12 = getelementptr inbounds i32, i32* %A, i64 4
+  %tmp4 = load i32, i32* %arrayidx12, align 4
+  %cmp13 = icmp eq i32 %tmp4, 1
+  %or15 = or i1 %or11, %cmp13
+  %arrayidx16 = getelementptr inbounds i32, i32* %A, i64 5
+  %tmp5 = load i32, i32* %arrayidx16, align 4
+  %cmp17 = icmp eq i32 %tmp5, 1
+  %or19 = or i1 %or15, %cmp17
+  %arrayidx20 = getelementptr inbounds i32, i32* %A, i64 6
+  %tmp6 = load i32, i32* %arrayidx20, align 4
+  %cmp21 = icmp eq i32 %tmp6, 1
+  %or23 = or i1 %or19, %cmp21
+  %arrayidx24 = getelementptr inbounds i32, i32* %A, i64 7
+  %tmp7 = load i32, i32* %arrayidx24, align 4
+  %cmp25 = icmp eq i32 %tmp7, 1
+  %or27 = or i1 %or23, %cmp25
+  %arrayidx28 = getelementptr inbounds i32, i32* %A, i64 8
+  %tmp8 = load i32, i32* %arrayidx28, align 4
+  %cmp29 = icmp eq i32 %tmp8, 1
+  %or31 = or i1 %or27, %cmp29
+  %arrayidx32 = getelementptr inbounds i32, i32* %A, i64 9
+  %tmp9 = load i32, i32* %arrayidx32, align 4
+  %cmp33 = icmp eq i32 %tmp9, 1
+  %or35 = or i1 %or31, %cmp33
+  %arrayidx36 = getelementptr inbounds i32, i32* %A, i64 10
+  %tmp10 = load i32, i32* %arrayidx36, align 4
+  %cmp37 = icmp eq i32 %tmp10, 1
+  %or39 = or i1 %or35, %cmp37
+  %arrayidx40 = getelementptr inbounds i32, i32* %A, i64 11
+  %tmp11 = load i32, i32* %arrayidx40, align 4
+  %cmp41 = icmp eq i32 %tmp11, 1
+  %or43 = or i1 %or39, %cmp41
+  %arrayidx44 = getelementptr inbounds i32, i32* %A, i64 12
+  %tmp12 = load i32, i32* %arrayidx44, align 4
+  %cmp45 = icmp eq i32 %tmp12, 1
+  %or47 = or i1 %or43, %cmp45
+  %arrayidx48 = getelementptr inbounds i32, i32* %A, i64 13
+  %tmp13 = load i32, i32* %arrayidx48, align 4
+  %cmp49 = icmp eq i32 %tmp13, 1
+  %or51 = or i1 %or47, %cmp49
+  %arrayidx52 = getelementptr inbounds i32, i32* %A, i64 14
+  %tmp14 = load i32, i32* %arrayidx52, align 4
+  %cmp53 = icmp eq i32 %tmp14, 1
+  %or55 = or i1 %or51, %cmp53
+  %arrayidx56 = getelementptr inbounds i32, i32* %A, i64 15
+  %tmp15 = load i32, i32* %arrayidx56, align 4
+  %cmp57 = icmp eq i32 %tmp15, 1
+  %or59 = or i1 %or55, %cmp57
+  %arrayidx60 = getelementptr inbounds i32, i32* %A, i64 16
+  %tmp16 = load i32, i32* %arrayidx60, align 4
+  %cmp61 = icmp eq i32 %tmp16, 1
+  %or63 = or i1 %or59, %cmp61
+  %arrayidx64 = getelementptr inbounds i32, i32* %A, i64 17
+  %tmp17 = load i32, i32* %arrayidx64, align 4
+  %cmp65 = icmp eq i32 %tmp17, 1
+  %or67 = or i1 %or63, %cmp65
+  %arrayidx68 = getelementptr inbounds i32, i32* %A, i64 18
+  %tmp18 = load i32, i32* %arrayidx68, align 4
+  %cmp69 = icmp eq i32 %tmp18, 1
+  %or71 = or i1 %or67, %cmp69
+  %arrayidx72 = getelementptr inbounds i32, i32* %A, i64 19
+  %tmp19 = load i32, i32* %arrayidx72, align 4
+  %cmp73 = icmp eq i32 %tmp19, 1
+  %or75 = or i1 %or71, %cmp73
+  %arrayidx76 = getelementptr inbounds i32, i32* %A, i64 20
+  %tmp20 = load i32, i32* %arrayidx76, align 4
+  %cmp77 = icmp eq i32 %tmp20, 1
+  %or79 = or i1 %or75, %cmp77
+  %arrayidx80 = getelementptr inbounds i32, i32* %A, i64 21
+  %tmp21 = load i32, i32* %arrayidx80, align 4
+  %cmp81 = icmp eq i32 %tmp21, 1
+  %or83 = or i1 %or79, %cmp81
+  %arrayidx84 = getelementptr inbounds i32, i32* %A, i64 22
+  %tmp22 = load i32, i32* %arrayidx84, align 4
+  %cmp85 = icmp eq i32 %tmp22, 1
+  %or87 = or i1 %or83, %cmp85
+  %arrayidx88 = getelementptr inbounds i32, i32* %A, i64 23
+  %tmp23 = load i32, i32* %arrayidx88, align 4
+  %cmp88 = icmp eq i32 %tmp23, 1
+  %or89 = or i1 %or87, %cmp88
+  br i1 %or89, label %if.else, label %if.then
+
+if.then:                                          ; preds = %Begin
+  %arrayidx90 = getelementptr inbounds i32, i32* %A, i64 -1
+  %tmp24 = load i32, i32* %arrayidx90, align 4
+  %inc = add nsw i32 %tmp24, 1
+  store i32 %inc, i32* %arrayidx90, align 4
+  br label %if.end
+
+if.else:                                          ; preds = %Begin
+  %arrayidx91 = getelementptr inbounds i32, i32* %A, i64 -1
+  %tmp25 = load i32, i32* %arrayidx91, align 4
+  %dec = add nsw i32 %tmp25, -1
+  store i32 %dec, i32* %arrayidx91, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  br label %End
+
+End:                                              ; preds = %if.end
+  ret void
+}
diff --git a/final/test/ScopInfo/complex-expression.ll b/final/test/ScopInfo/complex-expression.ll
new file mode 100644
index 0000000..11e2516
--- /dev/null
+++ b/final/test/ScopInfo/complex-expression.ll
@@ -0,0 +1,143 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN:     < %s 2>&1 | FileCheck %s
+;
+; This test case has an SCEVSMax expression with a very high arity. The
+; piecewise affine function we would create for it would have a huge amount of
+; conjuncts, thus it would take a lot of time creating and handling it.
+;
+; This ensures we bail out for really complex expressions:
+;
+; CHECK: Low complexity assumption: {  : 1 = 0 }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+
+; Function Attrs: norecurse nounwind
+define i32 @foo(i32* nocapture readonly %src1, i32* nocapture readonly %src2, i32* nocapture %score, i32* nocapture %max, i32 %n) #0 {
+entry:
+  %cmp33 = icmp sgt i32 %n, 0
+  br i1 %cmp33, label %for.body.preheader, label %for.body7.preheader
+
+for.body.preheader:                               ; preds = %entry
+  br label %for.body
+
+for.body7.preheader.loopexit:                     ; preds = %for.body
+  br label %for.body7.preheader
+
+for.body7.preheader:                              ; preds = %for.body7.preheader.loopexit, %entry
+  %0 = load i32, i32* %score, align 4, !tbaa !3
+  %cmp9 = icmp sgt i32 %0, -1
+  %.scoreMax.0 = select i1 %cmp9, i32 %0, i32 -1
+  %arrayidx8.1 = getelementptr inbounds i32, i32* %score, i32 1
+  %1 = load i32, i32* %arrayidx8.1, align 4, !tbaa !3
+  %cmp9.1 = icmp sgt i32 %1, %.scoreMax.0
+  %.scoreMax.0.1 = select i1 %cmp9.1, i32 %1, i32 %.scoreMax.0
+  %arrayidx8.2 = getelementptr inbounds i32, i32* %score, i32 2
+  %2 = load i32, i32* %arrayidx8.2, align 4, !tbaa !3
+  %cmp9.2 = icmp sgt i32 %2, %.scoreMax.0.1
+  %.scoreMax.0.2 = select i1 %cmp9.2, i32 %2, i32 %.scoreMax.0.1
+  %arrayidx8.3 = getelementptr inbounds i32, i32* %score, i32 3
+  %3 = load i32, i32* %arrayidx8.3, align 4, !tbaa !3
+  %cmp9.3 = icmp sgt i32 %3, %.scoreMax.0.2
+  %.scoreMax.0.3 = select i1 %cmp9.3, i32 %3, i32 %.scoreMax.0.2
+  %arrayidx8.4 = getelementptr inbounds i32, i32* %score, i32 4
+  %4 = load i32, i32* %arrayidx8.4, align 4, !tbaa !3
+  %cmp9.4 = icmp sgt i32 %4, %.scoreMax.0.3
+  %.scoreMax.0.4 = select i1 %cmp9.4, i32 %4, i32 %.scoreMax.0.3
+  %arrayidx8.5 = getelementptr inbounds i32, i32* %score, i32 5
+  %5 = load i32, i32* %arrayidx8.5, align 4, !tbaa !3
+  %cmp9.5 = icmp sgt i32 %5, %.scoreMax.0.4
+  %.scoreMax.0.5 = select i1 %cmp9.5, i32 %5, i32 %.scoreMax.0.4
+  %arrayidx8.6 = getelementptr inbounds i32, i32* %score, i32 6
+  %6 = load i32, i32* %arrayidx8.6, align 4, !tbaa !3
+  %cmp9.6 = icmp sgt i32 %6, %.scoreMax.0.5
+  %.scoreMax.0.6 = select i1 %cmp9.6, i32 %6, i32 %.scoreMax.0.5
+  %arrayidx8.7 = getelementptr inbounds i32, i32* %score, i32 7
+  %7 = load i32, i32* %arrayidx8.7, align 4, !tbaa !3
+  %cmp9.7 = icmp sgt i32 %7, %.scoreMax.0.6
+  %.scoreMax.0.7 = select i1 %cmp9.7, i32 %7, i32 %.scoreMax.0.6
+  %arrayidx8.8 = getelementptr inbounds i32, i32* %score, i32 8
+  %8 = load i32, i32* %arrayidx8.8, align 4, !tbaa !3
+  %cmp9.8 = icmp sgt i32 %8, %.scoreMax.0.7
+  %.scoreMax.0.8 = select i1 %cmp9.8, i32 %8, i32 %.scoreMax.0.7
+  %arrayidx8.9 = getelementptr inbounds i32, i32* %score, i32 9
+  %9 = load i32, i32* %arrayidx8.9, align 4, !tbaa !3
+  %cmp9.9 = icmp sgt i32 %9, %.scoreMax.0.8
+  %.scoreMax.0.9 = select i1 %cmp9.9, i32 %9, i32 %.scoreMax.0.8
+  %arrayidx8.10 = getelementptr inbounds i32, i32* %score, i32 10
+  %10 = load i32, i32* %arrayidx8.10, align 4, !tbaa !3
+  %cmp9.10 = icmp sgt i32 %10, %.scoreMax.0.9
+  %.scoreMax.0.10 = select i1 %cmp9.10, i32 %10, i32 %.scoreMax.0.9
+  %arrayidx8.11 = getelementptr inbounds i32, i32* %score, i32 11
+  %11 = load i32, i32* %arrayidx8.11, align 4, !tbaa !3
+  %cmp9.11 = icmp sgt i32 %11, %.scoreMax.0.10
+  %.scoreMax.0.11 = select i1 %cmp9.11, i32 %11, i32 %.scoreMax.0.10
+  %arrayidx8.12 = getelementptr inbounds i32, i32* %score, i32 12
+  %12 = load i32, i32* %arrayidx8.12, align 4, !tbaa !3
+  %cmp9.12 = icmp sgt i32 %12, %.scoreMax.0.11
+  %.scoreMax.0.12 = select i1 %cmp9.12, i32 %12, i32 %.scoreMax.0.11
+  %arrayidx8.13 = getelementptr inbounds i32, i32* %score, i32 13
+  %13 = load i32, i32* %arrayidx8.13, align 4, !tbaa !3
+  %cmp9.13 = icmp sgt i32 %13, %.scoreMax.0.12
+  %.scoreMax.0.13 = select i1 %cmp9.13, i32 %13, i32 %.scoreMax.0.12
+  %arrayidx8.14 = getelementptr inbounds i32, i32* %score, i32 14
+  %14 = load i32, i32* %arrayidx8.14, align 4, !tbaa !3
+  %cmp9.14 = icmp sgt i32 %14, %.scoreMax.0.13
+  %.scoreMax.0.14 = select i1 %cmp9.14, i32 %14, i32 %.scoreMax.0.13
+  %arrayidx8.15 = getelementptr inbounds i32, i32* %score, i32 15
+  %15 = load i32, i32* %arrayidx8.15, align 4, !tbaa !3
+  %cmp9.15 = icmp sgt i32 %15, %.scoreMax.0.14
+  %.scoreMax.0.15 = select i1 %cmp9.15, i32 %15, i32 %.scoreMax.0.14
+  %arrayidx8.16 = getelementptr inbounds i32, i32* %score, i32 16
+  %16 = load i32, i32* %arrayidx8.16, align 4, !tbaa !3
+  %cmp9.16 = icmp sgt i32 %16, %.scoreMax.0.15
+  %.scoreMax.0.16 = select i1 %cmp9.16, i32 %16, i32 %.scoreMax.0.15
+  %arrayidx8.17 = getelementptr inbounds i32, i32* %score, i32 17
+  %17 = load i32, i32* %arrayidx8.17, align 4, !tbaa !3
+  %cmp9.17 = icmp sgt i32 %17, %.scoreMax.0.16
+  %.scoreMax.0.17 = select i1 %cmp9.17, i32 %17, i32 %.scoreMax.0.16
+  %arrayidx8.18 = getelementptr inbounds i32, i32* %score, i32 18
+  %18 = load i32, i32* %arrayidx8.18, align 4, !tbaa !3
+  %cmp9.18 = icmp sgt i32 %18, %.scoreMax.0.17
+  %.scoreMax.0.18 = select i1 %cmp9.18, i32 %18, i32 %.scoreMax.0.17
+  %arrayidx8.19 = getelementptr inbounds i32, i32* %score, i32 19
+  %19 = load i32, i32* %arrayidx8.19, align 4, !tbaa !3
+  %cmp9.19 = icmp sgt i32 %19, %.scoreMax.0.18
+  %.scoreMax.0.19 = select i1 %cmp9.19, i32 %19, i32 %.scoreMax.0.18
+  %cmp14 = icmp eq i32 %.scoreMax.0.19, -1
+  br i1 %cmp14, label %cleanup, label %if.end16
+
+for.body:                                         ; preds = %for.body.preheader, %for.body
+  %i.034 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ]
+  %arrayidx = getelementptr inbounds i32, i32* %src1, i32 %i.034
+  %20 = load i32, i32* %arrayidx, align 4, !tbaa !3
+  %arrayidx1 = getelementptr inbounds i32, i32* %src2, i32 %i.034
+  %21 = load i32, i32* %arrayidx1, align 4, !tbaa !3
+  %add = add nsw i32 %21, %20
+  %arrayidx2 = getelementptr inbounds i32, i32* %score, i32 %i.034
+  store i32 %add, i32* %arrayidx2, align 4, !tbaa !3
+  %inc = add nuw nsw i32 %i.034, 1
+  %exitcond = icmp eq i32 %inc, %n
+  br i1 %exitcond, label %for.body7.preheader.loopexit, label %for.body
+
+if.end16:                                         ; preds = %for.body7.preheader
+  store i32 %.scoreMax.0.19, i32* %max, align 4, !tbaa !3
+  br label %cleanup
+
+cleanup:                                          ; preds = %for.body7.preheader, %if.end16
+  %retval.0 = phi i32 [ 1, %if.end16 ], [ 0, %for.body7.preheader ]
+  ret i32 %retval.0
+}
+
+attributes #0 = { norecurse nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="arm7tdmi" "target-features"="+strict-align" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"min_enum_size", i32 4}
+!2 = !{!"clang version 3.9.0 (http://llvm.org/git/clang.git 24028ac5d033be4c1e87ce65affb4ea61deb1897) (http://llvm.org/git/llvm.git b88337289681d6ede5bba5da77007c83509e54ae)"}
+!3 = !{!4, !4, i64 0}
+!4 = !{!"int", !5, i64 0}
+!5 = !{!"omnipotent char", !6, i64 0}
+!6 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/ScopInfo/complex-loop-nesting.ll b/final/test/ScopInfo/complex-loop-nesting.ll
new file mode 100644
index 0000000..28797fa
--- /dev/null
+++ b/final/test/ScopInfo/complex-loop-nesting.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body_outer
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_for_body_outer[i0] : 0 <= i0 <= 257 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_for_body_outer[i0] -> [i0, 0, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body_outer[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body_outer[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_for_body[257, i1] : 0 <= i1 <= 1025; Stmt_for_body[i0, 0] : 0 <= i0 <= 256 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_for_body[257, i1] -> [257, 1, i1, 0]; Stmt_for_body[i0, 0] -> [i0, 1, 0, 0] : i0 <= 256 };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body[i0, i1] -> MemRef_A[i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body[i0, i1] -> MemRef_A[i1] };
+; CHECK-NEXT:     Stmt_for_inc
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_for_inc[257, i1] : 0 <= i1 <= 1025 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_for_inc[i0, i1] -> [257, 1, i1, 1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_inc[i0, i1] -> MemRef_A[i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_inc[i0, i1] -> MemRef_A[i1] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-i128:128-n8:16:32:64-S128"
+
+define void @foo(i32* %A) {
+entry:
+  br label %for.body.outer
+
+for.body.outer:                                   ; preds = %for.body, %entry
+  %indvar = phi i32 [0, %entry], [%indvar.next, %for.body]
+  %addr = getelementptr i32, i32* %A, i32 %indvar
+  %val = load i32, i32* %addr
+  %indvar.next = add i32 %indvar, 1
+  store i32 %val, i32* %addr
+  br label %for.body
+
+for.body:                                         ; preds = %for.inc, %for.body.outer
+  %indvar.2 = phi i32 [0, %for.body.outer], [%indvar.2.next, %for.inc]
+  %addr.2 = getelementptr i32, i32* %A, i32 %indvar.2
+  %val.2  = load i32, i32* %addr.2
+  %indvar.2.next = add i32 %indvar.2, 1
+  store i32 %val.2, i32* %addr.2
+  %cond.1 = icmp sle i32 %indvar, 256
+  br i1 %cond.1, label %for.body.outer, label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %addr.3 = getelementptr i32, i32* %A, i32 %indvar.2
+  %val.3  = load i32, i32* %addr.3
+  store i32 %val.3, i32* %addr.3
+  %cond = icmp sle i32 %indvar.2, 1024
+  br i1 %cond, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.inc
+  ret void
+}
diff --git a/final/test/ScopInfo/complex-successor-structure-2.ll b/final/test/ScopInfo/complex-successor-structure-2.ll
new file mode 100644
index 0000000..c85c89e
--- /dev/null
+++ b/final/test/ScopInfo/complex-successor-structure-2.ll
@@ -0,0 +1,539 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN:     < %s 2>&1 | FileCheck %s
+
+; We build a scop for the region for.body->B13. The CFG is of the following
+; form and the branch conditions are build from "smax" SCEVs. However, in
+; contrast to complex-success-structure.ll the smax constraints do not grow
+; anymore after B3. This will keep the condition construction bounded.
+; Since we propagate the domains from one B(X) to the B(X+1) we can also keep
+; the domains simple. We will bail anyway due to invalid required invariant
+; loads.
+;
+; CHECK-NOT: Low complexity assumption
+;
+;      |
+;    for.body <--+
+;      |         |
+;      |---------+
+;      |
+;     \ /
+;    if.entry --+
+;      |        |
+;      A0       |
+;      |        |
+;      B0 <-----+
+;      |  \
+;      |   \
+;      A1   \
+;      |    |
+;      |    |
+;      B1<--+
+;      |  \
+;      |   \
+;      A2   \
+;      |    |
+;      |    |
+;      B2<--+
+;      |  \
+;      |   \
+;      A3   \
+;      |    |
+;      |    |
+;      B3<--+
+;      |  \
+;      |   \
+;      A4   \
+;      |    |
+;      |    |
+;      B4<--+
+;      |  \
+;      |   \
+;      A5   \
+;      |    |
+;      |    |
+;      B5<--+
+;      |  \
+;      |   \
+;      A6   \
+;      |    |
+;      |    |
+;      B6<--+
+;      |  \
+;      |   \
+;      A7   \
+;      |    |
+;      |    |
+;      B7<--+
+;      |  \
+;      |   \
+;      A8   \
+;      |    |
+;      |    |
+;      B8<--+
+;      |  \
+;      |   \
+;      A9   \
+;      |    |
+;      |    |
+;      B9<--+
+;      |  \
+;      |   \
+;      A10  \
+;      |    |
+;      |    |
+;      B10<-+
+;      |  \
+;      |   \
+;      A11  \
+;      |    |
+;      |    |
+;      B11<-+
+;      |  \
+;      |   \
+;      A12  \
+;      |    |
+;      |    |
+;      B12<-+
+;      |  \
+;      |   \
+;      A13  \
+;      |    |
+;      |    |
+;      B13<-+
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n8:16:32-S64"
+target triple = "thumbv7--linux-android"
+
+@Table1 = external global [2304 x i16], align 2
+@Table2 = external global [1792 x i16], align 2
+@Table3 = external global [16 x i16], align 2
+
+define void @foo(i16* nocapture readonly %indice, i16* nocapture %Output, i16* nocapture readonly %In1, i16* nocapture readonly %In2, i16 signext %var, i16 signext %var2) {
+entry:
+  %.reg2mem158 = alloca i16
+  %.reg2mem156 = alloca i16
+  %.reg2mem154 = alloca i16
+  %.reg2mem152 = alloca i16
+  %.reg2mem150 = alloca i16
+  %.reg2mem = alloca i16
+  %Temp_Ref = alloca [16 x i16], align 2
+  %0 = bitcast [16 x i16]* %Temp_Ref to i8*
+  %cmp = icmp eq i16 %var, 0
+  br label %for.body
+
+for.body:                                       ; preds = %for.body, %entry
+  %i.2138 = phi i32 [ %inc47, %for.body ], [ 0, %entry ]
+  %arrayidx28 = getelementptr inbounds [16 x i16], [16 x i16]* @Table3, i32 0, i32 %i.2138
+  %1 = load i16, i16* %arrayidx28, align 2
+  %conv29 = sext i16 %1 to i32
+  %arrayidx36 = getelementptr inbounds i16, i16* %In2, i32 %i.2138
+  %2 = load i16, i16* %arrayidx36, align 2
+  %conv37 = sext i16 %2 to i32
+  %shl38147 = add nsw i32 %conv37, %conv29
+  %add35.1 = add nuw nsw i32 %i.2138, 16
+  %arrayidx36.1 = getelementptr inbounds i16, i16* %In2, i32 %add35.1
+  %3 = load i16, i16* %arrayidx36.1, align 2
+  %conv37.1 = sext i16 %3 to i32
+  %shl38.1148 = add nsw i32 %conv37.1, %shl38147
+  %add35.2 = add nuw nsw i32 %i.2138, 32
+  %arrayidx36.2 = getelementptr inbounds i16, i16* %In2, i32 %add35.2
+  %4 = load i16, i16* %arrayidx36.2, align 2
+  %conv37.2 = sext i16 %4 to i32
+  %shl38.2149 = add nsw i32 %conv37.2, %shl38.1148
+  %add39.2 = shl i32 %shl38.2149, 14
+  %add43 = add nsw i32 %add39.2, 32768
+  %shr129 = lshr i32 %add43, 16
+  %conv44 = trunc i32 %shr129 to i16
+  %arrayidx45 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 %i.2138
+  store i16 %conv44, i16* %arrayidx45, align 2
+  %inc47 = add nuw nsw i32 %i.2138, 1
+  %exitcond144 = icmp eq i32 %i.2138, 15
+  br i1 %exitcond144, label %if.entry, label %for.body
+
+if.entry:                             ; preds = %for.body
+  %5 = load i16, i16* %In1, align 2
+  %conv54 = sext i16 %5 to i32
+  %mul55 = mul nsw i32 %conv54, 29491
+  %shr56127 = lshr i32 %mul55, 15
+  %arrayidx57 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 0
+  %6 = load i16, i16* %arrayidx57, align 2
+  %conv58 = sext i16 %6 to i32
+  %mul59 = mul nsw i32 %conv58, 3277
+  %shr60128 = lshr i32 %mul59, 15
+  %add61 = add nuw nsw i32 %shr60128, %shr56127
+  %conv62 = trunc i32 %add61 to i16
+  store i16 %conv62, i16* %Output, align 2
+  %arrayidx53.1 = getelementptr inbounds i16, i16* %In1, i32 1
+  %7 = load i16, i16* %arrayidx53.1, align 2
+  %conv54.1 = sext i16 %7 to i32
+  %mul55.1 = mul nsw i32 %conv54.1, 29491
+  %shr56127.1 = lshr i32 %mul55.1, 15
+  %arrayidx57.1 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 1
+  %8 = load i16, i16* %arrayidx57.1, align 2
+  %conv58.1 = sext i16 %8 to i32
+  %mul59.1 = mul nsw i32 %conv58.1, 3277
+  %shr60128.1 = lshr i32 %mul59.1, 15
+  %add61.1 = add nuw nsw i32 %shr60128.1, %shr56127.1
+  %conv62.1 = trunc i32 %add61.1 to i16
+  %arrayidx63.1 = getelementptr inbounds i16, i16* %Output, i32 1
+  store i16 %conv62.1, i16* %arrayidx63.1, align 2
+  %arrayidx53.2 = getelementptr inbounds i16, i16* %In1, i32 2
+  %9 = load i16, i16* %arrayidx53.2, align 2
+  %conv54.2 = sext i16 %9 to i32
+  %mul55.2 = mul nsw i32 %conv54.2, 29491
+  %shr56127.2 = lshr i32 %mul55.2, 15
+  %arrayidx57.2 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 2
+  %10 = load i16, i16* %arrayidx57.2, align 2
+  %conv58.2 = sext i16 %10 to i32
+  %mul59.2 = mul nsw i32 %conv58.2, 3277
+  %shr60128.2 = lshr i32 %mul59.2, 15
+  %add61.2 = add nuw nsw i32 %shr60128.2, %shr56127.2
+  %conv62.2 = trunc i32 %add61.2 to i16
+  %arrayidx63.2 = getelementptr inbounds i16, i16* %Output, i32 2
+  store i16 %conv62.2, i16* %arrayidx63.2, align 2
+  %arrayidx53.3 = getelementptr inbounds i16, i16* %In1, i32 3
+  %11 = load i16, i16* %arrayidx53.3, align 2
+  %conv54.3 = sext i16 %11 to i32
+  %mul55.3 = mul nsw i32 %conv54.3, 29491
+  %shr56127.3 = lshr i32 %mul55.3, 15
+  %arrayidx57.3 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 3
+  %12 = load i16, i16* %arrayidx57.3, align 2
+  %conv58.3 = sext i16 %12 to i32
+  %mul59.3 = mul nsw i32 %conv58.3, 3277
+  %shr60128.3 = lshr i32 %mul59.3, 15
+  %add61.3 = add nuw nsw i32 %shr60128.3, %shr56127.3
+  %conv62.3 = trunc i32 %add61.3 to i16
+  %arrayidx63.3 = getelementptr inbounds i16, i16* %Output, i32 3
+  store i16 %conv62.3, i16* %arrayidx63.3, align 2
+  %arrayidx53.4 = getelementptr inbounds i16, i16* %In1, i32 4
+  %13 = load i16, i16* %arrayidx53.4, align 2
+  %conv54.4 = sext i16 %13 to i32
+  %mul55.4 = mul nsw i32 %conv54.4, 29491
+  %shr56127.4 = lshr i32 %mul55.4, 15
+  %arrayidx57.4 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 4
+  %14 = load i16, i16* %arrayidx57.4, align 2
+  %conv58.4 = sext i16 %14 to i32
+  %mul59.4 = mul nsw i32 %conv58.4, 3277
+  %shr60128.4 = lshr i32 %mul59.4, 15
+  %add61.4 = add nuw nsw i32 %shr60128.4, %shr56127.4
+  %conv62.4 = trunc i32 %add61.4 to i16
+  %arrayidx63.4 = getelementptr inbounds i16, i16* %Output, i32 4
+  store i16 %conv62.4, i16* %arrayidx63.4, align 2
+  %arrayidx53.5 = getelementptr inbounds i16, i16* %In1, i32 5
+  %15 = load i16, i16* %arrayidx53.5, align 2
+  %conv54.5 = sext i16 %15 to i32
+  %mul55.5 = mul nsw i32 %conv54.5, 29491
+  %shr56127.5 = lshr i32 %mul55.5, 15
+  %arrayidx57.5 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 5
+  %16 = load i16, i16* %arrayidx57.5, align 2
+  %conv58.5 = sext i16 %16 to i32
+  %mul59.5 = mul nsw i32 %conv58.5, 3277
+  %shr60128.5 = lshr i32 %mul59.5, 15
+  %add61.5 = add nuw nsw i32 %shr60128.5, %shr56127.5
+  %conv62.5 = trunc i32 %add61.5 to i16
+  %arrayidx63.5 = getelementptr inbounds i16, i16* %Output, i32 5
+  store i16 %conv62.5, i16* %arrayidx63.5, align 2
+  %arrayidx53.6 = getelementptr inbounds i16, i16* %In1, i32 6
+  %17 = load i16, i16* %arrayidx53.6, align 2
+  %conv54.6 = sext i16 %17 to i32
+  %mul55.6 = mul nsw i32 %conv54.6, 29491
+  %shr56127.6 = lshr i32 %mul55.6, 15
+  %arrayidx57.6 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 6
+  %18 = load i16, i16* %arrayidx57.6, align 2
+  %conv58.6 = sext i16 %18 to i32
+  %mul59.6 = mul nsw i32 %conv58.6, 3277
+  %shr60128.6 = lshr i32 %mul59.6, 15
+  %add61.6 = add nuw nsw i32 %shr60128.6, %shr56127.6
+  %conv62.6 = trunc i32 %add61.6 to i16
+  %arrayidx63.6 = getelementptr inbounds i16, i16* %Output, i32 6
+  store i16 %conv62.6, i16* %arrayidx63.6, align 2
+  %arrayidx53.7 = getelementptr inbounds i16, i16* %In1, i32 7
+  %19 = load i16, i16* %arrayidx53.7, align 2
+  %conv54.7 = sext i16 %19 to i32
+  %mul55.7 = mul nsw i32 %conv54.7, 29491
+  %shr56127.7 = lshr i32 %mul55.7, 15
+  %arrayidx57.7 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 7
+  %20 = load i16, i16* %arrayidx57.7, align 2
+  %conv58.7 = sext i16 %20 to i32
+  %mul59.7 = mul nsw i32 %conv58.7, 3277
+  %shr60128.7 = lshr i32 %mul59.7, 15
+  %add61.7 = add nuw nsw i32 %shr60128.7, %shr56127.7
+  %conv62.7 = trunc i32 %add61.7 to i16
+  %arrayidx63.7 = getelementptr inbounds i16, i16* %Output, i32 7
+  store i16 %conv62.7, i16* %arrayidx63.7, align 2
+  %arrayidx53.8 = getelementptr inbounds i16, i16* %In1, i32 8
+  %21 = load i16, i16* %arrayidx53.8, align 2
+  %conv54.8 = sext i16 %21 to i32
+  %mul55.8 = mul nsw i32 %conv54.8, 29491
+  %shr56127.8 = lshr i32 %mul55.8, 15
+  %arrayidx57.8 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 8
+  %22 = load i16, i16* %arrayidx57.8, align 2
+  %conv58.8 = sext i16 %22 to i32
+  %mul59.8 = mul nsw i32 %conv58.8, 3277
+  %shr60128.8 = lshr i32 %mul59.8, 15
+  %add61.8 = add nuw nsw i32 %shr60128.8, %shr56127.8
+  %conv62.8 = trunc i32 %add61.8 to i16
+  %arrayidx63.8 = getelementptr inbounds i16, i16* %Output, i32 8
+  store i16 %conv62.8, i16* %arrayidx63.8, align 2
+  %arrayidx53.9 = getelementptr inbounds i16, i16* %In1, i32 9
+  %23 = load i16, i16* %arrayidx53.9, align 2
+  %conv54.9 = sext i16 %23 to i32
+  %mul55.9 = mul nsw i32 %conv54.9, 29491
+  %shr56127.9 = lshr i32 %mul55.9, 15
+  %arrayidx57.9 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 9
+  %24 = load i16, i16* %arrayidx57.9, align 2
+  %conv58.9 = sext i16 %24 to i32
+  %mul59.9 = mul nsw i32 %conv58.9, 3277
+  %shr60128.9 = lshr i32 %mul59.9, 15
+  %add61.9 = add nuw nsw i32 %shr60128.9, %shr56127.9
+  %conv62.9 = trunc i32 %add61.9 to i16
+  %arrayidx63.9 = getelementptr inbounds i16, i16* %Output, i32 9
+  store i16 %conv62.9, i16* %arrayidx63.9, align 2
+  %arrayidx53.10 = getelementptr inbounds i16, i16* %In1, i32 10
+  %25 = load i16, i16* %arrayidx53.10, align 2
+  %conv54.10 = sext i16 %25 to i32
+  %mul55.10 = mul nsw i32 %conv54.10, 29491
+  %shr56127.10 = lshr i32 %mul55.10, 15
+  %arrayidx57.10 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 10
+  %26 = load i16, i16* %arrayidx57.10, align 2
+  %conv58.10 = sext i16 %26 to i32
+  %mul59.10 = mul nsw i32 %conv58.10, 3277
+  %shr60128.10 = lshr i32 %mul59.10, 15
+  %add61.10 = add nuw nsw i32 %shr60128.10, %shr56127.10
+  %conv62.10 = trunc i32 %add61.10 to i16
+  %arrayidx63.10 = getelementptr inbounds i16, i16* %Output, i32 10
+  store i16 %conv62.10, i16* %arrayidx63.10, align 2
+  %arrayidx53.11 = getelementptr inbounds i16, i16* %In1, i32 11
+  %27 = load i16, i16* %arrayidx53.11, align 2
+  %conv54.11 = sext i16 %27 to i32
+  %mul55.11 = mul nsw i32 %conv54.11, 29491
+  %shr56127.11 = lshr i32 %mul55.11, 15
+  %arrayidx57.11 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 11
+  %28 = load i16, i16* %arrayidx57.11, align 2
+  %conv58.11 = sext i16 %28 to i32
+  %mul59.11 = mul nsw i32 %conv58.11, 3277
+  %shr60128.11 = lshr i32 %mul59.11, 15
+  %add61.11 = add nuw nsw i32 %shr60128.11, %shr56127.11
+  %conv62.11 = trunc i32 %add61.11 to i16
+  %arrayidx63.11 = getelementptr inbounds i16, i16* %Output, i32 11
+  store i16 %conv62.11, i16* %arrayidx63.11, align 2
+  %arrayidx53.12 = getelementptr inbounds i16, i16* %In1, i32 12
+  %29 = load i16, i16* %arrayidx53.12, align 2
+  %conv54.12 = sext i16 %29 to i32
+  %mul55.12 = mul nsw i32 %conv54.12, 29491
+  %shr56127.12 = lshr i32 %mul55.12, 15
+  %arrayidx57.12 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 12
+  %30 = load i16, i16* %arrayidx57.12, align 2
+  %conv58.12 = sext i16 %30 to i32
+  %mul59.12 = mul nsw i32 %conv58.12, 3277
+  %shr60128.12 = lshr i32 %mul59.12, 15
+  %add61.12 = add nuw nsw i32 %shr60128.12, %shr56127.12
+  %conv62.12 = trunc i32 %add61.12 to i16
+  %arrayidx63.12 = getelementptr inbounds i16, i16* %Output, i32 12
+  store i16 %conv62.12, i16* %arrayidx63.12, align 2
+  %arrayidx53.13 = getelementptr inbounds i16, i16* %In1, i32 13
+  %31 = load i16, i16* %arrayidx53.13, align 2
+  %conv54.13 = sext i16 %31 to i32
+  %mul55.13 = mul nsw i32 %conv54.13, 29491
+  %shr56127.13 = lshr i32 %mul55.13, 15
+  %arrayidx57.13 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 13
+  %32 = load i16, i16* %arrayidx57.13, align 2
+  %conv58.13 = sext i16 %32 to i32
+  %mul59.13 = mul nsw i32 %conv58.13, 3277
+  %shr60128.13 = lshr i32 %mul59.13, 15
+  %add61.13 = add nuw nsw i32 %shr60128.13, %shr56127.13
+  %conv62.13 = trunc i32 %add61.13 to i16
+  %arrayidx63.13 = getelementptr inbounds i16, i16* %Output, i32 13
+  store i16 %conv62.13, i16* %arrayidx63.13, align 2
+  %arrayidx53.14 = getelementptr inbounds i16, i16* %In1, i32 14
+  %33 = load i16, i16* %arrayidx53.14, align 2
+  %conv54.14 = sext i16 %33 to i32
+  %mul55.14 = mul nsw i32 %conv54.14, 29491
+  %shr56127.14 = lshr i32 %mul55.14, 15
+  %arrayidx57.14 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 14
+  %34 = load i16, i16* %arrayidx57.14, align 2
+  %conv58.14 = sext i16 %34 to i32
+  %mul59.14 = mul nsw i32 %conv58.14, 3277
+  %shr60128.14 = lshr i32 %mul59.14, 15
+  %add61.14 = add nuw nsw i32 %shr60128.14, %shr56127.14
+  %conv62.14 = trunc i32 %add61.14 to i16
+  %arrayidx63.14 = getelementptr inbounds i16, i16* %Output, i32 14
+  store i16 %conv62.14, i16* %arrayidx63.14, align 2
+  %arrayidx53.15 = getelementptr inbounds i16, i16* %In1, i32 15
+  %35 = load i16, i16* %arrayidx53.15, align 2
+  %conv54.15 = sext i16 %35 to i32
+  %mul55.15 = mul nsw i32 %conv54.15, 29491
+  %shr56127.15 = lshr i32 %mul55.15, 15
+  %arrayidx57.15 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 15
+  %36 = load i16, i16* %arrayidx57.15, align 2
+  %conv58.15 = sext i16 %36 to i32
+  %mul59.15 = mul nsw i32 %conv58.15, 3277
+  %shr60128.15 = lshr i32 %mul59.15, 15
+  %add61.15 = add nuw nsw i32 %shr60128.15, %shr56127.15
+  %conv62.15 = trunc i32 %add61.15 to i16
+  %arrayidx63.15 = getelementptr inbounds i16, i16* %Output, i32 15
+  store i16 %conv62.15, i16* %arrayidx63.15, align 2
+  store i16 %conv62.9, i16* %.reg2mem
+  store i16 %conv62.10, i16* %.reg2mem150
+  store i16 %conv62.11, i16* %.reg2mem152
+  store i16 %conv62.12, i16* %.reg2mem154
+  store i16 %conv62.13, i16* %.reg2mem156
+  store i16 %conv62.14, i16* %.reg2mem158
+  %.reload159 = load i16, i16* %.reg2mem158
+  %.reload157 = load i16, i16* %.reg2mem156
+  %.reload155 = load i16, i16* %.reg2mem154
+  %.reload153 = load i16, i16* %.reg2mem152
+  %.reload151 = load i16, i16* %.reg2mem150
+  %.reload = load i16, i16* %.reg2mem
+  %37 = load i16, i16* %Output, align 2
+  %cmp77 = icmp slt i16 %37, 128
+  br i1 %cmp77, label %A0, label %B0
+
+A0:                                        ; preds = %if.entry
+  store i16 128, i16* %Output, align 2
+  br label %B0
+
+B0:                                         ; preds = %A, %if.entry
+  %38 = phi i16 [ 128, %A0 ], [ %37, %if.entry ]
+  %add84 = add i16 %38, 128
+  %arrayidx74.1 = getelementptr inbounds i16, i16* %Output, i32 1
+  %39 = load i16, i16* %arrayidx74.1, align 2
+  %cmp77.1 = icmp slt i16 %39, %add84
+  br i1 %cmp77.1, label %A1, label %B1
+
+A1:                                      ; preds = %B
+  store i16 %add84, i16* %arrayidx74.1, align 2
+  br label %B1
+
+B1:                                       ; preds = %A1, %B
+  %40 = phi i16 [ %add84, %A1 ], [ %39, %B0 ]
+  %add84.1 = add i16 %40, 128
+  %arrayidx74.2 = getelementptr inbounds i16, i16* %Output, i32 2
+  %41 = load i16, i16* %arrayidx74.2, align 2
+  %cmp77.2 = icmp slt i16 %41, %add84.1
+  br i1 %cmp77.2, label %A2, label %B2
+
+A2:                                      ; preds = %B1
+  store i16 %add84.1, i16* %arrayidx74.2, align 2
+  br label %B2
+
+B2:                                       ; preds = %A2, %B1
+  %42 = phi i16 [ %add84.1, %A2 ], [ %41, %B1 ]
+  %add84.2 = add i16 %42, 128
+  %arrayidx74.3 = getelementptr inbounds i16, i16* %Output, i32 3
+  %43 = load i16, i16* %arrayidx74.3, align 2
+  %cmp77.3 = icmp slt i16 %43, %add84.2
+  br i1 %cmp77.3, label %A3, label %B3
+
+A3:                                      ; preds = %B2
+  store i16 %add84.2, i16* %arrayidx74.3, align 2
+  br label %B3
+
+B3:                                       ; preds = %A3, %B2
+  %44 = phi i16 [ %add84.2, %A3 ], [ %43, %B2 ]
+  %add84.3 = add i16 %44, 128
+  %arrayidx74.4 = getelementptr inbounds i16, i16* %Output, i32 4
+  %45 = load i16, i16* %arrayidx74.4, align 2
+  %cmp77.4 = icmp slt i16 %45, %add84.3
+  br i1 %cmp77.4, label %A4, label %B4
+
+A4:                                      ; preds = %B3
+  store i16 %add84.3, i16* %arrayidx74.4, align 2
+  br label %B4
+
+B4:                                       ; preds = %A4, %B3
+  %46 = phi i16 [ %add84.3, %A4 ], [ %45, %B3 ]
+  %add84.4 = add i16 %44, 128
+  %arrayidx74.5 = getelementptr inbounds i16, i16* %Output, i32 5
+  %47 = load i16, i16* %arrayidx74.5, align 2
+  %cmp77.5 = icmp slt i16 %47, %add84.4
+  br i1 %cmp77.5, label %A5, label %B5
+
+A5:                                      ; preds = %B4
+  store i16 %add84.4, i16* %arrayidx74.5, align 2
+  br label %B5
+
+B5:                                       ; preds = %A5, %B4
+  %48 = phi i16 [ %add84.4, %A5 ], [ %47, %B4 ]
+  %add84.5 = add i16 %44, 128
+  %arrayidx74.6 = getelementptr inbounds i16, i16* %Output, i32 6
+  %49 = load i16, i16* %arrayidx74.6, align 2
+  %cmp77.6 = icmp slt i16 %49, %add84.5
+  br i1 %cmp77.6, label %A6, label %B6
+
+A6:                                      ; preds = %B5
+  store i16 %add84.5, i16* %arrayidx74.6, align 2
+  br label %B6
+
+B6:                                       ; preds = %A6, %B5
+  %50 = phi i16 [ %add84.5, %A6 ], [ %49, %B5 ]
+  %add84.6 = add i16 %44, 128
+  %arrayidx74.7 = getelementptr inbounds i16, i16* %Output, i32 7
+  %51 = load i16, i16* %arrayidx74.7, align 2
+  %cmp77.7 = icmp slt i16 %51, %add84.6
+  br i1 %cmp77.7, label %A7, label %B7
+
+A7:                                      ; preds = %B6
+  store i16 %add84.6, i16* %arrayidx74.7, align 2
+  br label %B7
+
+B7:                                       ; preds = %A7, %B6
+  %52 = phi i16 [ %add84.6, %A7 ], [ %51, %B6 ]
+  %add84.7 = add i16 %44, 128
+  %arrayidx74.8 = getelementptr inbounds i16, i16* %Output, i32 8
+  %53 = load i16, i16* %arrayidx74.8, align 2
+  %cmp77.8 = icmp slt i16 %53, %add84.7
+  br i1 %cmp77.8, label %A8, label %B8
+
+A8:                                      ; preds = %B7
+  store i16 %add84.7, i16* %arrayidx74.8, align 2
+  br label %B8
+
+B8:                                       ; preds = %A8, %B7
+  %54 = phi i16 [ %add84.7, %A8 ], [ %53, %B7 ]
+  %add84.8 = add i16 %44, 128
+  %cmp77.9 = icmp slt i16 %.reload, %add84.8
+  br i1 %cmp77.9, label %A9, label %B9
+
+A9:                                      ; preds = %B8
+  %arrayidx74.9 = getelementptr inbounds i16, i16* %Output, i32 9
+  store i16 %add84.8, i16* %arrayidx74.9, align 2
+  br label %B9
+
+B9:                                       ; preds = %A9, %B8
+  %55 = phi i16 [ %add84.8, %A9 ], [ %.reload, %B8 ]
+  %add84.9 = add i16 %44, 128
+  %cmp77.10 = icmp slt i16 %.reload151, %add84.9
+  br i1 %cmp77.10, label %A10, label %B10
+
+A10:                                     ; preds = %B9
+  %arrayidx74.10 = getelementptr inbounds i16, i16* %Output, i32 10
+  store i16 %add84.9, i16* %arrayidx74.10, align 2
+  br label %B10
+
+B10:                                      ; preds = %A10, %B9
+  %56 = phi i16 [ %add84.9, %A10 ], [ %.reload151, %B9 ]
+  %add84.10 = add i16 %44, 128
+  %cmp77.11 = icmp slt i16 %.reload153, %add84.10
+  br i1 %cmp77.11, label %A11, label %B11
+
+A11:                                     ; preds = %B10
+  %arrayidx74.11 = getelementptr inbounds i16, i16* %Output, i32 11
+  store i16 %add84.10, i16* %arrayidx74.11, align 2
+  br label %B11
+
+B11:                                      ; preds = %A11, %B10
+  %57 = phi i16 [ %add84.10, %A11 ], [ %.reload153, %B10 ]
+  %add84.11 = add i16 %44, 128
+  %cmp77.12 = icmp slt i16 %.reload155, %add84.11
+  br i1 %cmp77.12, label %A12, label %B13
+
+A12:                                     ; preds = %B11
+  %arrayidx74.12 = getelementptr inbounds i16, i16* %Output, i32 12
+  store i16 %add84.11, i16* %arrayidx74.12, align 2
+  br label %B13
+
+B13:                                      ; preds = %A12, %B13
+  ret void
+}
diff --git a/final/test/ScopInfo/complex-successor-structure-3.ll b/final/test/ScopInfo/complex-successor-structure-3.ll
new file mode 100644
index 0000000..1e3f7f7
--- /dev/null
+++ b/final/test/ScopInfo/complex-successor-structure-3.ll
@@ -0,0 +1,366 @@
+; RUN: opt %loadPolly -analyze -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+; Check that propagation of domains from A(X) to A(X+1) will keep the
+; domains small and concise.
+;
+; CHECK:         Assumed Context:
+; CHECK-NEXT:    [tmp5, tmp, tmp8, tmp11, tmp14, tmp17, tmp20, tmp23, tmp26] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [tmp5, tmp, tmp8, tmp11, tmp14, tmp17, tmp20, tmp23, tmp26] -> {  : 1 = 0 }
+;
+; CHECK:         Stmt_FINAL
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [tmp5, tmp, tmp8, tmp11, tmp14, tmp17, tmp20, tmp23, tmp26] -> { Stmt_FINAL[] };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [tmp5, tmp, tmp8, tmp11, tmp14, tmp17, tmp20, tmp23, tmp26] -> { Stmt_FINAL[] -> [16] };
+;
+;
+;    void f(short *restrict In, int *restrict Out) {
+;      int InV, V, Idx;
+;      Idx = 0;
+;      V = 999;
+;
+;    A0:
+;      InV = In[Idx++];
+;      if (InV < V + 42) {
+;      B0:
+;        V = V + 42;
+;        Out[V]++;
+;      } else {
+;      C0:
+;        V = InV;
+;        Out[V]--;
+;      }
+;
+;    A1:
+;      InV = In[Idx++];
+;      if (InV < V + 42) {
+;      B1:
+;        V = V + 42;
+;        Out[V]++;
+;      } else {
+;      C1:
+;        V = InV;
+;        Out[V]--;
+;      }
+;      V = 999;
+;
+;    A2:
+;      InV = In[Idx++];
+;      if (InV < V + 42) {
+;      B2:
+;        V = V + 42;
+;        Out[V]++;
+;      } else {
+;      C2:
+;        V = InV;
+;        Out[V]--;
+;      }
+;
+;    A3:
+;      InV = In[Idx++];
+;      if (InV < V + 42) {
+;      B3:
+;        V = V + 42;
+;        Out[V]++;
+;      } else {
+;      C3:
+;        V = InV;
+;        Out[V]--;
+;      }
+;      V = 999;
+;
+;    A4:
+;      InV = In[Idx++];
+;      if (InV < V + 42) {
+;      B4:
+;        V = V + 42;
+;        Out[V]++;
+;      } else {
+;      C4:
+;        V = InV;
+;        Out[V]--;
+;      }
+;
+;    A5:
+;      InV = In[Idx++];
+;      if (InV < V + 42) {
+;      B5:
+;        V = V + 42;
+;        Out[V]++;
+;      } else {
+;      C5:
+;        V = InV;
+;        Out[V]--;
+;      }
+;      V = 999;
+;
+;    A6:
+;      InV = In[Idx++];
+;      if (InV < V + 42) {
+;      B6:
+;        V = V + 42;
+;        Out[V]++;
+;      } else {
+;      C6:
+;        V = InV;
+;        Out[V]--;
+;      }
+;
+;    A7:
+;      InV = In[Idx++];
+;      if (InV < V + 42) {
+;      B7:
+;        V = V + 42;
+;        Out[V]++;
+;      } else {
+;      C7:
+;        V = InV;
+;        Out[V]--;
+;      }
+;      V = 999;
+;
+;    A8:
+;      InV = In[Idx++];
+;      if (InV < V + 42) {
+;      B8:
+;        V = V + 42;
+;        Out[V]++;
+;      } else {
+;      C8:
+;        V = InV;
+;        Out[V]--;
+;      }
+;    FINAL:
+;      Out[V]++;
+;
+;    ScopExit:
+;      return;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i16* noalias %In, i32* noalias %Out) {
+entry:
+  %tmp = load i16, i16* %In, align 2
+  %conv = sext i16 %tmp to i32
+  %cmp = icmp slt i16 %tmp, 1041
+  br i1 %cmp, label %B0, label %C0
+
+B0:                                               ; preds = %entry
+  %arrayidx4 = getelementptr inbounds i32, i32* %Out, i64 1041
+  %tmp3 = load i32, i32* %arrayidx4, align 4
+  %inc5 = add nsw i32 %tmp3, 1
+  store i32 %inc5, i32* %arrayidx4, align 4
+  br label %A1
+
+C0:                                               ; preds = %entry
+  %idxprom6 = sext i16 %tmp to i64
+  %arrayidx7 = getelementptr inbounds i32, i32* %Out, i64 %idxprom6
+  %tmp4 = load i32, i32* %arrayidx7, align 4
+  %dec = add nsw i32 %tmp4, -1
+  store i32 %dec, i32* %arrayidx7, align 4
+  br label %A1
+
+A1:                                               ; preds = %B0, %C0
+  %V.0 = phi i32 [ 1041, %B0 ], [ %conv, %C0 ]
+  %arrayidx10 = getelementptr inbounds i16, i16* %In, i64 1
+  %tmp5 = load i16, i16* %arrayidx10, align 2
+  %conv11 = sext i16 %tmp5 to i32
+  %add12 = add nsw i32 %V.0, 42
+  %cmp13 = icmp slt i32 %conv11, %add12
+  br i1 %cmp13, label %B1, label %C1
+
+B1:                                               ; preds = %A1
+  %add16 = add nsw i32 %V.0, 42
+  %idxprom17 = sext i32 %add16 to i64
+  %arrayidx18 = getelementptr inbounds i32, i32* %Out, i64 %idxprom17
+  %tmp6 = load i32, i32* %arrayidx18, align 4
+  %inc19 = add nsw i32 %tmp6, 1
+  store i32 %inc19, i32* %arrayidx18, align 4
+  br label %A2
+
+C1:                                               ; preds = %A1
+  %idxprom21 = sext i16 %tmp5 to i64
+  %arrayidx22 = getelementptr inbounds i32, i32* %Out, i64 %idxprom21
+  %tmp7 = load i32, i32* %arrayidx22, align 4
+  %dec23 = add nsw i32 %tmp7, -1
+  store i32 %dec23, i32* %arrayidx22, align 4
+  br label %A2
+
+A2:                                               ; preds = %B1, %C1
+  %arrayidx27 = getelementptr inbounds i16, i16* %In, i64 2
+  %tmp8 = load i16, i16* %arrayidx27, align 2
+  %conv28 = sext i16 %tmp8 to i32
+  %cmp30 = icmp slt i16 %tmp8, 1041
+  br i1 %cmp30, label %B2, label %C2
+
+B2:                                               ; preds = %A2
+  %arrayidx35 = getelementptr inbounds i32, i32* %Out, i64 1041
+  %tmp9 = load i32, i32* %arrayidx35, align 4
+  %inc36 = add nsw i32 %tmp9, 1
+  store i32 %inc36, i32* %arrayidx35, align 4
+  br label %A3
+
+C2:                                               ; preds = %A2
+  %idxprom38 = sext i16 %tmp8 to i64
+  %arrayidx39 = getelementptr inbounds i32, i32* %Out, i64 %idxprom38
+  %tmp10 = load i32, i32* %arrayidx39, align 4
+  %dec40 = add nsw i32 %tmp10, -1
+  store i32 %dec40, i32* %arrayidx39, align 4
+  br label %A3
+
+A3:                                               ; preds = %B2, %C2
+  %V.1 = phi i32 [ 1041, %B2 ], [ %conv28, %C2 ]
+  %arrayidx44 = getelementptr inbounds i16, i16* %In, i64 3
+  %tmp11 = load i16, i16* %arrayidx44, align 2
+  %conv45 = sext i16 %tmp11 to i32
+  %add46 = add nsw i32 %V.1, 42
+  %cmp47 = icmp slt i32 %conv45, %add46
+  br i1 %cmp47, label %B3, label %C3
+
+B3:                                               ; preds = %A3
+  %add50 = add nsw i32 %V.1, 42
+  %idxprom51 = sext i32 %add50 to i64
+  %arrayidx52 = getelementptr inbounds i32, i32* %Out, i64 %idxprom51
+  %tmp12 = load i32, i32* %arrayidx52, align 4
+  %inc53 = add nsw i32 %tmp12, 1
+  store i32 %inc53, i32* %arrayidx52, align 4
+  br label %A4
+
+C3:                                               ; preds = %A3
+  %idxprom55 = sext i16 %tmp11 to i64
+  %arrayidx56 = getelementptr inbounds i32, i32* %Out, i64 %idxprom55
+  %tmp13 = load i32, i32* %arrayidx56, align 4
+  %dec57 = add nsw i32 %tmp13, -1
+  store i32 %dec57, i32* %arrayidx56, align 4
+  br label %A4
+
+A4:                                               ; preds = %B3, %C3
+  %arrayidx61 = getelementptr inbounds i16, i16* %In, i64 4
+  %tmp14 = load i16, i16* %arrayidx61, align 2
+  %conv62 = sext i16 %tmp14 to i32
+  %cmp64 = icmp slt i16 %tmp14, 1041
+  br i1 %cmp64, label %B4, label %C4
+
+B4:                                               ; preds = %A4
+  %arrayidx69 = getelementptr inbounds i32, i32* %Out, i64 1041
+  %tmp15 = load i32, i32* %arrayidx69, align 4
+  %inc70 = add nsw i32 %tmp15, 1
+  store i32 %inc70, i32* %arrayidx69, align 4
+  br label %A5
+
+C4:                                               ; preds = %A4
+  %idxprom72 = sext i16 %tmp14 to i64
+  %arrayidx73 = getelementptr inbounds i32, i32* %Out, i64 %idxprom72
+  %tmp16 = load i32, i32* %arrayidx73, align 4
+  %dec74 = add nsw i32 %tmp16, -1
+  store i32 %dec74, i32* %arrayidx73, align 4
+  %phitmp = add nsw i32 %conv62, 42
+  br label %A5
+
+A5:                                               ; preds = %B4, %C4
+  %V.2 = phi i32 [ 1083, %B4 ], [ %phitmp, %C4 ]
+  %arrayidx78 = getelementptr inbounds i16, i16* %In, i64 5
+  %tmp17 = load i16, i16* %arrayidx78, align 2
+  %conv79 = sext i16 %tmp17 to i32
+  %cmp81 = icmp slt i32 %conv79, %V.2
+  br i1 %cmp81, label %B5, label %C5
+
+B5:                                               ; preds = %A5
+  %idxprom85 = sext i32 %V.2 to i64
+  %arrayidx86 = getelementptr inbounds i32, i32* %Out, i64 %idxprom85
+  %tmp18 = load i32, i32* %arrayidx86, align 4
+  %inc87 = add nsw i32 %tmp18, 1
+  store i32 %inc87, i32* %arrayidx86, align 4
+  br label %A6
+
+C5:                                               ; preds = %A5
+  %idxprom89 = sext i16 %tmp17 to i64
+  %arrayidx90 = getelementptr inbounds i32, i32* %Out, i64 %idxprom89
+  %tmp19 = load i32, i32* %arrayidx90, align 4
+  %dec91 = add nsw i32 %tmp19, -1
+  store i32 %dec91, i32* %arrayidx90, align 4
+  br label %A6
+
+A6:                                               ; preds = %B5, %C5
+  %arrayidx95 = getelementptr inbounds i16, i16* %In, i64 6
+  %tmp20 = load i16, i16* %arrayidx95, align 2
+  %conv96 = sext i16 %tmp20 to i32
+  %cmp98 = icmp slt i16 %tmp20, 1041
+  br i1 %cmp98, label %B6, label %C6
+
+B6:                                               ; preds = %A6
+  %arrayidx103 = getelementptr inbounds i32, i32* %Out, i64 1041
+  %tmp21 = load i32, i32* %arrayidx103, align 4
+  %inc104 = add nsw i32 %tmp21, 1
+  store i32 %inc104, i32* %arrayidx103, align 4
+  br label %A7
+
+C6:                                               ; preds = %A6
+  %idxprom106 = sext i16 %tmp20 to i64
+  %arrayidx107 = getelementptr inbounds i32, i32* %Out, i64 %idxprom106
+  %tmp22 = load i32, i32* %arrayidx107, align 4
+  %dec108 = add nsw i32 %tmp22, -1
+  store i32 %dec108, i32* %arrayidx107, align 4
+  %phitmp1 = add nsw i32 %conv96, 42
+  br label %A7
+
+A7:                                               ; preds = %B6, %C6
+  %V.3 = phi i32 [ 1083, %B6 ], [ %phitmp1, %C6 ]
+  %arrayidx112 = getelementptr inbounds i16, i16* %In, i64 7
+  %tmp23 = load i16, i16* %arrayidx112, align 2
+  %conv113 = sext i16 %tmp23 to i32
+  %cmp115 = icmp slt i32 %conv113, %V.3
+  br i1 %cmp115, label %B7, label %C7
+
+B7:                                               ; preds = %A7
+  %idxprom119 = sext i32 %V.3 to i64
+  %arrayidx120 = getelementptr inbounds i32, i32* %Out, i64 %idxprom119
+  %tmp24 = load i32, i32* %arrayidx120, align 4
+  %inc121 = add nsw i32 %tmp24, 1
+  store i32 %inc121, i32* %arrayidx120, align 4
+  br label %A8
+
+C7:                                               ; preds = %A7
+  %idxprom123 = sext i16 %tmp23 to i64
+  %arrayidx124 = getelementptr inbounds i32, i32* %Out, i64 %idxprom123
+  %tmp25 = load i32, i32* %arrayidx124, align 4
+  %dec125 = add nsw i32 %tmp25, -1
+  store i32 %dec125, i32* %arrayidx124, align 4
+  br label %A8
+
+A8:                                               ; preds = %B7, %C7
+  %arrayidx129 = getelementptr inbounds i16, i16* %In, i64 8
+  %tmp26 = load i16, i16* %arrayidx129, align 2
+  %cmp132 = icmp slt i16 %tmp26, 1041
+  br i1 %cmp132, label %B8, label %C8
+
+B8:                                               ; preds = %A8
+  %arrayidx137 = getelementptr inbounds i32, i32* %Out, i64 1041
+  %tmp27 = load i32, i32* %arrayidx137, align 4
+  %inc138 = add nsw i32 %tmp27, 1
+  store i32 %inc138, i32* %arrayidx137, align 4
+  br label %FINAL
+
+C8:                                               ; preds = %A8
+  %idxprom140 = sext i16 %tmp26 to i64
+  %arrayidx141 = getelementptr inbounds i32, i32* %Out, i64 %idxprom140
+  %tmp28 = load i32, i32* %arrayidx141, align 4
+  %dec142 = add nsw i32 %tmp28, -1
+  store i32 %dec142, i32* %arrayidx141, align 4
+  %phitmp2 = sext i16 %tmp26 to i64
+  br label %FINAL
+
+FINAL:                                        ; preds = %C8, %B8
+  %V.4 = phi i64 [ 1041, %B8 ], [ %phitmp2, %C8 ]
+  %arrayidx145 = getelementptr inbounds i32, i32* %Out, i64 %V.4
+  %tmp29 = load i32, i32* %arrayidx145, align 4
+  %inc146 = add nsw i32 %tmp29, 1
+  store i32 %inc146, i32* %arrayidx145, align 4
+  br label %ScopExit
+
+ScopExit:
+  ret void
+}
diff --git a/final/test/ScopInfo/complex-successor-structure.ll b/final/test/ScopInfo/complex-successor-structure.ll
new file mode 100644
index 0000000..229f88a
--- /dev/null
+++ b/final/test/ScopInfo/complex-successor-structure.ll
@@ -0,0 +1,538 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN:     < %s 2>&1 | FileCheck %s
+
+; We build a scop from the region for.body->B13. The CFG is of the
+; following form. The test checks that the condition construction does not take
+; a huge amount of time. While we can propagate the domain constraints from
+; B(X) to B(X+1) the conditions in B(X+1) will exponentially grow the number
+; of needed constraints (it is basically the condition of B(X) + one smax),
+; thus we should bail out at some point.
+;
+; CHECK: Low complexity assumption: {  : 1 = 0 }
+
+;      |
+;    for.body <--+
+;      |         |
+;      |---------+
+;      |
+;     \ /
+;    if.entry --+
+;      |        |
+;      A0       |
+;      |        |
+;      B0 <-----+
+;      |  \
+;      |   \
+;      A1   \
+;      |    |
+;      |    |
+;      B1<--+
+;      |  \
+;      |   \
+;      A2   \
+;      |    |
+;      |    |
+;      B2<--+
+;      |  \
+;      |   \
+;      A3   \
+;      |    |
+;      |    |
+;      B3<--+
+;      |  \
+;      |   \
+;      A4   \
+;      |    |
+;      |    |
+;      B4<--+
+;      |  \
+;      |   \
+;      A5   \
+;      |    |
+;      |    |
+;      B5<--+
+;      |  \
+;      |   \
+;      A6   \
+;      |    |
+;      |    |
+;      B6<--+
+;      |  \
+;      |   \
+;      A7   \
+;      |    |
+;      |    |
+;      B7<--+
+;      |  \
+;      |   \
+;      A8   \
+;      |    |
+;      |    |
+;      B8<--+
+;      |  \
+;      |   \
+;      A9   \
+;      |    |
+;      |    |
+;      B9<--+
+;      |  \
+;      |   \
+;      A10  \
+;      |    |
+;      |    |
+;      B10<-+
+;      |  \
+;      |   \
+;      A11  \
+;      |    |
+;      |    |
+;      B11<-+
+;      |  \
+;      |   \
+;      A12  \
+;      |    |
+;      |    |
+;      B12<-+
+;      |  \
+;      |   \
+;      A13  \
+;      |    |
+;      |    |
+;      B13<-+
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n8:16:32-S64"
+target triple = "thumbv7--linux-android"
+
+@Table1 = external global [2304 x i16], align 2
+@Table2 = external global [1792 x i16], align 2
+@Table3 = external global [16 x i16], align 2
+
+define void @foo(i16* nocapture readonly %indice, i16* nocapture %Output, i16* nocapture readonly %In1, i16* nocapture readonly %In2, i16 signext %var, i16 signext %var2) {
+entry:
+  %.reg2mem158 = alloca i16
+  %.reg2mem156 = alloca i16
+  %.reg2mem154 = alloca i16
+  %.reg2mem152 = alloca i16
+  %.reg2mem150 = alloca i16
+  %.reg2mem = alloca i16
+  %Temp_Ref = alloca [16 x i16], align 2
+  %0 = bitcast [16 x i16]* %Temp_Ref to i8*
+  %cmp = icmp eq i16 %var, 0
+  br label %for.body
+
+for.body:                                       ; preds = %for.body, %entry
+  %i.2138 = phi i32 [ %inc47, %for.body ], [ 0, %entry ]
+  %arrayidx28 = getelementptr inbounds [16 x i16], [16 x i16]* @Table3, i32 0, i32 %i.2138
+  %1 = load i16, i16* %arrayidx28, align 2
+  %conv29 = sext i16 %1 to i32
+  %arrayidx36 = getelementptr inbounds i16, i16* %In2, i32 %i.2138
+  %2 = load i16, i16* %arrayidx36, align 2
+  %conv37 = sext i16 %2 to i32
+  %shl38147 = add nsw i32 %conv37, %conv29
+  %add35.1 = add nuw nsw i32 %i.2138, 16
+  %arrayidx36.1 = getelementptr inbounds i16, i16* %In2, i32 %add35.1
+  %3 = load i16, i16* %arrayidx36.1, align 2
+  %conv37.1 = sext i16 %3 to i32
+  %shl38.1148 = add nsw i32 %conv37.1, %shl38147
+  %add35.2 = add nuw nsw i32 %i.2138, 32
+  %arrayidx36.2 = getelementptr inbounds i16, i16* %In2, i32 %add35.2
+  %4 = load i16, i16* %arrayidx36.2, align 2
+  %conv37.2 = sext i16 %4 to i32
+  %shl38.2149 = add nsw i32 %conv37.2, %shl38.1148
+  %add39.2 = shl i32 %shl38.2149, 14
+  %add43 = add nsw i32 %add39.2, 32768
+  %shr129 = lshr i32 %add43, 16
+  %conv44 = trunc i32 %shr129 to i16
+  %arrayidx45 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 %i.2138
+  store i16 %conv44, i16* %arrayidx45, align 2
+  %inc47 = add nuw nsw i32 %i.2138, 1
+  %exitcond144 = icmp eq i32 %i.2138, 15
+  br i1 %exitcond144, label %if.entry, label %for.body
+
+if.entry:                             ; preds = %for.body
+  %5 = load i16, i16* %In1, align 2
+  %conv54 = sext i16 %5 to i32
+  %mul55 = mul nsw i32 %conv54, 29491
+  %shr56127 = lshr i32 %mul55, 15
+  %arrayidx57 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 0
+  %6 = load i16, i16* %arrayidx57, align 2
+  %conv58 = sext i16 %6 to i32
+  %mul59 = mul nsw i32 %conv58, 3277
+  %shr60128 = lshr i32 %mul59, 15
+  %add61 = add nuw nsw i32 %shr60128, %shr56127
+  %conv62 = trunc i32 %add61 to i16
+  store i16 %conv62, i16* %Output, align 2
+  %arrayidx53.1 = getelementptr inbounds i16, i16* %In1, i32 1
+  %7 = load i16, i16* %arrayidx53.1, align 2
+  %conv54.1 = sext i16 %7 to i32
+  %mul55.1 = mul nsw i32 %conv54.1, 29491
+  %shr56127.1 = lshr i32 %mul55.1, 15
+  %arrayidx57.1 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 1
+  %8 = load i16, i16* %arrayidx57.1, align 2
+  %conv58.1 = sext i16 %8 to i32
+  %mul59.1 = mul nsw i32 %conv58.1, 3277
+  %shr60128.1 = lshr i32 %mul59.1, 15
+  %add61.1 = add nuw nsw i32 %shr60128.1, %shr56127.1
+  %conv62.1 = trunc i32 %add61.1 to i16
+  %arrayidx63.1 = getelementptr inbounds i16, i16* %Output, i32 1
+  store i16 %conv62.1, i16* %arrayidx63.1, align 2
+  %arrayidx53.2 = getelementptr inbounds i16, i16* %In1, i32 2
+  %9 = load i16, i16* %arrayidx53.2, align 2
+  %conv54.2 = sext i16 %9 to i32
+  %mul55.2 = mul nsw i32 %conv54.2, 29491
+  %shr56127.2 = lshr i32 %mul55.2, 15
+  %arrayidx57.2 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 2
+  %10 = load i16, i16* %arrayidx57.2, align 2
+  %conv58.2 = sext i16 %10 to i32
+  %mul59.2 = mul nsw i32 %conv58.2, 3277
+  %shr60128.2 = lshr i32 %mul59.2, 15
+  %add61.2 = add nuw nsw i32 %shr60128.2, %shr56127.2
+  %conv62.2 = trunc i32 %add61.2 to i16
+  %arrayidx63.2 = getelementptr inbounds i16, i16* %Output, i32 2
+  store i16 %conv62.2, i16* %arrayidx63.2, align 2
+  %arrayidx53.3 = getelementptr inbounds i16, i16* %In1, i32 3
+  %11 = load i16, i16* %arrayidx53.3, align 2
+  %conv54.3 = sext i16 %11 to i32
+  %mul55.3 = mul nsw i32 %conv54.3, 29491
+  %shr56127.3 = lshr i32 %mul55.3, 15
+  %arrayidx57.3 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 3
+  %12 = load i16, i16* %arrayidx57.3, align 2
+  %conv58.3 = sext i16 %12 to i32
+  %mul59.3 = mul nsw i32 %conv58.3, 3277
+  %shr60128.3 = lshr i32 %mul59.3, 15
+  %add61.3 = add nuw nsw i32 %shr60128.3, %shr56127.3
+  %conv62.3 = trunc i32 %add61.3 to i16
+  %arrayidx63.3 = getelementptr inbounds i16, i16* %Output, i32 3
+  store i16 %conv62.3, i16* %arrayidx63.3, align 2
+  %arrayidx53.4 = getelementptr inbounds i16, i16* %In1, i32 4
+  %13 = load i16, i16* %arrayidx53.4, align 2
+  %conv54.4 = sext i16 %13 to i32
+  %mul55.4 = mul nsw i32 %conv54.4, 29491
+  %shr56127.4 = lshr i32 %mul55.4, 15
+  %arrayidx57.4 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 4
+  %14 = load i16, i16* %arrayidx57.4, align 2
+  %conv58.4 = sext i16 %14 to i32
+  %mul59.4 = mul nsw i32 %conv58.4, 3277
+  %shr60128.4 = lshr i32 %mul59.4, 15
+  %add61.4 = add nuw nsw i32 %shr60128.4, %shr56127.4
+  %conv62.4 = trunc i32 %add61.4 to i16
+  %arrayidx63.4 = getelementptr inbounds i16, i16* %Output, i32 4
+  store i16 %conv62.4, i16* %arrayidx63.4, align 2
+  %arrayidx53.5 = getelementptr inbounds i16, i16* %In1, i32 5
+  %15 = load i16, i16* %arrayidx53.5, align 2
+  %conv54.5 = sext i16 %15 to i32
+  %mul55.5 = mul nsw i32 %conv54.5, 29491
+  %shr56127.5 = lshr i32 %mul55.5, 15
+  %arrayidx57.5 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 5
+  %16 = load i16, i16* %arrayidx57.5, align 2
+  %conv58.5 = sext i16 %16 to i32
+  %mul59.5 = mul nsw i32 %conv58.5, 3277
+  %shr60128.5 = lshr i32 %mul59.5, 15
+  %add61.5 = add nuw nsw i32 %shr60128.5, %shr56127.5
+  %conv62.5 = trunc i32 %add61.5 to i16
+  %arrayidx63.5 = getelementptr inbounds i16, i16* %Output, i32 5
+  store i16 %conv62.5, i16* %arrayidx63.5, align 2
+  %arrayidx53.6 = getelementptr inbounds i16, i16* %In1, i32 6
+  %17 = load i16, i16* %arrayidx53.6, align 2
+  %conv54.6 = sext i16 %17 to i32
+  %mul55.6 = mul nsw i32 %conv54.6, 29491
+  %shr56127.6 = lshr i32 %mul55.6, 15
+  %arrayidx57.6 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 6
+  %18 = load i16, i16* %arrayidx57.6, align 2
+  %conv58.6 = sext i16 %18 to i32
+  %mul59.6 = mul nsw i32 %conv58.6, 3277
+  %shr60128.6 = lshr i32 %mul59.6, 15
+  %add61.6 = add nuw nsw i32 %shr60128.6, %shr56127.6
+  %conv62.6 = trunc i32 %add61.6 to i16
+  %arrayidx63.6 = getelementptr inbounds i16, i16* %Output, i32 6
+  store i16 %conv62.6, i16* %arrayidx63.6, align 2
+  %arrayidx53.7 = getelementptr inbounds i16, i16* %In1, i32 7
+  %19 = load i16, i16* %arrayidx53.7, align 2
+  %conv54.7 = sext i16 %19 to i32
+  %mul55.7 = mul nsw i32 %conv54.7, 29491
+  %shr56127.7 = lshr i32 %mul55.7, 15
+  %arrayidx57.7 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 7
+  %20 = load i16, i16* %arrayidx57.7, align 2
+  %conv58.7 = sext i16 %20 to i32
+  %mul59.7 = mul nsw i32 %conv58.7, 3277
+  %shr60128.7 = lshr i32 %mul59.7, 15
+  %add61.7 = add nuw nsw i32 %shr60128.7, %shr56127.7
+  %conv62.7 = trunc i32 %add61.7 to i16
+  %arrayidx63.7 = getelementptr inbounds i16, i16* %Output, i32 7
+  store i16 %conv62.7, i16* %arrayidx63.7, align 2
+  %arrayidx53.8 = getelementptr inbounds i16, i16* %In1, i32 8
+  %21 = load i16, i16* %arrayidx53.8, align 2
+  %conv54.8 = sext i16 %21 to i32
+  %mul55.8 = mul nsw i32 %conv54.8, 29491
+  %shr56127.8 = lshr i32 %mul55.8, 15
+  %arrayidx57.8 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 8
+  %22 = load i16, i16* %arrayidx57.8, align 2
+  %conv58.8 = sext i16 %22 to i32
+  %mul59.8 = mul nsw i32 %conv58.8, 3277
+  %shr60128.8 = lshr i32 %mul59.8, 15
+  %add61.8 = add nuw nsw i32 %shr60128.8, %shr56127.8
+  %conv62.8 = trunc i32 %add61.8 to i16
+  %arrayidx63.8 = getelementptr inbounds i16, i16* %Output, i32 8
+  store i16 %conv62.8, i16* %arrayidx63.8, align 2
+  %arrayidx53.9 = getelementptr inbounds i16, i16* %In1, i32 9
+  %23 = load i16, i16* %arrayidx53.9, align 2
+  %conv54.9 = sext i16 %23 to i32
+  %mul55.9 = mul nsw i32 %conv54.9, 29491
+  %shr56127.9 = lshr i32 %mul55.9, 15
+  %arrayidx57.9 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 9
+  %24 = load i16, i16* %arrayidx57.9, align 2
+  %conv58.9 = sext i16 %24 to i32
+  %mul59.9 = mul nsw i32 %conv58.9, 3277
+  %shr60128.9 = lshr i32 %mul59.9, 15
+  %add61.9 = add nuw nsw i32 %shr60128.9, %shr56127.9
+  %conv62.9 = trunc i32 %add61.9 to i16
+  %arrayidx63.9 = getelementptr inbounds i16, i16* %Output, i32 9
+  store i16 %conv62.9, i16* %arrayidx63.9, align 2
+  %arrayidx53.10 = getelementptr inbounds i16, i16* %In1, i32 10
+  %25 = load i16, i16* %arrayidx53.10, align 2
+  %conv54.10 = sext i16 %25 to i32
+  %mul55.10 = mul nsw i32 %conv54.10, 29491
+  %shr56127.10 = lshr i32 %mul55.10, 15
+  %arrayidx57.10 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 10
+  %26 = load i16, i16* %arrayidx57.10, align 2
+  %conv58.10 = sext i16 %26 to i32
+  %mul59.10 = mul nsw i32 %conv58.10, 3277
+  %shr60128.10 = lshr i32 %mul59.10, 15
+  %add61.10 = add nuw nsw i32 %shr60128.10, %shr56127.10
+  %conv62.10 = trunc i32 %add61.10 to i16
+  %arrayidx63.10 = getelementptr inbounds i16, i16* %Output, i32 10
+  store i16 %conv62.10, i16* %arrayidx63.10, align 2
+  %arrayidx53.11 = getelementptr inbounds i16, i16* %In1, i32 11
+  %27 = load i16, i16* %arrayidx53.11, align 2
+  %conv54.11 = sext i16 %27 to i32
+  %mul55.11 = mul nsw i32 %conv54.11, 29491
+  %shr56127.11 = lshr i32 %mul55.11, 15
+  %arrayidx57.11 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 11
+  %28 = load i16, i16* %arrayidx57.11, align 2
+  %conv58.11 = sext i16 %28 to i32
+  %mul59.11 = mul nsw i32 %conv58.11, 3277
+  %shr60128.11 = lshr i32 %mul59.11, 15
+  %add61.11 = add nuw nsw i32 %shr60128.11, %shr56127.11
+  %conv62.11 = trunc i32 %add61.11 to i16
+  %arrayidx63.11 = getelementptr inbounds i16, i16* %Output, i32 11
+  store i16 %conv62.11, i16* %arrayidx63.11, align 2
+  %arrayidx53.12 = getelementptr inbounds i16, i16* %In1, i32 12
+  %29 = load i16, i16* %arrayidx53.12, align 2
+  %conv54.12 = sext i16 %29 to i32
+  %mul55.12 = mul nsw i32 %conv54.12, 29491
+  %shr56127.12 = lshr i32 %mul55.12, 15
+  %arrayidx57.12 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 12
+  %30 = load i16, i16* %arrayidx57.12, align 2
+  %conv58.12 = sext i16 %30 to i32
+  %mul59.12 = mul nsw i32 %conv58.12, 3277
+  %shr60128.12 = lshr i32 %mul59.12, 15
+  %add61.12 = add nuw nsw i32 %shr60128.12, %shr56127.12
+  %conv62.12 = trunc i32 %add61.12 to i16
+  %arrayidx63.12 = getelementptr inbounds i16, i16* %Output, i32 12
+  store i16 %conv62.12, i16* %arrayidx63.12, align 2
+  %arrayidx53.13 = getelementptr inbounds i16, i16* %In1, i32 13
+  %31 = load i16, i16* %arrayidx53.13, align 2
+  %conv54.13 = sext i16 %31 to i32
+  %mul55.13 = mul nsw i32 %conv54.13, 29491
+  %shr56127.13 = lshr i32 %mul55.13, 15
+  %arrayidx57.13 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 13
+  %32 = load i16, i16* %arrayidx57.13, align 2
+  %conv58.13 = sext i16 %32 to i32
+  %mul59.13 = mul nsw i32 %conv58.13, 3277
+  %shr60128.13 = lshr i32 %mul59.13, 15
+  %add61.13 = add nuw nsw i32 %shr60128.13, %shr56127.13
+  %conv62.13 = trunc i32 %add61.13 to i16
+  %arrayidx63.13 = getelementptr inbounds i16, i16* %Output, i32 13
+  store i16 %conv62.13, i16* %arrayidx63.13, align 2
+  %arrayidx53.14 = getelementptr inbounds i16, i16* %In1, i32 14
+  %33 = load i16, i16* %arrayidx53.14, align 2
+  %conv54.14 = sext i16 %33 to i32
+  %mul55.14 = mul nsw i32 %conv54.14, 29491
+  %shr56127.14 = lshr i32 %mul55.14, 15
+  %arrayidx57.14 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 14
+  %34 = load i16, i16* %arrayidx57.14, align 2
+  %conv58.14 = sext i16 %34 to i32
+  %mul59.14 = mul nsw i32 %conv58.14, 3277
+  %shr60128.14 = lshr i32 %mul59.14, 15
+  %add61.14 = add nuw nsw i32 %shr60128.14, %shr56127.14
+  %conv62.14 = trunc i32 %add61.14 to i16
+  %arrayidx63.14 = getelementptr inbounds i16, i16* %Output, i32 14
+  store i16 %conv62.14, i16* %arrayidx63.14, align 2
+  %arrayidx53.15 = getelementptr inbounds i16, i16* %In1, i32 15
+  %35 = load i16, i16* %arrayidx53.15, align 2
+  %conv54.15 = sext i16 %35 to i32
+  %mul55.15 = mul nsw i32 %conv54.15, 29491
+  %shr56127.15 = lshr i32 %mul55.15, 15
+  %arrayidx57.15 = getelementptr inbounds [16 x i16], [16 x i16]* %Temp_Ref, i32 0, i32 15
+  %36 = load i16, i16* %arrayidx57.15, align 2
+  %conv58.15 = sext i16 %36 to i32
+  %mul59.15 = mul nsw i32 %conv58.15, 3277
+  %shr60128.15 = lshr i32 %mul59.15, 15
+  %add61.15 = add nuw nsw i32 %shr60128.15, %shr56127.15
+  %conv62.15 = trunc i32 %add61.15 to i16
+  %arrayidx63.15 = getelementptr inbounds i16, i16* %Output, i32 15
+  store i16 %conv62.15, i16* %arrayidx63.15, align 2
+  store i16 %conv62.9, i16* %.reg2mem
+  store i16 %conv62.10, i16* %.reg2mem150
+  store i16 %conv62.11, i16* %.reg2mem152
+  store i16 %conv62.12, i16* %.reg2mem154
+  store i16 %conv62.13, i16* %.reg2mem156
+  store i16 %conv62.14, i16* %.reg2mem158
+  %.reload159 = load i16, i16* %.reg2mem158
+  %.reload157 = load i16, i16* %.reg2mem156
+  %.reload155 = load i16, i16* %.reg2mem154
+  %.reload153 = load i16, i16* %.reg2mem152
+  %.reload151 = load i16, i16* %.reg2mem150
+  %.reload = load i16, i16* %.reg2mem
+  %37 = load i16, i16* %In1, align 2
+  %cmp77 = icmp slt i16 %37, 128
+  br i1 %cmp77, label %A0, label %B0
+
+A0:                                        ; preds = %if.entry
+  store i16 128, i16* %Output, align 2
+  br label %B0
+
+B0:                                         ; preds = %A, %if.entry
+  %38 = phi i16 [ 128, %A0 ], [ %37, %if.entry ]
+  %add84 = add i16 %38, 128
+  %arrayidx74.1 = getelementptr inbounds i16, i16* %Output, i32 1
+  %39 = load i16, i16* %arrayidx74.1, align 2
+  %cmp77.1 = icmp slt i16 %39, %add84
+  br i1 %cmp77.1, label %A1, label %B1
+
+A1:                                      ; preds = %B
+  store i16 %add84, i16* %arrayidx74.1, align 2
+  br label %B1
+
+B1:                                       ; preds = %A1, %B
+  %40 = phi i16 [ %add84, %A1 ], [ %39, %B0 ]
+  %add84.1 = add i16 %40, 128
+  %arrayidx74.2 = getelementptr inbounds i16, i16* %Output, i32 2
+  %41 = load i16, i16* %arrayidx74.2, align 2
+  %cmp77.2 = icmp slt i16 %41, %add84.1
+  br i1 %cmp77.2, label %A2, label %B2
+
+A2:                                      ; preds = %B1
+  store i16 %add84.1, i16* %arrayidx74.2, align 2
+  br label %B2
+
+B2:                                       ; preds = %A2, %B1
+  %42 = phi i16 [ %add84.1, %A2 ], [ %41, %B1 ]
+  %add84.2 = add i16 %42, 128
+  %arrayidx74.3 = getelementptr inbounds i16, i16* %Output, i32 3
+  %43 = load i16, i16* %arrayidx74.3, align 2
+  %cmp77.3 = icmp slt i16 %43, %add84.2
+  br i1 %cmp77.3, label %A3, label %B3
+
+A3:                                      ; preds = %B2
+  store i16 %add84.2, i16* %arrayidx74.3, align 2
+  br label %B3
+
+B3:                                       ; preds = %A3, %B2
+  %44 = phi i16 [ %add84.2, %A3 ], [ %43, %B2 ]
+  %add84.3 = add i16 %44, 128
+  %arrayidx74.4 = getelementptr inbounds i16, i16* %Output, i32 4
+  %45 = load i16, i16* %arrayidx74.4, align 2
+  %cmp77.4 = icmp slt i16 %45, %add84.3
+  br i1 %cmp77.4, label %A4, label %B4
+
+A4:                                      ; preds = %B3
+  store i16 %add84.3, i16* %arrayidx74.4, align 2
+  br label %B4
+
+B4:                                       ; preds = %A4, %B3
+  %46 = phi i16 [ %add84.3, %A4 ], [ %45, %B3 ]
+  %add84.4 = add i16 %46, 128
+  %arrayidx74.5 = getelementptr inbounds i16, i16* %Output, i32 5
+  %47 = load i16, i16* %arrayidx74.5, align 2
+  %cmp77.5 = icmp slt i16 %47, %add84.4
+  br i1 %cmp77.5, label %A5, label %B5
+
+A5:                                      ; preds = %B4
+  store i16 %add84.4, i16* %arrayidx74.5, align 2
+  br label %B5
+
+B5:                                       ; preds = %A5, %B4
+  %48 = phi i16 [ %add84.4, %A5 ], [ %47, %B4 ]
+  %add84.5 = add i16 %48, 128
+  %arrayidx74.6 = getelementptr inbounds i16, i16* %Output, i32 6
+  %49 = load i16, i16* %arrayidx74.6, align 2
+  %cmp77.6 = icmp slt i16 %49, %add84.5
+  br i1 %cmp77.6, label %A6, label %B6
+
+A6:                                      ; preds = %B5
+  store i16 %add84.5, i16* %arrayidx74.6, align 2
+  br label %B6
+
+B6:                                       ; preds = %A6, %B5
+  %50 = phi i16 [ %add84.5, %A6 ], [ %49, %B5 ]
+  %add84.6 = add i16 %50, 128
+  %arrayidx74.7 = getelementptr inbounds i16, i16* %Output, i32 7
+  %51 = load i16, i16* %arrayidx74.7, align 2
+  %cmp77.7 = icmp slt i16 %51, %add84.6
+  br i1 %cmp77.7, label %A7, label %B7
+
+A7:                                      ; preds = %B6
+  store i16 %add84.6, i16* %arrayidx74.7, align 2
+  br label %B7
+
+B7:                                       ; preds = %A7, %B6
+  %52 = phi i16 [ %add84.6, %A7 ], [ %51, %B6 ]
+  %add84.7 = add i16 %52, 128
+  %arrayidx74.8 = getelementptr inbounds i16, i16* %Output, i32 8
+  %53 = load i16, i16* %arrayidx74.8, align 2
+  %cmp77.8 = icmp slt i16 %53, %add84.7
+  br i1 %cmp77.8, label %A8, label %B8
+
+A8:                                      ; preds = %B7
+  store i16 %add84.7, i16* %arrayidx74.8, align 2
+  br label %B8
+
+B8:                                       ; preds = %A8, %B7
+  %54 = phi i16 [ %add84.7, %A8 ], [ %53, %B7 ]
+  %add84.8 = add i16 %54, 128
+  %cmp77.9 = icmp slt i16 %.reload, %add84.8
+  br i1 %cmp77.9, label %A9, label %B9
+
+A9:                                      ; preds = %B8
+  %arrayidx74.9 = getelementptr inbounds i16, i16* %Output, i32 9
+  store i16 %add84.8, i16* %arrayidx74.9, align 2
+  br label %B9
+
+B9:                                       ; preds = %A9, %B8
+  %55 = phi i16 [ %add84.8, %A9 ], [ %.reload, %B8 ]
+  %add84.9 = add i16 %55, 128
+  %cmp77.10 = icmp slt i16 %.reload151, %add84.9
+  br i1 %cmp77.10, label %A10, label %B10
+
+A10:                                     ; preds = %B9
+  %arrayidx74.10 = getelementptr inbounds i16, i16* %Output, i32 10
+  store i16 %add84.9, i16* %arrayidx74.10, align 2
+  br label %B10
+
+B10:                                      ; preds = %A10, %B9
+  %56 = phi i16 [ %add84.9, %A10 ], [ %.reload151, %B9 ]
+  %add84.10 = add i16 %56, 128
+  %cmp77.11 = icmp slt i16 %.reload153, %add84.10
+  br i1 %cmp77.11, label %A11, label %B11
+
+A11:                                     ; preds = %B10
+  %arrayidx74.11 = getelementptr inbounds i16, i16* %Output, i32 11
+  store i16 %add84.10, i16* %arrayidx74.11, align 2
+  br label %B11
+
+B11:                                      ; preds = %A11, %B10
+  %57 = phi i16 [ %add84.10, %A11 ], [ %.reload153, %B10 ]
+  %add84.11 = add i16 %57, 128
+  %cmp77.12 = icmp slt i16 %.reload155, %add84.11
+  br i1 %cmp77.12, label %A12, label %B13
+
+A12:                                     ; preds = %B11
+  %arrayidx74.12 = getelementptr inbounds i16, i16* %Output, i32 12
+  store i16 %add84.11, i16* %arrayidx74.12, align 2
+  br label %B13
+
+B13:                                      ; preds = %A12, %B13
+  ret void
+}
diff --git a/final/test/ScopInfo/complex_domain_binary_condition.ll b/final/test/ScopInfo/complex_domain_binary_condition.ll
new file mode 100644
index 0000000..2319863
--- /dev/null
+++ b/final/test/ScopInfo/complex_domain_binary_condition.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops \
+; RUN:     < %s 2>&1 | FileCheck %s
+;
+; CHECK: Low complexity assumption: {  : 1 = 0 }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.bc_struct.0.2.4.6.13.20.27.43.44.46.50.52.58.60.81.89.90.99.107.108.109.111.116.118.149 = type { i32, i32, i32, i32, [1024 x i8] }
+
+; Function Attrs: nounwind uwtable
+define void @bc_multiply(%struct.bc_struct.0.2.4.6.13.20.27.43.44.46.50.52.58.60.81.89.90.99.107.108.109.111.116.118.149* readonly %n1, i32 %scale) #0 {
+entry:
+  %0 = load i32, i32* undef, align 4
+  %1 = load i32, i32* undef, align 4
+  %2 = load i32, i32* undef, align 4
+  %add3 = add nsw i32 %2, %1
+  %cmp = icmp sgt i32 %0, %2
+  %. = select i1 %cmp, i32 %0, i32 %2
+  %cmp12 = icmp slt i32 %., %scale
+  %scale.. = select i1 %cmp12, i32 %scale, i32 %.
+  %cmp26 = icmp sgt i32 0, %scale..
+  %scale...add7 = select i1 %cmp26, i32 %scale.., i32 0
+  %sub = sub nsw i32 0, %scale...add7
+  %add.ptr = getelementptr inbounds %struct.bc_struct.0.2.4.6.13.20.27.43.44.46.50.52.58.60.81.89.90.99.107.108.109.111.116.118.149, %struct.bc_struct.0.2.4.6.13.20.27.43.44.46.50.52.58.60.81.89.90.99.107.108.109.111.116.118.149* %n1, i64 0, i32 4, i64 0
+  %add.ptr59 = getelementptr inbounds i8, i8* %add.ptr, i64 -1
+  %idx.ext62 = sext i32 %add3 to i64
+  %cmp70140 = icmp sgt i32 %sub, 0
+  br label %for.body104.lr.ph
+
+for.body104.lr.ph:                                ; preds = %entry
+  %3 = add i32 0, -1
+  %4 = sub i32 %3, %scale...add7
+  %5 = add i32 %4, 1
+  %6 = sext i32 %5 to i64
+  br label %for.body104
+
+for.body104:                                      ; preds = %while.end146, %for.body104.lr.ph
+  %indvars.iv = phi i64 [ %6, %for.body104.lr.ph ], [ undef, %while.end146 ]
+  %7 = sub nsw i64 %indvars.iv, %idx.ext62
+  %cmp107 = icmp slt i64 %7, -1
+  %.op = xor i64 %7, -1
+  %idx.neg116 = select i1 %cmp107, i64 0, i64 %.op
+  %add.ptr117 = getelementptr inbounds i8, i8* %add.ptr59, i64 %idx.neg116
+  br label %while.body138
+
+while.body138:                                    ; preds = %while.body138, %for.body104
+  %n1ptr.1126 = phi i8* [ %incdec.ptr139, %while.body138 ], [ %add.ptr117, %for.body104 ]
+  %incdec.ptr139 = getelementptr inbounds i8, i8* %n1ptr.1126, i64 -1
+  %cmp132 = icmp uge i8* %incdec.ptr139, null
+  %cmp135 = icmp slt i64 0, -1
+  %or.cond99 = and i1 %cmp135, %cmp132
+  br i1 %or.cond99, label %while.body138, label %while.end146
+
+while.end146:                                     ; preds = %while.body138
+  br i1 undef, label %free_num.exit, label %for.body104
+
+free_num.exit:                                    ; preds = %while.end146
+  ret void
+}
diff --git a/final/test/ScopInfo/complex_execution_context.ll b/final/test/ScopInfo/complex_execution_context.ll
new file mode 100644
index 0000000..b7add14
--- /dev/null
+++ b/final/test/ScopInfo/complex_execution_context.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN:     < %s 2>&1 | FileCheck %s
+;
+; CHECK: Low complexity assumption:
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@board = external global [421 x i8], align 16
+
+; Function Attrs: nounwind uwtable
+define fastcc void @ping_recurse(i32* nocapture %mx, i32* nocapture %mr, i32 %color) unnamed_addr {
+entry:
+  br label %land.lhs.true38.1
+
+if.end58:                                         ; preds = %land.lhs.true38.2, %if.end54.1
+  ret void
+
+land.lhs.true38.1:                                ; preds = %entry
+  %arrayidx34.1 = getelementptr inbounds [421 x i8], [421 x i8]* @board, i64 0, i64 0
+  %arrayidx40.1 = getelementptr inbounds i32, i32* %mr, i64 0
+  %0 = load i32, i32* %arrayidx40.1, align 4
+  %cmp41.1 = icmp eq i32 %0, 0
+  br i1 %cmp41.1, label %land.lhs.true43.1, label %if.end54.1
+
+land.lhs.true43.1:                                ; preds = %land.lhs.true38.1
+  %arrayidx45.1 = getelementptr inbounds i32, i32* %mx, i64 0
+  %1 = load i32, i32* %arrayidx45.1, align 4
+  %cmp46.1 = icmp eq i32 %1, 1
+  %cmp51.1 = icmp eq i32 0, %color
+  %or.cond.1 = or i1 %cmp51.1, %cmp46.1
+  br i1 %or.cond.1, label %if.then53.1, label %if.end54.1
+
+if.then53.1:                                      ; preds = %land.lhs.true43.1
+  tail call fastcc void @ping_recurse(i32* nonnull %mx, i32* nonnull %mr, i32 %color)
+  br label %if.end54.1
+
+if.end54.1:                                       ; preds = %if.then53.1, %land.lhs.true43.1, %land.lhs.true38.1
+  %arrayidx34.2 = getelementptr inbounds [421 x i8], [421 x i8]* @board, i64 0, i64 0
+  %2 = load i8, i8* %arrayidx34.2, align 1
+  %cmp36.2 = icmp eq i8 %2, 3
+  br i1 %cmp36.2, label %if.end58, label %land.lhs.true38.2
+
+land.lhs.true38.2:                                ; preds = %if.end54.1
+  %arrayidx40.2 = getelementptr inbounds i32, i32* %mr, i64 0
+  %3 = load i32, i32* %arrayidx40.2, align 4
+  br label %if.end58
+}
diff --git a/final/test/ScopInfo/cond_constant_in_loop.ll b/final/test/ScopInfo/cond_constant_in_loop.ll
new file mode 100644
index 0000000..7fe2a94
--- /dev/null
+++ b/final/test/ScopInfo/cond_constant_in_loop.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+;void f(long a[], long N, long M) {
+;  long i, j, k;
+;  for (j = 0; j < M; ++j)
+;    if (true)
+;      a[j] = j;
+;    else {
+;      a[j] = M;
+;      a[j - N] = 0;
+;    }
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* nocapture %a, i64 %N, i64 %M) nounwind {
+entry:
+  %0 = icmp sgt i64 %M, 0                         ; <i1> [#uses=1]
+  br i1 %0, label %bb, label %return
+
+bb:                                               ; preds = %bb3, %entry
+  %1 = phi i64 [ 0, %entry ], [ %2, %bb3 ]        ; <i64> [#uses=5]
+  %scevgep = getelementptr i64, i64* %a, i64 %1        ; <i64*> [#uses=2]
+  br i1 true, label %bb1, label %bb2
+
+bb1:                                              ; preds = %bb
+  store i64 %1, i64* %scevgep, align 8
+  br label %bb3
+
+bb2:                                              ; preds = %bb
+  %tmp7 = sub i64 %1, %N                          ; <i64> [#uses=1]
+  %scevgep8 = getelementptr i64, i64* %a, i64 %tmp7    ; <i64*> [#uses=1]
+  store i64 %M, i64* %scevgep, align 8
+  store i64 0, i64* %scevgep8, align 8
+  br label %bb3
+
+bb3:                                              ; preds = %bb2, %bb1
+  %2 = add nsw i64 %1, 1                          ; <i64> [#uses=2]
+  %exitcond = icmp eq i64 %2, %M                  ; <i1> [#uses=1]
+  br i1 %exitcond, label %return, label %bb
+
+return:                                           ; preds = %bb3, %entry
+  ret void
+}
+
+; CHECK:     Stmt_bb1
+; CHECK:       Domain :=
+; CHECK:         [M] -> { Stmt_bb1[i0] : 0 <= i0 < M };
+; CHECK-NOT: Stmt_bb2
diff --git a/final/test/ScopInfo/cond_in_loop.ll b/final/test/ScopInfo/cond_in_loop.ll
new file mode 100644
index 0000000..a971ede
--- /dev/null
+++ b/final/test/ScopInfo/cond_in_loop.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+;void f(long a[], long N, long M) {
+;  long i, j, k;
+;  for (j = 0; j < M; ++j)
+;    if (N > j)
+;      a[j] = j;
+;    else {
+;      a[j] = M;
+;      a[j - N] = 0;
+;    }
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* nocapture %a, i64 %N, i64 %M) nounwind {
+entry:
+  %0 = icmp sgt i64 %M, 0                         ; <i1> [#uses=1]
+  br i1 %0, label %bb, label %return
+
+bb:                                               ; preds = %bb3, %entry
+  %1 = phi i64 [ 0, %entry ], [ %3, %bb3 ]        ; <i64> [#uses=5]
+  %scevgep = getelementptr i64, i64* %a, i64 %1        ; <i64*> [#uses=2]
+  %2 = icmp slt i64 %1, %N                        ; <i1> [#uses=1]
+  br i1 %2, label %bb1, label %bb2
+
+bb1:                                              ; preds = %bb
+  store i64 %1, i64* %scevgep, align 8
+  br label %bb3
+
+bb2:                                              ; preds = %bb
+  %tmp7 = sub i64 %1, %N                          ; <i64> [#uses=1]
+  %scevgep8 = getelementptr i64, i64* %a, i64 %tmp7    ; <i64*> [#uses=1]
+  store i64 %M, i64* %scevgep, align 8
+  store i64 0, i64* %scevgep8, align 8
+  br label %bb3
+
+bb3:                                              ; preds = %bb2, %bb1
+  %3 = add nsw i64 %1, 1                          ; <i64> [#uses=2]
+  %exitcond = icmp eq i64 %3, %M                  ; <i1> [#uses=1]
+  br i1 %exitcond, label %return, label %bb
+
+return:                                           ; preds = %bb3, %entry
+  ret void
+}
+
+; CHECK-LABEL:      Function: f
+; CHECK-NEXT:      Region: %bb---%return
diff --git a/final/test/ScopInfo/condition-after-error-block-2.ll b/final/test/ScopInfo/condition-after-error-block-2.ll
new file mode 100644
index 0000000..4d8e176
--- /dev/null
+++ b/final/test/ScopInfo/condition-after-error-block-2.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; Verify that we do not allow PHI nodes such as %phi, if they reference an error
+; block and are used by anything else than a terminator instruction.
+
+; CHECK:      Statements {
+; CHECK-NEXT: 	Stmt_loop
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p] -> { Stmt_loop[i0] : p >= 13 and 0 <= i0 <= 1025 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p] -> { Stmt_loop[i0] -> [i0] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [p] -> { Stmt_loop[i0] -> MemRef_X[0] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p] -> { Stmt_loop[i0] -> MemRef_phi[] };
+; CHECK-NEXT: }
+
+declare void @bar()
+
+define void @foo(float* %X, i64 %p) {
+entry:
+  br label %br
+
+br:
+  %cmp1 = icmp sle i64 %p, 12
+  br i1 %cmp1, label %A, label %br2
+
+br2:
+  %cmp3 = icmp sle i64 %p, 12
+  br i1 %cmp3, label %cond, label %loop
+
+loop:
+  %indvar = phi i64 [0, %br2], [%indvar.next, %loop]
+  %indvar.next = add nsw i64 %indvar, 1
+  store float 41.0, float* %X
+  %cmp2 = icmp sle i64 %indvar, 1024
+  br i1 %cmp2, label %loop, label %merge
+
+cond:
+  br label %cond2
+
+cond2:
+  call void @bar()
+  br label %merge
+
+merge:
+  %phi = phi i1 [false, %cond2], [true, %loop]
+  %add = add i1 %phi, 1
+  br i1 %add, label %A, label %B
+
+A:
+  store float 42.0, float* %X
+  br label %exit
+
+B:
+  call void @bar()
+  store float 41.0, float* %X
+  br label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/condtion-after-error-block.ll b/final/test/ScopInfo/condtion-after-error-block.ll
new file mode 100644
index 0000000..5fa3c1e
--- /dev/null
+++ b/final/test/ScopInfo/condtion-after-error-block.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; Verify that we allow scops containing uniform branch conditions, where all
+; but one incoming block comes from an error condition.
+
+; CHECK:         Statements {
+; CHECK-NEXT:     	Stmt_A
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 [p] -> { Stmt_A[] };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 [p] -> { Stmt_A[] -> [1, 0] };
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [p] -> { Stmt_A[] -> MemRef_X[0] };
+; CHECK-NEXT:     	Stmt_loop
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 [p] -> { Stmt_loop[i0] : p >= 13 and 0 <= i0 <= 1025 };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 [p] -> { Stmt_loop[i0] -> [0, i0] };
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [p] -> { Stmt_loop[i0] -> MemRef_X[0] };
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [p] -> { Stmt_loop[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:     }
+
+declare void @bar()
+
+define void @foo(float* %X, i64 %p) {
+entry:
+  br label %br
+
+br:
+  %cmp1 = icmp sle i64 %p, 12
+  br i1 %cmp1, label %A, label %br2
+
+br2:
+  %cmp3 = icmp sle i64 %p, 12
+  br i1 %cmp3, label %cond, label %loop
+
+loop:
+  %indvar = phi i64 [0, %br2], [%indvar.next, %loop]
+  %indvar.next = add nsw i64 %indvar, 1
+  store float 41.0, float* %X
+  %cmp2 = icmp sle i64 %indvar, 1024
+  br i1 %cmp2, label %loop, label %merge
+
+cond:
+  br label %cond2
+
+cond2:
+  call void @bar()
+  br label %merge
+
+merge:
+  %phi = phi i1 [false, %cond2], [true, %loop]
+  br i1 %phi, label %A, label %B
+
+A:
+  store float 42.0, float* %X
+  br label %exit
+
+B:
+  call void @bar()
+  store float 41.0, float* %X
+  br label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/const_srem_sdiv.ll b/final/test/ScopInfo/const_srem_sdiv.ll
new file mode 100644
index 0000000..3c50cb8
--- /dev/null
+++ b/final/test/ScopInfo/const_srem_sdiv.ll
@@ -0,0 +1,104 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+; See http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf
+;
+;    void f(long *A) {
+;      for (long i = 0; i < 10; i++) {
+;        A[8 / 3] = A[8 % 3];
+;        A[8 / -3] = A[8 % -3];
+;        A[-8 / 3] = A[-8 % 3];
+;        A[-8 / -3] = A[-8 % -3];
+;        A[1 / 2] = A[1 % 2];
+;        A[1 / -2] = A[1 % -2];
+;        A[-1 / 2] = A[-1 % 2];
+;        A[-1 / -2] = A[-1 % -2];
+;      }
+;    }
+;
+; CHECK:   { Stmt_for_body[i0] -> MemRef_R[2] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_R[2] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_R[-2] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_R[-2] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_R[1] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_R[1] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_R[-1] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_R[-1] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_D[2] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_D[-2] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_D[-2] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_D[2] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_D[0] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_D[0] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_D[0] };
+; CHECK:   { Stmt_for_body[i0] -> MemRef_D[0] };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i64* %D, i64* %R) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %i.0, 10
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %rem = srem i64 8, 3
+  %arrayidx = getelementptr inbounds i64, i64* %R, i64 %rem
+  %tmp = load i64, i64* %arrayidx, align 8
+  %div = sdiv i64 8, 3
+  %arrayidx1 = getelementptr inbounds i64, i64* %D, i64 %div
+  store i64 %tmp, i64* %arrayidx1, align 8
+  %rem2 = srem i64 8, -3
+  %arrayidx3 = getelementptr inbounds i64, i64* %R, i64 %rem2
+  %tmp1 = load i64, i64* %arrayidx3, align 8
+  %div5 = sdiv i64 8, -3
+  %arrayidx6 = getelementptr inbounds i64, i64* %D, i64 %div5
+  store i64 %tmp1, i64* %arrayidx6, align 8
+  %rem8 = srem i64 -8, 3
+  %arrayidx9 = getelementptr inbounds i64, i64* %R, i64 %rem8
+  %tmp2 = load i64, i64* %arrayidx9, align 8
+  %div11 = sdiv i64 -8, 3
+  %arrayidx12 = getelementptr inbounds i64, i64* %D, i64 %div11
+  store i64 %tmp2, i64* %arrayidx12, align 8
+  %rem15 = srem i64 -8, -3
+  %arrayidx16 = getelementptr inbounds i64, i64* %R, i64 %rem15
+  %tmp3 = load i64, i64* %arrayidx16, align 8
+  %div19 = sdiv i64 -8, -3
+  %arrayidx20 = getelementptr inbounds i64, i64* %D, i64 %div19
+  store i64 %tmp3, i64* %arrayidx20, align 8
+  %rem29 = srem i64 1, 2
+  %arrayidx30 = getelementptr inbounds i64, i64* %R, i64 %rem29
+  %tmp5 = load i64, i64* %arrayidx30, align 8
+  %div31 = sdiv i64 1, 2
+  %arrayidx32 = getelementptr inbounds i64, i64* %D, i64 %div31
+  store i64 %tmp5, i64* %arrayidx32, align 8
+  %rem34 = srem i64 1, -2
+  %arrayidx35 = getelementptr inbounds i64, i64* %R, i64 %rem34
+  %tmp6 = load i64, i64* %arrayidx35, align 8
+  %div37 = sdiv i64 1, -2
+  %arrayidx38 = getelementptr inbounds i64, i64* %D, i64 %div37
+  store i64 %tmp6, i64* %arrayidx38, align 8
+  %rem40 = srem i64 -1, 2
+  %arrayidx41 = getelementptr inbounds i64, i64* %R, i64 %rem40
+  %tmp7 = load i64, i64* %arrayidx41, align 8
+  %div43 = sdiv i64 -1, 2
+  %arrayidx44 = getelementptr inbounds i64, i64* %D, i64 %div43
+  store i64 %tmp7, i64* %arrayidx44, align 8
+  %rem47 = srem i64 -1, -2
+  %arrayidx48 = getelementptr inbounds i64, i64* %R, i64 %rem47
+  %tmp8 = load i64, i64* %arrayidx48, align 8
+  %div51 = sdiv i64 -1, -2
+  %arrayidx52 = getelementptr inbounds i64, i64* %D, i64 %div51
+  store i64 %tmp8, i64* %arrayidx52, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/constant-non-integer-branch-condition.ll b/final/test/ScopInfo/constant-non-integer-branch-condition.ll
new file mode 100644
index 0000000..c58f92d
--- /dev/null
+++ b/final/test/ScopInfo/constant-non-integer-branch-condition.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -analyze -polly-scops %s | FileCheck %s
+;
+; At some point this caused a problem in the domain generation as we
+; assumed any constant branch condition to be valid. However, only constant
+; integers are interesting and can be handled.
+;
+; CHECK: Stmt_entry_split__TO__cleanup
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define i32 @main(i32* %A) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br i1 icmp ne (i32 (...)* @test_weak, i32 (...)* null), label %if.then, label %cleanup
+
+if.then:                                          ; preds = %entry.split
+  store i32 0, i32* %A
+  br label %cleanup
+
+cleanup:                                          ; preds = %if.then, %entry.split
+  ret i32 0
+}
+
+declare extern_weak i32 @test_weak(...)
diff --git a/final/test/ScopInfo/constant_factor_in_parameter.ll b/final/test/ScopInfo/constant_factor_in_parameter.ll
new file mode 100644
index 0000000..381ef36
--- /dev/null
+++ b/final/test/ScopInfo/constant_factor_in_parameter.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s
+; RUN: opt %loadPolly -analyze -polly-function-scops < %s | FileCheck %s
+;
+; Check that the constant part of the N * M * 4 expression is not part of the
+; parameter but explicit in the access function. This can avoid existentially
+; quantified variables, e.g., when computing the stride.
+;
+; CHECK: p1: (%N * %M)
+; CHECK: [N, p_1] -> { Stmt_for_body[i0] -> MemRef_A[4p_1 + i0] };
+;
+;    void f(int *A, int N, int M) {
+;      for (int i = 0; i < N; i++)
+;        A[i + N * M * 4] = i;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N, i32 %M) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %mul = mul nsw i32 %N, %M
+  %mul2 = mul nsw i32 %mul, 4
+  %tmp2 = sext i32 %mul2 to i64
+  %tmp3 = add nsw i64 %indvars.iv, %tmp2
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %tmp3
+  %tmp4 = trunc i64 %indvars.iv to i32
+  store i32 %tmp4, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/constant_functions_as_unknowns.ll b/final/test/ScopInfo/constant_functions_as_unknowns.ll
new file mode 100644
index 0000000..367be74
--- /dev/null
+++ b/final/test/ScopInfo/constant_functions_as_unknowns.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK:      Context:
+; CHECK-NEXT: [__global_id_0] -> {  : -9223372036854775808 <= __global_id_0 <= 9223372036854775807 }
+; CHECK-NEXT: Assumed Context:
+; CHECK-NEXT: [__global_id_0] -> {  :  }
+; CHECK-NEXT: Invalid Context:
+; CHECK-NEXT: [__global_id_0] -> {  : 1 = 0 }
+; CHECK-NEXT: p0: %__global_id_0
+; CHECK-NEXT: Arrays {
+; CHECK-NEXT:     i64 MemRef_A[*]; // Element size 8
+; CHECK-NEXT: }
+; CHECK-NEXT: Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:     i64 MemRef_A[*]; // Element size 8
+; CHECK-NEXT: }
+; CHECK-NEXT: Alias Groups (0):
+; CHECK-NEXT:     n/a
+; CHECK-NEXT: Statements {
+; CHECK-NEXT: 	Stmt_bb
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [__global_id_0] -> { Stmt_bb[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [__global_id_0] -> { Stmt_bb[] -> [] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [__global_id_0] -> { Stmt_bb[] -> MemRef_A[__global_id_0] };
+; CHECK-NEXT: }
+
+define void @globalid(i64* nocapture %A) local_unnamed_addr #0 !kernel_arg_addr_space !2 !kernel_arg_access_qual !3 !kernel_arg_type !4 !kernel_arg_base_type !4 !kernel_arg_type_qual !5 {
+entry:
+  br label %next
+
+next:
+  br i1 true, label %bb, label %exit
+
+bb:
+  %__global_id_0 = tail call i64 @_Z13get_global_idj(i32 0) #2
+  %arrayidx = getelementptr inbounds i64, i64* %A, i64 %__global_id_0
+  store i64 0, i64* %arrayidx, align 8, !tbaa !6
+  br label %exit
+
+exit:
+  ret void
+}
+
+; Function Attrs: nounwind readnone
+declare i64 @_Z13get_global_idj(i32) local_unnamed_addr #1
+
+attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-__global_id_0s"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-__global_id_0s"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang version 5.0.0 (trunk 303846) (llvm/trunk 303834)"}
+!2 = !{i32 1}
+!3 = !{!"none"}
+!4 = !{!"long*"}
+!5 = !{!""}
+!6 = !{!7, !7, i64 0}
+!7 = !{!"long", !8, i64 0}
+!8 = !{!"omnipotent char", !9, i64 0}
+!9 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/ScopInfo/constant_functions_multi_dim.ll b/final/test/ScopInfo/constant_functions_multi_dim.ll
new file mode 100644
index 0000000..726e19f
--- /dev/null
+++ b/final/test/ScopInfo/constant_functions_multi_dim.ll
@@ -0,0 +1,118 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN:                -polly-detect-full-functions < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK:         Statements {
+; CHECK-NEXT:    	Stmt_entry_split
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_entry_split[] };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_entry_split[] -> [0, 0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_entry_split[] -> MemRef_acc_0_lcssa__phi[] };
+; CHECK-NEXT:    	Stmt_for_inc_lr_ph
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_inc_lr_ph[] : N > 0 };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_inc_lr_ph[] -> [1, 0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_inc_lr_ph[] -> MemRef_acc_03__phi[] };
+; CHECK-NEXT:    	Stmt_for_inc
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_inc[i0] : 0 <= i0 < N };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_inc[i0] -> [2, i0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_inc[i0] -> MemRef_acc_03__phi[] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_inc[i0] -> MemRef_acc_03__phi[] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_inc[i0] -> MemRef_A[__global_id_0, i0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_inc[i0] -> MemRef_B[i0, __global_id_1] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_inc[i0] -> MemRef__lcssa__phi[] };
+; CHECK-NEXT:    	Stmt_for_cond_for_end_crit_edge
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_cond_for_end_crit_edge[] : N > 0 };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_cond_for_end_crit_edge[] -> [3, 0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_cond_for_end_crit_edge[] -> MemRef__lcssa__phi[] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_cond_for_end_crit_edge[] -> MemRef_acc_0_lcssa__phi[] };
+; CHECK-NEXT:    	Stmt_for_end
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_end[] };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_end[] -> [4, 0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_end[] -> MemRef_acc_0_lcssa__phi[] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [N, __global_id_0, __global_id_1] -> { Stmt_for_end[] -> MemRef_C[__global_id_0, __global_id_1] };
+; CHECK-NEXT:    }
+
+
+; Function Attrs: noinline nounwind uwtable
+define void @mat_mul(float* %C, float* %A, float* %B, i64 %N) #0 !kernel_arg_addr_space !2 !kernel_arg_access_qual !3 !kernel_arg_type !4 !kernel_arg_base_type !4 !kernel_arg_type_qual !5 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %call = tail call i64 @_Z13get_global_idj(i32 0) #3
+  %call1 = tail call i64 @_Z13get_global_idj(i32 1) #3
+  %cmp1 = icmp sgt i64 %N, 0
+  %mul = mul nsw i64 %call, %N
+  br i1 %cmp1, label %for.inc.lr.ph, label %for.end
+
+for.inc.lr.ph:                                    ; preds = %entry.split
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.inc.lr.ph, %for.inc
+  %acc.03 = phi float [ 0.000000e+00, %for.inc.lr.ph ], [ %tmp6, %for.inc ]
+  %m.02 = phi i64 [ 0, %for.inc.lr.ph ], [ %inc, %for.inc ]
+  %add = add nsw i64 %m.02, %mul
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %add
+  %tmp = load float, float* %arrayidx, align 4
+  %mul2 = mul nsw i64 %m.02, %N
+  %add3 = add nsw i64 %mul2, %call1
+  %arrayidx4 = getelementptr inbounds float, float* %B, i64 %add3
+  %tmp5 = load float, float* %arrayidx4, align 4
+  %tmp6 = tail call float @llvm.fmuladd.f32(float %tmp, float %tmp5, float %acc.03)
+  %inc = add nuw nsw i64 %m.02, 1
+  %exitcond = icmp ne i64 %inc, %N
+  br i1 %exitcond, label %for.inc, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %for.inc
+  %.lcssa = phi float [ %tmp6, %for.inc ]
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  %acc.0.lcssa = phi float [ %.lcssa, %for.cond.for.end_crit_edge ], [ 0.000000e+00, %entry.split ]
+  %add7 = add nsw i64 %mul, %call1
+  %arrayidx8 = getelementptr inbounds float, float* %C, i64 %add7
+  store float %acc.0.lcssa, float* %arrayidx8, align 4
+  ret void
+}
+
+; Function Attrs: nounwind readnone
+declare i64 @_Z13get_global_idj(i32) #1
+
+; Function Attrs: nounwind readnone speculatable
+declare float @llvm.fmuladd.f32(float, float, float) #2
+
+attributes #0 = { noinline nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone speculatable }
+attributes #3 = { nounwind readnone }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang version 5.0.0 (trunk 303846) (llvm/trunk 303834)"}
+!2 = !{i32 1, i32 1, i32 1, i32 0}
+!3 = !{!"none", !"none", !"none", !"none"}
+!4 = !{!"float*", !"float*", !"float*", !"long"}
+!5 = !{!"", !"", !"", !""}
diff --git a/final/test/ScopInfo/constant_functions_outside_scop_as_unknown.ll b/final/test/ScopInfo/constant_functions_outside_scop_as_unknown.ll
new file mode 100644
index 0000000..b1029a3
--- /dev/null
+++ b/final/test/ScopInfo/constant_functions_outside_scop_as_unknown.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-process-unprofitable -polly-scops -analyze < %s | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+
+; CHECK: Region: %for.cond62---%for.cond
+; CHECK: p0: {0,+,1}<nuw><%for.cond>
+; CHECK-NEXT: p1: %param1
+; CHECK-NEXT: p2: %param2
+; CHECK-NEXT: Arrays {
+
+define void @f(i8* %param1) {
+entry:
+  br label %for.cond
+
+for.cond:
+  %hook = phi i8* [ %param1, %entry ], [ %add.ptr201, %cleanup ]
+  br i1 undef, label %for.body, label %for.cond.cleanup
+
+for.body:
+  %param2 = call i32 @g()
+  %add.ptr60 = getelementptr inbounds i8, i8* %hook, i32 %param2
+  br label %for.cond62
+
+for.cond62:
+  %cmp64 = icmp ule i8* %add.ptr60, null
+  br i1 %cmp64, label %for.cond62, label %cleanup
+
+cleanup:
+  %add.ptr201 = getelementptr inbounds i8, i8* %hook, i32 1
+  br label %for.cond
+
+for.cond.cleanup:
+  ret void
+}
+
+declare i32 @g()
diff --git a/final/test/ScopInfo/constant_start_integer.ll b/final/test/ScopInfo/constant_start_integer.ll
new file mode 100644
index 0000000..dff6d10
--- /dev/null
+++ b/final/test/ScopInfo/constant_start_integer.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; void foo(float *input) {
+;   for (int j = 0; j < 8; j++) {
+;     //SCoP begin
+;     for (int i = 0; i < 63; i++) {
+;       float x = input[j * 64 + i + 1];
+;       input[j * 64 + i + 0] = x * x;
+;     }
+;   }
+; }
+
+; CHECK  p0: {0,+,256}<%for.cond1.preheader>
+; CHECK-NOT: p1
+
+; CHECK: ReadAccess
+; CHECK:   [p_0] -> { Stmt_for_body3[i0] -> MemRef_input[1 + 64p_0 + i0] };
+; CHECK: MustWriteAccess
+; CHECK:   [p_0] -> { Stmt_for_body3[i0] -> MemRef_input[64p_0 + i0] };
+
+define void @foo(float* nocapture %input) {
+entry:
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.inc10, %entry
+  %j.021 = phi i64 [ 0, %entry ], [ %inc11, %for.inc10 ]
+  %mul = shl nsw i64 %j.021, 6
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.body3, %for.cond1.preheader
+  %i.020 = phi i64 [ 0, %for.cond1.preheader ], [ %inc, %for.body3 ]
+  %add = add nsw i64 %i.020, %mul
+  %add4 = add nsw i64 %add, 1
+  %arrayidx = getelementptr inbounds float, float* %input, i64 %add4
+  %0 = load float, float* %arrayidx, align 8
+  %mul5 = fmul float %0, %0
+  %arrayidx9 = getelementptr inbounds float, float* %input, i64 %add
+  store float %mul5, float* %arrayidx9, align 8
+  %inc = add nsw i64 %i.020, 1
+  %exitcond = icmp eq i64 %inc, 63
+  br i1 %exitcond, label %for.inc10, label %for.body3
+
+for.inc10:                                        ; preds = %for.body3
+  %inc11 = add nsw i64 %j.021, 1
+  %exitcond22 = icmp eq i64 %inc11, 8
+  fence seq_cst
+  br i1 %exitcond22, label %for.end12, label %for.cond1.preheader
+
+for.end12:                                        ; preds = %for.inc10
+  ret void
+}
diff --git a/final/test/ScopInfo/delinearize-together-all-data-refs.ll b/final/test/ScopInfo/delinearize-together-all-data-refs.ll
new file mode 100644
index 0000000..484a7de
--- /dev/null
+++ b/final/test/ScopInfo/delinearize-together-all-data-refs.ll
@@ -0,0 +1,81 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; void foo(long n, long m, long o, double A[n][m][o]) {
+;   for (long i = 0; i < n-3; i++)
+;     for (long j = 4; j < m; j++)
+;       for (long k = 0; k < o-7; k++) {
+;         A[i+3][j-4][k+7] = 1.0;
+;         A[i][0][k] = 2.0;
+;       }
+; }
+
+
+; CHECK: Arrays {
+; CHECK:     double MemRef_A[*][%m][%o]; // Element size 8
+; CHECK: }
+
+; CHECK: [m, o, n] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[3 + i0, i1, 7 + i2] };
+; CHECK: [m, o, n] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @foo(i64 %n, i64 %m, i64 %o, double* nocapture %A) {
+entry:
+  %cmp35 = icmp sgt i64 %n, 0
+  br i1 %cmp35, label %for.cond1.preheader.lr.ph, label %for.end18
+
+for.cond1.preheader.lr.ph:                        ; preds = %entry
+  %cmp233 = icmp sgt i64 %m, 0
+  %cmp531 = icmp sgt i64 %o, 0
+  %0 = mul nuw i64 %o, %m
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %for.inc16, %for.cond1.preheader.lr.ph
+  %i.036 = phi i64 [ 0, %for.cond1.preheader.lr.ph ], [ %inc17, %for.inc16 ]
+  br i1 %cmp233, label %for.cond4.preheader.lr.ph, label %for.inc16
+
+for.cond4.preheader.lr.ph:                        ; preds = %for.cond1.preheader
+  %add7 = add nsw i64 %i.036, 3
+  %1 = mul nsw i64 %add7, %0
+  %add = add i64 %1, 7
+  %2 = mul nsw i64 %i.036, %0
+  br label %for.cond4.preheader
+
+for.cond4.preheader:                              ; preds = %for.inc13, %for.cond4.preheader.lr.ph
+  %j.034 = phi i64 [ 4, %for.cond4.preheader.lr.ph ], [ %inc14, %for.inc13 ]
+  br i1 %cmp531, label %for.body6.lr.ph, label %for.inc13
+
+for.body6.lr.ph:                                  ; preds = %for.cond4.preheader
+  %sub = add nsw i64 %j.034, -4
+  %3 = mul nsw i64 %sub, %o
+  %arrayidx.sum = add i64 %add, %3
+  br label %for.body6
+
+for.body6:                                        ; preds = %for.body6, %for.body6.lr.ph
+  %k.032 = phi i64 [ 0, %for.body6.lr.ph ], [ %inc, %for.body6 ]
+  %arrayidx8.sum = add i64 %arrayidx.sum, %k.032
+  %arrayidx9 = getelementptr inbounds double, double* %A, i64 %arrayidx8.sum
+  store double 1.000000e+00, double* %arrayidx9, align 8
+  %arrayidx10.sum = add i64 %k.032, %2
+  %arrayidx12 = getelementptr inbounds double, double* %A, i64 %arrayidx10.sum
+  store double 2.000000e+00, double* %arrayidx12, align 8
+  %inc = add nsw i64 %k.032, 1
+  %osub = sub nsw i64 %o, 7
+  %exitcond = icmp eq i64 %inc, %osub
+  br i1 %exitcond, label %for.inc13, label %for.body6
+
+for.inc13:                                        ; preds = %for.body6, %for.cond4.preheader
+  %inc14 = add nsw i64 %j.034, 1
+  %exitcond37 = icmp eq i64 %inc14, %m
+  br i1 %exitcond37, label %for.inc16, label %for.cond4.preheader
+
+for.inc16:                                        ; preds = %for.inc13, %for.cond1.preheader
+  %inc17 = add nsw i64 %i.036, 1
+  %nsub = sub nsw i64 %n, 3
+  %exitcond38 = icmp eq i64 %inc17, %nsub
+  br i1 %exitcond38, label %for.end18, label %for.cond1.preheader
+
+for.end18:                                        ; preds = %for.inc16, %entry
+  ret void
+}
diff --git a/final/test/ScopInfo/div_by_zero.ll b/final/test/ScopInfo/div_by_zero.ll
new file mode 100644
index 0000000..5cd408c
--- /dev/null
+++ b/final/test/ScopInfo/div_by_zero.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        A[i / 0]++;
+;    }
+;
+; CHECK-NOT: Statement
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc1, %for.inc ]
+  %cmp = icmp slt i32 %i.0, %N
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %div = sdiv i32 %i.0, 0
+  %idxprom = sext i32 %div to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  %tmp = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc1 = add nuw nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/do-not-model-error-block-accesses.ll b/final/test/ScopInfo/do-not-model-error-block-accesses.ll
new file mode 100644
index 0000000..a161afc
--- /dev/null
+++ b/final/test/ScopInfo/do-not-model-error-block-accesses.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s
+
+; Check that we do not crash on this input. Earlier this indeed crashed as
+; we tried to model the access functions in an error block.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @FORMAT3_4() #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br i1 false, label %if.end.38, label %if.else
+
+if.else:                                          ; preds = %entry.split
+  call void (i32, i32, i32*, ...) bitcast (void (...)* @BYTES_TO_BITS to void (i32, i32, i32*, ...)*)(i32 undef, i32 1, i32* undef) #2
+  %0 = load i32, i32* null, align 4
+  br label %if.end.38
+
+if.end.38:                                        ; preds = %if.else, %entry.split
+  unreachable
+}
+
+declare void @BYTES_TO_BITS(...) #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="haswell" "target-features"="+aes,+avx,+avx2,+bmi,+bmi2,+cmov,+cx16,+f16c,+fma,+fsgsbase,+fxsr,+hle,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+rdrnd,+rtm,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+xsave,+xsaveopt,-adx,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512pf,-avx512vl,-fma4,-prfchw,-rdseed,-sha,-sse4a,-tbm,-xop,-xsavec,-xsaves" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="haswell" "target-features"="+aes,+avx,+avx2,+bmi,+bmi2,+cmov,+cx16,+f16c,+fma,+fsgsbase,+fxsr,+hle,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+rdrnd,+rtm,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+xsave,+xsaveopt,-adx,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512pf,-avx512vl,-fma4,-prfchw,-rdseed,-sha,-sse4a,-tbm,-xop,-xsavec,-xsaves" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (http://llvm.org/git/clang.git 65eeefc97d2eee4d075ec7d9ed56b5f0786b6421)"}
diff --git a/final/test/ScopInfo/eager-binary-and-or-conditions.ll b/final/test/ScopInfo/eager-binary-and-or-conditions.ll
new file mode 100644
index 0000000..281c6a5
--- /dev/null
+++ b/final/test/ScopInfo/eager-binary-and-or-conditions.ll
@@ -0,0 +1,104 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -analyze < %s
+;
+; void or(float *A, long n, long m) {
+;   for (long i = 0; i < 100; i++) {
+;     if (i < n || i < m)
+;       A[i] += i;
+;   }
+; }
+;
+; void and(float *A, long n, long m) {
+;   for (long i = 0; i < 100; i++) {
+;     if (i < n && i < m)
+;       A[i] += i;
+;   }
+; }
+
+; CHECK-LABEL: Function: or
+;
+; CHECK:       Statements {
+; CHECK-NEXT:      Stmt_if_then
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [n, m] -> { Stmt_if_then[i0] : 0 <= i0 <= 99 and (i0 < m or i0 < n) };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [n, m] -> { Stmt_if_then[i0] -> [i0] : i0 < m or i0 < n };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              [n, m] -> { Stmt_if_then[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              [n, m] -> { Stmt_if_then[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:  }
+;
+; CHECK-LABEL: Function: and
+;
+; CHECK:       Statements {
+; CHECK-NEXT:      Stmt_if_then
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [n, m] -> { Stmt_if_then[i0] : 0 <= i0 <= 99 and i0 < m and i0 < n };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [n, m] -> { Stmt_if_then[i0] -> [i0] };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              [n, m] -> { Stmt_if_then[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              [n, m] -> { Stmt_if_then[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:  }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @or(float* nocapture %A, i64 %n, i64 %m) #0 {
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %for.inc, %entry
+  %i.03 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp1 = icmp slt i64 %i.03, %n
+  %cmp2 = icmp slt i64 %i.03, %m
+  %or.cond = or i1 %cmp1, %cmp2
+  br i1 %or.cond, label %if.then, label %for.inc
+
+if.then:                                          ; preds = %for.body
+  %conv = sitofp i64 %i.03 to float
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.03
+  %0 = load float, float* %arrayidx, align 4
+  %add = fadd float %conv, %0
+  store float %add, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.then, %for.body
+  %inc = add nuw nsw i64 %i.03, 1
+  %exitcond = icmp eq i64 %inc, 100
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.inc
+  ret void
+}
+
+; Function Attrs: nounwind uwtable
+define void @and(float* nocapture %A, i64 %n, i64 %m) #0 {
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %for.inc, %entry
+  %i.03 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp1 = icmp slt i64 %i.03, %n
+  %cmp2 = icmp slt i64 %i.03, %m
+  %or.cond = and i1 %cmp1, %cmp2
+  br i1 %or.cond, label %if.then, label %for.inc
+
+if.then:                                          ; preds = %for.body
+  %conv = sitofp i64 %i.03 to float
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.03
+  %0 = load float, float* %arrayidx, align 4
+  %add = fadd float %conv, %0
+  store float %add, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body, %if.then
+  %inc = add nuw nsw i64 %i.03, 1
+  %exitcond = icmp eq i64 %inc, 100
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.inc
+  ret void
+}
diff --git a/final/test/ScopInfo/early_exit_for_complex_domains.ll b/final/test/ScopInfo/early_exit_for_complex_domains.ll
new file mode 100644
index 0000000..660b8c4
--- /dev/null
+++ b/final/test/ScopInfo/early_exit_for_complex_domains.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-scops -disable-output < %s
+;
+; Check we do not crash.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.regnode_charclass_class.2.42.654.690.726.870.978.1770.1806.1842.2166.2274.2382.2598.2814.3030.3064 = type { i8, i8, i16, i32, [32 x i8], [4 x i8] }
+
+; Function Attrs: nounwind uwtable
+define void @S_cl_or(%struct.regnode_charclass_class.2.42.654.690.726.870.978.1770.1806.1842.2166.2274.2382.2598.2814.3030.3064* %cl, %struct.regnode_charclass_class.2.42.654.690.726.870.978.1770.1806.1842.2166.2274.2382.2598.2814.3030.3064* %or_with) #0 {
+entry:
+  %flags = getelementptr inbounds %struct.regnode_charclass_class.2.42.654.690.726.870.978.1770.1806.1842.2166.2274.2382.2598.2814.3030.3064, %struct.regnode_charclass_class.2.42.654.690.726.870.978.1770.1806.1842.2166.2274.2382.2598.2814.3030.3064* %or_with, i64 0, i32 0
+  %0 = load i8, i8* %flags, align 4, !tbaa !1
+  %conv = zext i8 %0 to i32
+  %1 = load i8, i8* undef, align 4, !tbaa !1
+  br label %land.lhs.true35
+
+land.lhs.true35:                                  ; preds = %entry
+  %and38 = and i32 %conv, 2
+  %tobool39 = icmp ne i32 %and38, 0
+  %and42 = and i8 %1, 2
+  %tobool43 = icmp eq i8 %and42, 0
+  %or.cond45 = and i1 %tobool39, %tobool43
+  br i1 %or.cond45, label %if.end91, label %for.body49
+
+for.body49:                                       ; preds = %land.lhs.true35
+  %2 = load i8, i8* %flags, align 4, !tbaa !1
+  %and65 = and i8 %2, 8
+  %tobool66 = icmp eq i8 %and65, 0
+  br i1 %tobool66, label %if.end91, label %for.body71
+
+for.body71:                                       ; preds = %for.body71, %for.body49
+  %arrayidx77 = getelementptr inbounds %struct.regnode_charclass_class.2.42.654.690.726.870.978.1770.1806.1842.2166.2274.2382.2598.2814.3030.3064, %struct.regnode_charclass_class.2.42.654.690.726.870.978.1770.1806.1842.2166.2274.2382.2598.2814.3030.3064* %cl, i64 0, i32 5, i64 0
+  store i8 undef, i8* %arrayidx77, align 1, !tbaa !7
+  br i1 false, label %for.body71, label %if.end91
+
+if.end91:                                         ; preds = %for.body71, %for.body49, %land.lhs.true35
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.9.0 (http://llvm.org/git/clang.git af4db76e059c1a3f4a7f437001051ccebc8a50fe)"}
+!1 = !{!2, !3, i64 0}
+!2 = !{!"regnode_charclass_class", !3, i64 0, !3, i64 1, !5, i64 2, !6, i64 4, !3, i64 8, !3, i64 40}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!"short", !3, i64 0}
+!6 = !{!"int", !3, i64 0}
+!7 = !{!3, !3, i64 0}
diff --git a/final/test/ScopInfo/error-blocks-1.ll b/final/test/ScopInfo/error-blocks-1.ll
new file mode 100644
index 0000000..459e333
--- /dev/null
+++ b/final/test/ScopInfo/error-blocks-1.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK:         Context:
+; CHECK-NEXT:    [N] -> {  : -2147483648 <= N <= 2147483647 }
+; CHECK-NEXT:    Assumed Context:
+; CHECK-NEXT:    [N] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [N] -> {  : N >= 514 }
+;
+; CHECK:         Statements {
+; CHECK-NEXT:    	Stmt_if_end
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [N] -> { Stmt_if_end[i0] : 0 <= i0 < N };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [N] -> { Stmt_if_end[i0] -> [i0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:                [N] -> { Stmt_if_end[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:                [N] -> { Stmt_if_end[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:    }
+;
+;    void f();
+;    void g(int *A, int N) {
+;      for (int i = 0; i < N; i++) {
+;        if (i > 512) {
+;          f();
+;          A[i]++;
+;        }
+;        A[i]++;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @g(i32* %A, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %cmp1 = icmp sgt i64 %indvars.iv, 512
+  br i1 %cmp1, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  call void (...) @f() #2
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp12 = load i32, i32* %arrayidx2, align 4
+  %inc2 = add nsw i32 %tmp12, 1
+  store i32 %inc2, i32* %arrayidx2, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp1, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare void @f(...)
diff --git a/final/test/ScopInfo/error-blocks-2.ll b/final/test/ScopInfo/error-blocks-2.ll
new file mode 100644
index 0000000..6ef4514
--- /dev/null
+++ b/final/test/ScopInfo/error-blocks-2.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+; CHECK:         Invariant Accesses: {
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [N, valid_val] -> { Stmt_for_body[i0] -> MemRef_valid[0] };
+; CHECK-NEXT:            Execution Context: [N, valid_val] -> {  : N > 0 }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [N, valid_val] -> { Stmt_S[i0] -> MemRef_ptr_addr[0] };
+; CHECK-NEXT:            Execution Context: [N, valid_val] -> { : }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [N, valid_val] -> { Stmt_S[i0] -> MemRef_tmp2[0] };
+; CHECK-NEXT:            Execution Context: [N, valid_val] -> { : N > 0 and (valid_val < 0 or valid_val > 0) }
+; CHECK-NEXT:    }
+; CHECK-NEXT:    Context:
+; CHECK-NEXT:    [N, valid_val] -> {  : -2147483648 <= N <= 2147483647 and -2147483648 <= valid_val <= 2147483647 }
+; CHECK-NEXT:    Assumed Context:
+; CHECK-NEXT:    [N, valid_val] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [N, valid_val] -> {  : valid_val = 0 and N > 0 }
+;
+; CHECK:         Statements {
+; CHECK-NEXT:       Stmt_S
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [N, valid_val] -> { Stmt_S[i0] : 0 <= i0 < N };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [N, valid_val] -> { Stmt_S[i0] -> [i0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [N, valid_val] -> { Stmt_S[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32 %N, i32* noalias %valid, i32* noalias %ptr, i32* noalias %A) {
+entry:
+  %ptr.addr = alloca i32*, align 8
+  store i32* %ptr, i32** %ptr.addr, align 8
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %valid_val = load i32, i32* %valid, align 4
+  %cmp1 = icmp eq i32 %valid_val, 0
+  br i1 %cmp1, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  call void @doSth(i32** nonnull %ptr.addr)
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  br label %S
+
+S:                                                ; preds = %if.end
+  %tmp2 = load i32*, i32** %ptr.addr, align 8
+  %tmp3 = load i32, i32* %tmp2, align 4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp3, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %S
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare void @doSth(i32**)
diff --git a/final/test/ScopInfo/error-blocks-3.ll b/final/test/ScopInfo/error-blocks-3.ll
new file mode 100644
index 0000000..15ff514
--- /dev/null
+++ b/final/test/ScopInfo/error-blocks-3.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -analyze -polly-scops  -polly-detect-keep-going -polly-allow-nonaffine < %s | FileCheck %s
+;
+; TODO: FIXME: Investigate why "-polly-detect-keep-going" is needed to detect
+;              this SCoP. That flag should not make a difference.
+;
+; CHECK:         Context:
+; CHECK-NEXT:    [N] -> {  : -2147483648 <= N <= 2147483647 }
+; CHECK-NEXT:    Assumed Context:
+; CHECK-NEXT:    [N] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [N] -> {  : N >= 514 }
+;
+; CHECK:         Statements {
+; CHECK-NEXT:    	Stmt_if_end3
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [N] -> { Stmt_if_end3[i0] : 0 <= i0 < N };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [N] -> { Stmt_if_end3[i0] -> [i0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:                [N] -> { Stmt_if_end3[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:                [N] -> { Stmt_if_end3[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:    }
+;
+;    int f();
+;    void g(int *A, int N) {
+;      for (int i = 0; i < N; i++) {
+;        if (i > 512) {
+;          int v = f();
+;        S:
+;          A[v]++;
+;        }
+;        A[i]++;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @g(i32* %A, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %cmp1 = icmp sgt i64 %indvars.iv, 512
+  br i1 %cmp1, label %if.then, label %if.end3
+
+if.then:                                          ; preds = %for.body
+  %call = call i32 (...) @f()
+  br label %S
+
+S:                                                ; preds = %if.then
+  %idxprom = sext i32 %call to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp1, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %if.end3
+
+if.end3:                                          ; preds = %if.end, %for.body
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx5, align 4
+  %inc6 = add nsw i32 %tmp2, 1
+  store i32 %inc6, i32* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end3, %if.then2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare i32 @f(...)
diff --git a/final/test/ScopInfo/escaping_empty_scop.ll b/final/test/ScopInfo/escaping_empty_scop.ll
new file mode 100644
index 0000000..048bf97
--- /dev/null
+++ b/final/test/ScopInfo/escaping_empty_scop.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void g();
+;    int f(int *A) {
+;      int a0 = 0, a1 = 0, a2 = 0;
+;      for (int i = 0; i < 1000; i++) {
+;        a0 = 2 * i;
+;        // split
+;        A[0] = i;
+;        a1 = 2 * i;
+;        // split
+;        a2 = 2 * i;
+;      }
+;      g();
+;      return a1 + a2;
+;    }
+;
+; CHECK:      Stmt_bb1
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                { Stmt_bb1[i0] -> MemRef_a_0[] };
+; CHECK:      Stmt_bb2
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                { Stmt_bb2[i0] -> MemRef_a_1[] };
+; CHECK:      Stmt_bb3
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                { Stmt_bb3[i0] -> MemRef_a_2[] };
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @f(i32* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb3, %bb
+  %i.0 = phi i32 [ 0, %bb ], [ %tmp4, %bb3 ]
+  %a.0 = mul i32 %i.0, 2
+  br label %bb2
+
+bb2:                                              ; preds = %bb1
+  %a.1 = mul i32 %i.0, 2
+  store i32 %i.0, i32 *%A, align 4
+  br label %bb3
+
+bb3:                                              ; preds = %bb2
+  %tmp = shl nsw i32 %i.0, 1
+  %tmp4 = add nuw nsw i32 %i.0, 1
+  %a.2 = mul i32 %i.0, 2
+  %exitcond = icmp ne i32 %i.0, 1000
+  br i1 %exitcond, label %bb1, label %bb5
+
+bb5:                                              ; preds = %bb1
+  call void (...) @g() #2
+  %add = add i32 %a.0, %a.1
+  %add2 = add i32 %add, %a.2
+  ret i32 %add2
+}
+
+declare void @g(...) #1
diff --git a/final/test/ScopInfo/exit-phi-1.ll b/final/test/ScopInfo/exit-phi-1.ll
new file mode 100644
index 0000000..920bc68
--- /dev/null
+++ b/final/test/ScopInfo/exit-phi-1.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s --check-prefix=CODEGEN
+;
+; Check for correct code generation of exit PHIs, even if the same PHI value
+; is used again inside the the SCoP.
+; Note that if.else113 is removed from the SCoP because it is never executed.
+;
+; CHECK: Region: %for.body
+;
+; CHECK:         Arrays {
+; CHECK-NEXT:        double MemRef_up_3_ph; // Element size 8
+; CHECK-NEXT:        i32* MemRef_A[*]; // Element size 8
+; CHECK-NEXT:        double MemRef_up_3_ph; // Element size 8
+; CHECK-NEXT:    }
+;
+; CODEGEN:      polly.merge_new_and_old:
+; CODEGEN-NEXT:   %up.3.ph.ph.merge = phi double [ %up.3.ph.ph.final_reload, %polly.exiting ], [ undef, %for.cond.outer304.region_exiting ]
+;
+; CODEGEN:      for.cond.outer304:
+; CODEGEN-NEXT:   %indvar = phi i64 [ %indvar.next, %polly.merge_new_and_old ], [ 0, %entry ]
+; CODEGEN-NEXT:   %up.3.ph = phi double [ 0.000000e+00, %entry ], [ %up.3.ph.ph.merge, %polly.merge_new_and_old ]
+;
+; CODEGEN:      polly.stmt.if.then111:
+; CODEGEN-NEXT:   store double undef, double* %up.3.ph.s2a
+;
+; CODEGEN:      polly.exiting:
+; CODEGEN-NEXT:   %up.3.ph.ph.final_reload = load double, double* %up.3.ph.s2a
+;
+; ModuleID = 'bugpoint-reduced-simplified.bc'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: uwtable
+define void @_ZN6soplex14SPxAggregateSM9eliminateERKNS_7SVectorEd(i32** nocapture readonly %A) {
+entry:
+  br label %for.cond.outer304
+
+for.cond.outer304:                                ; preds = %if.else113, %if.then111, %entry
+  %up.3.ph = phi double [ 0.000000e+00, %entry ], [ undef, %if.else113 ], [ undef, %if.then111 ]
+  br i1 undef, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond.outer304
+  %0 = load i32*, i32** %A, align 8
+  %add = fadd double %up.3.ph, undef
+  %val.i.i.i235 = getelementptr inbounds i32, i32* %0, i64 0
+  br i1 false, label %if.else113, label %if.then111
+
+if.then111:                                       ; preds = %for.body
+  br label %for.cond.outer304
+
+if.else113:                                       ; preds = %for.body
+  br label %for.cond.outer304
+
+for.end:                                          ; preds = %for.cond.outer304
+  ret void
+}
diff --git a/final/test/ScopInfo/exit-phi-2.ll b/final/test/ScopInfo/exit-phi-2.ll
new file mode 100644
index 0000000..4007ddc
--- /dev/null
+++ b/final/test/ScopInfo/exit-phi-2.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that there is no MK_ExitPHI READ access.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @local_book_besterror() {
+entry:
+  %0 = load i64, i64* undef, align 8
+  %conv = trunc i64 %0 to i32
+  br label %for.body64
+
+for.body64:
+  %bestf.011 = phi float [ 0.000000e+00, %entry ], [ %this.0.bestf.0, %if.end92 ]
+  br label %for.body74
+
+for.body74:
+  br i1 false, label %for.body74, label %for.cond71.for.end85_crit_edge
+
+for.cond71.for.end85_crit_edge:
+  %cmp88 = fcmp olt float undef, %bestf.011
+  %this.0.bestf.0 = select i1 undef, float undef, float %bestf.011
+  br label %if.end92
+
+if.end92:
+  br i1 undef, label %for.body64, label %for.cond60.if.end96.loopexit_crit_edge
+
+for.cond60.if.end96.loopexit_crit_edge:           ; preds = %if.end92
+  ret void
+}
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_cond71_for_end85_crit_edge
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_for_cond71_for_end85_crit_edge[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_for_cond71_for_end85_crit_edge[] -> [] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_for_cond71_for_end85_crit_edge[] -> MemRef_bestf_011[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_for_cond71_for_end85_crit_edge[] -> MemRef_this_0_bestf_0[] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/exit_phi_accesses-2.ll b/final/test/ScopInfo/exit_phi_accesses-2.ll
new file mode 100644
index 0000000..483cd70
--- /dev/null
+++ b/final/test/ScopInfo/exit_phi_accesses-2.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -analyze -polly-scops %s | FileCheck %s
+
+; CHECK-LABEL: Function: foo
+;
+; CHECK:       Statements {
+; CHECK-NEXT:      Stmt_body
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              { Stmt_body[i0] : 0 <= i0 <= 100 };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              { Stmt_body[i0] -> [i0] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_body[i0] -> MemRef_sum__phi[] };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_body[i0] -> MemRef_sum__phi[] };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              { Stmt_body[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_body[i0] -> MemRef_sum_next[] };
+; CHECK-NEXT:  }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define float @foo(float* %A) {
+entry:
+  br label %header
+
+header:
+  fence seq_cst
+  br i1 true, label %body, label %exit
+
+body:
+  %i = phi i64 [ 0, %header ], [ %next, %body ]
+  %sum = phi float [ 0.0, %header ], [ %sum.next, %body ]
+  %arrayidx = getelementptr float, float* %A, i64 %i
+  %scalar = fadd float 0.0, 0.0
+  %next = add nuw nsw i64 %i, 1
+  %val = load float, float* %arrayidx
+  %sum.next = fadd float %sum, %val
+  %cond = icmp ne i64 %i, 100
+  br i1 %cond, label %body, label %after
+
+after:
+  br label %exit
+
+exit:
+  %phi = phi float [%sum.next, %after], [0.0, %header]
+  ret float %phi
+}
diff --git a/final/test/ScopInfo/exit_phi_accesses.ll b/final/test/ScopInfo/exit_phi_accesses.ll
new file mode 100644
index 0000000..f045ed9
--- /dev/null
+++ b/final/test/ScopInfo/exit_phi_accesses.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -analyze -polly-scops %s | FileCheck %s
+
+; Check that PHI nodes only create PHI access and nothing else (e.g. unnecessary
+; SCALAR accesses). In this case, for a PHI in the exit node, hence there is no
+; PHI ReadAccess.
+
+; CHECK-LABEL: Function: foo
+;
+; CHECK:       Statements {
+; CHECK-NEXT:      Stmt_header
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              { Stmt_header[] };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              { Stmt_header[] -> [0, 0] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_header[] -> MemRef_phi[] };
+; CHECK-NEXT:      Stmt_body
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              { Stmt_body[i0] : 0 <= i0 <= 100 };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              { Stmt_body[i0] -> [1, i0] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_body[i0] -> MemRef_phi[] };
+; CHECK-NEXT:  }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define float @foo(float %sum, float* %A) {
+entry:
+  br label %header
+
+header:
+  br i1 true, label %body, label %exit
+
+body:
+  %i = phi i64 [ 0, %header ], [ %next, %body ]
+  %scalar = fadd float 0.0, 0.0
+  %next = add nuw nsw i64 %i, 1
+  %cond = icmp ne i64 %i, 100
+  br i1 %cond, label %body, label %exit
+
+exit:
+  %phi = phi float [%scalar, %body], [0.0, %header]
+  ret float %phi
+}
diff --git a/final/test/ScopInfo/expensive-boundary-context.ll b/final/test/ScopInfo/expensive-boundary-context.ll
new file mode 100644
index 0000000..d090e9d
--- /dev/null
+++ b/final/test/ScopInfo/expensive-boundary-context.ll
@@ -0,0 +1,300 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN:                < %s | FileCheck %s
+
+; CHECK-NOT:   Assumed Context:
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.hoge = type { i32, %struct.widget*, %struct.ham*, %struct.ham*, i32, %struct.wombat*, double*, i32, i32, i32**, i32, i32*, [6 x i32], i32, %struct.foo*, i32 }
+%struct.widget = type { i32, i32, %struct.wombat*, i32*, %struct.quux*, i32, %struct.barney*, i32, i32, [3 x i32], i32 }
+%struct.quux = type { %struct.wombat*, i32*, i32*, i32, i32, i32, [3 x [3 x [3 x %struct.hoge.0*]]]* }
+%struct.hoge.0 = type { i32, %struct.hoge.0* }
+%struct.barney = type { [3 x i32], [3 x i32] }
+%struct.ham = type { [3 x i32]*, i32, i32, i32, i32 }
+%struct.wombat = type { %struct.barney*, i32, i32 }
+%struct.foo = type { i32, i32, i32, i32, i32*, i32*, %struct.wibble**, %struct.wibble**, i32*, i32*, %struct.wibble*, %struct.wibble* }
+%struct.wibble = type { %struct.foo.1**, i32 }
+%struct.foo.1 = type { [3 x i32], [3 x i32], i32, i32, [4 x i32], [4 x i32] }
+
+; Function Attrs: nounwind uwtable
+define void @hoge() #0 {
+bb:
+  %tmp52 = alloca %struct.hoge*, align 8
+  %tmp53 = alloca %struct.barney*, align 8
+  %tmp54 = alloca %struct.barney*, align 8
+  %tmp55 = alloca %struct.barney*, align 8
+  br label %bb56
+
+bb56:                                             ; preds = %bb
+  switch i32 undef, label %bb59 [
+    i32 0, label %bb57
+    i32 1, label %bb58
+  ]
+
+bb57:                                             ; preds = %bb56
+  unreachable
+
+bb58:                                             ; preds = %bb56
+  unreachable
+
+bb59:                                             ; preds = %bb56
+  %tmp = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp60 = getelementptr inbounds %struct.barney, %struct.barney* %tmp, i32 0, i32 1
+  %tmp61 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp60, i64 0, i64 0
+  %tmp62 = load i32, i32* %tmp61, align 4, !tbaa !5
+  %tmp63 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp64 = getelementptr inbounds %struct.barney, %struct.barney* %tmp63, i32 0, i32 0
+  %tmp65 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp64, i64 0, i64 0
+  %tmp66 = sub nsw i32 %tmp62, 0
+  %tmp67 = add nsw i32 %tmp66, 1
+  %tmp68 = icmp slt i32 0, %tmp67
+  br i1 %tmp68, label %bb69, label %bb70
+
+bb69:                                             ; preds = %bb59
+  br label %bb70
+
+bb70:                                             ; preds = %bb69, %bb59
+  %tmp71 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp72 = getelementptr inbounds %struct.barney, %struct.barney* %tmp71, i32 0, i32 1
+  %tmp73 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp72, i64 0, i64 1
+  %tmp74 = load i32, i32* %tmp73, align 4, !tbaa !5
+  %tmp75 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp76 = getelementptr inbounds %struct.barney, %struct.barney* %tmp75, i32 0, i32 0
+  %tmp77 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp76, i64 0, i64 1
+  %tmp78 = sub nsw i32 %tmp74, 0
+  %tmp79 = add nsw i32 %tmp78, 1
+  %tmp80 = icmp slt i32 0, %tmp79
+  br i1 %tmp80, label %bb81, label %bb82
+
+bb81:                                             ; preds = %bb70
+  br label %bb82
+
+bb82:                                             ; preds = %bb81, %bb70
+  %tmp83 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp84 = getelementptr inbounds %struct.barney, %struct.barney* %tmp83, i32 0, i32 1
+  %tmp85 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp84, i64 0, i64 0
+  %tmp86 = load i32, i32* %tmp85, align 4, !tbaa !5
+  %tmp87 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp88 = getelementptr inbounds %struct.barney, %struct.barney* %tmp87, i32 0, i32 0
+  %tmp89 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp88, i64 0, i64 0
+  %tmp90 = sub nsw i32 %tmp86, 0
+  %tmp91 = add nsw i32 %tmp90, 1
+  %tmp92 = icmp slt i32 0, %tmp91
+  br i1 %tmp92, label %bb93, label %bb94
+
+bb93:                                             ; preds = %bb82
+  br label %bb94
+
+bb94:                                             ; preds = %bb93, %bb82
+  %tmp95 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp96 = getelementptr inbounds %struct.barney, %struct.barney* %tmp95, i32 0, i32 1
+  %tmp97 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp96, i64 0, i64 0
+  %tmp98 = load i32, i32* %tmp97, align 4, !tbaa !5
+  %tmp99 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp100 = getelementptr inbounds %struct.barney, %struct.barney* %tmp99, i32 0, i32 0
+  %tmp101 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp100, i64 0, i64 0
+  %tmp102 = sub nsw i32 %tmp98, 0
+  %tmp103 = add nsw i32 %tmp102, 1
+  %tmp104 = icmp slt i32 0, %tmp103
+  br i1 %tmp104, label %bb105, label %bb106
+
+bb105:                                            ; preds = %bb94
+  br label %bb106
+
+bb106:                                            ; preds = %bb105, %bb94
+  %tmp107 = load %struct.barney*, %struct.barney** %tmp53, align 8, !tbaa !1
+  %tmp108 = getelementptr inbounds %struct.barney, %struct.barney* %tmp107, i32 0, i32 1
+  %tmp109 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp108, i64 0, i64 1
+  %tmp110 = load i32, i32* %tmp109, align 4, !tbaa !5
+  %tmp111 = load %struct.barney*, %struct.barney** %tmp53, align 8, !tbaa !1
+  %tmp112 = getelementptr inbounds %struct.barney, %struct.barney* %tmp111, i32 0, i32 0
+  %tmp113 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp112, i64 0, i64 1
+  %tmp114 = sub nsw i32 %tmp110, 0
+  %tmp115 = add nsw i32 %tmp114, 1
+  %tmp116 = icmp slt i32 0, %tmp115
+  br i1 %tmp116, label %bb117, label %bb118
+
+bb117:                                            ; preds = %bb106
+  br label %bb118
+
+bb118:                                            ; preds = %bb117, %bb106
+  %tmp119 = load %struct.barney*, %struct.barney** %tmp53, align 8, !tbaa !1
+  %tmp120 = getelementptr inbounds %struct.barney, %struct.barney* %tmp119, i32 0, i32 1
+  %tmp121 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp120, i64 0, i64 0
+  %tmp122 = load i32, i32* %tmp121, align 4, !tbaa !5
+  %tmp123 = load %struct.barney*, %struct.barney** %tmp53, align 8, !tbaa !1
+  %tmp124 = getelementptr inbounds %struct.barney, %struct.barney* %tmp123, i32 0, i32 0
+  %tmp125 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp124, i64 0, i64 0
+  %tmp126 = sub nsw i32 %tmp122, 0
+  %tmp127 = add nsw i32 %tmp126, 1
+  %tmp128 = icmp slt i32 0, %tmp127
+  br i1 %tmp128, label %bb129, label %bb130
+
+bb129:                                            ; preds = %bb118
+  br label %bb130
+
+bb130:                                            ; preds = %bb129, %bb118
+  %tmp131 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp132 = getelementptr inbounds %struct.barney, %struct.barney* %tmp131, i32 0, i32 1
+  %tmp133 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp132, i64 0, i64 0
+  %tmp134 = load i32, i32* %tmp133, align 4, !tbaa !5
+  %tmp135 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp136 = getelementptr inbounds %struct.barney, %struct.barney* %tmp135, i32 0, i32 0
+  %tmp137 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp136, i64 0, i64 0
+  %tmp138 = sub nsw i32 %tmp134, 0
+  %tmp139 = add nsw i32 %tmp138, 1
+  %tmp140 = icmp slt i32 0, %tmp139
+  br i1 %tmp140, label %bb141, label %bb142
+
+bb141:                                            ; preds = %bb130
+  br label %bb142
+
+bb142:                                            ; preds = %bb141, %bb130
+  %tmp143 = load %struct.barney*, %struct.barney** %tmp55, align 8, !tbaa !1
+  %tmp144 = getelementptr inbounds %struct.barney, %struct.barney* %tmp143, i32 0, i32 1
+  %tmp145 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp144, i64 0, i64 0
+  %tmp146 = load i32, i32* %tmp145, align 4, !tbaa !5
+  %tmp147 = load %struct.barney*, %struct.barney** %tmp55, align 8, !tbaa !1
+  %tmp148 = getelementptr inbounds %struct.barney, %struct.barney* %tmp147, i32 0, i32 0
+  %tmp149 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp148, i64 0, i64 0
+  %tmp150 = sub nsw i32 %tmp146, 0
+  %tmp151 = add nsw i32 %tmp150, 1
+  %tmp152 = icmp slt i32 0, %tmp151
+  br i1 %tmp152, label %bb153, label %bb154
+
+bb153:                                            ; preds = %bb142
+  br label %bb154
+
+bb154:                                            ; preds = %bb153, %bb142
+  %tmp155 = load %struct.barney*, %struct.barney** %tmp53, align 8, !tbaa !1
+  %tmp156 = getelementptr inbounds %struct.barney, %struct.barney* %tmp155, i32 0, i32 1
+  %tmp157 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp156, i64 0, i64 0
+  %tmp158 = load i32, i32* %tmp157, align 4, !tbaa !5
+  %tmp159 = load %struct.barney*, %struct.barney** %tmp53, align 8, !tbaa !1
+  %tmp160 = getelementptr inbounds %struct.barney, %struct.barney* %tmp159, i32 0, i32 0
+  %tmp161 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp160, i64 0, i64 0
+  %tmp162 = load i32, i32* %tmp161, align 4, !tbaa !5
+  %tmp163 = sub nsw i32 %tmp158, %tmp162
+  %tmp164 = add nsw i32 %tmp163, 1
+  %tmp165 = icmp slt i32 0, %tmp164
+  br i1 %tmp165, label %bb166, label %bb167
+
+bb166:                                            ; preds = %bb154
+  br label %bb167
+
+bb167:                                            ; preds = %bb166, %bb154
+  %tmp168 = load %struct.barney*, %struct.barney** %tmp53, align 8, !tbaa !1
+  %tmp169 = getelementptr inbounds %struct.barney, %struct.barney* %tmp168, i32 0, i32 1
+  %tmp170 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp169, i64 0, i64 0
+  %tmp171 = load i32, i32* %tmp170, align 4, !tbaa !5
+  %tmp172 = load %struct.barney*, %struct.barney** %tmp53, align 8, !tbaa !1
+  %tmp173 = getelementptr inbounds %struct.barney, %struct.barney* %tmp172, i32 0, i32 0
+  %tmp174 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp173, i64 0, i64 0
+  %tmp175 = load i32, i32* %tmp174, align 4, !tbaa !5
+  %tmp176 = sub nsw i32 %tmp171, %tmp175
+  %tmp177 = add nsw i32 %tmp176, 1
+  %tmp178 = icmp slt i32 0, %tmp177
+  br i1 %tmp178, label %bb179, label %bb180
+
+bb179:                                            ; preds = %bb167
+  br label %bb180
+
+bb180:                                            ; preds = %bb179, %bb167
+  %tmp181 = load %struct.barney*, %struct.barney** %tmp53, align 8, !tbaa !1
+  %tmp182 = getelementptr inbounds %struct.barney, %struct.barney* %tmp181, i32 0, i32 1
+  %tmp183 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp182, i64 0, i64 1
+  %tmp184 = load i32, i32* %tmp183, align 4, !tbaa !5
+  %tmp185 = load %struct.barney*, %struct.barney** %tmp53, align 8, !tbaa !1
+  %tmp186 = getelementptr inbounds %struct.barney, %struct.barney* %tmp185, i32 0, i32 0
+  %tmp187 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp186, i64 0, i64 1
+  %tmp188 = load i32, i32* %tmp187, align 4, !tbaa !5
+  %tmp189 = sub nsw i32 %tmp184, %tmp188
+  %tmp190 = add nsw i32 %tmp189, 1
+  %tmp191 = icmp slt i32 0, %tmp190
+  br i1 %tmp191, label %bb192, label %bb193
+
+bb192:                                            ; preds = %bb180
+  br label %bb193
+
+bb193:                                            ; preds = %bb192, %bb180
+  %tmp194 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp195 = getelementptr inbounds %struct.barney, %struct.barney* %tmp194, i32 0, i32 1
+  %tmp196 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp195, i64 0, i64 0
+  %tmp197 = load i32, i32* %tmp196, align 4, !tbaa !5
+  %tmp198 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp199 = getelementptr inbounds %struct.barney, %struct.barney* %tmp198, i32 0, i32 0
+  %tmp200 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp199, i64 0, i64 0
+  %tmp201 = load i32, i32* %tmp200, align 4, !tbaa !5
+  %tmp202 = sub nsw i32 %tmp197, %tmp201
+  %tmp203 = add nsw i32 %tmp202, 1
+  %tmp204 = icmp slt i32 0, %tmp203
+  br i1 %tmp204, label %bb205, label %bb206
+
+bb205:                                            ; preds = %bb193
+  br label %bb206
+
+bb206:                                            ; preds = %bb205, %bb193
+  %tmp207 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp208 = getelementptr inbounds %struct.barney, %struct.barney* %tmp207, i32 0, i32 1
+  %tmp209 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp208, i64 0, i64 0
+  %tmp210 = load i32, i32* %tmp209, align 4, !tbaa !5
+  %tmp211 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp212 = getelementptr inbounds %struct.barney, %struct.barney* %tmp211, i32 0, i32 0
+  %tmp213 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp212, i64 0, i64 0
+  %tmp214 = load i32, i32* %tmp213, align 4, !tbaa !5
+  %tmp215 = sub nsw i32 %tmp210, %tmp214
+  %tmp216 = add nsw i32 %tmp215, 1
+  %tmp217 = icmp slt i32 0, %tmp216
+  br i1 %tmp217, label %bb218, label %bb219
+
+bb218:                                            ; preds = %bb206
+  br label %bb219
+
+bb219:                                            ; preds = %bb218, %bb206
+  %tmp220 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp221 = getelementptr inbounds %struct.barney, %struct.barney* %tmp220, i32 0, i32 1
+  %tmp222 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp221, i64 0, i64 1
+  %tmp223 = load i32, i32* %tmp222, align 4, !tbaa !5
+  %tmp224 = load %struct.barney*, %struct.barney** %tmp54, align 8, !tbaa !1
+  %tmp225 = getelementptr inbounds %struct.barney, %struct.barney* %tmp224, i32 0, i32 0
+  %tmp226 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp225, i64 0, i64 1
+  %tmp227 = load i32, i32* %tmp226, align 4, !tbaa !5
+  %tmp228 = sub nsw i32 %tmp223, %tmp227
+  %tmp229 = add nsw i32 %tmp228, 1
+  %tmp230 = icmp slt i32 0, %tmp229
+  br i1 %tmp230, label %bb231, label %bb232
+
+bb231:                                            ; preds = %bb219
+  br label %bb232
+
+bb232:                                            ; preds = %bb231, %bb219
+  %tmp233 = load %struct.barney*, %struct.barney** %tmp55, align 8, !tbaa !1
+  %tmp234 = getelementptr inbounds %struct.barney, %struct.barney* %tmp233, i32 0, i32 1
+  %tmp235 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp234, i64 0, i64 0
+  %tmp236 = load i32, i32* %tmp235, align 4, !tbaa !5
+  %tmp237 = load %struct.barney*, %struct.barney** %tmp55, align 8, !tbaa !1
+  %tmp238 = getelementptr inbounds %struct.barney, %struct.barney* %tmp237, i32 0, i32 0
+  %tmp239 = getelementptr inbounds [3 x i32], [3 x i32]* %tmp238, i64 0, i64 0
+  %tmp240 = load i32, i32* %tmp239, align 4, !tbaa !5
+  %tmp241 = sub nsw i32 %tmp236, %tmp240
+  %tmp242 = add nsw i32 %tmp241, 1
+  %tmp243 = icmp slt i32 0, %tmp242
+  br i1 %tmp243, label %bb244, label %bb245
+
+bb244:                                            ; preds = %bb232
+  br label %bb245
+
+bb245:                                            ; preds = %bb244, %bb232
+  unreachable
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0}
+
+!0 = !{!"clang version 3.8.0 (trunk 252261) (llvm/trunk 252271)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"any pointer", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!6, !6, i64 0}
+!6 = !{!"int", !3, i64 0}
diff --git a/final/test/ScopInfo/extract_constant_factor_introduces_new_parameter.ll b/final/test/ScopInfo/extract_constant_factor_introduces_new_parameter.ll
new file mode 100644
index 0000000..e95f185
--- /dev/null
+++ b/final/test/ScopInfo/extract_constant_factor_introduces_new_parameter.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -analyze < %s
+
+; CHECK: Valid Region for Scop: bb10 => bb16
+
+; Verify that -polly-scops does not crash. At some point this piece of
+; code crashed as we extracted from the SCEV expression:
+;
+;    ((8 * ((%a * %b) + %c)) + (-8 * %a))'
+;
+; the constant 8, which resulted in the new expression:
+;
+;    (((-1 + %b) * %a) + %c)
+;
+; which introduced a new parameter (-1 + %b) * %a which was not registered
+; correctly and consequently caused a crash due to an expression not being
+; regiustered as a parameter.
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+
+define void @barney(i32* %arg, i32* %arg1, double* %arg2, i32* %arg3, i32 %a, i32 %b, i32 %c) {
+bb:
+  br label %bb10
+
+bb10:                                             ; preds = %bb
+  br i1 true, label %bb11, label %bb16
+
+bb11:                                             ; preds = %bb10
+  %tmp4 = add nsw i32 1, %a
+  %tmp5 = sub i32 0, %tmp4
+  %tmp8 = add nsw i32 %c, 1
+  %tmp12 = mul nsw i32 %b, %a
+  %tmp13 = add nsw i32 %tmp8, %tmp12
+  %tmp6 = getelementptr inbounds double, double* %arg2, i32 %tmp5
+  %tmp14 = getelementptr inbounds double, double* %tmp6, i32 %tmp13
+  %tmp15 = load double, double* %tmp14
+  br label %bb16
+
+bb16:                                             ; preds = %bb11, %bb10
+  ret void
+}
diff --git a/final/test/ScopInfo/fortran_array_global_malloc_nonvectored.ll b/final/test/ScopInfo/fortran_array_global_malloc_nonvectored.ll
new file mode 100644
index 0000000..eceef8b
--- /dev/null
+++ b/final/test/ScopInfo/fortran_array_global_malloc_nonvectored.ll
@@ -0,0 +1,116 @@
+; RUN: opt %loadPolly -analyze -S -polly-detect-fortran-arrays \
+; RUN: -polly-process-unprofitable -polly-scops  < %s | FileCheck %s
+
+; MODULE src_soil
+; USE data_parameters, ONLY :   &
+;     wp,        & ! KIND-type parameter for real variables
+;     iintegers    ! KIND-type parameter for standard integer variables
+; IMPLICIT NONE
+; REAL (KIND = wp),     ALLOCATABLE, PRIVATE  :: &
+;   xdzs     (:)
+; CONTAINS
+; SUBROUTINE terra1(n)
+;   INTEGER, intent(in) :: n
+;   INTEGER (KIND=iintegers) ::  &
+;     j
+;   Allocate(xdzs(n));
+;    DO j = 2, n
+;         xdzs(j) = xdzs(j) * xdzs(j) + xdzs(j - 1)
+;   END DO
+; END SUBROUTINE terra1
+; END MODULE src_soil
+
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
+
+%"struct.array1_real(kind=8)" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
+%struct.descriptor_dimension = type { i64, i64, i64 }
+
+@__src_soil_MOD_xdzs = unnamed_addr global %"struct.array1_real(kind=8)" zeroinitializer, align 32
+@.cst = private unnamed_addr constant [67 x i8] c"Integer overflow when calculating the amount of memory to allocate\00", align 64
+@.cst1 = private unnamed_addr constant [37 x i8] c"Allocation would exceed memory limit\00", align 64
+@.cst2 = private unnamed_addr constant [93 x i8] c"At line 23 of file /home/siddhart/cosmo-self-installation/cosmo-pompa/cosmo/src/src_soil.f90\00", align 64
+@.cst3 = private unnamed_addr constant [55 x i8] c"Attempting to allocate already allocated variable '%s'\00", align 64
+@.cst4 = private unnamed_addr constant [5 x i8] c"xdzs\00", align 8
+
+; Function Attrs: nounwind uwtable
+define void @__src_soil_MOD_terra1(i32* noalias nocapture %n) unnamed_addr #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  store i64 537, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 2), align 16, !tbaa !0
+  store i64 1, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 3, i64 0, i32 1), align 8, !tbaa !0
+  %tmp = load i32, i32* %n, align 4, !tbaa !3
+  %tmp1 = sext i32 %tmp to i64
+  store i64 %tmp1, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 3, i64 0, i32 2), align 8, !tbaa !0
+  store i64 1, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 3, i64 0, i32 0), align 8, !tbaa !0
+  %tmp2 = icmp slt i32 %tmp, 1
+  %tmp3 = zext i32 %tmp to i64
+  %tmp4 = shl nuw nsw i64 %tmp3, 3
+  %.24 = select i1 %tmp2, i64 0, i64 %tmp4
+  %tmp5 = icmp ne i64 %.24, 0
+  %tmp6 = select i1 %tmp5, i64 %.24, i64 1
+  %tmp7 = tail call noalias i8* @malloc(i64 %tmp6) #2
+  store i8* %tmp7, i8** getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 0), align 32, !tbaa !5
+  store i64 -1, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 1), align 8, !tbaa !0
+  %tmp8 = icmp sgt i32 %tmp, 1
+  br i1 %tmp8, label %"21.preheader", label %return
+
+"21.preheader":                                   ; preds = %entry.split
+  %tmp9 = bitcast i8* %tmp7 to double*
+  %tmp10 = add i32 %tmp, 1
+  br label %"21"
+
+"21":                                             ; preds = %"21", %"21.preheader"
+  %tmp11 = phi double [ undef, %"21.preheader" ], [ %tmp16, %"21" ]
+  %indvars.iv = phi i64 [ 2, %"21.preheader" ], [ %indvars.iv.next, %"21" ]
+  %tmp12 = add nsw i64 %indvars.iv, -1
+  %tmp13 = getelementptr inbounds double, double* %tmp9, i64 %tmp12
+  %tmp14 = load double, double* %tmp13, align 8, !tbaa !7
+  %tmp15 = fmul double %tmp14, %tmp14
+  %tmp16 = fadd double %tmp11, %tmp15
+  store double %tmp16, double* %tmp13, align 8, !tbaa !7
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %lftr.wideiv1 = trunc i64 %indvars.iv.next to i32
+  %exitcond2 = icmp eq i32 %lftr.wideiv1, %tmp10
+  br i1 %exitcond2, label %return.loopexit, label %"21"
+
+return.loopexit:                                  ; preds = %"21"
+  br label %return
+
+return:                                           ; preds = %return.loopexit, %entry.split
+  ret void
+}
+
+; Function Attrs: noreturn
+declare void @_gfortran_runtime_error(i8*, ...) #1
+
+; Function Attrs: nounwind
+declare noalias i8* @malloc(i64) #2
+
+; Function Attrs: noreturn
+declare void @_gfortran_os_error(i8*) #1
+
+; Function Attrs: noreturn
+declare void @_gfortran_runtime_error_at(i8*, i8*, ...) #1
+
+attributes #0 = { nounwind uwtable }
+attributes #1 = { noreturn }
+attributes #2 = { nounwind }
+
+!0 = !{!1, !1, i64 0}
+!1 = !{!"alias set 4: integer(kind=8)", !2}
+!2 = distinct !{!2}
+!3 = !{!4, !4, i64 0}
+!4 = !{!"alias set 11: integer(kind=4)", !2}
+!5 = !{!6, !6, i64 0}
+!6 = !{!"alias set 3: void*", !2}
+!7 = !{!8, !8, i64 0}
+!8 = !{!"alias set 18: real(kind=8)", !2}
+
+; CHECK: ReadAccess :=	[Reduction Type: NONE] [Fortran array descriptor: __src_soil_MOD_xdzs] [Scalar: 0]
+; CHECK: MustWriteAccess :=	[Reduction Type: NONE] [Fortran array descriptor: __src_soil_MOD_xdzs] [Scalar: 0]
diff --git a/final/test/ScopInfo/fortran_array_global_nonmalloc_nonvectored.ll b/final/test/ScopInfo/fortran_array_global_nonmalloc_nonvectored.ll
new file mode 100644
index 0000000..9e7e37b
--- /dev/null
+++ b/final/test/ScopInfo/fortran_array_global_nonmalloc_nonvectored.ll
@@ -0,0 +1,89 @@
+; RUN: opt %loadPolly -analyze -S -polly-detect-fortran-arrays \
+; RUN: -polly-process-unprofitable -polly-scops  < %s | FileCheck %s
+
+; MODULE src_soil
+; USE data_parameters, ONLY :   &
+;     wp,        & ! KIND-type parameter for real variables
+;     iintegers    ! KIND-type parameter for standard integer variables
+; IMPLICIT NONE
+; REAL (KIND = wp),     ALLOCATABLE, PRIVATE  :: &
+;   xdzs     (:)
+; CONTAINS
+;
+; SUBROUTINE terra1(n)
+;   INTEGER, intent(in) :: n
+;
+;   INTEGER (KIND=iintegers) ::  &
+;     j
+;
+;    DO j = 22, n
+;         xdzs(j) = xdzs(j) * xdzs(j) + xdzs(j - 1)
+;   END DO
+; END SUBROUTINE terra1
+; END MODULE src_soil
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
+
+%"struct.array1_real(kind=8)" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
+%struct.descriptor_dimension = type { i64, i64, i64 }
+
+@__src_soil_MOD_xdzs = unnamed_addr global %"struct.array1_real(kind=8)" zeroinitializer, align 32
+
+; Function Attrs: nounwind uwtable
+define void @__src_soil_MOD_terra1(i32* noalias nocapture %n) unnamed_addr #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %tmp = load i32, i32* %n, align 4, !tbaa !0
+  %tmp1 = icmp sgt i32 %tmp, 21
+  br i1 %tmp1, label %"3.preheader", label %return
+
+"3.preheader":                                    ; preds = %entry.split
+  %tmp2 = load i64, i64* getelementptr inbounds (%"struct.array1_real(kind=8)", %"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs, i64 0, i32 1), align 8, !tbaa !3
+  %tmp3 = load double*, double** bitcast (%"struct.array1_real(kind=8)"* @__src_soil_MOD_xdzs to double**), align 32, !tbaa !5
+  %tmp4 = add i32 %tmp, 1
+  br label %"3"
+
+"3":                                              ; preds = %"3", %"3.preheader"
+  %indvars.iv = phi i64 [ 22, %"3.preheader" ], [ %indvars.iv.next, %"3" ]
+  %tmp5 = add nsw i64 %indvars.iv, %tmp2
+  %tmp6 = getelementptr inbounds double, double* %tmp3, i64 %tmp5
+  %tmp7 = load double, double* %tmp6, align 8, !tbaa !7
+  %tmp8 = fmul double %tmp7, %tmp7
+  %tmp9 = add i64 %tmp2, -1
+  %tmp10 = add i64 %tmp9, %indvars.iv
+  %tmp11 = getelementptr inbounds double, double* %tmp3, i64 %tmp10
+  %tmp12 = load double, double* %tmp11, align 8, !tbaa !7
+  %tmp13 = fadd double %tmp8, %tmp12
+  store double %tmp13, double* %tmp6, align 8, !tbaa !7
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %lftr.wideiv1 = trunc i64 %indvars.iv.next to i32
+  %exitcond2 = icmp eq i32 %lftr.wideiv1, %tmp4
+  br i1 %exitcond2, label %return.loopexit, label %"3"
+
+return.loopexit:                                  ; preds = %"3"
+  br label %return
+
+return:                                           ; preds = %return.loopexit, %entry.split
+  ret void
+}
+
+attributes #0 = { nounwind uwtable }
+
+!0 = !{!1, !1, i64 0}
+!1 = !{!"alias set 11: integer(kind=4)", !2}
+!2 = distinct !{!2}
+!3 = !{!4, !4, i64 0}
+!4 = !{!"alias set 4: integer(kind=8)", !2}
+!5 = !{!6, !6, i64 0}
+!6 = !{!"alias set 3: void*", !2}
+!7 = !{!8, !8, i64 0}
+!8 = !{!"alias set 18: real(kind=8)", !2}
+
+; CHECK: ReadAccess :=	[Reduction Type: NONE] [Fortran array descriptor: __src_soil_MOD_xdzs] [Scalar: 0]
+; CHECK: ReadAccess :=	[Reduction Type: NONE] [Fortran array descriptor: __src_soil_MOD_xdzs] [Scalar: 0]
+; CHECK: MustWriteAccess :=	[Reduction Type: NONE] [Fortran array descriptor: __src_soil_MOD_xdzs] [Scalar: 0]
diff --git a/final/test/ScopInfo/fortran_array_param_nonmalloc_nonvectored.ll b/final/test/ScopInfo/fortran_array_param_nonmalloc_nonvectored.ll
new file mode 100644
index 0000000..04af422
--- /dev/null
+++ b/final/test/ScopInfo/fortran_array_param_nonmalloc_nonvectored.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -analyze -polly-detect-fortran-arrays \
+; RUN: -polly-scops -polly-allow-nonaffine -polly-invariant-load-hoisting < %s | FileCheck %s
+
+; This testcase is the corresponding LLVM for testfunc:
+; PROGRAM main
+;     INTEGER, DIMENSION(1) :: xs
+;
+;     CALL testfunc(xs, 10)
+; CONTAINS
+;     SUBROUTINE func(xs, n)
+;         IMPLICIT NONE
+;         INTEGER, DIMENSION(:), INTENT(INOUT) :: xs
+;         INTEGER, INTENT(IN) :: n
+;         INTEGER :: i
+
+;         DO i = 1, n
+;             xs(i) = 1
+;         END DO
+;
+;     END SUBROUTINE func
+; END PROGRAM
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
+
+%"struct.array1_integer(kind=4)" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
+%struct.descriptor_dimension = type { i64, i64, i64 }
+
+define internal void @testfunc(%"struct.array1_integer(kind=4)"* noalias %xs, i32* noalias %n) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %tmp = getelementptr inbounds %"struct.array1_integer(kind=4)", %"struct.array1_integer(kind=4)"* %xs, i64 0, i32 3, i64 0, i32 0
+  %tmp1 = load i64, i64* %tmp, align 8
+  %tmp2 = icmp eq i64 %tmp1, 0
+  %tmp3 = select i1 %tmp2, i64 1, i64 %tmp1
+  %tmp4 = bitcast %"struct.array1_integer(kind=4)"* %xs to i32**
+  %tmp5 = load i32*, i32** %tmp4, align 8
+  %tmp6 = load i32, i32* %n, align 4
+  %tmp7 = icmp sgt i32 %tmp6, 0
+  br i1 %tmp7, label %"6.preheader", label %return
+
+"6.preheader":                                    ; preds = %entry.split
+  br label %"6"
+
+"6":                                              ; preds = %"6", %"6.preheader"
+  %tmp8 = phi i32 [ %tmp14, %"6" ], [ 1, %"6.preheader" ]
+  %tmp9 = sext i32 %tmp8 to i64
+  %tmp10 = mul i64 %tmp3, %tmp9
+  %tmp11 = sub i64 %tmp10, %tmp3
+  %tmp12 = getelementptr i32, i32* %tmp5, i64 %tmp11
+  ; store
+  store i32 1, i32* %tmp12, align 4
+  %tmp13 = icmp eq i32 %tmp8, %tmp6
+  %tmp14 = add i32 %tmp8, 1
+  br i1 %tmp13, label %return.loopexit, label %"6"
+
+return.loopexit:                                  ; preds = %"6"
+  br label %return
+
+return:                                           ; preds = %return.loopexit, %entry.split
+  ret void
+}
+
+; CHECK: MayWriteAccess := [Reduction Type: NONE] [Fortran array descriptor: xs] [Scalar: 0]
diff --git a/final/test/ScopInfo/fortran_array_param_nonmalloc_nonvectored_read_and_write.ll b/final/test/ScopInfo/fortran_array_param_nonmalloc_nonvectored_read_and_write.ll
new file mode 100644
index 0000000..480eb2e
--- /dev/null
+++ b/final/test/ScopInfo/fortran_array_param_nonmalloc_nonvectored_read_and_write.ll
@@ -0,0 +1,93 @@
+; RUN: opt %loadPolly -analyze -polly-detect-fortran-arrays \
+; RUN: -polly-scops -polly-allow-nonaffine -polly-ignore-aliasing < %s | FileCheck %s
+
+; PROGRAM main
+; ...
+; CONTAINS
+;     SUBROUTINE copy(xs, ys, n)
+;         IMPLICIT NONE
+;         INTEGER, DIMENSION(:), INTENT(INOUT) :: xs, ys
+;         INTEGER, INTENT(IN) :: n
+;         INTEGER :: i
+; 
+;         DO i = 1, n
+;             ys(i * i) = xs(i * i)
+;         END DO
+; 
+;     END SUBROUTINE copy
+; END PROGRAM
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
+
+%"struct.array1_integer(kind=4)" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
+%struct.descriptor_dimension = type { i64, i64, i64 }
+%"struct.array1_integer(kind=4).0" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
+%"struct.array1_integer(kind=4).1" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
+%"struct.array1_integer(kind=4).2" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
+%struct.__st_parameter_dt = type { %struct.__st_parameter_common, i64, i64*, i64*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i8*, [256 x i8], i32*, i64, i8*, i32, i32, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i8*, i8*, i32, [4 x i8] }
+%struct.__st_parameter_common = type { i32, i32, i8*, i32, i32, i8*, i32* }
+%"struct.array1_integer(kind=4).3" = type { i8*, i64, i64, [1 x %struct.descriptor_dimension] }
+
+@0 = internal constant i32 10
+@.cst = private constant [12 x i8] c"program.f90\00", align 8
+@options.12.1603 = internal constant [8 x i32] [i32 68, i32 511, i32 0, i32 0, i32 0, i32 1, i32 0, i32 1], align 32
+
+; Function Attrs: nounwind uwtable
+define internal void @copy.1550(%"struct.array1_integer(kind=4)"* noalias %xs, %"struct.array1_integer(kind=4).0"* noalias %ys, i32* noalias %n) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %0 = getelementptr inbounds %"struct.array1_integer(kind=4).0", %"struct.array1_integer(kind=4).0"* %ys, i64 0, i32 3, i64 0, i32 0
+  %1 = load i64, i64* %0, align 8
+  %2 = icmp eq i64 %1, 0
+  %3 = select i1 %2, i64 1, i64 %1
+  %4 = bitcast %"struct.array1_integer(kind=4).0"* %ys to i32**
+  %5 = load i32*, i32** %4, align 8
+  %6 = getelementptr inbounds %"struct.array1_integer(kind=4)", %"struct.array1_integer(kind=4)"* %xs, i64 0, i32 3, i64 0, i32 0
+  %7 = load i64, i64* %6, align 8
+  %8 = icmp eq i64 %7, 0
+  %. = select i1 %8, i64 1, i64 %7
+  %9 = bitcast %"struct.array1_integer(kind=4)"* %xs to i32**
+  %10 = load i32*, i32** %9, align 8
+  %11 = load i32, i32* %n, align 4
+  %12 = icmp sgt i32 %11, 0
+  br i1 %12, label %"9.preheader", label %return
+
+"9.preheader":                                    ; preds = %entry.split
+  br label %"9"
+
+"9":                                              ; preds = %"9.preheader", %"9"
+  %13 = phi i32 [ %26, %"9" ], [ 1, %"9.preheader" ]
+  %14 = mul i32 %13, %13
+  %15 = sext i32 %14 to i64
+  %16 = mul i64 %3, %15
+  %17 = sub i64 %16, %3
+  %18 = mul i32 %13, %13
+  %19 = sext i32 %18 to i64
+  %20 = mul i64 %., %19
+  %21 = sub i64 %20, %.
+  %22 = getelementptr i32, i32* %10, i64 %21
+  ; load
+  %23 = load i32, i32* %22, align 4
+  %24 = getelementptr i32, i32* %5, i64 %17
+  ; write
+  store i32 %23, i32* %24, align 4
+  %25 = icmp eq i32 %13, %11
+  %26 = add i32 %13, 1
+  br i1 %25, label %return.loopexit, label %"9"
+
+return.loopexit:                                  ; preds = %"9"
+  br label %return
+
+return:                                           ; preds = %return.loopexit, %entry.split
+  ret void
+}
+
+; CHECK:      ReadAccess :=	[Reduction Type: NONE] [Fortran array descriptor: xs] [Scalar: 0]
+; CHECK-NEXT:     [p_0_loaded_from_n, MemRef0_fortranarr_size, MemRef1_fortranarr_size] -> { Stmt_9[i0] -> MemRef0[o0] };
+; CHECK-NEXT: MayWriteAccess :=	[Reduction Type: NONE] [Fortran array descriptor: ys] [Scalar: 0]
+; CHECK-NEXT:     [p_0_loaded_from_n, MemRef0_fortranarr_size, MemRef1_fortranarr_size] -> { Stmt_9[i0] -> MemRef1[o0] };
diff --git a/final/test/ScopInfo/full-function.ll b/final/test/ScopInfo/full-function.ll
new file mode 100644
index 0000000..b91a517
--- /dev/null
+++ b/final/test/ScopInfo/full-function.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-detect-full-functions < %s \
+; RUN: | FileCheck %s -check-prefix=FULL
+; RUN: opt %loadPolly -polly-scops -analyze < %s \
+; RUN: | FileCheck %s -check-prefix=WITHOUT-FULL
+
+; FULL:      Region: %bb---FunctionExit
+; FULL:      Statements {
+; FULL-NEXT: 	Stmt_loop_1
+; FULL-NEXT:         Domain :=
+; FULL-NEXT:             [p] -> { Stmt_loop_1[i0] : p = 42 and 0 <= i0 <= 1025 };
+; FULL-NEXT:         Schedule :=
+; FULL-NEXT:             [p] -> { Stmt_loop_1[i0] -> [1, i0] };
+; FULL-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; FULL-NEXT:             [p] -> { Stmt_loop_1[i0] -> MemRef_A[0] };
+; FULL-NEXT: 	Stmt_loop_2
+; FULL-NEXT:         Domain :=
+; FULL-NEXT:             [p] -> { Stmt_loop_2[i0] : 0 <= i0 <= 1025 and (p >= 43 or p <= 41) };
+; FULL-NEXT:         Schedule :=
+; FULL-NEXT:             [p] -> { Stmt_loop_2[i0] -> [0, i0] : p >= 43 or p <= 41 };
+; FULL-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; FULL-NEXT:             [p] -> { Stmt_loop_2[i0] -> MemRef_A[0] };
+; FULL-NEXT: }
+
+; WITHOUT-FULL:        Region: %loop.2---%merge
+; WITHOUT-FULL:        Statements {
+; WITHOUT-FULL-NEXT:    	Stmt_loop_2
+; WITHOUT-FULL-NEXT:            Domain :=
+; WITHOUT-FULL-NEXT:                { Stmt_loop_2[i0] : 0 <= i0 <= 1025 };
+; WITHOUT-FULL-NEXT:            Schedule :=
+; WITHOUT-FULL-NEXT:                { Stmt_loop_2[i0] -> [i0] };
+; WITHOUT-FULL-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; WITHOUT-FULL-NEXT:                { Stmt_loop_2[i0] -> MemRef_A[0] };
+; WITHOUT-FULL-NEXT:    }
+
+; WITHOUT-FULL:         Region: %loop.1---%merge
+; WITHOUT-FULL:         Statements {
+; WITHOUT-FULL-NEXT:    	Stmt_loop_1
+; WITHOUT-FULL-NEXT:            Domain :=
+; WITHOUT-FULL-NEXT:                { Stmt_loop_1[i0] : 0 <= i0 <= 1025 };
+; WITHOUT-FULL-NEXT:            Schedule :=
+; WITHOUT-FULL-NEXT:                { Stmt_loop_1[i0] -> [i0] };
+; WITHOUT-FULL-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; WITHOUT-FULL-NEXT:                { Stmt_loop_1[i0] -> MemRef_A[0] };
+; WITHOUT-FULL-NEXT:    }
+
+define void @foo(float* %A, i32 %p) {
+bb:
+  %cmp = icmp eq i32 %p, 42
+  br i1 %cmp, label %loop.1, label %loop.2
+
+loop.1:
+  %indvar.1 = phi i64 [0, %bb], [%indvar.next.1, %loop.1]
+  %indvar.next.1 = add i64 %indvar.1, 1
+  store float 42.0, float* %A
+  %cmp.1 = icmp sle i64 %indvar.1, 1024
+  br i1 %cmp.1, label %loop.1, label %merge
+
+loop.2:
+  %indvar.2 = phi i64 [0, %bb], [%indvar.next.2, %loop.2]
+  %indvar.next.2 = add i64 %indvar.2, 1
+  store float 42.0, float* %A
+  %cmp.2 = icmp sle i64 %indvar.2, 1024
+  br i1 %cmp.2, label %loop.2, label %merge
+
+merge:
+  ret void
+}
diff --git a/final/test/ScopInfo/granularity_scalar-indep.ll b/final/test/ScopInfo/granularity_scalar-indep.ll
new file mode 100644
index 0000000..9a5b434
--- /dev/null
+++ b/final/test/ScopInfo/granularity_scalar-indep.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-stmt-granularity=scalar-indep -polly-print-instructions -polly-scops -analyze < %s | FileCheck %s -match-full-lines
+;
+; Split a block into two independent statements that share no scalar.
+; This case has the instructions of the two statements interleaved, such that
+; splitting the BasicBlock in the middle would cause a scalar dependency.
+;
+; for (int j = 0; j < n; j += 1) {
+; body:
+;   double valA = A[0];
+;   double valB = 21.0 + 21.0;
+;   A[0] = valA;
+;   B[0] = valB;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %valA = load double, double* %A
+      %valB = fadd double 21.0, 21.0
+      store double %valA, double* %A
+      store double %valB, double* %B
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_body[i0] : 0 <= i0 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_body[i0] -> [i0, 0] };
+; CHECK-NEXT:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         Instructions {
+; CHECK-NEXT:               %valA = load double, double* %A
+; CHECK-NEXT:               store double %valA, double* %A
+; CHECK-NEXT:         }
+; CHECK-NEXT:     Stmt_body1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_body1[i0] : 0 <= i0 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_body1[i0] -> [i0, 1] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_body1[i0] -> MemRef_B[0] };
+; CHECK-NEXT:         Instructions {
+; CHECK-NEXT:               %valB = fadd double 2.100000e+01, 2.100000e+01
+; CHECK-NEXT:               store double %valB, double* %B
+; CHECK-NEXT:         }
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/granularity_scalar-indep_epilogue.ll b/final/test/ScopInfo/granularity_scalar-indep_epilogue.ll
new file mode 100644
index 0000000..cf31929
--- /dev/null
+++ b/final/test/ScopInfo/granularity_scalar-indep_epilogue.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-stmt-granularity=scalar-indep -polly-print-instructions -polly-scops -analyze < %s | FileCheck %s -match-full-lines
+;
+; Split a block into two independent statements that share no scalar.
+; This case has an independent statement just for PHI writes.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double valA = A[0];
+;   A[0] = valA;
+;
+; bodyB:
+;   phi = 42.0;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %valA = load double, double* %A
+      store double %valA, double* %A
+      br label %bodyB
+
+    bodyB:
+      %phi = phi double [42.0, %bodyA]
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] : 0 <= i0 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> [i0, 0] };
+; CHECK-NEXT:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         Instructions {
+; CHECK-NEXT:             %valA = load double, double* %A
+; CHECK-NEXT:             store double %valA, double* %A
+; CHECK-NEXT:         }
+; CHECK-NEXT:     Stmt_bodyA1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_bodyA1[i0] : 0 <= i0 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_bodyA1[i0] -> [i0, 1] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n] -> { Stmt_bodyA1[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:         Instructions {
+; CHECK-NEXT:         }
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/granularity_scalar-indep_epilogue_last.ll b/final/test/ScopInfo/granularity_scalar-indep_epilogue_last.ll
new file mode 100644
index 0000000..3c29292
--- /dev/null
+++ b/final/test/ScopInfo/granularity_scalar-indep_epilogue_last.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-stmt-granularity=scalar-indep -polly-print-instructions -polly-scops -analyze < %s | FileCheck %s -match-full-lines
+;
+; Check that the statement where the PHI writes are in always comes last.
+; Otherwise we'd need to introduce a scalar dependency from the statement
+; defining a value to the last statement of a basic block.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double valA = A[0];
+;   A[0] = valA;
+;   double valB = B[0];
+;   B[0] = valB;
+;
+; bodyB:
+;   phi = valA;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %valA = load double, double* %A
+      store double %valA, double* %A
+      %valB = load double, double* %B
+      store double %valB, double* %B
+      br label %bodyB
+
+    bodyB:
+      %phi = phi double [%valA, %bodyA]
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] : 0 <= i0 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> [i0] };
+; CHECK-NEXT:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> MemRef_B[0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> MemRef_B[0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:         Instructions {
+; CHECK-NEXT:               %valA = load double, double* %A
+; CHECK-NEXT:               store double %valA, double* %A
+; CHECK-NEXT:               %valB = load double, double* %B
+; CHECK-NEXT:               store double %valB, double* %B
+; CHECK-NEXT:         }
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/granularity_scalar-indep_noepilogue.ll b/final/test/ScopInfo/granularity_scalar-indep_noepilogue.ll
new file mode 100644
index 0000000..cf438ab
--- /dev/null
+++ b/final/test/ScopInfo/granularity_scalar-indep_noepilogue.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-stmt-granularity=scalar-indep -polly-print-instructions -polly-scops -analyze < %s | FileCheck %s -match-full-lines
+;
+; This case has no explicit epilogue for PHI writes because it would
+; have a scalar dependency to the previous statement.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double valA = A[0];
+;   A[0] = valA;
+;
+; bodyB:
+;   phi = valA;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %valA = load double, double* %A
+      store double %valA, double* %A
+      br label %bodyB
+
+    bodyB:
+      %phi = phi double [%valA, %bodyA]
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] : 0 <= i0 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> [i0] };
+; CHECK-NEXT:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n] -> { Stmt_bodyA[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:         Instructions {
+; CHECK-NEXT:               %valA = load double, double* %A
+; CHECK-NEXT:               store double %valA, double* %A
+; CHECK-NEXT:         }
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/granularity_scalar-indep_ordered.ll b/final/test/ScopInfo/granularity_scalar-indep_ordered.ll
new file mode 100644
index 0000000..e0f3825
--- /dev/null
+++ b/final/test/ScopInfo/granularity_scalar-indep_ordered.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-stmt-granularity=scalar-indep -polly-print-instructions -polly-scops -analyze < %s | FileCheck %s -match-full-lines
+;
+; This case cannot be split into two statements because the order of
+; loads and store would be violated.
+;
+; for (int j = 0; j < n; j += 1) {
+; body:
+;   double valA = A[0];
+;   double valB = B[0];
+;   A[0] = valA;
+;   A[0] = valB;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %valA = load double, double* %A
+      %valB = load double, double* %B
+      store double %valA, double* %A
+      store double %valB, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:     Statements {
+; CHECK-NEXT:      Stmt_body
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [n] -> { Stmt_body[i0] : 0 <= i0 < n };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [n] -> { Stmt_body[i0] -> [i0] };
+; CHECK-NEXT:          ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:          ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              [n] -> { Stmt_body[i0] -> MemRef_B[0] };
+; CHECK-NEXT:          MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:          MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:          Instructions {
+; CHECK-NEXT:                %valA = load double, double* %A
+; CHECK-NEXT:                %valB = load double, double* %B
+; CHECK-NEXT:                store double %valA, double* %A
+; CHECK-NEXT:                store double %valB, double* %A
+; CHECK-NEXT:          }
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/i1_params.ll b/final/test/ScopInfo/i1_params.ll
new file mode 100644
index 0000000..345558e
--- /dev/null
+++ b/final/test/ScopInfo/i1_params.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that both a signed as well as an unsigned extended i1 parameter
+; is represented correctly.
+;
+;    void f(signed i1 p0, unsigned i1 p1, int *A) {
+;      for (int i = 0; i < 100; i++)
+;        A[i + p0] = A[i + p1];
+;    }
+;
+; CHECK:       Context:
+; CHECK-NEXT:    [p1, p0] -> {  : -1 <= p1 <= 0 and -1 <= p0 <= 0 }
+;
+; CHECK:       ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:    [p1, p0] -> { Stmt_for_body[i0] -> MemRef_A[1 + i0] : p1 = -1; Stmt_for_body[i0] -> MemRef_A[i0] : p1 = 0 };
+; CHECK-NEXT:  MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:    [p1, p0] -> { Stmt_for_body[i0] -> MemRef_A[p0 + i0] };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i1 %p0, i1 %p1, i32* %A) {
+entry:
+  %tmp4 = sext i1 %p0 to i64
+  %tmp = zext i1 %p1 to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp5 = add nsw i64 %indvars.iv, %tmp
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %tmp5
+  %tmp6 = load i32, i32* %arrayidx, align 4
+  %tmp7 = add nsw i64 %indvars.iv, %tmp4
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %tmp7
+  store i32 %tmp6, i32* %arrayidx3, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/infeasible-rtc.ll b/final/test/ScopInfo/infeasible-rtc.ll
new file mode 100644
index 0000000..957e3a0
--- /dev/null
+++ b/final/test/ScopInfo/infeasible-rtc.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s \
+; RUN:  | FileCheck %s -check-prefix=DETECT
+
+; RUN: opt %loadPolly -polly-scops -analyze < %s \
+; RUN:  | FileCheck %s -check-prefix=SCOPS
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; DETECT: Valid Region for Scop: test1.header => test1.exit
+; SCOPS-NOT: Region: %test1.header---%test1.exit
+
+; Verify that we detect this scop, but that, due to an infeasible run-time
+; check, we refuse to model it.
+
+define void @test(i64* %a) nounwind uwtable {
+preheader:
+  br label %test1.header
+
+test1.header:
+  %i = phi i56 [ 0, %preheader ], [ %i.1, %test1.header ]
+  %tmp = zext i56 %i to i64
+  %A.addr = getelementptr i64, i64* %a, i64 %tmp
+  %A.load = load i64, i64* %A.addr, align 4
+  %A.inc = zext i56 %i to i64
+  %A.val = add nsw i64 %A.load, %A.inc
+  store i64 %A.val, i64* %A.addr, align 4
+  %i.1 = add i56 %i, 1
+  %exitcond = icmp eq i56 %i.1, 0
+  br i1 %exitcond, label %test1.exit, label %test1.header
+
+test1.exit:
+  ret void
+}
+
+; Old version of the previous test; make sure we compute the trip count
+; correctly.
+
+; SCOPS: { Stmt_header[i0] : 0 <= i0 <= 127 };
+
+define void @test2([128 x i32]* %a) nounwind uwtable {
+preheader:
+  br label %header
+
+header:
+  %i = phi i7 [ 0, %preheader ], [ %i.1, %header ]
+  %tmp = zext i7 %i to i64
+  %A.addr = getelementptr [128 x i32], [128 x i32]* %a, i64 0, i64 %tmp
+  %A.load = load i32, i32* %A.addr, align 4
+  %A.inc = zext i7 %i to i32
+  %A.val = add nsw i32 %A.load, %A.inc
+  store i32 %A.val, i32* %A.addr, align 4
+  %i.1 = add i7 %i, 1
+  %exitcond = icmp eq i7 %i.1, 0
+  br i1 %exitcond, label %exit, label %header
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/infeasible_invalid_context.ll b/final/test/ScopInfo/infeasible_invalid_context.ll
new file mode 100644
index 0000000..9922bbc
--- /dev/null
+++ b/final/test/ScopInfo/infeasible_invalid_context.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s \
+; RUN:  | FileCheck %s -check-prefix=DETECT
+
+; RUN: opt %loadPolly -polly-scops -analyze < %s \
+; RUN:  | FileCheck %s -check-prefix=SCOPS
+
+; DETECT: Valid Region for Scop: if.end116 => for.inc216
+; SCOPS-NOT: Statements
+
+; Verify that we detect this scop, but that, due to an infeasible run-time
+; check, we refuse to model it.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739 = type { i32, i32, %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, i32, i32, %struct.plist.0.6.12.66.120.174.216.306.324.336.348.366.378.390.432.444.666.726.732.738* }
+%struct.plist.0.6.12.66.120.174.216.306.324.336.348.366.378.390.432.444.666.726.732.738 = type { i32, %struct.plist.0.6.12.66.120.174.216.306.324.336.348.366.378.390.432.444.666.726.732.738* }
+
+@vFixedEdgeRoot = external global %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, align 8
+@hEdgeRoot = external global %struct.tnode.1.7.13.67.121.175.217.307.325.337.349.367.379.391.433.445.667.727.733.739*, align 8
+
+; Function Attrs: nounwind uwtable
+define void @readgeo() #0 {
+entry:
+  %vx = alloca i32, align 4
+  br label %if.end64
+
+if.end64:                                         ; preds = %entry
+  br label %for.body73
+
+for.body73:                                       ; preds = %for.inc216, %if.end64
+  %v.0101 = phi i32 [ 0, %for.inc216 ], [ 1, %if.end64 ]
+  br i1 undef, label %if.then93, label %if.else
+
+if.then93:                                        ; preds = %for.body73
+  br label %for.inc216
+
+if.else:                                          ; preds = %for.body73
+  br i1 undef, label %if.then111, label %if.end116
+
+if.then111:                                       ; preds = %if.else
+  br label %if.end116
+
+if.end116:                                        ; preds = %if.then111, %if.else
+  %rippleCount.2 = phi i32 [ 1, %if.then111 ], [ undef, %if.else ]
+  %rem11790 = and i32 %v.0101, 1
+  %cmp118 = icmp eq i32 %rem11790, 0
+  br i1 %cmp118, label %if.then120, label %if.else154
+
+if.then120:                                       ; preds = %if.end116
+  call void @tinsert()
+  br label %if.end193
+
+if.else154:                                       ; preds = %if.end116
+  call void @tinsert()
+  br label %if.end193
+
+if.end193:                                        ; preds = %if.else154, %if.then120
+  %0 = load i32, i32* %vx, align 4
+  br label %for.inc216
+
+for.inc216:                                       ; preds = %if.end193, %if.then93
+  %rippleCount.3 = phi i32 [ undef, %if.then93 ], [ %rippleCount.2, %if.end193 ]
+  %ux.2 = phi i32 [ undef, %if.then93 ], [ %0, %if.end193 ]
+  br i1 undef, label %for.body73, label %for.end218
+
+for.end218:                                       ; preds = %for.inc216
+  unreachable
+}
+
+declare void @tinsert()
diff --git a/final/test/ScopInfo/int2ptr_ptr2int.ll b/final/test/ScopInfo/int2ptr_ptr2int.ll
new file mode 100644
index 0000000..586ee3f
--- /dev/null
+++ b/final/test/ScopInfo/int2ptr_ptr2int.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s
+; RUN: opt %loadPolly -S -polly-codegen < %s | FileCheck %s --check-prefix=IR
+;
+;    void f(long *A, long *ptr, long val) {
+;      for (long i = 0; i < 100; i++) {
+;        long ptrV = ((long)(ptr + 1)) + 1;
+;        long valP = (long)(((long *)(val + 1)) + 1);
+;        A[ptrV] += A[valP];
+;      }
+;    }
+;
+; CHECK:        ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       [val, ptr] -> { Stmt_for_body[i0] -> MemRef_A[9 + val] };
+; CHECK-NEXT:   ReadAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:       [val, ptr] -> { Stmt_for_body[i0] -> MemRef_A[9 + ptr] };
+; CHECK-NEXT:   MustWriteAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:       [val, ptr] -> { Stmt_for_body[i0] -> MemRef_A[9 + ptr] };
+;
+; IR:      polly.stmt.for.body:
+; IR-NEXT:   %p_tmp = ptrtoint i64* %scevgep to i64
+; IR-NEXT:   %p_add = add nsw i64 %p_tmp, 1
+; IR-NEXT:   %p_tmp1 = inttoptr i64 %10 to i64*
+; IR-NEXT:   %p_add.ptr2 = getelementptr inbounds i64, i64* %p_tmp1, i64 1
+; IR-NEXT:   %p_tmp2 = ptrtoint i64* %p_add.ptr2 to i64
+; IR-NEXT:   %p_arrayidx = getelementptr inbounds i64, i64* %A, i64 %p_tmp2
+; IR-NEXT:   %tmp3_p_scalar_ = load i64, i64* %p_arrayidx
+; IR-NEXT:   %p_arrayidx3 = getelementptr inbounds i64, i64* %A, i64 %p_add
+; IR-NEXT:   %tmp4_p_scalar_ = load i64, i64* %p_arrayidx3
+; IR-NEXT:   %p_add4 = add nsw i64 %tmp4_p_scalar_, %tmp3_p_scalar_
+; IR-NEXT:   store i64 %p_add4, i64* %p_arrayidx3
+;
+; IR:      polly.loop_preheader:
+; IR-NEXT:   %scevgep = getelementptr i64, i64* %ptr, i32 1
+; IR-NEXT:   %10 = add i64 %val, 1
+; IR-NEXT:   br label %polly.loop_header
+;
+target datalayout = "e-p:32:32:32-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i64* %A, i64* %ptr, i64 %val) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add.ptr = getelementptr inbounds i64, i64* %ptr, i64 1
+  %tmp = ptrtoint i64* %add.ptr to i64
+  %add = add nsw i64 %tmp, 1
+  %add1 = add nsw i64 %val, 1
+  %tmp1 = inttoptr i64 %add1 to i64*
+  %add.ptr2 = getelementptr inbounds i64, i64* %tmp1, i64 1
+  %tmp2 = ptrtoint i64* %add.ptr2 to i64
+  %arrayidx = getelementptr inbounds i64, i64* %A, i64 %tmp2
+  %tmp3 = load i64, i64* %arrayidx
+  %arrayidx3 = getelementptr inbounds i64, i64* %A, i64 %add
+  %tmp4 = load i64, i64* %arrayidx3
+  %add4 = add nsw i64 %tmp4, %tmp3
+  store i64 %add4, i64* %arrayidx3
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/int2ptr_ptr2int_2.ll b/final/test/ScopInfo/int2ptr_ptr2int_2.ll
new file mode 100644
index 0000000..951f493
--- /dev/null
+++ b/final/test/ScopInfo/int2ptr_ptr2int_2.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -analyze -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+; RUN: opt %loadPolly -S -polly-codegen \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s --check-prefix=IR
+;
+;    void f(long *A, long *B, long *ptr, long val) {
+;      for (long i = 0; i < 100; i++) {
+;        long ptrV = ((long)(ptr + 1)) + 1;
+;        long valP = (long)(((long *)(val + 1)) + 1);
+;        A[ptrV] += B[valP];
+;      }
+;    }
+;
+; CHECK:        ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       [val, ptr] -> { Stmt_for_body[i0] -> MemRef_B[9 + val] };
+; CHECK-NEXT:   Execution Context: [val, ptr] -> {  : val <= 32766 }
+;
+; CHECK:   ReadAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:       [val, ptr] -> { Stmt_for_body[i0] -> MemRef_A[9 + ptr] };
+; CHECK-NEXT:   MustWriteAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:       [val, ptr] -> { Stmt_for_body[i0] -> MemRef_A[9 + ptr] };
+;
+; IR:      polly.stmt.for.body:
+; IR-NEXT:  %p_tmp = ptrtoint i64* %scevgep to i16
+; IR-NEXT:  %p_add = add nsw i16 %p_tmp, 1
+; IR-NEXT:  %p_arrayidx3 = getelementptr inbounds i64, i64* %A, i16 %p_add
+; IR-NEXT:  %tmp4_p_scalar_ = load i64, i64* %p_arrayidx3
+; IR-NEXT:  %p_add4 = add nsw i64 %tmp4_p_scalar_, %polly.preload.tmp3.merge
+; IR-NEXT:  store i64 %p_add4, i64* %p_arrayidx3
+;
+; IR:      polly.loop_preheader:
+; IR-NEXT:   %scevgep = getelementptr i64, i64* %ptr, i16 1
+; IR-NEXT:   %35 = add i16 %val, 1
+; IR-NEXT:   br label %polly.loop_header
+;
+;
+target datalayout = "e-p:16:16:16-m:e-i64:64-f80:128-n8:16:16:64-S128"
+
+define void @f(i64* %A, i64* %B, i64* %ptr, i16 %val) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add.ptr = getelementptr inbounds i64, i64* %ptr, i64 1
+  %tmp = ptrtoint i64* %add.ptr to i16
+  %add = add nsw i16 %tmp, 1
+  %add1 = add nsw i16 %val, 1
+  %tmp1 = inttoptr i16 %add1 to i64*
+  %add.ptr2 = getelementptr inbounds i64, i64* %tmp1, i64 1
+  %tmp2 = ptrtoint i64* %add.ptr2 to i16
+  %arrayidx = getelementptr inbounds i64, i64* %B, i16 %tmp2
+  %tmp3 = load i64, i64* %arrayidx
+  %arrayidx3 = getelementptr inbounds i64, i64* %A, i16 %add
+  %tmp4 = load i64, i64* %arrayidx3
+  %add4 = add nsw i64 %tmp4, %tmp3
+  store i64 %add4, i64* %arrayidx3
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/integers.ll b/final/test/ScopInfo/integers.ll
new file mode 100644
index 0000000..25ef908
--- /dev/null
+++ b/final/test/ScopInfo/integers.ll
@@ -0,0 +1,143 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; Check that we correctly convert integers to isl values.
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+; Large positive integer
+define void @f(i1024* nocapture %a) nounwind {
+entry:
+  br label %bb
+
+bb:
+  %indvar = phi i1024 [ 0, %entry ], [ %indvar.next, %bb ]
+  store i1024 %indvar, i1024* %a, align 8
+  %indvar.next = add nsw i1024 %indvar, 1
+  %exitcond = icmp eq i1024 %indvar, 123456000000000000000000000
+; CHECK-LABEL: Function: f
+; CHECK-NEXT: Region: %bb---%return
+; CHECK: i0 <= 123456000000000000000000000
+  br i1 %exitcond, label %return, label %bb
+
+return:
+  ret void
+}
+
+; Normal positive integer
+define void @f2(i32* nocapture %a) nounwind {
+entry:
+  br label %bb
+
+bb:
+  %indvar = phi i32 [ 0, %entry ], [ %indvar.next, %bb ]
+  %scevgep = getelementptr i32, i32* %a, i32 %indvar
+  store i32 %indvar, i32* %scevgep, align 8
+  %indvar.next = add nsw i32 %indvar, 1
+  %exitcond = icmp eq i32 %indvar, 123456
+; CHECK-LABEL: Function: f2
+; CHECK-NEXT: Region: %bb---%return
+; CHECK: i0 <= 123456
+  br i1 %exitcond, label %return, label %bb
+
+return:
+  ret void
+}
+
+; Normal negative integer
+define void @f3(i32* nocapture %a, i32 %n) nounwind {
+entry:
+  br label %bb
+
+bb:
+  %indvar = phi i32 [ 0, %entry ], [ %indvar.next, %bb ]
+  %scevgep = getelementptr i32, i32* %a, i32 %indvar
+  store i32 %indvar, i32* %scevgep, align 8
+  %indvar.next = add nsw i32 %indvar, 1
+  %sub = sub i32 %n, 123456
+  %exitcond = icmp eq i32 %indvar, %sub
+; CHECK-LABEL: Function: f3
+; CHECK-NEXT: Region: %bb---%return
+; CHECK: -123456
+  br i1 %exitcond, label %return, label %bb
+
+return:
+  ret void
+}
+
+; Large negative integer
+define void @f4(i1024* nocapture %a, i1024 %n) nounwind {
+entry:
+  br label %bb
+
+bb:
+  %indvar = phi i1024 [ 0, %entry ], [ %indvar.next, %bb ]
+  %scevgep = getelementptr i1024, i1024* %a, i1024 %indvar
+  store i1024 %indvar, i1024* %scevgep, align 8
+  %indvar.next = add nsw i1024 %indvar, 1
+  %sub = sub i1024 %n, 123456000000000000000000000000000000
+; CHECK-LABEL: Function: f4
+; CHECK-NEXT: Region: %bb---%return
+; CHECK: -123456000000000000000000000000000000
+  %exitcond = icmp eq i1024 %indvar, %sub
+  br i1 %exitcond, label %return, label %bb
+
+return:
+  ret void
+}
+
+define void @f5(i1023* nocapture %a, i1023 %n) nounwind {
+entry:
+  br label %bb
+
+bb:
+  %indvar = phi i1023 [ 0, %entry ], [ %indvar.next, %bb ]
+  %scevgep = getelementptr i1023, i1023* %a, i1023 %indvar
+  store i1023 %indvar, i1023* %scevgep, align 8
+  %indvar.next = add nsw i1023 %indvar, 1
+  %sub = sub i1023 %n, 123456000000000000000000000000000000
+; CHECK-LABEL: Function: f5
+; CHECK-NEXT: Region: %bb---%return
+; CHECK: -123456000000000000000000000000000000
+  %exitcond = icmp eq i1023 %indvar, %sub
+  br i1 %exitcond, label %return, label %bb
+
+return:
+  ret void
+}
+
+; Tiny negative integer
+define void @f6(i3* nocapture %a, i3 %n) nounwind {
+entry:
+  br label %bb
+
+bb:
+  %indvar = phi i3 [ 0, %entry ], [ %indvar.next, %bb ]
+  %scevgep = getelementptr i3, i3* %a, i3 %indvar
+  store i3 %indvar, i3* %scevgep, align 8
+  %indvar.next = add nsw i3 %indvar, 1
+  %sub = sub i3 %n, 3
+; CHECK-LABEL: Function: f6
+; CHECK-NEXT: Region: %bb---%return
+; CHECK:         Context:
+; CHECK-NEXT:    [n] -> {  : -4 <= n <= 3 }
+; CHECK-NEXT:    Assumed Context:
+; CHECK-NEXT:    [n] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [n] -> {  : 1 = 0 }
+
+; CHECK:     Statements {
+; CHECK-NEXT:    Stmt_bb
+; CHECK-NEXT:        Domain :=
+; CHECK-NEXT:            [n] -> { Stmt_bb[i0] : i0 >= 0 and 8*floor((2 - n)/8) >= -5 - n + i0 and 8*floor((2 - n)/8) <= -2 - n };
+; CHECK-NEXT:        Schedule :=
+; CHECK-NEXT:            [n] -> { Stmt_bb[i0] -> [i0] };
+; CHECK-NEXT:        MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:            [n] -> { Stmt_bb[i0] -> MemRef_a[i0] };
+; CHECK-NEXT:}
+
+  %exitcond = icmp eq i3 %indvar, %sub
+  br i1 %exitcond, label %return, label %bb
+
+return:
+  ret void
+}
diff --git a/final/test/ScopInfo/inter-error-bb-dependence.ll b/final/test/ScopInfo/inter-error-bb-dependence.ll
new file mode 100644
index 0000000..0e0fcf8
--- /dev/null
+++ b/final/test/ScopInfo/inter-error-bb-dependence.ll
@@ -0,0 +1,51 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops -analyze < %s 2>&1 > /dev/null | FileCheck %s
+;
+; Error statements (%bb33) do not require their uses to be verified.
+; In this case it uses %tmp32 from %bb31 which is not available because
+; %bb31 is an error statement as well.
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+declare noalias i8* @widget()
+
+declare void @quux()
+
+define void @func(i32 %tmp3, i32 %tmp7, i32 %tmp17, i32 %tmp26, i32 %tmp19) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb
+  %tmp4 = icmp eq i32 %tmp3, 0
+  br i1 %tmp4, label %bb5, label %bb16
+
+bb5:                                              ; preds = %bb2
+  %tmp8 = icmp eq i32 %tmp7, 0
+  br i1 %tmp8, label %bb16, label %bb36
+
+bb16:                                             ; preds = %bb5, %bb2
+  %tmp18 = icmp eq i32 %tmp17, 0
+  %tmp20 = icmp eq i32 %tmp19, 0
+  %tmp21 = or i1 %tmp18, %tmp20
+  br i1 %tmp21, label %bb31, label %bb25
+
+bb25:                                             ; preds = %bb25, %bb16
+  %tmp27 = icmp eq i32 %tmp26, 0
+  br i1 %tmp27, label %bb31, label %bb25
+
+bb31:                                             ; preds = %bb25, %bb16
+  %tmp32 = call noalias i8* @widget()
+  br label %bb33
+
+bb33:                                             ; preds = %bb31
+  call void @quux()
+  %tmp34 = icmp eq i8* %tmp32, null
+  br label %bb36
+
+bb36:                                             ; preds = %bb33, %bb5
+  ret void
+}
+
+
+; CHECK:      SCoP begins here.
+; CHECK-NEXT: Low complexity assumption:       {  : 1 = 0 }
+; CHECK-NEXT: SCoP ends here but was dismissed.
diff --git a/final/test/ScopInfo/inter_bb_scalar_dep.ll b/final/test/ScopInfo/inter_bb_scalar_dep.ll
new file mode 100644
index 0000000..eabcefe
--- /dev/null
+++ b/final/test/ScopInfo/inter_bb_scalar_dep.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -basicaa -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+
+; void f(long A[], int N, int *init_ptr) {
+;   long i, j;
+;
+;   for (i = 0; i < N; ++i) {
+;     init = *init_ptr;
+;     for (i = 0; i < N; ++i) {
+;       A[i] = init + 2;
+;     }
+;   }
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+; Function Attrs: nounwind
+; CHECK: Invariant
+; CHECK:           ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:          MemRef_init_ptr[0]
+
+define void @f(i64* noalias %A, i64 %N, i64* noalias %init_ptr) #0 {
+entry:
+  br label %for.i
+
+for.i:                                            ; preds = %for.i.end, %entry
+  %indvar.i = phi i64 [ 0, %entry ], [ %indvar.i.next, %for.i.end ]
+  %indvar.i.next = add nsw i64 %indvar.i, 1
+  br label %entry.next
+
+entry.next:                                       ; preds = %for.i
+  %init = load i64, i64* %init_ptr
+; CHECK-NOT: Stmt_entry_next
+  br label %for.j
+
+for.j:                                            ; preds = %for.j, %entry.next
+  %indvar.j = phi i64 [ 0, %entry.next ], [ %indvar.j.next, %for.j ]
+  %init_plus_two = add i64 %init, 2
+; CHECK-LABEL: Stmt_for_j
+; CHECK:           ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:          [N] -> { Stmt_for_j[i0, i1] -> MemRef_init[] };
+; CHECK:           MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:          [N] -> { Stmt_for_j[i0, i1] -> MemRef_A[i1] };
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar.j
+  store i64 %init_plus_two, i64* %scevgep
+  %indvar.j.next = add nsw i64 %indvar.j, 1
+  %exitcond.j = icmp eq i64 %indvar.j.next, %N
+  br i1 %exitcond.j, label %for.i.end, label %for.j
+
+for.i.end:                                        ; preds = %for.j
+  %exitcond.i = icmp eq i64 %indvar.i.next, %N
+  br i1 %exitcond.i, label %return, label %for.i
+
+return:                                           ; preds = %for.i.end
+  ret void
+}
+
+attributes #0 = { nounwind }
diff --git a/final/test/ScopInfo/intra-non-affine-stmt-phi-node.ll b/final/test/ScopInfo/intra-non-affine-stmt-phi-node.ll
new file mode 100644
index 0000000..9fa38c0
--- /dev/null
+++ b/final/test/ScopInfo/intra-non-affine-stmt-phi-node.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN:     -S < %s | FileCheck %s
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_loop__TO__backedge
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_loop__TO__backedge[i0] : 0 <= i0 <= 100 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_loop__TO__backedge[i0] -> [i0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_loop__TO__backedge[i0] -> MemRef_merge__phi[] };
+; CHECK-NEXT:     Stmt_backedge
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_backedge[i0] : 0 <= i0 <= 100 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_backedge[i0] -> [i0, 1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_backedge[i0] -> MemRef_merge__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_backedge[i0] -> MemRef_A[0] };
+; CHECK-NEXT: }
+
+define void @foo(float* %A, i1 %cond0, i1 %cond1) {
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %entry], [%indvar.next, %backedge]
+  %val0 = fadd float 1.0, 2.0
+  %val1 = fadd float 1.0, 2.0
+  br i1 %cond0, label %branch1, label %backedge
+
+branch1:
+  %val2 = fadd float 1.0, 2.0
+  br i1 %cond1, label %branch2, label %backedge
+
+branch2:
+  br label %backedge
+
+backedge:
+  %merge = phi float [%val0, %loop], [%val1, %branch1], [%val2, %branch2]
+  %indvar.next = add i64 %indvar, 1
+  store float %merge, float* %A
+  %cmp = icmp sle i64 %indvar.next, 100
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/intra_and_inter_bb_scalar_dep.ll b/final/test/ScopInfo/intra_and_inter_bb_scalar_dep.ll
new file mode 100644
index 0000000..166f991
--- /dev/null
+++ b/final/test/ScopInfo/intra_and_inter_bb_scalar_dep.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+
+; void f(long A[], int N, int *init_ptr) {
+;   long i, j;
+;
+;   for (i = 0; i < N; ++i) {
+;     init = *init_ptr;
+;     for (i = 0; i < N; ++i) {
+;       init2 = *init_ptr;
+;       A[i] = init + init2;
+;     }
+;   }
+; }
+
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_for_j[i0, i1] -> MemRef_init_ptr[0] };
+; CHECK-NEXT:         Execution Context: [N] -> {  :  N > 0 }
+; CHECK-NEXT: }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_j
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_for_j[i0, i1] : 0 <= i0 < N and 0 <= i1 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_for_j[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_j[i0, i1] -> MemRef_init[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_for_j[i0, i1] -> MemRef_A[i1] };
+; CHECK-NEXT: }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* noalias %A, i64 %N, i64* noalias %init_ptr) #0 {
+entry:
+  br label %for.i
+
+for.i:                                            ; preds = %for.i.end, %entry
+  %indvar.i = phi i64 [ 0, %entry ], [ %indvar.i.next, %for.i.end ]
+  %indvar.i.next = add nsw i64 %indvar.i, 1
+  br label %entry.next
+
+entry.next:                                       ; preds = %for.i
+  %init = load i64, i64* %init_ptr
+  br label %for.j
+
+for.j:                                            ; preds = %for.j, %entry.next
+  %indvar.j = phi i64 [ 0, %entry.next ], [ %indvar.j.next, %for.j ]
+  %init_2 = load i64, i64* %init_ptr
+  %init_sum = add i64 %init, %init_2
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar.j
+  store i64 %init_sum, i64* %scevgep
+  %indvar.j.next = add nsw i64 %indvar.j, 1
+  %exitcond.j = icmp eq i64 %indvar.j.next, %N
+  br i1 %exitcond.j, label %for.i.end, label %for.j
+
+for.i.end:                                        ; preds = %for.j
+  %exitcond.i = icmp eq i64 %indvar.i.next, %N
+  br i1 %exitcond.i, label %return, label %for.i
+
+return:                                           ; preds = %for.i.end
+  ret void
+}
+
+attributes #0 = { nounwind }
diff --git a/final/test/ScopInfo/intra_bb_scalar_dep.ll b/final/test/ScopInfo/intra_bb_scalar_dep.ll
new file mode 100644
index 0000000..2a8c2fa
--- /dev/null
+++ b/final/test/ScopInfo/intra_bb_scalar_dep.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+
+; void f(long A[], int N, int *init_ptr) {
+;   long i, j;
+;
+;   for (i = 0; i < N; ++i) {
+;     for (i = 0; i < N; ++i) {
+;       init = *init_ptr;
+;       A[i] = init + 2;
+;     }
+;   }
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+; Function Attrs: nounwind
+; CHECK:      Invariant Accesses:
+; CHECK-NEXT:     ReadAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:          [N] -> { Stmt_for_j[i0, i1] -> MemRef_init_ptr[0] };
+define void @f(i64* noalias %A, i64 %N, i64* noalias %init_ptr) #0 {
+entry:
+  br label %for.i
+
+for.i:                                            ; preds = %for.i.end, %entry
+  %indvar.i = phi i64 [ 0, %entry ], [ %indvar.i.next, %for.i.end ]
+  %indvar.i.next = add nsw i64 %indvar.i, 1
+  br label %entry.next
+
+entry.next:                                       ; preds = %for.i
+  br label %for.j
+
+for.j:                                            ; preds = %for.j, %entry.next
+  %indvar.j = phi i64 [ 0, %entry.next ], [ %indvar.j.next, %for.j ]
+  %init = load i64, i64* %init_ptr
+  %init_plus_two = add i64 %init, 2
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar.j
+  store i64 %init_plus_two, i64* %scevgep
+; CHECK:      Statements {
+; CHECK-NEXT:   Stmt_for_j
+; CHECK-NOT:     ReadAccess
+; CHECK:         MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:            [N] -> { Stmt_for_j[i0, i1] -> MemRef_A[i1] };
+; CHECK-NEXT:  }
+  %indvar.j.next = add nsw i64 %indvar.j, 1
+  %exitcond.j = icmp eq i64 %indvar.j.next, %N
+  br i1 %exitcond.j, label %for.i.end, label %for.j
+
+for.i.end:                                        ; preds = %for.j
+  %exitcond.i = icmp eq i64 %indvar.i.next, %N
+  br i1 %exitcond.i, label %return, label %for.i
+
+return:                                           ; preds = %for.i.end
+  ret void
+}
+
+attributes #0 = { nounwind }
diff --git a/final/test/ScopInfo/intrinsics.ll b/final/test/ScopInfo/intrinsics.ll
new file mode 100644
index 0000000..dbd8285
--- /dev/null
+++ b/final/test/ScopInfo/intrinsics.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-print-instructions < %s | FileCheck %s
+;
+; Verify that we remove the ignored intrinsics from the instruction list.
+;
+; CHECK:       Instructions {
+; CHECK-NEXT:      store i32 %i.0, i32* %arrayidx, align 4
+; CHECK-NEXT:    }
+;
+;    int A[1024];
+;    void func() {
+;      for (int i = 0; i < 1024; i++)
+;          A[i] = i;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @fun() #0 {
+entry:
+  %A = alloca [1024 x i32], align 16
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp slt i32 %i.0, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %idxprom = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds [1024 x i32], [1024 x i32]* %A, i64 0, i64 %idxprom
+  call void @llvm.donothing()
+  store i32 %i.0, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.donothing() #1
+
+attributes #0 = { noinline nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
diff --git a/final/test/ScopInfo/invalid_add_rec_after_invariant_load_remapping.ll b/final/test/ScopInfo/invalid_add_rec_after_invariant_load_remapping.ll
new file mode 100644
index 0000000..df909d0
--- /dev/null
+++ b/final/test/ScopInfo/invalid_add_rec_after_invariant_load_remapping.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s
+;
+; This crased at some point as we place %1 and %4 in the same equivalence class
+; for invariant loads and when we remap SCEVs to use %4 instead of %1 AddRec SCEVs
+; for the for.body.10 loop caused a crash as their operands were not invariant
+; in the loop. While we know they are, ScalarEvolution does not. However, we can simply
+; rewrite the AddRecs to hoist everything from the "start" out of the AddRec.
+;
+; Check we do not crash.
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.codebook.48.118.748.1882.2972 = type { i64, i64, i64, %struct.static_codebook.19.89.719.1853.2971*, float*, i32*, i32*, i8*, i32*, i32, i32 }
+%struct.static_codebook.19.89.719.1853.2971 = type { i64, i64, i64*, i32, i64, i64, i32, i32, i64*, %struct.encode_aux_nearestmatch.16.86.716.1850.2968*, %struct.encode_aux_threshmatch.17.87.717.1851.2969*, %struct.encode_aux_pigeonhole.18.88.718.1852.2970*, i32 }
+%struct.encode_aux_nearestmatch.16.86.716.1850.2968 = type { i64*, i64*, i64*, i64*, i64, i64 }
+%struct.encode_aux_threshmatch.17.87.717.1851.2969 = type { float*, i64*, i32, i32 }
+%struct.encode_aux_pigeonhole.18.88.718.1852.2970 = type { float, float, i32, i32, i64*, i64, i64*, i64*, i64* }
+
+; Function Attrs: inlinehint nounwind uwtable
+declare i64 @decode_packed_entry_number() #0
+
+; Function Attrs: nounwind uwtable
+define void @vorbis_book_decodev_set(%struct.codebook.48.118.748.1882.2972* %book) #1 {
+entry:
+  br i1 undef, label %for.body, label %return
+
+for.cond.loopexit:                                ; preds = %for.body.10, %if.end
+  br i1 undef, label %for.body, label %return
+
+for.body:                                         ; preds = %for.cond.loopexit, %entry
+  %call = tail call i64 @decode_packed_entry_number()
+  br i1 undef, label %return, label %if.end
+
+if.end:                                           ; preds = %for.body
+  %valuelist = getelementptr inbounds %struct.codebook.48.118.748.1882.2972, %struct.codebook.48.118.748.1882.2972* %book, i64 0, i32 4
+  %0 = load float*, float** %valuelist, align 8
+  %sext = shl i64 %call, 32
+  %conv4 = ashr exact i64 %sext, 32
+  %dim = getelementptr inbounds %struct.codebook.48.118.748.1882.2972, %struct.codebook.48.118.748.1882.2972* %book, i64 0, i32 0
+  %1 = load i64, i64* %dim, align 8
+  %mul = mul nsw i64 %1, %conv4
+  %add.ptr = getelementptr inbounds float, float* %0, i64 %mul
+  %cmp8.7 = icmp sgt i64 %1, 0
+  br i1 %cmp8.7, label %for.body.10, label %for.cond.loopexit
+
+for.body.10:                                      ; preds = %for.body.10, %if.end
+  %indvars.iv15 = phi i64 [ %indvars.iv.next16, %for.body.10 ], [ 0, %if.end ]
+  %indvars.iv.next16 = add nuw nsw i64 %indvars.iv15, 1
+  %arrayidx = getelementptr inbounds float, float* %add.ptr, i64 %indvars.iv15
+  %2 = bitcast float* %arrayidx to i32*
+  %3 = load i32, i32* %2, align 4
+  %4 = load i64, i64* %dim, align 8
+  %cmp8 = icmp slt i64 %indvars.iv.next16, %4
+  br i1 %cmp8, label %for.body.10, label %for.cond.loopexit
+
+return:                                           ; preds = %for.body, %for.cond.loopexit, %entry
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant-loads-leave-read-only-statements.ll b/final/test/ScopInfo/invariant-loads-leave-read-only-statements.ll
new file mode 100644
index 0000000..c9aea55
--- /dev/null
+++ b/final/test/ScopInfo/invariant-loads-leave-read-only-statements.ll
@@ -0,0 +1,117 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -analyze < %s
+
+; CHECK:      Statements {
+; CHECK-NEXT: 	Stmt_L_4
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [tmp8, tmp22, tmp15] -> { Stmt_L_4[i0, i1, i2] : 0 <= i0 < tmp8 and 0 <= i1 < tmp8 and 0 <= i2 < tmp8 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [tmp8, tmp22, tmp15] -> { Stmt_L_4[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [tmp8, tmp22, tmp15] -> { Stmt_L_4[i0, i1, i2] -> MemRef_tmp19[i1, i0] };
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [tmp8, tmp22, tmp15] -> { Stmt_L_4[i0, i1, i2] -> MemRef_tmp5[i2, i0] };
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [tmp8, tmp22, tmp15] -> { Stmt_L_4[i0, i1, i2] -> MemRef_tmp12[i2, i1] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [tmp8, tmp22, tmp15] -> { Stmt_L_4[i0, i1, i2] -> MemRef_tmp19[i1, i0] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%jl_value_t = type { %jl_value_t* }
+
+define %jl_value_t* @julia_gemm_22583(%jl_value_t*, %jl_value_t** %tmp1, i32) {
+top:
+  br label %top.split
+
+top.split:                                        ; preds = %top
+  %tmp3 = load %jl_value_t*, %jl_value_t** %tmp1, align 8
+  %tmp4 = bitcast %jl_value_t* %tmp3 to double**
+  %tmp5 = load double*, double** %tmp4, align 8
+  %tmp6 = getelementptr inbounds %jl_value_t, %jl_value_t* %tmp3, i64 3, i32 0
+  %tmp7 = bitcast %jl_value_t** %tmp6 to i64*
+  %tmp8 = load i64, i64* %tmp7, align 8
+  %tmp9 = getelementptr %jl_value_t*, %jl_value_t** %tmp1, i64 1
+  %tmp10 = load %jl_value_t*, %jl_value_t** %tmp9, align 8
+  %tmp11 = bitcast %jl_value_t* %tmp10 to double**
+  %tmp12 = load double*, double** %tmp11, align 8
+  %tmp13 = getelementptr inbounds %jl_value_t, %jl_value_t* %tmp10, i64 3, i32 0
+  %tmp14 = bitcast %jl_value_t** %tmp13 to i64*
+  %tmp15 = load i64, i64* %tmp14, align 8
+  %tmp16 = getelementptr %jl_value_t*, %jl_value_t** %tmp1, i64 2
+  %tmp17 = load %jl_value_t*, %jl_value_t** %tmp16, align 8
+  %tmp18 = bitcast %jl_value_t* %tmp17 to double**
+  %tmp19 = load double*, double** %tmp18, align 8
+  %tmp20 = getelementptr inbounds %jl_value_t, %jl_value_t* %tmp17, i64 3, i32 0
+  %tmp21 = bitcast %jl_value_t** %tmp20 to i64*
+  %tmp22 = load i64, i64* %tmp21, align 8
+  %tmp23 = icmp sgt i64 %tmp8, 0
+  %tmp24 = select i1 %tmp23, i64 %tmp8, i64 0
+  %tmp25 = add i64 %tmp24, 1
+  %tmp26 = icmp eq i64 %tmp24, 0
+  br i1 %tmp26, label %L.11, label %L.preheader
+
+L.preheader:                                      ; preds = %top.split
+  br label %L
+
+L:                                                ; preds = %L.preheader, %L.9
+  %"#s5.0" = phi i64 [ %tmp27, %L.9 ], [ 1, %L.preheader ]
+  %tmp27 = add i64 %"#s5.0", 1
+  br i1 %tmp26, label %L.9, label %L.2.preheader
+
+L.2.preheader:                                    ; preds = %L
+  br label %L.2
+
+L.2:                                              ; preds = %L.2.preheader, %L.7
+  %"#s4.0" = phi i64 [ %tmp28, %L.7 ], [ 1, %L.2.preheader ]
+  %tmp28 = add i64 %"#s4.0", 1
+  br i1 %tmp26, label %L.7, label %L.4.preheader
+
+L.4.preheader:                                    ; preds = %L.2
+  br label %L.4
+
+L.4:                                              ; preds = %L.4.preheader, %L.4
+  %"#s3.0" = phi i64 [ %tmp29, %L.4 ], [ 1, %L.4.preheader ]
+  %tmp29 = add i64 %"#s3.0", 1
+  %tmp30 = add i64 %"#s5.0", -1
+  %tmp31 = add i64 %"#s4.0", -1
+  %tmp32 = mul i64 %tmp31, %tmp22
+  %tmp33 = add i64 %tmp32, %tmp30
+  %tmp34 = getelementptr double, double* %tmp19, i64 %tmp33
+  %tmp35 = load double, double* %tmp34, align 8
+  %tmp36 = add i64 %"#s3.0", -1
+  %tmp37 = mul i64 %tmp36, %tmp8
+  %tmp38 = add i64 %tmp37, %tmp30
+  %tmp39 = getelementptr double, double* %tmp5, i64 %tmp38
+  %tmp40 = load double, double* %tmp39, align 8
+  %tmp41 = mul i64 %tmp36, %tmp15
+  %tmp42 = add i64 %tmp41, %tmp31
+  %tmp43 = getelementptr double, double* %tmp12, i64 %tmp42
+  %tmp44 = load double, double* %tmp43, align 8
+  %tmp45 = fmul double %tmp40, %tmp44
+  %tmp46 = fadd double %tmp35, %tmp45
+  store double %tmp46, double* %tmp34, align 8
+  %tmp47 = icmp eq i64 %tmp29, %tmp25
+  br i1 %tmp47, label %L.7.loopexit, label %L.4
+
+L.7.loopexit:                                     ; preds = %L.4
+  br label %L.7
+
+L.7:                                              ; preds = %L.7.loopexit, %L.2
+  %tmp48 = icmp eq i64 %tmp28, %tmp25
+  br i1 %tmp48, label %L.9.loopexit, label %L.2
+
+L.9.loopexit:                                     ; preds = %L.7
+  br label %L.9
+
+L.9:                                              ; preds = %L.9.loopexit, %L
+  %tmp49 = icmp eq i64 %tmp27, %tmp25
+  br i1 %tmp49, label %L.11.loopexit, label %L
+
+L.11.loopexit:                                    ; preds = %L.9
+  br label %L.11
+
+L.11:                                             ; preds = %L.11.loopexit, %top.split
+  ret %jl_value_t* inttoptr (i64 140220477440016 to %jl_value_t*)
+}
diff --git a/final/test/ScopInfo/invariant_load.ll b/final/test/ScopInfo/invariant_load.ll
new file mode 100644
index 0000000..5a465e1
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; CHECK: Invariant Accesses:
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:   { Stmt_bb2[i0] -> MemRef_B[0] };
+;
+;    void f(int *restrict A, int *restrict B) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = *B;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* noalias %A, i32* noalias %B) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb4, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb4 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb5
+
+bb2:                                              ; preds = %bb1
+  %tmp = load i32, i32* %B, align 4
+  %tmp3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp, i32* %tmp3, align 4
+  br label %bb4
+
+bb4:                                              ; preds = %bb2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb5:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_access_classes_different_base_type.ll b/final/test/ScopInfo/invariant_load_access_classes_different_base_type.ll
new file mode 100644
index 0000000..0937682
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_access_classes_different_base_type.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s --check-prefix=CODEGEN
+;
+;    struct {
+;      int a;
+;      float b;
+;    } S;
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1000; i++)
+;        A[i] = S.a + S.b;
+;    }
+;
+; CHECK:    Invariant Accesses: {
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_for_body[i0] -> MemRef_S[0] };
+; CHECK:            Execution Context: {  :  }
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_for_body[i0] -> MemRef_S[1] };
+; CHECK:            Execution Context: {  :  }
+; CHECK:    }
+;
+; CODEGEN:    %S.b.preload.s2a = alloca float
+; CODEGEN:    %S.a.preload.s2a = alloca i32
+;
+; CODEGEN:    %.load = load i32, i32* getelementptr inbounds (%struct.anon, %struct.anon* @S, i32 0, i32 0)
+; CODEGEN:    store i32 %.load, i32* %S.a.preload.s2a
+; CODEGEN:    %.load1 = load float, float* bitcast (i32* getelementptr (i32, i32* getelementptr inbounds (%struct.anon, %struct.anon* @S, i32 0, i32 0), i64 1) to float*)
+; CODEGEN:    store float %.load1, float* %S.b.preload.s2a
+;
+; CODEGEN:  polly.stmt.for.body:
+; CODEGEN:    %p_conv = sitofp i32 %.load to float
+; CODEGEN:    %p_add = fadd float %p_conv, %.load1
+; CODEGEN:    %p_conv1 = fptosi float %p_add to i32
+
+%struct.anon = type { i32, float }
+
+@S = common global %struct.anon zeroinitializer, align 4
+
+define void @f(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1000
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %S.a = load i32, i32* getelementptr inbounds (%struct.anon, %struct.anon* @S, i64 0, i32 0), align 4
+  %conv = sitofp i32 %S.a to float
+  %S.b = load float, float* getelementptr inbounds (%struct.anon, %struct.anon* @S, i64 0, i32 1), align 4
+  %add = fadd float %conv, %S.b
+  %conv1 = fptosi float %add to i32
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %conv1, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_access_classes_different_base_type_escaping.ll b/final/test/ScopInfo/invariant_load_access_classes_different_base_type_escaping.ll
new file mode 100644
index 0000000..19b6133
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_access_classes_different_base_type_escaping.ll
@@ -0,0 +1,94 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s --check-prefix=CODEGEN
+;
+;    struct {
+;      int a;
+;      float b;
+;    } S;
+;
+;    float f(int *A) {
+;      int x;
+;      float y;
+;      int i = 0;
+;      do {
+;        x = S.a;
+;        y = S.b;
+;        A[i] = x + y;
+;      } while (i++ < 1000);
+;      return x + y;
+;    }
+;
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_do_body[i0] -> MemRef_S[0] };
+; CHECK-NEXT:         Execution Context: {  :  }
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_do_body[i0] -> MemRef_S[1] };
+; CHECK-NEXT:         Execution Context: {  :  }
+; CHECK-NEXT: }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_do_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_do_body[i0] : 0 <= i0 <= 1000 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_do_body[i0] -> [i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_do_body[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+;
+; CODEGEN: entry:
+; CODEGEN:   %S.b.preload.s2a = alloca float
+; CODEGEN:   %S.a.preload.s2a = alloca i32
+;
+; CODEGEN: polly.preload.begin:
+; CODEGEN:   %.load = load i32, i32* getelementptr inbounds (%struct.anon, %struct.anon* @S, i32 0, i32 0)
+; CODEGEN:   store i32 %.load, i32* %S.a.preload.s2a
+; CODEGEN:   %.load1 = load float, float* bitcast (i32* getelementptr (i32, i32* getelementptr inbounds (%struct.anon, %struct.anon* @S, i32 0, i32 0), i64 1) to float*)
+; CODEGEN:   store float %.load1, float* %S.b.preload.s2a
+;
+; CODEGEN:     polly.merge_new_and_old:
+; CODEGEN-DAG:   %S.b.merge = phi float [ %S.b.final_reload, %polly.exiting ], [ %S.b, %do.cond ]
+; CODEGEN-DAG:   %S.a.merge = phi i32 [ %S.a.final_reload, %polly.exiting ], [ %S.a, %do.cond ]
+;
+; CODEGEN: do.end:
+; CODEGEN:   %conv3 = sitofp i32 %S.a.merge to float
+; CODEGEN:   %add4 = fadd float %conv3, %S.b.merge
+; CODEGEN:   ret float %add4
+;
+; CODEGEN: polly.loop_exit:
+; CODEGEN-DAG:   %S.b.final_reload = load float, float* %S.b.preload.s2a
+; CODEGEN-DAG:   %S.a.final_reload = load i32, i32* %S.a.preload.s2a
+
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.anon = type { i32, float }
+
+@S = common global %struct.anon zeroinitializer, align 4
+
+define float @f(i32* %A) {
+entry:
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %do.cond ], [ 0, %entry ]
+  %S.a = load i32, i32* getelementptr inbounds (%struct.anon, %struct.anon* @S, i64 0, i32 0), align 4
+  %S.b = load float, float* getelementptr inbounds (%struct.anon, %struct.anon* @S, i64 0, i32 1), align 4
+  %conv = sitofp i32 %S.a to float
+  %add = fadd float %conv, %S.b
+  %conv1 = fptosi float %add to i32
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %conv1, i32* %arrayidx, align 4
+  br label %do.cond
+
+do.cond:                                          ; preds = %do.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1001
+  br i1 %exitcond, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  %conv3 = sitofp i32 %S.a to float
+  %add4 = fadd float %conv3, %S.b
+  ret float %add4
+}
diff --git a/final/test/ScopInfo/invariant_load_access_classes_different_base_type_same_pointer.ll b/final/test/ScopInfo/invariant_load_access_classes_different_base_type_same_pointer.ll
new file mode 100644
index 0000000..67ea216
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_access_classes_different_base_type_same_pointer.ll
@@ -0,0 +1,78 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s --check-prefix=CODEGEN
+;
+;    int U;
+;    void f(int *A) {
+;      for (int i = 0; i < 1000; i++)
+;        A[i] = (*(int *)&U) + (int)(*(float *)&U);
+;    }
+;
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body[i0] -> MemRef_U[0] };
+; CHECK-NEXT:         Execution Context: {  :  }
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body[i0] -> MemRef_U[0] };
+; CHECK-NEXT:         Execution Context: {  :  }
+; CHECK-NEXT: }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_for_body[i0] : 0 <= i0 <= 999 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_for_body[i0] -> [i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+;
+; CODEGEN: entry:
+; CODEGEN-DAG:   %U.f.preload.s2a = alloca float
+; CODEGEN-DAG:   %U.i.preload.s2a = alloca i32
+; CODEGEN:   br label %polly.split_new_and_old
+;
+; CODEGEN: polly.preload.begin:
+; CODEGEN-DAG:   %U.load[[f:[.0-9]*]] = load float, float* bitcast (i32* @U to float*)
+; CODEGEN-DAG:   store float %U.load[[f]], float* %U.f.preload.s2a
+; CODEGEN-DAG:   %U.load[[i:[.0-9]*]] = load i32, i32* @U
+; CODEGEN-DAG:   store i32 %U.load[[i]], i32* %U.i.preload.s2a
+;
+; CODEGEN:     polly.merge_new_and_old:
+; CODEGEN-NOT:   merge = phi
+;
+; CODEGEN: polly.loop_exit:
+; CODEGEN-NOT:   final_reload
+;
+; CODEGEN: polly.stmt.for.body:
+; CODEGEN:   %p_add = add nsw i32 %U.load[[i]], %p_conv
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@U = common global i32 0, align 4
+
+define void @f(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1000
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %U.i = load i32, i32* @U, align 4
+  %U.cast = bitcast i32 *@U to float*
+  %U.f = load float, float* %U.cast, align 4
+  %conv = fptosi float %U.f to i32
+  %add = add nsw i32 %U.i, %conv
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_access_classes_different_base_type_same_pointer_escaping.ll b/final/test/ScopInfo/invariant_load_access_classes_different_base_type_same_pointer_escaping.ll
new file mode 100644
index 0000000..4361ce7
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_access_classes_different_base_type_same_pointer_escaping.ll
@@ -0,0 +1,84 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s --check-prefix=CODEGEN
+;
+;    int U;
+;    int f(int *A) {
+;      int i = 0, x, y;
+;      do {
+;        x = (*(int *)&U);
+;        y = (int)(*(float *)&U);
+;        A[i] = x + y;
+;      } while (i++ < 100);
+;      return x + y;
+;    }
+;
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_do_body[i0] -> MemRef_U[0] };
+; CHECK-NEXT:         Execution Context: {  :  }
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_do_body[i0] -> MemRef_U[0] };
+; CHECK-NEXT:         Execution Context: {  :  }
+; CHECK-NEXT: }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_do_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_do_body[i0] : 0 <= i0 <= 100 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_do_body[i0] -> [i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_do_body[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+;
+; CODEGEN: entry:
+; CODEGEN-DAG:   %U.f.preload.s2a = alloca float
+; CODEGEN-DAG:   %U.i.preload.s2a = alloca i32
+; CODEGEN:   br label %polly.split_new_and_old
+;
+; CODEGEN: polly.preload.begin:
+; CODEGEN-DAG:   %U.load[[f:[.0-9]*]] = load float, float* bitcast (i32* @U to float*)
+; CODEGEN-DAG:   store float %U.load[[f]], float* %U.f.preload.s2a
+; CODEGEN-DAG:   %U.load[[i:[.0-9]*]] = load i32, i32* @U
+; CODEGEN-DAG:   store i32 %U.load[[i]], i32* %U.i.preload.s2a
+;
+; CODEGEN:     polly.merge_new_and_old:
+; CODEGEN-DAG:   %U.f.merge = phi float [ %U.f.final_reload, %polly.exiting ], [ %U.f, %do.cond ]
+; CODEGEN-DAG:   %U.i.merge = phi i32 [ %U.i.final_reload, %polly.exiting ], [ %U.i, %do.cond ]
+;
+; CODEGEN: polly.loop_exit:
+; CODEGEN-DAG:   %U.f.final_reload = load float, float* %U.f.preload.s2a
+; CODEGEN-DAG:   %U.i.final_reload = load i32, i32* %U.i.preload.s2a
+;
+; CODEGEN: polly.stmt.do.body:
+; CODEGEN:   %p_add = add nsw i32 %U.load[[i]], %p_conv
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@U = common global i32 0, align 4
+
+define i32 @f(i32* %A) {
+entry:
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %do.cond ], [ 0, %entry ]
+  %U.i = load i32, i32* @U, align 4
+  %U.cast = bitcast i32 *@U to float*
+  %U.f = load float, float* %U.cast, align 4
+  %conv = fptosi float %U.f to i32
+  %add = add nsw i32 %U.i, %conv
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %add, i32* %arrayidx, align 4
+  br label %do.cond
+
+do.cond:                                          ; preds = %do.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 101
+  br i1 %exitcond, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  %conv2 = fptosi float %U.f to i32
+  %add2 = add nsw i32 %U.i, %conv2
+  ret i32 %add2
+}
diff --git a/final/test/ScopInfo/invariant_load_addrec_sum.ll b/final/test/ScopInfo/invariant_load_addrec_sum.ll
new file mode 100644
index 0000000..964f873
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_addrec_sum.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -polly-ignore-aliasing -polly-process-unprofitable -analyze < %s | FileCheck %s
+;
+; CHECK: Region: %entry.split---%if.end
+; CHECK:     Invariant Accesses: {
+; CHECK:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                 [y, p_1_loaded_from_j] -> { Stmt_for_body[i0] -> MemRef_j[0] };
+; CHECK:             Execution Context: [y, p_1_loaded_from_j] -> {  :  }
+; CHECK:     }
+
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [y, p_1_loaded_from_j] -> { Stmt_for_body5[i0] -> MemRef_p[p_1_loaded_from_j + i0] };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [y, p_1_loaded_from_j] -> { Stmt_for_body[i0] -> MemRef_p[p_1_loaded_from_j + i0] };
+
+
+define void @a(i32 %y, i32* nocapture %p, i32* nocapture readonly %j) local_unnamed_addr #0 {
+entry:
+  br label %entry.split
+
+entry.split:
+  %tobool = icmp eq i32 %y, 0
+  br i1 %tobool, label %for.body5, label %for.body
+
+for.body:
+  %i.024 = phi i32 [ %inc, %for.body ], [ 0, %entry.split ]
+  %0 = load i32, i32* %j, align 4
+  %add = add nsw i32 %0, %i.024
+  %idxprom = sext i32 %add to i64
+  %arrayidx = getelementptr inbounds i32, i32* %p, i64 %idxprom
+  store i32 %i.024, i32* %arrayidx, align 4
+  %inc = add nuw nsw i32 %i.024, 1
+  %exitcond26 = icmp eq i32 %inc, 10000
+  br i1 %exitcond26, label %if.end, label %for.body
+
+for.body5:
+  %i1.023 = phi i32 [ %inc10, %for.body5 ], [ 0, %entry.split ]
+  %mul = shl nsw i32 %i1.023, 1
+  %1 = load i32, i32* %j, align 4
+  %add6 = add nsw i32 %1, %i1.023
+  %idxprom7 = sext i32 %add6 to i64
+  %arrayidx8 = getelementptr inbounds i32, i32* %p, i64 %idxprom7
+  store i32 %mul, i32* %arrayidx8, align 4
+  %inc10 = add nuw nsw i32 %i1.023, 1
+  %exitcond = icmp eq i32 %inc10, 10000
+  br i1 %exitcond, label %if.end, label %for.body5
+
+if.end:
+  ret void
+}
+
diff --git a/final/test/ScopInfo/invariant_load_base_pointer.ll b/final/test/ScopInfo/invariant_load_base_pointer.ll
new file mode 100644
index 0000000..2de9038
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_base_pointer.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -polly-ignore-aliasing -polly-process-unprofitable -analyze < %s | FileCheck %s
+;
+; CHECK: Invariant Accesses:
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:   { Stmt_bb2[i0] -> MemRef_BPLoc[0] };
+;
+;    void f(int **BPLoc) {
+;      for (int i = 0; i < 1024; i++)
+;        (*BPLoc)[i] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32** %BPLoc) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb4, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb4 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb5
+
+bb2:                                              ; preds = %bb1
+  %tmp = load i32*, i32** %BPLoc, align 8
+  %tmp3 = getelementptr inbounds i32, i32* %tmp, i64 %indvars.iv
+  store i32 0, i32* %tmp3, align 4
+  br label %bb4
+
+bb4:                                              ; preds = %bb2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb5:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_base_pointer_conditional.ll b/final/test/ScopInfo/invariant_load_base_pointer_conditional.ll
new file mode 100644
index 0000000..cad0ec5
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_base_pointer_conditional.ll
@@ -0,0 +1,51 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -polly-ignore-aliasing -polly-process-unprofitable -analyze < %s | FileCheck %s
+;
+; CHECK: Invariant Accesses:
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:   [N] -> { Stmt_bb5[i0] -> MemRef_BPLoc[0] };
+;
+;    void f(int **BPLoc, int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        if (i > 512)
+;          (*BPLoc)[i] = 0;
+;        else
+;          A[i] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32** %BPLoc, i32* %A, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  br label %bb1
+
+bb1:                                              ; preds = %bb11, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb11 ], [ 0, %bb ]
+  %tmp2 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp2, label %bb3, label %bb12
+
+bb3:                                              ; preds = %bb1
+  %tmp4 = icmp sgt i64 %indvars.iv, 512
+  br i1 %tmp4, label %bb5, label %bb8
+
+bb5:                                              ; preds = %bb3
+  %tmp6 = load i32*, i32** %BPLoc, align 8
+  %tmp7 = getelementptr inbounds i32, i32* %tmp6, i64 %indvars.iv
+  store i32 0, i32* %tmp7, align 4
+  br label %bb10
+
+bb8:                                              ; preds = %bb3
+  %tmp9 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 0, i32* %tmp9, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb8, %bb5
+  br label %bb11
+
+bb11:                                             ; preds = %bb10
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb12:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_base_pointer_in_conditional.ll b/final/test/ScopInfo/invariant_load_base_pointer_in_conditional.ll
new file mode 100644
index 0000000..d4ca8b1
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_base_pointer_in_conditional.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -polly-ignore-aliasing -analyze < %s | FileCheck %s
+;
+; CHECK: Invariant Accesses:
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:   [N] -> { Stmt_bb5[i0] -> MemRef_BP[0] };
+; CHECK-NEXT:  Execution Context: [N] -> {  : N >= 514 }
+;
+;    void f(int *BP, int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        if (i > 512)
+;          A[i] = *BP;
+;        else
+;          A[i] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %BP, i32* %A, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  br label %bb1
+
+bb1:                                              ; preds = %bb11, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb11 ], [ 0, %bb ]
+  %tmp2 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp2, label %bb3, label %bb12
+
+bb3:                                              ; preds = %bb1
+  %tmp4 = icmp sgt i64 %indvars.iv, 512
+  br i1 %tmp4, label %bb5, label %bb8
+
+bb5:                                              ; preds = %bb3
+  %tmp9a = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %inv = load i32, i32 *%BP
+  store i32 %inv, i32* %tmp9a, align 4
+  br label %bb10
+
+bb8:                                              ; preds = %bb3
+  %tmp9b = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 0, i32* %tmp9b, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb8, %bb5
+  br label %bb11
+
+bb11:                                             ; preds = %bb10
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb12:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_branch_condition.ll b/final/test/ScopInfo/invariant_load_branch_condition.ll
new file mode 100644
index 0000000..7e0bbdf
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_branch_condition.ll
@@ -0,0 +1,51 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN:     -polly-invariant-load-hoisting < %s | FileCheck %s
+
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [val] -> { Stmt_next[] -> MemRef_ptr[0] };
+; CHECK-NEXT:         Execution Context: [val] -> {  :  }
+; CHECK-NEXT: }
+
+; CHECK: Statements {
+; CHECK-NEXT: 	Stmt_a
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [val] -> { Stmt_a[] : val = -1 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [val] -> { Stmt_a[] -> [1, 0] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [val] -> { Stmt_a[] -> MemRef_X[0] };
+; CHECK-NEXT: 	Stmt_loop
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [val] -> { Stmt_loop[i0] : val = 0 and 0 <= i0 <= 1025 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [val] -> { Stmt_loop[i0] -> [0, i0] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [val] -> { Stmt_loop[i0] -> MemRef_X[0] };
+; CHECK-NEXT: }
+
+define void @foo(i1* %ptr, float* %X) {
+entry:
+  br label %next
+
+next:
+  %val = load i1, i1* %ptr
+  br i1 %val, label %a, label %loop
+
+a:
+  store float 1.0, float* %X
+  br label %merge
+
+loop:
+  %indvar = phi i64 [0, %next], [%indvar.next, %loop]
+  store float 1.0, float* %X
+  %indvar.next = add nsw i64 %indvar, 1
+  %cmp = icmp sle i64 %indvar, 1024
+  br i1 %cmp, label %loop, label %merge
+
+merge:
+  br label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs.ll b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs.ll
new file mode 100644
index 0000000..c17d457
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s \
+; RUN:  -polly-invariant-load-hoisting \
+; RUN:  | FileCheck %s
+
+; CHECK:      Stmt_body1
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_body1[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_body1[i0] -> [i0, 0] };
+; CHECK-NEXT:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:          { Stmt_body1[i0] -> MemRef_baseB[0] };
+; CHECK-NEXT: Stmt_body2
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_body2[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_body2[i0] -> [i0, 1] };
+; CHECK-NEXT:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_body2[i0] -> MemRef_baseB[0] };
+
+define void @foo(float** %A) {
+start:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
+  %indvar.next = add nsw i64 %indvar, 1
+  %icmp = icmp slt i64 %indvar.next, 1024
+  br i1 %icmp, label %body1, label %exit
+
+body1:
+  %baseA = load float*, float** %A
+  store float 42.0, float* %baseA
+  br label %body2
+
+body2:
+  %baseB = load float*, float** %A
+  store float 42.0, float* %baseB
+  br label %latch
+
+latch:
+  br label %loop
+
+exit:
+  ret void
+
+}
diff --git a/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_2.ll b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_2.ll
new file mode 100644
index 0000000..70b5e78
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_2.ll
@@ -0,0 +1,91 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s \
+; RUN:  -polly-invariant-load-hoisting \
+; RUN:  | FileCheck %s
+
+; Make sure we choose a canonical element that is not the first invariant load,
+; but the first that is an array base pointer.
+
+; CHECK:     Statements {
+; CHECK-NEXT:     	Stmt_body0
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 { Stmt_body0[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 { Stmt_body0[i0] -> [i0, 0] };
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_body0[i0] -> MemRef_X[0] };
+; CHECK-NEXT:     	Stmt_body1
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 { Stmt_body1[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 { Stmt_body1[i0] -> [i0, 1] };
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_body1[i0] -> MemRef_baseB[0] };
+; CHECK-NEXT:     	Stmt_body2
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 { Stmt_body2[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 { Stmt_body2[i0] -> [i0, 2] };
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_body2[i0] -> MemRef_X[0] };
+; CHECK-NEXT:             ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body2[i0] -> MemRef_ptr[] };
+; CHECK-NEXT:     	Stmt_body3
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 { Stmt_body3[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 { Stmt_body3[i0] -> [i0, 3] };
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_body3[i0] -> MemRef_baseB[0] };
+; CHECK-NEXT:     	Stmt_body4
+; CHECK-NEXT:             Domain :=
+; CHECK-NEXT:                 { Stmt_body4[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:             Schedule :=
+; CHECK-NEXT:                 { Stmt_body4[i0] -> [i0, 4] };
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_body4[i0] -> MemRef_X[0] };
+; CHECK-NEXT:             ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_body4[i0] -> MemRef_ptr[] };
+; CHECK-NEXT:     }
+
+define void @foo(float** %A, float** %X) {
+start:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
+  %indvar.next = add nsw i64 %indvar, 1
+  %icmp = icmp slt i64 %indvar.next, 1024
+  br i1 %icmp, label %body0, label %exit
+
+body0:
+  %ptr = load float*, float** %A
+  store float* %ptr, float** %X
+  br label %body1
+
+body1:
+  %baseA = load float*, float** %A
+  store float 42.0, float* %baseA
+  br label %body2
+
+body2:
+  %ptr2 = load float*, float** %A
+  store float* %ptr, float** %X
+  br label %body3
+
+body3:
+  %baseB = load float*, float** %A
+  store float 42.0, float* %baseB
+  br label %body4
+
+body4:
+  %ptr3 = load float*, float** %A
+  store float* %ptr, float** %X
+  br label %latch
+
+latch:
+  br label %loop
+
+exit:
+  ret void
+
+}
diff --git a/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_3.ll b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_3.ll
new file mode 100644
index 0000000..f36657a
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_3.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s \
+; RUN:  -polly-invariant-load-hoisting \
+; RUN:  | FileCheck %s
+
+; Verify that we canonicalize accesses even tough one of the accesses (even
+; the canonical base) has a partial execution context. This is correct as
+; the combined execution context still coveres both accesses.
+
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_body2[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         Execution Context: {  :  }
+; CHECK-NEXT: }
+
+; CHECK:      Stmt_body1
+; CHECK-NEXT:   Domain :=
+; CHECK-NEXT:       { Stmt_body1[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:   Schedule :=
+; CHECK-NEXT:       { Stmt_body1[i0] -> [i0, 0] };
+; CHECK-NEXT:   MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       { Stmt_body1[i0] -> MemRef_baseB[0] };
+; CHECK-NEXT: Stmt_body2
+; CHECK-NEXT:   Domain :=
+; CHECK-NEXT:       { Stmt_body2[i0] : 0 <= i0 <= 510 };
+; CHECK-NEXT:   Schedule :=
+; CHECK-NEXT:       { Stmt_body2[i0] -> [i0, 1] };
+; CHECK-NEXT:   MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       { Stmt_body2[i0] -> MemRef_baseB[0] };
+
+
+define void @foo(float** %A) {
+start:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
+  %indvar.next = add nsw i64 %indvar, 1
+  %icmp = icmp slt i64 %indvar.next, 1024
+  br i1 %icmp, label %body1, label %exit
+
+body1:
+  %baseA = load float*, float** %A
+  store float 42.0, float* %baseA
+  %cmp = icmp slt i64 %indvar.next, 512
+  br i1 %cmp, label %body2, label %latch
+
+body2:
+  %baseB = load float*, float** %A
+  store float 42.0, float* %baseB
+  br label %latch
+
+latch:
+  br label %loop
+
+exit:
+  ret void
+
+}
diff --git a/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4.ll b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4.ll
new file mode 100644
index 0000000..3c1f2ef
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s \
+; RUN:  -polly-invariant-load-hoisting \
+; RUN:  | FileCheck %s
+
+; Verify that a delinearized and a not delinearized access are not
+; canonizalized.
+
+; CHECK:      Stmt_body1
+; CHECK-NEXT:   Domain :=
+; CHECK-NEXT:       [n] -> { Stmt_body1[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:   Schedule :=
+; CHECK-NEXT:       [n] -> { Stmt_body1[i0] -> [i0, 0] };
+; CHECK-NEXT:   MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       [n] -> { Stmt_body1[i0] -> MemRef_baseB[0] };
+; CHECK-NEXT: Stmt_body2
+; CHECK-NEXT:   Domain :=
+; CHECK-NEXT:       [n] -> { Stmt_body2[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:   Schedule :=
+; CHECK-NEXT:       [n] -> { Stmt_body2[i0] -> [i0, 1] };
+; CHECK-NEXT:   MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       [n] -> { Stmt_body2[i0] -> MemRef_baseA[i0, i0] };
+; CHECK-NEXT: }
+
+
+define void @foo(float** %A, i64 %n, i64 %m) {
+start:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
+  %indvar.next = add nsw i64 %indvar, 1
+  %icmp = icmp slt i64 %indvar.next, 1024
+  br i1 %icmp, label %body1, label %exit
+
+body1:
+  %baseB = load float*, float** %A
+  store float 42.0, float* %baseB
+  br label %body2
+
+body2:
+  %baseA = load float*, float** %A
+  %offsetA = mul i64 %indvar, %n
+  %offsetA2 = add i64 %offsetA, %indvar
+  %ptrA = getelementptr float, float* %baseA, i64 %offsetA2
+  store float 42.0, float* %ptrA
+  br label %latch
+
+latch:
+  br label %loop
+
+exit:
+  ret void
+
+}
diff --git a/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4b.ll b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4b.ll
new file mode 100644
index 0000000..b308298
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4b.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s \
+; RUN:  -polly-invariant-load-hoisting \
+; RUN:  | FileCheck %s
+
+; Verify that two arrays delinearized with different sizes are not coalesced.
+
+; CHECK:      Stmt_body1
+; CHECK-NEXT:     Domain :=
+; CHECK-NEXT:         [m, n] -> { Stmt_body1[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:     Schedule :=
+; CHECK-NEXT:         [m, n] -> { Stmt_body1[i0] -> [i0, 0] };
+; CHECK-NEXT:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:         [m, n] -> { Stmt_body1[i0] -> MemRef_baseB[i0, i0] };
+; CHECK-NEXT: Stmt_body2
+; CHECK-NEXT:     Domain :=
+; CHECK-NEXT:         [m, n] -> { Stmt_body2[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:     Schedule :=
+; CHECK-NEXT:         [m, n] -> { Stmt_body2[i0] -> [i0, 1] };
+; CHECK-NEXT:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:         [m, n] -> { Stmt_body2[i0] -> MemRef_baseA[i0, i0] };
+; CHECK-NEXT: }
+
+define void @foo(float** %A, i64 %n, i64 %m) {
+start:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
+  %indvar.next = add nsw i64 %indvar, 1
+  %icmp = icmp slt i64 %indvar.next, 1024
+  br i1 %icmp, label %body1, label %exit
+
+body1:
+  %baseB = load float*, float** %A
+  %offsetB = mul i64 %indvar, %m
+  %offsetB2 = add i64 %offsetB, %indvar
+  %ptrB = getelementptr float, float* %baseB, i64 %offsetB2
+  store float 42.0, float* %ptrB
+  br label %body2
+
+body2:
+  %baseA = load float*, float** %A
+  %offsetA = mul i64 %indvar, %n
+  %offsetA2 = add i64 %offsetA, %indvar
+  %ptrA = getelementptr float, float* %baseA, i64 %offsetA2
+  store float 42.0, float* %ptrA
+  br label %latch
+
+latch:
+  br label %loop
+
+exit:
+  ret void
+
+}
diff --git a/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4c.ll b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4c.ll
new file mode 100644
index 0000000..6f71ff0
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_4c.ll
@@ -0,0 +1,51 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s \
+; RUN:  -polly-invariant-load-hoisting \
+; RUN:  | FileCheck %s
+
+; Verify that arrays with different element types are not coalesced.
+
+; CHECK:      Statements {
+; CHECK-NEXT: 	Stmt_body1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_body1[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_body1[i0] -> [i0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_body1[i0] -> MemRef_baseB[0] };
+; CHECK-NEXT: 	Stmt_body2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_body2[i0] : 0 <= i0 <= 1022 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_body2[i0] -> [i0, 1] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_body2[i0] -> MemRef_baseA[0] };
+; CHECK-NEXT: }
+
+define void @foo(float** %A, i64 %n, i64 %m) {
+start:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %start], [%indvar.next, %latch]
+  %indvar.next = add nsw i64 %indvar, 1
+  %icmp = icmp slt i64 %indvar.next, 1024
+  br i1 %icmp, label %body1, label %exit
+
+body1:
+  %baseB = load float*, float** %A
+  store float 42.0, float* %baseB
+  br label %body2
+
+body2:
+  %baseA = load float*, float** %A
+  %ptrcast = bitcast float* %baseA to i64*
+  store i64 42, i64* %ptrcast
+  br label %latch
+
+latch:
+  br label %loop
+
+exit:
+  ret void
+
+}
diff --git a/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_5.ll b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_5.ll
new file mode 100644
index 0000000..2927f37
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_canonicalize_array_baseptrs_5.ll
@@ -0,0 +1,78 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s \
+; RUN:  -polly-invariant-load-hoisting \
+; RUN:  | FileCheck %s
+
+; Verify that nested arrays with invariant base pointers are handled correctly.
+; Specifically, we currently do not canonicalize arrays where some accesses are
+; hoisted as invariant loads. If we would, we need to update the access function
+; of the invariant loads as well. However, as this is not a very common
+; situation, we leave this for now to avoid further complexity increases.
+;
+; In this test case the arrays baseA1 and baseA2 could be canonicalized to a
+; single array, but there is also an invariant access to baseA1[0] through
+; "%v0 = load float, float* %ptr" which prevents the canonicalization.
+
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_body2[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         Execution Context: {  :  }
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_body1[i0] -> MemRef_baseA1[0] };
+; CHECK-NEXT:         Execution Context: {  :  }
+; CHECK-NEXT: }
+
+; CHECK:      Statements {
+; CHECK-NEXT: 	Stmt_body1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_body1[i0] : 0 <= i0 <= 1021 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_body1[i0] -> [i0, 0] };
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_body1[i0] -> MemRef_baseA1[1 + i0] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_body1[i0] -> MemRef_B[0] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_body1[i0] -> MemRef_B[0] };
+; CHECK-NEXT: 	Stmt_body2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_body2[i0] : 0 <= i0 <= 1021 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_body2[i0] -> [i0, 1] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_body2[i0] -> MemRef_baseA2[0] };
+; CHECK-NEXT: }
+
+define void @foo(float** %A, float* %B) {
+start:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [1, %start], [%indvar.next, %latch]
+  %indvar.next = add nsw i64 %indvar, 1
+  %icmp = icmp slt i64 %indvar.next, 1024
+  br i1 %icmp, label %body1, label %exit
+
+body1:
+  %baseA1 = load float*, float** %A
+  %ptr = getelementptr inbounds float, float* %baseA1, i64 %indvar
+  %v0 = load float, float* %ptr
+  %v1 = load float, float* %baseA1
+  store float %v0, float* %B
+  store float %v1, float* %B
+  br label %body2
+
+body2:
+  %baseA2 = load float*, float** %A
+  store float undef, float* %baseA2
+  br label %body3
+
+body3:
+  br label %latch
+
+latch:
+  br label %loop
+
+exit:
+  ret void
+
+}
diff --git a/final/test/ScopInfo/invariant_load_complex_condition.ll b/final/test/ScopInfo/invariant_load_complex_condition.ll
new file mode 100644
index 0000000..f545656
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_complex_condition.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -S -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.IP = type { i32****, i32***, %struct.P, %struct.S, %struct.m }
+%struct.P = type { i32 }
+%struct.S = type { i32 }
+%struct.D = type { i32 }
+%struct.B = type { i32 }
+%struct.E = type { i32 }
+%struct.s = type { i32 }
+%struct.M = type { i32 }
+%struct.C = type { i32 }
+%struct.T = type { i32 }
+%struct.R = type { i32 }
+%struct.m = type { i32 }
+%struct.d = type { i32 }
+
+
+; Verify that we do not invariant load hoist very complex conditions.
+
+; CHECK:      Statements {
+; CHECK-NEXT: 	Stmt_entry_split
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [block_y, block_x] -> { Stmt_entry_split[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [block_y, block_x] -> { Stmt_entry_split[] -> [] };
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [block_y, block_x] -> { Stmt_entry_split[] -> MemRef4[o0] : (-3 <= block_y < 0 and block_x <= -4 and -8 + block_x - 4o0 <= 8*floor((-1 + block_x)/8) <= -5 + block_x - 4o0) or (-3 <= block_y < 0 and block_x >= 0 and -3 + block_x - 4o0 <= 8*floor((block_x)/8) <= block_x - 4o0) or (block_y <= -4 and block_x <= -4 and -16 + block_x - 4o0 - 8*floor((-1 + block_x)/8) + 8*floor((-1 + block_y)/4) <= 16*floor((-1 + block_y)/8) <= -13 + block_x - 4o0 - 8*floor((-1 + block_x)/8) + 8*floor((-1 + block_y)/4)) or (block_y <= -4 and block_x >= 0 and -11 + block_x - 4o0 - 8*floor((block_x)/8) + 8*floor((-1 + block_y)/4) <= 16*floor((-1 + block_y)/8) <= -8 + block_x - 4o0 - 8*floor((block_x)/8) + 8*floor((-1 + block_y)/4)) or (block_y >= 0 and block_x <= -4 and -8 + block_x - 4o0 - 8*floor((-1 + block_x)/8) + 8*floor((block_y)/4) <= 16*floor((block_y)/8) <= -5 + block_x - 4o0 - 8*floor((-1 + block_x)/8) + 8*floor((block_y)/4)) or (block_y >= 0 and block_x >= 0 and -3 + block_x - 4o0 - 8*floor((block_x)/8) + 8*floor((block_y)/4) <= 16*floor((block_y)/8) <= block_x - 4o0 - 8*floor((block_x)/8) + 8*floor((block_y)/4)) or (4*floor((block_y)/8) = -o0 + 2*floor((block_y)/4) and block_y >= 0 and -3 <= block_x < 0 and 4*floor((block_y)/4) >= -7 + block_y + 2o0 and 4*floor((block_y)/4) <= block_y + 2o0) or (4*floor((-1 + block_y)/8) = -2 - o0 + 2*floor((-1 + block_y)/4) and block_y <= -4 and -3 <= block_x < 0 and 4*floor((-1 + block_y)/4) >= -4 + block_y + 2o0 and 4*floor((-1 + block_y)/4) <= 3 + block_y + 2o0); Stmt_entry_split[] -> MemRef4[0] : -3 <= block_y < 0 and -3 <= block_x < 0 };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [block_y, block_x] -> { Stmt_entry_split[] -> MemRef0[] };
+; CHECK-NEXT: }
+
+@img = external global %struct.IP*, align 8
+
+; Function Attrs: nounwind uwtable
+define void @dct_luma(i32 %block_x, i32 %block_y) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %div = sdiv i32 %block_x, 4
+  %div1 = sdiv i32 %block_y, 4
+  %rem = srem i32 %div1, 2
+  %mul4 = shl nsw i32 %rem, 1
+  %rem5 = srem i32 %div, 2
+  %add6 = add nsw i32 %mul4, %rem5
+  %idxprom = sext i32 %add6 to i64
+  %0 = load %struct.IP*, %struct.IP** @img, align 8
+  %cofAC = getelementptr inbounds %struct.IP, %struct.IP* %0, i32 0, i32 0
+  %1 = load i32****, i32***** %cofAC, align 8
+  %arrayidx = getelementptr inbounds i32***, i32**** %1, i64 0
+  %2 = load i32***, i32**** %arrayidx, align 8
+  %arrayidx8 = getelementptr inbounds i32**, i32*** %2, i64 %idxprom
+  %3 = load i32**, i32*** %arrayidx8, align 8
+  %mb_data = getelementptr inbounds %struct.IP, %struct.IP* %0, i64 0, i32 4
+  %4 = load %struct.m, %struct.m* %mb_data, align 8
+  br i1 false, label %land.rhs, label %land.end
+
+land.rhs:                                         ; preds = %entry.split
+  br label %land.end
+
+land.end:                                         ; preds = %land.rhs, %entry.split
+  %5 = phi i1 [ false, %entry.split ], [ undef, %land.rhs ]
+  br i1 %5, label %for.cond104.preheader, label %for.cond34.preheader
+
+for.cond34.preheader:                             ; preds = %land.end
+  ret void
+
+for.cond104.preheader:                            ; preds = %land.end
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_condition.ll b/final/test/ScopInfo/invariant_load_condition.ll
new file mode 100644
index 0000000..092839a
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_condition.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-process-unprofitable -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; CHECK: Invariant Accesses:
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:  { Stmt_bb2[i0] -> MemRef_C[0] };
+;
+;    void f(int *A, int *C) {
+;      for (int i = 0; i < 1024; i++)
+;        if (*C)
+;          A[i] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %C) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb7, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb7 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = load i32, i32* %C, align 4
+  %tmp3 = icmp eq i32 %tmp, 0
+  br i1 %tmp3, label %bb6, label %bb4
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 0, i32* %tmp5, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2, %bb4
+  br label %bb7
+
+bb7:                                              ; preds = %bb6
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_dereferenceable.ll b/final/test/ScopInfo/invariant_load_dereferenceable.ll
new file mode 100644
index 0000000..420bbfe
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_dereferenceable.ll
@@ -0,0 +1,112 @@
+; RUN: opt %loadPolly -polly-detect -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN: -analyze < %s | FileCheck %s
+
+; CHECK-NOT: Function: foo_undereferanceable
+
+; CHECK:       Function: foo_dereferanceable
+
+; CHECK:       Invariant Accesses: {
+; CHECK-NEXT:               ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                   [sizeA] -> { Stmt_for_body_j__TO__for_latch_j[i0, i1] -> MemRef_sizeA_ptr[0] };
+; CHECK-NEXT:               Execution Context: [sizeA] -> {  :  }
+; CHECK-NEXT:       }
+
+; CHECK:            MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:               [sizeA] -> { Stmt_for_body_j__TO__for_latch_j[i0, i1] -> MemRef_A[i1, i0] };
+
+; CHECK-NOT: Function: foo_undereferanceable
+
+define void @foo_dereferanceable(double* %A, double* %B, i64* dereferenceable(8) %sizeA_ptr,
+		i32 %lb.i, i32 %lb.j, i32 %ub.i, i32 %ub.j) {
+entry:
+	br label %for.i
+
+for.i:
+	%indvar.i = phi i32 [0, %entry], [%indvar.next.i, %for.latch.i]
+	%indvar.next.i = add i32 %indvar.i, 1
+	%cmp.i = icmp sle i32 %indvar.i, 1024
+	br i1 %cmp.i, label %for.body.i, label %exit
+
+for.body.i:
+	br label %for.j
+
+for.j:
+	%indvar.j = phi i32 [0, %for.body.i], [%indvar.next.j, %for.latch.j]
+	%indvar.next.j = add i32 %indvar.j, 1
+	%cmp.j = icmp sle i32 %indvar.j, 1024
+	br i1 %cmp.j, label %for.body.j, label %for.latch.i
+
+for.body.j:
+	%prod = mul i32 %indvar.j, %indvar.j
+	%cmp = icmp sle i32 %prod, 1024
+	br i1 %cmp, label %stmt, label %for.latch.j
+
+stmt:
+	%sext.i = sext i32 %indvar.i to i64
+	%sext.j = sext i32 %indvar.j to i64
+
+	%sizeA = load i64, i64* %sizeA_ptr
+	%prodA = mul i64 %sext.j, %sizeA
+	%offsetA = add i64 %sext.i, %prodA
+	%ptrA = getelementptr double, double* %A, i64 %offsetA
+	store double 42.0, double* %ptrA
+
+	br label %for.latch.j
+
+for.latch.j:
+	br label %for.j
+
+for.latch.i:
+	br label %for.i
+
+exit:
+	ret void
+}
+
+define void @foo_undereferanceable(double* %A, double* %B, i64* %sizeA_ptr) {
+entry:
+	br label %for.i
+
+for.i:
+	%indvar.i = phi i32 [0, %entry], [%indvar.next.i, %for.latch.i]
+	%indvar.next.i = add i32 %indvar.i, 1
+	%cmp.i = icmp sle i32 %indvar.i, 1024
+	br i1 %cmp.i, label %for.body.i, label %exit
+
+for.body.i:
+	br label %for.j
+
+for.j:
+	%indvar.j = phi i32 [0, %for.body.i], [%indvar.next.j, %for.latch.j]
+	%indvar.next.j = add i32 %indvar.j, 1
+	%cmp.j = icmp sle i32 %indvar.j, 1024
+	br i1 %cmp.j, label %for.body.j, label %for.latch.i
+
+for.body.j:
+	%prod = mul i32 %indvar.j, %indvar.j
+	%cmp = icmp sle i32 %prod, 1024
+	br i1 %cmp, label %stmt, label %for.latch.j
+
+stmt:
+	%sext.i = sext i32 %indvar.i to i64
+	%sext.j = sext i32 %indvar.j to i64
+
+	%sizeA = load i64, i64* %sizeA_ptr
+	%prodA = mul i64 %sext.j, %sizeA
+	%offsetA = add i64 %sext.i, %prodA
+	%ptrA = getelementptr double, double* %A, i64 %offsetA
+	store double 42.0, double* %ptrA
+
+	br label %for.latch.j
+
+for.latch.j:
+	br label %for.j
+
+for.latch.i:
+	br label %for.i
+
+exit:
+	ret void
+}
+
diff --git a/final/test/ScopInfo/invariant_load_distinct_parameter_valuations.ll b/final/test/ScopInfo/invariant_load_distinct_parameter_valuations.ll
new file mode 100644
index 0000000..c80bf19
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_distinct_parameter_valuations.ll
@@ -0,0 +1,114 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; Check that we do not consolidate the invariant loads to smp[order - 1] and
+; smp[order - 2] in the blocks %0 and %16. While they have the same pointer
+; operand (SCEV) they do not have the same access relation due to the
+; instantiation of "order" from their domain.
+;
+; CHECK:         Invariant Accesses: {
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [order, n] -> { Stmt_bb1[] -> MemRef_smp[1] };
+; CHECK-NEXT:            Execution Context: [order, n] -> {  : order = 2 }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [order, n] -> { Stmt_bb1[] -> MemRef_smp[0] };
+; CHECK-NEXT:            Execution Context: [order, n] -> {  : order = 2 }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [order, n] -> { Stmt_bb16[] -> MemRef_smp[2] };
+; CHECK-NEXT:            Execution Context: [order, n] -> {  : order = 3 }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [order, n] -> { Stmt_bb16[] -> MemRef_smp[1] };
+; CHECK-NEXT:            Execution Context: [order, n] -> {  : order = 3 }
+; CHECK-NEXT:    }
+;
+; ModuleID = '/home/johannes/Downloads/test_case.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @encode_residual_fixed(i32* %res, i32* %smp, i32 %n, i32 %order) {
+bb:
+  br label %.split
+
+.split:                                           ; preds = %bb
+  switch i32 %order, label %bb32 [
+    i32 2, label %bb1
+    i32 3, label %bb16
+  ]
+
+bb1:                                              ; preds = %.split
+  %tmp = add nsw i32 %order, -1
+  %tmp2 = sext i32 %tmp to i64
+  %tmp3 = getelementptr inbounds i32, i32* %smp, i64 %tmp2
+  %tmp4 = load i32, i32* %tmp3, align 4
+  %tmp5 = add nsw i32 %order, -2
+  %tmp6 = sext i32 %tmp5 to i64
+  %tmp7 = getelementptr inbounds i32, i32* %smp, i64 %tmp6
+  %tmp8 = load i32, i32* %tmp7, align 4
+  %tmp9 = sub nsw i32 %tmp4, %tmp8
+  %tmp10 = icmp slt i32 %order, %n
+  br i1 %tmp10, label %.lr.ph, label %.loopexit
+
+.lr.ph:                                           ; preds = %bb1
+  %tmp11 = sext i32 %order to i64
+  br label %bb12
+
+bb12:                                             ; preds = %bb12, %.lr.ph
+  %indvars.iv = phi i64 [ %tmp11, %.lr.ph ], [ %indvars.iv.next, %bb12 ]
+  %i.03 = phi i32 [ %order, %.lr.ph ], [ %tmp14, %bb12 ]
+  %tmp13 = getelementptr inbounds i32, i32* %res, i64 %indvars.iv
+  store i32 %tmp9, i32* %tmp13, align 4
+  %tmp14 = add nsw i32 %i.03, 2
+  %tmp15 = icmp slt i32 %tmp14, %n
+  %indvars.iv.next = add nsw i64 %indvars.iv, 2
+  br i1 %tmp15, label %bb12, label %..loopexit_crit_edge
+
+bb16:                                             ; preds = %.split
+  %tmp17 = add nsw i32 %order, -1
+  %tmp18 = sext i32 %tmp17 to i64
+  %tmp19 = getelementptr inbounds i32, i32* %smp, i64 %tmp18
+  %tmp20 = load i32, i32* %tmp19, align 4
+  %tmp21 = add nsw i32 %order, -2
+  %tmp22 = sext i32 %tmp21 to i64
+  %tmp23 = getelementptr inbounds i32, i32* %smp, i64 %tmp22
+  %tmp24 = load i32, i32* %tmp23, align 4
+  %tmp25 = sub nsw i32 %tmp20, %tmp24
+  %tmp26 = icmp slt i32 %order, %n
+  br i1 %tmp26, label %.lr.ph5, label %.loopexit2
+
+.lr.ph5:                                          ; preds = %bb16
+  %tmp27 = sext i32 %order to i64
+  br label %bb28
+
+bb28:                                             ; preds = %bb28, %.lr.ph5
+  %indvars.iv6 = phi i64 [ %tmp27, %.lr.ph5 ], [ %indvars.iv.next7, %bb28 ]
+  %i.14 = phi i32 [ %order, %.lr.ph5 ], [ %tmp30, %bb28 ]
+  %tmp29 = getelementptr inbounds i32, i32* %res, i64 %indvars.iv6
+  store i32 %tmp25, i32* %tmp29, align 4
+  %tmp30 = add nsw i32 %i.14, 2
+  %tmp31 = icmp slt i32 %tmp30, %n
+  %indvars.iv.next7 = add nsw i64 %indvars.iv6, 2
+  br i1 %tmp31, label %bb28, label %..loopexit2_crit_edge
+
+..loopexit_crit_edge:                             ; preds = %bb12
+  br label %.loopexit
+
+.loopexit:                                        ; preds = %..loopexit_crit_edge, %bb1
+  br label %bb32
+
+..loopexit2_crit_edge:                            ; preds = %bb28
+  br label %.loopexit2
+
+.loopexit2:                                       ; preds = %..loopexit2_crit_edge, %bb16
+  br label %bb32
+
+bb32:                                             ; preds = %.loopexit2, %.loopexit, %.split
+  %tmp33 = getelementptr inbounds i32, i32* %res, i64 2
+  %tmp34 = load i32, i32* %tmp33, align 4
+  %tmp35 = icmp eq i32 %tmp34, 5
+  br i1 %tmp35, label %bb37, label %bb36
+
+bb36:                                             ; preds = %bb32
+  ret void
+
+bb37:                                             ; preds = %bb32
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_in_non_affine.ll b/final/test/ScopInfo/invariant_load_in_non_affine.ll
new file mode 100644
index 0000000..59cb265
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_in_non_affine.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -polly-detect -analyze \
+; RUN:   -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+; CHECK-NOT: Valid Region for Scop
+;
+;    void foo(float A[], float B[], long *p) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          if (B[i])
+;            A[i * (*p) + j] += i * j;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A, float* %B, i64* %p) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb21, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp22, %bb21 ]
+  %exitcond1 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond1, label %bb3, label %bb23
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb18, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp19, %bb18 ]
+  %exitcond = icmp ne i64 %j.0, 1024
+  br i1 %exitcond, label %bb5, label %bb20
+
+bb5:                                              ; preds = %bb4
+  %tmp = getelementptr inbounds float, float* %B, i64 %i.0
+  %tmp6 = load float, float* %tmp, align 4
+  %tmp7 = fcmp une float %tmp6, 0.000000e+00
+  br i1 %tmp7, label %bb8, label %bb17
+
+bb8:                                              ; preds = %bb5
+  %tmp9 = mul nuw nsw i64 %i.0, %j.0
+  %tmp10 = sitofp i64 %tmp9 to float
+  %tmp11 = load i64, i64* %p, align 8
+  %tmp12 = mul nsw i64 %i.0, %tmp11
+  %tmp13 = add nsw i64 %tmp12, %j.0
+  %tmp14 = getelementptr inbounds float, float* %A, i64 %tmp13
+  %tmp15 = load float, float* %tmp14, align 4
+  %tmp16 = fadd float %tmp15, %tmp10
+  store float %tmp16, float* %tmp14, align 4
+  br label %bb17
+
+bb17:                                             ; preds = %bb8, %bb5
+  br label %bb18
+
+bb18:                                             ; preds = %bb17
+  %tmp19 = add nuw nsw i64 %j.0, 1
+  br label %bb4
+
+bb20:                                             ; preds = %bb4
+  br label %bb21
+
+bb21:                                             ; preds = %bb20
+  %tmp22 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb23:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_loop_ub.ll b/final/test/ScopInfo/invariant_load_loop_ub.ll
new file mode 100644
index 0000000..9236c32
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_loop_ub.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -polly-process-unprofitable -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-function-scops -polly-invariant-load-hoisting=true -polly-process-unprofitable -analyze < %s | FileCheck %s
+;
+; CHECK: Invariant Accesses:
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:   { Stmt_bb1[i0] -> MemRef_UB[0] };
+;
+;    void f(int *A, int *UB) {
+;      for (int i = 0; i < *UB; i++)
+;        A[i] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %UB) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb6 ], [ 0, %bb ]
+  %tmp = load i32, i32* %UB, align 4
+  %tmp2 = sext i32 %tmp to i64
+  %tmp3 = icmp slt i64 %indvars.iv, %tmp2
+  br i1 %tmp3, label %bb4, label %bb7
+
+bb4:                                              ; preds = %bb1
+  %tmp5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 0, i32* %tmp5, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb7:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_ptr_ptr_noalias.ll b/final/test/ScopInfo/invariant_load_ptr_ptr_noalias.ll
new file mode 100644
index 0000000..7eb1f9b
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_ptr_ptr_noalias.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -tbaa -polly-scops -polly-invariant-load-hoisting=true -polly-ignore-aliasing \
+; RUN:                -analyze < %s | FileCheck %s
+;
+; Note: The order of the invariant accesses is important because A is the
+;       base pointer of tmp3 and we will generate code in the same order as
+;       the invariant accesses are listed here.
+;
+; CHECK: Invariant Accesses: {
+; CHECK:    ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:         MemRef_A[42]
+; CHECK:    ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:         MemRef_tmp3[32]
+; CHECK: }
+;
+; CHECK: Arrays {
+; CHECK:   i32** MemRef_A[*];
+; CHECK:   i32* MemRef_tmp3[*]; [BasePtrOrigin: MemRef_A]
+; CHECK:   i32 MemRef_tmp5[*]; [BasePtrOrigin: MemRef_tmp3]
+; CHECK: }
+;
+; CHECK: Arrays (Bounds as pw_affs) {
+; CHECK:   i32** MemRef_A[*];
+; CHECK:   i32* MemRef_tmp3[*]; [BasePtrOrigin: MemRef_A]
+; CHECK:   i32 MemRef_tmp5[*]; [BasePtrOrigin: MemRef_tmp3]
+; CHECK: }
+;
+;    void f(int ***A) {
+;      for (int i = 0; i < 1024; i++)
+;        A[42][32][i] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32*** %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb7, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb7 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i32**, i32*** %A, i64 42
+  %tmp3 = load i32**, i32*** %tmp, align 8
+  %tmp4 = getelementptr inbounds i32*, i32** %tmp3, i64 32
+  %tmp5 = load i32*, i32** %tmp4, align 8
+  %tmp6 = getelementptr inbounds i32, i32* %tmp5, i64 %indvars.iv
+  store i32 0, i32* %tmp6, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_scalar_dep.ll b/final/test/ScopInfo/invariant_load_scalar_dep.ll
new file mode 100644
index 0000000..3d0f723
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_scalar_dep.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-process-unprofitable -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; CHECK: Invariant Accesses:
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:   { Stmt_bb2[i0] -> MemRef_B[0] };
+; CHECK-NOT:  MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NOT:   { Stmt_bb2[i0] -> MemRef_tmp[] };
+;
+;    void f(int *restrict A, int *restrict B) {
+;      for (int i = 0; i < 1024; i++)
+;        auto tmp = *B;
+;        // Split BB
+;        A[i] = tmp;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* noalias %A, i32* noalias %B) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb4, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb4 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb5
+
+bb2:                                              ; preds = %bb1
+  %tmp = load i32, i32* %B, align 4
+  br label %bb2b
+
+bb2b:
+  %tmp3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp, i32* %tmp3, align 4
+  br label %bb4
+
+bb4:                                              ; preds = %bb2
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb5:                                              ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_stmt_domain.ll b/final/test/ScopInfo/invariant_load_stmt_domain.ll
new file mode 100644
index 0000000..e6722f1
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_stmt_domain.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+
+; This test case verifies that the statement domain of the invariant access
+; is the universe. In earlier versions of Polly, we accidentally computed an
+; empty access domain which resulted in invariant accesses not being executed
+; and consequently undef values being used.
+
+; CHECK:  Invariant Accesses: {
+; CHECK-NEXT:          ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              { Stmt_loop_next[i0] -> MemRef_a[1] };
+; CHECK-NEXT:          Execution Context: {  :  }
+; CHECK-NEXT:  }
+; CHECK-NEXT:  Context:
+; CHECK-NEXT:  {  :  }
+; CHECK-NEXT:  Assumed Context:
+; CHECK-NEXT:  {  :  }
+; CHECK-NEXT:  Invalid Context:
+; CHECK-NEXT:  {  : 1 = 0 }
+
+; CHECK:  Statements {
+; CHECK-NEXT:    Stmt_loop
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              { Stmt_loop[i0] : 0 <= i0 <= 1 };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              { Stmt_loop[i0] -> [i0, 0] };
+; CHECK-NEXT:          ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_loop[i0] -> MemRef_val__phi[] };
+; CHECK-NEXT:          MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              { Stmt_loop[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:    Stmt_loop_next
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              { Stmt_loop_next[0] };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              { Stmt_loop_next[i0] -> [0, 1] };
+; CHECK-NEXT:          MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_loop_next[i0] -> MemRef_val__phi[] };
+; CHECK-NEXT:  }
+
+define void @foo(float* %a, float* noalias %B) {
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %entry], [%indvar.next, %loop.next]
+  %val = phi float [1.0, %entry], [%a.val, %loop.next]
+  %indvar.next = add nuw nsw i64 %indvar, 1
+  %ptr = getelementptr float, float* %B, i64 %indvar
+  store float %val, float* %ptr
+  %icmp = icmp eq i64 %indvar.next, 2
+  br i1 %icmp, label %ret, label %loop.next
+
+loop.next:
+  %Aptr = getelementptr float, float* %a, i64 %indvar.next
+  %a.val = load float, float* %Aptr
+  br label %loop
+
+ret:
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_zext_parameter-2.ll b/final/test/ScopInfo/invariant_load_zext_parameter-2.ll
new file mode 100644
index 0000000..396828e
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_zext_parameter-2.ll
@@ -0,0 +1,112 @@
+; RUN: opt %loadPolly -scalar-evolution-max-value-compare-depth=3 -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -scalar-evolution-max-value-compare-depth=3 -polly-codegen -polly-invariant-load-hoisting=true -analyze < %s
+;
+; Stress test for the code generation of invariant accesses.
+;
+;    void f(int *I0, int *I1, int *I2, int *V, long p0, long p1, long p2, long p3) {
+;      *V = *I1;
+;      for (int i = 0; i < 1000; i++) {
+;        long n0 = p0 * *I1 + p1 * *I1;
+;        V[i] = I0[n0];
+;        long m0 = p0 * (I2[0]);
+;        long m1 = p1 * (I2[1]);
+;        long m2 = p2 * (I2[2]);
+;        long m3 = p3 * (I2[3]);
+;        int j = 0;
+;        do {
+;          if (j > 0) {
+;            V[i] += I1[m0 + m2];
+;            V[i] += I1[n0];
+;          }
+;        } while (j++ < m1 + m3 * n0);
+;      }
+;    }
+;
+; CHECK: p0: ((sext i32 %tmp6 to i64) * %p1)
+; CHECK: p1: ((sext i32 %tmp3 to i64) * (sext i32 %tmp8 to i64) * (%p0 + %p1) * %p3)
+; CHECK: p2: ((sext i32 %tmp3 to i64) * (%p0 + %p1))
+; CHECK: p3: ((sext i32 %tmp5 to i64) * %p0)
+; CHECK: p4: ((sext i32 %tmp7 to i64) * %p2)
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %I0, i32* %I1, i32* %I2, i32* %V, i64 %p0, i64 %p1, i64 %p2, i64 %p3) {
+entry:
+  %tmp = load i32, i32* %I1, align 4
+  store i32 %tmp, i32* %V, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv1, 1000
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp3 = load i32, i32* %I1, align 4
+  %conv = sext i32 %tmp3 to i64
+  %mul = mul nsw i64 %conv, %p0
+  %conv1 = sext i32 %tmp3 to i64
+  %mul2 = mul nsw i64 %conv1, %p1
+  %add = add nsw i64 %mul, %mul2
+  %arrayidx = getelementptr inbounds i32, i32* %I0, i64 %add
+  %tmp4 = load i32, i32* %arrayidx, align 4
+  %arrayidx3 = getelementptr inbounds i32, i32* %V, i64 %indvars.iv1
+  store i32 %tmp4, i32* %arrayidx3, align 4
+  %tmp5 = load i32, i32* %I2, align 4
+  %conv5 = sext i32 %tmp5 to i64
+  %mul6 = mul nsw i64 %conv5, %p0
+  %arrayidx7 = getelementptr inbounds i32, i32* %I2, i64 1
+  %tmp6 = load i32, i32* %arrayidx7, align 4
+  %conv8 = sext i32 %tmp6 to i64
+  %mul9 = mul nsw i64 %conv8, %p1
+  %arrayidx10 = getelementptr inbounds i32, i32* %I2, i64 2
+  %tmp7 = load i32, i32* %arrayidx10, align 4
+  %conv11 = sext i32 %tmp7 to i64
+  %mul12 = mul nsw i64 %conv11, %p2
+  %arrayidx13 = getelementptr inbounds i32, i32* %I2, i64 3
+  %tmp8 = load i32, i32* %arrayidx13, align 4
+  %conv14 = sext i32 %tmp8 to i64
+  %mul15 = mul nsw i64 %conv14, %p3
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond, %for.body
+  %indvars.iv = phi i64 [ %indvars.iv.next, %do.cond ], [ 0, %for.body ]
+  %cmp16 = icmp sgt i64 %indvars.iv, 0
+  br i1 %cmp16, label %if.then, label %if.end
+
+if.then:                                          ; preds = %do.body
+  %add18 = add nsw i64 %mul6, %mul12
+  %arrayidx19 = getelementptr inbounds i32, i32* %I1, i64 %add18
+  %tmp9 = load i32, i32* %arrayidx19, align 4
+  %arrayidx21 = getelementptr inbounds i32, i32* %V, i64 %indvars.iv1
+  %tmp10 = load i32, i32* %arrayidx21, align 4
+  %add22 = add nsw i32 %tmp10, %tmp9
+  store i32 %add22, i32* %arrayidx21, align 4
+  %arrayidx23 = getelementptr inbounds i32, i32* %I1, i64 %add
+  %tmp11 = load i32, i32* %arrayidx23, align 4
+  %arrayidx25 = getelementptr inbounds i32, i32* %V, i64 %indvars.iv1
+  %tmp12 = load i32, i32* %arrayidx25, align 4
+  %add26 = add nsw i32 %tmp12, %tmp11
+  store i32 %add26, i32* %arrayidx25, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %do.body
+  br label %do.cond
+
+do.cond:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %mul28 = mul nsw i64 %mul15, %add
+  %add29 = add nsw i64 %mul9, %mul28
+  %cmp30 = icmp slt i64 %indvars.iv, %add29
+  br i1 %cmp30, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  br label %for.inc
+
+for.inc:                                          ; preds = %do.end
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_zext_parameter.ll b/final/test/ScopInfo/invariant_load_zext_parameter.ll
new file mode 100644
index 0000000..ab2507a
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_zext_parameter.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s --check-prefix=CODEGEN
+;
+;    void f(int *I0, int *I1, int *V) {
+;      for (int i = 0; i < 1000; i++) {
+;        if ((long)(*I0) == 0)
+;          V[i] += *I1;
+;      }
+;    }
+;
+; CHECK:         Assumed Context:
+; CHECK-NEXT:      [loadI0] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:      [loadI0] -> {  : loadI0 < 0 }
+;
+; CHECK:   p0: %loadI0
+;
+; CHECK:       Stmt_if_then
+; CHECK-NEXT:    Domain :=
+; CHECK-NEXT:      [loadI0] -> { Stmt_if_then[i0] : loadI0 = 0 and 0 <= i0 <= 999 };
+;
+; CODEGEN:      polly.preload.begin:
+; CODEGEN-NEXT:   %polly.access.I0 = getelementptr i32, i32* %I0, i64 0
+; CODEGEN-NEXT:   %polly.access.I0.load = load i32, i32* %polly.access.I0
+; CODEGEN-NEXT:   store i32 %polly.access.I0.load, i32* %loadI1a.preload.s2a
+; CODEGEN-NEXT:   %0 = sext i32 %polly.access.I0.load to i64
+; CODEGEN-NEXT:   %1 = icmp eq i64 %0, 0
+; CODEGEN-NEXT:   br label %polly.preload.cond
+;
+; CODEGEN:      polly.preload.cond:
+; CODEGEN-NEXT:   br i1 %1, label %polly.preload.exec, label %polly.preload.merge
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %I0, i32* %I1, i32* %V) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1000
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %loadI1a = load i32, i32* %I0, align 4
+  %arrayidx = getelementptr inbounds i32, i32* %V, i64 %indvars.iv
+  %loadI1a1 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %loadI1a1, %loadI1a
+  store i32 %add, i32* %arrayidx, align 4
+  %loadI0 = load i32, i32* %I0, align 4
+  %loadI0ext = zext i32 %loadI0 to i64
+  %cmp1 = icmp eq i64 %loadI0ext, 0
+  br i1 %cmp1, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %loadI1b = load i32, i32* %I1, align 4
+  %arrayidx4 = getelementptr inbounds i32, i32* %V, i64 %indvars.iv
+  %loadI1a4 = load i32, i32* %arrayidx4, align 4
+  %add5 = add nsw i32 %loadI1a4, %loadI1b
+  store i32 %add5, i32* %arrayidx4, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_load_zextended_in_own_execution_context.ll b/final/test/ScopInfo/invariant_load_zextended_in_own_execution_context.ll
new file mode 100644
index 0000000..2ecacc7
--- /dev/null
+++ b/final/test/ScopInfo/invariant_load_zextended_in_own_execution_context.ll
@@ -0,0 +1,31 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -analyze < %s
+;
+; CHECK: Execution Context: [p_0_loaded_from_currpc] -> {  :  }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@currpc = external global i32, align 4
+@inbuff = external global i8*, align 8
+
+; Function Attrs: uwtable
+define void @_Z13dotableswitchP9Classfile() {
+entry:
+  br i1 undef, label %for.end, label %while.body
+
+while.body:                                       ; preds = %while.body, %entry
+  store i8* undef, i8** @inbuff, align 8
+  %0 = load i32, i32* @currpc, align 4
+  %rem = and i32 %0, 3
+  %tobool = icmp eq i32 %rem, 0
+  br i1 %tobool, label %while.end, label %while.body
+
+while.end:                                        ; preds = %while.body
+  br i1 undef, label %for.end, label %for.body
+
+for.body:                                         ; preds = %for.body, %while.end
+  br label %for.body
+
+for.end:                                          ; preds = %while.end, %entry
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_loads_complicated_dependences.ll b/final/test/ScopInfo/invariant_loads_complicated_dependences.ll
new file mode 100644
index 0000000..8f02a75
--- /dev/null
+++ b/final/test/ScopInfo/invariant_loads_complicated_dependences.ll
@@ -0,0 +1,85 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [LB, UB] -> { Stmt_for_body[i0] -> MemRef_LBptr[0] };
+; CHECK-NEXT:         Execution Context: [LB, UB] -> {  :  }
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [LB, UB] -> { Stmt_do_cond[i0, i1] -> MemRef_UBptr[0] };
+; CHECK-NEXT:         Execution Context: [LB, UB] -> {  :  }
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [LB, UB] -> { Stmt_if_then[i0, i1] -> MemRef_V[0] };
+; CHECK-NEXT:         Execution Context: [LB, UB] -> {  : LB >= 6 or (UB > LB and UB >= 6) }
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [LB, UB] -> { Stmt_if_else[i0, i1] -> MemRef_U[0] };
+; CHECK-NEXT:         Execution Context: [LB, UB] -> {  : LB <= 5 }
+; CHECK-NEXT: }
+;
+;    void f(int *restrict A, int *restrict V, int *restrict U, int *restrict UB,
+;           int *restrict LB) {
+;      for (int i = 0; i < 100; i++) {
+;        int j = /* invariant load */ *LB;
+;        do {
+;          if (j > 5)
+;            A[i] += /* invariant load */ *V;
+;          else
+;            A[i] += /* invariant load */ *U;
+;        } while (j++ < /* invariant load */ *UB);
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* noalias %A, i32* noalias %V, i32* noalias %U, i32* noalias %UBptr, i32* noalias %LBptr) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %LB = load i32, i32* %LBptr, align 4
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond, %for.body
+  %j.0 = phi i32 [ %LB, %for.body ], [ %inc, %do.cond ]
+  %cmp1 = icmp sgt i32 %j.0, 5
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:                                          ; preds = %do.body
+  %tmp1 = load i32, i32* %V, align 4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp2, %tmp1
+  store i32 %add, i32* %arrayidx, align 4
+  br label %if.end
+
+if.else:                                          ; preds = %do.body
+  %tmp3 = load i32, i32* %U, align 4
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp4 = load i32, i32* %arrayidx3, align 4
+  %add4 = add nsw i32 %tmp4, %tmp3
+  store i32 %add4, i32* %arrayidx3, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  br label %do.cond
+
+do.cond:                                          ; preds = %if.end
+  %inc = add nsw i32 %j.0, 1
+  %UB = load i32, i32* %UBptr, align 4
+  %cmp5 = icmp slt i32 %j.0, %UB
+  br i1 %cmp5, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  br label %for.inc
+
+for.inc:                                          ; preds = %do.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_loads_cyclic_dependences.ll b/final/test/ScopInfo/invariant_loads_cyclic_dependences.ll
new file mode 100644
index 0000000..ad421fb
--- /dev/null
+++ b/final/test/ScopInfo/invariant_loads_cyclic_dependences.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -analyze -polly-scops -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+; Negative test. If we assume UB[*V] to be invariant we get a cyclic
+; dependence in the invariant loads that needs to be resolved by
+; ignoring the actual accessed address and focusing on the fact
+; that the access happened. However, at the moment we assume UB[*V]
+; not to be loop invariant, thus reject this region.
+;
+; CHECK-NOT: Statements
+;
+;
+;    void f(int *restrict V, int *restrict UB, int *restrict A) {
+;      for (int i = 0; i < 100; i++) {
+;        int j = 0;
+;        int x = 0;
+;        do {
+;          x = /* invariant load dependent on UB[*V] */ *V;
+;          A[j + i]++;
+;        } while (j++ < /* invariant load dependent on *V */ UB[x]);
+;      }
+;    }
+;
+target datalayout = "e-m:e-i32:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* noalias %V, i32* noalias %UB, i32* noalias %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv2 = phi i32 [ %indvars.iv.next3, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i32 %indvars.iv2, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond, %for.body
+  %indvars.iv = phi i32 [ %indvars.iv.next, %do.cond ], [ 0, %for.body ]
+  %tmp = load i32, i32* %V, align 4
+  %tmp4 = add nuw nsw i32 %indvars.iv, %indvars.iv2
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %tmp4
+  %tmp5 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp5, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %do.cond
+
+do.cond:                                          ; preds = %do.body
+  %indvars.iv.next = add nuw nsw i32 %indvars.iv, 1
+  %arrayidx3 = getelementptr inbounds i32, i32* %UB, i32 %tmp
+  %tmp6 = load i32, i32* %arrayidx3, align 4
+  %cmp4 = icmp slt i32 %indvars.iv, %tmp6
+  br i1 %cmp4, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.cond
+  br label %for.inc
+
+for.inc:                                          ; preds = %do.end
+  %indvars.iv.next3 = add nuw nsw i32 %indvars.iv2, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_loop_bounds.ll b/final/test/ScopInfo/invariant_loop_bounds.ll
new file mode 100644
index 0000000..5e0980a
--- /dev/null
+++ b/final/test/ScopInfo/invariant_loop_bounds.ll
@@ -0,0 +1,109 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bounds2, bounds1, bounds0] -> { Stmt_for_cond[i0] -> MemRef_bounds[2] };
+; CHECK-NEXT:         Execution Context: [bounds2, bounds1, bounds0] -> {  :  }
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bounds2, bounds1, bounds0] -> { Stmt_for_cond_1[i0, i1] -> MemRef_bounds[1] };
+; CHECK-NEXT:         Execution Context: [bounds2, bounds1, bounds0] -> {  :  }
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bounds2, bounds1, bounds0] -> { Stmt_for_cond_4[i0, i1, i2] -> MemRef_bounds[0] };
+; CHECK-NEXT:         Execution Context: [bounds2, bounds1, bounds0] -> {  :  }
+; CHECK-NEXT: }
+;
+; CHECK:      p0: %bounds2
+; CHECK-NEXT: p1: %bounds1
+; CHECK-NEXT: p2: %bounds0
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body_6
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bounds2, bounds1, bounds0] -> { Stmt_for_body_6[i0, i1, i2] : 0 <= i0 < bounds2 and 0 <= i1 < bounds1 and 0 <= i2 < bounds0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bounds2, bounds1, bounds0] -> { Stmt_for_body_6[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bounds2, bounds1, bounds0] -> { Stmt_for_body_6[i0, i1, i2] -> MemRef_data[i0, i1, i2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bounds2, bounds1, bounds0] -> { Stmt_for_body_6[i0, i1, i2] -> MemRef_data[i0, i1, i2] };
+; CHECK-NEXT: }
+;
+;    int bounds[3];
+;    double data[1024][1024][1024];
+;
+;    void foo() {
+;      int i, j, k;
+;      for (k = 0; k < bounds[2]; k++)
+;        for (j = 0; j < bounds[1]; j++)
+;          for (i = 0; i < bounds[0]; i++)
+;            data[k][j][i] += i + j + k;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@bounds = common global [3 x i32] zeroinitializer, align 4
+@data = common global [1024 x [1024 x [1024 x double]]] zeroinitializer, align 16
+
+define void @foo() {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.16, %entry
+  %indvars.iv5 = phi i64 [ %indvars.iv.next6, %for.inc.16 ], [ 0, %entry ]
+  %bounds2 = load i32, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @bounds, i64 0, i64 2), align 4
+  %tmp7 = sext i32 %bounds2 to i64
+  %cmp = icmp slt i64 %indvars.iv5, %tmp7
+  br i1 %cmp, label %for.body, label %for.end.18
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond.1
+
+for.cond.1:                                       ; preds = %for.inc.13, %for.body
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc.13 ], [ 0, %for.body ]
+  %bounds1 = load i32, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @bounds, i64 0, i64 1), align 4
+  %tmp9 = sext i32 %bounds1 to i64
+  %cmp2 = icmp slt i64 %indvars.iv3, %tmp9
+  br i1 %cmp2, label %for.body.3, label %for.end.15
+
+for.body.3:                                       ; preds = %for.cond.1
+  br label %for.cond.4
+
+for.cond.4:                                       ; preds = %for.inc, %for.body.3
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %for.body.3 ]
+  %bounds0 = load i32, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @bounds, i64 0, i64 0), align 4
+  %tmp11 = sext i32 %bounds0 to i64
+  %cmp5 = icmp slt i64 %indvars.iv, %tmp11
+  br i1 %cmp5, label %for.body.6, label %for.end
+
+for.body.6:                                       ; preds = %for.cond.4
+  %tmp12 = add nsw i64 %indvars.iv, %indvars.iv3
+  %tmp13 = add nsw i64 %tmp12, %indvars.iv5
+  %tmp14 = trunc i64 %tmp13 to i32
+  %conv = sitofp i32 %tmp14 to double
+  %arrayidx11 = getelementptr inbounds [1024 x [1024 x [1024 x double]]], [1024 x [1024 x [1024 x double]]]* @data, i64 0, i64 %indvars.iv5, i64 %indvars.iv3, i64 %indvars.iv
+  %tmp15 = load double, double* %arrayidx11, align 8
+  %add12 = fadd double %tmp15, %conv
+  store double %add12, double* %arrayidx11, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body.6
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond.4
+
+for.end:                                          ; preds = %for.cond.4
+  br label %for.inc.13
+
+for.inc.13:                                       ; preds = %for.end
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  br label %for.cond.1
+
+for.end.15:                                       ; preds = %for.cond.1
+  br label %for.inc.16
+
+for.inc.16:                                       ; preds = %for.end.15
+  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1
+  br label %for.cond
+
+for.end.18:                                       ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_same_loop_bound_multiple_times-1.ll b/final/test/ScopInfo/invariant_same_loop_bound_multiple_times-1.ll
new file mode 100644
index 0000000..f31354e
--- /dev/null
+++ b/final/test/ScopInfo/invariant_same_loop_bound_multiple_times-1.ll
@@ -0,0 +1,107 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; Verify that we only have one parameter and one invariant load for all
+; three loads that occure in the region but actually access the same
+; location. Also check that the execution context is the most generic
+; one, e.g., here the universal set.
+;
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bounds0l0] -> { Stmt_for_cond_4[i0, i1, i2] -> MemRef_bounds[0] };
+; CHECK-NEXT:         Execution Context: [bounds0l0] -> {  :  }
+; CHECK-NEXT: }
+;
+; CHECK:      p0: %bounds0l0
+; CHECK-NOT:  p1
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body_6
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bounds0l0] -> { Stmt_for_body_6[i0, i1, i2] : 0 <= i0 < bounds0l0 and 0 <= i1 < bounds0l0 and 0 <= i2 < bounds0l0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bounds0l0] -> { Stmt_for_body_6[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bounds0l0] -> { Stmt_for_body_6[i0, i1, i2] -> MemRef_data[i0, i1, i2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bounds0l0] -> { Stmt_for_body_6[i0, i1, i2] -> MemRef_data[i0, i1, i2] };
+; CHECK-NEXT: }
+;
+;    int bounds[1];
+;    double data[1024][1024][1024];
+;
+;    void foo() {
+;      int i, j, k;
+;      for (k = 0; k < bounds[0]; k++)
+;        for (j = 0; j < bounds[0]; j++)
+;          for (i = 0; i < bounds[0]; i++)
+;            data[k][j][i] += i + j + k;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@bounds = common global [1 x i32] zeroinitializer, align 4
+@data = common global [1024 x [1024 x [1024 x double]]] zeroinitializer, align 16
+
+define void @foo() {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.16, %entry
+  %indvars.iv5 = phi i64 [ %indvars.iv.next6, %for.inc.16 ], [ 0, %entry ]
+  %bounds0l0 = load i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @bounds, i64 0, i64 0), align 4
+  %tmp7 = sext i32 %bounds0l0 to i64
+  %cmp = icmp slt i64 %indvars.iv5, %tmp7
+  br i1 %cmp, label %for.body, label %for.end.18
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond.1
+
+for.cond.1:                                       ; preds = %for.inc.13, %for.body
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc.13 ], [ 0, %for.body ]
+  %bounds0l1 = load i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @bounds, i64 0, i64 0), align 4
+  %tmp9 = sext i32 %bounds0l1 to i64
+  %cmp2 = icmp slt i64 %indvars.iv3, %tmp9
+  br i1 %cmp2, label %for.body.3, label %for.end.15
+
+for.body.3:                                       ; preds = %for.cond.1
+  br label %for.cond.4
+
+for.cond.4:                                       ; preds = %for.inc, %for.body.3
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %for.body.3 ]
+  %bounds0l2 = load i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @bounds, i64 0, i64 0), align 4
+  %tmp11 = sext i32 %bounds0l2 to i64
+  %cmp5 = icmp slt i64 %indvars.iv, %tmp11
+  br i1 %cmp5, label %for.body.6, label %for.end
+
+for.body.6:                                       ; preds = %for.cond.4
+  %tmp12 = add nsw i64 %indvars.iv, %indvars.iv3
+  %tmp13 = add nsw i64 %tmp12, %indvars.iv5
+  %tmp14 = trunc i64 %tmp13 to i32
+  %conv = sitofp i32 %tmp14 to double
+  %arrayidx11 = getelementptr inbounds [1024 x [1024 x [1024 x double]]], [1024 x [1024 x [1024 x double]]]* @data, i64 0, i64 %indvars.iv5, i64 %indvars.iv3, i64 %indvars.iv
+  %tmp15 = load double, double* %arrayidx11, align 8
+  %add12 = fadd double %tmp15, %conv
+  store double %add12, double* %arrayidx11, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body.6
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond.4
+
+for.end:                                          ; preds = %for.cond.4
+  br label %for.inc.13
+
+for.inc.13:                                       ; preds = %for.end
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  br label %for.cond.1
+
+for.end.15:                                       ; preds = %for.cond.1
+  br label %for.inc.16
+
+for.inc.16:                                       ; preds = %for.end.15
+  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1
+  br label %for.cond
+
+for.end.18:                                       ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/invariant_same_loop_bound_multiple_times-2.ll b/final/test/ScopInfo/invariant_same_loop_bound_multiple_times-2.ll
new file mode 100644
index 0000000..6e27837
--- /dev/null
+++ b/final/test/ScopInfo/invariant_same_loop_bound_multiple_times-2.ll
@@ -0,0 +1,110 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; Verify that we only have one parameter and one invariant load for all
+; three loads that occure in the region but actually access the same
+; location. Also check that the execution context is the most generic
+; one, e.g., here the universal set.
+;
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bounds0l0, p] -> { Stmt_for_cond_4[i0, i1, i2] -> MemRef_bounds[0] };
+; CHECK-NEXT:         Execution Context: [bounds0l0, p] -> {  :  }
+; CHECK-NEXT: }
+;
+; CHECK:      p0: %bounds0l0
+; CHECK-NEXT: p1: %p
+; CHECK-NOT:  p2
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body_6
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [bounds0l0, p] -> { Stmt_for_body_6[i0, i1, i2] : p = 0 and 0 <= i0 < bounds0l0 and 0 <= i1 < bounds0l0 and 0 <= i2 < bounds0l0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [bounds0l0, p] -> { Stmt_for_body_6[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bounds0l0, p] -> { Stmt_for_body_6[i0, i1, i2] -> MemRef_data[i0, i1, i2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [bounds0l0, p] -> { Stmt_for_body_6[i0, i1, i2] -> MemRef_data[i0, i1, i2] };
+; CHECK-NEXT: }
+;
+;    int bounds[1];
+;    double data[1024][1024][1024];
+;
+;    void foo(int p) {
+;      int i, j, k;
+;      for (k = 0; k < bounds[0]; k++)
+;        if (p == 0)
+;          for (j = 0; j < bounds[0]; j++)
+;            for (i = 0; i < bounds[0]; i++)
+;              data[k][j][i] += i + j + k;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@bounds = common global [1 x i32] zeroinitializer, align 4
+@data = common global [1024 x [1024 x [1024 x double]]] zeroinitializer, align 16
+
+define void @foo(i32 %p) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.16, %entry
+  %indvars.iv5 = phi i64 [ %indvars.iv.next6, %for.inc.16 ], [ 0, %entry ]
+  %bounds0l0 = load i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @bounds, i64 0, i64 0), align 4
+  %tmp7 = sext i32 %bounds0l0 to i64
+  %cmp = icmp slt i64 %indvars.iv5, %tmp7
+  br i1 %cmp, label %for.body, label %for.end.18
+
+for.body:                                         ; preds = %for.cond
+  %cmpp = icmp eq i32 %p, 0
+  br i1 %cmpp, label %for.cond.1, label %for.inc.16
+
+for.cond.1:                                       ; preds = %for.inc.13, %for.body
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc.13 ], [ 0, %for.body ]
+  %bounds0l1 = load i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @bounds, i64 0, i64 0), align 4
+  %tmp9 = sext i32 %bounds0l1 to i64
+  %cmp2 = icmp slt i64 %indvars.iv3, %tmp9
+  br i1 %cmp2, label %for.body.3, label %for.end.15
+
+for.body.3:                                       ; preds = %for.cond.1
+  br label %for.cond.4
+
+for.cond.4:                                       ; preds = %for.inc, %for.body.3
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %for.body.3 ]
+  %bounds0l2 = load i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @bounds, i64 0, i64 0), align 4
+  %tmp11 = sext i32 %bounds0l2 to i64
+  %cmp5 = icmp slt i64 %indvars.iv, %tmp11
+  br i1 %cmp5, label %for.body.6, label %for.end
+
+for.body.6:                                       ; preds = %for.cond.4
+  %tmp12 = add nsw i64 %indvars.iv, %indvars.iv3
+  %tmp13 = add nsw i64 %tmp12, %indvars.iv5
+  %tmp14 = trunc i64 %tmp13 to i32
+  %conv = sitofp i32 %tmp14 to double
+  %arrayidx11 = getelementptr inbounds [1024 x [1024 x [1024 x double]]], [1024 x [1024 x [1024 x double]]]* @data, i64 0, i64 %indvars.iv5, i64 %indvars.iv3, i64 %indvars.iv
+  %tmp15 = load double, double* %arrayidx11, align 8
+  %add12 = fadd double %tmp15, %conv
+  store double %add12, double* %arrayidx11, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body.6
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond.4
+
+for.end:                                          ; preds = %for.cond.4
+  br label %for.inc.13
+
+for.inc.13:                                       ; preds = %for.end
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  br label %for.cond.1
+
+for.end.15:                                       ; preds = %for.cond.1
+  br label %for.inc.16
+
+for.inc.16:                                       ; preds = %for.end.15
+  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1
+  br label %for.cond
+
+for.end.18:                                       ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/isl_aff_out_of_bounds.ll b/final/test/ScopInfo/isl_aff_out_of_bounds.ll
new file mode 100644
index 0000000..e8cd2a2
--- /dev/null
+++ b/final/test/ScopInfo/isl_aff_out_of_bounds.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -basicaa -polly-detect < %s
+
+; Used to fail with:
+; ../../isl/isl_aff.c:591: position out of bounds
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+declare double @frexp(double)
+
+define void @vorbis_lsp_to_curve(float* %lsp, i32 %m) {
+entry:
+  %q.1.reg2mem = alloca float, align 4
+  br i1 undef, label %do.body, label %while.end
+
+do.body:                                          ; preds = %do.body, %entry
+  %ftmp.0 = phi float* [ %add.ptr, %do.body ], [ %lsp, %entry ]
+  %add.ptr = getelementptr inbounds float, float* %ftmp.0, i64 2
+  br i1 true, label %do.end, label %do.body
+
+do.end:                                           ; preds = %do.body
+  br i1 false, label %if.end.single_exit, label %if.then
+
+if.then:                                          ; preds = %do.end
+  %0 = load float, float* %add.ptr, align 4
+  store float %0, float* %q.1.reg2mem, align 4
+  br label %if.end.single_exit
+
+if.end.single_exit:                               ; preds = %do.end, %if.then
+  br label %if.end
+
+if.end:                                           ; preds = %if.end.single_exit
+  %q.1.reload = load float, float* %q.1.reg2mem, align 4
+  %conv31 = fpext float %q.1.reload to double
+  %call32 = call double @frexp(double %conv31)
+  unreachable
+
+while.end:                                        ; preds = %entry
+  ret void
+}
diff --git a/final/test/ScopInfo/isl_trip_count_01.ll b/final/test/ScopInfo/isl_trip_count_01.ll
new file mode 100644
index 0000000..4336215
--- /dev/null
+++ b/final/test/ScopInfo/isl_trip_count_01.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: [M, N] -> { Stmt_while_body[i0] : i0 > 0 and 4i0 <= -M + N; Stmt_while_body[0] };
+;
+;   void f(int *A, int N, int M) {
+;     int i = 0;
+;     while (M <= N) {
+;       A[i++] = 1;
+;       M += 4;
+;     }
+;   }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+
+define void @f(i32* nocapture %A, i32 %N, i32 %M) {
+entry:
+  %cmp3 = icmp sgt i32 %M, %N
+  br i1 %cmp3, label %while.end, label %while.body.preheader
+
+while.body.preheader:
+  br label %while.body
+
+while.body:
+  %i.05 = phi i32 [ %inc, %while.body ], [ 0, %while.body.preheader ]
+  %M.addr.04 = phi i32 [ %add, %while.body ], [ %M, %while.body.preheader ]
+  %inc = add nuw nsw i32 %i.05, 1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.05
+  store i32 1, i32* %arrayidx, align 4
+  %add = add nsw i32 %M.addr.04, 4
+  %cmp = icmp sgt i32 %add, %N
+  br i1 %cmp, label %while.end.loopexit, label %while.body
+
+while.end.loopexit:
+  br label %while.end
+
+while.end:
+  ret void
+}
diff --git a/final/test/ScopInfo/isl_trip_count_02.ll b/final/test/ScopInfo/isl_trip_count_02.ll
new file mode 100644
index 0000000..7fd1cbb
--- /dev/null
+++ b/final/test/ScopInfo/isl_trip_count_02.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; TODO: We do not allow unbounded loops at the moment.
+;
+; CHECK-NOT: Stmt_for_body
+;
+;   void f(int *A, int N, int M) {
+;     for (int i = M; i > N; i++)
+;       A[i] = i;
+;   }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+
+define void @f(i32* %A, i32 %N, i32 %M) {
+entry:
+  br label %entry.split
+
+entry.split:
+  %cmp.1 = icmp sgt i32 %M, %N
+  br i1 %cmp.1, label %for.body, label %for.end
+
+for.body:
+  %indvars.iv = phi i32 [ %indvars.iv.next, %for.body ], [ %M, %entry.split ]
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %indvars.iv
+  store i32 %indvars.iv, i32* %arrayidx, align 4
+  %cmp = icmp slt i32 %M, %N
+  %indvars.iv.next = add i32 %indvars.iv, 1
+  br i1 %cmp, label %for.cond.for.end_crit_edge, label %for.body
+
+for.cond.for.end_crit_edge:
+  br label %for.end
+
+for.end:
+  ret void
+}
diff --git a/final/test/ScopInfo/isl_trip_count_03.ll b/final/test/ScopInfo/isl_trip_count_03.ll
new file mode 100644
index 0000000..61b29e4
--- /dev/null
+++ b/final/test/ScopInfo/isl_trip_count_03.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Test comes from a bug (15771) or better a feature request. It was not allowed
+; in Polly in the old domain generation as ScalarEvolution cannot figure out the
+; loop bounds. However, the new domain generation will detect the SCoP.
+
+; CHECK:      Context:
+; CHECK-NEXT: [n] -> {  : -2147483648 <= n <= 2147483647 }
+;
+; CHECK:      p0: %n
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_next
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_for_next[i0] : i0 >= 0 and 2i0 <= -3 + n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_for_next[i0] -> [i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_for_next[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_for_next[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+
+@A = common global [100 x i32] zeroinitializer, align 16
+
+define void @foo(i32 %n) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %cmp2 = icmp sgt i32 %n, 0
+  br i1 %cmp2, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.lr.ph, %for.body
+  %indvar = phi i64 [ 0, %for.body.lr.ph ], [ %indvar.next, %for.next ]
+  %arrayidx = getelementptr [100 x i32], [100 x i32]* @A, i64 0, i64 %indvar
+  %0 = mul i64 %indvar, 2
+  %1 = add i64 %0, 2
+  %add1 = trunc i64 %1 to i32
+  %cmp = icmp slt i32 %add1, %n
+  %indvar.next = add i64 %indvar, 1
+  br i1 %cmp, label %for.next, label %for.cond.for.end_crit_edge
+
+for.next:
+  %2 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %2, 1
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.body
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  ret void
+}
diff --git a/final/test/ScopInfo/isl_trip_count_multiple_exiting_blocks.ll b/final/test/ScopInfo/isl_trip_count_multiple_exiting_blocks.ll
new file mode 100644
index 0000000..c6118a8
--- /dev/null
+++ b/final/test/ScopInfo/isl_trip_count_multiple_exiting_blocks.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Domain :=
+; CHECK:   { Stmt_if_end[i0] : 0 <= i0 <= 1024 };
+;
+;    void f(int *A) {
+;      int i = 0;
+;      do {
+;        if (i > 1024)
+;          break;
+;        A[i] = i;
+;        i++;
+;      } while (i > 0);
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+entry:
+  br label %do.body
+
+do.body:                                          ; preds = %do.cond, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %do.cond ], [ 0, %entry ]
+  %cmp = icmp sgt i64 %indvars.iv, 1024
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %do.body
+  br label %do.end
+
+if.end:                                           ; preds = %do.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = trunc i64 %indvars.iv to i32
+  store i32 %tmp, i32* %arrayidx, align 4
+  br label %do.cond
+
+do.cond:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %cmp2 = icmp sgt i64 %indvars.iv.next, 0
+  br i1 %cmp2, label %do.body, label %do.end.loopexit
+
+do.end.loopexit:                                  ; preds = %do.cond
+  br label %do.end
+
+do.end:                                           ; preds = %do.end.loopexit, %if.then
+  ret void
+}
diff --git a/final/test/ScopInfo/kernel_gemm___%for.cond.1.preheader---%for.end.12.jscop b/final/test/ScopInfo/kernel_gemm___%for.cond.1.preheader---%for.end.12.jscop
new file mode 100644
index 0000000..06eb041
--- /dev/null
+++ b/final/test/ScopInfo/kernel_gemm___%for.cond.1.preheader---%for.end.12.jscop
@@ -0,0 +1,25 @@
+{
+   "context" : "[nk] -> {  : nk <= 2147483647 and nk >= -2147483648 }",
+   "name" : "for.cond.1.preheader => polly.merge_new_and_old",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[nk] -> { Stmt_for_body_3[i0, i1] -> MemRef_A[i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[nk] -> { Stmt_for_body_3[i0, i1] -> MemRef_C[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[nk] -> { Stmt_for_body_3[i0, i1] -> MemRef_C[i0] }"
+            }
+         ],
+         "domain" : "[nk] -> { Stmt_for_body_3[i0, i1] : i0 >= 0 and i0 <= 1023 and i1 >= 0 and i1 <= -1 + nk and nk >= 1 }",
+         "name" : "Stmt_for_body_3",
+         "schedule" : "[nk] -> { Stmt_for_body_3[i0, i1] -> [o0, o1, o2, i1 - 32o1, i0 - 32o0 - 4o2] : 4o2 >= -3 + i0 - 32o0 and 4o2 <= i0 - 32o0 and 32o1 >= -31 + i1 and 32o1 <= i1 and 32o0 <= i0 and 32o0 >= -31 + i0 }"
+      }
+   ]
+}
diff --git a/final/test/ScopInfo/licm_load.ll b/final/test/ScopInfo/licm_load.ll
new file mode 100644
index 0000000..b8b8a9c
--- /dev/null
+++ b/final/test/ScopInfo/licm_load.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -basicaa -loop-rotate -indvars       -polly-prepare \
+; RUN: -polly-invariant-load-hoisting=true -polly-scops -analyze < %s \
+; RUN: | FileCheck %s
+; RUN: opt %loadPolly -basicaa -loop-rotate -indvars -licm -polly-prepare \
+; RUN: -polly-invariant-load-hoisting=true -polly-scops -analyze < %s \
+; RUN: | FileCheck %s
+;
+;    void foo(int n, float A[static const restrict n],
+;             float B[static const restrict n], int j) {
+;      for (int i = 0; i < n; i++)
+;        A[i] = B[j];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i32 %n, float* noalias nonnull %A, float* noalias nonnull %B, i32 %j) {
+entry:
+  %tmp = sext i32 %n to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %idxprom = sext i32 %j to i64
+  %arrayidx = getelementptr inbounds float, float* %B, i64 %idxprom
+  %tmp1 = bitcast float* %arrayidx to i32*
+  %tmp2 = load i32, i32* %tmp1, align 4
+  %arrayidx2 = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp3 = bitcast float* %arrayidx2 to i32*
+  store i32 %tmp2, i32* %tmp3, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:   ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       [n, j] -> { Stmt_{{[a-zA-Z_]*}}[{{[i0]*}}] -> MemRef_B[j] };
+; CHECK-NEXT:       Execution Context: [n, j] -> {  : n > 0 }
+; CHECK-NEXT: }
+;
+; CHECK: Statements {
+; CHECK:      Stmt_for_body
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:        [n, j] -> { Stmt_for_body[i0] -> MemRef_A[i0] };
+; CHECK:     }
diff --git a/final/test/ScopInfo/licm_potential_store.ll b/final/test/ScopInfo/licm_potential_store.ll
new file mode 100644
index 0000000..8b389df
--- /dev/null
+++ b/final/test/ScopInfo/licm_potential_store.ll
@@ -0,0 +1,88 @@
+; RUN: opt %loadPolly -basicaa -sroa -instcombine -simplifycfg -tailcallopt \
+; RUN:    -simplifycfg -reassociate -loop-rotate -instcombine -indvars \
+; RUN:    -polly-prepare -polly-scops -analyze < %s \
+; RUN:    \
+; RUN:     | FileCheck %s --check-prefix=NOLICM
+
+; RUN: opt %loadPolly -basicaa -sroa -instcombine -simplifycfg -tailcallopt \
+; RUN:    -simplifycfg -reassociate -loop-rotate -instcombine -indvars -licm \
+; RUN:    -polly-prepare -polly-scops -analyze < %s \
+; RUN:    \
+; RUN:     | FileCheck %s --check-prefix=LICM
+
+;    void foo(int n, float A[static const restrict n], float x) {
+;      //      (0)
+;      for (int i = 0; i < 5; i += 1) {
+;        for (int j = 0; j < n; j += 1) {
+;          x = 7; // (1)
+;        }
+;        A[0] = x; // (3)
+;      }
+;      // (4)
+;    }
+
+; LICM:   Statements
+; NOLICM: Statements
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i32 %n, float* noalias nonnull %A, float %x) {
+entry:
+  %n.addr = alloca i32, align 4
+  %A.addr = alloca float*, align 8
+  %x.addr = alloca float, align 4
+  %i = alloca i32, align 4
+  %j = alloca i32, align 4
+  store i32 %n, i32* %n.addr, align 4
+  store float* %A, float** %A.addr, align 8
+  store float %x, float* %x.addr, align 4
+  %tmp = load i32, i32* %n.addr, align 4
+  %tmp1 = zext i32 %tmp to i64
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.4, %entry
+  %tmp2 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %tmp2, 5
+  br i1 %cmp, label %for.body, label %for.end.6
+
+for.body:                                         ; preds = %for.cond
+  store i32 0, i32* %j, align 4
+  br label %for.cond.1
+
+for.cond.1:                                       ; preds = %for.inc, %for.body
+  %tmp3 = load i32, i32* %j, align 4
+  %tmp4 = load i32, i32* %n.addr, align 4
+  %cmp2 = icmp slt i32 %tmp3, %tmp4
+  br i1 %cmp2, label %for.body.3, label %for.end
+
+for.body.3:                                       ; preds = %for.cond.1
+  store float 7.000000e+00, float* %x.addr, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body.3
+  %tmp5 = load i32, i32* %j, align 4
+  %add = add nsw i32 %tmp5, 1
+  store i32 %add, i32* %j, align 4
+  br label %for.cond.1
+
+for.end:                                          ; preds = %for.cond.1
+  %tmp6 = load float, float* %x.addr, align 4
+  %tmp7 = load float*, float** %A.addr, align 8
+  %arrayidx = getelementptr inbounds float, float* %tmp7, i64 0
+  store float %tmp6, float* %arrayidx, align 4
+  br label %for.inc.4
+
+for.inc.4:                                        ; preds = %for.end
+  %tmp8 = load i32, i32* %i, align 4
+  %add5 = add nsw i32 %tmp8, 1
+  store i32 %add5, i32* %i, align 4
+  br label %for.cond
+
+for.end.6:                                        ; preds = %for.cond
+  ret void
+}
+
+; CHECK: Statements {
+; CHECK:     Stmt_for_end
+; CHECK: }
diff --git a/final/test/ScopInfo/licm_reduction.ll b/final/test/ScopInfo/licm_reduction.ll
new file mode 100644
index 0000000..2a3c5a0
--- /dev/null
+++ b/final/test/ScopInfo/licm_reduction.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -basicaa -loop-rotate -indvars       -polly-prepare -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -loop-rotate -indvars -licm -polly-prepare -polly-scops -analyze < %s | FileCheck %s
+;
+; XFAIL: *
+;
+;    void test(int n, double B[static const restrict n], int j) {
+;      for (int i = 0; i < n; i += 1) {
+;        B[j] += i;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @test(i32 %n, double* noalias nonnull %B, i32 %j) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %add1, %for.inc ]
+  %cmp = icmp slt i32 %i.0, %n
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %conv = sitofp i32 %i.0 to double
+  %idxprom = sext i32 %j to i64
+  %arrayidx = getelementptr inbounds double, double* %B, i64 %idxprom
+  %tmp = load double, double* %arrayidx, align 8
+  %add = fadd double %tmp, %conv
+  store double %add, double* %arrayidx, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %add1 = add nuw nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+
+; CHECK: Statements {
+; CHECK:     Stmt_for_body
+; CHECK-DAG:     ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:        [n, j] -> { Stmt_for_body[i0] -> MemRef_B[j] };
+; CHECK-DAG:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:        [n, j] -> { Stmt_for_body[i0] -> MemRef_B[j] };
+; CHECK: }
diff --git a/final/test/ScopInfo/licm_reduction_nested.ll b/final/test/ScopInfo/licm_reduction_nested.ll
new file mode 100644
index 0000000..4901fc2
--- /dev/null
+++ b/final/test/ScopInfo/licm_reduction_nested.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -basicaa -loop-rotate -indvars       -polly-prepare -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -loop-rotate -indvars -licm -polly-prepare -polly-scops -analyze < %s | FileCheck %s
+;
+; XFAIL: *
+;
+; Even ScopDetection fails here after LICM because of PHI in exit node.
+;
+;    void foo(unsigned long *restrict A, unsigned long *restrict B,
+;             unsigned long j) {
+;      for (unsigned long i = 0; i < 100; i++)
+;        for (unsigned long k = 0; k < 100; k++)
+;          A[j] += B[i + k];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64* noalias %A, i64* noalias %B, i64 %j) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.6, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc7, %for.inc.6 ]
+  %exitcond1 = icmp ne i64 %i.0, 100
+  br i1 %exitcond1, label %for.body, label %for.end.8
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond.1
+
+for.cond.1:                                       ; preds = %for.inc, %for.body
+  %k.0 = phi i64 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %k.0, 100
+  br i1 %exitcond, label %for.body.3, label %for.end
+
+for.body.3:                                       ; preds = %for.cond.1
+  %add = add nuw nsw i64 %i.0, %k.0
+  %arrayidx = getelementptr inbounds i64, i64* %B, i64 %add
+  %tmp = load i64, i64* %arrayidx, align 8
+  %arrayidx4 = getelementptr inbounds i64, i64* %A, i64 %j
+  %tmp2 = load i64, i64* %arrayidx4, align 8
+  %add5 = add i64 %tmp2, %tmp
+  store i64 %add5, i64* %arrayidx4, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body.3
+  %inc = add nuw nsw i64 %k.0, 1
+  br label %for.cond.1
+
+for.end:                                          ; preds = %for.cond.1
+  br label %for.inc.6
+
+for.inc.6:                                        ; preds = %for.end
+  %inc7 = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end.8:                                        ; preds = %for.cond
+  ret void
+}
+
+
+; CHECK: Statements {
+; CHECK:     Stmt_for_body_3
+; CHECK-DAG:    ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       [j] -> { Stmt_for_body_3[i0, i1] -> MemRef_B[i0 + i1] };
+; CHECK-DAG:    ReadAccess :=       [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:       [j] -> { Stmt_for_body_3[i0, i1] -> MemRef_A[j] };
+; CHECK-DAG:    MustWriteAccess :=  [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:       [j] -> { Stmt_for_body_3[i0, i1] -> MemRef_A[j] };
+; CHECK: }
diff --git a/final/test/ScopInfo/licm_store.ll b/final/test/ScopInfo/licm_store.ll
new file mode 100644
index 0000000..6ca509b
--- /dev/null
+++ b/final/test/ScopInfo/licm_store.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -basicaa -loop-rotate -indvars       -polly-prepare -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -loop-rotate -indvars -licm -polly-prepare -polly-scops -analyze < %s | FileCheck %s
+;
+; XFAIL: *
+;
+;    void foo(float *restrict A, float *restrict B, long j) {
+;      for (long i = 0; i < 100; i++)
+;        A[j] = B[i];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* noalias %A, float* noalias %B, i64 %j) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds float, float* %B, i64 %i.0
+  %tmp = bitcast float* %arrayidx to i32*
+  %tmp1 = load i32, i32* %tmp, align 4
+  %arrayidx1 = getelementptr inbounds float, float* %A, i64 %j
+  %tmp2 = bitcast float* %arrayidx1 to i32*
+  store i32 %tmp1, i32* %tmp2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+; CHECK: Statements {
+; CHECK:     Stmt_for_body
+; CHECK-DAG:    ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       [j] -> { Stmt_for_body[i0] -> MemRef_B[i0] };
+; CHECK-DAG:    MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       [j] -> { Stmt_for_body[i0] -> MemRef_A[j] };
+; CHECK: }
diff --git a/final/test/ScopInfo/long-compile-time-alias-analysis.ll b/final/test/ScopInfo/long-compile-time-alias-analysis.ll
new file mode 100644
index 0000000..d090510
--- /dev/null
+++ b/final/test/ScopInfo/long-compile-time-alias-analysis.ll
@@ -0,0 +1,235 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s
+
+; Verify that the compilation of this test case does not take infinite time.
+; At some point Polly tried to model this test case and got stuck in
+; computing a lexicographic minima. Today it should gracefully bail out.
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64--linux-android"
+
+%0 = type { i8*, i64, i64, i64, i64, i64, i64 }
+
+define void @_Z1fR1SS0_Ph(%0* nocapture readonly dereferenceable(56) %arg, %0* nocapture readonly dereferenceable(56) %arg1, i8* nocapture readonly %arg2) {
+bb:
+  %tmp = getelementptr inbounds %0, %0* %arg1, i64 0, i32 1
+  %tmp3 = getelementptr inbounds %0, %0* %arg, i64 0, i32 0
+  %tmp4 = load i8*, i8** %tmp3, align 8
+  %tmp5 = getelementptr inbounds %0, %0* %arg, i64 0, i32 4
+  %tmp6 = load i64, i64* %tmp5, align 8
+  %tmp7 = getelementptr inbounds %0, %0* %arg, i64 0, i32 1
+  %tmp8 = load i64, i64* %tmp7, align 8
+  %tmp9 = mul i64 %tmp8, %tmp6
+  %tmp10 = getelementptr inbounds i8, i8* %tmp4, i64 %tmp9
+  %tmp11 = getelementptr inbounds %0, %0* %arg, i64 0, i32 3
+  %tmp12 = load i64, i64* %tmp11, align 8
+  %tmp13 = getelementptr inbounds i8, i8* %tmp10, i64 %tmp12
+  %tmp14 = getelementptr inbounds %0, %0* %arg, i64 0, i32 6
+  %tmp15 = load i64, i64* %tmp14, align 8
+  %tmp16 = add i64 %tmp15, 1
+  %tmp17 = icmp eq i64 %tmp16, %tmp6
+  br i1 %tmp17, label %bb51, label %bb18
+
+bb18:                                             ; preds = %bb
+  %tmp19 = getelementptr inbounds %0, %0* %arg, i64 0, i32 2
+  %tmp20 = load i64, i64* %tmp19, align 8
+  %tmp21 = mul i64 %tmp20, %tmp8
+  %tmp22 = getelementptr inbounds i8, i8* %tmp13, i64 %tmp21
+  %tmp23 = getelementptr inbounds i8, i8* %tmp22, i64 %tmp9
+  %tmp24 = getelementptr inbounds i8, i8* %tmp23, i64 %tmp12
+  %tmp25 = bitcast %0* %arg1 to i16**
+  %tmp26 = load i16*, i16** %tmp25, align 8
+  %tmp27 = load i64, i64* %tmp, align 8
+  %tmp28 = getelementptr inbounds %0, %0* %arg1, i64 0, i32 4
+  %tmp29 = load i64, i64* %tmp28, align 8
+  %tmp30 = mul i64 %tmp27, %tmp29
+  %tmp31 = getelementptr inbounds i16, i16* %tmp26, i64 %tmp30
+  %tmp32 = getelementptr inbounds %0, %0* %arg1, i64 0, i32 3
+  %tmp33 = load i64, i64* %tmp32, align 8
+  %tmp34 = getelementptr inbounds i16, i16* %tmp31, i64 %tmp33
+  %tmp35 = getelementptr inbounds %0, %0* %arg, i64 0, i32 5
+  %tmp36 = load i64, i64* %tmp35, align 8
+  br label %bb37
+
+bb37:                                             ; preds = %bb57, %bb18
+  %tmp38 = phi i64 [ %tmp6, %bb18 ], [ %tmp58, %bb57 ]
+  %tmp39 = phi i64 [ %tmp15, %bb18 ], [ %tmp59, %bb57 ]
+  %tmp40 = phi i64 [ %tmp27, %bb18 ], [ %tmp60, %bb57 ]
+  %tmp41 = phi i64 [ %tmp8, %bb18 ], [ %tmp61, %bb57 ]
+  %tmp42 = phi i64 [ %tmp12, %bb18 ], [ %tmp62, %bb57 ]
+  %tmp43 = phi i64 [ %tmp36, %bb18 ], [ %tmp63, %bb57 ]
+  %tmp44 = phi i16* [ %tmp34, %bb18 ], [ %tmp69, %bb57 ]
+  %tmp45 = phi i8* [ %tmp13, %bb18 ], [ %tmp64, %bb57 ]
+  %tmp46 = phi i8* [ %tmp24, %bb18 ], [ %tmp68, %bb57 ]
+  %tmp47 = phi i64 [ 0, %bb18 ], [ %tmp70, %bb57 ]
+  %tmp48 = add i64 %tmp43, 1
+  %tmp49 = sub i64 %tmp48, %tmp42
+  %tmp50 = icmp eq i64 %tmp49, 0
+  br i1 %tmp50, label %bb57, label %bb74
+
+bb51:                                             ; preds = %bb57, %bb
+  ret void
+
+bb52:                                             ; preds = %bb176
+  %tmp53 = load i64, i64* %tmp7, align 8
+  %tmp54 = load i64, i64* %tmp, align 8
+  %tmp55 = load i64, i64* %tmp14, align 8
+  %tmp56 = load i64, i64* %tmp5, align 8
+  br label %bb57
+
+bb57:                                             ; preds = %bb52, %bb37
+  %tmp58 = phi i64 [ %tmp56, %bb52 ], [ %tmp38, %bb37 ]
+  %tmp59 = phi i64 [ %tmp55, %bb52 ], [ %tmp39, %bb37 ]
+  %tmp60 = phi i64 [ %tmp54, %bb52 ], [ %tmp40, %bb37 ]
+  %tmp61 = phi i64 [ %tmp53, %bb52 ], [ %tmp41, %bb37 ]
+  %tmp62 = phi i64 [ %tmp179, %bb52 ], [ %tmp42, %bb37 ]
+  %tmp63 = phi i64 [ %tmp178, %bb52 ], [ %tmp43, %bb37 ]
+  %tmp64 = getelementptr inbounds i8, i8* %tmp45, i64 %tmp61
+  %tmp65 = and i64 %tmp47, 1
+  %tmp66 = icmp eq i64 %tmp65, 0
+  %tmp67 = getelementptr inbounds i8, i8* %tmp46, i64 %tmp61
+  %tmp68 = select i1 %tmp66, i8* %tmp46, i8* %tmp67
+  %tmp69 = getelementptr inbounds i16, i16* %tmp44, i64 %tmp60
+  %tmp70 = add i64 %tmp47, 1
+  %tmp71 = add i64 %tmp59, 1
+  %tmp72 = sub i64 %tmp71, %tmp58
+  %tmp73 = icmp ult i64 %tmp70, %tmp72
+  br i1 %tmp73, label %bb37, label %bb51
+
+bb74:                                             ; preds = %bb176, %bb37
+  %tmp75 = phi i64 [ %tmp181, %bb176 ], [ %tmp49, %bb37 ]
+  %tmp76 = phi i64 [ %tmp177, %bb176 ], [ 0, %bb37 ]
+  %tmp77 = getelementptr inbounds i8, i8* %tmp45, i64 %tmp76
+  %tmp78 = load i8, i8* %tmp77, align 1
+  %tmp79 = zext i8 %tmp78 to i32
+  %tmp80 = or i64 %tmp76, 1
+  %tmp81 = getelementptr inbounds i8, i8* %tmp45, i64 %tmp80
+  %tmp82 = load i8, i8* %tmp81, align 1
+  %tmp83 = zext i8 %tmp82 to i32
+  %tmp84 = getelementptr inbounds i8, i8* %tmp46, i64 %tmp76
+  %tmp85 = load i8, i8* %tmp84, align 1
+  %tmp86 = zext i8 %tmp85 to i32
+  %tmp87 = getelementptr inbounds i8, i8* %tmp46, i64 %tmp80
+  %tmp88 = load i8, i8* %tmp87, align 1
+  %tmp89 = zext i8 %tmp88 to i32
+  %tmp90 = mul nuw nsw i32 %tmp86, 517
+  %tmp91 = add nsw i32 %tmp90, -66176
+  %tmp92 = sub nsw i32 128, %tmp86
+  %tmp93 = mul nsw i32 %tmp92, 100
+  %tmp94 = sub nsw i32 128, %tmp89
+  %tmp95 = mul nsw i32 %tmp94, 208
+  %tmp96 = mul nuw nsw i32 %tmp89, 409
+  %tmp97 = add nsw i32 %tmp96, -52352
+  %tmp98 = mul nuw nsw i32 %tmp79, 298
+  %tmp99 = add nsw i32 %tmp98, -4768
+  %tmp100 = add nsw i32 %tmp91, %tmp99
+  %tmp101 = sdiv i32 %tmp100, 256
+  %tmp102 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %tmp99, i32 %tmp95)
+  %tmp103 = extractvalue { i32, i1 } %tmp102, 1
+  br i1 %tmp103, label %bb104, label %bb105
+
+bb104:                                            ; preds = %bb120, %bb109, %bb105, %bb74
+  tail call void @llvm.trap()
+  unreachable
+
+bb105:                                            ; preds = %bb74
+  %tmp106 = extractvalue { i32, i1 } %tmp102, 0
+  %tmp107 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %tmp106, i32 %tmp93)
+  %tmp108 = extractvalue { i32, i1 } %tmp107, 1
+  br i1 %tmp108, label %bb104, label %bb109
+
+bb109:                                            ; preds = %bb105
+  %tmp110 = extractvalue { i32, i1 } %tmp107, 0
+  %tmp111 = sdiv i32 %tmp110, 256
+  %tmp112 = add nsw i32 %tmp97, %tmp99
+  %tmp113 = sdiv i32 %tmp112, 256
+  %tmp114 = mul nuw nsw i32 %tmp83, 298
+  %tmp115 = add nsw i32 %tmp114, -4768
+  %tmp116 = add nsw i32 %tmp91, %tmp115
+  %tmp117 = sdiv i32 %tmp116, 256
+  %tmp118 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %tmp115, i32 %tmp95)
+  %tmp119 = extractvalue { i32, i1 } %tmp118, 1
+  br i1 %tmp119, label %bb104, label %bb120
+
+bb120:                                            ; preds = %bb109
+  %tmp121 = extractvalue { i32, i1 } %tmp118, 0
+  %tmp122 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %tmp121, i32 %tmp93)
+  %tmp123 = extractvalue { i32, i1 } %tmp122, 1
+  br i1 %tmp123, label %bb104, label %bb124
+
+bb124:                                            ; preds = %bb120
+  %tmp125 = sext i32 %tmp101 to i64
+  %tmp126 = getelementptr inbounds i8, i8* %arg2, i64 %tmp125
+  %tmp127 = load i8, i8* %tmp126, align 1
+  %tmp128 = zext i8 %tmp127 to i32
+  %tmp129 = lshr i32 %tmp128, 3
+  %tmp130 = shl nuw nsw i32 %tmp129, 11
+  %tmp131 = sext i32 %tmp111 to i64
+  %tmp132 = getelementptr inbounds i8, i8* %arg2, i64 %tmp131
+  %tmp133 = load i8, i8* %tmp132, align 1
+  %tmp134 = zext i8 %tmp133 to i32
+  %tmp135 = lshr i32 %tmp134, 2
+  %tmp136 = shl nuw nsw i32 %tmp135, 5
+  %tmp137 = or i32 %tmp136, %tmp130
+  %tmp138 = sext i32 %tmp113 to i64
+  %tmp139 = getelementptr inbounds i8, i8* %arg2, i64 %tmp138
+  %tmp140 = load i8, i8* %tmp139, align 1
+  %tmp141 = zext i8 %tmp140 to i32
+  %tmp142 = lshr i32 %tmp141, 3
+  %tmp143 = or i32 %tmp137, %tmp142
+  %tmp144 = icmp ult i64 %tmp80, %tmp75
+  br i1 %tmp144, label %bb145, label %bb173
+
+bb145:                                            ; preds = %bb124
+  %tmp146 = add nsw i32 %tmp97, %tmp115
+  %tmp147 = sdiv i32 %tmp146, 256
+  %tmp148 = sext i32 %tmp147 to i64
+  %tmp149 = getelementptr inbounds i8, i8* %arg2, i64 %tmp148
+  %tmp150 = load i8, i8* %tmp149, align 1
+  %tmp151 = extractvalue { i32, i1 } %tmp122, 0
+  %tmp152 = sdiv i32 %tmp151, 256
+  %tmp153 = sext i32 %tmp152 to i64
+  %tmp154 = getelementptr inbounds i8, i8* %arg2, i64 %tmp153
+  %tmp155 = load i8, i8* %tmp154, align 1
+  %tmp156 = sext i32 %tmp117 to i64
+  %tmp157 = getelementptr inbounds i8, i8* %arg2, i64 %tmp156
+  %tmp158 = load i8, i8* %tmp157, align 1
+  %tmp159 = zext i8 %tmp158 to i32
+  %tmp160 = lshr i32 %tmp159, 3
+  %tmp161 = shl nuw nsw i32 %tmp160, 11
+  %tmp162 = zext i8 %tmp155 to i32
+  %tmp163 = lshr i32 %tmp162, 2
+  %tmp164 = shl nuw nsw i32 %tmp163, 5
+  %tmp165 = zext i8 %tmp150 to i32
+  %tmp166 = lshr i32 %tmp165, 3
+  %tmp167 = or i32 %tmp164, %tmp166
+  %tmp168 = or i32 %tmp167, %tmp161
+  %tmp169 = shl nuw i32 %tmp168, 16
+  %tmp170 = or i32 %tmp169, %tmp143
+  %tmp171 = getelementptr inbounds i16, i16* %tmp44, i64 %tmp76
+  %tmp172 = bitcast i16* %tmp171 to i32*
+  store i32 %tmp170, i32* %tmp172, align 4
+  br label %bb176
+
+bb173:                                            ; preds = %bb124
+  %tmp174 = trunc i32 %tmp143 to i16
+  %tmp175 = getelementptr inbounds i16, i16* %tmp44, i64 %tmp76
+  store i16 %tmp174, i16* %tmp175, align 2
+  br label %bb176
+
+bb176:                                            ; preds = %bb173, %bb145
+  %tmp177 = add i64 %tmp76, 2
+  %tmp178 = load i64, i64* %tmp35, align 8
+  %tmp179 = load i64, i64* %tmp11, align 8
+  %tmp180 = add i64 %tmp178, 1
+  %tmp181 = sub i64 %tmp180, %tmp179
+  %tmp182 = icmp ult i64 %tmp177, %tmp181
+  br i1 %tmp182, label %bb74, label %bb52
+}
+
+; Function Attrs: noreturn nounwind
+declare void @llvm.trap() #0
+
+; Function Attrs: nounwind readnone speculatable
+declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1
+
+attributes #0 = { noreturn nounwind }
+attributes #1 = { nounwind readnone speculatable }
diff --git a/final/test/ScopInfo/long-sequence-of-error-blocks-2.ll b/final/test/ScopInfo/long-sequence-of-error-blocks-2.ll
new file mode 100644
index 0000000..5d7b9d9
--- /dev/null
+++ b/final/test/ScopInfo/long-sequence-of-error-blocks-2.ll
@@ -0,0 +1,148 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.hoge = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [8 x [2 x i32]], [8 x [2 x i32]], [4 x [4 x i32]], i32, i32, i32, i32, [256 x i8], [256 x i8], [256 x i8], [256 x i8], [256 x i8], i32, i32, i32, i32, i32, i32, [500 x i8], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [256 x i8], [256 x i8], [256 x i8], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [1024 x i8], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, double, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [256 x i8], [256 x i8], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [256 x i8], i32, i32, i32*, i32*, i8*, i32*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, double, double, double, [5 x double], i32, [8 x i32], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [6 x double], [6 x double], [256 x i8], i32, i32, i32, i32, [2 x [5 x i32]], [2 x [5 x i32]], i32, i32, i32, i32, i32, i32, i32, i32, i32, [3 x i32], i32 }
+
+; The execution context of invalid loads in this test case has at some point become very complex and we should bail.
+; CHECK-NOT: Statements
+
+@global = external global [300 x i8], align 16
+@global1 = external global %struct.hoge*, align 8
+@global2 = external unnamed_addr constant [79 x i8], align 1
+@global3 = external unnamed_addr constant [57 x i8], align 1
+
+declare void @widget() #0
+
+; Function Attrs: nounwind
+declare void @quux(i8*, i64, i8*, ...) #1
+
+; Function Attrs: nounwind uwtable
+define void @hoge(float* %A) #2 {
+bb:
+  br label %bb15
+
+bb15:                                             ; preds = %bb
+  %tmp = load %struct.hoge*, %struct.hoge** @global1, align 8, !tbaa !1
+  %tmp16 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp, i64 0, i32 153
+  store float 1.0, float* %A
+  %tmp17 = load i32, i32* %tmp16, align 4, !tbaa !5
+  %tmp18 = icmp eq i32 %tmp17, 0
+  br i1 %tmp18, label %bb24, label %bb19
+
+bb19:                                             ; preds = %bb15
+  %tmp20 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp, i64 0, i32 50
+  store float 1.0, float* %A
+  %tmp21 = load i32, i32* %tmp20, align 8, !tbaa !9
+  %tmp22 = icmp eq i32 %tmp21, 0
+  br i1 %tmp22, label %bb24, label %bb23
+
+bb23:                                             ; preds = %bb19
+  call void @widget() #3
+  br label %bb24
+
+bb24:                                             ; preds = %bb23, %bb19, %bb15
+  %tmp25 = load %struct.hoge*, %struct.hoge** @global1, align 8, !tbaa !1
+  store float 1.0, float* %A
+  %tmp26 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp25, i64 0, i32 16
+  %tmp27 = load i32, i32* %tmp26, align 8, !tbaa !10
+  %tmp28 = icmp eq i32 %tmp27, 3
+  br i1 %tmp28, label %bb29, label %bb34
+
+bb29:                                             ; preds = %bb24
+  %tmp30 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp25, i64 0, i32 0
+  store float 1.0, float* %A
+  %tmp31 = load i32, i32* %tmp30, align 8, !tbaa !11
+  %tmp32 = icmp slt i32 %tmp31, 144
+  br i1 %tmp32, label %bb33, label %bb34
+
+bb33:                                             ; preds = %bb29
+  call void (i8*, i64, i8*, ...) @quux(i8* getelementptr inbounds ([300 x i8], [300 x i8]* @global, i64 0, i64 0), i64 300, i8* getelementptr inbounds ([79 x i8], [79 x i8]* @global2, i64 0, i64 0), i32 144) #3
+  br label %bb34
+
+bb34:                                             ; preds = %bb33, %bb29, %bb24
+  %tmp35 = load %struct.hoge*, %struct.hoge** @global1, align 8, !tbaa !1
+  store float 1.0, float* %A
+  %tmp36 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp35, i64 0, i32 40
+  %tmp37 = load i32, i32* %tmp36, align 8, !tbaa !12
+  %tmp38 = icmp eq i32 %tmp37, 0
+  br i1 %tmp38, label %bb49, label %bb39
+
+bb39:                                             ; preds = %bb34
+  %tmp40 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp35, i64 0, i32 46
+  store float 1.0, float* %A
+  %tmp41 = load i32, i32* %tmp40, align 8, !tbaa !13
+  %tmp42 = icmp eq i32 %tmp41, 0
+  br i1 %tmp42, label %bb49, label %bb43
+
+bb43:                                             ; preds = %bb39
+  %tmp44 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp35, i64 0, i32 7
+  store float 1.0, float* %A
+  %tmp45 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp35, i64 0, i32 48
+  %tmp46 = load i32, i32* %tmp45, align 8, !tbaa !14
+  %tmp47 = icmp slt i32 0, %tmp46
+  br i1 %tmp47, label %bb48, label %bb49
+
+bb48:                                             ; preds = %bb43
+  call void @widget() #3
+  br label %bb49
+
+bb49:                                             ; preds = %bb48, %bb43, %bb39, %bb34
+  store float 1.0, float* %A
+  %tmp50 = load %struct.hoge*, %struct.hoge** @global1, align 8, !tbaa !1
+  %tmp51 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp50, i64 0, i32 198
+  %tmp52 = load i32, i32* %tmp51, align 8, !tbaa !15
+  %tmp53 = icmp eq i32 %tmp52, 0
+  br i1 %tmp53, label %bb59, label %bb54
+
+bb54:                                             ; preds = %bb49
+  store float 1.0, float* %A
+  %tmp55 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp50, i64 0, i32 16
+  %tmp56 = load i32, i32* %tmp55, align 8, !tbaa !10
+  %tmp57 = icmp eq i32 %tmp56, 0
+  br i1 %tmp57, label %bb58, label %bb59
+
+bb58:                                             ; preds = %bb54
+  call void (i8*, i64, i8*, ...) @quux(i8* getelementptr inbounds ([300 x i8], [300 x i8]* @global, i64 0, i64 0), i64 300, i8* getelementptr inbounds ([57 x i8], [57 x i8]* @global3, i64 0, i64 0)) #3
+  br label %bb59
+
+bb59:                                             ; preds = %bb58, %bb54, %bb49
+  store float 1.0, float* %A
+  %tmp60 = load %struct.hoge*, %struct.hoge** @global1, align 8, !tbaa !1
+  %tmp61 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp60, i64 0, i32 31
+  %tmp62 = load i32, i32* %tmp61, align 4, !tbaa !16
+  %tmp63 = icmp eq i32 %tmp62, 0
+  br i1 %tmp63, label %bb65, label %bb64
+
+bb64:                                             ; preds = %bb59
+  br label %bb65
+
+bb65:                                             ; preds = %bb64, %bb59
+  ret void
+}
+
+attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 252261) (llvm/trunk 252271)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"any pointer", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!6, !7, i64 5100}
+!6 = !{!"", !7, i64 0, !7, i64 4, !7, i64 8, !7, i64 12, !7, i64 16, !7, i64 20, !7, i64 24, !7, i64 28, !7, i64 32, !7, i64 36, !7, i64 40, !7, i64 44, !7, i64 48, !7, i64 52, !7, i64 56, !7, i64 60, !7, i64 64, !7, i64 68, !3, i64 72, !3, i64 136, !3, i64 200, !7, i64 264, !7, i64 268, !7, i64 272, !7, i64 276, !3, i64 280, !3, i64 536, !3, i64 792, !3, i64 1048, !3, i64 1304, !7, i64 1560, !7, i64 1564, !7, i64 1568, !7, i64 1572, !7, i64 1576, !7, i64 1580, !3, i64 1584, !7, i64 2084, !7, i64 2088, !7, i64 2092, !7, i64 2096, !7, i64 2100, !7, i64 2104, !7, i64 2108, !7, i64 2112, !7, i64 2116, !7, i64 2120, !7, i64 2124, !7, i64 2128, !7, i64 2132, !7, i64 2136, !7, i64 2140, !7, i64 2144, !7, i64 2148, !7, i64 2152, !7, i64 2156, !3, i64 2160, !3, i64 2416, !3, i64 2672, !7, i64 2928, !7, i64 2932, !7, i64 2936, !7, i64 2940, !7, i64 2944, !7, i64 2948, !7, i64 2952, !7, i64 2956, !7, i64 2960, !7, i64 2964, !7, i64 2968, !7, i64 2972, !3, i64 2976, !7, i64 4000, !7, i64 4004, !7, i64 4008, !7, i64 4012, !7, i64 4016, !7, i64 4020, !7, i64 4024, !7, i64 4028, !7, i64 4032, !7, i64 4036, !7, i64 4040, !7, i64 4044, !7, i64 4048, !7, i64 4052, !7, i64 4056, !7, i64 4060, !7, i64 4064, !7, i64 4068, !7, i64 4072, !7, i64 4076, !8, i64 4080, !7, i64 4088, !7, i64 4092, !7, i64 4096, !7, i64 4100, !7, i64 4104, !7, i64 4108, !7, i64 4112, !7, i64 4116, !7, i64 4120, !7, i64 4124, !7, i64 4128, !7, i64 4132, !7, i64 4136, !7, i64 4140, !7, i64 4144, !7, i64 4148, !7, i64 4152, !7, i64 4156, !7, i64 4160, !7, i64 4164, !7, i64 4168, !7, i64 4172, !7, i64 4176, !7, i64 4180, !7, i64 4184, !7, i64 4188, !3, i64 4192, !3, i64 4448, !7, i64 4704, !7, i64 4708, !7, i64 4712, !7, i64 4716, !7, i64 4720, !7, i64 4724, !7, i64 4728, !7, i64 4732, !7, i64 4736, !7, i64 4740, !7, i64 4744, !7, i64 4748, !7, i64 4752, !7, i64 4756, !7, i64 4760, !7, i64 4764, !7, i64 4768, !7, i64 4772, !3, i64 4776, !7, i64 5032, !7, i64 5036, !2, i64 5040, !2, i64 5048, !2, i64 5056, !2, i64 5064, !7, i64 5072, !7, i64 5076, !7, i64 5080, !7, i64 5084, !7, i64 5088, !7, i64 5092, !7, i64 5096, !7, i64 5100, !7, i64 5104, !7, i64 5108, !7, i64 5112, !7, i64 5116, !7, i64 5120, !7, i64 5124, !7, i64 5128, !7, i64 5132, !7, i64 5136, !8, i64 5144, !8, i64 5152, !8, i64 5160, !3, i64 5168, !7, i64 5208, !3, i64 5212, !3, i64 5244, !7, i64 5248, !7, i64 5252, !7, i64 5256, !7, i64 5260, !7, i64 5264, !7, i64 5268, !7, i64 5272, !7, i64 5276, !7, i64 5280, !7, i64 5284, !7, i64 5288, !3, i64 5296, !3, i64 5344, !3, i64 5392, !7, i64 5648, !7, i64 5652, !7, i64 5656, !7, i64 5660, !3, i64 5664, !3, i64 5704, !7, i64 5744, !7, i64 5748, !7, i64 5752, !7, i64 5756, !7, i64 5760, !7, i64 5764, !7, i64 5768, !7, i64 5772, !7, i64 5776, !3, i64 5780, !7, i64 5792}
+!7 = !{!"int", !3, i64 0}
+!8 = !{!"double", !3, i64 0}
+!9 = !{!6, !7, i64 2136}
+!10 = !{!6, !7, i64 64}
+!11 = !{!6, !7, i64 0}
+!12 = !{!6, !7, i64 2096}
+!13 = !{!6, !7, i64 2120}
+!14 = !{!6, !7, i64 2128}
+!15 = !{!6, !7, i64 5776}
+!16 = !{!6, !7, i64 1564}
diff --git a/final/test/ScopInfo/long-sequence-of-error-blocks.ll b/final/test/ScopInfo/long-sequence-of-error-blocks.ll
new file mode 100644
index 0000000..d367a90
--- /dev/null
+++ b/final/test/ScopInfo/long-sequence-of-error-blocks.ll
@@ -0,0 +1,129 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.hoge = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [8 x [2 x i32]], [8 x [2 x i32]], [4 x [4 x i32]], i32, i32, i32, i32, [256 x i8], [256 x i8], [256 x i8], [256 x i8], [256 x i8], i32, i32, i32, i32, i32, i32, [500 x i8], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [256 x i8], [256 x i8], [256 x i8], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [1024 x i8], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, double, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [256 x i8], [256 x i8], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [256 x i8], i32, i32, i32*, i32*, i8*, i32*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, double, double, double, [5 x double], i32, [8 x i32], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, [6 x double], [6 x double], [256 x i8], i32, i32, i32, i32, [2 x [5 x i32]], [2 x [5 x i32]], i32, i32, i32, i32, i32, i32, i32, i32, i32, [3 x i32], i32 }
+
+; This test case contains a long sequence of branch instructions together with
+; function calls that are considered 'error blocks'. We verify that the
+; iteration spaces are not overly complicated.
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> {  :  }
+; CHECK:      Invalid Context:
+; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> { : (tmp27 = 3 and tmp31 <= 143) or (tmp17 < 0 and tmp21 < 0) or (tmp17 < 0 and tmp21 > 0) or (tmp17 > 0 and tmp21 < 0) or (tmp17 > 0 and tmp21 > 0) }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb15
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb15[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb15[] -> [0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb15[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_bb19
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb19[] : tmp17 < 0 or tmp17 > 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb19[] -> [1] : tmp17 < 0 or tmp17 > 0 };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb19[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_bb24
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb24[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb24[] -> [2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb24[] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_bb29
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb29[] : tmp27 = 3 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb29[] -> [3] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [tmp17, tmp21, tmp27, tmp31] -> { Stmt_bb29[] -> MemRef_A[0] };
+; CHECK-NEXT: }
+
+@global = external global [300 x i8], align 16
+@global1 = external global %struct.hoge*, align 8
+@global2 = external unnamed_addr constant [79 x i8], align 1
+@global3 = external unnamed_addr constant [57 x i8], align 1
+
+declare void @widget() #0
+
+; Function Attrs: nounwind
+declare void @quux(i8*, i64, i8*, ...) #1
+
+; Function Attrs: nounwind uwtable
+define void @hoge(float* %A) #2 {
+bb:
+  br label %bb15
+
+bb15:                                             ; preds = %bb
+  %tmp = load %struct.hoge*, %struct.hoge** @global1, align 8, !tbaa !1
+  %tmp16 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp, i64 0, i32 153
+  store float 1.0, float* %A
+  %tmp17 = load i32, i32* %tmp16, align 4, !tbaa !5
+  %tmp18 = icmp eq i32 %tmp17, 0
+  br i1 %tmp18, label %bb24, label %bb19
+
+bb19:                                             ; preds = %bb15
+  %tmp20 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp, i64 0, i32 50
+  store float 1.0, float* %A
+  %tmp21 = load i32, i32* %tmp20, align 8, !tbaa !9
+  %tmp22 = icmp eq i32 %tmp21, 0
+  br i1 %tmp22, label %bb24, label %bb23
+
+bb23:                                             ; preds = %bb19
+  call void @widget() #3
+  br label %bb24
+
+bb24:                                             ; preds = %bb23, %bb19, %bb15
+  %tmp25 = load %struct.hoge*, %struct.hoge** @global1, align 8, !tbaa !1
+  store float 1.0, float* %A
+  %tmp26 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp25, i64 0, i32 16
+  %tmp27 = load i32, i32* %tmp26, align 8, !tbaa !10
+  %tmp28 = icmp eq i32 %tmp27, 3
+  br i1 %tmp28, label %bb29, label %bb34
+
+bb29:                                             ; preds = %bb24
+  %tmp30 = getelementptr inbounds %struct.hoge, %struct.hoge* %tmp25, i64 0, i32 0
+  store float 1.0, float* %A
+  %tmp31 = load i32, i32* %tmp30, align 8, !tbaa !11
+  %tmp32 = icmp slt i32 %tmp31, 144
+  br i1 %tmp32, label %bb33, label %bb34
+
+bb33:                                             ; preds = %bb29
+  call void (i8*, i64, i8*, ...) @quux(i8* getelementptr inbounds ([300 x i8], [300 x i8]* @global, i64 0, i64 0), i64 300, i8* getelementptr inbounds ([79 x i8], [79 x i8]* @global2, i64 0, i64 0), i32 144) #3
+  br label %bb34
+
+bb34:                                             ; preds = %bb33, %bb29, %bb24
+  ret void
+}
+
+attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 252261) (llvm/trunk 252271)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"any pointer", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!6, !7, i64 5100}
+!6 = !{!"", !7, i64 0, !7, i64 4, !7, i64 8, !7, i64 12, !7, i64 16, !7, i64 20, !7, i64 24, !7, i64 28, !7, i64 32, !7, i64 36, !7, i64 40, !7, i64 44, !7, i64 48, !7, i64 52, !7, i64 56, !7, i64 60, !7, i64 64, !7, i64 68, !3, i64 72, !3, i64 136, !3, i64 200, !7, i64 264, !7, i64 268, !7, i64 272, !7, i64 276, !3, i64 280, !3, i64 536, !3, i64 792, !3, i64 1048, !3, i64 1304, !7, i64 1560, !7, i64 1564, !7, i64 1568, !7, i64 1572, !7, i64 1576, !7, i64 1580, !3, i64 1584, !7, i64 2084, !7, i64 2088, !7, i64 2092, !7, i64 2096, !7, i64 2100, !7, i64 2104, !7, i64 2108, !7, i64 2112, !7, i64 2116, !7, i64 2120, !7, i64 2124, !7, i64 2128, !7, i64 2132, !7, i64 2136, !7, i64 2140, !7, i64 2144, !7, i64 2148, !7, i64 2152, !7, i64 2156, !3, i64 2160, !3, i64 2416, !3, i64 2672, !7, i64 2928, !7, i64 2932, !7, i64 2936, !7, i64 2940, !7, i64 2944, !7, i64 2948, !7, i64 2952, !7, i64 2956, !7, i64 2960, !7, i64 2964, !7, i64 2968, !7, i64 2972, !3, i64 2976, !7, i64 4000, !7, i64 4004, !7, i64 4008, !7, i64 4012, !7, i64 4016, !7, i64 4020, !7, i64 4024, !7, i64 4028, !7, i64 4032, !7, i64 4036, !7, i64 4040, !7, i64 4044, !7, i64 4048, !7, i64 4052, !7, i64 4056, !7, i64 4060, !7, i64 4064, !7, i64 4068, !7, i64 4072, !7, i64 4076, !8, i64 4080, !7, i64 4088, !7, i64 4092, !7, i64 4096, !7, i64 4100, !7, i64 4104, !7, i64 4108, !7, i64 4112, !7, i64 4116, !7, i64 4120, !7, i64 4124, !7, i64 4128, !7, i64 4132, !7, i64 4136, !7, i64 4140, !7, i64 4144, !7, i64 4148, !7, i64 4152, !7, i64 4156, !7, i64 4160, !7, i64 4164, !7, i64 4168, !7, i64 4172, !7, i64 4176, !7, i64 4180, !7, i64 4184, !7, i64 4188, !3, i64 4192, !3, i64 4448, !7, i64 4704, !7, i64 4708, !7, i64 4712, !7, i64 4716, !7, i64 4720, !7, i64 4724, !7, i64 4728, !7, i64 4732, !7, i64 4736, !7, i64 4740, !7, i64 4744, !7, i64 4748, !7, i64 4752, !7, i64 4756, !7, i64 4760, !7, i64 4764, !7, i64 4768, !7, i64 4772, !3, i64 4776, !7, i64 5032, !7, i64 5036, !2, i64 5040, !2, i64 5048, !2, i64 5056, !2, i64 5064, !7, i64 5072, !7, i64 5076, !7, i64 5080, !7, i64 5084, !7, i64 5088, !7, i64 5092, !7, i64 5096, !7, i64 5100, !7, i64 5104, !7, i64 5108, !7, i64 5112, !7, i64 5116, !7, i64 5120, !7, i64 5124, !7, i64 5128, !7, i64 5132, !7, i64 5136, !8, i64 5144, !8, i64 5152, !8, i64 5160, !3, i64 5168, !7, i64 5208, !3, i64 5212, !3, i64 5244, !7, i64 5248, !7, i64 5252, !7, i64 5256, !7, i64 5260, !7, i64 5264, !7, i64 5268, !7, i64 5272, !7, i64 5276, !7, i64 5280, !7, i64 5284, !7, i64 5288, !3, i64 5296, !3, i64 5344, !3, i64 5392, !7, i64 5648, !7, i64 5652, !7, i64 5656, !7, i64 5660, !3, i64 5664, !3, i64 5704, !7, i64 5744, !7, i64 5748, !7, i64 5752, !7, i64 5756, !7, i64 5760, !7, i64 5764, !7, i64 5768, !7, i64 5772, !7, i64 5776, !3, i64 5780, !7, i64 5792}
+!7 = !{!"int", !3, i64 0}
+!8 = !{!"double", !3, i64 0}
+!9 = !{!6, !7, i64 2136}
+!10 = !{!6, !7, i64 64}
+!11 = !{!6, !7, i64 0}
+!12 = !{!6, !7, i64 2096}
+!13 = !{!6, !7, i64 2120}
+!14 = !{!6, !7, i64 2128}
+!15 = !{!6, !7, i64 5776}
+!16 = !{!6, !7, i64 1564}
diff --git a/final/test/ScopInfo/loop-multiexit-succ-cond.ll b/final/test/ScopInfo/loop-multiexit-succ-cond.ll
new file mode 100644
index 0000000..368226f
--- /dev/null
+++ b/final/test/ScopInfo/loop-multiexit-succ-cond.ll
@@ -0,0 +1,97 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s --check-prefix=IR
+;
+; Check that we do not crash and generate valid IR.
+;
+; CHECK:      Assumed Context:
+; CHECK-NEXT:   [count1, dobreak, count2] -> {  :  }
+; CHECK-NEXT: Invalid Context:
+; CHECK-NEXT:   [count1, dobreak, count2] -> {  : (count1 > 0 and dobreak > 0) or count1 <= 0 or (count1 > 0 and dobreak <= 0 and count2 > 0) }
+;
+; CHECK:      Stmt_loop_enter
+; CHECK-NEXT:     Domain :=
+; CHECK-NEXT:         [count1, dobreak, count2] -> { Stmt_loop_enter[] : count1 > 0 };
+
+; CHECK:      Stmt_loop_break
+; CHECK-NEXT:     Domain :=
+; CHECK-NEXT:         [count1, dobreak, count2] -> { Stmt_loop_break[] : count1 > 0 and dobreak > 0 };
+
+; CHECK:      Stmt_loop_finish
+; CHECK-NEXT:     Domain :=
+; CHECK-NEXT:         [count1, dobreak, count2] -> { Stmt_loop_finish[] : count1 > 0 and dobreak <= 0 and count2 > 0 };
+
+; CHECK:      Stmt_loop_skip
+; CHECK-NEXT:     Domain :=
+; CHECK-NEXT:         [count1, dobreak, count2] -> { Stmt_loop_skip[] : count1 <= 0 };
+
+; IR:      polly.merge_new_and_old:
+; IR-NEXT:   %phi.ph.merge = phi float [ %phi.ph.final_reload, %polly.exiting ], [ %phi.ph, %return.region_exiting ]
+; IR-NEXT:   br label %return
+;
+; IR:      return:
+; IR-NEXT:   %phi = phi float [ %phi.ph.merge, %polly.merge_new_and_old ]
+
+declare void @g();
+
+define void @func(i64 %count1, i64 %count2, i32 %dobreak, float* %A) {
+entry:
+  %fadd = fadd float undef, undef
+  br label %loopguard
+
+loopguard:
+  %cmp6 = icmp sgt i64 %count1, 0
+  br i1 %cmp6, label %loop_enter, label %loop_skip
+
+
+loop_enter:
+  store float 1.0, float* %A
+  br label %loop_header
+
+loop_header:
+  %indvars.iv63 = phi i64 [ %indvars.iv.next64, %loop_continue ], [ 0, %loop_enter ]
+  %indvars.iv.next64 = add nuw nsw i64 %indvars.iv63, 1
+  %add8 = add i64 undef, undef
+  %cmp_break = icmp sge i32 %dobreak, 1
+  br i1 %cmp_break, label %loop_break, label %loop_continue
+
+loop_continue:
+  %cmp9 = icmp eq i64 %indvars.iv.next64, %count2
+  br i1 %cmp9, label %loop_finish, label %loop_header
+
+
+loop_break:
+  store float 2.0, float* %A
+  br label %loop_break_error
+
+loop_break_error:
+  %cmp_loop_break = fcmp oeq float %fadd, 2.
+  br i1 %cmp_loop_break, label %loop_break_g, label %return
+
+loop_break_g:
+  call void @g()
+  br label %return
+
+
+loop_finish:
+    store float 3.0, float* %A
+  br label %loop_finish_error
+
+loop_finish_error:
+  call void @g()
+  br label %return
+
+
+loop_skip:
+  store float 4.0, float* %A
+  br label %loop_skip_error
+
+loop_skip_error:
+  call void @g()
+  br label %return
+
+
+return:
+  %phi = phi float [ 0.0, %loop_finish_error ], [ 0.0, %loop_break_error ], [ 2.0, %loop_break_g ], [ 3.0, %loop_skip_error ]
+  store float 1.0, float* %A
+  ret void
+}
diff --git a/final/test/ScopInfo/loop_affine_bound_0.ll b/final/test/ScopInfo/loop_affine_bound_0.ll
new file mode 100644
index 0000000..2801763
--- /dev/null
+++ b/final/test/ScopInfo/loop_affine_bound_0.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-function-scops -analyze < %s | FileCheck %s
+
+; void f(long a[][128], long N, long M) {
+;   long i, j;
+;   for (j = 0; j < (4*N + 7*M +3); ++j)
+;     for (i = 0; i < (5*N + 2); ++i)
+;       a[j][i] = 0
+;   }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f([128 x i64]* nocapture %a, i64 %N, i64 %M) nounwind {
+entry:
+  %0 = shl i64 %N, 2                              ; <i64> [#uses=2]
+  %1 = mul i64 %M, 7                              ; <i64> [#uses=2]
+  %2 = or i64 %0, 3                               ; <i64> [#uses=1]
+  %3 = add nsw i64 %2, %1                         ; <i64> [#uses=1]
+  %4 = icmp sgt i64 %3, 0                         ; <i1> [#uses=1]
+  br i1 %4, label %bb.nph8, label %return
+
+bb1:                                              ; preds = %bb2.preheader, %bb1
+  %i.06 = phi i64 [ 0, %bb2.preheader ], [ %5, %bb1 ] ; <i64> [#uses=2]
+  %scevgep = getelementptr [128 x i64], [128 x i64]* %a, i64 %i.06, i64 %10 ; <i64*> [#uses=1]
+  store i64 0, i64* %scevgep, align 8
+  %5 = add nsw i64 %i.06, 1                       ; <i64> [#uses=2]
+  %exitcond = icmp eq i64 %5, %8                  ; <i1> [#uses=1]
+  br i1 %exitcond, label %bb3, label %bb1
+
+bb3:                                              ; preds = %bb1
+  %6 = add i64 %10, 1                             ; <i64> [#uses=2]
+  %exitcond14 = icmp eq i64 %6, %tmp13            ; <i1> [#uses=1]
+  br i1 %exitcond14, label %return, label %bb2.preheader
+
+bb.nph8:                                          ; preds = %entry
+  %7 = mul i64 %N, 5                              ; <i64> [#uses=1]
+  %8 = add nsw i64 %7, 2                          ; <i64> [#uses=2]
+  %9 = icmp sgt i64 %8, 0                         ; <i1> [#uses=1]
+  br i1 %9, label %bb.nph8.split, label %return
+
+bb.nph8.split:                                    ; preds = %bb.nph8
+  %tmp12 = add i64 %1, %0                         ; <i64> [#uses=1]
+  %tmp13 = add i64 %tmp12, 3                      ; <i64> [#uses=1]
+  br label %bb2.preheader
+
+bb2.preheader:                                    ; preds = %bb.nph8.split, %bb3
+  %10 = phi i64 [ 0, %bb.nph8.split ], [ %6, %bb3 ] ; <i64> [#uses=2]
+  br label %bb1
+
+return:                                           ; preds = %bb.nph8, %bb3, %entry
+  ret void
+}
+
+
+; CHECK:      p0: %N
+; CHECK-NEXT: p1: %M
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, M] -> { Stmt_bb1[i0, i1] : 0 <= i0 <= 2 + 4N + 7M and 0 <= i1 <= 1 + 5N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, M] -> { Stmt_bb1[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N, M] -> { Stmt_bb1[i0, i1] -> MemRef_a[i1, i0] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/loop_affine_bound_1.ll b/final/test/ScopInfo/loop_affine_bound_1.ll
new file mode 100644
index 0000000..9237b8a
--- /dev/null
+++ b/final/test/ScopInfo/loop_affine_bound_1.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-function-scops -analyze < %s | FileCheck %s
+
+;void f(long a[][128], long N, long M) {
+;  long i, j;
+;  for (j = 0; j < (4*N + 7*M +3); ++j)
+;    for (i = j; i < (5*N + 2); ++i)
+;        ...
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f([128 x i64]* nocapture %a, i64 %N, i64 %M) nounwind {
+entry:
+  %0 = shl i64 %N, 2                              ; <i64> [#uses=2]
+  %1 = mul i64 %M, 7                              ; <i64> [#uses=2]
+  %2 = or i64 %0, 3                               ; <i64> [#uses=1]
+  %3 = add nsw i64 %2, %1                         ; <i64> [#uses=1]
+  %4 = icmp sgt i64 %3, 0                         ; <i1> [#uses=1]
+  br i1 true, label %bb.nph8, label %return
+
+bb1:                                              ; preds = %bb2.preheader, %bb1
+  %indvar = phi i64 [ 0, %bb2.preheader ], [ %indvar.next, %bb1 ] ; <i64> [#uses=2]
+  %scevgep = getelementptr [128 x i64], [128 x i64]* %a, i64 %indvar, i64 %tmp10 ; <i64*> [#uses=1]
+  store i64 0, i64* %scevgep, align 8
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=2]
+  %exitcond = icmp sge i64 %indvar.next, %tmp9     ; <i1> [#uses=1]
+  br i1 %exitcond, label %bb3, label %bb1
+
+bb3:                                              ; preds = %bb2.preheader, %bb1
+  %5 = add i64 %8, 1                              ; <i64> [#uses=2]
+  %exitcond14 = icmp sge i64 %5, %tmp13            ; <i1> [#uses=1]
+  br i1 %exitcond14, label %return, label %bb2.preheader
+
+bb.nph8:                                          ; preds = %entry
+  %6 = mul i64 %N, 5                              ; <i64> [#uses=1]
+  %7 = add nsw i64 %6, 2                          ; <i64> [#uses=2]
+  %tmp12 = add i64 %1, %0                         ; <i64> [#uses=1]
+  %tmp13 = add i64 %tmp12, 3                      ; <i64> [#uses=1]
+  br label %bb2.preheader
+
+bb2.preheader:                                    ; preds = %bb.nph8, %bb3
+  %8 = phi i64 [ 0, %bb.nph8 ], [ %5, %bb3 ]      ; <i64> [#uses=4]
+  %tmp10 = mul i64 %8, 129                        ; <i64> [#uses=1]
+  %tmp9 = sub i64 %7, %8                          ; <i64> [#uses=1]
+  %9 = icmp sgt i64 %7, %8                        ; <i1> [#uses=1]
+  br i1 %9, label %bb1, label %bb3
+
+return:                                           ; preds = %bb3, %entry
+  ret void
+}
+
+
+; CHECK:      p0: %N
+; CHECK-NEXT: p1: %M
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, M] -> { Stmt_bb1[i0, i1] : 0 <= i0 <= 2 + 4N + 7M and 0 <= i1 <= 1 + 5N - i0; Stmt_bb1[0, i1] : 7M <= -3 - 4N and 0 <= i1 <= 1 + 5N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, M] -> { Stmt_bb1[i0, i1] -> [i0, i1] : i0 <= 2 + 4N + 7M; Stmt_bb1[0, i1] -> [0, i1] : 7M <= -3 - 4N };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N, M] -> { Stmt_bb1[i0, i1] -> MemRef_a[i1, 129i0] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/loop_affine_bound_2.ll b/final/test/ScopInfo/loop_affine_bound_2.ll
new file mode 100644
index 0000000..4ebaf71
--- /dev/null
+++ b/final/test/ScopInfo/loop_affine_bound_2.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-function-scops -analyze < %s | FileCheck %s
+
+; void f(long a[][128], long N, long M) {
+;   long i, j;
+;   for (j = 0; j < (4*N + 7*M +3); ++j)
+;     for (i = (7*j + 6*M -9); i < (3*j + 5*N + 2) ; ++i)
+;         a[i][j] = 0;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f([128 x i64]* nocapture %a, i64 %N, i64 %M) nounwind {
+entry:
+  %0 = shl i64 %N, 2
+  %1 = mul i64 %M, 7
+  %2 = or i64 %0, 3
+  %3 = add nsw i64 %2, %1
+  %4 = icmp sgt i64 %3, 0
+  br i1 %4, label %bb.nph8, label %return
+
+bb.nph8:                                          ; preds = %entry
+  %tmp14 = mul i64 %M, 6
+  %tmp15 = add i64 %tmp14, -9
+  %tmp20 = add i64 %1, %0
+  %tmp21 = add i64 %tmp20, 3
+  %tmp25 = mul i64 %M, -6
+  %tmp26 = mul i64 %N, 5
+  %tmp27 = add i64 %tmp25, %tmp26
+  %tmp28 = add i64 %tmp27, 11
+  %tmp35 = add i64 %tmp26, 2
+  br label %bb
+
+bb:                                               ; preds = %bb3, %bb.nph8
+  %j.07 = phi i64 [ 0, %bb.nph8 ], [ %6, %bb3 ]
+  %tmp17 = mul i64 %j.07, 897
+  %tmp24 = mul i64 %j.07, -4
+  %tmp13 = add i64 %tmp24, %tmp28
+  %tmp30 = mul i64 %j.07, 7
+  %tmp33 = add i64 %tmp30, %tmp15
+  %tmp34 = mul i64 %j.07, 3
+  %tmp36 = add i64 %tmp34, %tmp35
+  %5 = icmp sgt i64 %tmp36, %tmp33
+  br i1 %5, label %bb1, label %bb3
+
+bb1:                                              ; preds = %bb1, %bb
+  %indvar = phi i64 [ 0, %bb ], [ %indvar.next, %bb1 ]
+  %tmp16 = add i64 %indvar, %tmp15
+  %scevgep = getelementptr [128 x i64], [128 x i64]* %a, i64 %tmp16, i64 %tmp17
+  store i64 0, i64* %scevgep
+  %indvar.next = add i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %tmp13
+  br i1 %exitcond, label %bb3, label %bb1
+
+bb3:                                              ; preds = %bb1, %bb
+  %6 = add nsw i64 %j.07, 1
+  %exitcond22 = icmp eq i64 %6, %tmp21
+  br i1 %exitcond22, label %return, label %bb
+
+return:                                           ; preds = %bb3, %entry
+  ret void
+}
+
+
+; CHECK:      p0: %N
+; CHECK-NEXT: p1: %M
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, M] -> { Stmt_bb1[i0, i1] : 0 <= i0 <= 2 + 4N + 7M and 0 <= i1 <= 10 + 5N - 6M - 4i0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, M] -> { Stmt_bb1[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N, M] -> { Stmt_bb1[i0, i1] -> MemRef_a[-9 + 6M + i1, 897i0] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/loop_carry.ll b/final/test/ScopInfo/loop_carry.ll
new file mode 100644
index 0000000..ea24010
--- /dev/null
+++ b/final/test/ScopInfo/loop_carry.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze < %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+;long f(long a[], long n) {
+;  long i, k;
+;  k = 1;
+;  for (i = 1; i < n; ++i) {
+;   a[i] = k * a[i - 1];
+;   k = a[i + 3] + a[2 * i];
+;  }
+;  return 0;
+;}
+
+define i64 @f(i64* nocapture %a, i64 %n) nounwind {
+entry:
+  %0 = icmp sgt i64 %n, 1                         ; <i1> [#uses=1]
+  br i1 %0, label %bb.nph, label %bb2
+
+bb.nph:                                           ; preds = %entry
+  %tmp = add i64 %n, -1                           ; <i64> [#uses=1]
+  %.pre = load i64, i64* %a, align 8                   ; <i64> [#uses=1]
+  br label %bb
+
+bb:                                               ; preds = %bb, %bb.nph
+  %tmp1 = phi i64 [ %.pre, %bb.nph ], [ %tmp2, %bb ]    ; <i64> [#uses=1]
+  %indvar = phi i64 [ 0, %bb.nph ], [ %tmp6, %bb ] ; <i64> [#uses=3]
+  %k.05 = phi i64 [ 1, %bb.nph ], [ %tmp5, %bb ]     ; <i64> [#uses=1]
+  %tmp6 = add i64 %indvar, 1                      ; <i64> [#uses=3]
+  %scevgep = getelementptr i64, i64* %a, i64 %tmp6     ; <i64*> [#uses=1]
+  %tmp2 = mul nsw i64 %tmp1, %k.05                      ; <i64> [#uses=2]
+  store i64 %tmp2, i64* %scevgep, align 8
+  %tmp7 = shl i64 %indvar, 1                      ; <i64> [#uses=1]
+  %tmp11 = add i64 %indvar, 4                     ; <i64> [#uses=1]
+  %tmp8 = add i64 %tmp7, 2                        ; <i64> [#uses=1]
+  %scevgep12 = getelementptr i64, i64* %a, i64 %tmp11  ; <i64*> [#uses=1]
+  %scevgep9 = getelementptr i64, i64* %a, i64 %tmp8    ; <i64*> [#uses=1]
+  %tmp3 = load i64, i64* %scevgep9, align 8               ; <i64> [#uses=1]
+  %tmp4 = load i64, i64* %scevgep12, align 8              ; <i64> [#uses=1]
+  %tmp5 = add nsw i64 %tmp3, %tmp4                         ; <i64> [#uses=1]
+  %exitcond = icmp eq i64 %tmp6, %tmp             ; <i1> [#uses=1]
+  br i1 %exitcond, label %bb2, label %bb
+
+bb2:                                              ; preds = %bb, %entry
+  ret i64 0
+}
+
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_bb[i0] : 0 <= i0 <= -2 + n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_bb[i0] -> [i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n] -> { Stmt_bb[i0] -> MemRef_tmp1__phi[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n] -> { Stmt_bb[i0] -> MemRef_tmp1__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n] -> { Stmt_bb[i0] -> MemRef_k_05__phi[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n] -> { Stmt_bb[i0] -> MemRef_k_05__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bb[i0] -> MemRef_a[1 + i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bb[i0] -> MemRef_a[2 + 2i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_bb[i0] -> MemRef_a[4 + i0] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/many-scalar-dependences.ll b/final/test/ScopInfo/many-scalar-dependences.ll
new file mode 100644
index 0000000..92d409c
--- /dev/null
+++ b/final/test/ScopInfo/many-scalar-dependences.ll
@@ -0,0 +1,216 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(float a[100][100]) {
+;      float x;
+;
+;      for (int i = 0; i < 100; i++) {
+;        for (int j = 0; j < 100; j++) {
+;          for (int k = 0; k < 100; k++) {
+;            if (k == 0)
+;              x = 42;
+;            a[i][j] += x;
+;            x++;
+;          }
+;        }
+;      }
+;    }
+
+; The scop we generate for this kernel has a very large number of statements
+; and scalar data-dependences due to x being passed along as SSA value or PHI
+; node.
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb5
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb5[i0] : 0 <= i0 <= 100 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb5[i0] -> [i0, 0, 0, 0, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb5[i0] -> MemRef_x_0__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb5[i0] -> MemRef_x_0[] };
+; CHECK-NEXT:     Stmt_bb6
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb6[i0] : 0 <= i0 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb6[i0] -> [i0, 1, 0, 0, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb6[i0] -> MemRef_x_0[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb6[i0] -> MemRef_x_1__phi[] };
+; CHECK-NEXT:     Stmt_bb7
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] : 0 <= i0 <= 99 and 0 <= i1 <= 100 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> [i0, 2, i1, 0, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> MemRef_x_1__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> MemRef_x_1[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> MemRef_x_1_lcssa__phi[] };
+; CHECK-NEXT:     Stmt_bb8
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb8[i0, i1] : 0 <= i0 <= 99 and 0 <= i1 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb8[i0, i1] -> [i0, 2, i1, 1, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb8[i0, i1] -> MemRef_x_1[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb8[i0, i1] -> MemRef_x_2__phi[] };
+; CHECK-NEXT:     Stmt_bb9
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb9[i0, i1, i2] : 0 <= i0 <= 99 and 0 <= i1 <= 99 and 0 <= i2 <= 100 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb9[i0, i1, i2] -> [i0, 2, i1, 2, i2, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb9[i0, i1, i2] -> MemRef_x_2__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb9[i0, i1, i2] -> MemRef_x_2[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb9[i0, i1, i2] -> MemRef_x_2_lcssa__phi[] };
+; CHECK-NEXT:     Stmt_bb10
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb10[i0, i1, i2] : 0 <= i0 <= 99 and 0 <= i1 <= 99 and 0 <= i2 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb10[i0, i1, i2] -> [i0, 2, i1, 2, i2, 1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb10[i0, i1, i2] -> MemRef_x_2[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb10[i0, i1, i2] -> MemRef_x_3__phi[] };
+; CHECK-NEXT:     Stmt_bb11
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb11[i0, i1, 0] : 0 <= i0 <= 99 and 0 <= i1 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb11[i0, i1, i2] -> [i0, 2, i1, 2, 0, 2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb11[i0, i1, i2] -> MemRef_x_3__phi[] };
+; CHECK-NEXT:     Stmt_bb12
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb12[i0, i1, i2] : 0 <= i0 <= 99 and 0 <= i1 <= 99 and 0 <= i2 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb12[i0, i1, i2] -> [i0, 2, i1, 2, i2, 3] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb12[i0, i1, i2] -> MemRef_x_3__phi[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb12[i0, i1, i2] -> MemRef_a[i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb12[i0, i1, i2] -> MemRef_a[i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb12[i0, i1, i2] -> MemRef_x_3[] };
+; CHECK-NEXT:     Stmt_bb16
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb16[i0, i1, i2] : 0 <= i0 <= 99 and 0 <= i1 <= 99 and 0 <= i2 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb16[i0, i1, i2] -> [i0, 2, i1, 2, i2, 4] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb16[i0, i1, i2] -> MemRef_x_2__phi[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb16[i0, i1, i2] -> MemRef_x_3[] };
+; CHECK-NEXT:     Stmt_bb19
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb19[i0, i1] : 0 <= i0 <= 99 and 0 <= i1 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb19[i0, i1] -> [i0, 2, i1, 3, 0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb19[i0, i1] -> MemRef_x_2_lcssa[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb19[i0, i1] -> MemRef_x_2_lcssa__phi[] };
+; CHECK-NEXT:     Stmt_bb20
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb20[i0, i1] : 0 <= i0 <= 99 and 0 <= i1 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb20[i0, i1] -> [i0, 2, i1, 4, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb20[i0, i1] -> MemRef_x_2_lcssa[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb20[i0, i1] -> MemRef_x_1__phi[] };
+; CHECK-NEXT:     Stmt_bb21
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb21[i0] : 0 <= i0 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb21[i0] -> [i0, 3, 0, 0, 0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb21[i0] -> MemRef_x_1_lcssa[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb21[i0] -> MemRef_x_1_lcssa__phi[] };
+; CHECK-NEXT:     Stmt_bb22
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb22[i0] : 0 <= i0 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb22[i0] -> [i0, 4, 0, 0, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb22[i0] -> MemRef_x_1_lcssa[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb22[i0] -> MemRef_x_0__phi[] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f([100 x float]* %a) {
+bb:
+  br label %bb5
+
+bb5:                                              ; preds = %bb22, %bb
+  %indvars.iv2 = phi i64 [ %indvars.iv.next3, %bb22 ], [ 0, %bb ]
+  %x.0 = phi float [ undef, %bb ], [ %x.1.lcssa, %bb22 ]
+  %exitcond4 = icmp ne i64 %indvars.iv2, 100
+  br i1 %exitcond4, label %bb6, label %bb23
+
+bb6:                                              ; preds = %bb5
+  br label %bb7
+
+bb7:                                              ; preds = %bb20, %bb6
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb20 ], [ 0, %bb6 ]
+  %x.1 = phi float [ %x.0, %bb6 ], [ %x.2.lcssa, %bb20 ]
+  %exitcond1 = icmp ne i64 %indvars.iv, 100
+  br i1 %exitcond1, label %bb8, label %bb21
+
+bb8:                                              ; preds = %bb7
+  br label %bb9
+
+bb9:                                              ; preds = %bb16, %bb8
+  %x.2 = phi float [ %x.1, %bb8 ], [ %tmp17, %bb16 ]
+  %k.0 = phi i32 [ 0, %bb8 ], [ %tmp18, %bb16 ]
+  %exitcond = icmp ne i32 %k.0, 100
+  br i1 %exitcond, label %bb10, label %bb19
+
+bb10:                                             ; preds = %bb9
+  %tmp = icmp eq i32 %k.0, 0
+  br i1 %tmp, label %bb11, label %bb12
+
+bb11:                                             ; preds = %bb10
+  br label %bb12
+
+bb12:                                             ; preds = %bb11, %bb10
+  %x.3 = phi float [ 4.200000e+01, %bb11 ], [ %x.2, %bb10 ]
+  %tmp13 = getelementptr inbounds [100 x float], [100 x float]* %a, i64 %indvars.iv2, i64 %indvars.iv
+  %tmp14 = load float, float* %tmp13, align 4
+  %tmp15 = fadd float %tmp14, %x.3
+  store float %tmp15, float* %tmp13, align 4
+  br label %bb16
+
+bb16:                                             ; preds = %bb12
+  %tmp17 = fadd float %x.3, 1.000000e+00
+  %tmp18 = add nuw nsw i32 %k.0, 1
+  br label %bb9
+
+bb19:                                             ; preds = %bb9
+  %x.2.lcssa = phi float [ %x.2, %bb9 ]
+  br label %bb20
+
+bb20:                                             ; preds = %bb19
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb7
+
+bb21:                                             ; preds = %bb7
+  %x.1.lcssa = phi float [ %x.1, %bb7 ]
+  br label %bb22
+
+bb22:                                             ; preds = %bb21
+  %indvars.iv.next3 = add nuw nsw i64 %indvars.iv2, 1
+  br label %bb5
+
+bb23:                                             ; preds = %bb5
+  ret void
+}
diff --git a/final/test/ScopInfo/max-loop-depth.ll b/final/test/ScopInfo/max-loop-depth.ll
new file mode 100644
index 0000000..5012e7a
--- /dev/null
+++ b/final/test/ScopInfo/max-loop-depth.ll
@@ -0,0 +1,79 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void bar();
+;    void foo(int *A, int *B, long int N, long int M) {
+;      for (long int j = 0; j < M; ++j) {
+;        bar();
+;        for (long int i = 0; i < N; ++i)
+;          A[i] += 1;
+;        for (long int i = 0; i < N; ++i)
+;          A[i] += 1;
+;      }
+;    }
+;
+; Test to check that the scop only counts loop depth for loops fully contained
+; in the scop.
+; CHECK: Max Loop Depth: 1
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i32* %A, i32* %B, i64 %N, i64 %M) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc13, %entry
+  %j.0 = phi i64 [ 0, %entry ], [ %inc14, %for.inc13 ]
+  %cmp = icmp slt i64 %j.0, %M
+  br i1 %cmp, label %for.body, label %for.end15
+
+for.body:                                         ; preds = %for.cond
+  call void (...) @bar() #2
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %i.0 = phi i64 [ 0, %for.body ], [ %inc, %for.inc ]
+  %cmp2 = icmp slt i64 %i.0, %N
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 1
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.cond5
+
+for.cond5:                                        ; preds = %for.inc10, %for.end
+  %i4.0 = phi i64 [ 0, %for.end ], [ %inc11, %for.inc10 ]
+  %cmp6 = icmp slt i64 %i4.0, %N
+  br i1 %cmp6, label %for.body7, label %for.end12
+
+for.body7:                                        ; preds = %for.cond5
+  %arrayidx8 = getelementptr inbounds i32, i32* %A, i64 %i4.0
+  %tmp1 = load i32, i32* %arrayidx8, align 4
+  %add9 = add nsw i32 %tmp1, 1
+  store i32 %add9, i32* %arrayidx8, align 4
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.body7
+  %inc11 = add nuw nsw i64 %i4.0, 1
+  br label %for.cond5
+
+for.end12:                                        ; preds = %for.cond5
+  br label %for.inc13
+
+for.inc13:                                        ; preds = %for.end12
+  %inc14 = add nuw nsw i64 %j.0, 1
+  br label %for.cond
+
+for.end15:                                        ; preds = %for.cond
+  ret void
+}
+
+declare void @bar(...) #1
+
diff --git a/final/test/ScopInfo/memcpy-raw-source.ll b/final/test/ScopInfo/memcpy-raw-source.ll
new file mode 100644
index 0000000..309e963
--- /dev/null
+++ b/final/test/ScopInfo/memcpy-raw-source.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -basicaa -scoped-noalias -tbaa -polly-scops -analyze < %s
+;
+; Ensure that ScopInfo's alias analysis llvm.memcpy for,
+; like the AliasSetTracker, preserves bitcasts.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@tonemasks = external global [17 x [6 x [56 x float]]], align 16
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #0
+
+; Function Attrs: nounwind uwtable
+define void @setup_tone_curves() #1 {
+entry:
+  %workc = alloca [17 x [8 x [56 x float]]], align 16
+  br label %for.cond7.preheader
+
+for.cond7.preheader:                              ; preds = %for.cond7.preheader, %entry
+  %indvars.iv45 = phi i64 [ %indvars.iv.next46, %for.cond7.preheader ], [ 0, %entry ]
+  %indvars.iv.next46 = add nuw nsw i64 %indvars.iv45, 1
+  %exitcond48 = icmp ne i64 %indvars.iv.next46, 56
+  br i1 %exitcond48, label %for.cond7.preheader, label %for.body36
+
+for.body36:                                       ; preds = %for.body36, %for.cond7.preheader
+  %indvars.iv49 = phi i64 [ %indvars.iv.next50, %for.body36 ], [ 0, %for.cond7.preheader ]
+  %arraydecay42 = getelementptr inbounds [17 x [8 x [56 x float]]], [17 x [8 x [56 x float]]]* %workc, i64 0, i64 0, i64 0, i64 0
+  %0 = bitcast float* %arraydecay42 to i8*
+  %arraydecay47 = getelementptr inbounds [17 x [6 x [56 x float]]], [17 x [6 x [56 x float]]]* @tonemasks, i64 0, i64 0, i64 %indvars.iv49, i64 0
+  %1 = bitcast float* %arraydecay47 to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 224, i32 16, i1 false)
+  %indvars.iv.next50 = add nuw nsw i64 %indvars.iv49, 1
+  br i1 false, label %for.body36, label %for.end50
+
+for.end50:                                        ; preds = %for.body36
+  %arrayidx38 = getelementptr inbounds [17 x [8 x [56 x float]]], [17 x [8 x [56 x float]]]* %workc, i64 0, i64 0
+  %2 = bitcast [8 x [56 x float]]* %arrayidx38 to i8*
+  %arraydecay58 = getelementptr inbounds [17 x [6 x [56 x float]]], [17 x [6 x [56 x float]]]* @tonemasks, i64 0, i64 0, i64 0, i64 0
+  %3 = bitcast float* %arraydecay58 to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* %3, i64 224, i32 16, i1 false)
+  br label %for.body74
+
+for.body74:                                       ; preds = %for.body74, %for.end50
+  %indvars.iv53 = phi i64 [ %indvars.iv.next54, %for.body74 ], [ 0, %for.end50 ]
+  %arrayidx99 = getelementptr inbounds [17 x [8 x [56 x float]]], [17 x [8 x [56 x float]]]* %workc, i64 0, i64 0, i64 0, i64 %indvars.iv53
+  %4 = load float, float* %arrayidx99, align 4
+  store float undef, float* %arrayidx99, align 4
+  %indvars.iv.next54 = add nuw nsw i64 %indvars.iv53, 1
+  %exitcond57 = icmp ne i64 %indvars.iv.next54, 56
+  br i1 %exitcond57, label %for.body74, label %for.inc104
+
+for.inc104:                                       ; preds = %for.body74
+  ret void
+}
+
+attributes #0 = { argmemonly nounwind }
+attributes #1 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 4.0.0 (trunk 285057) (llvm/trunk 285063)"}
diff --git a/final/test/ScopInfo/memcpy.ll b/final/test/ScopInfo/memcpy.ll
new file mode 100644
index 0000000..df56c45
--- /dev/null
+++ b/final/test/ScopInfo/memcpy.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -basicaa -polly-allow-differing-element-types -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -S -basicaa -polly-allow-differing-element-types -polly-codegen < %s | FileCheck --check-prefix=IR %s
+;
+; CHECK:         Arrays {
+; CHECK-NEXT:        i8 MemRef_A[*]; // Element size 1
+; CHECK-NEXT:        i8 MemRef_B[*]; // Element size 1
+; CHECK-NEXT:    }
+; CHECK:         Statements {
+; CHECK-NEXT:       Stmt_for_body3
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                { Stmt_for_body3[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                { Stmt_for_body3[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_for_body3[i0, i1] -> MemRef_A[o0] : -16 <= o0 <= 20 };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_for_body3[i0, i1] -> MemRef_B[o0] : 64 <= o0 <= 100 };
+;
+; IR: polly.loop_preheader:
+; IR:   %[[r1:[a-zA-Z0-9]*]] = getelementptr i32, i32* %A, i64 -4
+; IR:   %[[r2:[a-zA-Z0-9]*]] = bitcast i32* %scevgep to i8*
+; IR:   %[[r3:[a-zA-Z0-9]*]] = getelementptr i64, i64* %B, i64 8
+; IR:   %[[r4:[a-zA-Z0-9]*]] = bitcast i64* %scevgep8 to i8*
+;
+; IR: polly.stmt.for.body3:
+; IR:   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %[[r2]], i8* %[[r4]], i64 37, i32 4, i1 false)
+;
+;
+;    #include <string.h>
+;
+;    void jd(int *restrict A, long *restrict B) {
+;      for (int i = 0; i < 1024; i++)
+;        for (int j = 0; j < 1024; j++)
+;          memcpy(A - 4, B + 8, 37);
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* noalias %A, i64* noalias %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc5, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc6, %for.inc5 ]
+  %exitcond1 = icmp ne i32 %i.0, 1024
+  br i1 %exitcond1, label %for.body, label %for.end7
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %add.ptr = getelementptr inbounds i32, i32* %A, i64 -4
+  %tmp = bitcast i32* %add.ptr to i8*
+  %add.ptr4 = getelementptr inbounds i64, i64* %B, i64 8
+  %tmp2 = bitcast i64* %add.ptr4 to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %tmp, i8* %tmp2, i64 37, i32 4, i1 false)
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc5
+
+for.inc5:                                         ; preds = %for.end
+  %inc6 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end7:                                         ; preds = %for.cond
+  ret void
+}
+
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #1
+
diff --git a/final/test/ScopInfo/memmove.ll b/final/test/ScopInfo/memmove.ll
new file mode 100644
index 0000000..d2c9fe4
--- /dev/null
+++ b/final/test/ScopInfo/memmove.ll
@@ -0,0 +1,79 @@
+; RUN: opt %loadPolly -basicaa -polly-allow-differing-element-types -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -S -basicaa -polly-allow-differing-element-types -polly-codegen < %s | FileCheck --check-prefix=IR %s
+;
+; CHECK:         Arrays {
+; CHECK-NEXT:        i8 MemRef_A[*]; // Element size 1
+; CHECK-NEXT:        i8 MemRef_B[*]; // Element size 1
+; CHECK-NEXT:    }
+; CHECK:         Statements {
+; CHECK-NEXT:       Stmt_for_body3
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                { Stmt_for_body3[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                { Stmt_for_body3[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_for_body3[i0, i1] -> MemRef_A[o0] : -16 <= o0 <= 15 };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_for_body3[i0, i1] -> MemRef_B[o0] : 64 <= o0 <= 95 };
+;
+; IR: polly.loop_preheader:
+; IR:   %[[r1:[a-zA-Z0-9]*]] = getelementptr i32, i32* %A, i64 -4
+; IR:   %[[r2:[a-zA-Z0-9]*]] = bitcast i32* %scevgep to i8*
+; IR:   %[[r3:[a-zA-Z0-9]*]] = getelementptr i64, i64* %B, i64 8
+; IR:   %[[r4:[a-zA-Z0-9]*]] = bitcast i64* %scevgep8 to i8*
+;
+; IR: polly.stmt.for.body3:
+; IR:   call void @llvm.memmove.p0i8.p0i8.i64(i8* %[[r2]], i8* %[[r4]], i64 32, i32 4, i1 false)
+;
+;    #include <string.h>
+;
+;    void jd(int *restrict A, long *restrict B) {
+;      for (int i = 0; i < 1024; i++)
+;        for (int j = 0; j < 1024; j++)
+;          memmove(A - 4, B + 8, 32);
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* noalias %A, i64* noalias %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc5, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc6, %for.inc5 ]
+  %exitcond1 = icmp ne i32 %i.0, 1024
+  br i1 %exitcond1, label %for.body, label %for.end7
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %add.ptr = getelementptr inbounds i32, i32* %A, i64 -4
+  %tmp = bitcast i32* %add.ptr to i8*
+  %add.ptr4 = getelementptr inbounds i64, i64* %B, i64 8
+  %tmp2 = bitcast i64* %add.ptr4 to i8*
+  call void @llvm.memmove.p0i8.p0i8.i64(i8* %tmp, i8* %tmp2, i64 32, i32 4, i1 false)
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc5
+
+for.inc5:                                         ; preds = %for.end
+  %inc6 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end7:                                         ; preds = %for.cond
+  ret void
+}
+
+declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #1
+
diff --git a/final/test/ScopInfo/memset.ll b/final/test/ScopInfo/memset.ll
new file mode 100644
index 0000000..24436c7
--- /dev/null
+++ b/final/test/ScopInfo/memset.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-allow-differing-element-types -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -S -polly-allow-differing-element-types -polly-codegen < %s | FileCheck --check-prefix=IR %s
+;
+; CHECK:         Arrays {
+; CHECK-NEXT:        i8 MemRef_A[*]; // Element size 1
+; CHECK-NEXT:    }
+; CHECK:         Statements {
+; CHECK-NEXT:       Stmt_for_body3
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                { Stmt_for_body3[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                { Stmt_for_body3[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_for_body3[i0, i1] -> MemRef_A[o0] : 0 <= o0 <= 186 };
+;
+; IR:   %[[r1:[a-zA-Z0-9]*]] = bitcast i32* %A to i8*
+;
+; IR: polly.stmt.for.body3:
+; IR:   call void @llvm.memset.p0i8.i64(i8* %[[r1]], i8 36, i64 187, i32 4, i1 false)
+;
+;    #include <string.h>
+;
+;    void jd(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        for (int j = 0; j < 1024; j++)
+;          memset(A, '$', 187);
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* noalias %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc5, %for.inc4 ]
+  %exitcond1 = icmp ne i32 %i.0, 1024
+  br i1 %exitcond1, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %tmp = bitcast i32* %A to i8*
+  call void @llvm.memset.p0i8.i64(i8* %tmp, i8 36, i64 187, i32 4, i1 false)
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %inc5 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret void
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) #1
+
diff --git a/final/test/ScopInfo/memset_null.ll b/final/test/ScopInfo/memset_null.ll
new file mode 100644
index 0000000..b0d0be0
--- /dev/null
+++ b/final/test/ScopInfo/memset_null.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-allow-modref-calls -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-allow-modref-calls -S -polly-codegen < %s
+;
+; Verify we can handle a memset to "null" and that we do not model it.
+; TODO: FIXME: We could use the undefined memset to optimize the code further,
+;              see the TODOs in the ScopInfo.cpp.
+;
+; CHECK:         Statements {
+; CHECK-NEXT:        Stmt_for_cond5_preheader_us221
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                { Stmt_for_cond5_preheader_us221[0] };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                { Stmt_for_cond5_preheader_us221[i0] -> [0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_for_cond5_preheader_us221[i0] -> MemRef_A[0] };
+; CHECK-NEXT:    }
+
+;
+target datalayout = "e-m:e-i64:64-i128:128-n8:16:32:64-S128"
+
+define void @test(i32* %A) {
+entry:
+  br i1 undef, label %for.end68, label %for.cond5.preheader.lr.ph
+
+for.cond5.preheader.lr.ph:                        ; preds = %entry
+  br label %for.cond5.preheader.us221
+
+for.cond5.preheader.us221:                        ; preds = %for.cond5.preheader.us221, %for.cond5.preheader.lr.ph
+  store i32 0, i32* %A
+  call void @llvm.memset.p0i8.i64(i8* null, i8 0, i64 undef, i32 1, i1 false)
+  br i1 true, label %for.end68, label %for.cond5.preheader.us221
+
+for.end68:                                        ; preds = %for.cond5.preheader.us221, %entry
+  ret void
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1)
diff --git a/final/test/ScopInfo/mismatching-array-dimensions.ll b/final/test/ScopInfo/mismatching-array-dimensions.ll
new file mode 100644
index 0000000..0cf4a43
--- /dev/null
+++ b/final/test/ScopInfo/mismatching-array-dimensions.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; CHECK-NOT: AssumedContext
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.9.0"
+
+; Function Attrs: nounwind ssp uwtable
+define void @hoge([38 x [64 x float]]* %arg, [32 x [2 x float]]* %arg5, i32 %arg6) #0 {
+bb:
+  br i1 undef, label %bb7, label %bb25
+
+bb7:                                              ; preds = %bb21, %bb
+  %tmp8 = phi i64 [ %tmp22, %bb21 ], [ 0, %bb ]
+  %tmp9 = icmp sgt i32 %arg6, 0
+  br i1 %tmp9, label %bb10, label %bb21
+
+bb10:                                             ; preds = %bb10, %bb7
+  %tmp11 = getelementptr inbounds [32 x [2 x float]], [32 x [2 x float]]* %arg5, i64 %tmp8, i64 0
+  %tmp = bitcast [2 x float]* %tmp11 to i32*
+  %tmp12 = load i32, i32* %tmp, align 4, !tbaa !4
+  %tmp13 = getelementptr inbounds [32 x [2 x float]], [32 x [2 x float]]* %arg5, i64 %tmp8, i64 0, i64 1
+  %tmp14 = bitcast float* %tmp13 to i32*
+  %tmp15 = load i32, i32* %tmp14, align 4, !tbaa !4
+  %tmp16 = getelementptr inbounds [38 x [64 x float]], [38 x [64 x float]]* %arg, i64 1, i64 0, i64 %tmp8
+  %tmp17 = bitcast float* %tmp16 to i32*
+  store i32 %tmp15, i32* %tmp17, align 4, !tbaa !4
+  %tmp18 = add nuw nsw i64 0, 1
+  %tmp19 = trunc i64 %tmp18 to i32
+  %tmp20 = icmp ne i32 %tmp19, %arg6
+  br i1 %tmp20, label %bb10, label %bb21
+
+bb21:                                             ; preds = %bb10, %bb7
+  %tmp22 = add nsw i64 %tmp8, 1
+  %tmp23 = trunc i64 %tmp22 to i32
+  %tmp24 = icmp ne i32 %tmp23, 64
+  br i1 %tmp24, label %bb7, label %bb25
+
+bb25:                                             ; preds = %bb21, %bb
+  ret void
+}
+
+attributes #0 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.module.flags = !{!0, !1, !2}
+!llvm.ident = !{!3}
+
+!0 = !{i32 2, !"Dwarf Version", i32 2}
+!1 = !{i32 2, !"Debug Info Version", i32 3}
+!2 = !{i32 1, !"PIC Level", i32 2}
+!3 = !{!"clang version 3.8.0 (trunk 251760) (llvm/trunk 251765)"}
+!4 = !{!5, !5, i64 0}
+!5 = !{!"float", !6, i64 0}
+!6 = !{!"omnipotent char", !7, i64 0}
+!7 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/ScopInfo/mod_ref_access_pointee_arguments.ll b/final/test/ScopInfo/mod_ref_access_pointee_arguments.ll
new file mode 100644
index 0000000..927c4e5
--- /dev/null
+++ b/final/test/ScopInfo/mod_ref_access_pointee_arguments.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze -polly-allow-modref-calls \
+; RUN:  < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -polly-codegen -polly-allow-modref-calls \
+; RUN: -disable-output < %s
+;
+; Verify that we model the may-write access of the prefetch intrinsic
+; correctly, thus that A is accessed by it but B is not.
+;
+; CHECK:      Stmt_for_body
+; CHECK-NEXT:   Domain :=
+; CHECK-NEXT:       { Stmt_for_body[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:   Schedule :=
+; CHECK-NEXT:       { Stmt_for_body[i0] -> [i0] };
+; CHECK-NEXT:   MayWriteAccess := [Reduction Type: NONE]
+; CHECK-NEXT:       { Stmt_for_body[i0] -> MemRef_A[o0] };
+; CHECK-NEXT:   ReadAccess := [Reduction Type: NONE]
+; CHECK-NEXT:       { Stmt_for_body[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:   MustWriteAccess :=  [Reduction Type: NONE]
+; CHECK-NEXT:       { Stmt_for_body[i0] -> MemRef_A[i0] };
+;
+;    void jd(int *restirct A, int *restrict B) {
+;      for (int i = 0; i < 1024; i++) {
+;        @llvm.prefetch(A);
+;        A[i] = B[i];
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* noalias %A, i32* noalias %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  %bc = bitcast i32* %arrayidx to i8*
+  call void @f(i8* %bc, i32 1, i32 1, i32 1)
+  %tmp = load i32, i32* %arrayidx2
+  store i32 %tmp, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare void @f(i8*, i32, i32, i32) #0
+
+attributes #0 = { argmemonly nounwind }
diff --git a/final/test/ScopInfo/mod_ref_read_pointee_arguments.ll b/final/test/ScopInfo/mod_ref_read_pointee_arguments.ll
new file mode 100644
index 0000000..c153846
--- /dev/null
+++ b/final/test/ScopInfo/mod_ref_read_pointee_arguments.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze -polly-allow-modref-calls \
+; RUN: < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -polly-codegen -disable-output \
+; RUN: -polly-allow-modref-calls < %s
+;
+; Verify that we model the read access of the gcread intrinsic
+; correctly, thus that A is read by it but B is not.
+;
+; CHECK:      Stmt_for_body
+; CHECK-NEXT:   Domain :=
+; CHECK-NEXT:       { Stmt_for_body[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:   Schedule :=
+; CHECK-NEXT:       { Stmt_for_body[i0] -> [i0] };
+; CHECK-NEXT:   ReadAccess := [Reduction Type: NONE]
+; CHECK-NEXT:       { Stmt_for_body[i0] -> MemRef_A[o0] };
+; CHECK-NEXT:   MustWriteAccess :=  [Reduction Type: NONE]
+; CHECK-NEXT:       { Stmt_for_body[i0] -> MemRef_dummyloc[0] };
+; CHECK-NEXT:   ReadAccess := [Reduction Type: NONE]
+; CHECK-NEXT:       { Stmt_for_body[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:   MustWriteAccess :=  [Reduction Type: NONE]
+; CHECK-NEXT:       { Stmt_for_body[i0] -> MemRef_A[i0] };
+;
+;    void jd(int *restirct A, int *restrict B) {
+;      char **dummyloc;
+;      for (int i = 0; i < 1024; i++) {
+;        char *dummy = @llvm.gcread(A, nullptr);
+;        *dummyloc = dummy;
+;        A[i] = B[i];
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* noalias %A, i32* noalias %B) gc "dummy" {
+entry:
+  %dummyloc = alloca i8*
+  br label %entry.split
+
+entry.split:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry.split
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry.split ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  %bc = bitcast i32* %arrayidx to i8*
+  %dummy = call i8* @f(i8* %bc, i8** null)
+  store i8* %dummy, i8** %dummyloc, align 4
+  %tmp = load i32, i32* %arrayidx2
+  store i32 %tmp, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare i8* @f(i8*, i8**) #0
+
+attributes #0 = { argmemonly readonly nounwind }
diff --git a/final/test/ScopInfo/mod_ref_read_pointer.ll b/final/test/ScopInfo/mod_ref_read_pointer.ll
new file mode 100644
index 0000000..deb5c7c
--- /dev/null
+++ b/final/test/ScopInfo/mod_ref_read_pointer.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze -polly-allow-modref-calls \
+; RUN:  < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -polly-codegen -disable-output \
+; RUN: -polly-allow-modref-calls < %s
+;
+; Check that we assume the call to func has a read on the whole A array.
+;
+; CHECK:      Stmt_for_body
+; CHECK-NEXT:   Domain :=
+; CHECK-NEXT:       { Stmt_for_body[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:   Schedule :=
+; CHECK-NEXT:       { Stmt_for_body[i0] -> [i0] };
+; CHECK-NEXT:   MustWriteAccess :=  [Reduction Type: NONE]
+; CHECK-NEXT:       { Stmt_for_body[i0] -> MemRef_A[2 + i0] };
+; CHECK-NEXT:   ReadAccess :=  [Reduction Type: NONE]
+; CHECK-NEXT:       { Stmt_for_body[i0] -> MemRef_A[o0] };
+;
+;    #pragma readonly
+;    int func(int *A);
+;
+;    void jd(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i + 2] = func(A);
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %call = call i32 @func(i32* %A) #2
+  %tmp = add nsw i64 %indvars.iv, 2
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %tmp
+  store i32 %call, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare i32 @func(i32*) #1
+
+attributes #1 = { nounwind readonly }
diff --git a/final/test/ScopInfo/mod_ref_read_pointers.ll b/final/test/ScopInfo/mod_ref_read_pointers.ll
new file mode 100644
index 0000000..2039c75
--- /dev/null
+++ b/final/test/ScopInfo/mod_ref_read_pointers.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze -polly-allow-modref-calls \
+; RUN: < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -polly-codegen -disable-output \
+; RUN: -polly-allow-modref-calls < %s
+;
+; Check that the call to func will "read" not only the A array but also the
+; B array. The reason is the readonly annotation of func.
+;
+; CHECK:      Stmt_for_body
+; CHECK-NEXT:  Domain :=
+; CHECK-NEXT:      { Stmt_for_body[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:  Schedule :=
+; CHECK-NEXT:      { Stmt_for_body[i0] -> [i0] };
+; CHECK-NEXT:  ReadAccess :=  [Reduction Type: NONE]
+; CHECK-NEXT:      { Stmt_for_body[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:  MustWriteAccess :=  [Reduction Type: NONE]
+; CHECK-NEXT:      { Stmt_for_body[i0] -> MemRef_A[2 + i0] };
+; CHECK-DAG:   ReadAccess :=  [Reduction Type: NONE]
+; CHECK-DAG:       { Stmt_for_body[i0] -> MemRef_B[o0] };
+; CHECK-DAG:   ReadAccess :=  [Reduction Type: NONE]
+; CHECK-DAG:       { Stmt_for_body[i0] -> MemRef_A[o0] };
+;
+;    #pragma readonly
+;    int func(int *A);
+;
+;    void jd(int *restrict A, int *restrict B) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i + 2] = func(A) + B[i];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* noalias %A, i32* noalias %B) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %call = call i32 @func(i32* %A)
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %call, %tmp
+  %tmp2 = add nsw i64 %indvars.iv, 2
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %tmp2
+  store i32 %add, i32* %arrayidx3, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare i32 @func(i32*) #1
+
+attributes #1 = { nounwind readonly }
diff --git a/final/test/ScopInfo/modulo_zext_1.ll b/final/test/ScopInfo/modulo_zext_1.ll
new file mode 100644
index 0000000..da0e773
--- /dev/null
+++ b/final/test/ScopInfo/modulo_zext_1.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK:         Assumed Context:
+; CHECK-NEXT:    [N] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [N] -> {  : 1 = 0 }
+; CHECK-NEXT:    p0: %N
+; CHECK:         Statements {
+; CHECK-NEXT:    	Stmt_for_body
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [N] -> { Stmt_for_body[i0] : 0 <= i0 < N };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [N] -> { Stmt_for_body[i0] -> [i0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:                [N] -> { Stmt_for_body[i0] -> MemRef_A[1] : 2*floor((1 + i0)/2) = 1 + i0; Stmt_for_body[i0] -> MemRef_A[0] : 2*floor((i0)/2) = i0 };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:                [N] -> { Stmt_for_body[i0] -> MemRef_A[1] : 2*floor((1 + i0)/2) = 1 + i0; Stmt_for_body[i0] -> MemRef_A[0] : 2*floor((i0)/2) = i0 };
+; CHECK-NEXT:    }
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++) {
+;        A[i % 2]++;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc1, %for.inc ]
+  %cmp = icmp slt i32 %i.0, %N
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %i.t = trunc i32 %i.0 to i1
+  %rem = zext i1 %i.t to i32
+  %idxprom = sext i32 %rem to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  %tmp = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc1 = add nuw nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/modulo_zext_2.ll b/final/test/ScopInfo/modulo_zext_2.ll
new file mode 100644
index 0000000..70eadf2
--- /dev/null
+++ b/final/test/ScopInfo/modulo_zext_2.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK:         Assumed Context:
+; CHECK-NEXT:    [N] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [N] -> {  : 1 = 0 }
+; CHECK-NEXT:    p0: %N
+; CHECK:         Statements {
+; CHECK-NEXT:    	Stmt_if_then
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [N] -> { Stmt_if_then[i0] : 2*floor((1 + i0)/2) = 1 + i0 and 0 < i0 < N }
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [N] -> { Stmt_if_then[i0] -> [i0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:                [N] -> { Stmt_if_then[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:                [N] -> { Stmt_if_then[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:    }
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++) {
+;        if (i & 1)
+;          A[i]++;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp1 = trunc i64 %indvars.iv to i32
+  %and = and i32 %tmp1, 1
+  %tobool = icmp eq i32 %and, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp2, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %for.body, %if.then
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/modulo_zext_3.ll b/final/test/ScopInfo/modulo_zext_3.ll
new file mode 100644
index 0000000..b44c40a
--- /dev/null
+++ b/final/test/ScopInfo/modulo_zext_3.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK:         Assumed Context:
+; CHECK-NEXT:    [N] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [N] -> {  : N >= 4294967297 }
+; CHECK-NEXT:    p0: %N
+; CHECK:         Statements {
+; CHECK-NEXT:    	Stmt_for_body
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [N] -> { Stmt_for_body[i0] : 0 <= i0 < N };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [N] -> { Stmt_for_body[i0] -> [i0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:                [N] -> { Stmt_for_body[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:                [N] -> { Stmt_for_body[i0] -> MemRef_A[i0]  };
+; CHECK-NEXT:    }
+;
+;    void f(long *A, long N) {
+;      long K = /* 2^32 */ 4294967296;
+;      for (long i = 0; i < N; i++) {
+;        A[i % K]++;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i64* %A, i64 %N) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc1, %for.inc ]
+  %cmp = icmp slt i64 %i.0, %N
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %i.t = trunc i64 %i.0 to i33
+  %rem = zext i33 %i.t to i64
+  %arrayidx = getelementptr inbounds i64, i64* %A, i64 %rem
+  %tmp = load i64, i64* %arrayidx, align 4
+  %inc = add nsw i64 %tmp, 1
+  store i64 %inc, i64* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc1 = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/multi-scop.ll b/final/test/ScopInfo/multi-scop.ll
new file mode 100644
index 0000000..6e30e3d
--- /dev/null
+++ b/final/test/ScopInfo/multi-scop.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -analyze < %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; This test case contains two scops.
+define void @test(i32 %l, double* %a) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %shl = shl i32 %l, 2
+  br i1 false, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.body, %entry.split
+  %j.011 = phi i32 [ 0, %entry.split ], [ %add76, %for.body ]
+  %add76 = add nsw i32 %j.011, 2
+  br i1 false, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body, %entry.split
+  br i1 undef, label %for.body81, label %for.end170
+
+for.body81:                                       ; preds = %for.body81, %for.end
+  %j.19 = phi i32 [ %shl, %for.end ], [ %add169, %for.body81 ]
+  %add13710 = or i32 %j.19, 1
+  %idxprom138 = sext i32 %add13710 to i64
+  %arrayidx139 = getelementptr inbounds double, double* %a, i64 %idxprom138
+  store double undef, double* %arrayidx139, align 8
+  %add169 = add nsw i32 %j.19, 2
+  br i1 false, label %for.body81, label %for.end170
+
+for.end170:                                       ; preds = %for.body81
+  ret void
+}
+
+; CHECK: Valid Region for Scop: entry.split => for.end
+; CHECK: Valid Region for Scop: for.body81 => for.end170
+
diff --git a/final/test/ScopInfo/multidim_2d-diagonal-matrix.ll b/final/test/ScopInfo/multidim_2d-diagonal-matrix.ll
new file mode 100644
index 0000000..6a60abd
--- /dev/null
+++ b/final/test/ScopInfo/multidim_2d-diagonal-matrix.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-function-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; Derived from the following code:
+;
+; void foo(long n, double A[n][n]) {
+;   for (long i = 0; i < n; i++)
+;     A[i][i] = 1.0;
+; }
+
+
+; CHECK: Assumed Context:
+; CHECK:   [n] -> {  :  }
+
+; CHECK: p0: %n
+; CHECK-NOT: p1
+
+; CHECK: Schedule :=
+; CHECK:   [n] -> { Stmt_for_i[i0] -> [i0] };
+; CHECK: MustWriteAccess :=
+; CHECK:   [n] -> { Stmt_for_i[i0] -> MemRef_A[i0, i0] };
+
+
+define void @foo(i64 %n, double* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i ]
+  %tmp = mul nsw i64 %i, %n
+  %vlaarrayidx.sum = add i64 %i, %tmp
+  %arrayidx = getelementptr inbounds double, double* %A, i64 %vlaarrayidx.sum
+  store double 1.0, double* %arrayidx
+  %i.inc = add nsw i64 %i, 1
+  %i.exitcond = icmp eq i64 %i.inc, %n
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_2d_outer_parametric_offset.ll b/final/test/ScopInfo/multidim_2d_outer_parametric_offset.ll
new file mode 100644
index 0000000..cecc4ce
--- /dev/null
+++ b/final/test/ScopInfo/multidim_2d_outer_parametric_offset.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; Derived from the following code:
+;
+; void foo(long n, long m, long p, double A[n][m]) {
+;   for (long i = 0; i < 100; i++)
+;     for (long j = 0; j < m; j++)
+;       A[i+p][j] = 1.0;
+; }
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [m, p] -> {  :  }
+;
+; CHECK:      p0: %m
+; CHECK-NEXT: p1: %p
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_j
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [m, p] -> { Stmt_for_j[i0, i1] : 0 <= i0 <= 99 and 0 <= i1 < m };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [m, p] -> { Stmt_for_j[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [m, p] -> { Stmt_for_j[i0, i1] -> MemRef_A[p + i0, i1] };
+; CHECK-NEXT: }
+
+define void @foo(i64 %n, i64 %m, i64 %p, double* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+  %add = add nsw i64 %i, %p
+  %tmp = mul nsw i64 %add, %m
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j ]
+  %vlaarrayidx.sum = add i64 %j, %tmp
+  %arrayidx = getelementptr inbounds double, double* %A, i64 %vlaarrayidx.sum
+  store double 1.0, double* %arrayidx
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, %m
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %i.exitcond = icmp eq i64 %i.inc, 100
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_2d_parametric_array_static_loop_bounds.ll b/final/test/ScopInfo/multidim_2d_parametric_array_static_loop_bounds.ll
new file mode 100644
index 0000000..fd47dd3
--- /dev/null
+++ b/final/test/ScopInfo/multidim_2d_parametric_array_static_loop_bounds.ll
@@ -0,0 +1,51 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; Derived from the following code:
+;
+; void foo(long n, long m, double A[n][m]) {
+;   for (long i = 0; i < 100; i++)
+;     for (long j = 0; j < 150; j++)
+;       A[i][j] = 1.0;
+; }
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [m] -> {  : m >= 150 }
+;
+; CHECK:      p0: %m
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_j
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [m] -> { Stmt_for_j[i0, i1] : 0 <= i0 <= 99 and 0 <= i1 <= 149 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [m] -> { Stmt_for_j[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [m] -> { Stmt_for_j[i0, i1] -> MemRef_A[i0, i1] };
+; CHECK-NEXT: }
+
+define void @foo(i64 %n, i64 %m, double* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+  %tmp = mul nsw i64 %i, %m
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j ]
+  %vlaarrayidx.sum = add i64 %j, %tmp
+  %arrayidx = getelementptr inbounds double, double* %A, i64 %vlaarrayidx.sum
+  store double 1.0, double* %arrayidx
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, 150
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %i.exitcond = icmp eq i64 %i.inc, 100
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_2d_with_modref_call.ll b/final/test/ScopInfo/multidim_2d_with_modref_call.ll
new file mode 100644
index 0000000..74cd009
--- /dev/null
+++ b/final/test/ScopInfo/multidim_2d_with_modref_call.ll
@@ -0,0 +1,183 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-allow-modref-calls \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN: < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -analyze \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN: -polly-allow-modref-calls < %s | FileCheck %s --check-prefix=NONAFFINE
+
+;  TODO: We should delinearize the accesses despite the use in a call to a
+;        readonly function. For now we verify we do not delinearize them though.
+
+; CHECK:         Function: ham
+; CHECK-NEXT:    Region: %bb12---%bb28
+; CHECK-NEXT:    Max Loop Depth:  1
+; CHECK-NEXT:    Invariant Accesses: {
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb12[] -> MemRef_arg1[0] };
+; CHECK-NEXT:            Execution Context: [tmp14, p_1] -> {  :  }
+; CHECK-NEXT:    }
+; CHECK-NEXT:    Context:
+; CHECK-NEXT:    [tmp14, p_1] -> {  : -9223372036854775808 <= tmp14 <= 9223372036854775807 and -9223372036854775808 <= p_1 <= 9223372036854775807 }
+; CHECK-NEXT:    Assumed Context:
+; CHECK-NEXT:    [tmp14, p_1] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [tmp14, p_1] -> { : tmp14 > 0 and (p_1 <= -1152921504606846977 or tmp14 >= 1152921504606846977 or p_1 >= 1152921504606846977 - tmp14) }
+; CHECK-NEXT:    p0: %tmp14
+; CHECK-NEXT:    p1: {0,+,(0 smax %tmp)}<%bb12>
+; CHECK-NEXT:    Arrays {
+; CHECK-NEXT:        i64 MemRef_arg1[*]; // Element size 8
+; CHECK-NEXT:        i64 MemRef_tmp13; // Element size 8
+; CHECK-NEXT:        double MemRef_arg4[*]; // Element size 8
+; CHECK-NEXT:    }
+; CHECK-NEXT:    Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:        i64 MemRef_arg1[*]; // Element size 8
+; CHECK-NEXT:        i64 MemRef_tmp13; // Element size 8
+; CHECK-NEXT:        double MemRef_arg4[*]; // Element size 8
+; CHECK-NEXT:    }
+; CHECK-NEXT:    Alias Groups (0):
+; CHECK-NEXT:        n/a
+; CHECK-NEXT:    Statements {
+; CHECK-NEXT:    	Stmt_bb12
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb12[] };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb12[] -> [0, 0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb12[] -> MemRef_tmp13[] };
+; CHECK-NEXT:    	Stmt_bb17
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] : 0 <= i0 < tmp14 };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] -> [1, i0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg4[p_1 + i0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg1[o0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg4[o0] };
+; CHECK-NEXT:    }
+
+
+; NONAFFINE:         Function: ham
+; NONAFFINE-NEXT:    Region: %bb5---%bb32
+; NONAFFINE-NEXT:    Max Loop Depth:  2
+; NONAFFINE-NEXT:    Invariant Accesses: {
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_arg[0] };
+; NONAFFINE-NEXT:            Execution Context: [tmp9, tmp14] -> {  :  }
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb12[i0] -> MemRef_arg1[0] };
+; NONAFFINE-NEXT:            Execution Context: [tmp9, tmp14] -> {  :  }
+; NONAFFINE-NEXT:    }
+; NONAFFINE-NEXT:    Context:
+; NONAFFINE-NEXT:    [tmp9, tmp14] -> {  : -9223372036854775808 <= tmp9 <= 9223372036854775807 and -9223372036854775808 <= tmp14 <= 9223372036854775807 }
+; NONAFFINE-NEXT:    Assumed Context:
+; NONAFFINE-NEXT:    [tmp9, tmp14] -> {  :  }
+; NONAFFINE-NEXT:    Invalid Context:
+; NONAFFINE-NEXT:    [tmp9, tmp14] -> {  : 1 = 0 }
+; NONAFFINE-NEXT:    p0: %tmp9
+; NONAFFINE-NEXT:    p1: %tmp14
+; NONAFFINE-NEXT:    Arrays {
+; NONAFFINE-NEXT:        i64 MemRef_arg[*]; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_arg1[*]; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_tmp7; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_tmp8; // Element size 8
+; NONAFFINE-NEXT:        double MemRef_arg4[*]; // Element size 8
+; NONAFFINE-NEXT:    }
+; NONAFFINE-NEXT:    Arrays (Bounds as pw_affs) {
+; NONAFFINE-NEXT:        i64 MemRef_arg[*]; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_arg1[*]; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_tmp7; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_tmp8; // Element size 8
+; NONAFFINE-NEXT:        double MemRef_arg4[*]; // Element size 8
+; NONAFFINE-NEXT:    }
+; NONAFFINE-NEXT:    Alias Groups (0):
+; NONAFFINE-NEXT:        n/a
+; NONAFFINE-NEXT:    Statements {
+; NONAFFINE-NEXT:    	Stmt_bb5
+; NONAFFINE-NEXT:            Domain :=
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] };
+; NONAFFINE-NEXT:            Schedule :=
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] -> [0, 0, 0] };
+; NONAFFINE-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_tmp7[] };
+; NONAFFINE-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_tmp8[] };
+; NONAFFINE-NEXT:    	Stmt_bb17
+; NONAFFINE-NEXT:            Domain :=
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] : 0 <= i0 < tmp9 and 0 <= i1 < tmp14 };
+; NONAFFINE-NEXT:            Schedule :=
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> [1, i0, i1] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_tmp7[] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_tmp8[] };
+; NONAFFINE-NEXT:            MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[o0] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg[o0] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg1[o0] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[o0] };
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @ham(i64* noalias %arg, i64* noalias %arg1, i64* noalias %arg2, i64* noalias %arg3, [1000 x double]* noalias %arg4) unnamed_addr {
+bb:
+  br label %bb5
+
+bb5:                                              ; preds = %bb
+  %tmp = load i64, i64* %arg1, align 8
+  %tmp6 = icmp slt i64 %tmp, 0
+  %tmp7 = select i1 %tmp6, i64 0, i64 %tmp
+  %tmp8 = xor i64 %tmp7, -1
+  %tmp9 = load i64, i64* %arg, align 8
+  %tmp10 = icmp sgt i64 %tmp9, 0
+  br i1 %tmp10, label %bb11, label %bb32
+
+bb11:                                             ; preds = %bb5
+  br label %bb12
+
+bb12:                                             ; preds = %bb28, %bb11
+  %tmp13 = phi i64 [ %tmp30, %bb28 ], [ 1, %bb11 ]
+  %tmp14 = load i64, i64* %arg1, align 8
+  %tmp15 = icmp sgt i64 %tmp14, 0
+  br i1 %tmp15, label %bb16, label %bb28
+
+bb16:                                             ; preds = %bb12
+  br label %bb17
+
+bb17:                                             ; preds = %bb17, %bb16
+  %tmp18 = phi i64 [ %tmp26, %bb17 ], [ 1, %bb16 ]
+  %tmp19 = mul i64 %tmp13, %tmp7
+  %tmp20 = add i64 %tmp19, %tmp8
+  %tmp21 = add i64 %tmp20, %tmp18
+  %tmp22 = add i64 %tmp18, %tmp13
+  %tmp23 = sitofp i64 %tmp22 to double
+  %tmp24 = getelementptr [1000 x double], [1000 x double]* %arg4, i64 0, i64 %tmp21
+  %call = call double @func(double* %tmp24) #2
+  %sum = fadd double %call, %tmp23
+  store double %sum, double* %tmp24, align 8
+  %tmp25 = icmp eq i64 %tmp18, %tmp14
+  %tmp26 = add i64 %tmp18, 1
+  br i1 %tmp25, label %bb27, label %bb17
+
+bb27:                                             ; preds = %bb17
+  br label %bb28
+
+bb28:                                             ; preds = %bb27, %bb12
+  %tmp29 = icmp eq i64 %tmp13, %tmp9
+  %tmp30 = add i64 %tmp13, 1
+  br i1 %tmp29, label %bb31, label %bb12
+
+bb31:                                             ; preds = %bb28
+  br label %bb32
+
+bb32:                                             ; preds = %bb31, %bb5
+  ret void
+}
+
+declare double @func(double*) #1
+
+attributes #1 = { nounwind readonly }
diff --git a/final/test/ScopInfo/multidim_2d_with_modref_call_2.ll b/final/test/ScopInfo/multidim_2d_with_modref_call_2.ll
new file mode 100644
index 0000000..1598d8e
--- /dev/null
+++ b/final/test/ScopInfo/multidim_2d_with_modref_call_2.ll
@@ -0,0 +1,176 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-allow-modref-calls \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN: < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN: -polly-allow-modref-calls -analyze < %s | FileCheck %s --check-prefix=NONAFFINE
+
+;  TODO: We should delinearize the accesses despite the use in a call to a
+;        readonly function. For now we verify we do not delinearize them though.
+
+; CHECK:         Function: ham
+; CHECK-NEXT:    Region: %bb12---%bb28
+; CHECK-NEXT:    Max Loop Depth:  1
+; CHECK-NEXT:    Invariant Accesses: {
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb12[] -> MemRef_arg1[0] };
+; CHECK-NEXT:            Execution Context: [tmp14, p_1] -> {  :  }
+; CHECK-NEXT:    }
+; CHECK-NEXT:    Context:
+; CHECK-NEXT:    [tmp14, p_1] -> {  : -9223372036854775808 <= tmp14 <= 9223372036854775807 and -9223372036854775808 <= p_1 <= 9223372036854775807 }
+; CHECK-NEXT:    Assumed Context:
+; CHECK-NEXT:    [tmp14, p_1] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [tmp14, p_1] -> { : tmp14 > 0 and (p_1 <= -1152921504606846977 or tmp14 >= 1152921504606846977 or p_1 >= 1152921504606846977 - tmp14) }
+; CHECK-NEXT:    p0: %tmp14
+; CHECK-NEXT:    p1: {0,+,(0 smax %tmp)}<%bb12>
+; CHECK-NEXT:    Arrays {
+; CHECK-NEXT:        i64 MemRef_arg1[*]; // Element size 8
+; CHECK-NEXT:        i64 MemRef_tmp13; // Element size 8
+; CHECK-NEXT:        [1000 x double]* MemRef_arg4[*]; // Element size 8
+; CHECK-NEXT:    }
+; CHECK-NEXT:    Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:        i64 MemRef_arg1[*]; // Element size 8
+; CHECK-NEXT:        i64 MemRef_tmp13; // Element size 8
+; CHECK-NEXT:        [1000 x double]* MemRef_arg4[*]; // Element size 8
+; CHECK-NEXT:    }
+; CHECK-NEXT:    Alias Groups (0):
+; CHECK-NEXT:        n/a
+; CHECK-NEXT:    Statements {
+; CHECK-NEXT:    	Stmt_bb12
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb12[] };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb12[] -> [0, 0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb12[] -> MemRef_tmp13[] };
+; CHECK-NEXT:    	Stmt_bb17
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] : 0 <= i0 < tmp14 };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] -> [1, i0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg4[o0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg4[p_1 + i0] };
+; CHECK-NEXT:    }
+
+
+; NONAFFINE:         Function: ham
+; NONAFFINE-NEXT:    Region: %bb5---%bb32
+; NONAFFINE-NEXT:    Max Loop Depth:  2
+; NONAFFINE-NEXT:    Invariant Accesses: {
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_arg[0] };
+; NONAFFINE-NEXT:            Execution Context: [tmp9, tmp14] -> {  :  }
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb12[i0] -> MemRef_arg1[0] };
+; NONAFFINE-NEXT:            Execution Context: [tmp9, tmp14] -> {  :  }
+; NONAFFINE-NEXT:    }
+; NONAFFINE-NEXT:    Context:
+; NONAFFINE-NEXT:    [tmp9, tmp14] -> {  : -9223372036854775808 <= tmp9 <= 9223372036854775807 and -9223372036854775808 <= tmp14 <= 9223372036854775807 }
+; NONAFFINE-NEXT:    Assumed Context:
+; NONAFFINE-NEXT:    [tmp9, tmp14] -> {  :  }
+; NONAFFINE-NEXT:    Invalid Context:
+; NONAFFINE-NEXT:    [tmp9, tmp14] -> {  : 1 = 0 }
+; NONAFFINE-NEXT:    p0: %tmp9
+; NONAFFINE-NEXT:    p1: %tmp14
+; NONAFFINE-NEXT:    Arrays {
+; NONAFFINE-NEXT:        i64 MemRef_arg[*]; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_arg1[*]; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_tmp7; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_tmp8; // Element size 8
+; NONAFFINE-NEXT:        [1000 x double]* MemRef_arg4[*]; // Element size 8
+; NONAFFINE-NEXT:    }
+; NONAFFINE-NEXT:    Arrays (Bounds as pw_affs) {
+; NONAFFINE-NEXT:        i64 MemRef_arg[*]; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_arg1[*]; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_tmp7; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_tmp8; // Element size 8
+; NONAFFINE-NEXT:        [1000 x double]* MemRef_arg4[*]; // Element size 8
+; NONAFFINE-NEXT:    }
+; NONAFFINE-NEXT:    Alias Groups (0):
+; NONAFFINE-NEXT:        n/a
+; NONAFFINE-NEXT:    Statements {
+; NONAFFINE-NEXT:    	Stmt_bb5
+; NONAFFINE-NEXT:            Domain :=
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] };
+; NONAFFINE-NEXT:            Schedule :=
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] -> [0, 0, 0] };
+; NONAFFINE-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_tmp7[] };
+; NONAFFINE-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_tmp8[] };
+; NONAFFINE-NEXT:    	Stmt_bb17
+; NONAFFINE-NEXT:            Domain :=
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] : 0 <= i0 < tmp9 and 0 <= i1 < tmp14 };
+; NONAFFINE-NEXT:            Schedule :=
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> [1, i0, i1] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_tmp7[] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_tmp8[] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[o0] };
+; NONAFFINE-NEXT:            MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[o0] };
+; NONAFFINE-NEXT:    }
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @ham(i64* noalias %arg, i64* noalias %arg1, i64* noalias %arg2, i64* noalias %arg3, [1000 x double]* noalias %arg4) gc "dummy" {
+bb:
+  br label %bb5
+
+bb5:                                              ; preds = %bb
+  %tmp = load i64, i64* %arg1, align 8
+  %tmp6 = icmp slt i64 %tmp, 0
+  %tmp7 = select i1 %tmp6, i64 0, i64 %tmp
+  %tmp8 = xor i64 %tmp7, -1
+  %tmp9 = load i64, i64* %arg, align 8
+  %tmp10 = icmp sgt i64 %tmp9, 0
+  br i1 %tmp10, label %bb11, label %bb32
+
+bb11:                                             ; preds = %bb5
+  br label %bb12
+
+bb12:                                             ; preds = %bb28, %bb11
+  %tmp13 = phi i64 [ %tmp30, %bb28 ], [ 1, %bb11 ]
+  %tmp14 = load i64, i64* %arg1, align 8
+  %tmp15 = icmp sgt i64 %tmp14, 0
+  br i1 %tmp15, label %bb16, label %bb28
+
+bb16:                                             ; preds = %bb12
+  br label %bb17
+
+bb17:                                             ; preds = %bb17, %bb16
+  %tmp18 = phi i64 [ %tmp26, %bb17 ], [ 1, %bb16 ]
+  %tmp19 = mul i64 %tmp13, %tmp7
+  %tmp20 = add i64 %tmp19, %tmp8
+  %tmp21 = add i64 %tmp20, %tmp18
+  %tmp22 = add i64 %tmp18, %tmp13
+  %tmp23 = sitofp i64 %tmp22 to double
+  %tmp24 = getelementptr [1000 x double], [1000 x double]* %arg4, i64 0, i64 %tmp21
+  %bc = bitcast double* %tmp24 to i8*
+  %dummy = call i8* @llvm.gcread(i8* %bc, i8** null)
+  store double %tmp23, double* %tmp24, align 8
+  %tmp25 = icmp eq i64 %tmp18, %tmp14
+  %tmp26 = add i64 %tmp18, 1
+  br i1 %tmp25, label %bb27, label %bb17
+
+bb27:                                             ; preds = %bb17
+  br label %bb28
+
+bb28:                                             ; preds = %bb27, %bb12
+  %tmp29 = icmp eq i64 %tmp13, %tmp9
+  %tmp30 = add i64 %tmp13, 1
+  br i1 %tmp29, label %bb31, label %bb12
+
+bb31:                                             ; preds = %bb28
+  br label %bb32
+
+bb32:                                             ; preds = %bb31, %bb5
+  ret void
+}
+
+declare i8* @llvm.gcread(i8*, i8**)
diff --git a/final/test/ScopInfo/multidim_3d_parametric_array_static_loop_bounds.ll b/final/test/ScopInfo/multidim_3d_parametric_array_static_loop_bounds.ll
new file mode 100644
index 0000000..1064b9e
--- /dev/null
+++ b/final/test/ScopInfo/multidim_3d_parametric_array_static_loop_bounds.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; void foo(long n, long m, long o, double A[n][m][o]) {
+;
+;   for (long i = 0; i < 100; i++)
+;     for (long j = 0; j < 150; j++)
+;       for (long k = 0; k < 200; k++)
+;         A[i][j][k] = 1.0;
+; }
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [m, o] -> {  : m >= 150 and o >= 200 }
+; CHECK:      Invalid Context:
+; CHECK-NEXT: [m, o] -> {  : 1 = 0 }
+;
+; CHECK:      p0: %m
+; CHECK-NEXT: p1: %o
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_k
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [m, o] -> { Stmt_for_k[i0, i1, i2] : 0 <= i0 <= 99 and 0 <= i1 <= 149 and 0 <= i2 <= 199 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [m, o] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [m, o] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[i0, i1, i2] };
+; CHECK-NEXT: }
+
+define void @foo(i64 %n, i64 %m, i64 %o, double* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j.inc ]
+  br label %for.k
+
+for.k:
+  %k = phi i64 [ 0, %for.j ], [ %k.inc, %for.k.inc ]
+  %subscript0 = mul i64 %i, %m
+  %subscript1 = add i64 %j, %subscript0
+  %subscript2 = mul i64 %subscript1, %o
+  %subscript = add i64 %subscript2, %k
+  %idx = getelementptr inbounds double, double* %A, i64 %subscript
+  store double 1.0, double* %idx
+  br label %for.k.inc
+
+for.k.inc:
+  %k.inc = add nsw i64 %k, 1
+  %k.exitcond = icmp eq i64 %k.inc, 200
+  br i1 %k.exitcond, label %for.j.inc, label %for.k
+
+for.j.inc:
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, 150
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %i.exitcond = icmp eq i64 %i.inc, 100
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_fixedsize_different_dimensionality.ll b/final/test/ScopInfo/multidim_fixedsize_different_dimensionality.ll
new file mode 100644
index 0000000..4b30f98
--- /dev/null
+++ b/final/test/ScopInfo/multidim_fixedsize_different_dimensionality.ll
@@ -0,0 +1,259 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    #define N 400
+;
+;    void first_higher_dimensional(float A[][N]) {
+;      for (long i = 0; i < N; i++)
+;        for (long j = 0; j < N; j++)
+;          A[i][j] += i + j;
+;
+;      A[0][0] += A[100][100];
+;
+;      for (long i = 0; i < N; i++)
+;        for (long j = 0; j < N; j++)
+;          A[i][j] += i + j;
+;    }
+
+;    void first_lower_dimensional(float A[][N], float B[][N]) {
+;      for (long i = 0; i < N; i++)
+;        for (long j = 0; j < N; j++)
+;          B[i][j] += i + j;
+;
+;      A[0][0] += B[100][100];
+;
+;      for (long i = 0; i < N; i++)
+;        for (long j = 0; j < N; j++)
+;          A[i][j] += i + j;
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb7
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] : 0 <= i0 <= 399 and 0 <= i1 <= 399 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> [0, i0, i1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> MemRef_A[i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> MemRef_A[i0, i1] };
+; CHECK-NEXT:     Stmt_bb17
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb17[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb17[] -> [1, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb17[] -> MemRef_A[100, 100] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb17[] -> MemRef_A[0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb17[] -> MemRef_A[0, 0] };
+; CHECK-NEXT:     Stmt_bb26
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb26[i0, i1] : 0 <= i0 <= 399 and 0 <= i1 <= 399 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb26[i0, i1] -> [2, i0, i1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb26[i0, i1] -> MemRef_A[i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb26[i0, i1] -> MemRef_A[i0, i1] };
+; CHECK-NEXT: }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb7
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] : 0 <= i0 <= 399 and 0 <= i1 <= 399 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> [0, i0, i1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> MemRef_B[i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb7[i0, i1] -> MemRef_B[i0, i1] };
+; CHECK-NEXT:     Stmt_bb17
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb17[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb17[] -> [1, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb17[] -> MemRef_B[100, 100] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb17[] -> MemRef_A[0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb17[] -> MemRef_A[0, 0] };
+; CHECK-NEXT:     Stmt_bb26
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb26[i0, i1] : 0 <= i0 <= 399 and 0 <= i1 <= 399 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb26[i0, i1] -> [2, i0, i1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb26[i0, i1] -> MemRef_A[i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb26[i0, i1] -> MemRef_A[i0, i1] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @first_higher_dimensional([400 x float]* %A) {
+bb:
+  br label %bb4
+
+bb4:                                              ; preds = %bb15, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp16, %bb15 ]
+  %exitcond3 = icmp ne i64 %i.0, 400
+  br i1 %exitcond3, label %bb5, label %bb17
+
+bb5:                                              ; preds = %bb4
+  br label %bb6
+
+bb6:                                              ; preds = %bb12, %bb5
+  %j.0 = phi i64 [ 0, %bb5 ], [ %tmp13, %bb12 ]
+  %exitcond2 = icmp ne i64 %j.0, 400
+  br i1 %exitcond2, label %bb7, label %bb14
+
+bb7:                                              ; preds = %bb6
+  %tmp = add nuw nsw i64 %i.0, %j.0
+  %tmp8 = sitofp i64 %tmp to float
+  %tmp9 = getelementptr inbounds [400 x float], [400 x float]* %A, i64 %i.0, i64 %j.0
+  %tmp10 = load float, float* %tmp9, align 4
+  %tmp11 = fadd float %tmp10, %tmp8
+  store float %tmp11, float* %tmp9, align 4
+  br label %bb12
+
+bb12:                                             ; preds = %bb7
+  %tmp13 = add nuw nsw i64 %j.0, 1
+  br label %bb6
+
+bb14:                                             ; preds = %bb6
+  br label %bb15
+
+bb15:                                             ; preds = %bb14
+  %tmp16 = add nuw nsw i64 %i.0, 1
+  br label %bb4
+
+bb17:                                             ; preds = %bb4
+  %tmp18 = getelementptr inbounds [400 x float], [400 x float]* %A, i64 100, i64 100
+  %tmp19 = load float, float* %tmp18, align 4
+  %tmp20 = getelementptr inbounds [400 x float], [400 x float]* %A, i64 0, i64 0
+  %tmp21 = load float, float* %tmp20, align 4
+  %tmp22 = fadd float %tmp21, %tmp19
+  store float %tmp22, float* %tmp20, align 4
+  br label %bb23
+
+bb23:                                             ; preds = %bb35, %bb17
+  %i1.0 = phi i64 [ 0, %bb17 ], [ %tmp36, %bb35 ]
+  %exitcond1 = icmp ne i64 %i1.0, 400
+  br i1 %exitcond1, label %bb24, label %bb37
+
+bb24:                                             ; preds = %bb23
+  br label %bb25
+
+bb25:                                             ; preds = %bb32, %bb24
+  %j2.0 = phi i64 [ 0, %bb24 ], [ %tmp33, %bb32 ]
+  %exitcond = icmp ne i64 %j2.0, 400
+  br i1 %exitcond, label %bb26, label %bb34
+
+bb26:                                             ; preds = %bb25
+  %tmp27 = add nuw nsw i64 %i1.0, %j2.0
+  %tmp28 = sitofp i64 %tmp27 to float
+  %tmp29 = getelementptr inbounds [400 x float], [400 x float]* %A, i64 %i1.0, i64 %j2.0
+  %tmp30 = load float, float* %tmp29, align 4
+  %tmp31 = fadd float %tmp30, %tmp28
+  store float %tmp31, float* %tmp29, align 4
+  br label %bb32
+
+bb32:                                             ; preds = %bb26
+  %tmp33 = add nuw nsw i64 %j2.0, 1
+  br label %bb25
+
+bb34:                                             ; preds = %bb25
+  br label %bb35
+
+bb35:                                             ; preds = %bb34
+  %tmp36 = add nuw nsw i64 %i1.0, 1
+  br label %bb23
+
+bb37:                                             ; preds = %bb23
+  ret void
+}
+
+define void @first_lower_dimensional([400 x float]* %A, [400 x float]* %B) {
+bb:
+  br label %bb4
+
+bb4:                                              ; preds = %bb15, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp16, %bb15 ]
+  %exitcond3 = icmp ne i64 %i.0, 400
+  br i1 %exitcond3, label %bb5, label %bb17
+
+bb5:                                              ; preds = %bb4
+  br label %bb6
+
+bb6:                                              ; preds = %bb12, %bb5
+  %j.0 = phi i64 [ 0, %bb5 ], [ %tmp13, %bb12 ]
+  %exitcond2 = icmp ne i64 %j.0, 400
+  br i1 %exitcond2, label %bb7, label %bb14
+
+bb7:                                              ; preds = %bb6
+  %tmp = add nuw nsw i64 %i.0, %j.0
+  %tmp8 = sitofp i64 %tmp to float
+  %tmp9 = getelementptr inbounds [400 x float], [400 x float]* %B, i64 %i.0, i64 %j.0
+  %tmp10 = load float, float* %tmp9, align 4
+  %tmp11 = fadd float %tmp10, %tmp8
+  store float %tmp11, float* %tmp9, align 4
+  br label %bb12
+
+bb12:                                             ; preds = %bb7
+  %tmp13 = add nuw nsw i64 %j.0, 1
+  br label %bb6
+
+bb14:                                             ; preds = %bb6
+  br label %bb15
+
+bb15:                                             ; preds = %bb14
+  %tmp16 = add nuw nsw i64 %i.0, 1
+  br label %bb4
+
+bb17:                                             ; preds = %bb4
+  %tmp18 = getelementptr inbounds [400 x float], [400 x float]* %B, i64 100, i64 100
+  %tmp19 = load float, float* %tmp18, align 4
+  %tmp20 = getelementptr inbounds [400 x float], [400 x float]* %A, i64 0, i64 0
+  %tmp21 = load float, float* %tmp20, align 4
+  %tmp22 = fadd float %tmp21, %tmp19
+  store float %tmp22, float* %tmp20, align 4
+  br label %bb23
+
+bb23:                                             ; preds = %bb35, %bb17
+  %i1.0 = phi i64 [ 0, %bb17 ], [ %tmp36, %bb35 ]
+  %exitcond1 = icmp ne i64 %i1.0, 400
+  br i1 %exitcond1, label %bb24, label %bb37
+
+bb24:                                             ; preds = %bb23
+  br label %bb25
+
+bb25:                                             ; preds = %bb32, %bb24
+  %j2.0 = phi i64 [ 0, %bb24 ], [ %tmp33, %bb32 ]
+  %exitcond = icmp ne i64 %j2.0, 400
+  br i1 %exitcond, label %bb26, label %bb34
+
+bb26:                                             ; preds = %bb25
+  %tmp27 = add nuw nsw i64 %i1.0, %j2.0
+  %tmp28 = sitofp i64 %tmp27 to float
+  %tmp29 = getelementptr inbounds [400 x float], [400 x float]* %A, i64 %i1.0, i64 %j2.0
+  %tmp30 = load float, float* %tmp29, align 4
+  %tmp31 = fadd float %tmp30, %tmp28
+  store float %tmp31, float* %tmp29, align 4
+  br label %bb32
+
+bb32:                                             ; preds = %bb26
+  %tmp33 = add nuw nsw i64 %j2.0, 1
+  br label %bb25
+
+bb34:                                             ; preds = %bb25
+  br label %bb35
+
+bb35:                                             ; preds = %bb34
+  %tmp36 = add nuw nsw i64 %i1.0, 1
+  br label %bb23
+
+bb37:                                             ; preds = %bb23
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_fixedsize_multi_offset.ll b/final/test/ScopInfo/multidim_fixedsize_multi_offset.ll
new file mode 100644
index 0000000..8cf2e8d
--- /dev/null
+++ b/final/test/ScopInfo/multidim_fixedsize_multi_offset.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK:      Context:
+; CHECK-NEXT: {  :  }
+; CHECK:      Assumed Context:
+; CHECK-NEXT: {  :  }
+; CHECK:      Invalid Context:
+; CHECK-NEXT: {  : 1 = 0 }
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_for_body[i0] : 0 <= i0 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_for_body[i0] -> [i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body[i0] -> MemRef_A[i0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body[i0] -> MemRef_A[i0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body[i0] -> MemRef_A[1 + i0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body[i0] -> MemRef_A[1 + i0, 0] };
+; CHECK-NEXT: }
+;
+;    void f(int A[][2]) {
+;      int(*B)[2] = &A[0][0];
+;      int(*C)[2] = &A[1][0];
+;      for (int i = 0; i < 100; i++) {
+;        B[i][0]++;
+;        C[i][0]++;
+;      }
+;    }
+;
+; Verify that the additional offset to A by accessing it through C is taken into
+; account.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f([2 x i32]* %A) {
+entry:
+  %arrayidx3 = getelementptr inbounds [2 x i32], [2 x i32]* %A, i64 1, i64 0
+  %tmp = bitcast i32* %arrayidx3 to [2 x i32]*
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx5 = getelementptr inbounds [2 x i32], [2 x i32]* %A, i64 %indvars.iv, i64 0
+  %tmp1 = load i32, i32* %arrayidx5, align 4
+  %inc = add nsw i32 %tmp1, 1
+  store i32 %inc, i32* %arrayidx5, align 4
+  %arrayidx8 = getelementptr inbounds [2 x i32], [2 x i32]* %tmp, i64 %indvars.iv, i64 0
+  %tmp2 = load i32, i32* %arrayidx8, align 4
+  %inc9 = add nsw i32 %tmp2, 1
+  store i32 %inc9, i32* %arrayidx8, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_fold_constant_dim.ll b/final/test/ScopInfo/multidim_fold_constant_dim.ll
new file mode 100644
index 0000000..1ee555f
--- /dev/null
+++ b/final/test/ScopInfo/multidim_fold_constant_dim.ll
@@ -0,0 +1,93 @@
+; RUN: opt %loadPolly -polly-scops -analyze -S < %s | FileCheck %s
+;
+;    struct com {
+;      double Real;
+;      double Img;
+;    };
+;
+;    void foo(long n, struct com A[][n]) {
+;      for (long i = 0; i < 100; i++)
+;        for (long j = 0; j < 1000; j++)
+;          A[i][j].Real += A[i][j].Img;
+;    }
+;
+;    int main() {
+;      struct com A[100][1000];
+;      foo(1000, A);
+;    }
+
+; CHECK:      Arrays {
+; CHECK-NEXT:     double MemRef_A[*][(2 * %n)]; // Element size 8
+; CHECK-NEXT: }
+
+; CHECK: 	Stmt_for_body3
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_for_body3[i0, i1] : 0 <= i0 <= 99 and 0 <= i1 <= 999 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_for_body3[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0, 1 + 2i1] };
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0, 2i1] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0, 2i1] };
+
+source_filename = "/tmp/test.c"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.com = type { double, double }
+
+define void @foo(i64 %n, %struct.com* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc7, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc8, %for.inc7 ]
+  %exitcond1 = icmp ne i64 %i.0, 100
+  br i1 %exitcond1, label %for.body, label %for.end9
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i64 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i64 %j.0, 1000
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %tmp = mul nsw i64 %i.0, %n
+  %arrayidx = getelementptr inbounds %struct.com, %struct.com* %A, i64 %tmp
+  %arrayidx4 = getelementptr inbounds %struct.com, %struct.com* %arrayidx, i64 %j.0
+  %Img = getelementptr inbounds %struct.com, %struct.com* %arrayidx4, i64 0, i32 1
+  %tmp2 = load double, double* %Img, align 8
+  %tmp3 = mul nsw i64 %i.0, %n
+  %arrayidx5 = getelementptr inbounds %struct.com, %struct.com* %A, i64 %tmp3
+  %arrayidx6 = getelementptr inbounds %struct.com, %struct.com* %arrayidx5, i64 %j.0
+  %Real = getelementptr inbounds %struct.com, %struct.com* %arrayidx6, i64 0, i32 0
+  %tmp4 = load double, double* %Real, align 8
+  %add = fadd double %tmp4, %tmp2
+  store double %add, double* %Real, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nuw nsw i64 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc7
+
+for.inc7:                                         ; preds = %for.end
+  %inc8 = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end9:                                         ; preds = %for.cond
+  ret void
+}
+
+define i32 @main() {
+entry:
+  %A = alloca [100 x [1000 x %struct.com]], align 16
+  %tmp = getelementptr inbounds [100 x [1000 x %struct.com]], [100 x [1000 x %struct.com]]* %A, i64 0, i64 0, i64 0
+  call void @foo(i64 1000, %struct.com* nonnull %tmp)
+  ret i32 0
+}
diff --git a/final/test/ScopInfo/multidim_fold_constant_dim_zero.ll b/final/test/ScopInfo/multidim_fold_constant_dim_zero.ll
new file mode 100644
index 0000000..26f72b4
--- /dev/null
+++ b/final/test/ScopInfo/multidim_fold_constant_dim_zero.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-scops -analyze -debug -S < %s 2>&1 | FileCheck %s
+
+; REQUIRES: asserts
+
+; This test case at some point crashed Polly due to a 'division by zero'
+; when trying to fold the constant dimension into outer dimension.
+; We verify that this scop is detected without crash. We also test the
+; output to undertand that the scop has been analyzed, but has also been
+; invalidated due to the zero size dimension.
+
+; CHECK: Assumed Context:
+; CHECK-NEXT: {  : 1 = 0 }
+; CHECK-NEXT: Invalid Context:
+; CHECK-NEXT: {  : 1 = 0 }
+; CHECK-NEXT: Arrays {
+; CHECK-NEXT:     i8 MemRef_arg[*][0]; // Element size 1
+; CHECK-NEXT: }
+; CHECK-NEXT: Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:     i8 MemRef_arg[*][ { [] -> [(0)] } ]; // Element size 1
+; CHECK-NEXT: }
+; CHECK-NEXT: Alias Groups (0):
+; CHECK-NEXT:     n/a
+; CHECK-NEXT: Statements {
+; CHECK-NEXT: 	Stmt_bb2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb2[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb2[] -> [] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb2[] -> MemRef_arg[0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb2[] -> MemRef_arg[o0, o1] : 1 = 0 };
+; CHECK-NEXT: }
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) #0
+
+define void @hoge([0 x [0 x i8]]* noalias %arg) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb5, %bb
+  br i1 false, label %bb5, label %bb2
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr [0 x [0 x i8]], [0 x [0 x i8]]* %arg, i64 0, i64 0, i64 0
+  store i8 32, i8* %tmp, align 1
+  %tmp3 = getelementptr [0 x [0 x i8]], [0 x [0 x i8]]* %arg, i64 0, i64 0, i64 0
+  %tmp4 = getelementptr i8, i8* %tmp3, i64 1
+  tail call void @llvm.memset.p0i8.i64(i8* %tmp4, i8 32, i64 0, i32 1, i1 false)
+  br label %bb5
+
+bb5:                                              ; preds = %bb2, %bb1
+  br i1 undef, label %bb6, label %bb1
+
+bb6:                                              ; preds = %bb5
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_fortran_2d.ll b/final/test/ScopInfo/multidim_fortran_2d.ll
new file mode 100644
index 0000000..868b3af
--- /dev/null
+++ b/final/test/ScopInfo/multidim_fortran_2d.ll
@@ -0,0 +1,77 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+
+;   subroutine init_array(ni, nj, pi, pj, a)
+;   implicit none
+;
+;   double precision, dimension(nj, ni) :: a
+;   integer*8 :: ni, nj
+;   integer*8 :: pi, pj
+;   integer*8 :: i, j
+;
+;   do i = 1, ni
+;     do j = 1, nj
+;       a(j, i) = i + j
+;     end do
+;   end do
+;   end subroutine
+;
+;  Verify we correctly delinearize accesses
+
+; CHECK: MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:   [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[i0, i1] };
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @ham(i64* noalias %arg, i64* noalias %arg1, i64* noalias %arg2, i64* noalias %arg3, [0 x double]* noalias %arg4) unnamed_addr {
+bb:
+  br label %bb5
+
+bb5:                                              ; preds = %bb
+  %tmp = load i64, i64* %arg1, align 8
+  %tmp6 = icmp slt i64 %tmp, 0
+  %tmp7 = select i1 %tmp6, i64 0, i64 %tmp
+  %tmp8 = xor i64 %tmp7, -1
+  %tmp9 = load i64, i64* %arg, align 8
+  %tmp10 = icmp sgt i64 %tmp9, 0
+  br i1 %tmp10, label %bb11, label %bb32
+
+bb11:                                             ; preds = %bb5
+  br label %bb12
+
+bb12:                                             ; preds = %bb28, %bb11
+  %tmp13 = phi i64 [ %tmp30, %bb28 ], [ 1, %bb11 ]
+  %tmp14 = load i64, i64* %arg1, align 8
+  %tmp15 = icmp sgt i64 %tmp14, 0
+  br i1 %tmp15, label %bb16, label %bb28
+
+bb16:                                             ; preds = %bb12
+  br label %bb17
+
+bb17:                                             ; preds = %bb17, %bb16
+  %tmp18 = phi i64 [ %tmp26, %bb17 ], [ 1, %bb16 ]
+  %tmp19 = mul i64 %tmp13, %tmp7
+  %tmp20 = add i64 %tmp19, %tmp8
+  %tmp21 = add i64 %tmp20, %tmp18
+  %tmp22 = add i64 %tmp18, %tmp13
+  %tmp23 = sitofp i64 %tmp22 to double
+  %tmp24 = getelementptr [0 x double], [0 x double]* %arg4, i64 0, i64 %tmp21
+  store double %tmp23, double* %tmp24, align 8
+  %tmp25 = icmp eq i64 %tmp18, %tmp14
+  %tmp26 = add i64 %tmp18, 1
+  br i1 %tmp25, label %bb27, label %bb17
+
+bb27:                                             ; preds = %bb17
+  br label %bb28
+
+bb28:                                             ; preds = %bb27, %bb12
+  %tmp29 = icmp eq i64 %tmp13, %tmp9
+  %tmp30 = add i64 %tmp13, 1
+  br i1 %tmp29, label %bb31, label %bb12
+
+bb31:                                             ; preds = %bb28
+  br label %bb32
+
+bb32:                                             ; preds = %bb31, %bb5
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_fortran_2d_params.ll b/final/test/ScopInfo/multidim_fortran_2d_params.ll
new file mode 100644
index 0000000..d4fa53d
--- /dev/null
+++ b/final/test/ScopInfo/multidim_fortran_2d_params.ll
@@ -0,0 +1,86 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-precise-fold-accesses \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+
+;   subroutine init_array(ni, nj, pi, pj, a)
+;   implicit none
+
+;   double precision, dimension(nj, ni) :: a
+;   integer*8 :: ni, nj
+;   integer*8 :: pi, pj
+;   integer*8 :: i, j
+
+;   do i = 1, ni
+;     do j = 1, nj
+;       a(j + pi, i + pj) = i + j
+;     end do
+;   end do
+;   end subroutine
+
+; CHECK: [tmp9, nj_loaded2, tmp20, tmp19] -> { Stmt_bb17[i0, i1] -> MemRef_a[-1 + tmp20 + i0, nj_loaded2 + tmp19 + i1] : i1 < -tmp19; Stmt_bb17[i0, i1] -> MemRef_a[tmp20 + i0, tmp19 + i1] : i1 >= -tmp19 };
+
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-unknown-linux-gnu"
+
+module asm "\09.ident\09\22GCC: (GNU) 4.6.4 LLVM: 3.3.1\22"
+
+; Function Attrs: nounwind uwtable
+define void @blam(i64* noalias %arg, i64* noalias %nj, i64* noalias %arg2, i64* noalias %arg3, [0 x double]* noalias %a) unnamed_addr #0 {
+bb:
+  br label %bb5
+
+bb5:                                              ; preds = %bb
+  %nj_loaded = load i64, i64* %nj, align 8
+  %tmp6 = icmp slt i64 %nj_loaded, 0
+  %tmp7 = select i1 %tmp6, i64 0, i64 %nj_loaded
+  %tmp8 = xor i64 %tmp7, -1
+  %tmp9 = load i64, i64* %arg, align 8
+  %tmp10 = icmp sgt i64 %tmp9, 0
+  br i1 %tmp10, label %bb11, label %bb36
+
+bb11:                                             ; preds = %bb5
+  br label %bb12
+
+bb12:                                             ; preds = %bb32, %bb11
+  %tmp13 = phi i64 [ %tmp34, %bb32 ], [ 1, %bb11 ]
+  %nj_loaded2 = load i64, i64* %nj, align 8
+  %tmp15 = icmp sgt i64 %nj_loaded2, 0
+  br i1 %tmp15, label %bb16, label %bb32
+
+bb16:                                             ; preds = %bb12
+  br label %bb17
+
+bb17:                                             ; preds = %bb17, %bb16
+  %tmp18 = phi i64 [ %tmp30, %bb17 ], [ 1, %bb16 ]
+  %tmp19 = load i64, i64* %arg2, align 8
+  %tmp20 = load i64, i64* %arg3, align 8
+  %tmp21 = add i64 %tmp20, %tmp13
+  %tmp22 = mul i64 %tmp21, %tmp7
+  %tmp23 = add i64 %tmp18, %tmp8
+  %tmp24 = add i64 %tmp23, %tmp19
+  %tmp25 = add i64 %tmp24, %tmp22
+  %tmp26 = add i64 %tmp18, %tmp13
+  %tmp27 = sitofp i64 %tmp26 to double
+  %tmp28 = getelementptr [0 x double], [0 x double]* %a, i64 0, i64 %tmp25
+  store double %tmp27, double* %tmp28, align 8
+  %tmp29 = icmp eq i64 %tmp18, %nj_loaded2
+  %tmp30 = add i64 %tmp18, 1
+  br i1 %tmp29, label %bb31, label %bb17
+
+bb31:                                             ; preds = %bb17
+  br label %bb32
+
+bb32:                                             ; preds = %bb31, %bb12
+  %tmp33 = icmp eq i64 %tmp13, %tmp9
+  %tmp34 = add i64 %tmp13, 1
+  br i1 %tmp33, label %bb35, label %bb12
+
+bb35:                                             ; preds = %bb32
+  br label %bb36
+
+bb36:                                             ; preds = %bb35, %bb5
+  ret void
+}
+
+attributes #0 = { nounwind uwtable }
diff --git a/final/test/ScopInfo/multidim_fortran_2d_with_modref_call.ll b/final/test/ScopInfo/multidim_fortran_2d_with_modref_call.ll
new file mode 100644
index 0000000..786ad84
--- /dev/null
+++ b/final/test/ScopInfo/multidim_fortran_2d_with_modref_call.ll
@@ -0,0 +1,184 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-allow-modref-calls \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN:  < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -analyze \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN: -polly-allow-modref-calls < %s | FileCheck %s --check-prefix=NONAFFINE
+
+;  TODO: We should delinearize the accesses despite the use in a call to a
+;        readonly function. For now we verify we do not delinearize them though.
+
+; CHECK:         Function: ham
+; CHECK-NEXT:    Region: %bb12---%bb28
+; CHECK-NEXT:    Max Loop Depth:  1
+; CHECK-NEXT:    Invariant Accesses: {
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb12[] -> MemRef_arg1[0] };
+; CHECK-NEXT:            Execution Context: [tmp14, p_1] -> {  :  }
+; CHECK-NEXT:    }
+; CHECK-NEXT:    Context:
+; CHECK-NEXT:    [tmp14, p_1] -> {  : -9223372036854775808 <= tmp14 <= 9223372036854775807 and -9223372036854775808 <= p_1 <= 9223372036854775807 }
+; CHECK-NEXT:    Assumed Context:
+; CHECK-NEXT:    [tmp14, p_1] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [tmp14, p_1] -> { : tmp14 > 0 and (p_1 <= -1152921504606846977 or tmp14 >= 1152921504606846977 or p_1 >= 1152921504606846977 - tmp14) }
+; CHECK-NEXT:    p0: %tmp14
+; CHECK-NEXT:    p1: {0,+,(0 smax %tmp)}<%bb12>
+; CHECK-NEXT:    Arrays {
+; CHECK-NEXT:        i64 MemRef_arg1[*]; // Element size 8
+; CHECK-NEXT:        i64 MemRef_tmp13; // Element size 8
+; CHECK-NEXT:        double MemRef_arg4[*]; // Element size 8
+; CHECK-NEXT:    }
+; CHECK-NEXT:    Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:        i64 MemRef_arg1[*]; // Element size 8
+; CHECK-NEXT:        i64 MemRef_tmp13; // Element size 8
+; CHECK-NEXT:        double MemRef_arg4[*]; // Element size 8
+; CHECK-NEXT:    }
+; CHECK-NEXT:    Alias Groups (0):
+; CHECK-NEXT:        n/a
+; CHECK-NEXT:    Statements {
+; CHECK-NEXT:    	Stmt_bb12
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb12[] };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb12[] -> [0, 0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb12[] -> MemRef_tmp13[] };
+; CHECK-NEXT:    	Stmt_bb17
+; CHECK-NEXT:            Domain :=
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] : 0 <= i0 < tmp14 };
+; CHECK-NEXT:            Schedule :=
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] -> [1, i0] };
+; CHECK-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg4[p_1 + i0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg1[o0] };
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [tmp14, p_1] -> { Stmt_bb17[i0] -> MemRef_arg4[o0] };
+; CHECK-NEXT:    }
+
+; NONAFFINE:         Function: ham
+; NONAFFINE-NEXT:    Region: %bb5---%bb32
+; NONAFFINE-NEXT:    Max Loop Depth:  2
+; NONAFFINE-NEXT:    Invariant Accesses: {
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_arg[0] };
+; NONAFFINE-NEXT:            Execution Context: [tmp9, tmp14] -> {  :  }
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb12[i0] -> MemRef_arg1[0] };
+; NONAFFINE-NEXT:            Execution Context: [tmp9, tmp14] -> {  :  }
+; NONAFFINE-NEXT:    }
+; NONAFFINE-NEXT:    Context:
+; NONAFFINE-NEXT:    [tmp9, tmp14] -> {  : -9223372036854775808 <= tmp9 <= 9223372036854775807 and -9223372036854775808 <= tmp14 <= 9223372036854775807 }
+; NONAFFINE-NEXT:    Assumed Context:
+; NONAFFINE-NEXT:    [tmp9, tmp14] -> {  :  }
+; NONAFFINE-NEXT:    Invalid Context:
+; NONAFFINE-NEXT:    [tmp9, tmp14] -> {  : 1 = 0 }
+; NONAFFINE-NEXT:    p0: %tmp9
+; NONAFFINE-NEXT:    p1: %tmp14
+; NONAFFINE-NEXT:    Arrays {
+; NONAFFINE-NEXT:        i64 MemRef_arg[*]; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_arg1[*]; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_tmp7; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_tmp8; // Element size 8
+; NONAFFINE-NEXT:        double MemRef_arg4[*]; // Element size 8
+; NONAFFINE-NEXT:    }
+; NONAFFINE-NEXT:    Arrays (Bounds as pw_affs) {
+; NONAFFINE-NEXT:        i64 MemRef_arg[*]; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_arg1[*]; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_tmp7; // Element size 8
+; NONAFFINE-NEXT:        i64 MemRef_tmp8; // Element size 8
+; NONAFFINE-NEXT:        double MemRef_arg4[*]; // Element size 8
+; NONAFFINE-NEXT:    }
+; NONAFFINE-NEXT:    Alias Groups (0):
+; NONAFFINE-NEXT:        n/a
+; NONAFFINE-NEXT:    Statements {
+; NONAFFINE-NEXT:    	Stmt_bb5
+; NONAFFINE-NEXT:            Domain :=
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] };
+; NONAFFINE-NEXT:            Schedule :=
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] -> [0, 0, 0] };
+; NONAFFINE-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_tmp7[] };
+; NONAFFINE-NEXT:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb5[] -> MemRef_tmp8[] };
+; NONAFFINE-NEXT:    	Stmt_bb17
+; NONAFFINE-NEXT:            Domain :=
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] : 0 <= i0 < tmp9 and 0 <= i1 < tmp14 };
+; NONAFFINE-NEXT:            Schedule :=
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> [1, i0, i1] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_tmp7[] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_tmp8[] };
+; NONAFFINE-NEXT:            MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[o0] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg[o0] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg1[o0] };
+; NONAFFINE-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:                [tmp9, tmp14] -> { Stmt_bb17[i0, i1] -> MemRef_arg4[o0] };
+; NONAFFINE-NEXT:    }
+
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @ham(i64* noalias %arg, i64* noalias %arg1, i64* noalias %arg2, i64* noalias %arg3, [0 x double]* noalias %arg4) unnamed_addr {
+bb:
+  br label %bb5
+
+bb5:                                              ; preds = %bb
+  %tmp = load i64, i64* %arg1, align 8
+  %tmp6 = icmp slt i64 %tmp, 0
+  %tmp7 = select i1 %tmp6, i64 0, i64 %tmp
+  %tmp8 = xor i64 %tmp7, -1
+  %tmp9 = load i64, i64* %arg, align 8
+  %tmp10 = icmp sgt i64 %tmp9, 0
+  br i1 %tmp10, label %bb11, label %bb32
+
+bb11:                                             ; preds = %bb5
+  br label %bb12
+
+bb12:                                             ; preds = %bb28, %bb11
+  %tmp13 = phi i64 [ %tmp30, %bb28 ], [ 1, %bb11 ]
+  %tmp14 = load i64, i64* %arg1, align 8
+  %tmp15 = icmp sgt i64 %tmp14, 0
+  br i1 %tmp15, label %bb16, label %bb28
+
+bb16:                                             ; preds = %bb12
+  br label %bb17
+
+bb17:                                             ; preds = %bb17, %bb16
+  %tmp18 = phi i64 [ %tmp26, %bb17 ], [ 1, %bb16 ]
+  %tmp19 = mul i64 %tmp13, %tmp7
+  %tmp20 = add i64 %tmp19, %tmp8
+  %tmp21 = add i64 %tmp20, %tmp18
+  %tmp22 = add i64 %tmp18, %tmp13
+  %tmp23 = sitofp i64 %tmp22 to double
+  %tmp24 = getelementptr [0 x double], [0 x double]* %arg4, i64 0, i64 %tmp21
+  %call = call double @func(double* %tmp24) #2
+  %sum = fadd double %call, %tmp23
+  store double %sum, double* %tmp24, align 8
+  %tmp25 = icmp eq i64 %tmp18, %tmp14
+  %tmp26 = add i64 %tmp18, 1
+  br i1 %tmp25, label %bb27, label %bb17
+
+bb27:                                             ; preds = %bb17
+  br label %bb28
+
+bb28:                                             ; preds = %bb27, %bb12
+  %tmp29 = icmp eq i64 %tmp13, %tmp9
+  %tmp30 = add i64 %tmp13, 1
+  br i1 %tmp29, label %bb31, label %bb12
+
+bb31:                                             ; preds = %bb28
+  br label %bb32
+
+bb32:                                             ; preds = %bb31, %bb5
+  ret void
+}
+
+declare double @func(double*) #1
+
+attributes #1 = { nounwind readonly }
diff --git a/final/test/ScopInfo/multidim_fortran_srem.ll b/final/test/ScopInfo/multidim_fortran_srem.ll
new file mode 100644
index 0000000..46cec71
--- /dev/null
+++ b/final/test/ScopInfo/multidim_fortran_srem.ll
@@ -0,0 +1,192 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb188
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb188[i0] : 0 <= i0 <= -3 + tmp183 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb188[i0] -> [i0, 0, 0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb188[i0] -> MemRef_tmp192[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb188[i0] -> MemRef_tmp194[] };
+; CHECK-NEXT:     Stmt_bb203
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] : 0 <= i0 <= -3 + tmp183 and 0 <= i1 <= -3 + tmp180 and 0 <= i2 <= -3 + tmp177 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> [i0, 1, i1, i2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> MemRef_tmp192[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> MemRef_tmp173[o0, 1 + i1, 1 + i2] : 3*floor((-i0 + o0)/3) = -i0 + o0 and 0 <= o0 <= 2 };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> MemRef_tmp194[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> MemRef_tmp173[o0, 1 + i1, 1 + i2] : 3*floor((1 - i0 + o0)/3) = 1 - i0 + o0 and 0 <= o0 <= 2 };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> MemRef_arg56[1 + i0, 1 + i1, 1 + i2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [tmp180, tmp177, tmp183, tmp162, tmp157, tmp150, tmp146, tmp140, tmp] -> { Stmt_bb203[i0, i1, i2] -> MemRef_arg55[1 + i0, 1 + i1, 1 + i2] };
+; CHECK-NEXT: }
+
+define void @pluto(i32* noalias %arg, [0 x i32]* noalias %arg2, [0 x i32]* noalias %arg3, [0 x i32]* noalias %arg4, [0 x i32]* noalias %arg5, [0 x i32]* noalias %arg6, [0 x i32]* noalias %arg7, [0 x i32]* noalias %arg8, [0 x i32]* noalias %arg9, double* noalias %arg10, double* noalias %arg11, [0 x double]* noalias %arg12, [0 x double]* noalias %arg13, [0 x i32]* noalias %arg14, i32* noalias %arg15, [0 x i32]* noalias %arg16, i32* noalias %arg17, i32* noalias %arg18, i32* noalias %arg19, i32* noalias %arg20, i32* noalias %arg21, i32* noalias %arg22, i32* noalias %arg23, i32* noalias %arg24, i32* noalias %arg25, i32* noalias %arg26, i32* noalias %arg27, [0 x double]* noalias %arg28, [0 x double]* noalias %arg29, [0 x double]* noalias %arg30, [0 x double]* noalias %arg31, [0 x double]* noalias %arg32, [0 x double]* noalias %arg33, [0 x double]* noalias %arg34, [0 x double]* noalias %arg35, [0 x double]* noalias %arg36, [0 x double]* noalias %arg37, [0 x double]* noalias %arg38, [0 x double]* noalias %arg39, [0 x double]* noalias %arg40, [0 x double]* noalias %arg41, [0 x double]* noalias %arg42, [0 x double]* noalias %arg43, [0 x double]* noalias %arg44, [0 x double]* noalias %arg45, [0 x double]* noalias %arg46, [0 x double]* noalias %arg47, [0 x double]* noalias %arg48, [0 x double]* noalias %arg49, [0 x double]* noalias %arg50, [0 x double]* noalias %arg51, [0 x double]* noalias %arg52, [0 x double]* noalias %arg53, [0 x double]* noalias %arg54, [0 x double]* noalias %arg55, [0 x double]* noalias %arg56, [0 x double]* noalias %arg57, [0 x double]* noalias %arg58, [0 x double]* noalias %arg59, [0 x double]* noalias %arg60, [0 x double]* noalias %arg61, [0 x double]* noalias %arg62, [0 x double]* noalias %arg63, [0 x double]* noalias %arg64, [0 x double]* noalias %arg65, [0 x double]* noalias %arg66, [0 x double]* noalias %arg67, [0 x double]* noalias %arg68, [0 x double]* noalias %arg69, i32* noalias %arg70, i32* noalias %arg71, i32* noalias %arg72, i32* noalias %arg73, i32* noalias %arg74, i32* noalias %arg75, i32* noalias %arg76, i32* noalias %arg77, i32* noalias %arg78, i32* noalias %arg79, i32* noalias %arg80, i32* noalias %arg81, i32* noalias %arg82, i32* noalias %arg83, i32* noalias %arg84, i32* noalias %arg85, i32* noalias %arg86, i32* noalias %arg87, i32* noalias %arg88, i32* noalias %arg89, i32* noalias %arg90, i32* noalias %arg91, i32* noalias %arg92, i32* noalias %arg93, i32* noalias %arg94, i32* noalias %arg95, i32* noalias %arg96, i32* noalias %arg97, [0 x double]* noalias %arg98, [0 x double]* noalias %arg99, [0 x double]* noalias %arg100, [0 x double]* noalias %arg101, double* noalias %arg102, double* noalias %arg103, double* noalias %arg104, i32* noalias %arg105, double* noalias %arg106, double* noalias %arg107, [0 x double]* noalias %arg108, [0 x double]* noalias %arg109, [0 x double]* noalias %arg110, [0 x double]* noalias %arg111, [0 x double]* noalias %arg112, [0 x double]* noalias %arg113, [0 x double]* noalias %arg114, [0 x double]* noalias %arg115, [0 x double]* noalias %arg116, [0 x double]* noalias %arg117, [0 x double]* noalias %arg118, [0 x double]* noalias %arg119, [0 x double]* noalias %arg120, [0 x double]* noalias %arg121, [0 x double]* noalias %arg122, [0 x double]* noalias %arg123, [0 x double]* noalias %arg124, [0 x double]* noalias %arg125, [0 x double]* noalias %arg126, [0 x double]* noalias %arg127, [0 x double]* noalias %arg128, [0 x double]* noalias %arg129, [0 x double]* noalias %arg130, [0 x double]* noalias %arg131, i32* noalias %arg132, [0 x double]* noalias %arg133, [0 x double]* noalias %arg134, [0 x double]* noalias %arg135) {
+bb:
+  br label %bb136
+
+bb136:                                            ; preds = %bb
+  %tmp = load i32, i32* %arg19, align 4
+  %tmp137 = sext i32 %tmp to i64
+  %tmp138 = icmp slt i64 %tmp137, 0
+  %tmp139 = select i1 %tmp138, i64 0, i64 %tmp137
+  %tmp140 = load i32, i32* %arg20, align 4
+  %tmp141 = sext i32 %tmp140 to i64
+  %tmp142 = mul nsw i64 %tmp139, %tmp141
+  %tmp143 = icmp slt i64 %tmp142, 0
+  %tmp144 = select i1 %tmp143, i64 0, i64 %tmp142
+  %tmp145 = xor i64 %tmp139, -1
+  %tmp146 = load i32, i32* %arg19, align 4
+  %tmp147 = sext i32 %tmp146 to i64
+  %tmp148 = icmp slt i64 %tmp147, 0
+  %tmp149 = select i1 %tmp148, i64 0, i64 %tmp147
+  %tmp150 = load i32, i32* %arg20, align 4
+  %tmp151 = sext i32 %tmp150 to i64
+  %tmp152 = mul nsw i64 %tmp149, %tmp151
+  %tmp153 = icmp slt i64 %tmp152, 0
+  %tmp154 = select i1 %tmp153, i64 0, i64 %tmp152
+  %tmp155 = xor i64 %tmp149, -1
+  %tmp156 = getelementptr inbounds [0 x i32], [0 x i32]* %arg3, i64 0, i64 0
+  %tmp157 = load i32, i32* %tmp156, align 4
+  %tmp158 = sext i32 %tmp157 to i64
+  %tmp159 = icmp slt i64 %tmp158, 0
+  %tmp160 = select i1 %tmp159, i64 0, i64 %tmp158
+  %tmp161 = getelementptr [0 x i32], [0 x i32]* %arg3, i64 0, i64 1
+  %tmp162 = load i32, i32* %tmp161, align 4
+  %tmp163 = sext i32 %tmp162 to i64
+  %tmp164 = mul nsw i64 %tmp160, %tmp163
+  %tmp165 = icmp slt i64 %tmp164, 0
+  %tmp166 = select i1 %tmp165, i64 0, i64 %tmp164
+  %tmp167 = mul i64 %tmp166, 3
+  %tmp168 = icmp slt i64 %tmp167, 0
+  %tmp169 = select i1 %tmp168, i64 0, i64 %tmp167
+  %tmp170 = shl i64 %tmp169, 3
+  %tmp171 = icmp ne i64 %tmp170, 0
+  %tmp172 = select i1 %tmp171, i64 %tmp170, i64 1
+  %tmp173 = tail call noalias i8* @wobble(i64 %tmp172) #1
+  %tmp174 = xor i64 %tmp160, -1
+  %tmp175 = sub i64 %tmp174, %tmp166
+  %tmp176 = getelementptr inbounds [0 x i32], [0 x i32]* %arg3, i64 0, i64 0
+  %tmp177 = load i32, i32* %tmp176, align 4
+  %tmp178 = sext i32 %tmp177 to i64
+  %tmp179 = getelementptr [0 x i32], [0 x i32]* %arg3, i64 0, i64 1
+  %tmp180 = load i32, i32* %tmp179, align 4
+  %tmp181 = sext i32 %tmp180 to i64
+  %tmp182 = getelementptr [0 x i32], [0 x i32]* %arg3, i64 0, i64 2
+  %tmp183 = load i32, i32* %tmp182, align 4
+  %tmp184 = sext i32 %tmp183 to i64
+  %tmp185 = add nsw i64 %tmp184, -1
+  %tmp186 = icmp sgt i64 %tmp185, 1
+  br i1 %tmp186, label %bb187, label %bb249
+
+bb187:                                            ; preds = %bb136
+  br label %bb188
+
+bb188:                                            ; preds = %bb187, %bb245
+  %tmp189 = phi i64 [ %tmp247, %bb245 ], [ 2, %bb187 ]
+  %tmp190 = add i64 %tmp189, -2
+  %tmp191 = srem i64 %tmp190, 3
+  %tmp192 = add nsw i64 %tmp191, 1
+  %tmp193 = srem i64 %tmp189, 3
+  %tmp194 = add nsw i64 %tmp193, 1
+  %tmp195 = add nsw i64 %tmp181, -1
+  %tmp196 = icmp sgt i64 %tmp195, 1
+  br i1 %tmp196, label %bb197, label %bb245
+
+bb197:                                            ; preds = %bb188
+  br label %bb198
+
+bb198:                                            ; preds = %bb197, %bb241
+  %tmp199 = phi i64 [ %tmp243, %bb241 ], [ 2, %bb197 ]
+  %tmp200 = add nsw i64 %tmp178, -1
+  %tmp201 = icmp sgt i64 %tmp200, 1
+  br i1 %tmp201, label %bb202, label %bb241
+
+bb202:                                            ; preds = %bb198
+  br label %bb203
+
+bb203:                                            ; preds = %bb202, %bb203
+  %tmp204 = phi i64 [ %tmp239, %bb203 ], [ 2, %bb202 ]
+  %tmp205 = mul i64 %tmp199, %tmp160
+  %tmp206 = mul i64 %tmp192, %tmp166
+  %tmp207 = add i64 %tmp206, %tmp175
+  %tmp208 = add i64 %tmp207, %tmp205
+  %tmp209 = add i64 %tmp208, %tmp204
+  %tmp210 = bitcast i8* %tmp173 to double*
+  %tmp211 = getelementptr double, double* %tmp210, i64 %tmp209
+  %tmp212 = load double, double* %tmp211, align 8
+  %tmp213 = mul i64 %tmp199, %tmp160
+  %tmp214 = mul i64 %tmp194, %tmp166
+  %tmp215 = add i64 %tmp214, %tmp175
+  %tmp216 = add i64 %tmp215, %tmp213
+  %tmp217 = add i64 %tmp216, %tmp204
+  %tmp218 = bitcast i8* %tmp173 to double*
+  %tmp219 = getelementptr double, double* %tmp218, i64 %tmp217
+  %tmp220 = load double, double* %tmp219, align 8
+  %tmp221 = fadd double %tmp212, %tmp220
+  %tmp222 = mul i64 %tmp199, %tmp139
+  %tmp223 = mul i64 %tmp189, %tmp144
+  %tmp224 = sub i64 %tmp145, %tmp144
+  %tmp225 = add i64 %tmp224, %tmp223
+  %tmp226 = add i64 %tmp225, %tmp222
+  %tmp227 = add i64 %tmp226, %tmp204
+  %tmp228 = mul i64 %tmp199, %tmp149
+  %tmp229 = mul i64 %tmp189, %tmp154
+  %tmp230 = sub i64 %tmp155, %tmp154
+  %tmp231 = add i64 %tmp230, %tmp229
+  %tmp232 = add i64 %tmp231, %tmp228
+  %tmp233 = add i64 %tmp232, %tmp204
+  %tmp234 = getelementptr [0 x double], [0 x double]* %arg56, i64 0, i64 %tmp233
+  %tmp235 = load double, double* %tmp234, align 8
+  %tmp236 = fadd double %tmp235, %tmp221
+  %tmp237 = getelementptr [0 x double], [0 x double]* %arg55, i64 0, i64 %tmp227
+  store double %tmp236, double* %tmp237, align 8
+  %tmp238 = icmp eq i64 %tmp204, %tmp200
+  %tmp239 = add i64 %tmp204, 1
+  br i1 %tmp238, label %bb240, label %bb203
+
+bb240:                                            ; preds = %bb203
+  br label %bb241
+
+bb241:                                            ; preds = %bb240, %bb198
+  %tmp242 = icmp eq i64 %tmp199, %tmp195
+  %tmp243 = add i64 %tmp199, 1
+  br i1 %tmp242, label %bb244, label %bb198
+
+bb244:                                            ; preds = %bb241
+  br label %bb245
+
+bb245:                                            ; preds = %bb244, %bb188
+  %tmp246 = icmp eq i64 %tmp189, %tmp185
+  %tmp247 = add i64 %tmp189, 1
+  br i1 %tmp246, label %bb248, label %bb188
+
+bb248:                                            ; preds = %bb245
+  br label %bb249
+
+bb249:                                            ; preds = %bb248, %bb136
+  %tmp250 = icmp eq i8* %tmp173, null
+  br i1 %tmp250, label %bb252, label %bb251
+
+bb251:                                            ; preds = %bb249
+  tail call void @snork(i8* %tmp173) #1
+  br label %bb252
+
+bb252:                                            ; preds = %bb251, %bb249
+  ret void
+}
+
+; Function Attrs: nounwind
+declare noalias i8* @wobble(i64) #1
+
+; Function Attrs: nounwind
+declare void @snork(i8*) #1
diff --git a/final/test/ScopInfo/multidim_gep_pointercast.ll b/final/test/ScopInfo/multidim_gep_pointercast.ll
new file mode 100644
index 0000000..3091767
--- /dev/null
+++ b/final/test/ScopInfo/multidim_gep_pointercast.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; The load access to A has a pointer-bitcast to another elements size before the
+; GetElementPtr. Verify that we do not the GEP delinearization because it
+; mismatches with the size of the loaded element type.
+;
+;    void f(short A[][4], int N, int P) {
+;      short(*B)[4] = &A[P][0];
+;      for (int i = 0; i < N; i++)
+;        *((<4 x short> *)&A[7 * i][0]) = *((<4 x short>)&B[7 * i][0]);
+;    }
+;
+define void @f([4 x i16]* %A, i32 %N, i32 %P) {
+entry:
+  %arrayidx1 = getelementptr inbounds [4 x i16], [4 x i16]* %A, i32 %P, i64 0
+  %tmp = bitcast i16* %arrayidx1 to [4 x i16]*
+  br label %for.cond
+
+for.cond:
+  %indvars.iv = phi i32 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i32 %indvars.iv, %N
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:
+  %mul = mul nsw i32 %indvars.iv, 7
+  %arrayidx4 = getelementptr inbounds [4 x i16], [4 x i16]* %tmp, i32 %mul, i64 0
+  %bc4 = bitcast i16* %arrayidx4 to <4 x i16>*
+  %tmp3 = load <4 x i16>, <4 x i16>* %bc4
+  %arrayidx8 = getelementptr inbounds [4 x i16], [4 x i16]* %A, i32 %mul, i64 0
+  %bc8 = bitcast i16* %arrayidx8 to <4 x i16>*
+  store <4 x i16> %tmp3, <4 x i16>* %bc8
+  br label %for.inc
+
+for.inc:
+  %indvars.iv.next = add nuw nsw i32 %indvars.iv, 1
+  br label %for.cond
+
+for.end:
+  ret void
+}
+
+
+; CHECK:      Arrays {
+; CHECK-NEXT:     <4 x i16> MemRef_A[*]; // Element size 8
+; CHECK-NEXT: }
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, P] -> { Stmt_for_body[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, P] -> { Stmt_for_body[i0] -> [i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N, P] -> { Stmt_for_body[i0] -> MemRef_A[P + 7i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N, P] -> { Stmt_for_body[i0] -> MemRef_A[7i0] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/multidim_gep_pointercast2.ll b/final/test/ScopInfo/multidim_gep_pointercast2.ll
new file mode 100644
index 0000000..2f590d1
--- /dev/null
+++ b/final/test/ScopInfo/multidim_gep_pointercast2.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Verfy that we do not use the GetElementPtr information to delinearize A
+; because of the cast in-between. Use the single-dimensional modeling instead.
+;
+;    void f(short A[][2]) {
+;      for (int i = 0; i < 100; i++)
+;        *((long *)&A[4 * i][0]) = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f([2 x i16]* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = shl nsw i64 %indvars.iv, 2
+  %arrayidx1 = getelementptr inbounds [2 x i16], [2 x i16]* %A, i64 %tmp, i64 0
+  %tmp2 = bitcast i16* %arrayidx1 to i64*
+  store i64 0, i64* %tmp2, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+
+; CHECK:      Arrays {
+; CHECK-NEXT:     i64 MemRef_A[*]; // Element size 8
+; CHECK-NEXT: }
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_for_body[i0] : 0 <= i0 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_for_body[i0] -> [i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body[i0] -> MemRef_A[2i0] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/multidim_ivs_and_integer_offsets_3d.ll b/final/test/ScopInfo/multidim_ivs_and_integer_offsets_3d.ll
new file mode 100644
index 0000000..432b06d
--- /dev/null
+++ b/final/test/ScopInfo/multidim_ivs_and_integer_offsets_3d.ll
@@ -0,0 +1,74 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; void foo(long n, long m, long o, double A[n][m][o]) {
+;
+;   for (long i = 0; i < n-3; i++)
+;     for (long j = 4; j < m; j++)
+;       for (long k = 0; k < o-7; k++)
+;         A[i+3][j-4][k+7] = 1.0;
+; }
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [o, m, n] -> {  :  }
+;
+; CHECK:      p0: %o
+; CHECK-NEXT: p1: %m
+; CHECK-NEXT: p2: %n
+; CHECK-NOT:  p3
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_k
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [o, m, n] -> { Stmt_for_k[i0, i1, i2] : 0 <= i0 <= -4 + n and 0 <= i1 <= -5 + m and 0 <= i2 <= -8 + o };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [o, m, n] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [o, m, n] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[3 + i0, i1, 7 + i2] };
+; CHECK-NEXT: }
+
+define void @foo(i64 %n, i64 %m, i64 %o, double* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 4, %for.i ], [ %j.inc, %for.j.inc ]
+  br label %for.k
+
+for.k:
+  %k = phi i64 [ 0, %for.j ], [ %k.inc, %for.k.inc ]
+  %offset0 = add nsw i64 %i, 3
+  %subscript0 = mul i64 %offset0, %m
+  %offset1 = add nsw i64 %j, -4
+  %subscript1 = add i64 %offset1, %subscript0
+  %subscript2 = mul i64 %subscript1, %o
+  %offset2 = add nsw i64 %k, 7
+  %subscript = add i64 %subscript2, %offset2
+  %idx = getelementptr inbounds double, double* %A, i64 %subscript
+  store double 1.0, double* %idx
+  br label %for.k.inc
+
+for.k.inc:
+  %k.inc = add nsw i64 %k, 1
+  %osub = sub nsw i64 %o, 7
+  %k.exitcond = icmp eq i64 %k.inc, %osub
+  br i1 %k.exitcond, label %for.j.inc, label %for.k
+
+for.j.inc:
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, %m
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %nsub = sub nsw i64 %n, 3
+  %i.exitcond = icmp eq i64 %i.inc, %nsub
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_ivs_and_parameteric_offsets_3d.ll b/final/test/ScopInfo/multidim_ivs_and_parameteric_offsets_3d.ll
new file mode 100644
index 0000000..22bfbab
--- /dev/null
+++ b/final/test/ScopInfo/multidim_ivs_and_parameteric_offsets_3d.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s \
+; RUN:     -polly-precise-fold-accesses | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; void foo(long n, long m, long o, double A[n][m][o], long p, long q, long r) {
+;
+;   for (long i = 0; i < n; i++)
+;     for (long j = 0; j < m; j++)
+;       for (long k = 0; k < o; k++)
+;         A[i+p][j+q][k+r] = 1.0;
+; }
+;
+; Access function:
+;    {{{((8 * ((((%m * %p) + %q) * %o) + %r)) + %A),+,(8 * %m * %o)}<%for.i>,+,
+;        (8 * %o)}<%for.j>,+,8}<%for.k>
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [o, m, n, p, q, r] -> {  : -m <= q <= 1 and ((-m < q <= 0 and -o < r < 0) or (r = 0 and q <= 0) or (r = -o and q > -m)) }
+;
+; CHECK:      p0: %o
+; CHECK-NEXT: p1: %m
+; CHECK-NEXT: p2: %n
+; CHECK-NEXT: p3: %p
+; CHECK-NEXT: p4: %q
+; CHECK-NEXT: p5: %r
+; CHECK-NOT:  p6
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_k
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [o, m, n, p, q, r] -> { Stmt_for_k[i0, i1, i2] : 0 <= i0 < n and 0 <= i1 < m and 0 <= i2 < o };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [o, m, n, p, q, r] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [o, m, n, p, q, r] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[-1 + p + i0, -1 + m + q + i1, o + r + i2] : i1 <= -q and i2 < -r; Stmt_for_k[i0, i1, i2] -> MemRef_A[p + i0, -1 + q + i1, o + r + i2] : i1 > -q and i2 < -r; Stmt_for_k[i0, i1, i2] -> MemRef_A[-1 + p + i0, m + q + i1, r + i2] : i1 < -q and i2 >= -r; Stmt_for_k[i0, i1, i2] -> MemRef_A[p + i0, q + i1, r + i2] : i1 >= -q and i2 >= -r };
+; CHECK-NEXT: }
+
+define void @foo(i64 %n, i64 %m, i64 %o, double* %A, i64 %p, i64 %q, i64 %r) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j.inc ]
+  br label %for.k
+
+for.k:
+  %k = phi i64 [ 0, %for.j ], [ %k.inc, %for.k.inc ]
+  %offset0 = add nsw i64 %i, %p
+  %subscript0 = mul i64 %offset0, %m
+  %offset1 = add nsw i64 %j, %q
+  %subscript1 = add i64 %offset1, %subscript0
+  %subscript2 = mul i64 %subscript1, %o
+  %offset2 = add nsw i64 %k, %r
+  %subscript = add i64 %subscript2, %offset2
+  %idx = getelementptr inbounds double, double* %A, i64 %subscript
+  store double 1.0, double* %idx
+  br label %for.k.inc
+
+for.k.inc:
+  %k.inc = add nsw i64 %k, 1
+  %k.exitcond = icmp eq i64 %k.inc, %o
+  br i1 %k.exitcond, label %for.j.inc, label %for.k
+
+for.j.inc:
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, %m
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %i.exitcond = icmp eq i64 %i.inc, %n
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_many_references.ll b/final/test/ScopInfo/multidim_many_references.ll
new file mode 100644
index 0000000..b65060c
--- /dev/null
+++ b/final/test/ScopInfo/multidim_many_references.ll
@@ -0,0 +1,520 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-ignore-aliasing < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-function-scops -analyze -polly-ignore-aliasing < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; typedef struct Mat {
+;   float* data;
+;   long rows;
+;   long cols;
+;   long deps;
+; } Matrix;
+;
+; #define M(m,r,c,d)  m->data[(r) * m->cols * mt->mdeps + (c) * m->deps + (d)]
+;
+; void jacobi(long nn, Matrix* a1, ..., Matrix* a19) {
+;   long i, j, k, n, imax, jmax, kmax;
+;
+;   for(n = 0 ; n < nn ; n++)
+;     for(i = 1 ; i < a1->rows-1; i++)
+;       for(j = 1 ; j < a1->cols-1; j++)
+;         for(k = 1 ; k < a1->deps-1; k++)
+;           M(a19,i,j,k) = M(a1,i,j,k) + ... + M(a18,i,j,k);
+; }
+;
+; We applied some loop invariant code motion to ensure the loads from m->data,
+; m->rows, m->cols and m->deps happen before the scop.
+
+; This test case verifies that the construction of the assumed context finishes
+; successfully. Depending on how constraineds are accummulated in the assumed
+; context, this test case can take even for a smaller number of arrays over a
+; minute to complete. With the unrolling choosen in this test, an inefficient
+; formulation of the assumption tracking cause LLVM to crash due to excessive
+; memory usage due to an overly large number of disjuncts being formed.
+
+%struct.Mat = type { float*, i64, i64, i64 }
+
+; CHECK: Assumed Context:
+; CHECK-DAG: a2_cols >= -1 + a1_cols
+; CHECK-DAG: a2_deps >= -1 + a1_deps
+; CHECK-DAG: a3_cols >= -1 + a1_cols
+; CHECK-DAG: a3_deps >= -1 + a1_deps
+; CHECK-DAG: a4_cols >= -1 + a1_cols
+; CHECK-DAG: a4_deps >= -1 + a1_deps
+; CHECK-DAG: a5_cols >= -1 + a1_cols
+; CHECK-DAG: a5_deps >= -1 + a1_deps
+; CHECK-DAG: a6_cols >= -1 + a1_cols
+; CHECK-DAG: a6_deps >= -1 + a1_deps
+; CHECK-DAG: a7_cols >= -1 + a1_cols
+; CHECK-DAG: a7_deps >= -1 + a1_deps
+; CHECK-DAG: a8_cols >= -1 + a1_cols
+; CHECK-DAG: a8_deps >= -1 + a1_deps
+; CHECK-DAG: a9_deps >= -1 + a1_deps
+; CHECK-DAG: a9_cols >= -1 + a1_cols
+; CHECK-DAG: a10_cols >= -1 + a1_cols
+; CHECK-DAG: a10_deps >= -1 + a1_deps
+; CHECK-DAG: a11_cols >= -1 + a1_cols
+; CHECK-DAG: a11_deps >= -1 + a1_deps
+; CHECK-DAG: a12_cols >= -1 + a1_cols
+; CHECK-DAG: a12_deps >= -1 + a1_deps
+; CHECK-DAG: a13_cols >= -1 + a1_cols
+; CHECK-DAG: a13_deps >= -1 + a1_deps
+; CHECK-DAG: a14_cols >= -1 + a1_cols
+; CHECK-DAG: a14_deps >= -1 + a1_deps
+; CHECK-DAG: a15_cols >= -1 + a1_cols
+; CHECK-DAG: a15_deps >= -1 + a1_deps
+; CHECK-DAG: a16_cols >= -1 + a1_cols
+; CHECK-DAG: a16_deps >= -1 + a1_deps
+; CHECK-DAG: a17_cols >= -1 + a1_cols
+; CHECK-DAG: a17_deps >= -1 + a1_deps
+; CHECK-DAG: a18_cols >= -1 + a1_cols
+; CHECK-DAG: a18_deps >= -1 + a1_deps
+; CHECK-DAG: a19_deps >= -1 + a1_deps
+; CHECK-DAG: a19_cols >= -1 + a1_cols
+
+define void @jacobi(i64 %nn,
+  %struct.Mat* %a1,
+  %struct.Mat* %a2,
+  %struct.Mat* %a3,
+  %struct.Mat* %a4,
+  %struct.Mat* %a5,
+  %struct.Mat* %a6,
+  %struct.Mat* %a7,
+  %struct.Mat* %a8,
+  %struct.Mat* %a9,
+  %struct.Mat* %a10,
+  %struct.Mat* %a11,
+  %struct.Mat* %a12,
+  %struct.Mat* %a13,
+  %struct.Mat* %a14,
+  %struct.Mat* %a15,
+  %struct.Mat* %a16,
+  %struct.Mat* %a17,
+  %struct.Mat* %a18,
+  %struct.Mat* %a19
+  )  {
+
+entry:
+  br label %entry.split
+
+entry.split:
+  %a1.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a1, i32 0, i32 0
+  %a1.data = load float*, float** %a1.data.ptr, align 8
+  %a1.rows.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a1, i32 0, i32 1
+  %a1.rows = load i64, i64* %a1.rows.ptr, align 8
+  %a1.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a1, i32 0, i32 2
+  %a1.cols = load i64, i64* %a1.cols.ptr, align 8
+  %a1.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a1, i32 0, i32 3
+  %a1.deps = load i64, i64* %a1.deps.ptr, align 8
+
+  %a2.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a2, i32 0, i32 0
+  %a2.data = load float*, float** %a2.data.ptr, align 8
+  %a2.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a2, i32 0, i32 2
+  %a2.cols = load i64, i64* %a2.cols.ptr, align 8
+  %a2.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a2, i32 0, i32 3
+  %a2.deps = load i64, i64* %a2.deps.ptr, align 8
+
+  %a3.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a3, i32 0, i32 0
+  %a3.data = load float*, float** %a3.data.ptr, align 8
+  %a3.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a3, i32 0, i32 2
+  %a3.cols = load i64, i64* %a3.cols.ptr, align 8
+  %a3.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a3, i32 0, i32 3
+  %a3.deps = load i64, i64* %a3.deps.ptr, align 8
+
+  %a4.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a4, i32 0, i32 0
+  %a4.data = load float*, float** %a4.data.ptr, align 8
+  %a4.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a4, i32 0, i32 2
+  %a4.cols = load i64, i64* %a4.cols.ptr, align 8
+  %a4.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a4, i32 0, i32 3
+  %a4.deps = load i64, i64* %a4.deps.ptr, align 8
+
+  %a5.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a5, i32 0, i32 0
+  %a5.data = load float*, float** %a5.data.ptr, align 8
+  %a5.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a5, i32 0, i32 2
+  %a5.cols = load i64, i64* %a5.cols.ptr, align 8
+  %a5.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a5, i32 0, i32 3
+  %a5.deps = load i64, i64* %a5.deps.ptr, align 8
+
+  %a6.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a6, i32 0, i32 0
+  %a6.data = load float*, float** %a6.data.ptr, align 8
+  %a6.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a6, i32 0, i32 2
+  %a6.cols = load i64, i64* %a6.cols.ptr, align 8
+  %a6.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a6, i32 0, i32 3
+  %a6.deps = load i64, i64* %a6.deps.ptr, align 8
+
+  %a7.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a7, i32 0, i32 0
+  %a7.data = load float*, float** %a7.data.ptr, align 8
+  %a7.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a7, i32 0, i32 2
+  %a7.cols = load i64, i64* %a7.cols.ptr, align 8
+  %a7.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a7, i32 0, i32 3
+  %a7.deps = load i64, i64* %a7.deps.ptr, align 8
+
+  %a8.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a8, i32 0, i32 0
+  %a8.data = load float*, float** %a8.data.ptr, align 8
+  %a8.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a8, i32 0, i32 2
+  %a8.cols = load i64, i64* %a8.cols.ptr, align 8
+  %a8.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a8, i32 0, i32 3
+  %a8.deps = load i64, i64* %a8.deps.ptr, align 8
+
+  %a9.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a9, i32 0, i32 0
+  %a9.data = load float*, float** %a9.data.ptr, align 8
+  %a9.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a9, i32 0, i32 2
+  %a9.cols = load i64, i64* %a9.cols.ptr, align 8
+  %a9.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a9, i32 0, i32 3
+  %a9.deps = load i64, i64* %a9.deps.ptr, align 8
+
+  %a10.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a10, i32 0, i32 0
+  %a10.data = load float*, float** %a10.data.ptr, align 8
+  %a10.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a10, i32 0, i32 2
+  %a10.cols = load i64, i64* %a10.cols.ptr, align 8
+  %a10.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a10, i32 0, i32 3
+  %a10.deps = load i64, i64* %a10.deps.ptr, align 8
+
+  %a11.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a11, i32 0, i32 0
+  %a11.data = load float*, float** %a11.data.ptr, align 8
+  %a11.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a11, i32 0, i32 2
+  %a11.cols = load i64, i64* %a11.cols.ptr, align 8
+  %a11.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a11, i32 0, i32 3
+  %a11.deps = load i64, i64* %a11.deps.ptr, align 8
+
+  %a12.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a12, i32 0, i32 0
+  %a12.data = load float*, float** %a12.data.ptr, align 8
+  %a12.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a12, i32 0, i32 2
+  %a12.cols = load i64, i64* %a12.cols.ptr, align 8
+  %a12.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a12, i32 0, i32 3
+  %a12.deps = load i64, i64* %a12.deps.ptr, align 8
+
+  %a13.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a13, i32 0, i32 0
+  %a13.data = load float*, float** %a13.data.ptr, align 8
+  %a13.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a13, i32 0, i32 2
+  %a13.cols = load i64, i64* %a13.cols.ptr, align 8
+  %a13.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a13, i32 0, i32 3
+  %a13.deps = load i64, i64* %a13.deps.ptr, align 8
+
+  %a14.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a14, i32 0, i32 0
+  %a14.data = load float*, float** %a14.data.ptr, align 8
+  %a14.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a14, i32 0, i32 2
+  %a14.cols = load i64, i64* %a14.cols.ptr, align 8
+  %a14.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a14, i32 0, i32 3
+  %a14.deps = load i64, i64* %a14.deps.ptr, align 8
+
+  %a15.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a15, i32 0, i32 0
+  %a15.data = load float*, float** %a15.data.ptr, align 8
+  %a15.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a15, i32 0, i32 2
+  %a15.cols = load i64, i64* %a15.cols.ptr, align 8
+  %a15.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a15, i32 0, i32 3
+  %a15.deps = load i64, i64* %a15.deps.ptr, align 8
+
+  %a16.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a16, i32 0, i32 0
+  %a16.data = load float*, float** %a16.data.ptr, align 8
+  %a16.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a16, i32 0, i32 2
+  %a16.cols = load i64, i64* %a16.cols.ptr, align 8
+  %a16.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a16, i32 0, i32 3
+  %a16.deps = load i64, i64* %a16.deps.ptr, align 8
+
+  %a17.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a17, i32 0, i32 0
+  %a17.data = load float*, float** %a17.data.ptr, align 8
+  %a17.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a17, i32 0, i32 2
+  %a17.cols = load i64, i64* %a17.cols.ptr, align 8
+  %a17.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a17, i32 0, i32 3
+  %a17.deps = load i64, i64* %a17.deps.ptr, align 8
+
+  %a18.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a18, i32 0, i32 0
+  %a18.data = load float*, float** %a18.data.ptr, align 8
+  %a18.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a18, i32 0, i32 2
+  %a18.cols = load i64, i64* %a18.cols.ptr, align 8
+  %a18.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a18, i32 0, i32 3
+  %a18.deps = load i64, i64* %a18.deps.ptr, align 8
+
+  %a19.data.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a19, i32 0, i32 0
+  %a19.data = load float*, float** %a19.data.ptr, align 8
+  %a19.cols.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a19, i32 0, i32 2
+  %a19.cols = load i64, i64* %a19.cols.ptr, align 8
+  %a19.deps.ptr = getelementptr inbounds %struct.Mat, %struct.Mat* %a19, i32 0, i32 3
+  %a19.deps = load i64, i64* %a19.deps.ptr, align 8
+  br label %for.n
+
+for.n:
+  %indvar.n = phi i64 [ 0, %entry.split ], [ %indvar.n.next, %for.inc.n ]
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ 0, %for.n ], [ %indvar.i.next, %for.inc.i ]
+  br label %for.j
+
+for.j:
+  %indvar.j = phi i64 [ 0, %for.i ], [ %indvar.j.next, %for.inc.j ]
+  br label %for.body.k
+
+for.body.k:
+  %indvar.k = phi i64 [ 0, %for.j ], [ %indvar.k.next, %for.body.k ]
+  %a1.tmp1 = add i64 %a1.cols, 1
+  %a1.tmp2 = mul i64 %a1.deps, %a1.tmp1
+  %a1.tmp3 = add i64 %a1.tmp2, 1
+  %a1.tmp4 = mul i64 %a1.cols, %a1.deps
+  %a1.idx.i = mul i64 %a1.tmp4, %indvar.i
+  %a1.tmp5 = add i64 %a1.tmp3, %a1.idx.i
+  %a1.idx.j = mul i64 %a1.deps, %indvar.j
+  %a1.tmp6 = add i64 %a1.tmp5, %a1.idx.j
+  %a1.idx.k = add i64 %a1.tmp6, %indvar.k
+  %a1.ptr = getelementptr float, float* %a1.data, i64 %a1.idx.k
+  %sum = load float, float* %a1.ptr, align 4
+
+  %a2.tmp1 = add i64 %a2.cols, 1
+  %a2.tmp2 = mul i64 %a2.deps, %a2.tmp1
+  %a2.tmp3 = add i64 %a2.tmp2, 1
+  %a2.tmp4 = mul i64 %a2.cols, %a2.deps
+  %a2.idx.i = mul i64 %a2.tmp4, %indvar.i
+  %a2.tmp5 = add i64 %a2.tmp3, %a2.idx.i
+  %a2.idx.j = mul i64 %a2.deps, %indvar.j
+  %a2.tmp6 = add i64 %a2.tmp5, %a2.idx.j
+  %a2.idx.k = add i64 %a2.tmp6, %indvar.k
+  %a2.ptr = getelementptr float, float* %a2.data, i64 %a2.idx.k
+  %a2.val = load float, float* %a2.ptr, align 4
+  %sum.a2 = fadd float %sum, %a2.val
+
+  %a3.tmp1 = add i64 %a3.cols, 1
+  %a3.tmp2 = mul i64 %a3.deps, %a3.tmp1
+  %a3.tmp3 = add i64 %a3.tmp2, 1
+  %a3.tmp4 = mul i64 %a3.cols, %a3.deps
+  %a3.idx.i = mul i64 %a3.tmp4, %indvar.i
+  %a3.tmp5 = add i64 %a3.tmp3, %a3.idx.i
+  %a3.idx.j = mul i64 %a3.deps, %indvar.j
+  %a3.tmp6 = add i64 %a3.tmp5, %a3.idx.j
+  %a3.idx.k = add i64 %a3.tmp6, %indvar.k
+  %a3.ptr = getelementptr float, float* %a3.data, i64 %a3.idx.k
+  %a3.val = load float, float* %a3.ptr, align 4
+  %sum.a3 = fadd float %sum.a2, %a3.val
+
+  %a4.tmp1 = add i64 %a4.cols, 1
+  %a4.tmp2 = mul i64 %a4.deps, %a4.tmp1
+  %a4.tmp3 = add i64 %a4.tmp2, 1
+  %a4.tmp4 = mul i64 %a4.cols, %a4.deps
+  %a4.idx.i = mul i64 %a4.tmp4, %indvar.i
+  %a4.tmp5 = add i64 %a4.tmp3, %a4.idx.i
+  %a4.idx.j = mul i64 %a4.deps, %indvar.j
+  %a4.tmp6 = add i64 %a4.tmp5, %a4.idx.j
+  %a4.idx.k = add i64 %a4.tmp6, %indvar.k
+  %a4.ptr = getelementptr float, float* %a4.data, i64 %a4.idx.k
+  %a4.val = load float, float* %a4.ptr, align 4
+  %sum.a4 = fadd float %sum.a3, %a4.val
+
+  %a5.tmp1 = add i64 %a5.cols, 1
+  %a5.tmp2 = mul i64 %a5.deps, %a5.tmp1
+  %a5.tmp3 = add i64 %a5.tmp2, 1
+  %a5.tmp4 = mul i64 %a5.cols, %a5.deps
+  %a5.idx.i = mul i64 %a5.tmp4, %indvar.i
+  %a5.tmp5 = add i64 %a5.tmp3, %a5.idx.i
+  %a5.idx.j = mul i64 %a5.deps, %indvar.j
+  %a5.tmp6 = add i64 %a5.tmp5, %a5.idx.j
+  %a5.idx.k = add i64 %a5.tmp6, %indvar.k
+  %a5.ptr = getelementptr float, float* %a5.data, i64 %a5.idx.k
+  %a5.val = load float, float* %a5.ptr, align 4
+  %sum.a5 = fadd float %sum.a4, %a5.val
+
+  %a6.tmp1 = add i64 %a6.cols, 1
+  %a6.tmp2 = mul i64 %a6.deps, %a6.tmp1
+  %a6.tmp3 = add i64 %a6.tmp2, 1
+  %a6.tmp4 = mul i64 %a6.cols, %a6.deps
+  %a6.idx.i = mul i64 %a6.tmp4, %indvar.i
+  %a6.tmp5 = add i64 %a6.tmp3, %a6.idx.i
+  %a6.idx.j = mul i64 %a6.deps, %indvar.j
+  %a6.tmp6 = add i64 %a6.tmp5, %a6.idx.j
+  %a6.idx.k = add i64 %a6.tmp6, %indvar.k
+  %a6.ptr = getelementptr float, float* %a6.data, i64 %a6.idx.k
+  %a6.val = load float, float* %a6.ptr, align 4
+  %sum.a6 = fadd float %sum.a5, %a6.val
+
+  %a7.tmp1 = add i64 %a7.cols, 1
+  %a7.tmp2 = mul i64 %a7.deps, %a7.tmp1
+  %a7.tmp3 = add i64 %a7.tmp2, 1
+  %a7.tmp4 = mul i64 %a7.cols, %a7.deps
+  %a7.idx.i = mul i64 %a7.tmp4, %indvar.i
+  %a7.tmp5 = add i64 %a7.tmp3, %a7.idx.i
+  %a7.idx.j = mul i64 %a7.deps, %indvar.j
+  %a7.tmp6 = add i64 %a7.tmp5, %a7.idx.j
+  %a7.idx.k = add i64 %a7.tmp6, %indvar.k
+  %a7.ptr = getelementptr float, float* %a7.data, i64 %a7.idx.k
+  %a7.val = load float, float* %a7.ptr, align 4
+  %sum.a7 = fadd float %sum.a6, %a7.val
+
+  %a8.tmp1 = add i64 %a8.cols, 1
+  %a8.tmp2 = mul i64 %a8.deps, %a8.tmp1
+  %a8.tmp3 = add i64 %a8.tmp2, 1
+  %a8.tmp4 = mul i64 %a8.cols, %a8.deps
+  %a8.idx.i = mul i64 %a8.tmp4, %indvar.i
+  %a8.tmp5 = add i64 %a8.tmp3, %a8.idx.i
+  %a8.idx.j = mul i64 %a8.deps, %indvar.j
+  %a8.tmp6 = add i64 %a8.tmp5, %a8.idx.j
+  %a8.idx.k = add i64 %a8.tmp6, %indvar.k
+  %a8.ptr = getelementptr float, float* %a8.data, i64 %a8.idx.k
+  %a8.val = load float, float* %a8.ptr, align 4
+  %sum.a8 = fadd float %sum.a7, %a8.val
+
+  %a9.tmp1 = add i64 %a9.cols, 1
+  %a9.tmp2 = mul i64 %a9.deps, %a9.tmp1
+  %a9.tmp3 = add i64 %a9.tmp2, 1
+  %a9.tmp4 = mul i64 %a9.cols, %a9.deps
+  %a9.idx.i = mul i64 %a9.tmp4, %indvar.i
+  %a9.tmp5 = add i64 %a9.tmp3, %a9.idx.i
+  %a9.idx.j = mul i64 %a9.deps, %indvar.j
+  %a9.tmp6  = add i64 %a9.tmp5, %a9.idx.j
+  %a9.idx.k = add i64 %a9.tmp6, %indvar.k
+  %a9.ptr = getelementptr float, float* %a9.data, i64 %a9.idx.k
+  %a9.val = load float, float* %a9.ptr, align 4
+  %sum.a9 = fadd float %sum.a8, %a9.val
+
+  %a10.tmp1 = add i64 %a10.cols, 1
+  %a10.tmp2 = mul i64 %a10.deps, %a10.tmp1
+  %a10.tmp3 = add i64 %a10.tmp2, 1
+  %a10.tmp4 = mul i64 %a10.cols, %a10.deps
+  %a10.idx.i = mul i64 %a10.tmp4, %indvar.i
+  %a10.tmp5 = add i64 %a10.tmp3, %a10.idx.i
+  %a10.idx.j = mul i64 %a10.deps, %indvar.j
+  %a10.tmp6 = add i64 %a10.tmp5, %a10.idx.j
+  %a10.idx.k = add i64 %a10.tmp6, %indvar.k
+  %a10.ptr = getelementptr float, float* %a10.data, i64 %a10.idx.k
+  %a10.val = load float, float* %a10.ptr, align 4
+  %sum.a10 = fadd float %sum.a9, %a10.val
+
+  %a11.tmp1 = add i64 %a11.cols, 1
+  %a11.tmp2 = mul i64 %a11.deps, %a11.tmp1
+  %a11.tmp3 = add i64 %a11.tmp2, 1
+  %a11.tmp4 = mul i64 %a11.cols, %a11.deps
+  %a11.idx.i = mul i64 %a11.tmp4, %indvar.i
+  %a11.tmp5 = add i64 %a11.tmp3, %a11.idx.i
+  %a11.idx.j = mul i64 %a11.deps, %indvar.j
+  %a11.tmp6 = add i64 %a11.tmp5, %a11.idx.j
+  %a11.idx.k = add i64 %a11.tmp6, %indvar.k
+  %a11.ptr = getelementptr float, float* %a11.data, i64 %a11.idx.k
+  %a11.val = load float, float* %a11.ptr, align 4
+  %sum.a11 = fadd float %sum.a10, %a11.val
+
+  %a12.tmp1 = add i64 %a12.cols, 1
+  %a12.tmp2 = mul i64 %a12.deps, %a12.tmp1
+  %a12.tmp3 = add i64 %a12.tmp2, 1
+  %a12.tmp4 = mul i64 %a12.cols, %a12.deps
+  %a12.idx.i = mul i64 %a12.tmp4, %indvar.i
+  %a12.tmp5 = add i64 %a12.tmp3, %a12.idx.i
+  %a12.idx.j = mul i64 %a12.deps, %indvar.j
+  %a12.tmp6 = add i64 %a12.tmp5, %a12.idx.j
+  %a12.idx.k = add i64 %a12.tmp6, %indvar.k
+  %a12.ptr = getelementptr float, float* %a12.data, i64 %a12.idx.k
+  %a12.val = load float, float* %a12.ptr, align 4
+  %sum.a12 = fadd float %sum.a11, %a12.val
+
+  %a13.tmp1 = add i64 %a13.cols, 1
+  %a13.tmp2 = mul i64 %a13.deps, %a13.tmp1
+  %a13.tmp3 = add i64 %a13.tmp2, 1
+  %a13.tmp4 = mul i64 %a13.cols, %a13.deps
+  %a13.idx.i = mul i64 %a13.tmp4, %indvar.i
+  %a13.tmp5 = add i64 %a13.tmp3, %a13.idx.i
+  %a13.idx.j = mul i64 %a13.deps, %indvar.j
+  %a13.tmp6 = add i64 %a13.tmp5, %a13.idx.j
+  %a13.idx.k = add i64 %a13.tmp6, %indvar.k
+  %a13.ptr = getelementptr float, float* %a13.data, i64 %a13.idx.k
+  %a13.val = load float, float* %a13.ptr, align 4
+  %sum.a13 = fadd float %sum.a12, %a13.val
+
+  %a14.tmp1 = add i64 %a14.cols, 1
+  %a14.tmp2 = mul i64 %a14.deps, %a14.tmp1
+  %a14.tmp3 = add i64 %a14.tmp2, 1
+  %a14.tmp4 = mul i64 %a14.cols, %a14.deps
+  %a14.idx.i = mul i64 %a14.tmp4, %indvar.i
+  %a14.tmp5 = add i64 %a14.tmp3, %a14.idx.i
+  %a14.idx.j = mul i64 %a14.deps, %indvar.j
+  %a14.tmp6 = add i64 %a14.tmp5, %a14.idx.j
+  %a14.idx.k = add i64 %a14.tmp6, %indvar.k
+  %a14.ptr = getelementptr float, float* %a14.data, i64 %a14.idx.k
+  %a14.val = load float, float* %a14.ptr, align 4
+  %sum.a14 = fadd float %sum.a13, %a14.val
+
+  %a15.tmp1 = add i64 %a15.cols, 1
+  %a15.tmp2 = mul i64 %a15.deps, %a15.tmp1
+  %a15.tmp3 = add i64 %a15.tmp2, 1
+  %a15.tmp4 = mul i64 %a15.cols, %a15.deps
+  %a15.idx.i = mul i64 %a15.tmp4, %indvar.i
+  %a15.tmp5 = add i64 %a15.tmp3, %a15.idx.i
+  %a15.idx.j = mul i64 %a15.deps, %indvar.j
+  %a15.tmp6 = add i64 %a15.tmp5, %a15.idx.j
+  %a15.idx.k = add i64 %a15.tmp6, %indvar.k
+  %a15.ptr = getelementptr float, float* %a15.data, i64 %a15.idx.k
+  %a15.val = load float, float* %a15.ptr, align 4
+  %sum.a15 = fadd float %sum.a14, %a15.val
+
+  %a16.tmp1 = add i64 %a16.cols, 1
+  %a16.tmp2 = mul i64 %a16.deps, %a16.tmp1
+  %a16.tmp3 = add i64 %a16.tmp2, 1
+  %a16.tmp4 = mul i64 %a16.cols, %a16.deps
+  %a16.idx.i = mul i64 %a16.tmp4, %indvar.i
+  %a16.tmp5 = add i64 %a16.tmp3, %a16.idx.i
+  %a16.idx.j = mul i64 %a16.deps, %indvar.j
+  %a16.tmp6 = add i64 %a16.tmp5, %a16.idx.j
+  %a16.idx.k = add i64 %a16.tmp6, %indvar.k
+  %a16.ptr = getelementptr float, float* %a16.data, i64 %a16.idx.k
+  %a16.val = load float, float* %a16.ptr, align 4
+  %sum.a16 = fadd float %sum.a15, %a16.val
+
+  %a17.tmp1 = add i64 %a17.cols, 1
+  %a17.tmp2 = mul i64 %a17.deps, %a17.tmp1
+  %a17.tmp3 = add i64 %a17.tmp2, 1
+  %a17.tmp4 = mul i64 %a17.cols, %a17.deps
+  %a17.idx.i = mul i64 %a17.tmp4, %indvar.i
+  %a17.tmp5 = add i64 %a17.tmp3, %a17.idx.i
+  %a17.idx.j = mul i64 %a17.deps, %indvar.j
+  %a17.tmp6 = add i64 %a17.tmp5, %a17.idx.j
+  %a17.idx.k = add i64 %a17.tmp6, %indvar.k
+  %a17.ptr = getelementptr float, float* %a17.data, i64 %a17.idx.k
+  %a17.val = load float, float* %a17.ptr, align 4
+  %sum.a17 = fadd float %sum.a16, %a17.val
+
+  %a18.tmp1 = add i64 %a18.cols, 1
+  %a18.tmp2 = mul i64 %a18.deps, %a18.tmp1
+  %a18.tmp3 = add i64 %a18.tmp2, 1
+  %a18.tmp4 = mul i64 %a18.cols, %a18.deps
+  %a18.idx.i = mul i64 %a18.tmp4, %indvar.i
+  %a18.tmp5 = add i64 %a18.tmp3, %a18.idx.i
+  %a18.idx.j = mul i64 %a18.deps, %indvar.j
+  %a18.tmp6 = add i64 %a18.tmp5, %a18.idx.j
+  %a18.idx.k = add i64 %a18.tmp6, %indvar.k
+  %a18.ptr = getelementptr float, float* %a18.data, i64 %a18.idx.k
+  %a18.val = load float, float* %a18.ptr, align 4
+  %sum.a18 = fadd float %sum.a17, %a18.val
+
+  %a19.tmp1 = add i64 %a19.cols, 1
+  %a19.tmp2 = mul i64 %a19.deps, %a19.tmp1
+  %a19.tmp3 = add i64 %a19.tmp2, 1
+  %a19.tmp4 = mul i64 %a19.cols, %a19.deps
+  %a19.idx.i = mul i64 %a19.tmp4, %indvar.i
+  %a19.tmp5 = add i64 %a19.tmp3, %a19.idx.i
+  %a19.idx.j = mul i64 %a19.deps, %indvar.j
+  %a19.tmp6  = add i64 %a19.tmp5, %a19.idx.j
+  %a19.idx.k = add i64 %a19.tmp6, %indvar.k
+  %a19.ptr = getelementptr float, float* %a19.data, i64 %a19.idx.k
+  store float %sum.a18, float* %a19.ptr, align 4
+
+  %indvar.k.next = add i64 %indvar.k, 1
+  %a1.deps.sub = add i64 %a1.deps, -2
+  %exitcond = icmp ne i64 %indvar.k.next, %a1.deps.sub
+  br i1 %exitcond, label %for.body.k, label %for.inc.j
+
+for.inc.j:
+  %indvar.j.next = add i64 %indvar.j, 1
+  %a1.cols.sub = add i64 %a1.cols, -2
+  %exitcond.j = icmp ne i64 %indvar.j.next, %a1.cols.sub
+  br i1 %exitcond.j, label %for.j, label %for.inc.i
+
+for.inc.i:
+  %indvar.i.next = add i64 %indvar.i, 1
+  %a1.rows.sub = add i64 %a1.rows, -2
+  %exitcond.i = icmp ne i64 %indvar.i.next, %a1.rows.sub
+  br i1 %exitcond.i, label %for.i, label %for.inc.n
+
+for.inc.n:
+  %indvar.n.next = add nsw i64 %indvar.n, 1
+  %exitcond.n = icmp ne i64 %indvar.n.next, %nn
+  br i1 %exitcond.n, label %for.n, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_nested_start_integer.ll b/final/test/ScopInfo/multidim_nested_start_integer.ll
new file mode 100644
index 0000000..a2cebd6
--- /dev/null
+++ b/final/test/ScopInfo/multidim_nested_start_integer.ll
@@ -0,0 +1,74 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-function-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; void foo(long n, long m, long o, double A[n][m][o]) {
+;   for (long i = 0; i < n - 3; i++)
+;     for (long j = 4; j < m; j++)
+;       for (long k = 0; k < o - 7; k++)
+;         A[i+3][j-4][k+7] = 1.0;
+; }
+;
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [o, m, n] -> {  :  }
+;
+; CHECK:      p0: %o
+; CHECK-NEXT: p1: %m
+; CHECK-NEXT: p2: %n
+; CHECK-NOT:  p3
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_k
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [o, m, n] -> { Stmt_for_k[i0, i1, i2] : 0 <= i0 <= -4 + n and 0 <= i1 <= -5 + m and 0 <= i2 <= -8 + o };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [o, m, n] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [o, m, n] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[3 + i0, i1, 7 + i2] };
+; CHECK-NEXT: }
+
+define void @foo(i64 %n, i64 %m, i64 %o, double* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 4, %for.i ], [ %j.inc, %for.j.inc ]
+  br label %for.k
+
+for.k:
+  %k = phi i64 [ 0, %for.j ], [ %k.inc, %for.k.inc ]
+  %offset0 = add nsw i64 %i, 3
+  %subscript0 = mul i64 %offset0, %m
+  %offset1 = add nsw i64 %j, -4
+  %subscript1 = add i64 %offset1, %subscript0
+  %subscript2 = mul i64 %subscript1, %o
+  %offset2 = add nsw i64 %k, 7
+  %subscript = add i64 %subscript2, %offset2
+  %idx = getelementptr inbounds double, double* %A, i64 %subscript
+  store double 1.0, double* %idx
+  br label %for.k.inc
+
+for.k.inc:
+  %k.inc = add nsw i64 %k, 1
+  %osub = sub nsw i64 %o, 7
+  %k.exitcond = icmp eq i64 %k.inc, %osub
+  br i1 %k.exitcond, label %for.j.inc, label %for.k
+
+for.j.inc:
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, %m
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %nsub = sub nsw i64 %n, 3
+  %i.exitcond = icmp eq i64 %i.inc, %nsub
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_nested_start_share_parameter.ll b/final/test/ScopInfo/multidim_nested_start_share_parameter.ll
new file mode 100644
index 0000000..6450f94
--- /dev/null
+++ b/final/test/ScopInfo/multidim_nested_start_share_parameter.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; void foo(long n, long m, long o, double A[n][m][o]) {
+;
+;   for (long i = 0; i < n-13; i++)
+;     for (long j = 14; j < m; j++)
+;       for (long k = 0; k < o-17; k++) {
+;         A[i+3][j-4][k+7] = 1.0;
+;         A[i+13][j-14][k+17] = 11.0;
+;       }
+; }
+;
+; CHECK: Assumed Context:
+; CHECK:   {  :  }
+; CHECK: p0: %o
+; CHECK: p1: %m
+; CHECK: p2: %n
+; CHECK-NOT: p3
+;
+; CHECK:   [o, m, n] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[3 + i0, 10 + i1, 7 + i2] };
+; CHECK:   [o, m, n] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[13 + i0, i1, 17 + i2] };
+
+define void @foo(i64 %n, i64 %m, i64 %o, double* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 14, %for.i ], [ %j.inc, %for.j.inc ]
+  br label %for.k
+
+for.k:
+  %k = phi i64 [ 0, %for.j ], [ %k.inc, %for.k.inc ]
+
+  %offset0 = add nsw i64 %i, 3
+  %subscript0 = mul i64 %offset0, %m
+  %offset1 = add nsw i64 %j, -4
+  %subscript1 = add i64 %offset1, %subscript0
+  %subscript2 = mul i64 %subscript1, %o
+  %offset2 = add nsw i64 %k, 7
+  %subscript3 = add i64 %subscript2, %offset2
+  %idx = getelementptr inbounds double, double* %A, i64 %subscript3
+  store double 1.0, double* %idx
+
+  %offset3 = add nsw i64 %i, 13
+  %subscript4 = mul i64 %offset3, %m
+  %offset4 = add nsw i64 %j, -14
+  %subscript5 = add i64 %offset4, %subscript4
+  %subscript6 = mul i64 %subscript5, %o
+  %offset5 = add nsw i64 %k, 17
+  %subscript7 = add i64 %subscript6, %offset5
+  %idx1 = getelementptr inbounds double, double* %A, i64 %subscript7
+  store double 11.0, double* %idx1
+
+  br label %for.k.inc
+
+for.k.inc:
+  %k.inc = add nsw i64 %k, 1
+  %osub = sub nsw i64 %o, 17
+  %k.exitcond = icmp eq i64 %k.inc, %osub
+  br i1 %k.exitcond, label %for.j.inc, label %for.k
+
+for.j.inc:
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, %m
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %nsub = sub nsw i64 %n, 13
+  %i.exitcond = icmp eq i64 %i.inc, %nsub
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_only_ivs_2d.ll b/final/test/ScopInfo/multidim_only_ivs_2d.ll
new file mode 100644
index 0000000..375aba4
--- /dev/null
+++ b/final/test/ScopInfo/multidim_only_ivs_2d.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; Derived from the following code:
+;
+; void foo(long n, long m, double A[n][m]) {
+;   for (long i = 0; i < n; i++)
+;     for (long j = 0; j < m; j++)
+;       A[i][j] = 1.0;
+; }
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [m, n] -> {  :  }
+;
+; CHECK:      p0: %m
+; CHECK-NEXT: p1: %n
+; CHECK-NOT: p3
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_j
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [m, n] -> { Stmt_for_j[i0, i1] : 0 <= i0 < n and 0 <= i1 < m };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [m, n] -> { Stmt_for_j[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [m, n] -> { Stmt_for_j[i0, i1] -> MemRef_A[i0, i1] };
+; CHECK-NEXT: }
+
+define void @foo(i64 %n, i64 %m, double* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+  %tmp = mul nsw i64 %i, %m
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j ]
+  %vlaarrayidx.sum = add i64 %j, %tmp
+  %arrayidx = getelementptr inbounds double, double* %A, i64 %vlaarrayidx.sum
+  store double 1.0, double* %arrayidx
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, %m
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %i.exitcond = icmp eq i64 %i.inc, %n
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_only_ivs_3d.ll b/final/test/ScopInfo/multidim_only_ivs_3d.ll
new file mode 100644
index 0000000..25143aa
--- /dev/null
+++ b/final/test/ScopInfo/multidim_only_ivs_3d.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; void foo(long n, long m, long o, double A[n][m][o]) {
+;
+;   for (long i = 0; i < n; i++)
+;     for (long j = 0; j < m; j++)
+;       for (long k = 0; k < o; k++)
+;         A[i][j][k] = 1.0;
+; }
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [o, m, n] -> {  :  }
+;
+; CHECK:      p0: %o
+; CHECK-NEXT: p1: %m
+; CHECK-NEXT: p2: %n
+; CHECK-NOT:  p3
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_k
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [o, m, n] -> { Stmt_for_k[i0, i1, i2] : 0 <= i0 < n and 0 <= i1 < m and 0 <= i2 < o };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [o, m, n] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [o, m, n] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[i0, i1, i2] };
+; CHECK-NEXT: }
+
+define void @foo(i64 %n, i64 %m, i64 %o, double* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j.inc ]
+  br label %for.k
+
+for.k:
+  %k = phi i64 [ 0, %for.j ], [ %k.inc, %for.k.inc ]
+  %subscript0 = mul i64 %i, %m
+  %subscript1 = add i64 %j, %subscript0
+  %subscript2 = mul i64 %subscript1, %o
+  %subscript = add i64 %subscript2, %k
+  %idx = getelementptr inbounds double, double* %A, i64 %subscript
+  store double 1.0, double* %idx
+  br label %for.k.inc
+
+for.k.inc:
+  %k.inc = add nsw i64 %k, 1
+  %k.exitcond = icmp eq i64 %k.inc, %o
+  br i1 %k.exitcond, label %for.j.inc, label %for.k
+
+for.j.inc:
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, %m
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %i.exitcond = icmp eq i64 %i.inc, %n
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_only_ivs_3d_cast.ll b/final/test/ScopInfo/multidim_only_ivs_3d_cast.ll
new file mode 100644
index 0000000..fbe722e
--- /dev/null
+++ b/final/test/ScopInfo/multidim_only_ivs_3d_cast.ll
@@ -0,0 +1,89 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; void foo(int n, int m, int o, double A[n][m][o]) {
+;
+;   for (int i = 0; i < n; i++)
+;     for (int j = 0; j < m; j++)
+;       for (int k = 0; k < o; k++)
+;         A[i][j][k] = 1.0;
+; }
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [o, m, n] -> {  :  }
+; CHECK-NEXT: Invalid Context:
+; CHECK-NEXT: [o, m, n] -> { : o < 0 or m < 0 or (o >= 0 and m >= 0 and n <= 0) or (m = 0 and o >= 0 and n > 0) or (o = 0 and m > 0 and n > 0) }
+
+;
+; CHECK:      p0: %o
+; CHECK-NEXT: p1: %m
+; CHECK-NEXT: p2: %n
+; CHECK-NOT:  p3
+;
+; CHECK:      Arrays {
+; CHECK-NEXT:     double MemRef_A[*][(zext i32 %m to i64)][(zext i32 %o to i64)]; // Element size 8
+; CHECK-NEXT: }
+;
+; CHECK:      Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:     double MemRef_A[*][ [m] -> { [] -> [(m)] } ][ [o] -> { [] -> [(o)] } ]; // Element size 8
+; CHECK-NEXT: }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_k
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [o, m, n] -> { Stmt_for_k[i0, i1, i2] : 0 <= i0 < n and 0 <= i1 < m and 0 <= i2 < o };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [o, m, n] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [o, m, n] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[i0, i1, i2] };
+; CHECK-NEXT: }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+define void @foo(i32 %n, i32 %m, i32 %o, double* %A) {
+entry:
+  %m_zext = zext i32 %m to i64
+  %n_zext = zext i32 %o to i64
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ %i.inc, %for.i.inc ], [ 0, %entry ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ %j.inc, %for.j.inc ], [ 0, %for.i ]
+  br label %for.k
+
+for.k:
+  %k = phi i64 [ %k.inc, %for.k.inc ], [ 0, %for.j ]
+  %tmp = mul i64 %i, %m_zext
+  %tmp1 = trunc i64 %j to i32
+  %tmp2 = trunc i64 %i to i32
+  %mul.us.us = mul nsw i32 %tmp1, %tmp2
+  %tmp.us.us = add i64 %j, %tmp
+  %tmp17.us.us = mul i64 %tmp.us.us, %n_zext
+  %subscript = add i64 %tmp17.us.us, %k
+  %idx = getelementptr inbounds double, double* %A, i64 %subscript
+  store double 1.0, double* %idx
+  br label %for.k.inc
+
+for.k.inc:
+  %k.inc = add i64 %k, 1
+  %k.inc.trunc = trunc i64 %k.inc to i32
+  %k.exitcond = icmp eq i32 %k.inc.trunc, %o
+  br i1 %k.exitcond, label %for.j.inc, label %for.k
+
+for.j.inc:
+  %j.inc = add i64 %j, 1
+  %j.inc.trunc = trunc i64 %j.inc to i32
+  %j.exitcond = icmp eq i32 %j.inc.trunc, %m
+  br i1 %j.exitcond, label %for.i.inc, label %for.j
+
+for.i.inc:
+  %i.inc = add i64 %i, 1
+  %i.inc.trunc = trunc i64 %i.inc to i32
+  %i.exitcond = icmp eq i32 %i.inc.trunc, %n
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_only_ivs_3d_reverse.ll b/final/test/ScopInfo/multidim_only_ivs_3d_reverse.ll
new file mode 100644
index 0000000..a0400ae
--- /dev/null
+++ b/final/test/ScopInfo/multidim_only_ivs_3d_reverse.ll
@@ -0,0 +1,74 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; This test case checks for array access functions where the order in which the
+; loop ivs appear in the array subscript does not follow the order of the
+; the loops in which they are defined. This (very common) case caused problems
+; in the delinearization pass.
+;
+; void foo(long n, long m, long o, double A[n][m][o]) {
+;
+;   for (long i = 0; i < n; i++)
+;     for (long k = 0; k < o; k++)
+;       for (long j = 0; j < m; j++)
+;         A[i][j][k] = 1.0;
+; }
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [m, o, n] -> {  :  }
+;
+; CHECK:      p0: %m
+; CHECK-NEXT: p1: %o
+; CHECK-NEXT: p2: %n
+; CHECK-NOT:  p3
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_j
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [m, o, n] -> { Stmt_for_j[i0, i1, i2] : 0 <= i0 < n and 0 <= i1 < o and 0 <= i2 < m };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [m, o, n] -> { Stmt_for_j[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [m, o, n] -> { Stmt_for_j[i0, i1, i2] -> MemRef_A[i0, i2, i1] };
+; CHECK-NEXT: }
+
+define void @foo(i64 %n, i64 %m, i64 %o, double* %A) {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
+  br label %for.k
+
+for.k:
+  %k = phi i64 [ 0, %for.i ], [ %k.inc, %for.k.inc ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.k ], [ %j.inc, %for.j.inc ]
+  %subscript0 = mul i64 %i, %m
+  %subscript1 = add i64 %j, %subscript0
+  %subscript2 = mul i64 %subscript1, %o
+  %subscript = add i64 %subscript2, %k
+  %idx = getelementptr inbounds double, double* %A, i64 %subscript
+  store double 1.0, double* %idx
+  br label %for.j.inc
+
+for.j.inc:
+  %j.inc = add nsw i64 %j, 1
+  %j.exitcond = icmp eq i64 %j.inc, %m
+  br i1 %j.exitcond, label %for.k.inc, label %for.j
+
+for.k.inc:
+  %k.inc = add nsw i64 %k, 1
+  %k.exitcond = icmp eq i64 %k.inc, %o
+  br i1 %k.exitcond, label %for.i.inc, label %for.k
+
+for.i.inc:
+  %i.inc = add nsw i64 %i, 1
+  %i.exitcond = icmp eq i64 %i.inc, %n
+  br i1 %i.exitcond, label %end, label %for.i
+
+end:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_param_in_subscript-2.ll b/final/test/ScopInfo/multidim_param_in_subscript-2.ll
new file mode 100644
index 0000000..b6c43e9
--- /dev/null
+++ b/final/test/ScopInfo/multidim_param_in_subscript-2.ll
@@ -0,0 +1,89 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN:  -polly-precise-fold-accesses  < %s | FileCheck %s
+;
+;    void foo(long n, long m, float A[][n][m]) {
+;      for (long i = 0; i < 100; i++)
+;        for (long j = 0; j < n; j++)
+;          for (long k = 0; k < m; k++)
+;            A[i][j][k] += A[i][n - j - 1][m - k - 1];
+;    }
+;
+; Verify that the parameter in the subscript expression is correctly
+; recovered.
+;
+; CHECK: Assumed Context:
+; CHECK-NEXT: [n, m] -> {  :  }
+; CHECK: ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT: [n, m] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, -1 + n - i1, -1 + m - i2] };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %n, i64 %m, float* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc18, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc19, %for.inc18 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %for.body, label %for.end20
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc15, %for.body
+  %j.0 = phi i64 [ 0, %for.body ], [ %inc16, %for.inc15 ]
+  %cmp2 = icmp slt i64 %j.0, %n
+  br i1 %cmp2, label %for.body3, label %for.end17
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.cond4
+
+for.cond4:                                        ; preds = %for.inc, %for.body3
+  %k.0 = phi i64 [ 0, %for.body3 ], [ %inc, %for.inc ]
+  %cmp5 = icmp slt i64 %k.0, %m
+  br i1 %cmp5, label %for.body6, label %for.end
+
+for.body6:                                        ; preds = %for.cond4
+  %sub = sub nsw i64 %m, %k.0
+  %sub7 = add nsw i64 %sub, -1
+  %sub8 = sub nsw i64 %n, %j.0
+  %sub9 = add nsw i64 %sub8, -1
+  %tmp = mul nuw i64 %n, %m
+  %tmp1 = mul nsw i64 %i.0, %tmp
+  %tmp2 = mul nsw i64 %sub9, %m
+  %arrayidx.sum = add i64 %tmp1, %tmp2
+  %arrayidx10.sum = add i64 %arrayidx.sum, %sub7
+  %arrayidx11 = getelementptr inbounds float, float* %A, i64 %arrayidx10.sum
+  %tmp3 = load float, float* %arrayidx11, align 4
+  %tmp4 = mul nuw i64 %n, %m
+  %tmp5 = mul nsw i64 %i.0, %tmp4
+  %tmp6 = mul nsw i64 %j.0, %m
+  %arrayidx12.sum = add i64 %tmp5, %tmp6
+  %arrayidx13.sum = add i64 %arrayidx12.sum, %k.0
+  %arrayidx14 = getelementptr inbounds float, float* %A, i64 %arrayidx13.sum
+  %tmp7 = load float, float* %arrayidx14, align 4
+  %add = fadd float %tmp7, %tmp3
+  store float %add, float* %arrayidx14, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body6
+  %inc = add nuw nsw i64 %k.0, 1
+  br label %for.cond4
+
+for.end:                                          ; preds = %for.cond4
+  br label %for.inc15
+
+for.inc15:                                        ; preds = %for.end
+  %inc16 = add nuw nsw i64 %j.0, 1
+  br label %for.cond1
+
+for.end17:                                        ; preds = %for.cond1
+  br label %for.inc18
+
+for.inc18:                                        ; preds = %for.end17
+  %inc19 = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end20:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_param_in_subscript.ll b/final/test/ScopInfo/multidim_param_in_subscript.ll
new file mode 100644
index 0000000..dfa9250
--- /dev/null
+++ b/final/test/ScopInfo/multidim_param_in_subscript.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;
+;    void foo(long n, float A[][n]) {
+;      for (long i = 0; i < 100; i++)
+;        for (long j = 0; j < n; j++)
+;          A[i][j] += A[i][n - j - 1];
+;    }
+;
+; Verify that the parameter in the subscript expression is correctly
+; recovered.
+;
+; CHECK: Assumed Context:
+; CHECK-NEXT: [n] -> {  :  }
+;
+; CHECK: ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:   [n] -> { Stmt_for_body3[i0, i1] -> MemRef_A[i0, -1 + n - i1] };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %n, float* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc8, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc9, %for.inc8 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %for.body, label %for.end10
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i64 [ 0, %for.body ], [ %inc, %for.inc ]
+  %cmp2 = icmp slt i64 %j.0, %n
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %sub = sub nsw i64 %n, %j.0
+  %sub4 = add nsw i64 %sub, -1
+  %tmp = mul nsw i64 %i.0, %n
+  %arrayidx.sum = add i64 %tmp, %sub4
+  %arrayidx5 = getelementptr inbounds float, float* %A, i64 %arrayidx.sum
+  %tmp1 = load float, float* %arrayidx5, align 4
+  %tmp2 = mul nsw i64 %i.0, %n
+  %arrayidx6.sum = add i64 %tmp2, %j.0
+  %arrayidx7 = getelementptr inbounds float, float* %A, i64 %arrayidx6.sum
+  %tmp3 = load float, float* %arrayidx7, align 4
+  %add = fadd float %tmp3, %tmp1
+  store float %add, float* %arrayidx7, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nuw nsw i64 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %for.end
+  %inc9 = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end10:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_parameter_addrec_product.ll b/final/test/ScopInfo/multidim_parameter_addrec_product.ll
new file mode 100644
index 0000000..7b14e30
--- /dev/null
+++ b/final/test/ScopInfo/multidim_parameter_addrec_product.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+;    void foo(float *A, long *p) {
+;      for (long i = 0; i < 100; i++)
+;        for (long j = 0; j < 100; j++)
+;          A[i * (*p) + j] += i + j;
+;    }
+
+; CHECK:  Invariant Accesses: {
+; CHECK-NEXT:          ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              [pval] -> { Stmt_bb5[i0, i1] -> MemRef_p[0] };
+; CHECK-NEXT:          Execution Context: [pval] -> {  :  }
+; CHECK-NEXT:  }
+
+; CHECK: ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:     [pval] -> { Stmt_bb5[i0, i1] -> MemRef_A[i0, i1] };
+; CHECK: MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:     [pval] -> { Stmt_bb5[i0, i1] -> MemRef_A[i0, i1] };
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A, i64* %p) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb16, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp17, %bb16 ]
+  %exitcond1 = icmp ne i64 %i.0, 100
+  br i1 %exitcond1, label %bb3, label %bb18
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb13, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp14, %bb13 ]
+  %exitcond = icmp ne i64 %j.0, 100
+  br i1 %exitcond, label %bb5, label %bb15
+
+bb5:                                              ; preds = %bb4
+  %tmp = add nuw nsw i64 %i.0, %j.0
+  %tmp6 = sitofp i64 %tmp to float
+  %pval = load i64, i64* %p, align 8
+  %tmp8 = mul nsw i64 %i.0, %pval
+  %tmp9 = add nsw i64 %tmp8, %j.0
+  %tmp10 = getelementptr inbounds float, float* %A, i64 %tmp9
+  %tmp11 = load float, float* %tmp10, align 4
+  %tmp12 = fadd float %tmp11, %tmp6
+  store float %tmp12, float* %tmp10, align 4
+  br label %bb13
+
+bb13:                                             ; preds = %bb5
+  %tmp14 = add nuw nsw i64 %j.0, 1
+  br label %bb4
+
+bb15:                                             ; preds = %bb4
+  br label %bb16
+
+bb16:                                             ; preds = %bb15
+  %tmp17 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb18:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_single_and_multidim_array.ll b/final/test/ScopInfo/multidim_single_and_multidim_array.ll
new file mode 100644
index 0000000..cb876ee
--- /dev/null
+++ b/final/test/ScopInfo/multidim_single_and_multidim_array.ll
@@ -0,0 +1,92 @@
+; RUN: opt %loadPolly -polly-scops -polly-delinearize=false -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -polly-delinearize=false -polly-allow-nonaffine -analyze < %s | FileCheck %s --check-prefix=NONAFFINE
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s --check-prefix=DELIN
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s --check-prefix=DELIN
+; RUN: opt %loadPolly -polly-function-scops -polly-delinearize=false -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-function-scops -polly-delinearize=false -polly-allow-nonaffine -analyze < %s | FileCheck %s --check-prefix=NONAFFINE
+; RUN: opt %loadPolly -polly-function-scops -analyze < %s | FileCheck %s --check-prefix=DELIN
+; RUN: opt %loadPolly -polly-function-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s --check-prefix=DELIN
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; void single-and-multi-dimensional-array(long n,float X[n][n]) {
+;  for (long i1 = 0; i1 < n; i1++)
+;    X[i1][0] = 1;
+;
+;  for (long i2 = 0; i2 < n; i2++)
+;    X[n-1][i2] = 1;
+; }
+;
+; In previous versions of Polly, the second access was detected as single
+; dimensional access whereas the first one was detected as multi-dimensional.
+; This test case checks that we now consistently delinearize the array accesses.
+
+; CHECK-NOT: Stmt_for_i_1
+
+; NONAFFINE:      p0: %n
+; NONAFFINE-NEXT: p1: ((-1 + %n) * %n)
+;
+; NONAFFINE:      Statements {
+; NONAFFINE-NEXT:     Stmt_for_i_1
+; NONAFFINE-NEXT:         Domain :=
+; NONAFFINE-NEXT:             [n, p_1] -> { Stmt_for_i_1[i0] : 0 <= i0 < n };
+; NONAFFINE-NEXT:         Schedule :=
+; NONAFFINE-NEXT:             [n, p_1] -> { Stmt_for_i_1[i0] -> [0, i0] };
+; NONAFFINE-NEXT:         MayWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:             [n, p_1] -> { Stmt_for_i_1[i0] -> MemRef_X[o0] };
+; NONAFFINE-NEXT:     Stmt_for_i_2
+; NONAFFINE-NEXT:         Domain :=
+; NONAFFINE-NEXT:             [n, p_1] -> { Stmt_for_i_2[i0] : 0 <= i0 < n };
+; NONAFFINE-NEXT:         Schedule :=
+; NONAFFINE-NEXT:             [n, p_1] -> { Stmt_for_i_2[i0] -> [1, i0] };
+; NONAFFINE-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; NONAFFINE-NEXT:             [n, p_1] -> { Stmt_for_i_2[i0] -> MemRef_X[p_1 + i0] };
+; NONAFFINE-NEXT: }
+
+; DELIN:      Statements {
+; DELIN-NEXT:     Stmt_for_i_1
+; DELIN-NEXT:         Domain :=
+; DELIN-NEXT:             [n] -> { Stmt_for_i_1[i0] : 0 <= i0 < n };
+; DELIN-NEXT:         Schedule :=
+; DELIN-NEXT:             [n] -> { Stmt_for_i_1[i0] -> [0, i0] };
+; DELIN-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; DELIN-NEXT:             [n] -> { Stmt_for_i_1[i0] -> MemRef_X[i0, 0] };
+; DELIN-NEXT:     Stmt_for_i_2
+; DELIN-NEXT:         Domain :=
+; DELIN-NEXT:             [n] -> { Stmt_for_i_2[i0] : 0 <= i0 < n };
+; DELIN-NEXT:         Schedule :=
+; DELIN-NEXT:             [n] -> { Stmt_for_i_2[i0] -> [1, i0] };
+; DELIN-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; DELIN-NEXT:             [n] -> { Stmt_for_i_2[i0] -> MemRef_X[-1 + n, i0] };
+; DELIN-NEXT: }
+
+define void @single-and-multi-dimensional-array(i64 %n, float* %X) {
+entry:
+  br label %for.i.1
+
+for.i.1:
+  %indvar.1 = phi i64 [ 0, %entry ], [ %indvar.next.1, %for.i.1 ]
+  %offset.1 = mul i64 %n, %indvar.1
+  %arrayidx.1 = getelementptr float, float* %X, i64 %offset.1
+  store float 1.000000e+00, float* %arrayidx.1
+  %indvar.next.1 = add nsw i64 %indvar.1, 1
+  %exitcond.1 = icmp ne i64 %indvar.next.1, %n
+  br i1 %exitcond.1, label %for.i.1, label %next
+
+next:
+  br label %for.i.2
+
+for.i.2:
+  %indvar.2 = phi i64 [ 0, %next ], [ %indvar.next.2, %for.i.2 ]
+  %offset.2.a = add i64 %n, -1
+  %offset.2.b = mul i64 %n, %offset.2.a
+  %offset.2.c = add i64 %offset.2.b, %indvar.2
+  %arrayidx.2 = getelementptr float, float* %X, i64 %offset.2.c
+  store float 1.000000e+00, float* %arrayidx.2
+  %indvar.next.2 = add nsw i64 %indvar.2, 1
+  %exitcond.2 = icmp ne i64 %indvar.next.2, %n
+  br i1 %exitcond.2, label %for.i.2, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/multidim_srem.ll b/final/test/ScopInfo/multidim_srem.ll
new file mode 100644
index 0000000..61a7307
--- /dev/null
+++ b/final/test/ScopInfo/multidim_srem.ll
@@ -0,0 +1,99 @@
+; RUN: opt %loadPolly -analyze -polly-scops -S < %s | FileCheck %s
+;
+;    void foo(long n, float A[][n][n]) {
+;      for (long i = 0; i < 200; i++)
+;        for (long j = 0; j < n; j++)
+;          for (long k = 0; k < n; k++)
+;            A[i % 2][j][k] += 10;
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body_8
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_for_body_8[i0, i1, i2] : 0 <= i0 <= 199 and 0 <= i1 < n and 0 <= i2 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_for_body_8[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_for_body_8[i0, i1, i2] -> MemRef_A[o0, i1, i2] : 2*floor((i0 + o0)/2) = i0 + o0 and 0 <= o0 <= 1 };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_for_body_8[i0, i1, i2] -> MemRef_A[o0, i1, i2] : 2*floor((i0 + o0)/2) = i0 + o0 and 0 <= o0 <= 1 };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+
+define void @foo(i64 %n, float* %A) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond.1.preheader
+
+for.cond.1.preheader:                             ; preds = %entry.split, %for.inc.14
+  %i.06 = phi i64 [ 0, %entry.split ], [ %inc15, %for.inc.14 ]
+  %cmp2.3 = icmp sgt i64 %n, 0
+  br i1 %cmp2.3, label %for.cond.5.preheader.lr.ph, label %for.inc.14
+
+for.cond.5.preheader.lr.ph:                       ; preds = %for.cond.1.preheader
+  br label %for.cond.5.preheader
+
+for.cond.5.preheader:                             ; preds = %for.cond.5.preheader.lr.ph, %for.inc.11
+  %j.04 = phi i64 [ 0, %for.cond.5.preheader.lr.ph ], [ %inc12, %for.inc.11 ]
+  %cmp6.1 = icmp sgt i64 %n, 0
+  br i1 %cmp6.1, label %for.body.8.lr.ph, label %for.inc.11
+
+for.body.8.lr.ph:                                 ; preds = %for.cond.5.preheader
+  br label %for.body.8
+
+for.body.8:                                       ; preds = %for.body.8.lr.ph, %for.body.8
+  %k.02 = phi i64 [ 0, %for.body.8.lr.ph ], [ %inc, %for.body.8 ]
+  %rem = srem i64 %i.06, 2
+  %0 = mul nuw i64 %n, %n
+  %1 = mul nsw i64 %0, %rem
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %1
+  %2 = mul nsw i64 %j.04, %n
+  %arrayidx9 = getelementptr inbounds float, float* %arrayidx, i64 %2
+  %arrayidx10 = getelementptr inbounds float, float* %arrayidx9, i64 %k.02
+  %3 = load float, float* %arrayidx10, align 4, !tbaa !1
+  %add = fadd float %3, 1.000000e+01
+  store float %add, float* %arrayidx10, align 4, !tbaa !1
+  %inc = add nuw nsw i64 %k.02, 1
+  %exitcond = icmp ne i64 %inc, %n
+  br i1 %exitcond, label %for.body.8, label %for.cond.5.for.inc.11_crit_edge
+
+for.cond.5.for.inc.11_crit_edge:                  ; preds = %for.body.8
+  br label %for.inc.11
+
+for.inc.11:                                       ; preds = %for.cond.5.for.inc.11_crit_edge, %for.cond.5.preheader
+  %inc12 = add nuw nsw i64 %j.04, 1
+  %exitcond7 = icmp ne i64 %inc12, %n
+  br i1 %exitcond7, label %for.cond.5.preheader, label %for.cond.1.for.inc.14_crit_edge
+
+for.cond.1.for.inc.14_crit_edge:                  ; preds = %for.inc.11
+  br label %for.inc.14
+
+for.inc.14:                                       ; preds = %for.cond.1.for.inc.14_crit_edge, %for.cond.1.preheader
+  %inc15 = add nuw nsw i64 %i.06, 1
+  %exitcond8 = icmp ne i64 %inc15, 200
+  br i1 %exitcond8, label %for.cond.1.preheader, label %for.end.16
+
+for.end.16:                                       ; preds = %for.inc.14
+  ret void
+}
+
+; Function Attrs: nounwind
+declare void @llvm.lifetime.start(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind
+declare void @llvm.lifetime.end(i64, i8* nocapture) #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.7.0 (trunk 240923) (llvm/trunk 240924)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"float", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/ScopInfo/multidim_with_bitcast.ll b/final/test/ScopInfo/multidim_with_bitcast.ll
new file mode 100644
index 0000000..d954088
--- /dev/null
+++ b/final/test/ScopInfo/multidim_with_bitcast.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Verify that we can look through a bitcast when delinearizing multi-dimensional
+; arrays.
+
+; CHECK: Stmt_bb7[i0, i1] -> MemRef_B[i0, i1]
+; CHECK: Stmt_bb7[i0, i1] -> MemRef_B[i0, i1]
+; CHECK: Stmt_bb17[i0] -> MemRef_B[i0, 100]
+
+define void @kernel(float* %A, [101 x float]* %B, [101 x float]* %C, float* %D) {
+bb:
+  br label %bb4
+
+bb4:                                              ; preds = %bb21, %bb
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %bb21 ], [ 0, %bb ]
+  %exitcond3 = icmp eq i64 %indvars.iv1, 100
+  br i1 %exitcond3, label %bb22, label %bb5
+
+bb5:                                              ; preds = %bb4
+  br label %bb6
+
+bb6:                                              ; preds = %bb16, %bb5
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb16 ], [ 0, %bb5 ]
+  %exitcond = icmp eq i64 %indvars.iv, 100
+  br i1 %exitcond, label %bb17, label %bb7
+
+bb7:                                              ; preds = %bb6
+  %tmp = getelementptr inbounds float, float* %D, i64 %indvars.iv
+  %tmp8 = load float, float* %tmp, align 4
+  %tmp9 = getelementptr inbounds [101 x float], [101 x float]* %B, i64 %indvars.iv1, i64 %indvars.iv
+  %tmp10 = load float, float* %tmp9, align 4
+  %tmp11 = fmul float %tmp8, %tmp10
+  %tmp12 = getelementptr inbounds [101 x float], [101 x float]* %C, i64 %indvars.iv1, i64 %indvars.iv
+  store float %tmp11, float* %tmp12, align 4
+  %tmp13 = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %0 = bitcast float* %tmp13 to i32*
+  %tmp141 = load i32, i32* %0, align 4
+  %tmp15 = getelementptr inbounds [101 x float], [101 x float]* %B, i64 %indvars.iv1, i64 %indvars.iv
+  %1 = bitcast float* %tmp15 to i32*
+  store i32 %tmp141, i32* %1, align 4
+  br label %bb16
+
+bb16:                                             ; preds = %bb7
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb6
+
+bb17:                                             ; preds = %bb6
+  %tmp18 = trunc i64 %indvars.iv1 to i32
+  %tmp19 = sitofp i32 %tmp18 to float
+  %tmp20 = getelementptr inbounds [101 x float], [101 x float]* %B, i64 %indvars.iv1, i64 100
+  store float %tmp19, float* %tmp20, align 4
+  br label %bb21
+
+bb21:                                             ; preds = %bb17
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %bb4
+
+bb22:                                             ; preds = %bb4
+  ret void
+}
diff --git a/final/test/ScopInfo/multiple-binary-or-conditions.ll b/final/test/ScopInfo/multiple-binary-or-conditions.ll
new file mode 100644
index 0000000..f1a90bc
--- /dev/null
+++ b/final/test/ScopInfo/multiple-binary-or-conditions.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -analyze < %s
+;
+; void or(float *A, long n, long m) {
+;   for (long i = 0; i < 100; i++) {
+;     if (i < n || i < m || i > p)
+;       A[i] += i;
+;   }
+; }
+;
+; CHECK: Function: or
+; CHECK:   Stmt_if_then
+; CHECK:     Domain :=
+; CHECK:       [n, m, p] -> { Stmt_if_then[i0] : 0 <= i0 <= 99 and (i0 > p or i0 < m or i0 < n) };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @or(float* nocapture %A, i64 %n, i64 %m, i64 %p) #0 {
+entry:
+  br label %for.body
+
+for.body:                                         ; preds = %for.inc, %entry
+  %i.03 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp1 = icmp slt i64 %i.03, %n
+  %cmp2 = icmp slt i64 %i.03, %m
+  %cmp3 = icmp sgt i64 %i.03, %p
+  %or.tmp = or i1 %cmp1, %cmp2
+  %or.cond = or i1 %or.tmp, %cmp3
+  br i1 %or.cond, label %if.then, label %for.inc
+
+if.then:                                          ; preds = %for.body
+  %conv = sitofp i64 %i.03 to float
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.03
+  %0 = load float, float* %arrayidx, align 4
+  %add = fadd float %conv, %0
+  store float %add, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.then, %for.body
+  %inc = add nuw nsw i64 %i.03, 1
+  %exitcond = icmp eq i64 %inc, 100
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.inc
+  ret void
+}
diff --git a/final/test/ScopInfo/multiple-types-access-offset-not-dividable-by-element-size.ll b/final/test/ScopInfo/multiple-types-access-offset-not-dividable-by-element-size.ll
new file mode 100644
index 0000000..738c38c
--- /dev/null
+++ b/final/test/ScopInfo/multiple-types-access-offset-not-dividable-by-element-size.ll
@@ -0,0 +1,83 @@
+; RUN: opt %loadPolly -polly-scops -pass-remarks-analysis="polly-scops" \
+; RUN: -polly-allow-differing-element-types \
+; RUN:                -analyze < %s  2>&1 | FileCheck %s
+;
+;    // For the following accesses the offset expression from the base pointer
+;    // is not always a multiple of the type size.
+;    void multiple_types(char *Short, char *Float, char *Double) {
+;      for (long i = 0; i < 100; i++) {
+;        Short[i] = *(short *)&Short[i];
+;        Float[i] = *(float *)&Float[i];
+;        Double[i] = *(double *)&Double[i];
+;      }
+;    }
+;
+; CHECK:    Arrays {
+; CHECK:        i8 MemRef_Short[*]; // Element size 1
+; CHECK:        i8 MemRef_Float[*]; // Element size 1
+; CHECK:        i8 MemRef_Double[*]; // Element size 1
+; CHECK:    }
+; CHECK:    Arrays (Bounds as pw_affs) {
+; CHECK:        i8 MemRef_Short[*]; // Element size 1
+; CHECK:        i8 MemRef_Float[*]; // Element size 1
+; CHECK:        i8 MemRef_Double[*]; // Element size 1
+; CHECK:    }
+; CHECK:    Statements {
+; CHECK:      Stmt_bb2
+; CHECK:            Domain :=
+; CHECK:                { Stmt_bb2[i0] : 0 <= i0 <= 99 };
+; CHECK:            Schedule :=
+; CHECK:                { Stmt_bb2[i0] -> [i0] };
+; CHECK:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2[i0] -> MemRef_Short[o0] : i0 <= o0 <= 1 + i0 };
+; CHECK:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2[i0] -> MemRef_Short[i0] };
+; CHECK:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2[i0] -> MemRef_Float[o0] : i0 <= o0 <= 3 + i0 };
+; CHECK:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2[i0] -> MemRef_Float[i0] };
+; CHECK:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2[i0] -> MemRef_Double[o0] : i0 <= o0 <= 7 + i0 };
+; CHECK:            MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2[i0] -> MemRef_Double[i0] };
+; CHECK:    }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @multiple_types(i8* %Short, i8* %Float, i8* %Double) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb17, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp18, %bb17 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb2, label %bb19
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i8, i8* %Short, i64 %i.0
+  %tmp3 = bitcast i8* %tmp to i16*
+  %tmp4 = load i16, i16* %tmp3, align 1
+  %tmp5 = trunc i16 %tmp4 to i8
+  %tmp6 = getelementptr inbounds i8, i8* %Short, i64 %i.0
+  store i8 %tmp5, i8* %tmp6, align 1
+  %tmp7 = getelementptr inbounds i8, i8* %Float, i64 %i.0
+  %tmp8 = bitcast i8* %tmp7 to float*
+  %tmp9 = load float, float* %tmp8, align 1
+  %tmp10 = fptosi float %tmp9 to i8
+  %tmp11 = getelementptr inbounds i8, i8* %Float, i64 %i.0
+  store i8 %tmp10, i8* %tmp11, align 1
+  %tmp12 = getelementptr inbounds i8, i8* %Double, i64 %i.0
+  %tmp13 = bitcast i8* %tmp12 to double*
+  %tmp14 = load double, double* %tmp13, align 1
+  %tmp15 = fptosi double %tmp14 to i8
+  %tmp16 = getelementptr inbounds i8, i8* %Double, i64 %i.0
+  store i8 %tmp15, i8* %tmp16, align 1
+  br label %bb17
+
+bb17:                                             ; preds = %bb2
+  %tmp18 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb19:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/multiple-types-non-affine-2.ll b/final/test/ScopInfo/multiple-types-non-affine-2.ll
new file mode 100644
index 0000000..6fb4638
--- /dev/null
+++ b/final/test/ScopInfo/multiple-types-non-affine-2.ll
@@ -0,0 +1,79 @@
+; RUN: opt %loadPolly -polly-allow-differing-element-types -polly-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-allow-differing-element-types -polly-codegen -polly-allow-nonaffine -analyze
+;
+;    // Check that accessing one array with different types works,
+;    // even though some accesses are non-affine.
+;    void multiple_types(char *Short, short *Char, char *Double) {
+;      for (long i = 0; i < 100; i++) {
+;        Short[i] = *(short *)&Short[i & 8];
+;        Char[i] = *(float *)&Char[i & 8];
+;        Double[i] = *(double *)&Double[i & 8];
+;      }
+;    }
+;
+; CHECK:    Arrays {
+; CHECK:        i16 MemRef_Short[*]; // Element size 2
+; CHECK:        i8 MemRef_Char[*]; // Element size 1
+; CHECK:        i32 MemRef_Double[*]; // Element size 4
+; CHECK:    }
+;
+; CHECK: Statements {
+; CHECK-NEXT: Stmt_bb2
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT:     { Stmt_bb2[i0] : 0 <= i0 <= 99 };
+; CHECK-NEXT: Schedule :=
+; CHECK-NEXT:     { Stmt_bb2[i0] -> [i0] };
+; CHECK-NEXT: ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Short[16] : 16*floor((8 + i0)/16) > i0; Stmt_bb2[i0] -> MemRef_Short[0] : 16*floor((8 + i0)/16) <= i0 }
+; CHECK-NEXT: MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Short[o0] : 2i0 <= o0 <= 1 + 2i0 };
+; CHECK-NEXT: ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Char[32] : 16*floor((8 + i0)/16) > i0; Stmt_bb2[i0] -> MemRef_Char[0] : 16*floor((8 + i0)/16) <= i0 }
+; CHECK-NEXT: MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Char[o0] : 4i0 <= o0 <= 3 + 4i0 };
+; CHECK-NEXT: ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Double[o0] : 0 <= o0 <= 9 and ((o0 >= 8 and 16*floor((8 + i0)/16) > i0) or (o0 <= 1 and 16*floor((8 + i0)/16) <= i0)) }
+; CHECK-NEXT: MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Double[i0] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @multiple_types(i32* noalias %Short, i32* noalias %Char, i32* noalias %Double) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb20, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp21, %bb20 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb2, label %bb22
+
+bb2:                                              ; preds = %bb1
+  %quad = and i64 %i.0, 8
+  %tmp3 = getelementptr inbounds i32, i32* %Short, i64 %quad
+  %tmp4 = bitcast i32* %tmp3 to i16*
+  %tmp5 = load i16, i16* %tmp4, align 2
+  %tmp6 = zext i16 %tmp5 to i32
+  %tmp7 = getelementptr inbounds i32, i32* %Short, i64 %i.0
+  store i32 %tmp6, i32* %tmp7, align 1
+  %tmp9 = getelementptr inbounds i32, i32* %Char, i64 %quad
+  %tmp10 = bitcast i32* %tmp9 to i8*
+  %tmp11 = load i8, i8* %tmp10, align 4
+  %tmp12 = zext i8 %tmp11 to i32
+  %tmp13 = getelementptr inbounds i32, i32* %Char, i64 %i.0
+  store i32 %tmp12, i32* %tmp13, align 1
+  %tmp15 = getelementptr inbounds i32, i32* %Double, i64 %quad
+  %tmp16 = bitcast i32* %tmp15 to double*
+  %tmp17 = load double, double* %tmp16, align 8
+  %tmp18 = fptosi double %tmp17 to i32
+  %tmp19 = getelementptr inbounds i32, i32* %Double, i64 %i.0
+  store i32 %tmp18, i32* %tmp19, align 1
+  br label %bb20
+
+bb20:                                             ; preds = %bb2
+  %tmp21 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb22:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/multiple-types-non-affine.ll b/final/test/ScopInfo/multiple-types-non-affine.ll
new file mode 100644
index 0000000..e090655
--- /dev/null
+++ b/final/test/ScopInfo/multiple-types-non-affine.ll
@@ -0,0 +1,79 @@
+; RUN: opt %loadPolly -polly-allow-differing-element-types -polly-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-allow-differing-element-types -polly-codegen -polly-allow-nonaffine -analyze
+;
+;    // Check that accessing one array with different types works,
+;    // even though some accesses are non-affine.
+;    void multiple_types(char *Short, short *Float, char *Double) {
+;      for (long i = 0; i < 100; i++) {
+;        Short[i] = *(short *)&Short[i & 8];
+;        Float[i] = *(float *)&Float[i & 8];
+;        Double[i] = *(double *)&Double[i & 8];
+;      }
+;    }
+;
+; CHECK:    Arrays {
+; CHECK:        i8 MemRef_Short[*]; // Element size 1
+; CHECK:        i16 MemRef_Float[*]; // Element size 2
+; CHECK:        i8 MemRef_Double[*]; // Element size 1
+; CHECK:    }
+;
+; CHECK: Statements {
+; CHECK-NEXT: Stmt_bb2
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT:     { Stmt_bb2[i0] : 0 <= i0 <= 99 };
+; CHECK-NEXT: Schedule :=
+; CHECK-NEXT:     { Stmt_bb2[i0] -> [i0] };
+; CHECK-NEXT: ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Short[o0] : 0 <= o0 <= 9 and ((o0 >= 8 and 16*floor((8 + i0)/16) > i0) or (o0 <= 1 and 16*floor((8 + i0)/16) <= i0)) };
+; CHECK-NEXT: MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Short[i0] };
+; CHECK-NEXT: ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Float[o0] : 0 <= o0 <= 9 and ((o0 >= 8 and 16*floor((8 + i0)/16) > i0) or (o0 <= 1 and 16*floor((8 + i0)/16) <= i0)) };
+; CHECK-NEXT: MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Float[i0] };
+; CHECK-NEXT: ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Double[o0] : 0 <= o0 <= 15 and ((o0 >= 8 and 16*floor((8 + i0)/16) > i0) or (o0 <= 7 and 16*floor((8 + i0)/16) <= i0)) };
+; CHECK-NEXT: MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Double[i0] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @multiple_types(i8* noalias %Short, i16* noalias %Float, i8* noalias %Double) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb20, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp21, %bb20 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb2, label %bb22
+
+bb2:                                              ; preds = %bb1
+  %quad = and i64 %i.0, 8
+  %tmp3 = getelementptr inbounds i8, i8* %Short, i64 %quad
+  %tmp4 = bitcast i8* %tmp3 to i16*
+  %tmp5 = load i16, i16* %tmp4, align 2
+  %tmp6 = trunc i16 %tmp5 to i8
+  %tmp7 = getelementptr inbounds i8, i8* %Short, i64 %i.0
+  store i8 %tmp6, i8* %tmp7, align 1
+  %tmp9 = getelementptr inbounds i16, i16* %Float, i64 %quad
+  %tmp10 = bitcast i16* %tmp9 to float*
+  %tmp11 = load float, float* %tmp10, align 4
+  %tmp12 = fptosi float %tmp11 to i16
+  %tmp13 = getelementptr inbounds i16, i16* %Float, i64 %i.0
+  store i16 %tmp12, i16* %tmp13, align 1
+  %tmp15 = getelementptr inbounds i8, i8* %Double, i64 %quad
+  %tmp16 = bitcast i8* %tmp15 to double*
+  %tmp17 = load double, double* %tmp16, align 8
+  %tmp18 = fptosi double %tmp17 to i8
+  %tmp19 = getelementptr inbounds i8, i8* %Double, i64 %i.0
+  store i8 %tmp18, i8* %tmp19, align 1
+  br label %bb20
+
+bb20:                                             ; preds = %bb2
+  %tmp21 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb22:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/multiple-types-non-power-of-two-2.ll b/final/test/ScopInfo/multiple-types-non-power-of-two-2.ll
new file mode 100644
index 0000000..7f12d03
--- /dev/null
+++ b/final/test/ScopInfo/multiple-types-non-power-of-two-2.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-allow-differing-element-types < %s | FileCheck %s
+;
+;  void multiple_types(i8 *A) {
+;    for (long i = 0; i < 100; i++) {
+;      A[i] = *(i128 *)&A[16 * i] +
+;             *(i192 *)&A[24 * i];
+;    }
+;  }
+;
+;
+; CHECK: Arrays {
+; CHECK:     i64 MemRef_A[*]; // Element size 8
+; CHECK: }
+; CHECK: Arrays (Bounds as pw_affs) {
+; CHECK:     i64 MemRef_A[*]; // Element size 8
+; CHECK: }
+; CHECK: Alias Groups (0):
+; CHECK:     n/a
+; CHECK: Statements {
+; CHECK:   Stmt_bb2
+; CHECK:         Domain :=
+; CHECK:             { Stmt_bb2[i0] : 0 <= i0 <= 99 };
+; CHECK:         Schedule :=
+; CHECK:             { Stmt_bb2[i0] -> [i0] };
+; CHECK:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 2i0 <= o0 <= 1 + 2i0 }
+; CHECK:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 3i0 <= o0 <= 2 + 3i0 }
+; CHECK:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 2i0 <= o0 <= 1 + 2i0 }
+; CHECK: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @multiple_types(i8* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb20, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp21, %bb20 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb2, label %bb22
+
+bb2:                                              ; preds = %bb1
+  %load.i128.offset = mul i64 %i.0, 16
+  %load.i128.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i128.offset
+  %load.i128.ptrcast = bitcast i8* %load.i128.ptr to i128*
+  %load.i128.val = load i128, i128* %load.i128.ptrcast
+
+  %load.i192.offset = mul i64 %i.0, 24
+  %load.i192.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i192.offset
+  %load.i192.ptrcast = bitcast i8* %load.i192.ptr to i192*
+  %load.i192.val = load i192, i192* %load.i192.ptrcast
+  %load.i192.val.trunc = trunc i192 %load.i192.val to i128
+
+  %sum = add i128 %load.i128.val, %load.i192.val.trunc
+  store i128 %sum, i128* %load.i128.ptrcast
+  br label %bb20
+
+bb20:                                             ; preds = %bb2
+  %tmp21 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb22:                                             ; preds = %bb1
+  ret void
+}
+
diff --git a/final/test/ScopInfo/multiple-types-non-power-of-two.ll b/final/test/ScopInfo/multiple-types-non-power-of-two.ll
new file mode 100644
index 0000000..f95aa12
--- /dev/null
+++ b/final/test/ScopInfo/multiple-types-non-power-of-two.ll
@@ -0,0 +1,161 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-allow-differing-element-types < %s | FileCheck %s
+;
+;  void multiple_types(i8 *A) {
+;    for (long i = 0; i < 100; i++) {
+;      A[i] = *(i1 *)&A[1 * i] +
+;             *(i16 *)&A[2 * i] +
+;             *(i24 *)&A[4 * i] +
+;             *(i32 *)&A[4 * i] +
+;             *(i40 *)&A[8 * i] +
+;             *(i48 *)&A[8 * i] +
+;             *(i56 *)&A[8 * i] +
+;             *(i64 *)&A[8 * i] +
+;             *(i120 *)&A[16 * i] +
+;             *(i192 *)&A[24 * i] +
+;             *(i248 *)&A[32 * i];
+;    }
+;  }
+;
+; Verify that different data type sizes are correctly modeled. Specifically,
+; we want to verify that type i1 is modeled with allocation size i8,
+; type i24 is modeled with allocation size i32 and that i40, i48 and i56 are
+; modeled with allocation size i64. Larger types, e.g., i120, i192 and i248 are
+; not rounded up to the next power-of-two allocation size, but rather to the
+; next multiple of 64.
+
+; The allocation size discussed above defines the number of canonical array
+; elements accessed. For example, even though i24 only consists of 3 bytes,
+; its allocation size is 4 bytes. Consequently, we model the access to an
+; i24 element as an access to four canonical elements resulting in access
+; relation constraints '4i0 <= o0 <= 3 + 4i0' instead of '3i0 <= o0 <= 2 + 3i0'.
+
+; CHECK: Statements {
+; CHECK:   Stmt_bb2
+; CHECK:         Domain :=
+; CHECK:             { Stmt_bb2[i0] : 0 <= i0 <= 99 };
+; CHECK:         Schedule :=
+; CHECK:             { Stmt_bb2[i0] -> [i0] };
+; CHECK:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 2i0 <= o0 <= 1 + 2i0 };
+; CHECK:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 4i0 <= o0 <= 3 + 4i0 };
+; CHECK:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 4i0 <= o0 <= 3 + 4i0 };
+; CHECK:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 8i0 <= o0 <= 7 + 8i0 };
+; CHECK:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 8i0 <= o0 <= 7 + 8i0 };
+; CHECK:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 8i0 <= o0 <= 7 + 8i0 };
+; CHECK:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 8i0 <= o0 <= 7 + 8i0 };
+; CHECK:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 16i0 <= o0 <= 15 + 16i0 };
+; CHECK:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 24i0 <= o0 <= 23 + 24i0 };
+; CHECK:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[o0] : 32i0 <= o0 <= 31 + 32i0 };
+; CHECK:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb2[i0] -> MemRef_A[i0] };
+; CHECK: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @multiple_types(i8* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb20, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp21, %bb20 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb2, label %bb22
+
+bb2:                                              ; preds = %bb1
+  %load.i1.offset = mul i64 %i.0, 1
+  %load.i1.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i1.offset
+  %load.i1.ptrcast = bitcast i8* %load.i1.ptr to i1*
+  %load.i1.val = load i1, i1* %load.i1.ptrcast
+  %load.i1.val.trunc = zext i1 %load.i1.val to i8
+
+  %load.i16.offset = mul i64 %i.0, 2
+  %load.i16.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i16.offset
+  %load.i16.ptrcast = bitcast i8* %load.i16.ptr to i16*
+  %load.i16.val = load i16, i16* %load.i16.ptrcast
+  %load.i16.val.trunc = trunc i16 %load.i16.val to i8
+
+  %load.i24.offset = mul i64 %i.0, 4
+  %load.i24.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i24.offset
+  %load.i24.ptrcast = bitcast i8* %load.i24.ptr to i24*
+  %load.i24.val = load i24, i24* %load.i24.ptrcast
+  %load.i24.val.trunc = trunc i24 %load.i24.val to i8
+
+  %load.i32.offset = mul i64 %i.0, 4
+  %load.i32.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i32.offset
+  %load.i32.ptrcast = bitcast i8* %load.i32.ptr to i32*
+  %load.i32.val = load i32, i32* %load.i32.ptrcast
+  %load.i32.val.trunc = trunc i32 %load.i32.val to i8
+
+  %load.i40.offset = mul i64 %i.0, 8
+  %load.i40.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i40.offset
+  %load.i40.ptrcast = bitcast i8* %load.i40.ptr to i40*
+  %load.i40.val = load i40, i40* %load.i40.ptrcast
+  %load.i40.val.trunc = trunc i40 %load.i40.val to i8
+
+  %load.i48.offset = mul i64 %i.0, 8
+  %load.i48.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i48.offset
+  %load.i48.ptrcast = bitcast i8* %load.i48.ptr to i48*
+  %load.i48.val = load i48, i48* %load.i48.ptrcast
+  %load.i48.val.trunc = trunc i48 %load.i48.val to i8
+
+  %load.i56.offset = mul i64 %i.0, 8
+  %load.i56.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i56.offset
+  %load.i56.ptrcast = bitcast i8* %load.i56.ptr to i56*
+  %load.i56.val = load i56, i56* %load.i56.ptrcast
+  %load.i56.val.trunc = trunc i56 %load.i56.val to i8
+
+  %load.i64.offset = mul i64 %i.0, 8
+  %load.i64.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i64.offset
+  %load.i64.ptrcast = bitcast i8* %load.i64.ptr to i64*
+  %load.i64.val = load i64, i64* %load.i64.ptrcast
+  %load.i64.val.trunc = trunc i64 %load.i64.val to i8
+
+  %load.i120.offset = mul i64 %i.0, 16
+  %load.i120.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i120.offset
+  %load.i120.ptrcast = bitcast i8* %load.i120.ptr to i120*
+  %load.i120.val = load i120, i120* %load.i120.ptrcast
+  %load.i120.val.trunc = trunc i120 %load.i120.val to i8
+
+  %load.i192.offset = mul i64 %i.0, 24
+  %load.i192.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i192.offset
+  %load.i192.ptrcast = bitcast i8* %load.i192.ptr to i192*
+  %load.i192.val = load i192, i192* %load.i192.ptrcast
+  %load.i192.val.trunc = trunc i192 %load.i192.val to i8
+
+  %load.i248.offset = mul i64 %i.0, 32
+  %load.i248.ptr = getelementptr inbounds i8, i8* %A, i64 %load.i248.offset
+  %load.i248.ptrcast = bitcast i8* %load.i248.ptr to i248*
+  %load.i248.val = load i248, i248* %load.i248.ptrcast
+  %load.i248.val.trunc = trunc i248 %load.i248.val to i8
+
+  %sum = add i8 %load.i1.val.trunc, %load.i16.val.trunc
+  %sum0 = add i8 %sum, %load.i24.val.trunc
+  %sum1 = add i8 %sum0, %load.i32.val.trunc
+  %sum2 = add i8 %sum1, %load.i40.val.trunc
+  %sum3 = add i8 %sum2, %load.i48.val.trunc
+  %sum4 = add i8 %sum3, %load.i56.val.trunc
+  %sum5 = add i8 %sum4, %load.i64.val.trunc
+  %sum6 = add i8 %sum5, %load.i120.val.trunc
+  %sum7 = add i8 %sum6, %load.i192.val.trunc
+  %sum8 = add i8 %sum7, %load.i248.val.trunc
+  %tmp7 = getelementptr inbounds i8, i8* %A, i64 %i.0
+  store i8 %sum8, i8* %tmp7
+  br label %bb20
+
+bb20:                                             ; preds = %bb2
+  %tmp21 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb22:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/multiple-types-two-dimensional-2.ll b/final/test/ScopInfo/multiple-types-two-dimensional-2.ll
new file mode 100644
index 0000000..116bdac
--- /dev/null
+++ b/final/test/ScopInfo/multiple-types-two-dimensional-2.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-scops -pass-remarks-analysis="polly-scops" \
+; RUN:                -polly-allow-differing-element-types \
+; RUN:                -analyze < %s  2>&1 | FileCheck %s
+;
+;
+;    void foo(long n, long m, char A[][m]) {
+;      for (long i = 0; i < n; i++)
+;        for (long j = 0; j < m / 4; j++)
+;          *(float *)&A[i][4 * j] = A[i][j];
+;    }
+;
+; We do not yet correctly handle multi-dimensional arrays which are accessed
+; through different base types. Verify that we correctly bail out.
+;
+; CHECK: Delinearization assumption:  {  : 1 = 0 }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %n, i64 %m, i8* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb20, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp21, %bb20 ]
+  %tmp = icmp slt i64 %i.0, %n
+  br i1 %tmp, label %bb2, label %bb22
+
+bb2:                                              ; preds = %bb1
+  br label %bb3
+
+bb3:                                              ; preds = %bb17, %bb2
+  %j.0 = phi i64 [ 0, %bb2 ], [ %tmp18, %bb17 ]
+  %tmp4 = sdiv i64 %m, 4
+  %tmp5 = icmp slt i64 %j.0, %tmp4
+  br i1 %tmp5, label %bb6, label %bb19
+
+bb6:                                              ; preds = %bb3
+  %tmp7 = mul nsw i64 %i.0, %m
+  %tmp8 = getelementptr inbounds i8, i8* %A, i64 %tmp7
+  %tmp9 = getelementptr inbounds i8, i8* %tmp8, i64 %j.0
+  %tmp10 = load i8, i8* %tmp9, align 1
+  %tmp11 = sitofp i8 %tmp10 to float
+  %tmp12 = shl nsw i64 %j.0, 2
+  %tmp13 = mul nsw i64 %i.0, %m
+  %tmp14 = getelementptr inbounds i8, i8* %A, i64 %tmp13
+  %tmp15 = getelementptr inbounds i8, i8* %tmp14, i64 %tmp12
+  %tmp16 = bitcast i8* %tmp15 to float*
+  store float %tmp11, float* %tmp16, align 4
+  br label %bb17
+
+bb17:                                             ; preds = %bb6
+  %tmp18 = add nuw nsw i64 %j.0, 1
+  br label %bb3
+
+bb19:                                             ; preds = %bb3
+  br label %bb20
+
+bb20:                                             ; preds = %bb19
+  %tmp21 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb22:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/multiple-types-two-dimensional.ll b/final/test/ScopInfo/multiple-types-two-dimensional.ll
new file mode 100644
index 0000000..5885595
--- /dev/null
+++ b/final/test/ScopInfo/multiple-types-two-dimensional.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-scops -pass-remarks-analysis="polly-scops" \
+; RUN: -polly-allow-differing-element-types \
+; RUN:                -analyze < %s  2>&1 | FileCheck %s
+;
+;    void foo(long n, long m, char A[][m]) {
+;      for (long i = 0; i < n; i++)
+;        for (long j = 0; j < m / 4; j++)
+;          A[i][j] = *(float *)&A[i][4 * j];
+;    }
+;
+; We do not yet correctly handle multi-dimensional arrays which are accessed
+; through different base types. Verify that we correctly bail out.
+;
+; CHECK: Delinearization assumption:  {  : 1 = 0 }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %n, i64 %m, i8* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb20, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp21, %bb20 ]
+  %tmp = icmp slt i64 %i.0, %n
+  br i1 %tmp, label %bb2, label %bb22
+
+bb2:                                              ; preds = %bb1
+  br label %bb3
+
+bb3:                                              ; preds = %bb17, %bb2
+  %j.0 = phi i64 [ 0, %bb2 ], [ %tmp18, %bb17 ]
+  %tmp4 = sdiv i64 %m, 4
+  %tmp5 = icmp slt i64 %j.0, %tmp4
+  br i1 %tmp5, label %bb6, label %bb19
+
+bb6:                                              ; preds = %bb3
+  %tmp7 = shl nsw i64 %j.0, 2
+  %tmp8 = mul nsw i64 %i.0, %m
+  %tmp9 = getelementptr inbounds i8, i8* %A, i64 %tmp8
+  %tmp10 = getelementptr inbounds i8, i8* %tmp9, i64 %tmp7
+  %tmp11 = bitcast i8* %tmp10 to float*
+  %tmp12 = load float, float* %tmp11, align 4
+  %tmp13 = fptosi float %tmp12 to i8
+  %tmp14 = mul nsw i64 %i.0, %m
+  %tmp15 = getelementptr inbounds i8, i8* %A, i64 %tmp14
+  %tmp16 = getelementptr inbounds i8, i8* %tmp15, i64 %j.0
+  store i8 %tmp13, i8* %tmp16, align 1
+  br label %bb17
+
+bb17:                                             ; preds = %bb6
+  %tmp18 = add nuw nsw i64 %j.0, 1
+  br label %bb3
+
+bb19:                                             ; preds = %bb3
+  br label %bb20
+
+bb20:                                             ; preds = %bb19
+  %tmp21 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb22:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/multiple-types.ll b/final/test/ScopInfo/multiple-types.ll
new file mode 100644
index 0000000..a776f3e
--- /dev/null
+++ b/final/test/ScopInfo/multiple-types.ll
@@ -0,0 +1,74 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-allow-differing-element-types < %s | FileCheck %s
+;
+;    // Check that accessing one array with different types works.
+;    void multiple_types(char *Short, char *Float, char *Double) {
+;      for (long i = 0; i < 100; i++) {
+;        Short[i] = *(short *)&Short[2 * i];
+;        Float[i] = *(float *)&Float[4 * i];
+;        Double[i] = *(double *)&Double[8 * i];
+;      }
+;    }
+
+; CHECK: Statements {
+; CHECK-NEXT: Stmt_bb2
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT:     { Stmt_bb2[i0] : 0 <= i0 <= 99 };
+; CHECK-NEXT: Schedule :=
+; CHECK-NEXT:     { Stmt_bb2[i0] -> [i0] };
+; CHECK-NEXT: ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Short[o0] : 2i0 <= o0 <= 1 + 2i0 };
+; CHECK-NEXT: MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Short[i0] };
+; CHECK-NEXT: ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Float[o0] : 4i0 <= o0 <= 3 + 4i0 };
+; CHECK-NEXT: MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Float[i0] };
+; CHECK-NEXT: ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Double[o0] : 8i0 <= o0 <= 7 + 8i0 };
+; CHECK-NEXT: MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:     { Stmt_bb2[i0] -> MemRef_Double[i0] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @multiple_types(i8* %Short, i8* %Float, i8* %Double) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb20, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp21, %bb20 ]
+  %exitcond = icmp ne i64 %i.0, 100
+  br i1 %exitcond, label %bb2, label %bb22
+
+bb2:                                              ; preds = %bb1
+  %tmp = shl nsw i64 %i.0, 1
+  %tmp3 = getelementptr inbounds i8, i8* %Short, i64 %tmp
+  %tmp4 = bitcast i8* %tmp3 to i16*
+  %tmp5 = load i16, i16* %tmp4, align 2
+  %tmp6 = trunc i16 %tmp5 to i8
+  %tmp7 = getelementptr inbounds i8, i8* %Short, i64 %i.0
+  store i8 %tmp6, i8* %tmp7, align 1
+  %tmp8 = shl nsw i64 %i.0, 2
+  %tmp9 = getelementptr inbounds i8, i8* %Float, i64 %tmp8
+  %tmp10 = bitcast i8* %tmp9 to float*
+  %tmp11 = load float, float* %tmp10, align 4
+  %tmp12 = fptosi float %tmp11 to i8
+  %tmp13 = getelementptr inbounds i8, i8* %Float, i64 %i.0
+  store i8 %tmp12, i8* %tmp13, align 1
+  %tmp14 = shl nsw i64 %i.0, 3
+  %tmp15 = getelementptr inbounds i8, i8* %Double, i64 %tmp14
+  %tmp16 = bitcast i8* %tmp15 to double*
+  %tmp17 = load double, double* %tmp16, align 8
+  %tmp18 = fptosi double %tmp17 to i8
+  %tmp19 = getelementptr inbounds i8, i8* %Double, i64 %i.0
+  store i8 %tmp18, i8* %tmp19, align 1
+  br label %bb20
+
+bb20:                                             ; preds = %bb2
+  %tmp21 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb22:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/multiple_exiting_blocks.ll b/final/test/ScopInfo/multiple_exiting_blocks.ll
new file mode 100644
index 0000000..01efa4e
--- /dev/null
+++ b/final/test/ScopInfo/multiple_exiting_blocks.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Domain :=
+; CHECK:   [N, P, Q] -> { Stmt_if_end[i0] : 0 <= i0 <= 1 + Q and i0 < N and (i0 < P or (P < 0 and i0 >= 2 + P)); Stmt_if_end[0] : N > 0 and ((P <= -2 and Q <= -2) or (P > 0 and Q <= -2) or P = -1) };
+;
+;    void f(int *A, int N, int P, int Q) {
+;      for (int i = 0; i < N; i++) {
+;        if (i == P)
+;          break;
+;        A[i]++;
+;        if (i > Q)
+;          break;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N, i32 %P, i32 %Q) {
+entry:
+  %tmp = sext i32 %N to i64
+  %tmp1 = sext i32 %Q to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end.loopexit
+
+for.body:                                         ; preds = %for.cond
+  %tmp2 = trunc i64 %indvars.iv to i32
+  %cmp1 = icmp eq i32 %tmp2, %P
+  br i1 %cmp1, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  br label %for.end
+
+if.end:                                           ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp3, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  %cmp2 = icmp sgt i64 %indvars.iv, %tmp1
+  br i1 %cmp2, label %if.then.3, label %if.end.4
+
+if.then.3:                                        ; preds = %if.end
+  br label %for.end
+
+if.end.4:                                         ; preds = %if.end
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end.4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end.loopexit:                                 ; preds = %for.cond
+  br label %for.end
+
+for.end:                                          ; preds = %for.end.loopexit, %if.then.3, %if.then
+  ret void
+}
diff --git a/final/test/ScopInfo/multiple_exiting_blocks_two_loop.ll b/final/test/ScopInfo/multiple_exiting_blocks_two_loop.ll
new file mode 100644
index 0000000..1283ef6
--- /dev/null
+++ b/final/test/ScopInfo/multiple_exiting_blocks_two_loop.ll
@@ -0,0 +1,78 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void foo(long n, float A[100]) {
+;      for (long j = 0; j < n; j++) {
+;        for (long i = j; i < n; i++) {
+;          if (i < 0)
+;            goto end;
+;
+;          if (i >= 100)
+;            goto end;
+;
+;          A[i] += i;
+;        }
+;      }
+;    end:
+;      return;
+;    }
+;
+; CHECK: Domain :=
+; CHECK:  [n] -> { Stmt_if_end_7[i0, i1] : i0 >= 0 and 0 <= i1 <= 99 - i0 and i1 < n - i0 };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(i64 %n, float* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.8, %entry
+  %j.0 = phi i64 [ 0, %entry ], [ %inc9, %for.inc.8 ]
+  %cmp = icmp slt i64 %j.0, %n
+  br i1 %cmp, label %for.body, label %for.end.10
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond.1
+
+for.cond.1:                                       ; preds = %for.inc, %for.body
+  %i.0 = phi i64 [ %j.0, %for.body ], [ %inc, %for.inc ]
+  %cmp2 = icmp slt i64 %i.0, %n
+  br i1 %cmp2, label %for.body.3, label %for.end
+
+for.body.3:                                       ; preds = %for.cond.1
+  br i1 false, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body.3
+  br label %end
+
+if.end:                                           ; preds = %for.body.3
+  %cmp5 = icmp sgt i64 %i.0, 99
+  br i1 %cmp5, label %if.then.6, label %if.end.7
+
+if.then.6:                                        ; preds = %if.end
+  br label %end
+
+if.end.7:                                         ; preds = %if.end
+  %conv = sitofp i64 %i.0 to float
+  %arrayidx = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp = load float, float* %arrayidx, align 4
+  %add = fadd float %tmp, %conv
+  store float %add, float* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end.7
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond.1
+
+for.end:                                          ; preds = %for.cond.1
+  br label %for.inc.8
+
+for.inc.8:                                        ; preds = %for.end
+  %inc9 = add nuw nsw i64 %j.0, 1
+  br label %for.cond
+
+for.end.10:                                       ; preds = %for.cond
+  br label %end
+
+end:                                              ; preds = %for.end.10, %if.then.6, %if.then
+  ret void
+}
diff --git a/final/test/ScopInfo/multiple_latch_blocks.ll b/final/test/ScopInfo/multiple_latch_blocks.ll
new file mode 100644
index 0000000..479bf2f
--- /dev/null
+++ b/final/test/ScopInfo/multiple_latch_blocks.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s
+;
+; CHECK: Domain :=
+; CHECK:   [N, P] -> { Stmt_if_end[i0] : 0 <= i0 < N and (i0 > P or i0 < P) };
+;
+;    void f(int *A, int N, int P, int Q) {
+;      for (int i = 0; i < N; i++) {
+;        if (i == P)
+;          continue;
+;        A[i]++;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N, i32 %P, i32 %Q) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %if.then ], [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp1 = trunc i64 %indvars.iv to i32
+  %cmp1 = icmp eq i32 %tmp1, %P
+  br i1 %cmp1, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  br label %for.cond
+
+if.end:                                           ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp2, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end, %if.then
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/nested-loops.ll b/final/test/ScopInfo/nested-loops.ll
new file mode 100644
index 0000000..f359866
--- /dev/null
+++ b/final/test/ScopInfo/nested-loops.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* nocapture %a) nounwind {
+entry:
+  br label %for.i
+
+for.i:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %for.j ]
+  %i.inc = add nsw i64 %i, 1
+  %exitcond.i = icmp sge i64 %i.inc, 2048
+  br i1 %exitcond.i, label %return, label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i ], [ %j.inc, %body ]
+  %j.inc = add nsw i64 %j, 1
+  %exitcond.j = icmp slt i64 %j.inc, 1024
+  br i1 %exitcond.j, label %body, label %for.i
+
+body:
+  %scevgep = getelementptr i64, i64* %a, i64 %j
+  store i64 %j, i64* %scevgep
+  br label %for.j
+
+return:
+  ret void
+}
+
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_body[i0, i1] : 0 <= i0 <= 2046 and 0 <= i1 <= 1022 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_body[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_body[i0, i1] -> MemRef_a[i1] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/no-scalar-deps-in-non-affine-subregion.ll b/final/test/ScopInfo/no-scalar-deps-in-non-affine-subregion.ll
new file mode 100644
index 0000000..379d02a
--- /dev/null
+++ b/final/test/ScopInfo/no-scalar-deps-in-non-affine-subregion.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-scops \
+; RUN:                -analyze < %s | FileCheck %s
+;
+; Check that we do not generate any scalar dependences regarding x. It is
+; defined and used on the non-affine subregion only, thus we do not need
+; to represent the definition and uses in the model.
+;
+; CHECK:          Stmt_bb2__TO__bb11
+; CHECK-NOT:        [Scalar: 1]
+; CHECK-NOT:        MemRef_x
+;
+;    void f(int *A) {
+;      int x;
+;      for (int i = 0; i < 1024; i++) {
+;        if (A[i]) {
+;          if (i > 512)
+;            x = 1;
+;          else
+;            x = 2;
+;          A[i] = x;
+;        }
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb12, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb12 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb13
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32,  i32* %tmp, align 4
+  %tmp4 = icmp eq i32 %tmp3, 0
+  br i1 %tmp4, label %bb11, label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = icmp sgt i64 %indvars.iv, 512
+  br i1 %tmp6, label %bb7, label %bb8
+
+bb7:                                              ; preds = %bb5
+  br label %bb9
+
+bb8:                                              ; preds = %bb5
+  br label %bb9
+
+bb9:                                              ; preds = %bb8, %bb7
+  %x.0 = phi i32 [ 1, %bb7 ], [ 2, %bb8 ]
+  %tmp10 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %x.0, i32* %tmp10, align 4
+  br label %bb11
+
+bb11:                                             ; preds = %bb2, %bb9
+  br label %bb12
+
+bb12:                                             ; preds = %bb11
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb13:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/non-affine-region-phi.ll b/final/test/ScopInfo/non-affine-region-phi.ll
new file mode 100644
index 0000000..ae2e6c4
--- /dev/null
+++ b/final/test/ScopInfo/non-affine-region-phi.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-allow-nonaffine -S < %s | FileCheck %s --check-prefix=CODE
+; RUN: opt %loadPolly -polly-allow-nonaffine -polly-scops -analyze < %s | FileCheck %s
+;
+; Verify there is a phi in the non-affine region but it is not represented in
+; the SCoP as all operands as well as the uses are inside the region too.
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++) {
+;        if (A[i]) {
+;          int x = 0;
+;          if (i > 512)
+;            x = 1 + A[i];
+;          A[i] = x;
+;        }
+;      }
+;    }
+;
+; CODE-LABEL: bb11:
+; CODE:         %x.0 = phi i32
+;
+; We have 3 accesses to A that should be present in the SCoP but no scalar access.
+;
+; CHECK-NOT: [Scalar: 1]
+; CHECK:     [Scalar: 0]
+; CHECK-NOT: [Scalar: 1]
+; CHECK:     [Scalar: 0]
+; CHECK-NOT: [Scalar: 1]
+; CHECK:     [Scalar: 0]
+; CHECK-NOT: [Scalar: 1]
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb14, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb14 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb15
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32,  i32* %tmp, align 4
+  %tmp4 = icmp eq i32 %tmp3, 0
+  br i1 %tmp4, label %bb13, label %bb5
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = icmp sgt i64 %indvars.iv, 512
+  br i1 %tmp6, label %bb7, label %bb11
+
+bb7:                                              ; preds = %bb5
+  %tmp8 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp9 = load i32,  i32* %tmp8, align 4
+  %tmp10 = add nsw i32 %tmp9, 1
+  br label %bb11
+
+bb11:                                             ; preds = %bb7, %bb5
+  %x.0 = phi i32 [ %tmp10, %bb7 ], [ 0, %bb5 ]
+  %tmp12 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %x.0, i32* %tmp12, align 4
+  br label %bb13
+
+bb13:                                             ; preds = %bb2, %bb11
+  br label %bb14
+
+bb14:                                             ; preds = %bb13
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb15:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/non-affine-region-with-loop-2.ll b/final/test/ScopInfo/non-affine-region-with-loop-2.ll
new file mode 100644
index 0000000..555c6e1
--- /dev/null
+++ b/final/test/ScopInfo/non-affine-region-with-loop-2.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-allow-nonaffine-loops -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-allow-nonaffine-loops -polly-codegen -analyze
+;
+; CHECK:    Stmt_loop3
+; CHECK:            Domain :=
+; CHECK:                [indvar] -> { Stmt_loop3[0] : indvar >= 101 or indvar <= 99 };
+; CHECK:            Schedule :=
+; CHECK:                [indvar] -> { Stmt_loop3[i0] -> [0, 0] : indvar >= 101 or indvar <= 99 };
+; CHECK:    Stmt_loop2__TO__loop
+; CHECK:            Domain :=
+; CHECK:                [indvar] -> { Stmt_loop2__TO__loop[] : indvar >= 101 or indvar <= 99 };
+; CHECK:            Schedule :=
+; CHECK:                [indvar] -> { Stmt_loop2__TO__loop[] -> [1, 0] : indvar >= 101 or indvar <= 99 };
+;
+define void @foo(i64* %A, i64 %p) {
+entry:
+  br label %loop
+
+loop:
+  %indvar.3 = phi i64 [0, %entry], [%indvar.3, %loop], [%indvar.next.3, %next2], [%indvar.next.3, %cond]
+  %indvar = phi i64 [0, %entry], [%indvar.next, %loop], [0, %next2], [0, %cond]
+  %indvar.next = add i64 %indvar, 1
+  fence seq_cst
+  %cmp = icmp eq i64 %indvar, 100
+  br i1 %cmp, label %next, label %loop
+
+next:
+  %indvar.next.3 = add i64 %indvar.3, 1
+  %cmp.3 = icmp eq i64 %indvar, 100
+  br i1 %cmp.3, label %loop3, label %exit
+
+loop3:
+  %indvar.6 = phi i64 [0, %next], [%indvar.next.6, %loop3]
+  %indvar.next.6 = add i64 %indvar.6, 1
+  %cmp.6 = icmp eq i64 %indvar.6, 100
+  br i1 %cmp.3, label %loop3, label %loop2
+
+loop2:
+  %indvar.2 = phi i64 [0, %loop3], [%indvar.next.2, %loop2], [0, %cond]
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %prod = mul i64 %indvar.2, %indvar.2
+  store i64 %indvar, i64* %A
+  %cmp.2 = icmp eq i64 %prod, 100
+  br i1 %cmp.2, label %loop2, label %next2
+
+next2:
+  %cmp.4 = icmp eq i64 %p, 100
+  br i1 %cmp.4, label %loop, label %cond
+
+cond:
+  br i1 false, label %loop, label %loop2
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/non-affine-region-with-loop.ll b/final/test/ScopInfo/non-affine-region-with-loop.ll
new file mode 100644
index 0000000..a447e09
--- /dev/null
+++ b/final/test/ScopInfo/non-affine-region-with-loop.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-allow-nonaffine-loops -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-allow-nonaffine-loops -polly-codegen -analyze
+;
+; CHECK:      Domain :=
+; CHECK-NEXT:   { Stmt_loop2__TO__loop[] };
+;
+define void @foo(i64* %A, i64 %p) {
+entry:
+  br label %loop
+
+loop:
+  %indvar.3 = phi i64 [0, %entry], [%indvar.3, %loop], [%indvar.next.3, %next2], [%indvar.next.3, %cond]
+  %indvar = phi i64 [0, %entry], [%indvar.next, %loop], [0, %next2], [0, %cond]
+  %indvar.next = add i64 %indvar, 1
+  fence seq_cst
+  %cmp = icmp eq i64 %indvar, 100
+  br i1 %cmp, label %next, label %loop
+
+next:
+  %indvar.next.3 = add i64 %indvar.3, 1
+  %cmp.3 = icmp eq i64 %indvar, 100
+  br i1 %cmp.3, label %loop2, label %exit
+
+loop2:
+  %indvar.2 = phi i64 [0, %next], [%indvar.next.2, %loop2], [0, %cond]
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %prod = mul i64 %indvar.2, %indvar.2
+  store i64 %indvar, i64* %A
+  %cmp.2 = icmp eq i64 %prod, 100
+  br i1 %cmp.2, label %loop2, label %next2
+
+next2:
+  %cmp.4 = icmp eq i64 %p, 100
+  br i1 %cmp.4, label %loop, label %cond
+
+cond:
+  br i1 false, label %loop, label %loop2
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/non-precise-inv-load-1.ll b/final/test/ScopInfo/non-precise-inv-load-1.ll
new file mode 100644
index 0000000..fce75be
--- /dev/null
+++ b/final/test/ScopInfo/non-precise-inv-load-1.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; Verify we do hoist the invariant access to I with a execution context
+; as the address computation might wrap in the original but not in our
+; optimized version. For an input of c = 127 the original accessed address
+; would be &I[-1] = &GI[128 -1] = &GI[127] but in our optimized version
+; (due to the usage of i64 types) we would access
+; &I[127 + 1] = &I[128] = &GI[256] which would here also be out-of-bounds.
+;
+; CHECK:        Invariant Accesses: {
+; CHECK-NEXT:     ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       [c] -> { Stmt_for_body[i0] -> MemRef_GI[129 + c] };
+; CHECK-NEXT:     Execution Context: [c] -> {  : c <= 126 }
+; CHECK-NEXT:   }
+;
+;    int GI[256];
+;    void f(int *A, unsigned char c) {
+;      int *I = &GI[128];
+;      for (int i = 0; i < 10; i++)
+;        A[i] += I[(signed char)(c + (unsigned char)1)];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@GI = common global [256 x i32] zeroinitializer, align 16
+
+define void @f(i32* %A, i8 zeroext %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 10
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add = add i8 %c, 1
+  %idxprom = sext i8 %add to i64
+  %arrayidx = getelementptr inbounds i32, i32* getelementptr inbounds ([256 x i32], [256 x i32]* @GI, i64 0, i64 128), i64 %idxprom
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx3, align 4
+  %add4 = add nsw i32 %tmp1, %tmp
+  store i32 %add4, i32* %arrayidx3, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/non-precise-inv-load-2.ll b/final/test/ScopInfo/non-precise-inv-load-2.ll
new file mode 100644
index 0000000..014c495
--- /dev/null
+++ b/final/test/ScopInfo/non-precise-inv-load-2.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+;
+; CHECK:       Invariant Accesses: {
+; CHECK-NEXT:    ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:    [c] -> { Stmt_for_body[i0] -> MemRef_I[-1 + c] };
+; CHECK-NEXT:    Execution Context: [c] -> {  : c > 0 }
+; CHECK-NEXT:  }
+; CHECK-NEXT:  Context:
+; CHECK-NEXT:  [c] -> {  : -128 <= c <= 127 }
+; CHECK-NEXT:  Assumed Context:
+; CHECK-NEXT:  [c] -> {  :  }
+; CHECK-NEXT:  Invalid Context:
+; CHECK-NEXT:  [c] -> {  : c <= 0 }
+;
+;    void f(int *A, int *I, unsigned char c) {
+;      for (int i = 0; i < 10; i++)
+;        A[i] += I[c - (char)1];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %I, i8 zeroext %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 10
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %sub = add i8 %c, -1
+  %conv = zext i8 %sub to i64
+  %arrayidx = getelementptr inbounds i32, i32* %I, i64 %conv
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx2, align 4
+  %add = add nsw i32 %tmp1, %tmp
+  store i32 %add, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/non-precise-inv-load-3.ll b/final/test/ScopInfo/non-precise-inv-load-3.ll
new file mode 100644
index 0000000..a4dc3da
--- /dev/null
+++ b/final/test/ScopInfo/non-precise-inv-load-3.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; CHECK:        Invariant Accesses: {
+; CHECK-NEXT:     ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       [c] -> { Stmt_if_then[i0] -> MemRef_I[0] };
+; CHECK-NEXT:     Execution Context: [c] -> {  : 0 <= c <= 126 }
+; CHECK-NEXT:   }
+;
+;    void f(int *A, unsigned char c, int *I) {
+;      for (int i = 0; i < 10; i++)
+;        if ((signed char)(c + (unsigned char)1) > 0)
+;          A[i] += I[0];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i8 zeroext %c, i32* %I) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 10
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add = add i8 %c, 1
+  %cmp3 = icmp sgt i8 %add, 0
+  br i1 %cmp3, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %tmp = load i32, i32* %I, align 4
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx5, align 4
+  %add6 = add nsw i32 %tmp1, %tmp
+  store i32 %add6, i32* %arrayidx5, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/non-precise-inv-load-4.ll b/final/test/ScopInfo/non-precise-inv-load-4.ll
new file mode 100644
index 0000000..618ac89
--- /dev/null
+++ b/final/test/ScopInfo/non-precise-inv-load-4.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; Verify we hoist I[0] without execution context even though it
+; is executed in a statement with an invalid domain.
+;
+; CHECK:         Invariant Accesses: {
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [c] -> { Stmt_if_then[i0] -> MemRef_I[0] };
+; CHECK-NEXT:            Execution Context: [c] -> {  :  }
+; CHECK-NEXT:    }
+;
+;    int I[1];
+;    void f(int *A, unsigned char c) {
+;      for (int i = 0; i < 10; i++)
+;        if ((signed char)(c + (unsigned char)1) > 0)
+;          A[i] += I[0];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@I = common global [1 x i32] zeroinitializer, align 4
+
+define void @f(i32* %A, i8 zeroext %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 10
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add = add i8 %c, 1
+  %cmp3 = icmp sgt i8 %add, 0
+  br i1 %cmp3, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %tmp = load i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @I, i64 0, i64 0), align 4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %add5 = add nsw i32 %tmp1, %tmp
+  store i32 %add5, i32* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/non-precise-inv-load-5.ll b/final/test/ScopInfo/non-precise-inv-load-5.ll
new file mode 100644
index 0000000..886d1b1
--- /dev/null
+++ b/final/test/ScopInfo/non-precise-inv-load-5.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; Verify we do not hoist I[c] without execution context because it
+; is executed in a statement with an invalid domain and it depends
+; on a parameter that was specialized by the domain.
+;
+; CHECK:         Invariant Accesses: {
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [c] -> { Stmt_if_then[i0] -> MemRef_I[-129] };
+; CHECK-NEXT:            Execution Context: [c] -> {  : 1 = 0 }
+; CHECK-NEXT:    }
+;
+; TODO: FIXME: We should remove the statement as it has an empty domain.
+; CHECK:      Stmt_if_then
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT: [c] -> { Stmt_if_then[i0] : 1 = 0 };
+;
+;    int I[1024];
+;    void f(int *A, unsigned char c) {
+;      for (int i = 0; i < 10; i++)
+;        if ((signed char)(c + (unsigned char)1) == 127)
+;          A[i] += I[c];
+;        else
+;          A[i] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@I = common global [1024 x i32] zeroinitializer, align 16
+
+define void @f(i32* %A, i8 zeroext %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 10
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add = add i8 %c, 1
+  %cmp3 = icmp eq i8 %add, 128
+  %arrayidx6 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  br i1 %cmp3, label %if.then, label %if.else
+
+if.then:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds [1024 x i32], [1024 x i32]* @I, i64 0, i8 %c
+  %tmp = load i32, i32* %arrayidx, align 4
+  %tmp1 = load i32, i32* %arrayidx6, align 4
+  %add7 = add nsw i32 %tmp1, %tmp
+  store i32 %add7, i32* %arrayidx6, align 4
+  br label %for.inc
+
+if.else:                                           ; preds = %if.then, %for.body
+  store i32 0, i32* %arrayidx6, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.else, if.then
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/non-precise-inv-load-6.ll b/final/test/ScopInfo/non-precise-inv-load-6.ll
new file mode 100644
index 0000000..0af9d74
--- /dev/null
+++ b/final/test/ScopInfo/non-precise-inv-load-6.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; Check that we model the execution context correctly.
+;
+;    void f(unsigned *I, unsigned *A, int c) {
+;      for (unsigned i = c; i < 10; i++)
+;        A[i] += *I;
+;    }
+;
+; CHECK:         Invariant Accesses: {
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [c] -> { Stmt_for_body[i0] -> MemRef_I[0] };
+; CHECK-NEXT:            Execution Context: [c] -> {  : 0 <= c <= 9 }
+; CHECK-NEXT:    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %I, i32* %A, i64 %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ %c, %entry ]
+  %exitcond = icmp ult i64 %indvars.iv, 10
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = load i32, i32* %I, align 4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %add = add i32 %tmp1, %tmp
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/non-pure-function-call.ll b/final/test/ScopInfo/non-pure-function-call.ll
new file mode 100644
index 0000000..d45b7e8
--- /dev/null
+++ b/final/test/ScopInfo/non-pure-function-call.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK:      Assumed Context:
+; CHECK-NEXT:   [N] -> {  :  }
+; CHECK:      Invalid Context:
+; CHECK-NEXT:   [N] -> {  : N >= 102 }
+;
+;    void g(void);
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++) {
+;        if (i > 100)
+;          g();
+;        A[i]++;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %cmp1 = icmp sgt i64 %indvars.iv, 100
+  br i1 %cmp1, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  call void @g() #2
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp1, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare void @g()
diff --git a/final/test/ScopInfo/non-pure-function-calls-causes-dead-blocks.ll b/final/test/ScopInfo/non-pure-function-calls-causes-dead-blocks.ll
new file mode 100644
index 0000000..fcc403e
--- /dev/null
+++ b/final/test/ScopInfo/non-pure-function-calls-causes-dead-blocks.ll
@@ -0,0 +1,137 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Error blocks are skipped during SCoP detection. We skip them during
+; SCoP formation too as they might contain instructions we can not handle.
+; However statements / basic blocks that follow error blocks are modeled.
+;
+;    void timer_start(void);
+;    void timer_stop(void);
+;    void kernel(int *A, int *B, int timeit, int N) {
+;
+;      if (timeit) {
+;        timer_start();
+;        // split BB
+;        A[0] = 0;                 // Do not create a statement for this block
+;      }
+;
+;      for (int i = 0; i < N; i++)
+;        A[i] += B[i];
+;
+;      if (timeit) {
+;        timer_stop();
+;        if (invalid float branch) // Do not crash on the float branch
+;          timer_start();
+;      }
+;
+;      for (int i = 0; i < N; i++)
+;        A[i] += B[i];
+;
+;      if (timeit)
+;        timer_stop();
+;    }
+;
+;  The assumed context should not be empty even though all statements are
+;  executed only if timeit != 0.
+;
+; CHECK:    Region: %entry.split---%if.end.20
+; CHECK:    Assumed Context:
+; CHECK-NEXT:    [timeit, N] -> { : }
+; CHECK:    Invalid Context:
+; CHECK-NEXT:    [timeit, N] -> { : timeit < 0 or timeit > 0 }
+; CHECK:    Statements {
+; CHECK-NOT:      Stmt_if_then_split
+; CHECK:      Stmt_for_body
+; CHECK:      Stmt_for_body_9
+; CHECK:    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @kernel(i32* %A, i32* %B, i32 %timeit, i32 %N) {
+entry:
+  br label %entry.split
+
+entry.split:
+  %tobool = icmp eq i32 %timeit, 0
+  br i1 %tobool, label %for.cond.pre, label %if.then
+
+if.then:                                          ; preds = %entry
+  call void @timer_start()
+  br label %if.then.split
+
+; Dead block if we assume if.then not to be executed because of the call
+if.then.split:                                           ; preds = %if.then
+  %A0 = getelementptr inbounds i32, i32* %A, i64 0
+  store i32 0, i32* %A0, align 4
+  br label %for.cond.pre
+
+for.cond.pre:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %if.end
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc ], [ 0, %for.cond.pre ]
+  %cmp = icmp slt i64 %indvars.iv1, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv1
+  %tmp3 = load i32, i32* %arrayidx, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv1
+  %tmp4 = load i32, i32* %arrayidx2, align 4
+  %add = add nsw i32 %tmp4, %tmp3
+  store i32 %add, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  %tobool3 = icmp eq i32 %timeit, 0
+  br i1 %tobool3, label %if.end.5, label %if.then.4
+
+if.then.4:                                        ; preds = %for.end
+  call void @timer_stop()
+  %na = fcmp one float 4.0, 5.0
+  br i1 %na, label %if.end.5, label %if.then.4.rem
+
+if.then.4.rem:                                        ; preds = %for.end
+  call void @timer_start()
+  br label %if.end.5
+
+if.end.5:                                         ; preds = %for.end, %if.then.4
+  %tmp5 = sext i32 %N to i64
+  br label %for.cond.7
+
+for.cond.7:                                       ; preds = %for.inc.15, %if.end.5
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc.15 ], [ 0, %if.end.5 ]
+  %cmp8 = icmp slt i64 %indvars.iv, %tmp5
+  br i1 %cmp8, label %for.body.9, label %for.end.17
+
+for.body.9:                                       ; preds = %for.cond.7
+  %arrayidx11 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  %tmp6 = load i32, i32* %arrayidx11, align 4
+  %arrayidx13 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp7 = load i32, i32* %arrayidx13, align 4
+  %add14 = add nsw i32 %tmp7, %tmp6
+  store i32 %add14, i32* %arrayidx13, align 4
+  br label %for.inc.15
+
+for.inc.15:                                       ; preds = %for.body.9
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond.7
+
+for.end.17:                                       ; preds = %for.cond.7
+  %tobool18 = icmp eq i32 %timeit, 0
+  br i1 %tobool18, label %if.end.20, label %if.then.19
+
+if.then.19:                                       ; preds = %for.end.17
+  call void @timer_stop()
+  br label %if.end.20
+
+if.end.20:                                        ; preds = %for.end.17, %if.then.19
+  ret void
+}
+
+declare void @timer_start()
+declare void @timer_stop()
diff --git a/final/test/ScopInfo/non-pure-function-calls.ll b/final/test/ScopInfo/non-pure-function-calls.ll
new file mode 100644
index 0000000..f8a7612
--- /dev/null
+++ b/final/test/ScopInfo/non-pure-function-calls.ll
@@ -0,0 +1,116 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Allow the user to define function names that are treated as
+; error functions and assumed not to be executed.
+;
+;    void timer_start(void);
+;    void timer_stop(void);
+;    void kernel(int *A, int *B, int timeit, int N) {
+;
+;      if (timeit)
+;        timer_start();
+;
+;      for (int i = 0; i < N; i++)
+;        A[i] += B[i];
+;
+;      if (timeit) {
+;        timer_stop();
+;        timer_start();
+;      }
+;
+;      for (int i = 0; i < N; i++)
+;        A[i] += B[i];
+;
+;      if (timeit)
+;        timer_stop();
+;    }
+;
+; CHECK:      Region: %for.cond---%if.end.20
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [N, timeit] -> {  :  }
+; CHECK:      Invalid Context:
+; CHECK-NEXT: [N, timeit] -> {  : timeit < 0 or timeit > 0 }
+; CHECK:      Statements {
+; CHECK:        Stmt
+; CHECK:        Stmt
+; CHECK-NOT:    Stmt
+; CHECK:      }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @kernel(i32* %A, i32* %B, i32 %timeit, i32 %N) {
+entry:
+  %tobool = icmp eq i32 %timeit, 0
+  br i1 %tobool, label %if.end, label %if.then
+
+if.then:                                          ; preds = %entry
+  call void @timer_start()
+  br label %if.end
+
+if.end:                                           ; preds = %entry, %if.then
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %if.end
+  %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc ], [ 0, %if.end ]
+  %cmp = icmp slt i64 %indvars.iv1, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv1
+  %tmp3 = load i32, i32* %arrayidx, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv1
+  %tmp4 = load i32, i32* %arrayidx2, align 4
+  %add = add nsw i32 %tmp4, %tmp3
+  store i32 %add, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  %tobool3 = icmp eq i32 %timeit, 0
+  br i1 %tobool3, label %if.end.5, label %if.then.4
+
+if.then.4:                                        ; preds = %for.end
+  call void @timer_stop()
+  call void @timer_start()
+  br label %if.end.5
+
+if.end.5:                                         ; preds = %for.end, %if.then.4
+  %tmp5 = sext i32 %N to i64
+  br label %for.cond.7
+
+for.cond.7:                                       ; preds = %for.inc.15, %if.end.5
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc.15 ], [ 0, %if.end.5 ]
+  %cmp8 = icmp slt i64 %indvars.iv, %tmp5
+  br i1 %cmp8, label %for.body.9, label %for.end.17
+
+for.body.9:                                       ; preds = %for.cond.7
+  %arrayidx11 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  %tmp6 = load i32, i32* %arrayidx11, align 4
+  %arrayidx13 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp7 = load i32, i32* %arrayidx13, align 4
+  %add14 = add nsw i32 %tmp7, %tmp6
+  store i32 %add14, i32* %arrayidx13, align 4
+  br label %for.inc.15
+
+for.inc.15:                                       ; preds = %for.body.9
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond.7
+
+for.end.17:                                       ; preds = %for.cond.7
+  %tobool18 = icmp eq i32 %timeit, 0
+  br i1 %tobool18, label %if.end.20, label %if.then.19
+
+if.then.19:                                       ; preds = %for.end.17
+  call void @timer_stop()
+  br label %if.end.20
+
+if.end.20:                                        ; preds = %for.end.17, %if.then.19
+  ret void
+}
+
+declare void @timer_start()
+declare void @timer_stop()
diff --git a/final/test/ScopInfo/non_affine_access.ll b/final/test/ScopInfo/non_affine_access.ll
new file mode 100644
index 0000000..26a4b38
--- /dev/null
+++ b/final/test/ScopInfo/non_affine_access.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s -check-prefix=NONAFFINE
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s -check-prefix=NONAFFINE
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; void foo(long *A) {
+;   for (i = 0; i < 1024; i++)
+;     A[i * i] = i;
+;
+
+define void @foo(i64 *%A) nounwind uwtable ssp {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %indvar = phi i64 [ 0, %entry.split ], [ %indvar.next, %for.body ]
+  %mul = mul nsw i64 %indvar, %indvar
+  %arrayidx = getelementptr inbounds i64, i64* %A, i64 %mul
+  store i64 %indvar, i64* %arrayidx, align 4
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp ne i64 %indvar.next, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body
+  ret void
+}
+
+; CHECK-NOT: Stmt_for_body
+; NONAFFINE: { Stmt_for_body[i0] -> MemRef_A[o0] };
diff --git a/final/test/ScopInfo/non_affine_region_1.ll b/final/test/ScopInfo/non_affine_region_1.ll
new file mode 100644
index 0000000..a178129
--- /dev/null
+++ b/final/test/ScopInfo/non_affine_region_1.ll
@@ -0,0 +1,108 @@
+; RUN: opt %loadPolly -polly-allow-nonaffine -polly-scops -analyze < %s | FileCheck %s
+;
+; Verify only the incoming scalar x is modeled as a read in the non-affine
+; region.
+;
+;    void f(int *A, int b) {
+;      int x;
+;      for (int i = 0; i < 1024; i++) {
+;        if (b > i)
+;          x = 0;
+;        else if (b < 2 * i)
+;          x = 3;
+;        else
+;          x = b;
+;
+;        if (A[x])
+;          A[x] = 0;
+;      }
+;    }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb3
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [b] -> { Stmt_bb3[i0] : 0 <= i0 <= 1023 and i0 < b };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [b] -> { Stmt_bb3[i0] -> [i0, 2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [b] -> { Stmt_bb3[i0] -> MemRef_x_1__phi[] };
+; CHECK-NEXT:     Stmt_bb7
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [b] -> { Stmt_bb7[i0] : i0 >= b and 0 <= i0 <= 1023 and 2i0 > b };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [b] -> { Stmt_bb7[i0] -> [i0, 1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [b] -> { Stmt_bb7[i0] -> MemRef_x_1__phi[] };
+; CHECK-NEXT:     Stmt_bb8
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [b] -> { Stmt_bb8[0] : b = 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [b] -> { Stmt_bb8[i0] -> [0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [b] -> { Stmt_bb8[i0] -> MemRef_x_1__phi[] };
+; CHECK-NEXT:     Stmt_bb10__TO__bb18
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [b] -> { Stmt_bb10__TO__bb18[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [b] -> { Stmt_bb10__TO__bb18[i0] -> [i0, 3] }
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [b] -> { Stmt_bb10__TO__bb18[i0] -> MemRef_x_1__phi[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [b] -> { Stmt_bb10__TO__bb18[i0] -> MemRef_A[o0] };
+; CHECK-NEXT:         MayWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [b] -> { Stmt_bb10__TO__bb18[i0] -> MemRef_A[o0] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb19, %bb
+  %i.0 = phi i32 [ 0, %bb ], [ %tmp20, %bb19 ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb21
+
+bb2:                                              ; preds = %bb1
+  %tmp = icmp slt i32 %i.0, %b
+  br i1 %tmp, label %bb3, label %bb4
+
+bb3:                                              ; preds = %bb2
+  br label %bb10
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = mul nsw i32 %i.0, 2
+  %tmp6 = icmp sgt i32 %tmp5, %b
+  br i1 %tmp6, label %bb7, label %bb8
+
+bb7:                                              ; preds = %bb4
+  br label %bb10
+
+bb8:                                              ; preds = %bb4
+  br label %bb10
+
+bb10:                                             ; preds = %bb9, %bb3
+  %x.1 = phi i32 [ 0, %bb3 ], [ 3, %bb7 ], [ %b, %bb8 ]
+  %tmp11 = sext i32 %x.1 to i64
+  %tmp12 = getelementptr inbounds i32, i32* %A, i64 %tmp11
+  %tmp13 = load i32,  i32* %tmp12, align 4
+  %tmp14 = icmp eq i32 %tmp13, 0
+  br i1 %tmp14, label %bb18, label %bb15
+
+bb15:                                             ; preds = %bb10
+  %tmp16 = sext i32 %x.1 to i64
+  %tmp17 = getelementptr inbounds i32, i32* %A, i64 %tmp16
+  store i32 0, i32* %tmp17, align 4
+  br label %bb18
+
+bb18:                                             ; preds = %bb10, %bb15
+  br label %bb19
+
+bb19:                                             ; preds = %bb18
+  %tmp20 = add nuw nsw i32 %i.0, 1
+  br label %bb1
+
+bb21:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/non_affine_region_2.ll b/final/test/ScopInfo/non_affine_region_2.ll
new file mode 100644
index 0000000..10b801f
--- /dev/null
+++ b/final/test/ScopInfo/non_affine_region_2.ll
@@ -0,0 +1,103 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Verify the scalar x defined in a non-affine subregion is written as it
+; escapes the region. In this test the two conditionals inside the region
+; are expressed as two PHI nodes with two incoming values each.
+;
+;    void f(int *A, int b) {
+;      for (int i = 0; i < 1024; i++) {
+;        int x = 0;
+;        if (A[i]) {
+;          if (b > i)
+;            x = 0;
+;          else if (b < 2 * i)
+;            x = i;
+;          else
+;            x = b;
+;        }
+;        A[i] = x;
+;      }
+;    }
+
+; CHECK-LABEL: Region: %bb2---%bb21
+;
+; CHECK:       Statements {
+; CHECK-NEXT:      Stmt_bb3__TO__bb18
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              { Stmt_bb3__TO__bb18[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              { Stmt_bb3__TO__bb18[i0] -> [i0, 0] };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              { Stmt_bb3__TO__bb18[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_bb3__TO__bb18[i0] -> MemRef_x_2__phi[] };
+; CHECK-NEXT:      Stmt_bb18
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              { Stmt_bb18[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              { Stmt_bb18[i0] -> [i0, 1] };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_bb18[i0] -> MemRef_x_2__phi[] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              { Stmt_bb18[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:  }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %b) {
+bb:
+  %tmp = sext i32 %b to i64
+  %tmp1 = sext i32 %b to i64
+  br label %bb2
+
+bb2:                                              ; preds = %bb20, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb20 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb3, label %bb21
+
+bb3:                                              ; preds = %bb2
+  %tmp4 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp5 = load i32,  i32* %tmp4, align 4
+  %tmp6 = icmp eq i32 %tmp5, 0
+  br i1 %tmp6, label %bb18, label %bb7
+
+bb7:                                              ; preds = %bb3
+  %tmp8 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp8, label %bb9, label %bb10
+
+bb9:                                              ; preds = %bb7
+  br label %bb17
+
+bb10:                                             ; preds = %bb7
+  %tmp11 = shl nsw i64 %indvars.iv, 1
+  %tmp12 = icmp sgt i64 %tmp11, %tmp1
+  br i1 %tmp12, label %bb13, label %bb15
+
+bb13:                                             ; preds = %bb10
+  %tmp14 = trunc i64 %indvars.iv to i32
+  br label %bb16
+
+bb15:                                             ; preds = %bb10
+  br label %bb16
+
+bb16:                                             ; preds = %bb15, %bb13
+  %x.0 = phi i32 [ %tmp14, %bb13 ], [ %b, %bb15 ]
+  br label %bb17
+
+bb17:                                             ; preds = %bb16, %bb9
+  %x.1 = phi i32 [ 0, %bb9 ], [ %x.0, %bb16 ]
+  br label %bb18
+
+bb18:                                             ; preds = %bb3, %bb17
+  %x.2 = phi i32 [ %x.1, %bb17 ], [ 0, %bb3 ]
+  %tmp19 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %x.2, i32* %tmp19, align 4
+  br label %bb20
+
+bb20:                                             ; preds = %bb18
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb2
+
+bb21:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/ScopInfo/non_affine_region_3.ll b/final/test/ScopInfo/non_affine_region_3.ll
new file mode 100644
index 0000000..e284c12
--- /dev/null
+++ b/final/test/ScopInfo/non_affine_region_3.ll
@@ -0,0 +1,96 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-function-scops -analyze < %s | FileCheck %s
+;
+; Verify the scalar x defined in a non-affine subregion is written as it
+; escapes the region. In this test the two conditionals inside the region
+; are expressed as one PHI nodes with three incoming values.
+;
+;    void f(int *A, int b) {
+;      for (int i = 0; i < 1024; i++) {
+;        int x = 0;
+;        if (A[i]) {
+;          if (b > i)
+;            x = 0;
+;          else if (b < 2 * i)
+;            x = i;
+;          else
+;            x = b;
+;        }
+;        A[i] = x;
+;      }
+;    }
+
+; CHECK-LABEL: Region: %bb2---%bb21
+;
+; CHECK:       Statements {
+; CHECK-NEXT:      Stmt_bb3__TO__bb18
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              { Stmt_bb3__TO__bb18[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              { Stmt_bb3__TO__bb18[i0] -> [i0, 0] };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              { Stmt_bb3__TO__bb18[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_bb3__TO__bb18[i0] -> MemRef_x_2__phi[] };
+; CHECK-NEXT:      Stmt_bb18
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              { Stmt_bb18[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              { Stmt_bb18[i0] -> [i0, 1] };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_bb18[i0] -> MemRef_x_2__phi[] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              { Stmt_bb18[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:  }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %b) {
+bb:
+  %tmp = sext i32 %b to i64
+  %tmp1 = sext i32 %b to i64
+  br label %bb2
+
+bb2:                                              ; preds = %bb20, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb20 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb3, label %bb21
+
+bb3:                                              ; preds = %bb2
+  %tmp4 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp5 = load i32,  i32* %tmp4, align 4
+  %tmp6 = icmp eq i32 %tmp5, 0
+  br i1 %tmp6, label %bb18, label %bb7
+
+bb7:                                              ; preds = %bb3
+  %tmp8 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp8, label %bb9, label %bb10
+
+bb9:                                              ; preds = %bb7
+  br label %bb18
+
+bb10:                                             ; preds = %bb7
+  %tmp11 = shl nsw i64 %indvars.iv, 1
+  %tmp12 = icmp sgt i64 %tmp11, %tmp1
+  br i1 %tmp12, label %bb13, label %bb15
+
+bb13:                                             ; preds = %bb10
+  %tmp14 = trunc i64 %indvars.iv to i32
+  br label %bb18
+
+bb15:                                             ; preds = %bb10
+  br label %bb18
+
+bb18:                                             ; preds = %bb3, %bb13, %bb15, %bb9
+  %x.2 = phi i32 [ 0, %bb9 ], [ %tmp14, %bb13 ], [ %b, %bb15 ], [ 0, %bb3 ]
+  %tmp19 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %x.2, i32* %tmp19, align 4
+  br label %bb20
+
+bb20:                                             ; preds = %bb18
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb2
+
+bb21:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/ScopInfo/non_affine_region_4.ll b/final/test/ScopInfo/non_affine_region_4.ll
new file mode 100644
index 0000000..261cda3
--- /dev/null
+++ b/final/test/ScopInfo/non_affine_region_4.ll
@@ -0,0 +1,89 @@
+; RUN: opt %loadPolly -polly-scops  -analyze < %s | FileCheck %s
+;
+; Verify that both scalars (x and y) are properly written in the non-affine
+; region and read afterwards.
+;
+;    void f(int *A, int b) {
+;      for (int i = 0; i < 1024; i++) {
+;        int x = 0, y = 0;
+;        if ((x = 1 + A[i]))
+;          y++;
+;        A[i] = x + y;
+;      }
+;    }
+
+; CHECK-LABEL: Region: %bb1---%bb11
+;
+; CHECK:       Arrays {
+; CHECK-NEXT:      i32 MemRef_A[*]; // Element size 4
+; CHECK-NEXT:      i32 MemRef_y__phi; // Element size 4
+; CHECK-NEXT:      i32 MemRef_x; // Element size 4
+; CHECK-NEXT:  }
+;
+; CHECK:       Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:      i32 MemRef_A[*]; // Element size 4
+; CHECK-NEXT:      i32 MemRef_y__phi; // Element size 4
+; CHECK-NEXT:      i32 MemRef_x; // Element size 4
+; CHECK-NEXT:  }
+;
+; CHECK:       Statements {
+; CHECK-NEXT:      Stmt_bb2__TO__bb7
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              { Stmt_bb2__TO__bb7[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              { Stmt_bb2__TO__bb7[i0] -> [i0, 0] };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              { Stmt_bb2__TO__bb7[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_bb2__TO__bb7[i0] -> MemRef_y__phi[] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_bb2__TO__bb7[i0] -> MemRef_x[] };
+; CHECK-NEXT:      Stmt_bb7
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              { Stmt_bb7[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              { Stmt_bb7[i0] -> [i0, 1] };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_bb7[i0] -> MemRef_y__phi[] };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              { Stmt_bb7[i0] -> MemRef_x[] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              { Stmt_bb7[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:  }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb10, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb10 ], [ 0, %bb ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %bb2, label %bb11
+
+bb2:                                              ; preds = %bb1
+  %tmp = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %x = load i32,  i32* %tmp, align 4
+  %tmp4 = add nsw i32 %x, 1
+  %tmp5 = icmp eq i32 %tmp4, 0
+  br i1 %tmp5, label %bb7, label %bb6
+
+bb6:                                              ; preds = %bb2
+  br label %bb7
+
+bb7:                                              ; preds = %bb2, %bb6
+  %y = phi i32 [ 1, %bb6 ], [ 0, %bb2 ]
+  %tmp4copy = add nsw i32 %x, 1
+  %tmp8 = add nsw i32 %tmp4copy, %y
+  %tmp9 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp8, i32* %tmp9, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb7
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb11:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/nonaffine-buildMemoryAccess.ll b/final/test/ScopInfo/nonaffine-buildMemoryAccess.ll
new file mode 100644
index 0000000..a8c143f
--- /dev/null
+++ b/final/test/ScopInfo/nonaffine-buildMemoryAccess.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-allow-nonaffine-loops -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK:      Domain :=
+; CHECK-NEXT:   { Stmt_while_cond_i__TO__while_end_i[] };
+;
+define i32 @func(i32 %param0, i32 %param1, i64* %param2) #3 {
+
+entry:
+  %var0 = alloca i32
+  %var1 = alloca i32
+  br label %while.cond.i
+
+while.cond.i:                                     ; preds = %while.cond.i.backedge, %entry
+  %var2 = phi i32 [ %param0, %entry ], [ %var3, %while.cond.i.backedge ]
+  %var3 = add nsw i32 %var2, 1
+  %var4 = icmp slt i32 %var2, -1
+  br i1 %var4, label %while.cond.i.backedge, label %if.end.i1.i
+
+if.end.i1.i:                                    ; preds = %while.cond.i
+  %var5 = sdiv i32 %var3, 64
+  %var6 = icmp sgt i32 %param1, %var5
+  br i1 %var6, label %exit1.i, label %while.cond.i.backedge
+
+exit1.i:                          ; preds = %if.end.i1.i
+  %var7 = srem i32 %var3, 64
+  %var8 = sext i32 %var5 to i64
+  %var9 = getelementptr inbounds i64, i64* %param2, i64 %var8
+  %var10 = load i64, i64* %var9, align 8
+  %var11 = zext i32 %var7 to i64
+  %var12 = shl i64 1, %var11
+  %var13 = and i64 %var10, %var12
+  %var14 = icmp eq i64 %var13, 0
+  store i32 %var2, i32* %var1
+  store i32 %var3, i32* %var0
+  br i1 %var14, label %while.cond.i.backedge, label %while.end.i
+
+while.cond.i.backedge:                            ; preds = %exit1.i, %while.cond.i, %if.end.i1.i
+  br label %while.cond.i
+
+while.end.i:
+  %var15 = load i32, i32* %var0
+  %var16 = load i32, i32* %var1
+  %var17 = add i32 %var15, %var16
+  ret i32 %var17
+}
diff --git a/final/test/ScopInfo/not-a-reduction.ll b/final/test/ScopInfo/not-a-reduction.ll
new file mode 100644
index 0000000..e087a39
--- /dev/null
+++ b/final/test/ScopInfo/not-a-reduction.ll
@@ -0,0 +1,51 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s 2>&1 | not FileCheck %s
+
+;#define TYPE float
+;#define NUM 4
+;
+;TYPE A[NUM];
+;TYPE B[NUM];
+;TYPE C[NUM];
+;
+;void vector_multiply(void) {
+;	int i;
+;	for (i = 0; i < NUM; i++) {
+;		A[i] = B[i] * C[i];
+;	}
+;}
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@B = common global [4 x float] zeroinitializer, align 16
+@C = common global [4 x float] zeroinitializer, align 16
+@A = common global [4 x float] zeroinitializer, align 16
+
+define void @vector_multiply() nounwind {
+bb:
+  br label %bb3
+
+bb3:                                              ; preds = %bb7, %bb
+  %indvar = phi i64 [ %indvar.next, %bb7 ], [ 0, %bb ]
+  %scevgep = getelementptr [4 x float], [4 x float]* @A, i64 0, i64 %indvar
+  %scevgep1 = getelementptr [4 x float], [4 x float]* @C, i64 0, i64 %indvar
+  %scevgep2 = getelementptr [4 x float], [4 x float]* @B, i64 0, i64 %indvar
+  %exitcond = icmp ne i64 %indvar, 4
+  br i1 %exitcond, label %bb4, label %bb8
+
+bb4:                                              ; preds = %bb3
+  %tmp = load float, float* %scevgep2, align 4
+  %tmp5 = load float, float* %scevgep1, align 4
+  %tmp6 = fmul float %tmp, %tmp5
+  store float %tmp6, float* %scevgep, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb4
+  %indvar.next = add i64 %indvar, 1
+  br label %bb3
+
+bb8:                                              ; preds = %bb3
+  ret void
+}
+
+; Match any reduction type except "[Reduction Type: NONE]"
+; CHECK:     [Reduction Type: {{[^N].*}}]
diff --git a/final/test/ScopInfo/opaque-struct.ll b/final/test/ScopInfo/opaque-struct.ll
new file mode 100644
index 0000000..2d6a66f
--- /dev/null
+++ b/final/test/ScopInfo/opaque-struct.ll
@@ -0,0 +1,25 @@
+; RUN: opt %loadPolly -polly-scops -disable-output < %s 
+;
+; Check that we do not crash with unsized (opaque) types.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.s3 = type opaque
+%struct.stmt = type opaque
+
+; Function Attrs: nounwind uwtable
+define void @columnMem(%struct.stmt* %pStmt) #0 {
+entry:
+  br label %if.else
+
+if.else:                                          ; preds = %entry
+  %db = bitcast %struct.stmt* %pStmt to %struct.s3**
+  %0 = load %struct.s3*, %struct.s3** %db, align 8
+  br i1 false, label %if.end9, label %if.then7
+
+if.then7:                                         ; preds = %if.else
+  br label %if.end9
+
+if.end9:                                          ; preds = %if.then7, %if.else
+  ret void
+}
diff --git a/final/test/ScopInfo/out-of-scop-use-in-region-entry-phi-node-nonaffine-subregion.ll b/final/test/ScopInfo/out-of-scop-use-in-region-entry-phi-node-nonaffine-subregion.ll
new file mode 100644
index 0000000..8bd073d
--- /dev/null
+++ b/final/test/ScopInfo/out-of-scop-use-in-region-entry-phi-node-nonaffine-subregion.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s
+;
+; Check whether %newval is identified as escaping value, even though it is used
+; in a phi that is in the region. Non-affine subregion case.
+;
+; CHECK-LABEL: subregion_entry.region_entering:
+; CHECK:         %loop_carried.ph = phi float [ %newval.merge, %backedge ], [ undef, %entry ]
+;
+; CHECK-LABEL: polly.merge_new_and_old:
+; CHECK:         %newval.merge = phi float [ %newval.final_reload, %polly.exiting ], [ %newval, %subregion_exit.region_exiting ]
+;
+; CHECK-LABEL: polly.start:
+; CHECK:         store float %loop_carried.ph, float* %loop_carried.phiops
+;
+; CHECK-LABEL: polly.stmt.subregion_entry.entry:
+; CHECK:         %loop_carried.phiops.reload = load float, float* %loop_carried.phiops
+;
+; CHECK-LABEL: polly.stmt.subregion_entry:
+; CHECK:         %polly.loop_carried = phi float [ %loop_carried.phiops.reload, %polly.stmt.subregion_entry.entry ]
+; CHECK:         %p_newval = fadd float %polly.loop_carried, 1.000000e+00
+;
+; CHECK-LABEL: polly.stmt.polly.merge_new_and_old.exit:
+; CHECK:         %newval.final_reload = load float, float* %newval.s2a
+
+define void @func() {
+entry:
+  br label %subregion_entry
+
+subregion_entry:
+  %loop_carried = phi float [ undef, %entry ], [ %newval, %backedge ]
+  %indvar = phi i32 [ 1, %entry ], [ %indvar_next, %backedge ]
+  %newval = fadd float %loop_carried, 1.0
+  %cmp = fcmp ogt float undef, undef
+  br i1 %cmp, label %subregion_if, label %subregion_exit
+
+subregion_if:
+  br label %subregion_exit
+
+subregion_exit:
+  br i1 undef, label %if_then, label %if_else
+
+if_then:
+  br label %backedge
+
+if_else:
+  br label %backedge
+
+backedge:
+  %indvar_next = add nuw nsw i32 %indvar, 1
+  br i1 false, label %subregion_entry, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/out-of-scop-use-in-region-entry-phi-node.ll b/final/test/ScopInfo/out-of-scop-use-in-region-entry-phi-node.ll
new file mode 100644
index 0000000..9491400
--- /dev/null
+++ b/final/test/ScopInfo/out-of-scop-use-in-region-entry-phi-node.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; CHECK: MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT: [p_0] -> { Stmt_bb3[] -> MemRef_tmp5[] };
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @hoge() {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb
+  %tmp = load i64*, i64** undef
+  br label %bb3
+
+bb3:                                              ; preds = %bb9, %bb2
+  %tmp4 = phi i64* [ %tmp, %bb2 ], [ %tmp5, %bb9 ]
+  %tmp5 = getelementptr inbounds i64, i64* %tmp4, i64 1
+  %tmp6 = load i64, i64* %tmp5
+  %tmp7 = and i64 %tmp6, 4160749568
+  br i1 false, label %bb8, label %bb9
+
+bb8:                                              ; preds = %bb3
+  br label %bb9
+
+bb9:                                              ; preds = %bb8, %bb3
+  %tmp10 = icmp eq i64 %tmp7, 134217728
+  br i1 %tmp10, label %bb11, label %bb3
+
+bb11:                                             ; preds = %bb9
+  br label %bb12
+
+bb12:                                             ; preds = %bb11
+  ret void
+}
diff --git a/final/test/ScopInfo/parameter-constant-division.ll b/final/test/ScopInfo/parameter-constant-division.ll
new file mode 100644
index 0000000..28a823b
--- /dev/null
+++ b/final/test/ScopInfo/parameter-constant-division.ll
@@ -0,0 +1,94 @@
+; RUN: opt %loadPolly -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true \
+; RUN: -analyze -S < %s | FileCheck %s
+;
+; CHECK:          Invariant Accesses: {
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_land_lhs_true563[] -> MemRef_tmp0[809] };
+; CHECK-NEXT:            Execution Context: {  :  }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_if_then570[] -> MemRef_fs[5] };
+; CHECK-NEXT:            Execution Context: {  :  }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_if_then570[] -> MemRef_fs[7] };
+; CHECK-NEXT:            Execution Context: {  :  }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_if_then570[] -> MemRef_tmp8[813] };
+; CHECK-NEXT:            Execution Context: {  :  }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_if_then570[] -> MemRef_tmp3[813] };
+; CHECK-NEXT:            Execution Context: {  :  }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_if_then570[] -> MemRef_tmp5[813] };
+; CHECK-NEXT:            Execution Context: {  :  }
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                { Stmt_if_then570[] -> MemRef_tmp3[812] };
+; CHECK-NEXT:            Execution Context: {  :  }
+; CHECK-NEXT:    }
+;
+; ModuleID = 'bugpoint-reduced-simplified.bc'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.frame_store = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, %struct.picture*, %struct.picture*, %struct.picture* }
+%struct.picture = type { i32, i32, i32, i32, i32, i32, [6 x [33 x i64]], [6 x [33 x i64]], [6 x [33 x i64]], [6 x [33 x i64]], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i16**, i16*, i16*, i16**, i16**, i16***, i8*, i16***, i64***, i64***, i16****, i8**, i8**, %struct.picture*, %struct.picture*, %struct.picture*, i32, i32, i32, i32, i32, i32, i32 }
+
+; Function Attrs: nounwind uwtable
+define void @dpb_split_field(%struct.frame_store* %fs) #0 {
+entry:
+  %frame = getelementptr inbounds %struct.frame_store, %struct.frame_store* %fs, i64 0, i32 10
+  br label %for.cond538.preheader.lr.ph
+
+for.cond538.preheader.lr.ph:                      ; preds = %entry
+  %bottom_field578 = getelementptr inbounds %struct.frame_store, %struct.frame_store* %fs, i64 0, i32 12
+  br label %for.cond538.preheader
+
+for.cond538.preheader:                            ; preds = %for.inc912, %for.cond538.preheader.lr.ph
+  %tmp0 = phi %struct.picture* [ undef, %for.cond538.preheader.lr.ph ], [ %tmp11, %for.inc912 ]
+  br i1 undef, label %land.lhs.true563, label %for.inc912
+
+land.lhs.true563:                                 ; preds = %for.cond538.preheader
+  %div552 = sdiv i32 0, 16
+  %div554 = sdiv i32 0, 4
+  %mul555 = mul i32 %div552, %div554
+  %rem558 = srem i32 0, 2
+  %tmp9a = add i32 %mul555, 0
+  %tmp10a = shl i32 %tmp9a, 1
+  %add559 = add i32 %tmp10a, %rem558
+  %idxprom564 = sext i32 %add559 to i64
+  %mb_field566 = getelementptr inbounds %struct.picture, %struct.picture* %tmp0, i64 0, i32 31
+  %tmp1 = load i8*, i8** %mb_field566, align 8
+  %arrayidx567 = getelementptr inbounds i8, i8* %tmp1, i64 %idxprom564
+  %tmp2 = load i8, i8* %arrayidx567, align 1
+  store i8 0, i8* %arrayidx567
+  br i1 false, label %if.end908, label %if.then570
+
+if.then570:                                       ; preds = %land.lhs.true563
+  %tmp3 = load %struct.picture*, %struct.picture** %frame, align 8
+  %mv = getelementptr inbounds %struct.picture, %struct.picture* %tmp3, i64 0, i32 35
+  %tmp4 = load i16****, i16***** %mv, align 8
+  %tmp5 = load %struct.picture*, %struct.picture** %bottom_field578, align 8
+  %mv612 = getelementptr inbounds %struct.picture, %struct.picture* %tmp5, i64 0, i32 35
+  %tmp6 = load i16****, i16***** %mv612, align 8
+  %arrayidx647 = getelementptr inbounds i16***, i16**** %tmp4, i64 1
+  %ref_id726 = getelementptr inbounds %struct.picture, %struct.picture* %tmp3, i64 0, i32 34
+  %tmp7 = load i64***, i64**** %ref_id726, align 8
+  %arrayidx746 = getelementptr inbounds i64**, i64*** %tmp7, i64 5
+  %tmp8 = load %struct.picture*, %struct.picture** %frame, align 8
+  %mv783 = getelementptr inbounds %struct.picture, %struct.picture* %tmp8, i64 0, i32 35
+  %tmp9 = load i16****, i16***** %mv783, align 8
+  %arrayidx804 = getelementptr inbounds i16***, i16**** %tmp9, i64 1
+  %tmp10 = load i16***, i16**** %arrayidx804, align 8
+  %arrayidx805 = getelementptr inbounds i16**, i16*** %tmp10, i64 0
+  store i16*** %tmp10, i16**** %arrayidx804
+  br label %if.end908
+
+if.end908:                                        ; preds = %if.then570, %land.lhs.true563
+  br label %for.inc912
+
+for.inc912:                                       ; preds = %if.end908, %for.cond538.preheader
+  %tmp11 = phi %struct.picture* [ %tmp0, %for.cond538.preheader ], [ undef, %if.end908 ]
+  br i1 undef, label %for.cond538.preheader, label %for.cond1392.preheader
+
+for.cond1392.preheader:                           ; preds = %for.inc912
+  ret void
+}
diff --git a/final/test/ScopInfo/parameter_in_dead_statement.ll b/final/test/ScopInfo/parameter_in_dead_statement.ll
new file mode 100644
index 0000000..ab76f75
--- /dev/null
+++ b/final/test/ScopInfo/parameter_in_dead_statement.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -S \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s --check-prefix=IR
+;
+; Verify we do not create assumptions based on the parameter p_1 which is the
+; load %0 and due to error-assumptions not "part of the SCoP".
+;
+; CHECK:        Invalid Context:
+; CHECK-NEXT:     [releaseCount, p_1] -> {  : releaseCount > 0 }
+;
+; IR: polly.start
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: uwtable
+define void @_ZN8NWindows16NSynchronization14CSemaphoreWFMO7ReleaseEi(i32 %releaseCount) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %cmp = icmp slt i32 %releaseCount, 1
+  br i1 %cmp, label %return, label %if.end
+
+if.end:                                           ; preds = %entry.split
+  tail call void @_ZN8NWindows16NSynchronization8CSynchro5EnterEv()
+  %0 = load i32, i32* null, align 8
+  %add = add nsw i32 %0, %releaseCount
+  %cmp2 = icmp sgt i32 %add, 0
+  br i1 %cmp2, label %if.then3, label %if.end5
+
+if.then3:                                         ; preds = %if.end
+  br label %return
+
+if.end5:                                          ; preds = %if.end
+  br label %return
+
+return:                                           ; preds = %if.end5, %if.then3, %entry.split
+  %retval.1 = phi i32 [ 1, %entry.split ], [ 1, %if.then3 ], [ 0, %if.end5 ]
+  ret void
+}
+
+; Function Attrs: nounwind uwtable
+declare void @_ZN8NWindows16NSynchronization8CSynchro5EnterEv()
diff --git a/final/test/ScopInfo/parameter_product.ll b/final/test/ScopInfo/parameter_product.ll
new file mode 100644
index 0000000..f4854c6
--- /dev/null
+++ b/final/test/ScopInfo/parameter_product.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -polly-scops -analyze -S < %s | FileCheck %s
+;
+; int n, m;
+; void foo(char* __restrict a)
+; {
+;   for (int i = 0; i < n*m; ++i)
+;     a[i]=2;
+; }
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+define void @foo(i8* noalias %a, i32 %param_n, i32 %param_m) {
+entry:
+  %mul = mul nsw i32 %param_m, %param_n
+  %cmp1 = icmp sgt i32 %mul, 0
+  br i1 %cmp1, label %for.body, label %for.end
+
+for.body:
+  %i.02 = phi i32 [ %add, %for.body ], [ 0, %entry ]
+  %arrayidx = getelementptr inbounds i8, i8* %a, i64 0
+  store i8 2, i8* %arrayidx, align 1
+  %add = add nsw i32 %i.02, 1
+  %cmp = icmp slt i32 %add, %mul
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+  ret void
+}
+
+; CHECK: p0: (%param_n * %param_m)
+
diff --git a/final/test/ScopInfo/parameter_with_constant_factor_in_add.ll b/final/test/ScopInfo/parameter_with_constant_factor_in_add.ll
new file mode 100644
index 0000000..eef9541
--- /dev/null
+++ b/final/test/ScopInfo/parameter_with_constant_factor_in_add.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that the access function of the store is simple and concise
+;
+; CHECK: p0: {0,+,(-1 + (sext i32 (-1 * %smax188) to i64))<nsw>}<%for.cond261.preheader>
+;
+; CHECK:      MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:   [p_0] -> { Stmt_for_body276[i0] -> MemRef_A[p_0] };
+;
+; ModuleID = 'bugpoint-reduced-simplified.bc'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @BPredPartitionCost(i32* %A) #0 {
+entry:
+  %curr_blk = alloca [16 x [16 x i32]], align 16
+  br label %for.cond261.preheader.lr.ph
+
+for.cond261.preheader.lr.ph:                      ; preds = %entry
+  %smax188 = select i1 undef, i32 undef, i32 -9
+  %0 = sub i32 0, %smax188
+  %1 = sext i32 %0 to i64
+  %2 = add i64 %1, -1
+  br label %for.cond261.preheader
+
+for.cond261.preheader:                            ; preds = %for.inc299, %for.cond261.preheader.lr.ph
+  %indvars.iv189 = phi i64 [ 0, %for.cond261.preheader.lr.ph ], [ %indvars.iv.next190, %for.inc299 ]
+  br i1 undef, label %for.cond273.preheader, label %for.inc299
+
+for.cond273.preheader:                            ; preds = %for.cond261.preheader
+  br label %for.body276
+
+for.body276:                                      ; preds = %for.body276, %for.cond273.preheader
+  %indvars.iv = phi i64 [ 0, %for.cond273.preheader ], [ %indvars.iv.next, %for.body276 ]
+  %3 = add nsw i64 0, %indvars.iv189
+  %arrayidx282 = getelementptr inbounds [16 x [16 x i32]], [16 x [16 x i32]]* %curr_blk, i64 0, i64 %3, i64 0
+  %4 = load i32, i32* %arrayidx282, align 4
+  %arridx = getelementptr i32, i32* %A, i64 %3
+  store i32 0, i32* %arridx, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br i1 false, label %for.body276, label %for.end291
+
+for.end291:                                       ; preds = %for.body276
+  ret void
+
+for.inc299:                                       ; preds = %for.cond261.preheader
+  %indvars.iv.next190 = add i64 %indvars.iv189, %2
+  br i1 undef, label %for.cond261.preheader, label %if.end302
+
+if.end302:                                        ; preds = %for.inc299
+  ret void
+}
diff --git a/final/test/ScopInfo/partially_invariant_load_1.ll b/final/test/ScopInfo/partially_invariant_load_1.ll
new file mode 100644
index 0000000..0358075
--- /dev/null
+++ b/final/test/ScopInfo/partially_invariant_load_1.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -polly-invariant-load-hoisting=true -S < %s | FileCheck %s --check-prefix=IR
+;
+; CHECK:          Invariant Accesses: {
+; CHECK-NEXT:             ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [N, tmp1] -> { Stmt_for_body[i0] -> MemRef_I[0] };
+; CHECK-NEXT:             Execution Context: [N, tmp1] -> {  : N > 0 and (tmp1 >= 43 or tmp1 <= 41) }
+; CHECK-NEXT:     }
+; CHECK:          Invalid Context:
+; CHECK-NEXT:     [N, tmp1] -> {  : tmp1 = 42 and N > 0 }
+;
+; IR:       polly.preload.begin:
+; IR-NEXT:    br i1 false, label %polly.start, label %for.cond
+;
+;    void f(int *A, int *I, int N) {
+;      for (int i = 0; i < N; i++) {
+;        if (*I == 42)
+;          *I = 0;
+;        else
+;          A[i]++;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %I, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp1 = load i32, i32* %I, align 4
+  %cmp1 = icmp eq i32 %tmp1, 42
+  br i1 %cmp1, label %if.then, label %if.else
+
+if.then:                                          ; preds = %for.body
+  store i32 0, i32* %I, align 4
+  br label %if.end
+
+if.else:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp2, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/partially_invariant_load_2.ll b/final/test/ScopInfo/partially_invariant_load_2.ll
new file mode 100644
index 0000000..4269c32
--- /dev/null
+++ b/final/test/ScopInfo/partially_invariant_load_2.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-scops -polly-invariant-load-hoisting=true -analyze < %s | FileCheck %s
+;
+; Check that we do not try to preload *I and assume p != 42.
+;
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT: }
+;
+; CHECK:      Invalid Context:
+; CHECK-NEXT: [N, p] -> {  : 1 = 0 }
+;
+; CHECK:      Stmt_if_then__TO__if_end
+; CHECK-NEXT:   Domain :=
+; CHECK-NEXT:   [N, p] -> { Stmt_if_then__TO__if_end[i0] : p = 42 and 0 <= i0 < N };
+;
+;    void f(int *A, int *I, int N, int p, int q) {
+;      for (int i = 0; i < N; i++) {
+;        if (p == 42) {
+;          *I = 0;
+;          if (*I == q)
+;            A[i] *= 2;
+;        }
+;        A[i]++;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %I, i32 %N, i32 %p, i32 %q) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %cmp1 = icmp eq i32 %p, 42
+  br i1 %cmp1, label %if.then, label %if.end4
+
+if.then:                                          ; preds = %for.body
+  store i32 0, i32* %I, align 4
+  %tmp1 = load i32, i32* %I, align 4
+  %cmp2 = icmp eq i32 %tmp1, %q
+  br i1 %cmp2, label %if.then3, label %if.end
+
+if.then3:                                         ; preds = %if.then
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %mul = shl nsw i32 %tmp2, 1
+  store i32 %mul, i32* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then3, %if.then
+  br label %if.end4
+
+if.end4:                                          ; preds = %if.end, %for.body
+  %arrayidx6 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %arrayidx6, align 4
+  %inc = add nsw i32 %tmp3, 1
+  store i32 %inc, i32* %arrayidx6, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/phi-in-non-affine-region.ll b/final/test/ScopInfo/phi-in-non-affine-region.ll
new file mode 100644
index 0000000..584e5e2
--- /dev/null
+++ b/final/test/ScopInfo/phi-in-non-affine-region.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s
+
+; Verify that 'tmp' is stored in bb1 and read by bb3, as it is needed as
+; incoming value for the tmp11 PHI node.
+
+; CHECK: Stmt_bb1
+; CHECK-NEXT:   Domain :=
+; CHECK-NEXT:       { Stmt_bb1[] };
+; CHECK-NEXT:   Schedule :=
+; CHECK-NEXT:       { Stmt_bb1[] -> [0] };
+; CHECK-NEXT:   ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:       { Stmt_bb1[] -> MemRef_global[0] };
+; CHECK-NEXT:   MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:       { Stmt_bb1[] -> MemRef_tmp[] };
+; CHECK-NEXT: Stmt_bb3__TO__bb10
+; CHECK-NEXT:   Domain :=
+; CHECK-NEXT:       { Stmt_bb3__TO__bb10[] };
+; CHECK-NEXT:   Schedule :=
+; CHECK-NEXT:       { Stmt_bb3__TO__bb10[] -> [1] };
+; CHECK-NEXT:   ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:       { Stmt_bb3__TO__bb10[] -> MemRef_tmp[] };
+; CHECK-NEXT:   MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:       { Stmt_bb3__TO__bb10[] -> MemRef_tmp11[] };
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.hoge = type { double, double, i8, i8, i8 }
+
+@global = external local_unnamed_addr global %struct.hoge, align 8
+
+define void @widget() local_unnamed_addr {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb
+  %tmp = load double, double* getelementptr inbounds (%struct.hoge, %struct.hoge* @global, i64 0, i32 0), align 8
+  br i1 false, label %bb3, label %bb2
+
+bb2:                                              ; preds = %bb1
+  br label %bb3
+
+bb3:                                              ; preds = %bb2, %bb1
+  br i1 false, label %bb8, label %bb4
+
+bb4:                                              ; preds = %bb3
+  br label %bb5
+
+bb5:                                              ; preds = %bb4
+  %tmp6 = and i32 undef, 16711680
+  %tmp7 = icmp eq i32 %tmp6, 0
+  br i1 %tmp7, label %bb8, label %bb10
+
+bb8:                                              ; preds = %bb5, %bb3
+  %tmp9 = phi double [ %tmp, %bb3 ], [ undef, %bb5 ]
+  br label %bb10
+
+bb10:                                             ; preds = %bb8, %bb5
+  %tmp11 = phi double [ undef, %bb5 ], [ %tmp9, %bb8 ]
+  ret void
+}
diff --git a/final/test/ScopInfo/phi_after_error_block.ll b/final/test/ScopInfo/phi_after_error_block.ll
new file mode 100644
index 0000000..c8aae44
--- /dev/null
+++ b/final/test/ScopInfo/phi_after_error_block.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+declare void @bar()
+
+define void @foo(float* %A, i64 %p) {
+start:
+   br label %next
+
+next:
+   %cmpA = icmp sle i64 %p, 0
+   br i1 %cmpA, label %error, label %ok
+
+error:
+   call void @bar()
+   br label %merge
+
+ok:
+   br label %merge
+
+merge:
+   %phi = phi i64 [0, %error], [1, %ok]
+   store float 42.0, float* %A
+   %cmp = icmp eq i64 %phi, %p
+   br i1 %cmp, label %loop, label %exit
+
+loop:
+   %indvar = phi i64 [0, %merge], [%indvar.next, %loop]
+   store float 42.0, float* %A
+   %indvar.next = add i64 %indvar, 1
+   %cmp2 = icmp sle i64 %indvar, 1024
+   br i1 %cmp2, label %loop, label %exit
+
+exit:
+   ret void
+}
+
+; CHECK:      Statements {
+; CHECK-NEXT: 	Stmt_ok
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p] -> { Stmt_ok[] : p > 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p] -> { Stmt_ok[] -> [0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p] -> { Stmt_ok[] -> MemRef_phi__phi[] };
+; CHECK-NEXT: 	Stmt_merge
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p] -> { Stmt_merge[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p] -> { Stmt_merge[] -> [1, 0] };
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p] -> { Stmt_merge[] -> MemRef_phi__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [p] -> { Stmt_merge[] -> MemRef_A[0] };
+; CHECK-NEXT: 	Stmt_loop
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p] -> { Stmt_loop[i0] : p = 1 and 0 <= i0 <= 1025 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p] -> { Stmt_loop[i0] -> [2, i0] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [p] -> { Stmt_loop[i0] -> MemRef_A[0] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/phi_condition_modeling_1.ll b/final/test/ScopInfo/phi_condition_modeling_1.ll
new file mode 100644
index 0000000..07f8216
--- /dev/null
+++ b/final/test/ScopInfo/phi_condition_modeling_1.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s
+;
+;    void f(int *A, int c, int N) {
+;      int tmp;
+;      for (int i = 0; i < N; i++) {
+;        if (i > c)
+;          tmp = 3;
+;        else
+;          tmp = 5;
+;        A[i] = tmp;
+;      }
+;    }
+;
+; CHECK:    Statements {
+; CHECK-LABEL:      Stmt_bb6
+; CHECK-NOT: Access
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb6[i0] -> MemRef_tmp_0__phi[] };
+; CHECK-NOT: Access
+; CHECK-LABEL:      Stmt_bb7
+; CHECK-NOT: Access
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb7[i0] -> MemRef_tmp_0__phi[] };
+; CHECK-NOT: Access
+; CHECK-LABEL:      Stmt_bb8
+; CHECK-NOT: Access
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb8[i0] -> MemRef_tmp_0__phi[] };
+; CHECK-NOT: Access
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [N, c] -> { Stmt_bb8[i0] -> MemRef_A[i0] };
+; CHECK-NOT: Access
+; CHECK:    }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %c, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  %tmp1 = sext i32 %c to i64
+  br label %bb2
+
+bb2:                                              ; preds = %bb10, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb10 ], [ 0, %bb ]
+  %tmp3 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp3, label %bb4, label %bb11
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = icmp sgt i64 %indvars.iv, %tmp1
+  br i1 %tmp5, label %bb6, label %bb7
+
+bb6:                                              ; preds = %bb4
+  br label %bb8
+
+bb7:                                              ; preds = %bb4
+  br label %bb8
+
+bb8:                                              ; preds = %bb7, %bb6
+  %tmp.0 = phi i32 [ 3, %bb6 ], [ 5, %bb7 ]
+  %tmp9 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp.0, i32* %tmp9, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb2
+
+bb11:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/ScopInfo/phi_condition_modeling_2.ll b/final/test/ScopInfo/phi_condition_modeling_2.ll
new file mode 100644
index 0000000..33b9655
--- /dev/null
+++ b/final/test/ScopInfo/phi_condition_modeling_2.ll
@@ -0,0 +1,87 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s
+;
+;    void f(int *A, int c, int N) {
+;      int tmp;
+;      for (int i = 0; i < N; i++) {
+;        if (i > c)
+;          tmp = 3;
+;        else
+;          tmp = 5;
+;        A[i] = tmp;
+;      }
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb6
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, c] -> { Stmt_bb6[i0] : i0 > c and 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, c] -> { Stmt_bb6[i0] -> [i0, 1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_bb6[i0] -> MemRef_tmp_0__phi[] };
+; CHECK-NEXT:     Stmt_bb7
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, c] -> { Stmt_bb7[i0] : 0 <= i0 <= c and i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, c] -> { Stmt_bb7[i0] -> [i0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_bb7[i0] -> MemRef_tmp_0__phi[] };
+; CHECK-NEXT:     Stmt_bb8
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, c] -> { Stmt_bb8[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, c] -> { Stmt_bb8[i0] -> [i0, 2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_bb8[i0] -> MemRef_tmp_0__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_bb8[i0] -> MemRef_tmp_0[] };
+; CHECK-NEXT:     Stmt_bb8b
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, c] -> { Stmt_bb8b[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, c] -> { Stmt_bb8b[i0] -> [i0, 3] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N, c] -> { Stmt_bb8b[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_bb8b[i0] -> MemRef_tmp_0[] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %c, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  %tmp1 = sext i32 %c to i64
+  br label %bb2
+
+bb2:                                              ; preds = %bb10, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb10 ], [ 0, %bb ]
+  %tmp3 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp3, label %bb4, label %bb11
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = icmp sgt i64 %indvars.iv, %tmp1
+  br i1 %tmp5, label %bb6, label %bb7
+
+bb6:                                              ; preds = %bb4
+  br label %bb8
+
+bb7:                                              ; preds = %bb4
+  br label %bb8
+
+bb8:                                              ; preds = %bb7, %bb6
+  %tmp.0 = phi i32 [ 3, %bb6 ], [ 5, %bb7 ]
+  br label %bb8b
+
+bb8b:
+  %tmp9 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %tmp.0, i32* %tmp9, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb2
+
+bb11:                                             ; preds = %bb2
+  ret void
+}
diff --git a/final/test/ScopInfo/phi_conditional_simple_1.ll b/final/test/ScopInfo/phi_conditional_simple_1.ll
new file mode 100644
index 0000000..ac7a5ff
--- /dev/null
+++ b/final/test/ScopInfo/phi_conditional_simple_1.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s
+;
+;    void jd(int *A, int c) {
+;      for (int i = 0; i < 1024; i++) {
+;        if (c)
+;          A[i] = 1;
+;        else
+;          A[i] = 2;
+;      }
+;    }
+;
+; CHECK:    Statements {
+; CHECK-LABEL:      Stmt_if_else
+; CHECK-NOT: Access
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [c] -> { Stmt_if_else[i0] -> MemRef_phi__phi[] };
+; CHECK-NOT: Access
+; CHECK-LABEL:      Stmt_if_then
+; CHECK-NOT: Access
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [c] -> { Stmt_if_then[i0] -> MemRef_phi__phi[] };
+; CHECK-NOT: Access
+; CHECK-LABEL:      Stmt_if_end
+; CHECK-NOT: Access
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [c] -> { Stmt_if_end[i0] -> MemRef_phi__phi[] };
+; CHECK-NOT: Access
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [c] -> { Stmt_if_end[i0] -> MemRef_A[i0] };
+; CHECK-NOT: Access
+; CHECK:    }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32 %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tobool = icmp eq i32 %c, 0
+  br i1 %tobool, label %if.else, label %if.then
+
+if.then:                                          ; preds = %for.body
+  br label %if.end
+
+if.else:                                          ; preds = %for.body
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  %phi = phi i32 [ 1, %if.then], [ 2, %if.else ]
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %phi, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/phi_loop_carried_float.ll b/final/test/ScopInfo/phi_loop_carried_float.ll
new file mode 100644
index 0000000..7f54242
--- /dev/null
+++ b/final/test/ScopInfo/phi_loop_carried_float.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    float f(float *A, int N) {
+;      float tmp = 0;
+;      for (int i = 0; i < N; i++)
+;        tmp += A[i];
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_bb1[i0] : 0 <= i0 <= N; Stmt_bb1[0] : N < 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_bb1[i0] -> [i0, 0] : i0 <= N; Stmt_bb1[0] -> [0, 0] : N < 0 };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_bb1[i0] -> MemRef_tmp_0__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_bb1[i0] -> MemRef_tmp_0[] };
+; CHECK-NEXT:     Stmt_bb4
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_bb4[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_bb4[i0] -> [i0, 1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_bb4[i0] -> MemRef_tmp_0__phi[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_bb4[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_bb4[i0] -> MemRef_tmp_0[] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(float* %A, i32 %N) {
+bb:
+  %tmp = sext i32 %N to i64
+  br label %bb1
+
+bb1:                                              ; preds = %bb4, %bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %bb4 ], [ 0, %bb ]
+  %tmp.0 = phi float [ 0.000000e+00, %bb ], [ %tmp7, %bb4 ]
+  %tmp2 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %tmp2, label %bb3, label %bb8
+
+bb3:                                              ; preds = %bb1
+  br label %bb4
+
+bb4:                                              ; preds = %bb3
+  %tmp5 = getelementptr inbounds float, float* %A, i64 %indvars.iv
+  %tmp6 = load float, float* %tmp5, align 4
+  %tmp7 = fadd float %tmp.0, %tmp6
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  br label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/phi_not_grouped_at_top.ll b/final/test/ScopInfo/phi_not_grouped_at_top.ll
new file mode 100644
index 0000000..a5a8017
--- /dev/null
+++ b/final/test/ScopInfo/phi_not_grouped_at_top.ll
@@ -0,0 +1,28 @@
+; RUN: opt %loadPolly -analyze  < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+declare i32 @funa() align 2
+
+declare i32 @generic_personality_v0(i32, i64, i8*, i8*)
+
+define void @funb() personality i32 (i32, i64, i8*, i8*)* @generic_personality_v0 {
+entry:
+  br label %bb117
+
+bb117:                                            ; preds = %bb56
+  %0 = invoke i32 @funa()
+          to label %bb121 unwind label %invcont118 ; <%struct.btHullTriangle*> [#uses=1]
+
+invcont118:                                       ; preds = %bb117
+  %d = landingpad { i8*, i32 } cleanup catch i32* null
+  br label %bb121
+
+bb121:                                            ; preds = %bb120, %invcont118
+  %iftmp.82.0 = phi i32 [ 0, %bb117 ], [ 1, %invcont118 ] ; <i8> [#uses=1]
+  %te.1 = phi i32 [ undef, %invcont118 ], [ %0, %bb117 ] ;
+  %cnd = icmp ne i32 %iftmp.82.0, %te.1          ; <i1> [#uses=1]
+  br label %return
+
+return:                                           ; preds = %entry
+  ret void
+}
diff --git a/final/test/ScopInfo/phi_scalar_simple_1.ll b/final/test/ScopInfo/phi_scalar_simple_1.ll
new file mode 100644
index 0000000..0b7ec16
--- /dev/null
+++ b/final/test/ScopInfo/phi_scalar_simple_1.ll
@@ -0,0 +1,120 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; The assumed context should be empty since the <nsw> flags on the IV
+; increments already guarantee that there is no wrap in the loop trip
+; count.
+;
+;    int jd(int *restrict A, int x, int N) {
+;      for (int i = 1; i < N; i++)
+;        for (int j = 3; j < N; j++)
+;          x += A[i];
+;      return x;
+;    }
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [N] -> {  :  }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_cond
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_for_cond[i0] : N >= 2 and 0 <= i0 < N; Stmt_for_cond[0] : N <= 1 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_for_cond[i0] -> [i0, 0, 0, 0] : N >= 2 and i0 < N; Stmt_for_cond[0] -> [0, 0, 0, 0] : N <= 1 };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0[] };
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_for_body[i0] : 0 <= i0 <= -2 + N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_for_body[i0] -> [i0, 1, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_body[i0] -> MemRef_x_addr_0[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_body[i0] -> MemRef_x_addr_1__phi[] };
+; CHECK-NEXT:     Stmt_for_cond1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_for_cond1[i0, i1] : 0 <= i0 <= -2 + N and 0 <= i1 <= -3 + N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_for_cond1[i0, i1] -> [i0, 2, i1, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1_lcssa__phi[] };
+; CHECK-NEXT:     Stmt_for_inc
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_for_inc[i0, i1] : 0 <= i0 <= -2 + N and 0 <= i1 <= -4 + N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_for_inc[i0, i1] -> [i0, 2, i1, 1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_1__phi[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_for_inc[i0, i1] -> MemRef_A[1 + i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NEXT:     Stmt_for_end
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_for_end[i0] : N >= 3 and 0 <= i0 <= -2 + N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_for_end[i0] -> [i0, 3, 0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_end[i0] -> MemRef_x_addr_1_lcssa[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_end[i0] -> MemRef_x_addr_1_lcssa__phi[] };
+; CHECK-NEXT:     Stmt_for_inc4
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_for_inc4[i0] : N >= 3 and 0 <= i0 <= -2 + N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_for_inc4[i0] -> [i0, 4, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_inc4[i0] -> MemRef_x_addr_1_lcssa[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_for_inc4[i0] -> MemRef_x_addr_0__phi[] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @jd(i32* noalias %A, i32 %x, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc4 ], [ 1, %entry ]
+  %x.addr.0 = phi i32 [ %x, %entry ], [ %x.addr.1.lcssa, %for.inc4 ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end6
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %x.addr.1 = phi i32 [ %x.addr.0, %for.body ], [ %add, %for.inc ]
+  %j.0 = phi i32 [ 3, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, %N
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %x.addr.1, %tmp1
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  %x.addr.1.lcssa = phi i32 [ %x.addr.1, %for.cond1 ]
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end6:                                         ; preds = %for.cond
+  ret i32 %x.addr.0
+}
diff --git a/final/test/ScopInfo/phi_scalar_simple_2.ll b/final/test/ScopInfo/phi_scalar_simple_2.ll
new file mode 100644
index 0000000..46010ac
--- /dev/null
+++ b/final/test/ScopInfo/phi_scalar_simple_2.ll
@@ -0,0 +1,143 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    int jd(int *restrict A, int x, int N, int c) {
+;      for (int i = 0; i < N; i++)
+;        for (int j = 0; j < N; j++)
+;          if (i < c)
+;            x += A[i];
+;      return x;
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_cond
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, c] -> { Stmt_for_cond[i0] : 0 <= i0 <= N; Stmt_for_cond[0] : N < 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, c] -> { Stmt_for_cond[i0] -> [i0, 0, 0, 0] : i0 <= N; Stmt_for_cond[0] -> [0, 0, 0, 0] : N < 0 };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_cond[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0[] };
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, c] -> { Stmt_for_body[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, c] -> { Stmt_for_body[i0] -> [i0, 1, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_body[i0] -> MemRef_x_addr_0[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_body[i0] -> MemRef_x_addr_1__phi[] };
+; CHECK-NEXT:     Stmt_for_cond1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, c] -> { Stmt_for_cond1[i0, i1] : 0 <= i0 < N and 0 <= i1 <= N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, c] -> { Stmt_for_cond1[i0, i1] -> [i0, 2, i1, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1__phi[] };
+; CHECK-NEXT:     Stmt_for_body3
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, c] -> { Stmt_for_body3[i0, i1] : 0 <= i0 < N and 0 <= i1 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, c] -> { Stmt_for_body3[i0, i1] -> [i0, 2, i1, 1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_body3[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_body3[i0, i1] -> MemRef_x_addr_2__phi[] };
+; CHECK-NEXT:     Stmt_if_then
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, c] -> { Stmt_if_then[i0, i1] : 0 <= i0 < c and i0 < N and 0 <= i1 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, c] -> { Stmt_if_then[i0, i1] -> [i0, 2, i1, 2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_x_addr_2__phi[] };
+; CHECK-NEXT:     Stmt_if_end
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, c] -> { Stmt_if_end[i0, i1] : 0 <= i0 < N and 0 <= i1 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, c] -> { Stmt_if_end[i0, i1] -> [i0, 2, i1, 3] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_if_end[i0, i1] -> MemRef_x_addr_2[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_if_end[i0, i1] -> MemRef_x_addr_2__phi[] };
+; CHECK-NEXT:     Stmt_for_inc
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, c] -> { Stmt_for_inc[i0, i1] : 0 <= i0 < N and 0 <= i1 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, c] -> { Stmt_for_inc[i0, i1] -> [i0, 2, i1, 4] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_2[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_1__phi[] };
+; CHECK-NEXT:     Stmt_for_inc5
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N, c] -> { Stmt_for_inc5[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N, c] -> { Stmt_for_inc5[i0] -> [i0, 3, 0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_inc5[i0] -> MemRef_x_addr_1[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N, c] -> { Stmt_for_inc5[i0] -> MemRef_x_addr_0__phi[] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @jd(i32* noalias %A, i32 %x, i32 %N, i32 %c) {
+entry:
+  %tmp = sext i32 %N to i64
+  %tmp1 = sext i32 %c to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc5, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc5 ], [ 0, %entry ]
+  %x.addr.0 = phi i32 [ %x, %entry ], [ %x.addr.1, %for.inc5 ]
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  store i32 %x.addr.0, i32* %arrayidx2
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end7
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %x.addr.1 = phi i32 [ %x.addr.0, %for.body ], [ %x.addr.2, %for.inc ]
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, %N
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %cmp4 = icmp slt i64 %indvars.iv, %tmp1
+  br i1 %cmp4, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body3
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %x.addr.1, %tmp2
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body3
+  %x.addr.2 = phi i32 [ %add, %if.then ], [ %x.addr.1, %for.body3 ]
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc5
+
+for.inc5:                                         ; preds = %for.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end7:                                         ; preds = %for.cond
+  ret i32 %x.addr.0
+}
+
diff --git a/final/test/ScopInfo/phi_with_invoke_edge.ll b/final/test/ScopInfo/phi_with_invoke_edge.ll
new file mode 100644
index 0000000..5f43c13
--- /dev/null
+++ b/final/test/ScopInfo/phi_with_invoke_edge.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-detect  -analyze  < %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+declare i32 @generic_personality_v0(i32, i64, i8*, i8*)
+
+define i16 @v() personality i32 (i32, i64, i8*, i8*)* @generic_personality_v0 {
+entry:
+  br i1 undef, label %bb16, label %invcont12
+
+invcont12:                                        ; preds = %invcont11
+  %a = invoke i16 @v() to label %return unwind label %lpad22   ; <i16*> [#uses=1]
+
+bb16:                                             ; preds = %bb7
+  br i1 undef, label %bb9, label %return
+
+return:                                           ; preds = %bb16, %invcont12
+  %b = phi i16 [ %a, %invcont12 ], [ 0, %bb16 ] ; <i16*> [#uses=1]
+  ret i16 %b
+
+bb9:                                             ; preds = %bb3
+  ret i16 0
+
+lpad22:                                           ; preds = %invcont12
+  %d = landingpad { i8*, i32 } cleanup catch i32* null
+  unreachable
+}
diff --git a/final/test/ScopInfo/pointer-comparison-no-nsw.ll b/final/test/ScopInfo/pointer-comparison-no-nsw.ll
new file mode 100644
index 0000000..4b644af
--- /dev/null
+++ b/final/test/ScopInfo/pointer-comparison-no-nsw.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(int *A, int *B) {
+;      while (A != B) {
+;        *A = *A + 1;
+;        A++;
+;      }
+;    }
+;
+; CHECK:      Invalid Context:
+; CHECK-NEXT:   [A, B] -> { : (4*floor((A - B)/4) < A - B) or (4*floor((-A + B)/4) = -A + B and B >= 9223372036854775808 + A) or (4*floor((-A + B)/4) = -A + B and B <= -4 + A) }
+;
+; CHECK:      Domain :=
+; CHECK-NEXT:   [A, B] -> { Stmt_while_body[i0] : 4*floor((-A + B)/4) = -A + B and i0 >= 0 and 4i0 <= -4 - A + B }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %B) {
+entry:
+  br label %entry.split
+
+entry.split:
+  br i1 true, label %while.cond, label %while.end
+
+while.cond:                                       ; preds = %while.body, %entry
+  %A.addr.0 = phi i32* [ %A, %entry.split ], [ %incdec.ptr, %while.body ]
+  %cmp = icmp eq i32* %A.addr.0, %B
+  br i1 %cmp, label %while.end, label %while.body
+
+while.body:                                       ; preds = %while.cond
+  %tmp = load i32, i32* %A.addr.0, align 4
+  %add = add i32 %tmp, 1
+  store i32 %add, i32* %A.addr.0, align 4
+  %incdec.ptr = getelementptr i32, i32* %A.addr.0, i64 1
+  br label %while.cond
+
+while.end:                                        ; preds = %while.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/pointer-comparison.ll b/final/test/ScopInfo/pointer-comparison.ll
new file mode 100644
index 0000000..d7ce6d2
--- /dev/null
+++ b/final/test/ScopInfo/pointer-comparison.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; TODO: FIXME: Investigate why we need a InvalidContext here.
+;
+;    void f(int *A, int *B) {
+;      while (A != B) {
+;        *A = *A + 1;
+;        A++;
+;      }
+;    }
+;
+; CHECK:      Invalid Context:
+; CHECK-NEXT:   [A, B] -> { : (4*floor((A - B)/4) < A - B) or (4*floor((-A + B)/4) = -A + B and B >= 9223372036854775808 + A) or (4*floor((-A + B)/4) = -A + B and B <= -4 + A) }
+;
+; CHECK:      Domain :=
+; CHECK-NEXT:   [A, B] -> { Stmt_while_body[i0] : 4*floor((-A + B)/4) = -A + B and i0 >= 0 and 4i0 <= -4 - A + B }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %B) {
+entry:
+  br label %while.cond
+
+while.cond:                                       ; preds = %while.body, %entry
+  %A.addr.0 = phi i32* [ %A, %entry ], [ %incdec.ptr, %while.body ]
+  %cmp = icmp eq i32* %A.addr.0, %B
+  br i1 %cmp, label %while.end, label %while.body
+
+while.body:                                       ; preds = %while.cond
+  %tmp = load i32, i32* %A.addr.0, align 4
+  %add = add nsw i32 %tmp, 1
+  store i32 %add, i32* %A.addr.0, align 4
+  %incdec.ptr = getelementptr inbounds i32, i32* %A.addr.0, i64 1
+  br label %while.cond
+
+while.end:                                        ; preds = %while.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/pointer-type-expressions.ll b/final/test/ScopInfo/pointer-type-expressions.ll
new file mode 100644
index 0000000..36abd9e
--- /dev/null
+++ b/final/test/ScopInfo/pointer-type-expressions.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; void f(int a[], int N, float *P) {
+;   int i;
+;   for (i = 0; i < N; ++i)
+;     if (*P != 0)
+;       a[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* nocapture %a, i64 %N, float * %P) nounwind {
+entry:
+  br label %bb
+
+bb:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %bb.backedge ]
+  %brcond = icmp ne float* %P, null
+  br i1 %brcond, label %store, label %bb.backedge
+
+store:
+  %scevgep = getelementptr inbounds i64, i64* %a, i64 %i
+  store i64 %i, i64* %scevgep
+  br label %bb.backedge
+
+bb.backedge:
+  %i.inc = add nsw i64 %i, 1
+  %exitcond = icmp eq i64 %i.inc, %N
+  br i1 %exitcond, label %return, label %bb
+
+return:
+  ret void
+}
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT:   {  :  }
+; CHECK-NEXT: Invalid Context:
+; CHECK-NEXT:   {  :  1 = 0 }
+
+; CHECK:  Stmt_store
+; CHECK:        Domain :=
+; CHECK:            [P, N] -> { Stmt_store[i0] : 0 <= i0 < N and (P < 0 or P > 0) };
+; CHECK:        Schedule :=
+; CHECK:            [P, N] -> { Stmt_store[i0] -> [i0] : P < 0 or P > 0 };
+; CHECK:        MustWriteAccess := [Reduction Type: NONE]
+; CHECK:            [P, N] -> { Stmt_store[i0] -> MemRef_a[i0] };
diff --git a/final/test/ScopInfo/pointer-used-as-base-pointer-and-scalar-read.ll b/final/test/ScopInfo/pointer-used-as-base-pointer-and-scalar-read.ll
new file mode 100644
index 0000000..c34b3f1
--- /dev/null
+++ b/final/test/ScopInfo/pointer-used-as-base-pointer-and-scalar-read.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; In this test case we pass a pointer %A into a PHI node and also use this
+; pointer as base pointer of an array store. As a result, we get both scalar
+; and array memory accesses to A[] and A[0].
+
+; CHECK:      Arrays {
+; CHECK-NEXT:     float MemRef_A[*]; // Element size 4
+; CHECK-NEXT:     float* MemRef_x__phi; // Element size 8
+; CHECK-NEXT:     float* MemRef_C[*]; // Element size 8
+; CHECK-NEXT: }
+; CHECK:      Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:     float MemRef_A[*]; // Element size 4
+; CHECK-NEXT:     float* MemRef_x__phi; // Element size 8
+; CHECK-NEXT:     float* MemRef_C[*]; // Element size 8
+; CHECK-NEXT: }
+; CHECK:      Alias Groups (0):
+; CHECK-NEXT:     n/a
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_then
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p] -> { Stmt_then[i0] : p = 32 and 0 <= i0 <= 999 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p] -> { Stmt_then[i0] -> [i0, 1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [p] -> { Stmt_then[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p] -> { Stmt_then[i0] -> MemRef_x__phi[] };
+; CHECK-NEXT:     Stmt_else
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p] -> { Stmt_else[i0] : 0 <= i0 <= 999 and (p >= 33 or p <= 31) };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p] -> { Stmt_else[i0] -> [i0, 0] : p >= 33 or p <= 31 };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [p] -> { Stmt_else[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p] -> { Stmt_else[i0] -> MemRef_x__phi[] };
+; CHECK-NEXT:     Stmt_bb8
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p] -> { Stmt_bb8[i0] : 0 <= i0 <= 999 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p] -> { Stmt_bb8[i0] -> [i0, 2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p] -> { Stmt_bb8[i0] -> MemRef_x__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [p] -> { Stmt_bb8[i0] -> MemRef_C[0] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* noalias %A, float* noalias %B, float ** noalias %C, i32 %p) {
+bb:
+  br label %bb1
+
+bb1:
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp9, %bb8 ]
+  %exitcond = icmp ne i64 %i.0, 1000
+  br i1 %exitcond, label %bb2, label %bb10
+
+bb2:
+  %cmp = icmp eq i32 %p, 32
+  br i1 %cmp, label %then, label %else
+
+then:
+  store float 3.0, float* %A
+  br label %bb8
+
+else:
+  store float 4.0, float* %A
+  br label %bb8
+
+bb8:
+  %x = phi float* [%A, %then], [%B, %else]
+  store float* %x, float** %C
+  %tmp9 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb10:
+  ret void
+}
diff --git a/final/test/ScopInfo/polly-timeout-parameter-bounds.ll b/final/test/ScopInfo/polly-timeout-parameter-bounds.ll
new file mode 100644
index 0000000..652a0d9
--- /dev/null
+++ b/final/test/ScopInfo/polly-timeout-parameter-bounds.ll
@@ -0,0 +1,378 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; CHECK:      Statements {
+; CHECK-NEXT:  	Stmt_bb9
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb9[] };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb9[] -> [0] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb9[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb12
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb12[] : 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb12[] -> [1] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb12[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb15
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb15[] : -268435455 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb15[] -> [2] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb15[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb18
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb18[] : -134217727 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb18[] -> [3] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb18[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb21
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb21[] : -67108863 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb21[] -> [4] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb21[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb24
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb24[] : -33554431 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb24[] -> [5] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb24[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb27
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb27[] : -16777215 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb27[] -> [6] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb27[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb30
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb30[] : -8388607 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb30[] -> [7] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb30[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb33
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb33[] : -4194303 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb33[] -> [8] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb33[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb36
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb36[] : -2097151 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb36[] -> [9] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb36[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb39
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb39[] : -1048575 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb39[] -> [10] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb39[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb42
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb42[] : -524287 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb42[] -> [11] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb42[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb45
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb45[] : -262143 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb45[] -> [12] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb45[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb48
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb48[] : -131071 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb48[] -> [13] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb48[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb51
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb51[] : -65535 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb51[] -> [14] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb51[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb54
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb54[] : -32767 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb54[] -> [15] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb54[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb57
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb57[] : -16383 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb57[] -> [16] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb57[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb60
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb60[] : -8191 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb60[] -> [17] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb60[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb63
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb63[] : -4095 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb63[] -> [18] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb63[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb66
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb66[] : -2047 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb66[] -> [19] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb66[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb69
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb69[] : -1023 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb69[] -> [20] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb69[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb72
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb72[] : -511 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb72[] -> [21] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb72[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb75
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb75[] : -255 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb75[] -> [22] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb75[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb78
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb78[] : -127 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb78[] -> [23] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb78[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb81
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb81[] : -63 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb81[] -> [24] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb81[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb84
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb84[] : -31 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb84[] -> [25] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb84[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb87
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb87[] : -15 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb87[] -> [26] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb87[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb90
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb90[] : -7 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb90[] -> [27] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb90[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb93
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb93[] : -3 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb93[] -> [28] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb93[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  	Stmt_bb96
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb96[] : -1 + tmp <= 1073741824*floor((536870912 + tmp)/1073741824) <= tmp };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [tmp] -> { Stmt_bb96[] -> [29] };
+; CHECK-NEXT:          MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [tmp] -> { Stmt_bb96[] -> MemRef_tmp8[] };
+; CHECK-NEXT:  }
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+target triple = "thumbv7--linux-android"
+
+define i32 @f(i32* nocapture readonly %arg5) {
+bb:
+  %tmp = load i32, i32* %arg5, align 4
+  %tmp6 = icmp eq i32 %tmp, 0
+  br i1 %tmp6, label %bb9, label %bb7
+
+bb7:                                              ; preds = %bb96, %bb93, %bb90, %bb87, %bb84, %bb81, %bb78, %bb75, %bb72, %bb69, %bb66, %bb63, %bb60, %bb57, %bb54, %bb51, %bb48, %bb45, %bb42, %bb39, %bb36, %bb33, %bb30, %bb27, %bb24, %bb21, %bb18, %bb15, %bb12, %bb9, %bb
+  %tmp8 = phi i32 [ 30, %bb93 ], [ 29, %bb90 ], [ 28, %bb87 ], [ 27, %bb84 ], [ 26, %bb81 ], [ 25, %bb78 ], [ 24, %bb75 ], [ 23, %bb72 ], [ 22, %bb69 ], [ 21, %bb66 ], [ 20, %bb63 ], [ 19, %bb60 ], [ 18, %bb57 ], [ 17, %bb54 ], [ 16, %bb51 ], [ 15, %bb48 ], [ 14, %bb45 ], [ 13, %bb42 ], [ 12, %bb39 ], [ 11, %bb36 ], [ 10, %bb33 ], [ 9, %bb30 ], [ 8, %bb27 ], [ 7, %bb24 ], [ 6, %bb21 ], [ 5, %bb18 ], [ 4, %bb15 ], [ 3, %bb12 ], [ 2, %bb9 ], [ 1, %bb ], [ %tmp98, %bb96 ]
+  ret i32 %tmp8
+
+bb9:                                              ; preds = %bb
+  %tmp10 = and i32 %tmp, 536870912
+  %tmp11 = icmp eq i32 %tmp10, 0
+  br i1 %tmp11, label %bb12, label %bb7
+
+bb12:                                             ; preds = %bb9
+  %tmp13 = and i32 %tmp, 268435456
+  %tmp14 = icmp eq i32 %tmp13, 0
+  br i1 %tmp14, label %bb15, label %bb7
+
+bb15:                                             ; preds = %bb12
+  %tmp16 = and i32 %tmp, 134217728
+  %tmp17 = icmp eq i32 %tmp16, 0
+  br i1 %tmp17, label %bb18, label %bb7
+
+bb18:                                             ; preds = %bb15
+  %tmp19 = and i32 %tmp, 67108864
+  %tmp20 = icmp eq i32 %tmp19, 0
+  br i1 %tmp20, label %bb21, label %bb7
+
+bb21:                                             ; preds = %bb18
+  %tmp22 = and i32 %tmp, 33554432
+  %tmp23 = icmp eq i32 %tmp22, 0
+  br i1 %tmp23, label %bb24, label %bb7
+
+bb24:                                             ; preds = %bb21
+  %tmp25 = and i32 %tmp, 16777216
+  %tmp26 = icmp eq i32 %tmp25, 0
+  br i1 %tmp26, label %bb27, label %bb7
+
+bb27:                                             ; preds = %bb24
+  %tmp28 = and i32 %tmp, 8388608
+  %tmp29 = icmp eq i32 %tmp28, 0
+  br i1 %tmp29, label %bb30, label %bb7
+
+bb30:                                             ; preds = %bb27
+  %tmp31 = and i32 %tmp, 4194304
+  %tmp32 = icmp eq i32 %tmp31, 0
+  br i1 %tmp32, label %bb33, label %bb7
+
+bb33:                                             ; preds = %bb30
+  %tmp34 = and i32 %tmp, 2097152
+  %tmp35 = icmp eq i32 %tmp34, 0
+  br i1 %tmp35, label %bb36, label %bb7
+
+bb36:                                             ; preds = %bb33
+  %tmp37 = and i32 %tmp, 1048576
+  %tmp38 = icmp eq i32 %tmp37, 0
+  br i1 %tmp38, label %bb39, label %bb7
+
+bb39:                                             ; preds = %bb36
+  %tmp40 = and i32 %tmp, 524288
+  %tmp41 = icmp eq i32 %tmp40, 0
+  br i1 %tmp41, label %bb42, label %bb7
+
+bb42:                                             ; preds = %bb39
+  %tmp43 = and i32 %tmp, 262144
+  %tmp44 = icmp eq i32 %tmp43, 0
+  br i1 %tmp44, label %bb45, label %bb7
+
+bb45:                                             ; preds = %bb42
+  %tmp46 = and i32 %tmp, 131072
+  %tmp47 = icmp eq i32 %tmp46, 0
+  br i1 %tmp47, label %bb48, label %bb7
+
+bb48:                                             ; preds = %bb45
+  %tmp49 = and i32 %tmp, 65536
+  %tmp50 = icmp eq i32 %tmp49, 0
+  br i1 %tmp50, label %bb51, label %bb7
+
+bb51:                                             ; preds = %bb48
+  %tmp52 = and i32 %tmp, 32768
+  %tmp53 = icmp eq i32 %tmp52, 0
+  br i1 %tmp53, label %bb54, label %bb7
+
+bb54:                                             ; preds = %bb51
+  %tmp55 = and i32 %tmp, 16384
+  %tmp56 = icmp eq i32 %tmp55, 0
+  br i1 %tmp56, label %bb57, label %bb7
+
+bb57:                                             ; preds = %bb54
+  %tmp58 = and i32 %tmp, 8192
+  %tmp59 = icmp eq i32 %tmp58, 0
+  br i1 %tmp59, label %bb60, label %bb7
+
+bb60:                                             ; preds = %bb57
+  %tmp61 = and i32 %tmp, 4096
+  %tmp62 = icmp eq i32 %tmp61, 0
+  br i1 %tmp62, label %bb63, label %bb7
+
+bb63:                                             ; preds = %bb60
+  %tmp64 = and i32 %tmp, 2048
+  %tmp65 = icmp eq i32 %tmp64, 0
+  br i1 %tmp65, label %bb66, label %bb7
+
+bb66:                                             ; preds = %bb63
+  %tmp67 = and i32 %tmp, 1024
+  %tmp68 = icmp eq i32 %tmp67, 0
+  br i1 %tmp68, label %bb69, label %bb7
+
+bb69:                                             ; preds = %bb66
+  %tmp70 = and i32 %tmp, 512
+  %tmp71 = icmp eq i32 %tmp70, 0
+  br i1 %tmp71, label %bb72, label %bb7
+
+bb72:                                             ; preds = %bb69
+  %tmp73 = and i32 %tmp, 256
+  %tmp74 = icmp eq i32 %tmp73, 0
+  br i1 %tmp74, label %bb75, label %bb7
+
+bb75:                                             ; preds = %bb72
+  %tmp76 = and i32 %tmp, 128
+  %tmp77 = icmp eq i32 %tmp76, 0
+  br i1 %tmp77, label %bb78, label %bb7
+
+bb78:                                             ; preds = %bb75
+  %tmp79 = and i32 %tmp, 64
+  %tmp80 = icmp eq i32 %tmp79, 0
+  br i1 %tmp80, label %bb81, label %bb7
+
+bb81:                                             ; preds = %bb78
+  %tmp82 = and i32 %tmp, 32
+  %tmp83 = icmp eq i32 %tmp82, 0
+  br i1 %tmp83, label %bb84, label %bb7
+
+bb84:                                             ; preds = %bb81
+  %tmp85 = and i32 %tmp, 16
+  %tmp86 = icmp eq i32 %tmp85, 0
+  br i1 %tmp86, label %bb87, label %bb7
+
+bb87:                                             ; preds = %bb84
+  %tmp88 = and i32 %tmp, 8
+  %tmp89 = icmp eq i32 %tmp88, 0
+  br i1 %tmp89, label %bb90, label %bb7
+
+bb90:                                             ; preds = %bb87
+  %tmp91 = and i32 %tmp, 4
+  %tmp92 = icmp eq i32 %tmp91, 0
+  br i1 %tmp92, label %bb93, label %bb7
+
+bb93:                                             ; preds = %bb90
+  %tmp94 = and i32 %tmp, 2
+  %tmp95 = icmp eq i32 %tmp94, 0
+  br i1 %tmp95, label %bb96, label %bb7
+
+bb96:                                             ; preds = %bb93
+  %tmp97 = and i32 %tmp, 1
+  %tmp98 = sub nsw i32 32, %tmp97
+  br label %bb7
+}
diff --git a/final/test/ScopInfo/process_added_dimensions.ll b/final/test/ScopInfo/process_added_dimensions.ll
new file mode 100644
index 0000000..48a8bdf
--- /dev/null
+++ b/final/test/ScopInfo/process_added_dimensions.ll
@@ -0,0 +1,120 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; CHECK:      Context:
+; CHECK-NEXT: {  :  }
+; CHECK:      Assumed Context:
+; CHECK-NEXT: {  :  }
+; CHECK:      Invalid Context:
+; CHECK-NEXT: {  : 1 = 0 }
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_cond40_preheader_4
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_for_cond40_preheader_4[i0] : 0 <= i0 <= 1 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_for_cond40_preheader_4[i0] -> [i0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_cond40_preheader_4[i0] -> MemRef_call[5, 5, 0] };
+; CHECK-NEXT:     Stmt_for_cond40_preheader_5
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_for_cond40_preheader_5[i0] : 0 <= i0 <= 1 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_for_cond40_preheader_5[i0] -> [i0, 1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_cond40_preheader_5[i0] -> MemRef_call[5, 5, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_for_cond40_preheader_5[i0] -> MemRef__pre160[] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare noalias i8* @malloc()
+
+define i32 @main() {
+entry:
+  %call = tail call noalias i8* @malloc()
+  %0 = bitcast i8* %call to [6 x [6 x [64 x i32]]]*
+  %arrayidx51.5.phi.trans.insert = getelementptr inbounds i8, i8* %call, i64 8960
+  %1 = bitcast i8* %arrayidx51.5.phi.trans.insert to i32*
+  br label %for.cond40.preheader.4
+
+for.end76:                                        ; preds = %for.inc71.5
+  ret i32 %.pre160
+
+for.cond40.preheader.4:                           ; preds = %for.inc71.5, %entry
+  %t.0131 = phi i32 [ 0, %entry ], [ %inc75, %for.inc71.5 ]
+  %indvars.iv.next135 = add nuw nsw i64 0, 1
+  %2 = trunc i64 %indvars.iv.next135 to i32
+  %indvars.iv.next = add nuw nsw i64 0, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 64
+  %exitcond137 = icmp eq i32 %2, 6
+  %indvars.iv.next135.1 = add nuw nsw i64 1, 1
+  %indvars.iv.next.1 = add nuw nsw i64 0, 1
+  %exitcond.1 = icmp eq i64 %indvars.iv.next.1, 64
+  %lftr.wideiv.1 = trunc i64 %indvars.iv.next135.1 to i32
+  %exitcond137.1 = icmp eq i32 %lftr.wideiv.1, 6
+  %indvars.iv.next135.2 = add nuw nsw i64 2, 1
+  %indvars.iv.next.2 = add nuw nsw i64 0, 1
+  %exitcond.2 = icmp eq i64 %indvars.iv.next.2, 64
+  %lftr.wideiv.2 = trunc i64 %indvars.iv.next135.2 to i32
+  %exitcond137.2 = icmp eq i32 %lftr.wideiv.2, 6
+  %indvars.iv.next135.3 = add nuw nsw i64 3, 1
+  %indvars.iv.next.3 = add nuw nsw i64 0, 1
+  %exitcond.3 = icmp eq i64 %indvars.iv.next.3, 64
+  %lftr.wideiv.3 = trunc i64 %indvars.iv.next135.3 to i32
+  %exitcond137.3 = icmp eq i32 %lftr.wideiv.3, 6
+  %indvars.iv.next135.4 = add nuw nsw i64 4, 1
+  %indvars.iv.next.4 = add nuw nsw i64 0, 1
+  %exitcond.4 = icmp eq i64 %indvars.iv.next.4, 64
+  %lftr.wideiv.4 = trunc i64 %indvars.iv.next135.4 to i32
+  %exitcond137.4 = icmp eq i32 %lftr.wideiv.4, 6
+  %arrayidx23.5 = getelementptr inbounds [6 x [6 x [64 x i32]]], [6 x [6 x [64 x i32]]]* %0, i64 0, i64 5, i64 5, i64 0
+  store i32 36, i32* %arrayidx23.5, align 4
+  %indvars.iv.next.5 = add nuw nsw i64 0, 1
+  %exitcond.5 = icmp eq i64 %indvars.iv.next.5, 64
+  %indvars.iv.next143 = add nuw nsw i64 1, 1
+  %exitcond145 = icmp eq i64 %indvars.iv.next143, 64
+  %indvars.iv.next149 = add nuw nsw i64 0, 1
+  %lftr.wideiv150 = trunc i64 %indvars.iv.next149 to i32
+  %exitcond151 = icmp eq i32 %lftr.wideiv150, 6
+  %indvars.iv.next143.1 = add nuw nsw i64 1, 1
+  %exitcond145.1 = icmp eq i64 %indvars.iv.next143.1, 64
+  %indvars.iv.next149.1 = add nuw nsw i64 1, 1
+  %lftr.wideiv150.1 = trunc i64 %indvars.iv.next149.1 to i32
+  %exitcond151.1 = icmp eq i32 %lftr.wideiv150.1, 6
+  %indvars.iv.next143.2 = add nuw nsw i64 1, 1
+  %exitcond145.2 = icmp eq i64 %indvars.iv.next143.2, 64
+  %indvars.iv.next149.2 = add nuw nsw i64 2, 1
+  %lftr.wideiv150.2 = trunc i64 %indvars.iv.next149.2 to i32
+  %exitcond151.2 = icmp eq i32 %lftr.wideiv150.2, 6
+  %indvars.iv.next143.3 = add nuw nsw i64 1, 1
+  %exitcond145.3 = icmp eq i64 %indvars.iv.next143.3, 64
+  %indvars.iv.next149.3 = add nuw nsw i64 3, 1
+  %lftr.wideiv150.3 = trunc i64 %indvars.iv.next149.3 to i32
+  %exitcond151.3 = icmp eq i32 %lftr.wideiv150.3, 6
+  br label %for.body44.4
+
+for.body44.4:                                     ; preds = %for.body44.4, %for.cond40.preheader.4
+  %indvars.iv142.4 = phi i64 [ 1, %for.cond40.preheader.4 ], [ %indvars.iv.next143.4, %for.body44.4 ]
+  %indvars.iv.next143.4 = add nuw nsw i64 %indvars.iv142.4, 1
+  %exitcond145.4 = icmp eq i64 %indvars.iv.next143.4, 64
+  br i1 %exitcond145.4, label %for.cond40.preheader.5, label %for.body44.4
+
+for.cond40.preheader.5:                           ; preds = %for.body44.4
+  %indvars.iv.next149.4 = add nuw nsw i64 4, 1
+  %lftr.wideiv150.4 = trunc i64 %indvars.iv.next149.4 to i32
+  %exitcond151.4 = icmp eq i32 %lftr.wideiv150.4, 6
+  %.pre160 = load i32, i32* %1, align 4
+  br label %for.body44.5
+
+for.body44.5:                                     ; preds = %for.body44.5, %for.cond40.preheader.5
+  %indvars.iv142.5 = phi i64 [ 1, %for.cond40.preheader.5 ], [ %indvars.iv.next143.5, %for.body44.5 ]
+  %indvars.iv.next143.5 = add nuw nsw i64 %indvars.iv142.5, 1
+  %exitcond145.5 = icmp eq i64 %indvars.iv.next143.5, 64
+  br i1 %exitcond145.5, label %for.inc71.5, label %for.body44.5
+
+for.inc71.5:                                      ; preds = %for.body44.5
+  %inc75 = add nuw nsw i32 %t.0131, 1
+  %exitcond155 = icmp eq i32 %inc75, 2
+  br i1 %exitcond155, label %for.end76, label %for.cond40.preheader.4
+}
diff --git a/final/test/ScopInfo/ranged_parameter.ll b/final/test/ScopInfo/ranged_parameter.ll
new file mode 100644
index 0000000..b59972c
--- /dev/null
+++ b/final/test/ScopInfo/ranged_parameter.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that the contstraints on the paramater derived from the
+; range metadata (see bottom of the file) are present:
+;
+; CHECK: Context:
+; CHECK:   [tmp] -> {  : 0 <= tmp <= 255 }
+;
+;    void jd(int *A, int *p /* in [0,256) */) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i + *p] = i;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %p) {
+entry:
+  %tmp = load i32, i32* %p, align 4, !range !0
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add = add i32 %i.0, %tmp
+  %idxprom = sext i32 %add to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  store i32 %i.0, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+!0 =  !{ i32 0, i32 256 }
diff --git a/final/test/ScopInfo/ranged_parameter_2.ll b/final/test/ScopInfo/ranged_parameter_2.ll
new file mode 100644
index 0000000..c2d6f57
--- /dev/null
+++ b/final/test/ScopInfo/ranged_parameter_2.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-allow-nonaffine -polly-invariant-load-hoisting=true < %s \
+; RUN:  -debug 2>&1 | FileCheck %s
+
+; REQUIRES: asserts
+
+; CHECK: Region: %bb1---%bb16
+; CHECK:   [n] -> {  : 1 = 0 }
+
+; This test case at some point caused an assertion when modeling a scop, due
+; to use constructing an invalid lower and upper bound for the range of
+; non-affine accesses.
+
+target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define void @zot(double* noalias %arg, double** %D, i32 %n) {
+bb:
+  br label %bb1
+
+bb1:
+  %tmp4 = load double*, double** %D
+  %tmp5 = add i64 undef, 3
+  %tmp6 = add i64 %tmp5, undef
+  %tmp7 = add i64 %tmp6, undef
+  %tmp8 = getelementptr double, double* %tmp4, i64 %tmp7
+  %tmp9 = bitcast double* %tmp8 to i64*
+  store i64 42, i64* %tmp9
+  br label %bb11
+
+bb11:
+  %tmp12 = getelementptr double, double* %arg, i64 0
+  %tmp13 = bitcast double* %tmp12 to i64*
+  store i64 43, i64* %tmp13
+  br label %bb14
+
+bb14:
+  %tmp15 = icmp eq i32 0, %n
+  br i1 %tmp15, label %bb16, label %bb1
+
+bb16:
+  ret void
+}
diff --git a/final/test/ScopInfo/ranged_parameter_wrap.ll b/final/test/ScopInfo/ranged_parameter_wrap.ll
new file mode 100644
index 0000000..3e6d68a
--- /dev/null
+++ b/final/test/ScopInfo/ranged_parameter_wrap.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that the constraints on the parameter derived from the
+; __wrapping__ range metadata (see bottom of the file) are present:
+;
+; CHECK: Context:
+; CHECK:   [tmp] -> {  : -2147483648 <= tmp <= 2147483647 and (tmp >= 256 or tmp < 0) }
+;
+;    void jd(int *A, int *p /* in [256, 0) */) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i + *p] = i;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A, i32* %p) {
+entry:
+  %tmp = load i32, i32* %p, align 4, !range !0
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add = add i32 %i.0, %tmp
+  %idxprom = sext i32 %add to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  store i32 %i.0, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+!0 =  !{ i32 256, i32 0 }
diff --git a/final/test/ScopInfo/ranged_parameter_wrap_2.ll b/final/test/ScopInfo/ranged_parameter_wrap_2.ll
new file mode 100644
index 0000000..c138901
--- /dev/null
+++ b/final/test/ScopInfo/ranged_parameter_wrap_2.ll
@@ -0,0 +1,207 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that the context is built fast and does not explode due to us
+; combining a large number of non-convex ranges. Instead, after a certain
+; time, we store range information with reduced precision.
+;
+; CHECK: Context:
+; CHECK:      [tmp_0, tmp_1, tmp_2, tmp_3, tmp_4, tmp_5, tmp_6, tmp_7, tmp_8,
+; CHECK:       tmp_9, tmp_10, tmp_11, tmp_12, tmp_13, tmp_14, tmp_15] -> {  :
+; CHECK:   -2147483648 <= tmp_0 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_1 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_2 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_3 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_4 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_5 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_6 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_7 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_8 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_9 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_10 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_11 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_12 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_13 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_14 <= 2147483647 and
+; CHECK:   -2147483648 <= tmp_15 <= 2147483647 and
+; CHECK:   ((tmp_0 >= 256 and tmp_1 >= 256 and tmp_2 >= 256) or
+; CHECK:    (tmp_0 >= 256 and tmp_1 >= 256 and tmp_2 < 0) or
+; CHECK:    (tmp_0 >= 256 and tmp_1 < 0 and tmp_2 >= 256) or
+; CHECK:    (tmp_0 >= 256 and tmp_1 < 0 and tmp_2 < 0) or
+; CHECK:    (tmp_0 < 0 and tmp_1 >= 256 and tmp_2 >= 256) or
+; CHECK:    (tmp_0 < 0 and tmp_1 >= 256 and tmp_2 < 0) or
+; CHECK:    (tmp_0 < 0 and tmp_1 < 0 and tmp_2 >= 256) or
+; CHECK:    (tmp_0 < 0 and tmp_1 < 0 and tmp_2 < 0)) }
+;
+;    void jd(int *A, int *p /* in [256, 0) */) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i + *p] = i;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @jd(i32* %A,
+  i32* %p_0,
+  i32* %p_1,
+  i32* %p_2,
+  i32* %p_3,
+  i32* %p_4,
+  i32* %p_5,
+  i32* %p_6,
+  i32* %p_7,
+  i32* %p_8,
+  i32* %p_9,
+  i32* %p_10,
+  i32* %p_11,
+  i32* %p_12,
+  i32* %p_13,
+  i32* %p_14,
+  i32* %p_15
+  ) {
+entry:
+  %tmp_0 = load i32, i32* %p_0, !range !0
+  %tmp_1 = load i32, i32* %p_1, !range !0
+  %tmp_2 = load i32, i32* %p_2, !range !0
+  %tmp_3 = load i32, i32* %p_3, !range !0
+  %tmp_4 = load i32, i32* %p_4, !range !0
+  %tmp_5 = load i32, i32* %p_5, !range !0
+  %tmp_6 = load i32, i32* %p_6, !range !0
+  %tmp_7 = load i32, i32* %p_7, !range !0
+  %tmp_8 = load i32, i32* %p_8, !range !0
+  %tmp_9 = load i32, i32* %p_9, !range !0
+  %tmp_10 = load i32, i32* %p_10, !range !0
+  %tmp_11 = load i32, i32* %p_11, !range !0
+  %tmp_12 = load i32, i32* %p_12, !range !0
+  %tmp_13 = load i32, i32* %p_13, !range !0
+  %tmp_14 = load i32, i32* %p_14, !range !0
+  %tmp_15 = load i32, i32* %p_15, !range !0
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body_0, label %for.end
+
+for.body_0:
+  %add_0 = add i32 %i.0, %tmp_0
+  %idxprom_0 = sext i32 %add_0 to i64
+  %arrayidx_0 = getelementptr inbounds i32, i32* %A, i64 %idxprom_0
+  store i32 %i.0, i32* %arrayidx_0, align 4
+  br label %for.body_1
+
+for.body_1:
+  %add_1 = add i32 %i.0, %tmp_1
+  %idxprom_1 = sext i32 %add_1 to i64
+  %arrayidx_1 = getelementptr inbounds i32, i32* %A, i64 %idxprom_1
+  store i32 %i.0, i32* %arrayidx_1, align 4
+  br label %for.body_2
+
+for.body_2:
+  %add_2 = add i32 %i.0, %tmp_2
+  %idxprom_2 = sext i32 %add_2 to i64
+  %arrayidx_2 = getelementptr inbounds i32, i32* %A, i64 %idxprom_2
+  store i32 %i.0, i32* %arrayidx_2, align 4
+  br label %for.body_3
+
+for.body_3:
+  %add_3 = add i32 %i.0, %tmp_3
+  %idxprom_3 = sext i32 %add_3 to i64
+  %arrayidx_3 = getelementptr inbounds i32, i32* %A, i64 %idxprom_3
+  store i32 %i.0, i32* %arrayidx_3, align 4
+  br label %for.body_4
+
+for.body_4:
+  %add_4 = add i32 %i.0, %tmp_4
+  %idxprom_4 = sext i32 %add_4 to i64
+  %arrayidx_4 = getelementptr inbounds i32, i32* %A, i64 %idxprom_4
+  store i32 %i.0, i32* %arrayidx_4, align 4
+  br label %for.body_5
+
+for.body_5:
+  %add_5 = add i32 %i.0, %tmp_5
+  %idxprom_5 = sext i32 %add_5 to i64
+  %arrayidx_5 = getelementptr inbounds i32, i32* %A, i64 %idxprom_5
+  store i32 %i.0, i32* %arrayidx_5, align 4
+  br label %for.body_6
+
+for.body_6:
+  %add_6 = add i32 %i.0, %tmp_6
+  %idxprom_6 = sext i32 %add_6 to i64
+  %arrayidx_6 = getelementptr inbounds i32, i32* %A, i64 %idxprom_6
+  store i32 %i.0, i32* %arrayidx_6, align 4
+  br label %for.body_7
+
+for.body_7:
+  %add_7 = add i32 %i.0, %tmp_7
+  %idxprom_7 = sext i32 %add_7 to i64
+  %arrayidx_7 = getelementptr inbounds i32, i32* %A, i64 %idxprom_7
+  store i32 %i.0, i32* %arrayidx_7, align 4
+  br label %for.body_8
+
+for.body_8:
+  %add_8 = add i32 %i.0, %tmp_8
+  %idxprom_8 = sext i32 %add_8 to i64
+  %arrayidx_8 = getelementptr inbounds i32, i32* %A, i64 %idxprom_8
+  store i32 %i.0, i32* %arrayidx_8, align 4
+  br label %for.body_9
+
+for.body_9:
+  %add_9 = add i32 %i.0, %tmp_9
+  %idxprom_9 = sext i32 %add_9 to i64
+  %arrayidx_9 = getelementptr inbounds i32, i32* %A, i64 %idxprom_9
+  store i32 %i.0, i32* %arrayidx_9, align 4
+  br label %for.body_10
+
+for.body_10:
+  %add_10 = add i32 %i.0, %tmp_10
+  %idxprom_10 = sext i32 %add_10 to i64
+  %arrayidx_10 = getelementptr inbounds i32, i32* %A, i64 %idxprom_10
+  store i32 %i.0, i32* %arrayidx_10, align 4
+  br label %for.body_11
+
+for.body_11:
+  %add_11 = add i32 %i.0, %tmp_11
+  %idxprom_11 = sext i32 %add_11 to i64
+  %arrayidx_11 = getelementptr inbounds i32, i32* %A, i64 %idxprom_11
+  store i32 %i.0, i32* %arrayidx_11, align 4
+  br label %for.body_12
+
+for.body_12:
+  %add_12 = add i32 %i.0, %tmp_12
+  %idxprom_12 = sext i32 %add_12 to i64
+  %arrayidx_12 = getelementptr inbounds i32, i32* %A, i64 %idxprom_12
+  store i32 %i.0, i32* %arrayidx_12, align 4
+  br label %for.body_13
+
+for.body_13:
+  %add_13 = add i32 %i.0, %tmp_13
+  %idxprom_13 = sext i32 %add_13 to i64
+  %arrayidx_13 = getelementptr inbounds i32, i32* %A, i64 %idxprom_13
+  store i32 %i.0, i32* %arrayidx_13, align 4
+  br label %for.body_14
+
+for.body_14:
+  %add_14 = add i32 %i.0, %tmp_14
+  %idxprom_14 = sext i32 %add_14 to i64
+  %arrayidx_14 = getelementptr inbounds i32, i32* %A, i64 %idxprom_14
+  store i32 %i.0, i32* %arrayidx_14, align 4
+  br label %for.body_15
+
+for.body_15:
+  %add_15 = add i32 %i.0, %tmp_15
+  %idxprom_15 = sext i32 %add_15 to i64
+  %arrayidx_15 = getelementptr inbounds i32, i32* %A, i64 %idxprom_15
+  store i32 %i.0, i32* %arrayidx_15, align 4
+  br label %for.body_end
+
+for.body_end:
+  br label %for.inc
+
+for.inc:
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+!0 =  !{ i32 256, i32 0 }
diff --git a/final/test/ScopInfo/read-only-scalar-used-in-phi-2.ll b/final/test/ScopInfo/read-only-scalar-used-in-phi-2.ll
new file mode 100644
index 0000000..4fcaa06
--- /dev/null
+++ b/final/test/ScopInfo/read-only-scalar-used-in-phi-2.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: < %s | FileCheck %s
+;
+;    float foo(float sum, float A[]) {
+;
+;      for (long i = 0; i < 100; i++)
+;        sum += A[i];
+;
+;      return sum;
+;    }
+
+; Verify that we do not model the read from %sum. Reads that only happen in
+; case control flow reaches the PHI node from outside the SCoP are handled
+; implicitly during code generation.
+
+; CHECK: Stmt_bb1[i0] -> MemRef_phisum__ph
+; CHECK-NOT: Stmt_bb1[i0] -> MemRef_sum[]
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define float @foo(float %sum, float* %A) {
+bb:
+  br label %bb1
+
+bb1:
+  %i = phi i64 [ 0, %bb ], [ %i.next, %bb1 ]
+  %phisum = phi float [ %sum, %bb ], [ %tmp5, %bb1 ]
+  %tmp = getelementptr inbounds float, float* %A, i64 %i
+  %tmp4 = load float, float* %tmp, align 4
+  %tmp5 = fadd float %phisum, %tmp4
+  %i.next = add nuw nsw i64 %i, 1
+  %exitcond = icmp ne i64 %i, 100
+  br i1 %exitcond, label %bb1, label %bb7
+
+bb7:
+  ret float %phisum
+}
diff --git a/final/test/ScopInfo/read-only-scalar-used-in-phi.ll b/final/test/ScopInfo/read-only-scalar-used-in-phi.ll
new file mode 100644
index 0000000..53ecb48
--- /dev/null
+++ b/final/test/ScopInfo/read-only-scalar-used-in-phi.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -analyze -polly-scops \
+; RUN: < %s | FileCheck %s
+;
+;    float foo(float sum, float A[]) {
+;
+;      for (long i = 0; i < 100; i++)
+;        sum += A[i];
+;
+;      return sum;
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_next
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_next[] };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_next[] -> [0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_next[] -> MemRef_sum[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_next[] -> MemRef_phisum__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_next[] -> MemRef_phisummerge[] };
+; CHECK-NEXT:     Stmt_bb1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_bb1[i0] : 0 <= i0 <= 100 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_bb1[i0] -> [1, i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb1[i0] -> MemRef_phisum__phi[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb1[i0] -> MemRef_phisum__phi[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_bb1[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             { Stmt_bb1[i0] -> MemRef_phisummerge[] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define float @foo(float %sum, float* %A) {
+bb:
+  br label %next
+
+next:
+  br i1 true, label %bb1, label %bb7
+
+bb1:
+  %i = phi i64 [ 0, %next ], [ %i.next, %bb1 ]
+  %phisum = phi float [ %sum, %next ], [ %tmp5, %bb1 ]
+  %tmp = getelementptr inbounds float, float* %A, i64 %i
+  %tmp4 = load float, float* %tmp, align 4
+  %tmp5 = fadd float %phisum, %tmp4
+  %i.next = add nuw nsw i64 %i, 1
+  %exitcond = icmp ne i64 %i, 100
+  br i1 %exitcond, label %bb1, label %bb7
+
+bb7:
+  %phisummerge = phi float [%phisum, %bb1], [0.0, %next]
+  ret float %phisummerge
+}
diff --git a/final/test/ScopInfo/read-only-scalars.ll b/final/test/ScopInfo/read-only-scalars.ll
new file mode 100644
index 0000000..0ffedf9
--- /dev/null
+++ b/final/test/ScopInfo/read-only-scalars.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-analyze-read-only-scalars=false -polly-scops \
+; RUN:                -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-analyze-read-only-scalars=true -polly-scops \
+; RUN:                -analyze < %s | FileCheck %s \
+; RUN:                -check-prefix=SCALARS
+
+; CHECK-NOT: Memref_scalar
+
+; SCALARS: float MemRef_scalar; // Element size 4
+
+; SCALARS: ReadAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; SCALARS:     { Stmt_stmt1[i0] -> MemRef_scalar[] };
+; SCALARS: ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; SCALARS:     { Stmt_stmt1[i0] -> MemRef_scalar2[] };
+
+
+define void @foo(float* noalias %A, float* %B, float %scalar, float %scalar2) {
+entry:
+  br label %loop
+
+loop:
+  %indvar = phi i64 [0, %entry], [%indvar.next, %loop.backedge]
+  br label %stmt1
+
+stmt1:
+  %val = load float, float* %A
+  %sum = fadd float %val, %scalar
+  store float %sum, float* %A
+  store float %scalar2, float* %B
+  br label %loop.backedge
+
+loop.backedge:
+  %indvar.next = add i64 %indvar, 1
+  %cond = icmp sle i64 %indvar, 100
+  br i1 %cond, label %loop, label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/read-only-statements.ll b/final/test/ScopInfo/read-only-statements.ll
new file mode 100644
index 0000000..7963731
--- /dev/null
+++ b/final/test/ScopInfo/read-only-statements.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check we remove read only statements.
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body_2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             { Stmt_for_body_2[i0] : 0 <= i0 <= 99 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             { Stmt_for_body_2[i0] -> [i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body_2[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             { Stmt_for_body_2[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+;
+;    int g(int);
+;    void f(int *A) {
+;      for (int i = 0; i < 100; i++) {
+;        (A[i]);
+;        /* Split BB */
+;        (A[i]);
+;        /* Split BB */
+;        A[i] += 1;
+;        /* Split BB */
+;        (A[i]);
+;        /* Split BB */
+;        (A[i]);
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4
+  br label %for.body.1
+
+for.body.1:
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx2, align 4
+  br label %for.body.2
+
+for.body.2:
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx5, align 4
+  %add = add nsw i32 %tmp2, 1
+  store i32 %add, i32* %arrayidx5, align 4
+  br label %for.body.3
+
+for.body.3:
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %arrayidx7, align 4
+  br label %for.body.4
+
+for.body.4:
+  %arrayidx10 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp4 = load i32, i32* %arrayidx10, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_alternating_base.ll b/final/test/ScopInfo/reduction_alternating_base.ll
new file mode 100644
index 0000000..25fc021
--- /dev/null
+++ b/final/test/ScopInfo/reduction_alternating_base.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i % 2] += i;
+;    }
+;
+; Verify that we detect the reduction on A
+;
+; CHECK: ReadAccess := [Reduction Type: +] [Scalar: 0]
+; CHECK: MustWriteAccess :=  [Reduction Type: +] [Scalar: 0]
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %rem = srem i32 %i.0, 2
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %rem
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  store i32 %add, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_chain_partially_outside_the_scop.ll b/final/test/ScopInfo/reduction_chain_partially_outside_the_scop.ll
new file mode 100644
index 0000000..cf24df9
--- /dev/null
+++ b/final/test/ScopInfo/reduction_chain_partially_outside_the_scop.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Reduction Type: NONE
+;
+;    int c, d;
+;    void f(int *sum) {
+;      for (int i = 0; i < 1024; i++)
+;        *sum = c + d;
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+@c = common global i32 0, align 4
+@d = common global i32 0, align 4
+
+define void @loads_outside_scop(i32* %sum) {
+entry:
+  %tmp = load i32, i32* @c, align 4
+  %tmp1 = load i32, i32* @d, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add = add nsw i32 %tmp, %tmp1
+  store i32 %add, i32* %sum, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+
+define void @binop_outside_scop(i32* %sum) {
+entry:
+  %tmp = load i32, i32* @c, align 4
+  %tmp1 = load i32, i32* @d, align 4
+  %add = add nsw i32 %tmp, %tmp1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  store i32 %add, i32* %sum, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_disabled_multiplicative.ll b/final/test/ScopInfo/reduction_disabled_multiplicative.ll
new file mode 100644
index 0000000..5b97232
--- /dev/null
+++ b/final/test/ScopInfo/reduction_disabled_multiplicative.ll
@@ -0,0 +1,52 @@
+; RUN: opt -basicaa %loadPolly -polly-scops -analyze -polly-disable-multiplicative-reductions < %s | FileCheck %s
+;
+; CHECK: ReadAccess :=       [Reduction Type: +
+; CHECK:     { Stmt_for_body[i0] -> MemRef_sum[0] };
+; CHECK: MustWriteAccess :=  [Reduction Type: +
+; CHECK:     { Stmt_for_body[i0] -> MemRef_sum[0] };
+; CHECK: ReadAccess :=       [Reduction Type: NONE
+; CHECK:     { Stmt_for_body[i0] -> MemRef_prod[0] };
+; CHECK: MustWriteAccess :=  [Reduction Type: NONE
+; CHECK:     { Stmt_for_body[i0] -> MemRef_prod[0] };
+;
+; int sum, prod;
+; 
+; void f() {
+;   int i;
+;   for (int i = 0; i < 100; i++) {
+;     sum += i * 3;
+;     prod *= (i + 3);
+;   }
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+@sum = common global i32 0, align 4
+@prod = common global i32 0, align 4
+
+define void @f() #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i1.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i1.0, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %mul = mul nsw i32 %i1.0, 3
+  %tmp = load i32, i32* @sum, align 4
+  %add = add nsw i32 %tmp, %mul
+  store i32 %add, i32* @sum, align 4
+  %add2 = add nsw i32 %i1.0, 3
+  %tmp1 = load i32, i32* @prod, align 4
+  %mul3 = mul nsw i32 %tmp1, %add2
+  store i32 %mul3, i32* @prod, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i1.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_escaping_intermediate.ll b/final/test/ScopInfo/reduction_escaping_intermediate.ll
new file mode 100644
index 0000000..2e3ae6f
--- /dev/null
+++ b/final/test/ScopInfo/reduction_escaping_intermediate.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze < %s | FileCheck %s
+;
+; void f(int N, int * restrict sums, int * restrict escape) {
+;   int i, j;
+;   for (i = 0; i < 1024; i++) {
+;     for (j = 0; j < 1024; j++) {
+;       sums[i] += 5;
+;       escape[N - i + j] = sums[i];
+;     }
+;   }
+; }
+;
+; CHECK: Reduction Type: NONE
+; CHECK: sums
+; CHECK: Reduction Type: NONE
+; CHECK: sums
+; CHECK: Reduction Type: NONE
+; CHECK: escape
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32 %N, i32* noalias %sums, i32* noalias %escape) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc7, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc8, %for.inc7 ]
+  %exitcond1 = icmp ne i32 %i.0, 1024
+  br i1 %exitcond1, label %for.body, label %for.end9
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %sums, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 5
+  store i32 %add, i32* %arrayidx, align 4
+  %sub = sub nsw i32 %N, %i.0
+  %add5 = add nsw i32 %sub, %j.0
+  %arrayidx6 = getelementptr inbounds i32, i32* %escape, i32 %add5
+  store i32 %add, i32* %arrayidx6, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc7
+
+for.inc7:                                         ; preds = %for.end
+  %inc8 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end9:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_escaping_intermediate_2.ll b/final/test/ScopInfo/reduction_escaping_intermediate_2.ll
new file mode 100644
index 0000000..0dcefa4
--- /dev/null
+++ b/final/test/ScopInfo/reduction_escaping_intermediate_2.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze < %s | FileCheck %s
+;
+; void f(int N, int * restrict sums, int * restrict escape) {
+;   int i, j;
+;   for (i = 0; i < 1024; i++) {
+;     for (j = 0; j < 1024; j++) {
+;       sums[i] += 5;
+;       escape[N-j] = escape[i] + sums[i-1];
+;     }
+;   }
+; }
+;
+; CHECK: Reduction Type: NONE
+; CHECK: sums
+; CHECK: Reduction Type: NONE
+; CHECK: sums
+; CHECK: Reduction Type: NONE
+; CHECK: escape
+; CHECK: Reduction Type: NONE
+; CHECK: sums
+; CHECK: Reduction Type: NONE
+; CHECK: escape
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32 %N, i32* noalias %sums, i32* noalias %escape) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc10, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc11, %for.inc10 ]
+  %exitcond1 = icmp ne i32 %i.0, 1024
+  br i1 %exitcond1, label %for.body, label %for.end12
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %sums, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 5
+  store i32 %add, i32* %arrayidx, align 4
+  %arrayidx4 = getelementptr inbounds i32, i32* %escape, i32 %i.0
+  %tmp2 = load i32, i32* %arrayidx4, align 4
+  %sub = add nsw i32 %i.0, -1
+  %arrayidx5 = getelementptr inbounds i32, i32* %sums, i32 %sub
+  %tmp3 = load i32, i32* %arrayidx5, align 4
+  %add6 = add nsw i32 %tmp2, %tmp3
+  %sub7 = sub nsw i32 %N, %i.0
+  %add8 = add nsw i32 %sub7, %j.0
+  %arrayidx9 = getelementptr inbounds i32, i32* %escape, i32 %add8
+  store i32 %add6, i32* %arrayidx9, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.end
+  %inc11 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end12:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_invalid_different_operators.ll b/final/test/ScopInfo/reduction_invalid_different_operators.ll
new file mode 100644
index 0000000..052d594
--- /dev/null
+++ b/final/test/ScopInfo/reduction_invalid_different_operators.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze < %s | FileCheck %s
+;
+; int f() {
+;   int i, sum = 0, sth = 0;
+;   for (i = 0; i < 1024; i++) {
+;     sum += 5;
+;     sth = sth + sth * sth + sth;
+;     sum *= 5;
+;   }
+;   return sum + sth;
+; }
+;
+; CHECK-NOT: Reduction Type: +
+; CHECK-NOT: Reduction Type: *
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define i32 @f() {
+entry:
+  %sum.0 = alloca i32
+  %sth.0 = alloca i32
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  store i32 0, i32* %sum.0
+  store i32 0, i32* %sth.0
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry.split
+  %i.0 = phi i32 [ 0, %entry.split ], [ %inc, %for.cond ]
+  %sth.0.reload = load i32, i32* %sth.0
+  %sum.0.reload = load i32, i32* %sum.0
+  %exitcond = icmp ne i32 %i.0, 1024
+  %mul = mul nsw i32 %sth.0.reload, %sth.0.reload
+  %add1 = add nsw i32 %sth.0.reload, %mul
+  %tmp = mul i32 %sum.0.reload, 5
+  store i32 %tmp, i32* %sum.0
+  %sum.1.reload = load i32, i32* %sum.0
+  %mul3 = add i32 %sum.1.reload, 25
+  %add2 = add nsw i32 %add1, %sth.0.reload
+  %inc = add nsw i32 %i.0, 1
+  store i32 %mul3, i32* %sum.0
+  store i32 %add2, i32* %sth.0
+  br i1 %exitcond, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  %sum.0.reload.2 = load i32, i32* %sum.0
+  %sth.0.reload.2 = load i32, i32* %sth.0
+  %add4 = add nsw i32 %sum.0.reload.2, %sth.0.reload.2
+  ret i32 %add4
+}
diff --git a/final/test/ScopInfo/reduction_invalid_overlapping_accesses.ll b/final/test/ScopInfo/reduction_invalid_overlapping_accesses.ll
new file mode 100644
index 0000000..845f8e7
--- /dev/null
+++ b/final/test/ScopInfo/reduction_invalid_overlapping_accesses.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; void f(int *sums) {
+;   int i, j;
+;   for (i = 0; i < 1024; i++) {
+;     for (j = 0; j < 1024; j++) {
+;       sums[i] += 5;
+;       sums[i+10] *= 5;
+;     }
+;   }
+; }
+;
+; CHECK-NOT: Reduction Type: +
+; CHECK-NOT: Reduction Type: *
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sums) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc6, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc7, %for.inc6 ]
+  %exitcond1 = icmp ne i32 %i.0, 1024
+  br i1 %exitcond1, label %for.body, label %for.end8
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %sums, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 5
+  store i32 %add, i32* %arrayidx, align 4
+  %add4 = add nsw i32 %i.0, 10
+  %arrayidx5 = getelementptr inbounds i32, i32* %sums, i32 %add4
+  %tmp2 = load i32, i32* %arrayidx5, align 4
+  %mul = mul nsw i32 %tmp2, 5
+  store i32 %mul, i32* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc6
+
+for.inc6:                                         ; preds = %for.end
+  %inc7 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end8:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_multiple_loops_array_sum.ll b/final/test/ScopInfo/reduction_multiple_loops_array_sum.ll
new file mode 100644
index 0000000..6d1b166
--- /dev/null
+++ b/final/test/ScopInfo/reduction_multiple_loops_array_sum.ll
@@ -0,0 +1,78 @@
+; RUN: opt -basicaa %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Stmt_for_body
+; CHECK: Reduction Type: *
+; CHECK: MemRef_sum
+; CHECK: Reduction Type: *
+; CHECK: MemRef_sum
+; CHECK: Stmt_for_body3
+; CHECK: Reduction Type: NONE
+; CHECK: MemRef_A
+; CHECK: Reduction Type: +
+; CHECK: MemRef_sum
+; CHECK: Reduction Type: +
+; CHECK: MemRef_sum
+; CHECK: Stmt_for_end
+; CHECK: Reduction Type: *
+; CHECK: MemRef_sum
+; CHECK: Reduction Type: *
+; CHECK: MemRef_sum
+;
+; void f(int *restrict A, int *restrict sum) {
+;   int i, j;
+;   for (i = 0; i < 100; i++) {
+;     *sum *= 7;
+;     for (j = 0; j < 100; j++) {
+;       *sum += A[i + j];
+;     }
+;     *sum *= 5;
+;   }
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* noalias %A, i32* noalias %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc6, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc7, %for.inc6 ]
+  %exitcond1 = icmp ne i32 %i.0, 100
+  br i1 %exitcond1, label %for.body, label %for.end8
+
+for.body:                                         ; preds = %for.cond
+  %tmp = load i32, i32* %sum, align 4
+  %mul = mul nsw i32 %tmp, 7
+  store i32 %mul, i32* %sum, align 4
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 100
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %add = add nsw i32 %i.0, %j.0
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %add
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %tmp3 = load i32, i32* %sum, align 4
+  %add4 = add nsw i32 %tmp3, %tmp2
+  store i32 %add4, i32* %sum, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  %tmp4 = load i32, i32* %sum, align 4
+  %mul5 = mul nsw i32 %tmp4, 5
+  store i32 %mul5, i32* %sum, align 4
+  br label %for.inc6
+
+for.inc6:                                         ; preds = %for.end
+  %inc7 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end8:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_multiple_loops_array_sum_1.ll b/final/test/ScopInfo/reduction_multiple_loops_array_sum_1.ll
new file mode 100644
index 0000000..3188c4c
--- /dev/null
+++ b/final/test/ScopInfo/reduction_multiple_loops_array_sum_1.ll
@@ -0,0 +1,72 @@
+; RUN: opt -basicaa %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Stmt_for_body
+; CHECK: Reduction Type: NONE
+; CHECK: MemRef_sum_04
+; CHECK: Reduction Type: NONE
+; CHECK: MemRef_sum_12
+; CHECK: Stmt_for_inc
+; CHECK: Reduction Type: +
+; CHECK: MemRef_sum_12
+; CHECK: Reduction Type: NONE
+; CHECK: MemRef_A
+; CHECK: Reduction Type: +
+; CHECK: MemRef_sum_12
+; CHECK: Stmt_for_inc5
+; CHECK: Reduction Type: NONE
+; CHECK: MemRef_sum_12
+; CHECK: Reduction Type: NONE
+; CHECK: MemRef_sum_04
+;
+; int f(int * __restrict__ A) {
+;   int i, j, sum = 1;
+;   for (i = 0; i < 100; i++) {
+;     sum *= 7;
+;     for (j = 0; j < 100; j++) {
+;       sum += A[i+j];
+;     }
+;   }
+;   return sum;
+; }
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @f(i32* noalias %A) {
+entry:
+  %sum.04.reg2mem = alloca i32
+  %sum.12.reg2mem = alloca i32
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  store i32 0, i32* %sum.04.reg2mem
+  br label %for.body
+
+for.body:                                         ; preds = %for.inc5, %entry.split
+  %indvars.iv23 = phi i64 [ 0, %entry.split ], [ %3, %for.inc5 ]
+  %sum.04.reload = load i32, i32* %sum.04.reg2mem
+  %mul = mul nsw i32 %sum.04.reload, 7
+  store i32 %mul, i32* %sum.12.reg2mem
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.inc, %for.body
+  %indvars.iv1 = phi i64 [ 0, %for.body ], [ %1, %for.inc ]
+  %sum.12.reload = load i32, i32* %sum.12.reg2mem
+  %0 = add i64 %indvars.iv23, %indvars.iv1
+  %arrayidx = getelementptr i32, i32* %A, i64 %0
+  %tmp5 = load i32, i32* %arrayidx, align 4
+  %add4 = add nsw i32 %tmp5, %sum.12.reload
+  %1 = add nuw nsw i64 %indvars.iv1, 1
+  %exitcond1 = icmp eq i64 %1, 100
+  store i32 %add4, i32* %sum.12.reg2mem
+  br i1 %exitcond1, label %for.inc5, label %for.inc
+
+for.inc5:                                         ; preds = %for.inc
+  %2 = load i32, i32* %sum.12.reg2mem
+  %3 = add nuw nsw i64 %indvars.iv23, 1
+  %exitcond2 = icmp eq i64 %3, 100
+  store i32 %2, i32* %sum.04.reg2mem
+  br i1 %exitcond2, label %for.end7, label %for.body
+
+for.end7:                                         ; preds = %for.inc5
+  %4 = load i32, i32* %sum.04.reg2mem
+  ret i32 %4
+}
diff --git a/final/test/ScopInfo/reduction_multiple_simple_binary.ll b/final/test/ScopInfo/reduction_multiple_simple_binary.ll
new file mode 100644
index 0000000..7bce4fa
--- /dev/null
+++ b/final/test/ScopInfo/reduction_multiple_simple_binary.ll
@@ -0,0 +1,98 @@
+; RUN: opt -basicaa %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: ReadAccess :=       [Reduction Type: NONE
+; CHECK:     { Stmt_for_body[i0] -> MemRef_A[1 + i0] };
+; CHECK: ReadAccess :=       [Reduction Type: NONE
+; CHECK:     { Stmt_for_body[i0] -> MemRef_A[i0] };
+; CHECK: MustWriteAccess :=  [Reduction Type: NONE
+; CHECK:     { Stmt_for_body[i0] -> MemRef_first[0] };
+; CHECK: ReadAccess :=       [Reduction Type: +
+; CHECK:     { Stmt_for_body[i0] -> MemRef_sum[0] };
+; CHECK: MustWriteAccess :=  [Reduction Type: +
+; CHECK:     { Stmt_for_body[i0] -> MemRef_sum[0] };
+; CHECK: ReadAccess :=       [Reduction Type: NONE
+; CHECK:     { Stmt_for_body[i0] -> MemRef_A[-1 + i0] };
+; CHECK: ReadAccess :=       [Reduction Type: NONE
+; CHECK:     { Stmt_for_body[i0] -> MemRef_A[i0] };
+; CHECK: MustWriteAccess :=  [Reduction Type: NONE
+; CHECK:     { Stmt_for_body[i0] -> MemRef_middle[0] };
+; CHECK: ReadAccess :=       [Reduction Type: *
+; CHECK:     { Stmt_for_body[i0] -> MemRef_prod[0] };
+; CHECK: MustWriteAccess :=  [Reduction Type: *
+; CHECK:     { Stmt_for_body[i0] -> MemRef_prod[0] };
+; CHECK: ReadAccess :=       [Reduction Type: NONE
+; CHECK:     { Stmt_for_body[i0] -> MemRef_A[-1 + i0] };
+; CHECK: ReadAccess :=       [Reduction Type: NONE
+; CHECK:     { Stmt_for_body[i0] -> MemRef_A[1 + i0] };
+; CHECK: MustWriteAccess :=  [Reduction Type: NONE
+; CHECK:     { Stmt_for_body[i0] -> MemRef_last[0] };
+;
+; int first, sum, middle, prod, last;
+;
+; void f(int * restrict A) {
+;   int i;
+;   for (int i = 0; i < 100; i++) {
+;     first = A[i+1] + A[i];
+;     sum += i * 3;
+;     middle = A[i-1] + A[i];
+;     prod *= (i + 3);
+;     last = A[i-1] + A[i+1];
+;   }
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+@first = common global i32 0, align 4
+@sum = common global i32 0, align 4
+@middle = common global i32 0, align 4
+@prod = common global i32 0, align 4
+@last = common global i32 0, align 4
+
+define void @f(i32* noalias %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i1.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i1.0, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %add = add nsw i32 %i1.0, 1
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %add
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i32 %i1.0
+  %tmp1 = load i32, i32* %arrayidx2, align 4
+  %add3 = add nsw i32 %tmp, %tmp1
+  store i32 %add3, i32* @first, align 4
+  %mul = mul nsw i32 %i1.0, 3
+  %tmp2 = load i32, i32* @sum, align 4
+  %add4 = add nsw i32 %tmp2, %mul
+  store i32 %add4, i32* @sum, align 4
+  %sub = add nsw i32 %i1.0, -1
+  %arrayidx5 = getelementptr inbounds i32, i32* %A, i32 %sub
+  %tmp3 = load i32, i32* %arrayidx5, align 4
+  %arrayidx6 = getelementptr inbounds i32, i32* %A, i32 %i1.0
+  %tmp4 = load i32, i32* %arrayidx6, align 4
+  %add7 = add nsw i32 %tmp3, %tmp4
+  store i32 %add7, i32* @middle, align 4
+  %add8 = add nsw i32 %i1.0, 3
+  %tmp5 = load i32, i32* @prod, align 4
+  %mul9 = mul nsw i32 %tmp5, %add8
+  store i32 %mul9, i32* @prod, align 4
+  %sub10 = add nsw i32 %i1.0, -1
+  %arrayidx11 = getelementptr inbounds i32, i32* %A, i32 %sub10
+  %tmp6 = load i32, i32* %arrayidx11, align 4
+  %add12 = add nsw i32 %i1.0, 1
+  %arrayidx13 = getelementptr inbounds i32, i32* %A, i32 %add12
+  %tmp7 = load i32, i32* %arrayidx13, align 4
+  %add14 = add nsw i32 %tmp6, %tmp7
+  store i32 %add14, i32* @last, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i1.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_non_overlapping_chains.ll b/final/test/ScopInfo/reduction_non_overlapping_chains.ll
new file mode 100644
index 0000000..e1f0df1
--- /dev/null
+++ b/final/test/ScopInfo/reduction_non_overlapping_chains.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Reduction Type: +
+; CHECK: Reduction Type: +
+; CHECK: Reduction Type: *
+; CHECK: Reduction Type: *
+;
+; void f(int *sums) {
+;   for (int i = 0; i < 1024; i++) {
+;     for (int j = 0; j < 1024; j++) {
+;       sums[i] += 5;
+;       sums[i+1024] *= 5;
+;     }
+;   }
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sums) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc6, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc7, %for.inc6 ]
+  %exitcond1 = icmp ne i32 %i.0, 1024
+  br i1 %exitcond1, label %for.body, label %for.end8
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 1024
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %arrayidx = getelementptr inbounds i32, i32* %sums, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, 5
+  store i32 %add, i32* %arrayidx, align 4
+  %add4 = add nsw i32 %i.0, 1024
+  %arrayidx5 = getelementptr inbounds i32, i32* %sums, i32 %add4
+  %tmp2 = load i32, i32* %arrayidx5, align 4
+  %mul = mul nsw i32 %tmp2, 5
+  store i32 %mul, i32* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %inc = add nsw i32 %j.0, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc6
+
+for.inc6:                                         ; preds = %for.end
+  %inc7 = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end8:                                         ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_only_reduction_like_access.ll b/final/test/ScopInfo/reduction_only_reduction_like_access.ll
new file mode 100644
index 0000000..ad89f6d
--- /dev/null
+++ b/final/test/ScopInfo/reduction_only_reduction_like_access.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Reduction Type: +
+;
+; void f(int *sum) {
+;   for (int i = 0; i < 100; i++)
+;     sum[i] = sum[99-i] + i;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %sub = sub nsw i32 99, %i.0
+  %arrayidx = getelementptr inbounds i32, i32* %sum, i32 %sub
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %i.0
+  %arrayidx1 = getelementptr inbounds i32, i32* %sum, i32 %i.0
+  store i32 %add, i32* %arrayidx1, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_simple_fp.ll b/final/test/ScopInfo/reduction_simple_fp.ll
new file mode 100644
index 0000000..dd117c9
--- /dev/null
+++ b/final/test/ScopInfo/reduction_simple_fp.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Function: f_no_fast_math
+; CHECK: Reduction Type: NONE
+; CHECK: Function: f_fast_math
+; CHECK: Reduction Type: +
+;
+; void f(float *sum) {
+;   for (int i = 0; i < 100; i++)
+;     *sum += 3.41 * i;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f_no_fast_math(float* %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %conv = sitofp i32 %i.0 to float
+  %pi = fptrunc double 3.41 to float
+  %mul = fmul float %conv, %pi
+  %tmp = load float, float* %sum, align 4
+  %add = fadd float %tmp, %mul
+  store float %add, float* %sum, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+define void @f_fast_math(float* %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %conv = sitofp i32 %i.0 to float
+  %pi = fptrunc double 3.41 to float
+  %mul = fmul fast float %conv, %pi
+  %tmp = load float, float* %sum, align 4
+  %add = fadd fast float %tmp, %mul
+  store float %add, float* %sum, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_simple_w_constant.ll b/final/test/ScopInfo/reduction_simple_w_constant.ll
new file mode 100644
index 0000000..6d9fa4b
--- /dev/null
+++ b/final/test/ScopInfo/reduction_simple_w_constant.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Reduction Type: +
+;
+; void f(int *sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += 3;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entry
+  %i1.0 = phi i32 [ 0, %entry ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %add = add nsw i32 %sum.reload, 3
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_simple_w_iv.ll b/final/test/ScopInfo/reduction_simple_w_iv.ll
new file mode 100644
index 0000000..7c37472
--- /dev/null
+++ b/final/test/ScopInfo/reduction_simple_w_iv.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Reduction Type: +
+;
+; void f(int* sum) {
+;   for (int i = 0; i <= 100; i++)
+;     sum += i * 3;
+; }
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f(i32* %sum) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.cond, %entr
+  %i1.0 = phi i32 [ 0, %entry ], [ %inc, %for.cond ]
+  %sum.reload = load i32, i32* %sum
+  %mul = mul nsw i32 %i1.0, 3
+  %add = add nsw i32 %sum.reload, %mul
+  %inc = add nsw i32 %i1.0, 1
+  store i32 %add, i32* %sum
+  %cmp = icmp slt i32 %i1.0, 100
+  br i1 %cmp, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/reduction_two_identical_reads.ll b/final/test/ScopInfo/reduction_two_identical_reads.ll
new file mode 100644
index 0000000..1937e73
--- /dev/null
+++ b/final/test/ScopInfo/reduction_two_identical_reads.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-function-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Reduction Type: NONE
+;
+; Check that we do not mark these accesses as reduction like.
+; We do this for the case the loads are modelt with the same LLVM-IR value and
+; for the case there are different LLVM-IR values.
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++)
+;        A[i] = A[i] + A[i];
+;    }
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
+
+define void @f_one_load_case(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp, %tmp
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i32 %i.0
+  store i32 %add, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+define void @f_two_loads_case(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmp = load i32, i32* %arrayidx, align 4
+  %arrayidxCopy = getelementptr inbounds i32, i32* %A, i32 %i.0
+  %tmpCopy = load i32, i32* %arrayidxCopy, align 4
+  %add = add nsw i32 %tmp, %tmpCopy
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i32 %i.0
+  store i32 %add, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/redundant_parameter_constraint.ll b/final/test/ScopInfo/redundant_parameter_constraint.ll
new file mode 100644
index 0000000..4ab055f
--- /dev/null
+++ b/final/test/ScopInfo/redundant_parameter_constraint.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; The constraint that r2 has to be bigger than r1 is implicitly containted in
+; the domain, hence we do not want to see it explicitly.
+;
+; CHECK-NOT:  r2 >= 1 + r1 
+;
+;    void wraps(int *A, int p, short q, char r1, char r2) {
+;      for (char i = r1; i < r2; i++)
+;        A[p + q] = A[(int)r1 + (int)r2];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @wraps(i32* %A, i32 %p, i16 signext %q, i8 signext %r1, i8 signext %r2) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i8 [ %r1, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp slt i8 %i.0, %r2
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %conv3 = sext i8 %r1 to i64
+  %conv4 = sext i8 %r2 to i64
+  %add = add nsw i64 %conv3, %conv4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %add
+  %tmp = load i32, i32* %arrayidx, align 4
+  %conv5 = sext i16 %q to i32
+  %add6 = add nsw i32 %conv5, %p
+  %idxprom7 = sext i32 %add6 to i64
+  %arrayidx8 = getelementptr inbounds i32, i32* %A, i64 %idxprom7
+  store i32 %tmp, i32* %arrayidx8, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add i8 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/region-with-instructions.ll b/final/test/ScopInfo/region-with-instructions.ll
new file mode 100644
index 0000000..b6d2965
--- /dev/null
+++ b/final/test/ScopInfo/region-with-instructions.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-print-instructions \
+; RUN:     < %s | FileCheck %s
+
+; CHECK: Statements {
+; CHECK: 	Stmt_bb46
+; CHECK:         Domain :=
+; CHECK:             [tmp44, tmp9] -> { Stmt_bb46[] : tmp9 = tmp44 };
+; CHECK:         Schedule :=
+; CHECK:             [tmp44, tmp9] -> { Stmt_bb46[] -> [0, 0] };
+; CHECK:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK:             [tmp44, tmp9] -> { Stmt_bb46[] -> MemRef_tmp47[] };
+; CHECK:         Instructions {
+; CHECK:               %tmp47 = or i64 1, %tmp14
+; CHECK:         }
+; CHECK: 	Stmt_bb48__TO__bb56
+; CHECK:         Domain :=
+; CHECK:             [tmp44, tmp9] -> { Stmt_bb48__TO__bb56[i0] : tmp9 = tmp44 and 0 <= i0 < tmp44 };
+; CHECK:         Schedule :=
+; CHECK:             [tmp44, tmp9] -> { Stmt_bb48__TO__bb56[i0] -> [1, i0] };
+; CHECK:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:             [tmp44, tmp9] -> { Stmt_bb48__TO__bb56[i0] -> MemRef_A[i0] };
+; CHECK:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:             [tmp44, tmp9] -> { Stmt_bb48__TO__bb56[i0] -> MemRef_A[i0] };
+; CHECK:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK:             [tmp44, tmp9] -> { Stmt_bb48__TO__bb56[i0] -> MemRef_tmp47[] };
+; CHECK:         MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:             [tmp44, tmp9] -> { Stmt_bb48__TO__bb56[i0] -> MemRef_A[i0] };
+; CHECK:         Instructions {
+; CHECK:               %tmp51 = load i64, i64* %tmp50, align 8
+; CHECK:               %tmp52 = and i64 %tmp51, %tmp26
+; CHECK:               %tmp53 = icmp eq i64 %tmp52, %tmp26
+; CHECK:               store i64 42, i64* %tmp50, align 8
+; CHECK:         }
+; CHECK: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @quux(i32 %arg, i32 %arg1, i64* %A, i64 %tmp9, i64 %tmp24, i64 %tmp14, i64 %tmp22, i64 %tmp44) {
+bb:
+  %tmp26 = or i64 %tmp22, %tmp24
+  br label %bb39
+
+bb39:                                             ; preds = %bb39, %bb38
+  %tmp45 = icmp eq i64 %tmp44, %tmp9
+  br i1 %tmp45, label %bb46, label %bb81
+
+bb46:                                             ; preds = %bb39
+  %tmp47 = or i64 1, %tmp14
+  br label %bb48
+
+bb48:                                             ; preds = %bb56, %bb46
+  %tmp49 = phi i64 [ 0, %bb46 ], [ %tmp57, %bb56 ]
+  %tmp50 = getelementptr inbounds i64, i64* %A, i64 %tmp49
+  %tmp51 = load i64, i64* %tmp50, align 8
+  %tmp52 = and i64 %tmp51, %tmp26
+  %tmp53 = icmp eq i64 %tmp52, %tmp26
+  store i64 42, i64* %tmp50, align 8
+  br i1 %tmp53, label %bb54, label %bb56
+
+bb54:                                             ; preds = %bb48
+  %tmp55 = xor i64 %tmp51, %tmp47
+  store i64 %tmp55, i64* %tmp50, align 8
+  br label %bb56
+
+bb56:                                             ; preds = %bb54, %bb48
+  %tmp57 = add nuw nsw i64 %tmp49, 1
+  %tmp58 = icmp eq i64 %tmp57, %tmp9
+  br i1 %tmp58, label %bb81, label %bb48
+
+bb81:                                             ; preds = %bb74, %bb56
+  ret void
+}
diff --git a/final/test/ScopInfo/remarks.ll b/final/test/ScopInfo/remarks.ll
new file mode 100644
index 0000000..316f3f1
--- /dev/null
+++ b/final/test/ScopInfo/remarks.ll
@@ -0,0 +1,317 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops \
+; RUN: -polly-invariant-load-hoisting=true -disable-output < %s 2>&1 | FileCheck %s
+;
+; CHECK: remark: test/ScopInfo/remarks.c:4:7: SCoP begins here.
+; CHECK: remark: test/ScopInfo/remarks.c:9:15: Inbounds assumption:    [N, M, Debug] -> {  : M <= 100 }
+; CHECK: remark: test/ScopInfo/remarks.c:13:7: No-error restriction:    [N, M, Debug] -> {  : N > 0 and M >= 0 and (Debug < 0 or Debug > 0) }
+; CHECK: remark: test/ScopInfo/remarks.c:8:5: Finite loop restriction:    [N, M, Debug] -> {  : N > 0 and (M <= -2 or M = -1) }
+; CHECK: remark: test/ScopInfo/remarks.c:4:7: No-overflows restriction:    [N, M, Debug] -> {  : M <= -2147483649 - N or M >= 2147483648 - N }
+; CHECK: remark: test/ScopInfo/remarks.c:9:18: Possibly aliasing pointer, use restrict keyword.
+; CHECK: remark: test/ScopInfo/remarks.c:9:33: Possibly aliasing pointer, use restrict keyword.
+; CHECK: remark: test/ScopInfo/remarks.c:9:15: Possibly aliasing pointer, use restrict keyword.
+; CHECK: remark: test/ScopInfo/remarks.c:14:3: SCoP ends here.
+; CHECK: remark: test/ScopInfo/remarks.c:19:3: SCoP begins here.
+; CHECK: remark: test/ScopInfo/remarks.c:21:11: Invariant load restriction:    [tmp] -> {  : tmp < 0 or tmp > 0 }
+; CHECK: remark: test/ScopInfo/remarks.c:22:16: SCoP ends here but was dismissed.
+;
+;    #include <stdio.h>
+;
+;    void valid(int *A, int *B, int N, int M, int C[100][100], int Debug) {
+;      if (N + M == -1)
+;        C[0][0] = 0;
+;
+;      for (int i = 0; i < N; i++) {
+;        for (int j = 0; j != M; j++) {
+;          C[i][j] += A[i * M + j] + B[i + j];
+;        }
+;
+;        if (Debug)
+;          printf("Printf!");
+;      }
+;    }
+;
+;    void invalid0(int *A) {
+;      for (int i = 0; i < 10; i++)
+;        for (int j = 0; j < 10; j++)
+;          if (A[0])
+;            A[0] = 0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@.str = private unnamed_addr constant [8 x i8] c"Printf!\00", align 1
+
+define void @valid(i32* %A, i32* %B, i32 %N, i32 %M, [100 x i32]* %C, i32 %Debug) #0 !dbg !4 {
+entry:
+  call void @llvm.dbg.value(metadata i32* %A, i64 0, metadata !23, metadata !24), !dbg !25
+  call void @llvm.dbg.value(metadata i32* %B, i64 0, metadata !26, metadata !24), !dbg !27
+  call void @llvm.dbg.value(metadata i32 %N, i64 0, metadata !28, metadata !24), !dbg !29
+  call void @llvm.dbg.value(metadata i32 %M, i64 0, metadata !30, metadata !24), !dbg !31
+  call void @llvm.dbg.value(metadata [100 x i32]* %C, i64 0, metadata !32, metadata !24), !dbg !33
+  call void @llvm.dbg.value(metadata i32 %Debug, i64 0, metadata !34, metadata !24), !dbg !35
+  br label %entry.split
+
+entry.split:
+  %add = add i32 %N, %M, !dbg !36
+  %cmp = icmp eq i32 %add, -1, !dbg !38
+  br i1 %cmp, label %if.then, label %if.end, !dbg !39
+
+if.then:                                          ; preds = %entry
+  %arrayidx1 = getelementptr inbounds [100 x i32], [100 x i32]* %C, i64 0, i64 0, !dbg !40
+  store i32 0, i32* %arrayidx1, align 4, !dbg !41
+  br label %if.end, !dbg !40
+
+if.end:                                           ; preds = %if.then, %entry
+  call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !42, metadata !24), !dbg !44
+  %N64 = sext i32 %N to i64, !dbg !45
+  %M64 = sext i32 %M to i64, !dbg !45
+  br label %for.cond, !dbg !45
+
+for.cond:                                         ; preds = %for.inc.19, %if.end
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc.19 ], [ 0, %if.end ]
+  %cmp2 = icmp slt i64 %indvars.iv3, %N64, !dbg !46
+  br i1 %cmp2, label %for.body, label %for.end.21, !dbg !49
+
+for.body:                                         ; preds = %for.cond
+  call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !50, metadata !24), !dbg !53
+  br label %for.cond.3, !dbg !54
+
+for.cond.3:                                       ; preds = %for.inc, %for.body
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %for.body ]
+  %cmp4 = icmp eq i64 %indvars.iv, %M64, !dbg !55
+  br i1 %cmp4, label %for.end, label %for.body.5, !dbg !58
+
+for.body.5:                                       ; preds = %for.cond.3
+  %tmp8 = mul i64 %indvars.iv3, %M64, !dbg !59
+  %tmp9 = add i64 %tmp8, %indvars.iv, !dbg !61
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i64 %tmp9, !dbg !62
+  %tmp10 = load i32, i32* %arrayidx7, align 4, !dbg !62
+  %tmp11 = add i64 %indvars.iv3, %indvars.iv, !dbg !63
+  %arrayidx10 = getelementptr inbounds i32, i32* %B, i64 %tmp11, !dbg !64
+  %tmp12 = load i32, i32* %arrayidx10, align 4, !dbg !64
+  %add11 = add i32 %tmp10, %tmp12, !dbg !65
+  %arrayidx15 = getelementptr inbounds [100 x i32], [100 x i32]* %C, i64 %indvars.iv3, i64 %indvars.iv, !dbg !66
+  %tmp13 = load i32, i32* %arrayidx15, align 4, !dbg !67
+  %add16 = add i32 %tmp13, %add11, !dbg !67
+  store i32 %add16, i32* %arrayidx15, align 4, !dbg !67
+  br label %for.inc, !dbg !68
+
+for.inc:                                          ; preds = %for.body.5
+  %indvars.iv.next = add i64 %indvars.iv, 1, !dbg !69
+  call void @llvm.dbg.value(metadata !2, i64 0, metadata !50, metadata !24), !dbg !53
+  br label %for.cond.3, !dbg !69
+
+for.end:                                          ; preds = %for.cond.3
+  %tobool = icmp eq i32 %Debug, 0, !dbg !70
+  br i1 %tobool, label %if.end.18, label %if.then.17, !dbg !72
+
+if.then.17:                                       ; preds = %for.end
+  %call = call i32 (i8*, ...) @printf(i8* nonnull getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0)) #3, !dbg !73
+  br label %if.end.18, !dbg !73
+
+if.end.18:                                        ; preds = %for.end, %if.then.17
+  br label %for.inc.19, !dbg !74
+
+for.inc.19:                                       ; preds = %if.end.18
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1, !dbg !75
+  call void @llvm.dbg.value(metadata !2, i64 0, metadata !42, metadata !24), !dbg !44
+  br label %for.cond, !dbg !75
+
+for.end.21:                                       ; preds = %for.cond
+  ret void, !dbg !76
+}
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+declare i32 @printf(i8*, ...) #2
+
+define void @invalid0(i32* %A) #0 !dbg !13 {
+entry:
+  call void @llvm.dbg.value(metadata i32* %A, i64 0, metadata !77, metadata !24), !dbg !78
+  call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !79, metadata !24), !dbg !81
+  br label %for.cond, !dbg !82
+
+for.cond:                                         ; preds = %for.inc.5, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc6, %for.inc.5 ]
+  %exitcond1 = icmp ne i32 %i.0, 10, !dbg !83
+  br i1 %exitcond1, label %for.body, label %for.end.7, !dbg !83
+
+for.body:                                         ; preds = %for.cond
+  call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !86, metadata !24), !dbg !88
+  br label %for.cond.1, !dbg !89
+
+for.cond.1:                                       ; preds = %for.inc, %for.body
+  %j.0 = phi i32 [ 0, %for.body ], [ %inc, %for.inc ]
+  %exitcond = icmp ne i32 %j.0, 10, !dbg !90
+  br i1 %exitcond, label %for.body.3, label %for.end, !dbg !90
+
+for.body.3:                                       ; preds = %for.cond.1
+  %tmp = load i32, i32* %A, align 4, !dbg !93
+  %tobool = icmp eq i32 %tmp, 0, !dbg !93
+  br i1 %tobool, label %if.end, label %if.then, !dbg !95
+
+if.then:                                          ; preds = %for.body.3
+  store i32 0, i32* %A, align 4, !dbg !96
+  br label %if.end, !dbg !97
+
+if.end:                                           ; preds = %for.body.3, %if.then
+  br label %for.inc, !dbg !98
+
+for.inc:                                          ; preds = %if.end
+  %inc = add nuw nsw i32 %j.0, 1, !dbg !100
+  call void @llvm.dbg.value(metadata i32 %inc, i64 0, metadata !86, metadata !24), !dbg !88
+  br label %for.cond.1, !dbg !101
+
+for.end:                                          ; preds = %for.cond.1
+  br label %for.inc.5, !dbg !102
+
+for.inc.5:                                        ; preds = %for.end
+  %inc6 = add nuw nsw i32 %i.0, 1, !dbg !103
+  call void @llvm.dbg.value(metadata i32 %inc6, i64 0, metadata !79, metadata !24), !dbg !81
+  br label %for.cond, !dbg !104
+
+for.end.7:                                        ; preds = %for.cond
+  ret void, !dbg !105
+}
+
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!20, !21}
+!llvm.ident = !{!22}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (http://llvm.org/git/clang.git 65eeefc97d2eee4d075ec7d9ed56b5f0786b6421)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2)
+!1 = !DIFile(filename: "test/ScopInfo/remarks.c", directory: "/home/johannes/repos/llvm-polly/tools/polly")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "valid", scope: !1, file: !1, line: 3, type: !5, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null, !7, !7, !8, !8, !9, !8}
+!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64, align: 64)
+!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64, align: 64)
+!10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 3200, align: 32, elements: !11)
+!11 = !{!12}
+!12 = !DISubrange(count: 100)
+!13 = distinct !DISubprogram(name: "invalid0", scope: !1, file: !1, line: 18, type: !14, isLocal: false, isDefinition: true, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!14 = !DISubroutineType(types: !15)
+!15 = !{null, !7}
+!16 = distinct !DISubprogram(name: "invalid1", scope: !1, file: !1, line: 25, type: !17, isLocal: false, isDefinition: true, scopeLine: 25, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!17 = !DISubroutineType(types: !18)
+!18 = !{null, !19, !19}
+!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64, align: 64)
+!20 = !{i32 2, !"Dwarf Version", i32 4}
+!21 = !{i32 2, !"Debug Info Version", i32 3}
+!22 = !{!"clang version 3.8.0 (http://llvm.org/git/clang.git 65eeefc97d2eee4d075ec7d9ed56b5f0786b6421)"}
+!23 = !DILocalVariable(name: "A", arg: 1, scope: !4, file: !1, line: 3, type: !7)
+!24 = !DIExpression()
+!25 = !DILocation(line: 3, column: 17, scope: !4)
+!26 = !DILocalVariable(name: "B", arg: 2, scope: !4, file: !1, line: 3, type: !7)
+!27 = !DILocation(line: 3, column: 25, scope: !4)
+!28 = !DILocalVariable(name: "N", arg: 3, scope: !4, file: !1, line: 3, type: !8)
+!29 = !DILocation(line: 3, column: 32, scope: !4)
+!30 = !DILocalVariable(name: "M", arg: 4, scope: !4, file: !1, line: 3, type: !8)
+!31 = !DILocation(line: 3, column: 39, scope: !4)
+!32 = !DILocalVariable(name: "C", arg: 5, scope: !4, file: !1, line: 3, type: !9)
+!33 = !DILocation(line: 3, column: 46, scope: !4)
+!34 = !DILocalVariable(name: "Debug", arg: 6, scope: !4, file: !1, line: 3, type: !8)
+!35 = !DILocation(line: 3, column: 63, scope: !4)
+!36 = !DILocation(line: 4, column: 9, scope: !37)
+!37 = distinct !DILexicalBlock(scope: !4, file: !1, line: 4, column: 7)
+!38 = !DILocation(line: 4, column: 13, scope: !37)
+!39 = !DILocation(line: 4, column: 7, scope: !4)
+!40 = !DILocation(line: 5, column: 5, scope: !37)
+!41 = !DILocation(line: 5, column: 13, scope: !37)
+!42 = !DILocalVariable(name: "i", scope: !43, file: !1, line: 7, type: !8)
+!43 = distinct !DILexicalBlock(scope: !4, file: !1, line: 7, column: 3)
+!44 = !DILocation(line: 7, column: 12, scope: !43)
+!45 = !DILocation(line: 7, column: 8, scope: !43)
+!46 = !DILocation(line: 7, column: 21, scope: !47)
+!47 = !DILexicalBlockFile(scope: !48, file: !1, discriminator: 1)
+!48 = distinct !DILexicalBlock(scope: !43, file: !1, line: 7, column: 3)
+!49 = !DILocation(line: 7, column: 3, scope: !47)
+!50 = !DILocalVariable(name: "j", scope: !51, file: !1, line: 8, type: !8)
+!51 = distinct !DILexicalBlock(scope: !52, file: !1, line: 8, column: 5)
+!52 = distinct !DILexicalBlock(scope: !48, file: !1, line: 7, column: 31)
+!53 = !DILocation(line: 8, column: 14, scope: !51)
+!54 = !DILocation(line: 8, column: 10, scope: !51)
+!55 = !DILocation(line: 8, column: 23, scope: !56)
+!56 = !DILexicalBlockFile(scope: !57, file: !1, discriminator: 1)
+!57 = distinct !DILexicalBlock(scope: !51, file: !1, line: 8, column: 5)
+!58 = !DILocation(line: 8, column: 5, scope: !56)
+!59 = !DILocation(line: 9, column: 22, scope: !60)
+!60 = distinct !DILexicalBlock(scope: !57, file: !1, line: 8, column: 34)
+!61 = !DILocation(line: 9, column: 26, scope: !60)
+!62 = !DILocation(line: 9, column: 18, scope: !60)
+!63 = !DILocation(line: 9, column: 37, scope: !60)
+!64 = !DILocation(line: 9, column: 33, scope: !60)
+!65 = !DILocation(line: 9, column: 31, scope: !60)
+!66 = !DILocation(line: 9, column: 7, scope: !60)
+!67 = !DILocation(line: 9, column: 15, scope: !60)
+!68 = !DILocation(line: 10, column: 5, scope: !60)
+!69 = !DILocation(line: 8, column: 5, scope: !57)
+!70 = !DILocation(line: 12, column: 9, scope: !71)
+!71 = distinct !DILexicalBlock(scope: !52, file: !1, line: 12, column: 9)
+!72 = !DILocation(line: 12, column: 9, scope: !52)
+!73 = !DILocation(line: 13, column: 7, scope: !71)
+!74 = !DILocation(line: 14, column: 3, scope: !52)
+!75 = !DILocation(line: 7, column: 3, scope: !48)
+!76 = !DILocation(line: 16, column: 1, scope: !4)
+!77 = !DILocalVariable(name: "A", arg: 1, scope: !13, file: !1, line: 18, type: !7)
+!78 = !DILocation(line: 18, column: 20, scope: !13)
+!79 = !DILocalVariable(name: "i", scope: !80, file: !1, line: 19, type: !8)
+!80 = distinct !DILexicalBlock(scope: !13, file: !1, line: 19, column: 3)
+!81 = !DILocation(line: 19, column: 12, scope: !80)
+!82 = !DILocation(line: 19, column: 8, scope: !80)
+!83 = !DILocation(line: 19, column: 3, scope: !84)
+!84 = !DILexicalBlockFile(scope: !85, file: !1, discriminator: 1)
+!85 = distinct !DILexicalBlock(scope: !80, file: !1, line: 19, column: 3)
+!86 = !DILocalVariable(name: "j", scope: !87, file: !1, line: 20, type: !8)
+!87 = distinct !DILexicalBlock(scope: !85, file: !1, line: 20, column: 5)
+!88 = !DILocation(line: 20, column: 14, scope: !87)
+!89 = !DILocation(line: 20, column: 10, scope: !87)
+!90 = !DILocation(line: 20, column: 5, scope: !91)
+!91 = !DILexicalBlockFile(scope: !92, file: !1, discriminator: 1)
+!92 = distinct !DILexicalBlock(scope: !87, file: !1, line: 20, column: 5)
+!93 = !DILocation(line: 21, column: 11, scope: !94)
+!94 = distinct !DILexicalBlock(scope: !92, file: !1, line: 21, column: 11)
+!95 = !DILocation(line: 21, column: 11, scope: !92)
+!96 = !DILocation(line: 22, column: 14, scope: !94)
+!97 = !DILocation(line: 22, column: 9, scope: !94)
+!98 = !DILocation(line: 21, column: 14, scope: !99)
+!99 = !DILexicalBlockFile(scope: !94, file: !1, discriminator: 1)
+!100 = !DILocation(line: 20, column: 30, scope: !92)
+!101 = !DILocation(line: 20, column: 5, scope: !92)
+!102 = !DILocation(line: 22, column: 16, scope: !87)
+!103 = !DILocation(line: 19, column: 28, scope: !85)
+!104 = !DILocation(line: 19, column: 3, scope: !85)
+!105 = !DILocation(line: 23, column: 1, scope: !13)
+!106 = !DILocalVariable(name: "A", arg: 1, scope: !16, file: !1, line: 25, type: !19)
+!107 = !DILocation(line: 25, column: 21, scope: !16)
+!108 = !DILocalVariable(name: "B", arg: 2, scope: !16, file: !1, line: 25, type: !19)
+!109 = !DILocation(line: 25, column: 30, scope: !16)
+!110 = !DILocalVariable(name: "i", scope: !111, file: !1, line: 26, type: !8)
+!111 = distinct !DILexicalBlock(scope: !16, file: !1, line: 26, column: 3)
+!112 = !DILocation(line: 26, column: 12, scope: !111)
+!113 = !DILocation(line: 26, column: 8, scope: !111)
+!114 = !DILocation(line: 26, column: 3, scope: !115)
+!115 = !DILexicalBlockFile(scope: !116, file: !1, discriminator: 1)
+!116 = distinct !DILexicalBlock(scope: !111, file: !1, line: 26, column: 3)
+!117 = !DILocalVariable(name: "j", scope: !118, file: !1, line: 27, type: !8)
+!118 = distinct !DILexicalBlock(scope: !116, file: !1, line: 27, column: 5)
+!119 = !DILocation(line: 27, column: 14, scope: !118)
+!120 = !DILocation(line: 27, column: 10, scope: !118)
+!121 = !DILocation(line: 27, column: 5, scope: !122)
+!122 = !DILexicalBlockFile(scope: !123, file: !1, discriminator: 1)
+!123 = distinct !DILexicalBlock(scope: !118, file: !1, line: 27, column: 5)
+!124 = !DILocation(line: 28, column: 17, scope: !123)
+!125 = !DILocation(line: 28, column: 7, scope: !123)
+!126 = !DILocation(line: 28, column: 15, scope: !123)
+!127 = !DILocation(line: 27, column: 5, scope: !123)
+!128 = !DILocation(line: 28, column: 23, scope: !118)
+!129 = !DILocation(line: 26, column: 3, scope: !116)
+!130 = !DILocation(line: 29, column: 1, scope: !16)
diff --git a/final/test/ScopInfo/required-invariant-loop-bounds.ll b/final/test/ScopInfo/required-invariant-loop-bounds.ll
new file mode 100644
index 0000000..0230a84
--- /dev/null
+++ b/final/test/ScopInfo/required-invariant-loop-bounds.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:       ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:         MemRef_bounds[0]
+; CHECK-NEXT: Execution Context: [bounds0, bounds1] -> {  :  }
+; CHECK-NEXT:       ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:         MemRef_bounds[1]
+; CHECK-NEXT: Execution Context: [bounds0, bounds1] -> {  :  }
+; CHECK:      }
+
+;    double A[1000][1000];
+;    long bounds[2];
+;
+;    void foo() {
+;
+;      for (long i = 0; i <= bounds[0]; i++)
+;        for (long j = 0; j <= bounds[1]; j++)
+;          A[i][j] += i + j;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@bounds = common global [2 x i64] zeroinitializer, align 16
+@A = common global [1000 x [1000 x double]] zeroinitializer, align 16
+
+define void @foo() {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.6, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc7, %for.inc.6 ]
+  %bounds0 = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @bounds, i64 0, i64 0), align 16
+  %cmp = icmp sgt i64 %i.0, %bounds0
+  br i1 %cmp, label %for.end.8, label %for.body
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond.1
+
+for.cond.1:                                       ; preds = %for.inc, %for.body
+  %j.0 = phi i64 [ 0, %for.body ], [ %inc, %for.inc ]
+  %bounds1 = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @bounds, i64 0, i64 1), align 8
+  %cmp2 = icmp sgt i64 %j.0, %bounds1
+  br i1 %cmp2, label %for.end, label %for.body.3
+
+for.body.3:                                       ; preds = %for.cond.1
+  %add = add nsw i64 %i.0, %j.0
+  %conv = sitofp i64 %add to double
+  %arrayidx4 = getelementptr inbounds [1000 x [1000 x double]], [1000 x [1000 x double]]* @A, i64 0, i64 %i.0, i64 %j.0
+  %tmp2 = load double, double* %arrayidx4, align 8
+  %add5 = fadd double %tmp2, %conv
+  store double %add5, double* %arrayidx4, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body.3
+  %inc = add nuw nsw i64 %j.0, 1
+  br label %for.cond.1
+
+for.end:                                          ; preds = %for.cond.1
+  br label %for.inc.6
+
+for.inc.6:                                        ; preds = %for.end
+  %inc7 = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end.8:                                        ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/restriction_in_dead_block.ll b/final/test/ScopInfo/restriction_in_dead_block.ll
new file mode 100644
index 0000000..c06cd7c
--- /dev/null
+++ b/final/test/ScopInfo/restriction_in_dead_block.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Verify we do not generate an empty invalid context only because the wrap
+; in the second conditional will always happen if the block is executed.
+;
+; CHECK:       Invalid Context:
+; CHECK-NEXT:    [N] -> {  : N > 0 }
+;
+;    void f(char *A, char N) {
+;      for (char i = 0; i < 10; i++) {
+;        if (N > 0)
+;          if (1 + 127 * N > 0)
+;            A[i] = 1;
+;        A[i] = 0;
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i8* %A, i8 signext %N) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i8 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i8 %indvars.iv, 10
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %cmp3 = icmp sgt i8 %N, 0
+  br i1 %cmp3, label %if.then, label %if.end10
+
+if.then:                                           ; preds = %for.body
+  %mul = mul i8 %N, 127
+  %add = add i8 1, %mul
+  %cmp7 = icmp sgt i8 %add, 0
+  br i1 %cmp7, label %if.then9, label %if.end10
+
+if.then9:                                         ; preds = %if.end
+  %arrayidx = getelementptr inbounds i8, i8* %A, i8 %indvars.iv
+  store i8 1, i8* %arrayidx, align 1
+  br label %if.end10
+
+if.end10:                                         ; preds = %if.then9, %if.end
+  %arrayidx12 = getelementptr inbounds i8, i8* %A, i8 %indvars.iv
+  store i8 0, i8* %arrayidx12, align 1
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end10, %if.then
+  %indvars.iv.next = add nuw nsw i8 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/run-time-check-many-array-disjuncts.ll b/final/test/ScopInfo/run-time-check-many-array-disjuncts.ll
new file mode 100644
index 0000000..191f4bd
--- /dev/null
+++ b/final/test/ScopInfo/run-time-check-many-array-disjuncts.ll
@@ -0,0 +1,241 @@
+; RUN: opt %loadPolly -polly-detect -analyze < %s \
+; RUN: | FileCheck %s -check-prefix=DETECT
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; DETECT: Valid Region for Scop: bb124 => bb176
+;
+; A valid Scop would print the list of it's statements, we check that we do not
+; see that list.
+;
+; CHECK-NOT: Statements
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64--linux-android"
+
+%0 = type { i8*, i64, i64, i64, i64, i64, i64 }
+
+define void @_Z1fR1SS0_Ph(%0* nocapture readonly dereferenceable(56) %arg, %0* nocapture readonly dereferenceable(56) %arg1, i8* nocapture readonly %arg2) {
+bb:
+  %tmp = getelementptr inbounds %0, %0* %arg1, i64 0, i32 1
+  %tmp3 = getelementptr inbounds %0, %0* %arg, i64 0, i32 0
+  %tmp4 = load i8*, i8** %tmp3, align 8
+  %tmp5 = getelementptr inbounds %0, %0* %arg, i64 0, i32 4
+  %tmp6 = load i64, i64* %tmp5, align 8
+  %tmp7 = getelementptr inbounds %0, %0* %arg, i64 0, i32 1
+  %tmp8 = load i64, i64* %tmp7, align 8
+  %tmp9 = mul i64 %tmp8, %tmp6
+  %tmp10 = getelementptr inbounds i8, i8* %tmp4, i64 %tmp9
+  %tmp11 = getelementptr inbounds %0, %0* %arg, i64 0, i32 3
+  %tmp12 = load i64, i64* %tmp11, align 8
+  %tmp13 = getelementptr inbounds i8, i8* %tmp10, i64 %tmp12
+  %tmp14 = getelementptr inbounds %0, %0* %arg, i64 0, i32 6
+  %tmp15 = load i64, i64* %tmp14, align 8
+  %tmp16 = add i64 %tmp15, 1
+  %tmp17 = icmp eq i64 %tmp16, %tmp6
+  br i1 %tmp17, label %bb51, label %bb18
+
+bb18:                                             ; preds = %bb
+  %tmp19 = getelementptr inbounds %0, %0* %arg, i64 0, i32 2
+  %tmp20 = load i64, i64* %tmp19, align 8
+  %tmp21 = mul i64 %tmp20, %tmp8
+  %tmp22 = getelementptr inbounds i8, i8* %tmp13, i64 %tmp21
+  %tmp23 = getelementptr inbounds i8, i8* %tmp22, i64 %tmp9
+  %tmp24 = getelementptr inbounds i8, i8* %tmp23, i64 %tmp12
+  %tmp25 = bitcast %0* %arg1 to i16**
+  %tmp26 = load i16*, i16** %tmp25, align 8
+  %tmp27 = load i64, i64* %tmp, align 8
+  %tmp28 = getelementptr inbounds %0, %0* %arg1, i64 0, i32 4
+  %tmp29 = load i64, i64* %tmp28, align 8
+  %tmp30 = mul i64 %tmp27, %tmp29
+  %tmp31 = getelementptr inbounds i16, i16* %tmp26, i64 %tmp30
+  %tmp32 = getelementptr inbounds %0, %0* %arg1, i64 0, i32 3
+  %tmp33 = load i64, i64* %tmp32, align 8
+  %tmp34 = getelementptr inbounds i16, i16* %tmp31, i64 %tmp33
+  %tmp35 = getelementptr inbounds %0, %0* %arg, i64 0, i32 5
+  %tmp36 = load i64, i64* %tmp35, align 8
+  br label %bb37
+
+bb37:                                             ; preds = %bb57, %bb18
+  %tmp38 = phi i64 [ %tmp6, %bb18 ], [ %tmp58, %bb57 ]
+  %tmp39 = phi i64 [ %tmp15, %bb18 ], [ %tmp59, %bb57 ]
+  %tmp40 = phi i64 [ %tmp27, %bb18 ], [ %tmp60, %bb57 ]
+  %tmp41 = phi i64 [ %tmp8, %bb18 ], [ %tmp61, %bb57 ]
+  %tmp42 = phi i64 [ %tmp12, %bb18 ], [ %tmp62, %bb57 ]
+  %tmp43 = phi i64 [ %tmp36, %bb18 ], [ %tmp63, %bb57 ]
+  %tmp44 = phi i16* [ %tmp34, %bb18 ], [ %tmp69, %bb57 ]
+  %tmp45 = phi i8* [ %tmp13, %bb18 ], [ %tmp64, %bb57 ]
+  %tmp46 = phi i8* [ %tmp24, %bb18 ], [ %tmp68, %bb57 ]
+  %tmp47 = phi i64 [ 0, %bb18 ], [ %tmp70, %bb57 ]
+  %tmp48 = add i64 %tmp43, 1
+  %tmp49 = sub i64 %tmp48, %tmp42
+  %tmp50 = icmp eq i64 %tmp49, 0
+  br i1 %tmp50, label %bb57, label %bb74
+
+bb51:                                             ; preds = %bb57, %bb
+  ret void
+
+bb52:                                             ; preds = %bb176
+  %tmp53 = load i64, i64* %tmp7, align 8
+  %tmp54 = load i64, i64* %tmp, align 8
+  %tmp55 = load i64, i64* %tmp14, align 8
+  %tmp56 = load i64, i64* %tmp5, align 8
+  br label %bb57
+
+bb57:                                             ; preds = %bb52, %bb37
+  %tmp58 = phi i64 [ %tmp56, %bb52 ], [ %tmp38, %bb37 ]
+  %tmp59 = phi i64 [ %tmp55, %bb52 ], [ %tmp39, %bb37 ]
+  %tmp60 = phi i64 [ %tmp54, %bb52 ], [ %tmp40, %bb37 ]
+  %tmp61 = phi i64 [ %tmp53, %bb52 ], [ %tmp41, %bb37 ]
+  %tmp62 = phi i64 [ %tmp179, %bb52 ], [ %tmp42, %bb37 ]
+  %tmp63 = phi i64 [ %tmp178, %bb52 ], [ %tmp43, %bb37 ]
+  %tmp64 = getelementptr inbounds i8, i8* %tmp45, i64 %tmp61
+  %tmp65 = and i64 %tmp47, 1
+  %tmp66 = icmp eq i64 %tmp65, 0
+  %tmp67 = getelementptr inbounds i8, i8* %tmp46, i64 %tmp61
+  %tmp68 = select i1 %tmp66, i8* %tmp46, i8* %tmp67
+  %tmp69 = getelementptr inbounds i16, i16* %tmp44, i64 %tmp60
+  %tmp70 = add i64 %tmp47, 1
+  %tmp71 = add i64 %tmp59, 1
+  %tmp72 = sub i64 %tmp71, %tmp58
+  %tmp73 = icmp ult i64 %tmp70, %tmp72
+  br i1 %tmp73, label %bb37, label %bb51
+
+bb74:                                             ; preds = %bb176, %bb37
+  %tmp75 = phi i64 [ %tmp181, %bb176 ], [ %tmp49, %bb37 ]
+  %tmp76 = phi i64 [ %tmp177, %bb176 ], [ 0, %bb37 ]
+  %tmp77 = getelementptr inbounds i8, i8* %tmp45, i64 %tmp76
+  %tmp78 = load i8, i8* %tmp77, align 1
+  %tmp79 = zext i8 %tmp78 to i32
+  %tmp80 = or i64 %tmp76, 1
+  %tmp81 = getelementptr inbounds i8, i8* %tmp45, i64 %tmp80
+  %tmp82 = load i8, i8* %tmp81, align 1
+  %tmp83 = zext i8 %tmp82 to i32
+  %tmp84 = getelementptr inbounds i8, i8* %tmp46, i64 %tmp76
+  %tmp85 = load i8, i8* %tmp84, align 1
+  %tmp86 = zext i8 %tmp85 to i32
+  %tmp87 = getelementptr inbounds i8, i8* %tmp46, i64 %tmp80
+  %tmp88 = load i8, i8* %tmp87, align 1
+  %tmp89 = zext i8 %tmp88 to i32
+  %tmp90 = mul nuw nsw i32 %tmp86, 517
+  %tmp91 = add nsw i32 %tmp90, -66176
+  %tmp92 = sub nsw i32 128, %tmp86
+  %tmp93 = mul nsw i32 %tmp92, 100
+  %tmp94 = sub nsw i32 128, %tmp89
+  %tmp95 = mul nsw i32 %tmp94, 208
+  %tmp96 = mul nuw nsw i32 %tmp89, 409
+  %tmp97 = add nsw i32 %tmp96, -52352
+  %tmp98 = mul nuw nsw i32 %tmp79, 298
+  %tmp99 = add nsw i32 %tmp98, -4768
+  %tmp100 = add nsw i32 %tmp91, %tmp99
+  %tmp101 = sdiv i32 %tmp100, 256
+  %tmp102 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %tmp99, i32 %tmp95)
+  %tmp103 = extractvalue { i32, i1 } %tmp102, 1
+  br i1 %tmp103, label %bb104, label %bb105
+
+bb104:                                            ; preds = %bb120, %bb109, %bb105, %bb74
+  tail call void @llvm.trap()
+  unreachable
+
+bb105:                                            ; preds = %bb74
+  %tmp106 = extractvalue { i32, i1 } %tmp102, 0
+  %tmp107 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %tmp106, i32 %tmp93)
+  %tmp108 = extractvalue { i32, i1 } %tmp107, 1
+  br i1 %tmp108, label %bb104, label %bb109
+
+bb109:                                            ; preds = %bb105
+  %tmp110 = extractvalue { i32, i1 } %tmp107, 0
+  %tmp111 = sdiv i32 %tmp110, 256
+  %tmp112 = add nsw i32 %tmp97, %tmp99
+  %tmp113 = sdiv i32 %tmp112, 256
+  %tmp114 = mul nuw nsw i32 %tmp83, 298
+  %tmp115 = add nsw i32 %tmp114, -4768
+  %tmp116 = add nsw i32 %tmp91, %tmp115
+  %tmp117 = sdiv i32 %tmp116, 256
+  %tmp118 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %tmp115, i32 %tmp95)
+  %tmp119 = extractvalue { i32, i1 } %tmp118, 1
+  br i1 %tmp119, label %bb104, label %bb120
+
+bb120:                                            ; preds = %bb109
+  %tmp121 = extractvalue { i32, i1 } %tmp118, 0
+  %tmp122 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %tmp121, i32 %tmp93)
+  %tmp123 = extractvalue { i32, i1 } %tmp122, 1
+  br i1 %tmp123, label %bb104, label %bb124
+
+bb124:                                            ; preds = %bb120
+  %tmp125 = sext i32 %tmp101 to i64
+  %tmp126 = getelementptr inbounds i8, i8* %arg2, i64 %tmp125
+  %tmp127 = load i8, i8* %tmp126, align 1
+  %tmp128 = zext i8 %tmp127 to i32
+  %tmp129 = lshr i32 %tmp128, 3
+  %tmp130 = shl nuw nsw i32 %tmp129, 11
+  %tmp131 = sext i32 %tmp111 to i64
+  %tmp132 = getelementptr inbounds i8, i8* %arg2, i64 %tmp131
+  %tmp133 = load i8, i8* %tmp132, align 1
+  %tmp134 = zext i8 %tmp133 to i32
+  %tmp135 = lshr i32 %tmp134, 2
+  %tmp136 = shl nuw nsw i32 %tmp135, 5
+  %tmp137 = or i32 %tmp136, %tmp130
+  %tmp138 = sext i32 %tmp113 to i64
+  %tmp139 = getelementptr inbounds i8, i8* %arg2, i64 %tmp138
+  %tmp140 = load i8, i8* %tmp139, align 1
+  %tmp141 = zext i8 %tmp140 to i32
+  %tmp142 = lshr i32 %tmp141, 3
+  %tmp143 = or i32 %tmp137, %tmp142
+  %tmp144 = icmp ult i64 %tmp80, %tmp75
+  br i1 %tmp144, label %bb145, label %bb173
+
+bb145:                                            ; preds = %bb124
+  %tmp146 = add nsw i32 %tmp97, %tmp115
+  %tmp147 = sdiv i32 %tmp146, 256
+  %tmp148 = sext i32 %tmp147 to i64
+  %tmp149 = getelementptr inbounds i8, i8* %arg2, i64 %tmp148
+  %tmp150 = load i8, i8* %tmp149, align 1
+  %tmp151 = extractvalue { i32, i1 } %tmp122, 0
+  %tmp152 = sdiv i32 %tmp151, 256
+  %tmp153 = sext i32 %tmp152 to i64
+  %tmp154 = getelementptr inbounds i8, i8* %arg2, i64 %tmp153
+  %tmp155 = load i8, i8* %tmp154, align 1
+  %tmp156 = sext i32 %tmp117 to i64
+  %tmp157 = getelementptr inbounds i8, i8* %arg2, i64 %tmp156
+  %tmp158 = load i8, i8* %tmp157, align 1
+  %tmp159 = zext i8 %tmp158 to i32
+  %tmp160 = lshr i32 %tmp159, 3
+  %tmp161 = shl nuw nsw i32 %tmp160, 11
+  %tmp162 = zext i8 %tmp155 to i32
+  %tmp163 = lshr i32 %tmp162, 2
+  %tmp164 = shl nuw nsw i32 %tmp163, 5
+  %tmp165 = zext i8 %tmp150 to i32
+  %tmp166 = lshr i32 %tmp165, 3
+  %tmp167 = or i32 %tmp164, %tmp166
+  %tmp168 = or i32 %tmp167, %tmp161
+  %tmp169 = shl nuw i32 %tmp168, 16
+  %tmp170 = or i32 %tmp169, %tmp143
+  %tmp171 = getelementptr inbounds i16, i16* %tmp44, i64 %tmp76
+  %tmp172 = bitcast i16* %tmp171 to i32*
+  store i32 %tmp170, i32* %tmp172, align 4
+  br label %bb176
+
+bb173:                                            ; preds = %bb124
+  %tmp174 = trunc i32 %tmp143 to i16
+  %tmp175 = getelementptr inbounds i16, i16* %tmp44, i64 %tmp76
+  store i16 %tmp174, i16* %tmp175, align 2
+  br label %bb176
+
+bb176:                                            ; preds = %bb173, %bb145
+  %tmp177 = add i64 %tmp76, 2
+  %tmp178 = load i64, i64* %tmp35, align 8
+  %tmp179 = load i64, i64* %tmp11, align 8
+  %tmp180 = add i64 %tmp178, 1
+  %tmp181 = sub i64 %tmp180, %tmp179
+  %tmp182 = icmp ult i64 %tmp177, %tmp181
+  br i1 %tmp182, label %bb74, label %bb52
+}
+
+; Function Attrs: noreturn nounwind
+declare void @llvm.trap() #0
+
+; Function Attrs: nounwind readnone
+declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1
+
+attributes #0 = { noreturn nounwind }
+attributes #1 = { nounwind readnone }
diff --git a/final/test/ScopInfo/run-time-check-many-parameters.ll b/final/test/ScopInfo/run-time-check-many-parameters.ll
new file mode 100644
index 0000000..732b53a
--- /dev/null
+++ b/final/test/ScopInfo/run-time-check-many-parameters.ll
@@ -0,0 +1,129 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; A valid Scop would print the list of it's statements, we check that we do not
+; see that list.
+;
+; CHECK-NOT: Statements
+;
+; FIXME: Handling this is an open problem, at the moment we just bail out.
+;
+; void foo(float *A, float *B,
+; 	long p1,
+; 	long p2,
+; 	long p3,
+; 	long p4,
+; 	long p5,
+; 	long p6,
+; 	long p7,
+; 	long p8,
+; 	long p9,
+; 	long p10,
+; 	long p11,
+; 	long p12) {
+;   for (long i = 0; i < 100; i++) {
+;     A[i] =
+; 	B[i + p1] +
+; 	B[i + p2] +
+; 	B[i + p3] +
+; 	B[i + p4] +
+; 	B[i + p5] +
+; 	B[i + p6] +
+; 	B[i + p7] +
+; 	B[i + p8] +
+; 	B[i + p9] +
+; 	B[i + p10] +
+; 	B[i + p11] +
+; 	B[i + p12];
+;   }
+; }
+;
+; Computing the minimal and maximal element accessed in B is very expensive.
+; Expressing the minimal element itself yields a rather complex isl_pw_aff which
+; looks as follows:
+; { ...
+;   MemRef_B[(100 + p11)] : p2 <= -1 + p1 and p3 <= -1 + p1 and p4 <= -1 + p1
+;                           and p5 <= -1 + p1 and p6 <= -1 + p1 and
+;                           p7 <= -1 + p1 and p8 <= -1 + p1 and p9 <= -1 + p1
+;                           and p10 <= -1 + p1 and p11 >= p1 and
+;                           p12 <= -1 + p11;
+;   MemRef_B[(100 + p12)] : p2 <= -1 + p1 and p3 <= -1 + p1 and p4 <= -1 + p1
+;                           and p5 <= -1 + p1 and p6 <= -1 + p1 and
+;                           p7 <= -1 + p1 and p8 <= -1 + p1 and p9 <= -1 + p1
+;                           and p10 <= -1 + p1 and p11 <= -1 + p1 and p12 >= p1;
+;
+; and this isl_pw_aff is then 1:1 translated into a isl ast expression.
+;
+; In the best case, we would create a run-time check such as:
+;
+; if (B[99 + max(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12)] < A[0]
+;     || A[99] B[min(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9]))
+;
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @foo(float* %A, float* %B, i64 %p1, i64 %p2, i64 %p3, i64 %p4, i64 %p5, i64 %p6, i64 %p7, i64 %p8, i64 %p9, i64 %p10, i64 %p11, i64 %p12) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %i.01 = phi i64 [ 0, %entry.split ], [ %tmp25, %for.body ]
+  %tmp = add i64 %p1, %i.01
+  %arrayidx = getelementptr float, float* %B, i64 %tmp
+  %tmp2 = add i64 %p2, %i.01
+  %arrayidx2 = getelementptr float, float* %B, i64 %tmp2
+  %tmp3 = add i64 %p3, %i.01
+  %arrayidx5 = getelementptr float, float* %B, i64 %tmp3
+  %tmp4 = add i64 %p4, %i.01
+  %arrayidx8 = getelementptr float, float* %B, i64 %tmp4
+  %tmp5 = add i64 %p5, %i.01
+  %arrayidx11 = getelementptr float, float* %B, i64 %tmp5
+  %tmp6 = add i64 %p6, %i.01
+  %arrayidx14 = getelementptr float, float* %B, i64 %tmp6
+  %tmp7 = add i64 %p7, %i.01
+  %arrayidx17 = getelementptr float, float* %B, i64 %tmp7
+  %tmp8 = add i64 %p8, %i.01
+  %arrayidx20 = getelementptr float, float* %B, i64 %tmp8
+  %tmp9 = add i64 %p9, %i.01
+  %arrayidx23 = getelementptr float, float* %B, i64 %tmp9
+  %tmp10 = add i64 %p10, %i.01
+  %arrayidx26 = getelementptr float, float* %B, i64 %tmp10
+  %tmp11 = add i64 %p11, %i.01
+  %arrayidx29 = getelementptr float, float* %B, i64 %tmp11
+  %tmp12 = add i64 %p12, %i.01
+  %arrayidx32 = getelementptr float, float* %B, i64 %tmp12
+  %arrayidx34 = getelementptr float, float* %A, i64 %i.01
+  %tmp13 = load float, float* %arrayidx, align 4
+  %tmp14 = load float, float* %arrayidx2, align 4
+  %add3 = fadd float %tmp13, %tmp14
+  %tmp15 = load float, float* %arrayidx5, align 4
+  %add6 = fadd float %add3, %tmp15
+  %tmp16 = load float, float* %arrayidx8, align 4
+  %add9 = fadd float %add6, %tmp16
+  %tmp17 = load float, float* %arrayidx11, align 4
+  %add12 = fadd float %add9, %tmp17
+  %tmp18 = load float, float* %arrayidx14, align 4
+  %add15 = fadd float %add12, %tmp18
+  %tmp19 = load float, float* %arrayidx17, align 4
+  %add18 = fadd float %add15, %tmp19
+  %tmp20 = load float, float* %arrayidx20, align 4
+  %add21 = fadd float %add18, %tmp20
+  %tmp21 = load float, float* %arrayidx23, align 4
+  %add24 = fadd float %add21, %tmp21
+  %tmp22 = load float, float* %arrayidx26, align 4
+  %add27 = fadd float %add24, %tmp22
+  %tmp23 = load float, float* %arrayidx29, align 4
+  %add30 = fadd float %add27, %tmp23
+  %tmp24 = load float, float* %arrayidx32, align 4
+  %add33 = fadd float %add30, %tmp24
+  store float %add33, float* %arrayidx34, align 4
+  %tmp25 = add nsw i64 %i.01, 1
+  %exitcond = icmp ne i64 %tmp25, 100
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body
+  ret void
+}
diff --git a/final/test/ScopInfo/run-time-check-read-only-arrays.ll b/final/test/ScopInfo/run-time-check-read-only-arrays.ll
new file mode 100644
index 0000000..61e979e
--- /dev/null
+++ b/final/test/ScopInfo/run-time-check-read-only-arrays.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; void foo(float *A, float *B, float *C, long N) {
+; 	for (long i = 0; i < N; i++)
+; 		C[i] = A[i] + B[i];
+; }
+;
+; CHECK: Alias Groups (2):
+;
+; This test case verifies that we do not create run-time checks for two
+; read-only arrays.
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo(float* %A, float* %B, float* %C, i64 %N) {
+entry:
+  br label %for.body
+
+for.body:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %for.body ]
+  %arrayidx.A = getelementptr float, float* %A, i64 %indvar
+  %arrayidx.B = getelementptr float, float* %B, i64 %indvar
+  %arrayidx.C = getelementptr float, float* %C, i64 %indvar
+  %val.A = load float, float* %arrayidx.A
+  %val.B = load float, float* %arrayidx.B
+  %add = fadd float %val.A, %val.B
+  store float %add, float* %arrayidx.C
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp ne i64 %indvar.next, %N
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.end:
+  ret void
+}
diff --git a/final/test/ScopInfo/same-base-address-scalar-and-array.ll b/final/test/ScopInfo/same-base-address-scalar-and-array.ll
new file mode 100644
index 0000000..65680fd
--- /dev/null
+++ b/final/test/ScopInfo/same-base-address-scalar-and-array.ll
@@ -0,0 +1,29 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Verify we introduce two ScopArrayInfo objects (or virtual arrays) for the %out variable
+; as it is used as a memory base pointer (%0) but also as a scalar (%out.addr.0.lcssa).
+;
+; CHECK:         Arrays {
+; CHECK-NEXT:        float* MemRef_out_addr_0_lcssa; // Element size 8
+; CHECK-NEXT:        float MemRef_out[*]; // Element size 4
+; CHECK-NEXT:    }
+;
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind ssp uwtable
+define void @ff_celp_lp_synthesis_filterf(float* %out) #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br i1 false, label %for.end.97, label %for.body.lr.ph
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  %arrayidx13 = getelementptr inbounds float, float* %out, i64 -3
+  %0 = load float, float* %arrayidx13, align 4
+  br label %for.end.97
+
+for.end.97:                                       ; preds = %for.cond.for.end.97_crit_edge, %entry.split
+  %out.addr.0.lcssa = phi float* [ undef, %for.body.lr.ph ], [ %out, %entry.split ]
+  ret void
+}
diff --git a/final/test/ScopInfo/scalar.ll b/final/test/ScopInfo/scalar.ll
new file mode 100644
index 0000000..ada644c
--- /dev/null
+++ b/final/test/ScopInfo/scalar.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* %a, i64 %N) {
+entry:
+  br label %for
+
+for:
+  %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %for.backedge ]
+  br label %S1
+
+S1:
+  %scevgep1 = getelementptr i64, i64* %a, i64 %indvar
+  %val = load i64, i64* %scevgep1, align 8
+  br label %S2
+
+S2:
+  %scevgep2 = getelementptr i64, i64* %a, i64 %indvar
+  store i64 %val, i64* %scevgep2, align 8
+  br label %for.backedge
+
+for.backedge:
+  %indvar.next = add nsw i64 %indvar, 1
+  %exitcond = icmp eq i64 %indvar.next, %N
+  br i1 %exitcond, label %return, label %for
+
+return:
+  ret void
+}
+
+
+; CHECK:      Arrays {
+; CHECK-NEXT:     i64 MemRef_a[*]; // Element size 8
+; CHECK-NEXT:     i64 MemRef_val; // Element size 8
+; CHECK-NEXT: }
+;
+; CHECK:      Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:     i64 MemRef_a[*]; // Element size 8
+; CHECK-NEXT:     i64 MemRef_val; // Element size 8
+; CHECK-NEXT: }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_S1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_S1[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_S1[i0] -> [i0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_S1[i0] -> MemRef_a[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_S1[i0] -> MemRef_val[] };
+; CHECK-NEXT:     Stmt_S2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_S2[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_S2[i0] -> [i0, 1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_S2[i0] -> MemRef_a[i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [N] -> { Stmt_S2[i0] -> MemRef_val[] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/scalar_dependence_cond_br.ll b/final/test/ScopInfo/scalar_dependence_cond_br.ll
new file mode 100644
index 0000000..e32a354
--- /dev/null
+++ b/final/test/ScopInfo/scalar_dependence_cond_br.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(int *A, int c, int d) {
+;      for (int i = 0; i < 1024; i++)
+;        if (c < i)
+;          A[i]++;
+;    }
+;
+; Verify that we do not generate a value write access for the use of %cmp1 in
+; the branch condition. As _affine_ branches are fully modeled and regenerated
+; from the polyhedral information we do not need this value to be available
+; during code generation.
+;
+; CHECK-NOT:  Stmt_for_cond[i0] -> MemRef_cmp1[] }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i64 %c) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 1024
+  %cmp1 = icmp slt i64 %c, %indvars.iv
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br i1 %cmp1, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/scalar_to_array.ll b/final/test/ScopInfo/scalar_to_array.ll
new file mode 100644
index 0000000..c959c2b
--- /dev/null
+++ b/final/test/ScopInfo/scalar_to_array.ll
@@ -0,0 +1,195 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -basicaa -polly-function-scops -analyze < %s | FileCheck %s
+
+; ModuleID = 'scalar_to_array.ll'
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+@A = common global [1024 x float] zeroinitializer, align 8
+
+; Terminating loops without side-effects will be optimzied away, hence
+; detecting a scop would be pointless.
+; CHECK-NOT: Function: empty
+; Function Attrs: nounwind
+define i32 @empty() #0 {
+entry:
+  fence seq_cst
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvar, 1024
+  br i1 %exitcond, label %for.body, label %return
+
+for.body:                                         ; preds = %for.cond
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond
+
+return:                                           ; preds = %for.cond
+  fence seq_cst
+  ret i32 0
+}
+
+; CHECK-LABEL: Function: array_access
+; Function Attrs: nounwind
+define i32 @array_access() #0 {
+entry:
+  fence seq_cst
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvar, 1024
+  br i1 %exitcond, label %for.body, label %return
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  %float = uitofp i64 %indvar to float
+  store float %float, float* %arrayidx
+  br label %for.inc
+; CHECK:     Stmt_for_body
+; CHECK-NOT:     ReadAccess
+; CHECK:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:        { Stmt_for_body[i0] -> MemRef_A[i0] };
+
+for.inc:                                          ; preds = %for.body
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond
+
+return:                                           ; preds = %for.cond
+  fence seq_cst
+  ret i32 0
+}
+
+; Function Attrs: nounwind
+; CHECK-LABEL: Function: intra_scop_dep
+define i32 @intra_scop_dep() #0 {
+entry:
+  fence seq_cst
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvar, 1024
+  br i1 %exitcond, label %for.body.a, label %return
+
+for.body.a:                                       ; preds = %for.cond
+  %arrayidx = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  %scalar = load float, float* %arrayidx
+  br label %for.body.b
+; CHECK:      Stmt_for_body_a
+; CHECK:          ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:         { Stmt_for_body_a[i0] -> MemRef_A[i0] };
+; CHECK:          MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:         { Stmt_for_body_a[i0] -> MemRef_scalar[] };
+
+for.body.b:                                       ; preds = %for.body.a
+  %arrayidx2 = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  %float = uitofp i64 %indvar to float
+  %sum = fadd float %scalar, %float
+  store float %sum, float* %arrayidx2
+  br label %for.inc
+; CHECK:      Stmt_for_body_b
+; CHECK:          ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:          { Stmt_for_body_b[i0] -> MemRef_scalar[] };
+; CHECK:          MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:         { Stmt_for_body_b[i0] -> MemRef_A[i0] };
+
+for.inc:                                          ; preds = %for.body.b
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond
+
+return:                                           ; preds = %for.cond
+  fence seq_cst
+  ret i32 0
+}
+
+; It is not possible to have a scop which accesses a scalar element that is
+; a global variable. All global variables are pointers containing possibly
+; a single element. Hence they do not need to be handled anyways.
+; Please note that this is still required when scalar to array rewritting is
+; disabled.
+
+; CHECK-LABEL: Function: use_after_scop
+; Function Attrs: nounwind
+define i32 @use_after_scop() #0 {
+entry:
+  %scalar.s2a = alloca float
+  fence seq_cst
+  br label %for.head
+
+for.head:                                         ; preds = %for.inc, %entry
+  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %entry ]
+  br label %for.body
+
+for.body:                                         ; preds = %for.head
+  %arrayidx = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  %scalar = load float, float* %arrayidx
+  store float %scalar, float* %scalar.s2a
+; Escaped uses are still required to be rewritten to stack variable.
+; CHECK:      Stmt_for_body
+; CHECK:          ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:         { Stmt_for_body[i0] -> MemRef_A[i0] };
+; CHECK:          MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:         { Stmt_for_body[i0] -> MemRef_scalar_s2a[0] };
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvar.next = add i64 %indvar, 1
+  %exitcond = icmp ne i64 %indvar.next, 1024
+  br i1 %exitcond, label %for.head, label %for.after
+
+for.after:                                        ; preds = %for.inc
+  %scalar.loadoutside = load float, float* %scalar.s2a
+  fence seq_cst
+  %return_value = fptosi float %scalar.loadoutside to i32
+  br label %return
+
+return:                                           ; preds = %for.after
+  ret i32 %return_value
+}
+
+; We currently do not transform scalar references, that have only read accesses
+; in the scop. There are two reasons for this:
+;
+;  o We don't introduce additional memory references which may yield to compile
+;    time overhead.
+;  o For integer values, such a translation may block the use of scalar
+;    evolution on those values.
+;
+; CHECK-LABEL: Function: before_scop
+; Function Attrs: nounwind
+define i32 @before_scop() #0 {
+entry:
+  br label %preheader
+
+preheader:                                        ; preds = %entry
+  %scalar = fadd float 4.000000e+00, 5.000000e+00
+  fence seq_cst
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %preheader
+  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %preheader ]
+  %exitcond = icmp ne i64 %indvar, 1024
+  br i1 %exitcond, label %for.body, label %return
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  store float %scalar, float* %arrayidx
+  br label %for.inc
+; CHECK:      Stmt_for_body
+; CHECK:          MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:         { Stmt_for_body[i0] -> MemRef_A[i0] };
+
+for.inc:                                          ; preds = %for.body
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond
+
+return:                                           ; preds = %for.cond
+  fence seq_cst
+  ret i32 0
+}
+
+attributes #0 = { nounwind }
diff --git a/final/test/ScopInfo/scev-div-with-evaluatable-divisor.ll b/final/test/ScopInfo/scev-div-with-evaluatable-divisor.ll
new file mode 100644
index 0000000..d1931c0
--- /dev/null
+++ b/final/test/ScopInfo/scev-div-with-evaluatable-divisor.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; Derived from test-suite/SingleSource/UnitTests/Vector/SSE/sse.stepfft.c
+
+; The values %mul.i44 is simplified to constant 4 by ScalarEvolution, but 
+; SCEVAffinator used to check whether the sdiv's argument was constant.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @cfft2(i32 %n, double* %A) local_unnamed_addr #0 {
+entry:
+  br i1 undef, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:                                   ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %for.inc, %for.body.lr.ph
+  %mj.017 = phi i32 [ 1, %for.body.lr.ph ], [ undef, %for.inc ]
+  br i1 undef, label %if.else, label %if.then
+
+if.then:                                          ; preds = %for.body
+  br label %for.inc
+
+if.else:                                          ; preds = %for.body
+  %mul.i44 = shl i32 %mj.017, 2
+  %div.i45 = sdiv i32 %n, %mul.i44
+  br i1 undef, label %for.body.i58.lr.ph, label %for.inc
+
+for.body.i58.lr.ph:                               ; preds = %if.else
+  br i1 undef, label %for.body.i58.us, label %for.body.i58.preheader
+
+for.body.i58.preheader:                           ; preds = %for.body.i58.lr.ph
+  br label %for.body.i58
+
+for.body.i58.us:                                  ; preds = %for.body.i58.us, %for.body.i58.lr.ph
+  br i1 undef, label %for.inc, label %for.body.i58.us
+
+for.body.i58:                                     ; preds = %for.body.i58, %for.body.i58.preheader
+  store double 0.0, double* %A
+  %exitcond42 = icmp eq i32 0, %div.i45
+  br i1 %exitcond42, label %for.inc, label %for.body.i58
+
+for.inc:                                          ; preds = %for.body.i58, %for.body.i58.us, %if.else, %if.then
+  br i1 undef, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.inc, %entry
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.9.0 (trunk 273249) (llvm/trunk 273255)"}
+
+; CHECK-LABEL: Stmt_for_body_i58
+; CHECK-NEXT:      Domain :=
+; CHECK-NEXT:          [n] -> { Stmt_for_body_i58[0] : -3 <= n <= 3 };
diff --git a/final/test/ScopInfo/scev-invalidated.ll b/final/test/ScopInfo/scev-invalidated.ll
new file mode 100644
index 0000000..1ed7798
--- /dev/null
+++ b/final/test/ScopInfo/scev-invalidated.ll
@@ -0,0 +1,24 @@
+; RUN: opt %loadPolly -polly-scops < %s
+;
+; CHECK: Region: %if.then6---%return
+;
+target datalayout ="e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+define void @arc_either() {
+entry:
+  %ang2.2.reg2mem = alloca i64
+  br i1 undef, label %return, label %if.then6
+
+if.then6:
+  %rem7 = srem i64 undef, 1474560
+  br i1 false, label %if.else, label %return
+
+if.else:
+  %add16 = add nsw i64 %rem7, 1474560
+  %rem7.add16 = select i1 undef, i64 %rem7, i64 %add16
+  store i64 %rem7.add16, i64* %ang2.2.reg2mem
+  br label %return
+
+return:
+  ret void
+}
diff --git a/final/test/ScopInfo/schedule-const-post-dominator-walk-2.ll b/final/test/ScopInfo/schedule-const-post-dominator-walk-2.ll
new file mode 100644
index 0000000..4fe4d17
--- /dev/null
+++ b/final/test/ScopInfo/schedule-const-post-dominator-walk-2.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s
+
+; CHECK: Stmt_loopA[i0] -> [0, 0, 0]
+; CHECK-DAG: Stmt_loopB[i0] -> [0, 0, 1]
+; CHECK-DAG: Stmt_bbB[] -> [1, 0, 0]
+; CHECK-DAG: Stmt_bbA[] -> [2, 0, 0]
+; CHECK-DAG: Stmt_bbMerge[]   -> [3, 0, 0]
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @hoge(i64 %p0, i64 %p1, i64 %p2, i64 %p3, float* %A) {
+entry:
+  br label %loopA
+
+loopA:
+  %tmp4 = phi i64 [ 0, %entry ], [ 0, %loopB]
+  store float 42.0, float* %A
+  %cmp0 = icmp sle i64 %p0, 100
+  br i1 %cmp0, label %loopB, label %bbB
+
+loopB:
+  store float 42.0, float* %A
+  %cmp1 = icmp sle i64 %p1, 100
+  br i1 %cmp1, label %loopA, label %bbA
+
+bbA:
+  store float 42.0, float* %A
+  %cmpbbA = icmp sle i64 %p2, 50
+  br i1 %cmpbbA, label %bbMerge, label %exit
+
+bbB:
+  store float 42.0, float* %A
+  %cmpbbB= icmp sle i64 %p3, 200
+  br i1 %cmpbbB, label %exit, label %bbMerge
+
+bbMerge:
+  store float 42.0, float* %A
+  br label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/schedule-const-post-dominator-walk.ll b/final/test/ScopInfo/schedule-const-post-dominator-walk.ll
new file mode 100644
index 0000000..e44d98a
--- /dev/null
+++ b/final/test/ScopInfo/schedule-const-post-dominator-walk.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -analyze -polly-scops < %s | FileCheck %s
+
+; CHECK: { Stmt_bb3[i0] -> [0, 0] };
+; CHECK: { Stmt_bb2[] -> [1, 0] };
+
+; Verify that we generate the correct schedule. In older versions of Polly,
+; we generated an incorrect schedule:
+;
+;   { Stmt_bb3[i0] -> [1, 0]; Stmt_bb2[] -> [0, 0] }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @hoge() {
+bb:
+  br label %bb3
+
+bb1:                                              ; preds = %bb5
+  br label %bb6
+
+bb2:                                              ; preds = %bb3
+  %tmp = phi i64 [ %tmp4, %bb3 ]
+  br label %bb6
+
+bb3:                                              ; preds = %bb5, %bb
+  %tmp4 = phi i64 [ 0, %bb ], [ 0, %bb5 ]
+  br i1 false, label %bb5, label %bb2
+
+bb5:                                              ; preds = %bb3
+  br i1 false, label %bb3, label %bb1
+
+bb6:                                              ; preds = %bb2, %bb1
+  %tmp2 = phi i64 [ %tmp, %bb2 ], [ undef, %bb1 ]
+  ret void
+}
diff --git a/final/test/ScopInfo/schedule-constuction-endless-loop1.ll b/final/test/ScopInfo/schedule-constuction-endless-loop1.ll
new file mode 100644
index 0000000..50af71b
--- /dev/null
+++ b/final/test/ScopInfo/schedule-constuction-endless-loop1.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that we do not build a SCoP and do not crash.
+;
+; CHECK-NOT: Statements
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @int_upsample(i32* %A) {
+entry:
+  %0 = load i8, i8* undef, align 1
+  %conv7 = zext i8 %0 to i32
+  br label %while.body.preheader
+
+while.body.preheader:                             ; preds = %entry
+  br label %while.body
+
+while.body:                                       ; preds = %if.end, %while.body.preheader
+  %outrow.036 = phi i32 [ %add23, %if.end ], [ 0, %while.body.preheader ]
+  br i1 true, label %if.end, label %while.body16
+
+while.body16:                                     ; preds = %while.body16, %while.body
+  br label %while.body16
+
+if.end:                                           ; preds = %while.body
+  store i32 0, i32* %A
+  %add23 = add nuw nsw i32 %outrow.036, 1
+  %cmp = icmp slt i32 %add23, 0
+  br i1 %cmp, label %while.body, label %while.end24
+
+while.end24:                                      ; preds = %if.end
+  ret void
+}
diff --git a/final/test/ScopInfo/schedule-constuction-endless-loop2.ll b/final/test/ScopInfo/schedule-constuction-endless-loop2.ll
new file mode 100644
index 0000000..d190ddd
--- /dev/null
+++ b/final/test/ScopInfo/schedule-constuction-endless-loop2.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that we do not build a SCoP and do not crash.
+;
+; CHECK-NOT: Statements
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @int_upsample(i32* %A) {
+entry:
+  %0 = load i8, i8* undef, align 1
+  %conv7 = zext i8 %0 to i32
+  br label %while.body.preheader
+
+while.body.preheader:                             ; preds = %entry
+  br label %while.body
+
+while.body:                                       ; preds = %if.end, %while.body.preheader
+  %outrow.036 = phi i32 [ %add23, %if.end ], [ 0, %while.body.preheader ]
+  br i1 true, label %if.end, label %while.body16
+
+while.body16:                                     ; preds = %while.body16, %while.body
+  br label %while.body16.split
+
+while.body16.split:
+  br label %while.body16
+
+if.end:                                           ; preds = %while.body
+  store i32 0, i32* %A
+  %add23 = add nuw nsw i32 %outrow.036, 1
+  %cmp = icmp slt i32 %add23, 0
+  br i1 %cmp, label %while.body, label %while.end24
+
+while.end24:                                      ; preds = %if.end
+  ret void
+}
diff --git a/final/test/ScopInfo/schedule-incorrectly-contructed-in-case-of-infinite-loop.ll b/final/test/ScopInfo/schedule-incorrectly-contructed-in-case-of-infinite-loop.ll
new file mode 100644
index 0000000..9d6ff99
--- /dev/null
+++ b/final/test/ScopInfo/schedule-incorrectly-contructed-in-case-of-infinite-loop.ll
@@ -0,0 +1,93 @@
+; RUN: opt %loadPolly -polly-process-unprofitable -analyze -polly-scops < %s
+;
+; This test contains a infinite loop (bb13) and crashed the domain generation
+; at some point. Just verify it does not anymore.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @hoge() #0 {
+bb:
+  %tmp5 = alloca [11 x [101 x i32]], align 16
+  br i1 false, label %bb24, label %bb6
+
+bb6:                                              ; preds = %bb
+  br label %bb8
+
+bb7:                                              ; preds = %bb23
+  unreachable
+
+bb8:                                              ; preds = %bb23, %bb6
+  %tmp9 = getelementptr inbounds [11 x [101 x i32]], [11 x [101 x i32]]* %tmp5, i64 0, i64 0, i64 0
+  br label %bb10
+
+bb10:                                             ; preds = %bb8
+  %tmp = load i32, i32* %tmp9, align 4
+  br i1 false, label %bb23, label %bb11
+
+bb11:                                             ; preds = %bb10
+  %tmp12 = load i32, i32* %tmp9, align 4
+  br label %bb13
+
+bb13:                                             ; preds = %bb13, %bb11
+  %tmp14 = phi i32 [ %tmp12, %bb11 ], [ %tmp19, %bb13 ]
+  %tmp15 = add nsw i32 %tmp14, 1
+  %tmp16 = sext i32 %tmp15 to i64
+  %tmp17 = getelementptr inbounds [11 x [101 x i32]], [11 x [101 x i32]]* %tmp5, i64 0, i64 0, i64 %tmp16
+  %tmp18 = load i32, i32* %tmp17, align 4
+  %tmp19 = add nsw i32 %tmp14, -1
+  %tmp20 = load i32, i32* %tmp9, align 4
+  %tmp21 = sext i32 %tmp20 to i64
+  %tmp22 = icmp slt i64 0, %tmp21
+  br label %bb13
+
+bb23:                                             ; preds = %bb10
+  br i1 undef, label %bb8, label %bb7
+
+bb24:                                             ; preds = %bb
+  ret void
+}
+
+define void @hoge2() #0 {
+bb:
+  %tmp5 = alloca [11 x [101 x i32]], align 16
+  br i1 false, label %bb24, label %bb6
+
+bb6:                                              ; preds = %bb
+  br label %bb8
+
+bb7:                                              ; preds = %bb23
+  unreachable
+
+bb8:                                              ; preds = %bb23, %bb6
+  %tmp9 = getelementptr inbounds [11 x [101 x i32]], [11 x [101 x i32]]* %tmp5, i64 0, i64 0, i64 0
+  br label %bb10
+
+bb10:                                             ; preds = %bb8
+  %tmp = load i32, i32* %tmp9, align 4
+  br i1 false, label %bb23, label %bb11
+
+bb11:                                             ; preds = %bb10
+  %tmp12 = load i32, i32* %tmp9, align 4
+  br label %bb13
+
+bb13:                                             ; preds = %bb13, %bb11
+  %tmp14 = phi i32 [ %tmp12, %bb11 ], [ %tmp19, %bb13.split ]
+  %tmp15 = add nsw i32 %tmp14, 1
+  %tmp16 = sext i32 %tmp15 to i64
+  %tmp17 = getelementptr inbounds [11 x [101 x i32]], [11 x [101 x i32]]* %tmp5, i64 0, i64 0, i64 %tmp16
+  %tmp18 = load i32, i32* %tmp17, align 4
+  br label %bb13.split
+
+bb13.split:
+  %tmp19 = add nsw i32 %tmp14, -1
+  %tmp20 = load i32, i32* %tmp9, align 4
+  %tmp21 = sext i32 %tmp20 to i64
+  %tmp22 = icmp slt i64 0, %tmp21
+  br label %bb13
+
+bb23:                                             ; preds = %bb10
+  br i1 undef, label %bb8, label %bb7
+
+bb24:                                             ; preds = %bb
+  ret void
+}
diff --git a/final/test/ScopInfo/scop-affine-parameter-ordering.ll b/final/test/ScopInfo/scop-affine-parameter-ordering.ll
new file mode 100644
index 0000000..ca5ba49
--- /dev/null
+++ b/final/test/ScopInfo/scop-affine-parameter-ordering.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-scops %s -analyze | FileCheck %s
+target datalayout = "e-m:e-i64:64-i128:128-n8:16:32:64-S128"
+target triple = "aarch64--linux-android"
+
+; Check for SCOP:
+; CHECK: Stmt_for_body8_us_us95_i
+; CHECK-NEXT: Domain :=
+; CHECK-NEXT: [p_0] -> { Stmt_for_body8_us_us95_i[i0] : 0 <= i0 <= 4 };
+; CHECK-NEXT: Schedule :=
+; CHECK-NEXT: [p_0] -> { Stmt_for_body8_us_us95_i[i0] -> [i0] };
+; CHECK-NEXT; MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT; [p_0] -> { Stmt_for_body8_us_us95_i[i0] -> MemRef_0[1 + p_0] };
+; CHECK-NEXT }
+
+define void @test1() unnamed_addr align 2 {
+entry:
+  %xFactor.0.reload = load i32, i32* undef
+  %0 = load i8*, i8** undef, align 8
+  %div = udiv i32 0, %xFactor.0.reload
+  %1 = load i32, i32* undef, align 4
+  %mul = mul i32 %1, %xFactor.0.reload
+  %col.023.us.us85.i = add i32 %div, -1
+  %mul11.us.us93.i = mul i32 %col.023.us.us85.i, %mul
+  br label %for.body8.us.us95.i
+
+for.body8.us.us95.i:
+  %niter.i = phi i32 [ %niter.i.next, %for.body8.us.us95.i ], [ 0, %entry ]
+  %add12.us.us100.1.i = add i32 1, %mul11.us.us93.i
+  %idxprom13.us.us101.1.i = zext i32 %add12.us.us100.1.i to i64
+  %arrayidx14.us.us102.1.i = getelementptr inbounds i8, i8* %0, i64 %idxprom13.us.us101.1.i
+  store i8 0, i8* %arrayidx14.us.us102.1.i, align 1
+  %niter.ncmp.3.i = icmp eq i32 %niter.i, 4
+  %niter.i.next = add i32 %niter.i, 1
+  br i1 %niter.ncmp.3.i, label %for.body8.us.us95.epil.i.preheader, label %for.body8.us.us95.i
+
+for.body8.us.us95.epil.i.preheader:
+  ret void
+}
+
diff --git a/final/test/ScopInfo/sign_wrapped_set.ll b/final/test/ScopInfo/sign_wrapped_set.ll
new file mode 100644
index 0000000..d8035ce
--- /dev/null
+++ b/final/test/ScopInfo/sign_wrapped_set.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-allow-nonaffine -polly-process-unprofitable < %s | FileCheck %s
+;
+; CHECK:        Domain :=
+; CHECK-NEXT:       [srcHeight] -> { Stmt_for_cond6_preheader_us[i0] : 0 <= i0 <= -3 + srcHeight };
+; CHECK-NEXT:   Schedule :=
+; CHECK-NEXT:       [srcHeight] -> { Stmt_for_cond6_preheader_us[i0] -> [i0] };
+; CHECK-NEXT:   ReadAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:       [srcHeight] -> { Stmt_for_cond6_preheader_us[i0] -> MemRef_src[o0] };
+; CHECK-NEXT:   MayWriteAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:       [srcHeight] -> { Stmt_for_cond6_preheader_us[i0] -> MemRef_src[o0] };
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+
+define void @test_case(i8* noalias nocapture readonly %src, i32 %srcHeight, i32 %srcStride) local_unnamed_addr {
+entry:
+  %extended = zext i32 %srcStride to i64
+  %sub = add i32 %srcHeight, -1
+  br label %for.cond6.preheader.us
+
+for.cond6.preheader.us:                           ; preds = %for.cond6.preheader.us, %entry
+  %srcPtr.075.us.pn = phi i8* [ %srcPtr.075.us, %for.cond6.preheader.us ], [ %src, %entry ]
+  %y.072.us = phi i32 [ %inc37.us, %for.cond6.preheader.us ], [ 1, %entry ]
+  %srcPtr.075.us = getelementptr inbounds i8, i8* %srcPtr.075.us.pn, i64 %extended
+
+  %0 = load i8, i8* %srcPtr.075.us, align 1, !tbaa !0
+  %1 = add i8 %0, 1
+  store i8 %1, i8* %srcPtr.075.us, align 1, !tbaa !0
+
+  %inc37.us = add nuw i32 %y.072.us, 1
+  %exitcond78 = icmp eq i32 %inc37.us, %sub
+  br i1 %exitcond78, label %for.cond.cleanup.loopexit, label %for.cond6.preheader.us
+
+for.cond.cleanup.loopexit:                        ; preds = %for.cond6.preheader.us
+  ret void
+}
+
+!0 = !{!1, !1, i64 0}
+!1 = !{!"omnipotent char", !2, i64 0}
+!2 = !{!"Simple C++ TBAA"}
+!3 = !{!4, !4, i64 0}
+!4 = !{!"float", !1, i64 0}
diff --git a/final/test/ScopInfo/simple_loop_1.ll b/final/test/ScopInfo/simple_loop_1.ll
new file mode 100644
index 0000000..602dc7e
--- /dev/null
+++ b/final/test/ScopInfo/simple_loop_1.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; void f(int a[], int N) {
+;   int i;
+;   for (i = 0; i < N; ++i)
+;     a[i] = i;
+; }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* nocapture %a, i64 %N) nounwind {
+entry:
+  br label %bb
+
+bb:                                               ; preds = %bb, %entry
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %bb ]
+  %scevgep = getelementptr inbounds i64, i64* %a, i64 %i
+  store i64 %i, i64* %scevgep
+  %i.inc = add nsw i64 %i, 1
+  %exitcond = icmp eq i64 %i.inc, %N
+  br i1 %exitcond, label %return, label %bb
+
+return:                                           ; preds = %bb, %entry
+  ret void
+}
+
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [N] -> {  :  }
+;
+; CHECK:      Arrays {
+; CHECK-NEXT:     i64 MemRef_a[*]; // Element size 8
+; CHECK-NEXT: }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_bb[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_bb[i0] -> [i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_bb[i0] -> MemRef_a[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/simple_loop_2.ll b/final/test/ScopInfo/simple_loop_2.ll
new file mode 100644
index 0000000..a3e0894
--- /dev/null
+++ b/final/test/ScopInfo/simple_loop_2.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; void f(int a[], int N) {
+;   int i;
+;   for (i = 0; i < N; ++i)
+;     a[i] = i;
+; }
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [N] -> {  :  }
+;
+; CHECK:      Arrays {
+; CHECK-NEXT:     i32 MemRef_a[*]; // Element size 4
+; CHECK-NEXT: }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_bb[i0] : 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_bb[i0] -> [i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_bb[i0] -> MemRef_a[i0] };
+; CHECK-NEXT: }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i32* nocapture %a, i64 %N) nounwind {
+entry:
+  br label %bb
+
+bb:                                               ; preds = %bb, %entry
+  %i = phi i32 [ 0, %entry ], [ %i.inc, %bb ]
+  %scevgep = getelementptr inbounds i32, i32* %a, i32 %i
+  store i32 %i, i32* %scevgep
+  %i.inc = add nsw i32 %i, 1
+  %i.ext = zext i32 %i.inc to i64
+  %exitcond = icmp eq i64 %i.ext, %N
+  br i1 %exitcond, label %return, label %bb
+
+return:                                           ; preds = %bb, %entry
+  ret void
+}
diff --git a/final/test/ScopInfo/simple_loop_unsigned.ll b/final/test/ScopInfo/simple_loop_unsigned.ll
new file mode 100644
index 0000000..c43e21e
--- /dev/null
+++ b/final/test/ScopInfo/simple_loop_unsigned.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; void f(int a[], unsigned N) {
+;   unsigned i;
+;   do {
+;     a[i] = i;
+;   } while (++i <= N);
+; }
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [N] -> {  :  }
+; CHECK-NEXT: Invalid Context:
+; CHECK-NEXT: [N] -> {  : 1 = 0 }
+;
+; CHECK:              Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_bb[i0] : 0 <= i0 < N; Stmt_bb[0] : N = 0 };
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* nocapture %a, i64 %N) nounwind {
+entry:
+  br label %bb
+
+bb:                                               ; preds = %bb, %entry
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %bb ]
+  %scevgep = getelementptr inbounds i64, i64* %a, i64 %i
+  store i64 %i, i64* %scevgep
+  %i.inc = add nsw i64 %i, 1
+  %exitcond = icmp uge i64 %i.inc, %N
+  br i1 %exitcond, label %return, label %bb
+
+return:                                           ; preds = %bb, %entry
+  ret void
+}
diff --git a/final/test/ScopInfo/simple_loop_unsigned_2.ll b/final/test/ScopInfo/simple_loop_unsigned_2.ll
new file mode 100644
index 0000000..8e7ef93
--- /dev/null
+++ b/final/test/ScopInfo/simple_loop_unsigned_2.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [N] -> {  :  }
+; CHECK-NEXT: Invalid Context:
+; CHECK-NEXT: [N] -> {  : N <= 0 or N >= 1152921504606846976 }
+;
+; CHECK:              Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_bb[i0] : 0 <= i0 < N; Stmt_bb[0] : N <= 0 };
+;
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* nocapture %a, i64 %N) nounwind {
+entry:
+  br label %bb
+
+bb:                                               ; preds = %bb, %entry
+  %i = phi i64 [ %N, %entry ], [ %i.dec, %bb ]
+  %scevgep = getelementptr inbounds i64, i64* %a, i64 %i
+  store i64 %i, i64* %scevgep
+  %i.dec = add nsw i64 %i, -1
+  %exitcond = icmp ugt i64 %i.dec, 0
+  br i1 %exitcond, label %bb, label %return
+
+return:                                           ; preds = %bb, %entry
+  ret void
+}
diff --git a/final/test/ScopInfo/simple_loop_unsigned_3.ll b/final/test/ScopInfo/simple_loop_unsigned_3.ll
new file mode 100644
index 0000000..c7fc3ac
--- /dev/null
+++ b/final/test/ScopInfo/simple_loop_unsigned_3.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [N] -> { : }
+;
+; CHECK:              Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_bb[0] };
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* nocapture %a, i64 %N) nounwind {
+entry:
+  br label %bb
+
+bb:                                               ; preds = %bb, %entry
+  %i = phi i64 [ 1000, %entry ], [ %i.dec, %bb ]
+  %scevgep = getelementptr inbounds i64, i64* %a, i64 %i
+  store i64 %i, i64* %scevgep
+  %i.dec = add nsw i64 %i, -1
+  %sub = sub nsw i64 %N, %i
+  %exitcond = icmp ult i64 %sub, 0
+  br i1 %exitcond, label %bb, label %return
+
+return:                                           ; preds = %bb, %entry
+  ret void
+}
diff --git a/final/test/ScopInfo/simple_nonaffine_loop_not.ll b/final/test/ScopInfo/simple_nonaffine_loop_not.ll
new file mode 100644
index 0000000..a5b5433
--- /dev/null
+++ b/final/test/ScopInfo/simple_nonaffine_loop_not.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | not FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+@.str = private unnamed_addr constant [17 x i8] c"Random Value: %d\00", align 1
+
+define i32 @main() nounwind uwtable ssp {
+entry:
+  %A = alloca [1048576 x i32], align 16
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %0 = phi i32 [ 0, %entry.split ], [ %1, %for.body ]
+  %mul = mul i32 %0, 2
+  %mul1 = mul nsw i32 %0, %0
+  %idxprom1 = zext i32 %mul1 to i64
+  %arrayidx = getelementptr inbounds [1048576 x i32], [1048576 x i32]* %A, i64 0, i64 %idxprom1
+  store i32 %mul, i32* %arrayidx, align 4
+  %1 = add nsw i32 %0, 1
+  %exitcond = icmp ne i32 %1, 1024
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.end:                                          ; preds = %for.body
+  %call = call i32 @rand() nounwind
+  %rem = srem i32 %call, 1024
+  %mul2 = shl nsw i32 %rem, 10
+  %idxprom3 = sext i32 %mul2 to i64
+  %arrayidx4 = getelementptr inbounds [1048576 x i32], [1048576 x i32]* %A, i64 0, i64 %idxprom3
+  %2 = load i32, i32* %arrayidx4, align 16
+  %call5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str, i64 0, i64 0), i32 %2) nounwind
+  ret i32 0
+}
+
+declare i32 @printf(i8*, ...)
+
+declare i32 @rand()
+; CHECK:                { Stmt_for_body[i0] -> MemRef_A[o0] };
diff --git a/final/test/ScopInfo/smax.ll b/final/test/ScopInfo/smax.ll
new file mode 100644
index 0000000..be7ca3c
--- /dev/null
+++ b/final/test/ScopInfo/smax.ll
@@ -0,0 +1,25 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:32-n32-S64"
+
+define void @foo(i32 * noalias %data, i32 * noalias %ptr, i32 %x_pos, i32 %w) {
+entry:
+  br label %for.body
+
+for.body:
+  %x = phi i32 [ 0, %entry ], [ %x.inc, %for.body ]
+  %add = add nsw i32 %x, %x_pos
+  %cmp1 = icmp sgt i32 %add, %w
+  %cond = select i1 %cmp1, i32 %w, i32 %add
+  %arrayidx = getelementptr inbounds i32, i32* %ptr, i32 %cond
+  store i32 1, i32* %arrayidx
+  %x.inc = add nsw i32 %x, 1
+  %cmp = icmp slt i32 %x.inc, 2
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+  ret void
+}
+
+; We check that there are only two parameters, but not a third one that
+; represents the smax() expression. This test case comes from PR 18155.
+; CHECK: [w, x_pos]
diff --git a/final/test/ScopInfo/statistics.ll b/final/test/ScopInfo/statistics.ll
new file mode 100644
index 0000000..d6f784d
--- /dev/null
+++ b/final/test/ScopInfo/statistics.ll
@@ -0,0 +1,241 @@
+; RUN: opt %loadPolly -polly-scops -stats -analyze < %s 2>&1 | FileCheck %s
+; REQUIRES: asserts
+
+; CHECK-DAG:  4 polly-scops      - Maximal number of loops in scops
+; CHECK-DAG: 10 polly-scops      - Number of loops in scops
+; CHECK-DAG:  1 polly-scops      - Number of scops with maximal loop depth 4
+; CHECK-DAG:  1 polly-scops      - Number of scops with maximal loop depth 1
+; CHECK-DAG:  1 polly-scops      - Number of scops with maximal loop depth 3
+; CHECK-DAG:  1 polly-scops      - Number of scops with maximal loop depth 2
+; CHECK-DAG:  4 polly-scops      - Number of Scops containing a loop
+; CHECK-DAG:  4 polly-scops      - Number of valid Scops
+;
+;    void foo_1d(float *A) {
+;      for (long i = 0; i < 1024; i++)
+;        A[i] += i;
+;    }
+;
+;    void foo_2d(float *A) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          A[i + j] += i + j;
+;    }
+;
+;    void foo_3d(float *A) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          for (long k = 0; k < 1024; k++)
+;            A[i + j + k] += i + j + k;
+;    }
+;
+;    void foo_4d(float *A) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++)
+;          for (long k = 0; k < 1024; k++)
+;            for (long l = 0; l < 1024; l++)
+;              A[i + j + k + l] += i + j + k + l;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @foo_1d(float* %A) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb6, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp7, %bb6 ]
+  %exitcond = icmp ne i64 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb8
+
+bb2:                                              ; preds = %bb1
+  %tmp = sitofp i64 %i.0 to float
+  %tmp3 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp4 = load float, float* %tmp3, align 4
+  %tmp5 = fadd float %tmp4, %tmp
+  store float %tmp5, float* %tmp3, align 4
+  br label %bb6
+
+bb6:                                              ; preds = %bb2
+  %tmp7 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb8:                                              ; preds = %bb1
+  ret void
+}
+
+define void @foo_2d(float* %A) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb14, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp15, %bb14 ]
+  %exitcond1 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond1, label %bb3, label %bb16
+
+bb3:                                              ; preds = %bb2
+  br label %bb4
+
+bb4:                                              ; preds = %bb11, %bb3
+  %j.0 = phi i64 [ 0, %bb3 ], [ %tmp12, %bb11 ]
+  %exitcond = icmp ne i64 %j.0, 1024
+  br i1 %exitcond, label %bb5, label %bb13
+
+bb5:                                              ; preds = %bb4
+  %tmp = add nuw nsw i64 %i.0, %j.0
+  %tmp6 = sitofp i64 %tmp to float
+  %tmp7 = add nuw nsw i64 %i.0, %j.0
+  %tmp8 = getelementptr inbounds float, float* %A, i64 %tmp7
+  %tmp9 = load float, float* %tmp8, align 4
+  %tmp10 = fadd float %tmp9, %tmp6
+  store float %tmp10, float* %tmp8, align 4
+  br label %bb11
+
+bb11:                                             ; preds = %bb5
+  %tmp12 = add nuw nsw i64 %j.0, 1
+  br label %bb4
+
+bb13:                                             ; preds = %bb4
+  br label %bb14
+
+bb14:                                             ; preds = %bb13
+  %tmp15 = add nuw nsw i64 %i.0, 1
+  br label %bb2
+
+bb16:                                             ; preds = %bb2
+  ret void
+}
+
+define void @foo_3d(float* %A) {
+bb:
+  br label %bb3
+
+bb3:                                              ; preds = %bb22, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp23, %bb22 ]
+  %exitcond2 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond2, label %bb4, label %bb24
+
+bb4:                                              ; preds = %bb3
+  br label %bb5
+
+bb5:                                              ; preds = %bb19, %bb4
+  %j.0 = phi i64 [ 0, %bb4 ], [ %tmp20, %bb19 ]
+  %exitcond1 = icmp ne i64 %j.0, 1024
+  br i1 %exitcond1, label %bb6, label %bb21
+
+bb6:                                              ; preds = %bb5
+  br label %bb7
+
+bb7:                                              ; preds = %bb16, %bb6
+  %k.0 = phi i64 [ 0, %bb6 ], [ %tmp17, %bb16 ]
+  %exitcond = icmp ne i64 %k.0, 1024
+  br i1 %exitcond, label %bb8, label %bb18
+
+bb8:                                              ; preds = %bb7
+  %tmp = add nuw nsw i64 %i.0, %j.0
+  %tmp9 = add nuw nsw i64 %tmp, %k.0
+  %tmp10 = sitofp i64 %tmp9 to float
+  %tmp11 = add nuw nsw i64 %i.0, %j.0
+  %tmp12 = add nuw nsw i64 %tmp11, %k.0
+  %tmp13 = getelementptr inbounds float, float* %A, i64 %tmp12
+  %tmp14 = load float, float* %tmp13, align 4
+  %tmp15 = fadd float %tmp14, %tmp10
+  store float %tmp15, float* %tmp13, align 4
+  br label %bb16
+
+bb16:                                             ; preds = %bb8
+  %tmp17 = add nuw nsw i64 %k.0, 1
+  br label %bb7
+
+bb18:                                             ; preds = %bb7
+  br label %bb19
+
+bb19:                                             ; preds = %bb18
+  %tmp20 = add nuw nsw i64 %j.0, 1
+  br label %bb5
+
+bb21:                                             ; preds = %bb5
+  br label %bb22
+
+bb22:                                             ; preds = %bb21
+  %tmp23 = add nuw nsw i64 %i.0, 1
+  br label %bb3
+
+bb24:                                             ; preds = %bb3
+  ret void
+}
+
+define void @foo_4d(float* %A) {
+bb:
+  br label %bb4
+
+bb4:                                              ; preds = %bb30, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp31, %bb30 ]
+  %exitcond3 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond3, label %bb5, label %bb32
+
+bb5:                                              ; preds = %bb4
+  br label %bb6
+
+bb6:                                              ; preds = %bb27, %bb5
+  %j.0 = phi i64 [ 0, %bb5 ], [ %tmp28, %bb27 ]
+  %exitcond2 = icmp ne i64 %j.0, 1024
+  br i1 %exitcond2, label %bb7, label %bb29
+
+bb7:                                              ; preds = %bb6
+  br label %bb8
+
+bb8:                                              ; preds = %bb24, %bb7
+  %k.0 = phi i64 [ 0, %bb7 ], [ %tmp25, %bb24 ]
+  %exitcond1 = icmp ne i64 %k.0, 1024
+  br i1 %exitcond1, label %bb9, label %bb26
+
+bb9:                                              ; preds = %bb8
+  br label %bb10
+
+bb10:                                             ; preds = %bb21, %bb9
+  %l.0 = phi i64 [ 0, %bb9 ], [ %tmp22, %bb21 ]
+  %exitcond = icmp ne i64 %l.0, 1024
+  br i1 %exitcond, label %bb11, label %bb23
+
+bb11:                                             ; preds = %bb10
+  %tmp = add nuw nsw i64 %i.0, %j.0
+  %tmp12 = add nuw nsw i64 %tmp, %k.0
+  %tmp13 = add nuw nsw i64 %tmp12, %l.0
+  %tmp14 = sitofp i64 %tmp13 to float
+  %tmp15 = add nuw nsw i64 %i.0, %j.0
+  %tmp16 = add nuw nsw i64 %tmp15, %k.0
+  %tmp17 = add nuw nsw i64 %tmp16, %l.0
+  %tmp18 = getelementptr inbounds float, float* %A, i64 %tmp17
+  %tmp19 = load float, float* %tmp18, align 4
+  %tmp20 = fadd float %tmp19, %tmp14
+  store float %tmp20, float* %tmp18, align 4
+  br label %bb21
+
+bb21:                                             ; preds = %bb11
+  %tmp22 = add nuw nsw i64 %l.0, 1
+  br label %bb10
+
+bb23:                                             ; preds = %bb10
+  br label %bb24
+
+bb24:                                             ; preds = %bb23
+  %tmp25 = add nuw nsw i64 %k.0, 1
+  br label %bb8
+
+bb26:                                             ; preds = %bb8
+  br label %bb27
+
+bb27:                                             ; preds = %bb26
+  %tmp28 = add nuw nsw i64 %j.0, 1
+  br label %bb6
+
+bb29:                                             ; preds = %bb6
+  br label %bb30
+
+bb30:                                             ; preds = %bb29
+  %tmp31 = add nuw nsw i64 %i.0, 1
+  br label %bb4
+
+bb32:                                             ; preds = %bb4
+  ret void
+}
diff --git a/final/test/ScopInfo/stmt_split_exit_of_region_stmt.ll b/final/test/ScopInfo/stmt_split_exit_of_region_stmt.ll
new file mode 100644
index 0000000..bdd8370
--- /dev/null
+++ b/final/test/ScopInfo/stmt_split_exit_of_region_stmt.ll
@@ -0,0 +1,74 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-print-instructions < %s | FileCheck %s
+;
+; CHECK:    Statements {
+; CHECK-NEXT:   Stmt_Region__TO__Stmt
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Region__TO__Stmt[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Region__TO__Stmt[i0] -> [i0, 0] };
+; CHECK-NEXT:       MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Region__TO__Stmt[i0] -> MemRef_C[0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             %cond = fcmp oeq double 2.100000e+01, 2.100000e+01
+; CHECK-NEXT:       }
+; CHECK-NEXT:   Stmt_Stmt
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> [i0, 1] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+; CHECK-NEXT:       }
+; CHECK-NEXT:   Stmt_Stmt1
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> [i0, 2] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx2, align 4
+; CHECK-NEXT:       }
+; CHECK-NEXT:   }
+;
+; Function Attrs: noinline nounwind uwtable 
+define void @func(i32* %A, i32* %B, double* %C) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ]
+  %cmp = icmp slt i32 %i.0, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %Region
+
+Region:                                           ; preds = %for.body
+  %cond = fcmp oeq double 2.100000e+01, 2.100000e+01
+  br i1 %cond, label %Region_true, label %Stmt
+
+Region_true:                                      ; preds = %Region
+  store double 0.000000e+00, double* %C
+  br label %Stmt
+
+Stmt:                                             ; preds = %Region_true, %Region
+  %idxprom = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+  %idxprom1 = sext i32 %i.0 to i64
+  %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %idxprom1
+  store i32 %i.0, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %Stmt
+  %add = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+!0 = !{!"polly_split_after"}
diff --git a/final/test/ScopInfo/stmt_split_no_after_split.ll b/final/test/ScopInfo/stmt_split_no_after_split.ll
new file mode 100644
index 0000000..07bf824
--- /dev/null
+++ b/final/test/ScopInfo/stmt_split_no_after_split.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-print-instructions < %s | FileCheck %s
+;
+; CHECK:    Statements {
+; CHECK-NEXT: 	Stmt_Stmt
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> [i0] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+; CHECK-NEXT:       }
+; CHECK-NEXT:   }
+;
+; Function Attrs: noinline nounwind uwtable
+define void @func(i32* %A) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ]
+  %cmp = icmp slt i32 %i.0, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %Stmt
+
+Stmt:
+  %idxprom = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+  br label %for.inc
+
+for.inc:                                          ; preds = %Stmt
+  %add = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+!0 = !{!"polly_split_after"}
diff --git a/final/test/ScopInfo/stmt_split_no_dependence.ll b/final/test/ScopInfo/stmt_split_no_dependence.ll
new file mode 100644
index 0000000..e11f7fb
--- /dev/null
+++ b/final/test/ScopInfo/stmt_split_no_dependence.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-print-instructions < %s | FileCheck %s
+
+;      void func(int *A, int *B){
+;        for (int i = 0; i < 1024; i+=1) {
+;      Stmt:
+;          A[i] = i;
+;          B[i] = i;
+;        }
+;      }
+;
+; CHECK:    Statements {
+; CHECK-NEXT: 	Stmt_Stmt
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> [i0, 0] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+; CHECK-NEXT:       }
+; CHECK-NEXT:  	Stmt_Stmt1
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> [i0, 1] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx2, align 4
+; CHECK-NEXT:       }
+; CHECK-NEXT:    }
+;
+; Function Attrs: noinline nounwind uwtable
+define void @func(i32* %A, i32* %B) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ]
+  %cmp = icmp slt i32 %i.0, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %Stmt
+
+Stmt:                                             ; preds = %for.body
+  %idxprom = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+  %idxprom1 = sext i32 %i.0 to i64
+  %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %idxprom1
+  store i32 %i.0, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %Stmt
+  %add = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+!0 = !{!"polly_split_after"}
diff --git a/final/test/ScopInfo/stmt_split_on_store.ll b/final/test/ScopInfo/stmt_split_on_store.ll
new file mode 100644
index 0000000..2b2fc46
--- /dev/null
+++ b/final/test/ScopInfo/stmt_split_on_store.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-stmt-granularity=store -polly-print-instructions < %s | FileCheck %s
+
+;      void func(int *A, int *B){
+;        for (int i = 0; i < 1024; i+=1) {
+;      Stmt:
+;          A[i] = i;
+;          B[i] = i;
+;        }
+;      }
+;
+; CHECK:    Statements {
+; CHECK-NEXT: 	Stmt_Stmt
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> [i0, 0] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx, align 4
+; CHECK-NEXT:       }
+; CHECK-NEXT:  	Stmt_Stmt1
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> [i0, 1] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx2, align 4
+; CHECK-NEXT:       }
+; CHECK-NEXT:    }
+;
+; Function Attrs: noinline nounwind uwtable
+define void @func(i32* %A, i32* %B) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ]
+  %cmp = icmp slt i32 %i.0, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %Stmt
+
+Stmt:                                             ; preds = %for.body
+  %idxprom = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  store i32 %i.0, i32* %arrayidx, align 4
+  %idxprom1 = sext i32 %i.0 to i64
+  %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %idxprom1
+  store i32 %i.0, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %Stmt
+  %add = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/stmt_split_on_synthesizable.ll b/final/test/ScopInfo/stmt_split_on_synthesizable.ll
new file mode 100644
index 0000000..0ae49d8
--- /dev/null
+++ b/final/test/ScopInfo/stmt_split_on_synthesizable.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-print-instructions < %s | FileCheck %s
+;
+; CHECK:    Statements {
+; CHECK-NEXT:   Stmt_Stmt
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> [i0, 0] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx, align 4
+; CHECK-NEXT:       }
+; CHECK-NEXT:   Stmt_Stmt1
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> [i0, 1] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx2, align 4
+; CHECK-NEXT:       }
+; CHECK-NEXT:   }
+;
+; Function Attrs: noinline nounwind uwtable
+define void @func(i32* %A, i32* %B, double* %C) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ]
+  %cmp = icmp slt i32 %i.0, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %Stmt
+
+Stmt:
+  %idxprom = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  store i32 %i.0, i32* %arrayidx, align 4
+  %idxprom1 = sext i32 %i.0 to i64, !polly_split_after !0
+  %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %idxprom1
+  store i32 %i.0, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %Stmt
+  %add = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+!0 = !{!"polly_split_after"}
diff --git a/final/test/ScopInfo/stmt_split_phi_in_beginning_bb.ll b/final/test/ScopInfo/stmt_split_phi_in_beginning_bb.ll
new file mode 100644
index 0000000..1e3c180
--- /dev/null
+++ b/final/test/ScopInfo/stmt_split_phi_in_beginning_bb.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-print-instructions < %s | FileCheck %s
+;
+; CHECK:    Statements {
+; CHECK-NEXT:  	Stmt_Stmt
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> [i0, 0] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %phi, i32* %arrayidx, align 4, !polly_split_after !0
+; CHECK-NEXT:       }
+; CHECK-NEXT: 	Stmt_Stmt1
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> [i0, 1] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx2, align 4
+; CHECK-NEXT:       }
+; CHECK-NEXT:   }
+;
+; Function Attrs: noinline nounwind uwtable
+define void @func(i32* %A, i32* %B) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ]
+  %cmp = icmp slt i32 %i.0, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %Stmt
+
+Stmt:
+  %phi = phi i32 [0, %for.body]
+  %idxprom = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  store i32 %phi, i32* %arrayidx, align 4, !polly_split_after !0
+  %idxprom1 = sext i32 %i.0 to i64
+  %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %idxprom1
+  store i32 %i.0, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %Stmt
+  %add = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+!0 = !{!"polly_split_after"}
diff --git a/final/test/ScopInfo/stmt_split_phi_in_stmt.ll b/final/test/ScopInfo/stmt_split_phi_in_stmt.ll
new file mode 100644
index 0000000..44faf84
--- /dev/null
+++ b/final/test/ScopInfo/stmt_split_phi_in_stmt.ll
@@ -0,0 +1,75 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-print-instructions < %s | FileCheck %s
+;
+; CHECK:    Statements {
+; CHECK-NEXT:  	Stmt_Stmt
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> [i0, 0] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+; CHECK-NEXT:       }
+; CHECK-NEXT:  	Stmt_Stmt1
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> [i0, 1] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             %d = fadd double 2.100000e+01, 2.100000e+01
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx2, align 4
+; CHECK-NEXT:       }
+; CHECK-NEXT:   Stmt_for_inc
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_for_inc[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_for_inc[i0] -> [i0, 2] };
+; CHECK-NEXT:       ReadAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:           { Stmt_for_inc[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_for_inc[i0] -> MemRef_C[0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             %phi = phi double [ %d, %Stmt ]
+; CHECK-NEXT:             store double %phi, double* %C
+; CHECK-NEXT:       }
+; CHECK-NEXT:   }
+;
+; Function Attrs: noinline nounwind uwtable
+define void @func(i32* %A, i32* %B, double* %C) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ]
+  %cmp = icmp slt i32 %i.0, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %Stmt
+
+Stmt:
+  %idxprom = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+  %idxprom1 = sext i32 %i.0 to i64
+  %d = fadd double 21.0, 21.0
+  %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %idxprom1
+  store i32 %i.0, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %Stmt
+  %phi = phi double [%d, %Stmt]
+  store double %phi, double* %C
+  %add = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+!0 = !{!"polly_split_after"}
diff --git a/final/test/ScopInfo/stmt_split_scalar_dependence.ll b/final/test/ScopInfo/stmt_split_scalar_dependence.ll
new file mode 100644
index 0000000..7ce13c3
--- /dev/null
+++ b/final/test/ScopInfo/stmt_split_scalar_dependence.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-print-instructions < %s | FileCheck %s
+;
+; CHECK:    Statements {
+; CHECK-NEXT:  	Stmt_Stmt
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> [i0, 0] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:           { Stmt_Stmt[i0] -> MemRef_a[] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             %a = fadd double 2.100000e+01, 2.100000e+01
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+; CHECK-NEXT:       }
+; CHECK-NEXT:   Stmt_Stmt1
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> [i0, 1] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> MemRef_B[0] };
+; CHECK-NEXT:       ReadAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:           { Stmt_Stmt1[i0] -> MemRef_a[] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store double %a, double* %B
+; CHECK-NEXT:       }
+; CHECK-NEXT:   }
+;
+; Function Attrs: noinline nounwind uwtable
+define void @func(i32* %A, double* %B) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ]
+  %cmp = icmp slt i32 %i.0, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %Stmt
+
+Stmt:
+  %a = fadd double 21.0, 21.0
+  %idxprom = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+  store double %a, double* %B
+  br label %for.inc
+
+for.inc:                                          ; preds = %Stmt
+  %add = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+!0 = !{!"polly_split_after"}
diff --git a/final/test/ScopInfo/stmt_split_within_loop.ll b/final/test/ScopInfo/stmt_split_within_loop.ll
new file mode 100644
index 0000000..a583771
--- /dev/null
+++ b/final/test/ScopInfo/stmt_split_within_loop.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-print-instructions < %s | FileCheck %s
+;
+; CHECK:    Statements {
+; CHECK-NEXT:  	Stmt_Stmt
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 512 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt[i0, i1] -> [i0, i1, 0] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt[i0, i1] -> MemRef_A[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+; CHECK-NEXT:       }
+; CHECK-NEXT:  	Stmt_Stmt1
+; CHECK-NEXT:       Domain :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 512 };
+; CHECK-NEXT:       Schedule :=
+; CHECK-NEXT:           { Stmt_Stmt1[i0, i1] -> [i0, i1, 1] };
+; CHECK-NEXT:       MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:           { Stmt_Stmt1[i0, i1] -> MemRef_B[i0] };
+; CHECK-NEXT:       Instructions {
+; CHECK-NEXT:             store i32 %i.0, i32* %arrayidx2, align 4
+; CHECK-NEXT:             %cond = icmp slt i32 %j, 512
+; CHECK-NEXT:       }
+; CHECK-NEXT:   }
+;
+; Function Attrs: noinline nounwind uwtable
+define void @func(i32* %A, i32* %B, double* %C) #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ]
+  %cmp = icmp slt i32 %i.0, 1024
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  br label %Stmt
+
+Stmt:
+  %j = phi i32 [ 0, %for.body ], [ %inc, %Stmt ]
+  %idxprom = sext i32 %i.0 to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  store i32 %i.0, i32* %arrayidx, align 4, !polly_split_after !0
+  %idxprom1 = sext i32 %i.0 to i64
+  %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %idxprom1
+  store i32 %i.0, i32* %arrayidx2, align 4
+  %inc = add nsw i32 %j, 1
+  %cond = icmp slt i32 %j, 512
+  br i1 %cond, label %Stmt, label %for.inc
+
+for.inc:                                          ; preds = %Stmt
+  %add = add nsw i32 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+!0 = !{!"polly_split_after"}
diff --git a/final/test/ScopInfo/stride_detection.ll b/final/test/ScopInfo/stride_detection.ll
new file mode 100644
index 0000000..da0abb0
--- /dev/null
+++ b/final/test/ScopInfo/stride_detection.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-vectorizer=polly -polly-codegen < %s -S | FileCheck %s
+
+; #pragma known-parallel
+;   for (int c0 = 0; c0 <= 31; c0 += 1)
+;     for (int c1 = 0; c1 <= floord(nk - 1, 32); c1 += 1)
+;       for (int c2 = 0; c2 <= 7; c2 += 1)
+;         for (int c3 = 0; c3 <= min(31, nk - 32 * c1 - 1); c3 += 1)
+;           #pragma simd
+;           for (int c4 = 0; c4 <= 3; c4 += 1)
+;             Stmt_for_body_3(32 * c0 + 4 * c2 + c4, 32 * c1 + c3);
+
+; CHECK: polly.stmt.for.body.3:                            ; preds = %polly.loop_header18
+; CHECK:   %_p_splat_one = load <1 x double>, <1 x double>* %_p_vec_p, align 8, !alias.scope !1, !noalias !3, !llvm.mem.parallel_loop_access !0
+; CHECK:   %_p_vec_full = load <4 x double>, <4 x double>* %vector_ptr, align 8, !alias.scope !4, !noalias !5, !llvm.mem.parallel_loop_access !0
+; CHECK:   extractelement <4 x double> %addp_vec, i32 0
+; CHECK:   extractelement <4 x double> %addp_vec, i32 1
+; CHECK:   extractelement <4 x double> %addp_vec, i32 2
+; CHECK:   extractelement <4 x double> %addp_vec, i32 3
+; CHECK:   store <4 x double> %addp_vec, <4 x double>* {{.*}}, align 8, !alias.scope !4, !noalias !5, !llvm.mem.parallel_loop_access !0
+
+define void @kernel_gemm(i32 %ni, i32 %nj, i32 %nk, [1024 x double]* %C, [1024 x double]* %A) #0 {
+entry:
+  br label %for.cond.1.preheader
+
+for.cond.1.preheader:                             ; preds = %entry, %for.inc.10
+  %indvars.iv16 = phi i64 [ 0, %entry ], [ %indvars.iv.next17, %for.inc.10 ]
+  %cmp2.13 = icmp sgt i32 %nk, 0
+  br i1 %cmp2.13, label %for.body.3.lr.ph, label %for.inc.10
+
+for.body.3.lr.ph:                                 ; preds = %for.cond.1.preheader
+  br label %for.body.3
+
+for.body.3:                                       ; preds = %for.body.3.lr.ph, %for.body.3
+  %indvars.iv = phi i64 [ 0, %for.body.3.lr.ph ], [ %indvars.iv.next, %for.body.3 ]
+  %arrayidx5 = getelementptr inbounds [1024 x double], [1024 x double]* %A, i64 0, i64 %indvars.iv
+  %0 = load double, double* %arrayidx5, align 8
+  %arrayidx9 = getelementptr inbounds [1024 x double], [1024 x double]* %C, i64 0, i64 %indvars.iv16
+  %1 = load double, double* %arrayidx9, align 8
+  %add = fadd double %0, %1
+  store double %add, double* %arrayidx9, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %lftr.wideiv = trunc i64 %indvars.iv.next to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, %nk
+  br i1 %exitcond, label %for.body.3, label %for.cond.1.for.inc.10_crit_edge
+
+for.cond.1.for.inc.10_crit_edge:                  ; preds = %for.body.3
+  br label %for.inc.10
+
+for.inc.10:                                       ; preds = %for.cond.1.for.inc.10_crit_edge, %for.cond.1.preheader
+  %indvars.iv.next17 = add nuw nsw i64 %indvars.iv16, 1
+  %exitcond18 = icmp ne i64 %indvars.iv.next17, 1024
+  br i1 %exitcond18, label %for.cond.1.preheader, label %for.end.12
+
+for.end.12:                                       ; preds = %for.inc.10
+  ret void
+}
diff --git a/final/test/ScopInfo/switch-1.ll b/final/test/ScopInfo/switch-1.ll
new file mode 100644
index 0000000..ca63b3e
--- /dev/null
+++ b/final/test/ScopInfo/switch-1.ll
@@ -0,0 +1,120 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=AST
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        switch (i % 4) {
+;        case 0:
+;          break;
+;        case 1:
+;          A[i] += 1;
+;          break;
+;        case 2:
+;          A[i] += 2;
+;          break;
+;        case 3:
+;          A[i] += 3;
+;          break;
+;        }
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_sw_bb_1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] : 4*floor((-1 + i0)/4) = -1 + i0 and 0 < i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] -> [i0, 2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_sw_bb_2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_2[i0] : 4*floor((2 + i0)/4) = 2 + i0 and 2 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_2[i0] -> [i0, 1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_2[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_2[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_sw_bb_6
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_6[i0] : 4*floor((1 + i0)/4) = 1 + i0 and 3 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_6[i0] -> [i0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_6[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_6[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+
+; AST:      if (1)
+;
+; AST:         for (int c0 = 1; c0 < N; c0 += 4) {
+; AST-NEXT:      Stmt_sw_bb_1(c0);
+; AST-NEXT:      if (N >= c0 + 2) {
+; AST-NEXT:        Stmt_sw_bb_2(c0 + 1);
+; AST-NEXT:        if (N >= c0 + 3)
+; AST-NEXT:          Stmt_sw_bb_6(c0 + 2);
+; AST-NEXT:      }
+; AST-NEXT:    }
+;
+; AST:      else
+; AST-NEXT:     {  /* original code */ }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp1 = trunc i64 %indvars.iv to i32
+  %rem = srem i32 %tmp1, 4
+  switch i32 %rem, label %sw.epilog [
+    i32 0, label %sw.bb
+    i32 1, label %sw.bb.1
+    i32 2, label %sw.bb.2
+    i32 3, label %sw.bb.6
+  ]
+
+sw.bb:                                            ; preds = %for.body
+  br label %sw.epilog
+
+sw.bb.1:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp2, 1
+  store i32 %add, i32* %arrayidx, align 4
+  br label %sw.epilog
+
+sw.bb.2:                                          ; preds = %for.body
+  %arrayidx4 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %arrayidx4, align 4
+  %add5 = add nsw i32 %tmp3, 2
+  store i32 %add5, i32* %arrayidx4, align 4
+  br label %sw.epilog
+
+sw.bb.6:                                          ; preds = %for.body
+  %arrayidx8 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp4 = load i32, i32* %arrayidx8, align 4
+  %add9 = add nsw i32 %tmp4, 3
+  store i32 %add9, i32* %arrayidx8, align 4
+  br label %sw.epilog
+
+sw.epilog:                                        ; preds = %sw.bb.6, %sw.bb.2, %sw.bb.1, %sw.bb, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %sw.epilog
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/switch-2.ll b/final/test/ScopInfo/switch-2.ll
new file mode 100644
index 0000000..1060519
--- /dev/null
+++ b/final/test/ScopInfo/switch-2.ll
@@ -0,0 +1,103 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=AST
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        switch (i % 4) {
+;        case 0:
+;          A[i] += 1;
+;          break;
+;        case 1:
+;          break;
+;        case 2:
+;          A[i] += 2;
+;          break;
+;        case 3:
+;          break;
+;        }
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_sw_bb
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] : 4*floor((i0)/4) = i0 and 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] -> [i0, 1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_sw_bb_2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_2[i0] : 4*floor((2 + i0)/4) = 2 + i0 and 2 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_2[i0] -> [i0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_2[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_2[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+
+; AST:      if (1)
+;
+; AST:         for (int c0 = 0; c0 < N; c0 += 4) {
+; AST-NEXT:      Stmt_sw_bb(c0);
+; AST-NEXT:      if (N >= c0 + 3)
+; AST-NEXT:        Stmt_sw_bb_2(c0 + 2);
+; AST-NEXT:    }
+;
+; AST:      else
+; AST-NEXT:     {  /* original code */ }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp1 = trunc i64 %indvars.iv to i32
+  %rem = srem i32 %tmp1, 4
+  switch i32 %rem, label %sw.epilog [
+    i32 0, label %sw.bb
+    i32 1, label %sw.bb.1
+    i32 2, label %sw.bb.2
+    i32 3, label %sw.bb.6
+  ]
+
+sw.bb:                                            ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp2, 1
+  store i32 %add, i32* %arrayidx, align 4
+  br label %sw.epilog
+
+sw.bb.1:                                          ; preds = %for.body
+  br label %sw.epilog
+
+sw.bb.2:                                          ; preds = %for.body
+  %arrayidx4 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %arrayidx4, align 4
+  %add5 = add nsw i32 %tmp3, 2
+  store i32 %add5, i32* %arrayidx4, align 4
+  br label %sw.epilog
+
+sw.bb.6:                                          ; preds = %for.body
+  br label %sw.epilog
+
+sw.epilog:                                        ; preds = %sw.bb.6, %sw.bb.2, %sw.bb.1, %sw.bb, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %sw.epilog
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/switch-3.ll b/final/test/ScopInfo/switch-3.ll
new file mode 100644
index 0000000..c32ce10
--- /dev/null
+++ b/final/test/ScopInfo/switch-3.ll
@@ -0,0 +1,135 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=AST
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        switch (i % 4) {
+;        case 0:
+;          A[i] += 1;
+;        case 1:
+;          A[i] += 2;
+;          break;
+;        case 2:
+;          A[i] += 3;
+;        case 3:
+;          A[i] += 4;
+;          break;
+;        }
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_sw_bb
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] : 4*floor((i0)/4) = i0 and 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] -> [i0, 2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_sw_bb_1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] : 0 <= i0 < N and 4*floor((i0)/4) >= -1 + i0  };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] -> [i0, 3] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_sw_bb_5
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_5[i0] : 4*floor((2 + i0)/4) = 2 + i0 and 2 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_5[i0] -> [i0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_5[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_5[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_sw_bb_9
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_9[i0] : 0 <= i0 < N and 4*floor((i0)/4) <= -2 + i0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_9[i0] -> [i0, 1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_9[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_9[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+
+; AST:      if (1)
+;
+; AST:          for (int c0 = 0; c0 < N; c0 += 1) {
+; AST-NEXT:       if ((c0 + 2) % 4 == 0)
+; AST-NEXT:         Stmt_sw_bb_5(c0);
+; AST-NEXT:       if (c0 % 4 >= 2) {
+; AST-NEXT:         Stmt_sw_bb_9(c0);
+; AST-NEXT:       } else {
+; AST-NEXT:         if (c0 % 4 == 0)
+; AST-NEXT:           Stmt_sw_bb(c0);
+; AST-NEXT:         Stmt_sw_bb_1(c0);
+; AST-NEXT:       }
+; AST-NEXT:     }
+;
+; AST:      else
+; AST-NEXT:     {  /* original code */ }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp1 = trunc i64 %indvars.iv to i32
+  %rem = srem i32 %tmp1, 4
+  switch i32 %rem, label %sw.epilog [
+    i32 0, label %sw.bb
+    i32 1, label %sw.bb.1
+    i32 2, label %sw.bb.5
+    i32 3, label %sw.bb.9
+  ]
+
+sw.bb:                                            ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp2, 1
+  store i32 %add, i32* %arrayidx, align 4
+  br label %sw.bb.1
+
+sw.bb.1:                                          ; preds = %sw.bb, %for.body
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %arrayidx3, align 4
+  %add4 = add nsw i32 %tmp3, 2
+  store i32 %add4, i32* %arrayidx3, align 4
+  br label %sw.epilog
+
+sw.bb.5:                                          ; preds = %for.body
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp4 = load i32, i32* %arrayidx7, align 4
+  %add8 = add nsw i32 %tmp4, 3
+  store i32 %add8, i32* %arrayidx7, align 4
+  br label %sw.bb.9
+
+sw.bb.9:                                          ; preds = %sw.bb.5, %for.body
+  %arrayidx11 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp5 = load i32, i32* %arrayidx11, align 4
+  %add12 = add nsw i32 %tmp5, 4
+  store i32 %add12, i32* %arrayidx11, align 4
+  br label %sw.epilog
+
+sw.epilog:                                        ; preds = %sw.bb.9, %sw.bb.1, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %sw.epilog
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/switch-4.ll b/final/test/ScopInfo/switch-4.ll
new file mode 100644
index 0000000..19644aa
--- /dev/null
+++ b/final/test/ScopInfo/switch-4.ll
@@ -0,0 +1,150 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=AST
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++)
+;        switch (i % 4) {
+;        case 0:
+;          A[i] += 1;
+;          break;
+;        case 1:
+;          A[i] += 2;
+;          break;
+;        case 2:
+;          A[i] += 3;
+;          break;
+;        case 3:
+;          A[i] += 4;
+;          break;
+;        default:
+;          A[i - 1] += A[i + 1];
+;        }
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_sw_bb
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] : 4*floor((i0)/4) = i0 and 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] -> [i0, 3] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_sw_bb_1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] : 4*floor((-1 + i0)/4) = -1 + i0 and 0 < i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] -> [i0, 2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_sw_bb_5
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_5[i0] : 4*floor((2 + i0)/4) = 2 + i0 and 2 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_5[i0] -> [i0, 1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_5[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_5[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_sw_bb_9
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_9[i0] : 4*floor((1 + i0)/4) = 1 + i0 and 3 <= i0 < N }; 
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_9[i0] -> [i0, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_9[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_9[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
+
+; AST:      if (1)
+;
+; AST:        for (int c0 = 0; c0 < N; c0 += 4) {
+; AST-NEXT:      Stmt_sw_bb(c0);
+; AST-NEXT:      if (N >= c0 + 2) {
+; AST-NEXT:        Stmt_sw_bb_1(c0 + 1);
+; AST-NEXT:        if (N >= c0 + 3) {
+; AST-NEXT:          Stmt_sw_bb_5(c0 + 2);
+; AST-NEXT:          if (N >= c0 + 4)
+; AST-NEXT:            Stmt_sw_bb_9(c0 + 3);
+; AST-NEXT:        }
+; AST-NEXT:      }
+; AST-NEXT:    }
+;
+; AST:      else
+; AST-NEXT:     {  /* original code */ }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp3 = trunc i64 %indvars.iv to i32
+  %rem = srem i32 %tmp3, 4
+  switch i32 %rem, label %sw.default [
+    i32 0, label %sw.bb
+    i32 1, label %sw.bb.1
+    i32 2, label %sw.bb.5
+    i32 3, label %sw.bb.9
+  ]
+
+sw.bb:                                            ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp4 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp4, 1
+  store i32 %add, i32* %arrayidx, align 4
+  br label %sw.epilog
+
+sw.bb.1:                                          ; preds = %for.body
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp5 = load i32, i32* %arrayidx3, align 4
+  %add4 = add nsw i32 %tmp5, 2
+  store i32 %add4, i32* %arrayidx3, align 4
+  br label %sw.epilog
+
+sw.bb.5:                                          ; preds = %for.body
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp6 = load i32, i32* %arrayidx7, align 4
+  %add8 = add nsw i32 %tmp6, 3
+  store i32 %add8, i32* %arrayidx7, align 4
+  br label %sw.epilog
+
+sw.bb.9:                                          ; preds = %for.body
+  %arrayidx11 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp7 = load i32, i32* %arrayidx11, align 4
+  %add12 = add nsw i32 %tmp7, 4
+  store i32 %add12, i32* %arrayidx11, align 4
+  br label %sw.epilog
+
+sw.default:                                       ; preds = %for.body
+  %tmp8 = add nuw nsw i64 %indvars.iv, 1
+  %arrayidx15 = getelementptr inbounds i32, i32* %A, i64 %tmp8
+  %tmp9 = load i32, i32* %arrayidx15, align 4
+  %tmp10 = add nsw i64 %indvars.iv, -1
+  %arrayidx17 = getelementptr inbounds i32, i32* %A, i64 %tmp10
+  %tmp11 = load i32, i32* %arrayidx17, align 4
+  %add18 = add nsw i32 %tmp11, %tmp9
+  store i32 %add18, i32* %arrayidx17, align 4
+  br label %sw.epilog
+
+sw.epilog:                                        ; preds = %sw.default, %sw.bb.9, %sw.bb.5, %sw.bb.1, %sw.bb
+  br label %for.inc
+
+for.inc:                                          ; preds = %sw.epilog
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/switch-5.ll b/final/test/ScopInfo/switch-5.ll
new file mode 100644
index 0000000..da0dfa4
--- /dev/null
+++ b/final/test/ScopInfo/switch-5.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=AST
+;
+;    void f(int *A, int *B, int N) {
+;      for (int i = 0; i < N; i++) {
+;        A[i]++;
+;        switch (N) {
+;        case 0:
+;          B[i]++;
+;          break;
+;        default:
+;          return;
+;        }
+;      }
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_for_body[0] : N > 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_for_body[i0] -> [0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_for_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_for_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT: }
+
+; AST:      if (1)
+;
+; AST:          if (N >= 1)
+; AST-NEXT:       Stmt_for_body(0);
+;
+; AST:      else
+; AST-NEXT:     {  /* original code */ }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %B, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end.loopexit
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp1, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  switch i32 %N, label %sw.default [
+    i32 0, label %sw.bb
+  ]
+
+sw.bb:                                            ; preds = %for.body
+  %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx2, align 4
+  %inc3 = add nsw i32 %tmp2, 1
+  store i32 %inc3, i32* %arrayidx2, align 4
+  br label %sw.epilog
+
+sw.default:                                       ; preds = %for.body
+  br label %for.end
+
+sw.epilog:                                        ; preds = %sw.bb
+  br label %for.inc
+
+for.inc:                                          ; preds = %sw.epilog
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end.loopexit:                                 ; preds = %for.cond
+  br label %for.end
+
+for.end:                                          ; preds = %for.end.loopexit, %sw.default
+  ret void
+}
diff --git a/final/test/ScopInfo/switch-6.ll b/final/test/ScopInfo/switch-6.ll
new file mode 100644
index 0000000..4ccd079
--- /dev/null
+++ b/final/test/ScopInfo/switch-6.ll
@@ -0,0 +1,141 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=AST
+;
+;    void f(int *A, int N) {
+;      for (int i = 0; i < N; i++) {
+;        switch (i) {
+;        case 0:
+;          A[i] += 1;
+;          break;
+;        case 1:
+;          A[i] += 2;
+;          break;
+;        case 2:
+;          A[i] += 3;
+;          break;
+;        case 3:
+;          A[i] += 4;
+;          break;
+;        default:;
+;        }
+;      }
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_sw_bb
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[0] : N > 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] -> [0, 3] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb[i0] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_sw_bb_1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[1] : N >= 2 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] -> [1, 2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] -> MemRef_A[1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_1[i0] -> MemRef_A[1] };
+; CHECK-NEXT:     Stmt_sw_bb_5
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_5[2] : N >= 3 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_5[i0] -> [2, 1] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_5[i0] -> MemRef_A[2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_5[i0] -> MemRef_A[2] };
+; CHECK-NEXT:     Stmt_sw_bb_9
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_9[3] : N >= 4 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_9[i0] -> [3, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_9[i0] -> MemRef_A[3] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_sw_bb_9[i0] -> MemRef_A[3] };
+; CHECK-NEXT: }
+
+; AST:      if (1)
+;
+; AST:          if (N >= 1) {
+; AST-NEXT:       Stmt_sw_bb(0);
+; AST-NEXT:       if (N >= 2) {
+; AST-NEXT:         Stmt_sw_bb_1(1);
+; AST-NEXT:         if (N >= 3) {
+; AST-NEXT:           Stmt_sw_bb_5(2);
+; AST-NEXT:           if (N >= 4)
+; AST-NEXT:             Stmt_sw_bb_9(3);
+; AST-NEXT:         }
+; AST-NEXT:       }
+; AST-NEXT:     }
+;
+; AST:      else
+; AST-NEXT:     {  /* original code */ }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp1 = trunc i64 %indvars.iv to i32
+  switch i32 %tmp1, label %sw.default [
+    i32 0, label %sw.bb
+    i32 1, label %sw.bb.1
+    i32 2, label %sw.bb.5
+    i32 3, label %sw.bb.9
+  ]
+
+sw.bb:                                            ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %add = add nsw i32 %tmp2, 1
+  store i32 %add, i32* %arrayidx, align 4
+  br label %sw.epilog
+
+sw.bb.1:                                          ; preds = %for.body
+  %arrayidx3 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp3 = load i32, i32* %arrayidx3, align 4
+  %add4 = add nsw i32 %tmp3, 2
+  store i32 %add4, i32* %arrayidx3, align 4
+  br label %sw.epilog
+
+sw.bb.5:                                          ; preds = %for.body
+  %arrayidx7 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp4 = load i32, i32* %arrayidx7, align 4
+  %add8 = add nsw i32 %tmp4, 3
+  store i32 %add8, i32* %arrayidx7, align 4
+  br label %sw.epilog
+
+sw.bb.9:                                          ; preds = %for.body
+  %arrayidx11 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp5 = load i32, i32* %arrayidx11, align 4
+  %add12 = add nsw i32 %tmp5, 4
+  store i32 %add12, i32* %arrayidx11, align 4
+  br label %sw.epilog
+
+sw.default:                                       ; preds = %for.body
+  br label %sw.epilog
+
+sw.epilog:                                        ; preds = %sw.default, %sw.bb.9, %sw.bb.5, %sw.bb.1, %sw.bb
+  br label %for.inc
+
+for.inc:                                          ; preds = %sw.epilog
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/switch-7.ll b/final/test/ScopInfo/switch-7.ll
new file mode 100644
index 0000000..e0f9c60
--- /dev/null
+++ b/final/test/ScopInfo/switch-7.ll
@@ -0,0 +1,126 @@
+
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-ast -analyze < %s | FileCheck %s --check-prefix=AST
+;
+;    void f(int *A, int c, int N) {
+;      switch (c) {
+;      case -1: {
+;        for (int j = N; j > 0; j--)
+;          A[j] += A[j - 1];
+;        break;
+;      }
+;      case 1: {
+;        for (int j = 1; j <= N; j++)
+;          A[j] += A[j - 1];
+;        break;
+;      }
+;      }
+;    }
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [c, N] -> { Stmt_for_body[i0] : c = -1 and 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [c, N] -> { Stmt_for_body[i0] -> [1, i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [c, N] -> { Stmt_for_body[i0] -> MemRef_A[-1 + N - i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [c, N] -> { Stmt_for_body[i0] -> MemRef_A[N - i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [c, N] -> { Stmt_for_body[i0] -> MemRef_A[N - i0] };
+; CHECK-NEXT:     Stmt_for_body_7
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [c, N] -> { Stmt_for_body_7[i0] : c = 1 and 0 <= i0 < N };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [c, N] -> { Stmt_for_body_7[i0] -> [0, i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [c, N] -> { Stmt_for_body_7[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [c, N] -> { Stmt_for_body_7[i0] -> MemRef_A[1 + i0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [c, N] -> { Stmt_for_body_7[i0] -> MemRef_A[1 + i0] };
+; CHECK-NEXT: }
+
+; AST:      if (1)
+;
+; AST:          if (c == 1) {
+; AST-NEXT:       for (int c0 = 0; c0 < N; c0 += 1)
+; AST-NEXT:         Stmt_for_body_7(c0);
+; AST-NEXT:     } else if (c == -1)
+; AST-NEXT:       for (int c0 = 0; c0 < N; c0 += 1)
+; AST-NEXT:         Stmt_for_body(c0);
+;
+; AST:      else
+; AST-NEXT:     {  /* original code */ }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %c, i32 %N) {
+entry:
+  br label %entry.split
+
+entry.split:
+  switch i32 %c, label %sw.epilog [
+    i32 -1, label %sw.bb
+    i32 1, label %sw.bb.3
+  ]
+
+sw.bb:                                            ; preds = %entry
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %sw.bb
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ %tmp, %sw.bb ]
+  %j.0 = phi i32 [ %N, %sw.bb ], [ %dec, %for.inc ]
+  %cmp = icmp sgt i64 %indvars.iv, 0
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %sub = add nsw i32 %j.0, -1
+  %idxprom = sext i32 %sub to i64
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %idxprom
+  %tmp6 = load i32, i32* %arrayidx, align 4
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp7 = load i32, i32* %arrayidx2, align 4
+  %add = add nsw i32 %tmp7, %tmp6
+  store i32 %add, i32* %arrayidx2, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %dec = add nsw i32 %j.0, -1
+  %indvars.iv.next = add nsw i64 %indvars.iv, -1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  br label %sw.epilog
+
+sw.bb.3:                                          ; preds = %entry
+  %tmp8 = sext i32 %N to i64
+  br label %for.cond.5
+
+for.cond.5:                                       ; preds = %for.inc.14, %sw.bb.3
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc.14 ], [ 1, %sw.bb.3 ]
+  %cmp6 = icmp sgt i64 %indvars.iv3, %tmp8
+  br i1 %cmp6, label %for.end.15, label %for.body.7
+
+for.body.7:                                       ; preds = %for.cond.5
+  %tmp9 = add nsw i64 %indvars.iv3, -1
+  %arrayidx10 = getelementptr inbounds i32, i32* %A, i64 %tmp9
+  %tmp10 = load i32, i32* %arrayidx10, align 4
+  %arrayidx12 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv3
+  %tmp11 = load i32, i32* %arrayidx12, align 4
+  %add13 = add nsw i32 %tmp11, %tmp10
+  store i32 %add13, i32* %arrayidx12, align 4
+  br label %for.inc.14
+
+for.inc.14:                                       ; preds = %for.body.7
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  br label %for.cond.5
+
+for.end.15:                                       ; preds = %for.cond.5
+  br label %sw.epilog
+
+sw.epilog:                                        ; preds = %for.end.15, %for.end, %entry
+  ret void
+}
diff --git a/final/test/ScopInfo/tempscop-printing.ll b/final/test/ScopInfo/tempscop-printing.ll
new file mode 100644
index 0000000..f9ddc4f
--- /dev/null
+++ b/final/test/ScopInfo/tempscop-printing.ll
@@ -0,0 +1,103 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+
+; void f(long A[], int N, int *init_ptr) {
+;   long i, j;
+;
+;   for (i = 0; i < N; ++i) {
+;     init = *init_ptr;
+;     for (i = 0; i < N; ++i) {
+;       A[i] = init + 2;
+;     }
+;   }
+; }
+
+; CHECK-LABEL: Function: f
+;
+; CHECK:       Statements {
+; CHECK-NEXT:      Stmt_for_j
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [N] -> { Stmt_for_j[i0, i1] : 0 <= i0 < N and 0 <= i1 < N };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [N] -> { Stmt_for_j[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [N] -> { Stmt_for_j[i0, i1] -> MemRef_init[] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              [N] -> { Stmt_for_j[i0, i1] -> MemRef_A[i1] };
+; CHECK-NEXT:  }
+;
+; CHECK-LABEL: Function: g
+;
+; CHECK:       Statements {
+; CHECK-NEXT:      Stmt_for_j
+; CHECK-NEXT:          Domain :=
+; CHECK-NEXT:              [N] -> { Stmt_for_j[i0, i1] : 0 <= i0 < N and 0 <= i1 < N };
+; CHECK-NEXT:          Schedule :=
+; CHECK-NEXT:              [N] -> { Stmt_for_j[i0, i1] -> [i0, i1] };
+; CHECK-NEXT:          MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:              [N] -> { Stmt_for_j[i0, i1] -> MemRef_A[i1] };
+; CHECK-NEXT:          ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:              [N] -> { Stmt_for_j[i0, i1] -> MemRef_init[] };
+; CHECK-NEXT:  }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+
+define void @f(i64* noalias %A, i64 %N, i64* noalias %init_ptr) nounwind {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ 0, %entry ], [ %indvar.i.next, %for.i.end ]
+  %indvar.i.next = add nsw i64 %indvar.i, 1
+  br label %entry.next
+
+entry.next:
+  %init = load i64, i64* %init_ptr
+  br label %for.j
+
+for.j:
+  %indvar.j = phi i64 [ 0, %entry.next ], [ %indvar.j.next, %for.j ]
+  %init_plus_two = add i64 %init, 2
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar.j
+  store i64 %init_plus_two, i64* %scevgep
+  %indvar.j.next = add nsw i64 %indvar.j, 1
+  %exitcond.j = icmp eq i64 %indvar.j.next, %N
+  br i1 %exitcond.j, label %for.i.end, label %for.j
+
+for.i.end:
+  %exitcond.i = icmp eq i64 %indvar.i.next, %N
+  br i1 %exitcond.i, label %return, label %for.i
+
+return:
+  ret void
+}
+
+define void @g(i64* noalias %A, i64 %N, i64* noalias %init_ptr) nounwind {
+entry:
+  br label %for.i
+
+for.i:
+  %indvar.i = phi i64 [ 0, %entry ], [ %indvar.i.next, %for.i.end ]
+  %indvar.i.next = add nsw i64 %indvar.i, 1
+  br label %entry.next
+
+entry.next:
+  %init = load i64, i64* %init_ptr
+  br label %for.j
+
+for.j:
+  %indvar.j = phi i64 [ 0, %entry.next ], [ %indvar.j.next, %for.j ]
+  %scevgep = getelementptr i64, i64* %A, i64 %indvar.j
+  store i64 %init, i64* %scevgep
+  %indvar.j.next = add nsw i64 %indvar.j, 1
+  %exitcond.j = icmp eq i64 %indvar.j.next, %N
+  br i1 %exitcond.j, label %for.i.end, label %for.j
+
+for.i.end:
+  %exitcond.i = icmp eq i64 %indvar.i.next, %N
+  br i1 %exitcond.i, label %return, label %for.i
+
+return:
+  ret void
+}
diff --git a/final/test/ScopInfo/test-wrapping-in-condition.ll b/final/test/ScopInfo/test-wrapping-in-condition.ll
new file mode 100644
index 0000000..0087a40
--- /dev/null
+++ b/final/test/ScopInfo/test-wrapping-in-condition.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-function-scops -analyze < %s | FileCheck %s
+;
+; CHECK:    Invalid Context:
+; CHECK:        [N] -> {  : N >= 129 }
+;
+;    #include <stdlib.h>
+;    #include <stdio.h>
+;
+;    void __attribute__((noinline)) foo(float *A, long N) {
+;      for (long i = 0; i < N; i++)
+;        if ((signed char)i < 100)
+;          A[i] += i;
+;    }
+define void @foo(float* %A, i64 %N) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb11, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp12, %bb11 ]
+  %tmp = icmp slt i64 %i.0, %N
+  br i1 %tmp, label %bb2, label %bb13
+
+bb2:                                              ; preds = %bb1
+  %tmp3 = trunc i64 %i.0 to i8
+  %tmp4 = icmp slt i8 %tmp3, 100
+  br i1 %tmp4, label %bb5, label %bb10
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = sitofp i64 %i.0 to float
+  %tmp7 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp8 = load float, float* %tmp7, align 4
+  %tmp9 = fadd float %tmp8, %tmp6
+  store float %tmp9, float* %tmp7, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb5, %bb2
+  br label %bb11
+
+bb11:                                             ; preds = %bb10
+  %tmp12 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb13:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/truncate-1.ll b/final/test/ScopInfo/truncate-1.ll
new file mode 100644
index 0000000..0c9118c
--- /dev/null
+++ b/final/test/ScopInfo/truncate-1.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(char *A, short N) {
+;      for (char i = 0; i < (char)N; i++)
+;        A[i]++;
+;    }
+;
+; FIXME: We should the truncate precisely... or just make it a separate parameter.
+; CHECK:       Assumed Context:
+; CHECK-NEXT:  [N] -> {  :  }
+; CHECK-NEXT:  Invalid Context:
+; CHECK-NEXT:  [N] -> { : N <= -129 or N >= 128 }
+;
+; CHECK:       Domain :=
+; CHECK-NEXT:    [N] -> { Stmt_for_body[i0] : 0 <= i0 < N };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i8* %A, i16 signext %N) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i8 [ 0, %entry ], [ %inc4, %for.inc ]
+  %conv = sext i8 %i.0 to i32
+  %conv1 = zext i16 %N to i32
+  %sext = shl i32 %conv1, 24
+  %conv2 = ashr exact i32 %sext, 24
+  %cmp = icmp slt i32 %conv, %conv2
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %idxprom = sext i8 %i.0 to i64
+  %arrayidx = getelementptr inbounds i8, i8* %A, i64 %idxprom
+  %tmp = load i8, i8* %arrayidx, align 1
+  %inc = add i8 %tmp, 1
+  store i8 %inc, i8* %arrayidx, align 1
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc4 = add nsw i8 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/truncate-2.ll b/final/test/ScopInfo/truncate-2.ll
new file mode 100644
index 0000000..3ff81ce
--- /dev/null
+++ b/final/test/ScopInfo/truncate-2.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(char *A, short N) {
+;      for (short i = 0; i < N; i++)
+;        A[(char)(N)]++;
+;    }
+;
+; FIXME: We should the truncate precisely... or just make it a separate parameter.
+; CHECK:       Assumed Context:
+; CHECK-NEXT:  [N] -> {  :  }
+; CHECK-NEXT:  Invalid Context:
+; CHECK-NEXT:  [N] -> { : N >= 128 }
+;
+; CHECK:         ReadAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:        [N] -> { Stmt_for_body[i0] -> MemRef_A[N] };
+; CHECK-NEXT:    MustWriteAccess :=	[Reduction Type: +] [Scalar: 0]
+; CHECK-NEXT:        [N] -> { Stmt_for_body[i0] -> MemRef_A[N] };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i8* %A, i16 signext %N) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i16 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp = icmp slt i16 %indvars.iv, %N
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %idxprom = trunc i16 %N to i8
+  %arrayidx = getelementptr inbounds i8, i8* %A, i8 %idxprom
+  %tmp1 = load i8, i8* %arrayidx, align 1
+  %inc = add i8 %tmp1, 1
+  store i8 %inc, i8* %arrayidx, align 1
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i16 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/truncate-3.ll b/final/test/ScopInfo/truncate-3.ll
new file mode 100644
index 0000000..f6a1f39
--- /dev/null
+++ b/final/test/ScopInfo/truncate-3.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-scops -pass-remarks-analysis="polly-scops" \
+; RUN:                -disable-output < %s 2>&1 | FileCheck %s
+
+; CHECK: Signed-unsigned restriction: [p] -> {  : p <= -129 or p >= 128 }
+
+; Verify that this test case does not crash when we try to model it.
+; At some point we tried to insert a restriction:
+;                                      [p] -> {  : p <= -129 or p >= 128 }
+; which resulted in a crash.
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+
+define void @wobble(i16* %A, i32 %p) {
+bb:
+  %tmp1 = and i32 %p, 255
+  br label %bb4
+
+bb4:                                              ; preds = %bb4, %bb
+  %indvar = phi i16* [ %A, %bb ], [ %indvar.next, %bb4 ]
+  %val = load i16, i16* %indvar
+  %indvar.next = getelementptr inbounds i16, i16* %indvar, i32 %tmp1
+  br i1 false, label %bb4, label %bb9
+
+bb9:                                              ; preds = %bb4
+  ret void
+}
diff --git a/final/test/ScopInfo/two-loops-one-infinite.ll b/final/test/ScopInfo/two-loops-one-infinite.ll
new file mode 100644
index 0000000..974194f
--- /dev/null
+++ b/final/test/ScopInfo/two-loops-one-infinite.ll
@@ -0,0 +1,40 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Verify we do not create a SCoP in the presence of infinite loops.
+;
+; CHECK-NOT:      Statements
+;
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n8:16:32-S64"
+
+define void @foo(i32* noalias nocapture readonly %xxx, i32* noalias nocapture readonly %yyy, i8*** nocapture readonly %zzz, i32 %conv6) {
+while.body.us.preheader:
+ %a2 = load i8**, i8*** %zzz, align 4  
+ %sub = add nsw i32 %conv6, -1 
+  br label %while.body.us
+
+while.body.us:                                    ; preds = %while.body.us.preheader, %if.then.us
+  %uuu = phi i32 [ %www, %if.then.us ], [ 0, %while.body.us.preheader ]
+  %a13 = load i32, i32* %yyy, align 8
+  %vvv = icmp sgt i32 %a13, 0
+  br i1 %vvv, label %while.body.13.us58.preheader, label %if.then.us
+
+while.body.13.us58.preheader:                     ; preds = %while.body.us
+  br label %while.body.13.us58
+
+if.then.us:                                       ; preds = %while.body.us
+  %add.us = add nuw nsw i32 %uuu, 1
+  tail call void @goo(i8** %a2, i32 %uuu, i8** %a2, i32 %add.us, i32 %sub, i32 %a13) #3
+  %www = add nuw nsw i32 %uuu, %conv6
+  %a14 = load i32, i32* %xxx, align 4
+  %cmp.us = icmp slt i32 %www, %a14
+  br i1 %cmp.us, label %while.body.us, label %while.end.21.loopexit145
+
+while.body.13.us58:
+    br label %while.body.13.us58
+
+while.end.21.loopexit145:
+  ret void
+}
+
+declare void @goo(i8**, i32, i8**, i32, i32, i32) #1
+
diff --git a/final/test/ScopInfo/two-loops-right-after-each-other.ll b/final/test/ScopInfo/two-loops-right-after-each-other.ll
new file mode 100644
index 0000000..95a368a
--- /dev/null
+++ b/final/test/ScopInfo/two-loops-right-after-each-other.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: < %s | FileCheck %s
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_loop_1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_loop_1[i0] : N <= 100 and 0 <= i0 <= 101 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_loop_1[i0] -> [0, i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_loop_1[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_loop_1[i0] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_loop_2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [N] -> { Stmt_loop_2[i0] : N <= 100 and 0 <= i0 <= 301 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [N] -> { Stmt_loop_2[i0] -> [1, i0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_loop_2[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [N] -> { Stmt_loop_2[i0] -> MemRef_A[0] };
+; CHECK-NEXT: }
+
+define void @foo(float* %A, i64 %N) {
+entry:
+  br label %branch
+
+branch:
+  %cond = icmp sle i64 %N, 100
+  br i1 %cond, label %loop.1, label %merge
+
+loop.1:
+  %indvar.1 = phi i64 [0, %branch], [%indvar.next.1, %loop.1]
+  %indvar.next.1 = add i64 %indvar.1, 1
+  %val.1 = load float, float* %A
+  %sum.1 = fadd float %val.1, 1.0
+  store float %sum.1, float* %A
+  %cond.1 = icmp sle i64 %indvar.1, 100
+  br i1 %cond.1, label %loop.1, label %loop.2
+
+loop.2:
+  %indvar.2 = phi i64 [0, %loop.1], [%indvar.next.2, %loop.2]
+  %indvar.next.2 = add i64 %indvar.2, 1
+  %val.2 = load float, float* %A
+  %sum.2 = fadd float %val.2, 1.0
+  store float %sum.2, float* %A
+  %cond.2 = icmp sle i64 %indvar.2, 300
+  br i1 %cond.2, label %loop.2, label %merge
+
+merge:
+  br label %exit
+
+exit:
+  ret void
+}
diff --git a/final/test/ScopInfo/undef_in_cond.ll b/final/test/ScopInfo/undef_in_cond.ll
new file mode 100644
index 0000000..e66685a
--- /dev/null
+++ b/final/test/ScopInfo/undef_in_cond.ll
@@ -0,0 +1,22 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+
+define fastcc void @fix_operands() nounwind {
+entry:
+  br i1 undef, label %bb3, label %bb1
+
+bb1:                                              ; preds = %bb
+  %0 = icmp eq i32 0, undef                       ; <i1> [#uses=1]
+  br i1 %0, label %bb3, label %bb2
+
+bb2:                                              ; preds = %bb1
+  br label %bb3
+
+bb3:                                              ; preds = %bb2, %bb1, %bb
+  br label %bb14
+
+bb14:                                             ; preds = %bb5, %bb4, %bb3, %entry
+  ret void
+}
+
+; CHECK-NOT: Function:
diff --git a/final/test/ScopInfo/unnamed_nonaffine.ll b/final/test/ScopInfo/unnamed_nonaffine.ll
new file mode 100644
index 0000000..4b28ffc
--- /dev/null
+++ b/final/test/ScopInfo/unnamed_nonaffine.ll
@@ -0,0 +1,150 @@
+; RUN: opt %loadPolly -polly-allow-nonaffine -polly-scops -analyze < %s \
+; RUN:     -polly-use-llvm-names=true | FileCheck %s
+;
+; RUN: opt %loadPolly -polly-allow-nonaffine -polly-scops -analyze < %s \
+; RUN:     -polly-use-llvm-names=false | FileCheck %s -check-prefix=UNNAMED
+;
+;    void f(int *A, int b) {
+;      int x;
+;      for (int i = 0; i < 1024; i++) {
+;        if (b > i)
+;          x = 0;
+;        else if (b < 2 * i)
+;          x = 3;
+;        else
+;          x = b;
+;
+;        if (A[x])
+;          A[x] = 0;
+;      }
+;    }
+;
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_bb3
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [b] -> { Stmt_bb3[i0] : 0 <= i0 <= 1023 and i0 < b };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [b] -> { Stmt_bb3[i0] -> [i0, 2] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [b] -> { Stmt_bb3[i0] -> MemRef_x_1__phi[] };
+; CHECK-NEXT:     Stmt_bb7
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [b] -> { Stmt_bb7[i0] : i0 >= b and 0 <= i0 <= 1023 and 2i0 > b };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [b] -> { Stmt_bb7[i0] -> [i0, 1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [b] -> { Stmt_bb7[i0] -> MemRef_x_1__phi[] };
+; CHECK-NEXT:     Stmt_bb8
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [b] -> { Stmt_bb8[0] : b = 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [b] -> { Stmt_bb8[i0] -> [0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [b] -> { Stmt_bb8[i0] -> MemRef_x_1__phi[] };
+; CHECK-NEXT:     Stmt_bb10__TO__bb18
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [b] -> { Stmt_bb10__TO__bb18[i0] : 0 <= i0 <= 1023 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [b] -> { Stmt_bb10__TO__bb18[i0] -> [i0, 3] }
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [b] -> { Stmt_bb10__TO__bb18[i0] -> MemRef_x_1__phi[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [b] -> { Stmt_bb10__TO__bb18[i0] -> MemRef_A[o0] };
+; CHECK-NEXT:         MayWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [b] -> { Stmt_bb10__TO__bb18[i0] -> MemRef_A[o0] };
+; CHECK-NEXT: }
+
+; UNNAMED:          Arrays {
+; UNNAMED-NEXT:         i32 MemRef0__phi; // Element size 4
+; UNNAMED-NEXT:         i32 MemRef1[*]; // Element size 4
+; UNNAMED-NEXT:     }
+
+; UNNAMED:          Statements {
+; UNNAMED-NEXT:     	Stmt2
+; UNNAMED-NEXT:             Domain :=
+; UNNAMED-NEXT:                 [p_0] -> { Stmt2[i0] : 0 <= i0 <= 1023 and i0 < p_0 };
+; UNNAMED-NEXT:             Schedule :=
+; UNNAMED-NEXT:                 [p_0] -> { Stmt2[i0] -> [i0, 2] };
+; UNNAMED-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; UNNAMED-NEXT:                 [p_0] -> { Stmt2[i0] -> MemRef0__phi[] };
+; UNNAMED-NEXT:     	Stmt4
+; UNNAMED-NEXT:             Domain :=
+; UNNAMED-NEXT:                 [p_0] -> { Stmt4[i0] : i0 >= p_0 and 0 <= i0 <= 1023 and 2i0 > p_0 };
+; UNNAMED-NEXT:             Schedule :=
+; UNNAMED-NEXT:                 [p_0] -> { Stmt4[i0] -> [i0, 1] };
+; UNNAMED-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; UNNAMED-NEXT:                 [p_0] -> { Stmt4[i0] -> MemRef0__phi[] };
+; UNNAMED-NEXT:     	Stmt5
+; UNNAMED-NEXT:             Domain :=
+; UNNAMED-NEXT:                 [p_0] -> { Stmt5[0] : p_0 = 0 };
+; UNNAMED-NEXT:             Schedule :=
+; UNNAMED-NEXT:                 [p_0] -> { Stmt5[i0] -> [0, 0] };
+; UNNAMED-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; UNNAMED-NEXT:                 [p_0] -> { Stmt5[i0] -> MemRef0__phi[] };
+; UNNAMED-NEXT:     	Stmt6
+; UNNAMED-NEXT:             Domain :=
+; UNNAMED-NEXT:                 [p_0] -> { Stmt6[i0] : 0 <= i0 <= 1023 };
+; UNNAMED-NEXT:             Schedule :=
+; UNNAMED-NEXT:                 [p_0] -> { Stmt6[i0] -> [i0, 3] };
+; UNNAMED-NEXT:             ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; UNNAMED-NEXT:                 [p_0] -> { Stmt6[i0] -> MemRef0__phi[] };
+; UNNAMED-NEXT:             ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; UNNAMED-NEXT:                 [p_0] -> { Stmt6[i0] -> MemRef1[o0] };
+; UNNAMED-NEXT:             MayWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; UNNAMED-NEXT:                 [p_0] -> { Stmt6[i0] -> MemRef1[o0] };
+; UNNAMED-NEXT:     }
+
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %b) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb19, %bb
+  %i.0 = phi i32 [ 0, %bb ], [ %tmp20, %bb19 ]
+  %exitcond = icmp ne i32 %i.0, 1024
+  br i1 %exitcond, label %bb2, label %bb21
+
+bb2:                                              ; preds = %bb1
+  %tmp = icmp slt i32 %i.0, %b
+  br i1 %tmp, label %bb3, label %bb4
+
+bb3:                                              ; preds = %bb2
+  br label %bb10
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = mul nsw i32 %i.0, 2
+  %tmp6 = icmp sgt i32 %tmp5, %b
+  br i1 %tmp6, label %bb7, label %bb8
+
+bb7:                                              ; preds = %bb4
+  br label %bb10
+
+bb8:                                              ; preds = %bb4
+  br label %bb10
+
+bb10:                                             ; preds = %bb9, %bb3
+  %x.1 = phi i32 [ 0, %bb3 ], [ 3, %bb7 ], [ %b, %bb8 ]
+  %tmp11 = sext i32 %x.1 to i64
+  %tmp12 = getelementptr inbounds i32, i32* %A, i64 %tmp11
+  %tmp13 = load i32,  i32* %tmp12, align 4
+  %tmp14 = icmp eq i32 %tmp13, 0
+  br i1 %tmp14, label %bb18, label %bb15
+
+bb15:                                             ; preds = %bb10
+  %tmp16 = sext i32 %x.1 to i64
+  %tmp17 = getelementptr inbounds i32, i32* %A, i64 %tmp16
+  store i32 0, i32* %tmp17, align 4
+  br label %bb18
+
+bb18:                                             ; preds = %bb10, %bb15
+  br label %bb19
+
+bb19:                                             ; preds = %bb18
+  %tmp20 = add nuw nsw i32 %i.0, 1
+  br label %bb1
+
+bb21:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/unnamed_stmts.ll b/final/test/ScopInfo/unnamed_stmts.ll
new file mode 100644
index 0000000..89d40c8
--- /dev/null
+++ b/final/test/ScopInfo/unnamed_stmts.ll
@@ -0,0 +1,148 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; This test case verifies that we generate numbered statement names in case
+; no LLVM-IR names are used in the test case. We also verify, that we
+; distinguish statements named with a number and unnamed statements that happen
+; to have an index identical to a number used in a statement name.
+
+; CHECK: Arrays {
+; CHECK-NEXT:     float MemRef0[*][%n]; // Element size 4
+; CHECK-NEXT:     float MemRef1[*][%n]; // Element size 4
+; CHECK-NEXT: }
+; CHECK-NEXT: Arrays (Bounds as pw_affs) {
+; CHECK-NEXT:     float MemRef0[*][ [n] -> { [] -> [(n)] } ]; // Element size 4
+; CHECK-NEXT:     float MemRef1[*][ [n] -> { [] -> [(n)] } ]; // Element size 4
+; CHECK-NEXT: }
+
+; CHECK: Statements {
+; CHECK-NEXT: 	Stmt2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt2[i0, i1] : 0 <= i0 < n and 0 <= i1 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt2[i0, i1] -> [0, i0, i1, 0] };
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt2[i0, i1] -> MemRef0[i0, i1] };
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt2[i0, i1] -> MemRef1[i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt2[i0, i1] -> MemRef1[i0, i1] };
+; CHECK-NEXT: 	Stmt10
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt10[i0, i1] : 0 <= i0 < n and 0 <= i1 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt10[i0, i1] -> [1, i0, i1, 0] };
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt10[i0, i1] -> MemRef1[i0, i1] };
+; CHECK-NEXT:         ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt10[i0, i1] -> MemRef0[i0, i1] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt10[i0, i1] -> MemRef0[i0, i1] };
+; CHECK-NEXT: 	Stmt_2
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n] -> { Stmt_2[i0, i1] : 0 <= i0 < n and 0 <= i1 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n] -> { Stmt_2[i0, i1] -> [1, i0, i1, 1] };
+; CHECK-NEXT:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n] -> { Stmt_2[i0, i1] -> MemRef0[i0, i1]
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @vec3(i64 %n, float*, float*) #0 {
+  br label %.split
+
+.split:                                           ; preds = %0
+  br label %.preheader2.lr.ph
+
+.preheader2.lr.ph:                                ; preds = %.split
+  br label %.preheader2
+
+.preheader2:                                      ; preds = %.preheader2.lr.ph, %15
+  %i.010 = phi i64 [ 0, %.preheader2.lr.ph ], [ %16, %15 ]
+  br label %.lr.ph8
+
+.lr.ph8:                                          ; preds = %.preheader2
+  br label %4
+
+..preheader1_crit_edge:                           ; preds = %15
+  br label %.preheader1
+
+.preheader1:                                      ; preds = %..preheader1_crit_edge, %.split
+  %3 = icmp sgt i64 %n, 0
+  br i1 %3, label %.preheader.lr.ph, label %"name"
+
+.preheader.lr.ph:                                 ; preds = %.preheader1
+  br label %.preheader
+
+; <label>:4:                                      ; preds = %.lr.ph8, %4
+  %j.07 = phi i64 [ 0, %.lr.ph8 ], [ %14, %4 ]
+  %5 = mul nsw i64 %i.010, %n
+  %6 = getelementptr inbounds float, float* %1, i64 %5
+  %7 = getelementptr inbounds float, float* %6, i64 %j.07
+  %8 = load float, float* %7, align 4
+  %9 = mul nsw i64 %i.010, %n
+  %10 = getelementptr inbounds float, float* %0, i64 %9
+  %11 = getelementptr inbounds float, float* %10, i64 %j.07
+  %12 = load float, float* %11, align 4
+  %13 = fadd float %8, %12
+  store float %13, float* %11, align 4
+  %14 = add nuw nsw i64 %j.07, 1
+  %exitcond13 = icmp ne i64 %14, %n
+  br i1 %exitcond13, label %4, label %._crit_edge9
+
+._crit_edge9:                                     ; preds = %4
+  br label %15
+
+; <label>:15:                                     ; preds = %._crit_edge9, %.preheader2
+  %16 = add nuw nsw i64 %i.010, 1
+  %exitcond14 = icmp ne i64 %16, %n
+  br i1 %exitcond14, label %.preheader2, label %..preheader1_crit_edge
+
+.preheader:                                       ; preds = %.preheader.lr.ph, %29
+  %i1.04 = phi i64 [ 0, %.preheader.lr.ph ], [ %30, %29 ]
+  %17 = icmp sgt i64 %n, 0
+  br i1 %17, label %.lr.ph, label %29
+
+.lr.ph:                                           ; preds = %.preheader
+  br label %18
+
+; <label>:18:                                     ; preds = %.lr.ph, %18
+  %j2.03 = phi i64 [ 0, %.lr.ph ], [ %28, %"2" ]
+  %19 = mul nsw i64 %i1.04, %n
+  %20 = getelementptr inbounds float, float* %0, i64 %19
+  %21 = getelementptr inbounds float, float* %20, i64 %j2.03
+  %22 = load float, float* %21, align 4
+  %23 = mul nsw i64 %i1.04, %n
+  %24 = getelementptr inbounds float, float* %1, i64 %23
+  %25 = getelementptr inbounds float, float* %24, i64 %j2.03
+  %26 = load float, float* %25, align 4
+  %27 = fadd float %22, %26
+  store float %27, float* %25, align 4
+  br label %"2"
+
+"2":
+  store float 42.0, float* %25
+  %28 = add nuw nsw i64 %j2.03, 1
+  %exitcond = icmp ne i64 %28, %n
+  br i1 %exitcond, label %18, label %._crit_edge
+
+._crit_edge:                                      ; preds = %18
+  br label %29
+
+; <label>:29:                                     ; preds = %._crit_edge, %.preheader
+  %30 = add nuw nsw i64 %i1.04, 1
+  %exitcond12 = icmp ne i64 %30, %n
+  br i1 %exitcond12, label %.preheader, label %._crit_edge6
+
+._crit_edge6:                                     ; preds = %29
+  br label %"name"
+
+"name":
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"Ubuntu clang version 3.7.1-3ubuntu4 (tags/RELEASE_371/final) (based on LLVM 3.7.1)"}
diff --git a/final/test/ScopInfo/unpredictable_nonscop_loop.ll b/final/test/ScopInfo/unpredictable_nonscop_loop.ll
new file mode 100644
index 0000000..5452fac
--- /dev/null
+++ b/final/test/ScopInfo/unpredictable_nonscop_loop.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s -match-full-lines
+; Derived from test-suite/MultiSource/Applications/sgefa/blas.c
+;
+; The exit value of %i.0320 in land.rhs is not computable.
+; It is still synthesizable in %if.end13---%for.end170 because
+; %i.0320 is fixed within the SCoP and therefore just another parameter.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @snrm2(i32 %n) local_unnamed_addr {
+entry:
+  br label %land.rhs
+
+land.rhs:                                         ; preds = %while.body, %entry
+  %i.0320 = phi i32 [ 0, %entry ], [ %inc, %while.body ]
+  br i1 undef, label %while.body, label %if.end13
+
+while.body:                                       ; preds = %land.rhs
+  %inc = add nuw nsw i32 %i.0320, 1
+  br label %land.rhs
+
+if.end13:                                         ; preds = %land.rhs
+  %i.4284 = add nsw i32 %i.0320, 1
+  %cmp131285 = icmp slt i32 %i.4284, %n
+  br i1 %cmp131285, label %for.body133.lr.ph, label %for.end170
+
+for.body133.lr.ph:                                ; preds = %if.end13
+  br label %for.body133
+
+for.body133:                                      ; preds = %for.body133, %for.body133.lr.ph
+  %i.4289 = phi i32 [ %i.4284, %for.body133.lr.ph ], [ %i.4, %for.body133 ]
+  %xmax.2287 = phi float [ undef, %for.body133.lr.ph ], [ undef, %for.body133 ]
+  %i.4 = add nsw i32 %i.4289, 1
+  %exitcond = icmp eq i32 %i.4, %n
+  br i1 %exitcond, label %for.end170, label %for.body133
+
+for.end170:                                       ; preds = %for.body133, %if.end13
+  ret void
+}
+
+
+; CHECK: Region: %if.end13---%for.end170
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body133_lr_ph
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p_0, n] -> { Stmt_for_body133_lr_ph[] : n >= 2 + p_0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p_0, n] -> { Stmt_for_body133_lr_ph[] -> [0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p_0, n] -> { Stmt_for_body133_lr_ph[] -> MemRef_xmax_2287__phi[] };
+; CHECK-NEXT:     Stmt_for_body133
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p_0, n] -> { Stmt_for_body133[i0] : 0 <= i0 <= -2 - p_0 + n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p_0, n] -> { Stmt_for_body133[i0] -> [1, i0] };
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p_0, n] -> { Stmt_for_body133[i0] -> MemRef_xmax_2287__phi[] };
+; CHECK-NEXT:         ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p_0, n] -> { Stmt_for_body133[i0] -> MemRef_xmax_2287__phi[] };
+; CHECK-NEXT: }
diff --git a/final/test/ScopInfo/unprofitable_scalar-accs.ll b/final/test/ScopInfo/unprofitable_scalar-accs.ll
new file mode 100644
index 0000000..c8b31de
--- /dev/null
+++ b/final/test/ScopInfo/unprofitable_scalar-accs.ll
@@ -0,0 +1,97 @@
+; RUN: opt %loadPolly -polly-process-unprofitable=false -polly-unprofitable-scalar-accs=false -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-process-unprofitable=false -polly-unprofitable-scalar-accs=true  -polly-scops -analyze < %s | FileCheck %s --check-prefix=HEURISTIC
+
+; Check the effect of -polly-unprofitable-scalar-accs
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @func(i32 %n, i32 %m, double* noalias nonnull %A) {
+entry:
+  br label %outer.for
+
+outer.for:
+  %j = phi i32 [0, %entry], [%j.inc, %outer.inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %inner.for, label %outer.exit
+
+  inner.for:
+    %i = phi i32 [1, %outer.for], [%i.inc, %inner.inc]
+    %b = phi double [0.0, %outer.for], [%a, %inner.inc]
+    %i.cmp = icmp slt i32 %i, %m
+    br i1 %i.cmp, label %body1, label %inner.exit
+
+    body1:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %i
+      %a = load double, double* %A_idx
+      store double %a, double* %A_idx
+      br label %inner.inc
+
+  inner.inc:
+    %i.inc = add nuw nsw i32 %i, 1
+    br label %inner.for
+
+  inner.exit:
+    br label %outer.inc
+
+outer.inc:
+  store double %b, double* %A
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %outer.for
+
+outer.exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_outer_for
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n, m] -> { Stmt_outer_for[i0] : 0 <= i0 <= n; Stmt_outer_for[0] : n < 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n, m] -> { Stmt_outer_for[i0] -> [i0, 0, 0, 0] : i0 <= n; Stmt_outer_for[0] -> [0, 0, 0, 0] : n < 0 };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n, m] -> { Stmt_outer_for[i0] -> MemRef_b__phi[] };
+; CHECK-NEXT:     Stmt_inner_for
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n, m] -> { Stmt_inner_for[i0, i1] : 0 <= i0 < n and 0 <= i1 < m; Stmt_inner_for[i0, 0] : m <= 0 and 0 <= i0 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n, m] -> { Stmt_inner_for[i0, i1] -> [i0, 1, i1, 0] : i1 < m; Stmt_inner_for[i0, 0] -> [i0, 1, 0, 0] : m <= 0 };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n, m] -> { Stmt_inner_for[i0, i1] -> MemRef_b__phi[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n, m] -> { Stmt_inner_for[i0, i1] -> MemRef_b[] };
+; CHECK-NEXT:     Stmt_body1
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n, m] -> { Stmt_body1[i0, i1] : 0 <= i0 < n and 0 <= i1 <= -2 + m };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n, m] -> { Stmt_body1[i0, i1] -> [i0, 1, i1, 1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n, m] -> { Stmt_body1[i0, i1] -> MemRef_a[] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n, m] -> { Stmt_body1[i0, i1] -> MemRef_A[1 + i1] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n, m] -> { Stmt_body1[i0, i1] -> MemRef_A[1 + i1] };
+; CHECK-NEXT:     Stmt_inner_inc
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n, m] -> { Stmt_inner_inc[i0, i1] : 0 <= i0 < n and 0 <= i1 <= -2 + m };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n, m] -> { Stmt_inner_inc[i0, i1] -> [i0, 1, i1, 2] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n, m] -> { Stmt_inner_inc[i0, i1] -> MemRef_a[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n, m] -> { Stmt_inner_inc[i0, i1] -> MemRef_b__phi[] };
+; CHECK-NEXT:     Stmt_outer_inc
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [n, m] -> { Stmt_outer_inc[i0] : 0 <= i0 < n };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [n, m] -> { Stmt_outer_inc[i0] -> [i0, 2, 0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [n, m] -> { Stmt_outer_inc[i0] -> MemRef_A[0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n, m] -> { Stmt_outer_inc[i0] -> MemRef_b[] };
+; CHECK-NEXT: }
+
+; HEURISTIC-NOT: Statements
diff --git a/final/test/ScopInfo/unsigned-condition.ll b/final/test/ScopInfo/unsigned-condition.ll
new file mode 100644
index 0000000..57c1039
--- /dev/null
+++ b/final/test/ScopInfo/unsigned-condition.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+
+; void f(int a[], int N, unsigned P) {
+;   int i;
+;   for (i = 0; i < N; ++i)
+;     if (P > 42)
+;       a[i] = i;
+; }
+
+; The assumed context is the universe because the "signed-unsigned assumption"
+;   [P, N] -> {  : N > 0 and P >= 0 }
+; is implied by the execution domain. Thus if something is executed this
+; assumption will hold.
+
+; CHECK:      Assumed Context:
+; CHECK-NEXT: [P, N] -> {  :  }
+;
+; CHECK:              Domain :=
+; CHECK-NEXT:             [P, N] -> { Stmt_store[i0] : P >= 42 and 0 <= i0 < N };
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* nocapture %a, i64 %N, i64 %P) nounwind {
+entry:
+  br label %bb
+
+bb:
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %bb.backedge ]
+  %brcond = icmp uge i64 %P, 42
+  br i1 %brcond, label %store, label %bb.backedge
+
+store:
+  %scevgep = getelementptr inbounds i64, i64* %a, i64 %i
+  store i64 %i, i64* %scevgep
+  br label %bb.backedge
+
+bb.backedge:
+  %i.inc = add nsw i64 %i, 1
+  %exitcond = icmp eq i64 %i.inc, %N
+  br i1 %exitcond, label %return, label %bb
+
+return:
+  ret void
+}
diff --git a/final/test/ScopInfo/unsigned-division-1.ll b/final/test/ScopInfo/unsigned-division-1.ll
new file mode 100644
index 0000000..c7a471c
--- /dev/null
+++ b/final/test/ScopInfo/unsigned-division-1.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(int *A, unsigned N) {
+;      for (unsigned i = 0; i < N / 2; i++)
+;        A[i]++;
+;    }
+;
+; CHECK:          Assumed Context:
+; CHECK-NEXT:     [N] -> {  :  }
+; CHECK-NEXT:     Invalid Context:
+; CHECK-NEXT:     [N] -> {  : N < 0 }
+;
+; CHECK:          Domain :=
+; CHECK-NEXT:     [N] -> { Stmt_for_body[i0] : i0 >= 0 and 2i0 <= -2 + N };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  %tmp = lshr i32 %N, 1
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %lftr.wideiv = trunc i64 %indvars.iv to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, %tmp
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp1, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/unsigned-division-2.ll b/final/test/ScopInfo/unsigned-division-2.ll
new file mode 100644
index 0000000..b58c709
--- /dev/null
+++ b/final/test/ScopInfo/unsigned-division-2.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(int *A, unsigned N) {
+;      for (unsigned i = 0; i < N / 2 + 3; i++)
+;        A[i]++;
+;    }
+;
+; CHECK:          Assumed Context:
+; CHECK-NEXT:     [N] -> {  :  }
+; CHECK-NEXT:     Invalid Context:
+; CHECK-NEXT:     [N] -> {  : N < 0 }
+;
+; CHECK:          Domain :=
+; CHECK-NEXT:     [N] -> { Stmt_for_body[i0] : i0 >= 0 and 2i0 <= 4 + N };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32 %N) {
+entry:
+  %tmp = lshr i32 %N, 1
+  %tmp1 = add i32 %tmp, 3
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %lftr.wideiv = trunc i64 %indvars.iv to i32
+  %exitcond = icmp ult i32 %lftr.wideiv, %tmp1
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp2, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/unsigned-division-3.ll b/final/test/ScopInfo/unsigned-division-3.ll
new file mode 100644
index 0000000..6f7e44f
--- /dev/null
+++ b/final/test/ScopInfo/unsigned-division-3.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(int *A, unsigned char N) {
+;      for (unsigned i = 0; i <= N / -128; i++)
+;        A[i]++;
+;    }
+;
+; CHECK:         Assumed Context:
+; CHECK-NEXT:    [N] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [N] -> {  : N < 0 }
+;
+; CHECK:       Domain :=
+; CHECK-NEXT:    [N] -> { Stmt_for_body[0] : N >= 0 };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i8 %N) {
+entry:
+  %tmp = udiv i8 %N, -128
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %lftr.wideiv = trunc i64 %indvars.iv to i8
+  %exitcond = icmp sle i8 %lftr.wideiv, %tmp
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp2, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/unsigned-division-4.ll b/final/test/ScopInfo/unsigned-division-4.ll
new file mode 100644
index 0000000..ff346c3
--- /dev/null
+++ b/final/test/ScopInfo/unsigned-division-4.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(int *A, unsigned char N) {
+;      for (unsigned i = 0; i < (N / -128) + 3; i++)
+;        A[i]++;
+;    }
+;
+; CHECK:         Assumed Context:
+; CHECK-NEXT:    [N] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [N] -> {  : N < 0 }
+;
+; CHECK:       Domain :=
+; CHECK-NEXT:    [N] -> { Stmt_for_body[i0] : i0 >= 0 and 128i0 <= 256 + N };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i8 %N) {
+entry:
+  %tmp1 = udiv i8 %N, -128
+  %tmp = add i8 %tmp1, 3
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %lftr.wideiv = trunc i64 %indvars.iv to i8
+  %exitcond = icmp ne i8 %lftr.wideiv, %tmp
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp2, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/unsigned-division-5.ll b/final/test/ScopInfo/unsigned-division-5.ll
new file mode 100644
index 0000000..6d82873
--- /dev/null
+++ b/final/test/ScopInfo/unsigned-division-5.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+;    void f(int *A, unsigned N) {
+;      for (unsigned i = 0; i < N; i++)
+;        A[i / 3] = A[5 * N / 3];
+;    }
+;
+; CHECK:         Invariant Accesses: {
+; CHECK-NEXT:            ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                [N] -> { Stmt_for_body[i0] -> MemRef_A[o0] : -2 + 5N <= 3o0 <= 5N };
+; CHECK-NEXT:            Execution Context: [N] -> {  : 0 < N <= 1844674407370955161 }
+; CHECK-NEXT:    }
+;
+; CHECK:         Assumed Context:
+; CHECK-NEXT:    [N] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [N] -> {  : N >= 1844674407370955162 }
+
+; CHECK:         MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:        [N] -> { Stmt_for_body[i0] -> MemRef_A[o0] : -2 + i0 <= 3o0 <= i0 };
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i64 %N) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, %N
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %mul = mul nsw i64 %N, 5
+  %div2 = udiv i64 %mul, 3
+  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %div2
+  %load = load i32, i32* %arrayidx2, align 4
+  %div = udiv i64 %indvars.iv, 3
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %div
+  store i32 %load, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/unsigned_wrap_uge.ll b/final/test/ScopInfo/unsigned_wrap_uge.ll
new file mode 100644
index 0000000..e5a6d7f
--- /dev/null
+++ b/final/test/ScopInfo/unsigned_wrap_uge.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Unsigned wrap-around check.
+;
+; for (int i = -1; i < 65 ; i ++ )
+;   if ( 63 >= (unsigned)i )
+;     A[i] = 42;
+
+
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %for
+
+  for:
+  %j = phi i32 [-1, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, 65
+  br i1 %j.cmp, label %body, label %exit
+
+  body:
+  %inbounds = icmp uge i32 63, %j
+  br i1 %inbounds, label %ifinbounds, label %ifoutbounds
+
+  ifinbounds:
+  %A_idx = getelementptr inbounds double, double* %A, i32 %j
+  store double 42.0, double* %A_idx
+  br label %inc
+
+  ifoutbounds:
+  br label %inc
+
+  inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+  exit:
+  br label %return
+
+  return:
+  ret void
+}
+
+
+; CHECK: Region: %for---%return
+; CHECK:            Domain :=
+; CHECK-NEXT:                            { Stmt_ifinbounds[i0] : 0 < i0 <= 64 };
+
diff --git a/final/test/ScopInfo/unsigned_wrap_ugt.ll b/final/test/ScopInfo/unsigned_wrap_ugt.ll
new file mode 100644
index 0000000..1f60271
--- /dev/null
+++ b/final/test/ScopInfo/unsigned_wrap_ugt.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Unsigned wrap-around check.
+;
+; for (int i = -1; i < 65 ; i ++ )
+;   if ( 64 > (unsigned)i )
+;     A[i] = 42;
+
+
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %for
+
+  for:
+  %j = phi i32 [-1, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, 65
+  br i1 %j.cmp, label %body, label %exit
+
+  body:
+  %inbounds = icmp ugt i32 64, %j
+  br i1 %inbounds, label %ifinbounds, label %ifoutbounds
+
+  ifinbounds:
+  %A_idx = getelementptr inbounds double, double* %A, i32 %j
+  store double 42.0, double* %A_idx
+  br label %inc
+
+  ifoutbounds:
+  br label %inc
+
+  inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+  exit:
+  br label %return
+
+  return:
+  ret void
+}
+
+
+; CHECK: Region: %for---%return
+; CHECK:            Domain :=
+; CHECK-NEXT:                            { Stmt_ifinbounds[i0] : 0 < i0 <= 64 };
+
diff --git a/final/test/ScopInfo/unsigned_wrap_ule.ll b/final/test/ScopInfo/unsigned_wrap_ule.ll
new file mode 100644
index 0000000..2beac8e
--- /dev/null
+++ b/final/test/ScopInfo/unsigned_wrap_ule.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Unsigned wrap-around check.
+;
+; for (int i = -1; i < 65 ; i ++ )
+;   if ( (unsigned)i <= 63 )
+;     A[i] = 42;
+
+
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %for
+
+  for:
+  %j = phi i32 [-1, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, 65
+  br i1 %j.cmp, label %body, label %exit
+
+  body:
+  %inbounds = icmp ule i32 %j, 63
+  br i1 %inbounds, label %ifinbounds, label %ifoutbounds
+
+  ifinbounds:
+  %A_idx = getelementptr inbounds double, double* %A, i32 %j
+  store double 42.0, double* %A_idx
+  br label %inc
+
+  ifoutbounds:
+  br label %inc
+
+  inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+  exit:
+  br label %return
+
+  return:
+  ret void
+}
+
+
+; CHECK: Region: %for---%return
+; CHECK:            Domain :=
+; CHECK-NEXT:                            { Stmt_ifinbounds[i0] : 0 < i0 <= 64 };
+
diff --git a/final/test/ScopInfo/unsigned_wrap_ult.ll b/final/test/ScopInfo/unsigned_wrap_ult.ll
new file mode 100644
index 0000000..8401d4b
--- /dev/null
+++ b/final/test/ScopInfo/unsigned_wrap_ult.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Unsigned wrap-around check.
+;
+; for (int i = -1; i < 65 ; i ++ )
+;   if ( (unsigned)i < 64 )
+;     A[i] = 42;
+
+
+define void @func(double* noalias nonnull %A) {
+entry:
+  br label %for
+
+  for:
+  %j = phi i32 [-1, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, 65
+  br i1 %j.cmp, label %body, label %exit
+
+  body:
+  %inbounds = icmp ult i32 %j, 64
+  br i1 %inbounds, label %ifinbounds, label %ifoutbounds
+
+  ifinbounds:
+  %A_idx = getelementptr inbounds double, double* %A, i32 %j
+  store double 42.0, double* %A_idx
+  br label %inc
+
+  ifoutbounds:
+  br label %inc
+
+  inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+  exit:
+  br label %return
+
+  return:
+  ret void
+}
+
+
+; CHECK: Region: %for---%return
+; CHECK:            Domain :=
+; CHECK-NEXT:                            { Stmt_ifinbounds[i0] : 0 < i0 <= 64 };
+
diff --git a/final/test/ScopInfo/user_context.ll b/final/test/ScopInfo/user_context.ll
new file mode 100644
index 0000000..95e4cbc
--- /dev/null
+++ b/final/test/ScopInfo/user_context.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -polly-context='[N] -> {: N = 1024}' -analyze < %s | FileCheck %s --check-prefix=CTX
+; RUN: opt %loadPolly -polly-scops -polly-context='[N,M] -> {: 1 = 0}' -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -polly-context='[] -> {: 1 = 0}' -analyze < %s | FileCheck %s
+
+; void f(int a[], int N) {
+;   int i;
+;   for (i = 0; i < N; ++i)
+;     a[i] = i;
+; }
+
+; CHECK:      Context:
+; CHECK-NEXT: [N] -> {  : -9223372036854775808 <= N <= 9223372036854775807 }
+
+; CTX:      Context:
+; CTX-NEXT: [N] -> {  : N = 1024 }
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
+
+define void @f(i64* nocapture %a, i64 %N) nounwind {
+entry:
+  br label %bb
+
+bb:                                               ; preds = %bb, %entry
+  %i = phi i64 [ 0, %entry ], [ %i.inc, %bb ]
+  %scevgep = getelementptr i64, i64* %a, i64 %i
+  store i64 %i, i64* %scevgep
+  %i.inc = add nsw i64 %i, 1
+  %exitcond = icmp eq i64 %i.inc, %N
+  br i1 %exitcond, label %return, label %bb
+
+return:                                           ; preds = %bb, %entry
+  ret void
+}
+
diff --git a/final/test/ScopInfo/user_provided_assumptions-in-bb-signed-conditional.ll b/final/test/ScopInfo/user_provided_assumptions-in-bb-signed-conditional.ll
new file mode 100644
index 0000000..c357f7e
--- /dev/null
+++ b/final/test/ScopInfo/user_provided_assumptions-in-bb-signed-conditional.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops -disable-output < %s 2>&1 | FileCheck %s --check-prefix=REMARK
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; REMARK: remark: <unknown>:0:0: Use user assumption: [n, b] -> {  : n <= 100 or (b = 0 and n >= 101) }
+;
+; CHECK:       Context:
+; CHECK-NEXT:    [n, b] -> {  : -9223372036854775808 <= n <= 9223372036854775807 and ((n <= 100 and -9223372036854775808 <= b <= 9223372036854775807) or (b = 0 and n >= 101)) }
+; CHECK-NEXT:    Assumed Context:
+; CHECK-NEXT:    [n, b] -> {  :  }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [n, b] -> {  : 1 = 0 }
+
+;
+;    void foo(float A[][100], long b, long n) {
+;      for (long i = 0; i < n; i++)
+;        if (b)
+;          A[42][i] = 42.0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@.src = private unnamed_addr constant [12 x i8] c"/tmp/test.c\00", align 1
+@0 = private unnamed_addr constant { i16, i16, [14 x i8] } { i16 -1, i16 0, [14 x i8] c"'float [100]'\00" }
+@1 = private unnamed_addr constant { i16, i16, [7 x i8] } { i16 0, i16 13, [7 x i8] c"'long'\00" }
+
+define void @foo([100 x float]* %A, i64 %b, i64 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp slt i64 %i.0, %n
+  br i1 %cmp, label %if.cond, label %for.end
+
+if.cond:
+  %bcmp = icmp ne i64 %b, 0
+  br i1 %bcmp, label %for.body, label %for.inc
+
+for.body:                                         ; preds = %for.cond
+  %tmp = icmp slt i64 %i.0, 100
+  call void @llvm.assume(i1 %tmp)
+  %arrayidx1 = getelementptr inbounds [100 x float], [100 x float]* %A, i64 42, i64 %i.0
+  store float 4.200000e+01, float* %arrayidx1, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare void @llvm.assume(i1) #1
+
diff --git a/final/test/ScopInfo/user_provided_assumptions-in-bb-signed.ll b/final/test/ScopInfo/user_provided_assumptions-in-bb-signed.ll
new file mode 100644
index 0000000..a70cb22
--- /dev/null
+++ b/final/test/ScopInfo/user_provided_assumptions-in-bb-signed.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: Context:
+; CHECK-NEXT: [n] -> {  : -9223372036854775808 <= n <= 100 }
+;
+;    void foo(float A[][100], long n) {
+;      for (long i = 0; i < n; i++)
+;        A[42][i] = 42.0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@.src = private unnamed_addr constant [12 x i8] c"/tmp/test.c\00", align 1
+@0 = private unnamed_addr constant { i16, i16, [14 x i8] } { i16 -1, i16 0, [14 x i8] c"'float [100]'\00" }
+@1 = private unnamed_addr constant { i16, i16, [7 x i8] } { i16 0, i16 13, [7 x i8] c"'long'\00" }
+
+define void @foo([100 x float]* %A, i64 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp slt i64 %i.0, %n
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = icmp slt i64 %i.0, 100
+  call void @llvm.assume(i1 %tmp)
+  %arrayidx1 = getelementptr inbounds [100 x float], [100 x float]* %A, i64 42, i64 %i.0
+  store float 4.200000e+01, float* %arrayidx1, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare void @llvm.assume(i1) #1
+
diff --git a/final/test/ScopInfo/user_provided_assumptions-in-bb-unsigned.ll b/final/test/ScopInfo/user_provided_assumptions-in-bb-unsigned.ll
new file mode 100644
index 0000000..d7fd25f
--- /dev/null
+++ b/final/test/ScopInfo/user_provided_assumptions-in-bb-unsigned.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops -disable-output < %s 2>&1 | FileCheck %s --check-prefix=REMARK
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; REMARK:      remark: <unknown>:0:0: SCoP begins here.
+; REMARK-NEXT: remark: <unknown>:0:0: Use user assumption: [n] -> {  : n <= 100 }
+; REMARK-NEXT: remark: <unknown>:0:0: Signed-unsigned restriction: [n] -> {  : n < 0 }
+; REMARK-NEXT: remark: <unknown>:0:0: SCoP ends here.
+;
+; CHECK: Context:
+; CHECK-NEXT: [n] -> {  : -9223372036854775808 <= n <= 100 }
+;
+;    void foo(float A[][100], long n) {
+;      for (long i = 0; i < n; i++)
+;        A[42][i] = 42.0;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@.src = private unnamed_addr constant [12 x i8] c"/tmp/test.c\00", align 1
+@0 = private unnamed_addr constant { i16, i16, [14 x i8] } { i16 -1, i16 0, [14 x i8] c"'float [100]'\00" }
+@1 = private unnamed_addr constant { i16, i16, [7 x i8] } { i16 0, i16 13, [7 x i8] c"'long'\00" }
+
+define void @foo([100 x float]* %A, i64 %n) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp ult i64 %i.0, %n
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = icmp slt i64 %i.0, 100
+  call void @llvm.assume(i1 %tmp)
+  %arrayidx1 = getelementptr inbounds [100 x float], [100 x float]* %A, i64 42, i64 %i.0
+  store float 4.200000e+01, float* %arrayidx1, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add nuw nsw i64 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+declare void @llvm.assume(i1) #1
+
diff --git a/final/test/ScopInfo/user_provided_assumptions.ll b/final/test/ScopInfo/user_provided_assumptions.ll
new file mode 100644
index 0000000..4e06341
--- /dev/null
+++ b/final/test/ScopInfo/user_provided_assumptions.ll
@@ -0,0 +1,123 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops -disable-output < %s 2>&1 | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s --check-prefix=SCOP
+;
+; CHECK:      remark: <unknown>:0:0: SCoP begins here.
+; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: [M, N] -> {  : N <= 2147483647 - M }
+; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: [M, N] -> {  : -2147483648 - M <= N <= 2147483647 - M }
+; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: [M, N, Debug] -> {  : Debug = 0 and 0 < M <= 100 and -2147483648 - M <= N <= 2147483647 - M }
+; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: [M, N, Debug] -> {  : Debug = 0 and 0 < M <= 100 and 0 < N <= 2147483647 - M }
+; CHECK-NEXT: remark: <unknown>:0:0: SCoP ends here.
+
+; SCOP:      Context:
+; SCOP-NEXT: [N, M, Debug] -> { : Debug = 0 and N > 0 and 0 < M <= 2147483647 - N and M <= 100 }
+; SCOP:      Assumed Context:
+; SCOP-NEXT: [N, M, Debug] -> {  :  }
+; SCOP:      Invalid Context:
+; SCOP-NEXT: [N, M, Debug] -> {  : 1 = 0 }
+;
+;    #include <stdio.h>
+;
+;    void valid(int * restrict A, int * restrict B, int N, int M, int C[100][100], int Debug) {
+;      __builtin_assume(M <= 2147483647 - N);
+;      __builtin_assume(M >= -2147483648 - N);
+;      __builtin_assume(Debug == 0 && M <= 100 && M >= 1 && N >= 1);
+;      if (N + M == -1)
+;        C[0][0] = 0;
+;
+;      for (int i = 0; i < N; i++) {
+;        for (int j = 0; j != M; j++) {
+;          C[i][j] += A[i * M + j] + B[i + j];
+;        }
+;
+;        if (Debug)
+;          printf("Printf!");
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+@.str = private unnamed_addr constant [8 x i8] c"Printf!\00", align 1
+
+define void @valid(i32* noalias %A, i32* noalias %B, i32 %N, i32 %M, [100 x i32]* %C, i32 %Debug) {
+entry:
+  %sub = sub nsw i32 2147483647, %N
+  %cmp = icmp sge i32 %sub, %M
+  call void @llvm.assume(i1 %cmp)
+  %conv = sext i32 %M to i64
+  %conv1 = sext i32 %N to i64
+  %sub2 = sub nsw i64 -2147483648, %conv1
+  %cmp3 = icmp sge i64 %conv, %sub2
+  call void @llvm.assume(i1 %cmp3)
+  %cmp5 = icmp eq i32 %Debug, 0
+  %cmp7 = icmp slt i32 %M, 101
+  %or.cond = and i1 %cmp5, %cmp7
+  %cmp10 = icmp sgt i32 %M, 0
+  %or.cond1 = and i1 %or.cond, %cmp10
+  %cmp12 = icmp sgt i32 %N, 0
+  call void @llvm.assume(i1 %or.cond1)
+  call void @llvm.assume(i1 %cmp12)
+  %add = add nsw i32 %N, %M
+  %cmp14 = icmp eq i32 %add, -1
+  br label %entry.split
+
+entry.split:
+  br i1 %cmp14, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  %arrayidx16 = getelementptr inbounds [100 x i32], [100 x i32]* %C, i64 0, i64 0
+  store i32 0, i32* %arrayidx16, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry
+  %M64 = sext i32 %M to i64
+  %N64 = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.36, %if.end
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc.36 ], [ 0, %if.end ]
+  %cmp17 = icmp slt i64 %indvars.iv3, %N64
+  br i1 %cmp17, label %for.cond.19, label %for.end.38
+
+for.cond.19:                                      ; preds = %for.cond, %for.body.22
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.body.22 ], [ 0, %for.cond ]
+  %cmp20 = icmp eq i64 %indvars.iv, %M64
+  br i1 %cmp20, label %for.end, label %for.body.22
+
+for.body.22:                                      ; preds = %for.cond.19
+  %tmp9 = mul nsw i64 %indvars.iv3, %M64
+  %tmp10 = add nsw i64 %tmp9, %indvars.iv
+  %arrayidx24 = getelementptr inbounds i32, i32* %A, i64 %tmp10
+  %tmp11 = load i32, i32* %arrayidx24, align 4
+  %tmp12 = add nuw nsw i64 %indvars.iv3, %indvars.iv
+  %arrayidx27 = getelementptr inbounds i32, i32* %B, i64 %tmp12
+  %tmp13 = load i32, i32* %arrayidx27, align 4
+  %add28 = add nsw i32 %tmp11, %tmp13
+  %arrayidx32 = getelementptr inbounds [100 x i32], [100 x i32]* %C, i64 %indvars.iv3, i64 %indvars.iv
+  %tmp14 = load i32, i32* %arrayidx32, align 4
+  %add33 = add nsw i32 %tmp14, %add28
+  store i32 %add33, i32* %arrayidx32, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond.19
+
+for.end:                                          ; preds = %for.cond.19
+  %tobool = icmp eq i32 %Debug, 0
+  br i1 %tobool, label %for.inc.36, label %if.then.34
+
+if.then.34:                                       ; preds = %for.end
+  %call = call i32 (i8*, ...) @printf(i8* nonnull getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0))
+  br label %for.inc.36
+
+for.inc.36:                                       ; preds = %for.end, %if.then.34
+  %indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
+  br label %for.cond
+
+for.end.38:                                       ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: nounwind
+declare void @llvm.assume(i1) #0
+
+declare i32 @printf(i8*, ...)
+
+attributes #0 = { nounwind }
diff --git a/final/test/ScopInfo/user_provided_assumptions_2.ll b/final/test/ScopInfo/user_provided_assumptions_2.ll
new file mode 100644
index 0000000..4636ef4
--- /dev/null
+++ b/final/test/ScopInfo/user_provided_assumptions_2.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops -disable-output < %s 2>&1 | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s --check-prefix=SCOP
+;
+; CHECK:      remark: <unknown>:0:0: SCoP begins here.
+; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: { : }
+; CHECK-NEXT: remark: <unknown>:0:0: SCoP ends here.
+
+; SCOP:      Context:
+; SCOP-NEXT: [N, M] -> { : -2147483648 <= N <= 2147483647 and -2147483648 <= M <= 2147483647 }
+; SCOP:      Assumed Context:
+; SCOP-NEXT: [N, M] -> { : }
+; SCOP:      Invalid Context:
+; SCOP-NEXT: [N, M] -> { : 1 = 0 }
+;
+;
+; This test checks that assumptions over parameters not used in the Scop are
+; not modeled. There is no benefit in knowing about parameters that are
+; unused in the scop, and adding them will increase the complexity of our
+; model.
+;
+;    int f(int *A, int N, int M) {
+;      __builtin_assume(M > 0);
+;      for (int i = 0; i < N; i++)
+;        A[i]++;
+;      return M;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @f(i32* %A, i32 %N, i32 %M) {
+entry:
+  %cmp = icmp sgt i32 %M, 0
+  call void @llvm.assume(i1 %cmp)
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp1 = icmp slt i64 %indvars.iv, %tmp
+  br i1 %cmp1, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp1, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret i32 %M
+}
+
+declare void @llvm.assume(i1) #1
+
diff --git a/final/test/ScopInfo/user_provided_assumptions_3.ll b/final/test/ScopInfo/user_provided_assumptions_3.ll
new file mode 100644
index 0000000..f16df21
--- /dev/null
+++ b/final/test/ScopInfo/user_provided_assumptions_3.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops -disable-output < %s 2>&1 | FileCheck %s
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s --check-prefix=SCOP
+;
+; CHECK:      remark: <unknown>:0:0: SCoP begins here.
+; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: [N] -> { : N >= 2 }
+; CHECK-NEXT: remark: <unknown>:0:0: SCoP ends here.
+
+; SCOP:      Context:
+; SCOP-NEXT: [N, M] -> { : 2 <= N <= 2147483647 and -2147483648 <= M <= 2147483647 }
+; SCOP:      Assumed Context:
+; SCOP-NEXT: [N, M] -> { : }
+; SCOP:      Invalid Context:
+; SCOP-NEXT: [N, M] -> { : 1 = 0 }
+;
+;    int f(int *A, int N, int M) {
+;      __builtin_assume(M > 0 && N > M);
+;      for (int i = 0; i < N; i++)
+;        A[i]++;
+;      return M;
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @f(i32* %A, i32 %N, i32 %M) {
+entry:
+  %cmp = icmp sgt i32 %M, 0
+  %cmp1 = icmp sgt i32 %N, %M
+  %and = and i1 %cmp, %cmp1
+  call void @llvm.assume(i1 %and)
+  %tmp1 = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %land.end
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %cmp2 = icmp slt i64 %indvars.iv, %tmp1
+  br i1 %cmp2, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp2, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret i32 %M
+}
+
+declare void @llvm.assume(i1) #1
+
diff --git a/final/test/ScopInfo/user_provided_non_dominating_assumptions.ll b/final/test/ScopInfo/user_provided_non_dominating_assumptions.ll
new file mode 100644
index 0000000..4ca96ff
--- /dev/null
+++ b/final/test/ScopInfo/user_provided_non_dominating_assumptions.ll
@@ -0,0 +1,110 @@
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops \
+; RUN:    -polly-precise-inbounds -disable-output < %s 2>&1 | FileCheck %s
+;
+; CHECK:      remark: <unknown>:0:0: SCoP begins here.
+; CHECK-NEXT: remark: <unknown>:0:0: Use user assumption: [i, N, M] -> {  : N <= i or (N > i and N >= 0) }
+; CHECK-NEXT: remark: <unknown>:0:0: Inbounds assumption:    [i, N, M] -> {  : N <= i or (N > i and M <= 100) }
+; CHECK-NEXT: remark: <unknown>:0:0: SCoP ends here.
+;
+;    void f(int *restrict A, int *restrict B, int i, int N, int M, int C[100][100]) {
+;      for (; i < N; i++) {
+;        __builtin_assume(N >= 0);
+;        for (int j = 0; j != M; j++) {
+;          __builtin_assume(N >= 0);
+;          C[i][j] += A[i * M + j] + B[i + j];
+;        }
+;      }
+;    }
+;
+
+
+; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops \
+; RUN:    -polly-precise-inbounds -disable-output < %s 2>&1 -pass-remarks-output=%t.yaml
+; RUN: cat %t.yaml | FileCheck -check-prefix=YAML %s
+; YAML: --- !Analysis
+; YAML: Pass:            polly-scops
+; YAML: Name:            ScopEntry
+; YAML: Function:        f
+; YAML: Args:
+; YAML:   - String:          SCoP begins here.
+; YAML: ...
+; YAML: --- !Analysis
+; YAML: Pass:            polly-scops
+; YAML: Name:            UserAssumption
+; YAML: Function:        f
+; YAML: Args:
+; YAML:   - String:          'Use user assumption: '
+; YAML:   - String:          '[i, N, M] -> {  : N <= i or (N > i and N >= 0) }'
+; YAML: ...
+; YAML: --- !Analysis
+; YAML: Pass:            polly-scops
+; YAML: Name:            AssumpRestrict
+; YAML: Function:        f
+; YAML: Args:
+; YAML:   - String:          'Inbounds assumption:      [i, N, M] -> {  : N <= i or (N > i and M <= 100) }'
+; YAML: ...
+; YAML: --- !Analysis
+; YAML: Pass:            polly-scops
+; YAML: Name:            ScopEnd
+; YAML: Function:        f
+; YAML: Args:
+; YAML:   - String:          SCoP ends here.
+; YAML: ...
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* noalias %A, i32* noalias %B, i32 %i, i32 %N, i32 %M, [100 x i32]* %C) {
+entry:
+  %tmp = zext i32 %M to i64
+  %tmp6 = sext i32 %i to i64
+  %tmp7 = sext i32 %N to i64
+  %tmp8 = sext i32 %M to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc.15, %entry
+  %indvars.iv3 = phi i64 [ %indvars.iv.next4, %for.inc.15 ], [ %tmp6, %entry ]
+  %cmp = icmp slt i64 %indvars.iv3, %tmp7
+  br i1 %cmp, label %for.body, label %for.end.17
+
+for.body:                                         ; preds = %for.cond
+  %cmp1 = icmp sgt i32 %N, -1
+  call void @llvm.assume(i1 %cmp1)
+  br label %for.cond.2
+
+for.cond.2:                                       ; preds = %for.inc, %for.body
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %for.body ]
+  %cmp3 = icmp eq i64 %indvars.iv, %tmp
+  br i1 %cmp3, label %for.end, label %for.body.4
+
+for.body.4:                                       ; preds = %for.cond.2
+  %tmp9 = mul nsw i64 %indvars.iv3, %tmp8
+  %tmp10 = add nsw i64 %tmp9, %indvars.iv
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %tmp10
+  %tmp11 = load i32, i32* %arrayidx, align 4
+  %tmp12 = add nsw i64 %indvars.iv3, %indvars.iv
+  %arrayidx8 = getelementptr inbounds i32, i32* %B, i64 %tmp12
+  %tmp13 = load i32, i32* %arrayidx8, align 4
+  %add9 = add nsw i32 %tmp11, %tmp13
+  %arrayidx13 = getelementptr inbounds [100 x i32], [100 x i32]* %C, i64 %indvars.iv3, i64 %indvars.iv
+  %tmp14 = load i32, i32* %arrayidx13, align 4
+  %add14 = add nsw i32 %tmp14, %add9
+  store i32 %add14, i32* %arrayidx13, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body.4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond.2
+
+for.end:                                          ; preds = %for.cond.2
+  br label %for.inc.15
+
+for.inc.15:                                       ; preds = %for.end
+  %indvars.iv.next4 = add nsw i64 %indvars.iv3, 1
+  br label %for.cond
+
+for.end.17:                                       ; preds = %for.cond
+  ret void
+}
+
+declare void @llvm.assume(i1) #1
+
diff --git a/final/test/ScopInfo/variant_base_pointer.ll b/final/test/ScopInfo/variant_base_pointer.ll
new file mode 100644
index 0000000..b40a2e6
--- /dev/null
+++ b/final/test/ScopInfo/variant_base_pointer.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-ignore-aliasing -polly-invariant-load-hoisting=true -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-ignore-aliasing -polly-invariant-load-hoisting=true -polly-codegen -analyze < %s
+;
+; %tmp is added to the list of required hoists by -polly-scops and just
+; assumed to be hoisted. Only -polly-scops recognizes it to be unhoistable
+; because ir depends on %call which cannot be executed speculatively.
+;
+; CHECK-NOT:       Invariant Accesses:
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @cli_hex2int() {
+entry:
+  br label %if.end
+
+if.end:                                           ; preds = %entry
+  %call = call i16** @__ctype_b_loc() #0
+  %tmp = load i16*, i16** %call, align 8
+  %arrayidx = getelementptr inbounds i16, i16* %tmp, i64 0
+  %tmp1 = load i16, i16* %arrayidx, align 2
+  store i16 3, i16 *%arrayidx, align 2
+  br i1 false, label %if.then.2, label %if.end.3
+
+if.then.2:                                        ; preds = %if.end
+  br label %cleanup
+
+if.end.3:                                         ; preds = %if.end
+  br label %cleanup
+
+cleanup:                                          ; preds = %if.end.3, %if.then.2
+  ret void
+}
+
+; Function Attrs: nounwind readnone
+declare i16** @__ctype_b_loc() #0
+
+attributes #0 = { nounwind readnone }
diff --git a/final/test/ScopInfo/variant_load_empty_domain.ll b/final/test/ScopInfo/variant_load_empty_domain.ll
new file mode 100644
index 0000000..d8b7bbd
--- /dev/null
+++ b/final/test/ScopInfo/variant_load_empty_domain.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT: }
+;
+; CHECK-NOT: Stmt_if_then
+;
+;
+;    void f(int *A) {
+;      for (int i = 1; i < 10; i++) {
+;        A[i]++;
+;        if (i > 10)
+;          A[i] += A[0];
+;      }
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 1, %entry ]
+  %exitcond = icmp ne i64 %indvars.iv, 10
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp = load i32, i32* %arrayidx, align 4
+  %inc = add nsw i32 %tmp, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br i1 false, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %tmp1 = load i32, i32* %A, align 4
+  %arrayidx4 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx4, align 4
+  %add = add nsw i32 %tmp2, %tmp1
+  store i32 %add, i32* %arrayidx4, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/wraping_signed_expr_0.ll b/final/test/ScopInfo/wraping_signed_expr_0.ll
new file mode 100644
index 0000000..768ccde
--- /dev/null
+++ b/final/test/ScopInfo/wraping_signed_expr_0.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(int *A, char N, char p) {
+;      for (char i = 0; i < N; i++) {
+;        A[i + 3] = 0;
+;      }
+;    }
+;
+; The wrap function has no inbounds GEP but the nowrap function has. Therefore,
+; we will add the assumption that i+1 won't overflow only to the former.
+;
+; CHECK:      Function: wrap
+; CHECK:      Invalid Context:
+; CHECK:      [N] -> {  : N >= 126 }
+;
+;
+; FIXME: This is a negative test as nowrap should not need an assumed context.
+;        However %tmp5 in @nowrap is translated to the SCEV <3,+,1><nw><%bb2>
+;        which lacks the <nsw> flags we would need to avoid runtime checks.
+;
+; CHECK:      Function: nowrap
+; CHECK:      Invalid Context:
+; CHECK-NOT:  [N] -> {  :  }
+;
+target datalayout = "e-m:e-i8:64-f80:128-n8:16:32:64-S128"
+
+define void @wrap(i32* %A, i8 %N, i8 %p) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb7, %bb
+  %indvars.iv = phi i8 [ %indvars.iv.next, %bb7 ], [ 0, %bb ]
+  %tmp3 = icmp slt i8 %indvars.iv, %N
+  br i1 %tmp3, label %bb4, label %bb8
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = add i8 %indvars.iv, 3
+  %tmp6 = getelementptr i32, i32* %A, i8 %tmp5
+  store i32 0, i32* %tmp6, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb4
+  %indvars.iv.next = add nsw nuw i8 %indvars.iv, 1
+  br label %bb2
+
+bb8:                                              ; preds = %bb2
+  ret void
+}
+
+define void @nowrap(i32* %A, i8 %N, i8 %p) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb7, %bb
+  %indvars.iv = phi i8 [ %indvars.iv.next, %bb7 ], [ 0, %bb ]
+  %tmp3 = icmp slt i8 %indvars.iv, %N
+  br i1 %tmp3, label %bb4, label %bb8
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = add nsw nuw i8 %indvars.iv, 3
+  %tmp6 = getelementptr inbounds i32, i32* %A, i8 %tmp5
+  store i32 0, i32* %tmp6, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb4
+  %indvars.iv.next = add nsw nuw i8 %indvars.iv, 1
+  br label %bb2
+
+bb8:                                              ; preds = %bb2
+  ret void
+}
diff --git a/final/test/ScopInfo/wraping_signed_expr_1.ll b/final/test/ScopInfo/wraping_signed_expr_1.ll
new file mode 100644
index 0000000..71a60ac
--- /dev/null
+++ b/final/test/ScopInfo/wraping_signed_expr_1.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(long *A, long N, long p) {
+;      for (long i = 0; i < N; i++)
+;        A[i + 1] = 0;
+;    }
+;
+; The wrap function has no inbounds GEP but the nowrap function has. Therefore,
+; we will add the assumption that i+1 won't overflow only to the former.
+;
+; Note:
+;       1152921504606846975 * sizeof(long) <= 2 ^ 63 - 1
+;  and
+;       1152921504606846976 * sizeof(long) >  2 ^ 63 - 1
+; with
+;       sizeof(long) == 8
+;
+; CHECK:      Function: wrap
+; CHECK:      Invalid Context:
+; CHECK-NEXT: [N] -> {  : N >= 1152921504606846976 }
+;
+; CHECK:      Function: nowrap
+; CHECK:      Invalid Context:
+; CHECK-NEXT: [N] -> {  : 1 = 0 }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @wrap(i64* %A, i64 %N, i64 %p) {
+bb:
+  %tmp31 = icmp slt i64 0, %N
+  br i1 %tmp31, label %bb4.lr.ph, label %bb8
+
+bb4.lr.ph:                                        ; preds = %bb
+  br label %bb4
+
+bb4:                                              ; preds = %bb4.lr.ph, %bb7
+  %indvars.iv2 = phi i64 [ 0, %bb4.lr.ph ], [ %indvars.iv.next, %bb7 ]
+  %tmp5 = add nuw nsw i64 %indvars.iv2, 1
+  %tmp6 = getelementptr i64, i64* %A, i64 %tmp5
+  store i64 0, i64* %tmp6, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv2, 1
+  %tmp3 = icmp slt i64 %indvars.iv.next, %N
+  br i1 %tmp3, label %bb4, label %bb2.bb8_crit_edge
+
+bb2.bb8_crit_edge:                                ; preds = %bb7
+  br label %bb8
+
+bb8:                                              ; preds = %bb2.bb8_crit_edge, %bb
+  ret void
+}
+
+define void @nowrap(i64* %A, i64 %N, i64 %p) {
+bb:
+  %tmp31 = icmp slt i64 0, %N
+  br i1 %tmp31, label %bb4.lr.ph, label %bb8
+
+bb4.lr.ph:                                        ; preds = %bb
+  br label %bb4
+
+bb4:                                              ; preds = %bb4.lr.ph, %bb7
+  %indvars.iv2 = phi i64 [ 0, %bb4.lr.ph ], [ %indvars.iv.next, %bb7 ]
+  %tmp5 = add nuw nsw i64 %indvars.iv2, 1
+  %tmp6 = getelementptr inbounds i64, i64* %A, i64 %tmp5
+  store i64 0, i64* %tmp6, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv2, 1
+  %tmp3 = icmp slt i64 %indvars.iv.next, %N
+  br i1 %tmp3, label %bb4, label %bb2.bb8_crit_edge
+
+bb2.bb8_crit_edge:                                ; preds = %bb7
+  br label %bb8
+
+bb8:                                              ; preds = %bb2.bb8_crit_edge, %bb
+  ret void
+}
diff --git a/final/test/ScopInfo/wraping_signed_expr_2.ll b/final/test/ScopInfo/wraping_signed_expr_2.ll
new file mode 100644
index 0000000..ddcbf43
--- /dev/null
+++ b/final/test/ScopInfo/wraping_signed_expr_2.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(int *A, int N, int p) {
+;      for (int i = 0; i < N; i++)
+;        A[i + 30] = 0;
+;    }
+;
+; The wrap function has no inbounds GEP but the nowrap function has. Therefore,
+; we will add the assumption that i+1 won't overflow only to the former.
+;
+; Note: 2147483618 + 30 == 2 ^ 31
+
+; CHECK:      Function: wrap
+;
+; CHECK:      Context:
+; CHECK-NEXT: [N] -> {  : -2147483648 <= N <= 2147483647 }
+;
+; CHECK:      Invalid Context:
+; CHECK-NEXT: [N] -> {  : N >= 2147483619 }
+
+target datalayout = "e-m:e-i32:64-f80:128-n8:16:32:64-S128"
+
+define void @wrap(i32* %A, i32 %N, i32 %p) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb7, %bb
+  %indvars.iv = phi i32 [ %indvars.iv.next, %bb7 ], [ 0, %bb ]
+  %tmp3 = icmp slt i32 %indvars.iv, %N
+  br i1 %tmp3, label %bb4, label %bb8
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = add i32 %indvars.iv, 30
+  %tmp6 = getelementptr i32, i32* %A, i32 %tmp5
+  store i32 0, i32* %tmp6, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb4
+  %indvars.iv.next = add nuw nsw i32 %indvars.iv, 1
+  br label %bb2
+
+bb8:                                              ; preds = %bb2
+  ret void
+}
diff --git a/final/test/ScopInfo/wraping_signed_expr_3.ll b/final/test/ScopInfo/wraping_signed_expr_3.ll
new file mode 100644
index 0000000..7a99f83
--- /dev/null
+++ b/final/test/ScopInfo/wraping_signed_expr_3.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(int *A, int N, int p) {
+;      for (int i = 0; i < N; i++)
+;        A[i + p] = 0;
+;    }
+;
+; Note: 2147483648 == 2 ^ 31
+;
+; CHECK:      Function: wrap
+; CHECK:      Invalid Context:
+; CHECK:      [N, p] -> {  : p >= 2147483649 - N }
+;
+target datalayout = "e-m:e-i32:64-f80:128-n8:16:32:64-S128"
+
+define void @wrap(i32* %A, i32 %N, i32 %p) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb7, %bb
+  %indvars.iv = phi i32 [ %indvars.iv.next, %bb7 ], [ 0, %bb ]
+  %tmp3 = icmp slt i32 %indvars.iv, %N
+  br i1 %tmp3, label %bb4, label %bb8
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = add i32 %indvars.iv, %p
+  %tmp6 = getelementptr inbounds i32, i32* %A, i32 %tmp5
+  store i32 0, i32* %tmp6, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb4
+  %indvars.iv.next = add nuw nsw i32 %indvars.iv, 1
+  br label %bb2
+
+bb8:                                              ; preds = %bb2
+  ret void
+}
diff --git a/final/test/ScopInfo/wraping_signed_expr_4.ll b/final/test/ScopInfo/wraping_signed_expr_4.ll
new file mode 100644
index 0000000..1ad3a7f
--- /dev/null
+++ b/final/test/ScopInfo/wraping_signed_expr_4.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void f(char *A, char N, char p) {
+;      for (char i = 0; i < N; i++)
+;        A[p-1] = 0;
+;    }
+
+; CHECK:      Function: wrap
+;
+; CHECK:      Context:
+; CHECK-NEXT: [N, p] -> {  : -128 <= N <= 127 and -128 <= p <= 127 }
+;
+; CHECK:      Invalid Context:
+; CHECK-NEXT: [N, p] -> {  : p = -128 and N > 0 }
+
+target datalayout = "e-m:e-i8:64-f80:128-n8:16:32:64-S128"
+
+define void @wrap(i8* %A, i8 %N, i8 %p) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb7, %bb
+  %indvars.iv = phi i8 [ %indvars.iv.next, %bb7 ], [ 0, %bb ]
+  %tmp3 = icmp slt i8 %indvars.iv, %N
+  br i1 %tmp3, label %bb4, label %bb8
+
+bb4:                                              ; preds = %bb2
+  %tmp5 = add i8 %p, -1
+  %tmp6 = getelementptr i8, i8* %A, i8 %tmp5
+  store i8 0, i8* %tmp6, align 4
+  br label %bb7
+
+bb7:                                              ; preds = %bb4
+  %indvars.iv.next = add nuw nsw i8 %indvars.iv, 1
+  br label %bb2
+
+bb8:                                              ; preds = %bb2
+  ret void
+}
diff --git a/final/test/ScopInfo/wraping_signed_expr_5.ll b/final/test/ScopInfo/wraping_signed_expr_5.ll
new file mode 100644
index 0000000..ab2f71d
--- /dev/null
+++ b/final/test/ScopInfo/wraping_signed_expr_5.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; We should not generate runtime check for ((int)r1 + (int)r2) as it is known not
+; to overflow. However (p + q) can, thus checks are needed.
+;
+; CHECK:      Invalid Context:
+; CHECK-NEXT:   [r1, r2, q, p] -> { : r2 > r1 and (p <= -2147483649 - q or r2 >= 128 + r1 or p >= 2147483648 - q) }
+;
+;    void wraps(int *A, int p, short q, char r1, char r2) {
+;      for (char i = r1; i < r2; i++)
+;        A[p + q] = A[(int)r1 + (int)r2];
+;    }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @wraps(i32* %A, i32 %p, i16 signext %q, i8 signext %r1, i8 signext %r2) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %i.0 = phi i8 [ %r1, %entry ], [ %inc, %for.inc ]
+  %cmp = icmp slt i8 %i.0, %r2
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %conv3 = sext i8 %r1 to i64
+  %conv4 = sext i8 %r2 to i64
+  %add = add nsw i64 %conv3, %conv4
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %add
+  %tmp = load i32, i32* %arrayidx, align 4
+  %conv5 = sext i16 %q to i32
+  %add6 = add nsw i32 %conv5, %p
+  %idxprom7 = sext i32 %add6 to i64
+  %arrayidx8 = getelementptr inbounds i32, i32* %A, i64 %idxprom7
+  store i32 %tmp, i32* %arrayidx8, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %inc = add i8 %i.0, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/wraping_signed_expr_6.ll b/final/test/ScopInfo/wraping_signed_expr_6.ll
new file mode 100644
index 0000000..d068cce
--- /dev/null
+++ b/final/test/ScopInfo/wraping_signed_expr_6.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK:    Invalid Context:
+; CHECK:        [N] -> {  : N >= 129 }
+;
+;    void foo(float *A, long N) {
+;      for (long i = 0; i < N; i++)
+;        if ((signed char)i < 100)
+;          A[i] += i;
+;    }
+define void @foo(float* %A, i64 %N) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb11, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp12, %bb11 ]
+  %tmp = icmp slt i64 %i.0, %N
+  br i1 %tmp, label %bb2, label %bb13
+
+bb2:                                              ; preds = %bb1
+  %tmp3 = trunc i64 %i.0 to i8
+  %tmp4 = icmp slt i8 %tmp3, 100
+  br i1 %tmp4, label %bb5, label %bb10
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = sitofp i64 %i.0 to float
+  %tmp7 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp8 = load float, float* %tmp7, align 4
+  %tmp9 = fadd float %tmp8, %tmp6
+  store float %tmp9, float* %tmp7, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb5, %bb2
+  br label %bb11
+
+bb11:                                             ; preds = %bb10
+  %tmp12 = add nuw nsw i64 %i.0, 1
+  br label %bb1
+
+bb13:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/wraping_signed_expr_7.ll b/final/test/ScopInfo/wraping_signed_expr_7.ll
new file mode 100644
index 0000000..d8604a9
--- /dev/null
+++ b/final/test/ScopInfo/wraping_signed_expr_7.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK:    Invalid Context:
+; CHECK:        [N] -> {  : N >= 129 }
+;
+;    void foo(float *A, long N) {
+;      for (long i = 0; i < N;)
+;        if ((signed char)i++ < 100)
+;          A[i] += i;
+;    }
+define void @foo(float* %A, i64 %N) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb11, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp12, %bb11 ]
+  %tmp = icmp slt i64 %i.0, %N
+  br i1 %tmp, label %bb2, label %bb13
+
+bb2:                                              ; preds = %bb1
+  %tmp12 = add nuw nsw i64 %i.0, 1
+  %tmp3 = trunc i64 %i.0 to i8
+  %tmp4 = icmp slt i8 %tmp3, 100
+  br i1 %tmp4, label %bb5, label %bb10
+
+bb5:                                              ; preds = %bb2
+  %tmp6 = sitofp i64 %i.0 to float
+  %tmp7 = getelementptr inbounds float, float* %A, i64 %i.0
+  %tmp8 = load float, float* %tmp7, align 4
+  %tmp9 = fadd float %tmp8, %tmp6
+  store float %tmp9, float* %tmp7, align 4
+  br label %bb10
+
+bb10:                                             ; preds = %bb5, %bb2
+  br label %bb11
+
+bb11:                                             ; preds = %bb10
+  br label %bb1
+
+bb13:                                             ; preds = %bb1
+  ret void
+}
diff --git a/final/test/ScopInfo/wraping_signed_expr_slow_1.ll b/final/test/ScopInfo/wraping_signed_expr_slow_1.ll
new file mode 100644
index 0000000..b0b1392
--- /dev/null
+++ b/final/test/ScopInfo/wraping_signed_expr_slow_1.ll
@@ -0,0 +1,81 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; This checks that the no-wraps checks will be computed fast as some example
+; already showed huge slowdowns even though the inbounds and nsw flags were
+; all in place.
+;
+;    // Inspired by itrans8x8 in transform8x8.c from the ldecode benchmark.
+;    void fast(char *A, char N, char M) {
+;      for (char i = 0; i < 8; i++) {
+;        short index0 = (short)(i + N);
+;        #ifdef fast
+;          short index1 = (index0 *  1) + (short)M;
+;        #else
+;          short index1 = (index0 * 16) + (short)M;
+;        #endif
+;        A[index1]++;
+;      }
+;    }
+;
+; CHECK: Function: fast
+; CHECK: Function: slow
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @fast(i8* %A, i8 %N, i8 %M) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i8 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i8 %indvars.iv, 8
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp3 = add nsw i8 %indvars.iv, %N
+  %tmp3ext = sext i8 %tmp3 to i16
+  ;%mul = mul nsw i16 %tmp3ext, 16
+  %Mext = sext i8 %M to i16
+  %add2 = add nsw i16 %tmp3ext, %Mext
+  %arrayidx = getelementptr inbounds i8, i8* %A, i16 %add2
+  %tmp4 = load i8, i8* %arrayidx, align 4
+  %inc = add nsw i8 %tmp4, 1
+  store i8 %inc, i8* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i8 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+define void @slow(i8* %A, i8 %N, i8 %M) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i8 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i8 %indvars.iv, 8
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp3 = add nsw i8 %indvars.iv, %N
+  %tmp3ext = sext i8 %tmp3 to i16
+  %mul = mul nsw i16 %tmp3ext, 16
+  %Mext = sext i8 %M to i16
+  %add2 = add nsw i16 %mul, %Mext
+  %arrayidx = getelementptr inbounds i8, i8* %A, i16 %add2
+  %tmp4 = load i8, i8* %arrayidx, align 4
+  %inc = add nsw i8 %tmp4, 1
+  store i8 %inc, i8* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i8 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/wraping_signed_expr_slow_2.ll b/final/test/ScopInfo/wraping_signed_expr_slow_2.ll
new file mode 100644
index 0000000..033096e
--- /dev/null
+++ b/final/test/ScopInfo/wraping_signed_expr_slow_2.ll
@@ -0,0 +1,86 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; This checks that the no-wraps checks will be computed fast as some example
+; already showed huge slowdowns even though the inbounds and nsw flags were
+; all in place.
+;
+;    // Inspired by itrans8x8 in transform8x8.c from the ldecode benchmark.
+;    void fast(char *A, char N, char M) {
+;      for (char i = 0; i < 8; i++) {
+;        char  index0 = i + N;
+;        char  index1 = index0 * 16;
+;        char  index2 = index1 + M;
+;        A[(short)index2]++;
+;      }
+;    }
+;
+;    void slow(char *A, char N, char M) {
+;      for (char i = 0; i < 8; i++) {
+;        char  index0 = i + N;
+;        char  index1 = index0 * 16;
+;        short index2 = ((short)index1) + ((short)M);
+;        A[index2]++;
+;      }
+;    }
+;
+; CHECK: Function: fast
+; CHECK: Function: slow
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @fast(i8* %A, i8 %N, i8 %M) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i8 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i8 %indvars.iv, 8
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp3 = add nsw i8 %indvars.iv, %N
+  %mul = mul nsw i8 %tmp3, 16
+  %add2 = add nsw i8 %mul, %M
+  %add2ext = sext i8 %add2 to i16
+  %arrayidx = getelementptr inbounds i8, i8* %A, i16 %add2ext
+  %tmp4 = load i8, i8* %arrayidx, align 4
+  %inc = add nsw i8 %tmp4, 1
+  store i8 %inc, i8* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i8 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
+
+define void @slow(i8* %A, i8 %N, i8 %M) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i8 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %exitcond = icmp ne i8 %indvars.iv, 8
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp3 = add nsw i8 %indvars.iv, %N
+  %mul = mul nsw i8 %tmp3, 16
+  %mulext = sext i8 %mul to i16
+  %Mext = sext i8 %M to i16
+  %add2 = add nsw i16 %mulext, %Mext
+  %arrayidx = getelementptr inbounds i8, i8* %A, i16 %add2
+  %tmp4 = load i8, i8* %arrayidx, align 4
+  %inc = add nsw i8 %tmp4, 1
+  store i8 %inc, i8* %arrayidx, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvars.iv.next = add nuw nsw i8 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/zero_ext_of_truncate.ll b/final/test/ScopInfo/zero_ext_of_truncate.ll
new file mode 100644
index 0000000..68f63e4
--- /dev/null
+++ b/final/test/ScopInfo/zero_ext_of_truncate.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+;    void f(unsigned *restrict I, unsigned *restrict A, unsigned N, unsigned M) {
+;      for (unsigned i = 0; i < N; i++) {
+;        unsigned char V = *I;
+;        if (V < M)
+;          A[i]++;
+;      }
+;    }
+;
+; FIXME: The truncated value should be a paramter.
+; CHECK:         Assumed Context:
+; CHECK-NEXT:    [N, tmp, M] -> { : }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [N, tmp, M] -> { : N < 0 or (N > 0 and tmp >= 128) or (N > 0 and tmp < 0) or (N > 0 and M < 0) }
+;
+; CHECK:         Domain :=
+; CHECK-NEXT:    [N, tmp, M] -> { Stmt_if_then[i0] : tmp >= 0 and M > tmp and 0 <= i0 < N };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* noalias %I, i32* noalias %A, i32 %N, i32 %M) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %lftr.wideiv = trunc i64 %indvars.iv to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, %N
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = load i32, i32* %I, align 4
+  %conv1 = and i32 %tmp, 255
+  %cmp2 = icmp ult i32 %conv1, %M
+  br i1 %cmp2, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp1 = load i32, i32* %arrayidx, align 4
+  %inc = add i32 %tmp1, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/zero_ext_of_truncate_2.ll b/final/test/ScopInfo/zero_ext_of_truncate_2.ll
new file mode 100644
index 0000000..e312cd4
--- /dev/null
+++ b/final/test/ScopInfo/zero_ext_of_truncate_2.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-scops -analyze \
+; RUN: -polly-invariant-load-hoisting=true < %s | FileCheck %s
+;
+;    void f(unsigned long *restrict I, unsigned *restrict A, unsigned N) {
+;      for (unsigned i = 0; i < N; i++) {
+;        unsigned V = *I;
+;        if (V < i)
+;          A[i]++;
+;      }
+;    }
+;
+; CHECK:         Assumed Context:
+; CHECK-NEXT:    [N, tmp] -> { : }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [N, tmp] -> { : N > 0 and (tmp < 0 or tmp >= 2147483648) }
+;
+; CHECK:         Domain :=
+; CHECK-NEXT:    [N, tmp] -> { Stmt_if_then[i0] : tmp >= 0 and tmp < i0 < N };
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i64* noalias %I, i32* noalias %A, i32 %N, i32 %M) {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+  %lftr.wideiv = trunc i64 %indvars.iv to i32
+  %exitcond = icmp ne i32 %lftr.wideiv, %N
+  br i1 %exitcond, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %tmp = load i64, i64* %I, align 8
+  %conv = trunc i64 %tmp to i32
+  %tmp1 = zext i32 %conv to i64
+  %cmp1 = icmp ult i64 %tmp1, %indvars.iv
+  br i1 %cmp1, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+  %tmp2 = load i32, i32* %arrayidx, align 4
+  %inc = add i32 %tmp2, 1
+  store i32 %inc, i32* %arrayidx, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  br label %for.cond
+
+for.end:                                          ; preds = %for.cond
+  ret void
+}
diff --git a/final/test/ScopInfo/zero_ext_space_mismatch.ll b/final/test/ScopInfo/zero_ext_space_mismatch.ll
new file mode 100644
index 0000000..98f3750
--- /dev/null
+++ b/final/test/ScopInfo/zero_ext_space_mismatch.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK:         Assumed Context:
+; CHECK-NEXT:    [dim] -> {  : dim > 0 }
+; CHECK-NEXT:    Invalid Context:
+; CHECK-NEXT:    [dim] -> {  : dim < 0 }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Function Attrs: nounwind uwtable
+define void @horner_bezier_curve(float* %cp, i32 %dim) #0 {
+entry:
+  br label %for.body18.lr.ph
+
+for.body18.lr.ph:                                 ; preds = %entry
+  %add.ptr = getelementptr inbounds float, float* %cp, i64 0
+  br label %for.body18
+
+for.body18:                                       ; preds = %for.body18, %for.body18.lr.ph
+  %cp.addr.052 = phi float* [ %add.ptr, %for.body18.lr.ph ], [ %add.ptr43, %for.body18 ]
+  %arrayidx31 = getelementptr inbounds float, float* %cp.addr.052, i64 0
+  %0 = load float, float* %arrayidx31, align 4
+  store float %0, float* %arrayidx31, align 4
+  %idx.ext42 = zext i32 %dim to i64
+  %add.ptr43 = getelementptr inbounds float, float* %cp.addr.052, i64 %idx.ext42
+  br i1 false, label %for.body18, label %if.end
+
+if.end:                                           ; preds = %for.body18
+  ret void
+}
diff --git a/final/test/ScopInliner/ignore-declares.ll b/final/test/ScopInliner/ignore-declares.ll
new file mode 100644
index 0000000..4f67858
--- /dev/null
+++ b/final/test/ScopInliner/ignore-declares.ll
@@ -0,0 +1,8 @@
+; RUN: opt %loadPolly -polly-detect-full-functions -polly-scop-inliner \
+; RUN: -polly-scops -analyze < %s
+
+; Check that we do not crash if there are declares. We should skip function
+; declarations and not try to query for domtree.
+
+declare void @foo()
+
diff --git a/final/test/ScopInliner/invariant-load-func.ll b/final/test/ScopInliner/invariant-load-func.ll
new file mode 100644
index 0000000..52387f8
--- /dev/null
+++ b/final/test/ScopInliner/invariant-load-func.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -polly-detect-full-functions -polly-scop-inliner \
+; RUN: -polly-scops -analyze -polly-invariant-load-hoisting < %s | FileCheck %s
+
+; Check that we inline a function that requires invariant load hoisting
+; correctly.
+; CHECK:    Max Loop Depth:  2
+
+; REQUIRES: pollyacc
+
+
+; void to_be_inlined(int A[], int *begin, int *end) {
+;     for(int i = *begin; i < *end; i++) {
+;         A[i] = 10;
+;     }
+; }
+;
+; static const int N = 1000;
+;
+; void inline_site(int A[], int *begin, int *end) {
+;     for(int i = 0; i < N; i++)
+;         to_be_inlined(A);
+; }
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.12.0"
+
+define void @to_be_inlined(i32* %A, i32* %begin, i32* %end) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %tmp = load i32, i32* %begin, align 4
+  %tmp21 = load i32, i32* %end, align 4
+  %cmp3 = icmp slt i32 %tmp, %tmp21
+  br i1 %cmp3, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:                                   ; preds = %entry.split
+  %tmp1 = sext i32 %tmp to i64
+  br label %for.body
+
+for.body:                                         ; preds = %for.body.lr.ph, %for.body
+  %indvars.iv4 = phi i64 [ %tmp1, %for.body.lr.ph ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv4
+  store i32 10, i32* %arrayidx, align 4
+  %indvars.iv.next = add i64 %indvars.iv4, 1
+  %tmp2 = load i32, i32* %end, align 4
+  %tmp3 = sext i32 %tmp2 to i64
+  %cmp = icmp slt i64 %indvars.iv.next, %tmp3
+  br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge
+
+for.cond.for.end_crit_edge:                       ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry.split
+  ret void
+}
+
+
+define void @inline_site(i32* %A, i32* %begin, i32 *%end) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %i.01 = phi i32 [ 0, %entry.split ], [ %inc, %for.body ]
+  tail call void @to_be_inlined(i32* %A, i32* %begin, i32* %end)
+  %inc = add nuw nsw i32 %i.01, 1
+  %exitcond = icmp eq i32 %inc, 1000
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.body
+  ret void
+}
+
diff --git a/final/test/ScopInliner/simple-inline-loop.ll b/final/test/ScopInliner/simple-inline-loop.ll
new file mode 100644
index 0000000..c849e1e
--- /dev/null
+++ b/final/test/ScopInliner/simple-inline-loop.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-detect-full-functions -polly-scop-inliner \
+; RUN: -polly-scops -analyze < %s | FileCheck %s
+
+; Check that we get the 2 nested loops by inlining `to_be_inlined` into
+; `inline_site`.
+; CHECK:    Max Loop Depth:  2
+
+; static const int N = 1000;
+;
+; void to_be_inlined(int A[]) {
+;     for(int i = 0; i < N; i++)
+;         A[i] *= 10;
+; }
+;
+; void inline_site(int A[]) {
+;     for(int i = 0; i < N; i++)
+;         to_be_inlined(A);
+; }
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.12.0"
+
+
+define void @to_be_inlined(i32* %A) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %indvars.iv1 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next, %for.body ]
+  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv1
+  %tmp = load i32, i32* %arrayidx, align 4
+  %mul = mul nsw i32 %tmp, 10
+  store i32 %mul, i32* %arrayidx, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv1, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 1000
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.body
+  ret void
+}
+
+define void @inline_site(i32* %A) {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.body
+
+for.body:                                         ; preds = %entry.split, %for.body
+  %i.01 = phi i32 [ 0, %entry.split ], [ %inc, %for.body ]
+  tail call void @to_be_inlined(i32* %A)
+  %inc = add nuw nsw i32 %i.01, 1
+  %exitcond = icmp eq i32 %inc, 1000
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.body
+  ret void
+}
+
diff --git a/final/test/Simplify/coalesce_3partials.ll b/final/test/Simplify/coalesce_3partials.ll
new file mode 100644
index 0000000..e3e4fed
--- /dev/null
+++ b/final/test/Simplify/coalesce_3partials.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Combine 3 partial accesses into one.
+;
+; for (int j = 0; j < n; j += 1) {
+;   A[0] = 42.0;
+;   A[0] = 42.0;
+;   A[0] = 42.0;
+; }
+;
+define void @coalesce_3partials(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 42.0, double* %A
+      store double 42.0, double* %A
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Overwrites removed: 0
+; CHECK:     Partial writes coalesced: 2
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0] -> MemRef_A[0] : n <= 2147483647 };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/coalesce_3partials___%for---%return.jscop b/final/test/Simplify/coalesce_3partials___%for---%return.jscop
new file mode 100644
index 0000000..d6ad070
--- /dev/null
+++ b/final/test/Simplify/coalesce_3partials___%for---%return.jscop
@@ -0,0 +1,32 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/coalesce_3partials___%for---%return.jscop.transformed b/final/test/Simplify/coalesce_3partials___%for---%return.jscop.transformed
new file mode 100644
index 0000000..498b0ed
--- /dev/null
+++ b/final/test/Simplify/coalesce_3partials___%for---%return.jscop.transformed
@@ -0,0 +1,32 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 < 8 }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : 8 <= i0 < 16 }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : 16 <= i0 }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/coalesce_disjointelements.ll b/final/test/Simplify/coalesce_disjointelements.ll
new file mode 100644
index 0000000..b7d9549
--- /dev/null
+++ b/final/test/Simplify/coalesce_disjointelements.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Combine four partial stores into two.
+; The stores write to the same array, but never the same element.
+;
+; for (int j = 0; j < n; j += 1) {
+;   A[0] = 21.0;
+;   A[1] = 42.0;
+;   A[0] = 21.0;
+;   A[1] = 42.0;
+; }
+;
+define void @coalesce_disjointelements(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %A_0 = getelementptr inbounds double, double* %A, i32 0
+      %A_1 = getelementptr inbounds double, double* %A, i32 1
+      store double 21.0, double* %A_0
+      store double 42.0, double* %A_1
+      store double 21.0, double* %A_0
+      store double 42.0, double* %A_1
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Overwrites removed: 0
+; CHECK:     Partial writes coalesced: 2
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0] -> MemRef_A[0] : n <= 2147483647 };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_A[1] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0] -> MemRef_A[1] : n <= 2147483647 };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/coalesce_disjointelements___%for---%return.jscop b/final/test/Simplify/coalesce_disjointelements___%for---%return.jscop
new file mode 100644
index 0000000..5a84248
--- /dev/null
+++ b/final/test/Simplify/coalesce_disjointelements___%for---%return.jscop
@@ -0,0 +1,36 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/coalesce_disjointelements___%for---%return.jscop.transformed b/final/test/Simplify/coalesce_disjointelements___%for---%return.jscop.transformed
new file mode 100644
index 0000000..3e1dd7e
--- /dev/null
+++ b/final/test/Simplify/coalesce_disjointelements___%for---%return.jscop.transformed
@@ -0,0 +1,36 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 > 16 }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] : i0 > 16 }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 <= 16 }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] : i0 <= 16 }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/coalesce_overlapping.ll b/final/test/Simplify/coalesce_overlapping.ll
new file mode 100644
index 0000000..6004644
--- /dev/null
+++ b/final/test/Simplify/coalesce_overlapping.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Combine two partial stores (with overlapping domains) into one.
+;
+; for (int j = 0; j < n; j += 1) {
+;   A[0] = 42.0;
+;   A[0] = 42.0;
+; }
+;
+define void @coalesce_overlapping(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 42.0, double* %A
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Overwrites removed: 0
+; CHECK:     Partial writes coalesced: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0] -> MemRef_A[0] : n <= 2147483647 };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/coalesce_overlapping___%for---%return.jscop b/final/test/Simplify/coalesce_overlapping___%for---%return.jscop
new file mode 100644
index 0000000..bb33622
--- /dev/null
+++ b/final/test/Simplify/coalesce_overlapping___%for---%return.jscop
@@ -0,0 +1,28 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/coalesce_overlapping___%for---%return.jscop.transformed b/final/test/Simplify/coalesce_overlapping___%for---%return.jscop.transformed
new file mode 100644
index 0000000..afb5819
--- /dev/null
+++ b/final/test/Simplify/coalesce_overlapping___%for---%return.jscop.transformed
@@ -0,0 +1,28 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 < 18 }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 >= 8}"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/coalesce_partial.ll b/final/test/Simplify/coalesce_partial.ll
new file mode 100644
index 0000000..4a19a7c
--- /dev/null
+++ b/final/test/Simplify/coalesce_partial.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Combine two partial stores (with disjoint domains) into one.
+;
+; for (int j = 0; j < n; j += 1) {
+;   A[0] = 42.0;
+;   A[0] = 42.0;
+; }
+;
+define void @coalesce_partial(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 42.0, double* %A
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Overwrites removed: 0
+; CHECK:     Partial writes coalesced: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0] -> MemRef_A[0] : n <= 2147483647 };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/coalesce_partial___%for---%return.jscop b/final/test/Simplify/coalesce_partial___%for---%return.jscop
new file mode 100644
index 0000000..bb33622
--- /dev/null
+++ b/final/test/Simplify/coalesce_partial___%for---%return.jscop
@@ -0,0 +1,28 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/coalesce_partial___%for---%return.jscop.transformed b/final/test/Simplify/coalesce_partial___%for---%return.jscop.transformed
new file mode 100644
index 0000000..9b7e63a
--- /dev/null
+++ b/final/test/Simplify/coalesce_partial___%for---%return.jscop.transformed
@@ -0,0 +1,28 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 < 16 }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 >= 16 }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/dead_access_load.ll b/final/test/Simplify/dead_access_load.ll
new file mode 100644
index 0000000..3febfa1
--- /dev/null
+++ b/final/test/Simplify/dead_access_load.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Remove a dead load-instruction
+; (an load whose result is not used anywhere)
+;
+; for (int j = 0; j < n; j += 1) {
+;   double val = A[0];
+;   A[0] = 42.0;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = load double, double* %A
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Dead accesses removed: 1
+; CHECK:     Dead instructions removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/dead_access_phi.ll b/final/test/Simplify/dead_access_phi.ll
new file mode 100644
index 0000000..627195e
--- /dev/null
+++ b/final/test/Simplify/dead_access_phi.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Remove a dead PHI write/read pair
+; (accesses that are effectively not used)
+;
+; for (int j = 0; j < n; j += 1) {
+; body:
+;   double phi = 42;
+; 
+; body_succ:
+;   A[0] = 42.0;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      br label %body_succ
+      
+    body_succ:
+      %phi = phi double [42.0, %body]
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Dead accesses removed: 2
+; CHECK:     Dead instructions removed: 1
+; CHECK:     Stmts removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_body_succ
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body_succ[i0] -> MemRef_A[0] };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/dead_access_value.ll b/final/test/Simplify/dead_access_value.ll
new file mode 100644
index 0000000..0b75e7e
--- /dev/null
+++ b/final/test/Simplify/dead_access_value.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Remove a dead value write/read pair
+; (accesses that are effectively not used)
+;
+; for (int j = 0; j < n; j += 1) {
+; body:
+;   double val = 12.5 + 12.5;
+; 
+; body_succ:
+;   double unused = val + 21.0;
+;   A[0] = 42.0;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = fadd double 12.5, 12.5
+      br label %body_succ
+      
+    body_succ:
+      %unused = fadd double %val, 21.0
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Dead accesses removed: 2
+; CHECK:     Dead instructions removed: 2
+; CHECK:     Stmts removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_body_succ
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body_succ[i0] -> MemRef_A[0] };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/dead_instruction.ll b/final/test/Simplify/dead_instruction.ll
new file mode 100644
index 0000000..0925c87
--- /dev/null
+++ b/final/test/Simplify/dead_instruction.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Remove a dead instruction
+; (an instruction whose result is not used anywhere)
+;
+; for (int j = 0; j < n; j += 1) {
+;   double val = 21.0 + 21.0;
+;   A[0] = 42.0;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = fadd double 21.0, 21.0
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Dead instructions removed: 1
+; CHECK: }
diff --git a/final/test/Simplify/emptyaccessdomain.ll b/final/test/Simplify/emptyaccessdomain.ll
new file mode 100644
index 0000000..fcbf075
--- /dev/null
+++ b/final/test/Simplify/emptyaccessdomain.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; for (int j = 0; j < n; j += 1) {
+;   A[0] = 42.0;
+; }
+;
+define void @emptyaccessdomain(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Accesses with empty domains removed: 1
+; CHECK:     Stmts removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/emptyaccessdomain___%for---%return.jscop b/final/test/Simplify/emptyaccessdomain___%for---%return.jscop
new file mode 100644
index 0000000..a0472bc
--- /dev/null
+++ b/final/test/Simplify/emptyaccessdomain___%for---%return.jscop
@@ -0,0 +1,24 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/emptyaccessdomain___%for---%return.jscop.transformed b/final/test/Simplify/emptyaccessdomain___%for---%return.jscop.transformed
new file mode 100644
index 0000000..e881f7e
--- /dev/null
+++ b/final/test/Simplify/emptyaccessdomain___%for---%return.jscop.transformed
@@ -0,0 +1,24 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : 1 = 0 }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/exit_phi_accesses-2.ll b/final/test/Simplify/exit_phi_accesses-2.ll
new file mode 100644
index 0000000..fde3d01
--- /dev/null
+++ b/final/test/Simplify/exit_phi_accesses-2.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-scops -polly-simplify -analyze < %s | FileCheck %s
+;
+; The use of %sum.next by %phi counts as an escaping use.
+; Don't remove the scalar write of %sum.next.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define float @foo(float* %A) {
+entry:
+  br label %header
+
+header:
+  fence seq_cst
+  br i1 true, label %body, label %exit
+
+body:
+  %i = phi i64 [ 0, %header ], [ %next, %body ]
+  %sum = phi float [ 0.0, %header ], [ %sum.next, %body ]
+  %arrayidx = getelementptr float, float* %A, i64 %i
+  %next = add nuw nsw i64 %i, 1
+  %val = load float, float* %arrayidx
+  %sum.next = fadd float %sum, %val
+  %cond = icmp ne i64 %i, 100
+  br i1 %cond, label %body, label %after
+
+after:
+  br label %exit
+
+exit:
+  %phi = phi float [%sum.next, %after], [0.0, %header]
+  ret float %phi
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Dead accesses removed: 0
+; CHECK: }
diff --git a/final/test/Simplify/gemm.ll b/final/test/Simplify/gemm.ll
new file mode 100644
index 0000000..85f05d1
--- /dev/null
+++ b/final/test/Simplify/gemm.ll
@@ -0,0 +1,114 @@
+; RUN: opt %loadPolly -polly-import-jscop \
+; RUN:   -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s \
+; RUN:   | FileCheck %s
+;
+;    void gemm(float A[][1024], float B[][1024], float C[][1024]) {
+;      for (long i = 0; i < 1024; i++)
+;        for (long j = 0; j < 1024; j++) {
+;          float tmp = C[i][j];
+;          for (long k = 0; k < 1024; k++)
+;            tmp += A[i][k] * B[k][j];
+;          C[i][j] = tmp;
+;        }
+;    }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_bb13
+; CHECK-NEXT:             MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_bb13[i0, i1, i2] -> MemRef_tmp_0__phi[] };
+; CHECK-NEXT:            new: { Stmt_bb13[i0, i1, i2] -> MemRef_C[i0, i1] };
+; CHECK-NEXT:             ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_bb13[i0, i1, i2] -> MemRef_A[i0, i2] };
+; CHECK-NEXT:             ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 { Stmt_bb13[i0, i1, i2] -> MemRef_B[i2, i1] };
+; CHECK-NEXT:             ReadAccess :=	[Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_bb13[i0, i1, i2] -> MemRef_tmp_0[] };
+; CHECK-NEXT:            new: { Stmt_bb13[i0, i1, i2] -> MemRef_C[i0, i1] };
+; CHECK-NEXT: }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+define void @gemm([1024 x float]* %A, [1024 x float]* %B, [1024 x float]* %C) {
+bb:
+  br label %bb3
+
+bb3:                                              ; preds = %bb26, %bb
+  %i.0 = phi i64 [ 0, %bb ], [ %tmp27, %bb26 ]
+  %exitcond2 = icmp ne i64 %i.0, 1024
+  br i1 %exitcond2, label %bb5, label %bb4
+
+bb4:                                              ; preds = %bb3
+  br label %bb28
+
+bb5:                                              ; preds = %bb3
+  br label %bb6
+
+bb6:                                              ; preds = %bb23, %bb5
+  %j.0 = phi i64 [ 0, %bb5 ], [ %tmp24, %bb23 ]
+  %exitcond1 = icmp ne i64 %j.0, 1024
+  br i1 %exitcond1, label %bb8, label %bb7
+
+bb7:                                              ; preds = %bb6
+  br label %bb25
+
+bb8:                                              ; preds = %bb6
+  %tmp = getelementptr inbounds [1024 x float], [1024 x float]* %C, i64 %i.0, i64 %j.0
+  %tmp9 = load float, float* %tmp, align 4, !tbaa !1
+  br label %bb10
+
+bb10:                                             ; preds = %bb13, %bb8
+  %tmp.0 = phi float [ %tmp9, %bb8 ], [ %tmp19, %bb13 ]
+  %k.0 = phi i64 [ 0, %bb8 ], [ %tmp20, %bb13 ]
+  %exitcond = icmp ne i64 %k.0, 1024
+  br i1 %exitcond, label %bb12, label %bb11
+
+bb11:                                             ; preds = %bb10
+  %tmp.0.lcssa = phi float [ %tmp.0, %bb10 ]
+  br label %bb21
+
+bb12:                                             ; preds = %bb10
+  br label %bb13
+
+bb13:                                             ; preds = %bb12
+  %tmp14 = getelementptr inbounds [1024 x float], [1024 x float]* %A, i64 %i.0, i64 %k.0
+  %tmp15 = load float, float* %tmp14, align 4, !tbaa !1
+  %tmp16 = getelementptr inbounds [1024 x float], [1024 x float]* %B, i64 %k.0, i64 %j.0
+  %tmp17 = load float, float* %tmp16, align 4, !tbaa !1
+  %tmp18 = fmul float %tmp15, %tmp17
+  %tmp19 = fadd float %tmp.0, %tmp18
+  %tmp20 = add nuw nsw i64 %k.0, 1
+  br label %bb10
+
+bb21:                                             ; preds = %bb11
+  %tmp22 = getelementptr inbounds [1024 x float], [1024 x float]* %C, i64 %i.0, i64 %j.0
+  store float %tmp.0.lcssa, float* %tmp22, align 4, !tbaa !1
+  br label %bb23
+
+bb23:                                             ; preds = %bb21
+  %tmp24 = add nuw nsw i64 %j.0, 1
+  br label %bb6
+
+bb25:                                             ; preds = %bb7
+  br label %bb26
+
+bb26:                                             ; preds = %bb25
+  %tmp27 = add nuw nsw i64 %i.0, 1
+  br label %bb3
+
+bb28:                                             ; preds = %bb4
+  ret void
+}
+
+declare void @llvm.lifetime.start(i64, i8* nocapture)
+
+declare void @llvm.lifetime.end(i64, i8* nocapture)
+
+
+!llvm.ident = !{!0}
+
+!0 = !{!"Ubuntu clang version 3.7.1-3ubuntu4 (tags/RELEASE_371/final) (based on LLVM 3.7.1)"}
+!1 = !{!2, !2, i64 0}
+!2 = !{!"float", !3, i64 0}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
diff --git a/final/test/Simplify/gemm___%bb3---%bb28.jscop b/final/test/Simplify/gemm___%bb3---%bb28.jscop
new file mode 100644
index 0000000..7fb3522
--- /dev/null
+++ b/final/test/Simplify/gemm___%bb3---%bb28.jscop
@@ -0,0 +1,110 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*", "1024" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1024" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1024" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb3---%bb28",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb8[i0, i1] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb8[i0, i1] -> MemRef_tmp_0__phi[] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb8[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 }",
+         "name" : "Stmt_bb8",
+         "schedule" : "{ Stmt_bb8[i0, i1] -> [i0, i1, 0, 0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb10[i0, i1, i2] -> MemRef_tmp_0__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb10[i0, i1, i2] -> MemRef_tmp_0[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb10[i0, i1, i2] -> MemRef_tmp_0_lcssa__phi[] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb10[i0, i1, i2] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 and 0 <= i2 <= 1024 }",
+         "name" : "Stmt_bb10",
+         "schedule" : "{ Stmt_bb10[i0, i1, i2] -> [i0, i1, 1, i2, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb13[i0, i1, i2] -> MemRef_tmp_0__phi[] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb13[i0, i1, i2] -> MemRef_A[i0, i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb13[i0, i1, i2] -> MemRef_B[i2, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb13[i0, i1, i2] -> MemRef_tmp_0[] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb13[i0, i1, i2] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 and 0 <= i2 <= 1023 }",
+         "name" : "Stmt_bb13",
+         "schedule" : "{ Stmt_bb13[i0, i1, i2] -> [i0, i1, 1, i2, 1] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb11[i0, i1] -> MemRef_tmp_0_lcssa__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb11[i0, i1] -> MemRef_tmp_0_lcssa[] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb11[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 }",
+         "name" : "Stmt_bb11",
+         "schedule" : "{ Stmt_bb11[i0, i1] -> [i0, i1, 2, 0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb21[i0, i1] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb21[i0, i1] -> MemRef_tmp_0_lcssa[] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb21[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 }",
+         "name" : "Stmt_bb21",
+         "schedule" : "{ Stmt_bb21[i0, i1] -> [i0, i1, 3, 0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/gemm___%bb3---%bb28.jscop.transformed b/final/test/Simplify/gemm___%bb3---%bb28.jscop.transformed
new file mode 100644
index 0000000..56928b7
--- /dev/null
+++ b/final/test/Simplify/gemm___%bb3---%bb28.jscop.transformed
@@ -0,0 +1,110 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*", "1024" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*", "1024" ],
+         "type" : "float"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*", "1024" ],
+         "type" : "float"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%bb3---%bb28",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb8[i0, i1] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb8[i0, i1] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb8[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 }",
+         "name" : "Stmt_bb8",
+         "schedule" : "{ Stmt_bb8[i0, i1] -> [i0, i1, 0, 0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb10[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb10[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb10[i0, i1, 1024] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb10[i0, i1, i2] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 and 0 <= i2 <= 1024 }",
+         "name" : "Stmt_bb10",
+         "schedule" : "{ Stmt_bb10[i0, i1, i2] -> [i0, i1, 1, i2, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb13[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb13[i0, i1, i2] -> MemRef_A[i0, i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb13[i0, i1, i2] -> MemRef_B[i2, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb13[i0, i1, i2] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb13[i0, i1, i2] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 and 0 <= i2 <= 1023 }",
+         "name" : "Stmt_bb13",
+         "schedule" : "{ Stmt_bb13[i0, i1, i2] -> [i0, i1, 1, i2, 1] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb11[i0, i1] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb11[i0, i1] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb11[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 }",
+         "name" : "Stmt_bb11",
+         "schedule" : "{ Stmt_bb11[i0, i1] -> [i0, i1, 2, 0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_bb21[i0, i1] -> MemRef_C[i0, i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_bb21[i0, i1] -> MemRef_C[i0, i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_bb21[i0, i1] : 0 <= i0 <= 1023 and 0 <= i1 <= 1023 }",
+         "name" : "Stmt_bb21",
+         "schedule" : "{ Stmt_bb21[i0, i1] -> [i0, i1, 3, 0, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/nocoalesce_differentvalues.ll b/final/test/Simplify/nocoalesce_differentvalues.ll
new file mode 100644
index 0000000..ef1b7fc
--- /dev/null
+++ b/final/test/Simplify/nocoalesce_differentvalues.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Do not combine stores that write different values.
+;
+; for (int j = 0; j < n; j += 1) {
+;   A[0] = 21.0;
+;   A[0] = 42.0;
+; }
+;
+define void @nocoalesce_differentvalues(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 21.0, double* %A
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Overwrites removed: 0
+; CHECK:     Partial writes coalesced: 0
+; CHECK: }
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/nocoalesce_differentvalues___%for---%return.jscop b/final/test/Simplify/nocoalesce_differentvalues___%for---%return.jscop
new file mode 100644
index 0000000..bb33622
--- /dev/null
+++ b/final/test/Simplify/nocoalesce_differentvalues___%for---%return.jscop
@@ -0,0 +1,28 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/nocoalesce_differentvalues___%for---%return.jscop.transformed b/final/test/Simplify/nocoalesce_differentvalues___%for---%return.jscop.transformed
new file mode 100644
index 0000000..b6078c9
--- /dev/null
+++ b/final/test/Simplify/nocoalesce_differentvalues___%for---%return.jscop.transformed
@@ -0,0 +1,28 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 >= 16}"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 < 16}"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/nocoalesce_elementmismatch.ll b/final/test/Simplify/nocoalesce_elementmismatch.ll
new file mode 100644
index 0000000..6eeeccb
--- /dev/null
+++ b/final/test/Simplify/nocoalesce_elementmismatch.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Do not combine stores that do not write to different elements in the
+; same instance.
+;
+; for (int j = 0; j < n; j += 1) {
+;   A[0] = 21.0;
+;   A[0] = 42.0;
+; }
+;
+define void @nocoalesce_elementmismatch(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %A_0 = getelementptr inbounds double, double* %A, i32 0
+      %A_1 = getelementptr inbounds double, double* %A, i32 1
+      store double 42.0, double* %A_0
+      store double 42.0, double* %A_1
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/nocoalesce_elementmismatch___%for---%return.jscop b/final/test/Simplify/nocoalesce_elementmismatch___%for---%return.jscop
new file mode 100644
index 0000000..b785f42
--- /dev/null
+++ b/final/test/Simplify/nocoalesce_elementmismatch___%for---%return.jscop
@@ -0,0 +1,28 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/nocoalesce_elementmismatch___%for---%return.jscop.transformed b/final/test/Simplify/nocoalesce_elementmismatch___%for---%return.jscop.transformed
new file mode 100644
index 0000000..9993867
--- /dev/null
+++ b/final/test/Simplify/nocoalesce_elementmismatch___%for---%return.jscop.transformed
@@ -0,0 +1,28 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 >= 16 }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] : i0 <= 16}"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/nocoalesce_readbetween.ll b/final/test/Simplify/nocoalesce_readbetween.ll
new file mode 100644
index 0000000..dad462e
--- /dev/null
+++ b/final/test/Simplify/nocoalesce_readbetween.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Do not combine stores if there is a read between them.
+; Note: The read between is unused, so will be removed by markAndSweep.
+; However, searches for coalesces takes place before.
+;
+; for (int j = 0; j < n; j += 1) {
+;   A[0] = 42.0;
+;   tmp = A[0];
+;   A[0] = 42.0;
+; }
+;
+define void @nocoalesce_readbetween(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 42.0, double* %A
+      %tmp = load double, double* %A
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Overwrites removed: 0
+; CHECK:     Partial writes coalesced: 0
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 >= 17 };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 <= 16 };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/nocoalesce_readbetween___%for---%return.jscop b/final/test/Simplify/nocoalesce_readbetween___%for---%return.jscop
new file mode 100644
index 0000000..6f074c1
--- /dev/null
+++ b/final/test/Simplify/nocoalesce_readbetween___%for---%return.jscop
@@ -0,0 +1,32 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/nocoalesce_readbetween___%for---%return.jscop.transformed b/final/test/Simplify/nocoalesce_readbetween___%for---%return.jscop.transformed
new file mode 100644
index 0000000..106021d
--- /dev/null
+++ b/final/test/Simplify/nocoalesce_readbetween___%for---%return.jscop.transformed
@@ -0,0 +1,32 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 > 16 }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 <= 16 }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/nocoalesce_writebetween.ll b/final/test/Simplify/nocoalesce_writebetween.ll
new file mode 100644
index 0000000..d467212
--- /dev/null
+++ b/final/test/Simplify/nocoalesce_writebetween.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Do not combine stores if there is a write between them.
+;
+; for (int j = 0; j < n; j += 1) {
+;   A[0] = 42.0;
+;   A[0] = 21.0;
+;   A[0] = 42.0;
+; }
+;
+define void @nocoalesce_writebetween(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 42.0, double* %A
+      store double 21.0, double* %A
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/nocoalesce_writebetween___%for---%return.jscop b/final/test/Simplify/nocoalesce_writebetween___%for---%return.jscop
new file mode 100644
index 0000000..d6ad070
--- /dev/null
+++ b/final/test/Simplify/nocoalesce_writebetween___%for---%return.jscop
@@ -0,0 +1,32 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/nocoalesce_writebetween___%for---%return.jscop.transformed b/final/test/Simplify/nocoalesce_writebetween___%for---%return.jscop.transformed
new file mode 100644
index 0000000..06f5433
--- /dev/null
+++ b/final/test/Simplify/nocoalesce_writebetween___%for---%return.jscop.transformed
@@ -0,0 +1,32 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 < 16 }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : 8 <= i0 < 24}"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 >= 16 }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/notdead_region_exitphi.ll b/final/test/Simplify/notdead_region_exitphi.ll
new file mode 100644
index 0000000..77c34ed
--- /dev/null
+++ b/final/test/Simplify/notdead_region_exitphi.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Do not remove dependencies of a phi node in a region's exit block.
+;
+define void @func(i32 %n, double* noalias nonnull %A, double %alpha) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = fadd double 21.0, 21.0
+      br label %region_entry
+
+
+    region_entry:
+      %region.cmp = fcmp ueq double %alpha, 0.0
+      br i1 %region.cmp, label %region_true, label %region_exit
+
+    region_true:
+      br label %region_exit
+
+    region_exit:
+      %phi = phi double [%val, %region_true], [0.0, %region_entry]
+      store double %phi, double* %A
+      br label %inc
+
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/notdead_region_innerphi.ll b/final/test/Simplify/notdead_region_innerphi.ll
new file mode 100644
index 0000000..5749186
--- /dev/null
+++ b/final/test/Simplify/notdead_region_innerphi.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Do not remove dependencies of a phi node within a region statement (%phi).
+;
+define void @func(i32 %n, double* noalias nonnull %A, double %alpha) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = fadd double 21.0, 21.0
+      br label %region_entry
+
+
+    region_entry:
+      %region.cmp = fcmp ueq double %alpha, 0.0
+      br i1 %region.cmp, label %region_true, label %region_exit
+
+    region_true:
+      br i1 true, label %region_verytrue, label %region_mostlytrue
+
+    region_verytrue:
+      br label %region_mostlytrue
+
+    region_mostlytrue:
+      %phi = phi double [%val, %region_true], [0.0, %region_verytrue]
+      store double %phi, double* %A
+      br label %region_exit
+
+    region_exit:
+      br label %inc
+
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/notredundant_region_loop.ll b/final/test/Simplify/notredundant_region_loop.ll
new file mode 100644
index 0000000..c8b7ee5
--- /dev/null
+++ b/final/test/Simplify/notredundant_region_loop.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-allow-nonaffine-loops -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Do not remove the store in region_entry. It can be executed multiple times
+; due to being part of a non-affine loop.
+;
+define void @notredundant_region_loop(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+
+    body:
+      %val = fadd double 21.0, 21.0
+      br label %region_entry
+
+    region_entry:
+      store double %val, double* %A
+      %sqr = mul i32 %j, %j
+      %cmp = icmp eq i32 %sqr, 42
+      br i1 %cmp, label %region_true, label %region_exit
+
+    region_true:
+      store double 0.0, double* %A
+      br label %region_entry
+
+    region_exit:
+      br label %inc
+
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/notredundant_region_loop___%for---%return.jscop b/final/test/Simplify/notredundant_region_loop___%for---%return.jscop
new file mode 100644
index 0000000..b86534e
--- /dev/null
+++ b/final/test/Simplify/notredundant_region_loop___%for---%return.jscop
@@ -0,0 +1,43 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_val[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_region_entry__TO__region_exit",
+         "schedule" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/notredundant_region_loop___%for---%return.jscop.transformed b/final/test/Simplify/notredundant_region_loop___%for---%return.jscop.transformed
new file mode 100644
index 0000000..9fe65e9
--- /dev/null
+++ b/final/test/Simplify/notredundant_region_loop___%for---%return.jscop.transformed
@@ -0,0 +1,43 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_region_entry__TO__region_exit",
+         "schedule" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/notredundant_region_middle.ll b/final/test/Simplify/notredundant_region_middle.ll
new file mode 100644
index 0000000..e42e60b
--- /dev/null
+++ b/final/test/Simplify/notredundant_region_middle.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Do not remove redundant stores in the middle of region statements.
+; The store in region_true could be removed, but in practice we do try to
+; determine the relative ordering of block in region statements.
+;
+; for (int j = 0; j < n; j += 1) {
+;   double val = A[0];
+;   if (val == 0.0)
+;     A[0] = val;
+;   else
+;     A[0] = 0.0;
+; }
+;
+define void @notredundant_region(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %region_entry, label %exit
+
+
+    region_entry:
+      %val = load double, double* %A
+      %cmp = fcmp oeq double %val, 0.0
+      br i1 %cmp, label %region_true, label %region_false
+
+    region_true:
+      store double %val, double* %A
+      br label %region_exit
+
+    region_false:
+      store double 0.0, double* %A
+      br label %region_exit
+
+    region_exit:
+      br label %inc
+
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/notredundant_synthesizable_unknownit.ll b/final/test/Simplify/notredundant_synthesizable_unknownit.ll
new file mode 100644
index 0000000..4dc33de
--- /dev/null
+++ b/final/test/Simplify/notredundant_synthesizable_unknownit.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Do not remove the scalar value write of %i.trunc in inner.for.
+; It is used by body.
+; %i.trunc is synthesizable in inner.for, so some code might think it is
+; synthesizable everywhere such that no scalar write would be needed.
+;
+; Note that -polly-simplify rightfully removes %inner.cond. It should
+; not have been added to the instruction list in the first place.
+;
+define void @func(i32 %n, i32* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  %zero = sext i32 0 to i64
+  br i1 %j.cmp, label %inner.for, label %exit
+
+
+    ; This loop has some unusual properties:
+    ; * It has a known iteration count (8), therefore SCoP-compatible.
+    ; * %i.trunc is synthesizable within the loop ({1,+,1}<%while.body>).
+    ; * %i.trunc is not synthesizable outside of the loop, because its value is
+    ;   unknown when exiting.
+    ;   (should be 8, but ScalarEvolution currently seems unable to derive that)
+    ;
+    ; ScalarEvolution currently seems to not able to handle the %zero.
+    ; If it becomes more intelligent, there might be other such loop constructs.
+    inner.for:
+      %i = phi i64 [%zero, %for], [%i.inc, %inner.for]
+      %i.inc = add nuw nsw i64 %i, 1
+      %i.trunc = trunc i64 %i.inc to i32
+      %i.and = and i32 %i.trunc, 7
+      %inner.cond = icmp eq i32 %i.and, 0
+      br i1 %inner.cond, label %body, label %inner.for
+
+    body:
+      store i32 %i.trunc, i32* %A
+      br label %inc
+
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_inner_for
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_inner_for[i0, i1] -> MemRef_i_trunc[] };
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_i_trunc[] };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/out-of-scop-use-in-region-entry-phi-node.ll b/final/test/Simplify/out-of-scop-use-in-region-entry-phi-node.ll
new file mode 100644
index 0000000..d41810d
--- /dev/null
+++ b/final/test/Simplify/out-of-scop-use-in-region-entry-phi-node.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-scops -polly-simplify -analyze < %s | FileCheck %s
+;
+; %tmp5 must keep the Value WRITE MemoryAccess, because as an incoming value of
+; %tmp4, it is an "external use".
+;
+; A common mistake is to assume that %tmp5 is used by %tmp4 in bb3, when
+; practially it's the incoming block %bb9 which is the user.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @hoge() {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb
+  %tmp = load i64*, i64** undef
+  br label %bb3
+
+bb3:                                              ; preds = %bb9, %bb2
+  %tmp4 = phi i64* [ %tmp, %bb2 ], [ %tmp5, %bb9 ]
+  %tmp5 = getelementptr inbounds i64, i64* %tmp4, i64 1
+  %tmp6 = load i64, i64* %tmp5
+  %tmp7 = and i64 %tmp6, 4160749568
+  br i1 false, label %bb8, label %bb9
+
+bb8:                                              ; preds = %bb3
+  br label %bb9
+
+bb9:                                              ; preds = %bb8, %bb3
+  %tmp10 = icmp eq i64 %tmp7, 134217728
+  br i1 %tmp10, label %bb11, label %bb3
+
+bb11:                                             ; preds = %bb9
+  br label %bb12
+
+bb12:                                             ; preds = %bb11
+  ret void
+}
+
+
+; CHECK:      MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:     [p_0] -> { Stmt_bb3[] -> MemRef_tmp5[] };
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/overwritten.ll b/final/test/Simplify/overwritten.ll
new file mode 100644
index 0000000..55d59b3
--- /dev/null
+++ b/final/test/Simplify/overwritten.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck -match-full-lines %s 
+;
+; Remove a store that is overwritten by another store in the same statement.
+;
+; for (int j = 0; j < n; j += 1) {
+;   A[0] = 21.0;
+;   A[0] = 42.0;
+; }
+;
+define void @overwritten(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 21.0, double* %A
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Overwrites removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/overwritten_3phi.ll b/final/test/Simplify/overwritten_3phi.ll
new file mode 100644
index 0000000..1651437
--- /dev/null
+++ b/final/test/Simplify/overwritten_3phi.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Remove identical writes
+; (two stores in the same statement that write the same value to the same
+; destination)
+;
+; for (int j = 0; j < n; j += 1) {
+; body:
+;   val = 21.0 + 21.0;
+;   A[1] = val;
+;   A[1] = val;
+;   A[1] = val;
+;
+; user:
+;   A[0] = A[1];
+; }
+;
+define void @overwritten_3phi(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = fadd double 21.0, 21.0
+      br label %user
+
+    user:
+      %phi1 = phi double [%val, %body]
+      %phi2 = phi double [%val, %body]
+      %phi3 = phi double [%val, %body]
+      %add1 = fadd double %phi1, %phi2
+      %add2 = fadd double %add1, %phi3
+      store double %add2, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+
+; CHECK: Statistics {
+; CHECK:     Overwrites removed: 2
+; CHECK: }
+
+; CHECK:      Stmt_body
+; CHECK-NEXT:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [n] -> { Stmt_body[i0] -> MemRef_phi3__phi[] };
+; CHECK-NEXT:        new: [n] -> { Stmt_body[i0] -> MemRef_A[1] };
+; CHECK-NEXT: Stmt_user
diff --git a/final/test/Simplify/overwritten_3phi___%for---%return.jscop b/final/test/Simplify/overwritten_3phi___%for---%return.jscop
new file mode 100644
index 0000000..af26b0a
--- /dev/null
+++ b/final/test/Simplify/overwritten_3phi___%for---%return.jscop
@@ -0,0 +1,55 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_phi1__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_phi2__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_phi3__phi[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_phi1__phi[] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_phi2__phi[] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_phi3__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/overwritten_3phi___%for---%return.jscop.transformed b/final/test/Simplify/overwritten_3phi___%for---%return.jscop.transformed
new file mode 100644
index 0000000..ddd9279
--- /dev/null
+++ b/final/test/Simplify/overwritten_3phi___%for---%return.jscop.transformed
@@ -0,0 +1,55 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/overwritten_3store.ll b/final/test/Simplify/overwritten_3store.ll
new file mode 100644
index 0000000..133a347
--- /dev/null
+++ b/final/test/Simplify/overwritten_3store.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck -match-full-lines %s 
+;
+; Remove a store that is overwritten by another store in the same statement.
+; Check that even multiple stores are removed.
+;
+; for (int j = 0; j < n; j += 1) {
+;   A[0] = 10.5;
+;   A[0] = 21.0;
+;   A[0] = 42.0;
+; }
+;
+define void @overwritten_3store(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 10.5, double* %A
+      store double 21.0, double* %A
+      store double 42.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Overwrites removed: 2
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/overwritten_implicit_and_explicit.ll b/final/test/Simplify/overwritten_implicit_and_explicit.ll
new file mode 100644
index 0000000..852bc21
--- /dev/null
+++ b/final/test/Simplify/overwritten_implicit_and_explicit.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Remove a store that is overwritten by another store in the same statement.
+; Check that this works even if one of the writes is a scalar MemoryKind.
+;
+; for (int j = 0; j < n; j += 1) {
+; body:
+;   val = 21.0 + 21.0;
+;   A[1] = val;
+;
+; user:
+;   A[0] = val;
+; }
+;
+define void @overwritten_implicit_and_explicit(i32 %n, double* noalias nonnull %A, double* noalias nonnull %C) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = fadd double 21.0, 21.0
+      store double %val, double* %A
+      br label %user
+
+    user:
+      store double %val, double* %C
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Overwrites removed: 1
+; CHECK: }
+
+; CHECK:          Stmt_body
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_body[i0] -> MemRef_val[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_body[i0] -> MemRef_A[0] };
+; CHECK-NEXT:     Stmt_user
diff --git a/final/test/Simplify/overwritten_implicit_and_explicit___%for---%return.jscop b/final/test/Simplify/overwritten_implicit_and_explicit___%for---%return.jscop
new file mode 100644
index 0000000..7ea3ca2
--- /dev/null
+++ b/final/test/Simplify/overwritten_implicit_and_explicit___%for---%return.jscop
@@ -0,0 +1,48 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_C[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/overwritten_implicit_and_explicit___%for---%return.jscop.transformed b/final/test/Simplify/overwritten_implicit_and_explicit___%for---%return.jscop.transformed
new file mode 100644
index 0000000..b49747d
--- /dev/null
+++ b/final/test/Simplify/overwritten_implicit_and_explicit___%for---%return.jscop.transformed
@@ -0,0 +1,48 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_C",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] ->  MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_C[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/overwritten_loadbetween.ll b/final/test/Simplify/overwritten_loadbetween.ll
new file mode 100644
index 0000000..c06263e
--- /dev/null
+++ b/final/test/Simplify/overwritten_loadbetween.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck -match-full-lines %s 
+;
+; Do not remove overwrites when the value is read before.
+;
+; for (int j = 0; j < n; j += 1) {
+;body:
+;   A[0] = 21.0;
+;   val = A[0];
+;   A[0] = 42.0;
+;
+;user:
+;   B[0] = val;
+; }
+;
+define void @overwritten(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 21.0, double* %A
+      %val = load double, double* %A
+      store double 42.0, double* %A
+      br label %user
+
+    user:
+      store double %val, double* %B
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/overwritten_scalar.ll b/final/test/Simplify/overwritten_scalar.ll
new file mode 100644
index 0000000..eac287a
--- /dev/null
+++ b/final/test/Simplify/overwritten_scalar.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck -match-full-lines %s
+;
+; Remove identical writes
+; (two stores in the same statement that write the same value to the same
+; destination)
+;
+; for (int j = 0; j < n; j += 1) {
+; body:
+;   val = 21.0 + 21.0;
+;   A[1] = val;
+;   A[1] = val;
+;
+; user:
+;   A[0] = A[1];
+; }
+;
+define void @overwritten_scalar(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = fadd double 21.0, 21.0
+      br label %user
+
+    user:
+      %phi = phi double [%val, %body]
+      %add = fadd double %val, %phi
+      store double %add, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Overwrites removed: 1
+; CHECK: }
+
+; CHECK:      Stmt_body
+; CHECK-NEXT:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:            [n] -> { Stmt_body[i0] ->  MemRef_val[] };
+; CHECK-NEXT:       new: [n] -> { Stmt_body[i0] -> MemRef_A[1] };
+; CHECK-NEXT: Stmt_user
diff --git a/final/test/Simplify/overwritten_scalar___%for---%return.jscop b/final/test/Simplify/overwritten_scalar___%for---%return.jscop
new file mode 100644
index 0000000..248afa8
--- /dev/null
+++ b/final/test/Simplify/overwritten_scalar___%for---%return.jscop
@@ -0,0 +1,47 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_phi__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_phi__phi[] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_val[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/overwritten_scalar___%for---%return.jscop.transformed b/final/test/Simplify/overwritten_scalar___%for---%return.jscop.transformed
new file mode 100644
index 0000000..25beb61
--- /dev/null
+++ b/final/test/Simplify/overwritten_scalar___%for---%return.jscop.transformed
@@ -0,0 +1,47 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[1] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_user[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_user[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_user",
+         "schedule" : "[n] -> { Stmt_user[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/pass_existence.ll b/final/test/Simplify/pass_existence.ll
new file mode 100644
index 0000000..833504d
--- /dev/null
+++ b/final/test/Simplify/pass_existence.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s
+;
+; Simple test for the existence of the Simplify pass.
+;
+; for (int j = 0; j < n; j += 1)
+;   A[0] = 0.0;
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 0.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/phi_in_regionstmt.ll b/final/test/Simplify/phi_in_regionstmt.ll
new file mode 100644
index 0000000..4127e87
--- /dev/null
+++ b/final/test/Simplify/phi_in_regionstmt.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; The PHINode %cond91.sink.sink.us.sink.6 is in the middle of a region
+; statement.
+; Check that we are not expect a MemoryKind::PHI access for it, and no
+; assertion guarding querying for it.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.pic_parameter_set_rbsp_t.3.45.87.129.192.255.465.927.969.990.1029 = type { i32, i32, i32, i32, i32, i32, [8 x i32], [6 x [16 x i32]], [2 x [64 x i32]], [6 x i32], [2 x i32], i32, i32, i32, [8 x i32], [8 x i32], [8 x i32], i32, i32, i32, i32*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }
+
+@quant8_intra_default = external global [64 x i32], align 16
+@quant_org = external global [16 x i32], align 16
+@qmatrix = external local_unnamed_addr global [8 x i32*], align 16
+
+; Function Attrs: nounwind uwtable
+define void @AssignQuantParam(%struct.pic_parameter_set_rbsp_t.3.45.87.129.192.255.465.927.969.990.1029* %pps) local_unnamed_addr #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  %pic_scaling_matrix_present_flag = getelementptr inbounds %struct.pic_parameter_set_rbsp_t.3.45.87.129.192.255.465.927.969.990.1029, %struct.pic_parameter_set_rbsp_t.3.45.87.129.192.255.465.927.969.990.1029* %pps, i64 0, i32 5
+  %0 = load i32, i32* %pic_scaling_matrix_present_flag, align 4, !tbaa !1
+  %tobool = icmp eq i32 %0, 0
+  br i1 %tobool, label %land.lhs.true, label %if.else
+
+land.lhs.true:                                    ; preds = %entry.split
+  store i32* getelementptr inbounds ([16 x i32], [16 x i32]* @quant_org, i64 0, i64 0), i32** getelementptr inbounds ([8 x i32*], [8 x i32*]* @qmatrix, i64 0, i64 4), align 16, !tbaa !7
+  br label %if.end161
+
+if.else:                                          ; preds = %entry.split
+  br label %if.else121.us.6
+
+if.end161:                                        ; preds = %if.else121.us.7, %land.lhs.true
+  ret void
+
+if.else121.us.6:                                  ; preds = %if.else
+  %arrayidx80.us.6 = getelementptr inbounds %struct.pic_parameter_set_rbsp_t.3.45.87.129.192.255.465.927.969.990.1029, %struct.pic_parameter_set_rbsp_t.3.45.87.129.192.255.465.927.969.990.1029* %pps, i64 0, i32 6, i64 6
+  br i1 false, label %if.else121.us.7, label %if.else135.us.6
+
+if.else135.us.6:                                  ; preds = %if.else121.us.6
+  br label %if.else121.us.7
+
+if.else121.us.7:                                  ; preds = %if.else135.us.6, %if.else121.us.6
+  %cond91.sink.sink.us.sink.6 = phi i32* [ undef, %if.else135.us.6 ], [ getelementptr inbounds ([64 x i32], [64 x i32]* @quant8_intra_default, i64 0, i64 0), %if.else121.us.6 ]
+  br label %if.end161
+}
+
+attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 6.0.0 (trunk 308961)"}
+!1 = !{!2, !3, i64 20}
+!2 = !{!"", !3, i64 0, !5, i64 4, !5, i64 8, !3, i64 12, !3, i64 16, !3, i64 20, !3, i64 24, !3, i64 56, !3, i64 440, !3, i64 952, !3, i64 976, !3, i64 984, !5, i64 988, !5, i64 992, !3, i64 996, !3, i64 1028, !3, i64 1060, !3, i64 1092, !5, i64 1096, !5, i64 1100, !6, i64 1104, !5, i64 1112, !5, i64 1116, !3, i64 1120, !5, i64 1124, !5, i64 1128, !5, i64 1132, !5, i64 1136, !5, i64 1140, !3, i64 1144, !3, i64 1148, !3, i64 1152}
+!3 = !{!"omnipotent char", !4, i64 0}
+!4 = !{!"Simple C/C++ TBAA"}
+!5 = !{!"int", !3, i64 0}
+!6 = !{!"any pointer", !3, i64 0}
+!7 = !{!6, !6, i64 0}
+
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/pr33323.ll b/final/test/Simplify/pr33323.ll
new file mode 100644
index 0000000..9c55ea6
--- /dev/null
+++ b/final/test/Simplify/pr33323.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck %s
+;
+; llvm.org/PR33323
+;
+; Do not remove the pair (store double %add119, read %add119) as redundant
+; because the are in the wrong order.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define fastcc void @pr33323([1000 x double]* nocapture %data, [1000 x double]* nocapture %symmat) {
+entry:
+  br label %for.body98
+
+for.cond87.loopexit:
+  ret void
+
+for.body98:
+  %indvars.iv13 = phi i64 [ 1, %entry ], [ %indvars.iv.next14, %for.end122 ]
+  br label %for.body105
+
+for.body105:
+  %indvars.iv = phi i64 [ 0, %for.body98 ], [ %indvars.iv.next, %for.body105 ]
+  %arrayidx109 = getelementptr inbounds [1000 x double], [1000 x double]* %data, i64 %indvars.iv, i64 0
+  %add119 = fadd double undef, undef
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, 1000
+  br i1 %exitcond, label %for.end122, label %for.body105
+
+for.end122:
+  %arrayidx130 = getelementptr inbounds [1000 x double], [1000 x double]* %symmat, i64 %indvars.iv13, i64 0
+  store double %add119, double* %arrayidx130
+  %indvars.iv.next14 = add nuw nsw i64 %indvars.iv13, 1
+  %exitcond15 = icmp eq i64 %indvars.iv.next14, 1000
+  br i1 %exitcond15, label %for.cond87.loopexit, label %for.body98
+}
+
+
+; CHECK: Statistics {
+; CHECK:    Redundant writes removed: 1
+; CHECK:    Stmts removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_for_body105
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 { Stmt_for_body105[i0, i1] -> MemRef_add119[] };
+; CHECK-NEXT:            new: { Stmt_for_body105[i0, i1] -> MemRef_symmat[1 + i0, 0] };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/pr33323___%for.body98---%for.cond87.loopexit.jscop b/final/test/Simplify/pr33323___%for.body98---%for.cond87.loopexit.jscop
new file mode 100644
index 0000000..34b5d43
--- /dev/null
+++ b/final/test/Simplify/pr33323___%for.body98---%for.cond87.loopexit.jscop
@@ -0,0 +1,39 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_symmat",
+         "sizes" : [ "*", "1000" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.body98---%for.cond87.loopexit",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body105[i0, i1] -> MemRef_add119[] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body105[i0, i1] : 0 <= i0 <= 998 and 0 <= i1 <= 999 }",
+         "name" : "Stmt_for_body105",
+         "schedule" : "{ Stmt_for_body105[i0, i1] -> [i0, 0, i1] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_end122[i0] -> MemRef_symmat[1 + i0, 0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_end122[i0] -> MemRef_add119[] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_end122[i0] : 0 <= i0 <= 998 }",
+         "name" : "Stmt_for_end122",
+         "schedule" : "{ Stmt_for_end122[i0] -> [i0, 1, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/pr33323___%for.body98---%for.cond87.loopexit.jscop.transformed b/final/test/Simplify/pr33323___%for.body98---%for.cond87.loopexit.jscop.transformed
new file mode 100644
index 0000000..c3a7788
--- /dev/null
+++ b/final/test/Simplify/pr33323___%for.body98---%for.cond87.loopexit.jscop.transformed
@@ -0,0 +1,39 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_symmat",
+         "sizes" : [ "*", "1000" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "{  :  }",
+   "name" : "%for.body98---%for.cond87.loopexit",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body105[i0, i1] -> MemRef_symmat[1 + i0, 0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body105[i0, i1] : 0 <= i0 <= 998 and 0 <= i1 <= 999 }",
+         "name" : "Stmt_for_body105",
+         "schedule" : "{ Stmt_for_body105[i0, i1] -> [i0, 0, i1] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_end122[i0] -> MemRef_symmat[1 + i0, 0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_end122[i0] -> MemRef_symmat[1 + i0, 0] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_end122[i0] : 0 <= i0 <= 998 }",
+         "name" : "Stmt_for_end122",
+         "schedule" : "{ Stmt_for_end122[i0] -> [i0, 1, 0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/redundant.ll b/final/test/Simplify/redundant.ll
new file mode 100644
index 0000000..b3d8647
--- /dev/null
+++ b/final/test/Simplify/redundant.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Remove redundant store (a store that writes the same value already
+; at the destination)
+;
+; for (int j = 0; j < n; j += 1)
+;   A[0] = A[0];
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = load double, double* %A
+      store double %val, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Redundant writes removed: 1
+; CHECK:     Stmts removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/redundant_differentindex.ll b/final/test/Simplify/redundant_differentindex.ll
new file mode 100644
index 0000000..3a5e073
--- /dev/null
+++ b/final/test/Simplify/redundant_differentindex.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; A store that has a different index than the load it is storing is
+; not redundant.
+;
+; for (int j = 0; j < n; j += 1)
+;   A[0] = A[0];
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = load double, double* %A
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/redundant_partialwrite.ll b/final/test/Simplify/redundant_partialwrite.ll
new file mode 100644
index 0000000..71c27bd
--- /dev/null
+++ b/final/test/Simplify/redundant_partialwrite.ll
@@ -0,0 +1,40 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Remove a redundant store, if its partial domain is a subset of the
+; read's domain.
+;
+define void @redundant_partialwrite(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = load double, double* %A
+      store double %val, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; Check successful import.
+; CHECK:    new: [n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 <= 15 };
+
+; CHECK: Statistics {
+; CHECK:     Redundant writes removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/redundant_partialwrite___%for---%return.jscop b/final/test/Simplify/redundant_partialwrite___%for---%return.jscop
new file mode 100644
index 0000000..9869237
--- /dev/null
+++ b/final/test/Simplify/redundant_partialwrite___%for---%return.jscop
@@ -0,0 +1,28 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/redundant_partialwrite___%for---%return.jscop.transformed b/final/test/Simplify/redundant_partialwrite___%for---%return.jscop.transformed
new file mode 100644
index 0000000..38b730f
--- /dev/null
+++ b/final/test/Simplify/redundant_partialwrite___%for---%return.jscop.transformed
@@ -0,0 +1,28 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] : i0 < 16 }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/redundant_region.ll b/final/test/Simplify/redundant_region.ll
new file mode 100644
index 0000000..c006f4b
--- /dev/null
+++ b/final/test/Simplify/redundant_region.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Remove redundant store (a store that writes the same value already
+; at the destination) in a region.
+;
+define void @redundant_region(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %region_entry, label %exit
+
+
+    region_entry:
+      %val = load double, double* %A
+      %cmp = fcmp oeq double %val, 0.0
+      br i1 %cmp, label %region_true, label %region_exit
+
+    region_true:
+      br label %region_exit
+
+    region_exit:
+      br label %body
+
+    body:
+      store double %val, double* %A
+      br label %inc
+
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Redundant writes removed: 2
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/redundant_region___%for---%return.jscop b/final/test/Simplify/redundant_region___%for---%return.jscop
new file mode 100644
index 0000000..7517c3e
--- /dev/null
+++ b/final/test/Simplify/redundant_region___%for---%return.jscop
@@ -0,0 +1,43 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_region_entry__TO__region_exit",
+         "schedule" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/redundant_region___%for---%return.jscop.transformed b/final/test/Simplify/redundant_region___%for---%return.jscop.transformed
new file mode 100644
index 0000000..b416142
--- /dev/null
+++ b/final/test/Simplify/redundant_region___%for---%return.jscop.transformed
@@ -0,0 +1,43 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_region_entry__TO__region_exit",
+         "schedule" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_body[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_body[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_body",
+         "schedule" : "[n] -> { Stmt_body[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/redundant_region_scalar.ll b/final/test/Simplify/redundant_region_scalar.ll
new file mode 100644
index 0000000..495a4ba
--- /dev/null
+++ b/final/test/Simplify/redundant_region_scalar.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Remove redundant store (a store that writes the same value already
+; at the destination) in a region.
+;
+define void @redundant_region_scalar(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+
+    bodyA:
+      %val1 = load double, double* %A
+      br label %region_entry
+
+    region_entry:
+      %val2 = load double, double* %A
+      %cmp = fcmp oeq double %val1, 0.0
+      br i1 %cmp, label %region_true, label %region_exit
+
+    region_true:
+      br label %region_exit
+
+    region_exit:
+      br label %bodyB
+
+    bodyB:
+      store double %val2, double* %A
+      br label %inc
+
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Redundant writes removed: 3
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/redundant_region_scalar___%for---%return.jscop b/final/test/Simplify/redundant_region_scalar___%for---%return.jscop
new file mode 100644
index 0000000..7712c26
--- /dev/null
+++ b/final/test/Simplify/redundant_region_scalar___%for---%return.jscop
@@ -0,0 +1,62 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_val1[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyA[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyA",
+         "schedule" : "[n] -> { Stmt_bodyA[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_val1[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_val2[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_region_entry__TO__region_exit",
+         "schedule" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> [i0, 1] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_val2[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyB[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyB",
+         "schedule" : "[n] -> { Stmt_bodyB[i0] -> [i0, 2] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/redundant_region_scalar___%for---%return.jscop.transformed b/final/test/Simplify/redundant_region_scalar___%for---%return.jscop.transformed
new file mode 100644
index 0000000..9bb0e0c
--- /dev/null
+++ b/final/test/Simplify/redundant_region_scalar___%for---%return.jscop.transformed
@@ -0,0 +1,62 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyA[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyA",
+         "schedule" : "[n] -> { Stmt_bodyA[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_region_entry__TO__region_exit",
+         "schedule" : "[n] -> { Stmt_region_entry__TO__region_exit[i0] -> [i0, 1] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyB[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyB",
+         "schedule" : "[n] -> { Stmt_bodyB[i0] -> [i0, 2] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/redundant_scalarwrite.ll b/final/test/Simplify/redundant_scalarwrite.ll
new file mode 100644
index 0000000..c007194
--- /dev/null
+++ b/final/test/Simplify/redundant_scalarwrite.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Remove redundant scalar stores.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = A[0];
+;
+; bodyB:
+;   A[0] = val;
+; }
+;
+define void @redundant_scalarwrite(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+
+    bodyA:
+      %val = load double, double* %A
+      br label %bodyB
+
+    bodyB:
+      store double %val, double* %A
+      br label %inc
+
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Redundant writes removed: 2
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/redundant_scalarwrite___%for---%return.jscop b/final/test/Simplify/redundant_scalarwrite___%for---%return.jscop
new file mode 100644
index 0000000..689c0c1
--- /dev/null
+++ b/final/test/Simplify/redundant_scalarwrite___%for---%return.jscop
@@ -0,0 +1,43 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyA[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyA",
+         "schedule" : "[n] -> { Stmt_bodyA[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyB[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyB",
+         "schedule" : "[n] -> { Stmt_bodyB[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/redundant_scalarwrite___%for---%return.jscop.transformed b/final/test/Simplify/redundant_scalarwrite___%for---%return.jscop.transformed
new file mode 100644
index 0000000..c018352
--- /dev/null
+++ b/final/test/Simplify/redundant_scalarwrite___%for---%return.jscop.transformed
@@ -0,0 +1,43 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyA[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyA",
+         "schedule" : "[n] -> { Stmt_bodyA[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_A[0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_A[0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyB[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyB",
+         "schedule" : "[n] -> { Stmt_bodyB[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/redundant_storebetween.ll b/final/test/Simplify/redundant_storebetween.ll
new file mode 100644
index 0000000..5e1befc
--- /dev/null
+++ b/final/test/Simplify/redundant_storebetween.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Don't remove store where there is another store to the same target
+; in-between them.
+;
+; for (int j = 0; j < n; j += 1)
+;   A[0] = A[0];
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %val = load double, double* %A_idx
+      store double 0.0, double* %A
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
+
diff --git a/final/test/Simplify/scalability1.ll b/final/test/Simplify/scalability1.ll
new file mode 100644
index 0000000..65f6a79
--- /dev/null
+++ b/final/test/Simplify/scalability1.ll
@@ -0,0 +1,104 @@
+; RUN: opt %loadPolly -polly-ignore-inbounds -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Test scalability.
+;
+define void @func(i32 %n, double* noalias nonnull %A,
+i32 %p0, i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5, i32 %p6, i32 %p7, i32 %p8, i32 %p9,
+i32 %p10, i32 %p11, i32 %p12, i32 %p13, i32 %p14, i32 %p15, i32 %p16, i32 %p17, i32 %p18, i32 %p19,
+i32 %p20, i32 %p21, i32 %p22, i32 %p23, i32 %p24, i32 %p25, i32 %p26, i32 %p27, i32 %p28, i32 %p29,
+i32 %p30, i32 %p31, i32 %p32) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+
+    body:
+      %A0 = getelementptr inbounds double, double* %A, i32 %p0
+      %A1 = getelementptr inbounds double, double* %A, i32 %p1
+      %A2 = getelementptr inbounds double, double* %A, i32 %p2
+      %A3 = getelementptr inbounds double, double* %A, i32 %p3
+      %A4 = getelementptr inbounds double, double* %A, i32 %p4
+      %A5 = getelementptr inbounds double, double* %A, i32 %p5
+      %A6 = getelementptr inbounds double, double* %A, i32 %p6
+      %A7 = getelementptr inbounds double, double* %A, i32 %p7
+      %A8 = getelementptr inbounds double, double* %A, i32 %p8
+      %A9 = getelementptr inbounds double, double* %A, i32 %p9
+      %A10 = getelementptr inbounds double, double* %A, i32 %p10
+      %A11 = getelementptr inbounds double, double* %A, i32 %p11
+      %A12 = getelementptr inbounds double, double* %A, i32 %p12
+      %A13 = getelementptr inbounds double, double* %A, i32 %p13
+      %A14 = getelementptr inbounds double, double* %A, i32 %p14
+      %A15 = getelementptr inbounds double, double* %A, i32 %p15
+      %A16 = getelementptr inbounds double, double* %A, i32 %p16
+      %A17 = getelementptr inbounds double, double* %A, i32 %p17
+      %A18 = getelementptr inbounds double, double* %A, i32 %p18
+      %A19 = getelementptr inbounds double, double* %A, i32 %p19
+      %A20 = getelementptr inbounds double, double* %A, i32 %p20
+      %A21 = getelementptr inbounds double, double* %A, i32 %p21
+      %A22 = getelementptr inbounds double, double* %A, i32 %p22
+      %A23 = getelementptr inbounds double, double* %A, i32 %p23
+      %A24 = getelementptr inbounds double, double* %A, i32 %p24
+      %A25 = getelementptr inbounds double, double* %A, i32 %p25
+      %A26 = getelementptr inbounds double, double* %A, i32 %p26
+      %A27 = getelementptr inbounds double, double* %A, i32 %p27
+      %A28 = getelementptr inbounds double, double* %A, i32 %p28
+      %A29 = getelementptr inbounds double, double* %A, i32 %p29
+      %A30 = getelementptr inbounds double, double* %A, i32 %p30
+      %A31 = getelementptr inbounds double, double* %A, i32 %p31
+      %A32 = getelementptr inbounds double, double* %A, i32 %p32
+
+      %val = load double, double* %A0
+
+      store double %val, double* %A1
+      store double %val, double* %A2
+      store double %val, double* %A3
+      store double %val, double* %A4
+      store double %val, double* %A5
+      store double %val, double* %A6
+      store double %val, double* %A7
+      store double %val, double* %A8
+      store double %val, double* %A9
+      store double %val, double* %A10
+      store double %val, double* %A11
+      store double %val, double* %A12
+      store double %val, double* %A13
+      store double %val, double* %A14
+      store double %val, double* %A15
+      store double %val, double* %A16
+      store double %val, double* %A17
+      store double %val, double* %A18
+      store double %val, double* %A19
+      store double %val, double* %A20
+      store double %val, double* %A21
+      store double %val, double* %A22
+      store double %val, double* %A23
+      store double %val, double* %A24
+      store double %val, double* %A25
+      store double %val, double* %A26
+      store double %val, double* %A27
+      store double %val, double* %A28
+      store double %val, double* %A29
+      store double %val, double* %A30
+      store double %val, double* %A31
+      store double %val, double* %A32
+
+      br label %inc
+
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/scalability2.ll b/final/test/Simplify/scalability2.ll
new file mode 100644
index 0000000..e669ec8
--- /dev/null
+++ b/final/test/Simplify/scalability2.ll
@@ -0,0 +1,188 @@
+; RUN: opt %loadPolly -polly-ignore-inbounds -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Test scalability.
+;
+define void @func(i32 %n, double* noalias nonnull %A,
+i32 %p0, i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5, i32 %p6, i32 %p7, i32 %p8, i32 %p9,
+i32 %p10, i32 %p11, i32 %p12, i32 %p13, i32 %p14, i32 %p15, i32 %p16, i32 %p17, i32 %p18, i32 %p19,
+i32 %p20, i32 %p21, i32 %p22, i32 %p23, i32 %p24, i32 %p25, i32 %p26, i32 %p27, i32 %p28, i32 %p29,
+i32 %p30, i32 %p31, i32 %p32, i32 %p33, i32 %p34, i32 %p35, i32 %p36, i32 %p37, i32 %p38, i32 %p39,
+i32 %p40, i32 %p41, i32 %p42, i32 %p43, i32 %p44, i32 %p45, i32 %p46, i32 %p47, i32 %p48, i32 %p49,
+i32 %p50, i32 %p51, i32 %p52, i32 %p53, i32 %p54, i32 %p55, i32 %p56, i32 %p57, i32 %p58, i32 %p59) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+
+    body:
+      %A0 = getelementptr inbounds double, double* %A, i32 %p0
+      %A1 = getelementptr inbounds double, double* %A, i32 %p1
+      %A2 = getelementptr inbounds double, double* %A, i32 %p2
+      %A3 = getelementptr inbounds double, double* %A, i32 %p3
+      %A4 = getelementptr inbounds double, double* %A, i32 %p4
+      %A5 = getelementptr inbounds double, double* %A, i32 %p5
+      %A6 = getelementptr inbounds double, double* %A, i32 %p6
+      %A7 = getelementptr inbounds double, double* %A, i32 %p7
+      %A8 = getelementptr inbounds double, double* %A, i32 %p8
+      %A9 = getelementptr inbounds double, double* %A, i32 %p9
+      %A10 = getelementptr inbounds double, double* %A, i32 %p10
+      %A11 = getelementptr inbounds double, double* %A, i32 %p11
+      %A12 = getelementptr inbounds double, double* %A, i32 %p12
+      %A13 = getelementptr inbounds double, double* %A, i32 %p13
+      %A14 = getelementptr inbounds double, double* %A, i32 %p14
+      %A15 = getelementptr inbounds double, double* %A, i32 %p15
+      %A16 = getelementptr inbounds double, double* %A, i32 %p16
+      %A17 = getelementptr inbounds double, double* %A, i32 %p17
+      %A18 = getelementptr inbounds double, double* %A, i32 %p18
+      %A19 = getelementptr inbounds double, double* %A, i32 %p19
+      %A20 = getelementptr inbounds double, double* %A, i32 %p20
+      %A21 = getelementptr inbounds double, double* %A, i32 %p21
+      %A22 = getelementptr inbounds double, double* %A, i32 %p22
+      %A23 = getelementptr inbounds double, double* %A, i32 %p23
+      %A24 = getelementptr inbounds double, double* %A, i32 %p24
+      %A25 = getelementptr inbounds double, double* %A, i32 %p25
+      %A26 = getelementptr inbounds double, double* %A, i32 %p26
+      %A27 = getelementptr inbounds double, double* %A, i32 %p27
+      %A28 = getelementptr inbounds double, double* %A, i32 %p28
+      %A29 = getelementptr inbounds double, double* %A, i32 %p29
+      %A30 = getelementptr inbounds double, double* %A, i32 %p30
+      %A31 = getelementptr inbounds double, double* %A, i32 %p31
+      %A32 = getelementptr inbounds double, double* %A, i32 %p32
+      %A33 = getelementptr inbounds double, double* %A, i32 %p33
+      %A34 = getelementptr inbounds double, double* %A, i32 %p34
+      %A35 = getelementptr inbounds double, double* %A, i32 %p35
+      %A36 = getelementptr inbounds double, double* %A, i32 %p36
+      %A37 = getelementptr inbounds double, double* %A, i32 %p37
+      %A38 = getelementptr inbounds double, double* %A, i32 %p38
+      %A39 = getelementptr inbounds double, double* %A, i32 %p39
+      %A40 = getelementptr inbounds double, double* %A, i32 %p40
+      %A41 = getelementptr inbounds double, double* %A, i32 %p41
+      %A42 = getelementptr inbounds double, double* %A, i32 %p42
+      %A43 = getelementptr inbounds double, double* %A, i32 %p43
+      %A44 = getelementptr inbounds double, double* %A, i32 %p44
+      %A45 = getelementptr inbounds double, double* %A, i32 %p45
+      %A46 = getelementptr inbounds double, double* %A, i32 %p46
+      %A47 = getelementptr inbounds double, double* %A, i32 %p47
+      %A48 = getelementptr inbounds double, double* %A, i32 %p48
+      %A49 = getelementptr inbounds double, double* %A, i32 %p49
+      %A50 = getelementptr inbounds double, double* %A, i32 %p50
+      %A51 = getelementptr inbounds double, double* %A, i32 %p51
+      %A52 = getelementptr inbounds double, double* %A, i32 %p52
+      %A53 = getelementptr inbounds double, double* %A, i32 %p53
+      %A54 = getelementptr inbounds double, double* %A, i32 %p54
+      %A55 = getelementptr inbounds double, double* %A, i32 %p55
+      %A56 = getelementptr inbounds double, double* %A, i32 %p56
+      %A57 = getelementptr inbounds double, double* %A, i32 %p57
+      %A58 = getelementptr inbounds double, double* %A, i32 %p58
+      %A59 = getelementptr inbounds double, double* %A, i32 %p59
+
+      %val0 = load double, double* %A0
+      store double %val0, double* %A1
+
+      %val2 = load double, double* %A2
+      store double %val2, double* %A3
+
+      %val4 = load double, double* %A4
+      store double %val4, double* %A5
+
+      %val6 = load double, double* %A6
+      store double %val6, double* %A7
+
+      %val8 = load double, double* %A8
+      store double %val8, double* %A9
+
+      %val10 = load double, double* %A10
+      store double %val10, double* %A11
+
+      %val12 = load double, double* %A12
+      store double %val12, double* %A13
+
+      %val13 = load double, double* %A13
+      store double %val13, double* %A15
+
+      %val16 = load double, double* %A16
+      store double %val16, double* %A17
+
+      %val18 = load double, double* %A18
+      store double %val18, double* %A19
+
+      %val20 = load double, double* %A20
+      store double %val20, double* %A21
+
+      %val22 = load double, double* %A22
+      store double %val22, double* %A23
+
+      %val24 = load double, double* %A24
+      store double %val24, double* %A25
+
+      %val26 = load double, double* %A26
+      store double %val26, double* %A27
+
+      %val28 = load double, double* %A28
+      store double %val28, double* %A29
+
+      %val30 = load double, double* %A30
+      store double %val30, double* %A31
+
+      %val32 = load double, double* %A32
+      store double %val32, double* %A33
+
+      %val34 = load double, double* %A34
+      store double %val34, double* %A35
+
+      %val36 = load double, double* %A36
+      store double %val36, double* %A37
+
+      %val38 = load double, double* %A38
+      store double %val38, double* %A39
+
+      %val40 = load double, double* %A40
+      store double %val40, double* %A41
+
+      %val42 = load double, double* %A42
+      store double %val42, double* %A43
+
+      %val44 = load double, double* %A44
+      store double %val44, double* %A45
+
+      %val46 = load double, double* %A46
+      store double %val46, double* %A47
+
+      %val48 = load double, double* %A48
+      store double %val48, double* %A49
+
+      %val50 = load double, double* %A50
+      store double %val50, double* %A51
+
+      %val52 = load double, double* %A52
+      store double %val52, double* %A53
+
+      %val54 = load double, double* %A54
+      store double %val54, double* %A55
+
+      %val56 = load double, double* %A56
+      store double %val56, double* %A57
+
+      %val58 = load double, double* %A58
+      store double %val58, double* %A59
+
+      br label %inc
+
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
diff --git a/final/test/Simplify/sweep_mapped_phi.ll b/final/test/Simplify/sweep_mapped_phi.ll
new file mode 100644
index 0000000..4491d43
--- /dev/null
+++ b/final/test/Simplify/sweep_mapped_phi.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Map %phi to A[j], so the scalar write in Stmt_for_bodyA can be removed.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   val = 21.0 + 21.0;
+;   A[j] = val;
+;
+; bodyB:
+;   B[j] = val;
+; }
+;
+
+define void @sweep_mapped_phi(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val = fadd double 21.0, 21.0
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %bodyB
+
+    bodyB:
+      %phi = phi double [%val, %bodyA]
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      store double %phi, double* %B_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Dead accesses removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/sweep_mapped_phi___%for---%return.jscop b/final/test/Simplify/sweep_mapped_phi___%for---%return.jscop
new file mode 100644
index 0000000..0d2e0dd
--- /dev/null
+++ b/final/test/Simplify/sweep_mapped_phi___%for---%return.jscop
@@ -0,0 +1,48 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_phi__phi[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyA[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyA",
+         "schedule" : "[n] -> { Stmt_bodyA[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_phi__phi[] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyB[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyB",
+         "schedule" : "[n] -> { Stmt_bodyB[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/sweep_mapped_phi___%for---%return.jscop.transformed b/final/test/Simplify/sweep_mapped_phi___%for---%return.jscop.transformed
new file mode 100644
index 0000000..6ebc74c
--- /dev/null
+++ b/final/test/Simplify/sweep_mapped_phi___%for---%return.jscop.transformed
@@ -0,0 +1,65 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_phi__phi[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyA[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyA",
+         "schedule" : "[n] -> { Stmt_bodyA[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyB[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyB",
+         "schedule" : "[n] -> { Stmt_bodyB[i0] -> [i0, 1] }"
+      }
+   ]
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Dead accesses removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_phi__phi[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/sweep_mapped_value.ll b/final/test/Simplify/sweep_mapped_value.ll
new file mode 100644
index 0000000..f193cf8
--- /dev/null
+++ b/final/test/Simplify/sweep_mapped_value.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Map %val to A[j], so the scalar write on Stmt_for_bodyB can be removed.
+;
+; for (int j = 0; j < n; j += 1) {
+; bodyA:
+;   double val = 21.0 + 21.0;
+;   A[j] = val;
+;
+; bodyB:
+;   B[j] = val;
+; }
+;
+
+define void @sweep_mapped_value(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %bodyA, label %exit
+
+    bodyA:
+      %val = fadd double 21.0, 21.0
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %bodyB
+
+    bodyB:
+      %B_idx = getelementptr inbounds double, double* %B, i32 %j
+      store double %val, double* %B_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Dead accesses removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_bodyA
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyA[i0] -> MemRef_A[i0] };
+; CHECK-NEXT:     Stmt_bodyB
+; CHECK-NEXT:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
+; CHECK-NEXT:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:                 [n] -> { Stmt_bodyB[i0] -> MemRef_val[] };
+; CHECK-NEXT:            new: [n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] };
+; CHECK-NEXT: }
diff --git a/final/test/Simplify/sweep_mapped_value___%for---%return.jscop b/final/test/Simplify/sweep_mapped_value___%for---%return.jscop
new file mode 100644
index 0000000..9a827f3
--- /dev/null
+++ b/final/test/Simplify/sweep_mapped_value___%for---%return.jscop
@@ -0,0 +1,48 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyA[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyA",
+         "schedule" : "[n] -> { Stmt_bodyA[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyB[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyB",
+         "schedule" : "[n] -> { Stmt_bodyB[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/sweep_mapped_value___%for---%return.jscop.transformed b/final/test/Simplify/sweep_mapped_value___%for---%return.jscop.transformed
new file mode 100644
index 0000000..f790262
--- /dev/null
+++ b/final/test/Simplify/sweep_mapped_value___%for---%return.jscop.transformed
@@ -0,0 +1,48 @@
+{
+   "arrays" : [
+      {
+         "name" : "MemRef_A",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      },
+      {
+         "name" : "MemRef_B",
+         "sizes" : [ "*" ],
+         "type" : "double"
+      }
+   ],
+   "context" : "[n] -> {  : -2147483648 <= n <= 2147483647 }",
+   "name" : "%for---%return",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_A[i0] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyA[i0] -> MemRef_val[] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyA[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyA",
+         "schedule" : "[n] -> { Stmt_bodyA[i0] -> [i0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "[n] -> { Stmt_bodyB[i0] -> MemRef_A[i0] }"
+            }
+         ],
+         "domain" : "[n] -> { Stmt_bodyB[i0] : 0 <= i0 < n }",
+         "name" : "Stmt_bodyB",
+         "schedule" : "[n] -> { Stmt_bodyB[i0] -> [i0, 1] }"
+      }
+   ]
+}
diff --git a/final/test/Simplify/ununsed_read_in_region_entry.ll b/final/test/Simplify/ununsed_read_in_region_entry.ll
new file mode 100644
index 0000000..4270013
--- /dev/null
+++ b/final/test/Simplify/ununsed_read_in_region_entry.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+; RUN: opt %loadPolly -polly-simplify -polly-codegen -S < %s | FileCheck %s -check-prefix=CODEGEN
+;
+; for (int i = 0; i < n; i+=1) {
+;    (void)A[0];
+;    if (21.0 == 0.0)
+;      B[0] = 42.0;
+; }
+;
+define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %region_entry, label %exit
+
+
+    region_entry:
+      %val = load double, double* %A
+      %cmp = fcmp oeq double 21.0, 0.0
+      br i1 %cmp, label %region_true, label %region_exit
+
+    region_true:
+      store double 42.0, double* %B
+      br label %region_exit
+
+    region_exit:
+      br label %body
+
+    body:
+      br label %inc
+
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Dead accesses removed: 1
+; CHECK:     Dead instructions removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT:     Stmt_region_entry__TO__region_exit
+; CHECK-NEXT:             MayWriteAccess :=   [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:                 [n] -> { Stmt_region_entry__TO__region_exit[i0] -> MemRef_B[0] };
+; CHECK-NEXT: }
+
+
+; CODEGEN:      polly.stmt.region_entry:
+; CODEGEN-NEXT:   %p_cmp = fcmp oeq double 2.100000e+01, 0.000000e+00
+; CODEGEN-NEXT:   br i1 %p_cmp
diff --git a/final/test/Unit/lit.cfg b/final/test/Unit/lit.cfg
new file mode 100644
index 0000000..eca3aae
--- /dev/null
+++ b/final/test/Unit/lit.cfg
@@ -0,0 +1,55 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+import os
+import platform
+
+import lit.formats
+import lit.util
+
+# name: The name of this test suite.
+config.name = 'Polly-Unit'
+
+if not config.has_unittests:
+    raise SystemExit
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = []
+
+# test_source_root: The root path where tests are located.
+# test_exec_root: The root path where tests should be run.
+config.test_exec_root = os.path.join(config.polly_obj_root, 'unittests')
+config.test_source_root = config.test_exec_root
+
+# testFormat: The test format to use to interpret tests.
+config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, 'Tests')
+
+# Propagate the temp directory. Windows requires this because it uses \Windows\
+# if none of these are present.
+if 'TMP' in os.environ:
+    config.environment['TMP'] = os.environ['TMP']
+if 'TEMP' in os.environ:
+    config.environment['TEMP'] = os.environ['TEMP']
+
+# Propagate path to symbolizer for ASan/MSan.
+for symbolizer in ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']:
+    if symbolizer in os.environ:
+        config.environment[symbolizer] = os.environ[symbolizer]
+
+if platform.system() == 'Darwin':
+    shlibpath_var = 'DYLD_LIBRARY_PATH'
+elif platform.system() == 'Windows':
+    shlibpath_var = 'PATH'
+else:
+    shlibpath_var = 'LD_LIBRARY_PATH'
+
+# Point the dynamic loader at dynamic libraries in 'lib'.
+shlibpath = os.path.pathsep.join((config.llvm_libs_dir,
+                                 config.environment.get(shlibpath_var,'')))
+
+# Win32 seeks DLLs along %PATH%.
+if sys.platform in ['win32', 'cygwin'] and os.path.isdir(config.shlibdir):
+    shlibpath = os.path.pathsep.join((config.shlibdir, shlibpath))
+
+config.environment[shlibpath_var] = shlibpath
diff --git a/final/test/Unit/lit.site.cfg.in b/final/test/Unit/lit.site.cfg.in
new file mode 100644
index 0000000..930fef5
--- /dev/null
+++ b/final/test/Unit/lit.site.cfg.in
@@ -0,0 +1,32 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+import sys
+
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
+config.llvm_build_mode = "@LLVM_BUILD_MODE@"
+config.polly_obj_root = "@POLLY_BINARY_DIR@"
+config.polly_lib_dir = "@POLLY_LIB_DIR@"
+config.enable_shared = @ENABLE_SHARED@
+config.shlibdir = "@SHLIBDIR@"
+config.target_triple = "@TARGET_TRIPLE@"
+config.enable_gpgpu_codegen = "@GPU_CODEGEN@"
+config.link_polly_into_tools = "@LINK_POLLY_INTO_TOOLS@"
+config.has_unittests = @POLLY_GTEST_AVAIL@
+
+# Support substitution of the tools_dir, libs_dirs, and build_mode with user
+# parameters. This is used when we can't determine the tool dir at
+# configuration time.
+try:
+    config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
+    config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
+    config.llvm_build_mode = config.llvm_build_mode % lit_config.params
+except KeyError:
+    e = sys.exc_info()[1]
+    key, = e.args
+    lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@POLLY_SOURCE_DIR@/test/Unit/lit.cfg")
diff --git a/final/test/UnitIsl/isl_test.sh b/final/test/UnitIsl/isl_test.sh
new file mode 100644
index 0000000..776ede5
--- /dev/null
+++ b/final/test/UnitIsl/isl_test.sh
@@ -0,0 +1 @@
+; RUN: polly-isl-test
diff --git a/final/test/UnitIsl/lit.cfg b/final/test/UnitIsl/lit.cfg
new file mode 100644
index 0000000..9c732a1
--- /dev/null
+++ b/final/test/UnitIsl/lit.cfg
@@ -0,0 +1,45 @@
+# -*clang- Python -*-
+
+import os
+import platform
+import re
+
+import lit.formats
+import lit.util
+
+# Configuration file for the 'lit' test runner.
+
+# name: The name of this test suite.
+config.name = 'Polly - isl unit tests'
+
+# testFormat: The test format to use to interpret tests.
+#
+# For now we require '&&' between commands, until they get globally killed and
+# the test runner updated.
+execute_external = platform.system() != 'Windows'
+config.test_format = lit.formats.ShTest(execute_external)
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.sh']
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.dirname(__file__)
+
+# test_exec_root: The root path where tests should be run.
+polly_obj_root = getattr(config, 'polly_obj_root', None)
+if polly_obj_root is not None:
+    config.test_exec_root = os.path.join(polly_obj_root, 'test')
+
+# Set llvm_{src,obj}_root for use by others.
+config.llvm_src_root = getattr(config, 'llvm_src_root', None)
+config.llvm_obj_root = getattr(config, 'llvm_obj_root', None)
+
+# Tweak the PATH to ensure that built files are the ones executed.
+bin_dir = getattr(config, 'bin_dir', None)
+if bin_dir is None:
+    lit_config.fatal('No executable dir set!')
+path = os.path.pathsep.join((bin_dir, config.environment['PATH']))
+config.environment['PATH'] = path
+
+config.environment['srcdir'] = os.path.join(config.test_source_root,
+                                            '../../lib/External/isl')
diff --git a/final/test/UnitIsl/lit.site.cfg.in b/final/test/UnitIsl/lit.site.cfg.in
new file mode 100644
index 0000000..80de8fc
--- /dev/null
+++ b/final/test/UnitIsl/lit.site.cfg.in
@@ -0,0 +1,10 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+import sys
+
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.polly_obj_root = "@POLLY_BINARY_DIR@"
+config.bin_dir = "@CMAKE_RUNTIME_OUTPUT_DIRECTORY@"
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@POLLY_SOURCE_DIR@/test/UnitIsl/lit.cfg")
diff --git a/final/test/create_ll.sh b/final/test/create_ll.sh
new file mode 100755
index 0000000..3ed6fc7
--- /dev/null
+++ b/final/test/create_ll.sh
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+
+LLFILE=`echo $1 | sed -e 's/\.c/.ll/g'`
+LLFILE_TMP=${LLFILE}.tmp
+
+clang -c -S -emit-llvm -O3 -mllvm -disable-llvm-optzns $1 -o ${LLFILE}
+
+opt -correlated-propagation -mem2reg -instcombine -loop-simplify -indvars \
+-instnamer ${LLFILE} -S -o ${LLFILE_TMP}
+
+# Insert a header into the new testcase containing a sample RUN line a FIXME and
+# an XFAIL. Then insert the formated C code and finally the LLVM-IR without
+# attributes, the module ID or the target triple.
+echo '; RUN: opt %loadPolly -analyze < %s | FileCheck %s' > ${LLFILE}
+echo ';' >> ${LLFILE}
+echo '; FIXME: Edit the run line and add checks!' >> ${LLFILE}
+echo ';' >> ${LLFILE}
+echo '; XFAIL: *' >> ${LLFILE}
+echo ';' >> ${LLFILE}
+clang-format $1 | sed -e 's/^[^$]/;    &/' -e 's/^$/;/' >> ${LLFILE}
+echo ';' >> ${LLFILE}
+
+cat ${LLFILE_TMP} >> ${LLFILE}
+sed -i".tmp" '/attributes .* =/d' ${LLFILE}
+sed -i".tmp" -e 's/) \#[0-9]*/)/' ${LLFILE}
+sed -i".tmp" '/; Function Attrs:/d' ${LLFILE}
+sed -i".tmp" '/; ModuleID =/d' ${LLFILE}
+sed -i".tmp" '/target triple/d' ${LLFILE}
+
+mv ${LLFILE_TMP} ${LLFILE}
diff --git a/final/test/lit.cfg b/final/test/lit.cfg
new file mode 100644
index 0000000..293b426
--- /dev/null
+++ b/final/test/lit.cfg
@@ -0,0 +1,68 @@
+# -*clang- Python -*-
+
+import os
+import platform
+import re
+import subprocess
+
+import lit.formats
+import lit.util
+
+# Configuration file for the 'lit' test runner.
+
+# name: The name of this test suite.
+config.name = 'Polly'
+
+# testFormat: The test format to use to interpret tests.
+#
+# For now we require '&&' between commands, until they get globally killed and
+# the test runner updated.
+execute_external = platform.system() != 'Windows'
+config.test_format = lit.formats.ShTest(execute_external)
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.ll']
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.dirname(__file__)
+
+# test_exec_root: The root path where tests should be run.
+config.test_exec_root = os.path.join(config.polly_obj_root, 'test')
+
+# Tweak the PATH to include the tools dir and the scripts dir.
+base_paths = [config.llvm_tools_dir, config.environment['PATH']]
+path = os.path.pathsep.join(base_paths + config.extra_paths)
+config.environment['PATH'] = path
+
+path = os.path.pathsep.join((config.llvm_libs_dir,
+                              config.environment.get('LD_LIBRARY_PATH','')))
+config.environment['LD_LIBRARY_PATH'] = path
+
+# opt knows whether it is compiled with -DNDEBUG.
+import subprocess
+try:
+    opt_cmd = subprocess.Popen([os.path.join(config.llvm_tools_dir, 'opt'), '-version'],
+                           stdout = subprocess.PIPE,
+                           env=config.environment)
+except OSError:
+    print("Could not find opt in " + config.llvm_tools_dir)
+    exit(42)
+
+if re.search(r'with assertions', opt_cmd.stdout.read().decode('ascii')):
+    config.available_features.add('asserts')
+opt_cmd.wait()
+
+try:
+    llvm_config_cmd = subprocess.Popen([os.path.join(
+                                        config.llvm_tools_dir,
+                                        'llvm-config'),
+                                        '--targets-built'],
+                                       stdout = subprocess.PIPE,
+                                       env=config.environment)
+except OSError:
+    print("Could not find llvm-config in " + config.llvm_tools_dir)
+    exit(42)
+
+if re.search(r'NVPTX', llvm_config_cmd.stdout.read().decode('ascii')):
+    config.available_features.add('nvptx-registered-target')
+llvm_config_cmd.wait()
diff --git a/final/test/lit.site.cfg.in b/final/test/lit.site.cfg.in
new file mode 100644
index 0000000..fda0865
--- /dev/null
+++ b/final/test/lit.site.cfg.in
@@ -0,0 +1,68 @@
+## Autogenerated by LLVM/Polly configuration.
+# Do not edit!
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
+config.polly_obj_root = "@POLLY_BINARY_DIR@"
+config.polly_lib_dir = "@POLLY_LIB_DIR@"
+config.target_triple = "@TARGET_TRIPLE@"
+config.enable_gpgpu_codegen = "@GPU_CODEGEN@"
+config.link_polly_into_tools = "@LINK_POLLY_INTO_TOOLS@"
+config.targets_to_build = "@TARGETS_TO_BUILD@"
+config.extra_paths = "@POLLY_TEST_EXTRA_PATHS@".split(";")
+
+## Check the current platform with regex
+import re
+EAT_ERR_ON_X86 = ' '
+if (re.match(r'^x86_64*', '@TARGET_TRIPLE@') == None) :
+  EAT_ERR_ON_X86 = '|| echo \"error is eaten\"'
+
+for arch in config.targets_to_build.split():
+    config.available_features.add(arch.lower() + '-registered-target')
+
+# Support substitution of the tools and libs dirs with user parameters. This is
+# used when we can't determine the tool dir at configuration time.
+try:
+    config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
+    config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
+except KeyError:
+    e = sys.exc_info()[1]
+    key, = e.args
+    lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+
+# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
+# subdirectories contain auxiliary inputs for various tests in their parent
+# directories.
+config.excludes = ['Inputs']
+
+if config.link_polly_into_tools == '' or \
+   config.link_polly_into_tools.lower() == '0' or \
+   config.link_polly_into_tools.lower() == 'n' or \
+   config.link_polly_into_tools.lower() == 'no' or \
+   config.link_polly_into_tools.lower() == 'off' or \
+   config.link_polly_into_tools.lower() == 'false' or \
+   config.link_polly_into_tools.lower() == 'notfound' or \
+   config.link_polly_into_tools.lower() == 'link_polly_into_tools-notfound':
+    config.substitutions.append(('%loadPolly', '-load '
+                                 + config.polly_lib_dir + '/LLVMPolly@LLVM_SHLIBEXT@'
+                                 + ' -polly-process-unprofitable '
+                                 + ' -polly-remarks-minimal '
+                                 + ' -polly-use-llvm-names '
+                                 + ' -polly-import-jscop-dir=%S '
+                                 + ' -polly-codegen-verify '
+                                 ))
+else:
+    config.substitutions.append(('%loadPolly', ''
+                                 + ' -polly-process-unprofitable '
+                                 + ' -polly-remarks-minimal '
+                                 + ' -polly-use-llvm-names '
+                                 + ' -polly-import-jscop-dir=%S '
+                                 + ' -polly-codegen-verify '
+                                 ))
+
+if config.enable_gpgpu_codegen == 'TRUE' :
+    config.available_features.add('pollyacc')
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@POLLY_SOURCE_DIR@/test/lit.cfg")
diff --git a/final/test/polly.ll b/final/test/polly.ll
new file mode 100644
index 0000000..f78ccea
--- /dev/null
+++ b/final/test/polly.ll
@@ -0,0 +1,11 @@
+; RUN: opt %loadPolly -polly-scops -S < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+define void @foo() nounwind {
+start:
+  br label %end
+
+end:
+  ret void
+}
+
+; CHECK: foo
diff --git a/final/test/update_check.py b/final/test/update_check.py
new file mode 100644
index 0000000..318fcfe
--- /dev/null
+++ b/final/test/update_check.py
@@ -0,0 +1,459 @@
+#! /usr/bin/env python3
+# -*- coding: UTF-8 -*-
+
+# Polly/LLVM update_check.py
+# Update lit FileCheck files by replacing the 'CHECK:' lines by the actual output of the 'RUN:' command.
+
+import argparse
+import os
+import subprocess
+import shlex
+import re
+
+
+polly_src_dir = '''@POLLY_SOURCE_DIR@'''
+polly_lib_dir = '''@POLLY_LIB_DIR@'''
+shlibext = '''@LLVM_SHLIBEXT@'''
+llvm_tools_dir = '''@LLVM_TOOLS_DIR@'''
+link_polly_into_tools = not '''@LINK_POLLY_INTO_TOOLS@'''.lower() in {'','0','n','no','off','false','notfound','link_polly_into_tools-notfound'}
+
+runre = re.compile(r'\s*\;\s*RUN\s*\:(?P<tool>.*)')
+filecheckre = re.compile(r'\s*(?P<tool>.*)\|\s*(?P<filecheck>FileCheck\s[^|]*)')
+emptyline = re.compile(r'\s*(\;\s*)?')
+commentline = re.compile(r'\s*(\;.*)?')
+
+
+def ltrim_emptylines(lines,meta=None):
+    while len(lines) and emptyline.fullmatch(lines[0]):
+        del lines[0]
+        if meta is not None:
+            del meta[0]
+
+
+def rtrim_emptylines(lines):
+    while len(lines) and emptyline.fullmatch(lines[-1]):
+        del lines[-1]
+
+
+def trim_emptylines(lines):
+    ltrim_emptylines(lines)
+    rtrim_emptylines(lines)
+
+
+def complete_exename(path, filename):
+    complpath = os.path.join(path, filename)
+    if os.path.isfile(complpath):
+        return complpath
+    elif os.path.isfile(complpath + '.exe'):
+        return complpath + '.exe'
+    return filename
+
+
+def indention(line):
+    for i,c in enumerate(line):
+        if c != ' ' and c != '\t':
+            return i
+    return None
+
+
+def common_indent(lines):
+    indentions = (indention(line) for line in lines)
+    indentions = (indent for indent in indentions if indent is not None)
+    return min(indentions,default=0)
+
+
+funcre = re.compile(r'^    Function: \S*$')
+regionre = re.compile(r'^    Region: \S*$')
+depthre = re.compile(r'^    Max Loop Depth: .*')
+paramre = re.compile(r'    [0-9a-z-A-Z_]+\: .*')
+
+def classyfier1(lines):
+    i = iter(lines)
+    line = i.__next__()
+    while True:
+        if line.startswith("Printing analysis 'Polly - Calculate dependences' for region: "):
+            yield {'PrintingDependenceInfo'}
+        elif line.startswith("remark: "):
+            yield {'Remark'}
+        elif funcre.fullmatch(line):
+            yield {'Function'}
+        elif regionre.fullmatch(line):
+            yield  { 'Region'}
+        elif depthre.fullmatch(line):
+            yield  {'MaxLoopDepth'}
+        elif line == '    Invariant Accesses: {':
+            while True:
+                yield { 'InvariantAccesses'}
+                if line == '    }':
+                    break
+                line = i.__next__()
+        elif line == '    Context:':
+            yield  {'Context'}
+            line = i.__next__()
+            yield  {'Context'}
+        elif line == '    Assumed Context:':
+            yield  {'AssumedContext'}
+            line = i.__next__()
+            yield  {'AssumedContext'}
+        elif line == '    Invalid Context:':
+            yield  {'InvalidContext'}
+            line = i.__next__()
+            yield  {'InvalidContext'}
+        elif line == '    Boundary Context:':
+            yield  {'BoundaryContext'}
+            line = i.__next__()
+            yield  {'BoundaryContext'}
+            line = i.__next__()
+            while paramre.fullmatch(line):
+                yield  {'Param'}
+                line = i.__next__()
+            continue
+        elif line == '    Arrays {':
+            while True:
+                yield  {'Arrays'}
+                if line == '    }':
+                    break
+                line = i.__next__()
+        elif line == '    Arrays (Bounds as pw_affs) {':
+            while True:
+                yield  {'PwAffArrays'}
+                if line == '    }':
+                    break
+                line = i.__next__()
+        elif line.startswith('    Alias Groups ('):
+            while True:
+                yield  {'AliasGroups'}
+                line = i.__next__()
+                if not line.startswith('        '):
+                    break
+            continue
+        elif line == '    Statements {':
+            while True:
+                yield  {'Statements'}
+                if line == '    }':
+                    break
+                line = i.__next__()
+        elif line == '    RAW dependences:':
+            yield {'RAWDep','BasicDep','Dep','DepInfo'}
+            line = i.__next__()
+            while line.startswith('        '):
+                yield  {'RAWDep','BasicDep','Dep','DepInfo'}
+                line = i.__next__()
+            continue
+        elif line == '    WAR dependences:':
+            yield {'WARDep','BasicDep','Dep','DepInfo'}
+            line = i.__next__()
+            while line.startswith('        '):
+                yield  {'WARDep','BasicDep','Dep','DepInfo'}
+                line = i.__next__()
+            continue
+        elif line == '    WAW dependences:':
+            yield {'WAWDep','BasicDep','Dep','DepInfo'}
+            line = i.__next__()
+            while line.startswith('        '):
+                yield  {'WAWDep','BasicDep','Dep','DepInfo'}
+                line = i.__next__()
+            continue
+        elif line == '    Reduction dependences:':
+            yield {'RedDep','Dep','DepInfo'}
+            line = i.__next__()
+            while line.startswith('        '):
+                yield  {'RedDep','Dep','DepInfo'}
+                line = i.__next__()
+            continue
+        elif line == '    Transitive closure of reduction dependences:':
+            yield {'TransitiveClosureDep','DepInfo'}
+            line = i.__next__()
+            while line.startswith('        '):
+                yield  {'TransitiveClosureDep','DepInfo'}
+                line = i.__next__()
+            continue
+        elif line.startswith("New access function '"):
+            yield {'NewAccessFunction'}
+        elif line == 'Schedule before flattening {':
+            while True:
+                yield  {'ScheduleBeforeFlattening'}
+                if line == '}':
+                    break
+                line = i.__next__()
+        elif line == 'Schedule after flattening {':
+            while True:
+                yield  {'ScheduleAfterFlattening'}
+                if line == '}':
+                    break
+                line = i.__next__()
+        else:
+            yield set()
+        line = i.__next__()
+
+
+def classyfier2(lines):
+    i = iter(lines)
+    line = i.__next__()
+    while True:
+        if funcre.fullmatch(line):
+            while line.startswith('    '):
+                yield  {'FunctionDetail'}
+                line = i.__next__()
+            continue
+        elif line.startswith("Printing analysis 'Polly - Generate an AST from the SCoP (isl)' for region: "):
+            yield {'PrintingIslAst'}
+            line = i.__next__()
+            while not line.startswith('Printing analysis'):
+                yield  {'AstDetail'}
+                line = i.__next__()
+            continue
+        else:
+            yield set()
+        line = i.__next__()
+
+
+replrepl = {'{{':'{{[{][{]}}','}}': '{{[}][}]}}', '[[':'{{\[\[}}',']]': '{{\]\]}}'}
+replre = re.compile('|'.join(re.escape(k) for k in replrepl.keys()))
+
+def main():
+    parser = argparse.ArgumentParser(description="Update CHECK lines")
+    parser.add_argument('testfile',help="File to update (absolute or relative to --testdir)")
+    parser.add_argument('--check-style',choices=['CHECK','CHECK-NEXT'],default='CHECK-NEXT',help="What kind of checks lines to generate")
+    parser.add_argument('--check-position',choices=['end','before-content','autodetect'],default='autodetect',help="Where to add the CHECK lines into the file; 'autodetect' searches for the first 'CHECK' line ind inserts it there")
+    parser.add_argument('--check-include',action='append',default=[], help="What parts of the output lines to check; use syntax 'CHECK=include' to apply to one CHECK-prefix only (by default, everything)")
+    parser.add_argument('--check-label-include',action='append',default=[],help="Use CHECK-LABEL for these includes")
+    parser.add_argument('--check-part-newline',action='store_true',help="Add empty line between different check parts")
+    parser.add_argument('--prefix-only',action='append',default=None,help="Update only these prefixes (default: all)")
+    parser.add_argument('--bindir',help="Location of the opt program")
+    parser.add_argument('--testdir',help="Root dir for unit tests")
+    parser.add_argument('--inplace','-i',action='store_true',help="Replace input file")
+    parser.add_argument('--output','-o',help="Write changed input to this file")
+    known = parser.parse_args()
+
+    if not known.inplace and known.output is None:
+        print("Must specify what to do with output (--output or --inplace)")
+        exit(1)
+    if known.inplace and known.output is not None:
+        print("--inplace and --output are mutually exclusive")
+        exit(1)
+
+    outfile = known.output
+
+    filecheckparser = argparse.ArgumentParser(add_help=False)
+    filecheckparser.add_argument('-check-prefix','--check-prefix',default='CHECK')
+
+    filename = known.testfile
+    for dir in ['.', known.testdir, os.path.join(polly_src_dir,'test'), polly_src_dir]:
+        if not dir:
+            continue
+        testfilename = os.path.join(dir,filename)
+        if os.path.isfile(testfilename):
+            filename = testfilename
+            break
+
+    if known.inplace:
+        outfile = filename
+
+    allchecklines = []
+    checkprefixes = []
+
+    with open(filename, 'r') as file:
+        oldlines = [line.rstrip('\r\n') for line in file.readlines()]
+
+    runlines = []
+    for line in oldlines:
+        m = runre.match(line)
+        if m:
+            runlines.append(m.group('tool'))
+
+    continuation = ''
+    newrunlines = []
+    for line in runlines:
+        if line.endswith('\\'):
+            continuation += line[:-2] + ' '
+        else:
+            newrunlines.append(continuation + line)
+            continuation = ''
+    if continuation:
+        newrunlines.append(continuation)
+
+    for line in newrunlines:
+        m = filecheckre.match(line)
+        if not m:
+            continue
+
+        tool, filecheck = m.group('tool', 'filecheck')
+        filecheck = shlex.split(filecheck)
+        tool = shlex.split(tool)
+        if known.bindir is not None:
+            tool[0] = complete_exename(known.bindir, tool[0])
+        if os.path.isdir(llvm_tools_dir):
+            tool[0] = complete_exename(llvm_tools_dir, tool[0])
+        check_prefix = filecheckparser.parse_known_args(filecheck)[0].check_prefix
+        if known.prefix_only is not None and not check_prefix in known.prefix_only:
+            continue
+        if check_prefix in checkprefixes:
+            continue
+        checkprefixes.append(check_prefix)
+
+        newtool = []
+        optstderr = None
+        for toolarg in tool:
+            toolarg = toolarg.replace('%s', filename)
+            toolarg = toolarg.replace('%S', os.path.dirname(filename))
+            if toolarg == '%loadPolly':
+                if not link_polly_into_tools:
+                    newtool += ['-load',os.path.join(polly_lib_dir,'LLVMPolly' + shlibext)]
+                newtool.append('-polly-process-unprofitable')
+                newtool.append('-polly-remarks-minimal')
+            elif toolarg == '2>&1':
+                optstderr = subprocess.STDOUT
+            else:
+                newtool.append(toolarg)
+        tool = newtool
+
+        inpfile = None
+        i = 1
+        while i <  len(tool):
+            if tool[i] == '<':
+                inpfile = tool[i + 1]
+                del tool[i:i + 2]
+                continue
+            i += 1
+        if inpfile:
+            with open(inpfile) as inp:
+                retlines = subprocess.check_output(tool,universal_newlines=True,stdin=inp,stderr=optstderr)
+        else:
+            retlines = subprocess.check_output(tool,universal_newlines=True,stderr=optstderr)
+        retlines = [line.replace('\t', '    ') for line in retlines.splitlines()]
+        check_include = []
+        for checkme in known.check_include + known.check_label_include:
+            parts = checkme.split('=')
+            if len(parts) == 2:
+                if parts[0] == check_prefix:
+                    check_include.append(parts[1])
+            else:
+                check_include.append(checkme)
+
+        if check_include:
+            filtered_retlines = []
+            classified_retlines = []
+            lastmatch = None
+            for line,kind in ((line,class1.union(class2)) for line,class1,class2 in zip(retlines,classyfier1(retlines), classyfier2(retlines))):
+                match = kind.intersection(check_include)
+                if match:
+                    if lastmatch != match:
+                        filtered_retlines.append('')
+                        classified_retlines.append({'Separator'})
+                    filtered_retlines.append(line)
+                    classified_retlines.append(kind)
+                lastmatch = match
+
+            retlines = filtered_retlines
+        else:
+            classified_retlines = (set() for line in retlines)
+
+        rtrim_emptylines(retlines)
+        ltrim_emptylines(retlines,classified_retlines)
+        retlines = [replre.sub(lambda m: replrepl[m.group(0)], line) for line in retlines]
+        indent = common_indent(retlines)
+        retlines = [line[indent:] for line in retlines]
+        checklines = []
+        previous_was_empty = True
+        for line,kind in zip(retlines,classified_retlines):
+            if line:
+                if known.check_style == 'CHECK' and known.check_label_include:
+                    if not kind.isdisjoint(known.check_label_include):
+                        checklines.append('; ' + check_prefix + '-LABEL: ' + line)
+                    else:
+                        checklines.append('; ' + check_prefix + ':       ' + line)
+                elif known.check_style == 'CHECK':
+                    checklines.append('; ' + check_prefix + ': ' + line)
+                elif known.check_label_include and known.check_label_include:
+                    if not kind.isdisjoint(known.check_label_include):
+                        checklines.append('; ' + check_prefix + '-LABEL: ' + line)
+                    elif previous_was_empty:
+                        checklines.append('; ' + check_prefix + ':       ' + line)
+                    else:
+                        checklines.append('; ' + check_prefix + '-NEXT:  ' + line)
+                else:
+                    if previous_was_empty:
+                        checklines.append('; ' + check_prefix + ':      ' + line)
+                    else:
+                        checklines.append('; ' + check_prefix + '-NEXT: ' + line)
+                previous_was_empty = False
+            else:
+                if not 'Separator' in kind or known.check_part_newline:
+                    checklines.append(';')
+                previous_was_empty = True
+        allchecklines.append(checklines)
+
+    if not checkprefixes:
+        return
+
+    checkre = re.compile(r'^\s*\;\s*(' + '|'.join([re.escape(s) for s in checkprefixes]) + ')(\-NEXT|\-DAG|\-NOT|\-LABEL|\-SAME)?\s*\:')
+    firstcheckline = None
+    firstnoncommentline = None
+    headerlines = []
+    newlines = []
+    uptonowlines = []
+    emptylines = []
+    lastwascheck = False
+    for line in oldlines:
+        if checkre.match(line):
+            if firstcheckline is None:
+                firstcheckline = len(newlines) + len(emptylines)
+            if not lastwascheck:
+                uptonowlines += emptylines
+            emptylines = []
+            lastwascheck = True
+        elif emptyline.fullmatch(line):
+            emptylines.append(line)
+        else:
+            newlines += uptonowlines
+            newlines += emptylines
+            newlines.append(line)
+            emptylines = []
+            uptonowlines = []
+            lastwascheck = False
+
+    for i,line in enumerate(newlines):
+        if not commentline.fullmatch(line):
+            firstnoncommentline = i
+            break
+
+    with open(outfile,'w',newline='') as file:
+        def writelines(lines):
+            for line in lines:
+                file.write(line)
+                file.write('\n')
+
+        if firstcheckline is not None and known.check_position == 'autodetect':
+            writelines(newlines[:firstcheckline])
+            writelines(uptonowlines)
+            for i,checklines in enumerate(allchecklines):
+                if i != 0:
+                    file.write('\n')
+                writelines(checklines)
+            writelines(newlines[firstcheckline:])
+            writelines(emptylines)
+        elif firstnoncommentline is not None and known.check_position == 'before-content':
+            headerlines = newlines[:firstnoncommentline]
+            rtrim_emptylines(headerlines)
+            contentlines = newlines[firstnoncommentline:]
+            ltrim_emptylines(contentlines)
+
+            writelines(headerlines)
+            for checklines in allchecklines:
+                file.write('\n')
+                writelines(checklines)
+            file.write('\n')
+            writelines(contentlines)
+            writelines(uptonowlines)
+            writelines(emptylines)
+        else:
+            writelines(newlines)
+            rtrim_emptylines(newlines)
+            for checklines in allchecklines:
+                file.write('\n\n')
+                writelines(checklines)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/final/tools/CMakeLists.txt b/final/tools/CMakeLists.txt
new file mode 100644
index 0000000..7c89ed5
--- /dev/null
+++ b/final/tools/CMakeLists.txt
@@ -0,0 +1,5 @@
+if (CUDA_FOUND OR OpenCL_FOUND)
+  add_subdirectory(GPURuntime)
+endif (CUDA_FOUND OR OpenCL_FOUND)
+
+set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE)
diff --git a/final/tools/GPURuntime/CMakeLists.txt b/final/tools/GPURuntime/CMakeLists.txt
new file mode 100644
index 0000000..4e17c27
--- /dev/null
+++ b/final/tools/GPURuntime/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(MODULE TRUE)
+set(LLVM_NO_RTTI 1)
+
+add_polly_library(GPURuntime
+  GPUJIT.c
+  )
+
+set_target_properties(GPURuntime
+  PROPERTIES
+  LINKER_LANGUAGE C
+  PREFIX "lib"
+  )
+
+set_property(TARGET GPURuntime PROPERTY C_STANDARD 99)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=default ")
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize=all ")
+endif()
diff --git a/final/tools/GPURuntime/GPUJIT.c b/final/tools/GPURuntime/GPUJIT.c
new file mode 100644
index 0000000..25c5d6b
--- /dev/null
+++ b/final/tools/GPURuntime/GPUJIT.c
@@ -0,0 +1,1856 @@
+/******************** GPUJIT.c - GPUJIT Execution Engine **********************/
+/*                                                                            */
+/*                     The LLVM Compiler Infrastructure                       */
+/*                                                                            */
+/* This file is dual licensed under the MIT and the University of Illinois    */
+/* Open Source License. See LICENSE.TXT for details.                          */
+/*                                                                            */
+/******************************************************************************/
+/*                                                                            */
+/*  This file implements GPUJIT, a ptx string execution engine for GPU.       */
+/*                                                                            */
+/******************************************************************************/
+
+#include "GPUJIT.h"
+
+#ifdef HAS_LIBCUDART
+#include <cuda.h>
+#include <cuda_runtime.h>
+#endif /* HAS_LIBCUDART */
+
+#ifdef HAS_LIBOPENCL
+#ifdef __APPLE__
+#include <OpenCL/opencl.h>
+#else
+#include <CL/cl.h>
+#endif /* __APPLE__ */
+#endif /* HAS_LIBOPENCL */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int DebugMode;
+static int CacheMode;
+#define max(x, y) ((x) > (y) ? (x) : (y))
+
+static PollyGPURuntime Runtime = RUNTIME_NONE;
+
+static void debug_print(const char *format, ...) {
+  if (!DebugMode)
+    return;
+
+  va_list args;
+  va_start(args, format);
+  vfprintf(stderr, format, args);
+  va_end(args);
+}
+#define dump_function() debug_print("-> %s\n", __func__)
+
+#define KERNEL_CACHE_SIZE 10
+
+static void err_runtime() __attribute__((noreturn));
+static void err_runtime() {
+  fprintf(stderr, "Runtime not correctly initialized.\n");
+  exit(-1);
+}
+
+struct PollyGPUContextT {
+  void *Context;
+};
+
+struct PollyGPUFunctionT {
+  void *Kernel;
+};
+
+struct PollyGPUDevicePtrT {
+  void *DevicePtr;
+};
+
+/******************************************************************************/
+/*                                  OpenCL                                    */
+/******************************************************************************/
+#ifdef HAS_LIBOPENCL
+
+struct OpenCLContextT {
+  cl_context Context;
+  cl_command_queue CommandQueue;
+};
+
+struct OpenCLKernelT {
+  cl_kernel Kernel;
+  cl_program Program;
+  const char *BinaryString;
+};
+
+struct OpenCLDevicePtrT {
+  cl_mem MemObj;
+};
+
+/* Dynamic library handles for the OpenCL runtime library. */
+static void *HandleOpenCL;
+static void *HandleOpenCLBeignet;
+
+/* Type-defines of function pointer to OpenCL Runtime API. */
+typedef cl_int clGetPlatformIDsFcnTy(cl_uint NumEntries,
+                                     cl_platform_id *Platforms,
+                                     cl_uint *NumPlatforms);
+static clGetPlatformIDsFcnTy *clGetPlatformIDsFcnPtr;
+
+typedef cl_int clGetDeviceIDsFcnTy(cl_platform_id Platform,
+                                   cl_device_type DeviceType,
+                                   cl_uint NumEntries, cl_device_id *Devices,
+                                   cl_uint *NumDevices);
+static clGetDeviceIDsFcnTy *clGetDeviceIDsFcnPtr;
+
+typedef cl_int clGetDeviceInfoFcnTy(cl_device_id Device,
+                                    cl_device_info ParamName,
+                                    size_t ParamValueSize, void *ParamValue,
+                                    size_t *ParamValueSizeRet);
+static clGetDeviceInfoFcnTy *clGetDeviceInfoFcnPtr;
+
+typedef cl_int clGetKernelInfoFcnTy(cl_kernel Kernel, cl_kernel_info ParamName,
+                                    size_t ParamValueSize, void *ParamValue,
+                                    size_t *ParamValueSizeRet);
+static clGetKernelInfoFcnTy *clGetKernelInfoFcnPtr;
+
+typedef cl_context clCreateContextFcnTy(
+    const cl_context_properties *Properties, cl_uint NumDevices,
+    const cl_device_id *Devices,
+    void CL_CALLBACK *pfn_notify(const char *Errinfo, const void *PrivateInfo,
+                                 size_t CB, void *UserData),
+    void *UserData, cl_int *ErrcodeRet);
+static clCreateContextFcnTy *clCreateContextFcnPtr;
+
+typedef cl_command_queue
+clCreateCommandQueueFcnTy(cl_context Context, cl_device_id Device,
+                          cl_command_queue_properties Properties,
+                          cl_int *ErrcodeRet);
+static clCreateCommandQueueFcnTy *clCreateCommandQueueFcnPtr;
+
+typedef cl_mem clCreateBufferFcnTy(cl_context Context, cl_mem_flags Flags,
+                                   size_t Size, void *HostPtr,
+                                   cl_int *ErrcodeRet);
+static clCreateBufferFcnTy *clCreateBufferFcnPtr;
+
+typedef cl_int
+clEnqueueWriteBufferFcnTy(cl_command_queue CommandQueue, cl_mem Buffer,
+                          cl_bool BlockingWrite, size_t Offset, size_t Size,
+                          const void *Ptr, cl_uint NumEventsInWaitList,
+                          const cl_event *EventWaitList, cl_event *Event);
+static clEnqueueWriteBufferFcnTy *clEnqueueWriteBufferFcnPtr;
+
+typedef cl_program
+clCreateProgramWithLLVMIntelFcnTy(cl_context Context, cl_uint NumDevices,
+                                  const cl_device_id *DeviceList,
+                                  const char *Filename, cl_int *ErrcodeRet);
+static clCreateProgramWithLLVMIntelFcnTy *clCreateProgramWithLLVMIntelFcnPtr;
+
+typedef cl_program clCreateProgramWithBinaryFcnTy(
+    cl_context Context, cl_uint NumDevices, const cl_device_id *DeviceList,
+    const size_t *Lengths, const unsigned char **Binaries, cl_int *BinaryStatus,
+    cl_int *ErrcodeRet);
+static clCreateProgramWithBinaryFcnTy *clCreateProgramWithBinaryFcnPtr;
+
+typedef cl_int clBuildProgramFcnTy(
+    cl_program Program, cl_uint NumDevices, const cl_device_id *DeviceList,
+    const char *Options,
+    void(CL_CALLBACK *pfn_notify)(cl_program Program, void *UserData),
+    void *UserData);
+static clBuildProgramFcnTy *clBuildProgramFcnPtr;
+
+typedef cl_kernel clCreateKernelFcnTy(cl_program Program,
+                                      const char *KernelName,
+                                      cl_int *ErrcodeRet);
+static clCreateKernelFcnTy *clCreateKernelFcnPtr;
+
+typedef cl_int clSetKernelArgFcnTy(cl_kernel Kernel, cl_uint ArgIndex,
+                                   size_t ArgSize, const void *ArgValue);
+static clSetKernelArgFcnTy *clSetKernelArgFcnPtr;
+
+typedef cl_int clEnqueueNDRangeKernelFcnTy(
+    cl_command_queue CommandQueue, cl_kernel Kernel, cl_uint WorkDim,
+    const size_t *GlobalWorkOffset, const size_t *GlobalWorkSize,
+    const size_t *LocalWorkSize, cl_uint NumEventsInWaitList,
+    const cl_event *EventWaitList, cl_event *Event);
+static clEnqueueNDRangeKernelFcnTy *clEnqueueNDRangeKernelFcnPtr;
+
+typedef cl_int clEnqueueReadBufferFcnTy(cl_command_queue CommandQueue,
+                                        cl_mem Buffer, cl_bool BlockingRead,
+                                        size_t Offset, size_t Size, void *Ptr,
+                                        cl_uint NumEventsInWaitList,
+                                        const cl_event *EventWaitList,
+                                        cl_event *Event);
+static clEnqueueReadBufferFcnTy *clEnqueueReadBufferFcnPtr;
+
+typedef cl_int clFlushFcnTy(cl_command_queue CommandQueue);
+static clFlushFcnTy *clFlushFcnPtr;
+
+typedef cl_int clFinishFcnTy(cl_command_queue CommandQueue);
+static clFinishFcnTy *clFinishFcnPtr;
+
+typedef cl_int clReleaseKernelFcnTy(cl_kernel Kernel);
+static clReleaseKernelFcnTy *clReleaseKernelFcnPtr;
+
+typedef cl_int clReleaseProgramFcnTy(cl_program Program);
+static clReleaseProgramFcnTy *clReleaseProgramFcnPtr;
+
+typedef cl_int clReleaseMemObjectFcnTy(cl_mem Memobject);
+static clReleaseMemObjectFcnTy *clReleaseMemObjectFcnPtr;
+
+typedef cl_int clReleaseCommandQueueFcnTy(cl_command_queue CommandQueue);
+static clReleaseCommandQueueFcnTy *clReleaseCommandQueueFcnPtr;
+
+typedef cl_int clReleaseContextFcnTy(cl_context Context);
+static clReleaseContextFcnTy *clReleaseContextFcnPtr;
+
+static void *getAPIHandleCL(void *Handle, const char *FuncName) {
+  char *Err;
+  void *FuncPtr;
+  dlerror();
+  FuncPtr = dlsym(Handle, FuncName);
+  if ((Err = dlerror()) != 0) {
+    fprintf(stderr, "Load OpenCL Runtime API failed: %s. \n", Err);
+    return 0;
+  }
+  return FuncPtr;
+}
+
+static int initialDeviceAPILibrariesCL() {
+  HandleOpenCLBeignet = dlopen("/usr/local/lib/beignet/libcl.so", RTLD_LAZY);
+  HandleOpenCL = dlopen("libOpenCL.so", RTLD_LAZY);
+  if (!HandleOpenCL) {
+    fprintf(stderr, "Cannot open library: %s. \n", dlerror());
+    return 0;
+  }
+  return 1;
+}
+
+/* Get function pointer to OpenCL Runtime API.
+ *
+ * Note that compilers conforming to the ISO C standard are required to
+ * generate a warning if a conversion from a void * pointer to a function
+ * pointer is attempted as in the following statements. The warning
+ * of this kind of cast may not be emitted by clang and new versions of gcc
+ * as it is valid on POSIX 2008. For compilers required to generate a warning,
+ * we temporarily disable -Wpedantic, to avoid bloating the output with
+ * unnecessary warnings.
+ *
+ * Reference:
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+static int initialDeviceAPIsCL() {
+  if (initialDeviceAPILibrariesCL() == 0)
+    return 0;
+
+  // FIXME: We are now always selecting the Intel Beignet driver if it is
+  // available on the system, instead of a possible NVIDIA or AMD OpenCL
+  // API. This selection should occurr based on the target architecture
+  // chosen when compiling.
+  void *Handle =
+      (HandleOpenCLBeignet != NULL ? HandleOpenCLBeignet : HandleOpenCL);
+
+  clGetPlatformIDsFcnPtr =
+      (clGetPlatformIDsFcnTy *)getAPIHandleCL(Handle, "clGetPlatformIDs");
+
+  clGetDeviceIDsFcnPtr =
+      (clGetDeviceIDsFcnTy *)getAPIHandleCL(Handle, "clGetDeviceIDs");
+
+  clGetDeviceInfoFcnPtr =
+      (clGetDeviceInfoFcnTy *)getAPIHandleCL(Handle, "clGetDeviceInfo");
+
+  clGetKernelInfoFcnPtr =
+      (clGetKernelInfoFcnTy *)getAPIHandleCL(Handle, "clGetKernelInfo");
+
+  clCreateContextFcnPtr =
+      (clCreateContextFcnTy *)getAPIHandleCL(Handle, "clCreateContext");
+
+  clCreateCommandQueueFcnPtr = (clCreateCommandQueueFcnTy *)getAPIHandleCL(
+      Handle, "clCreateCommandQueue");
+
+  clCreateBufferFcnPtr =
+      (clCreateBufferFcnTy *)getAPIHandleCL(Handle, "clCreateBuffer");
+
+  clEnqueueWriteBufferFcnPtr = (clEnqueueWriteBufferFcnTy *)getAPIHandleCL(
+      Handle, "clEnqueueWriteBuffer");
+
+  if (HandleOpenCLBeignet)
+    clCreateProgramWithLLVMIntelFcnPtr =
+        (clCreateProgramWithLLVMIntelFcnTy *)getAPIHandleCL(
+            Handle, "clCreateProgramWithLLVMIntel");
+
+  clCreateProgramWithBinaryFcnPtr =
+      (clCreateProgramWithBinaryFcnTy *)getAPIHandleCL(
+          Handle, "clCreateProgramWithBinary");
+
+  clBuildProgramFcnPtr =
+      (clBuildProgramFcnTy *)getAPIHandleCL(Handle, "clBuildProgram");
+
+  clCreateKernelFcnPtr =
+      (clCreateKernelFcnTy *)getAPIHandleCL(Handle, "clCreateKernel");
+
+  clSetKernelArgFcnPtr =
+      (clSetKernelArgFcnTy *)getAPIHandleCL(Handle, "clSetKernelArg");
+
+  clEnqueueNDRangeKernelFcnPtr = (clEnqueueNDRangeKernelFcnTy *)getAPIHandleCL(
+      Handle, "clEnqueueNDRangeKernel");
+
+  clEnqueueReadBufferFcnPtr =
+      (clEnqueueReadBufferFcnTy *)getAPIHandleCL(Handle, "clEnqueueReadBuffer");
+
+  clFlushFcnPtr = (clFlushFcnTy *)getAPIHandleCL(Handle, "clFlush");
+
+  clFinishFcnPtr = (clFinishFcnTy *)getAPIHandleCL(Handle, "clFinish");
+
+  clReleaseKernelFcnPtr =
+      (clReleaseKernelFcnTy *)getAPIHandleCL(Handle, "clReleaseKernel");
+
+  clReleaseProgramFcnPtr =
+      (clReleaseProgramFcnTy *)getAPIHandleCL(Handle, "clReleaseProgram");
+
+  clReleaseMemObjectFcnPtr =
+      (clReleaseMemObjectFcnTy *)getAPIHandleCL(Handle, "clReleaseMemObject");
+
+  clReleaseCommandQueueFcnPtr = (clReleaseCommandQueueFcnTy *)getAPIHandleCL(
+      Handle, "clReleaseCommandQueue");
+
+  clReleaseContextFcnPtr =
+      (clReleaseContextFcnTy *)getAPIHandleCL(Handle, "clReleaseContext");
+
+  return 1;
+}
+#pragma GCC diagnostic pop
+
+/* Context and Device. */
+static PollyGPUContext *GlobalContext = NULL;
+static cl_device_id GlobalDeviceID = NULL;
+
+/* Fd-Decl: Print out OpenCL Error codes to human readable strings. */
+static void printOpenCLError(int Error);
+
+static void checkOpenCLError(int Ret, const char *format, ...) {
+  if (Ret == CL_SUCCESS)
+    return;
+
+  printOpenCLError(Ret);
+  va_list args;
+  va_start(args, format);
+  vfprintf(stderr, format, args);
+  va_end(args);
+  exit(-1);
+}
+
+static PollyGPUContext *initContextCL() {
+  dump_function();
+
+  PollyGPUContext *Context;
+
+  cl_platform_id PlatformID = NULL;
+  cl_device_id DeviceID = NULL;
+  cl_uint NumDevicesRet;
+  cl_int Ret;
+
+  char DeviceRevision[256];
+  char DeviceName[256];
+  size_t DeviceRevisionRetSize, DeviceNameRetSize;
+
+  static __thread PollyGPUContext *CurrentContext = NULL;
+
+  if (CurrentContext)
+    return CurrentContext;
+
+  /* Get API handles. */
+  if (initialDeviceAPIsCL() == 0) {
+    fprintf(stderr, "Getting the \"handle\" for the OpenCL Runtime failed.\n");
+    exit(-1);
+  }
+
+  /* Get number of devices that support OpenCL. */
+  static const int NumberOfPlatforms = 1;
+  Ret = clGetPlatformIDsFcnPtr(NumberOfPlatforms, &PlatformID, NULL);
+  checkOpenCLError(Ret, "Failed to get platform IDs.\n");
+  // TODO: Extend to CL_DEVICE_TYPE_ALL?
+  static const int NumberOfDevices = 1;
+  Ret = clGetDeviceIDsFcnPtr(PlatformID, CL_DEVICE_TYPE_GPU, NumberOfDevices,
+                             &DeviceID, &NumDevicesRet);
+  checkOpenCLError(Ret, "Failed to get device IDs.\n");
+
+  GlobalDeviceID = DeviceID;
+  if (NumDevicesRet == 0) {
+    fprintf(stderr, "There is no device supporting OpenCL.\n");
+    exit(-1);
+  }
+
+  /* Get device revision. */
+  Ret =
+      clGetDeviceInfoFcnPtr(DeviceID, CL_DEVICE_VERSION, sizeof(DeviceRevision),
+                            DeviceRevision, &DeviceRevisionRetSize);
+  checkOpenCLError(Ret, "Failed to fetch device revision.\n");
+
+  /* Get device name. */
+  Ret = clGetDeviceInfoFcnPtr(DeviceID, CL_DEVICE_NAME, sizeof(DeviceName),
+                              DeviceName, &DeviceNameRetSize);
+  checkOpenCLError(Ret, "Failed to fetch device name.\n");
+
+  debug_print("> Running on GPU device %d : %s.\n", DeviceID, DeviceName);
+
+  /* Create context on the device. */
+  Context = (PollyGPUContext *)malloc(sizeof(PollyGPUContext));
+  if (Context == 0) {
+    fprintf(stderr, "Allocate memory for Polly GPU context failed.\n");
+    exit(-1);
+  }
+  Context->Context = (OpenCLContext *)malloc(sizeof(OpenCLContext));
+  if (Context->Context == 0) {
+    fprintf(stderr, "Allocate memory for Polly OpenCL context failed.\n");
+    exit(-1);
+  }
+  ((OpenCLContext *)Context->Context)->Context =
+      clCreateContextFcnPtr(NULL, NumDevicesRet, &DeviceID, NULL, NULL, &Ret);
+  checkOpenCLError(Ret, "Failed to create context.\n");
+
+  static const int ExtraProperties = 0;
+  ((OpenCLContext *)Context->Context)->CommandQueue =
+      clCreateCommandQueueFcnPtr(((OpenCLContext *)Context->Context)->Context,
+                                 DeviceID, ExtraProperties, &Ret);
+  checkOpenCLError(Ret, "Failed to create command queue.\n");
+
+  if (CacheMode)
+    CurrentContext = Context;
+
+  GlobalContext = Context;
+  return Context;
+}
+
+static void freeKernelCL(PollyGPUFunction *Kernel) {
+  dump_function();
+
+  if (CacheMode)
+    return;
+
+  if (!GlobalContext) {
+    fprintf(stderr, "GPGPU-code generation not correctly initialized.\n");
+    exit(-1);
+  }
+
+  cl_int Ret;
+  Ret = clFlushFcnPtr(((OpenCLContext *)GlobalContext->Context)->CommandQueue);
+  checkOpenCLError(Ret, "Failed to flush command queue.\n");
+  Ret = clFinishFcnPtr(((OpenCLContext *)GlobalContext->Context)->CommandQueue);
+  checkOpenCLError(Ret, "Failed to finish command queue.\n");
+
+  if (((OpenCLKernel *)Kernel->Kernel)->Kernel) {
+    cl_int Ret =
+        clReleaseKernelFcnPtr(((OpenCLKernel *)Kernel->Kernel)->Kernel);
+    checkOpenCLError(Ret, "Failed to release kernel.\n");
+  }
+
+  if (((OpenCLKernel *)Kernel->Kernel)->Program) {
+    cl_int Ret =
+        clReleaseProgramFcnPtr(((OpenCLKernel *)Kernel->Kernel)->Program);
+    checkOpenCLError(Ret, "Failed to release program.\n");
+  }
+
+  if (Kernel->Kernel)
+    free((OpenCLKernel *)Kernel->Kernel);
+
+  if (Kernel)
+    free(Kernel);
+}
+
+static PollyGPUFunction *getKernelCL(const char *BinaryBuffer,
+                                     const char *KernelName) {
+  dump_function();
+
+  if (!GlobalContext) {
+    fprintf(stderr, "GPGPU-code generation not correctly initialized.\n");
+    exit(-1);
+  }
+
+  static __thread PollyGPUFunction *KernelCache[KERNEL_CACHE_SIZE];
+  static __thread int NextCacheItem = 0;
+
+  for (long i = 0; i < KERNEL_CACHE_SIZE; i++) {
+    // We exploit here the property that all Polly-ACC kernels are allocated
+    // as global constants, hence a pointer comparision is sufficient to
+    // determin equality.
+    if (KernelCache[i] &&
+        ((OpenCLKernel *)KernelCache[i]->Kernel)->BinaryString ==
+            BinaryBuffer) {
+      debug_print("  -> using cached kernel\n");
+      return KernelCache[i];
+    }
+  }
+
+  PollyGPUFunction *Function = malloc(sizeof(PollyGPUFunction));
+  if (Function == 0) {
+    fprintf(stderr, "Allocate memory for Polly GPU function failed.\n");
+    exit(-1);
+  }
+  Function->Kernel = (OpenCLKernel *)malloc(sizeof(OpenCLKernel));
+  if (Function->Kernel == 0) {
+    fprintf(stderr, "Allocate memory for Polly OpenCL kernel failed.\n");
+    exit(-1);
+  }
+
+  if (!GlobalDeviceID) {
+    fprintf(stderr, "GPGPU-code generation not initialized correctly.\n");
+    exit(-1);
+  }
+
+  cl_int Ret;
+
+  if (HandleOpenCLBeignet) {
+    // This is a workaround, since clCreateProgramWithLLVMIntel only
+    // accepts a filename to a valid llvm-ir file as an argument, instead
+    // of accepting the BinaryBuffer directly.
+    char FileName[] = "/tmp/polly_kernelXXXXXX";
+    int File = mkstemp(FileName);
+    write(File, BinaryBuffer, strlen(BinaryBuffer));
+
+    ((OpenCLKernel *)Function->Kernel)->Program =
+        clCreateProgramWithLLVMIntelFcnPtr(
+            ((OpenCLContext *)GlobalContext->Context)->Context, 1,
+            &GlobalDeviceID, FileName, &Ret);
+    checkOpenCLError(Ret, "Failed to create program from llvm.\n");
+    close(File);
+    unlink(FileName);
+  } else {
+    size_t BinarySize = strlen(BinaryBuffer);
+    ((OpenCLKernel *)Function->Kernel)->Program =
+        clCreateProgramWithBinaryFcnPtr(
+            ((OpenCLContext *)GlobalContext->Context)->Context, 1,
+            &GlobalDeviceID, (const size_t *)&BinarySize,
+            (const unsigned char **)&BinaryBuffer, NULL, &Ret);
+    checkOpenCLError(Ret, "Failed to create program from binary.\n");
+  }
+
+  Ret = clBuildProgramFcnPtr(((OpenCLKernel *)Function->Kernel)->Program, 1,
+                             &GlobalDeviceID, NULL, NULL, NULL);
+  checkOpenCLError(Ret, "Failed to build program.\n");
+
+  ((OpenCLKernel *)Function->Kernel)->Kernel = clCreateKernelFcnPtr(
+      ((OpenCLKernel *)Function->Kernel)->Program, KernelName, &Ret);
+  checkOpenCLError(Ret, "Failed to create kernel.\n");
+
+  ((OpenCLKernel *)Function->Kernel)->BinaryString = BinaryBuffer;
+
+  if (CacheMode) {
+    if (KernelCache[NextCacheItem])
+      freeKernelCL(KernelCache[NextCacheItem]);
+
+    KernelCache[NextCacheItem] = Function;
+
+    NextCacheItem = (NextCacheItem + 1) % KERNEL_CACHE_SIZE;
+  }
+
+  return Function;
+}
+
+static void copyFromHostToDeviceCL(void *HostData, PollyGPUDevicePtr *DevData,
+                                   long MemSize) {
+  dump_function();
+
+  if (!GlobalContext) {
+    fprintf(stderr, "GPGPU-code generation not correctly initialized.\n");
+    exit(-1);
+  }
+
+  cl_int Ret;
+  Ret = clEnqueueWriteBufferFcnPtr(
+      ((OpenCLContext *)GlobalContext->Context)->CommandQueue,
+      ((OpenCLDevicePtr *)DevData->DevicePtr)->MemObj, CL_TRUE, 0, MemSize,
+      HostData, 0, NULL, NULL);
+  checkOpenCLError(Ret, "Copying data from host memory to device failed.\n");
+}
+
+static void copyFromDeviceToHostCL(PollyGPUDevicePtr *DevData, void *HostData,
+                                   long MemSize) {
+  dump_function();
+
+  if (!GlobalContext) {
+    fprintf(stderr, "GPGPU-code generation not correctly initialized.\n");
+    exit(-1);
+  }
+
+  cl_int Ret;
+  Ret = clEnqueueReadBufferFcnPtr(
+      ((OpenCLContext *)GlobalContext->Context)->CommandQueue,
+      ((OpenCLDevicePtr *)DevData->DevicePtr)->MemObj, CL_TRUE, 0, MemSize,
+      HostData, 0, NULL, NULL);
+  checkOpenCLError(Ret, "Copying results from device to host memory failed.\n");
+}
+
+static void launchKernelCL(PollyGPUFunction *Kernel, unsigned int GridDimX,
+                           unsigned int GridDimY, unsigned int BlockDimX,
+                           unsigned int BlockDimY, unsigned int BlockDimZ,
+                           void **Parameters) {
+  dump_function();
+
+  cl_int Ret;
+  cl_uint NumArgs;
+
+  if (!GlobalContext) {
+    fprintf(stderr, "GPGPU-code generation not correctly initialized.\n");
+    exit(-1);
+  }
+
+  OpenCLKernel *CLKernel = (OpenCLKernel *)Kernel->Kernel;
+  Ret = clGetKernelInfoFcnPtr(CLKernel->Kernel, CL_KERNEL_NUM_ARGS,
+                              sizeof(cl_uint), &NumArgs, NULL);
+  checkOpenCLError(Ret, "Failed to get number of kernel arguments.\n");
+
+  /* Argument sizes are stored at the end of the Parameters array. */
+  for (cl_uint i = 0; i < NumArgs; i++) {
+    Ret = clSetKernelArgFcnPtr(CLKernel->Kernel, i,
+                               *((int *)Parameters[NumArgs + i]),
+                               (void *)Parameters[i]);
+    checkOpenCLError(Ret, "Failed to set Kernel argument %d.\n", i);
+  }
+
+  unsigned int GridDimZ = 1;
+  size_t GlobalWorkSize[3] = {BlockDimX * GridDimX, BlockDimY * GridDimY,
+                              BlockDimZ * GridDimZ};
+  size_t LocalWorkSize[3] = {BlockDimX, BlockDimY, BlockDimZ};
+
+  static const int WorkDim = 3;
+  OpenCLContext *CLContext = (OpenCLContext *)GlobalContext->Context;
+  Ret = clEnqueueNDRangeKernelFcnPtr(CLContext->CommandQueue, CLKernel->Kernel,
+                                     WorkDim, NULL, GlobalWorkSize,
+                                     LocalWorkSize, 0, NULL, NULL);
+  checkOpenCLError(Ret, "Launching OpenCL kernel failed.\n");
+}
+
+static void freeDeviceMemoryCL(PollyGPUDevicePtr *Allocation) {
+  dump_function();
+
+  OpenCLDevicePtr *DevPtr = (OpenCLDevicePtr *)Allocation->DevicePtr;
+  cl_int Ret = clReleaseMemObjectFcnPtr((cl_mem)DevPtr->MemObj);
+  checkOpenCLError(Ret, "Failed to free device memory.\n");
+
+  free(DevPtr);
+  free(Allocation);
+}
+
+static PollyGPUDevicePtr *allocateMemoryForDeviceCL(long MemSize) {
+  dump_function();
+
+  if (!GlobalContext) {
+    fprintf(stderr, "GPGPU-code generation not correctly initialized.\n");
+    exit(-1);
+  }
+
+  PollyGPUDevicePtr *DevData = malloc(sizeof(PollyGPUDevicePtr));
+  if (DevData == 0) {
+    fprintf(stderr, "Allocate memory for GPU device memory pointer failed.\n");
+    exit(-1);
+  }
+  DevData->DevicePtr = (OpenCLDevicePtr *)malloc(sizeof(OpenCLDevicePtr));
+  if (DevData->DevicePtr == 0) {
+    fprintf(stderr, "Allocate memory for GPU device memory pointer failed.\n");
+    exit(-1);
+  }
+
+  cl_int Ret;
+  ((OpenCLDevicePtr *)DevData->DevicePtr)->MemObj =
+      clCreateBufferFcnPtr(((OpenCLContext *)GlobalContext->Context)->Context,
+                           CL_MEM_READ_WRITE, MemSize, NULL, &Ret);
+  checkOpenCLError(Ret,
+                   "Allocate memory for GPU device memory pointer failed.\n");
+
+  return DevData;
+}
+
+static void *getDevicePtrCL(PollyGPUDevicePtr *Allocation) {
+  dump_function();
+
+  OpenCLDevicePtr *DevPtr = (OpenCLDevicePtr *)Allocation->DevicePtr;
+  return (void *)DevPtr->MemObj;
+}
+
+static void synchronizeDeviceCL() {
+  dump_function();
+
+  if (!GlobalContext) {
+    fprintf(stderr, "GPGPU-code generation not correctly initialized.\n");
+    exit(-1);
+  }
+
+  if (clFinishFcnPtr(((OpenCLContext *)GlobalContext->Context)->CommandQueue) !=
+      CL_SUCCESS) {
+    fprintf(stderr, "Synchronizing device and host memory failed.\n");
+    exit(-1);
+  }
+}
+
+static void freeContextCL(PollyGPUContext *Context) {
+  dump_function();
+
+  cl_int Ret;
+
+  GlobalContext = NULL;
+
+  OpenCLContext *Ctx = (OpenCLContext *)Context->Context;
+  if (Ctx->CommandQueue) {
+    Ret = clReleaseCommandQueueFcnPtr(Ctx->CommandQueue);
+    checkOpenCLError(Ret, "Could not release command queue.\n");
+  }
+
+  if (Ctx->Context) {
+    Ret = clReleaseContextFcnPtr(Ctx->Context);
+    checkOpenCLError(Ret, "Could not release context.\n");
+  }
+
+  free(Ctx);
+  free(Context);
+}
+
+static void printOpenCLError(int Error) {
+
+  switch (Error) {
+  case CL_SUCCESS:
+    // Success, don't print an error.
+    break;
+
+  // JIT/Runtime errors.
+  case CL_DEVICE_NOT_FOUND:
+    fprintf(stderr, "Device not found.\n");
+    break;
+  case CL_DEVICE_NOT_AVAILABLE:
+    fprintf(stderr, "Device not available.\n");
+    break;
+  case CL_COMPILER_NOT_AVAILABLE:
+    fprintf(stderr, "Compiler not available.\n");
+    break;
+  case CL_MEM_OBJECT_ALLOCATION_FAILURE:
+    fprintf(stderr, "Mem object allocation failure.\n");
+    break;
+  case CL_OUT_OF_RESOURCES:
+    fprintf(stderr, "Out of resources.\n");
+    break;
+  case CL_OUT_OF_HOST_MEMORY:
+    fprintf(stderr, "Out of host memory.\n");
+    break;
+  case CL_PROFILING_INFO_NOT_AVAILABLE:
+    fprintf(stderr, "Profiling info not available.\n");
+    break;
+  case CL_MEM_COPY_OVERLAP:
+    fprintf(stderr, "Mem copy overlap.\n");
+    break;
+  case CL_IMAGE_FORMAT_MISMATCH:
+    fprintf(stderr, "Image format mismatch.\n");
+    break;
+  case CL_IMAGE_FORMAT_NOT_SUPPORTED:
+    fprintf(stderr, "Image format not supported.\n");
+    break;
+  case CL_BUILD_PROGRAM_FAILURE:
+    fprintf(stderr, "Build program failure.\n");
+    break;
+  case CL_MAP_FAILURE:
+    fprintf(stderr, "Map failure.\n");
+    break;
+  case CL_MISALIGNED_SUB_BUFFER_OFFSET:
+    fprintf(stderr, "Misaligned sub buffer offset.\n");
+    break;
+  case CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST:
+    fprintf(stderr, "Exec status error for events in wait list.\n");
+    break;
+  case CL_COMPILE_PROGRAM_FAILURE:
+    fprintf(stderr, "Compile program failure.\n");
+    break;
+  case CL_LINKER_NOT_AVAILABLE:
+    fprintf(stderr, "Linker not available.\n");
+    break;
+  case CL_LINK_PROGRAM_FAILURE:
+    fprintf(stderr, "Link program failure.\n");
+    break;
+  case CL_DEVICE_PARTITION_FAILED:
+    fprintf(stderr, "Device partition failed.\n");
+    break;
+  case CL_KERNEL_ARG_INFO_NOT_AVAILABLE:
+    fprintf(stderr, "Kernel arg info not available.\n");
+    break;
+
+  // Compiler errors.
+  case CL_INVALID_VALUE:
+    fprintf(stderr, "Invalid value.\n");
+    break;
+  case CL_INVALID_DEVICE_TYPE:
+    fprintf(stderr, "Invalid device type.\n");
+    break;
+  case CL_INVALID_PLATFORM:
+    fprintf(stderr, "Invalid platform.\n");
+    break;
+  case CL_INVALID_DEVICE:
+    fprintf(stderr, "Invalid device.\n");
+    break;
+  case CL_INVALID_CONTEXT:
+    fprintf(stderr, "Invalid context.\n");
+    break;
+  case CL_INVALID_QUEUE_PROPERTIES:
+    fprintf(stderr, "Invalid queue properties.\n");
+    break;
+  case CL_INVALID_COMMAND_QUEUE:
+    fprintf(stderr, "Invalid command queue.\n");
+    break;
+  case CL_INVALID_HOST_PTR:
+    fprintf(stderr, "Invalid host pointer.\n");
+    break;
+  case CL_INVALID_MEM_OBJECT:
+    fprintf(stderr, "Invalid memory object.\n");
+    break;
+  case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR:
+    fprintf(stderr, "Invalid image format descriptor.\n");
+    break;
+  case CL_INVALID_IMAGE_SIZE:
+    fprintf(stderr, "Invalid image size.\n");
+    break;
+  case CL_INVALID_SAMPLER:
+    fprintf(stderr, "Invalid sampler.\n");
+    break;
+  case CL_INVALID_BINARY:
+    fprintf(stderr, "Invalid binary.\n");
+    break;
+  case CL_INVALID_BUILD_OPTIONS:
+    fprintf(stderr, "Invalid build options.\n");
+    break;
+  case CL_INVALID_PROGRAM:
+    fprintf(stderr, "Invalid program.\n");
+    break;
+  case CL_INVALID_PROGRAM_EXECUTABLE:
+    fprintf(stderr, "Invalid program executable.\n");
+    break;
+  case CL_INVALID_KERNEL_NAME:
+    fprintf(stderr, "Invalid kernel name.\n");
+    break;
+  case CL_INVALID_KERNEL_DEFINITION:
+    fprintf(stderr, "Invalid kernel definition.\n");
+    break;
+  case CL_INVALID_KERNEL:
+    fprintf(stderr, "Invalid kernel.\n");
+    break;
+  case CL_INVALID_ARG_INDEX:
+    fprintf(stderr, "Invalid arg index.\n");
+    break;
+  case CL_INVALID_ARG_VALUE:
+    fprintf(stderr, "Invalid arg value.\n");
+    break;
+  case CL_INVALID_ARG_SIZE:
+    fprintf(stderr, "Invalid arg size.\n");
+    break;
+  case CL_INVALID_KERNEL_ARGS:
+    fprintf(stderr, "Invalid kernel args.\n");
+    break;
+  case CL_INVALID_WORK_DIMENSION:
+    fprintf(stderr, "Invalid work dimension.\n");
+    break;
+  case CL_INVALID_WORK_GROUP_SIZE:
+    fprintf(stderr, "Invalid work group size.\n");
+    break;
+  case CL_INVALID_WORK_ITEM_SIZE:
+    fprintf(stderr, "Invalid work item size.\n");
+    break;
+  case CL_INVALID_GLOBAL_OFFSET:
+    fprintf(stderr, "Invalid global offset.\n");
+    break;
+  case CL_INVALID_EVENT_WAIT_LIST:
+    fprintf(stderr, "Invalid event wait list.\n");
+    break;
+  case CL_INVALID_EVENT:
+    fprintf(stderr, "Invalid event.\n");
+    break;
+  case CL_INVALID_OPERATION:
+    fprintf(stderr, "Invalid operation.\n");
+    break;
+  case CL_INVALID_GL_OBJECT:
+    fprintf(stderr, "Invalid GL object.\n");
+    break;
+  case CL_INVALID_BUFFER_SIZE:
+    fprintf(stderr, "Invalid buffer size.\n");
+    break;
+  case CL_INVALID_MIP_LEVEL:
+    fprintf(stderr, "Invalid mip level.\n");
+    break;
+  case CL_INVALID_GLOBAL_WORK_SIZE:
+    fprintf(stderr, "Invalid global work size.\n");
+    break;
+  case CL_INVALID_PROPERTY:
+    fprintf(stderr, "Invalid property.\n");
+    break;
+  case CL_INVALID_IMAGE_DESCRIPTOR:
+    fprintf(stderr, "Invalid image descriptor.\n");
+    break;
+  case CL_INVALID_COMPILER_OPTIONS:
+    fprintf(stderr, "Invalid compiler options.\n");
+    break;
+  case CL_INVALID_LINKER_OPTIONS:
+    fprintf(stderr, "Invalid linker options.\n");
+    break;
+  case CL_INVALID_DEVICE_PARTITION_COUNT:
+    fprintf(stderr, "Invalid device partition count.\n");
+    break;
+  case -69: // OpenCL 2.0 Code for CL_INVALID_PIPE_SIZE
+    fprintf(stderr, "Invalid pipe size.\n");
+    break;
+  case -70: // OpenCL 2.0 Code for CL_INVALID_DEVICE_QUEUE
+    fprintf(stderr, "Invalid device queue.\n");
+    break;
+
+  // NVIDIA specific error.
+  case -9999:
+    fprintf(stderr, "NVIDIA invalid read or write buffer.\n");
+    break;
+
+  default:
+    fprintf(stderr, "Unknown error code!\n");
+    break;
+  }
+}
+
+#endif /* HAS_LIBOPENCL */
+/******************************************************************************/
+/*                                   CUDA                                     */
+/******************************************************************************/
+#ifdef HAS_LIBCUDART
+
+struct CUDAContextT {
+  CUcontext Cuda;
+};
+
+struct CUDAKernelT {
+  CUfunction Cuda;
+  CUmodule CudaModule;
+  const char *BinaryString;
+};
+
+struct CUDADevicePtrT {
+  CUdeviceptr Cuda;
+};
+
+/* Dynamic library handles for the CUDA and CUDA runtime library. */
+static void *HandleCuda;
+static void *HandleCudaRT;
+
+/* Type-defines of function pointer to CUDA driver APIs. */
+typedef CUresult CUDAAPI CuMemAllocFcnTy(CUdeviceptr *, size_t);
+static CuMemAllocFcnTy *CuMemAllocFcnPtr;
+
+typedef CUresult CUDAAPI CuMemAllocManagedFcnTy(CUdeviceptr *, size_t,
+                                                unsigned int);
+static CuMemAllocManagedFcnTy *CuMemAllocManagedFcnPtr;
+
+typedef CUresult CUDAAPI CuLaunchKernelFcnTy(
+    CUfunction F, unsigned int GridDimX, unsigned int GridDimY,
+    unsigned int gridDimZ, unsigned int blockDimX, unsigned int BlockDimY,
+    unsigned int BlockDimZ, unsigned int SharedMemBytes, CUstream HStream,
+    void **KernelParams, void **Extra);
+static CuLaunchKernelFcnTy *CuLaunchKernelFcnPtr;
+
+typedef CUresult CUDAAPI CuMemcpyDtoHFcnTy(void *, CUdeviceptr, size_t);
+static CuMemcpyDtoHFcnTy *CuMemcpyDtoHFcnPtr;
+
+typedef CUresult CUDAAPI CuMemcpyHtoDFcnTy(CUdeviceptr, const void *, size_t);
+static CuMemcpyHtoDFcnTy *CuMemcpyHtoDFcnPtr;
+
+typedef CUresult CUDAAPI CuMemFreeFcnTy(CUdeviceptr);
+static CuMemFreeFcnTy *CuMemFreeFcnPtr;
+
+typedef CUresult CUDAAPI CuModuleUnloadFcnTy(CUmodule);
+static CuModuleUnloadFcnTy *CuModuleUnloadFcnPtr;
+
+typedef CUresult CUDAAPI CuProfilerStopFcnTy();
+static CuProfilerStopFcnTy *CuProfilerStopFcnPtr;
+
+typedef CUresult CUDAAPI CuCtxDestroyFcnTy(CUcontext);
+static CuCtxDestroyFcnTy *CuCtxDestroyFcnPtr;
+
+typedef CUresult CUDAAPI CuInitFcnTy(unsigned int);
+static CuInitFcnTy *CuInitFcnPtr;
+
+typedef CUresult CUDAAPI CuDeviceGetCountFcnTy(int *);
+static CuDeviceGetCountFcnTy *CuDeviceGetCountFcnPtr;
+
+typedef CUresult CUDAAPI CuCtxCreateFcnTy(CUcontext *, unsigned int, CUdevice);
+static CuCtxCreateFcnTy *CuCtxCreateFcnPtr;
+
+typedef CUresult CUDAAPI CuCtxGetCurrentFcnTy(CUcontext *);
+static CuCtxGetCurrentFcnTy *CuCtxGetCurrentFcnPtr;
+
+typedef CUresult CUDAAPI CuDeviceGetFcnTy(CUdevice *, int);
+static CuDeviceGetFcnTy *CuDeviceGetFcnPtr;
+
+typedef CUresult CUDAAPI CuModuleLoadDataExFcnTy(CUmodule *, const void *,
+                                                 unsigned int, CUjit_option *,
+                                                 void **);
+static CuModuleLoadDataExFcnTy *CuModuleLoadDataExFcnPtr;
+
+typedef CUresult CUDAAPI CuModuleLoadDataFcnTy(CUmodule *Module,
+                                               const void *Image);
+static CuModuleLoadDataFcnTy *CuModuleLoadDataFcnPtr;
+
+typedef CUresult CUDAAPI CuModuleGetFunctionFcnTy(CUfunction *, CUmodule,
+                                                  const char *);
+static CuModuleGetFunctionFcnTy *CuModuleGetFunctionFcnPtr;
+
+typedef CUresult CUDAAPI CuDeviceComputeCapabilityFcnTy(int *, int *, CUdevice);
+static CuDeviceComputeCapabilityFcnTy *CuDeviceComputeCapabilityFcnPtr;
+
+typedef CUresult CUDAAPI CuDeviceGetNameFcnTy(char *, int, CUdevice);
+static CuDeviceGetNameFcnTy *CuDeviceGetNameFcnPtr;
+
+typedef CUresult CUDAAPI CuLinkAddDataFcnTy(CUlinkState State,
+                                            CUjitInputType Type, void *Data,
+                                            size_t Size, const char *Name,
+                                            unsigned int NumOptions,
+                                            CUjit_option *Options,
+                                            void **OptionValues);
+static CuLinkAddDataFcnTy *CuLinkAddDataFcnPtr;
+
+typedef CUresult CUDAAPI CuLinkCreateFcnTy(unsigned int NumOptions,
+                                           CUjit_option *Options,
+                                           void **OptionValues,
+                                           CUlinkState *StateOut);
+static CuLinkCreateFcnTy *CuLinkCreateFcnPtr;
+
+typedef CUresult CUDAAPI CuLinkCompleteFcnTy(CUlinkState State, void **CubinOut,
+                                             size_t *SizeOut);
+static CuLinkCompleteFcnTy *CuLinkCompleteFcnPtr;
+
+typedef CUresult CUDAAPI CuLinkDestroyFcnTy(CUlinkState State);
+static CuLinkDestroyFcnTy *CuLinkDestroyFcnPtr;
+
+typedef CUresult CUDAAPI CuCtxSynchronizeFcnTy();
+static CuCtxSynchronizeFcnTy *CuCtxSynchronizeFcnPtr;
+
+/* Type-defines of function pointer ot CUDA runtime APIs. */
+typedef cudaError_t CUDARTAPI CudaThreadSynchronizeFcnTy(void);
+static CudaThreadSynchronizeFcnTy *CudaThreadSynchronizeFcnPtr;
+
+static void *getAPIHandleCUDA(void *Handle, const char *FuncName) {
+  char *Err;
+  void *FuncPtr;
+  dlerror();
+  FuncPtr = dlsym(Handle, FuncName);
+  if ((Err = dlerror()) != 0) {
+    fprintf(stderr, "Load CUDA driver API failed: %s. \n", Err);
+    return 0;
+  }
+  return FuncPtr;
+}
+
+static int initialDeviceAPILibrariesCUDA() {
+  HandleCuda = dlopen("libcuda.so", RTLD_LAZY);
+  if (!HandleCuda) {
+    fprintf(stderr, "Cannot open library: %s. \n", dlerror());
+    return 0;
+  }
+
+  HandleCudaRT = dlopen("libcudart.so", RTLD_LAZY);
+  if (!HandleCudaRT) {
+    fprintf(stderr, "Cannot open library: %s. \n", dlerror());
+    return 0;
+  }
+
+  return 1;
+}
+
+/* Get function pointer to CUDA Driver APIs.
+ *
+ * Note that compilers conforming to the ISO C standard are required to
+ * generate a warning if a conversion from a void * pointer to a function
+ * pointer is attempted as in the following statements. The warning
+ * of this kind of cast may not be emitted by clang and new versions of gcc
+ * as it is valid on POSIX 2008. For compilers required to generate a warning,
+ * we temporarily disable -Wpedantic, to avoid bloating the output with
+ * unnecessary warnings.
+ *
+ * Reference:
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+static int initialDeviceAPIsCUDA() {
+  if (initialDeviceAPILibrariesCUDA() == 0)
+    return 0;
+
+  CuLaunchKernelFcnPtr =
+      (CuLaunchKernelFcnTy *)getAPIHandleCUDA(HandleCuda, "cuLaunchKernel");
+
+  CuMemAllocFcnPtr =
+      (CuMemAllocFcnTy *)getAPIHandleCUDA(HandleCuda, "cuMemAlloc_v2");
+
+  CuMemAllocManagedFcnPtr = (CuMemAllocManagedFcnTy *)getAPIHandleCUDA(
+      HandleCuda, "cuMemAllocManaged");
+
+  CuMemFreeFcnPtr =
+      (CuMemFreeFcnTy *)getAPIHandleCUDA(HandleCuda, "cuMemFree_v2");
+
+  CuMemcpyDtoHFcnPtr =
+      (CuMemcpyDtoHFcnTy *)getAPIHandleCUDA(HandleCuda, "cuMemcpyDtoH_v2");
+
+  CuMemcpyHtoDFcnPtr =
+      (CuMemcpyHtoDFcnTy *)getAPIHandleCUDA(HandleCuda, "cuMemcpyHtoD_v2");
+
+  CuModuleUnloadFcnPtr =
+      (CuModuleUnloadFcnTy *)getAPIHandleCUDA(HandleCuda, "cuModuleUnload");
+
+  CuProfilerStopFcnPtr =
+      (CuProfilerStopFcnTy *)getAPIHandleCUDA(HandleCuda, "cuProfilerStop");
+
+  CuCtxDestroyFcnPtr =
+      (CuCtxDestroyFcnTy *)getAPIHandleCUDA(HandleCuda, "cuCtxDestroy");
+
+  CuInitFcnPtr = (CuInitFcnTy *)getAPIHandleCUDA(HandleCuda, "cuInit");
+
+  CuDeviceGetCountFcnPtr =
+      (CuDeviceGetCountFcnTy *)getAPIHandleCUDA(HandleCuda, "cuDeviceGetCount");
+
+  CuDeviceGetFcnPtr =
+      (CuDeviceGetFcnTy *)getAPIHandleCUDA(HandleCuda, "cuDeviceGet");
+
+  CuCtxCreateFcnPtr =
+      (CuCtxCreateFcnTy *)getAPIHandleCUDA(HandleCuda, "cuCtxCreate_v2");
+
+  CuCtxGetCurrentFcnPtr =
+      (CuCtxGetCurrentFcnTy *)getAPIHandleCUDA(HandleCuda, "cuCtxGetCurrent");
+
+  CuModuleLoadDataExFcnPtr = (CuModuleLoadDataExFcnTy *)getAPIHandleCUDA(
+      HandleCuda, "cuModuleLoadDataEx");
+
+  CuModuleLoadDataFcnPtr =
+      (CuModuleLoadDataFcnTy *)getAPIHandleCUDA(HandleCuda, "cuModuleLoadData");
+
+  CuModuleGetFunctionFcnPtr = (CuModuleGetFunctionFcnTy *)getAPIHandleCUDA(
+      HandleCuda, "cuModuleGetFunction");
+
+  CuDeviceComputeCapabilityFcnPtr =
+      (CuDeviceComputeCapabilityFcnTy *)getAPIHandleCUDA(
+          HandleCuda, "cuDeviceComputeCapability");
+
+  CuDeviceGetNameFcnPtr =
+      (CuDeviceGetNameFcnTy *)getAPIHandleCUDA(HandleCuda, "cuDeviceGetName");
+
+  CuLinkAddDataFcnPtr =
+      (CuLinkAddDataFcnTy *)getAPIHandleCUDA(HandleCuda, "cuLinkAddData");
+
+  CuLinkCreateFcnPtr =
+      (CuLinkCreateFcnTy *)getAPIHandleCUDA(HandleCuda, "cuLinkCreate");
+
+  CuLinkCompleteFcnPtr =
+      (CuLinkCompleteFcnTy *)getAPIHandleCUDA(HandleCuda, "cuLinkComplete");
+
+  CuLinkDestroyFcnPtr =
+      (CuLinkDestroyFcnTy *)getAPIHandleCUDA(HandleCuda, "cuLinkDestroy");
+
+  CuCtxSynchronizeFcnPtr =
+      (CuCtxSynchronizeFcnTy *)getAPIHandleCUDA(HandleCuda, "cuCtxSynchronize");
+
+  /* Get function pointer to CUDA Runtime APIs. */
+  CudaThreadSynchronizeFcnPtr = (CudaThreadSynchronizeFcnTy *)getAPIHandleCUDA(
+      HandleCudaRT, "cudaThreadSynchronize");
+
+  return 1;
+}
+#pragma GCC diagnostic pop
+
+static PollyGPUContext *initContextCUDA() {
+  dump_function();
+  PollyGPUContext *Context;
+  CUdevice Device;
+
+  int Major = 0, Minor = 0, DeviceID = 0;
+  char DeviceName[256];
+  int DeviceCount = 0;
+
+  static __thread PollyGPUContext *CurrentContext = NULL;
+
+  if (CurrentContext)
+    return CurrentContext;
+
+  /* Get API handles. */
+  if (initialDeviceAPIsCUDA() == 0) {
+    fprintf(stderr, "Getting the \"handle\" for the CUDA driver API failed.\n");
+    exit(-1);
+  }
+
+  if (CuInitFcnPtr(0) != CUDA_SUCCESS) {
+    fprintf(stderr, "Initializing the CUDA driver API failed.\n");
+    exit(-1);
+  }
+
+  /* Get number of devices that supports CUDA. */
+  CuDeviceGetCountFcnPtr(&DeviceCount);
+  if (DeviceCount == 0) {
+    fprintf(stderr, "There is no device supporting CUDA.\n");
+    exit(-1);
+  }
+
+  CuDeviceGetFcnPtr(&Device, 0);
+
+  /* Get compute capabilities and the device name. */
+  CuDeviceComputeCapabilityFcnPtr(&Major, &Minor, Device);
+  CuDeviceGetNameFcnPtr(DeviceName, 256, Device);
+  debug_print("> Running on GPU device %d : %s.\n", DeviceID, DeviceName);
+
+  /* Create context on the device. */
+  Context = (PollyGPUContext *)malloc(sizeof(PollyGPUContext));
+  if (Context == 0) {
+    fprintf(stderr, "Allocate memory for Polly GPU context failed.\n");
+    exit(-1);
+  }
+  Context->Context = malloc(sizeof(CUDAContext));
+  if (Context->Context == 0) {
+    fprintf(stderr, "Allocate memory for Polly CUDA context failed.\n");
+    exit(-1);
+  }
+
+  // In cases where managed memory is used, it is quite likely that
+  // `cudaMallocManaged` / `polly_mallocManaged` was called before
+  // `polly_initContext` was called.
+  //
+  // If `polly_initContext` calls `CuCtxCreate` when there already was a
+  // pre-existing context created by the runtime API, this causes code running
+  // on P100 to hang. So, we query for a pre-existing context to try and use.
+  // If there is no pre-existing context, we create a new context
+
+  // The possible pre-existing context from previous runtime API calls.
+  CUcontext MaybeRuntimeAPIContext;
+  if (CuCtxGetCurrentFcnPtr(&MaybeRuntimeAPIContext) != CUDA_SUCCESS) {
+    fprintf(stderr, "cuCtxGetCurrent failed.\n");
+    exit(-1);
+  }
+
+  // There was no previous context, initialise it.
+  if (MaybeRuntimeAPIContext == NULL) {
+    if (CuCtxCreateFcnPtr(&(((CUDAContext *)Context->Context)->Cuda), 0,
+                          Device) != CUDA_SUCCESS) {
+      fprintf(stderr, "cuCtxCreateFcnPtr failed.\n");
+      exit(-1);
+    }
+  } else {
+    ((CUDAContext *)Context->Context)->Cuda = MaybeRuntimeAPIContext;
+  }
+
+  if (CacheMode)
+    CurrentContext = Context;
+
+  return Context;
+}
+
+static void freeKernelCUDA(PollyGPUFunction *Kernel) {
+  dump_function();
+
+  if (CacheMode)
+    return;
+
+  if (((CUDAKernel *)Kernel->Kernel)->CudaModule)
+    CuModuleUnloadFcnPtr(((CUDAKernel *)Kernel->Kernel)->CudaModule);
+
+  if (Kernel->Kernel)
+    free((CUDAKernel *)Kernel->Kernel);
+
+  if (Kernel)
+    free(Kernel);
+}
+
+static PollyGPUFunction *getKernelCUDA(const char *BinaryBuffer,
+                                       const char *KernelName) {
+  dump_function();
+
+  static __thread PollyGPUFunction *KernelCache[KERNEL_CACHE_SIZE];
+  static __thread int NextCacheItem = 0;
+
+  for (long i = 0; i < KERNEL_CACHE_SIZE; i++) {
+    // We exploit here the property that all Polly-ACC kernels are allocated
+    // as global constants, hence a pointer comparision is sufficient to
+    // determin equality.
+    if (KernelCache[i] &&
+        ((CUDAKernel *)KernelCache[i]->Kernel)->BinaryString == BinaryBuffer) {
+      debug_print("  -> using cached kernel\n");
+      return KernelCache[i];
+    }
+  }
+
+  PollyGPUFunction *Function = malloc(sizeof(PollyGPUFunction));
+  if (Function == 0) {
+    fprintf(stderr, "Allocate memory for Polly GPU function failed.\n");
+    exit(-1);
+  }
+  Function->Kernel = (CUDAKernel *)malloc(sizeof(CUDAKernel));
+  if (Function->Kernel == 0) {
+    fprintf(stderr, "Allocate memory for Polly CUDA function failed.\n");
+    exit(-1);
+  }
+
+  CUresult Res;
+  CUlinkState LState;
+  CUjit_option Options[6];
+  void *OptionVals[6];
+  float Walltime = 0;
+  unsigned long LogSize = 8192;
+  char ErrorLog[8192], InfoLog[8192];
+  void *CuOut;
+  size_t OutSize;
+
+  // Setup linker options
+  // Return walltime from JIT compilation
+  Options[0] = CU_JIT_WALL_TIME;
+  OptionVals[0] = (void *)&Walltime;
+  // Pass a buffer for info messages
+  Options[1] = CU_JIT_INFO_LOG_BUFFER;
+  OptionVals[1] = (void *)InfoLog;
+  // Pass the size of the info buffer
+  Options[2] = CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES;
+  OptionVals[2] = (void *)LogSize;
+  // Pass a buffer for error message
+  Options[3] = CU_JIT_ERROR_LOG_BUFFER;
+  OptionVals[3] = (void *)ErrorLog;
+  // Pass the size of the error buffer
+  Options[4] = CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES;
+  OptionVals[4] = (void *)LogSize;
+  // Make the linker verbose
+  Options[5] = CU_JIT_LOG_VERBOSE;
+  OptionVals[5] = (void *)1;
+
+  memset(ErrorLog, 0, sizeof(ErrorLog));
+
+  CuLinkCreateFcnPtr(6, Options, OptionVals, &LState);
+  Res = CuLinkAddDataFcnPtr(LState, CU_JIT_INPUT_PTX, (void *)BinaryBuffer,
+                            strlen(BinaryBuffer) + 1, 0, 0, 0, 0);
+  if (Res != CUDA_SUCCESS) {
+    fprintf(stderr, "PTX Linker Error:\n%s\n%s", ErrorLog, InfoLog);
+    exit(-1);
+  }
+
+  Res = CuLinkCompleteFcnPtr(LState, &CuOut, &OutSize);
+  if (Res != CUDA_SUCCESS) {
+    fprintf(stderr, "Complete ptx linker step failed.\n");
+    fprintf(stderr, "\n%s\n", ErrorLog);
+    exit(-1);
+  }
+
+  debug_print("CUDA Link Completed in %fms. Linker Output:\n%s\n", Walltime,
+              InfoLog);
+
+  Res = CuModuleLoadDataFcnPtr(&(((CUDAKernel *)Function->Kernel)->CudaModule),
+                               CuOut);
+  if (Res != CUDA_SUCCESS) {
+    fprintf(stderr, "Loading ptx assembly text failed.\n");
+    exit(-1);
+  }
+
+  Res = CuModuleGetFunctionFcnPtr(&(((CUDAKernel *)Function->Kernel)->Cuda),
+                                  ((CUDAKernel *)Function->Kernel)->CudaModule,
+                                  KernelName);
+  if (Res != CUDA_SUCCESS) {
+    fprintf(stderr, "Loading kernel function failed.\n");
+    exit(-1);
+  }
+
+  CuLinkDestroyFcnPtr(LState);
+
+  ((CUDAKernel *)Function->Kernel)->BinaryString = BinaryBuffer;
+
+  if (CacheMode) {
+    if (KernelCache[NextCacheItem])
+      freeKernelCUDA(KernelCache[NextCacheItem]);
+
+    KernelCache[NextCacheItem] = Function;
+
+    NextCacheItem = (NextCacheItem + 1) % KERNEL_CACHE_SIZE;
+  }
+
+  return Function;
+}
+
+static void synchronizeDeviceCUDA() {
+  dump_function();
+  if (CuCtxSynchronizeFcnPtr() != CUDA_SUCCESS) {
+    fprintf(stderr, "Synchronizing device and host memory failed.\n");
+    exit(-1);
+  }
+}
+
+static void copyFromHostToDeviceCUDA(void *HostData, PollyGPUDevicePtr *DevData,
+                                     long MemSize) {
+  dump_function();
+
+  CUdeviceptr CuDevData = ((CUDADevicePtr *)DevData->DevicePtr)->Cuda;
+  CuMemcpyHtoDFcnPtr(CuDevData, HostData, MemSize);
+}
+
+static void copyFromDeviceToHostCUDA(PollyGPUDevicePtr *DevData, void *HostData,
+                                     long MemSize) {
+  dump_function();
+
+  if (CuMemcpyDtoHFcnPtr(HostData, ((CUDADevicePtr *)DevData->DevicePtr)->Cuda,
+                         MemSize) != CUDA_SUCCESS) {
+    fprintf(stderr, "Copying results from device to host memory failed.\n");
+    exit(-1);
+  }
+}
+
+static void launchKernelCUDA(PollyGPUFunction *Kernel, unsigned int GridDimX,
+                             unsigned int GridDimY, unsigned int BlockDimX,
+                             unsigned int BlockDimY, unsigned int BlockDimZ,
+                             void **Parameters) {
+  dump_function();
+
+  unsigned GridDimZ = 1;
+  unsigned int SharedMemBytes = CU_SHARED_MEM_CONFIG_DEFAULT_BANK_SIZE;
+  CUstream Stream = 0;
+  void **Extra = 0;
+
+  CUresult Res;
+  Res =
+      CuLaunchKernelFcnPtr(((CUDAKernel *)Kernel->Kernel)->Cuda, GridDimX,
+                           GridDimY, GridDimZ, BlockDimX, BlockDimY, BlockDimZ,
+                           SharedMemBytes, Stream, Parameters, Extra);
+  if (Res != CUDA_SUCCESS) {
+    fprintf(stderr, "Launching CUDA kernel failed.\n");
+    exit(-1);
+  }
+}
+
+// Maximum number of managed memory pointers.
+#define DEFAULT_MAX_POINTERS 4000
+// For the rationale behing a list of free pointers, see `polly_freeManaged`.
+void **g_managedptrs;
+unsigned long long g_nmanagedptrs = 0;
+unsigned long long g_maxmanagedptrs = 0;
+
+__attribute__((constructor)) static void initManagedPtrsBuffer() {
+  g_maxmanagedptrs = DEFAULT_MAX_POINTERS;
+  const char *maxManagedPointersString = getenv("POLLY_MAX_MANAGED_POINTERS");
+  if (maxManagedPointersString)
+    g_maxmanagedptrs = atoll(maxManagedPointersString);
+
+  g_managedptrs = (void **)malloc(sizeof(void *) * g_maxmanagedptrs);
+}
+
+// Add a pointer as being allocated by cuMallocManaged
+void addManagedPtr(void *mem) {
+  assert(g_maxmanagedptrs > 0 && "g_maxmanagedptrs was set to 0!");
+  assert(g_nmanagedptrs < g_maxmanagedptrs &&
+         "We have hit the maximum number of "
+         "managed pointers allowed. Set the "
+         "POLLY_MAX_MANAGED_POINTERS environment variable. ");
+  g_managedptrs[g_nmanagedptrs++] = mem;
+}
+
+int isManagedPtr(void *mem) {
+  for (unsigned long long i = 0; i < g_nmanagedptrs; i++) {
+    if (g_managedptrs[i] == mem)
+      return 1;
+  }
+  return 0;
+}
+
+void freeManagedCUDA(void *mem) {
+  dump_function();
+
+  // In a real-world program this was used (COSMO), there were more `free`
+  // calls in the original source than `malloc` calls. Hence, replacing all
+  // `free`s with `cudaFree` does not work, since we would try to free
+  // 'illegal' memory.
+  // As a quick fix, we keep a free list and check if `mem` is a managed memory
+  // pointer. If it is, we call `cudaFree`.
+  // If not, we pass it along to the underlying allocator.
+  // This is a hack, and can be removed if the underlying issue is fixed.
+  if (isManagedPtr(mem)) {
+    if (CuMemFreeFcnPtr((size_t)mem) != CUDA_SUCCESS) {
+      fprintf(stderr, "cudaFree failed.\n");
+      exit(-1);
+    }
+    return;
+  } else {
+    free(mem);
+  }
+}
+
+void *mallocManagedCUDA(size_t size) {
+  // Note: [Size 0 allocations]
+  // Sometimes, some runtime computation of size could create a size of 0
+  // for an allocation. In these cases, we do not wish to fail.
+  // The CUDA API fails on size 0 allocations.
+  // So, we allocate size a minimum of size 1.
+  if (!size && DebugMode)
+    fprintf(stderr, "cudaMallocManaged called with size 0. "
+                    "Promoting to size 1");
+  size = max(size, 1);
+  PollyGPUContext *_ = polly_initContextCUDA();
+  assert(_ && "polly_initContextCUDA failed");
+
+  void *newMemPtr;
+  const CUresult Res = CuMemAllocManagedFcnPtr((CUdeviceptr *)&newMemPtr, size,
+                                               CU_MEM_ATTACH_GLOBAL);
+  if (Res != CUDA_SUCCESS) {
+    fprintf(stderr, "cudaMallocManaged failed for size: %zu\n", size);
+    exit(-1);
+  }
+  addManagedPtr(newMemPtr);
+  return newMemPtr;
+}
+
+static void freeDeviceMemoryCUDA(PollyGPUDevicePtr *Allocation) {
+  dump_function();
+  CUDADevicePtr *DevPtr = (CUDADevicePtr *)Allocation->DevicePtr;
+  CuMemFreeFcnPtr((CUdeviceptr)DevPtr->Cuda);
+  free(DevPtr);
+  free(Allocation);
+}
+
+static PollyGPUDevicePtr *allocateMemoryForDeviceCUDA(long MemSize) {
+  if (!MemSize && DebugMode)
+    fprintf(stderr, "allocateMemoryForDeviceCUDA called with size 0. "
+                    "Promoting to size 1");
+  // see: [Size 0 allocations]
+  MemSize = max(MemSize, 1);
+  dump_function();
+
+  PollyGPUDevicePtr *DevData = malloc(sizeof(PollyGPUDevicePtr));
+  if (DevData == 0) {
+    fprintf(stderr,
+            "Allocate memory for GPU device memory pointer failed."
+            " Line: %d | Size: %ld\n",
+            __LINE__, MemSize);
+    exit(-1);
+  }
+  DevData->DevicePtr = (CUDADevicePtr *)malloc(sizeof(CUDADevicePtr));
+  if (DevData->DevicePtr == 0) {
+    fprintf(stderr,
+            "Allocate memory for GPU device memory pointer failed."
+            " Line: %d | Size: %ld\n",
+            __LINE__, MemSize);
+    exit(-1);
+  }
+
+  CUresult Res =
+      CuMemAllocFcnPtr(&(((CUDADevicePtr *)DevData->DevicePtr)->Cuda), MemSize);
+
+  if (Res != CUDA_SUCCESS) {
+    fprintf(stderr,
+            "Allocate memory for GPU device memory pointer failed."
+            " Line: %d | Size: %ld\n",
+            __LINE__, MemSize);
+    exit(-1);
+  }
+
+  return DevData;
+}
+
+static void *getDevicePtrCUDA(PollyGPUDevicePtr *Allocation) {
+  dump_function();
+
+  CUDADevicePtr *DevPtr = (CUDADevicePtr *)Allocation->DevicePtr;
+  return (void *)DevPtr->Cuda;
+}
+
+static void freeContextCUDA(PollyGPUContext *Context) {
+  dump_function();
+
+  CUDAContext *Ctx = (CUDAContext *)Context->Context;
+  if (Ctx->Cuda) {
+    CuProfilerStopFcnPtr();
+    CuCtxDestroyFcnPtr(Ctx->Cuda);
+    free(Ctx);
+    free(Context);
+  }
+
+  dlclose(HandleCuda);
+  dlclose(HandleCudaRT);
+}
+
+#endif /* HAS_LIBCUDART */
+/******************************************************************************/
+/*                                    API                                     */
+/******************************************************************************/
+
+PollyGPUContext *polly_initContext() {
+  DebugMode = getenv("POLLY_DEBUG") != 0;
+  CacheMode = getenv("POLLY_NOCACHE") == 0;
+
+  dump_function();
+
+  PollyGPUContext *Context;
+
+  switch (Runtime) {
+#ifdef HAS_LIBCUDART
+  case RUNTIME_CUDA:
+    Context = initContextCUDA();
+    break;
+#endif /* HAS_LIBCUDART */
+#ifdef HAS_LIBOPENCL
+  case RUNTIME_CL:
+    Context = initContextCL();
+    break;
+#endif /* HAS_LIBOPENCL */
+  default:
+    err_runtime();
+  }
+
+  return Context;
+}
+
+void polly_freeKernel(PollyGPUFunction *Kernel) {
+  dump_function();
+
+  switch (Runtime) {
+#ifdef HAS_LIBCUDART
+  case RUNTIME_CUDA:
+    freeKernelCUDA(Kernel);
+    break;
+#endif /* HAS_LIBCUDART */
+#ifdef HAS_LIBOPENCL
+  case RUNTIME_CL:
+    freeKernelCL(Kernel);
+    break;
+#endif /* HAS_LIBOPENCL */
+  default:
+    err_runtime();
+  }
+}
+
+PollyGPUFunction *polly_getKernel(const char *BinaryBuffer,
+                                  const char *KernelName) {
+  dump_function();
+
+  PollyGPUFunction *Function;
+
+  switch (Runtime) {
+#ifdef HAS_LIBCUDART
+  case RUNTIME_CUDA:
+    Function = getKernelCUDA(BinaryBuffer, KernelName);
+    break;
+#endif /* HAS_LIBCUDART */
+#ifdef HAS_LIBOPENCL
+  case RUNTIME_CL:
+    Function = getKernelCL(BinaryBuffer, KernelName);
+    break;
+#endif /* HAS_LIBOPENCL */
+  default:
+    err_runtime();
+  }
+
+  return Function;
+}
+
+void polly_copyFromHostToDevice(void *HostData, PollyGPUDevicePtr *DevData,
+                                long MemSize) {
+  dump_function();
+
+  switch (Runtime) {
+#ifdef HAS_LIBCUDART
+  case RUNTIME_CUDA:
+    copyFromHostToDeviceCUDA(HostData, DevData, MemSize);
+    break;
+#endif /* HAS_LIBCUDART */
+#ifdef HAS_LIBOPENCL
+  case RUNTIME_CL:
+    copyFromHostToDeviceCL(HostData, DevData, MemSize);
+    break;
+#endif /* HAS_LIBOPENCL */
+  default:
+    err_runtime();
+  }
+}
+
+void polly_copyFromDeviceToHost(PollyGPUDevicePtr *DevData, void *HostData,
+                                long MemSize) {
+  dump_function();
+
+  switch (Runtime) {
+#ifdef HAS_LIBCUDART
+  case RUNTIME_CUDA:
+    copyFromDeviceToHostCUDA(DevData, HostData, MemSize);
+    break;
+#endif /* HAS_LIBCUDART */
+#ifdef HAS_LIBOPENCL
+  case RUNTIME_CL:
+    copyFromDeviceToHostCL(DevData, HostData, MemSize);
+    break;
+#endif /* HAS_LIBOPENCL */
+  default:
+    err_runtime();
+  }
+}
+
+void polly_launchKernel(PollyGPUFunction *Kernel, unsigned int GridDimX,
+                        unsigned int GridDimY, unsigned int BlockDimX,
+                        unsigned int BlockDimY, unsigned int BlockDimZ,
+                        void **Parameters) {
+  dump_function();
+
+  switch (Runtime) {
+#ifdef HAS_LIBCUDART
+  case RUNTIME_CUDA:
+    launchKernelCUDA(Kernel, GridDimX, GridDimY, BlockDimX, BlockDimY,
+                     BlockDimZ, Parameters);
+    break;
+#endif /* HAS_LIBCUDART */
+#ifdef HAS_LIBOPENCL
+  case RUNTIME_CL:
+    launchKernelCL(Kernel, GridDimX, GridDimY, BlockDimX, BlockDimY, BlockDimZ,
+                   Parameters);
+    break;
+#endif /* HAS_LIBOPENCL */
+  default:
+    err_runtime();
+  }
+}
+
+void polly_freeDeviceMemory(PollyGPUDevicePtr *Allocation) {
+  dump_function();
+
+  switch (Runtime) {
+#ifdef HAS_LIBCUDART
+  case RUNTIME_CUDA:
+    freeDeviceMemoryCUDA(Allocation);
+    break;
+#endif /* HAS_LIBCUDART */
+#ifdef HAS_LIBOPENCL
+  case RUNTIME_CL:
+    freeDeviceMemoryCL(Allocation);
+    break;
+#endif /* HAS_LIBOPENCL */
+  default:
+    err_runtime();
+  }
+}
+
+PollyGPUDevicePtr *polly_allocateMemoryForDevice(long MemSize) {
+  dump_function();
+
+  PollyGPUDevicePtr *DevData;
+
+  switch (Runtime) {
+#ifdef HAS_LIBCUDART
+  case RUNTIME_CUDA:
+    DevData = allocateMemoryForDeviceCUDA(MemSize);
+    break;
+#endif /* HAS_LIBCUDART */
+#ifdef HAS_LIBOPENCL
+  case RUNTIME_CL:
+    DevData = allocateMemoryForDeviceCL(MemSize);
+    break;
+#endif /* HAS_LIBOPENCL */
+  default:
+    err_runtime();
+  }
+
+  return DevData;
+}
+
+void *polly_getDevicePtr(PollyGPUDevicePtr *Allocation) {
+  dump_function();
+
+  void *DevPtr;
+
+  switch (Runtime) {
+#ifdef HAS_LIBCUDART
+  case RUNTIME_CUDA:
+    DevPtr = getDevicePtrCUDA(Allocation);
+    break;
+#endif /* HAS_LIBCUDART */
+#ifdef HAS_LIBOPENCL
+  case RUNTIME_CL:
+    DevPtr = getDevicePtrCL(Allocation);
+    break;
+#endif /* HAS_LIBOPENCL */
+  default:
+    err_runtime();
+  }
+
+  return DevPtr;
+}
+
+void polly_synchronizeDevice() {
+  dump_function();
+
+  switch (Runtime) {
+#ifdef HAS_LIBCUDART
+  case RUNTIME_CUDA:
+    synchronizeDeviceCUDA();
+    break;
+#endif /* HAS_LIBCUDART */
+#ifdef HAS_LIBOPENCL
+  case RUNTIME_CL:
+    synchronizeDeviceCL();
+    break;
+#endif /* HAS_LIBOPENCL */
+  default:
+    err_runtime();
+  }
+}
+
+void polly_freeContext(PollyGPUContext *Context) {
+  dump_function();
+
+  if (CacheMode)
+    return;
+
+  switch (Runtime) {
+#ifdef HAS_LIBCUDART
+  case RUNTIME_CUDA:
+    freeContextCUDA(Context);
+    break;
+#endif /* HAS_LIBCUDART */
+#ifdef HAS_LIBOPENCL
+  case RUNTIME_CL:
+    freeContextCL(Context);
+    break;
+#endif /* HAS_LIBOPENCL */
+  default:
+    err_runtime();
+  }
+}
+
+void polly_freeManaged(void *mem) {
+  dump_function();
+
+#ifdef HAS_LIBCUDART
+  freeManagedCUDA(mem);
+#else
+  fprintf(stderr, "No CUDA Runtime. Managed memory only supported by CUDA\n");
+  exit(-1);
+#endif
+}
+
+void *polly_mallocManaged(size_t size) {
+  dump_function();
+
+#ifdef HAS_LIBCUDART
+  return mallocManagedCUDA(size);
+#else
+  fprintf(stderr, "No CUDA Runtime. Managed memory only supported by CUDA\n");
+  exit(-1);
+#endif
+}
+
+/* Initialize GPUJIT with CUDA as runtime library. */
+PollyGPUContext *polly_initContextCUDA() {
+#ifdef HAS_LIBCUDART
+  Runtime = RUNTIME_CUDA;
+  return polly_initContext();
+#else
+  fprintf(stderr, "GPU Runtime was built without CUDA support.\n");
+  exit(-1);
+#endif /* HAS_LIBCUDART */
+}
+
+/* Initialize GPUJIT with OpenCL as runtime library. */
+PollyGPUContext *polly_initContextCL() {
+#ifdef HAS_LIBOPENCL
+  Runtime = RUNTIME_CL;
+  return polly_initContext();
+#else
+  fprintf(stderr, "GPU Runtime was built without OpenCL support.\n");
+  exit(-1);
+#endif /* HAS_LIBOPENCL */
+}
diff --git a/final/tools/GPURuntime/GPUJIT.h b/final/tools/GPURuntime/GPUJIT.h
new file mode 100644
index 0000000..fd52ec3
--- /dev/null
+++ b/final/tools/GPURuntime/GPUJIT.h
@@ -0,0 +1,123 @@
+/******************************************************************************/
+/*                                                                            */
+/*                     The LLVM Compiler Infrastructure                       */
+/*                                                                            */
+/* This file is dual licensed under the MIT and the University of Illinois    */
+/* Open Source License. See LICENSE.TXT for details.                          */
+/*                                                                            */
+/******************************************************************************/
+/*                                                                            */
+/*  This file defines GPUJIT.                                                 */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef GPUJIT_H_
+#define GPUJIT_H_
+#include "stddef.h"
+
+/*
+ * The following demostrates how we can use the GPURuntime library to
+ * execute a GPU kernel.
+ *
+ * char KernelString[] = "\n\
+ *   .version 1.4\n\
+ *   .target sm_10, map_f64_to_f32\n\
+ *   .entry _Z8myKernelPi (\n\
+ *   .param .u64 __cudaparm__Z8myKernelPi_data)\n\
+ *   {\n\
+ *     .reg .u16 %rh<4>;\n\
+ *     .reg .u32 %r<5>;\n\
+ *     .reg .u64 %rd<6>;\n\
+ *     cvt.u32.u16     %r1, %tid.x;\n\
+ *     mov.u16         %rh1, %ctaid.x;\n\
+ *     mov.u16         %rh2, %ntid.x;\n\
+ *     mul.wide.u16    %r2, %rh1, %rh2;\n\
+ *     add.u32         %r3, %r1, %r2;\n\
+ *     ld.param.u64    %rd1, [__cudaparm__Z8myKernelPi_data];\n\
+ *     cvt.s64.s32     %rd2, %r3;\n\
+ *     mul.wide.s32    %rd3, %r3, 4;\n\
+ *     add.u64         %rd4, %rd1, %rd3;\n\
+ *     st.global.s32   [%rd4+0], %r3;\n\
+ *     exit;\n\
+ *   }\n\
+ * ";
+ *
+ * const char *Entry = "_Z8myKernelPi";
+ *
+ * int main() {
+ *   PollyGPUFunction *Kernel;
+ *   PollyGPUContext *Context;
+ *   PollyGPUDevicePtr *DevArray;
+ *   int *HostData;
+ *   int MemSize;
+ *
+ *   int GridX = 8;
+ *   int GridY = 8;
+ *
+ *   int BlockX = 16;
+ *   int BlockY = 16;
+ *   int BlockZ = 1;
+ *
+ *   MemSize = 256*64*sizeof(int);
+ *   Context = polly_initContext();
+ *   DevArray = polly_allocateMemoryForDevice(MemSize);
+ *   Kernel = polly_getKernel(KernelString, KernelName);
+ *
+ *   void *Params[1];
+ *   void *DevPtr = polly_getDevicePtr(DevArray)
+ *   Params[0] = &DevPtr;
+ *
+ *   polly_launchKernel(Kernel, GridX, GridY, BlockX, BlockY, BlockZ, Params);
+ *
+ *   polly_copyFromDeviceToHost(HostData, DevData, MemSize);
+ *   polly_freeKernel(Kernel);
+ *   polly_freeDeviceMemory(DevArray);
+ *   polly_freeContext(Context);
+ * }
+ *
+ */
+
+typedef enum PollyGPURuntimeT {
+  RUNTIME_NONE,
+  RUNTIME_CUDA,
+  RUNTIME_CL
+} PollyGPURuntime;
+
+typedef struct PollyGPUContextT PollyGPUContext;
+typedef struct PollyGPUFunctionT PollyGPUFunction;
+typedef struct PollyGPUDevicePtrT PollyGPUDevicePtr;
+
+typedef struct OpenCLContextT OpenCLContext;
+typedef struct OpenCLKernelT OpenCLKernel;
+typedef struct OpenCLDevicePtrT OpenCLDevicePtr;
+
+typedef struct CUDAContextT CUDAContext;
+typedef struct CUDAKernelT CUDAKernel;
+typedef struct CUDADevicePtrT CUDADevicePtr;
+
+PollyGPUContext *polly_initContextCUDA();
+PollyGPUContext *polly_initContextCL();
+PollyGPUFunction *polly_getKernel(const char *BinaryBuffer,
+                                  const char *KernelName);
+void polly_freeKernel(PollyGPUFunction *Kernel);
+void polly_copyFromHostToDevice(void *HostData, PollyGPUDevicePtr *DevData,
+                                long MemSize);
+void polly_copyFromDeviceToHost(PollyGPUDevicePtr *DevData, void *HostData,
+                                long MemSize);
+void polly_synchronizeDevice();
+void polly_launchKernel(PollyGPUFunction *Kernel, unsigned int GridDimX,
+                        unsigned int GridDimY, unsigned int BlockSizeX,
+                        unsigned int BlockSizeY, unsigned int BlockSizeZ,
+                        void **Parameters);
+void polly_freeDeviceMemory(PollyGPUDevicePtr *Allocation);
+void polly_freeContext(PollyGPUContext *Context);
+
+// Note that polly_{malloc/free}Managed are currently not used by Polly.
+// We use them in COSMO by replacing all malloc with polly_mallocManaged and all
+// frees with cudaFree, so we can get managed memory "automatically".
+// Needless to say, this is a hack.
+// Please make sure that this code is not present in Polly when 2018 rolls in.
+// If this is still present, ping Siddharth Bhat <siddu.druid@gmail.com>
+void *polly_mallocManaged(size_t size);
+void polly_freeManaged(void *mem);
+#endif /* GPUJIT_H_ */
diff --git a/final/tools/GPURuntime/LICENSE.TXT b/final/tools/GPURuntime/LICENSE.TXT
new file mode 100644
index 0000000..8c724ed
--- /dev/null
+++ b/final/tools/GPURuntime/LICENSE.TXT
@@ -0,0 +1,75 @@
+==============================================================================
+GPURuntime License
+==============================================================================
+
+The GPURuntime library is dual licensed under both the University of Illinois
+"BSD-Like" license and the MIT license.  As a user of this code you may choose
+to use it under either license.  As a contributor, you agree to allow your code
+to be used under both.
+
+Full text of the relevant licenses is included below.
+
+==============================================================================
+
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT
+
+All rights reserved.
+
+Developed by:
+
+    Polly Team
+
+    http://polly.llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimers.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimers in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the names of the LLVM Team, University of Illinois at
+      Urbana-Champaign, nor the names of its contributors may be used to
+      endorse or promote products derived from this Software without specific
+      prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+
+Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/final/unittests/CMakeLists.txt b/final/unittests/CMakeLists.txt
new file mode 100644
index 0000000..cac10df
--- /dev/null
+++ b/final/unittests/CMakeLists.txt
@@ -0,0 +1,26 @@
+add_custom_target(PollyUnitTests)
+set_target_properties(PollyUnitTests PROPERTIES FOLDER "Polly")
+
+# add_polly_unittest(test_dirname file1.cpp file2.cpp)
+#
+# Will compile the list of files together and link against Polly and its dependences.
+function(add_polly_unittest test_name)
+  if(COMMAND add_unittest)
+    add_unittest(PollyUnitTests ${test_name} ${ARGN})
+  else()
+    add_executable(${test_name} EXCLUDE_FROM_ALL ${ARGN})
+    set_target_properties(${test_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+    target_link_libraries(${test_name} PRIVATE gtest_main gtest)
+    add_dependencies(PollyUnitTests ${test_name})
+
+    set_property(TARGET ${test_name} PROPERTY FOLDER "Polly")
+  endif()
+  target_link_libraries(${test_name} PRIVATE Polly)
+endfunction()
+
+add_subdirectory(Isl)
+add_subdirectory(Flatten)
+add_subdirectory(DeLICM)
+add_subdirectory(ScopPassManager)
+add_subdirectory(ScheduleOptimizer)
diff --git a/final/unittests/DeLICM/CMakeLists.txt b/final/unittests/DeLICM/CMakeLists.txt
new file mode 100644
index 0000000..d83c08a
--- /dev/null
+++ b/final/unittests/DeLICM/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_polly_unittest(DeLICMTests
+  DeLICMTest.cpp
+  )
diff --git a/final/unittests/DeLICM/DeLICMTest.cpp b/final/unittests/DeLICM/DeLICMTest.cpp
new file mode 100644
index 0000000..5bfff53
--- /dev/null
+++ b/final/unittests/DeLICM/DeLICMTest.cpp
@@ -0,0 +1,328 @@
+//===- DeLICMTest.cpp ----------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/DeLICM.h"
+#include "gtest/gtest.h"
+#include <isl/map.h>
+#include <isl/set.h>
+#include <isl/stream.h>
+#include <isl/union_map.h>
+#include <isl/union_set.h>
+#include <memory>
+
+using namespace llvm;
+using namespace polly;
+
+namespace {
+
+/// Get the universes of all spaces in @p USet.
+isl::union_set unionSpace(const isl::union_set &USet) {
+  auto Result = give(isl_union_set_empty(isl_union_set_get_space(USet.keep())));
+  USet.foreach_set([=, &Result](isl::set Set) -> isl::stat {
+    auto Space = give(isl_set_get_space(Set.keep()));
+    auto Universe = give(isl_set_universe(Space.take()));
+    Result = give(isl_union_set_add_set(Result.take(), Universe.take()));
+    return isl::stat::ok;
+  });
+  return Result;
+}
+
+void completeLifetime(isl::union_set Universe, isl::union_map OccupiedAndKnown,
+                      isl::union_set &Occupied, isl::union_map &Known,
+                      isl::union_set &Undef) {
+  auto ParamSpace = give(isl_union_set_get_space(Universe.keep()));
+
+  if (Undef && !Occupied) {
+    assert(!Occupied);
+    Occupied = give(isl_union_set_subtract(Universe.copy(), Undef.copy()));
+  }
+
+  if (OccupiedAndKnown) {
+    assert(!Known);
+
+    Known = isl::union_map::empty(ParamSpace);
+
+    if (!Occupied)
+      Occupied = OccupiedAndKnown.domain();
+
+    OccupiedAndKnown.foreach_map([&Known](isl::map Map) -> isl::stat {
+      if (isl_map_has_tuple_name(Map.keep(), isl_dim_out) != isl_bool_true)
+        return isl::stat::ok;
+      Known = give(isl_union_map_add_map(Known.take(), Map.take()));
+      return isl::stat::ok;
+    });
+  }
+
+  if (!Undef) {
+    assert(Occupied);
+    Undef = give(isl_union_set_subtract(Universe.copy(), Occupied.copy()));
+  }
+
+  if (!Known) { // By default, nothing is known.
+    Known = isl::union_map::empty(ParamSpace);
+  }
+
+  // Conditions that must hold when returning.
+  assert(Occupied);
+  assert(Undef);
+  assert(Known);
+}
+
+typedef struct {
+  const char *OccupiedStr;
+  const char *UndefStr;
+  const char *WrittenStr;
+} KnowledgeStr;
+
+isl::union_set parseSetOrNull(isl_ctx *Ctx, const char *Str) {
+  if (!Str)
+    return nullptr;
+  return isl::union_set(Ctx, Str);
+}
+
+isl::union_map parseMapOrNull(isl_ctx *Ctx, const char *Str) {
+  if (!Str)
+    return nullptr;
+  return isl::union_map(Ctx, Str);
+}
+
+bool checkIsConflictingNonsymmetricCommon(
+    isl_ctx *Ctx, isl::union_map ExistingOccupiedAndKnown,
+    isl::union_set ExistingUnused, isl::union_map ExistingWritten,
+    isl::union_map ProposedOccupiedAndKnown, isl::union_set ProposedUnused,
+    isl::union_map ProposedWritten) {
+  // Determine universe (set of all possible domains).
+  auto Universe = give(isl_union_set_empty(isl_space_params_alloc(Ctx, 0)));
+  if (ExistingOccupiedAndKnown)
+    Universe = give(isl_union_set_union(
+        Universe.take(), ExistingOccupiedAndKnown.domain().take()));
+  if (ExistingUnused)
+    Universe =
+        give(isl_union_set_union(Universe.take(), ExistingUnused.copy()));
+  if (ExistingWritten)
+    Universe = give(
+        isl_union_set_union(Universe.take(), ExistingWritten.domain().take()));
+  if (ProposedOccupiedAndKnown)
+    Universe = give(isl_union_set_union(
+        Universe.take(), ProposedOccupiedAndKnown.domain().take()));
+  if (ProposedUnused)
+    Universe =
+        give(isl_union_set_union(Universe.take(), ProposedUnused.copy()));
+  if (ProposedWritten)
+    Universe = give(
+        isl_union_set_union(Universe.take(), ProposedWritten.domain().take()));
+
+  Universe = unionSpace(Universe);
+
+  // Add a space the universe that does not occur anywhere else to ensure
+  // robustness. Use &NewId to ensure that this Id is unique.
+  isl::id NewId = give(isl_id_alloc(Ctx, "Unrelated", &NewId));
+  // The space must contains at least one dimension to allow order
+  // modifications.
+  auto NewSpace = give(isl_space_set_alloc(Ctx, 0, 1));
+  NewSpace =
+      give(isl_space_set_tuple_id(NewSpace.take(), isl_dim_set, NewId.copy()));
+  auto NewSet = give(isl_set_universe(NewSpace.take()));
+  Universe = give(isl_union_set_add_set(Universe.take(), NewSet.take()));
+
+  // Using the universe, fill missing data.
+  isl::union_set ExistingOccupied;
+  isl::union_map ExistingKnown;
+  completeLifetime(Universe, ExistingOccupiedAndKnown, ExistingOccupied,
+                   ExistingKnown, ExistingUnused);
+
+  isl::union_set ProposedOccupied;
+  isl::union_map ProposedKnown;
+  completeLifetime(Universe, ProposedOccupiedAndKnown, ProposedOccupied,
+                   ProposedKnown, ProposedUnused);
+
+  auto Result = isConflicting(ExistingOccupied, ExistingUnused, ExistingKnown,
+                              ExistingWritten, ProposedOccupied, ProposedUnused,
+                              ProposedKnown, ProposedWritten);
+
+  // isConflicting does not require ExistingOccupied nor ProposedUnused and are
+  // implicitly assumed to be the remainder elements. Test the implicitness as
+  // well.
+  EXPECT_EQ(Result,
+            isConflicting(ExistingOccupied, ExistingUnused, ExistingKnown,
+                          ExistingWritten, ProposedOccupied, {}, ProposedKnown,
+                          ProposedWritten));
+  EXPECT_EQ(Result,
+            isConflicting({}, ExistingUnused, ExistingKnown, ExistingWritten,
+                          ProposedOccupied, ProposedUnused, ProposedKnown,
+                          ProposedWritten));
+  EXPECT_EQ(Result, isConflicting({}, ExistingUnused, ExistingKnown,
+                                  ExistingWritten, ProposedOccupied, {},
+                                  ProposedKnown, ProposedWritten));
+
+  return Result;
+}
+
+bool checkIsConflictingNonsymmetricKnown(KnowledgeStr Existing,
+                                         KnowledgeStr Proposed) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Parse knowledge.
+  auto ExistingOccupiedAndKnown =
+      parseMapOrNull(Ctx.get(), Existing.OccupiedStr);
+  auto ExistingUnused = parseSetOrNull(Ctx.get(), Existing.UndefStr);
+  auto ExistingWritten = parseMapOrNull(Ctx.get(), Existing.WrittenStr);
+
+  auto ProposedOccupiedAndKnown =
+      parseMapOrNull(Ctx.get(), Proposed.OccupiedStr);
+  auto ProposedUnused = parseSetOrNull(Ctx.get(), Proposed.UndefStr);
+  auto ProposedWritten = parseMapOrNull(Ctx.get(), Proposed.WrittenStr);
+
+  return checkIsConflictingNonsymmetricCommon(
+      Ctx.get(), ExistingOccupiedAndKnown, ExistingUnused, ExistingWritten,
+      ProposedOccupiedAndKnown, ProposedUnused, ProposedWritten);
+}
+
+bool checkIsConflictingNonsymmetric(KnowledgeStr Existing,
+                                    KnowledgeStr Proposed) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Parse knowledge.
+  auto ExistingOccupied = parseSetOrNull(Ctx.get(), Existing.OccupiedStr);
+  auto ExistingUnused = parseSetOrNull(Ctx.get(), Existing.UndefStr);
+  auto ExistingWritten = parseSetOrNull(Ctx.get(), Existing.WrittenStr);
+
+  auto ProposedOccupied = parseSetOrNull(Ctx.get(), Proposed.OccupiedStr);
+  auto ProposedUnused = parseSetOrNull(Ctx.get(), Proposed.UndefStr);
+  auto ProposedWritten = parseSetOrNull(Ctx.get(), Proposed.WrittenStr);
+
+  return checkIsConflictingNonsymmetricCommon(
+      Ctx.get(),
+      isl::manage(isl_union_map_from_domain(ExistingOccupied.take())),
+      ExistingUnused,
+      isl::manage(isl_union_map_from_domain(ExistingWritten.take())),
+      isl::manage(isl_union_map_from_domain(ProposedOccupied.take())),
+      ProposedUnused,
+      isl::manage(isl_union_map_from_domain(ProposedWritten.take())));
+}
+
+bool checkIsConflicting(KnowledgeStr Existing, KnowledgeStr Proposed) {
+  auto Forward = checkIsConflictingNonsymmetric(Existing, Proposed);
+  auto Backward = checkIsConflictingNonsymmetric(Proposed, Existing);
+
+  // isConflicting should be symmetric.
+  EXPECT_EQ(Forward, Backward);
+
+  return Forward || Backward;
+}
+
+bool checkIsConflictingKnown(KnowledgeStr Existing, KnowledgeStr Proposed) {
+  auto Forward = checkIsConflictingNonsymmetricKnown(Existing, Proposed);
+  auto Backward = checkIsConflictingNonsymmetricKnown(Proposed, Existing);
+
+  // checkIsConflictingKnown should be symmetric.
+  EXPECT_EQ(Forward, Backward);
+
+  return Forward || Backward;
+}
+
+TEST(DeLICM, isConflicting) {
+
+  // Check occupied vs. occupied.
+  EXPECT_TRUE(
+      checkIsConflicting({"{ Dom[i] }", nullptr, "{}"}, {nullptr, "{}", "{}"}));
+  EXPECT_TRUE(checkIsConflicting({"{ Dom[i] }", nullptr, "{}"},
+                                 {"{ Dom[i] }", nullptr, "{}"}));
+  EXPECT_FALSE(checkIsConflicting({"{ Dom[0] }", nullptr, "{}"},
+                                  {nullptr, "{ Dom[0] }", "{}"}));
+  EXPECT_FALSE(checkIsConflicting({"{ Dom[i] : i != 0 }", nullptr, "{}"},
+                                  {"{ Dom[0] }", nullptr, "{}"}));
+
+  // Check occupied vs. occupied with known values.
+  EXPECT_FALSE(checkIsConflictingKnown({"{ Dom[i] -> Val[] }", nullptr, "{}"},
+                                       {"{ Dom[i] -> Val[] }", nullptr, "{}"}));
+  EXPECT_TRUE(checkIsConflictingKnown({"{ Dom[i] -> ValA[] }", nullptr, "{}"},
+                                      {"{ Dom[i] -> ValB[] }", nullptr, "{}"}));
+  EXPECT_TRUE(checkIsConflictingKnown({"{ Dom[i] -> Val[] }", nullptr, "{}"},
+                                      {"{ Dom[i] -> [] }", nullptr, "{}"}));
+  EXPECT_FALSE(checkIsConflictingKnown({"{ Dom[0] -> Val[] }", nullptr, "{}"},
+                                       {nullptr, "{ Dom[0] }", "{}"}));
+  EXPECT_FALSE(checkIsConflictingKnown(
+      {"{ Dom[i] -> Val[]; Dom[i] -> Phi[] }", nullptr, "{}"},
+      {"{ Dom[i] -> Val[] }", nullptr, "{}"}));
+
+  // An implementation using subtract would have exponential runtime on patterns
+  // such as this one.
+  EXPECT_TRUE(checkIsConflictingKnown(
+      {"{ Dom[i0,i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15]"
+       "-> Val[] }",
+       nullptr, "{}"},
+      {"[p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,q0,"
+       "q1,q2,q3,q4,q5,q6,q7,q8,q9,q10,q11,q12,q13,q14,q15] -> {"
+       "Dom[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] -> Val[];"
+       "Dom[p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15] -> Val[];"
+       "Dom[q0,q1,q2,q3,q4,q5,q6,q7,q8,q9,q10,q11,q12,q13,q14,q15] -> Val[] }",
+       "{}", "{}"}));
+
+  // Check occupied vs. written.
+  EXPECT_TRUE(
+      checkIsConflicting({nullptr, "{}", "{}"}, {"{}", nullptr, "{ Dom[0] }"}));
+  EXPECT_FALSE(
+      checkIsConflicting({"{}", nullptr, "{}"}, {"{}", nullptr, "{ Dom[0] }"}));
+
+  EXPECT_TRUE(checkIsConflicting({"{ Dom[i] }", nullptr, "{}"},
+                                 {"{}", nullptr, "{ Dom[0] }"}));
+  EXPECT_FALSE(checkIsConflicting({"{ DomA[i] }", nullptr, "{}"},
+                                  {"{}", nullptr, "{ DomB[0] }"}));
+
+  // Dom[1] represents the time between 0 and 1. Now Proposed writes at timestep
+  // 0 such that will have a different value between 0 and 1. Hence it is
+  // conflicting with Existing.
+  EXPECT_TRUE(checkIsConflicting({"{ Dom[1] }", nullptr, "{}"},
+                                 {"{}", nullptr, "{ Dom[0] }"}));
+  EXPECT_FALSE(checkIsConflicting({"{ Dom[i] : i != 1 }", nullptr, "{}"},
+                                  {"{}", nullptr, "{ Dom[0] }"}));
+
+  // Check occupied vs. written with known values.
+  EXPECT_FALSE(checkIsConflictingKnown({"{ Dom[i] -> Val[] }", nullptr, "{}"},
+                                       {"{}", nullptr, "{ Dom[0] -> Val[] }"}));
+  EXPECT_TRUE(checkIsConflictingKnown({"{ Dom[i] -> ValA[] }", nullptr, "{}"},
+                                      {"{}", nullptr, "{ Dom[0] -> ValB[] }"}));
+  EXPECT_TRUE(checkIsConflictingKnown({"{ Dom[i] -> Val[] }", nullptr, "{}"},
+                                      {"{}", nullptr, "{ Dom[0] -> [] }"}));
+  EXPECT_TRUE(checkIsConflictingKnown({"{ Dom[i] -> [] }", nullptr, "{}"},
+                                      {"{}", nullptr, "{ Dom[0] -> Val[] }"}));
+
+  // The same value can be known under multiple names, for instance a PHINode
+  // has the same value as one of the incoming values. One matching pair
+  // suffices.
+  EXPECT_FALSE(checkIsConflictingKnown(
+      {"{ Dom[i] -> Val[]; Dom[i] -> Phi[] }", nullptr, "{}"},
+      {"{}", nullptr, "{ Dom[0] -> Val[] }"}));
+  EXPECT_FALSE(checkIsConflictingKnown(
+      {"{ Dom[i] -> Val[] }", nullptr, "{}"},
+      {"{}", nullptr, "{ Dom[0] -> Val[]; Dom[0] -> Phi[] }"}));
+
+  // Check written vs. written.
+  EXPECT_TRUE(checkIsConflicting({"{}", nullptr, "{ Dom[0] }"},
+                                 {"{}", nullptr, "{ Dom[0] }"}));
+  EXPECT_FALSE(checkIsConflicting({"{}", nullptr, "{ Dom[-1] }"},
+                                  {"{}", nullptr, "{ Dom[0] }"}));
+  EXPECT_FALSE(checkIsConflicting({"{}", nullptr, "{ Dom[1] }"},
+                                  {"{}", nullptr, "{ Dom[0] }"}));
+
+  // Check written vs. written with known values.
+  EXPECT_FALSE(checkIsConflictingKnown({"{}", nullptr, "{ Dom[0] -> Val[] }"},
+                                       {"{}", nullptr, "{ Dom[0] -> Val[] }"}));
+  EXPECT_TRUE(checkIsConflictingKnown({"{}", nullptr, "{ Dom[0] -> ValA[] }"},
+                                      {"{}", nullptr, "{ Dom[0] -> ValB[] }"}));
+  EXPECT_TRUE(checkIsConflictingKnown({"{}", nullptr, "{ Dom[0] -> Val[] }"},
+                                      {"{}", nullptr, "{ Dom[0] -> [] }"}));
+  EXPECT_FALSE(checkIsConflictingKnown(
+      {"{}", nullptr, "{ Dom[0] -> Val[]}"},
+      {"{}", nullptr, "{ Dom[0] -> Val[]; Dom[0] -> Phi[] }"}));
+}
+} // anonymous namespace
diff --git a/final/unittests/Flatten/CMakeLists.txt b/final/unittests/Flatten/CMakeLists.txt
new file mode 100644
index 0000000..db7eaae
--- /dev/null
+++ b/final/unittests/Flatten/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_polly_unittest(FlattenTests
+  FlattenTest.cpp
+  )
diff --git a/final/unittests/Flatten/FlattenTest.cpp b/final/unittests/Flatten/FlattenTest.cpp
new file mode 100644
index 0000000..0880629
--- /dev/null
+++ b/final/unittests/Flatten/FlattenTest.cpp
@@ -0,0 +1,70 @@
+//===- FlattenTest.cpp ----------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/FlattenAlgo.h"
+#include "polly/Support/GICHelper.h"
+#include "gtest/gtest.h"
+#include "isl/union_map.h"
+
+using namespace llvm;
+using namespace polly;
+
+namespace {
+
+/// Flatten a schedule and compare to the expected result.
+///
+/// @param ScheduleStr The schedule to flatten as string.
+/// @param ExpectedStr The expected result as string.
+///
+/// @result Whether the flattened schedule is the same as the expected schedule.
+bool checkFlatten(const char *ScheduleStr, const char *ExpectedStr) {
+  auto *Ctx = isl_ctx_alloc();
+  isl_bool Success;
+
+  {
+    auto Schedule = give(isl_union_map_read_from_str(Ctx, ScheduleStr));
+    auto Expected = give(isl_union_map_read_from_str(Ctx, ExpectedStr));
+
+    auto Result = flattenSchedule(std::move(Schedule));
+    Success = isl_union_map_is_equal(Result.keep(), Expected.keep());
+  }
+
+  isl_ctx_free(Ctx);
+  return Success == isl_bool_true;
+}
+
+TEST(Flatten, FlattenTrivial) {
+  EXPECT_TRUE(checkFlatten("{ A[] -> [0] }", "{ A[] -> [0] }"));
+  EXPECT_TRUE(checkFlatten("{ A[i] -> [i, 0] : 0 <= i < 10 }",
+                           "{ A[i] -> [i] : 0 <= i < 10 }"));
+  EXPECT_TRUE(checkFlatten("{ A[i] -> [0, i] : 0 <= i < 10 }",
+                           "{ A[i] -> [i] : 0 <= i < 10 }"));
+}
+
+TEST(Flatten, FlattenSequence) {
+  EXPECT_TRUE(checkFlatten(
+      "[n] -> { A[i] -> [0, i] : 0 <= i < n; B[i] -> [1, i] : 0 <= i < n }",
+      "[n] -> { A[i] -> [i] : 0 <= i < n; B[i] -> [n + i] : 0 <= i < n }"));
+
+  EXPECT_TRUE(checkFlatten(
+      "{ A[i] -> [0, i] : 0 <= i < 10; B[i] -> [1, i] : 0 <= i < 10 }",
+      "{ A[i] -> [i] : 0 <= i < 10; B[i] -> [10 + i] : 0 <= i < 10 }"));
+}
+
+TEST(Flatten, FlattenLoop) {
+  EXPECT_TRUE(checkFlatten(
+      "[n] -> { A[i] -> [i, 0] : 0 <= i < n; B[i] -> [i, 1] : 0 <= i < n }",
+      "[n] -> { A[i] -> [2i] : 0 <= i < n; B[i] -> [2i + 1] : 0 <= i < n }"));
+
+  EXPECT_TRUE(checkFlatten(
+      "{ A[i] -> [i, 0] : 0 <= i < 10; B[i] -> [i, 1] : 0 <= i < 10 }",
+      "{ A[i] -> [2i] : 0 <= i < 10; B[i] -> [2i + 1] : 0 <= i < 10 }"));
+}
+
+} // anonymous namespace
diff --git a/final/unittests/Isl/CMakeLists.txt b/final/unittests/Isl/CMakeLists.txt
new file mode 100644
index 0000000..3aedabb
--- /dev/null
+++ b/final/unittests/Isl/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_polly_unittest(IslTests
+  IslTest.cpp
+  )
diff --git a/final/unittests/Isl/IslTest.cpp b/final/unittests/Isl/IslTest.cpp
new file mode 100644
index 0000000..b1e6fc8
--- /dev/null
+++ b/final/unittests/Isl/IslTest.cpp
@@ -0,0 +1,1006 @@
+//===- IslTest.cpp ----------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/ISLTools.h"
+#include "gtest/gtest.h"
+#include "isl/stream.h"
+#include "isl/val.h"
+
+using namespace llvm;
+using namespace polly;
+
+static isl::space parseSpace(isl_ctx *Ctx, const char *Str) {
+  isl_stream *Stream = isl_stream_new_str(Ctx, Str);
+  auto Obj = isl_stream_read_obj(Stream);
+
+  isl::space Result;
+  if (Obj.type == isl_obj_set)
+    Result = give(isl_set_get_space(static_cast<isl_set *>(Obj.v)));
+  else if (Obj.type == isl_obj_map)
+    Result = give(isl_map_get_space(static_cast<isl_map *>(Obj.v)));
+
+  isl_stream_free(Stream);
+  if (Obj.type)
+    Obj.type->free(Obj.v);
+  return Result;
+}
+
+#define SPACE(Str) parseSpace(Ctx.get(), Str)
+
+#define SET(Str) isl::set(Ctx.get(), Str)
+#define MAP(Str) isl::map(Ctx.get(), Str)
+
+#define USET(Str) isl::union_set(Ctx.get(), Str)
+#define UMAP(Str) isl::union_map(Ctx.get(), Str)
+
+namespace isl {
+inline namespace noexceptions {
+
+static bool operator==(const isl::space &LHS, const isl::space &RHS) {
+  return bool(LHS.is_equal(RHS));
+}
+
+static bool operator==(const isl::basic_set &LHS, const isl::basic_set &RHS) {
+  return bool(LHS.is_equal(RHS));
+}
+
+static bool operator==(const isl::set &LHS, const isl::set &RHS) {
+  return bool(LHS.is_equal(RHS));
+}
+
+static bool operator==(const isl::basic_map &LHS, const isl::basic_map &RHS) {
+  return bool(LHS.is_equal(RHS));
+}
+
+static bool operator==(const isl::map &LHS, const isl::map &RHS) {
+  return bool(LHS.is_equal(RHS));
+}
+
+static bool operator==(const isl::union_set &LHS, const isl::union_set &RHS) {
+  return bool(LHS.is_equal(RHS));
+}
+
+static bool operator==(const isl::union_map &LHS, const isl::union_map &RHS) {
+  return bool(LHS.is_equal(RHS));
+}
+
+static bool operator==(const isl::val &LHS, const isl::val &RHS) {
+  return bool(LHS.eq(RHS));
+}
+} // namespace noexceptions
+} // namespace isl
+
+namespace {
+
+TEST(Isl, APIntToIslVal) {
+  isl_ctx *IslCtx = isl_ctx_alloc();
+
+  {
+    APInt APZero(1, 0, true);
+    auto IslZero = valFromAPInt(IslCtx, APZero, true);
+    EXPECT_TRUE(IslZero.is_zero());
+  }
+
+  {
+    APInt APNOne(1, -1, true);
+    auto IslNOne = valFromAPInt(IslCtx, APNOne, true);
+    EXPECT_TRUE(IslNOne.is_negone());
+  }
+
+  {
+    APInt APZero(1, 0, false);
+    auto IslZero = valFromAPInt(IslCtx, APZero, false);
+    EXPECT_TRUE(IslZero.is_zero());
+  }
+
+  {
+    APInt APOne(1, 1, false);
+    auto IslOne = valFromAPInt(IslCtx, APOne, false);
+    EXPECT_TRUE(IslOne.is_one());
+  }
+
+  {
+    APInt APNTwo(2, -2, true);
+    auto IslNTwo = valFromAPInt(IslCtx, APNTwo, true);
+    auto IslNTwoCmp = isl::val(IslCtx, -2);
+    EXPECT_EQ(IslNTwo, IslNTwoCmp);
+  }
+
+  {
+    APInt APNOne(32, -1, true);
+    auto IslNOne = valFromAPInt(IslCtx, APNOne, true);
+    EXPECT_TRUE(IslNOne.is_negone());
+  }
+
+  {
+    APInt APZero(32, 0, false);
+    auto IslZero = valFromAPInt(IslCtx, APZero, false);
+    EXPECT_TRUE(IslZero.is_zero());
+  }
+
+  {
+    APInt APOne(32, 1, false);
+    auto IslOne = valFromAPInt(IslCtx, APOne, false);
+    EXPECT_TRUE(IslOne.is_one());
+  }
+
+  {
+    APInt APTwo(32, 2, false);
+    auto IslTwo = valFromAPInt(IslCtx, APTwo, false);
+    EXPECT_EQ(0, IslTwo.cmp_si(2));
+  }
+
+  {
+    APInt APNOne(32, (1ull << 32) - 1, false);
+    auto IslNOne = valFromAPInt(IslCtx, APNOne, false);
+    auto IslRef = isl::val(IslCtx, 32).two_exp().sub_ui(1);
+    EXPECT_EQ(IslNOne, IslRef);
+  }
+
+  {
+    APInt APLarge(130, 2, false);
+    APLarge = APLarge.shl(70);
+    auto IslLarge = valFromAPInt(IslCtx, APLarge, false);
+    auto IslRef = isl::val(IslCtx, 71);
+    IslRef = IslRef.two_exp();
+    EXPECT_EQ(IslLarge, IslRef);
+  }
+
+  isl_ctx_free(IslCtx);
+}
+
+TEST(Isl, IslValToAPInt) {
+  isl_ctx *IslCtx = isl_ctx_alloc();
+
+  {
+    auto IslNOne = isl::val(IslCtx, -1);
+    auto APNOne = APIntFromVal(IslNOne);
+    // Compare with the two's complement of -1 in a 1-bit integer.
+    EXPECT_EQ(1, APNOne);
+    EXPECT_EQ(1u, APNOne.getBitWidth());
+  }
+
+  {
+    auto IslNTwo = isl::val(IslCtx, -2);
+    auto APNTwo = APIntFromVal(IslNTwo);
+    // Compare with the two's complement of -2 in a 2-bit integer.
+    EXPECT_EQ(2, APNTwo);
+    EXPECT_EQ(2u, APNTwo.getBitWidth());
+  }
+
+  {
+    auto IslNThree = isl::val(IslCtx, -3);
+    auto APNThree = APIntFromVal(IslNThree);
+    // Compare with the two's complement of -3 in a 3-bit integer.
+    EXPECT_EQ(5, APNThree);
+    EXPECT_EQ(3u, APNThree.getBitWidth());
+  }
+
+  {
+    auto IslNFour = isl::val(IslCtx, -4);
+    auto APNFour = APIntFromVal(IslNFour);
+    // Compare with the two's complement of -4 in a 3-bit integer.
+    EXPECT_EQ(4, APNFour);
+    EXPECT_EQ(3u, APNFour.getBitWidth());
+  }
+
+  {
+    auto IslZero = isl::val(IslCtx, 0);
+    auto APZero = APIntFromVal(IslZero);
+    EXPECT_EQ(0, APZero);
+    EXPECT_EQ(1u, APZero.getBitWidth());
+  }
+
+  {
+    auto IslOne = isl::val(IslCtx, 1);
+    auto APOne = APIntFromVal(IslOne);
+    EXPECT_EQ(1, APOne);
+    EXPECT_EQ(2u, APOne.getBitWidth());
+  }
+
+  {
+    auto IslTwo = isl::val(IslCtx, 2);
+    auto APTwo = APIntFromVal(IslTwo);
+    EXPECT_EQ(2, APTwo);
+    EXPECT_EQ(3u, APTwo.getBitWidth());
+  }
+
+  {
+    auto IslThree = isl::val(IslCtx, 3);
+    auto APThree = APIntFromVal(IslThree);
+    EXPECT_EQ(3, APThree);
+    EXPECT_EQ(3u, APThree.getBitWidth());
+  }
+
+  {
+    auto IslFour = isl::val(IslCtx, 4);
+    auto APFour = APIntFromVal(IslFour);
+    EXPECT_EQ(4, APFour);
+    EXPECT_EQ(4u, APFour.getBitWidth());
+  }
+
+  {
+    auto IslNOne = isl::val(IslCtx, 32).two_exp().sub_ui(1);
+    auto APNOne = APIntFromVal(IslNOne);
+    EXPECT_EQ((1ull << 32) - 1, APNOne);
+    EXPECT_EQ(33u, APNOne.getBitWidth());
+  }
+
+  {
+    auto IslLargeNum = isl::val(IslCtx, 60);
+    IslLargeNum = IslLargeNum.two_exp();
+    IslLargeNum = IslLargeNum.sub_ui(1);
+    auto APLargeNum = APIntFromVal(IslLargeNum);
+    EXPECT_EQ((1ull << 60) - 1, APLargeNum);
+    EXPECT_EQ(61u, APLargeNum.getBitWidth());
+  }
+
+  {
+    auto IslExp = isl::val(IslCtx, 500);
+    auto IslLargePow2 = IslExp.two_exp();
+    auto APLargePow2 = APIntFromVal(IslLargePow2);
+    EXPECT_TRUE(APLargePow2.isPowerOf2());
+    EXPECT_EQ(502u, APLargePow2.getBitWidth());
+    EXPECT_EQ(502u, APLargePow2.getMinSignedBits());
+  }
+
+  {
+    auto IslExp = isl::val(IslCtx, 500);
+    auto IslLargeNPow2 = IslExp.two_exp().neg();
+    auto APLargeNPow2 = APIntFromVal(IslLargeNPow2);
+    EXPECT_EQ(501u, APLargeNPow2.getBitWidth());
+    EXPECT_EQ(501u, APLargeNPow2.getMinSignedBits());
+    EXPECT_EQ(500, (-APLargeNPow2).exactLogBase2());
+  }
+
+  {
+    auto IslExp = isl::val(IslCtx, 512);
+    auto IslLargePow2 = IslExp.two_exp();
+    auto APLargePow2 = APIntFromVal(IslLargePow2);
+    EXPECT_TRUE(APLargePow2.isPowerOf2());
+    EXPECT_EQ(514u, APLargePow2.getBitWidth());
+    EXPECT_EQ(514u, APLargePow2.getMinSignedBits());
+  }
+
+  {
+    auto IslExp = isl::val(IslCtx, 512);
+    auto IslLargeNPow2 = IslExp.two_exp().neg();
+    auto APLargeNPow2 = APIntFromVal(IslLargeNPow2);
+    EXPECT_EQ(513u, APLargeNPow2.getBitWidth());
+    EXPECT_EQ(513u, APLargeNPow2.getMinSignedBits());
+    EXPECT_EQ(512, (-APLargeNPow2).exactLogBase2());
+  }
+
+  isl_ctx_free(IslCtx);
+}
+
+TEST(Isl, Foreach) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  auto MapSpace = isl::space(Ctx.get(), 0, 1, 1);
+  auto TestBMap = isl::basic_map::universe(MapSpace);
+  TestBMap = TestBMap.fix_si(isl::dim::out, 0, 0);
+  TestBMap = TestBMap.fix_si(isl::dim::out, 0, 0);
+  isl::map TestMap = TestBMap;
+  isl::union_map TestUMap = TestMap;
+
+  auto SetSpace = isl::space(Ctx.get(), 0, 1);
+  isl::basic_set TestBSet = isl::point(SetSpace);
+  isl::set TestSet = TestBSet;
+  isl::union_set TestUSet = TestSet;
+
+  {
+    auto NumBMaps = 0;
+    TestMap.foreach_basic_map([&](isl::basic_map BMap) -> isl::stat {
+      EXPECT_EQ(BMap, TestBMap);
+      NumBMaps++;
+      return isl::stat::ok;
+    });
+    EXPECT_EQ(1, NumBMaps);
+  }
+
+  {
+    auto NumBSets = 0;
+    TestSet.foreach_basic_set([&](isl::basic_set BSet) -> isl::stat {
+      EXPECT_EQ(BSet, TestBSet);
+      NumBSets++;
+      return isl::stat::ok;
+    });
+    EXPECT_EQ(1, NumBSets);
+  }
+
+  {
+    auto NumMaps = 0;
+    TestUMap.foreach_map([&](isl::map Map) -> isl::stat {
+      EXPECT_EQ(Map, TestMap);
+      NumMaps++;
+      return isl::stat::ok;
+    });
+    EXPECT_EQ(1, NumMaps);
+  }
+
+  {
+    auto NumSets = 0;
+    TestUSet.foreach_set([&](isl::set Set) -> isl::stat {
+      EXPECT_EQ(Set, TestSet);
+      NumSets++;
+      return isl::stat::ok;
+    });
+    EXPECT_EQ(1, NumSets);
+  }
+
+  {
+    auto UPwAff = isl::union_pw_aff(TestUSet, isl::val::zero(Ctx.get()));
+    auto NumPwAffs = 0;
+    UPwAff.foreach_pw_aff([&](isl::pw_aff PwAff) -> isl::stat {
+      EXPECT_TRUE(PwAff.is_cst());
+      NumPwAffs++;
+      return isl::stat::ok;
+    });
+    EXPECT_EQ(1, NumPwAffs);
+  }
+
+  {
+    auto NumBMaps = 0;
+    EXPECT_EQ(isl::stat::error,
+              TestMap.foreach_basic_map([&](isl::basic_map BMap) -> isl::stat {
+                EXPECT_EQ(BMap, TestBMap);
+                NumBMaps++;
+                return isl::stat::error;
+              }));
+    EXPECT_EQ(1, NumBMaps);
+  }
+
+  {
+    auto NumMaps = 0;
+    EXPECT_EQ(isl::stat::error,
+              TestUMap.foreach_map([&](isl::map Map) -> isl::stat {
+                EXPECT_EQ(Map, TestMap);
+                NumMaps++;
+                return isl::stat::error;
+              }));
+    EXPECT_EQ(1, NumMaps);
+  }
+
+  {
+    auto TestPwAff = isl::pw_aff(TestSet, isl::val::zero(Ctx.get()));
+    auto NumPieces = 0;
+    TestPwAff.foreach_piece([&](isl::set Domain, isl::aff Aff) -> isl::stat {
+      EXPECT_EQ(Domain, TestSet);
+      EXPECT_TRUE(Aff.is_cst());
+      NumPieces++;
+      return isl::stat::error;
+    });
+    EXPECT_EQ(1, NumPieces);
+  }
+}
+
+TEST(ISLTools, beforeScatter) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage with isl_map
+  EXPECT_EQ(MAP("{ [] -> [i] : i <= 0 }"),
+            beforeScatter(MAP("{ [] -> [0] }"), false));
+  EXPECT_EQ(MAP("{ [] -> [i] : i < 0 }"),
+            beforeScatter(MAP("{ [] -> [0] }"), true));
+
+  // Basic usage with isl_union_map
+  EXPECT_EQ(UMAP("{ A[] -> [i] : i <= 0; B[] -> [i] : i <= 0 }"),
+            beforeScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"), false));
+  EXPECT_EQ(UMAP("{ A[] -> [i] : i < 0; B[] -> [i] : i < 0 }"),
+            beforeScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"), true));
+
+  // More than one dimension
+  EXPECT_EQ(UMAP("{ [] -> [i, j] : i < 0;  [] -> [i, j] : i = 0 and j <= 0 }"),
+            beforeScatter(UMAP("{ [] -> [0, 0] }"), false));
+  EXPECT_EQ(UMAP("{ [] -> [i, j] : i < 0;  [] -> [i, j] : i = 0 and j < 0 }"),
+            beforeScatter(UMAP("{ [] -> [0, 0] }"), true));
+
+  // Functional
+  EXPECT_EQ(UMAP("{ [i] -> [j] : j <= i }"),
+            beforeScatter(UMAP("{ [i] -> [i] }"), false));
+  EXPECT_EQ(UMAP("{ [i] -> [j] : j < i }"),
+            beforeScatter(UMAP("{ [i] -> [i] }"), true));
+
+  // Parametrized
+  EXPECT_EQ(UMAP("[i] -> { [] -> [j] : j <= i }"),
+            beforeScatter(UMAP("[i] -> { [] -> [i] }"), false));
+  EXPECT_EQ(UMAP("[i] -> { [] -> [j] : j < i }"),
+            beforeScatter(UMAP("[i] -> { [] -> [i] }"), true));
+
+  // More than one range
+  EXPECT_EQ(UMAP("{ [] -> [i] : i <= 10 }"),
+            beforeScatter(UMAP("{ [] -> [0]; [] -> [10] }"), false));
+  EXPECT_EQ(UMAP("{ [] -> [i] : i < 10 }"),
+            beforeScatter(UMAP("{ [] -> [0]; [] -> [10] }"), true));
+
+  // Edge case: empty
+  EXPECT_EQ(UMAP("{ [] -> [i] : 1 = 0 }"),
+            beforeScatter(UMAP("{ [] -> [i] : 1 = 0 }"), false));
+  EXPECT_EQ(UMAP("{ [] -> [i] : 1 = 0 }"),
+            beforeScatter(UMAP("{ [] -> [i] : 1 = 0 }"), true));
+}
+
+TEST(ISLTools, afterScatter) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage with isl_map
+  EXPECT_EQ(MAP("{ [] -> [i] : i >= 0 }"),
+            afterScatter(MAP("{ [] -> [0] }"), false));
+  EXPECT_EQ(MAP("{ [] -> [i] : i > 0 }"),
+            afterScatter(MAP("{ [] -> [0] }"), true));
+
+  // Basic usage with isl_union_map
+  EXPECT_EQ(UMAP("{ A[] -> [i] : i >= 0; B[] -> [i] : i >= 0 }"),
+            afterScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"), false));
+  EXPECT_EQ(UMAP("{ A[] -> [i] : i > 0; B[] -> [i] : i > 0 }"),
+            afterScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"), true));
+
+  // More than one dimension
+  EXPECT_EQ(UMAP("{ [] -> [i, j] : i > 0;  [] -> [i, j] : i = 0 and j >= 0 }"),
+            afterScatter(UMAP("{ [] -> [0, 0] }"), false));
+  EXPECT_EQ(UMAP("{ [] -> [i, j] : i > 0;  [] -> [i, j] : i = 0 and j > 0 }"),
+            afterScatter(UMAP("{ [] -> [0, 0] }"), true));
+
+  // Functional
+  EXPECT_EQ(UMAP("{ [i] -> [j] : j >= i }"),
+            afterScatter(UMAP("{ [i] -> [i] }"), false));
+  EXPECT_EQ(UMAP("{ [i] -> [j] : j > i }"),
+            afterScatter(UMAP("{ [i] -> [i] }"), true));
+
+  // Parametrized
+  EXPECT_EQ(UMAP("[i] -> { [] -> [j] : j >= i }"),
+            afterScatter(UMAP("[i] -> { [] -> [i] }"), false));
+  EXPECT_EQ(UMAP("[i] -> { [] -> [j] : j > i }"),
+            afterScatter(UMAP("[i] -> { [] -> [i] }"), true));
+
+  // More than one range
+  EXPECT_EQ(UMAP("{ [] -> [i] : i >= 0 }"),
+            afterScatter(UMAP("{ [] -> [0]; [] -> [10] }"), false));
+  EXPECT_EQ(UMAP("{ [] -> [i] : i > 0 }"),
+            afterScatter(UMAP("{ [] -> [0]; [] -> [10] }"), true));
+
+  // Edge case: empty
+  EXPECT_EQ(UMAP("{ }"), afterScatter(UMAP("{ }"), false));
+  EXPECT_EQ(UMAP("{ }"), afterScatter(UMAP("{ }"), true));
+}
+
+TEST(ISLTools, betweenScatter) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage with isl_map
+  EXPECT_EQ(MAP("{ [] -> [i] : 0 < i < 10 }"),
+            betweenScatter(MAP("{ [] -> [0] }"), MAP("{ [] -> [10] }"), false,
+                           false));
+  EXPECT_EQ(
+      MAP("{ [] -> [i] : 0 <= i < 10 }"),
+      betweenScatter(MAP("{ [] -> [0] }"), MAP("{ [] -> [10] }"), true, false));
+  EXPECT_EQ(
+      MAP("{ [] -> [i] : 0 < i <= 10 }"),
+      betweenScatter(MAP("{ [] -> [0] }"), MAP("{ [] -> [10] }"), false, true));
+  EXPECT_EQ(
+      MAP("{ [] -> [i] : 0 <= i <= 10 }"),
+      betweenScatter(MAP("{ [] -> [0] }"), MAP("{ [] -> [10] }"), true, true));
+
+  // Basic usage with isl_union_map
+  EXPECT_EQ(UMAP("{ A[] -> [i] : 0 < i < 10; B[] -> [i] : 0 < i < 10 }"),
+            betweenScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"),
+                           UMAP("{ A[] -> [10]; B[] -> [10] }"), false, false));
+  EXPECT_EQ(UMAP("{ A[] -> [i] : 0 <= i < 10; B[] -> [i] : 0 <= i < 10 }"),
+            betweenScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"),
+                           UMAP("{ A[] -> [10]; B[] -> [10] }"), true, false));
+  EXPECT_EQ(UMAP("{ A[] -> [i] : 0 < i <= 10; B[] -> [i] : 0 < i <= 10 }"),
+            betweenScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"),
+                           UMAP("{ A[] -> [10]; B[] -> [10] }"), false, true));
+  EXPECT_EQ(UMAP("{ A[] -> [i] : 0 <= i <= 10; B[] -> [i] : 0 <= i <= 10 }"),
+            betweenScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"),
+                           UMAP("{ A[] -> [10]; B[] -> [10] }"), true, true));
+}
+
+TEST(ISLTools, singleton) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // No element found
+  EXPECT_EQ(SET("{ [] : 1 = 0 }"), singleton(USET("{ }"), SPACE("{ [] }")));
+  EXPECT_EQ(MAP("{ [] -> [] : 1 = 0  }"),
+            singleton(UMAP("{  }"), SPACE("{ [] -> [] }")));
+
+  // One element found
+  EXPECT_EQ(SET("{ [] }"), singleton(USET("{ [] }"), SPACE("{ [] }")));
+  EXPECT_EQ(MAP("{ [] -> [] }"),
+            singleton(UMAP("{ [] -> [] }"), SPACE("{ [] -> [] }")));
+
+  // Many elements found
+  EXPECT_EQ(SET("{ [i] : 0 <= i < 10 }"),
+            singleton(USET("{ [i] : 0 <= i < 10 }"), SPACE("{ [i] }")));
+  EXPECT_EQ(
+      MAP("{ [i] -> [i] : 0 <= i < 10 }"),
+      singleton(UMAP("{ [i] -> [i] : 0 <= i < 10 }"), SPACE("{ [i] -> [j] }")));
+
+  // Different parameters
+  EXPECT_EQ(SET("[i] -> { [i] }"),
+            singleton(USET("[i] -> { [i] }"), SPACE("{ [i] }")));
+  EXPECT_EQ(MAP("[i] -> { [i] -> [i] }"),
+            singleton(UMAP("[i] -> { [i] -> [i] }"), SPACE("{ [i] -> [j] }")));
+}
+
+TEST(ISLTools, getNumScatterDims) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage
+  EXPECT_EQ(0u, getNumScatterDims(UMAP("{ [] -> [] }")));
+  EXPECT_EQ(1u, getNumScatterDims(UMAP("{ [] -> [i] }")));
+  EXPECT_EQ(2u, getNumScatterDims(UMAP("{ [] -> [i,j] }")));
+  EXPECT_EQ(3u, getNumScatterDims(UMAP("{ [] -> [i,j,k] }")));
+
+  // Different scatter spaces
+  EXPECT_EQ(0u, getNumScatterDims(UMAP("{ A[] -> []; [] -> []}")));
+  EXPECT_EQ(1u, getNumScatterDims(UMAP("{ A[] -> []; [] -> [i] }")));
+  EXPECT_EQ(2u, getNumScatterDims(UMAP("{ A[] -> [i]; [] -> [i,j] }")));
+  EXPECT_EQ(3u, getNumScatterDims(UMAP("{ A[] -> [i]; [] -> [i,j,k] }")));
+}
+
+TEST(ISLTools, getScatterSpace) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage
+  EXPECT_EQ(SPACE("{ [] }"), getScatterSpace(UMAP("{ [] -> [] }")));
+  EXPECT_EQ(SPACE("{ [i] }"), getScatterSpace(UMAP("{ [] -> [i] }")));
+  EXPECT_EQ(SPACE("{ [i,j] }"), getScatterSpace(UMAP("{ [] -> [i,j] }")));
+  EXPECT_EQ(SPACE("{ [i,j,k] }"), getScatterSpace(UMAP("{ [] -> [i,j,k] }")));
+
+  // Different scatter spaces
+  EXPECT_EQ(SPACE("{ [] }"), getScatterSpace(UMAP("{ A[] -> []; [] -> [] }")));
+  EXPECT_EQ(SPACE("{ [i] }"),
+            getScatterSpace(UMAP("{ A[] -> []; [] -> [i] }")));
+  EXPECT_EQ(SPACE("{ [i,j] }"),
+            getScatterSpace(UMAP("{ A[] -> [i]; [] -> [i,j] }")));
+  EXPECT_EQ(SPACE("{ [i,j,k] }"),
+            getScatterSpace(UMAP("{ A[] -> [i]; [] -> [i,j,k] }")));
+}
+
+TEST(ISLTools, makeIdentityMap) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage
+  EXPECT_EQ(UMAP("{ [i] -> [i] }"), makeIdentityMap(USET("{ [0] }"), false));
+  EXPECT_EQ(UMAP("{ [0] -> [0] }"), makeIdentityMap(USET("{ [0] }"), true));
+
+  // Multiple spaces
+  EXPECT_EQ(UMAP("{ [] -> []; [i] -> [i] }"),
+            makeIdentityMap(USET("{ []; [0] }"), false));
+  EXPECT_EQ(UMAP("{ [] -> []; [0] -> [0] }"),
+            makeIdentityMap(USET("{ []; [0] }"), true));
+
+  // Edge case: empty
+  EXPECT_EQ(UMAP("{ }"), makeIdentityMap(USET("{ }"), false));
+  EXPECT_EQ(UMAP("{ }"), makeIdentityMap(USET("{ }"), true));
+}
+
+TEST(ISLTools, reverseDomain) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage
+  EXPECT_EQ(MAP("{ [B[] -> A[]] -> [] }"),
+            reverseDomain(MAP("{ [A[] -> B[]] -> [] }")));
+  EXPECT_EQ(UMAP("{ [B[] -> A[]] -> [] }"),
+            reverseDomain(UMAP("{ [A[] -> B[]] -> [] }")));
+}
+
+TEST(ISLTools, shiftDim) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage
+  EXPECT_EQ(SET("{ [1] }"), shiftDim(SET("{ [0] }"), 0, 1));
+  EXPECT_EQ(USET("{ [1] }"), shiftDim(USET("{ [0] }"), 0, 1));
+
+  // From-end indexing
+  EXPECT_EQ(USET("{ [0,0,1] }"), shiftDim(USET("{ [0,0,0] }"), -1, 1));
+  EXPECT_EQ(USET("{ [0,1,0] }"), shiftDim(USET("{ [0,0,0] }"), -2, 1));
+  EXPECT_EQ(USET("{ [1,0,0] }"), shiftDim(USET("{ [0,0,0] }"), -3, 1));
+
+  // Parametrized
+  EXPECT_EQ(USET("[n] -> { [n+1] }"), shiftDim(USET("[n] -> { [n] }"), 0, 1));
+
+  // Union maps
+  EXPECT_EQ(MAP("{ [1] -> [] }"),
+            shiftDim(MAP("{ [0] -> [] }"), isl::dim::in, 0, 1));
+  EXPECT_EQ(UMAP("{ [1] -> [] }"),
+            shiftDim(UMAP("{ [0] -> [] }"), isl::dim::in, 0, 1));
+  EXPECT_EQ(MAP("{ [] -> [1] }"),
+            shiftDim(MAP("{ [] -> [0] }"), isl::dim::out, 0, 1));
+  EXPECT_EQ(UMAP("{ [] -> [1] }"),
+            shiftDim(UMAP("{ [] -> [0] }"), isl::dim::out, 0, 1));
+}
+
+TEST(DeLICM, computeReachingWrite) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : 0 < i }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), false, false,
+                                 false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : 0 < i }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), false, false,
+                                 true));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : 0 <= i }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), false, true,
+                                 false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : 0 <= i }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), false, true,
+                                 false));
+
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : i < 0 }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), true, false,
+                                 false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] :  i <= 0 }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), true, false,
+                                 true));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : i < 0 }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), true, true,
+                                 false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : i <= 0 }"),
+            computeReachingWrite(UMAP("{ Dom[] -> [0] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), true, true, true));
+
+  // Two writes
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom1[] : 0 < i < 10; [Elt[] -> [i]] -> "
+                 "Dom2[] : 10 < i }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 false, false, false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom1[] : 0 <= i < 10; [Elt[] -> [i]] -> "
+                 "Dom2[] : 10 <= i }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 false, true, false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom1[] : 0 < i <= 10; [Elt[] -> [i]] -> "
+                 "Dom2[] : 10 < i }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 false, false, true));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom1[] : 0 <= i <= 10; [Elt[] -> [i]] -> "
+                 "Dom2[] : 10 <= i }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 false, true, true));
+
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom2[] : 0 < i < 10; [Elt[] -> [i]] -> "
+                 "Dom1[] : i < 0 }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 true, false, false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom2[] : 0 <= i < 10; [Elt[] -> [i]] -> "
+                 "Dom1[] : i < 0 }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 true, true, false));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom2[] : 0 < i <= 10; [Elt[] -> [i]] -> "
+                 "Dom1[] : i <= 0 }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 true, false, true));
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom2[] : 0 <= i <= 10; [Elt[] -> [i]] -> "
+                 "Dom1[] : i <= 0 }"),
+            computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"),
+                                 UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"),
+                                 true, true, true));
+
+  // Domain in same space
+  EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[1] : 0 < i <= 10; [Elt[] -> [i]] -> "
+                 "Dom[2] : 10 < i }"),
+            computeReachingWrite(UMAP("{ Dom[i] -> [10i - 10] }"),
+                                 UMAP("{ Dom[1] -> Elt[]; Dom[2] -> Elt[] }"),
+                                 false, false, true));
+
+  // Parametric
+  EXPECT_EQ(UMAP("[p] -> { [Elt[] -> [i]] -> Dom[] : p < i }"),
+            computeReachingWrite(UMAP("[p] -> { Dom[] -> [p] }"),
+                                 UMAP("{ Dom[] -> Elt[] }"), false, false,
+                                 false));
+
+  // More realistic example (from reduction_embedded.ll)
+  EXPECT_EQ(
+      UMAP("{ [Elt[] -> [i]] -> Dom[0] : 0 < i <= 3; [Elt[] -> [i]] -> Dom[1] "
+           ": 3 < i <= 6; [Elt[] -> [i]] -> Dom[2] : 6 < i <= 9; [Elt[] -> "
+           "[i]] -> Dom[3] : 9 < i <= 12; [Elt[] -> [i]] -> Dom[4] : 12 < i }"),
+      computeReachingWrite(UMAP("{ Dom[i] -> [3i] : 0 <= i <= 4 }"),
+                           UMAP("{ Dom[i] -> Elt[] : 0 <= i <= 4 }"), false,
+                           false, true));
+}
+
+TEST(DeLICM, computeArrayUnused) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // The ReadEltInSameInst parameter doesn't matter in simple cases. To also
+  // cover the parameter without duplicating the tests, this loops runs over
+  // other in both settings.
+  for (bool ReadEltInSameInst = false, Done = false; !Done;
+       Done = ReadEltInSameInst, ReadEltInSameInst = true) {
+    // Basic usage: one read, one write
+    EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 < i < 10 }"),
+              computeArrayUnused(UMAP("{ Read[] -> [0]; Write[] -> [10] }"),
+                                 UMAP("{ Write[] -> Elt[] }"),
+                                 UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst,
+                                 false, false));
+    EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 < i <= 10 }"),
+              computeArrayUnused(UMAP("{ Read[] -> [0]; Write[] -> [10] }"),
+                                 UMAP("{ Write[] -> Elt[] }"),
+                                 UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst,
+                                 false, true));
+    EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 <= i < 10 }"),
+              computeArrayUnused(UMAP("{ Read[] -> [0]; Write[] -> [10] }"),
+                                 UMAP("{ Write[] -> Elt[] }"),
+                                 UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst,
+                                 true, false));
+    EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 <= i <= 10 }"),
+              computeArrayUnused(UMAP("{ Read[] -> [0]; Write[] -> [10] }"),
+                                 UMAP("{ Write[] -> Elt[] }"),
+                                 UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst,
+                                 true, true));
+
+    // Two reads
+    EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 < i <= 10 }"),
+              computeArrayUnused(
+                  UMAP("{ Read[0] -> [-10]; Read[1] -> [0]; Write[] -> [10] }"),
+                  UMAP("{ Write[] -> Elt[] }"), UMAP("{ Read[i] -> Elt[] }"),
+                  ReadEltInSameInst, false, true));
+
+    // Corner case: no writes
+    EXPECT_EQ(UMAP("{}"),
+              computeArrayUnused(UMAP("{ Read[] -> [0] }"), UMAP("{}"),
+                                 UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst,
+                                 false, false));
+
+    // Corner case: no reads
+    EXPECT_EQ(UMAP("{ Elt[] -> [i] : i <= 0 }"),
+              computeArrayUnused(UMAP("{ Write[] -> [0] }"),
+                                 UMAP("{ Write[] -> Elt[] }"), UMAP("{}"),
+                                 ReadEltInSameInst, false, true));
+
+    // Two writes
+    EXPECT_EQ(
+        UMAP("{ Elt[] -> [i] : i <= 10 }"),
+        computeArrayUnused(UMAP("{ WriteA[] -> [0];  WriteB[] -> [10] }"),
+                           UMAP("{ WriteA[] -> Elt[]; WriteB[] -> Elt[] }"),
+                           UMAP("{}"), ReadEltInSameInst, false, true));
+
+    // Two unused zones
+    // read,write,read,write
+    EXPECT_EQ(
+        UMAP("{ Elt[] -> [i] : 0 < i <= 10; Elt[] -> [i] : 20 < i <= 30 }"),
+        computeArrayUnused(UMAP("{ ReadA[] -> [0]; WriteA[] -> [10]; ReadB[] "
+                                "-> [20]; WriteB[] -> [30] }"),
+                           UMAP("{ WriteA[] -> Elt[]; WriteB[] -> Elt[] }"),
+                           UMAP("{ ReadA[] -> Elt[];  ReadB[] -> Elt[] }"),
+                           ReadEltInSameInst, false, true));
+
+    // write, write
+    EXPECT_EQ(
+        UMAP("{ Elt[] -> [i] : i <= 10 }"),
+        computeArrayUnused(
+            UMAP("{ WriteA[] -> [0];  WriteB[] -> [10];  Read[] -> [20] }"),
+            UMAP("{ WriteA[] -> Elt[]; WriteB[] -> Elt[] }"),
+            UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst, false, true));
+
+    // write, read
+    EXPECT_EQ(UMAP("{ Elt[] -> [i] : i <= 0 }"),
+              computeArrayUnused(UMAP("{ Write[] -> [0]; Read[] -> [10] }"),
+                                 UMAP("{ Write[] -> Elt[] }"),
+                                 UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst,
+                                 false, true));
+
+    // read, write, read
+    EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 < i <= 10 }"),
+              computeArrayUnused(
+                  UMAP("{ ReadA[] -> [0]; Write[] -> [10]; ReadB[] -> [20] }"),
+                  UMAP("{ Write[] -> Elt[] }"),
+                  UMAP("{ ReadA[] -> Elt[];  ReadB[] -> Elt[] }"),
+                  ReadEltInSameInst, false, true));
+
+    // read, write, write
+    EXPECT_EQ(
+        UMAP("{ Elt[] -> [i] : 0 < i <= 20 }"),
+        computeArrayUnused(
+            UMAP("{ Read[] -> [0]; WriteA[] -> [10];  WriteB[] -> [20] }"),
+            UMAP("{ WriteA[] -> Elt[]; WriteB[] -> Elt[] }"),
+            UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst, false, true));
+
+    // read, write, write, read
+    EXPECT_EQ(
+        UMAP("{ Elt[] -> [i] : 0 < i <= 20 }"),
+        computeArrayUnused(UMAP("{ ReadA[] -> [0]; WriteA[] -> [10];  WriteB[] "
+                                "-> [20]; ReadB[] -> [30] }"),
+                           UMAP("{ WriteA[] -> Elt[]; WriteB[] -> Elt[] }"),
+                           UMAP("{ ReadA[] -> Elt[];  ReadB[] -> Elt[] }"),
+                           ReadEltInSameInst, false, true));
+  }
+
+  // Read and write in same statement
+  EXPECT_EQ(UMAP("{ Elt[] -> [i] : i < 0 }"),
+            computeArrayUnused(UMAP("{ RW[] -> [0] }"),
+                               UMAP("{ RW[] -> Elt[] }"),
+                               UMAP("{ RW[] -> Elt[] }"), true, false, false));
+  EXPECT_EQ(UMAP("{ Elt[] -> [i] : i <= 0 }"),
+            computeArrayUnused(UMAP("{ RW[] -> [0] }"),
+                               UMAP("{ RW[] -> Elt[] }"),
+                               UMAP("{ RW[] -> Elt[] }"), true, false, true));
+  EXPECT_EQ(UMAP("{ Elt[] -> [0] }"),
+            computeArrayUnused(UMAP("{ RW[] -> [0] }"),
+                               UMAP("{ RW[] -> Elt[] }"),
+                               UMAP("{ RW[] -> Elt[] }"), false, true, true));
+}
+
+TEST(DeLICM, convertZoneToTimepoints) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Corner case: empty set
+  EXPECT_EQ(USET("{}"), convertZoneToTimepoints(USET("{}"), false, false));
+  EXPECT_EQ(USET("{}"), convertZoneToTimepoints(USET("{}"), true, false));
+  EXPECT_EQ(USET("{}"), convertZoneToTimepoints(USET("{}"), false, true));
+  EXPECT_EQ(USET("{}"), convertZoneToTimepoints(USET("{}"), true, true));
+
+  // Basic usage
+  EXPECT_EQ(USET("{}"), convertZoneToTimepoints(USET("{ [1] }"), false, false));
+  EXPECT_EQ(USET("{ [0] }"),
+            convertZoneToTimepoints(USET("{ [1] }"), true, false));
+  EXPECT_EQ(USET("{ [1] }"),
+            convertZoneToTimepoints(USET("{ [1] }"), false, true));
+  EXPECT_EQ(USET("{ [0]; [1] }"),
+            convertZoneToTimepoints(USET("{ [1] }"), true, true));
+
+  // Non-adjacent ranges
+  EXPECT_EQ(USET("{}"),
+            convertZoneToTimepoints(USET("{ [1]; [11] }"), false, false));
+  EXPECT_EQ(USET("{ [0]; [10] }"),
+            convertZoneToTimepoints(USET("{ [1]; [11] }"), true, false));
+  EXPECT_EQ(USET("{ [1]; [11] }"),
+            convertZoneToTimepoints(USET("{ [1]; [11] }"), false, true));
+  EXPECT_EQ(USET("{ [0]; [1]; [10]; [11] }"),
+            convertZoneToTimepoints(USET("{ [1]; [11] }"), true, true));
+
+  // Adjacent unit ranges
+  EXPECT_EQ(
+      USET("{ [i] : 0 < i < 10 }"),
+      convertZoneToTimepoints(USET("{ [i] : 0 < i <= 10 }"), false, false));
+  EXPECT_EQ(
+      USET("{ [i] : 0 <= i < 10 }"),
+      convertZoneToTimepoints(USET("{ [i] : 0 < i <= 10 }"), true, false));
+  EXPECT_EQ(
+      USET("{ [i] : 0 < i <= 10 }"),
+      convertZoneToTimepoints(USET("{ [i] : 0 < i <= 10 }"), false, true));
+  EXPECT_EQ(USET("{ [i] : 0 <= i <= 10 }"),
+            convertZoneToTimepoints(USET("{ [i] : 0 < i <= 10 }"), true, true));
+
+  // More than one dimension
+  EXPECT_EQ(USET("{}"),
+            convertZoneToTimepoints(USET("{ [0,1] }"), false, false));
+  EXPECT_EQ(USET("{ [0,0] }"),
+            convertZoneToTimepoints(USET("{ [0,1] }"), true, false));
+  EXPECT_EQ(USET("{ [0,1] }"),
+            convertZoneToTimepoints(USET("{ [0,1] }"), false, true));
+  EXPECT_EQ(USET("{ [0,0]; [0,1] }"),
+            convertZoneToTimepoints(USET("{ [0,1] }"), true, true));
+
+  // Map domains
+  EXPECT_EQ(UMAP("{}"), convertZoneToTimepoints(UMAP("{ [1] -> [] }"),
+                                                isl::dim::in, false, false));
+  EXPECT_EQ(UMAP("{ [0] -> [] }"),
+            convertZoneToTimepoints(UMAP("{ [1] -> [] }"), isl::dim::in, true,
+                                    false));
+  EXPECT_EQ(UMAP("{ [1] -> [] }"),
+            convertZoneToTimepoints(UMAP("{ [1] -> [] }"), isl::dim::in, false,
+                                    true));
+  EXPECT_EQ(
+      UMAP("{ [0] -> []; [1] -> [] }"),
+      convertZoneToTimepoints(UMAP("{ [1] -> [] }"), isl::dim::in, true, true));
+
+  // Map ranges
+  EXPECT_EQ(UMAP("{}"), convertZoneToTimepoints(UMAP("{ [] -> [1] }"),
+                                                isl::dim::out, false, false));
+  EXPECT_EQ(UMAP("{ [] -> [0] }"),
+            convertZoneToTimepoints(UMAP("{ [] -> [1] }"), isl::dim::out, true,
+                                    false));
+  EXPECT_EQ(UMAP("{ [] -> [1] }"),
+            convertZoneToTimepoints(UMAP("{ [] -> [1] }"), isl::dim::out, false,
+                                    true));
+  EXPECT_EQ(UMAP("{ [] -> [0]; [] -> [1] }"),
+            convertZoneToTimepoints(UMAP("{ [] -> [1] }"), isl::dim::out, true,
+                                    true));
+}
+
+TEST(DeLICM, distribute) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage
+  EXPECT_EQ(MAP("{ [Domain[] -> Range1[]] -> [Domain[] -> Range2[]] }"),
+            distributeDomain(MAP("{ Domain[] -> [Range1[] -> Range2[]] }")));
+  EXPECT_EQ(
+      MAP("{ [Domain[i,j] -> Range1[i,k]] -> [Domain[i,j] -> Range2[j,k]] }"),
+      distributeDomain(MAP("{ Domain[i,j] -> [Range1[i,k] -> Range2[j,k]] }")));
+
+  // Union maps
+  EXPECT_EQ(
+      UMAP(
+          "{ [DomainA[i,j] -> RangeA1[i,k]] -> [DomainA[i,j] -> RangeA2[j,k]];"
+          "[DomainB[i,j] -> RangeB1[i,k]] -> [DomainB[i,j] -> RangeB2[j,k]] }"),
+      distributeDomain(
+          UMAP("{ DomainA[i,j] -> [RangeA1[i,k] -> RangeA2[j,k]];"
+               "DomainB[i,j] -> [RangeB1[i,k] -> RangeB2[j,k]] }")));
+}
+
+TEST(DeLICM, lift) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage
+  EXPECT_EQ(UMAP("{ [Factor[] -> Domain[]] -> [Factor[] -> Range[]] }"),
+            liftDomains(UMAP("{ Domain[] -> Range[] }"), USET("{ Factor[] }")));
+  EXPECT_EQ(UMAP("{ [Factor[l] -> Domain[i,k]] -> [Factor[l] -> Range[j,k]] }"),
+            liftDomains(UMAP("{ Domain[i,k] -> Range[j,k] }"),
+                        USET("{ Factor[l] }")));
+
+  // Multiple maps in union
+  EXPECT_EQ(
+      UMAP("{ [FactorA[] -> DomainA[]] -> [FactorA[] -> RangeA[]];"
+           "[FactorB[] -> DomainA[]] -> [FactorB[] -> RangeA[]];"
+           "[FactorA[] -> DomainB[]] -> [FactorA[] -> RangeB[]];"
+           "[FactorB[] -> DomainB[]] -> [FactorB[] -> RangeB[]] }"),
+      liftDomains(UMAP("{ DomainA[] -> RangeA[]; DomainB[] -> RangeB[] }"),
+                  USET("{ FactorA[]; FactorB[] }")));
+}
+
+TEST(DeLICM, apply) {
+  std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(),
+                                                        &isl_ctx_free);
+
+  // Basic usage
+  EXPECT_EQ(
+      UMAP("{ [DomainDomain[] -> NewDomainRange[]] -> Range[] }"),
+      applyDomainRange(UMAP("{ [DomainDomain[] -> DomainRange[]] -> Range[] }"),
+                       UMAP("{ DomainRange[] -> NewDomainRange[] }")));
+  EXPECT_EQ(
+      UMAP("{ [DomainDomain[i,k] -> NewDomainRange[j,k,l]] -> Range[i,j] }"),
+      applyDomainRange(
+          UMAP("{ [DomainDomain[i,k] -> DomainRange[j,k]] -> Range[i,j] }"),
+          UMAP("{ DomainRange[j,k] -> NewDomainRange[j,k,l] }")));
+
+  // Multiple maps in union
+  EXPECT_EQ(UMAP("{ [DomainDomainA[] -> NewDomainRangeA[]] -> RangeA[];"
+                 "[DomainDomainB[] -> NewDomainRangeB[]] -> RangeB[] }"),
+            applyDomainRange(
+                UMAP("{ [DomainDomainA[] -> DomainRangeA[]] -> RangeA[];"
+                     "[DomainDomainB[] -> DomainRangeB[]] -> RangeB[] }"),
+                UMAP("{ DomainRangeA[] -> NewDomainRangeA[];"
+                     "DomainRangeB[] -> NewDomainRangeB[] }")));
+}
+
+} // anonymous namespace
diff --git a/final/unittests/ScheduleOptimizer/CMakeLists.txt b/final/unittests/ScheduleOptimizer/CMakeLists.txt
new file mode 100644
index 0000000..75adea6
--- /dev/null
+++ b/final/unittests/ScheduleOptimizer/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_polly_unittest(ScheduleOptimizerTests
+    ScheduleOptimizerTest.cpp
+  )
diff --git a/final/unittests/ScheduleOptimizer/ScheduleOptimizerTest.cpp b/final/unittests/ScheduleOptimizer/ScheduleOptimizerTest.cpp
new file mode 100644
index 0000000..d23766d
--- /dev/null
+++ b/final/unittests/ScheduleOptimizer/ScheduleOptimizerTest.cpp
@@ -0,0 +1,60 @@
+//===- ScheduleOptimizerTest.cpp ------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/ScheduleOptimizer.h"
+#include "gtest/gtest.h"
+#include "isl/stream.h"
+#include "isl/val.h"
+
+using namespace isl;
+namespace {
+
+TEST(ScheduleOptimizer, getPartialTilePrefixes) {
+
+  isl_ctx *ctx = isl_ctx_alloc();
+
+  {
+    // Verify that for a loop with 3 iterations starting at 0 that is
+    // pre-vectorized (strip-mined with a factor of 2), we correctly identify
+    // that only the first two iterations are full vector iterations.
+    isl::map Schedule(
+        ctx, "{[i] -> [floor(i/2), i - 2 * floor(i/2)] : 0 <= i < 3 }");
+    isl::set ScheduleRange = Schedule.range();
+    isl::set Result = getPartialTilePrefixes(ScheduleRange, 2);
+
+    EXPECT_TRUE(Result.is_equal(isl::set(ctx, "{[0]}")));
+  }
+
+  {
+    // Verify that for a loop with 3 iterations starting at 1 that is
+    // pre-vectorized (strip-mined with a factor of 2), we correctly identify
+    // that only the last two iterations are full vector iterations.
+    isl::map Schedule(
+        ctx, "{[i] -> [floor(i/2), i - 2 * floor(i/2)] : 1 <= i < 4 }");
+    isl::set ScheduleRange = Schedule.range();
+    isl::set Result = getPartialTilePrefixes(ScheduleRange, 2);
+
+    EXPECT_TRUE(Result.is_equal(isl::set(ctx, "{[1]}")));
+  }
+
+  {
+    // Verify that for a loop with 6 iterations starting at 1 that is
+    // pre-vectorized (strip-mined with a factor of 2), we correctly identify
+    // that all but the first and the last iteration are full vector iterations.
+    isl::map Schedule(
+        ctx, "{[i] -> [floor(i/2), i - 2 * floor(i/2)] : 1 <= i < 6 }");
+    isl::set ScheduleRange = Schedule.range();
+    isl::set Result = getPartialTilePrefixes(ScheduleRange, 2);
+
+    EXPECT_TRUE(Result.is_equal(isl::set(ctx, "{[1]; [2]}")));
+  }
+
+  isl_ctx_free(ctx);
+}
+} // anonymous namespace
diff --git a/final/unittests/ScopPassManager/CMakeLists.txt b/final/unittests/ScopPassManager/CMakeLists.txt
new file mode 100644
index 0000000..59c5a4a
--- /dev/null
+++ b/final/unittests/ScopPassManager/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_polly_unittest(ScopPassManagerTests
+  PassManagerTest.cpp
+  )
diff --git a/final/unittests/ScopPassManager/PassManagerTest.cpp b/final/unittests/ScopPassManager/PassManagerTest.cpp
new file mode 100644
index 0000000..49299c2
--- /dev/null
+++ b/final/unittests/ScopPassManager/PassManagerTest.cpp
@@ -0,0 +1,66 @@
+#include "llvm/IR/PassManager.h"
+#include "polly/CodeGen/IslAst.h"
+#include "polly/DependenceInfo.h"
+#include "polly/ScopPass.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/CGSCCPassManager.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Transforms/Scalar/LoopPassManager.h"
+#include "gtest/gtest.h"
+
+using namespace polly;
+using namespace llvm;
+
+namespace {
+class ScopPassRegistry : public ::testing::Test {
+protected:
+  ModuleAnalysisManager MAM;
+  FunctionAnalysisManager FAM;
+  LoopAnalysisManager LAM;
+  CGSCCAnalysisManager CGAM;
+  ScopAnalysisManager SAM;
+  AAManager AM;
+
+public:
+  ScopPassRegistry(ScopPassRegistry &&) = delete;
+  ScopPassRegistry(const ScopPassRegistry &) = delete;
+  ScopPassRegistry &operator=(ScopPassRegistry &&) = delete;
+  ScopPassRegistry &operator=(const ScopPassRegistry &) = delete;
+  ScopPassRegistry() {
+    PassBuilder PB;
+
+    AM = PB.buildDefaultAAPipeline();
+    PB.registerModuleAnalyses(MAM);
+    PB.registerFunctionAnalyses(FAM);
+    PB.registerLoopAnalyses(LAM);
+    PB.registerCGSCCAnalyses(CGAM);
+
+    FAM.registerPass([] { return ScopAnalysis(); });
+    FAM.registerPass([] { return ScopInfoAnalysis(); });
+    FAM.registerPass([this] { return ScopAnalysisManagerFunctionProxy(SAM); });
+
+    // SAM.registerPass([] { return IslAstAnalysis(); });
+    // SAM.registerPass([] { return DependenceAnalysis(); });
+    SAM.registerPass([this] { return FunctionAnalysisManagerScopProxy(FAM); });
+
+    PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+  }
+};
+
+TEST_F(ScopPassRegistry, PrintScops) {
+  FunctionPassManager FPM;
+  FPM.addPass(ScopAnalysisPrinterPass(errs()));
+}
+
+TEST_F(ScopPassRegistry, PrintScopInfo) {
+  FunctionPassManager FPM;
+  FPM.addPass(ScopInfoPrinterPass(errs()));
+}
+
+TEST_F(ScopPassRegistry, PrinIslAstInfo) {
+  FunctionPassManager FPM;
+  ScopPassManager SPM;
+  // SPM.addPass(IslAstPrinterPass(errs()));
+  FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
+}
+} // namespace
diff --git a/final/utils/arcanist/LitTestEngine/__phutil_library_init__.php b/final/utils/arcanist/LitTestEngine/__phutil_library_init__.php
new file mode 100644
index 0000000..72dd4a7
--- /dev/null
+++ b/final/utils/arcanist/LitTestEngine/__phutil_library_init__.php
@@ -0,0 +1,3 @@
+<?php
+
+phutil_register_library('lit-test-engine', __FILE__);
diff --git a/final/utils/arcanist/LitTestEngine/__phutil_library_map__.php b/final/utils/arcanist/LitTestEngine/__phutil_library_map__.php
new file mode 100644
index 0000000..6607226
--- /dev/null
+++ b/final/utils/arcanist/LitTestEngine/__phutil_library_map__.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * This file is automatically generated. Use 'arc liberate' to rebuild it.
+ * @generated
+ * @phutil-library-version 2
+ */
+
+phutil_register_library_map(array(
+  '__library_version__' => 2,
+  'class' =>
+  array(
+    'LitTestEngine' => 'src/LitTestEngine.php',
+  ),
+  'function' =>
+  array(
+  ),
+  'xmap' =>
+  array(
+    'LitTestEngine' => 'ArcanistBaseUnitTestEngine',
+  ),
+));
diff --git a/final/utils/arcanist/LitTestEngine/src/LitTestEngine.php b/final/utils/arcanist/LitTestEngine/src/LitTestEngine.php
new file mode 100644
index 0000000..5b82891
--- /dev/null
+++ b/final/utils/arcanist/LitTestEngine/src/LitTestEngine.php
@@ -0,0 +1,279 @@
+<?php
+
+/**
+ * llvm-lit wrapper
+ *
+ * To use, set unit.engine in .arcconfig, or use --engine flag
+ * with arc unit.
+ *
+ * This file was authored by Clemens Hammacher <hammacher@cs.uni-saarland.de>
+ * and initially used in the Sambamba project (www.sambamba.org).
+ *
+ * @group unitrun
+ */
+final class LitTestEngine extends ArcanistUnitTestEngine {
+
+    protected function supportsRunAllTests() {
+        return true;
+    }
+
+    private function progress($results, $numTests) {
+        static $colors = array(
+            ArcanistUnitTestResult::RESULT_PASS => 'green',
+            ArcanistUnitTestResult::RESULT_FAIL => 'red',
+            ArcanistUnitTestResult::RESULT_SKIP => 'yellow',
+            ArcanistUnitTestResult::RESULT_BROKEN => 'red',
+            ArcanistUnitTestResult::RESULT_UNSOUND => 'yellow',
+            ArcanistUnitTestResult::RESULT_POSTPONED => 'yellow'
+        );
+
+        $s = "\t[\033[0;30m";
+        $number = -1;
+        $lastColor = "";
+        $lastResult = "";
+        $lastNumber = "";
+        foreach ($results as $result) {
+            $color = $colors[$result->getResult()];
+            if (!$color && $lastColor)
+                $s .= "</bg>";
+            elseif (!$lastColor && $color)
+                $s .= "<bg:$color>";
+            elseif ($lastColor !== $color)
+                $s .= "</bg><bg:$color>";
+            if ($number <= 0)
+              $number = 1;
+            elseif ($lastResult == $result->getResult())
+              $number += 1;
+            else
+              $number = 1;
+            if ($number > 1 && $number <= 10)
+              $s = substr($s, 0, -1);
+            elseif ($number > 10 && $number <= 100)
+              $s = substr($s, 0, -2);
+            elseif ($number > 100 && $number <= 1000)
+              $s = substr($s, 0, -3);
+            $s .= "$number";
+            $lastNumber = $number;
+            $lastResult = $result->getResult();
+            $lastColor = $color;
+        }
+        if ($lastColor)
+            $s .= "</bg>";
+        $s .= "\033[0m";
+        $c = count($results);
+        if ($numTests)
+          $s .=  " $c/$numTests]";
+        else
+            $s .= " $c]";
+        return phutil_console_format($s);
+    }
+
+    public function run() {
+
+        $projectRoot = $this->getWorkingCopy()->getProjectRoot();
+        $cwd = getcwd();
+        $buildDir = $this->findBuildDirectory($projectRoot, $cwd);
+        $pollyObjDir = $buildDir;
+        if (is_dir($buildDir.DIRECTORY_SEPARATOR."tools".DIRECTORY_SEPARATOR."polly"))
+          $pollyObjDir = $buildDir.DIRECTORY_SEPARATOR."tools".DIRECTORY_SEPARATOR."polly";
+        $pollyTestDir = $pollyObjDir.DIRECTORY_SEPARATOR."test";
+
+        if (is_dir($buildDir.DIRECTORY_SEPARATOR."bin") &&
+          file_exists($buildDir.DIRECTORY_SEPARATOR."bin".DIRECTORY_SEPARATOR."llvm-lit")) {
+          $lit = $buildDir.DIRECTORY_SEPARATOR."bin".DIRECTORY_SEPARATOR."llvm-lit";
+          $cmd = "ninja -C ".$buildDir;
+          print "Running ninja (".$cmd.")\n";
+          exec($cmd);
+        } else {
+          $makeVars = $this->getMakeVars($buildDir);
+          $lit = $this->findLitExecutable($makeVars);
+        }
+        print "Using lit executable '$lit'\n";
+
+        // We have to modify the format string, because llvm-lit does not like a '' argument
+        $cmd = '%s ' . ($this->getEnableAsyncTests() ? '' : '-j1 ') .'%s 2>&1';
+        $litFuture = new ExecFuture($cmd, $lit, $pollyTestDir);
+        $out = "";
+        $results = array();
+        $lastTime = microtime(true);
+        $ready = false;
+        $dots = "";
+        $numTests = 0;
+        while (!$ready) {
+            $ready = $litFuture->isReady();
+            $newout = $litFuture->readStdout();
+            if (strlen($newout) == 0) {
+                usleep(100);
+                continue;
+            }
+            $out .= $newout;
+            if ($ready && strlen($out) > 0 && substr($out, -1) != "\n")
+                $out .= "\n";
+
+            while (($nlPos = strpos($out, "\n")) !== FALSE) {
+                $line = substr($out, 0, $nlPos+1);
+                $out = substr($out, $nlPos+1);
+
+                $res = ArcanistUnitTestResult::RESULT_UNSOUND;
+                if (substr($line, 0, 6) == "PASS: ") {
+                    $res = ArcanistUnitTestResult::RESULT_PASS;
+                } elseif (substr($line, 0, 6) == "FAIL: ") {
+                    $res = ArcanistUnitTestResult::RESULT_FAIL;
+                } elseif (substr($line, 0, 7) == "XPASS: ") {
+                    $res = ArcanistUnitTestResult::RESULT_FAIL;
+                } elseif (substr($line, 0, 7) == "XFAIL: ") {
+                    $res = ArcanistUnitTestResult::RESULT_PASS;
+                } elseif (substr($line, 0, 13) == "UNSUPPORTED: ") {
+                    $res = ArcanistUnitTestResult::RESULT_SKIP;
+                } elseif (!$numTests && preg_match('/Testing: ([0-9]+) tests/', $line, $matches)) {
+                    $numTests = (int)$matches[1];
+                }
+                if ($res == ArcanistUnitTestResult::RESULT_FAIL)
+                    print "\033[0A";
+                if ($res != ArcanistUnitTestResult::RESULT_SKIP && $res != ArcanistUnitTestResult::RESULT_PASS)
+                    print "\r\033[K\033[0A".$line.self::progress($results, $numTests);
+                if ($res == ArcanistUnitTestResult::RESULT_UNSOUND)
+                    continue;
+                $result = new ArcanistUnitTestResult();
+                $result->setName(trim(substr($line, strpos($line, ':') + 1)));
+                $result->setResult($res);
+                $newTime = microtime(true);
+                $result->setDuration($newTime - $lastTime);
+                $lastTime = $newTime;
+                $results[] = $result;
+                $dots .= ".";
+                print "\r\033[K\033[0A".self::progress($results, $numTests);
+            }
+        }
+        list ($out1,$out2) = $litFuture->read();
+        print $out1;
+        if ($out2) {
+            throw new Exception('There was error output, even though it should have been redirected to stdout.');
+        }
+        print "\n";
+
+        $timeThreshold = 0.050;
+        $interestingTests = array();
+        foreach ($results as $result) {
+          if ($result->getResult() != "pass")
+            $interestingTests[] = $result;
+          if ($result->getDuration() > $timeThreshold)
+            $interestingTests[] = $result;
+        }
+        return $interestingTests;
+    }
+
+    /**
+     * Try to find the build directory of the project, starting from the
+     * project root, and the current working directory.
+     * Also, the environment variable POLLY_BIN_DIR is read to determine the
+     * correct location.
+     *
+     * Search locations are:
+     * $POLLY_BIN_DIR (environment variable)
+     * <root>/build
+     * <root>.build
+     * <root>-build
+     * <root:s/src/build>
+     * <cwd>
+     *
+     * This list might be extended in the future according to other common
+     * setup.
+     *
+     * @param   projectRoot   Directory of the project root
+     * @param   cwd           Current working directory
+     * @return  string        Presumable build directory
+     */
+    public static function findBuildDirectory($projectRoot, $cwd) {
+
+        $projectRoot = rtrim($projectRoot, DIRECTORY_SEPARATOR);
+        $cwd = rtrim($cwd, DIRECTORY_SEPARATOR);
+
+        $tries = array();
+
+        $smbbin_env = getenv("POLLY_BIN_DIR");
+        if ($smbbin_env)
+            $tries[] = $smbbin_env;
+
+        $tries[] = $projectRoot.DIRECTORY_SEPARATOR."build";
+        $tries[] = $projectRoot.".build";
+        $tries[] = $projectRoot."-build";
+
+        // Try to replace each occurence of "src" by "build" (also within path components, like llvm-src)
+        $srcPos = 0;
+        while (($srcPos = strpos($projectRoot, "src", $srcPos)) !== FALSE) {
+            $tries[] = substr($projectRoot, 0, $srcPos)."build".substr($projectRoot, $srcPos+3);
+            $srcPos += 3;
+        }
+
+        $tries[] = $cwd;
+
+        foreach ($tries as $try) {
+            if (is_dir($try) &&
+                (file_exists($try.DIRECTORY_SEPARATOR."test".DIRECTORY_SEPARATOR."lit.site.cfg") ||
+                file_exists($try.DIRECTORY_SEPARATOR."test".DIRECTORY_SEPARATOR."lit.cfg")))
+                return Filesystem::resolvePath($try);
+        }
+
+        throw new Exception("Did not find a build directory for project '$projectRoot', cwd '$cwd'.\n" .
+            "Make sure to have a 'test' directory inside build, which contains lit.cfg or lit.site.cfg.\n" .
+            "You might have to run 'make test' once in the build directory.");
+    }
+
+    /**
+     * Try to find the llvm build directory, based on the make variables
+     * as determined by getMakeVars().
+     *
+     * @param   makeVars      The determined make variables
+     * @return  string        Presumable llvm build directory
+     */
+    public static function getLLVMObjDir($makeVars) {
+        if (!array_key_exists('LLVM_OBJ_ROOT', $makeVars))
+            throw new Exception("Make variables (determined by 'make printvars') does not contain LLVM_OBJ_ROOT.");
+        $llvmObjDir = $makeVars['LLVM_OBJ_ROOT'];
+        if (!is_dir($llvmObjDir))
+            throw new Exception("LLVM_OBJ_ROOT ('$llvmObjDir') is no directory.");
+        return $llvmObjDir;
+    }
+
+    /**
+     * Determine the make variables, by calling 'make printvars' in the
+     * build directory.
+     *
+     * @param   buildDir      The determined build directory
+     * @return  map<str,str>  Map of printed make variables to values
+     */
+    public static function getMakeVars($buildDir) {
+        $litFuture = new ExecFuture('make -C %s printvars', $buildDir);
+        list($stdout, $stderr) = $litFuture->resolvex(10);
+        print $stderr;
+        $makeVars = array();
+
+        foreach (explode("\n", $stdout) as $line) {
+            $components = explode(':', $line);
+            if (count($components) == 3)
+                $makeVars[trim($components[1])] = trim($components[2]);
+        }
+
+        return $makeVars;
+    }
+
+    /**
+     * Return full path to the llvm-lit executable.
+     *
+     * @param   llvmObjDir    The determined llvm build directory
+     * @return  string        Full path to the llvm-lit executable
+     */
+    public static function findLitExecutable($makeVars) {
+        $llvmObjDir = self::getLLVMObjDir($makeVars);
+        $buildMode = array_key_exists('BuildMode', $makeVars) ? $makeVars['BuildMode'] : '';
+
+        if (!$buildMode)
+            throw new Exception("Make variables (determined by 'make printvars') does not contain BuildMode.");
+
+        $lit = $llvmObjDir.DIRECTORY_SEPARATOR.$buildMode.DIRECTORY_SEPARATOR.'bin'.DIRECTORY_SEPARATOR.'llvm-lit';
+        if (!is_executable($lit))
+            throw new Exception("File does not exists or is not executable: $lit");
+        return $lit;
+    }
+}
diff --git a/final/utils/argparse.py b/final/utils/argparse.py
new file mode 100644
index 0000000..a060129
--- /dev/null
+++ b/final/utils/argparse.py
@@ -0,0 +1,2353 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © 2006-2009 Steven J. Bethard <steven.bethard@gmail.com>.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy
+# of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""Command-line parsing library
+
+This module is an optparse-inspired command-line parsing library that:
+
+    - handles both optional and positional arguments
+    - produces highly informative usage messages
+    - supports parsers that dispatch to sub-parsers
+
+The following is a simple usage example that sums integers from the
+command-line and writes the result to a file::
+
+    parser = argparse.ArgumentParser(
+        description='sum the integers at the command line')
+    parser.add_argument(
+        'integers', metavar='int', nargs='+', type=int,
+        help='an integer to be summed')
+    parser.add_argument(
+        '--log', default=sys.stdout, type=argparse.FileType('w'),
+        help='the file where the sum should be written')
+    args = parser.parse_args()
+    args.log.write('%s' % sum(args.integers))
+    args.log.close()
+
+The module contains the following public classes:
+
+    - ArgumentParser -- The main entry point for command-line parsing. As the
+        example above shows, the add_argument() method is used to populate
+        the parser with actions for optional and positional arguments. Then
+        the parse_args() method is invoked to convert the args at the
+        command-line into an object with attributes.
+
+    - ArgumentError -- The exception raised by ArgumentParser objects when
+        there are errors with the parser's actions. Errors raised while
+        parsing the command-line are caught by ArgumentParser and emitted
+        as command-line messages.
+
+    - FileType -- A factory for defining types of files to be created. As the
+        example above shows, instances of FileType are typically passed as
+        the type= argument of add_argument() calls.
+
+    - Action -- The base class for parser actions. Typically actions are
+        selected by passing strings like 'store_true' or 'append_const' to
+        the action= argument of add_argument(). However, for greater
+        customization of ArgumentParser actions, subclasses of Action may
+        be defined and passed as the action= argument.
+
+    - HelpFormatter, RawDescriptionHelpFormatter, RawTextHelpFormatter,
+        ArgumentDefaultsHelpFormatter -- Formatter classes which
+        may be passed as the formatter_class= argument to the
+        ArgumentParser constructor. HelpFormatter is the default,
+        RawDescriptionHelpFormatter and RawTextHelpFormatter tell the parser
+        not to change the formatting for help text, and
+        ArgumentDefaultsHelpFormatter adds information about argument defaults
+        to the help.
+
+All other classes in this module are considered implementation details.
+(Also note that HelpFormatter and RawDescriptionHelpFormatter are only
+considered public as object names -- the API of the formatter objects is
+still considered an implementation detail.)
+"""
+
+__version__ = '1.1'
+__all__ = [
+    'ArgumentParser',
+    'ArgumentError',
+    'Namespace',
+    'Action',
+    'FileType',
+    'HelpFormatter',
+    'RawDescriptionHelpFormatter',
+    'RawTextHelpFormatter',
+    'ArgumentDefaultsHelpFormatter',
+]
+
+
+import copy as _copy
+import os as _os
+import re as _re
+import sys as _sys
+import textwrap as _textwrap
+
+from gettext import gettext as _
+
+try:
+    _set = set
+except NameError:
+    from sets import Set as _set
+
+try:
+    _basestring = basestring
+except NameError:
+    _basestring = str
+
+try:
+    _sorted = sorted
+except NameError:
+
+    def _sorted(iterable, reverse=False):
+        result = list(iterable)
+        result.sort()
+        if reverse:
+            result.reverse()
+        return result
+
+
+def _callable(obj):
+    return hasattr(obj, '__call__') or hasattr(obj, '__bases__')
+
+# silence Python 2.6 buggy warnings about Exception.message
+if _sys.version_info[:2] == (2, 6):
+    import warnings
+    warnings.filterwarnings(
+        action='ignore',
+        message='BaseException.message has been deprecated as of Python 2.6',
+        category=DeprecationWarning,
+        module='argparse')
+
+
+SUPPRESS = '==SUPPRESS=='
+
+OPTIONAL = '?'
+ZERO_OR_MORE = '*'
+ONE_OR_MORE = '+'
+PARSER = 'A...'
+REMAINDER = '...'
+
+# =============================
+# Utility functions and classes
+# =============================
+
+class _AttributeHolder(object):
+    """Abstract base class that provides __repr__.
+
+    The __repr__ method returns a string in the format::
+        ClassName(attr=name, attr=name, ...)
+    The attributes are determined either by a class-level attribute,
+    '_kwarg_names', or by inspecting the instance __dict__.
+    """
+
+    def __repr__(self):
+        type_name = type(self).__name__
+        arg_strings = []
+        for arg in self._get_args():
+            arg_strings.append(repr(arg))
+        for name, value in self._get_kwargs():
+            arg_strings.append('%s=%r' % (name, value))
+        return '%s(%s)' % (type_name, ', '.join(arg_strings))
+
+    def _get_kwargs(self):
+        return _sorted(self.__dict__.items())
+
+    def _get_args(self):
+        return []
+
+
+def _ensure_value(namespace, name, value):
+    if getattr(namespace, name, None) is None:
+        setattr(namespace, name, value)
+    return getattr(namespace, name)
+
+
+# ===============
+# Formatting Help
+# ===============
+
+class HelpFormatter(object):
+    """Formatter for generating usage messages and argument help strings.
+
+    Only the name of this class is considered a public API. All the methods
+    provided by the class are considered an implementation detail.
+    """
+
+    def __init__(self,
+                 prog,
+                 indent_increment=2,
+                 max_help_position=24,
+                 width=None):
+
+        # default setting for width
+        if width is None:
+            try:
+                width = int(_os.environ['COLUMNS'])
+            except (KeyError, ValueError):
+                width = 80
+            width -= 2
+
+        self._prog = prog
+        self._indent_increment = indent_increment
+        self._max_help_position = max_help_position
+        self._width = width
+
+        self._current_indent = 0
+        self._level = 0
+        self._action_max_length = 0
+
+        self._root_section = self._Section(self, None)
+        self._current_section = self._root_section
+
+        self._whitespace_matcher = _re.compile(r'\s+')
+        self._long_break_matcher = _re.compile(r'\n\n\n+')
+
+    # ===============================
+    # Section and indentation methods
+    # ===============================
+    def _indent(self):
+        self._current_indent += self._indent_increment
+        self._level += 1
+
+    def _dedent(self):
+        self._current_indent -= self._indent_increment
+        assert self._current_indent >= 0, 'Indent decreased below 0.'
+        self._level -= 1
+
+    class _Section(object):
+
+        def __init__(self, formatter, parent, heading=None):
+            self.formatter = formatter
+            self.parent = parent
+            self.heading = heading
+            self.items = []
+
+        def format_help(self):
+            # format the indented section
+            if self.parent is not None:
+                self.formatter._indent()
+            join = self.formatter._join_parts
+            for func, args in self.items:
+                func(*args)
+            item_help = join([func(*args) for func, args in self.items])
+            if self.parent is not None:
+                self.formatter._dedent()
+
+            # return nothing if the section was empty
+            if not item_help:
+                return ''
+
+            # add the heading if the section was non-empty
+            if self.heading is not SUPPRESS and self.heading is not None:
+                current_indent = self.formatter._current_indent
+                heading = '%*s%s:\n' % (current_indent, '', self.heading)
+            else:
+                heading = ''
+
+            # join the section-initial newline, the heading and the help
+            return join(['\n', heading, item_help, '\n'])
+
+    def _add_item(self, func, args):
+        self._current_section.items.append((func, args))
+
+    # ========================
+    # Message building methods
+    # ========================
+    def start_section(self, heading):
+        self._indent()
+        section = self._Section(self, self._current_section, heading)
+        self._add_item(section.format_help, [])
+        self._current_section = section
+
+    def end_section(self):
+        self._current_section = self._current_section.parent
+        self._dedent()
+
+    def add_text(self, text):
+        if text is not SUPPRESS and text is not None:
+            self._add_item(self._format_text, [text])
+
+    def add_usage(self, usage, actions, groups, prefix=None):
+        if usage is not SUPPRESS:
+            args = usage, actions, groups, prefix
+            self._add_item(self._format_usage, args)
+
+    def add_argument(self, action):
+        if action.help is not SUPPRESS:
+
+            # find all invocations
+            get_invocation = self._format_action_invocation
+            invocations = [get_invocation(action)]
+            for subaction in self._iter_indented_subactions(action):
+                invocations.append(get_invocation(subaction))
+
+            # update the maximum item length
+            invocation_length = max([len(s) for s in invocations])
+            action_length = invocation_length + self._current_indent
+            self._action_max_length = max(self._action_max_length,
+                                          action_length)
+
+            # add the item to the list
+            self._add_item(self._format_action, [action])
+
+    def add_arguments(self, actions):
+        for action in actions:
+            self.add_argument(action)
+
+    # =======================
+    # Help-formatting methods
+    # =======================
+    def format_help(self):
+        help = self._root_section.format_help()
+        if help:
+            help = self._long_break_matcher.sub('\n\n', help)
+            help = help.strip('\n') + '\n'
+        return help
+
+    def _join_parts(self, part_strings):
+        return ''.join([part
+                        for part in part_strings
+                        if part and part is not SUPPRESS])
+
+    def _format_usage(self, usage, actions, groups, prefix):
+        if prefix is None:
+            prefix = _('usage: ')
+
+        # if usage is specified, use that
+        if usage is not None:
+            usage = usage % dict(prog=self._prog)
+
+        # if no optionals or positionals are available, usage is just prog
+        elif usage is None and not actions:
+            usage = '%(prog)s' % dict(prog=self._prog)
+
+        # if optionals and positionals are available, calculate usage
+        elif usage is None:
+            prog = '%(prog)s' % dict(prog=self._prog)
+
+            # split optionals from positionals
+            optionals = []
+            positionals = []
+            for action in actions:
+                if action.option_strings:
+                    optionals.append(action)
+                else:
+                    positionals.append(action)
+
+            # build full usage string
+            format = self._format_actions_usage
+            action_usage = format(optionals + positionals, groups)
+            usage = ' '.join([s for s in [prog, action_usage] if s])
+
+            # wrap the usage parts if it's too long
+            text_width = self._width - self._current_indent
+            if len(prefix) + len(usage) > text_width:
+
+                # break usage into wrappable parts
+                part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
+                opt_usage = format(optionals, groups)
+                pos_usage = format(positionals, groups)
+                opt_parts = _re.findall(part_regexp, opt_usage)
+                pos_parts = _re.findall(part_regexp, pos_usage)
+                assert ' '.join(opt_parts) == opt_usage
+                assert ' '.join(pos_parts) == pos_usage
+
+                # helper for wrapping lines
+                def get_lines(parts, indent, prefix=None):
+                    lines = []
+                    line = []
+                    if prefix is not None:
+                        line_len = len(prefix) - 1
+                    else:
+                        line_len = len(indent) - 1
+                    for part in parts:
+                        if line_len + 1 + len(part) > text_width:
+                            lines.append(indent + ' '.join(line))
+                            line = []
+                            line_len = len(indent) - 1
+                        line.append(part)
+                        line_len += len(part) + 1
+                    if line:
+                        lines.append(indent + ' '.join(line))
+                    if prefix is not None:
+                        lines[0] = lines[0][len(indent):]
+                    return lines
+
+                # if prog is short, follow it with optionals or positionals
+                if len(prefix) + len(prog) <= 0.75 * text_width:
+                    indent = ' ' * (len(prefix) + len(prog) + 1)
+                    if opt_parts:
+                        lines = get_lines([prog] + opt_parts, indent, prefix)
+                        lines.extend(get_lines(pos_parts, indent))
+                    elif pos_parts:
+                        lines = get_lines([prog] + pos_parts, indent, prefix)
+                    else:
+                        lines = [prog]
+
+                # if prog is long, put it on its own line
+                else:
+                    indent = ' ' * len(prefix)
+                    parts = opt_parts + pos_parts
+                    lines = get_lines(parts, indent)
+                    if len(lines) > 1:
+                        lines = []
+                        lines.extend(get_lines(opt_parts, indent))
+                        lines.extend(get_lines(pos_parts, indent))
+                    lines = [prog] + lines
+
+                # join lines into usage
+                usage = '\n'.join(lines)
+
+        # prefix with 'usage:'
+        return '%s%s\n\n' % (prefix, usage)
+
+    def _format_actions_usage(self, actions, groups):
+        # find group indices and identify actions in groups
+        group_actions = _set()
+        inserts = {}
+        for group in groups:
+            try:
+                start = actions.index(group._group_actions[0])
+            except ValueError:
+                continue
+            else:
+                end = start + len(group._group_actions)
+                if actions[start:end] == group._group_actions:
+                    for action in group._group_actions:
+                        group_actions.add(action)
+                    if not group.required:
+                        inserts[start] = '['
+                        inserts[end] = ']'
+                    else:
+                        inserts[start] = '('
+                        inserts[end] = ')'
+                    for i in range(start + 1, end):
+                        inserts[i] = '|'
+
+        # collect all actions format strings
+        parts = []
+        for i, action in enumerate(actions):
+
+            # suppressed arguments are marked with None
+            # remove | separators for suppressed arguments
+            if action.help is SUPPRESS:
+                parts.append(None)
+                if inserts.get(i) == '|':
+                    inserts.pop(i)
+                elif inserts.get(i + 1) == '|':
+                    inserts.pop(i + 1)
+
+            # produce all arg strings
+            elif not action.option_strings:
+                part = self._format_args(action, action.dest)
+
+                # if it's in a group, strip the outer []
+                if action in group_actions:
+                    if part[0] == '[' and part[-1] == ']':
+                        part = part[1:-1]
+
+                # add the action string to the list
+                parts.append(part)
+
+            # produce the first way to invoke the option in brackets
+            else:
+                option_string = action.option_strings[0]
+
+                # if the Optional doesn't take a value, format is:
+                #    -s or --long
+                if action.nargs == 0:
+                    part = '%s' % option_string
+
+                # if the Optional takes a value, format is:
+                #    -s ARGS or --long ARGS
+                else:
+                    default = action.dest.upper()
+                    args_string = self._format_args(action, default)
+                    part = '%s %s' % (option_string, args_string)
+
+                # make it look optional if it's not required or in a group
+                if not action.required and action not in group_actions:
+                    part = '[%s]' % part
+
+                # add the action string to the list
+                parts.append(part)
+
+        # insert things at the necessary indices
+        for i in _sorted(inserts, reverse=True):
+            parts[i:i] = [inserts[i]]
+
+        # join all the action items with spaces
+        text = ' '.join([item for item in parts if item is not None])
+
+        # clean up separators for mutually exclusive groups
+        open = r'[\[(]'
+        close = r'[\])]'
+        text = _re.sub(r'(%s) ' % open, r'\1', text)
+        text = _re.sub(r' (%s)' % close, r'\1', text)
+        text = _re.sub(r'%s *%s' % (open, close), r'', text)
+        text = _re.sub(r'\(([^|]*)\)', r'\1', text)
+        text = text.strip()
+
+        # return the text
+        return text
+
+    def _format_text(self, text):
+        if '%(prog)' in text:
+            text = text % dict(prog=self._prog)
+        text_width = self._width - self._current_indent
+        indent = ' ' * self._current_indent
+        return self._fill_text(text, text_width, indent) + '\n\n'
+
+    def _format_action(self, action):
+        # determine the required width and the entry label
+        help_position = min(self._action_max_length + 2,
+                            self._max_help_position)
+        help_width = self._width - help_position
+        action_width = help_position - self._current_indent - 2
+        action_header = self._format_action_invocation(action)
+
+        # ho nelp; start on same line and add a final newline
+        if not action.help:
+            tup = self._current_indent, '', action_header
+            action_header = '%*s%s\n' % tup
+
+        # short action name; start on the same line and pad two spaces
+        elif len(action_header) <= action_width:
+            tup = self._current_indent, '', action_width, action_header
+            action_header = '%*s%-*s  ' % tup
+            indent_first = 0
+
+        # long action name; start on the next line
+        else:
+            tup = self._current_indent, '', action_header
+            action_header = '%*s%s\n' % tup
+            indent_first = help_position
+
+        # collect the pieces of the action help
+        parts = [action_header]
+
+        # if there was help for the action, add lines of help text
+        if action.help:
+            help_text = self._expand_help(action)
+            help_lines = self._split_lines(help_text, help_width)
+            parts.append('%*s%s\n' % (indent_first, '', help_lines[0]))
+            for line in help_lines[1:]:
+                parts.append('%*s%s\n' % (help_position, '', line))
+
+        # or add a newline if the description doesn't end with one
+        elif not action_header.endswith('\n'):
+            parts.append('\n')
+
+        # if there are any sub-actions, add their help as well
+        for subaction in self._iter_indented_subactions(action):
+            parts.append(self._format_action(subaction))
+
+        # return a single string
+        return self._join_parts(parts)
+
+    def _format_action_invocation(self, action):
+        if not action.option_strings:
+            metavar, = self._metavar_formatter(action, action.dest)(1)
+            return metavar
+
+        else:
+            parts = []
+
+            # if the Optional doesn't take a value, format is:
+            #    -s, --long
+            if action.nargs == 0:
+                parts.extend(action.option_strings)
+
+            # if the Optional takes a value, format is:
+            #    -s ARGS, --long ARGS
+            else:
+                default = action.dest.upper()
+                args_string = self._format_args(action, default)
+                for option_string in action.option_strings:
+                    parts.append('%s %s' % (option_string, args_string))
+
+            return ', '.join(parts)
+
+    def _metavar_formatter(self, action, default_metavar):
+        if action.metavar is not None:
+            result = action.metavar
+        elif action.choices is not None:
+            choice_strs = [str(choice) for choice in action.choices]
+            result = '{%s}' % ','.join(choice_strs)
+        else:
+            result = default_metavar
+
+        def format(tuple_size):
+            if isinstance(result, tuple):
+                return result
+            else:
+                return (result, ) * tuple_size
+        return format
+
+    def _format_args(self, action, default_metavar):
+        get_metavar = self._metavar_formatter(action, default_metavar)
+        if action.nargs is None:
+            result = '%s' % get_metavar(1)
+        elif action.nargs == OPTIONAL:
+            result = '[%s]' % get_metavar(1)
+        elif action.nargs == ZERO_OR_MORE:
+            result = '[%s [%s ...]]' % get_metavar(2)
+        elif action.nargs == ONE_OR_MORE:
+            result = '%s [%s ...]' % get_metavar(2)
+        elif action.nargs == REMAINDER:
+            result = '...'
+        elif action.nargs == PARSER:
+            result = '%s ...' % get_metavar(1)
+        else:
+            formats = ['%s' for _ in range(action.nargs)]
+            result = ' '.join(formats) % get_metavar(action.nargs)
+        return result
+
+    def _expand_help(self, action):
+        params = dict(vars(action), prog=self._prog)
+        for name in list(params):
+            if params[name] is SUPPRESS:
+                del params[name]
+        for name in list(params):
+            if hasattr(params[name], '__name__'):
+                params[name] = params[name].__name__
+        if params.get('choices') is not None:
+            choices_str = ', '.join([str(c) for c in params['choices']])
+            params['choices'] = choices_str
+        return self._get_help_string(action) % params
+
+    def _iter_indented_subactions(self, action):
+        try:
+            get_subactions = action._get_subactions
+        except AttributeError:
+            pass
+        else:
+            self._indent()
+            for subaction in get_subactions():
+                yield subaction
+            self._dedent()
+
+    def _split_lines(self, text, width):
+        text = self._whitespace_matcher.sub(' ', text).strip()
+        return _textwrap.wrap(text, width)
+
+    def _fill_text(self, text, width, indent):
+        text = self._whitespace_matcher.sub(' ', text).strip()
+        return _textwrap.fill(text, width, initial_indent=indent,
+                                           subsequent_indent=indent)
+
+    def _get_help_string(self, action):
+        return action.help
+
+
+class RawDescriptionHelpFormatter(HelpFormatter):
+    """Help message formatter which retains any formatting in descriptions.
+
+    Only the name of this class is considered a public API. All the methods
+    provided by the class are considered an implementation detail.
+    """
+
+    def _fill_text(self, text, width, indent):
+        return ''.join([indent + line for line in text.splitlines(True)])
+
+
+class RawTextHelpFormatter(RawDescriptionHelpFormatter):
+    """Help message formatter which retains formatting of all help text.
+
+    Only the name of this class is considered a public API. All the methods
+    provided by the class are considered an implementation detail.
+    """
+
+    def _split_lines(self, text, width):
+        return text.splitlines()
+
+
+class ArgumentDefaultsHelpFormatter(HelpFormatter):
+    """Help message formatter which adds default values to argument help.
+
+    Only the name of this class is considered a public API. All the methods
+    provided by the class are considered an implementation detail.
+    """
+
+    def _get_help_string(self, action):
+        help = action.help
+        if '%(default)' not in action.help:
+            if action.default is not SUPPRESS:
+                defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
+                if action.option_strings or action.nargs in defaulting_nargs:
+                    help += ' (default: %(default)s)'
+        return help
+
+
+# =====================
+# Options and Arguments
+# =====================
+
+def _get_action_name(argument):
+    if argument is None:
+        return None
+    elif argument.option_strings:
+        return  '/'.join(argument.option_strings)
+    elif argument.metavar not in (None, SUPPRESS):
+        return argument.metavar
+    elif argument.dest not in (None, SUPPRESS):
+        return argument.dest
+    else:
+        return None
+
+
+class ArgumentError(Exception):
+    """An error from creating or using an argument (optional or positional).
+
+    The string value of this exception is the message, augmented with
+    information about the argument that caused it.
+    """
+
+    def __init__(self, argument, message):
+        self.argument_name = _get_action_name(argument)
+        self.message = message
+
+    def __str__(self):
+        if self.argument_name is None:
+            format = '%(message)s'
+        else:
+            format = 'argument %(argument_name)s: %(message)s'
+        return format % dict(message=self.message,
+                             argument_name=self.argument_name)
+
+
+class ArgumentTypeError(Exception):
+    """An error from trying to convert a command line string to a type."""
+    pass
+
+
+# ==============
+# Action classes
+# ==============
+
+class Action(_AttributeHolder):
+    """Information about how to convert command line strings to Python objects.
+
+    Action objects are used by an ArgumentParser to represent the information
+    needed to parse a single argument from one or more strings from the
+    command line. The keyword arguments to the Action constructor are also
+    all attributes of Action instances.
+
+    Keyword Arguments:
+
+        - option_strings -- A list of command-line option strings which
+            should be associated with this action.
+
+        - dest -- The name of the attribute to hold the created object(s)
+
+        - nargs -- The number of command-line arguments that should be
+            consumed. By default, one argument will be consumed and a single
+            value will be produced.  Other values include:
+                - N (an integer) consumes N arguments (and produces a list)
+                - '?' consumes zero or one arguments
+                - '*' consumes zero or more arguments (and produces a list)
+                - '+' consumes one or more arguments (and produces a list)
+            Note that the difference between the default and nargs=1 is that
+            with the default, a single value will be produced, while with
+            nargs=1, a list containing a single value will be produced.
+
+        - const -- The value to be produced if the option is specified and the
+            option uses an action that takes no values.
+
+        - default -- The value to be produced if the option is not specified.
+
+        - type -- The type which the command-line arguments should be converted
+            to, should be one of 'string', 'int', 'float', 'complex' or a
+            callable object that accepts a single string argument. If None,
+            'string' is assumed.
+
+        - choices -- A container of values that should be allowed. If not None,
+            after a command-line argument has been converted to the appropriate
+            type, an exception will be raised if it is not a member of this
+            collection.
+
+        - required -- True if the action must always be specified at the
+            command line. This is only meaningful for optional command-line
+            arguments.
+
+        - help -- The help string describing the argument.
+
+        - metavar -- The name to be used for the option's argument with the
+            help string. If None, the 'dest' value will be used as the name.
+    """
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 nargs=None,
+                 const=None,
+                 default=None,
+                 type=None,
+                 choices=None,
+                 required=False,
+                 help=None,
+                 metavar=None):
+        self.option_strings = option_strings
+        self.dest = dest
+        self.nargs = nargs
+        self.const = const
+        self.default = default
+        self.type = type
+        self.choices = choices
+        self.required = required
+        self.help = help
+        self.metavar = metavar
+
+    def _get_kwargs(self):
+        names = [
+            'option_strings',
+            'dest',
+            'nargs',
+            'const',
+            'default',
+            'type',
+            'choices',
+            'help',
+            'metavar',
+        ]
+        return [(name, getattr(self, name)) for name in names]
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        raise NotImplementedError(_('.__call__() not defined'))
+
+
+class _StoreAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 nargs=None,
+                 const=None,
+                 default=None,
+                 type=None,
+                 choices=None,
+                 required=False,
+                 help=None,
+                 metavar=None):
+        if nargs == 0:
+            raise ValueError('nargs for store actions must be > 0; if you '
+                             'have nothing to store, actions such as store '
+                             'true or store const may be more appropriate')
+        if const is not None and nargs != OPTIONAL:
+            raise ValueError('nargs must be %r to supply const' % OPTIONAL)
+        super(_StoreAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            nargs=nargs,
+            const=const,
+            default=default,
+            type=type,
+            choices=choices,
+            required=required,
+            help=help,
+            metavar=metavar)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        setattr(namespace, self.dest, values)
+
+
+class _StoreConstAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 const,
+                 default=None,
+                 required=False,
+                 help=None,
+                 metavar=None):
+        super(_StoreConstAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            nargs=0,
+            const=const,
+            default=default,
+            required=required,
+            help=help)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        setattr(namespace, self.dest, self.const)
+
+
+class _StoreTrueAction(_StoreConstAction):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 default=False,
+                 required=False,
+                 help=None):
+        super(_StoreTrueAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            const=True,
+            default=default,
+            required=required,
+            help=help)
+
+
+class _StoreFalseAction(_StoreConstAction):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 default=True,
+                 required=False,
+                 help=None):
+        super(_StoreFalseAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            const=False,
+            default=default,
+            required=required,
+            help=help)
+
+
+class _AppendAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 nargs=None,
+                 const=None,
+                 default=None,
+                 type=None,
+                 choices=None,
+                 required=False,
+                 help=None,
+                 metavar=None):
+        if nargs == 0:
+            raise ValueError('nargs for append actions must be > 0; if arg '
+                             'strings are not supplying the value to append, '
+                             'the append const action may be more appropriate')
+        if const is not None and nargs != OPTIONAL:
+            raise ValueError('nargs must be %r to supply const' % OPTIONAL)
+        super(_AppendAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            nargs=nargs,
+            const=const,
+            default=default,
+            type=type,
+            choices=choices,
+            required=required,
+            help=help,
+            metavar=metavar)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        items = _copy.copy(_ensure_value(namespace, self.dest, []))
+        items.append(values)
+        setattr(namespace, self.dest, items)
+
+
+class _AppendConstAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 const,
+                 default=None,
+                 required=False,
+                 help=None,
+                 metavar=None):
+        super(_AppendConstAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            nargs=0,
+            const=const,
+            default=default,
+            required=required,
+            help=help,
+            metavar=metavar)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        items = _copy.copy(_ensure_value(namespace, self.dest, []))
+        items.append(self.const)
+        setattr(namespace, self.dest, items)
+
+
+class _CountAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 dest,
+                 default=None,
+                 required=False,
+                 help=None):
+        super(_CountAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            nargs=0,
+            default=default,
+            required=required,
+            help=help)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        new_count = _ensure_value(namespace, self.dest, 0) + 1
+        setattr(namespace, self.dest, new_count)
+
+
+class _HelpAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 dest=SUPPRESS,
+                 default=SUPPRESS,
+                 help=None):
+        super(_HelpAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            default=default,
+            nargs=0,
+            help=help)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        parser.print_help()
+        parser.exit()
+
+
+class _VersionAction(Action):
+
+    def __init__(self,
+                 option_strings,
+                 version=None,
+                 dest=SUPPRESS,
+                 default=SUPPRESS,
+                 help=None):
+        super(_VersionAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            default=default,
+            nargs=0,
+            help=help)
+        self.version = version
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        version = self.version
+        if version is None:
+            version = parser.version
+        formatter = parser._get_formatter()
+        formatter.add_text(version)
+        parser.exit(message=formatter.format_help())
+
+
+class _SubParsersAction(Action):
+
+    class _ChoicesPseudoAction(Action):
+
+        def __init__(self, name, help):
+            sup = super(_SubParsersAction._ChoicesPseudoAction, self)
+            sup.__init__(option_strings=[], dest=name, help=help)
+
+    def __init__(self,
+                 option_strings,
+                 prog,
+                 parser_class,
+                 dest=SUPPRESS,
+                 help=None,
+                 metavar=None):
+
+        self._prog_prefix = prog
+        self._parser_class = parser_class
+        self._name_parser_map = {}
+        self._choices_actions = []
+
+        super(_SubParsersAction, self).__init__(
+            option_strings=option_strings,
+            dest=dest,
+            nargs=PARSER,
+            choices=self._name_parser_map,
+            help=help,
+            metavar=metavar)
+
+    def add_parser(self, name, **kwargs):
+        # set prog from the existing prefix
+        if kwargs.get('prog') is None:
+            kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
+
+        # create a pseudo-action to hold the choice help
+        if 'help' in kwargs:
+            help = kwargs.pop('help')
+            choice_action = self._ChoicesPseudoAction(name, help)
+            self._choices_actions.append(choice_action)
+
+        # create the parser and add it to the map
+        parser = self._parser_class(**kwargs)
+        self._name_parser_map[name] = parser
+        return parser
+
+    def _get_subactions(self):
+        return self._choices_actions
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        parser_name = values[0]
+        arg_strings = values[1:]
+
+        # set the parser name if requested
+        if self.dest is not SUPPRESS:
+            setattr(namespace, self.dest, parser_name)
+
+        # select the parser
+        try:
+            parser = self._name_parser_map[parser_name]
+        except KeyError:
+            tup = parser_name, ', '.join(self._name_parser_map)
+            msg = _('unknown parser %r (choices: %s)' % tup)
+            raise ArgumentError(self, msg)
+
+        # parse all the remaining options into the namespace
+        parser.parse_args(arg_strings, namespace)
+
+
+# ==============
+# Type classes
+# ==============
+
+class FileType(object):
+    """Factory for creating file object types
+
+    Instances of FileType are typically passed as type= arguments to the
+    ArgumentParser add_argument() method.
+
+    Keyword Arguments:
+        - mode -- A string indicating how the file is to be opened. Accepts the
+            same values as the builtin open() function.
+        - bufsize -- The file's desired buffer size. Accepts the same values as
+            the builtin open() function.
+    """
+
+    def __init__(self, mode='r', bufsize=None):
+        self._mode = mode
+        self._bufsize = bufsize
+
+    def __call__(self, string):
+        # the special argument "-" means sys.std{in,out}
+        if string == '-':
+            if 'r' in self._mode:
+                return _sys.stdin
+            elif 'w' in self._mode:
+                return _sys.stdout
+            else:
+                msg = _('argument "-" with mode %r' % self._mode)
+                raise ValueError(msg)
+
+        # all other arguments are used as file names
+        if self._bufsize:
+            return open(string, self._mode, self._bufsize)
+        else:
+            return open(string, self._mode)
+
+    def __repr__(self):
+        args = [self._mode, self._bufsize]
+        args_str = ', '.join([repr(arg) for arg in args if arg is not None])
+        return '%s(%s)' % (type(self).__name__, args_str)
+
+# ===========================
+# Optional and Positional Parsing
+# ===========================
+
+class Namespace(_AttributeHolder):
+    """Simple object for storing attributes.
+
+    Implements equality by attribute names and values, and provides a simple
+    string representation.
+    """
+
+    def __init__(self, **kwargs):
+        for name in kwargs:
+            setattr(self, name, kwargs[name])
+
+    def __eq__(self, other):
+        return vars(self) == vars(other)
+
+    def __ne__(self, other):
+        return not (self == other)
+
+    def __contains__(self, key):
+        return key in self.__dict__
+
+
+class _ActionsContainer(object):
+
+    def __init__(self,
+                 description,
+                 prefix_chars,
+                 argument_default,
+                 conflict_handler):
+        super(_ActionsContainer, self).__init__()
+
+        self.description = description
+        self.argument_default = argument_default
+        self.prefix_chars = prefix_chars
+        self.conflict_handler = conflict_handler
+
+        # set up registries
+        self._registries = {}
+
+        # register actions
+        self.register('action', None, _StoreAction)
+        self.register('action', 'store', _StoreAction)
+        self.register('action', 'store_const', _StoreConstAction)
+        self.register('action', 'store_true', _StoreTrueAction)
+        self.register('action', 'store_false', _StoreFalseAction)
+        self.register('action', 'append', _AppendAction)
+        self.register('action', 'append_const', _AppendConstAction)
+        self.register('action', 'count', _CountAction)
+        self.register('action', 'help', _HelpAction)
+        self.register('action', 'version', _VersionAction)
+        self.register('action', 'parsers', _SubParsersAction)
+
+        # raise an exception if the conflict handler is invalid
+        self._get_handler()
+
+        # action storage
+        self._actions = []
+        self._option_string_actions = {}
+
+        # groups
+        self._action_groups = []
+        self._mutually_exclusive_groups = []
+
+        # defaults storage
+        self._defaults = {}
+
+        # determines whether an "option" looks like a negative number
+        self._negative_number_matcher = _re.compile(r'^-\d+$|^-\d*\.\d+$')
+
+        # whether or not there are any optionals that look like negative
+        # numbers -- uses a list so it can be shared and edited
+        self._has_negative_number_optionals = []
+
+    # ====================
+    # Registration methods
+    # ====================
+    def register(self, registry_name, value, object):
+        registry = self._registries.setdefault(registry_name, {})
+        registry[value] = object
+
+    def _registry_get(self, registry_name, value, default=None):
+        return self._registries[registry_name].get(value, default)
+
+    # ==================================
+    # Namespace default accessor methods
+    # ==================================
+    def set_defaults(self, **kwargs):
+        self._defaults.update(kwargs)
+
+        # if these defaults match any existing arguments, replace
+        # the previous default on the object with the new one
+        for action in self._actions:
+            if action.dest in kwargs:
+                action.default = kwargs[action.dest]
+
+    def get_default(self, dest):
+        for action in self._actions:
+            if action.dest == dest and action.default is not None:
+                return action.default
+        return self._defaults.get(dest, None)
+
+
+    # =======================
+    # Adding argument actions
+    # =======================
+    def add_argument(self, *args, **kwargs):
+        """
+        add_argument(dest, ..., name=value, ...)
+        add_argument(option_string, option_string, ..., name=value, ...)
+        """
+
+        # if no positional args are supplied or only one is supplied and
+        # it doesn't look like an option string, parse a positional
+        # argument
+        chars = self.prefix_chars
+        if not args or len(args) == 1 and args[0][0] not in chars:
+            if args and 'dest' in kwargs:
+                raise ValueError('dest supplied twice for positional argument')
+            kwargs = self._get_positional_kwargs(*args, **kwargs)
+
+        # otherwise, we're adding an optional argument
+        else:
+            kwargs = self._get_optional_kwargs(*args, **kwargs)
+
+        # if no default was supplied, use the parser-level default
+        if 'default' not in kwargs:
+            dest = kwargs['dest']
+            if dest in self._defaults:
+                kwargs['default'] = self._defaults[dest]
+            elif self.argument_default is not None:
+                kwargs['default'] = self.argument_default
+
+        # create the action object, and add it to the parser
+        action_class = self._pop_action_class(kwargs)
+        if not _callable(action_class):
+            raise ValueError('unknown action "%s"' % action_class)
+        action = action_class(**kwargs)
+
+        # raise an error if the action type is not callable
+        type_func = self._registry_get('type', action.type, action.type)
+        if not _callable(type_func):
+            raise ValueError('%r is not callable' % type_func)
+
+        return self._add_action(action)
+
+    def add_argument_group(self, *args, **kwargs):
+        group = _ArgumentGroup(self, *args, **kwargs)
+        self._action_groups.append(group)
+        return group
+
+    def add_mutually_exclusive_group(self, **kwargs):
+        group = _MutuallyExclusiveGroup(self, **kwargs)
+        self._mutually_exclusive_groups.append(group)
+        return group
+
+    def _add_action(self, action):
+        # resolve any conflicts
+        self._check_conflict(action)
+
+        # add to actions list
+        self._actions.append(action)
+        action.container = self
+
+        # index the action by any option strings it has
+        for option_string in action.option_strings:
+            self._option_string_actions[option_string] = action
+
+        # set the flag if any option strings look like negative numbers
+        for option_string in action.option_strings:
+            if self._negative_number_matcher.match(option_string):
+                if not self._has_negative_number_optionals:
+                    self._has_negative_number_optionals.append(True)
+
+        # return the created action
+        return action
+
+    def _remove_action(self, action):
+        self._actions.remove(action)
+
+    def _add_container_actions(self, container):
+        # collect groups by titles
+        title_group_map = {}
+        for group in self._action_groups:
+            if group.title in title_group_map:
+                msg = _('cannot merge actions - two groups are named %r')
+                raise ValueError(msg % (group.title))
+            title_group_map[group.title] = group
+
+        # map each action to its group
+        group_map = {}
+        for group in container._action_groups:
+
+            # if a group with the title exists, use that, otherwise
+            # create a new group matching the container's group
+            if group.title not in title_group_map:
+                title_group_map[group.title] = self.add_argument_group(
+                    title=group.title,
+                    description=group.description,
+                    conflict_handler=group.conflict_handler)
+
+            # map the actions to their new group
+            for action in group._group_actions:
+                group_map[action] = title_group_map[group.title]
+
+        # add container's mutually exclusive groups
+        # NOTE: if add_mutually_exclusive_group ever gains title= and
+        # description= then this code will need to be expanded as above
+        for group in container._mutually_exclusive_groups:
+            mutex_group = self.add_mutually_exclusive_group(
+                required=group.required)
+
+            # map the actions to their new mutex group
+            for action in group._group_actions:
+                group_map[action] = mutex_group
+
+        # add all actions to this container or their group
+        for action in container._actions:
+            group_map.get(action, self)._add_action(action)
+
+    def _get_positional_kwargs(self, dest, **kwargs):
+        # make sure required is not specified
+        if 'required' in kwargs:
+            msg = _("'required' is an invalid argument for positionals")
+            raise TypeError(msg)
+
+        # mark positional arguments as required if at least one is
+        # always required
+        if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]:
+            kwargs['required'] = True
+        if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs:
+            kwargs['required'] = True
+
+        # return the keyword arguments with no option strings
+        return dict(kwargs, dest=dest, option_strings=[])
+
+    def _get_optional_kwargs(self, *args, **kwargs):
+        # determine short and long option strings
+        option_strings = []
+        long_option_strings = []
+        for option_string in args:
+            # error on strings that don't start with an appropriate prefix
+            if not option_string[0] in self.prefix_chars:
+                msg = _('invalid option string %r: '
+                        'must start with a character %r')
+                tup = option_string, self.prefix_chars
+                raise ValueError(msg % tup)
+
+            # strings starting with two prefix characters are long options
+            option_strings.append(option_string)
+            if option_string[0] in self.prefix_chars:
+                if len(option_string) > 1:
+                    if option_string[1] in self.prefix_chars:
+                        long_option_strings.append(option_string)
+
+        # infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x'
+        dest = kwargs.pop('dest', None)
+        if dest is None:
+            if long_option_strings:
+                dest_option_string = long_option_strings[0]
+            else:
+                dest_option_string = option_strings[0]
+            dest = dest_option_string.lstrip(self.prefix_chars)
+            if not dest:
+                msg = _('dest= is required for options like %r')
+                raise ValueError(msg % option_string)
+            dest = dest.replace('-', '_')
+
+        # return the updated keyword arguments
+        return dict(kwargs, dest=dest, option_strings=option_strings)
+
+    def _pop_action_class(self, kwargs, default=None):
+        action = kwargs.pop('action', default)
+        return self._registry_get('action', action, action)
+
+    def _get_handler(self):
+        # determine function from conflict handler string
+        handler_func_name = '_handle_conflict_%s' % self.conflict_handler
+        try:
+            return getattr(self, handler_func_name)
+        except AttributeError:
+            msg = _('invalid conflict_resolution value: %r')
+            raise ValueError(msg % self.conflict_handler)
+
+    def _check_conflict(self, action):
+
+        # find all options that conflict with this option
+        confl_optionals = []
+        for option_string in action.option_strings:
+            if option_string in self._option_string_actions:
+                confl_optional = self._option_string_actions[option_string]
+                confl_optionals.append((option_string, confl_optional))
+
+        # resolve any conflicts
+        if confl_optionals:
+            conflict_handler = self._get_handler()
+            conflict_handler(action, confl_optionals)
+
+    def _handle_conflict_error(self, action, conflicting_actions):
+        message = _('conflicting option string(s): %s')
+        conflict_string = ', '.join([option_string
+                                     for option_string, action
+                                     in conflicting_actions])
+        raise ArgumentError(action, message % conflict_string)
+
+    def _handle_conflict_resolve(self, action, conflicting_actions):
+
+        # remove all conflicting options
+        for option_string, action in conflicting_actions:
+
+            # remove the conflicting option
+            action.option_strings.remove(option_string)
+            self._option_string_actions.pop(option_string, None)
+
+            # if the option now has no option string, remove it from the
+            # container holding it
+            if not action.option_strings:
+                action.container._remove_action(action)
+
+
+class _ArgumentGroup(_ActionsContainer):
+
+    def __init__(self, container, title=None, description=None, **kwargs):
+        # add any missing keyword arguments by checking the container
+        update = kwargs.setdefault
+        update('conflict_handler', container.conflict_handler)
+        update('prefix_chars', container.prefix_chars)
+        update('argument_default', container.argument_default)
+        super_init = super(_ArgumentGroup, self).__init__
+        super_init(description=description, **kwargs)
+
+        # group attributes
+        self.title = title
+        self._group_actions = []
+
+        # share most attributes with the container
+        self._registries = container._registries
+        self._actions = container._actions
+        self._option_string_actions = container._option_string_actions
+        self._defaults = container._defaults
+        self._has_negative_number_optionals = \
+            container._has_negative_number_optionals
+
+    def _add_action(self, action):
+        action = super(_ArgumentGroup, self)._add_action(action)
+        self._group_actions.append(action)
+        return action
+
+    def _remove_action(self, action):
+        super(_ArgumentGroup, self)._remove_action(action)
+        self._group_actions.remove(action)
+
+
+class _MutuallyExclusiveGroup(_ArgumentGroup):
+
+    def __init__(self, container, required=False):
+        super(_MutuallyExclusiveGroup, self).__init__(container)
+        self.required = required
+        self._container = container
+
+    def _add_action(self, action):
+        if action.required:
+            msg = _('mutually exclusive arguments must be optional')
+            raise ValueError(msg)
+        action = self._container._add_action(action)
+        self._group_actions.append(action)
+        return action
+
+    def _remove_action(self, action):
+        self._container._remove_action(action)
+        self._group_actions.remove(action)
+
+
+class ArgumentParser(_AttributeHolder, _ActionsContainer):
+    """Object for parsing command line strings into Python objects.
+
+    Keyword Arguments:
+        - prog -- The name of the program (default: sys.argv[0])
+        - usage -- A usage message (default: auto-generated from arguments)
+        - description -- A description of what the program does
+        - epilog -- Text following the argument descriptions
+        - parents -- Parsers whose arguments should be copied into this one
+        - formatter_class -- HelpFormatter class for printing help messages
+        - prefix_chars -- Characters that prefix optional arguments
+        - fromfile_prefix_chars -- Characters that prefix files containing
+            additional arguments
+        - argument_default -- The default value for all arguments
+        - conflict_handler -- String indicating how to handle conflicts
+        - add_help -- Add a -h/-help option
+    """
+
+    def __init__(self,
+                 prog=None,
+                 usage=None,
+                 description=None,
+                 epilog=None,
+                 version=None,
+                 parents=[],
+                 formatter_class=HelpFormatter,
+                 prefix_chars='-',
+                 fromfile_prefix_chars=None,
+                 argument_default=None,
+                 conflict_handler='error',
+                 add_help=True):
+
+        if version is not None:
+            import warnings
+            warnings.warn(
+                """The "version" argument to ArgumentParser is deprecated. """
+                """Please use """
+                """"add_argument(..., action='version', version="N", ...)" """
+                """instead""", DeprecationWarning)
+
+        superinit = super(ArgumentParser, self).__init__
+        superinit(description=description,
+                  prefix_chars=prefix_chars,
+                  argument_default=argument_default,
+                  conflict_handler=conflict_handler)
+
+        # default setting for prog
+        if prog is None:
+            prog = _os.path.basename(_sys.argv[0])
+
+        self.prog = prog
+        self.usage = usage
+        self.epilog = epilog
+        self.version = version
+        self.formatter_class = formatter_class
+        self.fromfile_prefix_chars = fromfile_prefix_chars
+        self.add_help = add_help
+
+        add_group = self.add_argument_group
+        self._positionals = add_group(_('positional arguments'))
+        self._optionals = add_group(_('optional arguments'))
+        self._subparsers = None
+
+        # register types
+        def identity(string):
+            return string
+        self.register('type', None, identity)
+
+        # add help and version arguments if necessary
+        # (using explicit default to override global argument_default)
+        if self.add_help:
+            self.add_argument(
+                '-h', '--help', action='help', default=SUPPRESS,
+                help=_('show this help message and exit'))
+        if self.version:
+            self.add_argument(
+                '-v', '--version', action='version', default=SUPPRESS,
+                version=self.version,
+                help=_("show program's version number and exit"))
+
+        # add parent arguments and defaults
+        for parent in parents:
+            self._add_container_actions(parent)
+            try:
+                defaults = parent._defaults
+            except AttributeError:
+                pass
+            else:
+                self._defaults.update(defaults)
+
+    # =======================
+    # Pretty __repr__ methods
+    # =======================
+    def _get_kwargs(self):
+        names = [
+            'prog',
+            'usage',
+            'description',
+            'version',
+            'formatter_class',
+            'conflict_handler',
+            'add_help',
+        ]
+        return [(name, getattr(self, name)) for name in names]
+
+    # ==================================
+    # Optional/Positional adding methods
+    # ==================================
+    def add_subparsers(self, **kwargs):
+        if self._subparsers is not None:
+            self.error(_('cannot have multiple subparser arguments'))
+
+        # add the parser class to the arguments if it's not present
+        kwargs.setdefault('parser_class', type(self))
+
+        if 'title' in kwargs or 'description' in kwargs:
+            title = _(kwargs.pop('title', 'subcommands'))
+            description = _(kwargs.pop('description', None))
+            self._subparsers = self.add_argument_group(title, description)
+        else:
+            self._subparsers = self._positionals
+
+        # prog defaults to the usage message of this parser, skipping
+        # optional arguments and with no "usage:" prefix
+        if kwargs.get('prog') is None:
+            formatter = self._get_formatter()
+            positionals = self._get_positional_actions()
+            groups = self._mutually_exclusive_groups
+            formatter.add_usage(self.usage, positionals, groups, '')
+            kwargs['prog'] = formatter.format_help().strip()
+
+        # create the parsers action and add it to the positionals list
+        parsers_class = self._pop_action_class(kwargs, 'parsers')
+        action = parsers_class(option_strings=[], **kwargs)
+        self._subparsers._add_action(action)
+
+        # return the created parsers action
+        return action
+
+    def _add_action(self, action):
+        if action.option_strings:
+            self._optionals._add_action(action)
+        else:
+            self._positionals._add_action(action)
+        return action
+
+    def _get_optional_actions(self):
+        return [action
+                for action in self._actions
+                if action.option_strings]
+
+    def _get_positional_actions(self):
+        return [action
+                for action in self._actions
+                if not action.option_strings]
+
+    # =====================================
+    # Command line argument parsing methods
+    # =====================================
+    def parse_args(self, args=None, namespace=None):
+        args, argv = self.parse_known_args(args, namespace)
+        if argv:
+            msg = _('unrecognized arguments: %s')
+            self.error(msg % ' '.join(argv))
+        return args
+
+    def parse_known_args(self, args=None, namespace=None):
+        # args default to the system args
+        if args is None:
+            args = _sys.argv[1:]
+
+        # default Namespace built from parser defaults
+        if namespace is None:
+            namespace = Namespace()
+
+        # add any action defaults that aren't present
+        for action in self._actions:
+            if action.dest is not SUPPRESS:
+                if not hasattr(namespace, action.dest):
+                    if action.default is not SUPPRESS:
+                        default = action.default
+                        if isinstance(action.default, _basestring):
+                            default = self._get_value(action, default)
+                        setattr(namespace, action.dest, default)
+
+        # add any parser defaults that aren't present
+        for dest in self._defaults:
+            if not hasattr(namespace, dest):
+                setattr(namespace, dest, self._defaults[dest])
+
+        # parse the arguments and exit if there are any errors
+        try:
+            return self._parse_known_args(args, namespace)
+        except ArgumentError:
+            err = _sys.exc_info()[1]
+            self.error(str(err))
+
+    def _parse_known_args(self, arg_strings, namespace):
+        # replace arg strings that are file references
+        if self.fromfile_prefix_chars is not None:
+            arg_strings = self._read_args_from_files(arg_strings)
+
+        # map all mutually exclusive arguments to the other arguments
+        # they can't occur with
+        action_conflicts = {}
+        for mutex_group in self._mutually_exclusive_groups:
+            group_actions = mutex_group._group_actions
+            for i, mutex_action in enumerate(mutex_group._group_actions):
+                conflicts = action_conflicts.setdefault(mutex_action, [])
+                conflicts.extend(group_actions[:i])
+                conflicts.extend(group_actions[i + 1:])
+
+        # find all option indices, and determine the arg_string_pattern
+        # which has an 'O' if there is an option at an index,
+        # an 'A' if there is an argument, or a '-' if there is a '--'
+        option_string_indices = {}
+        arg_string_pattern_parts = []
+        arg_strings_iter = iter(arg_strings)
+        for i, arg_string in enumerate(arg_strings_iter):
+
+            # all args after -- are non-options
+            if arg_string == '--':
+                arg_string_pattern_parts.append('-')
+                for arg_string in arg_strings_iter:
+                    arg_string_pattern_parts.append('A')
+
+            # otherwise, add the arg to the arg strings
+            # and note the index if it was an option
+            else:
+                option_tuple = self._parse_optional(arg_string)
+                if option_tuple is None:
+                    pattern = 'A'
+                else:
+                    option_string_indices[i] = option_tuple
+                    pattern = 'O'
+                arg_string_pattern_parts.append(pattern)
+
+        # join the pieces together to form the pattern
+        arg_strings_pattern = ''.join(arg_string_pattern_parts)
+
+        # converts arg strings to the appropriate and then takes the action
+        seen_actions = _set()
+        seen_non_default_actions = _set()
+
+        def take_action(action, argument_strings, option_string=None):
+            seen_actions.add(action)
+            argument_values = self._get_values(action, argument_strings)
+
+            # error if this argument is not allowed with other previously
+            # seen arguments, assuming that actions that use the default
+            # value don't really count as "present"
+            if argument_values is not action.default:
+                seen_non_default_actions.add(action)
+                for conflict_action in action_conflicts.get(action, []):
+                    if conflict_action in seen_non_default_actions:
+                        msg = _('not allowed with argument %s')
+                        action_name = _get_action_name(conflict_action)
+                        raise ArgumentError(action, msg % action_name)
+
+            # take the action if we didn't receive a SUPPRESS value
+            # (e.g. from a default)
+            if argument_values is not SUPPRESS:
+                action(self, namespace, argument_values, option_string)
+
+        # function to convert arg_strings into an optional action
+        def consume_optional(start_index):
+
+            # get the optional identified at this index
+            option_tuple = option_string_indices[start_index]
+            action, option_string, explicit_arg = option_tuple
+
+            # identify additional optionals in the same arg string
+            # (e.g. -xyz is the same as -x -y -z if no args are required)
+            match_argument = self._match_argument
+            action_tuples = []
+            while True:
+
+                # if we found no optional action, skip it
+                if action is None:
+                    extras.append(arg_strings[start_index])
+                    return start_index + 1
+
+                # if there is an explicit argument, try to match the
+                # optional's string arguments to only this
+                if explicit_arg is not None:
+                    arg_count = match_argument(action, 'A')
+
+                    # if the action is a single-dash option and takes no
+                    # arguments, try to parse more single-dash options out
+                    # of the tail of the option string
+                    chars = self.prefix_chars
+                    if arg_count == 0 and option_string[1] not in chars:
+                        action_tuples.append((action, [], option_string))
+                        for char in self.prefix_chars:
+                            option_string = char + explicit_arg[0]
+                            explicit_arg = explicit_arg[1:] or None
+                            optionals_map = self._option_string_actions
+                            if option_string in optionals_map:
+                                action = optionals_map[option_string]
+                                break
+                        else:
+                            msg = _('ignored explicit argument %r')
+                            raise ArgumentError(action, msg % explicit_arg)
+
+                    # if the action expect exactly one argument, we've
+                    # successfully matched the option; exit the loop
+                    elif arg_count == 1:
+                        stop = start_index + 1
+                        args = [explicit_arg]
+                        action_tuples.append((action, args, option_string))
+                        break
+
+                    # error if a double-dash option did not use the
+                    # explicit argument
+                    else:
+                        msg = _('ignored explicit argument %r')
+                        raise ArgumentError(action, msg % explicit_arg)
+
+                # if there is no explicit argument, try to match the
+                # optional's string arguments with the following strings
+                # if successful, exit the loop
+                else:
+                    start = start_index + 1
+                    selected_patterns = arg_strings_pattern[start:]
+                    arg_count = match_argument(action, selected_patterns)
+                    stop = start + arg_count
+                    args = arg_strings[start:stop]
+                    action_tuples.append((action, args, option_string))
+                    break
+
+            # add the Optional to the list and return the index at which
+            # the Optional's string args stopped
+            assert action_tuples
+            for action, args, option_string in action_tuples:
+                take_action(action, args, option_string)
+            return stop
+
+        # the list of Positionals left to be parsed; this is modified
+        # by consume_positionals()
+        positionals = self._get_positional_actions()
+
+        # function to convert arg_strings into positional actions
+        def consume_positionals(start_index):
+            # match as many Positionals as possible
+            match_partial = self._match_arguments_partial
+            selected_pattern = arg_strings_pattern[start_index:]
+            arg_counts = match_partial(positionals, selected_pattern)
+
+            # slice off the appropriate arg strings for each Positional
+            # and add the Positional and its args to the list
+            for action, arg_count in zip(positionals, arg_counts):
+                args = arg_strings[start_index: start_index + arg_count]
+                start_index += arg_count
+                take_action(action, args)
+
+            # slice off the Positionals that we just parsed and return the
+            # index at which the Positionals' string args stopped
+            positionals[:] = positionals[len(arg_counts):]
+            return start_index
+
+        # consume Positionals and Optionals alternately, until we have
+        # passed the last option string
+        extras = []
+        start_index = 0
+        if option_string_indices:
+            max_option_string_index = max(option_string_indices)
+        else:
+            max_option_string_index = -1
+        while start_index <= max_option_string_index:
+
+            # consume any Positionals preceding the next option
+            next_option_string_index = min([
+                index
+                for index in option_string_indices
+                if index >= start_index])
+            if start_index != next_option_string_index:
+                positionals_end_index = consume_positionals(start_index)
+
+                # only try to parse the next optional if we didn't consume
+                # the option string during the positionals parsing
+                if positionals_end_index > start_index:
+                    start_index = positionals_end_index
+                    continue
+                else:
+                    start_index = positionals_end_index
+
+            # if we consumed all the positionals we could and we're not
+            # at the index of an option string, there were extra arguments
+            if start_index not in option_string_indices:
+                strings = arg_strings[start_index:next_option_string_index]
+                extras.extend(strings)
+                start_index = next_option_string_index
+
+            # consume the next optional and any arguments for it
+            start_index = consume_optional(start_index)
+
+        # consume any positionals following the last Optional
+        stop_index = consume_positionals(start_index)
+
+        # if we didn't consume all the argument strings, there were extras
+        extras.extend(arg_strings[stop_index:])
+
+        # if we didn't use all the Positional objects, there were too few
+        # arg strings supplied.
+        if positionals:
+            self.error(_('too few arguments'))
+
+        # make sure all required actions were present
+        for action in self._actions:
+            if action.required:
+                if action not in seen_actions:
+                    name = _get_action_name(action)
+                    self.error(_('argument %s is required') % name)
+
+        # make sure all required groups had one option present
+        for group in self._mutually_exclusive_groups:
+            if group.required:
+                for action in group._group_actions:
+                    if action in seen_non_default_actions:
+                        break
+
+                # if no actions were used, report the error
+                else:
+                    names = [_get_action_name(action)
+                             for action in group._group_actions
+                             if action.help is not SUPPRESS]
+                    msg = _('one of the arguments %s is required')
+                    self.error(msg % ' '.join(names))
+
+        # return the updated namespace and the extra arguments
+        return namespace, extras
+
+    def _read_args_from_files(self, arg_strings):
+        # expand arguments referencing files
+        new_arg_strings = []
+        for arg_string in arg_strings:
+
+            # for regular arguments, just add them back into the list
+            if arg_string[0] not in self.fromfile_prefix_chars:
+                new_arg_strings.append(arg_string)
+
+            # replace arguments referencing files with the file content
+            else:
+                try:
+                    args_file = open(arg_string[1:])
+                    try:
+                        arg_strings = []
+                        for arg_line in args_file.read().splitlines():
+                            for arg in self.convert_arg_line_to_args(arg_line):
+                                arg_strings.append(arg)
+                        arg_strings = self._read_args_from_files(arg_strings)
+                        new_arg_strings.extend(arg_strings)
+                    finally:
+                        args_file.close()
+                except IOError:
+                    err = _sys.exc_info()[1]
+                    self.error(str(err))
+
+        # return the modified argument list
+        return new_arg_strings
+
+    def convert_arg_line_to_args(self, arg_line):
+        return [arg_line]
+
+    def _match_argument(self, action, arg_strings_pattern):
+        # match the pattern for this action to the arg strings
+        nargs_pattern = self._get_nargs_pattern(action)
+        match = _re.match(nargs_pattern, arg_strings_pattern)
+
+        # raise an exception if we weren't able to find a match
+        if match is None:
+            nargs_errors = {
+                None: _('expected one argument'),
+                OPTIONAL: _('expected at most one argument'),
+                ONE_OR_MORE: _('expected at least one argument'),
+            }
+            default = _('expected %s argument(s)') % action.nargs
+            msg = nargs_errors.get(action.nargs, default)
+            raise ArgumentError(action, msg)
+
+        # return the number of arguments matched
+        return len(match.group(1))
+
+    def _match_arguments_partial(self, actions, arg_strings_pattern):
+        # progressively shorten the actions list by slicing off the
+        # final actions until we find a match
+        result = []
+        for i in range(len(actions), 0, -1):
+            actions_slice = actions[:i]
+            pattern = ''.join([self._get_nargs_pattern(action)
+                               for action in actions_slice])
+            match = _re.match(pattern, arg_strings_pattern)
+            if match is not None:
+                result.extend([len(string) for string in match.groups()])
+                break
+
+        # return the list of arg string counts
+        return result
+
+    def _parse_optional(self, arg_string):
+        # if it's an empty string, it was meant to be a positional
+        if not arg_string:
+            return None
+
+        # if it doesn't start with a prefix, it was meant to be positional
+        if not arg_string[0] in self.prefix_chars:
+            return None
+
+        # if the option string is present in the parser, return the action
+        if arg_string in self._option_string_actions:
+            action = self._option_string_actions[arg_string]
+            return action, arg_string, None
+
+        # if it's just a single character, it was meant to be positional
+        if len(arg_string) == 1:
+            return None
+
+        # if the option string before the "=" is present, return the action
+        if '=' in arg_string:
+            option_string, explicit_arg = arg_string.split('=', 1)
+            if option_string in self._option_string_actions:
+                action = self._option_string_actions[option_string]
+                return action, option_string, explicit_arg
+
+        # search through all possible prefixes of the option string
+        # and all actions in the parser for possible interpretations
+        option_tuples = self._get_option_tuples(arg_string)
+
+        # if multiple actions match, the option string was ambiguous
+        if len(option_tuples) > 1:
+            options = ', '.join([option_string
+                for action, option_string, explicit_arg in option_tuples])
+            tup = arg_string, options
+            self.error(_('ambiguous option: %s could match %s') % tup)
+
+        # if exactly one action matched, this segmentation is good,
+        # so return the parsed action
+        elif len(option_tuples) == 1:
+            option_tuple, = option_tuples
+            return option_tuple
+
+        # if it was not found as an option, but it looks like a negative
+        # number, it was meant to be positional
+        # unless there are negative-number-like options
+        if self._negative_number_matcher.match(arg_string):
+            if not self._has_negative_number_optionals:
+                return None
+
+        # if it contains a space, it was meant to be a positional
+        if ' ' in arg_string:
+            return None
+
+        # it was meant to be an optional but there is no such option
+        # in this parser (though it might be a valid option in a subparser)
+        return None, arg_string, None
+
+    def _get_option_tuples(self, option_string):
+        result = []
+
+        # option strings starting with two prefix characters are only
+        # split at the '='
+        chars = self.prefix_chars
+        if option_string[0] in chars and option_string[1] in chars:
+            if '=' in option_string:
+                option_prefix, explicit_arg = option_string.split('=', 1)
+            else:
+                option_prefix = option_string
+                explicit_arg = None
+            for option_string in self._option_string_actions:
+                if option_string.startswith(option_prefix):
+                    action = self._option_string_actions[option_string]
+                    tup = action, option_string, explicit_arg
+                    result.append(tup)
+
+        # single character options can be concatenated with their arguments
+        # but multiple character options always have to have their argument
+        # separate
+        elif option_string[0] in chars and option_string[1] not in chars:
+            option_prefix = option_string
+            explicit_arg = None
+            short_option_prefix = option_string[:2]
+            short_explicit_arg = option_string[2:]
+
+            for option_string in self._option_string_actions:
+                if option_string == short_option_prefix:
+                    action = self._option_string_actions[option_string]
+                    tup = action, option_string, short_explicit_arg
+                    result.append(tup)
+                elif option_string.startswith(option_prefix):
+                    action = self._option_string_actions[option_string]
+                    tup = action, option_string, explicit_arg
+                    result.append(tup)
+
+        # shouldn't ever get here
+        else:
+            self.error(_('unexpected option string: %s') % option_string)
+
+        # return the collected option tuples
+        return result
+
+    def _get_nargs_pattern(self, action):
+        # in all examples below, we have to allow for '--' args
+        # which are represented as '-' in the pattern
+        nargs = action.nargs
+
+        # the default (None) is assumed to be a single argument
+        if nargs is None:
+            nargs_pattern = '(-*A-*)'
+
+        # allow zero or one arguments
+        elif nargs == OPTIONAL:
+            nargs_pattern = '(-*A?-*)'
+
+        # allow zero or more arguments
+        elif nargs == ZERO_OR_MORE:
+            nargs_pattern = '(-*[A-]*)'
+
+        # allow one or more arguments
+        elif nargs == ONE_OR_MORE:
+            nargs_pattern = '(-*A[A-]*)'
+
+        # allow any number of options or arguments
+        elif nargs == REMAINDER:
+            nargs_pattern = '([-AO]*)'
+
+        # allow one argument followed by any number of options or arguments
+        elif nargs == PARSER:
+            nargs_pattern = '(-*A[-AO]*)'
+
+        # all others should be integers
+        else:
+            nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs)
+
+        # if this is an optional action, -- is not allowed
+        if action.option_strings:
+            nargs_pattern = nargs_pattern.replace('-*', '')
+            nargs_pattern = nargs_pattern.replace('-', '')
+
+        # return the pattern
+        return nargs_pattern
+
+    # ========================
+    # Value conversion methods
+    # ========================
+    def _get_values(self, action, arg_strings):
+        # for everything but PARSER args, strip out '--'
+        if action.nargs not in [PARSER, REMAINDER]:
+            arg_strings = [s for s in arg_strings if s != '--']
+
+        # optional argument produces a default when not present
+        if not arg_strings and action.nargs == OPTIONAL:
+            if action.option_strings:
+                value = action.const
+            else:
+                value = action.default
+            if isinstance(value, _basestring):
+                value = self._get_value(action, value)
+                self._check_value(action, value)
+
+        # when nargs='*' on a positional, if there were no command-line
+        # args, use the default if it is anything other than None
+        elif (not arg_strings and action.nargs == ZERO_OR_MORE and
+              not action.option_strings):
+            if action.default is not None:
+                value = action.default
+            else:
+                value = arg_strings
+            self._check_value(action, value)
+
+        # single argument or optional argument produces a single value
+        elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]:
+            arg_string, = arg_strings
+            value = self._get_value(action, arg_string)
+            self._check_value(action, value)
+
+        # REMAINDER arguments convert all values, checking none
+        elif action.nargs == REMAINDER:
+            value = [self._get_value(action, v) for v in arg_strings]
+
+        # PARSER arguments convert all values, but check only the first
+        elif action.nargs == PARSER:
+            value = [self._get_value(action, v) for v in arg_strings]
+            self._check_value(action, value[0])
+
+        # all other types of nargs produce a list
+        else:
+            value = [self._get_value(action, v) for v in arg_strings]
+            for v in value:
+                self._check_value(action, v)
+
+        # return the converted value
+        return value
+
+    def _get_value(self, action, arg_string):
+        type_func = self._registry_get('type', action.type, action.type)
+        if not _callable(type_func):
+            msg = _('%r is not callable')
+            raise ArgumentError(action, msg % type_func)
+
+        # convert the value to the appropriate type
+        try:
+            result = type_func(arg_string)
+
+        # ArgumentTypeErrors indicate errors
+        except ArgumentTypeError:
+            name = getattr(action.type, '__name__', repr(action.type))
+            msg = str(_sys.exc_info()[1])
+            raise ArgumentError(action, msg)
+
+        # TypeErrors or ValueErrors also indicate errors
+        except (TypeError, ValueError):
+            name = getattr(action.type, '__name__', repr(action.type))
+            msg = _('invalid %s value: %r')
+            raise ArgumentError(action, msg % (name, arg_string))
+
+        # return the converted value
+        return result
+
+    def _check_value(self, action, value):
+        # converted value must be one of the choices (if specified)
+        if action.choices is not None and value not in action.choices:
+            tup = value, ', '.join(map(repr, action.choices))
+            msg = _('invalid choice: %r (choose from %s)') % tup
+            raise ArgumentError(action, msg)
+
+    # =======================
+    # Help-formatting methods
+    # =======================
+    def format_usage(self):
+        formatter = self._get_formatter()
+        formatter.add_usage(self.usage, self._actions,
+                            self._mutually_exclusive_groups)
+        return formatter.format_help()
+
+    def format_help(self):
+        formatter = self._get_formatter()
+
+        # usage
+        formatter.add_usage(self.usage, self._actions,
+                            self._mutually_exclusive_groups)
+
+        # description
+        formatter.add_text(self.description)
+
+        # positionals, optionals and user-defined groups
+        for action_group in self._action_groups:
+            formatter.start_section(action_group.title)
+            formatter.add_text(action_group.description)
+            formatter.add_arguments(action_group._group_actions)
+            formatter.end_section()
+
+        # epilog
+        formatter.add_text(self.epilog)
+
+        # determine help from format above
+        return formatter.format_help()
+
+    def format_version(self):
+        import warnings
+        warnings.warn(
+            'The format_version method is deprecated -- the "version" '
+            'argument to ArgumentParser is no longer supported.',
+            DeprecationWarning)
+        formatter = self._get_formatter()
+        formatter.add_text(self.version)
+        return formatter.format_help()
+
+    def _get_formatter(self):
+        return self.formatter_class(prog=self.prog)
+
+    # =====================
+    # Help-printing methods
+    # =====================
+    def print_usage(self, file=None):
+        if file is None:
+            file = _sys.stdout
+        self._print_message(self.format_usage(), file)
+
+    def print_help(self, file=None):
+        if file is None:
+            file = _sys.stdout
+        self._print_message(self.format_help(), file)
+
+    def print_version(self, file=None):
+        import warnings
+        warnings.warn(
+            'The print_version method is deprecated -- the "version" '
+            'argument to ArgumentParser is no longer supported.',
+            DeprecationWarning)
+        self._print_message(self.format_version(), file)
+
+    def _print_message(self, message, file=None):
+        if message:
+            if file is None:
+                file = _sys.stderr
+            file.write(message)
+
+    # ===============
+    # Exiting methods
+    # ===============
+    def exit(self, status=0, message=None):
+        if message:
+            self._print_message(message, _sys.stderr)
+        _sys.exit(status)
+
+    def error(self, message):
+        """error(message: string)
+
+        Prints a usage message incorporating the message to stderr and
+        exits.
+
+        If you override this in a subclass, it should not return -- it
+        should either exit or raise an exception.
+        """
+        self.print_usage(_sys.stderr)
+        self.exit(2, _('%s: error: %s\n') % (self.prog, message))
diff --git a/final/utils/jscop2cloog.py b/final/utils/jscop2cloog.py
new file mode 100755
index 0000000..0d62646
--- /dev/null
+++ b/final/utils/jscop2cloog.py
@@ -0,0 +1,68 @@
+#!/usr/bin/python
+import argparse, os
+import json
+
+def getDomains(scop):
+  statements = scop['statements'];
+  numStatements = len(statements)
+
+  output = "%s\n\n" % str(numStatements)
+
+  for statement in scop['statements']:
+    output += "%s\n\n" % statement['domain']
+    output += "0  0  0               # for future options\n\n"
+
+
+  return output
+
+def getSchedules(scop):
+  statements = scop['statements'];
+  numStatements = len(statements)
+
+  output = "%s\n\n" % str(numStatements)
+
+  for statement in scop['statements']:
+    output += "%s\n\n" % statement['schedule']
+
+  return output
+
+def writeCloog(scop):
+  template = """
+# ---------------------- CONTEXT ----------------------
+c # language is C
+
+# Context (no constraints on two parameters)
+%s
+
+0 # We do not want to set manually the parameter names
+
+# --------------------- STATEMENTS --------------------
+%s
+
+0 # We do not want to set manually the iterator names
+
+# --------------------- SCATTERING --------------------
+%s
+
+0 # We do not want to set manually the schedule dimension names
+"""
+
+  context = scop['context']
+  domains = getDomains(scop)
+  schedules = getSchedules(scop)
+  print template % (context, domains, schedules)
+
+def __main__():
+  description = 'Translate JSCoP into iscc input'
+  parser = argparse.ArgumentParser(description)
+  parser.add_argument('inputFile', metavar='N', type=file,
+                      help='The JSCoP file')
+
+  args = parser.parse_args()
+  inputFile = args.inputFile
+  scop = json.load(inputFile)
+
+  writeCloog(scop)
+
+__main__()
+
diff --git a/final/utils/pyscop/isl.py b/final/utils/pyscop/isl.py
new file mode 100644
index 0000000..0c8de2f
--- /dev/null
+++ b/final/utils/pyscop/isl.py
@@ -0,0 +1,578 @@
+from ctypes import *
+
+isl = cdll.LoadLibrary("libisl.so")
+
+class Context:
+  defaultInstance = None
+  instances = {}
+
+  def __init__(self):
+    ptr = isl.isl_ctx_alloc()
+    self.ptr = ptr
+    Context.instances[ptr] = self
+
+  def __del__(self):
+    isl.isl_ctx_free(self)
+
+  def from_param(self):
+    return self.ptr
+
+  @staticmethod
+  def from_ptr(ptr):
+    return Context.instances[ptr]
+
+  @staticmethod
+  def getDefaultInstance():
+    if Context.defaultInstance == None:
+      Context.defaultInstance = Context()
+
+    return Context.defaultInstance
+
+class IslObject:
+  def __init__(self, string = "", ctx = None, ptr = None):
+    self.initialize_isl_methods()
+    if ptr != None:
+      self.ptr = ptr
+      self.ctx = self.get_isl_method("get_ctx")(self)
+      return
+
+    if ctx == None:
+      ctx = Context.getDefaultInstance()
+
+    self.ctx = ctx
+    self.ptr = self.get_isl_method("read_from_str")(ctx, string, -1)
+
+  def __del__(self):
+    self.get_isl_method("free")(self)
+
+  def from_param(self):
+    return self.ptr
+
+  @property
+  def context(self):
+    return self.ctx
+
+  def __repr__(self):
+    p = Printer(self.ctx)
+    self.to_printer(p)
+    return p.getString();
+
+  def __str__(self):
+    p = Printer(self.ctx)
+    self.to_printer(p)
+    return p.getString();
+
+  @staticmethod
+  def isl_name():
+    return "No isl name available"
+
+  def initialize_isl_methods(self):
+    if hasattr(self.__class__, "initialized"):
+      return
+
+    self.__class__.initalized = True
+    self.get_isl_method("read_from_str").argtypes = [Context, c_char_p, c_int]
+    self.get_isl_method("copy").argtypes = [self.__class__]
+    self.get_isl_method("copy").restype = c_int
+    self.get_isl_method("free").argtypes = [self.__class__]
+    self.get_isl_method("get_ctx").argtypes = [self.__class__]
+    self.get_isl_method("get_ctx").restype = Context.from_ptr 
+    getattr(isl, "isl_printer_print_" + self.isl_name()).argtypes = [Printer, self.__class__]
+
+  def get_isl_method(self, name):
+    return getattr(isl, "isl_" + self.isl_name() + "_" + name)
+
+  def to_printer(self, printer):
+    getattr(isl, "isl_printer_print_" + self.isl_name())(printer, self)
+
+class BSet(IslObject):
+  @staticmethod
+  def from_ptr(ptr):
+    if not ptr:
+      return
+    return BSet(ptr = ptr)
+
+  @staticmethod
+  def isl_name():
+    return "basic_set"
+
+class Set(IslObject):
+  @staticmethod
+  def from_ptr(ptr):
+    if not ptr:
+      return
+    return Set(ptr = ptr)
+
+  @staticmethod
+  def isl_name():
+    return "set"
+
+class USet(IslObject):
+  @staticmethod
+  def from_ptr(ptr):
+    if not ptr:
+      return
+    return USet(ptr = ptr)
+
+  @staticmethod
+  def isl_name():
+    return "union_set"
+
+
+class BMap(IslObject):
+  @staticmethod
+  def from_ptr(ptr):
+    if not ptr:
+      return
+    return BMap(ptr = ptr)
+
+  def __mul__(self, set):
+    return self.intersect_domain(set)
+
+  @staticmethod
+  def isl_name():
+    return "basic_map"
+
+class Map(IslObject):
+  @staticmethod
+  def from_ptr(ptr):
+    if not ptr:
+      return
+    return Map(ptr = ptr)
+
+  def __mul__(self, set):
+    return self.intersect_domain(set)
+
+  @staticmethod
+  def isl_name():
+    return "map"
+
+  @staticmethod
+  def lex_lt(dim):
+    dim = isl.isl_dim_copy(dim)
+    return isl.isl_map_lex_lt(dim)
+
+  @staticmethod
+  def lex_le(dim):
+    dim = isl.isl_dim_copy(dim)
+    return isl.isl_map_lex_le(dim)
+
+  @staticmethod
+  def lex_gt(dim):
+    dim = isl.isl_dim_copy(dim)
+    return isl.isl_map_lex_gt(dim)
+
+  @staticmethod
+  def lex_ge(dim):
+    dim = isl.isl_dim_copy(dim)
+    return isl.isl_map_lex_ge(dim)
+
+class UMap(IslObject):
+  @staticmethod
+  def from_ptr(ptr):
+    if not ptr:
+      return
+    return UMap(ptr = ptr)
+
+  @staticmethod
+  def isl_name():
+    return "union_map"
+
+class Dim(IslObject):
+  @staticmethod
+  def from_ptr(ptr):
+    if not ptr:
+      return
+    return Dim(ptr = ptr)
+
+  @staticmethod
+  def isl_name():
+    return "dim"
+
+  def initialize_isl_methods(self):
+    if hasattr(self.__class__, "initialized"):
+      return
+
+    self.__class__.initalized = True
+    self.get_isl_method("copy").argtypes = [self.__class__]
+    self.get_isl_method("copy").restype = c_int
+    self.get_isl_method("free").argtypes = [self.__class__]
+    self.get_isl_method("get_ctx").argtypes = [self.__class__]
+    self.get_isl_method("get_ctx").restype = Context.from_ptr 
+
+  def __repr__(self):
+    return str(self)
+
+  def __str__(self):
+
+    dimParam = isl.isl_dim_size(self, 1)
+    dimIn = isl.isl_dim_size(self, 2)
+    dimOut = isl.isl_dim_size(self, 3)
+
+    if dimIn:
+      return "<dim In:%s, Out:%s, Param:%s>" % (dimIn, dimOut, dimParam)
+
+    return "<dim Set:%s, Param:%s>" % (dimOut, dimParam)
+
+class Printer:
+  FORMAT_ISL = 0
+  FORMAT_POLYLIB = 1
+  FORMAT_POLYLIB_CONSTRAINTS = 2
+  FORMAT_OMEGA = 3
+  FORMAT_C = 4
+  FORMAT_LATEX = 5
+  FORMAT_EXT_POLYLIB = 6
+
+  def __init__(self, ctx = None):
+    if ctx == None:
+      ctx = Context.getDefaultInstance()
+
+    self.ctx = ctx
+    self.ptr = isl.isl_printer_to_str(ctx)
+
+  def setFormat(self, format):
+    self.ptr = isl.isl_printer_set_output_format(self, format);
+
+  def from_param(self):
+    return self.ptr
+
+  def __del__(self):
+    isl.isl_printer_free(self)
+
+  def getString(self):
+    return isl.isl_printer_get_str(self)
+
+functions = [
+             # Unary properties
+             ("is_empty", BSet, [BSet], c_int),
+             ("is_empty", Set, [Set], c_int),
+             ("is_empty", USet, [USet], c_int),
+             ("is_empty", BMap, [BMap], c_int),
+             ("is_empty", Map, [Map], c_int),
+             ("is_empty", UMap, [UMap], c_int),
+
+    #         ("is_universe", Set, [Set], c_int),
+    #         ("is_universe", Map, [Map], c_int),
+
+             ("is_single_valued", Map, [Map], c_int),
+
+             ("is_bijective", Map, [Map], c_int),
+
+             ("is_wrapping", BSet, [BSet], c_int),
+             ("is_wrapping", Set, [Set], c_int),
+
+             # Binary properties
+             ("is_equal", BSet, [BSet, BSet], c_int),
+             ("is_equal", Set, [Set, Set], c_int),
+             ("is_equal", USet, [USet, USet], c_int),
+             ("is_equal", BMap, [BMap, BMap], c_int),
+             ("is_equal", Map, [Map, Map], c_int),
+             ("is_equal", UMap, [UMap, UMap], c_int),
+
+             # is_disjoint missing
+
+             # ("is_subset", BSet, [BSet, BSet], c_int),
+             ("is_subset", Set, [Set, Set], c_int),
+             ("is_subset", USet, [USet, USet], c_int),
+             ("is_subset", BMap, [BMap, BMap], c_int),
+             ("is_subset", Map, [Map, Map], c_int),
+             ("is_subset", UMap, [UMap, UMap], c_int),
+             #("is_strict_subset", BSet, [BSet, BSet], c_int),
+             ("is_strict_subset", Set, [Set, Set], c_int),
+             ("is_strict_subset", USet, [USet, USet], c_int),
+             ("is_strict_subset", BMap, [BMap, BMap], c_int),
+             ("is_strict_subset", Map, [Map, Map], c_int),
+             ("is_strict_subset", UMap, [UMap, UMap], c_int),
+
+             # Unary Operations
+             ("complement", Set, [Set], Set),
+             ("reverse", BMap, [BMap], BMap),
+             ("reverse", Map, [Map], Map),
+             ("reverse", UMap, [UMap], UMap),
+
+             # Projection missing
+             ("range", BMap, [BMap], BSet),
+             ("range", Map, [Map], Set),
+             ("range", UMap, [UMap], USet),
+             ("domain", BMap, [BMap], BSet),
+             ("domain", Map, [Map], Set),
+             ("domain", UMap, [UMap], USet),
+
+             ("identity", Set, [Set], Map),
+             ("identity", USet, [USet], UMap),
+
+             ("deltas", BMap, [BMap], BSet),
+             ("deltas", Map, [Map], Set),
+             ("deltas", UMap, [UMap], USet),
+
+             ("coalesce", Set, [Set], Set),
+             ("coalesce", USet, [USet], USet),
+             ("coalesce", Map, [Map], Map),
+             ("coalesce", UMap, [UMap], UMap),
+
+             ("detect_equalities", BSet, [BSet], BSet),
+             ("detect_equalities", Set, [Set], Set),
+             ("detect_equalities", USet, [USet], USet),
+             ("detect_equalities", BMap, [BMap], BMap),
+             ("detect_equalities", Map, [Map], Map),
+             ("detect_equalities", UMap, [UMap], UMap),
+
+             ("convex_hull", Set, [Set], Set),
+             ("convex_hull", Map, [Map], Map),
+
+             ("simple_hull", Set, [Set], Set),
+             ("simple_hull", Map, [Map], Map),
+
+             ("affine_hull", BSet, [BSet], BSet),
+             ("affine_hull", Set, [Set], BSet),
+             ("affine_hull", USet, [USet], USet),
+             ("affine_hull", BMap, [BMap], BMap),
+             ("affine_hull", Map, [Map], BMap),
+             ("affine_hull", UMap, [UMap], UMap),
+
+             ("polyhedral_hull", Set, [Set], Set),
+             ("polyhedral_hull", USet, [USet], USet),
+             ("polyhedral_hull", Map, [Map], Map),
+             ("polyhedral_hull", UMap, [UMap], UMap),
+
+             # Power missing
+             # Transitive closure missing
+             # Reaching path lengths missing
+
+             ("wrap", BMap, [BMap], BSet),
+             ("wrap", Map, [Map], Set),
+             ("wrap", UMap, [UMap], USet),
+             ("unwrap", BSet, [BMap], BMap),
+             ("unwrap", Set, [Map], Map),
+             ("unwrap", USet, [UMap], UMap),
+
+             ("flatten", Set, [Set], Set),
+             ("flatten", Map, [Map], Map),
+             ("flatten_map", Set, [Set], Map),
+
+             # Dimension manipulation missing
+
+             # Binary Operations
+             ("intersect", BSet, [BSet, BSet], BSet),
+             ("intersect", Set, [Set, Set], Set),
+             ("intersect", USet, [USet, USet], USet),
+             ("intersect", BMap, [BMap, BMap], BMap),
+             ("intersect", Map, [Map, Map], Map),
+             ("intersect", UMap, [UMap, UMap], UMap),
+             ("intersect_domain", BMap, [BMap, BSet], BMap),
+             ("intersect_domain", Map, [Map, Set], Map),
+             ("intersect_domain", UMap, [UMap, USet], UMap),
+             ("intersect_range", BMap, [BMap, BSet], BMap),
+             ("intersect_range", Map, [Map, Set], Map),
+             ("intersect_range", UMap, [UMap, USet], UMap),
+
+             ("union", BSet, [BSet, BSet], Set),
+             ("union", Set, [Set, Set], Set),
+             ("union", USet, [USet, USet], USet),
+             ("union", BMap, [BMap, BMap], Map),
+             ("union", Map, [Map, Map], Map),
+             ("union", UMap, [UMap, UMap], UMap),
+
+             ("subtract", Set, [Set, Set], Set),
+             ("subtract", Map, [Map, Map], Map),
+             ("subtract", USet, [USet, USet], USet),
+             ("subtract", UMap, [UMap, UMap], UMap),
+
+             ("apply", BSet, [BSet, BMap], BSet),
+             ("apply", Set, [Set, Map], Set),
+             ("apply", USet, [USet, UMap], USet),
+             ("apply_domain", BMap, [BMap, BMap], BMap),
+             ("apply_domain", Map, [Map, Map], Map),
+             ("apply_domain", UMap, [UMap, UMap], UMap),
+             ("apply_range", BMap, [BMap, BMap], BMap),
+             ("apply_range", Map, [Map, Map], Map),
+             ("apply_range", UMap, [UMap, UMap], UMap),
+
+             ("gist", BSet, [BSet, BSet], BSet),
+             ("gist", Set, [Set, Set], Set),
+             ("gist", USet, [USet, USet], USet),
+             ("gist", BMap, [BMap, BMap], BMap),
+             ("gist", Map, [Map, Map], Map),
+             ("gist", UMap, [UMap, UMap], UMap),
+
+             # Lexicographic Optimizations
+             # partial_lexmin missing
+             ("lexmin", BSet, [BSet], BSet),
+             ("lexmin", Set, [Set], Set),
+             ("lexmin", USet, [USet], USet),
+             ("lexmin", BMap, [BMap], BMap),
+             ("lexmin", Map, [Map], Map),
+             ("lexmin", UMap, [UMap], UMap),
+
+             ("lexmax", BSet, [BSet], BSet),
+             ("lexmax", Set, [Set], Set),
+             ("lexmax", USet, [USet], USet),
+             ("lexmax", BMap, [BMap], BMap),
+             ("lexmax", Map, [Map], Map),
+             ("lexmax", UMap, [UMap], UMap),
+
+              # Undocumented
+             ("lex_lt_union_set", USet, [USet, USet], UMap),
+             ("lex_le_union_set", USet, [USet, USet], UMap),
+             ("lex_gt_union_set", USet, [USet, USet], UMap),
+             ("lex_ge_union_set", USet, [USet, USet], UMap),
+
+             ]
+keep_functions = [
+             # Unary properties
+             ("get_dim", BSet, [BSet], Dim),
+             ("get_dim", Set, [Set], Dim),
+             ("get_dim", USet, [USet], Dim),
+             ("get_dim", BMap, [BMap], Dim),
+             ("get_dim", Map, [Map], Dim),
+             ("get_dim", UMap, [UMap], Dim)
+             ]
+
+def addIslFunction(object, name):
+    functionName = "isl_" + object.isl_name() + "_" + name
+    islFunction = getattr(isl, functionName)
+    if len(islFunction.argtypes) == 1:
+      f = lambda a: islFunctionOneOp(islFunction, a)
+    elif len(islFunction.argtypes) == 2:
+      f = lambda a, b: islFunctionTwoOp(islFunction, a, b)
+    object.__dict__[name] = f
+
+
+def islFunctionOneOp(islFunction, ops):
+  ops = getattr(isl, "isl_" + ops.isl_name() + "_copy")(ops)
+  return islFunction(ops)
+
+def islFunctionTwoOp(islFunction, opOne, opTwo):
+  opOne = getattr(isl, "isl_" + opOne.isl_name() + "_copy")(opOne)
+  opTwo = getattr(isl, "isl_" + opTwo.isl_name() + "_copy")(opTwo)
+  return islFunction(opOne, opTwo)
+
+for (operation, base, operands, ret) in functions:
+  functionName = "isl_" + base.isl_name() + "_" + operation
+  islFunction = getattr(isl, functionName)
+  if len(operands) == 1:
+    islFunction.argtypes = [c_int]
+  elif len(operands) == 2:
+    islFunction.argtypes = [c_int, c_int]
+
+  if ret == c_int:
+    islFunction.restype = ret
+  else:
+    islFunction.restype = ret.from_ptr
+
+  addIslFunction(base, operation)
+
+def addIslFunctionKeep(object, name):
+    functionName = "isl_" + object.isl_name() + "_" + name
+    islFunction = getattr(isl, functionName)
+    if len(islFunction.argtypes) == 1:
+      f = lambda a: islFunctionOneOpKeep(islFunction, a)
+    elif len(islFunction.argtypes) == 2:
+      f = lambda a, b: islFunctionTwoOpKeep(islFunction, a, b)
+    object.__dict__[name] = f
+
+def islFunctionOneOpKeep(islFunction, ops):
+  return islFunction(ops)
+
+def islFunctionTwoOpKeep(islFunction, opOne, opTwo):
+  return islFunction(opOne, opTwo)
+
+for (operation, base, operands, ret) in keep_functions:
+  functionName = "isl_" + base.isl_name() + "_" + operation
+  islFunction = getattr(isl, functionName)
+  if len(operands) == 1:
+    islFunction.argtypes = [c_int]
+  elif len(operands) == 2:
+    islFunction.argtypes = [c_int, c_int]
+
+  if ret == c_int:
+    islFunction.restype = ret
+  else:
+    islFunction.restype = ret.from_ptr
+
+  addIslFunctionKeep(base, operation)
+
+isl.isl_ctx_free.argtypes = [Context]
+isl.isl_basic_set_read_from_str.argtypes = [Context, c_char_p, c_int]
+isl.isl_set_read_from_str.argtypes = [Context, c_char_p, c_int]
+isl.isl_basic_set_copy.argtypes = [BSet]
+isl.isl_basic_set_copy.restype = c_int
+isl.isl_set_copy.argtypes = [Set]
+isl.isl_set_copy.restype = c_int
+isl.isl_set_copy.argtypes = [Set]
+isl.isl_set_copy.restype = c_int
+isl.isl_set_free.argtypes = [Set]
+isl.isl_basic_set_get_ctx.argtypes = [BSet]
+isl.isl_basic_set_get_ctx.restype = Context.from_ptr
+isl.isl_set_get_ctx.argtypes = [Set]
+isl.isl_set_get_ctx.restype = Context.from_ptr
+isl.isl_basic_set_get_dim.argtypes = [BSet]
+isl.isl_basic_set_get_dim.restype = Dim.from_ptr
+isl.isl_set_get_dim.argtypes = [Set]
+isl.isl_set_get_dim.restype = Dim.from_ptr
+isl.isl_union_set_get_dim.argtypes = [USet]
+isl.isl_union_set_get_dim.restype = Dim.from_ptr
+
+isl.isl_basic_map_read_from_str.argtypes = [Context, c_char_p, c_int]
+isl.isl_map_read_from_str.argtypes = [Context, c_char_p, c_int]
+isl.isl_basic_map_free.argtypes = [BMap]
+isl.isl_map_free.argtypes = [Map]
+isl.isl_basic_map_copy.argtypes = [BMap]
+isl.isl_basic_map_copy.restype = c_int
+isl.isl_map_copy.argtypes = [Map]
+isl.isl_map_copy.restype = c_int
+isl.isl_map_get_ctx.argtypes = [Map]
+isl.isl_basic_map_get_ctx.argtypes = [BMap]
+isl.isl_basic_map_get_ctx.restype = Context.from_ptr
+isl.isl_map_get_ctx.argtypes = [Map]
+isl.isl_map_get_ctx.restype = Context.from_ptr
+isl.isl_basic_map_get_dim.argtypes = [BMap]
+isl.isl_basic_map_get_dim.restype = Dim.from_ptr
+isl.isl_map_get_dim.argtypes = [Map]
+isl.isl_map_get_dim.restype = Dim.from_ptr
+isl.isl_union_map_get_dim.argtypes = [UMap]
+isl.isl_union_map_get_dim.restype = Dim.from_ptr
+isl.isl_printer_free.argtypes = [Printer]
+isl.isl_printer_to_str.argtypes = [Context]
+isl.isl_printer_print_basic_set.argtypes = [Printer, BSet]
+isl.isl_printer_print_set.argtypes = [Printer, Set]
+isl.isl_printer_print_basic_map.argtypes = [Printer, BMap]
+isl.isl_printer_print_map.argtypes = [Printer, Map]
+isl.isl_printer_get_str.argtypes = [Printer]
+isl.isl_printer_get_str.restype = c_char_p
+isl.isl_printer_set_output_format.argtypes = [Printer, c_int]
+isl.isl_printer_set_output_format.restype = c_int
+isl.isl_dim_size.argtypes = [Dim, c_int]
+isl.isl_dim_size.restype = c_int
+
+isl.isl_map_lex_lt.argtypes = [c_int]
+isl.isl_map_lex_lt.restype = Map.from_ptr
+isl.isl_map_lex_le.argtypes = [c_int]
+isl.isl_map_lex_le.restype = Map.from_ptr
+isl.isl_map_lex_gt.argtypes = [c_int]
+isl.isl_map_lex_gt.restype = Map.from_ptr
+isl.isl_map_lex_ge.argtypes = [c_int]
+isl.isl_map_lex_ge.restype = Map.from_ptr
+
+isl.isl_union_map_compute_flow.argtypes = [c_int, c_int, c_int, c_int, c_void_p,
+                                           c_void_p, c_void_p, c_void_p]
+
+def dependences(sink, must_source, may_source, schedule):
+  sink = getattr(isl, "isl_" + sink.isl_name() + "_copy")(sink)
+  must_source = getattr(isl, "isl_" + must_source.isl_name() + "_copy")(must_source)
+  may_source = getattr(isl, "isl_" + may_source.isl_name() + "_copy")(may_source)
+  schedule = getattr(isl, "isl_" + schedule.isl_name() + "_copy")(schedule)
+  must_dep = c_int()
+  may_dep = c_int()
+  must_no_source = c_int()
+  may_no_source = c_int()
+  isl.isl_union_map_compute_flow(sink, must_source, may_source, schedule, \
+                                 byref(must_dep), byref(may_dep),
+                                 byref(must_no_source),
+                                 byref(may_no_source))
+
+  return (UMap.from_ptr(must_dep), UMap.from_ptr(may_dep), \
+          USet.from_ptr(must_no_source), USet.from_ptr(may_no_source))
+
+
+__all__ = ['Set', 'Map', 'Printer', 'Context']
diff --git a/final/utils/pyscop/jscop2iscc.py b/final/utils/pyscop/jscop2iscc.py
new file mode 100755
index 0000000..3267e8e
--- /dev/null
+++ b/final/utils/pyscop/jscop2iscc.py
@@ -0,0 +1,68 @@
+#!/usr/bin/python
+import argparse, isl, os
+import json
+
+def printDomain(scop):
+
+  domain = isl.USet('{}')
+
+  for statement in scop['statements']:
+    domain = domain.union(isl.USet(statement['domain']))
+
+  print "D :=",
+  print str(domain) + ";"
+
+def printAccesses(scop):
+
+  read = isl.UMap('{}')
+
+  for statement in scop['statements']:
+    for access in statement['accesses']:
+      if access['kind'] == 'read':
+        read = read.union(isl.UMap(access['relation']))
+
+  print "R :=",
+  print str(read) + ";"
+
+  write = isl.UMap('{}')
+
+  for statement in scop['statements']:
+    for access in statement['accesses']:
+      if access['kind'] == 'write':
+        write = write.union(isl.UMap(access['relation']))
+
+  print "W :=",
+  print str(write) + ";"
+
+def printSchedule(scop):
+
+  schedule = isl.UMap('{}')
+
+  for statement in scop['statements']:
+    schedule = schedule.union(isl.UMap(statement['schedule']))
+
+  print "S :=",
+  print str(schedule) + ";"
+
+def __main__():
+  description = 'Translate JSCoP into iscc input'
+  parser = argparse.ArgumentParser(description)
+  parser.add_argument('inputFile', metavar='N', type=file,
+                      help='The JSCoP file')
+
+  args = parser.parse_args()
+  inputFile = args.inputFile
+  scop = json.load(inputFile)
+
+  printDomain(scop)
+  printAccesses(scop)
+  printSchedule(scop)
+
+  print 'R := R * D;'
+  print 'W := W * D;'
+  print 'Dep := (last W before R under S)[0];'
+  print 'schedule D respecting Dep minimizing Dep;'
+
+
+__main__()
+
diff --git a/final/utils/pyscop/pyscop.py b/final/utils/pyscop/pyscop.py
new file mode 100644
index 0000000..a7c3481
--- /dev/null
+++ b/final/utils/pyscop/pyscop.py
@@ -0,0 +1,68 @@
+import json
+from isl import *
+
+class Scop:
+  def __init__(self, filename):
+    f = open(filename, 'r')
+    self.json = json.load(f)
+    return
+
+  def __str__(self):
+    return json.dumps(self.json, indent=2)
+
+  def __repr__(self):
+    return str(self)
+
+  @property
+  def statements(self):
+    return self.json['statements']
+
+class Transforms:
+  """
+  Create a map that interchanges two dimensions 'A' and 'B'
+
+  numberDimensions: The overall number of dimensions
+  dimensionA: The dimension of dimension 'A'
+  dimensionB: The dimension of dimension 'B'
+
+  getInterchange(2, 0, 1):
+  {[d0, d1] -> [d1, d0]}
+  """
+  @staticmethod
+  def getInterchange(numberDimensions, dimensionA, dimensionB):
+
+    dims = ['d' + str(i) for i in range(numberDimensions)]
+    dimString = ",".join(dims)
+
+    changedDims = dims
+    first = dims[dimensionA]
+    second = dims[dimensionB]
+    changedDims[dimensionA] = second
+    changedDims[dimensionB] = first
+    changedDimString = ",".join(changedDims)
+
+    return Map("{[%s] -> [%s]}" % (dimString, changedDimString))
+
+  """
+  Create a map that strip mines one dimension
+
+  numberDimensions: The overall number of dimensions
+  stripMineDim: The dimension to strip mine
+  factor: The strip mining factor
+
+  getStripMine(2, 1, 64):
+  {[d0, d1] -> [d0, o, d1] : o % 64 = 0 and o <= d1 <= d1 + 63}
+  """
+  @staticmethod
+  def getStripMine(numberDimensions, stripMineDim, factor):
+
+    dims = ['d' + str(i) for i in range(numberDimensions)]
+    dimString = ",".join(dims)
+
+    changedDims = dims
+    smd = dims[stripMineDim]
+    changedDims[stripMineDim] = "o,%s" % smd
+    changedDimString = ",".join(changedDims)
+    string = "{[%s] -> [%s]: o %% %i = 0 and o <= %s <= o + %i}" % \
+          (dimString, changedDimString, factor, smd, factor - 1)
+    return Map(string)
diff --git a/final/www/.htaccess b/final/www/.htaccess
new file mode 100644
index 0000000..bfd0afc
--- /dev/null
+++ b/final/www/.htaccess
@@ -0,0 +1 @@
+AddHandler server-parsed .html 
diff --git a/final/www/bugs.html b/final/www/bugs.html
new file mode 100644
index 0000000..07614d5
--- /dev/null
+++ b/final/www/bugs.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+  "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+  <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+  <title>Polly - Bugs</title>
+  <link type="text/css" rel="stylesheet" href="menu.css" />
+  <link type="text/css" rel="stylesheet" href="content.css" />
+</head>
+<body>
+
+<div id="box">
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<h1>Bug Reports</h1>
+
+Polly uses the LLVM bug tracking system:
+
+<ul>
+<li>
+<a href="https://bugs.llvm.org/enter_bug.cgi?product=Polly">File new bug</a>
+</li>
+
+<li>
+<a
+href="https://bugs.llvm.org/buglist.cgi?query_format=advanced&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&product=Polly&list_id=91437">Show open bugs</a>
+</li>
+</ul>
+
+
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/changelog.html b/final/www/changelog.html
new file mode 100644
index 0000000..94a54aa
--- /dev/null
+++ b/final/www/changelog.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+          "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head> <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Polly - ChangeLog</title>
+  <link type="text/css" rel="stylesheet" href="menu.css">
+  <link type="text/css" rel="stylesheet" href="content.css">
+</head>
+<body>
+<div id="box">
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+<h1> ChangeLog </h1>
+<h2> trunk</h2>
+
+<ul>
+<li>Optimized isl for small integers, such that mostly cheap 32bit operations
+are used instead of costly arbitrary precision integers that often also involve
+malloc/free calls. As a result, the compile-time increase due to Polly has
+been largely reduced.</li>
+
+<li>Support for modulo operations: Accesses such as <pre>A[t%2][i]</pre> can
+    now be analyzed.
+</ul>
+
+<h2> 3.7 </h2>
+
+<ul>
+<li>libPluto support has been removed. It has not been tested regularly and
+due to it being copyleft license it had never a chance to become a a core
+piece of Polly. Experiments with different schedulers should use the jscop
+interface.</li>
+</ul>
+
+<h2> 3.6</h2>
+
+<ul>
+<li>Switch to the new isl AST generator (replacing CLooG)</li>
+<li>Run-time alias checks</li>
+<li>Computation of no-alias information for later LLVM optimizations
+(vectorizer, LICM, ...)</li>
+<li>Support for multi-dimensional arrays of parameteric size (still tested)</li>
+<li>New assumption tracking framework</li>
+<ul>
+<li>Accesses to multi-dimensional arrays of fixed size are within bounds</li>
+</ul>
+<li>Compile-time reduction</li>
+</ul>
+
+<h2> Older releases</h2>
+
+No changelog available. Please look at the <a
+href="http://repo.or.cz/w/polly-mirror.git">commit history</a>.
+
+</html>
+</div>
+</body>
+</html>
diff --git a/final/www/content.css b/final/www/content.css
new file mode 100644
index 0000000..1294af7
--- /dev/null
+++ b/final/www/content.css
@@ -0,0 +1,139 @@
+html { margin: 0px; } body { margin: 8px; }
+
+html, body {
+  padding:0px;
+  font-family:"Lucida Grande", "Lucida Sans Unicode", Arial, Verdana, Helvetica, sans-serif; background-color: #fff; color: #222;
+}
+
+#box {
+  margin-left: auto;
+  margin-right: auto;
+  max-width: 67em;
+}
+[id=content] {
+	/* *****  EDIT THIS VALUE IF CONTENT OVERLAPS MENU ***** */
+        margin-left: 21em;
+	padding-left: 3em;
+}
+
+a:visited {
+  color: #931e24;
+}
+
+h1, h2, h3, tt { color: #000 }
+
+h1 { padding-top:0px; margin-top:0px;}
+h2 { color:#333333; padding-top:0.5em; }
+h3 { padding-top: 0.5em; color:#2d58b7}
+li { padding-bottom: 0.5em; }
+ul { padding-left:1.5em; }
+
+TD.done {background-color: #88ff99; text-align: center}
+TD.inprogress{background-color: #ffce00; text-align: center}
+TD.open{background-color: #e6705f; text-align: center}
+TD.nice{background-color: #5555df; text-align: center}
+TD.niceinprogress{background-color: #8888ff; text-align: center}
+
+PRE.code {padding-left: 0.5em; background-color: #eeeeee}
+PRE {padding-left: 0.5em}
+
+/* Slides */
+IMG.img_slide {
+    display: block;
+    margin-left: auto;
+    margin-right: auto
+}
+
+.itemTitle { color:#2d58b7 }
+
+span.error { color:red }
+span.caret { color:green; font-weight:bold }
+
+/* Tables */
+tr { vertical-align:top }
+#news P {padding: 0px; margin: 0px; border: 0px}
+
+#head {
+    min-height: 15em;
+    background-image:url(images/header-background.png);
+    background-repeat:no-repeat;
+    background-position: right;
+    max-width: 70em;
+    margin-bottom: 1em
+
+
+}
+
+#head h1 {
+  padding-bottom: 0em;
+  margin-bottom: 0em;
+  padding-top: 1em;
+  padding-left: 2em;
+  font-size: 3em;
+}
+
+#head h1 span {
+  background: white;
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  border-radius: 5px;
+  background: white;
+  box-shadow: 1px 2px 5px 1px rgba(0, 0, 0, 0.7),
+              -1px 2px 20px rgba(255, 255, 255, 0.6) inset; 
+}
+
+#head h1 span a {
+  text-decoration: none;
+  color: #3b4567;
+}
+#head h1 span:before {
+  content: "\00a0 ";
+}
+#head h1 span:after {
+  content: "\00a0 ";
+}
+
+#head h2 {
+  color: #3b4567;
+  text-align: center;
+  padding-top: 0em;
+  margin-top: 0em;
+  padding-left: .5em;
+  padding-bottom: .5em;
+}
+
+#head h2 span {
+  background: white;
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  border-radius: 5px;
+  background: white;
+  box-shadow: 1px 2px 5px 1px rgba(0, 0, 0, 0.7),
+              -1px 2px 20px rgba(255, 255, 255, 0.6) inset; 
+  padding-top: 0.2em;
+  padding-bottom: 0.2em;
+}
+
+#head h2 span:before {
+  content: "\00a0\00a0\00a0";
+}
+#head h2 span:after {
+  content: "\00a0\00a0\00a0";
+}
+
+#head p:before {
+  content: "\00a0\00a0\00a0";
+}
+#head p:after {
+  content: "\00a0\00a0\00a0";
+}
+
+#head p {
+  padding:0.1em;
+  background: rgba(0,0,0,0.3);
+  color: white;
+  position: absolute;
+  top: -1em; right: 0.5em;
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+}
diff --git a/final/www/contributors.html b/final/www/contributors.html
new file mode 100644
index 0000000..de15d01
--- /dev/null
+++ b/final/www/contributors.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+          "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+  <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+  <title>Polly - Contributors</title>
+  <link type="text/css" rel="stylesheet" href="menu.css" />
+  <link type="text/css" rel="stylesheet" href="content.css" />
+</head>
+<body>
+
+<div id="box">
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<h1>Contributors</h1>
+
+Polly is developed by a team of students supported by different universities.
+
+<h2>People</h2>
+<h3>Raghesh Aloor</h3>
+<p>Raghesh works on OpenMP code generation. He is funded as Google Summer of Code
+Student 2011.</p>
+
+<h3>Johannes Doerfert</h3>
+<p>Johannes works on Polly as part of his PhD research at Saarland University
+in Germany.</p>
+
+<h3>Tobias Grosser</h3>
+<p>Tobias is one of the two Co-founders of Polly. He designed the overall
+architecture and contributed to almost every part of Polly. Polly was started
+during his diploma studies at University of Passau. Furthermore, he spent 6
+months at Ohio State University (funded by the U.S. National Science Foundation
+through awards 0811781 and 0926688). From August 2011 he works on Polly,
+during his PhD with INRIA/UMPC/ENS (funded through a
+<a href="http://research.google.com/university/relations/fellowship_recipients.html">
+Google Europe Fellowship in Efficient Computing</a>).</p>
+
+<p>Website: <a href="http://www.grosser.es">www.grosser.es</a></p>
+
+
+<h3>Andreas Simb&uuml;rger</h3>
+<p>
+Andreas works on the profiling infrastructure during his PhD at University of
+Passau.
+</p>
+<p>Website: <a href="http://www.infosun.fim.uni-passau.de/cl/staff/simbuerger/">
+http://www.infosun.fim.uni-passau.de/cl/staff/simbuerger/</a></p>
+<h3>Hongbin Zheng</h3>
+<p>Hongbin Zheng is one of the two Co-founders of Polly. He was funded as a
+Google Summer of Code Student 2010 and implemented parts of the Polly frontends
+as well as the automake/cmake infrastructure.</p>
+
+<h2> Universities</h2>
+
+<p>Polly is supported by the following Universities.</p>
+<img src="images/iit-madras.png" style="padding:1em" />
+<img src="images/uni-passau.png" style="padding: 1em; padding-bottom:2em;"/>
+<img src="images/osu.png" style="padding:1em"/>
+<img src="images/sys-uni.png" style="padding:1em"/>
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/documentation.html b/final/www/documentation.html
new file mode 100644
index 0000000..67d6127
--- /dev/null
+++ b/final/www/documentation.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+          "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+  <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Polly - Documentation</title>
+  <link type="text/css" rel="stylesheet" href="menu.css">
+  <link type="text/css" rel="stylesheet" href="content.css">
+</head>
+<body>
+<div id="box">
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+  <!--*********************************************************************-->
+  <h1>Documentation</h1>
+  <!--*********************************************************************-->
+
+<ul>
+<li><a href="documentation/architecture.html">The Architecture of Polly</a></li>
+<li><a href="example_load_Polly_into_clang.html">Use Polly in clang/clang++</a>
+
+</li>
+
+<li>
+<a href="example_manual_matmul.html">Inside Polly - How to manually use the
+individual pieces of Polly</a>
+
+</li>
+<li><a href="documentation/passes.html">A list of the LLVM passes available
+in Polly</a></li>
+<li><a href="docs/">New SPINX based documentation (early stage)</a></li>
+</ul>
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/documentation/architecture.html b/final/www/documentation/architecture.html
new file mode 100644
index 0000000..aa1c80f
--- /dev/null
+++ b/final/www/documentation/architecture.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+  <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Polly - The architecture</title>
+  <link type="text/css" rel="stylesheet" href="../menu.css">
+  <link type="text/css" rel="stylesheet" href="../content.css">
+</head>
+<body>
+<div id="box">
+<!--#include virtual="../menu.html.incl"-->
+<div id="content">
+  <!--*********************************************************************-->
+  <h1>The Architecture Diagram of Polly</h1>
+  <!--*********************************************************************-->
+  <img src='../images/architecture.png' />
+</div>
+</div>
+</body>
+</html>
+
diff --git a/final/www/documentation/gpgpucodegen.html b/final/www/documentation/gpgpucodegen.html
new file mode 100644
index 0000000..bc2949a
--- /dev/null
+++ b/final/www/documentation/gpgpucodegen.html
@@ -0,0 +1,229 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+  <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Polly - GPGPU Code Generation</title>
+  <link type="text/css" rel="stylesheet" href="../menu.css">
+  <link type="text/css" rel="stylesheet" href="../content.css">
+</head>
+<body>
+<div id="box">
+<!--#include virtual="../menu.html.incl"-->
+<div id="content">
+  <!--*********************************************************************-->
+  <h1>Polly - GPGPU Code Generation</h1>
+  <!--*********************************************************************-->
+<p><em>WARNING: This project was part of the Google Summer of Code 2012.
+It is currently not finished, but it is in the design and implementation stage.
+The ideas/plans described here may not yet be implemented in Polly and may
+change later on.</em></p>
+
+This project adds GPGPU code generation feature to Polly.
+
+<h2>Objective</h2>
+<p>The overall objective of this GSoC project is to create a preliminary
+   implementation of GPGPU code generation for Polly. With this addition, users
+   can parallelize some perfectly nested loops with Polly to execute on a
+   heterogeneous platform, composed of CPU and GPU.</p>
+<p>There are several successful projects about automatic source-to-source gpu
+   code transformation. C-to-CUDA[1] uses the standard Pluto algorithms for
+   computing an affine schedule and then applies a wavefront transformation to
+   obtain one sequential and n-1 parallel loops. The parallel loops are then
+   mapped onto the blocks and threads of GPU. PPCG[2] introduces some advanced
+   algorithms which can expose much more parallelism than other methods . And It
+   also introduces affine partition heuristics and code generation algorithms
+   for locality enhancement in the registers and shared memory.</p>
+<p>Since automatic GPGPU code generation is quite a complex problem and what we
+   target is a low-level intermediate representation, LLVM IR, rather than a
+   high-level language source, it is important for us to set a proper objective
+   as a start step to give a complete solution to GPGPU code generation for LLVM
+   IR.</p>
+<p>Firstly, we plan to target two kinds of relatively simple test cases. One is
+   comprised of pure parallel and perfectly nested loops, like the following
+   code.</p>
+<pre>
+parfor(int i=0 to M)
+  parfor(int j=0 to N)
+    LoopBody(i, j);
+</pre>
+<p>Another one is that all the loops in it are parallel except the inner-most
+   one, just like this:</p>
+<pre>
+parfor(int i=0 to M)
+  parfor(int j=0 to N)
+    non-parfor(int k=0 to K)
+      LoopBody(i, j, k);
+</pre>
+<p>The LoopBody part should be limited to instructions or functions calls
+   (intrinsics) which can be handled by LLVM's NVPTX backend.</p>
+<p>On the other hand, we focus on building a preliminary and scalable framework
+   of GPGPU code generation for polly. Thus we plan to employ relatively simple
+   tiling and mapping algorithms and optimize them later.</p>
+<h2>Work Flow</h2>
+<h3>GPGPU Code Generation In General</h3>
+<p>C-to-CUDA[1] and PPCG[2] propose similar steps to solve the automatic GPGPU
+   code generation problem.</p>
+<li>Look for parallel loops.</li>
+<li>Create a polyhedral model from the loops.</li>
+<li>Tile and map the loops to GPU blocks and threads.</li>
+<li>Determine where to place the data.</li>
+<h3>What has been done in Polly</h3>
+<p>Polly has implemented the 1st, 2nd and part of the 3rd of the above steps and
+   many other analysis and transformation passes.</p>
+<h3>What to do in Polly</h3>
+<p>Unlike many source-to-source optimizers such as C-to-CUDA and PPCG, Polly is
+   a low-level optimizer, which means we can't use a source-level compiler
+   (e.g. NVCC) to generate the final assembly for the device. We need manually
+   insert device driver API calls to execute the generated kernel assembly
+   text.</p>
+<p>In this project, we assume that the device driver library has provided an
+   interface to launch kernels in the form of assembly text. Fortunately, most
+   of the mainstream GPU vendors provide such a feature in thier products (see
+   ptxjit of NVIDIA GPUs and CAL of AMD GPUs). Generally speaking, what we
+   are going to do in Polly is:</p>
+<li>Find a way to tile the parallel loops.</li>
+<li>Find a way to extract the loop body and transform it into thread-centric
+    parallel code.</li>
+<li>Find a way to store/load the thread-centric code into/from a device module.
+<li>Find a way to pass the target machine information and generate code of the
+    device module for the target.
+<li>Find a way to map the tiled loop to GPU blocks and threads.</li>
+<li>Find a way to insert CUDA synchronization operations on-demand.
+<li>Find a way to generate the memory copy operations between a host and a
+    device.</li>
+<li>Implement/Wrap a runtime library to serve as the execution engine for the
+    generated device code.</li>
+
+<h3>The Work Flow</h3>
+<p>In this section, we assume that the host cpu is X86 and the device is NVIDIA
+   CUDA-compatible. we will use the following test case to describe our work
+   flow.</p>
+<pre>
+for(i = 0; i &lt; 128; i++)
+      for(j = 0; j &lt; 128; j++)
+              A[i][j] = i*128 + j;
+</pre>
+<p>The work flow of our code generator is as follows.</p>
+<p>1.We first use Polly's jscop file importer to get a wanted 4-level parallel
+   tiled code.</p>
+The "schedule" part of the pre-optimization jscop file is as the following:
+<pre>
+"schedule" : "{ Stmt_for_body3[i0, i1] -&gt; schedule[0, i0, 0, i1, 0] }"
+</pre>
+The jscop file describing the tiling transformation is:
+<pre>
+"schedule" : "{ Stmt_for_body3[i0, i1] -&gt; schedule[0, o0, o1, o2, o3]:
+              o0 &gt;= 0 and o0 &lt;= 7 and o1 &gt;= 0 and o1 &lt;= 15 and
+              o2 &gt;= 0 and o2 &lt;= 7 and o3 &gt;= 0 and o3 &lt;= 15 and
+              i0 = 16o0 + o1 and i1 = 16o2 + o3 }"
+</pre>
+We can test the schedule with the following command line.
+<pre>
+opt -load /path/to/polly/build/LLVMPolly.so -basicaa -polly-import-jscop
+    -polly-ast -analyze -q ./test.ll
+    -polly-import-jscop-postfix=transformed+gpu
+</pre>
+The output of this schedule is:
+<pre>
+for (c2=0;c2&lt;=7;c2++) {
+  for (c3=0;c3&lt;=15;c3++) {
+    for (c4=0;c4&lt;=7;c4++) {
+      for (c5=0;c5&lt;=15;c5++) {
+        Stmt_for_body3(16*c2+c3,16*c4+c5);
+      }
+    }
+  }
+}
+</pre>
+Now we get a 4-dimensional parallel loops with a single SCoP statement in it.
+<p>2.We then extract the loop body (or the inner-most non-parallel loop) into a
+   LLVM function, tagging it with PTX_Kernel call convention.</p>
+<p>3.We extract the PTX_kernel function into a temporary module, set the target
+   triple (e.g. nvptx64-unknown-linux) for the module, transform the temporary
+   module into a string, store it in the original module and erase the
+   PTX_kernel function.</p>
+<p>4.We replace the loops with their GPGPU counterpart. The GPGPU part of code
+   is composed of a call to the llvm.codegen intrinsic and function calls to our
+   GPU runtime library.</p>
+<p>5.Finally, we generate the executable program with <em>llc</em> or run the
+   optimized LLVM IRs with a JIT compiler like  <em>lli</em>.</p>
+<h2>Usage</h2>
+<p>1. Apply the llvm.codegen intrinsic patch to LLVM code base.</p>
+<pre>cd /path/to/llvm/source
+git am /path/to/polly/source/utils/0001-Add-llvm.codegen-intrinsic.patch</pre>
+<p>2. Build the test case.</p>
+<pre>/path/to/polly/source/test/create_ll.sh test.c</pre>
+<p>3. Get and edit the jscop file (take function "gpu_codegen" as an example).
+</p>
+<pre>opt -load /path/to/polly/build/lib/LLVMPolly.so -basicaa
+    -polly-export-jscop ./test.ll
+cp gpu_codegen___%for.cond---%for.end8.jscop
+   gpu_codegen___%for.cond---%for.end8.jscop.transformed+gpu
+vi gpu_codegen___%for.cond---%for.end8.jscop.transformed+gpu</pre>
+<p><em>(Please refer to section "The Work Flow" on how to edit the "schedule"
+       part of a statement)</em></p>
+<p>4. Optimize the code with GPGPU code generation.</p>
+<pre>opt -load /path/to/polly/build/lib/LLVMPolly.so -basicaa
+    -polly-import-jscop-postfix=transformed+gpu -enable-polly-gpgpu
+    -polly-gpgpu-triple=nvptx64-unknown-unknown -polly-codegen ./test.ll -S
+    -o test.gpued.ll</pre>
+<p>5. Build the final assembly and executable.</p>
+<pre>llc test.gpued.ll -o test.s
+gcc test.s -lGPURuntime -o test</pre>
+<p><em>(Please make sure that LD_LIBRARY_PATH is set properly so that
+        /path/to/polly/build/lib/libGPURuntime.so is visible to gcc.)</em></p>
+<h2>TODO List</h2>
+
+<table class="wikitable" cellpadding="2">
+<tbody>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Tasks</th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left">Tiling the Parallel Loops with An External Jscop File</th>
+<td align="center" class='open'>Open, In Design</td>
+<td>Yabin Hu</td>
+</tr>
+<tr>
+<th align="left">GPU Runtime Library Implementation</th>
+<td align="center" class='inprogress'>Coding Finished, In Reviewing</td>
+<td></td>
+</tr>
+<tr>
+<th align="left">llvm.codegen Intrinsic Implementation</th>
+<td align="center" class='inprogress'>Codeing Finished, To Be Reviewed</td>
+<td></td>
+</tr>
+<tr>
+<th align="left">Code Generation For Host</th>
+<td align="center" class='inprogress'>50% Done</td>
+<td></td>
+</tr>
+
+</tbody></table>
+
+<h2>References</h2>
+<li type="1" value="1">
+<em>Automatic C-to-CUDA Code Generation for Affine Programs. </em><br />
+    Muthu Manikandan Baskaran, J. Ramanujam and P. Sadayappan.<br />
+    International Conference on Compiler Construction (CC) 2010.<br />
+</li>
+<li type="1"><em>PPCG Project</em><br />
+<a href="http://freecode.com/projects/ppcg">http://freecode.com/projects/ppcg
+</a></li>
+<li type="1">
+<em>Where is the Data? Why You Cannot Debate GPU vs. CPU Performance Without the
+    Answer. </em><br />
+  Chris Gregg and Kim Hazelwood<br />
+  International Symposium on Performance Analysis of Systems and Software
+  (ISPASS) 2011.
+</li>
+<p></p>
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/documentation/passes.html b/final/www/documentation/passes.html
new file mode 100644
index 0000000..a6f735b
--- /dev/null
+++ b/final/www/documentation/passes.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+          "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+  <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Polly - The available LLVM passes</title>
+  <link type="text/css" rel="stylesheet" href="../menu.css">
+  <link type="text/css" rel="stylesheet" href="../content.css">
+</head>
+<body>
+<div id="box">
+<!--#include virtual="../menu.html.incl"-->
+<div id="content">
+  <!--*********************************************************************-->
+  <h1>The available LLVM passes</h1>
+  <!--*********************************************************************-->
+
+  <p>Polly consists of a set of LLVM passes.  </p>
+
+<h2>Front End</h2>
+<ul>
+<li><em>polly-canonicalize</em> Prepare code for Polly</li>
+<li><em>polly-detect</em> Detect SCoPs in functions</li>
+<li><em>polly-scops</em> Create polyhedral description of SCoPs</li>
+</ul>
+<h2>Middle End</h2>
+<ul>
+<li><em>polly-dependences</em> Calculate the dependences in a SCoPs</li>
+<li><em>polly-opt-isl</em> Optimize the SCoP using isl</li>
+<li>Import/Export
+<ul>
+<li><em>polly-export-jscop</em> Export SCoPs as JSON
+(Writes a .jscop file for each SCoP)</li>
+<li><em>polly-import-jscop</em> Import SCoPs from JSON
+(Reads a .jscop file for each SCoP)</li>
+</ul>
+</li>
+<li>Graphviz
+<ul>
+<li><em>dot-scops</em> Print SCoPs of function</li>
+<li><em>dot-scops-only</em> Print SCoPs of function (without function bodies)</li>
+<li><em>view-scops</em> View SCoPs of function</li>
+<li><em>view-scops-only</em> View SCoPs of function (without function bodies)</li>
+</ul></li>
+</ul>
+<h2>Back End</h2>
+<ul>
+<li><em>polly-ast</em> Execute isl code generation</li>
+<li><em>polly-codegen</em> Create LLVM-IR from the polyhedral information</li>
+</ul>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/experiments/matmul/matmul.c b/final/www/experiments/matmul/matmul.c
new file mode 100644
index 0000000..49fffc8
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+
+#define N 1536
+float A[N][N];
+float B[N][N];
+float C[N][N];
+
+void init_array()
+{
+    int i, j;
+
+    for (i = 0; i < N; i++) {
+        for (j = 0; j < N; j++) {
+            A[i][j] = (1+(i*j)%1024)/2.0;
+            B[i][j] = (1+(i*j)%1024)/2.0;
+        }
+    }
+}
+
+void print_array()
+{
+    int i, j;
+
+    for (i = 0; i < N; i++) {
+        for (j = 0; j < N; j++) {
+            fprintf(stdout, "%lf ", C[i][j]);
+            if (j%80 == 79) fprintf(stdout, "\n");
+        }
+        fprintf(stdout, "\n");
+    }
+}
+
+int main()
+{
+    int i, j, k;
+    double t_start, t_end;
+
+    init_array();
+
+    for (i = 0; i < N; i++) {
+        for (j = 0; j < N; j++) {
+            C[i][j] = 0;
+            for (k = 0; k < N; k++)
+                C[i][j] = C[i][j] + A[i][k] * B[k][j];
+        }
+    }
+
+#ifdef TEST
+    print_array();
+#endif
+    return 0;
+}
diff --git a/final/www/experiments/matmul/matmul.normalopt.exe b/final/www/experiments/matmul/matmul.normalopt.exe
new file mode 100755
index 0000000..cdb9e67
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.normalopt.exe
Binary files differ
diff --git a/final/www/experiments/matmul/matmul.normalopt.ll b/final/www/experiments/matmul/matmul.normalopt.ll
new file mode 100644
index 0000000..ba792c2
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.normalopt.ll
Binary files differ
diff --git a/final/www/experiments/matmul/matmul.normalopt.s b/final/www/experiments/matmul/matmul.normalopt.s
new file mode 100644
index 0000000..079af70
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.normalopt.s
@@ -0,0 +1,274 @@
+	.file	"matmul.normalopt.ll"
+	.section	.rodata.cst8,"aM",@progbits,8
+	.align	8
+.LCPI0_0:
+	.quad	4602678819172646912     # double 0.5
+	.text
+	.globl	init_array
+	.align	16, 0x90
+	.type	init_array,@function
+init_array:                             # @init_array
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp2:
+	.cfi_def_cfa_offset 16
+.Ltmp3:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp4:
+	.cfi_def_cfa_register %rbp
+	xorl	%r8d, %r8d
+	vmovsd	.LCPI0_0(%rip), %xmm0
+	.align	16, 0x90
+.LBB0_1:                                # %for.cond1.preheader
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB0_2 Depth 2
+	xorl	%ecx, %ecx
+	.align	16, 0x90
+.LBB0_2:                                # %for.body3
+                                        #   Parent Loop BB0_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	movl	%ecx, %edx
+	imull	%r8d, %edx
+	movl	%edx, %esi
+	sarl	$31, %esi
+	shrl	$22, %esi
+	addl	%edx, %esi
+	andl	$-1024, %esi            # imm = 0xFFFFFFFFFFFFFC00
+	negl	%esi
+	movq	%r8, %rax
+	shlq	$11, %rax
+	leal	1(%rdx,%rsi), %edi
+	leaq	(%rax,%rax,2), %rsi
+	leaq	1(%rcx), %rdx
+	cmpq	$1536, %rdx             # imm = 0x600
+	vcvtsi2sdl	%edi, %xmm0, %xmm1
+	vmulsd	%xmm0, %xmm1, %xmm1
+	vcvtsd2ss	%xmm1, %xmm1, %xmm1
+	vmovss	%xmm1, A(%rsi,%rcx,4)
+	vmovss	%xmm1, B(%rsi,%rcx,4)
+	movq	%rdx, %rcx
+	jne	.LBB0_2
+# BB#3:                                 # %for.inc17
+                                        #   in Loop: Header=BB0_1 Depth=1
+	incq	%r8
+	cmpq	$1536, %r8              # imm = 0x600
+	jne	.LBB0_1
+# BB#4:                                 # %for.end19
+	popq	%rbp
+	ret
+.Ltmp5:
+	.size	init_array, .Ltmp5-init_array
+	.cfi_endproc
+
+	.globl	print_array
+	.align	16, 0x90
+	.type	print_array,@function
+print_array:                            # @print_array
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp9:
+	.cfi_def_cfa_offset 16
+.Ltmp10:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp11:
+	.cfi_def_cfa_register %rbp
+	pushq	%r15
+	pushq	%r14
+	pushq	%r12
+	pushq	%rbx
+.Ltmp12:
+	.cfi_offset %rbx, -48
+.Ltmp13:
+	.cfi_offset %r12, -40
+.Ltmp14:
+	.cfi_offset %r14, -32
+.Ltmp15:
+	.cfi_offset %r15, -24
+	xorl	%r14d, %r14d
+	movl	$C, %r15d
+	.align	16, 0x90
+.LBB1_1:                                # %for.cond1.preheader
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB1_2 Depth 2
+	movq	stdout(%rip), %rax
+	movq	%r15, %r12
+	xorl	%ebx, %ebx
+	.align	16, 0x90
+.LBB1_2:                                # %for.body3
+                                        #   Parent Loop BB1_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	vmovss	(%r12), %xmm0
+	vcvtss2sd	%xmm0, %xmm0, %xmm0
+	movq	%rax, %rdi
+	movl	$.L.str, %esi
+	movb	$1, %al
+	callq	fprintf
+	movslq	%ebx, %rax
+	imulq	$1717986919, %rax, %rcx # imm = 0x66666667
+	movq	%rcx, %rdx
+	shrq	$63, %rdx
+	sarq	$37, %rcx
+	addl	%edx, %ecx
+	imull	$80, %ecx, %ecx
+	subl	%ecx, %eax
+	cmpl	$79, %eax
+	jne	.LBB1_4
+# BB#3:                                 # %if.then
+                                        #   in Loop: Header=BB1_2 Depth=2
+	movq	stdout(%rip), %rsi
+	movl	$10, %edi
+	callq	fputc
+.LBB1_4:                                # %for.inc
+                                        #   in Loop: Header=BB1_2 Depth=2
+	addq	$4, %r12
+	incq	%rbx
+	movq	stdout(%rip), %rax
+	cmpq	$1536, %rbx             # imm = 0x600
+	jne	.LBB1_2
+# BB#5:                                 # %for.end
+                                        #   in Loop: Header=BB1_1 Depth=1
+	movl	$10, %edi
+	movq	%rax, %rsi
+	callq	fputc
+	addq	$6144, %r15             # imm = 0x1800
+	incq	%r14
+	cmpq	$1536, %r14             # imm = 0x600
+	jne	.LBB1_1
+# BB#6:                                 # %for.end12
+	popq	%rbx
+	popq	%r12
+	popq	%r14
+	popq	%r15
+	popq	%rbp
+	ret
+.Ltmp16:
+	.size	print_array, .Ltmp16-print_array
+	.cfi_endproc
+
+	.section	.rodata.cst8,"aM",@progbits,8
+	.align	8
+.LCPI2_0:
+	.quad	4602678819172646912     # double 0.5
+	.text
+	.globl	main
+	.align	16, 0x90
+	.type	main,@function
+main:                                   # @main
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp19:
+	.cfi_def_cfa_offset 16
+.Ltmp20:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp21:
+	.cfi_def_cfa_register %rbp
+	xorl	%r8d, %r8d
+	vmovsd	.LCPI2_0(%rip), %xmm0
+	.align	16, 0x90
+.LBB2_1:                                # %for.cond1.preheader.i
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB2_2 Depth 2
+	xorl	%ecx, %ecx
+	.align	16, 0x90
+.LBB2_2:                                # %for.body3.i
+                                        #   Parent Loop BB2_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	movl	%ecx, %edx
+	imull	%r8d, %edx
+	movl	%edx, %esi
+	sarl	$31, %esi
+	shrl	$22, %esi
+	addl	%edx, %esi
+	andl	$-1024, %esi            # imm = 0xFFFFFFFFFFFFFC00
+	negl	%esi
+	movq	%r8, %rax
+	shlq	$11, %rax
+	leal	1(%rdx,%rsi), %edi
+	leaq	(%rax,%rax,2), %rsi
+	leaq	1(%rcx), %rdx
+	cmpq	$1536, %rdx             # imm = 0x600
+	vcvtsi2sdl	%edi, %xmm0, %xmm1
+	vmulsd	%xmm0, %xmm1, %xmm1
+	vcvtsd2ss	%xmm1, %xmm1, %xmm1
+	vmovss	%xmm1, A(%rsi,%rcx,4)
+	vmovss	%xmm1, B(%rsi,%rcx,4)
+	movq	%rdx, %rcx
+	jne	.LBB2_2
+# BB#3:                                 # %for.inc17.i
+                                        #   in Loop: Header=BB2_1 Depth=1
+	incq	%r8
+	cmpq	$1536, %r8              # imm = 0x600
+	jne	.LBB2_1
+# BB#4:
+	xorl	%r8d, %r8d
+	movl	$A, %r9d
+	.align	16, 0x90
+.LBB2_5:                                # %for.cond1.preheader
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB2_6 Depth 2
+                                        #       Child Loop BB2_7 Depth 3
+	leaq	(%r8,%r8,2), %rdx
+	shlq	$11, %rdx
+	leaq	C(%rdx), %rsi
+	xorl	%edi, %edi
+	.align	16, 0x90
+.LBB2_6:                                # %for.body3
+                                        #   Parent Loop BB2_5 Depth=1
+                                        # =>  This Loop Header: Depth=2
+                                        #       Child Loop BB2_7 Depth 3
+	movl	$0, (%rsi)
+	vxorps	%xmm0, %xmm0, %xmm0
+	movq	$-9437184, %rax         # imm = 0xFFFFFFFFFF700000
+	movq	%r9, %rcx
+	.align	16, 0x90
+.LBB2_7:                                # %for.body8
+                                        #   Parent Loop BB2_5 Depth=1
+                                        #     Parent Loop BB2_6 Depth=2
+                                        # =>    This Inner Loop Header: Depth=3
+	vmovss	(%rcx), %xmm1
+	vmulss	B+9437184(%rax,%rdi,4), %xmm1, %xmm1
+	vaddss	%xmm1, %xmm0, %xmm0
+	addq	$4, %rcx
+	addq	$6144, %rax             # imm = 0x1800
+	jne	.LBB2_7
+# BB#8:                                 # %for.inc25
+                                        #   in Loop: Header=BB2_6 Depth=2
+	vmovss	%xmm0, (%rsi)
+	leaq	C+4(%rdx,%rdi,4), %rsi
+	incq	%rdi
+	cmpq	$1536, %rdi             # imm = 0x600
+	jne	.LBB2_6
+# BB#9:                                 # %for.inc28
+                                        #   in Loop: Header=BB2_5 Depth=1
+	addq	$6144, %r9              # imm = 0x1800
+	incq	%r8
+	cmpq	$1536, %r8              # imm = 0x600
+	jne	.LBB2_5
+# BB#10:                                # %for.end30
+	xorl	%eax, %eax
+	popq	%rbp
+	ret
+.Ltmp22:
+	.size	main, .Ltmp22-main
+	.cfi_endproc
+
+	.type	A,@object               # @A
+	.comm	A,9437184,16
+	.type	B,@object               # @B
+	.comm	B,9437184,16
+	.type	.L.str,@object          # @.str
+	.section	.rodata.str1.1,"aMS",@progbits,1
+.L.str:
+	.asciz	 "%lf "
+	.size	.L.str, 5
+
+	.type	C,@object               # @C
+	.comm	C,9437184,16
+
+	.section	".note.GNU-stack","",@progbits
diff --git a/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector+openmp.exe b/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector+openmp.exe
new file mode 100755
index 0000000..feb2436
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector+openmp.exe
Binary files differ
diff --git a/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector+openmp.ll b/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector+openmp.ll
new file mode 100644
index 0000000..593794e
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector+openmp.ll
Binary files differ
diff --git a/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector+openmp.s b/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector+openmp.s
new file mode 100644
index 0000000..ca87de1
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector+openmp.s
@@ -0,0 +1,754 @@
+	.file	"matmul.polly.interchanged+tiled+vector+openmp.ll"
+	.section	.rodata.cst8,"aM",@progbits,8
+	.align	8
+.LCPI0_0:
+	.quad	4602678819172646912     # double 0.5
+	.text
+	.globl	init_array
+	.align	16, 0x90
+	.type	init_array,@function
+init_array:                             # @init_array
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp3:
+	.cfi_def_cfa_offset 16
+.Ltmp4:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp5:
+	.cfi_def_cfa_register %rbp
+	pushq	%r15
+	pushq	%r14
+	pushq	%rbx
+	subq	$24, %rsp
+.Ltmp6:
+	.cfi_offset %rbx, -40
+.Ltmp7:
+	.cfi_offset %r14, -32
+.Ltmp8:
+	.cfi_offset %r15, -24
+	leaq	-32(%rbp), %rsi
+	movl	$init_array.omp_subfn, %edi
+	xorl	%edx, %edx
+	xorl	%ecx, %ecx
+	movl	$1536, %r8d             # imm = 0x600
+	movl	$1, %r9d
+	callq	GOMP_parallel_loop_runtime_start
+	leaq	-40(%rbp), %rdi
+	leaq	-48(%rbp), %rsi
+	callq	GOMP_loop_runtime_next
+	testb	%al, %al
+	je	.LBB0_4
+# BB#1:
+	leaq	-40(%rbp), %r14
+	leaq	-48(%rbp), %r15
+	vmovsd	.LCPI0_0(%rip), %xmm1
+	.align	16, 0x90
+.LBB0_2:                                # %omp.loadIVBounds.i
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB0_8 Depth 2
+                                        #       Child Loop BB0_5 Depth 3
+	movq	-48(%rbp), %r8
+	leaq	-1(%r8), %rcx
+	movq	-40(%rbp), %rax
+	cmpq	%rcx, %rax
+	jg	.LBB0_3
+# BB#7:                                 # %polly.loop_preheader4.preheader.i
+                                        #   in Loop: Header=BB0_2 Depth=1
+	addq	$-2, %r8
+	.align	16, 0x90
+.LBB0_8:                                # %polly.loop_preheader4.i
+                                        #   Parent Loop BB0_2 Depth=1
+                                        # =>  This Loop Header: Depth=2
+                                        #       Child Loop BB0_5 Depth 3
+	xorl	%edx, %edx
+	.align	16, 0x90
+.LBB0_5:                                # %polly.loop_header3.i
+                                        #   Parent Loop BB0_2 Depth=1
+                                        #     Parent Loop BB0_8 Depth=2
+                                        # =>    This Inner Loop Header: Depth=3
+	movl	%edx, %esi
+	imull	%eax, %esi
+	movl	%esi, %edi
+	sarl	$31, %edi
+	shrl	$22, %edi
+	addl	%esi, %edi
+	andl	$-1024, %edi            # imm = 0xFFFFFFFFFFFFFC00
+	negl	%edi
+	movq	%rax, %rcx
+	shlq	$11, %rcx
+	leal	1(%rsi,%rdi), %ebx
+	leaq	(%rcx,%rcx,2), %rdi
+	leaq	1(%rdx), %rsi
+	cmpq	$1536, %rsi             # imm = 0x600
+	vcvtsi2sdl	%ebx, %xmm0, %xmm0
+	vmulsd	%xmm1, %xmm0, %xmm0
+	vcvtsd2ss	%xmm0, %xmm0, %xmm0
+	vmovss	%xmm0, A(%rdi,%rdx,4)
+	vmovss	%xmm0, B(%rdi,%rdx,4)
+	movq	%rsi, %rdx
+	jne	.LBB0_5
+# BB#6:                                 # %polly.loop_exit5.i
+                                        #   in Loop: Header=BB0_8 Depth=2
+	cmpq	%r8, %rax
+	leaq	1(%rax), %rax
+	jle	.LBB0_8
+.LBB0_3:                                # %omp.checkNext.backedge.i
+                                        #   in Loop: Header=BB0_2 Depth=1
+	movq	%r14, %rdi
+	movq	%r15, %rsi
+	callq	GOMP_loop_runtime_next
+	vmovsd	.LCPI0_0(%rip), %xmm1
+	testb	%al, %al
+	jne	.LBB0_2
+.LBB0_4:                                # %init_array.omp_subfn.exit
+	callq	GOMP_loop_end_nowait
+	callq	GOMP_parallel_end
+	addq	$24, %rsp
+	popq	%rbx
+	popq	%r14
+	popq	%r15
+	popq	%rbp
+	ret
+.Ltmp9:
+	.size	init_array, .Ltmp9-init_array
+	.cfi_endproc
+
+	.globl	print_array
+	.align	16, 0x90
+	.type	print_array,@function
+print_array:                            # @print_array
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp13:
+	.cfi_def_cfa_offset 16
+.Ltmp14:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp15:
+	.cfi_def_cfa_register %rbp
+	pushq	%r15
+	pushq	%r14
+	pushq	%r12
+	pushq	%rbx
+.Ltmp16:
+	.cfi_offset %rbx, -48
+.Ltmp17:
+	.cfi_offset %r12, -40
+.Ltmp18:
+	.cfi_offset %r14, -32
+.Ltmp19:
+	.cfi_offset %r15, -24
+	xorl	%r14d, %r14d
+	movl	$C, %r15d
+	.align	16, 0x90
+.LBB1_1:                                # %for.cond1.preheader
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB1_2 Depth 2
+	movq	stdout(%rip), %rax
+	movq	%r15, %r12
+	xorl	%ebx, %ebx
+	.align	16, 0x90
+.LBB1_2:                                # %for.body3
+                                        #   Parent Loop BB1_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	vmovss	(%r12), %xmm0
+	vcvtss2sd	%xmm0, %xmm0, %xmm0
+	movq	%rax, %rdi
+	movl	$.L.str, %esi
+	movb	$1, %al
+	callq	fprintf
+	movslq	%ebx, %rax
+	imulq	$1717986919, %rax, %rcx # imm = 0x66666667
+	movq	%rcx, %rdx
+	shrq	$63, %rdx
+	sarq	$37, %rcx
+	addl	%edx, %ecx
+	imull	$80, %ecx, %ecx
+	subl	%ecx, %eax
+	cmpl	$79, %eax
+	jne	.LBB1_4
+# BB#3:                                 # %if.then
+                                        #   in Loop: Header=BB1_2 Depth=2
+	movq	stdout(%rip), %rsi
+	movl	$10, %edi
+	callq	fputc
+.LBB1_4:                                # %for.inc
+                                        #   in Loop: Header=BB1_2 Depth=2
+	addq	$4, %r12
+	incq	%rbx
+	movq	stdout(%rip), %rax
+	cmpq	$1536, %rbx             # imm = 0x600
+	jne	.LBB1_2
+# BB#5:                                 # %for.end
+                                        #   in Loop: Header=BB1_1 Depth=1
+	movl	$10, %edi
+	movq	%rax, %rsi
+	callq	fputc
+	addq	$6144, %r15             # imm = 0x1800
+	incq	%r14
+	cmpq	$1536, %r14             # imm = 0x600
+	jne	.LBB1_1
+# BB#6:                                 # %for.end12
+	popq	%rbx
+	popq	%r12
+	popq	%r14
+	popq	%r15
+	popq	%rbp
+	ret
+.Ltmp20:
+	.size	print_array, .Ltmp20-print_array
+	.cfi_endproc
+
+	.globl	main
+	.align	16, 0x90
+	.type	main,@function
+main:                                   # @main
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp24:
+	.cfi_def_cfa_offset 16
+.Ltmp25:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp26:
+	.cfi_def_cfa_register %rbp
+	pushq	%r15
+	pushq	%r14
+	pushq	%r13
+	pushq	%r12
+	pushq	%rbx
+	subq	$24, %rsp
+.Ltmp27:
+	.cfi_offset %rbx, -56
+.Ltmp28:
+	.cfi_offset %r12, -48
+.Ltmp29:
+	.cfi_offset %r13, -40
+.Ltmp30:
+	.cfi_offset %r14, -32
+.Ltmp31:
+	.cfi_offset %r15, -24
+	callq	init_array
+	leaq	-48(%rbp), %rsi
+	movl	$main.omp_subfn, %edi
+	xorl	%edx, %edx
+	xorl	%ecx, %ecx
+	movl	$1536, %r8d             # imm = 0x600
+	movl	$1, %r9d
+	callq	GOMP_parallel_loop_runtime_start
+	leaq	-56(%rbp), %rdi
+	leaq	-64(%rbp), %rsi
+	callq	GOMP_loop_runtime_next
+	testb	%al, %al
+	je	.LBB2_4
+# BB#1:
+	leaq	-56(%rbp), %r14
+	leaq	-64(%rbp), %r15
+	.align	16, 0x90
+.LBB2_2:                                # %omp.loadIVBounds.i
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB2_6 Depth 2
+	movq	-64(%rbp), %r12
+	leaq	-1(%r12), %rcx
+	movq	-56(%rbp), %rax
+	cmpq	%rcx, %rax
+	jg	.LBB2_3
+# BB#5:                                 # %polly.loop_preheader4.preheader.i
+                                        #   in Loop: Header=BB2_2 Depth=1
+	addq	$-2, %r12
+	leaq	(%rax,%rax,2), %rcx
+	leaq	-1(%rax), %r13
+	shlq	$11, %rcx
+	leaq	C(%rcx), %rbx
+	.align	16, 0x90
+.LBB2_6:                                # %polly.loop_preheader4.i
+                                        #   Parent Loop BB2_2 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	movq	%rbx, %rdi
+	xorl	%esi, %esi
+	movl	$6144, %edx             # imm = 0x1800
+	callq	memset
+	addq	$6144, %rbx             # imm = 0x1800
+	incq	%r13
+	cmpq	%r12, %r13
+	jle	.LBB2_6
+.LBB2_3:                                # %omp.checkNext.backedge.i
+                                        #   in Loop: Header=BB2_2 Depth=1
+	movq	%r14, %rdi
+	movq	%r15, %rsi
+	callq	GOMP_loop_runtime_next
+	testb	%al, %al
+	jne	.LBB2_2
+.LBB2_4:                                # %main.omp_subfn.exit
+	callq	GOMP_loop_end_nowait
+	callq	GOMP_parallel_end
+	leaq	-48(%rbp), %rbx
+	movl	$main.omp_subfn1, %edi
+	movq	%rbx, %rsi
+	xorl	%edx, %edx
+	xorl	%ecx, %ecx
+	movl	$1536, %r8d             # imm = 0x600
+	movl	$64, %r9d
+	callq	GOMP_parallel_loop_runtime_start
+	movq	%rbx, %rdi
+	callq	main.omp_subfn1
+	callq	GOMP_parallel_end
+	xorl	%eax, %eax
+	addq	$24, %rsp
+	popq	%rbx
+	popq	%r12
+	popq	%r13
+	popq	%r14
+	popq	%r15
+	popq	%rbp
+	ret
+.Ltmp32:
+	.size	main, .Ltmp32-main
+	.cfi_endproc
+
+	.section	.rodata.cst8,"aM",@progbits,8
+	.align	8
+.LCPI3_0:
+	.quad	4602678819172646912     # double 0.5
+	.text
+	.align	16, 0x90
+	.type	init_array.omp_subfn,@function
+init_array.omp_subfn:                   # @init_array.omp_subfn
+	.cfi_startproc
+# BB#0:                                 # %omp.setup
+	pushq	%rbp
+.Ltmp36:
+	.cfi_def_cfa_offset 16
+.Ltmp37:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp38:
+	.cfi_def_cfa_register %rbp
+	pushq	%r15
+	pushq	%r14
+	pushq	%rbx
+	subq	$24, %rsp
+.Ltmp39:
+	.cfi_offset %rbx, -40
+.Ltmp40:
+	.cfi_offset %r14, -32
+.Ltmp41:
+	.cfi_offset %r15, -24
+	leaq	-32(%rbp), %rdi
+	leaq	-40(%rbp), %rsi
+	callq	GOMP_loop_runtime_next
+	testb	%al, %al
+	je	.LBB3_4
+# BB#1:
+	leaq	-32(%rbp), %r14
+	leaq	-40(%rbp), %r15
+	vmovsd	.LCPI3_0(%rip), %xmm1
+	.align	16, 0x90
+.LBB3_2:                                # %omp.loadIVBounds
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB3_8 Depth 2
+                                        #       Child Loop BB3_5 Depth 3
+	movq	-40(%rbp), %r8
+	leaq	-1(%r8), %rcx
+	movq	-32(%rbp), %rax
+	cmpq	%rcx, %rax
+	jg	.LBB3_3
+# BB#7:                                 # %polly.loop_preheader4.preheader
+                                        #   in Loop: Header=BB3_2 Depth=1
+	addq	$-2, %r8
+	.align	16, 0x90
+.LBB3_8:                                # %polly.loop_preheader4
+                                        #   Parent Loop BB3_2 Depth=1
+                                        # =>  This Loop Header: Depth=2
+                                        #       Child Loop BB3_5 Depth 3
+	xorl	%edx, %edx
+	.align	16, 0x90
+.LBB3_5:                                # %polly.loop_header3
+                                        #   Parent Loop BB3_2 Depth=1
+                                        #     Parent Loop BB3_8 Depth=2
+                                        # =>    This Inner Loop Header: Depth=3
+	movl	%edx, %esi
+	imull	%eax, %esi
+	movl	%esi, %edi
+	sarl	$31, %edi
+	shrl	$22, %edi
+	addl	%esi, %edi
+	andl	$-1024, %edi            # imm = 0xFFFFFFFFFFFFFC00
+	negl	%edi
+	movq	%rax, %rcx
+	shlq	$11, %rcx
+	leal	1(%rsi,%rdi), %ebx
+	leaq	(%rcx,%rcx,2), %rdi
+	leaq	1(%rdx), %rsi
+	cmpq	$1536, %rsi             # imm = 0x600
+	vcvtsi2sdl	%ebx, %xmm0, %xmm0
+	vmulsd	%xmm1, %xmm0, %xmm0
+	vcvtsd2ss	%xmm0, %xmm0, %xmm0
+	vmovss	%xmm0, A(%rdi,%rdx,4)
+	vmovss	%xmm0, B(%rdi,%rdx,4)
+	movq	%rsi, %rdx
+	jne	.LBB3_5
+# BB#6:                                 # %polly.loop_exit5
+                                        #   in Loop: Header=BB3_8 Depth=2
+	cmpq	%r8, %rax
+	leaq	1(%rax), %rax
+	jle	.LBB3_8
+.LBB3_3:                                # %omp.checkNext.backedge
+                                        #   in Loop: Header=BB3_2 Depth=1
+	movq	%r14, %rdi
+	movq	%r15, %rsi
+	callq	GOMP_loop_runtime_next
+	vmovsd	.LCPI3_0(%rip), %xmm1
+	testb	%al, %al
+	jne	.LBB3_2
+.LBB3_4:                                # %omp.exit
+	callq	GOMP_loop_end_nowait
+	addq	$24, %rsp
+	popq	%rbx
+	popq	%r14
+	popq	%r15
+	popq	%rbp
+	ret
+.Ltmp42:
+	.size	init_array.omp_subfn, .Ltmp42-init_array.omp_subfn
+	.cfi_endproc
+
+	.align	16, 0x90
+	.type	main.omp_subfn,@function
+main.omp_subfn:                         # @main.omp_subfn
+	.cfi_startproc
+# BB#0:                                 # %omp.setup
+	pushq	%rbp
+.Ltmp46:
+	.cfi_def_cfa_offset 16
+.Ltmp47:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp48:
+	.cfi_def_cfa_register %rbp
+	pushq	%r15
+	pushq	%r14
+	pushq	%r13
+	pushq	%r12
+	pushq	%rbx
+	subq	$24, %rsp
+.Ltmp49:
+	.cfi_offset %rbx, -56
+.Ltmp50:
+	.cfi_offset %r12, -48
+.Ltmp51:
+	.cfi_offset %r13, -40
+.Ltmp52:
+	.cfi_offset %r14, -32
+.Ltmp53:
+	.cfi_offset %r15, -24
+	leaq	-48(%rbp), %rdi
+	leaq	-56(%rbp), %rsi
+	callq	GOMP_loop_runtime_next
+	testb	%al, %al
+	je	.LBB4_4
+# BB#1:
+	leaq	-48(%rbp), %r14
+	leaq	-56(%rbp), %r15
+	.align	16, 0x90
+.LBB4_2:                                # %omp.loadIVBounds
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB4_6 Depth 2
+	movq	-56(%rbp), %r12
+	leaq	-1(%r12), %rcx
+	movq	-48(%rbp), %rax
+	cmpq	%rcx, %rax
+	jg	.LBB4_3
+# BB#5:                                 # %polly.loop_preheader4.preheader
+                                        #   in Loop: Header=BB4_2 Depth=1
+	addq	$-2, %r12
+	leaq	(%rax,%rax,2), %rcx
+	leaq	-1(%rax), %r13
+	shlq	$11, %rcx
+	leaq	C(%rcx), %rbx
+	.align	16, 0x90
+.LBB4_6:                                # %polly.loop_preheader4
+                                        #   Parent Loop BB4_2 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	movq	%rbx, %rdi
+	xorl	%esi, %esi
+	movl	$6144, %edx             # imm = 0x1800
+	callq	memset
+	addq	$6144, %rbx             # imm = 0x1800
+	incq	%r13
+	cmpq	%r12, %r13
+	jle	.LBB4_6
+.LBB4_3:                                # %omp.checkNext.backedge
+                                        #   in Loop: Header=BB4_2 Depth=1
+	movq	%r14, %rdi
+	movq	%r15, %rsi
+	callq	GOMP_loop_runtime_next
+	testb	%al, %al
+	jne	.LBB4_2
+.LBB4_4:                                # %omp.exit
+	callq	GOMP_loop_end_nowait
+	addq	$24, %rsp
+	popq	%rbx
+	popq	%r12
+	popq	%r13
+	popq	%r14
+	popq	%r15
+	popq	%rbp
+	ret
+.Ltmp54:
+	.size	main.omp_subfn, .Ltmp54-main.omp_subfn
+	.cfi_endproc
+
+	.align	16, 0x90
+	.type	main.omp_subfn1,@function
+main.omp_subfn1:                        # @main.omp_subfn1
+	.cfi_startproc
+# BB#0:                                 # %omp.setup
+	pushq	%rbp
+.Ltmp58:
+	.cfi_def_cfa_offset 16
+.Ltmp59:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp60:
+	.cfi_def_cfa_register %rbp
+	pushq	%r15
+	pushq	%r14
+	pushq	%r13
+	pushq	%r12
+	pushq	%rbx
+	subq	$72, %rsp
+.Ltmp61:
+	.cfi_offset %rbx, -56
+.Ltmp62:
+	.cfi_offset %r12, -48
+.Ltmp63:
+	.cfi_offset %r13, -40
+.Ltmp64:
+	.cfi_offset %r14, -32
+.Ltmp65:
+	.cfi_offset %r15, -24
+	jmp	.LBB5_1
+	.align	16, 0x90
+.LBB5_2:                                # %omp.loadIVBounds
+                                        #   in Loop: Header=BB5_1 Depth=1
+	movq	-56(%rbp), %rax
+	movq	%rax, -112(%rbp)        # 8-byte Spill
+	leaq	-1(%rax), %rax
+	movq	-48(%rbp), %rcx
+	cmpq	%rax, %rcx
+	jg	.LBB5_1
+# BB#3:                                 # %polly.loop_preheader4.preheader
+                                        #   in Loop: Header=BB5_1 Depth=1
+	leaq	-1(%rcx), %rax
+	movq	%rax, -88(%rbp)         # 8-byte Spill
+	addq	$-65, -112(%rbp)        # 8-byte Folded Spill
+	movq	%rcx, %rax
+	shlq	$9, %rax
+	leaq	(%rax,%rax,2), %rax
+	leaq	C+16(,%rax,4), %rax
+	movq	%rax, -104(%rbp)        # 8-byte Spill
+	.align	16, 0x90
+.LBB5_7:                                # %polly.loop_preheader4
+                                        #   Parent Loop BB5_1 Depth=1
+                                        # =>  This Loop Header: Depth=2
+                                        #       Child Loop BB5_8 Depth 3
+                                        #         Child Loop BB5_9 Depth 4
+                                        #           Child Loop BB5_12 Depth 5
+                                        #             Child Loop BB5_17 Depth 6
+                                        #               Child Loop BB5_18 Depth 7
+                                        #           Child Loop BB5_14 Depth 5
+	movq	%rcx, -72(%rbp)         # 8-byte Spill
+	leaq	62(%rcx), %rdi
+	xorl	%edx, %edx
+	.align	16, 0x90
+.LBB5_8:                                # %polly.loop_preheader11
+                                        #   Parent Loop BB5_1 Depth=1
+                                        #     Parent Loop BB5_7 Depth=2
+                                        # =>    This Loop Header: Depth=3
+                                        #         Child Loop BB5_9 Depth 4
+                                        #           Child Loop BB5_12 Depth 5
+                                        #             Child Loop BB5_17 Depth 6
+                                        #               Child Loop BB5_18 Depth 7
+                                        #           Child Loop BB5_14 Depth 5
+	movq	%rdx, -96(%rbp)         # 8-byte Spill
+	leaq	-4(%rdx), %rcx
+	movq	%rdx, %rax
+	decq	%rax
+	cmovsq	%rcx, %rax
+	movq	%rax, %r14
+	sarq	$63, %r14
+	shrq	$62, %r14
+	addq	%rax, %r14
+	andq	$-4, %r14
+	movq	%rdx, %rax
+	orq	$63, %rax
+	leaq	-4(%rax), %rdx
+	movq	-104(%rbp), %rcx        # 8-byte Reload
+	leaq	(%rcx,%r14,4), %rcx
+	movq	%rcx, -80(%rbp)         # 8-byte Spill
+	leaq	B+16(,%r14,4), %rbx
+	leaq	4(%r14), %rcx
+	movq	%rcx, -64(%rbp)         # 8-byte Spill
+	xorl	%r11d, %r11d
+	.align	16, 0x90
+.LBB5_9:                                # %polly.loop_header10
+                                        #   Parent Loop BB5_1 Depth=1
+                                        #     Parent Loop BB5_7 Depth=2
+                                        #       Parent Loop BB5_8 Depth=3
+                                        # =>      This Loop Header: Depth=4
+                                        #           Child Loop BB5_12 Depth 5
+                                        #             Child Loop BB5_17 Depth 6
+                                        #               Child Loop BB5_18 Depth 7
+                                        #           Child Loop BB5_14 Depth 5
+	movabsq	$9223372036854775744, %rcx # imm = 0x7FFFFFFFFFFFFFC0
+	cmpq	%rcx, -72(%rbp)         # 8-byte Folded Reload
+	jg	.LBB5_15
+# BB#10:                                # %polly.loop_header17.preheader
+                                        #   in Loop: Header=BB5_9 Depth=4
+	movq	%r11, %r15
+	orq	$63, %r15
+	cmpq	%r15, %r11
+	movq	-88(%rbp), %rcx         # 8-byte Reload
+	jle	.LBB5_11
+	.align	16, 0x90
+.LBB5_14:                               # %polly.loop_exit28.us
+                                        #   Parent Loop BB5_1 Depth=1
+                                        #     Parent Loop BB5_7 Depth=2
+                                        #       Parent Loop BB5_8 Depth=3
+                                        #         Parent Loop BB5_9 Depth=4
+                                        # =>        This Inner Loop Header: Depth=5
+	incq	%rcx
+	cmpq	%rdi, %rcx
+	jle	.LBB5_14
+	jmp	.LBB5_15
+	.align	16, 0x90
+.LBB5_11:                               #   in Loop: Header=BB5_9 Depth=4
+	decq	%r15
+	movq	-80(%rbp), %r13         # 8-byte Reload
+	movq	-72(%rbp), %rcx         # 8-byte Reload
+	.align	16, 0x90
+.LBB5_12:                               # %polly.loop_header26.preheader
+                                        #   Parent Loop BB5_1 Depth=1
+                                        #     Parent Loop BB5_7 Depth=2
+                                        #       Parent Loop BB5_8 Depth=3
+                                        #         Parent Loop BB5_9 Depth=4
+                                        # =>        This Loop Header: Depth=5
+                                        #             Child Loop BB5_17 Depth 6
+                                        #               Child Loop BB5_18 Depth 7
+	cmpq	%rax, -64(%rbp)         # 8-byte Folded Reload
+	movq	%rbx, %r12
+	movq	%r11, %r8
+	jg	.LBB5_13
+	.align	16, 0x90
+.LBB5_17:                               # %polly.loop_header35.preheader
+                                        #   Parent Loop BB5_1 Depth=1
+                                        #     Parent Loop BB5_7 Depth=2
+                                        #       Parent Loop BB5_8 Depth=3
+                                        #         Parent Loop BB5_9 Depth=4
+                                        #           Parent Loop BB5_12 Depth=5
+                                        # =>          This Loop Header: Depth=6
+                                        #               Child Loop BB5_18 Depth 7
+	leaq	(%rcx,%rcx,2), %rsi
+	shlq	$11, %rsi
+	vbroadcastss	A(%rsi,%r8,4), %xmm0
+	movq	%r13, %r9
+	movq	%r12, %r10
+	movq	%r14, %rsi
+.LBB5_18:                               # %polly.loop_header35
+                                        #   Parent Loop BB5_1 Depth=1
+                                        #     Parent Loop BB5_7 Depth=2
+                                        #       Parent Loop BB5_8 Depth=3
+                                        #         Parent Loop BB5_9 Depth=4
+                                        #           Parent Loop BB5_12 Depth=5
+                                        #             Parent Loop BB5_17 Depth=6
+                                        # =>            This Inner Loop Header: Depth=7
+	vmulps	(%r10), %xmm0, %xmm1
+	vaddps	(%r9), %xmm1, %xmm1
+	vmovaps	%xmm1, (%r9)
+	addq	$16, %r9
+	addq	$16, %r10
+	addq	$4, %rsi
+	cmpq	%rdx, %rsi
+	jle	.LBB5_18
+# BB#16:                                # %polly.loop_exit37
+                                        #   in Loop: Header=BB5_17 Depth=6
+	addq	$6144, %r12             # imm = 0x1800
+	cmpq	%r15, %r8
+	leaq	1(%r8), %r8
+	jle	.LBB5_17
+	.align	16, 0x90
+.LBB5_13:                               # %polly.loop_exit28
+                                        #   in Loop: Header=BB5_12 Depth=5
+	addq	$6144, %r13             # imm = 0x1800
+	cmpq	%rdi, %rcx
+	leaq	1(%rcx), %rcx
+	jle	.LBB5_12
+	.align	16, 0x90
+.LBB5_15:                               # %polly.loop_exit19
+                                        #   in Loop: Header=BB5_9 Depth=4
+	addq	$393216, %rbx           # imm = 0x60000
+	cmpq	$1472, %r11             # imm = 0x5C0
+	leaq	64(%r11), %r11
+	jl	.LBB5_9
+# BB#5:                                 # %polly.loop_exit12
+                                        #   in Loop: Header=BB5_8 Depth=3
+	movq	-96(%rbp), %rdx         # 8-byte Reload
+	cmpq	$1472, %rdx             # imm = 0x5C0
+	leaq	64(%rdx), %rdx
+	jl	.LBB5_8
+# BB#6:                                 # %polly.loop_exit5
+                                        #   in Loop: Header=BB5_7 Depth=2
+	addq	$64, -88(%rbp)          # 8-byte Folded Spill
+	addq	$393216, -104(%rbp)     # 8-byte Folded Spill
+                                        # imm = 0x60000
+	movq	-72(%rbp), %rcx         # 8-byte Reload
+	cmpq	-112(%rbp), %rcx        # 8-byte Folded Reload
+	leaq	64(%rcx), %rcx
+	jle	.LBB5_7
+.LBB5_1:                                # %omp.setup
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB5_7 Depth 2
+                                        #       Child Loop BB5_8 Depth 3
+                                        #         Child Loop BB5_9 Depth 4
+                                        #           Child Loop BB5_12 Depth 5
+                                        #             Child Loop BB5_17 Depth 6
+                                        #               Child Loop BB5_18 Depth 7
+                                        #           Child Loop BB5_14 Depth 5
+	leaq	-48(%rbp), %rdi
+	leaq	-56(%rbp), %rsi
+	callq	GOMP_loop_runtime_next
+	testb	%al, %al
+	jne	.LBB5_2
+# BB#4:                                 # %omp.exit
+	callq	GOMP_loop_end_nowait
+	addq	$72, %rsp
+	popq	%rbx
+	popq	%r12
+	popq	%r13
+	popq	%r14
+	popq	%r15
+	popq	%rbp
+	ret
+.Ltmp66:
+	.size	main.omp_subfn1, .Ltmp66-main.omp_subfn1
+	.cfi_endproc
+
+	.type	A,@object               # @A
+	.comm	A,9437184,16
+	.type	B,@object               # @B
+	.comm	B,9437184,16
+	.type	.L.str,@object          # @.str
+	.section	.rodata.str1.1,"aMS",@progbits,1
+.L.str:
+	.asciz	 "%lf "
+	.size	.L.str, 5
+
+	.type	C,@object               # @C
+	.comm	C,9437184,16
+
+	.section	".note.GNU-stack","",@progbits
diff --git a/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector.exe b/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector.exe
new file mode 100755
index 0000000..36b788e
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector.exe
Binary files differ
diff --git a/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector.ll b/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector.ll
new file mode 100644
index 0000000..9d1f9ad
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector.ll
Binary files differ
diff --git a/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector.s b/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector.s
new file mode 100644
index 0000000..485d230
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.polly.interchanged+tiled+vector.s
@@ -0,0 +1,396 @@
+	.file	"matmul.polly.interchanged+tiled+vector.ll"
+	.section	.rodata.cst8,"aM",@progbits,8
+	.align	8
+.LCPI0_0:
+	.quad	4602678819172646912     # double 0.5
+	.text
+	.globl	init_array
+	.align	16, 0x90
+	.type	init_array,@function
+init_array:                             # @init_array
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp2:
+	.cfi_def_cfa_offset 16
+.Ltmp3:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp4:
+	.cfi_def_cfa_register %rbp
+	xorl	%r8d, %r8d
+	vmovsd	.LCPI0_0(%rip), %xmm0
+	.align	16, 0x90
+.LBB0_1:                                # %polly.loop_preheader3
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB0_2 Depth 2
+	xorl	%ecx, %ecx
+	.align	16, 0x90
+.LBB0_2:                                # %polly.loop_header2
+                                        #   Parent Loop BB0_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	movl	%ecx, %edx
+	imull	%r8d, %edx
+	movl	%edx, %esi
+	sarl	$31, %esi
+	shrl	$22, %esi
+	addl	%edx, %esi
+	andl	$-1024, %esi            # imm = 0xFFFFFFFFFFFFFC00
+	negl	%esi
+	movq	%r8, %rax
+	shlq	$11, %rax
+	leal	1(%rdx,%rsi), %edi
+	leaq	(%rax,%rax,2), %rsi
+	leaq	1(%rcx), %rdx
+	cmpq	$1536, %rdx             # imm = 0x600
+	vcvtsi2sdl	%edi, %xmm0, %xmm1
+	vmulsd	%xmm0, %xmm1, %xmm1
+	vcvtsd2ss	%xmm1, %xmm1, %xmm1
+	vmovss	%xmm1, A(%rsi,%rcx,4)
+	vmovss	%xmm1, B(%rsi,%rcx,4)
+	movq	%rdx, %rcx
+	jne	.LBB0_2
+# BB#3:                                 # %polly.loop_exit4
+                                        #   in Loop: Header=BB0_1 Depth=1
+	incq	%r8
+	cmpq	$1536, %r8              # imm = 0x600
+	jne	.LBB0_1
+# BB#4:                                 # %polly.loop_exit
+	popq	%rbp
+	ret
+.Ltmp5:
+	.size	init_array, .Ltmp5-init_array
+	.cfi_endproc
+
+	.globl	print_array
+	.align	16, 0x90
+	.type	print_array,@function
+print_array:                            # @print_array
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp9:
+	.cfi_def_cfa_offset 16
+.Ltmp10:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp11:
+	.cfi_def_cfa_register %rbp
+	pushq	%r15
+	pushq	%r14
+	pushq	%r12
+	pushq	%rbx
+.Ltmp12:
+	.cfi_offset %rbx, -48
+.Ltmp13:
+	.cfi_offset %r12, -40
+.Ltmp14:
+	.cfi_offset %r14, -32
+.Ltmp15:
+	.cfi_offset %r15, -24
+	xorl	%r14d, %r14d
+	movl	$C, %r15d
+	.align	16, 0x90
+.LBB1_1:                                # %for.cond1.preheader
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB1_2 Depth 2
+	movq	stdout(%rip), %rax
+	movq	%r15, %r12
+	xorl	%ebx, %ebx
+	.align	16, 0x90
+.LBB1_2:                                # %for.body3
+                                        #   Parent Loop BB1_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	vmovss	(%r12), %xmm0
+	vcvtss2sd	%xmm0, %xmm0, %xmm0
+	movq	%rax, %rdi
+	movl	$.L.str, %esi
+	movb	$1, %al
+	callq	fprintf
+	movslq	%ebx, %rax
+	imulq	$1717986919, %rax, %rcx # imm = 0x66666667
+	movq	%rcx, %rdx
+	shrq	$63, %rdx
+	sarq	$37, %rcx
+	addl	%edx, %ecx
+	imull	$80, %ecx, %ecx
+	subl	%ecx, %eax
+	cmpl	$79, %eax
+	jne	.LBB1_4
+# BB#3:                                 # %if.then
+                                        #   in Loop: Header=BB1_2 Depth=2
+	movq	stdout(%rip), %rsi
+	movl	$10, %edi
+	callq	fputc
+.LBB1_4:                                # %for.inc
+                                        #   in Loop: Header=BB1_2 Depth=2
+	addq	$4, %r12
+	incq	%rbx
+	movq	stdout(%rip), %rax
+	cmpq	$1536, %rbx             # imm = 0x600
+	jne	.LBB1_2
+# BB#5:                                 # %for.end
+                                        #   in Loop: Header=BB1_1 Depth=1
+	movl	$10, %edi
+	movq	%rax, %rsi
+	callq	fputc
+	addq	$6144, %r15             # imm = 0x1800
+	incq	%r14
+	cmpq	$1536, %r14             # imm = 0x600
+	jne	.LBB1_1
+# BB#6:                                 # %for.end12
+	popq	%rbx
+	popq	%r12
+	popq	%r14
+	popq	%r15
+	popq	%rbp
+	ret
+.Ltmp16:
+	.size	print_array, .Ltmp16-print_array
+	.cfi_endproc
+
+	.section	.rodata.cst8,"aM",@progbits,8
+	.align	8
+.LCPI2_0:
+	.quad	4602678819172646912     # double 0.5
+	.text
+	.globl	main
+	.align	16, 0x90
+	.type	main,@function
+main:                                   # @main
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp20:
+	.cfi_def_cfa_offset 16
+.Ltmp21:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp22:
+	.cfi_def_cfa_register %rbp
+	pushq	%r15
+	pushq	%r14
+	pushq	%r13
+	pushq	%r12
+	pushq	%rbx
+	subq	$56, %rsp
+.Ltmp23:
+	.cfi_offset %rbx, -56
+.Ltmp24:
+	.cfi_offset %r12, -48
+.Ltmp25:
+	.cfi_offset %r13, -40
+.Ltmp26:
+	.cfi_offset %r14, -32
+.Ltmp27:
+	.cfi_offset %r15, -24
+	xorl	%ebx, %ebx
+	vmovsd	.LCPI2_0(%rip), %xmm0
+	.align	16, 0x90
+.LBB2_1:                                # %polly.loop_preheader3.i
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB2_2 Depth 2
+	xorl	%ecx, %ecx
+	.align	16, 0x90
+.LBB2_2:                                # %polly.loop_header2.i
+                                        #   Parent Loop BB2_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	movl	%ecx, %edx
+	imull	%ebx, %edx
+	movl	%edx, %esi
+	sarl	$31, %esi
+	shrl	$22, %esi
+	addl	%edx, %esi
+	andl	$-1024, %esi            # imm = 0xFFFFFFFFFFFFFC00
+	negl	%esi
+	movq	%rbx, %rax
+	shlq	$11, %rax
+	leal	1(%rdx,%rsi), %edi
+	leaq	(%rax,%rax,2), %rsi
+	leaq	1(%rcx), %rdx
+	cmpq	$1536, %rdx             # imm = 0x600
+	vcvtsi2sdl	%edi, %xmm0, %xmm1
+	vmulsd	%xmm0, %xmm1, %xmm1
+	vcvtsd2ss	%xmm1, %xmm1, %xmm1
+	vmovss	%xmm1, A(%rsi,%rcx,4)
+	vmovss	%xmm1, B(%rsi,%rcx,4)
+	movq	%rdx, %rcx
+	jne	.LBB2_2
+# BB#3:                                 # %polly.loop_exit4.i
+                                        #   in Loop: Header=BB2_1 Depth=1
+	incq	%rbx
+	cmpq	$1536, %rbx             # imm = 0x600
+	jne	.LBB2_1
+# BB#4:                                 # %polly.loop_preheader3.preheader
+	movl	$C, %edi
+	xorl	%esi, %esi
+	movl	$9437184, %edx          # imm = 0x900000
+	callq	memset
+	xorl	%esi, %esi
+	movl	$C+16, %eax
+	movq	%rax, -88(%rbp)         # 8-byte Spill
+	.align	16, 0x90
+.LBB2_5:                                # %polly.loop_preheader17
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB2_15 Depth 2
+                                        #       Child Loop BB2_8 Depth 3
+                                        #         Child Loop BB2_11 Depth 4
+                                        #           Child Loop BB2_17 Depth 5
+                                        #             Child Loop BB2_18 Depth 6
+	movq	%rsi, -56(%rbp)         # 8-byte Spill
+	movq	%rsi, %rax
+	orq	$63, %rax
+	movq	%rax, -72(%rbp)         # 8-byte Spill
+	leaq	-1(%rax), %rax
+	movq	%rax, -48(%rbp)         # 8-byte Spill
+	xorl	%edx, %edx
+	.align	16, 0x90
+.LBB2_15:                               # %polly.loop_preheader24
+                                        #   Parent Loop BB2_5 Depth=1
+                                        # =>  This Loop Header: Depth=2
+                                        #       Child Loop BB2_8 Depth 3
+                                        #         Child Loop BB2_11 Depth 4
+                                        #           Child Loop BB2_17 Depth 5
+                                        #             Child Loop BB2_18 Depth 6
+	movq	%rdx, -80(%rbp)         # 8-byte Spill
+	leaq	-4(%rdx), %rcx
+	movq	%rdx, %rax
+	decq	%rax
+	cmovsq	%rcx, %rax
+	movq	%rax, %r15
+	sarq	$63, %r15
+	shrq	$62, %r15
+	addq	%rax, %r15
+	andq	$-4, %r15
+	movq	%rdx, %r13
+	orq	$63, %r13
+	leaq	-4(%r13), %rdx
+	xorl	%r10d, %r10d
+	movq	-88(%rbp), %rax         # 8-byte Reload
+	leaq	(%rax,%r15,4), %rax
+	movq	%rax, -64(%rbp)         # 8-byte Spill
+	leaq	B+16(,%r15,4), %rbx
+	leaq	4(%r15), %r12
+	.align	16, 0x90
+.LBB2_8:                                # %polly.loop_header23
+                                        #   Parent Loop BB2_5 Depth=1
+                                        #     Parent Loop BB2_15 Depth=2
+                                        # =>    This Loop Header: Depth=3
+                                        #         Child Loop BB2_11 Depth 4
+                                        #           Child Loop BB2_17 Depth 5
+                                        #             Child Loop BB2_18 Depth 6
+	cmpq	-72(%rbp), %rsi         # 8-byte Folded Reload
+	jg	.LBB2_13
+# BB#9:                                 # %polly.loop_header30.preheader
+                                        #   in Loop: Header=BB2_8 Depth=3
+	movq	%r10, %rax
+	orq	$63, %rax
+	cmpq	%rax, %r10
+	jg	.LBB2_13
+# BB#10:                                #   in Loop: Header=BB2_8 Depth=3
+	decq	%rax
+	movq	-64(%rbp), %r14         # 8-byte Reload
+	movq	-56(%rbp), %r11         # 8-byte Reload
+	.align	16, 0x90
+.LBB2_11:                               # %polly.loop_header37.preheader
+                                        #   Parent Loop BB2_5 Depth=1
+                                        #     Parent Loop BB2_15 Depth=2
+                                        #       Parent Loop BB2_8 Depth=3
+                                        # =>      This Loop Header: Depth=4
+                                        #           Child Loop BB2_17 Depth 5
+                                        #             Child Loop BB2_18 Depth 6
+	cmpq	%r13, %r12
+	movq	%rbx, %r8
+	movq	%r10, %rsi
+	jg	.LBB2_12
+	.align	16, 0x90
+.LBB2_17:                               # %polly.loop_header46.preheader
+                                        #   Parent Loop BB2_5 Depth=1
+                                        #     Parent Loop BB2_15 Depth=2
+                                        #       Parent Loop BB2_8 Depth=3
+                                        #         Parent Loop BB2_11 Depth=4
+                                        # =>        This Loop Header: Depth=5
+                                        #             Child Loop BB2_18 Depth 6
+	leaq	(%r11,%r11,2), %rcx
+	shlq	$11, %rcx
+	vbroadcastss	A(%rcx,%rsi,4), %xmm0
+	movq	%r14, %rdi
+	movq	%r8, %r9
+	movq	%r15, %rcx
+.LBB2_18:                               # %polly.loop_header46
+                                        #   Parent Loop BB2_5 Depth=1
+                                        #     Parent Loop BB2_15 Depth=2
+                                        #       Parent Loop BB2_8 Depth=3
+                                        #         Parent Loop BB2_11 Depth=4
+                                        #           Parent Loop BB2_17 Depth=5
+                                        # =>          This Inner Loop Header: Depth=6
+	vmulps	(%r9), %xmm0, %xmm1
+	vaddps	(%rdi), %xmm1, %xmm1
+	vmovaps	%xmm1, (%rdi)
+	addq	$16, %rdi
+	addq	$16, %r9
+	addq	$4, %rcx
+	cmpq	%rdx, %rcx
+	jle	.LBB2_18
+# BB#16:                                # %polly.loop_exit48
+                                        #   in Loop: Header=BB2_17 Depth=5
+	addq	$6144, %r8              # imm = 0x1800
+	cmpq	%rax, %rsi
+	leaq	1(%rsi), %rsi
+	jle	.LBB2_17
+	.align	16, 0x90
+.LBB2_12:                               # %polly.loop_exit39
+                                        #   in Loop: Header=BB2_11 Depth=4
+	addq	$6144, %r14             # imm = 0x1800
+	cmpq	-48(%rbp), %r11         # 8-byte Folded Reload
+	leaq	1(%r11), %r11
+	jle	.LBB2_11
+	.align	16, 0x90
+.LBB2_13:                               # %polly.loop_exit32
+                                        #   in Loop: Header=BB2_8 Depth=3
+	addq	$393216, %rbx           # imm = 0x60000
+	cmpq	$1472, %r10             # imm = 0x5C0
+	leaq	64(%r10), %r10
+	movq	-56(%rbp), %rsi         # 8-byte Reload
+	jl	.LBB2_8
+# BB#14:                                # %polly.loop_exit25
+                                        #   in Loop: Header=BB2_15 Depth=2
+	movq	-80(%rbp), %rdx         # 8-byte Reload
+	cmpq	$1472, %rdx             # imm = 0x5C0
+	leaq	64(%rdx), %rdx
+	jl	.LBB2_15
+# BB#6:                                 # %polly.loop_exit18
+                                        #   in Loop: Header=BB2_5 Depth=1
+	addq	$393216, -88(%rbp)      # 8-byte Folded Spill
+                                        # imm = 0x60000
+	cmpq	$1472, %rsi             # imm = 0x5C0
+	leaq	64(%rsi), %rsi
+	jl	.LBB2_5
+# BB#7:                                 # %polly.loop_exit11
+	xorl	%eax, %eax
+	addq	$56, %rsp
+	popq	%rbx
+	popq	%r12
+	popq	%r13
+	popq	%r14
+	popq	%r15
+	popq	%rbp
+	ret
+.Ltmp28:
+	.size	main, .Ltmp28-main
+	.cfi_endproc
+
+	.type	A,@object               # @A
+	.comm	A,9437184,16
+	.type	B,@object               # @B
+	.comm	B,9437184,16
+	.type	.L.str,@object          # @.str
+	.section	.rodata.str1.1,"aMS",@progbits,1
+.L.str:
+	.asciz	 "%lf "
+	.size	.L.str, 5
+
+	.type	C,@object               # @C
+	.comm	C,9437184,16
+
+	.section	".note.GNU-stack","",@progbits
diff --git a/final/www/experiments/matmul/matmul.polly.interchanged+tiled.exe b/final/www/experiments/matmul/matmul.polly.interchanged+tiled.exe
new file mode 100755
index 0000000..fbd8b12
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.polly.interchanged+tiled.exe
Binary files differ
diff --git a/final/www/experiments/matmul/matmul.polly.interchanged+tiled.ll b/final/www/experiments/matmul/matmul.polly.interchanged+tiled.ll
new file mode 100644
index 0000000..acdd95f
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.polly.interchanged+tiled.ll
Binary files differ
diff --git a/final/www/experiments/matmul/matmul.polly.interchanged+tiled.s b/final/www/experiments/matmul/matmul.polly.interchanged+tiled.s
new file mode 100644
index 0000000..f7ab7fd
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.polly.interchanged+tiled.s
@@ -0,0 +1,390 @@
+	.file	"matmul.polly.interchanged+tiled.ll"
+	.section	.rodata.cst8,"aM",@progbits,8
+	.align	8
+.LCPI0_0:
+	.quad	4602678819172646912     # double 0.5
+	.text
+	.globl	init_array
+	.align	16, 0x90
+	.type	init_array,@function
+init_array:                             # @init_array
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp2:
+	.cfi_def_cfa_offset 16
+.Ltmp3:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp4:
+	.cfi_def_cfa_register %rbp
+	xorl	%r8d, %r8d
+	vmovsd	.LCPI0_0(%rip), %xmm0
+	.align	16, 0x90
+.LBB0_1:                                # %polly.loop_preheader3
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB0_2 Depth 2
+	xorl	%ecx, %ecx
+	.align	16, 0x90
+.LBB0_2:                                # %polly.loop_header2
+                                        #   Parent Loop BB0_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	movl	%ecx, %edx
+	imull	%r8d, %edx
+	movl	%edx, %esi
+	sarl	$31, %esi
+	shrl	$22, %esi
+	addl	%edx, %esi
+	andl	$-1024, %esi            # imm = 0xFFFFFFFFFFFFFC00
+	negl	%esi
+	movq	%r8, %rax
+	shlq	$11, %rax
+	leal	1(%rdx,%rsi), %edi
+	leaq	(%rax,%rax,2), %rsi
+	leaq	1(%rcx), %rdx
+	cmpq	$1536, %rdx             # imm = 0x600
+	vcvtsi2sdl	%edi, %xmm0, %xmm1
+	vmulsd	%xmm0, %xmm1, %xmm1
+	vcvtsd2ss	%xmm1, %xmm1, %xmm1
+	vmovss	%xmm1, A(%rsi,%rcx,4)
+	vmovss	%xmm1, B(%rsi,%rcx,4)
+	movq	%rdx, %rcx
+	jne	.LBB0_2
+# BB#3:                                 # %polly.loop_exit4
+                                        #   in Loop: Header=BB0_1 Depth=1
+	incq	%r8
+	cmpq	$1536, %r8              # imm = 0x600
+	jne	.LBB0_1
+# BB#4:                                 # %polly.loop_exit
+	popq	%rbp
+	ret
+.Ltmp5:
+	.size	init_array, .Ltmp5-init_array
+	.cfi_endproc
+
+	.globl	print_array
+	.align	16, 0x90
+	.type	print_array,@function
+print_array:                            # @print_array
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp9:
+	.cfi_def_cfa_offset 16
+.Ltmp10:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp11:
+	.cfi_def_cfa_register %rbp
+	pushq	%r15
+	pushq	%r14
+	pushq	%r12
+	pushq	%rbx
+.Ltmp12:
+	.cfi_offset %rbx, -48
+.Ltmp13:
+	.cfi_offset %r12, -40
+.Ltmp14:
+	.cfi_offset %r14, -32
+.Ltmp15:
+	.cfi_offset %r15, -24
+	xorl	%r14d, %r14d
+	movl	$C, %r15d
+	.align	16, 0x90
+.LBB1_1:                                # %for.cond1.preheader
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB1_2 Depth 2
+	movq	stdout(%rip), %rax
+	movq	%r15, %r12
+	xorl	%ebx, %ebx
+	.align	16, 0x90
+.LBB1_2:                                # %for.body3
+                                        #   Parent Loop BB1_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	vmovss	(%r12), %xmm0
+	vcvtss2sd	%xmm0, %xmm0, %xmm0
+	movq	%rax, %rdi
+	movl	$.L.str, %esi
+	movb	$1, %al
+	callq	fprintf
+	movslq	%ebx, %rax
+	imulq	$1717986919, %rax, %rcx # imm = 0x66666667
+	movq	%rcx, %rdx
+	shrq	$63, %rdx
+	sarq	$37, %rcx
+	addl	%edx, %ecx
+	imull	$80, %ecx, %ecx
+	subl	%ecx, %eax
+	cmpl	$79, %eax
+	jne	.LBB1_4
+# BB#3:                                 # %if.then
+                                        #   in Loop: Header=BB1_2 Depth=2
+	movq	stdout(%rip), %rsi
+	movl	$10, %edi
+	callq	fputc
+.LBB1_4:                                # %for.inc
+                                        #   in Loop: Header=BB1_2 Depth=2
+	addq	$4, %r12
+	incq	%rbx
+	movq	stdout(%rip), %rax
+	cmpq	$1536, %rbx             # imm = 0x600
+	jne	.LBB1_2
+# BB#5:                                 # %for.end
+                                        #   in Loop: Header=BB1_1 Depth=1
+	movl	$10, %edi
+	movq	%rax, %rsi
+	callq	fputc
+	addq	$6144, %r15             # imm = 0x1800
+	incq	%r14
+	cmpq	$1536, %r14             # imm = 0x600
+	jne	.LBB1_1
+# BB#6:                                 # %for.end12
+	popq	%rbx
+	popq	%r12
+	popq	%r14
+	popq	%r15
+	popq	%rbp
+	ret
+.Ltmp16:
+	.size	print_array, .Ltmp16-print_array
+	.cfi_endproc
+
+	.section	.rodata.cst8,"aM",@progbits,8
+	.align	8
+.LCPI2_0:
+	.quad	4602678819172646912     # double 0.5
+	.text
+	.globl	main
+	.align	16, 0x90
+	.type	main,@function
+main:                                   # @main
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp20:
+	.cfi_def_cfa_offset 16
+.Ltmp21:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp22:
+	.cfi_def_cfa_register %rbp
+	pushq	%r15
+	pushq	%r14
+	pushq	%r13
+	pushq	%r12
+	pushq	%rbx
+	subq	$56, %rsp
+.Ltmp23:
+	.cfi_offset %rbx, -56
+.Ltmp24:
+	.cfi_offset %r12, -48
+.Ltmp25:
+	.cfi_offset %r13, -40
+.Ltmp26:
+	.cfi_offset %r14, -32
+.Ltmp27:
+	.cfi_offset %r15, -24
+	xorl	%ebx, %ebx
+	vmovsd	.LCPI2_0(%rip), %xmm0
+	.align	16, 0x90
+.LBB2_1:                                # %polly.loop_preheader3.i
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB2_2 Depth 2
+	xorl	%ecx, %ecx
+	.align	16, 0x90
+.LBB2_2:                                # %polly.loop_header2.i
+                                        #   Parent Loop BB2_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	movl	%ecx, %edx
+	imull	%ebx, %edx
+	movl	%edx, %esi
+	sarl	$31, %esi
+	shrl	$22, %esi
+	addl	%edx, %esi
+	andl	$-1024, %esi            # imm = 0xFFFFFFFFFFFFFC00
+	negl	%esi
+	movq	%rbx, %rax
+	shlq	$11, %rax
+	leal	1(%rdx,%rsi), %edi
+	leaq	(%rax,%rax,2), %rsi
+	leaq	1(%rcx), %rdx
+	cmpq	$1536, %rdx             # imm = 0x600
+	vcvtsi2sdl	%edi, %xmm0, %xmm1
+	vmulsd	%xmm0, %xmm1, %xmm1
+	vcvtsd2ss	%xmm1, %xmm1, %xmm1
+	vmovss	%xmm1, A(%rsi,%rcx,4)
+	vmovss	%xmm1, B(%rsi,%rcx,4)
+	movq	%rdx, %rcx
+	jne	.LBB2_2
+# BB#3:                                 # %polly.loop_exit4.i
+                                        #   in Loop: Header=BB2_1 Depth=1
+	incq	%rbx
+	cmpq	$1536, %rbx             # imm = 0x600
+	jne	.LBB2_1
+# BB#4:                                 # %polly.loop_preheader3.preheader
+	movl	$C, %ebx
+	movl	$C, %edi
+	xorl	%esi, %esi
+	movl	$9437184, %edx          # imm = 0x900000
+	callq	memset
+	xorl	%eax, %eax
+	.align	16, 0x90
+.LBB2_5:                                # %polly.loop_preheader17
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB2_15 Depth 2
+                                        #       Child Loop BB2_8 Depth 3
+                                        #         Child Loop BB2_11 Depth 4
+                                        #           Child Loop BB2_17 Depth 5
+                                        #             Child Loop BB2_18 Depth 6
+	movq	%rax, -56(%rbp)         # 8-byte Spill
+	movq	%rbx, -88(%rbp)         # 8-byte Spill
+	movq	%rax, %rcx
+	orq	$63, %rcx
+	movq	%rcx, -72(%rbp)         # 8-byte Spill
+	leaq	-1(%rcx), %rcx
+	movq	%rcx, -48(%rbp)         # 8-byte Spill
+	movq	$-1, %r15
+	movl	$B, %ecx
+	movq	%rbx, -64(%rbp)         # 8-byte Spill
+	xorl	%r12d, %r12d
+	.align	16, 0x90
+.LBB2_15:                               # %polly.loop_preheader24
+                                        #   Parent Loop BB2_5 Depth=1
+                                        # =>  This Loop Header: Depth=2
+                                        #       Child Loop BB2_8 Depth 3
+                                        #         Child Loop BB2_11 Depth 4
+                                        #           Child Loop BB2_17 Depth 5
+                                        #             Child Loop BB2_18 Depth 6
+	movq	%rcx, -80(%rbp)         # 8-byte Spill
+	movq	%r12, %r13
+	orq	$63, %r13
+	leaq	-1(%r13), %rbx
+	xorl	%r9d, %r9d
+	movq	%rcx, %rdx
+	.align	16, 0x90
+.LBB2_8:                                # %polly.loop_header23
+                                        #   Parent Loop BB2_5 Depth=1
+                                        #     Parent Loop BB2_15 Depth=2
+                                        # =>    This Loop Header: Depth=3
+                                        #         Child Loop BB2_11 Depth 4
+                                        #           Child Loop BB2_17 Depth 5
+                                        #             Child Loop BB2_18 Depth 6
+	cmpq	-72(%rbp), %rax         # 8-byte Folded Reload
+	jg	.LBB2_13
+# BB#9:                                 # %polly.loop_header30.preheader
+                                        #   in Loop: Header=BB2_8 Depth=3
+	movq	%r9, %rax
+	orq	$63, %rax
+	cmpq	%rax, %r9
+	jg	.LBB2_13
+# BB#10:                                #   in Loop: Header=BB2_8 Depth=3
+	decq	%rax
+	movq	-64(%rbp), %r10         # 8-byte Reload
+	movq	-56(%rbp), %r11         # 8-byte Reload
+	.align	16, 0x90
+.LBB2_11:                               # %polly.loop_header37.preheader
+                                        #   Parent Loop BB2_5 Depth=1
+                                        #     Parent Loop BB2_15 Depth=2
+                                        #       Parent Loop BB2_8 Depth=3
+                                        # =>      This Loop Header: Depth=4
+                                        #           Child Loop BB2_17 Depth 5
+                                        #             Child Loop BB2_18 Depth 6
+	cmpq	%r13, %r12
+	movq	%rdx, %r14
+	movq	%r9, %rcx
+	jg	.LBB2_12
+	.align	16, 0x90
+.LBB2_17:                               # %polly.loop_header46.preheader
+                                        #   Parent Loop BB2_5 Depth=1
+                                        #     Parent Loop BB2_15 Depth=2
+                                        #       Parent Loop BB2_8 Depth=3
+                                        #         Parent Loop BB2_11 Depth=4
+                                        # =>        This Loop Header: Depth=5
+                                        #             Child Loop BB2_18 Depth 6
+	leaq	(%r11,%r11,2), %rsi
+	shlq	$11, %rsi
+	vmovss	A(%rsi,%rcx,4), %xmm0
+	movq	%r10, %rdi
+	movq	%r14, %r8
+	movq	%r15, %rsi
+.LBB2_18:                               # %polly.loop_header46
+                                        #   Parent Loop BB2_5 Depth=1
+                                        #     Parent Loop BB2_15 Depth=2
+                                        #       Parent Loop BB2_8 Depth=3
+                                        #         Parent Loop BB2_11 Depth=4
+                                        #           Parent Loop BB2_17 Depth=5
+                                        # =>          This Inner Loop Header: Depth=6
+	vmulss	(%r8), %xmm0, %xmm1
+	vaddss	(%rdi), %xmm1, %xmm1
+	vmovss	%xmm1, (%rdi)
+	addq	$4, %rdi
+	addq	$4, %r8
+	incq	%rsi
+	cmpq	%rbx, %rsi
+	jle	.LBB2_18
+# BB#16:                                # %polly.loop_exit48
+                                        #   in Loop: Header=BB2_17 Depth=5
+	addq	$6144, %r14             # imm = 0x1800
+	cmpq	%rax, %rcx
+	leaq	1(%rcx), %rcx
+	jle	.LBB2_17
+	.align	16, 0x90
+.LBB2_12:                               # %polly.loop_exit39
+                                        #   in Loop: Header=BB2_11 Depth=4
+	addq	$6144, %r10             # imm = 0x1800
+	cmpq	-48(%rbp), %r11         # 8-byte Folded Reload
+	leaq	1(%r11), %r11
+	jle	.LBB2_11
+	.align	16, 0x90
+.LBB2_13:                               # %polly.loop_exit32
+                                        #   in Loop: Header=BB2_8 Depth=3
+	addq	$393216, %rdx           # imm = 0x60000
+	cmpq	$1472, %r9              # imm = 0x5C0
+	leaq	64(%r9), %r9
+	movq	-56(%rbp), %rax         # 8-byte Reload
+	jl	.LBB2_8
+# BB#14:                                # %polly.loop_exit25
+                                        #   in Loop: Header=BB2_15 Depth=2
+	addq	$256, -64(%rbp)         # 8-byte Folded Spill
+                                        # imm = 0x100
+	movq	-80(%rbp), %rcx         # 8-byte Reload
+	addq	$256, %rcx              # imm = 0x100
+	addq	$64, %r15
+	cmpq	$1472, %r12             # imm = 0x5C0
+	leaq	64(%r12), %r12
+	jl	.LBB2_15
+# BB#6:                                 # %polly.loop_exit18
+                                        #   in Loop: Header=BB2_5 Depth=1
+	movq	-88(%rbp), %rbx         # 8-byte Reload
+	addq	$393216, %rbx           # imm = 0x60000
+	cmpq	$1472, %rax             # imm = 0x5C0
+	leaq	64(%rax), %rax
+	jl	.LBB2_5
+# BB#7:                                 # %polly.loop_exit11
+	xorl	%eax, %eax
+	addq	$56, %rsp
+	popq	%rbx
+	popq	%r12
+	popq	%r13
+	popq	%r14
+	popq	%r15
+	popq	%rbp
+	ret
+.Ltmp28:
+	.size	main, .Ltmp28-main
+	.cfi_endproc
+
+	.type	A,@object               # @A
+	.comm	A,9437184,16
+	.type	B,@object               # @B
+	.comm	B,9437184,16
+	.type	.L.str,@object          # @.str
+	.section	.rodata.str1.1,"aMS",@progbits,1
+.L.str:
+	.asciz	 "%lf "
+	.size	.L.str, 5
+
+	.type	C,@object               # @C
+	.comm	C,9437184,16
+
+	.section	".note.GNU-stack","",@progbits
diff --git a/final/www/experiments/matmul/matmul.polly.interchanged.exe b/final/www/experiments/matmul/matmul.polly.interchanged.exe
new file mode 100755
index 0000000..240c95a
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.polly.interchanged.exe
Binary files differ
diff --git a/final/www/experiments/matmul/matmul.polly.interchanged.ll b/final/www/experiments/matmul/matmul.polly.interchanged.ll
new file mode 100644
index 0000000..52fbccc
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.polly.interchanged.ll
Binary files differ
diff --git a/final/www/experiments/matmul/matmul.polly.interchanged.s b/final/www/experiments/matmul/matmul.polly.interchanged.s
new file mode 100644
index 0000000..a764da0
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.polly.interchanged.s
@@ -0,0 +1,286 @@
+	.file	"matmul.polly.interchanged.ll"
+	.section	.rodata.cst8,"aM",@progbits,8
+	.align	8
+.LCPI0_0:
+	.quad	4602678819172646912     # double 0.5
+	.text
+	.globl	init_array
+	.align	16, 0x90
+	.type	init_array,@function
+init_array:                             # @init_array
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp2:
+	.cfi_def_cfa_offset 16
+.Ltmp3:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp4:
+	.cfi_def_cfa_register %rbp
+	xorl	%r8d, %r8d
+	vmovsd	.LCPI0_0(%rip), %xmm0
+	.align	16, 0x90
+.LBB0_1:                                # %polly.loop_preheader3
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB0_2 Depth 2
+	xorl	%ecx, %ecx
+	.align	16, 0x90
+.LBB0_2:                                # %polly.loop_header2
+                                        #   Parent Loop BB0_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	movl	%ecx, %edx
+	imull	%r8d, %edx
+	movl	%edx, %esi
+	sarl	$31, %esi
+	shrl	$22, %esi
+	addl	%edx, %esi
+	andl	$-1024, %esi            # imm = 0xFFFFFFFFFFFFFC00
+	negl	%esi
+	movq	%r8, %rax
+	shlq	$11, %rax
+	leal	1(%rdx,%rsi), %edi
+	leaq	(%rax,%rax,2), %rsi
+	leaq	1(%rcx), %rdx
+	cmpq	$1536, %rdx             # imm = 0x600
+	vcvtsi2sdl	%edi, %xmm0, %xmm1
+	vmulsd	%xmm0, %xmm1, %xmm1
+	vcvtsd2ss	%xmm1, %xmm1, %xmm1
+	vmovss	%xmm1, A(%rsi,%rcx,4)
+	vmovss	%xmm1, B(%rsi,%rcx,4)
+	movq	%rdx, %rcx
+	jne	.LBB0_2
+# BB#3:                                 # %polly.loop_exit4
+                                        #   in Loop: Header=BB0_1 Depth=1
+	incq	%r8
+	cmpq	$1536, %r8              # imm = 0x600
+	jne	.LBB0_1
+# BB#4:                                 # %polly.loop_exit
+	popq	%rbp
+	ret
+.Ltmp5:
+	.size	init_array, .Ltmp5-init_array
+	.cfi_endproc
+
+	.globl	print_array
+	.align	16, 0x90
+	.type	print_array,@function
+print_array:                            # @print_array
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp9:
+	.cfi_def_cfa_offset 16
+.Ltmp10:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp11:
+	.cfi_def_cfa_register %rbp
+	pushq	%r15
+	pushq	%r14
+	pushq	%r12
+	pushq	%rbx
+.Ltmp12:
+	.cfi_offset %rbx, -48
+.Ltmp13:
+	.cfi_offset %r12, -40
+.Ltmp14:
+	.cfi_offset %r14, -32
+.Ltmp15:
+	.cfi_offset %r15, -24
+	xorl	%r14d, %r14d
+	movl	$C, %r15d
+	.align	16, 0x90
+.LBB1_1:                                # %for.cond1.preheader
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB1_2 Depth 2
+	movq	stdout(%rip), %rax
+	movq	%r15, %r12
+	xorl	%ebx, %ebx
+	.align	16, 0x90
+.LBB1_2:                                # %for.body3
+                                        #   Parent Loop BB1_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	vmovss	(%r12), %xmm0
+	vcvtss2sd	%xmm0, %xmm0, %xmm0
+	movq	%rax, %rdi
+	movl	$.L.str, %esi
+	movb	$1, %al
+	callq	fprintf
+	movslq	%ebx, %rax
+	imulq	$1717986919, %rax, %rcx # imm = 0x66666667
+	movq	%rcx, %rdx
+	shrq	$63, %rdx
+	sarq	$37, %rcx
+	addl	%edx, %ecx
+	imull	$80, %ecx, %ecx
+	subl	%ecx, %eax
+	cmpl	$79, %eax
+	jne	.LBB1_4
+# BB#3:                                 # %if.then
+                                        #   in Loop: Header=BB1_2 Depth=2
+	movq	stdout(%rip), %rsi
+	movl	$10, %edi
+	callq	fputc
+.LBB1_4:                                # %for.inc
+                                        #   in Loop: Header=BB1_2 Depth=2
+	addq	$4, %r12
+	incq	%rbx
+	movq	stdout(%rip), %rax
+	cmpq	$1536, %rbx             # imm = 0x600
+	jne	.LBB1_2
+# BB#5:                                 # %for.end
+                                        #   in Loop: Header=BB1_1 Depth=1
+	movl	$10, %edi
+	movq	%rax, %rsi
+	callq	fputc
+	addq	$6144, %r15             # imm = 0x1800
+	incq	%r14
+	cmpq	$1536, %r14             # imm = 0x600
+	jne	.LBB1_1
+# BB#6:                                 # %for.end12
+	popq	%rbx
+	popq	%r12
+	popq	%r14
+	popq	%r15
+	popq	%rbp
+	ret
+.Ltmp16:
+	.size	print_array, .Ltmp16-print_array
+	.cfi_endproc
+
+	.section	.rodata.cst8,"aM",@progbits,8
+	.align	8
+.LCPI2_0:
+	.quad	4602678819172646912     # double 0.5
+	.text
+	.globl	main
+	.align	16, 0x90
+	.type	main,@function
+main:                                   # @main
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+.Ltmp20:
+	.cfi_def_cfa_offset 16
+.Ltmp21:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+.Ltmp22:
+	.cfi_def_cfa_register %rbp
+	pushq	%r14
+	pushq	%rbx
+.Ltmp23:
+	.cfi_offset %rbx, -32
+.Ltmp24:
+	.cfi_offset %r14, -24
+	xorl	%ebx, %ebx
+	vmovsd	.LCPI2_0(%rip), %xmm0
+	.align	16, 0x90
+.LBB2_1:                                # %polly.loop_preheader3.i
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB2_2 Depth 2
+	xorl	%ecx, %ecx
+	.align	16, 0x90
+.LBB2_2:                                # %polly.loop_header2.i
+                                        #   Parent Loop BB2_1 Depth=1
+                                        # =>  This Inner Loop Header: Depth=2
+	movl	%ecx, %edx
+	imull	%ebx, %edx
+	movl	%edx, %esi
+	sarl	$31, %esi
+	shrl	$22, %esi
+	addl	%edx, %esi
+	andl	$-1024, %esi            # imm = 0xFFFFFFFFFFFFFC00
+	negl	%esi
+	movq	%rbx, %rax
+	shlq	$11, %rax
+	leal	1(%rdx,%rsi), %edi
+	leaq	(%rax,%rax,2), %rsi
+	leaq	1(%rcx), %rdx
+	cmpq	$1536, %rdx             # imm = 0x600
+	vcvtsi2sdl	%edi, %xmm0, %xmm1
+	vmulsd	%xmm0, %xmm1, %xmm1
+	vcvtsd2ss	%xmm1, %xmm1, %xmm1
+	vmovss	%xmm1, A(%rsi,%rcx,4)
+	vmovss	%xmm1, B(%rsi,%rcx,4)
+	movq	%rdx, %rcx
+	jne	.LBB2_2
+# BB#3:                                 # %polly.loop_exit4.i
+                                        #   in Loop: Header=BB2_1 Depth=1
+	incq	%rbx
+	cmpq	$1536, %rbx             # imm = 0x600
+	jne	.LBB2_1
+# BB#4:                                 # %polly.loop_preheader3.preheader
+	movl	$C, %r14d
+	movl	$C, %edi
+	xorl	%esi, %esi
+	movl	$9437184, %edx          # imm = 0x900000
+	callq	memset
+	xorl	%eax, %eax
+	.align	16, 0x90
+.LBB2_5:                                # %polly.loop_preheader17
+                                        # =>This Loop Header: Depth=1
+                                        #     Child Loop BB2_10 Depth 2
+                                        #       Child Loop BB2_8 Depth 3
+	movl	$B, %ebx
+	xorl	%edx, %edx
+	.align	16, 0x90
+.LBB2_10:                               # %polly.loop_preheader24
+                                        #   Parent Loop BB2_5 Depth=1
+                                        # =>  This Loop Header: Depth=2
+                                        #       Child Loop BB2_8 Depth 3
+	leaq	(%rax,%rax,2), %rcx
+	shlq	$11, %rcx
+	vmovss	A(%rcx,%rdx,4), %xmm0
+	movl	$1536, %esi             # imm = 0x600
+	movq	%r14, %rdi
+	movq	%rbx, %rcx
+	.align	16, 0x90
+.LBB2_8:                                # %polly.loop_header23
+                                        #   Parent Loop BB2_5 Depth=1
+                                        #     Parent Loop BB2_10 Depth=2
+                                        # =>    This Inner Loop Header: Depth=3
+	vmulss	(%rcx), %xmm0, %xmm1
+	vaddss	(%rdi), %xmm1, %xmm1
+	vmovss	%xmm1, (%rdi)
+	addq	$4, %rdi
+	addq	$4, %rcx
+	decq	%rsi
+	jne	.LBB2_8
+# BB#9:                                 # %polly.loop_exit25
+                                        #   in Loop: Header=BB2_10 Depth=2
+	addq	$6144, %rbx             # imm = 0x1800
+	incq	%rdx
+	cmpq	$1536, %rdx             # imm = 0x600
+	jne	.LBB2_10
+# BB#6:                                 # %polly.loop_exit18
+                                        #   in Loop: Header=BB2_5 Depth=1
+	addq	$6144, %r14             # imm = 0x1800
+	incq	%rax
+	cmpq	$1536, %rax             # imm = 0x600
+	jne	.LBB2_5
+# BB#7:                                 # %polly.loop_exit11
+	xorl	%eax, %eax
+	popq	%rbx
+	popq	%r14
+	popq	%rbp
+	ret
+.Ltmp25:
+	.size	main, .Ltmp25-main
+	.cfi_endproc
+
+	.type	A,@object               # @A
+	.comm	A,9437184,16
+	.type	B,@object               # @B
+	.comm	B,9437184,16
+	.type	.L.str,@object          # @.str
+	.section	.rodata.str1.1,"aMS",@progbits,1
+.L.str:
+	.asciz	 "%lf "
+	.size	.L.str, 5
+
+	.type	C,@object               # @C
+	.comm	C,9437184,16
+
+	.section	".note.GNU-stack","",@progbits
diff --git a/final/www/experiments/matmul/matmul.preopt.ll b/final/www/experiments/matmul/matmul.preopt.ll
new file mode 100644
index 0000000..db53664
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.preopt.ll
@@ -0,0 +1,171 @@
+; ModuleID = 'matmul.s'
+source_filename = "matmul.c"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker = type { %struct._IO_marker*, %struct._IO_FILE*, i32 }
+
+@A = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@B = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@stdout = external global %struct._IO_FILE*, align 8
+@.str = private unnamed_addr constant [5 x i8] c"%lf \00", align 1
+@C = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@.str.1 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
+
+; Function Attrs: nounwind uwtable
+define void @init_array() #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %entry.split, %for.inc17
+  %indvars.iv5 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next6, %for.inc17 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.cond1.preheader, %for.body3
+  %indvars.iv = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next, %for.body3 ]
+  %0 = mul nuw nsw i64 %indvars.iv, %indvars.iv5
+  %1 = trunc i64 %0 to i32
+  %rem = srem i32 %1, 1024
+  %add = add nsw i32 %rem, 1
+  %conv = sitofp i32 %add to double
+  %div = fmul double %conv, 5.000000e-01
+  %conv4 = fptrunc double %div to float
+  %arrayidx6 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @A, i64 0, i64 %indvars.iv5, i64 %indvars.iv
+  store float %conv4, float* %arrayidx6, align 4
+  %2 = mul nuw nsw i64 %indvars.iv, %indvars.iv5
+  %3 = trunc i64 %2 to i32
+  %rem8 = srem i32 %3, 1024
+  %add9 = add nsw i32 %rem8, 1
+  %conv10 = sitofp i32 %add9 to double
+  %div11 = fmul double %conv10, 5.000000e-01
+  %conv12 = fptrunc double %div11 to float
+  %arrayidx16 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @B, i64 0, i64 %indvars.iv5, i64 %indvars.iv
+  store float %conv12, float* %arrayidx16, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1536
+  br i1 %exitcond, label %for.body3, label %for.inc17
+
+for.inc17:                                        ; preds = %for.body3
+  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1
+  %exitcond7 = icmp ne i64 %indvars.iv.next6, 1536
+  br i1 %exitcond7, label %for.cond1.preheader, label %for.end19
+
+for.end19:                                        ; preds = %for.inc17
+  ret void
+}
+
+; Function Attrs: nounwind uwtable
+define void @print_array() #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %entry.split, %for.end
+  %indvars.iv6 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next7, %for.end ]
+  %0 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.cond1.preheader, %for.inc
+  %indvars.iv = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next, %for.inc ]
+  %1 = phi %struct._IO_FILE* [ %0, %for.cond1.preheader ], [ %5, %for.inc ]
+  %arrayidx5 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i64 0, i64 %indvars.iv6, i64 %indvars.iv
+  %2 = load float, float* %arrayidx5, align 4
+  %conv = fpext float %2 to double
+  %call = tail call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %1, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), double %conv) #2
+  %3 = trunc i64 %indvars.iv to i32
+  %rem = srem i32 %3, 80
+  %cmp6 = icmp eq i32 %rem, 79
+  br i1 %cmp6, label %if.then, label %for.inc
+
+if.then:                                          ; preds = %for.body3
+  %4 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
+  %fputc3 = tail call i32 @fputc(i32 10, %struct._IO_FILE* %4)
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3, %if.then
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %5 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
+  %exitcond = icmp ne i64 %indvars.iv.next, 1536
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.end:                                          ; preds = %for.inc
+  %.lcssa = phi %struct._IO_FILE* [ %5, %for.inc ]
+  %fputc = tail call i32 @fputc(i32 10, %struct._IO_FILE* %.lcssa)
+  %indvars.iv.next7 = add nuw nsw i64 %indvars.iv6, 1
+  %exitcond8 = icmp ne i64 %indvars.iv.next7, 1536
+  br i1 %exitcond8, label %for.cond1.preheader, label %for.end12
+
+for.end12:                                        ; preds = %for.end
+  ret void
+}
+
+declare i32 @fprintf(%struct._IO_FILE*, i8*, ...) #1
+
+; Function Attrs: nounwind uwtable
+define i32 @main() #0 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  tail call void @init_array()
+  br label %for.cond1.preheader
+
+for.cond1.preheader:                              ; preds = %entry.split, %for.inc28
+  %indvars.iv7 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next8, %for.inc28 ]
+  br label %for.body3
+
+for.body3:                                        ; preds = %for.cond1.preheader, %for.inc25
+  %indvars.iv4 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next5, %for.inc25 ]
+  %arrayidx5 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i64 0, i64 %indvars.iv7, i64 %indvars.iv4
+  store float 0.000000e+00, float* %arrayidx5, align 4
+  br label %for.body8
+
+for.body8:                                        ; preds = %for.body3, %for.body8
+  %indvars.iv = phi i64 [ 0, %for.body3 ], [ %indvars.iv.next, %for.body8 ]
+  %arrayidx12 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i64 0, i64 %indvars.iv7, i64 %indvars.iv4
+  %0 = load float, float* %arrayidx12, align 4
+  %arrayidx16 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @A, i64 0, i64 %indvars.iv7, i64 %indvars.iv
+  %1 = load float, float* %arrayidx16, align 4
+  %arrayidx20 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @B, i64 0, i64 %indvars.iv, i64 %indvars.iv4
+  %2 = load float, float* %arrayidx20, align 4
+  %mul = fmul float %1, %2
+  %add = fadd float %0, %mul
+  %arrayidx24 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i64 0, i64 %indvars.iv7, i64 %indvars.iv4
+  store float %add, float* %arrayidx24, align 4
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp ne i64 %indvars.iv.next, 1536
+  br i1 %exitcond, label %for.body8, label %for.inc25
+
+for.inc25:                                        ; preds = %for.body8
+  %indvars.iv.next5 = add nuw nsw i64 %indvars.iv4, 1
+  %exitcond6 = icmp ne i64 %indvars.iv.next5, 1536
+  br i1 %exitcond6, label %for.body3, label %for.inc28
+
+for.inc28:                                        ; preds = %for.inc25
+  %indvars.iv.next8 = add nuw nsw i64 %indvars.iv7, 1
+  %exitcond9 = icmp ne i64 %indvars.iv.next8, 1536
+  br i1 %exitcond9, label %for.cond1.preheader, label %for.end30
+
+for.end30:                                        ; preds = %for.inc28
+  ret i32 0
+}
+
+; Function Attrs: nounwind
+declare i64 @fwrite(i8* nocapture, i64, i64, %struct._IO_FILE* nocapture) #2
+
+; Function Attrs: nounwind
+declare i32 @fputc(i32, %struct._IO_FILE* nocapture) #2
+
+attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 4.0.0 (http://llvm.org/git/clang.git 081569d9a29c7bc827b2d41f8e62891bbc895e2f) (http://llvm.org/git/llvm.git e117e506536626352e8e47f6c72cd6e2a276622c)"}
diff --git a/final/www/experiments/matmul/matmul.s b/final/www/experiments/matmul/matmul.s
new file mode 100644
index 0000000..17147be
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.s
@@ -0,0 +1,269 @@
+; ModuleID = 'matmul.c'
+source_filename = "matmul.c"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker = type { %struct._IO_marker*, %struct._IO_FILE*, i32 }
+
+@A = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@B = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@stdout = external global %struct._IO_FILE*, align 8
+@.str = private unnamed_addr constant [5 x i8] c"%lf \00", align 1
+@C = common global [1536 x [1536 x float]] zeroinitializer, align 16
+@.str.1 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
+
+; Function Attrs: nounwind uwtable
+define void @init_array() #0 {
+entry:
+  %i = alloca i32, align 4
+  %j = alloca i32, align 4
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc17, %entry
+  %0 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %0, 1536
+  br i1 %cmp, label %for.body, label %for.end19
+
+for.body:                                         ; preds = %for.cond
+  store i32 0, i32* %j, align 4
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %1 = load i32, i32* %j, align 4
+  %cmp2 = icmp slt i32 %1, 1536
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %2 = load i32, i32* %i, align 4
+  %3 = load i32, i32* %j, align 4
+  %mul = mul nsw i32 %2, %3
+  %rem = srem i32 %mul, 1024
+  %add = add nsw i32 1, %rem
+  %conv = sitofp i32 %add to double
+  %div = fdiv double %conv, 2.000000e+00
+  %conv4 = fptrunc double %div to float
+  %4 = load i32, i32* %j, align 4
+  %idxprom = sext i32 %4 to i64
+  %5 = load i32, i32* %i, align 4
+  %idxprom5 = sext i32 %5 to i64
+  %arrayidx = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @A, i64 0, i64 %idxprom5
+  %arrayidx6 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx, i64 0, i64 %idxprom
+  store float %conv4, float* %arrayidx6, align 4
+  %6 = load i32, i32* %i, align 4
+  %7 = load i32, i32* %j, align 4
+  %mul7 = mul nsw i32 %6, %7
+  %rem8 = srem i32 %mul7, 1024
+  %add9 = add nsw i32 1, %rem8
+  %conv10 = sitofp i32 %add9 to double
+  %div11 = fdiv double %conv10, 2.000000e+00
+  %conv12 = fptrunc double %div11 to float
+  %8 = load i32, i32* %j, align 4
+  %idxprom13 = sext i32 %8 to i64
+  %9 = load i32, i32* %i, align 4
+  %idxprom14 = sext i32 %9 to i64
+  %arrayidx15 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @B, i64 0, i64 %idxprom14
+  %arrayidx16 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx15, i64 0, i64 %idxprom13
+  store float %conv12, float* %arrayidx16, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %10 = load i32, i32* %j, align 4
+  %inc = add nsw i32 %10, 1
+  store i32 %inc, i32* %j, align 4
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc17
+
+for.inc17:                                        ; preds = %for.end
+  %11 = load i32, i32* %i, align 4
+  %inc18 = add nsw i32 %11, 1
+  store i32 %inc18, i32* %i, align 4
+  br label %for.cond
+
+for.end19:                                        ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: nounwind uwtable
+define void @print_array() #0 {
+entry:
+  %i = alloca i32, align 4
+  %j = alloca i32, align 4
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc10, %entry
+  %0 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %0, 1536
+  br i1 %cmp, label %for.body, label %for.end12
+
+for.body:                                         ; preds = %for.cond
+  store i32 0, i32* %j, align 4
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %1 = load i32, i32* %j, align 4
+  %cmp2 = icmp slt i32 %1, 1536
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %2 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
+  %3 = load i32, i32* %j, align 4
+  %idxprom = sext i32 %3 to i64
+  %4 = load i32, i32* %i, align 4
+  %idxprom4 = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i64 0, i64 %idxprom4
+  %arrayidx5 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx, i64 0, i64 %idxprom
+  %5 = load float, float* %arrayidx5, align 4
+  %conv = fpext float %5 to double
+  %call = call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %2, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i32 0, i32 0), double %conv)
+  %6 = load i32, i32* %j, align 4
+  %rem = srem i32 %6, 80
+  %cmp6 = icmp eq i32 %rem, 79
+  br i1 %cmp6, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body3
+  %7 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
+  %call8 = call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %7, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i32 0, i32 0))
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %for.body3
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+  %8 = load i32, i32* %j, align 4
+  %inc = add nsw i32 %8, 1
+  store i32 %inc, i32* %j, align 4
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  %9 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8
+  %call9 = call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %9, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i32 0, i32 0))
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.end
+  %10 = load i32, i32* %i, align 4
+  %inc11 = add nsw i32 %10, 1
+  store i32 %inc11, i32* %i, align 4
+  br label %for.cond
+
+for.end12:                                        ; preds = %for.cond
+  ret void
+}
+
+declare i32 @fprintf(%struct._IO_FILE*, i8*, ...) #1
+
+; Function Attrs: nounwind uwtable
+define i32 @main() #0 {
+entry:
+  %retval = alloca i32, align 4
+  %i = alloca i32, align 4
+  %j = alloca i32, align 4
+  %k = alloca i32, align 4
+  %t_start = alloca double, align 8
+  %t_end = alloca double, align 8
+  store i32 0, i32* %retval, align 4
+  call void @init_array()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc28, %entry
+  %0 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %0, 1536
+  br i1 %cmp, label %for.body, label %for.end30
+
+for.body:                                         ; preds = %for.cond
+  store i32 0, i32* %j, align 4
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc25, %for.body
+  %1 = load i32, i32* %j, align 4
+  %cmp2 = icmp slt i32 %1, 1536
+  br i1 %cmp2, label %for.body3, label %for.end27
+
+for.body3:                                        ; preds = %for.cond1
+  %2 = load i32, i32* %j, align 4
+  %idxprom = sext i32 %2 to i64
+  %3 = load i32, i32* %i, align 4
+  %idxprom4 = sext i32 %3 to i64
+  %arrayidx = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i64 0, i64 %idxprom4
+  %arrayidx5 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx, i64 0, i64 %idxprom
+  store float 0.000000e+00, float* %arrayidx5, align 4
+  store i32 0, i32* %k, align 4
+  br label %for.cond6
+
+for.cond6:                                        ; preds = %for.inc, %for.body3
+  %4 = load i32, i32* %k, align 4
+  %cmp7 = icmp slt i32 %4, 1536
+  br i1 %cmp7, label %for.body8, label %for.end
+
+for.body8:                                        ; preds = %for.cond6
+  %5 = load i32, i32* %j, align 4
+  %idxprom9 = sext i32 %5 to i64
+  %6 = load i32, i32* %i, align 4
+  %idxprom10 = sext i32 %6 to i64
+  %arrayidx11 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i64 0, i64 %idxprom10
+  %arrayidx12 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx11, i64 0, i64 %idxprom9
+  %7 = load float, float* %arrayidx12, align 4
+  %8 = load i32, i32* %k, align 4
+  %idxprom13 = sext i32 %8 to i64
+  %9 = load i32, i32* %i, align 4
+  %idxprom14 = sext i32 %9 to i64
+  %arrayidx15 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @A, i64 0, i64 %idxprom14
+  %arrayidx16 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx15, i64 0, i64 %idxprom13
+  %10 = load float, float* %arrayidx16, align 4
+  %11 = load i32, i32* %j, align 4
+  %idxprom17 = sext i32 %11 to i64
+  %12 = load i32, i32* %k, align 4
+  %idxprom18 = sext i32 %12 to i64
+  %arrayidx19 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @B, i64 0, i64 %idxprom18
+  %arrayidx20 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx19, i64 0, i64 %idxprom17
+  %13 = load float, float* %arrayidx20, align 4
+  %mul = fmul float %10, %13
+  %add = fadd float %7, %mul
+  %14 = load i32, i32* %j, align 4
+  %idxprom21 = sext i32 %14 to i64
+  %15 = load i32, i32* %i, align 4
+  %idxprom22 = sext i32 %15 to i64
+  %arrayidx23 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x float]]* @C, i64 0, i64 %idxprom22
+  %arrayidx24 = getelementptr inbounds [1536 x float], [1536 x float]* %arrayidx23, i64 0, i64 %idxprom21
+  store float %add, float* %arrayidx24, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body8
+  %16 = load i32, i32* %k, align 4
+  %inc = add nsw i32 %16, 1
+  store i32 %inc, i32* %k, align 4
+  br label %for.cond6
+
+for.end:                                          ; preds = %for.cond6
+  br label %for.inc25
+
+for.inc25:                                        ; preds = %for.end
+  %17 = load i32, i32* %j, align 4
+  %inc26 = add nsw i32 %17, 1
+  store i32 %inc26, i32* %j, align 4
+  br label %for.cond1
+
+for.end27:                                        ; preds = %for.cond1
+  br label %for.inc28
+
+for.inc28:                                        ; preds = %for.end27
+  %18 = load i32, i32* %i, align 4
+  %inc29 = add nsw i32 %18, 1
+  store i32 %inc29, i32* %i, align 4
+  br label %for.cond
+
+for.end30:                                        ; preds = %for.cond
+  ret i32 0
+}
+
+attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 4.0.0 (http://llvm.org/git/clang.git 081569d9a29c7bc827b2d41f8e62891bbc895e2f) (http://llvm.org/git/llvm.git e117e506536626352e8e47f6c72cd6e2a276622c)"}
diff --git a/final/www/experiments/matmul/runall.sh b/final/www/experiments/matmul/runall.sh
new file mode 100755
index 0000000..575b58f
--- /dev/null
+++ b/final/www/experiments/matmul/runall.sh
@@ -0,0 +1,95 @@
+#!/bin/sh -a
+
+echo "--> 1. Create LLVM-IR from C"
+clang -S -emit-llvm matmul.c -o matmul.s
+
+echo "--> 2. Prepare the LLVM-IR for Polly"
+opt -S -polly-canonicalize matmul.s > matmul.preopt.ll
+
+echo "--> 3. Show the SCoPs detected by Polly"
+opt -basicaa -polly-ast -analyze -q matmul.preopt.ll \
+    -polly-process-unprofitable
+
+echo "--> 4.1 Highlight the detected SCoPs in the CFGs of the program"
+# We only create .dot files, as directly -view-scops directly calls graphviz
+# which would require user interaction to continue the script.
+# opt -basicaa -view-scops -disable-output matmul.preopt.ll
+opt -basicaa -dot-scops -disable-output matmul.preopt.ll
+
+echo "--> 4.2 Highlight the detected SCoPs in the CFGs of the program (print \
+no instructions)"
+# We only create .dot files, as directly -view-scops-only directly calls
+# graphviz which would require user interaction to continue the script.
+# opt -basicaa -view-scops-only -disable-output matmul.preopt.ll
+opt -basicaa -dot-scops-only -disable-output matmul.preopt.ll
+
+echo "--> 4.3 Create .png files from the .dot files"
+for i in `ls *.dot`; do dot -Tpng $i > $i.png; done
+
+echo "--> 5. View the polyhedral representation of the SCoPs"
+opt -basicaa -polly-scops -analyze matmul.preopt.ll -polly-process-unprofitable
+
+echo "--> 6. Show the dependences for the SCoPs"
+opt -basicaa -polly-dependences -analyze matmul.preopt.ll \
+    -polly-process-unprofitable
+
+echo "--> 7. Export jscop files"
+opt -basicaa -polly-export-jscop matmul.preopt.ll -polly-process-unprofitable
+
+echo "--> 8. Import the updated jscop files and print the new SCoPs. (optional)"
+opt -basicaa -polly-import-jscop -polly-ast -analyze matmul.preopt.ll \
+    -polly-process-unprofitable
+opt -basicaa -polly-import-jscop -polly-ast -analyze matmul.preopt.ll \
+    -polly-import-jscop-postfix=interchanged -polly-process-unprofitable
+opt -basicaa -polly-import-jscop -polly-ast -analyze matmul.preopt.ll \
+    -polly-import-jscop-postfix=interchanged+tiled -polly-process-unprofitable
+opt -basicaa -polly-import-jscop -polly-ast -analyze matmul.preopt.ll \
+    -polly-import-jscop-postfix=interchanged+tiled+vector \
+    -polly-process-unprofitable
+
+echo "--> 9. Codegenerate the SCoPs"
+opt -basicaa -polly-import-jscop -polly-import-jscop-postfix=interchanged \
+    -polly-codegen -polly-process-unprofitable\
+    matmul.preopt.ll | opt -O3 > matmul.polly.interchanged.ll
+opt -basicaa -polly-import-jscop \
+    -polly-import-jscop-postfix=interchanged+tiled -polly-codegen \
+    matmul.preopt.ll -polly-process-unprofitable \
+    | opt -O3 > matmul.polly.interchanged+tiled.ll
+opt -basicaa -polly-import-jscop -polly-process-unprofitable\
+    -polly-import-jscop-postfix=interchanged+tiled+vector -polly-codegen \
+    matmul.preopt.ll -polly-vectorizer=polly\
+    | opt -O3 > matmul.polly.interchanged+tiled+vector.ll
+opt -basicaa -polly-import-jscop -polly-process-unprofitable\
+    -polly-import-jscop-postfix=interchanged+tiled+vector -polly-codegen \
+    matmul.preopt.ll -polly-vectorizer=polly -polly-parallel\
+    | opt -O3 > matmul.polly.interchanged+tiled+vector+openmp.ll
+opt matmul.preopt.ll | opt -O3 > matmul.normalopt.ll
+
+echo "--> 10. Create the executables"
+llc matmul.polly.interchanged.ll -o matmul.polly.interchanged.s && gcc matmul.polly.interchanged.s \
+    -o matmul.polly.interchanged.exe
+llc matmul.polly.interchanged+tiled.ll -o matmul.polly.interchanged+tiled.s && gcc matmul.polly.interchanged+tiled.s \
+    -o matmul.polly.interchanged+tiled.exe
+llc matmul.polly.interchanged+tiled+vector.ll \
+    -o matmul.polly.interchanged+tiled+vector.s \
+    && gcc matmul.polly.interchanged+tiled+vector.s \
+    -o matmul.polly.interchanged+tiled+vector.exe
+llc matmul.polly.interchanged+tiled+vector+openmp.ll \
+    -o matmul.polly.interchanged+tiled+vector+openmp.s \
+    && gcc -lgomp matmul.polly.interchanged+tiled+vector+openmp.s \
+    -o matmul.polly.interchanged+tiled+vector+openmp.exe
+llc matmul.normalopt.ll -o matmul.normalopt.s && gcc matmul.normalopt.s \
+    -o matmul.normalopt.exe
+
+echo "--> 11. Compare the runtime of the executables"
+
+echo "time ./matmul.normalopt.exe"
+time -f "%E real, %U user, %S sys" ./matmul.normalopt.exe
+echo "time ./matmul.polly.interchanged.exe"
+time -f "%E real, %U user, %S sys" ./matmul.polly.interchanged.exe
+echo "time ./matmul.polly.interchanged+tiled.exe"
+time -f "%E real, %U user, %S sys" ./matmul.polly.interchanged+tiled.exe
+echo "time ./matmul.polly.interchanged+tiled+vector.exe"
+time -f "%E real, %U user, %S sys" ./matmul.polly.interchanged+tiled+vector.exe
+echo "time ./matmul.polly.interchanged+tiled+vector+openmp.exe"
+time -f "%E real, %U user, %S sys" ./matmul.polly.interchanged+tiled+vector+openmp.exe
diff --git a/final/www/experiments/matmul/scops.init_array.dot b/final/www/experiments/matmul/scops.init_array.dot
new file mode 100644
index 0000000..3b9d6c9
--- /dev/null
+++ b/final/www/experiments/matmul/scops.init_array.dot
@@ -0,0 +1,39 @@
+digraph "Scop Graph for 'init_array' function" {
+	label="Scop Graph for 'init_array' function";
+
+	Node0x5b5b5a0 [shape=record,label="{entry:\l  br label %entry.split\l}"];
+	Node0x5b5b5a0 -> Node0x5b5de30;
+	Node0x5b5de30 [shape=record,label="{entry.split:                                      \l  br label %for.cond1.preheader\l}"];
+	Node0x5b5de30 -> Node0x5b5de50;
+	Node0x5b5de50 [shape=record,label="{for.cond1.preheader:                              \l  %indvars.iv5 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next6, %for.inc17 ]\l  br label %for.body3\l}"];
+	Node0x5b5de50 -> Node0x5b5b570;
+	Node0x5b5b570 [shape=record,label="{for.body3:                                        \l  %indvars.iv = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next,\l... %for.body3 ]\l  %0 = mul nuw nsw i64 %indvars.iv, %indvars.iv5\l  %1 = trunc i64 %0 to i32\l  %rem = srem i32 %1, 1024\l  %add = add nsw i32 %rem, 1\l  %conv = sitofp i32 %add to double\l  %div = fmul double %conv, 5.000000e-01\l  %conv4 = fptrunc double %div to float\l  %arrayidx6 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x\l... float]]* @A, i64 0, i64 %indvars.iv5, i64 %indvars.iv\l  store float %conv4, float* %arrayidx6, align 4\l  %2 = mul nuw nsw i64 %indvars.iv, %indvars.iv5\l  %3 = trunc i64 %2 to i32\l  %rem8 = srem i32 %3, 1024\l  %add9 = add nsw i32 %rem8, 1\l  %conv10 = sitofp i32 %add9 to double\l  %div11 = fmul double %conv10, 5.000000e-01\l  %conv12 = fptrunc double %div11 to float\l  %arrayidx16 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536\l... x float]]* @B, i64 0, i64 %indvars.iv5, i64 %indvars.iv\l  store float %conv12, float* %arrayidx16, align 4\l  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\l  %exitcond = icmp ne i64 %indvars.iv.next, 1536\l  br i1 %exitcond, label %for.body3, label %for.inc17\l}"];
+	Node0x5b5b570 -> Node0x5b5b570[constraint=false];
+	Node0x5b5b570 -> Node0x5b5df30;
+	Node0x5b5df30 [shape=record,label="{for.inc17:                                        \l  %indvars.iv.next6 = add nuw nsw i64 %indvars.iv5, 1\l  %exitcond7 = icmp ne i64 %indvars.iv.next6, 1536\l  br i1 %exitcond7, label %for.cond1.preheader, label %for.end19\l}"];
+	Node0x5b5df30 -> Node0x5b5de50[constraint=false];
+	Node0x5b5df30 -> Node0x5b5df90;
+	Node0x5b5df90 [shape=record,label="{for.end19:                                        \l  ret void\l}"];
+	colorscheme = "paired12"
+        subgraph cluster_0x5b4bdd0 {
+          label = "";
+          style = solid;
+          color = 1
+          subgraph cluster_0x5b4bf50 {
+            label = "Region can not profitably be optimized!";
+            style = solid;
+            color = 6
+            subgraph cluster_0x5b4c0d0 {
+              label = "";
+              style = solid;
+              color = 5
+              Node0x5b5b570;
+            }
+            Node0x5b5de50;
+            Node0x5b5df30;
+          }
+          Node0x5b5b5a0;
+          Node0x5b5de30;
+          Node0x5b5df90;
+        }
+}
diff --git a/final/www/experiments/matmul/scops.init_array.dot.png b/final/www/experiments/matmul/scops.init_array.dot.png
new file mode 100644
index 0000000..48a9f38
--- /dev/null
+++ b/final/www/experiments/matmul/scops.init_array.dot.png
Binary files differ
diff --git a/final/www/experiments/matmul/scops.main.dot b/final/www/experiments/matmul/scops.main.dot
new file mode 100644
index 0000000..e4abe8f
--- /dev/null
+++ b/final/www/experiments/matmul/scops.main.dot
@@ -0,0 +1,50 @@
+digraph "Scop Graph for 'main' function" {
+	label="Scop Graph for 'main' function";
+
+	Node0x5b5c850 [shape=record,label="{entry:\l  br label %entry.split\l}"];
+	Node0x5b5c850 -> Node0x5b5a440;
+	Node0x5b5a440 [shape=record,label="{entry.split:                                      \l  tail call void @init_array()\l  br label %for.cond1.preheader\l}"];
+	Node0x5b5a440 -> Node0x5b38cd0;
+	Node0x5b38cd0 [shape=record,label="{for.cond1.preheader:                              \l  %indvars.iv7 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next8, %for.inc28 ]\l  br label %for.body3\l}"];
+	Node0x5b38cd0 -> Node0x5b4bd30;
+	Node0x5b4bd30 [shape=record,label="{for.body3:                                        \l  %indvars.iv4 = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next5,\l... %for.inc25 ]\l  %arrayidx5 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x\l... float]]* @C, i64 0, i64 %indvars.iv7, i64 %indvars.iv4\l  store float 0.000000e+00, float* %arrayidx5, align 4\l  br label %for.body8\l}"];
+	Node0x5b4bd30 -> Node0x5b38c50;
+	Node0x5b38c50 [shape=record,label="{for.body8:                                        \l  %indvars.iv = phi i64 [ 0, %for.body3 ], [ %indvars.iv.next, %for.body8 ]\l  %arrayidx12 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536\l... x float]]* @C, i64 0, i64 %indvars.iv7, i64 %indvars.iv4\l  %0 = load float, float* %arrayidx12, align 4\l  %arrayidx16 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536\l... x float]]* @A, i64 0, i64 %indvars.iv7, i64 %indvars.iv\l  %1 = load float, float* %arrayidx16, align 4\l  %arrayidx20 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536\l... x float]]* @B, i64 0, i64 %indvars.iv, i64 %indvars.iv4\l  %2 = load float, float* %arrayidx20, align 4\l  %mul = fmul float %1, %2\l  %add = fadd float %0, %mul\l  %arrayidx24 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536\l... x float]]* @C, i64 0, i64 %indvars.iv7, i64 %indvars.iv4\l  store float %add, float* %arrayidx24, align 4\l  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\l  %exitcond = icmp ne i64 %indvars.iv.next, 1536\l  br i1 %exitcond, label %for.body8, label %for.inc25\l}"];
+	Node0x5b38c50 -> Node0x5b38c50[constraint=false];
+	Node0x5b38c50 -> Node0x5b5a290;
+	Node0x5b5a290 [shape=record,label="{for.inc25:                                        \l  %indvars.iv.next5 = add nuw nsw i64 %indvars.iv4, 1\l  %exitcond6 = icmp ne i64 %indvars.iv.next5, 1536\l  br i1 %exitcond6, label %for.body3, label %for.inc28\l}"];
+	Node0x5b5a290 -> Node0x5b4bd30[constraint=false];
+	Node0x5b5a290 -> Node0x5b5a340;
+	Node0x5b5a340 [shape=record,label="{for.inc28:                                        \l  %indvars.iv.next8 = add nuw nsw i64 %indvars.iv7, 1\l  %exitcond9 = icmp ne i64 %indvars.iv.next8, 1536\l  br i1 %exitcond9, label %for.cond1.preheader, label %for.end30\l}"];
+	Node0x5b5a340 -> Node0x5b38cd0[constraint=false];
+	Node0x5b5a340 -> Node0x5b5a3a0;
+	Node0x5b5a3a0 [shape=record,label="{for.end30:                                        \l  ret i32 0\l}"];
+	colorscheme = "paired12"
+        subgraph cluster_0x5b5c970 {
+          label = "";
+          style = solid;
+          color = 1
+          subgraph cluster_0x5b5c5a0 {
+            label = "";
+            style = filled;
+            color = 3            subgraph cluster_0x5b5c9f0 {
+              label = "";
+              style = solid;
+              color = 5
+              subgraph cluster_0x5b5c110 {
+                label = "";
+                style = solid;
+                color = 7
+                Node0x5b38c50;
+              }
+              Node0x5b4bd30;
+              Node0x5b5a290;
+            }
+            Node0x5b38cd0;
+            Node0x5b5a340;
+          }
+          Node0x5b5c850;
+          Node0x5b5a440;
+          Node0x5b5a3a0;
+        }
+}
diff --git a/final/www/experiments/matmul/scops.main.dot.png b/final/www/experiments/matmul/scops.main.dot.png
new file mode 100644
index 0000000..4e73701
--- /dev/null
+++ b/final/www/experiments/matmul/scops.main.dot.png
Binary files differ
diff --git a/final/www/experiments/matmul/scops.print_array.dot b/final/www/experiments/matmul/scops.print_array.dot
new file mode 100644
index 0000000..748ccb1
--- /dev/null
+++ b/final/www/experiments/matmul/scops.print_array.dot
@@ -0,0 +1,51 @@
+digraph "Scop Graph for 'print_array' function" {
+	label="Scop Graph for 'print_array' function";
+
+	Node0x5b5ee00 [shape=record,label="{entry:\l  br label %entry.split\l}"];
+	Node0x5b5ee00 -> Node0x5b5ee50;
+	Node0x5b5ee50 [shape=record,label="{entry.split:                                      \l  br label %for.cond1.preheader\l}"];
+	Node0x5b5ee50 -> Node0x5b5ee70;
+	Node0x5b5ee70 [shape=record,label="{for.cond1.preheader:                              \l  %indvars.iv6 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next7, %for.end ]\l  %0 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8\l  br label %for.body3\l}"];
+	Node0x5b5ee70 -> Node0x5b5ee20;
+	Node0x5b5ee20 [shape=record,label="{for.body3:                                        \l  %indvars.iv = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next,\l... %for.inc ]\l  %1 = phi %struct._IO_FILE* [ %0, %for.cond1.preheader ], [ %5, %for.inc ]\l  %arrayidx5 = getelementptr inbounds [1536 x [1536 x float]], [1536 x [1536 x\l... float]]* @C, i64 0, i64 %indvars.iv6, i64 %indvars.iv\l  %2 = load float, float* %arrayidx5, align 4\l  %conv = fpext float %2 to double\l  %call = tail call i32 (%struct._IO_FILE*, i8*, ...)\l... @fprintf(%struct._IO_FILE* %1, i8* getelementptr inbounds ([5 x i8], [5 x\l... i8]* @.str, i64 0, i64 0), double %conv) #2\l  %3 = trunc i64 %indvars.iv to i32\l  %rem = srem i32 %3, 80\l  %cmp6 = icmp eq i32 %rem, 79\l  br i1 %cmp6, label %if.then, label %for.inc\l}"];
+	Node0x5b5ee20 -> Node0x5b60d10;
+	Node0x5b5ee20 -> Node0x5b60d70;
+	Node0x5b60d10 [shape=record,label="{if.then:                                          \l  %4 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8\l  %fputc3 = tail call i32 @fputc(i32 10, %struct._IO_FILE* %4)\l  br label %for.inc\l}"];
+	Node0x5b60d10 -> Node0x5b60d70;
+	Node0x5b60d70 [shape=record,label="{for.inc:                                          \l  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\l  %5 = load %struct._IO_FILE*, %struct._IO_FILE** @stdout, align 8\l  %exitcond = icmp ne i64 %indvars.iv.next, 1536\l  br i1 %exitcond, label %for.body3, label %for.end\l}"];
+	Node0x5b60d70 -> Node0x5b5ee20[constraint=false];
+	Node0x5b60d70 -> Node0x5b60e10;
+	Node0x5b60e10 [shape=record,label="{for.end:                                          \l  %.lcssa = phi %struct._IO_FILE* [ %5, %for.inc ]\l  %fputc = tail call i32 @fputc(i32 10, %struct._IO_FILE* %.lcssa)\l  %indvars.iv.next7 = add nuw nsw i64 %indvars.iv6, 1\l  %exitcond8 = icmp ne i64 %indvars.iv.next7, 1536\l  br i1 %exitcond8, label %for.cond1.preheader, label %for.end12\l}"];
+	Node0x5b60e10 -> Node0x5b5ee70[constraint=false];
+	Node0x5b60e10 -> Node0x5b60e70;
+	Node0x5b60e70 [shape=record,label="{for.end12:                                        \l  ret void\l}"];
+	colorscheme = "paired12"
+        subgraph cluster_0x5b349a0 {
+          label = "";
+          style = solid;
+          color = 1
+          subgraph cluster_0x5b5c2c0 {
+            label = "Call instruction:   %call = tail call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %1, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), double %conv) #2";
+            style = solid;
+            color = 6
+            subgraph cluster_0x5b5c240 {
+              label = "Call instruction:   %call = tail call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %1, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), double %conv) #2";
+              style = solid;
+              color = 5
+              subgraph cluster_0x5b34a20 {
+                label = "Region can not profitably be optimized!";
+                style = solid;
+                color = 7
+                Node0x5b5ee20;
+                Node0x5b60d10;
+              }
+              Node0x5b60d70;
+            }
+            Node0x5b5ee70;
+            Node0x5b60e10;
+          }
+          Node0x5b5ee00;
+          Node0x5b5ee50;
+          Node0x5b60e70;
+        }
+}
diff --git a/final/www/experiments/matmul/scops.print_array.dot.png b/final/www/experiments/matmul/scops.print_array.dot.png
new file mode 100644
index 0000000..e3b973b
--- /dev/null
+++ b/final/www/experiments/matmul/scops.print_array.dot.png
Binary files differ
diff --git a/final/www/experiments/matmul/scopsonly.init_array.dot b/final/www/experiments/matmul/scopsonly.init_array.dot
new file mode 100644
index 0000000..3d2092b
--- /dev/null
+++ b/final/www/experiments/matmul/scopsonly.init_array.dot
@@ -0,0 +1,39 @@
+digraph "Scop Graph for 'init_array' function" {
+	label="Scop Graph for 'init_array' function";
+
+	Node0x5ae2570 [shape=record,label="{entry}"];
+	Node0x5ae2570 -> Node0x5ae4e90;
+	Node0x5ae4e90 [shape=record,label="{entry.split}"];
+	Node0x5ae4e90 -> Node0x5ae4f50;
+	Node0x5ae4f50 [shape=record,label="{for.cond1.preheader}"];
+	Node0x5ae4f50 -> Node0x5ae50e0;
+	Node0x5ae50e0 [shape=record,label="{for.body3}"];
+	Node0x5ae50e0 -> Node0x5ae50e0[constraint=false];
+	Node0x5ae50e0 -> Node0x5ae5100;
+	Node0x5ae5100 [shape=record,label="{for.inc17}"];
+	Node0x5ae5100 -> Node0x5ae4f50[constraint=false];
+	Node0x5ae5100 -> Node0x5ae4ff0;
+	Node0x5ae4ff0 [shape=record,label="{for.end19}"];
+	colorscheme = "paired12"
+        subgraph cluster_0x5ad2dd0 {
+          label = "";
+          style = solid;
+          color = 1
+          subgraph cluster_0x5ad2f50 {
+            label = "Region can not profitably be optimized!";
+            style = solid;
+            color = 6
+            subgraph cluster_0x5ad30d0 {
+              label = "";
+              style = solid;
+              color = 5
+              Node0x5ae50e0;
+            }
+            Node0x5ae4f50;
+            Node0x5ae5100;
+          }
+          Node0x5ae2570;
+          Node0x5ae4e90;
+          Node0x5ae4ff0;
+        }
+}
diff --git a/final/www/experiments/matmul/scopsonly.init_array.dot.png b/final/www/experiments/matmul/scopsonly.init_array.dot.png
new file mode 100644
index 0000000..f101d4d
--- /dev/null
+++ b/final/www/experiments/matmul/scopsonly.init_array.dot.png
Binary files differ
diff --git a/final/www/experiments/matmul/scopsonly.main.dot b/final/www/experiments/matmul/scopsonly.main.dot
new file mode 100644
index 0000000..c2d60c7
--- /dev/null
+++ b/final/www/experiments/matmul/scopsonly.main.dot
@@ -0,0 +1,50 @@
+digraph "Scop Graph for 'main' function" {
+	label="Scop Graph for 'main' function";
+
+	Node0x5abfcf0 [shape=record,label="{entry}"];
+	Node0x5abfcf0 -> Node0x5ade060;
+	Node0x5ade060 [shape=record,label="{entry.split}"];
+	Node0x5ade060 -> Node0x5ade0e0;
+	Node0x5ade0e0 [shape=record,label="{for.cond1.preheader}"];
+	Node0x5ade0e0 -> Node0x5ade100;
+	Node0x5ade100 [shape=record,label="{for.body3}"];
+	Node0x5ade100 -> Node0x5ae0020;
+	Node0x5ae0020 [shape=record,label="{for.body8}"];
+	Node0x5ae0020 -> Node0x5ae0020[constraint=false];
+	Node0x5ae0020 -> Node0x5ae0080;
+	Node0x5ae0080 [shape=record,label="{for.inc25}"];
+	Node0x5ae0080 -> Node0x5ade100[constraint=false];
+	Node0x5ae0080 -> Node0x5adfef0;
+	Node0x5adfef0 [shape=record,label="{for.inc28}"];
+	Node0x5adfef0 -> Node0x5ade0e0[constraint=false];
+	Node0x5adfef0 -> Node0x5adff50;
+	Node0x5adff50 [shape=record,label="{for.end30}"];
+	colorscheme = "paired12"
+        subgraph cluster_0x5ad2c80 {
+          label = "";
+          style = solid;
+          color = 1
+          subgraph cluster_0x5ad2e50 {
+            label = "";
+            style = filled;
+            color = 3            subgraph cluster_0x5ad2d00 {
+              label = "";
+              style = solid;
+              color = 5
+              subgraph cluster_0x5ad2dd0 {
+                label = "";
+                style = solid;
+                color = 7
+                Node0x5ae0020;
+              }
+              Node0x5ade100;
+              Node0x5ae0080;
+            }
+            Node0x5ade0e0;
+            Node0x5adfef0;
+          }
+          Node0x5abfcf0;
+          Node0x5ade060;
+          Node0x5adff50;
+        }
+}
diff --git a/final/www/experiments/matmul/scopsonly.main.dot.png b/final/www/experiments/matmul/scopsonly.main.dot.png
new file mode 100644
index 0000000..3263424
--- /dev/null
+++ b/final/www/experiments/matmul/scopsonly.main.dot.png
Binary files differ
diff --git a/final/www/experiments/matmul/scopsonly.print_array.dot b/final/www/experiments/matmul/scopsonly.print_array.dot
new file mode 100644
index 0000000..0f7de45
--- /dev/null
+++ b/final/www/experiments/matmul/scopsonly.print_array.dot
@@ -0,0 +1,51 @@
+digraph "Scop Graph for 'print_array' function" {
+	label="Scop Graph for 'print_array' function";
+
+	Node0x5ae5e30 [shape=record,label="{entry}"];
+	Node0x5ae5e30 -> Node0x5ae5f50;
+	Node0x5ae5f50 [shape=record,label="{entry.split}"];
+	Node0x5ae5f50 -> Node0x5ae7d90;
+	Node0x5ae7d90 [shape=record,label="{for.cond1.preheader}"];
+	Node0x5ae7d90 -> Node0x5ae7f20;
+	Node0x5ae7f20 [shape=record,label="{for.body3}"];
+	Node0x5ae7f20 -> Node0x5ae7f40;
+	Node0x5ae7f20 -> Node0x5ae7f60;
+	Node0x5ae7f40 [shape=record,label="{if.then}"];
+	Node0x5ae7f40 -> Node0x5ae7f60;
+	Node0x5ae7f60 [shape=record,label="{for.inc}"];
+	Node0x5ae7f60 -> Node0x5ae7f20[constraint=false];
+	Node0x5ae7f60 -> Node0x5ae7e30;
+	Node0x5ae7e30 [shape=record,label="{for.end}"];
+	Node0x5ae7e30 -> Node0x5ae7d90[constraint=false];
+	Node0x5ae7e30 -> Node0x5ae8110;
+	Node0x5ae8110 [shape=record,label="{for.end12}"];
+	colorscheme = "paired12"
+        subgraph cluster_0x5abb9a0 {
+          label = "";
+          style = solid;
+          color = 1
+          subgraph cluster_0x5ae32c0 {
+            label = "Call instruction:   %call = tail call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %1, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), double %conv) #2";
+            style = solid;
+            color = 6
+            subgraph cluster_0x5ae3240 {
+              label = "Call instruction:   %call = tail call i32 (%struct._IO_FILE*, i8*, ...) @fprintf(%struct._IO_FILE* %1, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), double %conv) #2";
+              style = solid;
+              color = 5
+              subgraph cluster_0x5abba20 {
+                label = "Region can not profitably be optimized!";
+                style = solid;
+                color = 7
+                Node0x5ae7f20;
+                Node0x5ae7f40;
+              }
+              Node0x5ae7f60;
+            }
+            Node0x5ae7d90;
+            Node0x5ae7e30;
+          }
+          Node0x5ae5e30;
+          Node0x5ae5f50;
+          Node0x5ae8110;
+        }
+}
diff --git a/final/www/experiments/matmul/scopsonly.print_array.dot.png b/final/www/experiments/matmul/scopsonly.print_array.dot.png
new file mode 100644
index 0000000..b0d4b45
--- /dev/null
+++ b/final/www/experiments/matmul/scopsonly.print_array.dot.png
Binary files differ
diff --git a/final/www/favicon.ico b/final/www/favicon.ico
new file mode 100644
index 0000000..0638d5b
--- /dev/null
+++ b/final/www/favicon.ico
Binary files differ
diff --git a/final/www/get_started.html b/final/www/get_started.html
new file mode 100644
index 0000000..5d2caba
--- /dev/null
+++ b/final/www/get_started.html
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+          "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+  <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+  <title>Polly - Getting Started</title>
+  <link type="text/css" rel="stylesheet" href="menu.css" />
+  <link type="text/css" rel="stylesheet" href="content.css" />
+</head>
+<body>
+
+<div id="box">
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<h1>Building and Installing Polly</h1>
+
+<h2> Automatic </h2>
+
+There is a <a href="polly.sh">script</a> available to automatically checkout,
+update, build, and test Polly. This script contains all the commands that are
+subsequently described on this webpage. The automatic installation consists
+of four simple steps:
+
+<pre>
+mkdir polly &amp;&amp; cd polly
+wget http://polly.llvm.org/polly.sh
+chmod +x polly.sh
+./polly.sh
+</pre>
+
+<h2> Manual </h2>
+<h3 id="source"> Get the code </h3>
+
+<p><b>Warning:</b> Polly/LLVM/clang need to be checked out at the same time.</p>
+
+<pre>
+git clone http://llvm.org/git/llvm.git llvm_git
+git clone http://llvm.org/git/polly.git llvm_git/tools/polly
+
+# Also build the matching clang-version (optional)
+git clone http://llvm.org/git/clang.git llvm_git/tools/clang
+</pre>
+<h3 id="build">Build Polly</h3>
+
+<pre>
+mkdir llvm_build && cd llvm_build
+cmake ../llvm_git && make
+</pre>
+
+<h3> Test Polly</h3>
+
+<pre>make check-polly</pre>
+
+<h3>Building Polly Without LLVM</h3>
+It is also possible to build Polly without
+also building LLVM. All you need is an installed version of LLVM or a previous
+build. To configure Polly to use a pre-built LLVM, set the
+<code>-DCMAKE_PREFIX_PATH</code> option:
+
+<pre>cmake -DCMAKE_PREFIX_PATH=${LLVM_PREFIX}/lib/cmake/llvm</pre>
+
+To run unittests, however, you need to have the LLVM source directory around.
+Polly will use the <code>llvm-config</code> of the LLVM you're building against
+to guess the location of the source directory. You may override autodetected
+location by setting the <code>-DLLVM_SOURCE_ROOT</code> option.
+
+<h3> Troubleshooting</h3>
+
+<p>If you get an error in one of the python files, your system probably uses python3
+as default python interpreter. This is the case, for instance, under Arch Linux.
+To solve this issue, run <code>cmake</code> again, but with the added argument:
+<code>-DPYTHON_EXECUTABLE=/usr/bin/python2</code> (replace <code>/usr/bin/python2</code>
+with the location of the python2 interpreter under your system).
+
+<pre>cmake -DCMAKE_PREFIX_PATH=${ISL_INSTALL} -DPYTHON_EXECUTABLE=/usr/bin/python2 ${LLVM_SRC}</pre>
+
+</div>
+</div>
+
+</body>
+</html>
diff --git a/final/www/google1242f26b67e33344.html b/final/www/google1242f26b67e33344.html
new file mode 100644
index 0000000..1cb18f4
--- /dev/null
+++ b/final/www/google1242f26b67e33344.html
@@ -0,0 +1 @@
+google-site-verification: google1242f26b67e33344.html
\ No newline at end of file
diff --git a/final/www/hangouts.html b/final/www/hangouts.html
new file mode 100644
index 0000000..cfdcb98
--- /dev/null
+++ b/final/www/hangouts.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html lang="en-US">
+    <head>
+        <meta charset="UTF-8">
+        <meta http-equiv="refresh" content="1; url=https://hangouts.google.com/hangouts/_/event/cj22k9t0q6sbhlr21g8kcha0r8g?hl=en-GB&authuser=0">
+        <script type="text/javascript">
+            window.location.href = "https://hangouts.google.com/hangouts/_/event/cj22k9t0q6sbhlr21g8kcha0r8g?hl=en-GB&authuser=0"
+        </script>
+        <title>Page Redirection</title>
+    </head>
+    <body>
+        <!-- Note: don't tell people to `click` the link, just tell them that it is a link. -->
+        If you are not redirected automatically, follow this <a href='https://hangouts.google.com/hangouts/_/event/cj22k9t0q6sbhlr21g8kcha0r8g?hl=en-GB&authuser=0'>link to Polly Hangouts</a>.
+    </body>
+</html>
diff --git a/final/www/images/GEMM_double.png b/final/www/images/GEMM_double.png
new file mode 100644
index 0000000..dfdf17e
--- /dev/null
+++ b/final/www/images/GEMM_double.png
Binary files differ
diff --git a/final/www/images/LLVM-Passes.xml b/final/www/images/LLVM-Passes.xml
new file mode 100644
index 0000000..9c18531
--- /dev/null
+++ b/final/www/images/LLVM-Passes.xml
@@ -0,0 +1 @@
+<mxfile type="device" userAgent="Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0" version="5.2.8.3" editor="www.draw.io"><diagram>7Vtdd+I2EP01PKYHLCDZxwSSNOdkT3NCu20fBQhQ11iuLEKyv35H8sgfIMCJjUib8AB4NOhjpDtzNRItMlg+30oaL76KKQtbQXv63CLDVhB0SL8DH1rykkou2l9SwVzyKSrlghH/wVDYRumKT1lSUlRChIrHZeFERBGbqJKMSinWZbWZCMutxnRuW8wFowkNt6V/8qla4CiCfi7/lfH5wrbc6eP4xnTyfS7FKsL2WgGZmVdavKS2LjNQcg1GlEJANfrb8nnAQm1Ia6PUGjc7SrNOShZhR/b/gHTTXzzRcIUDTQWJerEjN31n+gedFrlaL7hio5hOdOka5hpkC7UMsXhKk0Wmqx8eqFJMRkYStLsgjUPKozMhaaQtfjWXdMqhuwMRCglqkYi0eMbD0IrAZDc3171rAnLsL5OK2bW1PWgjwhHfMrFkSr6ACv4AbdLGlUh6+LzO57VnZYvCnAZtFFJcS/Os6tzE8AWt7La4bbxgYDaFlYaPQqqFmIuIhte59Gqykk+ZVfP5aJdtz565+qvw/W+t8ktPP0XQS12kf2Ee8rJ/mFIviDe6UgJEeSfuhYAJNjWm3dZ93W92GJpYSbM8tHERqlTOGWqZJbc9OZKFVPGncu21LH3h2dLn787U3myNbZfcSD+EXlzNBHS5OAn9f1fau5mCs8QY4xIUOv34OS+Eb3P9eX//7autaSyt9O7RyqBfaQNpwbbq1hJIFjTWXyOh9HwfcGdp/4baiOi3wF2llmnUBwVk2wddOFxQpwkX1MHI9EFcEIa4Ii5M0PYAC1d0fSUsui5YZOvcCgYUwiYHtsJ/wAhEVMBHplMZM2fQ7le2DB7ZHL7Bk0vhLkogZC/HHKL1TqXBze2IL+OQz7R5HUr1yIZFJGMw4NqQ7PR7ZUx2tzHZsTgtgtICtRYmfQer02ISLV3EZMcwTx+8wPbHl6lhtAVbm7JT2zrfa7zN1uanl9LEwkwhFjxSSaHmBy3IAdb/shH0+hubkwP6HQRkPs9pD/JZz4ZSzTv7puJ7CaJZJd5XAjF+xwPqsG1HKNwKUPViowk4OiYZcwXt32K9JveGPleULAcyrOtRKAq0cWe8Q7U/omTN1WRxUHHIQlapPimMMbXsOEH0BWZLrBuIor1NZuuKoq7ddSNR9PxDRVHMPRXxbGDmAc7Y9PGZrU7BUVjqbSSSk2b47f+PvhJLTU8BPEfasGngGXRVAp6HSGqz0qfYVNq2j4+9uygEfOjVXh1s9QEx1sOqj4euXf+WPVq7FfFgg1URD8hK680R+scPEojSvdvGHsNX7tE2fnxq+Xs6PIhFMZvwrWRLMS68mm82A93KtQSuWgqU8xucoQmZDfAQj+WJkny82q88un+oVvNh8zkD/HFMWmkO3xEBPz8lD0hB/3kQUH26vtiM/ilOAoKPdRLgOgrwRtv8HQY8QLJAD6FwKACE6vNA4LXQtETQ3hM493geQPBE9URJ6g1omsTlkbHpSE56uylQITmJoDo2gXOB822AHU1EPITsItyF2s3IQOcumol9GnCdZxUyyKLyJYxBZ2J2OYAkvEz2NDaAO2G3DPaTe5lfffhLUG9g+9gunwYS6w0Oob+RwEx8n1F5ALgjW+ktXekvX/mfzplk5HNfyHPlTBrJIR4/eY8EFFe9LvEf1LyteTuX7+N40weFcHmYuvT+TSfdGW4QR12ci10n3Zv6PYwhu/SzHPAb9Tf6U/sknRzjdNeZBziLNQ+D94QbFkGGjMoSMXt1sgbcpZYXN/tKiu9sz4VkFMHOaq67MIFVCS6fXGnnqzdcl1iw5NOpgZXLiQvQnumcDxkuQA+2LJWuTzdx0wnA6Fo+RTefpY2aTo2T46fGrSuynqnklgpuyhYe+V6u69qFtyCAQfVDXfDvb+TUXDf8nUm1Rm74d097v8x/3E3vEJ3oNp9t/HPv/rl3z/C/Ed8qZ+6a2btjUv0UZGjMZkKysyc8YyvtQz+J0eHLazYoWJ5sb6AWFg6xXLomMYLH/H9+KefO/zlJrn8C</diagram></mxfile>
\ No newline at end of file
diff --git a/final/www/images/PollyArchitecture.xml b/final/www/images/PollyArchitecture.xml
new file mode 100644
index 0000000..deb9ade
--- /dev/null
+++ b/final/www/images/PollyArchitecture.xml
@@ -0,0 +1 @@
+<mxfile type="device" userAgent="Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0" version="5.2.8.1" editor="www.draw.io"><diagram>3Vppk+I4D/41fIQiB9fHvpidqu7armVq9t2P7uAO3glx1jENzK8fOZZz0xwJxzsUBbFsHNnSIz1W6DgPy80XQaLFC5/ToGP355uO89ix7cnAgU8l2GrBYDjUAl+wuRZZmWDGflIU9lG6YnMaFwZKzgPJoqLQ42FIPVmQESH4ujjsnQfFu0bEN3fMBDOPBFXp32wuF1o6tnEVSv4HZf7C3NkaTnTPG/F++IKvQrxfx3bek5fuXhIzV7JQ5wn2UHAO06ir5eaBBmofzR7p3Zju6E2VFDRERT7/AWofy61ZJ53DsrHJhVxwn4ckeMqk98laqJqgD62FXAZwacEl3TD5v9z1P2pIb6BaoRRb1aV+kTSyvn+plFu0N1lJDqLsvs+cRzhjdWm42pivhIfaQzvxDCJ8iqMGWqTWlfsZbscXypcU1IEBggZEso+iuQl6jZ+OyzYTLnA/6/cWdfkgwQon7djDALS6f+ewhPyuD/9bKYsnHd042Ys7GGANo03WCVe++n5+/v5iZnoTRvr1LyMDvfQNdEfFwvGCROoy5FKZc71gks4ikmzhGrBbNKrW5tGawHUUEBZ2fUH0PtQZ44MKSRHzOzba9CKwMR7YQ5xhnUMXDlnkgdVHYRPTYCz6TUyjUNSqaUb9Uck2/V4/97qgpVyc46gI5a3ERxKg1C7tDVf9nlsIWKbvlQoG+lKRj1tpfCsGMRqalAVufXhMi6XgP9J8AhY5LMq51ShnocUuH+ZQmdax9MoD0KOMJeQVh8EJFAV6oDzCAMsL+Ar03ocsjaY3taLmaHIqkQ7bOfxYxs9bB9D4Mhm+1SzeesrGn75ylnikMYzZXzQMGKo3sl3LGU3g0nENZTUzarzhJCULpFodZJQBguaMUa1oolGBhZUCmNN+ACuZ7lCLF3hbK0a/E0lKTAdEynrxET6BqqUEet/4sab9mW9oDU72lJroWvKczBWURQ6KbL6gNGyDwzml0Da29hAFCw8khUBnAmKTOGchWH+bo4zJGnlM4Bovn+SNMq1n+bvZN+j7orxxR04vM4Bb8v+BhYE89f99RPl8/m9c6NYT/V7nxb114dBhMrE7tkfFI4nTn3yaq/dn/0GJlu2bcUf2r8zbTG8dAdrgGMY1P0sdhhazZVL9ynuAAgGD8tddwPwQZFJZNpU+kzcavPKYScZV7xuXki9hQKA67tOS1wMPuDo/ZUUv5z652V0c6SqdcjxiGu9so7xRD4H2QkpV3oPwMYW3Nw+dHoMC3zsDrxU9D+5oT+dEEvhScsjr03X0k/Nld04/aMAjKrqqoxtDBLWnA5Wsp8NR17LHvSj028iAhribCDCpYr6O2xtZI8gfQA7+7yzc32thMNY24nCRnI+mdCMF8WSbNp2UbVo9sJ3Lps4pNObIekc+pu9hNJeta5giRp7ymHx5Bc6D2rTOeR4Tfy7zmkcawW7T0IOnHEfXNw5iPVsYz9ctAKRcu7VGNRWNOqJjyoSNEHJKRaPJ2fmTo/PlEYKLL5T+8EHTFRCC2rSOkJm3oPNVwFQ4v20ouMbNEQp1tb1zIcE9hfI3yBWl829vCNWJQsZQbpw0q6Xzi4IEAZEHCZLhK2AElWkdI99YHh9ZHvkORIsL9hOWAcTt1uFjKqFXySSnPP1ukEl2c62LQ8RsaSGPYDRvuex+dAV2iKcYdAlk1TuP24YP1A5vXH81G9U+CaRkDp0P8DyriuGngC1ZWEBwvgB24+zQ5MArpMTU11utguWzYEoAKyhWPe1WgGvy2PXInltXbTgSCW4dEv6Ec8/L66Fefdn6bun5hjOo+nLdXx/Mzxrt9/mzEzK62vyUkb3rZCjjbgUSd7X/crnVWsDs64vGwO14Z02d6lzeaYCQ25AXKokubdzSprimfYlNOX/xrvRYvwTZ0nlskraveyDTj/Jv5EBmlGmd0VWZ2l0cr5ZRPYv7BkXrH2CPk+ld+pemLZwDoVh+cZ5nlXieM8TwnCd65u8RDYkeNLM/RWsan/3L3Hn6BQ==</diagram></mxfile>
\ No newline at end of file
diff --git a/final/www/images/architecture.png b/final/www/images/architecture.png
new file mode 100644
index 0000000..c540e72
--- /dev/null
+++ b/final/www/images/architecture.png
Binary files differ
diff --git a/final/www/images/header-background.png b/final/www/images/header-background.png
new file mode 100644
index 0000000..d736b99
--- /dev/null
+++ b/final/www/images/header-background.png
Binary files differ
diff --git a/final/www/images/iit-madras.png b/final/www/images/iit-madras.png
new file mode 100644
index 0000000..caf90ab
--- /dev/null
+++ b/final/www/images/iit-madras.png
Binary files differ
diff --git a/final/www/images/osu.png b/final/www/images/osu.png
new file mode 100644
index 0000000..154a04b
--- /dev/null
+++ b/final/www/images/osu.png
Binary files differ
diff --git a/final/www/images/performance/parallel-large.png b/final/www/images/performance/parallel-large.png
new file mode 100644
index 0000000..76261bb
--- /dev/null
+++ b/final/www/images/performance/parallel-large.png
Binary files differ
diff --git a/final/www/images/performance/parallel-small.png b/final/www/images/performance/parallel-small.png
new file mode 100644
index 0000000..3c9f6ba
--- /dev/null
+++ b/final/www/images/performance/parallel-small.png
Binary files differ
diff --git a/final/www/images/performance/sequential-large.png b/final/www/images/performance/sequential-large.png
new file mode 100644
index 0000000..5c88354
--- /dev/null
+++ b/final/www/images/performance/sequential-large.png
Binary files differ
diff --git a/final/www/images/performance/sequential-small.png b/final/www/images/performance/sequential-small.png
new file mode 100644
index 0000000..94b248d
--- /dev/null
+++ b/final/www/images/performance/sequential-small.png
Binary files differ
diff --git a/final/www/images/pollylabs.png b/final/www/images/pollylabs.png
new file mode 100644
index 0000000..d7b1555
--- /dev/null
+++ b/final/www/images/pollylabs.png
Binary files differ
diff --git a/final/www/images/sys-uni.png b/final/www/images/sys-uni.png
new file mode 100644
index 0000000..e6b84e1
--- /dev/null
+++ b/final/www/images/sys-uni.png
Binary files differ
diff --git a/final/www/images/uni-passau.png b/final/www/images/uni-passau.png
new file mode 100644
index 0000000..4bbfa21
--- /dev/null
+++ b/final/www/images/uni-passau.png
Binary files differ
diff --git a/final/www/images/video-summit-2011.png b/final/www/images/video-summit-2011.png
new file mode 100644
index 0000000..dc72e7c
--- /dev/null
+++ b/final/www/images/video-summit-2011.png
Binary files differ
diff --git a/final/www/index.html b/final/www/index.html
new file mode 100644
index 0000000..5af3856
--- /dev/null
+++ b/final/www/index.html
@@ -0,0 +1,450 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+          "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+  <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Polly - Polyhedral optimizations for LLVM</title>
+  <link type="text/css" rel="stylesheet" href="menu.css">
+  <link type="text/css" rel="stylesheet" href="content.css">
+  <script src="video-js/video.js" type="text/javascript" charset="utf-8"></script>
+  <script type="text/javascript">
+    VideoJS.setupAllWhenReady();
+  </script>
+
+  <!-- Include the VideoJS Stylesheet -->
+  <link rel="stylesheet" href="video-js/video-js.css" type="text/css" media="screen" title="Video JS">
+</head>
+<body>
+<div id="box">
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+  <!--*********************************************************************-->
+  <h1>About Polly</h1>
+  <!--*********************************************************************-->
+
+  <p> Polly is a high-level loop and data-locality optimizer and optimization
+  infrastructure for LLVM. It uses an abstract mathematical representation based
+  on integer polyhedra to analyze and optimize the memory access pattern of a
+  program. We currently perform classical loop transformations, especially
+  tiling and loop fusion to improve data-locality. Polly can also exploit
+  OpenMP level parallelism, expose SIMDization opportunities. Work has also be
+  done in the area of automatic GPU code generation.</p>
+
+  For many users, however, it's not the existing optimizations in Polly that are
+  of most interest, but the new analyses and optimizations enabled by the Polly
+  infrastructure. At
+  <a href="http://polyhedral.info">polyhedral.info</a> you can get an idea of
+  what has already been done and what is possible in the context of polyhedral
+  compilation.
+
+  <!--=====================================================================-->
+  <h2>News</h2>
+  <!--=====================================================================-->
+
+  <table id="news">
+  <tr><td><b>2017</b></td></tr>
+  <tr><td width="120"><p>September</p></td>
+  <td>
+    <h4>High-Performance Generalized Matrix Multiplication</h4>
+    Polly automatically detects and optimizes generalized matrix
+    multiplication, the computation C &larr; &alpha; &otimes; C &oplus; &beta;
+    &otimes; A &otimes; B, where A, B, and C are three appropriately sized
+    matrices, &oplus; and &otimes; operations are originating from the
+    corresponding matrix semiring, and &alpha; and &beta; are constants, and
+    beta is not equal to zero. It allows to obtain the highly optimized form
+    structured similar to the expert implementation of GEMM that can be found
+    in GotoBLAS and its successors.
+    <h4>The performance evaluation of GEMM</h4>
+    <img src="images/GEMM_double.png" /><br />
+  </td>
+  <tr><td><b>2017</b></td></tr>
+  <tr><td width="120"><p>January</p></td>
+  <td>
+  <a href="http://impact.gforge.inria.fr/impact2017">IMPACT 2017</a> program
+  announced. Join IMPACT 2017 on January 23rd in Stockholm <a
+  href="https://www.hipeac.net/2017/stockholm/">@HiPEAC'17</a>.
+  </td>
+  </tr>
+  <tr><td><b>2016</b></td></tr>
+  <tr><td width="120"><p>August</p></td>
+  <td>
+  <a href="http://impact.gforge.inria.fr/impact2017">IMPACT 2017</a> the 7th
+  International Workshop on Polyhedral Compilation Techniques will take place
+  at January 23-25, 2017 together with HiPEAC 2017 in Stockholm, Sweden. It is
+  a great opportunity to discuss and present work on Polyhedral Compilation,
+  including work on Polly.
+  </td>
+  </tr>
+  <tr><td width="120"><p>April</p></td>
+  <td>
+    A source checkout that contains Polly now provides Polly functionality
+    by default in clang/opt/bugpoint without the need to load an additional
+    module.
+  </td>
+  </tr>
+  <tr><td><b>2015</b></td></tr>
+  <tr><td width="120"><p>July</p></td>
+  <td>
+    <h4>AST Generation Paper published in TOPLAS</h4>
+    The July issue of TOPLAS contains a 50 page discussion of the AST
+    generation techniques used in Polly. This discussion gives not only an
+    in-depth description of how we (re)generate an imperative AST from our
+    polyhedral based mathematical program description, but also gives
+    interesting insights about:
+    <ul>
+      <li><b>Schedule trees:</b> A tree-based mathematical program description
+      that enables us to perform loop transformations on an abstract level,
+      while issues like the generation of the correct loop structure and loop
+      bounds will be taken care of by our AST generator.
+      <li><b>Polyhedral unrolling:</b> We discuss techniques that allow the
+      unrolling of non-trivial loops in the context of parameteric loop bounds,
+      complex tile shapes and conditionally executed statements. Such unrolling
+      support enables the generation of predicated code e.g. in the context of
+      GPGPU computing.
+      <li><b>Isolation for full/partial tile separation:</b> We discuss native
+      support for handling full/partial tile separation and -- in general --
+      native support for isolation of boundary cases to enable smooth code
+      generation for core computations.
+      <li><b>AST generation with modulo constraints:</b> We discuss how modulo
+      mappings are lowered to efficient C/LLVM code.
+      <li><b>User-defined constraint sets for run-time checks</b> We discuss how
+      arbitrary sets of constraints can be used to automatically create run-time
+      checks that ensure a set of constrainst actually hold. This feature is
+      very useful to verify at run-time various assumptions that have been taken
+      program optimization.
+    </ul>
+
+   <a href="http://www.grosser.es#pub-polyhedral-AST-generation">
+   <em>Polyhedral AST generation is more than scanning polyhedra</em></a><br />
+    Tobias Grosser, Sven Verdoolaege, Albert Cohen<br />
+    ACM Transations on Programming Languages and Systems (TOPLAS), 37(4),
+    July 2015
+
+    <br>
+    <br>
+    <br>
+    <br>
+  </td>
+  </tr>
+  <tr><td width="120"><p>February</p></td>
+  <td>
+    <h4>Polly allows now non-affine subregions</h4>
+    Data-dependent or floating point conditionals inside a SCoP can now be
+    overapproximated in order to increase the applicability on general purpose
+    code.
+  </td>
+  </tr>
+  <tr><td><b>2014</b></td></tr>
+  <tr><td width="120"><p>August</p></td>
+  <td>
+  <h4>Polly drops the support of ScopLib and the external optimizer PoCC</h4>
+  The support for ScopLib as an exchange format has been removed as recent
+  versions of clan, candl and pluto all support the OpenScop exchange format.
+
+  The support of the external optmizer PoCC has been dropped in favor of the
+  isl optimizer (default) and the still available pluto support.
+  </td>
+  </tr>
+  <tr><td><b>2014</b></td></tr>
+  <tr><td width="120"><p>June</p></td>
+  <td>
+  <h4>Polly can be built without GPL licensed software</h4> After Sebastian
+  Pop's
+  and David Peixotto's (both Qualcomm) recent <a
+  href="http://repo.or.cz/w/isl.git/commit/60703e3ee89b9d5d4d1afb6a3f611292c0884574">commit</a>
+  to isl, isl's latest development version can be built with imath instead of
+  GMP. With both CLooG and gmp having become optional, the last obilgatory
+  dependency to GPL licensed software has been removed. Now Polly only depends
+  on isl (and the included imath), which are both MIT licensed.
+  </td>
+  </tr>
+  <tr><td width="120"><p>April</p></td>
+  <td>
+  <h4>Polly Phone Call - 23April</h4>
+  We had a polly phone call about delinearizing array accesses (II)<a
+  href="https://docs.google.com/document/d/1IZewI8Up0iEkCNIPr6gVtwJxF7RV6KmXkdwOBM_Q5Cs/edit?usp=sharing ">Meeting notes</a> are available online.
+  <h4>Polly Phone Call - 17th April</h4>
+  We had a polly phone call about delinearizing array accesses <a
+  href="https://docs.google.com/document/d/14d3ehkH2MsvBdqsEOSYjysH0Ztyzb75Lp843hnxh2IA/edit?usp=sharing">Meeting notes</a> are available online.
+  <h4>Polly Phone Call - 10th April</h4>
+  We had a polly phone call. <a
+  href="https://docs.google.com/document/d/12W-qZjiZGEQ_lVrob4OzvKJI3EooonC-ap1b9f9KCUE/edit?usp=sharing">Meeting notes</a> are available online.
+  <h4>Polly Phone Call - 4th April</h4>
+  We had a polly phone call. <a
+  href="https://drive.google.com/folderview?id=0B7OMOXTgCYIUWkpJbWVJcW04ams&usp=sharing">Meeting notes</a> are available online.
+  </td>
+  </tr>
+  <tr><td width="120"><p>March</p></td>
+  <td>
+  <h4>Static link Polly into tools</h4> Polly can now be configured with 'cmake
+  -D LINK_POLLY_INTO_TOOLS:Bool=ON' to be statically linked in the tools (opt,
+  bugpoint, and clang.) This makes it easier to use polly without having to load
+  a shared library, and it also reduces the complexity of compiling Polly on
+  Windows.
+  </td>
+  </tr>
+  <tr><td width="120"><p>February</p></td>
+  <td>
+  <h4>Polly presentation at FOSDEM 2014</h4> Polly was <a
+  href="https://fosdem.org/2014/schedule/event/polly/">presented</a> at the
+  FOSDEM LLVM developer's meeting.
+  <h4>New LLVM test-suite buildbots</h4>
+  The set of <a href="http://lab.llvm.org:8011/console?category=polly">Polly
+  buildbots</a> has been extended. We now have 16 new blades that track
+  correctness and performance when compiling the LLVM test-suite. For now five
+  of them are used to provide <a
+  href="http://llvm.org/perf/db_default/v4/nts/22463">fine granularity
+  reports</a> (almost per-commit)
+  for 'clang -O3' (no polly). We also have six machines that track different
+  configurations of polly.
+  </td>
+  </tr>
+  <tr><td width="120"><p>January</p></td>
+  <td>
+  <h4>islplot released</h4>
+  <a href="https://github.com/tobig/islplot">islplot</a> is a library that
+  generates illustrations of integer sets and maps. It relies on <a
+  href="http://repo.or.cz/w/isl.git">isl</a> to model the integer sets and uses the <a
+  href="https://pypi.python.org/pypi/islpy">islpy</a> Python bindings to access
+  them. Plotting is performed with <a
+  href="http://matplotlib.org">matplotlib</a>. The following <a
+  href="http://nbviewer.ipython.org/github/tobig/islplot/blob/master/notebooks/islplot-examples.ipynb">
+  Examples</a> show its use.
+  </td>
+  </tr>
+  <tr><td><b>2013</b></td></tr>
+  <tr><td width="120"><p>November</p></td>
+  <td>
+  <h4>Loop optimization BoF at upcoming LLVM conference</h4>
+  At the upcoming <a href="http://llvm.org/devmtg/2013-11/#bof5">LLVM conference
+  </a> there will be a loop optimization BoF discussing Polly and other high
+  level loop optimizers.
+  </td>
+  </tr>
+  <tr><td width="120"><p>October</p></td>
+  <td>
+  <h4>Automatic code coverage and static analysis tests</h4>
+  Sylvestre Ledru set up automatic tests for <a
+  href="http://buildd-clang.debian.net/coverage/">code coverage</a> and
+  <a href="http://buildd-clang.debian.net/scan-build/">static analysis</a>
+  which run at least once a day and which include results for Polly.
+  <h4>Move to CLooG 0.18.1 and isl 0.12.1</h4>
+  With the move to an isl 0.12 version Polly can be compiled without the
+  need to link directly to GMP (if isl is used for code generation). Currently
+  isl is still internally using GMP, but private patches exist to also remove
+  this dependency. Without the use of GMP, a <b>GPL free</b> version of Polly
+  is possible.
+  </td></tr>
+
+  <tr><td><b>2012</b></td></tr>
+  <tr><td width="120"><p>December</p></td>
+  <td>
+  <h4> New publication in the PPL Journal
+     </h4>
+
+      We published a journal version of the Polly paper named
+      <em>
+      Polly - Performing polyhedral optimizations on a low-level intermediate
+      representation</em> in the Parallel Processing Letters 2012.
+  </td></tr>
+  <tr><td width="120"><p>September</p></td>
+  <td>
+  <h4>Experimental support for the <b>new isl code generator</b></h4>
+     The code generator can be parameterized on a fine-grained
+     level. It gives direct control for example over unrolling, the amount of
+     control overhead and the code size. It can also be used to
+     create loops to handle border conditions or to perform full-partial tile
+     separation.<br />
+     We also relicensed isl under the <b>MIT license</b>. This means, with the
+     exception of GMP (LGPL), there is no other (L)GPL licensed software used in
+     Polly. The
+     use of GMP is limited to a well defined interface. Replacing it with
+     a BSD licensed replacement is a tractable engineering project we would
+     be very interested in. For more information about isl see the <a
+     href="http://www.kotnet.org/~skimo/isl/manual.pdf">isl manual</a>.
+     </p>
+  </td></tr>
+  <tr><td width="120"><p>July</p></td>
+  <td>
+  <p> Polly can now be directly linked to the <a
+href="http://pluto-compiler.sourceforge.net/">Pluto optimizer</a>. We were
+already able to perform Pluto-like optimizations with Polly, as a similar
+algorithm was added to isl half a year ago. However, being able to directly
+compare with the original implementation will not only bring in competition in
+the optimizer field. It will also allow new experiments with a cutting edge
+research tool.<br \>
+  This support was on of the outcomes of the 1-day Polly workshop and the
+  following week of joint work at IISC Bangalore and in cooperation with
+  AMD India.
+  </td></tr>
+  <td>
+  </td></tr>
+  <tr><td width="120"><p>February</p></td>
+  <td>
+  <p>Polly is an official LLVM project, reachable at <a
+  href="http://polly.llvm.org">http://polly.llvm.org</a></p>
+  </td></tr>
+  <tr><td width="120"><p>January</p></td>
+  <td>
+  <p>Improved support for the isl scheduling optimizer</p>
+  Polly can now automatically optimize all <a
+  href="http://www.cse.ohio-state.edu/~pouchet/software/polybench/">polybench
+  2.0</a> kernels without the help of
+  an external optimizer. The compile time is reasonable and we can show
+  notable speedups for various kernels.
+  </td></tr>
+
+  <tr>
+  <tr><td><b><br/>2011</b></td></tr>
+  <tr><td width="120"><p>November</p></td>
+  <td>
+  <p>
+  Talk at the <a href="http://llvm.org/devmtg/2011-11/">
+      LLVM Developer Meeting 2011</a></p>
+  New SCEV parser<br>
+  (Allows parameters in array subscript and max/signextend)
+  </td></tr>
+
+  <tr>
+  <td><p>October</p></td>
+  <td>
+  <p>Polly can use the isl schedule optimizer<br>
+    (The optimizer is similar to the one in Pluto, but it is part of isl)
+  </p>
+  </td></tr>
+
+  <tr>
+  <td><p>August</p></td>
+  <td>
+  <p>
+  <a href="example_load_Polly_into_clang.html">Use Polly as
+  clang plugin</a></p>
+  </td>
+  </tr>
+
+  <tr>
+  <td><p>July</p></td>
+  <td>
+  <p> Polly builder as part of the <a
+  href="http://lab.llvm.org:8011/console">LLVM Buildbots</a>
+  </p>
+  </td>
+  </tr>
+
+  <tr>
+  <td><p>June</p></td>
+  <td>
+  <p><a href="http://www.grosser.es">Tobias</a> is founded for
+  three years by a <a
+  href="http://research.google.com/university/relations/fellowship_recipients.html">
+  Google Europe Fellowship in Efficient Computing</a>.
+  </p>
+  </td>
+  </tr>
+
+  <tr>
+  <td><p>May </p></td>
+  <td><p><a href="http://www.grosser.es">Tobias</a>' diploma thesis and
+  Raghesh's master thesis. See our <a
+  href="publications.html">list of publications</a>.</p></td>
+  </tr>
+
+  <tr>
+  <td><p>April</p></td>
+  <td><p>Polly moves to the LLVM infrastructure (svn, bugtracker)</p></td>
+  </tr>
+
+  <tr>
+  <td><p>March</p></td>
+  <td><p>Presentation at <a
+  href="http://impact2011.inrialpes.fr/">CGO/IMPACT</a></p>
+  <p>Polly can compile
+  polybench 2.0 with vectorization and OpenMP code generation</p>
+  </td>
+  </tr>
+  <tr>
+  <td><p>Februar</p></td>
+  <td><p>pollycc - a script to automatically compile with
+  polyhedral optimizations </p></td>
+  </tr>
+
+  <tr>
+  <td><p> Januar</p></td>
+  <td><p> Basic OpenMP support, Alias analysis integration,
+  Pluto/POCC support </p></td>
+  </tr>
+
+  <tr><td><b><br>2010</b></td></tr>
+  <tr>
+  <td><p> Dezember </p></td>
+  <td><p>Basic vectorization support </p></td>
+  </tr>
+
+  <tr>
+  <td><p> November </p></td>
+  <td><p>Talk at the <a
+  href="http://llvm.org/devmtg/2010-11/">LLVM Developer Meeting</a> </p></td>
+  </tr>
+
+  <tr>
+  <td><p>October</p></td>
+  <td><p>Dependency analysis </p>
+  <p>Finished Phase 1 - Get something working </p>
+  <p>Support scalar dependences and sequential SCoPs </p>
+  </td>
+  </tr>
+
+  <tr>
+  <td><p>August</p></td>
+  <td><p>RegionInfo pass committed to LLVM</p>
+  <p>llvm-test suite compiles </p>
+  </td>
+  </tr>
+
+  <tr>
+  <td><p>July</p></td>
+  <td><p>Code generation works for normal SCoPs.  </p></td>
+  </tr>
+
+  <tr>
+  <td><p>May</p></td>
+  <td><p>The CLooG AST can be parsed.</p>
+  </td>
+  </tr>
+
+  <tr>
+  <td><p>April</p></td>
+  <td><p>SCoPs can automatically be detected. </p></td>
+  </tr>
+
+  <tr>
+  <td><p>March</p></td>
+  <td><p>The RegionInfo framework is almost completed.  </p></td>
+  </tr>
+
+  <tr>
+  <td><p>February</p></td>
+  <td><p>Translate a simple loop to Polly-IR and regenerate a loop structure
+         with CLooG works.  </p>
+  <p>ISL and CLooG are integrated.  </p></td>
+  </tr>
+
+  </tr>
+
+  <tr>
+  <td><p>January</p></td>
+  <td><p>The RegionInfo pass is finished.  </p></td>
+  </tr>
+
+  <tr><td><b><br>2009</b></td></tr>
+  <tr>
+  <td><p>End of the year</p></td>
+  <td><p>Work on the infrastructure started.  </p></td>
+  </tr>
+  </table>
+  </ul>
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/menu.css b/final/www/menu.css
new file mode 100644
index 0000000..bb70a8f
--- /dev/null
+++ b/final/www/menu.css
@@ -0,0 +1,91 @@
+/***************/
+/* page layout */
+/***************/
+
+#menu {
+        line-height: 1.3em;
+	width: 18em;
+        float: left;
+        margin-right: 3em;
+        padding: 1em;
+        background-color: #edf7ff;
+}
+/**************/
+/* menu style */
+/**************/
+
+#menu .submenu {
+	display:block;
+        padding-top: 0.2em;
+        font-bottom: 1.2em;
+}
+
+/*
+ * Color scheme
+ * blue: #556293
+ * red:  #931e24
+ * brown: #937155
+ * green: #24931e
+ */
+
+#menu label {
+	display:block;
+        color: white;
+        margin-bottom: 0.4em;
+        margin-top: 0.4em;
+	font-weight: bold;
+        font-size: 1.1em;
+	text-align: center;
+	background-color: #3b4567;
+        -webkit-border-radius: 5px;
+        -moz-border-radius: 5px;
+        border-radius: 5px;
+        padding-top: 0.2em;
+        padding-bottom: 0.2em;
+}
+
+#menu a {
+	padding:0 .2em;
+        -webkit-border-radius: 5px;
+        -moz-border-radius: 5px;
+        border-radius: 5px;
+	display:block;
+        font-weight: bold;
+	text-decoration: none;
+        color: #3b4567;
+}
+
+a.rss-item {
+        margin-bottom: -1.2em;
+}
+#menu a:visited {
+}
+
+#menu .submenu2 {
+        margin-top: 2em;
+}
+
+#menu .submenu2 label {
+	background-color: #f35555;
+}
+
+.rss-box {
+  padding: 0em;
+}
+
+li.rss-item {
+  padding-bottom: 0em;
+}
+
+.rss_item {
+  padding-top: 0em;
+}
+
+.rss-date {
+  font-size: 0.6em;
+  color: gray;
+}
+.rss-title {
+  font-size: 0.7em;
+  margin: 0px;
+}
diff --git a/final/www/menu.html.incl b/final/www/menu.html.incl
new file mode 100644
index 0000000..5459473
--- /dev/null
+++ b/final/www/menu.html.incl
@@ -0,0 +1,113 @@
+<div id="head" style="position: relative">
+<h1><span><a href="/">Polly</a></span></h1>
+<h2><span>LLVM Framework for High-Level Loop and Data-Locality
+Optimizations</span></h2>
+
+
+<p> Hexagonal tiling in 3D</p>
+
+</div>
+<div id="menu">
+  <a href="http://llvm.org">llvm.org</a>
+  <div class="submenu">
+    <label>Information</label>
+    <a href="/index.html">Overview and News</a>
+    <a href="/get_started.html">Get and Install</a>
+    </a>
+    <a href="/docs">Documentation</a>
+    <a href="/performance.html">Performance</a>
+    <a href="/publications.html">Publications</a>
+    <a href="/contributors.html">Contributors</a>
+    <a href="/todo.html">TODO</a>
+    <a href="/changelog.html">ChangeLog</a>
+    <a href="/projects.html">Open Projects</a>
+  </div>
+
+  <div class="submenu">
+    <label>Development </label>
+    <a href="http://lists.llvm.org/mailman/listinfo/llvm-commits">
+      Mailing List (patches)
+    </a>
+    <a href="http://groups.google.com/group/polly-dev">Mailing List (discussion)</a>
+    <a href="/bugs.html">Bug Reports</a>
+    <a href="http://lab.llvm.org:8011/console?category=polly">Buildbot</a>
+    <a href="http://lab.llvm.org:8080/coverage/coverage-reports/polly/index.html">Code Coverage</a>
+    <a href="http://buildd-clang.debian.net/scan-build/">Static analysis</a>
+    <a href="/doxygen/">Doxygen</a>
+    <a href="https://github.com/llvm-mirror/polly">Source @ GitHub</a>
+  </div>
+
+  <div class="submenu">
+    <label>Resources</label>
+    <br>
+    <a href="https://www.pollylabs.org"><img style="padding-left: 3.5em;
+    padding-right: 1em; width:10em" src="/images/pollylabs.png" /></a>
+    <div class="container" style="width: 240px">
+      <div class="inner_pollylabs" style="width: 240px"></div>
+    </div>
+    <a href="https://www.polyhedral.info">polyhedral.info</a>
+    <div class="container" style="width: 240px">
+      <div class="inner_polyinfo" style="width: 240px"></div>
+    </div>
+    <br>
+  </div>
+</div>
+
+<script>
+  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+  ga('create', 'UA-66123869-2', 'auto');
+  ga('send', 'pageview');
+
+</script>
+
+<script
+src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
+
+<script>
+
+$(document).ready(function() {
+    
+    var yql =
+    "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20rss%20where%20url%3D%22http%3A%2F%2Fpollylabs.org%2Frss.xml%22%20LIMIT%205&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys";
+    
+    $.getJSON(yql, function(res) {
+	str = "<div class=\"rss-box\"><ul>";
+	for (var i = 0; i < res.query.count; i++) {
+	  var it = res.query.results.item[i];
+          var date = it.pubDate.substr(5, 11);
+	  str = str + "<li class=\"rss-item\" ><a href=\"" + it.link + "\">";
+	  str = str + "<span class=\"rss-title\">" + res.query.results.item[i].title + "</span> ";
+	  str = str + "<span class=\"rss-date\">(" + date + ")</span>";
+          str = str + "</a></li>";
+	}
+	str = str + "<li class=\"rss-item\"><a href=\"http://pollylabs.org/blog.html\"><span class=\"rss-title\"> ...  more news </span></a></li>";
+	str = str + "</ul></div>";
+	$( ".inner_pollylabs" ).append(str);
+    }, "jsonp");
+
+    var yql_polyinfo =
+    "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20rss%20where%20url%3D%22http%3A%2F%2Fpolyhedral.info%2Frss.xml%22%20LIMIT%205&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys";
+    
+    $.getJSON(yql_polyinfo, function(res) {
+	str = "<div class=\"rss-box\"><ul>";
+	for (var i = 0; i < res.query.count; i++) {
+	  var it = res.query.results.item[i];
+          var date = it.pubDate.substr(5, 11);
+	  str = str + "<li class=\"rss-item\" ><a href=\"" + it.link + "\">";
+	  str = str + "<span class=\"rss-title\">" + res.query.results.item[i].title + "</span> ";
+	  str = str + "<span class=\"rss-date\">(" + date + ")</span>";
+          str = str + "</a></li>";
+	}
+	str = str + "<li class=\"rss-item\"><a href=\"http://polyhedral.info/blog.html\"><span class=\"rss-title\"> ...  more news </span></a></li>";
+	str = str + "</ul></div>";
+	$( ".inner_polyinfo" ).append(str);
+	console.log(str);
+    }, "jsonp");
+    
+});
+
+</script>
diff --git a/final/www/performance.html b/final/www/performance.html
new file mode 100644
index 0000000..300a188
--- /dev/null
+++ b/final/www/performance.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+          "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head> <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Polly - Performance</title>
+  <link type="text/css" rel="stylesheet" href="menu.css">
+  <link type="text/css" rel="stylesheet" href="content.css">
+</head>
+<body>
+<div id="box">
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+<h1>Performance</h1>
+
+<p>To evaluate the performance benefits Polly currently provides we compiled the
+<a href="http://www.cse.ohio-state.edu/~pouchet/software/polybench/">Polybench
+2.0</a> benchmark suite.  Each benchmark was run with double precision floating
+point values on an Intel Core Xeon X5670 CPU @ 2.93GHz (12 cores, 24 thread)
+system. We used <a href="http://pocc.sf.net">PoCC</a> and the included <a
+href="http://pluto-compiler.sf.net">Pluto</a> transformations to optimize the
+code. The source code of Polly and LLVM/clang was checked out on 
+25/03/2011.</p>
+
+<p>The results shown were created fully automatically without manual
+interaction. We did not yet spend any time to tune the results. Hence
+further improvments may be achieved by tuning the code generated by Polly, the
+heuristics used by Pluto or by investigating if more code could be optimized.
+As Pluto was never used at such a low level, its heuristics are probably
+far from perfect. Another area where we expect larger performance improvements
+is the SIMD vector code generation. At the moment, it rarely yields to
+performance improvements, as we did not yet include vectorization in our
+heuristics. By changing this we should be able to significantly increase the
+number of test cases that show improvements.</p>
+
+<p>The polybench test suite contains computation kernels from linear algebra
+routines, stencil computations, image processing and data mining. Polly
+recognices the majority of them and is able to show good speedup. However,
+to show similar speedup on larger examples like the SPEC CPU benchmarks Polly
+still misses support for integer casts, variable-sized multi-dimensional arrays
+and probably several other construts. This support is necessary as such
+constructs appear in larger programs, but not in our limited test suite.
+
+<h2> Sequential runs</h2>
+
+For the sequential runs we used Polly to create a program structure that is
+optimized for data-locality. One of the major optimizations performed is tiling.
+The speedups shown are without the use of any multi-core parallelism. No
+additional hardware is used, but the single available core is used more
+efficiently.
+<h3> Small data size</h3>
+<img src="images/performance/sequential-small.png" /><br />
+<h3> Large data size</h3>
+<img src="images/performance/sequential-large.png" />
+<h2> Parallel runs</h2>
+For the parallel runs we used Polly to expose parallelism and to add calls to an
+OpenMP runtime library. With OpenMP we can use all 12 hardware cores
+instead of the single core that was used before. We can see that in several
+cases we obtain more than linear speedup. This additional speedup is due to
+improved data-locality.
+<h3> Small data size</h3>
+<img src="images/performance/parallel-small.png" /><br />
+<h3> Large data size</h3>
+<img src="images/performance/parallel-large.png" />
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/phonecall.html b/final/www/phonecall.html
new file mode 100644
index 0000000..53f1a92
--- /dev/null
+++ b/final/www/phonecall.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+          "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+  <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Polly - Polyhedral Phone Call</title>
+  <link type="text/css" rel="stylesheet" href="menu.css">
+  <link type="text/css" rel="stylesheet" href="content.css">
+</head>
+<body>
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+  <!--*********************************************************************-->
+  <h1>Polly: Polyhedral Phone Call</h1>
+  <!--*********************************************************************-->
+
+  <p>There are irregular phone calls to discuss polyhedral topics and
+     related projects. For this we use a conference service that can be
+     reached both through SIP clients and international dial in numbers.</p>
+
+ <ul>
+ <li><b>VoIP/SIP:</b> sip:000777polyhedral@iptel.org<br />
+    <a href="http://ekiga.org">Ekiga</a> is a SIP client that works well for
+    most of us.</li>
+ <li><b>Traditional Dailin Numbers:</b><br />
+    To use your normal land line phone to connect to the conference dial
+    one of the many available <a
+    href="http://www.sipbroker.com/sipbroker/action/pstnNumbers">dial in
+    numbers</a>. When asked for the number to connect type: <em>*011497659</em>.
+    <br />
+    Attention: Some of the dial in numbers do not work reliable. If you are not
+    asked for the number you want to connect to after a couple of seconds, just
+    try another one. <br/>
+    Some selected dial in numbers:
+    <ul>
+    <li><b>USA:</b> +1-443-524-7370, +1-702-553-2797 </li>
+    <li><b>UK:</b> +44-151-601-8747, +44-115-871-8347</li>
+    <li><b>Belgium:</b> +32-4-2680133, +32-9-2980106</li>
+    </ul>
+
+    </ul> 
+  
+</div>
+</body>
+</html>
diff --git a/final/www/polly.sh b/final/www/polly.sh
new file mode 100644
index 0000000..51f3faa
--- /dev/null
+++ b/final/www/polly.sh
@@ -0,0 +1,32 @@
+#!/bin/bash -xe
+
+export BASE=`pwd`
+export LLVM_SRC=${BASE}/llvm
+export POLLY_SRC=${LLVM_SRC}/tools/polly
+export CLANG_SRC=${LLVM_SRC}/tools/clang
+export LLVM_BUILD=${BASE}/llvm_build
+
+if [ -e /proc/cpuinfo ]; then
+    procs=`cat /proc/cpuinfo | grep processor | wc -l`
+else
+    procs=1
+fi
+
+if ! test -d ${LLVM_SRC}; then
+    git clone http://llvm.org/git/llvm.git ${LLVM_SRC}
+fi
+
+if ! test -d ${POLLY_SRC}; then
+    git clone http://llvm.org/git/polly.git ${POLLY_SRC}
+fi
+
+if ! test -d ${CLANG_SRC}; then
+    git clone http://llvm.org/git/clang.git ${CLANG_SRC}
+fi
+
+mkdir -p ${LLVM_BUILD}
+cd ${LLVM_BUILD}
+
+cmake ${LLVM_SRC}
+make -j$procs -l$procs
+make check-polly
diff --git a/final/www/projects.html b/final/www/projects.html
new file mode 100644
index 0000000..7388f05
--- /dev/null
+++ b/final/www/projects.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+          "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+  <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Polly - Polyhedral optimizations for LLVM</title>
+  <link type="text/css" rel="stylesheet" href="menu.css">
+  <link type="text/css" rel="stylesheet" href="content.css">
+  <script src="video-js/video.js" type="text/javascript" charset="utf-8"></script>
+  <script type="text/javascript">
+    VideoJS.setupAllWhenReady();
+  </script>
+
+  <!-- Include the VideoJS Stylesheet -->
+  <link rel="stylesheet" href="video-js/video-js.css" type="text/css" media="screen" title="Video JS">
+</head>
+<body>
+<div id="box">
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+  <!--*********************************************************************-->
+  <h1>Open Projects</h1>
+  <!--*********************************************************************-->
+
+  LLVM Polly keeps here a list of open projects which each of themselves would
+  be a great contribution to Polly. All of these projects are meant to be self
+  contained and should take a newcomer around 3-4 months of work. The projects
+  we propose are all suiteable as <a
+  href="https://developers.google.com/open-source/gsoc/">Google Summer of
+  Code</a> projects. In case you are interested in a Google Summer of code
+  project make sure to reach out via the Polly <a
+  href="http://groups.google.com/group/polly-dev">mailing list</a> early to
+  discuss your project proposal.
+
+  <h3>Integrate Polly with the LLVM vectorizers</h3>
+  Polly is not only a self-contained optimizer, but also provides a powerful
+  dependence and other program analyses. Currently, these analyses are only used
+  for our own optimizations. However, LLVM passes such as the loop vectorizer
+  would clearly benefit from having direct access to the available Polly
+  analyses. In this project, you would define in collaboration with the LLVM
+  community and considering existing dependence analysis interface a new
+  dependence analysis interface for Polly that allows passes to directly query
+  Polly analysis. Even though this project sounds straightforward at a first
+  glance, sorting out how to actually make this happen with the current and
+  the new pass managers, understanding how and when to invalidate the Polly
+  analysis and if dependence information can be computed on-demand make this
+  still a challenging project. If successful, this project may be a great way
+  to bring features of Polly to standard -O3 optimizations.
+
+  <h3>Register tiling to obtain fast BLAS kernels with Polly</h3>
+  Even though Polly is already able to speep up compute kernels significantly,
+  when comparing to the best BLAS routines we still are at least one order of
+  magnitude off. In this project you will investigate what is needed to close
+  this performance gap. Earlier investigations have shown that register tiling
+  is one important piece towards this goal. In combination with good tile size
+  models and some back-end work, this project is shooting to make common blas
+  operations, but also many non-blas kernels competitive with vendor math
+  libraries and outperforming the code icc/gcc currently generate.
+
+  <h3>Polly support for Julia - First steps</h3>
+  <a href="http://julialang.org/">Julia</a> is a new matlab style programming
+  language that provides C like performance for scientific computing. Even
+  though Julia also translates to LLVM-IR, parsing and optimizing Julia code
+  poses new challenges that currently prevent Polly from optimizing Julia
+  code despite the clear need for optimizations such as loop-tiling for Julia.
+  In this project you will -- starting from first proof-of-concept patches --
+  integrate Polly into Julia and ensure that Julia code can benefit from the
+  same high-level loop optimizations as todays C code already does. If time
+  permits, making Polly's recent bound-check elimination logic work in Julia
+  code would allow the optimization of Julia code, even if save out-of-bound
+  checking is used.
+  <h3>Interactive Polyhedral Web Calculator</h3>
+  At the core of Polly we use the isl math library. isl allows us to describe
+  loop transformations with relatively simple higher level operations while
+  still providing the full expressiveness of integer polyhedra. To understand
+  and describe the transformations we are performing it is often very convenient
+  to quickly script example transformations in a scripting language like python.
+  isl already comes with a python binding generator, with
+  pypyjs there is a python interpreter for the web and with emscriptem isl
+  itself can also be compiled to javascript. In this project you combine all
+  these components to obtain an interactive polyhedral web calculator, that uses
+  latest web technology to nicely illustrate the integer polyhedra you obtain.
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/publications.html b/final/www/publications.html
new file mode 100644
index 0000000..b7b9e56
--- /dev/null
+++ b/final/www/publications.html
@@ -0,0 +1,236 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+          "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+  <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Polly - Publications</title>
+  <link type="text/css" rel="stylesheet" href="menu.css">
+  <link type="text/css" rel="stylesheet" href="content.css">
+</head>
+<body>
+<div id="box">
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+  <!--*********************************************************************-->
+  <h1>Publications</h1>
+  <!--*********************************************************************-->
+
+  <h2> Publications about polyhedral compilation </h2>
+  <a href="http://polyhedral.info/publications.html">polyhedral.info</a> has a
+  large list of publications related to polyhedral compilation. They are very
+  useful to get an idea of the latest developments in this area of compilation
+  as well as to understand what kind of optimizations can be built on top of
+  Polly.
+
+  <h2> Citing Polly</h2>
+
+  The canonical publication to cite Polly is:
+
+<p>
+  <em>Polly - Performing polyhedral optimizations on a low-level intermediate
+      representation </em><br />
+Tobias Grosser, Armin Groesslinger, Christian Lengauer<br />
+Parallel Processing Letters 2012 22:04<br />
+  <a href="http://www.grosser.es#pub-Polly">Paper</a>
+</p>
+
+  <h2> Publications involving Polly </h2>
+  <h3> 2016 </h3>
+  <ul>
+  <li><em>Loopy: Programmable and Formally Verified Loop Transformations</em><br />
+  Kedar Namjoshi and Nimit Singhania<br />
+  23rd Static Analysis Symposium (SAS 2016)<br />
+  <a href="http://link.springer.com/chapter/10.1007/978-3-662-53413-7_19">Paper</a>
+  </li>
+  <li><em>Input Space Splitting for OpenCL</em><br />
+  Simon Moll, Johannes Doerfert and Sebastian Hack<br />
+  25th International Conference on Compiler Construction (CC 2016)<br />
+  </li>
+  <li><em>Parallelisation automatique de programmes scientifiques pour systems
+  distribues
+  </em><br />
+  Felix-Antoine Quellet<br />
+  Master Thesis, Universite de Sherbrooke<br />
+  <a
+  href="http://savoirs.usherbrooke.ca/bitstream/handle/11143/8171/Ouellet_Felix_Antoine_MSc_2016.pdf?sequence=4">Thesis</a>
+  </li>
+  </ul>
+  <h3> 2015 </h3>
+  <ul>
+  <li><em>Polyhedral AST generation is more than scanning polyhedra</em><br />
+  Tobias Grosser, Sven Verdoolaege, Albert Cohen<br />
+   ACM Transations on Programming Languages and Systems (TOPLAS), 37(4), July
+   2015<br />
+  <a href="http://www.grosser.es#pub-polyhedral-AST-generation">Paper</a>
+  </li>
+  <li><em>On recovering multi-dimensional arrays in Polly</em><br />
+  Tobias Grosser, Sebastian Pop, J. Ramanujam, P. Sadayappan <br />
+  Impact2015 at HiPEAC, Amsterdam, The Netherlands<br />
+  Slides & Paper: <a href="http://impact.gforge.inria.fr/impact2015/">Impact 2015</a>
+  </li>
+  <li><em>Polly's polyhedral scheduling in the presence of reductions </em><br />
+  Johannes Doerfert, Kevin Streit, Sebastian Hack, Zino Benaissa<br />
+  Impact2015 at HiPEAC, Amsterdam, The Netherlands<br />
+  Slides & Paper: <a href="http://impact.gforge.inria.fr/impact2015/">Impact 2015</a>
+  </li>
+  </ul>
+  <h3> 2014 </h3>
+  <ul>
+  <li><em>
+  Lattice QCD Optimization and Polytopic Representations of Distributed Memory </em><br />
+  Michael Kruse<br />
+  Doctoral Thesis,  Ecole doctorale Informatique de Paris-Sud<br />
+  <a href="http://www.theses.fr/2014PA112198">Thesis</a>
+  </li>
+  </ul>
+  <h3> 2012 </h3>
+  <ul>
+  <li><em>KernelGen - a prototype of auto-parallelizing Fortran/C compiler for NVIDIA GPUs</em><br />
+  Dmitry Mikushin, Nikolay Likhogrud, Hou Yunqing, Sergey Kovylov<br />
+  Multi-core Workshop 2012, NCAR, Boulder, CO<br /><a
+  href="publications/kernelgen-ncar-2012-slides.pdf">Slides</a>
+  </li>
+  <li><em>KernelGen - a toolchain for automatic GPU-centric applications porting</em><br />
+  Nikolay Likhogrud, Dmitry Mikushin, Andrew Adinets<br />
+  Parallel Computational Technologies (PCT) 2012, Novosibirsk<br /><a
+  href="publications/kernelgen-pavt-2012-slides.pdf">Slides</a>
+  </li>
+  </ul>
+  <h3> 2011 </h3>
+  <ul>
+  <li><em>Polly - First Successful Optimizations - How to proceed?</em><br />
+  Tobias Grosser, Ragesh A<br />
+  LLVM Developer Meeting 2011<br /><a
+  href="http://llvm.org/devmtg/2011-11/Grosser_PollyOptimizations.pdf">Slides</a>, <a
+  href="http://llvm.org/devmtg/2011-11/videos/Grosser_PollyOptimizations-desktop.mov">Video
+  (Computer)</a>, <a
+  href="http://llvm.org/devmtg/2011-11/videos/Grosser_PollyOptimizations-mobile.mp4">Video
+  (Mobile)</a></li>
+  <li><em>A Framework for Automatic OpenMP Code Generation</em><br />
+  Raghesh A<br />
+  Masters Thesis (May 2011)<br />
+  <a
+  href="publications/raghesh-a-masters-thesis.pdf">Thesis</a>
+  </li>
+  <li><em>Enabling Polyhedral Optimizations in LLVM</em><br />
+  Tobias Grosser<br />
+  Diploma Thesis (April 2011)<br />
+  <a
+  href="publications/grosser-diploma-thesis.pdf">Thesis</a>
+  </li>
+  <li><em>Polly - Polyhedral Optimization in LLVM</em><br />
+  Tobias Grosser, Hongbin Zheng, Ragesh Aloor, Andreas Simb&uuml;rger, Armin
+  Gr&ouml;&szlig;linger, Louis-No&euml;l Pouchet<br />
+  IMPACT at CGO 2011 <br />
+  <a
+  href="publications/grosser-impact-2011.pdf">Paper</a>, <a
+  href="publications/grosser-impact-2011-slides.pdf">Slides </a>
+  </li>
+  </ul>
+  <h3> 2010 </h3>
+  <ul>
+  <li><em>Polly - Polyhedral Transformations for LLVM</em><br />
+  Tobias Grosser, Hongbin Zheng<br />
+  LLVM Developer Meeting 2010<br /><a
+  href="http://llvm.org/devmtg/2010-11/Grosser-Polly.pdf">Slides</a>, <a
+  href="http://llvm.org/devmtg/2010-11/videos/Grosser_Polly-desktop.mp4">Video
+  (Computer)</a>, <a
+  href="http://llvm.org/devmtg/2010-11/videos/Grosser_Polly-mobile.mp4">Video
+  (Mobile)</a></li>
+  </ul>
+
+  <h2>Publications used within Polly</h2>
+  <h3>Polyhedral library</h3>
+  <ul>
+  <li><em>isl: An Integer Set Library for the Polyhedral Model </em><br />
+  Sven Verdoolaege<br />
+  ICMS 2010
+  </li>
+  </ul>
+  <h3>Optimization</h3>
+  <ul>
+  <li><em>A Practical Automatic Polyhedral Parallelizer and Locality Optimizer
+          </em><br />
+  Uday Bondhugula, Alberto Hartono, J. Ramanujam, P. Sadayappan<br />
+  PLDI 2008
+  </li>
+  <li><em>Effective Automatic Parallelization and Locality Optimization using
+          the Polyhedral Model
+          </em><br />
+  Uday Bondhugula<br />
+  PhD thesis 2008
+  </li>
+  </ul>
+  <h3>Code Generation</h3>
+  <ul>
+  <li><em>Code Generation in the Polyhedral Model Is Easier Than You Think</em>
+  <br />
+  C&eacute;dric Bastoul<br />
+  PACT 2004
+  </li>
+  </ul>
+  <h2>Interesting Publications</h2>
+
+  Publications that are not yet used or implemented in Polly, but that are
+  interesting to look at either to understand general concepts or to implement
+  the corresponding ideas. This list is incomplete and papers are added as
+  we hear about them.<br />
+  <h3>GPGPU</h3>
+  <ul>
+  <li><em>Automatic C-to-CUDA Code Generation for Affine Programs</em>
+  <br />
+  Muthu Manikandan Baskaran, J. Ramanujam and P. Sadayappan<br />
+  CC 2010
+  </li>
+  <li><em>Putting Automatic Polyhedral Compilation for GPGPU to Work<em>
+  Soufiane Baghdadi, Armin Gr&ouml;&szlig;linger, and Albert Cohen. <br />
+  In Proc. of Compilers for Parallel Computers (CPC), 2010.
+  </li>
+  </ul>
+  <h3>Vectorization</h3>
+  <ul>
+  <li><em>Joint Scheduling and Layout Optimization to Enable Multi-Level
+  Vectorization</em>
+  <br />
+  Nicolas Vasilache, Benoit Meister, Muthu Baskaran, Richard Lethin<br />
+  IMPACT 2012 (upcoming)
+  </li>
+  </ul>
+  <h3>Iterative Compilation</h3>
+  <ul>
+  <li><em>Iterative optimization in the polyhedral model: Part I,
+  one-dimensional time.  </em>
+  <br />
+  Louis-No&euml;l Pouchet, C&eacute;dric Bastoul, Albert Cohen and Nicolas Vasilache<br />
+  CGO 2007
+  </li>
+  <li><em>Iterative optimization in the polyhedral model: Part II,
+  multidimensional time.  </em>
+  <br />
+  Louis-No&euml;l Pouchet, C&eacute;dric Bastoul, Albert Cohen and John Cavazos<br />
+  PLDI 2008
+  </li>
+  </ul>
+  <h3>Non-static Control</h3>
+  <ul>
+  <li><em>The Polyhedral Model Is More Widely Applicable Than You Think</em>
+  <br />
+  Mohamed-Walid Benabderrahmane, Louis-No&euml;l Pouchet, Albert Cohen,
+  C&eacute;dric
+  Bastoul.<br />
+  CC 2010
+  </li>
+  </ul>
+  <h3>Source to Source Tools</h3>
+  <ul>
+  <li><em> Polyhedral Extraction Tool</em>
+  <br />
+  Sven Verdoolaege, Tobias Grosser<br />
+  IMPACT 2012
+  </li>
+  </ul>
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/publications/grosser-diploma-thesis.pdf b/final/www/publications/grosser-diploma-thesis.pdf
new file mode 100644
index 0000000..f7e8dd3
--- /dev/null
+++ b/final/www/publications/grosser-diploma-thesis.pdf
Binary files differ
diff --git a/final/www/publications/grosser-impact-2011-slides.pdf b/final/www/publications/grosser-impact-2011-slides.pdf
new file mode 100644
index 0000000..3e60410
--- /dev/null
+++ b/final/www/publications/grosser-impact-2011-slides.pdf
Binary files differ
diff --git a/final/www/publications/grosser-impact-2011.pdf b/final/www/publications/grosser-impact-2011.pdf
new file mode 100644
index 0000000..9b79bd2
--- /dev/null
+++ b/final/www/publications/grosser-impact-2011.pdf
Binary files differ
diff --git a/final/www/publications/kernelgen-ncar-2012-slides.pdf b/final/www/publications/kernelgen-ncar-2012-slides.pdf
new file mode 100644
index 0000000..8a91611
--- /dev/null
+++ b/final/www/publications/kernelgen-ncar-2012-slides.pdf
Binary files differ
diff --git a/final/www/publications/kernelgen-pavt-2012-slides.pdf b/final/www/publications/kernelgen-pavt-2012-slides.pdf
new file mode 100644
index 0000000..ce4b832
--- /dev/null
+++ b/final/www/publications/kernelgen-pavt-2012-slides.pdf
Binary files differ
diff --git a/final/www/publications/raghesh-a-masters-thesis.pdf b/final/www/publications/raghesh-a-masters-thesis.pdf
new file mode 100644
index 0000000..2eeb193
--- /dev/null
+++ b/final/www/publications/raghesh-a-masters-thesis.pdf
Binary files differ
diff --git a/final/www/todo.html b/final/www/todo.html
new file mode 100644
index 0000000..8aa45c9
--- /dev/null
+++ b/final/www/todo.html
@@ -0,0 +1,652 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+          "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head> <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <title>Polly - Todo</title>
+  <link type="text/css" rel="stylesheet" href="menu.css">
+  <link type="text/css" rel="stylesheet" href="content.css">
+</head>
+<body>
+<div id="box">
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+<h1> TODO </h1>
+
+<h2> Overview</h2>
+<ul>
+<li><a href="#phase3">Phase 4</a></li>
+<li><a href="#phase3">Phase 3 - Improve Robustness, Interoperability and
+Optimizations (ongoing)</a></li>
+<li><a href="#llvm">Polly as a LLVM Project (Finished February 2012)</a></li>
+<li><a href="#phase2">Phase 2 - First Optimizations and Enhanced User Experience (Finished
+February 2012)</a></li>
+<li><a href="#phase1">Phase 1 - Get Something Working (Finished October 2010)</a>
+</li>
+</ul>
+<h2> Individual Phases</h3>
+
+<h3 id="phase4"> Phase 4</h3>
+<table class="wikitable" cellpadding="2">
+<p> </p>
+
+<tbody>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Infrastructure </th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left"> Move to isl C++ bindings
+</th><td align="center" class='open'> Open
+</td><td>
+</td>
+</tr>
+<th align="left"> &nbsp; &nbsp; - Add isl C++ bindings generator to isl
+</th><td align="center" class='open'> Open
+</td><td>
+</td>
+</tr>
+<tr>
+<th align="left"> Add isl as an external library to Polly SVN
+</th><td align="center" class='done'> Done
+</td><td>
+</td>
+</tr>
+<tr>
+<th align="left"> Compile-time: Speed up transformations
+</th><td align="center">
+</td><td>
+</td>
+</tr>
+<th align="left"> &nbsp; &nbsp; - Optimize isl_int for small integers
+</th><td align="center" class='done'> Done
+</td><td>
+</td>
+</tr>
+<tr>
+<th align="left"> Compile-time: Minimize SCoP detection time
+</th><td align="center" class='open'> Open
+</td><td>
+</td>
+</tr>
+<th align="left"> &nbsp; &nbsp; - Reconsider pass-ordering (move Polly later)
+</th><td align="center" class='open'> Open
+</td><td>
+</td>
+</tr>
+
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Increase coverage
+</th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+
+<tr>
+<th align="left">
+Support for Modulos
+</th><td align="center" class='done'> Done
+</td><td> Johannes
+</td></tr>
+<tr>
+<th align="left">
+Boolean Combinations
+</th><td align="center" class='done'> Done
+</td><td> Johannes
+</td></tr>
+<tr>
+<th align="left">
+Unsigned Integers
+</th><td align="center" class='done'> Done
+</td><td> Johannes
+</td></tr>
+<tr>
+<th align="left">
+Pointer Comparisions
+</th><td align="center" class='done'> Done
+</td><td> Johannes
+</td></tr>
+<tr>
+<th align="left">
+Non-affine subregions
+</th><td align="center" class='done'> Done
+</td><td> Johannes
+</td></tr>
+
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Polly as an
+analysis </th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+
+<tr>
+<th align="left">
+Model scalars dependences directly in Polly
+</th><td align="center" class='done'> Done
+</td><td>
+</td></tr>
+<tr>
+<th align="left">
+Code generate scalar dependences
+</th><td align="center" class='done'> Done
+</td><td>
+</td></tr>
+<tr>
+<th align="left">
+Model PHI dependences directly in Polly
+</th><td align="center" class='done'> Done
+</td><td>
+</td></tr>
+<tr>
+<th align="left">
+Code generate PHI dependences
+</th><td align="center" class='done'> Done
+</td><td>
+</td></tr>
+<tr>
+<th align="left"> <a href="http://llvm.org/bugs/show_bug.cgi?id=12398">Remove
+the need for independent blocks</a>
+</th><td class="done"> Done
+</td><td>
+</td></tr>
+<tr>
+<th align="left">
+Remove polly-prepare pass
+</th><td align="center" class='open'> Open
+</td><td>
+</td></tr>
+
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Correctness in
+cornercases </th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left"> <a href="http://llvm.org/bugs/show_bug.cgi?id=10381">Derive
+optimal types (instead of always using i64)</a>
+</th><td class="open"> Open
+</td><td>
+</td></tr>
+<tr>
+<th align="left"> <a href="http://llvm.org/bugs/show_bug.cgi?id=12397">Model
+integer wrapping</a>
+</th><td align="center" class='done'> Done
+</td><td> Johannes
+</td></tr
+
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Optimize Julia
+code with Polly
+analysis </th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+
+<th align="left">
+Integrate Polly into Julia
+</th><td align="center" class='open'> Open
+</td><td>
+</td></tr>
+<tr>
+<th align="left">
+Eliminate run-time bounds checks
+</th><td align="center" class='open'> Open
+</td><td>
+</td></tr>
+<tr>
+<th align="left"> &nbsp; &nbsp; - Reconsider unreachables in post-dominance tree
+</th><td align="center" class='open'> Open
+</td><td>
+</td></tr>
+
+<th align="left"> &nbsp; &nbsp; - Actually eliminate statements
+</th><td align="center" class='done'> Done
+</td><td>
+</td></tr>
+
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Improved
+Optimizations in Polly
+</th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+
+<th align="left">
+Multi-level tiling
+</th><td align="center" class='open'> Open
+</td><td>
+</td></tr>
+<tr>
+<th align="left">
+Register Tiling
+</th><td align="center" class='open'> Open
+</td><td>
+</td></tr>
+<tr>
+<th align="left">
+Full/partial tile separation for vectorization
+</th><td align="center" class='done'> Done
+</td><td>
+</td></tr>
+<th align="left">
+Loop interchange after vectorization to maximize stride-one accesses
+</th><td align="center" class='open'> Open
+</td><td>
+</td></tr>
+</table>
+
+
+<h3 id="phase3"> Phase 3 - Improve Robustness, Interoperability and
+Optimizations (ongoing)</h3>
+<table class="wikitable" cellpadding="2">
+<p> </p>
+
+<tbody>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Frontend </th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left"> Non-affine access functions
+</th><td align="center" class='done'> Done, needs testing
+</td><td>Marcello
+</td>
+</tr>
+
+
+<tr>
+<tr>
+<th align="left"> <a
+href="http://llvm.org/bugs/show_bug.cgi?id=12403">Variable-size
+multi-dimensional arrays</a>
+</th><td align="center" class='done'> Done
+</td><td>Sebastian
+</td></tr>
+<tr>
+<th align="left"> <a
+href="http://llvm.org/bugs/show_bug.cgi?id=12407">Derive information for
+the SCoP context
+</a>
+</th>
+<td align="center" class='nice'> Open
+</td><td>
+</td></tr>
+<tr>
+<th align="left"> <a href="http://llvm.org/bugs/show_bug.cgi?id=12402">Finer
+grained statements</a>
+</th><td align="center" class='nice'> Open
+</td><td>
+</td></tr>
+<tr>
+<th align="left"> Detect reductions
+</th><td align="center" class='done'>Done
+</td><td>Johannes
+</td></tr>
+<tr>
+<th align="left"> Generate code for reductions
+</th><td align="center" class='niceinprogress'>in progress
+</td><td>Johannes
+</td></tr>
+<tr>
+<th align="left"> Assume static sized arrays are only accessed in-bounds
+</th><td align="center" class='done'>Done
+</td><td>Tobias
+</td></tr>
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Optimizer </th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left"> <a href="http://llvm.org/bugs/show_bug.cgi?id=12405">Polyhedral
+dead code elimination</a>
+</th><td class="done">Done
+</td><td>
+</td></tr>
+
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Back End</th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left"> OpenMP code generation support in isl backend
+(requirement to drop CLooG)
+</th><td class="done"> Done
+</td><td> Tobias
+</td></tr>
+<tr>
+<th align="left"> Run-time alias checks
+</th><td class="done"> Done
+</td><td>Johannes
+<tr>
+<th align="left"> <a
+href="http://polly.llvm.org/documentation/gpgpucodegen.html">GPGPU Code
+Generation</a>
+</th><td class="niceinprogress">in progress
+</td><td>
+Yabin
+</td></tr>
+<tr>
+<th align="left"> <a
+href="http://polly.llvm.org/documentation/memaccess.html">Allow optimizers to
+change memory access functions</a>
+</th><td class="done"> Done
+</td><td>Johannes
+</td></tr>
+<tr>
+<th align="left"> <a href="http://llvm.org/bugs/show_bug.cgi?id=12406">Make code
+generation independent of the clast</a>
+</th><td class="done">Done
+</td><td>
+</td></tr>
+
+<tr>
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> General</th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left"> Teach bugpoint to extract regions
+</th><td class="nice"> Open
+</td><td>
+</td></tr>
+<tr>
+<th align="left"> Add <a
+href="http://www.cse.ohio-state.edu/~pouchet/software/polybench/">Polybench
+3.2</a> to the LLVM test suite
+</th><td class="done"> Done
+</td><td>
+</td></tr>
+<tr>
+<th align="left"> Build against an installed LLVM
+</th><td class="done"> Done<br />
+</td><td>
+</td></tr>
+<tr>
+<th align="left"> Setup buildbot regression testers using LNT
+</th><td class="done"> Done
+</td><td> Tobias
+</td></tr>
+</tbody></table>
+<h3 id="llvm"> Polly as a LLVM Project (Finished February 2012)</h3>
+
+<table class="wikitable" cellpadding="2">
+
+<tbody>
+<tr style="background: rgb(239, 239, 239);">
+<th>Task
+</th><th> Status
+</th><th>Owner
+</th></tr>
+<tr>
+<th align="left"> Move to LLVM SVN
+</th><td class="done" align="center">
+<a
+href="http://llvm.org/svn/llvm-project/polly"
+>http://llvm.org/svn/llvm-project/polly</a>
+</td><td> Tobias
+
+</td></tr>
+<tr>
+<th align="left"> Git mirror
+</th><td class="done" align="center">
+git://llvm.org/git/polly.git
+</td><td> Tobias
+</td></tr>
+<tr>
+<th align="left"> Commit mails
+</th><td class="done" align="center">
+llvm-commits@lists.llvm.org
+</td><td> Tobias
+</td></tr>
+<tr>
+
+<th align="left"> LLVM Bugzilla category
+</th><td class="done" align="center">
+<a href="http://llvm.org/bugs/enter_bug.cgi?product=Projects">LLVM Bugzilla</a>
+<br />
+(Product is 'Projects', Component is 'Polly')
+</td><td> Tobias
+<tr>
+<th align="left"> Website
+</th><td class="done" align="center">
+<a href="http://polly.llvm.org">http://polly.llvm.org</a>
+</td><td> Tobias
+</td></tr>
+<tr>
+<th align="left">Buildbot that runs 'make polly-test'
+</th><td class="done" align="center">
+<a href="http://lab.llvm.org:8011/console">Buildbot</a>
+</td>
+<td> Tobias, Andreas
+</td></tr>
+</th><td>
+
+</td></tr>
+</tbody></table>
+<h3 id="phase2"> Phase 2 - First Optimizations and Enhanced User Experience (Finished
+February 2012)</h3>
+<p>
+
+First optimizations to show the usefullness of Polly and enhance the user
+experience. We also try to increase the amount of code we can optimize.
+</p>
+<table class="wikitable" cellpadding="2">
+
+<tbody>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Frontend </th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<tr>
+<th align="left"> Allow parameters in access functions
+</th><td align="center" class='done'> Done
+</td><td> Tobias
+</td></tr>
+
+<tr>
+<th align="left"> Improved Scalar Evolution parsing
+</th><td align="center" class='done'> Done
+</td><td> Tobias
+</td></tr>
+<tr>
+<th align="left"> (Graphical) user feedback on Scop Detection
+</th><td align="center" class='done'> Done
+</td><td> Tobias
+</td></tr>
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Optimizer </th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left"> Dependency Analysis
+</th><td class="done" align="center"> Done
+</td><td> Tobias
+</td></tr>
+<tr>
+<tr>
+<th align="left"> Optimizer - Connect Pluto (through PoCC)
+</th><td class="done" align="center"> Done
+</td><td> Tobias
+</td></tr>
+<tr>
+<tr>
+<th align="left"> Optimizer - Add ISL internal Pluto like optimizer
+</th><td class="done" align="center"> Done
+</td><td> Tobias
+</td></tr>
+
+<tr>
+<th align="left"> Import/Export - SCoPLib 0.2 (needed for PoCC)
+</th><td class="done" align="center">Done
+
+</td><td> Tobias
+</td></tr>
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Back End</th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left">SIMD code generation for trivially vectorizable loops
+</th><td class="done">Done
+</td><td>Tobias
+</td></tr>
+<tr>
+<th align="left">OpenMP code generation
+</th><td class="done">Done
+</td><td> Raghesh, Tobias
+
+</td></tr>
+<tr>
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> General</th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left"> clang integration
+</th><td class="done" align="center"> done
+
+</td><td> Tobias
+</td></tr>
+<tr>
+<th align="left"> Commit RegionPass patch upstream
+</th><td class="done" align="center"> done
+
+</td><td> Tobias
+</td></tr>
+<tr>
+</tbody></table>
+<h3 id="phase1">Phase 1 - Get Something Working (Finished October 2010)</h3>
+<p>Create a minimal version of Polly that can transform an LLVM-IR program to
+the polyhedral model and back to LLVM-IR. No transformations are performed.
+</p>
+<table class="wikitable" cellpadding="2">
+
+<tbody>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Front End</th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+
+<th align="left"> Region detection
+</td><td class="done"> Done
+</td><td>Ether
+</td></tr>
+<tr>
+<th align="left"> Access Functions
+</td><td class="done"> Done
+</td><td>John, Ether
+</td></tr>
+<tr>
+<th align="left"> Alias sets
+</td><td class="done"> Done
+</td><td>Ether
+</td></tr>
+<tr>
+<th align="left"> Scalar evolution to affine expression
+</td><td class="done"> Done
+
+</td><td>
+Ether
+</td></tr>
+<tr>
+<th align="left"> SCoP extraction
+</td><td class="done"> Done
+</td><td>Tobias, Ether
+
+</td></tr>
+<tr>
+<th align="left"> SCoPs to polyhedral model
+</td><td class="done"> Done
+</td><td>Tobias, Ether
+</td></tr>
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Optimizer </th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left"> Define polyhedral description
+</td><td class="done"> Done
+</td><td>Tobias
+
+</td></tr>
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> Back End</th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left"> Create LLVM-IR using CLooG
+</td><td class="done"> Done
+</td><td> Tobias
+
+</td></tr>
+<tr><td colspan='4'>&nbsp;</td></tr>
+<tr><th colspan="3" style="background: rgb(239, 239, 239);"> General</th></tr>
+<tr style="background: rgb(239, 239, 239)">
+  <th width="400px"> Task </th>
+  <th width="150px"> Status </th>
+  <th> Owner </th>
+</tr>
+<tr>
+<th align="left"> Setup git repositories
+
+</td><td class="done"> Done
+</td><td> Tobias
+</td></tr>
+<tr>
+<th align="left"> Add CLooG/isl to build system
+</td><td class="done"> Done
+</td><td> Tobias
+
+</td></tr>
+
+</tbody></table>
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/video-js/video-js.css b/final/www/video-js/video-js.css
new file mode 100644
index 0000000..c9c4823
--- /dev/null
+++ b/final/www/video-js/video-js.css
@@ -0,0 +1,242 @@
+/* 
+VideoJS Default Styles (http://videojs.com)
+Version 2.0.2
+
+REQUIRED STYLES (be careful overriding)
+================================================================================ */
+/* Box containing video, controls, and download links.
+   Will be set to the width of the video element through JS
+   If you want to add some kind of frame or special positioning, use another containing element, not video-js-box. */
+.video-js-box { text-align: left; position: relative; line-height: 0 !important; margin: 0; padding: 0 !important; border: none !important;  }
+
+/* Video Element */
+video.video-js { background-color: #000; position: relative; padding: 0; }
+
+.vjs-flash-fallback { display: block; }
+
+/* Poster Overlay Style */
+.video-js-box img.vjs-poster { display: block; position: absolute; left: 0; top: 0; width: 100%; height: 100%; margin: 0; padding: 0; cursor: pointer; }
+/* Subtiles Style */
+.video-js-box .vjs-subtitles { color: #fff; font-size: 20px; text-align: center; position: absolute; bottom: 40px; left: 0; right: 0; }
+
+/* Fullscreen styles for main elements */
+.video-js-box.vjs-fullscreen { position: fixed; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: 1000; }
+.video-js-box.vjs-fullscreen video.video-js,
+.video-js-box.vjs-fullscreen .vjs-flash-fallback { position: relative; top: 0; left: 0; width: 100%; height: 100%; z-index: 1000; }
+.video-js-box.vjs-fullscreen img.vjs-poster { z-index: 1001; }
+.video-js-box.vjs-fullscreen .vjs-spinner { z-index: 1001; }
+.video-js-box.vjs-fullscreen .vjs-controls { z-index: 1003; }
+.video-js-box.vjs-fullscreen .vjs-big-play-button { z-index: 1004; }
+.video-js-box.vjs-fullscreen .vjs-subtitles { z-index: 1004; }
+
+/* Styles Loaded Check */
+.vjs-styles-check { height: 5px; position: absolute; }
+/* Controls Below Video */
+.video-js-box.vjs-controls-below .vjs-controls { position: relative; opacity: 1; background-color: #000; }
+.video-js-box.vjs-controls-below .vjs-subtitles { bottom: 75px; } /* Account for height of controls below video */
+
+/* DEFAULT SKIN (override in another file)
+================================================================================
+Using all CSS to draw the controls. Images could be used if desired.
+Instead of editing this file, I recommend creating your own skin CSS file to be included after this file,
+so you can upgrade to newer versions easier. */
+
+/* Controls Layout 
+  Using absolute positioning to position controls */
+.video-js-box .vjs-controls {
+  position: absolute; margin: 0; opacity: 0.85; color: #fff;
+  display: none; /* Start hidden */
+  left: 0; right: 0; /* 100% width of video-js-box */ 
+  width: 100%;
+  bottom: 0px; /* Distance from the bottom of the box/video. Keep 0. Use height to add more bottom margin. */
+  height: 35px; /* Including any margin you want above or below control items */
+  padding: 0; /* Controls are absolutely position, so no padding necessary */
+}
+
+.video-js-box .vjs-controls > div { /* Direct div children of control bar */
+  position: absolute; /* Use top, bottom, left, and right to specifically position the control. */
+  text-align: center; margin: 0; padding: 0;
+  height: 25px; /* Default height of individual controls */
+  top: 5px; /* Top margin to put space between video and controls when controls are below */
+
+  /* CSS Background Gradients 
+     Using to give the aqua-ish look. */
+  /* Default */ background-color: #0B151A;
+  /* Webkit  */ background: #1F3744 -webkit-gradient(linear, left top, left bottom, from(#0B151A), to(#1F3744)) left 12px;
+  /* Firefox */ background: #1F3744 -moz-linear-gradient(top,  #0B151A,  #1F3744) left 12px;
+
+  /* CSS Curved Corners */
+  border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px;
+
+  /* CSS Shadows */
+  box-shadow: 1px 1px 2px #000; -webkit-box-shadow: 1px 1px 2px #000; -moz-box-shadow: 1px 1px 2px #000;
+}
+
+/* Placement of Control Items 
+   - Left side of pogress bar, use left & width
+   - Rigth side of progress bar, use right & width
+   - Expand with the video (like progress bar) use left & right */
+.vjs-controls > div.vjs-play-control       { left: 5px;   width: 25px;  }
+.vjs-controls > div.vjs-progress-control   { left: 35px;  right: 165px; } /* Using left & right so it expands with the width of the video */
+.vjs-controls > div.vjs-time-control       { width: 75px; right: 90px;  } /* Time control and progress bar are combined to look like one */
+.vjs-controls > div.vjs-volume-control     { width: 50px; right: 35px;  }
+.vjs-controls > div.vjs-fullscreen-control { width: 25px; right: 5px;   }
+
+/* Removing curved corners on progress control and time control to join them. */
+.vjs-controls > div.vjs-progress-control {
+  border-top-right-radius: 0; -webkit-border-top-right-radius: 0; -moz-border-radius-topright: 0;
+  border-bottom-right-radius: 0; -webkit-border-bottom-right-radius: 0; -moz-border-radius-bottomright: 0;
+}
+.vjs-controls > div.vjs-time-control { 
+  border-top-left-radius: 0; -webkit-border-top-left-radius: 0; -moz-border-radius-topleft: 0;
+  border-bottom-left-radius: 0; -webkit-border-bottom-left-radius: 0; -moz-border-radius-bottomleft: 0;
+}
+
+/* Play/Pause
+-------------------------------------------------------------------------------- */
+.vjs-play-control { cursor: pointer !important; }
+/* Play Icon */
+.vjs-play-control span { display: block; font-size: 0; line-height: 0; }
+.vjs-paused .vjs-play-control span {
+  width: 0; height: 0; margin: 8px 0 0 8px;
+  /* Drawing the play triangle with borders - http://www.infimum.dk/HTML/slantinfo.html */
+  border-left: 10px solid #fff; /* Width & Color of play icon */
+  /* Height of play icon is total top & bottom border widths. Color is transparent. */
+  border-top: 5px solid rgba(0,0,0,0); border-bottom: 5px solid rgba(0,0,0,0);
+}
+.vjs-playing .vjs-play-control span {
+  width: 3px; height: 10px; margin: 8px auto 0;
+  /* Drawing the pause bars with borders */
+  border-top: 0px; border-left: 3px solid #fff; border-bottom: 0px; border-right: 3px solid #fff;
+}
+
+/* Progress
+-------------------------------------------------------------------------------- */
+.vjs-progress-holder { /* Box containing play and load progresses */
+  position: relative; padding: 0; overflow:hidden; cursor: pointer !important;
+  height: 9px; border: 1px solid #777;
+  margin: 7px 1px 0 5px; /* Placement within the progress control item */
+  border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px;
+}
+.vjs-progress-holder div { /* Progress Bars */
+  position: absolute; display: block; width: 0; height: 9px; margin: 0; padding: 0;
+  border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px;
+}
+.vjs-play-progress {
+  /* CSS Gradient */
+  /* Default */ background: #fff;
+  /* Webkit  */ background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#777));
+  /* Firefox */ background: -moz-linear-gradient(top,  #fff,  #777);
+}
+.vjs-load-progress {
+  opacity: 0.8;
+  /* CSS Gradient */
+  /* Default */ background-color: #555;
+  /* Webkit  */ background: -webkit-gradient(linear, left top, left bottom, from(#555), to(#aaa));
+  /* Firefox */ background: -moz-linear-gradient(top,  #555,  #aaa);
+}
+
+/* Time Display
+-------------------------------------------------------------------------------- */
+.vjs-controls .vjs-time-control { font-size: 10px; line-height: 1; font-weight: normal; font-family: Helvetica, Arial, sans-serif; }
+.vjs-controls .vjs-time-control span { line-height: 25px; /* Centering vertically */ }
+
+/* Volume
+-------------------------------------------------------------------------------- */
+.vjs-volume-control { cursor: pointer !important; }
+.vjs-volume-control div { display: block; margin: 0 5px 0 5px; padding: 4px 0 0 0; }
+/* Drawing the volume icon using 6 span elements */
+.vjs-volume-control div span { /* Individual volume bars */
+  float: left; padding: 0;
+  margin: 0 2px 0 0; /* Space between */
+  width: 5px; height: 0px; /* Total height is height + bottom border */
+  border-bottom: 18px solid #555; /* Default (off) color and height of visible portion */
+}
+.vjs-volume-control div span.vjs-volume-level-on { border-color: #fff; /* Volume on bar color */ }
+/* Creating differnt bar heights through height (transparent) and bottom border (visible). */
+.vjs-volume-control div span:nth-child(1) { border-bottom-width: 2px; height: 16px; }
+.vjs-volume-control div span:nth-child(2) { border-bottom-width: 4px; height: 14px; }
+.vjs-volume-control div span:nth-child(3) { border-bottom-width: 7px; height: 11px; }
+.vjs-volume-control div span:nth-child(4) { border-bottom-width: 10px; height: 8px; }
+.vjs-volume-control div span:nth-child(5) { border-bottom-width: 14px; height: 4px; }
+.vjs-volume-control div span:nth-child(6) { margin-right: 0; }
+
+/* Fullscreen
+-------------------------------------------------------------------------------- */
+.vjs-fullscreen-control { cursor: pointer !important; }
+.vjs-fullscreen-control div {
+  padding: 0; text-align: left; vertical-align: top; cursor: pointer !important; 
+  margin: 5px 0 0 5px; /* Placement within the fullscreen control item */
+  width: 20px; height: 20px;
+}
+/* Drawing the fullscreen icon using 4 span elements */
+.vjs-fullscreen-control div span { float: left; margin: 0; padding: 0; font-size: 0; line-height: 0; width: 0; text-align: left; vertical-align: top; }
+.vjs-fullscreen-control div span:nth-child(1) { /* Top-left triangle */
+  margin-right: 3px; /* Space between top-left and top-right */
+  margin-bottom: 3px; /* Space between top-left and bottom-left */
+  border-top: 6px solid #fff; /* Height and color */
+  border-right: 6px solid rgba(0,0,0,0);  /* Width */
+}
+.vjs-fullscreen-control div span:nth-child(2) { border-top: 6px solid #fff; border-left: 6px solid rgba(0,0,0,0); }
+.vjs-fullscreen-control div span:nth-child(3) { clear: both; margin: 0 3px 0 0; border-bottom: 6px solid #fff; border-right: 6px solid rgba(0,0,0,0); }
+.vjs-fullscreen-control div span:nth-child(4) { border-bottom: 6px solid #fff; border-left: 6px solid rgba(0,0,0,0); }
+/* Icon when video is in fullscreen mode */
+.vjs-fullscreen .vjs-fullscreen-control div span:nth-child(1) { border: none; border-bottom: 6px solid #fff; border-left: 6px solid rgba(0,0,0,0); }
+.vjs-fullscreen .vjs-fullscreen-control div span:nth-child(2) { border: none; border-bottom: 6px solid #fff; border-right: 6px solid rgba(0,0,0,0); }
+.vjs-fullscreen .vjs-fullscreen-control div span:nth-child(3) { border: none; border-top: 6px solid #fff; border-left: 6px solid rgba(0,0,0,0); }
+.vjs-fullscreen .vjs-fullscreen-control div span:nth-child(4) { border: none; border-top: 6px solid #fff; border-right: 6px solid rgba(0,0,0,0); }
+
+/* Download Links - Used for browsers that don't support any video.
+---------------------------------------------------------*/
+.vjs-no-video { font-size: small; line-height: 1.5; }
+
+/* Big Play Button (at start)
+---------------------------------------------------------*/
+div.vjs-big-play-button {
+  display: none; /* Start hidden */ z-index: 2;
+  position: absolute; top: 50%; left: 50%; width: 80px; height: 80px; margin: -43px 0 0 -43px; text-align: center; vertical-align: center; cursor: pointer !important;
+  border: 3px solid #fff; opacity: 0.9;
+  border-radius: 20px; -webkit-border-radius: 20px; -moz-border-radius: 20px;
+  
+  /* CSS Background Gradients */
+  /* Default */ background-color: #0B151A;
+  /* Webkit  */ background: #1F3744 -webkit-gradient(linear, left top, left bottom, from(#0B151A), to(#1F3744)) left 40px;
+  /* Firefox */ background: #1F3744 -moz-linear-gradient(top,  #0B151A,  #1F3744) left 40px;
+
+  /* CSS Shadows */
+  box-shadow: 4px 4px 8px #000; -webkit-box-shadow: 4px 4px 8px #000; -moz-box-shadow: 4px 4px 8px #000;
+}
+div.vjs-big-play-button:hover {
+  box-shadow: 0px 0px 80px #fff; -webkit-box-shadow: 0px 0px 80px #fff; -moz-box-shadow: 0px 0px 80px #fff;
+}
+
+div.vjs-big-play-button span {
+  display: block; font-size: 0; line-height: 0;
+  width: 0; height: 0; margin: 20px 0 0 23px;
+  /* Drawing the play triangle with borders - http://www.infimum.dk/HTML/slantinfo.html */
+  border-left: 40px solid #fff; /* Width & Color of play icon */
+  /* Height of play icon is total top & bottom border widths. Color is transparent. */
+  border-top: 20px solid rgba(0,0,0,0); border-bottom: 20px solid rgba(0,0,0,0);
+}
+
+/* Spinner Styles
+---------------------------------------------------------*/
+/* CSS Spinners by Kilian Valkhof - http://kilianvalkhof.com/2010/css-xhtml/css3-loading-spinners-without-images/ */
+.vjs-spinner { display: none; position: absolute; top: 50%; left: 50%; width: 100px; height: 100px; z-index: 1; margin: -50px 0 0 -50px;
+  /* Scaling makes the circles look smoother. */
+  transform: scale(0.5); -webkit-transform:scale(0.5); -moz-transform:scale(0.5);
+}
+/* Spinner circles */
+.vjs-spinner div { position:absolute; left: 40px; top: 40px; width: 20px; height: 20px; background: #fff;
+  border-radius: 20px; -webkit-border-radius: 20px; -moz-border-radius: 20px;
+  border: 1px solid #ccc; /* Added border so can be visible on white backgrounds */
+}
+/* Each circle */
+.vjs-spinner div:nth-child(1) { opacity: 0.12; transform: rotate(000deg) translate(0, -40px) scale(0.1); -webkit-transform: rotate(000deg) translate(0, -40px) scale(0.1); -moz-transform: rotate(000deg) translate(0, -40px) scale(0.1); }
+.vjs-spinner div:nth-child(2) { opacity: 0.25; transform: rotate(045deg) translate(0, -40px) scale(0.2); -webkit-transform: rotate(045deg) translate(0, -40px) scale(0.2); -moz-transform: rotate(045deg) translate(0, -40px) scale(0.2); }
+.vjs-spinner div:nth-child(3) { opacity: 0.37; transform: rotate(090deg) translate(0, -40px) scale(0.4); -webkit-transform: rotate(090deg) translate(0, -40px) scale(0.4); -moz-transform: rotate(090deg) translate(0, -40px) scale(0.4); }
+.vjs-spinner div:nth-child(4) { opacity: 0.50; transform: rotate(135deg) translate(0, -40px) scale(0.6); -webkit-transform: rotate(135deg) translate(0, -40px) scale(0.6); -moz-transform: rotate(135deg) translate(0, -40px) scale(0.6); }
+.vjs-spinner div:nth-child(5) { opacity: 0.62; transform: rotate(180deg) translate(0, -40px) scale(0.8); -webkit-transform: rotate(180deg) translate(0, -40px) scale(0.8); -moz-transform: rotate(180deg) translate(0, -40px) scale(0.8); }
+.vjs-spinner div:nth-child(6) { opacity: 0.75; transform: rotate(225deg) translate(0, -40px) scale(1.0); -webkit-transform: rotate(225deg) translate(0, -40px) scale(1.0); -moz-transform: rotate(225deg) translate(0, -40px) scale(1.0); }
+.vjs-spinner div:nth-child(7) { opacity: 0.87; transform: rotate(270deg) translate(0, -40px) scale(1.1); -webkit-transform: rotate(270deg) translate(0, -40px) scale(1.1); -moz-transform: rotate(270deg) translate(0, -40px) scale(1.1); }
+.vjs-spinner div:nth-child(8) { opacity: 1.00; transform: rotate(315deg) translate(0, -40px) scale(1.3); -webkit-transform: rotate(315deg) translate(0, -40px) scale(1.3); -moz-transform: rotate(315deg) translate(0, -40px) scale(1.3); }
\ No newline at end of file
diff --git a/final/www/video-js/video.js b/final/www/video-js/video.js
new file mode 100644
index 0000000..9571eeb
--- /dev/null
+++ b/final/www/video-js/video.js
@@ -0,0 +1,1758 @@
+/*
+VideoJS - HTML5 Video Player
+v2.0.2
+
+This file is part of VideoJS. Copyright 2010 Zencoder, Inc.
+
+VideoJS is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+VideoJS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with VideoJS.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// Self-executing function to prevent global vars and help with minification
+(function(window, undefined){
+  var document = window.document;
+
+// Using jresig's Class implementation http://ejohn.org/blog/simple-javascript-inheritance/
+(function(){var initializing=false, fnTest=/xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; this.JRClass = function(){}; JRClass.extend = function(prop) { var _super = this.prototype; initializing = true; var prototype = new this(); initializing = false; for (var name in prop) { prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn){ return function() { var tmp = this._super; this._super = _super[name]; var ret = fn.apply(this, arguments); this._super = tmp; return ret; }; })(name, prop[name]) : prop[name]; } function JRClass() { if ( !initializing && this.init ) this.init.apply(this, arguments); } JRClass.prototype = prototype; JRClass.constructor = JRClass; JRClass.extend = arguments.callee; return JRClass;};})();
+
+// Video JS Player Class
+var VideoJS = JRClass.extend({
+
+  // Initialize the player for the supplied video tag element
+  // element: video tag
+  init: function(element, setOptions){
+
+    // Allow an ID string or an element
+    if (typeof element == 'string') {
+      this.video = document.getElementById(element);
+    } else {
+      this.video = element;
+    }
+    // Store reference to player on the video element.
+    // So you can access the player later: document.getElementById("video_id").player.play();
+    this.video.player = this;
+    this.values = {}; // Cache video values.
+    this.elements = {}; // Store refs to controls elements.
+
+    // Default Options
+    this.options = {
+      autoplay: false,
+      preload: true,
+      useBuiltInControls: false, // Use the browser's controls (iPhone)
+      controlsBelow: false, // Display control bar below video vs. in front of
+      controlsAtStart: false, // Make controls visible when page loads
+      controlsHiding: true, // Hide controls when not over the video
+      defaultVolume: 0.85, // Will be overridden by localStorage volume if available
+      playerFallbackOrder: ["html5", "flash", "links"], // Players and order to use them
+      flashPlayer: "htmlObject",
+      flashPlayerVersion: false // Required flash version for fallback
+    };
+    // Override default options with global options
+    if (typeof VideoJS.options == "object") { _V_.merge(this.options, VideoJS.options); }
+    // Override default & global options with options specific to this player
+    if (typeof setOptions == "object") { _V_.merge(this.options, setOptions); }
+    // Override preload & autoplay with video attributes
+    if (this.getPreloadAttribute() !== undefined) { this.options.preload = this.getPreloadAttribute(); }
+    if (this.getAutoplayAttribute() !== undefined) { this.options.autoplay = this.getAutoplayAttribute(); }
+
+    // Store reference to embed code pieces
+    this.box = this.video.parentNode;
+    this.linksFallback = this.getLinksFallback();
+    this.hideLinksFallback(); // Will be shown again if "links" player is used
+
+    // Loop through the player names list in options, "html5" etc.
+    // For each player name, initialize the player with that name under VideoJS.players
+    // If the player successfully initializes, we're done
+    // If not, try the next player in the list
+    this.each(this.options.playerFallbackOrder, function(playerType){
+      if (this[playerType+"Supported"]()) { // Check if player type is supported
+        this[playerType+"Init"](); // Initialize player type
+        return true; // Stop looping though players
+      }
+    });
+
+    // Start Global Listeners - API doesn't exist before now
+    this.activateElement(this, "player");
+    this.activateElement(this.box, "box");
+  },
+  /* Behaviors
+  ================================================================================ */
+  behaviors: {},
+  newBehavior: function(name, activate, functions){
+    this.behaviors[name] = activate;
+    this.extend(functions);
+  },
+  activateElement: function(element, behavior){
+    // Allow passing and ID string
+    if (typeof element == "string") { element = document.getElementById(element); }
+    this.behaviors[behavior].call(this, element);
+  },
+  /* Errors/Warnings
+  ================================================================================ */
+  errors: [], // Array to track errors
+  warnings: [],
+  warning: function(warning){
+    this.warnings.push(warning);
+    this.log(warning);
+  },
+  /* History of errors/events (not quite there yet)
+  ================================================================================ */
+  history: [],
+  log: function(event){
+    if (!event) { return; }
+    if (typeof event == "string") { event = { type: event }; }
+    if (event.type) { this.history.push(event.type); }
+    if (this.history.length >= 50) { this.history.shift(); }
+    try { console.log(event.type); } catch(e) { try { opera.postError(event.type); } catch(e){} }
+  },
+  /* Local Storage
+  ================================================================================ */
+  setLocalStorage: function(key, value){
+    if (!localStorage) { return; }
+    try {
+      localStorage[key] = value;
+    } catch(e) {
+      if (e.code == 22 || e.code == 1014) { // Webkit == 22 / Firefox == 1014
+        this.warning(VideoJS.warnings.localStorageFull);
+      }
+    }
+  },
+  /* Helpers
+  ================================================================================ */
+  getPreloadAttribute: function(){
+    if (typeof this.video.hasAttribute == "function" && this.video.hasAttribute("preload")) {
+      var preload = this.video.getAttribute("preload");
+      // Only included the attribute, thinking it was boolean
+      if (preload === "" || preload === "true") { return "auto"; }
+      if (preload === "false") { return "none"; }
+      return preload;
+    }
+  },
+  getAutoplayAttribute: function(){
+    if (typeof this.video.hasAttribute == "function" && this.video.hasAttribute("autoplay")) {
+      var autoplay = this.video.getAttribute("autoplay");
+      if (autoplay === "false") { return false; }
+      return true;
+    }
+  },
+  // Calculates amoutn of buffer is full
+  bufferedPercent: function(){ return (this.duration()) ? this.buffered()[1] / this.duration() : 0; },
+  // Each that maintains player as context
+  // Break if true is returned
+  each: function(arr, fn){
+    if (!arr || arr.length === 0) { return; }
+    for (var i=0,j=arr.length; i<j; i++) {
+      if (fn.call(this, arr[i], i)) { break; }
+    }
+  },
+  extend: function(obj){
+    for (var attrname in obj) {
+      if (obj.hasOwnProperty(attrname)) { this[attrname]=obj[attrname]; }
+    }
+  }
+});
+VideoJS.player = VideoJS.prototype;
+
+////////////////////////////////////////////////////////////////////////////////
+// Player Types
+////////////////////////////////////////////////////////////////////////////////
+
+/* Flash Object Fallback (Player Type)
+================================================================================ */
+VideoJS.player.extend({
+  flashSupported: function(){
+    if (!this.flashElement) { this.flashElement = this.getFlashElement(); }
+    // Check if object exists & Flash Player version is supported
+    if (this.flashElement && this.flashPlayerVersionSupported()) {
+      return true;
+    } else {
+      return false;
+    }
+  },
+  flashInit: function(){
+    this.replaceWithFlash();
+    this.element = this.flashElement;
+    this.video.src = ""; // Stop video from downloading if HTML5 is still supported
+    var flashPlayerType = VideoJS.flashPlayers[this.options.flashPlayer];
+    this.extend(VideoJS.flashPlayers[this.options.flashPlayer].api);
+    (flashPlayerType.init.context(this))();
+  },
+  // Get Flash Fallback object element from Embed Code
+  getFlashElement: function(){
+    var children = this.video.children;
+    for (var i=0,j=children.length; i<j; i++) {
+      if (children[i].className == "vjs-flash-fallback") {
+        return children[i];
+      }
+    }
+  },
+  // Used to force a browser to fall back when it's an HTML5 browser but there's no supported sources
+  replaceWithFlash: function(){
+    // this.flashElement = this.video.removeChild(this.flashElement);
+    if (this.flashElement) {
+      this.box.insertBefore(this.flashElement, this.video);
+      this.video.style.display = "none"; // Removing it was breaking later players
+    }
+  },
+  // Check if browser can use this flash player
+  flashPlayerVersionSupported: function(){
+    var playerVersion = (this.options.flashPlayerVersion) ? this.options.flashPlayerVersion : VideoJS.flashPlayers[this.options.flashPlayer].flashPlayerVersion;
+    return VideoJS.getFlashVersion() >= playerVersion;
+  }
+});
+VideoJS.flashPlayers = {};
+VideoJS.flashPlayers.htmlObject = {
+  flashPlayerVersion: 9,
+  init: function() { return true; },
+  api: { // No video API available with HTML Object embed method
+    width: function(width){
+      if (width !== undefined) {
+        this.element.width = width;
+        this.box.style.width = width+"px";
+        this.triggerResizeListeners();
+        return this;
+      }
+      return this.element.width;
+    },
+    height: function(height){
+      if (height !== undefined) {
+        this.element.height = height;
+        this.box.style.height = height+"px";
+        this.triggerResizeListeners();
+        return this;
+      }
+      return this.element.height;
+    }
+  }
+};
+
+
+/* Download Links Fallback (Player Type)
+================================================================================ */
+VideoJS.player.extend({
+  linksSupported: function(){ return true; },
+  linksInit: function(){
+    this.showLinksFallback();
+    this.element = this.video;
+  },
+  // Get the download links block element
+  getLinksFallback: function(){ return this.box.getElementsByTagName("P")[0]; },
+  // Hide no-video download paragraph
+  hideLinksFallback: function(){
+    if (this.linksFallback) { this.linksFallback.style.display = "none"; }
+  },
+  // Hide no-video download paragraph
+  showLinksFallback: function(){
+    if (this.linksFallback) { this.linksFallback.style.display = "block"; }
+  }
+});
+
+////////////////////////////////////////////////////////////////////////////////
+// Class Methods
+// Functions that don't apply to individual videos.
+////////////////////////////////////////////////////////////////////////////////
+
+// Combine Objects - Use "safe" to protect from overwriting existing items
+VideoJS.merge = function(obj1, obj2, safe){
+  for (var attrname in obj2){
+    if (obj2.hasOwnProperty(attrname) && (!safe || !obj1.hasOwnProperty(attrname))) { obj1[attrname]=obj2[attrname]; }
+  }
+  return obj1;
+};
+VideoJS.extend = function(obj){ this.merge(this, obj, true); };
+
+VideoJS.extend({
+  // Add VideoJS to all video tags with the video-js class when the DOM is ready
+  setupAllWhenReady: function(options){
+    // Options is stored globally, and added ot any new player on init
+    VideoJS.options = options;
+    VideoJS.DOMReady(VideoJS.setup);
+  },
+
+  // Run the supplied function when the DOM is ready
+  DOMReady: function(fn){
+    VideoJS.addToDOMReady(fn);
+  },
+
+  // Set up a specific video or array of video elements
+  // "video" can be:
+  //    false, undefined, or "All": set up all videos with the video-js class
+  //    A video tag ID or video tag element: set up one video and return one player
+  //    An array of video tag elements/IDs: set up each and return an array of players
+  setup: function(videos, options){
+    var returnSingular = false,
+    playerList = [],
+    videoElement;
+
+    // If videos is undefined or "All", set up all videos with the video-js class
+    if (!videos || videos == "All") {
+      videos = VideoJS.getVideoJSTags();
+    // If videos is not an array, add to an array
+    } else if (typeof videos != 'object' || videos.nodeType == 1) {
+      videos = [videos];
+      returnSingular = true;
+    }
+
+    // Loop through videos and create players for them
+    for (var i=0; i<videos.length; i++) {
+      if (typeof videos[i] == 'string') {
+        videoElement = document.getElementById(videos[i]);
+      } else { // assume DOM object
+        videoElement = videos[i];
+      }
+      playerList.push(new VideoJS(videoElement, options));
+    }
+
+    // Return one or all depending on what was passed in
+    return (returnSingular) ? playerList[0] : playerList;
+  },
+
+  // Find video tags with the video-js class
+  getVideoJSTags: function() {
+    var videoTags = document.getElementsByTagName("video"),
+    videoJSTags = [], videoTag;
+
+    for (var i=0,j=videoTags.length; i<j; i++) {
+      videoTag = videoTags[i];
+      if (videoTag.className.indexOf("video-js") != -1) {
+        videoJSTags.push(videoTag);
+      }
+    }
+    return videoJSTags;
+  },
+
+  // Check if the browser supports video.
+  browserSupportsVideo: function() {
+    if (typeof VideoJS.videoSupport != "undefined") { return VideoJS.videoSupport; }
+    VideoJS.videoSupport = !!document.createElement('video').canPlayType;
+    return VideoJS.videoSupport;
+  },
+
+  getFlashVersion: function(){
+    // Cache Version
+    if (typeof VideoJS.flashVersion != "undefined") { return VideoJS.flashVersion; }
+    var version = 0, desc;
+    if (typeof navigator.plugins != "undefined" && typeof navigator.plugins["Shockwave Flash"] == "object") {
+      desc = navigator.plugins["Shockwave Flash"].description;
+      if (desc && !(typeof navigator.mimeTypes != "undefined" && navigator.mimeTypes["application/x-shockwave-flash"] && !navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin)) {
+        version = parseInt(desc.match(/^.*\s+([^\s]+)\.[^\s]+\s+[^\s]+$/)[1], 10);
+      }
+    } else if (typeof window.ActiveXObject != "undefined") {
+      try {
+        var testObject = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
+        if (testObject) {
+          version = parseInt(testObject.GetVariable("$version").match(/^[^\s]+\s(\d+)/)[1], 10);
+        }
+      }
+      catch(e) {}
+    }
+    VideoJS.flashVersion = version;
+    return VideoJS.flashVersion;
+  },
+
+  // Browser & Device Checks
+  isIE: function(){ return !+"\v1"; },
+  isIPad: function(){ return navigator.userAgent.match(/iPad/i) !== null; },
+  isIPhone: function(){ return navigator.userAgent.match(/iPhone/i) !== null; },
+  isIOS: function(){ return VideoJS.isIPhone() || VideoJS.isIPad(); },
+  iOSVersion: function() {
+    var match = navigator.userAgent.match(/OS (\d+)_/i);
+    if (match && match[1]) { return match[1]; }
+  },
+  isAndroid: function(){ return navigator.userAgent.match(/Android/i) !== null; },
+  androidVersion: function() {
+    var match = navigator.userAgent.match(/Android (\d+)\./i);
+    if (match && match[1]) { return match[1]; }
+  },
+
+  warnings: {
+    // Safari errors if you call functions on a video that hasn't loaded yet
+    videoNotReady: "Video is not ready yet (try playing the video first).",
+    // Getting a QUOTA_EXCEEDED_ERR when setting local storage occasionally
+    localStorageFull: "Local Storage is Full"
+  }
+});
+
+// Shim to make Video tag valid in IE
+if(VideoJS.isIE()) { document.createElement("video"); }
+
+// Expose to global
+window.VideoJS = window._V_ = VideoJS;
+
+/* HTML5 Player Type
+================================================================================ */
+VideoJS.player.extend({
+  html5Supported: function(){
+    if (VideoJS.browserSupportsVideo() && this.canPlaySource()) {
+      return true;
+    } else {
+      return false;
+    }
+  },
+  html5Init: function(){
+    this.element = this.video;
+
+    this.fixPreloading(); // Support old browsers that used autobuffer
+    this.supportProgressEvents(); // Support browsers that don't use 'buffered'
+
+    // Set to stored volume OR 85%
+    this.volume((localStorage && localStorage.volume) || this.options.defaultVolume);
+
+    // Update interface for device needs
+    if (VideoJS.isIOS()) {
+      this.options.useBuiltInControls = true;
+      this.iOSInterface();
+    } else if (VideoJS.isAndroid()) {
+      this.options.useBuiltInControls = true;
+      this.androidInterface();
+    }
+
+    // Add VideoJS Controls
+    if (!this.options.useBuiltInControls) {
+      this.video.controls = false;
+
+      if (this.options.controlsBelow) { _V_.addClass(this.box, "vjs-controls-below"); }
+
+      // Make a click on th video act as a play button
+      this.activateElement(this.video, "playToggle");
+
+      // Build Interface
+      this.buildStylesCheckDiv(); // Used to check if style are loaded
+      this.buildAndActivatePoster();
+      this.buildBigPlayButton();
+      this.buildAndActivateSpinner();
+      this.buildAndActivateControlBar();
+      this.loadInterface(); // Show everything once styles are loaded
+      this.getSubtitles();
+    }
+  },
+  /* Source Managemet
+  ================================================================================ */
+  canPlaySource: function(){
+    // Cache Result
+    if (this.canPlaySourceResult) { return this.canPlaySourceResult; }
+    // Loop through sources and check if any can play
+    var children = this.video.children;
+    for (var i=0,j=children.length; i<j; i++) {
+      if (children[i].tagName.toUpperCase() == "SOURCE") {
+        var canPlay = this.video.canPlayType(children[i].type) || this.canPlayExt(children[i].src);
+        if (canPlay == "probably" || canPlay == "maybe") {
+          this.firstPlayableSource = children[i];
+          this.canPlaySourceResult = true;
+          return true;
+        }
+      }
+    }
+    this.canPlaySourceResult = false;
+    return false;
+  },
+  // Check if the extension is compatible, for when type won't work
+  canPlayExt: function(src){
+    if (!src) { return ""; }
+    var match = src.match(/\.([^\.]+)$/);
+    if (match && match[1]) {
+      var ext = match[1].toLowerCase();
+      // Android canPlayType doesn't work
+      if (VideoJS.isAndroid()) {
+        if (ext == "mp4" || ext == "m4v") { return "maybe"; }
+      // Allow Apple HTTP Streaming for iOS
+      } else if (VideoJS.isIOS()) {
+        if (ext == "m3u8") { return "maybe"; }
+      }
+    }
+    return "";
+  },
+  // Force the video source - Helps fix loading bugs in a handful of devices, like the iPad/iPhone poster bug
+  // And iPad/iPhone javascript include location bug. And Android type attribute bug
+  forceTheSource: function(){
+    this.video.src = this.firstPlayableSource.src; // From canPlaySource()
+    this.video.load();
+  },
+  /* Device Fixes
+  ================================================================================ */
+  // Support older browsers that used "autobuffer"
+  fixPreloading: function(){
+    if (typeof this.video.hasAttribute == "function" && this.video.hasAttribute("preload") && this.video.preload != "none") {
+      this.video.autobuffer = true; // Was a boolean
+    } else {
+      this.video.autobuffer = false;
+      this.video.preload = "none";
+    }
+  },
+
+  // Listen for Video Load Progress (currently does not if html file is local)
+  // Buffered does't work in all browsers, so watching progress as well
+  supportProgressEvents: function(e){
+    _V_.addListener(this.video, 'progress', this.playerOnVideoProgress.context(this));
+  },
+  playerOnVideoProgress: function(event){
+    this.setBufferedFromProgress(event);
+  },
+  setBufferedFromProgress: function(event){ // HTML5 Only
+    if(event.total > 0) {
+      var newBufferEnd = (event.loaded / event.total) * this.duration();
+      if (newBufferEnd > this.values.bufferEnd) { this.values.bufferEnd = newBufferEnd; }
+    }
+  },
+
+  iOSInterface: function(){
+    if(VideoJS.iOSVersion() < 4) { this.forceTheSource(); } // Fix loading issues
+    if(VideoJS.isIPad()) { // iPad could work with controlsBelow
+      this.buildAndActivateSpinner(); // Spinner still works well on iPad, since iPad doesn't have one
+    }
+  },
+
+  // Fix android specific quirks
+  // Use built-in controls, but add the big play button, since android doesn't have one.
+  androidInterface: function(){
+    this.forceTheSource(); // Fix loading issues
+    _V_.addListener(this.video, "click", function(){ this.play(); }); // Required to play
+    this.buildBigPlayButton(); // But don't activate the normal way. Pause doesn't work right on android.
+    _V_.addListener(this.bigPlayButton, "click", function(){ this.play(); }.context(this));
+    this.positionBox();
+    this.showBigPlayButtons();
+  },
+  /* Wait for styles (TODO: move to _V_)
+  ================================================================================ */
+  loadInterface: function(){
+    if(!this.stylesHaveLoaded()) {
+      // Don't want to create an endless loop either.
+      if (!this.positionRetries) { this.positionRetries = 1; }
+      if (this.positionRetries++ < 100) {
+        setTimeout(this.loadInterface.context(this),10);
+        return;
+      }
+    }
+    this.hideStylesCheckDiv();
+    this.showPoster();
+    if (this.video.paused !== false) { this.showBigPlayButtons(); }
+    if (this.options.controlsAtStart) { this.showControlBars(); }
+    this.positionAll();
+  },
+  /* Control Bar
+  ================================================================================ */
+  buildAndActivateControlBar: function(){
+    /* Creating this HTML
+      <div class="vjs-controls">
+        <div class="vjs-play-control">
+          <span></span>
+        </div>
+        <div class="vjs-progress-control">
+          <div class="vjs-progress-holder">
+            <div class="vjs-load-progress"></div>
+            <div class="vjs-play-progress"></div>
+          </div>
+        </div>
+        <div class="vjs-time-control">
+          <span class="vjs-current-time-display">00:00</span><span> / </span><span class="vjs-duration-display">00:00</span>
+        </div>
+        <div class="vjs-volume-control">
+          <div>
+            <span></span><span></span><span></span><span></span><span></span><span></span>
+          </div>
+        </div>
+        <div class="vjs-fullscreen-control">
+          <div>
+            <span></span><span></span><span></span><span></span>
+          </div>
+        </div>
+      </div>
+    */
+
+    // Create a div to hold the different controls
+    this.controls = _V_.createElement("div", { className: "vjs-controls" });
+    // Add the controls to the video's container
+    this.box.appendChild(this.controls);
+    this.activateElement(this.controls, "controlBar");
+    this.activateElement(this.controls, "mouseOverVideoReporter");
+
+    // Build the play control
+    this.playControl = _V_.createElement("div", { className: "vjs-play-control", innerHTML: "<span></span>" });
+    this.controls.appendChild(this.playControl);
+    this.activateElement(this.playControl, "playToggle");
+
+    // Build the progress control
+    this.progressControl = _V_.createElement("div", { className: "vjs-progress-control" });
+    this.controls.appendChild(this.progressControl);
+
+    // Create a holder for the progress bars
+    this.progressHolder = _V_.createElement("div", { className: "vjs-progress-holder" });
+    this.progressControl.appendChild(this.progressHolder);
+    this.activateElement(this.progressHolder, "currentTimeScrubber");
+
+    // Create the loading progress display
+    this.loadProgressBar = _V_.createElement("div", { className: "vjs-load-progress" });
+    this.progressHolder.appendChild(this.loadProgressBar);
+    this.activateElement(this.loadProgressBar, "loadProgressBar");
+
+    // Create the playing progress display
+    this.playProgressBar = _V_.createElement("div", { className: "vjs-play-progress" });
+    this.progressHolder.appendChild(this.playProgressBar);
+    this.activateElement(this.playProgressBar, "playProgressBar");
+
+    // Create the progress time display (00:00 / 00:00)
+    this.timeControl = _V_.createElement("div", { className: "vjs-time-control" });
+    this.controls.appendChild(this.timeControl);
+
+    // Create the current play time display
+    this.currentTimeDisplay = _V_.createElement("span", { className: "vjs-current-time-display", innerHTML: "00:00" });
+    this.timeControl.appendChild(this.currentTimeDisplay);
+    this.activateElement(this.currentTimeDisplay, "currentTimeDisplay");
+
+    // Add time separator
+    this.timeSeparator = _V_.createElement("span", { innerHTML: " / " });
+    this.timeControl.appendChild(this.timeSeparator);
+
+    // Create the total duration display
+    this.durationDisplay = _V_.createElement("span", { className: "vjs-duration-display", innerHTML: "00:00" });
+    this.timeControl.appendChild(this.durationDisplay);
+    this.activateElement(this.durationDisplay, "durationDisplay");
+
+    // Create the volumne control
+    this.volumeControl = _V_.createElement("div", {
+      className: "vjs-volume-control",
+      innerHTML: "<div><span></span><span></span><span></span><span></span><span></span><span></span></div>"
+    });
+    this.controls.appendChild(this.volumeControl);
+    this.activateElement(this.volumeControl, "volumeScrubber");
+
+    this.volumeDisplay = this.volumeControl.children[0];
+    this.activateElement(this.volumeDisplay, "volumeDisplay");
+
+    // Crete the fullscreen control
+    this.fullscreenControl = _V_.createElement("div", {
+      className: "vjs-fullscreen-control",
+      innerHTML: "<div><span></span><span></span><span></span><span></span></div>"
+    });
+    this.controls.appendChild(this.fullscreenControl);
+    this.activateElement(this.fullscreenControl, "fullscreenToggle");
+  },
+  /* Poster Image
+  ================================================================================ */
+  buildAndActivatePoster: function(){
+    this.updatePosterSource();
+    if (this.video.poster) {
+      this.poster = document.createElement("img");
+      // Add poster to video box
+      this.box.appendChild(this.poster);
+
+      // Add poster image data
+      this.poster.src = this.video.poster;
+      // Add poster styles
+      this.poster.className = "vjs-poster";
+      this.activateElement(this.poster, "poster");
+    } else {
+      this.poster = false;
+    }
+  },
+  /* Big Play Button
+  ================================================================================ */
+  buildBigPlayButton: function(){
+    /* Creating this HTML
+      <div class="vjs-big-play-button"><span></span></div>
+    */
+    this.bigPlayButton = _V_.createElement("div", {
+      className: "vjs-big-play-button",
+      innerHTML: "<span></span>"
+    });
+    this.box.appendChild(this.bigPlayButton);
+    this.activateElement(this.bigPlayButton, "bigPlayButton");
+  },
+  /* Spinner (Loading)
+  ================================================================================ */
+  buildAndActivateSpinner: function(){
+    this.spinner = _V_.createElement("div", {
+      className: "vjs-spinner",
+      innerHTML: "<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>"
+    });
+    this.box.appendChild(this.spinner);
+    this.activateElement(this.spinner, "spinner");
+  },
+  /* Styles Check - Check if styles are loaded (move ot _V_)
+  ================================================================================ */
+  // Sometimes the CSS styles haven't been applied to the controls yet
+  // when we're trying to calculate the height and position them correctly.
+  // This causes a flicker where the controls are out of place.
+  buildStylesCheckDiv: function(){
+    this.stylesCheckDiv = _V_.createElement("div", { className: "vjs-styles-check" });
+    this.stylesCheckDiv.style.position = "absolute";
+    this.box.appendChild(this.stylesCheckDiv);
+  },
+  hideStylesCheckDiv: function(){ this.stylesCheckDiv.style.display = "none"; },
+  stylesHaveLoaded: function(){
+    if (this.stylesCheckDiv.offsetHeight != 5) {
+       return false;
+    } else {
+      return true;
+    }
+  },
+  /* VideoJS Box - Holds all elements
+  ================================================================================ */
+  positionAll: function(){
+    this.positionBox();
+    this.positionControlBars();
+    this.positionPoster();
+  },
+  positionBox: function(){
+    // Set width based on fullscreen or not.
+    if (this.videoIsFullScreen) {
+      this.box.style.width = "";
+      this.element.style.height="";
+      if (this.options.controlsBelow) {
+        this.box.style.height = "";
+        this.element.style.height = (this.box.offsetHeight - this.controls.offsetHeight) + "px";
+      }
+    } else {
+      this.box.style.width = this.width() + "px";
+      this.element.style.height=this.height()+"px";
+      if (this.options.controlsBelow) {
+        this.element.style.height = "";
+        // this.box.style.height = this.video.offsetHeight + this.controls.offsetHeight + "px";
+      }
+    }
+  },
+  /* Subtitles
+  ================================================================================ */
+  getSubtitles: function(){
+    var tracks = this.video.getElementsByTagName("TRACK");
+    for (var i=0,j=tracks.length; i<j; i++) {
+      if (tracks[i].getAttribute("kind") == "subtitles" && tracks[i].getAttribute("src")) {
+        this.subtitlesSource = tracks[i].getAttribute("src");
+        this.loadSubtitles();
+        this.buildSubtitles();
+      }
+    }
+  },
+  loadSubtitles: function() { _V_.get(this.subtitlesSource, this.parseSubtitles.context(this)); },
+  parseSubtitles: function(subText) {
+    var lines = subText.split("\n"),
+        line = "",
+        subtitle, time, text;
+    this.subtitles = [];
+    this.currentSubtitle = false;
+    this.lastSubtitleIndex = 0;
+
+    for (var i=0; i<lines.length; i++) {
+      line = _V_.trim(lines[i]); // Trim whitespace and linebreaks
+      if (line) { // Loop until a line with content
+
+        // First line - Number
+        subtitle = {
+          id: line, // Subtitle Number
+          index: this.subtitles.length // Position in Array
+        };
+
+        // Second line - Time
+        line = _V_.trim(lines[++i]);
+        time = line.split(" --> ");
+        subtitle.start = this.parseSubtitleTime(time[0]);
+        subtitle.end = this.parseSubtitleTime(time[1]);
+
+        // Additional lines - Subtitle Text
+        text = [];
+        for (var j=i; j<lines.length; j++) { // Loop until a blank line or end of lines
+          line = _V_.trim(lines[++i]);
+          if (!line) { break; }
+          text.push(line);
+        }
+        subtitle.text = text.join('<br/>');
+
+        // Add this subtitle
+        this.subtitles.push(subtitle);
+      }
+    }
+  },
+
+  parseSubtitleTime: function(timeText) {
+    var parts = timeText.split(':'),
+        time = 0;
+    // hours => seconds
+    time += parseFloat(parts[0])*60*60;
+    // minutes => seconds
+    time += parseFloat(parts[1])*60;
+    // get seconds
+    var seconds = parts[2].split(/\.|,/); // Either . or ,
+    time += parseFloat(seconds[0]);
+    // add miliseconds
+    ms = parseFloat(seconds[1]);
+    if (ms) { time += ms/1000; }
+    return time;
+  },
+
+  buildSubtitles: function(){
+    /* Creating this HTML
+      <div class="vjs-subtitles"></div>
+    */
+    this.subtitlesDisplay = _V_.createElement("div", { className: 'vjs-subtitles' });
+    this.box.appendChild(this.subtitlesDisplay);
+    this.activateElement(this.subtitlesDisplay, "subtitlesDisplay");
+  },
+
+  /* Player API - Translate functionality from player to video
+  ================================================================================ */
+  addVideoListener: function(type, fn){ _V_.addListener(this.video, type, fn.rEvtContext(this)); },
+
+  play: function(){
+    this.video.play();
+    return this;
+  },
+  onPlay: function(fn){ this.addVideoListener("play", fn); return this; },
+
+  pause: function(){
+    this.video.pause();
+    return this;
+  },
+  onPause: function(fn){ this.addVideoListener("pause", fn); return this; },
+  paused: function() { return this.video.paused; },
+
+  currentTime: function(seconds){
+    if (seconds !== undefined) {
+      try { this.video.currentTime = seconds; }
+      catch(e) { this.warning(VideoJS.warnings.videoNotReady); }
+      this.values.currentTime = seconds;
+      return this;
+    }
+    return this.video.currentTime;
+  },
+  onCurrentTimeUpdate: function(fn){
+    this.currentTimeListeners.push(fn);
+  },
+
+  duration: function(){
+    return this.video.duration;
+  },
+
+  buffered: function(){
+    // Storing values allows them be overridden by setBufferedFromProgress
+    if (this.values.bufferStart === undefined) {
+      this.values.bufferStart = 0;
+      this.values.bufferEnd = 0;
+    }
+    if (this.video.buffered && this.video.buffered.length > 0) {
+      var newEnd = this.video.buffered.end(0);
+      if (newEnd > this.values.bufferEnd) { this.values.bufferEnd = newEnd; }
+    }
+    return [this.values.bufferStart, this.values.bufferEnd];
+  },
+
+  volume: function(percentAsDecimal){
+    if (percentAsDecimal !== undefined) {
+      // Force value to between 0 and 1
+      this.values.volume = Math.max(0, Math.min(1, parseFloat(percentAsDecimal)));
+      this.video.volume = this.values.volume;
+      this.setLocalStorage("volume", this.values.volume);
+      return this;
+    }
+    if (this.values.volume) { return this.values.volume; }
+    return this.video.volume;
+  },
+  onVolumeChange: function(fn){ _V_.addListener(this.video, 'volumechange', fn.rEvtContext(this)); },
+
+  width: function(width){
+    if (width !== undefined) {
+      this.video.width = width; // Not using style so it can be overridden on fullscreen.
+      this.box.style.width = width+"px";
+      this.triggerResizeListeners();
+      return this;
+    }
+    return this.video.offsetWidth;
+  },
+  height: function(height){
+    if (height !== undefined) {
+      this.video.height = height;
+      this.box.style.height = height+"px";
+      this.triggerResizeListeners();
+      return this;
+    }
+    return this.video.offsetHeight;
+  },
+
+  supportsFullScreen: function(){
+    if(typeof this.video.webkitEnterFullScreen == 'function') {
+      // Seems to be broken in Chromium/Chrome
+      if (!navigator.userAgent.match("Chrome") && !navigator.userAgent.match("Mac OS X 10.5")) {
+        return true;
+      }
+    }
+    return false;
+  },
+
+  html5EnterNativeFullScreen: function(){
+    try {
+      this.video.webkitEnterFullScreen();
+    } catch (e) {
+      if (e.code == 11) { this.warning(VideoJS.warnings.videoNotReady); }
+    }
+    return this;
+  },
+
+  // Turn on fullscreen (window) mode
+  // Real fullscreen isn't available in browsers quite yet.
+  enterFullScreen: function(){
+    if (this.supportsFullScreen()) {
+      this.html5EnterNativeFullScreen();
+    } else {
+      this.enterFullWindow();
+    }
+  },
+
+  exitFullScreen: function(){
+    if (this.supportsFullScreen()) {
+      // Shouldn't be called
+    } else {
+      this.exitFullWindow();
+    }
+  },
+
+  enterFullWindow: function(){
+    this.videoIsFullScreen = true;
+    // Storing original doc overflow value to return to when fullscreen is off
+    this.docOrigOverflow = document.documentElement.style.overflow;
+    // Add listener for esc key to exit fullscreen
+    _V_.addListener(document, "keydown", this.fullscreenOnEscKey.rEvtContext(this));
+    // Add listener for a window resize
+    _V_.addListener(window, "resize", this.fullscreenOnWindowResize.rEvtContext(this));
+    // Hide any scroll bars
+    document.documentElement.style.overflow = 'hidden';
+    // Apply fullscreen styles
+    _V_.addClass(this.box, "vjs-fullscreen");
+    // Resize the box, controller, and poster
+    this.positionAll();
+  },
+
+  // Turn off fullscreen (window) mode
+  exitFullWindow: function(){
+    this.videoIsFullScreen = false;
+    document.removeEventListener("keydown", this.fullscreenOnEscKey, false);
+    window.removeEventListener("resize", this.fullscreenOnWindowResize, false);
+    // Unhide scroll bars.
+    document.documentElement.style.overflow = this.docOrigOverflow;
+    // Remove fullscreen styles
+    _V_.removeClass(this.box, "vjs-fullscreen");
+    // Resize the box, controller, and poster to original sizes
+    this.positionAll();
+  },
+
+  onError: function(fn){ this.addVideoListener("error", fn); return this; },
+  onEnded: function(fn){
+    this.addVideoListener("ended", fn); return this;
+  }
+});
+
+////////////////////////////////////////////////////////////////////////////////
+// Element Behaviors
+// Tell elements how to act or react
+////////////////////////////////////////////////////////////////////////////////
+
+/* Player Behaviors - How VideoJS reacts to what the video is doing.
+================================================================================ */
+VideoJS.player.newBehavior("player", function(player){
+    this.onError(this.playerOnVideoError);
+    // Listen for when the video is played
+    this.onPlay(this.playerOnVideoPlay);
+    this.onPlay(this.trackCurrentTime);
+    // Listen for when the video is paused
+    this.onPause(this.playerOnVideoPause);
+    this.onPause(this.stopTrackingCurrentTime);
+    // Listen for when the video ends
+    this.onEnded(this.playerOnVideoEnded);
+    // Set interval for load progress using buffer watching method
+    // this.trackCurrentTime();
+    this.trackBuffered();
+    // Buffer Full
+    this.onBufferedUpdate(this.isBufferFull);
+  },{
+    playerOnVideoError: function(event){
+      this.log(event);
+      this.log(this.video.error);
+    },
+    playerOnVideoPlay: function(event){ this.hasPlayed = true; },
+    playerOnVideoPause: function(event){},
+    playerOnVideoEnded: function(event){
+      this.currentTime(0);
+      this.pause();
+    },
+
+    /* Load Tracking -------------------------------------------------------------- */
+    // Buffer watching method for load progress.
+    // Used for browsers that don't support the progress event
+    trackBuffered: function(){
+      this.bufferedInterval = setInterval(this.triggerBufferedListeners.context(this), 500);
+    },
+    stopTrackingBuffered: function(){ clearInterval(this.bufferedInterval); },
+    bufferedListeners: [],
+    onBufferedUpdate: function(fn){
+      this.bufferedListeners.push(fn);
+    },
+    triggerBufferedListeners: function(){
+      this.isBufferFull();
+      this.each(this.bufferedListeners, function(listener){
+        (listener.context(this))();
+      });
+    },
+    isBufferFull: function(){
+      if (this.bufferedPercent() == 1) { this.stopTrackingBuffered(); }
+    },
+
+    /* Time Tracking -------------------------------------------------------------- */
+    trackCurrentTime: function(){
+      if (this.currentTimeInterval) { clearInterval(this.currentTimeInterval); }
+      this.currentTimeInterval = setInterval(this.triggerCurrentTimeListeners.context(this), 100); // 42 = 24 fps
+      this.trackingCurrentTime = true;
+    },
+    // Turn off play progress tracking (when paused or dragging)
+    stopTrackingCurrentTime: function(){
+      clearInterval(this.currentTimeInterval);
+      this.trackingCurrentTime = false;
+    },
+    currentTimeListeners: [],
+    // onCurrentTimeUpdate is in API section now
+    triggerCurrentTimeListeners: function(late, newTime){ // FF passes milliseconds late as the first argument
+      this.each(this.currentTimeListeners, function(listener){
+        (listener.context(this))(newTime || this.currentTime());
+      });
+    },
+
+    /* Resize Tracking -------------------------------------------------------------- */
+    resizeListeners: [],
+    onResize: function(fn){
+      this.resizeListeners.push(fn);
+    },
+    // Trigger anywhere the video/box size is changed.
+    triggerResizeListeners: function(){
+      this.each(this.resizeListeners, function(listener){
+        (listener.context(this))();
+      });
+    }
+  }
+);
+/* Mouse Over Video Reporter Behaviors - i.e. Controls hiding based on mouse location
+================================================================================ */
+VideoJS.player.newBehavior("mouseOverVideoReporter", function(element){
+    // Listen for the mouse move the video. Used to reveal the controller.
+    _V_.addListener(element, "mousemove", this.mouseOverVideoReporterOnMouseMove.context(this));
+    // Listen for the mouse moving out of the video. Used to hide the controller.
+    _V_.addListener(element, "mouseout", this.mouseOverVideoReporterOnMouseOut.context(this));
+  },{
+    mouseOverVideoReporterOnMouseMove: function(){
+      this.showControlBars();
+      clearInterval(this.mouseMoveTimeout);
+      this.mouseMoveTimeout = setTimeout(this.hideControlBars.context(this), 4000);
+    },
+    mouseOverVideoReporterOnMouseOut: function(event){
+      // Prevent flicker by making sure mouse hasn't left the video
+      var parent = event.relatedTarget;
+      while (parent && parent !== this.box) {
+        parent = parent.parentNode;
+      }
+      if (parent !== this.box) {
+        this.hideControlBars();
+      }
+    }
+  }
+);
+/* Mouse Over Video Reporter Behaviors - i.e. Controls hiding based on mouse location
+================================================================================ */
+VideoJS.player.newBehavior("box", function(element){
+    this.positionBox();
+    _V_.addClass(element, "vjs-paused");
+    this.activateElement(element, "mouseOverVideoReporter");
+    this.onPlay(this.boxOnVideoPlay);
+    this.onPause(this.boxOnVideoPause);
+  },{
+    boxOnVideoPlay: function(){
+      _V_.removeClass(this.box, "vjs-paused");
+      _V_.addClass(this.box, "vjs-playing");
+    },
+    boxOnVideoPause: function(){
+      _V_.removeClass(this.box, "vjs-playing");
+      _V_.addClass(this.box, "vjs-paused");
+    }
+  }
+);
+/* Poster Image Overlay
+================================================================================ */
+VideoJS.player.newBehavior("poster", function(element){
+    this.activateElement(element, "mouseOverVideoReporter");
+    this.activateElement(element, "playButton");
+    this.onPlay(this.hidePoster);
+    this.onEnded(this.showPoster);
+    this.onResize(this.positionPoster);
+  },{
+    showPoster: function(){
+      if (!this.poster) { return; }
+      this.poster.style.display = "block";
+      this.positionPoster();
+    },
+    positionPoster: function(){
+      // Only if the poster is visible
+      if (!this.poster || this.poster.style.display == 'none') { return; }
+      this.poster.style.height = this.height() + "px"; // Need incase controlsBelow
+      this.poster.style.width = this.width() + "px"; // Could probably do 100% of box
+    },
+    hidePoster: function(){
+      if (!this.poster) { return; }
+      this.poster.style.display = "none";
+    },
+    // Update poster source from attribute or fallback image
+    // iPad breaks if you include a poster attribute, so this fixes that
+    updatePosterSource: function(){
+      if (!this.video.poster) {
+        var images = this.video.getElementsByTagName("img");
+        if (images.length > 0) { this.video.poster = images[0].src; }
+      }
+    }
+  }
+);
+/* Control Bar Behaviors
+================================================================================ */
+VideoJS.player.newBehavior("controlBar", function(element){
+    if (!this.controlBars) {
+      this.controlBars = [];
+      this.onResize(this.positionControlBars);
+    }
+    this.controlBars.push(element);
+    _V_.addListener(element, "mousemove", this.onControlBarsMouseMove.context(this));
+    _V_.addListener(element, "mouseout", this.onControlBarsMouseOut.context(this));
+  },{
+    showControlBars: function(){
+      if (!this.options.controlsAtStart && !this.hasPlayed) { return; }
+      this.each(this.controlBars, function(bar){
+        bar.style.display = "block";
+      });
+    },
+    // Place controller relative to the video's position (now just resizing bars)
+    positionControlBars: function(){
+      this.updatePlayProgressBars();
+      this.updateLoadProgressBars();
+    },
+    hideControlBars: function(){
+      if (this.options.controlsHiding && !this.mouseIsOverControls) {
+        this.each(this.controlBars, function(bar){
+          bar.style.display = "none";
+        });
+      }
+    },
+    // Block controls from hiding when mouse is over them.
+    onControlBarsMouseMove: function(){ this.mouseIsOverControls = true; },
+    onControlBarsMouseOut: function(event){
+      this.mouseIsOverControls = false;
+    }
+  }
+);
+/* PlayToggle, PlayButton, PauseButton Behaviors
+================================================================================ */
+// Play Toggle
+VideoJS.player.newBehavior("playToggle", function(element){
+    if (!this.elements.playToggles) {
+      this.elements.playToggles = [];
+      this.onPlay(this.playTogglesOnPlay);
+      this.onPause(this.playTogglesOnPause);
+    }
+    this.elements.playToggles.push(element);
+    _V_.addListener(element, "click", this.onPlayToggleClick.context(this));
+  },{
+    onPlayToggleClick: function(event){
+      if (this.paused()) {
+        this.play();
+      } else {
+        this.pause();
+      }
+    },
+    playTogglesOnPlay: function(event){
+      this.each(this.elements.playToggles, function(toggle){
+        _V_.removeClass(toggle, "vjs-paused");
+        _V_.addClass(toggle, "vjs-playing");
+      });
+    },
+    playTogglesOnPause: function(event){
+      this.each(this.elements.playToggles, function(toggle){
+        _V_.removeClass(toggle, "vjs-playing");
+        _V_.addClass(toggle, "vjs-paused");
+      });
+    }
+  }
+);
+// Play
+VideoJS.player.newBehavior("playButton", function(element){
+    _V_.addListener(element, "click", this.onPlayButtonClick.context(this));
+  },{
+    onPlayButtonClick: function(event){ this.play(); }
+  }
+);
+// Pause
+VideoJS.player.newBehavior("pauseButton", function(element){
+    _V_.addListener(element, "click", this.onPauseButtonClick.context(this));
+  },{
+    onPauseButtonClick: function(event){ this.pause(); }
+  }
+);
+/* Play Progress Bar Behaviors
+================================================================================ */
+VideoJS.player.newBehavior("playProgressBar", function(element){
+    if (!this.playProgressBars) {
+      this.playProgressBars = [];
+      this.onCurrentTimeUpdate(this.updatePlayProgressBars);
+    }
+    this.playProgressBars.push(element);
+  },{
+    // Ajust the play progress bar's width based on the current play time
+    updatePlayProgressBars: function(newTime){
+      var progress = (newTime !== undefined) ? newTime / this.duration() : this.currentTime() / this.duration();
+      if (isNaN(progress)) { progress = 0; }
+      this.each(this.playProgressBars, function(bar){
+        if (bar.style) { bar.style.width = _V_.round(progress * 100, 2) + "%"; }
+      });
+    }
+  }
+);
+/* Load Progress Bar Behaviors
+================================================================================ */
+VideoJS.player.newBehavior("loadProgressBar", function(element){
+    if (!this.loadProgressBars) { this.loadProgressBars = []; }
+    this.loadProgressBars.push(element);
+    this.onBufferedUpdate(this.updateLoadProgressBars);
+  },{
+    updateLoadProgressBars: function(){
+      this.each(this.loadProgressBars, function(bar){
+        if (bar.style) { bar.style.width = _V_.round(this.bufferedPercent() * 100, 2) + "%"; }
+      });
+    }
+  }
+);
+
+/* Current Time Display Behaviors
+================================================================================ */
+VideoJS.player.newBehavior("currentTimeDisplay", function(element){
+    if (!this.currentTimeDisplays) {
+      this.currentTimeDisplays = [];
+      this.onCurrentTimeUpdate(this.updateCurrentTimeDisplays);
+    }
+    this.currentTimeDisplays.push(element);
+  },{
+    // Update the displayed time (00:00)
+    updateCurrentTimeDisplays: function(newTime){
+      if (!this.currentTimeDisplays) { return; }
+      // Allows for smooth scrubbing, when player can't keep up.
+      var time = (newTime) ? newTime : this.currentTime();
+      this.each(this.currentTimeDisplays, function(dis){
+        dis.innerHTML = _V_.formatTime(time);
+      });
+    }
+  }
+);
+
+/* Duration Display Behaviors
+================================================================================ */
+VideoJS.player.newBehavior("durationDisplay", function(element){
+    if (!this.durationDisplays) {
+      this.durationDisplays = [];
+      this.onCurrentTimeUpdate(this.updateDurationDisplays);
+    }
+    this.durationDisplays.push(element);
+  },{
+    updateDurationDisplays: function(){
+      if (!this.durationDisplays) { return; }
+      this.each(this.durationDisplays, function(dis){
+        if (this.duration()) { dis.innerHTML = _V_.formatTime(this.duration()); }
+      });
+    }
+  }
+);
+
+/* Current Time Scrubber Behaviors
+================================================================================ */
+VideoJS.player.newBehavior("currentTimeScrubber", function(element){
+    _V_.addListener(element, "mousedown", this.onCurrentTimeScrubberMouseDown.rEvtContext(this));
+  },{
+    // Adjust the play position when the user drags on the progress bar
+    onCurrentTimeScrubberMouseDown: function(event, scrubber){
+      event.preventDefault();
+      this.currentScrubber = scrubber;
+
+      this.stopTrackingCurrentTime(); // Allows for smooth scrubbing
+
+      this.videoWasPlaying = !this.paused();
+      this.pause();
+
+      _V_.blockTextSelection();
+      this.setCurrentTimeWithScrubber(event);
+      _V_.addListener(document, "mousemove", this.onCurrentTimeScrubberMouseMove.rEvtContext(this));
+      _V_.addListener(document, "mouseup", this.onCurrentTimeScrubberMouseUp.rEvtContext(this));
+    },
+    onCurrentTimeScrubberMouseMove: function(event){ // Removable
+      this.setCurrentTimeWithScrubber(event);
+    },
+    onCurrentTimeScrubberMouseUp: function(event){ // Removable
+      _V_.unblockTextSelection();
+      document.removeEventListener("mousemove", this.onCurrentTimeScrubberMouseMove, false);
+      document.removeEventListener("mouseup", this.onCurrentTimeScrubberMouseUp, false);
+      if (this.videoWasPlaying) {
+        this.play();
+        this.trackCurrentTime();
+      }
+    },
+    setCurrentTimeWithScrubber: function(event){
+      var newProgress = _V_.getRelativePosition(event.pageX, this.currentScrubber);
+      var newTime = newProgress * this.duration();
+      this.triggerCurrentTimeListeners(0, newTime); // Allows for smooth scrubbing
+      // Don't let video end while scrubbing.
+      if (newTime == this.duration()) { newTime = newTime - 0.1; }
+      this.currentTime(newTime);
+    }
+  }
+);
+/* Volume Display Behaviors
+================================================================================ */
+VideoJS.player.newBehavior("volumeDisplay", function(element){
+    if (!this.volumeDisplays) {
+      this.volumeDisplays = [];
+      this.onVolumeChange(this.updateVolumeDisplays);
+    }
+    this.volumeDisplays.push(element);
+    this.updateVolumeDisplay(element); // Set the display to the initial volume
+  },{
+    // Update the volume control display
+    // Unique to these default controls. Uses borders to create the look of bars.
+    updateVolumeDisplays: function(){
+      if (!this.volumeDisplays) { return; }
+      this.each(this.volumeDisplays, function(dis){
+        this.updateVolumeDisplay(dis);
+      });
+    },
+    updateVolumeDisplay: function(display){
+      var volNum = Math.ceil(this.volume() * 6);
+      this.each(display.children, function(child, num){
+        if (num < volNum) {
+          _V_.addClass(child, "vjs-volume-level-on");
+        } else {
+          _V_.removeClass(child, "vjs-volume-level-on");
+        }
+      });
+    }
+  }
+);
+/* Volume Scrubber Behaviors
+================================================================================ */
+VideoJS.player.newBehavior("volumeScrubber", function(element){
+    _V_.addListener(element, "mousedown", this.onVolumeScrubberMouseDown.rEvtContext(this));
+  },{
+    // Adjust the volume when the user drags on the volume control
+    onVolumeScrubberMouseDown: function(event, scrubber){
+      // event.preventDefault();
+      _V_.blockTextSelection();
+      this.currentScrubber = scrubber;
+      this.setVolumeWithScrubber(event);
+      _V_.addListener(document, "mousemove", this.onVolumeScrubberMouseMove.rEvtContext(this));
+      _V_.addListener(document, "mouseup", this.onVolumeScrubberMouseUp.rEvtContext(this));
+    },
+    onVolumeScrubberMouseMove: function(event){
+      this.setVolumeWithScrubber(event);
+    },
+    onVolumeScrubberMouseUp: function(event){
+      this.setVolumeWithScrubber(event);
+      _V_.unblockTextSelection();
+      document.removeEventListener("mousemove", this.onVolumeScrubberMouseMove, false);
+      document.removeEventListener("mouseup", this.onVolumeScrubberMouseUp, false);
+    },
+    setVolumeWithScrubber: function(event){
+      var newVol = _V_.getRelativePosition(event.pageX, this.currentScrubber);
+      this.volume(newVol);
+    }
+  }
+);
+/* Fullscreen Toggle Behaviors
+================================================================================ */
+VideoJS.player.newBehavior("fullscreenToggle", function(element){
+    _V_.addListener(element, "click", this.onFullscreenToggleClick.context(this));
+  },{
+    // When the user clicks on the fullscreen button, update fullscreen setting
+    onFullscreenToggleClick: function(event){
+      if (!this.videoIsFullScreen) {
+        this.enterFullScreen();
+      } else {
+        this.exitFullScreen();
+      }
+    },
+
+    fullscreenOnWindowResize: function(event){ // Removable
+      this.positionControlBars();
+    },
+    // Create listener for esc key while in full screen mode
+    fullscreenOnEscKey: function(event){ // Removable
+      if (event.keyCode == 27) {
+        this.exitFullScreen();
+      }
+    }
+  }
+);
+/* Big Play Button Behaviors
+================================================================================ */
+VideoJS.player.newBehavior("bigPlayButton", function(element){
+    if (!this.elements.bigPlayButtons) {
+      this.elements.bigPlayButtons = [];
+      this.onPlay(this.bigPlayButtonsOnPlay);
+      this.onEnded(this.bigPlayButtonsOnEnded);
+    }
+    this.elements.bigPlayButtons.push(element);
+    this.activateElement(element, "playButton");
+  },{
+    bigPlayButtonsOnPlay: function(event){ this.hideBigPlayButtons(); },
+    bigPlayButtonsOnEnded: function(event){ this.showBigPlayButtons(); },
+    showBigPlayButtons: function(){
+      this.each(this.elements.bigPlayButtons, function(element){
+        element.style.display = "block";
+      });
+    },
+    hideBigPlayButtons: function(){
+      this.each(this.elements.bigPlayButtons, function(element){
+        element.style.display = "none";
+      });
+    }
+  }
+);
+/* Spinner
+================================================================================ */
+VideoJS.player.newBehavior("spinner", function(element){
+    if (!this.spinners) {
+      this.spinners = [];
+      _V_.addListener(this.video, "loadeddata", this.spinnersOnVideoLoadedData.context(this));
+      _V_.addListener(this.video, "loadstart", this.spinnersOnVideoLoadStart.context(this));
+      _V_.addListener(this.video, "seeking", this.spinnersOnVideoSeeking.context(this));
+      _V_.addListener(this.video, "seeked", this.spinnersOnVideoSeeked.context(this));
+      _V_.addListener(this.video, "canplay", this.spinnersOnVideoCanPlay.context(this));
+      _V_.addListener(this.video, "canplaythrough", this.spinnersOnVideoCanPlayThrough.context(this));
+      _V_.addListener(this.video, "waiting", this.spinnersOnVideoWaiting.context(this));
+      _V_.addListener(this.video, "stalled", this.spinnersOnVideoStalled.context(this));
+      _V_.addListener(this.video, "suspend", this.spinnersOnVideoSuspend.context(this));
+      _V_.addListener(this.video, "playing", this.spinnersOnVideoPlaying.context(this));
+      _V_.addListener(this.video, "timeupdate", this.spinnersOnVideoTimeUpdate.context(this));
+    }
+    this.spinners.push(element);
+  },{
+    showSpinners: function(){
+      this.each(this.spinners, function(spinner){
+        spinner.style.display = "block";
+      });
+      clearInterval(this.spinnerInterval);
+      this.spinnerInterval = setInterval(this.rotateSpinners.context(this), 100);
+    },
+    hideSpinners: function(){
+      this.each(this.spinners, function(spinner){
+        spinner.style.display = "none";
+      });
+      clearInterval(this.spinnerInterval);
+    },
+    spinnersRotated: 0,
+    rotateSpinners: function(){
+      this.each(this.spinners, function(spinner){
+        // spinner.style.transform =       'scale(0.5) rotate('+this.spinnersRotated+'deg)';
+        spinner.style.WebkitTransform = 'scale(0.5) rotate('+this.spinnersRotated+'deg)';
+        spinner.style.MozTransform =    'scale(0.5) rotate('+this.spinnersRotated+'deg)';
+      });
+      if (this.spinnersRotated == 360) { this.spinnersRotated = 0; }
+      this.spinnersRotated += 45;
+    },
+    spinnersOnVideoLoadedData: function(event){ this.hideSpinners(); },
+    spinnersOnVideoLoadStart: function(event){ this.showSpinners(); },
+    spinnersOnVideoSeeking: function(event){ /* this.showSpinners(); */ },
+    spinnersOnVideoSeeked: function(event){ /* this.hideSpinners(); */ },
+    spinnersOnVideoCanPlay: function(event){ /* this.hideSpinners(); */ },
+    spinnersOnVideoCanPlayThrough: function(event){ this.hideSpinners(); },
+    spinnersOnVideoWaiting: function(event){
+      // Safari sometimes triggers waiting inappropriately
+      // Like after video has played, any you play again.
+      this.showSpinners();
+    },
+    spinnersOnVideoStalled: function(event){},
+    spinnersOnVideoSuspend: function(event){},
+    spinnersOnVideoPlaying: function(event){ this.hideSpinners(); },
+    spinnersOnVideoTimeUpdate: function(event){
+      // Safari sometimes calls waiting and doesn't recover
+      if(this.spinner.style.display == "block") { this.hideSpinners(); }
+    }
+  }
+);
+/* Subtitles
+================================================================================ */
+VideoJS.player.newBehavior("subtitlesDisplay", function(element){
+    if (!this.subtitleDisplays) {
+      this.subtitleDisplays = [];
+      this.onCurrentTimeUpdate(this.subtitleDisplaysOnVideoTimeUpdate);
+      this.onEnded(function() { this.lastSubtitleIndex = 0; }.context(this));
+    }
+    this.subtitleDisplays.push(element);
+  },{
+    subtitleDisplaysOnVideoTimeUpdate: function(time){
+      // Assuming all subtitles are in order by time, and do not overlap
+      if (this.subtitles) {
+        // If current subtitle should stay showing, don't do anything. Otherwise, find new subtitle.
+        if (!this.currentSubtitle || this.currentSubtitle.start >= time || this.currentSubtitle.end < time) {
+          var newSubIndex = false,
+              // Loop in reverse if lastSubtitle is after current time (optimization)
+              // Meaning the user is scrubbing in reverse or rewinding
+              reverse = (this.subtitles[this.lastSubtitleIndex].start > time),
+              // If reverse, step back 1 becase we know it's not the lastSubtitle
+              i = this.lastSubtitleIndex - (reverse) ? 1 : 0;
+          while (true) { // Loop until broken
+            if (reverse) { // Looping in reverse
+              // Stop if no more, or this subtitle ends before the current time (no earlier subtitles should apply)
+              if (i < 0 || this.subtitles[i].end < time) { break; }
+              // End is greater than time, so if start is less, show this subtitle
+              if (this.subtitles[i].start < time) {
+                newSubIndex = i;
+                break;
+              }
+              i--;
+            } else { // Looping forward
+              // Stop if no more, or this subtitle starts after time (no later subtitles should apply)
+              if (i >= this.subtitles.length || this.subtitles[i].start > time) { break; }
+              // Start is less than time, so if end is later, show this subtitle
+              if (this.subtitles[i].end > time) {
+                newSubIndex = i;
+                break;
+              }
+              i++;
+            }
+          }
+
+          // Set or clear current subtitle
+          if (newSubIndex !== false) {
+            this.currentSubtitle = this.subtitles[newSubIndex];
+            this.lastSubtitleIndex = newSubIndex;
+            this.updateSubtitleDisplays(this.currentSubtitle.text);
+          } else if (this.currentSubtitle) {
+            this.currentSubtitle = false;
+            this.updateSubtitleDisplays("");
+          }
+        }
+      }
+    },
+    updateSubtitleDisplays: function(val){
+      this.each(this.subtitleDisplays, function(disp){
+        disp.innerHTML = val;
+      });
+    }
+  }
+);
+
+////////////////////////////////////////////////////////////////////////////////
+// Convenience Functions (mini library)
+// Functions not specific to video or VideoJS and could probably be replaced with a library like jQuery
+////////////////////////////////////////////////////////////////////////////////
+
+VideoJS.extend({
+
+  addClass: function(element, classToAdd){
+    if ((" "+element.className+" ").indexOf(" "+classToAdd+" ") == -1) {
+      element.className = element.className === "" ? classToAdd : element.className + " " + classToAdd;
+    }
+  },
+  removeClass: function(element, classToRemove){
+    if (element.className.indexOf(classToRemove) == -1) { return; }
+    var classNames = element.className.split(/\s+/);
+    classNames.splice(classNames.lastIndexOf(classToRemove),1);
+    element.className = classNames.join(" ");
+  },
+  createElement: function(tagName, attributes){
+    return this.merge(document.createElement(tagName), attributes);
+  },
+
+  // Attempt to block the ability to select text while dragging controls
+  blockTextSelection: function(){
+    document.body.focus();
+    document.onselectstart = function () { return false; };
+  },
+  // Turn off text selection blocking
+  unblockTextSelection: function(){ document.onselectstart = function () { return true; }; },
+
+  // Return seconds as MM:SS
+  formatTime: function(secs) {
+    var seconds = Math.round(secs);
+    var minutes = Math.floor(seconds / 60);
+    minutes = (minutes >= 10) ? minutes : "0" + minutes;
+    seconds = Math.floor(seconds % 60);
+    seconds = (seconds >= 10) ? seconds : "0" + seconds;
+    return minutes + ":" + seconds;
+  },
+
+  // Return the relative horizonal position of an event as a value from 0-1
+  getRelativePosition: function(x, relativeElement){
+    return Math.max(0, Math.min(1, (x - this.findPosX(relativeElement)) / relativeElement.offsetWidth));
+  },
+  // Get an objects position on the page
+  findPosX: function(obj) {
+    var curleft = obj.offsetLeft;
+    while(obj = obj.offsetParent) {
+      curleft += obj.offsetLeft;
+    }
+    return curleft;
+  },
+  getComputedStyleValue: function(element, style){
+    return window.getComputedStyle(element, null).getPropertyValue(style);
+  },
+
+  round: function(num, dec) {
+    if (!dec) { dec = 0; }
+    return Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
+  },
+
+  addListener: function(element, type, handler){
+    if (element.addEventListener) {
+      element.addEventListener(type, handler, false);
+    } else if (element.attachEvent) {
+      element.attachEvent("on"+type, handler);
+    }
+  },
+  removeListener: function(element, type, handler){
+    if (element.removeEventListener) {
+      element.removeEventListener(type, handler, false);
+    } else if (element.attachEvent) {
+      element.detachEvent("on"+type, handler);
+    }
+  },
+
+  get: function(url, onSuccess){
+    if (typeof XMLHttpRequest == "undefined") {
+      XMLHttpRequest = function () {
+        try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {}
+        try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (f) {}
+        try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (g) {}
+        //Microsoft.XMLHTTP points to Msxml2.XMLHTTP.3.0 and is redundant
+        throw new Error("This browser does not support XMLHttpRequest.");
+      };
+    }
+    var request = new XMLHttpRequest();
+    request.open("GET",url);
+    request.onreadystatechange = function() {
+      if (request.readyState == 4 && request.status == 200) {
+        onSuccess(request.responseText);
+      }
+    }.context(this);
+    request.send();
+  },
+
+  trim: function(string){ return string.toString().replace(/^\s+/, "").replace(/\s+$/, ""); },
+
+  // DOM Ready functionality adapted from jQuery. http://jquery.com/
+  bindDOMReady: function(){
+    if (document.readyState === "complete") {
+      return VideoJS.onDOMReady();
+    }
+    if (document.addEventListener) {
+      document.addEventListener("DOMContentLoaded", VideoJS.DOMContentLoaded, false);
+      window.addEventListener("load", VideoJS.onDOMReady, false);
+    } else if (document.attachEvent) {
+      document.attachEvent("onreadystatechange", VideoJS.DOMContentLoaded);
+      window.attachEvent("onload", VideoJS.onDOMReady);
+    }
+  },
+
+  DOMContentLoaded: function(){
+    if (document.addEventListener) {
+      document.removeEventListener( "DOMContentLoaded", VideoJS.DOMContentLoaded, false);
+      VideoJS.onDOMReady();
+    } else if ( document.attachEvent ) {
+      if ( document.readyState === "complete" ) {
+        document.detachEvent("onreadystatechange", VideoJS.DOMContentLoaded);
+        VideoJS.onDOMReady();
+      }
+    }
+  },
+
+  // Functions to be run once the DOM is loaded
+  DOMReadyList: [],
+  addToDOMReady: function(fn){
+    if (VideoJS.DOMIsReady) {
+      fn.call(document);
+    } else {
+      VideoJS.DOMReadyList.push(fn);
+    }
+  },
+
+  DOMIsReady: false,
+  onDOMReady: function(){
+    if (VideoJS.DOMIsReady) { return; }
+    if (!document.body) { return setTimeout(VideoJS.onDOMReady, 13); }
+    VideoJS.DOMIsReady = true;
+    if (VideoJS.DOMReadyList) {
+      for (var i=0; i<VideoJS.DOMReadyList.length; i++) {
+        VideoJS.DOMReadyList[i].call(document);
+      }
+      VideoJS.DOMReadyList = null;
+    }
+  }
+});
+VideoJS.bindDOMReady();
+
+// Allows for binding context to functions
+// when using in event listeners and timeouts
+Function.prototype.context = function(obj){
+  var method = this,
+  temp = function(){
+    return method.apply(obj, arguments);
+  };
+  return temp;
+};
+
+// Like context, in that it creates a closure
+// But insteaad keep "this" intact, and passes the var as the second argument of the function
+// Need for event listeners where you need to know what called the event
+// Only use with event callbacks
+Function.prototype.evtContext = function(obj){
+  var method = this,
+  temp = function(){
+    var origContext = this;
+    return method.call(obj, arguments[0], origContext);
+  };
+  return temp;
+};
+
+// Removable Event listener with Context
+// Replaces the original function with a version that has context
+// So it can be removed using the original function name.
+// In order to work, a version of the function must already exist in the player/prototype
+Function.prototype.rEvtContext = function(obj, funcParent){
+  if (this.hasContext === true) { return this; }
+  if (!funcParent) { funcParent = obj; }
+  for (var attrname in funcParent) {
+    if (funcParent[attrname] == this) {
+      funcParent[attrname] = this.evtContext(obj);
+      funcParent[attrname].hasContext = true;
+      return funcParent[attrname];
+    }
+  }
+  return this.evtContext(obj);
+};
+
+// jQuery Plugin
+if (window.jQuery) {
+  (function($) {
+    $.fn.VideoJS = function(options) {
+      this.each(function() {
+        VideoJS.setup(this, options);
+      });
+      return this;
+    };
+    $.fn.player = function() {
+      return this[0].player;
+    };
+  })(jQuery);
+}
+
+
+// Expose to global
+window.VideoJS = window._V_ = VideoJS;
+
+// End self-executing function
+})(window);
\ No newline at end of file